diff --git a/.cargo/config.toml b/.cargo/config.toml index 3e7c829b0a7..cb6abcad984 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,5 +1,4 @@ [env] -CAIRO_NATIVE_RUNTIME_LIBRARY = "./libcairo_native_runtime.a" LLVM_SYS_191_PREFIX = "/usr/lib/llvm-19/" MLIR_SYS_190_PREFIX = "/usr/lib/llvm-19/" TABLEGEN_190_PREFIX = "/usr/lib/llvm-19/" @@ -7,7 +6,7 @@ TABLEGEN_190_PREFIX = "/usr/lib/llvm-19/" # Use `lld` for linking instead of `ld`, since we run out of memory while linking with `ld` on # 16-cores linux machines, see: # https://nnethercote.github.io/perf-book/build-configuration.html#linking. -# TODO: remove this once `rust` stabilizes `lld` as the default linker, currently only on nightly: +# TODO(Gilad): remove this once `rust` stabilizes `lld` as the default linker, currently only on nightly: # https://github.com/rust-lang/rust/issues/39915#issuecomment-618726211 -[target.x86_64-unknown-linux-gnu] +[target.'cfg(all(target_os = "linux"))'] rustflags = ["-Clink-arg=-fuse-ld=lld"] diff --git a/.dockerignore b/.dockerignore index 4431bfca825..699c00d42b6 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,6 +1,6 @@ /data /deployments /logs -/target +**/target/ .git !crates/papyrus_load_test/resources diff --git a/.github/actions/bootstrap/action.yml b/.github/actions/bootstrap/action.yml index 5201006e79e..f5a1468c523 100644 --- a/.github/actions/bootstrap/action.yml +++ b/.github/actions/bootstrap/action.yml @@ -1,7 +1,17 @@ +name: Bootstrap +description: Install dependencies. + +inputs: + extra_rust_toolchains: + description: "Extra toolchains to install, but aren't used by default" + required: false + runs: using: "composite" steps: - name: Install rust. uses: ./.github/actions/install_rust + with: + extra_rust_toolchains: ${{ inputs.extra_rust_toolchains }} - name: Install cairo native. uses: ./.github/actions/setup_native_deps diff --git a/.github/actions/install_rust/action.yml b/.github/actions/install_rust/action.yml index c81c5ac5697..991102cc97b 100644 --- a/.github/actions/install_rust/action.yml +++ b/.github/actions/install_rust/action.yml @@ -1,9 +1,30 @@ -name: Bootsrap rust installation +name: Bootstrap rust installation description: Setup rust environment and its components, also caching the build results. +inputs: + extra_rust_toolchains: + description: "Extra toolchains to install, but aren't used by default" + required: false + runs: using: "composite" steps: - uses: moonrepo/setup-rust@v1 + name: Install Rust toolchain and binaries with: cache-base: main(-v[0-9].*)? + inherit-toolchain: true + bins: taplo-cli@0.9.3, cargo-machete + # Install additional non-default toolchains (for rustfmt for example), NOP if input omitted. + channel: ${{ inputs.extra_rust_toolchains }} + env: + RUSTFLAGS: "-C link-arg=-fuse-ld=lld" + + # This installation is _not_ cached, but takes a couple seconds: it's downloading prepackaged + # binaries. + # TODO(Gilad): once we migrate to a cached Docker image, we can remove this step and just + # install it during dependencies.sh (which we don't do now since dependencies.sh isn't cached). + - name: Install Anvil + uses: foundry-rs/foundry-toolchain@v1 + with: + version: v0.3.0 diff --git a/.github/workflows/blockifier_ci.yml b/.github/workflows/blockifier_ci.yml index ec3655e2bf9..7bebc5edc6a 100644 --- a/.github/workflows/blockifier_ci.yml +++ b/.github/workflows/blockifier_ci.yml @@ -22,39 +22,66 @@ on: paths: # Other than code-related changes, all changes related to the native-blockifier build-and-push # process should trigger the build (e.g., changes to the Dockerfile, build scripts, etc.). + - '.github/actions/bootstrap/action.yml' - '.github/workflows/blockifier_ci.yml' - '.github/workflows/upload_artifacts_workflow.yml' - 'build_native_in_docker.sh' - 'Cargo.lock' - 'Cargo.toml' - 'crates/blockifier/**' + - 'crates/blockifier_test_utils/**' - 'crates/native_blockifier/**' + - 'crates/starknet_sierra_multicompile/build.rs' - 'scripts/build_native_blockifier.sh' - 'scripts/dependencies.sh' - 'scripts/install_build_tools.sh' - 'scripts/sequencer-ci.Dockerfile' +env: + RUSTFLAGS: "-D warnings -C link-arg=-fuse-ld=lld" + # On PR events, cancel existing CI runs on this same PR for this workflow. +# Also, create different concurrency groups for different pushed commits, on push events. concurrency: - group: ${{ github.workflow }}-${{ github.ref }}-${{ github.job }} + group: > + ${{ github.workflow }}- + ${{ github.ref }}- + ${{ github.event_name == 'pull_request' && 'PR' || github.sha }} cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: - feature-combo-builds: - runs-on: starkware-ubuntu-20-04-medium + test-without-features: + runs-on: starkware-ubuntu-24.04-medium steps: - uses: actions/checkout@v4 - with: - # required to clone native as a gitsubmodule - submodules: recursive - fetch-depth: 0 - uses: ./.github/actions/bootstrap # No features - build blockifier without features activated by dependencies in the workspace. - - run: cargo build -p blockifier - run: cargo test -p blockifier + - run: cargo build -p blockifier + + test-with-transaction-serde-feature: + runs-on: starkware-ubuntu-24.04-medium + steps: + - uses: actions/checkout@v4 + - uses: ./.github/actions/bootstrap # transaction_serde is not activated by any workspace crate; test the build. - - run: cargo build -p blockifier --features transaction_serde - run: cargo test -p blockifier --features transaction_serde + - run: cargo build -p blockifier --features transaction_serde + + test-with-cairo-native-feature: + runs-on: starkware-ubuntu-24.04-medium + steps: + - uses: actions/checkout@v4 + - uses: ./.github/actions/bootstrap # cairo_native is not activated by any workspace crate; test the build. - run: cargo build -p blockifier --features cairo_native - run: cargo test -p blockifier --features cairo_native + + test-with-tracing-feature: + runs-on: starkware-ubuntu-24.04-medium + steps: + - uses: actions/checkout@v4 + - uses: ./.github/actions/bootstrap + # tracing is not activated by any workspace crate; test the build. + - run: cargo build -p blockifier --features tracing + - run: cargo test -p blockifier --features tracing diff --git a/.github/workflows/blockifier_compiled_cairo.yml b/.github/workflows/blockifier_compiled_cairo.yml index afc3099d4f6..48901a907af 100644 --- a/.github/workflows/blockifier_compiled_cairo.yml +++ b/.github/workflows/blockifier_compiled_cairo.yml @@ -9,20 +9,27 @@ on: paths: - 'Cargo.toml' - '.github/workflows/blockifier_compiled_cairo.yml' - - 'crates/blockifier/feature_contracts/**' - - 'crates/blockifier/src/test_utils/cairo_compile.rs' - - 'crates/blockifier/tests/feature_contracts_compatibility_test.rs' - - 'crates/blockifier/tests/requirements.txt' + - 'crates/blockifier_test_utils/cairo_compile.rs' + - 'crates/blockifier_test_utils/resources/feature_contracts/**' + - 'crates/blockifier_test_utils/tests/feature_contracts_compatibility_test.rs' + - 'crates/blockifier_test_utils/tests/requirements.txt' - 'scripts/dependencies.sh' +env: + RUSTFLAGS: "-D warnings -C link-arg=-fuse-ld=lld" + # On PR events, cancel existing CI runs on this same PR for this workflow. +# Also, create different concurrency groups for different pushed commits, on push events. concurrency: - group: ${{ github.workflow }}-${{ github.ref }}-${{ github.job }} + group: > + ${{ github.workflow }}- + ${{ github.ref }}- + ${{ github.event_name == 'pull_request' && 'PR' || github.sha }} cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: verify_cairo_file_dependencies: - runs-on: starkware-ubuntu-20-04-medium + runs-on: starkware-ubuntu-24.04-medium steps: - uses: actions/checkout@v4 - uses: ./.github/actions/bootstrap @@ -65,5 +72,5 @@ jobs: - name: Verify cairo contract recompilation (both cairo versions). run: cd sequencer && - pip install -r crates/blockifier/tests/requirements.txt && - cargo test -p blockifier --test feature_contracts_compatibility_test --features testing -- --include-ignored + pip install -r crates/blockifier_test_utils/tests/requirements.txt && + cargo test -p blockifier_test_utils --test feature_contracts_compatibility_test -- --include-ignored --nocapture diff --git a/.github/workflows/blockifier_post-merge.yml b/.github/workflows/blockifier_post-merge.yml index a001ccb6595..6fe133d1703 100644 --- a/.github/workflows/blockifier_post-merge.yml +++ b/.github/workflows/blockifier_post-merge.yml @@ -13,7 +13,7 @@ on: jobs: if_merged: if: github.event.pull_request.merged == true - runs-on: starkware-ubuntu-20-04-medium + runs-on: starkware-ubuntu-24.04-medium steps: - uses: actions/checkout@v4 - uses: ./.github/actions/bootstrap @@ -29,5 +29,5 @@ jobs: run: echo "LD_LIBRARY_PATH=${LD_LIBRARY_PATH}" >> $GITHUB_ENV - run: | - pip install -r crates/blockifier/tests/requirements.txt + pip install -r crates/blockifier_test_utils/tests/requirements.txt cargo test -p blockifier -p native_blockifier -- --include-ignored diff --git a/.github/workflows/blockifier_reexecution_ci.yml b/.github/workflows/blockifier_reexecution_ci.yml index 36b3c658752..0700a5537a0 100644 --- a/.github/workflows/blockifier_reexecution_ci.yml +++ b/.github/workflows/blockifier_reexecution_ci.yml @@ -19,14 +19,21 @@ on: - 'scripts/install_build_tools.sh' - 'scripts/sequencer-ci.Dockerfile' +env: + RUSTFLAGS: "-D warnings -C link-arg=-fuse-ld=lld" + # On PR events, cancel existing CI runs on this same PR for this workflow. +# Also, create different concurrency groups for different pushed commits, on push events. concurrency: - group: ${{ github.workflow }}-${{ github.ref }}-${{ github.job }} + group: > + ${{ github.workflow }}- + ${{ github.ref }}- + ${{ github.event_name == 'pull_request' && 'PR' || github.sha }} cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: blockifier_reexecution: - runs-on: starkware-ubuntu-latest-medium + runs-on: starkware-ubuntu-24.04-medium steps: - uses: actions/checkout@v4 - uses: ./.github/actions/bootstrap @@ -41,4 +48,4 @@ jobs: # Run blockifier re-execution tests. - run: cargo test --release -p blockifier_reexecution -- --include-ignored # Compile the rpc-tests, without running them. - - run: cargo test -p blockifier_reexecution --features blockifier_regression_https_testing --no-run + - run: cargo test --release -p blockifier_reexecution --features blockifier_regression_https_testing --no-run diff --git a/.github/workflows/clean_stale_prs.yml b/.github/workflows/clean_stale_prs.yml index 1ccbe73ac87..999282fc948 100644 --- a/.github/workflows/clean_stale_prs.yml +++ b/.github/workflows/clean_stale_prs.yml @@ -9,7 +9,7 @@ on: jobs: stale: name: 🧹 Clean up stale issues and PRs - runs-on: starkware-ubuntu-latest-small + runs-on: starkware-ubuntu-24.04-small steps: - name: 🚀 Run stale uses: actions/stale@v3 diff --git a/.github/workflows/committer_cli_push.yml b/.github/workflows/committer_and_os_cli_push.yml similarity index 66% rename from .github/workflows/committer_cli_push.yml rename to .github/workflows/committer_and_os_cli_push.yml index 8475728b120..671ed7fb42b 100644 --- a/.github/workflows/committer_cli_push.yml +++ b/.github/workflows/committer_and_os_cli_push.yml @@ -1,4 +1,4 @@ -name: Committer-CLI-push +name: Committer-And-OS-CLI-push on: push: @@ -7,15 +7,6 @@ on: - main-v[0-9].** tags: - v[0-9].** - paths: - - '.github/workflows/committer_cli_push.yml' - - 'Cargo.toml' - - 'Cargo.lock' - - 'crates/committer_cli/**' - - 'crates/starknet_api/**' - - 'crates/starknet_committer/**' - - 'crates/starknet_patricia/**' - - 'scripts/dependencies.sh' pull_request: types: @@ -25,23 +16,34 @@ on: - auto_merge_enabled - edited paths: - - '.github/workflows/committer_cli_push.yml' + - '.github/workflows/committer_and_os_cli_push.yml' + - 'build_native_in_docker.sh' + - 'docker-ci/images/sequencer-ci.Dockerfile' - 'Cargo.toml' - 'Cargo.lock' - - 'crates/committer_cli/**' + - 'crates/starknet_committer_and_os_cli/**' - 'crates/starknet_api/**' - 'crates/starknet_committer/**' + - 'crates/starknet_os/**' - 'crates/starknet_patricia/**' + - 'rust-toolchain.toml' - 'scripts/dependencies.sh' +env: + RUSTFLAGS: "-D warnings -C link-arg=-fuse-ld=lld" + # On PR events, cancel existing CI runs on this same PR for this workflow. +# Also, create different concurrency groups for different pushed commits, on push events. concurrency: - group: ${{ github.workflow }}-${{ github.ref }}-${{ github.job }} + group: > + ${{ github.workflow }}- + ${{ github.ref }}- + ${{ github.event_name == 'pull_request' && 'PR' || github.sha }} cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: gcs-push: - runs-on: starkware-ubuntu-20-04-medium + runs-on: starkware-ubuntu-24.04-medium steps: - uses: actions/checkout@v4 - uses: ./.github/actions/bootstrap @@ -61,7 +63,7 @@ jobs: run: echo "SHORT_HASH=${COMMIT_SHA:0:7}" >> $GITHUB_ENV - name: Build CLI binary - run: ./build_native_in_docker.sh cargo build -p committer_cli -r --bin committer_cli --target-dir CLI_TARGET + run: ./build_native_in_docker.sh rustup toolchain install && cargo build -p starknet_committer_and_os_cli -r --bin starknet_committer_and_os_cli --target-dir CLI_TARGET - id: auth uses: "google-github-actions/auth@v2" @@ -72,5 +74,5 @@ jobs: id: upload_file uses: "google-github-actions/upload-cloud-storage@v2" with: - path: "CLI_TARGET/release/committer_cli" + path: "CLI_TARGET/release/starknet_committer_and_os_cli" destination: "committer-products-external/${{ env.SHORT_HASH }}/release/" diff --git a/.github/workflows/committer_ci.yml b/.github/workflows/committer_ci.yml index bd91e8b39b6..400355069bb 100644 --- a/.github/workflows/committer_ci.yml +++ b/.github/workflows/committer_ci.yml @@ -12,20 +12,27 @@ on: - '.github/workflows/committer_ci.yml' - 'Cargo.toml' - 'Cargo.lock' - - 'crates/committer_cli/**' + - 'crates/starknet_committer_and_os_cli/**' - 'crates/starknet_api/**' - 'crates/starknet_committer/**' - 'crates/starknet_patricia/**' - 'scripts/dependencies.sh' +env: + RUSTFLAGS: "-D warnings -C link-arg=-fuse-ld=lld" + # On PR events, cancel existing CI runs on this same PR for this workflow. +# Also, create different concurrency groups for different pushed commits, on push events. concurrency: - group: ${{ github.workflow }}-${{ github.ref }}-${{ github.job }} + group: > + ${{ github.workflow }}- + ${{ github.ref }}- + ${{ github.event_name == 'pull_request' && 'PR' || github.sha }} cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: run-regression-tests: - runs-on: starkware-ubuntu-latest-medium + runs-on: starkware-ubuntu-24.04-medium if: ${{ github.event_name == 'pull_request' }} steps: - uses: actions/checkout@v4 @@ -36,12 +43,12 @@ jobs: with: credentials_json: ${{ secrets.COMMITER_PRODUCTS_EXT_WRITER_JSON }} - uses: 'google-github-actions/setup-gcloud@v2' - - run: echo "BENCH_INPUT_FILES_PREFIX=$(cat ./crates/committer_cli/src/tests/flow_test_files_prefix)" >> $GITHUB_ENV - - run: gcloud storage cp -r gs://committer-testing-artifacts/$BENCH_INPUT_FILES_PREFIX/* ./crates/committer_cli/test_inputs - - run: cargo test -p committer_cli --release -- --include-ignored test_regression + - run: echo "BENCH_INPUT_FILES_PREFIX=$(cat ./crates/starknet_committer_and_os_cli/src/committer_cli/tests/flow_test_files_prefix)" >> $GITHUB_ENV + - run: gcloud storage cp -r gs://committer-testing-artifacts/$BENCH_INPUT_FILES_PREFIX/* ./crates/starknet_committer_and_os_cli/test_inputs + - run: cargo test -p starknet_committer_and_os_cli --release -- --include-ignored test_regression benchmarking: - runs-on: starkware-ubuntu-latest-medium + runs-on: starkware-ubuntu-24.04-medium if: ${{ github.event_name == 'pull_request' }} steps: # Checkout the base branch to get the old code. @@ -56,39 +63,39 @@ jobs: with: credentials_json: ${{ secrets.COMMITER_PRODUCTS_EXT_WRITER_JSON }} - uses: 'google-github-actions/setup-gcloud@v2' - - run: echo "OLD_BENCH_INPUT_FILES_PREFIX=$(cat ./crates/committer_cli/src/tests/flow_test_files_prefix)" >> $GITHUB_ENV - - run: gcloud storage cp -r gs://committer-testing-artifacts/$OLD_BENCH_INPUT_FILES_PREFIX/* ./crates/committer_cli/test_inputs + - run: echo "OLD_BENCH_INPUT_FILES_PREFIX=$(cat ./crates/starknet_committer_and_os_cli/src/committer_cli/tests/flow_test_files_prefix)" >> $GITHUB_ENV + - run: gcloud storage cp -r gs://committer-testing-artifacts/$OLD_BENCH_INPUT_FILES_PREFIX/* ./crates/starknet_committer_and_os_cli/test_inputs # List the existing benchmarks. - run: | - cargo bench -p committer_cli -- --list | grep ': benchmark$' | sed -e "s/: benchmark$//" > benchmarks_list.txt + cargo bench -p starknet_committer_and_os_cli -- --list | grep ': benchmark$' | sed -e "s/: benchmark$//" > benchmarks_list.txt # Benchmark the old code. - - run: cargo bench -p committer_cli + - run: cargo bench -p starknet_committer_and_os_cli # Backup the downloaded files to avoid re-downloading them if they didn't change (overwritten by checkout). - - run: mv ./crates/committer_cli/test_inputs/tree_flow_inputs.json ./crates/committer_cli/test_inputs/tree_flow_inputs.json_bu - - run: mv ./crates/committer_cli/test_inputs/committer_flow_inputs.json ./crates/committer_cli/test_inputs/committer_flow_inputs.json_bu + - run: mv ./crates/starknet_committer_and_os_cli/test_inputs/tree_flow_inputs.json ./crates/starknet_committer_and_os_cli/test_inputs/tree_flow_inputs.json_bu + - run: mv ./crates/starknet_committer_and_os_cli/test_inputs/committer_flow_inputs.json ./crates/starknet_committer_and_os_cli/test_inputs/committer_flow_inputs.json_bu # Checkout the new code. - uses: actions/checkout@v4 with: clean: false - - run: echo "NEW_BENCH_INPUT_FILES_PREFIX=$(cat ./crates/committer_cli/src/tests/flow_test_files_prefix)" >> $GITHUB_ENV + - run: echo "NEW_BENCH_INPUT_FILES_PREFIX=$(cat ./crates/starknet_committer_and_os_cli/src/committer_cli/tests/flow_test_files_prefix)" >> $GITHUB_ENV # Input files didn't change. - if: env.OLD_BENCH_INPUT_FILES_PREFIX == env.NEW_BENCH_INPUT_FILES_PREFIX run: | - mv ./crates/committer_cli/test_inputs/tree_flow_inputs.json_bu ./crates/committer_cli/test_inputs/tree_flow_inputs.json - mv ./crates/committer_cli/test_inputs/committer_flow_inputs.json_bu ./crates/committer_cli/test_inputs/committer_flow_inputs.json + mv ./crates/starknet_committer_and_os_cli/test_inputs/tree_flow_inputs.json_bu ./crates/starknet_committer_and_os_cli/test_inputs/tree_flow_inputs.json + mv ./crates/starknet_committer_and_os_cli/test_inputs/committer_flow_inputs.json_bu ./crates/starknet_committer_and_os_cli/test_inputs/committer_flow_inputs.json # Input files did change, download new inputs. - if: env.OLD_BENCH_INPUT_FILES_PREFIX != env.NEW_BENCH_INPUT_FILES_PREFIX run: | - gcloud storage cp -r gs://committer-testing-artifacts/$NEW_BENCH_INPUT_FILES_PREFIX/* ./crates/committer_cli/test_inputs + gcloud storage cp -r gs://committer-testing-artifacts/$NEW_BENCH_INPUT_FILES_PREFIX/* ./crates/starknet_committer_and_os_cli/test_inputs # Benchmark the new code, splitting the benchmarks, and prepare the results for posting a comment. - - run: bash ./crates/committer_cli/benches/bench_split_and_prepare_post.sh benchmarks_list.txt bench_new.txt + - run: bash ./crates/starknet_committer_and_os_cli/benches/bench_split_and_prepare_post.sh benchmarks_list.txt bench_new.txt - run: echo BENCHES_RESULT=$(cat bench_new.txt) >> $GITHUB_ENV diff --git a/.github/workflows/deployment.yml b/.github/workflows/deployment.yml deleted file mode 100644 index ee62eb20c15..00000000000 --- a/.github/workflows/deployment.yml +++ /dev/null @@ -1,36 +0,0 @@ -name: Sequencer Deployment Test -on: - push: - branches: - - main - - main-v[0-9].** - tags: - - v[0-9].** - # TODO(Dori, 1/9/2024): Decide when exactly native-blockifier artifacts will be built. Until - # then, keep the 'paths' key empty and build on every push to a release branch / tag. - - pull_request: - types: - - opened - - reopened - - synchronize - - auto_merge_enabled - - edited - paths: - - 'deployments/sequencer/*' - -jobs: - deployment: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - run: | - # Install deps. - npm install -g cdk8s-cli - python3 -m pip install pipenv - - # Synthesize the CDK8s Sequencer app. - cd deployments/sequencer - pipenv install - cdk8s synth --app "pipenv run python main.py --namespace test" - diff -aur references dist diff --git a/.github/workflows/lock_closed_prs.yml b/.github/workflows/lock_closed_prs.yml index 91b0175ffd1..b1cb1f18ff8 100644 --- a/.github/workflows/lock_closed_prs.yml +++ b/.github/workflows/lock_closed_prs.yml @@ -9,7 +9,7 @@ on: jobs: lock: name: 🔒 Lock closed issues and PRs - runs-on: starkware-ubuntu-latest-small + runs-on: starkware-ubuntu-24.04-small steps: - uses: dessant/lock-threads@v2.0.3 with: diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 42e201a8502..36185a0fda4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -18,29 +18,30 @@ on: env: CI: 1 + RUSTFLAGS: "-D warnings -C link-arg=-fuse-ld=lld" + RUSTDOCFLAGS: "-D warnings -C link-arg=-fuse-ld=lld" + EXTRA_RUST_TOOLCHAINS: nightly-2024-04-29 # On PR events, cancel existing CI runs on this same PR for this workflow. +# Also, create different concurrency groups for different pushed commits, on push events. concurrency: - group: ${{ github.workflow }}-${{ github.ref }}-${{ github.job }} + group: > + ${{ github.workflow }}- + ${{ github.ref }}- + ${{ github.event_name == 'pull_request' && 'PR' || github.sha }} cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: code_style: - runs-on: starkware-ubuntu-20-04-medium + runs-on: starkware-ubuntu-24.04-medium steps: # Environment setup. - uses: actions/checkout@v4 with: - # required to clone native as a git submodule - submodules: recursive # Fetch the entire history. Required to checkout the merge target commit, so the diff can # be computed. fetch-depth: 0 - - uses: baptiste0928/cargo-install@v3 - with: - crate: taplo-cli - version: '0.9.0' - locked: true + # Setup pypy and link to the location expected by .cargo/config.toml. - uses: actions/setup-python@v5 @@ -54,6 +55,8 @@ jobs: # Install rust components. - uses: ./.github/actions/bootstrap + with: + extra_rust_toolchains: ${{ env.EXTRA_RUST_TOOLCHAINS }} - name: Setup Python venv run: | @@ -66,28 +69,30 @@ jobs: cargo update -w --locked git diff --exit-code Cargo.lock + # Make sure no submodules are out of date or missing. + - name: "Check submodules" + run: git submodule status + # Run code style on PR. - - name: "Run rustfmt pull request" + - name: "Run TODO style pull request" if: github.event_name == 'pull_request' - run: ci/bin/python scripts/run_tests.py --command rustfmt --changes_only --commit_id ${{ github.event.pull_request.base.sha }} + run: ci/bin/python scripts/named_todos.py --commit_id ${{ github.event.pull_request.base.sha }} - name: "Run clippy pull request" if: github.event_name == 'pull_request' run: ci/bin/python scripts/run_tests.py --command clippy --changes_only --commit_id ${{ github.event.pull_request.base.sha }} - env: - RUSTFLAGS: "-D warnings" - name: "Run cargo doc pull request" if: github.event_name == 'pull_request' run: ci/bin/python scripts/run_tests.py --command doc --changes_only --commit_id ${{ github.event.pull_request.base.sha }} # Run code style on push. - - name: "Run rustfmt on push" - if: github.event_name == 'push' - run: ci/bin/python scripts/run_tests.py --command rustfmt + - name: "Run rustfmt" + # The nightly here is coupled with the one in install_rust/action.yml. + # If we move the install here we can use a const. + run: cargo +"$EXTRA_RUST_TOOLCHAINS" fmt --all -- --check + - name: "Run clippy on push" if: github.event_name == 'push' run: ci/bin/python scripts/run_tests.py --command clippy - env: - RUSTFLAGS: "-D warnings" - name: "Run cargo doc on push" if: github.event_name == 'push' run: ci/bin/python scripts/run_tests.py --command doc @@ -95,17 +100,17 @@ jobs: - name: "Run taplo" run: scripts/taplo.sh - name: Run Machete (detect unused dependencies) - uses: bnjbvr/cargo-machete@main + run: cargo machete run-workspace-tests: - runs-on: starkware-ubuntu-latest-medium + runs-on: starkware-ubuntu-24.04-medium steps: - uses: actions/checkout@v4 - uses: ./.github/actions/bootstrap - run: cargo test -p workspace_tests run-tests: - runs-on: starkware-ubuntu-latest-large + runs-on: starkware-ubuntu-24.04-large steps: - uses: actions/checkout@v4 with: @@ -122,7 +127,10 @@ jobs: - env: LD_LIBRARY_PATH: ${{ env.Python3_ROOT_DIR }}/bin run: echo "LD_LIBRARY_PATH=${LD_LIBRARY_PATH}" >> $GITHUB_ENV + # TODO(Gilad): only one test needs this (base_layer_test.rs), once it migrates to + # anvil, remove. - run: npm install -g ganache@7.4.3 + - name: "Run tests pull request" if: github.event_name == 'pull_request' run: | @@ -131,73 +139,26 @@ jobs: ci/bin/python scripts/run_tests.py --command test --changes_only --include_dependencies --commit_id ${{ github.event.pull_request.base.sha }} env: SEED: 0 - RUSTFLAGS: "-D warnings" - - - name: "Run tests on push" - if: github.event_name == 'push' - # TODO: Better support for running tests on push. - run: | - python3 -m venv ci - ci/bin/pip install -r scripts/requirements.txt - ci/bin/python scripts/run_tests.py --command test - env: - SEED: 0 - RUSTFLAGS: "-D warnings" - - codecov: - runs-on: starkware-ubuntu-latest-large - steps: - - uses: actions/checkout@v4 - with: - # Fetch the entire history. - fetch-depth: 0 - - uses: ./.github/actions/bootstrap - - - name: Install cargo-llvm-cov - uses: taiki-e/install-action@cargo-llvm-cov - - run: npm install -g ganache@7.4.3 - - # Setup pypy and link to the location expected by .cargo/config.toml. - - uses: actions/setup-python@v5 - id: setup-pypy - with: - python-version: "pypy3.9" - - run: ln -s '${{ steps.setup-pypy.outputs.python-path }}' /usr/local/bin/pypy3.9 - - env: - LD_LIBRARY_PATH: ${{ env.Python3_ROOT_DIR }}/bin - run: echo "LD_LIBRARY_PATH=${LD_LIBRARY_PATH}" >> $GITHUB_ENV - - name: "Run codecov on pull request" - id: run_codecov_pr + - name: "Run integration tests pull request" if: github.event_name == 'pull_request' + # TODO(Tsabary): Find a better way to set the ephemeral port range. run: | python3 -m venv ci ci/bin/pip install -r scripts/requirements.txt - ci/bin/python scripts/run_tests.py --command codecov --changes_only --commit_id ${{ github.event.pull_request.base.sha }} - if [ -f codecov.json ]; then - echo "codecov_output=true" >> $GITHUB_OUTPUT - else - echo "codecov_output=false" >> $GITHUB_OUTPUT - fi + echo "net.ipv4.ip_local_port_range = 40000 40200" | sudo tee /etc/sysctl.conf + sudo sysctl -p + ci/bin/python scripts/run_tests.py --command integration --changes_only --include_dependencies --commit_id ${{ github.event.pull_request.base.sha }} env: SEED: 0 - - name: "Run codecov on push" + - name: "Run tests on push" if: github.event_name == 'push' - # TODO: Better support for running tests on push. + # TODO(AdiY/Dori): Better support for running tests on push. run: | python3 -m venv ci ci/bin/pip install -r scripts/requirements.txt - ci/bin/python scripts/run_tests.py --command codecov - echo "codecov_output=true" >> $GITHUB_OUTPUT + ci/bin/python scripts/run_tests.py --command test env: SEED: 0 - - name: Codecov - if: steps.run_codecov_pr.outputs.codecov_output == 'true' - uses: codecov/codecov-action@v3 - with: - token: ${{ secrets.CODECOV_TOKEN }} - verbose: true - fail_ci_if_error: true - version: "v0.1.15" diff --git a/.github/workflows/main_nightly.yml b/.github/workflows/main_nightly.yml new file mode 100644 index 00000000000..37cba63bcc6 --- /dev/null +++ b/.github/workflows/main_nightly.yml @@ -0,0 +1,56 @@ +name: Main-CI-Nightly +on: + schedule: + - cron: "0 0 * * *" # Runs at 00:00 UTC every day + workflow_dispatch: + +env: + RUSTFLAGS: "-D warnings -C link-arg=-fuse-ld=lld" + +jobs: + codecov: + runs-on: starkware-ubuntu-24.04-large + steps: + - uses: actions/checkout@v4 + - uses: ./.github/actions/bootstrap + - run: npm install -g ganache@7.4.3 + - name: Install cargo-llvm-cov + uses: taiki-e/install-action@cargo-llvm-cov + + - name: "Run codecov" + run: cargo llvm-cov --codecov --output-path codecov.json + env: + SEED: 0 + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v5 + with: + token: ${{ secrets.CODECOV_TOKEN }} + verbose: true + + feature_combos: + runs-on: starkware-ubuntu-24.04-large + steps: + - uses: actions/checkout@v4 + + # Setup pypy and link to the location expected by .cargo/config.toml. + - uses: actions/setup-python@v5 + id: setup-pypy + with: + python-version: "pypy3.9" + - run: ln -s '${{ steps.setup-pypy.outputs.python-path }}' /usr/local/bin/pypy3.9 + - env: + LD_LIBRARY_PATH: ${{ steps.setup-pypy.outputs.pythonLocation }}/bin + run: echo "LD_LIBRARY_PATH=${LD_LIBRARY_PATH}" >> $GITHUB_ENV + + # Install rust components. + - uses: ./.github/actions/bootstrap + + - name: Setup Python venv + run: | + python3 -m venv ci + ci/bin/pip install -r scripts/requirements.txt + + # Run feature combo test. + - name: "Run feature combo on all crates." + run: ci/bin/python scripts/run_feature_combos_test.py diff --git a/.github/workflows/main_pr.yml b/.github/workflows/main_pr.yml index a3d5cfe0946..fd103783716 100644 --- a/.github/workflows/main_pr.yml +++ b/.github/workflows/main_pr.yml @@ -1,6 +1,7 @@ name: Main-CI-PR-Flow on: + merge_group: pull_request: types: - opened @@ -9,14 +10,21 @@ on: - auto_merge_enabled - edited +env: + RUSTFLAGS: "-D warnings -C link-arg=-fuse-ld=lld" + # On PR events, cancel existing CI runs on this same PR for this workflow. +# Also, create different concurrency groups for different pushed commits, on push events. concurrency: - group: ${{ github.workflow }}-${{ github.ref }}-${{ github.job }} + group: > + ${{ github.workflow }}- + ${{ github.ref }}- + ${{ github.event_name == 'pull_request' && 'PR' || github.sha }} cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: commitlint: - runs-on: starkware-ubuntu-latest-small + runs-on: starkware-ubuntu-24.04-small steps: - uses: actions/checkout@v4 with: @@ -39,7 +47,7 @@ jobs: run: echo "$TITLE" | commitlint --verbose merge-gatekeeper: - runs-on: starkware-ubuntu-latest-small + runs-on: starkware-ubuntu-24.04-small # Restrict permissions of the GITHUB_TOKEN. # Docs: https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs permissions: @@ -51,7 +59,7 @@ jobs: uses: upsidr/merge-gatekeeper@v1 with: token: ${{ secrets.GITHUB_TOKEN }} - timeout: 1500 + timeout: 1800 interval: 30 ignored: "code-review/reviewable" @@ -61,6 +69,6 @@ jobs: with: token: ${{ secrets.GITHUB_TOKEN }} ref: ${{github.ref}} - timeout: 1500 + timeout: 1800 interval: 30 ignored: "code-review/reviewable" diff --git a/.github/workflows/merge_paths_ci.yml b/.github/workflows/merge_paths_ci.yml index 200aa1b5737..a5fc183da34 100644 --- a/.github/workflows/merge_paths_ci.yml +++ b/.github/workflows/merge_paths_ci.yml @@ -17,13 +17,17 @@ on: - 'scripts/merge_status.py' # On PR events, cancel existing CI runs on this same PR for this workflow. +# Also, create different concurrency groups for different pushed commits, on push events. concurrency: - group: ${{ github.workflow }}-${{ github.ref }}-${{ github.job }} + group: > + ${{ github.workflow }}- + ${{ github.ref }}- + ${{ github.event_name == 'pull_request' && 'PR' || github.sha }} cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: merge-paths-test: - runs-on: starkware-ubuntu-latest-small + runs-on: starkware-ubuntu-24.04-small steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 diff --git a/.github/workflows/merge_queue_ci.yml b/.github/workflows/merge_queue_ci.yml new file mode 100644 index 00000000000..7c13167f094 --- /dev/null +++ b/.github/workflows/merge_queue_ci.yml @@ -0,0 +1,52 @@ +name: Merge-queue-CI-Flow + +on: + merge_group: + types: + - checks_requested + +env: + CI: 1 + RUSTFLAGS: "-D warnings -C link-arg=-fuse-ld=lld" + EXTRA_RUST_TOOLCHAINS: nightly-2024-04-29 + +jobs: + code_style: + runs-on: starkware-ubuntu-24.04-medium + steps: + # Environment setup. + - uses: actions/checkout@v4 + + # Setup pypy and link to the location expected by .cargo/config.toml. + - uses: actions/setup-python@v5 + id: setup-pypy + with: + python-version: "pypy3.9" + - run: ln -s '${{ steps.setup-pypy.outputs.python-path }}' /usr/local/bin/pypy3.9 + - env: + LD_LIBRARY_PATH: ${{ steps.setup-pypy.outputs.pythonLocation }}/bin + run: echo "LD_LIBRARY_PATH=${LD_LIBRARY_PATH}" >> $GITHUB_ENV + + # Install rust components. + - uses: ./.github/actions/bootstrap + with: + extra_rust_toolchains: ${{ env.EXTRA_RUST_TOOLCHAINS }} + + - name: Setup Python venv + run: | + python3 -m venv ci + ci/bin/pip install -r scripts/requirements.txt + + # Check Cargo.lock is up to date. + - name: "Check Cargo.lock" + run: | + cargo update -w --locked + git diff --exit-code Cargo.lock + + - name: "Run clippy on merge queue" + run: ci/bin/python scripts/run_tests.py --command clippy + + - name: "Run rustfmt on merge queue" + # The nightly here is coupled with the one in install_rust/action.yml. + # If we move the install here we can use a const. + run: cargo +"$EXTRA_RUST_TOOLCHAINS" fmt --all -- --check diff --git a/.github/workflows/papyrus/helm-install.yml b/.github/workflows/papyrus/helm-install.yml index 886f307f09d..6f178612007 100644 --- a/.github/workflows/papyrus/helm-install.yml +++ b/.github/workflows/papyrus/helm-install.yml @@ -14,7 +14,7 @@ on: jobs: deploy-teardown: - runs-on: starkware-ubuntu-latest-small + runs-on: starkware-ubuntu-24.04-small permissions: contents: "read" id-token: "write" diff --git a/.github/workflows/papyrus_benchmark.yaml b/.github/workflows/papyrus_benchmark.yaml index b7912e49572..12ca7784879 100644 --- a/.github/workflows/papyrus_benchmark.yaml +++ b/.github/workflows/papyrus_benchmark.yaml @@ -2,13 +2,13 @@ name: Papyrus-Benchmarks on: workflow_dispatch: - # TODO: Uncomment and run this automatically when the storage benchmark is fixed. + # TODO(DanB): Uncomment and run this automatically when the storage benchmark is fixed. # push: # branches: [main] jobs: storage-benchmark: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 permissions: contents: "write" id-token: "write" diff --git a/.github/workflows/papyrus_ci.yml b/.github/workflows/papyrus_ci.yml index ca95f588373..d46c1d7bac9 100644 --- a/.github/workflows/papyrus_ci.yml +++ b/.github/workflows/papyrus_ci.yml @@ -9,84 +9,87 @@ on: - auto_merge_enabled - edited # for when the PR title is edited paths: - - '.github/workflows/papyrus_ci.yml' - - 'Dockerfile' - - 'papyrus_utilities.Dockerfile' - - 'Cargo.toml' - - 'Cargo.lock' - - 'crates/papyrus**/**' - - 'crates/sequencing/**' - - 'crates/starknet_client/**' - - 'scripts/dependencies.sh' + - ".github/workflows/papyrus_ci.yml" + - "deployments/images/base/Dockerfile" + - "papyrus_utilities.Dockerfile" + - "Cargo.toml" + - "Cargo.lock" + - "crates/papyrus**/**" + - "crates/starknet_client/**" + - "scripts/dependencies.sh" - merge_group: - types: [checks_requested] +env: + RUSTFLAGS: "-D warnings -C link-arg=-fuse-ld=lld" # On PR events, cancel existing CI runs on this same PR for this workflow. +# Also, create different concurrency groups for different pushed commits, on push events. concurrency: - group: ${{ github.workflow }}-${{ github.ref }}-${{ github.job }} + group: > + ${{ github.workflow }}- + ${{ github.ref }}- + ${{ github.event_name == 'pull_request' && 'PR' || github.sha }} cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: executable-run: - runs-on: starkware-ubuntu-latest-medium + runs-on: starkware-ubuntu-24.04-medium steps: - uses: actions/checkout@v4 - uses: ./.github/actions/bootstrap - name: Build node run: | mkdir data - cargo build -r -p papyrus_node + cargo build -p papyrus_node - name: Run executable run: > - target/release/papyrus_node --base_layer.node_url ${{ secrets.CI_BASE_LAYER_NODE_URL }} + target/debug/papyrus_node --chain_id SN_SEPOLIA --base_layer.node_url ${{ secrets.CI_BASE_LAYER_NODE_URL }} & sleep 30 ; kill $! executable-run-no-rpc: - runs-on: starkware-ubuntu-latest-medium + runs-on: starkware-ubuntu-24.04-medium steps: - uses: actions/checkout@v4 - uses: ./.github/actions/bootstrap - name: Build node run: | mkdir data - cargo build -r -p papyrus_node --no-default-features + cargo build -p papyrus_node --no-default-features - name: Run executable run: > - target/release/papyrus_node --base_layer.node_url ${{ secrets.CI_BASE_LAYER_NODE_URL }} + target/debug/papyrus_node --chain_id SN_SEPOLIA --base_layer.node_url ${{ secrets.CI_BASE_LAYER_NODE_URL }} & sleep 30 ; kill $! # FIXME: Job is currently running out of disk space, error is hidden inside the `Annoatations` # tab on github. FIX THE ISSUE AND RE-ENABLE THE JOB. # p2p-sync-e2e-test: - # runs-on: ubuntu-latest + # runs-on: starkware-ubuntu-24.04-medium # steps: # - uses: actions/checkout@v4 # - uses: ./.github/actions/bootstrap # - name: Build node - # run: cargo build -r -p papyrus_node + # run: cargo build -p papyrus_node # - name: Run p2p sync end-to-end test # run: scripts/papyrus/p2p_sync_e2e_test/main.sh ${{ secrets.CI_BASE_LAYER_NODE_URL }} integration-test: - runs-on: starkware-ubuntu-latest-medium + runs-on: starkware-ubuntu-24.04-medium steps: - uses: actions/checkout@v4 - uses: ./.github/actions/bootstrap - run: > - cargo test -r + cargo test --test latency_histogram --test gateway_integration_test --test feeder_gateway_integration_test -- --include-ignored --skip test_gw_integration_testnet; - cargo run -r -p papyrus_node --bin central_source_integration_test --features="futures-util tokio-stream" + cargo run -p papyrus_node --bin central_source_integration_test --features="futures-util tokio-stream" test-no-rpc: - runs-on: starkware-ubuntu-latest-medium + runs-on: starkware-ubuntu-24.04-medium steps: - uses: actions/checkout@v4 - uses: ./.github/actions/bootstrap @@ -95,25 +98,23 @@ jobs: env: SEED: 0 - - build-papyrus-utilities-image: - runs-on: starkware-ubuntu-latest-medium - steps: - - uses: actions/checkout@v4 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - name: Build Papyrus utilites docker image - uses: docker/build-push-action@v3.2.0 - continue-on-error: true # ignore the failure of a step and avoid terminating the job. - with: - push: false - context: . - file: papyrus_utilities.Dockerfile - cache-from: type=gha,scope=buildkit-ci - cache-to: type=gha,mode=max,scope=buildkit-ci + # TODO(DanB): Re-enable this job when necessary. + # Note that currently the `papyrus_load_test` build fails. + # build-papyrus-utilities-image: + # runs-on: starkware-ubuntu-24.04-medium + # steps: + # - uses: actions/checkout@v4 + # - name: Set up Docker Buildx + # uses: docker/setup-buildx-action@v3 + # - name: Build Papyrus utilites docker image + # uses: docker/build-push-action@v3.2.0 + # with: + # push: false + # context: . + # file: papyrus_utilities.Dockerfile random-table-test: - runs-on: starkware-ubuntu-latest-medium + runs-on: starkware-ubuntu-24.04-medium steps: - uses: actions/checkout@v4 # run this job only if the path 'crates/papyrus_storage/src/db/**' is changed, because it takes around 2 minutes. @@ -129,5 +130,5 @@ jobs: - 'crates/papyrus_storage/src/db/**' - uses: ./.github/actions/bootstrap # repeat this job 32 times. this is a random test for part of the code that may cause a corrupted database. - - run: for run in {1..32}; do cargo test -r -p papyrus_storage -- --include-ignored common_prefix_compare_with_simple_table_random; done + - run: for run in {1..32}; do cargo test -p papyrus_storage -- --include-ignored common_prefix_compare_with_simple_table_random; done if: steps.changes.outputs.target_directory == 'true' diff --git a/.github/workflows/papyrus_docker-publish.yml b/.github/workflows/papyrus_docker-publish.yml index bf2559ce2b1..038a72110ee 100644 --- a/.github/workflows/papyrus_docker-publish.yml +++ b/.github/workflows/papyrus_docker-publish.yml @@ -3,8 +3,12 @@ name: Papyrus-Docker-Publish on: workflow_dispatch: push: - branches: [main] - tags: ["v*.*.*"] + branches: + - main + - main-v[0-9].** + tags: + - v[0-9].** + - papyrus-v[0-9].** paths: - '.github/workflows/papyrus_docker-publish.yml' - 'crates/papyrus**/**' @@ -21,17 +25,22 @@ on: - 'deployments/images/papyrus/Dockerfile' # On PR events, cancel existing CI runs on this same PR for this workflow. +# Also, create different concurrency groups for different pushed commits, on push events. concurrency: - group: ${{ github.workflow }}-${{ github.ref }}-${{ github.job }} + group: > + ${{ github.workflow }}- + ${{ github.ref }}- + ${{ github.event_name == 'pull_request' && 'PR' || github.sha }} cancel-in-progress: ${{ github.event_name == 'pull_request' }} env: REGISTRY: ghcr.io REPO_NAME: ${{ github.repository }} + RUSTFLAGS: "-D warnings -C link-arg=-fuse-ld=lld" jobs: docker-build-push: - runs-on: starkware-ubuntu-latest-large + runs-on: starkware-ubuntu-24.04-large steps: - name: Checkout repository @@ -66,19 +75,21 @@ jobs: type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} type=ref,event=pr - # set `dev` tag for the default branch (`main`). - type=raw,value=dev,enable={{is_default_branch}} + # set `main*` tag for the default / release branches. + type=raw,value={{branch}},enable=${{ github.event_name == 'push' && contains(github.ref, 'main') }} + # set `{branch}-{tag}` tag for tag push events. + type=raw,value={{tag}},enable=${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags') }} + # For manual triggers of the workflow: type=raw,value={{branch}}{{tag}}-{{sha}},enable=${{ github.event_name == 'workflow_dispatch' }} # Build and push Docker image with Buildx # https://github.com/docker/build-push-action - name: Build and push Docker image - uses: docker/build-push-action@v3.2.0 + uses: docker/build-push-action@v6.13.0 with: context: . file: deployments/images/papyrus/Dockerfile push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - cache-from: type=gha - cache-to: type=gha,mode=max + no-cache: true diff --git a/.github/workflows/papyrus_nightly-tests-call.yml b/.github/workflows/papyrus_nightly-tests-call.yml index d05d1938e09..6171e514e6c 100644 --- a/.github/workflows/papyrus_nightly-tests-call.yml +++ b/.github/workflows/papyrus_nightly-tests-call.yml @@ -16,6 +16,9 @@ on: SLACK_ALERT_CHANNEL: required: true +env: + RUSTFLAGS: "-D warnings -C link-arg=-fuse-ld=lld" + jobs: GW-integration-test-call: runs-on: ${{ inputs.os }} diff --git a/.github/workflows/papyrus_nightly-tests.yml b/.github/workflows/papyrus_nightly-tests.yml index 0592f28e3e5..440b85ac48d 100644 --- a/.github/workflows/papyrus_nightly-tests.yml +++ b/.github/workflows/papyrus_nightly-tests.yml @@ -6,11 +6,14 @@ on: - cron: '30 0 * * *' # Uses macos runner. workflow_dispatch: # Uses ubuntu runner. +env: + RUSTFLAGS: "-D warnings -C link-arg=-fuse-ld=lld" + jobs: GW-integration-test-ubuntu: uses: ./.github/workflows/papyrus_nightly-tests-call.yml with: - os: starkware-ubuntu-latest-medium + os: starkware-ubuntu-24.04-medium secrets: INTEGRATION_TESTNET_NODE_URL: ${{ secrets.INTEGRATION_TESTNET_NODE_URL }} INTEGRATION_TESTNET_SENDER_PRIVATE_KEY: ${{ secrets.INTEGRATION_TESTNET_SENDER_PRIVATE_KEY }} @@ -39,11 +42,11 @@ jobs: - run: mkdir data - name: Build node - run: cargo build -r -p papyrus_node + run: cargo build -p papyrus_node - name: Run executable run: > - target/release/papyrus_node --base_layer.node_url ${{ secrets.CI_BASE_LAYER_NODE_URL }} + target/debug/papyrus_node --base_layer.node_url ${{ secrets.CI_BASE_LAYER_NODE_URL }} & sleep 30 ; kill $! test: @@ -54,9 +57,8 @@ jobs: - uses: ./.github/actions/bootstrap - run: npm install -g ganache@7.4.3 - - run: | - cargo test -r -p papyrus_node + cargo test -p papyrus_node env: SEED: 0 @@ -66,7 +68,7 @@ jobs: steps: - uses: actions/checkout@v4 - uses: ./.github/actions/bootstrap - - run: cargo build -r -p papyrus_load_test + - run: cargo build -p papyrus_load_test integration-test: runs-on: macos-latest @@ -75,18 +77,18 @@ jobs: - uses: actions/checkout@v4 - uses: ./.github/actions/bootstrap - run: > - cargo test -r + cargo test --test latency_histogram --test gateway_integration_test --test feeder_gateway_integration_test -- --include-ignored --skip test_gw_integration_testnet; - cargo run -r -p papyrus_node --bin central_source_integration_test --features="futures-util tokio-stream" + cargo run -p papyrus_node --bin central_source_integration_test --features="futures-util tokio-stream" # TODO(dvir): make this run only if the path 'crates/papyrus_storage/src/db/**' (same path as in the CI) was changed on the # last day and increase the number of repetitions. random-table-test: - runs-on: starkware-ubuntu-latest-medium + runs-on: starkware-ubuntu-24.04-medium steps: - uses: actions/checkout@v4 - uses: ./.github/actions/bootstrap - - run: for run in {1..100}; do cargo test -r -p papyrus_storage -- --include-ignored common_prefix_compare_with_simple_table_random; done + - run: for run in {1..100}; do cargo test -p papyrus_storage -- --include-ignored common_prefix_compare_with_simple_table_random; done diff --git a/.github/workflows/sequencer_cdk8s-test.yml b/.github/workflows/sequencer_cdk8s-test.yml new file mode 100644 index 00000000000..904db0c2681 --- /dev/null +++ b/.github/workflows/sequencer_cdk8s-test.yml @@ -0,0 +1,63 @@ +name: Sequencer-Cdk8s-Test +on: + push: + branches: + - main + - main-v[0-9].** + tags: + - v[0-9].** + paths: + - ".github/workflows/sequencer_cdk8s-test.yml" + - "config/sequencer" + - "deployments/sequencer" + - "Monitoring/sequencer" + + pull_request: + branches: + - main + - main-v[0-9].** + paths: + - ".github/workflows/sequencer_cdk8s-test.yml" + - "config/sequencer" + - "deployments/sequencer" + - "Monitoring/sequencer" + +jobs: + deployment: + runs-on: ubuntu-24.04 + steps: + - name: Checkout sequencer + uses: actions/checkout@v4 + + - name: Setup python + uses: actions/setup-python@v5.4.0 + with: + python-version: "3.10" + cache: "pip" + + - name: Setup Node + uses: actions/setup-node@v4.2.0 + with: + node-version: 22 + + - name: Install pip dependencies + run: python3 -m pip install black pipenv + + - name: Install cdk8s-cli + run: npm install -g cdk8s-cli@2.198.334 + + - name: Black all files + uses: psf/black@stable + with: + options: "--check --verbose -l 100 -t py310 --diff --color --exclude imports" + src: deployments/sequencer + + # Synthesize the CDK8s Sequencer app. + - name: CDk8s synth + working-directory: deployments/sequencer + env: + deployment_config_path: ${{ github.workspace }}/config/sequencer/deployment_configs/testing/nightly_test_all_in_one.json + run: | + cdk8s import + pipenv install + cdk8s synth --app "pipenv run python main.py --namespace test --deployment-config-file ${{ env.deployment_config_path }}" diff --git a/.github/workflows/sequencer_docker-publish.yml b/.github/workflows/sequencer_docker-publish.yml new file mode 100644 index 00000000000..c5027ed208f --- /dev/null +++ b/.github/workflows/sequencer_docker-publish.yml @@ -0,0 +1,93 @@ +name: Sequencer-Docker-Publish + +on: + workflow_dispatch: + push: + branches: [main] + tags: ["v*.*.*"] + paths: + - '.github/workflows/sequencer_docker-publish.yml' + - 'crates/**' + - 'scripts/dependencies.sh' + - 'scripts/install_build_tools.sh' + - 'deployments/images/base/Dockerfile' + - 'deployments/images/sequencer/Dockerfile' + + pull_request: + paths: + - '.github/workflows/sequencer_docker-publish.yml' + - 'crates/**' + - 'scripts/dependencies.sh' + - 'scripts/install_build_tools.sh' + - 'deployments/images/base/Dockerfile' + - 'deployments/images/sequencer/Dockerfile' + +permissions: + contents: read + packages: write + +# On PR events, cancel existing CI runs on this same PR for this workflow. +concurrency: + group: ${{ github.workflow }}-${{ github.ref }}-${{ github.job }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +env: + REGISTRY: ghcr.io + REPO_NAME: ${{ github.repository }} + RUSTFLAGS: "-D warnings -C link-arg=-fuse-ld=lld" + +jobs: + docker-build-push: + runs-on: starkware-ubuntu-24.04-large + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + # Not required but recommended - enables build multi-platform images, export cache, etc + # Also workaround for: https://github.com/docker/build-push-action/issues/461 + # https://github.com/docker/setup-buildx-action + - name: Setup Docker buildx + uses: docker/setup-buildx-action@v2.2.1 + + # Login to a Docker registry except on PR + # https://github.com/docker/login-action + - name: Login to registry ${{ env.REGISTRY }} + if: github.event_name != 'pull_request' + uses: docker/login-action@v2.1.0 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + logout: true + + # Extract metadata (tags, labels) for Docker + # https://github.com/docker/metadata-action + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@v4.1.1 + with: + images: ${{ env.REGISTRY }}/${{ env.REPO_NAME }}/sequencer + tags: | + type=semver,pattern={{raw}} + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=ref,event=pr + # set `dev` tag for the default branch (`main`). + type=raw,value=dev,enable={{is_default_branch}} + # set `dev-{{branch}}-{{sha}}` additional tag for the default branch (`main`). + type=raw,value=dev-{{branch}}{{tag}}-{{sha}},enable={{is_default_branch}} + type=raw,value={{branch}}{{tag}}-{{sha}},enable=${{ github.event_name == 'workflow_dispatch' }} + + # Build and push Docker image with Buildx + # https://github.com/docker/build-push-action + - name: Build and push Docker image + uses: docker/build-push-action@v6.13.0 + with: + context: . + file: deployments/images/sequencer/Dockerfile + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + load: true # Loads the build result to docker images. Required for "Run docker test" step to work. + no-cache: true diff --git a/.github/workflows/sequencer_docker-test.yml b/.github/workflows/sequencer_docker-test.yml new file mode 100644 index 00000000000..a7335b02278 --- /dev/null +++ b/.github/workflows/sequencer_docker-test.yml @@ -0,0 +1,110 @@ +name: Sequencer-Docker-Test + +on: + workflow_dispatch: + push: + branches: [main] + tags: ["v*.*.*"] + paths: + - ".github/workflows/sequencer_docker-test.yml" + - "crates/**" + - "scripts/dependencies.sh" + - "scripts/install_build_tools.sh" + - "deployments/images/base/Dockerfile" + - "deployments/images/sequencer/**" + - "deployments/monitoring/deploy_local_stack.sh" + - "deployments/monitoring/local/docker-compose.yml" + - "deployments/monitoring/local/.env" + + pull_request: + paths: + - ".github/workflows/sequencer_docker-test.yml" + - "crates/**" + - "scripts/dependencies.sh" + - "scripts/install_build_tools.sh" + - "deployments/images/base/Dockerfile" + - "deployments/images/sequencer/**" + - "deployments/monitoring/deploy_local_stack.sh" + - "deployments/monitoring/local/docker-compose.yml" + - "deployments/monitoring/local/.env" + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }}-${{ github.job }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +jobs: + sequencer_docker_compose_test: + runs-on: starkware-ubuntu-24.04-large + env: + MONITORING_ENABLED: false + SIMULATOR_RUN_FOREVER: false + FOLLOW_LOGS: false + SIMULATOR_TIMEOUT: 300 + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + # Not required but recommended - enables build multi-platform images, export cache, etc + # Also workaround for: https://github.com/docker/build-push-action/issues/461 + # https://github.com/docker/setup-buildx-action + - name: Setup Docker buildx + uses: docker/setup-buildx-action@v2.2.1 + + - name: Run docker compose + run: ./deployments/monitoring/deploy_local_stack.sh up -d --build + + # Getting the sequencer_simulator container id, then + # Invoking `docker wait $container_id`. + # docker wait will return the container exit_code. + - name: Wait for simulator results + working-directory: ./deployments/monitoring/local + timeout-minutes: 5 + run: | + simulator_id=$(docker compose ps -q sequencer_simulator 2>/dev/null) + exit_code=$(docker wait $simulator_id) + if (( $exit_code == 0 )); then + echo "✅ Simulator test succeeded. exit_code=$exit_code" + else + echo "❌ Simulator test failed. exit_code=$exit_code" + exit $exit_code + fi + + # Printing all services logs separately. Makes it more readable later. + - name: Print sequencer_node_setup logs + if: always() + working-directory: ./deployments/monitoring/local + run: docker compose logs sequencer_node_setup + + - name: Print dummy_recorder logs + if: always() + working-directory: ./deployments/monitoring/local + run: docker compose logs dummy_recorder + + - name: Print dummy_eth_to_strk_oracle logs + if: always() + working-directory: ./deployments/monitoring/local + run: docker compose logs dummy_eth_to_strk_oracle + + - name: Print config_injector logs + if: always() + working-directory: ./deployments/monitoring/local + run: docker compose logs config_injector + + - name: Print sequencer_node logs + if: always() + working-directory: ./deployments/monitoring/local + run: docker compose logs sequencer_node + + - name: Print sequencer_simulator logs + if: always() + working-directory: ./deployments/monitoring/local + run: docker compose logs sequencer_simulator + + # Shutting down all containers and cleaning volumes. + - name: Cleanup + if: always() + run: ./deployments/monitoring/deploy_local_stack.sh down -v diff --git a/.github/workflows/trigger _workflow.yml b/.github/workflows/trigger _workflow.yml deleted file mode 100644 index de9bcdb7772..00000000000 --- a/.github/workflows/trigger _workflow.yml +++ /dev/null @@ -1,52 +0,0 @@ -name: Trigger-Workflow - -# This workflow exists to trigger the upload_artifacts workflow on both pull requests and push -# events. It solves the issue of forked PRs not having access to secrets. Since external -# contributors don’t have permission to access secrets, this dummy workflow runs with their -# privileges and triggers the upload_artifacts workflow via the workflow_run event. -# The upload_artifacts workflow runs in the context of the main branch, where it has access to -# the necessary secrets for uploading artifacts, providing a secure solution for managing artifacts -# in forked PRs. - -on: - push: - branches: - - main - - main-v[0-9].** - tags: - - v[0-9].** - - pull_request: - types: - - opened - - reopened - - synchronize - - auto_merge_enabled - - edited - paths: - # Other than code-related changes, all changes related to the native-blockifier build-and-push - # process should trigger the build (e.g., changes to the Dockerfile, build scripts, etc.). - - '.github/workflows/blockifier_ci.yml' - - '.github/workflows/trigger_workflow.yml' - - '.github/workflows/upload_artifacts_workflow.yml' - - 'build_native_in_docker.sh' - - 'Cargo.lock' - - 'Cargo.toml' - - 'crates/blockifier/**' - - 'crates/native_blockifier/**' - - 'scripts/build_native_blockifier.sh' - - 'scripts/dependencies.sh' - - 'scripts/install_build_tools.sh' - - 'scripts/sequencer-ci.Dockerfile' - -# On PR events, cancel existing CI runs on this same PR for this workflow. -concurrency: - group: ${{ github.workflow }}-${{ github.ref }}-${{ github.job }} - cancel-in-progress: ${{ github.event_name == 'pull_request' }} - -jobs: - dummy_job: - runs-on: starkware-ubuntu-latest-small - steps: - - name: Dummy step - run: echo "This is a dummy job to trigger the upload_artifacts workflow." diff --git a/.github/workflows/upload_artifacts_workflow.yml b/.github/workflows/upload_artifacts_workflow.yml index 579aa8b3901..434c02659b2 100644 --- a/.github/workflows/upload_artifacts_workflow.yml +++ b/.github/workflows/upload_artifacts_workflow.yml @@ -1,73 +1,116 @@ name: Upload-Artifacts on: - workflow_run: - workflows: [Trigger-Workflow] - types: [completed] + push: + branches: + - main + - main-v[0-9].** + tags: + - v[0-9].** + + pull_request: + types: + - opened + - reopened + - synchronize + - auto_merge_enabled + - edited + paths: + # Other than code-related changes, all changes related to the native-blockifier build-and-push + # process should trigger the build (e.g., changes to the Dockerfile, build scripts, etc.). + - '.github/workflows/blockifier_ci.yml' + - '.github/workflows/upload_artifacts_workflow.yml' + - 'build_native_in_docker.sh' + - 'docker-ci/images/sequencer-ci.Dockerfile' + - 'scripts/build_native_blockifier.sh' + - 'scripts/dependencies.sh' + - 'scripts/install_build_tools.sh' + - 'Cargo.lock' + - 'Cargo.toml' + - 'crates/blockifier/**' + - 'crates/native_blockifier/**' + - 'crates/papyrus_state_reader/**' + - 'crates/papyrus_storage/**' + - 'crates/starknet_api/**' + - 'crates/starknet_sierra_multicompile/**' + - 'rust-toolchain.toml' + +# On PR events, cancel existing CI runs on this same PR for this workflow. +# Also, create different concurrency groups for different pushed commits, on push events. +concurrency: + group: > + ${{ github.workflow }}- + ${{ github.ref }}- + ${{ github.event_name == 'pull_request' && 'PR' || github.sha }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +env: + RUSTFLAGS: "-D warnings -C link-arg=-fuse-ld=lld" jobs: native-blockifier-artifacts-push: - runs-on: starkware-ubuntu-20-04-medium + runs-on: starkware-ubuntu-24.04-medium steps: + - uses: actions/checkout@v4 + + # Commit hash on pull request event would be the head commit of the branch. - name: Get commit hash prefix for PR update + if: ${{ github.event_name == 'pull_request' }} env: - COMMIT_SHA: ${{ github.event.workflow_run.head_commit.id }} - run: | - echo "SHORT_HASH=${COMMIT_SHA:0:7}" >> $GITHUB_ENV - echo "COMMIT_SHA=${COMMIT_SHA}" >> $GITHUB_ENV + COMMIT_SHA: ${{ github.event.pull_request.head.sha }} + run: echo "SHORT_HASH=${COMMIT_SHA:0:7}" >> $GITHUB_ENV - # This workflow is always triggered in `main` branch context, so need to checkout the commit. - - uses: actions/checkout@v4 - with: - ref: ${{ env.COMMIT_SHA }} + # On push event (to main, for example) we should take the commit post-push. + - name: Get commit hash prefix for merge + if: ${{ github.event_name != 'pull_request' }} + env: + COMMIT_SHA: ${{ github.event.after }} + run: echo "SHORT_HASH=${COMMIT_SHA:0:7}" >> $GITHUB_ENV # Set environment variables. - name: Set environment variable env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - pr_number=$(gh pr list --head "${{ github.event.workflow_run.head_branch }}" --json number --jq '.[0].number') - echo "PR_NUMBER=$pr_number" >> $GITHUB_ENV echo "WORKFLOW_LINK=$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" >> $GITHUB_ENV # Comment with a link to the workflow (or update existing comment on rerun). - # Required, as this is a triggered workflow, and does not appear on the PR status page. - name: Find Comment - if: env.PR_NUMBER != '' + if: github.event_name == 'pull_request' uses: starkware-libs/find-comment@v3 id: find-comment with: token: ${{ secrets.GITHUB_TOKEN }} - issue-number: ${{ env.PR_NUMBER }} + issue-number: ${{ github.event.pull_request.number }} comment-author: 'github-actions[bot]' body-includes: Artifacts upload workflows - name: Create comment # If the PR number is found and the comment is not found, create a new comment. - if: env.PR_NUMBER != '' && steps.find-comment.outputs.comment-id == '' + if: github.event_name == 'pull_request' && steps.find-comment.outputs.comment-id == '' uses: starkware-libs/create-or-update-comment@v4 with: token: ${{ secrets.GITHUB_TOKEN }} - issue-number: ${{ env.PR_NUMBER }} + issue-number: ${{ github.event.pull_request.number }} body: | Artifacts upload workflows: - * [Started at ${{ github.event.workflow_run.run_started_at }}](${{ env.WORKFLOW_LINK }}) + * [Started at ${{ github.event.pull_request.updated_at }}](${{ env.WORKFLOW_LINK }}) - name: Update comment # If the PR number is found and the comment exists, update it. - if: env.PR_NUMBER != '' && steps.find-comment.outputs.comment-id != '' + if: github.event_name == 'pull_request' && steps.find-comment.outputs.comment-id != '' uses: starkware-libs/create-or-update-comment@v4 with: token: ${{ secrets.GITHUB_TOKEN }} comment-id: ${{ steps.find-comment.outputs.comment-id }} edit-mode: append body: | - * [Started at ${{ github.event.workflow_run.run_started_at }}](${{ env.WORKFLOW_LINK }}) + * [Started at ${{ github.event.pull_request.updated_at }}](${{ env.WORKFLOW_LINK }}) # Build artifact. - - uses: ./.github/actions/bootstrap - name: Build native blockifier - run: ./build_native_in_docker.sh scripts/build_native_blockifier.sh + run: | + ./build_native_in_docker.sh scripts/build_native_blockifier.sh # Rename is required; see https://pyo3.rs/v0.19.2/building_and_distribution#manual-builds. - name: Rename shared object @@ -81,9 +124,16 @@ jobs: with: credentials_json: ${{ secrets.SA_NATIVE_BLOCKIFIER_ARTIFACTS_BUCKET_WRITER_ACCESS_KEY }} - - name: Upload binary to GCP - id: upload_file + - name: Upload native blockifier shared object to GCP + id: upload_nb_file uses: "google-github-actions/upload-cloud-storage@v2" with: path: "target/release/native_blockifier.pypy39-pp73-x86_64-linux-gnu.so" destination: "native_blockifier_artifacts/${{ env.SHORT_HASH }}/release/" + + - name: Upload starknet-native-compile to GCP + id: upload_snc_file + uses: "google-github-actions/upload-cloud-storage@v2" + with: + path: "target/release/shared_executables/starknet-native-compile" + destination: "native_blockifier_artifacts/${{ env.SHORT_HASH }}/release/" diff --git a/.github/workflows/verify-deps.yml b/.github/workflows/verify-deps.yml index 8582cb1b6bc..8838e13ea68 100644 --- a/.github/workflows/verify-deps.yml +++ b/.github/workflows/verify-deps.yml @@ -4,14 +4,17 @@ on: schedule: - cron: '0 0 * * *' # Runs at 00:00 UTC every day +env: + RUSTFLAGS: "-D warnings -C link-arg=-fuse-ld=lld" + jobs: latest_deps: name: Latest Dependencies - runs-on: starkware-ubuntu-latest-medium - continue-on-error: true + runs-on: starkware-ubuntu-24.04-medium steps: - uses: actions/checkout@v4 - uses: ./.github/actions/bootstrap + - run: npm install -g ganache@7.4.3 - name: Update Dependencies run: cargo update --verbose - name: Build diff --git a/.gitignore b/.gitignore index 86d3bfa13c4..fe9c9d53265 100644 --- a/.gitignore +++ b/.gitignore @@ -26,9 +26,13 @@ tmp_venv/* # Git hooks /.husky /.idea +__pycache__/ +.idea/ +**/.venv # Python artifacts. scripts/__pycache__ +monitoring_venv/ # Papyrus p2p sync test artifacts. scripts/papyrus/p2p_sync_e2e_test/data_client/ @@ -38,5 +42,4 @@ scripts/papyrus/p2p_sync_e2e_test/data_server/ deployments/papyrus/helm/config/* !deployments/papyrus/helm/config/example.json -# Generated file used for running contracts compiled with Cairo Native -crates/blockifier/libcairo_native_runtime.a +integration_test_temporary_logs diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 8ce19f6d3e8..00000000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "crates/blockifier/cairo_native"] - path = crates/blockifier/cairo_native - url = https://github.com/lambdaclass/cairo_native diff --git a/BUILD b/BUILD index 2adca64db77..14d5f42ae2b 100644 --- a/BUILD +++ b/BUILD @@ -1,8 +1,9 @@ # Export the built artifact to allow local builds. exports_files([ "target/release/libnative_blockifier.so", - "target/debug/committer_cli", - "target/release/committer_cli", - "target/x86_64-unknown-linux-musl/debug/committer_cli", - "target/x86_64-unknown-linux-musl/release/committer_cli", + "target/release/shared_executables/starknet-native-compile", + "target/debug/starknet_committer_and_os_cli", + "target/release/starknet_committer_and_os_cli", + "target/x86_64-unknown-linux-musl/debug/starknet_committer_and_os_cli", + "target/x86_64-unknown-linux-musl/release/starknet_committer_and_os_cli", ]) diff --git a/Cargo.lock b/Cargo.lock index 3fddafbc6bc..cb5cb457784 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "Inflector" @@ -69,11 +69,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", - "getrandom", + "getrandom 0.2.15", "once_cell", "serde", "version_check", - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -87,15 +87,37 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.18" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "alloy" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbcc41e8a11a4975b18ec6afba2cc48d591fa63336a4c526dacb50479a8d6b35" +dependencies = [ + "alloy-consensus", + "alloy-contract", + "alloy-core", + "alloy-eips", + "alloy-genesis", + "alloy-json-rpc", + "alloy-network", + "alloy-node-bindings", + "alloy-provider", + "alloy-rpc-client", + "alloy-rpc-types", + "alloy-serde", + "alloy-transport", + "alloy-transport-http", +] [[package]] name = "alloy-chains" -version = "0.1.38" +version = "0.1.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "156bfc5dcd52ef9a5f33381701fa03310317e14c65093a9430d3e3557b08dcd3" +checksum = "da226340862e036ab26336dc99ca85311c6b662267c1440e1733890fd688802c" dependencies = [ "alloy-primitives", "num_enum", @@ -104,23 +126,40 @@ dependencies = [ [[package]] name = "alloy-consensus" -version = "0.3.6" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "629b62e38d471cc15fea534eb7283d2f8a4e8bdb1811bcc5d66dda6cfce6fae1" +checksum = "f4138dc275554afa6f18c4217262ac9388790b2fc393c2dfe03c51d357abf013" dependencies = [ "alloy-eips", "alloy-primitives", "alloy-rlp", "alloy-serde", + "alloy-trie", + "auto_impl", "c-kzg", + "derive_more 1.0.0", + "serde", +] + +[[package]] +name = "alloy-consensus-any" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa04e1882c31288ce1028fdf31b6ea94cfa9eafa2e497f903ded631c8c6a42c" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", "serde", ] [[package]] name = "alloy-contract" -version = "0.3.6" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eefe64fd344cffa9cf9e3435ec4e93e6e9c3481bc37269af988bf497faf4a6a" +checksum = "5f21886c1fea0626f755a49b2ac653b396fb345233f6170db2da3d0ada31560c" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", @@ -133,14 +172,27 @@ dependencies = [ "alloy-transport", "futures", "futures-util", - "thiserror", + "thiserror 2.0.12", +] + +[[package]] +name = "alloy-core" +version = "0.8.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0713007d14d88a6edb8e248cddab783b698dbb954a28b8eee4bab21cfb7e578" +dependencies = [ + "alloy-dyn-abi", + "alloy-json-abi", + "alloy-primitives", + "alloy-rlp", + "alloy-sol-types", ] [[package]] name = "alloy-dyn-abi" -version = "0.8.7" +version = "0.8.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f95d76a38cae906fd394a5afb0736aaceee5432efe76addfd71048e623e208af" +checksum = "44e3b98c37b3218924cd1d2a8570666b89662be54e5b182643855f783ea68b33" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -150,7 +202,7 @@ dependencies = [ "itoa", "serde", "serde_json", - "winnow 0.6.20", + "winnow 0.6.22", ] [[package]] @@ -166,20 +218,21 @@ dependencies = [ [[package]] name = "alloy-eip7702" -version = "0.1.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea59dc42102bc9a1905dc57901edc6dd48b9f38115df86c7d252acba70d71d04" +checksum = "9b15b13d38b366d01e818fe8e710d4d702ef7499eacd44926a06171dd9585d0c" dependencies = [ "alloy-primitives", "alloy-rlp", "serde", + "thiserror 2.0.12", ] [[package]] name = "alloy-eips" -version = "0.3.6" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f923dd5fca5f67a43d81ed3ebad0880bd41f6dd0ada930030353ac356c54cd0f" +checksum = "52dd5869ed09e399003e0e0ec6903d981b2a92e74c5d37e6b40890bad2517526" dependencies = [ "alloy-eip2930", "alloy-eip7702", @@ -193,11 +246,24 @@ dependencies = [ "sha2", ] +[[package]] +name = "alloy-genesis" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7d2a7fe5c1a9bd6793829ea21a636f30fc2b3f5d2e7418ba86d96e41dd1f460" +dependencies = [ + "alloy-eips", + "alloy-primitives", + "alloy-serde", + "alloy-trie", + "serde", +] + [[package]] name = "alloy-json-abi" -version = "0.8.7" +version = "0.8.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c66eec1acdd96b39b995b8f5ee5239bc0c871d62c527ae1ac9fd1d7fecd455" +checksum = "731ea743b3d843bc657e120fb1d1e9cc94f5dab8107e35a82125a63e6420a102" dependencies = [ "alloy-primitives", "alloy-sol-type-parser", @@ -207,29 +273,31 @@ dependencies = [ [[package]] name = "alloy-json-rpc" -version = "0.3.6" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3c717b5298fad078cd3a418335b266eba91b511383ca9bd497f742d5975d5ab" +checksum = "2008bedb8159a255b46b7c8614516eda06679ea82f620913679afbd8031fea72" dependencies = [ "alloy-primitives", "alloy-sol-types", "serde", "serde_json", - "thiserror", + "thiserror 2.0.12", "tracing", ] [[package]] name = "alloy-network" -version = "0.3.6" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb3705ce7d8602132bcf5ac7a1dd293a42adc2f183abf5907c30ac535ceca049" +checksum = "4556f01fe41d0677495df10a648ddcf7ce118b0e8aa9642a0e2b6dd1fb7259de" dependencies = [ "alloy-consensus", + "alloy-consensus-any", "alloy-eips", "alloy-json-rpc", "alloy-network-primitives", "alloy-primitives", + "alloy-rpc-types-any", "alloy-rpc-types-eth", "alloy-serde", "alloy-signer", @@ -237,26 +305,46 @@ dependencies = [ "async-trait", "auto_impl", "futures-utils-wasm", - "thiserror", + "serde", + "serde_json", + "thiserror 2.0.12", ] [[package]] name = "alloy-network-primitives" -version = "0.3.6" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94ad40869867ed2d9cd3842b1e800889e5b49e6b92da346e93862b4a741bedf3" +checksum = "f31c3c6b71340a1d076831823f09cb6e02de01de5c6630a9631bdb36f947ff80" dependencies = [ + "alloy-consensus", "alloy-eips", "alloy-primitives", "alloy-serde", "serde", ] +[[package]] +name = "alloy-node-bindings" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4520cd4bc5cec20c32c98e4bc38914c7fb96bf4a712105e44da186a54e65e3ba" +dependencies = [ + "alloy-genesis", + "alloy-primitives", + "k256", + "rand 0.8.5", + "serde_json", + "tempfile", + "thiserror 2.0.12", + "tracing", + "url", +] + [[package]] name = "alloy-primitives" -version = "0.8.7" +version = "0.8.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb848c43f6b06ae3de2e4a67496cbbabd78ae87db0f1248934f15d76192c6a" +checksum = "788bb18e8f61d5d9340b52143f27771daf7e1dccbaf2741621d2493f9debf52e" dependencies = [ "alloy-rlp", "bytes", @@ -264,9 +352,8 @@ dependencies = [ "const-hex", "derive_more 1.0.0", "foldhash", - "hashbrown 0.15.0", - "hex-literal", - "indexmap 2.6.0", + "hashbrown 0.15.2", + "indexmap 2.7.0", "itoa", "k256", "keccak-asm", @@ -274,7 +361,7 @@ dependencies = [ "proptest", "rand 0.8.5", "ruint", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "serde", "sha3", "tiny-keccak", @@ -282,9 +369,9 @@ dependencies = [ [[package]] name = "alloy-provider" -version = "0.3.6" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927f708dd457ed63420400ee5f06945df9632d5d101851952056840426a10dc5" +checksum = "5a22c4441b3ebe2d77fa9cf629ba68c3f713eb91779cff84275393db97eddd82" dependencies = [ "alloy-chains", "alloy-consensus", @@ -292,9 +379,13 @@ dependencies = [ "alloy-json-rpc", "alloy-network", "alloy-network-primitives", + "alloy-node-bindings", "alloy-primitives", "alloy-rpc-client", + "alloy-rpc-types-anvil", "alloy-rpc-types-eth", + "alloy-signer", + "alloy-signer-local", "alloy-transport", "alloy-transport-http", "async-stream", @@ -304,21 +395,24 @@ dependencies = [ "futures", "futures-utils-wasm", "lru", + "parking_lot", "pin-project", - "reqwest 0.12.8", + "reqwest 0.12.12", + "schnellru", "serde", "serde_json", - "thiserror", + "thiserror 2.0.12", "tokio", "tracing", "url", + "wasmtimer", ] [[package]] name = "alloy-rlp" -version = "0.3.8" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26154390b1d205a4a7ac7352aa2eb4f81f391399d4e2f546fb81a2f8bb383f62" +checksum = "f542548a609dca89fcd72b3b9f355928cf844d4363c5eed9c5273a3dd225e097" dependencies = [ "alloy-rlp-derive", "arrayvec", @@ -327,62 +421,98 @@ dependencies = [ [[package]] name = "alloy-rlp-derive" -version = "0.3.8" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d0f2d905ebd295e7effec65e5f6868d153936130ae718352771de3e7d03c75c" +checksum = "5a833d97bf8a5f0f878daf2c8451fff7de7f9de38baa5a45d936ec718d81255a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] name = "alloy-rpc-client" -version = "0.3.6" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d82952dca71173813d4e5733e2c986d8b04aea9e0f3b0a576664c232ad050a5" +checksum = "d06a292b37e182e514903ede6e623b9de96420e8109ce300da288a96d88b7e4b" dependencies = [ "alloy-json-rpc", + "alloy-primitives", "alloy-transport", "alloy-transport-http", "futures", "pin-project", - "reqwest 0.12.8", + "reqwest 0.12.12", "serde", "serde_json", "tokio", "tokio-stream", - "tower 0.5.1", + "tower 0.5.2", "tracing", "url", + "wasmtimer", +] + +[[package]] +name = "alloy-rpc-types" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9383845dd924939e7ab0298bbfe231505e20928907d7905aa3bf112287305e06" +dependencies = [ + "alloy-primitives", + "alloy-rpc-types-eth", + "alloy-serde", + "serde", +] + +[[package]] +name = "alloy-rpc-types-anvil" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11495cb8c8d3141fc27556a4c9188b81531ad5ec3076a0394c61a6dcfbce9f34" +dependencies = [ + "alloy-primitives", + "alloy-rpc-types-eth", + "alloy-serde", + "serde", +] + +[[package]] +name = "alloy-rpc-types-any" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca445cef0eb6c2cf51cfb4e214fbf1ebd00893ae2e6f3b944c8101b07990f988" +dependencies = [ + "alloy-consensus-any", + "alloy-rpc-types-eth", + "alloy-serde", ] [[package]] name = "alloy-rpc-types-eth" -version = "0.3.6" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83aa984386deda02482660aa31cb8ca1e63d533f1c31a52d7d181ac5ec68e9b8" +checksum = "0938bc615c02421bd86c1733ca7205cc3d99a122d9f9bff05726bd604b76a5c2" dependencies = [ "alloy-consensus", + "alloy-consensus-any", "alloy-eips", "alloy-network-primitives", "alloy-primitives", "alloy-rlp", "alloy-serde", "alloy-sol-types", - "cfg-if", - "derive_more 1.0.0", - "hashbrown 0.14.5", "itertools 0.13.0", "serde", "serde_json", + "thiserror 2.0.12", ] [[package]] name = "alloy-serde" -version = "0.3.6" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "731f75ec5d383107fd745d781619bd9cedf145836c51ecb991623d41278e71fa" +checksum = "ae0465c71d4dced7525f408d84873aeebb71faf807d22d74c4a426430ccd9b55" dependencies = [ "alloy-primitives", "serde", @@ -391,80 +521,99 @@ dependencies = [ [[package]] name = "alloy-signer" -version = "0.3.6" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "307324cca94354cd654d6713629f0383ec037e1ff9e3e3d547212471209860c0" +checksum = "9bfa395ad5cc952c82358d31e4c68b27bf4a89a5456d9b27e226e77dac50e4ff" dependencies = [ "alloy-primitives", "async-trait", "auto_impl", "elliptic-curve", "k256", - "thiserror", + "thiserror 2.0.12", +] + +[[package]] +name = "alloy-signer-local" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbdc63ce9eda1283fcbaca66ba4a414b841c0e3edbeef9c86a71242fc9e84ccc" +dependencies = [ + "alloy-consensus", + "alloy-network", + "alloy-primitives", + "alloy-signer", + "async-trait", + "k256", + "rand 0.8.5", + "thiserror 2.0.12", ] [[package]] name = "alloy-sol-macro" -version = "0.8.7" +version = "0.8.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "661c516eb1fa3294cc7f2fb8955b3b609d639c282ac81a4eedb14d3046db503a" +checksum = "a07b74d48661ab2e4b50bb5950d74dbff5e61dd8ed03bb822281b706d54ebacb" dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] name = "alloy-sol-macro-expander" -version = "0.8.7" +version = "0.8.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecbabb8fc3d75a0c2cea5215be22e7a267e3efde835b0f2a8922f5e3f5d47683" +checksum = "19cc9c7f20b90f9be1a8f71a3d8e283a43745137b0837b1a1cb13159d37cad72" dependencies = [ + "alloy-json-abi", "alloy-sol-macro-input", "const-hex", "heck 0.5.0", - "indexmap 2.6.0", + "indexmap 2.7.0", "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", "syn-solidity", "tiny-keccak", ] [[package]] name = "alloy-sol-macro-input" -version = "0.8.7" +version = "0.8.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16517f2af03064485150d89746b8ffdcdbc9b6eeb3d536fb66efd7c2846fbc75" +checksum = "713b7e6dfe1cb2f55c80fb05fd22ed085a1b4e48217611365ed0ae598a74c6ac" dependencies = [ + "alloy-json-abi", "const-hex", "dunce", "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.79", + "serde_json", + "syn 2.0.95", "syn-solidity", ] [[package]] name = "alloy-sol-type-parser" -version = "0.8.7" +version = "0.8.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c07ebb0c1674ff8cbb08378d7c2e0e27919d2a2dae07ad3bca26174deda8d389" +checksum = "1eda2711ab2e1fb517fc6e2ffa9728c9a232e296d16810810e6957b781a1b8bc" dependencies = [ "serde", - "winnow 0.6.20", + "winnow 0.6.22", ] [[package]] name = "alloy-sol-types" -version = "0.8.7" +version = "0.8.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e448d879903624863f608c552d10efb0e0905ddbee98b0049412799911eb062" +checksum = "e3b478bc9c0c4737a04cd976accde4df7eba0bdc0d90ad6ff43d58bc93cf79c1" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -475,9 +624,9 @@ dependencies = [ [[package]] name = "alloy-transport" -version = "0.3.6" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33616b2edf7454302a1d48084db185e52c309f73f6c10be99b0fe39354b3f1e9" +checksum = "d17722a198f33bbd25337660787aea8b8f57814febb7c746bc30407bdfc39448" dependencies = [ "alloy-json-rpc", "base64 0.22.1", @@ -485,28 +634,45 @@ dependencies = [ "futures-utils-wasm", "serde", "serde_json", - "thiserror", + "thiserror 2.0.12", "tokio", - "tower 0.5.1", + "tower 0.5.2", "tracing", "url", + "wasmtimer", ] [[package]] name = "alloy-transport-http" -version = "0.3.6" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a944f5310c690b62bbb3e7e5ce34527cbd36b2d18532a797af123271ce595a49" +checksum = "6e1509599021330a31c4a6816b655e34bf67acb1cc03c564e09fd8754ff6c5de" dependencies = [ "alloy-json-rpc", "alloy-transport", - "reqwest 0.12.8", + "reqwest 0.12.12", "serde_json", - "tower 0.5.1", + "tower 0.5.2", "tracing", "url", ] +[[package]] +name = "alloy-trie" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6917c79e837aa7b77b7a6dae9f89cbe15313ac161c4d3cfaf8909ef21f3d22d8" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "arrayvec", + "derive_more 1.0.0", + "nybbles", + "serde", + "smallvec", + "tracing", +] + [[package]] name = "android-tzdata" version = "0.1.1" @@ -530,9 +696,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.6.15" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", @@ -545,56 +711,69 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.4" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.89" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" +checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" + +[[package]] +name = "apollo_reverts" +version = "0.0.0" +dependencies = [ + "futures", + "papyrus_config", + "papyrus_storage", + "serde", + "starknet_api", + "tracing", + "validator", +] [[package]] name = "aquamarine" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21cc1548309245035eb18aa7f0967da6bc65587005170c56e6ef2788a4cf3f4e" +checksum = "0f50776554130342de4836ba542aa85a4ddb361690d7e8df13774d7284c3d5c2" dependencies = [ "include_dir", "itertools 0.10.5", - "proc-macro-error", + "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -603,6 +782,18 @@ version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" +[[package]] +name = "ark-bls12-381" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c775f0d12169cba7aae4caeb547bb6a50781c7449a8aa53793827c9ec4abf488" +dependencies = [ + "ark-ec 0.4.2", + "ark-ff 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", +] + [[package]] name = "ark-ec" version = "0.4.2" @@ -610,13 +801,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" dependencies = [ "ark-ff 0.4.2", - "ark-poly", + "ark-poly 0.4.2", "ark-serialize 0.4.2", "ark-std 0.4.0", "derivative", "hashbrown 0.13.2", "itertools 0.10.5", - "num-traits 0.2.19", + "num-traits", + "zeroize", +] + +[[package]] +name = "ark-ec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d68f2d516162846c1238e755a7c4d131b892b70cc70c471a8e3ca3ed818fce" +dependencies = [ + "ahash", + "ark-ff 0.5.0", + "ark-poly 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "educe 0.6.0", + "fnv", + "hashbrown 0.15.2", + "itertools 0.13.0", + "num-bigint 0.4.6", + "num-integer", + "num-traits", "zeroize", ] @@ -632,7 +844,7 @@ dependencies = [ "ark-std 0.3.0", "derivative", "num-bigint 0.4.6", - "num-traits 0.2.19", + "num-traits", "paste", "rustc_version 0.3.3", "zeroize", @@ -652,12 +864,32 @@ dependencies = [ "digest 0.10.7", "itertools 0.10.5", "num-bigint 0.4.6", - "num-traits 0.2.19", + "num-traits", "paste", "rustc_version 0.4.1", "zeroize", ] +[[package]] +name = "ark-ff" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a177aba0ed1e0fbb62aa9f6d0502e9b46dad8c2eab04c14258a1212d2557ea70" +dependencies = [ + "ark-ff-asm 0.5.0", + "ark-ff-macros 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "arrayvec", + "digest 0.10.7", + "educe 0.6.0", + "itertools 0.13.0", + "num-bigint 0.4.6", + "num-traits", + "paste", + "zeroize", +] + [[package]] name = "ark-ff-asm" version = "0.3.0" @@ -678,6 +910,16 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ark-ff-asm" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" +dependencies = [ + "quote", + "syn 2.0.95", +] + [[package]] name = "ark-ff-macros" version = "0.3.0" @@ -685,7 +927,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" dependencies = [ "num-bigint 0.4.6", - "num-traits 0.2.19", + "num-traits", "quote", "syn 1.0.109", ] @@ -697,12 +939,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" dependencies = [ "num-bigint 0.4.6", - "num-traits 0.2.19", + "num-traits", "proc-macro2", "quote", "syn 1.0.109", ] +[[package]] +name = "ark-ff-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" +dependencies = [ + "num-bigint 0.4.6", + "num-traits", + "proc-macro2", + "quote", + "syn 2.0.95", +] + [[package]] name = "ark-poly" version = "0.4.2" @@ -716,28 +971,65 @@ dependencies = [ "hashbrown 0.13.2", ] +[[package]] +name = "ark-poly" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579305839da207f02b89cd1679e50e67b4331e2f9294a57693e5051b7703fe27" +dependencies = [ + "ahash", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "educe 0.6.0", + "fnv", + "hashbrown 0.15.2", +] + [[package]] name = "ark-secp256k1" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c02e954eaeb4ddb29613fee20840c2bbc85ca4396d53e33837e11905363c5f2" dependencies = [ - "ark-ec", + "ark-ec 0.4.2", "ark-ff 0.4.2", "ark-std 0.4.0", ] [[package]] -name = "ark-secp256r1" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +name = "ark-secp256k1" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8bd211c48debd3037b48873a7aa22c3aba034e83388aa4124795c9f220b88c7" +dependencies = [ + "ark-ec 0.5.0", + "ark-ff 0.5.0", + "ark-std 0.5.0", +] + +[[package]] +name = "ark-secp256r1" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3975a01b0a6e3eae0f72ec7ca8598a6620fc72fa5981f6f5cca33b7cd788f633" dependencies = [ - "ark-ec", + "ark-ec 0.4.2", "ark-ff 0.4.2", "ark-std 0.4.0", ] +[[package]] +name = "ark-secp256r1" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cf8be5820de567729bfa73a410ddd07cec8ad102d9a4bf61fd6b2e60db264e8" +dependencies = [ + "ark-ec 0.5.0", + "ark-ff 0.5.0", + "ark-std 0.5.0", +] + [[package]] name = "ark-serialize" version = "0.3.0" @@ -754,12 +1046,25 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" dependencies = [ - "ark-serialize-derive", + "ark-serialize-derive 0.4.2", "ark-std 0.4.0", "digest 0.10.7", "num-bigint 0.4.6", ] +[[package]] +name = "ark-serialize" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" +dependencies = [ + "ark-serialize-derive 0.5.0", + "ark-std 0.5.0", + "arrayvec", + "digest 0.10.7", + "num-bigint 0.4.6", +] + [[package]] name = "ark-serialize-derive" version = "0.4.2" @@ -771,13 +1076,24 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ark-serialize-derive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.95", +] + [[package]] name = "ark-std" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" dependencies = [ - "num-traits 0.2.19", + "num-traits", "rand 0.8.5", ] @@ -787,7 +1103,17 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" dependencies = [ - "num-traits 0.2.19", + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "ark-std" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" +dependencies = [ + "num-traits", "rand 0.8.5", ] @@ -802,6 +1128,9 @@ name = "arrayvec" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +dependencies = [ + "serde", +] [[package]] name = "ascii-canvas" @@ -822,9 +1151,9 @@ dependencies = [ "asn1-rs-impl", "displaydoc", "nom", - "num-traits 0.2.19", + "num-traits", "rusticata-macros", - "thiserror", + "thiserror 1.0.69", "time", ] @@ -836,7 +1165,7 @@ checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", "synstructure", ] @@ -848,7 +1177,7 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -892,9 +1221,9 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.15" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e26a9844c659a2a293d239c7910b752f8487fe122c6c8bd1659bf85a6507c302" +checksum = "df895a515f70646414f4b45c0b79082783b80552b373a68283012928df56f522" dependencies = [ "flate2", "futures-core", @@ -911,21 +1240,20 @@ checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" dependencies = [ "async-task", "concurrent-queue", - "fastrand 2.1.1", - "futures-lite 2.3.0", + "fastrand 2.3.0", + "futures-lite 2.5.0", "slab", ] [[package]] name = "async-fs" -version = "1.6.0" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "279cf904654eeebfa37ac9bb1598880884924aab82e290aa65c9e77a0e142e06" +checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a" dependencies = [ - "async-lock 2.8.0", - "autocfg 1.4.0", + "async-lock 3.4.0", "blocking", - "futures-lite 1.13.0", + "futures-lite 2.5.0", ] [[package]] @@ -936,10 +1264,10 @@ checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" dependencies = [ "async-channel 2.3.1", "async-executor", - "async-io 2.3.4", + "async-io 2.4.0", "async-lock 3.4.0", "blocking", - "futures-lite 2.3.0", + "futures-lite 2.5.0", "once_cell", ] @@ -965,18 +1293,18 @@ dependencies = [ [[package]] name = "async-io" -version = "2.3.4" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8" +checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" dependencies = [ "async-lock 3.4.0", "cfg-if", "concurrent-queue", "futures-io", - "futures-lite 2.3.0", + "futures-lite 2.5.0", "parking", - "polling 3.7.3", - "rustix 0.38.37", + "polling 3.7.4", + "rustix 0.38.43", "slab", "tracing", "windows-sys 0.59.0", @@ -997,37 +1325,39 @@ version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" dependencies = [ - "event-listener 5.3.1", + "event-listener 5.4.0", "event-listener-strategy", "pin-project-lite", ] [[package]] name = "async-net" -version = "1.8.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0434b1ed18ce1cf5769b8ac540e33f01fa9471058b5e89da9e06f3c882a8c12f" +checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" dependencies = [ - "async-io 1.13.0", + "async-io 2.4.0", "blocking", - "futures-lite 1.13.0", + "futures-lite 2.5.0", ] [[package]] name = "async-process" -version = "1.8.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea6438ba0a08d81529c69b36700fa2f95837bfe3e776ab39cde9c14d9149da88" +checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb" dependencies = [ - "async-io 1.13.0", - "async-lock 2.8.0", + "async-channel 2.3.1", + "async-io 2.4.0", + "async-lock 3.4.0", "async-signal", + "async-task", "blocking", "cfg-if", - "event-listener 3.1.0", - "futures-lite 1.13.0", - "rustix 0.38.37", - "windows-sys 0.48.0", + "event-listener 5.4.0", + "futures-lite 2.5.0", + "rustix 0.38.43", + "tracing", ] [[package]] @@ -1038,7 +1368,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -1047,13 +1377,13 @@ version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" dependencies = [ - "async-io 2.3.4", + "async-io 2.4.0", "async-lock 3.4.0", "atomic-waker", "cfg-if", "futures-core", "futures-io", - "rustix 0.38.37", + "rustix 0.38.43", "signal-hook-registry", "slab", "windows-sys 0.59.0", @@ -1067,13 +1397,13 @@ checksum = "c634475f29802fde2b8f0b505b1bd00dfe4df7d4a000f0b36f7671197d5c3615" dependencies = [ "async-channel 1.9.0", "async-global-executor", - "async-io 2.3.4", + "async-io 2.4.0", "async-lock 3.4.0", "crossbeam-utils", "futures-channel", "futures-core", "futures-io", - "futures-lite 2.3.0", + "futures-lite 2.5.0", "gloo-timers 0.3.0", "kv-log-macro", "log", @@ -1104,7 +1434,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -1115,13 +1445,13 @@ checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.83" +version = "0.1.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" +checksum = "3f934833b4b7233644e5848f235df3f57ed8c80f1528a26c3dfa13d2147fa056" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -1186,7 +1516,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -1204,6 +1534,31 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +[[package]] +name = "aws-lc-rs" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f409eb70b561706bf8abba8ca9c112729c481595893fd06a2dd9af8ed8441148" +dependencies = [ + "aws-lc-sys", + "paste", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "923ded50f602b3007e5e63e3f094c479d9c8a9b42d7f4034e4afe456aa48bfd2" +dependencies = [ + "bindgen 0.69.5", + "cc", + "cmake", + "dunce", + "fs_extra", + "paste", +] + [[package]] name = "axum" version = "0.6.20" @@ -1217,7 +1572,7 @@ dependencies = [ "futures-util", "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.30", + "hyper 0.14.32", "itoa", "matchit", "memchr", @@ -1319,27 +1674,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bigdecimal" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6773ddc0eafc0e509fb60e48dff7f450f8e674a0686ae8605e8d9901bd5eefa" -dependencies = [ - "num-bigint 0.4.6", - "num-integer", - "num-traits 0.2.19", - "serde", -] - -[[package]] -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - [[package]] name = "bincode" version = "2.0.0-rc.3" @@ -1366,7 +1700,7 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -1388,7 +1722,7 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.79", + "syn 2.0.95", "which", ] @@ -1397,6 +1731,24 @@ name = "bindgen" version = "0.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" +dependencies = [ + "bitflags 2.6.0", + "cexpr", + "clang-sys", + "itertools 0.13.0", + "proc-macro2", + "quote", + "regex", + "rustc-hash 1.1.0", + "shlex", + "syn 2.0.95", +] + +[[package]] +name = "bindgen" +version = "0.71.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" dependencies = [ "bitflags 2.6.0", "cexpr", @@ -1407,9 +1759,9 @@ dependencies = [ "proc-macro2", "quote", "regex", - "rustc-hash 1.1.0", + "rustc-hash 2.1.0", "shlex", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -1483,11 +1835,12 @@ name = "blockifier" version = "0.0.0" dependencies = [ "anyhow", - "ark-ec", + "ark-ec 0.4.2", "ark-ff 0.4.2", - "ark-secp256k1", - "ark-secp256r1", + "ark-secp256k1 0.4.0", + "ark-secp256r1 0.4.0", "assert_matches", + "blockifier_test_utils", "cached", "cairo-lang-casm", "cairo-lang-runner", @@ -1497,14 +1850,15 @@ dependencies = [ "criterion", "derive_more 0.99.18", "glob", - "indexmap 2.6.0", + "indexmap 2.7.0", "itertools 0.12.1", "keccak", "log", + "mockall", "num-bigint 0.4.6", "num-integer", "num-rational 0.4.2", - "num-traits 0.2.19", + "num-traits", "papyrus_config", "paste", "phf", @@ -1512,19 +1866,20 @@ dependencies = [ "rand 0.8.5", "regex", "rstest", - "semver 1.0.23", + "rstest_reuse", + "semver 1.0.24", "serde", "serde_json", "sha2", "starknet-types-core", "starknet_api", + "starknet_infra_utils", + "starknet_sierra_multicompile", "strum 0.25.0", "strum_macros 0.25.3", - "tempfile", "test-case", - "thiserror", + "thiserror 1.0.69", "tikv-jemallocator", - "toml", ] [[package]] @@ -1538,7 +1893,7 @@ dependencies = [ "clap", "flate2", "google-cloud-storage", - "indexmap 2.6.0", + "indexmap 2.7.0", "papyrus_execution", "pretty_assertions", "retry", @@ -1549,8 +1904,28 @@ dependencies = [ "starknet-types-core", "starknet_api", "starknet_gateway", - "thiserror", + "thiserror 1.0.69", + "tokio", +] + +[[package]] +name = "blockifier_test_utils" +version = "0.0.0" +dependencies = [ + "cairo-lang-starknet-classes", + "itertools 0.12.1", + "pretty_assertions", + "rstest", + "serde_json", + "starknet-types-core", + "starknet_api", + "starknet_infra_utils", + "strum 0.25.0", + "strum_macros 0.25.3", + "tempfile", "tokio", + "tracing", + "tracing-test", ] [[package]] @@ -1562,7 +1937,7 @@ dependencies = [ "async-channel 2.3.1", "async-task", "futures-io", - "futures-lite 2.3.0", + "futures-lite 2.5.0", "piper", ] @@ -1590,9 +1965,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.10.0" +version = "1.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" +checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0" dependencies = [ "memchr", "serde", @@ -1624,9 +1999,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.2" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" dependencies = [ "serde", ] @@ -1680,7 +2055,7 @@ dependencies = [ "hashbrown 0.13.2", "instant", "once_cell", - "thiserror", + "thiserror 1.0.69", "tokio", ] @@ -1705,14 +2080,14 @@ checksum = "ade8366b8bd5ba243f0a58f036cc0ca8a2f069cff1a2351ef1cac6b083e16fc0" [[package]] name = "cairo-lang-casm" -version = "2.9.0-dev.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e0dcdb6358bb639dd729546611bd99bada94c86e3f262c3637855abea9a972" +checksum = "e3670c7c84c310dfc96667b6f10c37e275ed750761058e8052cace1d1853a03b" dependencies = [ "cairo-lang-utils", "indoc 2.0.5", "num-bigint 0.4.6", - "num-traits 0.2.19", + "num-traits", "parity-scale-codec", "schemars", "serde", @@ -1720,9 +2095,9 @@ dependencies = [ [[package]] name = "cairo-lang-compiler" -version = "2.9.0-dev.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8657f5a5611f341a85e80ba0b21848fc34bfdf391bfd93df0baf4516c3e4159" +checksum = "7f704af3ba7499d63a695688d2f5b40109820f8ca38d78092a4aa4a64ec600d2" dependencies = [ "anyhow", "cairo-lang-defs", @@ -1739,25 +2114,25 @@ dependencies = [ "indoc 2.0.5", "rayon", "rust-analyzer-salsa", - "semver 1.0.23", + "semver 1.0.24", "smol_str", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "cairo-lang-debug" -version = "2.9.0-dev.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0635aa554d297acefe6a35b495aba2795d0af5b7f97c4ab63829c7d62291ef41" +checksum = "b27f41d3fdda19dfe8ae3bb80d63fe537dfee899547641c02e2f04508411273c" dependencies = [ "cairo-lang-utils", ] [[package]] name = "cairo-lang-defs" -version = "2.9.0-dev.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b356e1c09898e8b8cfdd9731579d89365a13d8b4f7e717962e0cc7d125b83c" +checksum = "26f3d2f98138296375b9cfb643dbd6e127aeba475858c11bb77a304f2a655d7f" dependencies = [ "cairo-lang-debug", "cairo-lang-diagnostics", @@ -1772,9 +2147,9 @@ dependencies = [ [[package]] name = "cairo-lang-diagnostics" -version = "2.9.0-dev.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dfe7c6ff96182da29012b707a3554e34a50f19cc96013ee45b0eb36dd396ec8" +checksum = "d066931c8811bfd972e8068bf5b1b43cbc371eb17d5a9b753bbfcc8dccb2c299" dependencies = [ "cairo-lang-debug", "cairo-lang-filesystem", @@ -1784,9 +2159,9 @@ dependencies = [ [[package]] name = "cairo-lang-eq-solver" -version = "2.9.0-dev.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "723d244465309d5409e297b5486d62cbec06f2c47b05044414bb640e3f14caab" +checksum = "d81fe837084f841398225eba8ae50759d7ff64fb64a5af0b4b42f1fed4e2c351" dependencies = [ "cairo-lang-utils", "good_lp", @@ -1794,15 +2169,15 @@ dependencies = [ [[package]] name = "cairo-lang-filesystem" -version = "2.9.0-dev.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "237030772ae5368f19a9247e1f63f753f8ad8de963477166e402f4825c0a141d" +checksum = "979357549a21e093f53d7ad504e91701bc055fad9a5b9a0fb8554b772e9b7e79" dependencies = [ "cairo-lang-debug", "cairo-lang-utils", "path-clean", "rust-analyzer-salsa", - "semver 1.0.23", + "semver 1.0.24", "serde", "smol_str", "toml", @@ -1810,9 +2185,9 @@ dependencies = [ [[package]] name = "cairo-lang-formatter" -version = "2.9.0-dev.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b71f0eb3a36a6cb5f7f07843926783c4c17e44c9516b53171727a108782f3eb" +checksum = "522eebf63d6c0e5d55f0337896589c2257c1e144664732ddad71e52c63329a10" dependencies = [ "anyhow", "cairo-lang-diagnostics", @@ -1825,14 +2200,14 @@ dependencies = [ "itertools 0.12.1", "rust-analyzer-salsa", "serde", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "cairo-lang-lowering" -version = "2.9.0-dev.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d095d78e2f1de499429c95655d6135a3d24c384b36d8de9f84e0aa4e07ee152" +checksum = "06b41ecb6e3911be45dc78411cf0a17ea8bc565d0f700ad5f6ca67c41b7cad1b" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -1848,26 +2223,26 @@ dependencies = [ "log", "num-bigint 0.4.6", "num-integer", - "num-traits 0.2.19", + "num-traits", "rust-analyzer-salsa", "smol_str", ] [[package]] name = "cairo-lang-parser" -version = "2.9.0-dev.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb828af7f948a3ef7fa65de14e3f639daedefb046dfefcad6e3116d2cb0f89a0" +checksum = "e05f51736d9905b1ea4ee63b1222a435c1243bbd64af18ad01cc10cece3377f3" dependencies = [ "cairo-lang-diagnostics", "cairo-lang-filesystem", "cairo-lang-syntax", "cairo-lang-syntax-codegen", "cairo-lang-utils", - "colored", + "colored 2.2.0", "itertools 0.12.1", "num-bigint 0.4.6", - "num-traits 0.2.19", + "num-traits", "rust-analyzer-salsa", "smol_str", "unescaper", @@ -1875,9 +2250,9 @@ dependencies = [ [[package]] name = "cairo-lang-plugins" -version = "2.9.0-dev.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "135a600043bf7030eacc6ebf2a609c2364d6ffeb04e1f3c809a2738f6b02c829" +checksum = "0b9cc61a811d4d3a66b210cc158332bece6813244903a15ed0a14f62fdbe4e78" dependencies = [ "cairo-lang-defs", "cairo-lang-diagnostics", @@ -1892,47 +2267,69 @@ dependencies = [ "smol_str", ] +[[package]] +name = "cairo-lang-primitive-token" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "123ac0ecadf31bacae77436d72b88fa9caef2b8e92c89ce63a125ae911a12fae" + [[package]] name = "cairo-lang-proc-macros" -version = "2.9.0-dev.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac857ec4b564712f3e16e3314e23cc0787ab1c05cdfee83f1c8f9989a6eee40f" +checksum = "32f8e3c2a2234955f2b5a49aef214bbe293d03ebf2c5f2b3143a9c002c1caa0b" dependencies = [ "cairo-lang-debug", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] name = "cairo-lang-project" -version = "2.9.0-dev.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23cc37b7f8889cdea631aeea3bcc70d5c86ac8fb1d98aabc83f16283d60f1643" +checksum = "d171b4ebc778458be84e706779c662efb0dfeb2c077075c4b6f4b63430491b0d" dependencies = [ "cairo-lang-filesystem", "cairo-lang-utils", "serde", - "smol_str", - "thiserror", + "thiserror 1.0.69", "toml", ] +[[package]] +name = "cairo-lang-runnable-utils" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dae123904bb7831433868377bb6e7d0a054504b6ea00535cc192abb1a364950" +dependencies = [ + "cairo-lang-casm", + "cairo-lang-sierra", + "cairo-lang-sierra-ap-change", + "cairo-lang-sierra-gas", + "cairo-lang-sierra-to-casm", + "cairo-lang-sierra-type-size", + "cairo-lang-utils", + "cairo-vm", + "itertools 0.12.1", + "thiserror 1.0.69", +] + [[package]] name = "cairo-lang-runner" -version = "2.9.0-dev.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7474375528ffa7f47e343983d32051898e4e7b05ac0bdc48ee84b1325d8b562a" +checksum = "8b00e638356ca1b6073fad36d95131ebe62ee8bc0cc2cb31880e0b17f5e38c39" dependencies = [ "ark-ff 0.4.2", - "ark-secp256k1", - "ark-secp256r1", + "ark-secp256k1 0.4.0", + "ark-secp256r1 0.4.0", "cairo-lang-casm", "cairo-lang-lowering", + "cairo-lang-runnable-utils", "cairo-lang-sierra", - "cairo-lang-sierra-ap-change", "cairo-lang-sierra-generator", "cairo-lang-sierra-to-casm", - "cairo-lang-sierra-type-size", "cairo-lang-starknet", "cairo-lang-utils", "cairo-vm", @@ -1940,19 +2337,19 @@ dependencies = [ "keccak", "num-bigint 0.4.6", "num-integer", - "num-traits 0.2.19", + "num-traits", "rand 0.8.5", "sha2", "smol_str", "starknet-types-core", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "cairo-lang-semantic" -version = "2.9.0-dev.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c560cf4b4a89325d3a9594f490fffee38cf30e0990e808bb927619de9d0c973a" +checksum = "1c3aa9c0d2f75a77d2e57bf8e146c8dd51a36e14e05bd8a3192237ac2ecac145" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -1968,17 +2365,18 @@ dependencies = [ "indoc 2.0.5", "itertools 0.12.1", "num-bigint 0.4.6", - "num-traits 0.2.19", + "num-traits", "rust-analyzer-salsa", + "sha3", "smol_str", "toml", ] [[package]] name = "cairo-lang-sierra" -version = "2.9.0-dev.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8118f55ca7d567bfc60960b445d388564d04bf48335c983b1595cb35f67a01c5" +checksum = "c6cfdac5d0a0be84e9247414b552905967e06feaef48633af4ca6e80240acb09" dependencies = [ "anyhow", "cairo-lang-utils", @@ -1990,7 +2388,7 @@ dependencies = [ "lalrpop-util", "num-bigint 0.4.6", "num-integer", - "num-traits 0.2.19", + "num-traits", "regex", "rust-analyzer-salsa", "serde", @@ -1998,14 +2396,14 @@ dependencies = [ "sha3", "smol_str", "starknet-types-core", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "cairo-lang-sierra-ap-change" -version = "2.9.0-dev.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2716ef8d4ce0fb700f83ed3281f3656436570e60249d41c65c79dc1ca27be002" +checksum = "5a923105c63704b7371f4ee92a17b3037c8be88f0c7021eb764d8f974a397ff5" dependencies = [ "cairo-lang-eq-solver", "cairo-lang-sierra", @@ -2013,15 +2411,15 @@ dependencies = [ "cairo-lang-utils", "itertools 0.12.1", "num-bigint 0.4.6", - "num-traits 0.2.19", - "thiserror", + "num-traits", + "thiserror 1.0.69", ] [[package]] name = "cairo-lang-sierra-gas" -version = "2.9.0-dev.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24a44da87a35845470c4f4c648225232a15e0875fe809045b6088464491f838b" +checksum = "1fa8dc62dfa49f57dcdb092f551bcba42d0123f4d0f0763087b3b41142543ecf" dependencies = [ "cairo-lang-eq-solver", "cairo-lang-sierra", @@ -2029,15 +2427,15 @@ dependencies = [ "cairo-lang-utils", "itertools 0.12.1", "num-bigint 0.4.6", - "num-traits 0.2.19", - "thiserror", + "num-traits", + "thiserror 1.0.69", ] [[package]] name = "cairo-lang-sierra-generator" -version = "2.9.0-dev.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15bc5cf9f3965a7030a114dfe3d31d183287fbfbfbf904deaaa2468cadb936aa" +checksum = "4526593827287b39af72c0d12698007a9fe693d8a8e9fc4e481885634e9c1601" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -2050,7 +2448,7 @@ dependencies = [ "cairo-lang-syntax", "cairo-lang-utils", "itertools 0.12.1", - "num-traits 0.2.19", + "num-traits", "rust-analyzer-salsa", "serde", "serde_json", @@ -2059,9 +2457,9 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-to-casm" -version = "2.9.0-dev.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18b7616f1a3c41c4646094b5abf774e558428e9c1eda5d78d7b0638ec5c264e5" +checksum = "e4357f1cadb6a713c85560aacba92a794eac1f5c82021c0f28ce3a6810c4e334" dependencies = [ "assert_matches", "cairo-lang-casm", @@ -2073,16 +2471,16 @@ dependencies = [ "indoc 2.0.5", "itertools 0.12.1", "num-bigint 0.4.6", - "num-traits 0.2.19", + "num-traits", "starknet-types-core", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "cairo-lang-sierra-type-size" -version = "2.9.0-dev.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "871077dbc08df5d134dc3975538171c14b266ba405d1298085afdb227216f0a3" +checksum = "c2963c5eea0778ba7f00e41916dc347b988ca73458edc3e460954e597484bc95" dependencies = [ "cairo-lang-sierra", "cairo-lang-utils", @@ -2090,9 +2488,9 @@ dependencies = [ [[package]] name = "cairo-lang-starknet" -version = "2.9.0-dev.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f21804eb8931d41e258e7a393afc8ee8858308e95b3ed2e9b6b469ef68a6a50" +checksum = "07a18683311c0976fbff8ac237e1f0940707695efee77438b56c1604d1db9b5e" dependencies = [ "anyhow", "cairo-lang-compiler", @@ -2115,14 +2513,14 @@ dependencies = [ "serde_json", "smol_str", "starknet-types-core", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "cairo-lang-starknet-classes" -version = "2.9.0-dev.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2496bccd68fa0286b35b72c98439316a3a872ef7ec6d881f0dac90b17997490" +checksum = "467bf061c5a43844880d5566931d6d2866b714b4451c61072301ce40b484cda4" dependencies = [ "cairo-lang-casm", "cairo-lang-sierra", @@ -2132,26 +2530,27 @@ dependencies = [ "itertools 0.12.1", "num-bigint 0.4.6", "num-integer", - "num-traits 0.2.19", + "num-traits", "serde", "serde_json", "sha3", "smol_str", "starknet-types-core", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "cairo-lang-syntax" -version = "2.9.0-dev.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d77ea2e35d3610098ff13e373fc519aedc6a5096ed8547081aacfc104ef4422" +checksum = "6e8470468ce1307e9daf67bf7cc6434233a0c18921e2a341890826595e9469aa" dependencies = [ "cairo-lang-debug", "cairo-lang-filesystem", + "cairo-lang-primitive-token", "cairo-lang-utils", "num-bigint 0.4.6", - "num-traits 0.2.19", + "num-traits", "rust-analyzer-salsa", "smol_str", "unescaper", @@ -2159,9 +2558,9 @@ dependencies = [ [[package]] name = "cairo-lang-syntax-codegen" -version = "2.9.0-dev.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b01d505ab26ca9ce829faf3a8dd097f5d7962d2eb8f136017a260694a6a72e8" +checksum = "fee2959e743f241b66ea3f6c743a96b1d44162aedf5cb960a04b3d25b1e7ce68" dependencies = [ "genco", "xshell", @@ -2169,9 +2568,9 @@ dependencies = [ [[package]] name = "cairo-lang-test-plugin" -version = "2.9.0-dev.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f83e082c8ebf81295156f13399f880037c749a9f1fc3f55b1be7e49fe124c6" +checksum = "ea61348e6f51d666bf82ec8c536c9f5be22bd86f18a3b357ec3014223df01c81" dependencies = [ "anyhow", "cairo-lang-compiler", @@ -2189,35 +2588,35 @@ dependencies = [ "indoc 2.0.5", "itertools 0.12.1", "num-bigint 0.4.6", - "num-traits 0.2.19", + "num-traits", "serde", "starknet-types-core", ] [[package]] name = "cairo-lang-test-utils" -version = "2.9.0-dev.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb143a22f5a3510df8c4dec76e17c1e36bbcbddcd7915601f6a51a72418c454f" +checksum = "3507a94b74770b265391ef32fec9370b38fc24edef4ca162e234f23dffd16706" dependencies = [ "cairo-lang-formatter", "cairo-lang-utils", - "colored", + "colored 2.2.0", "log", "pretty_assertions", ] [[package]] name = "cairo-lang-utils" -version = "2.9.0-dev.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35df943ebcf8e1db11ee9f4f46f843dde5b71639ca79ea0d8caa7973f91d8b12" +checksum = "cc13c3f9b93451df0011bf5ae11804ebaac4b85c8555aa01679a25d4a3e64da5" dependencies = [ "hashbrown 0.14.5", - "indexmap 2.6.0", + "indexmap 2.7.0", "itertools 0.12.1", "num-bigint 0.4.6", - "num-traits 0.2.19", + "num-traits", "parity-scale-codec", "schemars", "serde", @@ -2225,16 +2624,16 @@ dependencies = [ [[package]] name = "cairo-native" -version = "0.2.4" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bdebc70c3d563bc30078985ae3e975aa7dc4fa233631b5e0462a924c26c0dd9" +checksum = "a72a2a1fd26cfe84c9de7dfc5f1a78bc2e15847fb10f593fba96fd2b93ccd89b" dependencies = [ "anyhow", "aquamarine", - "ark-ec", - "ark-ff 0.4.2", - "ark-secp256k1", - "ark-secp256r1", + "ark-ec 0.5.0", + "ark-ff 0.5.0", + "ark-secp256k1 0.5.0", + "ark-secp256r1 0.5.0", "bumpalo", "cairo-lang-compiler", "cairo-lang-defs", @@ -2249,12 +2648,11 @@ dependencies = [ "cairo-lang-starknet-classes", "cairo-lang-test-plugin", "cairo-lang-utils", - "cairo-native-runtime", "cc", "clap", - "colored", - "educe", - "itertools 0.13.0", + "colored 2.2.0", + "educe 0.5.11", + "itertools 0.14.0", "keccak", "lazy_static", "libc", @@ -2264,42 +2662,29 @@ dependencies = [ "mlir-sys", "num-bigint 0.4.6", "num-integer", - "num-traits 0.2.19", + "num-traits", + "rand 0.9.0", "serde", "serde_json", "sha2", + "starknet-curve 0.5.1", "starknet-types-core", "stats_alloc", "tempfile", - "thiserror", + "thiserror 2.0.12", "tracing", "tracing-subscriber", "utf8_iter", ] -[[package]] -name = "cairo-native-runtime" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf997252c402d6844f41357660cde3c11825ac5b3feafd0fb99b9dcdfb58aa3" -dependencies = [ - "cairo-lang-sierra-gas", - "itertools 0.13.0", - "lazy_static", - "num-traits 0.2.19", - "rand 0.8.5", - "starknet-curve 0.5.1", - "starknet-types-core", -] - [[package]] name = "cairo-vm" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58363ad8065ed891e3b14a8191b707677c7c7cb5b9d10030822506786d8d8108" +checksum = "7fa8b4b56ee66cebcade4d85128e55b2bfdf046502187aeaa8c2768a427684dc" dependencies = [ "anyhow", - "bincode 2.0.0-rc.3", + "bincode", "bitvec", "generic-array", "hashbrown 0.14.5", @@ -2310,7 +2695,7 @@ dependencies = [ "num-bigint 0.4.6", "num-integer", "num-prime", - "num-traits 0.2.19", + "num-traits", "rand 0.8.5", "rust_decimal", "serde", @@ -2340,9 +2725,9 @@ dependencies = [ [[package]] name = "cargo-platform" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" dependencies = [ "serde", ] @@ -2355,19 +2740,18 @@ checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" dependencies = [ "camino", "cargo-platform", - "semver 1.0.23", + "semver 1.0.24", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "caseless" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808dab3318747be122cb31d36de18d4d1c81277a76f8332a02b81a3d73463d7f" +checksum = "8b6fd507454086c8edfd769ca6ada439193cdb209c7681712ef6275cccbfe5d8" dependencies = [ - "regex", "unicode-normalization", ] @@ -2379,9 +2763,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.1.30" +version = "1.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945" +checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" dependencies = [ "jobserver", "libc", @@ -2435,14 +2819,14 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.38" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" dependencies = [ "android-tzdata", "iana-time-zone", "js-sys", - "num-traits 0.2.19", + "num-traits", "serde", "wasm-bindgen", "windows-targets 0.52.6", @@ -2499,9 +2883,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.20" +version = "4.5.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" +checksum = "9560b07a799281c7e0958b9296854d6fafd4c5f31444a7e5bb1ad6dde5ccf1bd" dependencies = [ "clap_builder", "clap_derive", @@ -2509,9 +2893,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.20" +version = "4.5.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" +checksum = "874e0dd3eb68bf99058751ac9712f622e61e6f393a94f7128fa26e3f02f5c7cd" dependencies = [ "anstream", "anstyle", @@ -2521,21 +2905,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.18" +version = "4.5.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +checksum = "54b755194d6389280185988721fffba69495eed5ee9feeee9a599b53db80318c" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] name = "clap_lex" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "cloudabi" @@ -2546,6 +2930,15 @@ dependencies = [ "bitflags 1.2.1", ] +[[package]] +name = "cmake" +version = "0.1.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c682c223677e0e5b6b7f63a64b9351844c3f1b1678a68b7ee617e30fb082620e" +dependencies = [ + "cc", +] + [[package]] name = "coins-bip32" version = "0.8.7" @@ -2559,7 +2952,7 @@ dependencies = [ "k256", "serde", "sha2", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -2575,7 +2968,7 @@ dependencies = [ "pbkdf2 0.12.2", "rand 0.8.5", "sha2", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -2595,66 +2988,43 @@ dependencies = [ "serde_derive", "sha2", "sha3", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "colorchoice" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "colored" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" +checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" dependencies = [ "lazy_static", "windows-sys 0.48.0", ] [[package]] -name = "committer_cli" -version = "0.0.0" +name = "colored" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e" dependencies = [ - "clap", - "criterion", - "derive_more 0.99.18", - "ethnum", - "futures", - "indexmap 2.6.0", - "pretty_assertions", - "rand 0.8.5", - "rand_distr", - "serde", - "serde_json", - "serde_repr", - "starknet-types-core", - "starknet_api", - "starknet_committer", - "starknet_patricia", - "strum 0.25.0", - "strum_macros 0.25.3", - "tempfile", - "thiserror", - "tokio", - "tracing", - "tracing-subscriber", + "windows-sys 0.48.0", ] [[package]] name = "comrak" -version = "0.28.0" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c93ab3577cca16b4a1d80a88c2e0cd8b6e969e51696f0bbb0d1dcb0157109832" +checksum = "39bff2cbb80102771ca62bd2375bc6f6611dc1493373440b23aa08a155538708" dependencies = [ "caseless", - "derive_builder", "entities", "memchr", - "once_cell", - "regex", "slug", "typed-arena", "unicode_categories", @@ -2671,14 +3041,14 @@ dependencies = [ [[package]] name = "console" -version = "0.15.8" +version = "0.15.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +checksum = "ea3c6ecd8059b57859df5c69830340ed3c41d30e3da0c1cbed90a96ac853041b" dependencies = [ "encode_unicode", - "lazy_static", "libc", - "windows-sys 0.52.0", + "once_cell", + "windows-sys 0.59.0", ] [[package]] @@ -2689,9 +3059,9 @@ checksum = "32b13ea120a812beba79e34316b3942a857c86ec1593cb34f27bb28272ce2cca" [[package]] name = "const-hex" -version = "1.13.1" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0121754e84117e65f9d90648ee6aa4882a6e63110307ab73967a4c5e7e69e586" +checksum = "4b0485bab839b018a8f1723fc5391819fea5f8f0f32288ef8a735fd096b6160c" dependencies = [ "cfg-if", "cpufeatures", @@ -2708,18 +3078,18 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "const_format" -version = "0.2.33" +version = "0.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50c655d81ff1114fb0dcdea9225ea9f0cc712a6f8d189378e82bdf62a473a64b" +checksum = "126f97965c8ad46d6d9163268ff28432e8f6a1196a55578867832e3049df63dd" dependencies = [ "const_format_proc_macros", ] [[package]] name = "const_format_proc_macros" -version = "0.2.33" +version = "0.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eff1a44b93f47b1bac19a27932f5c591e43d1ba357ee4f61526c8a25603f0eb1" +checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" dependencies = [ "proc-macro2", "quote", @@ -2747,6 +3117,15 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "convert_case" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb402b8d4c85569410425650ce3eddc7d698ed96d39a73f941b08fb63082f1e7" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "cookie" version = "0.17.0" @@ -2785,6 +3164,16 @@ dependencies = [ "libc", ] +[[package]] +name = "core-foundation" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -2802,9 +3191,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" dependencies = [ "libc", ] @@ -2829,9 +3218,10 @@ dependencies = [ "ciborium", "clap", "criterion-plot", + "futures", "is-terminal", "itertools 0.10.5", - "num-traits 0.2.19", + "num-traits", "once_cell", "oorandom", "plotters", @@ -2841,6 +3231,7 @@ dependencies = [ "serde_derive", "serde_json", "tinytemplate", + "tokio", "walkdir", ] @@ -2856,9 +3247,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -2875,18 +3266,18 @@ dependencies = [ [[package]] name = "crossbeam-queue" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" @@ -2960,7 +3351,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -3008,7 +3399,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -3030,7 +3421,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core 0.20.10", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -3110,7 +3501,7 @@ dependencies = [ "displaydoc", "nom", "num-bigint 0.4.6", - "num-traits 0.2.19", + "num-traits", "rusticata-macros", ] @@ -3135,37 +3526,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "derive_builder" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" -dependencies = [ - "derive_builder_macro", -] - -[[package]] -name = "derive_builder_core" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" -dependencies = [ - "darling 0.20.10", - "proc-macro2", - "quote", - "syn 2.0.79", -] - -[[package]] -name = "derive_builder_macro" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" -dependencies = [ - "derive_builder_core", - "syn 2.0.79", -] - [[package]] name = "derive_more" version = "0.99.18" @@ -3176,7 +3536,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version 0.4.1", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -3196,7 +3556,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", "unicode-xid", ] @@ -3292,7 +3652,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -3373,7 +3733,19 @@ dependencies = [ "enum-ordinalize", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", +] + +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.95", ] [[package]] @@ -3412,15 +3784,15 @@ dependencies = [ [[package]] name = "encode_unicode" -version = "0.3.6" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" [[package]] name = "encoding_rs" -version = "0.8.34" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ "cfg-if", ] @@ -3458,18 +3830,18 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] name = "enum-assoc" -version = "1.1.0" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24247b89d37b9502dc5a4b80d369aab1a12106067776e440094c786dae5b9d07" +checksum = "4f4b100e337b021ae69f3e7dd82e230452c54ff833958446c4a3854c66dc9326" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.95", ] [[package]] @@ -3489,7 +3861,7 @@ checksum = "a1ab991c1362ac86c61ab6f556cff143daa22e5a15e4e189df818b2fd19fe65b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -3509,23 +3881,23 @@ checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] name = "env_filter" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" +checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" dependencies = [ "log", ] [[package]] name = "env_logger" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" +checksum = "dcaee3d8e3cfc3fd92428d477bc97fc29ec8716d180c0d74c643bb26166660e0" dependencies = [ "anstream", "anstyle", @@ -3541,9 +3913,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", "windows-sys 0.52.0", @@ -3567,7 +3939,7 @@ dependencies = [ "serde_json", "sha2", "sha3", - "thiserror", + "thiserror 1.0.69", "uuid 0.8.2", ] @@ -3584,7 +3956,7 @@ dependencies = [ "serde", "serde_json", "sha3", - "thiserror", + "thiserror 1.0.69", "uint", ] @@ -3663,7 +4035,7 @@ dependencies = [ "pin-project", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -3685,7 +4057,7 @@ dependencies = [ "reqwest 0.11.27", "serde", "serde_json", - "syn 2.0.79", + "syn 2.0.95", "toml", "walkdir", ] @@ -3703,7 +4075,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -3729,9 +4101,9 @@ dependencies = [ "serde", "serde_json", "strum 0.26.3", - "syn 2.0.79", + "syn 2.0.95", "tempfile", - "thiserror", + "thiserror 1.0.69", "tiny-keccak", "unicode-xid", ] @@ -3745,10 +4117,10 @@ dependencies = [ "chrono", "ethers-core", "reqwest 0.11.27", - "semver 1.0.23", + "semver 1.0.24", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "tracing", ] @@ -3772,7 +4144,7 @@ dependencies = [ "reqwest 0.11.27", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "tokio", "tracing", "tracing-futures", @@ -3804,7 +4176,7 @@ dependencies = [ "reqwest 0.11.27", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-tungstenite", "tracing", @@ -3831,7 +4203,7 @@ dependencies = [ "ethers-core", "rand 0.8.5", "sha2", - "thiserror", + "thiserror 1.0.69", "tracing", ] @@ -3854,12 +4226,12 @@ dependencies = [ "path-slash", "rayon", "regex", - "semver 1.0.23", + "semver 1.0.24", "serde", "serde_json", "solang-parser", "svm-rs", - "thiserror", + "thiserror 1.0.69", "tiny-keccak", "tokio", "tracing", @@ -3881,20 +4253,9 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "event-listener" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d93877bcde0eb80ca09131a08d23f0a5c18a620b01db137dba666d18cd9b30c2" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] - -[[package]] -name = "event-listener" -version = "5.3.1" +version = "5.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" dependencies = [ "concurrent-queue", "parking", @@ -3903,11 +4264,11 @@ dependencies = [ [[package]] name = "event-listener-strategy" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2" dependencies = [ - "event-listener 5.3.1", + "event-listener 5.4.0", "pin-project-lite", ] @@ -3942,9 +4303,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "fastrlp" @@ -3957,6 +4318,17 @@ dependencies = [ "bytes", ] +[[package]] +name = "fastrlp" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce8dba4714ef14b8274c371879b175aa55b16b30f269663f19d576f380018dc4" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", +] + [[package]] name = "ff" version = "0.13.0" @@ -4005,9 +4377,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.34" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" dependencies = [ "crc32fast", "miniz_oxide", @@ -4015,9 +4387,9 @@ dependencies = [ [[package]] name = "flume" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" dependencies = [ "futures-core", "futures-sink", @@ -4033,9 +4405,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "foldhash" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" +checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" [[package]] name = "foreign-types" @@ -4087,6 +4459,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + [[package]] name = "fuchsia-cprng" version = "0.1.1" @@ -4175,11 +4553,11 @@ dependencies = [ [[package]] name = "futures-lite" -version = "2.3.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +checksum = "cef40d21ae2c515b51041df9ed313ed21e572df340ea58a922a0aefe7e8891a1" dependencies = [ - "fastrand 2.1.1", + "fastrand 2.3.0", "futures-core", "futures-io", "parking", @@ -4204,7 +4582,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -4214,7 +4592,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f2f12607f92c69b12ed746fabf9ca4f5c482cba46679c1a75b874ed7c26adb" dependencies = [ "futures-io", - "rustls 0.23.14", + "rustls 0.23.20", "rustls-pki-types", ] @@ -4286,9 +4664,9 @@ dependencies = [ [[package]] name = "genco" -version = "0.17.9" +version = "0.17.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afac3cbb14db69ac9fef9cdb60d8a87e39a7a527f85a81a923436efa40ad42c6" +checksum = "a35958104272e516c2a5f66a9d82fba4784d2b585fc1e2358b8f96e15d342995" dependencies = [ "genco-macros", "relative-path", @@ -4297,13 +4675,13 @@ dependencies = [ [[package]] name = "genco-macros" -version = "0.17.9" +version = "0.17.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "553630feadf7b76442b0849fd25fdf89b860d933623aec9693fed19af0400c78" +checksum = "43eaff6bbc0b3a878361aced5ec6a2818ee7c541c5b33b5880dfa9a86c23e9e7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -4326,10 +4704,22 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "wasm-bindgen", ] +[[package]] +name = "getrandom" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.13.3+wasi-0.2.2", + "windows-targets 0.52.6", +] + [[package]] name = "ghash" version = "0.5.1" @@ -4348,9 +4738,9 @@ checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "glob" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] name = "globset" @@ -4361,7 +4751,7 @@ dependencies = [ "aho-corasick", "bstr", "log", - "regex-automata 0.4.8", + "regex-automata 0.4.9", "regex-syntax 0.8.5", ] @@ -4380,7 +4770,7 @@ dependencies = [ "pin-project", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", @@ -4425,19 +4815,19 @@ dependencies = [ [[package]] name = "good_lp" -version = "1.8.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3198bd13dea84c76a64621d6ee8ee26a4960a9a0d538eca95ca8f1320a469ac9" +checksum = "10efcd6c7d6f84cb5b4f9155248e0675deab9cfb92d0edbcb25cb81490b65ae7" dependencies = [ "fnv", - "minilp", + "microlp", ] [[package]] name = "google-cloud-auth" -version = "0.17.1" +version = "0.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357160f51a60ec3e32169ad687f4abe0ee1e90c73b449aa5d11256c4f1cf2ff6" +checksum = "e57a13fbacc5e9c41ded3ad8d0373175a6b7a6ad430d99e89d314ac121b7ab06" dependencies = [ "async-trait", "base64 0.21.7", @@ -4445,10 +4835,10 @@ dependencies = [ "google-cloud-token", "home", "jsonwebtoken 9.3.0", - "reqwest 0.12.8", + "reqwest 0.12.12", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "time", "tokio", "tracing", @@ -4461,8 +4851,8 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04f945a208886a13d07636f38fb978da371d0abc3e34bad338124b9f8c135a8f" dependencies = [ - "reqwest 0.12.8", - "thiserror", + "reqwest 0.12.12", + "thiserror 1.0.69", "tokio", ] @@ -4486,13 +4876,13 @@ dependencies = [ "percent-encoding", "pkcs8", "regex", - "reqwest 0.12.8", + "reqwest 0.12.12", "reqwest-middleware", "ring 0.17.8", "serde", "serde_json", "sha2", - "thiserror", + "thiserror 1.0.69", "time", "tokio", "tracing", @@ -4583,7 +4973,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.6.0", + "indexmap 2.7.0", "slab", "tokio", "tokio-util", @@ -4592,17 +4982,17 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" +checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" dependencies = [ "atomic-waker", "bytes", "fnv", "futures-core", "futures-sink", - "http 1.1.0", - "indexmap 2.6.0", + "http 1.2.0", + "indexmap 2.7.0", "slab", "tokio", "tokio-util", @@ -4647,9 +5037,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.0" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" dependencies = [ "allocator-api2", "equivalent", @@ -4673,7 +5063,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "765c9198f173dd59ce26ff9f95ef0aafd0a0fe01fb9d72841bc5066a4c06511d" dependencies = [ "byteorder", - "num-traits 0.2.19", + "num-traits", ] [[package]] @@ -4709,12 +5099,6 @@ dependencies = [ "serde", ] -[[package]] -name = "hex-literal" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" - [[package]] name = "hex_fmt" version = "0.3.0" @@ -4723,9 +5107,9 @@ checksum = "b07f60793ff0a4d9cef0f18e63b5357e06209987153a64648c972c1e5aff336f" [[package]] name = "hickory-proto" -version = "0.24.1" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07698b8420e2f0d6447a436ba999ec85d8fbf2a398bbd737b82cac4a2e96e512" +checksum = "447afdcdb8afb9d0a852af6dc65d9b285ce720ed7a59e42a8bf2e931c67bc1b5" dependencies = [ "async-trait", "cfg-if", @@ -4734,12 +5118,12 @@ dependencies = [ "futures-channel", "futures-io", "futures-util", - "idna 0.4.0", + "idna 1.0.3", "ipnet", "once_cell", "rand 0.8.5", - "socket2 0.5.7", - "thiserror", + "socket2 0.5.8", + "thiserror 1.0.69", "tinyvec", "tokio", "tracing", @@ -4748,9 +5132,9 @@ dependencies = [ [[package]] name = "hickory-resolver" -version = "0.24.1" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28757f23aa75c98f254cf0405e6d8c25b831b32921b050a66692427679b1f243" +checksum = "0a2e2aba9c389ce5267d31cf1e4dace82390ae276b0b364ea55630b1fa1b44b4" dependencies = [ "cfg-if", "futures-util", @@ -4762,7 +5146,7 @@ dependencies = [ "rand 0.8.5", "resolv-conf", "smallvec", - "thiserror", + "thiserror 1.0.69", "tokio", "tracing", ] @@ -4787,11 +5171,11 @@ dependencies = [ [[package]] name = "home" -version = "0.5.9" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -4818,9 +5202,9 @@ dependencies = [ [[package]] name = "http" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" dependencies = [ "bytes", "fnv", @@ -4845,7 +5229,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.1.0", + "http 1.2.0", ] [[package]] @@ -4856,7 +5240,7 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "pin-project-lite", ] @@ -4881,9 +5265,9 @@ checksum = "91f255a4535024abf7640cb288260811fc14794f62b063652ed349f9a6c2348e" [[package]] name = "hyper" -version = "0.14.30" +version = "0.14.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" dependencies = [ "bytes", "futures-channel", @@ -4896,7 +5280,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.5.7", + "socket2 0.5.8", "tokio", "tower-service", "tracing", @@ -4905,15 +5289,15 @@ dependencies = [ [[package]] name = "hyper" -version = "1.4.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +checksum = "256fb8d4bd6413123cc9d91832d78325c48ff41677595be797d90f42969beae0" dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.6", - "http 1.1.0", + "h2 0.4.7", + "http 1.2.0", "http-body 1.0.1", "httparse", "httpdate", @@ -4932,12 +5316,30 @@ checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", "http 0.2.12", - "hyper 0.14.30", + "hyper 0.14.32", "log", "rustls 0.21.12", - "rustls-native-certs", + "rustls-native-certs 0.6.3", + "tokio", + "tokio-rustls 0.24.1", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" +dependencies = [ + "futures-util", + "http 1.2.0", + "hyper 1.5.2", + "hyper-util", + "rustls 0.23.20", + "rustls-native-certs 0.8.1", + "rustls-pki-types", "tokio", - "tokio-rustls", + "tokio-rustls 0.26.1", + "tower-service", ] [[package]] @@ -4947,7 +5349,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes", - "hyper 0.14.30", + "hyper 0.14.32", "native-tls", "tokio", "tokio-native-tls", @@ -4961,7 +5363,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.4.1", + "hyper 1.5.2", "hyper-util", "native-tls", "tokio", @@ -4971,18 +5373,18 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", - "hyper 1.4.1", + "hyper 1.5.2", "pin-project-lite", - "socket2 0.5.7", + "socket2 0.5.8", "tokio", "tower-service", "tracing", @@ -5011,6 +5413,124 @@ dependencies = [ "cc", ] +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.95", +] + [[package]] name = "id-arena" version = "2.2.1" @@ -5046,22 +5566,23 @@ dependencies = [ [[package]] name = "idna" -version = "0.4.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "idna_adapter", + "smallvec", + "utf8_iter", ] [[package]] -name = "idna" -version = "0.5.0" +name = "idna_adapter" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "icu_normalizer", + "icu_properties", ] [[package]] @@ -5076,22 +5597,26 @@ dependencies = [ [[package]] name = "if-watch" -version = "3.2.0" +version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6b0422c86d7ce0e97169cc42e04ae643caf278874a7a3c87b8150a220dc7e1e" +checksum = "cdf9d64cfcf380606e64f9a0bcf493616b65331199f984151a6fa11a7b3cde38" dependencies = [ - "async-io 2.3.4", - "core-foundation", + "async-io 2.4.0", + "core-foundation 0.9.4", "fnv", "futures", "if-addrs", "ipnet", "log", + "netlink-packet-core", + "netlink-packet-route", + "netlink-proto", + "netlink-sys", "rtnetlink", "smol", - "system-configuration", + "system-configuration 0.6.1", "tokio", - "windows 0.51.1", + "windows 0.53.0", ] [[package]] @@ -5111,7 +5636,7 @@ dependencies = [ "bytes", "futures", "http 0.2.12", - "hyper 0.14.30", + "hyper 0.14.32", "log", "rand 0.8.5", "tokio", @@ -5129,7 +5654,7 @@ dependencies = [ "globset", "log", "memchr", - "regex-automata 0.4.8", + "regex-automata 0.4.9", "same-file", "walkdir", "winapi-util", @@ -5164,13 +5689,13 @@ dependencies = [ [[package]] name = "impl-trait-for-tuples" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.95", ] [[package]] @@ -5217,12 +5742,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", - "hashbrown 0.15.0", + "hashbrown 0.15.2", "serde", ] @@ -5238,14 +5763,6 @@ version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" -[[package]] -name = "infra_utils" -version = "0.0.0" -dependencies = [ - "rstest", - "tokio", -] - [[package]] name = "inout" version = "0.1.3" @@ -5257,13 +5774,13 @@ dependencies = [ [[package]] name = "insta" -version = "1.40.0" +version = "1.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6593a41c7a73841868772495db7dc1e8ecab43bb5c0b6da2059246c4b506ab60" +checksum = "6513e4067e16e69ed1db5ab56048ed65db32d10ba5fc1217f5393f8f17d8b5a5" dependencies = [ "console", - "lazy_static", "linked-hash-map", + "once_cell", "serde", "similar", ] @@ -5300,7 +5817,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" dependencies = [ - "socket2 0.5.7", + "socket2 0.5.8", "widestring", "windows-sys 0.48.0", "winreg", @@ -5374,11 +5891,20 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "jobserver" @@ -5391,10 +5917,11 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.72" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -5428,11 +5955,11 @@ dependencies = [ "http 0.2.12", "jsonrpsee-core", "pin-project", - "rustls-native-certs", + "rustls-native-certs 0.6.3", "soketto", - "thiserror", + "thiserror 1.0.69", "tokio", - "tokio-rustls", + "tokio-rustls 0.24.1", "tokio-util", "tracing", "url", @@ -5451,7 +5978,7 @@ dependencies = [ "beef", "futures-timer", "futures-util", - "hyper 0.14.30", + "hyper 0.14.32", "jsonrpsee-types", "parking_lot", "rand 0.8.5", @@ -5459,7 +5986,7 @@ dependencies = [ "serde", "serde_json", "soketto", - "thiserror", + "thiserror 1.0.69", "tokio", "tracing", "wasm-bindgen-futures", @@ -5472,13 +5999,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c7b9f95208927653e7965a98525e7fc641781cab89f0e27c43fa2974405683" dependencies = [ "async-trait", - "hyper 0.14.30", - "hyper-rustls", + "hyper 0.14.32", + "hyper-rustls 0.24.2", "jsonrpsee-core", "jsonrpsee-types", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "tokio", "tower 0.4.13", "tracing", @@ -5506,14 +6033,14 @@ checksum = "a482bc4e25eebd0adb61a3468c722763c381225bd3ec46e926f709df8a8eb548" dependencies = [ "futures-util", "http 0.2.12", - "hyper 0.14.30", + "hyper 0.14.32", "jsonrpsee-core", "jsonrpsee-types", "route-recognizer", "serde", "serde_json", "soketto", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", "tokio-util", @@ -5531,7 +6058,7 @@ dependencies = [ "beef", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "tracing", ] @@ -5572,7 +6099,7 @@ dependencies = [ "clap", "fancy-regex", "fraction", - "getrandom", + "getrandom 0.2.15", "iso8601", "itoa", "memchr", @@ -5586,7 +6113,7 @@ dependencies = [ "serde_json", "time", "url", - "uuid 1.10.0", + "uuid 1.11.0", ] [[package]] @@ -5688,7 +6215,7 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" dependencies = [ - "regex-automata 0.4.8", + "regex-automata 0.4.9", ] [[package]] @@ -5730,25 +6257,25 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.159" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "libloading" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets 0.48.5", ] [[package]] name = "libm" -version = "0.2.8" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" [[package]] name = "libmdbx" @@ -5764,7 +6291,7 @@ dependencies = [ "lifetimed-bytes", "mdbx-sys", "parking_lot", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -5777,7 +6304,7 @@ dependencies = [ "either", "futures", "futures-timer", - "getrandom", + "getrandom 0.2.15", "instant", "libp2p-allow-block-list", "libp2p-connection-limits", @@ -5798,7 +6325,7 @@ dependencies = [ "multiaddr", "pin-project", "rw-stream-sink", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -5847,7 +6374,7 @@ dependencies = [ "rw-stream-sink", "serde", "smallvec", - "thiserror", + "thiserror 1.0.69", "tracing", "unsigned-varint 0.8.0", "void", @@ -5884,7 +6411,7 @@ dependencies = [ "fnv", "futures", "futures-ticker", - "getrandom", + "getrandom 0.2.15", "hex_fmt", "instant", "libp2p-core", @@ -5920,16 +6447,16 @@ dependencies = [ "quick-protobuf", "quick-protobuf-codec 0.3.1", "smallvec", - "thiserror", + "thiserror 1.0.69", "tracing", "void", ] [[package]] name = "libp2p-identity" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cca1eb2bc1fd29f099f3daaab7effd01e1a54b7c577d0ed082521034d912e8" +checksum = "257b5621d159b32282eac446bed6670c39c7dc68a200a992d8f056afa0066f6d" dependencies = [ "bs58", "ed25519-dalek", @@ -5939,7 +6466,7 @@ dependencies = [ "rand 0.8.5", "serde", "sha2", - "thiserror", + "thiserror 1.0.69", "tracing", "zeroize", ] @@ -5968,7 +6495,7 @@ dependencies = [ "serde", "sha2", "smallvec", - "thiserror", + "thiserror 1.0.69", "tracing", "uint", "void", @@ -5989,7 +6516,7 @@ dependencies = [ "libp2p-swarm", "rand 0.8.5", "smallvec", - "socket2 0.5.7", + "socket2 0.5.8", "tokio", "tracing", "void", @@ -6033,7 +6560,7 @@ dependencies = [ "sha2", "snow", "static_assertions", - "thiserror", + "thiserror 1.0.69", "tracing", "x25519-dalek", "zeroize", @@ -6072,9 +6599,9 @@ dependencies = [ "quinn", "rand 0.8.5", "ring 0.17.8", - "rustls 0.23.14", - "socket2 0.5.7", - "thiserror", + "rustls 0.23.20", + "socket2 0.5.8", + "thiserror 1.0.69", "tokio", "tracing", ] @@ -6113,7 +6640,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -6148,7 +6675,7 @@ dependencies = [ "libc", "libp2p-core", "libp2p-identity", - "socket2 0.5.7", + "socket2 0.5.8", "tokio", "tracing", ] @@ -6165,9 +6692,9 @@ dependencies = [ "libp2p-identity", "rcgen", "ring 0.17.8", - "rustls 0.23.14", + "rustls 0.23.20", "rustls-webpki 0.101.7", - "thiserror", + "thiserror 1.0.69", "x509-parser", "yasna", ] @@ -6197,10 +6724,10 @@ dependencies = [ "either", "futures", "libp2p-core", - "thiserror", + "thiserror 1.0.69", "tracing", "yamux 0.12.1", - "yamux 0.13.3", + "yamux 0.13.4", ] [[package]] @@ -6248,9 +6775,15 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "litemap" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" [[package]] name = "llvm-sys" @@ -6263,7 +6796,7 @@ dependencies = [ "lazy_static", "libc", "regex-lite", - "semver 1.0.23", + "semver 1.0.24", ] [[package]] @@ -6291,7 +6824,7 @@ version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" dependencies = [ - "hashbrown 0.15.0", + "hashbrown 0.15.2", ] [[package]] @@ -6341,10 +6874,11 @@ checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" [[package]] name = "matrixmultiply" -version = "0.2.4" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "916806ba0031cd542105d916a97c8572e1fa6dd79c9c51e7eb43a09ec2dd84c1" +checksum = "9380b911e3e96d10c1f415da0876389aaf1b56759054eeb0de7df940c456ba1a" dependencies = [ + "autocfg 1.4.0", "rawpointer", ] @@ -6371,30 +6905,27 @@ dependencies = [ [[package]] name = "melior" -version = "0.19.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5d97014786c173a839839e2a068e82516ad1eb94fca1d40013d3c5e224e7c1e" +checksum = "f2af6454b7bcd7edc8c2060a3726a18ceaed60e25c34d9f8de9c6b44e82eb647" dependencies = [ - "dashmap", "melior-macro", "mlir-sys", - "once_cell", ] [[package]] name = "melior-macro" -version = "0.12.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef7ae0ba2f96784ec407d58374c8477f5b04ec8c57a114cafef0c8f165c4b288" +checksum = "a99671327250df8e24e56d8304474a970e7a2c6bb8f6dc71382d188136fe4d1b" dependencies = [ "comrak", - "convert_case 0.6.0", - "once_cell", + "convert_case 0.7.1", "proc-macro2", "quote", "regex", - "syn 2.0.79", - "tblgen-alt", + "syn 2.0.95", + "tblgen", "unindent 0.2.3", ] @@ -6436,30 +6967,28 @@ name = "mempool_test_utils" version = "0.0.0" dependencies = [ "assert_matches", - "blockifier", - "infra_utils", - "pretty_assertions", + "blockifier_test_utils", "serde_json", "starknet-types-core", "starknet_api", + "starknet_infra_utils", ] [[package]] name = "metrics" -version = "0.21.1" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fde3af1a009ed76a778cb84fdef9e7dbbdf5775ae3e4cc1f434a6a307f6f76c5" +checksum = "2be3cbd384d4e955b231c895ce10685e3d8260c5ccffae898c96c723b0772835" dependencies = [ "ahash", - "metrics-macros", "portable-atomic", ] [[package]] name = "metrics" -version = "0.22.3" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2be3cbd384d4e955b231c895ce10685e3d8260c5ccffae898c96c723b0772835" +checksum = "7a7deb012b3b2767169ff203fadb4c6b0b82b947512e5eb9e0b78c2e186ad9e3" dependencies = [ "ahash", "portable-atomic", @@ -6467,33 +6996,25 @@ dependencies = [ [[package]] name = "metrics-exporter-prometheus" -version = "0.12.2" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d4fa7ce7c4862db464a37b0b31d89bca874562f034bd7993895572783d02950" +checksum = "12779523996a67c13c84906a876ac6fe4d07a6e1adb54978378e13f199251a62" dependencies = [ - "base64 0.21.7", - "hyper 0.14.30", - "indexmap 1.9.3", + "base64 0.22.1", + "http-body-util", + "hyper 1.5.2", + "hyper-rustls 0.27.5", + "hyper-util", + "indexmap 2.7.0", "ipnet", - "metrics 0.21.1", + "metrics 0.24.1", "metrics-util", "quanta", - "thiserror", + "thiserror 1.0.69", "tokio", "tracing", ] -[[package]] -name = "metrics-macros" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b4faf00617defe497754acde3024865bc143d44a86799b24e191ecff91354f" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.79", -] - [[package]] name = "metrics-process" version = "1.2.1" @@ -6511,19 +7032,30 @@ dependencies = [ [[package]] name = "metrics-util" -version = "0.15.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "111cb375987443c3de8d503580b536f77dc8416d32db62d9456db5d93bd7ac47" +checksum = "dbd4884b1dd24f7d6628274a2f5ae22465c337c5ba065ec9b6edccddf8acc673" dependencies = [ "crossbeam-epoch", "crossbeam-utils", - "hashbrown 0.13.2", - "metrics 0.21.1", - "num_cpus", + "hashbrown 0.15.2", + "metrics 0.24.1", "quanta", + "rand 0.8.5", + "rand_xoshiro", "sketches-ddsketch", ] +[[package]] +name = "microlp" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8113ec0619201ef0ead05ecafe9ba59b525ab73508456b8d35dbaf810cd07704" +dependencies = [ + "log", + "sprs", +] + [[package]] name = "mime" version = "0.3.17" @@ -6540,16 +7072,6 @@ dependencies = [ "unicase", ] -[[package]] -name = "minilp" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82a7750a9e5076c660b7bec5e6457b4dbff402b9863c8d112891434e18fd5385" -dependencies = [ - "log", - "sprs", -] - [[package]] name = "minimal-lexical" version = "0.2.1" @@ -6558,32 +7080,31 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" dependencies = [ "adler2", ] [[package]] name = "mio" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ - "hermit-abi 0.3.9", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.52.0", ] [[package]] name = "mlir-sys" -version = "0.3.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fae0a14b0940736a243fef4a4d96d8cdf8a253272031b63c5e4b1bea207c82b0" +checksum = "21b598f9c0fa7a453eeaa9fe419ae93759c94a66eb6f8a496d195ba596ae3c4d" dependencies = [ - "bindgen 0.70.1", + "bindgen 0.71.1", ] [[package]] @@ -6610,7 +7131,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -6620,7 +7141,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80f9fece9bd97ab74339fe19f4bcaf52b76dcc18e5364c7977c1838f76b38de9" dependencies = [ "assert-json-diff", - "colored", + "colored 2.2.0", "httparse", "lazy_static", "log", @@ -6633,18 +7154,18 @@ dependencies = [ [[package]] name = "mockito" -version = "1.5.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b34bd91b9e5c5b06338d392463e1318d683cf82ec3d3af4014609be6e2108d" +checksum = "652cd6d169a36eaf9d1e6bce1a221130439a966d7f27858af66a33a66e9c4ee2" dependencies = [ "assert-json-diff", "bytes", - "colored", + "colored 2.2.0", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", - "hyper 1.4.1", + "hyper 1.5.2", "hyper-util", "log", "rand 0.8.5", @@ -6687,13 +7208,13 @@ dependencies = [ [[package]] name = "multihash" -version = "0.19.1" +version = "0.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076d548d76a0e2a0d4ab471d0b1c36c577786dfc4471242035d97a12a735c492" +checksum = "6b430e7953c29dd6a09afc29ff0bb69c6e306329ee6794700aee27b76a1aea8d" dependencies = [ "core2", "serde", - "unsigned-varint 0.7.2", + "unsigned-varint 0.8.0", ] [[package]] @@ -6722,7 +7243,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" dependencies = [ - "getrandom", + "getrandom 0.2.15", ] [[package]] @@ -6737,7 +7258,7 @@ dependencies = [ "openssl-probe", "openssl-sys", "schannel", - "security-framework", + "security-framework 2.11.1", "security-framework-sys", "tempfile", ] @@ -6750,7 +7271,7 @@ dependencies = [ "cached", "cairo-lang-starknet-classes", "cairo-vm", - "indexmap 2.6.0", + "indexmap 2.7.0", "log", "num-bigint 0.4.6", "papyrus_state_reader", @@ -6758,44 +7279,46 @@ dependencies = [ "pretty_assertions", "pyo3", "pyo3-log", - "serde", "serde_json", + "shared_execution_objects", "starknet-types-core", "starknet_api", + "starknet_sierra_multicompile", "tempfile", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "ndarray" -version = "0.13.1" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac06db03ec2f46ee0ecdca1a1c34a99c0d188a0d83439b84bf0cb4b386e4ab09" +checksum = "882ed72dce9365842bf196bdeedf5055305f11fc8c03dee7bb0194a6cad34841" dependencies = [ "matrixmultiply", - "num-complex 0.2.4", + "num-complex 0.4.6", "num-integer", - "num-traits 0.2.19", + "num-traits", + "portable-atomic", + "portable-atomic-util", "rawpointer", ] [[package]] name = "netlink-packet-core" -version = "0.4.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "345b8ab5bd4e71a2986663e88c56856699d060e78e152e6e9d7966fcd5491297" +checksum = "72724faf704479d67b388da142b186f916188505e7e0b26719019c525882eda4" dependencies = [ "anyhow", "byteorder", - "libc", "netlink-packet-utils", ] [[package]] name = "netlink-packet-route" -version = "0.12.0" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9ea4302b9759a7a88242299225ea3688e63c85ea136371bb6cf94fd674efaab" +checksum = "053998cea5a306971f88580d0829e90f270f940befd7cf928da179d4187a5a66" dependencies = [ "anyhow", "bitflags 1.2.1", @@ -6814,31 +7337,31 @@ dependencies = [ "anyhow", "byteorder", "paste", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "netlink-proto" -version = "0.10.0" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65b4b14489ab424703c092062176d52ba55485a89c076b4f9db05092b7223aa6" +checksum = "86b33524dc0968bfad349684447bfce6db937a9ac3332a1fe60c0c5a5ce63f21" dependencies = [ "bytes", "futures", "log", "netlink-packet-core", "netlink-sys", - "thiserror", + "thiserror 1.0.69", "tokio", ] [[package]] name = "netlink-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "416060d346fbaf1f23f9512963e3e878f1a78e707cb699ba9215761754244307" +checksum = "16c903aa70590cb93691bf97a767c8d1d6122d2cc9070433deb3bbf36ce8bd23" dependencies = [ - "async-io 1.13.0", + "async-io 2.4.0", "bytes", "futures", "libc", @@ -6867,9 +7390,9 @@ dependencies = [ [[package]] name = "nix" -version = "0.24.3" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" dependencies = [ "bitflags 1.2.1", "cfg-if", @@ -6925,7 +7448,7 @@ dependencies = [ "num-integer", "num-iter", "num-rational 0.2.4", - "num-traits 0.2.19", + "num-traits", ] [[package]] @@ -6939,7 +7462,7 @@ dependencies = [ "num-integer", "num-iter", "num-rational 0.4.2", - "num-traits 0.2.19", + "num-traits", ] [[package]] @@ -6950,7 +7473,7 @@ checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" dependencies = [ "autocfg 1.4.0", "num-integer", - "num-traits 0.2.19", + "num-traits", ] [[package]] @@ -6960,7 +7483,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", - "num-traits 0.2.19", + "num-traits", "rand 0.8.5", "serde", ] @@ -6978,7 +7501,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95" dependencies = [ "autocfg 1.4.0", - "num-traits 0.2.19", + "num-traits", ] [[package]] @@ -6987,7 +7510,7 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" dependencies = [ - "num-traits 0.2.19", + "num-traits", ] [[package]] @@ -7012,7 +7535,7 @@ version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "num-traits 0.2.19", + "num-traits", ] [[package]] @@ -7023,7 +7546,7 @@ checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" dependencies = [ "autocfg 1.4.0", "num-integer", - "num-traits 0.2.19", + "num-traits", ] [[package]] @@ -7034,7 +7557,7 @@ checksum = "64a5fe11d4135c3bcdf3a95b18b194afa9608a5f6ff034f5d857bc9a27fb0119" dependencies = [ "num-bigint 0.4.6", "num-integer", - "num-traits 0.2.19", + "num-traits", ] [[package]] @@ -7049,7 +7572,7 @@ dependencies = [ "num-bigint 0.4.6", "num-integer", "num-modular", - "num-traits 0.2.19", + "num-traits", "rand 0.8.5", ] @@ -7062,7 +7585,7 @@ dependencies = [ "autocfg 1.4.0", "num-bigint 0.2.6", "num-integer", - "num-traits 0.2.19", + "num-traits", ] [[package]] @@ -7073,19 +7596,10 @@ checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" dependencies = [ "num-bigint 0.4.6", "num-integer", - "num-traits 0.2.19", + "num-traits", "serde", ] -[[package]] -name = "num-traits" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" -dependencies = [ - "num-traits 0.2.19", -] - [[package]] name = "num-traits" version = "0.2.19" @@ -7121,10 +7635,10 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ - "proc-macro-crate 3.2.0", + "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -7136,11 +7650,24 @@ dependencies = [ "libc", ] +[[package]] +name = "nybbles" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8983bb634df7248924ee0c4c3a749609b5abcb082c28fffe3254b3eb3602b307" +dependencies = [ + "alloy-rlp", + "const-hex", + "proptest", + "serde", + "smallvec", +] + [[package]] name = "object" -version = "0.36.5" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] @@ -7199,9 +7726,9 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.66" +version = "0.10.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" +checksum = "f5e534d133a060a3c19daec1eb3e98ec6f4685978834f2dbadfe2ec215bab64e" dependencies = [ "bitflags 2.6.0", "cfg-if", @@ -7220,20 +7747,20 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] name = "openssl-probe" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-sys" -version = "0.9.103" +version = "0.9.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" +checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" dependencies = [ "cc", "libc", @@ -7249,9 +7776,9 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "os_info" -version = "3.8.2" +version = "3.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae99c7fa6dd38c7cafe1ec085e804f8f555a2f8659b0dbe03f1f9963a9b51092" +checksum = "6e6520c8cc998c5741ee68ec1dc369fc47e5f0ea5320018ecf2a1ccd6328f48b" dependencies = [ "log", "serde", @@ -7278,29 +7805,24 @@ dependencies = [ name = "papyrus_base_layer" version = "0.0.0" dependencies = [ - "alloy-contract", - "alloy-dyn-abi", - "alloy-json-rpc", - "alloy-primitives", - "alloy-provider", - "alloy-sol-types", - "alloy-transport", - "alloy-transport-http", + "alloy", "async-trait", + "colored 3.0.0", "ethers", "ethers-core", - "papyrus_base_layer", + "mempool_test_utils", + "mockall", "papyrus_config", "pretty_assertions", "serde", - "serde_json", "starknet-types-core", "starknet_api", "tar", "tempfile", - "thiserror", + "thiserror 1.0.69", "tokio", "url", + "validator", ] [[package]] @@ -7311,17 +7833,15 @@ dependencies = [ "base64 0.13.1", "cairo-lang-starknet-classes", "flate2", - "indexmap 2.6.0", - "lazy_static", + "indexmap 2.7.0", "papyrus_test_utils", "pretty_assertions", "rand 0.8.5", "serde", "serde_json", - "sha3", "starknet-types-core", "starknet_api", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -7330,69 +7850,18 @@ version = "0.0.0" dependencies = [ "assert_matches", "clap", - "infra_utils", "itertools 0.12.1", "lazy_static", "papyrus_test_utils", "serde", "serde_json", "starknet_api", + "starknet_infra_utils", "strum_macros 0.25.3", "tempfile", - "thiserror", - "validator", -] - -[[package]] -name = "papyrus_consensus" -version = "0.0.0" -dependencies = [ - "async-trait", - "clap", - "enum-as-inner", - "fs2", - "futures", - "lazy_static", - "lru", - "metrics 0.21.1", - "mockall", - "nix 0.20.2", - "papyrus_common", - "papyrus_config", - "papyrus_network", - "papyrus_network_types", - "papyrus_protobuf", - "papyrus_storage", - "papyrus_test_utils", - "serde", - "starknet-types-core", - "starknet_api", - "test-case", - "thiserror", - "tokio", - "tracing", -] - -[[package]] -name = "papyrus_consensus_orchestrator" -version = "0.0.0" -dependencies = [ - "async-trait", - "chrono", - "futures", - "lazy_static", - "mockall", - "papyrus_consensus", - "papyrus_network", - "papyrus_protobuf", - "papyrus_storage", - "papyrus_test_utils", - "starknet-types-core", - "starknet_api", - "starknet_batcher_types", - "test-case", - "tokio", + "thiserror 1.0.69", "tracing", + "validator", ] [[package]] @@ -7406,7 +7875,7 @@ dependencies = [ "cairo-lang-starknet-classes", "cairo-lang-utils", "cairo-vm", - "indexmap 2.6.0", + "indexmap 2.7.0", "itertools 0.12.1", "lazy_static", "papyrus_common", @@ -7420,7 +7889,7 @@ dependencies = [ "serde_json", "starknet-types-core", "starknet_api", - "thiserror", + "thiserror 1.0.69", "tracing", ] @@ -7447,8 +7916,8 @@ name = "papyrus_monitoring_gateway" version = "0.0.0" dependencies = [ "axum", - "hyper 0.14.30", - "metrics 0.21.1", + "hyper 0.14.32", + "metrics 0.24.1", "metrics-exporter-prometheus", "metrics-process", "papyrus_config", @@ -7458,7 +7927,7 @@ dependencies = [ "serde", "serde_json", "starknet_client", - "thiserror", + "thiserror 1.0.69", "tokio", "tower 0.4.13", "tracing", @@ -7480,16 +7949,16 @@ dependencies = [ "lazy_static", "libp2p", "libp2p-swarm-test", - "metrics 0.21.1", + "metrics 0.24.1", "mockall", - "papyrus_common", "papyrus_config", "papyrus_network_types", "pretty_assertions", "replace_with", "serde", "starknet_api", - "thiserror", + "starknet_sequencer_metrics", + "thiserror 1.0.69", "tokio", "tokio-retry", "tokio-stream", @@ -7514,13 +7983,11 @@ name = "papyrus_node" version = "0.0.0" dependencies = [ "anyhow", - "assert-json-diff", "clap", - "colored", + "colored 3.0.0", "const_format", "futures", "futures-util", - "infra_utils", "insta", "itertools 0.12.1", "lazy_static", @@ -7529,8 +7996,6 @@ dependencies = [ "papyrus_base_layer", "papyrus_common", "papyrus_config", - "papyrus_consensus", - "papyrus_consensus_orchestrator", "papyrus_monitoring_gateway", "papyrus_network", "papyrus_p2p_sync", @@ -7543,7 +8008,11 @@ dependencies = [ "serde", "serde_json", "starknet_api", + "starknet_class_manager_types", "starknet_client", + "starknet_consensus", + "starknet_consensus_orchestrator", + "starknet_infra_utils", "strum 0.25.0", "tempfile", "tokio", @@ -7559,42 +8028,51 @@ version = "0.0.0" dependencies = [ "assert_matches", "async-stream", + "async-trait", "chrono", "enum-iterator", "futures", - "indexmap 2.6.0", + "indexmap 2.7.0", "lazy_static", - "metrics 0.21.1", + "metrics 0.24.1", + "mockall", "papyrus_common", "papyrus_config", "papyrus_network", "papyrus_proc_macros", "papyrus_protobuf", "papyrus_storage", + "papyrus_sync", "papyrus_test_utils", "rand 0.8.5", "rand_chacha 0.3.1", "serde", "starknet-types-core", "starknet_api", + "starknet_class_manager_types", + "starknet_state_sync_types", "static_assertions", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", "tracing", + "validator", ] [[package]] name = "papyrus_proc_macros" version = "0.0.0" dependencies = [ - "metrics 0.21.1", + "metrics 0.24.1", "metrics-exporter-prometheus", "papyrus_common", "papyrus_test_utils", "prometheus-parse", "quote", - "syn 2.0.79", + "rstest", + "starknet_monitoring_endpoint", + "starknet_sequencer_metrics", + "syn 2.0.95", "tracing", ] @@ -7602,8 +8080,8 @@ dependencies = [ name = "papyrus_protobuf" version = "0.0.0" dependencies = [ - "futures", - "indexmap 2.6.0", + "bytes", + "indexmap 2.7.0", "lazy_static", "papyrus_common", "papyrus_test_utils", @@ -7617,7 +8095,9 @@ dependencies = [ "serde_json", "starknet-types-core", "starknet_api", - "thiserror", + "tempfile", + "thiserror 1.0.69", + "tracing", ] [[package]] @@ -7637,14 +8117,14 @@ dependencies = [ "flate2", "futures-util", "hex", - "hyper 0.14.30", - "indexmap 2.6.0", + "hyper 0.14.32", + "indexmap 2.7.0", "insta", "itertools 0.12.1", "jsonrpsee", "jsonschema", "lazy_static", - "metrics 0.21.1", + "metrics 0.24.1", "metrics-exporter-prometheus", "mockall", "papyrus_common", @@ -7679,10 +8159,16 @@ version = "0.0.0" dependencies = [ "assert_matches", "blockifier", - "indexmap 2.6.0", + "blockifier_test_utils", + "cairo-lang-starknet-classes", + "indexmap 2.7.0", + "log", "papyrus_storage", + "rstest", "starknet-types-core", "starknet_api", + "starknet_class_manager_types", + "tokio", ] [[package]] @@ -7697,16 +8183,16 @@ dependencies = [ "camelpaste", "clap", "human_bytes", - "indexmap 2.6.0", + "indexmap 2.7.0", "insta", "integer-encoding", "lazy_static", "libmdbx", "memmap2", - "metrics 0.21.1", + "metrics 0.24.1", "metrics-exporter-prometheus", "num-bigint 0.4.6", - "num-traits 0.2.19", + "num-traits", "page_size", "papyrus_common", "papyrus_config", @@ -7719,6 +8205,7 @@ dependencies = [ "prometheus-parse", "rand 0.8.5", "rand_chacha 0.3.1", + "rstest", "schemars", "serde", "serde_json", @@ -7729,7 +8216,7 @@ dependencies = [ "tempfile", "test-case", "test-log", - "thiserror", + "thiserror 1.0.69", "tokio", "tracing", "validator", @@ -7747,10 +8234,10 @@ dependencies = [ "chrono", "futures", "futures-util", - "indexmap 2.6.0", + "indexmap 2.7.0", "itertools 0.12.1", "lru", - "metrics 0.21.1", + "metrics 0.24.1", "mockall", "papyrus_base_layer", "papyrus_common", @@ -7764,8 +8251,10 @@ dependencies = [ "simple_logger", "starknet-types-core", "starknet_api", + "starknet_class_manager_types", "starknet_client", - "thiserror", + "starknet_sequencer_metrics", + "thiserror 1.0.69", "tokio", "tokio-stream", "tracing", @@ -7778,7 +8267,7 @@ dependencies = [ "cairo-lang-casm", "cairo-lang-starknet-classes", "cairo-lang-utils", - "indexmap 2.6.0", + "indexmap 2.7.0", "num-bigint 0.4.6", "pretty_assertions", "primitive-types", @@ -7794,9 +8283,9 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "3.6.9" +version = "3.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe" +checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" dependencies = [ "arrayvec", "bitvec", @@ -7940,12 +8429,12 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.13" +version = "2.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdbef9d1d47087a895abd220ed25eb4ad973a5e26f6a4367b038c25e28dfc2d9" +checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc" dependencies = [ "memchr", - "thiserror", + "thiserror 2.0.12", "ucd-trie", ] @@ -7956,7 +8445,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.6.0", + "indexmap 2.7.0", ] [[package]] @@ -7971,35 +8460,35 @@ dependencies = [ [[package]] name = "phf" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" dependencies = [ "phf_macros", - "phf_shared 0.11.2", + "phf_shared 0.11.3", ] [[package]] name = "phf_generator" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" dependencies = [ - "phf_shared 0.11.2", + "phf_shared 0.11.3", "rand 0.8.5", ] [[package]] name = "phf_macros" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" dependencies = [ "phf_generator", - "phf_shared 0.11.2", + "phf_shared 0.11.3", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -8008,16 +8497,16 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" dependencies = [ - "siphasher", + "siphasher 0.3.11", ] [[package]] name = "phf_shared" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" dependencies = [ - "siphasher", + "siphasher 1.0.1", ] [[package]] @@ -8028,29 +8517,29 @@ checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" [[package]] name = "pin-project" -version = "1.1.6" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf123a161dde1e524adf36f90bc5d8d3462824a9c43553ad07a8183161189ec" +checksum = "1e2ec53ad785f4d35dac0adea7f7dc6f1bb277ad84a680c7afefeae05d1f5916" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.6" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4502d8515ca9f32f1fb543d987f63d95a14934883db45bdb48060b6b69257f8" +checksum = "d56a66c0c55993aa927429d0f8a0abfd74f084e4d9c192cffed01e418d83eefb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -8065,7 +8554,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" dependencies = [ "atomic-waker", - "fastrand 2.1.1", + "fastrand 2.3.0", "futures-io", ] @@ -8091,7 +8580,7 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" dependencies = [ - "num-traits 0.2.19", + "num-traits", "plotters-backend", "plotters-svg", "wasm-bindgen", @@ -8129,15 +8618,15 @@ dependencies = [ [[package]] name = "polling" -version = "3.7.3" +version = "3.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511" +checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" dependencies = [ "cfg-if", "concurrent-queue", "hermit-abi 0.4.0", "pin-project-lite", - "rustix 0.38.37", + "rustix 0.38.43", "tracing", "windows-sys 0.59.0", ] @@ -8167,9 +8656,18 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.9.0" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" + +[[package]] +name = "portable-atomic-util" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] [[package]] name = "powerfmt" @@ -8183,7 +8681,7 @@ version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" dependencies = [ - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -8194,9 +8692,9 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "predicates" -version = "3.1.2" +version = "3.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e9086cc7640c29a356d1a29fd134380bee9d8f79a17410aa76e7ad295f42c97" +checksum = "a5d19ee57562043d37e82899fade9a22ebab7be9cef5026b07fda9cdd4293573" dependencies = [ "anstyle", "predicates-core", @@ -8204,15 +8702,15 @@ dependencies = [ [[package]] name = "predicates-core" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae8177bee8e75d6846599c6b9ff679ed51e882816914eec639944d7c9aa11931" +checksum = "727e462b119fe9c93fd0eb1429a5f7647394014cf3c04ab2c0350eeb09095ffa" [[package]] name = "predicates-tree" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41b740d195ed3166cd147c8047ec98db0e22ec019eb8eeb76d343b795304fb13" +checksum = "72dd2d6d381dfb73a193c7fca536518d7caee39fc8503f74e7dc0be0531b425c" dependencies = [ "predicates-core", "termtree", @@ -8230,12 +8728,12 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.22" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" +checksum = "483f8c21f64f3ea09fe0f30f5d48c3e8eefe5dac9129f0075f76593b4c1da705" dependencies = [ "proc-macro2", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -8314,14 +8812,14 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] name = "proc-macro2" -version = "1.0.87" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -8336,7 +8834,7 @@ dependencies = [ "hex", "lazy_static", "procfs-core", - "rustix 0.38.37", + "rustix 0.38.43", ] [[package]] @@ -8369,7 +8867,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -8394,7 +8892,7 @@ dependencies = [ "bit-vec", "bitflags 2.6.0", "lazy_static", - "num-traits 0.2.19", + "num-traits", "rand 0.8.5", "rand_chacha 0.3.1", "rand_xorshift 0.3.0", @@ -8431,7 +8929,7 @@ dependencies = [ "prost", "prost-types", "regex", - "syn 2.0.79", + "syn 2.0.95", "tempfile", ] @@ -8445,7 +8943,7 @@ dependencies = [ "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -8475,11 +8973,11 @@ checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac" [[package]] name = "publicsuffix" -version = "2.2.3" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96a8c1bda5ae1af7f99a2962e49df150414a43d62404644d98dd5c3a93d07457" +checksum = "6f42ea446cab60335f76979ec15e12619a2165b5ae2c12166bef27d283a9fadf" dependencies = [ - "idna 0.3.0", + "idna 1.0.3", "psl-types", ] @@ -8558,16 +9056,15 @@ dependencies = [ [[package]] name = "quanta" -version = "0.11.1" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17e662a7a8291a865152364c20c7abc5e60486ab2001e8ec10b24862de0b9ab" +checksum = "3bd1fe6824cea6538803de3ff1bc0cf3949024db3d43c9643024bfb33a807c0e" dependencies = [ "crossbeam-utils", "libc", - "mach2", "once_cell", "raw-cpuid", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "web-sys", "winapi", ] @@ -8596,7 +9093,7 @@ dependencies = [ "asynchronous-codec 0.6.2", "bytes", "quick-protobuf", - "thiserror", + "thiserror 1.0.69", "unsigned-varint 0.7.2", ] @@ -8609,64 +9106,68 @@ dependencies = [ "asynchronous-codec 0.7.0", "bytes", "quick-protobuf", - "thiserror", + "thiserror 1.0.69", "unsigned-varint 0.8.0", ] [[package]] name = "quinn" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c7c5fdde3cdae7203427dc4f0a68fe0ed09833edc525a03456b153b79828684" +checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef" dependencies = [ "bytes", "futures-io", "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash 2.0.0", - "rustls 0.23.14", - "socket2 0.5.7", - "thiserror", + "rustc-hash 2.1.0", + "rustls 0.23.20", + "socket2 0.5.8", + "thiserror 2.0.12", "tokio", "tracing", ] [[package]] name = "quinn-proto" -version = "0.11.8" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" +checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" dependencies = [ "bytes", + "getrandom 0.2.15", "rand 0.8.5", "ring 0.17.8", - "rustc-hash 2.0.0", - "rustls 0.23.14", + "rustc-hash 2.1.0", + "rustls 0.23.20", + "rustls-pki-types", "slab", - "thiserror", + "thiserror 2.0.12", "tinyvec", "tracing", + "web-time", ] [[package]] name = "quinn-udp" -version = "0.5.5" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fe68c2e9e1a1234e218683dbdf9f9dfcb094113c5ac2b938dfcb9bab4c4140b" +checksum = "1c40286217b4ba3a71d644d752e6a0b71f13f1b6a2c5311acfcbe0c2418ed904" dependencies = [ + "cfg_aliases", "libc", "once_cell", - "socket2 0.5.7", + "socket2 0.5.8", "tracing", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] name = "quote" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] @@ -8708,6 +9209,17 @@ dependencies = [ "serde", ] +[[package]] +name = "rand" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", + "zerocopy 0.8.23", +] + [[package]] name = "rand_chacha" version = "0.1.1" @@ -8728,6 +9240,16 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.3", +] + [[package]] name = "rand_core" version = "0.3.1" @@ -8749,7 +9271,16 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.15", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.1", ] [[package]] @@ -8758,7 +9289,7 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" dependencies = [ - "num-traits 0.2.19", + "num-traits", "rand 0.8.5", ] @@ -8833,13 +9364,22 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "rand_xoshiro" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" +dependencies = [ + "rand_core 0.6.4", +] + [[package]] name = "raw-cpuid" -version = "10.7.0" +version = "11.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332" +checksum = "1ab240315c661615f2ee9f0f2cd32d5a7343a84d5ebcccb99d46e6637565e7b0" dependencies = [ - "bitflags 1.2.1", + "bitflags 2.6.0", ] [[package]] @@ -8891,9 +9431,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ "bitflags 2.6.0", ] @@ -8904,20 +9444,20 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ - "getrandom", + "getrandom 0.2.15", "libredox", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "regex" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.8", + "regex-automata 0.4.9", "regex-syntax 0.8.5", ] @@ -8932,9 +9472,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -8988,8 +9528,8 @@ dependencies = [ "h2 0.3.26", "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.30", - "hyper-rustls", + "hyper 0.14.32", + "hyper-rustls 0.24.2", "hyper-tls 0.5.0", "ipnet", "js-sys", @@ -9005,10 +9545,10 @@ dependencies = [ "serde_json", "serde_urlencoded", "sync_wrapper 0.1.2", - "system-configuration", + "system-configuration 0.5.1", "tokio", "tokio-native-tls", - "tokio-rustls", + "tokio-rustls 0.24.1", "tokio-util", "tower-service", "url", @@ -9021,19 +9561,19 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.8" +version = "0.12.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b" +checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da" dependencies = [ "base64 0.22.1", "bytes", "encoding_rs", "futures-core", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", - "hyper 1.4.1", + "hyper 1.5.2", "hyper-tls 0.6.0", "hyper-util", "ipnet", @@ -9049,10 +9589,11 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "sync_wrapper 1.0.1", + "sync_wrapper 1.0.2", "tokio", "tokio-native-tls", "tokio-util", + "tower 0.5.2", "tower-service", "url", "wasm-bindgen", @@ -9070,10 +9611,10 @@ checksum = "562ceb5a604d3f7c885a792d42c199fd8af239d0a51b2fa6a78aafa092452b04" dependencies = [ "anyhow", "async-trait", - "http 1.1.0", - "reqwest 0.12.8", + "http 1.2.0", + "reqwest 0.12.12", "serde", - "thiserror", + "thiserror 1.0.69", "tower-service", ] @@ -9129,7 +9670,7 @@ checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", "cfg-if", - "getrandom", + "getrandom 0.2.15", "libc", "spin 0.9.8", "untrusted 0.9.0", @@ -9208,35 +9749,51 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "rstest_reuse" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3a8fb4672e840a587a66fc577a5491375df51ddb88f2a2c2a792598c326fe14" +dependencies = [ + "quote", + "rand 0.8.5", + "syn 2.0.95", +] + [[package]] name = "rtnetlink" -version = "0.10.1" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322c53fd76a18698f1c27381d58091de3a043d356aa5bd0d510608b565f469a0" +checksum = "7a552eb82d19f38c3beed3f786bd23aa434ceb9ac43ab44419ca6d67a7e186c0" dependencies = [ "async-global-executor", "futures", "log", + "netlink-packet-core", "netlink-packet-route", + "netlink-packet-utils", "netlink-proto", - "nix 0.24.3", - "thiserror", + "netlink-sys", + "nix 0.26.4", + "thiserror 1.0.69", "tokio", ] [[package]] name = "ruint" -version = "1.12.3" +version = "1.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c3cc4c2511671f327125da14133d0c5c5d137f006a1017a16f557bc85b16286" +checksum = "f5ef8fb1dd8de3870cb8400d51b4c2023854bbafd5431a3ac7e7317243e22d2f" dependencies = [ "alloy-rlp", "ark-ff 0.3.0", "ark-ff 0.4.2", "bytes", - "fastrlp", + "fastrlp 0.3.1", + "fastrlp 0.4.0", "num-bigint 0.4.6", - "num-traits 0.2.19", + "num-integer", + "num-traits", "parity-scale-codec", "primitive-types", "proptest", @@ -9260,7 +9817,7 @@ version = "0.17.0-pre.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719825638c59fd26a55412a24561c7c5bcf54364c88b9a7a04ba08a6eafaba8d" dependencies = [ - "indexmap 2.6.0", + "indexmap 2.7.0", "lock_api", "oorandom", "parking_lot", @@ -9280,7 +9837,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -9290,7 +9847,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b082d80e3e3cc52b2ed634388d436fe1f4de6af5786cc2de9ba9737527bdf555" dependencies = [ "arrayvec", - "num-traits 0.2.19", + "num-traits", ] [[package]] @@ -9307,9 +9864,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc-hash" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" +checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" [[package]] name = "rustc-hex" @@ -9332,7 +9889,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ - "semver 1.0.23", + "semver 1.0.24", ] [[package]] @@ -9360,14 +9917,14 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.37" +version = "0.38.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" +checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6" dependencies = [ "bitflags 2.6.0", "errno", "libc", - "linux-raw-sys 0.4.14", + "linux-raw-sys 0.4.15", "windows-sys 0.52.0", ] @@ -9385,10 +9942,11 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.14" +version = "0.23.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "415d9944693cb90382053259f89fbb077ea730ad7273047ec63b19bc9b160ba8" +checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b" dependencies = [ + "aws-lc-rs", "log", "once_cell", "ring 0.17.8", @@ -9407,11 +9965,23 @@ dependencies = [ "openssl-probe", "rustls-pemfile 1.0.4", "schannel", - "security-framework", + "security-framework 2.11.1", ] [[package]] -name = "rustls-pemfile" +name = "rustls-native-certs" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework 3.2.0", +] + +[[package]] +name = "rustls-pemfile" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" @@ -9430,9 +10000,12 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.9.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e696e35370c65c9c541198af4543ccd580cf17fc25d8e05c5a242b202488c55" +checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" +dependencies = [ + "web-time", +] [[package]] name = "rustls-webpki" @@ -9450,6 +10023,7 @@ version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ + "aws-lc-rs", "ring 0.17.8", "rustls-pki-types", "untrusted 0.9.0", @@ -9457,9 +10031,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" [[package]] name = "rusty-fork" @@ -9510,33 +10084,33 @@ dependencies = [ [[package]] name = "scale-info" -version = "2.11.3" +version = "2.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024" +checksum = "346a3b32eba2640d17a9cb5927056b08f3de90f65b72fe09402c2ad07d684d0b" dependencies = [ "cfg-if", - "derive_more 0.99.18", + "derive_more 1.0.0", "parity-scale-codec", "scale-info-derive", ] [[package]] name = "scale-info-derive" -version = "2.11.3" +version = "2.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62" +checksum = "c6630024bf739e2179b91fb424b28898baf819414262c5d376677dbff1fe7ebf" dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.95", ] [[package]] name = "schannel" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" dependencies = [ "windows-sys 0.59.0", ] @@ -9563,7 +10137,18 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.79", + "syn 2.0.95", +] + +[[package]] +name = "schnellru" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "356285bbf17bea63d9e52e96bd18f039672ac92b55b8cb997d6162a2a37d1649" +dependencies = [ + "ahash", + "cfg-if", + "hashbrown 0.13.2", ] [[package]] @@ -9615,7 +10200,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ "bitflags 2.6.0", - "core-foundation", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" +dependencies = [ + "bitflags 2.6.0", + "core-foundation 0.10.0", "core-foundation-sys", "libc", "security-framework-sys", @@ -9623,9 +10221,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.12.0" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6" +checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" dependencies = [ "core-foundation-sys", "libc", @@ -9642,18 +10240,18 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" dependencies = [ "serde", ] [[package]] name = "semver-parser" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +checksum = "9900206b54a3527fdc7b8a938bffd94a568bac4f4aa8113b209df75a09c0dec2" dependencies = [ "pest", ] @@ -9672,22 +10270,22 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.210" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.210" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -9698,14 +10296,14 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] name = "serde_json" -version = "1.0.128" +version = "1.0.135" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9" dependencies = [ "itoa", "memchr", @@ -9742,7 +10340,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -9768,14 +10366,15 @@ dependencies = [ [[package]] name = "serde_with" -version = "2.3.3" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07ff71d2c147a7b57362cead5e22f772cd52f6ab31cfcd9edcd7f6aeb2a0afbe" +checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" dependencies = [ - "base64 0.13.1", + "base64 0.22.1", "chrono", "hex", "serde", + "serde_derive", "serde_json", "serde_with_macros", "time", @@ -9783,14 +10382,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "2.3.3" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f" +checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" dependencies = [ "darling 0.20.10", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -9857,6 +10456,15 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shared_execution_objects" +version = "0.0.0" +dependencies = [ + "blockifier", + "serde", + "starknet_api", +] + [[package]] name = "shlex" version = "1.3.0" @@ -9895,8 +10503,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" dependencies = [ "num-bigint 0.4.6", - "num-traits 0.2.19", - "thiserror", + "num-traits", + "thiserror 1.0.69", "time", ] @@ -9906,7 +10514,7 @@ version = "4.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e7e46c8c90251d47d08b28b8a419ffb4aede0f87c2eea95e17d1d5bacbf3ef1" dependencies = [ - "colored", + "colored 2.2.0", "log", "time", "windows-sys 0.48.0", @@ -9929,11 +10537,17 @@ version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" +[[package]] +name = "siphasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" + [[package]] name = "sketches-ddsketch" -version = "0.2.2" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85636c14b73d81f541e525f585c0a2109e6744e1565b5c1668e31c70c10ed65c" +checksum = "c1e9a774a6c28142ac54bb25d25562e6bcf957493a184f15ad4eebccb23e410a" [[package]] name = "slab" @@ -9959,22 +10573,25 @@ name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +dependencies = [ + "serde", +] [[package]] name = "smol" -version = "1.3.0" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13f2b548cd8447f8de0fdf1c592929f70f4fc7039a05e47404b0d096ec6987a1" +checksum = "a33bd3e260892199c3ccfc487c88b2da2265080acb316cd920da72fdfd7c599f" dependencies = [ - "async-channel 1.9.0", + "async-channel 2.3.1", "async-executor", "async-fs", - "async-io 1.13.0", - "async-lock 2.8.0", + "async-io 2.4.0", + "async-lock 3.4.0", "async-net", "async-process", "blocking", - "futures-lite 1.13.0", + "futures-lite 2.5.0", ] [[package]] @@ -10015,9 +10632,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" dependencies = [ "libc", "windows-sys 0.52.0", @@ -10049,7 +10666,7 @@ dependencies = [ "lalrpop", "lalrpop-util", "phf", - "thiserror", + "thiserror 1.0.69", "unicode-xid", ] @@ -10080,13 +10697,14 @@ dependencies = [ [[package]] name = "sprs" -version = "0.7.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec63571489873d4506683915840eeb1bb16b3198ee4894cc6f2fe3013d505e56" +checksum = "704ef26d974e8a452313ed629828cd9d4e4fa34667ca1ad9d6b1fffa43c6e166" dependencies = [ "ndarray", - "num-complex 0.2.4", - "num-traits 0.1.43", + "num-complex 0.4.6", + "num-traits", + "smallvec", ] [[package]] @@ -10097,20 +10715,36 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "starknet-core" -version = "0.6.1" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14139b1c39bdc2f1e663c12090ff5108fe50ebe62c09e15e32988dfaf445a7e4" +checksum = "37abf0af45a3b866dd108880ace9949ae7830f6830adb8963024302ae9e82c24" dependencies = [ "base64 0.21.7", + "crypto-bigint", "flate2", + "foldhash", "hex", + "indexmap 2.7.0", + "num-traits", "serde", "serde_json", "serde_json_pythonic", "serde_with", "sha3", - "starknet-crypto 0.6.2", - "starknet-ff", + "starknet-core-derive", + "starknet-crypto 0.7.4", + "starknet-types-core", +] + +[[package]] +name = "starknet-core-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b08520b7d80eda7bf1a223e8db4f9bb5779a12846f15ebf8f8d76667eca7f5ad" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.95", ] [[package]] @@ -10124,7 +10758,7 @@ dependencies = [ "hmac", "num-bigint 0.4.6", "num-integer", - "num-traits 0.2.19", + "num-traits", "rfc6979", "sha2", "starknet-crypto-codegen", @@ -10135,16 +10769,16 @@ dependencies = [ [[package]] name = "starknet-crypto" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a5064173a8e8d2675e67744fd07f310de44573924b6b7af225a6bdd8102913" +checksum = "039a3bad70806b494c9e6b21c5238a6c8a373d66a26071859deb0ccca6f93634" dependencies = [ "crypto-bigint", "hex", "hmac", "num-bigint 0.4.6", "num-integer", - "num-traits 0.2.19", + "num-traits", "rfc6979", "sha2", "starknet-curve 0.5.1", @@ -10160,7 +10794,7 @@ checksum = "bbc159a1934c7be9761c237333a57febe060ace2bc9e3b337a59a37af206d19f" dependencies = [ "starknet-curve 0.4.2", "starknet-ff", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -10188,11 +10822,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7abf1b44ec5b18d87c1ae5f54590ca9d0699ef4dd5b2ffa66fc97f24613ec585" dependencies = [ "ark-ff 0.4.2", - "bigdecimal", "crypto-bigint", - "getrandom", + "getrandom 0.2.15", "hex", - "serde", ] [[package]] @@ -10206,7 +10838,7 @@ dependencies = [ "lazy_static", "num-bigint 0.4.6", "num-integer", - "num-traits 0.2.19", + "num-traits", "serde", ] @@ -10216,50 +10848,64 @@ version = "0.0.0" dependencies = [ "assert_matches", "bitvec", + "cached", "cairo-lang-runner", "cairo-lang-starknet-classes", "derive_more 0.99.18", "hex", - "indexmap 2.6.0", - "infra_utils", + "indexmap 2.7.0", "itertools 0.12.1", "num-bigint 0.4.6", + "num-traits", "pretty_assertions", "primitive-types", + "rand 0.8.5", "rstest", + "semver 1.0.24", "serde", "serde_json", "sha3", - "starknet-crypto 0.7.2", + "starknet-crypto 0.7.4", "starknet-types-core", + "starknet_infra_utils", "strum 0.25.0", "strum_macros 0.25.3", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "starknet_batcher" version = "0.0.0" dependencies = [ + "apollo_reverts", "assert_matches", "async-trait", "blockifier", + "cairo-lang-starknet-classes", "chrono", "futures", - "indexmap 2.6.0", + "indexmap 2.7.0", "mempool_test_utils", + "metrics 0.24.1", + "metrics-exporter-prometheus", "mockall", "papyrus_config", "papyrus_state_reader", "papyrus_storage", + "pretty_assertions", "rstest", "serde", "starknet-types-core", "starknet_api", "starknet_batcher_types", + "starknet_class_manager_types", + "starknet_infra_utils", + "starknet_l1_provider_types", "starknet_mempool_types", "starknet_sequencer_infra", - "thiserror", + "starknet_sequencer_metrics", + "starknet_state_sync_types", + "thiserror 1.0.69", "tokio", "tracing", "validator", @@ -10270,15 +10916,57 @@ name = "starknet_batcher_types" version = "0.0.0" dependencies = [ "async-trait", + "blockifier", "chrono", "derive_more 0.99.18", "mockall", "papyrus_proc_macros", "serde", "starknet_api", - "starknet_batcher_types", "starknet_sequencer_infra", - "thiserror", + "starknet_state_sync_types", + "strum_macros 0.25.3", + "thiserror 1.0.69", +] + +[[package]] +name = "starknet_class_manager" +version = "0.0.0" +dependencies = [ + "async-trait", + "hex", + "mockall", + "papyrus_config", + "papyrus_storage", + "serde", + "starknet_api", + "starknet_class_manager_types", + "starknet_sequencer_infra", + "starknet_sequencer_metrics", + "starknet_sierra_multicompile_types", + "strum 0.25.0", + "strum_macros 0.25.3", + "tempfile", + "thiserror 1.0.69", + "tokio", + "tracing", + "validator", +] + +[[package]] +name = "starknet_class_manager_types" +version = "0.0.0" +dependencies = [ + "async-trait", + "mockall", + "papyrus_proc_macros", + "serde", + "serde_json", + "starknet_api", + "starknet_sequencer_infra", + "starknet_sierra_multicompile_types", + "strum_macros 0.25.3", + "thiserror 1.0.69", ] [[package]] @@ -10290,7 +10978,7 @@ dependencies = [ "cairo-lang-starknet-classes", "enum-iterator", "http 0.2.12", - "indexmap 2.6.0", + "indexmap 2.7.0", "mockall", "mockito 0.31.1", "os_info", @@ -10309,7 +10997,7 @@ dependencies = [ "starknet_api", "strum 0.25.0", "strum_macros 0.25.3", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-retry", "tracing", @@ -10325,30 +11013,154 @@ dependencies = [ "rstest", "serde_json", "starknet-types-core", + "starknet_api", "starknet_patricia", - "thiserror", + "starknet_patricia_storage", + "thiserror 1.0.69", "tokio", "tracing", ] [[package]] -name = "starknet_consensus_manager" +name = "starknet_committer_and_os_cli" +version = "0.0.0" +dependencies = [ + "assert_matches", + "cairo-lang-starknet-classes", + "cairo-vm", + "clap", + "criterion", + "derive_more 0.99.18", + "ethnum", + "futures", + "indexmap 2.7.0", + "pretty_assertions", + "rand 0.8.5", + "rand_distr", + "serde", + "serde_json", + "serde_repr", + "starknet-types-core", + "starknet_api", + "starknet_committer", + "starknet_os", + "starknet_patricia", + "starknet_patricia_storage", + "strum 0.25.0", + "strum_macros 0.25.3", + "tempfile", + "thiserror 1.0.69", + "tokio", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "starknet_consensus" version = "0.0.0" dependencies = [ "async-trait", + "clap", + "enum-as-inner", + "fs2", "futures", - "libp2p", + "lazy_static", + "lru", + "metrics 0.24.1", + "mockall", + "nix 0.20.2", + "papyrus_common", "papyrus_config", - "papyrus_consensus", - "papyrus_consensus_orchestrator", "papyrus_network", "papyrus_network_types", "papyrus_protobuf", + "papyrus_storage", + "papyrus_test_utils", + "prost", "serde", + "starknet-types-core", + "starknet_api", + "starknet_sequencer_metrics", + "strum 0.25.0", + "strum_macros 0.25.3", + "test-case", + "thiserror 1.0.69", + "tokio", + "tracing", + "validator", +] + +[[package]] +name = "starknet_consensus_manager" +version = "0.0.0" +dependencies = [ + "apollo_reverts", + "async-trait", + "futures", + "mockall", + "papyrus_config", + "papyrus_network", + "papyrus_protobuf", + "rstest", + "serde", + "starknet_api", "starknet_batcher_types", + "starknet_class_manager_types", + "starknet_consensus", + "starknet_consensus_orchestrator", + "starknet_infra_utils", + "starknet_l1_gas_price", "starknet_sequencer_infra", + "starknet_sequencer_metrics", + "starknet_state_sync_types", + "tokio", + "tracing", + "validator", +] + +[[package]] +name = "starknet_consensus_orchestrator" +version = "0.0.0" +dependencies = [ + "async-trait", + "blockifier", + "cairo-lang-casm", + "cairo-lang-starknet-classes", + "cairo-lang-utils", + "cairo-vm", + "chrono", + "futures", + "indexmap 2.7.0", + "lazy_static", + "mockall", + "mockito 1.6.1", + "num-bigint 0.4.6", + "papyrus_config", + "papyrus_network", + "papyrus_protobuf", + "papyrus_storage", + "papyrus_test_utils", + "paste", + "reqwest 0.11.27", + "rstest", + "serde", + "serde_json", + "shared_execution_objects", + "starknet-types-core", + "starknet_api", + "starknet_batcher", + "starknet_batcher_types", + "starknet_class_manager_types", + "starknet_consensus", + "starknet_infra_utils", + "starknet_l1_gas_price_types", + "starknet_sequencer_metrics", + "starknet_state_sync_types", + "thiserror 1.0.69", "tokio", + "tokio-util", "tracing", + "url", "validator", ] @@ -10360,14 +11172,20 @@ dependencies = [ "async-trait", "axum", "blockifier", + "blockifier_test_utils", "cairo-lang-sierra-to-casm", "cairo-lang-starknet-classes", + "criterion", + "futures", "mempool_test_utils", + "metrics 0.24.1", + "metrics-exporter-prometheus", "mockall", - "mockito 1.5.0", + "mockito 1.6.1", "num-bigint 0.4.6", "papyrus_config", "papyrus_network_types", + "papyrus_proc_macros", "papyrus_rpc", "papyrus_test_utils", "pretty_assertions", @@ -10377,12 +11195,17 @@ dependencies = [ "serde_json", "starknet-types-core", "starknet_api", + "starknet_class_manager_types", "starknet_gateway_types", "starknet_mempool", "starknet_mempool_types", "starknet_sequencer_infra", - "starknet_sierra_compile", - "thiserror", + "starknet_sequencer_metrics", + "starknet_sierra_multicompile", + "starknet_state_sync_types", + "strum 0.25.0", + "strum_macros 0.25.3", + "thiserror 1.0.69", "tokio", "tracing", "tracing-test", @@ -10394,7 +11217,6 @@ name = "starknet_gateway_types" version = "0.0.0" dependencies = [ "async-trait", - "axum", "enum-assoc", "mockall", "papyrus_network_types", @@ -10403,9 +11225,9 @@ dependencies = [ "serde", "serde_json", "starknet_api", - "starknet_gateway_types", "starknet_sequencer_infra", - "thiserror", + "strum_macros 0.25.3", + "thiserror 1.0.69", "tracing", ] @@ -10414,72 +11236,181 @@ name = "starknet_http_server" version = "0.0.0" dependencies = [ "axum", - "hyper 0.14.30", + "blockifier", + "blockifier_test_utils", + "futures", + "hyper 0.14.32", + "jsonrpsee", + "mempool_test_utils", + "metrics 0.24.1", + "metrics-exporter-prometheus", "papyrus_config", + "reqwest 0.11.27", "serde", "serde_json", + "starknet-types-core", "starknet_api", "starknet_gateway_types", + "starknet_infra_utils", "starknet_sequencer_infra", - "thiserror", + "starknet_sequencer_metrics", + "thiserror 1.0.69", "tokio", "tracing", + "tracing-test", "validator", ] +[[package]] +name = "starknet_infra_utils" +version = "0.0.0" +dependencies = [ + "assert-json-diff", + "cached", + "colored 3.0.0", + "nix 0.20.2", + "pretty_assertions", + "rstest", + "serde", + "serde_json", + "tokio", + "toml", + "tracing", + "tracing-subscriber", +] + [[package]] name = "starknet_integration_tests" version = "0.0.0" dependencies = [ + "alloy", "anyhow", "assert_matches", "axum", "blockifier", + "blockifier_test_utils", "cairo-lang-starknet-classes", + "clap", "futures", - "indexmap 2.6.0", - "infra_utils", + "indexmap 2.7.0", + "itertools 0.12.1", "mempool_test_utils", - "papyrus_common", - "papyrus_consensus", - "papyrus_execution", + "papyrus_base_layer", "papyrus_network", "papyrus_protobuf", - "papyrus_rpc", "papyrus_storage", + "papyrus_sync", "pretty_assertions", - "reqwest 0.11.27", "rstest", + "serde", "serde_json", "starknet-types-core", "starknet_api", "starknet_batcher", - "starknet_client", + "starknet_class_manager", + "starknet_consensus", "starknet_consensus_manager", + "starknet_consensus_orchestrator", "starknet_gateway", "starknet_gateway_types", "starknet_http_server", + "starknet_infra_utils", + "starknet_l1_gas_price", + "starknet_l1_provider", + "starknet_mempool", "starknet_mempool_p2p", "starknet_monitoring_endpoint", + "starknet_sequencer_deployments", "starknet_sequencer_infra", "starknet_sequencer_node", - "starknet_task_executor", + "starknet_state_sync", "strum 0.25.0", "tempfile", "tokio", "tracing", + "url", +] + +[[package]] +name = "starknet_l1_gas_price" +version = "0.0.0" +dependencies = [ + "async-trait", + "mockall", + "mockito 1.6.1", + "papyrus_base_layer", + "papyrus_config", + "reqwest 0.11.27", + "serde", + "serde_json", + "starknet_api", + "starknet_l1_gas_price_types", + "starknet_sequencer_infra", + "thiserror 1.0.69", + "tokio", + "tracing", + "url", + "validator", +] + +[[package]] +name = "starknet_l1_gas_price_types" +version = "0.0.0" +dependencies = [ + "async-trait", + "mockall", + "papyrus_base_layer", + "papyrus_proc_macros", + "reqwest 0.11.27", + "serde", + "serde_json", + "starknet_api", + "starknet_sequencer_infra", + "strum_macros 0.25.3", + "thiserror 1.0.69", + "tracing", ] [[package]] name = "starknet_l1_provider" version = "0.0.0" dependencies = [ + "alloy", "assert_matches", - "indexmap 2.6.0", + "async-trait", + "hex", + "indexmap 2.7.0", + "itertools 0.12.1", + "mempool_test_utils", "papyrus_base_layer", + "papyrus_config", "pretty_assertions", + "serde", + "starknet-types-core", "starknet_api", - "thiserror", + "starknet_l1_provider_types", + "starknet_sequencer_infra", + "starknet_state_sync_types", + "thiserror 1.0.69", + "tokio", + "tracing", + "validator", +] + +[[package]] +name = "starknet_l1_provider_types" +version = "0.0.0" +dependencies = [ + "async-trait", + "mockall", + "papyrus_base_layer", + "papyrus_proc_macros", + "serde", + "starknet_api", + "starknet_sequencer_infra", + "strum_macros 0.25.3", + "thiserror 1.0.69", + "tracing", ] [[package]] @@ -10491,16 +11422,27 @@ dependencies = [ "derive_more 0.99.18", "itertools 0.12.1", "mempool_test_utils", + "metrics 0.24.1", + "metrics-exporter-prometheus", + "mockall", + "papyrus_config", + "papyrus_network", "papyrus_network_types", + "papyrus_test_utils", "pretty_assertions", "rstest", + "serde", "starknet-types-core", "starknet_api", - "starknet_mempool", "starknet_mempool_p2p_types", "starknet_mempool_types", "starknet_sequencer_infra", + "starknet_sequencer_metrics", + "strum 0.25.0", + "strum_macros 0.25.3", + "tokio", "tracing", + "validator", ] [[package]] @@ -10509,6 +11451,8 @@ version = "0.0.0" dependencies = [ "async-trait", "futures", + "libp2p", + "mockall", "papyrus_config", "papyrus_network", "papyrus_network_types", @@ -10517,9 +11461,11 @@ dependencies = [ "rand_chacha 0.3.1", "serde", "starknet_api", + "starknet_class_manager_types", "starknet_gateway_types", "starknet_mempool_p2p_types", "starknet_sequencer_infra", + "starknet_sequencer_metrics", "tokio", "tracing", "validator", @@ -10530,12 +11476,14 @@ name = "starknet_mempool_p2p_types" version = "0.0.0" dependencies = [ "async-trait", + "mockall", "papyrus_network_types", "papyrus_proc_macros", "serde", "starknet_api", "starknet_sequencer_infra", - "thiserror", + "strum_macros 0.25.3", + "thiserror 1.0.69", ] [[package]] @@ -10548,9 +11496,9 @@ dependencies = [ "papyrus_proc_macros", "serde", "starknet_api", - "starknet_mempool_types", "starknet_sequencer_infra", - "thiserror", + "strum_macros 0.25.3", + "thiserror 1.0.69", ] [[package]] @@ -10558,17 +11506,57 @@ name = "starknet_monitoring_endpoint" version = "0.0.0" dependencies = [ "axum", - "hyper 0.14.30", + "hyper 0.14.32", + "metrics 0.24.1", + "metrics-exporter-prometheus", + "num-traits", "papyrus_config", "pretty_assertions", "serde", + "starknet_infra_utils", "starknet_sequencer_infra", + "starknet_sequencer_metrics", + "thiserror 1.0.69", "tokio", "tower 0.4.13", "tracing", "validator", ] +[[package]] +name = "starknet_os" +version = "0.0.0" +dependencies = [ + "ark-bls12-381", + "ark-ff 0.4.2", + "ark-poly 0.4.2", + "assert_matches", + "blockifier", + "c-kzg", + "cairo-lang-starknet-classes", + "cairo-vm", + "indexmap 2.7.0", + "indoc 2.0.5", + "log", + "num-bigint 0.4.6", + "num-integer", + "num-traits", + "papyrus_common", + "rand 0.8.5", + "rstest", + "serde", + "serde_json", + "sha3", + "shared_execution_objects", + "starknet-types-core", + "starknet_api", + "starknet_infra_utils", + "starknet_patricia", + "strum 0.25.0", + "strum_macros 0.25.3", + "thiserror 1.0.69", +] + [[package]] name = "starknet_patricia" version = "0.0.0" @@ -10576,18 +11564,67 @@ dependencies = [ "async-recursion", "derive_more 0.99.18", "ethnum", - "hex", "pretty_assertions", "rand 0.8.5", "rstest", "serde", "serde_json", "starknet-types-core", + "starknet_patricia_storage", + "strum 0.25.0", + "strum_macros 0.25.3", + "thiserror 1.0.69", + "tokio", + "tracing", +] + +[[package]] +name = "starknet_patricia_storage" +version = "0.0.0" +dependencies = [ + "hex", + "serde", + "serde_json", + "starknet-types-core", + "starknet_api", + "thiserror 1.0.69", +] + +[[package]] +name = "starknet_sequencer_dashboard" +version = "0.0.0" +dependencies = [ + "const_format", + "indexmap 2.7.0", + "papyrus_sync", + "serde", + "serde_json", + "starknet_batcher", + "starknet_consensus", + "starknet_consensus_manager", + "starknet_gateway", + "starknet_http_server", + "starknet_infra_utils", + "starknet_mempool", + "starknet_mempool_p2p", + "starknet_sequencer_infra", + "starknet_sequencer_metrics", + "starknet_state_sync", +] + +[[package]] +name = "starknet_sequencer_deployments" +version = "0.0.0" +dependencies = [ + "indexmap 2.7.0", + "serde", + "serde_json", + "starknet_api", + "starknet_infra_utils", + "starknet_monitoring_endpoint", + "starknet_sequencer_node", "strum 0.25.0", "strum_macros 0.25.3", - "thiserror", - "tokio", - "tracing", ] [[package]] @@ -10596,98 +11633,155 @@ version = "0.0.0" dependencies = [ "assert_matches", "async-trait", - "bincode 1.3.3", - "hyper 0.14.30", + "hyper 0.14.32", + "metrics 0.24.1", + "metrics-exporter-prometheus", + "once_cell", "papyrus_config", "pretty_assertions", "rstest", "serde", + "serde_json", "starknet-types-core", - "thiserror", + "starknet_api", + "starknet_infra_utils", + "starknet_sequencer_metrics", + "thiserror 1.0.69", "tokio", + "tower 0.4.13", "tracing", "tracing-subscriber", "validator", ] +[[package]] +name = "starknet_sequencer_metrics" +version = "0.0.0" +dependencies = [ + "indexmap 2.7.0", + "metrics 0.24.1", + "metrics-exporter-prometheus", + "num-traits", + "paste", + "regex", + "rstest", + "strum 0.25.0", + "strum_macros 0.25.3", +] + [[package]] name = "starknet_sequencer_node" version = "0.0.0" dependencies = [ "anyhow", - "assert-json-diff", + "apollo_reverts", "assert_matches", "clap", - "colored", + "colored 3.0.0", "const_format", "futures", - "infra_utils", "mempool_test_utils", + "papyrus_base_layer", "papyrus_config", - "papyrus_proc_macros", "pretty_assertions", "rstest", "serde", "serde_json", - "starknet_api", "starknet_batcher", "starknet_batcher_types", + "starknet_class_manager", + "starknet_class_manager_types", "starknet_consensus_manager", "starknet_gateway", "starknet_gateway_types", "starknet_http_server", + "starknet_infra_utils", + "starknet_l1_gas_price", + "starknet_l1_gas_price_types", + "starknet_l1_provider", + "starknet_l1_provider_types", "starknet_mempool", "starknet_mempool_p2p", "starknet_mempool_p2p_types", "starknet_mempool_types", "starknet_monitoring_endpoint", "starknet_sequencer_infra", - "starknet_sequencer_node", - "starknet_sierra_compile", + "starknet_sierra_multicompile", + "starknet_sierra_multicompile_types", + "starknet_state_sync", "starknet_state_sync_types", - "thiserror", + "tikv-jemallocator", "tokio", "tracing", "validator", ] [[package]] -name = "starknet_sierra_compile" +name = "starknet_sierra_multicompile" version = "0.0.0" dependencies = [ "assert_matches", + "async-trait", "cairo-lang-sierra", "cairo-lang-starknet-classes", "cairo-lang-utils", "cairo-native", - "infra_utils", "mempool_test_utils", "papyrus_config", + "rlimit", "rstest", "serde", "serde_json", "starknet-types-core", "starknet_api", + "starknet_infra_utils", + "starknet_sequencer_infra", + "starknet_sierra_multicompile_types", "tempfile", - "thiserror", + "thiserror 1.0.69", + "toml_test_utils", + "tracing", "validator", ] +[[package]] +name = "starknet_sierra_multicompile_types" +version = "0.0.0" +dependencies = [ + "async-trait", + "mockall", + "papyrus_proc_macros", + "serde", + "serde_json", + "starknet_api", + "starknet_sequencer_infra", + "thiserror 1.0.69", +] + [[package]] name = "starknet_state_sync" version = "0.0.0" dependencies = [ + "apollo_reverts", "async-trait", "futures", - "papyrus_base_layer", + "indexmap 2.7.0", + "libp2p", "papyrus_common", "papyrus_config", + "papyrus_network", + "papyrus_p2p_sync", "papyrus_storage", "papyrus_sync", + "papyrus_test_utils", + "rand_chacha 0.3.1", "serde", + "starknet-types-core", "starknet_api", + "starknet_class_manager_types", "starknet_client", "starknet_sequencer_infra", + "starknet_sequencer_metrics", "starknet_state_sync_types", "tokio", "validator", @@ -10698,12 +11792,16 @@ name = "starknet_state_sync_types" version = "0.0.0" dependencies = [ "async-trait", + "futures", + "mockall", "papyrus_proc_macros", "papyrus_storage", "serde", + "starknet-types-core", "starknet_api", "starknet_sequencer_infra", - "thiserror", + "strum_macros 0.25.3", + "thiserror 1.0.69", ] [[package]] @@ -10768,6 +11866,9 @@ name = "strum" version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +dependencies = [ + "strum_macros 0.25.3", +] [[package]] name = "strum" @@ -10788,7 +11889,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -10801,7 +11902,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -10821,11 +11922,11 @@ dependencies = [ "hex", "once_cell", "reqwest 0.11.27", - "semver 1.0.23", + "semver 1.0.24", "serde", "serde_json", "sha2", - "thiserror", + "thiserror 1.0.69", "url", "zip", ] @@ -10843,9 +11944,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.79" +version = "2.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +checksum = "46f71c0377baf4ef1cc3e3402ded576dccc315800fbc62dfc7fe04b009773b4a" dependencies = [ "proc-macro2", "quote", @@ -10854,14 +11955,14 @@ dependencies = [ [[package]] name = "syn-solidity" -version = "0.8.7" +version = "0.8.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20e7b52ad118b2153644eea95c6fc740b6c1555b2344fdab763fc9de4075f665" +checksum = "31e89d8bf2768d277f40573c83a02a099e96d96dd3104e13ea676194e61ac4b0" dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -10872,9 +11973,9 @@ checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" [[package]] name = "sync_wrapper" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" dependencies = [ "futures-core", ] @@ -10887,7 +11988,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -10897,8 +11998,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" dependencies = [ "bitflags 1.2.1", - "core-foundation", - "system-configuration-sys", + "core-foundation 0.9.4", + "system-configuration-sys 0.5.0", +] + +[[package]] +name = "system-configuration" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +dependencies = [ + "bitflags 2.6.0", + "core-foundation 0.9.4", + "system-configuration-sys 0.6.0", ] [[package]] @@ -10911,6 +12023,16 @@ dependencies = [ "libc", ] +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "tap" version = "1.0.1" @@ -10919,9 +12041,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tar" -version = "0.4.42" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ff6c40d3aedb5e06b57c6f669ad17ab063dd1e63d977c6a88e7f4dfa4f04020" +checksum = "c65998313f8e17d0d553d28f91a0df93e4dbbbf770279c7bc21ca0f09ea1a1f6" dependencies = [ "filetime", "libc", @@ -10935,28 +12057,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] -name = "tblgen-alt" -version = "0.4.0" +name = "tblgen" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ecbc9175dd38627cd01d546e7b41c9a115e5773f4c98f64e2185c81ec5f45ab" +checksum = "c155c9310c9e11e6f642b4c8a30ae572ea0cad013d5c9e28bb264b52fa8163bb" dependencies = [ - "bindgen 0.69.5", + "bindgen 0.71.1", "cc", "paste", - "thiserror", + "thiserror 2.0.12", ] [[package]] name = "tempfile" -version = "3.13.0" +version = "3.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" +checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" dependencies = [ "cfg-if", - "fastrand 2.1.1", + "fastrand 2.3.0", + "getrandom 0.2.15", "once_cell", - "rustix 0.38.37", - "windows-sys 0.59.0", + "rustix 0.38.43", + "windows-sys 0.52.0", ] [[package]] @@ -10981,9 +12104,9 @@ dependencies = [ [[package]] name = "termtree" -version = "0.4.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" +checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683" [[package]] name = "test-case" @@ -11003,7 +12126,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -11014,7 +12137,7 @@ checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", "test-case-core", ] @@ -11037,27 +12160,47 @@ checksum = "5999e24eaa32083191ba4e425deb75cdf25efefabe5aaccb7446dd0d4122a3f5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", ] [[package]] name = "thiserror" -version = "1.0.64" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl 2.0.12", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ - "thiserror-impl", + "proc-macro2", + "quote", + "syn 2.0.95", ] [[package]] name = "thiserror-impl" -version = "1.0.64" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -11121,9 +12264,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.36" +version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" dependencies = [ "deranged", "itoa", @@ -11144,9 +12287,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" dependencies = [ "num-conv", "time-core", @@ -11161,6 +12304,16 @@ dependencies = [ "crunchy", ] +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "tinytemplate" version = "1.2.1" @@ -11173,9 +12326,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8" dependencies = [ "tinyvec_macros", ] @@ -11188,9 +12341,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.40.0" +version = "1.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" +checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" dependencies = [ "backtrace", "bytes", @@ -11199,7 +12352,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.7", + "socket2 0.5.8", "tokio-macros", "windows-sys 0.52.0", ] @@ -11212,7 +12365,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -11246,11 +12399,21 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" +dependencies = [ + "rustls 0.23.20", + "tokio", +] + [[package]] name = "tokio-stream" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" dependencies = [ "futures-core", "pin-project-lite", @@ -11281,21 +12444,23 @@ dependencies = [ "log", "rustls 0.21.12", "tokio", - "tokio-rustls", + "tokio-rustls 0.24.1", "tungstenite", "webpki-roots 0.25.4", ] [[package]] name = "tokio-util" -version = "0.7.12" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" +checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" dependencies = [ "bytes", "futures-core", "futures-io", "futures-sink", + "futures-util", + "hashbrown 0.14.5", "pin-project-lite", "tokio", ] @@ -11327,7 +12492,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.6.0", + "indexmap 2.7.0", "toml_datetime", "winnow 0.5.40", ] @@ -11338,11 +12503,19 @@ version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ - "indexmap 2.6.0", + "indexmap 2.7.0", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.20", + "winnow 0.6.22", +] + +[[package]] +name = "toml_test_utils" +version = "0.0.0" +dependencies = [ + "serde", + "toml", ] [[package]] @@ -11368,14 +12541,15 @@ dependencies = [ [[package]] name = "tower" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" dependencies = [ "futures-core", "futures-util", "pin-project-lite", - "sync_wrapper 0.1.2", + "sync_wrapper 1.0.2", + "tokio", "tower-layer", "tower-service", ] @@ -11394,9 +12568,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "log", "pin-project-lite", @@ -11406,20 +12580,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", "valuable", @@ -11448,9 +12622,9 @@ dependencies = [ [[package]] name = "tracing-serde" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" +checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" dependencies = [ "serde", "tracing-core", @@ -11458,9 +12632,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" dependencies = [ "matchers", "nu-ansi-term", @@ -11495,7 +12669,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04659ddb06c87d233c566112c1c9c5b9e98256d9af50ec3bc9c8327f873a7568" dependencies = [ "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -11529,7 +12703,7 @@ dependencies = [ "rand 0.8.5", "rustls 0.21.12", "sha1", - "thiserror", + "thiserror 1.0.69", "url", "utf-8", ] @@ -11576,26 +12750,26 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c878a167baa8afd137494101a688ef8c67125089ff2249284bd2b5f9bfedb815" dependencies = [ - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "unicase" -version = "2.8.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" [[package]] name = "unicode-bidi" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unicode-normalization" @@ -11676,27 +12850,27 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "ureq" -version = "2.10.1" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b74fc6b57825be3373f7054754755f03ac3a8f5d70015ccad699ba2029956f4a" +checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d" dependencies = [ "base64 0.22.1", "log", "once_cell", - "rustls 0.23.14", + "rustls 0.23.20", "rustls-pki-types", "url", - "webpki-roots 0.26.6", + "webpki-roots 0.26.7", ] [[package]] name = "url" -version = "2.5.2" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", - "idna 0.5.0", + "idna 1.0.3", "percent-encoding", "serde", ] @@ -11713,6 +12887,12 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + [[package]] name = "utf8_iter" version = "1.0.4" @@ -11731,15 +12911,15 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" dependencies = [ - "getrandom", + "getrandom 0.2.15", "serde", ] [[package]] name = "uuid" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" [[package]] name = "validator" @@ -11788,9 +12968,9 @@ checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] name = "value-bag" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a84c137d37ab0142f0f2ddfe332651fdbf252e7b7dbb4e67b6c1f1b2e925101" +checksum = "3ef4c4aa54d5d05a279399bfa921ec387b7aba77caf7a682ae8d86785b8fdad2" [[package]] name = "vcpkg" @@ -11850,11 +13030,20 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasi" +version = "0.13.3+wasi-0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +dependencies = [ + "wit-bindgen-rt", +] + [[package]] name = "wasm-bindgen" -version = "0.2.95" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" dependencies = [ "cfg-if", "once_cell", @@ -11863,36 +13052,36 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.95" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.45" +version = "0.4.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" +checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2" dependencies = [ "cfg-if", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.95" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -11900,22 +13089,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.95" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.95" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" +checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" [[package]] name = "wasm-streams" @@ -11930,11 +13119,25 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wasmtimer" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0048ad49a55b9deb3953841fa1fc5858f0efbcb7a18868c899a360269fac1b23" +dependencies = [ + "futures", + "js-sys", + "parking_lot", + "pin-utils", + "slab", + "wasm-bindgen", +] + [[package]] name = "web-sys" -version = "0.3.72" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" +checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc" dependencies = [ "js-sys", "wasm-bindgen", @@ -11958,9 +13161,9 @@ checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "webpki-roots" -version = "0.26.6" +version = "0.26.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958" +checksum = "5d642ff16b7e79272ae451b7322067cdc17cadf68c23264be9d94a32319efe7e" dependencies = [ "rustls-pki-types", ] @@ -11983,7 +13186,7 @@ dependencies = [ "either", "home", "once_cell", - "rustix 0.38.37", + "rustix 0.38.43", ] [[package]] @@ -12014,7 +13217,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.48.0", ] [[package]] @@ -12025,12 +13228,12 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.51.1" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9" +checksum = "efc5cf48f83140dcaab716eeaea345f9e93d0018fb81162753a3f76c3397b538" dependencies = [ - "windows-core 0.51.1", - "windows-targets 0.48.5", + "windows-core 0.53.0", + "windows-targets 0.52.6", ] [[package]] @@ -12045,19 +13248,20 @@ dependencies = [ [[package]] name = "windows-core" -version = "0.51.1" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] name = "windows-core" -version = "0.52.0" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "9dcc5b895a6377f1ab9fa55acedab1fd5ac0db66ad1e6c7f47e28a22e446a5dd" dependencies = [ + "windows-result 0.1.2", "windows-targets 0.52.6", ] @@ -12326,9 +13530,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.20" +version = "0.6.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +checksum = "39281189af81c07ec09db316b302a3e67bf9bd7cbf6c820b50e35fee9c2fa980" dependencies = [ "memchr", ] @@ -12343,14 +13547,34 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "wit-bindgen-rt" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +dependencies = [ + "bitflags 2.6.0", +] + [[package]] name = "workspace_tests" version = "0.0.0" dependencies = [ - "serde", - "toml", + "toml_test_utils", ] +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + [[package]] name = "ws_stream_wasm" version = "0.7.4" @@ -12364,7 +13588,7 @@ dependencies = [ "pharos", "rustc_version 0.4.1", "send_wrapper 0.6.0", - "thiserror", + "thiserror 1.0.69", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", @@ -12404,26 +13628,26 @@ dependencies = [ "nom", "oid-registry", "rusticata-macros", - "thiserror", + "thiserror 1.0.69", "time", ] [[package]] name = "xattr" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" +checksum = "e105d177a3871454f754b33bb0ee637ecaaac997446375fd3e5d43a2ed00c909" dependencies = [ "libc", - "linux-raw-sys 0.4.14", - "rustix 0.38.37", + "linux-raw-sys 0.4.15", + "rustix 0.38.43", ] [[package]] name = "xml-rs" -version = "0.8.22" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af4e2e2f7cba5a093896c1e150fbfe177d1883e7448200efb81d40b9d339ef26" +checksum = "c5b940ebc25896e71dd073bad2dbaa2abfe97b0a391415e22ad1326d9c54e3c4" [[package]] name = "xmltree" @@ -12436,18 +13660,18 @@ dependencies = [ [[package]] name = "xshell" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db0ab86eae739efd1b054a8d3d16041914030ac4e01cd1dca0cf252fd8b6437" +checksum = "9e7290c623014758632efe00737145b6867b66292c42167f2ec381eb566a373d" dependencies = [ "xshell-macros", ] [[package]] name = "xshell-macros" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d422e8e38ec76e2f06ee439ccc765e9c6a9638b9e7c9f2e8255e4d41e8bd852" +checksum = "32ac00cd3f8ec9c1d33fb3e7958a82df6989c42d747bd326c822b1d625283547" [[package]] name = "yamux" @@ -12466,9 +13690,9 @@ dependencies = [ [[package]] name = "yamux" -version = "0.13.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31b5e376a8b012bee9c423acdbb835fc34d45001cfa3106236a624e4b738028" +checksum = "17610762a1207ee816c6fadc29220904753648aba0a9ed61c7b8336e80a559c4" dependencies = [ "futures", "log", @@ -12501,6 +13725,30 @@ dependencies = [ "time", ] +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.95", + "synstructure", +] + [[package]] name = "zerocopy" version = "0.7.35" @@ -12508,7 +13756,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ "byteorder", - "zerocopy-derive", + "zerocopy-derive 0.7.35", +] + +[[package]] +name = "zerocopy" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd97444d05a4328b90e75e503a34bad781f14e28a823ad3557f0750df1ebcbc6" +dependencies = [ + "zerocopy-derive 0.8.23", ] [[package]] @@ -12519,7 +13776,39 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6352c01d0edd5db859a63e2605f4ea3183ddbd15e2c4a9e7d32184df75e4f154" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.95", +] + +[[package]] +name = "zerofrom" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.95", + "synstructure", ] [[package]] @@ -12539,7 +13828,29 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.95", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index a0f6d5c0dac..0d6720ba4a8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,10 +4,10 @@ resolver = "2" members = [ + "crates/apollo_reverts", "crates/blockifier", "crates/blockifier_reexecution", - "crates/committer_cli", - "crates/infra_utils", + "crates/blockifier_test_utils", "crates/mempool_test_utils", "crates/native_blockifier", "crates/papyrus_base_layer", @@ -27,36 +27,49 @@ members = [ "crates/papyrus_storage", "crates/papyrus_sync", "crates/papyrus_test_utils", - "crates/sequencing/papyrus_consensus", - "crates/sequencing/papyrus_consensus_orchestrator", + "crates/shared_execution_objects", "crates/starknet_api", "crates/starknet_batcher", "crates/starknet_batcher_types", + "crates/starknet_class_manager", + "crates/starknet_class_manager_types", "crates/starknet_client", "crates/starknet_committer", + "crates/starknet_committer_and_os_cli", + "crates/starknet_consensus", "crates/starknet_consensus_manager", + "crates/starknet_consensus_orchestrator", "crates/starknet_gateway", "crates/starknet_gateway_types", "crates/starknet_http_server", + "crates/starknet_infra_utils", "crates/starknet_integration_tests", + "crates/starknet_l1_gas_price", + "crates/starknet_l1_gas_price_types", "crates/starknet_l1_provider", + "crates/starknet_l1_provider_types", "crates/starknet_mempool", "crates/starknet_mempool_p2p", "crates/starknet_mempool_p2p_types", "crates/starknet_mempool_types", "crates/starknet_monitoring_endpoint", + "crates/starknet_os", "crates/starknet_patricia", + "crates/starknet_patricia_storage", + "crates/starknet_sequencer_dashboard", + "crates/starknet_sequencer_deployments", "crates/starknet_sequencer_infra", + "crates/starknet_sequencer_metrics", "crates/starknet_sequencer_node", - "crates/starknet_sierra_compile", + "crates/starknet_sierra_multicompile", + "crates/starknet_sierra_multicompile_types", "crates/starknet_state_sync", "crates/starknet_state_sync_types", "crates/starknet_task_executor", + "toml_test_utils", "workspace_tests", ] -exclude = ["crates/bin/starknet-native-compile"] - [workspace.package] version = "0.0.0" edition = "2021" @@ -65,19 +78,13 @@ license = "Apache-2.0" license-file = "LICENSE" [workspace.dependencies] -# fixating the version of parity-scale-codec and parity-scale-codec-derive due to an error in udeps. -# TODO: Remove this once udeps is fixed. -alloy-contract = "0.3.5" -alloy-dyn-abi = "0.8.3" -alloy-json-rpc = "0.3.5" -alloy-primitives = "0.8.3" -alloy-provider = "0.3.5" -alloy-sol-types = "0.8.3" -alloy-transport = "0.3.5" -alloy-transport-http = "0.3.5" +alloy = "0.9" anyhow = "1.0.44" +apollo_reverts.path = "crates/apollo_reverts" +ark-bls12-381 = "0.4.0" ark-ec = "0.4.2" ark-ff = "0.4.0-alpha.7" +ark-poly = "0.4.0" ark-secp256k1 = "0.4.0" ark-secp256r1 = "0.4.0" assert-json-diff = "2.0.2" @@ -92,28 +99,31 @@ bincode = "1.3.3" bisection = "0.1.0" bitvec = "1.0.1" blockifier = { path = "crates/blockifier", version = "0.0.0" } +blockifier_reexecution.path = "crates/blockifier_reexecution" +blockifier_test_utils = { path = "crates/blockifier_test_utils", version = "0.0.0" } byteorder = "1.4.3" bytes = "1" +c-kzg = "1.0.3" cached = "0.44.0" cairo-felt = "0.9.1" -cairo-lang-casm = "2.9.0-dev.0" -cairo-lang-runner = "2.9.0-dev.0" -cairo-lang-sierra = "=2.9.0-dev.0" -cairo-lang-sierra-to-casm = "2.9.0-dev.0" -cairo-lang-starknet-classes = "2.9.0-dev.0" -cairo-lang-utils = "2.9.0-dev.0" -# Important: when updated, make sure to update the cairo-native submodule as well. -cairo-native = "0.2.4" -cairo-vm = "=1.0.1" +cairo-lang-casm = "2.10.0" +cairo-lang-runner = "2.10.0" +cairo-lang-sierra = "=2.10.0" +cairo-lang-sierra-to-casm = "2.10.0" +cairo-lang-starknet-classes = "2.10.0" +cairo-lang-utils = "2.10.0" +cairo-native = "0.3.1" +cairo-vm = "=1.0.2" camelpaste = "0.1.0" chrono = "0.4.26" clap = "4.5.4" -colored = "2.1.0" +colored = "3" const_format = "0.2.30" criterion = "0.5.1" deadqueue = "0.2.4" defaultmap = "0.5.0" derive_more = "0.99.17" +enum-as-inner = "0.6.1" enum-assoc = "1.1.0" enum-iterator = "1.4.1" ethers = "2.0.3" @@ -125,6 +135,7 @@ futures = "0.3.21" futures-channel = "0.3.21" futures-util = "0.3.21" glob = "0.3.1" +google-cloud-storage = "0.22.1" goose = "0.17.0" hex = "0.4.3" http = "0.2.8" @@ -132,7 +143,7 @@ http-body = "0.4.5" human_bytes = "0.4.3" hyper = "0.14" indexmap = "2.1.0" -infra_utils = { path = "crates/infra_utils", version = "0.0.0" } +indoc = "2.0.5" insta = "1.29.0" integer-encoding = "3.0.4" itertools = "0.12.1" @@ -146,12 +157,13 @@ libp2p-swarm-test = "0.3.0" log = "0.4" lru = "0.12.0" memmap2 = "0.8.0" -mempool_test_utils = { path = "crates/mempool_test_utils", version = "0.0.0" } -metrics = "0.21.0" -metrics-exporter-prometheus = "0.12.1" +mempool_test_utils.path = "crates/mempool_test_utils" +metrics = "0.24.1" +metrics-exporter-prometheus = "0.16.1" metrics-process = "1.0.11" mockall = "0.12.1" mockito = "1.4.0" +native_blockifier.path = "crates/native_blockifier" nix = "0.20.0" num-bigint = "0.4" num-integer = "0.1.45" @@ -160,25 +172,25 @@ num-traits = "0.2.15" once_cell = "1.19.0" os_info = "3.6.0" page_size = "0.6.0" -papyrus_base_layer = { path = "crates/papyrus_base_layer", version = "0.0.0" } -papyrus_common = { path = "crates/papyrus_common", version = "0.0.0" } +papyrus_base_layer.path = "crates/papyrus_base_layer" +papyrus_common.path = "crates/papyrus_common" papyrus_config = { path = "crates/papyrus_config", version = "0.0.0" } -papyrus_consensus = { path = "crates/sequencing/papyrus_consensus", version = "0.0.0" } -papyrus_consensus_orchestrator = { path = "crates/sequencing/papyrus_consensus_orchestrator", version = "0.0.0" } -papyrus_execution = { path = "crates/papyrus_execution", version = "0.0.0" } -papyrus_monitoring_gateway = { path = "crates/papyrus_monitoring_gateway", version = "0.0.0" } -papyrus_network = { path = "crates/papyrus_network", version = "0.0.0" } -papyrus_network_types = { path = "crates/papyrus_network_types", version = "0.0.0" } -papyrus_p2p_sync = { path = "crates/papyrus_p2p_sync", version = "0.0.0" } +papyrus_execution.path = "crates/papyrus_execution" +papyrus_load_test.path = "crates/papyrus_load_test" +papyrus_monitoring_gateway.path = "crates/papyrus_monitoring_gateway" +papyrus_network.path = "crates/papyrus_network" +papyrus_network_types.path = "crates/papyrus_network_types" +papyrus_node.path = "crates/papyrus_node" +papyrus_p2p_sync.path = "crates/papyrus_p2p_sync" papyrus_proc_macros = { path = "crates/papyrus_proc_macros", version = "0.0.0" } -papyrus_protobuf = { path = "crates/papyrus_protobuf", version = "0.0.0" } -papyrus_rpc = { path = "crates/papyrus_rpc", version = "0.0.0" } -papyrus_state_reader = { path = "crates/papyrus_state_reader", version = "0.0.0" } -papyrus_storage = { path = "crates/papyrus_storage", version = "0.0.0" } -papyrus_sync = { path = "crates/papyrus_sync", version = "0.0.0" } -papyrus_test_utils = { path = "crates/papyrus_test_utils", version = "0.0.0" } -parity-scale-codec = "=3.6.9" -parity-scale-codec-derive = "=3.6.9" +papyrus_protobuf.path = "crates/papyrus_protobuf" +papyrus_rpc.path = "crates/papyrus_rpc" +papyrus_state_reader.path = "crates/papyrus_state_reader" +papyrus_storage.path = "crates/papyrus_storage" +papyrus_sync.path = "crates/papyrus_sync" +papyrus_test_utils.path = "crates/papyrus_test_utils" +parity-scale-codec = "3.6" +parity-scale-codec-derive = "3.6" paste = "1.0.15" phf = "0.11" pretty_assertions = "1.4.0" @@ -198,7 +210,9 @@ regex = "1.10.4" replace_with = "0.1.7" reqwest = "0.11" retry = "2.0.0" +rlimit = "0.10.2" rstest = "0.17.0" +rstest_reuse = "0.7.0" rustc-hex = "2.1.0" schemars = "0.8.12" semver = "1.0.23" @@ -208,32 +222,49 @@ serde_repr = "0.1.19" serde_yaml = "0.9.16" sha2 = "0.10.8" sha3 = "0.10.8" +shared_execution_objects.path = "crates/shared_execution_objects" simple_logger = "4.0.0" -starknet-core = "0.6.0" +starknet-core = "0.12.1" starknet-crypto = "0.7.1" starknet-types-core = "0.1.6" starknet_api = { path = "crates/starknet_api", version = "0.0.0" } -starknet_batcher = { path = "crates/starknet_batcher", version = "0.0.0" } -starknet_batcher_types = { path = "crates/starknet_batcher_types", version = "0.0.0" } -starknet_client = { path = "crates/starknet_client", version = "0.0.0" } -starknet_committer = { path = "crates/starknet_committer", version = "0.0.0" } -starknet_consensus_manager = { path = "crates/starknet_consensus_manager", version = "0.0.0" } -starknet_gateway = { path = "crates/starknet_gateway", version = "0.0.0" } -starknet_gateway_types = { path = "crates/starknet_gateway_types", version = "0.0.0" } -starknet_http_server = { path = "crates/starknet_http_server", version = "0.0.0" } -starknet_l1_provider = { path = "crates/starknet_l1_provider", version = "0.0.0" } -starknet_mempool = { path = "crates/starknet_mempool", version = "0.0.0" } -starknet_mempool_p2p = { path = "crates/starknet_mempool_p2p", version = "0.0.0" } -starknet_mempool_p2p_types = { path = "crates/starknet_mempool_p2p_types", version = "0.0.0" } -starknet_mempool_types = { path = "crates/starknet_mempool_types", version = "0.0.0" } -starknet_monitoring_endpoint = { path = "crates/starknet_monitoring_endpoint", version = "0.0.0" } -starknet_patricia = { path = "crates/starknet_patricia", version = "0.0.0" } +starknet_batcher.path = "crates/starknet_batcher" +starknet_batcher_types.path = "crates/starknet_batcher_types" +starknet_class_manager.path = "crates/starknet_class_manager" +starknet_class_manager_types.path = "crates/starknet_class_manager_types" +starknet_client.path = "crates/starknet_client" +starknet_committer.path = "crates/starknet_committer" +starknet_committer_and_os_cli.path = "crates/starknet_committer_and_os_cli" +starknet_consensus.path = "crates/starknet_consensus" +starknet_consensus_manager.path = "crates/starknet_consensus_manager" +starknet_consensus_orchestrator.path = "crates/starknet_consensus_orchestrator" +starknet_gateway.path = "crates/starknet_gateway" +starknet_gateway_types.path = "crates/starknet_gateway_types" +starknet_http_server.path = "crates/starknet_http_server" +starknet_infra_utils = { path = "crates/starknet_infra_utils", version = "0.0.0" } +starknet_integration_tests.path = "crates/starknet_integration_tests" +starknet_l1_gas_price.path = "crates/starknet_l1_gas_price" +starknet_l1_gas_price_types.path = "crates/starknet_l1_gas_price_types" +starknet_l1_provider.path = "crates/starknet_l1_provider" +starknet_l1_provider_types.path = "crates/starknet_l1_provider_types" +starknet_mempool.path = "crates/starknet_mempool" +starknet_mempool_p2p.path = "crates/starknet_mempool_p2p" +starknet_mempool_p2p_types.path = "crates/starknet_mempool_p2p_types" +starknet_mempool_types.path = "crates/starknet_mempool_types" +starknet_monitoring_endpoint.path = "crates/starknet_monitoring_endpoint" +starknet_os.path = "crates/starknet_os" +starknet_patricia.path = "crates/starknet_patricia" +starknet_patricia_storage.path = "crates/starknet_patricia_storage" +starknet_sequencer_dashboard.path = "crates/starknet_sequencer_dashboard" +starknet_sequencer_deployments.path = "crates/starknet_sequencer_deployments" starknet_sequencer_infra = { path = "crates/starknet_sequencer_infra", version = "0.0.0" } -starknet_sequencer_node = { path = "crates/starknet_sequencer_node", version = "0.0.0" } -starknet_sierra_compile = { path = "crates/starknet_sierra_compile", version = "0.0.0" } -starknet_state_sync = { path = "crates/starknet_state_sync", version = "0.0.0" } -starknet_state_sync_types = { path = "crates/starknet_state_sync_types", version = "0.0.0" } -starknet_task_executor = { path = "crates/starknet_task_executor", version = "0.0.0" } +starknet_sequencer_metrics = { path = "crates/starknet_sequencer_metrics", version = "0.0.0" } +starknet_sequencer_node.path = "crates/starknet_sequencer_node" +starknet_sierra_multicompile = { path = "crates/starknet_sierra_multicompile", version = "0.0.0" } +starknet_sierra_multicompile_types = { path = "crates/starknet_sierra_multicompile_types", version = "0.0.0" } +starknet_state_sync.path = "crates/starknet_state_sync" +starknet_state_sync_types.path = "crates/starknet_state_sync_types" +starknet_task_executor.path = "crates/starknet_task_executor" static_assertions = "1.1.0" statistical = "1.0.0" strum = "0.25.0" @@ -249,7 +280,9 @@ tokio = "1.37.0" tokio-retry = "0.3" tokio-stream = "0.1.8" tokio-test = "0.4.4" +tokio-util = "0.7.13" toml = "0.8" +toml_test_utils.path = "toml_test_utils" tower = "0.4.13" tracing = "0.1.37" tracing-subscriber = "0.3.16" @@ -258,6 +291,7 @@ unsigned-varint = "0.8.0" url = "2.5.0" validator = "0.12" void = "1.0.2" +workspace_tests.path = "workspace_tests" zstd = "0.13.1" # Note: both rust and clippy lints are warning by default and denied on the CI (see run_tests.py). @@ -268,9 +302,14 @@ zstd = "0.13.1" future-incompatible = "warn" nonstandard-style = "warn" rust-2018-idioms = "warn" -# See [here](https://github.com/taiki-e/cargo-llvm-cov/issues/370) for a discussion on why this is -# needed (from rust 1.80). -unexpected_cfgs = { level = "warn", check-cfg = ['cfg(coverage_nightly)'] } +unexpected_cfgs = { level = "warn", check-cfg = [ + # See [here](https://github.com/taiki-e/cargo-llvm-cov/issues/370) for a discussion on why this is + # needed (from rust 1.80). + 'cfg(coverage_nightly)', + # From rust 1.84, seems like the pyo3 crate version we are using breaks. Remove this once pyo3 is + # removed from the workspace. + 'cfg(addr_of)', +] } [workspace.lints.clippy] as_conversions = "warn" diff --git a/Monitoring/sequencer/dev_grafana.json b/Monitoring/sequencer/dev_grafana.json new file mode 100644 index 00000000000..cfae6f32e98 --- /dev/null +++ b/Monitoring/sequencer/dev_grafana.json @@ -0,0 +1,349 @@ +{ + "Sequencer Node Dashboard": { + "Batcher": [ + { + "title": "batcher_proposal_started", + "description": "Counter of proposals started", + "type": "stat", + "expr": "batcher_proposal_started", + "extra_params": {} + }, + { + "title": "batcher_proposal_succeeded", + "description": "Counter of successful proposals", + "type": "stat", + "expr": "batcher_proposal_succeeded", + "extra_params": {} + }, + { + "title": "batcher_proposal_failed", + "description": "Counter of failed proposals", + "type": "stat", + "expr": "batcher_proposal_failed", + "extra_params": {} + }, + { + "title": "batcher_batched_transactions", + "description": "Counter of batched transactions across all forks", + "type": "stat", + "expr": "batcher_batched_transactions", + "extra_params": {} + }, + { + "title": "cairo_native_cache_miss_ratio", + "description": "The ratio of cache misses in the Cairo native cache", + "type": "graph", + "expr": "100 * (class_cache_misses / clamp_min((class_cache_misses + class_cache_hits), 1))", + "extra_params": {} + } + ], + "Consensus": [ + { + "title": "consensus_block_number", + "description": "The block number consensus is working to decide", + "type": "stat", + "expr": "consensus_block_number", + "extra_params": {} + }, + { + "title": "consensus_round", + "description": "The round of the state machine", + "type": "stat", + "expr": "consensus_round", + "extra_params": {} + }, + { + "title": "consensus_max_cached_block_number", + "description": "How many blocks after current are cached", + "type": "stat", + "expr": "consensus_max_cached_block_number", + "extra_params": {} + }, + { + "title": "consensus_cached_votes", + "description": "How many votes are cached when starting to work on a new block number", + "type": "stat", + "expr": "consensus_cached_votes", + "extra_params": {} + }, + { + "title": "consensus_decisions_reached_by_consensus", + "description": "The total number of decisions reached by way of consensus", + "type": "stat", + "expr": "consensus_decisions_reached_by_consensus", + "extra_params": {} + }, + { + "title": "consensus_decisions_reached_by_sync", + "description": "The total number of decisions reached by way of sync", + "type": "stat", + "expr": "consensus_decisions_reached_by_sync", + "extra_params": {} + }, + { + "title": "consensus_proposals_received", + "description": "The total number of proposals received", + "type": "stat", + "expr": "consensus_proposals_received", + "extra_params": {} + }, + { + "title": "consensus_proposals_valid_init", + "description": "The total number of proposals received with a valid init", + "type": "stat", + "expr": "consensus_proposals_valid_init", + "extra_params": {} + }, + { + "title": "consensus_proposals_validated", + "description": "The total number of complete, valid proposals received", + "type": "stat", + "expr": "consensus_proposals_validated", + "extra_params": {} + }, + { + "title": "consensus_proposals_invalid", + "description": "The total number of proposals that failed validation", + "type": "stat", + "expr": "consensus_proposals_invalid", + "extra_params": {} + }, + { + "title": "consensus_build_proposal_total", + "description": "The total number of proposals built", + "type": "stat", + "expr": "consensus_build_proposal_total", + "extra_params": {} + }, + { + "title": "consensus_build_proposal_failed", + "description": "The number of proposals that failed to be built", + "type": "stat", + "expr": "consensus_build_proposal_failed", + "extra_params": {} + }, + { + "title": "consensus_reproposals", + "description": "The number of reproposals sent", + "type": "stat", + "expr": "consensus_reproposals", + "extra_params": {} + } + ], + "Http Server": [ + { + "title": "http_server_added_transactions_total", + "description": "Total number of transactions added", + "type": "stat", + "expr": "http_server_added_transactions_total", + "extra_params": {} + } + ], + "MempoolP2p": [ + { + "title": "apollo_mempool_p2p_num_connected_peers", + "description": "The number of connected peers to the mempool p2p component", + "type": "stat", + "expr": "apollo_mempool_p2p_num_connected_peers", + "extra_params": {} + }, + { + "title": "apollo_mempool_p2p_num_sent_messages", + "description": "The number of messages sent by the mempool p2p component", + "type": "stat", + "expr": "apollo_mempool_p2p_num_sent_messages", + "extra_params": {} + }, + { + "title": "apollo_mempool_p2p_num_received_messages", + "description": "The number of messages received by the mempool p2p component", + "type": "stat", + "expr": "apollo_mempool_p2p_num_received_messages", + "extra_params": {} + }, + { + "title": "apollo_mempool_p2p_broadcasted_transaction_batch_size", + "description": "The number of transactions in batches broadcast by the mempool p2p component", + "type": "stat", + "expr": "apollo_mempool_p2p_broadcasted_transaction_batch_size", + "extra_params": {} + } + ], + "ConsensusP2p": [ + { + "title": "apollo_consensus_num_connected_peers", + "description": "The number of connected peers to the consensus p2p component", + "type": "stat", + "expr": "apollo_consensus_num_connected_peers", + "extra_params": {} + }, + { + "title": "apollo_consensus_votes_num_sent_messages", + "description": "The number of messages sent by the consensus p2p component over the Votes topic", + "type": "stat", + "expr": "apollo_consensus_votes_num_sent_messages", + "extra_params": {} + }, + { + "title": "apollo_consensus_votes_num_received_messages", + "description": "The number of messages received by the consensus p2p component over the Votes topic", + "type": "stat", + "expr": "apollo_consensus_votes_num_received_messages", + "extra_params": {} + }, + { + "title": "apollo_consensus_proposals_num_sent_messages", + "description": "The number of messages sent by the consensus p2p component over the Proposals topic", + "type": "stat", + "expr": "apollo_consensus_proposals_num_sent_messages", + "extra_params": {} + }, + { + "title": "apollo_consensus_proposals_num_received_messages", + "description": "The number of messages received by the consensus p2p component over the Proposals topic", + "type": "stat", + "expr": "apollo_consensus_proposals_num_received_messages", + "extra_params": {} + } + ], + "StateSyncP2p": [ + { + "title": "apollo_sync_num_connected_peers", + "description": "The number of connected peers to the state sync p2p component", + "type": "stat", + "expr": "apollo_sync_num_connected_peers", + "extra_params": {} + }, + { + "title": "apollo_sync_num_active_inbound_sessions", + "description": "The number of inbound sessions to the state sync p2p component", + "type": "stat", + "expr": "apollo_sync_num_active_inbound_sessions", + "extra_params": {} + }, + { + "title": "apollo_sync_num_active_outbound_sessions", + "description": "The number of outbound sessions to the state sync p2p component", + "type": "stat", + "expr": "apollo_sync_num_active_outbound_sessions", + "extra_params": {} + } + ], + "Gateway": [ + { + "title": "gateway_transactions_received", + "description": "Counter of transactions received", + "type": "stat", + "expr": "sum by (tx_type) (gateway_transactions_received) ", + "extra_params": {} + }, + { + "title": "gateway_transactions_received", + "description": "Counter of transactions received", + "type": "stat", + "expr": "sum by (source) (gateway_transactions_received) ", + "extra_params": {} + }, + { + "title": "gateway_transactions_received_rate (TPS)", + "description": "The rate of transactions received by the gateway during the last 20 minutes", + "type": "graph", + "expr": "sum(rate(gateway_transactions_received[20m]))", + "extra_params": {} + }, + { + "title": "gateway_add_tx_latency", + "description": "Latency of gateway add_tx function in secs", + "type": "graph", + "expr": "avg_over_time(gateway_add_tx_latency[2m])", + "extra_params": {} + }, + { + "title": "gateway_validate_tx_latency", + "description": "Latency of gateway validate function in secs", + "type": "graph", + "expr": "avg_over_time(gateway_validate_tx_latency[2m])", + "extra_params": {} + }, + { + "title": "gateway_transactions_failed", + "description": "Counter of failed transactions", + "type": "stat", + "expr": "sum by (tx_type) (gateway_transactions_failed)", + "extra_params": {} + }, + { + "title": "gateway_transactions_sent_to_mempool", + "description": "Counter of transactions sent to the mempool", + "type": "stat", + "expr": "sum by (tx_type) (gateway_transactions_sent_to_mempool)", + "extra_params": {} + } + ], + "Mempool": [ + { + "title": "mempool_transactions_received", + "description": "Counter of transactions received by the mempool", + "type": "stat", + "expr": "sum by (tx_type) (mempool_transactions_received)", + "extra_params": {} + }, + { + "title": "mempool_transactions_received_rate (TPS)", + "description": "The rate of transactions received by the mempool during the last 20 minutes", + "type": "graph", + "expr": "sum(rate(mempool_transactions_received[20m]))", + "extra_params": {} + }, + { + "title": "mempool_transactions_dropped", + "description": "Counter of transactions dropped from the mempool", + "type": "stat", + "expr": "sum by (drop_reason) (mempool_transactions_dropped)", + "extra_params": {} + }, + { + "title": "mempool_txs_committed", + "description": "The number of transactions that were committed to block", + "type": "stat", + "expr": "mempool_txs_committed", + "extra_params": {} + }, + { + "title": "mempool_pool_size", + "description": "The average size of the pool", + "type": "graph", + "expr": "avg_over_time(mempool_pool_size[2m])", + "extra_params": {} + }, + { + "title": "mempool_priority_queue_size", + "description": "The average size of the priority queue", + "type": "graph", + "expr": "avg_over_time(mempool_priority_queue_size[2m])", + "extra_params": {} + }, + { + "title": "mempool_pending_queue_size", + "description": "The average size of the pending queue", + "type": "graph", + "expr": "avg_over_time(mempool_pending_queue_size[2m])", + "extra_params": {} + }, + { + "title": "mempool_get_txs_size", + "description": "The average size of the get_txs", + "type": "graph", + "expr": "avg_over_time(mempool_get_txs_size[2m])", + "extra_params": {} + }, + { + "title": "mempool_transaction_time_spent", + "description": "The time (secs) that a transaction spent in the mempool", + "type": "graph", + "expr": "avg_over_time(mempool_transaction_time_spent[2m])", + "extra_params": {} + } + ] + } +} diff --git a/Monitoring/sequencer/dev_grafana_alerts.json b/Monitoring/sequencer/dev_grafana_alerts.json new file mode 100644 index 00000000000..fcb1298f514 --- /dev/null +++ b/Monitoring/sequencer/dev_grafana_alerts.json @@ -0,0 +1,29 @@ +{ + "alerts": [ + { + "name": "gateway_add_tx_rate_drop", + "title": "Gateway add_tx rate drop", + "ruleGroup": "gateway", + "expr": "sum(rate(gateway_transactions_received[20m]))", + "conditions": [ + { + "evaluator": { + "params": [ + 0.01 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "reducer": { + "params": [], + "type": "avg" + }, + "type": "query" + } + ], + "for": "5m" + } + ] +} diff --git a/Monitoring/sequencer/grafana_data.json b/Monitoring/sequencer/grafana_data.json new file mode 100644 index 00000000000..b18a46b6834 --- /dev/null +++ b/Monitoring/sequencer/grafana_data.json @@ -0,0 +1,46 @@ +{ + "name": "dashboarad_example_1", + "description": "dashboarad_default_description_2", + "rows": [ + { + "name": "row_example_1", + "description": "row_default_description_1", + "panels": [ + { + "description": "panel_default_description_1", + "expr": "expr1", + "name": "row_example_1", + "panel_type": "Stat", + "position": 1 + }, + { + "description": "panel_default_description_2", + "expr": "expr2", + "name": "row_example_2", + "panel_type": "Stat", + "position": 2 + } + ] + }, + { + "name": "row_example_2", + "description": "row_default_description_2", + "panels": [ + { + "description": "panel_default_description_3", + "expr": "expr3", + "name": "row_example_3", + "panel_type": "Stat", + "position": 1 + }, + { + "description": "panel_default_description_4", + "expr": "expr4", + "name": "row_example_4", + "panel_type": "Stat", + "position": 2 + } + ] + } + ] +} diff --git a/build_native_in_docker.sh b/build_native_in_docker.sh index 9ceb7cdfab6..e603f5848ec 100755 --- a/build_native_in_docker.sh +++ b/build_native_in_docker.sh @@ -1,20 +1,21 @@ #!/bin/env bash set -e +# Enables build-x for older versions of docker. +export DOCKER_BUILDKIT=1 + docker_image_name=sequencer-ci +dockerfile_path="docker-ci/images/${docker_image_name}.Dockerfile" -( - cd scripts - docker build . -t ${docker_image_name} --file ${docker_image_name}.Dockerfile -) +docker build . --build-arg USER_UID=$UID -t ${docker_image_name} --file ${dockerfile_path} docker run \ --rm \ --net host \ - -e CARGO_HOME=${HOME}/.cargo \ + -e CARGO_HOME="${HOME}/.cargo" \ -u $UID \ -v /tmp:/tmp \ -v "${HOME}:${HOME}" \ - --workdir ${PWD} \ + --workdir "${PWD}" \ ${docker_image_name} \ "$@" diff --git a/commitlint.config.js b/commitlint.config.js index 35b60a56814..dda0bcb8883 100644 --- a/commitlint.config.js +++ b/commitlint.config.js @@ -18,55 +18,79 @@ const Configuration = { * Any rules defined here will override rules from @commitlint/config-conventional */ rules: { + 'scope-empty': [2, 'never'], 'scope-enum': [2, 'always', [ - 'base_layer', - 'batcher', - 'block_hash', + "apollo_reverts", 'blockifier', 'blockifier_reexecution', + 'blockifier_test_utils', 'cairo_native', 'ci', 'committer', - 'common', - 'concurrency', - 'config', 'consensus', 'deployment', - 'execution', - 'fee', - 'gateway', - 'helm', 'infra', - 'JSON-RPC', - 'l1_provider', - 'load_test', - 'mempool', - 'mempool_p2p', - 'mempool_p2p_types', 'mempool_test_utils', - 'mempool_types', - 'monitoring', 'native_blockifier', - 'network', - 'node', + 'papyrus_base_layer', + 'papyrus_common', + 'papyrus_config', + 'papyrus_execution', + 'papyrus_load_test', + 'papyrus_monitoring_gateway', + 'papyrus_network', + 'papyrus_network_types', + 'papyrus_node', + 'papyrus_p2p_sync', + 'papyrus_proc_macros', + 'papyrus_protobuf', + 'papyrus_rpc', 'papyrus_state_reader', - 'protobuf', + 'papyrus_storage', + 'papyrus_sync', + 'papyrus_test_utils', 'release', - 'sequencer_infra', - 'sequencer_node', - 'skeleton', + 'shared_execution_objects', 'starknet_api', + 'starknet_batcher', + 'starknet_batcher_types', 'starknet_client', + 'starknet_committer', + 'starknet_committer_and_os_cli', + 'starknet_consensus_manager', + 'starknet_consensus_orchestrator', + 'starknet_class_manager', + 'starknet_class_manager_types', 'starknet_gateway', - 'state', - 'storage', - 'sync', - 'test_utils', - 'tests_integration', - 'transaction', - 'types', + 'starknet_gateway_types', + 'starknet_http_server', + 'starknet_infra_utils', + 'starknet_integration_tests', + 'starknet_l1_gas_price', + 'starknet_l1_gas_price_types', + 'starknet_l1_provider', + 'starknet_l1_provider_types', + 'starknet_mempool', + 'starknet_mempool_p2p', + 'starknet_mempool_p2p_types', + 'starknet_mempool_types', + 'starknet_monitoring_endpoint', + 'starknet_os', + 'starknet_patricia', + 'starknet_patricia_storage', + 'starknet_sequencer_deployments', + 'starknet_sequencer_infra', + 'starknet_sequencer_dashboard', + 'starknet_sequencer_metrics', + 'starknet_sequencer_node', + 'starknet_sierra_multicompile', + 'starknet_sierra_multicompile_types', + 'starknet_state_sync', + 'starknet_state_sync_types', + 'starknet_task_executor', + 'workspace_tests', ]], - 'header-max-length': [2, 'always', 72], + 'header-max-length': [2, 'always', 100], }, /* * Functions that return true if commitlint should ignore the given message. diff --git a/config/papyrus/default_config.json b/config/papyrus/default_config.json index ab8323e8ad7..13a697b883c 100644 --- a/config/papyrus/default_config.json +++ b/config/papyrus/default_config.json @@ -1,8 +1,8 @@ { "base_layer.node_url": { - "description": "A required param! Ethereum node URL. A schema to match to Infura node: https://mainnet.infura.io/v3/, but any other node can be used.", - "param_type": "String", - "privacy": "Private" + "description": "Ethereum node URL. A schema to match to Infura node: https://mainnet.infura.io/v3/, but any other node can be used.", + "privacy": "Private", + "value": "https://mainnet.infura.io/v3/%3Cyour_api_key%3E" }, "base_layer.starknet_contract_address": { "description": "Starknet contract address in ethereum.", @@ -60,9 +60,9 @@ "privacy": "Public" }, "chain_id": { - "description": "The chain to follow. For more details see https://docs.starknet.io/documentation/architecture_and_concepts/Blocks/transactions/#chain-id.", - "privacy": "TemporaryValue", - "value": "SN_MAIN" + "description": "A required param! The chain to follow. For more details see https://docs.starknet.io/documentation/architecture_and_concepts/Blocks/transactions/#chain-id.", + "param_type": "String", + "privacy": "TemporaryValue" }, "collect_metrics": { "description": "If true, collect metrics for the node.", @@ -79,125 +79,95 @@ "privacy": "TemporaryValue", "value": true }, - "consensus.consensus_delay": { - "description": "Delay (seconds) before starting consensus to give time for network peering.", - "privacy": "Public", - "value": 5 - }, - "consensus.network_config.advertised_multiaddr": { - "description": "The external address other peers see this node. If this is set, the node will not try to find out which addresses it has and will write this address as external instead", - "privacy": "Public", - "value": "" - }, - "consensus.network_config.advertised_multiaddr.#is_none": { - "description": "Flag for an optional field.", - "privacy": "TemporaryValue", - "value": true - }, - "consensus.network_config.bootstrap_peer_multiaddr": { - "description": "The multiaddress of the peer node. It should include the peer's id. For more info: https://docs.libp2p.io/concepts/fundamentals/peers/", + "consensus.future_height_limit": { + "description": "How many heights in the future should we cache.", "privacy": "Public", - "value": "" - }, - "consensus.network_config.bootstrap_peer_multiaddr.#is_none": { - "description": "Flag for an optional field.", - "privacy": "TemporaryValue", - "value": true - }, - "consensus.network_config.chain_id": { - "description": "The chain to follow. For more details see https://docs.starknet.io/documentation/architecture_and_concepts/Blocks/transactions/#chain-id.", - "pointer_target": "chain_id", - "privacy": "Public" + "value": 10 }, - "consensus.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": { - "description": "The base delay in milliseconds for the exponential backoff strategy.", + "consensus.future_height_round_limit": { + "description": "How many rounds should we cache for future heights.", "privacy": "Public", - "value": 2 + "value": 1 }, - "consensus.network_config.discovery_config.bootstrap_dial_retry_config.factor": { - "description": "The factor for the exponential backoff strategy.", + "consensus.future_round_limit": { + "description": "How many rounds in the future (for current height) should we cache.", "privacy": "Public", - "value": 5 + "value": 10 }, - "consensus.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": { - "description": "The maximum delay in seconds for the exponential backoff strategy.", + "consensus.startup_delay": { + "description": "Delay (seconds) before starting consensus to give time for network peering.", "privacy": "Public", "value": 5 }, - "consensus.network_config.discovery_config.heartbeat_interval": { - "description": "The interval between each discovery (Kademlia) query in milliseconds.", + "consensus.sync_retry_interval": { + "description": "The duration (seconds) between sync attempts.", "privacy": "Public", - "value": 100 + "value": 1.0 }, - "consensus.network_config.idle_connection_timeout": { - "description": "Amount of time in seconds that a connection with no active sessions will stay alive.", + "consensus.timeouts.precommit_timeout": { + "description": "The timeout (seconds) for a precommit.", "privacy": "Public", - "value": 120 + "value": 1.0 }, - "consensus.network_config.peer_manager_config.malicious_timeout_seconds": { - "description": "The duration in seconds a peer is blacklisted after being marked as malicious.", + "consensus.timeouts.prevote_timeout": { + "description": "The timeout (seconds) for a prevote.", "privacy": "Public", - "value": 31536000 + "value": 1.0 }, - "consensus.network_config.peer_manager_config.unstable_timeout_millis": { - "description": "The duration in milliseconds a peer blacklisted after being reported as unstable.", + "consensus.timeouts.proposal_timeout": { + "description": "The timeout (seconds) for a proposal.", "privacy": "Public", - "value": 1000 + "value": 3.0 }, - "consensus.network_config.quic_port": { - "description": "The port that the node listens on for incoming quic connections.", + "consensus.validator_id": { + "description": "The validator id of the node.", "privacy": "Public", - "value": 10101 + "value": "0x64" }, - "consensus.network_config.secret_key": { - "description": "The secret key used for building the peer id. If it's an empty string a random one will be used.", - "privacy": "Private", - "value": "" + "context.#is_none": { + "description": "Flag for an optional field.", + "privacy": "TemporaryValue", + "value": true }, - "consensus.network_config.session_timeout": { - "description": "Maximal time in seconds that each session can take before failing on timeout.", + "context.block_timestamp_window": { + "description": "Maximum allowed deviation (seconds) of a proposed block's timestamp from the current time.", "privacy": "Public", - "value": 120 + "value": 1 }, - "consensus.network_config.tcp_port": { - "description": "The port that the node listens on for incoming tcp connections.", + "context.build_proposal_margin": { + "description": "Safety margin (in ms) to make sure that the batcher completes building the proposal with enough time for the Fin to be checked by validators.", "privacy": "Public", - "value": 10100 + "value": 1000 }, - "consensus.network_topic": { - "description": "The network topic of the consensus.", + "context.builder_address": { + "description": "The address of the contract that builds the block.", "privacy": "Public", - "value": "consensus" + "value": "0x0" }, - "consensus.num_validators": { - "description": "The number of validators in the consensus.", - "privacy": "Public", - "value": 1 + "context.chain_id": { + "description": "The chain id of the Starknet chain.", + "pointer_target": "chain_id", + "privacy": "Public" }, - "consensus.start_height": { - "description": "The height to start the consensus from.", + "context.l1_da_mode": { + "description": "The data availability mode, true: Blob, false: Calldata.", "privacy": "Public", - "value": 0 + "value": true }, - "consensus.timeouts.precommit_timeout": { - "description": "The timeout (seconds) for a precommit.", + "context.num_validators": { + "description": "The number of validators.", "privacy": "Public", - "value": 1.0 + "value": 1 }, - "consensus.timeouts.prevote_timeout": { - "description": "The timeout (seconds) for a prevote.", + "context.proposal_buffer_size": { + "description": "The buffer size for streaming outbound proposals.", "privacy": "Public", - "value": 1.0 - }, - "consensus.timeouts.proposal_timeout": { - "description": "The timeout (seconds) for a proposal.", - "privacy": "Public", - "value": 3.0 + "value": 100 }, - "consensus.validator_id": { - "description": "The validator id of the node.", + "context.validate_proposal_margin": { + "description": "Safety margin (in ms) to make sure that consensus determines when to timeout validating a proposal.", "privacy": "Public", - "value": "0x0" + "value": 10000 }, "monitoring_gateway.collect_metrics": { "description": "If true, collect and return metrics in the monitoring gateway.", @@ -282,17 +252,17 @@ "network.peer_manager_config.malicious_timeout_seconds": { "description": "The duration in seconds a peer is blacklisted after being marked as malicious.", "privacy": "Public", - "value": 31536000 + "value": 1 }, "network.peer_manager_config.unstable_timeout_millis": { "description": "The duration in milliseconds a peer blacklisted after being reported as unstable.", "privacy": "Public", "value": 1000 }, - "network.quic_port": { - "description": "The port that the node listens on for incoming quic connections.", + "network.port": { + "description": "The port that the node listens on for incoming tcp connections.", "privacy": "Public", - "value": 10001 + "value": 10000 }, "network.secret_key": { "description": "The secret key used for building the peer id. If it's an empty string a random one will be used.", @@ -304,11 +274,6 @@ "privacy": "Public", "value": 120 }, - "network.tcp_port": { - "description": "The port that the node listens on for incoming tcp connections.", - "privacy": "Public", - "value": 10000 - }, "p2p_sync.#is_none": { "description": "Flag for an optional field.", "privacy": "TemporaryValue", @@ -339,20 +304,15 @@ "privacy": "Public", "value": 10000 }, - "p2p_sync.stop_sync_at_block_number": { - "description": "Stops the sync at given block number and closes the node cleanly. Used to run profiling on the node.", + "p2p_sync.wait_period_for_new_data": { + "description": "Time in millisseconds to wait when a query returned with partial data before sending a new query", "privacy": "Public", - "value": 1000 - }, - "p2p_sync.stop_sync_at_block_number.#is_none": { - "description": "Flag for an optional field.", - "privacy": "TemporaryValue", - "value": true + "value": 50 }, - "p2p_sync.wait_period_for_new_data": { - "description": "Time in seconds to wait when a query returned with partial data before sending a new query", + "p2p_sync.wait_period_for_other_protocol": { + "description": "Time in millisseconds to wait for a dependency protocol to advance (e.g.state diff sync depends on header sync)", "privacy": "Public", - "value": 5 + "value": 50 }, "rpc.chain_id": { "description": "The chain to follow. For more details see https://docs.starknet.io/documentation/architecture_and_concepts/Blocks/transactions/#chain-id.", @@ -504,9 +464,14 @@ "privacy": "Public", "value": 1000 }, + "sync.store_sierras_and_casms": { + "description": "Whether to store sierras and casms to the storage. This allows maintaining backward-compatibility with native-blockifier", + "privacy": "Public", + "value": true + }, "sync.verify_blocks": { "description": "Whether to verify incoming blocks.", "privacy": "Public", "value": true } -} \ No newline at end of file +} diff --git a/config/sequencer/default_config.json b/config/sequencer/default_config.json index b5941df09da..a6ffb03f0e1 100644 --- a/config/sequencer/default_config.json +++ b/config/sequencer/default_config.json @@ -1,56 +1,16 @@ { - "batcher_config.block_builder_config.bouncer_config.block_max_capacity.builtin_count.add_mod": { - "description": "Max number of add mod builtin usage in a block.", - "privacy": "Public", - "value": 156250 - }, - "batcher_config.block_builder_config.bouncer_config.block_max_capacity.builtin_count.bitwise": { - "description": "Max number of bitwise builtin usage in a block.", - "privacy": "Public", - "value": 39062 - }, - "batcher_config.block_builder_config.bouncer_config.block_max_capacity.builtin_count.ec_op": { - "description": "Max number of EC operation builtin usage in a block.", - "privacy": "Public", - "value": 2441 - }, - "batcher_config.block_builder_config.bouncer_config.block_max_capacity.builtin_count.ecdsa": { - "description": "Max number of ECDSA builtin usage in a block.", - "privacy": "Public", - "value": 1220 - }, - "batcher_config.block_builder_config.bouncer_config.block_max_capacity.builtin_count.keccak": { - "description": "Max number of keccak builtin usage in a block.", - "privacy": "Public", - "value": 1220 - }, - "batcher_config.block_builder_config.bouncer_config.block_max_capacity.builtin_count.mul_mod": { - "description": "Max number of mul mod builtin usage in a block.", - "privacy": "Public", - "value": 156250 - }, - "batcher_config.block_builder_config.bouncer_config.block_max_capacity.builtin_count.pedersen": { - "description": "Max number of pedersen builtin usage in a block.", - "privacy": "Public", - "value": 78125 - }, - "batcher_config.block_builder_config.bouncer_config.block_max_capacity.builtin_count.poseidon": { - "description": "Max number of poseidon builtin usage in a block.", - "privacy": "Public", - "value": 78125 - }, - "batcher_config.block_builder_config.bouncer_config.block_max_capacity.builtin_count.range_check": { - "description": "Max number of range check builtin usage in a block.", - "privacy": "Public", - "value": 156250 + "base_layer_config.node_url": { + "description": "Ethereum node URL. A schema to match to Infura node: https://mainnet.infura.io/v3/, but any other node can be used.", + "privacy": "Private", + "value": "https://mainnet.infura.io/v3/%3Cyour_api_key%3E" }, - "batcher_config.block_builder_config.bouncer_config.block_max_capacity.builtin_count.range_check96": { - "description": "Max number of range check 96 builtin usage in a block.", + "base_layer_config.starknet_contract_address": { + "description": "Starknet contract address in ethereum.", "privacy": "Public", - "value": 156250 + "value": "0xc662c410C0ECf747543f5bA90660f6ABeBD9C8c4" }, - "batcher_config.block_builder_config.bouncer_config.block_max_capacity.gas": { - "description": "An upper bound on the total gas used in a block.", + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.l1_gas": { + "description": "An upper bound on the total l1_gas used in a block.", "privacy": "Public", "value": 2500000 }, @@ -64,10 +24,10 @@ "privacy": "Public", "value": 5000 }, - "batcher_config.block_builder_config.bouncer_config.block_max_capacity.n_steps": { - "description": "An upper bound on the total number of steps in a block.", + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.sierra_gas": { + "description": "An upper bound on the total sierra_gas used in a block.", "privacy": "Public", - "value": 2500000 + "value": 400000000 }, "batcher_config.block_builder_config.bouncer_config.block_max_capacity.state_diff_size": { "description": "An upper bound on the total state diff size in a block.", @@ -104,26 +64,26 @@ "privacy": "Public", "value": 0 }, - "batcher_config.block_builder_config.sequencer_address": { - "description": "The address of the sequencer.", - "pointer_target": "sequencer_address", - "privacy": "Public" + "batcher_config.block_builder_config.execute_config.stack_size": { + "description": "The thread stack size (proportional to the maximal gas of a transaction).", + "privacy": "Public", + "value": 62914560 }, "batcher_config.block_builder_config.tx_chunk_size": { - "description": "The size of the transaction chunk.", + "description": "Number of transactions in each request from the tx_provider.", "privacy": "Public", "value": 100 }, - "batcher_config.block_builder_config.use_kzg_da": { - "description": "Indicates whether the kzg mechanism is used for data availability.", - "privacy": "Public", - "value": true - }, "batcher_config.block_builder_config.versioned_constants_overrides.invoke_tx_max_n_steps": { "description": "Maximum number of steps the invoke function is allowed to run.", "pointer_target": "versioned_constants_overrides.invoke_tx_max_n_steps", "privacy": "Public" }, + "batcher_config.block_builder_config.versioned_constants_overrides.max_n_events": { + "description": "Maximum number of events that can be emitted from the transation.", + "pointer_target": "versioned_constants_overrides.max_n_events", + "privacy": "Public" + }, "batcher_config.block_builder_config.versioned_constants_overrides.max_recursion_depth": { "description": "Maximum recursion depth for nested calls during blockifier validation.", "pointer_target": "versioned_constants_overrides.max_recursion_depth", @@ -134,10 +94,70 @@ "pointer_target": "versioned_constants_overrides.validate_max_n_steps", "privacy": "Public" }, - "batcher_config.global_contract_cache_size": { - "description": "Cache size for the global_class_hash_to_class. Initialized with this size on creation.", + "batcher_config.contract_class_manager_config.cairo_native_run_config.channel_size": { + "description": "The size of the compilation request channel.", "privacy": "Public", - "value": 400 + "value": 2000 + }, + "batcher_config.contract_class_manager_config.cairo_native_run_config.native_classes_whitelist": { + "description": "Contracts for Cairo Specifies whether to execute all class hashes or only a limited selection using Cairo native contracts. If limited, a specific list of class hashes is provided. compilation.", + "privacy": "Public", + "value": "All" + }, + "batcher_config.contract_class_manager_config.cairo_native_run_config.run_cairo_native": { + "description": "Enables Cairo native execution.", + "privacy": "Public", + "value": false + }, + "batcher_config.contract_class_manager_config.cairo_native_run_config.wait_on_native_compilation": { + "description": "Block Sequencer main program while compiling sierra, for testing.", + "privacy": "Public", + "value": false + }, + "batcher_config.contract_class_manager_config.contract_cache_size": { + "description": "The size of the global contract cache.", + "privacy": "Public", + "value": 600 + }, + "batcher_config.contract_class_manager_config.native_compiler_config.max_casm_bytecode_size": { + "description": "Limitation of compiled casm bytecode size.", + "privacy": "Public", + "value": 81920 + }, + "batcher_config.contract_class_manager_config.native_compiler_config.max_cpu_time": { + "description": "Limitation of compilation cpu time (seconds).", + "privacy": "Public", + "value": 20 + }, + "batcher_config.contract_class_manager_config.native_compiler_config.max_memory_usage": { + "description": "Limitation of compilation process's virtual memory (bytes).", + "privacy": "Public", + "value": 5368709120 + }, + "batcher_config.contract_class_manager_config.native_compiler_config.max_native_bytecode_size": { + "description": "Limitation of compiled native bytecode size.", + "privacy": "Public", + "value": 15728640 + }, + "batcher_config.contract_class_manager_config.native_compiler_config.optimization_level": { + "description": "The level of optimization to apply during compilation.", + "privacy": "Public", + "value": 2 + }, + "batcher_config.contract_class_manager_config.native_compiler_config.panic_on_compilation_failure": { + "description": "Whether to panic on compilation failure.", + "privacy": "Public", + "value": false + }, + "batcher_config.contract_class_manager_config.native_compiler_config.sierra_to_native_compiler_path": { + "description": "The path to the Sierra-to-Native compiler binary.", + "privacy": "Public", + "value": "" + }, + "batcher_config.contract_class_manager_config.native_compiler_config.sierra_to_native_compiler_path.#is_none": { + "description": "Flag for an optional field.", + "privacy": "TemporaryValue", + "value": true }, "batcher_config.input_stream_content_buffer_size": { "description": "Sets the buffer size for the input transaction channel. Adding more transactions beyond this limit will block until space is available.", @@ -162,7 +182,7 @@ "batcher_config.storage.db_config.enforce_file_exists": { "description": "Whether to enforce that the path exists. If true, `open_env` fails when the mdbx.dat file does not exist.", "privacy": "Public", - "value": true + "value": false }, "batcher_config.storage.db_config.growth_step": { "description": "The growth step in bytes, must be greater than zero to allow the database to grow.", @@ -182,7 +202,7 @@ "batcher_config.storage.db_config.path_prefix": { "description": "Prefix of the path of the node's storage directory, the storage file path will be /. The path is not created automatically.", "privacy": "Public", - "value": "." + "value": "/data/batcher" }, "batcher_config.storage.mmap_file_config.growth_step": { "description": "The growth step in bytes, must be greater than max_object_size.", @@ -205,34 +225,104 @@ "value": "StateOnly" }, "chain_id": { - "description": "A required param! The chain to follow.", - "param_type": "String", - "privacy": "TemporaryValue" + "description": "The chain to follow. For more details see https://docs.starknet.io/documentation/architecture_and_concepts/Blocks/transactions/#chain-id.", + "privacy": "TemporaryValue", + "value": "PointerTarget" + }, + "class_manager_config.class_manager_config.cached_class_storage_config.class_cache_size": { + "description": "Contract classes cache size.", + "privacy": "Public", + "value": 10 + }, + "class_manager_config.class_manager_config.cached_class_storage_config.deprecated_class_cache_size": { + "description": "Deprecated contract classes cache size.", + "privacy": "Public", + "value": 10 + }, + "class_manager_config.class_storage_config.class_hash_storage_config.enforce_file_exists": { + "description": "Whether to enforce that the above path exists.", + "privacy": "Public", + "value": false + }, + "class_manager_config.class_storage_config.class_hash_storage_config.max_size": { + "description": "The maximum size of the class hash storage in bytes.", + "privacy": "Public", + "value": 1048576 + }, + "class_manager_config.class_storage_config.class_hash_storage_config.path_prefix": { + "description": "Prefix of the path of class hash storage directory.", + "privacy": "Public", + "value": "/data/class_hash_storage" + }, + "class_manager_config.class_storage_config.persistent_root": { + "description": "Path to the node's class storage directory.", + "privacy": "Public", + "value": "/data/classes" }, - "compiler_config.max_bytecode_size": { - "description": "Limitation of contract bytecode size.", + "compiler_config.max_casm_bytecode_size": { + "description": "Limitation of compiled casm bytecode size.", "privacy": "Public", "value": 81920 }, + "compiler_config.max_cpu_time": { + "description": "Limitation of compilation cpu time (seconds).", + "privacy": "Public", + "value": 20 + }, + "compiler_config.max_memory_usage": { + "description": "Limitation of compilation process's virtual memory (bytes).", + "privacy": "Public", + "value": 5368709120 + }, + "compiler_config.max_native_bytecode_size": { + "description": "Limitation of compiled native bytecode size.", + "privacy": "Public", + "value": 15728640 + }, + "compiler_config.optimization_level": { + "description": "The level of optimization to apply during compilation.", + "privacy": "Public", + "value": 2 + }, + "compiler_config.panic_on_compilation_failure": { + "description": "Whether to panic on compilation failure.", + "privacy": "Public", + "value": false + }, + "compiler_config.sierra_to_native_compiler_path": { + "description": "The path to the Sierra-to-Native compiler binary.", + "privacy": "Public", + "value": "" + }, + "compiler_config.sierra_to_native_compiler_path.#is_none": { + "description": "Flag for an optional field.", + "privacy": "TemporaryValue", + "value": true + }, "components.batcher.execution_mode": { "description": "The component execution mode.", "privacy": "Public", "value": "LocalExecutionWithRemoteDisabled" }, - "components.batcher.local_server_config.#is_none": { - "description": "Flag for an optional field.", - "privacy": "TemporaryValue", - "value": false + "components.batcher.ip": { + "description": "Binding address of the remote component server.", + "privacy": "Public", + "value": "0.0.0.0" }, "components.batcher.local_server_config.channel_buffer_size": { "description": "The communication channel buffer size.", "privacy": "Public", "value": 32 }, - "components.batcher.remote_client_config.#is_none": { - "description": "Flag for an optional field.", - "privacy": "TemporaryValue", - "value": true + "components.batcher.max_concurrency": { + "description": "The maximum number of concurrent requests handling.", + "privacy": "Public", + "value": 10 + }, + "components.batcher.port": { + "description": "Listening port of the remote component server.", + "privacy": "Public", + "value": 0 }, "components.batcher.remote_client_config.idle_connections": { "description": "The maximum number of idle connections to keep alive.", @@ -249,90 +339,95 @@ "privacy": "Public", "value": 3 }, - "components.batcher.remote_client_config.socket": { - "description": "The remote component server socket.", + "components.batcher.remote_client_config.retry_interval": { + "description": "The duration in seconds to wait between remote connection retries.", "privacy": "Public", - "value": "0.0.0.0:8080" - }, - "components.batcher.remote_server_config.#is_none": { - "description": "Flag for an optional field.", - "privacy": "TemporaryValue", - "value": true + "value": 3 }, - "components.batcher.remote_server_config.socket": { - "description": "The remote component server socket.", + "components.batcher.url": { + "description": "URL of the remote component server.", "privacy": "Public", - "value": "0.0.0.0:8080" + "value": "localhost" }, - "components.consensus_manager.execution_mode": { + "components.class_manager.execution_mode": { "description": "The component execution mode.", "privacy": "Public", "value": "LocalExecutionWithRemoteDisabled" }, - "components.consensus_manager.local_server_config.#is_none": { - "description": "Flag for an optional field.", - "privacy": "TemporaryValue", - "value": false + "components.class_manager.ip": { + "description": "Binding address of the remote component server.", + "privacy": "Public", + "value": "0.0.0.0" }, - "components.consensus_manager.local_server_config.channel_buffer_size": { + "components.class_manager.local_server_config.channel_buffer_size": { "description": "The communication channel buffer size.", "privacy": "Public", "value": 32 }, - "components.consensus_manager.remote_client_config.#is_none": { - "description": "Flag for an optional field.", - "privacy": "TemporaryValue", - "value": true + "components.class_manager.max_concurrency": { + "description": "The maximum number of concurrent requests handling.", + "privacy": "Public", + "value": 10 + }, + "components.class_manager.port": { + "description": "Listening port of the remote component server.", + "privacy": "Public", + "value": 0 }, - "components.consensus_manager.remote_client_config.idle_connections": { + "components.class_manager.remote_client_config.idle_connections": { "description": "The maximum number of idle connections to keep alive.", "privacy": "Public", "value": 18446744073709551615 }, - "components.consensus_manager.remote_client_config.idle_timeout": { + "components.class_manager.remote_client_config.idle_timeout": { "description": "The duration in seconds to keep an idle connection open before closing.", "privacy": "Public", "value": 90 }, - "components.consensus_manager.remote_client_config.retries": { + "components.class_manager.remote_client_config.retries": { "description": "The max number of retries for sending a message.", "privacy": "Public", "value": 3 }, - "components.consensus_manager.remote_client_config.socket": { - "description": "The remote component server socket.", + "components.class_manager.remote_client_config.retry_interval": { + "description": "The duration in seconds to wait between remote connection retries.", "privacy": "Public", - "value": "0.0.0.0:8080" + "value": 3 }, - "components.consensus_manager.remote_server_config.#is_none": { - "description": "Flag for an optional field.", - "privacy": "TemporaryValue", - "value": true + "components.class_manager.url": { + "description": "URL of the remote component server.", + "privacy": "Public", + "value": "localhost" }, - "components.consensus_manager.remote_server_config.socket": { - "description": "The remote component server socket.", + "components.consensus_manager.execution_mode": { + "description": "The component execution mode.", "privacy": "Public", - "value": "0.0.0.0:8080" + "value": "Enabled" }, "components.gateway.execution_mode": { "description": "The component execution mode.", "privacy": "Public", "value": "LocalExecutionWithRemoteDisabled" }, - "components.gateway.local_server_config.#is_none": { - "description": "Flag for an optional field.", - "privacy": "TemporaryValue", - "value": false + "components.gateway.ip": { + "description": "Binding address of the remote component server.", + "privacy": "Public", + "value": "0.0.0.0" }, "components.gateway.local_server_config.channel_buffer_size": { "description": "The communication channel buffer size.", "privacy": "Public", "value": 32 }, - "components.gateway.remote_client_config.#is_none": { - "description": "Flag for an optional field.", - "privacy": "TemporaryValue", - "value": true + "components.gateway.max_concurrency": { + "description": "The maximum number of concurrent requests handling.", + "privacy": "Public", + "value": 10 + }, + "components.gateway.port": { + "description": "Listening port of the remote component server.", + "privacy": "Public", + "value": 0 }, "components.gateway.remote_client_config.idle_connections": { "description": "The maximum number of idle connections to keep alive.", @@ -349,345 +444,555 @@ "privacy": "Public", "value": 3 }, - "components.gateway.remote_client_config.socket": { - "description": "The remote component server socket.", + "components.gateway.remote_client_config.retry_interval": { + "description": "The duration in seconds to wait between remote connection retries.", "privacy": "Public", - "value": "0.0.0.0:8080" - }, - "components.gateway.remote_server_config.#is_none": { - "description": "Flag for an optional field.", - "privacy": "TemporaryValue", - "value": true + "value": 3 }, - "components.gateway.remote_server_config.socket": { - "description": "The remote component server socket.", + "components.gateway.url": { + "description": "URL of the remote component server.", "privacy": "Public", - "value": "0.0.0.0:8080" + "value": "localhost" }, "components.http_server.execution_mode": { "description": "The component execution mode.", "privacy": "Public", - "value": "LocalExecutionWithRemoteEnabled" + "value": "Enabled" }, - "components.http_server.local_server_config.#is_none": { - "description": "Flag for an optional field.", - "privacy": "TemporaryValue", - "value": false + "components.l1_gas_price_provider.execution_mode": { + "description": "The component execution mode.", + "privacy": "Public", + "value": "LocalExecutionWithRemoteDisabled" }, - "components.http_server.local_server_config.channel_buffer_size": { + "components.l1_gas_price_provider.ip": { + "description": "Binding address of the remote component server.", + "privacy": "Public", + "value": "0.0.0.0" + }, + "components.l1_gas_price_provider.local_server_config.channel_buffer_size": { "description": "The communication channel buffer size.", "privacy": "Public", "value": 32 }, - "components.http_server.remote_client_config.#is_none": { - "description": "Flag for an optional field.", - "privacy": "TemporaryValue", - "value": true + "components.l1_gas_price_provider.max_concurrency": { + "description": "The maximum number of concurrent requests handling.", + "privacy": "Public", + "value": 10 + }, + "components.l1_gas_price_provider.port": { + "description": "Listening port of the remote component server.", + "privacy": "Public", + "value": 0 }, - "components.http_server.remote_client_config.idle_connections": { + "components.l1_gas_price_provider.remote_client_config.idle_connections": { "description": "The maximum number of idle connections to keep alive.", "privacy": "Public", "value": 18446744073709551615 }, - "components.http_server.remote_client_config.idle_timeout": { + "components.l1_gas_price_provider.remote_client_config.idle_timeout": { "description": "The duration in seconds to keep an idle connection open before closing.", "privacy": "Public", "value": 90 }, - "components.http_server.remote_client_config.retries": { + "components.l1_gas_price_provider.remote_client_config.retries": { "description": "The max number of retries for sending a message.", "privacy": "Public", "value": 3 }, - "components.http_server.remote_client_config.socket": { - "description": "The remote component server socket.", + "components.l1_gas_price_provider.remote_client_config.retry_interval": { + "description": "The duration in seconds to wait between remote connection retries.", "privacy": "Public", - "value": "0.0.0.0:8080" + "value": 3 }, - "components.http_server.remote_server_config.#is_none": { - "description": "Flag for an optional field.", - "privacy": "TemporaryValue", - "value": false + "components.l1_gas_price_provider.url": { + "description": "URL of the remote component server.", + "privacy": "Public", + "value": "localhost" }, - "components.http_server.remote_server_config.socket": { - "description": "The remote component server socket.", + "components.l1_gas_price_scraper.execution_mode": { + "description": "The component execution mode.", "privacy": "Public", - "value": "0.0.0.0:8080" + "value": "Enabled" }, - "components.mempool.execution_mode": { + "components.l1_provider.execution_mode": { "description": "The component execution mode.", "privacy": "Public", "value": "LocalExecutionWithRemoteDisabled" }, - "components.mempool.local_server_config.#is_none": { - "description": "Flag for an optional field.", - "privacy": "TemporaryValue", - "value": false + "components.l1_provider.ip": { + "description": "Binding address of the remote component server.", + "privacy": "Public", + "value": "0.0.0.0" }, - "components.mempool.local_server_config.channel_buffer_size": { + "components.l1_provider.local_server_config.channel_buffer_size": { "description": "The communication channel buffer size.", "privacy": "Public", "value": 32 }, - "components.mempool.remote_client_config.#is_none": { - "description": "Flag for an optional field.", - "privacy": "TemporaryValue", - "value": true + "components.l1_provider.max_concurrency": { + "description": "The maximum number of concurrent requests handling.", + "privacy": "Public", + "value": 10 }, - "components.mempool.remote_client_config.idle_connections": { + "components.l1_provider.port": { + "description": "Listening port of the remote component server.", + "privacy": "Public", + "value": 0 + }, + "components.l1_provider.remote_client_config.idle_connections": { "description": "The maximum number of idle connections to keep alive.", "privacy": "Public", "value": 18446744073709551615 }, - "components.mempool.remote_client_config.idle_timeout": { + "components.l1_provider.remote_client_config.idle_timeout": { "description": "The duration in seconds to keep an idle connection open before closing.", "privacy": "Public", "value": 90 }, - "components.mempool.remote_client_config.retries": { + "components.l1_provider.remote_client_config.retries": { "description": "The max number of retries for sending a message.", "privacy": "Public", "value": 3 }, - "components.mempool.remote_client_config.socket": { - "description": "The remote component server socket.", + "components.l1_provider.remote_client_config.retry_interval": { + "description": "The duration in seconds to wait between remote connection retries.", "privacy": "Public", - "value": "0.0.0.0:8080" + "value": 3 }, - "components.mempool.remote_server_config.#is_none": { - "description": "Flag for an optional field.", - "privacy": "TemporaryValue", - "value": true + "components.l1_provider.url": { + "description": "URL of the remote component server.", + "privacy": "Public", + "value": "localhost" }, - "components.mempool.remote_server_config.socket": { - "description": "The remote component server socket.", + "components.l1_scraper.execution_mode": { + "description": "The component execution mode.", "privacy": "Public", - "value": "0.0.0.0:8080" + "value": "Enabled" }, - "components.mempool_p2p.execution_mode": { + "components.mempool.execution_mode": { "description": "The component execution mode.", "privacy": "Public", "value": "LocalExecutionWithRemoteDisabled" }, - "components.mempool_p2p.local_server_config.#is_none": { - "description": "Flag for an optional field.", - "privacy": "TemporaryValue", - "value": false + "components.mempool.ip": { + "description": "Binding address of the remote component server.", + "privacy": "Public", + "value": "0.0.0.0" }, - "components.mempool_p2p.local_server_config.channel_buffer_size": { + "components.mempool.local_server_config.channel_buffer_size": { "description": "The communication channel buffer size.", "privacy": "Public", "value": 32 }, - "components.mempool_p2p.remote_client_config.#is_none": { - "description": "Flag for an optional field.", - "privacy": "TemporaryValue", - "value": true + "components.mempool.max_concurrency": { + "description": "The maximum number of concurrent requests handling.", + "privacy": "Public", + "value": 10 }, - "components.mempool_p2p.remote_client_config.idle_connections": { + "components.mempool.port": { + "description": "Listening port of the remote component server.", + "privacy": "Public", + "value": 0 + }, + "components.mempool.remote_client_config.idle_connections": { "description": "The maximum number of idle connections to keep alive.", "privacy": "Public", "value": 18446744073709551615 }, - "components.mempool_p2p.remote_client_config.idle_timeout": { + "components.mempool.remote_client_config.idle_timeout": { "description": "The duration in seconds to keep an idle connection open before closing.", "privacy": "Public", "value": 90 }, - "components.mempool_p2p.remote_client_config.retries": { + "components.mempool.remote_client_config.retries": { "description": "The max number of retries for sending a message.", "privacy": "Public", "value": 3 }, - "components.mempool_p2p.remote_client_config.socket": { - "description": "The remote component server socket.", + "components.mempool.remote_client_config.retry_interval": { + "description": "The duration in seconds to wait between remote connection retries.", "privacy": "Public", - "value": "0.0.0.0:8080" - }, - "components.mempool_p2p.remote_server_config.#is_none": { - "description": "Flag for an optional field.", - "privacy": "TemporaryValue", - "value": true + "value": 3 }, - "components.mempool_p2p.remote_server_config.socket": { - "description": "The remote component server socket.", + "components.mempool.url": { + "description": "URL of the remote component server.", "privacy": "Public", - "value": "0.0.0.0:8080" + "value": "localhost" }, - "components.monitoring_endpoint.execution_mode": { + "components.mempool_p2p.execution_mode": { "description": "The component execution mode.", "privacy": "Public", - "value": "LocalExecutionWithRemoteEnabled" + "value": "LocalExecutionWithRemoteDisabled" }, - "components.monitoring_endpoint.local_server_config.#is_none": { - "description": "Flag for an optional field.", - "privacy": "TemporaryValue", - "value": false + "components.mempool_p2p.ip": { + "description": "Binding address of the remote component server.", + "privacy": "Public", + "value": "0.0.0.0" }, - "components.monitoring_endpoint.local_server_config.channel_buffer_size": { + "components.mempool_p2p.local_server_config.channel_buffer_size": { "description": "The communication channel buffer size.", "privacy": "Public", "value": 32 }, - "components.monitoring_endpoint.remote_client_config.#is_none": { - "description": "Flag for an optional field.", - "privacy": "TemporaryValue", - "value": true + "components.mempool_p2p.max_concurrency": { + "description": "The maximum number of concurrent requests handling.", + "privacy": "Public", + "value": 10 + }, + "components.mempool_p2p.port": { + "description": "Listening port of the remote component server.", + "privacy": "Public", + "value": 0 }, - "components.monitoring_endpoint.remote_client_config.idle_connections": { + "components.mempool_p2p.remote_client_config.idle_connections": { "description": "The maximum number of idle connections to keep alive.", "privacy": "Public", "value": 18446744073709551615 }, - "components.monitoring_endpoint.remote_client_config.idle_timeout": { + "components.mempool_p2p.remote_client_config.idle_timeout": { "description": "The duration in seconds to keep an idle connection open before closing.", "privacy": "Public", "value": 90 }, - "components.monitoring_endpoint.remote_client_config.retries": { + "components.mempool_p2p.remote_client_config.retries": { "description": "The max number of retries for sending a message.", "privacy": "Public", "value": 3 }, - "components.monitoring_endpoint.remote_client_config.socket": { - "description": "The remote component server socket.", + "components.mempool_p2p.remote_client_config.retry_interval": { + "description": "The duration in seconds to wait between remote connection retries.", "privacy": "Public", - "value": "0.0.0.0:8080" + "value": 3 }, - "components.monitoring_endpoint.remote_server_config.#is_none": { - "description": "Flag for an optional field.", - "privacy": "TemporaryValue", - "value": false + "components.mempool_p2p.url": { + "description": "URL of the remote component server.", + "privacy": "Public", + "value": "localhost" }, - "components.monitoring_endpoint.remote_server_config.socket": { - "description": "The remote component server socket.", + "components.monitoring_endpoint.execution_mode": { + "description": "The component execution mode.", "privacy": "Public", - "value": "0.0.0.0:8080" + "value": "Enabled" }, - "consensus_manager_config.consensus_config.consensus_delay": { - "description": "Delay (seconds) before starting consensus to give time for network peering.", + "components.sierra_compiler.execution_mode": { + "description": "The component execution mode.", "privacy": "Public", - "value": 5 + "value": "LocalExecutionWithRemoteDisabled" }, - "consensus_manager_config.consensus_config.network_config.advertised_multiaddr": { - "description": "The external address other peers see this node. If this is set, the node will not try to find out which addresses it has and will write this address as external instead", + "components.sierra_compiler.ip": { + "description": "Binding address of the remote component server.", "privacy": "Public", - "value": "" + "value": "0.0.0.0" }, - "consensus_manager_config.consensus_config.network_config.advertised_multiaddr.#is_none": { - "description": "Flag for an optional field.", + "components.sierra_compiler.local_server_config.channel_buffer_size": { + "description": "The communication channel buffer size.", + "privacy": "Public", + "value": 32 + }, + "components.sierra_compiler.max_concurrency": { + "description": "The maximum number of concurrent requests handling.", + "privacy": "Public", + "value": 10 + }, + "components.sierra_compiler.port": { + "description": "Listening port of the remote component server.", + "privacy": "Public", + "value": 0 + }, + "components.sierra_compiler.remote_client_config.idle_connections": { + "description": "The maximum number of idle connections to keep alive.", + "privacy": "Public", + "value": 18446744073709551615 + }, + "components.sierra_compiler.remote_client_config.idle_timeout": { + "description": "The duration in seconds to keep an idle connection open before closing.", + "privacy": "Public", + "value": 90 + }, + "components.sierra_compiler.remote_client_config.retries": { + "description": "The max number of retries for sending a message.", + "privacy": "Public", + "value": 3 + }, + "components.sierra_compiler.remote_client_config.retry_interval": { + "description": "The duration in seconds to wait between remote connection retries.", + "privacy": "Public", + "value": 3 + }, + "components.sierra_compiler.url": { + "description": "URL of the remote component server.", + "privacy": "Public", + "value": "localhost" + }, + "components.state_sync.execution_mode": { + "description": "The component execution mode.", + "privacy": "Public", + "value": "LocalExecutionWithRemoteDisabled" + }, + "components.state_sync.ip": { + "description": "Binding address of the remote component server.", + "privacy": "Public", + "value": "0.0.0.0" + }, + "components.state_sync.local_server_config.channel_buffer_size": { + "description": "The communication channel buffer size.", + "privacy": "Public", + "value": 32 + }, + "components.state_sync.max_concurrency": { + "description": "The maximum number of concurrent requests handling.", + "privacy": "Public", + "value": 10 + }, + "components.state_sync.port": { + "description": "Listening port of the remote component server.", + "privacy": "Public", + "value": 0 + }, + "components.state_sync.remote_client_config.idle_connections": { + "description": "The maximum number of idle connections to keep alive.", + "privacy": "Public", + "value": 18446744073709551615 + }, + "components.state_sync.remote_client_config.idle_timeout": { + "description": "The duration in seconds to keep an idle connection open before closing.", + "privacy": "Public", + "value": 90 + }, + "components.state_sync.remote_client_config.retries": { + "description": "The max number of retries for sending a message.", + "privacy": "Public", + "value": 3 + }, + "components.state_sync.remote_client_config.retry_interval": { + "description": "The duration in seconds to wait between remote connection retries.", + "privacy": "Public", + "value": 3 + }, + "components.state_sync.url": { + "description": "URL of the remote component server.", + "privacy": "Public", + "value": "localhost" + }, + "consensus_manager_config.broadcast_buffer_size": { + "description": "The buffer size for the broadcast channel.", + "privacy": "Public", + "value": 10000 + }, + "consensus_manager_config.cende_config.recorder_url": { + "description": "The URL of the Pythonic cende_recorder", + "pointer_target": "recorder_url", + "privacy": "Private" + }, + "consensus_manager_config.cende_config.skip_write_height": { + "description": "A height that the consensus can skip writing to Aerospike. Needed for booting up (no previous height blob to write) or to handle extreme cases (all the nodes failed).", + "privacy": "Private", + "value": 0 + }, + "consensus_manager_config.cende_config.skip_write_height.#is_none": { + "description": "Flag for an optional field.", "privacy": "TemporaryValue", "value": true }, - "consensus_manager_config.consensus_config.network_config.bootstrap_peer_multiaddr": { + "consensus_manager_config.consensus_config.future_height_limit": { + "description": "How many heights in the future should we cache.", + "privacy": "Public", + "value": 10 + }, + "consensus_manager_config.consensus_config.future_height_round_limit": { + "description": "How many rounds should we cache for future heights.", + "privacy": "Public", + "value": 1 + }, + "consensus_manager_config.consensus_config.future_round_limit": { + "description": "How many rounds in the future (for current height) should we cache.", + "privacy": "Public", + "value": 10 + }, + "consensus_manager_config.consensus_config.startup_delay": { + "description": "Delay (seconds) before starting consensus to give time for network peering.", + "privacy": "Public", + "value": 5 + }, + "consensus_manager_config.consensus_config.sync_retry_interval": { + "description": "The duration (seconds) between sync attempts.", + "privacy": "Public", + "value": 1.0 + }, + "consensus_manager_config.consensus_config.timeouts.precommit_timeout": { + "description": "The timeout (seconds) for a precommit.", + "privacy": "Public", + "value": 1.0 + }, + "consensus_manager_config.consensus_config.timeouts.prevote_timeout": { + "description": "The timeout (seconds) for a prevote.", + "privacy": "Public", + "value": 1.0 + }, + "consensus_manager_config.consensus_config.timeouts.proposal_timeout": { + "description": "The timeout (seconds) for a proposal.", + "privacy": "Public", + "value": 3.0 + }, + "consensus_manager_config.consensus_config.validator_id": { + "description": "The validator id of the node.", + "pointer_target": "validator_id", + "privacy": "Public" + }, + "consensus_manager_config.context_config.block_timestamp_window": { + "description": "Maximum allowed deviation (seconds) of a proposed block's timestamp from the current time.", + "privacy": "Public", + "value": 1 + }, + "consensus_manager_config.context_config.build_proposal_margin": { + "description": "Safety margin (in ms) to make sure that the batcher completes building the proposal with enough time for the Fin to be checked by validators.", + "privacy": "Public", + "value": 1000 + }, + "consensus_manager_config.context_config.builder_address": { + "description": "The address of the contract that builds the block.", + "privacy": "Public", + "value": "0x0" + }, + "consensus_manager_config.context_config.chain_id": { + "description": "The chain id of the Starknet chain.", + "pointer_target": "chain_id", + "privacy": "Public" + }, + "consensus_manager_config.context_config.l1_da_mode": { + "description": "The data availability mode, true: Blob, false: Calldata.", + "privacy": "Public", + "value": true + }, + "consensus_manager_config.context_config.num_validators": { + "description": "The number of validators.", + "privacy": "Public", + "value": 1 + }, + "consensus_manager_config.context_config.proposal_buffer_size": { + "description": "The buffer size for streaming outbound proposals.", + "privacy": "Public", + "value": 100 + }, + "consensus_manager_config.context_config.validate_proposal_margin": { + "description": "Safety margin (in ms) to make sure that consensus determines when to timeout validating a proposal.", + "privacy": "Public", + "value": 10000 + }, + "consensus_manager_config.eth_to_strk_oracle_config.base_url": { + "description": "URL to query. This must end with the query parameter `timestamp=` as we append a UNIX timestamp.", + "privacy": "Private", + "value": "https://example.com/api?timestamp=" + }, + "consensus_manager_config.eth_to_strk_oracle_config.headers": { + "description": "HTTP headers for the eth to strk oracle, formatted as 'k1:v1 k2:v2 ...'.", + "privacy": "Private", + "value": "" + }, + "consensus_manager_config.immediate_active_height": { + "description": "The height at which the node may actively participate in consensus.", + "privacy": "Public", + "value": 0 + }, + "consensus_manager_config.network_config.advertised_multiaddr": { + "description": "The external address other peers see this node. If this is set, the node will not try to find out which addresses it has and will write this address as external instead", + "privacy": "Public", + "value": "" + }, + "consensus_manager_config.network_config.advertised_multiaddr.#is_none": { + "description": "Flag for an optional field.", + "privacy": "TemporaryValue", + "value": true + }, + "consensus_manager_config.network_config.bootstrap_peer_multiaddr": { "description": "The multiaddress of the peer node. It should include the peer's id. For more info: https://docs.libp2p.io/concepts/fundamentals/peers/", "privacy": "Public", "value": "" }, - "consensus_manager_config.consensus_config.network_config.bootstrap_peer_multiaddr.#is_none": { + "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": { "description": "Flag for an optional field.", "privacy": "TemporaryValue", "value": true }, - "consensus_manager_config.consensus_config.network_config.chain_id": { + "consensus_manager_config.network_config.chain_id": { "description": "The chain to follow. For more details see https://docs.starknet.io/documentation/architecture_and_concepts/Blocks/transactions/#chain-id.", "pointer_target": "chain_id", "privacy": "Public" }, - "consensus_manager_config.consensus_config.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": { + "consensus_manager_config.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": { "description": "The base delay in milliseconds for the exponential backoff strategy.", "privacy": "Public", "value": 2 }, - "consensus_manager_config.consensus_config.network_config.discovery_config.bootstrap_dial_retry_config.factor": { + "consensus_manager_config.network_config.discovery_config.bootstrap_dial_retry_config.factor": { "description": "The factor for the exponential backoff strategy.", "privacy": "Public", "value": 5 }, - "consensus_manager_config.consensus_config.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": { + "consensus_manager_config.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": { "description": "The maximum delay in seconds for the exponential backoff strategy.", "privacy": "Public", "value": 5 }, - "consensus_manager_config.consensus_config.network_config.discovery_config.heartbeat_interval": { + "consensus_manager_config.network_config.discovery_config.heartbeat_interval": { "description": "The interval between each discovery (Kademlia) query in milliseconds.", "privacy": "Public", "value": 100 }, - "consensus_manager_config.consensus_config.network_config.idle_connection_timeout": { + "consensus_manager_config.network_config.idle_connection_timeout": { "description": "Amount of time in seconds that a connection with no active sessions will stay alive.", "privacy": "Public", "value": 120 }, - "consensus_manager_config.consensus_config.network_config.peer_manager_config.malicious_timeout_seconds": { + "consensus_manager_config.network_config.peer_manager_config.malicious_timeout_seconds": { "description": "The duration in seconds a peer is blacklisted after being marked as malicious.", "privacy": "Public", - "value": 31536000 + "value": 1 }, - "consensus_manager_config.consensus_config.network_config.peer_manager_config.unstable_timeout_millis": { + "consensus_manager_config.network_config.peer_manager_config.unstable_timeout_millis": { "description": "The duration in milliseconds a peer blacklisted after being reported as unstable.", "privacy": "Public", "value": 1000 }, - "consensus_manager_config.consensus_config.network_config.quic_port": { - "description": "The port that the node listens on for incoming quic connections.", + "consensus_manager_config.network_config.port": { + "description": "The port that the node listens on for incoming tcp connections.", "privacy": "Public", - "value": 10101 + "value": 10000 }, - "consensus_manager_config.consensus_config.network_config.secret_key": { + "consensus_manager_config.network_config.secret_key": { "description": "The secret key used for building the peer id. If it's an empty string a random one will be used.", "privacy": "Private", "value": "" }, - "consensus_manager_config.consensus_config.network_config.session_timeout": { + "consensus_manager_config.network_config.session_timeout": { "description": "Maximal time in seconds that each session can take before failing on timeout.", "privacy": "Public", "value": 120 }, - "consensus_manager_config.consensus_config.network_config.tcp_port": { - "description": "The port that the node listens on for incoming tcp connections.", - "privacy": "Public", - "value": 10100 - }, - "consensus_manager_config.consensus_config.network_topic": { - "description": "The network topic of the consensus.", - "privacy": "Public", - "value": "consensus" - }, - "consensus_manager_config.consensus_config.num_validators": { - "description": "The number of validators in the consensus.", + "consensus_manager_config.proposals_topic": { + "description": "The topic for consensus proposals.", "privacy": "Public", - "value": 1 + "value": "consensus_proposals" }, - "consensus_manager_config.consensus_config.start_height": { - "description": "The height to start the consensus from.", - "privacy": "Public", - "value": 0 - }, - "consensus_manager_config.consensus_config.timeouts.precommit_timeout": { - "description": "The timeout (seconds) for a precommit.", - "privacy": "Public", - "value": 1.0 + "consensus_manager_config.revert_config.revert_up_to_and_including": { + "description": "The component will revert blocks up to this block number (including).", + "pointer_target": "revert_config.revert_up_to_and_including", + "privacy": "Public" }, - "consensus_manager_config.consensus_config.timeouts.prevote_timeout": { - "description": "The timeout (seconds) for a prevote.", - "privacy": "Public", - "value": 1.0 + "consensus_manager_config.revert_config.should_revert": { + "description": "If set true, the component would revert blocks and do nothing else.", + "pointer_target": "revert_config.should_revert", + "privacy": "Public" }, - "consensus_manager_config.consensus_config.timeouts.proposal_timeout": { - "description": "The timeout (seconds) for a proposal.", + "consensus_manager_config.votes_topic": { + "description": "The topic for consensus votes.", "privacy": "Public", - "value": 3.0 - }, - "consensus_manager_config.consensus_config.validator_id": { - "description": "The validator id of the node.", - "privacy": "Public", - "value": "0x0" + "value": "consensus_votes" }, "eth_fee_token_address": { - "description": "A required param! Address of the ETH fee token.", - "param_type": "String", - "privacy": "TemporaryValue" + "description": "Address of the ETH fee token.", + "privacy": "TemporaryValue", + "value": "PointerTarget" }, "gateway_config.chain_info.chain_id": { "description": "The chain ID of the StarkNet chain.", @@ -704,6 +1009,11 @@ "pointer_target": "strk_fee_token_address", "privacy": "Public" }, + "gateway_config.stateful_tx_validator_config.max_allowed_nonce_gap": { + "description": "The maximum allowed gap between the account nonce and the transaction nonce.", + "privacy": "Public", + "value": 50 + }, "gateway_config.stateful_tx_validator_config.max_nonce_for_validation_skip": { "description": "Maximum nonce for which the validation is skipped.", "privacy": "Public", @@ -714,6 +1024,11 @@ "pointer_target": "versioned_constants_overrides.invoke_tx_max_n_steps", "privacy": "Public" }, + "gateway_config.stateful_tx_validator_config.versioned_constants_overrides.max_n_events": { + "description": "Maximum number of events that can be emitted from the transation.", + "pointer_target": "versioned_constants_overrides.max_n_events", + "privacy": "Public" + }, "gateway_config.stateful_tx_validator_config.versioned_constants_overrides.max_recursion_depth": { "description": "Maximum recursion depth for nested calls during blockifier validation.", "pointer_target": "versioned_constants_overrides.max_recursion_depth", @@ -794,6 +1109,126 @@ "privacy": "Public", "value": 8080 }, + "l1_gas_price_provider_config.lag_margin_seconds": { + "description": "Difference between the time of the block from L1 used to calculate the gas price and the time of the L2 block this price is used in", + "privacy": "Public", + "value": 60 + }, + "l1_gas_price_provider_config.number_of_blocks_for_mean": { + "description": "Number of blocks to use for the mean gas price calculation", + "privacy": "Public", + "value": 300 + }, + "l1_gas_price_provider_config.storage_limit": { + "description": "Maximum number of L1 blocks to keep cached", + "privacy": "Public", + "value": 3000 + }, + "l1_gas_price_scraper_config.chain_id": { + "description": "The chain to follow. For more details see https://docs.starknet.io/documentation/architecture_and_concepts/Blocks/transactions/#chain-id", + "pointer_target": "chain_id", + "privacy": "Public" + }, + "l1_gas_price_scraper_config.finality": { + "description": "Number of blocks to wait for finality in L1", + "privacy": "Public", + "value": 0 + }, + "l1_gas_price_scraper_config.number_of_blocks_for_mean": { + "description": "Number of blocks to use for the mean gas price calculation", + "privacy": "Public", + "value": 300 + }, + "l1_gas_price_scraper_config.polling_interval": { + "description": "The duration (seconds) between each scraping attempt of L1", + "privacy": "Public", + "value": 1 + }, + "l1_gas_price_scraper_config.starting_block": { + "description": "Starting block to scrape from", + "privacy": "Public", + "value": 0 + }, + "l1_gas_price_scraper_config.starting_block.#is_none": { + "description": "Flag for an optional field.", + "privacy": "TemporaryValue", + "value": true + }, + "l1_provider_config.bootstrap_catch_up_height_override": { + "description": "Override height at which the provider should catch up to the bootstrapper.", + "privacy": "Public", + "value": 0 + }, + "l1_provider_config.bootstrap_catch_up_height_override.#is_none": { + "description": "Flag for an optional field.", + "privacy": "TemporaryValue", + "value": true + }, + "l1_provider_config.provider_startup_height_override": { + "description": "Override height at which the provider should start", + "privacy": "Public", + "value": 0 + }, + "l1_provider_config.provider_startup_height_override.#is_none": { + "description": "Flag for an optional field.", + "privacy": "TemporaryValue", + "value": true + }, + "l1_provider_config.startup_sync_sleep_retry_interval": { + "description": "Interval in seconds between each retry of syncing with L2 during startup.", + "privacy": "Public", + "value": 0.0 + }, + "l1_scraper_config.chain_id": { + "description": "The chain to follow. For more details see https://docs.starknet.io/documentation/architecture_and_concepts/Blocks/transactions/#chain-id.", + "pointer_target": "chain_id", + "privacy": "Public" + }, + "l1_scraper_config.finality": { + "description": "Number of blocks to wait for finality", + "privacy": "Public", + "value": 0 + }, + "l1_scraper_config.polling_interval": { + "description": "Interval in Seconds between each scraping attempt of L1.", + "privacy": "Public", + "value": 1 + }, + "l1_scraper_config.startup_rewind_time": { + "description": "Duration to rewind from latest L1 block when starting scraping.", + "privacy": "Public", + "value": 0 + }, + "mempool_config.committed_nonce_retention_block_count": { + "description": "Number of latest committed blocks for which committed account nonces are retained.", + "privacy": "Public", + "value": 100 + }, + "mempool_config.declare_delay": { + "description": "Time to wait before allowing a Declare transaction to be returned, in seconds.", + "privacy": "Public", + "value": 1 + }, + "mempool_config.enable_fee_escalation": { + "description": "If true, transactions can be replaced with higher fee transactions.", + "privacy": "Public", + "value": true + }, + "mempool_config.fee_escalation_percentage": { + "description": "Percentage increase for tip and max gas price to enable transaction replacement.", + "privacy": "Public", + "value": 10 + }, + "mempool_config.transaction_ttl": { + "description": "Time-to-live for transactions in the mempool, in seconds.", + "privacy": "Public", + "value": 60 + }, + "mempool_p2p_config.max_transaction_batch_size": { + "description": "Maximum number of transactions in each batch.", + "privacy": "Public", + "value": 1 + }, "mempool_p2p_config.network_buffer_size": { "description": "Network buffer size.", "privacy": "Public", @@ -852,17 +1287,17 @@ "mempool_p2p_config.network_config.peer_manager_config.malicious_timeout_seconds": { "description": "The duration in seconds a peer is blacklisted after being marked as malicious.", "privacy": "Public", - "value": 31536000 + "value": 1 }, "mempool_p2p_config.network_config.peer_manager_config.unstable_timeout_millis": { "description": "The duration in milliseconds a peer blacklisted after being reported as unstable.", "privacy": "Public", "value": 1000 }, - "mempool_p2p_config.network_config.quic_port": { - "description": "The port that the node listens on for incoming quic connections.", + "mempool_p2p_config.network_config.port": { + "description": "The port that the node listens on for incoming tcp connections.", "privacy": "Public", - "value": 10001 + "value": 11111 }, "mempool_p2p_config.network_config.secret_key": { "description": "The secret key used for building the peer id. If it's an empty string a random one will be used.", @@ -874,10 +1309,30 @@ "privacy": "Public", "value": 120 }, - "mempool_p2p_config.network_config.tcp_port": { - "description": "The port that the node listens on for incoming tcp connections.", + "mempool_p2p_config.transaction_batch_rate_millis": { + "description": "Maximum time until a transaction batch is closed and propagated in milliseconds.", "privacy": "Public", - "value": 10000 + "value": 1000 + }, + "monitoring_config.collect_metrics": { + "description": "Indicating if metrics should be recorded.", + "privacy": "Public", + "value": true + }, + "monitoring_config.collect_profiling_metrics": { + "description": "Indicating if profiling metrics should be collected.", + "privacy": "Public", + "value": true + }, + "monitoring_endpoint_config.collect_metrics": { + "description": "If true, collect and return metrics in the monitoring endpoint.", + "privacy": "Public", + "value": true + }, + "monitoring_endpoint_config.collect_profiling_metrics": { + "description": "If true, collect and return profiling metrics in the monitoring endpoint.", + "privacy": "Public", + "value": true }, "monitoring_endpoint_config.ip": { "description": "The monitoring endpoint ip address.", @@ -889,31 +1344,311 @@ "privacy": "Public", "value": 8082 }, - "rpc_state_reader_config.json_rpc_version": { - "description": "The json rpc version.", + "recorder_url": { + "description": "The URL of the Pythonic cende_recorder", + "privacy": "TemporaryValue", + "value": "PointerTarget" + }, + "revert_config.revert_up_to_and_including": { + "description": "The component will revert blocks up to this block number (including).", + "privacy": "TemporaryValue", + "value": 18446744073709551615 + }, + "revert_config.should_revert": { + "description": "If set true, the component would revert blocks and do nothing else.", + "privacy": "TemporaryValue", + "value": false + }, + "state_sync_config.central_sync_client_config.#is_none": { + "description": "Flag for an optional field.", + "privacy": "TemporaryValue", + "value": true + }, + "state_sync_config.central_sync_client_config.central_source_config.class_cache_size": { + "description": "Size of class cache, must be a positive integer.", "privacy": "Public", + "value": 100 + }, + "state_sync_config.central_sync_client_config.central_source_config.concurrent_requests": { + "description": "Maximum number of concurrent requests to Starknet feeder-gateway for getting a type of data (for example, blocks).", + "privacy": "Public", + "value": 10 + }, + "state_sync_config.central_sync_client_config.central_source_config.http_headers": { + "description": "'k1:v1 k2:v2 ...' headers for SN-client.", + "privacy": "Private", "value": "" }, - "rpc_state_reader_config.url": { - "description": "The url of the rpc server.", + "state_sync_config.central_sync_client_config.central_source_config.max_classes_to_download": { + "description": "Maximum number of classes to download at a given time.", + "privacy": "Public", + "value": 20 + }, + "state_sync_config.central_sync_client_config.central_source_config.max_state_updates_to_download": { + "description": "Maximum number of state updates to download at a given time.", + "privacy": "Public", + "value": 20 + }, + "state_sync_config.central_sync_client_config.central_source_config.max_state_updates_to_store_in_memory": { + "description": "Maximum number of state updates to store in memory at a given time.", + "privacy": "Public", + "value": 20 + }, + "state_sync_config.central_sync_client_config.central_source_config.retry_config.max_retries": { + "description": "Maximum number of retries before the node stops retrying.", + "privacy": "Public", + "value": 10 + }, + "state_sync_config.central_sync_client_config.central_source_config.retry_config.retry_base_millis": { + "description": "Base waiting time after a failed request. After that, the time increases exponentially.", + "privacy": "Public", + "value": 30 + }, + "state_sync_config.central_sync_client_config.central_source_config.retry_config.retry_max_delay_millis": { + "description": "Max waiting time after a failed request.", + "privacy": "Public", + "value": 30000 + }, + "state_sync_config.central_sync_client_config.central_source_config.starknet_url": { + "description": "Starknet feeder-gateway URL. It should match chain_id.", + "privacy": "Public", + "value": "https://alpha-mainnet.starknet.io/" + }, + "state_sync_config.central_sync_client_config.sync_config.base_layer_propagation_sleep_duration": { + "description": "Time in seconds to poll the base layer to get the latest proved block.", + "privacy": "Public", + "value": 10 + }, + "state_sync_config.central_sync_client_config.sync_config.block_propagation_sleep_duration": { + "description": "Time in seconds before checking for a new block after the node is synchronized.", + "privacy": "Public", + "value": 2 + }, + "state_sync_config.central_sync_client_config.sync_config.blocks_max_stream_size": { + "description": "Max amount of blocks to download in a stream.", + "privacy": "Public", + "value": 1000 + }, + "state_sync_config.central_sync_client_config.sync_config.collect_pending_data": { + "description": "Whether to collect data on pending blocks.", + "privacy": "Public", + "value": false + }, + "state_sync_config.central_sync_client_config.sync_config.recoverable_error_sleep_duration": { + "description": "Waiting time in seconds before restarting synchronization after a recoverable error.", + "privacy": "Public", + "value": 3 + }, + "state_sync_config.central_sync_client_config.sync_config.state_updates_max_stream_size": { + "description": "Max amount of state updates to download in a stream.", + "privacy": "Public", + "value": 1000 + }, + "state_sync_config.central_sync_client_config.sync_config.store_sierras_and_casms": { + "description": "Whether to store sierras and casms to the storage. This allows maintaining backward-compatibility with native-blockifier", + "privacy": "Public", + "value": false + }, + "state_sync_config.central_sync_client_config.sync_config.verify_blocks": { + "description": "Whether to verify incoming blocks.", + "privacy": "Public", + "value": true + }, + "state_sync_config.network_config.advertised_multiaddr": { + "description": "The external address other peers see this node. If this is set, the node will not try to find out which addresses it has and will write this address as external instead", + "privacy": "Public", + "value": "" + }, + "state_sync_config.network_config.advertised_multiaddr.#is_none": { + "description": "Flag for an optional field.", + "privacy": "TemporaryValue", + "value": true + }, + "state_sync_config.network_config.bootstrap_peer_multiaddr": { + "description": "The multiaddress of the peer node. It should include the peer's id. For more info: https://docs.libp2p.io/concepts/fundamentals/peers/", + "privacy": "Public", + "value": "" + }, + "state_sync_config.network_config.bootstrap_peer_multiaddr.#is_none": { + "description": "Flag for an optional field.", + "privacy": "TemporaryValue", + "value": true + }, + "state_sync_config.network_config.chain_id": { + "description": "The chain to follow. For more details see https://docs.starknet.io/documentation/architecture_and_concepts/Blocks/transactions/#chain-id.", + "pointer_target": "chain_id", + "privacy": "Public" + }, + "state_sync_config.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": { + "description": "The base delay in milliseconds for the exponential backoff strategy.", + "privacy": "Public", + "value": 2 + }, + "state_sync_config.network_config.discovery_config.bootstrap_dial_retry_config.factor": { + "description": "The factor for the exponential backoff strategy.", + "privacy": "Public", + "value": 5 + }, + "state_sync_config.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": { + "description": "The maximum delay in seconds for the exponential backoff strategy.", + "privacy": "Public", + "value": 5 + }, + "state_sync_config.network_config.discovery_config.heartbeat_interval": { + "description": "The interval between each discovery (Kademlia) query in milliseconds.", + "privacy": "Public", + "value": 100 + }, + "state_sync_config.network_config.idle_connection_timeout": { + "description": "Amount of time in seconds that a connection with no active sessions will stay alive.", + "privacy": "Public", + "value": 120 + }, + "state_sync_config.network_config.peer_manager_config.malicious_timeout_seconds": { + "description": "The duration in seconds a peer is blacklisted after being marked as malicious.", + "privacy": "Public", + "value": 1 + }, + "state_sync_config.network_config.peer_manager_config.unstable_timeout_millis": { + "description": "The duration in milliseconds a peer blacklisted after being reported as unstable.", + "privacy": "Public", + "value": 1000 + }, + "state_sync_config.network_config.port": { + "description": "The port that the node listens on for incoming tcp connections.", "privacy": "Public", + "value": 12345 + }, + "state_sync_config.network_config.secret_key": { + "description": "The secret key used for building the peer id. If it's an empty string a random one will be used.", + "privacy": "Private", "value": "" }, - "sequencer_address": { - "description": "A required param! The sequencer address.", - "param_type": "String", - "privacy": "TemporaryValue" + "state_sync_config.network_config.session_timeout": { + "description": "Maximal time in seconds that each session can take before failing on timeout.", + "privacy": "Public", + "value": 120 + }, + "state_sync_config.p2p_sync_client_config.#is_none": { + "description": "Flag for an optional field.", + "privacy": "TemporaryValue", + "value": false + }, + "state_sync_config.p2p_sync_client_config.buffer_size": { + "description": "Size of the buffer for read from the storage and for incoming responses.", + "privacy": "Public", + "value": 100000 + }, + "state_sync_config.p2p_sync_client_config.num_block_classes_per_query": { + "description": "The maximum amount of block's classes to ask from peers in each iteration.", + "privacy": "Public", + "value": 100 + }, + "state_sync_config.p2p_sync_client_config.num_block_state_diffs_per_query": { + "description": "The maximum amount of block's state diffs to ask from peers in each iteration.", + "privacy": "Public", + "value": 100 + }, + "state_sync_config.p2p_sync_client_config.num_block_transactions_per_query": { + "description": "The maximum amount of blocks to ask their transactions from peers in each iteration.", + "privacy": "Public", + "value": 100 + }, + "state_sync_config.p2p_sync_client_config.num_headers_per_query": { + "description": "The maximum amount of headers to ask from peers in each iteration.", + "privacy": "Public", + "value": 10000 + }, + "state_sync_config.p2p_sync_client_config.wait_period_for_new_data": { + "description": "Time in millisseconds to wait when a query returned with partial data before sending a new query", + "privacy": "Public", + "value": 50 + }, + "state_sync_config.p2p_sync_client_config.wait_period_for_other_protocol": { + "description": "Time in millisseconds to wait for a dependency protocol to advance (e.g.state diff sync depends on header sync)", + "privacy": "Public", + "value": 50 + }, + "state_sync_config.revert_config.revert_up_to_and_including": { + "description": "The component will revert blocks up to this block number (including).", + "pointer_target": "revert_config.revert_up_to_and_including", + "privacy": "Public" + }, + "state_sync_config.revert_config.should_revert": { + "description": "If set true, the component would revert blocks and do nothing else.", + "pointer_target": "revert_config.should_revert", + "privacy": "Public" + }, + "state_sync_config.storage_config.db_config.chain_id": { + "description": "The chain to follow. For more details see https://docs.starknet.io/documentation/architecture_and_concepts/Blocks/transactions/#chain-id.", + "pointer_target": "chain_id", + "privacy": "Public" + }, + "state_sync_config.storage_config.db_config.enforce_file_exists": { + "description": "Whether to enforce that the path exists. If true, `open_env` fails when the mdbx.dat file does not exist.", + "privacy": "Public", + "value": false + }, + "state_sync_config.storage_config.db_config.growth_step": { + "description": "The growth step in bytes, must be greater than zero to allow the database to grow.", + "privacy": "Public", + "value": 4294967296 + }, + "state_sync_config.storage_config.db_config.max_size": { + "description": "The maximum size of the node's storage in bytes.", + "privacy": "Public", + "value": 1099511627776 + }, + "state_sync_config.storage_config.db_config.min_size": { + "description": "The minimum size of the node's storage in bytes.", + "privacy": "Public", + "value": 1048576 + }, + "state_sync_config.storage_config.db_config.path_prefix": { + "description": "Prefix of the path of the node's storage directory, the storage file path will be /. The path is not created automatically.", + "privacy": "Public", + "value": "/data/state_sync" + }, + "state_sync_config.storage_config.mmap_file_config.growth_step": { + "description": "The growth step in bytes, must be greater than max_object_size.", + "privacy": "Public", + "value": 1073741824 + }, + "state_sync_config.storage_config.mmap_file_config.max_object_size": { + "description": "The maximum size of a single object in the file in bytes", + "privacy": "Public", + "value": 268435456 + }, + "state_sync_config.storage_config.mmap_file_config.max_size": { + "description": "The maximum size of a memory mapped file in bytes. Must be greater than growth_step.", + "privacy": "Public", + "value": 1099511627776 + }, + "state_sync_config.storage_config.scope": { + "description": "The categories of data saved in storage.", + "privacy": "Public", + "value": "FullArchive" }, "strk_fee_token_address": { - "description": "A required param! Address of the STRK fee token.", - "param_type": "String", - "privacy": "TemporaryValue" + "description": "Address of the STRK fee token.", + "privacy": "TemporaryValue", + "value": "PointerTarget" + }, + "validator_id": { + "description": "The ID of the validator. Also the address of this validator as a starknet contract.", + "privacy": "TemporaryValue", + "value": "PointerTarget" }, "versioned_constants_overrides.invoke_tx_max_n_steps": { "description": "Maximum number of steps the invoke function is allowed to run.", "privacy": "TemporaryValue", "value": 10000000 }, + "versioned_constants_overrides.max_n_events": { + "description": "Maximum number of events that can be emitted from the transation.", + "privacy": "TemporaryValue", + "value": 1000 + }, "versioned_constants_overrides.max_recursion_depth": { "description": "Maximum recursion depth for nested calls during blockifier validation.", "privacy": "TemporaryValue", diff --git a/config/sequencer/deployment_configs/testing/nightly_test_all_in_one.json b/config/sequencer/deployment_configs/testing/nightly_test_all_in_one.json new file mode 100644 index 00000000000..a34ef1f8e49 --- /dev/null +++ b/config/sequencer/deployment_configs/testing/nightly_test_all_in_one.json @@ -0,0 +1,15 @@ +{ + "chain_id": "SN_INTEGRATION_SEPOLIA", + "image": "ghcr.io/starkware-libs/sequencer/sequencer:dev", + "application_config_subdir": "config/sequencer/presets/consolidated_node/application_configs/", + "services": [ + { + "name": "Node", + "config_path": "node.json", + "ingress": false, + "autoscale": false, + "replicas": 1, + "storage": 32 + } + ] +} diff --git a/config/sequencer/deployment_configs/testing/nightly_test_distributed_node.json b/config/sequencer/deployment_configs/testing/nightly_test_distributed_node.json new file mode 100644 index 00000000000..81547a63675 --- /dev/null +++ b/config/sequencer/deployment_configs/testing/nightly_test_distributed_node.json @@ -0,0 +1,79 @@ +{ + "chain_id": "SN_INTEGRATION_SEPOLIA", + "image": "ghcr.io/starkware-libs/sequencer/sequencer:dev", + "application_config_subdir": "config/sequencer/presets/distributed_node/application_configs/", + "services": [ + { + "name": "Batcher", + "config_path": "batcher.json", + "ingress": false, + "autoscale": false, + "replicas": 1, + "storage": 32 + }, + { + "name": "ClassManager", + "config_path": "class_manager.json", + "ingress": false, + "autoscale": false, + "replicas": 1, + "storage": 32 + }, + { + "name": "ConsensusManager", + "config_path": "consensus_manager.json", + "ingress": false, + "autoscale": false, + "replicas": 1, + "storage": null + }, + { + "name": "HttpServer", + "config_path": "http_server.json", + "ingress": false, + "autoscale": false, + "replicas": 1, + "storage": null + }, + { + "name": "Gateway", + "config_path": "gateway.json", + "ingress": false, + "autoscale": false, + "replicas": 1, + "storage": null + }, + { + "name": "L1Provider", + "config_path": "l1_provider.json", + "ingress": false, + "autoscale": false, + "replicas": 1, + "storage": null + }, + { + "name": "Mempool", + "config_path": "mempool.json", + "ingress": false, + "autoscale": false, + "replicas": 1, + "storage": null + }, + { + "name": "SierraCompiler", + "config_path": "sierra_compiler.json", + "ingress": false, + "autoscale": false, + "replicas": 1, + "storage": null + }, + { + "name": "StateSync", + "config_path": "state_sync.json", + "ingress": false, + "autoscale": false, + "replicas": 1, + "storage": 32 + } + ] +} diff --git a/config/sequencer/presets/config-batcher.json b/config/sequencer/presets/config-batcher.json deleted file mode 100644 index f2bda320638..00000000000 --- a/config/sequencer/presets/config-batcher.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "chain_id": "0x5", - "eth_fee_token_address": "0x6", - "strk_fee_token_address": "0x7", - "batcher_config.storage.db_config.path_prefix": "/data", - "batcher_config.storage.db_config.enforce_file_exists": false, - "sequencer_address": "0x1" -} diff --git a/config/sequencer/presets/config.json b/config/sequencer/presets/config.json deleted file mode 100644 index 310df1b2091..00000000000 --- a/config/sequencer/presets/config.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "chain_id": "0x5", - "eth_fee_token_address": "0x6", - "strk_fee_token_address": "0x7", - "components.batcher.execution_mode": "Disabled", - "components.batcher.local_server_config.#is_none": true, - "components.consensus_manager.execution_mode": "Disabled", - "components.gateway.execution_mode": "Disabled", - "components.http_server.execution_mode": "Disabled", - "components.mempool.execution_mode": "Disabled", - "components.mempool_p2p.execution_mode": "Disabled", - "components.consensus_manager.local_server_config.#is_none": true, - "components.gateway.local_server_config.#is_none": true, - "components.http_server.local_server_config.#is_none": true, - "components.mempool.local_server_config.#is_none": true, - "components.mempool_p2p.local_server_config.#is_none": true, - "components.http_server.remote_server_config.#is_none": true, - "batcher_config.storage.db_config.enforce_file_exists": false, - "batcher_config.storage.db_config.path_prefix": "/data" -} diff --git a/config/sequencer/presets/consolidated_node/application_configs/node.json b/config/sequencer/presets/consolidated_node/application_configs/node.json new file mode 100644 index 00000000000..d7472690a27 --- /dev/null +++ b/config/sequencer/presets/consolidated_node/application_configs/node.json @@ -0,0 +1,306 @@ +{ + "base_layer_config.node_url": "http://localhost:53260/", + "base_layer_config.starknet_contract_address": "0x5FbDB2315678afecb367f032d93F642f64180aa3", + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.l1_gas": 2500000, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.message_segment_length": 3700, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.n_events": 5000, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.sierra_gas": 30000000, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.state_diff_size": 4000, + "batcher_config.block_builder_config.execute_config.concurrency_config.chunk_size": 64, + "batcher_config.block_builder_config.execute_config.concurrency_config.enabled": true, + "batcher_config.block_builder_config.execute_config.concurrency_config.n_workers": 4, + "batcher_config.block_builder_config.execute_config.stack_size": 62914560, + "batcher_config.block_builder_config.tx_chunk_size": 100, + "batcher_config.contract_class_manager_config.cairo_native_run_config.channel_size": 2000, + "batcher_config.contract_class_manager_config.cairo_native_run_config.native_classes_whitelist": "All", + "batcher_config.contract_class_manager_config.cairo_native_run_config.run_cairo_native": false, + "batcher_config.contract_class_manager_config.cairo_native_run_config.wait_on_native_compilation": false, + "batcher_config.contract_class_manager_config.contract_cache_size": 600, + "batcher_config.contract_class_manager_config.native_compiler_config.max_casm_bytecode_size": 81920, + "batcher_config.contract_class_manager_config.native_compiler_config.max_cpu_time": 20, + "batcher_config.contract_class_manager_config.native_compiler_config.max_memory_usage": 5368709120, + "batcher_config.contract_class_manager_config.native_compiler_config.max_native_bytecode_size": 15728640, + "batcher_config.contract_class_manager_config.native_compiler_config.optimization_level": 2, + "batcher_config.contract_class_manager_config.native_compiler_config.panic_on_compilation_failure": false, + "batcher_config.contract_class_manager_config.native_compiler_config.sierra_to_native_compiler_path": "", + "batcher_config.contract_class_manager_config.native_compiler_config.sierra_to_native_compiler_path.#is_none": true, + "batcher_config.input_stream_content_buffer_size": 400, + "batcher_config.max_l1_handler_txs_per_block_proposal": 3, + "batcher_config.outstream_content_buffer_size": 100, + "batcher_config.storage.db_config.enforce_file_exists": false, + "batcher_config.storage.db_config.growth_step": 67108864, + "batcher_config.storage.db_config.max_size": 34359738368, + "batcher_config.storage.db_config.min_size": 1048576, + "batcher_config.storage.db_config.path_prefix": "/data/node_0/executable_0/batcher", + "batcher_config.storage.mmap_file_config.growth_step": 1048576, + "batcher_config.storage.mmap_file_config.max_object_size": 65536, + "batcher_config.storage.mmap_file_config.max_size": 16777216, + "batcher_config.storage.scope": "StateOnly", + "chain_id": "CHAIN_ID_SUBDIR", + "class_manager_config.class_manager_config.cached_class_storage_config.class_cache_size": 100, + "class_manager_config.class_manager_config.cached_class_storage_config.deprecated_class_cache_size": 100, + "class_manager_config.class_storage_config.class_hash_storage_config.enforce_file_exists": false, + "class_manager_config.class_storage_config.class_hash_storage_config.max_size": 1048576, + "class_manager_config.class_storage_config.class_hash_storage_config.path_prefix": "/data/node_0/executable_0/class_manager/class_hash_storage", + "class_manager_config.class_storage_config.persistent_root": "/data/node_0/executable_0/class_manager/classes", + "compiler_config.max_casm_bytecode_size": 81920, + "compiler_config.max_cpu_time": 20, + "compiler_config.max_memory_usage": 5368709120, + "compiler_config.max_native_bytecode_size": 15728640, + "compiler_config.optimization_level": 2, + "compiler_config.panic_on_compilation_failure": false, + "compiler_config.sierra_to_native_compiler_path": "", + "compiler_config.sierra_to_native_compiler_path.#is_none": true, + "components.batcher.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.batcher.ip": "0.0.0.0", + "components.batcher.local_server_config.channel_buffer_size": 32, + "components.batcher.max_concurrency": 10, + "components.batcher.port": 0, + "components.batcher.remote_client_config.idle_connections": 18446744073709551615, + "components.batcher.remote_client_config.idle_timeout": 90, + "components.batcher.remote_client_config.retries": 3, + "components.batcher.remote_client_config.retry_interval": 3, + "components.batcher.url": "localhost", + "components.class_manager.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.class_manager.ip": "0.0.0.0", + "components.class_manager.local_server_config.channel_buffer_size": 32, + "components.class_manager.max_concurrency": 10, + "components.class_manager.port": 0, + "components.class_manager.remote_client_config.idle_connections": 18446744073709551615, + "components.class_manager.remote_client_config.idle_timeout": 90, + "components.class_manager.remote_client_config.retries": 3, + "components.class_manager.remote_client_config.retry_interval": 3, + "components.class_manager.url": "localhost", + "components.consensus_manager.execution_mode": "Enabled", + "components.gateway.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.gateway.ip": "0.0.0.0", + "components.gateway.local_server_config.channel_buffer_size": 32, + "components.gateway.max_concurrency": 10, + "components.gateway.port": 0, + "components.gateway.remote_client_config.idle_connections": 18446744073709551615, + "components.gateway.remote_client_config.idle_timeout": 90, + "components.gateway.remote_client_config.retries": 3, + "components.gateway.remote_client_config.retry_interval": 3, + "components.gateway.url": "localhost", + "components.http_server.execution_mode": "Enabled", + "components.l1_gas_price_provider.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.l1_gas_price_provider.ip": "0.0.0.0", + "components.l1_gas_price_provider.local_server_config.channel_buffer_size": 32, + "components.l1_gas_price_provider.max_concurrency": 10, + "components.l1_gas_price_provider.port": 0, + "components.l1_gas_price_provider.remote_client_config.idle_connections": 18446744073709551615, + "components.l1_gas_price_provider.remote_client_config.idle_timeout": 90, + "components.l1_gas_price_provider.remote_client_config.retries": 3, + "components.l1_gas_price_provider.remote_client_config.retry_interval": 3, + "components.l1_gas_price_provider.url": "localhost", + "components.l1_gas_price_scraper.execution_mode": "Enabled", + "components.l1_provider.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.l1_provider.ip": "0.0.0.0", + "components.l1_provider.local_server_config.channel_buffer_size": 32, + "components.l1_provider.max_concurrency": 10, + "components.l1_provider.port": 0, + "components.l1_provider.remote_client_config.idle_connections": 18446744073709551615, + "components.l1_provider.remote_client_config.idle_timeout": 90, + "components.l1_provider.remote_client_config.retries": 3, + "components.l1_provider.remote_client_config.retry_interval": 3, + "components.l1_provider.url": "localhost", + "components.l1_scraper.execution_mode": "Enabled", + "components.mempool.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.mempool.ip": "0.0.0.0", + "components.mempool.local_server_config.channel_buffer_size": 32, + "components.mempool.max_concurrency": 10, + "components.mempool.port": 0, + "components.mempool.remote_client_config.idle_connections": 18446744073709551615, + "components.mempool.remote_client_config.idle_timeout": 90, + "components.mempool.remote_client_config.retries": 3, + "components.mempool.remote_client_config.retry_interval": 3, + "components.mempool.url": "localhost", + "components.mempool_p2p.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.mempool_p2p.ip": "0.0.0.0", + "components.mempool_p2p.local_server_config.channel_buffer_size": 32, + "components.mempool_p2p.max_concurrency": 10, + "components.mempool_p2p.port": 0, + "components.mempool_p2p.remote_client_config.idle_connections": 18446744073709551615, + "components.mempool_p2p.remote_client_config.idle_timeout": 90, + "components.mempool_p2p.remote_client_config.retries": 3, + "components.mempool_p2p.remote_client_config.retry_interval": 3, + "components.mempool_p2p.url": "localhost", + "components.monitoring_endpoint.execution_mode": "Enabled", + "components.sierra_compiler.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.sierra_compiler.ip": "0.0.0.0", + "components.sierra_compiler.local_server_config.channel_buffer_size": 32, + "components.sierra_compiler.max_concurrency": 10, + "components.sierra_compiler.port": 0, + "components.sierra_compiler.remote_client_config.idle_connections": 18446744073709551615, + "components.sierra_compiler.remote_client_config.idle_timeout": 90, + "components.sierra_compiler.remote_client_config.retries": 3, + "components.sierra_compiler.remote_client_config.retry_interval": 3, + "components.sierra_compiler.url": "localhost", + "components.state_sync.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.state_sync.ip": "0.0.0.0", + "components.state_sync.local_server_config.channel_buffer_size": 32, + "components.state_sync.max_concurrency": 10, + "components.state_sync.port": 0, + "components.state_sync.remote_client_config.idle_connections": 18446744073709551615, + "components.state_sync.remote_client_config.idle_timeout": 90, + "components.state_sync.remote_client_config.retries": 3, + "components.state_sync.remote_client_config.retry_interval": 3, + "components.state_sync.url": "localhost", + "consensus_manager_config.broadcast_buffer_size": 10000, + "consensus_manager_config.cende_config.skip_write_height": 1, + "consensus_manager_config.cende_config.skip_write_height.#is_none": false, + "consensus_manager_config.consensus_config.future_height_limit": 10, + "consensus_manager_config.consensus_config.future_height_round_limit": 1, + "consensus_manager_config.consensus_config.future_round_limit": 10, + "consensus_manager_config.consensus_config.startup_delay": 15, + "consensus_manager_config.consensus_config.sync_retry_interval": 1.0, + "consensus_manager_config.consensus_config.timeouts.precommit_timeout": 3.0, + "consensus_manager_config.consensus_config.timeouts.prevote_timeout": 3.0, + "consensus_manager_config.consensus_config.timeouts.proposal_timeout": 9.0, + "consensus_manager_config.context_config.block_timestamp_window": 1, + "consensus_manager_config.context_config.build_proposal_margin": 1000, + "consensus_manager_config.context_config.builder_address": "0x4", + "consensus_manager_config.context_config.l1_da_mode": true, + "consensus_manager_config.context_config.num_validators": 1, + "consensus_manager_config.context_config.proposal_buffer_size": 100, + "consensus_manager_config.context_config.validate_proposal_margin": 10000, + "consensus_manager_config.eth_to_strk_oracle_config.base_url": "http://127.0.0.1:53262/eth_to_strk_oracle?timestamp=", + "consensus_manager_config.eth_to_strk_oracle_config.headers": "", + "consensus_manager_config.immediate_active_height": 1, + "consensus_manager_config.network_config.advertised_multiaddr": "", + "consensus_manager_config.network_config.advertised_multiaddr.#is_none": true, + "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "", + "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": true, + "consensus_manager_config.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": 2, + "consensus_manager_config.network_config.discovery_config.bootstrap_dial_retry_config.factor": 5, + "consensus_manager_config.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": 5, + "consensus_manager_config.network_config.discovery_config.heartbeat_interval": 100, + "consensus_manager_config.network_config.idle_connection_timeout": 120, + "consensus_manager_config.network_config.peer_manager_config.malicious_timeout_seconds": 1, + "consensus_manager_config.network_config.peer_manager_config.unstable_timeout_millis": 1000, + "consensus_manager_config.network_config.port": 53080, + "consensus_manager_config.network_config.secret_key": "0x0101010101010101010101010101010101010101010101010101010101010101", + "consensus_manager_config.network_config.session_timeout": 120, + "consensus_manager_config.proposals_topic": "consensus_proposals", + "consensus_manager_config.votes_topic": "consensus_votes", + "eth_fee_token_address": "0x1001", + "gateway_config.stateful_tx_validator_config.max_allowed_nonce_gap": 50, + "gateway_config.stateful_tx_validator_config.max_nonce_for_validation_skip": "0x1", + "gateway_config.stateless_tx_validator_config.max_calldata_length": 10, + "gateway_config.stateless_tx_validator_config.max_contract_class_object_size": 4089446, + "gateway_config.stateless_tx_validator_config.max_sierra_version.major": 1, + "gateway_config.stateless_tx_validator_config.max_sierra_version.minor": 5, + "gateway_config.stateless_tx_validator_config.max_sierra_version.patch": 18446744073709551615, + "gateway_config.stateless_tx_validator_config.max_signature_length": 2, + "gateway_config.stateless_tx_validator_config.min_sierra_version.major": 1, + "gateway_config.stateless_tx_validator_config.min_sierra_version.minor": 1, + "gateway_config.stateless_tx_validator_config.min_sierra_version.patch": 0, + "gateway_config.stateless_tx_validator_config.validate_non_zero_l1_data_gas_fee": false, + "gateway_config.stateless_tx_validator_config.validate_non_zero_l1_gas_fee": true, + "gateway_config.stateless_tx_validator_config.validate_non_zero_l2_gas_fee": false, + "http_server_config.ip": "127.0.0.1", + "http_server_config.port": 53320, + "l1_gas_price_provider_config.lag_margin_seconds": 60, + "l1_gas_price_provider_config.number_of_blocks_for_mean": 300, + "l1_gas_price_provider_config.storage_limit": 3000, + "l1_gas_price_scraper_config.finality": 0, + "l1_gas_price_scraper_config.number_of_blocks_for_mean": 300, + "l1_gas_price_scraper_config.polling_interval": 1, + "l1_gas_price_scraper_config.starting_block": 0, + "l1_gas_price_scraper_config.starting_block.#is_none": true, + "l1_provider_config.bootstrap_catch_up_height_override": 0, + "l1_provider_config.bootstrap_catch_up_height_override.#is_none": true, + "l1_provider_config.provider_startup_height_override": 1, + "l1_provider_config.provider_startup_height_override.#is_none": false, + "l1_provider_config.startup_sync_sleep_retry_interval": 0.0, + "l1_scraper_config.finality": 0, + "l1_scraper_config.polling_interval": 1, + "l1_scraper_config.startup_rewind_time": 0, + "mempool_config.committed_nonce_retention_block_count": 100, + "mempool_config.declare_delay": 1, + "mempool_config.enable_fee_escalation": true, + "mempool_config.fee_escalation_percentage": 10, + "mempool_config.transaction_ttl": 300, + "mempool_p2p_config.max_transaction_batch_size": 1, + "mempool_p2p_config.network_buffer_size": 10000, + "mempool_p2p_config.network_config.advertised_multiaddr": "", + "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": true, + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "", + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": true, + "mempool_p2p_config.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": 2, + "mempool_p2p_config.network_config.discovery_config.bootstrap_dial_retry_config.factor": 5, + "mempool_p2p_config.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": 5, + "mempool_p2p_config.network_config.discovery_config.heartbeat_interval": 100, + "mempool_p2p_config.network_config.idle_connection_timeout": 120, + "mempool_p2p_config.network_config.peer_manager_config.malicious_timeout_seconds": 1, + "mempool_p2p_config.network_config.peer_manager_config.unstable_timeout_millis": 1000, + "mempool_p2p_config.network_config.port": 53200, + "mempool_p2p_config.network_config.secret_key": "0x0101010101010101010101010101010101010101010101010101010101010101", + "mempool_p2p_config.network_config.session_timeout": 120, + "mempool_p2p_config.transaction_batch_rate_millis": 1000, + "monitoring_config.collect_metrics": true, + "monitoring_config.collect_profiling_metrics": true, + "monitoring_endpoint_config.collect_metrics": true, + "monitoring_endpoint_config.collect_profiling_metrics": true, + "monitoring_endpoint_config.ip": "0.0.0.0", + "monitoring_endpoint_config.port": 8082, + "recorder_url": "http://127.0.0.1:53261/", + "revert_config.revert_up_to_and_including": 18446744073709551615, + "revert_config.should_revert": false, + "state_sync_config.central_sync_client_config.#is_none": true, + "state_sync_config.central_sync_client_config.central_source_config.class_cache_size": 100, + "state_sync_config.central_sync_client_config.central_source_config.concurrent_requests": 10, + "state_sync_config.central_sync_client_config.central_source_config.http_headers": "", + "state_sync_config.central_sync_client_config.central_source_config.max_classes_to_download": 20, + "state_sync_config.central_sync_client_config.central_source_config.max_state_updates_to_download": 20, + "state_sync_config.central_sync_client_config.central_source_config.max_state_updates_to_store_in_memory": 20, + "state_sync_config.central_sync_client_config.central_source_config.retry_config.max_retries": 10, + "state_sync_config.central_sync_client_config.central_source_config.retry_config.retry_base_millis": 30, + "state_sync_config.central_sync_client_config.central_source_config.retry_config.retry_max_delay_millis": 30000, + "state_sync_config.central_sync_client_config.central_source_config.starknet_url": "https://alpha-mainnet.starknet.io/", + "state_sync_config.central_sync_client_config.sync_config.base_layer_propagation_sleep_duration": 10, + "state_sync_config.central_sync_client_config.sync_config.block_propagation_sleep_duration": 2, + "state_sync_config.central_sync_client_config.sync_config.blocks_max_stream_size": 1000, + "state_sync_config.central_sync_client_config.sync_config.collect_pending_data": false, + "state_sync_config.central_sync_client_config.sync_config.recoverable_error_sleep_duration": 3, + "state_sync_config.central_sync_client_config.sync_config.state_updates_max_stream_size": 1000, + "state_sync_config.central_sync_client_config.sync_config.store_sierras_and_casms": false, + "state_sync_config.central_sync_client_config.sync_config.verify_blocks": true, + "state_sync_config.network_config.advertised_multiaddr": "", + "state_sync_config.network_config.advertised_multiaddr.#is_none": true, + "state_sync_config.network_config.bootstrap_peer_multiaddr": "", + "state_sync_config.network_config.bootstrap_peer_multiaddr.#is_none": true, + "state_sync_config.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": 2, + "state_sync_config.network_config.discovery_config.bootstrap_dial_retry_config.factor": 5, + "state_sync_config.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": 5, + "state_sync_config.network_config.discovery_config.heartbeat_interval": 100, + "state_sync_config.network_config.idle_connection_timeout": 120, + "state_sync_config.network_config.peer_manager_config.malicious_timeout_seconds": 1, + "state_sync_config.network_config.peer_manager_config.unstable_timeout_millis": 1000, + "state_sync_config.network_config.port": 53140, + "state_sync_config.network_config.secret_key": "0x0101010101010101010101010101010101010101010101010101010101010101", + "state_sync_config.network_config.session_timeout": 120, + "state_sync_config.p2p_sync_client_config.#is_none": false, + "state_sync_config.p2p_sync_client_config.buffer_size": 100000, + "state_sync_config.p2p_sync_client_config.num_block_classes_per_query": 100, + "state_sync_config.p2p_sync_client_config.num_block_state_diffs_per_query": 100, + "state_sync_config.p2p_sync_client_config.num_block_transactions_per_query": 100, + "state_sync_config.p2p_sync_client_config.num_headers_per_query": 10000, + "state_sync_config.p2p_sync_client_config.wait_period_for_new_data": 50, + "state_sync_config.p2p_sync_client_config.wait_period_for_other_protocol": 50, + "state_sync_config.storage_config.db_config.enforce_file_exists": false, + "state_sync_config.storage_config.db_config.growth_step": 67108864, + "state_sync_config.storage_config.db_config.max_size": 34359738368, + "state_sync_config.storage_config.db_config.min_size": 1048576, + "state_sync_config.storage_config.db_config.path_prefix": "/data/node_0/executable_0/state_sync", + "state_sync_config.storage_config.mmap_file_config.growth_step": 1048576, + "state_sync_config.storage_config.mmap_file_config.max_object_size": 65536, + "state_sync_config.storage_config.mmap_file_config.max_size": 16777216, + "state_sync_config.storage_config.scope": "FullArchive", + "strk_fee_token_address": "0x1002", + "validator_id": "0x64", + "versioned_constants_overrides.invoke_tx_max_n_steps": 10000000, + "versioned_constants_overrides.max_n_events": 1000, + "versioned_constants_overrides.max_recursion_depth": 50, + "versioned_constants_overrides.validate_max_n_steps": 1000000 +} diff --git a/config/sequencer/presets/distributed_node/application_configs/batcher.json b/config/sequencer/presets/distributed_node/application_configs/batcher.json new file mode 100644 index 00000000000..dbb98ad1641 --- /dev/null +++ b/config/sequencer/presets/distributed_node/application_configs/batcher.json @@ -0,0 +1,306 @@ +{ + "base_layer_config.node_url": "http://localhost:53260/", + "base_layer_config.starknet_contract_address": "0x5FbDB2315678afecb367f032d93F642f64180aa3", + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.l1_gas": 2500000, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.message_segment_length": 3700, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.n_events": 5000, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.sierra_gas": 30000000, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.state_diff_size": 4000, + "batcher_config.block_builder_config.execute_config.concurrency_config.chunk_size": 64, + "batcher_config.block_builder_config.execute_config.concurrency_config.enabled": true, + "batcher_config.block_builder_config.execute_config.concurrency_config.n_workers": 4, + "batcher_config.block_builder_config.execute_config.stack_size": 62914560, + "batcher_config.block_builder_config.tx_chunk_size": 100, + "batcher_config.contract_class_manager_config.cairo_native_run_config.channel_size": 2000, + "batcher_config.contract_class_manager_config.cairo_native_run_config.native_classes_whitelist": "All", + "batcher_config.contract_class_manager_config.cairo_native_run_config.run_cairo_native": false, + "batcher_config.contract_class_manager_config.cairo_native_run_config.wait_on_native_compilation": false, + "batcher_config.contract_class_manager_config.contract_cache_size": 600, + "batcher_config.contract_class_manager_config.native_compiler_config.max_casm_bytecode_size": 81920, + "batcher_config.contract_class_manager_config.native_compiler_config.max_cpu_time": 20, + "batcher_config.contract_class_manager_config.native_compiler_config.max_memory_usage": 5368709120, + "batcher_config.contract_class_manager_config.native_compiler_config.max_native_bytecode_size": 15728640, + "batcher_config.contract_class_manager_config.native_compiler_config.optimization_level": 2, + "batcher_config.contract_class_manager_config.native_compiler_config.panic_on_compilation_failure": false, + "batcher_config.contract_class_manager_config.native_compiler_config.sierra_to_native_compiler_path": "", + "batcher_config.contract_class_manager_config.native_compiler_config.sierra_to_native_compiler_path.#is_none": true, + "batcher_config.input_stream_content_buffer_size": 400, + "batcher_config.max_l1_handler_txs_per_block_proposal": 3, + "batcher_config.outstream_content_buffer_size": 100, + "batcher_config.storage.db_config.enforce_file_exists": false, + "batcher_config.storage.db_config.growth_step": 67108864, + "batcher_config.storage.db_config.max_size": 34359738368, + "batcher_config.storage.db_config.min_size": 1048576, + "batcher_config.storage.db_config.path_prefix": "/data/node_0/executable_0/batcher", + "batcher_config.storage.mmap_file_config.growth_step": 1048576, + "batcher_config.storage.mmap_file_config.max_object_size": 65536, + "batcher_config.storage.mmap_file_config.max_size": 16777216, + "batcher_config.storage.scope": "StateOnly", + "chain_id": "CHAIN_ID_SUBDIR", + "class_manager_config.class_manager_config.cached_class_storage_config.class_cache_size": 100, + "class_manager_config.class_manager_config.cached_class_storage_config.deprecated_class_cache_size": 100, + "class_manager_config.class_storage_config.class_hash_storage_config.enforce_file_exists": false, + "class_manager_config.class_storage_config.class_hash_storage_config.max_size": 1048576, + "class_manager_config.class_storage_config.class_hash_storage_config.path_prefix": "/data/node_0/executable_0/class_manager/class_hash_storage", + "class_manager_config.class_storage_config.persistent_root": "/data/node_0/executable_0/class_manager/classes", + "compiler_config.max_casm_bytecode_size": 81920, + "compiler_config.max_cpu_time": 20, + "compiler_config.max_memory_usage": 5368709120, + "compiler_config.max_native_bytecode_size": 15728640, + "compiler_config.optimization_level": 2, + "compiler_config.panic_on_compilation_failure": false, + "compiler_config.sierra_to_native_compiler_path": "", + "compiler_config.sierra_to_native_compiler_path.#is_none": true, + "components.batcher.execution_mode": "LocalExecutionWithRemoteEnabled", + "components.batcher.ip": "0.0.0.0", + "components.batcher.local_server_config.channel_buffer_size": 32, + "components.batcher.max_concurrency": 10, + "components.batcher.port": 55000, + "components.batcher.remote_client_config.idle_connections": 18446744073709551615, + "components.batcher.remote_client_config.idle_timeout": 90, + "components.batcher.remote_client_config.retries": 3, + "components.batcher.remote_client_config.retry_interval": 3, + "components.batcher.url": "sequencer-batcher-service", + "components.class_manager.execution_mode": "Remote", + "components.class_manager.ip": "0.0.0.0", + "components.class_manager.local_server_config.channel_buffer_size": 32, + "components.class_manager.max_concurrency": 10, + "components.class_manager.port": 55001, + "components.class_manager.remote_client_config.idle_connections": 18446744073709551615, + "components.class_manager.remote_client_config.idle_timeout": 90, + "components.class_manager.remote_client_config.retries": 3, + "components.class_manager.remote_client_config.retry_interval": 3, + "components.class_manager.url": "sequencer-class-manager-service", + "components.consensus_manager.execution_mode": "Disabled", + "components.gateway.execution_mode": "Disabled", + "components.gateway.ip": "0.0.0.0", + "components.gateway.local_server_config.channel_buffer_size": 32, + "components.gateway.max_concurrency": 10, + "components.gateway.port": 0, + "components.gateway.remote_client_config.idle_connections": 18446744073709551615, + "components.gateway.remote_client_config.idle_timeout": 90, + "components.gateway.remote_client_config.retries": 3, + "components.gateway.remote_client_config.retry_interval": 3, + "components.gateway.url": "localhost", + "components.http_server.execution_mode": "Disabled", + "components.l1_gas_price_provider.execution_mode": "Disabled", + "components.l1_gas_price_provider.ip": "0.0.0.0", + "components.l1_gas_price_provider.local_server_config.channel_buffer_size": 32, + "components.l1_gas_price_provider.max_concurrency": 10, + "components.l1_gas_price_provider.port": 0, + "components.l1_gas_price_provider.remote_client_config.idle_connections": 18446744073709551615, + "components.l1_gas_price_provider.remote_client_config.idle_timeout": 90, + "components.l1_gas_price_provider.remote_client_config.retries": 3, + "components.l1_gas_price_provider.remote_client_config.retry_interval": 3, + "components.l1_gas_price_provider.url": "localhost", + "components.l1_gas_price_scraper.execution_mode": "Disabled", + "components.l1_provider.execution_mode": "Remote", + "components.l1_provider.ip": "0.0.0.0", + "components.l1_provider.local_server_config.channel_buffer_size": 32, + "components.l1_provider.max_concurrency": 10, + "components.l1_provider.port": 55005, + "components.l1_provider.remote_client_config.idle_connections": 18446744073709551615, + "components.l1_provider.remote_client_config.idle_timeout": 90, + "components.l1_provider.remote_client_config.retries": 3, + "components.l1_provider.remote_client_config.retry_interval": 3, + "components.l1_provider.url": "sequencer-l1-provider-service", + "components.l1_scraper.execution_mode": "Disabled", + "components.mempool.execution_mode": "Remote", + "components.mempool.ip": "0.0.0.0", + "components.mempool.local_server_config.channel_buffer_size": 32, + "components.mempool.max_concurrency": 10, + "components.mempool.port": 55006, + "components.mempool.remote_client_config.idle_connections": 18446744073709551615, + "components.mempool.remote_client_config.idle_timeout": 90, + "components.mempool.remote_client_config.retries": 3, + "components.mempool.remote_client_config.retry_interval": 3, + "components.mempool.url": "sequencer-mempool-service", + "components.mempool_p2p.execution_mode": "Disabled", + "components.mempool_p2p.ip": "0.0.0.0", + "components.mempool_p2p.local_server_config.channel_buffer_size": 32, + "components.mempool_p2p.max_concurrency": 10, + "components.mempool_p2p.port": 0, + "components.mempool_p2p.remote_client_config.idle_connections": 18446744073709551615, + "components.mempool_p2p.remote_client_config.idle_timeout": 90, + "components.mempool_p2p.remote_client_config.retries": 3, + "components.mempool_p2p.remote_client_config.retry_interval": 3, + "components.mempool_p2p.url": "localhost", + "components.monitoring_endpoint.execution_mode": "Enabled", + "components.sierra_compiler.execution_mode": "Disabled", + "components.sierra_compiler.ip": "0.0.0.0", + "components.sierra_compiler.local_server_config.channel_buffer_size": 32, + "components.sierra_compiler.max_concurrency": 10, + "components.sierra_compiler.port": 0, + "components.sierra_compiler.remote_client_config.idle_connections": 18446744073709551615, + "components.sierra_compiler.remote_client_config.idle_timeout": 90, + "components.sierra_compiler.remote_client_config.retries": 3, + "components.sierra_compiler.remote_client_config.retry_interval": 3, + "components.sierra_compiler.url": "localhost", + "components.state_sync.execution_mode": "Disabled", + "components.state_sync.ip": "0.0.0.0", + "components.state_sync.local_server_config.channel_buffer_size": 32, + "components.state_sync.max_concurrency": 10, + "components.state_sync.port": 0, + "components.state_sync.remote_client_config.idle_connections": 18446744073709551615, + "components.state_sync.remote_client_config.idle_timeout": 90, + "components.state_sync.remote_client_config.retries": 3, + "components.state_sync.remote_client_config.retry_interval": 3, + "components.state_sync.url": "localhost", + "consensus_manager_config.broadcast_buffer_size": 10000, + "consensus_manager_config.cende_config.skip_write_height": 1, + "consensus_manager_config.cende_config.skip_write_height.#is_none": false, + "consensus_manager_config.consensus_config.future_height_limit": 10, + "consensus_manager_config.consensus_config.future_height_round_limit": 1, + "consensus_manager_config.consensus_config.future_round_limit": 10, + "consensus_manager_config.consensus_config.startup_delay": 15, + "consensus_manager_config.consensus_config.sync_retry_interval": 1.0, + "consensus_manager_config.consensus_config.timeouts.precommit_timeout": 3.0, + "consensus_manager_config.consensus_config.timeouts.prevote_timeout": 3.0, + "consensus_manager_config.consensus_config.timeouts.proposal_timeout": 9.0, + "consensus_manager_config.context_config.block_timestamp_window": 1, + "consensus_manager_config.context_config.build_proposal_margin": 1000, + "consensus_manager_config.context_config.builder_address": "0x4", + "consensus_manager_config.context_config.l1_da_mode": true, + "consensus_manager_config.context_config.num_validators": 1, + "consensus_manager_config.context_config.proposal_buffer_size": 100, + "consensus_manager_config.context_config.validate_proposal_margin": 10000, + "consensus_manager_config.eth_to_strk_oracle_config.base_url": "http://127.0.0.1:53262/eth_to_strk_oracle?timestamp=", + "consensus_manager_config.eth_to_strk_oracle_config.headers": "", + "consensus_manager_config.immediate_active_height": 1, + "consensus_manager_config.network_config.advertised_multiaddr": "", + "consensus_manager_config.network_config.advertised_multiaddr.#is_none": true, + "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "", + "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": true, + "consensus_manager_config.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": 2, + "consensus_manager_config.network_config.discovery_config.bootstrap_dial_retry_config.factor": 5, + "consensus_manager_config.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": 5, + "consensus_manager_config.network_config.discovery_config.heartbeat_interval": 100, + "consensus_manager_config.network_config.idle_connection_timeout": 120, + "consensus_manager_config.network_config.peer_manager_config.malicious_timeout_seconds": 1, + "consensus_manager_config.network_config.peer_manager_config.unstable_timeout_millis": 1000, + "consensus_manager_config.network_config.port": 53080, + "consensus_manager_config.network_config.secret_key": "0x0101010101010101010101010101010101010101010101010101010101010101", + "consensus_manager_config.network_config.session_timeout": 120, + "consensus_manager_config.proposals_topic": "consensus_proposals", + "consensus_manager_config.votes_topic": "consensus_votes", + "eth_fee_token_address": "0x1001", + "gateway_config.stateful_tx_validator_config.max_allowed_nonce_gap": 50, + "gateway_config.stateful_tx_validator_config.max_nonce_for_validation_skip": "0x1", + "gateway_config.stateless_tx_validator_config.max_calldata_length": 10, + "gateway_config.stateless_tx_validator_config.max_contract_class_object_size": 4089446, + "gateway_config.stateless_tx_validator_config.max_sierra_version.major": 1, + "gateway_config.stateless_tx_validator_config.max_sierra_version.minor": 5, + "gateway_config.stateless_tx_validator_config.max_sierra_version.patch": 18446744073709551615, + "gateway_config.stateless_tx_validator_config.max_signature_length": 2, + "gateway_config.stateless_tx_validator_config.min_sierra_version.major": 1, + "gateway_config.stateless_tx_validator_config.min_sierra_version.minor": 1, + "gateway_config.stateless_tx_validator_config.min_sierra_version.patch": 0, + "gateway_config.stateless_tx_validator_config.validate_non_zero_l1_data_gas_fee": false, + "gateway_config.stateless_tx_validator_config.validate_non_zero_l1_gas_fee": true, + "gateway_config.stateless_tx_validator_config.validate_non_zero_l2_gas_fee": false, + "http_server_config.ip": "127.0.0.1", + "http_server_config.port": 53320, + "l1_gas_price_provider_config.lag_margin_seconds": 60, + "l1_gas_price_provider_config.number_of_blocks_for_mean": 300, + "l1_gas_price_provider_config.storage_limit": 3000, + "l1_gas_price_scraper_config.finality": 0, + "l1_gas_price_scraper_config.number_of_blocks_for_mean": 300, + "l1_gas_price_scraper_config.polling_interval": 1, + "l1_gas_price_scraper_config.starting_block": 0, + "l1_gas_price_scraper_config.starting_block.#is_none": true, + "l1_provider_config.bootstrap_catch_up_height_override": 0, + "l1_provider_config.bootstrap_catch_up_height_override.#is_none": true, + "l1_provider_config.provider_startup_height_override": 1, + "l1_provider_config.provider_startup_height_override.#is_none": false, + "l1_provider_config.startup_sync_sleep_retry_interval": 0.0, + "l1_scraper_config.finality": 0, + "l1_scraper_config.polling_interval": 1, + "l1_scraper_config.startup_rewind_time": 0, + "mempool_config.committed_nonce_retention_block_count": 100, + "mempool_config.declare_delay": 1, + "mempool_config.enable_fee_escalation": true, + "mempool_config.fee_escalation_percentage": 10, + "mempool_config.transaction_ttl": 300, + "mempool_p2p_config.max_transaction_batch_size": 1, + "mempool_p2p_config.network_buffer_size": 10000, + "mempool_p2p_config.network_config.advertised_multiaddr": "", + "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": true, + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "", + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": true, + "mempool_p2p_config.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": 2, + "mempool_p2p_config.network_config.discovery_config.bootstrap_dial_retry_config.factor": 5, + "mempool_p2p_config.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": 5, + "mempool_p2p_config.network_config.discovery_config.heartbeat_interval": 100, + "mempool_p2p_config.network_config.idle_connection_timeout": 120, + "mempool_p2p_config.network_config.peer_manager_config.malicious_timeout_seconds": 1, + "mempool_p2p_config.network_config.peer_manager_config.unstable_timeout_millis": 1000, + "mempool_p2p_config.network_config.port": 53200, + "mempool_p2p_config.network_config.secret_key": "0x0101010101010101010101010101010101010101010101010101010101010101", + "mempool_p2p_config.network_config.session_timeout": 120, + "mempool_p2p_config.transaction_batch_rate_millis": 1000, + "monitoring_config.collect_metrics": true, + "monitoring_config.collect_profiling_metrics": true, + "monitoring_endpoint_config.collect_metrics": true, + "monitoring_endpoint_config.collect_profiling_metrics": true, + "monitoring_endpoint_config.ip": "0.0.0.0", + "monitoring_endpoint_config.port": 8082, + "recorder_url": "http://127.0.0.1:53261/", + "revert_config.revert_up_to_and_including": 18446744073709551615, + "revert_config.should_revert": false, + "state_sync_config.central_sync_client_config.#is_none": true, + "state_sync_config.central_sync_client_config.central_source_config.class_cache_size": 100, + "state_sync_config.central_sync_client_config.central_source_config.concurrent_requests": 10, + "state_sync_config.central_sync_client_config.central_source_config.http_headers": "", + "state_sync_config.central_sync_client_config.central_source_config.max_classes_to_download": 20, + "state_sync_config.central_sync_client_config.central_source_config.max_state_updates_to_download": 20, + "state_sync_config.central_sync_client_config.central_source_config.max_state_updates_to_store_in_memory": 20, + "state_sync_config.central_sync_client_config.central_source_config.retry_config.max_retries": 10, + "state_sync_config.central_sync_client_config.central_source_config.retry_config.retry_base_millis": 30, + "state_sync_config.central_sync_client_config.central_source_config.retry_config.retry_max_delay_millis": 30000, + "state_sync_config.central_sync_client_config.central_source_config.starknet_url": "https://alpha-mainnet.starknet.io/", + "state_sync_config.central_sync_client_config.sync_config.base_layer_propagation_sleep_duration": 10, + "state_sync_config.central_sync_client_config.sync_config.block_propagation_sleep_duration": 2, + "state_sync_config.central_sync_client_config.sync_config.blocks_max_stream_size": 1000, + "state_sync_config.central_sync_client_config.sync_config.collect_pending_data": false, + "state_sync_config.central_sync_client_config.sync_config.recoverable_error_sleep_duration": 3, + "state_sync_config.central_sync_client_config.sync_config.state_updates_max_stream_size": 1000, + "state_sync_config.central_sync_client_config.sync_config.store_sierras_and_casms": false, + "state_sync_config.central_sync_client_config.sync_config.verify_blocks": true, + "state_sync_config.network_config.advertised_multiaddr": "", + "state_sync_config.network_config.advertised_multiaddr.#is_none": true, + "state_sync_config.network_config.bootstrap_peer_multiaddr": "", + "state_sync_config.network_config.bootstrap_peer_multiaddr.#is_none": true, + "state_sync_config.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": 2, + "state_sync_config.network_config.discovery_config.bootstrap_dial_retry_config.factor": 5, + "state_sync_config.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": 5, + "state_sync_config.network_config.discovery_config.heartbeat_interval": 100, + "state_sync_config.network_config.idle_connection_timeout": 120, + "state_sync_config.network_config.peer_manager_config.malicious_timeout_seconds": 1, + "state_sync_config.network_config.peer_manager_config.unstable_timeout_millis": 1000, + "state_sync_config.network_config.port": 53140, + "state_sync_config.network_config.secret_key": "0x0101010101010101010101010101010101010101010101010101010101010101", + "state_sync_config.network_config.session_timeout": 120, + "state_sync_config.p2p_sync_client_config.#is_none": false, + "state_sync_config.p2p_sync_client_config.buffer_size": 100000, + "state_sync_config.p2p_sync_client_config.num_block_classes_per_query": 100, + "state_sync_config.p2p_sync_client_config.num_block_state_diffs_per_query": 100, + "state_sync_config.p2p_sync_client_config.num_block_transactions_per_query": 100, + "state_sync_config.p2p_sync_client_config.num_headers_per_query": 10000, + "state_sync_config.p2p_sync_client_config.wait_period_for_new_data": 50, + "state_sync_config.p2p_sync_client_config.wait_period_for_other_protocol": 50, + "state_sync_config.storage_config.db_config.enforce_file_exists": false, + "state_sync_config.storage_config.db_config.growth_step": 67108864, + "state_sync_config.storage_config.db_config.max_size": 34359738368, + "state_sync_config.storage_config.db_config.min_size": 1048576, + "state_sync_config.storage_config.db_config.path_prefix": "/data/node_0/executable_0/state_sync", + "state_sync_config.storage_config.mmap_file_config.growth_step": 1048576, + "state_sync_config.storage_config.mmap_file_config.max_object_size": 65536, + "state_sync_config.storage_config.mmap_file_config.max_size": 16777216, + "state_sync_config.storage_config.scope": "FullArchive", + "strk_fee_token_address": "0x1002", + "validator_id": "0x64", + "versioned_constants_overrides.invoke_tx_max_n_steps": 10000000, + "versioned_constants_overrides.max_n_events": 1000, + "versioned_constants_overrides.max_recursion_depth": 50, + "versioned_constants_overrides.validate_max_n_steps": 1000000 +} diff --git a/config/sequencer/presets/distributed_node/application_configs/class_manager.json b/config/sequencer/presets/distributed_node/application_configs/class_manager.json new file mode 100644 index 00000000000..070c30de2f5 --- /dev/null +++ b/config/sequencer/presets/distributed_node/application_configs/class_manager.json @@ -0,0 +1,306 @@ +{ + "base_layer_config.node_url": "http://localhost:53260/", + "base_layer_config.starknet_contract_address": "0x5FbDB2315678afecb367f032d93F642f64180aa3", + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.l1_gas": 2500000, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.message_segment_length": 3700, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.n_events": 5000, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.sierra_gas": 30000000, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.state_diff_size": 4000, + "batcher_config.block_builder_config.execute_config.concurrency_config.chunk_size": 64, + "batcher_config.block_builder_config.execute_config.concurrency_config.enabled": true, + "batcher_config.block_builder_config.execute_config.concurrency_config.n_workers": 4, + "batcher_config.block_builder_config.execute_config.stack_size": 62914560, + "batcher_config.block_builder_config.tx_chunk_size": 100, + "batcher_config.contract_class_manager_config.cairo_native_run_config.channel_size": 2000, + "batcher_config.contract_class_manager_config.cairo_native_run_config.native_classes_whitelist": "All", + "batcher_config.contract_class_manager_config.cairo_native_run_config.run_cairo_native": false, + "batcher_config.contract_class_manager_config.cairo_native_run_config.wait_on_native_compilation": false, + "batcher_config.contract_class_manager_config.contract_cache_size": 600, + "batcher_config.contract_class_manager_config.native_compiler_config.max_casm_bytecode_size": 81920, + "batcher_config.contract_class_manager_config.native_compiler_config.max_cpu_time": 20, + "batcher_config.contract_class_manager_config.native_compiler_config.max_memory_usage": 5368709120, + "batcher_config.contract_class_manager_config.native_compiler_config.max_native_bytecode_size": 15728640, + "batcher_config.contract_class_manager_config.native_compiler_config.optimization_level": 2, + "batcher_config.contract_class_manager_config.native_compiler_config.panic_on_compilation_failure": false, + "batcher_config.contract_class_manager_config.native_compiler_config.sierra_to_native_compiler_path": "", + "batcher_config.contract_class_manager_config.native_compiler_config.sierra_to_native_compiler_path.#is_none": true, + "batcher_config.input_stream_content_buffer_size": 400, + "batcher_config.max_l1_handler_txs_per_block_proposal": 3, + "batcher_config.outstream_content_buffer_size": 100, + "batcher_config.storage.db_config.enforce_file_exists": false, + "batcher_config.storage.db_config.growth_step": 67108864, + "batcher_config.storage.db_config.max_size": 34359738368, + "batcher_config.storage.db_config.min_size": 1048576, + "batcher_config.storage.db_config.path_prefix": "/data/node_0/executable_0/batcher", + "batcher_config.storage.mmap_file_config.growth_step": 1048576, + "batcher_config.storage.mmap_file_config.max_object_size": 65536, + "batcher_config.storage.mmap_file_config.max_size": 16777216, + "batcher_config.storage.scope": "StateOnly", + "chain_id": "CHAIN_ID_SUBDIR", + "class_manager_config.class_manager_config.cached_class_storage_config.class_cache_size": 100, + "class_manager_config.class_manager_config.cached_class_storage_config.deprecated_class_cache_size": 100, + "class_manager_config.class_storage_config.class_hash_storage_config.enforce_file_exists": false, + "class_manager_config.class_storage_config.class_hash_storage_config.max_size": 1048576, + "class_manager_config.class_storage_config.class_hash_storage_config.path_prefix": "/data/node_0/executable_0/class_manager/class_hash_storage", + "class_manager_config.class_storage_config.persistent_root": "/data/node_0/executable_0/class_manager/classes", + "compiler_config.max_casm_bytecode_size": 81920, + "compiler_config.max_cpu_time": 20, + "compiler_config.max_memory_usage": 5368709120, + "compiler_config.max_native_bytecode_size": 15728640, + "compiler_config.optimization_level": 2, + "compiler_config.panic_on_compilation_failure": false, + "compiler_config.sierra_to_native_compiler_path": "", + "compiler_config.sierra_to_native_compiler_path.#is_none": true, + "components.batcher.execution_mode": "Disabled", + "components.batcher.ip": "0.0.0.0", + "components.batcher.local_server_config.channel_buffer_size": 32, + "components.batcher.max_concurrency": 10, + "components.batcher.port": 0, + "components.batcher.remote_client_config.idle_connections": 18446744073709551615, + "components.batcher.remote_client_config.idle_timeout": 90, + "components.batcher.remote_client_config.retries": 3, + "components.batcher.remote_client_config.retry_interval": 3, + "components.batcher.url": "localhost", + "components.class_manager.execution_mode": "LocalExecutionWithRemoteEnabled", + "components.class_manager.ip": "0.0.0.0", + "components.class_manager.local_server_config.channel_buffer_size": 32, + "components.class_manager.max_concurrency": 10, + "components.class_manager.port": 55001, + "components.class_manager.remote_client_config.idle_connections": 18446744073709551615, + "components.class_manager.remote_client_config.idle_timeout": 90, + "components.class_manager.remote_client_config.retries": 3, + "components.class_manager.remote_client_config.retry_interval": 3, + "components.class_manager.url": "sequencer-class-manager-service", + "components.consensus_manager.execution_mode": "Disabled", + "components.gateway.execution_mode": "Disabled", + "components.gateway.ip": "0.0.0.0", + "components.gateway.local_server_config.channel_buffer_size": 32, + "components.gateway.max_concurrency": 10, + "components.gateway.port": 0, + "components.gateway.remote_client_config.idle_connections": 18446744073709551615, + "components.gateway.remote_client_config.idle_timeout": 90, + "components.gateway.remote_client_config.retries": 3, + "components.gateway.remote_client_config.retry_interval": 3, + "components.gateway.url": "localhost", + "components.http_server.execution_mode": "Disabled", + "components.l1_gas_price_provider.execution_mode": "Disabled", + "components.l1_gas_price_provider.ip": "0.0.0.0", + "components.l1_gas_price_provider.local_server_config.channel_buffer_size": 32, + "components.l1_gas_price_provider.max_concurrency": 10, + "components.l1_gas_price_provider.port": 0, + "components.l1_gas_price_provider.remote_client_config.idle_connections": 18446744073709551615, + "components.l1_gas_price_provider.remote_client_config.idle_timeout": 90, + "components.l1_gas_price_provider.remote_client_config.retries": 3, + "components.l1_gas_price_provider.remote_client_config.retry_interval": 3, + "components.l1_gas_price_provider.url": "localhost", + "components.l1_gas_price_scraper.execution_mode": "Disabled", + "components.l1_provider.execution_mode": "Disabled", + "components.l1_provider.ip": "0.0.0.0", + "components.l1_provider.local_server_config.channel_buffer_size": 32, + "components.l1_provider.max_concurrency": 10, + "components.l1_provider.port": 0, + "components.l1_provider.remote_client_config.idle_connections": 18446744073709551615, + "components.l1_provider.remote_client_config.idle_timeout": 90, + "components.l1_provider.remote_client_config.retries": 3, + "components.l1_provider.remote_client_config.retry_interval": 3, + "components.l1_provider.url": "localhost", + "components.l1_scraper.execution_mode": "Disabled", + "components.mempool.execution_mode": "Disabled", + "components.mempool.ip": "0.0.0.0", + "components.mempool.local_server_config.channel_buffer_size": 32, + "components.mempool.max_concurrency": 10, + "components.mempool.port": 0, + "components.mempool.remote_client_config.idle_connections": 18446744073709551615, + "components.mempool.remote_client_config.idle_timeout": 90, + "components.mempool.remote_client_config.retries": 3, + "components.mempool.remote_client_config.retry_interval": 3, + "components.mempool.url": "localhost", + "components.mempool_p2p.execution_mode": "Disabled", + "components.mempool_p2p.ip": "0.0.0.0", + "components.mempool_p2p.local_server_config.channel_buffer_size": 32, + "components.mempool_p2p.max_concurrency": 10, + "components.mempool_p2p.port": 0, + "components.mempool_p2p.remote_client_config.idle_connections": 18446744073709551615, + "components.mempool_p2p.remote_client_config.idle_timeout": 90, + "components.mempool_p2p.remote_client_config.retries": 3, + "components.mempool_p2p.remote_client_config.retry_interval": 3, + "components.mempool_p2p.url": "localhost", + "components.monitoring_endpoint.execution_mode": "Enabled", + "components.sierra_compiler.execution_mode": "Remote", + "components.sierra_compiler.ip": "0.0.0.0", + "components.sierra_compiler.local_server_config.channel_buffer_size": 32, + "components.sierra_compiler.max_concurrency": 10, + "components.sierra_compiler.port": 55007, + "components.sierra_compiler.remote_client_config.idle_connections": 18446744073709551615, + "components.sierra_compiler.remote_client_config.idle_timeout": 90, + "components.sierra_compiler.remote_client_config.retries": 3, + "components.sierra_compiler.remote_client_config.retry_interval": 3, + "components.sierra_compiler.url": "sequencer-sierra-compiler-service", + "components.state_sync.execution_mode": "Disabled", + "components.state_sync.ip": "0.0.0.0", + "components.state_sync.local_server_config.channel_buffer_size": 32, + "components.state_sync.max_concurrency": 10, + "components.state_sync.port": 0, + "components.state_sync.remote_client_config.idle_connections": 18446744073709551615, + "components.state_sync.remote_client_config.idle_timeout": 90, + "components.state_sync.remote_client_config.retries": 3, + "components.state_sync.remote_client_config.retry_interval": 3, + "components.state_sync.url": "localhost", + "consensus_manager_config.broadcast_buffer_size": 10000, + "consensus_manager_config.cende_config.skip_write_height": 1, + "consensus_manager_config.cende_config.skip_write_height.#is_none": false, + "consensus_manager_config.consensus_config.future_height_limit": 10, + "consensus_manager_config.consensus_config.future_height_round_limit": 1, + "consensus_manager_config.consensus_config.future_round_limit": 10, + "consensus_manager_config.consensus_config.startup_delay": 15, + "consensus_manager_config.consensus_config.sync_retry_interval": 1.0, + "consensus_manager_config.consensus_config.timeouts.precommit_timeout": 3.0, + "consensus_manager_config.consensus_config.timeouts.prevote_timeout": 3.0, + "consensus_manager_config.consensus_config.timeouts.proposal_timeout": 9.0, + "consensus_manager_config.context_config.block_timestamp_window": 1, + "consensus_manager_config.context_config.build_proposal_margin": 1000, + "consensus_manager_config.context_config.builder_address": "0x4", + "consensus_manager_config.context_config.l1_da_mode": true, + "consensus_manager_config.context_config.num_validators": 1, + "consensus_manager_config.context_config.proposal_buffer_size": 100, + "consensus_manager_config.context_config.validate_proposal_margin": 10000, + "consensus_manager_config.eth_to_strk_oracle_config.base_url": "http://127.0.0.1:53262/eth_to_strk_oracle?timestamp=", + "consensus_manager_config.eth_to_strk_oracle_config.headers": "", + "consensus_manager_config.immediate_active_height": 1, + "consensus_manager_config.network_config.advertised_multiaddr": "", + "consensus_manager_config.network_config.advertised_multiaddr.#is_none": true, + "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "", + "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": true, + "consensus_manager_config.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": 2, + "consensus_manager_config.network_config.discovery_config.bootstrap_dial_retry_config.factor": 5, + "consensus_manager_config.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": 5, + "consensus_manager_config.network_config.discovery_config.heartbeat_interval": 100, + "consensus_manager_config.network_config.idle_connection_timeout": 120, + "consensus_manager_config.network_config.peer_manager_config.malicious_timeout_seconds": 1, + "consensus_manager_config.network_config.peer_manager_config.unstable_timeout_millis": 1000, + "consensus_manager_config.network_config.port": 53080, + "consensus_manager_config.network_config.secret_key": "0x0101010101010101010101010101010101010101010101010101010101010101", + "consensus_manager_config.network_config.session_timeout": 120, + "consensus_manager_config.proposals_topic": "consensus_proposals", + "consensus_manager_config.votes_topic": "consensus_votes", + "eth_fee_token_address": "0x1001", + "gateway_config.stateful_tx_validator_config.max_allowed_nonce_gap": 50, + "gateway_config.stateful_tx_validator_config.max_nonce_for_validation_skip": "0x1", + "gateway_config.stateless_tx_validator_config.max_calldata_length": 10, + "gateway_config.stateless_tx_validator_config.max_contract_class_object_size": 4089446, + "gateway_config.stateless_tx_validator_config.max_sierra_version.major": 1, + "gateway_config.stateless_tx_validator_config.max_sierra_version.minor": 5, + "gateway_config.stateless_tx_validator_config.max_sierra_version.patch": 18446744073709551615, + "gateway_config.stateless_tx_validator_config.max_signature_length": 2, + "gateway_config.stateless_tx_validator_config.min_sierra_version.major": 1, + "gateway_config.stateless_tx_validator_config.min_sierra_version.minor": 1, + "gateway_config.stateless_tx_validator_config.min_sierra_version.patch": 0, + "gateway_config.stateless_tx_validator_config.validate_non_zero_l1_data_gas_fee": false, + "gateway_config.stateless_tx_validator_config.validate_non_zero_l1_gas_fee": true, + "gateway_config.stateless_tx_validator_config.validate_non_zero_l2_gas_fee": false, + "http_server_config.ip": "127.0.0.1", + "http_server_config.port": 53320, + "l1_gas_price_provider_config.lag_margin_seconds": 60, + "l1_gas_price_provider_config.number_of_blocks_for_mean": 300, + "l1_gas_price_provider_config.storage_limit": 3000, + "l1_gas_price_scraper_config.finality": 0, + "l1_gas_price_scraper_config.number_of_blocks_for_mean": 300, + "l1_gas_price_scraper_config.polling_interval": 1, + "l1_gas_price_scraper_config.starting_block": 0, + "l1_gas_price_scraper_config.starting_block.#is_none": true, + "l1_provider_config.bootstrap_catch_up_height_override": 0, + "l1_provider_config.bootstrap_catch_up_height_override.#is_none": true, + "l1_provider_config.provider_startup_height_override": 1, + "l1_provider_config.provider_startup_height_override.#is_none": false, + "l1_provider_config.startup_sync_sleep_retry_interval": 0.0, + "l1_scraper_config.finality": 0, + "l1_scraper_config.polling_interval": 1, + "l1_scraper_config.startup_rewind_time": 0, + "mempool_config.committed_nonce_retention_block_count": 100, + "mempool_config.declare_delay": 1, + "mempool_config.enable_fee_escalation": true, + "mempool_config.fee_escalation_percentage": 10, + "mempool_config.transaction_ttl": 300, + "mempool_p2p_config.max_transaction_batch_size": 1, + "mempool_p2p_config.network_buffer_size": 10000, + "mempool_p2p_config.network_config.advertised_multiaddr": "", + "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": true, + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "", + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": true, + "mempool_p2p_config.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": 2, + "mempool_p2p_config.network_config.discovery_config.bootstrap_dial_retry_config.factor": 5, + "mempool_p2p_config.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": 5, + "mempool_p2p_config.network_config.discovery_config.heartbeat_interval": 100, + "mempool_p2p_config.network_config.idle_connection_timeout": 120, + "mempool_p2p_config.network_config.peer_manager_config.malicious_timeout_seconds": 1, + "mempool_p2p_config.network_config.peer_manager_config.unstable_timeout_millis": 1000, + "mempool_p2p_config.network_config.port": 53200, + "mempool_p2p_config.network_config.secret_key": "0x0101010101010101010101010101010101010101010101010101010101010101", + "mempool_p2p_config.network_config.session_timeout": 120, + "mempool_p2p_config.transaction_batch_rate_millis": 1000, + "monitoring_config.collect_metrics": true, + "monitoring_config.collect_profiling_metrics": true, + "monitoring_endpoint_config.collect_metrics": true, + "monitoring_endpoint_config.collect_profiling_metrics": true, + "monitoring_endpoint_config.ip": "0.0.0.0", + "monitoring_endpoint_config.port": 8082, + "recorder_url": "http://127.0.0.1:53261/", + "revert_config.revert_up_to_and_including": 18446744073709551615, + "revert_config.should_revert": false, + "state_sync_config.central_sync_client_config.#is_none": true, + "state_sync_config.central_sync_client_config.central_source_config.class_cache_size": 100, + "state_sync_config.central_sync_client_config.central_source_config.concurrent_requests": 10, + "state_sync_config.central_sync_client_config.central_source_config.http_headers": "", + "state_sync_config.central_sync_client_config.central_source_config.max_classes_to_download": 20, + "state_sync_config.central_sync_client_config.central_source_config.max_state_updates_to_download": 20, + "state_sync_config.central_sync_client_config.central_source_config.max_state_updates_to_store_in_memory": 20, + "state_sync_config.central_sync_client_config.central_source_config.retry_config.max_retries": 10, + "state_sync_config.central_sync_client_config.central_source_config.retry_config.retry_base_millis": 30, + "state_sync_config.central_sync_client_config.central_source_config.retry_config.retry_max_delay_millis": 30000, + "state_sync_config.central_sync_client_config.central_source_config.starknet_url": "https://alpha-mainnet.starknet.io/", + "state_sync_config.central_sync_client_config.sync_config.base_layer_propagation_sleep_duration": 10, + "state_sync_config.central_sync_client_config.sync_config.block_propagation_sleep_duration": 2, + "state_sync_config.central_sync_client_config.sync_config.blocks_max_stream_size": 1000, + "state_sync_config.central_sync_client_config.sync_config.collect_pending_data": false, + "state_sync_config.central_sync_client_config.sync_config.recoverable_error_sleep_duration": 3, + "state_sync_config.central_sync_client_config.sync_config.state_updates_max_stream_size": 1000, + "state_sync_config.central_sync_client_config.sync_config.store_sierras_and_casms": false, + "state_sync_config.central_sync_client_config.sync_config.verify_blocks": true, + "state_sync_config.network_config.advertised_multiaddr": "", + "state_sync_config.network_config.advertised_multiaddr.#is_none": true, + "state_sync_config.network_config.bootstrap_peer_multiaddr": "", + "state_sync_config.network_config.bootstrap_peer_multiaddr.#is_none": true, + "state_sync_config.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": 2, + "state_sync_config.network_config.discovery_config.bootstrap_dial_retry_config.factor": 5, + "state_sync_config.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": 5, + "state_sync_config.network_config.discovery_config.heartbeat_interval": 100, + "state_sync_config.network_config.idle_connection_timeout": 120, + "state_sync_config.network_config.peer_manager_config.malicious_timeout_seconds": 1, + "state_sync_config.network_config.peer_manager_config.unstable_timeout_millis": 1000, + "state_sync_config.network_config.port": 53140, + "state_sync_config.network_config.secret_key": "0x0101010101010101010101010101010101010101010101010101010101010101", + "state_sync_config.network_config.session_timeout": 120, + "state_sync_config.p2p_sync_client_config.#is_none": false, + "state_sync_config.p2p_sync_client_config.buffer_size": 100000, + "state_sync_config.p2p_sync_client_config.num_block_classes_per_query": 100, + "state_sync_config.p2p_sync_client_config.num_block_state_diffs_per_query": 100, + "state_sync_config.p2p_sync_client_config.num_block_transactions_per_query": 100, + "state_sync_config.p2p_sync_client_config.num_headers_per_query": 10000, + "state_sync_config.p2p_sync_client_config.wait_period_for_new_data": 50, + "state_sync_config.p2p_sync_client_config.wait_period_for_other_protocol": 50, + "state_sync_config.storage_config.db_config.enforce_file_exists": false, + "state_sync_config.storage_config.db_config.growth_step": 67108864, + "state_sync_config.storage_config.db_config.max_size": 34359738368, + "state_sync_config.storage_config.db_config.min_size": 1048576, + "state_sync_config.storage_config.db_config.path_prefix": "/data/node_0/executable_0/state_sync", + "state_sync_config.storage_config.mmap_file_config.growth_step": 1048576, + "state_sync_config.storage_config.mmap_file_config.max_object_size": 65536, + "state_sync_config.storage_config.mmap_file_config.max_size": 16777216, + "state_sync_config.storage_config.scope": "FullArchive", + "strk_fee_token_address": "0x1002", + "validator_id": "0x64", + "versioned_constants_overrides.invoke_tx_max_n_steps": 10000000, + "versioned_constants_overrides.max_n_events": 1000, + "versioned_constants_overrides.max_recursion_depth": 50, + "versioned_constants_overrides.validate_max_n_steps": 1000000 +} diff --git a/config/sequencer/presets/distributed_node/application_configs/consensus_manager.json b/config/sequencer/presets/distributed_node/application_configs/consensus_manager.json new file mode 100644 index 00000000000..dc0bb948229 --- /dev/null +++ b/config/sequencer/presets/distributed_node/application_configs/consensus_manager.json @@ -0,0 +1,306 @@ +{ + "base_layer_config.node_url": "http://localhost:53260/", + "base_layer_config.starknet_contract_address": "0x5FbDB2315678afecb367f032d93F642f64180aa3", + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.l1_gas": 2500000, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.message_segment_length": 3700, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.n_events": 5000, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.sierra_gas": 30000000, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.state_diff_size": 4000, + "batcher_config.block_builder_config.execute_config.concurrency_config.chunk_size": 64, + "batcher_config.block_builder_config.execute_config.concurrency_config.enabled": true, + "batcher_config.block_builder_config.execute_config.concurrency_config.n_workers": 4, + "batcher_config.block_builder_config.execute_config.stack_size": 62914560, + "batcher_config.block_builder_config.tx_chunk_size": 100, + "batcher_config.contract_class_manager_config.cairo_native_run_config.channel_size": 2000, + "batcher_config.contract_class_manager_config.cairo_native_run_config.native_classes_whitelist": "All", + "batcher_config.contract_class_manager_config.cairo_native_run_config.run_cairo_native": false, + "batcher_config.contract_class_manager_config.cairo_native_run_config.wait_on_native_compilation": false, + "batcher_config.contract_class_manager_config.contract_cache_size": 600, + "batcher_config.contract_class_manager_config.native_compiler_config.max_casm_bytecode_size": 81920, + "batcher_config.contract_class_manager_config.native_compiler_config.max_cpu_time": 20, + "batcher_config.contract_class_manager_config.native_compiler_config.max_memory_usage": 5368709120, + "batcher_config.contract_class_manager_config.native_compiler_config.max_native_bytecode_size": 15728640, + "batcher_config.contract_class_manager_config.native_compiler_config.optimization_level": 2, + "batcher_config.contract_class_manager_config.native_compiler_config.panic_on_compilation_failure": false, + "batcher_config.contract_class_manager_config.native_compiler_config.sierra_to_native_compiler_path": "", + "batcher_config.contract_class_manager_config.native_compiler_config.sierra_to_native_compiler_path.#is_none": true, + "batcher_config.input_stream_content_buffer_size": 400, + "batcher_config.max_l1_handler_txs_per_block_proposal": 3, + "batcher_config.outstream_content_buffer_size": 100, + "batcher_config.storage.db_config.enforce_file_exists": false, + "batcher_config.storage.db_config.growth_step": 67108864, + "batcher_config.storage.db_config.max_size": 34359738368, + "batcher_config.storage.db_config.min_size": 1048576, + "batcher_config.storage.db_config.path_prefix": "/data/node_0/executable_0/batcher", + "batcher_config.storage.mmap_file_config.growth_step": 1048576, + "batcher_config.storage.mmap_file_config.max_object_size": 65536, + "batcher_config.storage.mmap_file_config.max_size": 16777216, + "batcher_config.storage.scope": "StateOnly", + "chain_id": "CHAIN_ID_SUBDIR", + "class_manager_config.class_manager_config.cached_class_storage_config.class_cache_size": 100, + "class_manager_config.class_manager_config.cached_class_storage_config.deprecated_class_cache_size": 100, + "class_manager_config.class_storage_config.class_hash_storage_config.enforce_file_exists": false, + "class_manager_config.class_storage_config.class_hash_storage_config.max_size": 1048576, + "class_manager_config.class_storage_config.class_hash_storage_config.path_prefix": "/data/node_0/executable_0/class_manager/class_hash_storage", + "class_manager_config.class_storage_config.persistent_root": "/data/node_0/executable_0/class_manager/classes", + "compiler_config.max_casm_bytecode_size": 81920, + "compiler_config.max_cpu_time": 20, + "compiler_config.max_memory_usage": 5368709120, + "compiler_config.max_native_bytecode_size": 15728640, + "compiler_config.optimization_level": 2, + "compiler_config.panic_on_compilation_failure": false, + "compiler_config.sierra_to_native_compiler_path": "", + "compiler_config.sierra_to_native_compiler_path.#is_none": true, + "components.batcher.execution_mode": "Remote", + "components.batcher.ip": "0.0.0.0", + "components.batcher.local_server_config.channel_buffer_size": 32, + "components.batcher.max_concurrency": 10, + "components.batcher.port": 55000, + "components.batcher.remote_client_config.idle_connections": 18446744073709551615, + "components.batcher.remote_client_config.idle_timeout": 90, + "components.batcher.remote_client_config.retries": 3, + "components.batcher.remote_client_config.retry_interval": 3, + "components.batcher.url": "sequencer-batcher-service", + "components.class_manager.execution_mode": "Remote", + "components.class_manager.ip": "0.0.0.0", + "components.class_manager.local_server_config.channel_buffer_size": 32, + "components.class_manager.max_concurrency": 10, + "components.class_manager.port": 55001, + "components.class_manager.remote_client_config.idle_connections": 18446744073709551615, + "components.class_manager.remote_client_config.idle_timeout": 90, + "components.class_manager.remote_client_config.retries": 3, + "components.class_manager.remote_client_config.retry_interval": 3, + "components.class_manager.url": "sequencer-class-manager-service", + "components.consensus_manager.execution_mode": "Enabled", + "components.gateway.execution_mode": "Disabled", + "components.gateway.ip": "0.0.0.0", + "components.gateway.local_server_config.channel_buffer_size": 32, + "components.gateway.max_concurrency": 10, + "components.gateway.port": 0, + "components.gateway.remote_client_config.idle_connections": 18446744073709551615, + "components.gateway.remote_client_config.idle_timeout": 90, + "components.gateway.remote_client_config.retries": 3, + "components.gateway.remote_client_config.retry_interval": 3, + "components.gateway.url": "localhost", + "components.http_server.execution_mode": "Disabled", + "components.l1_gas_price_provider.execution_mode": "Disabled", + "components.l1_gas_price_provider.ip": "0.0.0.0", + "components.l1_gas_price_provider.local_server_config.channel_buffer_size": 32, + "components.l1_gas_price_provider.max_concurrency": 10, + "components.l1_gas_price_provider.port": 0, + "components.l1_gas_price_provider.remote_client_config.idle_connections": 18446744073709551615, + "components.l1_gas_price_provider.remote_client_config.idle_timeout": 90, + "components.l1_gas_price_provider.remote_client_config.retries": 3, + "components.l1_gas_price_provider.remote_client_config.retry_interval": 3, + "components.l1_gas_price_provider.url": "localhost", + "components.l1_gas_price_scraper.execution_mode": "Disabled", + "components.l1_provider.execution_mode": "Disabled", + "components.l1_provider.ip": "0.0.0.0", + "components.l1_provider.local_server_config.channel_buffer_size": 32, + "components.l1_provider.max_concurrency": 10, + "components.l1_provider.port": 0, + "components.l1_provider.remote_client_config.idle_connections": 18446744073709551615, + "components.l1_provider.remote_client_config.idle_timeout": 90, + "components.l1_provider.remote_client_config.retries": 3, + "components.l1_provider.remote_client_config.retry_interval": 3, + "components.l1_provider.url": "localhost", + "components.l1_scraper.execution_mode": "Disabled", + "components.mempool.execution_mode": "Disabled", + "components.mempool.ip": "0.0.0.0", + "components.mempool.local_server_config.channel_buffer_size": 32, + "components.mempool.max_concurrency": 10, + "components.mempool.port": 0, + "components.mempool.remote_client_config.idle_connections": 18446744073709551615, + "components.mempool.remote_client_config.idle_timeout": 90, + "components.mempool.remote_client_config.retries": 3, + "components.mempool.remote_client_config.retry_interval": 3, + "components.mempool.url": "localhost", + "components.mempool_p2p.execution_mode": "Disabled", + "components.mempool_p2p.ip": "0.0.0.0", + "components.mempool_p2p.local_server_config.channel_buffer_size": 32, + "components.mempool_p2p.max_concurrency": 10, + "components.mempool_p2p.port": 0, + "components.mempool_p2p.remote_client_config.idle_connections": 18446744073709551615, + "components.mempool_p2p.remote_client_config.idle_timeout": 90, + "components.mempool_p2p.remote_client_config.retries": 3, + "components.mempool_p2p.remote_client_config.retry_interval": 3, + "components.mempool_p2p.url": "localhost", + "components.monitoring_endpoint.execution_mode": "Enabled", + "components.sierra_compiler.execution_mode": "Disabled", + "components.sierra_compiler.ip": "0.0.0.0", + "components.sierra_compiler.local_server_config.channel_buffer_size": 32, + "components.sierra_compiler.max_concurrency": 10, + "components.sierra_compiler.port": 0, + "components.sierra_compiler.remote_client_config.idle_connections": 18446744073709551615, + "components.sierra_compiler.remote_client_config.idle_timeout": 90, + "components.sierra_compiler.remote_client_config.retries": 3, + "components.sierra_compiler.remote_client_config.retry_interval": 3, + "components.sierra_compiler.url": "localhost", + "components.state_sync.execution_mode": "Remote", + "components.state_sync.ip": "0.0.0.0", + "components.state_sync.local_server_config.channel_buffer_size": 32, + "components.state_sync.max_concurrency": 10, + "components.state_sync.port": 55008, + "components.state_sync.remote_client_config.idle_connections": 18446744073709551615, + "components.state_sync.remote_client_config.idle_timeout": 90, + "components.state_sync.remote_client_config.retries": 3, + "components.state_sync.remote_client_config.retry_interval": 3, + "components.state_sync.url": "sequencer-state-sync-service", + "consensus_manager_config.broadcast_buffer_size": 10000, + "consensus_manager_config.cende_config.skip_write_height": 1, + "consensus_manager_config.cende_config.skip_write_height.#is_none": false, + "consensus_manager_config.consensus_config.future_height_limit": 10, + "consensus_manager_config.consensus_config.future_height_round_limit": 1, + "consensus_manager_config.consensus_config.future_round_limit": 10, + "consensus_manager_config.consensus_config.startup_delay": 15, + "consensus_manager_config.consensus_config.sync_retry_interval": 1.0, + "consensus_manager_config.consensus_config.timeouts.precommit_timeout": 3.0, + "consensus_manager_config.consensus_config.timeouts.prevote_timeout": 3.0, + "consensus_manager_config.consensus_config.timeouts.proposal_timeout": 9.0, + "consensus_manager_config.context_config.block_timestamp_window": 1, + "consensus_manager_config.context_config.build_proposal_margin": 1000, + "consensus_manager_config.context_config.builder_address": "0x4", + "consensus_manager_config.context_config.l1_da_mode": true, + "consensus_manager_config.context_config.num_validators": 1, + "consensus_manager_config.context_config.proposal_buffer_size": 100, + "consensus_manager_config.context_config.validate_proposal_margin": 10000, + "consensus_manager_config.eth_to_strk_oracle_config.base_url": "http://127.0.0.1:53262/eth_to_strk_oracle?timestamp=", + "consensus_manager_config.eth_to_strk_oracle_config.headers": "", + "consensus_manager_config.immediate_active_height": 1, + "consensus_manager_config.network_config.advertised_multiaddr": "", + "consensus_manager_config.network_config.advertised_multiaddr.#is_none": true, + "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "", + "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": true, + "consensus_manager_config.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": 2, + "consensus_manager_config.network_config.discovery_config.bootstrap_dial_retry_config.factor": 5, + "consensus_manager_config.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": 5, + "consensus_manager_config.network_config.discovery_config.heartbeat_interval": 100, + "consensus_manager_config.network_config.idle_connection_timeout": 120, + "consensus_manager_config.network_config.peer_manager_config.malicious_timeout_seconds": 1, + "consensus_manager_config.network_config.peer_manager_config.unstable_timeout_millis": 1000, + "consensus_manager_config.network_config.port": 53080, + "consensus_manager_config.network_config.secret_key": "0x0101010101010101010101010101010101010101010101010101010101010101", + "consensus_manager_config.network_config.session_timeout": 120, + "consensus_manager_config.proposals_topic": "consensus_proposals", + "consensus_manager_config.votes_topic": "consensus_votes", + "eth_fee_token_address": "0x1001", + "gateway_config.stateful_tx_validator_config.max_allowed_nonce_gap": 50, + "gateway_config.stateful_tx_validator_config.max_nonce_for_validation_skip": "0x1", + "gateway_config.stateless_tx_validator_config.max_calldata_length": 10, + "gateway_config.stateless_tx_validator_config.max_contract_class_object_size": 4089446, + "gateway_config.stateless_tx_validator_config.max_sierra_version.major": 1, + "gateway_config.stateless_tx_validator_config.max_sierra_version.minor": 5, + "gateway_config.stateless_tx_validator_config.max_sierra_version.patch": 18446744073709551615, + "gateway_config.stateless_tx_validator_config.max_signature_length": 2, + "gateway_config.stateless_tx_validator_config.min_sierra_version.major": 1, + "gateway_config.stateless_tx_validator_config.min_sierra_version.minor": 1, + "gateway_config.stateless_tx_validator_config.min_sierra_version.patch": 0, + "gateway_config.stateless_tx_validator_config.validate_non_zero_l1_data_gas_fee": false, + "gateway_config.stateless_tx_validator_config.validate_non_zero_l1_gas_fee": true, + "gateway_config.stateless_tx_validator_config.validate_non_zero_l2_gas_fee": false, + "http_server_config.ip": "127.0.0.1", + "http_server_config.port": 53320, + "l1_gas_price_provider_config.lag_margin_seconds": 60, + "l1_gas_price_provider_config.number_of_blocks_for_mean": 300, + "l1_gas_price_provider_config.storage_limit": 3000, + "l1_gas_price_scraper_config.finality": 0, + "l1_gas_price_scraper_config.number_of_blocks_for_mean": 300, + "l1_gas_price_scraper_config.polling_interval": 1, + "l1_gas_price_scraper_config.starting_block": 0, + "l1_gas_price_scraper_config.starting_block.#is_none": true, + "l1_provider_config.bootstrap_catch_up_height_override": 0, + "l1_provider_config.bootstrap_catch_up_height_override.#is_none": true, + "l1_provider_config.provider_startup_height_override": 1, + "l1_provider_config.provider_startup_height_override.#is_none": false, + "l1_provider_config.startup_sync_sleep_retry_interval": 0.0, + "l1_scraper_config.finality": 0, + "l1_scraper_config.polling_interval": 1, + "l1_scraper_config.startup_rewind_time": 0, + "mempool_config.committed_nonce_retention_block_count": 100, + "mempool_config.declare_delay": 1, + "mempool_config.enable_fee_escalation": true, + "mempool_config.fee_escalation_percentage": 10, + "mempool_config.transaction_ttl": 300, + "mempool_p2p_config.max_transaction_batch_size": 1, + "mempool_p2p_config.network_buffer_size": 10000, + "mempool_p2p_config.network_config.advertised_multiaddr": "", + "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": true, + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "", + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": true, + "mempool_p2p_config.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": 2, + "mempool_p2p_config.network_config.discovery_config.bootstrap_dial_retry_config.factor": 5, + "mempool_p2p_config.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": 5, + "mempool_p2p_config.network_config.discovery_config.heartbeat_interval": 100, + "mempool_p2p_config.network_config.idle_connection_timeout": 120, + "mempool_p2p_config.network_config.peer_manager_config.malicious_timeout_seconds": 1, + "mempool_p2p_config.network_config.peer_manager_config.unstable_timeout_millis": 1000, + "mempool_p2p_config.network_config.port": 53200, + "mempool_p2p_config.network_config.secret_key": "0x0101010101010101010101010101010101010101010101010101010101010101", + "mempool_p2p_config.network_config.session_timeout": 120, + "mempool_p2p_config.transaction_batch_rate_millis": 1000, + "monitoring_config.collect_metrics": true, + "monitoring_config.collect_profiling_metrics": true, + "monitoring_endpoint_config.collect_metrics": true, + "monitoring_endpoint_config.collect_profiling_metrics": true, + "monitoring_endpoint_config.ip": "0.0.0.0", + "monitoring_endpoint_config.port": 8082, + "recorder_url": "http://127.0.0.1:53261/", + "revert_config.revert_up_to_and_including": 18446744073709551615, + "revert_config.should_revert": false, + "state_sync_config.central_sync_client_config.#is_none": true, + "state_sync_config.central_sync_client_config.central_source_config.class_cache_size": 100, + "state_sync_config.central_sync_client_config.central_source_config.concurrent_requests": 10, + "state_sync_config.central_sync_client_config.central_source_config.http_headers": "", + "state_sync_config.central_sync_client_config.central_source_config.max_classes_to_download": 20, + "state_sync_config.central_sync_client_config.central_source_config.max_state_updates_to_download": 20, + "state_sync_config.central_sync_client_config.central_source_config.max_state_updates_to_store_in_memory": 20, + "state_sync_config.central_sync_client_config.central_source_config.retry_config.max_retries": 10, + "state_sync_config.central_sync_client_config.central_source_config.retry_config.retry_base_millis": 30, + "state_sync_config.central_sync_client_config.central_source_config.retry_config.retry_max_delay_millis": 30000, + "state_sync_config.central_sync_client_config.central_source_config.starknet_url": "https://alpha-mainnet.starknet.io/", + "state_sync_config.central_sync_client_config.sync_config.base_layer_propagation_sleep_duration": 10, + "state_sync_config.central_sync_client_config.sync_config.block_propagation_sleep_duration": 2, + "state_sync_config.central_sync_client_config.sync_config.blocks_max_stream_size": 1000, + "state_sync_config.central_sync_client_config.sync_config.collect_pending_data": false, + "state_sync_config.central_sync_client_config.sync_config.recoverable_error_sleep_duration": 3, + "state_sync_config.central_sync_client_config.sync_config.state_updates_max_stream_size": 1000, + "state_sync_config.central_sync_client_config.sync_config.store_sierras_and_casms": false, + "state_sync_config.central_sync_client_config.sync_config.verify_blocks": true, + "state_sync_config.network_config.advertised_multiaddr": "", + "state_sync_config.network_config.advertised_multiaddr.#is_none": true, + "state_sync_config.network_config.bootstrap_peer_multiaddr": "", + "state_sync_config.network_config.bootstrap_peer_multiaddr.#is_none": true, + "state_sync_config.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": 2, + "state_sync_config.network_config.discovery_config.bootstrap_dial_retry_config.factor": 5, + "state_sync_config.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": 5, + "state_sync_config.network_config.discovery_config.heartbeat_interval": 100, + "state_sync_config.network_config.idle_connection_timeout": 120, + "state_sync_config.network_config.peer_manager_config.malicious_timeout_seconds": 1, + "state_sync_config.network_config.peer_manager_config.unstable_timeout_millis": 1000, + "state_sync_config.network_config.port": 53140, + "state_sync_config.network_config.secret_key": "0x0101010101010101010101010101010101010101010101010101010101010101", + "state_sync_config.network_config.session_timeout": 120, + "state_sync_config.p2p_sync_client_config.#is_none": false, + "state_sync_config.p2p_sync_client_config.buffer_size": 100000, + "state_sync_config.p2p_sync_client_config.num_block_classes_per_query": 100, + "state_sync_config.p2p_sync_client_config.num_block_state_diffs_per_query": 100, + "state_sync_config.p2p_sync_client_config.num_block_transactions_per_query": 100, + "state_sync_config.p2p_sync_client_config.num_headers_per_query": 10000, + "state_sync_config.p2p_sync_client_config.wait_period_for_new_data": 50, + "state_sync_config.p2p_sync_client_config.wait_period_for_other_protocol": 50, + "state_sync_config.storage_config.db_config.enforce_file_exists": false, + "state_sync_config.storage_config.db_config.growth_step": 67108864, + "state_sync_config.storage_config.db_config.max_size": 34359738368, + "state_sync_config.storage_config.db_config.min_size": 1048576, + "state_sync_config.storage_config.db_config.path_prefix": "/data/node_0/executable_0/state_sync", + "state_sync_config.storage_config.mmap_file_config.growth_step": 1048576, + "state_sync_config.storage_config.mmap_file_config.max_object_size": 65536, + "state_sync_config.storage_config.mmap_file_config.max_size": 16777216, + "state_sync_config.storage_config.scope": "FullArchive", + "strk_fee_token_address": "0x1002", + "validator_id": "0x64", + "versioned_constants_overrides.invoke_tx_max_n_steps": 10000000, + "versioned_constants_overrides.max_n_events": 1000, + "versioned_constants_overrides.max_recursion_depth": 50, + "versioned_constants_overrides.validate_max_n_steps": 1000000 +} diff --git a/config/sequencer/presets/distributed_node/application_configs/gateway.json b/config/sequencer/presets/distributed_node/application_configs/gateway.json new file mode 100644 index 00000000000..eff6fc45fe4 --- /dev/null +++ b/config/sequencer/presets/distributed_node/application_configs/gateway.json @@ -0,0 +1,306 @@ +{ + "base_layer_config.node_url": "http://localhost:53260/", + "base_layer_config.starknet_contract_address": "0x5FbDB2315678afecb367f032d93F642f64180aa3", + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.l1_gas": 2500000, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.message_segment_length": 3700, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.n_events": 5000, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.sierra_gas": 30000000, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.state_diff_size": 4000, + "batcher_config.block_builder_config.execute_config.concurrency_config.chunk_size": 64, + "batcher_config.block_builder_config.execute_config.concurrency_config.enabled": true, + "batcher_config.block_builder_config.execute_config.concurrency_config.n_workers": 4, + "batcher_config.block_builder_config.execute_config.stack_size": 62914560, + "batcher_config.block_builder_config.tx_chunk_size": 100, + "batcher_config.contract_class_manager_config.cairo_native_run_config.channel_size": 2000, + "batcher_config.contract_class_manager_config.cairo_native_run_config.native_classes_whitelist": "All", + "batcher_config.contract_class_manager_config.cairo_native_run_config.run_cairo_native": false, + "batcher_config.contract_class_manager_config.cairo_native_run_config.wait_on_native_compilation": false, + "batcher_config.contract_class_manager_config.contract_cache_size": 600, + "batcher_config.contract_class_manager_config.native_compiler_config.max_casm_bytecode_size": 81920, + "batcher_config.contract_class_manager_config.native_compiler_config.max_cpu_time": 20, + "batcher_config.contract_class_manager_config.native_compiler_config.max_memory_usage": 5368709120, + "batcher_config.contract_class_manager_config.native_compiler_config.max_native_bytecode_size": 15728640, + "batcher_config.contract_class_manager_config.native_compiler_config.optimization_level": 2, + "batcher_config.contract_class_manager_config.native_compiler_config.panic_on_compilation_failure": false, + "batcher_config.contract_class_manager_config.native_compiler_config.sierra_to_native_compiler_path": "", + "batcher_config.contract_class_manager_config.native_compiler_config.sierra_to_native_compiler_path.#is_none": true, + "batcher_config.input_stream_content_buffer_size": 400, + "batcher_config.max_l1_handler_txs_per_block_proposal": 3, + "batcher_config.outstream_content_buffer_size": 100, + "batcher_config.storage.db_config.enforce_file_exists": false, + "batcher_config.storage.db_config.growth_step": 67108864, + "batcher_config.storage.db_config.max_size": 34359738368, + "batcher_config.storage.db_config.min_size": 1048576, + "batcher_config.storage.db_config.path_prefix": "/data/node_0/executable_0/batcher", + "batcher_config.storage.mmap_file_config.growth_step": 1048576, + "batcher_config.storage.mmap_file_config.max_object_size": 65536, + "batcher_config.storage.mmap_file_config.max_size": 16777216, + "batcher_config.storage.scope": "StateOnly", + "chain_id": "CHAIN_ID_SUBDIR", + "class_manager_config.class_manager_config.cached_class_storage_config.class_cache_size": 100, + "class_manager_config.class_manager_config.cached_class_storage_config.deprecated_class_cache_size": 100, + "class_manager_config.class_storage_config.class_hash_storage_config.enforce_file_exists": false, + "class_manager_config.class_storage_config.class_hash_storage_config.max_size": 1048576, + "class_manager_config.class_storage_config.class_hash_storage_config.path_prefix": "/data/node_0/executable_0/class_manager/class_hash_storage", + "class_manager_config.class_storage_config.persistent_root": "/data/node_0/executable_0/class_manager/classes", + "compiler_config.max_casm_bytecode_size": 81920, + "compiler_config.max_cpu_time": 20, + "compiler_config.max_memory_usage": 5368709120, + "compiler_config.max_native_bytecode_size": 15728640, + "compiler_config.optimization_level": 2, + "compiler_config.panic_on_compilation_failure": false, + "compiler_config.sierra_to_native_compiler_path": "", + "compiler_config.sierra_to_native_compiler_path.#is_none": true, + "components.batcher.execution_mode": "Disabled", + "components.batcher.ip": "0.0.0.0", + "components.batcher.local_server_config.channel_buffer_size": 32, + "components.batcher.max_concurrency": 10, + "components.batcher.port": 0, + "components.batcher.remote_client_config.idle_connections": 18446744073709551615, + "components.batcher.remote_client_config.idle_timeout": 90, + "components.batcher.remote_client_config.retries": 3, + "components.batcher.remote_client_config.retry_interval": 3, + "components.batcher.url": "localhost", + "components.class_manager.execution_mode": "Remote", + "components.class_manager.ip": "0.0.0.0", + "components.class_manager.local_server_config.channel_buffer_size": 32, + "components.class_manager.max_concurrency": 10, + "components.class_manager.port": 55001, + "components.class_manager.remote_client_config.idle_connections": 18446744073709551615, + "components.class_manager.remote_client_config.idle_timeout": 90, + "components.class_manager.remote_client_config.retries": 3, + "components.class_manager.remote_client_config.retry_interval": 3, + "components.class_manager.url": "sequencer-class-manager-service", + "components.consensus_manager.execution_mode": "Disabled", + "components.gateway.execution_mode": "LocalExecutionWithRemoteEnabled", + "components.gateway.ip": "0.0.0.0", + "components.gateway.local_server_config.channel_buffer_size": 32, + "components.gateway.max_concurrency": 10, + "components.gateway.port": 55004, + "components.gateway.remote_client_config.idle_connections": 18446744073709551615, + "components.gateway.remote_client_config.idle_timeout": 90, + "components.gateway.remote_client_config.retries": 3, + "components.gateway.remote_client_config.retry_interval": 3, + "components.gateway.url": "sequencer-gateway-service", + "components.http_server.execution_mode": "Disabled", + "components.l1_gas_price_provider.execution_mode": "Disabled", + "components.l1_gas_price_provider.ip": "0.0.0.0", + "components.l1_gas_price_provider.local_server_config.channel_buffer_size": 32, + "components.l1_gas_price_provider.max_concurrency": 10, + "components.l1_gas_price_provider.port": 0, + "components.l1_gas_price_provider.remote_client_config.idle_connections": 18446744073709551615, + "components.l1_gas_price_provider.remote_client_config.idle_timeout": 90, + "components.l1_gas_price_provider.remote_client_config.retries": 3, + "components.l1_gas_price_provider.remote_client_config.retry_interval": 3, + "components.l1_gas_price_provider.url": "localhost", + "components.l1_gas_price_scraper.execution_mode": "Disabled", + "components.l1_provider.execution_mode": "Disabled", + "components.l1_provider.ip": "0.0.0.0", + "components.l1_provider.local_server_config.channel_buffer_size": 32, + "components.l1_provider.max_concurrency": 10, + "components.l1_provider.port": 0, + "components.l1_provider.remote_client_config.idle_connections": 18446744073709551615, + "components.l1_provider.remote_client_config.idle_timeout": 90, + "components.l1_provider.remote_client_config.retries": 3, + "components.l1_provider.remote_client_config.retry_interval": 3, + "components.l1_provider.url": "localhost", + "components.l1_scraper.execution_mode": "Disabled", + "components.mempool.execution_mode": "Remote", + "components.mempool.ip": "0.0.0.0", + "components.mempool.local_server_config.channel_buffer_size": 32, + "components.mempool.max_concurrency": 10, + "components.mempool.port": 55006, + "components.mempool.remote_client_config.idle_connections": 18446744073709551615, + "components.mempool.remote_client_config.idle_timeout": 90, + "components.mempool.remote_client_config.retries": 3, + "components.mempool.remote_client_config.retry_interval": 3, + "components.mempool.url": "sequencer-mempool-service", + "components.mempool_p2p.execution_mode": "Disabled", + "components.mempool_p2p.ip": "0.0.0.0", + "components.mempool_p2p.local_server_config.channel_buffer_size": 32, + "components.mempool_p2p.max_concurrency": 10, + "components.mempool_p2p.port": 0, + "components.mempool_p2p.remote_client_config.idle_connections": 18446744073709551615, + "components.mempool_p2p.remote_client_config.idle_timeout": 90, + "components.mempool_p2p.remote_client_config.retries": 3, + "components.mempool_p2p.remote_client_config.retry_interval": 3, + "components.mempool_p2p.url": "localhost", + "components.monitoring_endpoint.execution_mode": "Enabled", + "components.sierra_compiler.execution_mode": "Disabled", + "components.sierra_compiler.ip": "0.0.0.0", + "components.sierra_compiler.local_server_config.channel_buffer_size": 32, + "components.sierra_compiler.max_concurrency": 10, + "components.sierra_compiler.port": 0, + "components.sierra_compiler.remote_client_config.idle_connections": 18446744073709551615, + "components.sierra_compiler.remote_client_config.idle_timeout": 90, + "components.sierra_compiler.remote_client_config.retries": 3, + "components.sierra_compiler.remote_client_config.retry_interval": 3, + "components.sierra_compiler.url": "localhost", + "components.state_sync.execution_mode": "Remote", + "components.state_sync.ip": "0.0.0.0", + "components.state_sync.local_server_config.channel_buffer_size": 32, + "components.state_sync.max_concurrency": 10, + "components.state_sync.port": 55008, + "components.state_sync.remote_client_config.idle_connections": 18446744073709551615, + "components.state_sync.remote_client_config.idle_timeout": 90, + "components.state_sync.remote_client_config.retries": 3, + "components.state_sync.remote_client_config.retry_interval": 3, + "components.state_sync.url": "sequencer-state-sync-service", + "consensus_manager_config.broadcast_buffer_size": 10000, + "consensus_manager_config.cende_config.skip_write_height": 1, + "consensus_manager_config.cende_config.skip_write_height.#is_none": false, + "consensus_manager_config.consensus_config.future_height_limit": 10, + "consensus_manager_config.consensus_config.future_height_round_limit": 1, + "consensus_manager_config.consensus_config.future_round_limit": 10, + "consensus_manager_config.consensus_config.startup_delay": 15, + "consensus_manager_config.consensus_config.sync_retry_interval": 1.0, + "consensus_manager_config.consensus_config.timeouts.precommit_timeout": 3.0, + "consensus_manager_config.consensus_config.timeouts.prevote_timeout": 3.0, + "consensus_manager_config.consensus_config.timeouts.proposal_timeout": 9.0, + "consensus_manager_config.context_config.block_timestamp_window": 1, + "consensus_manager_config.context_config.build_proposal_margin": 1000, + "consensus_manager_config.context_config.builder_address": "0x4", + "consensus_manager_config.context_config.l1_da_mode": true, + "consensus_manager_config.context_config.num_validators": 1, + "consensus_manager_config.context_config.proposal_buffer_size": 100, + "consensus_manager_config.context_config.validate_proposal_margin": 10000, + "consensus_manager_config.eth_to_strk_oracle_config.base_url": "http://127.0.0.1:53262/eth_to_strk_oracle?timestamp=", + "consensus_manager_config.eth_to_strk_oracle_config.headers": "", + "consensus_manager_config.immediate_active_height": 1, + "consensus_manager_config.network_config.advertised_multiaddr": "", + "consensus_manager_config.network_config.advertised_multiaddr.#is_none": true, + "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "", + "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": true, + "consensus_manager_config.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": 2, + "consensus_manager_config.network_config.discovery_config.bootstrap_dial_retry_config.factor": 5, + "consensus_manager_config.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": 5, + "consensus_manager_config.network_config.discovery_config.heartbeat_interval": 100, + "consensus_manager_config.network_config.idle_connection_timeout": 120, + "consensus_manager_config.network_config.peer_manager_config.malicious_timeout_seconds": 1, + "consensus_manager_config.network_config.peer_manager_config.unstable_timeout_millis": 1000, + "consensus_manager_config.network_config.port": 53080, + "consensus_manager_config.network_config.secret_key": "0x0101010101010101010101010101010101010101010101010101010101010101", + "consensus_manager_config.network_config.session_timeout": 120, + "consensus_manager_config.proposals_topic": "consensus_proposals", + "consensus_manager_config.votes_topic": "consensus_votes", + "eth_fee_token_address": "0x1001", + "gateway_config.stateful_tx_validator_config.max_allowed_nonce_gap": 50, + "gateway_config.stateful_tx_validator_config.max_nonce_for_validation_skip": "0x1", + "gateway_config.stateless_tx_validator_config.max_calldata_length": 10, + "gateway_config.stateless_tx_validator_config.max_contract_class_object_size": 4089446, + "gateway_config.stateless_tx_validator_config.max_sierra_version.major": 1, + "gateway_config.stateless_tx_validator_config.max_sierra_version.minor": 5, + "gateway_config.stateless_tx_validator_config.max_sierra_version.patch": 18446744073709551615, + "gateway_config.stateless_tx_validator_config.max_signature_length": 2, + "gateway_config.stateless_tx_validator_config.min_sierra_version.major": 1, + "gateway_config.stateless_tx_validator_config.min_sierra_version.minor": 1, + "gateway_config.stateless_tx_validator_config.min_sierra_version.patch": 0, + "gateway_config.stateless_tx_validator_config.validate_non_zero_l1_data_gas_fee": false, + "gateway_config.stateless_tx_validator_config.validate_non_zero_l1_gas_fee": true, + "gateway_config.stateless_tx_validator_config.validate_non_zero_l2_gas_fee": false, + "http_server_config.ip": "127.0.0.1", + "http_server_config.port": 53320, + "l1_gas_price_provider_config.lag_margin_seconds": 60, + "l1_gas_price_provider_config.number_of_blocks_for_mean": 300, + "l1_gas_price_provider_config.storage_limit": 3000, + "l1_gas_price_scraper_config.finality": 0, + "l1_gas_price_scraper_config.number_of_blocks_for_mean": 300, + "l1_gas_price_scraper_config.polling_interval": 1, + "l1_gas_price_scraper_config.starting_block": 0, + "l1_gas_price_scraper_config.starting_block.#is_none": true, + "l1_provider_config.bootstrap_catch_up_height_override": 0, + "l1_provider_config.bootstrap_catch_up_height_override.#is_none": true, + "l1_provider_config.provider_startup_height_override": 1, + "l1_provider_config.provider_startup_height_override.#is_none": false, + "l1_provider_config.startup_sync_sleep_retry_interval": 0.0, + "l1_scraper_config.finality": 0, + "l1_scraper_config.polling_interval": 1, + "l1_scraper_config.startup_rewind_time": 0, + "mempool_config.committed_nonce_retention_block_count": 100, + "mempool_config.declare_delay": 1, + "mempool_config.enable_fee_escalation": true, + "mempool_config.fee_escalation_percentage": 10, + "mempool_config.transaction_ttl": 300, + "mempool_p2p_config.max_transaction_batch_size": 1, + "mempool_p2p_config.network_buffer_size": 10000, + "mempool_p2p_config.network_config.advertised_multiaddr": "", + "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": true, + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "", + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": true, + "mempool_p2p_config.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": 2, + "mempool_p2p_config.network_config.discovery_config.bootstrap_dial_retry_config.factor": 5, + "mempool_p2p_config.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": 5, + "mempool_p2p_config.network_config.discovery_config.heartbeat_interval": 100, + "mempool_p2p_config.network_config.idle_connection_timeout": 120, + "mempool_p2p_config.network_config.peer_manager_config.malicious_timeout_seconds": 1, + "mempool_p2p_config.network_config.peer_manager_config.unstable_timeout_millis": 1000, + "mempool_p2p_config.network_config.port": 53200, + "mempool_p2p_config.network_config.secret_key": "0x0101010101010101010101010101010101010101010101010101010101010101", + "mempool_p2p_config.network_config.session_timeout": 120, + "mempool_p2p_config.transaction_batch_rate_millis": 1000, + "monitoring_config.collect_metrics": true, + "monitoring_config.collect_profiling_metrics": true, + "monitoring_endpoint_config.collect_metrics": true, + "monitoring_endpoint_config.collect_profiling_metrics": true, + "monitoring_endpoint_config.ip": "0.0.0.0", + "monitoring_endpoint_config.port": 8082, + "recorder_url": "http://127.0.0.1:53261/", + "revert_config.revert_up_to_and_including": 18446744073709551615, + "revert_config.should_revert": false, + "state_sync_config.central_sync_client_config.#is_none": true, + "state_sync_config.central_sync_client_config.central_source_config.class_cache_size": 100, + "state_sync_config.central_sync_client_config.central_source_config.concurrent_requests": 10, + "state_sync_config.central_sync_client_config.central_source_config.http_headers": "", + "state_sync_config.central_sync_client_config.central_source_config.max_classes_to_download": 20, + "state_sync_config.central_sync_client_config.central_source_config.max_state_updates_to_download": 20, + "state_sync_config.central_sync_client_config.central_source_config.max_state_updates_to_store_in_memory": 20, + "state_sync_config.central_sync_client_config.central_source_config.retry_config.max_retries": 10, + "state_sync_config.central_sync_client_config.central_source_config.retry_config.retry_base_millis": 30, + "state_sync_config.central_sync_client_config.central_source_config.retry_config.retry_max_delay_millis": 30000, + "state_sync_config.central_sync_client_config.central_source_config.starknet_url": "https://alpha-mainnet.starknet.io/", + "state_sync_config.central_sync_client_config.sync_config.base_layer_propagation_sleep_duration": 10, + "state_sync_config.central_sync_client_config.sync_config.block_propagation_sleep_duration": 2, + "state_sync_config.central_sync_client_config.sync_config.blocks_max_stream_size": 1000, + "state_sync_config.central_sync_client_config.sync_config.collect_pending_data": false, + "state_sync_config.central_sync_client_config.sync_config.recoverable_error_sleep_duration": 3, + "state_sync_config.central_sync_client_config.sync_config.state_updates_max_stream_size": 1000, + "state_sync_config.central_sync_client_config.sync_config.store_sierras_and_casms": false, + "state_sync_config.central_sync_client_config.sync_config.verify_blocks": true, + "state_sync_config.network_config.advertised_multiaddr": "", + "state_sync_config.network_config.advertised_multiaddr.#is_none": true, + "state_sync_config.network_config.bootstrap_peer_multiaddr": "", + "state_sync_config.network_config.bootstrap_peer_multiaddr.#is_none": true, + "state_sync_config.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": 2, + "state_sync_config.network_config.discovery_config.bootstrap_dial_retry_config.factor": 5, + "state_sync_config.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": 5, + "state_sync_config.network_config.discovery_config.heartbeat_interval": 100, + "state_sync_config.network_config.idle_connection_timeout": 120, + "state_sync_config.network_config.peer_manager_config.malicious_timeout_seconds": 1, + "state_sync_config.network_config.peer_manager_config.unstable_timeout_millis": 1000, + "state_sync_config.network_config.port": 53140, + "state_sync_config.network_config.secret_key": "0x0101010101010101010101010101010101010101010101010101010101010101", + "state_sync_config.network_config.session_timeout": 120, + "state_sync_config.p2p_sync_client_config.#is_none": false, + "state_sync_config.p2p_sync_client_config.buffer_size": 100000, + "state_sync_config.p2p_sync_client_config.num_block_classes_per_query": 100, + "state_sync_config.p2p_sync_client_config.num_block_state_diffs_per_query": 100, + "state_sync_config.p2p_sync_client_config.num_block_transactions_per_query": 100, + "state_sync_config.p2p_sync_client_config.num_headers_per_query": 10000, + "state_sync_config.p2p_sync_client_config.wait_period_for_new_data": 50, + "state_sync_config.p2p_sync_client_config.wait_period_for_other_protocol": 50, + "state_sync_config.storage_config.db_config.enforce_file_exists": false, + "state_sync_config.storage_config.db_config.growth_step": 67108864, + "state_sync_config.storage_config.db_config.max_size": 34359738368, + "state_sync_config.storage_config.db_config.min_size": 1048576, + "state_sync_config.storage_config.db_config.path_prefix": "/data/node_0/executable_0/state_sync", + "state_sync_config.storage_config.mmap_file_config.growth_step": 1048576, + "state_sync_config.storage_config.mmap_file_config.max_object_size": 65536, + "state_sync_config.storage_config.mmap_file_config.max_size": 16777216, + "state_sync_config.storage_config.scope": "FullArchive", + "strk_fee_token_address": "0x1002", + "validator_id": "0x64", + "versioned_constants_overrides.invoke_tx_max_n_steps": 10000000, + "versioned_constants_overrides.max_n_events": 1000, + "versioned_constants_overrides.max_recursion_depth": 50, + "versioned_constants_overrides.validate_max_n_steps": 1000000 +} diff --git a/config/sequencer/presets/distributed_node/application_configs/http_server.json b/config/sequencer/presets/distributed_node/application_configs/http_server.json new file mode 100644 index 00000000000..b14a3ffadb1 --- /dev/null +++ b/config/sequencer/presets/distributed_node/application_configs/http_server.json @@ -0,0 +1,306 @@ +{ + "base_layer_config.node_url": "http://localhost:53260/", + "base_layer_config.starknet_contract_address": "0x5FbDB2315678afecb367f032d93F642f64180aa3", + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.l1_gas": 2500000, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.message_segment_length": 3700, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.n_events": 5000, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.sierra_gas": 30000000, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.state_diff_size": 4000, + "batcher_config.block_builder_config.execute_config.concurrency_config.chunk_size": 64, + "batcher_config.block_builder_config.execute_config.concurrency_config.enabled": true, + "batcher_config.block_builder_config.execute_config.concurrency_config.n_workers": 4, + "batcher_config.block_builder_config.execute_config.stack_size": 62914560, + "batcher_config.block_builder_config.tx_chunk_size": 100, + "batcher_config.contract_class_manager_config.cairo_native_run_config.channel_size": 2000, + "batcher_config.contract_class_manager_config.cairo_native_run_config.native_classes_whitelist": "All", + "batcher_config.contract_class_manager_config.cairo_native_run_config.run_cairo_native": false, + "batcher_config.contract_class_manager_config.cairo_native_run_config.wait_on_native_compilation": false, + "batcher_config.contract_class_manager_config.contract_cache_size": 600, + "batcher_config.contract_class_manager_config.native_compiler_config.max_casm_bytecode_size": 81920, + "batcher_config.contract_class_manager_config.native_compiler_config.max_cpu_time": 20, + "batcher_config.contract_class_manager_config.native_compiler_config.max_memory_usage": 5368709120, + "batcher_config.contract_class_manager_config.native_compiler_config.max_native_bytecode_size": 15728640, + "batcher_config.contract_class_manager_config.native_compiler_config.optimization_level": 2, + "batcher_config.contract_class_manager_config.native_compiler_config.panic_on_compilation_failure": false, + "batcher_config.contract_class_manager_config.native_compiler_config.sierra_to_native_compiler_path": "", + "batcher_config.contract_class_manager_config.native_compiler_config.sierra_to_native_compiler_path.#is_none": true, + "batcher_config.input_stream_content_buffer_size": 400, + "batcher_config.max_l1_handler_txs_per_block_proposal": 3, + "batcher_config.outstream_content_buffer_size": 100, + "batcher_config.storage.db_config.enforce_file_exists": false, + "batcher_config.storage.db_config.growth_step": 67108864, + "batcher_config.storage.db_config.max_size": 34359738368, + "batcher_config.storage.db_config.min_size": 1048576, + "batcher_config.storage.db_config.path_prefix": "/data/node_0/executable_0/batcher", + "batcher_config.storage.mmap_file_config.growth_step": 1048576, + "batcher_config.storage.mmap_file_config.max_object_size": 65536, + "batcher_config.storage.mmap_file_config.max_size": 16777216, + "batcher_config.storage.scope": "StateOnly", + "chain_id": "CHAIN_ID_SUBDIR", + "class_manager_config.class_manager_config.cached_class_storage_config.class_cache_size": 100, + "class_manager_config.class_manager_config.cached_class_storage_config.deprecated_class_cache_size": 100, + "class_manager_config.class_storage_config.class_hash_storage_config.enforce_file_exists": false, + "class_manager_config.class_storage_config.class_hash_storage_config.max_size": 1048576, + "class_manager_config.class_storage_config.class_hash_storage_config.path_prefix": "/data/node_0/executable_0/class_manager/class_hash_storage", + "class_manager_config.class_storage_config.persistent_root": "/data/node_0/executable_0/class_manager/classes", + "compiler_config.max_casm_bytecode_size": 81920, + "compiler_config.max_cpu_time": 20, + "compiler_config.max_memory_usage": 5368709120, + "compiler_config.max_native_bytecode_size": 15728640, + "compiler_config.optimization_level": 2, + "compiler_config.panic_on_compilation_failure": false, + "compiler_config.sierra_to_native_compiler_path": "", + "compiler_config.sierra_to_native_compiler_path.#is_none": true, + "components.batcher.execution_mode": "Disabled", + "components.batcher.ip": "0.0.0.0", + "components.batcher.local_server_config.channel_buffer_size": 32, + "components.batcher.max_concurrency": 10, + "components.batcher.port": 0, + "components.batcher.remote_client_config.idle_connections": 18446744073709551615, + "components.batcher.remote_client_config.idle_timeout": 90, + "components.batcher.remote_client_config.retries": 3, + "components.batcher.remote_client_config.retry_interval": 3, + "components.batcher.url": "localhost", + "components.class_manager.execution_mode": "Disabled", + "components.class_manager.ip": "0.0.0.0", + "components.class_manager.local_server_config.channel_buffer_size": 32, + "components.class_manager.max_concurrency": 10, + "components.class_manager.port": 0, + "components.class_manager.remote_client_config.idle_connections": 18446744073709551615, + "components.class_manager.remote_client_config.idle_timeout": 90, + "components.class_manager.remote_client_config.retries": 3, + "components.class_manager.remote_client_config.retry_interval": 3, + "components.class_manager.url": "localhost", + "components.consensus_manager.execution_mode": "Disabled", + "components.gateway.execution_mode": "Remote", + "components.gateway.ip": "0.0.0.0", + "components.gateway.local_server_config.channel_buffer_size": 32, + "components.gateway.max_concurrency": 10, + "components.gateway.port": 55004, + "components.gateway.remote_client_config.idle_connections": 18446744073709551615, + "components.gateway.remote_client_config.idle_timeout": 90, + "components.gateway.remote_client_config.retries": 3, + "components.gateway.remote_client_config.retry_interval": 3, + "components.gateway.url": "sequencer-gateway-service", + "components.http_server.execution_mode": "Enabled", + "components.l1_gas_price_provider.execution_mode": "Disabled", + "components.l1_gas_price_provider.ip": "0.0.0.0", + "components.l1_gas_price_provider.local_server_config.channel_buffer_size": 32, + "components.l1_gas_price_provider.max_concurrency": 10, + "components.l1_gas_price_provider.port": 0, + "components.l1_gas_price_provider.remote_client_config.idle_connections": 18446744073709551615, + "components.l1_gas_price_provider.remote_client_config.idle_timeout": 90, + "components.l1_gas_price_provider.remote_client_config.retries": 3, + "components.l1_gas_price_provider.remote_client_config.retry_interval": 3, + "components.l1_gas_price_provider.url": "localhost", + "components.l1_gas_price_scraper.execution_mode": "Disabled", + "components.l1_provider.execution_mode": "Disabled", + "components.l1_provider.ip": "0.0.0.0", + "components.l1_provider.local_server_config.channel_buffer_size": 32, + "components.l1_provider.max_concurrency": 10, + "components.l1_provider.port": 0, + "components.l1_provider.remote_client_config.idle_connections": 18446744073709551615, + "components.l1_provider.remote_client_config.idle_timeout": 90, + "components.l1_provider.remote_client_config.retries": 3, + "components.l1_provider.remote_client_config.retry_interval": 3, + "components.l1_provider.url": "localhost", + "components.l1_scraper.execution_mode": "Disabled", + "components.mempool.execution_mode": "Disabled", + "components.mempool.ip": "0.0.0.0", + "components.mempool.local_server_config.channel_buffer_size": 32, + "components.mempool.max_concurrency": 10, + "components.mempool.port": 0, + "components.mempool.remote_client_config.idle_connections": 18446744073709551615, + "components.mempool.remote_client_config.idle_timeout": 90, + "components.mempool.remote_client_config.retries": 3, + "components.mempool.remote_client_config.retry_interval": 3, + "components.mempool.url": "localhost", + "components.mempool_p2p.execution_mode": "Disabled", + "components.mempool_p2p.ip": "0.0.0.0", + "components.mempool_p2p.local_server_config.channel_buffer_size": 32, + "components.mempool_p2p.max_concurrency": 10, + "components.mempool_p2p.port": 0, + "components.mempool_p2p.remote_client_config.idle_connections": 18446744073709551615, + "components.mempool_p2p.remote_client_config.idle_timeout": 90, + "components.mempool_p2p.remote_client_config.retries": 3, + "components.mempool_p2p.remote_client_config.retry_interval": 3, + "components.mempool_p2p.url": "localhost", + "components.monitoring_endpoint.execution_mode": "Enabled", + "components.sierra_compiler.execution_mode": "Disabled", + "components.sierra_compiler.ip": "0.0.0.0", + "components.sierra_compiler.local_server_config.channel_buffer_size": 32, + "components.sierra_compiler.max_concurrency": 10, + "components.sierra_compiler.port": 0, + "components.sierra_compiler.remote_client_config.idle_connections": 18446744073709551615, + "components.sierra_compiler.remote_client_config.idle_timeout": 90, + "components.sierra_compiler.remote_client_config.retries": 3, + "components.sierra_compiler.remote_client_config.retry_interval": 3, + "components.sierra_compiler.url": "localhost", + "components.state_sync.execution_mode": "Disabled", + "components.state_sync.ip": "0.0.0.0", + "components.state_sync.local_server_config.channel_buffer_size": 32, + "components.state_sync.max_concurrency": 10, + "components.state_sync.port": 0, + "components.state_sync.remote_client_config.idle_connections": 18446744073709551615, + "components.state_sync.remote_client_config.idle_timeout": 90, + "components.state_sync.remote_client_config.retries": 3, + "components.state_sync.remote_client_config.retry_interval": 3, + "components.state_sync.url": "localhost", + "consensus_manager_config.broadcast_buffer_size": 10000, + "consensus_manager_config.cende_config.skip_write_height": 1, + "consensus_manager_config.cende_config.skip_write_height.#is_none": false, + "consensus_manager_config.consensus_config.future_height_limit": 10, + "consensus_manager_config.consensus_config.future_height_round_limit": 1, + "consensus_manager_config.consensus_config.future_round_limit": 10, + "consensus_manager_config.consensus_config.startup_delay": 15, + "consensus_manager_config.consensus_config.sync_retry_interval": 1.0, + "consensus_manager_config.consensus_config.timeouts.precommit_timeout": 3.0, + "consensus_manager_config.consensus_config.timeouts.prevote_timeout": 3.0, + "consensus_manager_config.consensus_config.timeouts.proposal_timeout": 9.0, + "consensus_manager_config.context_config.block_timestamp_window": 1, + "consensus_manager_config.context_config.build_proposal_margin": 1000, + "consensus_manager_config.context_config.builder_address": "0x4", + "consensus_manager_config.context_config.l1_da_mode": true, + "consensus_manager_config.context_config.num_validators": 1, + "consensus_manager_config.context_config.proposal_buffer_size": 100, + "consensus_manager_config.context_config.validate_proposal_margin": 10000, + "consensus_manager_config.eth_to_strk_oracle_config.base_url": "http://127.0.0.1:53262/eth_to_strk_oracle?timestamp=", + "consensus_manager_config.eth_to_strk_oracle_config.headers": "", + "consensus_manager_config.immediate_active_height": 1, + "consensus_manager_config.network_config.advertised_multiaddr": "", + "consensus_manager_config.network_config.advertised_multiaddr.#is_none": true, + "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "", + "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": true, + "consensus_manager_config.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": 2, + "consensus_manager_config.network_config.discovery_config.bootstrap_dial_retry_config.factor": 5, + "consensus_manager_config.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": 5, + "consensus_manager_config.network_config.discovery_config.heartbeat_interval": 100, + "consensus_manager_config.network_config.idle_connection_timeout": 120, + "consensus_manager_config.network_config.peer_manager_config.malicious_timeout_seconds": 1, + "consensus_manager_config.network_config.peer_manager_config.unstable_timeout_millis": 1000, + "consensus_manager_config.network_config.port": 53080, + "consensus_manager_config.network_config.secret_key": "0x0101010101010101010101010101010101010101010101010101010101010101", + "consensus_manager_config.network_config.session_timeout": 120, + "consensus_manager_config.proposals_topic": "consensus_proposals", + "consensus_manager_config.votes_topic": "consensus_votes", + "eth_fee_token_address": "0x1001", + "gateway_config.stateful_tx_validator_config.max_allowed_nonce_gap": 50, + "gateway_config.stateful_tx_validator_config.max_nonce_for_validation_skip": "0x1", + "gateway_config.stateless_tx_validator_config.max_calldata_length": 10, + "gateway_config.stateless_tx_validator_config.max_contract_class_object_size": 4089446, + "gateway_config.stateless_tx_validator_config.max_sierra_version.major": 1, + "gateway_config.stateless_tx_validator_config.max_sierra_version.minor": 5, + "gateway_config.stateless_tx_validator_config.max_sierra_version.patch": 18446744073709551615, + "gateway_config.stateless_tx_validator_config.max_signature_length": 2, + "gateway_config.stateless_tx_validator_config.min_sierra_version.major": 1, + "gateway_config.stateless_tx_validator_config.min_sierra_version.minor": 1, + "gateway_config.stateless_tx_validator_config.min_sierra_version.patch": 0, + "gateway_config.stateless_tx_validator_config.validate_non_zero_l1_data_gas_fee": false, + "gateway_config.stateless_tx_validator_config.validate_non_zero_l1_gas_fee": true, + "gateway_config.stateless_tx_validator_config.validate_non_zero_l2_gas_fee": false, + "http_server_config.ip": "127.0.0.1", + "http_server_config.port": 53320, + "l1_gas_price_provider_config.lag_margin_seconds": 60, + "l1_gas_price_provider_config.number_of_blocks_for_mean": 300, + "l1_gas_price_provider_config.storage_limit": 3000, + "l1_gas_price_scraper_config.finality": 0, + "l1_gas_price_scraper_config.number_of_blocks_for_mean": 300, + "l1_gas_price_scraper_config.polling_interval": 1, + "l1_gas_price_scraper_config.starting_block": 0, + "l1_gas_price_scraper_config.starting_block.#is_none": true, + "l1_provider_config.bootstrap_catch_up_height_override": 0, + "l1_provider_config.bootstrap_catch_up_height_override.#is_none": true, + "l1_provider_config.provider_startup_height_override": 1, + "l1_provider_config.provider_startup_height_override.#is_none": false, + "l1_provider_config.startup_sync_sleep_retry_interval": 0.0, + "l1_scraper_config.finality": 0, + "l1_scraper_config.polling_interval": 1, + "l1_scraper_config.startup_rewind_time": 0, + "mempool_config.committed_nonce_retention_block_count": 100, + "mempool_config.declare_delay": 1, + "mempool_config.enable_fee_escalation": true, + "mempool_config.fee_escalation_percentage": 10, + "mempool_config.transaction_ttl": 300, + "mempool_p2p_config.max_transaction_batch_size": 1, + "mempool_p2p_config.network_buffer_size": 10000, + "mempool_p2p_config.network_config.advertised_multiaddr": "", + "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": true, + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "", + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": true, + "mempool_p2p_config.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": 2, + "mempool_p2p_config.network_config.discovery_config.bootstrap_dial_retry_config.factor": 5, + "mempool_p2p_config.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": 5, + "mempool_p2p_config.network_config.discovery_config.heartbeat_interval": 100, + "mempool_p2p_config.network_config.idle_connection_timeout": 120, + "mempool_p2p_config.network_config.peer_manager_config.malicious_timeout_seconds": 1, + "mempool_p2p_config.network_config.peer_manager_config.unstable_timeout_millis": 1000, + "mempool_p2p_config.network_config.port": 53200, + "mempool_p2p_config.network_config.secret_key": "0x0101010101010101010101010101010101010101010101010101010101010101", + "mempool_p2p_config.network_config.session_timeout": 120, + "mempool_p2p_config.transaction_batch_rate_millis": 1000, + "monitoring_config.collect_metrics": true, + "monitoring_config.collect_profiling_metrics": true, + "monitoring_endpoint_config.collect_metrics": true, + "monitoring_endpoint_config.collect_profiling_metrics": true, + "monitoring_endpoint_config.ip": "0.0.0.0", + "monitoring_endpoint_config.port": 8082, + "recorder_url": "http://127.0.0.1:53261/", + "revert_config.revert_up_to_and_including": 18446744073709551615, + "revert_config.should_revert": false, + "state_sync_config.central_sync_client_config.#is_none": true, + "state_sync_config.central_sync_client_config.central_source_config.class_cache_size": 100, + "state_sync_config.central_sync_client_config.central_source_config.concurrent_requests": 10, + "state_sync_config.central_sync_client_config.central_source_config.http_headers": "", + "state_sync_config.central_sync_client_config.central_source_config.max_classes_to_download": 20, + "state_sync_config.central_sync_client_config.central_source_config.max_state_updates_to_download": 20, + "state_sync_config.central_sync_client_config.central_source_config.max_state_updates_to_store_in_memory": 20, + "state_sync_config.central_sync_client_config.central_source_config.retry_config.max_retries": 10, + "state_sync_config.central_sync_client_config.central_source_config.retry_config.retry_base_millis": 30, + "state_sync_config.central_sync_client_config.central_source_config.retry_config.retry_max_delay_millis": 30000, + "state_sync_config.central_sync_client_config.central_source_config.starknet_url": "https://alpha-mainnet.starknet.io/", + "state_sync_config.central_sync_client_config.sync_config.base_layer_propagation_sleep_duration": 10, + "state_sync_config.central_sync_client_config.sync_config.block_propagation_sleep_duration": 2, + "state_sync_config.central_sync_client_config.sync_config.blocks_max_stream_size": 1000, + "state_sync_config.central_sync_client_config.sync_config.collect_pending_data": false, + "state_sync_config.central_sync_client_config.sync_config.recoverable_error_sleep_duration": 3, + "state_sync_config.central_sync_client_config.sync_config.state_updates_max_stream_size": 1000, + "state_sync_config.central_sync_client_config.sync_config.store_sierras_and_casms": false, + "state_sync_config.central_sync_client_config.sync_config.verify_blocks": true, + "state_sync_config.network_config.advertised_multiaddr": "", + "state_sync_config.network_config.advertised_multiaddr.#is_none": true, + "state_sync_config.network_config.bootstrap_peer_multiaddr": "", + "state_sync_config.network_config.bootstrap_peer_multiaddr.#is_none": true, + "state_sync_config.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": 2, + "state_sync_config.network_config.discovery_config.bootstrap_dial_retry_config.factor": 5, + "state_sync_config.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": 5, + "state_sync_config.network_config.discovery_config.heartbeat_interval": 100, + "state_sync_config.network_config.idle_connection_timeout": 120, + "state_sync_config.network_config.peer_manager_config.malicious_timeout_seconds": 1, + "state_sync_config.network_config.peer_manager_config.unstable_timeout_millis": 1000, + "state_sync_config.network_config.port": 53140, + "state_sync_config.network_config.secret_key": "0x0101010101010101010101010101010101010101010101010101010101010101", + "state_sync_config.network_config.session_timeout": 120, + "state_sync_config.p2p_sync_client_config.#is_none": false, + "state_sync_config.p2p_sync_client_config.buffer_size": 100000, + "state_sync_config.p2p_sync_client_config.num_block_classes_per_query": 100, + "state_sync_config.p2p_sync_client_config.num_block_state_diffs_per_query": 100, + "state_sync_config.p2p_sync_client_config.num_block_transactions_per_query": 100, + "state_sync_config.p2p_sync_client_config.num_headers_per_query": 10000, + "state_sync_config.p2p_sync_client_config.wait_period_for_new_data": 50, + "state_sync_config.p2p_sync_client_config.wait_period_for_other_protocol": 50, + "state_sync_config.storage_config.db_config.enforce_file_exists": false, + "state_sync_config.storage_config.db_config.growth_step": 67108864, + "state_sync_config.storage_config.db_config.max_size": 34359738368, + "state_sync_config.storage_config.db_config.min_size": 1048576, + "state_sync_config.storage_config.db_config.path_prefix": "/data/node_0/executable_0/state_sync", + "state_sync_config.storage_config.mmap_file_config.growth_step": 1048576, + "state_sync_config.storage_config.mmap_file_config.max_object_size": 65536, + "state_sync_config.storage_config.mmap_file_config.max_size": 16777216, + "state_sync_config.storage_config.scope": "FullArchive", + "strk_fee_token_address": "0x1002", + "validator_id": "0x64", + "versioned_constants_overrides.invoke_tx_max_n_steps": 10000000, + "versioned_constants_overrides.max_n_events": 1000, + "versioned_constants_overrides.max_recursion_depth": 50, + "versioned_constants_overrides.validate_max_n_steps": 1000000 +} diff --git a/config/sequencer/presets/distributed_node/application_configs/l1_provider.json b/config/sequencer/presets/distributed_node/application_configs/l1_provider.json new file mode 100644 index 00000000000..17fd09cff5c --- /dev/null +++ b/config/sequencer/presets/distributed_node/application_configs/l1_provider.json @@ -0,0 +1,306 @@ +{ + "base_layer_config.node_url": "http://localhost:53260/", + "base_layer_config.starknet_contract_address": "0x5FbDB2315678afecb367f032d93F642f64180aa3", + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.l1_gas": 2500000, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.message_segment_length": 3700, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.n_events": 5000, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.sierra_gas": 30000000, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.state_diff_size": 4000, + "batcher_config.block_builder_config.execute_config.concurrency_config.chunk_size": 64, + "batcher_config.block_builder_config.execute_config.concurrency_config.enabled": true, + "batcher_config.block_builder_config.execute_config.concurrency_config.n_workers": 4, + "batcher_config.block_builder_config.execute_config.stack_size": 62914560, + "batcher_config.block_builder_config.tx_chunk_size": 100, + "batcher_config.contract_class_manager_config.cairo_native_run_config.channel_size": 2000, + "batcher_config.contract_class_manager_config.cairo_native_run_config.native_classes_whitelist": "All", + "batcher_config.contract_class_manager_config.cairo_native_run_config.run_cairo_native": false, + "batcher_config.contract_class_manager_config.cairo_native_run_config.wait_on_native_compilation": false, + "batcher_config.contract_class_manager_config.contract_cache_size": 600, + "batcher_config.contract_class_manager_config.native_compiler_config.max_casm_bytecode_size": 81920, + "batcher_config.contract_class_manager_config.native_compiler_config.max_cpu_time": 20, + "batcher_config.contract_class_manager_config.native_compiler_config.max_memory_usage": 5368709120, + "batcher_config.contract_class_manager_config.native_compiler_config.max_native_bytecode_size": 15728640, + "batcher_config.contract_class_manager_config.native_compiler_config.optimization_level": 2, + "batcher_config.contract_class_manager_config.native_compiler_config.panic_on_compilation_failure": false, + "batcher_config.contract_class_manager_config.native_compiler_config.sierra_to_native_compiler_path": "", + "batcher_config.contract_class_manager_config.native_compiler_config.sierra_to_native_compiler_path.#is_none": true, + "batcher_config.input_stream_content_buffer_size": 400, + "batcher_config.max_l1_handler_txs_per_block_proposal": 3, + "batcher_config.outstream_content_buffer_size": 100, + "batcher_config.storage.db_config.enforce_file_exists": false, + "batcher_config.storage.db_config.growth_step": 67108864, + "batcher_config.storage.db_config.max_size": 34359738368, + "batcher_config.storage.db_config.min_size": 1048576, + "batcher_config.storage.db_config.path_prefix": "/data/node_0/executable_0/batcher", + "batcher_config.storage.mmap_file_config.growth_step": 1048576, + "batcher_config.storage.mmap_file_config.max_object_size": 65536, + "batcher_config.storage.mmap_file_config.max_size": 16777216, + "batcher_config.storage.scope": "StateOnly", + "chain_id": "CHAIN_ID_SUBDIR", + "class_manager_config.class_manager_config.cached_class_storage_config.class_cache_size": 100, + "class_manager_config.class_manager_config.cached_class_storage_config.deprecated_class_cache_size": 100, + "class_manager_config.class_storage_config.class_hash_storage_config.enforce_file_exists": false, + "class_manager_config.class_storage_config.class_hash_storage_config.max_size": 1048576, + "class_manager_config.class_storage_config.class_hash_storage_config.path_prefix": "/data/node_0/executable_0/class_manager/class_hash_storage", + "class_manager_config.class_storage_config.persistent_root": "/data/node_0/executable_0/class_manager/classes", + "compiler_config.max_casm_bytecode_size": 81920, + "compiler_config.max_cpu_time": 20, + "compiler_config.max_memory_usage": 5368709120, + "compiler_config.max_native_bytecode_size": 15728640, + "compiler_config.optimization_level": 2, + "compiler_config.panic_on_compilation_failure": false, + "compiler_config.sierra_to_native_compiler_path": "", + "compiler_config.sierra_to_native_compiler_path.#is_none": true, + "components.batcher.execution_mode": "Disabled", + "components.batcher.ip": "0.0.0.0", + "components.batcher.local_server_config.channel_buffer_size": 32, + "components.batcher.max_concurrency": 10, + "components.batcher.port": 0, + "components.batcher.remote_client_config.idle_connections": 18446744073709551615, + "components.batcher.remote_client_config.idle_timeout": 90, + "components.batcher.remote_client_config.retries": 3, + "components.batcher.remote_client_config.retry_interval": 3, + "components.batcher.url": "localhost", + "components.class_manager.execution_mode": "Disabled", + "components.class_manager.ip": "0.0.0.0", + "components.class_manager.local_server_config.channel_buffer_size": 32, + "components.class_manager.max_concurrency": 10, + "components.class_manager.port": 0, + "components.class_manager.remote_client_config.idle_connections": 18446744073709551615, + "components.class_manager.remote_client_config.idle_timeout": 90, + "components.class_manager.remote_client_config.retries": 3, + "components.class_manager.remote_client_config.retry_interval": 3, + "components.class_manager.url": "localhost", + "components.consensus_manager.execution_mode": "Disabled", + "components.gateway.execution_mode": "Disabled", + "components.gateway.ip": "0.0.0.0", + "components.gateway.local_server_config.channel_buffer_size": 32, + "components.gateway.max_concurrency": 10, + "components.gateway.port": 0, + "components.gateway.remote_client_config.idle_connections": 18446744073709551615, + "components.gateway.remote_client_config.idle_timeout": 90, + "components.gateway.remote_client_config.retries": 3, + "components.gateway.remote_client_config.retry_interval": 3, + "components.gateway.url": "localhost", + "components.http_server.execution_mode": "Disabled", + "components.l1_gas_price_provider.execution_mode": "Disabled", + "components.l1_gas_price_provider.ip": "0.0.0.0", + "components.l1_gas_price_provider.local_server_config.channel_buffer_size": 32, + "components.l1_gas_price_provider.max_concurrency": 10, + "components.l1_gas_price_provider.port": 0, + "components.l1_gas_price_provider.remote_client_config.idle_connections": 18446744073709551615, + "components.l1_gas_price_provider.remote_client_config.idle_timeout": 90, + "components.l1_gas_price_provider.remote_client_config.retries": 3, + "components.l1_gas_price_provider.remote_client_config.retry_interval": 3, + "components.l1_gas_price_provider.url": "localhost", + "components.l1_gas_price_scraper.execution_mode": "Disabled", + "components.l1_provider.execution_mode": "LocalExecutionWithRemoteEnabled", + "components.l1_provider.ip": "0.0.0.0", + "components.l1_provider.local_server_config.channel_buffer_size": 32, + "components.l1_provider.max_concurrency": 10, + "components.l1_provider.port": 55005, + "components.l1_provider.remote_client_config.idle_connections": 18446744073709551615, + "components.l1_provider.remote_client_config.idle_timeout": 90, + "components.l1_provider.remote_client_config.retries": 3, + "components.l1_provider.remote_client_config.retry_interval": 3, + "components.l1_provider.url": "sequencer-l1-provider-service", + "components.l1_scraper.execution_mode": "Enabled", + "components.mempool.execution_mode": "Disabled", + "components.mempool.ip": "0.0.0.0", + "components.mempool.local_server_config.channel_buffer_size": 32, + "components.mempool.max_concurrency": 10, + "components.mempool.port": 0, + "components.mempool.remote_client_config.idle_connections": 18446744073709551615, + "components.mempool.remote_client_config.idle_timeout": 90, + "components.mempool.remote_client_config.retries": 3, + "components.mempool.remote_client_config.retry_interval": 3, + "components.mempool.url": "localhost", + "components.mempool_p2p.execution_mode": "Disabled", + "components.mempool_p2p.ip": "0.0.0.0", + "components.mempool_p2p.local_server_config.channel_buffer_size": 32, + "components.mempool_p2p.max_concurrency": 10, + "components.mempool_p2p.port": 0, + "components.mempool_p2p.remote_client_config.idle_connections": 18446744073709551615, + "components.mempool_p2p.remote_client_config.idle_timeout": 90, + "components.mempool_p2p.remote_client_config.retries": 3, + "components.mempool_p2p.remote_client_config.retry_interval": 3, + "components.mempool_p2p.url": "localhost", + "components.monitoring_endpoint.execution_mode": "Enabled", + "components.sierra_compiler.execution_mode": "Disabled", + "components.sierra_compiler.ip": "0.0.0.0", + "components.sierra_compiler.local_server_config.channel_buffer_size": 32, + "components.sierra_compiler.max_concurrency": 10, + "components.sierra_compiler.port": 0, + "components.sierra_compiler.remote_client_config.idle_connections": 18446744073709551615, + "components.sierra_compiler.remote_client_config.idle_timeout": 90, + "components.sierra_compiler.remote_client_config.retries": 3, + "components.sierra_compiler.remote_client_config.retry_interval": 3, + "components.sierra_compiler.url": "localhost", + "components.state_sync.execution_mode": "Remote", + "components.state_sync.ip": "0.0.0.0", + "components.state_sync.local_server_config.channel_buffer_size": 32, + "components.state_sync.max_concurrency": 10, + "components.state_sync.port": 55008, + "components.state_sync.remote_client_config.idle_connections": 18446744073709551615, + "components.state_sync.remote_client_config.idle_timeout": 90, + "components.state_sync.remote_client_config.retries": 3, + "components.state_sync.remote_client_config.retry_interval": 3, + "components.state_sync.url": "sequencer-state-sync-service", + "consensus_manager_config.broadcast_buffer_size": 10000, + "consensus_manager_config.cende_config.skip_write_height": 1, + "consensus_manager_config.cende_config.skip_write_height.#is_none": false, + "consensus_manager_config.consensus_config.future_height_limit": 10, + "consensus_manager_config.consensus_config.future_height_round_limit": 1, + "consensus_manager_config.consensus_config.future_round_limit": 10, + "consensus_manager_config.consensus_config.startup_delay": 15, + "consensus_manager_config.consensus_config.sync_retry_interval": 1.0, + "consensus_manager_config.consensus_config.timeouts.precommit_timeout": 3.0, + "consensus_manager_config.consensus_config.timeouts.prevote_timeout": 3.0, + "consensus_manager_config.consensus_config.timeouts.proposal_timeout": 9.0, + "consensus_manager_config.context_config.block_timestamp_window": 1, + "consensus_manager_config.context_config.build_proposal_margin": 1000, + "consensus_manager_config.context_config.builder_address": "0x4", + "consensus_manager_config.context_config.l1_da_mode": true, + "consensus_manager_config.context_config.num_validators": 1, + "consensus_manager_config.context_config.proposal_buffer_size": 100, + "consensus_manager_config.context_config.validate_proposal_margin": 10000, + "consensus_manager_config.eth_to_strk_oracle_config.base_url": "http://127.0.0.1:53262/eth_to_strk_oracle?timestamp=", + "consensus_manager_config.eth_to_strk_oracle_config.headers": "", + "consensus_manager_config.immediate_active_height": 1, + "consensus_manager_config.network_config.advertised_multiaddr": "", + "consensus_manager_config.network_config.advertised_multiaddr.#is_none": true, + "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "", + "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": true, + "consensus_manager_config.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": 2, + "consensus_manager_config.network_config.discovery_config.bootstrap_dial_retry_config.factor": 5, + "consensus_manager_config.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": 5, + "consensus_manager_config.network_config.discovery_config.heartbeat_interval": 100, + "consensus_manager_config.network_config.idle_connection_timeout": 120, + "consensus_manager_config.network_config.peer_manager_config.malicious_timeout_seconds": 1, + "consensus_manager_config.network_config.peer_manager_config.unstable_timeout_millis": 1000, + "consensus_manager_config.network_config.port": 53080, + "consensus_manager_config.network_config.secret_key": "0x0101010101010101010101010101010101010101010101010101010101010101", + "consensus_manager_config.network_config.session_timeout": 120, + "consensus_manager_config.proposals_topic": "consensus_proposals", + "consensus_manager_config.votes_topic": "consensus_votes", + "eth_fee_token_address": "0x1001", + "gateway_config.stateful_tx_validator_config.max_allowed_nonce_gap": 50, + "gateway_config.stateful_tx_validator_config.max_nonce_for_validation_skip": "0x1", + "gateway_config.stateless_tx_validator_config.max_calldata_length": 10, + "gateway_config.stateless_tx_validator_config.max_contract_class_object_size": 4089446, + "gateway_config.stateless_tx_validator_config.max_sierra_version.major": 1, + "gateway_config.stateless_tx_validator_config.max_sierra_version.minor": 5, + "gateway_config.stateless_tx_validator_config.max_sierra_version.patch": 18446744073709551615, + "gateway_config.stateless_tx_validator_config.max_signature_length": 2, + "gateway_config.stateless_tx_validator_config.min_sierra_version.major": 1, + "gateway_config.stateless_tx_validator_config.min_sierra_version.minor": 1, + "gateway_config.stateless_tx_validator_config.min_sierra_version.patch": 0, + "gateway_config.stateless_tx_validator_config.validate_non_zero_l1_data_gas_fee": false, + "gateway_config.stateless_tx_validator_config.validate_non_zero_l1_gas_fee": true, + "gateway_config.stateless_tx_validator_config.validate_non_zero_l2_gas_fee": false, + "http_server_config.ip": "127.0.0.1", + "http_server_config.port": 53320, + "l1_gas_price_provider_config.lag_margin_seconds": 60, + "l1_gas_price_provider_config.number_of_blocks_for_mean": 300, + "l1_gas_price_provider_config.storage_limit": 3000, + "l1_gas_price_scraper_config.finality": 0, + "l1_gas_price_scraper_config.number_of_blocks_for_mean": 300, + "l1_gas_price_scraper_config.polling_interval": 1, + "l1_gas_price_scraper_config.starting_block": 0, + "l1_gas_price_scraper_config.starting_block.#is_none": true, + "l1_provider_config.bootstrap_catch_up_height_override": 0, + "l1_provider_config.bootstrap_catch_up_height_override.#is_none": true, + "l1_provider_config.provider_startup_height_override": 1, + "l1_provider_config.provider_startup_height_override.#is_none": false, + "l1_provider_config.startup_sync_sleep_retry_interval": 0.0, + "l1_scraper_config.finality": 0, + "l1_scraper_config.polling_interval": 1, + "l1_scraper_config.startup_rewind_time": 0, + "mempool_config.committed_nonce_retention_block_count": 100, + "mempool_config.declare_delay": 1, + "mempool_config.enable_fee_escalation": true, + "mempool_config.fee_escalation_percentage": 10, + "mempool_config.transaction_ttl": 300, + "mempool_p2p_config.max_transaction_batch_size": 1, + "mempool_p2p_config.network_buffer_size": 10000, + "mempool_p2p_config.network_config.advertised_multiaddr": "", + "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": true, + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "", + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": true, + "mempool_p2p_config.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": 2, + "mempool_p2p_config.network_config.discovery_config.bootstrap_dial_retry_config.factor": 5, + "mempool_p2p_config.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": 5, + "mempool_p2p_config.network_config.discovery_config.heartbeat_interval": 100, + "mempool_p2p_config.network_config.idle_connection_timeout": 120, + "mempool_p2p_config.network_config.peer_manager_config.malicious_timeout_seconds": 1, + "mempool_p2p_config.network_config.peer_manager_config.unstable_timeout_millis": 1000, + "mempool_p2p_config.network_config.port": 53200, + "mempool_p2p_config.network_config.secret_key": "0x0101010101010101010101010101010101010101010101010101010101010101", + "mempool_p2p_config.network_config.session_timeout": 120, + "mempool_p2p_config.transaction_batch_rate_millis": 1000, + "monitoring_config.collect_metrics": true, + "monitoring_config.collect_profiling_metrics": true, + "monitoring_endpoint_config.collect_metrics": true, + "monitoring_endpoint_config.collect_profiling_metrics": true, + "monitoring_endpoint_config.ip": "0.0.0.0", + "monitoring_endpoint_config.port": 8082, + "recorder_url": "http://127.0.0.1:53261/", + "revert_config.revert_up_to_and_including": 18446744073709551615, + "revert_config.should_revert": false, + "state_sync_config.central_sync_client_config.#is_none": true, + "state_sync_config.central_sync_client_config.central_source_config.class_cache_size": 100, + "state_sync_config.central_sync_client_config.central_source_config.concurrent_requests": 10, + "state_sync_config.central_sync_client_config.central_source_config.http_headers": "", + "state_sync_config.central_sync_client_config.central_source_config.max_classes_to_download": 20, + "state_sync_config.central_sync_client_config.central_source_config.max_state_updates_to_download": 20, + "state_sync_config.central_sync_client_config.central_source_config.max_state_updates_to_store_in_memory": 20, + "state_sync_config.central_sync_client_config.central_source_config.retry_config.max_retries": 10, + "state_sync_config.central_sync_client_config.central_source_config.retry_config.retry_base_millis": 30, + "state_sync_config.central_sync_client_config.central_source_config.retry_config.retry_max_delay_millis": 30000, + "state_sync_config.central_sync_client_config.central_source_config.starknet_url": "https://alpha-mainnet.starknet.io/", + "state_sync_config.central_sync_client_config.sync_config.base_layer_propagation_sleep_duration": 10, + "state_sync_config.central_sync_client_config.sync_config.block_propagation_sleep_duration": 2, + "state_sync_config.central_sync_client_config.sync_config.blocks_max_stream_size": 1000, + "state_sync_config.central_sync_client_config.sync_config.collect_pending_data": false, + "state_sync_config.central_sync_client_config.sync_config.recoverable_error_sleep_duration": 3, + "state_sync_config.central_sync_client_config.sync_config.state_updates_max_stream_size": 1000, + "state_sync_config.central_sync_client_config.sync_config.store_sierras_and_casms": false, + "state_sync_config.central_sync_client_config.sync_config.verify_blocks": true, + "state_sync_config.network_config.advertised_multiaddr": "", + "state_sync_config.network_config.advertised_multiaddr.#is_none": true, + "state_sync_config.network_config.bootstrap_peer_multiaddr": "", + "state_sync_config.network_config.bootstrap_peer_multiaddr.#is_none": true, + "state_sync_config.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": 2, + "state_sync_config.network_config.discovery_config.bootstrap_dial_retry_config.factor": 5, + "state_sync_config.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": 5, + "state_sync_config.network_config.discovery_config.heartbeat_interval": 100, + "state_sync_config.network_config.idle_connection_timeout": 120, + "state_sync_config.network_config.peer_manager_config.malicious_timeout_seconds": 1, + "state_sync_config.network_config.peer_manager_config.unstable_timeout_millis": 1000, + "state_sync_config.network_config.port": 53140, + "state_sync_config.network_config.secret_key": "0x0101010101010101010101010101010101010101010101010101010101010101", + "state_sync_config.network_config.session_timeout": 120, + "state_sync_config.p2p_sync_client_config.#is_none": false, + "state_sync_config.p2p_sync_client_config.buffer_size": 100000, + "state_sync_config.p2p_sync_client_config.num_block_classes_per_query": 100, + "state_sync_config.p2p_sync_client_config.num_block_state_diffs_per_query": 100, + "state_sync_config.p2p_sync_client_config.num_block_transactions_per_query": 100, + "state_sync_config.p2p_sync_client_config.num_headers_per_query": 10000, + "state_sync_config.p2p_sync_client_config.wait_period_for_new_data": 50, + "state_sync_config.p2p_sync_client_config.wait_period_for_other_protocol": 50, + "state_sync_config.storage_config.db_config.enforce_file_exists": false, + "state_sync_config.storage_config.db_config.growth_step": 67108864, + "state_sync_config.storage_config.db_config.max_size": 34359738368, + "state_sync_config.storage_config.db_config.min_size": 1048576, + "state_sync_config.storage_config.db_config.path_prefix": "/data/node_0/executable_0/state_sync", + "state_sync_config.storage_config.mmap_file_config.growth_step": 1048576, + "state_sync_config.storage_config.mmap_file_config.max_object_size": 65536, + "state_sync_config.storage_config.mmap_file_config.max_size": 16777216, + "state_sync_config.storage_config.scope": "FullArchive", + "strk_fee_token_address": "0x1002", + "validator_id": "0x64", + "versioned_constants_overrides.invoke_tx_max_n_steps": 10000000, + "versioned_constants_overrides.max_n_events": 1000, + "versioned_constants_overrides.max_recursion_depth": 50, + "versioned_constants_overrides.validate_max_n_steps": 1000000 +} diff --git a/config/sequencer/presets/distributed_node/application_configs/mempool.json b/config/sequencer/presets/distributed_node/application_configs/mempool.json new file mode 100644 index 00000000000..549a8d4728f --- /dev/null +++ b/config/sequencer/presets/distributed_node/application_configs/mempool.json @@ -0,0 +1,306 @@ +{ + "base_layer_config.node_url": "http://localhost:53260/", + "base_layer_config.starknet_contract_address": "0x5FbDB2315678afecb367f032d93F642f64180aa3", + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.l1_gas": 2500000, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.message_segment_length": 3700, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.n_events": 5000, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.sierra_gas": 30000000, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.state_diff_size": 4000, + "batcher_config.block_builder_config.execute_config.concurrency_config.chunk_size": 64, + "batcher_config.block_builder_config.execute_config.concurrency_config.enabled": true, + "batcher_config.block_builder_config.execute_config.concurrency_config.n_workers": 4, + "batcher_config.block_builder_config.execute_config.stack_size": 62914560, + "batcher_config.block_builder_config.tx_chunk_size": 100, + "batcher_config.contract_class_manager_config.cairo_native_run_config.channel_size": 2000, + "batcher_config.contract_class_manager_config.cairo_native_run_config.native_classes_whitelist": "All", + "batcher_config.contract_class_manager_config.cairo_native_run_config.run_cairo_native": false, + "batcher_config.contract_class_manager_config.cairo_native_run_config.wait_on_native_compilation": false, + "batcher_config.contract_class_manager_config.contract_cache_size": 600, + "batcher_config.contract_class_manager_config.native_compiler_config.max_casm_bytecode_size": 81920, + "batcher_config.contract_class_manager_config.native_compiler_config.max_cpu_time": 20, + "batcher_config.contract_class_manager_config.native_compiler_config.max_memory_usage": 5368709120, + "batcher_config.contract_class_manager_config.native_compiler_config.max_native_bytecode_size": 15728640, + "batcher_config.contract_class_manager_config.native_compiler_config.optimization_level": 2, + "batcher_config.contract_class_manager_config.native_compiler_config.panic_on_compilation_failure": false, + "batcher_config.contract_class_manager_config.native_compiler_config.sierra_to_native_compiler_path": "", + "batcher_config.contract_class_manager_config.native_compiler_config.sierra_to_native_compiler_path.#is_none": true, + "batcher_config.input_stream_content_buffer_size": 400, + "batcher_config.max_l1_handler_txs_per_block_proposal": 3, + "batcher_config.outstream_content_buffer_size": 100, + "batcher_config.storage.db_config.enforce_file_exists": false, + "batcher_config.storage.db_config.growth_step": 67108864, + "batcher_config.storage.db_config.max_size": 34359738368, + "batcher_config.storage.db_config.min_size": 1048576, + "batcher_config.storage.db_config.path_prefix": "/data/node_0/executable_0/batcher", + "batcher_config.storage.mmap_file_config.growth_step": 1048576, + "batcher_config.storage.mmap_file_config.max_object_size": 65536, + "batcher_config.storage.mmap_file_config.max_size": 16777216, + "batcher_config.storage.scope": "StateOnly", + "chain_id": "CHAIN_ID_SUBDIR", + "class_manager_config.class_manager_config.cached_class_storage_config.class_cache_size": 100, + "class_manager_config.class_manager_config.cached_class_storage_config.deprecated_class_cache_size": 100, + "class_manager_config.class_storage_config.class_hash_storage_config.enforce_file_exists": false, + "class_manager_config.class_storage_config.class_hash_storage_config.max_size": 1048576, + "class_manager_config.class_storage_config.class_hash_storage_config.path_prefix": "/data/node_0/executable_0/class_manager/class_hash_storage", + "class_manager_config.class_storage_config.persistent_root": "/data/node_0/executable_0/class_manager/classes", + "compiler_config.max_casm_bytecode_size": 81920, + "compiler_config.max_cpu_time": 20, + "compiler_config.max_memory_usage": 5368709120, + "compiler_config.max_native_bytecode_size": 15728640, + "compiler_config.optimization_level": 2, + "compiler_config.panic_on_compilation_failure": false, + "compiler_config.sierra_to_native_compiler_path": "", + "compiler_config.sierra_to_native_compiler_path.#is_none": true, + "components.batcher.execution_mode": "Disabled", + "components.batcher.ip": "0.0.0.0", + "components.batcher.local_server_config.channel_buffer_size": 32, + "components.batcher.max_concurrency": 10, + "components.batcher.port": 0, + "components.batcher.remote_client_config.idle_connections": 18446744073709551615, + "components.batcher.remote_client_config.idle_timeout": 90, + "components.batcher.remote_client_config.retries": 3, + "components.batcher.remote_client_config.retry_interval": 3, + "components.batcher.url": "localhost", + "components.class_manager.execution_mode": "Remote", + "components.class_manager.ip": "0.0.0.0", + "components.class_manager.local_server_config.channel_buffer_size": 32, + "components.class_manager.max_concurrency": 10, + "components.class_manager.port": 55001, + "components.class_manager.remote_client_config.idle_connections": 18446744073709551615, + "components.class_manager.remote_client_config.idle_timeout": 90, + "components.class_manager.remote_client_config.retries": 3, + "components.class_manager.remote_client_config.retry_interval": 3, + "components.class_manager.url": "sequencer-class-manager-service", + "components.consensus_manager.execution_mode": "Disabled", + "components.gateway.execution_mode": "Remote", + "components.gateway.ip": "0.0.0.0", + "components.gateway.local_server_config.channel_buffer_size": 32, + "components.gateway.max_concurrency": 10, + "components.gateway.port": 55004, + "components.gateway.remote_client_config.idle_connections": 18446744073709551615, + "components.gateway.remote_client_config.idle_timeout": 90, + "components.gateway.remote_client_config.retries": 3, + "components.gateway.remote_client_config.retry_interval": 3, + "components.gateway.url": "sequencer-gateway-service", + "components.http_server.execution_mode": "Disabled", + "components.l1_gas_price_provider.execution_mode": "Disabled", + "components.l1_gas_price_provider.ip": "0.0.0.0", + "components.l1_gas_price_provider.local_server_config.channel_buffer_size": 32, + "components.l1_gas_price_provider.max_concurrency": 10, + "components.l1_gas_price_provider.port": 0, + "components.l1_gas_price_provider.remote_client_config.idle_connections": 18446744073709551615, + "components.l1_gas_price_provider.remote_client_config.idle_timeout": 90, + "components.l1_gas_price_provider.remote_client_config.retries": 3, + "components.l1_gas_price_provider.remote_client_config.retry_interval": 3, + "components.l1_gas_price_provider.url": "localhost", + "components.l1_gas_price_scraper.execution_mode": "Disabled", + "components.l1_provider.execution_mode": "Disabled", + "components.l1_provider.ip": "0.0.0.0", + "components.l1_provider.local_server_config.channel_buffer_size": 32, + "components.l1_provider.max_concurrency": 10, + "components.l1_provider.port": 0, + "components.l1_provider.remote_client_config.idle_connections": 18446744073709551615, + "components.l1_provider.remote_client_config.idle_timeout": 90, + "components.l1_provider.remote_client_config.retries": 3, + "components.l1_provider.remote_client_config.retry_interval": 3, + "components.l1_provider.url": "localhost", + "components.l1_scraper.execution_mode": "Disabled", + "components.mempool.execution_mode": "LocalExecutionWithRemoteEnabled", + "components.mempool.ip": "0.0.0.0", + "components.mempool.local_server_config.channel_buffer_size": 32, + "components.mempool.max_concurrency": 10, + "components.mempool.port": 55006, + "components.mempool.remote_client_config.idle_connections": 18446744073709551615, + "components.mempool.remote_client_config.idle_timeout": 90, + "components.mempool.remote_client_config.retries": 3, + "components.mempool.remote_client_config.retry_interval": 3, + "components.mempool.url": "sequencer-mempool-service", + "components.mempool_p2p.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.mempool_p2p.ip": "0.0.0.0", + "components.mempool_p2p.local_server_config.channel_buffer_size": 32, + "components.mempool_p2p.max_concurrency": 10, + "components.mempool_p2p.port": 0, + "components.mempool_p2p.remote_client_config.idle_connections": 18446744073709551615, + "components.mempool_p2p.remote_client_config.idle_timeout": 90, + "components.mempool_p2p.remote_client_config.retries": 3, + "components.mempool_p2p.remote_client_config.retry_interval": 3, + "components.mempool_p2p.url": "localhost", + "components.monitoring_endpoint.execution_mode": "Enabled", + "components.sierra_compiler.execution_mode": "Disabled", + "components.sierra_compiler.ip": "0.0.0.0", + "components.sierra_compiler.local_server_config.channel_buffer_size": 32, + "components.sierra_compiler.max_concurrency": 10, + "components.sierra_compiler.port": 0, + "components.sierra_compiler.remote_client_config.idle_connections": 18446744073709551615, + "components.sierra_compiler.remote_client_config.idle_timeout": 90, + "components.sierra_compiler.remote_client_config.retries": 3, + "components.sierra_compiler.remote_client_config.retry_interval": 3, + "components.sierra_compiler.url": "localhost", + "components.state_sync.execution_mode": "Disabled", + "components.state_sync.ip": "0.0.0.0", + "components.state_sync.local_server_config.channel_buffer_size": 32, + "components.state_sync.max_concurrency": 10, + "components.state_sync.port": 0, + "components.state_sync.remote_client_config.idle_connections": 18446744073709551615, + "components.state_sync.remote_client_config.idle_timeout": 90, + "components.state_sync.remote_client_config.retries": 3, + "components.state_sync.remote_client_config.retry_interval": 3, + "components.state_sync.url": "localhost", + "consensus_manager_config.broadcast_buffer_size": 10000, + "consensus_manager_config.cende_config.skip_write_height": 1, + "consensus_manager_config.cende_config.skip_write_height.#is_none": false, + "consensus_manager_config.consensus_config.future_height_limit": 10, + "consensus_manager_config.consensus_config.future_height_round_limit": 1, + "consensus_manager_config.consensus_config.future_round_limit": 10, + "consensus_manager_config.consensus_config.startup_delay": 15, + "consensus_manager_config.consensus_config.sync_retry_interval": 1.0, + "consensus_manager_config.consensus_config.timeouts.precommit_timeout": 3.0, + "consensus_manager_config.consensus_config.timeouts.prevote_timeout": 3.0, + "consensus_manager_config.consensus_config.timeouts.proposal_timeout": 9.0, + "consensus_manager_config.context_config.block_timestamp_window": 1, + "consensus_manager_config.context_config.build_proposal_margin": 1000, + "consensus_manager_config.context_config.builder_address": "0x4", + "consensus_manager_config.context_config.l1_da_mode": true, + "consensus_manager_config.context_config.num_validators": 1, + "consensus_manager_config.context_config.proposal_buffer_size": 100, + "consensus_manager_config.context_config.validate_proposal_margin": 10000, + "consensus_manager_config.eth_to_strk_oracle_config.base_url": "http://127.0.0.1:53262/eth_to_strk_oracle?timestamp=", + "consensus_manager_config.eth_to_strk_oracle_config.headers": "", + "consensus_manager_config.immediate_active_height": 1, + "consensus_manager_config.network_config.advertised_multiaddr": "", + "consensus_manager_config.network_config.advertised_multiaddr.#is_none": true, + "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "", + "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": true, + "consensus_manager_config.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": 2, + "consensus_manager_config.network_config.discovery_config.bootstrap_dial_retry_config.factor": 5, + "consensus_manager_config.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": 5, + "consensus_manager_config.network_config.discovery_config.heartbeat_interval": 100, + "consensus_manager_config.network_config.idle_connection_timeout": 120, + "consensus_manager_config.network_config.peer_manager_config.malicious_timeout_seconds": 1, + "consensus_manager_config.network_config.peer_manager_config.unstable_timeout_millis": 1000, + "consensus_manager_config.network_config.port": 53080, + "consensus_manager_config.network_config.secret_key": "0x0101010101010101010101010101010101010101010101010101010101010101", + "consensus_manager_config.network_config.session_timeout": 120, + "consensus_manager_config.proposals_topic": "consensus_proposals", + "consensus_manager_config.votes_topic": "consensus_votes", + "eth_fee_token_address": "0x1001", + "gateway_config.stateful_tx_validator_config.max_allowed_nonce_gap": 50, + "gateway_config.stateful_tx_validator_config.max_nonce_for_validation_skip": "0x1", + "gateway_config.stateless_tx_validator_config.max_calldata_length": 10, + "gateway_config.stateless_tx_validator_config.max_contract_class_object_size": 4089446, + "gateway_config.stateless_tx_validator_config.max_sierra_version.major": 1, + "gateway_config.stateless_tx_validator_config.max_sierra_version.minor": 5, + "gateway_config.stateless_tx_validator_config.max_sierra_version.patch": 18446744073709551615, + "gateway_config.stateless_tx_validator_config.max_signature_length": 2, + "gateway_config.stateless_tx_validator_config.min_sierra_version.major": 1, + "gateway_config.stateless_tx_validator_config.min_sierra_version.minor": 1, + "gateway_config.stateless_tx_validator_config.min_sierra_version.patch": 0, + "gateway_config.stateless_tx_validator_config.validate_non_zero_l1_data_gas_fee": false, + "gateway_config.stateless_tx_validator_config.validate_non_zero_l1_gas_fee": true, + "gateway_config.stateless_tx_validator_config.validate_non_zero_l2_gas_fee": false, + "http_server_config.ip": "127.0.0.1", + "http_server_config.port": 53320, + "l1_gas_price_provider_config.lag_margin_seconds": 60, + "l1_gas_price_provider_config.number_of_blocks_for_mean": 300, + "l1_gas_price_provider_config.storage_limit": 3000, + "l1_gas_price_scraper_config.finality": 0, + "l1_gas_price_scraper_config.number_of_blocks_for_mean": 300, + "l1_gas_price_scraper_config.polling_interval": 1, + "l1_gas_price_scraper_config.starting_block": 0, + "l1_gas_price_scraper_config.starting_block.#is_none": true, + "l1_provider_config.bootstrap_catch_up_height_override": 0, + "l1_provider_config.bootstrap_catch_up_height_override.#is_none": true, + "l1_provider_config.provider_startup_height_override": 1, + "l1_provider_config.provider_startup_height_override.#is_none": false, + "l1_provider_config.startup_sync_sleep_retry_interval": 0.0, + "l1_scraper_config.finality": 0, + "l1_scraper_config.polling_interval": 1, + "l1_scraper_config.startup_rewind_time": 0, + "mempool_config.committed_nonce_retention_block_count": 100, + "mempool_config.declare_delay": 1, + "mempool_config.enable_fee_escalation": true, + "mempool_config.fee_escalation_percentage": 10, + "mempool_config.transaction_ttl": 300, + "mempool_p2p_config.max_transaction_batch_size": 1, + "mempool_p2p_config.network_buffer_size": 10000, + "mempool_p2p_config.network_config.advertised_multiaddr": "", + "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": true, + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "", + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": true, + "mempool_p2p_config.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": 2, + "mempool_p2p_config.network_config.discovery_config.bootstrap_dial_retry_config.factor": 5, + "mempool_p2p_config.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": 5, + "mempool_p2p_config.network_config.discovery_config.heartbeat_interval": 100, + "mempool_p2p_config.network_config.idle_connection_timeout": 120, + "mempool_p2p_config.network_config.peer_manager_config.malicious_timeout_seconds": 1, + "mempool_p2p_config.network_config.peer_manager_config.unstable_timeout_millis": 1000, + "mempool_p2p_config.network_config.port": 53200, + "mempool_p2p_config.network_config.secret_key": "0x0101010101010101010101010101010101010101010101010101010101010101", + "mempool_p2p_config.network_config.session_timeout": 120, + "mempool_p2p_config.transaction_batch_rate_millis": 1000, + "monitoring_config.collect_metrics": true, + "monitoring_config.collect_profiling_metrics": true, + "monitoring_endpoint_config.collect_metrics": true, + "monitoring_endpoint_config.collect_profiling_metrics": true, + "monitoring_endpoint_config.ip": "0.0.0.0", + "monitoring_endpoint_config.port": 8082, + "recorder_url": "http://127.0.0.1:53261/", + "revert_config.revert_up_to_and_including": 18446744073709551615, + "revert_config.should_revert": false, + "state_sync_config.central_sync_client_config.#is_none": true, + "state_sync_config.central_sync_client_config.central_source_config.class_cache_size": 100, + "state_sync_config.central_sync_client_config.central_source_config.concurrent_requests": 10, + "state_sync_config.central_sync_client_config.central_source_config.http_headers": "", + "state_sync_config.central_sync_client_config.central_source_config.max_classes_to_download": 20, + "state_sync_config.central_sync_client_config.central_source_config.max_state_updates_to_download": 20, + "state_sync_config.central_sync_client_config.central_source_config.max_state_updates_to_store_in_memory": 20, + "state_sync_config.central_sync_client_config.central_source_config.retry_config.max_retries": 10, + "state_sync_config.central_sync_client_config.central_source_config.retry_config.retry_base_millis": 30, + "state_sync_config.central_sync_client_config.central_source_config.retry_config.retry_max_delay_millis": 30000, + "state_sync_config.central_sync_client_config.central_source_config.starknet_url": "https://alpha-mainnet.starknet.io/", + "state_sync_config.central_sync_client_config.sync_config.base_layer_propagation_sleep_duration": 10, + "state_sync_config.central_sync_client_config.sync_config.block_propagation_sleep_duration": 2, + "state_sync_config.central_sync_client_config.sync_config.blocks_max_stream_size": 1000, + "state_sync_config.central_sync_client_config.sync_config.collect_pending_data": false, + "state_sync_config.central_sync_client_config.sync_config.recoverable_error_sleep_duration": 3, + "state_sync_config.central_sync_client_config.sync_config.state_updates_max_stream_size": 1000, + "state_sync_config.central_sync_client_config.sync_config.store_sierras_and_casms": false, + "state_sync_config.central_sync_client_config.sync_config.verify_blocks": true, + "state_sync_config.network_config.advertised_multiaddr": "", + "state_sync_config.network_config.advertised_multiaddr.#is_none": true, + "state_sync_config.network_config.bootstrap_peer_multiaddr": "", + "state_sync_config.network_config.bootstrap_peer_multiaddr.#is_none": true, + "state_sync_config.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": 2, + "state_sync_config.network_config.discovery_config.bootstrap_dial_retry_config.factor": 5, + "state_sync_config.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": 5, + "state_sync_config.network_config.discovery_config.heartbeat_interval": 100, + "state_sync_config.network_config.idle_connection_timeout": 120, + "state_sync_config.network_config.peer_manager_config.malicious_timeout_seconds": 1, + "state_sync_config.network_config.peer_manager_config.unstable_timeout_millis": 1000, + "state_sync_config.network_config.port": 53140, + "state_sync_config.network_config.secret_key": "0x0101010101010101010101010101010101010101010101010101010101010101", + "state_sync_config.network_config.session_timeout": 120, + "state_sync_config.p2p_sync_client_config.#is_none": false, + "state_sync_config.p2p_sync_client_config.buffer_size": 100000, + "state_sync_config.p2p_sync_client_config.num_block_classes_per_query": 100, + "state_sync_config.p2p_sync_client_config.num_block_state_diffs_per_query": 100, + "state_sync_config.p2p_sync_client_config.num_block_transactions_per_query": 100, + "state_sync_config.p2p_sync_client_config.num_headers_per_query": 10000, + "state_sync_config.p2p_sync_client_config.wait_period_for_new_data": 50, + "state_sync_config.p2p_sync_client_config.wait_period_for_other_protocol": 50, + "state_sync_config.storage_config.db_config.enforce_file_exists": false, + "state_sync_config.storage_config.db_config.growth_step": 67108864, + "state_sync_config.storage_config.db_config.max_size": 34359738368, + "state_sync_config.storage_config.db_config.min_size": 1048576, + "state_sync_config.storage_config.db_config.path_prefix": "/data/node_0/executable_0/state_sync", + "state_sync_config.storage_config.mmap_file_config.growth_step": 1048576, + "state_sync_config.storage_config.mmap_file_config.max_object_size": 65536, + "state_sync_config.storage_config.mmap_file_config.max_size": 16777216, + "state_sync_config.storage_config.scope": "FullArchive", + "strk_fee_token_address": "0x1002", + "validator_id": "0x64", + "versioned_constants_overrides.invoke_tx_max_n_steps": 10000000, + "versioned_constants_overrides.max_n_events": 1000, + "versioned_constants_overrides.max_recursion_depth": 50, + "versioned_constants_overrides.validate_max_n_steps": 1000000 +} diff --git a/config/sequencer/presets/distributed_node/application_configs/sierra_compiler.json b/config/sequencer/presets/distributed_node/application_configs/sierra_compiler.json new file mode 100644 index 00000000000..f8e2b218c10 --- /dev/null +++ b/config/sequencer/presets/distributed_node/application_configs/sierra_compiler.json @@ -0,0 +1,306 @@ +{ + "base_layer_config.node_url": "http://localhost:53260/", + "base_layer_config.starknet_contract_address": "0x5FbDB2315678afecb367f032d93F642f64180aa3", + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.l1_gas": 2500000, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.message_segment_length": 3700, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.n_events": 5000, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.sierra_gas": 30000000, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.state_diff_size": 4000, + "batcher_config.block_builder_config.execute_config.concurrency_config.chunk_size": 64, + "batcher_config.block_builder_config.execute_config.concurrency_config.enabled": true, + "batcher_config.block_builder_config.execute_config.concurrency_config.n_workers": 4, + "batcher_config.block_builder_config.execute_config.stack_size": 62914560, + "batcher_config.block_builder_config.tx_chunk_size": 100, + "batcher_config.contract_class_manager_config.cairo_native_run_config.channel_size": 2000, + "batcher_config.contract_class_manager_config.cairo_native_run_config.native_classes_whitelist": "All", + "batcher_config.contract_class_manager_config.cairo_native_run_config.run_cairo_native": false, + "batcher_config.contract_class_manager_config.cairo_native_run_config.wait_on_native_compilation": false, + "batcher_config.contract_class_manager_config.contract_cache_size": 600, + "batcher_config.contract_class_manager_config.native_compiler_config.max_casm_bytecode_size": 81920, + "batcher_config.contract_class_manager_config.native_compiler_config.max_cpu_time": 20, + "batcher_config.contract_class_manager_config.native_compiler_config.max_memory_usage": 5368709120, + "batcher_config.contract_class_manager_config.native_compiler_config.max_native_bytecode_size": 15728640, + "batcher_config.contract_class_manager_config.native_compiler_config.optimization_level": 2, + "batcher_config.contract_class_manager_config.native_compiler_config.panic_on_compilation_failure": false, + "batcher_config.contract_class_manager_config.native_compiler_config.sierra_to_native_compiler_path": "", + "batcher_config.contract_class_manager_config.native_compiler_config.sierra_to_native_compiler_path.#is_none": true, + "batcher_config.input_stream_content_buffer_size": 400, + "batcher_config.max_l1_handler_txs_per_block_proposal": 3, + "batcher_config.outstream_content_buffer_size": 100, + "batcher_config.storage.db_config.enforce_file_exists": false, + "batcher_config.storage.db_config.growth_step": 67108864, + "batcher_config.storage.db_config.max_size": 34359738368, + "batcher_config.storage.db_config.min_size": 1048576, + "batcher_config.storage.db_config.path_prefix": "/data/node_0/executable_0/batcher", + "batcher_config.storage.mmap_file_config.growth_step": 1048576, + "batcher_config.storage.mmap_file_config.max_object_size": 65536, + "batcher_config.storage.mmap_file_config.max_size": 16777216, + "batcher_config.storage.scope": "StateOnly", + "chain_id": "CHAIN_ID_SUBDIR", + "class_manager_config.class_manager_config.cached_class_storage_config.class_cache_size": 100, + "class_manager_config.class_manager_config.cached_class_storage_config.deprecated_class_cache_size": 100, + "class_manager_config.class_storage_config.class_hash_storage_config.enforce_file_exists": false, + "class_manager_config.class_storage_config.class_hash_storage_config.max_size": 1048576, + "class_manager_config.class_storage_config.class_hash_storage_config.path_prefix": "/data/node_0/executable_0/class_manager/class_hash_storage", + "class_manager_config.class_storage_config.persistent_root": "/data/node_0/executable_0/class_manager/classes", + "compiler_config.max_casm_bytecode_size": 81920, + "compiler_config.max_cpu_time": 20, + "compiler_config.max_memory_usage": 5368709120, + "compiler_config.max_native_bytecode_size": 15728640, + "compiler_config.optimization_level": 2, + "compiler_config.panic_on_compilation_failure": false, + "compiler_config.sierra_to_native_compiler_path": "", + "compiler_config.sierra_to_native_compiler_path.#is_none": true, + "components.batcher.execution_mode": "Disabled", + "components.batcher.ip": "0.0.0.0", + "components.batcher.local_server_config.channel_buffer_size": 32, + "components.batcher.max_concurrency": 10, + "components.batcher.port": 0, + "components.batcher.remote_client_config.idle_connections": 18446744073709551615, + "components.batcher.remote_client_config.idle_timeout": 90, + "components.batcher.remote_client_config.retries": 3, + "components.batcher.remote_client_config.retry_interval": 3, + "components.batcher.url": "localhost", + "components.class_manager.execution_mode": "Disabled", + "components.class_manager.ip": "0.0.0.0", + "components.class_manager.local_server_config.channel_buffer_size": 32, + "components.class_manager.max_concurrency": 10, + "components.class_manager.port": 0, + "components.class_manager.remote_client_config.idle_connections": 18446744073709551615, + "components.class_manager.remote_client_config.idle_timeout": 90, + "components.class_manager.remote_client_config.retries": 3, + "components.class_manager.remote_client_config.retry_interval": 3, + "components.class_manager.url": "localhost", + "components.consensus_manager.execution_mode": "Disabled", + "components.gateway.execution_mode": "Disabled", + "components.gateway.ip": "0.0.0.0", + "components.gateway.local_server_config.channel_buffer_size": 32, + "components.gateway.max_concurrency": 10, + "components.gateway.port": 0, + "components.gateway.remote_client_config.idle_connections": 18446744073709551615, + "components.gateway.remote_client_config.idle_timeout": 90, + "components.gateway.remote_client_config.retries": 3, + "components.gateway.remote_client_config.retry_interval": 3, + "components.gateway.url": "localhost", + "components.http_server.execution_mode": "Disabled", + "components.l1_gas_price_provider.execution_mode": "Disabled", + "components.l1_gas_price_provider.ip": "0.0.0.0", + "components.l1_gas_price_provider.local_server_config.channel_buffer_size": 32, + "components.l1_gas_price_provider.max_concurrency": 10, + "components.l1_gas_price_provider.port": 0, + "components.l1_gas_price_provider.remote_client_config.idle_connections": 18446744073709551615, + "components.l1_gas_price_provider.remote_client_config.idle_timeout": 90, + "components.l1_gas_price_provider.remote_client_config.retries": 3, + "components.l1_gas_price_provider.remote_client_config.retry_interval": 3, + "components.l1_gas_price_provider.url": "localhost", + "components.l1_gas_price_scraper.execution_mode": "Disabled", + "components.l1_provider.execution_mode": "Disabled", + "components.l1_provider.ip": "0.0.0.0", + "components.l1_provider.local_server_config.channel_buffer_size": 32, + "components.l1_provider.max_concurrency": 10, + "components.l1_provider.port": 0, + "components.l1_provider.remote_client_config.idle_connections": 18446744073709551615, + "components.l1_provider.remote_client_config.idle_timeout": 90, + "components.l1_provider.remote_client_config.retries": 3, + "components.l1_provider.remote_client_config.retry_interval": 3, + "components.l1_provider.url": "localhost", + "components.l1_scraper.execution_mode": "Disabled", + "components.mempool.execution_mode": "Disabled", + "components.mempool.ip": "0.0.0.0", + "components.mempool.local_server_config.channel_buffer_size": 32, + "components.mempool.max_concurrency": 10, + "components.mempool.port": 0, + "components.mempool.remote_client_config.idle_connections": 18446744073709551615, + "components.mempool.remote_client_config.idle_timeout": 90, + "components.mempool.remote_client_config.retries": 3, + "components.mempool.remote_client_config.retry_interval": 3, + "components.mempool.url": "localhost", + "components.mempool_p2p.execution_mode": "Disabled", + "components.mempool_p2p.ip": "0.0.0.0", + "components.mempool_p2p.local_server_config.channel_buffer_size": 32, + "components.mempool_p2p.max_concurrency": 10, + "components.mempool_p2p.port": 0, + "components.mempool_p2p.remote_client_config.idle_connections": 18446744073709551615, + "components.mempool_p2p.remote_client_config.idle_timeout": 90, + "components.mempool_p2p.remote_client_config.retries": 3, + "components.mempool_p2p.remote_client_config.retry_interval": 3, + "components.mempool_p2p.url": "localhost", + "components.monitoring_endpoint.execution_mode": "Enabled", + "components.sierra_compiler.execution_mode": "LocalExecutionWithRemoteEnabled", + "components.sierra_compiler.ip": "0.0.0.0", + "components.sierra_compiler.local_server_config.channel_buffer_size": 32, + "components.sierra_compiler.max_concurrency": 10, + "components.sierra_compiler.port": 55007, + "components.sierra_compiler.remote_client_config.idle_connections": 18446744073709551615, + "components.sierra_compiler.remote_client_config.idle_timeout": 90, + "components.sierra_compiler.remote_client_config.retries": 3, + "components.sierra_compiler.remote_client_config.retry_interval": 3, + "components.sierra_compiler.url": "sequencer-sierra-compiler-service", + "components.state_sync.execution_mode": "Disabled", + "components.state_sync.ip": "0.0.0.0", + "components.state_sync.local_server_config.channel_buffer_size": 32, + "components.state_sync.max_concurrency": 10, + "components.state_sync.port": 0, + "components.state_sync.remote_client_config.idle_connections": 18446744073709551615, + "components.state_sync.remote_client_config.idle_timeout": 90, + "components.state_sync.remote_client_config.retries": 3, + "components.state_sync.remote_client_config.retry_interval": 3, + "components.state_sync.url": "localhost", + "consensus_manager_config.broadcast_buffer_size": 10000, + "consensus_manager_config.cende_config.skip_write_height": 1, + "consensus_manager_config.cende_config.skip_write_height.#is_none": false, + "consensus_manager_config.consensus_config.future_height_limit": 10, + "consensus_manager_config.consensus_config.future_height_round_limit": 1, + "consensus_manager_config.consensus_config.future_round_limit": 10, + "consensus_manager_config.consensus_config.startup_delay": 15, + "consensus_manager_config.consensus_config.sync_retry_interval": 1.0, + "consensus_manager_config.consensus_config.timeouts.precommit_timeout": 3.0, + "consensus_manager_config.consensus_config.timeouts.prevote_timeout": 3.0, + "consensus_manager_config.consensus_config.timeouts.proposal_timeout": 9.0, + "consensus_manager_config.context_config.block_timestamp_window": 1, + "consensus_manager_config.context_config.build_proposal_margin": 1000, + "consensus_manager_config.context_config.builder_address": "0x4", + "consensus_manager_config.context_config.l1_da_mode": true, + "consensus_manager_config.context_config.num_validators": 1, + "consensus_manager_config.context_config.proposal_buffer_size": 100, + "consensus_manager_config.context_config.validate_proposal_margin": 10000, + "consensus_manager_config.eth_to_strk_oracle_config.base_url": "http://127.0.0.1:53262/eth_to_strk_oracle?timestamp=", + "consensus_manager_config.eth_to_strk_oracle_config.headers": "", + "consensus_manager_config.immediate_active_height": 1, + "consensus_manager_config.network_config.advertised_multiaddr": "", + "consensus_manager_config.network_config.advertised_multiaddr.#is_none": true, + "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "", + "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": true, + "consensus_manager_config.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": 2, + "consensus_manager_config.network_config.discovery_config.bootstrap_dial_retry_config.factor": 5, + "consensus_manager_config.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": 5, + "consensus_manager_config.network_config.discovery_config.heartbeat_interval": 100, + "consensus_manager_config.network_config.idle_connection_timeout": 120, + "consensus_manager_config.network_config.peer_manager_config.malicious_timeout_seconds": 1, + "consensus_manager_config.network_config.peer_manager_config.unstable_timeout_millis": 1000, + "consensus_manager_config.network_config.port": 53080, + "consensus_manager_config.network_config.secret_key": "0x0101010101010101010101010101010101010101010101010101010101010101", + "consensus_manager_config.network_config.session_timeout": 120, + "consensus_manager_config.proposals_topic": "consensus_proposals", + "consensus_manager_config.votes_topic": "consensus_votes", + "eth_fee_token_address": "0x1001", + "gateway_config.stateful_tx_validator_config.max_allowed_nonce_gap": 50, + "gateway_config.stateful_tx_validator_config.max_nonce_for_validation_skip": "0x1", + "gateway_config.stateless_tx_validator_config.max_calldata_length": 10, + "gateway_config.stateless_tx_validator_config.max_contract_class_object_size": 4089446, + "gateway_config.stateless_tx_validator_config.max_sierra_version.major": 1, + "gateway_config.stateless_tx_validator_config.max_sierra_version.minor": 5, + "gateway_config.stateless_tx_validator_config.max_sierra_version.patch": 18446744073709551615, + "gateway_config.stateless_tx_validator_config.max_signature_length": 2, + "gateway_config.stateless_tx_validator_config.min_sierra_version.major": 1, + "gateway_config.stateless_tx_validator_config.min_sierra_version.minor": 1, + "gateway_config.stateless_tx_validator_config.min_sierra_version.patch": 0, + "gateway_config.stateless_tx_validator_config.validate_non_zero_l1_data_gas_fee": false, + "gateway_config.stateless_tx_validator_config.validate_non_zero_l1_gas_fee": true, + "gateway_config.stateless_tx_validator_config.validate_non_zero_l2_gas_fee": false, + "http_server_config.ip": "127.0.0.1", + "http_server_config.port": 53320, + "l1_gas_price_provider_config.lag_margin_seconds": 60, + "l1_gas_price_provider_config.number_of_blocks_for_mean": 300, + "l1_gas_price_provider_config.storage_limit": 3000, + "l1_gas_price_scraper_config.finality": 0, + "l1_gas_price_scraper_config.number_of_blocks_for_mean": 300, + "l1_gas_price_scraper_config.polling_interval": 1, + "l1_gas_price_scraper_config.starting_block": 0, + "l1_gas_price_scraper_config.starting_block.#is_none": true, + "l1_provider_config.bootstrap_catch_up_height_override": 0, + "l1_provider_config.bootstrap_catch_up_height_override.#is_none": true, + "l1_provider_config.provider_startup_height_override": 1, + "l1_provider_config.provider_startup_height_override.#is_none": false, + "l1_provider_config.startup_sync_sleep_retry_interval": 0.0, + "l1_scraper_config.finality": 0, + "l1_scraper_config.polling_interval": 1, + "l1_scraper_config.startup_rewind_time": 0, + "mempool_config.committed_nonce_retention_block_count": 100, + "mempool_config.declare_delay": 1, + "mempool_config.enable_fee_escalation": true, + "mempool_config.fee_escalation_percentage": 10, + "mempool_config.transaction_ttl": 300, + "mempool_p2p_config.max_transaction_batch_size": 1, + "mempool_p2p_config.network_buffer_size": 10000, + "mempool_p2p_config.network_config.advertised_multiaddr": "", + "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": true, + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "", + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": true, + "mempool_p2p_config.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": 2, + "mempool_p2p_config.network_config.discovery_config.bootstrap_dial_retry_config.factor": 5, + "mempool_p2p_config.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": 5, + "mempool_p2p_config.network_config.discovery_config.heartbeat_interval": 100, + "mempool_p2p_config.network_config.idle_connection_timeout": 120, + "mempool_p2p_config.network_config.peer_manager_config.malicious_timeout_seconds": 1, + "mempool_p2p_config.network_config.peer_manager_config.unstable_timeout_millis": 1000, + "mempool_p2p_config.network_config.port": 53200, + "mempool_p2p_config.network_config.secret_key": "0x0101010101010101010101010101010101010101010101010101010101010101", + "mempool_p2p_config.network_config.session_timeout": 120, + "mempool_p2p_config.transaction_batch_rate_millis": 1000, + "monitoring_config.collect_metrics": true, + "monitoring_config.collect_profiling_metrics": true, + "monitoring_endpoint_config.collect_metrics": true, + "monitoring_endpoint_config.collect_profiling_metrics": true, + "monitoring_endpoint_config.ip": "0.0.0.0", + "monitoring_endpoint_config.port": 8082, + "recorder_url": "http://127.0.0.1:53261/", + "revert_config.revert_up_to_and_including": 18446744073709551615, + "revert_config.should_revert": false, + "state_sync_config.central_sync_client_config.#is_none": true, + "state_sync_config.central_sync_client_config.central_source_config.class_cache_size": 100, + "state_sync_config.central_sync_client_config.central_source_config.concurrent_requests": 10, + "state_sync_config.central_sync_client_config.central_source_config.http_headers": "", + "state_sync_config.central_sync_client_config.central_source_config.max_classes_to_download": 20, + "state_sync_config.central_sync_client_config.central_source_config.max_state_updates_to_download": 20, + "state_sync_config.central_sync_client_config.central_source_config.max_state_updates_to_store_in_memory": 20, + "state_sync_config.central_sync_client_config.central_source_config.retry_config.max_retries": 10, + "state_sync_config.central_sync_client_config.central_source_config.retry_config.retry_base_millis": 30, + "state_sync_config.central_sync_client_config.central_source_config.retry_config.retry_max_delay_millis": 30000, + "state_sync_config.central_sync_client_config.central_source_config.starknet_url": "https://alpha-mainnet.starknet.io/", + "state_sync_config.central_sync_client_config.sync_config.base_layer_propagation_sleep_duration": 10, + "state_sync_config.central_sync_client_config.sync_config.block_propagation_sleep_duration": 2, + "state_sync_config.central_sync_client_config.sync_config.blocks_max_stream_size": 1000, + "state_sync_config.central_sync_client_config.sync_config.collect_pending_data": false, + "state_sync_config.central_sync_client_config.sync_config.recoverable_error_sleep_duration": 3, + "state_sync_config.central_sync_client_config.sync_config.state_updates_max_stream_size": 1000, + "state_sync_config.central_sync_client_config.sync_config.store_sierras_and_casms": false, + "state_sync_config.central_sync_client_config.sync_config.verify_blocks": true, + "state_sync_config.network_config.advertised_multiaddr": "", + "state_sync_config.network_config.advertised_multiaddr.#is_none": true, + "state_sync_config.network_config.bootstrap_peer_multiaddr": "", + "state_sync_config.network_config.bootstrap_peer_multiaddr.#is_none": true, + "state_sync_config.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": 2, + "state_sync_config.network_config.discovery_config.bootstrap_dial_retry_config.factor": 5, + "state_sync_config.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": 5, + "state_sync_config.network_config.discovery_config.heartbeat_interval": 100, + "state_sync_config.network_config.idle_connection_timeout": 120, + "state_sync_config.network_config.peer_manager_config.malicious_timeout_seconds": 1, + "state_sync_config.network_config.peer_manager_config.unstable_timeout_millis": 1000, + "state_sync_config.network_config.port": 53140, + "state_sync_config.network_config.secret_key": "0x0101010101010101010101010101010101010101010101010101010101010101", + "state_sync_config.network_config.session_timeout": 120, + "state_sync_config.p2p_sync_client_config.#is_none": false, + "state_sync_config.p2p_sync_client_config.buffer_size": 100000, + "state_sync_config.p2p_sync_client_config.num_block_classes_per_query": 100, + "state_sync_config.p2p_sync_client_config.num_block_state_diffs_per_query": 100, + "state_sync_config.p2p_sync_client_config.num_block_transactions_per_query": 100, + "state_sync_config.p2p_sync_client_config.num_headers_per_query": 10000, + "state_sync_config.p2p_sync_client_config.wait_period_for_new_data": 50, + "state_sync_config.p2p_sync_client_config.wait_period_for_other_protocol": 50, + "state_sync_config.storage_config.db_config.enforce_file_exists": false, + "state_sync_config.storage_config.db_config.growth_step": 67108864, + "state_sync_config.storage_config.db_config.max_size": 34359738368, + "state_sync_config.storage_config.db_config.min_size": 1048576, + "state_sync_config.storage_config.db_config.path_prefix": "/data/node_0/executable_0/state_sync", + "state_sync_config.storage_config.mmap_file_config.growth_step": 1048576, + "state_sync_config.storage_config.mmap_file_config.max_object_size": 65536, + "state_sync_config.storage_config.mmap_file_config.max_size": 16777216, + "state_sync_config.storage_config.scope": "FullArchive", + "strk_fee_token_address": "0x1002", + "validator_id": "0x64", + "versioned_constants_overrides.invoke_tx_max_n_steps": 10000000, + "versioned_constants_overrides.max_n_events": 1000, + "versioned_constants_overrides.max_recursion_depth": 50, + "versioned_constants_overrides.validate_max_n_steps": 1000000 +} diff --git a/config/sequencer/presets/distributed_node/application_configs/state_sync.json b/config/sequencer/presets/distributed_node/application_configs/state_sync.json new file mode 100644 index 00000000000..3eddf142bdc --- /dev/null +++ b/config/sequencer/presets/distributed_node/application_configs/state_sync.json @@ -0,0 +1,306 @@ +{ + "base_layer_config.node_url": "http://localhost:53260/", + "base_layer_config.starknet_contract_address": "0x5FbDB2315678afecb367f032d93F642f64180aa3", + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.l1_gas": 2500000, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.message_segment_length": 3700, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.n_events": 5000, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.sierra_gas": 30000000, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.state_diff_size": 4000, + "batcher_config.block_builder_config.execute_config.concurrency_config.chunk_size": 64, + "batcher_config.block_builder_config.execute_config.concurrency_config.enabled": true, + "batcher_config.block_builder_config.execute_config.concurrency_config.n_workers": 4, + "batcher_config.block_builder_config.execute_config.stack_size": 62914560, + "batcher_config.block_builder_config.tx_chunk_size": 100, + "batcher_config.contract_class_manager_config.cairo_native_run_config.channel_size": 2000, + "batcher_config.contract_class_manager_config.cairo_native_run_config.native_classes_whitelist": "All", + "batcher_config.contract_class_manager_config.cairo_native_run_config.run_cairo_native": false, + "batcher_config.contract_class_manager_config.cairo_native_run_config.wait_on_native_compilation": false, + "batcher_config.contract_class_manager_config.contract_cache_size": 600, + "batcher_config.contract_class_manager_config.native_compiler_config.max_casm_bytecode_size": 81920, + "batcher_config.contract_class_manager_config.native_compiler_config.max_cpu_time": 20, + "batcher_config.contract_class_manager_config.native_compiler_config.max_memory_usage": 5368709120, + "batcher_config.contract_class_manager_config.native_compiler_config.max_native_bytecode_size": 15728640, + "batcher_config.contract_class_manager_config.native_compiler_config.optimization_level": 2, + "batcher_config.contract_class_manager_config.native_compiler_config.panic_on_compilation_failure": false, + "batcher_config.contract_class_manager_config.native_compiler_config.sierra_to_native_compiler_path": "", + "batcher_config.contract_class_manager_config.native_compiler_config.sierra_to_native_compiler_path.#is_none": true, + "batcher_config.input_stream_content_buffer_size": 400, + "batcher_config.max_l1_handler_txs_per_block_proposal": 3, + "batcher_config.outstream_content_buffer_size": 100, + "batcher_config.storage.db_config.enforce_file_exists": false, + "batcher_config.storage.db_config.growth_step": 67108864, + "batcher_config.storage.db_config.max_size": 34359738368, + "batcher_config.storage.db_config.min_size": 1048576, + "batcher_config.storage.db_config.path_prefix": "/data/node_0/executable_0/batcher", + "batcher_config.storage.mmap_file_config.growth_step": 1048576, + "batcher_config.storage.mmap_file_config.max_object_size": 65536, + "batcher_config.storage.mmap_file_config.max_size": 16777216, + "batcher_config.storage.scope": "StateOnly", + "chain_id": "CHAIN_ID_SUBDIR", + "class_manager_config.class_manager_config.cached_class_storage_config.class_cache_size": 100, + "class_manager_config.class_manager_config.cached_class_storage_config.deprecated_class_cache_size": 100, + "class_manager_config.class_storage_config.class_hash_storage_config.enforce_file_exists": false, + "class_manager_config.class_storage_config.class_hash_storage_config.max_size": 1048576, + "class_manager_config.class_storage_config.class_hash_storage_config.path_prefix": "/data/node_0/executable_0/class_manager/class_hash_storage", + "class_manager_config.class_storage_config.persistent_root": "/data/node_0/executable_0/class_manager/classes", + "compiler_config.max_casm_bytecode_size": 81920, + "compiler_config.max_cpu_time": 20, + "compiler_config.max_memory_usage": 5368709120, + "compiler_config.max_native_bytecode_size": 15728640, + "compiler_config.optimization_level": 2, + "compiler_config.panic_on_compilation_failure": false, + "compiler_config.sierra_to_native_compiler_path": "", + "compiler_config.sierra_to_native_compiler_path.#is_none": true, + "components.batcher.execution_mode": "Disabled", + "components.batcher.ip": "0.0.0.0", + "components.batcher.local_server_config.channel_buffer_size": 32, + "components.batcher.max_concurrency": 10, + "components.batcher.port": 0, + "components.batcher.remote_client_config.idle_connections": 18446744073709551615, + "components.batcher.remote_client_config.idle_timeout": 90, + "components.batcher.remote_client_config.retries": 3, + "components.batcher.remote_client_config.retry_interval": 3, + "components.batcher.url": "localhost", + "components.class_manager.execution_mode": "Remote", + "components.class_manager.ip": "0.0.0.0", + "components.class_manager.local_server_config.channel_buffer_size": 32, + "components.class_manager.max_concurrency": 10, + "components.class_manager.port": 55001, + "components.class_manager.remote_client_config.idle_connections": 18446744073709551615, + "components.class_manager.remote_client_config.idle_timeout": 90, + "components.class_manager.remote_client_config.retries": 3, + "components.class_manager.remote_client_config.retry_interval": 3, + "components.class_manager.url": "sequencer-class-manager-service", + "components.consensus_manager.execution_mode": "Disabled", + "components.gateway.execution_mode": "Disabled", + "components.gateway.ip": "0.0.0.0", + "components.gateway.local_server_config.channel_buffer_size": 32, + "components.gateway.max_concurrency": 10, + "components.gateway.port": 0, + "components.gateway.remote_client_config.idle_connections": 18446744073709551615, + "components.gateway.remote_client_config.idle_timeout": 90, + "components.gateway.remote_client_config.retries": 3, + "components.gateway.remote_client_config.retry_interval": 3, + "components.gateway.url": "localhost", + "components.http_server.execution_mode": "Disabled", + "components.l1_gas_price_provider.execution_mode": "Disabled", + "components.l1_gas_price_provider.ip": "0.0.0.0", + "components.l1_gas_price_provider.local_server_config.channel_buffer_size": 32, + "components.l1_gas_price_provider.max_concurrency": 10, + "components.l1_gas_price_provider.port": 0, + "components.l1_gas_price_provider.remote_client_config.idle_connections": 18446744073709551615, + "components.l1_gas_price_provider.remote_client_config.idle_timeout": 90, + "components.l1_gas_price_provider.remote_client_config.retries": 3, + "components.l1_gas_price_provider.remote_client_config.retry_interval": 3, + "components.l1_gas_price_provider.url": "localhost", + "components.l1_gas_price_scraper.execution_mode": "Disabled", + "components.l1_provider.execution_mode": "Disabled", + "components.l1_provider.ip": "0.0.0.0", + "components.l1_provider.local_server_config.channel_buffer_size": 32, + "components.l1_provider.max_concurrency": 10, + "components.l1_provider.port": 0, + "components.l1_provider.remote_client_config.idle_connections": 18446744073709551615, + "components.l1_provider.remote_client_config.idle_timeout": 90, + "components.l1_provider.remote_client_config.retries": 3, + "components.l1_provider.remote_client_config.retry_interval": 3, + "components.l1_provider.url": "localhost", + "components.l1_scraper.execution_mode": "Disabled", + "components.mempool.execution_mode": "Disabled", + "components.mempool.ip": "0.0.0.0", + "components.mempool.local_server_config.channel_buffer_size": 32, + "components.mempool.max_concurrency": 10, + "components.mempool.port": 0, + "components.mempool.remote_client_config.idle_connections": 18446744073709551615, + "components.mempool.remote_client_config.idle_timeout": 90, + "components.mempool.remote_client_config.retries": 3, + "components.mempool.remote_client_config.retry_interval": 3, + "components.mempool.url": "localhost", + "components.mempool_p2p.execution_mode": "Disabled", + "components.mempool_p2p.ip": "0.0.0.0", + "components.mempool_p2p.local_server_config.channel_buffer_size": 32, + "components.mempool_p2p.max_concurrency": 10, + "components.mempool_p2p.port": 0, + "components.mempool_p2p.remote_client_config.idle_connections": 18446744073709551615, + "components.mempool_p2p.remote_client_config.idle_timeout": 90, + "components.mempool_p2p.remote_client_config.retries": 3, + "components.mempool_p2p.remote_client_config.retry_interval": 3, + "components.mempool_p2p.url": "localhost", + "components.monitoring_endpoint.execution_mode": "Enabled", + "components.sierra_compiler.execution_mode": "Disabled", + "components.sierra_compiler.ip": "0.0.0.0", + "components.sierra_compiler.local_server_config.channel_buffer_size": 32, + "components.sierra_compiler.max_concurrency": 10, + "components.sierra_compiler.port": 0, + "components.sierra_compiler.remote_client_config.idle_connections": 18446744073709551615, + "components.sierra_compiler.remote_client_config.idle_timeout": 90, + "components.sierra_compiler.remote_client_config.retries": 3, + "components.sierra_compiler.remote_client_config.retry_interval": 3, + "components.sierra_compiler.url": "localhost", + "components.state_sync.execution_mode": "LocalExecutionWithRemoteEnabled", + "components.state_sync.ip": "0.0.0.0", + "components.state_sync.local_server_config.channel_buffer_size": 32, + "components.state_sync.max_concurrency": 10, + "components.state_sync.port": 55008, + "components.state_sync.remote_client_config.idle_connections": 18446744073709551615, + "components.state_sync.remote_client_config.idle_timeout": 90, + "components.state_sync.remote_client_config.retries": 3, + "components.state_sync.remote_client_config.retry_interval": 3, + "components.state_sync.url": "sequencer-state-sync-service", + "consensus_manager_config.broadcast_buffer_size": 10000, + "consensus_manager_config.cende_config.skip_write_height": 1, + "consensus_manager_config.cende_config.skip_write_height.#is_none": false, + "consensus_manager_config.consensus_config.future_height_limit": 10, + "consensus_manager_config.consensus_config.future_height_round_limit": 1, + "consensus_manager_config.consensus_config.future_round_limit": 10, + "consensus_manager_config.consensus_config.startup_delay": 15, + "consensus_manager_config.consensus_config.sync_retry_interval": 1.0, + "consensus_manager_config.consensus_config.timeouts.precommit_timeout": 3.0, + "consensus_manager_config.consensus_config.timeouts.prevote_timeout": 3.0, + "consensus_manager_config.consensus_config.timeouts.proposal_timeout": 9.0, + "consensus_manager_config.context_config.block_timestamp_window": 1, + "consensus_manager_config.context_config.build_proposal_margin": 1000, + "consensus_manager_config.context_config.builder_address": "0x4", + "consensus_manager_config.context_config.l1_da_mode": true, + "consensus_manager_config.context_config.num_validators": 1, + "consensus_manager_config.context_config.proposal_buffer_size": 100, + "consensus_manager_config.context_config.validate_proposal_margin": 10000, + "consensus_manager_config.eth_to_strk_oracle_config.base_url": "http://127.0.0.1:53262/eth_to_strk_oracle?timestamp=", + "consensus_manager_config.eth_to_strk_oracle_config.headers": "", + "consensus_manager_config.immediate_active_height": 1, + "consensus_manager_config.network_config.advertised_multiaddr": "", + "consensus_manager_config.network_config.advertised_multiaddr.#is_none": true, + "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "", + "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": true, + "consensus_manager_config.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": 2, + "consensus_manager_config.network_config.discovery_config.bootstrap_dial_retry_config.factor": 5, + "consensus_manager_config.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": 5, + "consensus_manager_config.network_config.discovery_config.heartbeat_interval": 100, + "consensus_manager_config.network_config.idle_connection_timeout": 120, + "consensus_manager_config.network_config.peer_manager_config.malicious_timeout_seconds": 1, + "consensus_manager_config.network_config.peer_manager_config.unstable_timeout_millis": 1000, + "consensus_manager_config.network_config.port": 53080, + "consensus_manager_config.network_config.secret_key": "0x0101010101010101010101010101010101010101010101010101010101010101", + "consensus_manager_config.network_config.session_timeout": 120, + "consensus_manager_config.proposals_topic": "consensus_proposals", + "consensus_manager_config.votes_topic": "consensus_votes", + "eth_fee_token_address": "0x1001", + "gateway_config.stateful_tx_validator_config.max_allowed_nonce_gap": 50, + "gateway_config.stateful_tx_validator_config.max_nonce_for_validation_skip": "0x1", + "gateway_config.stateless_tx_validator_config.max_calldata_length": 10, + "gateway_config.stateless_tx_validator_config.max_contract_class_object_size": 4089446, + "gateway_config.stateless_tx_validator_config.max_sierra_version.major": 1, + "gateway_config.stateless_tx_validator_config.max_sierra_version.minor": 5, + "gateway_config.stateless_tx_validator_config.max_sierra_version.patch": 18446744073709551615, + "gateway_config.stateless_tx_validator_config.max_signature_length": 2, + "gateway_config.stateless_tx_validator_config.min_sierra_version.major": 1, + "gateway_config.stateless_tx_validator_config.min_sierra_version.minor": 1, + "gateway_config.stateless_tx_validator_config.min_sierra_version.patch": 0, + "gateway_config.stateless_tx_validator_config.validate_non_zero_l1_data_gas_fee": false, + "gateway_config.stateless_tx_validator_config.validate_non_zero_l1_gas_fee": true, + "gateway_config.stateless_tx_validator_config.validate_non_zero_l2_gas_fee": false, + "http_server_config.ip": "127.0.0.1", + "http_server_config.port": 53320, + "l1_gas_price_provider_config.lag_margin_seconds": 60, + "l1_gas_price_provider_config.number_of_blocks_for_mean": 300, + "l1_gas_price_provider_config.storage_limit": 3000, + "l1_gas_price_scraper_config.finality": 0, + "l1_gas_price_scraper_config.number_of_blocks_for_mean": 300, + "l1_gas_price_scraper_config.polling_interval": 1, + "l1_gas_price_scraper_config.starting_block": 0, + "l1_gas_price_scraper_config.starting_block.#is_none": true, + "l1_provider_config.bootstrap_catch_up_height_override": 0, + "l1_provider_config.bootstrap_catch_up_height_override.#is_none": true, + "l1_provider_config.provider_startup_height_override": 1, + "l1_provider_config.provider_startup_height_override.#is_none": false, + "l1_provider_config.startup_sync_sleep_retry_interval": 0.0, + "l1_scraper_config.finality": 0, + "l1_scraper_config.polling_interval": 1, + "l1_scraper_config.startup_rewind_time": 0, + "mempool_config.committed_nonce_retention_block_count": 100, + "mempool_config.declare_delay": 1, + "mempool_config.enable_fee_escalation": true, + "mempool_config.fee_escalation_percentage": 10, + "mempool_config.transaction_ttl": 300, + "mempool_p2p_config.max_transaction_batch_size": 1, + "mempool_p2p_config.network_buffer_size": 10000, + "mempool_p2p_config.network_config.advertised_multiaddr": "", + "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": true, + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "", + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": true, + "mempool_p2p_config.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": 2, + "mempool_p2p_config.network_config.discovery_config.bootstrap_dial_retry_config.factor": 5, + "mempool_p2p_config.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": 5, + "mempool_p2p_config.network_config.discovery_config.heartbeat_interval": 100, + "mempool_p2p_config.network_config.idle_connection_timeout": 120, + "mempool_p2p_config.network_config.peer_manager_config.malicious_timeout_seconds": 1, + "mempool_p2p_config.network_config.peer_manager_config.unstable_timeout_millis": 1000, + "mempool_p2p_config.network_config.port": 53200, + "mempool_p2p_config.network_config.secret_key": "0x0101010101010101010101010101010101010101010101010101010101010101", + "mempool_p2p_config.network_config.session_timeout": 120, + "mempool_p2p_config.transaction_batch_rate_millis": 1000, + "monitoring_config.collect_metrics": true, + "monitoring_config.collect_profiling_metrics": true, + "monitoring_endpoint_config.collect_metrics": true, + "monitoring_endpoint_config.collect_profiling_metrics": true, + "monitoring_endpoint_config.ip": "0.0.0.0", + "monitoring_endpoint_config.port": 8082, + "recorder_url": "http://127.0.0.1:53261/", + "revert_config.revert_up_to_and_including": 18446744073709551615, + "revert_config.should_revert": false, + "state_sync_config.central_sync_client_config.#is_none": true, + "state_sync_config.central_sync_client_config.central_source_config.class_cache_size": 100, + "state_sync_config.central_sync_client_config.central_source_config.concurrent_requests": 10, + "state_sync_config.central_sync_client_config.central_source_config.http_headers": "", + "state_sync_config.central_sync_client_config.central_source_config.max_classes_to_download": 20, + "state_sync_config.central_sync_client_config.central_source_config.max_state_updates_to_download": 20, + "state_sync_config.central_sync_client_config.central_source_config.max_state_updates_to_store_in_memory": 20, + "state_sync_config.central_sync_client_config.central_source_config.retry_config.max_retries": 10, + "state_sync_config.central_sync_client_config.central_source_config.retry_config.retry_base_millis": 30, + "state_sync_config.central_sync_client_config.central_source_config.retry_config.retry_max_delay_millis": 30000, + "state_sync_config.central_sync_client_config.central_source_config.starknet_url": "https://alpha-mainnet.starknet.io/", + "state_sync_config.central_sync_client_config.sync_config.base_layer_propagation_sleep_duration": 10, + "state_sync_config.central_sync_client_config.sync_config.block_propagation_sleep_duration": 2, + "state_sync_config.central_sync_client_config.sync_config.blocks_max_stream_size": 1000, + "state_sync_config.central_sync_client_config.sync_config.collect_pending_data": false, + "state_sync_config.central_sync_client_config.sync_config.recoverable_error_sleep_duration": 3, + "state_sync_config.central_sync_client_config.sync_config.state_updates_max_stream_size": 1000, + "state_sync_config.central_sync_client_config.sync_config.store_sierras_and_casms": false, + "state_sync_config.central_sync_client_config.sync_config.verify_blocks": true, + "state_sync_config.network_config.advertised_multiaddr": "", + "state_sync_config.network_config.advertised_multiaddr.#is_none": true, + "state_sync_config.network_config.bootstrap_peer_multiaddr": "", + "state_sync_config.network_config.bootstrap_peer_multiaddr.#is_none": true, + "state_sync_config.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": 2, + "state_sync_config.network_config.discovery_config.bootstrap_dial_retry_config.factor": 5, + "state_sync_config.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": 5, + "state_sync_config.network_config.discovery_config.heartbeat_interval": 100, + "state_sync_config.network_config.idle_connection_timeout": 120, + "state_sync_config.network_config.peer_manager_config.malicious_timeout_seconds": 1, + "state_sync_config.network_config.peer_manager_config.unstable_timeout_millis": 1000, + "state_sync_config.network_config.port": 53140, + "state_sync_config.network_config.secret_key": "0x0101010101010101010101010101010101010101010101010101010101010101", + "state_sync_config.network_config.session_timeout": 120, + "state_sync_config.p2p_sync_client_config.#is_none": false, + "state_sync_config.p2p_sync_client_config.buffer_size": 100000, + "state_sync_config.p2p_sync_client_config.num_block_classes_per_query": 100, + "state_sync_config.p2p_sync_client_config.num_block_state_diffs_per_query": 100, + "state_sync_config.p2p_sync_client_config.num_block_transactions_per_query": 100, + "state_sync_config.p2p_sync_client_config.num_headers_per_query": 10000, + "state_sync_config.p2p_sync_client_config.wait_period_for_new_data": 50, + "state_sync_config.p2p_sync_client_config.wait_period_for_other_protocol": 50, + "state_sync_config.storage_config.db_config.enforce_file_exists": false, + "state_sync_config.storage_config.db_config.growth_step": 67108864, + "state_sync_config.storage_config.db_config.max_size": 34359738368, + "state_sync_config.storage_config.db_config.min_size": 1048576, + "state_sync_config.storage_config.db_config.path_prefix": "/data/node_0/executable_0/state_sync", + "state_sync_config.storage_config.mmap_file_config.growth_step": 1048576, + "state_sync_config.storage_config.mmap_file_config.max_object_size": 65536, + "state_sync_config.storage_config.mmap_file_config.max_size": 16777216, + "state_sync_config.storage_config.scope": "FullArchive", + "strk_fee_token_address": "0x1002", + "validator_id": "0x64", + "versioned_constants_overrides.invoke_tx_max_n_steps": 10000000, + "versioned_constants_overrides.max_n_events": 1000, + "versioned_constants_overrides.max_recursion_depth": 50, + "versioned_constants_overrides.validate_max_n_steps": 1000000 +} diff --git a/config/sequencer/presets/state_sync_only/integration-sepolia.json b/config/sequencer/presets/state_sync_only/integration-sepolia.json new file mode 100644 index 00000000000..3e092da1faf --- /dev/null +++ b/config/sequencer/presets/state_sync_only/integration-sepolia.json @@ -0,0 +1,30 @@ +{ + "base_layer_config.node_url": "http://unused", + "base_layer_config.starknet_contract_address": "0x0000000000000000000000000000000000000000", + "chain_id": "SN_INTEGRATION_SEPOLIA", + "class_manager_config.class_storage_config.class_hash_storage_config.path_prefix": "/data/class_manager/class_hash_storage", + "class_manager_config.class_storage_config.persistent_root": "/data/class_manager/classes", + "components.batcher.execution_mode": "Disabled", + "components.consensus_manager.execution_mode": "Disabled", + "components.gateway.execution_mode": "Disabled", + "components.http_server.execution_mode": "Disabled", + "components.l1_gas_price_scraper.execution_mode": "Disabled", + "components.l1_gas_price_provider.execution_mode": "Disabled", + "components.l1_provider.execution_mode": "Disabled", + "components.l1_scraper.execution_mode": "Disabled", + "components.mempool.execution_mode": "Disabled", + "components.mempool_p2p.execution_mode": "Disabled", + "eth_fee_token_address": "0x0", + "recorder_url": "http://unused", + "state_sync_config.central_sync_client_config.#is_none": false, + "state_sync_config.central_sync_client_config.central_source_config.starknet_url": "https://integration-sepolia.starknet.io/", + "state_sync_config.p2p_sync_client_config.#is_none": true, + "state_sync_config.storage_config.db_config.growth_step": 4294967296, + "state_sync_config.storage_config.db_config.max_size": 1099511627776, + "state_sync_config.storage_config.db_config.path_prefix": "/data/state_sync", + "state_sync_config.storage_config.mmap_file_config.growth_step": 1073741824, + "state_sync_config.storage_config.mmap_file_config.max_object_size": 268435456, + "state_sync_config.storage_config.mmap_file_config.max_size": 1099511627776, + "strk_fee_token_address": "0x0", + "validator_id": "0x0" +} diff --git a/config/sequencer/presets/state_sync_only/mainnet.json b/config/sequencer/presets/state_sync_only/mainnet.json new file mode 100644 index 00000000000..2aaae16f4ff --- /dev/null +++ b/config/sequencer/presets/state_sync_only/mainnet.json @@ -0,0 +1,30 @@ +{ + "base_layer_config.node_url": "http://unused", + "base_layer_config.starknet_contract_address": "0x0000000000000000000000000000000000000000", + "chain_id": "SN_MAIN", + "class_manager_config.class_storage_config.class_hash_storage_config.path_prefix": "/data/class_manager/class_hash_storage", + "class_manager_config.class_storage_config.persistent_root": "/data/class_manager/classes", + "components.batcher.execution_mode": "Disabled", + "components.consensus_manager.execution_mode": "Disabled", + "components.gateway.execution_mode": "Disabled", + "components.http_server.execution_mode": "Disabled", + "components.l1_gas_price_scraper.execution_mode": "Disabled", + "components.l1_gas_price_provider.execution_mode": "Disabled", + "components.l1_provider.execution_mode": "Disabled", + "components.l1_scraper.execution_mode": "Disabled", + "components.mempool.execution_mode": "Disabled", + "components.mempool_p2p.execution_mode": "Disabled", + "eth_fee_token_address": "0x0", + "recorder_url": "http://unused", + "state_sync_config.central_sync_client_config.#is_none": false, + "state_sync_config.central_sync_client_config.central_source_config.starknet_url": "https://alpha-mainnet.starknet.io/", + "state_sync_config.p2p_sync_client_config.#is_none": true, + "state_sync_config.storage_config.db_config.growth_step": 4294967296, + "state_sync_config.storage_config.db_config.max_size": 1099511627776, + "state_sync_config.storage_config.db_config.path_prefix": "/data/state_sync", + "state_sync_config.storage_config.mmap_file_config.growth_step": 1073741824, + "state_sync_config.storage_config.mmap_file_config.max_object_size": 268435456, + "state_sync_config.storage_config.mmap_file_config.max_size": 1099511627776, + "strk_fee_token_address": "0x0", + "validator_id": "0x0" +} diff --git a/config/sequencer/presets/state_sync_only/testnet-sepolia.json b/config/sequencer/presets/state_sync_only/testnet-sepolia.json new file mode 100644 index 00000000000..e47b0f91285 --- /dev/null +++ b/config/sequencer/presets/state_sync_only/testnet-sepolia.json @@ -0,0 +1,30 @@ +{ + "base_layer_config.node_url": "http://unused", + "base_layer_config.starknet_contract_address": "0x0000000000000000000000000000000000000000", + "chain_id": "SN_SEPOLIA", + "class_manager_config.class_storage_config.class_hash_storage_config.path_prefix": "/data/class_manager/class_hash_storage", + "class_manager_config.class_storage_config.persistent_root": "/data/class_manager/classes", + "components.batcher.execution_mode": "Disabled", + "components.consensus_manager.execution_mode": "Disabled", + "components.gateway.execution_mode": "Disabled", + "components.http_server.execution_mode": "Disabled", + "components.l1_gas_price_scraper.execution_mode": "Disabled", + "components.l1_gas_price_provider.execution_mode": "Disabled", + "components.l1_provider.execution_mode": "Disabled", + "components.l1_scraper.execution_mode": "Disabled", + "components.mempool.execution_mode": "Disabled", + "components.mempool_p2p.execution_mode": "Disabled", + "eth_fee_token_address": "0x0", + "recorder_url": "http://unused", + "state_sync_config.central_sync_client_config.#is_none": false, + "state_sync_config.central_sync_client_config.central_source_config.starknet_url": "https://alpha-sepolia.starknet.io/", + "state_sync_config.p2p_sync_client_config.#is_none": true, + "state_sync_config.storage_config.db_config.growth_step": 4294967296, + "state_sync_config.storage_config.db_config.max_size": 1099511627776, + "state_sync_config.storage_config.db_config.path_prefix": "/data/state_sync", + "state_sync_config.storage_config.mmap_file_config.growth_step": 1073741824, + "state_sync_config.storage_config.mmap_file_config.max_object_size": 268435456, + "state_sync_config.storage_config.mmap_file_config.max_size": 1099511627776, + "strk_fee_token_address": "0x0", + "validator_id": "0x0" +} diff --git a/config/sequencer/presets/system_test_presets/single_node/node_0/executable_0/node_config.json b/config/sequencer/presets/system_test_presets/single_node/node_0/executable_0/node_config.json new file mode 100644 index 00000000000..f72b5b52730 --- /dev/null +++ b/config/sequencer/presets/system_test_presets/single_node/node_0/executable_0/node_config.json @@ -0,0 +1,306 @@ +{ + "base_layer_config.node_url": "http://localhost:53260/", + "base_layer_config.starknet_contract_address": "0x5FbDB2315678afecb367f032d93F642f64180aa3", + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.l1_gas": 2500000, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.message_segment_length": 3700, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.n_events": 5000, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.sierra_gas": 30000000, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.state_diff_size": 4000, + "batcher_config.block_builder_config.execute_config.concurrency_config.chunk_size": 64, + "batcher_config.block_builder_config.execute_config.concurrency_config.enabled": true, + "batcher_config.block_builder_config.execute_config.concurrency_config.n_workers": 4, + "batcher_config.block_builder_config.execute_config.stack_size": 62914560, + "batcher_config.block_builder_config.tx_chunk_size": 100, + "batcher_config.contract_class_manager_config.cairo_native_run_config.channel_size": 2000, + "batcher_config.contract_class_manager_config.cairo_native_run_config.native_classes_whitelist": "All", + "batcher_config.contract_class_manager_config.cairo_native_run_config.run_cairo_native": false, + "batcher_config.contract_class_manager_config.cairo_native_run_config.wait_on_native_compilation": false, + "batcher_config.contract_class_manager_config.contract_cache_size": 600, + "batcher_config.contract_class_manager_config.native_compiler_config.max_casm_bytecode_size": 81920, + "batcher_config.contract_class_manager_config.native_compiler_config.max_cpu_time": 20, + "batcher_config.contract_class_manager_config.native_compiler_config.max_memory_usage": 5368709120, + "batcher_config.contract_class_manager_config.native_compiler_config.max_native_bytecode_size": 15728640, + "batcher_config.contract_class_manager_config.native_compiler_config.optimization_level": 2, + "batcher_config.contract_class_manager_config.native_compiler_config.panic_on_compilation_failure": false, + "batcher_config.contract_class_manager_config.native_compiler_config.sierra_to_native_compiler_path": "", + "batcher_config.contract_class_manager_config.native_compiler_config.sierra_to_native_compiler_path.#is_none": true, + "batcher_config.input_stream_content_buffer_size": 400, + "batcher_config.max_l1_handler_txs_per_block_proposal": 3, + "batcher_config.outstream_content_buffer_size": 100, + "batcher_config.storage.db_config.enforce_file_exists": false, + "batcher_config.storage.db_config.growth_step": 67108864, + "batcher_config.storage.db_config.max_size": 34359738368, + "batcher_config.storage.db_config.min_size": 1048576, + "batcher_config.storage.db_config.path_prefix": "/data/node_0/executable_0/batcher", + "batcher_config.storage.mmap_file_config.growth_step": 1048576, + "batcher_config.storage.mmap_file_config.max_object_size": 65536, + "batcher_config.storage.mmap_file_config.max_size": 16777216, + "batcher_config.storage.scope": "StateOnly", + "chain_id": "CHAIN_ID_SUBDIR", + "class_manager_config.class_manager_config.cached_class_storage_config.class_cache_size": 100, + "class_manager_config.class_manager_config.cached_class_storage_config.deprecated_class_cache_size": 100, + "class_manager_config.class_storage_config.class_hash_storage_config.enforce_file_exists": false, + "class_manager_config.class_storage_config.class_hash_storage_config.max_size": 1048576, + "class_manager_config.class_storage_config.class_hash_storage_config.path_prefix": "/data/node_0/executable_0/class_manager/class_hash_storage", + "class_manager_config.class_storage_config.persistent_root": "/data/node_0/executable_0/class_manager/classes", + "compiler_config.max_casm_bytecode_size": 81920, + "compiler_config.max_cpu_time": 20, + "compiler_config.max_memory_usage": 5368709120, + "compiler_config.max_native_bytecode_size": 15728640, + "compiler_config.optimization_level": 2, + "compiler_config.panic_on_compilation_failure": false, + "compiler_config.sierra_to_native_compiler_path": "", + "compiler_config.sierra_to_native_compiler_path.#is_none": true, + "components.batcher.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.batcher.ip": "0.0.0.0", + "components.batcher.local_server_config.channel_buffer_size": 32, + "components.batcher.max_concurrency": 10, + "components.batcher.port": 0, + "components.batcher.remote_client_config.idle_connections": 18446744073709551615, + "components.batcher.remote_client_config.idle_timeout": 90, + "components.batcher.remote_client_config.retries": 3, + "components.batcher.remote_client_config.retry_interval": 3, + "components.batcher.url": "localhost", + "components.class_manager.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.class_manager.ip": "0.0.0.0", + "components.class_manager.local_server_config.channel_buffer_size": 32, + "components.class_manager.max_concurrency": 10, + "components.class_manager.port": 0, + "components.class_manager.remote_client_config.idle_connections": 18446744073709551615, + "components.class_manager.remote_client_config.idle_timeout": 90, + "components.class_manager.remote_client_config.retries": 3, + "components.class_manager.remote_client_config.retry_interval": 3, + "components.class_manager.url": "localhost", + "components.consensus_manager.execution_mode": "Enabled", + "components.gateway.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.gateway.ip": "0.0.0.0", + "components.gateway.local_server_config.channel_buffer_size": 32, + "components.gateway.max_concurrency": 10, + "components.gateway.port": 0, + "components.gateway.remote_client_config.idle_connections": 18446744073709551615, + "components.gateway.remote_client_config.idle_timeout": 90, + "components.gateway.remote_client_config.retries": 3, + "components.gateway.remote_client_config.retry_interval": 3, + "components.gateway.url": "localhost", + "components.http_server.execution_mode": "Enabled", + "components.l1_gas_price_provider.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.l1_gas_price_provider.ip": "0.0.0.0", + "components.l1_gas_price_provider.local_server_config.channel_buffer_size": 32, + "components.l1_gas_price_provider.max_concurrency": 10, + "components.l1_gas_price_provider.port": 0, + "components.l1_gas_price_provider.remote_client_config.idle_connections": 18446744073709551615, + "components.l1_gas_price_provider.remote_client_config.idle_timeout": 90, + "components.l1_gas_price_provider.remote_client_config.retries": 3, + "components.l1_gas_price_provider.remote_client_config.retry_interval": 3, + "components.l1_gas_price_provider.url": "localhost", + "components.l1_gas_price_scraper.execution_mode": "Enabled", + "components.l1_provider.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.l1_provider.ip": "0.0.0.0", + "components.l1_provider.local_server_config.channel_buffer_size": 32, + "components.l1_provider.max_concurrency": 10, + "components.l1_provider.port": 0, + "components.l1_provider.remote_client_config.idle_connections": 18446744073709551615, + "components.l1_provider.remote_client_config.idle_timeout": 90, + "components.l1_provider.remote_client_config.retries": 3, + "components.l1_provider.remote_client_config.retry_interval": 3, + "components.l1_provider.url": "localhost", + "components.l1_scraper.execution_mode": "Enabled", + "components.mempool.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.mempool.ip": "0.0.0.0", + "components.mempool.local_server_config.channel_buffer_size": 32, + "components.mempool.max_concurrency": 10, + "components.mempool.port": 0, + "components.mempool.remote_client_config.idle_connections": 18446744073709551615, + "components.mempool.remote_client_config.idle_timeout": 90, + "components.mempool.remote_client_config.retries": 3, + "components.mempool.remote_client_config.retry_interval": 3, + "components.mempool.url": "localhost", + "components.mempool_p2p.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.mempool_p2p.ip": "0.0.0.0", + "components.mempool_p2p.local_server_config.channel_buffer_size": 32, + "components.mempool_p2p.max_concurrency": 10, + "components.mempool_p2p.port": 0, + "components.mempool_p2p.remote_client_config.idle_connections": 18446744073709551615, + "components.mempool_p2p.remote_client_config.idle_timeout": 90, + "components.mempool_p2p.remote_client_config.retries": 3, + "components.mempool_p2p.remote_client_config.retry_interval": 3, + "components.mempool_p2p.url": "localhost", + "components.monitoring_endpoint.execution_mode": "Enabled", + "components.sierra_compiler.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.sierra_compiler.ip": "0.0.0.0", + "components.sierra_compiler.local_server_config.channel_buffer_size": 32, + "components.sierra_compiler.max_concurrency": 10, + "components.sierra_compiler.port": 0, + "components.sierra_compiler.remote_client_config.idle_connections": 18446744073709551615, + "components.sierra_compiler.remote_client_config.idle_timeout": 90, + "components.sierra_compiler.remote_client_config.retries": 3, + "components.sierra_compiler.remote_client_config.retry_interval": 3, + "components.sierra_compiler.url": "localhost", + "components.state_sync.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.state_sync.ip": "0.0.0.0", + "components.state_sync.local_server_config.channel_buffer_size": 32, + "components.state_sync.max_concurrency": 10, + "components.state_sync.port": 0, + "components.state_sync.remote_client_config.idle_connections": 18446744073709551615, + "components.state_sync.remote_client_config.idle_timeout": 90, + "components.state_sync.remote_client_config.retries": 3, + "components.state_sync.remote_client_config.retry_interval": 3, + "components.state_sync.url": "localhost", + "consensus_manager_config.broadcast_buffer_size": 10000, + "consensus_manager_config.cende_config.skip_write_height": 1, + "consensus_manager_config.cende_config.skip_write_height.#is_none": false, + "consensus_manager_config.consensus_config.future_height_limit": 10, + "consensus_manager_config.consensus_config.future_height_round_limit": 1, + "consensus_manager_config.consensus_config.future_round_limit": 10, + "consensus_manager_config.consensus_config.startup_delay": 15, + "consensus_manager_config.consensus_config.sync_retry_interval": 1.0, + "consensus_manager_config.consensus_config.timeouts.precommit_timeout": 3.0, + "consensus_manager_config.consensus_config.timeouts.prevote_timeout": 3.0, + "consensus_manager_config.consensus_config.timeouts.proposal_timeout": 9.0, + "consensus_manager_config.context_config.block_timestamp_window": 1, + "consensus_manager_config.context_config.build_proposal_margin": 1000, + "consensus_manager_config.context_config.builder_address": "0x4", + "consensus_manager_config.context_config.l1_da_mode": true, + "consensus_manager_config.context_config.num_validators": 1, + "consensus_manager_config.context_config.proposal_buffer_size": 100, + "consensus_manager_config.context_config.validate_proposal_margin": 10000, + "consensus_manager_config.eth_to_strk_oracle_config.base_url": "http://127.0.0.1:53262/eth_to_strk_oracle?timestamp=", + "consensus_manager_config.eth_to_strk_oracle_config.headers": "", + "consensus_manager_config.immediate_active_height": 1, + "consensus_manager_config.network_config.advertised_multiaddr": "", + "consensus_manager_config.network_config.advertised_multiaddr.#is_none": true, + "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "", + "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": true, + "consensus_manager_config.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": 2, + "consensus_manager_config.network_config.discovery_config.bootstrap_dial_retry_config.factor": 5, + "consensus_manager_config.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": 5, + "consensus_manager_config.network_config.discovery_config.heartbeat_interval": 100, + "consensus_manager_config.network_config.idle_connection_timeout": 120, + "consensus_manager_config.network_config.peer_manager_config.malicious_timeout_seconds": 1, + "consensus_manager_config.network_config.peer_manager_config.unstable_timeout_millis": 1000, + "consensus_manager_config.network_config.port": 53080, + "consensus_manager_config.network_config.secret_key": "0x0101010101010101010101010101010101010101010101010101010101010101", + "consensus_manager_config.network_config.session_timeout": 120, + "consensus_manager_config.proposals_topic": "consensus_proposals", + "consensus_manager_config.votes_topic": "consensus_votes", + "eth_fee_token_address": "0x1001", + "gateway_config.stateful_tx_validator_config.max_allowed_nonce_gap": 50, + "gateway_config.stateful_tx_validator_config.max_nonce_for_validation_skip": "0x1", + "gateway_config.stateless_tx_validator_config.max_calldata_length": 10, + "gateway_config.stateless_tx_validator_config.max_contract_class_object_size": 4089446, + "gateway_config.stateless_tx_validator_config.max_sierra_version.major": 1, + "gateway_config.stateless_tx_validator_config.max_sierra_version.minor": 5, + "gateway_config.stateless_tx_validator_config.max_sierra_version.patch": 18446744073709551615, + "gateway_config.stateless_tx_validator_config.max_signature_length": 2, + "gateway_config.stateless_tx_validator_config.min_sierra_version.major": 1, + "gateway_config.stateless_tx_validator_config.min_sierra_version.minor": 1, + "gateway_config.stateless_tx_validator_config.min_sierra_version.patch": 0, + "gateway_config.stateless_tx_validator_config.validate_non_zero_l1_data_gas_fee": false, + "gateway_config.stateless_tx_validator_config.validate_non_zero_l1_gas_fee": true, + "gateway_config.stateless_tx_validator_config.validate_non_zero_l2_gas_fee": false, + "http_server_config.ip": "127.0.0.1", + "http_server_config.port": 53320, + "l1_gas_price_provider_config.lag_margin_seconds": 60, + "l1_gas_price_provider_config.number_of_blocks_for_mean": 300, + "l1_gas_price_provider_config.storage_limit": 3000, + "l1_gas_price_scraper_config.finality": 0, + "l1_gas_price_scraper_config.number_of_blocks_for_mean": 300, + "l1_gas_price_scraper_config.polling_interval": 1, + "l1_gas_price_scraper_config.starting_block": 0, + "l1_gas_price_scraper_config.starting_block.#is_none": true, + "l1_provider_config.bootstrap_catch_up_height_override": 0, + "l1_provider_config.bootstrap_catch_up_height_override.#is_none": true, + "l1_provider_config.provider_startup_height_override": 1, + "l1_provider_config.provider_startup_height_override.#is_none": false, + "l1_provider_config.startup_sync_sleep_retry_interval": 0.0, + "l1_scraper_config.finality": 0, + "l1_scraper_config.polling_interval": 1, + "l1_scraper_config.startup_rewind_time": 0, + "mempool_config.committed_nonce_retention_block_count": 100, + "mempool_config.declare_delay": 1, + "mempool_config.enable_fee_escalation": true, + "mempool_config.fee_escalation_percentage": 10, + "mempool_config.transaction_ttl": 300, + "mempool_p2p_config.max_transaction_batch_size": 1, + "mempool_p2p_config.network_buffer_size": 10000, + "mempool_p2p_config.network_config.advertised_multiaddr": "", + "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": true, + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "", + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": true, + "mempool_p2p_config.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": 2, + "mempool_p2p_config.network_config.discovery_config.bootstrap_dial_retry_config.factor": 5, + "mempool_p2p_config.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": 5, + "mempool_p2p_config.network_config.discovery_config.heartbeat_interval": 100, + "mempool_p2p_config.network_config.idle_connection_timeout": 120, + "mempool_p2p_config.network_config.peer_manager_config.malicious_timeout_seconds": 1, + "mempool_p2p_config.network_config.peer_manager_config.unstable_timeout_millis": 1000, + "mempool_p2p_config.network_config.port": 53200, + "mempool_p2p_config.network_config.secret_key": "0x0101010101010101010101010101010101010101010101010101010101010101", + "mempool_p2p_config.network_config.session_timeout": 120, + "mempool_p2p_config.transaction_batch_rate_millis": 1000, + "monitoring_config.collect_metrics": true, + "monitoring_config.collect_profiling_metrics": true, + "monitoring_endpoint_config.collect_metrics": true, + "monitoring_endpoint_config.collect_profiling_metrics": true, + "monitoring_endpoint_config.ip": "0.0.0.0", + "monitoring_endpoint_config.port": 53380, + "recorder_url": "http://127.0.0.1:53261/", + "revert_config.revert_up_to_and_including": 18446744073709551615, + "revert_config.should_revert": false, + "state_sync_config.central_sync_client_config.#is_none": true, + "state_sync_config.central_sync_client_config.central_source_config.class_cache_size": 100, + "state_sync_config.central_sync_client_config.central_source_config.concurrent_requests": 10, + "state_sync_config.central_sync_client_config.central_source_config.http_headers": "", + "state_sync_config.central_sync_client_config.central_source_config.max_classes_to_download": 20, + "state_sync_config.central_sync_client_config.central_source_config.max_state_updates_to_download": 20, + "state_sync_config.central_sync_client_config.central_source_config.max_state_updates_to_store_in_memory": 20, + "state_sync_config.central_sync_client_config.central_source_config.retry_config.max_retries": 10, + "state_sync_config.central_sync_client_config.central_source_config.retry_config.retry_base_millis": 30, + "state_sync_config.central_sync_client_config.central_source_config.retry_config.retry_max_delay_millis": 30000, + "state_sync_config.central_sync_client_config.central_source_config.starknet_url": "https://alpha-mainnet.starknet.io/", + "state_sync_config.central_sync_client_config.sync_config.base_layer_propagation_sleep_duration": 10, + "state_sync_config.central_sync_client_config.sync_config.block_propagation_sleep_duration": 2, + "state_sync_config.central_sync_client_config.sync_config.blocks_max_stream_size": 1000, + "state_sync_config.central_sync_client_config.sync_config.collect_pending_data": false, + "state_sync_config.central_sync_client_config.sync_config.recoverable_error_sleep_duration": 3, + "state_sync_config.central_sync_client_config.sync_config.state_updates_max_stream_size": 1000, + "state_sync_config.central_sync_client_config.sync_config.store_sierras_and_casms": false, + "state_sync_config.central_sync_client_config.sync_config.verify_blocks": true, + "state_sync_config.network_config.advertised_multiaddr": "", + "state_sync_config.network_config.advertised_multiaddr.#is_none": true, + "state_sync_config.network_config.bootstrap_peer_multiaddr": "", + "state_sync_config.network_config.bootstrap_peer_multiaddr.#is_none": true, + "state_sync_config.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": 2, + "state_sync_config.network_config.discovery_config.bootstrap_dial_retry_config.factor": 5, + "state_sync_config.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": 5, + "state_sync_config.network_config.discovery_config.heartbeat_interval": 100, + "state_sync_config.network_config.idle_connection_timeout": 120, + "state_sync_config.network_config.peer_manager_config.malicious_timeout_seconds": 1, + "state_sync_config.network_config.peer_manager_config.unstable_timeout_millis": 1000, + "state_sync_config.network_config.port": 53140, + "state_sync_config.network_config.secret_key": "0x0101010101010101010101010101010101010101010101010101010101010101", + "state_sync_config.network_config.session_timeout": 120, + "state_sync_config.p2p_sync_client_config.#is_none": false, + "state_sync_config.p2p_sync_client_config.buffer_size": 100000, + "state_sync_config.p2p_sync_client_config.num_block_classes_per_query": 100, + "state_sync_config.p2p_sync_client_config.num_block_state_diffs_per_query": 100, + "state_sync_config.p2p_sync_client_config.num_block_transactions_per_query": 100, + "state_sync_config.p2p_sync_client_config.num_headers_per_query": 10000, + "state_sync_config.p2p_sync_client_config.wait_period_for_new_data": 50, + "state_sync_config.p2p_sync_client_config.wait_period_for_other_protocol": 50, + "state_sync_config.storage_config.db_config.enforce_file_exists": false, + "state_sync_config.storage_config.db_config.growth_step": 67108864, + "state_sync_config.storage_config.db_config.max_size": 34359738368, + "state_sync_config.storage_config.db_config.min_size": 1048576, + "state_sync_config.storage_config.db_config.path_prefix": "/data/node_0/executable_0/state_sync", + "state_sync_config.storage_config.mmap_file_config.growth_step": 1048576, + "state_sync_config.storage_config.mmap_file_config.max_object_size": 65536, + "state_sync_config.storage_config.mmap_file_config.max_size": 16777216, + "state_sync_config.storage_config.scope": "FullArchive", + "strk_fee_token_address": "0x1002", + "validator_id": "0x64", + "versioned_constants_overrides.invoke_tx_max_n_steps": 10000000, + "versioned_constants_overrides.max_n_events": 1000, + "versioned_constants_overrides.max_recursion_depth": 50, + "versioned_constants_overrides.validate_max_n_steps": 1000000 +} diff --git a/crates/apollo_reverts/Cargo.toml b/crates/apollo_reverts/Cargo.toml new file mode 100644 index 00000000000..88c89e491f9 --- /dev/null +++ b/crates/apollo_reverts/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "apollo_reverts" +version.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true + +[lints] +workspace = true + +[dependencies] +futures.workspace = true +papyrus_config.workspace = true +papyrus_storage.workspace = true +serde.workspace = true +starknet_api.workspace = true +tracing.workspace = true +validator.workspace = true diff --git a/crates/apollo_reverts/src/lib.rs b/crates/apollo_reverts/src/lib.rs new file mode 100644 index 00000000000..37aea18a7bf --- /dev/null +++ b/crates/apollo_reverts/src/lib.rs @@ -0,0 +1,127 @@ +use std::collections::BTreeMap; +use std::future::Future; + +use futures::future::pending; +use futures::never::Never; +use papyrus_config::dumping::{ser_param, SerializeConfig}; +use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; +use papyrus_storage::base_layer::BaseLayerStorageWriter; +use papyrus_storage::body::BodyStorageWriter; +use papyrus_storage::class_manager::ClassManagerStorageWriter; +use papyrus_storage::header::HeaderStorageWriter; +use papyrus_storage::state::StateStorageWriter; +use papyrus_storage::StorageWriter; +use serde::{Deserialize, Serialize}; +use starknet_api::block::BlockNumber; +use tracing::info; +use validator::Validate; + +#[derive(Clone, Debug, Serialize, Deserialize, Validate, PartialEq)] +pub struct RevertConfig { + pub revert_up_to_and_including: BlockNumber, + pub should_revert: bool, +} + +impl Default for RevertConfig { + fn default() -> Self { + Self { + // Use u64::MAX as a placeholder to prevent setting this value to + // a low block number by mistake, which will cause significant revert operations. + revert_up_to_and_including: BlockNumber(u64::MAX), + should_revert: false, + } + } +} + +impl SerializeConfig for RevertConfig { + fn dump(&self) -> BTreeMap { + BTreeMap::from_iter([ + ser_param( + "revert_up_to_and_including", + &self.revert_up_to_and_including, + "The component will revert blocks up to this block number (including).", + // Use this configuration carefully to prevent significant revert operations and + // data loss + ParamPrivacyInput::Public, + ), + ser_param( + "should_revert", + &self.should_revert, + "If set true, the component would revert blocks and do nothing else.", + ParamPrivacyInput::Public, + ), + ]) + } +} + +pub async fn revert_blocks_and_eternal_pending( + mut storage_height_marker: BlockNumber, + revert_up_to_and_including: BlockNumber, + mut revert_block_fn: impl FnMut(BlockNumber) -> Fut, + component_name: &str, +) -> Never +where + Fut: Future, +{ + // If we revert all blocks up to height X (including), the new height marker will be X. + let target_height_marker = revert_up_to_and_including; + + if storage_height_marker <= target_height_marker { + panic!( + "{component_name}'s storage height marker {storage_height_marker} is not larger than \ + the target height marker {target_height_marker}. No reverts are needed." + ); + } + + info!( + "Reverting {component_name}'s storage from height marker {storage_height_marker} to \ + target height marker {target_height_marker}" + ); + + while storage_height_marker > target_height_marker { + storage_height_marker = storage_height_marker.prev().expect( + "A block number that's greater than another block number should return Some on prev", + ); + info!("Reverting {component_name}'s storage to height marker {storage_height_marker}."); + revert_block_fn(storage_height_marker).await; + info!( + "Successfully reverted {component_name}'s storage to height marker \ + {storage_height_marker}." + ); + } + + info!("Done reverting {component_name}'s storage up to height {target_height_marker}!"); + match storage_height_marker.prev() { + Some(latest_block_in_storage) => info!( + "The latest block saved in {component_name}'s storage is {latest_block_in_storage}!" + ), + None => info!("There aren't any blocks saved in {component_name}'s storage!"), + }; + info!("Starting eternal pending."); + + pending().await +} + +/// Reverts everything related to the block, will succeed even if there is partial information for +/// the block. +// This function will panic if the storage reader fails to revert. +pub fn revert_block(storage_writer: &mut StorageWriter, target_block_marker: BlockNumber) { + storage_writer + .begin_rw_txn() + .unwrap() + .revert_header(target_block_marker) + .unwrap() + .0 + .revert_body(target_block_marker) + .unwrap() + .0 + .revert_state_diff(target_block_marker) + .unwrap() + .0 + .try_revert_class_manager_marker(target_block_marker) + .unwrap() + .try_revert_base_layer_marker(target_block_marker) + .unwrap() + .commit() + .unwrap(); +} diff --git a/crates/bin/starknet-native-compile/Cargo.lock b/crates/bin/starknet-native-compile/Cargo.lock deleted file mode 100644 index b8bc1ad7814..00000000000 --- a/crates/bin/starknet-native-compile/Cargo.lock +++ /dev/null @@ -1,3754 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "adler2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" - -[[package]] -name = "aes" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", -] - -[[package]] -name = "ahash" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "allocator-api2" -version = "0.2.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" - -[[package]] -name = "anstream" -version = "0.6.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" - -[[package]] -name = "anstyle-parse" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" -dependencies = [ - "anstyle", - "windows-sys 0.59.0", -] - -[[package]] -name = "anyhow" -version = "1.0.93" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" - -[[package]] -name = "aquamarine" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21cc1548309245035eb18aa7f0967da6bc65587005170c56e6ef2788a4cf3f4e" -dependencies = [ - "include_dir", - "itertools 0.10.5", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "ark-ec" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" -dependencies = [ - "ark-ff", - "ark-poly", - "ark-serialize", - "ark-std", - "derivative", - "hashbrown 0.13.2", - "itertools 0.10.5", - "num-traits", - "zeroize", -] - -[[package]] -name = "ark-ff" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" -dependencies = [ - "ark-ff-asm", - "ark-ff-macros", - "ark-serialize", - "ark-std", - "derivative", - "digest", - "itertools 0.10.5", - "num-bigint", - "num-traits", - "paste", - "rustc_version", - "zeroize", -] - -[[package]] -name = "ark-ff-asm" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" -dependencies = [ - "quote", - "syn 1.0.109", -] - -[[package]] -name = "ark-ff-macros" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" -dependencies = [ - "num-bigint", - "num-traits", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "ark-poly" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" -dependencies = [ - "ark-ff", - "ark-serialize", - "ark-std", - "derivative", - "hashbrown 0.13.2", -] - -[[package]] -name = "ark-secp256k1" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c02e954eaeb4ddb29613fee20840c2bbc85ca4396d53e33837e11905363c5f2" -dependencies = [ - "ark-ec", - "ark-ff", - "ark-std", -] - -[[package]] -name = "ark-secp256r1" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3975a01b0a6e3eae0f72ec7ca8598a6620fc72fa5981f6f5cca33b7cd788f633" -dependencies = [ - "ark-ec", - "ark-ff", - "ark-std", -] - -[[package]] -name = "ark-serialize" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" -dependencies = [ - "ark-serialize-derive", - "ark-std", - "digest", - "num-bigint", -] - -[[package]] -name = "ark-serialize-derive" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "ark-std" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" -dependencies = [ - "num-traits", - "rand", -] - -[[package]] -name = "arrayvec" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" - -[[package]] -name = "ascii-canvas" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" -dependencies = [ - "term", -] - -[[package]] -name = "assert_matches" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" - -[[package]] -name = "autocfg" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" - -[[package]] -name = "base64ct" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" - -[[package]] -name = "bincode" -version = "2.0.0-rc.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f11ea1a0346b94ef188834a65c068a03aec181c94896d481d7a0a40d85b0ce95" -dependencies = [ - "serde", -] - -[[package]] -name = "bindgen" -version = "0.69.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" -dependencies = [ - "bitflags", - "cexpr", - "clang-sys", - "itertools 0.12.1", - "lazy_static", - "lazycell", - "log", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn 2.0.87", - "which", -] - -[[package]] -name = "bindgen" -version = "0.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" -dependencies = [ - "bitflags", - "cexpr", - "clang-sys", - "itertools 0.13.0", - "log", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn 2.0.87", -] - -[[package]] -name = "bit-set" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" -dependencies = [ - "bit-vec", -] - -[[package]] -name = "bit-vec" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" - -[[package]] -name = "bitflags" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" - -[[package]] -name = "bitvec" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bstr" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" -dependencies = [ - "memchr", - "serde", -] - -[[package]] -name = "bumpalo" -version = "3.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" - -[[package]] -name = "byte-slice-cast" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bzip2" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" -dependencies = [ - "bzip2-sys", - "libc", -] - -[[package]] -name = "bzip2-sys" -version = "0.1.11+1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" -dependencies = [ - "cc", - "libc", - "pkg-config", -] - -[[package]] -name = "cairo-lang-casm" -version = "2.9.0-dev.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e0dcdb6358bb639dd729546611bd99bada94c86e3f262c3637855abea9a972" -dependencies = [ - "cairo-lang-utils", - "indoc", - "num-bigint", - "num-traits", - "parity-scale-codec", - "serde", -] - -[[package]] -name = "cairo-lang-compiler" -version = "2.9.0-dev.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8657f5a5611f341a85e80ba0b21848fc34bfdf391bfd93df0baf4516c3e4159" -dependencies = [ - "anyhow", - "cairo-lang-defs", - "cairo-lang-diagnostics", - "cairo-lang-filesystem", - "cairo-lang-lowering", - "cairo-lang-parser", - "cairo-lang-project", - "cairo-lang-semantic", - "cairo-lang-sierra", - "cairo-lang-sierra-generator", - "cairo-lang-syntax", - "cairo-lang-utils", - "indoc", - "rayon", - "rust-analyzer-salsa", - "semver", - "smol_str", - "thiserror", -] - -[[package]] -name = "cairo-lang-debug" -version = "2.9.0-dev.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0635aa554d297acefe6a35b495aba2795d0af5b7f97c4ab63829c7d62291ef41" -dependencies = [ - "cairo-lang-utils", -] - -[[package]] -name = "cairo-lang-defs" -version = "2.9.0-dev.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b356e1c09898e8b8cfdd9731579d89365a13d8b4f7e717962e0cc7d125b83c" -dependencies = [ - "cairo-lang-debug", - "cairo-lang-diagnostics", - "cairo-lang-filesystem", - "cairo-lang-parser", - "cairo-lang-syntax", - "cairo-lang-utils", - "itertools 0.12.1", - "rust-analyzer-salsa", - "smol_str", -] - -[[package]] -name = "cairo-lang-diagnostics" -version = "2.9.0-dev.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dfe7c6ff96182da29012b707a3554e34a50f19cc96013ee45b0eb36dd396ec8" -dependencies = [ - "cairo-lang-debug", - "cairo-lang-filesystem", - "cairo-lang-utils", - "itertools 0.12.1", -] - -[[package]] -name = "cairo-lang-eq-solver" -version = "2.9.0-dev.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "723d244465309d5409e297b5486d62cbec06f2c47b05044414bb640e3f14caab" -dependencies = [ - "cairo-lang-utils", - "good_lp", -] - -[[package]] -name = "cairo-lang-filesystem" -version = "2.9.0-dev.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "237030772ae5368f19a9247e1f63f753f8ad8de963477166e402f4825c0a141d" -dependencies = [ - "cairo-lang-debug", - "cairo-lang-utils", - "path-clean", - "rust-analyzer-salsa", - "semver", - "serde", - "smol_str", - "toml", -] - -[[package]] -name = "cairo-lang-formatter" -version = "2.9.0-dev.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b71f0eb3a36a6cb5f7f07843926783c4c17e44c9516b53171727a108782f3eb" -dependencies = [ - "anyhow", - "cairo-lang-diagnostics", - "cairo-lang-filesystem", - "cairo-lang-parser", - "cairo-lang-syntax", - "cairo-lang-utils", - "diffy", - "ignore", - "itertools 0.12.1", - "rust-analyzer-salsa", - "serde", - "thiserror", -] - -[[package]] -name = "cairo-lang-lowering" -version = "2.9.0-dev.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d095d78e2f1de499429c95655d6135a3d24c384b36d8de9f84e0aa4e07ee152" -dependencies = [ - "cairo-lang-debug", - "cairo-lang-defs", - "cairo-lang-diagnostics", - "cairo-lang-filesystem", - "cairo-lang-parser", - "cairo-lang-proc-macros", - "cairo-lang-semantic", - "cairo-lang-syntax", - "cairo-lang-utils", - "id-arena", - "itertools 0.12.1", - "log", - "num-bigint", - "num-integer", - "num-traits", - "rust-analyzer-salsa", - "smol_str", -] - -[[package]] -name = "cairo-lang-parser" -version = "2.9.0-dev.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb828af7f948a3ef7fa65de14e3f639daedefb046dfefcad6e3116d2cb0f89a0" -dependencies = [ - "cairo-lang-diagnostics", - "cairo-lang-filesystem", - "cairo-lang-syntax", - "cairo-lang-syntax-codegen", - "cairo-lang-utils", - "colored", - "itertools 0.12.1", - "num-bigint", - "num-traits", - "rust-analyzer-salsa", - "smol_str", - "unescaper", -] - -[[package]] -name = "cairo-lang-plugins" -version = "2.9.0-dev.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "135a600043bf7030eacc6ebf2a609c2364d6ffeb04e1f3c809a2738f6b02c829" -dependencies = [ - "cairo-lang-defs", - "cairo-lang-diagnostics", - "cairo-lang-filesystem", - "cairo-lang-parser", - "cairo-lang-syntax", - "cairo-lang-utils", - "indent", - "indoc", - "itertools 0.12.1", - "rust-analyzer-salsa", - "smol_str", -] - -[[package]] -name = "cairo-lang-proc-macros" -version = "2.9.0-dev.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac857ec4b564712f3e16e3314e23cc0787ab1c05cdfee83f1c8f9989a6eee40f" -dependencies = [ - "cairo-lang-debug", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "cairo-lang-project" -version = "2.9.0-dev.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23cc37b7f8889cdea631aeea3bcc70d5c86ac8fb1d98aabc83f16283d60f1643" -dependencies = [ - "cairo-lang-filesystem", - "cairo-lang-utils", - "serde", - "smol_str", - "thiserror", - "toml", -] - -[[package]] -name = "cairo-lang-runner" -version = "2.9.0-dev.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7474375528ffa7f47e343983d32051898e4e7b05ac0bdc48ee84b1325d8b562a" -dependencies = [ - "ark-ff", - "ark-secp256k1", - "ark-secp256r1", - "cairo-lang-casm", - "cairo-lang-lowering", - "cairo-lang-sierra", - "cairo-lang-sierra-ap-change", - "cairo-lang-sierra-generator", - "cairo-lang-sierra-to-casm", - "cairo-lang-sierra-type-size", - "cairo-lang-starknet", - "cairo-lang-utils", - "cairo-vm", - "itertools 0.12.1", - "keccak", - "num-bigint", - "num-integer", - "num-traits", - "rand", - "sha2", - "smol_str", - "starknet-types-core", - "thiserror", -] - -[[package]] -name = "cairo-lang-semantic" -version = "2.9.0-dev.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c560cf4b4a89325d3a9594f490fffee38cf30e0990e808bb927619de9d0c973a" -dependencies = [ - "cairo-lang-debug", - "cairo-lang-defs", - "cairo-lang-diagnostics", - "cairo-lang-filesystem", - "cairo-lang-parser", - "cairo-lang-plugins", - "cairo-lang-proc-macros", - "cairo-lang-syntax", - "cairo-lang-test-utils", - "cairo-lang-utils", - "id-arena", - "indoc", - "itertools 0.12.1", - "num-bigint", - "num-traits", - "rust-analyzer-salsa", - "smol_str", - "toml", -] - -[[package]] -name = "cairo-lang-sierra" -version = "2.9.0-dev.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8118f55ca7d567bfc60960b445d388564d04bf48335c983b1595cb35f67a01c5" -dependencies = [ - "anyhow", - "cairo-lang-utils", - "const-fnv1a-hash", - "convert_case", - "derivative", - "itertools 0.12.1", - "lalrpop", - "lalrpop-util", - "num-bigint", - "num-integer", - "num-traits", - "regex", - "rust-analyzer-salsa", - "serde", - "serde_json", - "sha3", - "smol_str", - "starknet-types-core", - "thiserror", -] - -[[package]] -name = "cairo-lang-sierra-ap-change" -version = "2.9.0-dev.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2716ef8d4ce0fb700f83ed3281f3656436570e60249d41c65c79dc1ca27be002" -dependencies = [ - "cairo-lang-eq-solver", - "cairo-lang-sierra", - "cairo-lang-sierra-type-size", - "cairo-lang-utils", - "itertools 0.12.1", - "num-bigint", - "num-traits", - "thiserror", -] - -[[package]] -name = "cairo-lang-sierra-gas" -version = "2.9.0-dev.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24a44da87a35845470c4f4c648225232a15e0875fe809045b6088464491f838b" -dependencies = [ - "cairo-lang-eq-solver", - "cairo-lang-sierra", - "cairo-lang-sierra-type-size", - "cairo-lang-utils", - "itertools 0.12.1", - "num-bigint", - "num-traits", - "thiserror", -] - -[[package]] -name = "cairo-lang-sierra-generator" -version = "2.9.0-dev.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15bc5cf9f3965a7030a114dfe3d31d183287fbfbfbf904deaaa2468cadb936aa" -dependencies = [ - "cairo-lang-debug", - "cairo-lang-defs", - "cairo-lang-diagnostics", - "cairo-lang-filesystem", - "cairo-lang-lowering", - "cairo-lang-parser", - "cairo-lang-semantic", - "cairo-lang-sierra", - "cairo-lang-syntax", - "cairo-lang-utils", - "itertools 0.12.1", - "num-traits", - "rust-analyzer-salsa", - "serde", - "serde_json", - "smol_str", -] - -[[package]] -name = "cairo-lang-sierra-to-casm" -version = "2.9.0-dev.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18b7616f1a3c41c4646094b5abf774e558428e9c1eda5d78d7b0638ec5c264e5" -dependencies = [ - "assert_matches", - "cairo-lang-casm", - "cairo-lang-sierra", - "cairo-lang-sierra-ap-change", - "cairo-lang-sierra-gas", - "cairo-lang-sierra-type-size", - "cairo-lang-utils", - "indoc", - "itertools 0.12.1", - "num-bigint", - "num-traits", - "starknet-types-core", - "thiserror", -] - -[[package]] -name = "cairo-lang-sierra-type-size" -version = "2.9.0-dev.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "871077dbc08df5d134dc3975538171c14b266ba405d1298085afdb227216f0a3" -dependencies = [ - "cairo-lang-sierra", - "cairo-lang-utils", -] - -[[package]] -name = "cairo-lang-starknet" -version = "2.9.0-dev.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f21804eb8931d41e258e7a393afc8ee8858308e95b3ed2e9b6b469ef68a6a50" -dependencies = [ - "anyhow", - "cairo-lang-compiler", - "cairo-lang-defs", - "cairo-lang-diagnostics", - "cairo-lang-filesystem", - "cairo-lang-lowering", - "cairo-lang-plugins", - "cairo-lang-semantic", - "cairo-lang-sierra", - "cairo-lang-sierra-generator", - "cairo-lang-starknet-classes", - "cairo-lang-syntax", - "cairo-lang-utils", - "const_format", - "indent", - "indoc", - "itertools 0.12.1", - "serde", - "serde_json", - "smol_str", - "starknet-types-core", - "thiserror", -] - -[[package]] -name = "cairo-lang-starknet-classes" -version = "2.9.0-dev.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2496bccd68fa0286b35b72c98439316a3a872ef7ec6d881f0dac90b17997490" -dependencies = [ - "cairo-lang-casm", - "cairo-lang-sierra", - "cairo-lang-sierra-to-casm", - "cairo-lang-utils", - "convert_case", - "itertools 0.12.1", - "num-bigint", - "num-integer", - "num-traits", - "serde", - "serde_json", - "sha3", - "smol_str", - "starknet-types-core", - "thiserror", -] - -[[package]] -name = "cairo-lang-syntax" -version = "2.9.0-dev.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d77ea2e35d3610098ff13e373fc519aedc6a5096ed8547081aacfc104ef4422" -dependencies = [ - "cairo-lang-debug", - "cairo-lang-filesystem", - "cairo-lang-utils", - "num-bigint", - "num-traits", - "rust-analyzer-salsa", - "smol_str", - "unescaper", -] - -[[package]] -name = "cairo-lang-syntax-codegen" -version = "2.9.0-dev.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b01d505ab26ca9ce829faf3a8dd097f5d7962d2eb8f136017a260694a6a72e8" -dependencies = [ - "genco", - "xshell", -] - -[[package]] -name = "cairo-lang-test-plugin" -version = "2.9.0-dev.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f83e082c8ebf81295156f13399f880037c749a9f1fc3f55b1be7e49fe124c6" -dependencies = [ - "anyhow", - "cairo-lang-compiler", - "cairo-lang-debug", - "cairo-lang-defs", - "cairo-lang-filesystem", - "cairo-lang-lowering", - "cairo-lang-semantic", - "cairo-lang-sierra", - "cairo-lang-sierra-generator", - "cairo-lang-starknet", - "cairo-lang-starknet-classes", - "cairo-lang-syntax", - "cairo-lang-utils", - "indoc", - "itertools 0.12.1", - "num-bigint", - "num-traits", - "serde", - "starknet-types-core", -] - -[[package]] -name = "cairo-lang-test-utils" -version = "2.9.0-dev.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb143a22f5a3510df8c4dec76e17c1e36bbcbddcd7915601f6a51a72418c454f" -dependencies = [ - "cairo-lang-formatter", - "cairo-lang-utils", - "colored", - "log", - "pretty_assertions", -] - -[[package]] -name = "cairo-lang-utils" -version = "2.9.0-dev.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35df943ebcf8e1db11ee9f4f46f843dde5b71639ca79ea0d8caa7973f91d8b12" -dependencies = [ - "hashbrown 0.14.5", - "indexmap 2.6.0", - "itertools 0.12.1", - "num-bigint", - "num-traits", - "schemars", - "serde", -] - -[[package]] -name = "cairo-native" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "833170f422b08eec0e5ab116573bbb73c73f1601987d4b151cf71760836bd142" -dependencies = [ - "anyhow", - "aquamarine", - "ark-ec", - "ark-ff", - "ark-secp256k1", - "ark-secp256r1", - "bumpalo", - "cairo-lang-compiler", - "cairo-lang-defs", - "cairo-lang-filesystem", - "cairo-lang-runner", - "cairo-lang-semantic", - "cairo-lang-sierra", - "cairo-lang-sierra-ap-change", - "cairo-lang-sierra-gas", - "cairo-lang-sierra-generator", - "cairo-lang-starknet", - "cairo-lang-starknet-classes", - "cairo-lang-test-plugin", - "cairo-lang-utils", - "cairo-native-runtime", - "cc", - "clap", - "colored", - "educe", - "itertools 0.13.0", - "keccak", - "lazy_static", - "libc", - "libloading", - "llvm-sys", - "melior", - "mlir-sys", - "num-bigint", - "num-integer", - "num-traits", - "serde", - "serde_json", - "sha2", - "starknet-types-core", - "stats_alloc", - "tempfile", - "thiserror", - "tracing", - "tracing-subscriber", - "utf8_iter", -] - -[[package]] -name = "cairo-native-runtime" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fa4ec78d0a6df2988b71838c330a5113f65a4db6ccff53d8d71465f6619a427" -dependencies = [ - "cairo-lang-sierra-gas", - "itertools 0.13.0", - "lazy_static", - "num-traits", - "rand", - "starknet-curve 0.5.1", - "starknet-types-core", -] - -[[package]] -name = "cairo-vm" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58363ad8065ed891e3b14a8191b707677c7c7cb5b9d10030822506786d8d8108" -dependencies = [ - "anyhow", - "bincode", - "bitvec", - "generic-array", - "hashbrown 0.14.5", - "hex", - "keccak", - "lazy_static", - "nom", - "num-bigint", - "num-integer", - "num-prime", - "num-traits", - "rand", - "rust_decimal", - "serde", - "serde_json", - "sha2", - "sha3", - "starknet-crypto", - "starknet-types-core", - "thiserror-no-std", - "zip", -] - -[[package]] -name = "caseless" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808dab3318747be122cb31d36de18d4d1c81277a76f8332a02b81a3d73463d7f" -dependencies = [ - "regex", - "unicode-normalization", -] - -[[package]] -name = "cc" -version = "1.1.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40545c26d092346d8a8dab71ee48e7685a7a9cba76e634790c215b41a4a7b4cf" -dependencies = [ - "jobserver", - "libc", - "shlex", -] - -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "cipher" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common", - "inout", -] - -[[package]] -name = "clang-sys" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" -dependencies = [ - "glob", - "libc", - "libloading", -] - -[[package]] -name = "clap" -version = "4.5.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.5.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.5.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" -dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "clap_lex" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" - -[[package]] -name = "colorchoice" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" - -[[package]] -name = "colored" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" -dependencies = [ - "lazy_static", - "windows-sys 0.48.0", -] - -[[package]] -name = "comrak" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c93ab3577cca16b4a1d80a88c2e0cd8b6e969e51696f0bbb0d1dcb0157109832" -dependencies = [ - "caseless", - "derive_builder", - "entities", - "memchr", - "once_cell", - "regex", - "slug", - "typed-arena", - "unicode_categories", -] - -[[package]] -name = "const-fnv1a-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b13ea120a812beba79e34316b3942a857c86ec1593cb34f27bb28272ce2cca" - -[[package]] -name = "const_format" -version = "0.2.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50c655d81ff1114fb0dcdea9225ea9f0cc712a6f8d189378e82bdf62a473a64b" -dependencies = [ - "const_format_proc_macros", -] - -[[package]] -name = "const_format_proc_macros" -version = "0.2.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eff1a44b93f47b1bac19a27932f5c591e43d1ba357ee4f61526c8a25603f0eb1" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - -[[package]] -name = "convert_case" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "cpufeatures" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" -dependencies = [ - "libc", -] - -[[package]] -name = "crc32fast" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - -[[package]] -name = "crypto-bigint" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" -dependencies = [ - "generic-array", - "subtle", - "zeroize", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "darling" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 2.0.87", -] - -[[package]] -name = "darling_macro" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" -dependencies = [ - "darling_core", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "dashmap" -version = "6.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" -dependencies = [ - "cfg-if", - "crossbeam-utils", - "hashbrown 0.14.5", - "lock_api", - "once_cell", - "parking_lot_core", -] - -[[package]] -name = "deranged" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" -dependencies = [ - "powerfmt", -] - -[[package]] -name = "derivative" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "derive_builder" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" -dependencies = [ - "derive_builder_macro", -] - -[[package]] -name = "derive_builder_core" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "derive_builder_macro" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" -dependencies = [ - "derive_builder_core", - "syn 2.0.87", -] - -[[package]] -name = "deunicode" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "339544cc9e2c4dc3fc7149fd630c5f22263a4fdf18a98afd0075784968b5cf00" - -[[package]] -name = "diff" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" - -[[package]] -name = "diffy" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e616e59155c92257e84970156f506287853355f58cd4a6eb167385722c32b790" -dependencies = [ - "nu-ansi-term", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", - "subtle", -] - -[[package]] -name = "dirs-next" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" -dependencies = [ - "cfg-if", - "dirs-sys-next", -] - -[[package]] -name = "dirs-sys-next" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - -[[package]] -name = "dyn-clone" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" - -[[package]] -name = "educe" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4bd92664bf78c4d3dba9b7cdafce6fa15b13ed3ed16175218196942e99168a8" -dependencies = [ - "enum-ordinalize", - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "either" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" - -[[package]] -name = "ena" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d248bdd43ce613d87415282f69b9bb99d947d290b10962dd6c56233312c2ad5" -dependencies = [ - "log", -] - -[[package]] -name = "entities" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5320ae4c3782150d900b79807611a59a99fc9a1d61d686faafc24b93fc8d7ca" - -[[package]] -name = "enum-ordinalize" -version = "4.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea0dcfa4e54eeb516fe454635a95753ddd39acda650ce703031c6973e315dd5" -dependencies = [ - "enum-ordinalize-derive", -] - -[[package]] -name = "enum-ordinalize-derive" -version = "4.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "errno" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "fastrand" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" - -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - -[[package]] -name = "flate2" -version = "1.0.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foldhash" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" - -[[package]] -name = "funty" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" - -[[package]] -name = "genco" -version = "0.17.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afac3cbb14db69ac9fef9cdb60d8a87e39a7a527f85a81a923436efa40ad42c6" -dependencies = [ - "genco-macros", - "relative-path", - "smallvec", -] - -[[package]] -name = "genco-macros" -version = "0.17.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "553630feadf7b76442b0849fd25fdf89b860d933623aec9693fed19af0400c78" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi", - "wasm-bindgen", -] - -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - -[[package]] -name = "globset" -version = "0.4.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15f1ce686646e7f1e19bf7d5533fe443a45dbfb990e00629110797578b42fb19" -dependencies = [ - "aho-corasick", - "bstr", - "log", - "regex-automata 0.4.8", - "regex-syntax 0.8.5", -] - -[[package]] -name = "good_lp" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97630e1e456d7081c524488a87d8f8f7ed0fd3100ba10c55e3cfa7add5ce05c6" -dependencies = [ - "fnv", - "microlp", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "hashbrown" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" -dependencies = [ - "ahash", -] - -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash", - "allocator-api2", - "serde", -] - -[[package]] -name = "hashbrown" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" -dependencies = [ - "allocator-api2", - "equivalent", - "foldhash", -] - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - -[[package]] -name = "home" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "id-arena" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" - -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - -[[package]] -name = "ignore" -version = "0.4.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b" -dependencies = [ - "crossbeam-deque", - "globset", - "log", - "memchr", - "regex-automata 0.4.8", - "same-file", - "walkdir", - "winapi-util", -] - -[[package]] -name = "impl-trait-for-tuples" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "include_dir" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "923d117408f1e49d914f1a379a309cffe4f18c05cf4e3d12e613a15fc81bd0dd" -dependencies = [ - "include_dir_macros", -] - -[[package]] -name = "include_dir_macros" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cab85a7ed0bd5f0e76d93846e0147172bed2e2d3f859bcc33a8d9699cad1a75" -dependencies = [ - "proc-macro2", - "quote", -] - -[[package]] -name = "indent" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9f1a0777d972970f204fdf8ef319f1f4f8459131636d7e3c96c5d59570d0fa6" - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", - "serde", -] - -[[package]] -name = "indexmap" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" -dependencies = [ - "equivalent", - "hashbrown 0.15.1", - "serde", -] - -[[package]] -name = "indoc" -version = "2.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" - -[[package]] -name = "inout" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" -dependencies = [ - "generic-array", -] - -[[package]] -name = "is_terminal_polyfill" -version = "1.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" - -[[package]] -name = "jobserver" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" -dependencies = [ - "libc", -] - -[[package]] -name = "js-sys" -version = "0.3.72" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "keccak" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" -dependencies = [ - "cpufeatures", -] - -[[package]] -name = "lalrpop" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cb077ad656299f160924eb2912aa147d7339ea7d69e1b5517326fdcec3c1ca" -dependencies = [ - "ascii-canvas", - "bit-set", - "ena", - "itertools 0.11.0", - "lalrpop-util", - "petgraph", - "pico-args", - "regex", - "regex-syntax 0.8.5", - "string_cache", - "term", - "tiny-keccak", - "unicode-xid", - "walkdir", -] - -[[package]] -name = "lalrpop-util" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" -dependencies = [ - "regex-automata 0.4.8", -] - -[[package]] -name = "lambdaworks-crypto" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbc2a4da0d9e52ccfe6306801a112e81a8fc0c76aa3e4449fefeda7fef72bb34" -dependencies = [ - "lambdaworks-math", - "serde", - "sha2", - "sha3", -] - -[[package]] -name = "lambdaworks-math" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1bd2632acbd9957afc5aeec07ad39f078ae38656654043bf16e046fa2730e23" -dependencies = [ - "serde", - "serde_json", -] - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -dependencies = [ - "spin", -] - -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - -[[package]] -name = "libc" -version = "0.2.162" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" - -[[package]] -name = "libloading" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" -dependencies = [ - "cfg-if", - "windows-targets 0.52.6", -] - -[[package]] -name = "libredox" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" -dependencies = [ - "bitflags", - "libc", -] - -[[package]] -name = "linux-raw-sys" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" - -[[package]] -name = "llvm-sys" -version = "191.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "893cddf1adf0354b93411e413553dd4daf5c43195d73f1acfa1e394bdd371456" -dependencies = [ - "anyhow", - "cc", - "lazy_static", - "libc", - "regex-lite", - "semver", -] - -[[package]] -name = "lock_api" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" - -[[package]] -name = "lru" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" -dependencies = [ - "hashbrown 0.15.1", -] - -[[package]] -name = "matchers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" -dependencies = [ - "regex-automata 0.1.10", -] - -[[package]] -name = "matrixmultiply" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9380b911e3e96d10c1f415da0876389aaf1b56759054eeb0de7df940c456ba1a" -dependencies = [ - "autocfg", - "rawpointer", -] - -[[package]] -name = "melior" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5d97014786c173a839839e2a068e82516ad1eb94fca1d40013d3c5e224e7c1e" -dependencies = [ - "dashmap", - "melior-macro", - "mlir-sys", - "once_cell", -] - -[[package]] -name = "melior-macro" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef7ae0ba2f96784ec407d58374c8477f5b04ec8c57a114cafef0c8f165c4b288" -dependencies = [ - "comrak", - "convert_case", - "once_cell", - "proc-macro2", - "quote", - "regex", - "syn 2.0.87", - "tblgen-alt", - "unindent", -] - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "microlp" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4190b5ca62abfbc95a81d57f4a8e3e3872289d656f3eeea5820b3046a1f81d4b" -dependencies = [ - "log", - "sprs", -] - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "miniz_oxide" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" -dependencies = [ - "adler2", -] - -[[package]] -name = "mlir-sys" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fae0a14b0940736a243fef4a4d96d8cdf8a253272031b63c5e4b1bea207c82b0" -dependencies = [ - "bindgen 0.70.1", -] - -[[package]] -name = "ndarray" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "882ed72dce9365842bf196bdeedf5055305f11fc8c03dee7bb0194a6cad34841" -dependencies = [ - "matrixmultiply", - "num-complex", - "num-integer", - "num-traits", - "portable-atomic", - "portable-atomic-util", - "rawpointer", -] - -[[package]] -name = "new_debug_unreachable" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", -] - -[[package]] -name = "num-bigint" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "num-traits", - "rand", - "serde", -] - -[[package]] -name = "num-complex" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-modular" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a5fe11d4135c3bcdf3a95b18b194afa9608a5f6ff034f5d857bc9a27fb0119" -dependencies = [ - "num-bigint", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-prime" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e238432a7881ec7164503ccc516c014bf009be7984cde1ba56837862543bdec3" -dependencies = [ - "bitvec", - "either", - "lru", - "num-bigint", - "num-integer", - "num-modular", - "num-traits", - "rand", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "once_cell" -version = "1.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" - -[[package]] -name = "oorandom" -version = "11.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" - -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - -[[package]] -name = "parity-scale-codec" -version = "3.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" -dependencies = [ - "arrayvec", - "bitvec", - "byte-slice-cast", - "impl-trait-for-tuples", - "parity-scale-codec-derive", - "serde", -] - -[[package]] -name = "parity-scale-codec-derive" -version = "3.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "parking_lot" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.52.6", -] - -[[package]] -name = "password-hash" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" -dependencies = [ - "base64ct", - "rand_core", - "subtle", -] - -[[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - -[[package]] -name = "path-clean" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17359afc20d7ab31fdb42bb844c8b3bb1dabd7dcf7e68428492da7f16966fcef" - -[[package]] -name = "pbkdf2" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" -dependencies = [ - "digest", - "hmac", - "password-hash", - "sha2", -] - -[[package]] -name = "petgraph" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" -dependencies = [ - "fixedbitset", - "indexmap 2.6.0", -] - -[[package]] -name = "phf_shared" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" -dependencies = [ - "siphasher", -] - -[[package]] -name = "pico-args" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" - -[[package]] -name = "pin-project-lite" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" - -[[package]] -name = "pkg-config" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" - -[[package]] -name = "portable-atomic" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" - -[[package]] -name = "portable-atomic-util" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90a7d5beecc52a491b54d6dd05c7a45ba1801666a5baad9fdbfc6fef8d2d206c" -dependencies = [ - "portable-atomic", -] - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "ppv-lite86" -version = "0.2.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" -dependencies = [ - "zerocopy", -] - -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - -[[package]] -name = "pretty_assertions" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" -dependencies = [ - "diff", - "yansi", -] - -[[package]] -name = "prettyplease" -version = "0.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" -dependencies = [ - "proc-macro2", - "syn 2.0.87", -] - -[[package]] -name = "proc-macro-crate" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" -dependencies = [ - "toml_edit", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro2" -version = "1.0.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "radium" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "rawpointer" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" - -[[package]] -name = "rayon" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - -[[package]] -name = "redox_syscall" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" -dependencies = [ - "bitflags", -] - -[[package]] -name = "redox_users" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" -dependencies = [ - "getrandom", - "libredox", - "thiserror", -] - -[[package]] -name = "regex" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata 0.4.8", - "regex-syntax 0.8.5", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax 0.6.29", -] - -[[package]] -name = "regex-automata" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax 0.8.5", -] - -[[package]] -name = "regex-lite" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" - -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - -[[package]] -name = "regex-syntax" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" - -[[package]] -name = "relative-path" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" - -[[package]] -name = "rfc6979" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" -dependencies = [ - "hmac", - "subtle", -] - -[[package]] -name = "rust-analyzer-salsa" -version = "0.17.0-pre.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719825638c59fd26a55412a24561c7c5bcf54364c88b9a7a04ba08a6eafaba8d" -dependencies = [ - "indexmap 2.6.0", - "lock_api", - "oorandom", - "parking_lot", - "rust-analyzer-salsa-macros", - "rustc-hash", - "smallvec", - "tracing", - "triomphe", -] - -[[package]] -name = "rust-analyzer-salsa-macros" -version = "0.17.0-pre.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d96498e9684848c6676c399032ebc37c52da95ecbefa83d71ccc53b9f8a4a8e" -dependencies = [ - "heck 0.4.1", - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "rust_decimal" -version = "1.36.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b082d80e3e3cc52b2ed634388d436fe1f4de6af5786cc2de9ba9737527bdf555" -dependencies = [ - "arrayvec", - "num-traits", -] - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] - -[[package]] -name = "rustix" -version = "0.38.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99e4ea3e1cdc4b559b8e5650f9c8e5998e3e5c1343b4eaf034565f32318d63c0" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.52.0", -] - -[[package]] -name = "rustversion" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" - -[[package]] -name = "ryu" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "schemars" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92" -dependencies = [ - "dyn-clone", - "indexmap 1.9.3", - "schemars_derive", - "serde", - "serde_json", -] - -[[package]] -name = "schemars_derive" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e" -dependencies = [ - "proc-macro2", - "quote", - "serde_derive_internals", - "syn 2.0.87", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "semver" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" -dependencies = [ - "serde", -] - -[[package]] -name = "serde" -version = "1.0.214" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.214" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "serde_derive_internals" -version = "0.29.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "serde_json" -version = "1.0.132" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", -] - -[[package]] -name = "serde_spanned" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" -dependencies = [ - "serde", -] - -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha2" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha3" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" -dependencies = [ - "digest", - "keccak", -] - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "siphasher" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" - -[[package]] -name = "slug" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "882a80f72ee45de3cc9a5afeb2da0331d58df69e4e7d8eeb5d3c7784ae67e724" -dependencies = [ - "deunicode", - "wasm-bindgen", -] - -[[package]] -name = "smallvec" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" - -[[package]] -name = "smol_str" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead" -dependencies = [ - "serde", -] - -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" - -[[package]] -name = "sprs" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "704ef26d974e8a452313ed629828cd9d4e4fa34667ca1ad9d6b1fffa43c6e166" -dependencies = [ - "ndarray", - "num-complex", - "num-traits", - "smallvec", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "starknet-crypto" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e2c30c01e8eb0fc913c4ee3cf676389fffc1d1182bfe5bb9670e4e72e968064" -dependencies = [ - "crypto-bigint", - "hex", - "hmac", - "num-bigint", - "num-integer", - "num-traits", - "rfc6979", - "sha2", - "starknet-crypto-codegen", - "starknet-curve 0.4.2", - "starknet-ff", - "zeroize", -] - -[[package]] -name = "starknet-crypto-codegen" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbc159a1934c7be9761c237333a57febe060ace2bc9e3b337a59a37af206d19f" -dependencies = [ - "starknet-curve 0.4.2", - "starknet-ff", - "syn 2.0.87", -] - -[[package]] -name = "starknet-curve" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1c383518bb312751e4be80f53e8644034aa99a0afb29d7ac41b89a997db875b" -dependencies = [ - "starknet-ff", -] - -[[package]] -name = "starknet-curve" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcde6bd74269b8161948190ace6cf069ef20ac6e79cd2ba09b320efa7500b6de" -dependencies = [ - "starknet-types-core", -] - -[[package]] -name = "starknet-ff" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7abf1b44ec5b18d87c1ae5f54590ca9d0699ef4dd5b2ffa66fc97f24613ec585" -dependencies = [ - "ark-ff", - "crypto-bigint", - "getrandom", - "hex", -] - -[[package]] -name = "starknet-native-compile" -version = "0.2.1-alpha.0" -dependencies = [ - "cairo-lang-sierra", - "cairo-lang-starknet-classes", - "cairo-native", - "clap", - "serde_json", -] - -[[package]] -name = "starknet-types-core" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa1b9e01ccb217ab6d475c5cda05dbb22c30029f7bb52b192a010a00d77a3d74" -dependencies = [ - "lambdaworks-crypto", - "lambdaworks-math", - "lazy_static", - "num-bigint", - "num-integer", - "num-traits", - "serde", -] - -[[package]] -name = "stats_alloc" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c0e04424e733e69714ca1bbb9204c1a57f09f5493439520f9f68c132ad25eec" - -[[package]] -name = "string_cache" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" -dependencies = [ - "new_debug_unreachable", - "once_cell", - "parking_lot", - "phf_shared", - "precomputed-hash", -] - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - -[[package]] -name = "tblgen-alt" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ecbc9175dd38627cd01d546e7b41c9a115e5773f4c98f64e2185c81ec5f45ab" -dependencies = [ - "bindgen 0.69.5", - "cc", - "paste", - "thiserror", -] - -[[package]] -name = "tempfile" -version = "3.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" -dependencies = [ - "cfg-if", - "fastrand", - "once_cell", - "rustix", - "windows-sys 0.59.0", -] - -[[package]] -name = "term" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" -dependencies = [ - "dirs-next", - "rustversion", - "winapi", -] - -[[package]] -name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "thiserror-impl-no-std" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58e6318948b519ba6dc2b442a6d0b904ebfb8d411a3ad3e07843615a72249758" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "thiserror-no-std" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3ad459d94dd517257cc96add8a43190ee620011bb6e6cdc82dafd97dfafafea" -dependencies = [ - "thiserror-impl-no-std", -] - -[[package]] -name = "thread_local" -version = "1.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" -dependencies = [ - "cfg-if", - "once_cell", -] - -[[package]] -name = "time" -version = "0.3.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" -dependencies = [ - "deranged", - "num-conv", - "powerfmt", - "serde", - "time-core", -] - -[[package]] -name = "time-core" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" - -[[package]] -name = "tiny-keccak" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" -dependencies = [ - "crunchy", -] - -[[package]] -name = "tinyvec" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "toml" -version = "0.8.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit", -] - -[[package]] -name = "toml_datetime" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_edit" -version = "0.22.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" -dependencies = [ - "indexmap 2.6.0", - "serde", - "serde_spanned", - "toml_datetime", - "winnow", -] - -[[package]] -name = "tracing" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" -dependencies = [ - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "tracing-core" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-serde" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" -dependencies = [ - "serde", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex", - "serde", - "serde_json", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", - "tracing-serde", -] - -[[package]] -name = "triomphe" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef8f7726da4807b58ea5c96fdc122f80702030edc33b35aff9190a51148ccc85" -dependencies = [ - "serde", - "stable_deref_trait", -] - -[[package]] -name = "typed-arena" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" - -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - -[[package]] -name = "unescaper" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c878a167baa8afd137494101a688ef8c67125089ff2249284bd2b5f9bfedb815" -dependencies = [ - "thiserror", -] - -[[package]] -name = "unicode-ident" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" - -[[package]] -name = "unicode-normalization" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-segmentation" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" - -[[package]] -name = "unicode-xid" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" - -[[package]] -name = "unicode_categories" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" - -[[package]] -name = "unindent" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce" - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" -dependencies = [ - "cfg-if", - "once_cell", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 2.0.87", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" - -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "winnow" -version = "0.6.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" -dependencies = [ - "memchr", -] - -[[package]] -name = "wyz" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" -dependencies = [ - "tap", -] - -[[package]] -name = "xshell" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db0ab86eae739efd1b054a8d3d16041914030ac4e01cd1dca0cf252fd8b6437" -dependencies = [ - "xshell-macros", -] - -[[package]] -name = "xshell-macros" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d422e8e38ec76e2f06ee439ccc765e9c6a9638b9e7c9f2e8255e4d41e8bd852" - -[[package]] -name = "yansi" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" - -[[package]] -name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "byteorder", - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "zeroize" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "zip" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" -dependencies = [ - "aes", - "byteorder", - "bzip2", - "constant_time_eq", - "crc32fast", - "crossbeam-utils", - "flate2", - "hmac", - "pbkdf2", - "sha1", - "time", - "zstd", -] - -[[package]] -name = "zstd" -version = "0.11.2+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" -dependencies = [ - "zstd-safe", -] - -[[package]] -name = "zstd-safe" -version = "5.0.2+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" -dependencies = [ - "libc", - "zstd-sys", -] - -[[package]] -name = "zstd-sys" -version = "2.0.13+zstd.1.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" -dependencies = [ - "cc", - "pkg-config", -] diff --git a/crates/bin/starknet-native-compile/Cargo.toml b/crates/bin/starknet-native-compile/Cargo.toml deleted file mode 100644 index 2894bcc5f9f..00000000000 --- a/crates/bin/starknet-native-compile/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "starknet-native-compile" -# The version of this crate should equal the version of cairo-native. -version = "0.2.4" -edition = "2021" -repository = "https://github.com/starkware-libs/sequencer/" -license = "Apache-2.0" - -[dependencies] -# TODO(Avi, 01/02/2025): Check consistency with the blockifier. -cairo-lang-sierra = "2.9.0-dev.0" -cairo-lang-starknet-classes = "2.9.0-dev.0" -cairo-native = "0.2.4" -clap = { version = "4.5.4", features = ["derive"] } -serde_json = "1.0.116" diff --git a/crates/bin/starknet-native-compile/src/main.rs b/crates/bin/starknet-native-compile/src/main.rs deleted file mode 100644 index 6e6990d4214..00000000000 --- a/crates/bin/starknet-native-compile/src/main.rs +++ /dev/null @@ -1,43 +0,0 @@ -use std::path::PathBuf; -use std::process; - -use cairo_native::executor::AotContractExecutor; -use cairo_native::OptLevel; -use clap::Parser; - -use crate::utils::load_sierra_program_from_file; - -mod utils; - -#[derive(Parser, Debug)] -#[clap(version, verbatim_doc_comment)] -struct Args { - /// The path of the Sierra file to compile. - path: PathBuf, - /// The output file path. - output: PathBuf, -} - -fn main() { - // TODO(Avi, 01/12/2024): Find a way to restrict time, memory and file size during compilation. - let args = Args::parse(); - let path = args.path; - let output = args.output; - - let (contract_class, sierra_program) = load_sierra_program_from_file(&path); - - // TODO(Avi, 01/12/2024): Test different optimization levels for best performance. - let mut contract_executor = AotContractExecutor::new( - &sierra_program, - &contract_class.entry_points_by_type, - OptLevel::default(), - ) - .unwrap_or_else(|err| { - eprintln!("Error compiling Sierra program: {}", err); - process::exit(1); - }); - contract_executor.save(output.clone()).unwrap_or_else(|err| { - eprintln!("Error saving compiled program: {}", err); - process::exit(1); - }); -} diff --git a/crates/bin/starknet-native-compile/src/utils.rs b/crates/bin/starknet-native-compile/src/utils.rs deleted file mode 100644 index 728f547a019..00000000000 --- a/crates/bin/starknet-native-compile/src/utils.rs +++ /dev/null @@ -1,24 +0,0 @@ -use std::path::PathBuf; -use std::process; - -use cairo_lang_sierra::program::Program; -use cairo_lang_starknet_classes::contract_class::ContractClass; - -pub(crate) fn load_sierra_program_from_file(path: &PathBuf) -> (ContractClass, Program) { - let raw_contract_class = std::fs::read_to_string(path).unwrap_or_else(|err| { - eprintln!("Error reading Sierra file: {}", err); - process::exit(1); - }); - let contract_class: ContractClass = - serde_json::from_str(&raw_contract_class).unwrap_or_else(|err| { - eprintln!("Error deserializing Sierra file into contract class: {}", err); - process::exit(1); - }); - ( - contract_class.clone(), - contract_class.extract_sierra_program().unwrap_or_else(|err| { - eprintln!("Error extracting Sierra program from contract class: {}", err); - process::exit(1); - }), - ) -} diff --git a/crates/blockifier/Cargo.toml b/crates/blockifier/Cargo.toml index 0df3a1419b7..9d00fc2d220 100644 --- a/crates/blockifier/Cargo.toml +++ b/crates/blockifier/Cargo.toml @@ -10,10 +10,16 @@ description = "The transaction-executing component in the Starknet sequencer." workspace = true [features] -cairo_native = ["dep:cairo-native"] -jemalloc = ["dep:tikv-jemallocator"] +cairo_native = [ + "blockifier_test_utils/cairo_native", + "dep:cairo-native", + "starknet_sierra_multicompile/cairo_native", +] +native_blockifier = [] +node_api = [] reexecution = ["transaction_serde"] -testing = ["rand", "rstest", "starknet_api/testing"] +testing = ["blockifier_test_utils", "rand", "rstest", "rstest_reuse", "starknet_api/testing"] +tracing = [] transaction_serde = [] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -24,6 +30,7 @@ ark-ec.workspace = true ark-ff.workspace = true ark-secp256k1.workspace = true ark-secp256r1.workspace = true +blockifier_test_utils = { workspace = true, optional = true } cached.workspace = true cairo-lang-casm = { workspace = true, features = ["parity-scale-codec"] } cairo-lang-runner.workspace = true @@ -32,6 +39,7 @@ cairo-native = { workspace = true, optional = true } cairo-vm.workspace = true derive_more.workspace = true indexmap.workspace = true +mockall.workspace = true itertools.workspace = true keccak.workspace = true log.workspace = true @@ -44,21 +52,22 @@ paste.workspace = true phf = { workspace = true, features = ["macros"] } rand = { workspace = true, optional = true } rstest = { workspace = true, optional = true } +rstest_reuse = { workspace = true, optional = true } semver.workspace = true serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true, features = ["arbitrary_precision"] } sha2.workspace = true starknet-types-core.workspace = true starknet_api.workspace = true +starknet_infra_utils.workspace = true +starknet_sierra_multicompile.workspace = true strum.workspace = true strum_macros.workspace = true -tempfile.workspace = true thiserror.workspace = true -tikv-jemallocator = { workspace = true, optional = true } -toml.workspace = true [dev-dependencies] assert_matches.workspace = true +blockifier_test_utils.workspace = true criterion = { workspace = true, features = ["html_reports"] } glob.workspace = true itertools.workspace = true @@ -66,15 +75,20 @@ pretty_assertions.workspace = true rand.workspace = true regex.workspace = true rstest.workspace = true +rstest_reuse.workspace = true starknet_api = { workspace = true, features = ["testing"] } test-case.workspace = true +tikv-jemallocator.workspace = true + +[build-dependencies] +starknet_infra_utils.workspace = true [[bench]] harness = false -name = "blockifier_bench" -path = "bench/blockifier_bench.rs" - -[[test]] -name = "feature_contracts_compatibility_test" -path = "tests/feature_contracts_compatibility_test.rs" +name = "blockifier" +path = "benches/main.rs" required-features = ["testing"] + +[package.metadata.cargo-machete] +# `paste` is used in the `define_versioned_constants!` macro but may be falsely detected as unused. +ignored = ["paste"] diff --git a/crates/blockifier/bench/blockifier_bench.rs b/crates/blockifier/benches/main.rs similarity index 63% rename from crates/blockifier/bench/blockifier_bench.rs rename to crates/blockifier/benches/main.rs index 2097bb1cecb..53704ac2c02 100644 --- a/crates/blockifier/bench/blockifier_bench.rs +++ b/crates/blockifier/benches/main.rs @@ -5,18 +5,31 @@ //! The main benchmark function is `transfers_benchmark`, which measures the performance //! of transfers between randomly created accounts, which are iterated over round-robin. //! -//! Run the benchmarks using `cargo bench --bench blockifier_bench`. +//! Run the benchmarks using `cargo bench --bench blockifier`. +//! +//! For Cairo Native compilation run the benchmarks using: +//! `cargo bench --bench blockifier --features "cairo_native"`. use blockifier::test_utils::transfers_generator::{ RecipientGeneratorType, TransfersGenerator, TransfersGeneratorConfig, }; +#[cfg(feature = "cairo_native")] +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; use criterion::{criterion_group, criterion_main, Criterion}; +use starknet_infra_utils::set_global_allocator; + +// TODO(Arni): Consider how to run this benchmark both with and without setting the allocator. Maybe +// hide this macro call under a feature, and run this benchmark regularly or with +// `cargo bench --bench blockifier --feature=specified_allocator` +set_global_allocator!(); pub fn transfers_benchmark(c: &mut Criterion) { let transfers_generator_config = TransfersGeneratorConfig { recipient_generator_type: RecipientGeneratorType::Random, + #[cfg(feature = "cairo_native")] + cairo_version: CairoVersion::Cairo1(RunnableCairo1::Native), ..Default::default() }; let mut transfers_generator = TransfersGenerator::new(transfers_generator_config); diff --git a/crates/blockifier/build.rs b/crates/blockifier/build.rs deleted file mode 100644 index f23af037cfa..00000000000 --- a/crates/blockifier/build.rs +++ /dev/null @@ -1,68 +0,0 @@ -use std::path::PathBuf; -use std::process::Command; - -fn compile_cairo_native_aot_runtime() { - let cairo_native_dir = std::env::current_dir() - .expect("Failed to get current directory") - .join(PathBuf::from("cairo_native")); - - if !cairo_native_dir.exists() || !cairo_native_dir.join(".git").exists() { - panic!( - "It seems git submodule at {} doesn't exist or it is not initialized, please \ - run:\n\ngit submodule update --init --recursive\n", - cairo_native_dir.to_str().unwrap() - ); - } - - let runtime_target_dir = cairo_native_dir.join(PathBuf::from("target")); - let status = Command::new("cargo") - .args([ - "build", - "--release", - "-p", - "cairo-native-runtime", - "--message-format=json", - "--target-dir", - runtime_target_dir.to_str().unwrap(), - ]) - .current_dir(cairo_native_dir) - .status() - .expect("Failed to execute cargo"); - if !status.success() { - panic!("Building cairo native runtime failed: {status}") - } - - let runtime_target_path = - runtime_target_dir.join(PathBuf::from("release/libcairo_native_runtime.a")); - - const RUNTIME_LIBRARY: &str = "CAIRO_NATIVE_RUNTIME_LIBRARY"; - let runtime_expected_path = { - let expected_path_env = - std::env::var(RUNTIME_LIBRARY).expect("Cairo Native runtime path variable is not set"); - let expected_path = PathBuf::from(&expected_path_env); - - if expected_path.is_absolute() { - expected_path - } else { - std::env::current_dir().expect("Failed to get current directory").join(expected_path) - } - }; - - std::fs::copy(&runtime_target_path, &runtime_expected_path) - .expect("Failed to copy native runtime"); - - println!("cargo::rerun-if-changed=./cairo_native/runtime/"); - // todo(rodrigo): this directive seems to cause the build script to trigger everytime on - // Linux based machines. Investigate the issue further. - println!("cargo::rerun-if-changed={}", runtime_expected_path.to_str().unwrap()); - println!("cargo::rerun-if-env-changed={RUNTIME_LIBRARY}"); -} - -fn main() { - // `CARGO_FEATURE_CAIRO_NATIVE` env var is set by Cargo when compiling with the `cairo_native` - // feature flag. Build instructions are defined behind this condition since they are only - // relevant when using Cairo Native. - if std::env::var("CARGO_FEATURE_CAIRO_NATIVE").is_ok() { - compile_cairo_native_aot_runtime(); - } -} diff --git a/crates/blockifier/cairo_native b/crates/blockifier/cairo_native deleted file mode 160000 index 76e83965d3b..00000000000 --- a/crates/blockifier/cairo_native +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 76e83965d3bf1252eb6c68200a3accd5fd1ec004 diff --git a/crates/blockifier/feature_contracts/cairo_native/compiled/test_contract.sierra.json b/crates/blockifier/feature_contracts/cairo_native/compiled/test_contract.sierra.json deleted file mode 100644 index 628eaa8b32c..00000000000 --- a/crates/blockifier/feature_contracts/cairo_native/compiled/test_contract.sierra.json +++ /dev/null @@ -1,8985 +0,0 @@ -{ - "sierra_program": [ - "0x1", - "0x6", - "0x0", - "0x2", - "0x9", - "0x0", - "0x887", - "0x779", - "0x1a3", - "0x52616e6765436865636b", - "0x800000000000000100000000000000000000000000000000", - "0x436f6e7374", - "0x800000000000000000000000000000000000000000000002", - "0x1", - "0x48", - "0x2", - "0x6e5f627974657320746f6f20626967", - "0x1b", - "0x1000000000000000000000000000000", - "0x10000000000000000000000000000", - "0x100000000000000000000000000", - "0x1000000000000000000000000", - "0x10000000000000000000000", - "0x100000000000000000000", - "0x1000000000000000000", - "0x10000000000000000", - "0x100000000000000", - "0x1000000000000", - "0x10000000000", - "0x100000000", - "0x1000000", - "0x10000", - "0x100", - "0x537472756374", - "0x800000000000000f00000000000000000000000000000001", - "0x0", - "0x2ee1e2b1b89f8c495f200e4956278a4d47395fe262f27b52e5865c9524c08c3", - "0x456e756d", - "0x800000000000000700000000000000000000000000000011", - "0x14cb65c06498f4a8e9db457528e9290f453897bdb216ce18347fff8fef2cd11", - "0x11", - "0x426f756e646564496e74", - "0x800000000000000700000000000000000000000000000002", - "0xf", - "0x3", - "0x18", - "0x52", - "0xd", - "0x426f78", - "0x800000000000000700000000000000000000000000000001", - "0x1d", - "0x75313238", - "0x800000000000000700000000000000000000000000000000", - "0x800000000000000700000000000000000000000000000003", - "0x25e2ca4b84968c2d8b83ef476ca8549410346b00836ce79beaf538155990bb2", - "0x1c", - "0x42697477697365", - "0x556e696e697469616c697a6564", - "0x800000000000000200000000000000000000000000000001", - "0x1e", - "0x753235365f737562204f766572666c6f77", - "0x43", - "0x51", - "0x800000000000000000000000000000000000000000000003", - "0x27", - "0x24", - "0x26", - "0x25", - "0x483ada7726a3c4655da4fbfc0e1108a8", - "0x79be667ef9dcbbac55a06295ce870b07", - "0x29bfcdb2dce28d959f2815b16f81798", - "0xfd17b448a68554199c47d08ffb10d4b8", - "0xe", - "0xb", - "0xa", - "0x9", - "0x8", - "0x7", - "0x6", - "0x5", - "0x4", - "0xa0", - "0x16a4c8d7c05909052238a862d8cc3e7975bf05a07b3a69c6b28951083a6d672", - "0x4172726179", - "0x800000000000000300000000000000000000000000000001", - "0x800000000000000300000000000000000000000000000003", - "0x36", - "0x37", - "0x2f23416cc60464d4158423619ba713070eb82b686c9d621a22c67bd37f6e0a9", - "0x35", - "0x38", - "0x3f", - "0x3c", - "0x3e", - "0x3d", - "0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e16", - "0x6b17d1f2e12c4247f8bce6e563a440f2", - "0x77037d812deb33a0f4a13945d898c296", - "0x2bce33576b315ececbb6406837bf51f5", - "0x800000000000000700000000000000000000000000000005", - "0x2907a9767b8e0b68c23345eea8650b1366373b598791523a07fddaa450ba526", - "0x553132384d756c47756172616e746565", - "0x44", - "0x4e6f6e5a65726f", - "0x47", - "0x46", - "0x496e76616c6964207369676e6174757265", - "0xffffffff00000000ffffffffffffffff", - "0xbce6faada7179e84f3b9cac2fc632551", - "0x66656c74323532", - "0x3233063c5dc6197e9bf4ddc53b925e10907665cf58255b7899f8212442d4605", - "0x49", - "0x1d8a68005db1b26d0d9f54faae1798d540e7df6326fae758cc2cf8f7ee88e72", - "0x4a", - "0x536563703235366b31506f696e74", - "0x3179e7829d19e62b12c79010203ceee40c98166e97eb104c25ad1adb6b9675a", - "0x4c", - "0x4d", - "0x3c7b5436891664778e6019991e6bd154eeab5d43a552b1f19485dec008095d3", - "0x4e", - "0x5369676e6174757265206f7574206f662072616e6765", - "0x54", - "0x53", - "0xfffffffffffffffffffffffffffffffe", - "0xbaaedce6af48a03bbfd25e8cd0364141", - "0x58", - "0x14ef93a95bec47ff4e55863055b7a948870fa13be1cbddd481656bdaf5facc2", - "0x55", - "0x753332", - "0x57", - "0x7533325f6d756c204f766572666c6f77", - "0x7533325f616464204f766572666c6f77", - "0x20", - "0x10", - "0x7a", - "0x6a", - "0x800000", - "0x66", - "0x8000", - "0x63", - "0x80", - "0x60", - "0x80000000", - "0x6b", - "0x8000000000000000", - "0x753634", - "0x4b656363616b206c61737420696e70757420776f7264203e3762", - "0x7b", - "0x313d53fcef2616901e3fd6801087e8d55f5cb59357e1fc8b603b82ae0af064c", - "0x7c", - "0x38b0179dda7eba3d95708820abf10d3d4f66e97d9a9013dc38d712dce2af15", - "0x7e", - "0x800000000000000700000000000000000000000000000004", - "0x3342418ef16b3e2799b906b1e4e89dbb9b111332dd44f72458ce44f9895b508", - "0x38f1b5bca324642b144da837412e9d82e31937ed4bbe21a1ebccb0c3d3d8d36", - "0x7533325f737562204f766572666c6f77", - "0x76616c7565732073686f756c64206e6f74206368616e67652e", - "0x53746f726167654261736541646472657373", - "0x31448060506164e4d1df7635613bacfbea8af9c3dc85ea9a55935292a4acddc", - "0x84", - "0x556e6578706563746564206572726f72", - "0x454e545259504f494e545f4e4f545f464f554e44", - "0x1c4e1062ccac759d9786c18a401086aa7ab90fde340fffd5cbd792d11daa7e7", - "0x454e545259504f494e545f4641494c4544", - "0x457870656374656420726576657274", - "0x4369726375697444617461", - "0x8c", - "0x43697263756974", - "0x800000000000000800000000000000000000000000000001", - "0x8f", - "0x43697263756974496e707574416363756d756c61746f72", - "0x43697263756974496e707574", - "0x800000000000000800000000000000000000000000000002", - "0x8e", - "0x4e6f7420616c6c20696e707574732068617665206265656e2066696c6c6564", - "0x526573756c743a3a756e77726170206661696c65642e", - "0x536e617073686f74", - "0x92", - "0x149ee8c97f9cdd259b09b6ca382e10945af23ee896a644de8c7b57da1779da7", - "0x93", - "0x800000000000000300000000000000000000000000000004", - "0x36775737a2dc48f3b19f9a1f4bc3ab9cb367d1e2e827cef96323826fd39f53f", - "0x95", - "0x46a6158a16a947e5916b2a2ca68501a45e93d7110e81aa2d6438b1c57c879a3", - "0x602e", - "0x206c696d62313a20302c206c696d62323a20302c206c696d62333a2030207d", - "0x6f7574707574286d756c29203d3d2075333834207b206c696d62303a20362c", - "0x679ea9c5b65e40ad9da80f5a4150d36f3b6af3e88305e2e3ae5eccbc5743d9", - "0x9c", - "0x1f", - "0x617373657274696f6e206661696c65643a20606f7574707574732e6765745f", - "0x62797465733331", - "0x5539364c696d62734c7447756172616e746565", - "0x800000000000000100000000000000000000000000000001", - "0x4d756c4d6f6447617465", - "0xa7", - "0xa6", - "0x5375624d6f6447617465", - "0xa8", - "0x496e766572736547617465", - "0xa9", - "0x4164644d6f6447617465", - "0xffffffffffffffffffffffff", - "0x35de1f6419a35f1a8c6f276f09c80570ebf482614031777c6d07679cf95b8bb", - "0xaa", - "0x436972637569744661696c75726547756172616e746565", - "0x436972637569745061727469616c4f757470757473", - "0xba", - "0x436972637569744f757470757473", - "0xb0", - "0xb2", - "0x4369726375697444657363726970746f72", - "0x416c6c20696e707574732068617665206265656e2066696c6c6564", - "0x55393647756172616e746565", - "0x800000000000000100000000000000000000000000000005", - "0xb7", - "0xbc", - "0xa4", - "0x436972637569744d6f64756c7573", - "0x4d756c4d6f64", - "0xc1", - "0x52616e6765436865636b3936", - "0xc3", - "0x4164644d6f64", - "0xc6", - "0x6d232c016ef1b12aec4b7f88cc0b3ab662be3b7dd7adbce5209fcfdbd42a504", - "0x45635374617465", - "0x4b5810004d9272776dec83ecc20c19353453b956e594188890b48467cb53c19", - "0x3dbce56de34e1cfe252ead5a1f14fd261d520d343ff6b7652174e62976ef44d", - "0x4563506f696e74", - "0xcd", - "0x4fad269cbf860980e38768fe9cb6b0b9ab03ee3fe84cfde2eccce597c874fd8", - "0x654fd7e67a123dd13868093b3b7777f1ffef596c2e324f25ceaf9146698482c", - "0xd2", - "0x7538", - "0x3c4930bb381033105f3ca15ccded195c90cd2af5baa0e1ceb36fde292df7652", - "0x34482b42d8542e3c880c5c93d387fb8b01fe2a5d54b6f50d62fe82d9e6c2526", - "0x2691cb735b18f3f656c3b82bd97a32b65d15019b64117513f8604d1e06fe58b", - "0x7265637572736976655f6661696c", - "0x4469766973696f6e2062792030", - "0x32564d7e0fe091d49b4c20f4632191e4ed6986bf993849879abfef9465def25", - "0x62c83572d28cb834a3de3c1e94977a4191469a4a8c26d1d7bc55305e640ed5", - "0x3288d594b9a45d15bb2fcb7903f06cdb06b27f0ba88186ec4cfaa98307cb972", - "0xdb", - "0xa853c166304d20fb0711becf2cbdf482dee3cac4e9717d040b7a7ab1df7eec", - "0xdc", - "0xe3", - "0xe0", - "0xe2", - "0xe1", - "0x177e60492c5a8242f76f07bfe3661bd", - "0xb292a619339f6e567a305c951c0dcbcc", - "0x42d16e47f219f9e98e76e09d8770b34a", - "0xe59ec2a17ce5bd2dab2abebdf89a62e2", - "0xe9", - "0xe6", - "0xe8", - "0xe7", - "0xe3b0c44298fc1c149afbf4c8996fb924", - "0x87d9315798aaa3a5ba01775787ced05e", - "0xaaf7b4e09fc81d6d1aa546e8365d525d", - "0x27ae41e4649b934ca495991b7852b855", - "0xee", - "0xec", - "0xed", - "0xef", - "0x4aaec73635726f213fb8a9e64da3b86", - "0x6e1cda979008bfaf874ff796eb3bb1c0", - "0x32e41495a944d0045b522eba7240fad5", - "0x49288242", - "0xf5", - "0xf2", - "0xf4", - "0xf3", - "0xdb0a2e6710c71ba80afeb3abdf69d306", - "0x502a43ce77c6f5c736a82f847fa95f8c", - "0x2d483fe223b12b91047d83258a958b0f", - "0xce729c7704f4ddf2eaaf0b76209fe1b0", - "0xf9", - "0xf8", - "0x536563703235367231506f696e74", - "0xffffffff000000010000000000000000", - "0xcb47311929e7a903ce831cb2b3e67fe265f121b394a36bc46c17cf352547fc", - "0xf7", - "0x185fda19bc33857e9f1d92d61312b69416f20cf740fa3993dcc2de228a6671d", - "0xfb", - "0xf83fa82126e7aeaf5fe12fff6a0f4a02d8a185bf5aaee3d10d1c4e751399b4", - "0xfc", - "0x107a3e65b6e33d1b25fa00c80dfe693f414350005bc697782c25eaac141fedd", - "0x104", - "0x101", - "0x103", - "0x102", - "0x4ac5e5c0c0e8a4871583cc131f35fb49", - "0x4c8e4fbc1fbb1dece52185e532812c4f", - "0x7a5f81cf3ee10044320a0d03b62d3e9a", - "0xc2b7f60e6a8b84965830658f08f7410c", - "0x108", - "0x107", - "0x100000000000000000000000000000000", - "0xe888fbb4cf9ae6254f19ba12e6d9af54", - "0x788f195a6f509ca3e934f78d7a71dd85", - "0x10b", - "0x10a", - "0x767410c1", - "0xbb448978bd42b984d7de5970bcaf5c43", - "0x556e657870656374656420636f6f7264696e61746573", - "0x112", - "0x10f", - "0x111", - "0x110", - "0x8e182ca967f38e1bd6a49583f43f1876", - "0xf728b4fa42485e3a0a5d2f346baa9455", - "0xe3e70682c2094cac629f6fbed82c07cd", - "0x8e031ab54fc0c4a8f0dc94fad0d0611", - "0x496e76616c696420617267756d656e74", - "0x117", - "0x116", - "0x53686f756c64206265206e6f6e65", - "0xffffffffffffffffffffffffffffffff", - "0xfffffffffffffffffffffffefffffc2f", - "0x141", - "0x140", - "0x61be55a8", - "0x800000000000000700000000000000000000000000000009", - "0x11c", - "0x336711c2797eda3aaf8c07c5cf7b92162501924a7090b25482d45dd3a24ddce", - "0x11d", - "0x536861323536537461746548616e646c65", - "0x11e", - "0x11f", - "0x324f33e2d695adb91665eafd5b62ec62f181e09c2e0e60401806dcc4bb3fa1", - "0x120", - "0x800000000000000000000000000000000000000000000009", - "0x11b", - "0x12b", - "0x12a", - "0x129", - "0x128", - "0x127", - "0x126", - "0x125", - "0x124", - "0x5be0cd19", - "0x1f83d9ab", - "0x9b05688c", - "0x510e527f", - "0xa54ff53a", - "0x3c6ef372", - "0xbb67ae85", - "0x6a09e667", - "0x176a53827827a9b5839f3d68f1c2ed4673066bf89e920a3d4110d3e191ce66b", - "0x12c", - "0x61616161", - "0x496e646578206f7574206f6620626f756e6473", - "0x57726f6e67206572726f72206d7367", - "0x496e76616c696420696e707574206c656e677468", - "0x53686f756c64206661696c", - "0xa5963aa610cb75ba273817bce5f8c48f", - "0x57726f6e6720686173682076616c7565", - "0x587f7cc3722e9654ea3963d5fe8c0748", - "0x136", - "0x3f829a4bc463d91621ba418d447cc38c95ddc483f9ccfebae79050eb7b3dcb6", - "0x137", - "0x25e50662218619229b3f53f1dc3253192a0f68ca423d900214253db415a90b4", - "0x139", - "0x13b", - "0x38b507bf259d96f5c53e8ab8f187781c3d096482729ec2d57f3366318a8502f", - "0x13c", - "0x13d", - "0x3c5ce4d28d473343dbe52c630edf038a582af9574306e1d609e379cd17fc87a", - "0x13e", - "0x424c4f434b5f494e464f5f4d49534d41544348", - "0x54585f494e464f5f4d49534d41544348", - "0x43414c4c45525f4d49534d41544348", - "0x434f4e54524143545f4d49534d41544348", - "0x53454c4543544f525f4d49534d41544348", - "0x148", - "0x1597b831feeb60c71f259624b79cf66995ea4f7e383403583674ab9c33b9cec", - "0x149", - "0x14a", - "0x21afb2f280564fc34ddb766bf42f7ca36154bbba994fbc0f0235cd873ace36a", - "0x14b", - "0x1baeba72e79e9db2587cf44fedb2f3700b2075a5e8e39a562584862c4b71f62", - "0x14d", - "0x14e", - "0x45b67c75542d42836cef6c02cca4dbff4a80a8621fa521cbfff1b2dd4af35a", - "0x14f", - "0x156", - "0x179", - "0x436f6e747261637441646472657373", - "0x800000000000000700000000000000000000000000000006", - "0x7d4d99e9ed8d285b5c61b493cedb63976bc3d9da867933d829f49ce838b5e7", - "0x152", - "0x151", - "0x153", - "0x154", - "0x80000000000000070000000000000000000000000000000e", - "0x348a62b7a38c0673e61e888d83a3ac1bf334ee7361a8514593d3d9532ed8b39", - "0x1ce0be45cbaa9547dfece0f040e22ec60de2d0d5a6c79fa5514066dfdbb7ca6", - "0x3128e9bfd21b6f544f537413d7dd38a8f2e017a3b81c1a4bcf8f51a64d0dc3d", - "0x15a", - "0x33ecdfa3f249457fb2ae8b6a6713b3069fa0c38450e972297821b52ba929029", - "0x15b", - "0x1d49f7a4b277bf7b55a2664ce8cef5d6922b5ffb806b89644b9e0cdbbcac378", - "0x15d", - "0x13fdd7105045794a99550ae1c4ac13faa62610dfab62c16422bfcf5803baa6e", - "0x15e", - "0x7536345f616464204f766572666c6f77", - "0x746573745f7265766572745f68656c706572", - "0x22", - "0xc", - "0x45634f70", - "0x7772be8b80a8a33dc6c1f9a6ab820c02e537c73e859de67f288c70f92571bb", - "0x30395f664644a8fcaf5ade2c4222939f92c008e26373687503ba48223c8c394", - "0x168", - "0x506564657273656e", - "0x6661696c", - "0x223b876ce59fbc872ac2e1412727be9abe279bf03bb3002a29d7aeba8b23a9f", - "0x16c", - "0x4609194bf9403d809e38367adb782a43edaf535df565a1b05eea7b577c89af", - "0x16d", - "0x7820213d2079", - "0x73756363657373", - "0x537175617368656446656c7432353244696374", - "0x46656c7432353244696374", - "0x5365676d656e744172656e61", - "0x800000000000000f00000000000000000000000000000002", - "0xcc5e86243f861d2d64b08c35db21013e773ac5cf10097946fe0011304886d5", - "0x174", - "0x2271e6a0c1b1931cf78a8bfd030df986f9544c426af3bd6023dc55382237cf7", - "0x176", - "0x1d2ae7ecff8f8db67bf542f1d1f8201ff21e9f36f780ef569bcc7bc74ab634c", - "0x177", - "0x3808c701a5d13e100ab11b6c02f91f752ecae7e420d21b56c90ec0a475cc7e5", - "0x1cbd0cd3f779a7c0d3cdc804f89c39bcf71a85b43d3cf8a042111f0bc2ddf63", - "0x57524f4e475f434c4153535f48415348", - "0x909b0519d7c88c554565d942b48b326c8dcbd2e2915301868fb8159e606aa3", - "0x17e", - "0x800000000000000f00000000000000000000000000000003", - "0x3153ad87fe24a37e12e7b17b2ed757f4e86be104f506a9fcc51c44f485a3293", - "0x181", - "0x436c61737348617368", - "0x4661696c656420746f20646573657269616c697a6520706172616d202334", - "0x4661696c656420746f20646573657269616c697a6520706172616d202335", - "0x4661696c656420746f20646573657269616c697a6520706172616d202336", - "0x74584e9f10ffb1a40aa5a3582e203f6758defc4a497d1a2d5a89f274a320e9", - "0x187", - "0x53797374656d", - "0x18b", - "0x4661696c656420746f20646573657269616c697a6520706172616d202333", - "0x17b6ecc31946835b0d9d92c2dd7a9c14f29af0371571ae74a1b228828b2242", - "0x18e", - "0x34f9bd7c6cb2dd4263175964ad75f1ff1461ddc332fbfb274e0fb2a5d7ab968", - "0x18f", - "0x29d7d57c04a880978e7b3689f6218e507f3be17588744b58dc17762447ad0e7", - "0x191", - "0x4f7074696f6e3a3a756e77726170206661696c65642e", - "0x4661696c656420746f20646573657269616c697a6520706172616d202331", - "0x4661696c656420746f20646573657269616c697a6520706172616d202332", - "0x4f7574206f6620676173", - "0x4275696c74696e436f737473", - "0x9931c641b913035ae674b400b61a51476d506bbe8bba2ff8a6272790aba9e6", - "0x19b", - "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", - "0x53746f7261676541646472657373", - "0x11c6d8087e00642489f92d2821ad6ebd6532ad1a3b6d12833da6d6810391511", - "0x4761734275696c74696e", - "0x349", - "0x7265766f6b655f61705f747261636b696e67", - "0x77697468647261775f676173", - "0x6272616e63685f616c69676e", - "0x7374727563745f6465636f6e737472756374", - "0x656e61626c655f61705f747261636b696e67", - "0x73746f72655f74656d70", - "0x61727261795f736e617073686f745f706f705f66726f6e74", - "0x756e626f78", - "0x72656e616d65", - "0x656e756d5f696e6974", - "0x1a1", - "0x6a756d70", - "0x7374727563745f636f6e737472756374", - "0x656e756d5f6d61746368", - "0x1ad5911ecb88aa4a50482c4de3232f196cfcaf7bd4e9c96d22b283733045007", - "0x64697361626c655f61705f747261636b696e67", - "0x64726f70", - "0x1a0", - "0x61727261795f6e6577", - "0x636f6e73745f61735f696d6d656469617465", - "0x19f", - "0x61727261795f617070656e64", - "0x19e", - "0x1a2", - "0x6765745f6275696c74696e5f636f737473", - "0x19d", - "0x77697468647261775f6761735f616c6c", - "0x19c", - "0x647570", - "0x73746f726167655f77726974655f73797363616c6c", - "0x73746f726167655f726561645f73797363616c6c", - "0x736e617073686f745f74616b65", - "0x19a", - "0x199", - "0x198", - "0x197", - "0x196", - "0x195", - "0x194", - "0x616c6c6f635f6c6f63616c", - "0x66696e616c697a655f6c6f63616c73", - "0x73746f72655f6c6f63616c", - "0x21adb5788e32c84f69a1863d85ef9394b7bf761a0ce1190f826984e5075c371", - "0x192", - "0x66756e6374696f6e5f63616c6c", - "0x190", - "0x63616c6c5f636f6e74726163745f73797363616c6c", - "0x18d", - "0x193", - "0x18c", - "0x18a", - "0x188", - "0x61727261795f6c656e", - "0x7533325f746f5f66656c74323532", - "0x186", - "0x185", - "0x184", - "0x189", - "0x636c6173735f686173685f7472795f66726f6d5f66656c74323532", - "0x183", - "0x28", - "0x182", - "0x7536345f7472795f66726f6d5f66656c74323532", - "0x180", - "0x29", - "0x17f", - "0x6765745f636c6173735f686173685f61745f73797363616c6c", - "0x636c6173735f686173685f746f5f66656c74323532", - "0x66656c743235325f737562", - "0x66656c743235325f69735f7a65726f", - "0x17d", - "0x17c", - "0x6765745f626c6f636b5f686173685f73797363616c6c", - "0x2a", - "0x17a", - "0x2b", - "0x178", - "0x2c", - "0x175", - "0x17b", - "0x6c6962726172795f63616c6c5f73797363616c6c", - "0x2d", - "0x7265706c6163655f636c6173735f73797363616c6c", - "0x73656e645f6d6573736167655f746f5f6c315f73797363616c6c", - "0x173", - "0x66656c743235325f646963745f6e6577", - "0x172", - "0x2e", - "0x171", - "0x626f6f6c5f6e6f745f696d706c", - "0x6465706c6f795f73797363616c6c", - "0x2f", - "0x30", - "0x31", - "0x32", - "0x170", - "0x16f", - "0x33", - "0x16e", - "0x16b", - "0x34", - "0x636f6e74726163745f616464726573735f746f5f66656c74323532", - "0x16a", - "0x75313238735f66726f6d5f66656c74323532", - "0x169", - "0x753132385f746f5f66656c74323532", - "0x167", - "0x166", - "0x39", - "0x165", - "0x164", - "0x3a", - "0x3b", - "0x73746f726167655f626173655f616464726573735f636f6e7374", - "0x1275130f95dda36bcbb6e9d28796c1d7e10b6e9fd5ed083e0ede4b12f613528", - "0x73746f726167655f616464726573735f66726f6d5f62617365", - "0x66656c743235325f616464", - "0x656d69745f6576656e745f73797363616c6c", - "0x163", - "0x162", - "0x7536345f6571", - "0x161", - "0x7536345f6f766572666c6f77696e675f616464", - "0x160", - "0x15f", - "0x15c", - "0x159", - "0x7533325f7472795f66726f6d5f66656c74323532", - "0x6765745f657865637574696f6e5f696e666f5f76325f73797363616c6c", - "0x155", - "0x157", - "0x753132385f6571", - "0x7533325f6571", - "0x150", - "0x40", - "0x14c", - "0x147", - "0x146", - "0x145", - "0x144", - "0x143", - "0x158", - "0x142", - "0x66656c743235325f646963745f737175617368", - "0x41", - "0x13f", - "0x42", - "0x13a", - "0x138", - "0x6b656363616b5f73797363616c6c", - "0x135", - "0x134", - "0x133", - "0x132", - "0x61727261795f676574", - "0x131", - "0x130", - "0x12f", - "0x12e", - "0x12d", - "0x636f6e73745f61735f626f78", - "0x122", - "0x7368613235365f73746174655f68616e646c655f696e6974", - "0x121", - "0x7368613235365f73746174655f68616e646c655f646967657374", - "0x123", - "0x11a", - "0x119", - "0x118", - "0x736563703235366b315f6e65775f73797363616c6c", - "0x115", - "0x114", - "0x113", - "0x10e", - "0x10d", - "0x736563703235366b315f6765745f78795f73797363616c6c", - "0x10c", - "0x109", - "0x106", - "0x66656c743235325f6d756c", - "0x105", - "0xff", - "0xfe", - "0x45", - "0xfd", - "0x7365637032353672315f6e65775f73797363616c6c", - "0xfa", - "0xf6", - "0xf1", - "0xf0", - "0x7365637032353672315f6765745f78795f73797363616c6c", - "0xeb", - "0xea", - "0xe5", - "0xe4", - "0xdf", - "0xde", - "0xdd", - "0xda", - "0x7533325f6f766572666c6f77696e675f737562", - "0x61727261795f706f705f66726f6e74", - "0xd9", - "0xd8", - "0xd7", - "0xd6", - "0xd5", - "0xd4", - "0x706564657273656e", - "0xad292db4ff05a993c318438c1b6c8a8303266af2da151aa28ccece6726f1f1", - "0xd3", - "0xd1", - "0x2679d68052ccd03a53755ca9169677965fbd93e489df62f5f40d4f03c24f7a4", - "0x62697477697365", - "0xd0", - "0xcf", - "0x65635f706f696e745f7472795f6e65775f6e7a", - "0xce", - "0x756e777261705f6e6f6e5f7a65726f", - "0xcc", - "0xcb", - "0x65635f706f696e745f69735f7a65726f", - "0x65635f73746174655f696e6974", - "0xc9", - "0x65635f73746174655f6164645f6d756c", - "0xca", - "0x65635f73746174655f7472795f66696e616c697a655f6e7a", - "0x65635f706f696e745f7a65726f", - "0x65635f73746174655f616464", - "0x65635f706f696e745f756e77726170", - "0x161bc82433cf4a92809836390ccd14921dfc4dc410cf3d2adbfee5e21ecfec8", - "0xc8", - "0xc0", - "0xbf", - "0xbe", - "0x7472795f696e746f5f636972637569745f6d6f64756c7573", - "0x696e69745f636972637569745f64617461", - "0xb9", - "0x696e746f5f7539365f67756172616e746565", - "0xb8", - "0xbb", - "0x6164645f636972637569745f696e707574", - "0xb6", - "0xc4", - "0xc5", - "0xc7", - "0xc2", - "0xbd", - "0xb5", - "0xb4", - "0x6765745f636972637569745f64657363726970746f72", - "0xb1", - "0xaf", - "0x6576616c5f63697263756974", - "0x6765745f636972637569745f6f7574707574", - "0x3ec1c84a1511eed894537833882a965abdddafab0d627a3ee76e01e6b57f37a", - "0x1d1238f44227bdf67f367571e4dec83368c54054d98ccf71a67381f7c51f1c4", - "0x7539365f67756172616e7465655f766572696679", - "0xab", - "0x9f", - "0x9e", - "0x9d", - "0x9b", - "0x9a", - "0x99", - "0x98", - "0x97", - "0x96", - "0x7374727563745f736e617073686f745f6465636f6e737472756374", - "0x94", - "0xad", - "0x91", - "0x4ef3b3bc4d34db6611aef96d643937624ebee01d56eae5bde6f3b158e32b15", - "0x90", - "0x8d", - "0x8b", - "0x8a", - "0x61727261795f736e617073686f745f706f705f6261636b", - "0x89", - "0x88", - "0x87", - "0x86", - "0x85", - "0x83", - "0x61727261795f736c696365", - "0x82", - "0x81", - "0x7f", - "0x7d", - "0x4b", - "0x79", - "0x7533325f736166655f6469766d6f64", - "0x7533325f69735f7a65726f", - "0x78", - "0x77", - "0x76", - "0x75", - "0x74", - "0x73", - "0x72", - "0x71", - "0x70", - "0x6f", - "0x6e", - "0x6d", - "0x7536345f69735f7a65726f", - "0x7536345f736166655f6469766d6f64", - "0x69", - "0x68", - "0x67", - "0x65", - "0x64", - "0x62", - "0x61", - "0x5f", - "0x7533325f776964655f6d756c", - "0x646f776e63617374", - "0x7533325f6f766572666c6f77696e675f616464", - "0x5e", - "0x5d", - "0x5c", - "0x5b", - "0x5a", - "0x59", - "0x61727261795f736e617073686f745f6d756c74695f706f705f66726f6e74", - "0x56", - "0x7368613235365f70726f636573735f626c6f636b5f73797363616c6c", - "0x753132385f69735f7a65726f", - "0x753132385f6f766572666c6f77696e675f737562", - "0x50", - "0x4f", - "0x753235365f67756172616e7465655f696e765f6d6f645f6e", - "0x753132385f6d756c5f67756172616e7465655f766572696679", - "0x753531325f736166655f6469766d6f645f62795f75323536", - "0x7365637032353672315f6d756c5f73797363616c6c", - "0x7365637032353672315f6164645f73797363616c6c", - "0x757063617374", - "0x753132385f736166655f6469766d6f64", - "0x627974657333315f7472795f66726f6d5f66656c74323532", - "0x627974657333315f746f5f66656c74323532", - "0x393d13543d6033e70e218aad8050e8de40a1dfbac0e80459811df56e3716ce6", - "0x23", - "0x21", - "0x736563703235366b315f6d756c5f73797363616c6c", - "0x736563703235366b315f6164645f73797363616c6c", - "0x696e746f5f626f78", - "0x7370616e5f66726f6d5f7475706c65", - "0x753132385f627974655f72657665727365", - "0x19", - "0x753132385f67756172616e7465655f6d756c", - "0x753132385f6f766572666c6f77696e675f616464", - "0x17", - "0x16", - "0x626f756e6465645f696e745f616464", - "0x15", - "0x14", - "0x13", - "0x656e756d5f66726f6d5f626f756e6465645f696e74", - "0x12", - "0x37a0", - "0xffffffffffffffff", - "0x1a", - "0x1e8", - "0x1d5", - "0x1d0", - "0x1bf", - "0x1ab", - "0x1b3", - "0x1db", - "0x6c", - "0x3f1", - "0x20e", - "0x213", - "0x3d9", - "0x3cf", - "0x3b9", - "0x225", - "0x22a", - "0x3a0", - "0x392", - "0x385", - "0x246", - "0x24b", - "0x36d", - "0x363", - "0x34d", - "0x25d", - "0x262", - "0x334", - "0x326", - "0x319", - "0x28d", - "0x304", - "0x2f2", - "0x2e9", - "0x2e0", - "0x2d8", - "0xa1", - "0xa2", - "0x2d1", - "0xa3", - "0xa5", - "0xac", - "0xae", - "0x2fc", - "0xb3", - "0x341", - "0x378", - "0x3ad", - "0x3e4", - "0x475", - "0x414", - "0x419", - "0x464", - "0x460", - "0x430", - "0x452", - "0x44b", - "0x468", - "0x58b", - "0x492", - "0x497", - "0x578", - "0x573", - "0x4a5", - "0x4aa", - "0x55f", - "0x556", - "0x54e", - "0x4c4", - "0x4c9", - "0x53a", - "0x531", - "0x529", - "0x4ef", - "0x519", - "0x512", - "0x542", - "0x567", - "0x57e", - "0x64a", - "0x5a9", - "0x5ae", - "0x639", - "0x635", - "0x5bb", - "0x5c0", - "0x623", - "0x61e", - "0x5d8", - "0x60e", - "0x600", - "0x5f6", - "0x605", - "0x628", - "0x63d", - "0x6c6", - "0x664", - "0x669", - "0x6b5", - "0x6b1", - "0x683", - "0x6a3", - "0x69a", - "0x6b9", - "0x7a4", - "0x794", - "0x78c", - "0x77c", - "0x76c", - "0x75b", - "0x749", - "0x70d", - "0x737", - "0x730", - "0x880", - "0x7c4", - "0x7c9", - "0x86d", - "0x868", - "0x857", - "0x7db", - "0x7e0", - "0x843", - "0x83a", - "0x832", - "0x806", - "0x822", - "0x819", - "0x84b", - "0x873", - "0x95a", - "0x89e", - "0x8a3", - "0x949", - "0x945", - "0x935", - "0x924", - "0x912", - "0x8ff", - "0x8d2", - "0x8ed", - "0x94d", - "0x9d3", - "0x976", - "0x97b", - "0x9c2", - "0x9be", - "0x992", - "0x9b0", - "0x9a7", - "0x9c6", - "0xa7f", - "0xa70", - "0x9f5", - "0x9fa", - "0xa5d", - "0xa55", - "0xa4e", - "0xa1f", - "0xa3f", - "0xa36", - "0xa64", - "0xacb", - "0xaa4", - "0xabd", - "0xbd6", - "0xaeb", - "0xaf0", - "0xbc3", - "0xbbe", - "0xbad", - "0xb02", - "0xb07", - "0xb99", - "0xb90", - "0xb88", - "0xb77", - "0xb26", - "0xb2b", - "0xb40", - "0xb65", - "0xb5c", - "0xba1", - "0xbc9", - "0xc28", - "0xbfb", - "0xc1b", - "0xc14", - "0xc78", - "0xc4b", - "0xc6b", - "0xc64", - "0xccd", - "0xc9c", - "0xcbf", - "0xcb7", - "0xd1e", - "0xcf1", - "0xd11", - "0xd0a", - "0xda2", - "0xd94", - "0xd85", - "0xd4d", - "0xd76", - "0xd68", - "0xe35", - "0xdbc", - "0xdc1", - "0xe23", - "0xe1c", - "0xe16", - "0xde5", - "0xe08", - "0xe01", - "0xe29", - "0xe77", - "0xe58", - "0xe6a", - "0xedd", - "0xecf", - "0xea0", - "0xec1", - "0xeba", - "0xf43", - "0xf35", - "0xf06", - "0xf27", - "0xf20", - "0x100c", - "0xf5f", - "0xf64", - "0xffb", - "0xff7", - "0xfe7", - "0xfd6", - "0xf87", - "0xfc6", - "0xf9a", - "0xfb0", - "0xfbc", - "0xfff", - "0x10ac", - "0x109d", - "0x108d", - "0x107c", - "0x1042", - "0x106b", - "0x1063", - "0x1171", - "0x115f", - "0x10cd", - "0x10d2", - "0x1157", - "0x1150", - "0x10e0", - "0x10e5", - "0x1148", - "0x1140", - "0x1103", - "0x112d", - "0x1124", - "0x114e", - "0x115d", - "0x115c", - "0x1162", - "0x126e", - "0x118f", - "0x1194", - "0x125d", - "0x1259", - "0x1248", - "0x11a5", - "0x11aa", - "0x123f", - "0x1237", - "0x11b8", - "0x11bd", - "0x122e", - "0x1225", - "0x11da", - "0x1213", - "0x120a", - "0x1235", - "0x1246", - "0x1245", - "0x124c", - "0x1261", - "0x12c3", - "0x1292", - "0x12b5", - "0x12ad", - "0x1331", - "0x1322", - "0x12ee", - "0x1313", - "0x130b", - "0x13a0", - "0x1392", - "0x135b", - "0x1384", - "0x137b", - "0x13fe", - "0x13c6", - "0x13ee", - "0x13e4", - "0x1461", - "0x1425", - "0x1453", - "0x1448", - "0x1444", - "0x144b", - "0x1544", - "0x1481", - "0x1486", - "0x1531", - "0x152c", - "0x151b", - "0x1498", - "0x149d", - "0x1507", - "0x14fe", - "0x14f6", - "0x14c3", - "0x14e6", - "0x14df", - "0x150f", - "0x1537", - "0x15b1", - "0x15a3", - "0x1595", - "0x1574", - "0x1587", - "0x165a", - "0x164c", - "0x15d2", - "0x15d7", - "0x163b", - "0x1637", - "0x1627", - "0x15f4", - "0x1618", - "0x160e", - "0x163f", - "0x16de", - "0x16d0", - "0x16c1", - "0x1689", - "0x16b2", - "0x16a8", - "0x1725", - "0x16fb", - "0x1707", - "0x170c", - "0x171a", - "0x174f", - "0x1746", - "0x1778", - "0x176f", - "0x17cd", - "0x17c3", - "0x17ba", - "0x17b1", - "0x1820", - "0x1814", - "0x1807", - "0x17f6", - "0x1838", - "0x183d", - "0x1898", - "0x1894", - "0x184e", - "0x1853", - "0x188a", - "0x1885", - "0x1866", - "0x186b", - "0x187b", - "0x1876", - "0x1880", - "0x188f", - "0x189c", - "0x1aeb", - "0x18b9", - "0x18be", - "0x1ad8", - "0x1ace", - "0x18ce", - "0x18d3", - "0x1abc", - "0x1ab1", - "0x1aa3", - "0x1a93", - "0x1a81", - "0x1a6f", - "0x1a5d", - "0x18fd", - "0x1902", - "0x1a46", - "0x1a39", - "0x191c", - "0x1921", - "0x1a2b", - "0x1929", - "0x192e", - "0x1a18", - "0x1a0b", - "0x19fb", - "0x19e9", - "0x1945", - "0x194a", - "0x19d3", - "0x19c5", - "0x195b", - "0x1960", - "0x19af", - "0x19a1", - "0x198e", - "0x1979", - "0x19bd", - "0x19e1", - "0x1a23", - "0x1a55", - "0x1ac6", - "0x1ae3", - "0x1eeb", - "0x1b2f", - "0x1b47", - "0x1b48", - "0x1ede", - "0x1ed3", - "0x1ea8", - "0x1e9d", - "0x1bcc", - "0x1eb2", - "0x1c03", - "0x1c1c", - "0x1e8b", - "0x1c1f", - "0x1eb5", - "0x1e7e", - "0x1e71", - "0x1e64", - "0x1cbc", - "0x1cd4", - "0x1e57", - "0x1cd7", - "0x1ebd", - "0x1d04", - "0x1ebf", - "0x1a4", - "0x1a5", - "0x1a6", - "0x1a7", - "0x1a8", - "0x1a9", - "0x1aa", - "0x1d3a", - "0x1ac", - "0x1ad", - "0x1d52", - "0x1ae", - "0x1af", - "0x1b0", - "0x1b1", - "0x1e4a", - "0x1b2", - "0x1b4", - "0x1b5", - "0x1b6", - "0x1d55", - "0x1b7", - "0x1b8", - "0x1b9", - "0x1ec1", - "0x1ba", - "0x1bb", - "0x1bc", - "0x1bd", - "0x1be", - "0x1c0", - "0x1c1", - "0x1c2", - "0x1c3", - "0x1c4", - "0x1c5", - "0x1c6", - "0x1c7", - "0x1c8", - "0x1c9", - "0x1ca", - "0x1cb", - "0x1cc", - "0x1cd", - "0x1ce", - "0x1cf", - "0x1d1", - "0x1d2", - "0x1d3", - "0x1d4", - "0x1d6", - "0x1d7", - "0x1d82", - "0x1d8", - "0x1d9", - "0x1ec3", - "0x1da", - "0x1dc", - "0x1dd", - "0x1de", - "0x1df", - "0x1e0", - "0x1e1", - "0x1e2", - "0x1e3", - "0x1e4", - "0x1e5", - "0x1e6", - "0x1e7", - "0x1e9", - "0x1ea", - "0x1eb", - "0x1ec", - "0x1ed", - "0x1ee", - "0x1ef", - "0x1f0", - "0x1f1", - "0x1f2", - "0x1f3", - "0x1f4", - "0x1f5", - "0x1f6", - "0x1f7", - "0x1dae", - "0x1f8", - "0x1f9", - "0x1ec5", - "0x1fa", - "0x1fb", - "0x1fc", - "0x1fd", - "0x1fe", - "0x1ff", - "0x200", - "0x201", - "0x202", - "0x203", - "0x204", - "0x205", - "0x206", - "0x207", - "0x208", - "0x209", - "0x20a", - "0x20b", - "0x20c", - "0x20d", - "0x20f", - "0x210", - "0x211", - "0x212", - "0x214", - "0x215", - "0x216", - "0x217", - "0x218", - "0x219", - "0x21a", - "0x21b", - "0x1de0", - "0x21c", - "0x21d", - "0x1ec7", - "0x21e", - "0x21f", - "0x220", - "0x221", - "0x1e3f", - "0x222", - "0x223", - "0x224", - "0x226", - "0x1df7", - "0x227", - "0x228", - "0x229", - "0x1e2d", - "0x22b", - "0x22c", - "0x1e1d", - "0x22d", - "0x22e", - "0x1e0f", - "0x22f", - "0x230", - "0x231", - "0x232", - "0x233", - "0x234", - "0x235", - "0x236", - "0x237", - "0x238", - "0x239", - "0x23a", - "0x23b", - "0x23c", - "0x23d", - "0x23e", - "0x23f", - "0x240", - "0x241", - "0x242", - "0x243", - "0x244", - "0x245", - "0x247", - "0x1e97", - "0x248", - "0x249", - "0x1ebb", - "0x24a", - "0x1eb9", - "0x24c", - "0x24d", - "0x1eb7", - "0x24e", - "0x24f", - "0x250", - "0x251", - "0x252", - "0x253", - "0x254", - "0x255", - "0x256", - "0x257", - "0x258", - "0x259", - "0x25a", - "0x25b", - "0x25c", - "0x1f32", - "0x1f2a", - "0x1ff4", - "0x1feb", - "0x1fe4", - "0x1f81", - "0x1f92", - "0x1fab", - "0x1fd6", - "0x1fc7", - "0x1ffc", - "0x2050", - "0x2049", - "0x2040", - "0x2056", - "0x2190", - "0x2079", - "0x2090", - "0x2181", - "0x2171", - "0x2164", - "0x2152", - "0x2145", - "0x20cc", - "0x20d8", - "0x20d9", - "0x20f6", - "0x20ec", - "0x2104", - "0x2136", - "0x2130", - "0x213b", - "0x22ce", - "0x21b6", - "0x21cc", - "0x22c0", - "0x22b1", - "0x22a5", - "0x2294", - "0x2288", - "0x2207", - "0x2213", - "0x2214", - "0x2231", - "0x2227", - "0x223d", - "0x227e", - "0x226f", - "0x2267", - "0x23be", - "0x23ae", - "0x239f", - "0x238f", - "0x237e", - "0x231e", - "0x230e", - "0x2304", - "0x2379", - "0x234c", - "0x233c", - "0x2332", - "0x2376", - "0x235c", - "0x2371", - "0x23ea", - "0x23e1", - "0x2410", - "0x2407", - "0x248a", - "0x2480", - "0x246e", - "0x2468", - "0x2477", - "0x2494", - "0x2541", - "0x2538", - "0x2523", - "0x250e", - "0x24fc", - "0x24f6", - "0x2504", - "0x254a", - "0x25ea", - "0x25da", - "0x256a", - "0x257c", - "0x2578", - "0x2582", - "0x2597", - "0x2588", - "0x2594", - "0x25a7", - "0x25c9", - "0x25c3", - "0x25d1", - "0x26ca", - "0x26b8", - "0x26af", - "0x269c", - "0x2689", - "0x2677", - "0x2671", - "0x2680", - "0x26c1", - "0x282b", - "0x2708", - "0x2815", - "0x27e2", - "0x272f", - "0x272c", - "0x2729", - "0x2731", - "0x27d5", - "0x27cb", - "0x27c1", - "0x27b7", - "0x27ad", - "0x279d", - "0x27a2", - "0x2807", - "0x2804", - "0x2801", - "0x2809", - "0x2850", - "0x2852", - "0x2876", - "0x2912", - "0x2901", - "0x28f1", - "0x28a9", - "0x289a", - "0x28b0", - "0x28e2", - "0x28d8", - "0x28c9", - "0x2929", - "0x292e", - "0x2980", - "0x2977", - "0x296a", - "0x295b", - "0x294f", - "0x29b4", - "0x2999", - "0x29aa", - "0x2a13", - "0x29cf", - "0x29d4", - "0x2a08", - "0x29f8", - "0x29ed", - "0x2a97", - "0x2a2d", - "0x2a32", - "0x2a8c", - "0x2a7c", - "0x2a6f", - "0x2a5b", - "0x2a73", - "0x2a67", - "0x2adc", - "0x25e", - "0x25f", - "0x2ab1", - "0x260", - "0x261", - "0x2ab6", - "0x263", - "0x264", - "0x2ad2", - "0x265", - "0x266", - "0x267", - "0x2aca", - "0x268", - "0x269", - "0x26a", - "0x26b", - "0x26c", - "0x26d", - "0x26e", - "0x26f", - "0x270", - "0x2afd", - "0x2b69", - "0x271", - "0x2b4b", - "0x2b45", - "0x2b3f", - "0x272", - "0x2b39", - "0x273", - "0x2b33", - "0x274", - "0x2b2d", - "0x275", - "0x2b29", - "0x276", - "0x277", - "0x278", - "0x279", - "0x2b31", - "0x27a", - "0x2b37", - "0x27b", - "0x2b3d", - "0x27c", - "0x2b43", - "0x27d", - "0x2b49", - "0x27e", - "0x2b4f", - "0x27f", - "0x280", - "0x2b62", - "0x281", - "0x2ba5", - "0x282", - "0x2b88", - "0x2b7a", - "0x283", - "0x284", - "0x2b97", - "0x285", - "0x286", - "0x287", - "0x2bc2", - "0x288", - "0x2bf0", - "0x2bde", - "0x2bd3", - "0x289", - "0x28a", - "0x28b", - "0x2bda", - "0x28c", - "0x28e", - "0x28f", - "0x2be5", - "0x290", - "0x291", - "0x292", - "0x293", - "0x294", - "0x2c5a", - "0x295", - "0x2c4b", - "0x2c3c", - "0x296", - "0x297", - "0x298", - "0x299", - "0x2c2f", - "0x29a", - "0x2c22", - "0x2c15", - "0x29b", - "0x29c", - "0x29d", - "0x29e", - "0x29f", - "0x2a0", - "0x2c9e", - "0x2a1", - "0x2a2", - "0x2c75", - "0x2a3", - "0x2a4", - "0x2a5", - "0x2c7b", - "0x2a6", - "0x2a7", - "0x2c93", - "0x2a8", - "0x2a9", - "0x2c89", - "0x2aa", - "0x2ab", - "0x2ac", - "0x2ad", - "0x2ae", - "0x2af", - "0x2b0", - "0x2b1", - "0x2cc7", - "0x2cc4", - "0x2b2", - "0x2b3", - "0x2ce8", - "0x2b4", - "0x2cca", - "0x2b5", - "0x2b6", - "0x2b7", - "0x2cf5", - "0x2cde", - "0x2cf1", - "0x2b8", - "0x2b9", - "0x2ba", - "0x2bb", - "0x2bc", - "0x2cfc", - "0x2d13", - "0x2d10", - "0x2d33", - "0x2d16", - "0x2d40", - "0x2d2a", - "0x2d3c", - "0x2d47", - "0x2bd", - "0x2be", - "0x2d95", - "0x2bf", - "0x2d85", - "0x2c0", - "0x2c1", - "0x2c2", - "0x2d7c", - "0x2c3", - "0x2c4", - "0x2c5", - "0x2d70", - "0x2c6", - "0x2c7", - "0x2c8", - "0x2db5", - "0x2db2", - "0x2dd6", - "0x2db8", - "0x2c9", - "0x2ddc", - "0x2dcc", - "0x2dd8", - "0x2f05", - "0x2de3", - "0x2df9", - "0x2df6", - "0x2e2a", - "0x2dfc", - "0x2e20", - "0x2e0f", - "0x2e19", - "0x2efe", - "0x2ca", - "0x2cb", - "0x2cc", - "0x2cd", - "0x2eeb", - "0x2ce", - "0x2cf", - "0x2d0", - "0x2d2", - "0x2d3", - "0x2d4", - "0x2edb", - "0x2ecd", - "0x2d5", - "0x2ec1", - "0x2eb6", - "0x2d6", - "0x2eac", - "0x2ea2", - "0x2e8a", - "0x2e9b", - "0x2e97", - "0x2d7", - "0x2d9", - "0x2da", - "0x2ee3", - "0x2db", - "0x2dc", - "0x2dd", - "0x2de", - "0x2df", - "0x2f67", - "0x2f62", - "0x2f5d", - "0x2f57", - "0x2f6b", - "0x2f7a", - "0x2e1", - "0x2e2", - "0x2e3", - "0x2e4", - "0x32bd", - "0x3243", - "0x31e0", - "0x31d0", - "0x3140", - "0x3061", - "0x2fa3", - "0x2fa7", - "0x304d", - "0x2e5", - "0x2e6", - "0x3041", - "0x2e7", - "0x2fc1", - "0x2e8", - "0x305b", - "0x3031", - "0x3001", - "0x2ff2", - "0x2fe6", - "0x300c", - "0x302e", - "0x3023", - "0x2ea", - "0x3017", - "0x2eb", - "0x30e4", - "0x2ec", - "0x2ed", - "0x306a", - "0x306e", - "0x312f", - "0x3084", - "0x313a", - "0x311f", - "0x3112", - "0x3101", - "0x30cf", - "0x30c0", - "0x30b4", - "0x30da", - "0x30fe", - "0x30f3", - "0x30e7", - "0x2ee", - "0x3199", - "0x3148", - "0x314c", - "0x31bc", - "0x3184", - "0x3175", - "0x3169", - "0x318f", - "0x31b9", - "0x31ae", - "0x31a2", - "0x31ca", - "0x320e", - "0x3202", - "0x31f9", - "0x3219", - "0x323d", - "0x3235", - "0x3229", - "0x3253", - "0x3285", - "0x3277", - "0x326c", - "0x3291", - "0x32b7", - "0x32ad", - "0x329d", - "0x32ea", - "0x2ef", - "0x2f0", - "0x32e1", - "0x2f1", - "0x2f3", - "0x2f4", - "0x334e", - "0x3305", - "0x330a", - "0x3344", - "0x333f", - "0x331b", - "0x3320", - "0x3335", - "0x332e", - "0x2f5", - "0x2f6", - "0x2f7", - "0x333a", - "0x2f8", - "0x3349", - "0x2f9", - "0x2fa", - "0x2fb", - "0x3394", - "0x3389", - "0x337a", - "0x3370", - "0x3383", - "0x339e", - "0x33d4", - "0x33c8", - "0x33ba", - "0x33e8", - "0x33f7", - "0x3406", - "0x3415", - "0x2fd", - "0x3424", - "0x2fe", - "0x3433", - "0x2ff", - "0x3442", - "0x300", - "0x3451", - "0x301", - "0x3460", - "0x302", - "0x346f", - "0x303", - "0x347e", - "0x348d", - "0x349c", - "0x305", - "0x34ab", - "0x306", - "0x34ba", - "0x34c7", - "0x307", - "0x35c0", - "0x35b4", - "0x308", - "0x309", - "0x35a4", - "0x3596", - "0x30a", - "0x3582", - "0x350a", - "0x3510", - "0x3517", - "0x351f", - "0x356c", - "0x3561", - "0x30b", - "0x3556", - "0x354c", - "0x30c", - "0x3543", - "0x30d", - "0x30e", - "0x30f", - "0x310", - "0x311", - "0x3576", - "0x312", - "0x35ac", - "0x313", - "0x314", - "0x3630", - "0x315", - "0x316", - "0x317", - "0x318", - "0x31a", - "0x31b", - "0x31c", - "0x3620", - "0x3618", - "0x3612", - "0x31d", - "0x31e", - "0x31f", - "0x320", - "0x321", - "0x3627", - "0x322", - "0x323", - "0x324", - "0x325", - "0x364c", - "0x327", - "0x3651", - "0x328", - "0x365b", - "0x3660", - "0x3667", - "0x366c", - "0x3675", - "0x367a", - "0x329", - "0x32a", - "0x3684", - "0x3689", - "0x32b", - "0x32c", - "0x32d", - "0x3693", - "0x3696", - "0x32e", - "0x32f", - "0x330", - "0x36f4", - "0x331", - "0x332", - "0x333", - "0x36a5", - "0x36aa", - "0x36af", - "0x36b4", - "0x36b9", - "0x36be", - "0x36c3", - "0x36c8", - "0x36cd", - "0x36d2", - "0x36d7", - "0x36dc", - "0x36e1", - "0x36e6", - "0x36eb", - "0x36ef", - "0x335", - "0x336", - "0x337", - "0x338", - "0x339", - "0x33a", - "0x33b", - "0x33c", - "0x33d", - "0x33e", - "0x33f", - "0x340", - "0x342", - "0x343", - "0x344", - "0x345", - "0x346", - "0x347", - "0x373a", - "0x370b", - "0x3710", - "0x372f", - "0x348", - "0x3726", - "0x378f", - "0x3784", - "0x3774", - "0x376a", - "0x377d", - "0x3799", - "0x406", - "0x483", - "0x59b", - "0x658", - "0x6d4", - "0x7b3", - "0x890", - "0x968", - "0x9e1", - "0xa8e", - "0xada", - "0xbe6", - "0xc36", - "0xc86", - "0xcdc", - "0xd2c", - "0xdb0", - "0xe43", - "0xe85", - "0xeeb", - "0xf51", - "0x101a", - "0x10bb", - "0x1181", - "0x127c", - "0x12d2", - "0x1340", - "0x13ae", - "0x140f", - "0x1470", - "0x1554", - "0x15bf", - "0x1668", - "0x16ec", - "0x1734", - "0x175d", - "0x1786", - "0x17d8", - "0x1831", - "0x18a1", - "0x1afc", - "0x1efe", - "0x1f3e", - "0x1f45", - "0x2004", - "0x205c", - "0x219b", - "0x22d8", - "0x23cd", - "0x23f8", - "0x241e", - "0x249d", - "0x2554", - "0x25f9", - "0x26d6", - "0x283f", - "0x2858", - "0x2922", - "0x298a", - "0x29c3", - "0x2a21", - "0x2aa5", - "0x2aea", - "0x2bb5", - "0x2c69", - "0x2cad", - "0x2d9e", - "0x2f0d", - "0x2f6f", - "0x32ce", - "0x32f8", - "0x3356", - "0x33a4", - "0x33e2", - "0x34ce", - "0x35cc", - "0x363c", - "0x369a", - "0x36ff", - "0x3749", - "0x1cca9", - "0x700900500400300a007009005004003008007006005004003002001000", - "0x300e00700900500400300d00700900500400300c00700900500400300b", - "0x500400301100700900500400301000700900500400300f007009005004", - "0x7009005004003014007009005004003013007009005004003012007009", - "0x19018007009005004003017007009005004003016007009005004003015", - "0x502000502000502000502000502000502000501f01b01e01d01c01b01a", - "0x21020005020005020005020005020005020005020005020005020005020", - "0x500400300700701b00702202102400701b00702202102300701b007022", - "0x502600500400300500701b00702202101b007025005004003005007025", - "0x501c01b02d01900900500900502e01b02d01902c02b02a005029028027", - "0x503500500400303400700600500400303300503203100203002f00502f", - "0x500400303b00503a00502f00503700303900503800502f005037003036", - "0x700900500400303e00700900500400303d00700900500400303c007009", - "0x304100700600500400302700700600500400304000700600500400303f", - "0x5004003044007006005004003043007006005004003042007006005004", - "0x7006005004003047007006005004003046007006005004003045007006", - "0x1b022019049005029028043005026005004003024007006005004003048", - "0x1d04f00504e00501c01b04d01900600504c04b04a01b01a01900900501c", - "0x502f00503700305400505300502f00503700305200505100505001b04d", - "0x7009005004003058007009005004003057007009005004003056005055", - "0x5d00900500900500900500900505c01b05b01905a007009005004003059", - "0x306100506000502f00503700302f00502905f05e005035005004003002", - "0x1902c065064007009005004003063007009005004003062007006005004", - "0x6a05200506900506801b04d01d06700501c01b02201900600506601b022", - "0x506e01b04d01d06d00501c01b02201902000506c00506b01b02d01d02c", - "0x502905f07200507100502f00503700307000700600500400305200506f", - "0x1b02d01d075005029028074007009005004003073007009005004003009", - "0x507900507900507900507900501c01b01e01902c078020005077005076", - "0x5079005079005079005079005079005079005079005079005079005079", - "0x707900500400307b00700600500400307a007006005004003079005079", - "0x307f00507e00500400307d00700600500400307c007079005004003044", - "0x500400308100507e005004003016007079005004003080007079005004", - "0x707900500400308300507e005004003017007079005004003082007079", - "0x308600707900500400308500507e005004003018007079005004003084", - "0x500400308700502905f02c08907d007079005004003088007087005004", - "0x7087005004003016007087005004003017007087005004003018007087", - "0x3012007087005004003013007087005004003014007087005004003015", - "0x500400304600707900500400304500707900500400308a007006005004", - "0x307900502905f08b00507e005004003048007079005004003047007079", - "0x502902802000508d00508c01b02d01d02f005029028020007079005004", - "0x1d00900508700500600509101b09001902000508f00508e01b02d01d084", - "0x9509400700600500400309300700600500400302000508400509201b02d", - "0x309900700600500400309800700600500400309700509601b02201902c", - "0x504c09d09c00700600500400309b00700600500400309a007006005004", - "0x30a500501c01b0a401901b0070a00a309e00504c0a20a10050a009f09e", - "0x190a90050290a804900504c04b0a70070060050040030a6007006005004", - "0x30ae0050290a80790050060050a90050ad01b0ac0190ab0050aa01b022", - "0x50040030b00070060050040030070070790050040030af007006005004", - "0x1b04d01d0200050ae00501c01b04d0190b20070060050040030b1007006", - "0xb802c0b70b60070060050040030b50070790050040030520050b40050b3", - "0x70b90b80bc0050bb0050a40ba0240070b90b80070070b90b80050070b9", - "0x50a50050a40c10050070a00a30c00050a00bf0be0050bb0050a40bd048", - "0xc50c40050c40050c40050c40050c301b05b0190c200701b0070220210be", - "0x70050070220210050070c90050040030c70050290c80c700504c0c6002", - "0x50040030c70050290cb01b00701b00702202101b0070ca005004003005", - "0x501c01b0ce0190020cd0c700504c09d0cc0070060050040030460070c4", - "0x504c0a20d00050a009f0240070c40050040030cf0050cf0050cf0050cf", - "0x50c40050c40050c400501c01b05b01902c0d20d100501c01b0a40190c7", - "0xd50d40050320310020d30450070c400500400301b0070c40050040030c4", - "0x70790050040030d80050320310020d70ae0050320310d6005032031002", - "0x70060050040030db00700600500400302c0da0d9007006005004003005", - "0x30e00070060050040030df0070060050040030de00502905f02c0dd0dc", - "0x30060050e401b0220190970050e301b02201902c0e20050070e1005004", - "0x50040030e70070060050040030e60070060050040030e5007006005004", - "0x50ea01b02d01d0240070790050040030e90070060050040030e8007006", - "0x50370030520050ed0050ec01b04d01d0eb00501c01b022019020005020", - "0x30f20070090050040030f10050f000502f0050370030ef0050ee00502f", - "0x50370030f50070090050040030f40070090050040030f3007009005004", - "0x30fa0070090050040030f90050f800502f0050370030f70050f600502f", - "0x50370030fd0070090050040030fc0070090050040030fb007009005004", - "0x310200700900500400310100510000502f0050370030ff0050fe00502f", - "0x5037003105007009005004003104007009005004003103007009005004", - "0x310a00700900500400310900510800502f00503700310700510600502f", - "0x503700310d00700900500400310c00700900500400310b007009005004", - "0x1d0c200700900500400311100700900500400302c11010f00510e00502f", - "0x501c01b02201900600502000511401b02d01d02000511300511201b02d", - "0x30eb00502f00502f00511801b09001905200511700511601b04d01d115", - "0x700900500400311c00511b00502f00503700311a00511900502f005037", - "0x312000700900500400311f00700900500400311e00700900500400311d", - "0x312400700900500400312300700600500400312200512100502f005037", - "0x312800700900500400312700512600502f005037003125007009005004", - "0x312c00512b00502f00503700312a007006005004003129007009005004", - "0x313000700900500400312f00700900500400312e00512d00502f005037", - "0x5037003133007006005004003132007009005004003131007009005004", - "0x500400313700700900500400313600700600500400313500513400502f", - "0x313a00513a00502f00503700313a00513900502f005037003138007009", - "0x507900507900507900507900507900501c01b13c01913b007079005004", - "0x14013f00513e01b02201913d0050290a807900504c04b079005079005079", - "0x305200514400514301b04d01d02000514200514100501c01b09001902c", - "0x2814e00514d00514c00514b00514a005149005148005147005146005145", - "0x707900500400315000707900500400314f007079005004003146005029", - "0x3154007079005004003153007079005004003152007079005004003151", - "0x1d02000513d00501c01b04d019156007079005004003155007079005004", - "0x315a00700600500400315900707900500400305200515800515701b04d", - "0x500400315d00700600500400315c00700600500400315b007006005004", - "0xa808700504c04b16000700900500400315f00700600500400315e007009", - "0x1b04d01d02000516100501c01b04d01916300516201b022019161005029", - "0x1916800516701b0220191660050290a802f00504c04b052005165005164", - "0x500400305200516b00516a01b04d01d02000516100516900501c01b0ac", - "0x700600500400300700700600500400300500700900500400301b007009", - "0x316f00700600500400316e00700600500400316d00700600500400316c", - "0x1917300517201b0220191710050290a808400504c04b170007006005004", - "0x50290a805200517600517501b04d01d0eb00517400517400501c01b090", - "0x1b04d01d0eb00517900517900501c01b09001917800517701b02201904f", - "0x518001b17f01902c17e17d00502902817c00502902805200517b00517a", - "0x500600518601b185019184005029028006005183005183005182005181", - "0x5079005179005009005174005006005006005006005179005009005183", - "0x1d02000517400518701b02d01d18300503203117c005032031179005079", - "0x518a01b04d01d18900517900501c01b04d01902000517100518801b04d", - "0x1d18d00517900501c01b02d01902000517900518c01b02d01d05200518b", - "0x300500708700500400319000700600500400305200518f00518e01b04d", - "0x5004003192007006005004003020007006005004003191007006005004", - "0x1900900500900501c01b02d019195007006005004003002194193007006", - "0x1919a01b01a01919900700600500400300219819700500600519601b02d", - "0x700600500400305200519d00519c01b04d01d00600519b00501c01b02d", - "0x1b1a30190021a20060050b91a100600504c1a019f00700600500400319e", - "0x1902000517c0051a601b02d01d0520051a50051a401b04d01d02000501c", - "0x51aa01b0900190520051a90051a801b04d01d1a700517900501c01b02d", - "0x500400317d00503203102000517d0051ab01b02d01d183005087005087", - "0x51ad01b04d01d02000508700501c01b02d01900600502905f1ac007006", - "0x1b04d01d02000519b00501c01b1af01901b0070870050040030520051ae", - "0x31b40070060050040031b300700600500400302c1b20520051b10051b0", - "0x51b70051b601b04d01d02000504f00501c01b04d0191b5007006005004", - "0x70060050040031b90050320310021b817900503203104f005032031052", - "0x1b04d01d1bc00517900501c01b04d01902000504f0051bb01b04d01d1ba", - "0x50320310200051c00051bf01b02d01d0060050290280520051be0051bd", - "0x301b0070060050040030050070060050040031c1007006005004003006", - "0x50040031c30070060050040031c2007006005004003023007006005004", - "0x1b04d01d02c1c501b00707900500400317900501c01b0220191c4007006", - "0x50060051ca01b02d01d02c1c91c80070060050040030520051c70051c6", - "0x1b0050051d201b1d11790050051d001b1cf01b1ce01b1cd1cc0021cb020", - "0x51d201b0071d70050071d60060050051d50060050051d40060050051d3", - "0x51da0050071d70050071d60200050051d901b1d81d70050051d2178005", - "0x51dd1c00050051dd1780050051dd01b1dc0060050051d201b1db1d7005", - "0x51d90060050051e21e10050051e00060050051df1de0050051dd006005", - "0x1b90050051d21e40050051d20050071e30050071d60520050051d904e005", - "0x790050051e91e80050051e001b1e71e60050051d201b1e51e30050051d2", - "0x4f0050051dd04f0050051ec01b1eb01b1ea0790050051d21de0050051e9", - "0x51dd04f0050051d201b0071e30050071d61c70050051d91790050051d9", - "0x51dd1ef0050051e00200050051dd1ee0050051e01ed0050051e0079005", - "0x51f41f30050051e01f20050051e01f10050051e01f00050051e0179005", - "0x1f80050051d201b0071f80050071d601b1f70060050051f601b1f5006005", - "0x51da03b0240051f91790050051d21f80050051da0050071f80050071d6", - "0x1fc0050051e001b1fb1830050051dd1bc0050051da1be0050051d01fa005", - "0x4f0050051f604f0050051f41790050051f41b90050051f41fd0050051dd", - "0x3a0240051f91790050051f61b90050051f61ff0050051dd1fe0050051dd", - "0x51f901b2020060050052011780050051e91b70050051d02000050051da", - "0x51e02040050051e02030050051e004e0050051dd0520050051d0038024", - "0x2080050051d219b0050051d92080050051dd01b2072060050051dd205005", - "0x51e00870050051dd01b20b1b10050051dd20a0050051da2090240051f9", - "0x51dd20e0050051da20d0240051f90870050051d20870050051ec20c005", - "0x1b2152140050051e02130050051dd01b21201b21101b21001b20f1ae005", - "0x2180240051f917d0050051f62170050051da2160240051f917d0050051f4", - "0x17d0050051dd17c0050051dd1a70050051da1a90050051d02190050051da", - "0x21a0240051f917c0050051d217d0050051d219b0050051dd19b0050051ec", - "0x1b21f21e0240051f901b21d21c0050051dd1a50050051dd21b0050051da", - "0x51dd2240240051f92230050051d20060050052222210050051d201b220", - "0x51dd01b0070eb0050071d60eb0050051d20050070eb0050071d6225005", - "0x51f90330050051d22290240051f92280240051f901b22701b2260eb005", - "0x51da22e0240051f922d0050051e022c0050051e022b0240051f922a024", - "0x51e90510240051f92310240051f92300050051e019d0050051d022f005", - "0x51dd01b23404e0240051f92330050051d201b2321830050051e9006005", - "0x51d504f0240051f92350050051d22350050051d91970050051d9009005", - "0x51dd2350050051d02350050051e92350050051dd2350050051ec01b005", - "0x2380050051d22370050051e001b2360090050051d51970050051d0197005", - "0xd60050051d223b0050051e023a0050051e02390240051f90520240051f9", - "0x520050051d223d0240051f923c0240051f90d40050051d20d80050051d2", - "0x1de0050051d201b24101b24023f00700523e0540240051f91830050051d2", - "0x1fa0050051d201b0071fa0050071d61be0050051d901b0071bc0050071d6", - "0x2000050071d61b70050051d90050071fa0050071d60050071bc0050071d6", - "0x51e001b2421790050051e90050072000050071d62000050051d201b007", - "0x870050051e920a0050051d200500720a0050071d62440050051e0243005", - "0x20e0050071d62480050051e001b2472460050051e001b2450870050051d5", - "0x17d0050051d901b00720e0050071d61ae0050051d920e0050051d2005007", - "0x560240051f90050072170050071d62170050051d201b0072170050071d6", - "0x1710050051d20840050051df18d0050051da18f0050051d02490050051da", - "0x1710050051ec1890050051da18b0050051d024a0050051da0550240051f9", - "0x71d624b0050051d201b00724b0050071d61740050051d91710050051dd", - "0x1b0071a70050071d617c0050051d901b24c24b0050051da00500724b005", - "0x71d61740050051dd2190050051d201b0072190050071d61a90050051d9", - "0x51f41830050051f40200050051d50050072190050071d60050071a7005", - "0x1810050051d21840050051d01840050051d424e0050051d201b24d17c005", - "0x1820050051d217d0050051d017d0050051e917d0050051ec17d0050051d4", - "0x17c0050051d41830050051d51820050051dd24f0050051dd1830050051f6", - "0x51d501b25017c0050051d017c0050051e917c0050051ec17c0050051f6", - "0xeb0050051da17b0050051d02520050051da0530240051f901b251179005", - "0x840050052011740050051d01740050051e91740050051d51e40050051d5", - "0x790050051d51760050051d02540050051da2530240051f91740050051d2", - "0x71d62550050051e021b0050051d201b00721b0050071d61a50050051d9", - "0x2590050051e02580050051e02570050051e02560050051e000500721b005", - "0x2250050051d200600500525c25b0050051e02080050051e925a0050051dd", - "0x2f0050051d202f0050051d913a0050051e01390050051e002f0050051df", - "0x1690050051d91660050051dd1660050051ec0870050051df02f0050051e2", - "0x16b0050051d025e0050051da25d0240051f91610050051d21690050051d2", - "0x1610050051ec1650050051d02600050051da25f0240051f91690050051dd", - "0x51d22630050051e002f0050051d001b2622610050051d91610050051dd", - "0x51dd2610050051d20870050051e22650050051e02640050051e0009005", - "0x51d92680050051e01c00050051d20060050052672660050051e002f005", - "0x790050051df26a0050051e02690050051e001b00720a0050071d61b1005", - "0x26c0050051da0350240051f913d0050051d20790050051e226b0050051e0", - "0x13d0050051dd13d0050051ec1580050051d001b26f01b00726e00500726d", - "0x2700050051da05e0240051f91420050051d21410050051d21410050051d9", - "0x51d01460050051d42720050051d201b2711410050051dd1440050051d0", - "0x6d0050051ec01b2762750050051e02740050051e02730050051e0146005", - "0x2770050051e006c0050051dd06d0050051da06d0050051d206d0050051dd", - "0x2f0050051e927b0050051e027a0050051e02790050051e02780050051e0", - "0x51e027e0050051e01270050051e027d0050051e002f0050051ec01b27c", - "0x2830050051d92820050051e00180050051e02810050051e001b28027f005", - "0x2850050051da2840240051f90670050051d22830050051d20670050051d9", - "0x51d22870050051dd2870050051ec01b2861150050051da1170050051d0", - "0x51e02890050051e02880050051e01130050051dd2870050051da287005", - "0x28e0050051e028d0050051e028c0050051e01010050051e001b28b28a005", - "0x610240051f91130050051d22910050051e02900050051e028f0050051e0", - "0x71d600600500529501b2942930050051e00ed0050051dd2920050051da", - "0x1b90050051d52970050051e02960050051e022f0050051d200500722f005", - "0x51e02990050051e02980050051e001b00722f0050071d619d0050051d9", - "0x1b29c29b0050051d029b0050051dd29b0050051ec29b0050051d929a005", - "0x51d529e0050051d029e0050051dd29e0050051ec29e0050051d901b29d", - "0x51e001b2a10970050051dd01b2a029f0050051e00970050051e9097005", - "0x2a70050051e00de0050052a62a50050051d201b2a42a30050051e02a2005", - "0x1b2aa0de0050051dd0de0050051d201b2a90de0050051e92a80050051e0", - "0x1b2b02a50050051dd01b2af01b2ae2ad0050051d201b2ac2ab0050051e0", - "0x51f42b30050051e01810050051dd0970050051d22b200700523e01b2b1", - "0x51e02b40050051e00d40050051f40d60050051f40ae0050051f40d8005", - "0x2b90050051e00c70050052b801b2b72b60050051d22b60050051d92b5005", - "0xc70050052bd2bb0050051d22bc0050051d22bb0050051d90c40050052ba", - "0x2c20050051dd2c10050051dd2c00050051dd2bf0050051dd2be0050051dd", - "0x2c70050051e00c70050052c62c50050051e02c40050051e02c30050051dd", - "0xc70050072ca0c70050052c90c90050051d20ca0050051d22c80050051e0", - "0x52cb0240070052cb0480070052cb0d40050051f60d80050051f60d1005", - "0x51d92ce0050051dd2ce0050051ec01b2cd0cf0050051d201b2cc007007", - "0x51e00490050051df0d60050051f60600240051f92ce0050051d22ce005", - "0x51da0060240051f90ae0050051d20ae0050051d92d00050051e02cf005", - "0x51e02d40050051e02d30050051e02d20050051e00b40050051d02d1005", - "0x51e90ae0050051dd0ae0050051ec0ae0050051f62d60050051e02d5005", - "0x51d22d90050051d90490050052010ab0050051e90ae0050052d82d7005", - "0x51e02da0050051dd2d70050051dd0ab0050051dd0670240051f92d9005", - "0x2de0050051d209e0050052b82dd0050051e02bc0050051dd01b2dc2db005", - "0x60050052e12e00050051e02de0050051dd2df0050051dd09e0050052bd", - "0x2e60050051d92e50050051e02e40050051e02e30050051e02e20050051e0", - "0x60050052e82e70050051e02e60050051d02e60050051dd2e60050051ec", - "0x2490050051d201b0072490050071d618f0050051d901b00718d0050071d6", - "0x1890050071d600500718d0050071d62e90050051e00050072490050071d6", - "0x690240051f924a0050051d201b00724a0050071d618b0050051d901b007", - "0x500724a0050071d60050071890050071d60840050051e22ea0050051da", - "0x50072520050071d62520050051d201b0072520050071d617b0050051d9", - "0x71d62eb0050051d21730050051d201b0072eb0050071d60840050051d3", - "0x840050051e90840050051d20840050051d42eb0050051da0050072eb005", - "0x51d201b0072540050071d61760050051d90840050051dd0840050051d0", - "0x2f0050051d31690050051d00050072540050071d61730050051dd254005", - "0x50072ec0050071d62ec0050051d21680050051d201b0072ec0050071d6", - "0x25e0050071d62ed0240051f902f0050051d502f0050051d42ec0050051da", - "0x8700500520101b00725e0050071d616b0050051d925e0050051d2005007", - "0x2f10050051e007e0050051dd01b2f001b2ef07e0050051d22ee0050051e0", - "0x2600050071d62f50050051e02f40050051e02f30050051e02f20050051e0", - "0x51e02f80050051e02f70050051e02f60050051e02600050051d2005007", - "0x51e001b2fe01b2fd2fc0050051e02fb0050051e02fa0050051e02f9005", - "0x1b0072600050071d61650050051d92ff0050051e006c0240051f907f005", - "0x3020050051e00810050051e03010050051e03000050051e0079005005201", - "0x3050050051e007e0050051d53040050051e00830050051e03030050051e0", - "0x51e001b30907900508700500730801b3073060050051e00850050051e0", - "0x51d930d0050051e030c0050051e006d0240051f930b0050051e030a005", - "0x26c0050071d630e0050051e026c0050051d201b00726c0050071d6158005", - "0x1b0073110050071d60750050053101410050051d030f0050051e0005007", - "0x51d53110050051da0050073110050071d63110050051d213f0050051d2", - "0x71d61440050051d92700050051d20050072700050071d601b312077005", - "0x51dd01b3132830050051d02830050051e91420050051dd01b007270005", - "0x1b3140090050051e90360050051e00260050051dd2830050051dd067005", - "0x1b0072850050071d61170050051d90050071150050071d63150050051e0", - "0x6c0050051d206f0050051d03160050051da06f0240051f92850050051d2", - "0x670050051d00670050051ec0690050051d02ed0050051da3160240051f9", - "0x5e0050051e00050072850050071d62840050051e001b0071150050071d6", - "0x2f0050052a601b31801b3170350050051d20350050051e925f0050051e0", - "0x1b31a23c0050051e023d0050051e02530050051dd01b3193150240051f9", - "0x2920050071d62920050051d201b0072920050071d60ed0050051d901b31b", - "0x51d50c40050051dd2ce0050051d02ce0050051e90350050051dd005007", - "0x51d201b0072d10050071d60b40050051d90060050c400500731c0c4005", - "0x51dd0510050051d02390050051da0360240051f90ae0050051d02d1005", - "0x50072d10050071d604f0050051d50490050051e201b31e01b31d0a9005", - "0x490050051d50490050051d40490050051d32d90050051d00ae0050051d5", - "0x2ea0050051d201b0072ea0050071d60840050051d92d90050051dd01b31f", - "0x870050090050073080260050051d222e0050051e00050072ea0050071d6", - "0x2240050051e02280050051e02290050051e022a0050051e022b0050051e0", - "0x20d0050051e02160050051e02180050051e021a0050051e021e0050051e0", - "0x1b3233220050051e01920050051e03210050051e001b3202090050051e0", - "0x51d201b0073160050071d606f0050051d901b00706d0050071d601b324", - "0x51f400500706d0050071d607c0050051e00050073160050071d6316005", - "0x532502a0050051d202a0050051dd02a0050051ec02a0050051d9033005", - "0x3280050051e001b3270330050051f60260240051f902a00500532602a005", - "0x50072ed0050071d62ed0050051d201b0072ed0050071d60690050051d9", - "0x32c0050051e00250050051d232b0050051e001b32a01b3290b50050051dd", - "0x32e00500732d32e0050051d200900532e00500731c02500502500500732d", - "0x790050073082530050051d22530050051d900900532f00500731c025005", - "0x51e007d0050051e03320050051da3320050051d2332005005331330005", - "0x51e00410050051e01930050051e00270050051e00400050051e0023005", - "0x51e00460050051e00450050051e00440050051e00430050051e0042005", - "0x71d60510050051d90070050051e00240050051e00480050051e0047005", - "0x51f90050072390050071d60050050051e02390050051d201b007239005", - "0x2d304704800733400700501b00700501b01b33400501b01b01b333072024", - "0x1b04801b04400533400502400502401b01b33400501b00701b045046007", - "0x4204300733400704400504601b04800533400504800504701b01b334005", - "0x504401b19300533400504200504501b01b33400501b00701b041005040", - "0x533400504300504201b04000533400502700504301b027005334005193", - "0x33400501b00701b01b33000501b19301b07d00533400504000504101b023", - "0x4100504201b33200533400502000504001b02000533400501b02701b01b", - "0x33000533400707d00502301b07d00533400533200504101b023005334005", - "0x2e632c32e00733400733004800707d01b01b33400501b00701b32f0052e2", - "0x2300504601b32e00533400532e00504701b01b33400501b00701b32b005", - "0x33400532800504501b01b33400501b00701b3350052f4328025007334007", - "0x4601b00900533400500900502001b02500533400502500504201b009005", - "0x501b33201b01b33400501b00701b03300522902a02f007334007025005", - "0x900532e01b01b33400502a00532f01b01b33400502f00533001b01b334", - "0x1b02501b0b500533400501b32b01b01b33400532c00532c01b01b334005", - "0x533400507c0b500732801b07c00533400507c00502001b07c005334005", - "0x502f01b32100533400532219200700901b19200533400501b33501b322", - "0x533400504700502a01b32e00533400532e00504701b039005334005321", - "0x32e0480050390053340050390050b501b00700533400500700503301b047", - "0x503300533001b01b33400501b33201b01b33400501b00701b039007047", - "0x2419201b03b00533400503b00532201b03b00533400501b07c01b01b334", - "0x4401b01b33400501b00701b20d20900708103803a00733400703b04732e", - "0x1b01b33400501b04801b21800533400501b32101b216005334005009005", - "0x503a01b21e32c00733400532c00503b01b21a218007334005218005039", - "0x21e21a00703804703801b03a00533400503a00504701b21a00533400521a", - "0x502a01b01b33400501b00701b22b22a229024079228224007334007216", - "0x32c21822822404820901b21800533400521800503a01b224005334005224", - "0x1b33201b01b33400501b00701b05204f04e02402605123122e024334007", - "0x32801b05100533400505100502001b23900533400501b32b01b01b334005", - "0x23d00521601b05423d00733400523c00520d01b23c005334005051239007", - "0x1b05500533400505600521a01b05600533400505400521801b01b334005", - "0x522e00502a01b03a00533400503a00504701b05300533400505500521e", - "0x50530053340050530050b501b23100533400523100503301b22e005334", - "0x1b25300533400504e00502a01b01b33400501b00701b05323122e03a048", - "0x30b00501b19301b25f00533400505200522401b25d00533400504f005033", - "0x33400521800522801b01b33400532c00532c01b01b33400501b00701b01b", - "0x522401b25d00533400522a00503301b25300533400522900502a01b01b", - "0x901b03500533400501b33501b01b33400501b33201b25f00533400522b", - "0x503a00504701b28400533400505e00502f01b05e00533400525f035007", - "0x1b25d00533400525d00503301b25300533400525300502a01b03a005334", - "0x1b01b33400501b00701b28425d25303a0480052840053340052840050b5", - "0x6100533400501b32b01b01b33400532c00532c01b01b33400500900532e", - "0x6006100732801b06000533400506000502001b06000533400501b22901b", - "0x6900533400500606700700901b06700533400501b33501b006005334005", - "0x20d00502a01b20900533400520900504701b2ed00533400506900502f01b", - "0x2ed0053340052ed0050b501b00700533400500700503301b20d005334005", - "0x33001b01b33400501b33201b01b33400501b00701b2ed00720d209048005", - "0x1b06c00533400501b32b01b01b33400532c00532c01b01b334005335005", - "0x506d06c00732801b06d00533400506d00502001b06d00533400501b22a", - "0x1b31500533400506f31600700901b31600533400501b33501b06f005334", - "0x504700502a01b32e00533400532e00504701b03600533400531500502f", - "0x50360053340050360050b501b00700533400500700503301b047005334", - "0x4701b01b33400502300533001b01b33400501b00701b03600704732e048", - "0x22b01b01b33400501b00701b01b2de00501b19301b02600533400532b005", - "0x2600533400504800504701b01b33400502300533001b01b33400532f005", - "0x7100533400501b22e01b07200533400501b32b01b01b33400501b33201b", - "0x1b33501b07700533400507107200732801b07100533400507100502001b", - "0x533400507900502f01b07900533400507731100700901b311005334005", - "0x503301b04700533400504700502a01b02600533400502600504701b075", - "0x1b0750070470260480050750053340050750050b501b007005334005007", - "0x1b30f00533400501b32b01b01b33400502400523101b01b33400501b007", - "0x530e30f00732801b30e00533400530e00502001b30e00533400501b229", - "0x1b30b00533400530d30c00700901b30c00533400501b33501b30d005334", - "0x504500502a01b04600533400504600504701b30a00533400530b00502f", - "0x530a00533400530a0050b501b00700533400500700503301b045005334", - "0x4800733400700501b00700501b01b33400501b01b01b30a007045046048", - "0x1b04400533400502400502401b01b33400501b00701b04504600727b047", - "0x1b0410052c304204300733400704400504601b048005334005048005047", - "0x1b01b33400504200532f01b01b33400504300533001b01b33400501b007", - "0x533400502700502001b02700533400501b02501b19300533400501b32b", - "0x700901b02300533400501b33501b04000533400502719300732801b027", - "0x33400504800504701b02000533400507d00502f01b07d005334005040023", - "0xb501b00700533400500700503301b04700533400504700502a01b048005", - "0x33001b01b33400501b00701b020007047048048005020005334005020005", - "0x33200533400533200532201b33200533400501b07c01b01b334005041005", - "0x33400501b00701b32c32e00701832f33000733400733204704802419201b", - "0x33000707d01b32b00533400532b00502001b32b00533400501b05101b01b", - "0x33400501b32101b01b33400501b00701b33500510132802500733400732b", - "0x3b01b02a00900733400500900503901b02f00533400501b04e01b009005", - "0x502f00502001b02a00533400502a00503a01b033328007334005328005", - "0x702f03302a00732f04703801b02500533400502500504701b02f005334", - "0x33400501b04f01b01b33400501b00701b3211923220240f907c0b5007334", - "0x2001b00900533400500900503a01b0b50053340050b500502a01b039005", - "0xf103a03b00733400703932800907c0b504703801b039005334005039005", - "0x520d01b21600533400501b32b01b01b33400501b00701b20d209038024", - "0x533400521a00521801b01b33400521800521601b21a218007334005216", - "0x504701b22800533400522400521e01b22400533400521e00521a01b21e", - "0x533400503a00503301b03b00533400503b00502a01b025005334005025", - "0x33400501b00701b22803a03b0250480052280053340052280050b501b03a", - "0x503301b22a00533400503800502a01b22900533400502500504701b01b", - "0x1b01b10f00501b19301b22e00533400520d00522401b22b005334005209", - "0x1b01b33400532800532c01b01b33400500900522801b01b33400501b007", - "0x519200503301b22a00533400532200502a01b229005334005025005047", - "0x1b00701b01b10f00501b19301b22e00533400532100522401b22b005334", - "0x502001b05100533400501b05201b23100533400501b32b01b01b334005", - "0x33400533500504701b04e00533400505123100732801b051005334005051", - "0x22401b22b00533400500700503301b22a00533400532f00502a01b229005", - "0x33400522e04f00700901b04f00533400501b33501b22e00533400504e005", - "0x2a01b22900533400522900504701b23900533400505200502f01b052005", - "0x3340052390050b501b22b00533400522b00503301b22a00533400522a005", - "0x533400501b32b01b01b33400501b00701b23922b22a229048005239005", - "0x23c00732801b23d00533400523d00502001b23d00533400501b22901b23c", - "0x533400505405600700901b05600533400501b33501b05400533400523d", - "0x502a01b32e00533400532e00504701b05300533400505500502f01b055", - "0x53340050530050b501b00700533400500700503301b32c00533400532c", - "0x1b33400502400523101b01b33400501b00701b05300732c32e048005053", - "0x33400525d00502001b25d00533400501b22901b25300533400501b32b01b", - "0x901b03500533400501b33501b25f00533400525d25300732801b25d005", - "0x504600504701b28400533400505e00502f01b05e00533400525f035007", - "0x1b00700533400500700503301b04500533400504500502a01b046005334", - "0x4700533400501b23901b2840070450460480052840053340052840050b5", - "0x1b01b33400501b01b01b01b33400501b23c01b04500533400501b23901b", - "0x1b01b33400501b00701b04104200733604304400733400700501b007005", - "0x533400504400504701b01b33400501b04801b193005334005024005024", - "0x1b01b33400501b00701b02300515804002700733400719300504601b044", - "0x502000504301b02000533400507d00504401b07d005334005040005045", - "0x1b32f00533400533200504101b33000533400502700504201b332005334", - "0x4001b32e00533400501b02701b01b33400501b00701b01b26800501b193", - "0x33400532c00504101b33000533400502300504201b32c00533400532e005", - "0x1b01b33400501b00701b32b00533704800533400732f00502301b32f005", - "0x533832802500733400704804400705401b04800533400504804700723d", - "0x733000504601b02500533400502500504701b01b33400501b00701b335", - "0x533400502f00504501b01b33400501b00701b02a00533902f009007334", - "0x4201b03300533400504600504401b04600533400504604500723d01b046", - "0x701b32200525907c0b500733400700900504601b009005334005009005", - "0x3210053340050b500504201b19200533400507c00505601b01b33400501b", - "0x1b33400501b00701b01b17100501b19301b03900533400519200505501b", - "0x532200504201b03a00533400503b00505301b03b00533400501b02701b", - "0x33a03800533400703900525301b03900533400503a00505501b321005334", - "0x33400503800504501b01b33400501b33201b01b33400501b00701b209005", - "0x504401b21800533400532100521801b21600533400501b32b01b20d005", - "0x533400504300502a01b02500533400502500504701b21a00533400520d", - "0x502001b21600533400521600522401b21800533400521800525d01b043", - "0x1b22822421e02433400521a21621804302504725f01b21a00533400521a", - "0x22900505e01b01b33400501b00701b22a0051e4229005334007228005035", - "0x501b00701b0510051ed23100533400722e00528401b22e22b007334005", - "0x22f05204f00733400704e00504601b04e00533400522b00502401b01b334", - "0x505200532f01b01b33400504f00533001b01b33400501b00701b239005", - "0x32800506101b01b33400503300532e01b01b33400523100521601b01b334", - "0x502001b23d00533400501b02501b23c00533400501b32b01b01b334005", - "0x533400501b33501b05400533400523d23c00732801b23d00533400523d", - "0x4701b05300533400505500502f01b05500533400505405600700901b056", - "0x33400500700503301b22400533400522400502a01b21e00533400521e005", - "0x501b00701b05300722421e0480050530053340050530050b501b007005", - "0x25300532201b25300533400501b07c01b01b33400523900533001b01b334", - "0x1b05e0350071ff25f25d00733400725322421e02419201b253005334005", - "0x33400528400521601b06128400733400523100520d01b01b33400501b007", - "0x4706001b25d00533400525d00504701b06000533400506100521801b01b", - "0x501b00701b06d06c2ed0241b106906700602433400706003332800725f", - "0x4701b31600533400506f00521e01b06f00533400506900521a01b01b334", - "0x33400506700503301b00600533400500600502a01b25d00533400525d005", - "0x501b00701b31606700625d0480053160053340053160050b501b067005", - "0x2f01b03600533400506d31500700901b31500533400501b33501b01b334", - "0x3340052ed00502a01b25d00533400525d00504701b026005334005036005", - "0x480050260053340050260050b501b06c00533400506c00503301b2ed005", - "0x532e01b01b33400523100521601b01b33400501b00701b02606c2ed25d", - "0x22901b07200533400501b32b01b01b33400532800506101b01b334005033", - "0x33400507107200732801b07100533400507100502001b07100533400501b", - "0x2f01b07900533400507731100700901b31100533400501b33501b077005", - "0x33400505e00502a01b03500533400503500504701b075005334005079005", - "0x480050750053340050750050b501b00700533400500700503301b05e005", - "0x523101b01b33400505100522b01b01b33400501b00701b07500705e035", - "0x4701b01b33400532800506101b01b33400503300532e01b01b33400522b", - "0x1b33b00501b19301b30e00533400522400502a01b30f00533400521e005", - "0x1b33400503300532e01b01b33400532800506101b01b33400501b00701b", - "0x22400502a01b21e00533400521e00504701b30d00533400522a00502f01b", - "0x30d00533400530d0050b501b00700533400500700503301b224005334005", - "0x22b01b01b33400501b33201b01b33400501b00701b30d00722421e048005", - "0x1b01b33400503300532e01b01b33400532800506101b01b334005209005", - "0x33400504300502a01b30f00533400502500504701b01b334005321005330", - "0x30b00502001b30b00533400501b00601b30c00533400501b32b01b30e005", - "0x30600533400501b33501b30a00533400530b30c00732801b30b005334005", - "0x504701b30500533400508500502f01b08500533400530a30600700901b", - "0x533400500700503301b30e00533400530e00502a01b30f00533400530f", - "0x33400501b00701b30500730e30f0480053050053340053050050b501b007", - "0x33400532800506101b01b33400502a00533001b01b33400501b33201b01b", - "0x33400501b22a01b30400533400501b32b01b01b33400504500506701b01b", - "0x1b30300533400508330400732801b08300533400508300502001b083005", - "0x508100502f01b08100533400530330200700901b30200533400501b335", - "0x1b04300533400504300502a01b02500533400502500504701b301005334", - "0x70430250480053010053340053010050b501b007005334005007005033", - "0x33400533000533001b01b33400504500506701b01b33400501b00701b301", - "0x33400501b00701b01b33c00501b19301b30000533400533500504701b01b", - "0x533000533001b01b33400504500506701b01b33400532b00522b01b01b", - "0x1b33201b30000533400504400504701b01b33400504700506701b01b334", - "0x502001b07f00533400501b22e01b2ff00533400501b32b01b01b334005", - "0x533400501b33501b08700533400507f2ff00732801b07f00533400507f", - "0x4701b2fb0053340052fc00502f01b2fc00533400508733d00700901b33d", - "0x33400500700503301b04300533400504300502a01b300005334005300005", - "0x501b00701b2fb0070433000480052fb0053340052fb0050b501b007005", - "0x4700506701b01b33400504500506701b01b33400502400523101b01b334", - "0x502001b2f900533400501b22901b2fa00533400501b32b01b01b334005", - "0x533400501b33501b2f80053340052f92fa00732801b2f90053340052f9", - "0x4701b2f50053340052f600502f01b2f60053340052f82f700700901b2f7", - "0x33400500700503301b04100533400504100502a01b042005334005042005", - "0x501b06901b2f50070410420480052f50053340052f50050b501b007005", - "0x1b23901b04300533400501b23901b04500533400501b2ed01b047005334", - "0x23901b02300533400501b23901b02700533400501b06c01b041005334005", - "0x700501b01b33400501b01b01b01b33400501b23c01b02000533400501b", - "0x502401b01b33400501b00701b32e32f00733e33033200733400700501b", - "0x1b33200533400533200504701b01b33400501b04801b32c005334005024", - "0x504501b01b33400501b00701b32800533f02532b00733400732c005046", - "0x533400500900504301b00900533400533500504401b335005334005025", - "0x1b19301b03300533400502f00504101b02a00533400532b00504201b02f", - "0xb500504001b0b500533400501b02701b01b33400501b00701b01b340005", - "0x3300533400507c00504101b02a00533400532800504201b07c005334005", - "0x723d01b01b33400501b00701b32200534107d00533400703300502301b", - "0x1b03900534232119200733400707d33200705401b07d00533400507d020", - "0x733400702a00504601b19200533400519200504701b01b33400501b007", - "0x1b04200533400503a00504501b01b33400501b00701b03800534303a03b", - "0x3b00504201b20900533400504200504401b04200533400504204100723d", - "0x501b00701b21800534421620d00733400703b00504601b03b005334005", - "0x5501b21e00533400520d00504201b21a00533400521600505601b01b334", - "0x2701b01b33400501b00701b01b34500501b19301b22400533400521a005", - "0x533400521800504201b22900533400522800505301b22800533400501b", - "0x22b00534622a00533400722400525301b22400533400522900505501b21e", - "0x533400501b32b01b22e00533400522a00504501b01b33400501b00701b", - "0x504701b04e00533400522e00504401b05100533400521e00521801b231", - "0x533400505100525d01b33000533400533000502a01b192005334005192", - "0x4725f01b04e00533400504e00502001b23100533400523100522401b051", - "0x34723c00533400723900503501b23905204f02433400504e231051330192", - "0x528401b05605400733400523c00505e01b01b33400501b00701b23d005", - "0x33400505400502401b01b33400501b00701b055005348193005334007056", - "0x504601b19300533400519302700706d01b01b33400501b04801b053005", - "0x525d00504501b01b33400501b00701b25f00534925d253007334007053", - "0x1b28400533400505e00504301b05e00533400503500504401b035005334", - "0x34a00501b19301b06000533400528400504101b061005334005253005042", - "0x33400500600504001b00600533400501b02701b01b33400501b00701b01b", - "0x2301b06000533400506700504101b06100533400525f00504201b067005", - "0x4002300723d01b01b33400501b00701b06900534b040005334007060005", - "0x1b00701b06d00534c06c2ed00733400704004f00705401b040005334005", - "0x31606f00733400706100504601b2ed0053340052ed00504701b01b334005", - "0x723d01b04400533400531600504501b01b33400501b00701b31500534d", - "0x33400506f00504201b03600533400504400504401b044005334005044043", - "0x1b33400501b00701b07100534e07202600733400706f00504601b06f005", - "0x7700505501b31100533400502600504201b07700533400507200505601b", - "0x501b02701b01b33400501b00701b01b34f00501b19301b079005334005", - "0x1b31100533400507100504201b30f00533400507500505301b075005334", - "0x701b30d00535030e00533400707900525301b07900533400530f005055", - "0x32b01b30c00533400530e00504501b01b33400501b33201b01b33400501b", - "0x533400530c00504401b30a00533400531100521801b30b00533400501b", - "0x525d01b05200533400505200502a01b2ed0053340052ed00504701b306", - "0x533400530600502001b30b00533400530b00522401b30a00533400530a", - "0x730400503501b30430508502433400530630b30a0522ed04725f01b306", - "0x30200733400508300505e01b01b33400501b00701b303005351083005334", - "0x2401b01b33400501b00701b30000535230100533400708100528401b081", - "0x701b33d00535308707f0073340072ff00504601b2ff005334005302005", - "0x21601b01b33400508700532f01b01b33400507f00533001b01b33400501b", - "0x1b01b33400504700506f01b01b33400506c00506101b01b334005193005", - "0x1b33400503600532e01b01b33400530100521601b01b334005045005316", - "0x533400501b32b01b01b33400532100506101b01b33400520900532e01b", - "0x2fc00732801b2fb0053340052fb00502001b2fb00533400501b02501b2fc", - "0x53340052fa2f900700901b2f900533400501b33501b2fa0053340052fb", - "0x502a01b08500533400508500504701b2f70053340052f800502f01b2f8", - "0x53340052f70050b501b00700533400500700503301b305005334005305", - "0x1b33400533d00533001b01b33400501b00701b2f70073050850480052f7", - "0x30508502419201b2f60053340052f600532201b2f600533400501b07c01b", - "0x19300520d01b01b33400501b00701b2f22f30073542f42f50073340072f6", - "0x7e0053340052ee00521801b01b3340052f100521601b2ee2f1007334005", - "0x8b02433400707e2093210072f404706001b2f50053340052f500504701b", - "0x733400530100520d01b01b33400501b00701b0842eb08f0243552ec08d", - "0x502a01b2e70053340052e900521801b01b3340052ea00521601b2e92ea", - "0x3606c08d08b04706001b2ec0053340052ec00525d01b08b00533400508b", - "0x32b01b01b33400501b00701b2e42e52e60243560460480970243340072e7", - "0x533400509700502a01b2f50053340052f500504701b2e300533400501b", - "0x731501b2ec0053340052ec00525d01b2e30053340052e300522401b097", - "0x972f504802601b04600533400504604500703601b048005334005048047", - "0x1b2de00535709e0053340072df00507201b2df2e02e20243340052ec2e3", - "0x3340050a100522b01b0a10a500733400509e00507101b01b33400501b007", - "0x522401b2e00053340052e000502a01b2e20053340052e200504701b01b", - "0x460a52e02e204802601b04600533400504600525d01b0a50053340050a5", - "0x1b00701b2d90053580ab0053340070a900507201b0a92db2dd024334005", - "0x1b2d62d70073340050ab00507101b0ae00533400501b32b01b01b334005", - "0x52d500521601b2d42d50073340052d700520d01b01b3340052d600522b", - "0x1b2d20053340052d300531101b2d32d40073340052d400507701b01b334", - "0xb40ae00732801b0b40053340050b400502001b0b40053340052d2005079", - "0x2dd0053340052dd00504701b2d00053340052d400521801b2d1005334005", - "0x2d100522401b2d00053340052d000525d01b2db0053340052db00502a01b", - "0x507201b3590492cf0243340052d12d02db2dd04807501b2d1005334005", - "0x33400535a00507101b01b33400501b00701b35c00535b35a005334007359", - "0x1b0bb0bc0073340050d100520d01b01b33400535d00522b01b35d0d1007", - "0x3340050be00521a01b0be0053340050bb00521801b01b3340050bc005216", - "0x2a01b2cf0053340052cf00504701b0c40053340050c000521e01b0c0005", - "0x3340050c40050b501b04800533400504800503301b049005334005049005", - "0x33400535c00502f01b01b33400501b00701b0c40480492cf0480050c4005", - "0x3301b04900533400504900502a01b2cf0053340052cf00504701b2ce005", - "0x2ce0480492cf0480052ce0053340052ce0050b501b048005334005048005", - "0x535e00530e01b2da35e0073340052d900530f01b01b33400501b00701b", - "0x3301b2c80053340052db00502a01b35f0053340052dd00504701b01b334", - "0x1b36000501b19301b2c70053340052da00522401b0c9005334005048005", - "0x73340052de00530f01b01b33400504600523101b01b33400501b00701b", - "0x502a01b35f0053340052e200504701b01b3340050ca00530e01b3610ca", - "0x533400536100522401b0c900533400504800503301b2c80053340052e0", - "0x1b3340052ec00523101b01b33400501b00701b01b36000501b19301b2c7", - "0x3340052f500504701b01b33400504500531601b01b33400504700506f01b", - "0x22401b0c90053340052e500503301b2c80053340052e600502a01b35f005", - "0x6101b01b33400501b00701b01b36000501b19301b2c70053340052e4005", - "0x1b01b33400504500531601b01b33400504700506f01b01b33400506c005", - "0x53340052f500504701b01b33400503600532e01b01b334005301005216", - "0x522401b0c90053340052eb00503301b2c800533400508f00502a01b35f", - "0x53340052c72c500700901b2c500533400501b33501b2c7005334005084", - "0x502a01b35f00533400535f00504701b2be0053340052c400502f01b2c4", - "0x53340052be0050b501b0c90053340050c900503301b2c80053340052c8", - "0x1b33400519300521601b01b33400501b00701b2be0c92c835f0480052be", - "0x33400504500531601b01b33400504700506f01b01b33400506c00506101b", - "0x520900532e01b01b33400503600532e01b01b33400530100521601b01b", - "0x501b22901b0cf00533400501b32b01b01b33400532100506101b01b334", - "0x2b90053340052bb0cf00732801b2bb0053340052bb00502001b2bb005334", - "0x2bc00502f01b2bc0053340052b90c700700901b0c700533400501b33501b", - "0x2f20053340052f200502a01b2f30053340052f300504701b0d0005334005", - "0x2f22f30480050d00053340050d00050b501b00700533400500700503301b", - "0x519300521601b01b33400530000522b01b01b33400501b00701b0d0007", - "0x4500531601b01b33400504700506f01b01b33400506c00506101b01b334", - "0x532e01b01b33400503600532e01b01b33400530200523101b01b334005", - "0x1b2c300533400508500504701b01b33400532100506101b01b334005209", - "0x1b01b33400501b00701b01b36200501b19301b2b600533400530500502a", - "0x1b33400504700506f01b01b33400506c00506101b01b334005193005216", - "0x33400503600532e01b01b33400532100506101b01b33400504500531601b", - "0x8500504701b2b500533400530300502f01b01b33400520900532e01b01b", - "0x700533400500700503301b30500533400530500502a01b085005334005", - "0x1b33400501b00701b2b50073050850480052b50053340052b50050b501b", - "0x1b33400503600532e01b01b33400530d00522b01b01b33400501b33201b", - "0x33400506c00506101b01b33400519300521601b01b33400520900532e01b", - "0x532100506101b01b33400504500531601b01b33400504700506f01b01b", - "0x502a01b2c30053340052ed00504701b01b33400531100533001b01b334", - "0x1b0d400533400501b30d01b2b400533400501b32b01b2b6005334005052", - "0x501b33501b2c20053340050d42b400732801b0d40053340050d4005020", - "0x2c00053340052bf00502f01b2bf0053340052c20d600700901b0d6005334", - "0x700503301b2b60053340052b600502a01b2c30053340052c300504701b", - "0x701b2c00072b62c30480052c00053340052c00050b501b007005334005", - "0x506701b01b33400531500533001b01b33400501b33201b01b33400501b", - "0x6101b01b33400519300521601b01b33400520900532e01b01b334005043", - "0x1b01b33400504500531601b01b33400504700506f01b01b33400506c005", - "0x2c100533400501b30c01b0d800533400501b32b01b01b334005321005061", - "0x1b33501b2b30053340052c10d800732801b2c10053340052c100502001b", - "0x53340052ad00502f01b2ad0053340052b32ab00700901b2ab005334005", - "0x503301b05200533400505200502a01b2ed0053340052ed00504701b2a8", - "0x1b2a80070522ed0480052a80053340052a80050b501b007005334005007", - "0x1b01b33400520900532e01b01b33400504300506701b01b33400501b007", - "0x1b33400504500531601b01b33400504700506f01b01b334005193005216", - "0x33400506d00504701b01b33400506100533001b01b33400532100506101b", - "0x33400506900522b01b01b33400501b00701b01b36300501b19301b2a7005", - "0x519300521601b01b33400520900532e01b01b33400504300506701b01b", - "0x32100506101b01b33400504500531601b01b33400504700506f01b01b334", - "0x504701b01b33400502300506701b01b33400506100533001b01b334005", - "0x30b01b0de00533400501b32b01b01b33400501b33201b2a700533400504f", - "0x3340052a50de00732801b2a50053340052a500502001b2a500533400501b", - "0x2f01b29f0053340052a32a200700901b2a200533400501b33501b2a3005", - "0x33400505200502a01b2a70053340052a700504701b0e100533400529f005", - "0x480050e10053340050e10050b501b00700533400500700503301b052005", - "0x506701b01b33400505500522b01b01b33400501b00701b0e10070522a7", - "0x6f01b01b33400505400523101b01b33400520900532e01b01b334005043", - "0x1b01b33400532100506101b01b33400504500531601b01b334005047005", - "0x533400504f00504701b01b33400502700530a01b01b334005023005067", - "0x33400501b00701b01b36400501b19301b29b00533400505200502a01b29e", - "0x502700530a01b01b33400520900532e01b01b33400504300506701b01b", - "0x32100506101b01b33400504500531601b01b33400504700506f01b01b334", - "0x4701b29a00533400523d00502f01b01b33400502300506701b01b334005", - "0x33400500700503301b05200533400505200502a01b04f00533400504f005", - "0x501b00701b29a00705204f04800529a00533400529a0050b501b007005", - "0x504300506701b01b33400522b00522b01b01b33400501b33201b01b334", - "0x2300506701b01b33400502700530a01b01b33400520900532e01b01b334", - "0x506101b01b33400504500531601b01b33400504700506f01b01b334005", - "0x1b29e00533400519200504701b01b33400521e00533001b01b334005321", - "0x533400501b00601b29900533400501b32b01b29b00533400533000502a", - "0x33501b29700533400529829900732801b29800533400529800502001b298", - "0x33400529300502f01b29300533400529729600700901b29600533400501b", - "0x3301b29b00533400529b00502a01b29e00533400529e00504701b0eb005", - "0xeb00729b29e0480050eb0053340050eb0050b501b007005334005007005", - "0x1b01b33400503800533001b01b33400501b33201b01b33400501b00701b", - "0x1b33400502700530a01b01b33400504100506701b01b334005043005067", - "0x33400504500531601b01b33400504700506f01b01b33400502300506701b", - "0x33400501b22a01b0ed00533400501b32b01b01b33400532100506101b01b", - "0x1b2910053340052920ed00732801b29200533400529200502001b292005", - "0x50ef00502f01b0ef00533400529129000700901b29000533400501b335", - "0x1b33000533400533000502a01b19200533400519200504701b0f1005334", - "0x73301920480050f10053340050f10050b501b007005334005007005033", - "0x33400504100506701b01b33400504300506701b01b33400501b00701b0f1", - "0x504700506f01b01b33400502300506701b01b33400502700530a01b01b", - "0x3900504701b01b33400502a00533001b01b33400504500531601b01b334", - "0x32200522b01b01b33400501b00701b01b36500501b19301b0f0005334005", - "0x530a01b01b33400504100506701b01b33400504300506701b01b334005", - "0x31601b01b33400504700506f01b01b33400502300506701b01b334005027", - "0x1b01b33400502000506701b01b33400502a00533001b01b334005045005", - "0xee00533400501b32b01b01b33400501b33201b0f0005334005332005047", - "0x28f0ee00732801b28f00533400528f00502001b28f00533400501b22e01b", - "0xf900533400528e0f700700901b0f700533400501b33501b28e005334005", - "0x33000502a01b0f00053340050f000504701b0f80053340050f900502f01b", - "0xf80053340050f80050b501b00700533400500700503301b330005334005", - "0x1b01b33400504300506701b01b33400501b00701b0f80073300f0048005", - "0x1b33400502300506701b01b33400502700530a01b01b334005041005067", - "0x33400502400523101b01b33400504500531601b01b33400504700506f01b", - "0x33400501b22901b0f600533400501b32b01b01b33400502000506701b01b", - "0x1b28c00533400528d0f600732801b28d00533400528d00502001b28d005", - "0x510000502f01b10000533400528c0ff00700901b0ff00533400501b335", - "0x1b32e00533400532e00502a01b32f00533400532f00504701b0fe005334", - "0x732e32f0480050fe0053340050fe0050b501b007005334005007005033", - "0x4600736604704800733400700501b00700501b01b33400501b01b01b0fe", - "0x33400501b04801b04400533400502400502401b01b33400501b00701b045", - "0x536704204300733400704400504601b04800533400504800504701b01b", - "0x519300504401b19300533400504200504501b01b33400501b00701b041", - "0x1b02300533400504300504201b04000533400502700504301b027005334", - "0x1b01b33400501b00701b01b36800501b19301b07d005334005040005041", - "0x33400504100504201b33200533400502000504001b02000533400501b027", - "0x536933000533400707d00502301b07d00533400533200504101b023005", - "0x32b00536a32c32e00733400733004800730601b01b33400501b00701b32f", - "0x33400702300504601b32e00533400532e00504701b01b33400501b00701b", - "0x33001b01b33400501b33201b01b33400501b00701b33500536b328025007", - "0x1b01b33400532c00508501b01b33400532800532f01b01b334005025005", - "0x533400502f00502001b02f00533400501b02501b00900533400501b32b", - "0x700901b03300533400501b33501b02a00533400502f00900732801b02f", - "0x33400532e00504701b07c0053340050b500502f01b0b500533400502a033", - "0xb501b00700533400500700503301b04700533400504700502a01b32e005", - "0x33201b01b33400501b00701b07c00704732e04800507c00533400507c005", - "0x32201b32200533400501b07c01b01b33400533500533001b01b33400501b", - "0x3900736c32119200733400732204732e02419201b322005334005322005", - "0x33400519200504701b03a00533400501b30501b01b33400501b00701b03b", - "0x30401b00700533400500700503301b32100533400532100502a01b192005", - "0x20d20903804833400532c03a00732119204708301b32c00533400532c005", - "0x30201b01b33400501b00701b21a00536d21800533400721600530301b216", - "0x22400733400521e00520d01b21e00533400501b32b01b01b334005218005", - "0x22900521a01b22900533400522800521801b01b33400522400521601b228", - "0x3800533400503800504701b22b00533400522a00521e01b22a005334005", - "0x22b0050b501b20d00533400520d00503301b20900533400520900502a01b", - "0x21a00502f01b01b33400501b00701b22b20d20903804800522b005334005", - "0x20900533400520900502a01b03800533400503800504701b22e005334005", - "0x20903804800522e00533400522e0050b501b20d00533400520d00503301b", - "0x33400501b32b01b01b33400532c00508501b01b33400501b00701b22e20d", - "0x732801b05100533400505100502001b05100533400501b22901b231005", - "0x33400504e04f00700901b04f00533400501b33501b04e005334005051231", - "0x2a01b03900533400503900504701b23900533400505200502f01b052005", - "0x3340052390050b501b00700533400500700503301b03b00533400503b005", - "0x33400502300533001b01b33400501b00701b23900703b039048005239005", - "0x33400501b00701b01b36e00501b19301b23c00533400532b00504701b01b", - "0x504800504701b01b33400502300533001b01b33400532f00522b01b01b", - "0x501b22e01b23d00533400501b32b01b01b33400501b33201b23c005334", - "0x5600533400505423d00732801b05400533400505400502001b054005334", - "0x5300502f01b05300533400505605500700901b05500533400501b33501b", - "0x4700533400504700502a01b23c00533400523c00504701b253005334005", - "0x4723c0480052530053340052530050b501b00700533400500700503301b", - "0x33400501b32b01b01b33400502400523101b01b33400501b00701b253007", - "0x732801b25f00533400525f00502001b25f00533400501b22901b25d005", - "0x33400503505e00700901b05e00533400501b33501b03500533400525f25d", - "0x2a01b04600533400504600504701b06100533400528400502f01b284005", - "0x3340050610050b501b00700533400500700503301b045005334005045005", - "0x33400501b23901b04700533400501b06c01b061007045046048005061005", - "0x700501b00700501b01b33400501b01b01b01b33400501b23c01b045005", - "0x33400502400502401b01b33400501b00701b04104200736f043044007334", - "0x19300504601b04400533400504400504701b01b33400501b04801b193005", - "0x33400504000505601b01b33400501b00701b023005370040027007334007", - "0x19301b33200533400507d00505501b02000533400502700504201b07d005", - "0x505301b33000533400501b02701b01b33400501b00701b01b37100501b", - "0x533400532f00505501b02000533400502300504201b32f005334005330", - "0x4501b01b33400501b00701b32c00537232e00533400733200525301b332", - "0x504600504401b04600533400504604500723d01b04600533400532e005", - "0x501b00701b33500537332802500733400732b04400708101b32b005334", - "0x37402f00900733400702000504601b02500533400502500504701b01b334", - "0x900504201b03300533400502f00505601b01b33400501b00701b02a005", - "0x701b01b37500501b19301b07c00533400503300505501b0b5005334005", - "0x1b19200533400532200505301b32200533400501b02701b01b33400501b", - "0x707c00525301b07c00533400519200505501b0b500533400502a005042", - "0x3b00533400532100504501b01b33400501b00701b039005376321005334", - "0x503b00504401b0380053340050b500521801b03a00533400501b32b01b", - "0x1b04300533400504300502a01b02500533400502500504701b209005334", - "0x520900502001b03a00533400503a00522401b03800533400503800525d", - "0x503501b21821620d02433400520903a03804302504725f01b209005334", - "0x33400521a00505e01b01b33400501b00701b21e00537721a005334007218", - "0x1b33400501b00701b22900537804800533400722800528401b228224007", - "0x504804700706d01b01b33400501b04801b22a00533400522400502401b", - "0x33400501b00701b23100537922e22b00733400722a00504601b048005334", - "0x505501b04e00533400522b00504201b05100533400522e00505601b01b", - "0x1b02701b01b33400501b00701b01b37a00501b19301b04f005334005051", - "0x4e00533400523100504201b23900533400505200505301b052005334005", - "0x1b23d00537b23c00533400704f00525301b04f00533400523900505501b", - "0x1b05400533400523c00504501b01b33400501b33201b01b33400501b007", - "0x33400505400504401b05500533400504e00521801b05600533400501b32b", - "0x25d01b21600533400521600502a01b20d00533400520d00504701b053005", - "0x33400505300502001b05600533400505600522401b055005334005055005", - "0x25f00503501b25f25d25302433400505305605521620d04725f01b053005", - "0x733400503500505e01b01b33400501b00701b05e00537c035005334007", - "0x1b01b33400501b00701b00600537d06000533400706100528401b061284", - "0x1b06c00537e2ed06900733400706700504601b067005334005284005024", - "0x1b01b3340052ed00532f01b01b33400506900533001b01b33400501b007", - "0x1b33400506000521601b01b33400532800530101b01b334005048005216", - "0x33400506f00502001b06f00533400501b02501b06d00533400501b32b01b", - "0x901b31500533400501b33501b31600533400506f06d00732801b06f005", - "0x525300504701b02600533400503600502f01b036005334005316315007", - "0x1b00700533400500700503301b25d00533400525d00502a01b253005334", - "0x1b01b33400501b00701b02600725d2530480050260053340050260050b5", - "0x533400507200532201b07200533400501b07c01b01b33400506c005330", - "0x501b00701b07931100737f07707100733400707225d25302419201b072", - "0x21601b30e30f00733400506000520d01b07500533400501b30001b01b334", - "0x33400530d00530101b30c30d0073340053280052ff01b01b33400530f005", - "0x504701b01b33400530b00521601b30a30b00733400504800520d01b01b", - "0x533400500700503301b07700533400507700502a01b071005334005071", - "0x507f01b30e00533400530e00504201b07500533400507500507f01b007", - "0x7500707707104508701b30a00533400530a00504201b30c00533400530c", - "0x538008300533400730400533d01b30430508530604833400530a30c30e", - "0x533400501b32b01b01b3340050830052fc01b01b33400501b00701b303", - "0x521801b01b33400508100521601b30108100733400530200520d01b302", - "0x53340052ff00521e01b2ff00533400530000521a01b300005334005301", - "0x503301b08500533400508500502a01b30600533400530600504701b07f", - "0x1b07f30508530604800507f00533400507f0050b501b305005334005305", - "0x533400530600504701b08700533400530300502f01b01b33400501b007", - "0x50b501b30500533400530500503301b08500533400508500502a01b306", - "0x521601b01b33400501b00701b087305085306048005087005334005087", - "0x32b01b01b33400506000521601b01b33400532800530101b01b334005048", - "0x2fc0053340052fc00502001b2fc00533400501b22901b33d00533400501b", - "0x2fa00700901b2fa00533400501b33501b2fb0053340052fc33d00732801b", - "0x533400531100504701b2f80053340052f900502f01b2f90053340052fb", - "0x50b501b00700533400500700503301b07900533400507900502a01b311", - "0x522b01b01b33400501b00701b2f80070793110480052f80053340052f8", - "0x23101b01b33400532800530101b01b33400504800521601b01b334005006", - "0x533400525d00502a01b2f700533400525300504701b01b334005284005", - "0x1b33400504800521601b01b33400501b00701b01b38100501b19301b2f6", - "0x525300504701b2f500533400505e00502f01b01b33400532800530101b", - "0x1b00700533400500700503301b25d00533400525d00502a01b253005334", - "0x1b01b33400501b00701b2f500725d2530480052f50053340052f50050b5", - "0x1b01b33400504800521601b01b33400523d00522b01b01b33400501b332", - "0x533400520d00504701b01b33400504e00533001b01b334005328005301", - "0x501b00601b2f400533400501b32b01b2f600533400521600502a01b2f7", - "0x2f20053340052f32f400732801b2f30053340052f300502001b2f3005334", - "0x2ee00502f01b2ee0053340052f22f100700901b2f100533400501b33501b", - "0x2f60053340052f600502a01b2f70053340052f700504701b07e005334005", - "0x2f62f704800507e00533400507e0050b501b00700533400500700503301b", - "0x522400523101b01b33400522900522b01b01b33400501b00701b07e007", - "0x20d00504701b01b33400504700530a01b01b33400532800530101b01b334", - "0x701b01b38200501b19301b08d00533400521600502a01b08b005334005", - "0x2f01b01b33400532800530101b01b33400504700530a01b01b33400501b", - "0x33400521600502a01b20d00533400520d00504701b2ec00533400521e005", - "0x480052ec0053340052ec0050b501b00700533400500700503301b216005", - "0x3900522b01b01b33400501b33201b01b33400501b00701b2ec00721620d", - "0x533001b01b33400532800530101b01b33400504700530a01b01b334005", - "0x8d00533400504300502a01b08b00533400502500504701b01b3340050b5", - "0x3340052eb00502001b2eb00533400501b22a01b08f00533400501b32b01b", - "0x901b2ea00533400501b33501b0840053340052eb08f00732801b2eb005", - "0x508b00504701b2e70053340052e900502f01b2e90053340050842ea007", - "0x1b00700533400500700503301b08d00533400508d00502a01b08b005334", - "0x1b01b33400501b00701b2e700708d08b0480052e70053340052e70050b5", - "0x533400533500504701b01b33400502000533001b01b33400504700530a", - "0x1b33400532c00522b01b01b33400501b00701b01b38300501b19301b097", - "0x33400504500506701b01b33400502000533001b01b33400504700530a01b", - "0x33400501b32b01b01b33400501b33201b09700533400504400504701b01b", - "0x732801b2e50053340052e500502001b2e500533400501b22e01b2e6005", - "0x3340052e42e300700901b2e300533400501b33501b2e40053340052e52e6", - "0x2a01b09700533400509700504701b2e00053340052e200502f01b2e2005", - "0x3340052e00050b501b00700533400500700503301b043005334005043005", - "0x33400504700530a01b01b33400501b00701b2e00070430970480052e0005", - "0x33400501b32b01b01b33400504500506701b01b33400502400523101b01b", - "0x732801b09e00533400509e00502001b09e00533400501b22901b2df005", - "0x3340052de0a500700901b0a500533400501b33501b2de00533400509e2df", - "0x2a01b04200533400504200504701b2dd0053340050a100502f01b0a1005", - "0x3340052dd0050b501b00700533400500700503301b041005334005041005", - "0x700501b00700501b01b33400501b01b01b2dd0070410420480052dd005", - "0x33400502400502401b01b33400501b00701b045046007384047048007334", - "0x4400504601b04800533400504800504701b01b33400501b04801b044005", - "0x33400504200504501b01b33400501b00701b041005385042043007334007", - "0x4201b04000533400502700504301b02700533400519300504401b193005", - "0x1b38600501b19301b07d00533400504000504101b023005334005043005", - "0x533400502000504001b02000533400501b02701b01b33400501b00701b", - "0x502301b07d00533400533200504101b02300533400504100504201b332", - "0x733004800705401b01b33400501b00701b32f00538733000533400707d", - "0x533400532e00504701b01b33400501b00701b32b00538832c32e007334", - "0x1b01b33400501b00701b33500538932802500733400702300504601b32e", - "0x502f00504301b02f00533400500900504401b009005334005328005045", - "0x1b0b500533400502a00504101b03300533400502500504201b02a005334", - "0x4001b07c00533400501b02701b01b33400501b00701b01b38a00501b193", - "0x33400532200504101b03300533400533500504201b32200533400507c005", - "0x1b01b33400501b00701b32100538b1920053340070b500502301b0b5005", - "0x4701b01b33400501b00701b03a00538c03b03900733400719232e007306", - "0x701b20d00538d20903800733400703300504601b039005334005039005", - "0x532f01b01b33400503800533001b01b33400501b33201b01b33400501b", - "0x32b01b01b33400532c00506101b01b33400503b00508501b01b334005209", - "0x21800533400521800502001b21800533400501b02501b21600533400501b", - "0x21e00700901b21e00533400501b33501b21a00533400521821600732801b", - "0x533400503900504701b22800533400522400502f01b22400533400521a", - "0x50b501b00700533400500700503301b04700533400504700502a01b039", - "0x533001b01b33400501b00701b228007047039048005228005334005228", - "0x1b22900533400522900532201b22900533400501b07c01b01b33400520d", - "0x1b33400501b00701b23122e00738e22b22a007334007229047039024192", - "0x4f04e05102433400732c00722b0242fb01b22a00533400522a00504701b", - "0x1b23d00533400504f0052fa01b01b33400501b00701b23c23905202438f", - "0x5423d0072f901b23d00533400523d00502001b05400533400503b0052fa", - "0x5100533400505100502a01b05600533400505600502001b056005334005", - "0x701b05500539001b3340070560052f801b04e00533400504e00503301b", - "0x520d01b05300533400501b32b01b01b33400501b33201b01b33400501b", - "0x533400525d00521801b01b33400525300521601b25d253007334005053", - "0x504701b05e00533400503500521e01b03500533400525f00521a01b25f", - "0x533400504e00503301b05100533400505100502a01b22a00533400522a", - "0x33400501b00701b05e04e05122a04800505e00533400505e0050b501b04e", - "0x33400501b2f601b28400533400501b32b01b01b3340050550052f701b01b", - "0x1b06000533400506128400732801b06100533400506100502001b061005", - "0x506000522401b06700533400504e00503301b00600533400505100502a", - "0x503b00508501b01b33400501b00701b01b39100501b19301b069005334", - "0x22401b06700533400523900503301b00600533400505200502a01b01b334", - "0x1b2ed00533400501b33501b01b33400501b33201b06900533400523c005", - "0x22a00504701b06d00533400506c00502f01b06c0053340050692ed007009", - "0x6700533400506700503301b00600533400500600502a01b22a005334005", - "0x1b33400501b00701b06d06700622a04800506d00533400506d0050b501b", - "0x1b33400532c00506101b01b33400503b00508501b01b33400501b33201b", - "0x33400531600502001b31600533400501b22901b06f00533400501b32b01b", - "0x901b03600533400501b33501b31500533400531606f00732801b316005", - "0x522e00504701b07200533400502600502f01b026005334005315036007", - "0x1b00700533400500700503301b23100533400523100502a01b22e005334", - "0x1b01b33400501b00701b07200723122e0480050720053340050720050b5", - "0x533400503a00504701b01b33400532c00506101b01b334005033005330", - "0x1b33400532100522b01b01b33400501b00701b01b39200501b19301b071", - "0x33400532e00504701b01b33400532c00506101b01b33400503300533001b", - "0x33400501b22a01b07700533400501b32b01b01b33400501b33201b071005", - "0x1b07900533400531107700732801b31100533400531100502001b311005", - "0x530f00502f01b30f00533400507907500700901b07500533400501b335", - "0x1b04700533400504700502a01b07100533400507100504701b30e005334", - "0x704707104800530e00533400530e0050b501b007005334005007005033", - "0x33400532b00504701b01b33400502300533001b01b33400501b00701b30e", - "0x33400532f00522b01b01b33400501b00701b01b39300501b19301b30d005", - "0x501b33201b30d00533400504800504701b01b33400502300533001b01b", - "0x30b00502001b30b00533400501b22e01b30c00533400501b32b01b01b334", - "0x30600533400501b33501b30a00533400530b30c00732801b30b005334005", - "0x504701b30500533400508500502f01b08500533400530a30600700901b", - "0x533400500700503301b04700533400504700502a01b30d00533400530d", - "0x33400501b00701b30500704730d0480053050053340053050050b501b007", - "0x33400501b22901b30400533400501b32b01b01b33400502400523101b01b", - "0x1b30300533400508330400732801b08300533400508300502001b083005", - "0x508100502f01b08100533400530330200700901b30200533400501b335", - "0x1b04500533400504500502a01b04600533400504600504701b301005334", - "0x70450460480053010053340053010050b501b007005334005007005033", - "0x4600739404704800733400700501b00700501b01b33400501b01b01b301", - "0x33400501b04801b04400533400502400502401b01b33400501b00701b045", - "0x539504204300733400704400504601b04800533400504800504701b01b", - "0x504300504201b19300533400504200505601b01b33400501b00701b041", - "0x1b00701b01b39600501b19301b04000533400519300505501b027005334", - "0x4201b07d00533400502300505301b02300533400501b02701b01b334005", - "0x33400704000525301b04000533400507d00505501b027005334005041005", - "0x1b33000533400502000504501b01b33400501b00701b332005397020005", - "0x32f04800708101b32f00533400532f00502001b32f005334005330005044", - "0x33400532e00504701b01b33400501b00701b32b00539832c32e007334007", - "0x1b33400501b00701b33500539932802500733400702700504601b32e005", - "0x1b33400532800532f01b01b33400502500533001b01b33400501b33201b", - "0x533400501b02501b00900533400501b32b01b01b33400532c00530101b", - "0x33501b02a00533400502f00900732801b02f00533400502f00502001b02f", - "0x3340050b500502f01b0b500533400502a03300700901b03300533400501b", - "0x3301b04700533400504700502a01b32e00533400532e00504701b07c005", - "0x7c00704732e04800507c00533400507c0050b501b007005334005007005", - "0x1b01b33400533500533001b01b33400501b33201b01b33400501b00701b", - "0x32204732e02419201b32200533400532200532201b32200533400501b07c", - "0x519200504701b01b33400501b00701b03b03900739a321192007334007", - "0x21821620d02439b20903803a02433400732c0073210242f501b192005334", - "0x533400520900502001b21a00533400501b32b01b01b33400501b00701b", - "0x1b22822400733400521e00520d01b21e00533400520921a00732801b209", - "0x33400522900521a01b22900533400522800521801b01b334005224005216", - "0x2a01b19200533400519200504701b22b00533400522a00521e01b22a005", - "0x33400522b0050b501b03800533400503800503301b03a00533400503a005", - "0x533400501b33501b01b33400501b00701b22b03803a19204800522b005", - "0x4701b05100533400523100502f01b23100533400521822e00700901b22e", - "0x33400521600503301b20d00533400520d00502a01b192005334005192005", - "0x501b00701b05121620d1920480050510053340050510050b501b216005", - "0x501b22901b04e00533400501b32b01b01b33400532c00530101b01b334", - "0x5200533400504f04e00732801b04f00533400504f00502001b04f005334", - "0x23c00502f01b23c00533400505223900700901b23900533400501b33501b", - "0x3b00533400503b00502a01b03900533400503900504701b23d005334005", - "0x3b03904800523d00533400523d0050b501b00700533400500700503301b", - "0x532b00504701b01b33400502700533001b01b33400501b00701b23d007", - "0x533200522b01b01b33400501b00701b01b39c00501b19301b054005334", - "0x1b33201b05400533400504800504701b01b33400502700533001b01b334", - "0x502001b05500533400501b22e01b05600533400501b32b01b01b334005", - "0x533400501b33501b05300533400505505600732801b055005334005055", - "0x4701b25f00533400525d00502f01b25d00533400505325300700901b253", - "0x33400500700503301b04700533400504700502a01b054005334005054005", - "0x501b00701b25f00704705404800525f00533400525f0050b501b007005", - "0x501b22901b03500533400501b32b01b01b33400502400523101b01b334", - "0x28400533400505e03500732801b05e00533400505e00502001b05e005334", - "0x6000502f01b06000533400528406100700901b06100533400501b33501b", - "0x4500533400504500502a01b04600533400504600504701b006005334005", - "0x450460480050060053340050060050b501b00700533400500700503301b", - "0x33400501b01b01b01b33400501b23c01b04700533400501b2f401b006007", - "0x33400501b00701b04304400739d04504600733400700501b00700501b01b", - "0x72f301b02400533400502400525d01b04600533400504600504701b01b", - "0x1b02700539e0480053340071930052f201b193041042024334005024046", - "0x533400504500502a01b04200533400504200504701b01b33400501b007", - "0x2ee01b0480053340050480470072f101b04100533400504100525d01b045", - "0x539f02000533400707d00507e01b07d023040024334005041045042024", - "0x32f00508d01b32f33000733400502000508b01b01b33400501b00701b332", - "0x533400533000502401b01b33400501b00701b32c0053a032e005334007", - "0x1b01b33400501b00701b3350053a132802500733400732b00504601b32b", - "0x500900502001b02500533400502500504201b009005334005328005045", - "0x33400501b00701b0330053a202a02f00733400702500504601b009005334", - "0x502001b02f00533400502f00504201b0b500533400502a00504501b01b", - "0x1b00701b1920053a332207c00733400702f00504601b0b50053340050b5", - "0x1b07c00533400507c00504201b32100533400532200504501b01b334005", - "0x1b03a0053a403b03900733400707c00504601b321005334005321005020", - "0x1b01b33400503b00532f01b01b33400503900533001b01b33400501b007", - "0x1b33400532e0052ec01b01b3340050b500532e01b01b33400532100532e", - "0x533400501b32b01b01b33400500900532e01b01b33400504800508f01b", - "0x3800732801b20900533400520900502001b20900533400501b02501b038", - "0x533400520d21600700901b21600533400501b33501b20d005334005209", - "0x502a01b04000533400504000504701b21a00533400521800502f01b218", - "0x533400521a0050b501b00700533400500700503301b023005334005023", - "0x1b33400503a00533001b01b33400501b00701b21a00702304004800521a", - "0x2304002419201b21e00533400521e00532201b21e00533400501b07c01b", - "0x900504401b01b33400501b00701b22a2290073a522822400733400721e", - "0x23100533400532100504401b22e0053340050b500504401b22b005334005", - "0x4e00508401b04f04e0073340050510052eb01b05100533400501b30501b", - "0x1b22800533400522800502a01b22400533400522400504701b01b334005", - "0x532e0052e901b0480053340050480052ea01b007005334005007005033", - "0x1b22e00533400522e00502001b22b00533400522b00502001b32e005334", - "0x523122e22b32e04804f0072282240432e701b231005334005231005020", - "0x1b00701b0560053a605400533400723d00509701b23d23c239052048334", - "0x520d01b05500533400501b32b01b01b3340050540052e601b01b334005", - "0x533400525300521801b01b33400505300521601b253053007334005055", - "0x504701b03500533400525f00521e01b25f00533400525d00521a01b25d", - "0x533400523c00503301b23900533400523900502a01b052005334005052", - "0x33400501b00701b03523c2390520480050350053340050350050b501b23c", - "0x502a01b05200533400505200504701b05e00533400505600502f01b01b", - "0x533400505e0050b501b23c00533400523c00503301b239005334005239", - "0x1b33400532100532e01b01b33400501b00701b05e23c23905204800505e", - "0x33400504800508f01b01b33400532e0052ec01b01b3340050b500532e01b", - "0x33400501b22901b28400533400501b32b01b01b33400500900532e01b01b", - "0x1b06000533400506128400732801b06100533400506100502001b061005", - "0x506700502f01b06700533400506000600700901b00600533400501b335", - "0x1b22a00533400522a00502a01b22900533400522900504701b069005334", - "0x722a2290480050690053340050690050b501b007005334005007005033", - "0x33400500900532e01b01b33400519200533001b01b33400501b00701b069", - "0x504800508f01b01b33400532e0052ec01b01b3340050b500532e01b01b", - "0x6c00502001b06c00533400501b30c01b2ed00533400501b32b01b01b334", - "0x6f00533400501b33501b06d00533400506c2ed00732801b06c005334005", - "0x504701b31500533400531600502f01b31600533400506d06f00700901b", - "0x533400500700503301b02300533400502300502a01b040005334005040", - "0x33400501b00701b3150070230400480053150053340053150050b501b007", - "0x504800508f01b01b33400500900532e01b01b33400503300533001b01b", - "0x501b30b01b03600533400501b32b01b01b33400532e0052ec01b01b334", - "0x7200533400502603600732801b02600533400502600502001b026005334", - "0x7700502f01b07700533400507207100700901b07100533400501b33501b", - "0x2300533400502300502a01b04000533400504000504701b311005334005", - "0x230400480053110053340053110050b501b00700533400500700503301b", - "0x532e0052ec01b01b33400533500533001b01b33400501b00701b311007", - "0x501b00601b07900533400501b32b01b01b33400504800508f01b01b334", - "0x30f00533400507507900732801b07500533400507500502001b075005334", - "0x30d00502f01b30d00533400530f30e00700901b30e00533400501b33501b", - "0x2300533400502300502a01b04000533400504000504701b30c005334005", - "0x2304004800530c00533400530c0050b501b00700533400500700503301b", - "0x533000523101b01b33400532c00522b01b01b33400501b00701b30c007", - "0x501b22a01b30b00533400501b32b01b01b33400504800508f01b01b334", - "0x30600533400530a30b00732801b30a00533400530a00502001b30a005334", - "0x30500502f01b30500533400530608500700901b08500533400501b33501b", - "0x2300533400502300502a01b04000533400504000504701b304005334005", - "0x230400480053040053340053040050b501b00700533400500700503301b", - "0x533200502f01b01b33400504800508f01b01b33400501b00701b304007", - "0x1b02300533400502300502a01b04000533400504000504701b083005334", - "0x70230400480050830053340050830050b501b007005334005007005033", - "0x33400504100523101b01b33400502700522b01b01b33400501b00701b083", - "0x33400501b22e01b30300533400501b32b01b01b3340050470052e501b01b", - "0x1b08100533400530230300732801b30200533400530200502001b302005", - "0x530000502f01b30000533400508130100700901b30100533400501b335", - "0x1b04500533400504500502a01b04200533400504200504701b2ff005334", - "0x70450420480052ff0053340052ff0050b501b007005334005007005033", - "0x3340050470052e501b01b33400502400523101b01b33400501b00701b2ff", - "0x508700502001b08700533400501b22901b07f00533400501b32b01b01b", - "0x1b2fc00533400501b33501b33d00533400508707f00732801b087005334", - "0x4400504701b2fa0053340052fb00502f01b2fb00533400533d2fc007009", - "0x700533400500700503301b04300533400504300502a01b044005334005", - "0x533400501b23901b2fa0070430440480052fa0053340052fa0050b501b", - "0x1b33400501b01b01b01b33400501b23c01b04500533400501b23901b047", - "0x1b33400501b00701b0410420073a704304400733400700501b00700501b", - "0x33400504400504701b01b33400501b04801b19300533400502400502401b", - "0x1b33400501b00701b0230053a804002700733400719300504601b044005", - "0x2000504301b02000533400507d00504401b07d00533400504000504501b", - "0x32f00533400533200504101b33000533400502700504201b332005334005", - "0x1b32e00533400501b02701b01b33400501b00701b01b3a900501b19301b", - "0x532c00504101b33000533400502300504201b32c00533400532e005040", - "0x1b33400501b00701b32b0053aa04800533400732f00502301b32f005334", - "0x3ab32802500733400704804400730601b04800533400504804700723d01b", - "0x33000504601b02500533400502500504701b01b33400501b00701b335005", - "0x33400502f00504501b01b33400501b00701b02a0053ac02f009007334007", - "0x1b03300533400504600504401b04600533400504604500723d01b046005", - "0x1b3220053ad07c0b500733400700900504601b009005334005009005042", - "0x53340050b500504201b19200533400507c00505601b01b33400501b007", - "0x33400501b00701b01b3ae00501b19301b03900533400519200505501b321", - "0x32200504201b03a00533400503b00505301b03b00533400501b02701b01b", - "0x3800533400703900525301b03900533400503a00505501b321005334005", - "0x503800504501b01b33400501b33201b01b33400501b00701b2090053af", - "0x4401b21800533400532100521801b21600533400501b32b01b20d005334", - "0x33400504300502a01b02500533400502500504701b21a00533400520d005", - "0x2001b21600533400521600522401b21800533400521800525d01b043005", - "0x22822421e02433400521a21621804302504725f01b21a00533400521a005", - "0x505e01b01b33400501b00701b22a0053b022900533400722800503501b", - "0x1b00701b0510053b123100533400722e00528401b22e22b007334005229", - "0x5204f00733400704e00504601b04e00533400522b00502401b01b334005", - "0x5200532f01b01b33400504f00533001b01b33400501b00701b2390053b2", - "0x508501b01b33400503300532e01b01b33400523100521601b01b334005", - "0x2001b23d00533400501b02501b23c00533400501b32b01b01b334005328", - "0x33400501b33501b05400533400523d23c00732801b23d00533400523d005", - "0x1b05300533400505500502f01b05500533400505405600700901b056005", - "0x500700503301b22400533400522400502a01b21e00533400521e005047", - "0x1b00701b05300722421e0480050530053340050530050b501b007005334", - "0x532201b25300533400501b07c01b01b33400523900533001b01b334005", - "0x5e0350073b325f25d00733400725322421e02419201b253005334005253", - "0x528400521601b06128400733400523100520d01b01b33400501b00701b", - "0x2e401b25d00533400525d00504701b06000533400506100521801b01b334", - "0x1b00701b06d06c2ed0243b406906700602433400706003332800725f047", - "0x1b31600533400506f00521e01b06f00533400506900521a01b01b334005", - "0x506700503301b00600533400500600502a01b25d00533400525d005047", - "0x1b00701b31606700625d0480053160053340053160050b501b067005334", - "0x1b03600533400506d31500700901b31500533400501b33501b01b334005", - "0x52ed00502a01b25d00533400525d00504701b02600533400503600502f", - "0x50260053340050260050b501b06c00533400506c00503301b2ed005334", - "0x32e01b01b33400523100521601b01b33400501b00701b02606c2ed25d048", - "0x1b07200533400501b32b01b01b33400532800508501b01b334005033005", - "0x507107200732801b07100533400507100502001b07100533400501b229", - "0x1b07900533400507731100700901b31100533400501b33501b077005334", - "0x505e00502a01b03500533400503500504701b07500533400507900502f", - "0x50750053340050750050b501b00700533400500700503301b05e005334", - "0x23101b01b33400505100522b01b01b33400501b00701b07500705e035048", - "0x1b01b33400532800508501b01b33400503300532e01b01b33400522b005", - "0x3b500501b19301b30e00533400522400502a01b30f00533400521e005047", - "0x33400503300532e01b01b33400532800508501b01b33400501b00701b01b", - "0x502a01b21e00533400521e00504701b30d00533400522a00502f01b01b", - "0x533400530d0050b501b00700533400500700503301b224005334005224", - "0x1b01b33400501b33201b01b33400501b00701b30d00722421e04800530d", - "0x1b33400503300532e01b01b33400532800508501b01b33400520900522b", - "0x504300502a01b30f00533400502500504701b01b33400532100533001b", - "0x502001b30b00533400501b00601b30c00533400501b32b01b30e005334", - "0x533400501b33501b30a00533400530b30c00732801b30b00533400530b", - "0x4701b30500533400508500502f01b08500533400530a30600700901b306", - "0x33400500700503301b30e00533400530e00502a01b30f00533400530f005", - "0x501b00701b30500730e30f0480053050053340053050050b501b007005", - "0x532800508501b01b33400502a00533001b01b33400501b33201b01b334", - "0x501b22a01b30400533400501b32b01b01b33400504500506701b01b334", - "0x30300533400508330400732801b08300533400508300502001b083005334", - "0x8100502f01b08100533400530330200700901b30200533400501b33501b", - "0x4300533400504300502a01b02500533400502500504701b301005334005", - "0x430250480053010053340053010050b501b00700533400500700503301b", - "0x533000533001b01b33400504500506701b01b33400501b00701b301007", - "0x501b00701b01b3b600501b19301b30000533400533500504701b01b334", - "0x33000533001b01b33400504500506701b01b33400532b00522b01b01b334", - "0x33201b30000533400504400504701b01b33400504700506701b01b334005", - "0x2001b07f00533400501b22e01b2ff00533400501b32b01b01b33400501b", - "0x33400501b33501b08700533400507f2ff00732801b07f00533400507f005", - "0x1b2fb0053340052fc00502f01b2fc00533400508733d00700901b33d005", - "0x500700503301b04300533400504300502a01b300005334005300005047", - "0x1b00701b2fb0070433000480052fb0053340052fb0050b501b007005334", - "0x506701b01b33400504500506701b01b33400502400523101b01b334005", - "0x2001b2f900533400501b22901b2fa00533400501b32b01b01b334005047", - "0x33400501b33501b2f80053340052f92fa00732801b2f90053340052f9005", - "0x1b2f50053340052f600502f01b2f60053340052f82f700700901b2f7005", - "0x500700503301b04100533400504100502a01b042005334005042005047", - "0x1b01b01b2f50070410420480052f50053340052f50050b501b007005334", - "0x1b00701b0450460073b704704800733400700501b00700501b01b334005", - "0x504701b01b33400501b04801b04400533400502400502401b01b334005", - "0x1b00701b0410053b804204300733400704400504601b048005334005048", - "0x1b02700533400519300504401b19300533400504200504501b01b334005", - "0x504000504101b02300533400504300504201b040005334005027005043", - "0x33400501b02701b01b33400501b00701b01b3b900501b19301b07d005334", - "0x4101b02300533400504100504201b33200533400502000504001b020005", - "0x1b00701b32f0053ba33000533400707d00502301b07d005334005332005", - "0x501b00701b32b0053bb32c32e00733400733004800730601b01b334005", - "0x3bc32802500733400702300504601b32e00533400532e00504701b01b334", - "0x2500504201b00900533400532800504501b01b33400501b00701b335005", - "0x2f00733400702500504601b00900533400500900502001b025005334005", - "0x4201b0b500533400502a00504501b01b33400501b00701b0330053bd02a", - "0x33400702f00504601b0b50053340050b500502001b02f00533400502f005", - "0x32100533400532200504501b01b33400501b00701b1920053be32207c007", - "0x7c00504601b32100533400532100502001b07c00533400507c00504201b", - "0x33400503b00504501b01b33400501b00701b03a0053bf03b039007334007", - "0x4601b03800533400503800502001b03900533400503900504201b038005", - "0x501b33201b01b33400501b00701b2160053c020d209007334007039005", - "0x900532e01b01b33400520d00532f01b01b33400520900533001b01b334", - "0x532e01b01b33400532100532e01b01b33400503800532e01b01b334005", - "0x2501b21800533400501b32b01b01b33400532c00508501b01b3340050b5", - "0x33400521a21800732801b21a00533400521a00502001b21a00533400501b", - "0x2f01b22800533400521e22400700901b22400533400501b33501b21e005", - "0x33400504700502a01b32e00533400532e00504701b229005334005228005", - "0x480052290053340052290050b501b00700533400500700503301b047005", - "0x21600533001b01b33400501b33201b01b33400501b00701b22900704732e", - "0x19201b22a00533400522a00532201b22a00533400501b07c01b01b334005", - "0x1b01b33400501b00701b0512310073c122e22b00733400722a04732e024", - "0x532100504401b04f0053340050b500504401b04e005334005009005044", - "0x2eb01b23c00533400501b30501b23900533400503800504401b052005334", - "0x33400522e00502a01b01b33400523d00508401b05423d00733400523c005", - "0x2001b32c00533400532c00530401b00700533400500700503301b22e005", - "0x33400505200502001b04f00533400504f00502001b04e00533400504e005", - "0x5204f04e32c05400722e0442e301b23900533400523900502001b052005", - "0x505600502a01b22b00533400522b00504701b053055056024334005239", - "0x50530053340050530050b501b05500533400505500503301b056005334", - "0x32e01b01b33400500900532e01b01b33400501b00701b05305505622b048", - "0x1b01b3340050b500532e01b01b33400532100532e01b01b334005038005", - "0x25d00533400501b22901b25300533400501b32b01b01b33400532c005085", - "0x1b33501b25f00533400525d25300732801b25d00533400525d00502001b", - "0x533400505e00502f01b05e00533400525f03500700901b035005334005", - "0x503301b05100533400505100502a01b23100533400523100504701b284", - "0x1b2840070512310480052840053340052840050b501b007005334005007", - "0x32e01b01b33400503a00533001b01b33400501b33201b01b33400501b007", - "0x1b01b33400532100532e01b01b33400532c00508501b01b334005009005", - "0x6000533400501b30c01b06100533400501b32b01b01b3340050b500532e", - "0x1b33501b00600533400506006100732801b06000533400506000502001b", - "0x533400506900502f01b06900533400500606700700901b067005334005", - "0x503301b04700533400504700502a01b32e00533400532e00504701b2ed", - "0x1b2ed00704732e0480052ed0053340052ed0050b501b007005334005007", - "0x32e01b01b33400519200533001b01b33400501b33201b01b33400501b007", - "0x1b01b3340050b500532e01b01b33400532c00508501b01b334005009005", - "0x533400506d00502001b06d00533400501b30b01b06c00533400501b32b", - "0x700901b31600533400501b33501b06f00533400506d06c00732801b06d", - "0x33400532e00504701b03600533400531500502f01b31500533400506f316", - "0xb501b00700533400500700503301b04700533400504700502a01b32e005", - "0x33201b01b33400501b00701b03600704732e048005036005334005036005", - "0x8501b01b33400500900532e01b01b33400503300533001b01b33400501b", - "0x1b07200533400501b00601b02600533400501b32b01b01b33400532c005", - "0x501b33501b07100533400507202600732801b072005334005072005020", - "0x7900533400531100502f01b31100533400507107700700901b077005334", - "0x700503301b04700533400504700502a01b32e00533400532e00504701b", - "0x701b07900704732e0480050790053340050790050b501b007005334005", - "0x508501b01b33400533500533001b01b33400501b33201b01b33400501b", - "0x2001b30f00533400501b22a01b07500533400501b32b01b01b33400532c", - "0x33400501b33501b30e00533400530f07500732801b30f00533400530f005", - "0x1b30b00533400530c00502f01b30c00533400530e30d00700901b30d005", - "0x500700503301b04700533400504700502a01b32e00533400532e005047", - "0x1b00701b30b00704732e04800530b00533400530b0050b501b007005334", - "0x19301b30a00533400532b00504701b01b33400502300533001b01b334005", - "0x533001b01b33400532f00522b01b01b33400501b00701b01b3c200501b", - "0x32b01b01b33400501b33201b30a00533400504800504701b01b334005023", - "0x8500533400508500502001b08500533400501b22e01b30600533400501b", - "0x30400700901b30400533400501b33501b30500533400508530600732801b", - "0x533400530a00504701b30300533400508300502f01b083005334005305", - "0x50b501b00700533400500700503301b04700533400504700502a01b30a", - "0x523101b01b33400501b00701b30300704730a048005303005334005303", - "0x2001b08100533400501b22901b30200533400501b32b01b01b334005024", - "0x33400501b33501b30100533400508130200732801b081005334005081005", - "0x1b07f0053340052ff00502f01b2ff00533400530130000700901b300005", - "0x500700503301b04500533400504500502a01b046005334005046005047", - "0x1b01b01b07f00704504604800507f00533400507f0050b501b007005334", - "0x1b00701b0450460073c304704800733400700501b00700501b01b334005", - "0x504701b01b33400501b04801b04400533400502400502401b01b334005", - "0x1b00701b0410053c404204300733400704400504601b048005334005048", - "0x1b02700533400519300504401b19300533400504200504501b01b334005", - "0x504000504101b02300533400504300504201b040005334005027005043", - "0x33400501b02701b01b33400501b00701b01b3c500501b19301b07d005334", - "0x4101b02300533400504100504201b33200533400502000504001b020005", - "0x1b00701b32f0053c633000533400707d00502301b07d005334005332005", - "0x501b00701b32b0053c732c32e00733400733004800730601b01b334005", - "0x3c832802500733400702300504601b32e00533400532e00504701b01b334", - "0x33400502500533001b01b33400501b33201b01b33400501b00701b335005", - "0x33400501b32b01b01b33400532c00508501b01b33400532800532f01b01b", - "0x732801b02f00533400502f00502001b02f00533400501b02501b009005", - "0x33400502a03300700901b03300533400501b33501b02a00533400502f009", - "0x2a01b32e00533400532e00504701b07c0053340050b500502f01b0b5005", - "0x33400507c0050b501b00700533400500700503301b047005334005047005", - "0x1b33400501b33201b01b33400501b00701b07c00704732e04800507c005", - "0x33400532200532201b32200533400501b07c01b01b33400533500533001b", - "0x1b00701b03b0390073c932119200733400732204732e02419201b322005", - "0x733400732c0073210242e201b19200533400519200504701b01b334005", - "0x21800533400501b32b01b01b33400501b00701b21620d2090243ca03803a", - "0x21e00521801b01b33400521a00521601b21e21a00733400521800520d01b", - "0x22900533400522800521e01b22800533400522400521a01b224005334005", - "0x3800503301b03a00533400503a00502a01b19200533400519200504701b", - "0x701b22903803a1920480052290053340052290050b501b038005334005", - "0x22b00533400521622a00700901b22a00533400501b33501b01b33400501b", - "0x20900502a01b19200533400519200504701b22e00533400522b00502f01b", - "0x22e00533400522e0050b501b20d00533400520d00503301b209005334005", - "0x1b01b33400532c00508501b01b33400501b00701b22e20d209192048005", - "0x533400505100502001b05100533400501b22901b23100533400501b32b", - "0x700901b04f00533400501b33501b04e00533400505123100732801b051", - "0x33400503900504701b23900533400505200502f01b05200533400504e04f", - "0xb501b00700533400500700503301b03b00533400503b00502a01b039005", - "0x33001b01b33400501b00701b23900703b039048005239005334005239005", - "0x1b01b3cb00501b19301b23c00533400532b00504701b01b334005023005", - "0x1b01b33400502300533001b01b33400532f00522b01b01b33400501b007", - "0x23d00533400501b32b01b01b33400501b33201b23c005334005048005047", - "0x5423d00732801b05400533400505400502001b05400533400501b22e01b", - "0x5300533400505605500700901b05500533400501b33501b056005334005", - "0x4700502a01b23c00533400523c00504701b25300533400505300502f01b", - "0x2530053340052530050b501b00700533400500700503301b047005334005", - "0x1b01b33400502400523101b01b33400501b00701b25300704723c048005", - "0x533400525f00502001b25f00533400501b22901b25d00533400501b32b", - "0x700901b05e00533400501b33501b03500533400525f25d00732801b25f", - "0x33400504600504701b06100533400528400502f01b28400533400503505e", - "0xb501b00700533400500700503301b04500533400504500502a01b046005", - "0x1b04700533400501b23901b061007045046048005061005334005061005", - "0x4600733400700501b00700501b01b33400501b01b01b01b33400501b23c", - "0x1b04200533400502400502401b01b33400501b00701b0430440073cc045", - "0x1b0270053cd19304100733400704200504601b046005334005046005047", - "0x33400504804700723d01b04800533400519300504501b01b33400501b007", - "0x4100504201b01b33400501b04801b04000533400504800504401b048005", - "0x501b00701b0200053ce07d02300733400704100504601b041005334005", - "0x5501b33000533400502300504201b33200533400507d00505601b01b334", - "0x2701b01b33400501b00701b01b3cf00501b19301b32f005334005332005", - "0x533400502000504201b32c00533400532e00505301b32e00533400501b", - "0x250053d032b00533400732f00525301b32f00533400532c00505501b330", - "0x32800533400532b00504501b01b33400501b33201b01b33400501b00701b", - "0x532800504401b00900533400533000521801b33500533400501b32b01b", - "0x1b04500533400504500502a01b04600533400504600504701b02f005334", - "0x502f00502001b33500533400533500522401b00900533400500900525d", - "0x503501b0b503302a02433400502f33500904504604725f01b02f005334", - "0x33400507c00505e01b01b33400501b00701b3220053d107c0053340070b5", - "0x1b33400501b00701b03b0053d203900533400732100528401b321192007", - "0x20d0053d320903800733400703a00504601b03a00533400519200502401b", - "0x1b33400520900532f01b01b33400503800533001b01b33400501b00701b", - "0x533400501b32b01b01b33400504000532e01b01b33400503900521601b", - "0x21600732801b21800533400521800502001b21800533400501b02501b216", - "0x533400521a21e00700901b21e00533400501b33501b21a005334005218", - "0x502a01b02a00533400502a00504701b22800533400522400502f01b224", - "0x53340052280050b501b00700533400500700503301b033005334005033", - "0x1b33400520d00533001b01b33400501b00701b22800703302a048005228", - "0x3302a02419201b22900533400522900532201b22900533400501b07c01b", - "0x3900520d01b01b33400501b00701b23122e0073d422b22a007334007229", - "0x4f00533400504e00521801b01b33400505100521601b04e051007334005", - "0x23905200733400704f04000722b0482e001b22a00533400522a00504701b", - "0x20d01b05600533400501b32b01b01b33400501b00701b05423d23c0243d5", - "0x33400505300521801b01b33400505500521601b053055007334005056005", - "0x4701b25f00533400525d00521e01b25d00533400525300521a01b253005", - "0x33400523900503301b05200533400505200502a01b22a00533400522a005", - "0x501b00701b25f23905222a04800525f00533400525f0050b501b239005", - "0x2f01b05e00533400505403500700901b03500533400501b33501b01b334", - "0x33400523c00502a01b22a00533400522a00504701b28400533400505e005", - "0x480052840053340052840050b501b23d00533400523d00503301b23c005", - "0x532e01b01b33400503900521601b01b33400501b00701b28423d23c22a", - "0x2001b06000533400501b22901b06100533400501b32b01b01b334005040", - "0x33400501b33501b00600533400506006100732801b060005334005060005", - "0x1b2ed00533400506900502f01b06900533400500606700700901b067005", - "0x500700503301b23100533400523100502a01b22e00533400522e005047", - "0x1b00701b2ed00723122e0480052ed0053340052ed0050b501b007005334", - "0x532e01b01b33400519200523101b01b33400503b00522b01b01b334005", - "0x6d00533400503300502a01b06c00533400502a00504701b01b334005040", - "0x1b01b33400504000532e01b01b33400501b00701b01b3d600501b19301b", - "0x503300502a01b02a00533400502a00504701b06f00533400532200502f", - "0x506f00533400506f0050b501b00700533400500700503301b033005334", - "0x522b01b01b33400501b33201b01b33400501b00701b06f00703302a048", - "0x4701b01b33400533000533001b01b33400504000532e01b01b334005025", - "0x533400501b32b01b06d00533400504500502a01b06c005334005046005", - "0x31600732801b31500533400531500502001b31500533400501b22a01b316", - "0x533400503602600700901b02600533400501b33501b036005334005315", - "0x502a01b06c00533400506c00504701b07100533400507200502f01b072", - "0x53340050710050b501b00700533400500700503301b06d00533400506d", - "0x1b33400502700533001b01b33400501b00701b07100706d06c048005071", - "0x533400501b22e01b07700533400501b32b01b01b33400504700506701b", - "0x33501b07900533400531107700732801b31100533400531100502001b311", - "0x33400530f00502f01b30f00533400507907500700901b07500533400501b", - "0x3301b04500533400504500502a01b04600533400504600504701b30e005", - "0x30e00704504604800530e00533400530e0050b501b007005334005007005", - "0x1b33400502400523101b01b33400504700506701b01b33400501b00701b", - "0x33400530c00502001b30c00533400501b22901b30d00533400501b32b01b", - "0x901b30a00533400501b33501b30b00533400530c30d00732801b30c005", - "0x504400504701b08500533400530600502f01b30600533400530b30a007", - "0x1b00700533400500700503301b04300533400504300502a01b044005334", - "0x1b01b33400501b01b01b0850070430440480050850053340050850050b5", - "0x1b01b33400501b00701b0440450073d704604700733400700701b007005", - "0x704300504601b04700533400504700504701b043005334005048005024", - "0x1b33400504200533001b01b33400501b00701b1930053d8041042007334", - "0x533400501b02501b02700533400501b32b01b01b33400504100532f01b", - "0x33501b02300533400504002700732801b04000533400504000502001b040", - "0x33400502000502f01b02000533400502307d00700901b07d00533400501b", - "0x2a01b0050053340050050052df01b04700533400504700504701b332005", - "0x3340053320050b501b02400533400502400503301b046005334005046005", - "0x519300533001b01b33400501b00701b332024046005047047005332005", - "0x2419201b33000533400533000532201b33000533400501b07c01b01b334", - "0x9e01b01b33400501b00701b32b32c0073d932e32f007334007330046047", - "0x50250052df01b32f00533400532f00504701b328025007334005005005", - "0x1b3280053340053280052de01b32e00533400532e00502a01b025005334", - "0x1b33400502a0050a101b02a02f00933504833400532832e02532f0480a5", - "0xb500521601b07c0b500733400503300520d01b03300533400501b32b01b", - "0x1b19200533400532200521a01b32200533400507c00521801b01b334005", - "0x50090052df01b33500533400533500504701b32100533400519200521e", - "0x1b02400533400502400503301b02f00533400502f00502a01b009005334", - "0x1b33400501b00701b32102402f0093350470053210053340053210050b5", - "0x33400503b00502001b03b00533400501b22901b03900533400501b32b01b", - "0x901b03800533400501b33501b03a00533400503b03900732801b03b005", - "0x532c00504701b20d00533400520900502f01b20900533400503a038007", - "0x1b32b00533400532b00502a01b0050053340050050052df01b32c005334", - "0x32b00532c04700520d00533400520d0050b501b024005334005024005033", - "0x33400501b32b01b01b33400504800523101b01b33400501b00701b20d024", - "0x732801b21800533400521800502001b21800533400501b22901b216005", - "0x33400521a21e00700901b21e00533400501b33501b21a005334005218216", - "0x2df01b04500533400504500504701b22800533400522400502f01b224005", - "0x33400502400503301b04400533400504400502a01b005005334005005005", - "0x1b23901b2280240440050450470052280053340052280050b501b024005", - "0x1b01b01b01b33400501b23c01b04500533400501b23901b047005334005", - "0x1b00701b0410420073da04304400733400700501b00700501b01b334005", - "0x504701b01b33400501b04801b19300533400502400502401b01b334005", - "0x1b00701b0230053db04002700733400719300504601b044005334005044", - "0x1b02000533400507d00504401b07d00533400504000504501b01b334005", - "0x533200504101b33000533400502700504201b332005334005020005043", - "0x33400501b02701b01b33400501b00701b01b3dc00501b19301b32f005334", - "0x4101b33000533400502300504201b32c00533400532e00504001b32e005", - "0x1b00701b32b0053dd04800533400732f00502301b32f00533400532c005", - "0x733400704804400730601b04800533400504804700723d01b01b334005", - "0x1b02500533400502500504701b01b33400501b00701b3350053de328025", - "0x504501b01b33400501b00701b02a0053df02f009007334007330005046", - "0x33400504600504401b04600533400504604500723d01b04600533400502f", - "0x3e007c0b500733400700900504601b00900533400500900504201b033005", - "0xb500504201b19200533400507c00505601b01b33400501b00701b322005", - "0x701b01b3e100501b19301b03900533400519200505501b321005334005", - "0x1b03a00533400503b00505301b03b00533400501b02701b01b33400501b", - "0x703900525301b03900533400503a00505501b321005334005322005042", - "0x20d00533400503800504501b01b33400501b00701b2090053e2038005334", - "0x520d00504401b21800533400532100521801b21600533400501b32b01b", - "0x1b04300533400504300502a01b02500533400502500504701b21a005334", - "0x521a00502001b21600533400521600522401b21800533400521800525d", - "0x503501b22822421e02433400521a21621804302504725f01b21a005334", - "0x33400522900505e01b01b33400501b00701b22a0053e3229005334007228", - "0x1b33400501b00701b0510053e423100533400722e00528401b22e22b007", - "0x2390053e505204f00733400704e00504601b04e00533400522b00502401b", - "0x33400523c00504401b23c00533400505200504501b01b33400501b00701b", - "0x4f00504201b23d00533400523d00502001b01b33400501b04801b23d005", - "0x1b33400501b00701b0540053e601b33400723d0052f801b04f005334005", - "0x50550052db01b0550053340050560052dd01b05600533400501b02701b", - "0x50540052f701b01b33400501b00701b01b3e700501b19301b053005334", - "0x52db01b25d0053340052530050a901b25300533400501b02701b01b334", - "0x1b00701b05e0053e803525f00733400704f00504601b05300533400525d", - "0x3500532f01b01b33400525f00533001b01b33400501b33201b01b334005", - "0x532e01b01b33400523100521601b01b3340050530050ab01b01b334005", - "0x2501b28400533400501b32b01b01b33400532800508501b01b334005033", - "0x33400506128400732801b06100533400506100502001b06100533400501b", - "0x2f01b06700533400506000600700901b00600533400501b33501b060005", - "0x33400522400502a01b21e00533400521e00504701b069005334005067005", - "0x480050690053340050690050b501b00700533400500700503301b224005", - "0x1b07c01b01b33400505e00533001b01b33400501b00701b06900722421e", - "0x3340072ed22421e02419201b2ed0053340052ed00532201b2ed005334005", - "0x1b01b33400501b33201b01b33400501b00701b31606f0073e906d06c007", - "0x3600521601b02603600733400523100520d01b3150053340050530052d9", - "0x1b3150053340053150052db01b07200533400502600521801b01b334005", - "0x7104833400731507203332800706d0460ae01b06c00533400506c005047", - "0x33400531100506101b01b33400501b00701b30e30f0750243ea079311077", - "0x530d00520d01b30d00533400501b32b01b01b33400507900523101b01b", - "0x1b30a00533400530b00521801b01b33400530c00521601b30b30c007334", - "0x506c00504701b08500533400530600521e01b30600533400530a00521a", - "0x1b07700533400507700503301b07100533400507100502a01b06c005334", - "0x1b01b33400501b00701b08507707106c0480050850053340050850050b5", - "0x530400502f01b30400533400530e30500700901b30500533400501b335", - "0x1b07500533400507500502a01b06c00533400506c00504701b083005334", - "0x30f07506c0480050830053340050830050b501b30f00533400530f005033", - "0x1b3340050530050ab01b01b33400501b33201b01b33400501b00701b083", - "0x33400532800508501b01b33400503300532e01b01b33400523100521601b", - "0x530200502001b30200533400501b22901b30300533400501b32b01b01b", - "0x1b30100533400501b33501b08100533400530230300732801b302005334", - "0x6f00504701b2ff00533400530000502f01b300005334005081301007009", - "0x700533400500700503301b31600533400531600502a01b06f005334005", - "0x1b33400501b00701b2ff00731606f0480052ff0053340052ff0050b501b", - "0x33400523100521601b01b33400532800508501b01b33400523900533001b", - "0x33400501b30b01b07f00533400501b32b01b01b33400503300532e01b01b", - "0x1b33d00533400508707f00732801b08700533400508700502001b087005", - "0x52fb00502f01b2fb00533400533d2fc00700901b2fc00533400501b335", - "0x1b22400533400522400502a01b21e00533400521e00504701b2fa005334", - "0x722421e0480052fa0053340052fa0050b501b007005334005007005033", - "0x33400532800508501b01b33400505100522b01b01b33400501b00701b2fa", - "0x521e00504701b01b33400503300532e01b01b33400522b00523101b01b", - "0x1b00701b01b3eb00501b19301b2f800533400522400502a01b2f9005334", - "0x502f01b01b33400503300532e01b01b33400532800508501b01b334005", - "0x533400522400502a01b21e00533400521e00504701b2f700533400522a", - "0x21e0480052f70053340052f70050b501b00700533400500700503301b224", - "0x520900522b01b01b33400501b33201b01b33400501b00701b2f7007224", - "0x32100533001b01b33400503300532e01b01b33400532800508501b01b334", - "0x1b2f800533400504300502a01b2f900533400502500504701b01b334005", - "0x53340052f500502001b2f500533400501b00601b2f600533400501b32b", - "0x700901b2f300533400501b33501b2f40053340052f52f600732801b2f5", - "0x3340052f900504701b2f10053340052f200502f01b2f20053340052f42f3", - "0xb501b00700533400500700503301b2f80053340052f800502a01b2f9005", - "0x33201b01b33400501b00701b2f10072f82f90480052f10053340052f1005", - "0x6701b01b33400532800508501b01b33400502a00533001b01b33400501b", - "0x1b07e00533400501b22a01b2ee00533400501b32b01b01b334005045005", - "0x501b33501b08b00533400507e2ee00732801b07e00533400507e005020", - "0x8f0053340052ec00502f01b2ec00533400508b08d00700901b08d005334", - "0x700503301b04300533400504300502a01b02500533400502500504701b", - "0x701b08f00704302504800508f00533400508f0050b501b007005334005", - "0x4701b01b33400533000533001b01b33400504500506701b01b33400501b", - "0x22b01b01b33400501b00701b01b3ec00501b19301b2eb005334005335005", - "0x1b01b33400533000533001b01b33400504500506701b01b33400532b005", - "0x1b33400501b33201b2eb00533400504400504701b01b334005047005067", - "0x3340052ea00502001b2ea00533400501b22e01b08400533400501b32b01b", - "0x901b2e700533400501b33501b2e90053340052ea08400732801b2ea005", - "0x52eb00504701b2e600533400509700502f01b0970053340052e92e7007", - "0x1b00700533400500700503301b04300533400504300502a01b2eb005334", - "0x1b01b33400501b00701b2e60070432eb0480052e60053340052e60050b5", - "0x1b33400504700506701b01b33400504500506701b01b334005024005231", - "0x3340052e400502001b2e400533400501b22901b2e500533400501b32b01b", - "0x901b2e200533400501b33501b2e30053340052e42e500732801b2e4005", - "0x504200504701b2df0053340052e000502f01b2e00053340052e32e2007", - "0x1b00700533400500700503301b04100533400504100502a01b042005334", - "0x1b01b33400501b01b01b2df0070410420480052df0053340052df0050b5", - "0x1b01b33400501b00701b0450460073ed04704800733400700501b007005", - "0x704400504601b04800533400504800504701b044005334005024005024", - "0x1b33400504300533001b01b33400501b00701b0410053ee042043007334", - "0x533400501b02501b19300533400501b32b01b01b33400504200532f01b", - "0x33501b04000533400502719300732801b02700533400502700502001b027", - "0x33400507d00502f01b07d00533400504002300700901b02300533400501b", - "0x3301b04700533400504700502a01b04800533400504800504701b020005", - "0x200070470480480050200053340050200050b501b007005334005007005", - "0x33200533400501b07c01b01b33400504100533001b01b33400501b00701b", - "0x3ef32f33000733400733204704802419201b33200533400533200532201b", - "0x33000504701b32b00533400501b30501b01b33400501b00701b32c32e007", - "0x700533400500700503301b32f00533400532f00502a01b330005334005", - "0x33400700900530301b00933532802504833400532b00732f3300482d701b", - "0x32b01b01b33400502f00530201b01b33400501b00701b02a0053f002f005", - "0x3340050b500521601b07c0b500733400503300520d01b03300533400501b", - "0x521e01b19200533400532200521a01b32200533400507c00521801b01b", - "0x533400532800502a01b02500533400502500504701b321005334005192", - "0x250480053210053340053210050b501b33500533400533500503301b328", - "0x504701b03900533400502a00502f01b01b33400501b00701b321335328", - "0x533400533500503301b32800533400532800502a01b025005334005025", - "0x33400501b00701b0393353280250480050390053340050390050b501b335", - "0x503a00502001b03a00533400501b22901b03b00533400501b32b01b01b", - "0x1b20900533400501b33501b03800533400503a03b00732801b03a005334", - "0x32e00504701b21600533400520d00502f01b20d005334005038209007009", - "0x700533400500700503301b32c00533400532c00502a01b32e005334005", - "0x1b33400501b00701b21600732c32e0480052160053340052160050b501b", - "0x533400501b22901b21800533400501b32b01b01b33400502400523101b", - "0x33501b21e00533400521a21800732801b21a00533400521a00502001b21a", - "0x33400522800502f01b22800533400521e22400700901b22400533400501b", - "0x3301b04500533400504500502a01b04600533400504600504701b229005", - "0x2290070450460480052290053340052290050b501b007005334005007005", - "0x450460073f104704800733400700501b00700501b01b33400501b01b01b", - "0x33400504800504701b04400533400502400502401b01b33400501b00701b", - "0x1b33400501b00701b0410053f204204300733400704400504601b048005", - "0x533400501b32b01b01b33400504200532f01b01b33400504300533001b", - "0x19300732801b02700533400502700502001b02700533400501b02501b193", - "0x533400504002300700901b02300533400501b33501b040005334005027", - "0x502a01b04800533400504800504701b02000533400507d00502f01b07d", - "0x53340050200050b501b00700533400500700503301b047005334005047", - "0x1b33400504100533001b01b33400501b00701b020007047048048005020", - "0x4704802419201b33200533400533200532201b33200533400501b07c01b", - "0x501b30501b01b33400501b00701b32c32e0073f332f330007334007332", - "0x1b32f00533400532f00502a01b33000533400533000504701b32b005334", - "0x33532802504833400532b00732f3300482d601b007005334005007005033", - "0x30201b01b33400501b00701b02a0053f402f00533400700900530301b009", - "0xb500733400503300520d01b03300533400501b32b01b01b33400502f005", - "0x32200521a01b32200533400507c00521801b01b3340050b500521601b07c", - "0x2500533400502500504701b32100533400519200521e01b192005334005", - "0x3210050b501b33500533400533500503301b32800533400532800502a01b", - "0x2a00502f01b01b33400501b00701b321335328025048005321005334005", - "0x32800533400532800502a01b02500533400502500504701b039005334005", - "0x3280250480050390053340050390050b501b33500533400533500503301b", - "0x33400501b22901b03b00533400501b32b01b01b33400501b00701b039335", - "0x1b03800533400503a03b00732801b03a00533400503a00502001b03a005", - "0x520d00502f01b20d00533400503820900700901b20900533400501b335", - "0x1b32c00533400532c00502a01b32e00533400532e00504701b216005334", - "0x732c32e0480052160053340052160050b501b007005334005007005033", - "0x533400501b32b01b01b33400502400523101b01b33400501b00701b216", - "0x21800732801b21a00533400521a00502001b21a00533400501b22901b218", - "0x533400521e22400700901b22400533400501b33501b21e00533400521a", - "0x502a01b04600533400504600504701b22900533400522800502f01b228", - "0x53340052290050b501b00700533400500700503301b045005334005045", - "0x33400700701b00700501b01b33400501b01b01b229007045046048005229", - "0x533400504800502401b01b33400501b00701b0440450073f5046047007", - "0x53f604104200733400704300504601b04700533400504700504701b043", - "0x33400504100532f01b01b33400504200533001b01b33400501b00701b193", - "0x504000502001b04000533400501b02501b02700533400501b32b01b01b", - "0x1b07d00533400501b33501b02300533400504002700732801b040005334", - "0x4700504701b33200533400502000502f01b02000533400502307d007009", - "0x4600533400504600502a01b0050053340050050052d501b047005334005", - "0x50470470053320053340053320050b501b02400533400502400503301b", - "0x501b07c01b01b33400519300533001b01b33400501b00701b332024046", - "0x733400733004604702419201b33000533400533000532201b330005334", - "0x1b02500533400501b30501b01b33400501b00701b32b32c0073f732e32f", - "0x50050052d501b32e00533400532e00502a01b32f00533400532f005047", - "0x502502400532e32f0472d401b02400533400502400503301b005005334", - "0x701b0b50053f803300533400702a00530301b02a02f009335328047334", - "0x20d01b07c00533400501b32b01b01b33400503300530201b01b33400501b", - "0x33400519200521801b01b33400532200521601b19232200733400507c005", - "0x4701b03b00533400503900521e01b03900533400532100521a01b321005", - "0x33400533500502a01b0090053340050090052d501b328005334005328005", - "0x4700503b00533400503b0050b501b02f00533400502f00503301b335005", - "0x1b03a0053340050b500502f01b01b33400501b00701b03b02f335009328", - "0x533500502a01b0090053340050090052d501b328005334005328005047", - "0x503a00533400503a0050b501b02f00533400502f00503301b335005334", - "0x1b03800533400501b32b01b01b33400501b00701b03a02f335009328047", - "0x520903800732801b20900533400520900502001b20900533400501b229", - "0x1b21800533400520d21600700901b21600533400501b33501b20d005334", - "0x50050052d501b32c00533400532c00504701b21a00533400521800502f", - "0x1b02400533400502400503301b32b00533400532b00502a01b005005334", - "0x1b33400501b00701b21a02432b00532c04700521a00533400521a0050b5", - "0x533400501b22901b21e00533400501b32b01b01b33400504800523101b", - "0x33501b22800533400522421e00732801b22400533400522400502001b224", - "0x33400522a00502f01b22a00533400522822900700901b22900533400501b", - "0x2a01b0050053340050050052d501b04500533400504500504701b22b005", - "0x33400522b0050b501b02400533400502400503301b044005334005044005", - "0x501b00700501b01b33400501b01b01b22b02404400504504700522b005", - "0x502400502401b01b33400501b00701b0450460073f9047048007334007", - "0x4204300733400704400504601b04800533400504800504701b044005334", - "0x4200532f01b01b33400504300533001b01b33400501b00701b0410053fa", - "0x502001b02700533400501b02501b19300533400501b32b01b01b334005", - "0x533400501b33501b04000533400502719300732801b027005334005027", - "0x4701b02000533400507d00502f01b07d00533400504002300700901b023", - "0x33400500700503301b04700533400504700502a01b048005334005048005", - "0x501b00701b0200070470480480050200053340050200050b501b007005", - "0x33200532201b33200533400501b07c01b01b33400504100533001b01b334", - "0x1b32c32e0073fb32f33000733400733204704802419201b332005334005", - "0x33000533400533000504701b32b00533400501b30501b01b33400501b007", - "0x3300482d301b00700533400500700503301b32f00533400532f00502a01b", - "0x53fc02f00533400700900530301b00933532802504833400532b00732f", - "0x533400501b32b01b01b33400502f00530201b01b33400501b00701b02a", - "0x521801b01b3340050b500521601b07c0b500733400503300520d01b033", - "0x533400519200521e01b19200533400532200521a01b32200533400507c", - "0x503301b32800533400532800502a01b02500533400502500504701b321", - "0x1b3213353280250480053210053340053210050b501b335005334005335", - "0x533400502500504701b03900533400502a00502f01b01b33400501b007", - "0x50b501b33500533400533500503301b32800533400532800502a01b025", - "0x1b32b01b01b33400501b00701b039335328025048005039005334005039", - "0x1b03a00533400503a00502001b03a00533400501b22901b03b005334005", - "0x3820900700901b20900533400501b33501b03800533400503a03b007328", - "0x32e00533400532e00504701b21600533400520d00502f01b20d005334005", - "0x2160050b501b00700533400500700503301b32c00533400532c00502a01b", - "0x2400523101b01b33400501b00701b21600732c32e048005216005334005", - "0x502001b21a00533400501b22901b21800533400501b32b01b01b334005", - "0x533400501b33501b21e00533400521a21800732801b21a00533400521a", - "0x4701b22900533400522800502f01b22800533400521e22400700901b224", - "0x33400500700503301b04500533400504500502a01b046005334005046005", - "0x501b01b01b2290070450460480052290053340052290050b501b007005", - "0x501b00701b0450460073fd04704800733400700501b00700501b01b334", - "0x4601b04800533400504800504701b04400533400502400502401b01b334", - "0x4200504501b01b33400501b00701b0410053fe042043007334007044005", - "0x19300533400519300502001b04300533400504300504201b193005334005", - "0x4501b01b33400501b00701b0230053ff04002700733400704300504601b", - "0x33400507d00502001b02700533400502700504201b07d005334005040005", - "0x1b33400501b00701b33000540033202000733400702700504601b07d005", - "0x33400519300532e01b01b33400533200532f01b01b33400502000533001b", - "0x33400501b02501b32f00533400501b32b01b01b33400507d00532e01b01b", - "0x1b32c00533400532e32f00732801b32e00533400532e00502001b32e005", - "0x502500502f01b02500533400532c32b00700901b32b00533400501b335", - "0x1b04700533400504700502a01b04800533400504800504701b328005334", - "0x70470480480053280053340053280050b501b007005334005007005033", - "0x533400501b07c01b01b33400533000533001b01b33400501b00701b328", - "0x2f00900733400733504704802419201b33500533400533500532201b335", - "0x4401b0b500533400519300504401b01b33400501b00701b03302a007401", - "0x532200502001b32200533400507c0b50072f901b07c00533400507d005", - "0x540201b3340073220052f801b00900533400500900504701b322005334", - "0x533400501b2d201b32100533400501b32b01b01b33400501b00701b192", - "0x20d01b03b00533400503932100732801b03900533400503900502001b039", - "0x33400503800521801b01b33400503a00521601b03803a00733400503b005", - "0x4701b21600533400520d00521e01b20d00533400520900521a01b209005", - "0x33400500700503301b02f00533400502f00502a01b009005334005009005", - "0x501b00701b21600702f0090480052160053340052160050b501b007005", - "0x501b0b401b21800533400501b32b01b01b3340051920052f701b01b334", - "0x21e00533400521a21800732801b21a00533400521a00502001b21a005334", - "0x22800502f01b22800533400521e22400700901b22400533400501b33501b", - "0x2f00533400502f00502a01b00900533400500900504701b229005334005", - "0x2f0090480052290053340052290050b501b00700533400500700503301b", - "0x507d00532e01b01b33400519300532e01b01b33400501b00701b229007", - "0x22b00502001b22b00533400501b22901b22a00533400501b32b01b01b334", - "0x23100533400501b33501b22e00533400522b22a00732801b22b005334005", - "0x504701b04e00533400505100502f01b05100533400522e23100700901b", - "0x533400500700503301b03300533400503300502a01b02a00533400502a", - "0x33400501b00701b04e00703302a04800504e00533400504e0050b501b007", - "0x33400501b32b01b01b33400519300532e01b01b33400502300533001b01b", - "0x732801b05200533400505200502001b05200533400501b22a01b04f005", - "0x33400523923c00700901b23c00533400501b33501b23900533400505204f", - "0x2a01b04800533400504800504701b05400533400523d00502f01b23d005", - "0x3340050540050b501b00700533400500700503301b047005334005047005", - "0x33400504100533001b01b33400501b00701b054007047048048005054005", - "0x505500502001b05500533400501b22e01b05600533400501b32b01b01b", - "0x1b25300533400501b33501b05300533400505505600732801b055005334", - "0x4800504701b25f00533400525d00502f01b25d005334005053253007009", - "0x700533400500700503301b04700533400504700502a01b048005334005", - "0x1b33400501b00701b25f00704704804800525f00533400525f0050b501b", - "0x533400501b22901b03500533400501b32b01b01b33400502400523101b", - "0x33501b28400533400505e03500732801b05e00533400505e00502001b05e", - "0x33400506000502f01b06000533400528406100700901b06100533400501b", - "0x3301b04500533400504500502a01b04600533400504600504701b006005", - "0x60070450460480050060053340050060050b501b007005334005007005", - "0x4504600740304704800733400700501b00700501b01b33400501b01b01b", - "0x1b33400501b04801b04400533400502400502401b01b33400501b00701b", - "0x4100540404204300733400704400504601b04800533400504800504701b", - "0x33400504300504201b19300533400504200505601b01b33400501b00701b", - "0x501b00701b01b40500501b19301b04000533400519300505501b027005", - "0x504201b07d00533400502300505301b02300533400501b02701b01b334", - "0x533400704000525301b04000533400507d00505501b027005334005041", - "0x2000504501b01b33400501b33201b01b33400501b00701b332005406020", - "0x1b32e00533400502700521801b32f00533400501b32b01b330005334005", - "0x504700502a01b04800533400504800504701b32c005334005330005044", - "0x1b32f00533400532f00522401b32e00533400532e00525d01b047005334", - "0x2532b02433400532c32f32e04704804725f01b32c00533400532c005020", - "0x5e01b01b33400501b00701b00900540733500533400732800503501b328", - "0x701b0b500540803300533400702a00528401b02a02f007334005335005", - "0x32200733400707c00504601b07c00533400502f00502401b01b33400501b", - "0x532f01b01b33400532200533001b01b33400501b00701b321005409192", - "0x2501b03900533400501b32b01b01b33400503300521601b01b334005192", - "0x33400503b03900732801b03b00533400503b00502001b03b00533400501b", - "0x2f01b20900533400503a03800700901b03800533400501b33501b03a005", - "0x33400502500502a01b32b00533400532b00504701b20d005334005209005", - "0x4800520d00533400520d0050b501b00700533400500700503301b025005", - "0x1b07c01b01b33400532100533001b01b33400501b00701b20d00702532b", - "0x33400721602532b02419201b21600533400521600532201b216005334005", - "0x22800533400501b30501b01b33400501b00701b22421e00740a21a218007", - "0x700503301b21a00533400521a00502a01b21800533400521800504701b", - "0x3322800721a2180472d101b03300533400503300522401b007005334005", - "0x701b05100540b23100533400722e0052d001b22e22b22a229048334005", - "0x5204f0073340052310052cf01b04e00533400501b32b01b01b33400501b", - "0x23900520d01b23900533400505204e00732801b01b33400504f00508401b", - "0x5400533400523d00521801b01b33400523c00521601b23d23c007334005", - "0x22900504701b05500533400505600521e01b05600533400505400521a01b", - "0x22b00533400522b00503301b22a00533400522a00502a01b229005334005", - "0x1b33400501b00701b05522b22a2290480050550053340050550050b501b", - "0x22a00502a01b22900533400522900504701b05300533400505100502f01b", - "0x530053340050530050b501b22b00533400522b00503301b22a005334005", - "0x1b01b33400503300521601b01b33400501b00701b05322b22a229048005", - "0x533400525d00502001b25d00533400501b22901b25300533400501b32b", - "0x700901b03500533400501b33501b25f00533400525d25300732801b25d", - "0x33400521e00504701b28400533400505e00502f01b05e00533400525f035", - "0xb501b00700533400500700503301b22400533400522400502a01b21e005", - "0x22b01b01b33400501b00701b28400722421e048005284005334005284005", - "0x6100533400532b00504701b01b33400502f00523101b01b3340050b5005", - "0x1b33400501b00701b01b40c00501b19301b06000533400502500502a01b", - "0x2500502a01b32b00533400532b00504701b00600533400500900502f01b", - "0x60053340050060050b501b00700533400500700503301b025005334005", - "0x22b01b01b33400501b33201b01b33400501b00701b00600702532b048005", - "0x6100533400504800504701b01b33400502700533001b01b334005332005", - "0x33400501b22e01b06700533400501b32b01b06000533400504700502a01b", - "0x1b2ed00533400506906700732801b06900533400506900502001b069005", - "0x506d00502f01b06d0053340052ed06c00700901b06c00533400501b335", - "0x1b06000533400506000502a01b06100533400506100504701b06f005334", - "0x706006104800506f00533400506f0050b501b007005334005007005033", - "0x533400501b32b01b01b33400502400523101b01b33400501b00701b06f", - "0x31600732801b31500533400531500502001b31500533400501b22901b316", - "0x533400503602600700901b02600533400501b33501b036005334005315", - "0x502a01b04600533400504600504701b07100533400507200502f01b072", - "0x53340050710050b501b00700533400500700503301b045005334005045", - "0x33400700501b00700501b01b33400501b01b01b071007045046048005071", - "0x533400502400502401b01b33400501b00701b04504600740d047048007", - "0x540e04204300733400704400504601b04800533400504800504701b044", - "0x33400504200532f01b01b33400504300533001b01b33400501b00701b041", - "0x502700502001b02700533400501b02501b19300533400501b32b01b01b", - "0x1b02300533400501b33501b04000533400502719300732801b027005334", - "0x4800504701b02000533400507d00502f01b07d005334005040023007009", - "0x700533400500700503301b04700533400504700502a01b048005334005", - "0x1b33400501b00701b0200070470480480050200053340050200050b501b", - "0x33400533200532201b33200533400501b07c01b01b33400504100533001b", - "0x1b00701b32c32e00740f32f33000733400733204704802419201b332005", - "0x502001b02500533400501b04901b32b00533400501b32b01b01b334005", - "0x533400501b33501b32800533400502532b00732801b025005334005025", - "0x4701b02f00533400500900502f01b00900533400532833500700901b335", - "0x33400500700503301b32f00533400532f00502a01b330005334005330005", - "0x501b00701b02f00732f33004800502f00533400502f0050b501b007005", - "0x3300502001b03300533400501b22901b02a00533400501b32b01b01b334", - "0x7c00533400501b33501b0b500533400503302a00732801b033005334005", - "0x504701b19200533400532200502f01b3220053340050b507c00700901b", - "0x533400500700503301b32c00533400532c00502a01b32e00533400532e", - "0x33400501b00701b19200732c32e0480051920053340051920050b501b007", - "0x33400501b22901b32100533400501b32b01b01b33400502400523101b01b", - "0x1b03b00533400503932100732801b03900533400503900502001b039005", - "0x503800502f01b03800533400503b03a00700901b03a00533400501b335", - "0x1b04500533400504500502a01b04600533400504600504701b209005334", - "0x70450460480052090053340052090050b501b007005334005007005033", - "0x4600741004704800733400700501b00700501b01b33400501b01b01b209", - "0x504800504701b04400533400502400502401b01b33400501b00701b045", - "0x33400501b00701b04100541104204300733400704400504601b048005334", - "0x502001b04300533400504300504201b19300533400504200504501b01b", - "0x1b00701b02300541204002700733400704300504601b193005334005193", - "0x532e01b01b33400504000532f01b01b33400502700533001b01b334005", - "0x2001b02000533400501b02501b07d00533400501b32b01b01b334005193", - "0x33400501b33501b33200533400502007d00732801b020005334005020005", - "0x1b32e00533400532f00502f01b32f00533400533233000700901b330005", - "0x500700503301b04700533400504700502a01b048005334005048005047", - "0x1b00701b32e00704704804800532e00533400532e0050b501b007005334", - "0x532201b32c00533400501b07c01b01b33400502300533001b01b334005", - "0x33532800741302532b00733400732c04704802419201b32c00533400532c", - "0x533400501b30501b00900533400519300504401b01b33400501b00701b", - "0x502001b02500533400502500502a01b32b00533400532b00504701b02f", - "0x30301b0b503302a02433400500902f02532b04835901b009005334005009", - "0x507c00530201b01b33400501b00701b32200541407c0053340070b5005", - "0x21601b03932100733400519200520d01b19200533400501b32b01b01b334", - "0x533400503b00521a01b03b00533400503900521801b01b334005321005", - "0x502a01b02a00533400502a00504701b03800533400503a00521e01b03a", - "0x53340050380050b501b00700533400500700503301b033005334005033", - "0x533400532200502f01b01b33400501b00701b03800703302a048005038", - "0x503301b03300533400503300502a01b02a00533400502a00504701b209", - "0x1b20900703302a0480052090053340052090050b501b007005334005007", - "0x1b20d00533400501b32b01b01b33400519300532e01b01b33400501b007", - "0x521620d00732801b21600533400521600502001b21600533400501b229", - "0x1b21e00533400521821a00700901b21a00533400501b33501b218005334", - "0x533500502a01b32800533400532800504701b22400533400521e00502f", - "0x52240053340052240050b501b00700533400500700503301b335005334", - "0x32b01b01b33400504100533001b01b33400501b00701b224007335328048", - "0x22900533400522900502001b22900533400501b22e01b22800533400501b", - "0x22b00700901b22b00533400501b33501b22a00533400522922800732801b", - "0x533400504800504701b23100533400522e00502f01b22e00533400522a", - "0x50b501b00700533400500700503301b04700533400504700502a01b048", - "0x523101b01b33400501b00701b231007047048048005231005334005231", - "0x2001b04e00533400501b22901b05100533400501b32b01b01b334005024", - "0x33400501b33501b04f00533400504e05100732801b04e00533400504e005", - "0x1b23c00533400523900502f01b23900533400504f05200700901b052005", - "0x500700503301b04500533400504500502a01b046005334005046005047", - "0x1b01b01b23c00704504604800523c00533400523c0050b501b007005334", - "0x1b00701b04504600741504704800733400700501b00700501b01b334005", - "0x1b04800533400504800504701b04400533400502400502401b01b334005", - "0x504501b01b33400501b00701b041005416042043007334007044005046", - "0x533400519300502001b04300533400504300504201b193005334005042", - "0x1b01b33400501b00701b02300541704002700733400704300504601b193", - "0x1b33400519300532e01b01b33400504000532f01b01b334005027005330", - "0x33400502000502001b02000533400501b02501b07d00533400501b32b01b", - "0x901b33000533400501b33501b33200533400502007d00732801b020005", - "0x504800504701b32e00533400532f00502f01b32f005334005332330007", - "0x1b00700533400500700503301b04700533400504700502a01b048005334", - "0x1b01b33400501b00701b32e00704704804800532e00533400532e0050b5", - "0x533400532c00532201b32c00533400501b07c01b01b334005023005330", - "0x501b00701b33532800741802532b00733400732c04704802419201b32c", - "0x504701b02f00533400501b30501b00900533400519300504401b01b334", - "0x533400500900502001b02500533400502500502a01b32b00533400532b", - "0x3340070b500530301b0b503302a02433400500902f02532b04835a01b009", - "0x32b01b01b33400507c00530201b01b33400501b00701b32200541907c005", - "0x33400532100521601b03932100733400519200520d01b19200533400501b", - "0x521e01b03a00533400503b00521a01b03b00533400503900521801b01b", - "0x533400503300502a01b02a00533400502a00504701b03800533400503a", - "0x2a0480050380053340050380050b501b00700533400500700503301b033", - "0x504701b20900533400532200502f01b01b33400501b00701b038007033", - "0x533400500700503301b03300533400503300502a01b02a00533400502a", - "0x33400501b00701b20900703302a0480052090053340052090050b501b007", - "0x33400501b22901b20d00533400501b32b01b01b33400519300532e01b01b", - "0x1b21800533400521620d00732801b21600533400521600502001b216005", - "0x521e00502f01b21e00533400521821a00700901b21a00533400501b335", - "0x1b33500533400533500502a01b32800533400532800504701b224005334", - "0x73353280480052240053340052240050b501b007005334005007005033", - "0x533400501b32b01b01b33400504100533001b01b33400501b00701b224", - "0x22800732801b22900533400522900502001b22900533400501b22e01b228", - "0x533400522a22b00700901b22b00533400501b33501b22a005334005229", - "0x502a01b04800533400504800504701b23100533400522e00502f01b22e", - "0x53340052310050b501b00700533400500700503301b047005334005047", - "0x1b33400502400523101b01b33400501b00701b231007047048048005231", - "0x33400504e00502001b04e00533400501b22901b05100533400501b32b01b", - "0x901b05200533400501b33501b04f00533400504e05100732801b04e005", - "0x504600504701b23c00533400523900502f01b23900533400504f052007", - "0x1b00700533400500700503301b04500533400504500502a01b046005334", - "0x1b01b33400501b01b01b23c00704504604800523c00533400523c0050b5", - "0x1b01b33400501b00701b04504600741a04704800733400700501b007005", - "0x533400504800504701b01b33400501b04801b044005334005024005024", - "0x1b01b33400501b00701b04100541b04204300733400704400504601b048", - "0x502700504301b02700533400519300504401b193005334005042005045", - "0x1b07d00533400504000504101b02300533400504300504201b040005334", - "0x4001b02000533400501b02701b01b33400501b00701b01b41c00501b193", - "0x33400533200504101b02300533400504100504201b332005334005020005", - "0x1b01b33400501b00701b32f00541d33000533400707d00502301b07d005", - "0x4701b01b33400501b00701b32b00541e32c32e007334007330048007054", - "0x701b33500541f32802500733400702300504601b32e00533400532e005", - "0x2500533400502500504201b00900533400532800504501b01b33400501b", - "0x3300542002a02f00733400702500504601b00900533400500900502001b", - "0x33400502f00504201b0b500533400502a00504501b01b33400501b00701b", - "0x42132207c00733400702f00504601b0b50053340050b500502001b02f005", - "0x33400507c00533001b01b33400501b33201b01b33400501b00701b192005", - "0x532c00506101b01b3340050b500532e01b01b33400532200532f01b01b", - "0x501b02501b32100533400501b32b01b01b33400500900532e01b01b334", - "0x3b00533400503932100732801b03900533400503900502001b039005334", - "0x3800502f01b03800533400503b03a00700901b03a00533400501b33501b", - "0x4700533400504700502a01b32e00533400532e00504701b209005334005", - "0x4732e0480052090053340052090050b501b00700533400500700503301b", - "0x33400519200533001b01b33400501b33201b01b33400501b00701b209007", - "0x32e02419201b20d00533400520d00532201b20d00533400501b07c01b01b", - "0x504401b01b33400501b00701b21e21a00742221821600733400720d047", - "0x22822400733400522400535c01b01b33400501b04801b2240053340050b5", - "0x701b22900542301b3340072280052f801b21600533400521600504701b", - "0x32e01b01b33400532c00506101b01b33400500900532e01b01b33400501b", - "0x533400500700503301b22a00533400521800502a01b01b334005224005", - "0x1b3340052290052f701b01b33400501b00701b01b42400501b19301b22b", - "0x23100535d01b23132c00733400532c0050d101b22e00533400501b32b01b", - "0x533400500900504401b04e00533400505122e00732801b051005334005", - "0x1b23900533400505204e00732801b05204f00733400504f00535c01b04f", - "0x523d00502001b23d00533400523c2240072f901b23c00533400501b04f", - "0x5600733400505400520d01b05400533400523d23900732801b23d005334", - "0x5300525d01b05300533400505500521801b01b33400505600521601b055", - "0x2442525f25d25302433400705304f32c00721804706001b053005334005", - "0x25300502a01b01b33400525f00523101b01b33400501b00701b28405e035", - "0x32b01b01b33400501b33201b22b00533400525d00503301b22a005334005", - "0x33400506000521601b00606000733400506100520d01b06100533400501b", - "0x521e01b06900533400506700521a01b06700533400500600521801b01b", - "0x533400522a00502a01b21600533400521600504701b2ed005334005069", - "0x2160480052ed0053340052ed0050b501b22b00533400522b00503301b22a", - "0x33400501b33501b01b33400501b33201b01b33400501b00701b2ed22b22a", - "0x1b06f00533400506d00502f01b06d00533400528406c00700901b06c005", - "0x505e00503301b03500533400503500502a01b216005334005216005047", - "0x1b00701b06f05e03521604800506f00533400506f0050b501b05e005334", - "0x532e01b01b33400532c00506101b01b3340050b500532e01b01b334005", - "0x2001b31500533400501b22901b31600533400501b32b01b01b334005009", - "0x33400501b33501b03600533400531531600732801b315005334005315005", - "0x1b07100533400507200502f01b07200533400503602600700901b026005", - "0x500700503301b21e00533400521e00502a01b21a00533400521a005047", - "0x1b00701b07100721e21a0480050710053340050710050b501b007005334", - "0x900532e01b01b33400503300533001b01b33400501b33201b01b334005", - "0x1b00601b07700533400501b32b01b01b33400532c00506101b01b334005", - "0x533400531107700732801b31100533400531100502001b311005334005", - "0x502f01b30f00533400507907500700901b07500533400501b33501b079", - "0x533400504700502a01b32e00533400532e00504701b30e00533400530f", - "0x32e04800530e00533400530e0050b501b00700533400500700503301b047", - "0x533500533001b01b33400501b33201b01b33400501b00701b30e007047", - "0x501b22a01b30d00533400501b32b01b01b33400532c00506101b01b334", - "0x30b00533400530c30d00732801b30c00533400530c00502001b30c005334", - "0x30600502f01b30600533400530b30a00700901b30a00533400501b33501b", - "0x4700533400504700502a01b32e00533400532e00504701b085005334005", - "0x4732e0480050850053340050850050b501b00700533400500700503301b", - "0x532b00504701b01b33400502300533001b01b33400501b00701b085007", - "0x532f00522b01b01b33400501b00701b01b42600501b19301b305005334", - "0x1b33201b30500533400504800504701b01b33400502300533001b01b334", - "0x502001b08300533400501b22e01b30400533400501b32b01b01b334005", - "0x533400501b33501b30300533400508330400732801b083005334005083", - "0x4701b30100533400508100502f01b08100533400530330200700901b302", - "0x33400500700503301b04700533400504700502a01b305005334005305005", - "0x501b00701b3010070473050480053010053340053010050b501b007005", - "0x501b22901b30000533400501b32b01b01b33400502400523101b01b334", - "0x7f0053340052ff30000732801b2ff0053340052ff00502001b2ff005334", - "0x33d00502f01b33d00533400507f08700700901b08700533400501b33501b", - "0x4500533400504500502a01b04600533400504600504701b2fc005334005", - "0x450460480052fc0053340052fc0050b501b00700533400500700503301b", - "0x742704604700733400700700500700501b01b33400501b01b01b2fc007", - "0x4700504701b04300533400504800502401b01b33400501b00701b044045", - "0x501b00701b19300542804104200733400704300504601b047005334005", - "0x2001b04200533400504200504201b02700533400504100504501b01b334", - "0x701b07d00542902304000733400704200504601b027005334005027005", - "0x4000533400504000504201b02000533400502300504501b01b33400501b", - "0x32f00542a33033200733400704000504601b02000533400502000502001b", - "0x33400533200504201b32e00533400533000504501b01b33400501b00701b", - "0x42b32b32c00733400733200504601b32e00533400532e00502001b332005", - "0x532b00532f01b01b33400532c00533001b01b33400501b00701b025005", - "0x2700532e01b01b33400502000532e01b01b33400532e00532e01b01b334", - "0x502001b33500533400501b02501b32800533400501b32b01b01b334005", - "0x533400501b33501b00900533400533532800732801b335005334005335", - "0xbc01b03300533400502a00502f01b02a00533400500902f00700901b02f", - "0x33400504600502a01b04700533400504700504701b01b00533400501b005", - "0x470050330053340050330050b501b02400533400502400503301b046005", - "0x7c01b01b33400502500533001b01b33400501b00701b03302404604701b", - "0x70b504604702419201b0b50053340050b500532201b0b500533400501b", - "0x33400502700504401b01b33400501b00701b32119200742c32207c007334", - "0x30501b03a00533400532e00504401b03b00533400502000504401b039005", - "0x533400532200502a01b07c00533400507c00504701b03800533400501b", - "0x502001b02400533400502400503301b01b00533400501b0050bc01b322", - "0x533400503a00502001b03b00533400503b00502001b039005334005039", - "0x21a21821620d20904733400503a03b03903802401b32207c0440bb01b03a", - "0x530201b01b33400501b00701b22400542d21e00533400721a00530301b", - "0x22a22900733400522800520d01b22800533400501b32b01b01b33400521e", - "0x522b00521a01b22b00533400522a00521801b01b33400522900521601b", - "0x1b2160053340052160050bc01b23100533400522e00521e01b22e005334", - "0x521800503301b20d00533400520d00502a01b209005334005209005047", - "0x701b23121820d2092160470052310053340052310050b501b218005334", - "0x2160053340052160050bc01b05100533400522400502f01b01b33400501b", - "0x21800503301b20d00533400520d00502a01b20900533400520900504701b", - "0x1b05121820d2092160470050510053340050510050b501b218005334005", - "0x1b01b33400502000532e01b01b33400532e00532e01b01b33400501b007", - "0x4f00533400501b22901b04e00533400501b32b01b01b33400502700532e", - "0x1b33501b05200533400504f04e00732801b04f00533400504f00502001b", - "0x533400523c00502f01b23c00533400505223900700901b239005334005", - "0x502a01b19200533400519200504701b01b00533400501b0050bc01b23d", - "0x533400523d0050b501b02400533400502400503301b321005334005321", - "0x33400532f00533001b01b33400501b00701b23d02432119201b04700523d", - "0x33400501b32b01b01b33400502000532e01b01b33400502700532e01b01b", - "0x732801b05600533400505600502001b05600533400501b00601b054005", - "0x33400505505300700901b05300533400501b33501b055005334005056054", - "0x4701b01b00533400501b0050bc01b25d00533400525300502f01b253005", - "0x33400502400503301b04600533400504600502a01b047005334005047005", - "0x1b00701b25d02404604701b04700525d00533400525d0050b501b024005", - "0x1b32b01b01b33400502700532e01b01b33400507d00533001b01b334005", - "0x1b03500533400503500502001b03500533400501b22a01b25f005334005", - "0x5e28400700901b28400533400501b33501b05e00533400503525f007328", - "0x1b00533400501b0050bc01b06000533400506100502f01b061005334005", - "0x2400503301b04600533400504600502a01b04700533400504700504701b", - "0x1b06002404604701b0470050600053340050600050b501b024005334005", - "0x1b00600533400501b32b01b01b33400519300533001b01b33400501b007", - "0x506700600732801b06700533400506700502001b06700533400501b22e", - "0x1b06c0053340050692ed00700901b2ed00533400501b33501b069005334", - "0x504700504701b01b00533400501b0050bc01b06d00533400506c00502f", - "0x1b02400533400502400503301b04600533400504600502a01b047005334", - "0x1b33400501b00701b06d02404604701b04700506d00533400506d0050b5", - "0x533400501b22901b06f00533400501b32b01b01b33400504800523101b", - "0x33501b31500533400531606f00732801b31600533400531600502001b316", - "0x33400502600502f01b02600533400531503600700901b03600533400501b", - "0x2a01b04500533400504500504701b01b00533400501b0050bc01b072005", - "0x3340050720050b501b02400533400502400503301b044005334005044005", - "0x2400500700501b01b33400501b01b01b07202404404501b047005072005", - "0x504700502401b01b33400501b00701b04304400742e045046007334007", - "0x504601b04600533400504600504701b01b33400501b04801b042005334", - "0x519300504501b01b33400501b00701b02700542f193041007334007042", - "0x1b04100533400504100504201b02300533400504000504401b040005334", - "0x1b33200543002007d00733400704100504601b023005334005023005020", - "0x533400507d00504201b33000533400502000505601b01b33400501b007", - "0x33400501b00701b01b43100501b19301b32e00533400533000505501b32f", - "0x33200504201b32b00533400532c00505301b32c00533400501b02701b01b", - "0x2500533400732e00525301b32e00533400532b00505501b32f005334005", - "0x504401b33500533400502500504501b01b33400501b00701b328005432", - "0x3340070090460070be01b00900533400500900502001b009005334005335", - "0x33400502f00504701b01b33400501b00701b07c0b503302443302a02f007", - "0x1b33400501b00701b32100543419232200733400732f00504601b02f005", - "0x3900505501b03b00533400532200504201b03900533400519200505601b", - "0x501b02701b01b33400501b00701b01b43500501b19301b03a005334005", - "0x1b03b00533400532100504201b20900533400503800505301b038005334", - "0x701b21600543620d00533400703a00525301b03a005334005209005055", - "0x21a00533400521800504401b21800533400520d00504501b01b33400501b", - "0x2443722421e00733400721a02f0070be01b21a00533400521a00502001b", - "0x504601b21e00533400521e00504701b01b33400501b00701b22a229228", - "0x33400501b33201b01b33400501b00701b23100543822e22b00733400703b", - "0x52240050c001b01b33400522e00532f01b01b33400522b00533001b01b", - "0x501b32b01b01b33400502300532e01b01b33400502a0050c001b01b334", - "0x32801b04e00533400504e00502001b04e00533400501b02501b051005334", - "0x504f05200700901b05200533400501b33501b04f00533400504e051007", - "0x1b01b00533400501b0050bc01b23c00533400523900502f01b239005334", - "0x504500502a01b0070053340050070052d501b21e00533400521e005047", - "0x523c00533400523c0050b501b04800533400504800503301b045005334", - "0x1b33400523100533001b01b33400501b00701b23c04804500721e01b046", - "0x4521e02419201b23d00533400523d00532201b23d00533400501b07c01b", - "0x501b33201b01b33400501b00701b05305500743905605400733400723d", - "0x25d0053340052530230072ce01b25300533400522402a0070c401b01b334", - "0x505600502a01b05400533400505400504701b25f00533400501b30501b", - "0x1b01b00533400501b0050bc01b0070053340050070052d501b056005334", - "0x560540452da01b25d00533400525d00535e01b048005334005048005033", - "0x33400700600530301b00606006128405e03504633400525d25f04801b007", - "0x32b01b01b33400506700530201b01b33400501b00701b06900543a067005", - "0x33400506c00521601b06d06c0073340052ed00520d01b2ed00533400501b", - "0x521e01b31600533400506f00521a01b06f00533400506d00521801b01b", - "0x533400503500504701b0610053340050610050bc01b315005334005316", - "0x503301b05e00533400505e00502a01b2840053340052840052d501b035", - "0x6005e2840350610460053150053340053150050b501b060005334005060", - "0x50610050bc01b03600533400506900502f01b01b33400501b00701b315", - "0x1b2840053340052840052d501b03500533400503500504701b061005334", - "0x50360050b501b06000533400506000503301b05e00533400505e00502a", - "0x1b33201b01b33400501b00701b03606005e284035061046005036005334", - "0x532e01b01b33400502a0050c001b01b3340052240050c001b01b334005", - "0x2001b07200533400501b22901b02600533400501b32b01b01b334005023", - "0x33400501b33501b07100533400507202600732801b072005334005072005", - "0x1b07900533400531100502f01b31100533400507107700700901b077005", - "0x50070052d501b05500533400505500504701b01b00533400501b0050bc", - "0x1b04800533400504800503301b05300533400505300502a01b007005334", - "0x33400501b00701b07904805300705501b0460050790053340050790050b5", - "0x503b00533001b01b33400522a0050c001b01b3340052290050c001b01b", - "0x22800504701b01b33400502a0050c001b01b33400502300532e01b01b334", - "0x21600522b01b01b33400501b00701b01b43b00501b19301b075005334005", - "0x50c001b01b33400502300532e01b01b33400503b00533001b01b334005", - "0x30f00533400507500535f01b07500533400502f00504701b01b33400502a", - "0x1b01b3340050b50050c001b01b33400501b00701b01b43c00501b19301b", - "0x1b33400502300532e01b01b33400532f00533001b01b33400507c0050c0", - "0x1b33400501b00701b01b43d00501b19301b30e00533400503300504701b", - "0x33400502300532e01b01b33400532f00533001b01b33400532800522b01b", - "0x535f01b30f00533400530e00535f01b30e00533400504600504701b01b", - "0x533001b01b33400501b00701b01b43e00501b19301b30d00533400530f", - "0x32b01b01b33400501b33201b30d00533400504600504701b01b334005027", - "0x30b00533400530b00502001b30b00533400501b22e01b30c00533400501b", - "0x30600700901b30600533400501b33501b30a00533400530b30c00732801b", - "0x533400501b0050bc01b30500533400508500502f01b08500533400530a", - "0x502a01b0070053340050070052d501b30d00533400530d00504701b01b", - "0x53340053050050b501b04800533400504800503301b045005334005045", - "0x504700523101b01b33400501b00701b30504804500730d01b046005305", - "0x8300502001b08300533400501b22901b30400533400501b32b01b01b334", - "0x30200533400501b33501b30300533400508330400732801b083005334005", - "0x50bc01b30100533400508100502f01b08100533400530330200700901b", - "0x53340050070052d501b04400533400504400504701b01b00533400501b", - "0x50b501b04800533400504800503301b04300533400504300502a01b007", - "0x1b01b33400501b01b01b30104804300704401b046005301005334005301", - "0x1b01b33400501b00701b04504600743f04704800733400700501b007005", - "0x533400504800504701b01b33400501b04801b044005334005024005024", - "0x1b01b33400501b00701b04100544004204300733400704400504601b048", - "0x502700504301b02700533400519300504401b193005334005042005045", - "0x1b07d00533400504000504101b02300533400504300504201b040005334", - "0x4001b02000533400501b02701b01b33400501b00701b01b44100501b193", - "0x33400533200504101b02300533400504100504201b332005334005020005", - "0x1b01b33400501b00701b32f00544233000533400707d00502301b07d005", - "0x4701b01b33400501b00701b32b00544332c32e007334007330048007054", - "0x701b33500544432802500733400702300504601b32e00533400532e005", - "0x2f00533400500900504401b00900533400532800504501b01b33400501b", - "0x2500504601b02f00533400502f00502001b02500533400502500504201b", - "0x33400503300505601b01b33400501b00701b0b500544503302a007334007", - "0x19301b19200533400507c00505501b32200533400502a00504201b07c005", - "0x505301b32100533400501b02701b01b33400501b00701b01b44600501b", - "0x533400503900505501b3220053340050b500504201b039005334005321", - "0x4501b01b33400501b00701b03a00544703b00533400719200525301b192", - "0x33400520900502001b20900533400503800504401b03800533400503b005", - "0x1b00701b21e21a21802444821620d00733400720932e0070be01b209005", - "0x22822400733400732200504601b20d00533400520d00504701b01b334005", - "0x504201b22a00533400522800505601b01b33400501b00701b229005449", - "0x1b01b44a00501b19301b22e00533400522a00505501b22b005334005224", - "0x5100533400523100505301b23100533400501b02701b01b33400501b007", - "0x22e00525301b22e00533400505100505501b22b00533400522900504201b", - "0x533400504e00504501b01b33400501b00701b04f00544b04e005334007", - "0x70be01b23900533400523900502001b23900533400505200504401b052", - "0x4701b01b33400501b00701b05505605402444c23d23c00733400723920d", - "0x701b25d00544d25305300733400722b00504601b23c00533400523c005", - "0x532f01b01b33400505300533001b01b33400501b33201b01b33400501b", - "0x6101b01b33400502f00532e01b01b33400523d0050c001b01b334005253", - "0x1b25f00533400501b32b01b01b3340052160050c001b01b33400532c005", - "0x503525f00732801b03500533400503500502001b03500533400501b025", - "0x1b06100533400505e28400700901b28400533400501b33501b05e005334", - "0x504700502a01b23c00533400523c00504701b06000533400506100502f", - "0x50600053340050600050b501b00700533400500700503301b047005334", - "0x7c01b01b33400525d00533001b01b33400501b00701b06000704723c048", - "0x700604723c02419201b00600533400500600532201b00600533400501b", - "0x1b33400501b33201b01b33400501b00701b06c2ed00744e069067007334", - "0x2f0072ce01b06f00533400523d2160070c401b06d00533400501b32b01b", - "0x3340053150050c901b0363150073340053160052c801b31600533400506f", - "0xca01b0260360073340050360052c701b03600533400503600535e01b01b", - "0x33400507200504401b01b33400507100536101b071072007334005026005", - "0x750790073340050360050ca01b31100533400507706d00732801b077005", - "0x30f0052c401b30e30f0073340050750052c501b01b33400507900532e01b", - "0x533400530c31100732801b30c00533400530d0052be01b30d005334005", - "0x732801b30600533400530a0052be01b30a00533400530e0052c401b30b", - "0x733400508500520d01b30500533400501b0cf01b08500533400530630b", - "0x502001b30300533400508300521801b01b33400530400521601b083304", - "0x533400506700504701b30300533400530300525d01b305005334005305", - "0x7f2ff30002444f30108130202433400730330532c00706904706001b067", - "0x8700533400501b32b01b01b33400530100523101b01b33400501b00701b", - "0x2fc00521801b01b33400533d00521601b2fc33d00733400508700520d01b", - "0x2f90053340052fa00521e01b2fa0053340052fb00521a01b2fb005334005", - "0x8100503301b30200533400530200502a01b06700533400506700504701b", - "0x701b2f90813020670480052f90053340052f90050b501b081005334005", - "0x2f700533400507f2f800700901b2f800533400501b33501b01b33400501b", - "0x30000502a01b06700533400506700504701b2f60053340052f700502f01b", - "0x2f60053340052f60050b501b2ff0053340052ff00503301b300005334005", - "0xc001b01b33400501b33201b01b33400501b00701b2f62ff300067048005", - "0x1b01b33400532c00506101b01b33400502f00532e01b01b33400523d005", - "0x2f400533400501b22901b2f500533400501b32b01b01b3340052160050c0", - "0x1b33501b2f30053340052f42f500732801b2f40053340052f400502001b", - "0x53340052f100502f01b2f10053340052f32f200700901b2f2005334005", - "0x503301b06c00533400506c00502a01b2ed0053340052ed00504701b2ee", - "0x1b2ee00706c2ed0480052ee0053340052ee0050b501b007005334005007", - "0x1b01b3340050550050c001b01b3340050560050c001b01b33400501b007", - "0x1b33400502f00532e01b01b3340052160050c001b01b33400522b005330", - "0x45000501b19301b07e00533400505400504701b01b33400532c00506101b", - "0x33400522b00533001b01b33400504f00522b01b01b33400501b00701b01b", - "0x532c00506101b01b33400502f00532e01b01b3340052160050c001b01b", - "0x19301b08b00533400507e00535f01b07e00533400520d00504701b01b334", - "0x50c001b01b33400521a0050c001b01b33400501b00701b01b45100501b", - "0x32e01b01b33400532c00506101b01b33400532200533001b01b33400521e", - "0x1b01b45200501b19301b08d00533400521800504701b01b33400502f005", - "0x1b01b33400532200533001b01b33400503a00522b01b01b33400501b007", - "0x533400532e00504701b01b33400502f00532e01b01b33400532c005061", - "0x1b19301b2ec00533400508b00535f01b08b00533400508d00535f01b08d", - "0x32c00506101b01b33400533500533001b01b33400501b00701b01b453005", - "0x1b32b01b01b33400501b33201b2ec00533400532e00504701b01b334005", - "0x1b2eb0053340052eb00502001b2eb00533400501b22a01b08f005334005", - "0x842ea00700901b2ea00533400501b33501b0840053340052eb08f007328", - "0x2ec0053340052ec00504701b2e70053340052e900502f01b2e9005334005", - "0x2e70050b501b00700533400500700503301b04700533400504700502a01b", - "0x2300533001b01b33400501b00701b2e70070472ec0480052e7005334005", - "0x1b00701b01b45400501b19301b09700533400532b00504701b01b334005", - "0x504701b01b33400502300533001b01b33400532f00522b01b01b334005", - "0x22e01b2e600533400501b32b01b01b33400501b33201b097005334005048", - "0x3340052e52e600732801b2e50053340052e500502001b2e500533400501b", - "0x2f01b2e20053340052e42e300700901b2e300533400501b33501b2e4005", - "0x33400504700502a01b09700533400509700504701b2e00053340052e2005", - "0x480052e00053340052e00050b501b00700533400500700503301b047005", - "0x1b32b01b01b33400502400523101b01b33400501b00701b2e0007047097", - "0x1b09e00533400509e00502001b09e00533400501b22901b2df005334005", - "0x2de0a500700901b0a500533400501b33501b2de00533400509e2df007328", - "0x4600533400504600504701b2dd0053340050a100502f01b0a1005334005", - "0x2dd0050b501b00700533400500700503301b04500533400504500502a01b", - "0x1b00700501b01b33400501b01b01b2dd0070450460480052dd005334005", - "0x4800502401b01b33400501b00701b044045007455046047007334007007", - "0x4200733400704300504601b04700533400504700504701b043005334005", - "0x532f01b01b33400504200533001b01b33400501b00701b193005456041", - "0x2001b04000533400501b02501b02700533400501b32b01b01b334005041", - "0x33400501b33501b02300533400504002700732801b040005334005040005", - "0x1b33200533400502000502f01b02000533400502307d00700901b07d005", - "0x504600502a01b0050053340050050052bb01b047005334005047005047", - "0x53320053340053320050b501b02400533400502400503301b046005334", - "0x1b01b33400519300533001b01b33400501b00701b332024046005047047", - "0x33004604702419201b33000533400533000532201b33000533400501b07c", - "0x33400501b30501b01b33400501b00701b32b32c00745732e32f007334007", - "0x2a01b0050053340050050052bb01b32f00533400532f00504701b025005", - "0x32e00532f0472b901b02400533400502400503301b32e00533400532e005", - "0x545803300533400702a00530301b02a02f009335328047334005025024", - "0x533400501b32b01b01b33400503300530201b01b33400501b00701b0b5", - "0x521801b01b33400532200521601b19232200733400507c00520d01b07c", - "0x533400503900521e01b03900533400532100521a01b321005334005192", - "0x502a01b3350053340053350052bb01b32800533400532800504701b03b", - "0x533400503b0050b501b02f00533400502f00503301b009005334005009", - "0x3340050b500502f01b01b33400501b00701b03b02f00933532804700503b", - "0x2a01b3350053340053350052bb01b32800533400532800504701b03a005", - "0x33400503a0050b501b02f00533400502f00503301b009005334005009005", - "0x33400501b32b01b01b33400501b00701b03a02f00933532804700503a005", - "0x732801b20900533400520900502001b20900533400501b22901b038005", - "0x33400520d21600700901b21600533400501b33501b20d005334005209038", - "0x2bb01b32c00533400532c00504701b21a00533400521800502f01b218005", - "0x33400502400503301b32b00533400532b00502a01b005005334005005005", - "0x1b00701b21a02432b00532c04700521a00533400521a0050b501b024005", - "0x1b22901b21e00533400501b32b01b01b33400504800523101b01b334005", - "0x533400522421e00732801b22400533400522400502001b224005334005", - "0x502f01b22a00533400522822900700901b22900533400501b33501b228", - "0x53340050050052bb01b04500533400504500504701b22b00533400522a", - "0x50b501b02400533400502400503301b04400533400504400502a01b005", - "0x501b01b33400501b01b01b22b02404400504504700522b00533400522b", - "0x2401b01b33400501b00701b044045007459046047007334007007005007", - "0x33400704300504601b04700533400504700504701b043005334005048005", - "0x2700533400504100504501b01b33400501b00701b19300545a041042007", - "0x4200504601b02700533400502700502001b04200533400504200504201b", - "0x33400504000533001b01b33400501b00701b07d00545b023040007334007", - "0x33400501b32b01b01b33400502700532e01b01b33400502300532f01b01b", - "0x732801b33200533400533200502001b33200533400501b02501b020005", - "0x33400533032f00700901b32f00533400501b33501b330005334005332020", - "0x4701b01b00533400501b0050bc01b32c00533400532e00502f01b32e005", - "0x33400502400503301b04600533400504600502a01b047005334005047005", - "0x1b00701b32c02404604701b04700532c00533400532c0050b501b024005", - "0x532201b32b00533400501b07c01b01b33400507d00533001b01b334005", - "0x933500745c32802500733400732b04604702419201b32b00533400532b", - "0x533400501b30501b02f00533400502700504401b01b33400501b00701b", - "0x50bc01b32800533400532800502a01b02500533400502500504701b02a", - "0x533400502f00502001b02400533400502400503301b01b00533400501b", - "0x30301b19232207c0b503304733400502f02a02401b3280250460c701b02f", - "0x532100530201b01b33400501b00701b03900545d321005334007192005", - "0x21601b03803a00733400503b00520d01b03b00533400501b32b01b01b334", - "0x533400520900521a01b20900533400503800521801b01b33400503a005", - "0x504701b07c00533400507c0050bc01b21600533400520d00521e01b20d", - "0x533400532200503301b0b50053340050b500502a01b033005334005033", - "0x501b00701b2163220b503307c0470052160053340052160050b501b322", - "0x4701b07c00533400507c0050bc01b21800533400503900502f01b01b334", - "0x33400532200503301b0b50053340050b500502a01b033005334005033005", - "0x1b00701b2183220b503307c0470052180053340052180050b501b322005", - "0x1b22901b21a00533400501b32b01b01b33400502700532e01b01b334005", - "0x533400521e21a00732801b21e00533400521e00502001b21e005334005", - "0x502f01b22900533400522422800700901b22800533400501b33501b224", - "0x533400533500504701b01b00533400501b0050bc01b22a005334005229", - "0x50b501b02400533400502400503301b00900533400500900502a01b335", - "0x33001b01b33400501b00701b22a02400933501b04700522a00533400522a", - "0x1b22e00533400501b22e01b22b00533400501b32b01b01b334005193005", - "0x501b33501b23100533400522e22b00732801b22e00533400522e005020", - "0x4f00533400504e00502f01b04e00533400523105100700901b051005334", - "0x4600502a01b04700533400504700504701b01b00533400501b0050bc01b", - "0x4f00533400504f0050b501b02400533400502400503301b046005334005", - "0x1b33400504800523101b01b33400501b00701b04f02404604701b047005", - "0x33400523900502001b23900533400501b22901b05200533400501b32b01b", - "0x901b23d00533400501b33501b23c00533400523905200732801b239005", - "0x501b0050bc01b05600533400505400502f01b05400533400523c23d007", - "0x1b04400533400504400502a01b04500533400504500504701b01b005334", - "0x4404501b0470050560053340050560050b501b024005334005024005033", - "0x745e04704800733400700501b00700501b01b33400501b01b01b056024", - "0x4800504701b04400533400502400502401b01b33400501b00701b045046", - "0x501b00701b04100545f04204300733400704400504601b048005334005", - "0x2001b04300533400504300504201b19300533400504200504501b01b334", - "0x701b02300546004002700733400704300504601b193005334005193005", - "0x32e01b01b33400504000532f01b01b33400502700533001b01b33400501b", - "0x1b02000533400501b02501b07d00533400501b32b01b01b334005193005", - "0x501b33501b33200533400502007d00732801b020005334005020005020", - "0x32e00533400532f00502f01b32f00533400533233000700901b330005334", - "0x700503301b04700533400504700502a01b04800533400504800504701b", - "0x701b32e00704704804800532e00533400532e0050b501b007005334005", - "0x32201b32c00533400501b07c01b01b33400502300533001b01b33400501b", - "0x32800746102532b00733400732c04704802419201b32c00533400532c005", - "0x533400501b2bc01b00900533400501b32b01b01b33400501b00701b335", - "0xd001b02a00533400502f00900732801b02f00533400502f00502001b02f", - "0x33400503302a00732801b03300533400503300502001b03300533400501b", - "0x1b1923220073340050b500520d01b07c00533400519300504401b0b5005", - "0x33400532100525d01b32100533400519200521801b01b334005322005216", - "0x733400732107c0070250482e001b32b00533400532b00504701b321005", - "0x20d00533400501b32b01b01b33400501b00701b20903803a02446203b039", - "0x21800521801b01b33400521600521601b21821600733400520d00520d01b", - "0x22400533400521e00521e01b21e00533400521a00521a01b21a005334005", - "0x3b00503301b03900533400503900502a01b32b00533400532b00504701b", - "0x701b22403b03932b0480052240053340052240050b501b03b005334005", - "0x22900533400520922800700901b22800533400501b33501b01b33400501b", - "0x3a00502a01b32b00533400532b00504701b22a00533400522900502f01b", - "0x22a00533400522a0050b501b03800533400503800503301b03a005334005", - "0x1b01b33400519300532e01b01b33400501b00701b22a03803a32b048005", - "0x533400522e00502001b22e00533400501b22901b22b00533400501b32b", - "0x700901b05100533400501b33501b23100533400522e22b00732801b22e", - "0x33400532800504701b04f00533400504e00502f01b04e005334005231051", - "0xb501b00700533400500700503301b33500533400533500502a01b328005", - "0x33001b01b33400501b00701b04f00733532804800504f00533400504f005", - "0x1b23900533400501b22e01b05200533400501b32b01b01b334005041005", - "0x501b33501b23c00533400523905200732801b239005334005239005020", - "0x5600533400505400502f01b05400533400523c23d00700901b23d005334", - "0x700503301b04700533400504700502a01b04800533400504800504701b", - "0x701b0560070470480480050560053340050560050b501b007005334005", - "0x22901b05500533400501b32b01b01b33400502400523101b01b33400501b", - "0x33400505305500732801b05300533400505300502001b05300533400501b", - "0x2f01b25f00533400525325d00700901b25d00533400501b33501b253005", - "0x33400504500502a01b04600533400504600504701b03500533400525f005", - "0x480050350053340050350050b501b00700533400500700503301b045005", - "0x4404500733400704801b00700501b01b33400501b01b01b035007045046", - "0x4701b04100533400504600502401b01b33400501b00701b042043007463", - "0x701b04000546402719300733400704100504601b045005334005045005", - "0x32b01b01b33400502700532f01b01b33400519300533001b01b33400501b", - "0x7d00533400507d00502001b07d00533400501b02501b02300533400501b", - "0x33200700901b33200533400501b33501b02000533400507d02300732801b", - "0x533400504500504701b32f00533400533000502f01b330005334005020", - "0x52b501b0070053340050070052b601b0050053340050050052c301b045", - "0x533400504700503301b04400533400504400502a01b024005334005024", - "0x701b32f04704402400700504504500532f00533400532f0050b501b047", - "0x32201b32e00533400501b07c01b01b33400504000533001b01b33400501b", - "0x2500746532b32c00733400732e04404502419201b32e00533400532e005", - "0x33400532c00504701b33500533400501b30501b01b33400501b00701b328", - "0x2c301b0240053340050240052b501b0070053340050070052b601b32c005", - "0x2400732c0462b401b32b00533400532b00502a01b005005334005005005", - "0x32200533400707c00530301b07c0b503302a02f00904633400533532b005", - "0x501b32b01b01b33400532200530201b01b33400501b00701b192005466", - "0x1b01b33400503900521601b03b03900733400532100520d01b321005334", - "0x503800521e01b03800533400503a00521a01b03a00533400503b005218", - "0x1b0330053340050330052c301b00900533400500900504701b209005334", - "0x50b500502a01b02a00533400502a0052b501b02f00533400502f0052b6", - "0x52090053340052090050b501b04700533400504700503301b0b5005334", - "0x33400519200502f01b01b33400501b00701b2090470b502a02f033009045", - "0x2b601b0330053340050330052c301b00900533400500900504701b20d005", - "0x3340050b500502a01b02a00533400502a0052b501b02f00533400502f005", - "0x4500520d00533400520d0050b501b04700533400504700503301b0b5005", - "0x21600533400501b32b01b01b33400501b00701b20d0470b502a02f033009", - "0x21821600732801b21800533400521800502001b21800533400501b22901b", - "0x22400533400521a21e00700901b21e00533400501b33501b21a005334005", - "0x50052c301b02500533400502500504701b22800533400522400502f01b", - "0x240053340050240052b501b0070053340050070052b601b005005334005", - "0x2280050b501b04700533400504700503301b32800533400532800502a01b", - "0x1b01b33400501b00701b228047328024007005025045005228005334005", - "0x22a00533400501b22901b22900533400501b32b01b01b334005046005231", - "0x1b33501b22b00533400522a22900732801b22a00533400522a00502001b", - "0x533400523100502f01b23100533400522b22e00700901b22e005334005", - "0x52b601b0050053340050050052c301b04300533400504300504701b051", - "0x533400504200502a01b0240053340050240052b501b007005334005007", - "0x430450050510053340050510050b501b04700533400504700503301b042", - "0x733400700701b00700501b01b33400501b01b01b051047042024007005", - "0x4300533400504800502401b01b33400501b00701b044045007467046047", - "0x19300546804104200733400704300504601b04700533400504700504701b", - "0x1b33400504100532f01b01b33400504200533001b01b33400501b00701b", - "0x33400504000502001b04000533400501b02501b02700533400501b32b01b", - "0x901b07d00533400501b33501b02300533400504002700732801b040005", - "0x504700504701b33200533400502000502f01b02000533400502307d007", - "0x1b04600533400504600502a01b0050053340050050052c301b047005334", - "0x460050470470053320053340053320050b501b024005334005024005033", - "0x33400501b07c01b01b33400519300533001b01b33400501b00701b332024", - "0x32f00733400733004604702419201b33000533400533000532201b330005", - "0x1b0050053340050050052c301b01b33400501b00701b32b32c00746932e", - "0x33400532f00504701b01b33400501b04801b3280250073340050050050d4", - "0x1b01b33400501b00701b00900546a33500533400732800509701b32f005", - "0x3340050250050d401b0250053340050250052c301b01b3340053350052e6", - "0x1b33400501b00701b0b500546b03300533400702a00509701b02a02f007", - "0x7c00533400501b32b01b01b3340050330052e601b01b33400501b33201b", - "0x19200521801b01b33400532200521601b19232200733400507c00520d01b", - "0x3b00533400503900521e01b03900533400532100521a01b321005334005", - "0x32e00502a01b02f00533400502f0052c301b32f00533400532f00504701b", - "0x3b00533400503b0050b501b02400533400502400503301b32e005334005", - "0x533400502f0052c301b01b33400501b00701b03b02432e02f32f047005", - "0x33400501b00701b01b46c00501b19301b0380053340050b50052c201b03a", - "0x1b33201b0380053340050090052c201b03a0053340050250052c301b01b", - "0x1b32f00533400532f00504701b20900533400503800502f01b01b334005", - "0x502400503301b32e00533400532e00502a01b03a00533400503a0052c3", - "0x701b20902432e03a32f0470052090053340052090050b501b024005334", - "0x2001b21600533400501b22901b20d00533400501b32b01b01b33400501b", - "0x33400501b33501b21800533400521620d00732801b216005334005216005", - "0x1b22400533400521e00502f01b21e00533400521821a00700901b21a005", - "0x532b00502a01b0050053340050050052c301b32c00533400532c005047", - "0x52240053340052240050b501b02400533400502400503301b32b005334", - "0x1b01b33400504800523101b01b33400501b00701b22402432b00532c047", - "0x533400522900502001b22900533400501b22901b22800533400501b32b", - "0x700901b22b00533400501b33501b22a00533400522922800732801b229", - "0x33400504500504701b23100533400522e00502f01b22e00533400522a22b", - "0x3301b04400533400504400502a01b0050053340050050052c301b045005", - "0x240440050450470052310053340052310050b501b024005334005024005", - "0x33400501b23c01b04500533400501b23901b04700533400501b23901b231", - "0x4200746d04304400733400700501b00700501b01b33400501b01b01b01b", - "0x33400501b04801b19300533400502400502401b01b33400501b00701b041", - "0x546e04002700733400719300504601b04400533400504400504701b01b", - "0x507d00504401b07d00533400504000504501b01b33400501b00701b023", - "0x1b33000533400502700504201b33200533400502000504301b020005334", - "0x1b01b33400501b00701b01b46f00501b19301b32f005334005332005041", - "0x33400502300504201b32c00533400532e00504001b32e00533400501b027", - "0x547004800533400732f00502301b32f00533400532c00504101b330005", - "0x4400705401b04800533400504804700723d01b01b33400501b00701b32b", - "0x502500504701b01b33400501b00701b335005471328025007334007048", - "0x33400501b00701b02a00547202f00900733400733000504601b025005334", - "0x4401b04600533400504604500723d01b04600533400502f00504501b01b", - "0x33400700900504601b00900533400500900504201b033005334005046005", - "0x19200533400507c00505601b01b33400501b00701b32200547307c0b5007", - "0x501b19301b03900533400519200505501b3210053340050b500504201b", - "0x503b00505301b03b00533400501b02701b01b33400501b00701b01b474", - "0x1b03900533400503a00505501b32100533400532200504201b03a005334", - "0x501b33201b01b33400501b00701b209005475038005334007039005253", - "0x521801b21600533400501b32b01b20d00533400503800504501b01b334", - "0x533400502500504701b21a00533400520d00504401b218005334005321", - "0x522401b21800533400521800525d01b04300533400504300502a01b025", - "0x21621804302504725f01b21a00533400521a00502001b216005334005216", - "0x701b22a00547622900533400722800503501b22822421e02433400521a", - "0x533400722e00528401b22e22b00733400522900505e01b01b33400501b", - "0x4601b04e00533400522b00502401b01b33400501b00701b051005477231", - "0x4f00533001b01b33400501b00701b23900547805204f00733400704e005", - "0x532e01b01b33400523100521601b01b33400505200532f01b01b334005", - "0x2501b23c00533400501b32b01b01b33400532800506101b01b334005033", - "0x33400523d23c00732801b23d00533400523d00502001b23d00533400501b", - "0x2f01b05500533400505405600700901b05600533400501b33501b054005", - "0x33400522400502a01b21e00533400521e00504701b053005334005055005", - "0x480050530053340050530050b501b00700533400500700503301b224005", - "0x1b07c01b01b33400523900533001b01b33400501b00701b05300722421e", - "0x33400725322421e02419201b25300533400525300532201b253005334005", - "0x28400533400501b30501b01b33400501b00701b05e03500747925f25d007", - "0x700503301b25f00533400525f00502a01b25d00533400525d00504701b", - "0x3300533400503300502001b3280053340053280050d601b007005334005", - "0x33400523103332828400725f25d0452bf01b23100533400523100522401b", - "0x501b00701b2ed00547a06900533400706700530301b067006060061048", - "0x6c00520d01b06c00533400501b32b01b01b33400506900530201b01b334", - "0x31600533400506f00521801b01b33400506d00521601b06f06d007334005", - "0x6100504701b03600533400531500521e01b31500533400531600521a01b", - "0x600533400500600503301b06000533400506000502a01b061005334005", - "0x1b33400501b00701b0360060600610480050360053340050360050b501b", - "0x6000502a01b06100533400506100504701b0260053340052ed00502f01b", - "0x260053340050260050b501b00600533400500600503301b060005334005", - "0x1b01b33400523100521601b01b33400501b00701b026006060061048005", - "0x7200533400501b32b01b01b33400532800506101b01b33400503300532e", - "0x7107200732801b07100533400507100502001b07100533400501b22901b", - "0x7900533400507731100700901b31100533400501b33501b077005334005", - "0x5e00502a01b03500533400503500504701b07500533400507900502f01b", - "0x750053340050750050b501b00700533400500700503301b05e005334005", - "0x1b01b33400505100522b01b01b33400501b00701b07500705e035048005", - "0x1b33400532800506101b01b33400503300532e01b01b33400522b005231", - "0x501b19301b30e00533400522400502a01b30f00533400521e00504701b", - "0x503300532e01b01b33400532800506101b01b33400501b00701b01b47b", - "0x2a01b21e00533400521e00504701b30d00533400522a00502f01b01b334", - "0x33400530d0050b501b00700533400500700503301b224005334005224005", - "0x1b33400501b33201b01b33400501b00701b30d00722421e04800530d005", - "0x33400503300532e01b01b33400532800506101b01b33400520900522b01b", - "0x4300502a01b30f00533400502500504701b01b33400532100533001b01b", - "0x2001b30b00533400501b00601b30c00533400501b32b01b30e005334005", - "0x33400501b33501b30a00533400530b30c00732801b30b00533400530b005", - "0x1b30500533400508500502f01b08500533400530a30600700901b306005", - "0x500700503301b30e00533400530e00502a01b30f00533400530f005047", - "0x1b00701b30500730e30f0480053050053340053050050b501b007005334", - "0x32800506101b01b33400502a00533001b01b33400501b33201b01b334005", - "0x1b22a01b30400533400501b32b01b01b33400504500506701b01b334005", - "0x533400508330400732801b08300533400508300502001b083005334005", - "0x502f01b08100533400530330200700901b30200533400501b33501b303", - "0x533400504300502a01b02500533400502500504701b301005334005081", - "0x250480053010053340053010050b501b00700533400500700503301b043", - "0x33000533001b01b33400504500506701b01b33400501b00701b301007043", - "0x1b00701b01b47c00501b19301b30000533400533500504701b01b334005", - "0x533001b01b33400504500506701b01b33400532b00522b01b01b334005", - "0x1b30000533400504400504701b01b33400504700506701b01b334005330", - "0x1b07f00533400501b22e01b2ff00533400501b32b01b01b33400501b332", - "0x501b33501b08700533400507f2ff00732801b07f00533400507f005020", - "0x2fb0053340052fc00502f01b2fc00533400508733d00700901b33d005334", - "0x700503301b04300533400504300502a01b30000533400530000504701b", - "0x701b2fb0070433000480052fb0053340052fb0050b501b007005334005", - "0x6701b01b33400504500506701b01b33400502400523101b01b33400501b", - "0x1b2f900533400501b22901b2fa00533400501b32b01b01b334005047005", - "0x501b33501b2f80053340052f92fa00732801b2f90053340052f9005020", - "0x2f50053340052f600502f01b2f60053340052f82f700700901b2f7005334", - "0x700503301b04100533400504100502a01b04200533400504200504701b", - "0x1b01b2f50070410420480052f50053340052f50050b501b007005334005", - "0x701b04504600747d04704800733400700501b00700501b01b33400501b", - "0x4800533400504800504701b04400533400502400502401b01b33400501b", - "0x4501b01b33400501b00701b04100547e04204300733400704400504601b", - "0x533400504300504201b01b33400519300532e01b193005334005042005", - "0x1b01b33400501b00701b02300547f04002700733400704300504601b043", - "0x507d00502001b02700533400502700504201b07d005334005040005045", - "0x33400501b00701b33000548033202000733400702700504601b07d005334", - "0x507d00532e01b01b33400533200532f01b01b33400502000533001b01b", - "0x32e00502001b32e00533400501b02501b32f00533400501b32b01b01b334", - "0x32b00533400501b33501b32c00533400532e32f00732801b32e005334005", - "0x504701b32800533400502500502f01b02500533400532c32b00700901b", - "0x533400500700503301b04700533400504700502a01b048005334005048", - "0x33400501b00701b3280070470480480053280053340053280050b501b007", - "0x533500532201b33500533400501b07c01b01b33400533000533001b01b", - "0x701b03302a00748102f00900733400733504704802419201b335005334", - "0x1b07c00533400507d00504401b0b500533400501b32b01b01b33400501b", - "0x521601b32119200733400532200520d01b32200533400507c0b5007328", - "0x3b00533400503900521a01b03900533400532100521801b01b334005192", - "0x2f00502a01b00900533400500900504701b03a00533400503b00521e01b", - "0x3a00533400503a0050b501b00700533400500700503301b02f005334005", - "0x1b01b33400507d00532e01b01b33400501b00701b03a00702f009048005", - "0x533400520900502001b20900533400501b22901b03800533400501b32b", - "0x700901b21600533400501b33501b20d00533400520903800732801b209", - "0x33400502a00504701b21a00533400521800502f01b21800533400520d216", - "0xb501b00700533400500700503301b03300533400503300502a01b02a005", - "0x33001b01b33400501b00701b21a00703302a04800521a00533400521a005", - "0x1b22400533400501b22a01b21e00533400501b32b01b01b334005023005", - "0x501b33501b22800533400522421e00732801b224005334005224005020", - "0x22b00533400522a00502f01b22a00533400522822900700901b229005334", - "0x700503301b04700533400504700502a01b04800533400504800504701b", - "0x701b22b00704704804800522b00533400522b0050b501b007005334005", - "0x22e01b22e00533400501b32b01b01b33400504100533001b01b33400501b", - "0x33400523122e00732801b23100533400523100502001b23100533400501b", - "0x2f01b04f00533400505104e00700901b04e00533400501b33501b051005", - "0x33400504700502a01b04800533400504800504701b05200533400504f005", - "0x480050520053340050520050b501b00700533400500700503301b047005", - "0x1b32b01b01b33400502400523101b01b33400501b00701b052007047048", - "0x1b23c00533400523c00502001b23c00533400501b22901b239005334005", - "0x23d05400700901b05400533400501b33501b23d00533400523c239007328", - "0x4600533400504600504701b05500533400505600502f01b056005334005", - "0x550050b501b00700533400500700503301b04500533400504500502a01b", - "0x1b00700501b01b33400501b01b01b055007045046048005055005334005", - "0x2400502401b01b33400501b00701b045046007482047048007334007005", - "0x4300733400704400504601b04800533400504800504701b044005334005", - "0x32e01b19300533400504200504501b01b33400501b00701b041005483042", - "0x1b04300533400504300504201b01b33400501b04801b01b334005193005", - "0x504501b01b33400501b00701b023005484040027007334007043005046", - "0x533400502000504301b02000533400507d00504401b07d005334005040", - "0x1b19301b32f00533400533200504101b33000533400502700504201b332", - "0x32e00504001b32e00533400501b02701b01b33400501b00701b01b485005", - "0x32f00533400532c00504101b33000533400502300504201b32c005334005", - "0x707d01b01b33400501b00701b02500548632b00533400732f00502301b", - "0x32800504701b01b33400501b00701b00900548733532800733400732b048", - "0x501b00701b03300548802a02f00733400733000504601b328005334005", - "0x2001b02f00533400502f00504201b0b500533400502a00504501b01b334", - "0x701b19200548932207c00733400702f00504601b0b50053340050b5005", - "0x532f01b01b33400507c00533001b01b33400501b33201b01b33400501b", - "0x32b01b01b33400533500532c01b01b3340050b500532e01b01b334005322", - "0x3900533400503900502001b03900533400501b02501b32100533400501b", - "0x3a00700901b03a00533400501b33501b03b00533400503932100732801b", - "0x533400532800504701b20900533400503800502f01b03800533400503b", - "0x50b501b00700533400500700503301b04700533400504700502a01b328", - "0x1b33201b01b33400501b00701b209007047328048005209005334005209", - "0x532201b20d00533400501b07c01b01b33400519200533001b01b334005", - "0x21e21a00748a21821600733400720d04732802419201b20d00533400520d", - "0x533400501b32101b2240053340050b500504401b01b33400501b00701b", - "0x4701b22800533400522800503a01b22922400733400522400535c01b228", - "0x48b22b22a00733400722933522800721804703801b216005334005216005", - "0x732801b04e00533400501b32b01b01b33400501b00701b05123122e024", - "0x505200521601b23905200733400504f00520d01b04f00533400522404e", - "0x21e01b23d00533400523c00521a01b23c00533400523900521801b01b334", - "0x33400522a00502a01b21600533400521600504701b05400533400523d005", - "0x480050540053340050540050b501b22b00533400522b00503301b22a005", - "0x1b33501b01b33400522400532e01b01b33400501b00701b05422b22a216", - "0x533400505500502f01b05500533400505105600700901b056005334005", - "0x503301b22e00533400522e00502a01b21600533400521600504701b053", - "0x1b05323122e2160480050530053340050530050b501b231005334005231", - "0x1b01b33400533500532c01b01b3340050b500532e01b01b33400501b007", - "0x533400525d00502001b25d00533400501b22901b25300533400501b32b", - "0x700901b03500533400501b33501b25f00533400525d25300732801b25d", - "0x33400521a00504701b28400533400505e00502f01b05e00533400525f035", - "0xb501b00700533400500700503301b21e00533400521e00502a01b21a005", - "0x33201b01b33400501b00701b28400721e21a048005284005334005284005", - "0x32b01b01b33400533500532c01b01b33400503300533001b01b33400501b", - "0x6000533400506000502001b06000533400501b00601b06100533400501b", - "0x6700700901b06700533400501b33501b00600533400506006100732801b", - "0x533400532800504701b2ed00533400506900502f01b069005334005006", - "0x50b501b00700533400500700503301b04700533400504700502a01b328", - "0x533001b01b33400501b00701b2ed0070473280480052ed0053340052ed", - "0x701b01b48c00501b19301b06c00533400500900504701b01b334005330", - "0x4701b01b33400533000533001b01b33400502500522b01b01b33400501b", - "0x1b06d00533400501b32b01b01b33400501b33201b06c005334005048005", - "0x506f06d00732801b06f00533400506f00502001b06f00533400501b22a", - "0x1b03600533400531631500700901b31500533400501b33501b316005334", - "0x504700502a01b06c00533400506c00504701b02600533400503600502f", - "0x50260053340050260050b501b00700533400500700503301b047005334", - "0x32b01b01b33400504100533001b01b33400501b00701b02600704706c048", - "0x7100533400507100502001b07100533400501b22e01b07200533400501b", - "0x31100700901b31100533400501b33501b07700533400507107200732801b", - "0x533400504800504701b07500533400507900502f01b079005334005077", - "0x50b501b00700533400500700503301b04700533400504700502a01b048", - "0x523101b01b33400501b00701b075007047048048005075005334005075", - "0x2001b30e00533400501b22901b30f00533400501b32b01b01b334005024", - "0x33400501b33501b30d00533400530e30f00732801b30e00533400530e005", - "0x1b30a00533400530b00502f01b30b00533400530d30c00700901b30c005", - "0x500700503301b04500533400504500502a01b046005334005046005047", - "0x1b01b01b30a00704504604800530a00533400530a0050b501b007005334", - "0x1b00701b04504600748d04704800733400700501b00700501b01b334005", - "0x1b04800533400504800504701b04400533400502400502401b01b334005", - "0x504501b01b33400501b00701b04100548e042043007334007044005046", - "0x533400519300502001b04300533400504300504201b193005334005042", - "0x1b01b33400501b00701b02300548f04002700733400704300504601b193", - "0x507d00502001b02700533400502700504201b07d005334005040005045", - "0x33400501b00701b33000549033202000733400702700504601b07d005334", - "0x519300532e01b01b33400533200532f01b01b33400502000533001b01b", - "0x501b02501b32f00533400501b32b01b01b33400507d00532e01b01b334", - "0x32c00533400532e32f00732801b32e00533400532e00502001b32e005334", - "0x2500502f01b02500533400532c32b00700901b32b00533400501b33501b", - "0x4700533400504700502a01b04800533400504800504701b328005334005", - "0x470480480053280053340053280050b501b00700533400500700503301b", - "0x33400501b07c01b01b33400533000533001b01b33400501b00701b328007", - "0x900733400733504704802419201b33500533400533500532201b335005", - "0xd801b0b500533400501b2c001b01b33400501b00701b03302a00749102f", - "0x33400507d00504401b32200533400519300504401b07c0053340050b5005", - "0x390053340051923210072c101b32132200733400532200535c01b192005", - "0x507c0052b301b03b00533400503b00503a01b03b00533400501b32101b", - "0x1b00900533400500900504701b03900533400503900502001b07c005334", - "0x1b00701b21620d20902449203803a00733400703907c03b00702f047038", - "0x1b21a00533400532221800732801b21800533400501b32b01b01b334005", - "0x522400521801b01b33400521e00521601b22421e00733400521a00520d", - "0x1b22a00533400522900521e01b22900533400522800521a01b228005334", - "0x503800503301b03a00533400503a00502a01b009005334005009005047", - "0x1b00701b22a03803a00904800522a00533400522a0050b501b038005334", - "0x700901b22b00533400501b33501b01b33400532200532e01b01b334005", - "0x33400500900504701b23100533400522e00502f01b22e00533400521622b", - "0xb501b20d00533400520d00503301b20900533400520900502a01b009005", - "0x32e01b01b33400501b00701b23120d209009048005231005334005231005", - "0x1b05100533400501b32b01b01b33400507d00532e01b01b334005193005", - "0x504e05100732801b04e00533400504e00502001b04e00533400501b229", - "0x1b23900533400504f05200700901b05200533400501b33501b04f005334", - "0x503300502a01b02a00533400502a00504701b23c00533400523900502f", - "0x523c00533400523c0050b501b00700533400500700503301b033005334", - "0x32e01b01b33400502300533001b01b33400501b00701b23c00703302a048", - "0x1b05400533400501b22a01b23d00533400501b32b01b01b334005193005", - "0x501b33501b05600533400505423d00732801b054005334005054005020", - "0x25300533400505300502f01b05300533400505605500700901b055005334", - "0x700503301b04700533400504700502a01b04800533400504800504701b", - "0x701b2530070470480480052530053340052530050b501b007005334005", - "0x22e01b25d00533400501b32b01b01b33400504100533001b01b33400501b", - "0x33400525f25d00732801b25f00533400525f00502001b25f00533400501b", - "0x2f01b28400533400503505e00700901b05e00533400501b33501b035005", - "0x33400504700502a01b04800533400504800504701b061005334005284005", - "0x480050610053340050610050b501b00700533400500700503301b047005", - "0x1b32b01b01b33400502400523101b01b33400501b00701b061007047048", - "0x1b00600533400500600502001b00600533400501b22901b060005334005", - "0x6706900700901b06900533400501b33501b067005334005006060007328", - "0x4600533400504600504701b06c0053340052ed00502f01b2ed005334005", - "0x6c0050b501b00700533400500700503301b04500533400504500502a01b", - "0x1b00700501b01b33400501b33201b06c00704504604800506c005334005", - "0x4800535c01b01b33400501b00701b044045007493046047007334007005", - "0x1b3340070430052f801b04700533400504700504701b043048007334005", - "0x240052ab01b01b33400504800532e01b01b33400501b00701b042005494", - "0x53340051930052a801b1930053340050410070072ad01b041005334005", - "0x52a701b04600533400504600502a01b04700533400504700504701b027", - "0x420052f701b01b33400501b00701b027046047024005027005334005027", - "0x504601b01b33400501b04801b04000533400500700502401b01b334005", - "0x507d00504501b01b33400501b00701b02000549507d023007334007040", - "0x1b32f00533400533000504301b33000533400533200504401b332005334", - "0x49600501b19301b32c00533400532f00504101b32e005334005023005042", - "0x33400532b00504001b32b00533400501b02701b01b33400501b00701b01b", - "0x21801b32c00533400502500504101b32e00533400502000504201b025005", - "0x1b00701b00900549733500533400732c00502301b32800533400532e005", - "0x4f01b02f00533400533502400732801b01b33400501b33201b01b334005", - "0x33400504700504701b03300533400502a0480072f901b02a00533400501b", - "0x22401b32800533400532800525d01b04600533400504600502a01b047005", - "0x32804604704725f01b03300533400503300502001b02f00533400502f005", - "0x1b01b33400501b00701b32207c0b502400532207c0b502433400503302f", - "0x1b01b33400502400521601b01b33400504800532e01b01b33400501b332", - "0x3210052a801b3210053340051923280072ad01b1920053340050090050de", - "0x4600533400504600502a01b04700533400504700504701b039005334005", - "0x1b01b33400501b00701b0390460470240050390053340050390052a701b", - "0x1b33400500700523101b01b33400502400521601b01b33400504800532e", - "0x33400503a00502001b03a00533400501b22901b03b00533400501b32b01b", - "0x901b20900533400501b33501b03800533400503a03b00732801b03a005", - "0x504500504701b21600533400520d0052a501b20d005334005038209007", - "0x52160053340052160052a701b04400533400504400502a01b045005334", - "0x4704800733400700501b00700501b01b33400501b33201b216044045024", - "0x4701b04400533400502400502401b01b33400501b00701b045046007498", - "0x701b04100549904204300733400704400504601b048005334005048005", - "0x2700533400519300504401b19300533400504200504501b01b33400501b", - "0x521801b04000533400502700700732801b02700533400502700502001b", - "0x533400504700502a01b04800533400504800504701b023005334005043", - "0x4802601b02300533400502300525d01b04000533400504000522401b047", - "0x33400501b00701b33202007d02400533202007d024334005023040047048", - "0x3300070072a301b33000533400501b02701b01b33400504100533001b01b", - "0x4800533400504800504701b32e00533400532f0052a201b32f005334005", - "0x4704802400532e00533400532e00529f01b04700533400504700502a01b", - "0x33400500700521601b01b33400502400523101b01b33400501b00701b32e", - "0x532b00502001b32b00533400501b22901b32c00533400501b32b01b01b", - "0x1b32800533400501b33501b02500533400532b32c00732801b32b005334", - "0x4600504701b0090053340053350050e101b335005334005025328007009", - "0x900533400500900529f01b04500533400504500502a01b046005334005", - "0x4800733400700501b00700501b01b33400501b33201b009045046024005", - "0x1b04400533400500700502401b01b33400501b00701b04504600749a047", - "0x1b04100549b04204300733400704400504601b048005334005048005047", - "0x533400519300504401b19300533400504200504501b01b33400501b007", - "0x21801b04000533400502702400732801b02700533400502700502001b027", - "0x33400504700502a01b04800533400504800504701b023005334005043005", - "0x7501b04000533400504000522401b02300533400502300525d01b047005", - "0x501b00701b33202007d02400533202007d024334005040023047048048", - "0x240072a301b33000533400501b02701b01b33400504100533001b01b334", - "0x533400504800504701b32e00533400532f0052a201b32f005334005330", - "0x4802400532e00533400532e00529f01b04700533400504700502a01b048", - "0x500700523101b01b33400502400521601b01b33400501b00701b32e047", - "0x32b00502001b32b00533400501b22901b32c00533400501b32b01b01b334", - "0x32800533400501b33501b02500533400532b32c00732801b32b005334005", - "0x504701b0090053340053350050e101b33500533400502532800700901b", - "0x533400500900529f01b04500533400504500502a01b046005334005046", - "0x4700533400501b32b01b01b33400502400508401b009045046024005009", - "0x4604700732801b04600533400504600502001b04600533400501b04e01b", - "0x1b33400504400521601b04304400733400504500520d01b045005334005", - "0x4200529e01b04200533400504200525d01b04200533400504300521801b", - "0x4100700504829b01b19304200733400504200529e01b041042007334005", - "0x502a01b01b33400501b00701b02007d02302449c040027007334007193", - "0x32e32f02449d3303320073340070480400270242e201b027005334005027", - "0x33400533200502a01b32b00533400501b29a01b01b33400501b00701b32c", - "0x733400704232b3303320482e001b32b00533400532b00502001b332005", - "0x2a00533400501b2c001b01b33400501b00701b02f00933502449e328025", - "0x33400501b32101b0b500533400501b29a01b03300533400502a0050d801b", - "0x2b301b07c00533400507c00503a01b02500533400502500502a01b07c005", - "0x7c32802504703801b0b50053340050b500502001b033005334005033005", - "0x32b01b01b33400501b00701b03b03932102449f1923220073340070b5033", - "0x3800533400503800502001b03800533400501b29901b03a00533400501b", - "0x20d00700901b20d00533400501b33501b20900533400503803a00732801b", - "0x533400501b00504701b21800533400521600529801b216005334005209", - "0x529701b19200533400519200503301b32200533400532200502a01b01b", - "0x1b33501b01b33400501b00701b21819232201b048005218005334005218", - "0x533400521e00529801b21e00533400503b21a00700901b21a005334005", - "0x503301b32100533400532100502a01b01b00533400501b00504701b224", - "0x1b22403932101b04800522400533400522400529701b039005334005039", - "0x533400502f22800700901b22800533400501b33501b01b33400501b007", - "0x502a01b01b00533400501b00504701b22a00533400522900529801b229", - "0x533400522a00529701b00900533400500900503301b335005334005335", - "0x1b33400504200523101b01b33400501b00701b22a00933501b04800522a", - "0x22e00529801b22e00533400532c22b00700901b22b00533400501b33501b", - "0x32f00533400532f00502a01b01b00533400501b00504701b231005334005", - "0x32f01b04800523100533400523100529701b32e00533400532e00503301b", - "0x504800508501b01b33400504200523101b01b33400501b00701b23132e", - "0x29801b04e00533400502005100700901b05100533400501b33501b01b334", - "0x33400502300502a01b01b00533400501b00504701b04f00533400504e005", - "0x4800504f00533400504f00529701b07d00533400507d00503301b023005", - "0x4404500733400700501b00700501b01b33400501b33201b04f07d02301b", - "0x1b04104700733400504700529601b01b33400501b00701b0420430074a0", - "0x4500504701b02702400733400502400529601b193005334005041005293", - "0x1b33400501b00701b01b4a101b3340071930270070eb01b045005334005", - "0x507701b02300533400504000521801b04004600733400504600507701b", - "0x2300704404829b01b02000533400507d00521801b07d048007334005048", - "0x1b0ed01b01b33400501b00701b32c32e32f0244a2330332007334007020", - "0x33200533400533200502a01b32b00533400532b00507f01b32b005334005", - "0x4a332802500733400732b02404502429201b33000533400533000503301b", - "0x502a01b02500533400502500504701b01b33400501b00701b009335007", - "0x533400532800507f01b33000533400533000503301b332005334005332", - "0x504201b04700533400504700507f01b04800533400504800504201b328", - "0x2a02f04833400504604704832833033202504508701b046005334005046", - "0x33400500900530101b01b33400501b00701b0b503302a02f0480050b5033", - "0x504800533001b01b33400504700530101b01b33400504600533001b01b", - "0x32200502001b32200533400501b29101b07c00533400501b32b01b01b334", - "0x32100533400501b33501b19200533400532207c00732801b322005334005", - "0x504701b03b00533400503900529001b03900533400519232100700901b", - "0x533400533000503301b33200533400533200502a01b335005334005335", - "0x33400501b00701b03b33033233504800503b00533400503b0050ef01b330", - "0x504800533001b01b33400504700530101b01b33400504600533001b01b", - "0x3a00700901b03a00533400501b33501b01b33400502400530101b01b334", - "0x533400504500504701b20900533400503800529001b03800533400532c", - "0x50ef01b32e00533400532e00503301b32f00533400532f00502a01b045", - "0x533001b01b33400501b00701b20932e32f045048005209005334005209", - "0x2701b01b33400504800533001b01b33400504700530101b01b334005046", - "0x3340052160050f001b21600533400520d0240070f101b20d00533400501b", - "0x3301b04400533400504400502a01b04500533400504500504701b218005", - "0x2180070440450480052180053340052180050ef01b007005334005007005", - "0x1b33400504700530101b01b33400504600533001b01b33400501b00701b", - "0x533400501b32b01b01b33400502400530101b01b33400504800533001b", - "0x21a00732801b21e00533400521e00502001b21e00533400501b22901b21a", - "0x533400522422800700901b22800533400501b33501b22400533400521e", - "0x502a01b04300533400504300504701b22a00533400522900529001b229", - "0x533400522a0050ef01b00700533400500700503301b042005334005042", - "0x700700504601b00700533400500500502401b22a00704204304800522a", - "0x533400504800505601b01b33400501b00701b0470054a4048024007334", - "0x1b19301b04400533400504600505501b04500533400502400504201b046", - "0x4300505301b04300533400501b02701b01b33400501b00701b01b4a5005", - "0x4400533400504200505501b04500533400504700504201b042005334005", - "0x525301b19300533400504100521801b04104500733400504500507701b", - "0x33400502700504501b01b33400501b00701b0400054a6027005334007044", - "0x8101b07d00533400507d00502001b07d00533400502300504401b023005", - "0x523101b01b33400501b00701b3300054a733202000733400707d01b007", - "0x32f00733400704500504601b02000533400502000504701b01b334005193", - "0x4201b32b00533400532e00505601b01b33400501b00701b32c0054a832e", - "0x1b4a900501b19301b32800533400532b00505501b02500533400532f005", - "0x533400533500505301b33500533400501b02701b01b33400501b00701b", - "0x507701b32800533400500900505501b02500533400532c00504201b009", - "0x33400732800525301b02a00533400502f00521801b02f025007334005025", - "0x1b07c00533400503300504501b01b33400501b00701b0b50054aa033005", - "0x32202000708101b32200533400532200502001b32200533400507c005044", - "0x33400502a00523101b01b33400501b00701b0390054ab321192007334007", - "0x54ac03a03b00733400702500504601b19200533400519200504701b01b", - "0x520900504401b20900533400503a00504501b01b33400501b00701b038", - "0x1b21800533400503b00504201b21600533400520d00504301b20d005334", - "0x1b01b33400501b00701b01b4ad00501b19301b21a005334005216005041", - "0x33400503800504201b22400533400521e00504001b21e00533400501b027", - "0x2301b22800533400521800521801b21a00533400522400504101b218005", - "0x22919200705401b01b33400501b00701b22a0054ae22900533400721a005", - "0x22e3213320240ee01b01b33400501b00701b2310054af22e22b007334007", - "0x22b00533400522b00504701b04e00533400505100528f01b051005334005", - "0x22822b02400504e00533400504e00528e01b22800533400522800525d01b", - "0x33400532100530101b01b33400533200530101b01b33400501b00701b04e", - "0x33400501b00701b01b4b000501b19301b04f00533400523100504701b01b", - "0x532100530101b01b33400533200530101b01b33400522a00522b01b01b", - "0x50f701b05200533400501b02701b04f00533400519200504701b01b334", - "0x533400523900528e01b22800533400522800525d01b239005334005052", - "0x1b01b33400533200530101b01b33400501b00701b23922804f024005239", - "0x1b4b100501b19301b23c00533400503900504701b01b334005025005330", - "0x1b33400533200530101b01b3340050b500522b01b01b33400501b00701b", - "0x33400501b02701b23c00533400502000504701b01b33400502500533001b", - "0x28e01b02a00533400502a00525d01b05400533400523d0050f701b23d005", - "0x533001b01b33400501b00701b05402a23c024005054005334005054005", - "0x701b01b4b200501b19301b05600533400533000504701b01b334005045", - "0x4701b01b33400504500533001b01b33400504000522b01b01b33400501b", - "0x53340050550050f701b05500533400501b02701b05600533400501b005", - "0x5602400505300533400505300528e01b19300533400519300525d01b053", - "0x501b23901b04600533400501b23901b04800533400501b23901b053193", - "0x1b2ed01b19300533400501b23901b04200533400501b23901b044005334", - "0x1b33201b01b33400501b23c01b07d00533400501b23901b040005334005", - "0x33033200733400702000504601b02000533400500700502401b01b334005", - "0x723d01b04300533400533000504501b01b33400501b00701b32f0054b3", - "0x33400533200504201b32e00533400504300504401b043005334005043042", - "0x1b33400501b00701b0250054b432b32c00733400733200504601b332005", - "0x33500504301b33500533400532800504401b32800533400532b00504501b", - "0x2a00533400500900504101b02f00533400532c00504201b009005334005", - "0x1b03300533400501b02701b01b33400501b00701b01b4b500501b19301b", - "0x50b500504101b02f00533400502500504201b0b5005334005033005040", - "0x32200533400507c00521801b07c02f00733400502f00507701b02a005334", - "0x1b00701b1920054b604500533400702a00502301b01b33400501b04801b", - "0x733400704501b00705401b04500533400504504400723d01b01b334005", - "0x4701b01b33400532200523101b01b33400501b00701b03b0054b7039321", - "0x701b2090054b803803a00733400702f00504601b321005334005321005", - "0x21600533400503a00504201b20d00533400503800505601b01b33400501b", - "0x1b33400501b00701b01b4b900501b19301b21800533400520d00505501b", - "0x520900504201b21e00533400521a00505301b21a00533400501b02701b", - "0x1b22400533400521600521801b21800533400521e00505501b216005334", - "0x22800504501b01b33400501b00701b2290054ba228005334007218005253", - "0x533400502400504401b02400533400502404800723d01b024005334005", - "0x501b00701b04e0512310244bb22e22b00733400722a3210070be01b22a", - "0xf901b22400533400522400525d01b22b00533400522b00504701b01b334", - "0x1b23c0054bc2390053340070520050f801b05204f00733400522422b007", - "0x33400705400528d01b05423d0073340052390050f601b01b33400501b007", - "0x1b05500533400523d00502401b01b33400501b00701b0560054bd027005", - "0x25d0054be25305300733400705500504601b027005334005027040007036", - "0x33400505300504201b02300533400525300504501b01b33400501b00701b", - "0x3525f00733400705300504601b02300533400502307d00723d01b053005", - "0x504201b04100533400503500504501b01b33400501b00701b05e0054bf", - "0x33400725f00504601b04100533400504119300723d01b25f00533400525f", - "0x4700533400506100504501b01b33400501b00701b0600054c0061284007", - "0x4600723d01b06700533400504100504401b00600533400502300504401b", - "0x533400528400504201b06900533400504700504401b047005334005047", - "0x1b01b33400501b00701b06d0054c106c2ed00733400728400504601b284", - "0x506f00505501b3160053340052ed00504201b06f00533400506c005056", - "0x33400501b02701b01b33400501b00701b01b4c200501b19301b315005334", - "0x5501b31600533400506d00504201b02600533400503600505301b036005", - "0x1b00701b0710054c307200533400731500525301b315005334005026005", - "0x21801b31100533400501b28c01b07700533400507200504501b01b334005", - "0x33400504f00504701b07500533400507700504401b079005334005316005", - "0xff01b07900533400507900525d01b00500533400500500502a01b04f005", - "0x7900504f04710001b07500533400507500502001b311005334005311005", - "0x1b30b0054c430c00533400730d0050fe01b30d30e30f024334005075311", - "0x1b33400501b04801b30630a00733400530c00510101b01b33400501b007", - "0x528901b01b33400501b00701b3050054c508500533400730600528a01b", - "0x533400508300510901b01b33400530400510701b083304007334005085", - "0x504201b08100533400530a00502401b30200533400530300510801b303", - "0x1b01b4c600501b19301b30000533400530200510601b301005334005081", - "0x533400530a00502401b2ff00533400530500528801b01b33400501b007", - "0x511301b3000053340052ff00510601b30100533400507f00504201b07f", - "0x33400730100504601b01b33400501b00701b33d0054c7087005334007300", - "0x2f90053340052fb00505601b01b33400501b00701b2fa0054c82fb2fc007", - "0x501b19301b2f70053340052f900505501b2f80053340052fc00504201b", - "0x52f600505301b2f600533400501b02701b01b33400501b00701b01b4c9", - "0x1b2f70053340052f500505501b2f80053340052fa00504201b2f5005334", - "0x701b2f20054ca2f30053340072f700525301b2f40053340052f8005218", - "0x2ee0053340052f100504401b2f10053340052f300504501b01b33400501b", - "0x244cb08b07e0073340072ee30f0070be01b2ee0053340052ee00502001b", - "0x525d01b07e00533400507e00504701b01b33400501b00701b08f2ec08d", - "0x70840050f801b0842eb0073340052f407e0070f901b2f40053340052f4", - "0x2e70073340052ea0050f601b01b33400501b00701b2e90054cc2ea005334", - "0x2401b01b33400501b00701b2e50054cd2e600533400709700528d01b097", - "0x701b2e00054ce2e22e30073340072e400504601b2e40053340052e7005", - "0x9e0053340052e300504201b2df0053340052e200505601b01b33400501b", - "0x1b33400501b00701b01b4cf00501b19301b2de0053340052df00505501b", - "0x52e000504201b0a10053340050a500505301b0a500533400501b02701b", - "0x2dd09e00733400509e00507701b2de0053340050a100505501b09e005334", - "0x1b0ab0054d00a90053340072de00525301b2db0053340052dd00521801b", - "0x53340052d900504401b2d90053340050a900504501b01b33400501b007", - "0x4d12d62d70073340070ae2eb00710f01b0ae0053340050ae00502001b0ae", - "0x52d700504701b01b3340052db00523101b01b33400501b00701b2d5005", - "0x33400501b00701b2d20054d22d32d400733400709e00504601b2d7005334", - "0x505501b2d10053340052d400504201b0b40053340052d300505601b01b", - "0x1b02701b01b33400501b00701b01b4d300501b19301b2d00053340050b4", - "0x2d10053340052d200504201b0490053340052cf00505301b2cf005334005", - "0x2d000525301b3590053340052d100521801b2d000533400504900505501b", - "0x533400535a00504501b01b33400501b00701b35c0054d435a005334007", - "0x710f01b35d00533400535d00502001b35d0053340050d100504401b0d1", - "0xbc00504701b01b33400501b00701b0be0054d50bb0bc00733400735d2d7", - "0x73340053590bc0070f901b35900533400535900525d01b0bc005334005", - "0x1b01b33400501b00701b35e0054d62ce0053340070c40050f801b0c40c0", - "0x1b0c90054d72c800533400735f00528d01b35f2da0073340052ce0050f6", - "0x6700602722e03932e02710e01b01b33400501b33201b01b33400501b007", - "0x1b0ca0053340052c700528701b2c70053340052c80bb2d62e608b087069", - "0xc000504701b2c500533400536100511701b3610053340050ca2da007115", - "0x2c50053340052c500528501b30e00533400530e00502a01b0c0005334005", - "0x532e01b01b33400501b33201b01b33400501b00701b2c530e0c0024005", - "0x23101b01b3340052d600522801b01b3340050bb00522801b01b33400532e", - "0x1b01b33400508700528301b01b33400508b0050c001b01b3340052e6005", - "0x1b33400500600532e01b01b33400506700532e01b01b33400506900532e", - "0x33400503900506101b01b33400522e0050c001b01b33400502700523101b", - "0x11701b2be0053340052c42da00711501b2c40053340050c900528201b01b", - "0x33400530e00502a01b0c00053340050c000504701b0cf0053340052be005", - "0x33400501b00701b0cf30e0c00240050cf0053340050cf00528501b30e005", - "0x33400532e00532e01b01b33400503900506101b01b33400501b33201b01b", - "0x52e600523101b01b3340052d600522801b01b3340050bb00522801b01b", - "0x6900532e01b01b33400508700528301b01b33400508b0050c001b01b334", - "0x523101b01b33400500600532e01b01b33400506700532e01b01b334005", - "0x1b2bb00533400535e00501801b01b33400522e0050c001b01b334005027", - "0x52bb00528501b30e00533400530e00502a01b0c00053340050c0005047", - "0x33400522e0050c001b01b33400501b00701b2bb30e0c00240052bb005334", - "0x52d600522801b01b33400532e00532e01b01b33400503900506101b01b", - "0x8700528301b01b33400508b0050c001b01b3340052e600523101b01b334", - "0x532e01b01b33400506700532e01b01b33400506900532e01b01b334005", - "0x1b2b90053340050be00504701b01b33400502700523101b01b334005006", - "0xc001b01b33400535c00522b01b01b33400501b00701b01b4d800501b193", - "0x1b01b33400532e00532e01b01b33400503900506101b01b33400522e005", - "0x1b33400508b0050c001b01b3340052e600523101b01b3340052d6005228", - "0x33400506700532e01b01b33400506900532e01b01b33400508700528301b", - "0x52d700504701b01b33400502700523101b01b33400500600532e01b01b", - "0xc700528201b0c700533400501b02701b01b33400501b33201b2b9005334", - "0x53340050d000511701b0d00053340052bc35900711501b2bc005334005", - "0x2b90240052c30053340052c300528501b30e00533400530e00502a01b2c3", - "0x503900506101b01b33400522e0050c001b01b33400501b00701b2c330e", - "0x2700523101b01b33400509e00533001b01b33400532e00532e01b01b334", - "0x528301b01b33400508b0050c001b01b3340052e600523101b01b334005", - "0x32e01b01b33400506700532e01b01b33400506900532e01b01b334005087", - "0x1b01b4d900501b19301b2b60053340052d500504701b01b334005006005", - "0x1b01b33400522e0050c001b01b3340050ab00522b01b01b33400501b007", - "0x1b33400509e00533001b01b33400532e00532e01b01b334005039005061", - "0x33400508b0050c001b01b3340052e600523101b01b33400502700523101b", - "0x506700532e01b01b33400506900532e01b01b33400508700528301b01b", - "0x1b33201b2b60053340052eb00504701b01b33400500600532e01b01b334", - "0x11501b2b40053340052b500528201b2b500533400501b02701b01b334005", - "0x530e00502a01b2c20053340050d400511701b0d40053340052b42db007", - "0x501b00701b2c230e2b60240052c20053340052c200528501b30e005334", - "0x503900506101b01b33400522e0050c001b01b33400501b33201b01b334", - "0x8b0050c001b01b33400502700523101b01b33400532e00532e01b01b334", - "0x532e01b01b33400506900532e01b01b33400508700528301b01b334005", - "0x1b0d60053340052e500528201b01b33400500600532e01b01b334005067", - "0x2eb00504701b2c00053340052bf00511701b2bf0053340050d62e7007115", - "0x2c00053340052c000528501b30e00533400530e00502a01b2eb005334005", - "0x50c001b01b33400501b33201b01b33400501b00701b2c030e2eb024005", - "0x23101b01b33400532e00532e01b01b33400503900506101b01b33400522e", - "0x1b01b33400508b0050c001b01b33400500600532e01b01b334005027005", - "0x1b33400506700532e01b01b33400506900532e01b01b334005087005283", - "0x30e00502a01b2eb0053340052eb00504701b0d80053340052e900501801b", - "0x1b00701b0d830e2eb0240050d80053340050d800528501b30e005334005", - "0x50c001b01b33400508f0050c001b01b3340052ec0050c001b01b334005", - "0x32e01b01b33400532e00532e01b01b33400503900506101b01b33400522e", - "0x1b01b33400500600532e01b01b33400502700523101b01b334005067005", - "0x533400508d00504701b01b33400506900532e01b01b334005087005283", - "0x1b3340052f200522b01b01b33400501b00701b01b4da00501b19301b2c1", - "0x33400532e00532e01b01b33400503900506101b01b33400522e0050c001b", - "0x500600532e01b01b33400502700523101b01b33400506700532e01b01b", - "0x30f00504701b01b33400506900532e01b01b33400508700528301b01b334", - "0x528201b2b300533400501b02701b01b33400501b33201b2c1005334005", - "0x3340052ad00511701b2ad0053340052ab2f400711501b2ab0053340052b3", - "0x240052a80053340052a800528501b30e00533400530e00502a01b2a8005", - "0x522e0050c001b01b33400501b33201b01b33400501b00701b2a830e2c1", - "0x6700532e01b01b33400532e00532e01b01b33400503900506101b01b334", - "0x532e01b01b33400500600532e01b01b33400502700523101b01b334005", - "0xde00533400530e00502a01b2a700533400530f00504701b01b334005069", - "0x501b19301b2a300533400530100504201b2a500533400533d00511a01b", - "0x503900506101b01b33400522e0050c001b01b33400501b00701b01b4db", - "0x2700523101b01b33400506700532e01b01b33400532e00532e01b01b334", - "0x501801b01b33400506900532e01b01b33400500600532e01b01b334005", - "0x533400530e00502a01b30f00533400530f00504701b2a200533400530b", - "0x1b33400501b00701b2a230e30f0240052a20053340052a200528501b30e", - "0x1b33400522e0050c001b01b33400507100522b01b01b33400501b33201b", - "0x33400532e00532e01b01b33400503900506101b01b33400506900532e01b", - "0x500600532e01b01b33400502700523101b01b33400506700532e01b01b", - "0x502a01b2a700533400504f00504701b29f00533400501b02701b01b334", - "0x533400531600504201b2a500533400529f00511a01b0de005334005005", - "0x711501b29e0053340052a500528201b0e10053340052a300521801b2a3", - "0x3340052a700504701b29a00533400529b00511701b29b00533400529e0e1", - "0x2400529a00533400529a00528501b0de0053340050de00502a01b2a7005", - "0x522e0050c001b01b33400501b33201b01b33400501b00701b29a0de2a7", - "0x32e00532e01b01b33400503900506101b01b33400504600506701b01b334", - "0x532e01b01b33400502700523101b01b33400502300532e01b01b334005", - "0x1b29800533400506000521801b29900533400501b02701b01b334005041", - "0x29600511701b29600533400529729800711501b297005334005299005282", - "0x500533400500500502a01b04f00533400504f00504701b293005334005", - "0x1b01b33400501b00701b29300504f02400529300533400529300528501b", - "0x1b01b33400504600506701b01b33400522e0050c001b01b33400501b332", - "0x1b33400502300532e01b01b33400532e00532e01b01b334005039005061", - "0x533400501b02701b01b33400519300506701b01b33400502700523101b", - "0x711501b2920053340050eb00528201b0ed00533400505e00521801b0eb", - "0x33400504f00504701b29000533400529100511701b2910053340052920ed", - "0x2400529000533400529000528501b00500533400500500502a01b04f005", - "0x522e0050c001b01b33400501b33201b01b33400501b00701b29000504f", - "0x32e00532e01b01b33400503900506101b01b33400504600506701b01b334", - "0x506701b01b33400502700523101b01b33400507d00506701b01b334005", - "0x1b0f100533400525d00521801b0ef00533400501b02701b01b334005193", - "0xee00511701b0ee0053340050f00f100711501b0f00053340050ef005282", - "0x500533400500500502a01b04f00533400504f00504701b28f005334005", - "0x1b01b33400501b00701b28f00504f02400528f00533400528f00528501b", - "0x1b01b33400504600506701b01b33400522e0050c001b01b33400501b332", - "0x1b33400507d00506701b01b33400532e00532e01b01b334005039005061", - "0x33400505600528201b01b33400504000531601b01b33400519300506701b", - "0x1b0f90053340050f700511701b0f700533400528e23d00711501b28e005", - "0x50f900528501b00500533400500500502a01b04f00533400504f005047", - "0x1b33400501b33201b01b33400501b00701b0f900504f0240050f9005334", - "0x33400503900506101b01b33400504600506701b01b33400522e0050c001b", - "0x504000531601b01b33400507d00506701b01b33400532e00532e01b01b", - "0x504701b0f800533400523c00501801b01b33400519300506701b01b334", - "0x53340050f800528501b00500533400500500502a01b04f00533400504f", - "0x1b01b3340050510050c001b01b33400501b00701b0f800504f0240050f8", - "0x1b33400503900506101b01b33400504600506701b01b33400504e0050c0", - "0x33400504000531601b01b33400507d00506701b01b33400532e00532e01b", - "0x501b19301b0f600533400523100504701b01b33400519300506701b01b", - "0x504600506701b01b33400522900522b01b01b33400501b00701b01b4dc", - "0x7d00506701b01b33400532e00532e01b01b33400503900506101b01b334", - "0x506701b01b33400519300506701b01b33400504000531601b01b334005", - "0x2701b01b33400501b33201b0f600533400532100504701b01b334005048", - "0x33400528c22400711501b28c00533400528d00528201b28d00533400501b", - "0x28501b00500533400500500502a01b1000053340050ff00511701b0ff005", - "0x506701b01b33400501b00701b1000050f6024005100005334005100005", - "0x32e01b01b33400502f00533001b01b33400504600506701b01b334005048", - "0x1b01b33400504000531601b01b33400507d00506701b01b33400532e005", - "0x1b4dd00501b19301b0fe00533400503b00504701b01b334005193005067", - "0x1b33400504800506701b01b33400519200522b01b01b33400501b00701b", - "0x33400532e00532e01b01b33400502f00533001b01b33400504600506701b", - "0x519300506701b01b33400504000531601b01b33400507d00506701b01b", - "0x1b33201b0fe00533400501b00504701b01b33400504400506701b01b334", - "0x11501b28a00533400510100528201b10100533400501b02701b01b334005", - "0x500500502a01b10700533400528900511701b28900533400528a322007", - "0x501b00701b1070050fe02400510700533400510700528501b005005334", - "0x4200506701b01b33400504600506701b01b33400504800506701b01b334", - "0x506701b01b33400504000531601b01b33400507d00506701b01b334005", - "0x21801b10900533400501b02701b01b33400504400506701b01b334005193", - "0x510610800711501b10600533400510900528201b10800533400532f005", - "0x1b01b00533400501b00504701b11300533400528800511701b288005334", - "0x11300501b02400511300533400511300528501b00500533400500500502a", - "0x533400501b23901b19300533400501b06901b04200533400501b11c01b", - "0x33400501b23c01b33200533400501b11b01b07d00533400501b11c01b040", - "0x700700500711901b01b33400502400508401b01b33400501b33201b01b", - "0x32f00528101b01b33400501b00701b32b32c32e0244de32f041330024334", - "0x32804733400502500512201b02500533400532f00527f01b32f005334005", - "0x900533400532800527e01b32800533400532800512101b027023043335", - "0x4800512701b01b33400502f00508f01b02a02f00733400500900512701b", - "0x2a00533400502a0052ea01b01b33400503300508f01b0b5033007334005", - "0x1b32119232202433400507c00527d01b07c02a00733400502a00512601b", - "0x533400532200529301b01b33400532100506101b01b334005192005301", - "0x20903803a02433400503b00527d01b03b0b50073340050b500512601b039", - "0x33400503a00529301b01b33400520900506101b01b33400503800530101b", - "0x19300731501b33000533400533000502a01b01b33400501b04801b20d005", - "0x33400504304200727a01b33500533400533500527b01b041005334005041", - "0x2700533400502704000723d01b02300533400502307d00727a01b043005", - "0x2700532e01b01b33400501b00701b01b4df01b33400720d0390070eb01b", - "0x532e01b01b33400502300506101b01b33400504400532e01b01b334005", - "0x6101b01b33400504600532e01b01b3340050470052ec01b01b334005045", - "0x1b01b33400533500512e01b01b33400533200512c01b01b334005043005", - "0x1b01b4e000501b19301b01b33400502a00508f01b01b3340050b500508f", - "0x33400521600527d01b21602a00733400502a00512601b01b33400501b007", - "0x29301b01b33400521e00506101b01b33400521800530101b21e21a218024", - "0x522800527d01b2280b50073340050b500512601b22400533400521a005", - "0x1b01b33400522b00506101b01b33400522900530101b22b22a229024334", - "0x1b00701b01b4e101b33400722e2240070eb01b22e00533400522a005293", - "0x506101b01b33400504400532e01b01b33400502700532e01b01b334005", - "0x32e01b01b3340050470052ec01b01b33400504500532e01b01b334005023", - "0x1b01b33400533200512c01b01b33400504300506101b01b334005046005", - "0x1b33400502a00508f01b01b3340050b500508f01b01b33400533500512e", - "0x23102433400502a00527d01b01b33400501b00701b01b4e200501b19301b", - "0x4e00512d01b01b33400505100530101b01b33400523100530101b04e051", - "0x2390243340050b500527d01b05200533400504f00535d01b04f005334005", - "0x23d00512d01b01b33400523c00530101b01b33400523900530101b23d23c", - "0x53340050560520072f901b05600533400505400535d01b054005334005", - "0x1b0530054e301b3340070550052f801b05500533400505500502001b055", - "0x33400502033200727901b02000533400533500512b01b01b33400501b007", - "0x27801b01b3340052530052ec01b25d25300733400502000527801b020005", - "0x33400525d00527701b01b33400525f0052ec01b03525f007334005047005", - "0x6f06d06c2ed06906700606006128402733400505e00513501b05e25d007", - "0x523101b01b3340050600050c001b01b33400506100506101b036315316", - "0x32e01b01b33400506900532e01b01b33400506700532e01b01b334005006", - "0x1b01b33400506d0050c001b01b33400506c00528301b01b3340052ed005", - "0x1b33400531500522801b01b33400531600522801b01b33400506f005231", - "0x503500527701b02600533400528400504401b01b33400503600523101b", - "0x30c30d30e30f07507931107707102733400507200513501b072035007334", - "0x23101b01b3340053110050c001b01b33400507700506101b08530630a30b", - "0x1b01b33400530f00532e01b01b33400507500532e01b01b334005079005", - "0x1b33400530c0050c001b01b33400530d00528301b01b33400530e00532e", - "0x33400530600522801b01b33400530a00522801b01b33400530b00523101b", - "0x260072f901b30500533400507100504401b01b33400508500523101b01b", - "0x1b3340073040052f801b30400533400530400502001b304005334005305", - "0x13501b30325d00733400525d00527701b01b33400501b00701b0830054e4", - "0x32e01b2f82f92fa2fb2fc33d08707f2ff300301081302027334005303005", - "0x1b01b33400530000523101b01b3340053010050c001b01b334005302005", - "0x1b33400508700532e01b01b33400507f00532e01b01b3340052ff00532e", - "0x3340052fb00523101b01b3340052fc0050c001b01b33400533d00528301b", - "0x52f800523101b01b3340052f900522801b01b3340052fa00522801b01b", - "0x27701b2f60053340052f700535d01b2f700533400508100512d01b01b334", - "0x7e2ee2f12f22f32f40273340052f500513501b2f5035007334005035005", - "0x3340052f20050c001b01b3340052f400532e01b2ea0842eb08f2ec08d08b", - "0x507e00532e01b01b3340052ee00532e01b01b3340052f100523101b01b", - "0x2ec0050c001b01b33400508d00528301b01b33400508b00532e01b01b334", - "0x522801b01b3340052eb00522801b01b33400508f00523101b01b334005", - "0x1b2e90053340052f300512d01b01b3340052ea00523101b01b334005084", - "0x9700502001b0970053340052e72f60072f901b2e70053340052e900535d", - "0x1b33400501b00701b2e60054e501b3340070970052f801b097005334005", - "0x2e02e22e32e40273340052e500513501b2e525d00733400525d00527701b", - "0x2e300506101b01b3340052e400532e01b0ab0a92db2dd0a10a52de09e2df", - "0x532e01b01b3340052df00532e01b01b3340052e000523101b01b334005", - "0xc001b01b3340050a500528301b01b3340052de00532e01b01b33400509e", - "0x1b01b3340052db00522801b01b3340052dd00523101b01b3340050a1005", - "0x53340052e20052c401b01b3340050ab00523101b01b3340050a9005228", - "0x2d52d62d70273340050ae00513501b0ae03500733400503500527701b2d9", - "0x506101b01b3340052d700532e01b35a3590492cf2d02d10b42d22d32d4", - "0x32e01b01b3340052d300532e01b01b3340052d400523101b01b3340052d6", - "0x1b01b3340052d100528301b01b3340050b400532e01b01b3340052d2005", - "0x1b33400504900522801b01b3340052cf00523101b01b3340052d00050c0", - "0x3340052d50052c401b01b33400535a00523101b01b33400535900522801b", - "0x32e01b01b33400501b00701b01b4e601b33400735c2d900713401b35c005", - "0x1b01b33400502300506101b01b33400504400532e01b01b334005027005", - "0x1b3340050350052ec01b01b33400525d0052ec01b01b33400504500532e", - "0x1b4e700501b19301b01b33400504600532e01b01b33400504300506101b", - "0x50d100513501b0d125d00733400525d00527701b01b33400501b00701b", - "0x535d00532e01b2c70c92c835f2da35e2ce0c40c00be0bb0bc35d027334", - "0xc000532e01b01b3340050bb0050c001b01b3340050bc00506101b01b334", - "0x528301b01b3340052ce00532e01b01b3340050c400532e01b01b334005", - "0x22801b01b33400535f00523101b01b3340052da0050c001b01b33400535e", - "0x1b01b3340052c700523101b01b3340050c900522801b01b3340052c8005", - "0x36100502401b3610ca0073340050ca00529e01b0ca0053340050be005275", - "0x3500733400503500527701b2c40053340052c500531101b2c5005334005", - "0x2c20d42b42b52b62c30d02bc0c72b92bb0cf0273340052be00513501b2be", - "0x52b90050c001b01b3340052bb00506101b01b3340050cf00532e01b0d6", - "0x2c300532e01b01b3340050d000532e01b01b3340052bc00532e01b01b334", - "0x523101b01b3340052b50050c001b01b3340052b600528301b01b334005", - "0x23101b01b3340052c200522801b01b3340050d400522801b01b3340052b4", - "0x73340052bf00529e01b2bf0053340050c700527501b01b3340050d6005", - "0x3a01b2c10053340050d800531101b0d80053340052c000502401b2c02bf", - "0x72c12c400727401b2c10053340052c100503a01b2c40053340052c4005", - "0x2700532e01b01b33400501b33201b01b33400501b00701b01b4e801b334", - "0x532e01b01b33400502300506101b01b33400504400532e01b01b334005", - "0x6101b01b3340050350052ec01b01b33400525d0052ec01b01b334005045", - "0x1b01b3340052bf00523101b01b33400504600532e01b01b334005043005", - "0x33400533000502a01b2b300533400501b00504701b01b3340050ca005231", - "0x1b33400501b33201b01b33400501b00701b01b4e900501b19301b2ab005", - "0xca00525d01b33000533400533000502a01b01b00533400501b00504701b", - "0x52bf0ca33001b04827301b2bf0053340052bf00525d01b0ca005334005", - "0x501b00701b2a50054ea0de0053340072a700514601b2a72a82ad024334", - "0x1b01b3340052a300523101b29f2a22a30243340050de00513d01b01b334", - "0x1b00701b29e0054eb0e100533400729f00513f01b01b3340052a2005231", - "0x532e01b01b33400502300506101b01b3340050e100522b01b01b334005", - "0x6101b01b3340050350052ec01b01b33400525d0052ec01b01b334005045", - "0x1b01b33400504400532e01b01b33400504600532e01b01b334005043005", - "0x3340052a800502a01b2b30053340052ad00504701b01b33400502700532e", - "0x19301b29a0053340052ab00514101b29b0053340052b300535f01b2ab005", - "0x527701b01b33400529e00522b01b01b33400501b00701b01b4ec00501b", - "0x2920ed0eb29329629729802733400529900513501b29925d00733400525d", - "0x1b33400529700506101b01b33400529800532e01b0ee0f00f10ef290291", - "0x3340050ed00532e01b01b33400529300523101b01b3340052960050c001b", - "0x52900050c001b01b33400529100528301b01b33400529200532e01b01b", - "0xf000522801b01b3340050f100522801b01b3340050ef00523101b01b334", - "0x27701b28f0053340050eb00504401b01b3340050ee00523101b01b334005", - "0x28c28d0f60f80f90f702733400528e00513501b28e035007334005035005", - "0x3340050f900506101b01b3340050f700532e01b10728928a1010fe1000ff", - "0x528c00532e01b01b3340050f600523101b01b3340050f80050c001b01b", - "0xfe0050c001b01b33400510000528301b01b3340050ff00532e01b01b334", - "0x522801b01b33400528a00522801b01b33400510100523101b01b334005", - "0x1b10900533400528d00504401b01b33400510700523101b01b334005289", - "0x1080052f801b10800533400510800502001b10800533400510928f0072f9", - "0x25d00733400525d00527701b01b33400501b00701b1060054ed01b334007", - "0x11c11a01828228328511711528710e10f11302733400528800513501b288", - "0x510e0050c001b01b33400510f00506101b01b33400511300532e01b11b", - "0x28500532e01b01b33400511500532e01b01b33400528700523101b01b334", - "0x523101b01b3340052820050c001b01b33400528300528301b01b334005", - "0x23101b01b33400511c00522801b01b33400511a00522801b01b334005018", - "0x733400503500527701b11900533400511700504401b01b33400511b005", - "0x12e12c27a27b27d12612727e12112227f02733400528100513501b281035", - "0x1210050c001b01b33400512200506101b01b33400527f00532e01b12b12d", - "0x532e01b01b33400512700532e01b01b33400527e00523101b01b334005", - "0x23101b01b33400527a0050c001b01b33400527b00528301b01b33400527d", - "0x1b01b33400512d00522801b01b33400512e00522801b01b33400512c005", - "0x52791190072f901b27900533400512600504401b01b33400512b005231", - "0x54ee01b3340072780052f801b27800533400527800502001b278005334", - "0x13500513501b13525d00733400525d00527701b01b33400501b00701b277", - "0x13400532e01b27226e27014414214113f13d146273274275134027334005", - "0x523101b01b3340052740050c001b01b33400527500506101b01b334005", - "0x28301b01b33400513d00532e01b01b33400514600532e01b01b334005273", - "0x1b01b33400514400523101b01b3340051420050c001b01b334005141005", - "0x1b33400527200523101b01b33400526e00522801b01b334005270005228", - "0x513501b14d03500733400503500527701b14e00533400513f00504401b", - "0x532e01b26626826926a26b26c15814714814914a14b14c02733400514d", - "0x23101b01b33400514a0050c001b01b33400514b00506101b01b33400514c", - "0x1b01b33400514700532e01b01b33400514800532e01b01b334005149005", - "0x1b33400526a00523101b01b33400526b0050c001b01b33400526c005283", - "0x33400526600523101b01b33400526800522801b01b33400526900522801b", - "0x2001b26400533400526514e0072f901b26500533400515800504401b01b", - "0x501b00701b2630054ef01b3340072640052f801b264005334005264005", - "0x26116302733400516100513501b16125d00733400525d00527701b01b334", - "0x6101b01b33400516300532e01b25925b13913a25e16b169168166260165", - "0x1b01b33400526000523101b01b3340051650050c001b01b334005261005", - "0x1b33400516900532e01b01b33400516800532e01b01b33400516600532e", - "0x33400513900522801b01b33400513a00523101b01b33400525e0050c001b", - "0x516b00514201b01b33400525900523101b01b33400525b00522801b01b", - "0x25600533400525700527001b25725800733400525800514401b258005334", - "0x513501b17103500733400503500527701b25500533400525600526e01b", - "0x532e01b24e18418318118225217b179178254176174173027334005171", - "0x23101b01b3340051760050c001b01b33400517400506101b01b334005173", - "0x1b01b33400517900532e01b01b33400517800532e01b01b334005254005", - "0x1b33400518100523101b01b3340051820050c001b01b33400517b00532e", - "0x33400524e00523101b01b33400518400522801b01b33400518300522801b", - "0x27001b24f17c00733400517c00514401b17c00533400525200514201b01b", - "0x33400525500503a01b24b00533400525a00526e01b25a00533400524f005", - "0x1b4f001b33400724b25500727401b24b00533400524b00503a01b255005", - "0x1b33400504500532e01b01b33400502300506101b01b33400501b00701b", - "0x33400504300506101b01b3340050350052ec01b01b33400525d0052ec01b", - "0x502700532e01b01b33400504400532e01b01b33400504600532e01b01b", - "0x2ad00504701b01b33400525800528301b01b33400517c00528301b01b334", - "0x701b01b4f100501b19301b18b0053340052a800502a01b189005334005", - "0x2a80053340052a800502a01b2ad0053340052ad00504701b01b33400501b", - "0x2ad04814e01b17c00533400517c00527201b25800533400525800527201b", - "0x2480054f224900533400718f00514d01b18f18d24a02433400517c2582a8", - "0x24600528301b24324424602433400524900514c01b01b33400501b00701b", - "0x54f323b00533400724300513f01b01b33400524400528301b01b334005", - "0x33400525d0052ec01b01b33400523b00522b01b01b33400501b00701b23a", - "0x504600532e01b01b33400504300506101b01b3340050350052ec01b01b", - "0x4500532e01b01b33400502700532e01b01b33400504400532e01b01b334", - "0x2a01b18900533400524a00504701b01b33400502300506101b01b334005", - "0x33400518b00514101b23800533400518900535f01b18b00533400518d005", - "0x33400523a00522b01b01b33400501b00701b01b4f400501b19301b237005", - "0x23023323502733400519700513501b19725d00733400525d00527701b01b", - "0x506101b01b33400523500532e01b21b1a522122322522c22d22f19d19b", - "0x32e01b01b33400519b00523101b01b3340052300050c001b01b334005233", - "0x1b01b33400522d00532e01b01b33400522f00532e01b01b33400519d005", - "0x1b33400522100522801b01b33400522300523101b01b33400522c005283", - "0x3340052250052c401b01b33400521b00523101b01b3340051a500522801b", - "0x17d2190273340051a900513501b1a903500733400503500527701b1a7005", - "0x6101b01b33400521900532e01b20520820a1b120c20e1ae21321421c217", - "0x1b01b33400521c00523101b01b3340052170050c001b01b33400517d005", - "0x1b3340051ae00532e01b01b33400521300532e01b01b33400521400532e", - "0x33400520a00522801b01b3340051b100523101b01b33400520e00528301b", - "0x520c0052c401b01b33400520500523101b01b33400520800522801b01b", - "0x1b01b33400501b00701b01b4f501b3340072041a700713401b204005334", - "0x1b33400504300506101b01b3340050350052ec01b01b33400525d0052ec", - "0x33400502700532e01b01b33400504400532e01b01b33400504600532e01b", - "0x524a00504701b01b33400502300506101b01b33400504500532e01b01b", - "0x1b00701b01b4f600501b19301b1b700533400518d00502a01b203005334", - "0x20602733400520000513501b20025d00733400525d00527701b01b334005", - "0x1b01b33400520600532e01b1f21f31fd1f81c01fa1be1bc1fc1fe1b91ff", - "0x1b3340051fe00523101b01b3340051b90050c001b01b3340051ff005061", - "0x3340051be00532e01b01b3340051bc00532e01b01b3340051fc00532e01b", - "0x51fd00522801b01b3340051c00050c001b01b3340051fa00528301b01b", - "0x1f800527501b01b3340051f200523101b01b3340051f300522801b01b334", - "0x53340051f000502401b1f01f10073340051f100529e01b1f1005334005", - "0x13501b1ed03500733400503500527701b1ee0053340051ef00531101b1ef", - "0x32e01b4fa4f94f84f70001e41d71de1e11e31e61e81c70273340051ed005", - "0x1b01b3340051e60050c001b01b3340051e800506101b01b3340051c7005", - "0x1b3340051de00532e01b01b3340051e100532e01b01b3340051e3005231", - "0x3340050000050c001b01b3340051e400528301b01b3340051d700532e01b", - "0x54fa00523101b01b3340054f900522801b01b3340054f800522801b01b", - "0x1b4fc4fb0073340054fb00529e01b4fb0053340054f700527501b01b334", - "0x51ee00503a01b33a0053340054fd00531101b4fd0053340054fc005024", - "0x4fe01b33400733a1ee00727401b33a00533400533a00503a01b1ee005334", - "0x3340050350052ec01b01b33400525d0052ec01b01b33400501b00701b01b", - "0x504400532e01b01b33400504600532e01b01b33400504300506101b01b", - "0x2300506101b01b33400504500532e01b01b33400502700532e01b01b334", - "0x504701b01b3340051f100523101b01b3340054fb00523101b01b334005", - "0x1b01b50100501b19301b50000533400518d00502a01b4ff00533400524a", - "0x533400518d00502a01b24a00533400524a00504701b01b33400501b007", - "0x4827301b4fb0053340054fb00525d01b1f10053340051f100525d01b18d", - "0x550650500533400750400514601b5045035020243340054fb1f118d24a", - "0x523101b50950833b02433400550500513d01b01b33400501b00701b507", - "0x50b50a00533400750900513f01b01b33400550800523101b01b33400533b", - "0x504300506101b01b33400550a00522b01b01b33400501b00701b50c005", - "0x2700532e01b01b33400504400532e01b01b33400504600532e01b01b334", - "0x52ec01b01b33400502300506101b01b33400504500532e01b01b334005", - "0x1b4ff00533400550200504701b01b33400525d0052ec01b01b334005035", - "0x550000514101b50d0053340054ff00535f01b50000533400550300502a", - "0x550c00522b01b01b33400501b00701b01b50f00501b19301b50e005334", - "0x51251102733400551000513501b51025d00733400525d00527701b01b334", - "0x6101b01b33400551100532e01b51c51b51a519518517516515339514513", - "0x1b01b33400551400523101b01b3340055130050c001b01b334005512005", - "0x1b33400551600532e01b01b33400551500532e01b01b33400533900532e", - "0x33400551900523101b01b3340055180050c001b01b33400551700528301b", - "0x551a00514b01b01b33400551c00523101b01b33400551b00522801b01b", - "0x51f02733400551e00513501b51e03500733400503500527701b51d005334", - "0x1b01b33400551f00532e01b529337528527526525338524523522521520", - "0x1b33400552200523101b01b3340055210050c001b01b334005520005061", - "0x33400533800532e01b01b33400552400532e01b01b33400552300532e01b", - "0x552700523101b01b3340055260050c001b01b33400552500528301b01b", - "0x52800514b01b01b33400552900523101b01b33400533700522801b01b334", - "0x1b33400501b00701b01b52b01b33400752a51d00727401b52a005334005", - "0x33400504400532e01b01b33400504600532e01b01b33400504300506101b", - "0x502300506101b01b33400504500532e01b01b33400502700532e01b01b", - "0x50200504701b01b33400525d0052ec01b01b3340050350052ec01b01b334", - "0x701b01b52e00501b19301b52d00533400550300502a01b52c005334005", - "0x2733400552f00513501b52f25d00733400525d00527701b01b33400501b", - "0x1b33400533c00532e01b53b53a53953853753653553453353253153033c", - "0x33400553200523101b01b3340055310050c001b01b33400553000506101b", - "0x553500532e01b01b33400553400532e01b01b33400553300532e01b01b", - "0x53800523101b01b3340055370050c001b01b33400553600528301b01b334", - "0x514b01b01b33400553b00523101b01b33400553900522801b01b334005", - "0x33400553c00513501b53c03500733400503500527701b33600533400553a", - "0x33400553d00532e01b54954854754654554454354254154053f53e53d027", - "0x554000523101b01b33400553f0050c001b01b33400553e00506101b01b", - "0x54300532e01b01b33400554200532e01b01b33400554100532e01b01b334", - "0x523101b01b3340055450050c001b01b33400554400528301b01b334005", - "0x14b01b01b33400554900523101b01b33400554700522801b01b334005546", - "0x501b00701b01b54b01b33400754a33600727401b54a005334005548005", - "0x4400532e01b01b33400504600532e01b01b33400504300506101b01b334", - "0x506101b01b33400504500532e01b01b33400502700532e01b01b334005", - "0x4701b01b33400525d0052ec01b01b3340050350052ec01b01b334005023", - "0x1b54e00501b19301b54d00533400550300502a01b54c005334005502005", - "0x55555455355255155054f02733400525d00513501b01b33400501b00701b", - "0x1b33400555000506101b01b33400554f00532e01b55b55a559558557556", - "0x33400555300532e01b01b33400555200523101b01b3340055510050c001b", - "0x555600528301b01b33400555500532e01b01b33400555400532e01b01b", - "0x55900522801b01b33400555800523101b01b3340055570050c001b01b334", - "0x29e01b55c00533400555b00527501b01b33400555a00522801b01b334005", - "0x555e00531101b55e00533400555d00502401b55d55c00733400555c005", - "0x56734056656556456333f56256156002733400503500513501b55f005334", - "0x50c001b01b33400556100506101b01b33400556000532e01b56a569568", - "0x32e01b01b33400556300532e01b01b33400533f00523101b01b334005562", - "0x1b01b33400556600528301b01b33400556500532e01b01b334005564005", - "0x1b33400556800522801b01b33400556700523101b01b3340053400050c0", - "0x556b00529e01b56b00533400556a00527501b01b33400556900522801b", - "0x56e00533400556d00531101b56d00533400556c00502401b56c56b007334", - "0x55f00727401b56e00533400556e00503a01b55f00533400555f00503a01b", - "0x1b01b33400504300506101b01b33400501b00701b01b56f01b33400756e", - "0x1b33400502700532e01b01b33400504400532e01b01b33400504600532e", - "0x33400556b00523101b01b33400502300506101b01b33400504500532e01b", - "0x50300502a01b57000533400550200504701b01b33400555c00523101b01b", - "0x50200504701b01b33400501b00701b01b57200501b19301b571005334005", - "0x55c00533400555c00525d01b50300533400550300502a01b502005334005", - "0x57457302433400556b55c50350204827301b56b00533400556b00525d01b", - "0x13d01b01b33400501b00701b57800557757600533400757500514601b575", - "0x557a00523101b01b33400557900523101b34457a579024334005576005", - "0x1b01b33400501b00701b57d00557c57b00533400734400513f01b01b334", - "0x1b33400502700532e01b01b33400504400532e01b01b33400557b00522b", - "0x33400504600532e01b01b33400502300506101b01b33400504500532e01b", - "0x57400502a01b57000533400557300504701b01b33400504300506101b01b", - "0x57d00522b01b01b33400501b00701b01b57200501b19301b571005334005", - "0x57f00533400504657e0072f901b57e00533400504300535d01b01b334005", - "0x701b34500558001b33400757f0052f801b57f00533400557f00502001b", - "0x53340050455810072f901b58100533400502300535d01b01b33400501b", - "0x1b58400558301b3340075820052f801b58200533400558200502001b582", - "0x33400558500502001b5850053340050440270072f901b01b33400501b007", - "0x2701b01b33400501b00701b58700558601b3340075850052f801b585005", - "0x533400558900514901b58900533400558800514a01b58800533400501b", - "0x503301b57400533400557400502a01b57300533400557300504701b58a", - "0x1b58a04157457304800558a00533400558a00514801b041005334005041", - "0x1b58b00533400501b32b01b01b3340055870052f701b01b33400501b007", - "0x558c58b00732801b58c00533400558c00502001b58c00533400501b147", - "0x1b58f00533400558d58e00700901b58e00533400501b33501b58d005334", - "0x557400502a01b57300533400557300504701b59000533400558f005158", - "0x559000533400559000514801b04100533400504100503301b574005334", - "0x32e01b01b3340055840052f701b01b33400501b00701b590041574573048", - "0x1b59100533400501b32b01b01b33400502700532e01b01b334005044005", - "0x559259100732801b59200533400559200502001b59200533400501b26c", - "0x1b59500533400559359400700901b59400533400501b33501b593005334", - "0x557400502a01b57300533400557300504701b596005334005595005158", - "0x559600533400559600514801b04100533400504100503301b574005334", - "0x32e01b01b3340053450052f701b01b33400501b00701b596041574573048", - "0x1b01b33400504500532e01b01b33400502700532e01b01b334005044005", - "0x59800533400501b26b01b59700533400501b32b01b01b334005023005061", - "0x1b33501b59900533400559859700732801b59800533400559800502001b", - "0x533400559b00515801b59b00533400559959a00700901b59a005334005", - "0x503301b57400533400557400502a01b57300533400557300504701b59c", - "0x1b59c04157457304800559c00533400559c00514801b041005334005041", - "0x1b01b33400502700532e01b01b33400504400532e01b01b33400501b007", - "0x1b33400504600532e01b01b33400502300506101b01b33400504500532e", - "0x557400502a01b59d00533400557300504701b01b33400504300506101b", - "0x1b00701b01b59f00501b19301b59e0053340055780052c201b349005334", - "0x532e01b01b33400504600532e01b01b33400504300506101b01b334005", - "0x6101b01b33400504500532e01b01b33400502700532e01b01b334005044", - "0x1b01b33400525d0052ec01b01b3340050350052ec01b01b334005023005", - "0x55070052c201b34900533400550300502a01b59d005334005502005047", - "0x525d0052ec01b01b33400501b00701b01b59f00501b19301b59e005334", - "0x4600532e01b01b33400504300506101b01b3340050350052ec01b01b334", - "0x532e01b01b33400502700532e01b01b33400504400532e01b01b334005", - "0x1b59d00533400524a00504701b01b33400502300506101b01b334005045", - "0x59f00501b19301b59e0053340052480052c201b34900533400518d00502a", - "0x33400502300506101b01b3340052630052f701b01b33400501b00701b01b", - "0x50350052ec01b01b33400525d0052ec01b01b33400504500532e01b01b", - "0x4400532e01b01b33400504600532e01b01b33400504300506101b01b334", - "0x2a01b5a00053340052ad00504701b01b33400502700532e01b01b334005", - "0x2f701b01b33400501b00701b01b5a200501b19301b5a10053340052a8005", - "0x1b01b33400504500532e01b01b33400502300506101b01b334005277005", - "0x1b33400504300506101b01b3340050350052ec01b01b33400525d0052ec", - "0x33400502700532e01b01b33400504400532e01b01b33400504600532e01b", - "0x1b19301b34a0053340052a800502a01b5a30053340052ad00504701b01b", - "0x2300506101b01b3340051060052f701b01b33400501b00701b01b5a4005", - "0x52ec01b01b33400525d0052ec01b01b33400504500532e01b01b334005", - "0x32e01b01b33400504600532e01b01b33400504300506101b01b334005035", - "0x5a50053340052ad00504701b01b33400502700532e01b01b334005044005", - "0x1b33400501b00701b01b5a700501b19301b5a60053340052a800502a01b", - "0x33400525d0052ec01b01b33400504500532e01b01b33400502300506101b", - "0x504600532e01b01b33400504300506101b01b3340050350052ec01b01b", - "0x2ad00504701b01b33400502700532e01b01b33400504400532e01b01b334", - "0x59e0053340052a50052c201b3490053340052a800502a01b59d005334005", - "0x34900502a01b59d00533400559d00504701b5a800533400559e00515801b", - "0x5a80053340055a800514801b04100533400504100503301b349005334005", - "0x1b01b3340052e60052f701b01b33400501b00701b5a804134959d048005", - "0x1b33400502300506101b01b33400504400532e01b01b33400502700532e", - "0x3340050350052ec01b01b33400525d0052ec01b01b33400504500532e01b", - "0x4e700501b19301b01b33400504600532e01b01b33400504300506101b01b", - "0x33400502700532e01b01b3340050830052f701b01b33400501b00701b01b", - "0x504500532e01b01b33400502300506101b01b33400504400532e01b01b", - "0x4300506101b01b3340050350052ec01b01b33400525d0052ec01b01b334", - "0x1b00504701b01b33400501b33201b01b33400504600532e01b01b334005", - "0x5a500533400529b00535f01b29a00533400533000502a01b29b005334005", - "0x5a600514101b5a30053340055a500535f01b5a600533400529a00514101b", - "0x5a100533400534a00514101b5a00053340055a300535f01b34a005334005", - "0x23800535f01b2370053340055a100514101b2380053340055a000535f01b", - "0x50d00533400520300535f01b1b700533400523700514101b203005334005", - "0x50e00514101b52c00533400550d00535f01b50e0053340051b700514101b", - "0x54d00533400552d00514101b54c00533400552c00535f01b52d005334005", - "0x501b32b01b57100533400554d00514101b57000533400554c00535f01b", - "0x32801b5aa0053340055aa00502001b5aa00533400501b26a01b5a9005334", - "0x55ab5ac00700901b5ac00533400501b33501b5ab0053340055aa5a9007", - "0x1b57000533400557000504701b5ae0053340055ad00515801b5ad005334", - "0x55ae00514801b04100533400504100503301b57100533400557100502a", - "0x50530052f701b01b33400501b00701b5ae0415715700480055ae005334", - "0x2300506101b01b33400504400532e01b01b33400502700532e01b01b334", - "0x532e01b01b3340050470052ec01b01b33400504500532e01b01b334005", - "0x12e01b01b33400533200512c01b01b33400504300506101b01b334005046", - "0x26901b5af00533400501b32b01b01b33400501b33201b01b334005335005", - "0x3340055b05af00732801b5b00053340055b000502001b5b000533400501b", - "0x15801b5b30053340055b15b200700901b5b200533400501b33501b5b1005", - "0x33400533000502a01b01b00533400501b00504701b5b40053340055b3005", - "0x480055b40053340055b400514801b04100533400504100503301b330005", - "0x526801b01b33400504000506701b01b33400501b00701b5b404133001b", - "0x12c01b01b33400504400532e01b01b33400504800508f01b01b33400507d", - "0x1b01b3340050470052ec01b01b33400504500532e01b01b334005332005", - "0x1b33400519300506f01b01b33400504200526801b01b33400504600532e", - "0x5b600515801b5b600533400532b5b500700901b5b500533400501b33501b", - "0x32e00533400532e00502a01b01b00533400501b00504701b34e005334005", - "0x32e01b04800534e00533400534e00514801b32c00533400532c00503301b", - "0x2400526601b04400533400501b32b01b01b33400500700508401b34e32c", - "0x33400504204400732801b0420053340050430052fa01b043024007334005", - "0x2700533400519304100732801b19304700733400504700535c01b041005", - "0x4002700732801b04000533400504000502001b04000533400501b26501b", - "0x2004600733400504600535c01b07d00533400501b04f01b023005334005", - "0x732801b33200533400533200502001b33200533400507d0200072c101b", - "0x733400504500535c01b32f00533400501b04f01b330005334005332023", - "0x1b32c00533400532c00502001b32c00533400532f32e0072c101b32e045", - "0x521601b32802500733400532b00520d01b32b00533400532c330007328", - "0x2400733400502400526601b33500533400532800521801b01b334005025", - "0x2433400733504800900501b0472e401b33500533400533500525d01b009", - "0x33400503300523101b01b33400501b00701b32207c0b50245b703302a02f", - "0x732801b32100533400504619200732801b19200533400501b32b01b01b", - "0x503b00521601b03a03b00733400503900520d01b039005334005045321", - "0x25d01b02f00533400502f00502a01b03800533400503a00521801b01b334", - "0x21620d20902433400703804702402a02f0472e401b038005334005038005", - "0x1b22400533400521600521a01b01b33400501b00701b21e21a2180245b8", - "0x520d00503301b20900533400520900502a01b22800533400522400521e", - "0x501b00701b22820d2090240052280053340052280050b501b20d005334", - "0x2f01b22a00533400521e22900700901b22900533400501b33501b01b334", - "0x33400521a00503301b21800533400521800502a01b22b00533400522a005", - "0x33400501b00701b22b21a21802400522b00533400522b0050b501b21a005", - "0x502400508501b01b33400504700532e01b01b33400504600532e01b01b", - "0x22e00700901b22e00533400501b33501b01b33400504500532e01b01b334", - "0x53340050b500502a01b05100533400523100502f01b231005334005322", - "0xb50240050510053340050510050b501b07c00533400507c00503301b0b5", - "0x4704804833400502400500701b04826401b01b33400501b33201b05107c", - "0x2a01b0460053340050460052df01b04800533400504800504701b045046", - "0x4504704604804800504500533400504500526301b047005334005047005", - "0x4700533400501b16301b04800533400501b16101b01b33400501b33201b", - "0x4500526001b04500533400504604700716501b04600533400501b26101b", - "0x4300533400501b16801b04400533400504504800716601b045005334005", - "0x4100525e01b01b33400504200516b01b04104200733400504400516901b", - "0x500533400500500502a01b01b00533400501b00504701b193005334005", - "0x1b04825b01b04300533400504300513901b19300533400519300513a01b", - "0x200055b907d00533400702300525901b023040027024334005043193005", - "0x33200525701b32f33033202433400507d00525801b01b33400501b00701b", - "0x1b32101b32e00533400501b30001b01b33400532f00522b01b01b334005", - "0x4000533400504000502a01b02700533400502700504701b32c005334005", - "0x32c00503a01b32e00533400532e00507f01b33000533400533000513901b", - "0x25501b32802532b02433400532c32e33004002704725601b32c005334005", - "0x533500517101b01b33400501b00701b0090055ba335005334007328005", - "0xb503300733400502f00517301b01b33400502a00522b01b02a02f007334", - "0x702502425401b07c0053340050b500517601b01b33400503300517401b", - "0x17801b01b33400501b00701b03a03b0390245bb32119232202433400707c", - "0x33400503800517b01b20d00533400501b17901b209038007334005321005", - "0x17b01b19200533400519200503301b32200533400532200502a01b038005", - "0x501b00701b01b5bc01b33400720d03800713401b209005334005209005", - "0x501b32b01b01b3340052090050c001b01b33400502400508401b01b334", - "0x32801b21800533400521800502001b21800533400501b25201b216005334", - "0x521a21e00700901b21e00533400501b33501b21a005334005218216007", - "0x1b32b00533400532b00504701b22800533400522400529801b224005334", - "0x522800529701b19200533400519200503301b32200533400532200502a", - "0x33400501b18201b01b33400501b00701b22819232232b048005228005334", - "0x8401b01b33400501b00701b01b5bd01b33400722920900713401b229005", - "0x1b22b00533400501b25201b22a00533400501b32b01b01b334005024005", - "0x501b33501b22e00533400522b22a00732801b22b00533400522b005020", - "0x4e00533400505100529801b05100533400522e23100700901b231005334", - "0x19200503301b32200533400532200502a01b32b00533400532b00504701b", - "0x701b04e19232232b04800504e00533400504e00529701b192005334005", - "0x7f01b05200533400501b0ed01b04f00533400501b16801b01b33400501b", - "0x523900517301b23900533400505204f00718101b052005334005052005", - "0x1b05400533400523d00517601b01b33400523c00517401b23d23c007334", - "0x5be05305505602433400705419232202425401b054005334005054005183", - "0x508401b01b33400505300518401b01b33400501b00701b25f25d253024", - "0x2001b05e00533400501b24e01b03500533400501b32b01b01b334005024", - "0x33400501b33501b28400533400505e03500732801b05e00533400505e005", - "0x1b00600533400506000529801b06000533400528406100700901b061005", - "0x505500503301b05600533400505600502a01b32b00533400532b005047", - "0x1b00701b00605505632b04800500600533400500600529701b055005334", - "0x1b01b33400506700521601b06906700733400525f00520d01b01b334005", - "0x3340052ed00503a01b06900533400506900504201b2ed00533400501b321", - "0x17c01b25d00533400525d00503301b25300533400525300502a01b2ed005", - "0x24f01b01b33400501b00701b06f0055bf06d06c0073340072ed06932b024", - "0x33400531600504401b31600533400506d00504501b06d00533400506d005", - "0x72f901b31500533400531500502001b03600533400501b25a01b315005", - "0x33400506c00504701b02600533400502600502001b026005334005036315", - "0x2701b01b33400501b00701b0720055c001b3340070260052f801b06c005", - "0x33400507700518901b07700533400507102400724b01b07100533400501b", - "0x3301b25300533400525300502a01b06c00533400506c00504701b311005", - "0x31125d25306c04800531100533400531100529701b25d00533400525d005", - "0x1b33400502400508401b01b3340050720052f701b01b33400501b00701b", - "0x33400507500502001b07500533400501b18b01b07900533400501b32b01b", - "0x901b30e00533400501b33501b30f00533400507507900732801b075005", - "0x506c00504701b30c00533400530d00529801b30d00533400530f30e007", - "0x1b25d00533400525d00503301b25300533400525300502a01b06c005334", - "0x1b01b33400501b00701b30c25d25306c04800530c00533400530c005297", - "0x30a00533400501b24a01b30b00533400501b32b01b01b334005024005084", - "0x1b33501b30600533400530a30b00732801b30a00533400530a00502001b", - "0x533400530500529801b30500533400530608500700901b085005334005", - "0x503301b25300533400525300502a01b06f00533400506f00504701b304", - "0x1b30425d25306f04800530400533400530400529701b25d00533400525d", - "0x8300533400532b00504701b01b33400502400508401b01b33400501b007", - "0x3a00522401b30200533400503b00503301b30300533400503900502a01b", - "0x2400508401b01b33400501b00701b01b5c100501b19301b081005334005", - "0x1b01b33400530100530e01b30030100733400500900530f01b01b334005", - "0x500700503301b30300533400502500502a01b08300533400532b005047", - "0x1b00701b01b5c100501b19301b08100533400530000522401b302005334", - "0x1b07f2ff00733400502000530f01b01b33400502400508401b01b334005", - "0x33400504000502a01b08300533400502700504701b01b3340052ff00530e", - "0x33501b08100533400507f00522401b30200533400500700503301b303005", - "0x33400533d00529801b33d00533400508108700700901b08700533400501b", - "0x3301b30300533400530300502a01b08300533400508300504701b2fc005", - "0x2fc3023030830480052fc0053340052fc00529701b302005334005302005", - "0x4700533400501b18f01b04800533400501b18d01b01b33400501b33201b", - "0x1b32101b04600533400504704800724901b04700533400504700503a01b", - "0x1b01b00533400501b00504701b04400533400501b32101b045005334005", - "0x504400503a01b04500533400504500503a01b046005334005046005248", - "0x704200524401b04204300733400504404504601b04824601b044005334", - "0x1b02700533400501b24301b01b33400501b00701b1930055c2041005334", - "0x7d00522b01b07d02300733400504100523a01b04000533400502700523b", - "0x1b01b33400502000523701b33202000733400502300523801b01b334005", - "0x500500502a01b04300533400504300504701b330005334005332005197", - "0x1b33000533400533000523501b00700533400500700503301b005005334", - "0x32e32f04833400504033000700504304723001b040005334005040005233", - "0x1b01b33400501b00701b3280055c302500533400732b00519b01b32b32c", - "0x2f00522b01b01b33400533500522f01b02f00933502433400502500519d", - "0x1b02a00533400502a00522c01b02a00533400500900522d01b01b334005", - "0x3932119232207c0b504433400503300522301b03300533400502a005225", - "0x19200522801b01b33400532200522801b01b33400507c00522801b03a03b", - "0x522801b01b33400503900522801b01b33400532100522801b01b334005", - "0x3a01b03800533400501b22101b01b33400503a00522801b01b33400503b", - "0x501b00701b01b5c401b3340070380b500727401b0b50053340050b5005", - "0x501b25201b20900533400501b32b01b01b33400502400508401b01b334", - "0x21600533400520d20900732801b20d00533400520d00502001b20d005334", - "0x21a00529801b21a00533400521621800700901b21800533400501b33501b", - "0x32e00533400532e00502a01b32f00533400532f00504701b21e005334005", - "0x32e32f04800521e00533400521e00529701b32c00533400532c00503301b", - "0x22402400724b01b22400533400501b02701b01b33400501b00701b21e32c", - "0x32f00533400532f00504701b22900533400522800518901b228005334005", - "0x22900529701b32c00533400532c00503301b32e00533400532e00502a01b", - "0x2400508401b01b33400501b00701b22932c32e32f048005229005334005", - "0x1b22b00533400532e00502a01b22a00533400532f00504701b01b334005", - "0x5c500501b19301b2310053340053280052c201b22e00533400532c005033", - "0x33400504300504701b01b33400502400508401b01b33400501b00701b01b", - "0x2c201b22e00533400500700503301b22b00533400500500502a01b22a005", - "0x33400522a00504701b05100533400523100529801b231005334005193005", - "0x29701b22e00533400522e00503301b22b00533400522b00502a01b22a005", - "0x1a501b01b33400501b33201b05122e22b22a048005051005334005051005", - "0x4700533400504700526001b04600533400501b21b01b04700533400501b", - "0x440450243340070460470240050481a701b04600533400504600526001b", - "0x270073340050430051a901b01b33400501b00701b1930410420245c6043", - "0x4500502a01b04000533400504000517d01b01b33400502700521901b040", - "0x2300533400704000521701b04400533400504400503301b045005334005", - "0x4800508401b01b33400502300521c01b01b33400501b00701b07d0055c7", - "0x502001b33200533400501b21401b02000533400501b32b01b01b334005", - "0x533400501b33501b33000533400533202000732801b332005334005332", - "0x4701b32c00533400532e00529801b32e00533400533032f00700901b32f", - "0x3340050070052d501b04500533400504500502a01b01b00533400501b005", - "0x4700532c00533400532c00529701b04400533400504400503301b007005", - "0x21301b01b33400507d00522b01b01b33400501b00701b32c04400704501b", - "0x32b00533400532b00526001b02500533400501b21b01b32b00533400501b", - "0x33532802433400702532b0440450481a701b02500533400502500526001b", - "0x1b01b33400500900521901b01b33400501b00701b03302a02f0245c8009", - "0x7c00533400501b24e01b0b500533400501b32b01b01b334005048005084", - "0x1b33501b32200533400507c0b500732801b07c00533400507c00502001b", - "0x533400532100529801b32100533400532219200700901b192005334005", - "0x52d501b32800533400532800502a01b01b00533400501b00504701b039", - "0x533400503900529701b33500533400533500503301b007005334005007", - "0x33400503300520d01b01b33400501b00701b03933500732801b047005039", - "0x504201b03800533400501b32101b01b33400503b00521601b03a03b007", - "0x533400502f00502a01b03800533400503800503a01b03a00533400503a", - "0x20d20900733400703803a01b02417c01b02a00533400502a00503301b02f", - "0x504501b20d00533400520d00524f01b01b33400501b00701b2160055c9", - "0x21e00533400501b1ae01b21a00533400521800504401b21800533400520d", - "0x502001b22400533400521e21a0072f901b21a00533400521a00502001b", - "0x1b3340072240052f801b20900533400520900504701b224005334005224", - "0x501b20c01b22900533400501b20e01b01b33400501b00701b2280055ca", - "0x22a00733400522a0051b101b22b2290073340052290051b101b22a005334", - "0x481a701b22e00533400522e00526001b22b00533400522b00526001b22e", - "0x33400501b00701b23905204f0245cb04e05123102433400722e22b02a02f", - "0x503301b23100533400523100502a01b04e00533400504e00517d01b01b", - "0x501b00701b23d0055cc23c00533400704e00521701b051005334005051", - "0x25f25d2530245cd05305505605404833400723c05123102420a01b01b334", - "0x503500518401b05e03500733400505500520801b01b33400501b00701b", - "0x26001b01b33400528400518401b06128400733400522900520801b01b334", - "0x506000517801b06005e00733400505e0051b101b05e00533400505e005", - "0x690610073340050610051b101b01b3340050670050c001b067006007334", - "0x60052c401b01b33400506c0050c001b06c2ed00733400506900517801b", - "0x2a01b01b33400501b04801b06f0053340052ed0052c401b06d005334005", - "0x33400505300526001b05600533400505600503301b054005334005054005", - "0x8401b01b33400501b00701b01b5ce01b33400706f06d00713401b053005", - "0x1b01b33400505300518401b01b33400522a00518401b01b334005048005", - "0x1b01b5cf00501b19301b01b33400505e00518401b01b334005061005184", - "0x3340053160050c001b31531600733400505e00517801b01b33400501b007", - "0x52c401b01b3340050360050c001b02603600733400506100517801b01b", - "0x33400707107200713401b0710053340050260052c401b072005334005315", - "0x22a00518401b01b33400504800508401b01b33400501b00701b01b5d001b", - "0x501b00701b01b5d100501b19301b01b33400505300518401b01b334005", - "0x20801b01b33400507700518401b31107700733400505300520801b01b334", - "0x3340053110051b101b01b33400507900518401b07507900733400522a005", - "0x1b01b33400530d0050c001b30d30e00733400530f00517801b30f311007", - "0x50c001b30a30b00733400530c00517801b30c0750073340050750051b1", - "0x8500533400530b0052c401b30600533400530e0052c401b01b33400530a", - "0x4800508401b01b33400501b00701b01b5d201b33400708530600713401b", - "0x1b19301b01b33400531100518401b01b33400507500518401b01b334005", - "0xc001b30430500733400531100517801b01b33400501b00701b01b5d1005", - "0x3340050830050c001b30308300733400507500517801b01b334005305005", - "0x713401b0810053340053030052c401b3020053340053040052c401b01b", - "0x1b33400504800508401b01b33400501b00701b01b5d301b334007081302", - "0x30000533400501b20501b30100533400501b32b01b01b33400501b33201b", - "0x1b33501b2ff00533400530030100732801b30000533400530000502001b", - "0x533400508700529801b0870053340052ff07f00700901b07f005334005", - "0x52d501b05400533400505400502a01b20900533400520900504701b33d", - "0x533400533d00529701b05600533400505600503301b007005334005007", - "0x533400501b20401b01b33400501b00701b33d05600705420904700533d", - "0x2fa00517801b2fa00533400501b20301b2fb0053340052fc0052be01b2fc", - "0x2f70053340052f90052be01b01b3340052f80050c001b2f82f9007334005", - "0x2f62fb00720001b2fb0053340052fb00502001b2f600533400501b1b701b", - "0x53340052f72f50072c101b2f50053340052f500502001b2f5005334005", - "0x33400501b1b901b2f200533400501b1ff01b2f300533400501b20601b2f4", - "0x241fe01b07e0053340052ee0052dd01b2ee00533400501b02701b2f1005", - "0x520900504701b08d0053340052f40051fc01b08b00533400507e2f12f2", - "0x1b0070053340050070052d501b05400533400505400502a01b209005334", - "0x508b0051bc01b2f30053340052f300526001b056005334005056005033", - "0x8b2f30560070542090451fa01b08d00533400508d0051be01b08b005334", - "0x72ea0051c001b01b33400501b04801b2ea0842eb08f2ec04733400508d", - "0x970053340052e90051f801b01b33400501b00701b2e70055d42e9005334", - "0x1b33201b01b33400501b00701b2e50055d52e60053340070970051fd01b", - "0x724b01b2e400533400501b02701b01b3340052e600522b01b01b334005", - "0x3340052ec00504701b2e20053340052e300518901b2e30053340052e4048", - "0x3301b2eb0053340052eb0052d501b08f00533400508f00502a01b2ec005", - "0x842eb08f2ec0470052e20053340052e200529701b084005334005084005", - "0x533400501b32b01b01b33400504800508401b01b33400501b00701b2e2", - "0x19301b09e0053340052df00522401b2df0053340052e52e000732801b2e0", - "0x530f01b01b33400504800508401b01b33400501b00701b01b5d600501b", - "0x53340050a500522401b01b3340052de00530e01b0a52de0073340052e7", - "0x509e0a100700901b0a100533400501b33501b01b33400501b33201b09e", - "0x1b2ec0053340052ec00504701b2db0053340052dd00529801b2dd005334", - "0x508400503301b2eb0053340052eb0052d501b08f00533400508f00502a", - "0x701b2db0842eb08f2ec0470052db0053340052db00529701b084005334", - "0x8401b01b33400522a00518401b01b33400522900518401b01b33400501b", - "0x533400525f0a900700901b0a900533400501b33501b01b334005048005", - "0x502a01b20900533400520900504701b2d90053340050ab00529801b0ab", - "0x533400525d00503301b0070053340050070052d501b253005334005253", - "0x501b00701b2d925d0072532090470052d90053340052d900529701b25d", - "0x22a00518401b01b33400522900518401b01b33400523d00522b01b01b334", - "0x1b05201b0ae00533400501b32b01b01b33400504800508401b01b334005", - "0x53340052d70ae00732801b2d70053340052d700502001b2d7005334005", - "0x529801b2d40053340052d62d500700901b2d500533400501b33501b2d6", - "0x533400523100502a01b20900533400520900504701b2d30053340052d4", - "0x529701b05100533400505100503301b0070053340050070052d501b231", - "0x18401b01b33400501b00701b2d30510072312090470052d30053340052d3", - "0x1b01b33400504800508401b01b33400522a00518401b01b334005229005", - "0x50b400529801b0b40053340052392d200700901b2d200533400501b335", - "0x1b04f00533400504f00502a01b20900533400520900504701b2d1005334", - "0x52d100529701b05200533400505200503301b0070053340050070052d5", - "0x2280052f701b01b33400501b00701b2d105200704f2090470052d1005334", - "0x1b18b01b2d000533400501b32b01b01b33400504800508401b01b334005", - "0x53340052cf2d000732801b2cf0053340052cf00502001b2cf005334005", - "0x529801b35a00533400504935900700901b35900533400501b33501b049", - "0x533400502f00502a01b20900533400520900504701b35c00533400535a", - "0x529701b02a00533400502a00503301b0070053340050070052d501b02f", - "0x8401b01b33400501b00701b35c02a00702f20904700535c00533400535c", - "0x1b35d00533400501b24a01b0d100533400501b32b01b01b334005048005", - "0x501b33501b0bc00533400535d0d100732801b35d00533400535d005020", - "0xc00053340050be00529801b0be0053340050bc0bb00700901b0bb005334", - "0x70052d501b02f00533400502f00502a01b21600533400521600504701b", - "0xc00053340050c000529701b02a00533400502a00503301b007005334005", - "0x1b33400504800508401b01b33400501b00701b0c002a00702f216047005", - "0x2ce00529801b2ce0053340051930c400700901b0c400533400501b33501b", - "0x4200533400504200502a01b01b00533400501b00504701b35e005334005", - "0x35e00529701b04100533400504100503301b0070053340050070052d501b", - "0x21b01b04800533400501b1a501b35e04100704201b04700535e005334005", - "0x533400504700526001b04800533400504800526001b04700533400501b", - "0x1b0410420430245d70440450460243340070470480070050481f301b047", - "0x3340051930051f101b0271930073340050440051f201b01b33400501b007", - "0x503301b04600533400504600502a01b0270053340050270051f001b01b", - "0x501b00701b0230055d80400053340070270051ef01b045005334005045", - "0x501b32b01b01b33400502400508401b01b3340050400051ee01b01b334", - "0x32801b02000533400502000502001b02000533400501b21401b07d005334", - "0x533233000700901b33000533400501b33501b33200533400502007d007", - "0x1b01b00533400501b00504701b32e00533400532f00529801b32f005334", - "0x532e00529701b04500533400504500503301b04600533400504600502a", - "0x502300522b01b01b33400501b00701b32e04504601b04800532e005334", - "0x32c00526001b32b00533400501b21b01b32c00533400501b1ed01b01b334", - "0x732b32c0450460481f301b32b00533400532b00526001b32c005334005", - "0x3350051f101b01b33400501b00701b02a02f0090245d9335328025024334", - "0x1b24e01b03300533400501b32b01b01b33400502400508401b01b334005", - "0x53340050b503300732801b0b50053340050b500502001b0b5005334005", - "0x529801b19200533400507c32200700901b32200533400501b33501b07c", - "0x533400502500502a01b01b00533400501b00504701b321005334005192", - "0x1b04800532100533400532100529701b32800533400532800503301b025", - "0x21601b03b03900733400502a00520d01b01b33400501b00701b321328025", - "0x3b00533400503b00504201b03a00533400501b32101b01b334005039005", - "0x2f00503301b00900533400500900502a01b03a00533400503a00503a01b", - "0x701b20d0055da20903800733400703a03b01b02417c01b02f005334005", - "0x21600533400520900504501b20900533400520900524f01b01b33400501b", - "0x521800502001b21a00533400501b1ae01b21800533400521600504401b", - "0x21e00533400521e00502001b21e00533400521a2180072f901b218005334", - "0x701b2240055db01b33400721e0052f801b03800533400503800504701b", - "0x1b101b22900533400501b1e801b22800533400501b1c701b01b33400501b", - "0x22a00526001b22b2290073340052290051b101b22a228007334005228005", - "0x722b22a02f0090481f301b22b00533400522b00526001b22a005334005", - "0x510051f001b01b33400501b00701b05204f04e0245dc05123122e024334", - "0x23100533400523100503301b22e00533400522e00502a01b051005334005", - "0x241e601b01b33400501b00701b23c0055dd2390053340070510051ef01b", - "0x33400501b00701b25d2530530245de05505605423d04833400723923122e", - "0x520801b01b33400525f00518401b03525f00733400505600520801b01b", - "0x533400503500526001b01b33400505e00518401b28405e007334005228", - "0x1b00606000733400506100517801b0610350073340050350051b101b035", - "0x506700517801b0672840073340052840051b101b01b3340050060050c0", - "0x1b06c0053340050600052c401b01b3340052ed0050c001b2ed069007334", - "0x505400503301b23d00533400523d00502a01b06d0053340050690052c4", - "0x5df01b33400706d06c00713401b05500533400505500526001b054005334", - "0x33400522900518401b01b33400502400508401b01b33400501b00701b01b", - "0x503500518401b01b33400528400518401b01b33400505500518401b01b", - "0x33400503500517801b01b33400501b00701b01b5e000501b19301b01b334", - "0x1b03631500733400528400517801b01b33400506f0050c001b31606f007", - "0x3340050360052c401b0260053340053160052c401b01b3340053150050c0", - "0x8401b01b33400501b00701b01b5e101b33400707202600713401b072005", - "0x1b01b33400505500518401b01b33400522900518401b01b334005024005", - "0x7707100733400505500520801b01b33400501b00701b01b5e200501b193", - "0x31100518401b07931100733400522900520801b01b33400507100518401b", - "0x30f00733400507500517801b0750770073340050770051b101b01b334005", - "0x517801b30d0790073340050790051b101b01b33400530e0050c001b30e", - "0x533400530f0052c401b01b33400530b0050c001b30b30c00733400530d", - "0x1b01b5e301b33400730630a00713401b30600533400530c0052c401b30a", - "0x1b01b33400507900518401b01b33400502400508401b01b33400501b007", - "0x17801b01b33400501b00701b01b5e200501b19301b01b334005077005184", - "0x33400507900517801b01b3340050850050c001b305085007334005077005", - "0x2c401b3030053340053050052c401b01b3340053040050c001b083304007", - "0x501b00701b01b5e401b33400730230300713401b302005334005083005", - "0x501b20501b08100533400501b32b01b01b33400502400508401b01b334", - "0x30000533400530108100732801b30100533400530100502001b301005334", - "0x7f00529801b07f0053340053002ff00700901b2ff00533400501b33501b", - "0x23d00533400523d00502a01b03800533400503800504701b087005334005", - "0x23d03804800508700533400508700529701b05400533400505400503301b", - "0x533d0052be01b33d00533400501b1e301b01b33400501b00701b087054", - "0x517801b2fb00533400501b1e101b01b3340052fc00532e01b2fc005334", - "0x53340052fa0052be01b01b3340052f90050c001b2f92fa0073340052fb", - "0x33400501b1d701b2f700533400501b1de01b01b3340052f800532e01b2f8", - "0x1f301b2f60053340052f600526001b2f70053340052f700526001b2f6005", - "0x501b00701b2ee2f12f20245e52f32f42f50243340072f62f705423d048", - "0x3301b2f50053340052f500502a01b2f30053340052f30051f001b01b334", - "0x1b00701b08b0055e607e0053340072f30051ef01b2f40053340052f4005", - "0x1b4f701b2ec00533400501b00001b08d00533400501b1e401b01b334005", - "0x2f50053340052f500502a01b03800533400503800504701b08f005334005", - "0x2ec00526001b08d00533400508d00526001b2f40053340052f400503301b", - "0x7e00533400507e0054f801b08f00533400508f00526001b2ec005334005", - "0x54fa01b2e92ea0842eb04833400507e08f2ec08d2f42f50380454f901b", - "0x3340052e70054fb01b01b33400501b00701b0970055e72e70053340072e9", - "0x518901b2e50053340052e602400724b01b2e600533400501b02701b01b", - "0x533400508400502a01b2eb0053340052eb00504701b2e40053340052e5", - "0x2eb0480052e40053340052e400529701b2ea0053340052ea00503301b084", - "0x9700529801b01b33400502400508401b01b33400501b00701b2e42ea084", - "0x8400533400508400502a01b2eb0053340052eb00504701b2e3005334005", - "0x842eb0480052e30053340052e300529701b2ea0053340052ea00503301b", - "0x502400508401b01b33400508b00522b01b01b33400501b00701b2e32ea", - "0x2e000502001b2e000533400501b05201b2e200533400501b32b01b01b334", - "0x9e00533400501b33501b2df0053340052e02e200732801b2e0005334005", - "0x504701b0a50053340052de00529801b2de0053340052df09e00700901b", - "0x53340052f400503301b2f50053340052f500502a01b038005334005038", - "0x33400501b00701b0a52f42f50380480050a50053340050a500529701b2f4", - "0x2ee0a100700901b0a100533400501b33501b01b33400502400508401b01b", - "0x3800533400503800504701b2db0053340052dd00529801b2dd005334005", - "0x2db00529701b2f10053340052f100503301b2f20053340052f200502a01b", - "0x22800518401b01b33400501b00701b2db2f12f20380480052db005334005", - "0x1b33501b01b33400502400508401b01b33400522900518401b01b334005", - "0x53340050ab00529801b0ab00533400525d0a900700901b0a9005334005", - "0x503301b05300533400505300502a01b03800533400503800504701b2d9", - "0x1b2d92530530380480052d90053340052d900529701b253005334005253", - "0x1b01b33400522800518401b01b33400523c00522b01b01b33400501b007", - "0xae00533400501b32b01b01b33400502400508401b01b334005229005184", - "0x2d70ae00732801b2d70053340052d700502001b2d700533400501b05201b", - "0x2d40053340052d62d500700901b2d500533400501b33501b2d6005334005", - "0x22e00502a01b03800533400503800504701b2d30053340052d400529801b", - "0x2d30053340052d300529701b23100533400523100503301b22e005334005", - "0x1b01b33400522800518401b01b33400501b00701b2d323122e038048005", - "0x2d200533400501b33501b01b33400502400508401b01b334005229005184", - "0x504701b2d10053340050b400529801b0b40053340050522d200700901b", - "0x533400504f00503301b04e00533400504e00502a01b038005334005038", - "0x33400501b00701b2d104f04e0380480052d10053340052d100529701b04f", - "0x33400501b32b01b01b33400502400508401b01b3340052240052f701b01b", - "0x732801b2cf0053340052cf00502001b2cf00533400501b18b01b2d0005", - "0x33400504935900700901b35900533400501b33501b0490053340052cf2d0", - "0x2a01b03800533400503800504701b35c00533400535a00529801b35a005", - "0x33400535c00529701b02f00533400502f00503301b009005334005009005", - "0x33400502400508401b01b33400501b00701b35c02f00903804800535c005", - "0x535d00502001b35d00533400501b24a01b0d100533400501b32b01b01b", - "0x1b0bb00533400501b33501b0bc00533400535d0d100732801b35d005334", - "0x20d00504701b0c00053340050be00529801b0be0053340050bc0bb007009", - "0x2f00533400502f00503301b00900533400500900502a01b20d005334005", - "0x1b33400501b00701b0c002f00920d0480050c00053340050c000529701b", - "0x50410c400700901b0c400533400501b33501b01b33400502400508401b", - "0x1b01b00533400501b00504701b35e0053340052ce00529801b2ce005334", - "0x535e00529701b04200533400504200503301b04300533400504300502a", - "0x501b00700501b01b33400501b33201b35e04204301b04800535e005334", - "0x504800520d01b01b33400501b00701b0440450075e8046047007334007", - "0x1b19300533400501b4fc01b04100533400504200531101b042043007334", - "0x410470244fd01b19300533400519300503a01b04100533400504100503a", - "0x4000522801b01b33400501b00701b07d0230075e9040027007334007193", - "0x33202000733400704300533a01b02700533400502700504701b01b334005", - "0x522401b32f00533400533200504501b01b33400501b00701b3300055ea", - "0x733400702000533a01b32f00533400532f00502001b020005334005020", - "0x1b02500533400532c00504501b01b33400501b00701b32b0055eb32c32e", - "0x732e00533a01b02500533400502500502001b32e00533400532e005224", - "0x533400533500504501b01b33400501b00701b0090055ec335328007334", - "0x22401b02a02f00733400502f00535c01b02f00533400502f00502001b02f", - "0x501b00701b0330055ed01b33400702a0052f801b328005334005328005", - "0x5ee07c0b500733400732f02700705401b01b33400502f00532e01b01b334", - "0x521601b32119200733400532800520d01b01b33400501b00701b322005", - "0xb50053340050b500504701b03900533400532100521801b01b334005192", - "0x1b21620d2090245ef03803a03b02433400703902507c00704604706001b", - "0x2180053340050b500504701b01b33400503800523101b01b33400501b007", - "0x501b19301b21e00533400503a00503301b21a00533400503b00502a01b", - "0x33400501b33501b01b33400502400508401b01b33400501b00701b01b5f0", - "0x1b2290053340052280054ff01b22800533400521622400700901b224005", - "0x520d00503301b20900533400520900502a01b0b50053340050b5005047", - "0x1b00701b22920d2090b504800522900533400522900550001b20d005334", - "0x532e01b01b33400502400508401b01b33400532800521601b01b334005", - "0x2001b22b00533400501b05201b22a00533400501b32b01b01b334005025", - "0x33400501b33501b22e00533400522b22a00732801b22b00533400522b005", - "0x1b04e0053340050510054ff01b05100533400522e23100700901b231005", - "0x500700503301b04600533400504600502a01b322005334005322005047", - "0x1b00701b04e00704632204800504e00533400504e00550001b007005334", - "0x72f901b04f00533400501b04f01b01b3340050330052f701b01b334005", - "0x3340070520052f801b05200533400505200502001b05200533400504f02f", - "0x23d23c00733400732f02700730601b01b33400501b00701b2390055f101b", - "0x21601b05505600733400532800520d01b01b33400501b00701b0540055f2", - "0x533400523c00504701b05300533400505500521801b01b334005056005", - "0x28405e0350245f325f25d25302433400705302523d0070460472e401b23c", - "0x533400523c00504701b01b33400525f00523101b01b33400501b00701b", - "0x1b19301b00600533400525d00503301b06000533400525300502a01b061", - "0x501b33501b01b33400502400508401b01b33400501b00701b01b5f4005", - "0x2ed0053340050690054ff01b06900533400528406700700901b067005334", - "0x5e00503301b03500533400503500502a01b23c00533400523c00504701b", - "0x701b2ed05e03523c0480052ed0053340052ed00550001b05e005334005", - "0x32e01b01b33400502400508401b01b33400532800521601b01b33400501b", - "0x1b06d00533400501b05201b06c00533400501b32b01b01b334005025005", - "0x501b33501b06f00533400506d06c00732801b06d00533400506d005020", - "0x360053340053150054ff01b31500533400506f31600700901b316005334", - "0x700503301b04600533400504600502a01b05400533400505400504701b", - "0x701b03600704605404800503600533400503600550001b007005334005", - "0x50201b01b33400532f00532e01b01b3340052390052f701b01b33400501b", - "0x50260720072f901b07202500733400502500535c01b02600533400501b", - "0x55f501b3340070710052f801b07100533400507100502001b071005334", - "0x33400502700504701b01b33400502500532e01b01b33400501b00701b077", - "0x22401b00700533400500700503301b04600533400504600502a01b027005", - "0x750793110483340053280240070460270472d101b328005334005328005", - "0x1b3340050770052f701b01b33400501b00701b30f07507931104800530f", - "0x530e0250072f901b30e00533400501b50301b01b33400532800521601b", - "0x55f601b33400730d0052f801b30d00533400530d00502001b30d005334", - "0x533400501b32b01b01b33400502400508401b01b33400501b00701b30c", - "0x30b00732801b30a00533400530a00502001b30a00533400501b04901b30b", - "0x533400530608500700901b08500533400501b33501b30600533400530a", - "0x502a01b02700533400502700504701b3040053340053050054ff01b305", - "0x533400530400550001b00700533400500700503301b046005334005046", - "0x1b33400530c0052f701b01b33400501b00701b304007046027048005304", - "0x700503301b06000533400504600502a01b06100533400502700504701b", - "0x21a00533400506000514101b21800533400506100535f01b006005334005", - "0x8302400750501b08300533400501b04e01b21e00533400500600550401b", - "0x30200533400530200550001b30200533400530300550701b303005334005", - "0x1b01b33400500900521601b01b33400501b00701b30221e21a218048005", - "0x1b33400532f00532e01b01b33400502500532e01b01b334005024005084", - "0x33400530100502001b30100533400501b05201b08100533400501b32b01b", - "0x901b2ff00533400501b33501b30000533400530108100732801b301005", - "0x502700504701b08700533400507f0054ff01b07f0053340053002ff007", - "0x1b00700533400500700503301b04600533400504600502a01b027005334", - "0x1b01b33400501b00701b087007046027048005087005334005087005500", - "0x1b33400532f00532e01b01b33400502400508401b01b33400532b005216", - "0x3340052fc00502001b2fc00533400501b05201b33d00533400501b32b01b", - "0x901b2fa00533400501b33501b2fb0053340052fc33d00732801b2fc005", - "0x502700504701b2f80053340052f90054ff01b2f90053340052fb2fa007", - "0x1b00700533400500700503301b04600533400504600502a01b027005334", - "0x1b01b33400501b00701b2f80070460270480052f80053340052f8005500", - "0x2f700533400501b32b01b01b33400502400508401b01b334005330005216", - "0x2f62f700732801b2f60053340052f600502001b2f600533400501b05201b", - "0x2f30053340052f52f400700901b2f400533400501b33501b2f5005334005", - "0x4600502a01b02700533400502700504701b2f20053340052f30054ff01b", - "0x2f20053340052f200550001b00700533400500700503301b046005334005", - "0x1b01b33400507d00522801b01b33400501b00701b2f2007046027048005", - "0x2f100533400501b32b01b01b33400502400508401b01b334005043005216", - "0x2ee2f100732801b2ee0053340052ee00502001b2ee00533400501b33b01b", - "0x8d00533400507e08b00700901b08b00533400501b33501b07e005334005", - "0x4600502a01b02300533400502300504701b2ec00533400508d0054ff01b", - "0x2ec0053340052ec00550001b00700533400500700503301b046005334005", - "0x1b01b33400504800521601b01b33400501b00701b2ec007046023048005", - "0x2eb00533400501b22901b08f00533400501b32b01b01b334005024005084", - "0x1b33501b0840053340052eb08f00732801b2eb0053340052eb00502001b", - "0x53340052e90054ff01b2e90053340050842ea00700901b2ea005334005", - "0x503301b04400533400504400502a01b04500533400504500504701b2e7", - "0x1b2e70070440450480052e70053340052e700550001b007005334005007", - "0x1b0450460075f704704800733400700501b00700501b01b33400501b332", - "0x33400504800504701b04402400733400502400535c01b01b33400501b007", - "0x8401b01b33400501b00701b0430055f801b3340070440052f801b048005", - "0x1b04200533400501b32b01b01b33400502400532e01b01b334005007005", - "0x504104200732801b04100533400504100502001b04100533400501b508", - "0x1b04000533400519302700700901b02700533400501b33501b193005334", - "0x504700502a01b04800533400504800504701b023005334005040005298", - "0x501b00701b02304704802400502300533400502300529701b047005334", - "0x240072f901b07d00533400501b04f01b01b3340050430052f701b01b334", - "0x533400504700502a01b04800533400504800504701b02000533400507d", - "0x33202433400502000704704804835901b02000533400502000502001b047", - "0x1b33400502400532e01b01b33400501b00701b32f33033202400532f330", - "0x533400501b22901b32e00533400501b32b01b01b33400500700508401b", - "0x33501b32b00533400532c32e00732801b32c00533400532c00502001b32c", - "0x33400532800529801b32800533400532b02500700901b02500533400501b", - "0x29701b04500533400504500502a01b04600533400504600504701b335005", - "0x700501b01b33400501b33201b335045046024005335005334005335005", - "0x535c01b01b33400501b00701b0450460075f904704800733400700501b", - "0x3340070440052f801b04800533400504800504701b044024007334005024", - "0x1b02701b01b33400502400532e01b01b33400501b00701b0430055fa01b", - "0x533400504100518901b04100533400504200700724b01b042005334005", - "0x529701b04700533400504700502a01b04800533400504800504701b193", - "0x430052f701b01b33400501b00701b193047048024005193005334005193", - "0x1b0400053340050270240072f901b02700533400501b04f01b01b334005", - "0x504000502001b04700533400504700502a01b048005334005048005047", - "0x7d02302400502007d02302433400504000704704804835a01b040005334", - "0x33400500700508401b01b33400502400532e01b01b33400501b00701b020", - "0x533000502001b33000533400501b22901b33200533400501b32b01b01b", - "0x1b32e00533400501b33501b32f00533400533033200732801b330005334", - "0x4600504701b32b00533400532c00529801b32c00533400532f32e007009", - "0x32b00533400532b00529701b04500533400504500502a01b046005334005", - "0x4300533400504400550a01b04400533400501b50901b32b045046024005", - "0x4100550e01b01b33400504200550d01b04104200733400504300550c01b", - "0x4700733400504700535c01b02700533400519300504401b193005334005", - "0x7d02300733400504002700702451001b02700533400502700502001b040", - "0x51201b33202000733400507d01b00751101b07d00533400507d00502001b", - "0x532f00551401b32e32f00733400533000551301b330005334005332005", - "0x51601b32b00533400532c00551501b32c00533400532e00533901b01b334", - "0x33400501b32101b3280053340050250050d801b02532b00733400532b005", - "0x1b00900533400500900503a01b00933500733400533500503901b335005", - "0x2400504820901b02000533400502000504701b0230053340050230050bc", - "0x1b01b33400501b00701b32207c0b50245fb03302a02f024334007328009", - "0x502f00502a01b32100533400519232b00751801b19200533400501b517", - "0x1b3210053340053210052b301b33500533400533500503a01b02f005334", - "0x3a03b03902433400732133502a02f04820901b033005334005033005020", - "0x50a01b21600533400501b50901b01b33400501b00701b20d2090380245fc", - "0x521a00550d01b21e21a00733400521800550c01b218005334005216005", - "0x2001b22800533400522400504401b22400533400521e00550e01b01b334", - "0x502001b22a22900733400504722802302451001b228005334005228005", - "0x522e00551601b22e22b00733400522a02000751101b22a00533400522a", - "0x53340050460330072c101b0510053340052310050d801b23122e007334", - "0x502a01b05204f00733400504f00503901b04f00533400501b32101b04e", - "0x533400504e00502001b05200533400505200503a01b039005334005039", - "0x504701b2290053340052290050bc01b03a00533400503a00502001b04e", - "0x245fd23c23900733400704e05105203b03904703801b22b00533400522b", - "0x22e00751801b05500533400501b51701b01b33400501b00701b05605423d", - "0x33400523900502a01b25300533400504503a0072c101b053005334005055", - "0x2001b0530053340050530052b301b04f00533400504f00503a01b239005", - "0x5fe25f25d00733400725305304f23c23904703801b253005334005253005", - "0x724b01b06100533400501b02701b01b33400501b00701b28405e035024", - "0x33400522b00504701b00600533400506000518901b060005334005061048", - "0x3301b2290053340052290050bc01b25d00533400525d00502a01b22b005", - "0x25f22925d22b04700500600533400500600529701b25f00533400525f005", - "0x33400503500502a01b01b33400504800508401b01b33400501b00701b006", - "0x19301b2ed00533400528400522401b06900533400505e00503301b067005", - "0x551901b01b33400504800508401b01b33400501b00701b01b5ff00501b", - "0x32e01b01b33400504f00522801b01b33400503a00532e01b01b33400522e", - "0x533400505400503301b06700533400523d00502a01b01b334005045005", - "0x6c00700901b06c00533400501b33501b2ed00533400505600522401b069", - "0x533400522b00504701b06f00533400506d00529801b06d0053340052ed", - "0x503301b2290053340052290050bc01b06700533400506700502a01b22b", - "0x6f06922906722b04700506f00533400506f00529701b069005334005069", - "0x1b33400504800508401b01b33400504600532e01b01b33400501b00701b", - "0x33400504500532e01b01b33400504700532e01b01b33400503300532e01b", - "0x522401b31500533400520900503301b31600533400503800502a01b01b", - "0x532e01b01b33400501b00701b01b60000501b19301b03600533400520d", - "0x32e01b01b33400533500522801b01b33400504800508401b01b334005046", - "0x1b01b33400532b00551901b01b33400504500532e01b01b334005047005", - "0x532200522401b31500533400507c00503301b3160053340050b500502a", - "0x1b07200533400503602600700901b02600533400501b33501b036005334", - "0x531600502a01b02000533400502000504701b071005334005072005298", - "0x1b31500533400531500503301b0230053340050230050bc01b316005334", - "0x3340050460050ca01b071315023316020047005071005334005071005297", - "0x50c01b04200533400504300550a01b04300533400501b50901b044045007", - "0x33400519300550e01b01b33400504100550d01b193041007334005042005", - "0x1b02304500733400504500535c01b04000533400502700504401b027005", - "0x2001b02007d00733400502304002402451001b040005334005040005020", - "0x33000551201b33033200733400502001b00751101b020005334005020005", - "0x1b33400532e00551401b32c32e00733400532f00551301b32f005334005", - "0x2500551601b02500533400532b00551501b32b00533400532c00533901b", - "0x900533400501b32101b3350053340053280050d801b328025007334005", - "0x50bc01b02f00533400502f00503a01b02f00900733400500900503901b", - "0x33502f04800504820901b33200533400533200504701b07d00533400507d", - "0x1b51701b01b33400501b00701b19232207c0246010b503302a024334007", - "0x533400502a00502a01b03900533400532102500751801b321005334005", - "0x502001b0390053340050390052b301b00900533400500900503a01b02a", - "0x2460203803a03b02433400703900903302a04820901b0b50053340050b5", - "0x503301b03b00533400503b00502a01b01b33400501b00701b21620d209", - "0x3340070b53320070be01b03800533400503800502001b03a00533400503a", - "0x70382180070be01b01b33400501b00701b22822421e02460321a218007", - "0x50440052c501b01b33400501b00701b23122e22b02460422a229007334", - "0x50c001b23c23905204f04833400505121a00702451a01b04e051007334", - "0x1b23d0053340052390052be01b01b33400523c0050c001b01b334005052", - "0x1b01b3340050560050c001b05305505605404833400504e22a04f02451a", - "0x533400501b50901b2530053340050550052be01b01b3340050530050c0", - "0x50d01b05e03500733400525f00550c01b25f00533400525d00550a01b25d", - "0x533400528400504401b28400533400505e00550e01b01b334005035005", - "0x606000733400504506107d02451001b06100533400506100502001b061", - "0x51601b06906700733400500622900751101b00600533400500600502001b", - "0x33400501b32101b06c0053340052ed0050d801b2ed069007334005069005", - "0x1b06f00533400506f00503a01b06f06d00733400506d00503901b06d005", - "0x525300502001b0540053340050540052d501b23d00533400523d005020", - "0x1b06700533400506700504701b0600053340050600050bc01b253005334", - "0x1b00701b07202603602460531531600733400723d06c06f03a03b047038", - "0x1b07700533400507106900751801b07100533400501b51701b01b334005", - "0x50770052b301b06d00533400506d00503a01b31600533400531600502a", - "0x30f07502460607931100733400725307706d31531604703801b077005334", - "0x530d04700724b01b30d00533400501b02701b01b33400501b00701b30e", - "0x1b06700533400506700504701b30b00533400530c00518901b30c005334", - "0x50600050bc01b0540053340050540052d501b31100533400531100502a", - "0x530b00533400530b00529701b07900533400507900503301b060005334", - "0x1b33400504700508401b01b33400501b00701b30b079060054311067046", - "0x30e00522401b30600533400530f00503301b30a00533400507500502a01b", - "0x4700508401b01b33400501b00701b01b60700501b19301b085005334005", - "0x522801b01b33400506900551901b01b33400525300532e01b01b334005", - "0x30600533400502600503301b30a00533400503600502a01b01b33400506d", - "0x8530500700901b30500533400501b33501b08500533400507200522401b", - "0x6700533400506700504701b08300533400530400529801b304005334005", - "0x600050bc01b0540053340050540052d501b30a00533400530a00502a01b", - "0x8300533400508300529701b30600533400530600503301b060005334005", - "0x33400522e0050c001b01b33400501b00701b08330606005430a067046005", - "0x504400536101b01b33400504700508401b01b3340052310050c001b01b", - "0x501b32b01b01b33400521a0050c001b01b33400504500532e01b01b334", - "0x32801b30200533400530200502001b30200533400501b05201b303005334", - "0x508130100700901b30100533400501b33501b081005334005302303007", - "0x1b22b00533400522b00504701b2ff00533400530000529801b300005334", - "0x507d0050bc01b0070053340050070052d501b03b00533400503b00502a", - "0x52ff0053340052ff00529701b03a00533400503a00503301b07d005334", - "0x1b3340052240050c001b01b33400501b00701b2ff03a07d00703b22b046", - "0x33400504400536101b01b33400504700508401b01b3340052280050c001b", - "0x33400501b32b01b01b33400503800532e01b01b33400504500532e01b01b", - "0x732801b08700533400508700502001b08700533400501b05201b07f005", - "0x33400533d2fc00700901b2fc00533400501b33501b33d00533400508707f", - "0x2a01b21e00533400521e00504701b2fa0053340052fb00529801b2fb005", - "0x33400507d0050bc01b0070053340050070052d501b03b00533400503b005", - "0x460052fa0053340052fa00529701b03a00533400503a00503301b07d005", - "0x1b01b3340050b500532e01b01b33400501b00701b2fa03a07d00703b21e", - "0x1b33400504500532e01b01b33400504400536101b01b334005047005084", - "0x21600522401b2f800533400520d00503301b2f900533400520900502a01b", - "0x900522801b01b33400501b00701b01b60800501b19301b2f7005334005", - "0x532e01b01b33400504400536101b01b33400504700508401b01b334005", - "0x1b2f900533400507c00502a01b01b33400502500551901b01b334005045", - "0x33400501b33501b2f700533400519200522401b2f8005334005322005033", - "0x1b2f40053340052f500529801b2f50053340052f72f600700901b2f6005", - "0x50070052d501b2f90053340052f900502a01b332005334005332005047", - "0x1b2f80053340052f800503301b07d00533400507d0050bc01b007005334", - "0x33400501b51b01b2f42f807d0072f93320460052f40053340052f4005297", - "0x502001b04700533400504700502001b04600533400501b51c01b047005", - "0x501b00701b01b60904500533400704604700751d01b046005334005046", - "0x52001b04400533400504500551f01b04500533400504500551e01b01b334", - "0x4300533400504300502001b04200533400501b52101b04300533400501b", - "0x1b01b60a04100533400704204300751d01b04200533400504200502001b", - "0x533400504100551f01b04100533400504100551e01b01b33400501b007", - "0x4000560b01b33400702700552301b02719300733400519300552201b193", - "0x33400519300552401b0230053340050050052bb01b01b33400501b00701b", - "0x33400519300533801b01b33400501b00701b01b60c00501b19301b07d005", - "0x533200502001b33200533400501b52601b02000533400501b52501b01b", - "0x532f00552801b32f33000733400504033202000504852701b332005334", - "0x60d32e00533400732f00533701b3300053340053300052bb01b32f005334", - "0x53300052bb01b32c00533400532e00551f01b01b33400501b00701b01b", - "0x1b00701b01b60c00501b19301b07d00533400532c00552401b023005334", - "0x52401b0230053340053300052bb01b32b00533400501b52901b01b334005", - "0x702500552301b02507d00733400507d00552201b07d00533400532b005", - "0x52401b01b33400507d00533801b01b33400501b00701b32800560e01b334", - "0x52301b01b33400501b00701b01b60f00501b19301b335005334005044005", - "0x33400532800552a01b01b33400501b00701b00900561001b334007044005", - "0x33400501b00701b01b60f00501b19301b33500533400507d00552401b01b", - "0x32802f00752c01b02f00533400501b52501b01b33400507d00533801b01b", - "0x533400500902a00752c01b02a00533400502a00552801b02a005334005", - "0x1b01b6110b500533400703300533701b03300533400503300552801b033", - "0x533400507c00552401b07c0053340050b500551f01b01b33400501b007", - "0x32200533400501b52901b01b33400501b00701b01b60f00501b19301b335", - "0x701b19200561201b33400733500552301b33500533400532200552401b", - "0x5201b32100533400501b32b01b01b33400504800508401b01b33400501b", - "0x33400503932100732801b03900533400503900502001b03900533400501b", - "0x29801b03800533400503b03a00700901b03a00533400501b33501b03b005", - "0x3340050230052bb01b01b00533400501b00504701b209005334005038005", - "0x29701b02400533400502400503301b00700533400500700502a01b023005", - "0x1b01b33400501b00701b20902400702301b047005209005334005209005", - "0x521800551601b21800533400501b52f01b21620d00733400519200552d", - "0x1b22400533400501b32101b21e00533400521a0050d801b21a218007334", - "0x21e0052b301b22800533400522800503a01b228224007334005224005039", - "0x22b02461322a22900733400720d21e22802400704703801b21e005334005", - "0x521800533c01b05100533400501b51701b01b33400501b00701b23122e", - "0x22900533400522900502a01b04e00533400505121800751801b218005334", - "0x22904703801b04e00533400504e0052b301b22400533400522400503a01b", - "0x1b33400501b00701b23d23c23902461405204f00733400721604e22422a", - "0x5600518901b05600533400505404800724b01b05400533400501b02701b", - "0x230053340050230052bb01b01b00533400501b00504701b055005334005", - "0x5500529701b05200533400505200503301b04f00533400504f00502a01b", - "0x508401b01b33400501b00701b05505204f02301b047005055005334005", - "0x25300533400523c00503301b05300533400523900502a01b01b334005048", - "0x1b33400501b00701b01b61500501b19301b25d00533400523d00522401b", - "0x33400521800551901b01b33400521600532e01b01b33400504800508401b", - "0x22e00503301b05300533400522b00502a01b01b33400522400522801b01b", - "0x1b25f00533400501b33501b25d00533400523100522401b253005334005", - "0x1b00504701b05e00533400503500529801b03500533400525d25f007009", - "0x5300533400505300502a01b0230053340050230052bb01b01b005334005", - "0x2301b04700505e00533400505e00529701b25300533400525300503301b", - "0x4400533801b01b33400504800508401b01b33400501b00701b05e253053", - "0x502001b06100533400501b05201b28400533400501b32b01b01b334005", - "0x533400501b33501b06000533400506128400732801b061005334005061", - "0x4701b06900533400506700529801b06700533400506000600700901b006", - "0x33400500700502a01b0050053340050050052bb01b01b00533400501b005", - "0x4700506900533400506900529701b02400533400502400503301b007005", - "0x32b01b01b33400504800508401b01b33400501b00701b06902400700501b", - "0x6c00533400506c00502001b06c00533400501b05201b2ed00533400501b", - "0x6f00700901b06f00533400501b33501b06d00533400506c2ed00732801b", - "0x533400501b00504701b31500533400531600529801b31600533400506d", - "0x503301b00700533400500700502a01b0050053340050050052bb01b01b", - "0x31502400700501b04700531500533400531500529701b024005334005024", - "0x501b00701b04104204302461604404504602433400702400500711901b", - "0x12201b19300533400504400527f01b04400533400504400528101b01b334", - "0x506101b01b33400502700553001b02007d023040027047334005193005", - "0x27b01b01b33400502000532e01b01b33400507d00506101b01b334005023", - "0x533400501b50901b33200533400504000512b01b040005334005040005", - "0x50d01b32c32e00733400532f00550c01b32f00533400533000550a01b330", - "0x533400532b00504401b32b00533400532c00550e01b01b33400532e005", - "0x51001b02500533400502500502001b32804700733400504700535c01b025", - "0x751101b00900533400500900502001b009335007334005328025007024", - "0x503300551301b03300533400502a00551201b02a02f00733400500901b", - "0x1b32200533400507c00533901b01b3340050b500551401b07c0b5007334", - "0x3210050d801b32119200733400519200551601b192005334005322005515", - "0x3a03b00733400503b00503901b03b00533400501b32101b039005334005", - "0x3320052e901b03a00533400503a00503a01b04600533400504600502a01b", - "0x2f00533400502f00504701b3350053340053350050bc01b332005334005", - "0x701b21a21821602461720d20903802433400703903a04504604820901b", - "0x22400533400521e19200751801b21e00533400501b51701b01b33400501b", - "0x2240052b301b03b00533400503b00503a01b03800533400503800502a01b", - "0x722403b20903804820901b20d00533400520d00502001b224005334005", - "0x33200513501b01b33400501b00701b23122e22b02461822a229228024334", - "0x5100532e01b25d25305305505605423d23c23905204f04e051027334005", - "0x532e01b01b33400504f0050c001b01b33400504e00506101b01b334005", - "0x28301b01b33400523d00532e01b01b33400523c00532e01b01b334005239", - "0x1b01b33400505500523101b01b3340050560050c001b01b334005054005", - "0x1b33400525d00523101b01b33400525300522801b01b334005053005228", - "0x3500502401b03505200733400505200529e01b25f00533400501b32101b", - "0x22800533400522800502a01b25f00533400525f00503a01b05e005334005", - "0x2f02417c01b22a00533400522a00502001b22900533400522900503301b", - "0x6100524f01b01b33400501b00701b06000561906128400733400725f05e", - "0x1b06700533400501b53101b00600533400506100504501b061005334005", - "0x500600502001b06700533400506700503a01b069005334005052005024", - "0x1b00701b06d00561a06c2ed00733400706706928402417c01b006005334", - "0x1b06f00533400506c00504501b06c00533400506c00524f01b01b334005", - "0x33400531500550c01b31500533400531600550a01b31600533400501b509", - "0x4401b07200533400502600550e01b01b33400503600550d01b026036007", - "0x4707133502451001b07100533400507100502001b071005334005072005", - "0x3340053112ed00751101b31100533400531100502001b311077007334005", - "0x30e00533400530f0050d801b30f07500733400507500551601b075079007", - "0x1b32101b30c00533400530d20d0072c101b30d00533400500600504401b", - "0x533400530a00503a01b30a30b00733400530b00503901b30b005334005", - "0x50bc01b06f00533400506f00502001b30c00533400530c00502001b30a", - "0x30e30a22922804703801b07900533400507900504701b077005334005077", - "0x1b51701b01b33400501b00701b08330430502461b08530600733400730c", - "0x533400506f00504401b30200533400530307500751801b303005334005", - "0x3a01b30600533400530600502a01b30100533400508122a0072c101b081", - "0x33400530100502001b3020053340053020052b301b30b00533400530b005", - "0x33d08707f02461c2ff30000733400730130230b08530604703801b301005", - "0x3340052fc04800724b01b2fc00533400501b02701b01b33400501b00701b", - "0x2a01b07900533400507900504701b2fa0053340052fb00518901b2fb005", - "0x3340052ff00503301b0770053340050770050bc01b300005334005300005", - "0x1b00701b2fa2ff0773000790470052fa0053340052fa00529701b2ff005", - "0x3301b2f900533400507f00502a01b01b33400504800508401b01b334005", - "0x1b61d00501b19301b2f700533400533d00522401b2f8005334005087005", - "0x1b33400507500551901b01b33400504800508401b01b33400501b00701b", - "0x33400522a00532e01b01b33400530b00522801b01b33400506f00532e01b", - "0x522401b2f800533400530400503301b2f900533400530500502a01b01b", - "0x53340052f72f600700901b2f600533400501b33501b2f7005334005083", - "0x502a01b07900533400507900504701b2f40053340052f500529801b2f5", - "0x53340052f800503301b0770053340050770050bc01b2f90053340052f9", - "0x501b00701b2f42f80772f90790470052f40053340052f400529701b2f8", - "0x4700532e01b01b33400504800508401b01b33400520d00532e01b01b334", - "0x1b32b01b01b33400522a00532e01b01b33400500600532e01b01b334005", - "0x1b2f20053340052f200502001b2f200533400501b24a01b2f3005334005", - "0x2f12ee00700901b2ee00533400501b33501b2f10053340052f22f3007328", - "0x6d00533400506d00504701b08b00533400507e00529801b07e005334005", - "0x22900503301b3350053340053350050bc01b22800533400522800502a01b", - "0x1b08b22933522806d04700508b00533400508b00529701b229005334005", - "0x1b01b33400504800508401b01b33400520d00532e01b01b33400501b007", - "0x1b33400522a00532e01b01b33400505200523101b01b33400504700532e", - "0x3340052ec00502001b2ec00533400501b24a01b08d00533400501b32b01b", - "0x901b2eb00533400501b33501b08f0053340052ec08d00732801b2ec005", - "0x506000504701b2ea00533400508400529801b08400533400508f2eb007", - "0x1b3350053340053350050bc01b22800533400522800502a01b060005334", - "0x3352280600470052ea0053340052ea00529701b229005334005229005033", - "0x504800508401b01b33400520d00532e01b01b33400501b00701b2ea229", - "0x22b00502a01b01b3340053320052ec01b01b33400504700532e01b01b334", - "0x9700533400523100522401b2e700533400522e00503301b2e9005334005", - "0x1b01b33400503b00522801b01b33400501b00701b01b61e00501b19301b", - "0x1b3340053320052ec01b01b33400504700532e01b01b334005048005084", - "0x521800503301b2e900533400521600502a01b01b33400519200551901b", - "0x901b2e600533400501b33501b09700533400521a00522401b2e7005334", - "0x502f00504701b2e40053340052e500529801b2e50053340050972e6007", - "0x1b3350053340053350050bc01b2e90053340052e900502a01b02f005334", - "0x3352e902f0470052e40053340052e400529701b2e70053340052e7005033", - "0x504700532e01b01b33400504800508401b01b33400501b00701b2e42e7", - "0x29801b2e20053340050412e300700901b2e300533400501b33501b01b334", - "0x33400504300502a01b01b00533400501b00504701b2e00053340052e2005", - "0x29701b04200533400504200503301b0070053340050070050bc01b043005", - "0x4500533400501b53201b2e004200704301b0470052e00053340052e0005", - "0x533400501b53501b04100533400501b53401b04300533400501b53301b", - "0x4000533400501b53601b01b33400501b33201b01b33400501b23c01b027", - "0x533400501b53701b07d00533400501b53701b02300533400501b53701b", - "0x33200533400533200553901b33200533400502007d02304004853801b020", - "0x2400553b01b01b33400501b00701b01b61f33000533400733200553a01b", - "0x32b00533400532c00553c01b32c00533400501b33601b32e32f007334005", - "0x33400501b53701b32800533400502500553c01b02500533400501b53701b", - "0x553c01b02f00533400501b53701b00900533400533500553c01b335005", - "0x32e00553e01b03300533400502a00932832b04853d01b02a00533400502f", - "0x32f00533400532f0052c301b03300533400503300553f01b32e005334005", - "0x54101b01b33400501b00701b07c0056200b500533400703332e00754001b", - "0x1b01b33400504100554201b01b33400504700508401b01b3340050b5005", - "0x1b33400502700554501b01b33400504500554401b01b334005043005543", - "0x533400501b54701b32200533400501b32b01b01b33400533000554601b", - "0x33501b32100533400519232200732801b19200533400519200502001b192", - "0x33400503b00529801b03b00533400532103900700901b03900533400501b", - "0x2b501b0050053340050050052b601b01b00533400501b00504701b03a005", - "0x33400504800502a01b32f00533400532f0052c301b007005334005007005", - "0x701b03a04832f00700501b04600503a00533400503a00529701b048005", - "0x1b20900533400503800553c01b03800533400501b54801b01b33400501b", - "0x533400501b53701b21600533400520d00553c01b20d00533400501b537", - "0x21e00553c01b21e00533400501b53701b21a00533400521800553c01b218", - "0x522800553f01b22800533400522421a21620904853d01b224005334005", - "0x33400501b00701b22a00562122900533400722807c00754001b228005334", - "0x33400501b54c01b22e00533400501b54a01b22b00533400501b54901b01b", - "0x55001b23100533400523100554f01b22e00533400522e00554d01b231005", - "0x23905204f04e04862205119304602433400723122e33022922b007005045", - "0x33400501b04801b23d23c00733400505100555101b01b33400501b00701b", - "0x1b19300533400519302700755301b04600533400504604500755201b01b", - "0x5400555501b01b33400501b00701b05600562305400533400723d005554", - "0x533400705500555601b01b33400501b00701b053005624055005334007", - "0x55801b25f00533400525300555701b01b33400501b00701b25d005625253", - "0x55801b01b33400501b00701b01b62600501b19301b03500533400525f005", - "0x55801b01b33400501b00701b01b62600501b19301b03500533400525d005", - "0x55801b01b33400501b00701b01b62600501b19301b035005334005053005", - "0x533400503532f00755901b01b33400501b33201b035005334005056005", - "0x1b54801b01b33400505e00555b01b28405e00733400523c00555a01b042", - "0x53701b00600533400501b53701b06000533400501b53701b061005334005", - "0x6900555a01b06900533400506700606006104855c01b06700533400501b", - "0x28400533400528400555d01b01b3340052ed00555b01b06c2ed007334005", - "0x755f01b06d00533400506c28400755e01b06c00533400506c00555d01b", - "0x1b00701b31600562706f00533400706d00513f01b042005334005042041", - "0x1b56001b01b33400504700508401b01b33400506f00522b01b01b334005", - "0x56101b02600533400501b32101b03600533400501b04e01b315005334005", - "0x33400502603631502433f01b07100533400501b56201b07200533400501b", - "0x2001b07700533400507700556301b01b00533400501b00504701b077005", - "0x7207701b04856401b07100533400507100503a01b072005334005072005", - "0x1b00701b30f00562807500533400707900556501b079311007334005071", - "0x1b01b33400530d00522b01b30d30e00733400507500556601b01b334005", - "0x533400531100504701b30b00533400501b56201b30c00533400501b340", - "0x503a01b30c00533400530c00502001b30e00533400530e00556301b311", - "0x556501b30630a00733400530b30c30e31104856401b30b00533400530b", - "0x33400508500556601b01b33400501b00701b305005629085005334007306", - "0x1b56201b30300533400501b56701b01b33400508300522b01b083304007", - "0x30400533400530400556301b30a00533400530a00504701b302005334005", - "0x30a04856401b30200533400530200503a01b30300533400530300502001b", - "0x1b2ff00562a30000533400730100556501b301081007334005302303304", - "0x33400508700522b01b08707f00733400530000556601b01b33400501b007", - "0x508100504701b2fc00533400501b56901b33d00533400501b56801b01b", - "0x1b33d00533400533d00502001b07f00533400507f00556301b081005334", - "0x1b2fa2fb0073340052fc33d07f08104856401b2fc0053340052fc00503a", - "0x501b32b01b01b33400501b00701b2f800562b2f90053340072fa005565", - "0x32801b2f60053340052f600502001b2f600533400501b56a01b2f7005334", - "0x2f400522b01b2f40440073340052f900556601b2f50053340052f62f7007", - "0x2f300733400504400556c01b04400533400504404300756b01b01b334005", - "0x557001b2f12f20073340052f200556e01b01b3340052f300556d01b2f2", - "0x33400508b00522801b01b33400507e00532e01b08b07e2ee0243340052f1", - "0x7901b2ec00533400508d00557301b08d2ee0073340052ee00557101b01b", - "0x508f2f500732801b08f00533400508f00502001b08f0053340052ec005", - "0x1b2fb0053340052fb00504701b0840053340052ee00557401b2eb005334", - "0x52eb00522401b08400533400508400557501b04800533400504800502a", - "0x501b04801b2e72e92ea0243340052eb0840482fb04857601b2eb005334", - "0x1b01b33400501b00701b2e600562c0970053340072e700507201b01b334", - "0x52f200556e01b01b3340052e400522b01b2e42e5007334005097005071", - "0x3340052e200557801b2df2e02e20243340052e300557001b2e32f2007334", - "0x2e500732801b09e0053340052e000504401b01b3340052df00522801b01b", - "0x50a500557801b2dd0a10a50243340052f200557001b2de00533400509e", - "0x507901b2db0053340052dd00514b01b01b3340050a100532e01b01b334", - "0x3340050ab00522401b0ab0053340050a92de00732801b0a90053340052db", - "0x3340052f200557901b01b33400501b00701b01b62d00501b19301b2d9005", - "0x522401b01b3340050ae00530e01b2d70ae0073340052e600530f01b01b", - "0x901b2d600533400501b33501b01b33400501b33201b2d90053340052d7", - "0x52ea00504701b2d40053340052d500529801b2d50053340052d92d6007", - "0x1b1930053340051930052b501b0460053340050460052b601b2ea005334", - "0x52d400529701b2e90053340052e900502a01b0420053340050420052c3", - "0x554301b01b33400501b00701b2d42e90421930462ea0460052d4005334", - "0x2fb0053340052fb00504701b2d30053340052f800529801b01b334005043", - "0x420052c301b1930053340051930052b501b0460053340050460052b601b", - "0x2d30053340052d300529701b04800533400504800502a01b042005334005", - "0x33400504300554301b01b33400501b00701b2d30480421930462fb046005", - "0x52b601b08100533400508100504701b2d20053340052ff00529801b01b", - "0x53340050420052c301b1930053340051930052b501b046005334005046", - "0x810460052d20053340052d200529701b04800533400504800502a01b042", - "0x29801b01b33400504300554301b01b33400501b00701b2d2048042193046", - "0x3340050460052b601b30a00533400530a00504701b0b4005334005305005", - "0x2a01b0420053340050420052c301b1930053340051930052b501b046005", - "0x4219304630a0460050b40053340050b400529701b048005334005048005", - "0x530f00529801b01b33400504300554301b01b33400501b00701b0b4048", - "0x1b0460053340050460052b601b31100533400531100504701b2d1005334", - "0x504800502a01b0420053340050420052c301b1930053340051930052b5", - "0x1b2d10480421930463110460052d10053340052d100529701b048005334", - "0x1b01b33400504300554301b01b33400531600522b01b01b33400501b007", - "0x52cf00518901b2cf0053340052d004700724b01b2d000533400501b027", - "0x1b0460053340050460052b601b01b00533400501b00504701b049005334", - "0x504800502a01b0420053340050420052c301b1930053340051930052b5", - "0x1b04904804219304601b04600504900533400504900529701b048005334", - "0x1b01b33400504700508401b01b33400505200557a01b01b33400501b007", - "0x1b33400504500554401b01b33400504300554301b01b334005041005542", - "0x533400501b34401b35900533400501b32b01b01b33400502700554501b", - "0x54a01b35c00533400535a35900732801b35a00533400535a00502001b35a", - "0x4f00533400504f0052b501b35d00533400501b54c01b0d100533400501b", - "0x32f04757b01b35d00533400535d00554f01b0d10053340050d100554d01b", - "0x4e0052b601b01b33400501b04801b0be0bb0bc02433400535d0d123904f", - "0xbc0053340050bc0052c301b35c00533400535c00522401b04e005334005", - "0x1b0c400562e0c00053340070be00555401b0bb0053340050bb0052b501b", - "0x501b00701b35e00562f2ce0053340070c000555501b01b33400501b007", - "0x1b01b33400501b00701b35f0056302da0053340072ce00555601b01b334", - "0x63100501b19301b0c90053340052c800555801b2c80053340052da005557", - "0x63100501b19301b0c900533400535f00555801b01b33400501b00701b01b", - "0x63100501b19301b0c900533400535e00555801b01b33400501b00701b01b", - "0x33400501b33201b0c90053340050c400555801b01b33400501b00701b01b", - "0x700901b0ca00533400501b33501b2c70053340050c90bc00755901b01b", - "0x33400501b00504701b2c500533400536100529801b36100533400535c0ca", - "0x2c301b0bb0053340050bb0052b501b04e00533400504e0052b601b01b005", - "0x3340052c500529701b04800533400504800502a01b2c70053340052c7005", - "0x22a00557d01b01b33400501b00701b2c50482c70bb04e01b0460052c5005", - "0x554301b01b33400504100554201b01b33400504700508401b01b334005", - "0x54601b01b33400502700554501b01b33400504500554401b01b334005043", - "0x1b2be00533400501b57e01b2c400533400501b32b01b01b334005330005", - "0x501b33501b0cf0053340052be2c400732801b2be0053340052be005020", - "0xc70053340052b900529801b2b90053340050cf2bb00700901b2bb005334", - "0x70052b501b0050053340050050052b601b01b00533400501b00504701b", - "0x4800533400504800502a01b32f00533400532f0052c301b007005334005", - "0x501b00701b0c704832f00700501b0460050c70053340050c700529701b", - "0x4300554301b01b33400504100554201b01b33400504700508401b01b334", - "0x1b32b01b01b33400502700554501b01b33400504500554401b01b334005", - "0x1b0d00053340050d000502001b0d000533400501b05201b2bc005334005", - "0x2c32b600700901b2b600533400501b33501b2c30053340050d02bc007328", - "0x1b00533400501b00504701b2b40053340052b500529801b2b5005334005", - "0x240052c301b0070053340050070052b501b0050053340050050052b601b", - "0x2b40053340052b400529701b04800533400504800502a01b024005334005", - "0x1b33601b00700500733400501b00557f01b2b404802400700501b046005", - "0x1b04700533400501b53701b04800533400502400553c01b024005334005", - "0x33400504500553c01b04500533400501b53701b04600533400504700553c", - "0x4853d01b04200533400504300553c01b04300533400501b53701b044005", - "0x4100553f01b00700533400500700534501b041005334005042044046048", - "0x533400704100700758101b0050053340050050052c301b041005334005", - "0x1b19301b01b33400519300558201b01b33400501b00701b027005632193", - "0x501b02701b01b33400502700558401b01b33400501b00701b01b633005", - "0x1b07d00533400502300514901b02300533400504000514a01b040005334", - "0x1b07d00500700507d00533400507d00514801b0050053340050050052c3", - "0x504400521801b01b33400504500521601b04404500733400504600520d", - "0x4304204800700504706001b04204700733400504700535c01b043005334", - "0x523101b01b33400501b00701b07d023040024634027193041024334007", - "0x32b01b01b33400504700532e01b01b33400502400508401b01b334005027", - "0x33200533400533200502001b33200533400501b56a01b02000533400501b", - "0x32f00502001b32f00533400501b04e01b33000533400533202000732801b", - "0x32c00533400501b58501b32e00533400532f33000732801b32f005334005", - "0x1b05101b32b00533400532c32e00732801b32c00533400532c00502001b", - "0x533400502532b00732801b02500533400502500502001b025005334005", - "0x529801b00900533400532833500700901b33500533400501b33501b328", - "0x533400504100502a01b01b00533400501b00504701b02f005334005009", - "0x1b04800502f00533400502f00529701b19300533400519300503301b041", - "0x21601b03302a00733400507d00520d01b01b33400501b00701b02f193041", - "0x533400504000502a01b03300533400503300504201b01b33400502a005", - "0x563507c0b500733400703300558701b02300533400502300503301b040", - "0x507c00504501b07c00533400507c00524f01b01b33400501b00701b322", - "0x2001b03900533400501b58801b32100533400519200504401b192005334", - "0x503b00502001b03b0053340050393210072f901b321005334005321005", - "0x563601b33400703b0052f801b0b50053340050b500504201b03b005334", - "0x1b20d0056372090380073340070b500558701b01b33400501b00701b03a", - "0x20900533400520900524f01b01b33400503800533001b01b33400501b007", - "0x501b58901b21800533400521600504401b21600533400520900504501b", - "0x21e00533400521e00502001b21e00533400521a0470072f901b21a005334", - "0x701b22400563801b33400721e0052f801b21800533400521800502001b", - "0x2290053340052282180072f901b22800533400501b58a01b01b33400501b", - "0x701b22a00563901b3340072290052f801b22900533400522900502001b", - "0x22a0052f701b01b33400501b00701b01b63a00501b19301b01b33400501b", - "0x1b58b01b22b00533400501b32b01b01b33400502400508401b01b334005", - "0x533400522e22b00732801b22e00533400522e00502001b22e005334005", - "0x529801b04e00533400523105100700901b05100533400501b33501b231", - "0x533400504000502a01b01b00533400501b00504701b04f00533400504e", - "0x1b04800504f00533400504f00529701b02300533400502300503301b040", - "0x501b29901b01b3340052240052f701b01b33400501b00701b04f023040", - "0x23900533400523900502001b2390053340050522180072f901b052005334", - "0x501b2c001b01b33400501b00701b23c00563b01b3340072390052f801b", - "0x5505600733400505400558d01b05400533400523d00558c01b23d005334", - "0x505300551501b05300533400505500558f01b01b33400505600558e01b", - "0x3a01b25f00533400501b32101b25d0053340052530050d801b253005334", - "0x25f02304004820901b25d00533400525d0052b301b25f00533400525f005", - "0x2001b01b33400501b00701b00606006102463c28405e03502433400725d", - "0x33400505e00503301b03500533400503500502a01b284005334005284005", - "0x2701b01b33400501b00701b06700563d01b3340072840052f801b05e005", - "0x3340052ed00518901b2ed00533400506902400724b01b06900533400501b", - "0x3301b03500533400503500502a01b01b00533400501b00504701b06c005", - "0x6c05e03501b04800506c00533400506c00529701b05e00533400505e005", - "0x1b33400502400508401b01b3340050670052f701b01b33400501b00701b", - "0x33400506f00502001b06f00533400501b59001b06d00533400501b32b01b", - "0x901b31500533400501b33501b31600533400506f06d00732801b06f005", - "0x501b00504701b02600533400503600529801b036005334005316315007", - "0x1b05e00533400505e00503301b03500533400503500502a01b01b005334", - "0x1b01b33400501b00701b02605e03501b048005026005334005026005297", - "0x33400500607200700901b07200533400501b33501b01b334005024005084", - "0x2a01b01b00533400501b00504701b07700533400507100529801b071005", - "0x33400507700529701b06000533400506000503301b061005334005061005", - "0x33400523c0052f701b01b33400501b00701b07706006101b048005077005", - "0x33400501b58b01b31100533400501b32b01b01b33400502400508401b01b", - "0x1b07500533400507931100732801b07900533400507900502001b079005", - "0x530e00529801b30e00533400507530f00700901b30f00533400501b335", - "0x1b04000533400504000502a01b01b00533400501b00504701b30d005334", - "0x2304001b04800530d00533400530d00529701b023005334005023005033", - "0x33400502400508401b01b33400520d00533001b01b33400501b00701b30d", - "0x33400501b05201b30c00533400501b32b01b01b33400504700532e01b01b", - "0x1b30a00533400530b30c00732801b30b00533400530b00502001b30b005", - "0x508500529801b08500533400530a30600700901b30600533400501b335", - "0x1b04000533400504000502a01b01b00533400501b00504701b305005334", - "0x2304001b04800530500533400530500529701b023005334005023005033", - "0x33400502400508401b01b33400503a0052f701b01b33400501b00701b305", - "0x33400501b32b01b01b3340050b500533001b01b33400504700532e01b01b", - "0x732801b08300533400508300502001b08300533400501b58b01b304005", - "0x33400530330200700901b30200533400501b33501b303005334005083304", - "0x2a01b01b00533400501b00504701b30100533400508100529801b081005", - "0x33400530100529701b02300533400502300503301b040005334005040005", - "0x33400532200533001b01b33400501b00701b30102304001b048005301005", - "0x33400501b32b01b01b33400504700532e01b01b33400502400508401b01b", - "0x732801b2ff0053340052ff00502001b2ff00533400501b05201b300005", - "0x33400507f08700700901b08700533400501b33501b07f0053340052ff300", - "0x2a01b01b00533400501b00504701b2fc00533400533d00529801b33d005", - "0x3340052fc00529701b02300533400502300503301b040005334005040005", - "0x700504601b00700533400500500502401b2fc02304001b0480052fc005", - "0x33400504800505601b01b33400501b00701b04700563e048024007334007", - "0x19301b04400533400504600505501b04500533400502400504201b046005", - "0x505301b04300533400501b02701b01b33400501b00701b01b63f00501b", - "0x533400504200505501b04500533400504700504201b042005334005043", - "0x25301b19300533400504100521801b04104500733400504500507701b044", - "0x502700504501b01b33400501b00701b040005640027005334007044005", - "0x1b07d00533400507d00502001b07d00533400502300504401b023005334", - "0x23101b01b33400501b00701b33000564133202000733400707d01b00710f", - "0x4500733400504500507701b32f00533400501b32101b01b334005193005", - "0x59101b32f00533400532f00503a01b32c33200733400533200503901b32e", - "0x1b01b33400501b00701b32800564202532b00733400732c32f32e020048", - "0x33200503901b00900533400533500531101b335045007334005045005077", - "0x533400502500504201b00900533400500900503a01b02f332007334005", - "0x501b00701b07c0b500764303302a00733400702f00932b0244fd01b025", - "0x1b00701b32100564419232200733400703333204502a04859101b01b334", - "0x1b03b00533400503900559201b03900533400502500521801b01b334005", - "0x3800559401b03800533400503b03a00759301b03a005334005192005218", - "0x20900533400520900559501b32200533400532200504701b209005334005", - "0x1b32b01b01b33400502500533001b01b33400501b00701b209322007005", - "0x1b21600533400521600502001b21600533400501b24a01b20d005334005", - "0x21821a00700901b21a00533400501b33501b21800533400521620d007328", - "0x32100533400532100504701b22400533400521e00559601b21e005334005", - "0x22801b01b33400501b00701b22432100700522400533400522400559501b", - "0x1b01b33400504500533001b01b33400502500533001b01b33400507c005", - "0x22900533400501b59701b22800533400501b32b01b01b334005332005228", - "0x1b33501b22a00533400522922800732801b22900533400522900502001b", - "0x533400522e00559601b22e00533400522a22b00700901b22b005334005", - "0xb500700523100533400523100559501b0b50053340050b500504701b231", - "0x33400504500533001b01b33400533200522801b01b33400501b00701b231", - "0x504e00502001b04e00533400501b24a01b05100533400501b32b01b01b", - "0x1b05200533400501b33501b04f00533400504e05100732801b04e005334", - "0x32800504701b23c00533400523900559601b23900533400504f052007009", - "0x501b00701b23c32800700523c00533400523c00559501b328005334005", - "0x23d00559801b23d00533400501b02701b01b33400504500533001b01b334", - "0x533400505600559401b05600533400505419300759301b054005334005", - "0x33000700505500533400505500559501b33000533400533000504701b055", - "0x33400504500533001b01b33400504000522b01b01b33400501b00701b055", - "0x19300759301b25300533400505300559801b05300533400501b02701b01b", - "0x533400501b00504701b25f00533400525d00559401b25d005334005253", - "0x1b01b33400501b33201b25f01b00700525f00533400525f00559501b01b", - "0x1b01b33400501b00701b04404500764504604700733400700501b007005", - "0x430052f801b04700533400504700504701b04304800733400504800535c", - "0x1b01b33400504800532e01b01b33400501b00701b04200564601b334007", - "0x19300559b01b19300533400504100700759a01b041005334005024005599", - "0x4600533400504600502a01b04700533400504700504701b027005334005", - "0x1b01b33400501b00701b02704604702400502700533400502700559c01b", - "0x33400500700525d01b04700533400504700504701b01b3340050420052f7", - "0x533400707d00534901b07d02304002433400500704700759d01b007005", - "0x1b33000533400502002400759e01b01b33400501b00701b332005647020", - "0x504000504701b32e00533400532f0480072f901b32f00533400501b04f", - "0x1b02300533400502300525d01b04600533400504600502a01b040005334", - "0x4604004710001b32e00533400532e00502001b3300053340053300050ff", - "0x1b33400501b00701b02532b32c02400502532b32c02433400532e330023", - "0x3340053320055a001b01b33400502400510701b01b33400504800532e01b", - "0x1b00900533400533500559b01b33500533400532802300759a01b328005", - "0x500900559c01b04600533400504600502a01b040005334005040005047", - "0x33400504800532e01b01b33400501b00701b009046040024005009005334", - "0x33400501b32b01b01b33400500700523101b01b33400502400510701b01b", - "0x732801b02a00533400502a00502001b02a00533400501b22901b02f005", - "0x3340050330b500700901b0b500533400501b33501b03300533400502a02f", - "0x2a01b04500533400504500504701b32200533400507c0055a101b07c005", - "0x1b32204404502400532200533400532200559c01b044005334005044005", - "0x1b04504600764804704800733400700501b00700501b01b33400501b332", - "0x1b01b33400501b04801b04400533400500700502401b01b33400501b007", - "0x1b04100564904204300733400704400504601b048005334005048005047", - "0x533400504300504201b19300533400504200505601b01b33400501b007", - "0x33400501b00701b01b64a00501b19301b04000533400519300505501b027", - "0x4100504201b07d00533400502300505301b02300533400501b02701b01b", - "0x2000533400502700521801b04000533400507d00505501b027005334005", - "0x504501b01b33400501b00701b33000564b33200533400704000525301b", - "0x533400532f00502001b32e00533400502400502401b32f005334005332", - "0x1b01b33400501b00701b02500564c32b32c00733400732e00504601b32f", - "0x532f00504401b33500533400532c00521801b32800533400532b005045", - "0x1b02f00533400502f00502001b02f00533400532800504401b009005334", - "0x33500525d01b02a00533400502a00502001b02a00533400502f0090072f9", - "0x1b33400501b00701b03300564d01b33400702a0052f801b335005334005", - "0x33400504700502a01b04800533400504800504701b01b33400501b33201b", - "0x27301b33500533400533500525d01b02000533400502000525d01b047005", - "0x501b00701b32207c0b502400532207c0b5024334005335020047048048", - "0x33400501b02701b01b3340050330052f701b01b33400501b33201b01b334", - "0x390053340053213350200245a301b3210053340051920050a901b192005", - "0x4700502a01b04800533400504800504701b03b00533400503900534a01b", - "0x1b00701b03b04704802400503b00533400503b0055a501b047005334005", - "0x32f00532e01b01b33400502500533001b01b33400501b33201b01b334005", - "0x1b05201b03a00533400501b32b01b01b33400502000523101b01b334005", - "0x533400503803a00732801b03800533400503800502001b038005334005", - "0x55a601b21600533400520920d00700901b20d00533400501b33501b209", - "0x533400504700502a01b04800533400504800504701b218005334005216", - "0x1b33400501b00701b2180470480240052180053340052180055a501b047", - "0x21a00533400501b02701b01b33400533000522b01b01b33400501b33201b", - "0x34a01b22400533400521e0240200245a301b21e00533400521a0052dd01b", - "0x33400504700502a01b04800533400504800504701b228005334005224005", - "0x33400501b00701b2280470480240052280053340052280055a501b047005", - "0x33400501b32b01b01b33400500700523101b01b33400502400523101b01b", - "0x732801b22a00533400522a00502001b22a00533400501b22901b229005", - "0x33400522b22e00700901b22e00533400501b33501b22b00533400522a229", - "0x2a01b04600533400504600504701b0510053340052310055a601b231005", - "0x1b0510450460240050510053340050510055a501b045005334005045005", - "0x1b04504600764e04704800733400700501b00700501b01b33400501b332", - "0x1b01b33400501b04801b04400533400500700527001b01b33400501b007", - "0x1b04100564f0420430073340070440055a801b048005334005048005047", - "0x53340050430055aa01b1930053340050420055a901b01b33400501b007", - "0x33400501b00701b01b65000501b19301b0400053340051930055ab01b027", - "0x410055aa01b07d0053340050230055ac01b02300533400501b02701b01b", - "0x2000533400502700510901b04000533400507d0055ab01b027005334005", - "0x55ae01b01b33400501b00701b3300056513320053340070400055ad01b", - "0x533400532f0055af01b32e00533400502400527001b32f005334005332", - "0x1b01b33400501b00701b02500565232b32c00733400732e0055a801b32f", - "0x532f0055b001b33500533400532c00510901b32800533400532b0055ae", - "0x33400502a00530101b03302a02f0243340050090055b101b00932f007334", - "0x3280055af01b0b500533400502f00504401b01b3340050330050c001b01b", - "0x2433400507c0055b101b07c3280073340053280055b001b328005334005", - "0x504401b01b3340053210050c001b01b33400519200530101b321192322", - "0x33400503b00502001b03b0053340050390b50072f901b039005334005322", - "0x3a00565301b33400703b0052f801b33500533400533500527201b03b005", - "0x50380055b101b03832f00733400532f0055b001b01b33400501b00701b", - "0x1b01b3340052160050c001b01b33400520900532e01b21620d209024334", - "0x21a0055b101b21a3280073340053280055b001b21800533400520d005293", - "0x1b3340052280050c001b01b33400521e00532e01b22822421e024334005", - "0x701b01b65401b3340072292180070eb01b22900533400522400529301b", - "0x19301b01b33400532f0055b201b01b3340053280055b201b01b33400501b", - "0x22e22b22a02433400532f0055b101b01b33400501b00701b01b65500501b", - "0x33400522e0052c401b01b33400522b00530101b01b33400522a00532e01b", - "0x1b01b33400505100532e01b04f04e0510243340053280055b101b231005", - "0x705223100713401b05200533400504f0052c401b01b33400504e005301", - "0x501b00701b01b65500501b19301b01b33400501b00701b01b65601b334", - "0x4700502a01b04800533400504800504701b01b33400501b33201b01b334", - "0x33500533400533500527201b02000533400502000527201b047005334005", - "0x701b23d23c23902400523d23c23902433400533502004704804814e01b", - "0x5b201b01b3340053280055b201b01b33400503a0052f701b01b33400501b", - "0xa901b05400533400501b02701b01b33400501b33201b01b33400532f005", - "0x550055b401b0550053340050563350200245b301b056005334005054005", - "0x4700533400504700502a01b04800533400504800504701b053005334005", - "0x1b01b33400501b00701b0530470480240050530053340050530055b501b", - "0x1b01b33400502000528301b01b3340050250055b601b01b33400501b332", - "0x25d00533400501b05201b25300533400501b32b01b01b33400532f0055b2", - "0x1b33501b25f00533400525d25300732801b25d00533400525d00502001b", - "0x533400505e00534e01b05e00533400525f03500700901b035005334005", - "0x55b501b04700533400504700502a01b04800533400504800504701b284", - "0x501b33201b01b33400501b00701b284047048024005284005334005284", - "0x610052dd01b06100533400501b02701b01b33400533000522b01b01b334", - "0x3340050060055b401b0060053340050600240200245b301b060005334005", - "0x5b501b04700533400504700502a01b04800533400504800504701b067005", - "0x528301b01b33400501b00701b067047048024005067005334005067005", - "0x22901b06900533400501b32b01b01b33400502400528301b01b334005007", - "0x3340052ed06900732801b2ed0053340052ed00502001b2ed00533400501b", - "0x34e01b06f00533400506c06d00700901b06d00533400501b33501b06c005", - "0x33400504500502a01b04600533400504600504701b31600533400506f005", - "0x33400501b33201b3160450460240053160053340053160055b501b045005", - "0x33400501b00701b04504600765704704800733400700501b00700501b01b", - "0x504800504701b01b33400501b04801b04400533400500700565801b01b", - "0x33400501b00701b04100565a04204300733400704400565901b048005334", - "0x534f01b02700533400504300565c01b19300533400504200565b01b01b", - "0x1b02701b01b33400501b00701b01b65d00501b19301b040005334005193", - "0x2700533400504100565c01b07d00533400502300565e01b023005334005", - "0x4000565f01b02000533400502700525e01b04000533400507d00534f01b", - "0x533400533200566101b01b33400501b00701b330005660332005334007", - "0x513901b04800533400504800504701b32e00533400532f00566201b32f", - "0x532e02404802466301b32e00533400532e00526001b024005334005024", - "0x33400501b00701b32800566402500533400732b00525501b32b32c007334", - "0x900522b01b00933500733400502500517101b01b33400501b33201b01b", - "0x1b04700533400504700502a01b32c00533400532c00504701b01b334005", - "0x4732c04825b01b33500533400533500513901b02000533400502000513a", - "0x1b01b33400501b00701b03302a02f02400503302a02f024334005335020", - "0xb500533400532800566501b01b33400502000525701b01b33400501b332", - "0xb500566601b04700533400504700502a01b32c00533400532c00504701b", - "0x33400501b33201b01b33400501b00701b0b504732c0240050b5005334005", - "0x2402002466701b07c00533400501b02701b01b33400533000522b01b01b", - "0x533400504800504701b19200533400532200566801b32200533400507c", - "0x4802400519200533400519200566601b04700533400504700502a01b048", - "0x502400517401b01b33400500700525701b01b33400501b00701b192047", - "0x3900502001b03900533400501b22901b32100533400501b32b01b01b334", - "0x3a00533400501b33501b03b00533400503932100732801b039005334005", - "0x504701b20900533400503800566501b03800533400503b03a00700901b", - "0x533400520900566601b04500533400504500502a01b046005334005046", - "0x4700733400500700517301b01b33400501b33201b209045046024005209", - "0x4500503a01b04400533400501b66a01b04500533400504600566901b046", - "0x33400504404501b02466c01b04400533400504400566b01b045005334005", - "0x503901b01b33400501b04801b01b33400504200522801b041042043024", - "0x33400719300566d01b04300533400504300504701b193048007334005048", - "0x522801b01b33400502400530101b01b33400501b00701b02700566e01b", - "0x1b02300533400504300504701b04000533400501b0ed01b01b334005048", - "0x1b01b33400501b00701b01b66f00501b19301b07d00533400504000507f", - "0x733400504800503901b02000533400501b53101b01b334005027005670", - "0x56901b01b33400501b00701b01b67101b33400702033200727401b332048", - "0x733032f00727401b32f04800733400504800503901b33000533400501b", - "0x503901b32e00533400501b4fc01b01b33400501b00701b01b67201b334", - "0x501b00701b01b67301b33400732e32c00727401b32c048007334005048", - "0x27401b02504800733400504800503901b32b00533400501b67401b01b334", - "0x533400501b67601b01b33400501b00701b01b67501b33400732b025007", - "0x1b67701b33400732833500727401b33504800733400504800503901b328", - "0x733400504800503901b00900533400501b67801b01b33400501b00701b", - "0x67a01b01b33400501b00701b01b67901b33400700902f00727401b02f048", - "0x33400501b00701b01b67b01b33400702a04800727401b02a00533400501b", - "0x33400504100522801b01b33400504700517401b01b33400501b33201b01b", - "0x33400501b67c01b03300533400501b32b01b01b33400502400530101b01b", - "0x1b07c0053340050b503300732801b0b50053340050b500502001b0b5005", - "0x519200567d01b19200533400507c32200700901b32200533400501b335", - "0x1b00500533400500500502a01b04300533400504300504701b321005334", - "0x67f01b01b33400501b00701b32100504302400532100533400532100567e", - "0x1b01b68000501b19301b03b00533400503900507f01b03900533400501b", - "0x1b03a00533400501b68101b01b33400504800522801b01b33400501b007", - "0x68200501b19301b03800533400503b00529301b03b00533400503a00507f", - "0x533400501b68301b01b33400504800522801b01b33400501b00701b01b", - "0x1b19301b20d00533400503800529301b03800533400520900507f01b209", - "0x501b68501b01b33400504800522801b01b33400501b00701b01b684005", - "0x1b21800533400520d00529301b20d00533400521600507f01b216005334", - "0x68701b01b33400504800522801b01b33400501b00701b01b68600501b193", - "0x533400521800529301b21800533400521a00507f01b21a00533400501b", - "0x1b33400504800522801b01b33400501b00701b01b68800501b19301b21e", - "0x521e00529301b21e00533400522400507f01b22400533400501b68901b", - "0x504800522801b01b33400501b00701b01b68a00501b19301b228005334", - "0x529601b22800533400522900507f01b22900533400501b68b01b01b334", - "0x501b00701b22b00568d01b33400722a00568c01b22a228007334005228", - "0x504100522801b01b33400504700517401b01b33400501b33201b01b334", - "0x501b32b01b01b33400502400530101b01b33400522800530101b01b334", - "0x32801b23100533400523100502001b23100533400501b05201b22e005334", - "0x505104e00700901b04e00533400501b33501b05100533400523122e007", - "0x1b04300533400504300504701b05200533400504f00567d01b04f005334", - "0x5200504302400505200533400505200567e01b00500533400500500502a", - "0x30101b23d23c23902433400522b02404302468e01b01b33400501b00701b", - "0x5305500768f05605400733400723d22823902429201b01b33400523c005", - "0x33400505600507f01b02300533400505400504701b01b33400501b00701b", - "0x27401b25d04100733400504100503901b25300533400501b69001b07d005", - "0x1b33400501b33201b01b33400501b00701b01b69101b33400725325d007", - "0x3500503a01b03500533400501b69001b25f00533400507d04700718101b", - "0x3340070410350230244fd01b25f00533400525f00513901b035005334005", - "0x533400505e00504701b01b33400501b00701b06006100769228405e007", - "0x503a01b25f00533400525f00513901b00500533400500500502a01b05e", - "0x2400506906700602433400528425f00505e04869301b284005334005284", - "0x25f00517401b01b33400506000522801b01b33400501b00701b069067006", - "0x502001b06c00533400501b59701b2ed00533400501b32b01b01b334005", - "0x533400501b33501b06d00533400506c2ed00732801b06c00533400506c", - "0x4701b31500533400531600567d01b31600533400506d06f00700901b06f", - "0x33400531500567e01b00500533400500500502a01b061005334005061005", - "0x1b01b33400501b33201b01b33400501b00701b315005061024005315005", - "0x533400503600507f01b03600533400501b69401b01b334005041005228", - "0x501b00701b07707100769507202600733400707d03602302429201b036", - "0x69601b07900533400501b02701b31100533400507204700718101b01b334", - "0x502600504701b30f00533400507500569701b075005334005079311007", - "0x530f00533400530f00567e01b00500533400500500502a01b026005334", - "0x517401b01b33400507700530101b01b33400501b00701b30f005026024", - "0x2001b30d00533400501b29101b30e00533400501b32b01b01b334005047", - "0x33400501b33501b30c00533400530d30e00732801b30d00533400530d005", - "0x1b30600533400530a00567d01b30a00533400530c30b00700901b30b005", - "0x530600567e01b00500533400500500502a01b071005334005071005047", - "0x1b33400501b33201b01b33400501b00701b306005071024005306005334", - "0x33400504100522801b01b33400504700517401b01b33400505300530101b", - "0x530500502001b30500533400501b29101b08500533400501b32b01b01b", - "0x1b08300533400501b33501b30400533400530508500732801b305005334", - "0x5500504701b30200533400530300567d01b303005334005304083007009", - "0x30200533400530200567e01b00500533400500500502a01b055005334005", - "0x33400504700569801b04704800733400500500523801b302005055024005", - "0x1b04600533400504600503a01b04502400733400502400503901b046005", - "0x500700522801b01b33400501b00701b04400569901b33400704500566d", - "0x724901b04300533400504300503a01b04300533400501b69a01b01b334", - "0x33400504200524801b04100533400501b00504701b042005334005043048", - "0x33400504400567001b01b33400501b00701b01b69b00501b19301b193005", - "0x727401b04002400733400502400503901b02700533400501b53101b01b", - "0x2300533400501b56901b01b33400501b00701b01b69c01b334007027040", - "0x1b01b69d01b33400702307d00727401b07d02400733400502400503901b", - "0x1b33200533400501b69f01b02000533400501b69e01b01b33400501b007", - "0x33400533200503a01b32f00533400502000566b01b33000533400501b6a0", - "0x501b00701b01b6a100501b19301b32c00533400533000503a01b32e005", - "0x501b6a301b02500533400501b35301b32b00533400501b6a201b01b334", - "0x1b32e00533400502500503a01b32f00533400532b00566b01b328005334", - "0x532e00514b01b33500533400532f0056a401b32c00533400532800503a", - "0x1b00701b01b6a500501b19301b02f00533400532c00514b01b009005334", - "0x1b6a801b03300533400501b6a701b02a00533400501b6a601b01b334005", - "0x900533400503300503a01b33500533400502a00566b01b0b5005334005", - "0x19232207c02433400533500701b02466c01b02f0053340050b500503a01b", - "0x32100507f01b3210053340050091920076a901b01b33400532200522801b", - "0x1b00701b03a0056ab03b03900733400732107c0076aa01b321005334005", - "0x701b21620d0076ad20903800733400702f03b0390246ac01b01b334005", - "0x533400503800504701b21800533400520904800724901b01b33400501b", - "0x69801b21e21a00733400519300523801b19300533400521800524801b041", - "0x533400522400503a01b22800533400501b53101b22400533400521e005", - "0x22a2290073340072282240410246ac01b22800533400522800503a01b224", - "0x566b01b23100533400501b6af01b01b33400501b00701b22e22b0076ae", - "0x522801b04f04e05102433400523122a22902466c01b231005334005231", - "0x1b23900533400501b6b001b05200533400504f00507901b01b33400504e", - "0x21a00524801b23c0053340050522390072f901b239005334005239005020", - "0x533400523c21a0076b101b23c00533400523c00502001b21a005334005", - "0x507f01b0560053340050540460076a901b05400533400501b6b201b23d", - "0x701b2530056b30530550073340070560510076aa01b056005334005056", - "0x25f00533400525d0240076a901b25d00533400501b6b401b01b33400501b", - "0x56b505e03500733400725f0550076aa01b25f00533400525f00507f01b", - "0x76b606006100733400705e0530350246ac01b01b33400501b00701b284", - "0x1b02701b06900533400506023d00724901b01b33400501b00701b067006", - "0x533400506c0056b801b06c0053340052ed0690076b701b2ed005334005", - "0x6100700506d00533400506d0056b901b06100533400506100504701b06d", - "0x33400523d00523701b01b33400506700522801b01b33400501b00701b06d", - "0x531600502001b31600533400501b6ba01b06f00533400501b32b01b01b", - "0x1b03600533400501b33501b31500533400531606f00732801b316005334", - "0x600504701b0720053340050260056bb01b026005334005315036007009", - "0x501b00701b0720060070050720053340050720056b901b006005334005", - "0x501b32b01b01b33400505300522801b01b33400523d00523701b01b334", - "0x32801b07700533400507700502001b07700533400501b6bc01b071005334", - "0x531107900700901b07900533400501b33501b311005334005077071007", - "0x1b28400533400528400504701b30f0053340050750056bb01b075005334", - "0x523701b01b33400501b00701b30f28400700530f00533400530f0056b9", - "0x6bc01b30e00533400501b32b01b01b33400502400522801b01b33400523d", - "0x33400530d30e00732801b30d00533400530d00502001b30d00533400501b", - "0x6bb01b30a00533400530c30b00700901b30b00533400501b33501b30c005", - "0x3340053060056b901b25300533400525300504701b30600533400530a005", - "0x1b01b33400522e00522801b01b33400501b00701b306253007005306005", - "0x1b33400521a00523701b01b33400502400522801b01b334005046005228", - "0x33400530500502001b30500533400501b6ba01b08500533400501b32b01b", - "0x901b08300533400501b33501b30400533400530508500732801b305005", - "0x522b00504701b3020053340053030056bb01b303005334005304083007", - "0x33400501b00701b30222b0070053020053340053020056b901b22b005334", - "0x502400522801b01b33400504600522801b01b33400521600522801b01b", - "0x501b6ba01b08100533400501b32b01b01b33400504800523701b01b334", - "0x30000533400530108100732801b30100533400530100502001b301005334", - "0x7f0056bb01b07f0053340053002ff00700901b2ff00533400501b33501b", - "0x870053340050870056b901b20d00533400520d00504701b087005334005", - "0x522801b01b33400504600522801b01b33400501b00701b08720d007005", - "0x32b01b01b33400502f00522801b01b33400504800523701b01b334005024", - "0x2fc0053340052fc00502001b2fc00533400501b6bc01b33d00533400501b", - "0x2fa00700901b2fa00533400501b33501b2fb0053340052fc33d00732801b", - "0x533400503a00504701b2f80053340052f90056bb01b2f90053340052fb", - "0x1b01b33400501b33201b2f803a0070052f80053340052f80056b901b03a", - "0x1b01b33400501b00701b0440450076bd04604700733400700501b007005", - "0x3340070430470076bf01b01b33400501b04801b0430053340050240056be", - "0x3340051930056c101b01b33400501b00701b0400270076c0193041042024", - "0x6c301b0200053340050410056c201b07d00533400504200504701b023005", - "0x2701b01b33400501b00701b01b6c400501b19301b332005334005023005", - "0x533400502700504701b32f0053340053300056c501b33000533400501b", - "0x519701b33200533400532f0056c301b0200053340050400056c201b07d", - "0x501b00701b32b0056c732c0053340073320056c601b32e005334005020", - "0x460486c901b02500533400532c0056c801b01b33400501b33201b01b334", - "0x1b33400501b00701b03302a02f0246ca009335328024334007025048007", - "0x33500503301b32800533400532800502a01b07d00533400507d00504701b", - "0x900533400500900523301b32e00533400532e00523501b335005334005", - "0x32207c0b504800519232207c0b504833400500932e33532807d04723001b", - "0x533400501b33501b01b33400532e00522f01b01b33400501b00701b192", - "0x4701b03b0053340050390056cb01b03900533400503332100700901b321", - "0x33400502a00503301b02f00533400502f00502a01b07d00533400507d005", - "0x501b00701b03b02a02f07d04800503b00533400503b0056cc01b02a005", - "0x33400501b02701b01b33400532b00522b01b01b33400501b33201b01b334", - "0x2090053340050380056ce01b03800533400503a04832e0246cd01b03a005", - "0x700503301b04600533400504600502a01b07d00533400507d00504701b", - "0x701b20900704607d0480052090053340052090056cc01b007005334005", - "0x32b01b01b33400502400522f01b01b3340050480056cf01b01b33400501b", - "0x21600533400521600502001b21600533400501b22901b20d00533400501b", - "0x21a00700901b21a00533400501b33501b21800533400521620d00732801b", - "0x533400504500504701b22400533400521e0056cb01b21e005334005218", - "0x56cc01b00700533400500700503301b04400533400504400502a01b045", - "0x56d001b01b33400501b33201b224007044045048005224005334005224", - "0x420050ab01b0420430440243340050450056d101b045047007334005047", - "0x1930073340051930051b101b19304100733400504400520801b01b334005", - "0x52c401b01b3340050230050c001b02304000733400502700517801b027", - "0x33400501b00701b0200056d301b33400707d0056d201b07d005334005040", - "0x52c401b01b3340053320050c001b33033200733400519300517801b01b", - "0x33400501b00701b32e0056d401b33400732f0056d201b32f005334005330", - "0x50470056d601b01b3340050460056d501b01b33400504300518401b01b", - "0x1b00504701b01b33400504100518401b01b33400504800518401b01b334", - "0x32e0056d801b01b33400501b00701b01b6d700501b19301b32c005334005", - "0x50200056d801b01b33400501b00701b01b6d900501b19301b01b334005", - "0x6da01b02532b00733400504100517801b01b33400519300518401b01b334", - "0x3340050250056db01b00933500733400532800517801b32800533400501b", - "0x2a00533400502a00517b01b02a0090073340050090056db01b02f025007", - "0x33400501b00701b32207c0076dd0b503300733400702a02f01b0246dc01b", - "0x2500713401b03300533400503300504701b01b3340050b50050c001b01b", - "0x1b01b33400504300518401b01b33400501b00701b01b6de01b334007009", - "0x1b33400504800518401b01b3340050470056d601b01b3340050460056d5", - "0x33400503300504701b01b33400532b0050c001b01b3340053350050c001b", - "0x33400533500517b01b01b33400501b00701b01b6d700501b19301b32c005", - "0x1b00701b03b0390076df32119200733400733532b0330246dc01b335005", - "0x56d501b01b33400504300518401b01b3340053210050c001b01b334005", - "0x4701b01b33400504800518401b01b3340050470056d601b01b334005046", - "0x533400503a0056e101b03a00533400501b6e001b32c005334005192005", - "0x502a01b20d0053340052090056e301b2090053340050380056e201b038", - "0x533400502400503301b0070053340050070052d501b005005334005005", - "0x501b00701b20d02400700532c04700520d00533400520d0056e401b024", - "0x1b19301b21600533400503900504701b01b33400503b0050c001b01b334", - "0x250050c001b01b3340053220050c001b01b33400501b00701b01b6e5005", - "0x50c001b01b33400532b0050c001b01b3340053350050c001b01b334005", - "0x21800733400504300520801b21600533400507c00504701b01b334005009", - "0x1b22822400733400521e00517801b21e21a00733400521a0051b101b21a", - "0x1b33400501b04801b2290053340052240052c401b01b3340052280050c0", - "0x21a00517801b01b33400501b00701b22a0056e601b3340072290056d201b", - "0x23100533400522e0052c401b01b33400522b0050c001b22e22b007334005", - "0x501b33201b01b33400501b00701b0510056e701b3340072310056d201b", - "0x4800518401b01b3340050470056d601b01b3340050460056d501b01b334", - "0x19301b04e00533400521600504701b01b33400521800518401b01b334005", - "0x1b19301b01b3340050510056d801b01b33400501b00701b01b6e800501b", - "0x21a00518401b01b33400522a0056d801b01b33400501b00701b01b6e9005", - "0x6da01b05204f00733400521800517801b01b33400501b33201b01b334005", - "0x3340050520056db01b23d23c00733400523900517801b23900533400501b", - "0x5600533400505600517b01b05623d00733400523d0056db01b054052007", - "0x33400501b00701b25d2530076ea0530550073340070560542160246dc01b", - "0x5200713401b05500533400505500504701b01b3340050530050c001b01b", - "0x1b01b3340050460056d501b01b33400501b00701b01b6eb01b33400723d", - "0x1b33400523c0050c001b01b33400504800518401b01b3340050470056d6", - "0x6e800501b19301b04e00533400505500504701b01b33400504f0050c001b", - "0x4f0550246dc01b23c00533400523c00517b01b01b33400501b00701b01b", - "0x350050c001b01b33400501b00701b28405e0076ec03525f00733400723c", - "0x518401b01b3340050470056d601b01b3340050460056d501b01b334005", - "0x1b06100533400501b6e001b04e00533400525f00504701b01b334005048", - "0x50060056e301b0060053340050600056e201b0600053340050610056e1", - "0x1b0070053340050070052d501b00500533400500500502a01b067005334", - "0x700504e0470050670053340050670056e401b024005334005024005033", - "0x505e00504701b01b3340052840050c001b01b33400501b00701b067024", - "0x525d0050c001b01b33400501b00701b01b6ed00501b19301b069005334", - "0x4f0050c001b01b33400523c0050c001b01b3340050520050c001b01b334", - "0x2a01b06900533400525300504701b01b33400523d0050c001b01b334005", - "0x33400504800526001b02400533400502400503301b005005334005005005", - "0x3340050470480240050690476ee01b0470053340050470051bc01b048005", - "0x501b00701b3150056f031600533400706f0056ef01b06f06d06c2ed048", - "0x56f202600533400703600521701b0360053340053160056f101b01b334", - "0x506c00502a01b2ed0053340052ed00504701b01b33400501b00701b072", - "0x1b06d00533400506d00503301b0070053340050070052d501b06c005334", - "0x7707104733400502606d00706c2ed0476f401b0260053340050260056f3", - "0x1b33400501b00701b30e0056f630f0053340070750056f501b075079311", - "0x56d501b30b30c0073340050460056f801b30d00533400530f0056f701b", - "0x1b33400530a0056d501b30630a00733400530d0056f801b01b33400530c", - "0x8500504401b3050053340053060056f901b08500533400530b0056f901b", - "0x53340050833040072f901b08300533400530500504401b304005334005", - "0x1b3020056fa01b3340073030052f801b30300533400530300502001b303", - "0x3010053340050810056fb01b08100533400501b02701b01b33400501b007", - "0x7100504701b2ff0053340053000056e301b3000053340053010056e201b", - "0x3110053340053110052d501b07700533400507700502a01b071005334005", - "0x770710470052ff0053340052ff0056e401b07900533400507900503301b", - "0x501b6fc01b01b3340053020052f701b01b33400501b00701b2ff079311", - "0x1b33d0053340050870056e201b08700533400507f0056e101b07f005334", - "0x507700502a01b07100533400507100504701b2fc00533400533d0056e3", - "0x1b07900533400507900503301b3110053340053110052d501b077005334", - "0x1b33400501b00701b2fc0793110770710470052fc0053340052fc0056e4", - "0x507100504701b2fb00533400530e0056fd01b01b3340050460056d501b", - "0x1b3110053340053110052d501b07700533400507700502a01b071005334", - "0x3110770710470052fb0053340052fb0056e401b079005334005079005033", - "0x50460056d501b01b33400507200522b01b01b33400501b00701b2fb079", - "0x2f900502001b2f900533400501b05201b2fa00533400501b32b01b01b334", - "0x2f700533400501b33501b2f80053340052f92fa00732801b2f9005334005", - "0x504701b2f50053340052f60056fd01b2f60053340052f82f700700901b", - "0x53340050070052d501b06c00533400506c00502a01b2ed0053340052ed", - "0x2ed0470052f50053340052f50056e401b06d00533400506d00503301b007", - "0x56fd01b01b3340050460056d501b01b33400501b00701b2f506d00706c", - "0x533400506c00502a01b2ed0053340052ed00504701b2f4005334005315", - "0x56e401b06d00533400506d00503301b0070053340050070052d501b06c", - "0x480073340050480051b101b2f406d00706c2ed0470052f40053340052f4", - "0x1b0420430073340050430051b101b04304400733400504500520801b045", - "0x50410052c401b01b3340051930050c001b193041007334005042005178", - "0x1b01b33400501b00701b0400056fe01b3340070270056d201b027005334", - "0x507d0052c401b01b3340050230050c001b07d023007334005043005178", - "0x1b01b33400501b00701b3320056ff01b3340070200056d201b020005334", - "0x1b33400502400518401b01b3340050460051ee01b01b334005048005184", - "0x33400501b00504701b01b33400504400518401b01b33400504700518401b", - "0x3340053320056d801b01b33400501b00701b01b70000501b19301b330005", - "0x1b3340050400056d801b01b33400501b00701b01b70100501b19301b01b", - "0x501b70201b32e32f00733400504400517801b01b33400504300518401b", - "0x32e00733400532e0056db01b02532b00733400532c00517801b32c005334", - "0x6dc01b33500533400533500517b01b3350250073340050250056db01b328", - "0x1b01b33400501b00701b03302a00770302f00900733400733532801b024", - "0x702532e00713401b00900533400500900504701b01b33400502f0050c0", - "0x51ee01b01b33400504800518401b01b33400501b00701b01b70401b334", - "0xc001b01b33400504700518401b01b33400502400518401b01b334005046", - "0x33000533400500900504701b01b33400532f0050c001b01b33400532b005", - "0x32b00533400532b00517b01b01b33400501b00701b01b70000501b19301b", - "0x33400501b00701b19232200770507c0b500733400732b32f0090246dc01b", - "0x50460051ee01b01b33400504800518401b01b33400507c0050c001b01b", - "0xb500504701b01b33400504700518401b01b33400502400518401b01b334", - "0x701b01b70600501b19301b32100533400533000535f01b330005334005", - "0x1b03900533400532200504701b01b3340051920050c001b01b33400501b", - "0xc001b01b3340050330050c001b01b33400501b00701b01b70700501b193", - "0x1b01b33400532f0050c001b01b33400532b0050c001b01b33400532e005", - "0x3340050470051b101b03900533400502a00504701b01b3340050250050c0", - "0x380073340050380051b101b03803a00733400503b00520801b03b047007", - "0x52c401b01b3340052160050c001b21620d00733400520900517801b209", - "0x33400501b00701b21a00570801b3340072180056d201b21800533400520d", - "0x52c401b01b33400521e0050c001b22421e00733400503800517801b01b", - "0x33400501b00701b22900570901b3340072280056d201b228005334005224", - "0x522a0050a901b22a00533400501b02701b01b33400503a00518401b01b", - "0x1b23100533400522b0052db01b22e00533400503900504701b22b005334", - "0x19301b01b3340052290056d801b01b33400501b00701b01b70a00501b193", - "0x518401b01b33400521a0056d801b01b33400501b00701b01b70b00501b", - "0x4f00533400501b70201b04e05100733400503a00517801b01b334005038", - "0x6db01b23c04e00733400504e0056db01b23905200733400504f00517801b", - "0x23c0390246dc01b23d00533400523d00517b01b23d239007334005239005", - "0x560050c001b01b33400501b00701b05305500770c05605400733400723d", - "0x70d01b33400723904e00713401b05400533400505400504701b01b334005", - "0x3340050510050c001b01b3340050520050c001b01b33400501b00701b01b", - "0x5400504701b25d0053340052530050a901b25300533400501b02701b01b", - "0x701b01b70a00501b19301b23100533400525d0052db01b22e005334005", - "0x3340070520510540246dc01b05200533400505200517b01b01b33400501b", - "0x1b3340050350050c001b01b33400501b00701b28405e00770e03525f007", - "0x525f00504701b0600053340050610050a901b06100533400501b02701b", - "0x1b00701b01b70a00501b19301b2310053340050600052db01b22e005334", - "0x52dd01b00600533400501b02701b01b3340052840050c001b01b334005", - "0x53340050670052db01b22e00533400505e00504701b067005334005006", - "0x1b3340050530050c001b01b33400501b00701b01b70a00501b19301b231", - "0x3340050510050c001b01b3340050520050c001b01b33400504e0050c001b", - "0x50690052dd01b06900533400501b02701b01b3340052390050c001b01b", - "0x1b2310053340052ed0052db01b22e00533400505500504701b2ed005334", - "0x706c00513f01b06c00533400506c0052db01b06c0053340052310052d9", - "0x1b01b33400506d00522b01b01b33400501b00701b06f00570f06d005334", - "0x531500571201b31531600733400531600571101b31600533400501b710", - "0x7507931107707107202603604233400731504722e02471301b315005334", - "0x33400530e03600771501b01b33400501b00701b30b30c30d02471430e30f", - "0x8500533400507530600771501b30600533400530f30a00771501b30a005", - "0x71501b30400533400531130500771501b30500533400507908500771501b", - "0x30300771501b30300533400507108300771501b083005334005077304007", - "0x533400530200504701b08100533400502600571601b302005334005072", - "0x26001b3010810073340050810051b101b02400533400502400526001b302", - "0x571101b2ff30000733400530102430202471701b301005334005301005", - "0x7f2ff30002435b01b07f00533400507f00571201b07f316007334005316", - "0x71501b01b33400533d00571801b2f72f82f92fa2fb2fc33d087044334005", - "0x2f500771501b2f50053340052f82f600771501b2f60053340052f7087007", - "0x52fb2f300771501b2f30053340052fa2f400771501b2f40053340052f9", - "0x2f10480073340050480051b101b2f20053340052f200504701b2f2005334", - "0x2f202471701b08100533400508100526001b2f10053340052f100526001b", - "0x7e2ee02435b01b31600533400531600571201b07e2ee0073340050812f1", - "0x1b01b33400508d00571801b2e92ea0842eb08f2ec08d08b044334005316", - "0x771501b0970053340052ea2e700771501b2e70053340052e908b007715", - "0x8f2e500771501b2e50053340052eb2e600771501b2e6005334005084097", - "0x26001b2e200533400501b71a01b2e300533400501b71901b2e4005334005", - "0x3340052e400504701b2e20053340052e200526001b2e30053340052e3005", - "0xa10a52de02471b09e2df2e00243340072e22e30070050481f301b2e4005", - "0x3340052e000502a01b09e00533400509e0051f001b01b33400501b00701b", - "0x571c2dd00533400709e0051ef01b2df0053340052df00503301b2e0005", - "0x2d90ab0a90243340072fc2dd2df2e004871d01b01b33400501b00701b2db", - "0x1b0a90053340050a900502a01b01b33400501b00701b2d62d70ae02471e", - "0x2d32d42d50243340072ec0460ab0a904871d01b2d90053340052d90054f8", - "0x1b2d50053340052d500502a01b01b33400501b00701b2d10b42d202471f", - "0x492cf2d00243340072d32d92d42d504872001b2d30053340052d30054f8", - "0x1b2d00053340052d000502a01b01b33400501b00701b35c35a359024721", - "0xbb0bc35d0d10483340070492cf2d00241e601b0490053340050490054f8", - "0x20801b01b3340050bb00518401b01b33400501b00701b0c40c00be024722", - "0x33400504800520801b01b3340052ce00518401b35e2ce0073340050bc005", - "0x1b101b35e00533400535e00526001b01b3340052da00518401b35f2da007", - "0x2c70050c001b2c70c90073340052c800517801b2c835e00733400535e005", - "0x3610073340050ca00517801b0ca35f00733400535f0051b101b01b334005", - "0x3610052c401b2c40053340050c90052c401b01b3340052c50050c001b2c5", - "0x35d00533400535d00503301b0d10053340050d100502a01b2be005334005", - "0x35f00518401b01b33400501b00701b01b72301b3340072be2c400713401b", - "0x50a901b0cf00533400501b02701b01b33400535e00518401b01b334005", - "0x1b01b72400501b19301b2b90053340052bb0052db01b2bb0053340050cf", - "0x3340050c70050c001b2bc0c700733400535e00517801b01b33400501b007", - "0x52c401b01b3340050d00050c001b2c30d000733400535f00517801b01b", - "0x3340072b52b600713401b2b50053340052c30052c401b2b60053340052bc", - "0x2b40050a901b2b400533400501b02701b01b33400501b00701b01b72501b", - "0x701b01b72400501b19301b2b90053340050d40052db01b0d4005334005", - "0x1b0d60053340052c20052dd01b2c200533400501b02701b01b33400501b", - "0x52bf00535801b2bf0053340052b900572601b2b90053340050d60052db", - "0x1b0d10053340050d100502a01b2e40053340052e400504701b2c0005334", - "0x35d0d12e40480052c00053340052c000572701b35d00533400535d005033", - "0x533400501b33501b01b33400504800518401b01b33400501b00701b2c0", - "0x4701b2b30053340052c100572801b2c10053340050c40d800700901b0d8", - "0x3340050c000503301b0be0053340050be00502a01b2e40053340052e4005", - "0x501b00701b2b30c00be2e40480052b30053340052b300572701b0c0005", - "0x2ab00700901b2ab00533400501b33501b01b33400504800518401b01b334", - "0x53340052e400504701b2a80053340052ad00572801b2ad00533400535c", - "0x572701b35a00533400535a00503301b35900533400535900502a01b2e4", - "0x518401b01b33400501b00701b2a835a3592e40480052a80053340052a8", - "0x901b2a700533400501b33501b01b3340052d90051ee01b01b334005048", - "0x52e400504701b2a50053340050de00572801b0de0053340052d12a7007", - "0x1b0b40053340050b400503301b2d20053340052d200502a01b2e4005334", - "0x1b01b33400501b00701b2a50b42d22e40480052a50053340052a5005727", - "0x1b3340052ec00518401b01b3340050460051ee01b01b334005048005184", - "0x2a200572801b2a20053340052d62a300700901b2a300533400501b33501b", - "0xae0053340050ae00502a01b2e40053340052e400504701b29f005334005", - "0xae2e404800529f00533400529f00572701b2d70053340052d700503301b", - "0x504800518401b01b3340052db00522b01b01b33400501b00701b29f2d7", - "0x2fc00518401b01b3340052ec00518401b01b3340050460051ee01b01b334", - "0x502001b29e00533400501b05201b0e100533400501b32b01b01b334005", - "0x3340052e000502a01b29b00533400529e0e100732801b29e00533400529e", - "0x19301b29800533400529b00522401b2990053340052df00503301b29a005", - "0x51ee01b01b33400504800518401b01b33400501b00701b01b72900501b", - "0x2a01b01b3340052fc00518401b01b3340052ec00518401b01b334005046", - "0x3340050a100522401b2990053340050a500503301b29a0053340052de005", - "0x72801b29600533400529829700700901b29700533400501b33501b298005", - "0x33400529a00502a01b2e40053340052e400504701b293005334005296005", - "0x4800529300533400529300572701b29900533400529900503301b29a005", - "0x51ee01b01b33400504800518401b01b33400501b00701b29329929a2e4", - "0x71501b01b33400531600572a01b01b33400502400518401b01b334005046", - "0x501b32b01b0ed00533400530c0eb00771501b0eb00533400530b30d007", - "0x32801b29100533400529100502001b29100533400501b05201b292005334", - "0x52900ef00700901b0ef00533400501b33501b290005334005291292007", - "0x1b0ed0053340050ed00504701b0f00053340050f100572801b0f1005334", - "0x50f000572701b00700533400500700503301b00500533400500500502a", - "0x506f00522b01b01b33400501b00701b0f00070050ed0480050f0005334", - "0x2400518401b01b3340050460051ee01b01b33400504800518401b01b334", - "0x2701b32100533400522e00504701b01b33400504700518401b01b334005", - "0x533400528f00572601b28f0053340050ee0050a901b0ee00533400501b", - "0x503301b00500533400500500502a01b0f700533400528e00535801b28e", - "0x1b0f70070053210480050f70053340050f700572701b007005334005007", - "0x1b04604704802404833400500700572c01b00701b00733400501b00572b", - "0x1b33400504600572d01b01b33400504700572d01b01b33400504800572d", - "0x500572b01b04400533400504500535701b04500533400502400572e01b", - "0x4100572d01b02719304104204833400504300572c01b043005007334005", - "0x572e01b01b33400502700572d01b01b33400519300572d01b01b334005", - "0x3340050230440072f901b02300533400504000535701b040005334005042", - "0x2000572f01b33400707d0052f801b07d00533400507d00502001b07d005", - "0x533200572c01b33201b00733400501b00572b01b01b33400501b00701b", - "0x1b33400532e00572d01b01b33400533000572d01b32c32e32f330048334", - "0x532b00535701b32b00533400532f00572e01b01b33400532c00572d01b", - "0x33504833400532800572c01b32800500733400500500572b01b025005334", - "0x572d01b01b33400502f00572d01b01b33400533500572d01b02a02f009", - "0xb500533400503300535701b03300533400500900572e01b01b33400502a", - "0x52f801b07c00533400507c00502001b07c0053340050b50250072f901b", - "0x733400501b00572b01b01b33400501b00701b32200573001b33400707c", - "0x1b33400532100572d01b03a03b03932104833400519200572c01b19201b", - "0x33400503b00572e01b01b33400503a00572d01b01b33400503900572d01b", - "0x1b20d00500733400500500572b01b20900533400503800535701b038005", - "0x572d01b01b33400521600572d01b21e21a21821604833400520d00572c", - "0x1b22400533400521a00572e01b01b33400521e00572d01b01b334005218", - "0x22900502001b2290053340052282090072f901b228005334005224005357", - "0x1b33400501b00701b22a00573101b3340072290052f801b229005334005", - "0x72d01b01b33400522b00572d01b05123122e22b04833400501b00572c01b", - "0x4e00533400505100572e01b01b33400523100572d01b01b33400522e005", - "0x1b23d23c23905204833400500500572c01b04f00533400504e00535701b", - "0x1b33400523c00572d01b01b33400523900572d01b01b33400505200572d", - "0x4f0072f901b05600533400505400535701b05400533400523d00572e01b", - "0x1b3340070550052f801b05500533400505500502001b055005334005056", - "0x2530052dd01b25300533400501b02701b01b33400501b00701b053005732", - "0x33400501b00701b25d00500525d00533400525d0052db01b25d005334005", - "0x525f0050a901b25f00533400501b02701b01b3340050530052f701b01b", - "0x1b33400501b00701b0350050050350053340050350052db01b035005334", - "0x33400501b00555b01b01b33400500500555b01b01b33400522a0052f701b", - "0x1b3340053220052f701b01b33400501b00701b01b73300501b19301b01b", - "0x1b73300501b19301b01b33400501b00555b01b01b33400500500555b01b", - "0x1b33400500500555b01b01b3340050200052f701b01b33400501b00701b", - "0x33400505e0050a901b05e00533400501b02701b01b33400501b00555b01b", - "0x733400502400503901b2840050052840053340052840052db01b284005", - "0x22801b01b33400501b00701b04700573401b33400704800566d01b048024", - "0x1b04600533400501b02701b01b33400500700532e01b01b334005024005", - "0x1b00504701b04400533400504500573601b045005334005046005007735", - "0x501b00701b04401b00700504400533400504400573701b01b005334005", - "0x1b04104204302433400500500573801b01b33400504700567001b01b334", - "0x246ac01b02702400733400502400503901b193041007334005041005039", - "0x56201b01b33400501b00701b02007d00773902304000733400702719301b", - "0x33400533200503a01b33002300733400502300503901b33200533400501b", - "0x1b00701b32b32c00773a32e32f0073340073323300400244fd01b332005", - "0x503901b02500533400501b56201b01b33400532e00522801b01b334005", - "0x702532800727401b32f00533400532f00504701b328023007334005023", - "0x1b56201b01b33400502400522801b01b33400501b00701b01b73b01b334", - "0x33400733502332f0244fd01b33500533400533500503a01b335005334005", - "0xb500533400501b69001b01b33400501b00701b03302a00773c02f009007", - "0x727401b00900533400500900504701b07c02f00733400502f00503901b", - "0x32200533400501b69001b01b33400501b00701b01b73d01b3340070b507c", - "0x244fd01b32200533400532200503a01b19202f00733400502f00503901b", - "0x22801b01b33400501b00701b03a03b00773e039321007334007322192009", - "0x21821620d02473f2090380073340070073210070be01b01b334005039005", - "0x533400503800504701b21a00533400501b26101b01b33400501b00701b", - "0x1b19301b22800533400521a00517b01b22400533400520900517b01b21e", - "0x517b01b21e00533400520d00504701b01b33400501b00701b01b740005", - "0x22900533400501b69001b22800533400521600517b01b224005334005218", - "0x244fd01b22900533400522900503a01b22a02f00733400502f00503901b", - "0x4701b01b33400501b00701b05123100774122e22b00733400722922a21e", - "0x522e22b00774201b22e00533400522e00503a01b22b00533400522b005", - "0x33400501b00701b23900574405200533400704f00574301b04f04e007334", - "0x1b23d00574601b33400723c0056d201b23c00533400505200574501b01b", - "0x1b01b33400502f00522801b01b33400504300574701b01b33400501b007", - "0x1b33400504200532e01b01b3340052240050c001b01b334005041005228", - "0x533400501b05201b05400533400501b32b01b01b3340052280050c001b", - "0x4701b05500533400505605400732801b05600533400505600502001b056", - "0x1b74800501b19301b25300533400505500522401b05300533400504e005", - "0x2be01b03525f25d02433400523d22804e02435601b01b33400501b00701b", - "0x33400525f0052be01b2840053340052240052be01b05e005334005035005", - "0x3a01b00604100733400504100503901b06000533400501b56201b061005", - "0x2ed00774906906700733400700606025d0244fd01b060005334005060005", - "0x506d05e00720001b06d00533400501b1b701b01b33400501b00701b06c", - "0x31600533400528406f0072c101b06f00533400506f00502001b06f005334", - "0x31500503a01b03606900733400506900503901b31500533400501b69001b", - "0x3340073150360670244fd01b31600533400531600502001b315005334005", - "0x1b33400507200522801b01b33400501b00701b07707100774a072026007", - "0x690260244fd01b31100533400531100503a01b31100533400501b69001b", - "0x7900504701b01b33400501b00701b30e30f00774b075079007334007311", - "0x733400507507900774201b07500533400507500503a01b079005334005", - "0x1b01b33400501b00701b30a00574c30b00533400730c00574301b30c30d", - "0x33400501b1b701b0850053340053060052be01b30600533400530b005745", - "0x1b08300533400530d00504701b30400533400530508500720001b305005", - "0x1b01b33400501b00701b01b74d00501b19301b303005334005304005020", - "0x1b33400504100522801b01b33400502f00522801b01b334005043005747", - "0x33400504200532e01b01b33400506100532e01b01b33400531600532e01b", - "0x504701b01b33400530200530e01b08130200733400530a00530f01b01b", - "0x1b01b74e00501b19301b30000533400508100522401b30100533400530d", - "0x1b01b33400504300574701b01b33400530e00522801b01b33400501b007", - "0x1b33400531600532e01b01b33400504100522801b01b33400502f005228", - "0x533400501b32b01b01b33400506100532e01b01b33400504200532e01b", - "0x2ff00732801b07f00533400507f00502001b07f00533400501b59701b2ff", - "0x533400508700522401b30100533400530f00504701b08700533400507f", - "0x1b33400507700522801b01b33400501b00701b01b74e00501b19301b300", - "0x7100774201b06900533400506900503a01b07100533400507100504701b", - "0x1b00701b2fa00574f2fb0053340072fc00574301b2fc33d007334005069", - "0x1b2f80053340052f90052be01b2f90053340052fb00574501b01b334005", - "0x30304200720001b3030053340052f800502001b08300533400533d005047", - "0x53340052f70610072c101b2f70053340052f700502001b2f7005334005", - "0x7512f42f50073340072f608300775001b2f60053340052f600502001b2f6", - "0x2433f01b2f20053340052f404300775201b01b33400501b00701b2f3005", - "0x52f100556301b2ee0053340052f500504701b2f10053340050413162f2", - "0x504300574701b01b33400501b00701b01b75300501b19301b07e005334", - "0x31600532e01b01b33400504100522801b01b33400502f00522801b01b334", - "0x502001b08d00533400501b05201b08b00533400501b32b01b01b334005", - "0x3340052f300504701b2ec00533400508d08b00732801b08d00533400508d", - "0x501b00701b01b74800501b19301b2530053340052ec00522401b053005", - "0x4100522801b01b33400502f00522801b01b33400504300574701b01b334", - "0x532e01b01b33400506100532e01b01b33400531600532e01b01b334005", - "0x1b33400508f00530e01b2eb08f0073340052fa00530f01b01b334005042", - "0x30100535f01b3000053340052eb00522401b30100533400533d00504701b", - "0x701b01b74800501b19301b25300533400530000575401b053005334005", - "0x22801b01b33400504300574701b01b33400506c00522801b01b33400501b", - "0x1b01b33400505e00532e01b01b33400504100522801b01b33400502f005", - "0x1b33400528400532e01b01b33400506100532e01b01b33400504200532e", - "0x3340052ea00502001b2ea00533400501b59701b08400533400501b32b01b", - "0x1b0530053340052ed00504701b2e90053340052ea08400732801b2ea005", - "0x1b01b33400501b00701b01b74800501b19301b2530053340052e9005224", - "0x1b33400504100522801b01b33400502f00522801b01b334005043005747", - "0x3340052280050c001b01b33400504200532e01b01b3340052240050c001b", - "0x504701b01b3340052e700530e01b0972e700733400523900530f01b01b", - "0x1b01b74800501b19301b25300533400509700522401b05300533400504e", - "0x1b01b3340052280050c001b01b33400505100522801b01b33400501b007", - "0x1b33400504100522801b01b33400502f00522801b01b334005043005747", - "0x533400501b32b01b01b33400504200532e01b01b3340052240050c001b", - "0x2e600732801b2e50053340052e500502001b2e500533400501b59701b2e6", - "0x53340052e400522401b05300533400523100504701b2e40053340052e5", - "0x575501b2e20053340052532e300700901b2e300533400501b33501b253", - "0x53340052e000573701b05300533400505300504701b2e00053340052e2", - "0xbe01b01b33400503a00522801b01b33400501b00701b2e00530070052e0", - "0x1b01b33400501b00701b0a10a52de02475609e2df00733400700703b007", - "0x33400509e00517b01b2db0053340052df00504701b2dd00533400501b261", - "0x501b00701b01b75700501b19301b0ab0053340052dd00517b01b0a9005", - "0x17b01b0a90053340050a100517b01b2db0053340052de00504701b01b334", - "0x33400502f00503901b2db0053340052db00504701b0ab0053340050a5005", - "0xae0073340052d92db00774201b2d90053340052d900503a01b2d902f007", - "0x74501b01b33400501b00701b2d50057582d60053340072d700574301b2d7", - "0x501b00701b2d300575901b3340072d40056d201b2d40053340052d6005", - "0x4100522801b01b33400502f00522801b01b33400504300574701b01b334", - "0x50c001b01b33400504200532e01b01b3340050ab0050c001b01b334005", - "0x2001b0b400533400501b05201b2d200533400501b32b01b01b3340050a9", - "0x50ae00504701b2d10053340050b42d200732801b0b40053340050b4005", - "0x1b00701b01b75a00501b19301b2cf0053340052d100522401b2d0005334", - "0x50ab0052be01b35a3590490243340052d30a90ae02435601b01b334005", - "0x1b35d02f00733400502f00503901b0d100533400501b69001b35c005334", - "0x775b0bb0bc00733400735d0d10490244fd01b0d10053340050d100503a", - "0xbb00503a01b0bc0053340050bc00504701b01b33400501b00701b0c00be", - "0x3340072ce00574301b2ce0c40073340050bb0bc00774201b0bb005334005", - "0x1b35f00533400535e00574501b01b33400501b00701b2da00575c35e005", - "0x535a0052be01b0c90053340053590052be01b2c800533400535f0052be", - "0x1b36104100733400504100503901b0ca00533400501b56201b2c7005334", - "0x775d2c42c50073340073610ca0c40244fd01b0ca0053340050ca00503a", - "0x502001b2bb0053340052c835c00720001b01b33400501b00701b0cf2be", - "0x533400501b69001b2b90053340050c92bb0072c101b2bb0053340052bb", - "0x2001b0c70053340050c700503a01b2bc2c40073340052c400503901b0c7", - "0x2b600775e2c30d00073340070c72bc2c50244fd01b2b90053340052b9005", - "0x533400501b69001b01b3340052c300522801b01b33400501b00701b2b5", - "0x2c20d40073340072b42c40d00244fd01b2b40053340052b400503a01b2b4", - "0x3a01b0d40053340050d400504701b01b33400501b00701b2bf0d600775f", - "0xd800574301b0d82c00073340052c20d400774201b2c20053340052c2005", - "0x53340052c100574501b01b33400501b00701b2b30057602c1005334007", - "0x2ad00720001b2a800533400501b1b701b2ad0053340052ab0052be01b2ab", - "0x53340052a700502001b0de0053340052c000504701b2a70053340052a8", - "0x1b33400504300574701b01b33400501b00701b01b76100501b19301b2a5", - "0x3340052c700532e01b01b33400504100522801b01b33400502f00522801b", - "0x52b300530f01b01b33400504200532e01b01b3340052b900532e01b01b", - "0x1b29f0053340052c000504701b01b3340052a300530e01b2a22a3007334", - "0x1b01b33400501b00701b01b76200501b19301b0e10053340052a2005224", - "0x1b33400502f00522801b01b33400504300574701b01b3340052bf005228", - "0x33400504200532e01b01b3340052c700532e01b01b33400504100522801b", - "0x33400501b59701b29e00533400501b32b01b01b3340052b900532e01b01b", - "0x1b29a00533400529b29e00732801b29b00533400529b00502001b29b005", - "0x76200501b19301b0e100533400529a00522401b29f0053340050d6005047", - "0x3340052b600504701b01b3340052b500522801b01b33400501b00701b01b", - "0x2982990073340052c42b600774201b2c40053340052c400503a01b2b6005", - "0x574501b01b33400501b00701b29600576329700533400729800574301b", - "0x533400529900504701b0eb0053340052930052be01b293005334005297", - "0x2001b0ed0053340052a504200720001b2a50053340050eb00502001b0de", - "0x529200502001b2920053340050ed2b90072c101b0ed0053340050ed005", - "0x501b00701b0ef0057642902910073340072920de00775001b292005334", - "0x53340050412c70f102433f01b0f100533400529004300775201b01b334", - "0x535f01b07e0053340050f000556301b2ee00533400529100504701b0f0", - "0x1b01b76600501b19301b28f00533400507e00576501b0ee0053340052ee", - "0x1b01b33400502f00522801b01b33400504300574701b01b33400501b007", - "0x28e00533400501b32b01b01b3340052c700532e01b01b334005041005228", - "0xf728e00732801b0f70053340050f700502001b0f700533400501b05201b", - "0x2cf0053340050f900522401b2d00053340050ef00504701b0f9005334005", - "0x1b01b33400504300574701b01b33400501b00701b01b75a00501b19301b", - "0x1b3340052c700532e01b01b33400504100522801b01b33400502f005228", - "0x33400529600530f01b01b33400504200532e01b01b3340052b900532e01b", - "0x22401b29f00533400529900504701b01b3340050f800530e01b0f60f8007", - "0x3340050e100575401b2d000533400529f00535f01b0e10053340050f6005", - "0x3340050cf00522801b01b33400501b00701b01b75a00501b19301b2cf005", - "0x504100522801b01b33400502f00522801b01b33400504300574701b01b", - "0x35c00532e01b01b33400504200532e01b01b3340052c700532e01b01b334", - "0x1b32b01b01b3340050c900532e01b01b3340052c800532e01b01b334005", - "0x1b28c00533400528c00502001b28c00533400501b59701b28d005334005", - "0xff00522401b2d00053340052be00504701b0ff00533400528c28d007328", - "0x4300574701b01b33400501b00701b01b75a00501b19301b2cf005334005", - "0x532e01b01b33400504100522801b01b33400502f00522801b01b334005", - "0xc001b01b3340053590050c001b01b33400535c00532e01b01b334005042", - "0x33400510000530e01b0fe1000073340052da00530f01b01b33400535a005", - "0x1b19301b2cf0053340050fe00522401b2d00053340050c400504701b01b", - "0x4300574701b01b3340050c000522801b01b33400501b00701b01b75a005", - "0x50c001b01b33400504100522801b01b33400502f00522801b01b334005", - "0xc001b01b33400535c00532e01b01b33400504200532e01b01b33400535a", - "0x1b28a00533400501b59701b10100533400501b32b01b01b334005359005", - "0xbe00504701b28900533400528a10100732801b28a00533400528a005020", - "0x701b01b75a00501b19301b2cf00533400528900522401b2d0005334005", - "0x22801b01b33400502f00522801b01b33400504300574701b01b33400501b", - "0x1b01b33400504200532e01b01b3340050ab0050c001b01b334005041005", - "0x510700530e01b1091070073340052d500530f01b01b3340050a90050c0", - "0x33501b2cf00533400510900522401b2d00053340050ae00504701b01b334", - "0x33400510600575501b1060053340052cf10800700901b10800533400501b", - "0x700528800533400528800573701b2d00053340052d000504701b288005", - "0x2476710f1130073340070070090070be01b01b33400501b00701b2882d0", - "0x11300504701b11700533400501b26101b01b33400501b00701b11528710e", - "0x28200533400511700517b01b28300533400510f00517b01b285005334005", - "0x28500533400510e00504701b01b33400501b00701b01b76800501b19301b", - "0x2820052be01b28200533400528700517b01b28300533400511500517b01b", - "0x1b11c00533400501b56201b11a0053340052830052be01b018005334005", - "0x2850244fd01b11c00533400511c00503a01b11b041007334005041005039", - "0x1b69001b01b33400501b00701b12227f00776928111900733400711b11c", - "0x533400512100503a01b27e28100733400528100503901b121005334005", - "0x501b00701b27b27d00776a12612700733400712127e1190244fd01b121", - "0x27a00503a01b27a00533400501b69001b01b33400512600522801b01b334", - "0x1b12b12d00776b12e12c00733400727a2811270244fd01b27a005334005", - "0x533400512e00503a01b12c00533400512c00504701b01b33400501b007", - "0x76c27700533400727800574301b27827900733400512e12c00774201b12e", - "0x1340052be01b13400533400527700574501b01b33400501b00701b135005", - "0x27300533400527427500720001b27400533400501b1b701b275005334005", - "0x501b19301b13d00533400527300502001b14600533400527900504701b", - "0x502f00522801b01b33400504300574701b01b33400501b00701b01b76d", - "0x1800532e01b01b33400511a00532e01b01b33400504100522801b01b334", - "0x1b14113f00733400513500530f01b01b33400504200532e01b01b334005", - "0x33400514100522401b14200533400527900504701b01b33400513f00530e", - "0x33400512b00522801b01b33400501b00701b01b76e00501b19301b144005", - "0x504100522801b01b33400502f00522801b01b33400504300574701b01b", - "0x1800532e01b01b33400504200532e01b01b33400511a00532e01b01b334", - "0x502001b26e00533400501b59701b27000533400501b32b01b01b334005", - "0x33400512d00504701b27200533400526e27000732801b26e00533400526e", - "0x501b00701b01b76e00501b19301b14400533400527200522401b142005", - "0x503a01b27d00533400527d00504701b01b33400527b00522801b01b334", - "0x714d00574301b14d14e00733400528127d00774201b281005334005281", - "0x14a00533400514c00574501b01b33400501b00701b14b00576f14c005334", - "0x14900502001b14600533400514e00504701b14900533400514a0052be01b", - "0x533400514800502001b14800533400513d04200720001b13d005334005", - "0x75001b14700533400514700502001b1470053340051480180072c101b148", - "0x775201b01b33400501b00701b26b00577026c158007334007147146007", - "0x15800504701b26900533400504111a26a02433f01b26a00533400526c043", - "0x26802433400528f00573801b28f00533400526900556301b0ee005334005", - "0x1b26400533400502f26626802433f01b01b33400526500522801b265266", - "0x516100573601b16100533400526326400773501b26300533400501b027", - "0x516300533400516300573701b0ee0053340050ee00504701b163005334", - "0x2f00522801b01b33400504300574701b01b33400501b00701b1630ee007", - "0x1b32b01b01b33400511a00532e01b01b33400504100522801b01b334005", - "0x1b16500533400516500502001b16500533400501b05201b261005334005", - "0x26000522401b16600533400526b00504701b260005334005165261007328", - "0x4300574701b01b33400501b00701b01b77100501b19301b168005334005", - "0x532e01b01b33400504100522801b01b33400502f00522801b01b334005", - "0x30f01b01b33400504200532e01b01b33400501800532e01b01b33400511a", - "0x33400514e00504701b01b33400516900530e01b16b16900733400514b005", - "0x75401b16600533400514200535f01b14400533400516b00522401b142005", - "0x22801b01b33400501b00701b01b77100501b19301b168005334005144005", - "0x1b01b33400502f00522801b01b33400504300574701b01b334005122005", - "0x1b33400504200532e01b01b33400511a00532e01b01b334005041005228", - "0x533400501b59701b25e00533400501b32b01b01b33400501800532e01b", - "0x4701b13900533400513a25e00732801b13a00533400513a00502001b13a", - "0x533400501b33501b16800533400513900522401b16600533400527f005", - "0x4701b25800533400525900575501b25900533400516825b00700901b25b", - "0x701b25816600700525800533400525800573701b166005334005166005", - "0x74701b01b33400504200532e01b01b33400503300522801b01b33400501b", - "0x1b01b33400504100522801b01b33400500700532e01b01b334005043005", - "0x533400525600502001b25600533400501b59701b25700533400501b32b", - "0x700901b17100533400501b33501b25500533400525625700732801b256", - "0x33400502a00504701b17400533400517300575501b173005334005255171", - "0x1b33400501b00701b17402a00700517400533400517400573701b02a005", - "0x533400501b69001b01b33400502300522801b01b33400504100522801b", - "0x4fd01b17600533400517600503a01b25402400733400502400503901b176", - "0x1b01b33400501b00701b25217b00777217917800733400717625432f024", - "0x533400518200503a01b18200533400501b69001b01b334005179005228", - "0x501b00701b24e1840077731831810073340071820241780244fd01b182", - "0x74201b18300533400518300503a01b18100533400518100504701b01b334", - "0x1b24b00577425a00533400724f00574301b24f17c007334005183181007", - "0x53340051890052be01b18900533400525a00574501b01b33400501b007", - "0x504701b18d00533400524a18b00720001b24a00533400501b1b701b18b", - "0x1b01b77500501b19301b24900533400518d00502001b18f00533400517c", - "0x1b01b33400500700532e01b01b33400504300574701b01b33400501b007", - "0x524800530e01b24624800733400524b00530f01b01b33400504200532e", - "0x19301b24300533400524600522401b24400533400517c00504701b01b334", - "0x574701b01b33400524e00522801b01b33400501b00701b01b77600501b", - "0x32b01b01b33400500700532e01b01b33400504200532e01b01b334005043", - "0x23a00533400523a00502001b23a00533400501b59701b23b00533400501b", - "0x522401b24400533400518400504701b23800533400523a23b00732801b", - "0x522801b01b33400501b00701b01b77600501b19301b243005334005238", - "0x2400533400502400503a01b17b00533400517b00504701b01b334005252", - "0x577723500533400719700574301b19723700733400502417b00774201b", - "0x52300052be01b23000533400523500574501b01b33400501b00701b233", - "0x1b24900533400519b00502001b18f00533400523700504701b19b005334", - "0x70072c101b19d00533400519d00502001b19d005334005249042007200", - "0x33400722f18f00775001b22f00533400522f00502001b22f00533400519d", - "0x533400522c04300775201b01b33400501b00701b22500577822c22d007", - "0x22122302433f01b1a500533400501b32101b22100533400501b04e01b223", - "0x53340051a721b00773501b1a700533400501b02701b21b0053340051a5", - "0x573701b22d00533400522d00504701b2190053340051a900573601b1a9", - "0x504300574701b01b33400501b00701b21922d007005219005334005219", - "0x21700502001b21700533400501b05201b17d00533400501b32b01b01b334", - "0x21400533400501b33501b21c00533400521717d00732801b217005334005", - "0x504701b1ae00533400521300575501b21300533400521c21400700901b", - "0x1b00701b1ae2250070051ae0053340051ae00573701b225005334005225", - "0x532e01b01b33400500700532e01b01b33400504300574701b01b334005", - "0x1b33400520e00530e01b20c20e00733400523300530f01b01b334005042", - "0x501b33501b24300533400520c00522401b24400533400523700504701b", - "0x20800533400520a00575501b20a0053340052431b100700901b1b1005334", - "0x20824400700520800533400520800573701b24400533400524400504701b", - "0x1b33400502300522801b01b33400532b00522801b01b33400501b00701b", - "0x566d01b32c00533400532c00504701b20504100733400504100503901b", - "0x1b33400504200532e01b01b33400501b00701b20400577901b334007205", - "0x1b02701b20300533400502400704302433f01b01b33400504100522801b", - "0x533400520000573601b2000053340051b720300773501b1b7005334005", - "0x32c00700520600533400520600573701b32c00533400532c00504701b206", - "0x533400501b69001b01b33400520400567001b01b33400501b00701b206", - "0x4fd01b1ff0053340051ff00503a01b1b902400733400502400503901b1ff", - "0x1b01b33400501b00701b1be1bc00777a1fc1fe0073340071ff1b932c024", - "0x733400502400503901b1fa00533400501b69001b01b3340051fc005228", - "0x1f80073340071fa1c01fe0244fd01b1fa0053340051fa00503a01b1c0024", - "0x1b1f80053340051f800504701b01b33400501b00701b1f21f300777b1fd", - "0x574301b1f01f10073340051fd1f800774201b1fd0053340051fd00503a", - "0x3340051ef00574501b01b33400501b00701b1ee00577c1ef0053340071f0", - "0x720001b1e800533400501b1b701b1c70053340051ed0052be01b1ed005", - "0x3340051e600502001b1e30053340051f100504701b1e60053340051e81c7", - "0x33400504200532e01b01b33400501b00701b01b77d00501b19301b1e1005", - "0x502400522801b01b33400500700532e01b01b33400504300574701b01b", - "0x30e01b1d71de0073340051ee00530f01b01b33400504100522801b01b334", - "0x53340051d700522401b1e40053340051f100504701b01b3340051de005", - "0x1b3340051f200522801b01b33400501b00701b01b77e00501b19301b000", - "0x33400504300574701b01b33400504100522801b01b33400504200532e01b", - "0x33400501b32b01b01b33400502400522801b01b33400500700532e01b01b", - "0x732801b4f80053340054f800502001b4f800533400501b59701b4f7005", - "0x3340054f900522401b1e40053340051f300504701b4f90053340054f84f7", - "0x3340051be00522801b01b33400501b00701b01b77e00501b19301b000005", - "0x3a01b4fa02400733400502400503901b1bc0053340051bc00504701b01b", - "0x4fc00574301b4fc4fb0073340054fa1bc00774201b4fa0053340054fa005", - "0x53340054fd00574501b01b33400501b00701b33a00577f4fd005334007", - "0x502001b1e30053340054fb00504701b5000053340054ff0052be01b4ff", - "0x5055040077805035020073340070240411e30246ac01b1e1005334005500", - "0x550700502001b5070053340051e104200720001b01b33400501b00701b", - "0x33400550333b04302433f01b33b0053340055070070072c101b507005334", - "0x73601b50a00533400550950800773501b50900533400501b02701b508005", - "0x33400550c00573701b50200533400550200504701b50c00533400550a005", - "0x1b01b33400550500522801b01b33400501b00701b50c50200700550c005", - "0x1b33400504300574701b01b3340051e100532e01b01b33400504200532e", - "0x533400501b6ba01b50d00533400501b32b01b01b33400500700532e01b", - "0x33501b51000533400550e50d00732801b50e00533400550e00502001b50e", - "0x33400551200575501b51200533400551051100700901b51100533400501b", - "0x700551300533400551300573701b50400533400550400504701b513005", - "0x504300574701b01b33400504200532e01b01b33400501b00701b513504", - "0x4100522801b01b33400502400522801b01b33400500700532e01b01b334", - "0x1b01b33400551400530e01b33951400733400533a00530f01b01b334005", - "0x33400501b33501b00000533400533900522401b1e40053340054fb005047", - "0x1b51700533400551600575501b51600533400500051500700901b515005", - "0x1b5171e400700551700533400551700573701b1e40053340051e4005047", - "0x1b01b33400504200532e01b01b33400502000522801b01b33400501b007", - "0x1b33400504100522801b01b33400500700532e01b01b334005043005747", - "0x533400501b6ba01b51800533400501b32b01b01b33400502400522801b", - "0x33501b51a00533400551951800732801b51900533400551900502001b519", - "0x33400551c00575501b51c00533400551a51b00700901b51b00533400501b", - "0x700551d00533400551d00573701b07d00533400507d00504701b51d005", - "0x778104704800733400700501b00700501b01b33400501b33201b51d07d", - "0x4800504701b04400533400500700578201b01b33400501b00701b045046", - "0x501b00701b04100578404204300733400704400578301b048005334005", - "0x78601b02700533400519300535501b19300533400504200578501b01b334", - "0x504002400732801b04000533400504000502001b040005334005027005", - "0x1b04800533400504800504701b07d00533400504300557401b023005334", - "0x502300522401b07d00533400507d00557501b04700533400504700502a", - "0x33202002400533033202002433400502307d04704804857601b023005334", - "0x533400501b02701b01b33400504100557801b01b33400501b00701b330", - "0x4701b32c00533400532e0052a201b32e00533400532f0240072a301b32f", - "0x33400532c00529f01b04700533400504700502a01b048005334005048005", - "0x1b33400502400521601b01b33400501b00701b32c04704802400532c005", - "0x533400501b22901b32b00533400501b32b01b01b33400500700578701b", - "0x33501b32800533400502532b00732801b02500533400502500502001b025", - "0x3340050090050e101b00900533400532833500700901b33500533400501b", - "0x29f01b04500533400504500502a01b04600533400504600504701b02f005", - "0x1b00700533400500500502401b02f04504602400502f00533400502f005", - "0x504501b01b33400501b00701b047005788048024007334007007005046", - "0x533400502400504201b04500533400504600504401b046005334005048", - "0x578904304400733400702400504601b04500533400504500502001b024", - "0x504400504201b04100533400504300505601b01b33400501b00701b042", - "0x1b00701b01b78a00501b19301b02700533400504100505501b193005334", - "0x4201b02300533400504000505301b04000533400501b02701b01b334005", - "0x33400519300507701b02700533400502300505501b193005334005042005", - "0x78b33200533400702700525301b02000533400507d00521801b07d193007", - "0x32f00504401b32f00533400533200504501b01b33400501b00701b330005", - "0x733400732e01b00708101b32e00533400532e00502001b32e005334005", - "0x4701b01b33400502000523101b01b33400501b00701b02500578c32b32c", - "0x701b00900578d33532800733400719300504601b32c00533400532c005", - "0x2a00533400532800504201b02f00533400533500505601b01b33400501b", - "0x1b33400501b00701b01b78e00501b19301b03300533400502f00505501b", - "0x500900504201b07c0053340050b500505301b0b500533400501b02701b", - "0x1b32200533400502a00521801b03300533400507c00505501b02a005334", - "0x19200504501b01b33400501b00701b32100578f192005334007033005253", - "0x3b00533400503b00502001b03b00533400503900504401b039005334005", - "0x33400501b00701b21620d20902479003803a00733400703b32c0070be01b", - "0x1b21a00533400521800579201b21800533400503832b04502479101b01b", - "0x521a00579301b32200533400532200525d01b03a00533400503a005047", - "0x33400520d0050c001b01b33400501b00701b21a32203a02400521a005334", - "0x532b00530101b01b33400504500532e01b01b3340052160050c001b01b", - "0x501b00701b01b79400501b19301b21e00533400520900504701b01b334", - "0x32b00530101b01b33400504500532e01b01b33400532100522b01b01b334", - "0x79501b22400533400501b02701b21e00533400532c00504701b01b334005", - "0x33400522800579301b32200533400532200525d01b228005334005224005", - "0x1b33400504500532e01b01b33400501b00701b22832221e024005228005", - "0x79600501b19301b22900533400502500504701b01b33400519300533001b", - "0x33400504500532e01b01b33400533000522b01b01b33400501b00701b01b", - "0x501b02701b22900533400501b00504701b01b33400519300533001b01b", - "0x1b02000533400502000525d01b22b00533400522a00579501b22a005334", - "0x2701b01b33400501b00701b22b02022902400522b00533400522b005793", - "0x533400522e00579501b23100533400504700521801b22e00533400501b", - "0x579301b23100533400523100525d01b01b00533400501b00504701b051", - "0x1b04802400733400500700517801b05123101b024005051005334005051", - "0x4702401b02435601b04700533400504700579801b04700533400501b797", - "0x1b04100579a04204300733400704504600779901b044045046024334005", - "0x701b04000579b02719300733400704404300779901b01b33400501b007", - "0x33400504202300718101b02300533400502700500718101b01b33400501b", - "0x2435601b02000533400502000579801b02000533400501b79701b07d005", - "0x779901b07d00533400507d00513901b32f330332024334005020048193", - "0x32e00779901b01b33400501b00701b32b00579c32c32e007334007330332", - "0x32807d00718101b01b33400501b00701b33500579d32802500733400732f", - "0x2a00533400501b02701b02f00533400532c00900718101b009005334005", - "0x504701b0b500533400503300569701b03300533400502a02f00769601b", - "0x1b00701b0b50250070050b50053340050b500567e01b025005334005025", - "0x1b32b01b01b33400532c00530101b01b33400507d00517401b01b334005", - "0x1b32200533400532200502001b32200533400501b05201b07c005334005", - "0x19200522401b32100533400533500504701b19200533400532207c007328", - "0x7d00517401b01b33400501b00701b01b79e00501b19301b039005334005", - "0x1b05201b03b00533400501b32b01b01b33400532f0050c001b01b334005", - "0x533400503a03b00732801b03a00533400503a00502001b03a005334005", - "0x1b33501b03900533400503800522401b32100533400532b00504701b038", - "0x533400520d00567d01b20d00533400503920900700901b209005334005", - "0x32100700521600533400521600567e01b32100533400532100504701b216", - "0x33400500500517401b01b3340050480050c001b01b33400501b00701b216", - "0x33400501b05201b21800533400501b32b01b01b33400504200530101b01b", - "0x1b21e00533400521a21800732801b21a00533400521a00502001b21a005", - "0x79f00501b19301b22800533400521e00522401b224005334005040005047", - "0x33400500500517401b01b3340050480050c001b01b33400501b00701b01b", - "0x33400501b05201b22900533400501b32b01b01b3340050440050c001b01b", - "0x1b22b00533400522a22900732801b22a00533400522a00502001b22a005", - "0x33400501b33501b22800533400522b00522401b224005334005041005047", - "0x1b05100533400523100567d01b23100533400522822e00700901b22e005", - "0x1b05122400700505100533400505100567e01b224005334005224005047", - "0x1b0450460077a004704800733400700501b00700501b01b33400501b332", - "0x2400733400502400503901b04400533400501b53101b01b33400501b007", - "0x1b01b7a101b33400704404300727401b04800533400504800504701b043", - "0x4200533400504200507f01b04200533400501b30001b01b33400501b007", - "0x19300503a01b19300533400501b53101b04100533400504200700718101b", - "0x3340071930240480244fd01b04100533400504100513901b193005334005", - "0x533400502700504701b01b33400501b00701b07d0230077a2040027007", - "0x503a01b04100533400504100513901b04700533400504700502a01b027", - "0x2400533033202002433400504004104702704869301b040005334005040", - "0x4100517401b01b33400507d00522801b01b33400501b00701b330332020", - "0x502001b32e00533400501b59701b32f00533400501b32b01b01b334005", - "0x533400501b33501b32c00533400532e32f00732801b32e00533400532e", - "0x4701b32800533400502500567d01b02500533400532c32b00700901b32b", - "0x33400532800567e01b04700533400504700502a01b023005334005023005", - "0x1b33400502400522801b01b33400501b00701b328047023024005328005", - "0x33500700718101b33500533400533500507f01b33500533400501b69401b", - "0x2a00533400502f00900769601b02f00533400501b02701b009005334005", - "0x4700502a01b04800533400504800504701b03300533400502a00569701b", - "0x1b00701b03304704802400503300533400503300567e01b047005334005", - "0x1b32b01b01b33400502400522801b01b33400500700517401b01b334005", - "0x1b07c00533400507c00502001b07c00533400501b22901b0b5005334005", - "0x32219200700901b19200533400501b33501b32200533400507c0b5007328", - "0x4600533400504600504701b03900533400532100567d01b321005334005", - "0x4504602400503900533400503900567e01b04500533400504500502a01b", - "0x240057a301b3340070070052f801b00700500733400500500535c01b039", - "0x533400501b00524801b01b33400500500532e01b01b33400501b00701b", - "0x1b32101b01b3340050240052f701b01b33400501b00701b01b00500501b", - "0x533400504801b00724901b04800533400504800503a01b048005334005", - "0x72f901b04500500733400500500535c01b04600533400501b04f01b047", - "0x33400504700524801b04400533400504400502001b044005334005046045", - "0x32e01b01b33400501b00701b0430057a401b3340070440052f801b047005", - "0x501b00701b04700500504700533400504700524801b01b334005005005", - "0x4200503a01b04200533400501b32101b01b3340050430052f701b01b334", - "0x19300533400501b26501b04100533400504204700724901b042005334005", - "0x2001b0400053340051930270072f901b02700500733400500500535c01b", - "0x3340070400052f801b04100533400504100524801b040005334005040005", - "0x524801b01b33400500500532e01b01b33400501b00701b0230057a501b", - "0x3340050230052f701b01b33400501b00701b041005005041005334005041", - "0x4100724901b07d00533400507d00503a01b07d00533400501b32101b01b", - "0x500733400500500535c01b33200533400501b36001b02000533400507d", - "0x24801b32f00533400532f00502001b32f0053340053323300072f901b330", - "0x501b00701b32e0057a601b33400732f0052f801b020005334005020005", - "0x2000500502000533400502000524801b01b33400500500532e01b01b334", - "0x32c00533400501b32101b01b33400532e0052f701b01b33400501b00701b", - "0x1b7a701b32b00533400532c02000724901b32c00533400532c00503a01b", - "0x3340050253280072f901b32800500733400500500535c01b025005334005", - "0x2f801b32b00533400532b00524801b33500533400533500502001b335005", - "0x33400500500532e01b01b33400501b00701b0090057a801b334007335005", - "0x2f701b01b33400501b00701b32b00500532b00533400532b00524801b01b", - "0x2f00533400502f00503a01b02f00533400501b32101b01b334005009005", - "0x500535c01b03300533400501b7a901b02a00533400502f32b00724901b", - "0x33400507c00502001b07c0053340050330b50072f901b0b5005007334005", - "0x3220057aa01b33400707c0052f801b02a00533400502a00524801b07c005", - "0x533400502a00524801b01b33400500500532e01b01b33400501b00701b", - "0x1b32101b01b3340053220052f701b01b33400501b00701b02a00500502a", - "0x533400519202a00724901b19200533400519200503a01b192005334005", - "0x72f901b03b00500733400500500535c01b03900533400501b7ab01b321", - "0x33400532100524801b03a00533400503a00502001b03a00533400503903b", - "0x32e01b01b33400501b00701b0380057ac01b33400703a0052f801b321005", - "0x501b00701b32100500532100533400532100524801b01b334005005005", - "0x20900503a01b20900533400501b32101b01b3340050380052f701b01b334", - "0x21600533400501b7ad01b20d00533400520932100724901b209005334005", - "0x2001b21a0053340052162180072f901b21800500733400500500535c01b", - "0x33400721a0052f801b20d00533400520d00524801b21a00533400521a005", - "0x524801b01b33400500500532e01b01b33400501b00701b21e0057ae01b", - "0x33400521e0052f701b01b33400501b00701b20d00500520d00533400520d", - "0x20d00724901b22400533400522400503a01b22400533400501b32101b01b", - "0x500733400500500535c01b22900533400501b7af01b228005334005224", - "0x24801b22b00533400522b00502001b22b00533400522922a0072f901b22a", - "0x501b00701b22e0057b001b33400722b0052f801b228005334005228005", - "0x22800500522800533400522800524801b01b33400500500532e01b01b334", - "0x23100533400501b32101b01b33400522e0052f701b01b33400501b00701b", - "0x1b7b101b05100533400523122800724901b23100533400523100503a01b", - "0x33400504e04f0072f901b04f00500733400500500535c01b04e005334005", - "0x2f801b05100533400505100524801b05200533400505200502001b052005", - "0x33400500500532e01b01b33400501b00701b2390057b201b334007052005", - "0x2f701b01b33400501b00701b05100500505100533400505100524801b01b", - "0x23c00533400523c00503a01b23c00533400501b32101b01b334005239005", - "0x500535c01b05400533400501b7b301b23d00533400523c05100724901b", - "0x33400505500502001b0550053340050540560072f901b056005007334005", - "0x530057b401b3340070550052f801b23d00533400523d00524801b055005", - "0x533400523d00524801b01b33400500500532e01b01b33400501b00701b", - "0x1b32101b01b3340050530052f701b01b33400501b00701b23d00500523d", - "0x533400525323d00724901b25300533400525300503a01b253005334005", - "0x72f901b03500500733400500500535c01b25f00533400501b35401b25d", - "0x33400525d00524801b05e00533400505e00502001b05e00533400525f035", - "0x32e01b01b33400501b00701b2840057b501b33400705e0052f801b25d005", - "0x501b00701b25d00500525d00533400525d00524801b01b334005005005", - "0x6100503a01b06100533400501b32101b01b3340052840052f701b01b334", - "0x600533400501b2bc01b06000533400506125d00724901b061005334005", - "0x2001b0690053340050060670072f901b06700500733400500500535c01b", - "0x3340070690052f801b06000533400506000524801b069005334005069005", - "0x524801b01b33400500500532e01b01b33400501b00701b2ed0057b601b", - "0x3340052ed0052f701b01b33400501b00701b060005005060005334005060", - "0x6000724901b06c00533400506c00503a01b06c00533400501b32101b01b", - "0x500733400500500535c01b06f00533400501b7b701b06d00533400506c", - "0x24801b31500533400531500502001b31500533400506f3160072f901b316", - "0x501b00701b0360057b801b3340073150052f801b06d00533400506d005", - "0x6d00500506d00533400506d00524801b01b33400500500532e01b01b334", - "0x2600533400501b32101b01b3340050360052f701b01b33400501b00701b", - "0x1b7b901b07200533400502606d00724901b02600533400502600503a01b", - "0x3340050710770072f901b07700500733400500500535c01b071005334005", - "0x2f801b07200533400507200524801b31100533400531100502001b311005", - "0x33400500500532e01b01b33400501b00701b0790057ba01b334007311005", - "0x2f701b01b33400501b00701b07200500507200533400507200524801b01b", - "0x7500533400507500503a01b07500533400501b32101b01b334005079005", - "0x50072f901b30e00533400501b05101b30f00533400507507200724901b", - "0x533400530f00524801b30d00533400530d00502001b30d00533400530e", - "0x524801b01b33400501b00701b30c0057bb01b33400730d0052f801b30f", - "0x33400530c0052f701b01b33400501b00701b30f00500530f00533400530f", - "0x30f00724901b30b00533400530b00503a01b30b00533400501b32101b01b", - "0x480056d101b30a00500530a00533400530a00524801b30a00533400530b", - "0x70050487bc01b0440470073340050470051b101b045046047024334005", - "0x1b01b33400501b00701b0400271930247bd041042043024334007045044", - "0x504200503301b04300533400504300502a01b04100533400504100517d", - "0x1b33400501b00701b07d0057be02300533400704100521701b042005334", - "0x33400502000526001b33200533400501b7c001b02000533400501b7bf01b", - "0x243340073320200420430481a701b33200533400533200526001b020005", - "0x33400532e00517d01b01b33400501b00701b02532b32c0247c132e32f330", - "0x21701b32f00533400532f00503301b33000533400533000502a01b32e005", - "0x33400501b7c301b01b33400501b00701b3350057c232800533400732e005", - "0x1b02f00533400502f00571201b02f00900733400500900571101b009005", - "0x247c403a03b03932119232207c0b503302a04233400702f04701b024713", - "0x71501b21600533400503a02a00771501b01b33400501b00701b20d209038", - "0x21a00771501b21a00533400503921800771501b21800533400503b216007", - "0x532222400771501b22400533400519221e00771501b21e005334005321", - "0x53340050b522900771501b22900533400507c22800771501b228005334", - "0x526001b22a00533400522a00504701b22b00533400503300571601b22a", - "0x33400522e00526001b22e22b00733400522b0051b101b024005334005024", - "0x733400500900571101b05123100733400522e02422a02471701b22e005", - "0x4f04433400504e05123102435b01b04e00533400504e00571201b04e009", - "0x505504f00771501b01b33400505200571801b05505605423d23c239052", - "0x533400505425300771501b25300533400505605300771501b053005334", - "0x1b03500533400523c25f00771501b25f00533400523d25d00771501b25d", - "0x523900517801b06128400733400505e00517801b05e00533400501b6da", - "0x3340070060610350246dc01b06100533400506100517b01b006060007334", - "0x6d00533400501b02701b01b33400501b00701b06c2ed0077c5069067007", - "0x6900517b01b31600533400506700504701b06f00533400506d0050a901b", - "0x701b01b7c600501b19301b03600533400506f0052db01b315005334005", - "0x1b0720053340050260052dd01b02600533400501b02701b01b33400501b", - "0x50720052db01b31500533400506c00517b01b3160053340052ed005047", - "0x73340070602843160246dc01b28400533400528400517b01b036005334", - "0x7500533400507100504701b01b33400501b00701b0793110077c7077071", - "0x501b19301b30e00533400531500517b01b30f00533400507700517b01b", - "0x530d00517b01b30d00533400501b16301b01b33400501b00701b01b7c8", - "0x701b30630a0077c930b30c00733400730d3153110246dc01b30d005334", - "0x30f00533400507900517b01b07500533400530c00504701b01b33400501b", - "0x1b3050057ca08500533400703600513f01b30e00533400530b00517b01b", - "0x7500533400507500504701b01b33400508500522b01b01b33400501b007", - "0x7502471701b22b00533400522b00526001b04600533400504600526001b", - "0x8330402435b01b00900533400500900571201b08330400733400522b046", - "0x1b01b33400530200571801b08707f2ff300301081302303044334005009", - "0x771501b2fc00533400507f33d00771501b33d005334005087303007715", - "0x3012fa00771501b2fa0053340053002fb00771501b2fb0053340052ff2fc", - "0x53340052f800526001b2f800533400530e30f00716501b2f9005334005", - "0x2f70243340072f832832f3300487cb01b2f90053340052f900504701b2f8", - "0x53340052f700502a01b01b33400501b00701b2f22f32f40247cc2f52f6", - "0x2f10243340070810232f62f70487cb01b2f50053340052f50056f301b2f7", - "0x53340052f100502a01b01b33400501b00701b2ec08d08b0247cd07e2ee", - "0x8f02433400707e2f52ee2f10487ce01b07e00533400507e0056f301b2f1", - "0x53340050840057d001b01b33400501b00701b2e72e92ea0247cf0842eb", - "0x504701b2e50053340052e60057d201b2e60053340050970057d101b097", - "0x53340052eb00503301b08f00533400508f00502a01b2f90053340052f9", - "0x33400501b00701b2e52eb08f2f90480052e50053340052e50057d301b2eb", - "0x57d401b2e30053340052e72e400700901b2e400533400501b33501b01b", - "0x53340052ea00502a01b2f90053340052f900504701b2e20053340052e3", - "0x2f90480052e20053340052e20057d301b2e90053340052e900503301b2ea", - "0x501b33501b01b3340052f500521c01b01b33400501b00701b2e22e92ea", - "0x9e0053340052df0057d401b2df0053340052ec2e000700901b2e0005334", - "0x8d00503301b08b00533400508b00502a01b2f90053340052f900504701b", - "0x701b09e08d08b2f904800509e00533400509e0057d301b08d005334005", - "0x33501b01b33400508100518401b01b33400502300521c01b01b33400501b", - "0x3340050a50057d401b0a50053340052f22de00700901b2de00533400501b", - "0x3301b2f40053340052f400502a01b2f90053340052f900504701b0a1005", - "0xa12f32f42f90480050a10053340050a10057d301b2f30053340052f3005", - "0x1b33400530f0050c001b01b33400530500522b01b01b33400501b00701b", - "0x33400532800521c01b01b33400530e0050c001b01b33400502300521c01b", - "0x504600518401b01b33400522b00518401b01b33400500900572a01b01b", - "0x501b00701b01b7d500501b19301b2dd00533400507500504701b01b334", - "0x2300521c01b01b3340050790050c001b01b3340053060050c001b01b334", - "0x572a01b01b33400532800521c01b01b3340050360050ab01b01b334005", - "0x4701b01b33400504600518401b01b33400522b00518401b01b334005009", - "0xa900533400501b7d601b2db00533400501b32b01b2dd00533400530a005", - "0x1b33501b0ab0053340050a92db00732801b0a90053340050a900502001b", - "0x53340050ae0057d401b0ae0053340050ab2d900700901b2d9005334005", - "0x503301b33000533400533000502a01b2dd0053340052dd00504701b2d7", - "0x1b2d732f3302dd0480052d70053340052d70057d301b32f00533400532f", - "0x1b01b33400502300521c01b01b33400502400518401b01b33400501b007", - "0x1b33400500900572a01b01b33400532800521c01b01b334005046005184", - "0x32b01b2d50053340052092d600771501b2d600533400520d03800771501b", - "0x2d30053340052d300502001b2d300533400501b05201b2d400533400501b", - "0xb400700901b0b400533400501b33501b2d20053340052d32d400732801b", - "0x53340052d500504701b2d00053340052d10057d401b2d10053340052d2", - "0x57d301b32f00533400532f00503301b33000533400533000502a01b2d5", - "0x522b01b01b33400501b00701b2d032f3302d50480052d00053340052d0", - "0x18401b01b33400502300521c01b01b33400502400518401b01b334005335", - "0x1b2cf00533400501b32b01b01b33400504700518401b01b334005046005", - "0x50492cf00732801b04900533400504900502001b04900533400501b052", - "0x1b35c00533400532f00503301b35a00533400533000502a01b359005334", - "0x1b01b33400501b00701b01b7d700501b19301b0d1005334005359005224", - "0x1b33400504600518401b01b33400502300521c01b01b334005024005184", - "0x532b00503301b35a00533400532c00502a01b01b33400504700518401b", - "0x901b35d00533400501b33501b0d100533400502500522401b35c005334", - "0x501b00504701b0bb0053340050bc0057d401b0bc0053340050d135d007", - "0x1b35c00533400535c00503301b35a00533400535a00502a01b01b005334", - "0x1b01b33400501b00701b0bb35c35a01b0480050bb0053340050bb0057d3", - "0x1b33400504700518401b01b33400504600518401b01b334005024005184", - "0xc00057d201b0c00053340050be0057d101b0be00533400507d0057d801b", - "0x4300533400504300502a01b01b00533400501b00504701b0c4005334005", - "0x4301b0480050c40053340050c40057d301b04200533400504200503301b", - "0x504700518401b01b33400502400518401b01b33400501b00701b0c4042", - "0x2ce00700901b2ce00533400501b33501b01b33400504600518401b01b334", - "0x533400501b00504701b2da00533400535e0057d401b35e005334005040", - "0x57d301b02700533400502700503301b19300533400519300502a01b01b", - "0x6901b04600533400501b7d901b2da02719301b0480052da0053340052da", - "0x2420a01b01b33400501b33201b01b33400501b23c01b04400533400501b", - "0x33400501b00701b0400271930247da041042045043048334007048024005", - "0x1b02007d0073340050230057dc01b0230053340050410420077db01b01b", - "0x33400502000535201b0200053340050200057de01b01b33400507d0057dd", - "0x525e01b32f00533400501b16801b3300053340053320057df01b332005", - "0x533400504300502a01b01b00533400501b00504701b32e005334005330", - "0x513901b32e00533400532e00513a01b0070053340050070052d501b043", - "0x704301b0477e001b04500533400504504400731501b32f00533400532f", - "0x25901b0470053340050470460077e101b02504732b32c04833400532f32e", - "0x532800525801b01b33400501b00701b3350057e2328005334007025005", - "0x1b01b33400502a00522b01b01b33400500900525701b02a02f009024334", - "0x533400532c00504701b0b500533400501b32101b03300533400501b300", - "0x507f01b02f00533400502f00513901b32b00533400532b00502a01b32c", - "0x3302f32b32c04725601b0b50053340050b500503a01b033005334005033", - "0x701b0390057e332100533400719200525501b19232207c0243340050b5", - "0x1b33400503a00522b01b03a03b00733400532100517101b01b33400501b", - "0x20900517601b01b33400503800517401b20903800733400503b00517301b", - "0x22421e0247e421a21821602433400720d04532202425401b20d005334005", - "0x22a00517b01b22a22900733400521a00517801b01b33400501b00701b228", - "0x33400522900517b01b22e22b00733400522a0470077e501b22a005334005", - "0x1b04e00533400501b7e601b05123100733400522922b0077e501b229005", - "0x5107c02435601b04e00533400504e00579801b05100533400505100517b", - "0x3340052390052be01b01b3340050520050c001b23905204f02433400504e", - "0x720001b05400533400501b1b701b23d00533400522e0052be01b23c005", - "0x33400523d00502001b05600533400505600502001b05600533400505423c", - "0x1b0530053340050550051fc01b05500533400523d0560072c101b23d005", - "0x504f00504701b25d0053340052530057e801b2530053340050530057e7", - "0x1b2310053340052310052d501b21600533400521600502a01b04f005334", - "0x23121604f04700525d00533400525d0057e901b218005334005218005033", - "0x21e00502a01b25f00533400507c00504701b01b33400501b00701b25d218", - "0x28400533400522800522401b05e00533400522400503301b035005334005", - "0x6100733400503900530f01b01b33400501b00701b01b7ea00501b19301b", - "0x32200502a01b25f00533400507c00504701b01b33400506100530e01b060", - "0x28400533400506000522401b05e00533400504500503301b035005334005", - "0x600733400533500530f01b01b33400501b00701b01b7ea00501b19301b", - "0x32b00502a01b25f00533400532c00504701b01b33400500600530e01b067", - "0x28400533400506700522401b05e00533400504500503301b035005334005", - "0x2ed0057eb01b2ed00533400528406900700901b06900533400501b33501b", - "0x3500533400503500502a01b25f00533400525f00504701b06c005334005", - "0x6c0057e901b05e00533400505e00503301b0470053340050470052d501b", - "0x57ec01b01b33400501b00701b06c05e04703525f04700506c005334005", - "0x901b06d00533400501b33501b01b33400504400506f01b01b334005046", - "0x501b00504701b31600533400506f0057eb01b06f00533400504006d007", - "0x1b0070053340050070052d501b19300533400519300502a01b01b005334", - "0x719301b0470053160053340053160057e901b027005334005027005033", - "0x4604700733400500700517801b04802400733400500500517801b316027", - "0x7ed01b0440470073340050470056db01b0450240073340050240056db01b", - "0x6db01b19300533400504101b00771501b041042043024334005044045007", - "0x71501b07d0230400243340050270240077ed01b027046007334005046005", - "0x77ef3303320073340070230430200247ee01b02000533400507d193007", - "0x533200504701b32c00533400501b35101b01b33400501b00701b32e32f", - "0x1b32800533400532c0057f001b02500533400533000517b01b32b005334", - "0x4701b33500533400501b7f201b01b33400501b00701b01b7f100501b193", - "0x3340053350057f001b02500533400532e00517b01b32b00533400532f005", - "0x2f0243340050470090077ed01b0090480073340050480056db01b328005", - "0x733400702a0250b50247ee01b0b500533400503332b00771501b03302a", - "0x1b03900533400501b35101b01b33400501b00701b3211920077f332207c", - "0x50390057f001b03a00533400532200517b01b03b00533400507c005047", - "0x33400501b7f201b01b33400501b00701b01b7f400501b19301b038005334", - "0x7f001b03a00533400532100517b01b03b00533400519200504701b209005", - "0x2180077f521620d00733400702f04003b0247ee01b038005334005209005", - "0x33400520d00504701b21e00533400501b35101b01b33400501b00701b21a", - "0x19301b22900533400521e0057f001b22800533400521600517b01b224005", - "0x504701b22a00533400501b7f201b01b33400501b00701b01b7f600501b", - "0x533400522a0057f001b22800533400521a00517b01b224005334005218", - "0x533400523122400771501b23122e22b0243340050460480077ed01b229", - "0x501b00701b2390520077f704f04e00733400722e2280510247ee01b051", - "0x517b01b23d00533400504e00504701b23c00533400501b35101b01b334", - "0x1b01b7f800501b19301b05600533400523c0057f001b05400533400504f", - "0x23d00533400505200504701b05500533400501b7f201b01b33400501b007", - "0x3280077f901b0560053340050550057f001b05400533400523900517b01b", - "0x533400525300517b01b2530053340050530057fa01b053005334005038", - "0x501b00701b05e0350077fb25f25d00733400725305423d0247ee01b253", - "0x517b01b06100533400525d00504701b28400533400501b35101b01b334", - "0x1b01b7fc00501b19301b0060053340052840057f001b06000533400525f", - "0x6100533400503500504701b06700533400501b7f201b01b33400501b007", - "0x2290077f901b0060053340050670057f001b06000533400505e00517b01b", - "0x3340050060690077fe01b0690053340050690057fd01b069005334005056", - "0x7ee01b06c00533400506c00517b01b06c0053340052ed0057ff01b2ed005", - "0x1b01b33400501b00701b31531600780006f06d00733400706c22b061024", - "0x80100501b19301b02600533400506f00517b01b03600533400506d005047", - "0x531500517b01b03600533400531600504701b01b33400501b00701b01b", - "0x33400503600504701b07200533400502606003a04204880201b026005334", - "0x700501b00780401b07203600700507200533400507200580301b036005", - "0x533400502400580601b01b33400501b00701b048005805024007007334", - "0x580801b00700533400500700504701b04700533400504700580701b047", - "0x4100580d04200580c04300580b04400580a04500580904600533407d047", - "0x581402000581307d00581202300581104000581002700580f19300580e", - "0x4600522b01b01b33400501b00701b32e00581732f005816330005815332", - "0x19301b32b00533400532c00517b01b32c00533400501b16301b01b334005", - "0x1b35001b01b33400504500522b01b01b33400501b00701b01b81800501b", - "0x701b01b81800501b19301b32b00533400502500517b01b025005334005", - "0x17b01b32800533400501b81901b01b33400504400522b01b01b33400501b", - "0x22b01b01b33400501b00701b01b81800501b19301b32b005334005328005", - "0x32b00533400533500517b01b33500533400501b81a01b01b334005043005", - "0x1b01b33400504200522b01b01b33400501b00701b01b81800501b19301b", - "0x1b81800501b19301b32b00533400500900517b01b00900533400501b81b", - "0x2f00533400501b81c01b01b33400504100522b01b01b33400501b00701b", - "0x1b33400501b00701b01b81800501b19301b32b00533400502f00517b01b", - "0x33400502a00517b01b02a00533400501b81d01b01b33400519300522b01b", - "0x33400502700522b01b01b33400501b00701b01b81800501b19301b32b005", - "0x501b19301b32b00533400503300517b01b03300533400501b81e01b01b", - "0x33400501b81f01b01b33400504000522b01b01b33400501b00701b01b818", - "0x501b00701b01b81800501b19301b32b0053340050b500517b01b0b5005", - "0x7c00517b01b07c00533400501b82001b01b33400502300522b01b01b334", - "0x7d00522b01b01b33400501b00701b01b81800501b19301b32b005334005", - "0x19301b32b00533400532200517b01b32200533400501b82101b01b334005", - "0x1b82201b01b33400502000522b01b01b33400501b00701b01b81800501b", - "0x701b01b81800501b19301b32b00533400519200517b01b192005334005", - "0x17b01b32100533400501b82301b01b33400533200522b01b01b33400501b", - "0x22b01b01b33400501b00701b01b81800501b19301b32b005334005321005", - "0x32b00533400503900517b01b03900533400501b82401b01b334005330005", - "0x1b01b33400532f00522b01b01b33400501b00701b01b81800501b19301b", - "0x1b81800501b19301b32b00533400503b00517b01b03b00533400501b362", - "0x3a00533400501b82501b01b33400532e00522b01b01b33400501b00701b", - "0x3800582701b03800533400532b00582601b32b00533400503a00517b01b", - "0x20900533400520900582801b00700533400500700504701b209005334005", - "0x1b82901b20d00533400501b32b01b01b33400501b00701b209007007005", - "0x533400521620d00732801b21600533400521600502001b216005334005", - "0x582a01b21e00533400521821a00700901b21a00533400501b33501b218", - "0x533400522400582801b04800533400504800504701b22400533400521e", - "0x4700733400700501b00700501b01b33400501b33201b224048007005224", - "0x1b04300533400502400565801b01b33400501b00701b04404500782b046", - "0x733400704300565901b04700533400504700504701b01b33400501b048", - "0x1b02700533400504100565b01b01b33400501b00701b19300582c041042", - "0x82d00501b19301b02300533400502700534f01b04000533400504200565c", - "0x33400507d00565e01b07d00533400501b02701b01b33400501b00701b01b", - "0x25e01b02300533400502000534f01b04000533400519300565c01b020005", - "0x1b00701b32f00582e33000533400702300565f01b332005334005040005", - "0x1b32c00533400532e00566201b32e00533400533000566101b01b334005", - "0x504800513901b0070053340050070052d501b047005334005047005047", - "0x33400532c04800704704882f01b32c00533400532c00526001b048005334", - "0x33400501b00701b00900583033500533400732800525501b32802532b024", - "0x2a00522b01b02a02f00733400533500517101b01b33400501b33201b01b", - "0x1b04600533400504600502a01b32b00533400532b00504701b01b334005", - "0x502f00513901b33200533400533200513a01b0250053340050250052d5", - "0x4800532207c0b503304833400502f33202504632b0477e001b02f005334", - "0x33200525701b01b33400501b33201b01b33400501b00701b32207c0b5033", - "0x1b32b00533400532b00504701b19200533400500900566501b01b334005", - "0x519200566601b0250053340050250052d501b04600533400504600502a", - "0x33400501b33201b01b33400501b00701b19202504632b048005192005334", - "0x4833202466701b32100533400501b02701b01b33400532f00522b01b01b", - "0x533400504700504701b03b00533400503900566801b039005334005321", - "0x566601b0070053340050070052d501b04600533400504600502a01b047", - "0x517401b01b33400501b00701b03b00704604704800503b00533400503b", - "0x22901b03a00533400501b32b01b01b33400502400525701b01b334005048", - "0x33400503803a00732801b03800533400503800502001b03800533400501b", - "0x66501b21600533400520920d00700901b20d00533400501b33501b209005", - "0x33400504400502a01b04500533400504500504701b218005334005216005", - "0x4800521800533400521800566601b0070053340050070052d501b044005", - "0x3340050470050077e501b04704800733400502400517801b218007044045", - "0x79801b04500533400504500517b01b04400533400501b79701b045046007", - "0x2d501b04104204302433400504404501b02435601b044005334005044005", - "0x1b04000583102719300733400704204300779901b046005334005046005", - "0x701b02000583207d02300733400704119300779901b01b33400501b007", - "0x33400502733200718101b33200533400507d00700718101b01b33400501b", - "0x1b32c00533400501b79701b32e32f0073340050480460077e501b330005", - "0x32e02302435601b32c00533400532c00579801b32e00533400532e00517b", - "0x532f0052d501b33000533400533000513901b32802532b02433400532c", - "0x501b00701b02f00583300933500733400702532b00779901b32f005334", - "0x33400501b00701b0b500583403302a00733400732833500779901b01b334", - "0x1b32200533400500907c00718101b07c00533400503333000718101b01b", - "0x532100569701b32100533400519232200769601b19200533400501b027", - "0x1b32f00533400532f0052d501b02a00533400502a00504701b039005334", - "0x17401b01b33400501b00701b03932f02a02400503900533400503900567e", - "0x1b03b00533400501b32b01b01b33400500900530101b01b334005330005", - "0x503a03b00732801b03a00533400503a00502001b03a00533400501b052", - "0x1b20d00533400503800522401b2090053340050b500504701b038005334", - "0xc001b01b33400533000517401b01b33400501b00701b01b83500501b193", - "0x1b21800533400501b05201b21600533400501b32b01b01b334005328005", - "0x2f00504701b21a00533400521821600732801b218005334005218005020", - "0x1b21e00533400501b33501b20d00533400521a00522401b209005334005", - "0x20900504701b22800533400522400567d01b22400533400520d21e007009", - "0x22800533400522800567e01b32f00533400532f0052d501b209005334005", - "0xc001b01b33400500700517401b01b33400501b00701b22832f209024005", - "0x1b22900533400501b32b01b01b33400502700530101b01b334005048005", - "0x522a22900732801b22a00533400522a00502001b22a00533400501b052", - "0x1b23100533400522b00522401b22e00533400502000504701b22b005334", - "0xc001b01b33400500700517401b01b33400501b00701b01b83600501b193", - "0x1b05100533400501b32b01b01b3340050410050c001b01b334005048005", - "0x504e05100732801b04e00533400504e00502001b04e00533400501b052", - "0x1b23100533400504f00522401b22e00533400504000504701b04f005334", - "0x523900567d01b23900533400523105200700901b05200533400501b335", - "0x1b0460053340050460052d501b22e00533400522e00504701b23c005334", - "0x1b0481791b91e401b04807123c04622e02400523c00533400523c00567e", - "0x501b1e31b91e401b0481791b91e401b04801b02400700501b1e31b91e4", - "0x1b04814602400700501b1e31b91e401b0481791b91e401b0480be024007", - "0x1b0481791b91e401b04854c02400700501b1e31b91e401b0481791b91e4", - "0x501b1e31b91e401b0481791b91e401b04883702400700501b1e31b91e4", - "0x1b04883902400700501b1e31b91e401b0481791b91e401b048838024007", - "0x1b0481791b91e401b04883a02400700501b1e31b91e401b0481791b91e4", - "0x501b1e31b91e401b0481791b91e401b04883b02400700501b1e31b91e4", - "0x1b04883d02400700501b1e31b91e401b0481791b91e401b04883c024007", - "0x1b0481791b91e401b04883e02400700501b1e31b91e401b0481791b91e4", - "0x1e31b91e422101b0471791b91e422101b04783f02400700501b1e31b91e4", - "0x2400700501b1e31b91e401b0481791b91e401b04884004802400700501b", - "0x1b91e401b04884202400700501b1e31b91e401b0481791b91e401b048841", - "0x3301b0471791b91e403301b04784302400700501b1e31b91e401b048179", - "0x1b1e31b91e401b0481791b91e401b04884404802400700501b1e31b91e4", - "0x4884602400700501b1e31b91e401b0481791b91e401b048845024007005", - "0x481791b91e401b04884702400700501b1e31b91e401b0481791b91e401b", - "0x1b1e31b91e401b0481791b91e401b04884802400700501b1e31b91e401b", - "0x4884a02400700501b1e31b91e401b0481791b91e401b048849024007005", - "0x1791b91e401b23304784b02400700501b1e31b91e401b0481791b91e401b", - "0x461791b91e403301b23304684c04802400700501b1e31b91e401b233047", - "0x1b0481791b91e401b04884d04704802400700501b1e31b91e403301b233", - "0x1e31b91e423801b0471791b91e423801b04784e02400700501b1e31b91e4", - "0x501b1e31b91e401b2330471791b91e401b23304784f04802400700501b", - "0x4585102400700501b1e31b91e401b0481791b91e401b048850048024007", - "0x4802400700501b1e31b91e40d40d80d601b0451791b91e40d40d80d601b", - "0x4802400700501b1e31b91e40d601b0471791b91e40d601b047852046047", - "0x1b91e401b04885402400700501b1e31b91e401b0481791b91e401b048853", - "0x1b91e401b0481791b91e401b04885502400700501b1e31b91e401b048179", - "0x2400700501b1e31b91e401b0481791b91e401b04885602400700501b1e3", - "0x1e401b04885804802400700501b1fa1e401b02400604f1791e401b047857", - "0x2001e401b02404f1791e401b04885902400700501b2001e401b02417904f", - "0x2400700501b20a1b91e401b04820819b1b91e401b04785a02400700501b", - "0x4802400700501b20e1b91e401b0481780871780871b91e401b04585b048", - "0x1e401b0241791e401b02485d00501b21717901b02417901b00785c046047", - "0x21b1b91e401b04800600600617c17d19b1b91e401b04385e00700501b219", - "0x2400600600600620819b1b91e404485f04404504604704802400700501b", - "0x22101b0482231e422101b04886004504604704802400700501b1e31b91e4", - "0x700501b20a1b91e401b04819b1b91e401b04886102400700501b2251e4", - "0x1e401b04786302400700501b20a1b91e401b04819b1b91e401b048862024", - "0x19b1b91e401b04886404802400700501b20a1b90331e401b04719b1b9033", - "0x1b91e401b04804f19b1b91e401b04786502400700501b20a1b91e401b048", - "0x2400700501b20a1e401b02400619b1e401b04886604802400700501b22f", - "0x1b92331e401b04486802400700501b20a1e401b02400619b1e401b048867", - "0x4586904504604704802400700501b20a1b92331e401b04700600600619b", - "0x4704802400700501b20a1b92330331e401b04623519b1b92330331e401b", - "0x86b04802400700501b20a1b91e423801b04719b1b91e423801b04786a046", - "0x86c04704802400700501b20a1b92331e401b04700619b1b92331e401b046", - "0x4704802400700501b20a1e40d60d40d801b04619b1e40d60d40d801b046", - "0x1b91e401b04804f00618319b1b91e401b04586e01b21b0d60070d600586d", - "0x1b04787000501b24901b00717901b00786f04604704802400700501b20a", - "0x241791791e401b04887104802400700501b24a1e401b0240061711791e4", - "0x700501b2541e401b0241741741e401b04887202400700501b2521e401b", - "0x1611e401b04787402400700501b25e1e401b0241611691e401b048873024", - "0x26c01b00707907913d01b04887504802400700501b2601e401b024079087", - "0x2400700501b2701b91e401b0481421411b91e401b04787602400700501b", - "0x2400700501b2851b90331e401b04706728302f1b90331e401b045877048", - "0x700501b2921b91e401b04811302f02f02f1b91e401b045878046047048", - "0x1b0070790060ae01b04887a00501b0eb0052ce2ce007879046047048024", - "0x87c02400700501b2001e401b02404f2d91e401b04887b02400700501b2d1", - "0x700501b26001b00702f16101b02487d00501b2ea17901b02417901b007", - "0x13d00500613d00787f02400700501b2601e401b0240791611e401b04887e", - "0x88104802400700501b3161b91e401b04828302f1b91e401b04788000501b", - "0x1b02488204802400700501b2ed1b90331e401b04706c1b90331e401b047", - "0x1b04788400501b23901b00707901b00788300700501b25301b00702f02f", - "0x2f16103301b04888504802400700501b25e0331e401b0481611690331e4", - "0x88602400700501b26003301b024" - ], - "sierra_program_debug_info": { - "type_names": [], - "libfunc_names": [], - "user_func_names": [] - }, - "contract_class_version": "0.1.0", - "entry_points_by_type": { - "EXTERNAL": [ - { - "selector": "0x1143aa89c8e3ebf8ed14df2a3606c1cd2dd513fac8040b0f8ab441f5c52fe4", - "function_idx": 23 - }, - { - "selector": "0x3541591104188daef4379e06e92ecce09094a3b381da2e654eb041d00566d8", - "function_idx": 32 - }, - { - "selector": "0x3c118a68e16e12e97ed25cb4901c12f4d3162818669cc44c391d8049924c14", - "function_idx": 8 - }, - { - "selector": "0x5562b3e932b4d139366854d5a2e578382e6a3b6572ac9943d55e7efbe43d00", - "function_idx": 19 - }, - { - "selector": "0x600c98a299d72ef1e09a2e1503206fbc76081233172c65f7e2438ef0069d8d", - "function_idx": 24 - }, - { - "selector": "0x62c83572d28cb834a3de3c1e94977a4191469a4a8c26d1d7bc55305e640ed5", - "function_idx": 20 - }, - { - "selector": "0x679c22735055a10db4f275395763a3752a1e3a3043c192299ab6b574fba8d6", - "function_idx": 28 - }, - { - "selector": "0x7772be8b80a8a33dc6c1f9a6ab820c02e537c73e859de67f288c70f92571bb", - "function_idx": 26 - }, - { - "selector": "0xd47144c49bce05b6de6bce9d5ff0cc8da9420f8945453e20ef779cbea13ad4", - "function_idx": 1 - }, - { - "selector": "0xe7510edcf6e9f1b70f7bd1f488767b50f0363422f3c563160ab77adf62467b", - "function_idx": 11 - }, - { - "selector": "0xf818e4530ec36b83dfe702489b4df537308c3b798b0cc120e32c2056d68b7d", - "function_idx": 15 - }, - { - "selector": "0x10d2fede95e3ec06a875a67219425c27c5bd734d57f1b221d729a2337b6b556", - "function_idx": 13 - }, - { - "selector": "0x12ead94ae9d3f9d2bdb6b847cf255f1f398193a1f88884a0ae8e18f24a037b6", - "function_idx": 30 - }, - { - "selector": "0x14dae1999ae9ab799bc72def6dc6e90890cf8ac0d64525021b7e71d05cb13e8", - "function_idx": 5 - }, - { - "selector": "0x169f135eddda5ab51886052d777a57f2ea9c162d713691b5e04a6d4ed71d47f", - "function_idx": 14 - }, - { - "selector": "0x1995689b6aedab51ad67bc2ae0b0ee3fe1ffc433f96179953e6a6b7210b9e13", - "function_idx": 6 - }, - { - "selector": "0x1ae1a515cf2d214b29bdf63a79ee2d490efd4dd1acc99d383a8e549c3cecb5d", - "function_idx": 29 - }, - { - "selector": "0x1e4089d1f1349077b1970f9937c904e27c4582b49a60b6078946dba95bc3c08", - "function_idx": 4 - }, - { - "selector": "0x23039bef544cff56442d9f61ae9b13cf9e36fcce009102c5b678aac93f37b36", - "function_idx": 7 - }, - { - "selector": "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", - "function_idx": 2 - }, - { - "selector": "0x298e03955860424b6a946506da72353a645f653dc1879f6b55fd756f3d20a59", - "function_idx": 3 - }, - { - "selector": "0x2d7cf5d5a324a320f9f37804b1615a533fde487400b41af80f13f7ac5581325", - "function_idx": 12 - }, - { - "selector": "0x30f842021fbf02caf80d09a113997c1e00a32870eee0c6136bed27acb348bea", - "function_idx": 27 - }, - { - "selector": "0x31401f504973a5e8e1bb41e9c592519e3aa0b8cf6bbfb9c91b532aab8db54b0", - "function_idx": 33 - }, - { - "selector": "0x317eb442b72a9fae758d4fb26830ed0d9f31c8e7da4dbff4e8c59ea6a158e7f", - "function_idx": 25 - }, - { - "selector": "0x32564d7e0fe091d49b4c20f4632191e4ed6986bf993849879abfef9465def25", - "function_idx": 21 - }, - { - "selector": "0x3604cea1cdb094a73a31144f14a3e5861613c008e1e879939ebc4827d10cd50", - "function_idx": 9 - }, - { - "selector": "0x382be990ca34815134e64a9ac28f41a907c62e5ad10547f97174362ab94dc89", - "function_idx": 16 - }, - { - "selector": "0x38be5d5f7bf135b52888ba3e440a457d11107aca3f6542e574b016bf3f074d8", - "function_idx": 17 - }, - { - "selector": "0x3a6a8bae4c51d5959683ae246347ffdd96aa5b2bfa68cc8c3a6a7c2ed0be331", - "function_idx": 10 - }, - { - "selector": "0x3b097c62d3e4b85742aadd0dfb823f96134b886ec13bda57b68faf86f294d97", - "function_idx": 0 - }, - { - "selector": "0x3d3da80997f8be5d16e9ae7ee6a4b5f7191d60765a1a6c219ab74269c85cf97", - "function_idx": 31 - }, - { - "selector": "0x3d95049b565ec2d4197a55108ef03996381d31c84acf392a0a42b28163d69d1", - "function_idx": 18 - }, - { - "selector": "0x3eb640b15f75fcc06d43182cdb94ed38c8e71755d5fb57c16dd673b466db1d4", - "function_idx": 22 - } - ], - "L1_HANDLER": [ - { - "selector": "0x205500a208d0d49d79197fea83cc3f5fde99ac2e1909ae0a5d9f394c0c52ed0", - "function_idx": 35 - }, - { - "selector": "0x39edbbb129ad752107a94d40c3873cae369a46fd2fc578d075679aa67e85d12", - "function_idx": 34 - } - ], - "CONSTRUCTOR": [ - { - "selector": "0x28ffe4ff0f226a9107253e17a904099aa4f63a02a5621de0576e5aa71bc5194", - "function_idx": 36 - } - ] - }, - "abi": [ - { - "type": "constructor", - "name": "constructor", - "inputs": [ - { - "name": "arg1", - "type": "core::felt252" - }, - { - "name": "arg2", - "type": "core::felt252" - } - ] - }, - { - "type": "function", - "name": "test_storage_read_write", - "inputs": [ - { - "name": "address", - "type": "core::starknet::storage_access::StorageAddress" - }, - { - "name": "value", - "type": "core::felt252" - } - ], - "outputs": [ - { - "type": "core::felt252" - } - ], - "state_mutability": "view" - }, - { - "type": "function", - "name": "test_count_actual_storage_changes", - "inputs": [], - "outputs": [], - "state_mutability": "view" - }, - { - "type": "struct", - "name": "core::array::Span::", - "members": [ - { - "name": "snapshot", - "type": "@core::array::Array::" - } - ] - }, - { - "type": "function", - "name": "test_call_contract", - "inputs": [ - { - "name": "contract_address", - "type": "core::starknet::contract_address::ContractAddress" - }, - { - "name": "entry_point_selector", - "type": "core::felt252" - }, - { - "name": "calldata", - "type": "core::array::Array::" - } - ], - "outputs": [ - { - "type": "core::array::Span::" - } - ], - "state_mutability": "view" - }, - { - "type": "function", - "name": "test_call_two_contracts", - "inputs": [ - { - "name": "contract_address_0", - "type": "core::starknet::contract_address::ContractAddress" - }, - { - "name": "entry_point_selector_0", - "type": "core::felt252" - }, - { - "name": "calldata_0", - "type": "core::array::Array::" - }, - { - "name": "contract_address_1", - "type": "core::starknet::contract_address::ContractAddress" - }, - { - "name": "entry_point_selector_1", - "type": "core::felt252" - }, - { - "name": "calldata_1", - "type": "core::array::Array::" - } - ], - "outputs": [ - { - "type": "core::array::Span::" - } - ], - "state_mutability": "view" - }, - { - "type": "function", - "name": "test_revert_helper", - "inputs": [ - { - "name": "class_hash", - "type": "core::starknet::class_hash::ClassHash" - } - ], - "outputs": [], - "state_mutability": "external" - }, - { - "type": "function", - "name": "test_emit_events", - "inputs": [ - { - "name": "events_number", - "type": "core::integer::u64" - }, - { - "name": "keys", - "type": "core::array::Array::" - }, - { - "name": "data", - "type": "core::array::Array::" - } - ], - "outputs": [], - "state_mutability": "view" - }, - { - "type": "function", - "name": "test_get_class_hash_at", - "inputs": [ - { - "name": "address", - "type": "core::starknet::contract_address::ContractAddress" - }, - { - "name": "expected_class_hash", - "type": "core::starknet::class_hash::ClassHash" - } - ], - "outputs": [], - "state_mutability": "view" - }, - { - "type": "function", - "name": "test_get_block_hash", - "inputs": [ - { - "name": "block_number", - "type": "core::integer::u64" - } - ], - "outputs": [ - { - "type": "core::felt252" - } - ], - "state_mutability": "view" - }, - { - "type": "struct", - "name": "core::starknet::info::BlockInfo", - "members": [ - { - "name": "block_number", - "type": "core::integer::u64" - }, - { - "name": "block_timestamp", - "type": "core::integer::u64" - }, - { - "name": "sequencer_address", - "type": "core::starknet::contract_address::ContractAddress" - } - ] - }, - { - "type": "struct", - "name": "core::starknet::info::v2::ResourceBounds", - "members": [ - { - "name": "resource", - "type": "core::felt252" - }, - { - "name": "max_amount", - "type": "core::integer::u64" - }, - { - "name": "max_price_per_unit", - "type": "core::integer::u128" - } - ] - }, - { - "type": "struct", - "name": "core::array::Span::", - "members": [ - { - "name": "snapshot", - "type": "@core::array::Array::" - } - ] - }, - { - "type": "struct", - "name": "core::starknet::info::v2::TxInfo", - "members": [ - { - "name": "version", - "type": "core::felt252" - }, - { - "name": "account_contract_address", - "type": "core::starknet::contract_address::ContractAddress" - }, - { - "name": "max_fee", - "type": "core::integer::u128" - }, - { - "name": "signature", - "type": "core::array::Span::" - }, - { - "name": "transaction_hash", - "type": "core::felt252" - }, - { - "name": "chain_id", - "type": "core::felt252" - }, - { - "name": "nonce", - "type": "core::felt252" - }, - { - "name": "resource_bounds", - "type": "core::array::Span::" - }, - { - "name": "tip", - "type": "core::integer::u128" - }, - { - "name": "paymaster_data", - "type": "core::array::Span::" - }, - { - "name": "nonce_data_availability_mode", - "type": "core::integer::u32" - }, - { - "name": "fee_data_availability_mode", - "type": "core::integer::u32" - }, - { - "name": "account_deployment_data", - "type": "core::array::Span::" - } - ] - }, - { - "type": "function", - "name": "test_get_execution_info", - "inputs": [ - { - "name": "expected_block_info", - "type": "core::starknet::info::BlockInfo" - }, - { - "name": "expected_tx_info", - "type": "core::starknet::info::v2::TxInfo" - }, - { - "name": "expected_caller_address", - "type": "core::felt252" - }, - { - "name": "expected_contract_address", - "type": "core::felt252" - }, - { - "name": "expected_entry_point_selector", - "type": "core::felt252" - } - ], - "outputs": [], - "state_mutability": "view" - }, - { - "type": "function", - "name": "test_library_call", - "inputs": [ - { - "name": "class_hash", - "type": "core::starknet::class_hash::ClassHash" - }, - { - "name": "function_selector", - "type": "core::felt252" - }, - { - "name": "calldata", - "type": "core::array::Array::" - } - ], - "outputs": [ - { - "type": "core::array::Span::" - } - ], - "state_mutability": "view" - }, - { - "type": "function", - "name": "test_nested_library_call", - "inputs": [ - { - "name": "class_hash", - "type": "core::starknet::class_hash::ClassHash" - }, - { - "name": "lib_selector", - "type": "core::felt252" - }, - { - "name": "nested_selector", - "type": "core::felt252" - }, - { - "name": "a", - "type": "core::felt252" - }, - { - "name": "b", - "type": "core::felt252" - } - ], - "outputs": [ - { - "type": "core::array::Span::" - } - ], - "state_mutability": "view" - }, - { - "type": "function", - "name": "test_replace_class", - "inputs": [ - { - "name": "class_hash", - "type": "core::starknet::class_hash::ClassHash" - } - ], - "outputs": [], - "state_mutability": "view" - }, - { - "type": "function", - "name": "test_send_message_to_l1", - "inputs": [ - { - "name": "to_address", - "type": "core::felt252" - }, - { - "name": "payload", - "type": "core::array::Array::" - } - ], - "outputs": [], - "state_mutability": "view" - }, - { - "type": "function", - "name": "segment_arena_builtin", - "inputs": [], - "outputs": [], - "state_mutability": "view" - }, - { - "type": "l1_handler", - "name": "l1_handle", - "inputs": [ - { - "name": "from_address", - "type": "core::felt252" - }, - { - "name": "arg", - "type": "core::felt252" - } - ], - "outputs": [ - { - "type": "core::felt252" - } - ], - "state_mutability": "view" - }, - { - "type": "l1_handler", - "name": "l1_handler_set_value", - "inputs": [ - { - "name": "from_address", - "type": "core::felt252" - }, - { - "name": "key", - "type": "core::starknet::storage_access::StorageAddress" - }, - { - "name": "value", - "type": "core::felt252" - } - ], - "outputs": [ - { - "type": "core::felt252" - } - ], - "state_mutability": "view" - }, - { - "type": "enum", - "name": "core::bool", - "variants": [ - { - "name": "False", - "type": "()" - }, - { - "name": "True", - "type": "()" - } - ] - }, - { - "type": "function", - "name": "test_deploy", - "inputs": [ - { - "name": "class_hash", - "type": "core::starknet::class_hash::ClassHash" - }, - { - "name": "contract_address_salt", - "type": "core::felt252" - }, - { - "name": "calldata", - "type": "core::array::Array::" - }, - { - "name": "deploy_from_zero", - "type": "core::bool" - } - ], - "outputs": [], - "state_mutability": "view" - }, - { - "type": "function", - "name": "test_keccak", - "inputs": [], - "outputs": [], - "state_mutability": "external" - }, - { - "type": "function", - "name": "test_sha256", - "inputs": [], - "outputs": [], - "state_mutability": "external" - }, - { - "type": "function", - "name": "test_secp256k1", - "inputs": [], - "outputs": [], - "state_mutability": "external" - }, - { - "type": "function", - "name": "test_secp256r1", - "inputs": [], - "outputs": [], - "state_mutability": "external" - }, - { - "type": "function", - "name": "assert_eq", - "inputs": [ - { - "name": "x", - "type": "core::felt252" - }, - { - "name": "y", - "type": "core::felt252" - } - ], - "outputs": [ - { - "type": "core::felt252" - } - ], - "state_mutability": "external" - }, - { - "type": "function", - "name": "invoke_call_chain", - "inputs": [ - { - "name": "call_chain", - "type": "core::array::Array::" - } - ], - "outputs": [ - { - "type": "core::felt252" - } - ], - "state_mutability": "external" - }, - { - "type": "function", - "name": "fail", - "inputs": [], - "outputs": [], - "state_mutability": "external" - }, - { - "type": "function", - "name": "recursive_fail", - "inputs": [ - { - "name": "depth", - "type": "core::felt252" - } - ], - "outputs": [], - "state_mutability": "external" - }, - { - "type": "function", - "name": "recurse", - "inputs": [ - { - "name": "depth", - "type": "core::felt252" - } - ], - "outputs": [], - "state_mutability": "external" - }, - { - "type": "function", - "name": "recursive_syscall", - "inputs": [ - { - "name": "contract_address", - "type": "core::starknet::contract_address::ContractAddress" - }, - { - "name": "function_selector", - "type": "core::felt252" - }, - { - "name": "depth", - "type": "core::felt252" - } - ], - "outputs": [], - "state_mutability": "external" - }, - { - "type": "function", - "name": "advance_counter", - "inputs": [ - { - "name": "index", - "type": "core::felt252" - }, - { - "name": "diff_0", - "type": "core::felt252" - }, - { - "name": "diff_1", - "type": "core::felt252" - } - ], - "outputs": [], - "state_mutability": "external" - }, - { - "type": "struct", - "name": "test_contract::test_contract::TestContract::IndexAndValues", - "members": [ - { - "name": "index", - "type": "core::felt252" - }, - { - "name": "values", - "type": "(core::integer::u128, core::integer::u128)" - } - ] - }, - { - "type": "function", - "name": "xor_counters", - "inputs": [ - { - "name": "index_and_x", - "type": "test_contract::test_contract::TestContract::IndexAndValues" - } - ], - "outputs": [], - "state_mutability": "external" - }, - { - "type": "function", - "name": "call_xor_counters", - "inputs": [ - { - "name": "address", - "type": "core::starknet::contract_address::ContractAddress" - }, - { - "name": "index_and_x", - "type": "test_contract::test_contract::TestContract::IndexAndValues" - } - ], - "outputs": [], - "state_mutability": "external" - }, - { - "type": "function", - "name": "test_ec_op", - "inputs": [], - "outputs": [], - "state_mutability": "external" - }, - { - "type": "function", - "name": "add_signature_to_counters", - "inputs": [ - { - "name": "index", - "type": "core::felt252" - } - ], - "outputs": [], - "state_mutability": "external" - }, - { - "type": "function", - "name": "send_message", - "inputs": [ - { - "name": "to_address", - "type": "core::felt252" - } - ], - "outputs": [], - "state_mutability": "view" - }, - { - "type": "function", - "name": "test_circuit", - "inputs": [], - "outputs": [], - "state_mutability": "external" - }, - { - "type": "function", - "name": "test_rc96_holes", - "inputs": [], - "outputs": [], - "state_mutability": "external" - }, - { - "type": "function", - "name": "test_call_contract_revert", - "inputs": [ - { - "name": "contract_address", - "type": "core::starknet::contract_address::ContractAddress" - }, - { - "name": "entry_point_selector", - "type": "core::felt252" - }, - { - "name": "calldata", - "type": "core::array::Array::" - } - ], - "outputs": [], - "state_mutability": "external" - }, - { - "type": "event", - "name": "test_contract::test_contract::TestContract::Event", - "kind": "enum", - "variants": [] - } - ] -} \ No newline at end of file diff --git a/crates/blockifier/feature_contracts/cairo_native/compiled/test_contract_execution_info_v1.sierra.json b/crates/blockifier/feature_contracts/cairo_native/compiled/test_contract_execution_info_v1.sierra.json deleted file mode 100644 index 0c653fe3c64..00000000000 --- a/crates/blockifier/feature_contracts/cairo_native/compiled/test_contract_execution_info_v1.sierra.json +++ /dev/null @@ -1,900 +0,0 @@ -{ - "sierra_program": [ - "0x1", - "0x6", - "0x0", - "0x2", - "0x8", - "0x0", - "0x17a", - "0x86", - "0x44", - "0x52616e6765436865636b", - "0x800000000000000100000000000000000000000000000000", - "0x436f6e7374", - "0x800000000000000000000000000000000000000000000002", - "0x1", - "0x1a", - "0x2", - "0x4f7074696f6e3a3a756e77726170206661696c65642e", - "0x7533325f737562204f766572666c6f77", - "0x496e646578206f7574206f6620626f756e6473", - "0x18", - "0x0", - "0x53455155454e4345525f4d49534d41544348", - "0x54585f494e464f5f56455253494f4e5f4d49534d41544348", - "0x4143434f554e545f435f414444524553535f4d49534d41544348", - "0x54585f494e464f5f484153485f4d49534d41544348", - "0x54585f494e464f5f434841494e5f49445f4d49534d41544348", - "0x54585f494e464f5f4e4f4e43455f4d49534d41544348", - "0x43414c4c45525f4d49534d41544348", - "0x434f4e54524143545f4d49534d41544348", - "0x53454c4543544f525f4d49534d41544348", - "0x54585f494e464f5f5349474e41545552455f4d49534d41544348", - "0x537472756374", - "0x800000000000000f00000000000000000000000000000001", - "0x2ee1e2b1b89f8c495f200e4956278a4d47395fe262f27b52e5865c9524c08c3", - "0x456e756d", - "0x800000000000000700000000000000000000000000000003", - "0x3288d594b9a45d15bb2fcb7903f06cdb06b27f0ba88186ec4cfaa98307cb972", - "0xf", - "0x4172726179", - "0x800000000000000300000000000000000000000000000001", - "0x536e617073686f74", - "0x800000000000000700000000000000000000000000000001", - "0x11", - "0x800000000000000700000000000000000000000000000002", - "0x1baeba72e79e9db2587cf44fedb2f3700b2075a5e8e39a562584862c4b71f62", - "0x12", - "0x800000000000000700000000000000000000000000000004", - "0x13", - "0x10", - "0x16a4c8d7c05909052238a862d8cc3e7975bf05a07b3a69c6b28951083a6d672", - "0x800000000000000300000000000000000000000000000003", - "0x15", - "0x45b67c75542d42836cef6c02cca4dbff4a80a8621fa521cbfff1b2dd4af35a", - "0x14", - "0x16", - "0x753332", - "0x800000000000000700000000000000000000000000000000", - "0x54585f494e464f5f4d41585f4645455f4d49534d41544348", - "0x66656c74323532", - "0x4e6f6e5a65726f", - "0x424c4f434b5f54494d455354414d505f4d49534d41544348", - "0x424c4f434b5f4e554d4245525f4d49534d41544348", - "0x753634", - "0x436f6e747261637441646472657373", - "0x3808c701a5d13e100ab11b6c02f91f752ecae7e420d21b56c90ec0a475cc7e5", - "0x1e", - "0x1f", - "0x426f78", - "0x3c", - "0x20", - "0x800000000000000700000000000000000000000000000006", - "0x19367431bdedfe09ea99eed9ade3de00f195dd97087ed511b8942ebb45dbc5a", - "0x22", - "0x21", - "0x23", - "0x556e696e697469616c697a6564", - "0x800000000000000200000000000000000000000000000001", - "0x53797374656d", - "0x26", - "0x1d49f7a4b277bf7b55a2664ce8cef5d6922b5ffb806b89644b9e0cdbbcac378", - "0x29", - "0x13fdd7105045794a99550ae1c4ac13faa62610dfab62c16422bfcf5803baa6e", - "0x2a", - "0x75313238", - "0x4661696c656420746f20646573657269616c697a6520706172616d202331", - "0x4661696c656420746f20646573657269616c697a6520706172616d202332", - "0x4661696c656420746f20646573657269616c697a6520706172616d202333", - "0x4661696c656420746f20646573657269616c697a6520706172616d202334", - "0x4661696c656420746f20646573657269616c697a6520706172616d202335", - "0x4661696c656420746f20646573657269616c697a6520706172616d202336", - "0x4661696c656420746f20646573657269616c697a6520706172616d202337", - "0x4f7574206f6620676173", - "0x800000000000000f00000000000000000000000000000002", - "0xcc5e86243f861d2d64b08c35db21013e773ac5cf10097946fe0011304886d5", - "0x36", - "0x371a38276a14d2475f9072073e9ab9b154a40bb41edce5be7d1ade8ccbeb2e4", - "0x4275696c74696e436f737473", - "0x9931c641b913035ae674b400b61a51476d506bbe8bba2ff8a6272790aba9e6", - "0x35", - "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", - "0x800000000000000700000000000000000000000000000008", - "0x2e655a7513158873ca2e5e659a9e175d23bf69a2325cdd0397ca3b8d864b967", - "0x2c", - "0x109c59bf70ce1d096631b005c20ec90d752446fc0fd825dac0e61dd34c3af50", - "0x3d", - "0x12635a64ec5093a14e1239a44eef43a4a94ce4403a075c9e94b6ef456572cda", - "0x3e", - "0x11c6d8087e00642489f92d2821ad6ebd6532ad1a3b6d12833da6d6810391511", - "0x29d7d57c04a880978e7b3689f6218e507f3be17588744b58dc17762447ad0e7", - "0x41", - "0x4761734275696c74696e", - "0x9f", - "0x7265766f6b655f61705f747261636b696e67", - "0x77697468647261775f676173", - "0x6272616e63685f616c69676e", - "0x7374727563745f6465636f6e737472756374", - "0x656e61626c655f61705f747261636b696e67", - "0x73746f72655f74656d70", - "0x61727261795f736e617073686f745f706f705f66726f6e74", - "0x656e756d5f696e6974", - "0x42", - "0x6a756d70", - "0x7374727563745f636f6e737472756374", - "0x656e756d5f6d61746368", - "0x756e626f78", - "0x72656e616d65", - "0x7536345f7472795f66726f6d5f66656c74323532", - "0x40", - "0x21adb5788e32c84f69a1863d85ef9394b7bf761a0ce1190f826984e5075c371", - "0x66756e6374696f6e5f63616c6c", - "0x3", - "0x3f", - "0x64697361626c655f61705f747261636b696e67", - "0x64726f70", - "0x61727261795f6e6577", - "0x636f6e73745f61735f696d6d656469617465", - "0x3b", - "0x61727261795f617070656e64", - "0x3a", - "0x43", - "0x6765745f6275696c74696e5f636f737473", - "0x39", - "0x77697468647261775f6761735f616c6c", - "0x38", - "0x736e617073686f745f74616b65", - "0x37", - "0x34", - "0x33", - "0x32", - "0x31", - "0x30", - "0x2f", - "0x2e", - "0x2d", - "0x647570", - "0x75313238735f66726f6d5f66656c74323532", - "0x2b", - "0x616c6c6f635f6c6f63616c", - "0x66696e616c697a655f6c6f63616c73", - "0x6765745f657865637574696f6e5f696e666f5f73797363616c6c", - "0x24", - "0x73746f72655f6c6f63616c", - "0x7536345f6571", - "0x28", - "0x1d", - "0x1c", - "0x636f6e74726163745f616464726573735f746f5f66656c74323532", - "0x66656c743235325f737562", - "0x66656c743235325f69735f7a65726f", - "0x753132385f6571", - "0x19", - "0x61727261795f6c656e", - "0x7533325f6571", - "0x4", - "0x17", - "0xe", - "0x1b", - "0xd", - "0xc", - "0xb", - "0xa", - "0x9", - "0x8", - "0x7", - "0x6", - "0x5", - "0x25", - "0x27", - "0x7533325f7472795f66726f6d5f66656c74323532", - "0x61727261795f736c696365", - "0x7533325f6f766572666c6f77696e675f737562", - "0x50a", - "0xffffffffffffffff", - "0x16d", - "0x15c", - "0x158", - "0x146", - "0x141", - "0x12e", - "0x128", - "0x11d", - "0x10a", - "0x4f", - "0x45", - "0x46", - "0x47", - "0x54", - "0x48", - "0x49", - "0x4a", - "0xf6", - "0x4b", - "0x4c", - "0x4d", - "0x5e", - "0x4e", - "0x50", - "0x51", - "0x52", - "0x53", - "0x63", - "0x55", - "0x56", - "0xe1", - "0x57", - "0x58", - "0x59", - "0x6d", - "0x5a", - "0x5b", - "0x5c", - "0x5d", - "0x5f", - "0x72", - "0x60", - "0x61", - "0x62", - "0xcb", - "0x64", - "0x65", - "0x8c", - "0x66", - "0x67", - "0x68", - "0x69", - "0x6a", - "0x6b", - "0x6c", - "0x6e", - "0x6f", - "0xb6", - "0x70", - "0x71", - "0x73", - "0x74", - "0x75", - "0x76", - "0x77", - "0x78", - "0x79", - "0xaf", - "0x7a", - "0x7b", - "0x7c", - "0x7d", - "0x7e", - "0x7f", - "0x80", - "0x81", - "0x82", - "0x83", - "0x84", - "0x85", - "0x86", - "0x87", - "0x88", - "0x89", - "0x8a", - "0x8b", - "0x8d", - "0x8e", - "0x8f", - "0x90", - "0x91", - "0x92", - "0x93", - "0x94", - "0x95", - "0x96", - "0x97", - "0x98", - "0x99", - "0x9a", - "0x9b", - "0x9c", - "0x9d", - "0x9e", - "0xa0", - "0xa1", - "0x134", - "0xa2", - "0xa3", - "0xa4", - "0xa5", - "0xa6", - "0xa7", - "0xa8", - "0x14b", - "0xa9", - "0xaa", - "0xab", - "0xac", - "0xad", - "0xae", - "0x160", - "0xb0", - "0xb1", - "0xb2", - "0xb3", - "0xb4", - "0xb5", - "0xb7", - "0xb8", - "0xb9", - "0xba", - "0xbb", - "0x184", - "0x189", - "0x24b", - "0x193", - "0x198", - "0x240", - "0x23b", - "0x1a6", - "0x1ab", - "0x230", - "0x229", - "0x221", - "0x217", - "0x1c4", - "0x1c9", - "0x20b", - "0x1d3", - "0x1d8", - "0x1fe", - "0x1e2", - "0x1e7", - "0x1f1", - "0x235", - "0x245", - "0x422", - "0x28b", - "0x2a7", - "0x409", - "0x3e9", - "0x3cb", - "0x2de", - "0x2fa", - "0x316", - "0x3b8", - "0x322", - "0x3a0", - "0x38a", - "0x376", - "0x364", - "0x354", - "0x346", - "0x440", - "0x445", - "0x497", - "0x48e", - "0x481", - "0x472", - "0x466", - "0x4fc", - "0x4ad", - "0x4b2", - "0x4f1", - "0x4be", - "0x4c3", - "0x4e0", - "0x4d5", - "0x17b", - "0x253", - "0x439", - "0x4a1", - "0x2ab2", - "0x300e0b02810060a038180a04018240e06028100608038180a04018080200", - "0x1408030801c0c050200c1e070301408030701c0c050200c1a07030140803", - "0x540e06028100614038180a040184c0e06028100612038180a04018440e06", - "0x5c4405108800c050f8783a050e814380c0d868320c0c05c2c07030140803", - "0x880a2b02864182a0b8a418180b8a00a270289c0a19060982e25028901823", - "0x1c0c050200c0c05108cc60321881c0c050200c602f170145a0516030541a", - "0x84763c02884763a028e40a39028e018260b8c06e301b0d40e06028100634", - "0x10c04451d014884321014423b0301474051d0148205200147e0c1f05c7a05", - "0x124182a0d1200a2702864181b0b8740a270291c181b0d0180a44219180a44", - "0x1408032701c0c050200c9a070301408032601c0c050200c604b170149405", - "0x14c0e06028100652038180a04019440e06028100650038180a040193c0e06", - "0x6860582b830301717014ac052a830541a0e814320c2a05c4e050c8304617", - "0x180a27029780a3a028180a5d061702e5b038180a04018b80a5a02964182a", - "0x14c40530830541a300144e050c83036170e81478052f830361a030140c05", - "0x1a4186833808cc1d029940a640606c340602884761d028180a630606c342e", - "0x940a05368300e700281cde0602814dc0c02814da0c3609c0a0535830d40c", - "0x140a75030140a74380140a730281ce005039bc3a05029c81871380140a6d", - "0x1dc0a05398140e770281cde7702814da0c039dc0a0737830ec0602814da06", - "0x1f0c005029ccc405029acf605029cc0a7a029e44e05029b44e05029c81878", - "0x14fc3902814fa3a02814fa3c02814fa0602814fa6502814fa2502814fa0c", - "0x140a6d0281d0405039bc5c05029c85605029c80c0502a050005029fc0c05", - "0x14fa8702815108702814e40c432140a0536831088202814da4602814da83", - "0x220ac05029f51205029cc0e7a029e47805029b47405029b47205029b50e05", - "0x14fe1d02814fa8a02814fe0c03a080a07379680a05390880a053e8880a05", - "0x1fd2005029fd1e05029fd1c05029fc4e05029f51a05029fd1805029fd1605", - "0x14e44802814e64a02814d69402814e67a3d014f20c498940a05492440a05", - "0x1bcbc05029f4f605029b418073d8140e6f310140a720601cc005039bc7805", - "0x312e0c4b0e80a054a9180a054a8180a054a8140e7b0281cde05039800a07", - "0x140a991e8140a6b1e8140a74200140a6d210140a6b210140a744c0140a6d", - "0x2700a053f9040a053ea6c0a053e831340602815323a02815324102814da46", - "0x140a6b1e0140a7406280189f062793a05029fd1205029b40a07448140e6f", - "0x14f20c5202c0a05368180a055189c0a05492880a053f831425e02814da3c", - "0x1d1205039bcac05029c94e05029fc5005029cc5a05029ad4c05029cd4a7a", - "0x14fead02814feac02814feab02814feaa02814fea902814fea802814fa0c", - "0x140a7f062d16605029f56405029f56205029fd6005029fd5e05029fd5c05", - "0x300e940281cde4a02814e40c039200a07378316c06028156a0b0281524a5", - "0x1c9005039bc0e05029fc1605029f40a074a0140e6f3d0140a7f4a0140a6d", - "0x1cde0502814fea602814da0c03a980a07378b40a05390300e280281cde05", - "0x2c54a075c01c0a0c03814180c5c014180c062dc0a07140140e6f0281d4c05", - "0x15620c062e00a0c528315c055c014f4053d03018b8028300e0c57ac00eb9", - "0x2b00aaf0603170050601c18ab02aa958ad03ae00eae02ac018a502ae00aa5", - "0x30182202831580c538157005550155a0c548157005568155c0c550157005", - "0x157005558155c0c1401570050e815540c0e8157005062ac180c5c0141807", - "0x3018b8028300e0c12815742202ae00ea702aa418a702ae00a2802ab418a9", - "0x2940e22060b40ab8028b40a28060b40ab80289c0a1d0609c0ab8028880aa7", - "0x2a40ab0060ac0ab8028ac0ab10603170050601c18a602aec5c2b03ae00e2d", - "0x1416055703150055c01544055783018b8028300e0c0301474a20581d7007", - "0x1418ab0603170050601c180c4c01418ac062700ab802aa00aad062740ab8", - "0x2700ab8028e80aad062740ab8028180aae060e80ab8028e40aaa060e40ab8", - "0x74184002ae00a3d02a9c180c5c0141807061040abc1e81570074e015520c", - "0x1180abd592600eb80390856071103084055c01484051403084055c0148005", - "0x3090054526d66075c01d3a055803130055c01530055883018b8028300e0c", - "0x2e00a9402894189402ae00a4a02874184a02ae00a9b02a9c180c5c0141807", - "0x300e0c062140a0c5603120055c014bc051383122055c015660557030bc05", - "0x3122055c0149005570311c055c0151e05168311e055c01418ab060317005", - "0x1c5c0c062e00a0c0383118055f2340ab803a400a2b062400ab802a380a27", - "0x15620c2b0157005488154c0c062e00a0c03830b4055fa2916075c01d1a98", - "0x21c0a060621d12075c014ac8b03a88185602ae00a560282c188b02ae00a8b", - "0x1c78054e830788003ae00a8502aa0180c5c0141807062080ac0428157007", - "0x1d70073d815600c3d815700540014f40c062e00a0c03830c405609800ab8", - "0xab802a0c0a1d0620c0ab8029940aa70603170050601c187002b08ca77", - "0x31580c628157005618144e0c6201570053b8155c0c618157005000144a0c", - "0x155c0c640157005638145a0c638157005062ac180c5c0141807060318c05", - "0x300e0c6581594c902ae00ec5028ac18c502ae00ac80289c18c402ae00a70", - "0x2e00acd02a9c180c5c01418070633c0ace66b300eb803b100ab0060317005", - "0x31a4055c015980557031a2055c015a00512831a0055c01584050e8318405", - "0x318c055c01418ab0603170050601c180c6a01418ac0634c0ab802b440a27", - "0x34c0a2b0634c0ab802b540a27063480ab802b3c0aae063540ab802b180a2d", - "0x1c18dc02b6db4d903ae00ed202ac0180c5c0141807063600ad76b0157007", - "0x1570056f0144a0c6f01570056e8143a0c6e81570056d0154e0c062e00a0c", - "0x14180706031c205062b018e002ae00adf0289c18ce02ae00ad902ab818df", - "0x9c18ce02ae00adc02ab818e302ae00ae2028b418e202ae00a0c5583018b8", - "0x3380ab00603170050601c18d402b95c8055c01dc00515831c0055c015c605", - "0x31700573014720c062e00a0c4e03018b8028300e0c74815d0e77301d7007", - "0x2e00ac9028f4180c5c015ac051e83018b802b900a3d06031700573814740c", - "0x145c052103018b802ac80a4206031700545014800c062e00a6002904180c", - "0x1c8c0c75815700575814500c758157005062c818ea02ae00a0c4c03018b8", - "0x15dc0524031dc055c015d8ed03a6c18ed02ae00a0c59831d8055c015d6ea", - "0x1c0ab80281c0a94062c40ab802ac40a4a062240ab802a240ab1063bc0ab8", - "0x31700574814720c062e00a0c03831de0758a254a0577815700577814bc0c", - "0x3c9e2f003ae00edb58a24f48f0636c0ab802b6c0a900636c0ab802831220c", - "0x15c20546831c2055c014188e06031700506270180c5c0141807063d1e607", - "0x3c40ab802bc40a4a063c00ab802bc00ab10603170057a815180c7b3d40eb8", - "0x15140c59015700559015160c17015700517015160c03815700503815280c", - "0x2e00ad6028a018c902ae00ac9028a0186002ae00a6002968188a02ae00a8a", - "0x2957005723599260452c85cf603bc5e0ab2b031c8055c015c80514031ac05", - "0x2e00afb02a1c180c5c0141807063f40afc7d81570077d015120c7d3e5f0f7", - "0x154c0c062e00aff02a0819007f81d70057f0150a0c7f015700506260180c", - "0x2e00af702ac4190302ae00b02028f0190202ae00b0102a00190102ae00b00", - "0x1606055c01606052f031f2055c015f2054a031f0055c015f00525031ee05", - "0x3dc0ab802bdc0ab1064100ab802bf40a480603170050601c19037cbe1eea5", - "0x3dd4a0582015700582014bc0c7c81570057c815280c7c01570057c014940c", - "0x15ac051e83018b802b900a3d06031700506270180c5c014180706411f2f8", - "0x2c80a4206031700545014800c062e00a6002904180c5c01592051e83018b8", - "0x14500c83015700506180190502ae00a0c4c03018b8028b80a42060317005", - "0x160f0803a6c190802ae00a0c598320e055c0160d0503918190602ae00b06", - "0x3d00ab802bd00a4a063cc0ab802bcc0ab1064280ab802c240a48064240ab8", - "0x2e00a0c0383214077a3cd4a0585015700585014bc0c03815700503815280c", - "0x2e00ad6028f4180c5c0159c051c83018b802b500a6206031700506270180c", - "0x1564052103018b802a280a4006031700530014820c062e00ac9028f4180c", - "0x4300a28064300ab802830f60c85815700506260180c5c0145c052103018b8", - "0x2e00b0d8701d360c870157005062cc190d02ae00b0c8581c8c0c860157005", - "0x3162055c01562052503112055c0151205588321e055c015d00524031d005", - "0x3170050601c190f03ac512a502c3c0ab802c3c0a5e0601c0ab80281c0a94", - "0x31700569014720c062e00a2e02908180c5c015b0053103018b802831380c", - "0x2e00ab202908180c5c01514052003018b8029800a41060317005648147a0c", - "0x4400e46064440ab802c440a28064440ab802830ee0c88015700506260180c", - "0x2e00b1402920191402ae00b128981d360c898157005062cc191202ae00b11", - "0x300e055c0140e054a03162055c01562052503112055c0151205588322a05", - "0x188180c5c014189c0603170050601c191503ac512a502c540ab802c540a5e", - "0x3018b802b100a3906031700559014840c062e00a2e02908180c5c0159605", - "0x45c0ab802830ca0c8b015700506260180c5c01514052003018b8029800a41", - "0x1d360c8c8157005062cc191802ae00b178b01c8c0c8b81570058b814500c", - "0x1562052503112055c01512055883236055c01634052403234055c0163119", - "0x1c191b03ac512a502c6c0ab802c6c0a5e0601c0ab80281c0a94062c40ab8", - "0x14840c062e00a2e02908180c5c014c4053103018b802831380c062e00a0c", - "0x20c191c02ae00a0c4c03018b802a000a7006031700545014800c062e00ab2", - "0x2e00a0c598323c055c0163b1c03918191d02ae00b1d028a0191d02ae00a0c", - "0x2240ab802a240ab10619c0ab802c800a48064800ab802c7a3e074d8323e05", - "0x2254a0533815700533814bc0c03815700503815280c58815700558814940c", - "0x1564052103018b8028b80a4206031700506270180c5c01418070619c0eb1", - "0x128188902ae00a8902ac4192102ae00a8202920180c5c01514052003018b8", - "0x1d62895281642055c01642052f0300e055c0140e054a03162055c0156205", - "0x2e00ab202908180c5c0145c052103018b802a440a390603170050601c1921", - "0x2e00a8c02988180c5c0141807060324605062b0192202ae00a5a02ac4180c", - "0x1530055883018b802ac80a4206031700517014840c062e00a91028e4180c", - "0x4940a28064940ab802830000c92015700506260180c5c014189c064880ab8", - "0x2e00b269381d360c938157005062cc192602ae00b259201c8c0c928157005", - "0x3162055c01562052503244055c01644055883252055c0165005240325005", - "0x3170050601c192903ac644a502ca40ab802ca40a5e0601c0ab80281c0a94", - "0x4ac0a0c5603254055c0148c055883018b8028b80a420603170054e814720c", - "0x2e00a2e02908180c5c0153a051c83018b8029040a620603170050601c180c", - "0x2e00a0c6183258055c014189806031700506270192a02ae00a2b02ac4180c", - "0x325e055c01418b3064b80ab802cb65807230325a055c0165a05140325a05", - "0x14940c95015700595015620c98815700598014900c980157005974bc0e9b", - "0x4c40eb1952940b3102ae00b3102978180702ae00a0702a5018b102ae00ab1", - "0x326405062b018fc02ae00aa602ac4180c5c01552051c83018b8028300e0c", - "0x15700552815620c062e00aa9028e4180c5c0144a053103018b8028300e0c", - "0x2e00b34028a0193402ae00a0c6203266055c01418980603170050627018fc", - "0x4dc0ab802cd66c074d8326c055c01418b3064d40ab802cd26607230326805", - "0x15280c58815700558814940c7e01570057e015620c9c01570059b814900c", - "0x1c0180c5c0141807064e00eb17e2940b3802ae00b3802978180702ae00a07", - "0x4e40ab802ce40a28064e40ab802830c00c79015700506260180c5c014f405", - "0x120193c02ae00b3a9d81d360c9d8157005062cc193a02ae00b397901c8c0c", - "0x140e054a0315e055c0155e052503160055c0156005588327a055c0167805", - "0x2c0180702ae00a05029e8193d03abd60a502cf40ab802cf40a5e0601c0ab8", - "0x143a0c580157005528154e0c062e00a0c0383162059f294f4075c01c0e05", - "0x2e00aae0289c18ad02ae00a7a02ab818ae02ae00aaf0289418af02ae00ab0", - "0x2e00aab028b418ab02ae00a0c5583018b8028300e0c064fc0a0c560315805", - "0x50152055c01d58051583158055c0155405138315a055c0156205570315405", - "0x3018b8028300e0c1101682280e81d700756815600c062e00a0c038314e05", - "0x740aae060b40ab80289c0a250609c0ab8028940a1d060940ab8028a00aa7", - "0x31560c062e00a0c03830194202831580c170157005168144e0c158157005", - "0x157005058144e0c158157005110155c0c058157005530145a0c530157005", - "0x50d50055c01c5c05158300c055c015440553031442b03ae00a2b02b14182e", - "0x3170050601c183a02d10729c03ae00ea80601c5c0c062e00a0c038313a05", - "0x1000b45208f40eb8038ac0ab0062700ab802a700ab106031700503014e00c", - "0x1484055683130055c0147a055703084055c01482055783018b8028300e0c", - "0x148c05550308c055c01418ab0603170050601c180ca301418ac062c80ab8", - "0x26c0ab802a600aa6062c80ab802acc0aad062600ab8029000aae062cc0ab8", - "0x74189402ae00a4802a9c180c5c0141807061280b4724015700759015520c", - "0x23cf548482440eb803979380763830bc055c014bc0514030bc055c0152805", - "0x1d900c4d81570054d814160c48815700548815620c062e00a0c038311a8e", - "0x15960c062e00a0c03830b405a4a280ab803a2c0ac90622d18075c0153691", - "0x1580a7a0603170050601c188502d290e055c01d120566031125603ae00a8a", - "0x1478055383018b8028300e0c30016963c4001d700741015600c410157005", - "0x1940ab802a000aae061dc0ab8029ec0a25061ec0ab8029880a1d061880ab8", - "0x20c0ab802831560c062e00a0c03830194c02831580c3801570053b8144e0c", - "0x14560c380157005000144e0c328157005300155c0c000157005418145a0c", - "0x319005a731d8a075c01cca055803018b8028300e0c620169ac302ae00e70", - "0x2e00acb0289418cb02ae00ac90287418c902ae00ac702a9c180c5c0141807", - "0x300e0c0653c0a0c560319e055c0159805138319a055c0158a05570319805", - "0x319a055c015900557031a0055c01584051683184055c01418ab060317005", - "0x15600c062e00a0c03831a405a83440ab803b3c0a2b0633c0ab802b400a27", - "0x3580a1d063580ab802b180aa70603170050601c18d502d458cd303ae00ecd", - "0x1570056c8144e0c6d0157005698155c0c6c81570056c0144a0c6c0157005", - "0x1570056e8145a0c6e8157005062ac180c5c014180706032a405062b018dc", - "0xac18df02ae00ada02a9818dc02ae00ade0289c18da02ae00ad502ab818de", - "0x2e00ace68b0d0e901caa55ecd0603170050601c18e002d4d9c055c01db805", - "0x3500ab802b900ad0063900ab802b8dbe0761031c6055c015c40567831c405", - "0x3018b8028300e0c6a2300e056a01570056a015a20c46015700546015620c", - "0x31700543814e00c062e00ac3028f4180c5c015a2051e83018b802aa40a3d", - "0x399be0761031cc055c015c0056983018b8028e40a4006031700548015a40c", - "0x15700574815a20c46015700546015620c74815700573815a00c738157005", - "0xf4180c5c01552051e83018b8028e40a400603170050601c18e94601c0ae9", - "0x3a80ab802b340aa606031700548015a40c062e00a87029c0180c5c0158605", - "0x2c418ed02ae00aec02b4018ec02ae00aeb7501d840c75815700569015a60c", - "0x14800c062e00a0c03831da8c03815da055c015da056883118055c0151805", - "0x298180c5c0150e053803018b802a400ad2060317005548147a0c062e00a39", - "0x36c0ad00636c0ab802bbddc0761031de055c015880569831dc055c014ca05", - "0x300e0c782300e0578015700578015a20c46015700546015620c780157005", - "0x15a60c062e00a9002b48180c5c01552051e83018b8028e40a40060317005", - "0x15180558831e8055c015e60568031e6055c015e25603b0818f102ae00a85", - "0x2e00a3902900180c5c0141807063d1180702bd00ab802bd00ad1062300ab8", - "0x2300ab1063840ab8029680ac606031700548015a40c062e00aa9028f4180c", - "0x151c056903018b8028300e0c70a300e0570815700570815a20c460157005", - "0x23c0ab1060317005548147a0c062e00a3902900180c5c0151a056903018b8", - "0xe40a4006031700525014c40c062e00a0c03830195402831580c7a8157005", - "0x34c18f602ae00a0c55831ea055c01538055883018b802aa40a3d060317005", - "0x3e40ad1063e40ab802be00ad0063e00ab802bdd360761031ee055c015ec05", - "0x2e00aa9028f4180c5c01456051c83018b8028300e0c7cbd40e057c8157005", - "0x2e00a9d02988180c5c014180706032aa05062b018fa02ae00a3a02ac4180c", - "0x1418ab063e80ab8028300ab1060317005548147a0c062e00a2b028e4180c", - "0x1570057f015a00c7f01570057e8180ec2063f40ab802bec0ad3063ec0ab8", - "0x4000ab802ab40aa60603170050601c18ff7d01c0aff02ae00aff02b4418ff", - "0x2c4190302ae00b0202b40190202ae00b018001d840c80815700553815a60c", - "0x35818aa02ae00a0c6a832060c0381606055c01606056883018055c0141805", - "0x305a055c01418d8060940ab802831b00c1401570050635418a702ae00a0c", - "0x230180c5c014189c06031700506364180b02ae00a0c6a8305c055c01418d5", - "0x3170050601c189c4eaa0f556032a5447a5c01c0e0503b68180c5c014f405", - "0x884e3d1d2c570051c815bc0c1c815700503015ba0c03015700503015b80c", - "0x26084403d2e00a4102b80184102ae00a3a02b38183a02ae00a3a02b7c181d", - "0x38c18a902ae00aa95381dc40c51015700551014940c20015700520015160c", - "0x1da80c110157005110940ee40609c0ab80289c5a07720307a055c0147a05", - "0x29480077303130055c01530054503084055c0148405458303a055c0143a28", - "0xf4180c5c0155e052083018b80289c0a400603170050601c180cab8317007", - "0x3018b8028880a40060317005568147a0c062e00a1d028f4180c5c0155805", - "0x31700517015ce0c062e00a0b02b9c180c5c01554057383018b802ab80a3d", - "0x2e00ab102908180c5c01530052003018b802ac00a400603170051e815d20c", - "0x148c05140308c055c01418ea062c80ab802831300c062e00a4202908180c", - "0x15700559a6c0e9b0626c0ab802831660c598157005232c80e46061180ab8", - "0x25018a202ae00aa202928180c02ae00a0c02ac4184a02ae00a4802bac1848", - "0x3018b8028300e0c252a5440c5281494055c01494057603152055c0155205", - "0x155e052083018b80289c0a400603170050601c180cac0317007589080ee6", - "0x880a40060317005568147a0c062e00a1d028f4180c5c01558051e83018b8", - "0x15ce0c062e00a0b02b9c180c5c01554057383018b802ab80a3d060317005", - "0x260180c5c01530052003018b802ac00a400603170051e815d20c062e00a2e", - "0x2e00a5e4a01c8c0c2f01570052f014500c2f0157005063b4189402ae00a0c", - "0x311c055c0151e05758311e055c015229003a6c189002ae00a0c598312205", - "0x2380aec062a40ab802aa40a94062880ab802a880a4a060300ab8028300ab1", - "0x15dc0c4681570054c015dc0c062e00a0c038311ca9510314a05470157005", - "0x1d16056d83116055c01516051403116055c015188d03bbc188c02ae00ab0", - "0x1595eb8029680af1061680ab8028f40af00603170050601c188a02d6418b8", - "0x1570052b014500c3b9ecc4601e20104af5c0155e057883056a655a150e89", - "0x3112055c015120545030ca055c014ca0514030ca055c015045603bbc1856", - "0x1da80c55815700555aa80ed4062140ab802a140a0b0621c0ab802a1c0af3", - "0x1c187002d6818b8039940adb060ac0ab8028ac5c076a0314c055c0154c0b", - "0x2e00a004181dde0c00015700540015dc0c41815700544815dc0c062e00a0c", - "0x3018b8028300e0c62016b60c5c01d86056d83186055c0158605140318605", - "0x14c4051e83018b802aac0a3d0603170050601c180cae03170071e21c0ef4", - "0x880a40060317005568147a0c062e00a1d028f4180c5c01558051e83018b8", - "0x147a0c062e00a77028f4180c5c0144e052003018b802ab80a3d060317005", - "0x1c0180c5c014c0053803018b802a980a3d0603170053d8147a0c062e00a2b", - "0x31c0ab802b1c0a280631c0ab802831c20c62815700506260180c5c0150a05", - "0x3ac18cb02ae00ac86481d360c648157005062cc18c802ae00ac76281c8c0c", - "0x1552054a03144055c01544052503018055c01418055883198055c0159605", - "0x2140af50603170050601c18cc54a8818a502b300ab802b300aec062a40ab8", - "0x2e00a6002bd418c202ae00acf02bd818cf02ae00acd029e818cd4281d7005", - "0x3080ab802b080af7063480ab802b440af6063440ab802b400a7a06340c007", - "0x147a0c062e00a0c03830195d062e00ed26101df00c69015700569015ee0c", - "0xf4180c5c0143a051e83018b802ab00a3d060317005310147a0c062e00aab", - "0x3018b80289c0a40060317005570147a0c062e00a2202900180c5c0155a05", - "0x317005530147a0c062e00a7b028f4180c5c01456051e83018b8029dc0a3d", - "0x15440525031a6055c01418055883018b802a140a7006031700530014e00c", - "0x2880a4a060300ab8028300ab10603170050601c180caf01418ac063180ab8", - "0x1810aa206295f20c30015700530014160c42815700542814160c510157005", - "0x3640afb0603170050601c18da02d7db2055c01db0057d031b0d66a9e97005", - "0x1570076f015fa0c062e00add029c0180c5c015b80538031bcdd6e1e97005", - "0x147a0c062e00aac028f4180c5c015be053103018b8028300e0c67016c0df", - "0x100180c5c0155c051e83018b8028880a40060317005568147a0c062e00a1d", - "0x3018b8029ec0a3d060317005158147a0c062e00a77028f4180c5c0144e05", - "0x1570056a815620c062e00aab028f4180c5c014c4051e83018b802a980a3d", - "0x3880a28063880ab802831fc0c7001570050626018c602ae00ad60292818d3", - "0x2e00ae37201d360c720157005062cc18e302ae00ae27001c8c0c710157005", - "0x318c055c0158c0525031a6055c015a60558831cc055c015a80575831a805", - "0x3170050601c18e654b19a6a502b980ab802b980aec062a40ab802aa40a94", - "0x15b60c73815700573814500c738157005312ac0eef06031700567014c40c", - "0x15d40514031d4055c014f6a603bbc180c5c0141807063a40b61062e00ee7", - "0x1570053b8ac0eef0603170050601c18eb02d8818b803ba80adb063a80ab8", - "0x3b8180c5c0141807063b40b63062e00eec02b6c18ec02ae00aec028a018ec", - "0x3bc0adb063bc0ab802bbc0a28063bc0ab802ab9dc0777831dc055c0144e05", - "0x2e00aad7801dde0c78015700511015dc0c062e00a0c03831b605b20317007", - "0x3018b8028300e0c79816ca0c5c01de2056d831e2055c015e20514031e205", - "0x31c205b303170077a015b60c7a01570057a014500c7a0157005560740eef", - "0x1570057b016000c7b01570057a815fe0c7a8157005062ac180c5c0141807", - "0x3b018a902ae00aa902a5018d602ae00ad60292818d502ae00ad502ac418f7", - "0x260180c5c015c2058083018b8028300e0c7baa5acd552815ee055c015ee05", - "0x2e00af97c01c8c0c7c81570057c814500c7c81570050640818f802ae00a0c", - "0x31fc055c015fa0575831fa055c015f4fb03a6c18fb02ae00a0c59831f405", - "0x3f80aec062a40ab802aa40a94063580ab802b580a4a063540ab802b540ab1", - "0x2b00a3d06031700579816020c062e00a0c03831fca96b3554a057f0157005", - "0x14500c8001570050640c18ff02ae00a0c4c03018b8028740a3d060317005", - "0x16030203a6c190202ae00a0c5983202055c01600ff03918190002ae00b00", - "0x3580ab802b580a4a063540ab802b540ab1064100ab802c0c0aeb0640c0ab8", - "0x2e00a0c0383208a96b3554a0582015700582015d80c54815700554815280c", - "0x155a051e83018b8028740a3d060317005560147a0c062e00adb02c04180c", - "0x4180a28064180ab802832080c82815700506260180c5c01444052003018b8", - "0x2e00b078401d360c840157005062cc190702ae00b068281c8c0c830157005", - "0x31ac055c015ac0525031aa055c015aa055883214055c0161205758321205", - "0x3170050601c190a54b59aaa502c280ab802c280aec062a40ab802aa40a94", - "0x2e00aad028f4180c5c0143a051e83018b802ab00a3d06031700576816020c", - "0x2e00a0c4c03018b80289c0a40060317005570147a0c062e00a2202900180c", - "0x321a055c016190b03918190c02ae00b0c028a0190c02ae00a0c828321605", - "0x3540ab10643c0ab802ba00aeb063a00ab802c361c074d8321c055c01418b3", - "0x15700587815d80c54815700554815280c6b01570056b014940c6a8157005", - "0x317005560147a0c062e00aeb02c04180c5c01418070643d52d66aa940b0f", - "0x2e00aae028f4180c5c01444052003018b802ab40a3d0603170050e8147a0c", - "0x2e00a0c4c03018b8028ac0a3d0603170053b8147a0c062e00a2702900180c", - "0x3224055c016231003918191102ae00b11028a0191102ae00a0c830322005", - "0x3540ab1064540ab802c500aeb064500ab802c4a26074d83226055c01418b3", - "0x1570058a815d80c54815700554815280c6b01570056b014940c6a8157005", - "0x317005560147a0c062e00ae902c04180c5c01418070645552d66aa940b15", - "0x2e00aae028f4180c5c01444052003018b802ab40a3d0603170050e8147a0c", - "0x14f6051e83018b8028ac0a3d0603170053b8147a0c062e00a2702900180c", - "0x45c0a280645c0ab8028320e0c8b015700506260180c5c0154c051e83018b8", - "0x2e00b188c81d360c8c8157005062cc191802ae00b178b01c8c0c8b8157005", - "0x31ac055c015ac0525031aa055c015aa055883236055c0163405758323405", - "0x3170050601c191b54b59aaa502c6c0ab802c6c0aec062a40ab802aa40a94", - "0x2e00a2202900180c5c0155a051e83018b8028740a3d060317005560147a0c", - "0x1456051e83018b8029dc0a3d06031700513814800c062e00aae028f4180c", - "0x2ac0a3d060317005310147a0c062e00aa6028f4180c5c014f6051e83018b8", - "0x3580ab802b580a4a063540ab802b540ab1064700ab802b680aeb060317005", - "0x2e00a0c0383238a96b3554a058e01570058e015d80c54815700554815280c", - "0x1558051e83018b8029880a3d060317005558147a0c062e00ac402c04180c", - "0x2b80a3d06031700511014800c062e00aad028f4180c5c0143a051e83018b8", - "0x147a0c062e00a2b028f4180c5c014ee051e83018b80289c0a40060317005", - "0x348180c5c0150a053803018b8029800a70060317005530147a0c062e00a7b", - "0x323c055c0141908064740ab802831300c062e00a8702b48180c5c0147805", - "0x4800e9b064800ab802831660c8f81570058f4740e46064780ab802c780a28", - "0x2e00aa202928180c02ae00a0c02ac4192102ae00a6702bac186702ae00b1f", - "0x300e0c90aa5440c5281642055c01642057603152055c01552054a0314405", - "0x147a0c062e00a62028f4180c5c01556051e83018b8029c00b01060317005", - "0xf4180c5c01444052003018b802ab40a3d0603170050e8147a0c062e00aac", - "0x3018b8028ac0a3d0603170053b8147a0c062e00a2702900180c5c0155c05", - "0x31700542814e00c062e00a60029c0180c5c0154c051e83018b8029ec0a3d", - "0x2e00a8902900180c5c01500052003018b802a1c0ad20603170051e015a40c", - "0x4880e46064900ab802c900a28064900ab802832120c91015700506260180c", - "0x2e00b2702bac192702ae00b259301d360c930157005062cc192502ae00b24", - "0x3152055c01552054a03144055c01544052503018055c0141805588325005", - "0x3018b802a280b010603170050601c192854a8818a502ca00ab802ca00aec", - "0x3170050e8147a0c062e00aac028f4180c5c0155e052083018b80289c0a40", - "0x2e00aaa02b9c180c5c0155c051e83018b8028880a40060317005568147a0c", - "0x2e00a0c4c03018b8028f40ae906031700517015ce0c062e00a0b02b9c180c", - "0x3258055c016552903918192a02ae00b2a028a0192a02ae00a0c850325205", - "0x300ab1064bc0ab802cb80aeb064b80ab802cb25a074d8325a055c01418b3", - "0x15700597815d80c54815700554815280c51015700551014940c060157005", - "0x31700512816160c062e00a2802b9c180c5c0141807064bd52a2062940b2f", - "0x2e00ab102908180c5c01558051e83018b802abc0a4106031700552814840c", - "0x1554057383018b802ab80a3d06031700558014800c062e00aad028f4180c", - "0x29c0b0c06031700516816160c062e00a2e02b9c180c5c01416057383018b8", - "0x3f00ab802cc40aeb064c40ab802a7260074d83260055c01418b3060317005", - "0x15d80c4e81570054e815280c54015700554014940c06015700506015620c", - "0x1e80eb80381c0ab00601c0ab8028140a7a063f13aa8062940afc02ae00afc", - "0x315e055c014f4055703160055c0154a055783018b8028300e0c58816cea5", - "0x315a055c01418ab0603170050601c180cb401418ac062b80ab802ac00aad", - "0x2bc0ac5062b80ab802ab00aad062bc0ab802ac40aae062b00ab802ab40aaa", - "0x300e0c53816d2a902ae00eae02aa418aa02ae00aab02a9818ab5781d7005", - "0xa00ab8028a00a28060a00ab8028740a1d060740ab802aa40aa7060317005", - "0x3018b802aa80a700603170050601c182702da84a2203ae00e280601e1a0c", - "0x15ee0c170940eb8028940ae8060ad5e075c0155e05628305a055c014190e", - "0x3018b8028300e0c51016d60b5301d7007170b4562252c3c182d02ae00a2d", - "0x3dc189d1281d700512815d00c54015700503015ec0c032bc0eb802abc0ac5", - "0x1ed8394e01d70074eaa14c7a8803016055c01416055703150055c0155005", - "0x141807061080b6d201040eb8038e44aaf4e2961e0c062e00a0c038307a3a", - "0x308c055c01480055303164055c01530058883130055c01416055303018b8", - "0x16280c20815700520815620c4d815700559816260c598157005591180f12", - "0x2e00a0c4c03018b80282c0a390603170050601c189b2081c0a9b02ae00a9b", - "0x3128055c014944803918184a02ae00a4a028a0184a02ae00a0c8a8309005", - "0x1080ab1062400ab802a440b16062440ab802a50bc074d830bc055c01418b3", - "0x147a058b83018b8028300e0c481080e0548015700548016280c210157005", - "0x141898060317005128162e0c062e00aaf028e4180c5c01416051c83018b8", - "0x2340ab802a391e07230311c055c0151c05140311c055c01419180623c0ab8", - "0x15620c450157005458162c0c45815700546a300e9b062300ab802831660c", - "0x940b170603170050601c188a1d01c0a8a02ae00a8a02c50183a02ae00a3a", - "0x14500c2b015700506454185a02ae00a0c4c03018b802abc0a39060317005", - "0x15128703a6c188702ae00a0c5983112055c014ac5a03918185602ae00a56", - "0x2080ab802a080b14062880ab802a880ab1062080ab802a140b16062140ab8", - "0x16320c400157005062ac180c5c0155e051c83018b8028300e0c412880e05", - "0x144e0558830c4055c014c00589830c0055c01478aa03c48183c02ae00a80", - "0x2e00aa702988180c5c0141807061884e07029880ab8029880b140609c0ab8", - "0x2a80f12061dc0ab8029ec0b19061ec0ab802831560c062e00aaf028e4180c", - "0x2e00a7002c50180c02ae00a0c02ac4187002ae00a6502c4c186502ae00a77", - "0x315eb003db962a503ae00e050601c0a0c062e00a0c4e030e00c03814e005", - "0x2940ab802a940ab10603170050629418ae02ae00a07029e8180c5c0141807", - "0x3154055c01558055783018b8028300e0c55816deac5681d700757015600c", - "0x3170050601c180cb801418ac0629c0ab802aa80aad062a40ab802ab40aae", - "0xa00aad062a40ab802aac0aae060a00ab8028740aaa060740ab802831560c", - "0x1418070609c0b7112815700753815520c110157005548154c0c538157005", - "0x305a055c0145a051403056055c014f4053d0305a055c0144a055383018b8", - "0x2b818a202ae00aa602abc180c5c01418070602c0b72530b80eb8038ac0ab0", - "0x3018b8028300e0c065cc0a0c5603150055c0154405568300c055c0145c05", - "0x153805568300c055c01416055703138055c0153a05550313a055c01418ab", - "0x1570051c8154e0c062e00a0c038307405ba0e40ab803aa00aa9062a00ab8", - "0xa0184202ae00a3d02874184002ae00a2d02874184102ae00a0602a98183d", - "0x2600adb062600ab802a600a28062600ab80290880077783084055c0148405", - "0x314a055c0154a055883018b802831380c062e00a0c038316405ba8317007", - "0x2954af9061040ab8029040a0b060880ab8028880a0b062c40ab802ac40a4a", - "0x3018b802831380c062e00a0c0383136b3231e80a9b59918f4b80290444b1", - "0x12882223d46c184a02ae00a4802c68184802ae00a0c5583018b802ac80b01", - "0x15700558814940c52815700552815620c2f01570054a016380c4a0157005", - "0x3018b802831380c062e00a0c03830bcb1529e80a5e02ae00a5e02c7418b1", - "0x31700503014720c062e00a22029c0180c5c0145a051e83018b8028e80a62", - "0x24122072303120055c01520051403120055c014191e062440ab802831300c", - "0x157005468163e0c46815700547a380e9b062380ab802831660c478157005", - "0x1e80a8c02ae00a8c02c7418b102ae00ab10292818a502ae00aa502ac4188c", - "0x2e00a0c5583018b80289c0a6206031700506270180c5c01418070623162a5", - "0x1570052d016380c2d0157005451e8447a8d83114055c0151605900311605", - "0x1e80a5602ae00a5602c7418b102ae00ab10292818a502ae00aa502ac41856", - "0x14189806031700503814e00c062e00a7a029c0180c5c01418070615962a5", - "0x2140ab802a1d1207230310e055c0150e05140310e055c0141860062240ab8", - "0x15620c1e0157005400163e0c40015700542a080e9b062080ab802831660c", - "0x2c478af581e80a3c02ae00a3c02c7418af02ae00aaf0292818b002ae00ab0", - "0x20c18abbb014187b0601c4e0c03830f407028310446418314a272320c18a5", - "0x1eeeac56ab95eb058a94f407028311246418314a0603018783a1c8e50e46", - "0x2f27a0381418a641830f42713a0c18a5bc01418940601c4e0c" - ], - "sierra_program_debug_info": { - "type_names": [], - "libfunc_names": [], - "user_func_names": [] - }, - "contract_class_version": "0.1.0", - "entry_points_by_type": { - "EXTERNAL": [ - { - "selector": "0x3c118a68e16e12e97ed25cb4901c12f4d3162818669cc44c391d8049924c14", - "function_idx": 0 - } - ], - "L1_HANDLER": [], - "CONSTRUCTOR": [] - }, - "abi": [ - { - "type": "struct", - "name": "core::array::Span::", - "members": [ - { - "name": "snapshot", - "type": "@core::array::Array::" - } - ] - }, - { - "type": "struct", - "name": "core::starknet::info::TxInfo", - "members": [ - { - "name": "version", - "type": "core::felt252" - }, - { - "name": "account_contract_address", - "type": "core::starknet::contract_address::ContractAddress" - }, - { - "name": "max_fee", - "type": "core::integer::u128" - }, - { - "name": "signature", - "type": "core::array::Span::" - }, - { - "name": "transaction_hash", - "type": "core::felt252" - }, - { - "name": "chain_id", - "type": "core::felt252" - }, - { - "name": "nonce", - "type": "core::felt252" - } - ] - }, - { - "type": "function", - "name": "test_get_execution_info", - "inputs": [ - { - "name": "expected_block_number", - "type": "core::integer::u64" - }, - { - "name": "expected_block_timestamp", - "type": "core::integer::u64" - }, - { - "name": "expected_sequencer_address", - "type": "core::starknet::contract_address::ContractAddress" - }, - { - "name": "expected_tx_info", - "type": "core::starknet::info::TxInfo" - }, - { - "name": "expected_caller_address", - "type": "core::felt252" - }, - { - "name": "expected_contract_address", - "type": "core::felt252" - }, - { - "name": "expected_entry_point_selector", - "type": "core::felt252" - } - ], - "outputs": [], - "state_mutability": "view" - }, - { - "type": "event", - "name": "test_contract_execution_info_v1::test_contract_execution_info_v1::TestContract::Event", - "kind": "enum", - "variants": [] - } - ] -} \ No newline at end of file diff --git a/crates/blockifier/feature_contracts/cairo_native/test_contract.cairo b/crates/blockifier/feature_contracts/cairo_native/test_contract.cairo deleted file mode 100644 index 5b1994aa2a8..00000000000 --- a/crates/blockifier/feature_contracts/cairo_native/test_contract.cairo +++ /dev/null @@ -1,648 +0,0 @@ -#[starknet::contract] -mod TestContract { - use box::BoxTrait; - use core::sha256::{compute_sha256_u32_array, sha256_state_handle_init, SHA256_INITIAL_STATE}; - use dict::Felt252DictTrait; - use ec::EcPointTrait; - use starknet::ClassHash; - use starknet::ContractAddress; - use starknet::get_execution_info; - use starknet::StorageAddress; - use array::ArrayTrait; - use clone::Clone; - use core::bytes_31::POW_2_128; - use core::integer::bitwise; - use traits::Into; - use traits::TryInto; - use starknet::{ - class_hash_try_from_felt252, contract_address_try_from_felt252, - eth_address::U256IntoEthAddress, EthAddress, secp256_trait::{Signature, is_valid_signature}, - secp256r1::{Secp256r1Point, Secp256r1Impl}, eth_signature::verify_eth_signature, - info::{BlockInfo, SyscallResultTrait}, info::v2::{ExecutionInfo, TxInfo, ResourceBounds,}, - syscalls - }; - use core::circuit::{ - CircuitElement, CircuitInput, circuit_add, circuit_sub, circuit_mul, circuit_inverse, - EvalCircuitResult, EvalCircuitTrait, u384, CircuitOutputsTrait, - CircuitModulus, CircuitInputs, AddInputResultTrait - }; - - #[storage] - struct Storage { - my_storage_var: felt252, - two_counters: starknet::storage::Map, - ec_point: (felt252, felt252), - } - - #[constructor] - fn constructor(ref self: ContractState, arg1: felt252, arg2: felt252) -> felt252 { - self.my_storage_var.write(arg1 + arg2); - arg1 - } - - #[external(v0)] - fn test_storage_read_write( - self: @ContractState, address: StorageAddress, value: felt252 - ) -> felt252 { - let address_domain = 0; - syscalls::storage_write_syscall(address_domain, address, value).unwrap_syscall(); - syscalls::storage_read_syscall(address_domain, address).unwrap_syscall() - } - - #[external(v0)] - fn test_count_actual_storage_changes(self: @ContractState) { - let storage_address = 15.try_into().unwrap(); - let address_domain = 0; - syscalls::storage_write_syscall(address_domain, storage_address, 0).unwrap_syscall(); - syscalls::storage_write_syscall(address_domain, storage_address, 1).unwrap_syscall(); - } - - #[external(v0)] - #[raw_output] - fn test_call_contract( - self: @ContractState, - contract_address: ContractAddress, - entry_point_selector: felt252, - calldata: Array:: - ) -> Span:: { - syscalls::call_contract_syscall(contract_address, entry_point_selector, calldata.span()) - .unwrap_syscall() - .snapshot - .span() - } - - #[external(v0)] - fn test_call_two_contracts( - self: @ContractState, - contract_address_0: ContractAddress, - entry_point_selector_0: felt252, - calldata_0: Array::, - contract_address_1: ContractAddress, - entry_point_selector_1: felt252, - calldata_1: Array::, - ) -> Span:: { - let res_0 = syscalls::call_contract_syscall( - contract_address_0, - entry_point_selector_0, - calldata_0.span(), - ) - .unwrap_syscall(); - let res_1 = syscalls::call_contract_syscall( - contract_address_1, - entry_point_selector_1, - calldata_1.span(), - ) - .unwrap_syscall(); - let mut res: Array:: = Default::default(); - res.append_span(res_0.snapshot.span()); - res.append_span(res_1.snapshot.span()); - res.span() - } - - #[external(v0)] - fn test_revert_helper(ref self: ContractState, class_hash: ClassHash) { - let dummy_span = array![0].span(); - syscalls::emit_event_syscall(dummy_span, dummy_span).unwrap_syscall(); - syscalls::replace_class_syscall(class_hash).unwrap_syscall(); - syscalls::send_message_to_l1_syscall(17.try_into().unwrap(), dummy_span).unwrap_syscall(); - self.my_storage_var.write(17); - panic(array!['test_revert_helper']); - } - - #[external(v0)] - fn test_emit_events( - self: @ContractState, events_number: u64, keys: Array::, data: Array:: - ) { - let mut c = 0_u64; - loop { - if c == events_number { - break; - } - syscalls::emit_event_syscall(keys.span(), data.span()).unwrap_syscall(); - c += 1; - }; - } - - #[external(v0)] - fn test_get_class_hash_at( - self: @ContractState, address: ContractAddress, expected_class_hash: ClassHash - ) { - let class_hash = syscalls::get_class_hash_at_syscall(address).unwrap_syscall(); - assert(class_hash == expected_class_hash, 'WRONG_CLASS_HASH'); - } - - #[external(v0)] - fn test_get_block_hash(self: @ContractState, block_number: u64) -> felt252 { - syscalls::get_block_hash_syscall(block_number).unwrap_syscall() - } - - #[external(v0)] - fn test_get_execution_info( - self: @ContractState, - expected_block_info: BlockInfo, - expected_tx_info: TxInfo, - // Expected call info. - expected_caller_address: felt252, - expected_contract_address: felt252, - expected_entry_point_selector: felt252, - ) { - let execution_info = starknet::get_execution_info().unbox(); - let block_info = execution_info.block_info.unbox(); - assert(block_info == expected_block_info, 'BLOCK_INFO_MISMATCH'); - - let tx_info = execution_info.tx_info.unbox(); - assert(tx_info == expected_tx_info, 'TX_INFO_MISMATCH'); - - assert(execution_info.caller_address.into() == expected_caller_address, 'CALLER_MISMATCH'); - assert( - execution_info.contract_address.into() == expected_contract_address, 'CONTRACT_MISMATCH' - ); - assert( - execution_info.entry_point_selector == expected_entry_point_selector, - 'SELECTOR_MISMATCH' - ); - } - - #[external(v0)] - #[raw_output] - fn test_library_call( - self: @ContractState, - class_hash: ClassHash, - function_selector: felt252, - calldata: Array - ) -> Span:: { - starknet::library_call_syscall(class_hash, function_selector, calldata.span()) - .unwrap_syscall() - .snapshot - .span() - } - - #[external(v0)] - #[raw_output] - fn test_nested_library_call( - self: @ContractState, - class_hash: ClassHash, - lib_selector: felt252, - nested_selector: felt252, - a: felt252, - b: felt252 - ) -> Span:: { - let mut nested_library_calldata: Array:: = Default::default(); - nested_library_calldata.append(class_hash.into()); - nested_library_calldata.append(nested_selector); - nested_library_calldata.append(2); - nested_library_calldata.append(a + 1); - nested_library_calldata.append(b + 1); - let _res = starknet::library_call_syscall( - class_hash, lib_selector, nested_library_calldata.span(), - ) - .unwrap_syscall(); - - let mut calldata: Array:: = Default::default(); - calldata.append(a); - calldata.append(b); - starknet::library_call_syscall(class_hash, nested_selector, calldata.span()) - .unwrap_syscall() - } - - #[external(v0)] - fn test_replace_class(self: @ContractState, class_hash: ClassHash) { - syscalls::replace_class_syscall(class_hash).unwrap_syscall(); - } - - #[external(v0)] - fn test_send_message_to_l1( - self: @ContractState, to_address: felt252, payload: Array:: - ) { - starknet::send_message_to_l1_syscall(to_address, payload.span()).unwrap_syscall(); - } - - /// An external method that requires the `segment_arena` builtin. - #[external(v0)] - fn segment_arena_builtin(self: @ContractState) { - let x = felt252_dict_new::(); - x.squash(); - } - - #[l1_handler] - fn l1_handle(self: @ContractState, from_address: felt252, arg: felt252) -> felt252 { - arg - } - - #[l1_handler] - fn l1_handler_set_value( - self: @ContractState, from_address: felt252, key: StorageAddress, value: felt252 - ) -> felt252 { - let address_domain = 0; - syscalls::storage_write_syscall(address_domain, key, value).unwrap_syscall(); - value - } - - #[external(v0)] - fn test_deploy( - self: @ContractState, - class_hash: ClassHash, - contract_address_salt: felt252, - calldata: Array::, - deploy_from_zero: bool, - ) { - syscalls::deploy_syscall( - class_hash, contract_address_salt, calldata.span(), deploy_from_zero - ) - .unwrap_syscall(); - } - - - #[external(v0)] - fn test_keccak(ref self: ContractState) { - let mut input: Array:: = Default::default(); - input.append(u256 { low: 1, high: 0 }); - - let res = keccak::keccak_u256s_le_inputs(input.span()); - assert(res.low == 0x587f7cc3722e9654ea3963d5fe8c0748, 'Wrong hash value'); - assert(res.high == 0xa5963aa610cb75ba273817bce5f8c48f, 'Wrong hash value'); - - let mut input: Array:: = Default::default(); - input.append(1_u64); - match syscalls::keccak_syscall(input.span()) { - Result::Ok(_) => panic_with_felt252('Should fail'), - Result::Err(revert_reason) => assert( - *revert_reason.at(0) == 'Invalid input length', 'Wrong error msg' - ), - } - } - - #[external(v0)] - fn test_sha256(ref self: ContractState) { - let mut input: Array:: = Default::default(); - input.append('aaaa'); - - // Test the sha256 syscall computation of the string 'aaaa'. - let [res, _, _, _, _, _, _, _,] = compute_sha256_u32_array(input, 0, 0); - assert(res == 0x61be55a8, 'Wrong hash value'); - } - - #[external(v0)] - fn test_secp256k1(ref self: ContractState) { - // Test a point not on the curve. - assert( - starknet::secp256k1::secp256k1_new_syscall(x: 0, y: 1).unwrap_syscall().is_none(), - 'Should be none' - ); - - let secp256k1_prime = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f; - match starknet::secp256k1::secp256k1_new_syscall(x: secp256k1_prime, y: 1) { - Result::Ok(_) => panic_with_felt252('Should fail'), - Result::Err(revert_reason) => assert( - *revert_reason.at(0) == 'Invalid argument', 'Wrong error msg' - ), - } - - // Test a point on the curve. - let x = 0xF728B4FA42485E3A0A5D2F346BAA9455E3E70682C2094CAC629F6FBED82C07CD; - let y = 0x8E182CA967F38E1BD6A49583F43F187608E031AB54FC0C4A8F0DC94FAD0D0611; - let p0 = starknet::secp256k1::secp256k1_new_syscall(x, y).unwrap_syscall().unwrap(); - - let (x_coord, y_coord) = starknet::secp256k1::secp256k1_get_xy_syscall(p0).unwrap_syscall(); - assert(x_coord == x && y_coord == y, 'Unexpected coordinates'); - - let (msg_hash, signature, _expected_public_key_x, _expected_public_key_y, eth_address) = - get_message_and_secp256k1_signature(); - verify_eth_signature(:msg_hash, :signature, :eth_address); - } - - /// Returns a golden valid message hash and its signature, for testing. - fn get_message_and_secp256k1_signature() -> (u256, Signature, u256, u256, EthAddress) { - let msg_hash = 0xe888fbb4cf9ae6254f19ba12e6d9af54788f195a6f509ca3e934f78d7a71dd85; - let r = 0x4c8e4fbc1fbb1dece52185e532812c4f7a5f81cf3ee10044320a0d03b62d3e9a; - let s = 0x4ac5e5c0c0e8a4871583cc131f35fb49c2b7f60e6a8b84965830658f08f7410c; - - let (public_key_x, public_key_y) = ( - 0xa9a02d48081294b9bb0d8740d70d3607feb20876964d432846d9b9100b91eefd, - 0x18b410b5523a1431024a6ab766c89fa5d062744c75e49efb9925bf8025a7c09e - ); - - let eth_address = 0x767410c1bb448978bd42b984d7de5970bcaf5c43_u256.into(); - - (msg_hash, Signature { r, s, y_parity: true }, public_key_x, public_key_y, eth_address) - } - - - #[external(v0)] - fn test_secp256r1(ref self: ContractState) { - // Test a point not on the curve. - assert( - starknet::secp256r1::secp256r1_new_syscall(x: 0, y: 1).unwrap_syscall().is_none(), - 'Should be none' - ); - - let secp256r1_prime = 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff; - match starknet::secp256r1::secp256r1_new_syscall(x: secp256r1_prime, y: 1) { - Result::Ok(_) => panic_with_felt252('Should fail'), - Result::Err(revert_reason) => assert( - *revert_reason.at(0) == 'Invalid argument', 'Wrong error msg' - ), - } - - // Test a point on the curve. - let x = 0x502A43CE77C6F5C736A82F847FA95F8C2D483FE223B12B91047D83258A958B0F; - let y = 0xDB0A2E6710C71BA80AFEB3ABDF69D306CE729C7704F4DDF2EAAF0B76209FE1B0; - let p0 = starknet::secp256r1::secp256r1_new_syscall(x, y).unwrap_syscall().unwrap(); - - let (x_coord, y_coord) = starknet::secp256r1::secp256r1_get_xy_syscall(p0).unwrap_syscall(); - assert(x_coord == x && y_coord == y, 'Unexpected coordinates'); - - let (msg_hash, signature, expected_public_key_x, expected_public_key_y, _eth_address) = - get_message_and_secp256r1_signature(); - let public_key = Secp256r1Impl::secp256_ec_new_syscall( - expected_public_key_x, expected_public_key_y - ) - .unwrap_syscall() - .unwrap(); - is_valid_signature::(msg_hash, signature.r, signature.s, public_key); - } - - - /// Returns a golden valid message hash and its signature, for testing. - fn get_message_and_secp256r1_signature() -> (u256, Signature, u256, u256, EthAddress) { - let msg_hash = 0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855; - let r = 0xb292a619339f6e567a305c951c0dcbcc42d16e47f219f9e98e76e09d8770b34a; - let s = 0x177e60492c5a8242f76f07bfe3661bde59ec2a17ce5bd2dab2abebdf89a62e2; - - let (public_key_x, public_key_y) = ( - 0x04aaec73635726f213fb8a9e64da3b8632e41495a944d0045b522eba7240fad5, - 0x0087d9315798aaa3a5ba01775787ced05eaaf7b4e09fc81d6d1aa546e8365d525d - ); - let eth_address = 0x492882426e1cda979008bfaf874ff796eb3bb1c0_u256.into(); - - (msg_hash, Signature { r, s, y_parity: true }, public_key_x, public_key_y, eth_address) - } - - impl ResourceBoundsPartialEq of PartialEq { - #[inline(always)] - fn eq(lhs: @ResourceBounds, rhs: @ResourceBounds) -> bool { - (*lhs.resource == *rhs.resource) - && (*lhs.max_amount == *rhs.max_amount) - && (*lhs.max_price_per_unit == *rhs.max_price_per_unit) - } - #[inline(always)] - fn ne(lhs: @ResourceBounds, rhs: @ResourceBounds) -> bool { - !(*lhs == *rhs) - } - } - - impl TxInfoPartialEq of PartialEq { - #[inline(always)] - fn eq(lhs: @TxInfo, rhs: @TxInfo) -> bool { - (*lhs.version == *rhs.version) - && (*lhs.account_contract_address == *rhs.account_contract_address) - && (*lhs.max_fee == *rhs.max_fee) - && (*lhs.signature == *rhs.signature) - && (*lhs.transaction_hash == *rhs.transaction_hash) - && (*lhs.chain_id == *rhs.chain_id) - && (*lhs.nonce == *rhs.nonce) - && (*lhs.resource_bounds == *rhs.resource_bounds) - && (*lhs.tip == *rhs.tip) - && (*lhs.paymaster_data == *rhs.paymaster_data) - && (*lhs.nonce_data_availability_mode == *rhs.nonce_data_availability_mode) - && (*lhs.fee_data_availability_mode == *rhs.fee_data_availability_mode) - && (*lhs.account_deployment_data == *rhs.account_deployment_data) - } - #[inline(always)] - fn ne(lhs: @TxInfo, rhs: @TxInfo) -> bool { - !(*lhs == *rhs) - } - } - - impl BlockInfoPartialEq of PartialEq { - #[inline(always)] - fn eq(lhs: @BlockInfo, rhs: @BlockInfo) -> bool { - (*lhs.block_number == *rhs.block_number) - && (*lhs.block_timestamp == *rhs.block_timestamp) - && (*lhs.sequencer_address == *rhs.sequencer_address) - } - #[inline(always)] - fn ne(lhs: @BlockInfo, rhs: @BlockInfo) -> bool { - !(*lhs == *rhs) - } - } - - #[external(v0)] - fn assert_eq(ref self: ContractState, x: felt252, y: felt252) -> felt252 { - assert(x == y, 'x != y'); - 'success' - } - - #[external(v0)] - fn invoke_call_chain(ref self: ContractState, mut call_chain: Array::,) -> felt252 { - // If the chain is too short, fail with division by zero. - let len = call_chain.len(); - if len < 3 { - return (1_u8 / 0_u8).into(); - } - - // Pop the parameters for the next call in the chain. - let contract_id = call_chain.pop_front().unwrap(); - let function_selector = call_chain.pop_front().unwrap(); - let call_type = call_chain.pop_front().unwrap(); - - // Choose call type according to the following options: - // 0 - call contract syscall. 1 - library call syscall. other - regular inner call. - // The remaining items of the call_chain array are passed on as calldata. - if call_type == 0 { - let contract_address = contract_address_try_from_felt252(contract_id).unwrap(); - syscalls::call_contract_syscall(contract_address, function_selector, call_chain.span()) - .unwrap_syscall(); - } else if call_type == 1 { - let class_hash = class_hash_try_from_felt252(contract_id).unwrap(); - syscalls::library_call_syscall(class_hash, function_selector, call_chain.span()) - .unwrap_syscall(); - } else { - let invoke_call_chain_selector: felt252 = - 0x0062c83572d28cb834a3de3c1e94977a4191469a4a8c26d1d7bc55305e640ed5; - let fail_selector: felt252 = - 0x032564d7e0fe091d49b4c20f4632191e4ed6986bf993849879abfef9465def25; - if function_selector == invoke_call_chain_selector { - return invoke_call_chain(ref self, call_chain); - } - if function_selector == fail_selector { - fail(ref self); - } - } - return 0; - } - - #[external(v0)] - fn fail(ref self: ContractState) { - panic_with_felt252('fail'); - } - - #[external(v0)] - fn recursive_fail(ref self: ContractState, depth: felt252) { - if depth == 0 { - panic_with_felt252('recursive_fail'); - } - recursive_fail(ref self, depth - 1) - } - - #[external(v0)] - fn recurse(ref self: ContractState, depth: felt252) { - if depth == 0 { - return; - } - recurse(ref self, depth - 1) - } - - #[external(v0)] - fn recursive_syscall( - ref self: ContractState, - contract_address: ContractAddress, - function_selector: felt252, - depth: felt252, - ) { - if depth == 0 { - return; - } - let calldata: Array:: = array![ - contract_address.into(), function_selector, depth - 1 - ]; - syscalls::call_contract_syscall(contract_address, function_selector, calldata.span()) - .unwrap_syscall(); - return; - } - - #[derive(Drop, Serde)] - struct IndexAndValues { - index: felt252, - values: (u128, u128), - } - - #[starknet::interface] - trait MyContract { - fn xor_counters(ref self: TContractState, index_and_x: IndexAndValues); - } - - // Advances the 'two_counters' storage variable by 'diff'. - #[external(v0)] - fn advance_counter(ref self: ContractState, index: felt252, diff_0: felt252, diff_1: felt252) { - let val = self.two_counters.read(index); - let (val_0, val_1) = val; - self.two_counters.write(index, (val_0 + diff_0, val_1 + diff_1)); - } - - #[external(v0)] - fn xor_counters(ref self: ContractState, index_and_x: IndexAndValues) { - let index = index_and_x.index; - let (val_0, val_1) = index_and_x.values; - let counters = self.two_counters.read(index); - let (counter_0, counter_1) = counters; - let counter_0: u128 = counter_0.try_into().unwrap(); - let counter_1: u128 = counter_1.try_into().unwrap(); - let res_0: felt252 = (counter_0 ^ val_0).into(); - let res_1: felt252 = (counter_1 ^ val_1).into(); - self.two_counters.write(index, (res_0, res_1)); - } - - #[external(v0)] - fn call_xor_counters( - ref self: ContractState, address: ContractAddress, index_and_x: IndexAndValues - ) { - MyContractDispatcher { contract_address: address }.xor_counters(index_and_x); - } - - #[external(v0)] - fn test_ec_op(ref self: ContractState) { - let p = EcPointTrait::new( - 0x654fd7e67a123dd13868093b3b7777f1ffef596c2e324f25ceaf9146698482c, - 0x4fad269cbf860980e38768fe9cb6b0b9ab03ee3fe84cfde2eccce597c874fd8 - ) - .unwrap(); - let q = EcPointTrait::new( - 0x3dbce56de34e1cfe252ead5a1f14fd261d520d343ff6b7652174e62976ef44d, - 0x4b5810004d9272776dec83ecc20c19353453b956e594188890b48467cb53c19 - ) - .unwrap(); - let m: felt252 = 0x6d232c016ef1b12aec4b7f88cc0b3ab662be3b7dd7adbce5209fcfdbd42a504; - let res = q.mul(m) + p; - let res_nz = res.try_into().unwrap(); - self.ec_point.write(res_nz.coordinates()); - } - - #[external(v0)] - fn add_signature_to_counters(ref self: ContractState, index: felt252) { - let signature = get_execution_info().unbox().tx_info.unbox().signature; - let val = self.two_counters.read(index); - let (val_0, val_1) = val; - self.two_counters.write(index, (val_0 + *signature.at(0), val_1 + *signature.at(1))); - } - - #[external(v0)] - fn send_message(self: @ContractState, to_address: felt252) { - let mut payload = ArrayTrait::::new(); - payload.append(12); - payload.append(34); - starknet::send_message_to_l1_syscall(to_address, payload.span()).unwrap_syscall(); - } - - #[external(v0)] - fn test_circuit(ref self: ContractState) { - let in1 = CircuitElement::> {}; - let in2 = CircuitElement::> {}; - let add = circuit_add(in1, in2); - let inv = circuit_inverse(add); - let sub = circuit_sub(inv, in2); - let mul = circuit_mul(inv, sub); - - let modulus = TryInto::<_, CircuitModulus>::try_into([7, 0, 0, 0]).unwrap(); - let outputs = - (mul,).new_inputs().next([3, 0, 0, 0]).next([6, 0, 0, 0]).done().eval(modulus).unwrap(); - - assert!(outputs.get_output(mul) == u384 { limb0: 6, limb1: 0, limb2: 0, limb3: 0 }); - } - - // Add drop for these objects as they only have PanicDestruct. - impl AddInputResultDrop of Drop>; - impl CircuitDataDrop of Drop>; - impl CircuitInputAccumulatorDrop of Drop>; - - #[external(v0)] - fn test_rc96_holes(ref self: ContractState) { - test_rc96_holes_helper(); - test_rc96_holes_helper(); - } - - #[inline(never)] - fn test_rc96_holes_helper() { - let in1 = CircuitElement::> {}; - (in1,).new_inputs().next([3, 0, 0, 0]); - } - - #[external(v0)] - fn test_call_contract_revert( - ref self: ContractState, - contract_address: ContractAddress, - entry_point_selector: felt252, - calldata: Array:: - ) { - match syscalls::call_contract_syscall( - contract_address, entry_point_selector, calldata.span()) - { - Result::Ok(_) => panic!("Expected revert"), - Result::Err(errors) => { - let mut error_span = errors.span(); - assert( - *error_span.pop_back().unwrap() == 'ENTRYPOINT_FAILED', - 'Unexpected error', - ); - let inner_error = *error_span.pop_back().unwrap(); - if entry_point_selector == selector!("bad_selector") { - assert(inner_error == 'ENTRYPOINT_NOT_FOUND', 'Unexpected error'); - } else { - assert(inner_error == 'test_revert_helper', 'Unexpected error'); - } - }, - }; - // TODO(Yoni, 1/12/2024): test replace class once get_class_hash_at syscall is supported. - assert(self.my_storage_var.read() == 0, 'values should not change.'); - } -} diff --git a/crates/blockifier/resources/versioned_constants_0_13_0.json b/crates/blockifier/resources/blockifier_versioned_constants_0_13_0.json similarity index 58% rename from crates/blockifier/resources/versioned_constants_0_13_0.json rename to crates/blockifier/resources/blockifier_versioned_constants_0_13_0.json index 6f52d6cb438..e56ed25f3ed 100644 --- a/crates/blockifier/resources/versioned_constants_0_13_0.json +++ b/crates/blockifier/resources/blockifier_versioned_constants_0_13_0.json @@ -8,6 +8,7 @@ "segment_arena_cells": true, "disable_cairo0_redeclaration": false, "enable_stateful_compression": false, + "comprehensive_state_diff": false, "allocation_cost": { "blob_cost": { "l1_gas": 0, @@ -69,17 +70,33 @@ "validate_deploy_entry_point_selector": "0x36fcbf06cd96843058359e1a75928beacfac10727dab22a3972f0af8aa92895", "transfer_entry_point_selector": "0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e", "default_entry_point_selector": 0, - "block_hash_contract_address": 1, + "validate_max_sierra_gas": 10000000000, + "execute_max_sierra_gas": 10000000000, "stored_block_hash_buffer": 10, "step_gas_cost": 100, - "range_check_gas_cost": 70, - "pedersen_gas_cost": 0, - "bitwise_builtin_gas_cost": 0, - "ecop_gas_cost": 0, - "poseidon_gas_cost": 0, - "add_mod_gas_cost": 0, - "mul_mod_gas_cost": 0, + "builtin_gas_costs": { + "range_check": 70, + "range_check96": 0, + "keccak": 0, + "pedersen": 0, + "bitwise": 0, + "ecop": 0, + "poseidon": 0, + "add_mod": 0, + "mul_mod": 0, + "ecdsa": 0 + }, + "l1_handler_max_amount_bounds": { + "l1_gas": 10000000000, + "l1_data_gas": 10000000000, + "l2_gas": 10000000000 + }, "memory_hole_gas_cost": 10, + "os_contract_addresses": { + "block_hash_contract_address": 1, + "alias_contract_address": 2, + "reserved_contract_address": 3 + }, "default_initial_gas_cost": { "step_gas_cost": 100000000 }, @@ -89,119 +106,6 @@ "syscall_base_gas_cost": { "step_gas_cost": 100 }, - "entry_point_gas_cost": { - "entry_point_initial_budget": 1, - "step_gas_cost": 500 - }, - "fee_transfer_gas_cost": { - "entry_point_gas_cost": 1, - "step_gas_cost": 100 - }, - "transaction_gas_cost": { - "entry_point_gas_cost": 2, - "fee_transfer_gas_cost": 1, - "step_gas_cost": 100 - }, - "call_contract_gas_cost": { - "syscall_base_gas_cost": 1, - "step_gas_cost": 10, - "entry_point_gas_cost": 1 - }, - "deploy_gas_cost": { - "syscall_base_gas_cost": 1, - "step_gas_cost": 200, - "entry_point_gas_cost": 1 - }, - "get_block_hash_gas_cost": { - "syscall_base_gas_cost": 1, - "step_gas_cost": 50 - }, - "get_execution_info_gas_cost": { - "syscall_base_gas_cost": 1, - "step_gas_cost": 10 - }, - "library_call_gas_cost": { - "call_contract_gas_cost": 1 - }, - "replace_class_gas_cost": { - "syscall_base_gas_cost": 1, - "step_gas_cost": 50 - }, - "storage_read_gas_cost": { - "syscall_base_gas_cost": 1, - "step_gas_cost": 50 - }, - "storage_write_gas_cost": { - "syscall_base_gas_cost": 1, - "step_gas_cost": 50 - }, - "get_class_hash_at_gas_cost": { - "step_gas_cost": 0, - "syscall_base_gas_cost": 0 - }, - "emit_event_gas_cost": { - "syscall_base_gas_cost": 1, - "step_gas_cost": 10 - }, - "send_message_to_l1_gas_cost": { - "syscall_base_gas_cost": 1, - "step_gas_cost": 50 - }, - "secp256k1_add_gas_cost": { - "step_gas_cost": 406, - "range_check_gas_cost": 29 - }, - "secp256k1_get_point_from_x_gas_cost": { - "step_gas_cost": 391, - "range_check_gas_cost": 30, - "memory_hole_gas_cost": 20 - }, - "secp256k1_get_xy_gas_cost": { - "step_gas_cost": 239, - "range_check_gas_cost": 11, - "memory_hole_gas_cost": 40 - }, - "secp256k1_mul_gas_cost": { - "step_gas_cost": 76401, - "range_check_gas_cost": 7045 - }, - "secp256k1_new_gas_cost": { - "step_gas_cost": 475, - "range_check_gas_cost": 35, - "memory_hole_gas_cost": 40 - }, - "secp256r1_add_gas_cost": { - "step_gas_cost": 589, - "range_check_gas_cost": 57 - }, - "secp256r1_get_point_from_x_gas_cost": { - "step_gas_cost": 510, - "range_check_gas_cost": 44, - "memory_hole_gas_cost": 20 - }, - "secp256r1_get_xy_gas_cost": { - "step_gas_cost": 241, - "range_check_gas_cost": 11, - "memory_hole_gas_cost": 40 - }, - "secp256r1_mul_gas_cost": { - "step_gas_cost": 125240, - "range_check_gas_cost": 13961 - }, - "secp256r1_new_gas_cost": { - "step_gas_cost": 594, - "range_check_gas_cost": 49, - "memory_hole_gas_cost": 40 - }, - "keccak_gas_cost": { - "syscall_base_gas_cost": 1 - }, - "keccak_round_cost_gas_cost": 180000, - "sha256_process_block_gas_cost": { - "step_gas_cost": 0, - "range_check_gas_cost": 0, - "syscall_base_gas_cost": 0 - }, "error_block_number_out_of_range": "Block number out of range", "error_out_of_gas": "Out of gas", "error_entry_point_failed": "ENTRYPOINT_FAILED", @@ -212,7 +116,116 @@ "l1_gas": "L1_GAS", "l2_gas": "L2_GAS", "l1_gas_index": 0, - "l2_gas_index": 1 + "l2_gas_index": 1, + "syscall_gas_costs": { + "call_contract": { + "syscall_base_gas_cost": 1, + "step_gas_cost": 510 + }, + "deploy": { + "syscall_base_gas_cost": 1, + "step_gas_cost": 700 + }, + "get_block_hash": { + "syscall_base_gas_cost": 1, + "step_gas_cost": 50 + }, + "get_execution_info": { + "syscall_base_gas_cost": 1, + "step_gas_cost": 10 + }, + "library_call": { + "syscall_base_gas_cost": 1, + "step_gas_cost": 510 + }, + "meta_tx_v0": { + "syscall_base_gas_cost": 0, + "step_gas_cost": 0 + }, + "replace_class": { + "syscall_base_gas_cost": 1, + "step_gas_cost": 50 + }, + "storage_read": { + "syscall_base_gas_cost": 1, + "step_gas_cost": 50 + }, + "storage_write": { + "syscall_base_gas_cost": 1, + "step_gas_cost": 50 + }, + "get_class_hash_at": { + "step_gas_cost": 0, + "syscall_base_gas_cost": 0 + }, + "emit_event": { + "syscall_base_gas_cost": 1, + "step_gas_cost": 10 + }, + "send_message_to_l1": { + "syscall_base_gas_cost": 1, + "step_gas_cost": 50 + }, + "secp256k1_add": { + "step_gas_cost": 406, + "range_check": 29 + }, + "secp256k1_get_point_from_x": { + "step_gas_cost": 391, + "range_check": 30, + "memory_hole_gas_cost": 20 + }, + "secp256k1_get_xy": { + "step_gas_cost": 239, + "range_check": 11, + "memory_hole_gas_cost": 40 + }, + "secp256k1_mul": { + "step_gas_cost": 76401, + "range_check": 7045 + }, + "secp256k1_new": { + "step_gas_cost": 475, + "range_check": 35, + "memory_hole_gas_cost": 40 + }, + "secp256r1_add": { + "step_gas_cost": 589, + "range_check": 57 + }, + "secp256r1_get_point_from_x": { + "step_gas_cost": 510, + "range_check": 44, + "memory_hole_gas_cost": 20 + }, + "secp256r1_get_xy": { + "step_gas_cost": 241, + "range_check": 11, + "memory_hole_gas_cost": 40 + }, + "secp256r1_mul": { + "step_gas_cost": 125240, + "range_check": 13961 + }, + "secp256r1_new": { + "step_gas_cost": 594, + "range_check": 49, + "memory_hole_gas_cost": 40 + }, + "keccak": { + "syscall_base_gas_cost": 1 + }, + "keccak_round_cost": 180000, + "sha256_process_block": { + "step_gas_cost": 0, + "range_check": 0, + "syscall_base_gas_cost": 0 + } + }, + "v1_bound_accounts_cairo0": [], + "v1_bound_accounts_cairo1": [], + "v1_bound_accounts_max_tip": "0x0", + "data_gas_accounts": [] }, "os_resources": { "execute_syscalls": { @@ -297,7 +310,7 @@ "n_memory_holes": 0, "n_steps": 44 }, - "Keccak": { + "KeccakRound": { "builtin_instance_counter": { "bitwise_builtin": 6, "keccak_builtin": 1, @@ -306,6 +319,11 @@ "n_memory_holes": 0, "n_steps": 381 }, + "Keccak": { + "builtin_instance_counter": {}, + "n_memory_holes": 0, + "n_steps": 0 + }, "LibraryCall": { "builtin_instance_counter": { "range_check_builtin": 19 @@ -320,6 +338,13 @@ "n_memory_holes": 0, "n_steps": 659 }, + "MetaTxV0": { + "n_steps": 0, + "builtin_instance_counter": { + "range_check_builtin": 0 + }, + "n_memory_holes": 0 + }, "ReplaceClass": { "builtin_instance_counter": {}, "n_memory_holes": 0, @@ -423,131 +448,63 @@ }, "execute_txs_inner": { "Declare": { - "resources": { - "constant": { - "builtin_instance_counter": { - "pedersen_builtin": 15, - "range_check_builtin": 63 - }, - "n_memory_holes": 0, - "n_steps": 2711 + "constant": { + "builtin_instance_counter": { + "pedersen_builtin": 15, + "range_check_builtin": 63 }, - "calldata_factor": { - "n_steps": 0, - "builtin_instance_counter": {}, - "n_memory_holes": 0 - } + "n_memory_holes": 0, + "n_steps": 2711 }, - "deprecated_resources": { - "constant": { - "builtin_instance_counter": { - "pedersen_builtin": 15, - "range_check_builtin": 63 - }, - "n_memory_holes": 0, - "n_steps": 2711 - }, - "calldata_factor": { - "n_steps": 0, - "builtin_instance_counter": {}, - "n_memory_holes": 0 - } + "calldata_factor": { + "n_steps": 0, + "builtin_instance_counter": {}, + "n_memory_holes": 0 } }, "DeployAccount": { - "resources": { - "constant": { - "builtin_instance_counter": { - "pedersen_builtin": 23, - "range_check_builtin": 83 - }, - "n_memory_holes": 0, - "n_steps": 3628 + "constant": { + "builtin_instance_counter": { + "pedersen_builtin": 23, + "range_check_builtin": 83 }, - "calldata_factor": { - "n_steps": 0, - "builtin_instance_counter": {}, - "n_memory_holes": 0 - } + "n_memory_holes": 0, + "n_steps": 3628 }, - "deprecated_resources": { - "constant": { - "builtin_instance_counter": { - "pedersen_builtin": 23, - "range_check_builtin": 83 - }, - "n_memory_holes": 0, - "n_steps": 3628 - }, - "calldata_factor": { - "n_steps": 0, - "builtin_instance_counter": {}, - "n_memory_holes": 0 - } + "calldata_factor": { + "n_steps": 0, + "builtin_instance_counter": {}, + "n_memory_holes": 0 } }, "InvokeFunction": { - "resources": { - "constant": { - "builtin_instance_counter": { - "pedersen_builtin": 16, - "range_check_builtin": 80 - }, - "n_memory_holes": 0, - "n_steps": 3382 + "constant": { + "builtin_instance_counter": { + "pedersen_builtin": 16, + "range_check_builtin": 80 }, - "calldata_factor": { - "n_steps": 0, - "builtin_instance_counter": {}, - "n_memory_holes": 0 - } + "n_memory_holes": 0, + "n_steps": 3382 }, - "deprecated_resources": { - "constant": { - "builtin_instance_counter": { - "pedersen_builtin": 16, - "range_check_builtin": 80 - }, - "n_memory_holes": 0, - "n_steps": 3382 - }, - "calldata_factor": { - "n_steps": 0, - "builtin_instance_counter": {}, - "n_memory_holes": 0 - } + "calldata_factor": { + "n_steps": 0, + "builtin_instance_counter": {}, + "n_memory_holes": 0 } }, "L1Handler": { - "resources": { - "constant": { - "builtin_instance_counter": { - "pedersen_builtin": 11, - "range_check_builtin": 17 - }, - "n_memory_holes": 0, - "n_steps": 1069 + "constant": { + "builtin_instance_counter": { + "pedersen_builtin": 11, + "range_check_builtin": 17 }, - "calldata_factor": { - "n_steps": 0, - "builtin_instance_counter": {}, - "n_memory_holes": 0 - } + "n_memory_holes": 0, + "n_steps": 1069 }, - "deprecated_resources": { - "constant": { - "builtin_instance_counter": { - "pedersen_builtin": 11, - "range_check_builtin": 17 - }, - "n_memory_holes": 0, - "n_steps": 1069 - }, - "calldata_factor": { - "n_steps": 0, - "builtin_instance_counter": {}, - "n_memory_holes": 0 - } + "calldata_factor": { + "n_steps": 0, + "builtin_instance_counter": {}, + "n_memory_holes": 0 } } }, @@ -558,7 +515,7 @@ } }, "validate_max_n_steps": 1000000, - "min_compiler_version_for_sierra_gas": "2.8.0", + "min_sierra_version_for_sierra_gas": "100.0.0", "vm_resource_fee_cost": { "builtins": { "add_mod_builtin": [ @@ -610,5 +567,6 @@ 5, 1000 ] - } + }, + "enable_tip": false } diff --git a/crates/blockifier/resources/versioned_constants_0_13_1.json b/crates/blockifier/resources/blockifier_versioned_constants_0_13_1.json similarity index 58% rename from crates/blockifier/resources/versioned_constants_0_13_1.json rename to crates/blockifier/resources/blockifier_versioned_constants_0_13_1.json index 1be6a8686f8..0bfbda116bc 100644 --- a/crates/blockifier/resources/versioned_constants_0_13_1.json +++ b/crates/blockifier/resources/blockifier_versioned_constants_0_13_1.json @@ -41,6 +41,7 @@ "segment_arena_cells": true, "disable_cairo0_redeclaration": false, "enable_stateful_compression": false, + "comprehensive_state_diff": false, "allocation_cost": { "blob_cost": { "l1_gas": 0, @@ -69,16 +70,32 @@ "validate_deploy_entry_point_selector": "0x36fcbf06cd96843058359e1a75928beacfac10727dab22a3972f0af8aa92895", "transfer_entry_point_selector": "0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e", "default_entry_point_selector": 0, - "block_hash_contract_address": 1, + "validate_max_sierra_gas": 10000000000, + "execute_max_sierra_gas": 10000000000, "stored_block_hash_buffer": 10, "step_gas_cost": 100, - "range_check_gas_cost": 70, - "pedersen_gas_cost": 0, - "bitwise_builtin_gas_cost": 0, - "ecop_gas_cost": 0, - "poseidon_gas_cost": 0, - "add_mod_gas_cost": 0, - "mul_mod_gas_cost": 0, + "builtin_gas_costs": { + "range_check": 70, + "range_check96": 0, + "keccak": 0, + "pedersen": 0, + "bitwise": 0, + "ecop": 0, + "poseidon": 0, + "add_mod": 0, + "mul_mod": 0, + "ecdsa": 0 + }, + "l1_handler_max_amount_bounds": { + "l1_gas": 10000000000, + "l1_data_gas": 10000000000, + "l2_gas": 10000000000 + }, + "os_contract_addresses": { + "block_hash_contract_address": 1, + "alias_contract_address": 2, + "reserved_contract_address": 3 + }, "memory_hole_gas_cost": 10, "default_initial_gas_cost": { "step_gas_cost": 100000000 @@ -89,121 +106,6 @@ "syscall_base_gas_cost": { "step_gas_cost": 100 }, - "entry_point_gas_cost": { - "entry_point_initial_budget": 1, - "step_gas_cost": 500 - }, - "fee_transfer_gas_cost": { - "entry_point_gas_cost": 1, - "step_gas_cost": 100 - }, - "transaction_gas_cost": { - "entry_point_gas_cost": 2, - "fee_transfer_gas_cost": 1, - "step_gas_cost": 100 - }, - "call_contract_gas_cost": { - "syscall_base_gas_cost": 1, - "step_gas_cost": 10, - "entry_point_gas_cost": 1 - }, - "deploy_gas_cost": { - "syscall_base_gas_cost": 1, - "step_gas_cost": 200, - "entry_point_gas_cost": 1 - }, - "get_block_hash_gas_cost": { - "syscall_base_gas_cost": 1, - "step_gas_cost": 50 - }, - "get_execution_info_gas_cost": { - "syscall_base_gas_cost": 1, - "step_gas_cost": 10 - }, - "library_call_gas_cost": { - "call_contract_gas_cost": 1 - }, - "replace_class_gas_cost": { - "syscall_base_gas_cost": 1, - "step_gas_cost": 50 - }, - "storage_read_gas_cost": { - "syscall_base_gas_cost": 1, - "step_gas_cost": 50 - }, - "storage_write_gas_cost": { - "syscall_base_gas_cost": 1, - "step_gas_cost": 50 - }, - "get_class_hash_at_gas_cost": { - "step_gas_cost": 0, - "syscall_base_gas_cost": 0 - }, - "emit_event_gas_cost": { - "syscall_base_gas_cost": 1, - "step_gas_cost": 10 - }, - "send_message_to_l1_gas_cost": { - "syscall_base_gas_cost": 1, - "step_gas_cost": 50 - }, - "secp256k1_add_gas_cost": { - "step_gas_cost": 406, - "range_check_gas_cost": 29 - }, - "secp256k1_get_point_from_x_gas_cost": { - "step_gas_cost": 391, - "range_check_gas_cost": 30, - "memory_hole_gas_cost": 20 - }, - "secp256k1_get_xy_gas_cost": { - "step_gas_cost": 239, - "range_check_gas_cost": 11, - "memory_hole_gas_cost": 40 - }, - "secp256k1_mul_gas_cost": { - "step_gas_cost": 76501, - "range_check_gas_cost": 7045, - "memory_hole_gas_cost": 2 - }, - "secp256k1_new_gas_cost": { - "step_gas_cost": 475, - "range_check_gas_cost": 35, - "memory_hole_gas_cost": 40 - }, - "secp256r1_add_gas_cost": { - "step_gas_cost": 589, - "range_check_gas_cost": 57 - }, - "secp256r1_get_point_from_x_gas_cost": { - "step_gas_cost": 510, - "range_check_gas_cost": 44, - "memory_hole_gas_cost": 20 - }, - "secp256r1_get_xy_gas_cost": { - "step_gas_cost": 241, - "range_check_gas_cost": 11, - "memory_hole_gas_cost": 40 - }, - "secp256r1_mul_gas_cost": { - "step_gas_cost": 125340, - "range_check_gas_cost": 13961, - "memory_hole_gas_cost": 2 - }, - "secp256r1_new_gas_cost": { - "step_gas_cost": 594, - "range_check_gas_cost": 49, - "memory_hole_gas_cost": 40 - }, - "keccak_gas_cost": { - "syscall_base_gas_cost": 1 - }, - "keccak_round_cost_gas_cost": 180000, - "sha256_process_block_gas_cost": { - "step_gas_cost": 0, - "range_check_gas_cost": 0, - "syscall_base_gas_cost": 0 - }, "error_block_number_out_of_range": "Block number out of range", "error_out_of_gas": "Out of gas", "error_entry_point_failed": "ENTRYPOINT_FAILED", @@ -218,7 +120,118 @@ "validate_rounding_consts": { "validate_block_number_rounding": 100, "validate_timestamp_rounding": 3600 - } + }, + "syscall_gas_costs": { + "call_contract": { + "syscall_base_gas_cost": 1, + "step_gas_cost": 510 + }, + "deploy": { + "syscall_base_gas_cost": 1, + "step_gas_cost": 700 + }, + "get_block_hash": { + "syscall_base_gas_cost": 1, + "step_gas_cost": 50 + }, + "get_execution_info": { + "syscall_base_gas_cost": 1, + "step_gas_cost": 10 + }, + "library_call": { + "syscall_base_gas_cost": 1, + "step_gas_cost": 510 + }, + "meta_tx_v0": { + "syscall_base_gas_cost": 0, + "step_gas_cost": 0 + }, + "replace_class": { + "syscall_base_gas_cost": 1, + "step_gas_cost": 50 + }, + "storage_read": { + "syscall_base_gas_cost": 1, + "step_gas_cost": 50 + }, + "storage_write": { + "syscall_base_gas_cost": 1, + "step_gas_cost": 50 + }, + "get_class_hash_at": { + "step_gas_cost": 0, + "syscall_base_gas_cost": 0 + }, + "emit_event": { + "syscall_base_gas_cost": 1, + "step_gas_cost": 10 + }, + "send_message_to_l1": { + "syscall_base_gas_cost": 1, + "step_gas_cost": 50 + }, + "secp256k1_add": { + "step_gas_cost": 406, + "range_check": 29 + }, + "secp256k1_get_point_from_x": { + "step_gas_cost": 391, + "range_check": 30, + "memory_hole_gas_cost": 20 + }, + "secp256k1_get_xy": { + "step_gas_cost": 239, + "range_check": 11, + "memory_hole_gas_cost": 40 + }, + "secp256k1_mul": { + "step_gas_cost": 76501, + "range_check": 7045, + "memory_hole_gas_cost": 2 + }, + "secp256k1_new": { + "step_gas_cost": 475, + "range_check": 35, + "memory_hole_gas_cost": 40 + }, + "secp256r1_add": { + "step_gas_cost": 589, + "range_check": 57 + }, + "secp256r1_get_point_from_x": { + "step_gas_cost": 510, + "range_check": 44, + "memory_hole_gas_cost": 20 + }, + "secp256r1_get_xy": { + "step_gas_cost": 241, + "range_check": 11, + "memory_hole_gas_cost": 40 + }, + "secp256r1_mul": { + "step_gas_cost": 125340, + "range_check": 13961, + "memory_hole_gas_cost": 2 + }, + "secp256r1_new": { + "step_gas_cost": 594, + "range_check": 49, + "memory_hole_gas_cost": 40 + }, + "keccak": { + "syscall_base_gas_cost": 1 + }, + "keccak_round_cost": 180000, + "sha256_process_block": { + "step_gas_cost": 0, + "range_check": 0, + "syscall_base_gas_cost": 0 + } + }, + "v1_bound_accounts_cairo0": [], + "v1_bound_accounts_cairo1": [], + "v1_bound_accounts_max_tip": "0x0", + "data_gas_accounts": [] }, "os_resources": { "execute_syscalls": { @@ -313,7 +326,7 @@ "builtin_instance_counter": {}, "n_memory_holes": 0 }, - "Keccak": { + "KeccakRound": { "n_steps": 381, "builtin_instance_counter": { "bitwise_builtin": 6, @@ -322,6 +335,11 @@ }, "n_memory_holes": 0 }, + "Keccak": { + "n_steps": 0, + "builtin_instance_counter": {}, + "n_memory_holes": 0 + }, "LibraryCall": { "n_steps": 751, "builtin_instance_counter": { @@ -336,6 +354,13 @@ }, "n_memory_holes": 0 }, + "MetaTxV0": { + "n_steps": 0, + "builtin_instance_counter": { + "range_check_builtin": 0 + }, + "n_memory_holes": 0 + }, "ReplaceClass": { "n_steps": 98, "builtin_instance_counter": { @@ -447,143 +472,69 @@ }, "execute_txs_inner": { "Declare": { - "resources": { - "constant": { - "n_steps": 2839, - "builtin_instance_counter": { - "pedersen_builtin": 16, - "range_check_builtin": 63 - }, - "n_memory_holes": 0 + "constant": { + "n_steps": 2839, + "builtin_instance_counter": { + "pedersen_builtin": 16, + "range_check_builtin": 63 }, - "calldata_factor": { - "n_steps": 0, - "builtin_instance_counter": {}, - "n_memory_holes": 0 - } - }, - "deprecated_resources": { - "constant": { - "n_steps": 2839, - "builtin_instance_counter": { - "pedersen_builtin": 16, - "range_check_builtin": 63 - }, - "n_memory_holes": 0 - }, - "calldata_factor": { - "n_steps": 0, - "builtin_instance_counter": {}, - "n_memory_holes": 0 - } + "n_memory_holes": 0 + }, + "calldata_factor": { + "n_steps": 0, + "builtin_instance_counter": {}, + "n_memory_holes": 0 } }, "DeployAccount": { - "resources": { - "constant": { - "n_steps": 3792, - "builtin_instance_counter": { - "pedersen_builtin": 23, - "range_check_builtin": 83 - }, - "n_memory_holes": 0 + "constant": { + "n_steps": 3792, + "builtin_instance_counter": { + "pedersen_builtin": 23, + "range_check_builtin": 83 }, - "calldata_factor": { - "n_steps": 21, - "builtin_instance_counter": { - "pedersen_builtin": 2 - }, - "n_memory_holes": 0 - } - }, - "deprecated_resources": { - "constant": { - "n_steps": 3792, - "builtin_instance_counter": { - "pedersen_builtin": 23, - "range_check_builtin": 83 - }, - "n_memory_holes": 0 + "n_memory_holes": 0 + }, + "calldata_factor": { + "n_steps": 21, + "builtin_instance_counter": { + "pedersen_builtin": 2 }, - "calldata_factor": { - "n_steps": 21, - "builtin_instance_counter": { - "pedersen_builtin": 2 - }, - "n_memory_holes": 0 - } + "n_memory_holes": 0 } }, "InvokeFunction": { - "resources": { - "constant": { - "n_steps": 3546, - "builtin_instance_counter": { - "pedersen_builtin": 14, - "range_check_builtin": 80 - }, - "n_memory_holes": 0 + "constant": { + "n_steps": 3546, + "builtin_instance_counter": { + "pedersen_builtin": 14, + "range_check_builtin": 80 }, - "calldata_factor": { - "n_steps": 8, - "builtin_instance_counter": { - "pedersen_builtin": 1 - }, - "n_memory_holes": 0 - } - }, - "deprecated_resources": { - "constant": { - "n_steps": 3546, - "builtin_instance_counter": { - "pedersen_builtin": 14, - "range_check_builtin": 80 - }, - "n_memory_holes": 0 + "n_memory_holes": 0 + }, + "calldata_factor": { + "n_steps": 8, + "builtin_instance_counter": { + "pedersen_builtin": 1 }, - "calldata_factor": { - "n_steps": 8, - "builtin_instance_counter": { - "pedersen_builtin": 1 - }, - "n_memory_holes": 0 - } + "n_memory_holes": 0 } }, "L1Handler": { - "resources": { - "constant": { - "n_steps": 1146, - "builtin_instance_counter": { - "pedersen_builtin": 11, - "range_check_builtin": 17 - }, - "n_memory_holes": 0 + "constant": { + "n_steps": 1146, + "builtin_instance_counter": { + "pedersen_builtin": 11, + "range_check_builtin": 17 }, - "calldata_factor": { - "n_steps": 13, - "builtin_instance_counter": { - "pedersen_builtin": 1 - }, - "n_memory_holes": 0 - } - }, - "deprecated_resources": { - "constant": { - "n_steps": 1146, - "builtin_instance_counter": { - "pedersen_builtin": 11, - "range_check_builtin": 17 - }, - "n_memory_holes": 0 + "n_memory_holes": 0 + }, + "calldata_factor": { + "n_steps": 13, + "builtin_instance_counter": { + "pedersen_builtin": 1 }, - "calldata_factor": { - "n_steps": 13, - "builtin_instance_counter": { - "pedersen_builtin": 1 - }, - "n_memory_holes": 0 - } + "n_memory_holes": 0 } } }, @@ -594,7 +545,7 @@ } }, "validate_max_n_steps": 1000000, - "min_compiler_version_for_sierra_gas": "2.8.0", + "min_sierra_version_for_sierra_gas": "100.0.0", "vm_resource_fee_cost": { "builtins": { "add_mod_builtin": [ @@ -646,5 +597,6 @@ 25, 10000 ] - } + }, + "enable_tip": false } diff --git a/crates/blockifier/resources/versioned_constants_0_13_1_1.json b/crates/blockifier/resources/blockifier_versioned_constants_0_13_1_1.json similarity index 58% rename from crates/blockifier/resources/versioned_constants_0_13_1_1.json rename to crates/blockifier/resources/blockifier_versioned_constants_0_13_1_1.json index 782d3ca1307..f518c7c3ff9 100644 --- a/crates/blockifier/resources/versioned_constants_0_13_1_1.json +++ b/crates/blockifier/resources/blockifier_versioned_constants_0_13_1_1.json @@ -41,6 +41,7 @@ "segment_arena_cells": true, "disable_cairo0_redeclaration": false, "enable_stateful_compression": false, + "comprehensive_state_diff": false, "allocation_cost": { "blob_cost": { "l1_gas": 0, @@ -69,17 +70,33 @@ "validate_deploy_entry_point_selector": "0x36fcbf06cd96843058359e1a75928beacfac10727dab22a3972f0af8aa92895", "transfer_entry_point_selector": "0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e", "default_entry_point_selector": 0, - "block_hash_contract_address": 1, + "validate_max_sierra_gas": 10000000000, + "execute_max_sierra_gas": 10000000000, "stored_block_hash_buffer": 10, "step_gas_cost": 100, - "range_check_gas_cost": 70, - "pedersen_gas_cost": 0, - "bitwise_builtin_gas_cost": 0, - "ecop_gas_cost": 0, - "poseidon_gas_cost": 0, - "add_mod_gas_cost": 0, - "mul_mod_gas_cost": 0, + "builtin_gas_costs": { + "range_check": 70, + "range_check96": 0, + "keccak": 0, + "pedersen": 0, + "bitwise": 0, + "ecop": 0, + "poseidon": 0, + "add_mod": 0, + "mul_mod": 0, + "ecdsa": 0 + }, + "l1_handler_max_amount_bounds": { + "l1_gas": 10000000000, + "l1_data_gas": 10000000000, + "l2_gas": 10000000000 + }, "memory_hole_gas_cost": 10, + "os_contract_addresses": { + "block_hash_contract_address": 1, + "alias_contract_address": 2, + "reserved_contract_address": 3 + }, "default_initial_gas_cost": { "step_gas_cost": 100000000 }, @@ -89,121 +106,6 @@ "syscall_base_gas_cost": { "step_gas_cost": 100 }, - "entry_point_gas_cost": { - "entry_point_initial_budget": 1, - "step_gas_cost": 500 - }, - "fee_transfer_gas_cost": { - "entry_point_gas_cost": 1, - "step_gas_cost": 100 - }, - "transaction_gas_cost": { - "entry_point_gas_cost": 2, - "fee_transfer_gas_cost": 1, - "step_gas_cost": 100 - }, - "call_contract_gas_cost": { - "syscall_base_gas_cost": 1, - "step_gas_cost": 10, - "entry_point_gas_cost": 1 - }, - "deploy_gas_cost": { - "syscall_base_gas_cost": 1, - "step_gas_cost": 200, - "entry_point_gas_cost": 1 - }, - "get_block_hash_gas_cost": { - "syscall_base_gas_cost": 1, - "step_gas_cost": 50 - }, - "get_execution_info_gas_cost": { - "syscall_base_gas_cost": 1, - "step_gas_cost": 10 - }, - "library_call_gas_cost": { - "call_contract_gas_cost": 1 - }, - "replace_class_gas_cost": { - "syscall_base_gas_cost": 1, - "step_gas_cost": 50 - }, - "storage_read_gas_cost": { - "syscall_base_gas_cost": 1, - "step_gas_cost": 50 - }, - "storage_write_gas_cost": { - "syscall_base_gas_cost": 1, - "step_gas_cost": 50 - }, - "get_class_hash_at_gas_cost": { - "step_gas_cost": 0, - "syscall_base_gas_cost": 0 - }, - "emit_event_gas_cost": { - "syscall_base_gas_cost": 1, - "step_gas_cost": 10 - }, - "send_message_to_l1_gas_cost": { - "syscall_base_gas_cost": 1, - "step_gas_cost": 50 - }, - "secp256k1_add_gas_cost": { - "step_gas_cost": 406, - "range_check_gas_cost": 29 - }, - "secp256k1_get_point_from_x_gas_cost": { - "step_gas_cost": 391, - "range_check_gas_cost": 30, - "memory_hole_gas_cost": 20 - }, - "secp256k1_get_xy_gas_cost": { - "step_gas_cost": 239, - "range_check_gas_cost": 11, - "memory_hole_gas_cost": 40 - }, - "secp256k1_mul_gas_cost": { - "step_gas_cost": 76501, - "range_check_gas_cost": 7045, - "memory_hole_gas_cost": 2 - }, - "secp256k1_new_gas_cost": { - "step_gas_cost": 475, - "range_check_gas_cost": 35, - "memory_hole_gas_cost": 40 - }, - "secp256r1_add_gas_cost": { - "step_gas_cost": 589, - "range_check_gas_cost": 57 - }, - "secp256r1_get_point_from_x_gas_cost": { - "step_gas_cost": 510, - "range_check_gas_cost": 44, - "memory_hole_gas_cost": 20 - }, - "secp256r1_get_xy_gas_cost": { - "step_gas_cost": 241, - "range_check_gas_cost": 11, - "memory_hole_gas_cost": 40 - }, - "secp256r1_mul_gas_cost": { - "step_gas_cost": 125340, - "range_check_gas_cost": 13961, - "memory_hole_gas_cost": 2 - }, - "secp256r1_new_gas_cost": { - "step_gas_cost": 594, - "range_check_gas_cost": 49, - "memory_hole_gas_cost": 40 - }, - "keccak_gas_cost": { - "syscall_base_gas_cost": 1 - }, - "keccak_round_cost_gas_cost": 180000, - "sha256_process_block_gas_cost": { - "step_gas_cost": 0, - "range_check_gas_cost": 0, - "syscall_base_gas_cost": 0 - }, "error_block_number_out_of_range": "Block number out of range", "error_out_of_gas": "Out of gas", "error_entry_point_failed": "ENTRYPOINT_FAILED", @@ -218,7 +120,118 @@ "validate_rounding_consts": { "validate_block_number_rounding": 100, "validate_timestamp_rounding": 3600 - } + }, + "syscall_gas_costs": { + "call_contract": { + "syscall_base_gas_cost": 1, + "step_gas_cost": 510 + }, + "deploy": { + "syscall_base_gas_cost": 1, + "step_gas_cost": 700 + }, + "get_block_hash": { + "syscall_base_gas_cost": 1, + "step_gas_cost": 50 + }, + "get_execution_info": { + "syscall_base_gas_cost": 1, + "step_gas_cost": 10 + }, + "library_call": { + "syscall_base_gas_cost": 1, + "step_gas_cost": 510 + }, + "meta_tx_v0": { + "syscall_base_gas_cost": 0, + "step_gas_cost": 0 + }, + "replace_class": { + "syscall_base_gas_cost": 1, + "step_gas_cost": 50 + }, + "storage_read": { + "syscall_base_gas_cost": 1, + "step_gas_cost": 50 + }, + "storage_write": { + "syscall_base_gas_cost": 1, + "step_gas_cost": 50 + }, + "get_class_hash_at": { + "step_gas_cost": 0, + "syscall_base_gas_cost": 0 + }, + "emit_event": { + "syscall_base_gas_cost": 1, + "step_gas_cost": 10 + }, + "send_message_to_l1": { + "syscall_base_gas_cost": 1, + "step_gas_cost": 50 + }, + "secp256k1_add": { + "step_gas_cost": 406, + "range_check": 29 + }, + "secp256k1_get_point_from_x": { + "step_gas_cost": 391, + "range_check": 30, + "memory_hole_gas_cost": 20 + }, + "secp256k1_get_xy": { + "step_gas_cost": 239, + "range_check": 11, + "memory_hole_gas_cost": 40 + }, + "secp256k1_mul": { + "step_gas_cost": 76501, + "range_check": 7045, + "memory_hole_gas_cost": 2 + }, + "secp256k1_new": { + "step_gas_cost": 475, + "range_check": 35, + "memory_hole_gas_cost": 40 + }, + "secp256r1_add": { + "step_gas_cost": 589, + "range_check": 57 + }, + "secp256r1_get_point_from_x": { + "step_gas_cost": 510, + "range_check": 44, + "memory_hole_gas_cost": 20 + }, + "secp256r1_get_xy": { + "step_gas_cost": 241, + "range_check": 11, + "memory_hole_gas_cost": 40 + }, + "secp256r1_mul": { + "step_gas_cost": 125340, + "range_check": 13961, + "memory_hole_gas_cost": 2 + }, + "secp256r1_new": { + "step_gas_cost": 594, + "range_check": 49, + "memory_hole_gas_cost": 40 + }, + "keccak": { + "syscall_base_gas_cost": 1 + }, + "keccak_round_cost": 180000, + "sha256_process_block": { + "step_gas_cost": 0, + "range_check": 0, + "syscall_base_gas_cost": 0 + } + }, + "v1_bound_accounts_cairo0": [], + "v1_bound_accounts_cairo1": [], + "v1_bound_accounts_max_tip": "0x0", + "data_gas_accounts": [] }, "os_resources": { "execute_syscalls": { @@ -313,7 +326,7 @@ "builtin_instance_counter": {}, "n_memory_holes": 0 }, - "Keccak": { + "KeccakRound": { "n_steps": 381, "builtin_instance_counter": { "bitwise_builtin": 6, @@ -322,6 +335,11 @@ }, "n_memory_holes": 0 }, + "Keccak": { + "n_steps": 0, + "builtin_instance_counter": {}, + "n_memory_holes": 0 + }, "LibraryCall": { "n_steps": 751, "builtin_instance_counter": { @@ -336,6 +354,13 @@ }, "n_memory_holes": 0 }, + "MetaTxV0": { + "n_steps": 0, + "builtin_instance_counter": { + "range_check_builtin": 0 + }, + "n_memory_holes": 0 + }, "ReplaceClass": { "n_steps": 98, "builtin_instance_counter": { @@ -447,143 +472,69 @@ }, "execute_txs_inner": { "Declare": { - "resources": { - "constant": { - "n_steps": 2839, - "builtin_instance_counter": { - "pedersen_builtin": 16, - "range_check_builtin": 63 - }, - "n_memory_holes": 0 + "constant": { + "n_steps": 2839, + "builtin_instance_counter": { + "pedersen_builtin": 16, + "range_check_builtin": 63 }, - "calldata_factor": { - "n_steps": 0, - "builtin_instance_counter": {}, - "n_memory_holes": 0 - } - }, - "deprecated_resources": { - "constant": { - "n_steps": 2839, - "builtin_instance_counter": { - "pedersen_builtin": 16, - "range_check_builtin": 63 - }, - "n_memory_holes": 0 - }, - "calldata_factor": { - "n_steps": 0, - "builtin_instance_counter": {}, - "n_memory_holes": 0 - } + "n_memory_holes": 0 + }, + "calldata_factor": { + "n_steps": 0, + "builtin_instance_counter": {}, + "n_memory_holes": 0 } }, "DeployAccount": { - "resources": { - "constant": { - "n_steps": 3792, - "builtin_instance_counter": { - "pedersen_builtin": 23, - "range_check_builtin": 83 - }, - "n_memory_holes": 0 + "constant": { + "n_steps": 3792, + "builtin_instance_counter": { + "pedersen_builtin": 23, + "range_check_builtin": 83 }, - "calldata_factor": { - "n_steps": 21, - "builtin_instance_counter": { - "pedersen_builtin": 2 - }, - "n_memory_holes": 0 - } - }, - "deprecated_resources": { - "constant": { - "n_steps": 3792, - "builtin_instance_counter": { - "pedersen_builtin": 23, - "range_check_builtin": 83 - }, - "n_memory_holes": 0 + "n_memory_holes": 0 + }, + "calldata_factor": { + "n_steps": 21, + "builtin_instance_counter": { + "pedersen_builtin": 2 }, - "calldata_factor": { - "n_steps": 21, - "builtin_instance_counter": { - "pedersen_builtin": 2 - }, - "n_memory_holes": 0 - } + "n_memory_holes": 0 } }, "InvokeFunction": { - "resources": { - "constant": { - "n_steps": 3546, - "builtin_instance_counter": { - "pedersen_builtin": 14, - "range_check_builtin": 80 - }, - "n_memory_holes": 0 + "constant": { + "n_steps": 3546, + "builtin_instance_counter": { + "pedersen_builtin": 14, + "range_check_builtin": 80 }, - "calldata_factor": { - "n_steps": 8, - "builtin_instance_counter": { - "pedersen_builtin": 1 - }, - "n_memory_holes": 0 - } - }, - "deprecated_resources": { - "constant": { - "n_steps": 3546, - "builtin_instance_counter": { - "pedersen_builtin": 14, - "range_check_builtin": 80 - }, - "n_memory_holes": 0 + "n_memory_holes": 0 + }, + "calldata_factor": { + "n_steps": 8, + "builtin_instance_counter": { + "pedersen_builtin": 1 }, - "calldata_factor": { - "n_steps": 8, - "builtin_instance_counter": { - "pedersen_builtin": 1 - }, - "n_memory_holes": 0 - } + "n_memory_holes": 0 } }, "L1Handler": { - "resources": { - "constant": { - "n_steps": 1146, - "builtin_instance_counter": { - "pedersen_builtin": 11, - "range_check_builtin": 17 - }, - "n_memory_holes": 0 + "constant": { + "n_steps": 1146, + "builtin_instance_counter": { + "pedersen_builtin": 11, + "range_check_builtin": 17 }, - "calldata_factor": { - "n_steps": 13, - "builtin_instance_counter": { - "pedersen_builtin": 1 - }, - "n_memory_holes": 0 - } - }, - "deprecated_resources": { - "constant": { - "n_steps": 1146, - "builtin_instance_counter": { - "pedersen_builtin": 11, - "range_check_builtin": 17 - }, - "n_memory_holes": 0 + "n_memory_holes": 0 + }, + "calldata_factor": { + "n_steps": 13, + "builtin_instance_counter": { + "pedersen_builtin": 1 }, - "calldata_factor": { - "n_steps": 13, - "builtin_instance_counter": { - "pedersen_builtin": 1 - }, - "n_memory_holes": 0 - } + "n_memory_holes": 0 } } }, @@ -594,7 +545,7 @@ } }, "validate_max_n_steps": 1000000, - "min_compiler_version_for_sierra_gas": "2.8.0", + "min_sierra_version_for_sierra_gas": "100.0.0", "vm_resource_fee_cost": { "builtins": { "add_mod_builtin": [ @@ -646,5 +597,6 @@ 25, 10000 ] - } + }, + "enable_tip": false } diff --git a/crates/blockifier/resources/versioned_constants_0_13_2.json b/crates/blockifier/resources/blockifier_versioned_constants_0_13_2.json similarity index 58% rename from crates/blockifier/resources/versioned_constants_0_13_2.json rename to crates/blockifier/resources/blockifier_versioned_constants_0_13_2.json index 86ab5aeb02b..7231246005b 100644 --- a/crates/blockifier/resources/versioned_constants_0_13_2.json +++ b/crates/blockifier/resources/blockifier_versioned_constants_0_13_2.json @@ -39,6 +39,7 @@ }, "disable_cairo0_redeclaration": true, "enable_stateful_compression": false, + "comprehensive_state_diff": false, "allocation_cost": { "blob_cost": { "l1_gas": 0, @@ -56,27 +57,8 @@ "max_recursion_depth": 50, "segment_arena_cells": false, "os_constants": { - "block_hash_contract_address": 1, - "call_contract_gas_cost": { - "entry_point_gas_cost": 1, - "step_gas_cost": 10, - "syscall_base_gas_cost": 1 - }, "constructor_entry_point_selector": "0x28ffe4ff0f226a9107253e17a904099aa4f63a02a5621de0576e5aa71bc5194", "default_entry_point_selector": 0, - "deploy_gas_cost": { - "entry_point_gas_cost": 1, - "step_gas_cost": 200, - "syscall_base_gas_cost": 1 - }, - "emit_event_gas_cost": { - "step_gas_cost": 10, - "syscall_base_gas_cost": 1 - }, - "entry_point_gas_cost": { - "entry_point_initial_budget": 1, - "step_gas_cost": 500 - }, "entry_point_initial_budget": { "step_gas_cost": 100 }, @@ -90,136 +72,167 @@ "error_entry_point_failed": "ENTRYPOINT_FAILED", "error_entry_point_not_found": "ENTRYPOINT_NOT_FOUND", "execute_entry_point_selector": "0x15d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad", - "fee_transfer_gas_cost": { - "entry_point_gas_cost": 1, - "step_gas_cost": 100 - }, - "get_block_hash_gas_cost": { - "step_gas_cost": 50, - "syscall_base_gas_cost": 1 - }, - "get_execution_info_gas_cost": { - "step_gas_cost": 10, - "syscall_base_gas_cost": 1 - }, + "execute_max_sierra_gas": 10000000000, "default_initial_gas_cost": { "step_gas_cost": 100000000 }, - "keccak_gas_cost": { - "syscall_base_gas_cost": 1 - }, - "keccak_round_cost_gas_cost": 180000, "l1_gas": "L1_GAS", "l1_gas_index": 0, "l1_handler_version": 0, "l2_gas": "L2_GAS", "l2_gas_index": 1, - "library_call_gas_cost": { - "call_contract_gas_cost": 1 - }, - "sha256_process_block_gas_cost": { - "step_gas_cost": 1852, - "range_check_gas_cost": 65, - "bitwise_builtin_gas_cost": 1115, - "syscall_base_gas_cost": 1 - }, "memory_hole_gas_cost": 10, "nop_entry_point_offset": -1, - "range_check_gas_cost": 70, - "pedersen_gas_cost": 0, - "bitwise_builtin_gas_cost": 594, - "ecop_gas_cost": 0, - "poseidon_gas_cost": 0, - "add_mod_gas_cost": 0, - "mul_mod_gas_cost": 0, - "replace_class_gas_cost": { - "step_gas_cost": 50, - "syscall_base_gas_cost": 1 - }, - "secp256k1_add_gas_cost": { - "range_check_gas_cost": 29, - "step_gas_cost": 406 - }, - "secp256k1_get_point_from_x_gas_cost": { - "memory_hole_gas_cost": 20, - "range_check_gas_cost": 30, - "step_gas_cost": 391 - }, - "secp256k1_get_xy_gas_cost": { - "memory_hole_gas_cost": 40, - "range_check_gas_cost": 11, - "step_gas_cost": 239 - }, - "secp256k1_mul_gas_cost": { - "memory_hole_gas_cost": 2, - "range_check_gas_cost": 7045, - "step_gas_cost": 76501 - }, - "secp256k1_new_gas_cost": { - "memory_hole_gas_cost": 40, - "range_check_gas_cost": 35, - "step_gas_cost": 475 - }, - "secp256r1_add_gas_cost": { - "range_check_gas_cost": 57, - "step_gas_cost": 589 - }, - "secp256r1_get_point_from_x_gas_cost": { - "memory_hole_gas_cost": 20, - "range_check_gas_cost": 44, - "step_gas_cost": 510 - }, - "secp256r1_get_xy_gas_cost": { - "memory_hole_gas_cost": 40, - "range_check_gas_cost": 11, - "step_gas_cost": 241 - }, - "secp256r1_mul_gas_cost": { - "memory_hole_gas_cost": 2, - "range_check_gas_cost": 13961, - "step_gas_cost": 125340 - }, - "secp256r1_new_gas_cost": { - "memory_hole_gas_cost": 40, - "range_check_gas_cost": 49, - "step_gas_cost": 594 - }, - "send_message_to_l1_gas_cost": { - "step_gas_cost": 50, - "syscall_base_gas_cost": 1 + "os_contract_addresses": { + "block_hash_contract_address": 1, + "alias_contract_address": 2, + "reserved_contract_address": 3 + }, + "builtin_gas_costs": { + "range_check": 70, + "range_check96": 0, + "keccak": 0, + "pedersen": 0, + "bitwise": 594, + "ecop": 0, + "poseidon": 0, + "add_mod": 0, + "mul_mod": 0, + "ecdsa": 0 + }, + "l1_handler_max_amount_bounds": { + "l1_gas": 10000000000, + "l1_data_gas": 10000000000, + "l2_gas": 10000000000 }, "sierra_array_len_bound": 4294967296, "step_gas_cost": 100, - "storage_read_gas_cost": { - "step_gas_cost": 50, - "syscall_base_gas_cost": 1 - }, - "storage_write_gas_cost": { - "step_gas_cost": 50, - "syscall_base_gas_cost": 1 - }, - "get_class_hash_at_gas_cost": { - "step_gas_cost": 0, - "syscall_base_gas_cost": 0 - }, "stored_block_hash_buffer": 10, "syscall_base_gas_cost": { "step_gas_cost": 100 }, - "transaction_gas_cost": { - "entry_point_gas_cost": 2, - "fee_transfer_gas_cost": 1, - "step_gas_cost": 100 - }, "transfer_entry_point_selector": "0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e", "validate_declare_entry_point_selector": "0x289da278a8dc833409cabfdad1581e8e7d40e42dcaed693fa4008dcdb4963b3", "validate_deploy_entry_point_selector": "0x36fcbf06cd96843058359e1a75928beacfac10727dab22a3972f0af8aa92895", "validate_entry_point_selector": "0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775", + "validate_max_sierra_gas": 10000000000, "validate_rounding_consts": { "validate_block_number_rounding": 100, "validate_timestamp_rounding": 3600 }, - "validated": "VALID" + "validated": "VALID", + "syscall_gas_costs": { + "call_contract": { + "step_gas_cost": 510, + "syscall_base_gas_cost": 1 + }, + "deploy": { + "step_gas_cost": 700, + "syscall_base_gas_cost": 1 + }, + "emit_event": { + "step_gas_cost": 10, + "syscall_base_gas_cost": 1 + }, + "get_block_hash": { + "step_gas_cost": 50, + "syscall_base_gas_cost": 1 + }, + "get_execution_info": { + "step_gas_cost": 10, + "syscall_base_gas_cost": 1 + }, + "keccak": { + "syscall_base_gas_cost": 1 + }, + "keccak_round_cost": 180000, + "library_call": { + "step_gas_cost": 510, + "syscall_base_gas_cost": 1 + }, + "meta_tx_v0": { + "syscall_base_gas_cost": 0, + "step_gas_cost": 0 + }, + "sha256_process_block": { + "step_gas_cost": 1852, + "range_check": 65, + "bitwise": 1115, + "syscall_base_gas_cost": 1 + }, + "replace_class": { + "step_gas_cost": 50, + "syscall_base_gas_cost": 1 + }, + "secp256k1_add": { + "range_check": 29, + "step_gas_cost": 406 + }, + "secp256k1_get_point_from_x": { + "memory_hole_gas_cost": 20, + "range_check": 30, + "step_gas_cost": 391 + }, + "secp256k1_get_xy": { + "memory_hole_gas_cost": 40, + "range_check": 11, + "step_gas_cost": 239 + }, + "secp256k1_mul": { + "memory_hole_gas_cost": 2, + "range_check": 7045, + "step_gas_cost": 76501 + }, + "secp256k1_new": { + "memory_hole_gas_cost": 40, + "range_check": 35, + "step_gas_cost": 475 + }, + "secp256r1_add": { + "range_check": 57, + "step_gas_cost": 589 + }, + "secp256r1_get_point_from_x": { + "memory_hole_gas_cost": 20, + "range_check": 44, + "step_gas_cost": 510 + }, + "secp256r1_get_xy": { + "memory_hole_gas_cost": 40, + "range_check": 11, + "step_gas_cost": 241 + }, + "secp256r1_mul": { + "memory_hole_gas_cost": 2, + "range_check": 13961, + "step_gas_cost": 125340 + }, + "secp256r1_new": { + "memory_hole_gas_cost": 40, + "range_check": 49, + "step_gas_cost": 594 + }, + "send_message_to_l1": { + "step_gas_cost": 50, + "syscall_base_gas_cost": 1 + }, + "storage_read": { + "step_gas_cost": 50, + "syscall_base_gas_cost": 1 + }, + "storage_write": { + "step_gas_cost": 50, + "syscall_base_gas_cost": 1 + }, + "get_class_hash_at": { + "step_gas_cost": 0, + "syscall_base_gas_cost": 0 + } + }, + "v1_bound_accounts_cairo0": [], + "v1_bound_accounts_cairo1": [], + "v1_bound_accounts_max_tip": "0x0", + "data_gas_accounts": [] }, "os_resources": { "execute_syscalls": { @@ -314,7 +327,7 @@ "builtin_instance_counter": {}, "n_memory_holes": 0 }, - "Keccak": { + "KeccakRound": { "n_steps": 381, "builtin_instance_counter": { "bitwise_builtin": 6, @@ -323,6 +336,11 @@ }, "n_memory_holes": 0 }, + "Keccak": { + "n_steps": 0, + "builtin_instance_counter": {}, + "n_memory_holes": 0 + }, "LibraryCall": { "n_steps": 818, "builtin_instance_counter": { @@ -337,6 +355,13 @@ }, "n_memory_holes": 0 }, + "MetaTxV0": { + "n_steps": 0, + "builtin_instance_counter": { + "range_check_builtin": 0 + }, + "n_memory_holes": 0 + }, "ReplaceClass": { "n_steps": 98, "builtin_instance_counter": { @@ -451,143 +476,69 @@ }, "execute_txs_inner": { "Declare": { - "deprecated_resources": { - "constant": { - "n_steps": 2973, - "builtin_instance_counter": { - "pedersen_builtin": 16, - "range_check_builtin": 53 - }, - "n_memory_holes": 0 - }, - "calldata_factor": { - "n_steps": 0, - "builtin_instance_counter": {}, - "n_memory_holes": 0 - } - }, - "resources": { - "constant": { - "n_steps": 3079, - "builtin_instance_counter": { - "pedersen_builtin": 4, - "range_check_builtin": 58, - "poseidon_builtin": 10 - }, - "n_memory_holes": 0 + "constant": { + "n_steps": 2973, + "builtin_instance_counter": { + "pedersen_builtin": 16, + "range_check_builtin": 53 }, - "calldata_factor": { - "n_steps": 0, - "builtin_instance_counter": {}, - "n_memory_holes": 0 - } + "n_memory_holes": 0 + }, + "calldata_factor": { + "n_steps": 0, + "builtin_instance_counter": {}, + "n_memory_holes": 0 } }, "DeployAccount": { - "deprecated_resources": { - "constant": { - "n_steps": 4015, - "builtin_instance_counter": { - "pedersen_builtin": 23, - "range_check_builtin": 72 - }, - "n_memory_holes": 0 + "constant": { + "n_steps": 4015, + "builtin_instance_counter": { + "pedersen_builtin": 23, + "range_check_builtin": 72 }, - "calldata_factor": { - "n_steps": 21, - "builtin_instance_counter": { - "pedersen_builtin": 2 - }, - "n_memory_holes": 0 - } - }, - "resources": { - "constant": { - "n_steps": 4137, - "builtin_instance_counter": { - "pedersen_builtin": 11, - "range_check_builtin": 77, - "poseidon_builtin": 10 - }, - "n_memory_holes": 0 + "n_memory_holes": 0 + }, + "calldata_factor": { + "n_steps": 21, + "builtin_instance_counter": { + "pedersen_builtin": 2 }, - "calldata_factor": { - "n_steps": 21, - "builtin_instance_counter": { - "pedersen_builtin": 2 - }, - "n_memory_holes": 0 - } + "n_memory_holes": 0 } }, "InvokeFunction": { - "deprecated_resources": { - "constant": { - "n_steps": 3763, - "builtin_instance_counter": { - "pedersen_builtin": 14, - "range_check_builtin": 69 - }, - "n_memory_holes": 0 + "constant": { + "n_steps": 3763, + "builtin_instance_counter": { + "pedersen_builtin": 14, + "range_check_builtin": 69 }, - "calldata_factor": { - "n_steps": 8, - "builtin_instance_counter": { - "pedersen_builtin": 1 - }, - "n_memory_holes": 0 - } - }, - "resources": { - "constant": { - "n_steps": 3904, - "builtin_instance_counter": { - "pedersen_builtin": 4, - "range_check_builtin": 74, - "poseidon_builtin": 11 - }, - "n_memory_holes": 0 + "n_memory_holes": 0 + }, + "calldata_factor": { + "n_steps": 8, + "builtin_instance_counter": { + "pedersen_builtin": 1 }, - "calldata_factor": { - "n_steps": 8, - "builtin_instance_counter": { - "pedersen_builtin": 1 - }, - "n_memory_holes": 0 - } + "n_memory_holes": 0 } }, "L1Handler": { - "deprecated_resources": { - "constant": { - "n_steps": 1233, - "builtin_instance_counter": { - "pedersen_builtin": 11, - "range_check_builtin": 16 - }, - "n_memory_holes": 0 + "constant": { + "n_steps": 1233, + "builtin_instance_counter": { + "pedersen_builtin": 11, + "range_check_builtin": 16 }, - "calldata_factor": { - "n_steps": 13, - "builtin_instance_counter": { - "pedersen_builtin": 1 - }, - "n_memory_holes": 0 - } - }, - "resources": { - "constant": { - "n_steps": 0, - "builtin_instance_counter": {}, - "n_memory_holes": 0 + "n_memory_holes": 0 + }, + "calldata_factor": { + "n_steps": 13, + "builtin_instance_counter": { + "pedersen_builtin": 1 }, - "calldata_factor": { - "n_steps": 13, - "builtin_instance_counter": { - "pedersen_builtin": 1 - }, - "n_memory_holes": 0 - } + "n_memory_holes": 0 } } }, @@ -600,7 +551,7 @@ } }, "validate_max_n_steps": 1000000, - "min_compiler_version_for_sierra_gas": "2.8.0", + "min_sierra_version_for_sierra_gas": "100.0.0", "vm_resource_fee_cost": { "builtins": { "add_mod_builtin": [ @@ -652,5 +603,6 @@ 25, 10000 ] - } + }, + "enable_tip": false } diff --git a/crates/blockifier/resources/versioned_constants_0_13_2_1.json b/crates/blockifier/resources/blockifier_versioned_constants_0_13_2_1.json similarity index 58% rename from crates/blockifier/resources/versioned_constants_0_13_2_1.json rename to crates/blockifier/resources/blockifier_versioned_constants_0_13_2_1.json index 0b740a12059..588164b2036 100644 --- a/crates/blockifier/resources/versioned_constants_0_13_2_1.json +++ b/crates/blockifier/resources/blockifier_versioned_constants_0_13_2_1.json @@ -39,6 +39,7 @@ }, "disable_cairo0_redeclaration": true, "enable_stateful_compression": false, + "comprehensive_state_diff": false, "allocation_cost": { "blob_cost": { "l1_gas": 0, @@ -56,27 +57,8 @@ "enable_reverts": false, "segment_arena_cells": false, "os_constants": { - "block_hash_contract_address": 1, - "call_contract_gas_cost": { - "entry_point_gas_cost": 1, - "step_gas_cost": 10, - "syscall_base_gas_cost": 1 - }, "constructor_entry_point_selector": "0x28ffe4ff0f226a9107253e17a904099aa4f63a02a5621de0576e5aa71bc5194", "default_entry_point_selector": 0, - "deploy_gas_cost": { - "entry_point_gas_cost": 1, - "step_gas_cost": 200, - "syscall_base_gas_cost": 1 - }, - "emit_event_gas_cost": { - "step_gas_cost": 10, - "syscall_base_gas_cost": 1 - }, - "entry_point_gas_cost": { - "entry_point_initial_budget": 1, - "step_gas_cost": 500 - }, "entry_point_initial_budget": { "step_gas_cost": 100 }, @@ -90,136 +72,167 @@ "error_entry_point_failed": "ENTRYPOINT_FAILED", "error_entry_point_not_found": "ENTRYPOINT_NOT_FOUND", "execute_entry_point_selector": "0x15d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad", - "fee_transfer_gas_cost": { - "entry_point_gas_cost": 1, - "step_gas_cost": 100 - }, - "get_block_hash_gas_cost": { - "step_gas_cost": 50, - "syscall_base_gas_cost": 1 - }, - "get_execution_info_gas_cost": { - "step_gas_cost": 10, - "syscall_base_gas_cost": 1 - }, + "execute_max_sierra_gas": 10000000000, "default_initial_gas_cost": { "step_gas_cost": 100000000 }, - "keccak_gas_cost": { - "syscall_base_gas_cost": 1 - }, - "keccak_round_cost_gas_cost": 180000, "l1_gas": "L1_GAS", "l1_gas_index": 0, "l1_handler_version": 0, "l2_gas": "L2_GAS", "l2_gas_index": 1, - "library_call_gas_cost": { - "call_contract_gas_cost": 1 - }, - "sha256_process_block_gas_cost": { - "step_gas_cost": 1852, - "range_check_gas_cost": 65, - "bitwise_builtin_gas_cost": 1115, - "syscall_base_gas_cost": 1 - }, "memory_hole_gas_cost": 10, "nop_entry_point_offset": -1, - "range_check_gas_cost": 70, - "pedersen_gas_cost": 0, - "bitwise_builtin_gas_cost": 594, - "ecop_gas_cost": 0, - "poseidon_gas_cost": 0, - "add_mod_gas_cost": 0, - "mul_mod_gas_cost": 0, - "replace_class_gas_cost": { - "step_gas_cost": 50, - "syscall_base_gas_cost": 1 - }, - "secp256k1_add_gas_cost": { - "range_check_gas_cost": 29, - "step_gas_cost": 406 - }, - "secp256k1_get_point_from_x_gas_cost": { - "memory_hole_gas_cost": 20, - "range_check_gas_cost": 30, - "step_gas_cost": 391 - }, - "secp256k1_get_xy_gas_cost": { - "memory_hole_gas_cost": 40, - "range_check_gas_cost": 11, - "step_gas_cost": 239 - }, - "secp256k1_mul_gas_cost": { - "memory_hole_gas_cost": 2, - "range_check_gas_cost": 7045, - "step_gas_cost": 76501 - }, - "secp256k1_new_gas_cost": { - "memory_hole_gas_cost": 40, - "range_check_gas_cost": 35, - "step_gas_cost": 475 - }, - "secp256r1_add_gas_cost": { - "range_check_gas_cost": 57, - "step_gas_cost": 589 - }, - "secp256r1_get_point_from_x_gas_cost": { - "memory_hole_gas_cost": 20, - "range_check_gas_cost": 44, - "step_gas_cost": 510 - }, - "secp256r1_get_xy_gas_cost": { - "memory_hole_gas_cost": 40, - "range_check_gas_cost": 11, - "step_gas_cost": 241 - }, - "secp256r1_mul_gas_cost": { - "memory_hole_gas_cost": 2, - "range_check_gas_cost": 13961, - "step_gas_cost": 125340 - }, - "secp256r1_new_gas_cost": { - "memory_hole_gas_cost": 40, - "range_check_gas_cost": 49, - "step_gas_cost": 594 - }, - "send_message_to_l1_gas_cost": { - "step_gas_cost": 50, - "syscall_base_gas_cost": 1 + "os_contract_addresses": { + "block_hash_contract_address": 1, + "alias_contract_address": 2, + "reserved_contract_address": 3 + }, + "builtin_gas_costs": { + "range_check": 70, + "range_check96": 0, + "keccak": 0, + "pedersen": 0, + "bitwise": 594, + "ecop": 0, + "poseidon": 0, + "add_mod": 0, + "mul_mod": 0, + "ecdsa": 0 + }, + "l1_handler_max_amount_bounds": { + "l1_gas": 10000000000, + "l1_data_gas": 10000000000, + "l2_gas": 10000000000 }, "sierra_array_len_bound": 4294967296, "step_gas_cost": 100, - "storage_read_gas_cost": { - "step_gas_cost": 50, - "syscall_base_gas_cost": 1 - }, - "storage_write_gas_cost": { - "step_gas_cost": 50, - "syscall_base_gas_cost": 1 - }, - "get_class_hash_at_gas_cost": { - "step_gas_cost": 0, - "syscall_base_gas_cost": 0 - }, "stored_block_hash_buffer": 10, "syscall_base_gas_cost": { "step_gas_cost": 100 }, - "transaction_gas_cost": { - "entry_point_gas_cost": 2, - "fee_transfer_gas_cost": 1, - "step_gas_cost": 100 - }, "transfer_entry_point_selector": "0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e", "validate_declare_entry_point_selector": "0x289da278a8dc833409cabfdad1581e8e7d40e42dcaed693fa4008dcdb4963b3", "validate_deploy_entry_point_selector": "0x36fcbf06cd96843058359e1a75928beacfac10727dab22a3972f0af8aa92895", "validate_entry_point_selector": "0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775", + "validate_max_sierra_gas": 10000000000, "validate_rounding_consts": { "validate_block_number_rounding": 100, "validate_timestamp_rounding": 3600 }, - "validated": "VALID" + "validated": "VALID", + "syscall_gas_costs": { + "call_contract": { + "step_gas_cost": 510, + "syscall_base_gas_cost": 1 + }, + "deploy": { + "step_gas_cost": 700, + "syscall_base_gas_cost": 1 + }, + "emit_event": { + "step_gas_cost": 10, + "syscall_base_gas_cost": 1 + }, + "get_block_hash": { + "step_gas_cost": 50, + "syscall_base_gas_cost": 1 + }, + "get_execution_info": { + "step_gas_cost": 10, + "syscall_base_gas_cost": 1 + }, + "keccak": { + "syscall_base_gas_cost": 1 + }, + "keccak_round_cost": 180000, + "library_call": { + "step_gas_cost": 510, + "syscall_base_gas_cost": 1 + }, + "meta_tx_v0": { + "syscall_base_gas_cost": 0, + "step_gas_cost": 0 + }, + "sha256_process_block": { + "step_gas_cost": 1852, + "range_check": 65, + "bitwise": 1115, + "syscall_base_gas_cost": 1 + }, + "replace_class": { + "step_gas_cost": 50, + "syscall_base_gas_cost": 1 + }, + "secp256k1_add": { + "range_check": 29, + "step_gas_cost": 406 + }, + "secp256k1_get_point_from_x": { + "memory_hole_gas_cost": 20, + "range_check": 30, + "step_gas_cost": 391 + }, + "secp256k1_get_xy": { + "memory_hole_gas_cost": 40, + "range_check": 11, + "step_gas_cost": 239 + }, + "secp256k1_mul": { + "memory_hole_gas_cost": 2, + "range_check": 7045, + "step_gas_cost": 76501 + }, + "secp256k1_new": { + "memory_hole_gas_cost": 40, + "range_check": 35, + "step_gas_cost": 475 + }, + "secp256r1_add": { + "range_check": 57, + "step_gas_cost": 589 + }, + "secp256r1_get_point_from_x": { + "memory_hole_gas_cost": 20, + "range_check": 44, + "step_gas_cost": 510 + }, + "secp256r1_get_xy": { + "memory_hole_gas_cost": 40, + "range_check": 11, + "step_gas_cost": 241 + }, + "secp256r1_mul": { + "memory_hole_gas_cost": 2, + "range_check": 13961, + "step_gas_cost": 125340 + }, + "secp256r1_new": { + "memory_hole_gas_cost": 40, + "range_check": 49, + "step_gas_cost": 594 + }, + "send_message_to_l1": { + "step_gas_cost": 50, + "syscall_base_gas_cost": 1 + }, + "storage_read": { + "step_gas_cost": 50, + "syscall_base_gas_cost": 1 + }, + "storage_write": { + "step_gas_cost": 50, + "syscall_base_gas_cost": 1 + }, + "get_class_hash_at": { + "step_gas_cost": 0, + "syscall_base_gas_cost": 0 + } + }, + "v1_bound_accounts_cairo0": [], + "v1_bound_accounts_cairo1": [], + "v1_bound_accounts_max_tip": "0x0", + "data_gas_accounts": [] }, "os_resources": { "execute_syscalls": { @@ -314,7 +327,7 @@ "builtin_instance_counter": {}, "n_memory_holes": 0 }, - "Keccak": { + "KeccakRound": { "n_steps": 381, "builtin_instance_counter": { "bitwise_builtin": 6, @@ -323,6 +336,11 @@ }, "n_memory_holes": 0 }, + "Keccak": { + "n_steps": 0, + "builtin_instance_counter": {}, + "n_memory_holes": 0 + }, "LibraryCall": { "n_steps": 818, "builtin_instance_counter": { @@ -337,6 +355,13 @@ }, "n_memory_holes": 0 }, + "MetaTxV0": { + "n_steps": 0, + "builtin_instance_counter": { + "range_check_builtin": 0 + }, + "n_memory_holes": 0 + }, "ReplaceClass": { "n_steps": 98, "builtin_instance_counter": { @@ -451,143 +476,69 @@ }, "execute_txs_inner": { "Declare": { - "deprecated_resources": { - "constant": { - "n_steps": 2973, - "builtin_instance_counter": { - "pedersen_builtin": 16, - "range_check_builtin": 53 - }, - "n_memory_holes": 0 - }, - "calldata_factor": { - "n_steps": 0, - "builtin_instance_counter": {}, - "n_memory_holes": 0 - } - }, - "resources": { - "constant": { - "n_steps": 3079, - "builtin_instance_counter": { - "pedersen_builtin": 4, - "range_check_builtin": 58, - "poseidon_builtin": 10 - }, - "n_memory_holes": 0 + "constant": { + "n_steps": 2973, + "builtin_instance_counter": { + "pedersen_builtin": 16, + "range_check_builtin": 53 }, - "calldata_factor": { - "n_steps": 0, - "builtin_instance_counter": {}, - "n_memory_holes": 0 - } + "n_memory_holes": 0 + }, + "calldata_factor": { + "n_steps": 0, + "builtin_instance_counter": {}, + "n_memory_holes": 0 } }, "DeployAccount": { - "deprecated_resources": { - "constant": { - "n_steps": 4015, - "builtin_instance_counter": { - "pedersen_builtin": 23, - "range_check_builtin": 72 - }, - "n_memory_holes": 0 + "constant": { + "n_steps": 4015, + "builtin_instance_counter": { + "pedersen_builtin": 23, + "range_check_builtin": 72 }, - "calldata_factor": { - "n_steps": 21, - "builtin_instance_counter": { - "pedersen_builtin": 2 - }, - "n_memory_holes": 0 - } - }, - "resources": { - "constant": { - "n_steps": 4137, - "builtin_instance_counter": { - "pedersen_builtin": 11, - "range_check_builtin": 77, - "poseidon_builtin": 10 - }, - "n_memory_holes": 0 + "n_memory_holes": 0 + }, + "calldata_factor": { + "n_steps": 21, + "builtin_instance_counter": { + "pedersen_builtin": 2 }, - "calldata_factor": { - "n_steps": 21, - "builtin_instance_counter": { - "pedersen_builtin": 2 - }, - "n_memory_holes": 0 - } + "n_memory_holes": 0 } }, "InvokeFunction": { - "deprecated_resources": { - "constant": { - "n_steps": 3763, - "builtin_instance_counter": { - "pedersen_builtin": 14, - "range_check_builtin": 69 - }, - "n_memory_holes": 0 + "constant": { + "n_steps": 3763, + "builtin_instance_counter": { + "pedersen_builtin": 14, + "range_check_builtin": 69 }, - "calldata_factor": { - "n_steps": 8, - "builtin_instance_counter": { - "pedersen_builtin": 1 - }, - "n_memory_holes": 0 - } - }, - "resources": { - "constant": { - "n_steps": 3904, - "builtin_instance_counter": { - "pedersen_builtin": 4, - "range_check_builtin": 74, - "poseidon_builtin": 11 - }, - "n_memory_holes": 0 + "n_memory_holes": 0 + }, + "calldata_factor": { + "n_steps": 8, + "builtin_instance_counter": { + "pedersen_builtin": 1 }, - "calldata_factor": { - "n_steps": 8, - "builtin_instance_counter": { - "pedersen_builtin": 1 - }, - "n_memory_holes": 0 - } + "n_memory_holes": 0 } }, "L1Handler": { - "deprecated_resources": { - "constant": { - "n_steps": 1233, - "builtin_instance_counter": { - "pedersen_builtin": 11, - "range_check_builtin": 16 - }, - "n_memory_holes": 0 + "constant": { + "n_steps": 1233, + "builtin_instance_counter": { + "pedersen_builtin": 11, + "range_check_builtin": 16 }, - "calldata_factor": { - "n_steps": 13, - "builtin_instance_counter": { - "pedersen_builtin": 1 - }, - "n_memory_holes": 0 - } - }, - "resources": { - "constant": { - "n_steps": 0, - "builtin_instance_counter": {}, - "n_memory_holes": 0 + "n_memory_holes": 0 + }, + "calldata_factor": { + "n_steps": 13, + "builtin_instance_counter": { + "pedersen_builtin": 1 }, - "calldata_factor": { - "n_steps": 13, - "builtin_instance_counter": { - "pedersen_builtin": 1 - }, - "n_memory_holes": 0 - } + "n_memory_holes": 0 } } }, @@ -600,7 +551,7 @@ } }, "validate_max_n_steps": 1000000, - "min_compiler_version_for_sierra_gas": "2.8.0", + "min_sierra_version_for_sierra_gas": "100.0.0", "vm_resource_fee_cost": { "builtins": { "add_mod_builtin": [ @@ -652,5 +603,6 @@ 25, 10000 ] - } + }, + "enable_tip": false } diff --git a/crates/blockifier/resources/versioned_constants_0_13_3.json b/crates/blockifier/resources/blockifier_versioned_constants_0_13_3.json similarity index 58% rename from crates/blockifier/resources/versioned_constants_0_13_3.json rename to crates/blockifier/resources/blockifier_versioned_constants_0_13_3.json index 0b740a12059..588164b2036 100644 --- a/crates/blockifier/resources/versioned_constants_0_13_3.json +++ b/crates/blockifier/resources/blockifier_versioned_constants_0_13_3.json @@ -39,6 +39,7 @@ }, "disable_cairo0_redeclaration": true, "enable_stateful_compression": false, + "comprehensive_state_diff": false, "allocation_cost": { "blob_cost": { "l1_gas": 0, @@ -56,27 +57,8 @@ "enable_reverts": false, "segment_arena_cells": false, "os_constants": { - "block_hash_contract_address": 1, - "call_contract_gas_cost": { - "entry_point_gas_cost": 1, - "step_gas_cost": 10, - "syscall_base_gas_cost": 1 - }, "constructor_entry_point_selector": "0x28ffe4ff0f226a9107253e17a904099aa4f63a02a5621de0576e5aa71bc5194", "default_entry_point_selector": 0, - "deploy_gas_cost": { - "entry_point_gas_cost": 1, - "step_gas_cost": 200, - "syscall_base_gas_cost": 1 - }, - "emit_event_gas_cost": { - "step_gas_cost": 10, - "syscall_base_gas_cost": 1 - }, - "entry_point_gas_cost": { - "entry_point_initial_budget": 1, - "step_gas_cost": 500 - }, "entry_point_initial_budget": { "step_gas_cost": 100 }, @@ -90,136 +72,167 @@ "error_entry_point_failed": "ENTRYPOINT_FAILED", "error_entry_point_not_found": "ENTRYPOINT_NOT_FOUND", "execute_entry_point_selector": "0x15d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad", - "fee_transfer_gas_cost": { - "entry_point_gas_cost": 1, - "step_gas_cost": 100 - }, - "get_block_hash_gas_cost": { - "step_gas_cost": 50, - "syscall_base_gas_cost": 1 - }, - "get_execution_info_gas_cost": { - "step_gas_cost": 10, - "syscall_base_gas_cost": 1 - }, + "execute_max_sierra_gas": 10000000000, "default_initial_gas_cost": { "step_gas_cost": 100000000 }, - "keccak_gas_cost": { - "syscall_base_gas_cost": 1 - }, - "keccak_round_cost_gas_cost": 180000, "l1_gas": "L1_GAS", "l1_gas_index": 0, "l1_handler_version": 0, "l2_gas": "L2_GAS", "l2_gas_index": 1, - "library_call_gas_cost": { - "call_contract_gas_cost": 1 - }, - "sha256_process_block_gas_cost": { - "step_gas_cost": 1852, - "range_check_gas_cost": 65, - "bitwise_builtin_gas_cost": 1115, - "syscall_base_gas_cost": 1 - }, "memory_hole_gas_cost": 10, "nop_entry_point_offset": -1, - "range_check_gas_cost": 70, - "pedersen_gas_cost": 0, - "bitwise_builtin_gas_cost": 594, - "ecop_gas_cost": 0, - "poseidon_gas_cost": 0, - "add_mod_gas_cost": 0, - "mul_mod_gas_cost": 0, - "replace_class_gas_cost": { - "step_gas_cost": 50, - "syscall_base_gas_cost": 1 - }, - "secp256k1_add_gas_cost": { - "range_check_gas_cost": 29, - "step_gas_cost": 406 - }, - "secp256k1_get_point_from_x_gas_cost": { - "memory_hole_gas_cost": 20, - "range_check_gas_cost": 30, - "step_gas_cost": 391 - }, - "secp256k1_get_xy_gas_cost": { - "memory_hole_gas_cost": 40, - "range_check_gas_cost": 11, - "step_gas_cost": 239 - }, - "secp256k1_mul_gas_cost": { - "memory_hole_gas_cost": 2, - "range_check_gas_cost": 7045, - "step_gas_cost": 76501 - }, - "secp256k1_new_gas_cost": { - "memory_hole_gas_cost": 40, - "range_check_gas_cost": 35, - "step_gas_cost": 475 - }, - "secp256r1_add_gas_cost": { - "range_check_gas_cost": 57, - "step_gas_cost": 589 - }, - "secp256r1_get_point_from_x_gas_cost": { - "memory_hole_gas_cost": 20, - "range_check_gas_cost": 44, - "step_gas_cost": 510 - }, - "secp256r1_get_xy_gas_cost": { - "memory_hole_gas_cost": 40, - "range_check_gas_cost": 11, - "step_gas_cost": 241 - }, - "secp256r1_mul_gas_cost": { - "memory_hole_gas_cost": 2, - "range_check_gas_cost": 13961, - "step_gas_cost": 125340 - }, - "secp256r1_new_gas_cost": { - "memory_hole_gas_cost": 40, - "range_check_gas_cost": 49, - "step_gas_cost": 594 - }, - "send_message_to_l1_gas_cost": { - "step_gas_cost": 50, - "syscall_base_gas_cost": 1 + "os_contract_addresses": { + "block_hash_contract_address": 1, + "alias_contract_address": 2, + "reserved_contract_address": 3 + }, + "builtin_gas_costs": { + "range_check": 70, + "range_check96": 0, + "keccak": 0, + "pedersen": 0, + "bitwise": 594, + "ecop": 0, + "poseidon": 0, + "add_mod": 0, + "mul_mod": 0, + "ecdsa": 0 + }, + "l1_handler_max_amount_bounds": { + "l1_gas": 10000000000, + "l1_data_gas": 10000000000, + "l2_gas": 10000000000 }, "sierra_array_len_bound": 4294967296, "step_gas_cost": 100, - "storage_read_gas_cost": { - "step_gas_cost": 50, - "syscall_base_gas_cost": 1 - }, - "storage_write_gas_cost": { - "step_gas_cost": 50, - "syscall_base_gas_cost": 1 - }, - "get_class_hash_at_gas_cost": { - "step_gas_cost": 0, - "syscall_base_gas_cost": 0 - }, "stored_block_hash_buffer": 10, "syscall_base_gas_cost": { "step_gas_cost": 100 }, - "transaction_gas_cost": { - "entry_point_gas_cost": 2, - "fee_transfer_gas_cost": 1, - "step_gas_cost": 100 - }, "transfer_entry_point_selector": "0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e", "validate_declare_entry_point_selector": "0x289da278a8dc833409cabfdad1581e8e7d40e42dcaed693fa4008dcdb4963b3", "validate_deploy_entry_point_selector": "0x36fcbf06cd96843058359e1a75928beacfac10727dab22a3972f0af8aa92895", "validate_entry_point_selector": "0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775", + "validate_max_sierra_gas": 10000000000, "validate_rounding_consts": { "validate_block_number_rounding": 100, "validate_timestamp_rounding": 3600 }, - "validated": "VALID" + "validated": "VALID", + "syscall_gas_costs": { + "call_contract": { + "step_gas_cost": 510, + "syscall_base_gas_cost": 1 + }, + "deploy": { + "step_gas_cost": 700, + "syscall_base_gas_cost": 1 + }, + "emit_event": { + "step_gas_cost": 10, + "syscall_base_gas_cost": 1 + }, + "get_block_hash": { + "step_gas_cost": 50, + "syscall_base_gas_cost": 1 + }, + "get_execution_info": { + "step_gas_cost": 10, + "syscall_base_gas_cost": 1 + }, + "keccak": { + "syscall_base_gas_cost": 1 + }, + "keccak_round_cost": 180000, + "library_call": { + "step_gas_cost": 510, + "syscall_base_gas_cost": 1 + }, + "meta_tx_v0": { + "syscall_base_gas_cost": 0, + "step_gas_cost": 0 + }, + "sha256_process_block": { + "step_gas_cost": 1852, + "range_check": 65, + "bitwise": 1115, + "syscall_base_gas_cost": 1 + }, + "replace_class": { + "step_gas_cost": 50, + "syscall_base_gas_cost": 1 + }, + "secp256k1_add": { + "range_check": 29, + "step_gas_cost": 406 + }, + "secp256k1_get_point_from_x": { + "memory_hole_gas_cost": 20, + "range_check": 30, + "step_gas_cost": 391 + }, + "secp256k1_get_xy": { + "memory_hole_gas_cost": 40, + "range_check": 11, + "step_gas_cost": 239 + }, + "secp256k1_mul": { + "memory_hole_gas_cost": 2, + "range_check": 7045, + "step_gas_cost": 76501 + }, + "secp256k1_new": { + "memory_hole_gas_cost": 40, + "range_check": 35, + "step_gas_cost": 475 + }, + "secp256r1_add": { + "range_check": 57, + "step_gas_cost": 589 + }, + "secp256r1_get_point_from_x": { + "memory_hole_gas_cost": 20, + "range_check": 44, + "step_gas_cost": 510 + }, + "secp256r1_get_xy": { + "memory_hole_gas_cost": 40, + "range_check": 11, + "step_gas_cost": 241 + }, + "secp256r1_mul": { + "memory_hole_gas_cost": 2, + "range_check": 13961, + "step_gas_cost": 125340 + }, + "secp256r1_new": { + "memory_hole_gas_cost": 40, + "range_check": 49, + "step_gas_cost": 594 + }, + "send_message_to_l1": { + "step_gas_cost": 50, + "syscall_base_gas_cost": 1 + }, + "storage_read": { + "step_gas_cost": 50, + "syscall_base_gas_cost": 1 + }, + "storage_write": { + "step_gas_cost": 50, + "syscall_base_gas_cost": 1 + }, + "get_class_hash_at": { + "step_gas_cost": 0, + "syscall_base_gas_cost": 0 + } + }, + "v1_bound_accounts_cairo0": [], + "v1_bound_accounts_cairo1": [], + "v1_bound_accounts_max_tip": "0x0", + "data_gas_accounts": [] }, "os_resources": { "execute_syscalls": { @@ -314,7 +327,7 @@ "builtin_instance_counter": {}, "n_memory_holes": 0 }, - "Keccak": { + "KeccakRound": { "n_steps": 381, "builtin_instance_counter": { "bitwise_builtin": 6, @@ -323,6 +336,11 @@ }, "n_memory_holes": 0 }, + "Keccak": { + "n_steps": 0, + "builtin_instance_counter": {}, + "n_memory_holes": 0 + }, "LibraryCall": { "n_steps": 818, "builtin_instance_counter": { @@ -337,6 +355,13 @@ }, "n_memory_holes": 0 }, + "MetaTxV0": { + "n_steps": 0, + "builtin_instance_counter": { + "range_check_builtin": 0 + }, + "n_memory_holes": 0 + }, "ReplaceClass": { "n_steps": 98, "builtin_instance_counter": { @@ -451,143 +476,69 @@ }, "execute_txs_inner": { "Declare": { - "deprecated_resources": { - "constant": { - "n_steps": 2973, - "builtin_instance_counter": { - "pedersen_builtin": 16, - "range_check_builtin": 53 - }, - "n_memory_holes": 0 - }, - "calldata_factor": { - "n_steps": 0, - "builtin_instance_counter": {}, - "n_memory_holes": 0 - } - }, - "resources": { - "constant": { - "n_steps": 3079, - "builtin_instance_counter": { - "pedersen_builtin": 4, - "range_check_builtin": 58, - "poseidon_builtin": 10 - }, - "n_memory_holes": 0 + "constant": { + "n_steps": 2973, + "builtin_instance_counter": { + "pedersen_builtin": 16, + "range_check_builtin": 53 }, - "calldata_factor": { - "n_steps": 0, - "builtin_instance_counter": {}, - "n_memory_holes": 0 - } + "n_memory_holes": 0 + }, + "calldata_factor": { + "n_steps": 0, + "builtin_instance_counter": {}, + "n_memory_holes": 0 } }, "DeployAccount": { - "deprecated_resources": { - "constant": { - "n_steps": 4015, - "builtin_instance_counter": { - "pedersen_builtin": 23, - "range_check_builtin": 72 - }, - "n_memory_holes": 0 + "constant": { + "n_steps": 4015, + "builtin_instance_counter": { + "pedersen_builtin": 23, + "range_check_builtin": 72 }, - "calldata_factor": { - "n_steps": 21, - "builtin_instance_counter": { - "pedersen_builtin": 2 - }, - "n_memory_holes": 0 - } - }, - "resources": { - "constant": { - "n_steps": 4137, - "builtin_instance_counter": { - "pedersen_builtin": 11, - "range_check_builtin": 77, - "poseidon_builtin": 10 - }, - "n_memory_holes": 0 + "n_memory_holes": 0 + }, + "calldata_factor": { + "n_steps": 21, + "builtin_instance_counter": { + "pedersen_builtin": 2 }, - "calldata_factor": { - "n_steps": 21, - "builtin_instance_counter": { - "pedersen_builtin": 2 - }, - "n_memory_holes": 0 - } + "n_memory_holes": 0 } }, "InvokeFunction": { - "deprecated_resources": { - "constant": { - "n_steps": 3763, - "builtin_instance_counter": { - "pedersen_builtin": 14, - "range_check_builtin": 69 - }, - "n_memory_holes": 0 + "constant": { + "n_steps": 3763, + "builtin_instance_counter": { + "pedersen_builtin": 14, + "range_check_builtin": 69 }, - "calldata_factor": { - "n_steps": 8, - "builtin_instance_counter": { - "pedersen_builtin": 1 - }, - "n_memory_holes": 0 - } - }, - "resources": { - "constant": { - "n_steps": 3904, - "builtin_instance_counter": { - "pedersen_builtin": 4, - "range_check_builtin": 74, - "poseidon_builtin": 11 - }, - "n_memory_holes": 0 + "n_memory_holes": 0 + }, + "calldata_factor": { + "n_steps": 8, + "builtin_instance_counter": { + "pedersen_builtin": 1 }, - "calldata_factor": { - "n_steps": 8, - "builtin_instance_counter": { - "pedersen_builtin": 1 - }, - "n_memory_holes": 0 - } + "n_memory_holes": 0 } }, "L1Handler": { - "deprecated_resources": { - "constant": { - "n_steps": 1233, - "builtin_instance_counter": { - "pedersen_builtin": 11, - "range_check_builtin": 16 - }, - "n_memory_holes": 0 + "constant": { + "n_steps": 1233, + "builtin_instance_counter": { + "pedersen_builtin": 11, + "range_check_builtin": 16 }, - "calldata_factor": { - "n_steps": 13, - "builtin_instance_counter": { - "pedersen_builtin": 1 - }, - "n_memory_holes": 0 - } - }, - "resources": { - "constant": { - "n_steps": 0, - "builtin_instance_counter": {}, - "n_memory_holes": 0 + "n_memory_holes": 0 + }, + "calldata_factor": { + "n_steps": 13, + "builtin_instance_counter": { + "pedersen_builtin": 1 }, - "calldata_factor": { - "n_steps": 13, - "builtin_instance_counter": { - "pedersen_builtin": 1 - }, - "n_memory_holes": 0 - } + "n_memory_holes": 0 } } }, @@ -600,7 +551,7 @@ } }, "validate_max_n_steps": 1000000, - "min_compiler_version_for_sierra_gas": "2.8.0", + "min_sierra_version_for_sierra_gas": "100.0.0", "vm_resource_fee_cost": { "builtins": { "add_mod_builtin": [ @@ -652,5 +603,6 @@ 25, 10000 ] - } + }, + "enable_tip": false } diff --git a/crates/blockifier/resources/versioned_constants_0_13_4.json b/crates/blockifier/resources/blockifier_versioned_constants_0_13_4.json similarity index 58% rename from crates/blockifier/resources/versioned_constants_0_13_4.json rename to crates/blockifier/resources/blockifier_versioned_constants_0_13_4.json index 3c1703482bf..7189b2bb4a9 100644 --- a/crates/blockifier/resources/versioned_constants_0_13_4.json +++ b/crates/blockifier/resources/blockifier_versioned_constants_0_13_4.json @@ -39,6 +39,7 @@ }, "disable_cairo0_redeclaration": true, "enable_stateful_compression": true, + "comprehensive_state_diff": true, "allocation_cost": { "blob_cost": { "l1_gas": 0, @@ -56,28 +57,8 @@ "max_recursion_depth": 50, "segment_arena_cells": false, "os_constants": { - "block_hash_contract_address": 1, - "call_contract_gas_cost": { - "entry_point_gas_cost": 1, - "step_gas_cost": 860, - "range_check_gas_cost": 15 - }, "constructor_entry_point_selector": "0x28ffe4ff0f226a9107253e17a904099aa4f63a02a5621de0576e5aa71bc5194", "default_entry_point_selector": 0, - "deploy_gas_cost": { - "entry_point_gas_cost": 1, - "step_gas_cost": 1128, - "range_check_gas_cost": 18, - "pedersen_gas_cost": 7 - }, - "emit_event_gas_cost": { - "step_gas_cost": 100, - "range_check_gas_cost": 1 - }, - "entry_point_gas_cost": { - "entry_point_initial_budget": 1, - "step_gas_cost": 500 - }, "entry_point_initial_budget": { "step_gas_cost": 100 }, @@ -91,21 +72,10 @@ "error_entry_point_failed": "ENTRYPOINT_FAILED", "error_entry_point_not_found": "ENTRYPOINT_NOT_FOUND", "execute_entry_point_selector": "0x15d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad", - "get_block_hash_gas_cost": { - "step_gas_cost": 104, - "range_check_gas_cost": 2 - }, - "get_execution_info_gas_cost": { - "step_gas_cost": 100, - "range_check_gas_cost": 1 - }, + "execute_max_sierra_gas": 1000000000, "default_initial_gas_cost": { "step_gas_cost": 100000000 }, - "keccak_gas_cost": { - "syscall_base_gas_cost": 1 - }, - "keccak_round_cost_gas_cost": 180000, "l1_gas": "L1_GAS", "l1_gas_index": 0, "l1_handler_version": 0, @@ -113,115 +83,50 @@ "l1_data_gas": "L1_DATA", "l1_data_gas_index": 2, "l2_gas_index": 1, - "library_call_gas_cost": { - "entry_point_gas_cost": 1, - "step_gas_cost": 836, - "range_check_gas_cost": 15 - }, - "sha256_process_block_gas_cost": { - "step_gas_cost": 1855, - "range_check_gas_cost": 65, - "bitwise_builtin_gas_cost": 1115, - "syscall_base_gas_cost": 1 - }, "memory_hole_gas_cost": 10, "nop_entry_point_offset": -1, - "range_check_gas_cost": 70, - "pedersen_gas_cost": 4050, - "bitwise_builtin_gas_cost": 583, - "ecop_gas_cost": 4085, - "poseidon_gas_cost": 491, - "add_mod_gas_cost": 230, - "mul_mod_gas_cost": 604, - "replace_class_gas_cost": { - "step_gas_cost": 104, - "range_check_gas_cost": 1 - }, - "secp256k1_add_gas_cost": { - "range_check_gas_cost": 29, - "step_gas_cost": 410 - }, - "secp256k1_get_point_from_x_gas_cost": { - "memory_hole_gas_cost": 20, - "range_check_gas_cost": 30, - "step_gas_cost": 395 - }, - "secp256k1_get_xy_gas_cost": { - "memory_hole_gas_cost": 40, - "range_check_gas_cost": 11, - "step_gas_cost": 207 - }, - "secp256k1_mul_gas_cost": { - "memory_hole_gas_cost": 2, - "range_check_gas_cost": 7045, - "step_gas_cost": 76505 - }, - "secp256k1_new_gas_cost": { - "memory_hole_gas_cost": 40, - "range_check_gas_cost": 35, - "step_gas_cost": 461 - }, - "secp256r1_add_gas_cost": { - "range_check_gas_cost": 57, - "step_gas_cost": 593 - }, - "secp256r1_get_point_from_x_gas_cost": { - "memory_hole_gas_cost": 20, - "range_check_gas_cost": 44, - "step_gas_cost": 514 - }, - "secp256r1_get_xy_gas_cost": { - "memory_hole_gas_cost": 40, - "range_check_gas_cost": 11, - "step_gas_cost": 209 - }, - "secp256r1_mul_gas_cost": { - "memory_hole_gas_cost": 2, - "range_check_gas_cost": 13961, - "step_gas_cost": 125344 - }, - "secp256r1_new_gas_cost": { - "memory_hole_gas_cost": 40, - "range_check_gas_cost": 49, - "step_gas_cost": 580 - }, - "send_message_to_l1_gas_cost": { - "step_gas_cost": 141, - "range_check_gas_cost": 1 + "os_contract_addresses": { + "block_hash_contract_address": 1, + "alias_contract_address": 2, + "reserved_contract_address": 3 + }, + "builtin_gas_costs": { + "range_check": 70, + "range_check96": 56, + "keccak": 136189, + "pedersen": 4050, + "bitwise": 583, + "ecop": 4085, + "poseidon": 491, + "add_mod": 230, + "mul_mod": 604, + "ecdsa": 10561 + }, + "l1_handler_max_amount_bounds": { + "l1_gas": 10000000000, + "l1_data_gas": 10000000000, + "l2_gas": 1000000000 }, "sierra_array_len_bound": 4294967296, "step_gas_cost": 100, - "storage_read_gas_cost": { - "step_gas_cost": 100, - "range_check_gas_cost": 1 - }, - "storage_write_gas_cost": { - "step_gas_cost": 100, - "range_check_gas_cost": 1 - }, - "get_class_hash_at_gas_cost": { - "step_gas_cost": 100, - "range_check_gas_cost": 1 - }, "stored_block_hash_buffer": 10, "syscall_base_gas_cost": { "step_gas_cost": 100 }, - "transaction_gas_cost": { - "step_gas_cost": 4098, - "pedersen_gas_cost": 4, - "range_check_gas_cost": 77, - "poseidon_gas_cost": 11 - }, "transfer_entry_point_selector": "0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e", "validate_declare_entry_point_selector": "0x289da278a8dc833409cabfdad1581e8e7d40e42dcaed693fa4008dcdb4963b3", "validate_deploy_entry_point_selector": "0x36fcbf06cd96843058359e1a75928beacfac10727dab22a3972f0af8aa92895", "validate_entry_point_selector": "0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775", + "validate_max_sierra_gas": 100000000, "validate_rounding_consts": { "validate_block_number_rounding": 100, "validate_timestamp_rounding": 3600 }, - "validated": "VALID" + "validated": "VALID", + "v1_bound_accounts_cairo0": [], + "v1_bound_accounts_cairo1": [], + "v1_bound_accounts_max_tip": "0x0", + "data_gas_accounts": [] }, "os_resources": { "execute_syscalls": { @@ -316,8 +221,8 @@ "builtin_instance_counter": {}, "n_memory_holes": 0 }, - "Keccak": { - "n_steps": 381, + "KeccakRound": { + "n_steps": 281, "builtin_instance_counter": { "bitwise_builtin": 6, "keccak_builtin": 1, @@ -325,6 +230,11 @@ }, "n_memory_holes": 0 }, + "Keccak": { + "n_steps": 100, + "builtin_instance_counter": {}, + "n_memory_holes": 0 + }, "LibraryCall": { "n_steps": 842, "builtin_instance_counter": { @@ -339,6 +249,13 @@ }, "n_memory_holes": 0 }, + "MetaTxV0": { + "n_steps": 0, + "builtin_instance_counter": { + "range_check_builtin": 0 + }, + "n_memory_holes": 0 + }, "ReplaceClass": { "n_steps": 104, "builtin_instance_counter": { @@ -455,144 +372,70 @@ }, "execute_txs_inner": { "Declare": { - "deprecated_resources": { - "constant": { - "n_steps": 3203, - "builtin_instance_counter": { - "pedersen_builtin": 16, - "range_check_builtin": 56, - "poseidon_builtin": 4 - }, - "n_memory_holes": 0 + "constant": { + "n_steps": 3203, + "builtin_instance_counter": { + "pedersen_builtin": 16, + "range_check_builtin": 56, + "poseidon_builtin": 4 }, - "calldata_factor": { - "n_steps": 0, - "builtin_instance_counter": {}, - "n_memory_holes": 0 - } - }, - "resources": { - "constant": { - "n_steps": 3346, - "builtin_instance_counter": { - "pedersen_builtin": 4, - "range_check_builtin": 64, - "poseidon_builtin": 14 - }, - "n_memory_holes": 0 - }, - "calldata_factor": { - "n_steps": 0, - "builtin_instance_counter": {}, - "n_memory_holes": 0 - } + "n_memory_holes": 0 + }, + "calldata_factor": { + "n_steps": 0, + "builtin_instance_counter": {}, + "n_memory_holes": 0 } }, "DeployAccount": { - "deprecated_resources": { - "constant": { - "n_steps": 4161, - "builtin_instance_counter": { - "pedersen_builtin": 23, - "range_check_builtin": 72 - }, - "n_memory_holes": 0 + "constant": { + "n_steps": 4161, + "builtin_instance_counter": { + "pedersen_builtin": 23, + "range_check_builtin": 72 }, - "calldata_factor": { - "n_steps": 21, - "builtin_instance_counter": { - "pedersen_builtin": 2 - }, - "n_memory_holes": 0 - } - }, - "resources": { - "constant": { - "n_steps": 4321, - "builtin_instance_counter": { - "pedersen_builtin": 11, - "range_check_builtin": 80, - "poseidon_builtin": 10 - }, - "n_memory_holes": 0 + "n_memory_holes": 0 + }, + "calldata_factor": { + "n_steps": 21, + "builtin_instance_counter": { + "pedersen_builtin": 2 }, - "calldata_factor": { - "n_steps": 21, - "builtin_instance_counter": { - "pedersen_builtin": 2 - }, - "n_memory_holes": 0 - } + "n_memory_holes": 0 } }, "InvokeFunction": { - "deprecated_resources": { - "constant": { - "n_steps": 3918, - "builtin_instance_counter": { - "pedersen_builtin": 14, - "range_check_builtin": 69 - }, - "n_memory_holes": 0 + "constant": { + "n_steps": 3918, + "builtin_instance_counter": { + "pedersen_builtin": 14, + "range_check_builtin": 69 }, - "calldata_factor": { - "n_steps": 8, - "builtin_instance_counter": { - "pedersen_builtin": 1 - }, - "n_memory_holes": 0 - } - }, - "resources": { - "constant": { - "n_steps": 4102, - "builtin_instance_counter": { - "pedersen_builtin": 4, - "range_check_builtin": 77, - "poseidon_builtin": 11 - }, - "n_memory_holes": 0 + "n_memory_holes": 0 + }, + "calldata_factor": { + "n_steps": 8, + "builtin_instance_counter": { + "pedersen_builtin": 1 }, - "calldata_factor": { - "n_steps": 8, - "builtin_instance_counter": { - "pedersen_builtin": 1 - }, - "n_memory_holes": 0 - } + "n_memory_holes": 0 } }, "L1Handler": { - "deprecated_resources": { - "constant": { - "n_steps": 1279, - "builtin_instance_counter": { - "pedersen_builtin": 11, - "range_check_builtin": 16 - }, - "n_memory_holes": 0 + "constant": { + "n_steps": 1279, + "builtin_instance_counter": { + "pedersen_builtin": 11, + "range_check_builtin": 16 }, - "calldata_factor": { - "n_steps": 13, - "builtin_instance_counter": { - "pedersen_builtin": 1 - }, - "n_memory_holes": 0 - } - }, - "resources": { - "constant": { - "n_steps": 0, - "builtin_instance_counter": {}, - "n_memory_holes": 0 + "n_memory_holes": 0 + }, + "calldata_factor": { + "n_steps": 13, + "builtin_instance_counter": { + "pedersen_builtin": 1 }, - "calldata_factor": { - "n_steps": 13, - "builtin_instance_counter": { - "pedersen_builtin": 1 - }, - "n_memory_holes": 0 - } + "n_memory_holes": 0 } } }, @@ -605,7 +448,7 @@ } }, "validate_max_n_steps": 1000000, - "min_compiler_version_for_sierra_gas": "2.8.0", + "min_sierra_version_for_sierra_gas": "1.7.0", "vm_resource_fee_cost": { "builtins": { "add_mod_builtin": [ @@ -657,5 +500,6 @@ 25, 10000 ] - } + }, + "enable_tip": false } diff --git a/crates/blockifier/resources/blockifier_versioned_constants_0_13_5.json b/crates/blockifier/resources/blockifier_versioned_constants_0_13_5.json new file mode 100644 index 00000000000..643a98615c1 --- /dev/null +++ b/crates/blockifier/resources/blockifier_versioned_constants_0_13_5.json @@ -0,0 +1,527 @@ +{ + "tx_event_limits": { + "max_data_length": 300, + "max_keys_length": 50, + "max_n_emitted_events": 1000 + }, + "gateway": { + "max_calldata_length": 5000, + "max_contract_bytecode_size": 81920 + }, + "invoke_tx_max_n_steps": 10000000, + "deprecated_l2_resource_gas_costs": { + "gas_per_data_felt": [ + 128, + 1000 + ], + "event_key_factor": [ + 2, + 1 + ], + "gas_per_code_byte": [ + 32, + 1000 + ] + }, + "archival_data_gas_costs": { + "gas_per_data_felt": [ + 5120, + 1 + ], + "event_key_factor": [ + 2, + 1 + ], + "gas_per_code_byte": [ + 1280, + 1 + ] + }, + "disable_cairo0_redeclaration": true, + "enable_stateful_compression": true, + "comprehensive_state_diff": true, + "allocation_cost": { + "blob_cost": { + "l1_gas": 0, + "l1_data_gas": 32, + "l2_gas": 0 + }, + "gas_cost": { + "l1_gas": 551, + "l1_data_gas": 0, + "l2_gas": 0 + } + }, + "ignore_inner_event_resources": false, + "enable_reverts": true, + "max_recursion_depth": 50, + "segment_arena_cells": false, + "os_constants": { + "constructor_entry_point_selector": "0x28ffe4ff0f226a9107253e17a904099aa4f63a02a5621de0576e5aa71bc5194", + "default_entry_point_selector": 0, + "entry_point_initial_budget": { + "step_gas_cost": 100 + }, + "entry_point_type_constructor": 2, + "entry_point_type_external": 0, + "entry_point_type_l1_handler": 1, + "error_block_number_out_of_range": "Block number out of range", + "error_invalid_input_len": "Invalid input length", + "error_invalid_argument": "Invalid argument", + "error_out_of_gas": "Out of gas", + "error_entry_point_failed": "ENTRYPOINT_FAILED", + "error_entry_point_not_found": "ENTRYPOINT_NOT_FOUND", + "execute_entry_point_selector": "0x15d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad", + "execute_max_sierra_gas": 1000000000, + "default_initial_gas_cost": { + "step_gas_cost": 100000000 + }, + "l1_gas": "L1_GAS", + "l1_gas_index": 0, + "l1_handler_version": 0, + "l2_gas": "L2_GAS", + "l1_data_gas": "L1_DATA", + "l1_data_gas_index": 2, + "l2_gas_index": 1, + "memory_hole_gas_cost": 10, + "nop_entry_point_offset": -1, + "os_contract_addresses": { + "block_hash_contract_address": 1, + "alias_contract_address": 2, + "reserved_contract_address": 3 + }, + "builtin_gas_costs": { + "range_check": 70, + "range_check96": 56, + "keccak": 136189, + "pedersen": 4050, + "bitwise": 583, + "ecop": 4085, + "poseidon": 491, + "add_mod": 230, + "mul_mod": 604, + "ecdsa": 10561 + }, + "l1_handler_max_amount_bounds": { + "l1_gas": 10000000000, + "l1_data_gas": 10000000000, + "l2_gas": 1000000000 + }, + "sierra_array_len_bound": 4294967296, + "step_gas_cost": 100, + "stored_block_hash_buffer": 10, + "syscall_base_gas_cost": { + "step_gas_cost": 100 + }, + "transfer_entry_point_selector": "0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e", + "validate_declare_entry_point_selector": "0x289da278a8dc833409cabfdad1581e8e7d40e42dcaed693fa4008dcdb4963b3", + "validate_deploy_entry_point_selector": "0x36fcbf06cd96843058359e1a75928beacfac10727dab22a3972f0af8aa92895", + "validate_entry_point_selector": "0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775", + "validate_max_sierra_gas": 100000000, + "validate_rounding_consts": { + "validate_block_number_rounding": 100, + "validate_timestamp_rounding": 3600 + }, + "validated": "VALID", + "v1_bound_accounts_cairo0": [ + "0x06d706cfbac9b8262d601c38251c5fbe0497c3a96cc91a92b08d91b61d9e70c4", + "0x0309c042d3729173c7f2f91a34f04d8c509c1b292d334679ef1aabf8da0899cc", + "0x01a7820094feaf82d53f53f214b81292d717e7bb9a92bb2488092cd306f3993f", + "0x033434ad846cdd5f23eb73ff09fe6fddd568284a0fb7d1be20ee482f044dabe2" + ], + "v1_bound_accounts_cairo1": [ + "0x01a736d6ed154502257f02b1ccdf4d9d1089f80811cd6acad48e6b6a9d1f2003", + "0x0737ee2f87ce571a58c6c8da558ec18a07ceb64a6172d5ec46171fbc80077a48", + "0x05400e90f7e0ae78bd02c77cd75527280470e2fe19c54970dd79dc37a9d3645c", + "0x04c6d6cf894f8bc96bb9c525e6853e5483177841f7388f74a46cfda6f028c755", + "0x01c0bb51e2ce73dc007601a1e7725453627254016c28f118251a71bbb0507fcb", + "0x0251830adc3d8b4d818c2c309d71f1958308e8c745212480c26e01120c69ee49", + "0x0251cac7b2f45d255b83b7a06dcdef70c8a8752f00ea776517c1c2243c7a06e5" + ], + "v1_bound_accounts_max_tip": "0x746a5288000", + "data_gas_accounts": [] + }, + "os_resources": { + "execute_syscalls": { + "CallContract": { + "n_steps": 866, + "builtin_instance_counter": { + "range_check_builtin": 15 + }, + "n_memory_holes": 0 + }, + "DelegateCall": { + "n_steps": 713, + "builtin_instance_counter": { + "range_check_builtin": 19 + }, + "n_memory_holes": 0 + }, + "DelegateL1Handler": { + "n_steps": 692, + "builtin_instance_counter": { + "range_check_builtin": 15 + }, + "n_memory_holes": 0 + }, + "Deploy": { + "constant": { + "n_steps": 1132, + "builtin_instance_counter": { + "pedersen_builtin": 7, + "range_check_builtin": 18 + }, + "n_memory_holes": 0 + }, + "calldata_factor": { + "n_steps": 8, + "builtin_instance_counter": { + "pedersen_builtin": 1 + }, + "n_memory_holes": 0 + } + }, + "EmitEvent": { + "n_steps": 61, + "builtin_instance_counter": { + "range_check_builtin": 1 + }, + "n_memory_holes": 0 + }, + "GetBlockHash": { + "n_steps": 104, + "builtin_instance_counter": { + "range_check_builtin": 2 + }, + "n_memory_holes": 0 + }, + "GetBlockNumber": { + "n_steps": 40, + "builtin_instance_counter": {}, + "n_memory_holes": 0 + }, + "GetBlockTimestamp": { + "n_steps": 38, + "builtin_instance_counter": {}, + "n_memory_holes": 0 + }, + "GetCallerAddress": { + "n_steps": 64, + "builtin_instance_counter": { + "range_check_builtin": 1 + }, + "n_memory_holes": 0 + }, + "GetContractAddress": { + "n_steps": 64, + "builtin_instance_counter": { + "range_check_builtin": 1 + }, + "n_memory_holes": 0 + }, + "GetExecutionInfo": { + "n_steps": 64, + "builtin_instance_counter": { + "range_check_builtin": 1 + }, + "n_memory_holes": 0 + }, + "GetSequencerAddress": { + "n_steps": 34, + "builtin_instance_counter": {}, + "n_memory_holes": 0 + }, + "GetTxInfo": { + "n_steps": 64, + "builtin_instance_counter": { + "range_check_builtin": 1 + }, + "n_memory_holes": 0 + }, + "GetTxSignature": { + "n_steps": 44, + "builtin_instance_counter": {}, + "n_memory_holes": 0 + }, + "KeccakRound": { + "n_steps": 281, + "builtin_instance_counter": { + "bitwise_builtin": 6, + "keccak_builtin": 1, + "range_check_builtin": 56 + }, + "n_memory_holes": 0 + }, + "Keccak": { + "n_steps": 100, + "builtin_instance_counter": {}, + "n_memory_holes": 0 + }, + "LibraryCall": { + "n_steps": 842, + "builtin_instance_counter": { + "range_check_builtin": 15 + }, + "n_memory_holes": 0 + }, + "LibraryCallL1Handler": { + "n_steps": 659, + "builtin_instance_counter": { + "range_check_builtin": 15 + }, + "n_memory_holes": 0 + }, + "MetaTxV0": { + "n_steps": 0, + "builtin_instance_counter": { + "range_check_builtin": 0 + }, + "n_memory_holes": 0 + }, + "ReplaceClass": { + "n_steps": 104, + "builtin_instance_counter": { + "range_check_builtin": 1 + }, + "n_memory_holes": 0 + }, + "Secp256k1Add": { + "n_steps": 410, + "builtin_instance_counter": { + "range_check_builtin": 29 + }, + "n_memory_holes": 0 + }, + "Secp256k1GetPointFromX": { + "n_steps": 395, + "builtin_instance_counter": { + "range_check_builtin": 30 + }, + "n_memory_holes": 0 + }, + "Secp256k1GetXy": { + "n_steps": 207, + "builtin_instance_counter": { + "range_check_builtin": 11 + }, + "n_memory_holes": 0 + }, + "Secp256k1Mul": { + "n_steps": 76505, + "builtin_instance_counter": { + "range_check_builtin": 7045 + }, + "n_memory_holes": 0 + }, + "Secp256k1New": { + "n_steps": 461, + "builtin_instance_counter": { + "range_check_builtin": 35 + }, + "n_memory_holes": 0 + }, + "Secp256r1Add": { + "n_steps": 593, + "builtin_instance_counter": { + "range_check_builtin": 57 + }, + "n_memory_holes": 0 + }, + "Secp256r1GetPointFromX": { + "n_steps": 514, + "builtin_instance_counter": { + "range_check_builtin": 44 + }, + "n_memory_holes": 0 + }, + "Secp256r1GetXy": { + "n_steps": 209, + "builtin_instance_counter": { + "range_check_builtin": 11 + }, + "n_memory_holes": 0 + }, + "Secp256r1Mul": { + "n_steps": 125344, + "builtin_instance_counter": { + "range_check_builtin": 13961 + }, + "n_memory_holes": 0 + }, + "Secp256r1New": { + "n_steps": 580, + "builtin_instance_counter": { + "range_check_builtin": 49 + }, + "n_memory_holes": 0 + }, + "SendMessageToL1": { + "n_steps": 141, + "builtin_instance_counter": { + "range_check_builtin": 1 + }, + "n_memory_holes": 0 + }, + "Sha256ProcessBlock": { + "n_steps": 1865, + "builtin_instance_counter": { + "range_check_builtin": 65, + "bitwise_builtin": 1115 + }, + "n_memory_holes": 0 + }, + "StorageRead": { + "n_steps": 87, + "builtin_instance_counter": { + "range_check_builtin": 1 + }, + "n_memory_holes": 0 + }, + "StorageWrite": { + "n_steps": 93, + "builtin_instance_counter": { + "range_check_builtin": 1 + }, + "n_memory_holes": 0 + }, + "GetClassHashAt": { + "n_steps": 89, + "builtin_instance_counter": { + "range_check_builtin": 1 + }, + "n_memory_holes": 0 + } + }, + "execute_txs_inner": { + "Declare": { + "constant": { + "n_steps": 3203, + "builtin_instance_counter": { + "pedersen_builtin": 16, + "range_check_builtin": 56, + "poseidon_builtin": 4 + }, + "n_memory_holes": 0 + }, + "calldata_factor": { + "n_steps": 0, + "builtin_instance_counter": {}, + "n_memory_holes": 0 + } + }, + "DeployAccount": { + "constant": { + "n_steps": 4161, + "builtin_instance_counter": { + "pedersen_builtin": 23, + "range_check_builtin": 72 + }, + "n_memory_holes": 0 + }, + "calldata_factor": { + "n_steps": 21, + "builtin_instance_counter": { + "pedersen_builtin": 2 + }, + "n_memory_holes": 0 + } + }, + "InvokeFunction": { + "constant": { + "n_steps": 3918, + "builtin_instance_counter": { + "pedersen_builtin": 14, + "range_check_builtin": 69 + }, + "n_memory_holes": 0 + }, + "calldata_factor": { + "n_steps": 8, + "builtin_instance_counter": { + "pedersen_builtin": 1 + }, + "n_memory_holes": 0 + } + }, + "L1Handler": { + "constant": { + "n_steps": 1279, + "builtin_instance_counter": { + "pedersen_builtin": 11, + "range_check_builtin": 16 + }, + "n_memory_holes": 0 + }, + "calldata_factor": { + "n_steps": 13, + "builtin_instance_counter": { + "pedersen_builtin": 1 + }, + "n_memory_holes": 0 + } + } + }, + "compute_os_kzg_commitment_info": { + "n_steps": 113, + "builtin_instance_counter": { + "range_check_builtin": 17 + }, + "n_memory_holes": 0 + } + }, + "validate_max_n_steps": 1000000, + "min_sierra_version_for_sierra_gas": "1.7.0", + "vm_resource_fee_cost": { + "builtins": { + "add_mod_builtin": [ + 4, + 100 + ], + "bitwise_builtin": [ + 16, + 100 + ], + "ec_op_builtin": [ + 256, + 100 + ], + "ecdsa_builtin": [ + 512, + 100 + ], + "keccak_builtin": [ + 512, + 100 + ], + "mul_mod_builtin": [ + 4, + 100 + ], + "output_builtin": [ + 0, + 1 + ], + "pedersen_builtin": [ + 8, + 100 + ], + "poseidon_builtin": [ + 8, + 100 + ], + "range_check_builtin": [ + 4, + 100 + ], + "range_check96_builtin": [ + 4, + 100 + ] + }, + "n_steps": [ + 25, + 10000 + ] + }, + "enable_tip": false +} diff --git a/crates/blockifier/resources/blockifier_versioned_constants_0_14_0.json b/crates/blockifier/resources/blockifier_versioned_constants_0_14_0.json new file mode 100644 index 00000000000..9d47995959d --- /dev/null +++ b/crates/blockifier/resources/blockifier_versioned_constants_0_14_0.json @@ -0,0 +1,536 @@ +{ + "tx_event_limits": { + "max_data_length": 300, + "max_keys_length": 50, + "max_n_emitted_events": 1000 + }, + "gateway": { + "max_calldata_length": 5000, + "max_contract_bytecode_size": 81920 + }, + "invoke_tx_max_n_steps": 10000000, + "deprecated_l2_resource_gas_costs": { + "gas_per_data_felt": [ + 128, + 1000 + ], + "event_key_factor": [ + 2, + 1 + ], + "gas_per_code_byte": [ + 32, + 1000 + ] + }, + "archival_data_gas_costs": { + "gas_per_data_felt": [ + 5120, + 1 + ], + "event_key_factor": [ + 2, + 1 + ], + "gas_per_code_byte": [ + 1280, + 1 + ] + }, + "disable_cairo0_redeclaration": true, + "enable_stateful_compression": true, + "comprehensive_state_diff": true, + "allocation_cost": { + "blob_cost": { + "l1_gas": 0, + "l1_data_gas": 32, + "l2_gas": 0 + }, + "gas_cost": { + "l1_gas": 551, + "l1_data_gas": 0, + "l2_gas": 0 + } + }, + "ignore_inner_event_resources": false, + "enable_reverts": true, + "max_recursion_depth": 50, + "segment_arena_cells": false, + "os_constants": { + "constructor_entry_point_selector": "0x28ffe4ff0f226a9107253e17a904099aa4f63a02a5621de0576e5aa71bc5194", + "default_entry_point_selector": 0, + "entry_point_initial_budget": { + "step_gas_cost": 100 + }, + "entry_point_type_constructor": 2, + "entry_point_type_external": 0, + "entry_point_type_l1_handler": 1, + "error_block_number_out_of_range": "Block number out of range", + "error_invalid_input_len": "Invalid input length", + "error_invalid_argument": "Invalid argument", + "error_out_of_gas": "Out of gas", + "error_entry_point_failed": "ENTRYPOINT_FAILED", + "error_entry_point_not_found": "ENTRYPOINT_NOT_FOUND", + "execute_entry_point_selector": "0x15d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad", + "execute_max_sierra_gas": 1000000000, + "default_initial_gas_cost": { + "step_gas_cost": 100000000 + }, + "l1_gas": "L1_GAS", + "l1_gas_index": 0, + "l1_handler_version": 0, + "l2_gas": "L2_GAS", + "l1_data_gas": "L1_DATA", + "l1_data_gas_index": 2, + "l2_gas_index": 1, + "memory_hole_gas_cost": 10, + "nop_entry_point_offset": -1, + "os_contract_addresses": { + "block_hash_contract_address": 1, + "alias_contract_address": 2, + "reserved_contract_address": 3 + }, + "builtin_gas_costs": { + "range_check": 70, + "range_check96": 56, + "keccak": 136189, + "pedersen": 4050, + "bitwise": 583, + "ecop": 4085, + "poseidon": 491, + "add_mod": 230, + "mul_mod": 604, + "ecdsa": 10561 + }, + "l1_handler_max_amount_bounds": { + "l1_gas": 40000, + "l1_data_gas": 20000, + "l2_gas": 1000000 + }, + "sierra_array_len_bound": 4294967296, + "step_gas_cost": 100, + "stored_block_hash_buffer": 10, + "syscall_base_gas_cost": { + "step_gas_cost": 100 + }, + "transfer_entry_point_selector": "0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e", + "validate_declare_entry_point_selector": "0x289da278a8dc833409cabfdad1581e8e7d40e42dcaed693fa4008dcdb4963b3", + "validate_deploy_entry_point_selector": "0x36fcbf06cd96843058359e1a75928beacfac10727dab22a3972f0af8aa92895", + "validate_entry_point_selector": "0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775", + "validate_max_sierra_gas": 100000000, + "validate_rounding_consts": { + "validate_block_number_rounding": 100, + "validate_timestamp_rounding": 3600 + }, + "validated": "VALID", + "v1_bound_accounts_cairo0": [ + "0x06d706cfbac9b8262d601c38251c5fbe0497c3a96cc91a92b08d91b61d9e70c4", + "0x0309c042d3729173c7f2f91a34f04d8c509c1b292d334679ef1aabf8da0899cc", + "0x01a7820094feaf82d53f53f214b81292d717e7bb9a92bb2488092cd306f3993f", + "0x033434ad846cdd5f23eb73ff09fe6fddd568284a0fb7d1be20ee482f044dabe2" + ], + "v1_bound_accounts_cairo1": [ + "0x01a736d6ed154502257f02b1ccdf4d9d1089f80811cd6acad48e6b6a9d1f2003", + "0x0737ee2f87ce571a58c6c8da558ec18a07ceb64a6172d5ec46171fbc80077a48", + "0x05400e90f7e0ae78bd02c77cd75527280470e2fe19c54970dd79dc37a9d3645c", + "0x04c6d6cf894f8bc96bb9c525e6853e5483177841f7388f74a46cfda6f028c755", + "0x01c0bb51e2ce73dc007601a1e7725453627254016c28f118251a71bbb0507fcb", + "0x0251830adc3d8b4d818c2c309d71f1958308e8c745212480c26e01120c69ee49", + "0x0251cac7b2f45d255b83b7a06dcdef70c8a8752f00ea776517c1c2243c7a06e5" + ], + "v1_bound_accounts_max_tip": "0x746a5288000", + "data_gas_accounts": [ + "0x02c8c7e6fbcfb3e8e15a46648e8914c6aa1fc506fc1e7fb3d1e19630716174bc", + "0x00816dd0297efc55dc1e7559020a3a825e81ef734b558f03c83325d4da7e6253", + "0x041bf1e71792aecb9df3e9d04e1540091c5e13122a731e02bec588f71dc1a5c3" + ] + }, + "os_resources": { + "execute_syscalls": { + "CallContract": { + "builtin_instance_counter": { + "range_check_builtin": 16 + }, + "n_memory_holes": 0, + "n_steps": 903 + }, + "DelegateCall": { + "builtin_instance_counter": { + "range_check_builtin": 19 + }, + "n_memory_holes": 0, + "n_steps": 713 + }, + "DelegateL1Handler": { + "builtin_instance_counter": { + "range_check_builtin": 15 + }, + "n_memory_holes": 0, + "n_steps": 692 + }, + "Deploy": { + "constant": { + "builtin_instance_counter": { + "pedersen_builtin": 7, + "range_check_builtin": 19 + }, + "n_memory_holes": 0, + "n_steps": 1173 + }, + "calldata_factor": { + "n_steps": 8, + "builtin_instance_counter": { + "pedersen_builtin": 1 + }, + "n_memory_holes": 0 + } + }, + "EmitEvent": { + "builtin_instance_counter": { + "range_check_builtin": 1 + }, + "n_memory_holes": 0, + "n_steps": 61 + }, + "GetBlockHash": { + "builtin_instance_counter": { + "range_check_builtin": 2 + }, + "n_memory_holes": 0, + "n_steps": 107 + }, + "GetBlockNumber": { + "builtin_instance_counter": {}, + "n_memory_holes": 0, + "n_steps": 40 + }, + "GetBlockTimestamp": { + "builtin_instance_counter": {}, + "n_memory_holes": 0, + "n_steps": 38 + }, + "GetCallerAddress": { + "builtin_instance_counter": { + "range_check_builtin": 2 + }, + "n_memory_holes": 0, + "n_steps": 108 + }, + "GetClassHashAt": { + "builtin_instance_counter": { + "range_check_builtin": 1 + }, + "n_memory_holes": 0, + "n_steps": 89 + }, + "GetContractAddress": { + "builtin_instance_counter": { + "range_check_builtin": 2 + }, + "n_memory_holes": 0, + "n_steps": 108 + }, + "GetExecutionInfo": { + "builtin_instance_counter": { + "range_check_builtin": 2 + }, + "n_memory_holes": 0, + "n_steps": 108 + }, + "GetSequencerAddress": { + "builtin_instance_counter": {}, + "n_memory_holes": 0, + "n_steps": 34 + }, + "GetTxInfo": { + "builtin_instance_counter": { + "range_check_builtin": 2 + }, + "n_memory_holes": 0, + "n_steps": 108 + }, + "GetTxSignature": { + "builtin_instance_counter": {}, + "n_memory_holes": 0, + "n_steps": 44 + }, + "Keccak": { + "builtin_instance_counter": {}, + "n_memory_holes": 0, + "n_steps": 100 + }, + "KeccakRound": { + "builtin_instance_counter": { + "bitwise_builtin": 6, + "keccak_builtin": 1, + "range_check_builtin": 56 + }, + "n_memory_holes": 0, + "n_steps": 281 + }, + "LibraryCall": { + "builtin_instance_counter": { + "range_check_builtin": 16 + }, + "n_memory_holes": 0, + "n_steps": 879 + }, + "LibraryCallL1Handler": { + "builtin_instance_counter": { + "range_check_builtin": 15 + }, + "n_memory_holes": 0, + "n_steps": 659 + }, + "MetaTxV0": { + "constant": { + "builtin_instance_counter": { + "pedersen_builtin": 9, + "range_check_builtin": 16 + }, + "n_memory_holes": 0, + "n_steps": 1273 + }, + "calldata_factor": { + "n_steps": 8, + "builtin_instance_counter": { + "pedersen_builtin": 1 + }, + "n_memory_holes": 0 + } + }, + "ReplaceClass": { + "builtin_instance_counter": { + "range_check_builtin": 1 + }, + "n_memory_holes": 0, + "n_steps": 106 + }, + "Secp256k1Add": { + "builtin_instance_counter": { + "range_check_builtin": 29 + }, + "n_memory_holes": 0, + "n_steps": 412 + }, + "Secp256k1GetPointFromX": { + "builtin_instance_counter": { + "range_check_builtin": 30 + }, + "n_memory_holes": 0, + "n_steps": 397 + }, + "Secp256k1GetXy": { + "builtin_instance_counter": { + "range_check_builtin": 11 + }, + "n_memory_holes": 0, + "n_steps": 209 + }, + "Secp256k1Mul": { + "builtin_instance_counter": { + "range_check_builtin": 7045 + }, + "n_memory_holes": 0, + "n_steps": 76507 + }, + "Secp256k1New": { + "builtin_instance_counter": { + "range_check_builtin": 35 + }, + "n_memory_holes": 0, + "n_steps": 463 + }, + "Secp256r1Add": { + "builtin_instance_counter": { + "range_check_builtin": 57 + }, + "n_memory_holes": 0, + "n_steps": 595 + }, + "Secp256r1GetPointFromX": { + "builtin_instance_counter": { + "range_check_builtin": 44 + }, + "n_memory_holes": 0, + "n_steps": 516 + }, + "Secp256r1GetXy": { + "builtin_instance_counter": { + "range_check_builtin": 11 + }, + "n_memory_holes": 0, + "n_steps": 211 + }, + "Secp256r1Mul": { + "builtin_instance_counter": { + "range_check_builtin": 13961 + }, + "n_memory_holes": 0, + "n_steps": 125346 + }, + "Secp256r1New": { + "builtin_instance_counter": { + "range_check_builtin": 49 + }, + "n_memory_holes": 0, + "n_steps": 582 + }, + "SendMessageToL1": { + "builtin_instance_counter": { + "range_check_builtin": 1 + }, + "n_memory_holes": 0, + "n_steps": 144 + }, + "Sha256ProcessBlock": { + "builtin_instance_counter": { + "range_check_builtin": 65, + "bitwise_builtin": 1115 + }, + "n_memory_holes": 0, + "n_steps": 1867 + }, + "StorageRead": { + "builtin_instance_counter": { + "range_check_builtin": 1 + }, + "n_memory_holes": 0, + "n_steps": 90 + }, + "StorageWrite": { + "builtin_instance_counter": { + "range_check_builtin": 1 + }, + "n_memory_holes": 0, + "n_steps": 96 + } + }, + "execute_txs_inner": { + "Declare": { + "builtin_instance_counter": { + "pedersen_builtin": 4, + "range_check_builtin": 70, + "poseidon_builtin": 15 + }, + "n_memory_holes": 0, + "n_steps": 3501 + }, + "DeployAccount": { + "constant": { + "builtin_instance_counter": { + "pedersen_builtin": 11, + "range_check_builtin": 89, + "poseidon_builtin": 11 + }, + "n_memory_holes": 0, + "n_steps": 4554 + }, + "calldata_factor": { + "builtin_instance_counter": { + "pedersen_builtin": 2 + }, + "n_memory_holes": 0, + "n_steps": 21 + } + }, + "InvokeFunction": { + "constant": { + "builtin_instance_counter": { + "pedersen_builtin": 4, + "range_check_builtin": 86, + "poseidon_builtin": 12 + }, + "n_memory_holes": 0, + "n_steps": 4319 + }, + "calldata_factor": { + "builtin_instance_counter": { + "pedersen_builtin": 1 + }, + "n_memory_holes": 0, + "n_steps": 8 + } + }, + "L1Handler": { + "constant": { + "builtin_instance_counter": { + "pedersen_builtin": 11, + "range_check_builtin": 19 + }, + "n_memory_holes": 0, + "n_steps": 1354 + }, + "calldata_factor": { + "builtin_instance_counter": { + "pedersen_builtin": 1 + }, + "n_memory_holes": 0, + "n_steps": 13 + } + } + }, + "compute_os_kzg_commitment_info": { + "builtin_instance_counter": { + "range_check_builtin": 17 + }, + "n_memory_holes": 0, + "n_steps": 113 + } + }, + "validate_max_n_steps": 1000000, + "min_sierra_version_for_sierra_gas": "1.7.0", + "vm_resource_fee_cost": { + "builtins": { + "add_mod_builtin": [ + 4, + 100 + ], + "bitwise_builtin": [ + 16, + 100 + ], + "ec_op_builtin": [ + 256, + 100 + ], + "ecdsa_builtin": [ + 512, + 100 + ], + "keccak_builtin": [ + 512, + 100 + ], + "mul_mod_builtin": [ + 4, + 100 + ], + "output_builtin": [ + 0, + 1 + ], + "pedersen_builtin": [ + 8, + 100 + ], + "poseidon_builtin": [ + 8, + 100 + ], + "range_check_builtin": [ + 4, + 100 + ], + "range_check96_builtin": [ + 4, + 100 + ] + }, + "n_steps": [ + 25, + 10000 + ] + }, + "enable_tip": true +} diff --git a/crates/blockifier/src/abi/constants.rs b/crates/blockifier/src/abi/constants.rs index ecdab0e1330..3ee51f45754 100644 --- a/crates/blockifier/src/abi/constants.rs +++ b/crates/blockifier/src/abi/constants.rs @@ -1,9 +1,3 @@ -use starknet_api::transaction::TransactionVersion; -use starknet_types_core::felt::Felt; - -// The version is considered 0 for L1-Handler transaction hash calculation purposes. -pub const L1_HANDLER_VERSION: TransactionVersion = TransactionVersion(Felt::ZERO); - // OS-related constants. pub const L1_TO_L2_MSG_HEADER_SIZE: usize = 5; pub const L2_TO_L1_MSG_HEADER_SIZE: usize = 3; @@ -27,24 +21,20 @@ pub const CONSUMED_MSG_TO_L2_ENCODED_DATA_SIZE: usize = // Transaction resource names. // TODO(Amos, 1/10/2024): Rename to l1_gas_weight. pub const L1_GAS_USAGE: &str = "gas_weight"; -pub const L2_GAS_USAGE: &str = "l2_gas_weight"; -pub const BLOB_GAS_USAGE: &str = "l1_blob_gas_usage"; pub const N_STEPS_RESOURCE: &str = "n_steps"; pub const N_EVENTS: &str = "n_events"; pub const MESSAGE_SEGMENT_LENGTH: &str = "message_segment_length"; pub const STATE_DIFF_SIZE: &str = "state_diff_size"; pub const N_MEMORY_HOLES: &str = "n_memory_holes"; +pub const SIERRA_GAS: &str = "sierra_gas"; // Casm hash calculation-related constants. pub const CAIRO0_ENTRY_POINT_STRUCT_SIZE: usize = 2; pub const N_STEPS_PER_PEDERSEN: usize = 8; -// OS reserved contract addresses. - -// This contract stores the block number -> block hash mapping. -// TODO(Arni, 14/6/2023): Replace BLOCK_HASH_CONSTANT_ADDRESS with a lazy calculation. -// pub static BLOCK_HASH_CONTRACT_ADDRESS: Lazy = ... -pub const BLOCK_HASH_CONTRACT_ADDRESS: u64 = 1; - // The block number -> block hash mapping is written for the current block number minus this number. pub const STORED_BLOCK_HASH_BUFFER: u64 = 10; + +// Maximum possible Sierra gas for a transaction to run with in Sierra mode. +// This limit is derived from the stack size limit when running natively. +pub const MAX_POSSIBLE_SIERRA_GAS: u64 = 3_500_000_000; diff --git a/crates/blockifier/src/abi/sierra_types.rs b/crates/blockifier/src/abi/sierra_types.rs index 121a5b84b3b..620fdd97a93 100644 --- a/crates/blockifier/src/abi/sierra_types.rs +++ b/crates/blockifier/src/abi/sierra_types.rs @@ -3,26 +3,18 @@ use cairo_vm::types::relocatable::Relocatable; use cairo_vm::vm::errors::memory_errors::MemoryError; use cairo_vm::vm::vm_core::VirtualMachine; use num_bigint::{BigUint, ToBigUint}; -use num_traits::ToPrimitive; -use starknet_api::core::ContractAddress; +use starknet_api::core::{felt_to_u128, ContractAddress}; use starknet_api::state::StorageKey; use starknet_api::StarknetApiError; -use starknet_types_core::felt::Felt; use thiserror::Error; use crate::state::errors::StateError; use crate::state::state_api::StateReader; -#[cfg(test)] -#[path = "sierra_types_test.rs"] -mod test; - pub type SierraTypeResult = Result; #[derive(Debug, Error)] pub enum SierraTypeError { - #[error("Felt {val} is too big to convert to '{ty}'.")] - ValueTooLargeForType { val: Felt, ty: &'static str }, #[error(transparent)] MemoryError(#[from] MemoryError), #[error(transparent)] @@ -43,12 +35,6 @@ pub trait SierraType: Sized { ) -> SierraTypeResult; } -// Utils. - -fn felt_to_u128(felt: &Felt) -> Result { - felt.to_u128().ok_or(SierraTypeError::ValueTooLargeForType { val: *felt, ty: "u128" }) -} - // Implementations. // We implement the trait SierraType for SierraU128 and not for u128 since it's not guaranteed that diff --git a/crates/blockifier/src/abi/sierra_types_test.rs b/crates/blockifier/src/abi/sierra_types_test.rs deleted file mode 100644 index a78b1e35329..00000000000 --- a/crates/blockifier/src/abi/sierra_types_test.rs +++ /dev/null @@ -1,21 +0,0 @@ -use num_bigint::BigUint; -use starknet_types_core::felt::Felt; - -use crate::abi::sierra_types::felt_to_u128; - -#[test] -fn test_value_too_large_for_type() { - // Happy flow. - let n = 1991_u128; - let n_as_felt = Felt::from(n); - felt_to_u128(&n_as_felt).unwrap(); - - // Value too large for type. - let overflowed_u128: BigUint = BigUint::from(1_u8) << 128; - let overflowed_u128_as_felt = Felt::from(overflowed_u128); - let error = felt_to_u128(&overflowed_u128_as_felt).unwrap_err(); - assert_eq!( - format!("{error}"), - "Felt 340282366920938463463374607431768211456 is too big to convert to 'u128'." - ); -} diff --git a/crates/blockifier/src/blockifier/block.rs b/crates/blockifier/src/blockifier/block.rs index 83aca48b1c4..9e98b63ee91 100644 --- a/crates/blockifier/src/blockifier/block.rs +++ b/crates/blockifier/src/blockifier/block.rs @@ -2,104 +2,70 @@ use log::warn; use starknet_api::block::{ BlockHashAndNumber, BlockNumber, - BlockTimestamp, GasPrice, GasPriceVector, + GasPrices, NonzeroGasPrice, }; -use starknet_api::core::ContractAddress; use starknet_api::state::StorageKey; use crate::abi::constants; +use crate::blockifier_versioned_constants::{OsConstants, VersionedConstants}; use crate::state::errors::StateError; use crate::state::state_api::{State, StateResult}; -use crate::transaction::objects::FeeType; -use crate::versioned_constants::VersionedConstants; #[cfg(test)] #[path = "block_test.rs"] pub mod block_test; -#[cfg_attr(feature = "transaction_serde", derive(serde::Serialize, serde::Deserialize))] -#[derive(Clone, Debug)] -pub struct BlockInfo { - pub block_number: BlockNumber, - pub block_timestamp: BlockTimestamp, - - // Fee-related. - pub sequencer_address: ContractAddress, - pub gas_prices: GasPrices, - pub use_kzg_da: bool, -} - -#[cfg_attr(feature = "transaction_serde", derive(serde::Serialize, serde::Deserialize))] -#[derive(Clone, Debug)] -pub struct GasPrices { - eth_gas_prices: GasPriceVector, // In wei. - strk_gas_prices: GasPriceVector, // In fri. -} - -impl GasPrices { - pub fn new( - eth_l1_gas_price: NonzeroGasPrice, - strk_l1_gas_price: NonzeroGasPrice, - eth_l1_data_gas_price: NonzeroGasPrice, - strk_l1_data_gas_price: NonzeroGasPrice, - eth_l2_gas_price: NonzeroGasPrice, - strk_l2_gas_price: NonzeroGasPrice, - ) -> Self { - // TODO(Aner): fix backwards compatibility. - let expected_eth_l2_gas_price = VersionedConstants::latest_constants() - .convert_l1_to_l2_gas_price_round_up(eth_l1_gas_price.into()); - if GasPrice::from(eth_l2_gas_price) != expected_eth_l2_gas_price { - // TODO!(Aner): change to panic! Requires fixing several tests. - warn!( - "eth_l2_gas_price {eth_l2_gas_price} does not match expected eth_l2_gas_price \ - {expected_eth_l2_gas_price}." - ) - } - let expected_strk_l2_gas_price = VersionedConstants::latest_constants() - .convert_l1_to_l2_gas_price_round_up(strk_l1_gas_price.into()); - if GasPrice::from(strk_l2_gas_price) != expected_strk_l2_gas_price { - // TODO!(Aner): change to panic! Requires fixing test_discounted_gas_overdraft - warn!( - "strk_l2_gas_price {strk_l2_gas_price} does not match expected strk_l2_gas_price \ - {expected_strk_l2_gas_price}." - ) - } - - Self { - eth_gas_prices: GasPriceVector { - l1_gas_price: eth_l1_gas_price, - l1_data_gas_price: eth_l1_data_gas_price, - l2_gas_price: eth_l2_gas_price, - }, - strk_gas_prices: GasPriceVector { - l1_gas_price: strk_l1_gas_price, - l1_data_gas_price: strk_l1_data_gas_price, - l2_gas_price: strk_l2_gas_price, - }, - } +/// Warns if the submitted gas prices do not match the expected gas prices. +fn validate_l2_gas_price(gas_prices: &GasPrices) { + // TODO(Aner): fix backwards compatibility. + let eth_l2_gas_price = gas_prices.eth_gas_prices.l2_gas_price; + let expected_eth_l2_gas_price = VersionedConstants::latest_constants() + .convert_l1_to_l2_gas_price_round_up(gas_prices.eth_gas_prices.l1_gas_price.into()); + if GasPrice::from(eth_l2_gas_price) != expected_eth_l2_gas_price { + // TODO(Aner): change to panic! Requires fixing several tests. + warn!( + "eth_l2_gas_price {} does not match expected eth_l2_gas_price {}.", + eth_l2_gas_price, expected_eth_l2_gas_price + ) } - - pub fn get_l1_gas_price_by_fee_type(&self, fee_type: &FeeType) -> NonzeroGasPrice { - self.get_gas_prices_by_fee_type(fee_type).l1_gas_price - } - - pub fn get_l1_data_gas_price_by_fee_type(&self, fee_type: &FeeType) -> NonzeroGasPrice { - self.get_gas_prices_by_fee_type(fee_type).l1_data_gas_price + let strk_l2_gas_price = gas_prices.strk_gas_prices.l2_gas_price; + let expected_strk_l2_gas_price = VersionedConstants::latest_constants() + .convert_l1_to_l2_gas_price_round_up(gas_prices.strk_gas_prices.l1_gas_price.into()); + if GasPrice::from(strk_l2_gas_price) != expected_strk_l2_gas_price { + // TODO(Aner): change to panic! Requires fixing test_discounted_gas_overdraft + warn!( + "strk_l2_gas_price {} does not match expected strk_l2_gas_price {}.", + strk_l2_gas_price, expected_strk_l2_gas_price + ) } +} - pub fn get_l2_gas_price_by_fee_type(&self, fee_type: &FeeType) -> NonzeroGasPrice { - self.get_gas_prices_by_fee_type(fee_type).l2_gas_price - } +pub fn validated_gas_prices( + eth_l1_gas_price: NonzeroGasPrice, + strk_l1_gas_price: NonzeroGasPrice, + eth_l1_data_gas_price: NonzeroGasPrice, + strk_l1_data_gas_price: NonzeroGasPrice, + eth_l2_gas_price: NonzeroGasPrice, + strk_l2_gas_price: NonzeroGasPrice, +) -> GasPrices { + let gas_prices = GasPrices { + eth_gas_prices: GasPriceVector { + l1_gas_price: eth_l1_gas_price, + l1_data_gas_price: eth_l1_data_gas_price, + l2_gas_price: eth_l2_gas_price, + }, + strk_gas_prices: GasPriceVector { + l1_gas_price: strk_l1_gas_price, + l1_data_gas_price: strk_l1_data_gas_price, + l2_gas_price: strk_l2_gas_price, + }, + }; + validate_l2_gas_price(&gas_prices); - pub fn get_gas_prices_by_fee_type(&self, fee_type: &FeeType) -> &GasPriceVector { - match fee_type { - FeeType::Strk => &self.strk_gas_prices, - FeeType::Eth => &self.eth_gas_prices, - } - } + gas_prices } // Block pre-processing. @@ -111,12 +77,13 @@ pub fn pre_process_block( state: &mut dyn State, old_block_number_and_hash: Option, next_block_number: BlockNumber, + os_constants: &OsConstants, ) -> StateResult<()> { let should_block_hash_be_provided = next_block_number >= BlockNumber(constants::STORED_BLOCK_HASH_BUFFER); if let Some(BlockHashAndNumber { number, hash }) = old_block_number_and_hash { let block_hash_contract_address = - ContractAddress::from(constants::BLOCK_HASH_CONTRACT_ADDRESS); + os_constants.os_contract_addresses.block_hash_contract_address(); let block_number_as_storage_key = StorageKey::from(number.0); state.set_storage_at(block_hash_contract_address, block_number_as_storage_key, hash.0)?; } else if should_block_hash_be_provided { diff --git a/crates/blockifier/src/blockifier/block_test.rs b/crates/blockifier/src/blockifier/block_test.rs index 39dd8e5336d..54ede92c6be 100644 --- a/crates/blockifier/src/blockifier/block_test.rs +++ b/crates/blockifier/src/blockifier/block_test.rs @@ -1,20 +1,22 @@ +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; +use blockifier_test_utils::contracts::FeatureContract; use starknet_api::block::{BlockHash, BlockHashAndNumber, BlockNumber}; -use starknet_api::core::ContractAddress; use starknet_api::felt; use starknet_api::state::StorageKey; use crate::abi::constants; use crate::blockifier::block::pre_process_block; +use crate::blockifier_versioned_constants::VersionedConstants; use crate::context::ChainInfo; use crate::state::state_api::StateReader; -use crate::test_utils::contracts::FeatureContract; use crate::test_utils::initial_test_state::test_state; -use crate::test_utils::{CairoVersion, BALANCE}; +use crate::test_utils::BALANCE; #[test] fn test_pre_process_block() { - let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1); + let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1(RunnableCairo1::Casm)); let mut state = test_state(&ChainInfo::create_for_testing(), BALANCE, &[(test_contract, 1)]); + let os_constants = VersionedConstants::create_for_testing().os_constants; // Test the positive flow of pre_process_block inside the allowed block number interval let block_number = BlockNumber(constants::STORED_BLOCK_HASH_BUFFER); @@ -23,11 +25,12 @@ fn test_pre_process_block() { &mut state, Some(BlockHashAndNumber { hash: BlockHash(block_hash), number: block_number }), block_number, + &os_constants, ) .unwrap(); let written_hash = state.get_storage_at( - ContractAddress::from(constants::BLOCK_HASH_CONTRACT_ADDRESS), + os_constants.os_contract_addresses.block_hash_contract_address(), StorageKey::from(block_number.0), ); assert_eq!(written_hash.unwrap(), block_hash); @@ -35,10 +38,10 @@ fn test_pre_process_block() { // Test that block pre-process with block hash None is successful only within the allowed // block number interval. let block_number = BlockNumber(constants::STORED_BLOCK_HASH_BUFFER - 1); - assert!(pre_process_block(&mut state, None, block_number).is_ok()); + assert!(pre_process_block(&mut state, None, block_number, &os_constants).is_ok()); let block_number = BlockNumber(constants::STORED_BLOCK_HASH_BUFFER); - let error = pre_process_block(&mut state, None, block_number); + let error = pre_process_block(&mut state, None, block_number, &os_constants); assert_eq!( format!( "A block hash must be provided for block number > {}.", diff --git a/crates/blockifier/src/blockifier/config.rs b/crates/blockifier/src/blockifier/config.rs index 3252394a456..cfa9077fb7a 100644 --- a/crates/blockifier/src/blockifier/config.rs +++ b/crates/blockifier/src/blockifier/config.rs @@ -3,21 +3,44 @@ use std::collections::BTreeMap; use papyrus_config::dumping::{append_sub_config_name, ser_param, SerializeConfig}; use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; use serde::{Deserialize, Serialize}; +use starknet_api::core::ClassHash; +use starknet_sierra_multicompile::config::SierraCompilationConfig; -#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)] +use crate::blockifier::transaction_executor::DEFAULT_STACK_SIZE; +use crate::state::contract_class_manager::DEFAULT_COMPILATION_REQUEST_CHANNEL_SIZE; +use crate::state::global_cache::GLOBAL_CONTRACT_CACHE_SIZE_FOR_TEST; + +#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] pub struct TransactionExecutorConfig { pub concurrency_config: ConcurrencyConfig, + pub stack_size: usize, } impl TransactionExecutorConfig { - #[cfg(any(test, feature = "testing"))] + #[cfg(any(test, feature = "testing", feature = "native_blockifier"))] pub fn create_for_testing(concurrency_enabled: bool) -> Self { - Self { concurrency_config: ConcurrencyConfig::create_for_testing(concurrency_enabled) } + Self { + concurrency_config: ConcurrencyConfig::create_for_testing(concurrency_enabled), + stack_size: DEFAULT_STACK_SIZE, + } + } +} + +impl Default for TransactionExecutorConfig { + fn default() -> Self { + Self { concurrency_config: ConcurrencyConfig::default(), stack_size: DEFAULT_STACK_SIZE } } } impl SerializeConfig for TransactionExecutorConfig { fn dump(&self) -> BTreeMap { - append_sub_config_name(self.concurrency_config.dump(), "concurrency_config") + let mut dump = append_sub_config_name(self.concurrency_config.dump(), "concurrency_config"); + dump.append(&mut BTreeMap::from([ser_param( + "stack_size", + &self.stack_size, + "The thread stack size (proportional to the maximal gas of a transaction).", + ParamPrivacyInput::Public, + )])); + dump } } @@ -61,3 +84,111 @@ impl SerializeConfig for ConcurrencyConfig { ]) } } + +#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +pub struct ContractClassManagerConfig { + pub cairo_native_run_config: CairoNativeRunConfig, + pub contract_cache_size: usize, + pub native_compiler_config: SierraCompilationConfig, +} + +impl Default for ContractClassManagerConfig { + fn default() -> Self { + Self { + cairo_native_run_config: CairoNativeRunConfig::default(), + contract_cache_size: GLOBAL_CONTRACT_CACHE_SIZE_FOR_TEST, + native_compiler_config: SierraCompilationConfig::default(), + } + } +} + +impl ContractClassManagerConfig { + #[cfg(any(test, feature = "testing", feature = "native_blockifier"))] + pub fn create_for_testing(run_cairo_native: bool, wait_on_native_compilation: bool) -> Self { + let cairo_native_run_config = CairoNativeRunConfig { + run_cairo_native, + wait_on_native_compilation, + ..Default::default() + }; + Self { cairo_native_run_config, ..Default::default() } + } +} + +impl SerializeConfig for ContractClassManagerConfig { + fn dump(&self) -> BTreeMap { + let mut dump = BTreeMap::from_iter([ser_param( + "contract_cache_size", + &self.contract_cache_size, + "The size of the global contract cache.", + ParamPrivacyInput::Public, + )]); + dump.append(&mut append_sub_config_name( + self.cairo_native_run_config.dump(), + "cairo_native_run_config", + )); + dump.append(&mut append_sub_config_name( + self.native_compiler_config.dump(), + "native_compiler_config", + )); + dump + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +pub enum NativeClassesWhitelist { + All, + Limited(Vec), +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +pub struct CairoNativeRunConfig { + pub run_cairo_native: bool, + pub wait_on_native_compilation: bool, + pub channel_size: usize, + // TODO(AvivG): implement `native_classes_whitelist` logic. + pub native_classes_whitelist: NativeClassesWhitelist, +} + +impl Default for CairoNativeRunConfig { + fn default() -> Self { + Self { + run_cairo_native: false, + wait_on_native_compilation: false, + channel_size: DEFAULT_COMPILATION_REQUEST_CHANNEL_SIZE, + native_classes_whitelist: NativeClassesWhitelist::All, + } + } +} + +impl SerializeConfig for CairoNativeRunConfig { + fn dump(&self) -> BTreeMap { + BTreeMap::from_iter([ + ser_param( + "run_cairo_native", + &self.run_cairo_native, + "Enables Cairo native execution.", + ParamPrivacyInput::Public, + ), + ser_param( + "wait_on_native_compilation", + &self.wait_on_native_compilation, + "Block Sequencer main program while compiling sierra, for testing.", + ParamPrivacyInput::Public, + ), + ser_param( + "channel_size", + &self.channel_size, + "The size of the compilation request channel.", + ParamPrivacyInput::Public, + ), + ser_param( + "native_classes_whitelist", + &self.native_classes_whitelist, + "Contracts for Cairo Specifies whether to execute all class hashes or only a \ + limited selection using Cairo native contracts. If limited, a specific list of \ + class hashes is provided. compilation.", + ParamPrivacyInput::Public, + ), + ]) + } +} diff --git a/crates/blockifier/src/blockifier/stateful_validator.rs b/crates/blockifier/src/blockifier/stateful_validator.rs index 1d2a12ae3e5..fdc1b0bae1c 100644 --- a/crates/blockifier/src/blockifier/stateful_validator.rs +++ b/crates/blockifier/src/blockifier/stateful_validator.rs @@ -2,6 +2,7 @@ use std::sync::Arc; use starknet_api::core::{ContractAddress, Nonce}; use starknet_api::executable_transaction::AccountTransaction as ApiTransaction; +use starknet_api::execution_resources::GasAmount; use thiserror::Error; use crate::blockifier::config::TransactionExecutorConfig; @@ -52,88 +53,59 @@ impl StatefulValidator { Self { tx_executor } } - pub fn perform_validations( - &mut self, - tx: AccountTransaction, - skip_validate: bool, - ) -> StatefulValidatorResult<()> { + pub fn perform_validations(&mut self, tx: AccountTransaction) -> StatefulValidatorResult<()> { // Deploy account transactions should be fully executed, since the constructor must run // before `__validate_deploy__`. The execution already includes all necessary validations, // so they are skipped here. if let ApiTransaction::DeployAccount(_) = tx.tx { - self.execute(tx)?; - return Ok(()); + return self.execute(tx); } - let tx_context = self.tx_executor.block_context.to_tx_context(&tx); - self.perform_pre_validation_stage(&tx, &tx_context)?; - - if skip_validate { + let tx_context = Arc::new(self.tx_executor.block_context.to_tx_context(&tx)); + tx.perform_pre_validation_stage(self.state(), &tx_context)?; + if !tx.execution_flags.validate { return Ok(()); } // `__validate__` call. - let (_optional_call_info, actual_cost) = - self.validate(&tx, tx_context.initial_sierra_gas())?; + let (_optional_call_info, actual_cost) = self.validate(&tx, tx_context.clone())?; // Post validations. - PostValidationReport::verify(&tx_context, &actual_cost)?; + PostValidationReport::verify(&tx_context, &actual_cost, tx.execution_flags.charge_fee)?; Ok(()) } - fn execute(&mut self, tx: AccountTransaction) -> StatefulValidatorResult<()> { - self.tx_executor.execute(&Transaction::Account(tx))?; - Ok(()) + fn state(&mut self) -> &mut CachedState { + self.tx_executor.block_state.as_mut().expect(BLOCK_STATE_ACCESS_ERR) } - fn perform_pre_validation_stage( - &mut self, - tx: &AccountTransaction, - tx_context: &TransactionContext, - ) -> StatefulValidatorResult<()> { - let strict_nonce_check = false; - // Run pre-validation in charge fee mode to perform fee and balance related checks. - let charge_fee = tx.enforce_fee(); - tx.perform_pre_validation_stage( - self.tx_executor.block_state.as_mut().expect(BLOCK_STATE_ACCESS_ERR), - tx_context, - charge_fee, - strict_nonce_check, - )?; - + fn execute(&mut self, tx: AccountTransaction) -> StatefulValidatorResult<()> { + self.tx_executor.execute(&Transaction::Account(tx))?; Ok(()) } fn validate( &mut self, tx: &AccountTransaction, - mut remaining_gas: u64, + tx_context: Arc, ) -> StatefulValidatorResult<(Option, TransactionReceipt)> { - let tx_context = Arc::new(self.tx_executor.block_context.to_tx_context(tx)); - - let limit_steps_by_resources = tx.enforce_fee(); let validate_call_info = tx.validate_tx( - self.tx_executor.block_state.as_mut().expect(BLOCK_STATE_ACCESS_ERR), + self.state(), tx_context.clone(), - &mut remaining_gas, - limit_steps_by_resources, + &mut tx_context.initial_sierra_gas().0, )?; let tx_receipt = TransactionReceipt::from_account_tx( tx, &tx_context, - &self - .tx_executor - .block_state - .as_mut() - .expect(BLOCK_STATE_ACCESS_ERR) - .get_actual_state_changes()?, + &self.state().get_actual_state_changes()?, CallInfo::summarize_many( validate_call_info.iter(), &tx_context.block_context.versioned_constants, ), 0, + GasAmount(0), ); Ok((validate_call_info, tx_receipt)) @@ -143,11 +115,6 @@ impl StatefulValidator { &mut self, account_address: ContractAddress, ) -> StatefulValidatorResult { - Ok(self - .tx_executor - .block_state - .as_ref() - .expect(BLOCK_STATE_ACCESS_ERR) - .get_nonce_at(account_address)?) + Ok(self.state().get_nonce_at(account_address)?) } } diff --git a/crates/blockifier/src/blockifier/stateful_validator_test.rs b/crates/blockifier/src/blockifier/stateful_validator_test.rs index 7a0019dd3eb..b1b8d6ecadc 100644 --- a/crates/blockifier/src/blockifier/stateful_validator_test.rs +++ b/crates/blockifier/src/blockifier/stateful_validator_test.rs @@ -1,4 +1,6 @@ use assert_matches::assert_matches; +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; +use blockifier_test_utils::contracts::FeatureContract; use rstest::rstest; use starknet_api::executable_transaction::AccountTransaction as Transaction; use starknet_api::transaction::fields::ValidResourceBounds; @@ -6,9 +8,8 @@ use starknet_api::transaction::TransactionVersion; use crate::blockifier::stateful_validator::StatefulValidator; use crate::context::BlockContext; -use crate::test_utils::contracts::FeatureContract; use crate::test_utils::initial_test_state::{fund_account, test_state}; -use crate::test_utils::{CairoVersion, BALANCE}; +use crate::test_utils::BALANCE; use crate::transaction::test_utils::{ block_context, create_account_tx_for_validate_test_nonce_0, @@ -37,7 +38,8 @@ fn test_tx_validator( block_context: BlockContext, #[values(default_l1_resource_bounds(), default_all_resource_bounds())] resource_bounds: ValidResourceBounds, - #[values(CairoVersion::Cairo0, CairoVersion::Cairo1)] cairo_version: CairoVersion, + #[values(CairoVersion::Cairo0, CairoVersion::Cairo1(RunnableCairo1::Casm))] + cairo_version: CairoVersion, ) { let chain_info = &block_context.chain_info; @@ -62,8 +64,10 @@ fn test_tx_validator( }; // Positive flow. + let validate = true; let account_tx = create_account_tx_for_validate_test_nonce_0(FaultyAccountTxCreatorArgs { scenario: VALID, + validate, ..tx_args }); if let Transaction::DeployAccount(deploy_tx) = &account_tx.tx { @@ -72,21 +76,21 @@ fn test_tx_validator( // Test the stateful validator. let mut stateful_validator = StatefulValidator::create(state, block_context); - let skip_validate = false; - let result = stateful_validator.perform_validations(account_tx, skip_validate); + let result = stateful_validator.perform_validations(account_tx); assert!(result.is_ok(), "Validation failed: {:?}", result.unwrap_err()); } #[rstest] -fn test_tx_validator_skip_validate( +fn test_tx_validator_conditional_validate( #[values(default_l1_resource_bounds(), default_all_resource_bounds())] resource_bounds: ValidResourceBounds, ) { let block_context = BlockContext::create_for_testing(); - let faulty_account = FeatureContract::FaultyAccount(CairoVersion::Cairo1); + let faulty_account = FeatureContract::FaultyAccount(CairoVersion::Cairo1(RunnableCairo1::Casm)); let state = test_state(&block_context.chain_info, BALANCE, &[(faulty_account, 1)]); // Create a transaction that does not pass validations. + let validate = false; let tx = create_account_tx_for_validate_test_nonce_0(FaultyAccountTxCreatorArgs { scenario: INVALID, tx_type: TransactionType::InvokeFunction, @@ -94,11 +98,12 @@ fn test_tx_validator_skip_validate( sender_address: faulty_account.get_instance_address(0), class_hash: faulty_account.get_class_hash(), resource_bounds, + validate, ..Default::default() }); let mut stateful_validator = StatefulValidator::create(state, block_context); // The transaction validations should be skipped and the function should return Ok. - let result = stateful_validator.perform_validations(tx, true); + let result = stateful_validator.perform_validations(tx); assert_matches!(result, Ok(())); } diff --git a/crates/blockifier/src/blockifier/transaction_executor.rs b/crates/blockifier/src/blockifier/transaction_executor.rs index af9d216e1bc..f8e80c2043a 100644 --- a/crates/blockifier/src/blockifier/transaction_executor.rs +++ b/crates/blockifier/src/blockifier/transaction_executor.rs @@ -1,11 +1,9 @@ -use std::collections::{HashMap, HashSet}; use std::panic::{self, catch_unwind, AssertUnwindSafe}; use std::sync::{Arc, Mutex}; use itertools::FoldWhile::{Continue, Done}; use itertools::Itertools; use starknet_api::block::BlockHashAndNumber; -use starknet_api::core::ClassHash; use thiserror::Error; use crate::blockifier::block::pre_process_block; @@ -13,19 +11,23 @@ use crate::blockifier::config::TransactionExecutorConfig; use crate::bouncer::{Bouncer, BouncerWeights}; use crate::concurrency::worker_logic::WorkerExecutor; use crate::context::BlockContext; -use crate::state::cached_state::{CachedState, CommitmentStateDiff, TransactionalState}; +use crate::state::cached_state::{CachedState, CommitmentStateDiff, StateMaps, TransactionalState}; use crate::state::errors::StateError; use crate::state::state_api::{StateReader, StateResult}; +use crate::state::stateful_compression::{allocate_aliases_in_storage, compress, CompressionError}; use crate::transaction::errors::TransactionExecutionError; -use crate::transaction::objects::{TransactionExecutionInfo, TransactionInfoCreator}; +use crate::transaction::objects::TransactionExecutionInfo; use crate::transaction::transaction_execution::Transaction; -use crate::transaction::transactions::{ExecutableTransaction, ExecutionFlags}; +use crate::transaction::transactions::ExecutableTransaction; #[cfg(test)] #[path = "transaction_executor_test.rs"] pub mod transaction_executor_test; pub const BLOCK_STATE_ACCESS_ERR: &str = "Error: The block state should be `Some`."; +pub const DEFAULT_STACK_SIZE: usize = 60 * 1024 * 1024; + +pub type TransactionExecutionOutput = (TransactionExecutionInfo, StateMaps); #[derive(Debug, Error)] pub enum TransactionExecutorError { @@ -35,10 +37,17 @@ pub enum TransactionExecutorError { StateError(#[from] StateError), #[error(transparent)] TransactionExecutionError(#[from] TransactionExecutionError), + #[error(transparent)] + CompressionError(#[from] CompressionError), } pub type TransactionExecutorResult = Result; -pub type VisitedSegmentsMapping = Vec<(ClassHash, Vec)>; + +pub struct BlockExecutionSummary { + pub state_diff: CommitmentStateDiff, + pub compressed_state_diff: Option, + pub bouncer_weights: BouncerWeights, +} /// A transaction executor, used for building a single block. pub struct TransactionExecutor { @@ -68,6 +77,7 @@ impl TransactionExecutor { &mut block_state, old_block_number_and_hash, block_context.block_info().block_number, + &block_context.versioned_constants.os_constants, )?; Ok(Self::new(block_state, block_context, config)) } @@ -95,29 +105,29 @@ impl TransactionExecutor { pub fn execute( &mut self, tx: &Transaction, - ) -> TransactionExecutorResult { + ) -> TransactionExecutorResult { let mut transactional_state = TransactionalState::create_transactional( self.block_state.as_mut().expect(BLOCK_STATE_ACCESS_ERR), ); - let tx_charge_fee = tx.create_tx_info().enforce_fee(); // Executing a single transaction cannot be done in a concurrent mode. - let execution_flags = - ExecutionFlags { charge_fee: tx_charge_fee, validate: true, concurrency_mode: false }; + let concurrency_mode = false; let tx_execution_result = - tx.execute_raw(&mut transactional_state, &self.block_context, execution_flags); + tx.execute_raw(&mut transactional_state, &self.block_context, concurrency_mode); match tx_execution_result { Ok(tx_execution_info) => { - let tx_state_changes_keys = - transactional_state.get_actual_state_changes()?.state_maps.into_keys(); + let state_diff = transactional_state.to_state_diff()?.state_maps; + let tx_state_changes_keys = state_diff.keys(); self.bouncer.try_update( &transactional_state, &tx_state_changes_keys, &tx_execution_info.summarize(&self.block_context.versioned_constants), &tx_execution_info.receipt.resources, + &self.block_context.versioned_constants, )?; transactional_state.commit(); - Ok(tx_execution_info) + + Ok((tx_execution_info, state_diff)) } Err(error) => { transactional_state.abort(); @@ -126,14 +136,16 @@ impl TransactionExecutor { } } - pub fn execute_txs_sequentially( + fn execute_txs_sequentially_inner( &mut self, txs: &[Transaction], - ) -> Vec> { + ) -> Vec> { let mut results = Vec::new(); for tx in txs { match self.execute(tx) { - Ok(tx_execution_info) => results.push(Ok(tx_execution_info)), + Ok((tx_execution_info, state_diff)) => { + results.push(Ok((tx_execution_info, state_diff))) + } Err(TransactionExecutorError::BlockFull) => break, Err(error) => results.push(Err(error)), } @@ -141,42 +153,41 @@ impl TransactionExecutor { results } - /// Returns the state diff, a list of contract class hash with the corresponding list of - /// visited segment values and the block weights. - pub fn finalize( - &mut self, - ) -> TransactionExecutorResult<(CommitmentStateDiff, VisitedSegmentsMapping, BouncerWeights)> - { - // Get the visited segments of each contract class. - // This is done by taking all the visited PCs of each contract, and compress them to one - // representative for each visited segment. - let visited_segments = self - .block_state - .as_ref() - .expect(BLOCK_STATE_ACCESS_ERR) - .visited_pcs - .iter() - .map(|(class_hash, class_visited_pcs)| -> TransactionExecutorResult<_> { - let contract_class = self - .block_state - .as_ref() - .expect(BLOCK_STATE_ACCESS_ERR) - .get_compiled_contract_class(*class_hash)?; - Ok((*class_hash, contract_class.get_visited_segments(class_visited_pcs)?)) - }) - .collect::>()?; + /// Returns the state diff and the block weights. + // TODO(Aner): Consume "self", i.e., remove the reference, after removing the native blockifier. + pub fn finalize(&mut self) -> TransactionExecutorResult { + self.internal_finalize() + } + #[cfg(feature = "reexecution")] + pub fn non_consuming_finalize(&mut self) -> TransactionExecutorResult { + self.internal_finalize() + } + + fn internal_finalize(&mut self) -> TransactionExecutorResult { log::debug!("Final block weights: {:?}.", self.bouncer.get_accumulated_weights()); - Ok(( - self.block_state - .as_mut() - .expect(BLOCK_STATE_ACCESS_ERR) - .to_state_diff()? - .state_maps - .into(), - visited_segments, - *self.bouncer.get_accumulated_weights(), - )) + let block_state = self.block_state.as_mut().expect(BLOCK_STATE_ACCESS_ERR); + let alias_contract_address = self + .block_context + .versioned_constants + .os_constants + .os_contract_addresses + .alias_contract_address(); + if self.block_context.versioned_constants.enable_stateful_compression { + allocate_aliases_in_storage(block_state, alias_contract_address)?; + } + let state_diff = block_state.to_state_diff()?.state_maps; + let compressed_state_diff = + if self.block_context.versioned_constants.enable_stateful_compression { + Some(compress(&state_diff, block_state, alias_contract_address)?.into()) + } else { + None + }; + Ok(BlockExecutionSummary { + state_diff: state_diff.into(), + compressed_state_diff, + bouncer_weights: *self.bouncer.get_accumulated_weights(), + }) } } @@ -187,7 +198,7 @@ impl TransactionExecutor { pub fn execute_txs( &mut self, txs: &[Transaction], - ) -> Vec> { + ) -> Vec> { if !self.config.concurrency_config.enabled { log::debug!("Executing transactions sequentially."); self.execute_txs_sequentially(txs) @@ -223,10 +234,43 @@ impl TransactionExecutor { } } - pub fn execute_chunk( + fn execute_txs_sequentially( + &mut self, + txs: &[Transaction], + ) -> Vec> { + #[cfg(not(feature = "cairo_native"))] + return self.execute_txs_sequentially_inner(txs); + #[cfg(feature = "cairo_native")] + { + // TODO(meshi): find a way to access the contract class manager config from transaction + // executor. + let txs = txs.to_vec(); + std::thread::scope(|s| { + std::thread::Builder::new() + // when running Cairo natively, the real stack is used and could get overflowed + // (unlike the VM where the stack is simulated in the heap as a memory segment). + // + // We pre-allocate the stack here, and not during Native execution (not trivial), so it + // needs to be big enough ahead. + // However, making it very big is wasteful (especially with multi-threading). + // So, the stack size should support calls with a reasonable gas limit, for extremely deep + // recursions to reach out-of-gas before hitting the bottom of the recursion. + // + // The gas upper bound is MAX_POSSIBLE_SIERRA_GAS, and sequencers must not raise it without + // adjusting the stack size. + .stack_size(self.config.stack_size) + .spawn_scoped(s, || self.execute_txs_sequentially_inner(&txs)) + .expect("Failed to spawn thread") + .join() + .expect("Failed to join thread.") + }) + } + } + + fn execute_chunk( &mut self, chunk: &[Transaction], - ) -> Vec> { + ) -> Vec> { use crate::concurrency::utils::AbortIfPanic; let block_state = self.block_state.take().expect("The block state should be `Some`."); @@ -246,32 +290,45 @@ impl TransactionExecutor { std::thread::scope(|s| { for _ in 0..self.config.concurrency_config.n_workers { let worker_executor = Arc::clone(&worker_executor); - s.spawn(move || { - // Making sure that the program will abort if a panic accured while halting the - // scheduler. - let abort_guard = AbortIfPanic; - // If a panic is not handled or the handling logic itself panics, then we abort - // the program. - if let Err(err) = catch_unwind(AssertUnwindSafe(|| { - worker_executor.run(); - })) { - // If the program panics here, the abort guard will exit the program. - // In this case, no panic message will be logged. Add the cargo flag - // --nocapture to log the panic message. + let _handle = std::thread::Builder::new() + // when running Cairo natively, the real stack is used and could get overflowed + // (unlike the VM where the stack is simulated in the heap as a memory segment). + // + // We pre-allocate the stack here, and not during Native execution (not trivial), so it + // needs to be big enough ahead. + // However, making it very big is wasteful (especially with multi-threading). + // So, the stack size should support calls with a reasonable gas limit, for extremely deep + // recursions to reach out-of-gas before hitting the bottom of the recursion. + // + // The gas upper bound is MAX_POSSIBLE_SIERRA_GAS, and sequencers must not raise it without + // adjusting the stack size. + .stack_size(self.config.stack_size) + .spawn_scoped(s, move || { + // Making sure that the program will abort if a panic accured while halting + // the scheduler. + let abort_guard = AbortIfPanic; + // If a panic is not handled or the handling logic itself panics, then we + // abort the program. + if let Err(err) = catch_unwind(AssertUnwindSafe(|| { + worker_executor.run(); + })) { + // If the program panics here, the abort guard will exit the program. + // In this case, no panic message will be logged. Add the cargo flag + // --nocapture to log the panic message. - worker_executor.scheduler.halt(); - abort_guard.release(); - panic::resume_unwind(err); - } + worker_executor.scheduler.halt(); + abort_guard.release(); + panic::resume_unwind(err); + } - abort_guard.release(); - }); + abort_guard.release(); + }) + .expect("Failed to spawn thread."); } }); let n_committed_txs = worker_executor.scheduler.get_n_committed_txs(); let mut tx_execution_results = Vec::new(); - let mut visited_pcs: HashMap> = HashMap::new(); for execution_output in worker_executor.execution_outputs.iter() { if tx_execution_results.len() >= n_committed_txs { break; @@ -281,11 +338,11 @@ impl TransactionExecutor { .expect("Failed to lock execution output.") .take() .expect("Output must be ready."); - tx_execution_results - .push(locked_execution_output.result.map_err(TransactionExecutorError::from)); - for (class_hash, class_visited_pcs) in locked_execution_output.visited_pcs { - visited_pcs.entry(class_hash).or_default().extend(class_visited_pcs); - } + let tx_execution_output = locked_execution_output + .result + .map(|tx_execution_info| (tx_execution_info, locked_execution_output.state_diff)) + .map_err(TransactionExecutorError::from); + tx_execution_results.push(tx_execution_output); } let block_state_after_commit = Arc::try_unwrap(worker_executor) @@ -296,7 +353,7 @@ impl TransactionExecutor { it." ) }) - .commit_chunk_and_recover_block_state(n_committed_txs, visited_pcs); + .commit_chunk_and_recover_block_state(n_committed_txs); self.block_state.replace(block_state_after_commit); tx_execution_results diff --git a/crates/blockifier/src/blockifier/transaction_executor_test.rs b/crates/blockifier/src/blockifier/transaction_executor_test.rs index 3089818a87f..0d29573011d 100644 --- a/crates/blockifier/src/blockifier/transaction_executor_test.rs +++ b/crates/blockifier/src/blockifier/transaction_executor_test.rs @@ -1,7 +1,13 @@ use assert_matches::assert_matches; +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; +use blockifier_test_utils::calldata::create_calldata; +use blockifier_test_utils::contracts::FeatureContract; use pretty_assertions::assert_eq; use rstest::rstest; -use starknet_api::test_utils::NonceManager; +use starknet_api::test_utils::declare::executable_declare_tx; +use starknet_api::test_utils::deploy_account::executable_deploy_account_tx; +use starknet_api::test_utils::invoke::executable_invoke_tx; +use starknet_api::test_utils::DEFAULT_STRK_L1_GAS_PRICE; use starknet_api::transaction::fields::Fee; use starknet_api::transaction::TransactionVersion; use starknet_api::{declare_tx_args, deploy_account_tx_args, felt, invoke_tx_args, nonce}; @@ -17,21 +23,13 @@ use crate::bouncer::{Bouncer, BouncerWeights}; use crate::context::BlockContext; use crate::state::cached_state::CachedState; use crate::state::state_api::StateReader; -use crate::test_utils::contracts::FeatureContract; -use crate::test_utils::declare::declare_tx; -use crate::test_utils::deploy_account::deploy_account_tx; +use crate::test_utils::contracts::FeatureContractTrait; use crate::test_utils::initial_test_state::test_state; use crate::test_utils::l1_handler::l1handler_tx; -use crate::test_utils::{ - create_calldata, - maybe_dummy_block_hash_and_number, - CairoVersion, - BALANCE, - DEFAULT_STRK_L1_GAS_PRICE, -}; +use crate::test_utils::{maybe_dummy_block_hash_and_number, BALANCE}; +use crate::transaction::account_transaction::AccountTransaction; use crate::transaction::errors::TransactionExecutionError; use crate::transaction::test_utils::{ - account_invoke_tx, block_context, calculate_class_info_for_testing, create_test_init_data, @@ -40,6 +38,7 @@ use crate::transaction::test_utils::{ TestInitData, }; use crate::transaction::transaction_execution::Transaction; + fn tx_executor_test_body( state: CachedState, block_context: BlockContext, @@ -58,7 +57,7 @@ fn tx_executor_test_body( // TODO(Arni, 30/03/2024): Consider adding a test for the transaction execution info. If A test // should not be added, rename the test to `test_bouncer_info`. // TODO(Arni, 30/03/2024): Test all bouncer weights. - let _tx_execution_info = tx_executor.execute(&tx).unwrap(); + let _tx_execution_output = tx_executor.execute(&tx).unwrap(); let bouncer_weights = tx_executor.bouncer.get_accumulated_weights(); assert_eq!(bouncer_weights.state_diff_size, expected_bouncer_weights.state_diff_size); assert_eq!( @@ -91,7 +90,7 @@ fn tx_executor_test_body( )] #[case::tx_version_2( TransactionVersion::TWO, - CairoVersion::Cairo1, + CairoVersion::Cairo1(RunnableCairo1::Casm), BouncerWeights { state_diff_size: 4, message_segment_length: 0, @@ -101,7 +100,7 @@ fn tx_executor_test_body( )] #[case::tx_version_3( TransactionVersion::THREE, - CairoVersion::Cairo1, + CairoVersion::Cairo1(RunnableCairo1::Casm), BouncerWeights { state_diff_size: 4, message_segment_length: 0, @@ -111,7 +110,8 @@ fn tx_executor_test_body( )] fn test_declare( block_context: BlockContext, - #[values(CairoVersion::Cairo0, CairoVersion::Cairo1)] account_cairo_version: CairoVersion, + #[values(CairoVersion::Cairo0, CairoVersion::Cairo1(RunnableCairo1::Casm))] + account_cairo_version: CairoVersion, #[case] tx_version: TransactionVersion, #[case] cairo_version: CairoVersion, #[case] expected_bouncer_weights: BouncerWeights, @@ -120,7 +120,7 @@ fn test_declare( let declared_contract = FeatureContract::Empty(cairo_version); let state = test_state(&block_context.chain_info, BALANCE, &[(account_contract, 1)]); - let tx = declare_tx( + let declare_tx = executable_declare_tx( declare_tx_args! { sender_address: account_contract.get_instance_address(0), class_hash: declared_contract.get_class_hash(), @@ -129,8 +129,8 @@ fn test_declare( resource_bounds: l1_resource_bounds(0_u8.into(), DEFAULT_STRK_L1_GAS_PRICE.into()), }, calculate_class_info_for_testing(declared_contract.get_class()), - ) - .into(); + ); + let tx = AccountTransaction::new_for_sequencing(declare_tx).into(); tx_executor_test_body(state, block_context, tx, expected_bouncer_weights); } @@ -138,20 +138,18 @@ fn test_declare( fn test_deploy_account( block_context: BlockContext, #[values(TransactionVersion::ONE, TransactionVersion::THREE)] version: TransactionVersion, - #[values(CairoVersion::Cairo0, CairoVersion::Cairo1)] cairo_version: CairoVersion, + #[values(CairoVersion::Cairo0, CairoVersion::Cairo1(RunnableCairo1::Casm))] + cairo_version: CairoVersion, ) { let account_contract = FeatureContract::AccountWithoutValidations(cairo_version); let state = test_state(&block_context.chain_info, BALANCE, &[(account_contract, 0)]); - let tx = deploy_account_tx( - deploy_account_tx_args! { - class_hash: account_contract.get_class_hash(), - resource_bounds: l1_resource_bounds(0_u8.into(), DEFAULT_STRK_L1_GAS_PRICE.into()), - version, - }, - &mut NonceManager::default(), - ) - .into(); + let deploy_account_tx = executable_deploy_account_tx(deploy_account_tx_args! { + class_hash: account_contract.get_class_hash(), + resource_bounds: l1_resource_bounds(0_u8.into(), DEFAULT_STRK_L1_GAS_PRICE.into()), + version, + }); + let tx = AccountTransaction::new_for_sequencing(deploy_account_tx).into(); let expected_bouncer_weights = BouncerWeights { state_diff_size: 3, message_segment_length: 0, @@ -202,7 +200,8 @@ fn test_deploy_account( fn test_invoke( block_context: BlockContext, #[values(TransactionVersion::ONE, TransactionVersion::THREE)] version: TransactionVersion, - #[values(CairoVersion::Cairo0, CairoVersion::Cairo1)] cairo_version: CairoVersion, + #[values(CairoVersion::Cairo0, CairoVersion::Cairo1(RunnableCairo1::Casm))] + cairo_version: CairoVersion, #[case] entry_point_name: &str, #[case] entry_point_args: Vec, #[case] expected_bouncer_weights: BouncerWeights, @@ -217,18 +216,18 @@ fn test_invoke( let calldata = create_calldata(test_contract.get_instance_address(0), entry_point_name, &entry_point_args); - let tx = account_invoke_tx(invoke_tx_args! { + let invoke_tx = executable_invoke_tx(invoke_tx_args! { sender_address: account_contract.get_instance_address(0), calldata, version, - }) - .into(); + }); + let tx = AccountTransaction::new_for_sequencing(invoke_tx).into(); tx_executor_test_body(state, block_context, tx, expected_bouncer_weights); } #[rstest] fn test_l1_handler(block_context: BlockContext) { - let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1); + let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1(RunnableCairo1::Casm)); let state = test_state(&block_context.chain_info, BALANCE, &[(test_contract, 1)]); let tx = Transaction::L1Handler(l1handler_tx( @@ -263,7 +262,10 @@ fn test_bouncing(#[case] initial_bouncer_weights: BouncerWeights, #[case] n_even let block_context = BlockContext::create_for_bouncer_testing(max_n_events_in_block); let TestInitData { state, account_address, contract_address, mut nonce_manager } = - create_test_init_data(&block_context.chain_info, CairoVersion::Cairo1); + create_test_init_data( + &block_context.chain_info, + CairoVersion::Cairo1(RunnableCairo1::Casm), + ); // TODO(Yoni, 15/6/2024): turn on concurrency mode. let mut tx_executor = @@ -291,8 +293,10 @@ fn test_execute_txs_bouncing(#[values(true, false)] concurrency_enabled: bool) { let max_n_events_in_block = 10; let block_context = BlockContext::create_for_bouncer_testing(max_n_events_in_block); - let TestInitData { state, account_address, contract_address, .. } = - create_test_init_data(&block_context.chain_info, CairoVersion::Cairo1); + let TestInitData { state, account_address, contract_address, .. } = create_test_init_data( + &block_context.chain_info, + CairoVersion::Cairo1(RunnableCairo1::Casm), + ); let mut tx_executor = TransactionExecutor::new(state, block_context, config); @@ -364,3 +368,45 @@ fn test_execute_txs_bouncing(#[values(true, false)] concurrency_enabled: bool) { nonce!(4_u32) ); } + +#[cfg(feature = "cairo_native")] +#[rstest::rstest] +/// Tests that Native can handle deep recursion calls without causing a stack overflow. +/// The recursive function must be complex enough to prevent the compiler from optimizing it into a +/// loop. This function was manually tested with increased maximum gas to ensure it reaches a stack +/// overflow. +/// +/// Note: Testing the VM is unnecessary here as it simulates the stack where the stack in the heap +/// as a memory segment. +fn test_stack_overflow(#[values(true, false)] concurrency_enabled: bool) { + let block_context = BlockContext::create_for_account_testing(); + let cairo_version = CairoVersion::Cairo1(RunnableCairo1::Native); + let TestInitData { state, account_address, contract_address, mut nonce_manager } = + create_test_init_data(&block_context.chain_info, cairo_version); + let depth = felt!(1000000_u128); + let entry_point_args = vec![depth]; + let calldata = create_calldata(contract_address, "test_stack_overflow", &entry_point_args); + let invoke_tx = executable_invoke_tx(invoke_tx_args! { + sender_address: account_address, + calldata, + nonce: nonce_manager.next(account_address), + }); + let account_tx = AccountTransaction::new_for_sequencing(invoke_tx); + // Ensure the transaction is allocated the maximum gas limits. + assert!( + account_tx.resource_bounds().get_l2_bounds().max_amount + >= block_context.versioned_constants.os_constants.execute_max_sierra_gas + + block_context.versioned_constants.os_constants.validate_max_sierra_gas + ); + // Run. + let config = TransactionExecutorConfig::create_for_testing(concurrency_enabled); + let mut executor = TransactionExecutor::new(state, block_context, config); + let results = executor.execute_txs(&vec![account_tx.into()]); + + let (tx_execution_info, _state_diff) = results[0].as_ref().unwrap(); + assert!(tx_execution_info.is_reverted()); + let err = tx_execution_info.revert_error.clone().unwrap().to_string(); + + // Recursion is terminated by resource bounds before stack overflow occurs. + assert!(err.contains("'Out of gas'")); +} diff --git a/crates/blockifier/src/blockifier/transfers_flow_test.rs b/crates/blockifier/src/blockifier/transfers_flow_test.rs index 94cd27518c6..bb617f7089e 100644 --- a/crates/blockifier/src/blockifier/transfers_flow_test.rs +++ b/crates/blockifier/src/blockifier/transfers_flow_test.rs @@ -1,3 +1,4 @@ +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; use rstest::rstest; use crate::blockifier::config::ConcurrencyConfig; @@ -8,12 +9,20 @@ use crate::test_utils::transfers_generator::{ }; #[rstest] -#[case::concurrency_enabled(ConcurrencyConfig{enabled: true, n_workers: 4, chunk_size: 100})] -#[case::concurrency_disabled(ConcurrencyConfig{enabled: false, n_workers: 0, chunk_size: 0})] -pub fn transfers_flow_test(#[case] concurrency_config: ConcurrencyConfig) { +#[case::cairo1(CairoVersion::Cairo1(RunnableCairo1::Casm))] +#[cfg_attr( + feature = "cairo_native", + case::cairo1_native(CairoVersion::Cairo1(RunnableCairo1::Native)) +)] +pub fn transfers_flow_test( + #[values(true, false)] concurrency_enabled: bool, + #[case] cairo_version: CairoVersion, +) { + let concurrency_config = ConcurrencyConfig::create_for_testing(concurrency_enabled); let transfers_generator_config = TransfersGeneratorConfig { recipient_generator_type: RecipientGeneratorType::DisjointFromSenders, concurrency_config, + cairo_version, ..Default::default() }; assert!( diff --git a/crates/blockifier/src/versioned_constants.rs b/crates/blockifier/src/blockifier_versioned_constants.rs similarity index 54% rename from crates/blockifier/src/versioned_constants.rs rename to crates/blockifier/src/blockifier_versioned_constants.rs index 6d18bca5e8c..28642205155 100644 --- a/crates/blockifier/src/versioned_constants.rs +++ b/crates/blockifier/src/blockifier_versioned_constants.rs @@ -1,7 +1,7 @@ use std::collections::{BTreeMap, HashMap, HashSet}; -use std::path::{Path, PathBuf}; -use std::sync::{Arc, LazyLock}; -use std::{fs, io}; +use std::io; +use std::path::Path; +use std::sync::Arc; use cairo_vm::types::builtin_name::BuiltinName; use cairo_vm::vm::runners::cairo_runner::ExecutionResources; @@ -10,115 +10,49 @@ use num_rational::Ratio; use num_traits::Inv; use papyrus_config::dumping::{ser_param, SerializeConfig}; use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; -use paste::paste; use semver::Version; use serde::de::Error as DeserializationError; use serde::{Deserialize, Deserializer, Serialize}; use serde_json::{Map, Number, Value}; use starknet_api::block::{GasPrice, StarknetVersion}; +use starknet_api::contract_class::SierraVersion; +use starknet_api::core::{ClassHash, ContractAddress}; +use starknet_api::define_versioned_constants; use starknet_api::execution_resources::{GasAmount, GasVector}; -use starknet_api::transaction::fields::GasVectorComputationMode; +use starknet_api::transaction::fields::{GasVectorComputationMode, Tip}; use strum::IntoEnumIterator; use thiserror::Error; -use crate::execution::deprecated_syscalls::hint_processor::SyscallCounter; +use crate::execution::common_hints::ExecutionMode; use crate::execution::execution_utils::poseidon_hash_many_cost; +use crate::execution::syscalls::hint_processor::SyscallUsageMap; use crate::execution::syscalls::SyscallSelector; use crate::fee::resources::StarknetResources; use crate::transaction::transaction_types::TransactionType; +use crate::utils::get_gas_cost_from_vm_resources; #[cfg(test)] #[path = "versioned_constants_test.rs"] pub mod test; -/// Auto-generate getters for listed versioned constants versions. -macro_rules! define_versioned_constants { - ($(($variant:ident, $path_to_json:expr)),* $(,)?) => { - // Static (lazy) instances of the versioned constants. - // For internal use only; for access to a static instance use the `StarknetVersion` enum. - paste! { - $( - pub(crate) const []: &str = - include_str!($path_to_json); - pub static []: LazyLock = LazyLock::new(|| { - serde_json::from_str([]) - .expect(&format!("Versioned constants {} is malformed.", $path_to_json)) - }); - )* - } - - /// API to access a static instance of the versioned constants. - impl TryFrom for &'static VersionedConstants { - type Error = VersionedConstantsError; - - fn try_from(version: StarknetVersion) -> VersionedConstantsResult { - match version { - $( - StarknetVersion::$variant => { - Ok(& paste! { [] }) - } - )* - _ => Err(VersionedConstantsError::InvalidStarknetVersion(version)), - } - } - } - - impl VersionedConstants { - pub fn path_to_json(version: &StarknetVersion) -> VersionedConstantsResult<&'static str> { - match version { - $(StarknetVersion::$variant => Ok($path_to_json),)* - _ => Err(VersionedConstantsError::InvalidStarknetVersion(*version)), - } - } - - /// Gets the constants that shipped with the current version of the Blockifier. - /// To use custom constants, initialize the struct from a file using `from_path`. - pub fn latest_constants() -> &'static Self { - Self::get(&StarknetVersion::LATEST) - .expect("Latest version should support VC.") - } - - /// Gets the constants for the specified Starknet version. - pub fn get(version: &StarknetVersion) -> VersionedConstantsResult<&'static Self> { - match version { - $( - StarknetVersion::$variant => Ok( - & paste! { [] } - ), - )* - _ => Err(VersionedConstantsError::InvalidStarknetVersion(*version)), - } - } - } - - pub static VERSIONED_CONSTANTS_LATEST_JSON: LazyLock = LazyLock::new(|| { - let latest_variant = StarknetVersion::LATEST; - let path_to_json: PathBuf = [ - env!("CARGO_MANIFEST_DIR"), - "src", - VersionedConstants::path_to_json(&latest_variant) - .expect("Latest variant should have a path to json.") - ].iter().collect(); - fs::read_to_string(path_to_json.clone()) - .expect(&format!("Failed to read file {}.", path_to_json.display())) - }); - }; -} - -define_versioned_constants! { - (V0_13_0, "../resources/versioned_constants_0_13_0.json"), - (V0_13_1, "../resources/versioned_constants_0_13_1.json"), - (V0_13_1_1, "../resources/versioned_constants_0_13_1_1.json"), - (V0_13_2, "../resources/versioned_constants_0_13_2.json"), - (V0_13_2_1, "../resources/versioned_constants_0_13_2_1.json"), - (V0_13_3, "../resources/versioned_constants_0_13_3.json"), - (V0_13_4, "../resources/versioned_constants_0_13_4.json"), -} +define_versioned_constants!( + VersionedConstants, + VersionedConstantsError, + (V0_13_0, "../resources/blockifier_versioned_constants_0_13_0.json"), + (V0_13_1, "../resources/blockifier_versioned_constants_0_13_1.json"), + (V0_13_1_1, "../resources/blockifier_versioned_constants_0_13_1_1.json"), + (V0_13_2, "../resources/blockifier_versioned_constants_0_13_2.json"), + (V0_13_2_1, "../resources/blockifier_versioned_constants_0_13_2_1.json"), + (V0_13_3, "../resources/blockifier_versioned_constants_0_13_3.json"), + (V0_13_4, "../resources/blockifier_versioned_constants_0_13_4.json"), + (V0_13_5, "../resources/blockifier_versioned_constants_0_13_5.json"), + (V0_14_0, "../resources/blockifier_versioned_constants_0_14_0.json"), +); pub type ResourceCost = Ratio; -// TODO: Delete this ratio-converter function once event keys / data length are no longer 128 bits -// (no other usage is expected). +// TODO(Dori): Delete this ratio-converter function once event keys / data length are no longer 128 +// bits (no other usage is expected). pub fn resource_cost_to_u128_ratio(cost: ResourceCost) -> Ratio { Ratio::new((*cost.numer()).into(), (*cost.denom()).into()) } @@ -153,8 +87,8 @@ impl AllocationCost { } } -// TODO: This (along with the Serialize impl) is implemented in pub(crate) scope in the VM (named -// serde_generic_map_impl); use it if and when it's public. +// TODO(Dori): This (along with the Serialize impl) is implemented in pub(crate) scope in the VM +// (named serde_generic_map_impl); use it if and when it's public. fn builtin_map_from_string_map<'de, D: Deserializer<'de>>( d: D, ) -> Result, D::Error> { @@ -171,6 +105,7 @@ fn builtin_map_from_string_map<'de, D: Deserializer<'de>>( /// Instances of this struct for specific Starknet versions can be selected by using the above enum. #[derive(Clone, Debug, Default, Deserialize)] #[serde(deny_unknown_fields)] +#[serde(remote = "Self")] pub struct VersionedConstants { // Limits. pub tx_event_limits: EventLimits, @@ -179,7 +114,7 @@ pub struct VersionedConstants { pub archival_data_gas_costs: ArchivalDataGasCosts, pub max_recursion_depth: usize, pub validate_max_n_steps: u32, - pub min_compiler_version_for_sierra_gas: CompilerVersion, + pub min_sierra_version_for_sierra_gas: SierraVersion, // BACKWARD COMPATIBILITY: If true, the segment_arena builtin instance counter will be // multiplied by 3. This offsets a bug in the old vm where the counter counted the number of // cells used by instances of the builtin, instead of the number of instances. @@ -188,6 +123,7 @@ pub struct VersionedConstants { // Transactions settings. pub disable_cairo0_redeclaration: bool, pub enable_stateful_compression: bool, + pub comprehensive_state_diff: bool, pub ignore_inner_event_resources: bool, // Compiler settings. @@ -200,6 +136,7 @@ pub struct VersionedConstants { // Fee related. pub(crate) vm_resource_fee_cost: Arc, + pub enable_tip: bool, // Cost of allocating a storage cell. pub allocation_cost: AllocationCost, @@ -216,34 +153,53 @@ impl VersionedConstants { Ok(serde_json::from_reader(std::fs::File::open(path)?)?) } - /// Converts from L1 gas price to L2 gas price with **upward rounding**. + /// Converts from L1 gas price to L2 gas price with **upward rounding**, based on the + /// conversion of a Cairo step from Sierra gas to L1 gas. pub fn convert_l1_to_l2_gas_price_round_up(&self, l1_gas_price: GasPrice) -> GasPrice { - (*(resource_cost_to_u128_ratio(self.l1_to_l2_gas_price_ratio()) * l1_gas_price.0) + (*(resource_cost_to_u128_ratio(self.sierra_gas_in_l1_gas_amount()) * l1_gas_price.0) .ceil() .numer()) .into() } - /// Converts from L1 gas amount to L2 gas amount with **upward rounding**. - pub fn convert_l1_to_l2_gas_amount_round_up(&self, l1_gas_amount: GasAmount) -> GasAmount { + /// Converts L1 gas amount to Sierra (L2) gas amount with **upward rounding**. + pub fn l1_gas_to_sierra_gas_amount_round_up(&self, l1_gas_amount: GasAmount) -> GasAmount { // The amount ratio is the inverse of the price ratio. - (*(self.l1_to_l2_gas_price_ratio().inv() * l1_gas_amount.0).ceil().numer()).into() + (*(self.sierra_gas_in_l1_gas_amount().inv() * l1_gas_amount.0).ceil().numer()).into() } - /// Returns the following ratio: L2_gas_price/L1_gas_price. - fn l1_to_l2_gas_price_ratio(&self) -> ResourceCost { - Ratio::new(1, self.os_constants.gas_costs.step_gas_cost) + /// Converts Sierra (L2) gas amount to L1 gas amount with **upward rounding**. + pub fn sierra_gas_to_l1_gas_amount_round_up(&self, l2_gas_amount: GasAmount) -> GasAmount { + (*(self.sierra_gas_in_l1_gas_amount() * l2_gas_amount.0).ceil().numer()).into() + } + + /// Returns the equivalent L1 gas amount of one unit of Sierra gas. + /// The conversion is based on the pricing of a single Cairo step. + fn sierra_gas_in_l1_gas_amount(&self) -> ResourceCost { + Ratio::new(1, self.os_constants.gas_costs.base.step_gas_cost) * self.vm_resource_fee_cost().n_steps } - #[cfg(any(feature = "testing", test))] - pub fn get_l1_to_l2_gas_price_ratio(&self) -> ResourceCost { - self.l1_to_l2_gas_price_ratio() + /// Default initial gas amount when L2 gas is not provided. + pub fn initial_gas_no_user_l2_bound(&self) -> GasAmount { + (self + .os_constants + .execute_max_sierra_gas + .checked_add(self.os_constants.validate_max_sierra_gas)) + .expect("The default initial gas cost should be less than the maximum gas amount.") + } + + /// Returns the maximum gas amount according to the given mode. + pub fn sierra_gas_limit(&self, mode: &ExecutionMode) -> GasAmount { + match mode { + ExecutionMode::Validate => self.os_constants.validate_max_sierra_gas, + ExecutionMode::Execute => self.os_constants.execute_max_sierra_gas, + } } /// Returns the default initial gas for VM mode transactions. - pub fn default_initial_gas_cost(&self) -> u64 { - self.os_constants.gas_costs.default_initial_gas_cost + pub fn infinite_gas_for_vm_mode(&self) -> u64 { + self.os_constants.gas_costs.base.default_initial_gas_cost } pub fn vm_resource_fee_cost(&self) -> &VmResourceCosts { @@ -278,9 +234,9 @@ impl VersionedConstants { pub fn get_additional_os_syscall_resources( &self, - syscall_counter: &SyscallCounter, + syscalls_usage: &SyscallUsageMap, ) -> ExecutionResources { - self.os_resources.get_additional_os_syscall_resources(syscall_counter) + self.os_resources.get_additional_os_syscall_resources(syscalls_usage) } pub fn get_validate_block_number_rounding(&self) -> u64 { @@ -329,12 +285,17 @@ impl VersionedConstants { validate_max_n_steps, max_recursion_depth, invoke_tx_max_n_steps, + max_n_events, } = versioned_constants_overrides; + let latest_constants = Self::latest_constants().clone(); + let tx_event_limits = + EventLimits { max_n_emitted_events: max_n_events, ..latest_constants.tx_event_limits }; Self { validate_max_n_steps, max_recursion_depth, invoke_tx_max_n_steps, - ..Self::latest_constants().clone() + tx_event_limits, + ..latest_constants } } @@ -347,6 +308,92 @@ impl VersionedConstants { GasVectorComputationMode::NoL2Gas => &self.deprecated_l2_resource_gas_costs, } } + + /// Calculates the syscall gas cost from the OS resources. + pub fn get_syscall_gas_cost(&self, syscall_selector: &SyscallSelector) -> SyscallGasCost { + let gas_costs = &self.os_constants.gas_costs; + let vm_resources = &self + .os_resources + .execute_syscalls + .get(syscall_selector) + .expect("Fetching the execution resources of a syscall should not fail."); + + let mut base_gas_cost = get_gas_cost_from_vm_resources(&vm_resources.constant, gas_costs); + + // The minimum total cost is `syscall_base_gas_cost`, which is pre-charged by the compiler. + base_gas_cost = std::cmp::max(gas_costs.base.syscall_base_gas_cost, base_gas_cost); + let linear_gas_cost = + get_gas_cost_from_vm_resources(&vm_resources.calldata_factor, gas_costs); + SyscallGasCost { base: base_gas_cost, linear_factor: linear_gas_cost } + } +} + +impl<'de> Deserialize<'de> for VersionedConstants { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let mut versioned_constants = Self::deserialize(deserializer)?; + + let syscall_gas_costs = &(versioned_constants.os_constants.gas_costs.syscalls); + if syscall_gas_costs == &SyscallGasCosts::default() { + let syscalls = SyscallGasCosts { + call_contract: versioned_constants + .get_syscall_gas_cost(&SyscallSelector::CallContract), + deploy: versioned_constants.get_syscall_gas_cost(&SyscallSelector::Deploy), + get_block_hash: versioned_constants + .get_syscall_gas_cost(&SyscallSelector::GetBlockHash), + get_execution_info: versioned_constants + .get_syscall_gas_cost(&SyscallSelector::GetExecutionInfo), + library_call: versioned_constants + .get_syscall_gas_cost(&SyscallSelector::LibraryCall), + meta_tx_v0: versioned_constants.get_syscall_gas_cost(&SyscallSelector::MetaTxV0), + replace_class: versioned_constants + .get_syscall_gas_cost(&SyscallSelector::ReplaceClass), + storage_read: versioned_constants + .get_syscall_gas_cost(&SyscallSelector::StorageRead), + storage_write: versioned_constants + .get_syscall_gas_cost(&SyscallSelector::StorageWrite), + get_class_hash_at: versioned_constants + .get_syscall_gas_cost(&SyscallSelector::GetClassHashAt), + emit_event: versioned_constants.get_syscall_gas_cost(&SyscallSelector::EmitEvent), + send_message_to_l1: versioned_constants + .get_syscall_gas_cost(&SyscallSelector::SendMessageToL1), + secp256k1_add: versioned_constants + .get_syscall_gas_cost(&SyscallSelector::Secp256k1Add), + secp256k1_get_point_from_x: versioned_constants + .get_syscall_gas_cost(&SyscallSelector::Secp256k1GetPointFromX), + secp256k1_get_xy: versioned_constants + .get_syscall_gas_cost(&SyscallSelector::Secp256k1GetXy), + secp256k1_mul: versioned_constants + .get_syscall_gas_cost(&SyscallSelector::Secp256k1Mul), + secp256k1_new: versioned_constants + .get_syscall_gas_cost(&SyscallSelector::Secp256k1New), + secp256r1_add: versioned_constants + .get_syscall_gas_cost(&SyscallSelector::Secp256r1Add), + secp256r1_get_point_from_x: versioned_constants + .get_syscall_gas_cost(&SyscallSelector::Secp256r1GetPointFromX), + secp256r1_get_xy: versioned_constants + .get_syscall_gas_cost(&SyscallSelector::Secp256r1GetXy), + secp256r1_mul: versioned_constants + .get_syscall_gas_cost(&SyscallSelector::Secp256r1Mul), + secp256r1_new: versioned_constants + .get_syscall_gas_cost(&SyscallSelector::Secp256r1New), + keccak: versioned_constants.get_syscall_gas_cost(&SyscallSelector::Keccak), + keccak_round_cost: versioned_constants + .get_syscall_gas_cost(&SyscallSelector::KeccakRound), + sha256_process_block: versioned_constants + .get_syscall_gas_cost(&SyscallSelector::Sha256ProcessBlock), + }; + + Arc::get_mut(&mut versioned_constants.os_constants) + .expect("Failed to get mutable reference") + .gas_costs + .syscalls = syscalls; + } + + Ok(versioned_constants) + } } #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq)] @@ -361,6 +408,37 @@ pub struct ArchivalDataGasCosts { pub gas_per_code_byte: ResourceCost, } +pub struct CairoNativeStackConfig { + pub gas_to_stack_ratio: Ratio, + pub max_stack_size: u64, + pub min_stack_red_zone: u64, + pub buffer_size: u64, +} + +impl CairoNativeStackConfig { + /// Rounds up the given size to the nearest multiple of MB. + pub fn round_up_to_mb(size: u64) -> u64 { + const MB: u64 = 1024 * 1024; + size.div_ceil(MB) * MB + } + + /// Returns the stack size sufficient for running Cairo Native. + /// Rounds up to the nearest multiple of MB. + pub fn get_stack_size_red_zone(&self, remaining_gas: u64) -> u64 { + let stack_size_based_on_gas = + (self.gas_to_stack_ratio * Ratio::new(remaining_gas, 1)).to_integer(); + // Ensure the computed stack size is within the allowed range. + CairoNativeStackConfig::round_up_to_mb( + stack_size_based_on_gas.clamp(self.min_stack_red_zone, self.max_stack_size), + ) + } + + pub fn get_target_stack_size(&self, red_zone: u64) -> u64 { + // Stack size should be a multiple of page size, since `stacker::grow` works with this unit. + CairoNativeStackConfig::round_up_to_mb(red_zone + self.buffer_size) + } +} + #[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq)] pub struct EventLimits { pub max_data_length: usize, @@ -377,12 +455,12 @@ pub struct OsResources { // steps). // TODO(Arni, 14/6/2023): Update `GetBlockHash` values. // TODO(ilya): Consider moving the resources of a keccak round to a seperate dict. - execute_syscalls: HashMap, + execute_syscalls: HashMap, // Mapping from every transaction to its extra execution resources in the OS, // i.e., resources that don't count during the execution itself. // For each transaction the OS uses a constant amount of VM resources, and an // additional variable amount that depends on the calldata length. - execute_txs_inner: HashMap, + execute_txs_inner: HashMap, // Resources needed for the OS to compute the KZG commitment info, as a factor of the data // segment length. Does not include poseidon_hash_many cost. @@ -429,13 +507,12 @@ impl OsResources { let execution_resources = self .execute_txs_inner .values() - .flat_map(|resources_vector| { - [ - &resources_vector.deprecated_resources.constant, - &resources_vector.deprecated_resources.calldata_factor, - ] + .flat_map(|resources_params| { + [&resources_params.constant, &resources_params.calldata_factor] }) - .chain(self.execute_syscalls.values()) + .chain(self.execute_syscalls.values().flat_map(|resources_params| { + [&resources_params.constant, &resources_params.calldata_factor] + })) .chain(std::iter::once(&self.compute_os_kzg_commitment_info)); let builtin_names = execution_resources.flat_map(|resources| resources.builtin_instance_counter.keys()); @@ -473,26 +550,37 @@ impl OsResources { /// i.e., the resources of the Starknet OS function `execute_syscalls`. fn get_additional_os_syscall_resources( &self, - syscall_counter: &SyscallCounter, + syscalls_usage: &SyscallUsageMap, ) -> ExecutionResources { let mut os_additional_resources = ExecutionResources::default(); - for (syscall_selector, count) in syscall_counter { + for (syscall_selector, syscall_usage) in syscalls_usage { + if syscall_selector == &SyscallSelector::Keccak { + let keccak_base_resources = + self.execute_syscalls.get(syscall_selector).unwrap_or_else(|| { + panic!("OS resources of syscall '{syscall_selector:?}' are unknown.") + }); + os_additional_resources += &keccak_base_resources.constant; + } + let syscall_selector = if syscall_selector == &SyscallSelector::Keccak { + &SyscallSelector::KeccakRound + } else { + syscall_selector + }; let syscall_resources = self.execute_syscalls.get(syscall_selector).unwrap_or_else(|| { panic!("OS resources of syscall '{syscall_selector:?}' are unknown.") }); - os_additional_resources += &(syscall_resources * *count); + os_additional_resources += &(&(&syscall_resources.constant * syscall_usage.call_count) + + &(&syscall_resources.calldata_factor * syscall_usage.linear_factor)); } os_additional_resources } fn resources_params_for_tx_type(&self, tx_type: &TransactionType) -> &ResourcesParams { - &(self - .execute_txs_inner + self.execute_txs_inner .get(tx_type) .unwrap_or_else(|| panic!("should contain transaction type '{tx_type:?}'.")) - .deprecated_resources) } fn resources_for_tx_type( @@ -532,107 +620,88 @@ impl<'de> Deserialize<'de> for OsResources { } } -/// Gas cost constants. For more documentation see in core/os/constants.cairo. -#[derive(Debug, Default, Deserialize)] -pub struct GasCosts { - pub step_gas_cost: u64, - pub memory_hole_gas_cost: u64, - // Range check has a hard-coded cost higher than its proof percentage to avoid the overhead of - // retrieving its price from the table. - pub range_check_gas_cost: u64, - // Priced builtins. - pub pedersen_gas_cost: u64, - pub bitwise_builtin_gas_cost: u64, - pub ecop_gas_cost: u64, - pub poseidon_gas_cost: u64, - pub add_mod_gas_cost: u64, - pub mul_mod_gas_cost: u64, - // An estimation of the initial gas for a transaction to run with. This solution is - // temporary and this value will be deduced from the transaction's fields. - pub default_initial_gas_cost: u64, - // Compiler gas costs. - pub entry_point_initial_budget: u64, - pub syscall_base_gas_cost: u64, - // OS gas costs. - pub entry_point_gas_cost: u64, - pub transaction_gas_cost: u64, - // Syscall gas costs. - pub call_contract_gas_cost: u64, - pub deploy_gas_cost: u64, - pub get_block_hash_gas_cost: u64, - pub get_execution_info_gas_cost: u64, - pub library_call_gas_cost: u64, - pub replace_class_gas_cost: u64, - pub storage_read_gas_cost: u64, - pub storage_write_gas_cost: u64, - pub get_class_hash_at_gas_cost: u64, - pub emit_event_gas_cost: u64, - pub send_message_to_l1_gas_cost: u64, - pub secp256k1_add_gas_cost: u64, - pub secp256k1_get_point_from_x_gas_cost: u64, - pub secp256k1_get_xy_gas_cost: u64, - pub secp256k1_mul_gas_cost: u64, - pub secp256k1_new_gas_cost: u64, - pub secp256r1_add_gas_cost: u64, - pub secp256r1_get_point_from_x_gas_cost: u64, - pub secp256r1_get_xy_gas_cost: u64, - pub secp256r1_mul_gas_cost: u64, - pub secp256r1_new_gas_cost: u64, - pub keccak_gas_cost: u64, - pub keccak_round_cost_gas_cost: u64, - pub sha256_process_block_gas_cost: u64, -} - -impl GasCosts { - pub fn get_builtin_gas_cost(&self, builtin: &BuiltinName) -> Result { - const KECCAK_BUILTIN_GAS_COST: u64 = 136189; +#[derive(Deserialize, PartialEq, Debug, Clone, Copy, Serialize, Default)] +pub struct SyscallGasCost { + base: u64, + linear_factor: u64, +} - let gas_cost = match *builtin { - BuiltinName::range_check => self.range_check_gas_cost, - BuiltinName::pedersen => self.pedersen_gas_cost, - BuiltinName::bitwise => self.bitwise_builtin_gas_cost, - BuiltinName::ec_op => self.ecop_gas_cost, - // TODO (Yonatan): once keccak_builtin_gas_cost is being inserted to the versioned - // constants, replace the constant with field's value - BuiltinName::keccak => KECCAK_BUILTIN_GAS_COST, - BuiltinName::poseidon => self.poseidon_gas_cost, - BuiltinName::range_check96 => self.range_check_gas_cost, - BuiltinName::add_mod => self.add_mod_gas_cost, - BuiltinName::mul_mod => self.mul_mod_gas_cost, - BuiltinName::segment_arena => return Err(GasCostsError::VirtualBuiltin), - BuiltinName::output | BuiltinName::ecdsa => { - return Err(GasCostsError::UnsupportedBuiltinInCairo1 { builtin: *builtin }); - } - }; +impl SyscallGasCost { + pub fn new_from_base_cost(base: u64) -> Self { + Self { base, linear_factor: 0 } + } - Ok(gas_cost) + pub fn get_syscall_cost(&self, linear_length: u64) -> u64 { + self.base + self.linear_factor * linear_length + } + + pub fn base_syscall_cost(&self) -> u64 { + assert!(self.linear_factor == 0, "The syscall has a linear factor cost to be considered."); + self.base } +} + +#[cfg_attr(any(test, feature = "testing"), derive(Clone, Copy))] +#[derive(Debug, Default, Deserialize, PartialEq)] +pub struct SyscallGasCosts { + pub call_contract: SyscallGasCost, + pub deploy: SyscallGasCost, + pub get_block_hash: SyscallGasCost, + pub get_execution_info: SyscallGasCost, + pub library_call: SyscallGasCost, + pub replace_class: SyscallGasCost, + pub storage_read: SyscallGasCost, + pub storage_write: SyscallGasCost, + pub get_class_hash_at: SyscallGasCost, + pub emit_event: SyscallGasCost, + pub send_message_to_l1: SyscallGasCost, + pub secp256k1_add: SyscallGasCost, + pub secp256k1_get_point_from_x: SyscallGasCost, + pub secp256k1_get_xy: SyscallGasCost, + pub secp256k1_mul: SyscallGasCost, + pub secp256k1_new: SyscallGasCost, + pub secp256r1_add: SyscallGasCost, + pub secp256r1_get_point_from_x: SyscallGasCost, + pub secp256r1_get_xy: SyscallGasCost, + pub secp256r1_mul: SyscallGasCost, + pub secp256r1_new: SyscallGasCost, + pub keccak: SyscallGasCost, + pub keccak_round_cost: SyscallGasCost, + pub meta_tx_v0: SyscallGasCost, + pub sha256_process_block: SyscallGasCost, +} - pub fn get_syscall_gas_cost(&self, selector: &SyscallSelector) -> Result { +impl SyscallGasCosts { + pub fn get_syscall_gas_cost( + &self, + selector: &SyscallSelector, + ) -> Result { let gas_cost = match *selector { - SyscallSelector::CallContract => self.call_contract_gas_cost, - SyscallSelector::Deploy => self.deploy_gas_cost, - SyscallSelector::EmitEvent => self.emit_event_gas_cost, - SyscallSelector::GetBlockHash => self.get_block_hash_gas_cost, - SyscallSelector::GetExecutionInfo => self.get_execution_info_gas_cost, - SyscallSelector::GetClassHashAt => self.get_class_hash_at_gas_cost, - SyscallSelector::Keccak => self.keccak_gas_cost, - SyscallSelector::Sha256ProcessBlock => self.sha256_process_block_gas_cost, - SyscallSelector::LibraryCall => self.library_call_gas_cost, - SyscallSelector::ReplaceClass => self.replace_class_gas_cost, - SyscallSelector::Secp256k1Add => self.secp256k1_add_gas_cost, - SyscallSelector::Secp256k1GetPointFromX => self.secp256k1_get_point_from_x_gas_cost, - SyscallSelector::Secp256k1GetXy => self.secp256k1_get_xy_gas_cost, - SyscallSelector::Secp256k1Mul => self.secp256k1_mul_gas_cost, - SyscallSelector::Secp256k1New => self.secp256k1_new_gas_cost, - SyscallSelector::Secp256r1Add => self.secp256r1_add_gas_cost, - SyscallSelector::Secp256r1GetPointFromX => self.secp256r1_get_point_from_x_gas_cost, - SyscallSelector::Secp256r1GetXy => self.secp256r1_get_xy_gas_cost, - SyscallSelector::Secp256r1Mul => self.secp256r1_mul_gas_cost, - SyscallSelector::Secp256r1New => self.secp256r1_new_gas_cost, - SyscallSelector::SendMessageToL1 => self.send_message_to_l1_gas_cost, - SyscallSelector::StorageRead => self.storage_read_gas_cost, - SyscallSelector::StorageWrite => self.storage_write_gas_cost, + SyscallSelector::CallContract => self.call_contract, + SyscallSelector::Deploy => self.deploy, + SyscallSelector::EmitEvent => self.emit_event, + SyscallSelector::GetBlockHash => self.get_block_hash, + SyscallSelector::GetExecutionInfo => self.get_execution_info, + SyscallSelector::GetClassHashAt => self.get_class_hash_at, + SyscallSelector::KeccakRound => self.keccak_round_cost, + SyscallSelector::Keccak => self.keccak, + SyscallSelector::Sha256ProcessBlock => self.sha256_process_block, + SyscallSelector::LibraryCall => self.library_call, + SyscallSelector::MetaTxV0 => self.meta_tx_v0, + SyscallSelector::ReplaceClass => self.replace_class, + SyscallSelector::Secp256k1Add => self.secp256k1_add, + SyscallSelector::Secp256k1GetPointFromX => self.secp256k1_get_point_from_x, + SyscallSelector::Secp256k1GetXy => self.secp256k1_get_xy, + SyscallSelector::Secp256k1Mul => self.secp256k1_mul, + SyscallSelector::Secp256k1New => self.secp256k1_new, + SyscallSelector::Secp256r1Add => self.secp256r1_add, + SyscallSelector::Secp256r1GetPointFromX => self.secp256r1_get_point_from_x, + SyscallSelector::Secp256r1GetXy => self.secp256r1_get_xy, + SyscallSelector::Secp256r1Mul => self.secp256r1_mul, + SyscallSelector::Secp256r1New => self.secp256r1_new, + SyscallSelector::SendMessageToL1 => self.send_message_to_l1, + SyscallSelector::StorageRead => self.storage_read, + SyscallSelector::StorageWrite => self.storage_write, SyscallSelector::DelegateCall | SyscallSelector::DelegateL1Handler | SyscallSelector::GetBlockNumber @@ -651,25 +720,96 @@ impl GasCosts { } } +#[cfg_attr(any(test, feature = "testing"), derive(Clone, Copy))] +#[derive(Debug, Default, Deserialize)] +pub struct BaseGasCosts { + pub step_gas_cost: u64, + pub memory_hole_gas_cost: u64, + // An estimation of the initial gas for a transaction to run with. This solution is + // temporary and this value will be deduced from the transaction's fields. + pub default_initial_gas_cost: u64, + // Compiler gas costs. + pub entry_point_initial_budget: u64, + pub syscall_base_gas_cost: u64, +} + +#[cfg_attr(any(test, feature = "testing"), derive(Clone, Copy))] +#[derive(Debug, Default, Deserialize)] +pub struct BuiltinGasCosts { + // Range check has a hard-coded cost higher than its proof percentage to avoid the overhead of + // retrieving its price from the table. + pub range_check: u64, + pub range_check96: u64, + // Priced builtins. + pub keccak: u64, + pub pedersen: u64, + pub bitwise: u64, + pub ecop: u64, + pub poseidon: u64, + pub add_mod: u64, + pub mul_mod: u64, + pub ecdsa: u64, +} + +impl BuiltinGasCosts { + pub fn get_builtin_gas_cost(&self, builtin: &BuiltinName) -> Result { + let gas_cost = match *builtin { + BuiltinName::range_check => self.range_check, + BuiltinName::pedersen => self.pedersen, + BuiltinName::bitwise => self.bitwise, + BuiltinName::ec_op => self.ecop, + BuiltinName::keccak => self.keccak, + BuiltinName::poseidon => self.poseidon, + BuiltinName::range_check96 => self.range_check96, + BuiltinName::add_mod => self.add_mod, + BuiltinName::mul_mod => self.mul_mod, + BuiltinName::ecdsa => self.ecdsa, + BuiltinName::segment_arena => return Err(GasCostsError::VirtualBuiltin), + BuiltinName::output => { + return Err(GasCostsError::UnsupportedBuiltinInCairo1 { builtin: *builtin }); + } + }; + + Ok(gas_cost) + } +} + +/// Gas cost constants. For more documentation see in core/os/constants.cairo. +#[cfg_attr(any(test, feature = "testing"), derive(Clone, Copy))] +#[derive(Debug, Default, Deserialize)] +pub struct GasCosts { + pub base: BaseGasCosts, + pub builtins: BuiltinGasCosts, + pub syscalls: SyscallGasCosts, +} + // Below, serde first deserializes the json into a regular IndexMap wrapped by the newtype // `OsConstantsRawJson`, then calls the `try_from` of the newtype, which handles the // conversion into actual values. -// TODO: consider encoding the * and + operations inside the json file, instead of hardcoded below -// in the `try_from`. +// TODO(Dori): consider encoding the * and + operations inside the json file, instead of hardcoded +// below in the `try_from`. +#[cfg_attr(any(test, feature = "testing"), derive(Clone))] #[derive(Debug, Default, Deserialize)] #[serde(try_from = "OsConstantsRawJson")] pub struct OsConstants { pub gas_costs: GasCosts, pub validate_rounding_consts: ValidateRoundingConsts, + pub os_contract_addresses: OsContractAddresses, + pub validate_max_sierra_gas: GasAmount, + pub execute_max_sierra_gas: GasAmount, + pub v1_bound_accounts_cairo0: Vec, + pub v1_bound_accounts_cairo1: Vec, + pub v1_bound_accounts_max_tip: Tip, + pub l1_handler_max_amount_bounds: GasVector, + pub data_gas_accounts: Vec, } impl OsConstants { - // List of additinal os constants, beside the gas cost and validate rounding constants, that are - // not used by the blockifier but included for transparency. These constanst will be ignored - // during the creation of the struct containing the gas costs. + // List of os constants to be ignored + // during the creation of the struct containing the base gas costs. - const ADDITIONAL_FIELDS: [&'static str; 29] = [ - "block_hash_contract_address", + const ADDITIONAL_FIELDS: [&'static str; 32] = [ + "builtin_gas_costs", "constructor_entry_point_selector", "default_entry_point_selector", "entry_point_type_constructor", @@ -682,6 +822,7 @@ impl OsConstants { "error_entry_point_not_found", "error_out_of_gas", "execute_entry_point_selector", + "execute_max_sierra_gas", "l1_gas", "l1_gas_index", "l1_handler_version", @@ -692,10 +833,12 @@ impl OsConstants { "nop_entry_point_offset", "sierra_array_len_bound", "stored_block_hash_buffer", + "syscall_gas_costs", "transfer_entry_point_selector", "validate_declare_entry_point_selector", "validate_deploy_entry_point_selector", "validate_entry_point_selector", + "validate_max_sierra_gas", "validate_rounding_consts", "validated", ]; @@ -705,9 +848,18 @@ impl TryFrom<&OsConstantsRawJson> for GasCosts { type Error = OsConstantsSerdeError; fn try_from(raw_json_data: &OsConstantsRawJson) -> Result { - let gas_costs_value: Value = serde_json::to_value(&raw_json_data.parse_gas_costs()?)?; - let gas_costs: GasCosts = serde_json::from_value(gas_costs_value)?; - Ok(gas_costs) + let base_value: Value = serde_json::to_value(&raw_json_data.parse_base()?)?; + let base: BaseGasCosts = serde_json::from_value(base_value)?; + let builtins_value: Value = serde_json::to_value(&raw_json_data.parse_builtin()?)?; + let builtins: BuiltinGasCosts = serde_json::from_value(builtins_value)?; + if (raw_json_data.raw_json_file_as_dict).contains_key("syscall_gas_costs") { + let syscalls_value: Value = + serde_json::to_value(&raw_json_data.parse_syscalls(&base, &builtins)?)?; + let syscalls: SyscallGasCosts = serde_json::from_value(syscalls_value)?; + Ok(GasCosts { base, builtins, syscalls }) + } else { + Ok(GasCosts { base, builtins, syscalls: SyscallGasCosts::default() }) + } } } @@ -717,10 +869,69 @@ impl TryFrom for OsConstants { fn try_from(raw_json_data: OsConstantsRawJson) -> Result { let gas_costs = GasCosts::try_from(&raw_json_data)?; let validate_rounding_consts = raw_json_data.validate_rounding_consts; - let os_constants = OsConstants { gas_costs, validate_rounding_consts }; + let os_contract_addresses = raw_json_data.os_contract_addresses; + let key = "validate_max_sierra_gas"; + let validate_max_sierra_gas = GasAmount(serde_json::from_value( + raw_json_data + .raw_json_file_as_dict + .get(key) + .ok_or_else(|| OsConstantsSerdeError::KeyNotFoundInFile(key.to_string()))? + .clone(), + )?); + let key = "execute_max_sierra_gas"; + let execute_max_sierra_gas = GasAmount(serde_json::from_value( + raw_json_data + .raw_json_file_as_dict + .get(key) + .ok_or_else(|| OsConstantsSerdeError::KeyNotFoundInFile(key.to_string()))? + .clone(), + )?); + let v1_bound_accounts_cairo0 = raw_json_data.v1_bound_accounts_cairo0; + let v1_bound_accounts_cairo1 = raw_json_data.v1_bound_accounts_cairo1; + let v1_bound_accounts_max_tip = raw_json_data.v1_bound_accounts_max_tip; + let data_gas_accounts = raw_json_data.data_gas_accounts; + let l1_handler_max_amount_bounds = raw_json_data.l1_handler_max_amount_bounds; + let os_constants = OsConstants { + gas_costs, + validate_rounding_consts, + os_contract_addresses, + validate_max_sierra_gas, + execute_max_sierra_gas, + v1_bound_accounts_cairo0, + v1_bound_accounts_cairo1, + v1_bound_accounts_max_tip, + data_gas_accounts, + l1_handler_max_amount_bounds, + }; Ok(os_constants) } } +#[derive(Clone, Copy, Debug, Deserialize, Serialize)] +pub struct OsContractAddresses { + block_hash_contract_address: u8, + alias_contract_address: u8, + reserved_contract_address: u8, +} + +impl OsContractAddresses { + pub fn block_hash_contract_address(&self) -> ContractAddress { + ContractAddress::from(self.block_hash_contract_address) + } + + pub fn alias_contract_address(&self) -> ContractAddress { + ContractAddress::from(self.alias_contract_address) + } + + pub fn reserved_contract_address(&self) -> ContractAddress { + ContractAddress::from(self.reserved_contract_address) + } +} + +impl Default for OsContractAddresses { + fn default() -> Self { + VersionedConstants::latest_constants().os_constants.os_contract_addresses + } +} // Intermediate representation of the JSON file in order to make the deserialization easier, using a // regular try_from. @@ -730,11 +941,17 @@ struct OsConstantsRawJson { raw_json_file_as_dict: IndexMap, #[serde(default)] validate_rounding_consts: ValidateRoundingConsts, + os_contract_addresses: OsContractAddresses, + v1_bound_accounts_cairo0: Vec, + v1_bound_accounts_cairo1: Vec, + v1_bound_accounts_max_tip: Tip, + data_gas_accounts: Vec, + l1_handler_max_amount_bounds: GasVector, } impl OsConstantsRawJson { - fn parse_gas_costs(&self) -> Result, OsConstantsSerdeError> { - let mut gas_costs = IndexMap::new(); + fn parse_base(&self) -> Result, OsConstantsSerdeError> { + let mut base = IndexMap::new(); let additional_fields: IndexSet<_> = OsConstants::ADDITIONAL_FIELDS.iter().copied().collect(); for (key, value) in &self.raw_json_file_as_dict { @@ -743,14 +960,60 @@ impl OsConstantsRawJson { continue; } - self.recursive_add_to_gas_costs(key, value, &mut gas_costs)?; + self.recursive_add_to_base(key, value, &mut base)?; + } + + Ok(base) + } + + fn parse_syscalls( + &self, + base: &BaseGasCosts, + builtins: &BuiltinGasCosts, + ) -> Result, OsConstantsSerdeError> { + let mut gas_costs = IndexMap::new(); + let key = "syscall_gas_costs"; + let syscalls: IndexMap = serde_json::from_value( + (self + .raw_json_file_as_dict + .get(key) + .ok_or_else(|| OsConstantsSerdeError::KeyNotFoundInFile(key.to_string()))?) + .clone(), + )?; + for (key, value) in syscalls { + self.add_to_syscalls(&key, &value, &mut gas_costs, base, builtins)?; + } + Ok(gas_costs) + } + + fn parse_builtin(&self) -> Result, OsConstantsSerdeError> { + let mut gas_costs = IndexMap::new(); + let key = "builtin_gas_costs"; + let builtins: IndexMap = serde_json::from_value( + (self + .raw_json_file_as_dict + .get(key) + .ok_or_else(|| OsConstantsSerdeError::KeyNotFoundInFile(key.to_string()))?) + .clone(), + )?; + for (key, value) in builtins { + match value { + Value::Number(n) => { + let cost = n.as_u64().ok_or_else(|| OsConstantsSerdeError::OutOfRange { + key: key.to_string(), + value: n.clone(), + })?; + gas_costs.insert(key.to_string(), cost); + } + _ => return Err(OsConstantsSerdeError::UnhandledValueType(value.clone())), + } } Ok(gas_costs) } /// Recursively adds a key to gas costs, calculating its value after processing any nested keys. // Invariant: there is no circular dependency between key definitions. - fn recursive_add_to_gas_costs( + fn recursive_add_to_base( &self, key: &str, value: &Value, @@ -782,7 +1045,7 @@ impl OsConstantsRawJson { inner_key: inner_key.clone(), } })?; - self.recursive_add_to_gas_costs(inner_key, inner_value, gas_costs)?; + self.recursive_add_to_base(inner_key, inner_value, gas_costs)?; let inner_key_value = gas_costs.get(inner_key).ok_or_else(|| { OsConstantsSerdeError::KeyNotFound { key: key.to_string(), @@ -809,6 +1072,61 @@ impl OsConstantsRawJson { Ok(()) } + + fn add_to_syscalls( + &self, + key: &str, + value: &Value, + syscalls: &mut IndexMap, + base: &BaseGasCosts, + builtins: &BuiltinGasCosts, + ) -> Result<(), OsConstantsSerdeError> { + let mut cost = 0; + match value { + Value::Object(obj) => { + for (inner_key, factor) in obj { + let inner_value = match inner_key.as_str() { + "step_gas_cost" => base.step_gas_cost, + "memory_hole_gas_cost" => base.memory_hole_gas_cost, + "default_initial_gas_cost" => base.default_initial_gas_cost, + "entry_point_initial_budget" => base.entry_point_initial_budget, + "syscall_base_gas_cost" => base.syscall_base_gas_cost, + "range_check" => builtins.range_check, + "keccak" => builtins.keccak, + "pedersen" => builtins.pedersen, + "bitwise" => builtins.bitwise, + "ecop" => builtins.ecop, + "poseidon" => builtins.poseidon, + "add_mod" => builtins.add_mod, + "mul_mod" => builtins.mul_mod, + "ecdsa" => builtins.ecdsa, + _ => { + return Err(OsConstantsSerdeError::KeyNotFound { + key: key.to_string(), + inner_key: inner_key.clone(), + }); + } + }; + let factor = + factor.as_u64().ok_or_else(|| OsConstantsSerdeError::OutOfRangeFactor { + key: key.to_string(), + value: factor.clone(), + })?; + cost += inner_value * factor; + } + syscalls.insert(key.to_string(), SyscallGasCost::new_from_base_cost(cost)); + } + Value::Number(n) => { + cost = n.as_u64().ok_or_else(|| OsConstantsSerdeError::OutOfRange { + key: key.to_string(), + value: n.clone(), + })?; + syscalls.insert(key.to_string(), SyscallGasCost::new_from_base_cost(cost)); + } + _ => return Err(OsConstantsSerdeError::UnhandledValueType(value.clone())), + } + Ok(()) + } } #[derive(Debug, Error)] @@ -831,6 +1149,8 @@ pub enum OsConstantsSerdeError { InvalidFactorFormat(Value), #[error("Unknown key '{inner_key}' used to create value for '{key}'")] KeyNotFound { key: String, inner_key: String }, + #[error("Key'{0}' is not found")] + KeyNotFoundInFile(String), #[error("Value {value} for key '{key}' is out of range and cannot be cast into u64")] OutOfRange { key: String, value: Number }, #[error( @@ -898,6 +1218,7 @@ impl TryFrom for ResourcesParams { } } +#[cfg_attr(any(test, feature = "testing"), derive(Copy))] #[derive(Clone, Debug, Deserialize)] pub struct ValidateRoundingConsts { // Flooring factor for block number in validate mode. @@ -912,17 +1233,12 @@ impl Default for ValidateRoundingConsts { } } -#[derive(Clone, Debug, Deserialize)] -pub struct ResourcesByVersion { - pub resources: ResourcesParams, - pub deprecated_resources: ResourcesParams, -} - #[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] pub struct VersionedConstantsOverrides { pub validate_max_n_steps: u32, pub max_recursion_depth: usize, pub invoke_tx_max_n_steps: u32, + pub max_n_events: usize, } impl Default for VersionedConstantsOverrides { @@ -932,6 +1248,7 @@ impl Default for VersionedConstantsOverrides { validate_max_n_steps: latest_versioned_constants.validate_max_n_steps, max_recursion_depth: latest_versioned_constants.max_recursion_depth, invoke_tx_max_n_steps: latest_versioned_constants.invoke_tx_max_n_steps, + max_n_events: latest_versioned_constants.tx_event_limits.max_n_emitted_events, } } } @@ -957,6 +1274,12 @@ impl SerializeConfig for VersionedConstantsOverrides { "Maximum number of steps the invoke function is allowed to run.", ParamPrivacyInput::Public, ), + ser_param( + "max_n_events", + &self.max_n_events, + "Maximum number of events that can be emitted from the transation.", + ParamPrivacyInput::Public, + ), ]) } } diff --git a/crates/blockifier/src/bouncer.rs b/crates/blockifier/src/bouncer.rs index 414fff93a9b..0cc129aeceb 100644 --- a/crates/blockifier/src/bouncer.rs +++ b/crates/blockifier/src/bouncer.rs @@ -6,11 +6,13 @@ use papyrus_config::dumping::{append_sub_config_name, ser_param, SerializeConfig use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; use serde::{Deserialize, Serialize}; use starknet_api::core::ClassHash; +use starknet_api::execution_resources::GasAmount; use crate::blockifier::transaction_executor::{ TransactionExecutorError, TransactionExecutorResult, }; +use crate::blockifier_versioned_constants::VersionedConstants; use crate::execution::call_info::ExecutionSummary; use crate::fee::gas_usage::get_onchain_data_segment_length; use crate::fee::resources::TransactionResources; @@ -18,13 +20,13 @@ use crate::state::cached_state::{StateChangesKeys, StorageEntry}; use crate::state::state_api::StateReader; use crate::transaction::errors::TransactionExecutionError; use crate::transaction::objects::{ExecutionResourcesTraits, TransactionExecutionResult}; -use crate::utils::usize_from_u64; +use crate::utils::{u64_from_usize, usize_from_u64}; #[cfg(test)] #[path = "bouncer_test.rs"] mod test; -macro_rules! impl_checked_sub { +macro_rules! impl_checked_ops { ($($field:ident),+) => { pub fn checked_sub(self: Self, other: Self) -> Option { Some( @@ -35,10 +37,20 @@ macro_rules! impl_checked_sub { } ) } + + pub fn checked_add(self: Self, other: Self) -> Option { + Some( + Self { + $( + $field: self.$field.checked_add(other.$field)?, + )+ + } + ) + } }; } -pub type HashMapWrapper = HashMap; +pub type BuiltinCounterMap = HashMap; #[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)] pub struct BouncerConfig { @@ -79,36 +91,19 @@ impl SerializeConfig for BouncerConfig { } } -#[derive( - Clone, - Copy, - Debug, - derive_more::Add, - derive_more::AddAssign, - derive_more::Sub, - Deserialize, - PartialEq, - Serialize, -)] +#[cfg_attr(any(test, feature = "testing"), derive(derive_more::Add, derive_more::AddAssign))] +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] /// Represents the execution resources counted throughout block creation. pub struct BouncerWeights { - pub builtin_count: BuiltinCount, - pub gas: usize, + pub l1_gas: usize, pub message_segment_length: usize, pub n_events: usize, - pub n_steps: usize, pub state_diff_size: usize, + pub sierra_gas: GasAmount, } impl BouncerWeights { - impl_checked_sub!( - builtin_count, - gas, - message_segment_length, - n_events, - n_steps, - state_diff_size - ); + impl_checked_ops!(l1_gas, message_segment_length, n_events, state_diff_size, sierra_gas); pub fn has_room(&self, other: Self) -> bool { self.checked_sub(other).is_some() @@ -116,50 +111,46 @@ impl BouncerWeights { pub fn max() -> Self { Self { - gas: usize::MAX, - n_steps: usize::MAX, + l1_gas: usize::MAX, message_segment_length: usize::MAX, - state_diff_size: usize::MAX, n_events: usize::MAX, - builtin_count: BuiltinCount::max(), + state_diff_size: usize::MAX, + sierra_gas: GasAmount::MAX, } } pub fn empty() -> Self { Self { - n_events: 0, - builtin_count: BuiltinCount::empty(), - gas: 0, + l1_gas: 0, message_segment_length: 0, - n_steps: 0, + n_events: 0, state_diff_size: 0, + sierra_gas: GasAmount::ZERO, } } } impl Default for BouncerWeights { - // TODO: update the default values once the actual values are known. + // TODO(Yael): update the default values once the actual values are known. fn default() -> Self { Self { - gas: 2500000, - n_steps: 2500000, + l1_gas: 2500000, message_segment_length: 3700, n_events: 5000, state_diff_size: 4000, - builtin_count: BuiltinCount::default(), + sierra_gas: GasAmount(400000000), } } } impl SerializeConfig for BouncerWeights { fn dump(&self) -> BTreeMap { - let mut dump = append_sub_config_name(self.builtin_count.dump(), "builtin_count"); - dump.append(&mut BTreeMap::from([ser_param( - "gas", - &self.gas, - "An upper bound on the total gas used in a block.", + let mut dump = BTreeMap::from([ser_param( + "l1_gas", + &self.l1_gas, + "An upper bound on the total l1_gas used in a block.", ParamPrivacyInput::Public, - )])); + )]); dump.append(&mut BTreeMap::from([ser_param( "message_segment_length", &self.message_segment_length, @@ -172,18 +163,18 @@ impl SerializeConfig for BouncerWeights { "An upper bound on the total number of events generated in a block.", ParamPrivacyInput::Public, )])); - dump.append(&mut BTreeMap::from([ser_param( - "n_steps", - &self.n_steps, - "An upper bound on the total number of steps in a block.", - ParamPrivacyInput::Public, - )])); dump.append(&mut BTreeMap::from([ser_param( "state_diff_size", &self.state_diff_size, "An upper bound on the total state diff size in a block.", ParamPrivacyInput::Public, )])); + dump.append(&mut BTreeMap::from([ser_param( + "sierra_gas", + &self.sierra_gas, + "An upper bound on the total sierra_gas used in a block.", + ParamPrivacyInput::Public, + )])); dump } } @@ -192,233 +183,17 @@ impl std::fmt::Display for BouncerWeights { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, - "BouncerWeights {{ gas: {}, n_steps: {}, message_segment_length: {}, n_events: {}, \ - state_diff_size: {}, builtin_count: {} }}", - self.gas, - self.n_steps, + "BouncerWeights {{ l1_gas: {}, message_segment_length: {}, n_events: {}, \ + state_diff_size: {}, sierra_gas: {} }}", + self.l1_gas, self.message_segment_length, self.n_events, self.state_diff_size, - self.builtin_count - ) - } -} - -#[derive( - Clone, - Copy, - Debug, - derive_more::Add, - derive_more::AddAssign, - derive_more::Sub, - Deserialize, - PartialEq, - Serialize, -)] -pub struct BuiltinCount { - pub add_mod: usize, - pub bitwise: usize, - pub ecdsa: usize, - pub ec_op: usize, - pub keccak: usize, - pub mul_mod: usize, - pub pedersen: usize, - pub poseidon: usize, - pub range_check: usize, - pub range_check96: usize, -} - -macro_rules! impl_all_non_zero { - ($($field:ident),+) => { - pub fn all_non_zero(&self) -> bool { - $( self.$field != 0 )&&+ - } - }; -} - -macro_rules! impl_builtin_variants { - ($($field:ident),+) => { - impl_checked_sub!($($field),+); - impl_all_non_zero!($($field),+); - }; -} - -impl BuiltinCount { - impl_builtin_variants!( - add_mod, - bitwise, - ec_op, - ecdsa, - keccak, - mul_mod, - pedersen, - poseidon, - range_check, - range_check96 - ); - - pub fn max() -> Self { - Self { - add_mod: usize::MAX, - bitwise: usize::MAX, - ecdsa: usize::MAX, - ec_op: usize::MAX, - keccak: usize::MAX, - mul_mod: usize::MAX, - pedersen: usize::MAX, - poseidon: usize::MAX, - range_check: usize::MAX, - range_check96: usize::MAX, - } - } - - pub fn empty() -> Self { - Self { - add_mod: 0, - bitwise: 0, - ecdsa: 0, - ec_op: 0, - keccak: 0, - mul_mod: 0, - pedersen: 0, - poseidon: 0, - range_check: 0, - range_check96: 0, - } - } -} - -impl From for BuiltinCount { - fn from(mut data: HashMapWrapper) -> Self { - // TODO(yael 24/3/24): replace the unwrap_or_default with expect, once the - // ExecutionResources contains all the builtins. - // The keccak config we get from python is not always present. - let builtin_count = Self { - add_mod: data.remove(&BuiltinName::add_mod).unwrap_or_default(), - bitwise: data.remove(&BuiltinName::bitwise).unwrap_or_default(), - ecdsa: data.remove(&BuiltinName::ecdsa).unwrap_or_default(), - ec_op: data.remove(&BuiltinName::ec_op).unwrap_or_default(), - keccak: data.remove(&BuiltinName::keccak).unwrap_or_default(), - mul_mod: data.remove(&BuiltinName::mul_mod).unwrap_or_default(), - pedersen: data.remove(&BuiltinName::pedersen).unwrap_or_default(), - poseidon: data.remove(&BuiltinName::poseidon).unwrap_or_default(), - range_check: data.remove(&BuiltinName::range_check).unwrap_or_default(), - range_check96: data.remove(&BuiltinName::range_check96).unwrap_or_default(), - }; - assert!( - data.is_empty(), - "The following keys do not exist in BuiltinCount: {:?} ", - data.keys() - ); - builtin_count - } -} - -impl std::fmt::Display for BuiltinCount { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "BuiltinCount {{ add_mod: {}, bitwise: {}, ecdsa: {}, ec_op: {}, keccak: {}, mul_mod: \ - {}, pedersen: {}, poseidon: {}, range_check: {}, range_check96: {} }}", - self.add_mod, - self.bitwise, - self.ecdsa, - self.ec_op, - self.keccak, - self.mul_mod, - self.pedersen, - self.poseidon, - self.range_check, - self.range_check96 + self.sierra_gas ) } } -impl Default for BuiltinCount { - // TODO: update the default values once the actual production values are known. - fn default() -> Self { - Self { - add_mod: 156250, - bitwise: 39062, - ecdsa: 1220, - ec_op: 2441, - keccak: 1220, - mul_mod: 156250, - pedersen: 78125, - poseidon: 78125, - range_check: 156250, - range_check96: 156250, - } - } -} - -impl SerializeConfig for BuiltinCount { - fn dump(&self) -> BTreeMap { - BTreeMap::from_iter([ - ser_param( - "add_mod", - &self.add_mod, - "Max number of add mod builtin usage in a block.", - ParamPrivacyInput::Public, - ), - ser_param( - "bitwise", - &self.bitwise, - "Max number of bitwise builtin usage in a block.", - ParamPrivacyInput::Public, - ), - ser_param( - "ecdsa", - &self.ecdsa, - "Max number of ECDSA builtin usage in a block.", - ParamPrivacyInput::Public, - ), - ser_param( - "ec_op", - &self.ec_op, - "Max number of EC operation builtin usage in a block.", - ParamPrivacyInput::Public, - ), - ser_param( - "keccak", - &self.keccak, - "Max number of keccak builtin usage in a block.", - ParamPrivacyInput::Public, - ), - ser_param( - "mul_mod", - &self.mul_mod, - "Max number of mul mod builtin usage in a block.", - ParamPrivacyInput::Public, - ), - ser_param( - "pedersen", - &self.pedersen, - "Max number of pedersen builtin usage in a block.", - ParamPrivacyInput::Public, - ), - ser_param( - "poseidon", - &self.poseidon, - "Max number of poseidon builtin usage in a block.", - ParamPrivacyInput::Public, - ), - ser_param( - "range_check", - &self.range_check, - "Max number of range check builtin usage in a block.", - ParamPrivacyInput::Public, - ), - ser_param( - "range_check96", - &self.range_check96, - "Max number of range check 96 builtin usage in a block.", - ParamPrivacyInput::Public, - ), - ]) - } -} - #[derive(Debug, PartialEq)] #[cfg_attr(test, derive(Clone))] pub struct Bouncer { @@ -459,6 +234,7 @@ impl Bouncer { tx_state_changes_keys: &StateChangesKeys, tx_execution_summary: &ExecutionSummary, tx_resources: &TransactionResources, + versioned_constants: &VersionedConstants, ) -> TransactionExecutorResult<()> { // The countings here should be linear in the transactional state changes and execution info // rather than the cumulative state attributes. @@ -479,10 +255,18 @@ impl Bouncer { n_marginal_visited_storage_entries, tx_resources, &marginal_state_changes_keys, + versioned_constants, )?; // Check if the transaction can fit the current block available capacity. - if !self.bouncer_config.has_room(self.accumulated_weights + tx_weights) { + let err_msg = format!( + "Addition overflow. Transaction weights: {tx_weights:?}, block weights: {:?}.", + self.accumulated_weights + ); + if !self + .bouncer_config + .has_room(self.accumulated_weights.checked_add(tx_weights).expect(&err_msg)) + { log::debug!( "Transaction cannot be added to the current block, block capacity reached; \ transaction weights: {tx_weights:?}, block weights: {:?}.", @@ -502,7 +286,12 @@ impl Bouncer { tx_execution_summary: &ExecutionSummary, state_changes_keys: &StateChangesKeys, ) { - self.accumulated_weights += tx_weights; + let err_msg = format!( + "Addition overflow. Transaction weights: {tx_weights:?}, block weights: {:?}.", + self.accumulated_weights + ); + self.accumulated_weights = + self.accumulated_weights.checked_add(tx_weights).expect(&err_msg); self.visited_storage_entries.extend(&tx_execution_summary.visited_storage_entries); self.executed_class_hashes.extend(&tx_execution_summary.executed_class_hashes); // Note: cancelling writes (0 -> 1 -> 0) will not be removed, but it's fine since fee was @@ -516,29 +305,92 @@ impl Bouncer { } } +fn n_steps_to_sierra_gas(n_steps: usize, versioned_constants: &VersionedConstants) -> GasAmount { + let n_steps_u64 = u64_from_usize(n_steps); + let gas_per_step = versioned_constants.os_constants.gas_costs.base.step_gas_cost; + let n_steps_gas_cost = n_steps_u64.checked_mul(gas_per_step).unwrap_or_else(|| { + panic!( + "Multiplication overflow while converting steps to gas. steps: {}, gas per step: {}.", + n_steps, gas_per_step + ) + }); + GasAmount(n_steps_gas_cost) +} + +fn vm_resources_to_sierra_gas( + resources: ExecutionResources, + versioned_constants: &VersionedConstants, +) -> GasAmount { + let builtins_gas_cost = + builtins_to_sierra_gas(&resources.prover_builtins(), versioned_constants); + let n_steps_gas_cost = n_steps_to_sierra_gas(resources.total_n_steps(), versioned_constants); + n_steps_gas_cost.checked_add(builtins_gas_cost).unwrap_or_else(|| { + panic!( + "Addition overflow while converting vm resources to gas. steps gas: {}, builtins gas: \ + {}.", + n_steps_gas_cost, builtins_gas_cost + ) + }) +} + +pub fn builtins_to_sierra_gas( + builtin_counts: &BuiltinCounterMap, + versioned_constants: &VersionedConstants, +) -> GasAmount { + let gas_costs = &versioned_constants.os_constants.gas_costs.builtins; + + let total_gas = builtin_counts + .iter() + .try_fold(0u64, |accumulated_gas, (&builtin, &count)| { + let builtin_gas_cost = gas_costs + .get_builtin_gas_cost(&builtin) + .unwrap_or_else(|err| panic!("Failed to get gas cost: {}", err)); + let builtin_count_u64 = u64_from_usize(count); + let builtin_total_cost = builtin_count_u64.checked_mul(builtin_gas_cost)?; + accumulated_gas.checked_add(builtin_total_cost) + }) + .unwrap_or_else(|| { + panic!( + "Overflow occurred while converting built-in resources to gas. Builtins: {:?}", + builtin_counts + ) + }); + + GasAmount(total_gas) +} + pub fn get_tx_weights( state_reader: &S, executed_class_hashes: &HashSet, n_visited_storage_entries: usize, tx_resources: &TransactionResources, state_changes_keys: &StateChangesKeys, + versioned_constants: &VersionedConstants, ) -> TransactionExecutionResult { let message_resources = &tx_resources.starknet_resources.messages; - let message_starknet_gas = usize_from_u64(message_resources.get_starknet_gas_cost().l1_gas.0) + let message_starknet_l1gas = usize_from_u64(message_resources.get_starknet_gas_cost().l1_gas.0) .expect("This conversion should not fail as the value is a converted usize."); let mut additional_os_resources = get_casm_hash_calculation_resources(state_reader, executed_class_hashes)?; additional_os_resources += &get_particia_update_resources(n_visited_storage_entries); let vm_resources = &additional_os_resources + &tx_resources.computation.vm_resources; + let sierra_gas = tx_resources.computation.sierra_gas; + let vm_resources_gas = vm_resources_to_sierra_gas(vm_resources, versioned_constants); + let sierra_gas = sierra_gas.checked_add(vm_resources_gas).unwrap_or_else(|| { + panic!( + "Addition overflow while converting vm resources to gas. current gas: {}, vm as gas: \ + {}.", + sierra_gas, vm_resources_gas + ) + }); Ok(BouncerWeights { - gas: message_starknet_gas, + l1_gas: message_starknet_l1gas, message_segment_length: message_resources.message_segment_length, n_events: tx_resources.starknet_resources.archival_data.event_summary.n_events, - n_steps: vm_resources.total_n_steps(), - builtin_count: BuiltinCount::from(vm_resources.prover_builtins()), state_diff_size: get_onchain_data_segment_length(&state_changes_keys.count()), + sierra_gas, }) } @@ -551,7 +403,7 @@ pub fn get_casm_hash_calculation_resources( let mut casm_hash_computation_resources = ExecutionResources::default(); for class_hash in executed_class_hashes { - let class = state_reader.get_compiled_contract_class(*class_hash)?; + let class = state_reader.get_compiled_class(*class_hash)?; casm_hash_computation_resources += &class.estimate_casm_hash_computation_resources(); } @@ -582,6 +434,7 @@ pub fn verify_tx_weights_within_max_capacity( tx_resources: &TransactionResources, tx_state_changes_keys: &StateChangesKeys, bouncer_config: &BouncerConfig, + versioned_constants: &VersionedConstants, ) -> TransactionExecutionResult<()> { let tx_weights = get_tx_weights( state_reader, @@ -589,6 +442,7 @@ pub fn verify_tx_weights_within_max_capacity( tx_execution_summary.visited_storage_entries.len(), tx_resources, tx_state_changes_keys, + versioned_constants, )?; bouncer_config.within_max_capacity_or_err(tx_weights) diff --git a/crates/blockifier/src/bouncer_test.rs b/crates/blockifier/src/bouncer_test.rs index 588be7b6583..3f2a704cda3 100644 --- a/crates/blockifier/src/bouncer_test.rs +++ b/crates/blockifier/src/bouncer_test.rs @@ -1,20 +1,14 @@ -use std::collections::{HashMap, HashSet}; +use std::collections::HashSet; use assert_matches::assert_matches; -use cairo_vm::types::builtin_name::BuiltinName; -use cairo_vm::vm::runners::cairo_runner::ExecutionResources; use rstest::rstest; +use starknet_api::execution_resources::GasAmount; use starknet_api::transaction::fields::Fee; use starknet_api::{class_hash, contract_address, storage_key}; use super::BouncerConfig; use crate::blockifier::transaction_executor::TransactionExecutorError; -use crate::bouncer::{ - verify_tx_weights_within_max_capacity, - Bouncer, - BouncerWeights, - BuiltinCount, -}; +use crate::bouncer::{verify_tx_weights_within_max_capacity, Bouncer, BouncerWeights}; use crate::context::BlockContext; use crate::execution::call_info::ExecutionSummary; use crate::fee::resources::{ComputationResources, TransactionResources}; @@ -25,65 +19,29 @@ use crate::transaction::errors::TransactionExecutionError; #[test] fn test_block_weights_has_room() { let max_bouncer_weights = BouncerWeights { - builtin_count: BuiltinCount { - add_mod: 10, - bitwise: 10, - ecdsa: 10, - ec_op: 10, - keccak: 10, - mul_mod: 10, - pedersen: 10, - poseidon: 10, - range_check: 10, - range_check96: 10, - }, - gas: 10, + l1_gas: 10, message_segment_length: 10, n_events: 10, - n_steps: 10, state_diff_size: 10, + sierra_gas: GasAmount(10), }; let bouncer_weights = BouncerWeights { - builtin_count: BuiltinCount { - add_mod: 6, - bitwise: 6, - ecdsa: 7, - ec_op: 7, - keccak: 8, - mul_mod: 6, - pedersen: 7, - poseidon: 9, - range_check: 10, - range_check96: 10, - }, - gas: 7, + l1_gas: 7, message_segment_length: 10, - n_steps: 0, n_events: 2, state_diff_size: 7, + sierra_gas: GasAmount(7), }; assert!(max_bouncer_weights.has_room(bouncer_weights)); let bouncer_weights_exceeds_max = BouncerWeights { - builtin_count: BuiltinCount { - add_mod: 5, - bitwise: 11, - ecdsa: 5, - ec_op: 5, - keccak: 5, - mul_mod: 5, - pedersen: 5, - poseidon: 5, - range_check: 5, - range_check96: 5, - }, - gas: 5, + l1_gas: 5, message_segment_length: 5, - n_steps: 5, n_events: 5, state_diff_size: 5, + sierra_gas: GasAmount(15), }; assert!(!max_bouncer_weights.has_room(bouncer_weights_exceeds_max)); @@ -102,23 +60,11 @@ fn test_block_weights_has_room() { ])), bouncer_config: BouncerConfig::empty(), accumulated_weights: BouncerWeights { - builtin_count: BuiltinCount { - add_mod: 10, - bitwise: 10, - ecdsa: 10, - ec_op: 10, - keccak: 10, - mul_mod: 10, - pedersen: 10, - poseidon: 10, - range_check: 10, - range_check96: 10, - }, - gas: 10, + l1_gas: 10, message_segment_length: 10, - n_steps: 10, n_events: 10, state_diff_size: 10, + sierra_gas: GasAmount(10), }, })] fn test_bouncer_update(#[case] initial_bouncer: Bouncer) { @@ -132,23 +78,11 @@ fn test_bouncer_update(#[case] initial_bouncer: Bouncer) { }; let weights_to_update = BouncerWeights { - builtin_count: BuiltinCount { - add_mod: 0, - bitwise: 1, - ecdsa: 2, - ec_op: 3, - keccak: 4, - mul_mod: 0, - pedersen: 6, - poseidon: 7, - range_check: 8, - range_check96: 0, - }, - gas: 9, + l1_gas: 9, message_segment_length: 10, - n_steps: 0, n_events: 1, state_diff_size: 2, + sierra_gas: GasAmount(9), }; let state_changes_keys_to_update = @@ -175,81 +109,43 @@ fn test_bouncer_update(#[case] initial_bouncer: Bouncer) { } #[rstest] -#[case::positive_flow(1, "ok")] -#[case::block_full(11, "block_full")] -#[case::transaction_too_large(21, "too_large")] -fn test_bouncer_try_update(#[case] added_ecdsa: usize, #[case] scenario: &'static str) { - let state = - &mut test_state(&BlockContext::create_for_account_testing().chain_info, Fee(0), &[]); +#[case::positive_flow(GasAmount(1), "ok")] +#[case::block_full(GasAmount(11), "block_full")] +#[case::transaction_too_large(GasAmount(21), "too_large")] +fn test_bouncer_try_update(#[case] added_gas: GasAmount, #[case] scenario: &'static str) { + let block_context = BlockContext::create_for_account_testing(); + let state = &mut test_state(&block_context.chain_info, Fee(0), &[]); let mut transactional_state = TransactionalState::create_transactional(state); // Setup the bouncer. let block_max_capacity = BouncerWeights { - builtin_count: BuiltinCount { - add_mod: 20, - bitwise: 20, - ecdsa: 20, - ec_op: 20, - keccak: 20, - mul_mod: 20, - pedersen: 20, - poseidon: 20, - range_check: 20, - range_check96: 20, - }, - gas: 20, + l1_gas: 20, message_segment_length: 20, - n_steps: 20, n_events: 20, state_diff_size: 20, + sierra_gas: GasAmount(20), }; let bouncer_config = BouncerConfig { block_max_capacity }; let accumulated_weights = BouncerWeights { - builtin_count: BuiltinCount { - add_mod: 10, - bitwise: 10, - ecdsa: 10, - ec_op: 10, - keccak: 10, - mul_mod: 10, - pedersen: 10, - poseidon: 10, - range_check: 10, - range_check96: 10, - }, - gas: 10, + l1_gas: 10, message_segment_length: 10, - n_steps: 10, n_events: 10, state_diff_size: 10, + sierra_gas: GasAmount(10), }; let mut bouncer = Bouncer { accumulated_weights, bouncer_config, ..Bouncer::empty() }; // Prepare the resources to be added to the bouncer. let execution_summary = ExecutionSummary { ..Default::default() }; - let builtin_counter = HashMap::from([ - (BuiltinName::bitwise, 1), - (BuiltinName::ecdsa, added_ecdsa), - (BuiltinName::ec_op, 1), - (BuiltinName::keccak, 1), - (BuiltinName::pedersen, 1), - (BuiltinName::poseidon, 1), - (BuiltinName::range_check, 1), - ]); + let tx_resources = TransactionResources { - computation: ComputationResources { - vm_resources: ExecutionResources { - builtin_instance_counter: builtin_counter.clone(), - ..Default::default() - }, - ..Default::default() - }, + computation: ComputationResources { sierra_gas: added_gas, ..Default::default() }, ..Default::default() }; let tx_state_changes_keys = - transactional_state.get_actual_state_changes().unwrap().state_maps.into_keys(); + transactional_state.get_actual_state_changes().unwrap().state_maps.keys(); // TODO(Yoni, 1/10/2024): simplify this test and move tx-too-large cases out. @@ -260,10 +156,10 @@ fn test_bouncer_try_update(#[case] added_ecdsa: usize, #[case] scenario: &'stati &tx_resources, &tx_state_changes_keys, &bouncer.bouncer_config, + &block_context.versioned_constants, ) .map_err(TransactionExecutorError::TransactionExecutionError); - let expected_weights = - BouncerWeights { builtin_count: builtin_counter.into(), ..BouncerWeights::empty() }; + let expected_weights = BouncerWeights { sierra_gas: added_gas, ..BouncerWeights::empty() }; if result.is_ok() { // Try to update the bouncer. @@ -272,6 +168,7 @@ fn test_bouncer_try_update(#[case] added_ecdsa: usize, #[case] scenario: &'stati &tx_state_changes_keys, &execution_summary, &tx_resources, + &block_context.versioned_constants, ); } diff --git a/crates/blockifier/src/concurrency/fee_utils.rs b/crates/blockifier/src/concurrency/fee_utils.rs index 8ea34ea0654..6c63a1b5103 100644 --- a/crates/blockifier/src/concurrency/fee_utils.rs +++ b/crates/blockifier/src/concurrency/fee_utils.rs @@ -11,6 +11,7 @@ use crate::fee::fee_utils::get_sequencer_balance_keys; use crate::state::cached_state::{ContractClassMapping, StateMaps}; use crate::state::state_api::UpdatableState; use crate::transaction::objects::TransactionExecutionInfo; +use crate::transaction::transaction_execution::Transaction; #[cfg(test)] #[path = "fee_utils_test.rs"] @@ -25,7 +26,9 @@ pub(crate) const STORAGE_READ_SEQUENCER_BALANCE_INDICES: (usize, usize) = (2, 3) pub fn complete_fee_transfer_flow( tx_context: &TransactionContext, tx_execution_info: &mut TransactionExecutionInfo, + state_diff: &mut StateMaps, state: &mut impl UpdatableState, + tx: &Transaction, ) { if tx_context.is_sequencer_the_sender() { // When the sequencer is the sender, we use the sequential (full) fee transfer. @@ -54,10 +57,14 @@ pub fn complete_fee_transfer_flow( tx_execution_info.receipt.fee, &tx_context.block_context, sequencer_balance, + tx_context.tx_info.sender_address(), + state_diff, ); } else { - // Assumes we set the charge fee flag to the transaction enforce fee value. - let charge_fee = tx_context.tx_info.enforce_fee(); + let charge_fee = match tx { + Transaction::Account(tx) => tx.execution_flags.charge_fee, + Transaction::L1Handler(_) => tx_context.tx_info.enforce_fee(), + }; assert!(!charge_fee, "Transaction with no fee transfer info must not enforce a fee charge.") } } @@ -69,7 +76,7 @@ pub fn fill_sequencer_balance_reads( sequencer_balance: (Felt, Felt), ) { let storage_read_values = if fee_transfer_call_info.inner_calls.is_empty() { - &mut fee_transfer_call_info.storage_read_values + &mut fee_transfer_call_info.storage_access_tracker.storage_read_values } else // Proxy pattern. { @@ -78,7 +85,7 @@ pub fn fill_sequencer_balance_reads( 1, "Proxy pattern should have one inner call" ); - &mut fee_transfer_call_info.inner_calls[0].storage_read_values + &mut fee_transfer_call_info.inner_calls[0].storage_access_tracker.storage_read_values }; assert_eq!(storage_read_values.len(), 4, "Storage read values should have 4 elements"); @@ -97,16 +104,23 @@ pub fn add_fee_to_sequencer_balance( actual_fee: Fee, block_context: &BlockContext, sequencer_balance: (Felt, Felt), + sender_address: ContractAddress, + state_diff: &mut StateMaps, ) { + assert_ne!( + sender_address, block_context.block_info.sequencer_address, + "The sender cannot be the sequencer." + ); let (low, high) = sequencer_balance; let sequencer_balance_low_as_u128 = low.to_u128().expect("sequencer balance low should be u128"); let sequencer_balance_high_as_u128 = high.to_u128().expect("sequencer balance high should be u128"); - let (new_value_low, carry) = sequencer_balance_low_as_u128.overflowing_add(actual_fee.0); - let (new_value_high, carry) = sequencer_balance_high_as_u128.overflowing_add(carry.into()); + let (new_value_low, overflow_low) = sequencer_balance_low_as_u128.overflowing_add(actual_fee.0); + let (new_value_high, overflow_high) = + sequencer_balance_high_as_u128.overflowing_add(overflow_low.into()); assert!( - !carry, + !overflow_high, "The sequencer balance overflowed when adding the fee. This should not happen." ); let (sequencer_balance_key_low, sequencer_balance_key_high) = @@ -118,5 +132,23 @@ pub fn add_fee_to_sequencer_balance( ]), ..StateMaps::default() }; - state.apply_writes(&writes, &ContractClassMapping::default(), &HashMap::default()); + + // Modify state_diff to accurately reflect the post tx-execution state, after fee transfer to + // the sequencer. We assume that a non-sequencer sender cannot reduce the sequencer's + // balance—only increases are possible. + + if sequencer_balance_high_as_u128 != new_value_high { + // Update the high balance only if it has changed. + state_diff + .storage + .insert((fee_token_address, sequencer_balance_key_high), Felt::from(new_value_high)); + } + + if sequencer_balance_low_as_u128 != new_value_low { + // Update the low balance only if it has changed. + state_diff + .storage + .insert((fee_token_address, sequencer_balance_key_low), Felt::from(new_value_low)); + } + state.apply_writes(&writes, &ContractClassMapping::default()); } diff --git a/crates/blockifier/src/concurrency/fee_utils_test.rs b/crates/blockifier/src/concurrency/fee_utils_test.rs index d5884c4530b..57076f1918e 100644 --- a/crates/blockifier/src/concurrency/fee_utils_test.rs +++ b/crates/blockifier/src/concurrency/fee_utils_test.rs @@ -1,5 +1,9 @@ +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; +use blockifier_test_utils::calldata::create_trivial_calldata; +use blockifier_test_utils::contracts::FeatureContract; use num_bigint::BigUint; use rstest::rstest; +use starknet_api::block::FeeType; use starknet_api::transaction::fields::{Fee, ValidResourceBounds}; use starknet_api::{felt, invoke_tx_args}; use starknet_types_core::felt::Felt; @@ -8,31 +12,32 @@ use crate::concurrency::fee_utils::{add_fee_to_sequencer_balance, fill_sequencer use crate::concurrency::test_utils::create_fee_transfer_call_info; use crate::context::BlockContext; use crate::fee::fee_utils::get_sequencer_balance_keys; +use crate::state::cached_state::StateMaps; use crate::state::state_api::StateReader; -use crate::test_utils::contracts::FeatureContract; use crate::test_utils::initial_test_state::{fund_account, test_state, test_state_inner}; -use crate::test_utils::{create_trivial_calldata, CairoVersion, BALANCE}; -use crate::transaction::objects::FeeType; +use crate::test_utils::BALANCE; use crate::transaction::test_utils::{ - account_invoke_tx, block_context, default_all_resource_bounds, + invoke_tx_with_default_flags, }; #[rstest] pub fn test_fill_sequencer_balance_reads( block_context: BlockContext, default_all_resource_bounds: ValidResourceBounds, - #[values(CairoVersion::Cairo0, CairoVersion::Cairo1)] erc20_version: CairoVersion, + #[values(CairoVersion::Cairo0, CairoVersion::Cairo1(RunnableCairo1::Casm))] + erc20_version: CairoVersion, ) { - let account = FeatureContract::AccountWithoutValidations(CairoVersion::Cairo1); - let account_tx = account_invoke_tx(invoke_tx_args! { + let account = + FeatureContract::AccountWithoutValidations(CairoVersion::Cairo1(RunnableCairo1::Casm)); + let account_tx = invoke_tx_with_default_flags(invoke_tx_args! { sender_address: account.get_instance_address(0), calldata: create_trivial_calldata(account.get_instance_address(0)), resource_bounds: default_all_resource_bounds, }); let chain_info = &block_context.chain_info; - let state = &mut test_state_inner(chain_info, BALANCE, &[(account, 1)], erc20_version); + let state = &mut test_state_inner(chain_info, BALANCE, &[(account.into(), 1)], erc20_version); let sequencer_balance = Fee(100); let sequencer_address = block_context.block_info.sequencer_address; @@ -61,12 +66,13 @@ pub fn test_add_fee_to_sequencer_balance( #[case] sequencer_balance_high: Felt, ) { let block_context = BlockContext::create_for_account_testing(); - let account = FeatureContract::Empty(CairoVersion::Cairo1); + let account = FeatureContract::Empty(CairoVersion::Cairo1(RunnableCairo1::Casm)); let mut state = test_state(&block_context.chain_info, Fee(0), &[(account, 1)]); let (sequencer_balance_key_low, sequencer_balance_key_high) = get_sequencer_balance_keys(&block_context); let fee_token_address = block_context.chain_info.fee_token_address(&FeeType::Strk); + let state_diff = &mut StateMaps::default(); add_fee_to_sequencer_balance( fee_token_address, @@ -74,6 +80,8 @@ pub fn test_add_fee_to_sequencer_balance( actual_fee, &block_context, (sequencer_balance_low, sequencer_balance_high), + account.get_instance_address(0), + state_diff, ); let new_sequencer_balance_value_low = @@ -89,4 +97,28 @@ pub fn test_add_fee_to_sequencer_balance( assert_eq!(new_sequencer_balance_value_low, expected_sequencer_balance_value_low); assert_eq!(new_sequencer_balance_value_high, expected_sequencer_balance_value_high); + + let expected_state_diff = StateMaps { + storage: { + let mut storage_entries = Vec::new(); + if new_sequencer_balance_value_low != sequencer_balance_low { + storage_entries.push(( + (fee_token_address, sequencer_balance_key_low), + new_sequencer_balance_value_low, + )); + } + if new_sequencer_balance_value_high != sequencer_balance_high { + storage_entries.push(( + (fee_token_address, sequencer_balance_key_high), + new_sequencer_balance_value_high, + )); + } + storage_entries + } + .into_iter() + .collect(), + ..StateMaps::default() + }; + + assert_eq!(state_diff, &expected_state_diff); } diff --git a/crates/blockifier/src/concurrency/flow_test.rs b/crates/blockifier/src/concurrency/flow_test.rs index 5b828c32600..15f0af4f50c 100644 --- a/crates/blockifier/src/concurrency/flow_test.rs +++ b/crates/blockifier/src/concurrency/flow_test.rs @@ -48,11 +48,7 @@ fn scheduler_flow_test( Task::ExecutionTask(tx_index), &versioned_state, ); - state_proxy.apply_writes( - &new_writes, - &ContractClassMapping::default(), - &HashMap::default(), - ); + state_proxy.apply_writes(&new_writes, &ContractClassMapping::default()); scheduler.finish_execution_during_commit(tx_index); } } @@ -61,11 +57,9 @@ fn scheduler_flow_test( Task::ExecutionTask(tx_index) => { let (_, writes) = get_reads_writes_for(Task::ExecutionTask(tx_index), &versioned_state); - versioned_state.pin_version(tx_index).apply_writes( - &writes, - &ContractClassMapping::default(), - &HashMap::default(), - ); + versioned_state + .pin_version(tx_index) + .apply_writes(&writes, &ContractClassMapping::default()); scheduler.finish_execution(tx_index); Task::AskForTask } diff --git a/crates/blockifier/src/concurrency/test_utils.rs b/crates/blockifier/src/concurrency/test_utils.rs index 96e8d20261d..fa18a9f32f3 100644 --- a/crates/blockifier/src/concurrency/test_utils.rs +++ b/crates/blockifier/src/concurrency/test_utils.rs @@ -9,7 +9,7 @@ use crate::state::cached_state::{CachedState, TransactionalState}; use crate::state::state_api::StateReader; use crate::test_utils::dict_state_reader::DictStateReader; use crate::transaction::account_transaction::AccountTransaction; -use crate::transaction::transactions::{ExecutableTransaction, ExecutionFlags}; +use crate::transaction::transactions::ExecutableTransaction; // Public Consts. @@ -76,9 +76,8 @@ pub fn create_fee_transfer_call_info( ) -> CallInfo { let block_context = BlockContext::create_for_account_testing(); let mut transactional_state = TransactionalState::create_transactional(state); - let execution_flags = ExecutionFlags { charge_fee: true, validate: true, concurrency_mode }; let execution_info = - account_tx.execute_raw(&mut transactional_state, &block_context, execution_flags).unwrap(); + account_tx.execute_raw(&mut transactional_state, &block_context, concurrency_mode).unwrap(); let execution_info = execution_info.fee_transfer_call_info.unwrap(); transactional_state.abort(); diff --git a/crates/blockifier/src/concurrency/versioned_state.rs b/crates/blockifier/src/concurrency/versioned_state.rs index 33d97670b9e..901ad1c7636 100644 --- a/crates/blockifier/src/concurrency/versioned_state.rs +++ b/crates/blockifier/src/concurrency/versioned_state.rs @@ -1,4 +1,3 @@ -use std::collections::{HashMap, HashSet}; use std::sync::{Arc, Mutex, MutexGuard}; use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; @@ -7,7 +6,7 @@ use starknet_types_core::felt::Felt; use crate::concurrency::versioned_storage::VersionedStorage; use crate::concurrency::TxIndex; -use crate::execution::contract_class::RunnableContractClass; +use crate::execution::contract_class::RunnableCompiledClass; use crate::state::cached_state::{ContractClassMapping, StateMaps}; use crate::state::errors::StateError; use crate::state::state_api::{StateReader, StateResult, UpdatableState}; @@ -34,7 +33,7 @@ pub struct VersionedState { // the compiled contract classes mapping. Each key with value false, sohuld not apprear // in the compiled contract classes mapping. declared_contracts: VersionedStorage, - compiled_contract_classes: VersionedStorage, + compiled_contract_classes: VersionedStorage, } impl VersionedState { @@ -74,8 +73,8 @@ impl VersionedState { // TODO(Mohammad, 01/04/2024): Store the read set (and write set) within a shared // object (probabily `VersionedState`). As RefCell operations are not thread-safe. Therefore, // accessing this function should be protected by a mutex to ensure thread safety. - // TODO: Consider coupling the tx index with the read set to ensure any mismatch between them - // will cause the validation to fail. + // TODO(Mohammad): Consider coupling the tx index with the read set to ensure any mismatch + // between them will cause the validation to fail. fn validate_reads(&mut self, tx_index: TxIndex, reads: &StateMaps) -> bool { // If is the first transaction in the chunk, then the read set is valid. Since it has no // predecessors, there's nothing to compare it to. @@ -199,11 +198,7 @@ impl VersionedState { } impl VersionedState { - pub fn commit_chunk_and_recover_block_state( - mut self, - n_committed_txs: usize, - visited_pcs: HashMap>, - ) -> U { + pub fn commit_chunk_and_recover_block_state(mut self, n_committed_txs: usize) -> U { if n_committed_txs == 0 { return self.into_initial_state(); } @@ -212,7 +207,7 @@ impl VersionedState { let class_hash_to_class = self.compiled_contract_classes.get_writes_up_to_index(commit_index); let mut state = self.into_initial_state(); - state.apply_writes(&writes, &class_hash_to_class, &visited_pcs); + state.apply_writes(&writes, &class_hash_to_class); state } } @@ -271,14 +266,8 @@ impl VersionedStateProxy { } } -// TODO(Noa, 15/5/24): Consider using visited_pcs. impl UpdatableState for VersionedStateProxy { - fn apply_writes( - &mut self, - writes: &StateMaps, - class_hash_to_class: &ContractClassMapping, - _visited_pcs: &HashMap>, - ) { + fn apply_writes(&mut self, writes: &StateMaps, class_hash_to_class: &ContractClassMapping) { self.state().apply_writes(self.tx_index, writes, class_hash_to_class) } } @@ -336,14 +325,11 @@ impl StateReader for VersionedStateProxy { } } - fn get_compiled_contract_class( - &self, - class_hash: ClassHash, - ) -> StateResult { + fn get_compiled_class(&self, class_hash: ClassHash) -> StateResult { let mut state = self.state(); match state.compiled_contract_classes.read(self.tx_index, class_hash) { Some(value) => Ok(value), - None => match state.initial_state.get_compiled_contract_class(class_hash) { + None => match state.initial_state.get_compiled_class(class_hash) { Ok(initial_value) => { state.declared_contracts.set_initial_value(class_hash, true); state diff --git a/crates/blockifier/src/concurrency/versioned_state_test.rs b/crates/blockifier/src/concurrency/versioned_state_test.rs index 991723acfba..6f48b04ad07 100644 --- a/crates/blockifier/src/concurrency/versioned_state_test.rs +++ b/crates/blockifier/src/concurrency/versioned_state_test.rs @@ -3,11 +3,14 @@ use std::sync::{Arc, Mutex}; use std::thread; use assert_matches::assert_matches; +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; +use blockifier_test_utils::contracts::FeatureContract; use rstest::{fixture, rstest}; use starknet_api::abi::abi_utils::{get_fee_token_var_address, get_storage_var_address}; -use starknet_api::core::{calculate_contract_address, ClassHash, ContractAddress}; -use starknet_api::test_utils::NonceManager; -use starknet_api::transaction::fields::{ContractAddressSalt, ValidResourceBounds}; +use starknet_api::core::{ClassHash, ContractAddress}; +use starknet_api::test_utils::deploy_account::executable_deploy_account_tx; +use starknet_api::test_utils::DEFAULT_STRK_L1_GAS_PRICE; +use starknet_api::transaction::fields::ValidResourceBounds; use starknet_api::{ calldata, class_hash, @@ -39,11 +42,11 @@ use crate::state::cached_state::{ }; use crate::state::errors::StateError; use crate::state::state_api::{State, StateReader, UpdatableState}; -use crate::test_utils::contracts::FeatureContract; -use crate::test_utils::deploy_account::deploy_account_tx; +use crate::test_utils::contracts::FeatureContractTrait; use crate::test_utils::dict_state_reader::DictStateReader; use crate::test_utils::initial_test_state::test_state; -use crate::test_utils::{CairoVersion, BALANCE, DEFAULT_STRK_L1_GAS_PRICE}; +use crate::test_utils::BALANCE; +use crate::transaction::account_transaction::AccountTransaction; use crate::transaction::objects::HasRelatedFeeType; use crate::transaction::test_utils::{default_all_resource_bounds, l1_resource_bounds}; use crate::transaction::transactions::ExecutableTransaction; @@ -97,12 +100,9 @@ fn test_versioned_state_proxy() { versioned_state_proxys[5].get_compiled_class_hash(class_hash).unwrap(), compiled_class_hash ); - assert_eq!( - versioned_state_proxys[7].get_compiled_contract_class(class_hash).unwrap(), - contract_class - ); + assert_eq!(versioned_state_proxys[7].get_compiled_class(class_hash).unwrap(), contract_class); assert_matches!( - versioned_state_proxys[7].get_compiled_contract_class(another_class_hash).unwrap_err(), + versioned_state_proxys[7].get_compiled_class(another_class_hash).unwrap_err(), StateError::UndeclaredClassHash(class_hash) if another_class_hash == class_hash ); @@ -118,7 +118,8 @@ fn test_versioned_state_proxy() { let class_hash_v10 = class_hash!(29_u8); let compiled_class_hash_v18 = compiled_class_hash!(30_u8); let contract_class_v11 = - FeatureContract::TestContract(CairoVersion::Cairo1).get_runnable_class(); + FeatureContract::TestContract(CairoVersion::Cairo1(RunnableCairo1::Casm)) + .get_runnable_class(); versioned_state_proxys[3].state().apply_writes( 3, @@ -197,7 +198,7 @@ fn test_versioned_state_proxy() { compiled_class_hash_v18 ); assert_eq!( - versioned_state_proxys[15].get_compiled_contract_class(class_hash).unwrap(), + versioned_state_proxys[15].get_compiled_class(class_hash).unwrap(), contract_class_v11 ); } @@ -207,7 +208,6 @@ fn test_versioned_state_proxy() { fn test_run_parallel_txs(default_all_resource_bounds: ValidResourceBounds) { let block_context = BlockContext::create_for_account_testing(); let chain_info = &block_context.chain_info; - let zero_bounds = true; // Test Accounts let grindy_account = FeatureContract::AccountWithLongValidate(CairoVersion::Cairo0); @@ -228,34 +228,31 @@ fn test_run_parallel_txs(default_all_resource_bounds: ValidResourceBounds) { let mut state_2 = TransactionalState::create_transactional(&mut versioned_state_proxy_2); // Prepare transactions - let deploy_account_tx_1 = deploy_account_tx( - deploy_account_tx_args! { - class_hash: account_without_validation.get_class_hash(), - resource_bounds: l1_resource_bounds( - u8::from(!zero_bounds).into(), - DEFAULT_STRK_L1_GAS_PRICE.into() - ), - }, - &mut NonceManager::default(), - ); + let max_amount = 0_u8.into(); + let max_price_per_unit = DEFAULT_STRK_L1_GAS_PRICE.into(); + let tx = executable_deploy_account_tx(deploy_account_tx_args! { + class_hash: account_without_validation.get_class_hash(), + resource_bounds: l1_resource_bounds(max_amount, max_price_per_unit), + }); + let deploy_account_tx_1 = AccountTransaction::new_for_sequencing(tx); let enforce_fee = deploy_account_tx_1.enforce_fee(); - let class_hash = grindy_account.get_class_hash(); let ctor_storage_arg = felt!(1_u8); let ctor_grind_arg = felt!(0_u8); // Do not grind in deploy phase. let constructor_calldata = calldata![ctor_grind_arg, ctor_storage_arg]; let deploy_tx_args = deploy_account_tx_args! { - class_hash, + class_hash: grindy_account.get_class_hash(), resource_bounds: default_all_resource_bounds, - constructor_calldata: constructor_calldata.clone(), + constructor_calldata: constructor_calldata, }; - let nonce_manager = &mut NonceManager::default(); - let delpoy_account_tx_2 = deploy_account_tx(deploy_tx_args, nonce_manager); - let account_address = delpoy_account_tx_2.sender_address(); - let tx_context = block_context.to_tx_context(&delpoy_account_tx_2); + let tx = executable_deploy_account_tx(deploy_tx_args); + let deploy_account_tx_2 = AccountTransaction::new_for_sequencing(tx); + + let deployed_contract_address = deploy_account_tx_2.sender_address(); + let tx_context = block_context.to_tx_context(&deploy_account_tx_2); let fee_type = tx_context.tx_info.fee_type(); - let deployed_account_balance_key = get_fee_token_var_address(account_address); + let deployed_account_balance_key = get_fee_token_var_address(deployed_contract_address); let fee_token_address = chain_info.fee_token_address(&fee_type); state_2 .set_storage_at(fee_token_address, deployed_account_balance_key, felt!(BALANCE.0)) @@ -267,21 +264,16 @@ fn test_run_parallel_txs(default_all_resource_bounds: ValidResourceBounds) { // Execute transactions thread::scope(|s| { s.spawn(move || { - let result = - deploy_account_tx_1.execute(&mut state_1, &block_context_1, enforce_fee, true); - assert_eq!(result.is_err(), enforce_fee); // Transaction fails iff we enforced the fee charge (as the acount is not funded). + let result = deploy_account_tx_1.execute(&mut state_1, &block_context_1); + // TODO(Arni): Check that the storage updated as expected. + // Transaction fails iff we enforced the fee charge (as the account is not funded). + assert!(!enforce_fee, "Expected fee enforcement to be disabled for this transaction."); + assert!(result.is_ok()); }); s.spawn(move || { - delpoy_account_tx_2.execute(&mut state_2, &block_context_2, true, true).unwrap(); + deploy_account_tx_2.execute(&mut state_2, &block_context_2).unwrap(); // Check that the constructor wrote ctor_arg to the storage. let storage_key = get_storage_var_address("ctor_arg", &[]); - let deployed_contract_address = calculate_contract_address( - ContractAddressSalt::default(), - class_hash, - &constructor_calldata, - ContractAddress::default(), - ) - .unwrap(); let read_storage_arg = state_2.get_storage_at(deployed_contract_address, storage_key).unwrap(); assert_eq!(ctor_storage_arg, read_storage_arg); @@ -321,7 +313,7 @@ fn test_validate_reads( assert!(transactional_state.cache.borrow().initial_reads.declared_contracts.is_empty()); assert_matches!( - transactional_state.get_compiled_contract_class(class_hash), + transactional_state.get_compiled_class(class_hash), Err(StateError::UndeclaredClassHash(err_class_hash)) if err_class_hash == class_hash ); @@ -404,7 +396,8 @@ fn test_false_validate_reads_declared_contracts( }; let version_state_proxy = safe_versioned_state.pin_version(0); let compiled_contract_calss = - FeatureContract::TestContract(CairoVersion::Cairo1).get_runnable_class(); + FeatureContract::TestContract(CairoVersion::Cairo1(RunnableCairo1::Casm)) + .get_runnable_class(); let class_hash_to_class = HashMap::from([(class_hash!(1_u8), compiled_contract_calss)]); version_state_proxy.state().apply_writes(0, &tx_0_writes, &class_hash_to_class); assert!(!safe_versioned_state.pin_version(1).validate_reads(&tx_1_reads)); @@ -429,7 +422,9 @@ fn test_apply_writes( assert_eq!(transactional_states[0].cache.borrow().writes.class_hashes.len(), 1); // Transaction 0 contract class. - let contract_class_0 = FeatureContract::TestContract(CairoVersion::Cairo1).get_runnable_class(); + let contract_class_0 = + FeatureContract::TestContract(CairoVersion::Cairo1(RunnableCairo1::Casm)) + .get_runnable_class(); assert!(transactional_states[0].class_hash_to_class.borrow().is_empty()); transactional_states[0].set_contract_class(class_hash, contract_class_0.clone()).unwrap(); assert_eq!(transactional_states[0].class_hash_to_class.borrow().len(), 1); @@ -437,13 +432,9 @@ fn test_apply_writes( safe_versioned_state.pin_version(0).apply_writes( &transactional_states[0].cache.borrow().writes, &transactional_states[0].class_hash_to_class.borrow().clone(), - &HashMap::default(), ); assert!(transactional_states[1].get_class_hash_at(contract_address).unwrap() == class_hash_0); - assert!( - transactional_states[1].get_compiled_contract_class(class_hash).unwrap() - == contract_class_0 - ); + assert!(transactional_states[1].get_compiled_class(class_hash).unwrap() == contract_class_0); } #[rstest] @@ -469,13 +460,12 @@ fn test_apply_writes_reexecute_scenario( safe_versioned_state.pin_version(0).apply_writes( &transactional_states[0].cache.borrow().writes, &transactional_states[0].class_hash_to_class.borrow().clone(), - &HashMap::default(), ); // Although transaction 0 wrote to the shared state, version 1 needs to be re-executed to see // the new value (its read value has already been cached). assert!(transactional_states[1].get_class_hash_at(contract_address).unwrap() == class_hash); - // TODO: Use re-execution native util once it's ready. + // TODO(Noa): Use re-execution native util once it's ready. // "Re-execute" the transaction. let mut versioned_state_proxy = safe_versioned_state.pin_version(1); transactional_states[1] = TransactionalState::create_transactional(&mut versioned_state_proxy); @@ -501,7 +491,8 @@ fn test_delete_writes( (contract_address!("0x100"), class_hash!(20_u8)), (contract_address!("0x200"), class_hash!(21_u8)), ]; - let feature_contract = FeatureContract::TestContract(CairoVersion::Cairo1); + let feature_contract = + FeatureContract::TestContract(CairoVersion::Cairo1(RunnableCairo1::Casm)); for (i, tx_state) in transactional_states.iter_mut().enumerate() { // Modify the `cache` member of the CachedState. for (contract_address, class_hash) in contract_addresses.iter() { @@ -514,11 +505,9 @@ fn test_delete_writes( feature_contract.get_runnable_class(), ) .unwrap(); - safe_versioned_state.pin_version(i).apply_writes( - &tx_state.cache.borrow().writes, - &tx_state.class_hash_to_class.borrow(), - &HashMap::default(), - ); + safe_versioned_state + .pin_version(i) + .apply_writes(&tx_state.cache.borrow().writes, &tx_state.class_hash_to_class.borrow()); } safe_versioned_state.pin_version(tx_index_to_delete_writes).delete_writes( @@ -556,7 +545,8 @@ fn test_delete_writes( fn test_delete_writes_completeness( safe_versioned_state: ThreadSafeVersionedState>, ) { - let feature_contract = FeatureContract::TestContract(CairoVersion::Cairo1); + let feature_contract = + FeatureContract::TestContract(CairoVersion::Cairo1(RunnableCairo1::Casm)); let state_maps_writes = StateMaps { nonces: HashMap::from([(contract_address!("0x1"), nonce!(1_u8))]), class_hashes: HashMap::from([( @@ -576,11 +566,7 @@ fn test_delete_writes_completeness( let tx_index = 0; let mut versioned_state_proxy = safe_versioned_state.pin_version(tx_index); - versioned_state_proxy.apply_writes( - &state_maps_writes, - &class_hash_to_class_writes, - &HashMap::default(), - ); + versioned_state_proxy.apply_writes(&state_maps_writes, &class_hash_to_class_writes); assert_eq!( safe_versioned_state.0.lock().unwrap().get_writes_of_index(tx_index), state_maps_writes @@ -636,7 +622,8 @@ fn test_versioned_proxy_state_flow( // Clients contract class values. let contract_class_0 = FeatureContract::TestContract(CairoVersion::Cairo0).get_runnable_class(); let contract_class_2 = - FeatureContract::AccountWithLongValidate(CairoVersion::Cairo1).get_runnable_class(); + FeatureContract::AccountWithLongValidate(CairoVersion::Cairo1(RunnableCairo1::Casm)) + .get_runnable_class(); transactional_states[0].set_contract_class(class_hash, contract_class_0).unwrap(); transactional_states[2].set_contract_class(class_hash, contract_class_2.clone()).unwrap(); @@ -654,12 +641,9 @@ fn test_versioned_proxy_state_flow( for proxy in versioned_proxy_states { drop(proxy); } - let modified_block_state = safe_versioned_state - .into_inner_state() - .commit_chunk_and_recover_block_state(4, HashMap::new()); + let modified_block_state = + safe_versioned_state.into_inner_state().commit_chunk_and_recover_block_state(4); assert!(modified_block_state.get_class_hash_at(contract_address).unwrap() == class_hash_3); - assert!( - modified_block_state.get_compiled_contract_class(class_hash).unwrap() == contract_class_2 - ); + assert!(modified_block_state.get_compiled_class(class_hash).unwrap() == contract_class_2); } diff --git a/crates/blockifier/src/concurrency/versioned_storage.rs b/crates/blockifier/src/concurrency/versioned_storage.rs index c55735c5664..7d4db9a1866 100644 --- a/crates/blockifier/src/concurrency/versioned_storage.rs +++ b/crates/blockifier/src/concurrency/versioned_storage.rs @@ -40,7 +40,7 @@ where V: Clone + Debug, { pub fn read(&self, tx_index: TxIndex, key: K) -> Option { - // TODO: Ignore `ESTIMATE` values (when added). + // TODO(Noa): Ignore `ESTIMATE` values (when added). let value = self.writes.get(&key).and_then(|cell| cell.range(..=tx_index).next_back()); value.map(|(_, value)| value).or_else(|| self.cached_initial_values.get(&key)).cloned() } diff --git a/crates/blockifier/src/concurrency/worker_logic.rs b/crates/blockifier/src/concurrency/worker_logic.rs index b66de3b3de2..a463a17e27f 100644 --- a/crates/blockifier/src/concurrency/worker_logic.rs +++ b/crates/blockifier/src/concurrency/worker_logic.rs @@ -1,11 +1,9 @@ -use std::collections::{HashMap, HashSet}; +use std::collections::HashMap; use std::fmt::Debug; use std::sync::Mutex; use std::thread; use std::time::Duration; -use starknet_api::core::ClassHash; - use super::versioned_state::VersionedState; use crate::blockifier::transaction_executor::TransactionExecutorError; use crate::bouncer::Bouncer; @@ -17,13 +15,9 @@ use crate::concurrency::TxIndex; use crate::context::BlockContext; use crate::state::cached_state::{ContractClassMapping, StateMaps, TransactionalState}; use crate::state::state_api::{StateReader, UpdatableState}; -use crate::transaction::objects::{ - TransactionExecutionInfo, - TransactionExecutionResult, - TransactionInfoCreator, -}; +use crate::transaction::objects::{TransactionExecutionInfo, TransactionExecutionResult}; use crate::transaction::transaction_execution::Transaction; -use crate::transaction::transactions::{ExecutableTransaction, ExecutionFlags}; +use crate::transaction::transactions::ExecutableTransaction; #[cfg(test)] #[path = "worker_logic_test.rs"] @@ -34,10 +28,8 @@ const EXECUTION_OUTPUTS_UNWRAP_ERROR: &str = "Execution task outputs should not #[derive(Debug)] pub struct ExecutionTaskOutput { pub reads: StateMaps, - // TODO(Yoni): rename to state_diff. - pub writes: StateMaps, + pub state_diff: StateMaps, pub contract_classes: ContractClassMapping, - pub visited_pcs: HashMap>, pub result: TransactionExecutionResult, } @@ -127,37 +119,32 @@ impl<'a, S: StateReader> WorkerExecutor<'a, S> { fn execute_tx(&self, tx_index: TxIndex) { let mut tx_versioned_state = self.state.pin_version(tx_index); let tx = &self.chunk[tx_index]; - let tx_charge_fee = tx.create_tx_info().enforce_fee(); + // TODO(Yoni): is it necessary to use a transactional state here? let mut transactional_state = TransactionalState::create_transactional(&mut tx_versioned_state); - let execution_flags = - ExecutionFlags { charge_fee: tx_charge_fee, validate: true, concurrency_mode: true }; + let concurrency_mode = true; let execution_result = - tx.execute_raw(&mut transactional_state, self.block_context, execution_flags); + tx.execute_raw(&mut transactional_state, self.block_context, concurrency_mode); // Update the versioned state and store the transaction execution output. let execution_output_inner = match execution_result { Ok(_) => { let tx_reads_writes = transactional_state.cache.take(); - let writes = tx_reads_writes.to_state_diff().state_maps; + let state_diff = tx_reads_writes.to_state_diff().state_maps; let contract_classes = transactional_state.class_hash_to_class.take(); - let visited_pcs = transactional_state.visited_pcs; - // The versioned state does not carry the visited PCs. - tx_versioned_state.apply_writes(&writes, &contract_classes, &HashMap::default()); + tx_versioned_state.apply_writes(&state_diff, &contract_classes); ExecutionTaskOutput { reads: tx_reads_writes.initial_reads, - writes, + state_diff, contract_classes, - visited_pcs, result: execution_result, } } Err(_) => ExecutionTaskOutput { reads: transactional_state.cache.take().initial_reads, - // Failed transaction - ignore the writes and visited PCs. - writes: StateMaps::default(), + // Failed transaction - ignore the writes. + state_diff: StateMaps::default(), contract_classes: HashMap::default(), - visited_pcs: HashMap::default(), result: execution_result, }, }; @@ -175,7 +162,7 @@ impl<'a, S: StateReader> WorkerExecutor<'a, S> { let aborted = !reads_valid && self.scheduler.try_validation_abort(tx_index); if aborted { tx_versioned_state - .delete_writes(&execution_output.writes, &execution_output.contract_classes); + .delete_writes(&execution_output.state_diff, &execution_output.contract_classes); self.scheduler.finish_abort(tx_index) } else { Task::AskForTask @@ -206,7 +193,7 @@ impl<'a, S: StateReader> WorkerExecutor<'a, S> { if !reads_valid { // Revalidate failed: re-execute the transaction. tx_versioned_state.delete_writes( - &execution_output_ref.writes, + &execution_output_ref.state_diff, &execution_output_ref.contract_classes, ); // Release the execution output lock as it is acquired in execution (avoid dead-lock). @@ -226,13 +213,10 @@ impl<'a, S: StateReader> WorkerExecutor<'a, S> { // Execution is final. let mut execution_output = lock_mutex_in_array(&self.execution_outputs, tx_index); - let writes = &execution_output.as_ref().expect(EXECUTION_OUTPUTS_UNWRAP_ERROR).writes; - // TODO(Yoni): get rid of this clone. - let mut tx_state_changes_keys = writes.clone().into_keys(); - let tx_result = - &mut execution_output.as_mut().expect(EXECUTION_OUTPUTS_UNWRAP_ERROR).result; + let execution_output = execution_output.as_mut().expect(EXECUTION_OUTPUTS_UNWRAP_ERROR); + let mut tx_state_changes_keys = execution_output.state_diff.keys(); - if let Ok(tx_execution_info) = tx_result.as_mut() { + if let Ok(tx_execution_info) = execution_output.result.as_mut() { let tx_context = self.block_context.to_tx_context(&self.chunk[tx_index]); // Add the deleted sequencer balance key to the storage keys. let concurrency_mode = true; @@ -247,6 +231,7 @@ impl<'a, S: StateReader> WorkerExecutor<'a, S> { &tx_state_changes_keys, &tx_execution_info.summarize(&self.block_context.versioned_constants), &tx_execution_info.receipt.resources, + &self.block_context.versioned_constants, ); if let Err(error) = bouncer_result { match error { @@ -257,7 +242,13 @@ impl<'a, S: StateReader> WorkerExecutor<'a, S> { } } } - complete_fee_transfer_flow(&tx_context, tx_execution_info, &mut tx_versioned_state); + complete_fee_transfer_flow( + &tx_context, + tx_execution_info, + &mut execution_output.state_diff, + &mut tx_versioned_state, + &self.chunk[tx_index], + ); // Optimization: changing the sequencer balance storage cell does not trigger // (re-)validation of the next transactions. } @@ -266,14 +257,8 @@ impl<'a, S: StateReader> WorkerExecutor<'a, S> { } } -impl<'a, U: UpdatableState> WorkerExecutor<'a, U> { - pub fn commit_chunk_and_recover_block_state( - self, - n_committed_txs: usize, - visited_pcs: HashMap>, - ) -> U { - self.state - .into_inner_state() - .commit_chunk_and_recover_block_state(n_committed_txs, visited_pcs) +impl WorkerExecutor<'_, U> { + pub fn commit_chunk_and_recover_block_state(self, n_committed_txs: usize) -> U { + self.state.into_inner_state().commit_chunk_and_recover_block_state(n_committed_txs) } } diff --git a/crates/blockifier/src/concurrency/worker_logic_test.rs b/crates/blockifier/src/concurrency/worker_logic_test.rs index 057d4bafab5..3f47f834f4b 100644 --- a/crates/blockifier/src/concurrency/worker_logic_test.rs +++ b/crates/blockifier/src/concurrency/worker_logic_test.rs @@ -1,10 +1,14 @@ use std::collections::HashMap; use std::sync::Mutex; +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; +use blockifier_test_utils::calldata::{create_calldata, create_trivial_calldata}; +use blockifier_test_utils::contracts::FeatureContract; use rstest::rstest; use starknet_api::abi::abi_utils::get_fee_token_var_address; use starknet_api::core::{ContractAddress, Nonce}; -use starknet_api::test_utils::NonceManager; +use starknet_api::test_utils::declare::executable_declare_tx; +use starknet_api::test_utils::{NonceManager, TEST_ERC20_CONTRACT_ADDRESS2}; use starknet_api::transaction::constants::DEPLOY_CONTRACT_FUNCTION_ENTRY_POINT_NAME; use starknet_api::transaction::fields::{ContractAddressSalt, Fee, ValidResourceBounds}; use starknet_api::transaction::TransactionVersion; @@ -22,23 +26,16 @@ use crate::context::{BlockContext, TransactionContext}; use crate::fee::fee_utils::get_sequencer_balance_keys; use crate::state::cached_state::StateMaps; use crate::state::state_api::StateReader; -use crate::test_utils::contracts::FeatureContract; -use crate::test_utils::declare::declare_tx; +use crate::test_utils::contracts::FeatureContractTrait; use crate::test_utils::initial_test_state::test_state; -use crate::test_utils::{ - create_calldata, - create_trivial_calldata, - CairoVersion, - BALANCE, - TEST_ERC20_CONTRACT_ADDRESS2, -}; +use crate::test_utils::BALANCE; use crate::transaction::account_transaction::AccountTransaction; use crate::transaction::objects::HasRelatedFeeType; use crate::transaction::test_utils::{ - account_invoke_tx, calculate_class_info_for_testing, default_all_resource_bounds, emit_n_events_tx, + invoke_tx_with_default_flags, max_fee, }; use crate::transaction::transaction_execution::Transaction; @@ -48,7 +45,7 @@ fn trivial_calldata_invoke_tx( test_contract_address: ContractAddress, nonce: Nonce, ) -> AccountTransaction { - account_invoke_tx(invoke_tx_args! { + invoke_tx_with_default_flags(invoke_tx_args! { sender_address: account_address, calldata: create_trivial_calldata(test_contract_address), resource_bounds: default_all_resource_bounds(), @@ -80,7 +77,8 @@ fn verify_sequencer_balance_update( #[rstest] pub fn test_commit_tx() { let block_context = BlockContext::create_for_account_testing(); - let account = FeatureContract::AccountWithoutValidations(CairoVersion::Cairo1); + let account = + FeatureContract::AccountWithoutValidations(CairoVersion::Cairo1(RunnableCairo1::Casm)); let test_contract = FeatureContract::TestContract(CairoVersion::Cairo0); let mut expected_sequencer_balance_low = 0_u128; let mut nonce_manager = NonceManager::default(); @@ -164,6 +162,7 @@ pub fn test_commit_tx() { .fee_transfer_call_info .as_ref() .unwrap() + .storage_access_tracker .storage_read_values[read_storage_index]; assert_eq!(felt!(expected_sequencer_storage_read), actual_sequencer_storage_read,); } @@ -186,7 +185,8 @@ pub fn test_commit_tx() { // commit tx should be the same (except for re-execution changes). fn test_commit_tx_when_sender_is_sequencer() { let mut block_context = BlockContext::create_for_account_testing(); - let account = FeatureContract::AccountWithoutValidations(CairoVersion::Cairo1); + let account = + FeatureContract::AccountWithoutValidations(CairoVersion::Cairo1(RunnableCairo1::Casm)); let test_contract = FeatureContract::TestContract(CairoVersion::Cairo0); let account_address = account.get_instance_address(0_u16); let test_contract_address = test_contract.get_instance_address(0_u16); @@ -219,7 +219,8 @@ fn test_commit_tx_when_sender_is_sequencer() { let execution_result = &execution_task_outputs.as_ref().unwrap().result; let fee_transfer_call_info = execution_result.as_ref().unwrap().fee_transfer_call_info.as_ref().unwrap(); - let read_values_before_commit = fee_transfer_call_info.storage_read_values.clone(); + let read_values_before_commit = + fee_transfer_call_info.storage_access_tracker.storage_read_values.clone(); drop(execution_task_outputs); let tx_context = &executor.block_context.to_tx_context(&sequencer_tx[0]); @@ -237,7 +238,10 @@ fn test_commit_tx_when_sender_is_sequencer() { let fee_transfer_call_info = commit_result.as_ref().unwrap().fee_transfer_call_info.as_ref().unwrap(); // Check that the result call info is the same as before the commit. - assert_eq!(read_values_before_commit, fee_transfer_call_info.storage_read_values); + assert_eq!( + read_values_before_commit, + fee_transfer_call_info.storage_access_tracker.storage_read_values + ); let sequencer_balance_low_after = tx_versioned_state.get_storage_at(fee_token_address, sequencer_balance_key_low).unwrap(); @@ -253,7 +257,8 @@ fn test_commit_tx_when_sender_is_sequencer() { fn test_worker_execute(default_all_resource_bounds: ValidResourceBounds) { // Settings. let block_context = BlockContext::create_for_account_testing(); - let account_contract = FeatureContract::AccountWithoutValidations(CairoVersion::Cairo1); + let account_contract = + FeatureContract::AccountWithoutValidations(CairoVersion::Cairo1(RunnableCairo1::Casm)); let test_contract = FeatureContract::TestContract(CairoVersion::Cairo0); let chain_info = &block_context.chain_info; @@ -268,7 +273,7 @@ fn test_worker_execute(default_all_resource_bounds: ValidResourceBounds) { let storage_value = felt!(93_u8); let storage_key = storage_key!(1993_u16); - let tx_success = account_invoke_tx(invoke_tx_args! { + let tx_success = invoke_tx_with_default_flags(invoke_tx_args! { sender_address: account_address, calldata: create_calldata( test_contract_address, @@ -281,7 +286,7 @@ fn test_worker_execute(default_all_resource_bounds: ValidResourceBounds) { // Create a transaction with invalid nonce. nonce_manager.rollback(account_address); - let tx_failure = account_invoke_tx(invoke_tx_args! { + let tx_failure = invoke_tx_with_default_flags(invoke_tx_args! { sender_address: account_address, calldata: create_calldata( test_contract_address, @@ -293,7 +298,7 @@ fn test_worker_execute(default_all_resource_bounds: ValidResourceBounds) { }); - let tx_revert = account_invoke_tx(invoke_tx_args! { + let tx_revert = invoke_tx_with_default_flags(invoke_tx_args! { sender_address: account_address, calldata: create_calldata( test_contract_address, @@ -380,9 +385,8 @@ fn test_worker_execute(default_all_resource_bounds: ValidResourceBounds) { ..Default::default() }; - assert_eq!(execution_output.writes, writes.diff(&reads)); + assert_eq!(execution_output.state_diff, writes.diff(&reads)); assert_eq!(execution_output.reads, reads); - assert_ne!(execution_output.visited_pcs, HashMap::default()); // Failed execution. let tx_index = 1; @@ -400,8 +404,7 @@ fn test_worker_execute(default_all_resource_bounds: ValidResourceBounds) { ..Default::default() }; assert_eq!(execution_output.reads, reads); - assert_eq!(execution_output.writes, StateMaps::default()); - assert_eq!(execution_output.visited_pcs, HashMap::default()); + assert_eq!(execution_output.state_diff, StateMaps::default()); // Reverted execution. let tx_index = 2; @@ -414,8 +417,7 @@ fn test_worker_execute(default_all_resource_bounds: ValidResourceBounds) { let execution_output = worker_executor.execution_outputs[tx_index].lock().unwrap(); let execution_output = execution_output.as_ref().unwrap(); assert!(execution_output.result.as_ref().unwrap().is_reverted()); - assert_ne!(execution_output.writes, StateMaps::default()); - assert_ne!(execution_output.visited_pcs, HashMap::default()); + assert_ne!(execution_output.state_diff, StateMaps::default()); // Validate status change. for tx_index in 0..3 { @@ -427,7 +429,8 @@ fn test_worker_execute(default_all_resource_bounds: ValidResourceBounds) { fn test_worker_validate(default_all_resource_bounds: ValidResourceBounds) { // Settings. let block_context = BlockContext::create_for_account_testing(); - let account_contract = FeatureContract::AccountWithoutValidations(CairoVersion::Cairo1); + let account_contract = + FeatureContract::AccountWithoutValidations(CairoVersion::Cairo1(RunnableCairo1::Casm)); let test_contract = FeatureContract::TestContract(CairoVersion::Cairo0); let chain_info = &block_context.chain_info; @@ -444,7 +447,7 @@ fn test_worker_validate(default_all_resource_bounds: ValidResourceBounds) { let storage_key = storage_key!(1993_u16); // Both transactions change the same storage key. - let account_tx0 = account_invoke_tx(invoke_tx_args! { + let account_tx0 = invoke_tx_with_default_flags(invoke_tx_args! { sender_address: account_address, calldata: create_calldata( test_contract_address, @@ -455,7 +458,7 @@ fn test_worker_validate(default_all_resource_bounds: ValidResourceBounds) { nonce: nonce_manager.next(account_address) }); - let account_tx1 = account_invoke_tx(invoke_tx_args! { + let account_tx1 = invoke_tx_with_default_flags(invoke_tx_args! { sender_address: account_address, calldata: create_calldata( test_contract_address, @@ -528,7 +531,7 @@ fn test_worker_validate(default_all_resource_bounds: ValidResourceBounds) { #[rstest] #[case::declare_cairo0(CairoVersion::Cairo0, TransactionVersion::ONE)] -#[case::declare_cairo1(CairoVersion::Cairo1, TransactionVersion::THREE)] +#[case::declare_cairo1(CairoVersion::Cairo1(RunnableCairo1::Casm), TransactionVersion::THREE)] fn test_deploy_before_declare( max_fee: Fee, default_all_resource_bounds: ValidResourceBounds, @@ -538,7 +541,8 @@ fn test_deploy_before_declare( // Create the state. let block_context = BlockContext::create_for_account_testing(); let chain_info = &block_context.chain_info; - let account_contract = FeatureContract::AccountWithoutValidations(CairoVersion::Cairo1); + let account_contract = + FeatureContract::AccountWithoutValidations(CairoVersion::Cairo1(RunnableCairo1::Casm)); let state = test_state(chain_info, BALANCE, &[(account_contract, 2)]); let safe_versioned_state = safe_versioned_state_for_testing(state); @@ -549,7 +553,7 @@ fn test_deploy_before_declare( let test_class_hash = test_contract.get_class_hash(); let test_class_info = calculate_class_info_for_testing(test_contract.get_class()); let test_compiled_class_hash = test_contract.get_compiled_class_hash(); - let declare_tx = declare_tx( + let declare_tx = AccountTransaction::new_with_default_flags(executable_declare_tx( declare_tx_args! { sender_address: account_address_0, resource_bounds: default_all_resource_bounds, @@ -560,10 +564,10 @@ fn test_deploy_before_declare( nonce: nonce!(0_u8), }, test_class_info.clone(), - ); + )); // Deploy test contract. - let invoke_tx = account_invoke_tx(invoke_tx_args! { + let invoke_tx = invoke_tx_with_default_flags(invoke_tx_args! { sender_address: account_address_1, calldata: create_calldata( account_address_0, @@ -624,7 +628,8 @@ fn test_deploy_before_declare( fn test_worker_commit_phase(default_all_resource_bounds: ValidResourceBounds) { // Settings. let block_context = BlockContext::create_for_account_testing(); - let account_contract = FeatureContract::AccountWithoutValidations(CairoVersion::Cairo1); + let account_contract = + FeatureContract::AccountWithoutValidations(CairoVersion::Cairo1(RunnableCairo1::Casm)); let test_contract = FeatureContract::TestContract(CairoVersion::Cairo0); let chain_info = &block_context.chain_info; @@ -646,7 +651,7 @@ fn test_worker_commit_phase(default_all_resource_bounds: ValidResourceBounds) { let txs = (0..3) .map(|_| { - Transaction::Account(account_invoke_tx(invoke_tx_args! { + Transaction::Account(invoke_tx_with_default_flags(invoke_tx_args! { sender_address, calldata: calldata.clone(), resource_bounds: default_all_resource_bounds, @@ -717,7 +722,8 @@ fn test_worker_commit_phase_with_halt() { let max_n_events_in_block = 3; let block_context = BlockContext::create_for_bouncer_testing(max_n_events_in_block); - let account_contract = FeatureContract::AccountWithoutValidations(CairoVersion::Cairo1); + let account_contract = + FeatureContract::AccountWithoutValidations(CairoVersion::Cairo1(RunnableCairo1::Casm)); let test_contract = FeatureContract::TestContract(CairoVersion::Cairo0); let chain_info = &block_context.chain_info; diff --git a/crates/blockifier/src/context.rs b/crates/blockifier/src/context.rs index e77c5e03820..9ede5950771 100644 --- a/crates/blockifier/src/context.rs +++ b/crates/blockifier/src/context.rs @@ -1,30 +1,32 @@ use std::collections::BTreeMap; +use std::sync::Arc; use papyrus_config::dumping::{append_sub_config_name, ser_param, SerializeConfig}; use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; use serde::{Deserialize, Serialize}; -use starknet_api::block::GasPriceVector; +use starknet_api::block::{BlockInfo, BlockNumber, BlockTimestamp, FeeType, GasPriceVector}; use starknet_api::core::{ChainId, ContractAddress}; +use starknet_api::execution_resources::GasAmount; use starknet_api::transaction::fields::{ AllResourceBounds, GasVectorComputationMode, ValidResourceBounds, }; -use crate::blockifier::block::BlockInfo; +use crate::blockifier_versioned_constants::VersionedConstants; use crate::bouncer::BouncerConfig; +use crate::execution::call_info::CallInfo; +use crate::execution::common_hints::ExecutionMode; use crate::transaction::objects::{ CurrentTransactionInfo, - FeeType, HasRelatedFeeType, TransactionInfo, TransactionInfoCreator, }; -use crate::versioned_constants::VersionedConstants; #[derive(Clone, Debug)] pub struct TransactionContext { - pub block_context: BlockContext, + pub block_context: Arc, pub tx_info: TransactionInfo, } @@ -39,30 +41,57 @@ impl TransactionContext { self.tx_info.gas_mode() } pub fn get_gas_prices(&self) -> &GasPriceVector { - self.block_context - .block_info - .gas_prices - .get_gas_prices_by_fee_type(&self.tx_info.fee_type()) + self.block_context.block_info.gas_prices.gas_price_vector(&self.tx_info.fee_type()) + } + pub fn sierra_gas_limit(&self, mode: &ExecutionMode) -> GasAmount { + self.block_context.versioned_constants.sierra_gas_limit(mode) } /// Returns the initial Sierra gas of the transaction. /// This value is used to limit the transaction's run. - // TODO(tzahi): replace returned value from u64 to GasAmount. - pub fn initial_sierra_gas(&self) -> u64 { + pub fn initial_sierra_gas(&self) -> GasAmount { match &self.tx_info { TransactionInfo::Deprecated(_) | TransactionInfo::Current(CurrentTransactionInfo { resource_bounds: ValidResourceBounds::L1Gas(_), .. - }) => self.block_context.versioned_constants.default_initial_gas_cost(), + }) => self.block_context.versioned_constants.initial_gas_no_user_l2_bound(), TransactionInfo::Current(CurrentTransactionInfo { resource_bounds: ValidResourceBounds::AllResources(AllResourceBounds { l2_gas, .. }), .. - }) => l2_gas.max_amount.0, + }) => l2_gas.max_amount, } } } +pub(crate) struct GasCounter { + pub(crate) spent_gas: GasAmount, + pub(crate) remaining_gas: GasAmount, +} + +impl GasCounter { + pub(crate) fn new(initial_gas: GasAmount) -> Self { + GasCounter { spent_gas: GasAmount(0), remaining_gas: initial_gas } + } + + fn spend(&mut self, amount: GasAmount) { + self.spent_gas = self.spent_gas.checked_add(amount).expect("Gas overflow"); + self.remaining_gas = self + .remaining_gas + .checked_sub(amount) + .expect("Overuse of gas; should have been caught earlier"); + } + + /// Limits the amount of gas that can be used (in validate\execute) by the given global limit. + pub(crate) fn limit_usage(&self, amount: GasAmount) -> u64 { + self.remaining_gas.min(amount).0 + } + + pub(crate) fn subtract_used_gas(&mut self, call_info: &CallInfo) { + self.spend(GasAmount(call_info.execution.gas_consumed)); + } +} + #[derive(Clone, Debug)] pub struct BlockContext { // TODO(Yoni, 1/10/2024): consider making these fields public. @@ -99,10 +128,50 @@ impl BlockContext { tx_info_creator: &impl TransactionInfoCreator, ) -> TransactionContext { TransactionContext { - block_context: self.clone(), + block_context: Arc::new(self.clone()), tx_info: tx_info_creator.create_tx_info(), } } + + pub fn block_info_for_validate(&self) -> BlockInfo { + let block_number = self.block_info.block_number.0; + let block_timestamp = self.block_info.block_timestamp.0; + // Round down to the nearest multiple of validate_block_number_rounding. + let validate_block_number_rounding = + self.versioned_constants.get_validate_block_number_rounding(); + let rounded_block_number = + (block_number / validate_block_number_rounding) * validate_block_number_rounding; + // Round down to the nearest multiple of validate_timestamp_rounding. + let validate_timestamp_rounding = + self.versioned_constants.get_validate_timestamp_rounding(); + let rounded_timestamp = + (block_timestamp / validate_timestamp_rounding) * validate_timestamp_rounding; + BlockInfo { + block_number: BlockNumber(rounded_block_number), + block_timestamp: BlockTimestamp(rounded_timestamp), + sequencer_address: 0_u128.into(), + // TODO(Yoni): consider setting here trivial prices if and when this field is exposed. + gas_prices: self.block_info.gas_prices.clone(), + use_kzg_da: self.block_info.use_kzg_da, + } + } + + /// Test util to allow overriding block gas limits. + #[cfg(any(test, feature = "testing"))] + pub fn set_sierra_gas_limits( + &mut self, + execute_max_gas: Option, + validate_max_gas: Option, + ) { + let mut new_os_constants = (*self.versioned_constants.os_constants).clone(); + if let Some(execute_max_gas) = execute_max_gas { + new_os_constants.execute_max_sierra_gas = execute_max_gas; + } + if let Some(validate_max_gas) = validate_max_gas { + new_os_constants.validate_max_sierra_gas = validate_max_gas; + } + self.versioned_constants.os_constants = std::sync::Arc::new(new_os_constants); + } } #[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] @@ -123,6 +192,7 @@ impl ChainInfo { impl Default for ChainInfo { fn default() -> Self { ChainInfo { + // TODO(guyn): should we remove the default value for chain_id? chain_id: ChainId::Other("0x0".to_string()), fee_token_addresses: FeeTokenAddresses::default(), } diff --git a/crates/blockifier/src/execution/call_info.rs b/crates/blockifier/src/execution/call_info.rs index e078376b481..ab35261363d 100644 --- a/crates/blockifier/src/execution/call_info.rs +++ b/crates/blockifier/src/execution/call_info.rs @@ -4,17 +4,19 @@ use std::ops::{Add, AddAssign}; use cairo_vm::vm::runners::cairo_runner::ExecutionResources; use serde::Serialize; +use starknet_api::block::{BlockHash, BlockNumber}; use starknet_api::core::{ClassHash, ContractAddress, EthAddress}; -use starknet_api::execution_resources::GasAmount; +use starknet_api::execution_resources::{GasAmount, GasVector}; use starknet_api::state::StorageKey; +use starknet_api::transaction::fields::GasVectorComputationMode; use starknet_api::transaction::{EventContent, L2ToL1Payload}; use starknet_types_core::felt::Felt; +use crate::blockifier_versioned_constants::VersionedConstants; use crate::execution::contract_class::TrackedResource; use crate::execution::entry_point::CallEntryPoint; use crate::state::cached_state::StorageEntry; use crate::utils::u64_from_usize; -use crate::versioned_constants::VersionedConstants; #[cfg_attr(feature = "transaction_serde", derive(serde::Deserialize))] #[derive(Clone, Debug, Default, Eq, PartialEq, Serialize)] @@ -71,6 +73,25 @@ pub struct EventSummary { pub total_event_data_size: u64, } +impl EventSummary { + pub fn to_gas_vector( + &self, + versioned_constants: &VersionedConstants, + mode: &GasVectorComputationMode, + ) -> GasVector { + let archival_gas_costs = versioned_constants.get_archival_data_gas_costs(mode); + let gas_amount: GasAmount = (archival_gas_costs.gas_per_data_felt + * (archival_gas_costs.event_key_factor * self.total_event_keys + + self.total_event_data_size)) + .to_integer() + .into(); + match mode { + GasVectorComputationMode::All => GasVector::from_l2_gas(gas_amount), + GasVectorComputationMode::NoL2Gas => GasVector::from_l1_gas(gas_amount), + } + } +} + #[derive(Clone, Debug, Default, PartialEq)] pub struct ExecutionSummary { pub charged_resources: ChargedResources, @@ -99,6 +120,44 @@ impl Sum for ExecutionSummary { } } +impl ExecutionSummary { + /// Returns the a gas cost _estimation_ for the execution summary. + /// + /// In particular, this calculation ignores state changes, cost of declared classes, L1 handler + /// payload length, plus Starknet OS overhead. These costs are only accounted for on a + /// transaction level and cannot be computed based on a single execution summary. + #[cfg(feature = "node_api")] + pub fn to_partial_gas_vector( + self, + versioned_constants: &VersionedConstants, + mode: &GasVectorComputationMode, + ) -> GasVector { + use crate::fee::resources::{ComputationResources, MessageResources}; + + let computation_resources = ComputationResources { + vm_resources: self.charged_resources.vm_resources, + n_reverted_steps: 0, + sierra_gas: self.charged_resources.gas_consumed, + reverted_sierra_gas: 0u64.into(), + }; + + [ + computation_resources.to_gas_vector(versioned_constants, mode), + self.event_summary.to_gas_vector(versioned_constants, mode), + MessageResources::new(self.l2_to_l1_payload_lengths, None).to_gas_vector(), + ] + .iter() + .fold(GasVector::ZERO, |accumulator, cost| { + accumulator.checked_add(*cost).unwrap_or_else(|| { + panic!( + "Execution summary to gas vector overflowed: tried to add {cost:?} to \ + {accumulator:?}" + ); + }) + }) + } +} + /// L2 resources counted for fee charge. /// When all execution will be using gas (no VM mode), this should be removed, and the gas_consumed /// field should be used for fee collection. @@ -106,13 +165,17 @@ impl Sum for ExecutionSummary { #[derive(Clone, Debug, Default, Serialize, Eq, PartialEq)] pub struct ChargedResources { pub vm_resources: ExecutionResources, // Counted in CairoSteps mode calls. - pub gas_for_fee: GasAmount, // Counted in SierraGas mode calls. + pub gas_consumed: GasAmount, // Counted in SierraGas mode calls. } impl ChargedResources { pub fn from_execution_resources(resources: ExecutionResources) -> Self { Self { vm_resources: resources, ..Default::default() } } + + pub fn from_gas(gas_consumed: GasAmount) -> Self { + Self { gas_consumed, ..Default::default() } + } } impl Add<&ChargedResources> for &ChargedResources { @@ -128,11 +191,25 @@ impl Add<&ChargedResources> for &ChargedResources { impl AddAssign<&ChargedResources> for ChargedResources { fn add_assign(&mut self, other: &Self) { self.vm_resources += &other.vm_resources; - self.gas_for_fee = - self.gas_for_fee.checked_add(other.gas_for_fee).expect("Gas for fee overflowed."); + self.gas_consumed = + self.gas_consumed.checked_add(other.gas_consumed).expect("Gas for fee overflowed."); } } +#[cfg_attr(any(test, feature = "testing"), derive(Clone))] +#[cfg_attr(feature = "transaction_serde", derive(serde::Deserialize))] +#[derive(Debug, Default, Eq, PartialEq, Serialize)] +pub struct StorageAccessTracker { + // TODO(Aner): refactor all to use a single enum with accessed_keys and ordered_values. + pub storage_read_values: Vec, + pub accessed_storage_keys: HashSet, + pub read_class_hash_values: Vec, + pub accessed_contract_addresses: HashSet, + // TODO(Aner): add tests for storage tracking of contract 0x1 + pub read_block_hash_values: Vec, + pub accessed_blocks: HashSet, +} + /// Represents the full effects of executing an entry point, including the inner calls it invoked. #[cfg_attr(any(test, feature = "testing"), derive(Clone))] #[cfg_attr(feature = "transaction_serde", derive(serde::Deserialize))] @@ -141,14 +218,11 @@ pub struct CallInfo { pub call: CallEntryPoint, pub execution: CallExecution, pub inner_calls: Vec, + pub resources: ExecutionResources, pub tracked_resource: TrackedResource, - pub charged_resources: ChargedResources, // Additional information gathered during execution. - pub storage_read_values: Vec, - pub accessed_storage_keys: HashSet, - pub read_class_hash_values: Vec, - pub accessed_contract_addresses: HashSet, + pub storage_access_tracker: StorageAccessTracker, } impl CallInfo { @@ -181,6 +255,7 @@ impl CallInfo { // Storage entries. let call_storage_entries = call_info + .storage_access_tracker .accessed_storage_keys .iter() .map(|storage_key| (call_info.call.storage_address, *storage_key)); @@ -208,9 +283,12 @@ impl CallInfo { } ExecutionSummary { - // Note: the charged resourses of a call contains the inner call resources, unlike other - // fields such as events and messages, - charged_resources: self.charged_resources.clone(), + // Note: the vm_resources and gas_consumed of a call contains the inner call resources, + // unlike other fields such as events and messages. + charged_resources: ChargedResources { + vm_resources: self.resources.clone(), + gas_consumed: GasAmount(self.execution.gas_consumed), + }, executed_class_hashes, visited_storage_entries, l2_to_l1_payload_lengths, @@ -225,13 +303,13 @@ impl CallInfo { call_infos.map(|call_info| call_info.summarize(versioned_constants)).sum() } - pub fn summarize_charged_resources<'a>( + pub fn summarize_vm_resources<'a>( call_infos: impl Iterator, - ) -> ChargedResources { - // Note: the charged resourses of a call contains the inner call resources, unlike other - // fields such as events and messages, - call_infos.fold(ChargedResources::default(), |mut acc, inner_call| { - acc += &inner_call.charged_resources; + ) -> ExecutionResources { + // Note: the vm resources (and entire charged resources) of a call contains the inner call + // resources, unlike other fields such as events and messages. + call_infos.fold(ExecutionResources::default(), |mut acc, inner_call| { + acc += &inner_call.resources; acc }) } diff --git a/crates/blockifier/src/execution/contract_address_test.rs b/crates/blockifier/src/execution/contract_address_test.rs index 7c0959e817a..7e65651686d 100644 --- a/crates/blockifier/src/execution/contract_address_test.rs +++ b/crates/blockifier/src/execution/contract_address_test.rs @@ -1,19 +1,20 @@ +use blockifier_test_utils::cairo_versions::CairoVersion; +use blockifier_test_utils::contracts::FeatureContract; use rstest::rstest; use starknet_api::abi::abi_utils::selector_from_name; use starknet_api::core::{calculate_contract_address, ClassHash, ContractAddress}; use starknet_api::transaction::fields::{Calldata, ContractAddressSalt}; use starknet_api::{calldata, felt}; +use crate::blockifier_versioned_constants::VersionedConstants; use crate::context::ChainInfo; use crate::execution::call_info::CallExecution; use crate::execution::entry_point::CallEntryPoint; use crate::retdata; use crate::state::cached_state::CachedState; -use crate::test_utils::contracts::FeatureContract; use crate::test_utils::dict_state_reader::DictStateReader; use crate::test_utils::initial_test_state::test_state; -use crate::test_utils::{CairoVersion, BALANCE}; -use crate::versioned_constants::VersionedConstants; +use crate::test_utils::BALANCE; #[rstest] fn test_calculate_contract_address() { @@ -34,7 +35,7 @@ fn test_calculate_contract_address() { calldata, entry_point_selector: selector_from_name("test_contract_address"), storage_address: deployer_address, - initial_gas: versioned_constants.default_initial_gas_cost(), + initial_gas: versioned_constants.infinite_gas_for_vm_mode(), ..Default::default() }; let contract_address = diff --git a/crates/blockifier/src/execution/contract_class.rs b/crates/blockifier/src/execution/contract_class.rs index c1c6eec8044..1b40de15035 100644 --- a/crates/blockifier/src/execution/contract_class.rs +++ b/crates/blockifier/src/execution/contract_class.rs @@ -18,10 +18,9 @@ use cairo_vm::types::program::Program; use cairo_vm::types::relocatable::MaybeRelocatable; use cairo_vm::vm::runners::cairo_runner::ExecutionResources; use itertools::Itertools; -use semver::Version; use serde::de::Error as DeserializationError; use serde::{Deserialize, Deserializer, Serialize}; -use starknet_api::contract_class::{ContractClass, EntryPointType}; +use starknet_api::contract_class::{ContractClass, EntryPointType, SierraVersion, VersionedCasm}; use starknet_api::core::EntryPointSelector; use starknet_api::deprecated_contract_class::{ ContractClass as DeprecatedContractClass, @@ -29,17 +28,15 @@ use starknet_api::deprecated_contract_class::{ EntryPointV0, Program as DeprecatedProgram, }; -use starknet_api::transaction::fields::GasVectorComputationMode; use starknet_types_core::felt::Felt; use crate::abi::constants::{self}; -use crate::execution::entry_point::CallEntryPoint; +use crate::execution::entry_point::{EntryPointExecutionContext, EntryPointTypeAndSelector}; use crate::execution::errors::PreExecutionError; use crate::execution::execution_utils::{poseidon_hash_many_cost, sn_api_to_cairo_vm_program}; #[cfg(feature = "cairo_native")] -use crate::execution::native::contract_class::NativeContractClassV1; +use crate::execution::native::contract_class::NativeCompiledClassV1; use crate::transaction::errors::TransactionExecutionError; -use crate::versioned_constants::CompilerVersion; #[cfg(test)] #[path = "contract_class_test.rs"] @@ -58,29 +55,30 @@ pub enum TrackedResource { SierraGas, // AKA Sierra mode. } -/// Represents a runnable Starknet contract class (meaning, the program is runnable by the VM). +/// Represents a runnable Starknet compiled class. +/// Meaning, the program is runnable by the VM (or natively). #[derive(Clone, Debug, Eq, PartialEq, derive_more::From)] -pub enum RunnableContractClass { - V0(ContractClassV0), - V1(ContractClassV1), +pub enum RunnableCompiledClass { + V0(CompiledClassV0), + V1(CompiledClassV1), #[cfg(feature = "cairo_native")] - V1Native(NativeContractClassV1), + V1Native(NativeCompiledClassV1), } -impl TryFrom for RunnableContractClass { +impl TryFrom for RunnableCompiledClass { type Error = ProgramError; fn try_from(raw_contract_class: ContractClass) -> Result { let contract_class: Self = match raw_contract_class { ContractClass::V0(raw_contract_class) => Self::V0(raw_contract_class.try_into()?), - ContractClass::V1(raw_contract_class) => Self::V1(raw_contract_class.try_into()?), + ContractClass::V1(versioned_casm) => Self::V1(versioned_casm.try_into()?), }; Ok(contract_class) } } -impl RunnableContractClass { +impl RunnableCompiledClass { pub fn constructor_selector(&self) -> Option { match self { Self::V0(class) => class.constructor_selector(), @@ -95,9 +93,7 @@ impl RunnableContractClass { Self::V0(class) => class.estimate_casm_hash_computation_resources(), Self::V1(class) => class.estimate_casm_hash_computation_resources(), #[cfg(feature = "cairo_native")] - Self::V1Native(_) => { - todo!("Use casm to estimate casm hash computation resources") - } + Self::V1Native(class) => class.casm().estimate_casm_hash_computation_resources(), } } @@ -117,34 +113,36 @@ impl RunnableContractClass { } } - pub fn bytecode_length(&self) -> usize { - match self { - Self::V0(class) => class.bytecode_length(), - Self::V1(class) => class.bytecode_length(), + /// Returns whether this contract should run using Cairo steps or Sierra gas. + pub fn tracked_resource( + &self, + min_sierra_version: &SierraVersion, + last_tracked_resource: Option<&TrackedResource>, + ) -> TrackedResource { + let contract_tracked_resource = match self { + Self::V0(_) => TrackedResource::CairoSteps, + Self::V1(contract_class) => contract_class.tracked_resource(min_sierra_version), #[cfg(feature = "cairo_native")] - Self::V1Native(_) => { - todo!("implement bytecode_length for native contracts.") + Self::V1Native(contract_class) => { + contract_class.casm().tracked_resource(min_sierra_version) } + }; + match last_tracked_resource { + // Once we ran with CairoSteps, we will continue to run using it for all nested calls. + Some(TrackedResource::CairoSteps) => TrackedResource::CairoSteps, + Some(TrackedResource::SierraGas) | None => contract_tracked_resource, } } - /// Returns whether this contract should run using Cairo steps or Sierra gas. - pub fn tracked_resource( + /// Returns the tracked resource for calling this contract from within a context. + pub fn get_current_tracked_resource( &self, - min_sierra_version: &CompilerVersion, - gas_mode: GasVectorComputationMode, + context: &EntryPointExecutionContext, ) -> TrackedResource { - match gas_mode { - GasVectorComputationMode::All => match self { - Self::V0(_) => TrackedResource::CairoSteps, - Self::V1(contract_class) => contract_class.tracked_resource(min_sierra_version), - #[cfg(feature = "cairo_native")] - Self::V1Native(contract_class) => { - contract_class.casm().tracked_resource(min_sierra_version) - } - }, - GasVectorComputationMode::NoL2Gas => TrackedResource::CairoSteps, - } + self.tracked_resource( + &context.versioned_constants().min_sierra_version_for_sierra_gas, + context.tracked_resource_stack.last(), + ) } } @@ -156,16 +154,16 @@ impl RunnableContractClass { // Note: when deserializing from a SN API class JSON string, the ABI field is ignored // by serde, since it is not required for execution. #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq)] -pub struct ContractClassV0(pub Arc); -impl Deref for ContractClassV0 { - type Target = ContractClassV0Inner; +pub struct CompiledClassV0(pub Arc); +impl Deref for CompiledClassV0 { + type Target = CompiledClassV0Inner; fn deref(&self) -> &Self::Target { &self.0 } } -impl ContractClassV0 { +impl CompiledClassV0 { fn constructor_selector(&self) -> Option { Some(self.entry_points_by_type[&EntryPointType::Constructor].first()?.selector) } @@ -201,24 +199,24 @@ impl ContractClassV0 { TrackedResource::CairoSteps } - pub fn try_from_json_string(raw_contract_class: &str) -> Result { - let contract_class: ContractClassV0Inner = serde_json::from_str(raw_contract_class)?; - Ok(ContractClassV0(Arc::new(contract_class))) + pub fn try_from_json_string(raw_contract_class: &str) -> Result { + let contract_class: CompiledClassV0Inner = serde_json::from_str(raw_contract_class)?; + Ok(CompiledClassV0(Arc::new(contract_class))) } } #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq)] -pub struct ContractClassV0Inner { +pub struct CompiledClassV0Inner { #[serde(deserialize_with = "deserialize_program")] pub program: Program, pub entry_points_by_type: HashMap>, } -impl TryFrom for ContractClassV0 { +impl TryFrom for CompiledClassV0 { type Error = ProgramError; fn try_from(class: DeprecatedContractClass) -> Result { - Ok(Self(Arc::new(ContractClassV0Inner { + Ok(Self(Arc::new(CompiledClassV0Inner { program: sn_api_to_cairo_vm_program(class.program)?, entry_points_by_type: class.entry_points_by_type, }))) @@ -227,12 +225,12 @@ impl TryFrom for ContractClassV0 { // V1. -/// Represents a runnable Cario (Cairo 1) Starknet contract class (meaning, the program is runnable +/// Represents a runnable Cario (Cairo 1) Starknet compiled class (meaning, the program is runnable /// by the VM). We wrap the actual class in an Arc to avoid cloning the program when cloning the /// class. #[derive(Clone, Debug, Eq, PartialEq)] -pub struct ContractClassV1(pub Arc); -impl Deref for ContractClassV1 { +pub struct CompiledClassV1(pub Arc); +impl Deref for CompiledClassV1 { type Target = ContractClassV1Inner; fn deref(&self) -> &Self::Target { @@ -240,7 +238,7 @@ impl Deref for ContractClassV1 { } } -impl ContractClassV1 { +impl CompiledClassV1 { pub fn constructor_selector(&self) -> Option { self.0.entry_points_by_type.constructor.first().map(|ep| ep.selector) } @@ -255,14 +253,14 @@ impl ContractClassV1 { pub fn get_entry_point( &self, - call: &CallEntryPoint, + entry_point: &EntryPointTypeAndSelector, ) -> Result { - self.entry_points_by_type.get_entry_point(call) + self.entry_points_by_type.get_entry_point(entry_point) } /// Returns whether this contract should run using Cairo steps or Sierra gas. - pub fn tracked_resource(&self, min_sierra_version: &CompilerVersion) -> TrackedResource { - if *min_sierra_version <= self.compiler_version { + pub fn tracked_resource(&self, min_sierra_version: &SierraVersion) -> TrackedResource { + if *min_sierra_version <= self.sierra_version { TrackedResource::SierraGas } else { TrackedResource::CairoSteps @@ -286,10 +284,12 @@ impl ContractClassV1 { get_visited_segments(&self.bytecode_segment_lengths, &mut reversed_visited_pcs, &mut 0) } - pub fn try_from_json_string(raw_contract_class: &str) -> Result { + pub fn try_from_json_string( + raw_contract_class: &str, + sierra_version: SierraVersion, + ) -> Result { let casm_contract_class: CasmContractClass = serde_json::from_str(raw_contract_class)?; - let contract_class = ContractClassV1::try_from(casm_contract_class)?; - + let contract_class = CompiledClassV1::try_from((casm_contract_class, sierra_version))?; Ok(contract_class) } } @@ -390,7 +390,7 @@ pub struct ContractClassV1Inner { pub program: Program, pub entry_points_by_type: EntryPointsByType, pub hints: HashMap, - pub compiler_version: CompilerVersion, + pub sierra_version: SierraVersion, bytecode_segment_lengths: NestedIntList, } @@ -413,10 +413,10 @@ impl HasSelector for EntryPointV1 { } } -impl TryFrom for ContractClassV1 { +impl TryFrom for CompiledClassV1 { type Error = ProgramError; - fn try_from(class: CasmContractClass) -> Result { + fn try_from((class, sierra_version): VersionedCasm) -> Result { let data: Vec = class.bytecode.iter().map(|x| MaybeRelocatable::from(Felt::from(&x.value))).collect(); @@ -462,15 +462,11 @@ impl TryFrom for ContractClassV1 { let bytecode_segment_lengths = class .bytecode_segment_lengths .unwrap_or_else(|| NestedIntList::Leaf(program.data_len())); - let compiler_version = CompilerVersion( - Version::parse(&class.compiler_version) - .unwrap_or_else(|_| panic!("Invalid version: '{}'", class.compiler_version)), - ); - Ok(ContractClassV1(Arc::new(ContractClassV1Inner { + Ok(CompiledClassV1(Arc::new(ContractClassV1Inner { program, entry_points_by_type, hints: string_to_hint, - compiler_version, + sierra_version, bytecode_segment_lengths, }))) } @@ -526,21 +522,24 @@ pub struct EntryPointsByType { } impl EntryPointsByType { - pub fn get_entry_point(&self, call: &CallEntryPoint) -> Result { - call.verify_constructor()?; + pub fn get_entry_point( + &self, + entry_point: &EntryPointTypeAndSelector, + ) -> Result { + entry_point.verify_constructor()?; - let entry_points_of_same_type = &self[call.entry_point_type]; + let entry_points_of_same_type = &self[entry_point.entry_point_type]; let filtered_entry_points: Vec<_> = entry_points_of_same_type .iter() - .filter(|ep| *ep.selector() == call.entry_point_selector) + .filter(|ep| *ep.selector() == entry_point.entry_point_selector) .collect(); match filtered_entry_points[..] { - [] => Err(PreExecutionError::EntryPointNotFound(call.entry_point_selector)), + [] => Err(PreExecutionError::EntryPointNotFound(entry_point.entry_point_selector)), [entry_point] => Ok(entry_point.clone()), _ => Err(PreExecutionError::DuplicatedEntryPointSelector { - selector: call.entry_point_selector, - typ: call.entry_point_type, + selector: entry_point.entry_point_selector, + typ: entry_point.entry_point_type, }), } } diff --git a/crates/blockifier/src/execution/contract_class_test.rs b/crates/blockifier/src/execution/contract_class_test.rs index 6dcfd7411e2..15a76af858c 100644 --- a/crates/blockifier/src/execution/contract_class_test.rs +++ b/crates/blockifier/src/execution/contract_class_test.rs @@ -5,16 +5,16 @@ use assert_matches::assert_matches; use cairo_lang_starknet_classes::NestedIntList; use rstest::rstest; -use crate::execution::contract_class::{ContractClassV1, ContractClassV1Inner}; +use crate::execution::contract_class::{CompiledClassV1, ContractClassV1Inner}; use crate::transaction::errors::TransactionExecutionError; #[rstest] fn test_get_visited_segments() { - let test_contract = ContractClassV1(Arc::new(ContractClassV1Inner { + let test_contract = CompiledClassV1(Arc::new(ContractClassV1Inner { program: Default::default(), entry_points_by_type: Default::default(), hints: Default::default(), - compiler_version: Default::default(), + sierra_version: Default::default(), bytecode_segment_lengths: NestedIntList::Node(vec![ NestedIntList::Leaf(151), NestedIntList::Leaf(104), diff --git a/crates/blockifier/src/execution/deprecated_entry_point_execution.rs b/crates/blockifier/src/execution/deprecated_entry_point_execution.rs index fd4084682db..7559e560d20 100644 --- a/crates/blockifier/src/execution/deprecated_entry_point_execution.rs +++ b/crates/blockifier/src/execution/deprecated_entry_point_execution.rs @@ -9,17 +9,17 @@ use starknet_api::abi::abi_utils::selector_from_name; use starknet_api::abi::constants::{CONSTRUCTOR_ENTRY_POINT_NAME, DEFAULT_ENTRY_POINT_SELECTOR}; use starknet_api::contract_class::EntryPointType; use starknet_api::core::EntryPointSelector; -use starknet_api::execution_resources::GasAmount; use starknet_api::hash::StarkHash; +use super::call_info::StorageAccessTracker; use super::execution_utils::SEGMENT_ARENA_BUILTIN_SIZE; -use crate::execution::call_info::{CallExecution, CallInfo, ChargedResources}; -use crate::execution::contract_class::{ContractClassV0, TrackedResource}; +use crate::execution::call_info::{CallExecution, CallInfo}; +use crate::execution::contract_class::{CompiledClassV0, TrackedResource}; use crate::execution::deprecated_syscalls::hint_processor::DeprecatedSyscallHintProcessor; use crate::execution::entry_point::{ - CallEntryPoint, EntryPointExecutionContext, EntryPointExecutionResult, + ExecutableCallEntryPoint, }; use crate::execution::errors::{PostExecutionError, PreExecutionError}; use crate::execution::execution_utils::{read_execution_retdata, Args, ReadOnlySegments}; @@ -43,13 +43,13 @@ pub const CAIRO0_BUILTINS_NAMES: [BuiltinName; 6] = [ /// Executes a specific call to a contract entry point and returns its output. pub fn execute_entry_point_call( - call: CallEntryPoint, - contract_class: ContractClassV0, + call: ExecutableCallEntryPoint, + compiled_class: CompiledClassV0, state: &mut dyn State, context: &mut EntryPointExecutionContext, ) -> EntryPointExecutionResult { let VmExecutionContext { mut runner, mut syscall_handler, initial_syscall_ptr, entry_point_pc } = - initialize_execution_context(&call, contract_class, state, context)?; + initialize_execution_context(&call, compiled_class, state, context)?; let (implicit_args, args) = prepare_call_arguments( &call, @@ -66,14 +66,14 @@ pub fn execute_entry_point_call( } pub fn initialize_execution_context<'a>( - call: &CallEntryPoint, - contract_class: ContractClassV0, + call: &ExecutableCallEntryPoint, + compiled_class: CompiledClassV0, state: &'a mut dyn State, context: &'a mut EntryPointExecutionContext, ) -> Result, PreExecutionError> { // Verify use of cairo0 builtins only. let program_builtins: HashSet<&BuiltinName> = - HashSet::from_iter(contract_class.program.iter_builtins()); + HashSet::from_iter(compiled_class.program.iter_builtins()); let unsupported_builtins = &program_builtins - &HashSet::from_iter(CAIRO0_BUILTINS_NAMES.iter()); if !unsupported_builtins.is_empty() { @@ -83,14 +83,14 @@ pub fn initialize_execution_context<'a>( } // Resolve initial PC from EP indicator. - let entry_point_pc = resolve_entry_point_pc(call, &contract_class)?; + let entry_point_pc = resolve_entry_point_pc(call, &compiled_class)?; // Instantiate Cairo runner. let proof_mode = false; let trace_enabled = false; let allow_missing_builtins = false; let program_base = None; let mut runner = - CairoRunner::new(&contract_class.program, LayoutName::starknet, proof_mode, trace_enabled)?; + CairoRunner::new(&compiled_class.program, LayoutName::starknet, proof_mode, trace_enabled)?; runner.initialize_builtins(allow_missing_builtins)?; runner.initialize_segments(program_base); @@ -103,14 +103,15 @@ pub fn initialize_execution_context<'a>( initial_syscall_ptr, call.storage_address, call.caller_address, + call.class_hash, ); Ok(VmExecutionContext { runner, syscall_handler, initial_syscall_ptr, entry_point_pc }) } pub fn resolve_entry_point_pc( - call: &CallEntryPoint, - contract_class: &ContractClassV0, + call: &ExecutableCallEntryPoint, + compiled_class: &CompiledClassV0, ) -> Result { if call.entry_point_type == EntryPointType::Constructor && call.entry_point_selector != selector_from_name(CONSTRUCTOR_ENTRY_POINT_NAME) @@ -118,7 +119,7 @@ pub fn resolve_entry_point_pc( return Err(PreExecutionError::InvalidConstructorEntryPointName); } - let entry_points_of_same_type = &contract_class.entry_points_by_type[&call.entry_point_type]; + let entry_points_of_same_type = &compiled_class.entry_points_by_type[&call.entry_point_type]; let filtered_entry_points: Vec<_> = entry_points_of_same_type .iter() .filter(|ep| ep.selector == call.entry_point_selector) @@ -157,7 +158,7 @@ pub fn resolve_entry_point_pc( } pub fn prepare_call_arguments( - call: &CallEntryPoint, + call: &ExecutableCallEntryPoint, runner: &mut CairoRunner, initial_syscall_ptr: Relocatable, read_only_segments: &mut ReadOnlySegments, @@ -218,7 +219,7 @@ pub fn run_entry_point( pub fn finalize_execution( mut runner: CairoRunner, syscall_handler: DeprecatedSyscallHintProcessor<'_>, - call: CallEntryPoint, + call: ExecutableCallEntryPoint, implicit_args: Vec, n_total_args: usize, ) -> Result { @@ -252,17 +253,13 @@ pub fn finalize_execution( } // Take into account the syscall resources of the current call. vm_resources_without_inner_calls += - &versioned_constants.get_additional_os_syscall_resources(&syscall_handler.syscall_counter); + &versioned_constants.get_additional_os_syscall_resources(&syscall_handler.syscalls_usage); - let charged_resources_without_inner_calls = ChargedResources { - vm_resources: vm_resources_without_inner_calls, - gas_for_fee: GasAmount(0), - }; - let charged_resources = &charged_resources_without_inner_calls - + &CallInfo::summarize_charged_resources(syscall_handler.inner_calls.iter()); + let vm_resources = &vm_resources_without_inner_calls + + &CallInfo::summarize_vm_resources(syscall_handler.inner_calls.iter()); Ok(CallInfo { - call, + call: call.into(), execution: CallExecution { retdata: read_execution_retdata(&runner, retdata_size, &retdata_ptr)?, events: syscall_handler.events, @@ -272,10 +269,12 @@ pub fn finalize_execution( }, inner_calls: syscall_handler.inner_calls, tracked_resource: TrackedResource::CairoSteps, - charged_resources, - storage_read_values: syscall_handler.read_values, - accessed_storage_keys: syscall_handler.accessed_keys, - ..Default::default() + resources: vm_resources, + storage_access_tracker: StorageAccessTracker { + storage_read_values: syscall_handler.read_values, + accessed_storage_keys: syscall_handler.accessed_keys, + ..Default::default() + }, }) } diff --git a/crates/blockifier/src/execution/deprecated_syscalls/deprecated_syscalls_test.rs b/crates/blockifier/src/execution/deprecated_syscalls/deprecated_syscalls_test.rs index 33aad71bbef..63b8b2fa55a 100644 --- a/crates/blockifier/src/execution/deprecated_syscalls/deprecated_syscalls_test.rs +++ b/crates/blockifier/src/execution/deprecated_syscalls/deprecated_syscalls_test.rs @@ -1,52 +1,51 @@ use std::collections::{HashMap, HashSet}; +use blockifier_test_utils::cairo_versions::CairoVersion; +use blockifier_test_utils::contracts::FeatureContract; use cairo_vm::types::builtin_name::BuiltinName; use cairo_vm::vm::runners::cairo_runner::ExecutionResources; use pretty_assertions::assert_eq; use rstest::rstest; use starknet_api::abi::abi_utils::selector_from_name; -use starknet_api::core::{calculate_contract_address, ChainId}; +use starknet_api::core::calculate_contract_address; use starknet_api::state::StorageKey; -use starknet_api::transaction::fields::{Calldata, ContractAddressSalt, Fee}; +use starknet_api::test_utils::{ + CHAIN_ID_FOR_TESTS, + CURRENT_BLOCK_NUMBER, + CURRENT_BLOCK_NUMBER_FOR_VALIDATE, + CURRENT_BLOCK_TIMESTAMP, + CURRENT_BLOCK_TIMESTAMP_FOR_VALIDATE, + TEST_SEQUENCER_ADDRESS, +}; +use starknet_api::transaction::fields::{Calldata, ContractAddressSalt, Fee, Tip}; use starknet_api::transaction::{ EventContent, EventData, EventKey, - TransactionHash, TransactionVersion, QUERY_VERSION_BASE, }; -use starknet_api::{calldata, felt, nonce, storage_key}; +use starknet_api::{calldata, felt, nonce, storage_key, tx_hash}; use starknet_types_core::felt::Felt; use test_case::test_case; +use crate::blockifier_versioned_constants::VersionedConstants; use crate::context::ChainInfo; -use crate::execution::call_info::{CallExecution, CallInfo, ChargedResources, OrderedEvent}; +use crate::execution::call_info::{CallExecution, CallInfo, OrderedEvent, StorageAccessTracker}; use crate::execution::common_hints::ExecutionMode; use crate::execution::deprecated_syscalls::DeprecatedSyscallSelector; use crate::execution::entry_point::{CallEntryPoint, CallType}; use crate::execution::errors::EntryPointExecutionError; use crate::execution::syscalls::hint_processor::EmitEventError; use crate::state::state_api::StateReader; -use crate::test_utils::contracts::FeatureContract; -use crate::test_utils::initial_test_state::test_state; +use crate::test_utils::contracts::FeatureContractData; +use crate::test_utils::initial_test_state::{test_state, test_state_ex}; use crate::test_utils::{ calldata_for_deploy_test, - get_syscall_resources, + get_const_syscall_resources, trivial_external_entry_point_new, - CairoVersion, - CURRENT_BLOCK_NUMBER, - CURRENT_BLOCK_NUMBER_FOR_VALIDATE, - CURRENT_BLOCK_TIMESTAMP, - CURRENT_BLOCK_TIMESTAMP_FOR_VALIDATE, - TEST_SEQUENCER_ADDRESS, }; -use crate::transaction::objects::{ - CommonAccountFields, - DeprecatedTransactionInfo, - TransactionInfo, -}; -use crate::versioned_constants::VersionedConstants; +use crate::transaction::objects::{CommonAccountFields, CurrentTransactionInfo, TransactionInfo}; use crate::{check_entry_point_execution_error_for_custom_hint, retdata}; #[test] @@ -147,59 +146,61 @@ fn test_nested_library_call() { ..nested_storage_entry_point }; let storage_entry_point_resources = ExecutionResources { - n_steps: 222, + n_steps: 228, n_memory_holes: 0, builtin_instance_counter: HashMap::from([(BuiltinName::range_check, 2)]), }; let nested_storage_call_info = CallInfo { call: nested_storage_entry_point, execution: CallExecution::from_retdata(retdata![felt!(value + 1)]), - charged_resources: ChargedResources::from_execution_resources( - storage_entry_point_resources.clone(), - ), - storage_read_values: vec![felt!(value + 1)], - accessed_storage_keys: HashSet::from([storage_key!(key + 1)]), + resources: storage_entry_point_resources.clone(), + storage_access_tracker: StorageAccessTracker { + storage_read_values: vec![felt!(value + 1)], + accessed_storage_keys: HashSet::from([storage_key!(key + 1)]), + ..Default::default() + }, ..Default::default() }; - let mut library_call_resources = &get_syscall_resources(DeprecatedSyscallSelector::LibraryCall) - + &ExecutionResources { - n_steps: 39, - n_memory_holes: 0, - builtin_instance_counter: HashMap::from([(BuiltinName::range_check, 1)]), - }; + let mut library_call_resources = + &get_const_syscall_resources(DeprecatedSyscallSelector::LibraryCall) + + &ExecutionResources { + n_steps: 39, + n_memory_holes: 0, + builtin_instance_counter: HashMap::from([(BuiltinName::range_check, 1)]), + }; library_call_resources += &storage_entry_point_resources; let library_call_info = CallInfo { call: library_entry_point, execution: CallExecution::from_retdata(retdata![felt!(value + 1)]), - charged_resources: ChargedResources::from_execution_resources( - library_call_resources.clone(), - ), + resources: library_call_resources.clone(), inner_calls: vec![nested_storage_call_info], ..Default::default() }; let storage_call_info = CallInfo { call: storage_entry_point, execution: CallExecution::from_retdata(retdata![felt!(value)]), - charged_resources: ChargedResources::from_execution_resources( - storage_entry_point_resources.clone(), - ), - storage_read_values: vec![felt!(value)], - accessed_storage_keys: HashSet::from([storage_key!(key)]), + resources: storage_entry_point_resources.clone(), + storage_access_tracker: StorageAccessTracker { + storage_read_values: vec![felt!(value)], + accessed_storage_keys: HashSet::from([storage_key!(key)]), + ..Default::default() + }, ..Default::default() }; // Nested library call cost: library_call(inner) + library_call(library_call(inner)). - let mut main_call_resources = &get_syscall_resources(DeprecatedSyscallSelector::LibraryCall) - + &ExecutionResources { - n_steps: 45, - n_memory_holes: 0, - builtin_instance_counter: HashMap::new(), - }; + let mut main_call_resources = + &get_const_syscall_resources(DeprecatedSyscallSelector::LibraryCall) + + &ExecutionResources { + n_steps: 45, + n_memory_holes: 0, + builtin_instance_counter: HashMap::new(), + }; main_call_resources += &(&library_call_resources * 2); let expected_call_info = CallInfo { call: main_entry_point.clone(), execution: CallExecution::from_retdata(retdata![felt!(0_u8)]), - charged_resources: ChargedResources::from_execution_resources(main_call_resources), + resources: main_call_resources, inner_calls: vec![library_call_info, storage_call_info], ..Default::default() }; @@ -244,13 +245,16 @@ fn test_call_contract() { ..trivial_external_entry_point }, execution: expected_execution.clone(), - charged_resources: ChargedResources::from_execution_resources(ExecutionResources { - n_steps: 222, + resources: ExecutionResources { + n_steps: 228, n_memory_holes: 0, builtin_instance_counter: HashMap::from([(BuiltinName::range_check, 2)]), - }), - storage_read_values: vec![value], - accessed_storage_keys: HashSet::from([storage_key!(key_int)]), + }, + storage_access_tracker: StorageAccessTracker { + storage_read_values: vec![value], + accessed_storage_keys: HashSet::from([storage_key!(key_int)]), + ..Default::default() + }, ..Default::default() }; let expected_call_info = CallInfo { @@ -262,14 +266,12 @@ fn test_call_contract() { ..trivial_external_entry_point }, execution: expected_execution, - charged_resources: ChargedResources::from_execution_resources( - &get_syscall_resources(DeprecatedSyscallSelector::CallContract) - + &ExecutionResources { - n_steps: 261, - n_memory_holes: 0, - builtin_instance_counter: HashMap::from([(BuiltinName::range_check, 3)]), - }, - ), + resources: &get_const_syscall_resources(DeprecatedSyscallSelector::CallContract) + + &ExecutionResources { + n_steps: 267, + n_memory_holes: 0, + builtin_instance_counter: HashMap::from([(BuiltinName::range_check, 3)]), + }, ..Default::default() }; @@ -459,25 +461,41 @@ fn test_block_info_syscalls( } #[rstest] -fn test_tx_info(#[values(false, true)] only_query: bool) { +fn test_tx_info( + #[values(false, true)] only_query: bool, + #[values(false, true)] v1_bound_account: bool, + // Whether the tip is larger than `v1_bound_accounts_max_tip`. + #[values(false, true)] high_tip: bool, +) { let test_contract = FeatureContract::TestContract(CairoVersion::Cairo0); - let mut state = test_state(&ChainInfo::create_for_testing(), Fee(0), &[(test_contract, 1)]); - let mut version = felt!(1_u8); + let mut test_contract_data: FeatureContractData = test_contract.into(); + if v1_bound_account { + let optional_class_hash = + VersionedConstants::latest_constants().os_constants.v1_bound_accounts_cairo0.first(); + test_contract_data.class_hash = + *optional_class_hash.expect("No v1 bound accounts found in versioned constants."); + } + + let mut state = + test_state_ex(&ChainInfo::create_for_testing(), Fee(0), &[(test_contract_data, 1)]); + let mut version = felt!(3_u8); + let mut expected_version = if v1_bound_account && !high_tip { felt!(1_u8) } else { version }; if only_query { let simulate_version_base = *QUERY_VERSION_BASE; version += simulate_version_base; + expected_version += simulate_version_base; } - let tx_hash = TransactionHash(felt!(1991_u16)); + let tx_hash = tx_hash!(1991); let max_fee = Fee(0); let nonce = nonce!(3_u16); let sender_address = test_contract.get_instance_address(0); let expected_tx_info = calldata![ - version, // Transaction version. - *sender_address.0.key(), // Account address. - felt!(max_fee.0), // Max fee. - tx_hash.0, // Transaction hash. - felt!(&*ChainId::create_for_testing().as_hex()), // Chain ID. - nonce.0 // Nonce. + expected_version, // Transaction version. + *sender_address.0.key(), // Account address. + felt!(max_fee.0), // Max fee. + tx_hash.0, // Transaction hash. + felt!(&*CHAIN_ID_FOR_TESTS.as_hex()), // Chain ID. + nonce.0 // Nonce. ]; let entry_point_selector = selector_from_name("test_get_tx_info"); let entry_point_call = CallEntryPoint { @@ -485,22 +503,29 @@ fn test_tx_info(#[values(false, true)] only_query: bool) { calldata: expected_tx_info, ..trivial_external_entry_point_new(test_contract) }; - let tx_info = TransactionInfo::Deprecated(DeprecatedTransactionInfo { + + // Transaction tip. + let tip = Tip(VersionedConstants::latest_constants().os_constants.v1_bound_accounts_max_tip.0 + + if high_tip { 1 } else { 0 }); + + let tx_info = TransactionInfo::Current(CurrentTransactionInfo { common_fields: CommonAccountFields { transaction_hash: tx_hash, - version: TransactionVersion::ONE, + version: TransactionVersion::THREE, nonce, sender_address, only_query, ..Default::default() }, - max_fee, + tip, + ..CurrentTransactionInfo::create_for_testing() }); let limit_steps_by_resources = false; // Do not limit steps by resources as we use default reasources. let result = entry_point_call .execute_directly_given_tx_info( &mut state, tx_info, + None, limit_steps_by_resources, ExecutionMode::Execute, ) @@ -525,7 +550,7 @@ fn test_emit_event() { call_info.execution, CallExecution { events: vec![OrderedEvent { order: 0, event }], - gas_consumed: 0, // TODO why? + gas_consumed: 0, // TODO(Yael): why? ..Default::default() } ); diff --git a/crates/blockifier/src/execution/deprecated_syscalls/hint_processor.rs b/crates/blockifier/src/execution/deprecated_syscalls/hint_processor.rs index 0ea7f175f64..7de27e12667 100644 --- a/crates/blockifier/src/execution/deprecated_syscalls/hint_processor.rs +++ b/crates/blockifier/src/execution/deprecated_syscalls/hint_processor.rs @@ -17,15 +17,16 @@ use cairo_vm::vm::errors::vm_errors::VirtualMachineError; use cairo_vm::vm::runners::cairo_runner::{ResourceTracker, RunResources}; use cairo_vm::vm::vm_core::VirtualMachine; use num_bigint::{BigUint, TryFromBigIntError}; +use starknet_api::block::BlockInfo; use starknet_api::contract_class::EntryPointType; use starknet_api::core::{ClassHash, ContractAddress, EntryPointSelector}; use starknet_api::state::StorageKey; use starknet_api::transaction::fields::Calldata; +use starknet_api::transaction::{signed_tx_version, TransactionOptions, TransactionVersion}; use starknet_api::StarknetApiError; use starknet_types_core::felt::{Felt, FromStrError}; use thiserror::Error; -use crate::blockifier::block::BlockInfo; use crate::context::TransactionContext; use crate::execution::call_info::{CallInfo, OrderedEvent, OrderedL2ToL1Message}; use crate::execution::common_hints::{ @@ -68,11 +69,10 @@ use crate::execution::execution_utils::{ ReadOnlySegments, }; use crate::execution::hint_code; -use crate::execution::syscalls::hint_processor::EmitEventError; +use crate::execution::syscalls::hint_processor::{EmitEventError, SyscallUsageMap}; use crate::state::errors::StateError; use crate::state::state_api::State; - -pub type SyscallCounter = HashMap; +use crate::transaction::objects::TransactionInfo; #[derive(Debug, Error)] pub enum DeprecatedSyscallExecutionError { @@ -166,13 +166,14 @@ pub struct DeprecatedSyscallHintProcessor<'a> { pub context: &'a mut EntryPointExecutionContext, pub storage_address: ContractAddress, pub caller_address: ContractAddress, + pub class_hash: ClassHash, // Execution results. /// Inner calls invoked by the current execution. pub inner_calls: Vec, pub events: Vec, pub l2_to_l1_messages: Vec, - pub syscall_counter: SyscallCounter, + pub syscalls_usage: SyscallUsageMap, // Fields needed for execution and validation. pub read_only_segments: ReadOnlySegments, @@ -197,16 +198,18 @@ impl<'a> DeprecatedSyscallHintProcessor<'a> { initial_syscall_ptr: Relocatable, storage_address: ContractAddress, caller_address: ContractAddress, + class_hash: ClassHash, ) -> Self { DeprecatedSyscallHintProcessor { state, context, storage_address, caller_address, + class_hash, inner_calls: vec![], events: vec![], l2_to_l1_messages: vec![], - syscall_counter: SyscallCounter::default(), + syscalls_usage: SyscallUsageMap::default(), read_only_segments: ReadOnlySegments::default(), syscall_ptr: initial_syscall_ptr, read_values: vec![], @@ -319,10 +322,36 @@ impl<'a> DeprecatedSyscallHintProcessor<'a> { &mut self, vm: &mut VirtualMachine, ) -> DeprecatedSyscallResult { + let tx_context = &self.context.tx_context; + // The transaction version, ignoring the only_query bit. + let version = tx_context.tx_info.version(); + let versioned_constants = &tx_context.block_context.versioned_constants; + // The set of v1-bound-accounts. + let v1_bound_accounts = &versioned_constants.os_constants.v1_bound_accounts_cairo0; + + // If the transaction version is 3 and the account is in the v1-bound-accounts set, + // the syscall should return transaction version 1 instead. + // In such a case, `self.tx_info_start_ptr` is not used. + if version == TransactionVersion::THREE && v1_bound_accounts.contains(&self.class_hash) { + let tip = match &tx_context.tx_info { + TransactionInfo::Current(transaction_info) => transaction_info.tip, + TransactionInfo::Deprecated(_) => { + panic!("Transaction info variant doesn't match transaction version") + } + }; + if tip <= versioned_constants.os_constants.v1_bound_accounts_max_tip { + let modified_version = signed_tx_version( + &TransactionVersion::ONE, + &TransactionOptions { only_query: tx_context.tx_info.only_query() }, + ); + return self.allocate_tx_info_segment(vm, Some(modified_version)); + } + } + match self.tx_info_start_ptr { Some(tx_info_start_ptr) => Ok(tx_info_start_ptr), None => { - let tx_info_start_ptr = self.allocate_tx_info_segment(vm)?; + let tx_info_start_ptr = self.allocate_tx_info_segment(vm, None)?; self.tx_info_start_ptr = Some(tx_info_start_ptr); Ok(tx_info_start_ptr) } @@ -359,8 +388,7 @@ impl<'a> DeprecatedSyscallHintProcessor<'a> { } fn increment_syscall_count(&mut self, selector: &DeprecatedSyscallSelector) { - let syscall_count = self.syscall_counter.entry(*selector).or_default(); - *syscall_count += 1; + self.syscalls_usage.entry(*selector).or_default().increment_call_count(); } fn allocate_tx_signature_segment( @@ -375,15 +403,20 @@ impl<'a> DeprecatedSyscallHintProcessor<'a> { Ok(signature_segment_start_ptr) } + /// Allocates and populates a segment with the transaction info. + /// + /// If `tx_version_override` is given, it will be used instead of the real value. fn allocate_tx_info_segment( &mut self, vm: &mut VirtualMachine, + tx_version_override: Option, ) -> DeprecatedSyscallResult { let tx_signature_start_ptr = self.get_or_allocate_tx_signature_segment(vm)?; let TransactionContext { block_context, tx_info } = self.context.tx_context.as_ref(); let tx_signature_length = tx_info.signature().0.len(); + let tx_version = tx_version_override.unwrap_or(tx_info.signed_version()); let tx_info: Vec = vec![ - tx_info.signed_version().0.into(), + tx_version.0.into(), (*tx_info.sender_address().0.key()).into(), Felt::from(tx_info.max_fee_for_execution_info_syscall().0).into(), tx_signature_length.into(), @@ -533,7 +566,7 @@ pub fn execute_library_call( storage_address: syscall_handler.storage_address, caller_address: syscall_handler.caller_address, call_type: CallType::Delegate, - initial_gas: syscall_handler.context.gas_costs().default_initial_gas_cost, + initial_gas: syscall_handler.context.gas_costs().base.default_initial_gas_cost, }; execute_inner_call(entry_point, vm, syscall_handler).map_err(|error| { diff --git a/crates/blockifier/src/execution/deprecated_syscalls/mod.rs b/crates/blockifier/src/execution/deprecated_syscalls/mod.rs index ff0741948fd..a754422bd54 100644 --- a/crates/blockifier/src/execution/deprecated_syscalls/mod.rs +++ b/crates/blockifier/src/execution/deprecated_syscalls/mod.rs @@ -64,9 +64,13 @@ pub enum DeprecatedSyscallSelector { GetTxInfo, GetTxSignature, Keccak, + // TODO(Noa): Remove it (as it is not a syscall) and define its resources in + // `OsResources`. + KeccakRound, Sha256ProcessBlock, LibraryCall, LibraryCallL1Handler, + MetaTxV0, ReplaceClass, Secp256k1Add, Secp256k1GetPointFromX, @@ -83,6 +87,21 @@ pub enum DeprecatedSyscallSelector { StorageWrite, } +impl DeprecatedSyscallSelector { + pub fn is_calling_syscall(&self) -> bool { + matches!( + self, + Self::CallContract + | Self::DelegateCall + | Self::DelegateL1Handler + | Self::Deploy + | Self::LibraryCall + | Self::LibraryCallL1Handler + | Self::MetaTxV0 + ) + } +} + impl TryFrom for DeprecatedSyscallSelector { type Error = DeprecatedSyscallExecutionError; fn try_from(raw_selector: Felt) -> Result { @@ -110,6 +129,7 @@ impl TryFrom for DeprecatedSyscallSelector { b"Sha256ProcessBlock" => Ok(Self::Sha256ProcessBlock), b"LibraryCall" => Ok(Self::LibraryCall), b"LibraryCallL1Handler" => Ok(Self::LibraryCallL1Handler), + b"MetaTxV0" => Ok(Self::MetaTxV0), b"ReplaceClass" => Ok(Self::ReplaceClass), b"Secp256k1Add" => Ok(Self::Secp256k1Add), b"Secp256k1GetPointFromX" => Ok(Self::Secp256k1GetPointFromX), @@ -219,7 +239,7 @@ pub fn call_contract( storage_address, caller_address: syscall_handler.storage_address, call_type: CallType::Call, - initial_gas: syscall_handler.context.gas_costs().default_initial_gas_cost, + initial_gas: syscall_handler.context.gas_costs().base.default_initial_gas_cost, }; let retdata_segment = execute_inner_call(entry_point, vm, syscall_handler).map_err(|error| { @@ -338,13 +358,21 @@ pub fn deploy( deployer_address_for_calculation, )?; + // Increment the Deploy syscall's linear cost counter by the number of elements in the + // constructor calldata. + let syscall_usage = syscall_handler + .syscalls_usage + .get_mut(&DeprecatedSyscallSelector::Deploy) + .expect("syscalls_usage entry for Deploy must be initialized"); + syscall_usage.linear_factor += request.constructor_calldata.0.len(); + let ctor_context = ConstructorContext { class_hash: request.class_hash, code_address: Some(deployed_contract_address), storage_address: deployed_contract_address, caller_address: deployer_address, }; - let mut remaining_gas = syscall_handler.context.gas_costs().default_initial_gas_cost; + let mut remaining_gas = syscall_handler.context.gas_costs().base.default_initial_gas_cost; let call_info = execute_deployment( syscall_handler.state, syscall_handler.context, @@ -653,7 +681,7 @@ pub fn replace_class( syscall_handler: &mut DeprecatedSyscallHintProcessor<'_>, ) -> DeprecatedSyscallResult { // Ensure the class is declared (by reading it). - syscall_handler.state.get_compiled_contract_class(request.class_hash)?; + syscall_handler.state.get_compiled_class(request.class_hash)?; syscall_handler.state.set_class_hash_at(syscall_handler.storage_address, request.class_hash)?; Ok(ReplaceClassResponse {}) diff --git a/crates/blockifier/src/execution/entry_point.rs b/crates/blockifier/src/execution/entry_point.rs index 048023e0c1d..f6d9eb65837 100644 --- a/crates/blockifier/src/execution/entry_point.rs +++ b/crates/blockifier/src/execution/entry_point.rs @@ -10,6 +10,7 @@ use starknet_api::abi::abi_utils::selector_from_name; use starknet_api::abi::constants::CONSTRUCTOR_ENTRY_POINT_NAME; use starknet_api::contract_class::EntryPointType; use starknet_api::core::{ClassHash, ContractAddress, EntryPointSelector}; +use starknet_api::execution_resources::GasAmount; use starknet_api::state::StorageKey; use starknet_api::transaction::fields::{ AllResourceBounds, @@ -20,10 +21,11 @@ use starknet_api::transaction::fields::{ use starknet_api::transaction::TransactionVersion; use starknet_types_core::felt::Felt; +use crate::blockifier_versioned_constants::{GasCosts, VersionedConstants}; use crate::context::{BlockContext, TransactionContext}; use crate::execution::call_info::CallInfo; use crate::execution::common_hints::ExecutionMode; -use crate::execution::contract_class::TrackedResource; +use crate::execution::contract_class::{RunnableCompiledClass, TrackedResource}; use crate::execution::errors::{ ConstructorEntryPointExecutionError, EntryPointExecutionError, @@ -35,7 +37,6 @@ use crate::state::state_api::{State, StateResult}; use crate::transaction::objects::{HasRelatedFeeType, TransactionInfo}; use crate::transaction::transaction_types::TransactionType; use crate::utils::usize_from_u64; -use crate::versioned_constants::{GasCosts, VersionedConstants}; #[cfg(test)] #[path = "entry_point_test.rs"] @@ -92,15 +93,38 @@ pub enum CallType { Call = 0, Delegate = 1, } + +pub struct EntryPointTypeAndSelector { + pub entry_point_type: EntryPointType, + pub entry_point_selector: EntryPointSelector, +} + +impl EntryPointTypeAndSelector { + pub fn verify_constructor(&self) -> Result<(), PreExecutionError> { + if self.entry_point_type == EntryPointType::Constructor + && self.entry_point_selector != selector_from_name(CONSTRUCTOR_ENTRY_POINT_NAME) + { + Err(PreExecutionError::InvalidConstructorEntryPointName) + } else { + Ok(()) + } + } +} + /// Represents a call to an entry point of a Starknet contract. #[cfg_attr(feature = "transaction_serde", derive(serde::Deserialize))] #[derive(Clone, Debug, Default, Eq, PartialEq, Serialize)] -pub struct CallEntryPoint { - // The class hash is not given if it can be deduced from the storage address. - pub class_hash: Option, +pub struct CallEntryPointVariant { + /// The class hash of the entry point. + /// The type is `ClassHash` in the case of [ExecutableCallEntryPoint] and `Option` + /// in the case of [CallEntryPoint]. + /// + /// The class hash is not given if it can be deduced from the storage address. + /// It is resolved prior to entry point's execution. + pub class_hash: TClassHash, // Optional, since there is no address to the code implementation in a library call. // and for outermost calls (triggered by the transaction itself). - // TODO: BACKWARD-COMPATIBILITY. + // TODO(AlonH): BACKWARD-COMPATIBILITY. pub code_address: Option, pub entry_point_type: EntryPointType, pub entry_point_selector: EntryPointSelector, @@ -112,6 +136,25 @@ pub struct CallEntryPoint { pub initial_gas: u64, } +pub type CallEntryPoint = CallEntryPointVariant>; +pub type ExecutableCallEntryPoint = CallEntryPointVariant; + +impl From for CallEntryPoint { + fn from(call: ExecutableCallEntryPoint) -> Self { + Self { + class_hash: Some(call.class_hash), + code_address: call.code_address, + entry_point_type: call.entry_point_type, + entry_point_selector: call.entry_point_selector, + calldata: call.calldata, + storage_address: call.storage_address, + caller_address: call.caller_address, + call_type: call.call_type, + initial_gas: call.initial_gas, + } + } +} + impl CallEntryPoint { pub fn execute( mut self, @@ -147,7 +190,7 @@ impl CallEntryPoint { } // Add class hash to the call, that will appear in the output (call info). self.class_hash = Some(class_hash); - let contract_class = state.get_compiled_contract_class(class_hash)?; + let compiled_class = state.get_compiled_class(class_hash)?; context.revert_infos.0.push(EntryPointRevertInfo::new( self.storage_address, @@ -157,7 +200,13 @@ impl CallEntryPoint { )); // This is the last operation of this function. - execute_entry_point_call_wrapper(self, contract_class, state, context, remaining_gas) + execute_entry_point_call_wrapper( + self.into_executable(class_hash), + compiled_class, + state, + context, + remaining_gas, + ) } /// Similar to `execute`, but returns an error if the outer call is reverted. @@ -169,6 +218,12 @@ impl CallEntryPoint { ) -> EntryPointExecutionResult { let execution_result = self.execute(state, context, remaining_gas); if let Ok(call_info) = &execution_result { + // Update revert gas tracking (for completeness - value will not be used unless the tx + // is reverted). + context.sierra_gas_revert_tracker.update_with_next_remaining_gas( + call_info.tracked_resource, + GasAmount(*remaining_gas), + ); // If the execution of the outer call failed, revert the transction. if call_info.execution.failed { return Err(EntryPointExecutionError::ExecutionFailed { @@ -182,13 +237,27 @@ impl CallEntryPoint { execution_result } - pub fn verify_constructor(&self) -> Result<(), PreExecutionError> { - if self.entry_point_type == EntryPointType::Constructor - && self.entry_point_selector != selector_from_name(CONSTRUCTOR_ENTRY_POINT_NAME) - { - Err(PreExecutionError::InvalidConstructorEntryPointName) - } else { - Ok(()) + + fn into_executable(self, class_hash: ClassHash) -> ExecutableCallEntryPoint { + ExecutableCallEntryPoint { + class_hash, + code_address: self.code_address, + entry_point_type: self.entry_point_type, + entry_point_selector: self.entry_point_selector, + calldata: self.calldata, + storage_address: self.storage_address, + caller_address: self.caller_address, + call_type: self.call_type, + initial_gas: self.initial_gas, + } + } +} + +impl ExecutableCallEntryPoint { + pub fn type_and_selector(&self) -> EntryPointTypeAndSelector { + EntryPointTypeAndSelector { + entry_point_type: self.entry_point_type, + entry_point_selector: self.entry_point_selector, } } } @@ -201,6 +270,38 @@ pub struct ConstructorContext { pub caller_address: ContractAddress, } +#[derive(Debug)] +pub struct SierraGasRevertTracker { + initial_remaining_gas: GasAmount, + last_seen_remaining_gas: GasAmount, +} + +impl SierraGasRevertTracker { + pub fn new(initial_remaining_gas: GasAmount) -> Self { + Self { initial_remaining_gas, last_seen_remaining_gas: initial_remaining_gas } + } + + /// Updates the last seen remaining gas, if we are in gas-tracking mode. + pub fn update_with_next_remaining_gas( + &mut self, + tracked_resource: TrackedResource, + next_remaining_gas: GasAmount, + ) { + if tracked_resource == TrackedResource::SierraGas { + self.last_seen_remaining_gas = next_remaining_gas; + } + } + + pub fn get_gas_consumed(&self) -> GasAmount { + self.initial_remaining_gas.checked_sub(self.last_seen_remaining_gas).unwrap_or_else(|| { + panic!( + "The consumed gas must be non-negative. Initial gas: {}, last seen gas: {}.", + self.initial_remaining_gas, self.last_seen_remaining_gas + ) + }) + } +} + #[derive(Debug)] pub struct EntryPointExecutionContext { // We use `Arc` to avoid the clone of this potentially large object, as inner calls @@ -222,6 +323,9 @@ pub struct EntryPointExecutionContext { // Information for reverting the state (inludes the revert info of the callers). pub revert_infos: ExecutionRevertInfo, + + // Used to support charging for gas consumed in blockifier revert flow. + pub sierra_gas_revert_tracker: SierraGasRevertTracker, } impl EntryPointExecutionContext { @@ -229,6 +333,7 @@ impl EntryPointExecutionContext { tx_context: Arc, mode: ExecutionMode, limit_steps_by_resources: bool, + sierra_gas_revert_tracker: SierraGasRevertTracker, ) -> Self { let max_steps = Self::max_steps(&tx_context, &mode, limit_steps_by_resources); Self { @@ -240,18 +345,34 @@ impl EntryPointExecutionContext { execution_mode: mode, tracked_resource_stack: vec![], revert_infos: ExecutionRevertInfo(vec![]), + sierra_gas_revert_tracker, } } pub fn new_validate( tx_context: Arc, limit_steps_by_resources: bool, + sierra_gas_revert_tracker: SierraGasRevertTracker, ) -> Self { - Self::new(tx_context, ExecutionMode::Validate, limit_steps_by_resources) + Self::new( + tx_context, + ExecutionMode::Validate, + limit_steps_by_resources, + sierra_gas_revert_tracker, + ) } - pub fn new_invoke(tx_context: Arc, limit_steps_by_resources: bool) -> Self { - Self::new(tx_context, ExecutionMode::Execute, limit_steps_by_resources) + pub fn new_invoke( + tx_context: Arc, + limit_steps_by_resources: bool, + sierra_gas_revert_tracker: SierraGasRevertTracker, + ) -> Self { + Self::new( + tx_context, + ExecutionMode::Execute, + limit_steps_by_resources, + sierra_gas_revert_tracker, + ) } /// Returns the maximum number of cairo steps allowed, given the max fee, gas price and the @@ -264,7 +385,7 @@ impl EntryPointExecutionContext { limit_steps_by_resources: bool, ) -> usize { let TransactionContext { block_context, tx_info } = tx_context; - let BlockContext { block_info, versioned_constants, .. } = block_context; + let BlockContext { block_info, versioned_constants, .. } = block_context.as_ref(); let block_upper_bound = match mode { ExecutionMode::Validate => versioned_constants.validate_max_n_steps, ExecutionMode::Execute => versioned_constants.invoke_tx_max_n_steps, @@ -284,7 +405,7 @@ impl EntryPointExecutionContext { // New transactions with only L1 bounds use the L1 resource bounds directly. // New transactions with L2 bounds use the L2 bounds directly. let l1_gas_per_step = versioned_constants.vm_resource_fee_cost().n_steps; - let l2_gas_per_step = versioned_constants.os_constants.gas_costs.step_gas_cost; + let l2_gas_per_step = versioned_constants.os_constants.gas_costs.base.step_gas_cost; let tx_upper_bound_u64 = match tx_info { // Fee is a larger uint type than GasAmount, so we need to saturate the division. @@ -293,9 +414,9 @@ impl EntryPointExecutionContext { if l1_gas_per_step.is_zero() { u64::MAX } else { - let induced_l1_gas_limit = context.max_fee.saturating_div( - block_info.gas_prices.get_l1_gas_price_by_fee_type(&tx_info.fee_type()), - ); + let induced_l1_gas_limit = context + .max_fee + .saturating_div(block_info.gas_prices.l1_gas_price(&tx_info.fee_type())); (l1_gas_per_step.inv() * induced_l1_gas_limit.0).to_integer() } } @@ -343,11 +464,7 @@ impl EntryPointExecutionContext { // would cause underflow error. // Logically, we update remaining steps to `max(0, remaining_steps - steps_to_subtract)`. let remaining_steps = self.n_remaining_steps(); - let new_remaining_steps = if remaining_steps < steps_to_subtract { - 0 - } else { - remaining_steps - steps_to_subtract - }; + let new_remaining_steps = remaining_steps.saturating_sub(steps_to_subtract); self.vm_run_resources = RunResources::new(new_remaining_steps); self.n_remaining_steps() } @@ -363,7 +480,7 @@ impl EntryPointExecutionContext { ) -> usize { let validate_steps = validate_call_info .as_ref() - .map(|call_info| call_info.charged_resources.vm_resources.n_steps) + .map(|call_info| call_info.resources.n_steps) .unwrap_or_default(); let overhead_steps = @@ -371,6 +488,17 @@ impl EntryPointExecutionContext { self.subtract_steps(validate_steps + overhead_steps) } + /// Calls update_with_next_remaining_gas if the tracked resource is sierra gas. + pub fn update_revert_gas_with_next_remaining_gas(&mut self, next_remaining_gas: GasAmount) { + self.sierra_gas_revert_tracker.update_with_next_remaining_gas( + *self + .tracked_resource_stack + .last() + .expect("Tracked resource stack should not be empty at this point."), + next_remaining_gas, + ); + } + pub fn versioned_constants(&self) -> &VersionedConstants { &self.tx_context.block_context.versioned_constants } @@ -406,14 +534,19 @@ pub fn execute_constructor_entry_point( remaining_gas: &mut u64, ) -> ConstructorEntryPointExecutionResult { // Ensure the class is declared (by reading it). - let contract_class = - state.get_compiled_contract_class(ctor_context.class_hash).map_err(|error| { - ConstructorEntryPointExecutionError::new(error.into(), &ctor_context, None) - })?; - let Some(constructor_selector) = contract_class.constructor_selector() else { + let compiled_class = state.get_compiled_class(ctor_context.class_hash).map_err(|error| { + ConstructorEntryPointExecutionError::new(error.into(), &ctor_context, None) + })?; + let Some(constructor_selector) = compiled_class.constructor_selector() else { // Contract has no constructor. - return handle_empty_constructor(&ctor_context, calldata, *remaining_gas) - .map_err(|error| ConstructorEntryPointExecutionError::new(error, &ctor_context, None)); + return handle_empty_constructor( + compiled_class, + context, + &ctor_context, + calldata, + *remaining_gas, + ) + .map_err(|error| ConstructorEntryPointExecutionError::new(error, &ctor_context, None)); }; let constructor_call = CallEntryPoint { @@ -434,6 +567,8 @@ pub fn execute_constructor_entry_point( } pub fn handle_empty_constructor( + compiled_class: RunnableCompiledClass, + context: &mut EntryPointExecutionContext, ctor_context: &ConstructorContext, calldata: Calldata, remaining_gas: u64, @@ -446,6 +581,14 @@ pub fn handle_empty_constructor( }); } + let current_tracked_resource = compiled_class.get_current_tracked_resource(context); + let initial_gas = if current_tracked_resource == TrackedResource::CairoSteps { + // Override the initial gas with a high value to be consistent with the behavior for the + // rest of the CairoSteps mode calls. + context.versioned_constants().infinite_gas_for_vm_mode() + } else { + remaining_gas + }; let empty_constructor_call_info = CallInfo { call: CallEntryPoint { class_hash: Some(ctor_context.class_hash), @@ -456,8 +599,9 @@ pub fn handle_empty_constructor( storage_address: ctor_context.storage_address, caller_address: ctor_context.caller_address, call_type: CallType::Call, - initial_gas: remaining_gas, + initial_gas, }, + tracked_resource: current_tracked_resource, ..Default::default() }; diff --git a/crates/blockifier/src/execution/entry_point_execution.rs b/crates/blockifier/src/execution/entry_point_execution.rs index 070e55be8a5..b11c540131a 100644 --- a/crates/blockifier/src/execution/entry_point_execution.rs +++ b/crates/blockifier/src/execution/entry_point_execution.rs @@ -1,5 +1,3 @@ -use std::collections::HashSet; - use cairo_vm::types::builtin_name::BuiltinName; use cairo_vm::types::layout_name::LayoutName; use cairo_vm::types::relocatable::{MaybeRelocatable, Relocatable}; @@ -7,18 +5,18 @@ use cairo_vm::vm::errors::cairo_run_errors::CairoRunError; use cairo_vm::vm::errors::memory_errors::MemoryError; use cairo_vm::vm::errors::vm_errors::VirtualMachineError; use cairo_vm::vm::runners::builtin_runner::BuiltinRunner; -use cairo_vm::vm::runners::cairo_runner::{CairoArg, CairoRunner}; +use cairo_vm::vm::runners::cairo_runner::{CairoArg, CairoRunner, ExecutionResources}; use cairo_vm::vm::security::verify_secure_runner; use num_traits::{ToPrimitive, Zero}; -use starknet_api::execution_resources::GasAmount; use starknet_types_core::felt::Felt; -use crate::execution::call_info::{CallExecution, CallInfo, ChargedResources, Retdata}; -use crate::execution::contract_class::{ContractClassV1, EntryPointV1, TrackedResource}; +use crate::blockifier_versioned_constants::GasCosts; +use crate::execution::call_info::{CallExecution, CallInfo, Retdata}; +use crate::execution::contract_class::{CompiledClassV1, EntryPointV1, TrackedResource}; use crate::execution::entry_point::{ - CallEntryPoint, EntryPointExecutionContext, EntryPointExecutionResult, + ExecutableCallEntryPoint, }; use crate::execution::errors::{EntryPointExecutionError, PostExecutionError, PreExecutionError}; use crate::execution::execution_utils::{ @@ -31,7 +29,6 @@ use crate::execution::execution_utils::{ }; use crate::execution::syscalls::hint_processor::SyscallHintProcessor; use crate::state::state_api::State; -use crate::versioned_constants::GasCosts; #[cfg(test)] #[path = "entry_point_execution_test.rs"] @@ -54,27 +51,48 @@ pub struct CallResult { pub gas_consumed: u64, } +pub enum ExecutionRunnerMode { + Starknet, + #[cfg(feature = "tracing")] + Tracing, +} + +impl ExecutionRunnerMode { + pub fn proof_mode(&self) -> bool { + match self { + ExecutionRunnerMode::Starknet => false, + #[cfg(feature = "tracing")] + ExecutionRunnerMode::Tracing => false, + } + } + + pub fn trace_enabled(&self) -> bool { + match self { + ExecutionRunnerMode::Starknet => false, + #[cfg(feature = "tracing")] + ExecutionRunnerMode::Tracing => true, + } + } +} + /// Executes a specific call to a contract entry point and returns its output. pub fn execute_entry_point_call( - call: CallEntryPoint, - contract_class: ContractClassV1, + call: ExecutableCallEntryPoint, + compiled_class: CompiledClassV1, state: &mut dyn State, context: &mut EntryPointExecutionContext, ) -> EntryPointExecutionResult { - // Fetch the class hash from `call`. - let class_hash = call.class_hash.ok_or(EntryPointExecutionError::InternalError( - "Class hash must not be None when executing an entry point.".into(), - ))?; - let tracked_resource = *context.tracked_resource_stack.last().expect("Unexpected empty tracked resource."); + // Extract information from the context, as it will be passed as a mutable reference. + let entry_point_initial_budget = context.gas_costs().base.entry_point_initial_budget; let VmExecutionContext { mut runner, mut syscall_handler, initial_syscall_ptr, entry_point, program_extra_data_length, - } = initialize_execution_context(call, &contract_class, state, context)?; + } = initialize_execution_context(call, &compiled_class, state, context)?; let args = prepare_call_arguments( &syscall_handler.base.call, @@ -82,23 +100,16 @@ pub fn execute_entry_point_call( initial_syscall_ptr, &mut syscall_handler.read_only_segments, &entry_point, + entry_point_initial_budget, )?; + let n_total_args = args.len(); // Execute. - let bytecode_length = contract_class.bytecode_length(); + let bytecode_length = compiled_class.bytecode_length(); let program_segment_size = bytecode_length + program_extra_data_length; run_entry_point(&mut runner, &mut syscall_handler, entry_point, args, program_segment_size)?; - // Collect the set PC values that were visited during the entry point execution. - register_visited_pcs( - &mut runner, - syscall_handler.base.state, - class_hash, - program_segment_size, - bytecode_length, - )?; - Ok(finalize_execution( runner, syscall_handler, @@ -108,51 +119,20 @@ pub fn execute_entry_point_call( )?) } -// Collects the set PC values that were visited during the entry point execution. -fn register_visited_pcs( - runner: &mut CairoRunner, - state: &mut dyn State, - class_hash: starknet_api::core::ClassHash, - program_segment_size: usize, - bytecode_length: usize, -) -> EntryPointExecutionResult<()> { - let mut class_visited_pcs = HashSet::new(); - // Relocate the trace, putting the program segment at address 1 and the execution segment right - // after it. - // TODO(lior): Avoid unnecessary relocation once the VM has a non-relocated `get_trace()` - // function. - runner.relocate_trace(&[1, 1 + program_segment_size])?; - for trace_entry in runner.relocated_trace.as_ref().expect("Relocated trace not found") { - let pc = trace_entry.pc; - if pc < 1 { - return Err(EntryPointExecutionError::InternalError(format!( - "Invalid PC value {pc} in trace." - ))); - } - let real_pc = pc - 1; - // Jumping to a PC that is not inside the bytecode is possible. For example, to obtain - // the builtin costs. Filter out these values. - if real_pc < bytecode_length { - class_visited_pcs.insert(real_pc); - } - } - state.add_visited_pcs(class_hash, &class_visited_pcs); - Ok(()) -} - -pub fn initialize_execution_context<'a>( - call: CallEntryPoint, - contract_class: &'a ContractClassV1, +pub fn initialize_execution_context_with_runner_mode<'a>( + call: ExecutableCallEntryPoint, + compiled_class: &'a CompiledClassV1, state: &'a mut dyn State, context: &'a mut EntryPointExecutionContext, + execution_runner_mode: ExecutionRunnerMode, ) -> Result, PreExecutionError> { - let entry_point = contract_class.get_entry_point(&call)?; + let entry_point = compiled_class.get_entry_point(&call.type_and_selector())?; // Instantiate Cairo runner. - let proof_mode = false; - let trace_enabled = true; + let proof_mode = execution_runner_mode.proof_mode(); + let trace_enabled = execution_runner_mode.trace_enabled(); let mut runner = CairoRunner::new( - &contract_class.0.program, + &compiled_class.0.program, LayoutName::starknet, proof_mode, trace_enabled, @@ -162,7 +142,7 @@ pub fn initialize_execution_context<'a>( let mut read_only_segments = ReadOnlySegments::default(); let program_extra_data_length = prepare_program_extra_data( &mut runner, - contract_class, + compiled_class, &mut read_only_segments, &context.versioned_constants().os_constants.gas_costs, )?; @@ -174,7 +154,7 @@ pub fn initialize_execution_context<'a>( context, initial_syscall_ptr, call, - &contract_class.hints, + &compiled_class.hints, read_only_segments, ); @@ -187,21 +167,36 @@ pub fn initialize_execution_context<'a>( }) } +pub fn initialize_execution_context<'a>( + call: ExecutableCallEntryPoint, + compiled_class: &'a CompiledClassV1, + state: &'a mut dyn State, + context: &'a mut EntryPointExecutionContext, +) -> Result, PreExecutionError> { + initialize_execution_context_with_runner_mode( + call, + compiled_class, + state, + context, + ExecutionRunnerMode::Starknet, + ) +} + fn prepare_program_extra_data( runner: &mut CairoRunner, - contract_class: &ContractClassV1, + contract_class: &CompiledClassV1, read_only_segments: &mut ReadOnlySegments, gas_costs: &GasCosts, ) -> Result { // Create the builtin cost segment, the builtin order should be the same as the price builtin // array in the os in compiled_class.cairo in load_compiled_class_facts. let builtin_price_array = [ - gas_costs.pedersen_gas_cost, - gas_costs.bitwise_builtin_gas_cost, - gas_costs.ecop_gas_cost, - gas_costs.poseidon_gas_cost, - gas_costs.add_mod_gas_cost, - gas_costs.mul_mod_gas_cost, + gas_costs.builtins.pedersen, + gas_costs.builtins.bitwise, + gas_costs.builtins.ecop, + gas_costs.builtins.poseidon, + gas_costs.builtins.add_mod, + gas_costs.builtins.mul_mod, ]; let data = builtin_price_array @@ -223,11 +218,12 @@ fn prepare_program_extra_data( } pub fn prepare_call_arguments( - call: &CallEntryPoint, + call: &ExecutableCallEntryPoint, runner: &mut CairoRunner, initial_syscall_ptr: Relocatable, read_only_segments: &mut ReadOnlySegments, entrypoint: &EntryPointV1, + entry_point_initial_budget: u64, ) -> Result { let mut args: Args = vec![]; @@ -256,8 +252,15 @@ pub fn prepare_call_arguments( } return Err(PreExecutionError::InvalidBuiltin(*builtin_name)); } + // Pre-charge entry point's initial budget to ensure sufficient gas for executing a minimal + // entry point code. When redepositing is used, the entry point is aware of this pre-charge + // and adjusts the gas counter accordingly if a smaller amount of gas is required. + let call_initial_gas = call + .initial_gas + .checked_sub(entry_point_initial_budget) + .ok_or(PreExecutionError::InsufficientEntryPointGas)?; // Push gas counter. - args.push(CairoArg::Single(MaybeRelocatable::from(Felt::from(call.initial_gas)))); + args.push(CairoArg::Single(MaybeRelocatable::from(Felt::from(call_initial_gas)))); // Push syscall ptr. args.push(CairoArg::Single(MaybeRelocatable::from(initial_syscall_ptr))); @@ -360,32 +363,6 @@ fn maybe_fill_holes( Ok(()) } -/// Calculates the total gas for fee in the current call + subtree. -#[allow(dead_code)] -fn to_gas_for_fee( - tracked_resource: &TrackedResource, - gas_consumed: u64, - inner_calls: &[CallInfo], -) -> GasAmount { - // The Sierra gas consumed in this specific call is `gas_consumed` - // (= total gas of self + subtree), minus the sum of all inner calls Sierra gas consumed. - // To compute the total Sierra gas to charge (of self + subtree), if the tracked resource is - // Sierra gas, we add this amount to the total gas to charge for in the subtree: - // gas_for_fee = gas_consumed - subtree_gas_consumed + subtree_gas_to_fee. - GasAmount(match tracked_resource { - // If the tracked resource is CairoSteps, then all tracked resources of all calls in - // the subtree are also CairoSteps. Thus, the total gas to charge in this subtree is zero. - TrackedResource::CairoSteps => 0, - TrackedResource::SierraGas => gas_consumed - .checked_sub( - inner_calls - .iter() - .map(|call| call.execution.gas_consumed - call.charged_resources.gas_for_fee.0) - .sum::(), - ) - .expect("gas_for_fee unexpectedly underflowed."), - }) -} pub fn finalize_execution( mut runner: CairoRunner, mut syscall_handler: SyscallHintProcessor<'_>, @@ -408,38 +385,38 @@ pub fn finalize_execution( runner.vm.mark_address_range_as_accessed(args_ptr, n_total_args)?; syscall_handler.read_only_segments.mark_as_accessed(&mut runner)?; - let call_result = get_call_result(&runner, &syscall_handler)?; - - // Take into account the resources of the current call, without inner calls. - // Has to happen after marking holes in segments as accessed. - let mut vm_resources_without_inner_calls = runner - .get_execution_resources() - .map_err(VirtualMachineError::RunnerError)? - .filter_unused_builtins(); - let versioned_constants = syscall_handler.base.context.versioned_constants(); - if versioned_constants.segment_arena_cells { - vm_resources_without_inner_calls - .builtin_instance_counter - .get_mut(&BuiltinName::segment_arena) - .map_or_else(|| {}, |val| *val *= SEGMENT_ARENA_BUILTIN_SIZE); - } - // Take into account the syscall resources of the current call. - vm_resources_without_inner_calls += - &versioned_constants.get_additional_os_syscall_resources(&syscall_handler.syscall_counter); + let call_result = get_call_result(&runner, &syscall_handler, &tracked_resource)?; + + let vm_resources_without_inner_calls = match tracked_resource { + TrackedResource::CairoSteps => { + // Take into account the resources of the current call, without inner calls. + // Has to happen after marking holes in segments as accessed. + let mut vm_resources_without_inner_calls = runner + .get_execution_resources() + .map_err(VirtualMachineError::RunnerError)? + .filter_unused_builtins(); + let versioned_constants = syscall_handler.base.context.versioned_constants(); + if versioned_constants.segment_arena_cells { + vm_resources_without_inner_calls + .builtin_instance_counter + .get_mut(&BuiltinName::segment_arena) + .map_or_else(|| {}, |val| *val *= SEGMENT_ARENA_BUILTIN_SIZE); + } + // Take into account the syscall resources of the current call. + vm_resources_without_inner_calls += &versioned_constants + .get_additional_os_syscall_resources(&syscall_handler.syscalls_usage); + vm_resources_without_inner_calls + } + TrackedResource::SierraGas => ExecutionResources::default(), + }; syscall_handler.finalize(); - let charged_resources_without_inner_calls = ChargedResources { - vm_resources: vm_resources_without_inner_calls, - // TODO(tzahi): Replace with a computed value. - gas_for_fee: GasAmount(0), - }; - let charged_resources = &charged_resources_without_inner_calls - + &CallInfo::summarize_charged_resources(syscall_handler.base.inner_calls.iter()); - + let vm_resources = &vm_resources_without_inner_calls + + &CallInfo::summarize_vm_resources(syscall_handler.base.inner_calls.iter()); let syscall_handler_base = syscall_handler.base; Ok(CallInfo { - call: syscall_handler_base.call, + call: syscall_handler_base.call.into(), execution: CallExecution { retdata: call_result.retdata, events: syscall_handler_base.events, @@ -449,17 +426,15 @@ pub fn finalize_execution( }, inner_calls: syscall_handler_base.inner_calls, tracked_resource, - charged_resources, - storage_read_values: syscall_handler_base.read_values, - accessed_storage_keys: syscall_handler_base.accessed_keys, - read_class_hash_values: syscall_handler_base.read_class_hash_values, - accessed_contract_addresses: syscall_handler_base.accessed_contract_addresses, + resources: vm_resources, + storage_access_tracker: syscall_handler_base.storage_access_tracker, }) } fn get_call_result( runner: &CairoRunner, syscall_handler: &SyscallHintProcessor<'_>, + tracked_resource: &TrackedResource, ) -> Result { let return_result = runner.vm.get_return_values(5)?; // Corresponds to the Cairo 1.0 enum: @@ -496,7 +471,11 @@ fn get_call_result( }); } - let gas_consumed = syscall_handler.base.call.initial_gas - gas; + let gas_consumed = match tracked_resource { + // Do not count Sierra gas in CairoSteps mode. + TrackedResource::CairoSteps => 0, + TrackedResource::SierraGas => syscall_handler.base.call.initial_gas - gas, + }; Ok(CallResult { failed, retdata: read_execution_retdata(runner, retdata_size, retdata_start)?, diff --git a/crates/blockifier/src/execution/entry_point_execution_test.rs b/crates/blockifier/src/execution/entry_point_execution_test.rs index 958bf8d837c..8d27d958055 100644 --- a/crates/blockifier/src/execution/entry_point_execution_test.rs +++ b/crates/blockifier/src/execution/entry_point_execution_test.rs @@ -1,55 +1,97 @@ +use std::sync::Arc; + +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; +use blockifier_test_utils::contracts::FeatureContract; +use cairo_vm::vm::runners::cairo_runner::ExecutionResources; +use rstest::rstest; +use starknet_api::abi::abi_utils::selector_from_name; use starknet_api::execution_resources::GasAmount; +use starknet_api::transaction::fields::Calldata; -use crate::execution::call_info::{CallExecution, CallInfo, ChargedResources}; +use crate::context::ChainInfo; +use crate::execution::call_info::CallInfo; use crate::execution::contract_class::TrackedResource; -use crate::execution::entry_point_execution::to_gas_for_fee; - -#[test] -/// Verifies that every call from the inner most to the outer has the expected gas_for_fee for the -/// following topology (marked as TrackedResource(gas_consumed)): -// Gas(8) -> Gas(3) -> VM(2) -> VM(1) -// \ -> VM(4) -// Expected values are 2 -> 1 -> 0 -> 0. -// \-> 0. -fn test_gas_for_fee() { - // First branch - 3 nested calls. - let mut inner_calls = vec![]; - for (tracked_resource, gas_consumed, expected_gas_for_fee) in [ - (TrackedResource::CairoSteps, 1, 0), - (TrackedResource::CairoSteps, 2, 0), - (TrackedResource::SierraGas, 3, 1), - ] { - assert_eq!( - to_gas_for_fee(&tracked_resource, gas_consumed, &inner_calls).0, - expected_gas_for_fee - ); - inner_calls = vec![CallInfo { - execution: CallExecution { gas_consumed, ..Default::default() }, - tracked_resource, - inner_calls, - charged_resources: ChargedResources { - gas_for_fee: GasAmount(expected_gas_for_fee), - ..Default::default() - }, - ..Default::default() - }]; +use crate::execution::entry_point::CallEntryPoint; +use crate::test_utils::initial_test_state::test_state; +use crate::test_utils::syscall::build_recurse_calldata; +use crate::test_utils::{trivial_external_entry_point_new, CompilerBasedVersion, BALANCE}; + +/// Asserts that the charged resources of a call is consistent with the inner calls in its subtree. +fn assert_charged_resource_as_expected_rec(call_info: &CallInfo) { + let inner_calls = &call_info.inner_calls; + let mut children_vm_resources = ExecutionResources::default(); + let mut children_gas = GasAmount(0); + for child_call_info in inner_calls.iter() { + let gas_consumed = GasAmount(child_call_info.execution.gas_consumed); + let vm_resources = &child_call_info.resources; + children_vm_resources += vm_resources; + children_gas += gas_consumed; + } + + let gas_consumed = GasAmount(call_info.execution.gas_consumed); + let vm_resources = &call_info.resources; + + match call_info.tracked_resource { + TrackedResource::SierraGas => { + assert_eq!(vm_resources, &children_vm_resources); + assert!(gas_consumed > children_gas) + } + TrackedResource::CairoSteps => { + assert_eq!(gas_consumed, children_gas); + assert!(vm_resources.n_steps > children_vm_resources.n_steps) + } } - // Second branch - 1 call. - let (tracked_resource, gas_consumed, expected_gas_for_fee) = - (TrackedResource::CairoSteps, 4, 0); - assert_eq!(to_gas_for_fee(&tracked_resource, gas_consumed, &[]).0, expected_gas_for_fee); - - inner_calls.push(CallInfo { - execution: CallExecution { gas_consumed, ..Default::default() }, - tracked_resource, - charged_resources: ChargedResources { - gas_for_fee: GasAmount(expected_gas_for_fee), - ..Default::default() - }, - ..Default::default() - }); - - // Outer call. - assert_eq!(to_gas_for_fee(&TrackedResource::SierraGas, 8, &inner_calls).0, 2); + for child_call_info in inner_calls.iter() { + assert_charged_resource_as_expected_rec(child_call_info); + } +} + +#[rstest] +fn test_charged_resources_computation( + #[values( + CompilerBasedVersion::CairoVersion(CairoVersion::Cairo0), + CompilerBasedVersion::OldCairo1 + )] + third_contract_version: CompilerBasedVersion, + #[values( + CompilerBasedVersion::CairoVersion(CairoVersion::Cairo0), + CompilerBasedVersion::OldCairo1 + )] + fourth_contract_version: CompilerBasedVersion, + #[values( + CompilerBasedVersion::CairoVersion(CairoVersion::Cairo0), + CompilerBasedVersion::OldCairo1 + )] + second_branch_contract_version: CompilerBasedVersion, +) { + let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1(RunnableCairo1::Casm)); + let chain_info = &ChainInfo::create_for_testing(); + let contracts = CompilerBasedVersion::iter().map(|version| version.get_test_contract()); + let mut state = test_state( + chain_info, + BALANCE, + &contracts.map(|contract| (contract, 1)).collect::>(), + ); + let call_versions = [ + CompilerBasedVersion::CairoVersion(CairoVersion::Cairo1(RunnableCairo1::Casm)), + CompilerBasedVersion::CairoVersion(CairoVersion::Cairo1(RunnableCairo1::Casm)), + third_contract_version, + fourth_contract_version, + ]; + + let first_calldata = build_recurse_calldata(&call_versions); + let second_calldata = build_recurse_calldata(&[second_branch_contract_version]); + let outer_calldata = Calldata(Arc::new( + (*first_calldata.0).iter().copied().chain((*second_calldata.0).iter().copied()).collect(), + )); + let call_contract_selector = selector_from_name("test_call_two_contracts"); + let entry_point_call = CallEntryPoint { + entry_point_selector: call_contract_selector, + calldata: outer_calldata, + ..trivial_external_entry_point_new(test_contract) + }; + let call_info = entry_point_call.execute_directly(&mut state).unwrap(); + + assert_charged_resource_as_expected_rec(&call_info); } diff --git a/crates/blockifier/src/execution/entry_point_test.rs b/crates/blockifier/src/execution/entry_point_test.rs index a3079aeca03..1137a35720d 100644 --- a/crates/blockifier/src/execution/entry_point_test.rs +++ b/crates/blockifier/src/execution/entry_point_test.rs @@ -1,5 +1,7 @@ use std::collections::HashSet; +use blockifier_test_utils::cairo_versions::CairoVersion; +use blockifier_test_utils::contracts::FeatureContract; use cairo_vm::types::builtin_name::BuiltinName; use num_bigint::BigInt; use pretty_assertions::assert_eq; @@ -9,16 +11,15 @@ use starknet_api::execution_utils::format_panic_data; use starknet_api::transaction::fields::{Calldata, Fee}; use starknet_api::{calldata, felt, storage_key}; +use crate::blockifier_versioned_constants::VersionedConstants; use crate::context::ChainInfo; use crate::execution::call_info::{CallExecution, CallInfo}; use crate::execution::entry_point::CallEntryPoint; use crate::retdata; use crate::state::cached_state::CachedState; -use crate::test_utils::contracts::FeatureContract; use crate::test_utils::dict_state_reader::DictStateReader; use crate::test_utils::initial_test_state::test_state; -use crate::test_utils::{trivial_external_entry_point_new, CairoVersion, BALANCE}; -use crate::versioned_constants::VersionedConstants; +use crate::test_utils::{trivial_external_entry_point_new, BALANCE}; #[test] fn test_call_info_iteration() { @@ -200,7 +201,7 @@ fn run_security_test( entry_point_selector: selector_from_name(entry_point_name), calldata, storage_address: security_contract.get_instance_address(0), - initial_gas: versioned_constants.default_initial_gas_cost(), + initial_gas: versioned_constants.infinite_gas_for_vm_mode(), ..Default::default() }; let error = match entry_point_call.execute_directly(state) { @@ -491,9 +492,9 @@ fn test_storage_related_members() { ..trivial_external_entry_point_new(test_contract) }; let actual_call_info = entry_point_call.execute_directly(&mut state).unwrap(); - assert_eq!(actual_call_info.storage_read_values, vec![felt!(39_u8)]); + assert_eq!(actual_call_info.storage_access_tracker.storage_read_values, vec![felt!(39_u8)]); assert_eq!( - actual_call_info.accessed_storage_keys, + actual_call_info.storage_access_tracker.accessed_storage_keys, HashSet::from([get_storage_var_address("number_map", &[felt!(1_u8)])]) ); @@ -508,13 +509,16 @@ fn test_storage_related_members() { ..trivial_external_entry_point_new(test_contract) }; let actual_call_info = entry_point_call.execute_directly(&mut state).unwrap(); - assert_eq!(actual_call_info.storage_read_values, vec![value]); - assert_eq!(actual_call_info.accessed_storage_keys, HashSet::from([storage_key!(key_int)])); + assert_eq!(actual_call_info.storage_access_tracker.storage_read_values, vec![value]); + assert_eq!( + actual_call_info.storage_access_tracker.accessed_storage_keys, + HashSet::from([storage_key!(key_int)]) + ); } #[test] -fn test_cairo1_entry_point_segment_arena() { - let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1); +fn test_old_cairo1_entry_point_segment_arena() { + let test_contract = FeatureContract::CairoStepsTestContract; let chain_info = &ChainInfo::create_for_testing(); let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); let calldata = calldata![]; @@ -525,12 +529,8 @@ fn test_cairo1_entry_point_segment_arena() { }; assert_eq!( - entry_point_call - .execute_directly(&mut state) - .unwrap() - .charged_resources - .vm_resources - .builtin_instance_counter[&BuiltinName::segment_arena], + entry_point_call.execute_directly(&mut state).unwrap().resources.builtin_instance_counter + [&BuiltinName::segment_arena], // Note: the number of segment_arena instances should not depend on the compiler or VM // version. Do not manually fix this then when upgrading them - it might be a bug. 2 diff --git a/crates/blockifier/src/execution/errors.rs b/crates/blockifier/src/execution/errors.rs index 6dc1b6f9bdb..8345db57ccd 100644 --- a/crates/blockifier/src/execution/errors.rs +++ b/crates/blockifier/src/execution/errors.rs @@ -50,6 +50,11 @@ pub enum PreExecutionError { UninitializedStorageAddress(ContractAddress), #[error("Called builtins: {0:?} are unsupported in a Cairo0 contract")] UnsupportedCairo0Builtin(HashSet), + #[error( + "Insufficient entry point initial gas, must be greater than the entry point initial \ + budget." + )] + InsufficientEntryPointGas, } impl From for PreExecutionError { diff --git a/crates/blockifier/src/execution/execution_utils.rs b/crates/blockifier/src/execution/execution_utils.rs index d2c0b9aeaf3..7dfc38fa694 100644 --- a/crates/blockifier/src/execution/execution_utils.rs +++ b/crates/blockifier/src/execution/execution_utils.rs @@ -22,14 +22,14 @@ use starknet_api::transaction::fields::Calldata; use starknet_types_core::felt::Felt; use crate::execution::call_info::{CallExecution, CallInfo, Retdata}; -use crate::execution::contract_class::{RunnableContractClass, TrackedResource}; +use crate::execution::contract_class::{RunnableCompiledClass, TrackedResource}; use crate::execution::entry_point::{ execute_constructor_entry_point, - CallEntryPoint, ConstructorContext, ConstructorEntryPointExecutionResult, EntryPointExecutionContext, EntryPointExecutionResult, + ExecutableCallEntryPoint, }; use crate::execution::errors::{ ConstructorEntryPointExecutionError, @@ -40,7 +40,7 @@ use crate::execution::errors::{ #[cfg(feature = "cairo_native")] use crate::execution::native::entry_point_execution as native_entry_point_execution; use crate::execution::stack_trace::{extract_trailing_cairo1_revert_trace, Cairo1RevertHeader}; -use crate::execution::syscalls::hint_processor::ENTRYPOINT_NOT_FOUND_ERROR; +use crate::execution::syscalls::hint_processor::{ENTRYPOINT_NOT_FOUND_ERROR, OUT_OF_GAS_ERROR}; use crate::execution::{deprecated_entry_point_execution, entry_point_execution}; use crate::state::errors::StateError; use crate::state::state_api::State; @@ -51,39 +51,23 @@ pub const SEGMENT_ARENA_BUILTIN_SIZE: usize = 3; /// A wrapper for execute_entry_point_call that performs pre and post-processing. pub fn execute_entry_point_call_wrapper( - mut call: CallEntryPoint, - contract_class: RunnableContractClass, + mut call: ExecutableCallEntryPoint, + compiled_class: RunnableCompiledClass, state: &mut dyn State, context: &mut EntryPointExecutionContext, remaining_gas: &mut u64, ) -> EntryPointExecutionResult { - let contract_tracked_resource = contract_class.tracked_resource( - &context.versioned_constants().min_compiler_version_for_sierra_gas, - context.tx_context.tx_info.gas_mode(), - ); + let current_tracked_resource = compiled_class.get_current_tracked_resource(context); + if current_tracked_resource == TrackedResource::CairoSteps { + // Override the initial gas with a high value so it won't limit the run. + call.initial_gas = context.versioned_constants().infinite_gas_for_vm_mode(); + } + let orig_call = call.clone(); // Note: no return statements (explicit or implicit) should be added between the push and the // pop commands. - - // Once we ran with CairoSteps, we will continue to run using it for all nested calls. - match context.tracked_resource_stack.last() { - Some(TrackedResource::CairoSteps) => { - context.tracked_resource_stack.push(TrackedResource::CairoSteps) - } - Some(TrackedResource::SierraGas) => { - if contract_tracked_resource == TrackedResource::CairoSteps { - // Switching from SierraGas to CairoSteps: override initial_gas with a high value so - // it won't limit the run. - call.initial_gas = context.versioned_constants().default_initial_gas_cost(); - }; - context.tracked_resource_stack.push(contract_tracked_resource) - } - None => context.tracked_resource_stack.push(contract_tracked_resource), - }; - - let orig_call = call.clone(); - let res = execute_entry_point_call(call, contract_class, state, context); - let current_tracked_resource = - context.tracked_resource_stack.pop().expect("Unexpected empty tracked resource."); + context.tracked_resource_stack.push(current_tracked_resource); + let res = execute_entry_point_call(call, compiled_class, state, context); + context.tracked_resource_stack.pop().expect("Unexpected empty tracked resource."); match res { Ok(call_info) => { @@ -99,58 +83,65 @@ pub fn execute_entry_point_call_wrapper( update_remaining_gas(remaining_gas, &call_info); Ok(call_info) } - Err(EntryPointExecutionError::PreExecutionError( - PreExecutionError::EntryPointNotFound(_) - | PreExecutionError::NoEntryPointOfTypeFound(_), - )) if context.versioned_constants().enable_reverts => Ok(CallInfo { - call: orig_call, - execution: CallExecution { - retdata: Retdata(vec![Felt::from_hex(ENTRYPOINT_NOT_FOUND_ERROR).unwrap()]), - failed: true, - gas_consumed: 0, - ..CallExecution::default() - }, - tracked_resource: current_tracked_resource, - ..CallInfo::default() - }), + Err(EntryPointExecutionError::PreExecutionError(err)) + if context.versioned_constants().enable_reverts => + { + let error_code = match err { + PreExecutionError::EntryPointNotFound(_) + | PreExecutionError::NoEntryPointOfTypeFound(_) => ENTRYPOINT_NOT_FOUND_ERROR, + PreExecutionError::InsufficientEntryPointGas => OUT_OF_GAS_ERROR, + _ => return Err(err.into()), + }; + Ok(CallInfo { + call: orig_call.into(), + execution: CallExecution { + retdata: Retdata(vec![Felt::from_hex(error_code).unwrap()]), + failed: true, + gas_consumed: 0, + ..CallExecution::default() + }, + tracked_resource: current_tracked_resource, + ..CallInfo::default() + }) + } Err(err) => Err(err), } } /// Executes a specific call to a contract entry point and returns its output. pub fn execute_entry_point_call( - call: CallEntryPoint, - contract_class: RunnableContractClass, + call: ExecutableCallEntryPoint, + compiled_class: RunnableCompiledClass, state: &mut dyn State, context: &mut EntryPointExecutionContext, ) -> EntryPointExecutionResult { - match contract_class { - RunnableContractClass::V0(contract_class) => { + match compiled_class { + RunnableCompiledClass::V0(compiled_class) => { deprecated_entry_point_execution::execute_entry_point_call( call, - contract_class, + compiled_class, state, context, ) } - RunnableContractClass::V1(contract_class) => { - entry_point_execution::execute_entry_point_call(call, contract_class, state, context) + RunnableCompiledClass::V1(compiled_class) => { + entry_point_execution::execute_entry_point_call(call, compiled_class, state, context) } #[cfg(feature = "cairo_native")] - RunnableContractClass::V1Native(contract_class) => { + RunnableCompiledClass::V1Native(compiled_class) => { if context.tracked_resource_stack.last() == Some(&TrackedResource::CairoSteps) { // We cannot run native with cairo steps as the tracked resources (it's a vm // resouorce). entry_point_execution::execute_entry_point_call( call, - contract_class.casm(), + compiled_class.casm(), state, context, ) } else { native_entry_point_execution::execute_entry_point_call( call, - contract_class, + compiled_class, state, context, ) diff --git a/crates/blockifier/src/execution/native/contract_class.rs b/crates/blockifier/src/execution/native/contract_class.rs index 2e85feb4f2f..d757538d96d 100644 --- a/crates/blockifier/src/execution/native/contract_class.rs +++ b/crates/blockifier/src/execution/native/contract_class.rs @@ -4,64 +4,64 @@ use std::sync::Arc; use cairo_native::executor::AotContractExecutor; use starknet_api::core::EntryPointSelector; -use crate::execution::contract_class::{ContractClassV1, EntryPointV1}; -use crate::execution::entry_point::CallEntryPoint; +use crate::execution::contract_class::{CompiledClassV1, EntryPointV1}; +use crate::execution::entry_point::EntryPointTypeAndSelector; use crate::execution::errors::PreExecutionError; #[derive(Clone, Debug, PartialEq, Eq)] -pub struct NativeContractClassV1(pub Arc); -impl Deref for NativeContractClassV1 { - type Target = NativeContractClassV1Inner; +pub struct NativeCompiledClassV1(pub Arc); +impl Deref for NativeCompiledClassV1 { + type Target = NativeCompiledClassV1Inner; fn deref(&self) -> &Self::Target { &self.0 } } -impl NativeContractClassV1 { +impl NativeCompiledClassV1 { pub(crate) fn constructor_selector(&self) -> Option { self.casm.constructor_selector() } - /// Initialize a compiled contract class for native. + /// Initialize a compiled class for native. /// /// executor must be derived from sierra_program which in turn must be derived from /// sierra_contract_class. - pub fn new(executor: AotContractExecutor, casm: ContractClassV1) -> NativeContractClassV1 { - let contract = NativeContractClassV1Inner::new(executor, casm); + pub fn new(executor: AotContractExecutor, casm: CompiledClassV1) -> NativeCompiledClassV1 { + let contract = NativeCompiledClassV1Inner::new(executor, casm); Self(Arc::new(contract)) } pub fn get_entry_point( &self, - call: &CallEntryPoint, + entry_point: &EntryPointTypeAndSelector, ) -> Result { - self.casm.get_entry_point(call) + self.casm.get_entry_point(entry_point) } - pub fn casm(&self) -> ContractClassV1 { + pub fn casm(&self) -> CompiledClassV1 { self.casm.clone() } } #[derive(Debug)] -pub struct NativeContractClassV1Inner { +pub struct NativeCompiledClassV1Inner { pub executor: AotContractExecutor, - casm: ContractClassV1, + casm: CompiledClassV1, } -impl NativeContractClassV1Inner { - fn new(executor: AotContractExecutor, casm: ContractClassV1) -> Self { - NativeContractClassV1Inner { executor, casm } +impl NativeCompiledClassV1Inner { + fn new(executor: AotContractExecutor, casm: CompiledClassV1) -> Self { + NativeCompiledClassV1Inner { executor, casm } } } -// The location where the compiled contract is loaded into memory will not +// The location where the compiled class is loaded into memory will not // be the same therefore we exclude it from the comparison. -impl PartialEq for NativeContractClassV1Inner { +impl PartialEq for NativeCompiledClassV1Inner { fn eq(&self, other: &Self) -> bool { self.casm == other.casm } } -impl Eq for NativeContractClassV1Inner {} +impl Eq for NativeCompiledClassV1Inner {} diff --git a/crates/blockifier/src/execution/native/entry_point_execution.rs b/crates/blockifier/src/execution/native/entry_point_execution.rs index 34b3460c678..b419b204029 100644 --- a/crates/blockifier/src/execution/native/entry_point_execution.rs +++ b/crates/blockifier/src/execution/native/entry_point_execution.rs @@ -1,28 +1,26 @@ use cairo_native::execution_result::ContractExecutionResult; use cairo_native::utils::BuiltinCosts; -use cairo_vm::vm::runners::cairo_runner::ExecutionResources; -use starknet_api::execution_resources::GasAmount; -use crate::execution::call_info::{CallExecution, CallInfo, ChargedResources, Retdata}; +use crate::execution::call_info::{CallExecution, CallInfo, Retdata}; use crate::execution::contract_class::TrackedResource; use crate::execution::entry_point::{ - CallEntryPoint, EntryPointExecutionContext, EntryPointExecutionResult, + ExecutableCallEntryPoint, }; -use crate::execution::errors::{EntryPointExecutionError, PostExecutionError}; -use crate::execution::native::contract_class::NativeContractClassV1; +use crate::execution::errors::{EntryPointExecutionError, PostExecutionError, PreExecutionError}; +use crate::execution::native::contract_class::NativeCompiledClassV1; use crate::execution::native::syscall_handler::NativeSyscallHandler; use crate::state::state_api::State; // todo(rodrigo): add an `entry point not found` test for Native pub fn execute_entry_point_call( - call: CallEntryPoint, - contract_class: NativeContractClassV1, + call: ExecutableCallEntryPoint, + compiled_class: NativeCompiledClassV1, state: &mut dyn State, context: &mut EntryPointExecutionContext, ) -> EntryPointExecutionResult { - let entry_point = contract_class.get_entry_point(&call)?; + let entry_point = compiled_class.get_entry_point(&call.type_and_selector())?; let mut syscall_handler: NativeSyscallHandler<'_> = NativeSyscallHandler::new(call, state, context); @@ -31,21 +29,33 @@ pub fn execute_entry_point_call( let builtin_costs = BuiltinCosts { // todo(rodrigo): Unsure of what value `const` means, but 1 is the right value. r#const: 1, - pedersen: gas_costs.pedersen_gas_cost, - bitwise: gas_costs.bitwise_builtin_gas_cost, - ecop: gas_costs.ecop_gas_cost, - poseidon: gas_costs.poseidon_gas_cost, - add_mod: gas_costs.add_mod_gas_cost, - mul_mod: gas_costs.mul_mod_gas_cost, + pedersen: gas_costs.builtins.pedersen, + bitwise: gas_costs.builtins.bitwise, + ecop: gas_costs.builtins.ecop, + poseidon: gas_costs.builtins.poseidon, + add_mod: gas_costs.builtins.add_mod, + mul_mod: gas_costs.builtins.mul_mod, }; - let execution_result = contract_class.executor.run( + // Pre-charge entry point's initial budget to ensure sufficient gas for executing a minimal + // entry point code. When redepositing is used, the entry point is aware of this pre-charge + // and adjusts the gas counter accordingly if a smaller amount of gas is required. + let initial_budget = syscall_handler.base.context.gas_costs().base.entry_point_initial_budget; + let call_initial_gas = syscall_handler + .base + .call + .initial_gas + .checked_sub(initial_budget) + .ok_or(PreExecutionError::InsufficientEntryPointGas)?; + + let execution_result = compiled_class.executor.run( entry_point.selector.0, &syscall_handler.base.call.calldata.0.clone(), - syscall_handler.base.call.initial_gas, + call_initial_gas, Some(builtin_costs), &mut syscall_handler, ); + syscall_handler.finalize(); let call_result = execution_result.map_err(EntryPointExecutionError::NativeUnexpectedError)?; @@ -74,17 +84,10 @@ fn create_callinfo( } let gas_consumed = syscall_handler.base.call.initial_gas - remaining_gas; - - let charged_resources_without_inner_calls = ChargedResources { - vm_resources: ExecutionResources::default(), - // TODO(tzahi): Replace with a computed value. - gas_for_fee: GasAmount(0), - }; - let charged_resources = &charged_resources_without_inner_calls - + &CallInfo::summarize_charged_resources(syscall_handler.base.inner_calls.iter()); + let vm_resources = CallInfo::summarize_vm_resources(syscall_handler.base.inner_calls.iter()); Ok(CallInfo { - call: syscall_handler.base.call, + call: syscall_handler.base.call.into(), execution: CallExecution { retdata: Retdata(call_result.return_values), events: syscall_handler.base.events, @@ -92,12 +95,9 @@ fn create_callinfo( failed: call_result.failure_flag, gas_consumed, }, - charged_resources, + resources: vm_resources, inner_calls: syscall_handler.base.inner_calls, - storage_read_values: syscall_handler.base.read_values, - accessed_storage_keys: syscall_handler.base.accessed_keys, - accessed_contract_addresses: syscall_handler.base.accessed_contract_addresses, - read_class_hash_values: syscall_handler.base.read_class_hash_values, + storage_access_tracker: syscall_handler.base.storage_access_tracker, tracked_resource: TrackedResource::SierraGas, }) } diff --git a/crates/blockifier/src/execution/native/syscall_handler.rs b/crates/blockifier/src/execution/native/syscall_handler.rs index 5412a62d797..23bc1e0ddf1 100644 --- a/crates/blockifier/src/execution/native/syscall_handler.rs +++ b/crates/blockifier/src/execution/native/syscall_handler.rs @@ -19,27 +19,32 @@ use cairo_native::starknet::{ use num_bigint::BigUint; use starknet_api::contract_class::EntryPointType; use starknet_api::core::{ClassHash, ContractAddress, EntryPointSelector, EthAddress}; +use starknet_api::execution_resources::GasAmount; use starknet_api::state::StorageKey; use starknet_api::transaction::fields::{Calldata, ContractAddressSalt}; use starknet_api::transaction::{EventContent, EventData, EventKey, L2ToL1Payload}; use starknet_types_core::felt::Felt; +use crate::blockifier_versioned_constants::GasCosts; use crate::execution::call_info::{MessageToL1, Retdata}; use crate::execution::common_hints::ExecutionMode; -use crate::execution::entry_point::{CallEntryPoint, CallType, EntryPointExecutionContext}; +use crate::execution::entry_point::{ + CallEntryPoint, + CallType, + EntryPointExecutionContext, + ExecutableCallEntryPoint, +}; use crate::execution::errors::EntryPointExecutionError; use crate::execution::native::utils::{calculate_resource_bounds, default_tx_v2_info}; use crate::execution::secp; -use crate::execution::syscalls::hint_processor::{ - SyscallExecutionError, - INVALID_INPUT_LENGTH_ERROR, - OUT_OF_GAS_ERROR, -}; +use crate::execution::syscalls::hint_processor::{SyscallExecutionError, OUT_OF_GAS_ERROR}; use crate::execution::syscalls::syscall_base::SyscallHandlerBase; use crate::state::state_api::State; use crate::transaction::objects::TransactionInfo; -use crate::versioned_constants::GasCosts; +use crate::utils::u64_from_usize; +pub const CALL_CONTRACT_SELECTOR_NAME: &str = "call_contract"; +pub const LIBRARY_CALL_SELECTOR_NAME: &str = "library_call"; pub struct NativeSyscallHandler<'state> { pub base: Box>, @@ -49,7 +54,7 @@ pub struct NativeSyscallHandler<'state> { impl<'state> NativeSyscallHandler<'state> { pub fn new( - call: CallEntryPoint, + call: ExecutableCallEntryPoint, state: &'state mut dyn State, context: &'state mut EntryPointExecutionContext, ) -> NativeSyscallHandler<'state> { @@ -59,19 +64,6 @@ impl<'state> NativeSyscallHandler<'state> { } } - fn execute_inner_call( - &mut self, - entry_point: CallEntryPoint, - remaining_gas: &mut u64, - ) -> SyscallResult { - let raw_retdata = self - .base - .execute_inner_call(entry_point, remaining_gas) - .map_err(|e| self.handle_error(remaining_gas, e))?; - - Ok(Retdata(raw_retdata)) - } - pub fn gas_costs(&self) -> &GasCosts { self.base.context.gas_costs() } @@ -81,15 +73,15 @@ impl<'state> NativeSyscallHandler<'state> { fn pre_execute_syscall( &mut self, remaining_gas: &mut u64, - syscall_gas_cost: u64, + total_gas_cost: u64, ) -> SyscallResult<()> { if self.unrecoverable_error.is_some() { - // An unrecoverable error was found in a previous syscall, we return immediatly to + // An unrecoverable error was found in a previous syscall, we return immediately to // accelerate the end of the execution. The returned data is not important return Err(vec![]); } // Refund `SYSCALL_BASE_GAS_COST` as it was pre-charged. - let required_gas = syscall_gas_cost - self.gas_costs().syscall_base_gas_cost; + let required_gas = total_gas_cost - self.gas_costs().base.syscall_base_gas_cost; if *remaining_gas < required_gas { // Out of gas failure. @@ -101,6 +93,20 @@ impl<'state> NativeSyscallHandler<'state> { *remaining_gas -= required_gas; + // To support sierra gas charge for blockifier revert flow, we track the remaining gas left + // before executing a syscall if the current tracked resource is gas. + // 1. If the syscall does not run Cairo code (i.e. not library call, not call contract, and + // not a deploy), any failure will not run in the OS, so no need to charge - the value + // before entering the callback is good enough to charge. + // 2. If the syscall runs Cairo code, but the tracked resource is steps (and not gas), the + // additional charge of reverted cairo steps will cover the inner cost, and the outer + // cost we track here will be the additional reverted gas. + // 3. If the syscall runs Cairo code and the tracked resource is gas, either the inner + // failure will be a Cairo1 revert (and the gas consumed on the call info will override + // the current tracked value), or we will pass through another syscall before failing - + // and by induction (we will reach this point again), the gas will be charged correctly. + self.base.context.update_revert_gas_with_next_remaining_gas(GasAmount(*remaining_gas)); + Ok(()) } @@ -120,7 +126,7 @@ impl<'state> NativeSyscallHandler<'state> { } match error { - SyscallExecutionError::SyscallError { error_data } => error_data, + SyscallExecutionError::Revert { error_data } => error_data, error => { assert!( self.unrecoverable_error.is_none(), @@ -133,10 +139,40 @@ impl<'state> NativeSyscallHandler<'state> { } } + fn execute_inner_call( + &mut self, + entry_point: CallEntryPoint, + remaining_gas: &mut u64, + class_hash: ClassHash, + error_wrapper_fn: impl Fn( + SyscallExecutionError, + ClassHash, + ContractAddress, + EntryPointSelector, + ) -> SyscallExecutionError, + ) -> SyscallResult { + let entry_point_clone = entry_point.clone(); + let raw_data = self.base.execute_inner_call(entry_point, remaining_gas).map_err(|e| { + self.handle_error( + remaining_gas, + match e { + SyscallExecutionError::Revert { .. } => e, + _ => error_wrapper_fn( + e, + class_hash, + entry_point_clone.storage_address, + entry_point_clone.entry_point_selector, + ), + }, + ) + })?; + Ok(Retdata(raw_data)) + } + fn get_tx_info_v1(&self) -> TxInfo { let tx_info = &self.base.context.tx_context.tx_info; TxInfo { - version: tx_info.version().0, + version: self.base.tx_version_for_get_execution_info().0, account_contract_address: Felt::from(tx_info.sender_address()), max_fee: tx_info.max_fee_for_execution_info_syscall().0, signature: tx_info.signature().0, @@ -150,38 +186,23 @@ impl<'state> NativeSyscallHandler<'state> { } fn get_block_info(&self) -> BlockInfo { - let block_info = &self.base.context.tx_context.block_context.block_info; - if self.base.context.execution_mode == ExecutionMode::Validate { - let versioned_constants = self.base.context.versioned_constants(); - let block_number = block_info.block_number.0; - let block_timestamp = block_info.block_timestamp.0; - // Round down to the nearest multiple of validate_block_number_rounding. - let validate_block_number_rounding = - versioned_constants.get_validate_block_number_rounding(); - let rounded_block_number = - (block_number / validate_block_number_rounding) * validate_block_number_rounding; - // Round down to the nearest multiple of validate_timestamp_rounding. - let validate_timestamp_rounding = versioned_constants.get_validate_timestamp_rounding(); - let rounded_timestamp = - (block_timestamp / validate_timestamp_rounding) * validate_timestamp_rounding; - BlockInfo { - block_number: rounded_block_number, - block_timestamp: rounded_timestamp, - sequencer_address: Felt::ZERO, - } - } else { - BlockInfo { - block_number: block_info.block_number.0, - block_timestamp: block_info.block_timestamp.0, - sequencer_address: Felt::from(block_info.sequencer_address), + let block_info = match self.base.context.execution_mode { + ExecutionMode::Execute => self.base.context.tx_context.block_context.block_info(), + ExecutionMode::Validate => { + &self.base.context.tx_context.block_context.block_info_for_validate() } + }; + BlockInfo { + block_number: block_info.block_number.0, + block_timestamp: block_info.block_timestamp.0, + sequencer_address: Felt::from(block_info.sequencer_address), } } fn get_tx_info_v2(&self) -> SyscallResult { let tx_info = &self.base.context.tx_context.tx_info; let native_tx_info = TxV2Info { - version: tx_info.version().0, + version: self.base.tx_version_for_get_execution_info().0, account_contract_address: Felt::from(tx_info.sender_address()), max_fee: tx_info.max_fee_for_execution_info_syscall().0, signature: tx_info.signature().0, @@ -197,7 +218,10 @@ impl<'state> NativeSyscallHandler<'state> { match tx_info { TransactionInfo::Deprecated(_) => Ok(native_tx_info), TransactionInfo::Current(context) => Ok(TxV2Info { - resource_bounds: calculate_resource_bounds(context)?, + resource_bounds: calculate_resource_bounds( + context, + self.base.should_exclude_l1_data_gas(), + ), tip: context.tip.0.into(), paymaster_data: context.paymaster_data.0.clone(), nonce_data_availability_mode: context.nonce_data_availability_mode.into(), @@ -212,13 +236,16 @@ impl<'state> NativeSyscallHandler<'state> { } } -impl<'state> StarknetSyscallHandler for &mut NativeSyscallHandler<'state> { +impl StarknetSyscallHandler for &mut NativeSyscallHandler<'_> { fn get_block_hash( &mut self, block_number: u64, remaining_gas: &mut u64, ) -> SyscallResult { - self.pre_execute_syscall(remaining_gas, self.gas_costs().get_block_hash_gas_cost)?; + self.pre_execute_syscall( + remaining_gas, + self.gas_costs().syscalls.get_block_hash.base_syscall_cost(), + )?; match self.base.get_block_hash(block_number) { Ok(value) => Ok(value), @@ -227,7 +254,10 @@ impl<'state> StarknetSyscallHandler for &mut NativeSyscallHandler<'state> { } fn get_execution_info(&mut self, remaining_gas: &mut u64) -> SyscallResult { - self.pre_execute_syscall(remaining_gas, self.gas_costs().get_execution_info_gas_cost)?; + self.pre_execute_syscall( + remaining_gas, + self.gas_costs().syscalls.get_execution_info.base_syscall_cost(), + )?; Ok(ExecutionInfo { block_info: self.get_block_info(), @@ -243,7 +273,10 @@ impl<'state> StarknetSyscallHandler for &mut NativeSyscallHandler<'state> { contract_address: Felt, remaining_gas: &mut u64, ) -> SyscallResult { - self.pre_execute_syscall(remaining_gas, self.gas_costs().get_class_hash_at_gas_cost)?; + self.pre_execute_syscall( + remaining_gas, + self.gas_costs().syscalls.get_class_hash_at.base_syscall_cost(), + )?; let request = ContractAddress::try_from(contract_address) .map_err(|err| self.handle_error(remaining_gas, err.into()))?; @@ -255,7 +288,10 @@ impl<'state> StarknetSyscallHandler for &mut NativeSyscallHandler<'state> { } fn get_execution_info_v2(&mut self, remaining_gas: &mut u64) -> SyscallResult { - self.pre_execute_syscall(remaining_gas, self.gas_costs().get_execution_info_gas_cost)?; + self.pre_execute_syscall( + remaining_gas, + self.gas_costs().syscalls.get_execution_info.base_syscall_cost(), + )?; Ok(ExecutionInfoV2 { block_info: self.get_block_info(), @@ -274,7 +310,11 @@ impl<'state> StarknetSyscallHandler for &mut NativeSyscallHandler<'state> { deploy_from_zero: bool, remaining_gas: &mut u64, ) -> SyscallResult<(Felt, Vec)> { - self.pre_execute_syscall(remaining_gas, self.gas_costs().deploy_gas_cost)?; + // The cost of deploying a contract is the base cost plus the linear cost of the calldata + // len. + let total_gas_cost = + self.gas_costs().syscalls.deploy.get_syscall_cost(u64_from_usize(calldata.len())); + self.pre_execute_syscall(remaining_gas, total_gas_cost)?; let (deployed_contract_address, call_info) = self .base @@ -293,7 +333,10 @@ impl<'state> StarknetSyscallHandler for &mut NativeSyscallHandler<'state> { Ok((Felt::from(deployed_contract_address), constructor_retdata)) } fn replace_class(&mut self, class_hash: Felt, remaining_gas: &mut u64) -> SyscallResult<()> { - self.pre_execute_syscall(remaining_gas, self.gas_costs().replace_class_gas_cost)?; + self.pre_execute_syscall( + remaining_gas, + self.gas_costs().syscalls.replace_class.base_syscall_cost(), + )?; self.base .replace_class(ClassHash(class_hash)) @@ -308,17 +351,22 @@ impl<'state> StarknetSyscallHandler for &mut NativeSyscallHandler<'state> { calldata: &[Felt], remaining_gas: &mut u64, ) -> SyscallResult> { - self.pre_execute_syscall(remaining_gas, self.gas_costs().library_call_gas_cost)?; + self.pre_execute_syscall( + remaining_gas, + self.gas_costs().syscalls.library_call.base_syscall_cost(), + )?; let class_hash = ClassHash(class_hash); let wrapper_calldata = Calldata(Arc::new(calldata.to_vec())); + let selector = EntryPointSelector(function_selector); + let entry_point = CallEntryPoint { class_hash: Some(class_hash), code_address: None, entry_point_type: EntryPointType::External, - entry_point_selector: EntryPointSelector(function_selector), + entry_point_selector: selector, calldata: wrapper_calldata, // The call context remains the same in a library call. storage_address: self.base.call.storage_address, @@ -327,7 +375,17 @@ impl<'state> StarknetSyscallHandler for &mut NativeSyscallHandler<'state> { initial_gas: *remaining_gas, }; - Ok(self.execute_inner_call(entry_point, remaining_gas)?.0) + let error_wrapper_function = + |e: SyscallExecutionError, + class_hash: ClassHash, + storage_address: ContractAddress, + selector: EntryPointSelector| { + e.as_lib_call_execution_error(class_hash, storage_address, selector) + }; + + Ok(self + .execute_inner_call(entry_point, remaining_gas, class_hash, error_wrapper_function)? + .0) } fn call_contract( @@ -337,10 +395,19 @@ impl<'state> StarknetSyscallHandler for &mut NativeSyscallHandler<'state> { calldata: &[Felt], remaining_gas: &mut u64, ) -> SyscallResult> { - self.pre_execute_syscall(remaining_gas, self.gas_costs().call_contract_gas_cost)?; + self.pre_execute_syscall( + remaining_gas, + self.gas_costs().syscalls.call_contract.base_syscall_cost(), + )?; let contract_address = ContractAddress::try_from(address) .map_err(|error| self.handle_error(remaining_gas, error.into()))?; + + let class_hash = self + .base + .state + .get_class_hash_at(contract_address) + .map_err(|e| self.handle_error(remaining_gas, e.into()))?; if self.base.context.execution_mode == ExecutionMode::Validate && self.base.call.storage_address != contract_address { @@ -360,12 +427,22 @@ impl<'state> StarknetSyscallHandler for &mut NativeSyscallHandler<'state> { entry_point_selector: EntryPointSelector(entry_point_selector), calldata: wrapper_calldata, storage_address: contract_address, - caller_address: self.base.call.caller_address, + caller_address: self.base.call.storage_address, call_type: CallType::Call, initial_gas: *remaining_gas, }; - Ok(self.execute_inner_call(entry_point, remaining_gas)?.0) + let error_wrapper_function = + |e: SyscallExecutionError, + class_hash: ClassHash, + storage_address: ContractAddress, + selector: EntryPointSelector| { + e.as_call_contract_execution_error(class_hash, storage_address, selector) + }; + + Ok(self + .execute_inner_call(entry_point, remaining_gas, class_hash, error_wrapper_function)? + .0) } fn storage_read( @@ -374,7 +451,10 @@ impl<'state> StarknetSyscallHandler for &mut NativeSyscallHandler<'state> { address: Felt, remaining_gas: &mut u64, ) -> SyscallResult { - self.pre_execute_syscall(remaining_gas, self.gas_costs().storage_read_gas_cost)?; + self.pre_execute_syscall( + remaining_gas, + self.gas_costs().syscalls.storage_read.base_syscall_cost(), + )?; if address_domain != 0 { let address_domain = Felt::from(address_domain); @@ -396,7 +476,10 @@ impl<'state> StarknetSyscallHandler for &mut NativeSyscallHandler<'state> { value: Felt, remaining_gas: &mut u64, ) -> SyscallResult<()> { - self.pre_execute_syscall(remaining_gas, self.gas_costs().storage_write_gas_cost)?; + self.pre_execute_syscall( + remaining_gas, + self.gas_costs().syscalls.storage_write.base_syscall_cost(), + )?; if address_domain != 0 { let address_domain = Felt::from(address_domain); @@ -417,7 +500,10 @@ impl<'state> StarknetSyscallHandler for &mut NativeSyscallHandler<'state> { data: &[Felt], remaining_gas: &mut u64, ) -> SyscallResult<()> { - self.pre_execute_syscall(remaining_gas, self.gas_costs().emit_event_gas_cost)?; + self.pre_execute_syscall( + remaining_gas, + self.gas_costs().syscalls.emit_event.base_syscall_cost(), + )?; let event = EventContent { keys: keys.iter().copied().map(EventKey).collect(), @@ -434,7 +520,10 @@ impl<'state> StarknetSyscallHandler for &mut NativeSyscallHandler<'state> { payload: &[Felt], remaining_gas: &mut u64, ) -> SyscallResult<()> { - self.pre_execute_syscall(remaining_gas, self.gas_costs().send_message_to_l1_gas_cost)?; + self.pre_execute_syscall( + remaining_gas, + self.gas_costs().syscalls.send_message_to_l1.base_syscall_cost(), + )?; let to_address = EthAddress::try_from(to_address) .map_err(|err| self.handle_error(remaining_gas, err.into()))?; @@ -444,49 +533,18 @@ impl<'state> StarknetSyscallHandler for &mut NativeSyscallHandler<'state> { } fn keccak(&mut self, input: &[u64], remaining_gas: &mut u64) -> SyscallResult { - self.pre_execute_syscall(remaining_gas, self.gas_costs().keccak_gas_cost)?; - - const KECCAK_FULL_RATE_IN_WORDS: usize = 17; - - let input_length = input.len(); - let (n_rounds, remainder) = num_integer::div_rem(input_length, KECCAK_FULL_RATE_IN_WORDS); - - if remainder != 0 { - return Err(self.handle_error( - remaining_gas, - SyscallExecutionError::SyscallError { - error_data: vec![Felt::from_hex(INVALID_INPUT_LENGTH_ERROR).unwrap()], - }, - )); - } - - // TODO(Ori, 1/2/2024): Write an indicative expect message explaining why the conversion - // works. - let n_rounds = u64::try_from(n_rounds).expect("Failed to convert usize to u64."); - let gas_cost = n_rounds * self.gas_costs().keccak_round_cost_gas_cost; - - if gas_cost > *remaining_gas { - return Err(self.handle_error( - remaining_gas, - SyscallExecutionError::SyscallError { - error_data: vec![Felt::from_hex(OUT_OF_GAS_ERROR).unwrap()], - }, - )); - } - *remaining_gas -= gas_cost; + self.pre_execute_syscall( + remaining_gas, + self.gas_costs().syscalls.keccak.base_syscall_cost(), + )?; - let mut state = [0u64; 25]; - for chunk in input.chunks(KECCAK_FULL_RATE_IN_WORDS) { - for (i, val) in chunk.iter().enumerate() { - state[i] ^= val; - } - keccak::f1600(&mut state) + match self.base.keccak(input, remaining_gas) { + Ok((state, _n_rounds)) => Ok(U256 { + hi: u128::from(state[2]) | (u128::from(state[3]) << 64), + lo: u128::from(state[0]) | (u128::from(state[1]) << 64), + }), + Err(err) => Err(self.handle_error(remaining_gas, err)), } - - Ok(U256 { - hi: u128::from(state[2]) | (u128::from(state[3]) << 64), - lo: u128::from(state[0]) | (u128::from(state[1]) << 64), - }) } fn secp256k1_new( @@ -495,7 +553,10 @@ impl<'state> StarknetSyscallHandler for &mut NativeSyscallHandler<'state> { y: U256, remaining_gas: &mut u64, ) -> SyscallResult> { - self.pre_execute_syscall(remaining_gas, self.gas_costs().secp256k1_new_gas_cost)?; + self.pre_execute_syscall( + remaining_gas, + self.gas_costs().syscalls.secp256k1_new.base_syscall_cost(), + )?; Secp256Point::new(x, y) .map(|op| op.map(|p| p.into())) @@ -508,7 +569,10 @@ impl<'state> StarknetSyscallHandler for &mut NativeSyscallHandler<'state> { p1: Secp256k1Point, remaining_gas: &mut u64, ) -> SyscallResult { - self.pre_execute_syscall(remaining_gas, self.gas_costs().secp256k1_add_gas_cost)?; + self.pre_execute_syscall( + remaining_gas, + self.gas_costs().syscalls.secp256k1_add.base_syscall_cost(), + )?; Ok(Secp256Point::add(p0.into(), p1.into()).into()) } @@ -519,7 +583,10 @@ impl<'state> StarknetSyscallHandler for &mut NativeSyscallHandler<'state> { m: U256, remaining_gas: &mut u64, ) -> SyscallResult { - self.pre_execute_syscall(remaining_gas, self.gas_costs().secp256k1_mul_gas_cost)?; + self.pre_execute_syscall( + remaining_gas, + self.gas_costs().syscalls.secp256k1_mul.base_syscall_cost(), + )?; Ok(Secp256Point::mul(p.into(), m).into()) } @@ -532,7 +599,7 @@ impl<'state> StarknetSyscallHandler for &mut NativeSyscallHandler<'state> { ) -> SyscallResult> { self.pre_execute_syscall( remaining_gas, - self.gas_costs().secp256k1_get_point_from_x_gas_cost, + self.gas_costs().syscalls.secp256k1_get_point_from_x.base_syscall_cost(), )?; Secp256Point::get_point_from_x(x, y_parity) @@ -545,7 +612,10 @@ impl<'state> StarknetSyscallHandler for &mut NativeSyscallHandler<'state> { p: Secp256k1Point, remaining_gas: &mut u64, ) -> SyscallResult<(U256, U256)> { - self.pre_execute_syscall(remaining_gas, self.gas_costs().secp256k1_get_xy_gas_cost)?; + self.pre_execute_syscall( + remaining_gas, + self.gas_costs().syscalls.secp256k1_get_xy.base_syscall_cost(), + )?; Ok((p.x, p.y)) } @@ -556,7 +626,10 @@ impl<'state> StarknetSyscallHandler for &mut NativeSyscallHandler<'state> { y: U256, remaining_gas: &mut u64, ) -> SyscallResult> { - self.pre_execute_syscall(remaining_gas, self.gas_costs().secp256r1_new_gas_cost)?; + self.pre_execute_syscall( + remaining_gas, + self.gas_costs().syscalls.secp256r1_new.base_syscall_cost(), + )?; Secp256Point::new(x, y) .map(|option| option.map(|p| p.into())) @@ -569,7 +642,10 @@ impl<'state> StarknetSyscallHandler for &mut NativeSyscallHandler<'state> { p1: Secp256r1Point, remaining_gas: &mut u64, ) -> SyscallResult { - self.pre_execute_syscall(remaining_gas, self.gas_costs().secp256r1_add_gas_cost)?; + self.pre_execute_syscall( + remaining_gas, + self.gas_costs().syscalls.secp256r1_add.base_syscall_cost(), + )?; Ok(Secp256Point::add(p0.into(), p1.into()).into()) } @@ -579,7 +655,10 @@ impl<'state> StarknetSyscallHandler for &mut NativeSyscallHandler<'state> { m: U256, remaining_gas: &mut u64, ) -> SyscallResult { - self.pre_execute_syscall(remaining_gas, self.gas_costs().secp256r1_mul_gas_cost)?; + self.pre_execute_syscall( + remaining_gas, + self.gas_costs().syscalls.secp256r1_mul.base_syscall_cost(), + )?; Ok(Secp256Point::mul(p.into(), m).into()) } @@ -592,7 +671,7 @@ impl<'state> StarknetSyscallHandler for &mut NativeSyscallHandler<'state> { ) -> SyscallResult> { self.pre_execute_syscall( remaining_gas, - self.gas_costs().secp256r1_get_point_from_x_gas_cost, + self.gas_costs().syscalls.secp256r1_get_point_from_x.base_syscall_cost(), )?; Secp256Point::get_point_from_x(x, y_parity) @@ -605,7 +684,10 @@ impl<'state> StarknetSyscallHandler for &mut NativeSyscallHandler<'state> { p: Secp256r1Point, remaining_gas: &mut u64, ) -> SyscallResult<(U256, U256)> { - self.pre_execute_syscall(remaining_gas, self.gas_costs().secp256r1_get_xy_gas_cost)?; + self.pre_execute_syscall( + remaining_gas, + self.gas_costs().syscalls.secp256r1_get_xy.base_syscall_cost(), + )?; Ok((p.x, p.y)) } @@ -616,7 +698,10 @@ impl<'state> StarknetSyscallHandler for &mut NativeSyscallHandler<'state> { current_block: &[u32; 16], remaining_gas: &mut u64, ) -> SyscallResult<()> { - self.pre_execute_syscall(remaining_gas, self.gas_costs().sha256_process_block_gas_cost)?; + self.pre_execute_syscall( + remaining_gas, + self.gas_costs().syscalls.sha256_process_block.base_syscall_cost(), + )?; let data_as_bytes = sha2::digest::generic_array::GenericArray::from_exact_iter( current_block.iter().flat_map(|x| x.to_be_bytes()), diff --git a/crates/blockifier/src/execution/native/utils.rs b/crates/blockifier/src/execution/native/utils.rs index c566c9e8d5c..4be60ec7a38 100644 --- a/crates/blockifier/src/execution/native/utils.rs +++ b/crates/blockifier/src/execution/native/utils.rs @@ -1,7 +1,7 @@ use cairo_lang_starknet_classes::contract_class::ContractEntryPoint; -use cairo_native::starknet::{ResourceBounds, SyscallResult, TxV2Info}; +use cairo_native::starknet::{ResourceBounds, TxV2Info}; use starknet_api::core::EntryPointSelector; -use starknet_api::transaction::fields::{Resource, ValidResourceBounds}; +use starknet_api::transaction::fields::{AllResourceBounds, Resource, ValidResourceBounds}; use starknet_types_core::felt::Felt; use crate::transaction::objects::CurrentTransactionInfo; @@ -45,40 +45,33 @@ pub fn default_tx_v2_info() -> TxV2Info { pub fn calculate_resource_bounds( tx_info: &CurrentTransactionInfo, -) -> SyscallResult> { - Ok(match tx_info.resource_bounds { - ValidResourceBounds::L1Gas(l1_bounds) => { - vec![ - ResourceBounds { - resource: Felt::from_hex(Resource::L1Gas.to_hex()).unwrap(), - max_amount: l1_bounds.max_amount.0, - max_price_per_unit: l1_bounds.max_price_per_unit.0, - }, - ResourceBounds { - resource: Felt::from_hex(Resource::L2Gas.to_hex()).unwrap(), - max_amount: 0, - max_price_per_unit: 0, - }, - ] - } - ValidResourceBounds::AllResources(all_bounds) => { - vec![ - ResourceBounds { - resource: Felt::from_hex(Resource::L1Gas.to_hex()).unwrap(), - max_amount: all_bounds.l1_gas.max_amount.0, - max_price_per_unit: all_bounds.l1_gas.max_price_per_unit.0, - }, - ResourceBounds { - resource: Felt::from_hex(Resource::L2Gas.to_hex()).unwrap(), - max_amount: all_bounds.l2_gas.max_amount.0, - max_price_per_unit: all_bounds.l2_gas.max_price_per_unit.0, - }, - ResourceBounds { + exclude_l1_data_gas: bool, +) -> Vec { + let l1_gas_bounds = tx_info.resource_bounds.get_l1_bounds(); + let l2_gas_bounds = tx_info.resource_bounds.get_l2_bounds(); + let mut res = vec![ + ResourceBounds { + resource: Felt::from_hex(Resource::L1Gas.to_hex()).unwrap(), + max_amount: l1_gas_bounds.max_amount.0, + max_price_per_unit: l1_gas_bounds.max_price_per_unit.0, + }, + ResourceBounds { + resource: Felt::from_hex(Resource::L2Gas.to_hex()).unwrap(), + max_amount: l2_gas_bounds.max_amount.0, + max_price_per_unit: l2_gas_bounds.max_price_per_unit.0, + }, + ]; + match tx_info.resource_bounds { + ValidResourceBounds::L1Gas(_) => return res, + ValidResourceBounds::AllResources(AllResourceBounds { l1_data_gas, .. }) => { + if !exclude_l1_data_gas { + res.push(ResourceBounds { resource: Felt::from_hex(Resource::L1DataGas.to_hex()).unwrap(), - max_amount: all_bounds.l1_data_gas.max_amount.0, - max_price_per_unit: all_bounds.l1_data_gas.max_price_per_unit.0, - }, - ] + max_amount: l1_data_gas.max_amount.0, + max_price_per_unit: l1_data_gas.max_price_per_unit.0, + }) + } } - }) + } + res } diff --git a/crates/blockifier/src/execution/secp.rs b/crates/blockifier/src/execution/secp.rs index f96bb11633f..976bbfacb18 100644 --- a/crates/blockifier/src/execution/secp.rs +++ b/crates/blockifier/src/execution/secp.rs @@ -47,7 +47,7 @@ where if bounds.iter().any(|p| **p >= modulus) { let error = match Felt::from_hex(INVALID_ARGUMENT) { - Ok(err) => SyscallExecutionError::SyscallError { error_data: vec![err] }, + Ok(err) => SyscallExecutionError::Revert { error_data: vec![err] }, Err(err) => SyscallExecutionError::from(err), }; diff --git a/crates/blockifier/src/execution/stack_trace.rs b/crates/blockifier/src/execution/stack_trace.rs index 1b90caad70d..f05a023b167 100644 --- a/crates/blockifier/src/execution/stack_trace.rs +++ b/crates/blockifier/src/execution/stack_trace.rs @@ -709,6 +709,10 @@ fn extract_entry_point_execution_error_into_stack_trace( EntryPointExecutionError::CairoRunError(cairo_run_error) => { extract_cairo_run_error_into_stack_trace(error_stack, depth, cairo_run_error) } + #[cfg(feature = "cairo_native")] + EntryPointExecutionError::NativeUnrecoverableError(error) => { + extract_syscall_execution_error_into_stack_trace(error_stack, depth, error) + } EntryPointExecutionError::ExecutionFailed { error_trace } => { error_stack.push(error_trace.clone().into()) } diff --git a/crates/blockifier/src/execution/stack_trace_test.rs b/crates/blockifier/src/execution/stack_trace_test.rs index 80e77478a6e..8998495a1fb 100644 --- a/crates/blockifier/src/execution/stack_trace_test.rs +++ b/crates/blockifier/src/execution/stack_trace_test.rs @@ -1,7 +1,11 @@ use assert_matches::assert_matches; +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; +use blockifier_test_utils::calldata::create_calldata; +use blockifier_test_utils::contracts::FeatureContract; use pretty_assertions::assert_eq; use regex::Regex; use rstest::rstest; +use rstest_reuse::apply; use starknet_api::abi::abi_utils::selector_from_name; use starknet_api::abi::constants::CONSTRUCTOR_ENTRY_POINT_NAME; use starknet_api::core::{ @@ -42,14 +46,16 @@ use crate::execution::stack_trace::{ TRACE_LENGTH_CAP, }; use crate::execution::syscalls::hint_processor::ENTRYPOINT_FAILED_ERROR; -use crate::test_utils::contracts::FeatureContract; +use crate::test_utils::contracts::FeatureContractTrait; use crate::test_utils::initial_test_state::{fund_account, test_state}; -use crate::test_utils::{create_calldata, CairoVersion, BALANCE}; +use crate::test_utils::test_templates::cairo_version; +use crate::test_utils::BALANCE; +use crate::transaction::account_transaction::{AccountTransaction, ExecutionFlags}; use crate::transaction::test_utils::{ - account_invoke_tx, block_context, create_account_tx_for_validate_test_nonce_0, default_all_resource_bounds, + invoke_tx_with_default_flags, run_invoke_tx, FaultyAccountTxCreatorArgs, INVALID, @@ -144,10 +150,10 @@ An ASSERT_EQ instruction failed: 1 != 0. } #[rstest] -fn test_stack_trace( - block_context: BlockContext, - #[values(CairoVersion::Cairo0, CairoVersion::Cairo1)] cairo_version: CairoVersion, -) { +#[case(CairoVersion::Cairo0)] +#[case(CairoVersion::Cairo1(RunnableCairo1::Casm))] +#[cfg_attr(feature = "cairo_native", case(CairoVersion::Cairo1(RunnableCairo1::Native)))] +fn test_stack_trace(block_context: BlockContext, #[case] cairo_version: CairoVersion) { let chain_info = ChainInfo::create_for_testing(); let account = FeatureContract::AccountWithoutValidations(cairo_version); let test_contract = FeatureContract::TestContract(cairo_version); @@ -185,40 +191,43 @@ fn test_stack_trace( ) .unwrap_err(); - // Fetch PC locations from the compiled contract to compute the expected PC locations in the - // traceback. Computation is not robust, but as long as the cairo function itself is not edited, - // this computation should be stable. - let account_entry_point_offset = - account.get_entry_point_offset(selector_from_name(EXECUTE_ENTRY_POINT_NAME)); let execute_selector_felt = selector_from_name(EXECUTE_ENTRY_POINT_NAME).0; let external_entry_point_selector_felt = selector_from_name(call_contract_function_name).0; - let entry_point_offset = - test_contract.get_entry_point_offset(selector_from_name(call_contract_function_name)); - // Relative offsets of the test_call_contract entry point and the inner call. - let call_location = entry_point_offset.0 + 14; - let entry_point_location = entry_point_offset.0 - 3; - // Relative offsets of the account contract. - let account_call_location = account_entry_point_offset.0 + 18; - let account_entry_point_location = account_entry_point_offset.0 - 8; - - let expected_trace_cairo0 = format!( - "Transaction execution has failed: + let expected_trace = match cairo_version { + CairoVersion::Cairo0 => { + // Fetch PC locations from the compiled contract to compute the expected PC locations in + // the traceback. Computation is not robust, but as long as the cairo + // function itself is not edited, this computation should be stable. + let account_entry_point_offset = + account.get_entry_point_offset(selector_from_name(EXECUTE_ENTRY_POINT_NAME)); + let entry_point_offset = test_contract + .get_entry_point_offset(selector_from_name(call_contract_function_name)); + // Relative offsets of the test_call_contract entry point and the inner call. + let call_location = entry_point_offset.0 + 14; + let entry_point_location = entry_point_offset.0 - 3; + // Relative offsets of the account contract. + let account_call_location = account_entry_point_offset.0 + 18; + let account_entry_point_location = account_entry_point_offset.0 - 8; + format!( + "Transaction execution has failed: 0: Error in the called contract (contract address: {account_address_felt:#064x}, class hash: \ - {account_contract_hash:#064x}, selector: {execute_selector_felt:#064x}): + {account_contract_hash:#064x}, selector: {execute_selector_felt:#064x}): Error at pc=0:7: Cairo traceback (most recent call last): Unknown location (pc=0:{account_call_location}) Unknown location (pc=0:{account_entry_point_location}) 1: Error in the called contract (contract address: {test_contract_address_felt:#064x}, class hash: \ - {test_contract_hash:#064x}, selector: {external_entry_point_selector_felt:#064x}): + {test_contract_hash:#064x}, selector: \ + {external_entry_point_selector_felt:#064x}): Error at pc=0:37: Cairo traceback (most recent call last): Unknown location (pc=0:{call_location}) Unknown location (pc=0:{entry_point_location}) 2: Error in the called contract (contract address: {test_contract_address_2_felt:#064x}, class \ - hash: {test_contract_hash:#064x}, selector: {inner_entry_point_selector_felt:#064x}): + hash: {test_contract_hash:#064x}, selector: \ + {inner_entry_point_selector_felt:#064x}): Error message: You shall not pass! Error at pc=0:1294: Cairo traceback (most recent call last): @@ -226,28 +235,24 @@ Unknown location (pc=0:1298) An ASSERT_EQ instruction failed: 1 != 0. " - ); - - let expected_trace_cairo1 = format!( - "Transaction execution has failed: + ) + .to_string() + } + CairoVersion::Cairo1(_) => format!( + "Transaction execution has failed: 0: Error in the called contract (contract address: {account_address_felt:#064x}, class hash: \ - {account_contract_hash:#064x}, selector: {execute_selector_felt:#064x}): + {account_contract_hash:#064x}, selector: {execute_selector_felt:#064x}): Execution failed. Failure reason: Error in contract (contract address: {account_address_felt:#064x}, class hash: \ - {account_contract_hash:#064x}, selector: {execute_selector_felt:#064x}): + {account_contract_hash:#064x}, selector: {execute_selector_felt:#064x}): Error in contract (contract address: {test_contract_address_felt:#064x}, class hash: \ - {test_contract_hash:#064x}, selector: {external_entry_point_selector_felt:#064x}): + {test_contract_hash:#064x}, selector: {external_entry_point_selector_felt:#064x}): Error in contract (contract address: {test_contract_address_2_felt:#064x}, class hash: \ - {test_contract_hash:#064x}, selector: {inner_entry_point_selector_felt:#064x}): + {test_contract_hash:#064x}, selector: {inner_entry_point_selector_felt:#064x}): 0x6661696c ('fail'). " - ); - - let expected_trace = match cairo_version { - CairoVersion::Cairo0 => expected_trace_cairo0, - CairoVersion::Cairo1 => expected_trace_cairo1, - #[cfg(feature = "cairo_native")] - CairoVersion::Native => panic!("Cairo Native is not yet supported"), + ) + .to_string(), }; assert_eq!(tx_execution_error.to_string(), expected_trace); @@ -256,8 +261,16 @@ Error in contract (contract address: {test_contract_address_2_felt:#064x}, class #[rstest] #[case(CairoVersion::Cairo0, "invoke_call_chain", "Couldn't compute operand op0. Unknown value for memory cell 1:37", (1191_u16, 1237_u16))] #[case(CairoVersion::Cairo0, "fail", "An ASSERT_EQ instruction failed: 1 != 0.", (1294_u16, 1245_u16))] -#[case(CairoVersion::Cairo1, "invoke_call_chain", "0x4469766973696f6e2062792030 ('Division by 0')", (0_u16, 0_u16))] -#[case(CairoVersion::Cairo1, "fail", "0x6661696c ('fail')", (0_u16, 0_u16))] +#[case(CairoVersion::Cairo1(RunnableCairo1::Casm), "invoke_call_chain", "0x4469766973696f6e2062792030 ('Division by 0')", (0_u16, 0_u16))] +#[case(CairoVersion::Cairo1(RunnableCairo1::Casm), "fail", "0x6661696c ('fail')", (0_u16, 0_u16))] +#[cfg_attr( + feature = "cairo_native", + case(CairoVersion::Cairo1(RunnableCairo1::Native), "invoke_call_chain", "0x4469766973696f6e2062792030 ('Division by 0')", (0_u16, 0_u16)) +)] +#[cfg_attr( + feature = "cairo_native", + case(CairoVersion::Cairo1(RunnableCairo1::Native), "fail", "0x6661696c ('fail')", (0_u16, 0_u16)) +)] fn test_trace_callchain_ends_with_regular_call( block_context: BlockContext, #[case] cairo_version: CairoVersion, @@ -311,13 +324,14 @@ fn test_trace_callchain_ends_with_regular_call( ) .unwrap_err(); - let account_entry_point_offset = - account_contract.get_entry_point_offset(selector_from_name(EXECUTE_ENTRY_POINT_NAME)); - let entry_point_offset = test_contract.get_entry_point_offset(invoke_call_chain_selector); let execute_selector_felt = selector_from_name(EXECUTE_ENTRY_POINT_NAME).0; let expected_trace = match cairo_version { CairoVersion::Cairo0 => { + let account_entry_point_offset = account_contract + .get_entry_point_offset(selector_from_name(EXECUTE_ENTRY_POINT_NAME)); + let entry_point_offset = + test_contract.get_entry_point_offset(invoke_call_chain_selector); let call_location = entry_point_offset.0 + 12; let entry_point_location = entry_point_offset.0 - 61; // Relative offsets of the account contract. @@ -352,7 +366,7 @@ Unknown location (pc=0:{expected_pc1}) " ) } - CairoVersion::Cairo1 => { + CairoVersion::Cairo1(_) => { format!( "Transaction execution has failed: 0: Error in the called contract (contract address: {account_address_felt:#064x}, class hash: \ @@ -368,10 +382,6 @@ Error in contract (contract address: {contract_address_felt:#064x}, class hash: " ) } - #[cfg(feature = "cairo_native")] - CairoVersion::Native => { - todo!("Cairo Native is not yet supported here") - } }; assert_eq!(tx_execution_error.to_string(), expected_trace); @@ -382,10 +392,26 @@ Error in contract (contract address: {contract_address_felt:#064x}, class hash: #[case(CairoVersion::Cairo0, "invoke_call_chain", "Couldn't compute operand op0. Unknown value for memory cell 1:23", 1_u8, 1_u8, (49_u16, 1221_u16, 1191_u16, 1276_u16))] #[case(CairoVersion::Cairo0, "fail", "An ASSERT_EQ instruction failed: 1 != 0.", 0_u8, 0_u8, (37_u16, 1203_u16, 1294_u16, 1298_u16))] #[case(CairoVersion::Cairo0, "fail", "An ASSERT_EQ instruction failed: 1 != 0.", 0_u8, 1_u8, (49_u16, 1221_u16, 1294_u16, 1298_u16))] -#[case(CairoVersion::Cairo1, "invoke_call_chain", "0x4469766973696f6e2062792030 ('Division by 0')", 1_u8, 0_u8, (9631_u16, 9631_u16, 0_u16, 0_u16))] -#[case(CairoVersion::Cairo1, "invoke_call_chain", "0x4469766973696f6e2062792030 ('Division by 0')", 1_u8, 1_u8, (9631_u16, 9700_u16, 0_u16, 0_u16))] -#[case(CairoVersion::Cairo1, "fail", "0x6661696c ('fail')", 0_u8, 0_u8, (9631_u16, 9631_u16, 0_u16, 0_u16))] -#[case(CairoVersion::Cairo1, "fail", "0x6661696c ('fail')", 0_u8, 1_u8, (9631_u16, 9700_u16, 0_u16, 0_u16))] +#[case(CairoVersion::Cairo1(RunnableCairo1::Casm), "invoke_call_chain", "0x4469766973696f6e2062792030 ('Division by 0')", 1_u8, 0_u8, (9631_u16, 9631_u16, 0_u16, 0_u16))] +#[case(CairoVersion::Cairo1(RunnableCairo1::Casm), "invoke_call_chain", "0x4469766973696f6e2062792030 ('Division by 0')", 1_u8, 1_u8, (9631_u16, 9700_u16, 0_u16, 0_u16))] +#[case(CairoVersion::Cairo1(RunnableCairo1::Casm), "fail", "0x6661696c ('fail')", 0_u8, 0_u8, (9631_u16, 9631_u16, 0_u16, 0_u16))] +#[case(CairoVersion::Cairo1(RunnableCairo1::Casm), "fail", "0x6661696c ('fail')", 0_u8, 1_u8, (9631_u16, 9700_u16, 0_u16, 0_u16))] +#[cfg_attr( + feature = "cairo_native", + case(CairoVersion::Cairo1(RunnableCairo1::Native), "invoke_call_chain", "0x4469766973696f6e2062792030 ('Division by 0')", 1_u8, 0_u8, (9631_u16, 9631_u16, 0_u16, 0_u16)) +)] +#[cfg_attr( + feature = "cairo_native", + case(CairoVersion::Cairo1(RunnableCairo1::Native), "invoke_call_chain", "0x4469766973696f6e2062792030 ('Division by 0')", 1_u8, 1_u8, (9631_u16, 9700_u16, 0_u16, 0_u16)) +)] +#[cfg_attr( + feature = "cairo_native", + case(CairoVersion::Cairo1(RunnableCairo1::Native), "fail", "0x6661696c ('fail')", 0_u8, 0_u8, (9631_u16, 9631_u16, 0_u16, 0_u16)) +)] +#[cfg_attr( + feature = "cairo_native", + case(CairoVersion::Cairo1(RunnableCairo1::Native), "fail", "0x6661696c ('fail')", 0_u8, 1_u8, (9631_u16, 9700_u16, 0_u16, 0_u16)) +)] fn test_trace_call_chain_with_syscalls( block_context: BlockContext, #[case] cairo_version: CairoVersion, @@ -452,9 +478,6 @@ fn test_trace_call_chain_with_syscalls( ) .unwrap_err(); - let account_entry_point_offset = - account_contract.get_entry_point_offset(selector_from_name(EXECUTE_ENTRY_POINT_NAME)); - let entry_point_offset = test_contract.get_entry_point_offset(invoke_call_chain_selector); let execute_selector_felt = selector_from_name(EXECUTE_ENTRY_POINT_NAME).0; let last_call_preamble = if call_type == 0 { @@ -471,6 +494,10 @@ fn test_trace_call_chain_with_syscalls( let expected_trace = match cairo_version { CairoVersion::Cairo0 => { + let account_entry_point_offset = account_contract + .get_entry_point_offset(selector_from_name(EXECUTE_ENTRY_POINT_NAME)); + let entry_point_offset = + test_contract.get_entry_point_offset(invoke_call_chain_selector); let call_location = entry_point_offset.0 + 12; let entry_point_location = entry_point_offset.0 - 61; // Relative offsets of the account contract. @@ -509,7 +536,7 @@ Unknown location (pc=0:{expected_pc3}) " ) } - CairoVersion::Cairo1 => { + CairoVersion::Cairo1(_) => { format!( "Transaction execution has failed: 0: Error in the called contract (contract address: {account_address_felt:#064x}, class hash: \ @@ -527,10 +554,6 @@ Error in contract (contract address: {address_felt:#064x}, class hash: {test_con " ) } - #[cfg(feature = "cairo_native")] - CairoVersion::Native => { - todo!("Cairo Native not yet supported here.") - } }; assert_eq!(tx_execution_error.to_string(), expected_trace); @@ -538,7 +561,7 @@ Error in contract (contract address: {address_felt:#064x}, class hash: {test_con // TODO(Arni, 1/5/2024): Cover version 0 declare transaction. // TODO(Arni, 1/5/2024): Consider version 0 invoke. -#[rstest] +#[apply(cairo_version)] #[case::validate_version_1( TransactionType::InvokeFunction, VALIDATE_ENTRY_POINT_NAME, @@ -578,7 +601,7 @@ fn test_validate_trace( #[case] tx_type: TransactionType, #[case] entry_point_name: &str, #[case] tx_version: TransactionVersion, - #[values(CairoVersion::Cairo0, CairoVersion::Cairo1)] cairo_version: CairoVersion, + cairo_version: CairoVersion, ) { let create_for_account_testing = &BlockContext::create_for_account_testing(); let block_context = create_for_account_testing; @@ -608,6 +631,11 @@ fn test_validate_trace( } } + // TODO(AvivG): Change this fixup to not create account_tx twice w wrong charge_fee. + let execution_flags = + ExecutionFlags { charge_fee: account_tx.enforce_fee(), ..ExecutionFlags::default() }; + let account_tx = AccountTransaction { tx: account_tx.tx, execution_flags }; + let contract_address = *sender_address.0.key(); let expected_error = match cairo_version { @@ -624,7 +652,7 @@ An ASSERT_EQ instruction failed: 1 != 0. ", class_hash.0 ), - CairoVersion::Cairo1 => format!( + CairoVersion::Cairo1(_) => format!( "The `validate` entry point panicked with: Error in contract (contract address: {contract_address:#064x}, class hash: {:#064x}, selector: \ {selector:#064x}): @@ -632,15 +660,12 @@ Error in contract (contract address: {contract_address:#064x}, class hash: {:#06 ", class_hash.0 ), - #[cfg(feature = "cairo_native")] - CairoVersion::Native => todo!("Cairo Native is not yet supported here."), }; // Clean pc locations from the trace. let re = Regex::new(r"pc=0:[0-9]+").unwrap(); let cleaned_expected_error = &re.replace_all(&expected_error, "pc=0:*"); - let charge_fee = account_tx.enforce_fee(); - let actual_error = account_tx.execute(state, block_context, charge_fee, true).unwrap_err(); + let actual_error = account_tx.execute(state, block_context).unwrap_err(); let actual_error_str = actual_error.to_string(); let cleaned_actual_error = &re.replace_all(&actual_error_str, "pc=0:*"); // Compare actual trace to the expected trace (sans pc locations). @@ -650,9 +675,12 @@ Error in contract (contract address: {contract_address:#064x}, class hash: {:#06 #[rstest] /// Tests that hitting an execution error in an account contract constructor outputs the correct /// traceback (including correct class hash, contract address and constructor entry point selector). +#[case(CairoVersion::Cairo0)] +#[case(CairoVersion::Cairo1(RunnableCairo1::Casm))] +#[cfg_attr(feature = "cairo_native", case(CairoVersion::Cairo1(RunnableCairo1::Native)))] fn test_account_ctor_frame_stack_trace( block_context: BlockContext, - #[values(CairoVersion::Cairo0, CairoVersion::Cairo1)] cairo_version: CairoVersion, + #[case] cairo_version: CairoVersion, ) { let chain_info = &block_context.chain_info; let faulty_account = FeatureContract::FaultyAccount(cairo_version); @@ -689,15 +717,15 @@ fn test_account_ctor_frame_stack_trace( ) .to_string() + &match cairo_version { - CairoVersion::Cairo0 => "Error at pc=0:223: + CairoVersion::Cairo0 => "Error at pc=0:250: Cairo traceback (most recent call last): -Unknown location (pc=0:195) -Unknown location (pc=0:179) +Unknown location (pc=0:222) +Unknown location (pc=0:206) An ASSERT_EQ instruction failed: 1 != 0. " .to_string(), - CairoVersion::Cairo1 => format!( + CairoVersion::Cairo1(_) => format!( "Execution failed. Failure reason: Error in contract (contract address: {expected_address:#064x}, class hash: {:#064x}, selector: \ {expected_selector:#064x}): @@ -706,14 +734,10 @@ Error in contract (contract address: {expected_address:#064x}, class hash: {:#06 class_hash.0 ) .to_string(), - #[cfg(feature = "cairo_native")] - CairoVersion::Native => { - todo!("Cairo Native not yet supported here.") - } }; // Compare expected and actual error. - let error = deploy_account_tx.execute(state, &block_context, true, true).unwrap_err(); + let error = deploy_account_tx.execute(state, &block_context).unwrap_err(); assert_eq!(error.to_string(), expected_error); } @@ -721,10 +745,13 @@ Error in contract (contract address: {expected_address:#064x}, class hash: {:#06 /// Tests that hitting an execution error in a contract constructor during a deploy syscall outputs /// the correct traceback (including correct class hash, contract address and constructor entry /// point selector). +#[case(CairoVersion::Cairo0)] +#[case(CairoVersion::Cairo1(RunnableCairo1::Casm))] +#[cfg_attr(feature = "cairo_native", case(CairoVersion::Cairo1(RunnableCairo1::Native)))] fn test_contract_ctor_frame_stack_trace( block_context: BlockContext, default_all_resource_bounds: ValidResourceBounds, - #[values(CairoVersion::Cairo0, CairoVersion::Cairo1)] cairo_version: CairoVersion, + #[case] cairo_version: CairoVersion, ) { let chain_info = &block_context.chain_info; let account = FeatureContract::AccountWithoutValidations(cairo_version); @@ -747,7 +774,7 @@ fn test_contract_ctor_frame_stack_trace( ) .unwrap(); // Invoke the deploy_contract function on the dummy account to deploy the faulty contract. - let invoke_deploy_tx = account_invoke_tx(invoke_tx_args! { + let invoke_deploy_tx = invoke_tx_with_default_flags(invoke_tx_args! { sender_address: account_address, signature, calldata: create_calldata( @@ -790,14 +817,14 @@ fn test_contract_ctor_frame_stack_trace( faulty_class_hash.0, ctor_selector.0 ), ); - let (execute_offset, deploy_offset, ctor_offset) = ( - account.get_entry_point_offset(execute_selector).0, - account.get_entry_point_offset(deploy_contract_selector).0, - faulty_ctor.get_ctor_offset(Some(ctor_selector)).0, - ); let expected_error = match cairo_version { CairoVersion::Cairo0 => { + let (execute_offset, deploy_offset, ctor_offset) = ( + account.get_entry_point_offset(execute_selector).0, + account.get_entry_point_offset(deploy_contract_selector).0, + faulty_ctor.get_ctor_offset(Some(ctor_selector)).0, + ); format!( "{frame_0} Error at pc=0:7: @@ -812,7 +839,7 @@ Unknown location (pc=0:{}) Unknown location (pc=0:{}) {frame_2} -Error at pc=0:223: +Error at pc=0:250: Cairo traceback (most recent call last): Unknown location (pc=0:{}) Unknown location (pc=0:{}) @@ -827,35 +854,47 @@ An ASSERT_EQ instruction failed: 1 != 0. ctor_offset - 9 ) } - CairoVersion::Cairo1 => { + CairoVersion::Cairo1(runnable_version) => { + let final_error = format!( + "Execution failed. Failure reason: +Error in contract (contract address: {expected_address:#064x}, class hash: {:#064x}, selector: \ + {:#064x}): +0x496e76616c6964207363656e6172696f ('Invalid scenario'). +", + faulty_class_hash.0, ctor_selector.0 + ); // TODO(Dori, 1/1/2025): Get lowest level PC locations from Cairo1 errors (ctor offset // does not appear in the trace). - format!( - "{frame_0} + match runnable_version { + RunnableCairo1::Casm => { + let (execute_offset, deploy_offset) = ( + account.get_entry_point_offset(execute_selector).0, + account.get_entry_point_offset(deploy_contract_selector).0, + ); + format!( + "{frame_0} Error at pc=0:{}: {frame_1} Error at pc=0:{}: {frame_2} -Execution failed. Failure reason: -Error in contract (contract address: {expected_address:#064x}, class hash: {:#064x}, selector: \ - {:#064x}): -0x496e76616c6964207363656e6172696f ('Invalid scenario'). -", - execute_offset + 165, - deploy_offset + 154, - faulty_class_hash.0, - ctor_selector.0 - ) - } - #[cfg(feature = "cairo_native")] - CairoVersion::Native => { - todo!("Cairo Native not yet supported here.") +{final_error}", + execute_offset + 181, + deploy_offset + 168, + ) + } + #[cfg(feature = "cairo_native")] + RunnableCairo1::Native => format!( + "{frame_0} +{frame_1} +{frame_2} +{final_error}" + ), + } } }; // Compare expected and actual error. - let error = - invoke_deploy_tx.execute(state, &block_context, true, true).unwrap().revert_error.unwrap(); + let error = invoke_deploy_tx.execute(state, &block_context).unwrap().revert_error.unwrap(); assert_eq!(error.to_string(), expected_error); } diff --git a/crates/blockifier/src/execution/syscalls/hint_processor.rs b/crates/blockifier/src/execution/syscalls/hint_processor.rs index db6ada14edd..3a8a9e8f467 100644 --- a/crates/blockifier/src/execution/syscalls/hint_processor.rs +++ b/crates/blockifier/src/execution/syscalls/hint_processor.rs @@ -14,10 +14,12 @@ use cairo_vm::vm::errors::vm_errors::VirtualMachineError; use cairo_vm::vm::runners::cairo_runner::{ResourceTracker, RunResources}; use cairo_vm::vm::vm_core::VirtualMachine; use starknet_api::core::{ClassHash, ContractAddress, EntryPointSelector}; +use starknet_api::execution_resources::GasAmount; use starknet_api::transaction::fields::{ AllResourceBounds, Calldata, Resource, + ResourceBounds, ValidResourceBounds, }; use starknet_api::StarknetApiError; @@ -25,8 +27,14 @@ use starknet_types_core::felt::{Felt, FromStrError}; use thiserror::Error; use crate::abi::sierra_types::SierraTypeError; +use crate::blockifier_versioned_constants::{GasCosts, SyscallGasCost}; use crate::execution::common_hints::{ExecutionMode, HintExecutionResult}; -use crate::execution::entry_point::{CallEntryPoint, EntryPointExecutionContext}; +use crate::execution::contract_class::TrackedResource; +use crate::execution::entry_point::{ + CallEntryPoint, + EntryPointExecutionContext, + ExecutableCallEntryPoint, +}; use crate::execution::errors::{ConstructorEntryPointExecutionError, EntryPointExecutionError}; use crate::execution::execution_utils::{ felt_from_ptr, @@ -58,6 +66,7 @@ use crate::execution::syscalls::{ get_execution_info, keccak, library_call, + meta_tx_v0, replace_class, send_message_to_l1, sha_256_process_block, @@ -73,9 +82,25 @@ use crate::execution::syscalls::{ use crate::state::errors::StateError; use crate::state::state_api::State; use crate::transaction::objects::{CurrentTransactionInfo, TransactionInfo}; -use crate::versioned_constants::GasCosts; +use crate::utils::u64_from_usize; + +#[derive(Clone, Debug, Default)] +pub struct SyscallUsage { + pub call_count: usize, + pub linear_factor: usize, +} -pub type SyscallCounter = HashMap; +impl SyscallUsage { + pub fn new(call_count: usize, linear_factor: usize) -> Self { + SyscallUsage { call_count, linear_factor } + } + + pub fn increment_call_count(&mut self) { + self.call_count += 1; + } +} + +pub type SyscallUsageMap = HashMap; #[derive(Debug, Error)] pub enum SyscallExecutionError { @@ -125,8 +150,8 @@ pub enum SyscallExecutionError { StateError(#[from] StateError), #[error(transparent)] VirtualMachineError(#[from] VirtualMachineError), - #[error("Syscall error.")] - SyscallError { error_data: Vec }, + #[error("Syscall revert.")] + Revert { error_data: Vec }, } #[derive(Debug, Error)] @@ -187,7 +212,6 @@ impl SyscallExecutionError { } /// Error codes returned by Cairo 1.0 code. - // "Out of gas"; pub const OUT_OF_GAS_ERROR: &str = "0x000000000000000000000000000000000000000000004f7574206f6620676173"; @@ -213,7 +237,7 @@ pub struct SyscallHintProcessor<'a> { pub base: Box>, // VM-specific fields. - pub syscall_counter: SyscallCounter, + pub syscalls_usage: SyscallUsageMap, // Fields needed for execution and validation. pub read_only_segments: ReadOnlySegments, @@ -232,18 +256,58 @@ pub struct SyscallHintProcessor<'a> { hints: &'a HashMap, } +pub struct ResourceAsFelts { + pub resource_name: Felt, + pub max_amount: Felt, + pub max_price_per_unit: Felt, +} + +impl ResourceAsFelts { + pub fn new(resource: Resource, resource_bounds: &ResourceBounds) -> SyscallResult { + Ok(Self { + resource_name: Felt::from_hex(resource.to_hex()) + .map_err(SyscallExecutionError::from)?, + max_amount: Felt::from(resource_bounds.max_amount), + max_price_per_unit: Felt::from(resource_bounds.max_price_per_unit), + }) + } + + pub fn flatten(self) -> Vec { + vec![self.resource_name, self.max_amount, self.max_price_per_unit] + } +} + +pub fn valid_resource_bounds_as_felts( + resource_bounds: &ValidResourceBounds, + exclude_l1_data_gas: bool, +) -> SyscallResult> { + let mut resource_bounds_vec: Vec<_> = vec![ + ResourceAsFelts::new(Resource::L1Gas, &resource_bounds.get_l1_bounds())?, + ResourceAsFelts::new(Resource::L2Gas, &resource_bounds.get_l2_bounds())?, + ]; + if exclude_l1_data_gas { + return Ok(resource_bounds_vec); + } + if let ValidResourceBounds::AllResources(AllResourceBounds { l1_data_gas, .. }) = + resource_bounds + { + resource_bounds_vec.push(ResourceAsFelts::new(Resource::L1DataGas, l1_data_gas)?) + } + Ok(resource_bounds_vec) +} + impl<'a> SyscallHintProcessor<'a> { pub fn new( state: &'a mut dyn State, context: &'a mut EntryPointExecutionContext, initial_syscall_ptr: Relocatable, - call: CallEntryPoint, + call: ExecutableCallEntryPoint, hints: &'a HashMap, read_only_segments: ReadOnlySegments, ) -> Self { SyscallHintProcessor { base: Box::new(SyscallHandlerBase::new(call, state, context)), - syscall_counter: SyscallCounter::default(), + syscalls_usage: SyscallUsageMap::default(), read_only_segments, syscall_ptr: initial_syscall_ptr, hints, @@ -301,89 +365,92 @@ impl<'a> SyscallHintProcessor<'a> { match selector { SyscallSelector::CallContract => { - self.execute_syscall(vm, call_contract, self.gas_costs().call_contract_gas_cost) + self.execute_syscall(vm, call_contract, self.gas_costs().syscalls.call_contract) } SyscallSelector::Deploy => { - self.execute_syscall(vm, deploy, self.gas_costs().deploy_gas_cost) + self.execute_syscall(vm, deploy, self.gas_costs().syscalls.deploy) } SyscallSelector::EmitEvent => { - self.execute_syscall(vm, emit_event, self.gas_costs().emit_event_gas_cost) + self.execute_syscall(vm, emit_event, self.gas_costs().syscalls.emit_event) } SyscallSelector::GetBlockHash => { - self.execute_syscall(vm, get_block_hash, self.gas_costs().get_block_hash_gas_cost) + self.execute_syscall(vm, get_block_hash, self.gas_costs().syscalls.get_block_hash) } SyscallSelector::GetClassHashAt => self.execute_syscall( vm, get_class_hash_at, - self.gas_costs().get_class_hash_at_gas_cost, + self.gas_costs().syscalls.get_class_hash_at, ), SyscallSelector::GetExecutionInfo => self.execute_syscall( vm, get_execution_info, - self.gas_costs().get_execution_info_gas_cost, + self.gas_costs().syscalls.get_execution_info, ), SyscallSelector::Keccak => { - self.execute_syscall(vm, keccak, self.gas_costs().keccak_gas_cost) + self.execute_syscall(vm, keccak, self.gas_costs().syscalls.keccak) } SyscallSelector::Sha256ProcessBlock => self.execute_syscall( vm, sha_256_process_block, - self.gas_costs().sha256_process_block_gas_cost, + self.gas_costs().syscalls.sha256_process_block, ), SyscallSelector::LibraryCall => { - self.execute_syscall(vm, library_call, self.gas_costs().library_call_gas_cost) + self.execute_syscall(vm, library_call, self.gas_costs().syscalls.library_call) + } + SyscallSelector::MetaTxV0 => { + self.execute_syscall(vm, meta_tx_v0, self.gas_costs().syscalls.meta_tx_v0) } SyscallSelector::ReplaceClass => { - self.execute_syscall(vm, replace_class, self.gas_costs().replace_class_gas_cost) + self.execute_syscall(vm, replace_class, self.gas_costs().syscalls.replace_class) } SyscallSelector::Secp256k1Add => { - self.execute_syscall(vm, secp256k1_add, self.gas_costs().secp256k1_add_gas_cost) + self.execute_syscall(vm, secp256k1_add, self.gas_costs().syscalls.secp256k1_add) } SyscallSelector::Secp256k1GetPointFromX => self.execute_syscall( vm, secp256k1_get_point_from_x, - self.gas_costs().secp256k1_get_point_from_x_gas_cost, + self.gas_costs().syscalls.secp256k1_get_point_from_x, ), SyscallSelector::Secp256k1GetXy => self.execute_syscall( vm, secp256k1_get_xy, - self.gas_costs().secp256k1_get_xy_gas_cost, + self.gas_costs().syscalls.secp256k1_get_xy, ), SyscallSelector::Secp256k1Mul => { - self.execute_syscall(vm, secp256k1_mul, self.gas_costs().secp256k1_mul_gas_cost) + self.execute_syscall(vm, secp256k1_mul, self.gas_costs().syscalls.secp256k1_mul) } SyscallSelector::Secp256k1New => { - self.execute_syscall(vm, secp256k1_new, self.gas_costs().secp256k1_new_gas_cost) + self.execute_syscall(vm, secp256k1_new, self.gas_costs().syscalls.secp256k1_new) } SyscallSelector::Secp256r1Add => { - self.execute_syscall(vm, secp256r1_add, self.gas_costs().secp256r1_add_gas_cost) + self.execute_syscall(vm, secp256r1_add, self.gas_costs().syscalls.secp256r1_add) } SyscallSelector::Secp256r1GetPointFromX => self.execute_syscall( vm, secp256r1_get_point_from_x, - self.gas_costs().secp256r1_get_point_from_x_gas_cost, + self.gas_costs().syscalls.secp256r1_get_point_from_x, ), SyscallSelector::Secp256r1GetXy => self.execute_syscall( vm, secp256r1_get_xy, - self.gas_costs().secp256r1_get_xy_gas_cost, + self.gas_costs().syscalls.secp256r1_get_xy, ), SyscallSelector::Secp256r1Mul => { - self.execute_syscall(vm, secp256r1_mul, self.gas_costs().secp256r1_mul_gas_cost) + self.execute_syscall(vm, secp256r1_mul, self.gas_costs().syscalls.secp256r1_mul) } SyscallSelector::Secp256r1New => { - self.execute_syscall(vm, secp256r1_new, self.gas_costs().secp256r1_new_gas_cost) + self.execute_syscall(vm, secp256r1_new, self.gas_costs().syscalls.secp256r1_new) } SyscallSelector::SendMessageToL1 => self.execute_syscall( vm, send_message_to_l1, - self.gas_costs().send_message_to_l1_gas_cost, + self.gas_costs().syscalls.send_message_to_l1, ), SyscallSelector::StorageRead => { - self.execute_syscall(vm, storage_read, self.gas_costs().storage_read_gas_cost) + self.execute_syscall(vm, storage_read, self.gas_costs().syscalls.storage_read) } SyscallSelector::StorageWrite => { - self.execute_syscall(vm, storage_write, self.gas_costs().storage_write_gas_cost) + self.execute_syscall(vm, storage_write, self.gas_costs().syscalls.storage_write) } _ => Err(HintError::UnknownHint( format!("Unsupported syscall selector {selector:?}.").into(), @@ -409,33 +476,13 @@ impl<'a> SyscallHintProcessor<'a> { &mut self, vm: &mut VirtualMachine, tx_info: &CurrentTransactionInfo, + exclude_l1_data_gas: bool, ) -> SyscallResult<(Relocatable, Relocatable)> { - let l1_gas_as_felt = - Felt::from_hex(Resource::L1Gas.to_hex()).map_err(SyscallExecutionError::from)?; - let l2_gas_as_felt = - Felt::from_hex(Resource::L2Gas.to_hex()).map_err(SyscallExecutionError::from)?; - let l1_data_gas_as_felt = - Felt::from_hex(Resource::L1DataGas.to_hex()).map_err(SyscallExecutionError::from)?; - - let l1_gas_bounds = tx_info.resource_bounds.get_l1_bounds(); - let l2_gas_bounds = tx_info.resource_bounds.get_l2_bounds(); - let mut flat_resource_bounds = vec![ - l1_gas_as_felt, - Felt::from(l1_gas_bounds.max_amount), - Felt::from(l1_gas_bounds.max_price_per_unit), - l2_gas_as_felt, - Felt::from(l2_gas_bounds.max_amount), - Felt::from(l2_gas_bounds.max_price_per_unit), - ]; - if let ValidResourceBounds::AllResources(AllResourceBounds { l1_data_gas, .. }) = - tx_info.resource_bounds - { - flat_resource_bounds.extend(vec![ - l1_data_gas_as_felt, - Felt::from(l1_data_gas.max_amount), - Felt::from(l1_data_gas.max_price_per_unit), - ]) - } + let flat_resource_bounds: Vec<_> = + valid_resource_bounds_as_felts(&tx_info.resource_bounds, exclude_l1_data_gas)? + .into_iter() + .flat_map(ResourceAsFelts::flatten) + .collect(); self.allocate_data_segment(vm, &flat_resource_bounds) } @@ -444,7 +491,7 @@ impl<'a> SyscallHintProcessor<'a> { &mut self, vm: &mut VirtualMachine, execute_callback: ExecuteCallback, - syscall_gas_cost: u64, + syscall_gas_cost: SyscallGasCost, ) -> HintExecutionResult where Request: SyscallRequest + std::fmt::Debug, @@ -456,12 +503,22 @@ impl<'a> SyscallHintProcessor<'a> { &mut u64, // Remaining gas. ) -> SyscallResult, { - // Refund `SYSCALL_BASE_GAS_COST` as it was pre-charged. - let required_gas = syscall_gas_cost - self.base.context.gas_costs().syscall_base_gas_cost; - let SyscallRequestWrapper { gas_counter, request } = SyscallRequestWrapper::::read(vm, &mut self.syscall_ptr)?; + let syscall_gas_cost = + syscall_gas_cost.get_syscall_cost(u64_from_usize(request.get_linear_factor_length())); + let syscall_base_cost = self.base.context.gas_costs().base.syscall_base_gas_cost; + + // Sanity check for preventing underflow. + assert!( + syscall_gas_cost >= syscall_base_cost, + "Syscall gas cost must be greater than base syscall gas cost" + ); + + // Refund `SYSCALL_BASE_GAS_COST` as it was pre-charged. + let required_gas = syscall_gas_cost - syscall_base_cost; + if gas_counter < required_gas { // Out of gas failure. let out_of_gas_error = @@ -475,12 +532,27 @@ impl<'a> SyscallHintProcessor<'a> { // Execute. let mut remaining_gas = gas_counter - required_gas; + + // To support sierra gas charge for blockifier revert flow, we track the remaining gas left + // before executing a syscall if the current tracked resource is gas. + // 1. If the syscall does not run Cairo code (i.e. not library call, not call contract, and + // not a deploy), any failure will not run in the OS, so no need to charge - the value + // before entering the callback is good enough to charge. + // 2. If the syscall runs Cairo code, but the tracked resource is steps (and not gas), the + // additional charge of reverted cairo steps will cover the inner cost, and the outer + // cost we track here will be the additional reverted gas. + // 3. If the syscall runs Cairo code and the tracked resource is gas, either the inner + // failure will be a Cairo1 revert (and the gas consumed on the call info will override + // the current tracked value), or we will pass through another syscall before failing - + // and by induction (we will reach this point again), the gas will be charged correctly. + self.base.context.update_revert_gas_with_next_remaining_gas(GasAmount(remaining_gas)); + let original_response = execute_callback(request, vm, self, &mut remaining_gas); let response = match original_response { Ok(response) => { SyscallResponseWrapper::Success { gas_counter: remaining_gas, response } } - Err(SyscallExecutionError::SyscallError { error_data: data }) => { + Err(SyscallExecutionError::Revert { error_data: data }) => { SyscallResponseWrapper::Failure { gas_counter: remaining_gas, error_data: data } } Err(error) => return Err(error.into()), @@ -496,14 +568,22 @@ impl<'a> SyscallHintProcessor<'a> { } pub fn increment_syscall_count_by(&mut self, selector: &SyscallSelector, n: usize) { - let syscall_count = self.syscall_counter.entry(*selector).or_default(); - *syscall_count += n; + let syscall_usage = self.syscalls_usage.entry(*selector).or_default(); + syscall_usage.call_count += n; } fn increment_syscall_count(&mut self, selector: &SyscallSelector) { self.increment_syscall_count_by(selector, 1); } + pub fn increment_linear_factor_by(&mut self, selector: &SyscallSelector, n: usize) { + let syscall_usage = self + .syscalls_usage + .get_mut(selector) + .expect("syscalls_usage entry must be initialized before incrementing linear factor"); + syscall_usage.linear_factor += n; + } + fn allocate_execution_info_segment( &mut self, vm: &mut VirtualMachine, @@ -528,29 +608,17 @@ impl<'a> SyscallHintProcessor<'a> { &mut self, vm: &mut VirtualMachine, ) -> SyscallResult { - let block_info = &self.base.context.tx_context.block_context.block_info; - let block_timestamp = block_info.block_timestamp.0; - let block_number = block_info.block_number.0; - let versioned_constants = self.base.context.versioned_constants(); - let block_data: Vec = if self.is_validate_mode() { - // Round down to the nearest multiple of validate_block_number_rounding. - let validate_block_number_rounding = - versioned_constants.get_validate_block_number_rounding(); - let rounded_block_number = - (block_number / validate_block_number_rounding) * validate_block_number_rounding; - // Round down to the nearest multiple of validate_timestamp_rounding. - let validate_timestamp_rounding = versioned_constants.get_validate_timestamp_rounding(); - let rounded_timestamp = - (block_timestamp / validate_timestamp_rounding) * validate_timestamp_rounding; - - vec![Felt::from(rounded_block_number), Felt::from(rounded_timestamp), Felt::ZERO] - } else { - vec![ - Felt::from(block_number), - Felt::from(block_timestamp), - *block_info.sequencer_address.0.key(), - ] + let block_info = match self.base.context.execution_mode { + ExecutionMode::Execute => self.base.context.tx_context.block_context.block_info(), + ExecutionMode::Validate => { + &self.base.context.tx_context.block_context.block_info_for_validate() + } }; + let block_data = vec![ + Felt::from(block_info.block_number.0), + Felt::from(block_info.block_timestamp.0), + Felt::from(block_info.sequencer_address), + ]; let (block_info_segment_start_ptr, _) = self.allocate_data_segment(vm, &block_data)?; Ok(block_info_segment_start_ptr) @@ -572,8 +640,13 @@ impl<'a> SyscallHintProcessor<'a> { let (tx_signature_start_ptr, tx_signature_end_ptr) = &self.allocate_data_segment(vm, &tx_info.signature().0)?; + // Note: the returned version might not be equal to the actual transaction version. + // Also, the returned version is a property of the current VM execution (of some contract + // call) so it is okay to allocate it once whithout re-checking the version in every + // `get_execution_info` syscall invocation. + let returned_version = self.base.tx_version_for_get_execution_info(); let mut tx_data: Vec = vec![ - tx_info.signed_version().0.into(), + returned_version.0.into(), tx_info.sender_address().0.key().into(), Felt::from(tx_info.max_fee_for_execution_info_syscall().0).into(), tx_signature_start_ptr.into(), @@ -588,8 +661,10 @@ impl<'a> SyscallHintProcessor<'a> { match tx_info { TransactionInfo::Current(context) => { - let (tx_resource_bounds_start_ptr, tx_resource_bounds_end_ptr) = - &self.allocate_tx_resource_bounds_segment(vm, context)?; + // See comment above about the returned version. + let should_exclude_l1_data_gas = self.base.should_exclude_l1_data_gas(); + let (tx_resource_bounds_start_ptr, tx_resource_bounds_end_ptr) = &self + .allocate_tx_resource_bounds_segment(vm, context, should_exclude_l1_data_gas)?; let (tx_paymaster_data_start_ptr, tx_paymaster_data_end_ptr) = &self.allocate_data_segment(vm, &context.paymaster_data.0)?; @@ -639,8 +714,18 @@ impl ResourceTracker for SyscallHintProcessor<'_> { self.base.context.vm_run_resources.consumed() } + /// Consumes a single step (if we are in step-tracking mode). fn consume_step(&mut self) { - self.base.context.vm_run_resources.consume_step() + if *self + .base + .context + .tracked_resource_stack + .last() + .expect("When consume_step is called, tracked resource stack is initialized.") + == TrackedResource::CairoSteps + { + self.base.context.vm_run_resources.consume_step(); + } } fn get_n_steps(&self) -> Option { @@ -661,9 +746,17 @@ impl HintProcessorLogic for SyscallHintProcessor<'_> { _constants: &HashMap, ) -> HintExecutionResult { let hint = hint_data.downcast_ref::().ok_or(HintError::WrongHintData)?; + // Segment arena finalization is relevant only for proof so there is no need to allocate + // memory segments for it in the sequencer. + let no_temporary_segments = true; match hint { - Hint::Core(hint) => execute_core_hint_base(vm, exec_scopes, hint), + Hint::Core(hint) => { + execute_core_hint_base(vm, exec_scopes, hint, no_temporary_segments) + } Hint::Starknet(hint) => self.execute_next_syscall(vm, hint), + Hint::External(_) => { + panic!("starknet should never accept classes with external hints!") + } } } diff --git a/crates/blockifier/src/execution/syscalls/mod.rs b/crates/blockifier/src/execution/syscalls/mod.rs index 1ea040b7d15..6ab6c0e24dc 100644 --- a/crates/blockifier/src/execution/syscalls/mod.rs +++ b/crates/blockifier/src/execution/syscalls/mod.rs @@ -1,12 +1,24 @@ +use std::sync::Arc; + use cairo_vm::types::relocatable::{MaybeRelocatable, Relocatable}; use cairo_vm::vm::vm_core::VirtualMachine; use num_traits::ToPrimitive; use starknet_api::block::{BlockHash, BlockNumber}; use starknet_api::contract_class::EntryPointType; -use starknet_api::core::{ClassHash, ContractAddress, EntryPointSelector, EthAddress}; +use starknet_api::core::{ClassHash, ContractAddress, EntryPointSelector, EthAddress, Nonce}; use starknet_api::state::StorageKey; -use starknet_api::transaction::fields::{Calldata, ContractAddressSalt}; -use starknet_api::transaction::{EventContent, EventData, EventKey, L2ToL1Payload}; +use starknet_api::transaction::fields::{Calldata, ContractAddressSalt, Fee, TransactionSignature}; +use starknet_api::transaction::{ + signed_tx_version, + EventContent, + EventData, + EventKey, + InvokeTransactionV0, + L2ToL1Payload, + TransactionHasher, + TransactionOptions, + TransactionVersion, +}; use starknet_types_core::felt::Felt; use self::hint_processor::{ @@ -21,6 +33,8 @@ use self::hint_processor::{ SyscallExecutionError, SyscallHintProcessor, }; +use crate::blockifier_versioned_constants::{EventLimits, VersionedConstants}; +use crate::context::TransactionContext; use crate::execution::call_info::MessageToL1; use crate::execution::deprecated_syscalls::DeprecatedSyscallSelector; use crate::execution::entry_point::{CallEntryPoint, CallType}; @@ -30,9 +44,12 @@ use crate::execution::execution_utils::{ write_maybe_relocatable, ReadOnlySegment, }; -use crate::execution::syscalls::hint_processor::{INVALID_INPUT_LENGTH_ERROR, OUT_OF_GAS_ERROR}; use crate::execution::syscalls::syscall_base::SyscallResult; -use crate::versioned_constants::{EventLimits, VersionedConstants}; +use crate::transaction::objects::{ + CommonAccountFields, + DeprecatedTransactionInfo, + TransactionInfo, +}; pub mod hint_processor; mod secp; @@ -47,6 +64,12 @@ pub type SyscallSelector = DeprecatedSyscallSelector; pub trait SyscallRequest: Sized { fn read(_vm: &VirtualMachine, _ptr: &mut Relocatable) -> SyscallResult; + + /// Returns the linear factor's length for the syscall. + /// If no factor exists, it returns 0. + fn get_linear_factor_length(&self) -> usize { + 0 + } } pub trait SyscallResponse { @@ -185,7 +208,7 @@ pub fn call_contract( let retdata_segment = execute_inner_call(entry_point, vm, syscall_handler, remaining_gas) .map_err(|error| match error { - SyscallExecutionError::SyscallError { .. } => error, + SyscallExecutionError::Revert { .. } => error, _ => error.as_call_contract_execution_error(class_hash, storage_address, selector), })?; @@ -219,6 +242,10 @@ impl SyscallRequest for DeployRequest { )?, }) } + + fn get_linear_factor_length(&self) -> usize { + self.constructor_calldata.0.len() + } } #[derive(Debug)] @@ -240,6 +267,11 @@ pub fn deploy( syscall_handler: &mut SyscallHintProcessor<'_>, remaining_gas: &mut u64, ) -> SyscallResult { + // Increment the Deploy syscall's linear cost counter by the number of elements in the + // constructor calldata. + syscall_handler + .increment_linear_factor_by(&SyscallSelector::Deploy, request.constructor_calldata.0.len()); + let (deployed_contract_address, call_info) = syscall_handler.base.deploy( request.class_hash, request.contract_address_salt, @@ -344,8 +376,8 @@ impl SyscallResponse for GetBlockHashResponse { /// Returns the block hash of a given block_number. /// Returns the expected block hash if the given block was created at least -/// [constants::STORED_BLOCK_HASH_BUFFER] blocks before the current block. Otherwise, returns an -/// error. +/// [crate::abi::constants::STORED_BLOCK_HASH_BUFFER] blocks before the current block. Otherwise, +/// returns an error. pub fn get_block_hash( request: GetBlockHashRequest, _vm: &mut VirtualMachine, @@ -424,7 +456,7 @@ pub fn library_call( let retdata_segment = execute_inner_call(entry_point, vm, syscall_handler, remaining_gas) .map_err(|error| match error { - SyscallExecutionError::SyscallError { .. } => error, + SyscallExecutionError::Revert { .. } => error, _ => error.as_lib_call_execution_error( request.class_hash, syscall_handler.storage_address(), @@ -435,6 +467,114 @@ pub fn library_call( Ok(LibraryCallResponse { segment: retdata_segment }) } +// MetaTxV0 syscall. + +#[derive(Debug, Eq, PartialEq)] +pub struct MetaTxV0Request { + pub contract_address: ContractAddress, + pub entry_point_selector: EntryPointSelector, + pub calldata: Calldata, + pub signature: TransactionSignature, +} + +impl SyscallRequest for MetaTxV0Request { + fn read(vm: &VirtualMachine, ptr: &mut Relocatable) -> SyscallResult { + let contract_address = ContractAddress::try_from(felt_from_ptr(vm, ptr)?)?; + let (entry_point_selector, calldata) = read_call_params(vm, ptr)?; + let signature = TransactionSignature(read_felt_array::(vm, ptr)?); + + Ok(MetaTxV0Request { contract_address, entry_point_selector, calldata, signature }) + } + + fn get_linear_factor_length(&self) -> usize { + self.calldata.0.len() + } +} + +type MetaTxV0Response = CallContractResponse; + +pub(crate) fn meta_tx_v0( + request: MetaTxV0Request, + vm: &mut VirtualMachine, + syscall_handler: &mut SyscallHintProcessor<'_>, + remaining_gas: &mut u64, +) -> SyscallResult { + if syscall_handler.is_validate_mode() { + return Err(SyscallExecutionError::InvalidSyscallInExecutionMode { + syscall_name: "meta_tx_v0".to_string(), + execution_mode: syscall_handler.execution_mode(), + }); + } + + // Increment the MetaTxV0 syscall's linear cost counter by the number of elements in the + // calldata. + syscall_handler + .increment_linear_factor_by(&SyscallSelector::MetaTxV0, request.get_linear_factor_length()); + + let storage_address = request.contract_address; + let selector = request.entry_point_selector; + let class_hash = syscall_handler.base.state.get_class_hash_at(storage_address)?; + let entry_point = CallEntryPoint { + class_hash: None, + code_address: Some(storage_address), + entry_point_type: EntryPointType::External, + entry_point_selector: selector, + calldata: request.calldata.clone(), + storage_address, + caller_address: ContractAddress::default(), + call_type: CallType::Call, + // NOTE: this value might be overridden later on. + initial_gas: *remaining_gas, + }; + + let old_tx_context = syscall_handler.base.context.tx_context.clone(); + let only_query = old_tx_context.tx_info.only_query(); + + // Compute meta-transaction hash. + let transaction_hash = InvokeTransactionV0 { + max_fee: Fee(0), + signature: request.signature.clone(), + contract_address: storage_address, + entry_point_selector: selector, + calldata: request.calldata, + } + .calculate_transaction_hash( + &syscall_handler.base.context.tx_context.block_context.chain_info.chain_id, + &signed_tx_version(&TransactionVersion::ZERO, &TransactionOptions { only_query }), + )?; + + // Replace `tx_context`. + let new_tx_info = TransactionInfo::Deprecated(DeprecatedTransactionInfo { + common_fields: CommonAccountFields { + transaction_hash, + version: TransactionVersion::ZERO, + signature: request.signature, + nonce: Nonce(0.into()), + sender_address: storage_address, + only_query, + }, + max_fee: Fee(0), + }); + syscall_handler.base.context.tx_context = Arc::new(TransactionContext { + block_context: old_tx_context.block_context.clone(), + tx_info: new_tx_info, + }); + + let retdata_segment = execute_inner_call(entry_point, vm, syscall_handler, remaining_gas) + .map_err(|error| match error { + SyscallExecutionError::Revert { .. } => error, + _ => { + // TODO(lior): Change to meta-tx specific error. + error.as_call_contract_execution_error(class_hash, storage_address, selector) + } + })?; + + // Restore the old `tx_context`. + syscall_handler.base.context.tx_context = old_tx_context; + + Ok(MetaTxV0Response { segment: retdata_segment }) +} + // ReplaceClass syscall. #[derive(Debug, Eq, PartialEq)] @@ -606,45 +746,23 @@ pub fn keccak( ) -> SyscallResult { let input_length = (request.input_end - request.input_start)?; - const KECCAK_FULL_RATE_IN_WORDS: usize = 17; - let (n_rounds, remainder) = num_integer::div_rem(input_length, KECCAK_FULL_RATE_IN_WORDS); - - if remainder != 0 { - return Err(SyscallExecutionError::SyscallError { - error_data: vec![ - Felt::from_hex(INVALID_INPUT_LENGTH_ERROR).map_err(SyscallExecutionError::from)?, - ], - }); - } - - // TODO(Ori, 1/2/2024): Write an indicative expect message explaining why the conversion works. - let n_rounds_as_u64 = u64::try_from(n_rounds).expect("Failed to convert usize to u64."); - let gas_cost = n_rounds_as_u64 * syscall_handler.gas_costs().keccak_round_cost_gas_cost; - if gas_cost > *remaining_gas { - let out_of_gas_error = - Felt::from_hex(OUT_OF_GAS_ERROR).map_err(SyscallExecutionError::from)?; + let data = vm.get_integer_range(request.input_start, input_length)?; + let data_u64: &[u64] = &data + .iter() + .map(|felt| { + felt.to_u64().ok_or_else(|| SyscallExecutionError::InvalidSyscallInput { + input: **felt, + info: "Invalid input for the keccak syscall.".to_string(), + }) + }) + .collect::, _>>()?; - return Err(SyscallExecutionError::SyscallError { error_data: vec![out_of_gas_error] }); - } - *remaining_gas -= gas_cost; + let (state, n_rounds) = syscall_handler.base.keccak(data_u64, remaining_gas)?; // For the keccak system call we want to count the number of rounds rather than the number of // syscall invocations. syscall_handler.increment_syscall_count_by(&SyscallSelector::Keccak, n_rounds); - let data = vm.get_integer_range(request.input_start, input_length)?; - - let mut state = [0u64; 25]; - for chunk in data.chunks(KECCAK_FULL_RATE_IN_WORDS) { - for (i, val) in chunk.iter().enumerate() { - state[i] ^= val.to_u64().ok_or_else(|| SyscallExecutionError::InvalidSyscallInput { - input: **val, - info: String::from("Invalid input for the keccak syscall."), - })?; - } - keccak::f1600(&mut state) - } - Ok(KeccakResponse { result_low: (Felt::from(state[1]) * Felt::TWO.pow(64_u128)) + Felt::from(state[0]), result_high: (Felt::from(state[3]) * Felt::TWO.pow(64_u128)) + Felt::from(state[2]), diff --git a/crates/blockifier/src/execution/syscalls/syscall_base.rs b/crates/blockifier/src/execution/syscalls/syscall_base.rs index ade9cb398cf..55a5e78b1f3 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_base.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_base.rs @@ -1,39 +1,55 @@ -use std::collections::{hash_map, HashMap, HashSet}; +/// This file is for sharing common logic between Native and VM syscall implementations. +use std::collections::{hash_map, HashMap}; use std::convert::From; +use starknet_api::block::{BlockHash, BlockNumber}; use starknet_api::core::{calculate_contract_address, ClassHash, ContractAddress}; use starknet_api::state::StorageKey; use starknet_api::transaction::fields::{Calldata, ContractAddressSalt}; -use starknet_api::transaction::EventContent; +use starknet_api::transaction::{ + signed_tx_version, + EventContent, + TransactionOptions, + TransactionVersion, +}; use starknet_types_core::felt::Felt; use super::exceeds_event_size_limit; use crate::abi::constants; -use crate::execution::call_info::{CallInfo, MessageToL1, OrderedEvent, OrderedL2ToL1Message}; +use crate::execution::call_info::{ + CallInfo, + MessageToL1, + OrderedEvent, + OrderedL2ToL1Message, + StorageAccessTracker, +}; use crate::execution::common_hints::ExecutionMode; use crate::execution::entry_point::{ CallEntryPoint, ConstructorContext, EntryPointExecutionContext, + ExecutableCallEntryPoint, }; use crate::execution::execution_utils::execute_deployment; use crate::execution::syscalls::hint_processor::{ SyscallExecutionError, BLOCK_NUMBER_OUT_OF_RANGE_ERROR, ENTRYPOINT_FAILED_ERROR, + INVALID_INPUT_LENGTH_ERROR, + OUT_OF_GAS_ERROR, }; use crate::state::state_api::State; use crate::transaction::account_transaction::is_cairo1; +use crate::transaction::objects::TransactionInfo; pub type SyscallResult = Result; - -/// This file is for sharing common logic between Native and VM syscall implementations. +pub const KECCAK_FULL_RATE_IN_WORDS: usize = 17; pub struct SyscallHandlerBase<'state> { // Input for execution. pub state: &'state mut dyn State, pub context: &'state mut EntryPointExecutionContext, - pub call: CallEntryPoint, + pub call: ExecutableCallEntryPoint, // Execution results. pub events: Vec, @@ -41,23 +57,22 @@ pub struct SyscallHandlerBase<'state> { pub inner_calls: Vec, // Additional information gathered during execution. - pub read_values: Vec, - pub accessed_keys: HashSet, - pub read_class_hash_values: Vec, - // Accessed addresses by the `get_class_hash_at` syscall. - pub accessed_contract_addresses: HashSet, + pub storage_access_tracker: StorageAccessTracker, // The original storage value of the executed contract. // Should be moved back `context.revert_info` before executing an inner call. pub original_values: HashMap, + + revert_info_idx: usize, } impl<'state> SyscallHandlerBase<'state> { pub fn new( - call: CallEntryPoint, + call: ExecutableCallEntryPoint, state: &'state mut dyn State, context: &'state mut EntryPointExecutionContext, ) -> SyscallHandlerBase<'state> { + let revert_info_idx = context.revert_infos.0.len() - 1; let original_values = std::mem::take( &mut context .revert_infos @@ -73,45 +88,66 @@ impl<'state> SyscallHandlerBase<'state> { events: Vec::new(), l2_to_l1_messages: Vec::new(), inner_calls: Vec::new(), - read_values: Vec::new(), - accessed_keys: HashSet::new(), - read_class_hash_values: Vec::new(), - accessed_contract_addresses: HashSet::new(), + storage_access_tracker: StorageAccessTracker::default(), original_values, + revert_info_idx, } } - pub fn get_block_hash(&self, requested_block_number: u64) -> SyscallResult { - let execution_mode = self.context.execution_mode; - if execution_mode == ExecutionMode::Validate { - return Err(SyscallExecutionError::InvalidSyscallInExecutionMode { - syscall_name: "get_block_hash".to_string(), - execution_mode, - }); - } - + pub fn get_block_hash(&mut self, requested_block_number: u64) -> SyscallResult { + // Note: we take the actual block number (and not the rounded one for validate) + // in any case; it is consistent with the OS implementation and safe (see `Validate` arm). let current_block_number = self.context.tx_context.block_context.block_info.block_number.0; if current_block_number < constants::STORED_BLOCK_HASH_BUFFER || requested_block_number > current_block_number - constants::STORED_BLOCK_HASH_BUFFER { - let out_of_range_error = Felt::from_hex(BLOCK_NUMBER_OUT_OF_RANGE_ERROR) - .expect("Converting BLOCK_NUMBER_OUT_OF_RANGE_ERROR to Felt should not fail."); - return Err(SyscallExecutionError::SyscallError { - error_data: vec![out_of_range_error], - }); + // Requested block is too recent. + match self.context.execution_mode { + ExecutionMode::Execute => { + // Revert the syscall. + let out_of_range_error = Felt::from_hex(BLOCK_NUMBER_OUT_OF_RANGE_ERROR) + .expect( + "Converting BLOCK_NUMBER_OUT_OF_RANGE_ERROR to Felt should not fail.", + ); + return Err(SyscallExecutionError::Revert { + error_data: vec![out_of_range_error], + }); + } + ExecutionMode::Validate => { + // In this case, the transaction must be **rejected** to avoid the following + // attack: + // * query a given block in validate, + // * if reverted - ignore, if succeeded - panic. + // * in the gateway, the queried block is (actual_latest - 9), + // * while in the sequencer, the queried block can be further than that. + return Err(SyscallExecutionError::InvalidSyscallInExecutionMode { + syscall_name: "get_block_hash on recent blocks".to_string(), + execution_mode: ExecutionMode::Validate, + }); + } + } } + self.storage_access_tracker.accessed_blocks.insert(BlockNumber(requested_block_number)); let key = StorageKey::try_from(Felt::from(requested_block_number))?; - let block_hash_contract_address = - ContractAddress::try_from(Felt::from(constants::BLOCK_HASH_CONTRACT_ADDRESS))?; - Ok(self.state.get_storage_at(block_hash_contract_address, key)?) + let block_hash_contract_address = self + .context + .tx_context + .block_context + .versioned_constants + .os_constants + .os_contract_addresses + .block_hash_contract_address(); + let block_hash = self.state.get_storage_at(block_hash_contract_address, key)?; + self.storage_access_tracker.read_block_hash_values.push(BlockHash(block_hash)); + Ok(block_hash) } pub fn storage_read(&mut self, key: StorageKey) -> SyscallResult { - self.accessed_keys.insert(key); + self.storage_access_tracker.accessed_storage_keys.insert(key); let value = self.state.get_storage_at(self.call.storage_address, key)?; - self.read_values.push(value); + self.storage_access_tracker.storage_read_values.push(value); Ok(value) } @@ -125,7 +161,7 @@ impl<'state> SyscallHandlerBase<'state> { hash_map::Entry::Occupied(_) => {} } - self.accessed_keys.insert(key); + self.storage_access_tracker.accessed_storage_keys.insert(key); self.state.set_storage_at(contract_address, key, value)?; Ok(()) @@ -135,12 +171,55 @@ impl<'state> SyscallHandlerBase<'state> { &mut self, contract_address: ContractAddress, ) -> SyscallResult { - self.accessed_contract_addresses.insert(contract_address); + if self.context.execution_mode == ExecutionMode::Validate { + return Err(SyscallExecutionError::InvalidSyscallInExecutionMode { + syscall_name: "get_class_hash_at".to_string(), + execution_mode: ExecutionMode::Validate, + }); + } + self.storage_access_tracker.accessed_contract_addresses.insert(contract_address); let class_hash = self.state.get_class_hash_at(contract_address)?; - self.read_class_hash_values.push(class_hash); + self.storage_access_tracker.read_class_hash_values.push(class_hash); Ok(class_hash) } + /// Returns the transaction version for the `get_execution_info` syscall. + pub fn tx_version_for_get_execution_info(&self) -> TransactionVersion { + let tx_context = &self.context.tx_context; + // The transaction version, ignoring the only_query bit. + let version = tx_context.tx_info.version(); + let versioned_constants = &tx_context.block_context.versioned_constants; + // The set of v1-bound-accounts. + let v1_bound_accounts = &versioned_constants.os_constants.v1_bound_accounts_cairo1; + let class_hash = &self.call.class_hash; + + // If the transaction version is 3 and the account is in the v1-bound-accounts set, + // the syscall should return transaction version 1 instead. + if version == TransactionVersion::THREE && v1_bound_accounts.contains(class_hash) { + let tip = match &tx_context.tx_info { + TransactionInfo::Current(transaction_info) => transaction_info.tip, + TransactionInfo::Deprecated(_) => { + panic!("Transaction info variant doesn't match transaction version") + } + }; + if tip <= versioned_constants.os_constants.v1_bound_accounts_max_tip { + return signed_tx_version( + &TransactionVersion::ONE, + &TransactionOptions { only_query: tx_context.tx_info.only_query() }, + ); + } + } + + tx_context.tx_info.signed_version() + } + + /// Return whether the L1 data gas should be excluded for the `get_execution_info` syscall. + pub fn should_exclude_l1_data_gas(&self) -> bool { + let class_hash = self.call.class_hash; + let versioned_constants = &self.context.tx_context.block_context.versioned_constants; + versioned_constants.os_constants.data_gas_accounts.contains(&class_hash) + } + pub fn emit_event(&mut self, event: EventContent) -> SyscallResult<()> { exceeds_event_size_limit( self.context.versioned_constants(), @@ -156,9 +235,9 @@ impl<'state> SyscallHandlerBase<'state> { pub fn replace_class(&mut self, class_hash: ClassHash) -> SyscallResult<()> { // Ensure the class is declared (by reading it), and of type V1. - let class = self.state.get_compiled_contract_class(class_hash)?; + let compiled_class = self.state.get_compiled_class(class_hash)?; - if !is_cairo1(&class) { + if !is_cairo1(&compiled_class) { return Err(SyscallExecutionError::ForbiddenClassReplacement { class_hash }); } self.state.set_class_hash_at(self.call.storage_address, class_hash)?; @@ -244,17 +323,59 @@ impl<'state> SyscallHandlerBase<'state> { raw_retdata.push( Felt::from_hex(ENTRYPOINT_FAILED_ERROR).map_err(SyscallExecutionError::from)?, ); - return Err(SyscallExecutionError::SyscallError { error_data: raw_retdata }); + return Err(SyscallExecutionError::Revert { error_data: raw_retdata }); } Ok(raw_retdata) } + pub fn keccak( + &mut self, + input: &[u64], + remaining_gas: &mut u64, + ) -> SyscallResult<([u64; 4], usize)> { + let input_length = input.len(); + + let (n_rounds, remainder) = num_integer::div_rem(input_length, KECCAK_FULL_RATE_IN_WORDS); + + if remainder != 0 { + return Err(SyscallExecutionError::Revert { + error_data: vec![ + Felt::from_hex(INVALID_INPUT_LENGTH_ERROR) + .expect("Failed to parse INVALID_INPUT_LENGTH_ERROR hex string"), + ], + }); + } + // TODO(Ori, 1/2/2024): Write an indicative expect message explaining why the conversion + // works. + let n_rounds_as_u64 = u64::try_from(n_rounds).expect("Failed to convert usize to u64."); + let gas_cost = n_rounds_as_u64 + * self.context.gas_costs().syscalls.keccak_round_cost.base_syscall_cost(); + + if gas_cost > *remaining_gas { + let out_of_gas_error = Felt::from_hex(OUT_OF_GAS_ERROR) + .expect("Failed to parse OUT_OF_GAS_ERROR hex string"); + + return Err(SyscallExecutionError::Revert { error_data: vec![out_of_gas_error] }); + } + *remaining_gas -= gas_cost; + + let mut state = [0u64; 25]; + for chunk in input.chunks(KECCAK_FULL_RATE_IN_WORDS) { + for (i, val) in chunk.iter().enumerate() { + state[i] ^= val; + } + keccak::f1600(&mut state) + } + + Ok((state[..4].try_into().expect("Slice with incorrect length"), n_rounds)) + } + pub fn finalize(&mut self) { self.context .revert_infos .0 - .last_mut() + .get_mut(self.revert_info_idx) .expect("Missing contract revert info.") .original_values = std::mem::take(&mut self.original_values); } diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/builtins_test.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/builtins_test.rs new file mode 100644 index 00000000000..31332afdc5e --- /dev/null +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/builtins_test.rs @@ -0,0 +1,78 @@ +use std::sync::Arc; + +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; +use blockifier_test_utils::contracts::FeatureContract; +use rstest::rstest; +use rstest_reuse::apply; +use starknet_api::abi::abi_utils::selector_from_name; +use starknet_api::calldata; + +use crate::blockifier_versioned_constants::BuiltinGasCosts; +use crate::context::{BlockContext, ChainInfo}; +use crate::execution::entry_point::CallEntryPoint; +use crate::test_utils::initial_test_state::test_state; +use crate::test_utils::test_templates::runnable_version; +use crate::test_utils::{trivial_external_entry_point_new, BALANCE}; + +const TESTED_BUILTIN_GAS_COST: u64 = u64::pow(10, 7); + +#[apply(runnable_version)] +#[case::pedersen("test_pedersen")] +#[case::bitwise("test_bitwise")] +#[case::ecop("test_ecop")] +#[case::poseidon("test_poseidon")] +// This test case tests the add_mod and mul_mod builtins. +#[case::add_and_mul_mod("test_circuit")] +fn builtins_test(runnable_version: RunnableCairo1, #[case] selector_name: &str) { + let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1(runnable_version)); + let chain_info = &ChainInfo::create_for_testing(); + let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); + + let calldata = calldata![]; + let entry_point_call = CallEntryPoint { + entry_point_selector: selector_from_name(selector_name), + calldata, + ..trivial_external_entry_point_new(test_contract) + }; + + let mut block_context = BlockContext::create_for_account_testing(); + assert!( + block_context.versioned_constants.os_constants.execute_max_sierra_gas.0 + > TESTED_BUILTIN_GAS_COST + ); + change_builtins_gas_cost(&mut block_context, selector_name); + let mut minimal_gas = TESTED_BUILTIN_GAS_COST; + if selector_name == "test_circuit" { + minimal_gas *= 2; + } + + let call_info = + entry_point_call.execute_directly_given_block_context(&mut state, block_context).unwrap(); + + assert!(!call_info.execution.failed, "Execution failed"); + assert!(call_info.execution.gas_consumed >= minimal_gas); +} + +fn change_builtins_gas_cost(block_context: &mut BlockContext, selector_name: &str) { + let os_constants = Arc::make_mut(&mut block_context.versioned_constants.os_constants); + os_constants.gas_costs.builtins = BuiltinGasCosts::default(); + match selector_name { + "test_pedersen" => { + os_constants.gas_costs.builtins.pedersen = TESTED_BUILTIN_GAS_COST; + } + "test_bitwise" => { + os_constants.gas_costs.builtins.bitwise = TESTED_BUILTIN_GAS_COST; + } + "test_ecop" => { + os_constants.gas_costs.builtins.ecop = TESTED_BUILTIN_GAS_COST; + } + "test_poseidon" => { + os_constants.gas_costs.builtins.poseidon = TESTED_BUILTIN_GAS_COST; + } + "test_circuit" => { + os_constants.gas_costs.builtins.add_mod = TESTED_BUILTIN_GAS_COST; + os_constants.gas_costs.builtins.mul_mod = TESTED_BUILTIN_GAS_COST; + } + _ => panic!("Unknown selector name: {}", selector_name), + } +} diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/call_contract.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/call_contract.rs index 606cc9a8e82..b9c8122bd06 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_tests/call_contract.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/call_contract.rs @@ -1,6 +1,9 @@ use core::panic; use std::sync::Arc; +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; +use blockifier_test_utils::calldata::create_calldata; +use blockifier_test_utils::contracts::FeatureContract; use itertools::Itertools; use pretty_assertions::assert_eq; use rstest::rstest; @@ -16,31 +19,25 @@ use crate::execution::call_info::CallExecution; use crate::execution::contract_class::TrackedResource; use crate::execution::entry_point::CallEntryPoint; use crate::retdata; -use crate::test_utils::contracts::FeatureContract; use crate::test_utils::initial_test_state::test_state; use crate::test_utils::syscall::build_recurse_calldata; -use crate::test_utils::{ - create_calldata, - trivial_external_entry_point_new, - CairoVersion, - CompilerBasedVersion, - BALANCE, -}; - -#[cfg_attr(feature = "cairo_native", test_case(CairoVersion::Native; "Native"))] -#[test_case(CairoVersion::Cairo1;"VM")] -fn test_call_contract_that_panics(cairo_version: CairoVersion) { - let test_contract = FeatureContract::TestContract(cairo_version); - let empty_contract = FeatureContract::Empty(CairoVersion::Cairo1); +use crate::test_utils::{trivial_external_entry_point_new, CompilerBasedVersion, BALANCE}; + +#[cfg_attr(feature = "cairo_native", test_case(RunnableCairo1::Native; "Native"))] +#[test_case(RunnableCairo1::Casm;"VM")] +fn test_call_contract_that_panics(runnable_version: RunnableCairo1) { + let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1(runnable_version)); + let empty_contract = FeatureContract::Empty(CairoVersion::Cairo1(runnable_version)); let chain_info = &ChainInfo::create_for_testing(); let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1), (empty_contract, 0)]); let new_class_hash = empty_contract.get_class_hash(); + let to_panic = true.into(); let outer_entry_point_selector = selector_from_name("test_call_contract_revert"); let calldata = create_calldata( - FeatureContract::TestContract(CairoVersion::Cairo1).get_instance_address(0), + test_contract.get_instance_address(0), "test_revert_helper", - &[new_class_hash.0], + &[new_class_hash.0, to_panic], ); let entry_point_call = CallEntryPoint { entry_point_selector: outer_entry_point_selector, @@ -68,17 +65,152 @@ fn test_call_contract_that_panics(cairo_version: CairoVersion) { } } +#[rstest] +#[cfg_attr(feature = "cairo_native", case::native(RunnableCairo1::Native))] +#[case::vm(RunnableCairo1::Casm)] +/// This test verifies the behavior of a contract call sequence with nested calls and state +/// assertions. +/// +/// - Contract A calls Contract B and asserts that the state remains unchanged. +/// - Contract B calls Contract C and panics. +/// - Contract C modifies the state but does not panic. +/// +/// The test ensures that: +/// 1. Contract A's state remains unaffected despite the modifications in Contract C. +/// 2. Contract B error as expected. +/// 3. Tracked resources are correctly identified as SierraGas in all calls. +fn test_call_contract_and_than_revert(#[case] runnable_version: RunnableCairo1) { + let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1(runnable_version)); + let empty_contract = FeatureContract::Empty(CairoVersion::Cairo1(runnable_version)); + let chain_info = &ChainInfo::create_for_testing(); + let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1), (empty_contract, 0)]); + + // Arguments of Contact C. + let new_class_hash = empty_contract.get_class_hash(); + let to_panic = false.into(); + + // Calldata of contract B + let middle_call_data = create_calldata( + test_contract.get_instance_address(0), + "test_revert_helper", + &[new_class_hash.0, to_panic], + ); + + // Calldata of contract A + let calldata = create_calldata( + test_contract.get_instance_address(0), + "middle_revert_contract", + &middle_call_data.0, + ); + + // Create the entry point call to contract A. + let outer_entry_point_selector = selector_from_name("test_call_contract_revert"); + let entry_point_call = CallEntryPoint { + entry_point_selector: outer_entry_point_selector, + calldata, + ..trivial_external_entry_point_new(test_contract) + }; + + // Execute. + let call_info_a = entry_point_call.execute_directly(&mut state).unwrap(); + + // Contract A should not fail. + assert!(!call_info_a.execution.failed); + + // Contract B should fail. + let [inner_call_b] = &call_info_a.inner_calls[..] else { + panic!("Expected one inner call, got {:?}", call_info_a.inner_calls); + }; + assert!(inner_call_b.execution.failed); + assert!(inner_call_b.execution.events.is_empty()); + assert!(inner_call_b.execution.l2_to_l1_messages.is_empty()); + assert_eq!( + format_panic_data(&inner_call_b.execution.retdata.0), + "0x657865637574655f616e645f726576657274 ('execute_and_revert')" + ); + + // Contract C should not fail. + let [inner_inner_call_c] = &inner_call_b.inner_calls[..] else { + panic!("Expected one inner call, got {:?}", inner_call_b.inner_calls); + }; + assert!(!inner_inner_call_c.execution.failed); + + // Contract C events and messages should be reverted, + // since his parent (contract B) panics. + assert!(inner_inner_call_c.execution.events.is_empty()); + assert!(inner_inner_call_c.execution.l2_to_l1_messages.is_empty()); + + // Check that the tracked resource is SierraGas to make sure that Native is running. + for call in call_info_a.iter() { + assert_eq!(call.tracked_resource, TrackedResource::SierraGas); + } +} + +#[rstest] +#[cfg_attr(feature = "cairo_native", case::native(RunnableCairo1::Native))] +#[case::vm(RunnableCairo1::Casm)] +/// This test verifies the behavior of a contract call with inner calls where both try to change +/// the storage, but one succeeds and the other fails (panics). +/// +/// - Contract A call contact B. +/// - Contract B changes the storage value from 0 to 10. +/// - Contract A call contact C. +/// - Contract C changes the storage value from 10 to 17 and panics. +/// - Contract A checks that storage value == 10. +fn test_revert_with_inner_call_and_reverted_storage(#[case] runnable_version: RunnableCairo1) { + let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1(runnable_version)); + let empty_contract = FeatureContract::Empty(CairoVersion::Cairo1(runnable_version)); + let chain_info = &ChainInfo::create_for_testing(); + let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1), (empty_contract, 0)]); + + // Calldata of contract A + let calldata = Calldata( + [test_contract.get_instance_address(0).into(), empty_contract.get_class_hash().0] + .to_vec() + .into(), + ); + + // Create the entry point call to contract A. + let outer_entry_point_selector = + selector_from_name("test_revert_with_inner_call_and_reverted_storage"); + let entry_point_call = CallEntryPoint { + entry_point_selector: outer_entry_point_selector, + calldata, + ..trivial_external_entry_point_new(test_contract) + }; + + // Execute. + let outer_call = entry_point_call.execute_directly(&mut state).unwrap(); + + // The outer call (contract A) should not fail. + assert!(!outer_call.execution.failed); + + let [inner_call_to_b, inner_call_to_c] = &outer_call.inner_calls[..] else { + panic!("Expected two inner calls, got {:?}", outer_call.inner_calls); + }; + + // The first inner call (contract B) should not fail. + assert!(inner_call_to_c.execution.failed); + // The second inner call (contract C) should fail. + assert!(!inner_call_to_b.execution.failed); + + // Check that the tracked resource is SierraGas to make sure that Native is running. + for call in outer_call.iter() { + assert_eq!(call.tracked_resource, TrackedResource::SierraGas); + } +} + #[cfg_attr( feature = "cairo_native", test_case( - FeatureContract::TestContract(CairoVersion::Native), - FeatureContract::TestContract(CairoVersion::Native); + FeatureContract::TestContract(CairoVersion::Cairo1(RunnableCairo1::Native)), + FeatureContract::TestContract(CairoVersion::Cairo1(RunnableCairo1::Native)); "Call Contract between two contracts using Native" ) )] #[test_case( - FeatureContract::TestContract(CairoVersion::Cairo1), - FeatureContract::TestContract(CairoVersion::Cairo1); + FeatureContract::TestContract(CairoVersion::Cairo1(RunnableCairo1::Casm)), + FeatureContract::TestContract(CairoVersion::Cairo1(RunnableCairo1::Casm)); "Call Contract between two contracts using VM" )] fn test_call_contract(outer_contract: FeatureContract, inner_contract: FeatureContract) { @@ -117,15 +249,15 @@ fn test_tracked_resources( #[values( CompilerBasedVersion::CairoVersion(CairoVersion::Cairo0), CompilerBasedVersion::OldCairo1, - CompilerBasedVersion::CairoVersion(CairoVersion::Cairo1), - CompilerBasedVersion::CairoVersion(CairoVersion::Native) + CompilerBasedVersion::CairoVersion(CairoVersion::Cairo1(RunnableCairo1::Casm)), + CompilerBasedVersion::CairoVersion(CairoVersion::Cairo1(RunnableCairo1::Native)) )] outer_version: CompilerBasedVersion, #[values( CompilerBasedVersion::CairoVersion(CairoVersion::Cairo0), CompilerBasedVersion::OldCairo1, - CompilerBasedVersion::CairoVersion(CairoVersion::Cairo1), - CompilerBasedVersion::CairoVersion(CairoVersion::Native) + CompilerBasedVersion::CairoVersion(CairoVersion::Cairo1(RunnableCairo1::Casm)), + CompilerBasedVersion::CairoVersion(CairoVersion::Cairo1(RunnableCairo1::Native)) )] inner_version: CompilerBasedVersion, ) { @@ -139,13 +271,13 @@ fn test_tracked_resources( #[values( CompilerBasedVersion::CairoVersion(CairoVersion::Cairo0), CompilerBasedVersion::OldCairo1, - CompilerBasedVersion::CairoVersion(CairoVersion::Cairo1) + CompilerBasedVersion::CairoVersion(CairoVersion::Cairo1(RunnableCairo1::Casm)) )] outer_version: CompilerBasedVersion, #[values( CompilerBasedVersion::CairoVersion(CairoVersion::Cairo0), CompilerBasedVersion::OldCairo1, - CompilerBasedVersion::CairoVersion(CairoVersion::Cairo1) + CompilerBasedVersion::CairoVersion(CairoVersion::Cairo1(RunnableCairo1::Casm)) )] inner_version: CompilerBasedVersion, ) { @@ -185,15 +317,15 @@ fn test_tracked_resources_fn( assert_eq!(execution.inner_calls.first().unwrap().tracked_resource, expected_inner_resource); } -#[test_case(CompilerBasedVersion::CairoVersion(CairoVersion::Cairo0), CompilerBasedVersion::CairoVersion(CairoVersion::Cairo1); "Cairo0_and_Cairo1")] -#[test_case(CompilerBasedVersion::OldCairo1, CompilerBasedVersion::CairoVersion(CairoVersion::Cairo1); "OldCairo1_and_Cairo1")] +#[test_case(CompilerBasedVersion::CairoVersion(CairoVersion::Cairo0), CompilerBasedVersion::CairoVersion(CairoVersion::Cairo1(RunnableCairo1::Casm)); "Cairo0_and_Cairo1")] +#[test_case(CompilerBasedVersion::OldCairo1, CompilerBasedVersion::CairoVersion(CairoVersion::Cairo1(RunnableCairo1::Casm)); "OldCairo1_and_Cairo1")] #[cfg_attr( feature = "cairo_native", - test_case(CompilerBasedVersion::CairoVersion(CairoVersion::Cairo0), CompilerBasedVersion::CairoVersion(CairoVersion::Native); "Cairo0_and_Native") + test_case(CompilerBasedVersion::CairoVersion(CairoVersion::Cairo0), CompilerBasedVersion::CairoVersion(CairoVersion::Cairo1(RunnableCairo1::Native)); "Cairo0_and_Native") )] #[cfg_attr( feature = "cairo_native", - test_case(CompilerBasedVersion::OldCairo1, CompilerBasedVersion::CairoVersion(CairoVersion::Native); "OldCairo1_and_Native") + test_case(CompilerBasedVersion::OldCairo1, CompilerBasedVersion::CairoVersion(CairoVersion::Cairo1(RunnableCairo1::Native)); "OldCairo1_and_Native") )] fn test_tracked_resources_nested( cairo_steps_contract_version: CompilerBasedVersion, @@ -221,16 +353,46 @@ fn test_tracked_resources_nested( calldata: concated_calldata, ..trivial_external_entry_point_new(sierra_gas_contract) }; - let execution = entry_point_call.execute_directly(&mut state).unwrap(); + let main_call_info = entry_point_call.execute_directly(&mut state).unwrap(); - assert_eq!(execution.tracked_resource, TrackedResource::SierraGas); - let first_call_info = execution.inner_calls.first().unwrap(); - assert_eq!(first_call_info.tracked_resource, TrackedResource::CairoSteps); - assert_eq!( - first_call_info.inner_calls.first().unwrap().tracked_resource, - TrackedResource::CairoSteps + assert_eq!(main_call_info.tracked_resource, TrackedResource::SierraGas); + assert_ne!(main_call_info.execution.gas_consumed, 0); + + let first_inner_call = main_call_info.inner_calls.first().unwrap(); + assert_eq!(first_inner_call.tracked_resource, TrackedResource::CairoSteps); + assert_eq!(first_inner_call.execution.gas_consumed, 0); + let inner_inner_call = first_inner_call.inner_calls.first().unwrap(); + assert_eq!(inner_inner_call.tracked_resource, TrackedResource::CairoSteps); + assert_eq!(inner_inner_call.execution.gas_consumed, 0); + + let second_inner_call = main_call_info.inner_calls.get(1).unwrap(); + assert_eq!(second_inner_call.tracked_resource, TrackedResource::SierraGas); + assert_ne!(second_inner_call.execution.gas_consumed, 0); +} + +#[rstest] +#[case(RunnableCairo1::Casm)] +#[cfg_attr(feature = "cairo_native", case(RunnableCairo1::Native))] +fn test_empty_function_flow(#[case] runnable: RunnableCairo1) { + let outer_contract = FeatureContract::TestContract(CairoVersion::Cairo1(runnable)); + let chain_info = &ChainInfo::create_for_testing(); + let mut state = test_state(chain_info, BALANCE, &[(outer_contract, 1)]); + let test_contract_address = outer_contract.get_instance_address(0); + + let calldata = create_calldata( + test_contract_address, + "empty_function", + &[], // Calldata. ); + let outer_entry_point_selector = selector_from_name("test_call_contract"); + let entry_point_call = CallEntryPoint { + entry_point_selector: outer_entry_point_selector, + calldata, + ..trivial_external_entry_point_new(outer_contract) + }; + + let call_info = entry_point_call.execute_directly(&mut state).unwrap(); - let second_inner_call_info = execution.inner_calls.get(1).unwrap(); - assert_eq!(second_inner_call_info.tracked_resource, TrackedResource::SierraGas); + // Contract should not fail. + assert!(!call_info.execution.failed); } diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/constants.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/constants.rs index daf276fd656..7d0016473aa 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_tests/constants.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/constants.rs @@ -1,4 +1,5 @@ -pub const REQUIRED_GAS_CALL_CONTRACT_TEST: u64 = 170370; -pub const REQUIRED_GAS_STORAGE_READ_WRITE_TEST: u64 = 16990; -pub const REQUIRED_GAS_GET_CLASS_HASH_AT_TEST: u64 = 7830; -pub const REQUIRED_GAS_LIBRARY_CALL_TEST: u64 = 167970; +pub const REQUIRED_GAS_CALL_CONTRACT_TEST: u64 = 134530; +pub const REQUIRED_GAS_STORAGE_READ_WRITE_TEST: u64 = 27550; +pub const REQUIRED_GAS_GET_CLASS_HASH_AT_TEST: u64 = 17760; +pub const REQUIRED_GAS_LIBRARY_CALL_TEST: u64 = 132130; +pub const REQUIRED_GAS_GET_BLOCK_HASH_TEST: u64 = 16220; diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/deploy.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/deploy.rs index 8bf28078521..adf4123dace 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_tests/deploy.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/deploy.rs @@ -1,25 +1,32 @@ +use std::collections::HashMap; + +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; +use blockifier_test_utils::contracts::FeatureContract; +use cairo_vm::types::builtin_name::BuiltinName; use pretty_assertions::assert_eq; use starknet_api::abi::abi_utils::selector_from_name; +use starknet_api::contract_class::SierraVersion; use starknet_api::core::calculate_contract_address; use starknet_api::transaction::fields::{Calldata, ContractAddressSalt, Fee}; use starknet_api::{calldata, felt}; use test_case::test_case; -use crate::context::ChainInfo; +use crate::context::{BlockContext, ChainInfo}; use crate::execution::call_info::CallExecution; use crate::execution::entry_point::CallEntryPoint; +use crate::execution::syscalls::hint_processor::SyscallUsage; +use crate::execution::syscalls::SyscallSelector; use crate::retdata; use crate::state::state_api::StateReader; -use crate::test_utils::contracts::FeatureContract; use crate::test_utils::initial_test_state::test_state; -use crate::test_utils::{calldata_for_deploy_test, trivial_external_entry_point_new, CairoVersion}; +use crate::test_utils::{calldata_for_deploy_test, trivial_external_entry_point_new}; -#[test_case(CairoVersion::Cairo1;"VM")] -#[cfg_attr(feature = "cairo_native", test_case(CairoVersion::Native;"Native"))] -fn no_constructor(cairo_version: CairoVersion) { +#[test_case(RunnableCairo1::Casm;"VM")] +#[cfg_attr(feature = "cairo_native", test_case(RunnableCairo1::Native;"Native"))] +fn no_constructor(runnable_version: RunnableCairo1) { // TODO(Yoni): share the init code of the tests in this file. - let deployer_contract = FeatureContract::TestContract(cairo_version); - let empty_contract = FeatureContract::Empty(CairoVersion::Cairo1); + let deployer_contract = FeatureContract::TestContract(CairoVersion::Cairo1(runnable_version)); + let empty_contract = FeatureContract::Empty(CairoVersion::Cairo1(runnable_version)); let class_hash = empty_contract.get_class_hash(); let mut state = test_state( @@ -38,7 +45,7 @@ fn no_constructor(cairo_version: CairoVersion) { let deploy_call = &entry_point_call.execute_directly(&mut state).unwrap(); assert_eq!( deploy_call.execution, - CallExecution { retdata: retdata![], gas_consumed: 205200, ..CallExecution::default() } + CallExecution { retdata: retdata![], gas_consumed: 158600, ..CallExecution::default() } ); let deployed_contract_address = calculate_contract_address( @@ -59,11 +66,11 @@ fn no_constructor(cairo_version: CairoVersion) { assert_eq!(state.get_class_hash_at(deployed_contract_address).unwrap(), class_hash); } -#[test_case(CairoVersion::Cairo1;"VM")] -#[cfg_attr(feature = "cairo_native", test_case(CairoVersion::Native;"Native"))] -fn no_constructor_nonempty_calldata(cairo_version: CairoVersion) { - let deployer_contract = FeatureContract::TestContract(cairo_version); - let empty_contract = FeatureContract::Empty(CairoVersion::Cairo1); +#[test_case(RunnableCairo1::Casm;"VM")] +#[cfg_attr(feature = "cairo_native", test_case(RunnableCairo1::Native;"Native"))] +fn no_constructor_nonempty_calldata(runnable_version: RunnableCairo1) { + let deployer_contract = FeatureContract::TestContract(CairoVersion::Cairo1(runnable_version)); + let empty_contract = FeatureContract::Empty(CairoVersion::Cairo1(runnable_version)); let class_hash = empty_contract.get_class_hash(); let mut state = test_state( @@ -87,10 +94,10 @@ fn no_constructor_nonempty_calldata(cairo_version: CairoVersion) { )); } -#[test_case(CairoVersion::Cairo1;"VM")] -#[cfg_attr(feature = "cairo_native", test_case(CairoVersion::Native;"Native"))] -fn with_constructor(cairo_version: CairoVersion) { - let deployer_contract = FeatureContract::TestContract(cairo_version); +#[test_case(RunnableCairo1::Casm;"VM")] +#[cfg_attr(feature = "cairo_native", test_case(RunnableCairo1::Native;"Native"))] +fn with_constructor(runnable_version: RunnableCairo1) { + let deployer_contract = FeatureContract::TestContract(CairoVersion::Cairo1(runnable_version)); let mut state = test_state(&ChainInfo::create_for_testing(), Fee(0), &[(deployer_contract, 1)]); let class_hash = deployer_contract.get_class_hash(); @@ -117,9 +124,10 @@ fn with_constructor(cairo_version: CairoVersion) { .unwrap(); let deploy_call = &entry_point_call.execute_directly(&mut state).unwrap(); + assert_eq!( deploy_call.execution, - CallExecution { retdata: retdata![], gas_consumed: 214550, ..CallExecution::default() } + CallExecution { retdata: retdata![], gas_consumed: 188780, ..CallExecution::default() } ); let constructor_call = &deploy_call.inner_calls[0]; @@ -131,17 +139,17 @@ fn with_constructor(cairo_version: CairoVersion) { // The test contract constructor returns its first argument. retdata: retdata![constructor_calldata[0]], // This reflects the gas cost of storage write syscall. - gas_consumed: 4610, + gas_consumed: 15140, ..CallExecution::default() } ); assert_eq!(state.get_class_hash_at(contract_address).unwrap(), class_hash); } -#[test_case(CairoVersion::Cairo1;"VM")] -#[cfg_attr(feature = "cairo_native", test_case(CairoVersion::Native;"Native"))] -fn to_unavailable_address(cairo_version: CairoVersion) { - let deployer_contract = FeatureContract::TestContract(cairo_version); +#[test_case(RunnableCairo1::Casm;"VM")] +#[cfg_attr(feature = "cairo_native", test_case(RunnableCairo1::Native;"Native"))] +fn to_unavailable_address(runnable_version: RunnableCairo1) { + let deployer_contract = FeatureContract::TestContract(CairoVersion::Cairo1(runnable_version)); let mut state = test_state(&ChainInfo::create_for_testing(), Fee(0), &[(deployer_contract, 1)]); let class_hash = deployer_contract.get_class_hash(); @@ -163,3 +171,129 @@ fn to_unavailable_address(cairo_version: CairoVersion) { assert!(error.contains("Deployment failed:")); } + +/// Test that call data length affects the call info resources. +/// Specifcly every argument in the call data add 1 pedersen builtin. +#[test_case(CairoVersion::Cairo1(RunnableCairo1::Casm);"Cairo1-VM")] +#[test_case(CairoVersion::Cairo0;"Cairo0")] +fn calldata_length(cairo_version: CairoVersion) { + // Test contract: (constructor gets 2 arguments) + let test_contract = FeatureContract::TestContract(cairo_version); + // Account contract: (constructor gets 1 argument) + let account_contract = FeatureContract::FaultyAccount(cairo_version); + // Empty contract. + let empty_contract = FeatureContract::Empty(cairo_version); + + let mut state = test_state( + &ChainInfo::create_for_testing(), + Fee(0), + &[(test_contract, 1), (account_contract, 0), (empty_contract, 0)], + ); + + // Use the maximum sierra version to avoid using sierra gas as the tracked resource. + let max_sierra_version = SierraVersion::new(u64::MAX, u64::MAX, u64::MAX); + let mut block_context = BlockContext::create_for_testing(); + block_context.versioned_constants.min_sierra_version_for_sierra_gas = max_sierra_version; + + // Flag of deploy syscall. + let deploy_from_zero = true; + + // Deploy account contract. + let account_constructor_calldata = vec![felt!(0_u8)]; + let calldata = calldata_for_deploy_test( + account_contract.get_class_hash(), + &account_constructor_calldata, + deploy_from_zero, + ); + let deploy_account_call = CallEntryPoint { + entry_point_selector: selector_from_name("test_deploy"), + calldata, + ..trivial_external_entry_point_new(test_contract) + }; + let deploy_account_call_info = &deploy_account_call + .execute_directly_given_block_context(&mut state, block_context.clone()) + .unwrap(); + + // Deploy test contract. + let test_constructor_calldata = vec![felt!(1_u8), felt!(1_u8)]; + let calldata = calldata_for_deploy_test( + test_contract.get_class_hash(), + &test_constructor_calldata, + deploy_from_zero, + ); + let deploy_test_call = CallEntryPoint { + entry_point_selector: selector_from_name("test_deploy"), + calldata, + ..trivial_external_entry_point_new(test_contract) + }; + let deploy_test_call_info = deploy_test_call + .execute_directly_given_block_context(&mut state, block_context.clone()) + .unwrap(); + + // Deploy empty contract. + let calldata = calldata_for_deploy_test(empty_contract.get_class_hash(), &[], deploy_from_zero); + let deploy_empty_call = CallEntryPoint { + entry_point_selector: selector_from_name("test_deploy"), + calldata, + ..trivial_external_entry_point_new(test_contract) + }; + let deploy_empty_call_info = deploy_empty_call + .execute_directly_given_block_context(&mut state, block_context.clone()) + .unwrap(); + + // Extract pedersen counter from each call. + let deploy_empty_call_pedersen = deploy_empty_call_info + .resources + .builtin_instance_counter + .get(&BuiltinName::pedersen) + .copied() + .unwrap(); + + let deploy_account_pedersen = deploy_account_call_info + .resources + .builtin_instance_counter + .get(&BuiltinName::pedersen) + .copied() + .unwrap(); + let deploy_test_pedersen = deploy_test_call_info + .resources + .builtin_instance_counter + .get(&BuiltinName::pedersen) + .copied() + .unwrap(); + + // Verify that pedersen cost = base_pedersen cost + + // deploy_syscall_linear_factor_cost*linear_factor. + let deploy_syscall_base_pedersen_cost = block_context + .versioned_constants + .get_additional_os_syscall_resources(&HashMap::from([( + SyscallSelector::Deploy, + (SyscallUsage::new(1, 0)), + )])) + .builtin_instance_counter + .get(&BuiltinName::pedersen) + .copied() + .unwrap(); + let deploy_syscall_linear_factor_cost = block_context + .versioned_constants + .get_additional_os_syscall_resources(&HashMap::from([( + SyscallSelector::Deploy, + (SyscallUsage::new(0, 1)), + )])) + .builtin_instance_counter + .get(&BuiltinName::pedersen) + .copied() + .unwrap(); + + assert!( + deploy_syscall_base_pedersen_cost + + test_constructor_calldata.len() * deploy_syscall_linear_factor_cost + == deploy_test_pedersen + ); + assert!( + deploy_syscall_base_pedersen_cost + + account_constructor_calldata.len() * deploy_syscall_linear_factor_cost + == deploy_account_pedersen + ); + assert!(deploy_empty_call_pedersen == deploy_syscall_base_pedersen_cost); +} diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/emit_event.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/emit_event.rs index 46e7564bd22..e85eec1f754 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_tests/emit_event.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/emit_event.rs @@ -1,3 +1,5 @@ +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; +use blockifier_test_utils::contracts::FeatureContract; use itertools::concat; #[cfg(feature = "cairo_native")] use pretty_assertions::assert_eq; @@ -8,15 +10,14 @@ use starknet_api::transaction::{EventContent, EventData, EventKey}; use starknet_types_core::felt::Felt; use test_case::test_case; +use crate::blockifier_versioned_constants::VersionedConstants; use crate::context::ChainInfo; use crate::execution::call_info::{CallExecution, CallInfo, OrderedEvent}; use crate::execution::entry_point::CallEntryPoint; use crate::execution::errors::EntryPointExecutionError; use crate::execution::syscalls::hint_processor::EmitEventError; -use crate::test_utils::contracts::FeatureContract; use crate::test_utils::initial_test_state::test_state; -use crate::test_utils::{trivial_external_entry_point_new, CairoVersion, BALANCE}; -use crate::versioned_constants::VersionedConstants; +use crate::test_utils::{trivial_external_entry_point_new, BALANCE}; const KEYS: [Felt; 2] = [Felt::from_hex_unchecked("0x2019"), Felt::from_hex_unchecked("0x2020")]; const DATA: [Felt; 3] = [ @@ -26,10 +27,10 @@ const DATA: [Felt; 3] = [ ]; const N_EMITTED_EVENTS: [Felt; 1] = [Felt::from_hex_unchecked("0x1")]; -#[cfg_attr(feature = "cairo_native", test_case(CairoVersion::Native;"Native"))] -#[test_case(CairoVersion::Cairo1;"VM")] -fn positive_flow(cairo_version: CairoVersion) { - let test_contract = FeatureContract::TestContract(cairo_version); +#[cfg_attr(feature = "cairo_native", test_case(RunnableCairo1::Native;"Native"))] +#[test_case(RunnableCairo1::Casm;"VM")] +fn positive_flow(runnable_version: RunnableCairo1) { + let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1(runnable_version)); let call_info = emit_events(test_contract, &N_EMITTED_EVENTS, &KEYS, &DATA) .expect("emit_events failed with valued parameters"); let event = EventContent { @@ -41,16 +42,16 @@ fn positive_flow(cairo_version: CairoVersion) { call_info.execution, CallExecution { events: vec![OrderedEvent { order: 0, event }], - gas_consumed: 47330, + gas_consumed: 41880, ..Default::default() } ); } -#[cfg_attr(feature = "cairo_native", test_case(CairoVersion::Native;"Native"))] -#[test_case(CairoVersion::Cairo1;"VM")] -fn data_length_exceeds_limit(cairo_version: CairoVersion) { - let test_contract = FeatureContract::TestContract(cairo_version); +#[cfg_attr(feature = "cairo_native", test_case(RunnableCairo1::Native;"Native"))] +#[test_case(RunnableCairo1::Casm;"VM")] +fn data_length_exceeds_limit(runnable_version: RunnableCairo1) { + let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1(runnable_version)); let versioned_constants = VersionedConstants::create_for_testing(); let max_event_data_length = versioned_constants.tx_event_limits.max_data_length; @@ -67,10 +68,10 @@ fn data_length_exceeds_limit(cairo_version: CairoVersion) { assert!(error_message.contains(&expected_error.to_string())); } -#[cfg_attr(feature = "cairo_native", test_case(CairoVersion::Native;"Native"))] -#[test_case(CairoVersion::Cairo1;"VM")] -fn keys_length_exceeds_limit(cairo_version: CairoVersion) { - let test_contract = FeatureContract::TestContract(cairo_version); +#[cfg_attr(feature = "cairo_native", test_case(RunnableCairo1::Native;"Native"))] +#[test_case(RunnableCairo1::Casm;"VM")] +fn keys_length_exceeds_limit(runnable_version: RunnableCairo1) { + let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1(runnable_version)); let versioned_constants = VersionedConstants::create_for_testing(); let max_event_keys_length = versioned_constants.tx_event_limits.max_keys_length; @@ -88,10 +89,10 @@ fn keys_length_exceeds_limit(cairo_version: CairoVersion) { assert!(error_message.contains(&expected_error.to_string())); } -#[cfg_attr(feature = "cairo_native", test_case(CairoVersion::Native;"Native"))] -#[test_case(CairoVersion::Cairo1;"VM")] -fn event_number_exceeds_limit(cairo_version: CairoVersion) { - let test_contract = FeatureContract::TestContract(cairo_version); +#[cfg_attr(feature = "cairo_native", test_case(RunnableCairo1::Native;"Native"))] +#[test_case(RunnableCairo1::Casm;"VM")] +fn event_number_exceeds_limit(runnable_version: RunnableCairo1) { + let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1(runnable_version)); let versioned_constants = VersionedConstants::create_for_testing(); let max_n_emitted_events = versioned_constants.tx_event_limits.max_n_emitted_events; diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/get_block_hash.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/get_block_hash.rs index 83c7af1a633..cc88d38abd1 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_tests/get_block_hash.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/get_block_hash.rs @@ -1,30 +1,31 @@ +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; +use blockifier_test_utils::contracts::FeatureContract; use pretty_assertions::assert_eq; use starknet_api::abi::abi_utils::selector_from_name; -use starknet_api::core::ContractAddress; +use starknet_api::block::{BlockHash, BlockNumber}; use starknet_api::execution_utils::format_panic_data; use starknet_api::state::StorageKey; +use starknet_api::test_utils::CURRENT_BLOCK_NUMBER; use starknet_api::{calldata, felt}; use starknet_types_core::felt::Felt; use test_case::test_case; use crate::abi::constants; +use crate::blockifier_versioned_constants::VersionedConstants; use crate::context::ChainInfo; use crate::execution::call_info::CallExecution; use crate::execution::entry_point::CallEntryPoint; +use crate::execution::syscalls::syscall_tests::constants::REQUIRED_GAS_GET_BLOCK_HASH_TEST; +use crate::retdata; use crate::state::cached_state::CachedState; use crate::state::state_api::State; -use crate::test_utils::contracts::FeatureContract; use crate::test_utils::dict_state_reader::DictStateReader; use crate::test_utils::initial_test_state::test_state; -use crate::test_utils::{ - trivial_external_entry_point_new, - CairoVersion, - BALANCE, - CURRENT_BLOCK_NUMBER, -}; -use crate::{check_entry_point_execution_error_for_custom_hint, retdata}; +use crate::test_utils::{trivial_external_entry_point_new, BALANCE}; -fn initialize_state(test_contract: FeatureContract) -> (CachedState, Felt, Felt) { +pub fn initialize_state( + test_contract: FeatureContract, +) -> (CachedState, Felt, Felt) { let chain_info = &ChainInfo::create_for_testing(); let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); @@ -33,17 +34,19 @@ fn initialize_state(test_contract: FeatureContract) -> (CachedState [ // Rounded block number. @@ -166,6 +339,11 @@ fn test_get_execution_info( let test_contract_address = test_contract.get_instance_address(0); + // Transaction tip. + let tip = Tip(VersionedConstants::latest_constants().os_constants.v1_bound_accounts_max_tip.0 + + if high_tip { 1 } else { 0 }); + let expected_tip = if version == TransactionVersion::THREE { tip } else { Tip(0) }; + let expected_unsupported_fields = match test_contract { FeatureContract::LegacyTestContract => { // Read and parse file content. @@ -180,64 +358,72 @@ fn test_get_execution_info( vec![] } #[cfg(feature = "cairo_native")] - FeatureContract::SierraExecutionInfoV1Contract => { + FeatureContract::SierraExecutionInfoV1Contract(RunnableCairo1::Native) => { vec![] } _ => { vec![ - Felt::ZERO, // Tip. - Felt::ZERO, // Paymaster data. - Felt::ZERO, // Nonce DA. - Felt::ZERO, // Fee DA. - Felt::ZERO, // Account data. + expected_tip.into(), // Tip. + Felt::ZERO, // Paymaster data. + Felt::ZERO, // Nonce DA. + Felt::ZERO, // Fee DA. + Felt::ZERO, // Account data. ] } }; + let mut expected_version = if v1_bound_account && !high_tip { 1.into() } else { version.0 }; if only_query { let simulate_version_base = *QUERY_VERSION_BASE; let query_version = simulate_version_base + version.0; version = TransactionVersion(query_version); + expected_version += simulate_version_base; } - let tx_hash = TransactionHash(felt!(1991_u16)); + let tx_hash = tx_hash!(1991); let max_fee = Fee(42); let nonce = nonce!(3_u16); let sender_address = test_contract_address; - let max_amount = GasAmount(13); - let max_price_per_unit = GasPrice(61); + let resource_bounds = + ResourceBounds { max_amount: GasAmount(13), max_price_per_unit: GasPrice(61) }; + let all_resource_bounds = ValidResourceBounds::AllResources(AllResourceBounds { + l1_gas: resource_bounds, + l2_gas: resource_bounds, + l1_data_gas: resource_bounds, + }); let expected_resource_bounds: Vec = match (test_contract, version) { (FeatureContract::LegacyTestContract, _) => vec![], #[cfg(feature = "cairo_native")] - (FeatureContract::SierraExecutionInfoV1Contract, _) => vec![], + (FeatureContract::SierraExecutionInfoV1Contract(RunnableCairo1::Native), _) => vec![], (_, version) if version == TransactionVersion::ONE => vec![ felt!(0_u16), // Length of resource bounds array. ], - (_, _) => vec![ - Felt::from(2u32), // Length of ResourceBounds array. - felt!(Resource::L1Gas.to_hex()), // Resource. - max_amount.into(), // Max amount. - max_price_per_unit.into(), // Max price per unit. - felt!(Resource::L2Gas.to_hex()), // Resource. - Felt::ZERO, // Max amount. - Felt::ZERO, // Max price per unit. - ], + (_, _) => { + vec![felt!(if exclude_l1_data_gas { 2_u8 } else { 3_u8 })] // Length of resource bounds array. + .into_iter() + .chain( + valid_resource_bounds_as_felts(&all_resource_bounds, exclude_l1_data_gas) + .unwrap() + .into_iter() + .flat_map(|bounds| bounds.flatten()), + ) + .collect() + } }; let expected_tx_info: Vec; let tx_info: TransactionInfo; if version == TransactionVersion::ONE { expected_tx_info = vec![ - version.0, /* Transaction - * version. */ - *sender_address.0.key(), // Account address. - felt!(max_fee.0), // Max fee. - Felt::ZERO, // Signature. - tx_hash.0, // Transaction hash. - felt!(&*ChainId::create_for_testing().as_hex()), // Chain ID. - nonce.0, // Nonce. + expected_version, // Transaction version. + *sender_address.0.key(), // Account address. + felt!(max_fee.0), // Max fee. + Felt::ZERO, // Signature. + tx_hash.0, // Transaction hash. + felt!(&*CHAIN_ID_FOR_TESTS.as_hex()), // Chain ID. + nonce.0, // Nonce. ]; tx_info = TransactionInfo::Deprecated(DeprecatedTransactionInfo { @@ -253,14 +439,13 @@ fn test_get_execution_info( }); } else { expected_tx_info = vec![ - version.0, /* Transaction - * version. */ - *sender_address.0.key(), // Account address. - Felt::ZERO, // Max fee. - Felt::ZERO, // Signature. - tx_hash.0, // Transaction hash. - felt!(&*ChainId::create_for_testing().as_hex()), // Chain ID. - nonce.0, // Nonce. + expected_version, // Transaction version. + *sender_address.0.key(), // Account address. + Felt::ZERO, // Max fee. + Felt::ZERO, // Signature. + tx_hash.0, // Transaction hash. + felt!(&*CHAIN_ID_FOR_TESTS.as_hex()), // Chain ID. + nonce.0, // Nonce. ]; tx_info = TransactionInfo::Current(CurrentTransactionInfo { @@ -272,11 +457,8 @@ fn test_get_execution_info( only_query, ..Default::default() }, - resource_bounds: ValidResourceBounds::L1Gas(ResourceBounds { - max_amount, - max_price_per_unit, - }), - tip: Tip::default(), + resource_bounds: all_resource_bounds, + tip, nonce_data_availability_mode: DataAvailabilityMode::L1, fee_data_availability_mode: DataAvailabilityMode::L1, paymaster_data: PaymasterData::default(), @@ -305,8 +487,13 @@ fn test_get_execution_info( ), ..trivial_external_entry_point_with_address(test_contract_address) }; - let result = - entry_point_call.execute_directly_given_tx_info(state, tx_info, false, execution_mode); + let result = entry_point_call.execute_directly_given_tx_info( + state, + tx_info, + None, + false, + execution_mode, + ); assert!(!result.unwrap().execution.failed); } diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/keccak.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/keccak.rs index cb7727c7386..77f81a48a2e 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_tests/keccak.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/keccak.rs @@ -1,3 +1,5 @@ +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; +use blockifier_test_utils::contracts::FeatureContract; use starknet_api::abi::abi_utils::selector_from_name; use starknet_api::transaction::fields::Calldata; use test_case::test_case; @@ -6,14 +8,13 @@ use crate::context::ChainInfo; use crate::execution::call_info::CallExecution; use crate::execution::entry_point::CallEntryPoint; use crate::retdata; -use crate::test_utils::contracts::FeatureContract; use crate::test_utils::initial_test_state::test_state; -use crate::test_utils::{trivial_external_entry_point_new, CairoVersion, BALANCE}; +use crate::test_utils::{trivial_external_entry_point_new, BALANCE}; -#[test_case(CairoVersion::Cairo1; "VM")] -#[cfg_attr(feature = "cairo_native", test_case(CairoVersion::Native; "Native"))] -fn test_keccak(cairo_version: CairoVersion) { - let test_contract = FeatureContract::TestContract(cairo_version); +#[test_case(RunnableCairo1::Casm; "VM")] +#[cfg_attr(feature = "cairo_native", test_case(RunnableCairo1::Native; "Native"))] +fn test_keccak(runnable_version: RunnableCairo1) { + let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1(runnable_version)); let chain_info = &ChainInfo::create_for_testing(); let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); @@ -26,6 +27,6 @@ fn test_keccak(cairo_version: CairoVersion) { pretty_assertions::assert_eq!( entry_point_call.execute_directly(&mut state).unwrap().execution, - CallExecution { gas_consumed: 254910, ..CallExecution::from_retdata(retdata![]) } + CallExecution { gas_consumed: 245767, ..CallExecution::from_retdata(retdata![]) } ); } diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/library_call.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/library_call.rs index 9a3ede71b5e..968c3518c67 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_tests/library_call.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/library_call.rs @@ -1,37 +1,29 @@ -use std::collections::{HashMap, HashSet}; +use std::collections::HashSet; -use cairo_vm::types::builtin_name::BuiltinName; -use cairo_vm::vm::runners::cairo_runner::ExecutionResources; +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; +use blockifier_test_utils::contracts::FeatureContract; use pretty_assertions::assert_eq; use starknet_api::abi::abi_utils::selector_from_name; -use starknet_api::execution_resources::GasAmount; -use starknet_api::transaction::fields::GasVectorComputationMode; use starknet_api::{calldata, felt, storage_key}; use test_case::test_case; +use crate::blockifier_versioned_constants::VersionedConstants; use crate::context::ChainInfo; -use crate::execution::call_info::{CallExecution, CallInfo, ChargedResources, Retdata}; +use crate::execution::call_info::{CallExecution, CallInfo, Retdata, StorageAccessTracker}; use crate::execution::entry_point::{CallEntryPoint, CallType}; use crate::execution::syscalls::syscall_tests::constants::{ REQUIRED_GAS_LIBRARY_CALL_TEST, REQUIRED_GAS_STORAGE_READ_WRITE_TEST, }; -use crate::execution::syscalls::SyscallSelector; use crate::retdata; -use crate::test_utils::contracts::FeatureContract; +use crate::test_utils::contracts::FeatureContractTrait; use crate::test_utils::initial_test_state::test_state; -use crate::test_utils::{ - get_syscall_resources, - trivial_external_entry_point_new, - CairoVersion, - BALANCE, -}; -use crate::versioned_constants::VersionedConstants; +use crate::test_utils::{trivial_external_entry_point_new, BALANCE}; -#[cfg_attr(feature = "cairo_native", test_case(CairoVersion::Native; "Native"))] -#[test_case(CairoVersion::Cairo1; "VM")] -fn test_library_call(cairo_version: CairoVersion) { - let test_contract = FeatureContract::TestContract(cairo_version); +#[cfg_attr(feature = "cairo_native", test_case(RunnableCairo1::Native; "Native"))] +#[test_case(RunnableCairo1::Casm; "VM")] +fn test_library_call(runnable_version: RunnableCairo1) { + let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1(runnable_version)); let chain_info = &ChainInfo::create_for_testing(); let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); @@ -61,10 +53,10 @@ fn test_library_call(cairo_version: CairoVersion) { ); } -#[cfg_attr(feature = "cairo_native", test_case(CairoVersion::Native; "Native"))] -#[test_case(CairoVersion::Cairo1; "VM")] -fn test_library_call_assert_fails(cairo_version: CairoVersion) { - let test_contract = FeatureContract::TestContract(cairo_version); +#[cfg_attr(feature = "cairo_native", test_case(RunnableCairo1::Native; "Native"))] +#[test_case(RunnableCairo1::Casm; "VM")] +fn test_library_call_assert_fails(runnable_version: RunnableCairo1) { + let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1(runnable_version)); let chain_info = &ChainInfo::create_for_testing(); let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); let inner_entry_point_selector = selector_from_name("assert_eq"); @@ -93,17 +85,17 @@ fn test_library_call_assert_fails(cairo_version: CairoVersion) { // 'ENTRYPOINT_FAILED'. felt!("0x454e545259504f494e545f4641494c4544") ]), - gas_consumed: 150980, + gas_consumed: 108820, failed: true, ..Default::default() } ); } -#[cfg_attr(feature = "cairo_native", test_case(CairoVersion::Native; "Native"))] -#[test_case(CairoVersion::Cairo1; "VM")] -fn test_nested_library_call(cairo_version: CairoVersion) { - let test_contract = FeatureContract::TestContract(cairo_version); +#[cfg_attr(feature = "cairo_native", test_case(RunnableCairo1::Native; "Native"))] +#[test_case(RunnableCairo1::Casm; "VM")] +fn test_nested_library_call(runnable_version: RunnableCairo1) { + let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1(runnable_version)); let chain_info = &ChainInfo::create_for_testing(); let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); @@ -133,7 +125,7 @@ fn test_nested_library_call(cairo_version: CairoVersion) { class_hash: Some(test_class_hash), code_address: None, call_type: CallType::Delegate, - initial_gas: 9998985960, + initial_gas: 9999076890, ..trivial_external_entry_point_new(test_contract) }; let library_entry_point = CallEntryPoint { @@ -148,31 +140,19 @@ fn test_nested_library_call(cairo_version: CairoVersion) { class_hash: Some(test_class_hash), code_address: None, call_type: CallType::Delegate, - initial_gas: 9999136940, + initial_gas: 9999181470, ..trivial_external_entry_point_new(test_contract) }; let storage_entry_point = CallEntryPoint { calldata: calldata![felt!(key), felt!(value)], - initial_gas: 9998834320, + initial_gas: 9998970320, ..nested_storage_entry_point }; - let mut first_storage_entry_point_resources = - ChargedResources { gas_for_fee: GasAmount(0), ..Default::default() }; - if cairo_version == CairoVersion::Cairo1 { - first_storage_entry_point_resources.vm_resources = ExecutionResources { - n_steps: 244, - n_memory_holes: 0, - builtin_instance_counter: HashMap::from([(BuiltinName::range_check, 7)]), - }; - } - - let storage_entry_point_resources = first_storage_entry_point_resources.clone(); - // The default VersionedConstants is used in the execute_directly call bellow. let tracked_resource = test_contract.get_runnable_class().tracked_resource( - &VersionedConstants::create_for_testing().min_compiler_version_for_sierra_gas, - GasVectorComputationMode::All, + &VersionedConstants::create_for_testing().min_sierra_version_for_sierra_gas, + None, ); let nested_storage_call_info = CallInfo { @@ -182,24 +162,15 @@ fn test_nested_library_call(cairo_version: CairoVersion) { gas_consumed: REQUIRED_GAS_STORAGE_READ_WRITE_TEST, ..CallExecution::default() }, - charged_resources: first_storage_entry_point_resources, tracked_resource, - storage_read_values: vec![felt!(value + 1)], - accessed_storage_keys: HashSet::from([storage_key!(key + 1)]), + storage_access_tracker: StorageAccessTracker { + storage_read_values: vec![felt!(value + 1)], + accessed_storage_keys: HashSet::from([storage_key!(key + 1)]), + ..Default::default() + }, ..Default::default() }; - let mut library_call_resources = - ChargedResources { gas_for_fee: GasAmount(0), ..Default::default() }; - if cairo_version == CairoVersion::Cairo1 { - library_call_resources.vm_resources = &get_syscall_resources(SyscallSelector::LibraryCall) - + &ExecutionResources { - n_steps: 377, - n_memory_holes: 0, - builtin_instance_counter: HashMap::from([(BuiltinName::range_check, 15)]), - } - } - let library_call_info = CallInfo { call: library_entry_point, execution: CallExecution { @@ -207,7 +178,6 @@ fn test_nested_library_call(cairo_version: CairoVersion) { gas_consumed: REQUIRED_GAS_LIBRARY_CALL_TEST, ..CallExecution::default() }, - charged_resources: library_call_resources, inner_calls: vec![nested_storage_call_info], tracked_resource, ..Default::default() @@ -220,33 +190,23 @@ fn test_nested_library_call(cairo_version: CairoVersion) { gas_consumed: REQUIRED_GAS_STORAGE_READ_WRITE_TEST, ..CallExecution::default() }, - charged_resources: storage_entry_point_resources, - storage_read_values: vec![felt!(value)], - accessed_storage_keys: HashSet::from([storage_key!(key)]), + storage_access_tracker: StorageAccessTracker { + storage_read_values: vec![felt!(value)], + accessed_storage_keys: HashSet::from([storage_key!(key)]), + ..Default::default() + }, tracked_resource, ..Default::default() }; - let mut main_call_resources = - ChargedResources { gas_for_fee: GasAmount(0), ..Default::default() }; - if cairo_version == CairoVersion::Cairo1 { - main_call_resources.vm_resources = &(&get_syscall_resources(SyscallSelector::LibraryCall) - * 3) - + &ExecutionResources { - n_steps: 727, - n_memory_holes: 2, - builtin_instance_counter: HashMap::from([(BuiltinName::range_check, 27)]), - } - } - + let main_gas_consumed = 349670; let expected_call_info = CallInfo { call: main_entry_point.clone(), execution: CallExecution { retdata: retdata![felt!(value)], - gas_consumed: 475110, + gas_consumed: main_gas_consumed, ..CallExecution::default() }, - charged_resources: main_call_resources, inner_calls: vec![library_call_info, storage_call_info], tracked_resource, ..Default::default() diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/meta_tx.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/meta_tx.rs new file mode 100644 index 00000000000..2a472b8c1dd --- /dev/null +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/meta_tx.rs @@ -0,0 +1,218 @@ +use std::sync::Arc; + +use blockifier_test_utils::cairo_versions::RunnableCairo1; +use blockifier_test_utils::contracts::FeatureContract; +use cairo_vm::types::builtin_name::BuiltinName; +use cairo_vm::vm::runners::cairo_runner::ExecutionResources; +use cairo_vm::Felt252; +use starknet_api::abi::abi_utils::{selector_from_name, starknet_keccak}; +use starknet_api::contract_class::SierraVersion; +use starknet_api::core::{ContractAddress, Nonce}; +use starknet_api::test_utils::CHAIN_ID_FOR_TESTS; +use starknet_api::transaction::fields::{Calldata, Fee}; +use starknet_api::transaction::{ + signed_tx_version, + InvokeTransactionV0, + TransactionHash, + TransactionHasher, + TransactionOptions, + TransactionVersion, + QUERY_VERSION_BASE, +}; +use starknet_api::{calldata, felt}; +use starknet_types_core::hash::{Pedersen, StarkHash}; +use test_case::test_case; + +use crate::context::{BlockContext, ChainInfo}; +use crate::execution::call_info::CallExecution; +use crate::execution::common_hints::ExecutionMode; +use crate::execution::entry_point::CallEntryPoint; +use crate::state::state_api::StateReader; +use crate::test_utils::initial_test_state::test_state; +use crate::test_utils::{trivial_external_entry_point_with_address, BALANCE}; +use crate::transaction::objects::{CommonAccountFields, CurrentTransactionInfo, TransactionInfo}; + +#[test_case(RunnableCairo1::Casm, ExecutionMode::Execute, false, false; "VM, execute")] +#[test_case(RunnableCairo1::Casm, ExecutionMode::Execute, true, false; "VM, execute, only_query")] +#[test_case(RunnableCairo1::Casm, ExecutionMode::Validate, false, false; "VM, validate")] +#[test_case( + RunnableCairo1::Casm, ExecutionMode::Execute, false, true; "VM, execute, measure resources" +)] +// TODO(lior): Uncomment when native supports `meta_tx_v0`. +// #[cfg_attr( +// feature = "cairo_native", +// test_case( +// RunnableCairo1::Native, +// ExecutionMode::Execute, +// false; +// "Native, execute" +// ) +// )] +// #[cfg_attr( +// feature = "cairo_native", +// test_case( +// RunnableCairo1::Native, +// ExecutionMode::Execute, +// true; +// "Native, execute, only_query" +// ) +// )] +// #[cfg_attr( +// feature = "cairo_native", +// test_case( +// RunnableCairo1::Native, +// ExecutionMode::Validate, +// false; +// "Native, validate" +// ) +// )] +fn test_meta_tx_v0( + runnable_version: RunnableCairo1, + execution_mode: ExecutionMode, + only_query: bool, + measure_resources: bool, +) { + let meta_tx_contract = FeatureContract::MetaTx(runnable_version); + let mut state = test_state(&ChainInfo::create_for_testing(), BALANCE, &[(meta_tx_contract, 1)]); + + // Prepare some constants. + let contract_address = meta_tx_contract.get_instance_address(0); + let argument: Felt252 = 1234.into(); + let signature0: Felt252 = 1000.into(); + let signature1: Felt252 = 17.into(); + let nonce: Felt252 = 13.into(); + let tx_hash: Felt252 = 0xabcdef.into(); + let account_address: ContractAddress = 0xfedcba0000_u128.into(); + let expected_version = felt!(3_u32) + (if only_query { *QUERY_VERSION_BASE } else { 0.into() }); + let expected_meta_tx_version = if only_query { *QUERY_VERSION_BASE } else { 0.into() }; + + let expected_meta_tx_hash = InvokeTransactionV0 { + max_fee: Fee(0), + signature: Default::default(), + contract_address, + entry_point_selector: selector_from_name("foo"), + calldata: calldata!(argument), + } + .calculate_transaction_hash( + &CHAIN_ID_FOR_TESTS.clone(), + &signed_tx_version(&TransactionVersion::ZERO, &TransactionOptions { only_query }), + ) + .unwrap(); + + let calldata = Calldata( + vec![ + contract_address.into(), + selector_from_name("foo").0, + // Inner calldata. + 1.into(), + argument, + // Inner signature. + 2.into(), + signature0, + signature1, + ] + .into(), + ); + + let entry_point_call = CallEntryPoint { + entry_point_selector: selector_from_name("execute_meta_tx_v0"), + calldata, + caller_address: account_address, + ..trivial_external_entry_point_with_address(contract_address) + }; + + let tx_info = TransactionInfo::Current(CurrentTransactionInfo { + common_fields: CommonAccountFields { + transaction_hash: TransactionHash(tx_hash), + version: TransactionVersion::THREE, + signature: Default::default(), + nonce: Nonce(nonce), + sender_address: account_address, + only_query, + }, + ..CurrentTransactionInfo::create_for_testing() + }); + + // Use the maximum sierra version to avoid sierra gas. + let max_sierra_version = SierraVersion::new(u64::MAX, u64::MAX, u64::MAX); + let mut block_context = BlockContext::create_for_testing(); + if measure_resources { + block_context.versioned_constants.min_sierra_version_for_sierra_gas = max_sierra_version; + } + + let exec_result = entry_point_call.execute_directly_given_tx_info( + &mut state, + tx_info, + Some(Arc::new(block_context)), + false, + execution_mode, + ); + + let call_info = match execution_mode { + ExecutionMode::Execute => exec_result.unwrap(), + ExecutionMode::Validate => { + assert!(exec_result.is_err()); + return; + } + }; + + assert!(!call_info.execution.failed); + assert_eq!( + call_info.execution, + CallExecution { + gas_consumed: if measure_resources { 0 } else { 529010 }, + ..CallExecution::default() + } + ); + assert_eq!( + call_info.resources, + if measure_resources { + ExecutionResources { + n_steps: 4642, + n_memory_holes: 30, + builtin_instance_counter: [ + (BuiltinName::range_check, 99), + (BuiltinName::pedersen, 12), + ] + .into_iter() + .collect(), + } + } else { + ExecutionResources::default() + } + ); + + let check_value = |key: Felt252, value: Felt252| { + assert_eq!(state.get_storage_at(contract_address, key.try_into().unwrap()).unwrap(), value) + }; + let from_bytes = |bytes| Felt252::from_bytes_be_slice(bytes); + + let call_data_key = starknet_keccak("call_data".as_bytes()); + let call_data_item0_key = Pedersen::hash(&call_data_key, &0.into()); + let call_data_item1_key = Pedersen::hash(&call_data_key, &1.into()); + + // Size of `call_data` vector. + check_value(call_data_key, 2.into()); + + // Inside the meta-tx. + check_value(call_data_item0_key + 0, 0.into()); // caller_address. + check_value(call_data_item0_key + 1, contract_address.into()); // account_contract_address. + check_value(call_data_item0_key + 2, expected_meta_tx_version); // tx_version. + check_value(call_data_item0_key + 3, argument); // argument. + check_value(call_data_item0_key + 4, expected_meta_tx_hash.0); // transaction_hash. + check_value(call_data_item0_key + 5, signature0); // signature. + check_value(call_data_item0_key + 6, 0.into()); // max_fee. + check_value(call_data_item0_key + 7, 0.into()); // resource_bound_len. + check_value(call_data_item0_key + 8, 0.into()); // nonce. + + // Outside the meta-tx. + check_value(call_data_item1_key + 0, account_address.into()); // caller_address + check_value(call_data_item1_key + 1, account_address.into()); // account_contract_address. + check_value(call_data_item1_key + 2, expected_version); // tx_version. + check_value(call_data_item1_key + 3, from_bytes(b"NO_ARGUMENT")); // argument. + check_value(call_data_item1_key + 4, tx_hash); // transaction_hash. + check_value(call_data_item1_key + 5, from_bytes(b"NO_SIGNATURE")); // signature. + check_value(call_data_item1_key + 6, 0.into()); // max_fee. + check_value(call_data_item1_key + 7, 3.into()); // resource_bound_len. + check_value(call_data_item1_key + 8, nonce); // nonce. +} diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/mod.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/mod.rs index 981449e0ce5..9b6ce87b573 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_tests/mod.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/mod.rs @@ -1,3 +1,4 @@ +mod builtins_test; mod call_contract; mod constants; mod deploy; @@ -8,6 +9,7 @@ mod get_class_hash_at; mod get_execution_info; mod keccak; mod library_call; +mod meta_tx; mod out_of_gas; mod replace_class; mod secp; diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/out_of_gas.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/out_of_gas.rs index 3a6f9091700..54c3345974e 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_tests/out_of_gas.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/out_of_gas.rs @@ -1,41 +1,60 @@ +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; +use blockifier_test_utils::contracts::FeatureContract; use starknet_api::abi::abi_utils::selector_from_name; use starknet_api::{calldata, felt}; use test_case::test_case; -use crate::context::ChainInfo; +use crate::abi::constants::MAX_POSSIBLE_SIERRA_GAS; +use crate::blockifier_versioned_constants::VersionedConstants; use crate::execution::call_info::CallExecution; use crate::execution::entry_point::CallEntryPoint; -use crate::execution::syscalls::syscall_tests::constants::REQUIRED_GAS_STORAGE_READ_WRITE_TEST; +use crate::execution::syscalls::syscall_tests::constants; +use crate::execution::syscalls::syscall_tests::get_block_hash::initialize_state; +use crate::execution::syscalls::SyscallSelector; use crate::retdata; -use crate::test_utils::contracts::FeatureContract; -use crate::test_utils::initial_test_state::test_state; -use crate::test_utils::{trivial_external_entry_point_new, CairoVersion, BALANCE}; +use crate::test_utils::trivial_external_entry_point_new; -#[cfg_attr(feature = "cairo_native", test_case(CairoVersion::Native; "Native"))] -#[test_case(CairoVersion::Cairo1; "VM")] -fn test_out_of_gas(cairo_version: CairoVersion) { - let test_contract = FeatureContract::TestContract(cairo_version); - let chain_info = &ChainInfo::create_for_testing(); - let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); +#[cfg_attr(feature = "cairo_native", test_case(RunnableCairo1::Native; "Native"))] +#[test_case(RunnableCairo1::Casm; "VM")] +fn test_out_of_gas(runnable_version: RunnableCairo1) { + let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1(runnable_version)); + let (mut state, block_number, _block_hash) = initialize_state(test_contract); - let key = felt!(1234_u16); - let value = felt!(18_u8); - let calldata = calldata![key, value]; + let calldata = calldata![block_number]; let entry_point_call = CallEntryPoint { + entry_point_selector: selector_from_name("test_get_block_hash"), calldata, - entry_point_selector: selector_from_name("test_storage_read_write"), - initial_gas: REQUIRED_GAS_STORAGE_READ_WRITE_TEST - 1, + initial_gas: constants::REQUIRED_GAS_GET_BLOCK_HASH_TEST - 1, ..trivial_external_entry_point_new(test_contract) }; - let call_info = entry_point_call.execute_directly(&mut state).unwrap(); + + let gas_costs = &VersionedConstants::create_for_testing().os_constants.gas_costs; + let get_block_hash_gas_cost = + gas_costs.syscalls.get_syscall_gas_cost(&SyscallSelector::GetBlockHash).unwrap(); + + // We hit the out of gas error right before executing the syscall. + let syscall_base_gas_cost = gas_costs.base.syscall_base_gas_cost; + let redeposit_gas = 300; + let syscall_required_gas = get_block_hash_gas_cost.base_syscall_cost() - syscall_base_gas_cost; + let call_info = entry_point_call.clone().execute_directly(&mut state).unwrap(); assert_eq!( call_info.execution, CallExecution { // 'Out of gas' retdata: retdata![felt!["0x4f7574206f6620676173"]], - gas_consumed: REQUIRED_GAS_STORAGE_READ_WRITE_TEST - 70, + gas_consumed: constants::REQUIRED_GAS_GET_BLOCK_HASH_TEST + - syscall_required_gas + - redeposit_gas, failed: true, ..Default::default() } ); } + +#[test] +fn test_total_tx_limits_less_than_max_sierra_gas() { + assert!( + VersionedConstants::create_for_testing().initial_gas_no_user_l2_bound().0 + <= MAX_POSSIBLE_SIERRA_GAS + ); +} diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/replace_class.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/replace_class.rs index 03eecc996bc..b245ed8e872 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_tests/replace_class.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/replace_class.rs @@ -1,3 +1,5 @@ +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; +use blockifier_test_utils::contracts::FeatureContract; use pretty_assertions::assert_eq; use starknet_api::abi::abi_utils::selector_from_name; use starknet_api::{calldata, felt}; @@ -7,14 +9,13 @@ use crate::context::ChainInfo; use crate::execution::call_info::CallExecution; use crate::execution::entry_point::CallEntryPoint; use crate::state::state_api::StateReader; -use crate::test_utils::contracts::FeatureContract; use crate::test_utils::initial_test_state::test_state; -use crate::test_utils::{trivial_external_entry_point_new, CairoVersion, BALANCE}; +use crate::test_utils::{trivial_external_entry_point_new, BALANCE}; -#[cfg_attr(feature = "cairo_native", test_case(CairoVersion::Native; "Native"))] -#[test_case(CairoVersion::Cairo1; "VM")] -fn undeclared_class_hash(cairo_version: CairoVersion) { - let test_contract = FeatureContract::TestContract(cairo_version); +#[cfg_attr(feature = "cairo_native", test_case(RunnableCairo1::Native; "Native"))] +#[test_case(RunnableCairo1::Casm; "VM")] +fn undeclared_class_hash(runnable_version: RunnableCairo1) { + let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1(runnable_version)); let mut state = test_state(&ChainInfo::create_for_testing(), BALANCE, &[(test_contract, 1)]); let entry_point_call = CallEntryPoint { @@ -27,10 +28,10 @@ fn undeclared_class_hash(cairo_version: CairoVersion) { assert!(error.to_string().contains("is not declared")); } -#[cfg_attr(feature = "cairo_native", test_case(CairoVersion::Native; "Native"))] -#[test_case(CairoVersion::Cairo1; "VM")] -fn cairo0_class_hash(cairo_version: CairoVersion) { - let test_contract = FeatureContract::TestContract(cairo_version); +#[cfg_attr(feature = "cairo_native", test_case(RunnableCairo1::Native; "Native"))] +#[test_case(RunnableCairo1::Casm; "VM")] +fn cairo0_class_hash(runnable_version: RunnableCairo1) { + let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1(runnable_version)); let empty_contract_cairo0 = FeatureContract::Empty(CairoVersion::Cairo0); let mut state = test_state( &ChainInfo::create_for_testing(), @@ -51,11 +52,11 @@ fn cairo0_class_hash(cairo_version: CairoVersion) { assert!(error.to_string().contains("Cannot replace V1 class hash with V0 class hash")); } -#[cfg_attr(feature = "cairo_native", test_case(CairoVersion::Native; "Native"))] -#[test_case(CairoVersion::Cairo1; "VM")] -fn positive_flow(cairo_version: CairoVersion) { - let test_contract = FeatureContract::TestContract(cairo_version); - let empty_contract = FeatureContract::Empty(CairoVersion::Cairo1); +#[cfg_attr(feature = "cairo_native", test_case(RunnableCairo1::Native; "Native"))] +#[test_case(RunnableCairo1::Casm; "VM")] +fn positive_flow(runnable_version: RunnableCairo1) { + let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1(runnable_version)); + let empty_contract = FeatureContract::Empty(CairoVersion::Cairo1(runnable_version)); let empty_contract_cairo0 = FeatureContract::Empty(CairoVersion::Cairo0); let mut state = test_state( &ChainInfo::create_for_testing(), @@ -74,7 +75,7 @@ fn positive_flow(cairo_version: CairoVersion) { }; assert_eq!( entry_point_call.execute_directly(&mut state).unwrap().execution, - CallExecution { gas_consumed: 5220, ..Default::default() } + CallExecution { gas_consumed: 16120, ..Default::default() } ); assert_eq!(state.get_class_hash_at(contract_address).unwrap(), new_class_hash); } diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/secp.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/secp.rs index 14255d9891e..7d9deb1bdb9 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_tests/secp.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/secp.rs @@ -1,3 +1,5 @@ +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; +use blockifier_test_utils::contracts::FeatureContract; use starknet_api::abi::abi_utils::selector_from_name; use starknet_api::transaction::fields::Calldata; use test_case::test_case; @@ -5,14 +7,13 @@ use test_case::test_case; use crate::context::ChainInfo; use crate::execution::call_info::CallExecution; use crate::execution::entry_point::CallEntryPoint; -use crate::test_utils::contracts::FeatureContract; use crate::test_utils::initial_test_state::test_state; -use crate::test_utils::{trivial_external_entry_point_new, CairoVersion, BALANCE}; +use crate::test_utils::{trivial_external_entry_point_new, BALANCE}; -#[cfg_attr(feature = "cairo_native", test_case(CairoVersion::Native; "Native"))] -#[test_case(CairoVersion::Cairo1; "VM")] -fn test_secp256k1(cairo_version: CairoVersion) { - let test_contract = FeatureContract::TestContract(cairo_version); +#[cfg_attr(feature = "cairo_native", test_case(RunnableCairo1::Native; "Native"))] +#[test_case(RunnableCairo1::Casm; "VM")] +fn test_secp256k1(runnable_version: RunnableCairo1) { + let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1(runnable_version)); let chain_info = &ChainInfo::create_for_testing(); let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); @@ -25,14 +26,14 @@ fn test_secp256k1(cairo_version: CairoVersion) { pretty_assertions::assert_eq!( entry_point_call.execute_directly(&mut state).unwrap().execution, - CallExecution { gas_consumed: 17034156, ..Default::default() } + CallExecution { gas_consumed: 17013779, ..Default::default() } ); } -#[cfg_attr(feature = "cairo_native",test_case(CairoVersion::Native; "Native"))] -#[test_case(CairoVersion::Cairo1; "VM")] -fn test_secp256r1(cairo_version: CairoVersion) { - let test_contract = FeatureContract::TestContract(cairo_version); +#[cfg_attr(feature = "cairo_native",test_case(RunnableCairo1::Native; "Native"))] +#[test_case(RunnableCairo1::Casm; "VM")] +fn test_secp256r1(runnable_version: RunnableCairo1) { + let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1(runnable_version)); let chain_info = &ChainInfo::create_for_testing(); let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); @@ -45,6 +46,6 @@ fn test_secp256r1(cairo_version: CairoVersion) { pretty_assertions::assert_eq!( entry_point_call.execute_directly(&mut state).unwrap().execution, - CallExecution { gas_consumed: 27563600, ..Default::default() } + CallExecution { gas_consumed: 27573210, ..Default::default() } ); } diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/send_message_to_l1.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/send_message_to_l1.rs index ab4e59b85b6..551a6640567 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_tests/send_message_to_l1.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/send_message_to_l1.rs @@ -1,3 +1,5 @@ +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; +use blockifier_test_utils::contracts::FeatureContract; use itertools::concat; use starknet_api::abi::abi_utils::selector_from_name; use starknet_api::core::EthAddress; @@ -9,14 +11,13 @@ use test_case::test_case; use crate::context::ChainInfo; use crate::execution::call_info::{CallExecution, MessageToL1, OrderedL2ToL1Message}; use crate::execution::entry_point::CallEntryPoint; -use crate::test_utils::contracts::FeatureContract; use crate::test_utils::initial_test_state::test_state; -use crate::test_utils::{trivial_external_entry_point_new, CairoVersion, BALANCE}; +use crate::test_utils::{trivial_external_entry_point_new, BALANCE}; -#[cfg_attr(feature = "cairo_native", test_case(CairoVersion::Native; "Native"))] -#[test_case(CairoVersion::Cairo1; "VM")] -fn test_send_message_to_l1(cairo_version: CairoVersion) { - let test_contract = FeatureContract::TestContract(cairo_version); +#[cfg_attr(feature = "cairo_native", test_case(RunnableCairo1::Native; "Native"))] +#[test_case(RunnableCairo1::Casm; "VM")] +fn test_send_message_to_l1(runnable_version: RunnableCairo1) { + let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1(runnable_version)); let chain_info = &ChainInfo::create_for_testing(); let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); @@ -47,7 +48,7 @@ fn test_send_message_to_l1(cairo_version: CairoVersion) { entry_point_call.execute_directly(&mut state).unwrap().execution, CallExecution { l2_to_l1_messages: vec![OrderedL2ToL1Message { order: 0, message }], - gas_consumed: 20960, + gas_consumed: 30490, ..Default::default() } ); diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/sha256.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/sha256.rs index 9f8c57b9c02..b1db86074ce 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_tests/sha256.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/sha256.rs @@ -1,3 +1,5 @@ +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; +use blockifier_test_utils::contracts::FeatureContract; use starknet_api::abi::abi_utils::selector_from_name; use starknet_api::transaction::fields::Calldata; use test_case::test_case; @@ -6,14 +8,13 @@ use crate::context::ChainInfo; use crate::execution::call_info::CallExecution; use crate::execution::entry_point::CallEntryPoint; use crate::retdata; -use crate::test_utils::contracts::FeatureContract; use crate::test_utils::initial_test_state::test_state; -use crate::test_utils::{trivial_external_entry_point_new, CairoVersion, BALANCE}; +use crate::test_utils::{trivial_external_entry_point_new, BALANCE}; -#[cfg_attr(feature = "cairo_native", test_case(CairoVersion::Native; "Native"))] -#[test_case(CairoVersion::Cairo1; "VM")] -fn test_sha256(cairo_version: CairoVersion) { - let test_contract = FeatureContract::TestContract(cairo_version); +#[cfg_attr(feature = "cairo_native", test_case(RunnableCairo1::Native; "Native"))] +#[test_case(RunnableCairo1::Casm; "VM")] +fn test_sha256(runnable_version: RunnableCairo1) { + let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1(runnable_version)); let chain_info = &ChainInfo::create_for_testing(); let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); @@ -26,6 +27,6 @@ fn test_sha256(cairo_version: CairoVersion) { pretty_assertions::assert_eq!( entry_point_call.execute_directly(&mut state).unwrap().execution, - CallExecution { gas_consumed: 881425, ..CallExecution::from_retdata(retdata![]) } + CallExecution { gas_consumed: 871055, ..CallExecution::from_retdata(retdata![]) } ); } diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/storage_read_write.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/storage_read_write.rs index a87b6adc8bc..650fce4459d 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_tests/storage_read_write.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/storage_read_write.rs @@ -1,3 +1,5 @@ +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; +use blockifier_test_utils::contracts::FeatureContract; use starknet_api::abi::abi_utils::selector_from_name; use starknet_api::state::StorageKey; use starknet_api::{calldata, felt}; @@ -9,14 +11,13 @@ use crate::execution::entry_point::CallEntryPoint; use crate::execution::syscalls::syscall_tests::constants::REQUIRED_GAS_STORAGE_READ_WRITE_TEST; use crate::retdata; use crate::state::state_api::StateReader; -use crate::test_utils::contracts::FeatureContract; use crate::test_utils::initial_test_state::test_state; -use crate::test_utils::{trivial_external_entry_point_new, CairoVersion, BALANCE}; +use crate::test_utils::{trivial_external_entry_point_new, BALANCE}; -#[cfg_attr(feature = "cairo_native", test_case(CairoVersion::Native; "Native"))] -#[test_case(CairoVersion::Cairo1; "VM")] -fn test_storage_read_write(cairo_version: CairoVersion) { - let test_contract = FeatureContract::TestContract(cairo_version); +#[cfg_attr(feature = "cairo_native", test_case(RunnableCairo1::Native; "Native"))] +#[test_case(RunnableCairo1::Casm; "VM")] +fn test_storage_read_write(runnable_version: RunnableCairo1) { + let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1(runnable_version)); let chain_info = &ChainInfo::create_for_testing(); let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); diff --git a/crates/blockifier/src/fee/fee_checks.rs b/crates/blockifier/src/fee/fee_checks.rs index f5bc38a2bd3..b0e4955cb6c 100644 --- a/crates/blockifier/src/fee/fee_checks.rs +++ b/crates/blockifier/src/fee/fee_checks.rs @@ -1,20 +1,20 @@ +use starknet_api::block::FeeType; use starknet_api::execution_resources::{GasAmount, GasVector}; use starknet_api::transaction::fields::Resource::{self, L1DataGas, L1Gas, L2Gas}; -use starknet_api::transaction::fields::{ - AllResourceBounds, - Fee, - ResourceBounds, - ValidResourceBounds, -}; +use starknet_api::transaction::fields::{Fee, ResourceBounds, ValidResourceBounds}; use starknet_types_core::felt::Felt; use thiserror::Error; use crate::context::TransactionContext; -use crate::fee::fee_utils::{get_balance_and_if_covers_fee, get_fee_by_gas_vector}; +use crate::fee::fee_utils::{ + get_balance_and_if_covers_fee, + get_fee_by_gas_vector, + GasVectorToL1GasForFee, +}; use crate::fee::receipt::TransactionReceipt; use crate::state::state_api::StateReader; use crate::transaction::errors::TransactionExecutionError; -use crate::transaction::objects::{FeeType, TransactionExecutionResult, TransactionInfo}; +use crate::transaction::objects::{TransactionExecutionResult, TransactionInfo}; #[cfg_attr(feature = "transaction_serde", derive(serde::Serialize, serde::Deserialize))] #[derive(Clone, Copy, Debug, Error, PartialEq)] @@ -36,7 +36,7 @@ pub(crate) type FeeCheckResult = Result; /// This struct holds the result of fee checks: recommended fee to charge (useful in post-execution /// revert flow) and an error if the check failed. -struct FeeCheckReport { +pub(crate) struct FeeCheckReport { recommended_fee: Fee, error: Option, } @@ -124,6 +124,27 @@ impl FeeCheckReport { Self { recommended_fee, error: Some(error) } } + pub fn check_all_gas_amounts_within_bounds( + max_amount_bounds: &GasVector, + gas_vector: &GasVector, + ) -> FeeCheckResult<()> { + for (resource, max_amount, actual_amount) in [ + (L1Gas, max_amount_bounds.l1_gas, gas_vector.l1_gas), + (L2Gas, max_amount_bounds.l2_gas, gas_vector.l2_gas), + (L1DataGas, max_amount_bounds.l1_data_gas, gas_vector.l1_data_gas), + ] { + if max_amount < actual_amount { + return Err(FeeCheckError::MaxGasAmountExceeded { + resource, + max_amount, + actual_amount, + }); + } + } + + Ok(()) + } + /// If the actual cost exceeds the resource bounds on the transaction, returns a fee check /// error. fn check_actual_cost_within_bounds( @@ -145,7 +166,9 @@ impl FeeCheckReport { // Check max fee. let max_fee = context.max_fee; if fee > &max_fee { - return Err(FeeCheckError::MaxFeeExceeded { max_fee, actual_fee: *fee })?; + return Err(TransactionExecutionError::FeeCheckError( + FeeCheckError::MaxFeeExceeded { max_fee, actual_fee: *fee }, + )); } Ok(()) } @@ -177,48 +200,33 @@ impl FeeCheckReport { match valid_resource_bounds { ValidResourceBounds::AllResources(all_resource_bounds) => { // Iterate over resources and check actual_amount <= max_amount. - FeeCheckReport::check_all_resources_within_bounds(all_resource_bounds, gas_vector) + FeeCheckReport::check_all_gas_amounts_within_bounds( + &all_resource_bounds.to_max_amounts(), + gas_vector, + ) } ValidResourceBounds::L1Gas(l1_bounds) => { // Check that the total discounted l1 gas used <= l1_bounds.max_amount. - FeeCheckReport::check_l1_gas_within_bounds(l1_bounds, gas_vector, tx_context) + FeeCheckReport::check_l1_gas_amount_within_bounds(l1_bounds, gas_vector, tx_context) } } } - fn check_all_resources_within_bounds( - all_resource_bounds: &AllResourceBounds, - gas_vector: &GasVector, - ) -> FeeCheckResult<()> { - for (resource, max_amount, actual_amount) in [ - (L1Gas, all_resource_bounds.l1_gas.max_amount, gas_vector.l1_gas), - (L2Gas, all_resource_bounds.l2_gas.max_amount, gas_vector.l2_gas), - (L1DataGas, all_resource_bounds.l1_data_gas.max_amount, gas_vector.l1_data_gas), - ] { - if max_amount < actual_amount { - return Err(FeeCheckError::MaxGasAmountExceeded { - resource, - max_amount, - actual_amount, - }); - } - } - - Ok(()) - } - - fn check_l1_gas_within_bounds( + fn check_l1_gas_amount_within_bounds( &l1_bounds: &ResourceBounds, gas_vector: &GasVector, tx_context: &TransactionContext, ) -> FeeCheckResult<()> { - let total_discounted_gas_used = - gas_vector.to_discounted_l1_gas(tx_context.get_gas_prices()); - if total_discounted_gas_used > l1_bounds.max_amount { + let total_l1_gas_used = gas_vector.to_l1_gas_for_fee( + tx_context.get_gas_prices(), + &tx_context.block_context.versioned_constants, + ); + + if total_l1_gas_used > l1_bounds.max_amount { return Err(FeeCheckError::MaxGasAmountExceeded { resource: L1Gas, max_amount: l1_bounds.max_amount, - actual_amount: total_discounted_gas_used, + actual_amount: total_l1_gas_used, }); } Ok(()) @@ -252,9 +260,10 @@ impl PostValidationReport { pub fn verify( tx_context: &TransactionContext, tx_receipt: &TransactionReceipt, + charge_fee: bool, ) -> TransactionExecutionResult<()> { // If fee is not enforced, no need to check post-execution. - if !tx_context.tx_info.enforce_fee() { + if !charge_fee { return Ok(()); } diff --git a/crates/blockifier/src/fee/fee_test.rs b/crates/blockifier/src/fee/fee_test.rs index e96f443431e..90bf1661e6c 100644 --- a/crates/blockifier/src/fee/fee_test.rs +++ b/crates/blockifier/src/fee/fee_test.rs @@ -1,9 +1,19 @@ use assert_matches::assert_matches; +use blockifier_test_utils::cairo_versions::CairoVersion; +use blockifier_test_utils::contracts::FeatureContract; use cairo_vm::types::builtin_name::BuiltinName; use rstest::rstest; -use starknet_api::block::{GasPrice, NonzeroGasPrice}; +use starknet_api::block::{FeeType, GasPrice, NonzeroGasPrice}; use starknet_api::execution_resources::{GasAmount, GasVector}; use starknet_api::invoke_tx_args; +use starknet_api::test_utils::{ + DEFAULT_ETH_L1_DATA_GAS_PRICE, + DEFAULT_ETH_L1_GAS_PRICE, + DEFAULT_L1_DATA_GAS_MAX_AMOUNT, + DEFAULT_L1_GAS_AMOUNT, + DEFAULT_L2_GAS_MAX_AMOUNT, + DEFAULT_STRK_L1_GAS_PRICE, +}; use starknet_api::transaction::fields::{ AllResourceBounds, Fee, @@ -13,34 +23,21 @@ use starknet_api::transaction::fields::{ ValidResourceBounds, }; -use crate::blockifier::block::GasPrices; +use crate::blockifier::block::validated_gas_prices; +use crate::blockifier_versioned_constants::VersionedConstants; use crate::context::BlockContext; use crate::fee::fee_checks::{FeeCheckError, FeeCheckReportFields, PostExecutionReport}; use crate::fee::fee_utils::{get_fee_by_gas_vector, get_vm_resources_cost}; use crate::fee::receipt::TransactionReceipt; -use crate::test_utils::contracts::FeatureContract; use crate::test_utils::initial_test_state::test_state; -use crate::test_utils::{ - gas_vector_from_vm_usage, - get_vm_resource_usage, - CairoVersion, - BALANCE, - DEFAULT_ETH_L1_DATA_GAS_PRICE, - DEFAULT_ETH_L1_GAS_PRICE, - DEFAULT_L1_DATA_GAS_MAX_AMOUNT, - DEFAULT_L1_GAS_AMOUNT, - DEFAULT_L2_GAS_MAX_AMOUNT, - DEFAULT_STRK_L1_GAS_PRICE, -}; -use crate::transaction::objects::FeeType; +use crate::test_utils::{gas_vector_from_vm_usage, get_vm_resource_usage, BALANCE}; use crate::transaction::test_utils::{ - account_invoke_tx, all_resource_bounds, block_context, + invoke_tx_with_default_flags, l1_resource_bounds, }; use crate::utils::u64_from_usize; -use crate::versioned_constants::VersionedConstants; #[rstest] fn test_simple_get_vm_resource_usage( @@ -178,7 +175,7 @@ fn test_discounted_gas_overdraft( NonzeroGasPrice::try_from(data_gas_price).unwrap(), ); let mut block_context = BlockContext::create_for_account_testing(); - block_context.block_info.gas_prices = GasPrices::new( + block_context.block_info.gas_prices = validated_gas_prices( DEFAULT_ETH_L1_GAS_PRICE, gas_price, DEFAULT_ETH_L1_DATA_GAS_PRICE, @@ -187,8 +184,8 @@ fn test_discounted_gas_overdraft( .convert_l1_to_l2_gas_price_round_up(DEFAULT_ETH_L1_GAS_PRICE.into()) .try_into() .unwrap(), + // TODO(Aner): fix test parameters to allow using `gas_price` here. VersionedConstants::latest_constants() - //TODO!(Aner): fix test parameters to allow using `gas_price` here! .convert_l1_to_l2_gas_price_round_up(DEFAULT_STRK_L1_GAS_PRICE.into()) .try_into() .unwrap(), @@ -196,7 +193,7 @@ fn test_discounted_gas_overdraft( let account = FeatureContract::AccountWithoutValidations(CairoVersion::Cairo0); let mut state = test_state(&block_context.chain_info, BALANCE, &[(account, 1)]); - let tx = account_invoke_tx(invoke_tx_args! { + let tx = invoke_tx_with_default_flags(invoke_tx_args! { sender_address: account.get_instance_address(0), resource_bounds: l1_resource_bounds(gas_bound, (gas_price.get().0 * 10).into()), }); @@ -271,7 +268,7 @@ fn test_post_execution_gas_overdraft_all_resource_bounds( let account = FeatureContract::AccountWithoutValidations(CairoVersion::Cairo0); let mut state = test_state(&block_context.chain_info, BALANCE, &[(account, 1)]); - let tx = account_invoke_tx(invoke_tx_args! { + let tx = invoke_tx_with_default_flags(invoke_tx_args! { sender_address: account.get_instance_address(0), resource_bounds: all_resource_bounds, }); @@ -313,7 +310,7 @@ fn test_get_fee_by_gas_vector_regression( #[case] expected_fee_strk: u128, ) { let mut block_info = BlockContext::create_for_account_testing().block_info; - block_info.gas_prices = GasPrices::new( + block_info.gas_prices = validated_gas_prices( 1_u8.try_into().unwrap(), 2_u8.try_into().unwrap(), 3_u8.try_into().unwrap(), @@ -347,7 +344,7 @@ fn test_get_fee_by_gas_vector_overflow( ) { let huge_gas_price = NonzeroGasPrice::try_from(2_u128 * u128::from(u64::MAX)).unwrap(); let mut block_info = BlockContext::create_for_account_testing().block_info; - block_info.gas_prices = GasPrices::new( + block_info.gas_prices = validated_gas_prices( huge_gas_price, huge_gas_price, huge_gas_price, @@ -362,7 +359,7 @@ fn test_get_fee_by_gas_vector_overflow( #[rstest] #[case::default( - VersionedConstants::create_for_account_testing().default_initial_gas_cost(), + VersionedConstants::create_for_account_testing().initial_gas_no_user_l2_bound().0, GasVectorComputationMode::NoL2Gas )] #[case::from_l2_gas(4321, GasVectorComputationMode::All)] @@ -384,7 +381,7 @@ fn test_initial_sierra_gas( ..Default::default() }), }; - let account_tx = account_invoke_tx(invoke_tx_args!(resource_bounds)); - let actual = block_context.to_tx_context(&account_tx).initial_sierra_gas(); + let account_tx = invoke_tx_with_default_flags(invoke_tx_args!(resource_bounds)); + let actual = block_context.to_tx_context(&account_tx).initial_sierra_gas().0; assert_eq!(actual, expected) } diff --git a/crates/blockifier/src/fee/fee_utils.rs b/crates/blockifier/src/fee/fee_utils.rs index 89a3685f3e5..76dc9496146 100644 --- a/crates/blockifier/src/fee/fee_utils.rs +++ b/crates/blockifier/src/fee/fee_utils.rs @@ -4,26 +4,62 @@ use cairo_vm::types::builtin_name::BuiltinName; use cairo_vm::vm::runners::cairo_runner::ExecutionResources; use num_bigint::BigUint; use starknet_api::abi::abi_utils::get_fee_token_var_address; +use starknet_api::block::{BlockInfo, FeeType, GasPriceVector}; use starknet_api::core::ContractAddress; -use starknet_api::execution_resources::GasVector; +use starknet_api::execution_resources::{to_discounted_l1_gas, GasAmount, GasVector}; use starknet_api::state::StorageKey; use starknet_api::transaction::fields::ValidResourceBounds::{AllResources, L1Gas}; use starknet_api::transaction::fields::{Fee, GasVectorComputationMode, Resource}; use starknet_types_core::felt::Felt; -use crate::blockifier::block::BlockInfo; +use crate::blockifier_versioned_constants::VersionedConstants; use crate::context::{BlockContext, TransactionContext}; use crate::fee::resources::TransactionFeeResult; use crate::state::state_api::StateReader; use crate::transaction::errors::TransactionFeeError; -use crate::transaction::objects::{ExecutionResourcesTraits, FeeType, TransactionInfo}; +use crate::transaction::objects::{ExecutionResourcesTraits, TransactionInfo}; use crate::utils::u64_from_usize; -use crate::versioned_constants::VersionedConstants; #[cfg(test)] #[path = "fee_test.rs"] pub mod test; +/// A trait for converting a gas vector to L1 gas for fee. Converts both L1 data gas and L2 gas to +/// L1 gas units. +/// The trait is defined to allow implementing a method on GasVector, which is a starknet-api type. +pub trait GasVectorToL1GasForFee { + fn to_l1_gas_for_fee( + &self, + gas_prices: &GasPriceVector, + versioned_constants: &VersionedConstants, + ) -> GasAmount; +} + +impl GasVectorToL1GasForFee for GasVector { + fn to_l1_gas_for_fee( + &self, + gas_prices: &GasPriceVector, + versioned_constants: &VersionedConstants, + ) -> GasAmount { + // Discounted gas converts data gas to L1 gas. Add L2 gas using conversion ratio. + let discounted_l1_gas = to_discounted_l1_gas( + gas_prices.l1_gas_price, + gas_prices.l1_data_gas_price.into(), + self.l1_gas, + self.l1_data_gas, + ); + discounted_l1_gas + .checked_add(versioned_constants.sierra_gas_to_l1_gas_amount_round_up(self.l2_gas)) + .unwrap_or_else(|| { + panic!( + "L1 gas amount overflowed: addition of converted L2 gas ({}) to discounted \ + gas ({}) resulted in overflow.", + self.l2_gas, discounted_l1_gas + ); + }) + } +} + /// Calculates the gas consumed when submitting the underlying Cairo program to SHARP. /// I.e., returns the heaviest Cairo resource weight (in terms of gas), as the size of /// a proof is determined similarly - by the (normalized) largest segment. @@ -68,7 +104,7 @@ pub fn get_vm_resources_cost( match computation_mode { GasVectorComputationMode::NoL2Gas => GasVector::from_l1_gas(vm_l1_gas_usage), GasVectorComputationMode::All => GasVector::from_l2_gas( - versioned_constants.convert_l1_to_l2_gas_amount_round_up(vm_l1_gas_usage), + versioned_constants.l1_gas_to_sierra_gas_amount_round_up(vm_l1_gas_usage), ), } } @@ -79,7 +115,7 @@ pub fn get_fee_by_gas_vector( gas_vector: GasVector, fee_type: &FeeType, ) -> Fee { - gas_vector.cost(block_info.gas_prices.get_gas_prices_by_fee_type(fee_type)) + gas_vector.cost(block_info.gas_prices.gas_price_vector(fee_type)) } /// Returns the current fee balance and a boolean indicating whether the balance covers the fee. diff --git a/crates/blockifier/src/fee/gas_usage.rs b/crates/blockifier/src/fee/gas_usage.rs index 7e68193a20c..ac3a9cea50f 100644 --- a/crates/blockifier/src/fee/gas_usage.rs +++ b/crates/blockifier/src/fee/gas_usage.rs @@ -65,12 +65,8 @@ pub fn get_da_gas_cost(state_changes_count: &StateChangesCount, use_kzg_da: bool let fee_balance_value_cost = eth_gas_constants::get_calldata_word_cost(12); discount += eth_gas_constants::GAS_PER_MEMORY_WORD - fee_balance_value_cost; - let gas = if naive_cost < discount { - // Cost must be non-negative after discount. - 0 - } else { - naive_cost - discount - }; + // Cost must be non-negative after discount. + let gas = naive_cost.saturating_sub(discount); (u64_from_usize(gas).into(), 0_u8.into()) }; @@ -168,6 +164,7 @@ pub fn estimate_minimal_gas_vector( Transaction::Declare(_) => StateChangesCount { n_storage_updates: 1, n_class_hash_updates: 0, + // TODO(Yoni): BLOCKIFIER-RESET: should be 1. n_compiled_class_hash_updates: 0, n_modified_contracts: 1, }, @@ -186,6 +183,7 @@ pub fn estimate_minimal_gas_vector( }, }; + // TODO(Yoni): BLOCKIFIER-RESET: reuse TransactionReceipt code. let data_segment_length = get_onchain_data_segment_length(&state_changes_by_account_tx); let os_steps_for_type = versioned_constants.os_resources_for_tx_type(&tx.tx_type(), tx.calldata_length()).n_steps diff --git a/crates/blockifier/src/fee/gas_usage_test.rs b/crates/blockifier/src/fee/gas_usage_test.rs index 9d1bcb0f345..586e76b8e19 100644 --- a/crates/blockifier/src/fee/gas_usage_test.rs +++ b/crates/blockifier/src/fee/gas_usage_test.rs @@ -3,18 +3,20 @@ use std::sync::Arc; use num_rational::Ratio; use pretty_assertions::assert_eq; use rstest::{fixture, rstest}; -use starknet_api::block::StarknetVersion; +use starknet_api::block::{FeeType, StarknetVersion}; use starknet_api::execution_resources::{GasAmount, GasVector}; use starknet_api::invoke_tx_args; +use starknet_api::test_utils::{DEFAULT_ETH_L1_DATA_GAS_PRICE, DEFAULT_ETH_L1_GAS_PRICE}; use starknet_api::transaction::fields::GasVectorComputationMode; use starknet_api::transaction::{EventContent, EventData, EventKey}; use starknet_types_core::felt::Felt; use crate::abi::constants; +use crate::blockifier_versioned_constants::{ResourceCost, VersionedConstants, VmResourceCosts}; use crate::context::BlockContext; use crate::execution::call_info::{CallExecution, CallInfo, OrderedEvent}; use crate::fee::eth_gas_constants; -use crate::fee::fee_utils::get_fee_by_gas_vector; +use crate::fee::fee_utils::{get_fee_by_gas_vector, GasVectorToL1GasForFee}; use crate::fee::gas_usage::{get_da_gas_cost, get_message_segment_length}; use crate::fee::resources::{ ComputationResources, @@ -23,15 +25,9 @@ use crate::fee::resources::{ TransactionResources, }; use crate::state::cached_state::StateChangesCount; -use crate::test_utils::{ - get_vm_resource_usage, - DEFAULT_ETH_L1_DATA_GAS_PRICE, - DEFAULT_ETH_L1_GAS_PRICE, -}; -use crate::transaction::objects::FeeType; -use crate::transaction::test_utils::account_invoke_tx; +use crate::test_utils::get_vm_resource_usage; +use crate::transaction::test_utils::invoke_tx_with_default_flags; use crate::utils::u64_from_usize; -use crate::versioned_constants::{ResourceCost, VersionedConstants, VmResourceCosts}; pub fn create_event_for_testing(keys_size: usize, data_size: usize) -> OrderedEvent { OrderedEvent { @@ -283,20 +279,29 @@ fn test_get_message_segment_length( #[rstest] fn test_discounted_gas_from_gas_vector_computation() { - let tx_context = - BlockContext::create_for_testing().to_tx_context(&account_invoke_tx(invoke_tx_args! {})); - let gas_usage = - GasVector { l1_gas: 100_u8.into(), l1_data_gas: 2_u8.into(), ..Default::default() }; - let actual_result = gas_usage.to_discounted_l1_gas(tx_context.get_gas_prices()); + let tx_context = BlockContext::create_for_testing() + .to_tx_context(&invoke_tx_with_default_flags(invoke_tx_args! {})); + let mut gas_usage = + GasVector { l1_gas: 100_u8.into(), l1_data_gas: 2_u8.into(), l2_gas: 3_u8.into() }; + let actual_result = gas_usage.to_l1_gas_for_fee( + tx_context.get_gas_prices(), + &tx_context.block_context.versioned_constants, + ); + let converted_l2_gas = tx_context + .block_context + .versioned_constants + .sierra_gas_to_l1_gas_amount_round_up(gas_usage.l2_gas); let result_div_ceil = gas_usage.l1_gas + (gas_usage.l1_data_gas.checked_mul(DEFAULT_ETH_L1_DATA_GAS_PRICE.into()).unwrap()) .checked_div_ceil(DEFAULT_ETH_L1_GAS_PRICE) - .unwrap(); + .unwrap() + + converted_l2_gas; let result_div_floor = gas_usage.l1_gas + (gas_usage.l1_data_gas.checked_mul(DEFAULT_ETH_L1_DATA_GAS_PRICE.into()).unwrap()) .checked_div(DEFAULT_ETH_L1_GAS_PRICE) - .unwrap(); + .unwrap() + + converted_l2_gas; assert_eq!(actual_result, result_div_ceil); assert_eq!(actual_result, result_div_floor + 1_u8.into()); @@ -304,6 +309,15 @@ fn test_discounted_gas_from_gas_vector_computation() { get_fee_by_gas_vector(&tx_context.block_context.block_info, gas_usage, &FeeType::Eth) <= actual_result.checked_mul(DEFAULT_ETH_L1_GAS_PRICE.into()).unwrap() ); + + // Make sure L2 gas has an effect. + gas_usage.l2_gas = 0_u8.into(); + assert!( + gas_usage.to_l1_gas_for_fee( + tx_context.get_gas_prices(), + &tx_context.block_context.versioned_constants, + ) < actual_result + ); } #[rstest] diff --git a/crates/blockifier/src/fee/receipt.rs b/crates/blockifier/src/fee/receipt.rs index 97805f48b86..6f2a787d963 100644 --- a/crates/blockifier/src/fee/receipt.rs +++ b/crates/blockifier/src/fee/receipt.rs @@ -1,6 +1,6 @@ use starknet_api::core::ContractAddress; use starknet_api::execution_resources::{GasAmount, GasVector}; -use starknet_api::transaction::fields::Fee; +use starknet_api::transaction::fields::{Fee, GasVectorComputationMode}; use crate::context::TransactionContext; use crate::execution::call_info::ExecutionSummary; @@ -22,6 +22,7 @@ pub mod test; /// Parameters required to compute actual cost of a transaction. struct TransactionReceiptParameters<'a> { tx_context: &'a TransactionContext, + gas_mode: GasVectorComputationMode, calldata_length: usize, signature_length: usize, code_size: usize, @@ -31,6 +32,7 @@ struct TransactionReceiptParameters<'a> { execution_summary_without_fee_transfer: ExecutionSummary, tx_type: TransactionType, reverted_steps: usize, + reverted_sierra_gas: GasAmount, } // TODO(Gilad): Use everywhere instead of passing the `actual_{fee,resources}` tuple, which often @@ -49,6 +51,7 @@ impl TransactionReceipt { fn from_params(tx_receipt_params: TransactionReceiptParameters<'_>) -> Self { let TransactionReceiptParameters { tx_context, + gas_mode, calldata_length, signature_length, code_size, @@ -58,6 +61,7 @@ impl TransactionReceipt { execution_summary_without_fee_transfer, tx_type, reverted_steps, + reverted_sierra_gas, } = tx_receipt_params; let charged_resources = execution_summary_without_fee_transfer.charged_resources.clone(); let starknet_resources = StarknetResources::new( @@ -84,15 +88,15 @@ impl TransactionReceipt { computation: ComputationResources { vm_resources: total_vm_resources, n_reverted_steps: reverted_steps, - sierra_gas: charged_resources.gas_for_fee, - reverted_sierra_gas: GasAmount(0), // TODO(tzahi): compute value. + sierra_gas: charged_resources.gas_consumed, + reverted_sierra_gas, }, }; let gas = tx_resources.to_gas_vector( &tx_context.block_context.versioned_constants, tx_context.block_context.block_info.use_kzg_da, - &tx_context.get_gas_vector_computation_mode(), + &gas_mode, ); // Backward-compatibility. let fee = if tx_type == TransactionType::Declare && tx_context.tx_info.is_v0() { @@ -104,7 +108,7 @@ impl TransactionReceipt { let da_gas = tx_resources .starknet_resources .state - .to_gas_vector(tx_context.block_context.block_info.use_kzg_da); + .da_gas_vector(tx_context.block_context.block_info.use_kzg_da); Self { resources: tx_resources, gas, da_gas, fee } } @@ -118,6 +122,7 @@ impl TransactionReceipt { ) -> Self { Self::from_params(TransactionReceiptParameters { tx_context, + gas_mode: GasVectorComputationMode::All, /* Although L1 resources are deprecated, we still want to compute a full gas vector. */ calldata_length: l1_handler_payload_size, signature_length: 0, // Signature is validated on L1. code_size: 0, @@ -127,6 +132,7 @@ impl TransactionReceipt { execution_summary_without_fee_transfer, tx_type: TransactionType::L1Handler, reverted_steps: 0, + reverted_sierra_gas: GasAmount(0), }) } @@ -137,9 +143,11 @@ impl TransactionReceipt { state_changes: &'a StateChanges, execution_summary_without_fee_transfer: ExecutionSummary, reverted_steps: usize, + reverted_sierra_gas: GasAmount, ) -> Self { Self::from_params(TransactionReceiptParameters { tx_context, + gas_mode: tx_context.get_gas_vector_computation_mode(), calldata_length: account_tx.calldata_length(), signature_length: account_tx.signature_length(), code_size: account_tx.declare_code_size(), @@ -149,6 +157,7 @@ impl TransactionReceipt { execution_summary_without_fee_transfer, tx_type: account_tx.tx_type(), reverted_steps, + reverted_sierra_gas, }) } } diff --git a/crates/blockifier/src/fee/receipt_test.rs b/crates/blockifier/src/fee/receipt_test.rs index 496c2b6bdcd..80ebe3114dc 100644 --- a/crates/blockifier/src/fee/receipt_test.rs +++ b/crates/blockifier/src/fee/receipt_test.rs @@ -1,3 +1,6 @@ +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; +use blockifier_test_utils::calldata::{create_calldata, create_trivial_calldata}; +use blockifier_test_utils::contracts::FeatureContract; use rstest::{fixture, rstest}; use starknet_api::execution_resources::GasVector; use starknet_api::transaction::fields::GasVectorComputationMode; @@ -5,6 +8,7 @@ use starknet_api::transaction::{constants, L2ToL1Payload}; use starknet_api::{invoke_tx_args, nonce}; use starknet_types_core::felt::Felt; +use crate::blockifier_versioned_constants::VersionedConstants; use crate::context::BlockContext; use crate::execution::call_info::{ CallExecution, @@ -21,18 +25,17 @@ use crate::fee::gas_usage::{ }; use crate::fee::resources::{StarknetResources, StateResources}; use crate::state::cached_state::StateChangesCount; -use crate::test_utils::contracts::FeatureContract; +use crate::test_utils::contracts::FeatureContractTrait; use crate::test_utils::initial_test_state::test_state; -use crate::test_utils::{create_calldata, create_trivial_calldata, CairoVersion, BALANCE}; +use crate::test_utils::BALANCE; use crate::transaction::objects::HasRelatedFeeType; use crate::transaction::test_utils::{ - account_invoke_tx, calculate_class_info_for_testing, create_resource_bounds, + invoke_tx_with_default_flags, }; use crate::transaction::transactions::ExecutableTransaction; use crate::utils::{u64_from_usize, usize_from_u64}; -use crate::versioned_constants::VersionedConstants; #[fixture] fn versioned_constants() -> &'static VersionedConstants { @@ -49,8 +52,6 @@ fn versioned_constants() -> &'static VersionedConstants { /// 5. A transaction with L2-to-L1 messages. /// 6. A transaction that modifies the storage. /// 7. A combination of cases 4. 5. and 6. -// TODO(Aner, 29/01/24) Refactor with assert on GasVector objects. -// TODO(Aner, 29/01/24) Refactor to replace match with if when formatting is nicer #[rstest] fn test_calculate_tx_gas_usage_basic<'a>( #[values(false, true)] use_kzg_da: bool, @@ -68,7 +69,7 @@ fn test_calculate_tx_gas_usage_basic<'a>( assert_eq!(empty_tx_gas_usage_vector, GasVector::default()); // Declare. - for cairo_version in [CairoVersion::Cairo0, CairoVersion::Cairo1] { + for cairo_version in [CairoVersion::Cairo0, CairoVersion::Cairo1(RunnableCairo1::Casm)] { let empty_contract = FeatureContract::Empty(cairo_version).get_class(); let class_info = calculate_class_info_for_testing(empty_contract); let declare_tx_starknet_resources = StarknetResources::new( @@ -136,7 +137,9 @@ fn test_calculate_tx_gas_usage_basic<'a>( GasVectorComputationMode::All => GasVector::from_l2_gas(calldata_and_signature_gas_cost), }; let manual_gas_vector = manual_starknet_gas_usage_vector - + deploy_account_tx_starknet_resources.state.to_gas_vector(use_kzg_da); + + deploy_account_tx_starknet_resources + .state + .to_gas_vector(use_kzg_da, &versioned_constants.allocation_cost); let deploy_account_gas_usage_vector = deploy_account_tx_starknet_resources.to_gas_vector( &versioned_constants, @@ -249,10 +252,18 @@ fn test_calculate_tx_gas_usage_basic<'a>( .unwrap(); let manual_sharp_gas_usage = message_segment_length * eth_gas_constants::SHARP_GAS_PER_MEMORY_WORD - + usize_from_u64(l2_to_l1_starknet_resources.state.to_gas_vector(use_kzg_da).l1_gas.0) - .unwrap(); - let manual_sharp_blob_gas_usage = - l2_to_l1_starknet_resources.state.to_gas_vector(use_kzg_da).l1_data_gas; + + usize_from_u64( + l2_to_l1_starknet_resources + .state + .to_gas_vector(use_kzg_da, &versioned_constants.allocation_cost) + .l1_gas + .0, + ) + .unwrap(); + let manual_sharp_blob_gas_usage = l2_to_l1_starknet_resources + .state + .to_gas_vector(use_kzg_da, &versioned_constants.allocation_cost) + .l1_data_gas; let manual_gas_computation = GasVector { l1_gas: u64_from_usize(manual_starknet_gas_usage + manual_sharp_gas_usage).into(), l1_data_gas: manual_sharp_blob_gas_usage, @@ -288,7 +299,9 @@ fn test_calculate_tx_gas_usage_basic<'a>( // Manual calculation. // No L2 gas is used, so gas amount does not depend on gas vector computation mode. - let manual_gas_computation = storage_writes_starknet_resources.state.to_gas_vector(use_kzg_da); + let manual_gas_computation = storage_writes_starknet_resources + .state + .to_gas_vector(use_kzg_da, &versioned_constants.allocation_cost); assert_eq!(manual_gas_computation, storage_writings_gas_usage_vector); @@ -334,7 +347,10 @@ fn test_calculate_tx_gas_usage_basic<'a>( // the combined calculation got it once. + u64_from_usize(fee_balance_discount).into(), // Expected blob gas usage is from data availability only. - l1_data_gas: combined_cases_starknet_resources.state.to_gas_vector(use_kzg_da).l1_data_gas, + l1_data_gas: combined_cases_starknet_resources + .state + .to_gas_vector(use_kzg_da, &versioned_constants.allocation_cost) + .l1_data_gas, l2_gas: l1_handler_gas_usage_vector.l2_gas, }; @@ -360,7 +376,7 @@ fn test_calculate_tx_gas_usage( let account_contract_address = account_contract.get_instance_address(0); let state = &mut test_state(chain_info, BALANCE, &[(account_contract, 1), (test_contract, 1)]); - let account_tx = account_invoke_tx(invoke_tx_args! { + let account_tx = invoke_tx_with_default_flags(invoke_tx_args! { sender_address: account_contract_address, calldata: create_trivial_calldata(test_contract.get_instance_address(0)), resource_bounds: max_resource_bounds, @@ -368,7 +384,7 @@ fn test_calculate_tx_gas_usage( let calldata_length = account_tx.calldata_length(); let signature_length = account_tx.signature_length(); let fee_token_address = chain_info.fee_token_address(&account_tx.fee_type()); - let tx_execution_info = account_tx.execute(state, block_context, true, true).unwrap(); + let tx_execution_info = account_tx.execute(state, block_context).unwrap(); let n_storage_updates = 1; // For the account balance update. let n_modified_contracts = 1; @@ -378,11 +394,12 @@ fn test_calculate_tx_gas_usage( n_modified_contracts, n_compiled_class_hash_updates: 0, }; + let n_allocated_keys = 0; // This tx doesn't allocate the account balance. let starknet_resources = StarknetResources::new( calldata_length, signature_length, 0, - StateResources::new_for_testing(state_changes_count, 0), + StateResources::new_for_testing(state_changes_count, n_allocated_keys), None, ExecutionSummary::default(), ); @@ -412,7 +429,7 @@ fn test_calculate_tx_gas_usage( ], ); - let account_tx = account_invoke_tx(invoke_tx_args! { + let account_tx = invoke_tx_with_default_flags(invoke_tx_args! { resource_bounds: max_resource_bounds, sender_address: account_contract_address, calldata: execute_calldata, @@ -421,7 +438,7 @@ fn test_calculate_tx_gas_usage( let calldata_length = account_tx.calldata_length(); let signature_length = account_tx.signature_length(); - let tx_execution_info = account_tx.execute(state, block_context, true, true).unwrap(); + let tx_execution_info = account_tx.execute(state, block_context).unwrap(); // For the balance update of the sender and the recipient. let n_storage_updates = 2; // Only the account contract modification (nonce update) excluding the fee token contract. @@ -432,6 +449,7 @@ fn test_calculate_tx_gas_usage( n_modified_contracts, n_compiled_class_hash_updates: 0, }; + let n_allocated_keys = 1; // Only for the recipient. let execution_call_info = &tx_execution_info.execute_call_info.expect("Execution call info should exist."); let execution_summary = @@ -440,7 +458,7 @@ fn test_calculate_tx_gas_usage( calldata_length, signature_length, 0, - StateResources::new_for_testing(state_changes_count, 0), + StateResources::new_for_testing(state_changes_count, n_allocated_keys), None, // The transfer entrypoint emits an event - pass the call info to count its resources. execution_summary, diff --git a/crates/blockifier/src/fee/resources.rs b/crates/blockifier/src/fee/resources.rs index c69b53f5310..7b29cc8ceea 100644 --- a/crates/blockifier/src/fee/resources.rs +++ b/crates/blockifier/src/fee/resources.rs @@ -3,7 +3,10 @@ use starknet_api::core::ContractAddress; use starknet_api::execution_resources::{GasAmount, GasVector}; use starknet_api::transaction::fields::GasVectorComputationMode; +use crate::blockifier_versioned_constants::{AllocationCost, VersionedConstants}; use crate::execution::call_info::{EventSummary, ExecutionSummary}; +#[cfg(test)] +use crate::execution::contract_class::TrackedResource; use crate::fee::eth_gas_constants; use crate::fee::fee_utils::get_vm_resources_cost; use crate::fee::gas_usage::{ @@ -16,7 +19,6 @@ use crate::fee::gas_usage::{ use crate::state::cached_state::{StateChanges, StateChangesCountForFee}; use crate::transaction::errors::TransactionFeeError; use crate::utils::u64_from_usize; -use crate::versioned_constants::{ArchivalDataGasCosts, VersionedConstants}; pub type TransactionFeeResult = Result; @@ -73,14 +75,21 @@ impl ComputationResources { self.n_reverted_steps, computation_mode, ); - let sierra_gas_cost = GasVector::from_l2_gas( + + let total_sierra_gas = self.sierra_gas.checked_add(self.reverted_sierra_gas).unwrap_or_else(|| { panic!( "Sierra gas overflowed: tried to add {} to {}", self.sierra_gas, self.reverted_sierra_gas ) - }), - ); + }); + let sierra_gas_cost = match computation_mode { + GasVectorComputationMode::All => GasVector::from_l2_gas(total_sierra_gas), + GasVectorComputationMode::NoL2Gas => GasVector::from_l1_gas( + versioned_constants.sierra_gas_to_l1_gas_amount_round_up(total_sierra_gas), + ), + }; + vm_cost.checked_add(sierra_gas_cost).unwrap_or_else(|| { panic!( "Computation resources to gas vector overflowed: tried to add {sierra_gas_cost:?} \ @@ -89,9 +98,15 @@ impl ComputationResources { }) } + /// Returns total consumed + reverted units of steps or sierra gas. #[cfg(test)] - pub fn total_charged_steps(&self) -> usize { - self.n_reverted_steps + self.vm_resources.n_steps + pub fn total_charged_computation_units(&self, resource: TrackedResource) -> usize { + match resource { + TrackedResource::CairoSteps => self.vm_resources.n_steps + self.n_reverted_steps, + TrackedResource::SierraGas => { + usize::try_from(self.sierra_gas.0 + self.reverted_sierra_gas.0).unwrap() + } + } } } @@ -139,7 +154,7 @@ impl StarknetResources { ) -> GasVector { [ self.archival_data.to_gas_vector(versioned_constants, mode), - self.state.to_gas_vector(use_kzg_da), + self.state.to_gas_vector(use_kzg_da, &versioned_constants.allocation_cost), self.messages.to_gas_vector(), ] .iter() @@ -186,9 +201,30 @@ impl StateResources { } /// Returns the gas cost of the transaction's state changes. - pub fn to_gas_vector(&self, use_kzg_da: bool) -> GasVector { - // TODO(Nimrod, 29/3/2024): delete `get_da_gas_cost` and move it's logic here. - // TODO(Yoav): Add the cost of allocating keys. + pub fn to_gas_vector(&self, use_kzg_da: bool, allocation_cost: &AllocationCost) -> GasVector { + let n_allocated_keys: u64 = self + .state_changes_for_fee + .n_allocated_keys + .try_into() + .expect("n_allocated_keys overflowed"); + let allocation_gas_vector = allocation_cost.get_cost(use_kzg_da); + let total_allocation_cost = + allocation_gas_vector.checked_scalar_mul(n_allocated_keys).unwrap_or_else(|| { + panic!( + "State resources to gas vector overflowed: tried to multiply \ + {allocation_gas_vector:?} by {n_allocated_keys:?}", + ) + }); + let da_gas_cost = self.da_gas_vector(use_kzg_da); + total_allocation_cost.checked_add(da_gas_cost).unwrap_or_else(|| { + panic!( + "State resources to gas vector overflowed: tried to add {total_allocation_cost:?} \ + to {da_gas_cost:?}", + ) + }) + } + + pub fn da_gas_vector(&self, use_kzg_da: bool) -> GasVector { get_da_gas_cost(&self.state_changes_for_fee.state_changes_count, use_kzg_da) } @@ -202,8 +238,8 @@ impl StateResources { pub struct ArchivalDataResources { pub event_summary: EventSummary, pub calldata_length: usize, - signature_length: usize, - code_size: usize, + pub signature_length: usize, + pub code_size: usize, } impl ArchivalDataResources { @@ -214,60 +250,60 @@ impl ArchivalDataResources { versioned_constants: &VersionedConstants, mode: &GasVectorComputationMode, ) -> GasVector { - let archival_gas_costs = match mode { - // Computation is in L2 gas units. - GasVectorComputationMode::All => &versioned_constants.archival_data_gas_costs, - // Computation is in L1 gas units. - GasVectorComputationMode::NoL2Gas => { - &versioned_constants.deprecated_l2_resource_gas_costs - } - }; - let gas_amount = [ - self.get_calldata_and_signature_gas_cost(archival_gas_costs), - self.get_code_gas_cost(archival_gas_costs), - self.get_events_gas_cost(archival_gas_costs), + [ + self.get_calldata_and_signature_gas_cost(versioned_constants, mode), + self.get_code_gas_cost(versioned_constants, mode), + self.event_summary.to_gas_vector(versioned_constants, mode), ] .into_iter() - .fold(GasAmount::ZERO, |accumulator, cost| { + .fold(GasVector::ZERO, |accumulator, cost| { accumulator.checked_add(cost).unwrap_or_else(|| { panic!( "Archival data resources to gas vector overflowed: tried to add \ - {accumulator:?} gas to {cost:?} gas.", + {accumulator:?} gas vector to {cost:?} gas vector.", ) }) - }); - match mode { - GasVectorComputationMode::All => GasVector::from_l2_gas(gas_amount), - GasVectorComputationMode::NoL2Gas => GasVector::from_l1_gas(gas_amount), - } + }) } /// Returns the cost for transaction calldata and transaction signature. Each felt costs a /// fixed and configurable amount of gas. This cost represents the cost of storing the - /// calldata and the signature on L2. The result is given in L1/L2 gas units, depending on the - /// mode. + /// calldata and the signature on L2. fn get_calldata_and_signature_gas_cost( &self, - archival_gas_costs: &ArchivalDataGasCosts, - ) -> GasAmount { + versioned_constants: &VersionedConstants, + mode: &GasVectorComputationMode, + ) -> GasVector { + let archival_gas_costs = versioned_constants.get_archival_data_gas_costs(mode); + // TODO(Avi, 20/2/2024): Calculate the number of bytes instead of the number of felts. let total_data_size = u64_from_usize(self.calldata_length + self.signature_length); - (archival_gas_costs.gas_per_data_felt * total_data_size).to_integer().into() - } + let gas_amount = + (archival_gas_costs.gas_per_data_felt * total_data_size).to_integer().into(); - /// Returns the cost of declared class codes in L1/L2 gas units, depending on the mode. - fn get_code_gas_cost(&self, archival_gas_costs: &ArchivalDataGasCosts) -> GasAmount { - (archival_gas_costs.gas_per_code_byte * u64_from_usize(self.code_size)).to_integer().into() + match mode { + GasVectorComputationMode::All => GasVector::from_l2_gas(gas_amount), + GasVectorComputationMode::NoL2Gas => GasVector::from_l1_gas(gas_amount), + } } - /// Returns the cost of the transaction's emmited events in L1/L2 gas units, depending on the - /// mode. - fn get_events_gas_cost(&self, archival_gas_costs: &ArchivalDataGasCosts) -> GasAmount { - (archival_gas_costs.gas_per_data_felt - * (archival_gas_costs.event_key_factor * self.event_summary.total_event_keys - + self.event_summary.total_event_data_size)) - .to_integer() - .into() + /// Returns the cost of declared class codes. + fn get_code_gas_cost( + &self, + versioned_constants: &VersionedConstants, + mode: &GasVectorComputationMode, + ) -> GasVector { + let archival_gas_costs = versioned_constants.get_archival_data_gas_costs(mode); + + let gas_amount: GasAmount = (archival_gas_costs.gas_per_code_byte + * u64_from_usize(self.code_size)) + .to_integer() + .into(); + + match mode { + GasVectorComputationMode::All => GasVector::from_l2_gas(gas_amount), + GasVectorComputationMode::NoL2Gas => GasVector::from_l1_gas(gas_amount), + } } } diff --git a/crates/blockifier/src/lib.rs b/crates/blockifier/src/lib.rs index 8129f9f65bc..480fc64e054 100644 --- a/crates/blockifier/src/lib.rs +++ b/crates/blockifier/src/lib.rs @@ -4,13 +4,9 @@ // when converting usize to u128. #![cfg(any(target_pointer_width = "16", target_pointer_width = "32", target_pointer_width = "64",))] -#[cfg(feature = "jemalloc")] -// Override default allocator. -#[global_allocator] -static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; - pub mod abi; pub mod blockifier; +pub mod blockifier_versioned_constants; pub mod bouncer; pub mod concurrency; pub mod context; @@ -21,4 +17,3 @@ pub mod state; pub mod test_utils; pub mod transaction; pub mod utils; -pub mod versioned_constants; diff --git a/crates/blockifier/src/state.rs b/crates/blockifier/src/state.rs index e027d2b301c..a2f784c311f 100644 --- a/crates/blockifier/src/state.rs +++ b/crates/blockifier/src/state.rs @@ -1,6 +1,10 @@ pub mod cached_state; +pub mod contract_class_manager; #[cfg(test)] pub mod error_format_test; pub mod errors; pub mod global_cache; +#[cfg(feature = "cairo_native")] +pub mod native_class_manager; pub mod state_api; +pub mod stateful_compression; diff --git a/crates/blockifier/src/state/cached_state.rs b/crates/blockifier/src/state/cached_state.rs index dbb84243e7e..ef28aaec15b 100644 --- a/crates/blockifier/src/state/cached_state.rs +++ b/crates/blockifier/src/state/cached_state.rs @@ -1,4 +1,4 @@ -use std::cell::RefCell; +use std::cell::{Ref, RefCell}; use std::collections::{HashMap, HashSet}; use indexmap::IndexMap; @@ -8,7 +8,7 @@ use starknet_api::state::StorageKey; use starknet_types_core::felt::Felt; use crate::context::TransactionContext; -use crate::execution::contract_class::RunnableContractClass; +use crate::execution::contract_class::RunnableCompiledClass; use crate::state::errors::StateError; use crate::state::state_api::{State, StateReader, StateResult, UpdatableState}; use crate::transaction::objects::TransactionExecutionInfo; @@ -18,21 +18,20 @@ use crate::utils::{strict_subtract_mappings, subtract_mappings}; #[path = "cached_state_test.rs"] mod test; -pub type ContractClassMapping = HashMap; +pub type ContractClassMapping = HashMap; /// Caches read and write requests. /// /// Writer functionality is builtin, whereas Reader functionality is injected through /// initialization. +#[cfg_attr(any(test, feature = "reexecution"), derive(Clone))] #[derive(Debug)] pub struct CachedState { pub state: S, // Invariant: read/write access is managed by CachedState. // Using interior mutability to update caches during `State`'s immutable getters. - pub(crate) cache: RefCell, - pub(crate) class_hash_to_class: RefCell, - /// A map from class hash to the set of PC values that were visited in the class. - pub visited_pcs: HashMap>, + pub cache: RefCell, + pub class_hash_to_class: RefCell, } impl CachedState { @@ -41,7 +40,6 @@ impl CachedState { state, cache: RefCell::new(StateCache::default()), class_hash_to_class: RefCell::new(HashMap::default()), - visited_pcs: HashMap::default(), } } @@ -58,6 +56,11 @@ impl CachedState { self.to_state_diff() } + pub fn borrow_updated_state_cache(&mut self) -> StateResult> { + self.update_initial_values_of_write_only_access()?; + Ok(self.cache.borrow()) + } + pub fn update_cache( &mut self, write_updates: &StateMaps, @@ -72,12 +75,6 @@ impl CachedState { self.class_hash_to_class.get_mut().extend(local_contract_cache_updates); } - pub fn update_visited_pcs_cache(&mut self, visited_pcs: &HashMap>) { - for (class_hash, class_visited_pcs) in visited_pcs { - self.add_visited_pcs(*class_hash, class_visited_pcs); - } - } - /// Updates cache with initial cell values for write-only access. /// If written values match the original, the cell is unchanged and not counted as a /// storage-change for fee calculation. @@ -85,8 +82,7 @@ impl CachedState { /// * Nonce: read previous before incrementing. /// * Class hash: Deploy: verify the address is not occupied; Replace class: verify the /// contract is deployed before running any code. - /// * Compiled class hash: verify the class is not declared through - /// `get_compiled_contract_class`. + /// * Compiled class hash: verify the class is not declared through `get_compiled_class`. /// /// TODO(Noa, 30/07/23): Consider adding DB getters in bulk (via a DB read transaction). fn update_initial_values_of_write_only_access(&mut self) -> StateResult<()> { @@ -104,18 +100,22 @@ impl CachedState { } Ok(()) } + + pub fn writes_contract_addresses(&self) -> HashSet { + self.cache.borrow().writes.get_contract_addresses() + } + + // TODO(Aner): move under OS cfg flag. + // TODO(Aner): Try to avoid cloning. + pub fn writes_compiled_class_hashes(&self) -> HashMap { + self.cache.borrow().writes.compiled_class_hashes.clone() + } } impl UpdatableState for CachedState { - fn apply_writes( - &mut self, - writes: &StateMaps, - class_hash_to_class: &ContractClassMapping, - visited_pcs: &HashMap>, - ) { + fn apply_writes(&mut self, writes: &StateMaps, class_hash_to_class: &ContractClassMapping) { // TODO(Noa,15/5/24): Reconsider the clone. self.update_cache(writes, class_hash_to_class.clone()); - self.update_visited_pcs_cache(visited_pcs); } } @@ -174,17 +174,14 @@ impl StateReader for CachedState { Ok(*class_hash) } - fn get_compiled_contract_class( - &self, - class_hash: ClassHash, - ) -> StateResult { + fn get_compiled_class(&self, class_hash: ClassHash) -> StateResult { let mut cache = self.cache.borrow_mut(); let class_hash_to_class = &mut *self.class_hash_to_class.borrow_mut(); if let std::collections::hash_map::Entry::Vacant(vacant_entry) = class_hash_to_class.entry(class_hash) { - match self.state.get_compiled_contract_class(class_hash) { + match self.state.get_compiled_class(class_hash) { Err(StateError::UndeclaredClassHash(class_hash)) => { cache.set_declared_contract_initial_value(class_hash, false); cache.set_compiled_class_hash_initial_value( @@ -260,7 +257,7 @@ impl State for CachedState { fn set_contract_class( &mut self, class_hash: ClassHash, - contract_class: RunnableContractClass, + contract_class: RunnableCompiledClass, ) -> StateResult<()> { self.class_hash_to_class.get_mut().insert(class_hash, contract_class); let mut cache = self.cache.borrow_mut(); @@ -276,10 +273,6 @@ impl State for CachedState { self.cache.get_mut().set_compiled_class_hash_write(class_hash, compiled_class_hash); Ok(()) } - - fn add_visited_pcs(&mut self, class_hash: ClassHash, pcs: &HashSet) { - self.visited_pcs.entry(class_hash).or_default().extend(pcs); - } } #[cfg(any(feature = "testing", test))] @@ -289,7 +282,6 @@ impl Default for CachedState HashSet { + pub fn get_contract_addresses(&self) -> HashSet { // Storage updates. let mut modified_contracts: HashSet = self.storage.keys().map(|address_key_pair| address_key_pair.0).collect(); @@ -373,13 +365,13 @@ impl StateMaps { modified_contracts } - pub fn into_keys(self) -> StateChangesKeys { + pub fn keys(&self) -> StateChangesKeys { StateChangesKeys { - modified_contracts: self.get_modified_contracts(), - nonce_keys: self.nonces.into_keys().collect(), - class_hash_keys: self.class_hashes.into_keys().collect(), - storage_keys: self.storage.into_keys().collect(), - compiled_class_hash_keys: self.compiled_class_hashes.into_keys().collect(), + modified_contracts: self.get_contract_addresses(), + nonce_keys: self.nonces.keys().cloned().collect(), + class_hash_keys: self.class_hashes.keys().cloned().collect(), + storage_keys: self.storage.keys().cloned().collect(), + compiled_class_hash_keys: self.compiled_class_hashes.keys().cloned().collect(), } } } @@ -387,7 +379,7 @@ impl StateMaps { /// The tracked changes are needed for block state commitment. // Invariant: keys cannot be deleted from fields (only used internally by the cached state). -#[derive(Debug, Default, PartialEq, Eq)] +#[derive(Clone, Debug, Default, PartialEq, Eq)] pub struct StateCache { // Reader's cached information; initial values, read before any write operation (per cell). pub(crate) initial_reads: StateMaps, @@ -406,6 +398,44 @@ impl StateCache { StateChanges { state_maps, allocated_keys } } + /// Squashes the given state caches into a single one and returns the state diff. Note that the + /// order of the state caches is important. + pub fn squash_state_caches(state_caches: Vec<&Self>) -> Self { + let mut squashed_state_cache = StateCache::default(); + + // Gives priority to early initial reads. + state_caches.iter().rev().for_each(|state_cache| { + squashed_state_cache.initial_reads.extend(&state_cache.initial_reads) + }); + // Gives priority to late writes. + state_caches + .iter() + .for_each(|state_cache| squashed_state_cache.writes.extend(&state_cache.writes)); + squashed_state_cache + } + + /// Squashes the given state caches into a single one and returns the state diff. Note that the + /// order of the state caches is important. + /// If 'comprehensive_state_diff' is false, opposite updates may not be canceled out. Used for + /// backward compatibility. + pub fn squash_state_diff( + state_caches: Vec<&Self>, + comprehensive_state_diff: bool, + ) -> StateChanges { + if comprehensive_state_diff { + return Self::squash_state_caches(state_caches).to_state_diff(); + } + + // Backward compatibility. + let mut merged_state_changes = StateChanges::default(); + for state_cache in state_caches { + let state_change = state_cache.to_state_diff(); + merged_state_changes.state_maps.extend(&state_change.state_maps); + merged_state_changes.allocated_keys.0.extend(&state_change.allocated_keys.0); + } + merged_state_changes + } + fn declare_contract(&mut self, class_hash: ClassHash) { self.writes.declared_contracts.insert(class_hash, true); } @@ -511,7 +541,7 @@ impl<'a, S: StateReader + ?Sized> MutRefState<'a, S> { } /// Proxies inner object to expose `State` functionality. -impl<'a, S: StateReader + ?Sized> StateReader for MutRefState<'a, S> { +impl StateReader for MutRefState<'_, S> { fn get_storage_at( &self, contract_address: ContractAddress, @@ -528,11 +558,8 @@ impl<'a, S: StateReader + ?Sized> StateReader for MutRefState<'a, S> { self.0.get_class_hash_at(contract_address) } - fn get_compiled_contract_class( - &self, - class_hash: ClassHash, - ) -> StateResult { - self.0.get_compiled_contract_class(class_hash) + fn get_compiled_class(&self, class_hash: ClassHash) -> StateResult { + self.0.get_compiled_class(class_hash) } fn get_compiled_class_hash(&self, class_hash: ClassHash) -> StateResult { @@ -542,7 +569,7 @@ impl<'a, S: StateReader + ?Sized> StateReader for MutRefState<'a, S> { pub type TransactionalState<'a, U> = CachedState>; -impl<'a, S: StateReader> TransactionalState<'a, S> { +impl TransactionalState<'_, S> { /// Creates a transactional instance from the given updatable state. /// It allows performing buffered modifying actions on the given state, which /// will either all happen (will be updated in the state and committed) @@ -556,16 +583,12 @@ impl<'a, S: StateReader> TransactionalState<'a, S> { } /// Adds the ability to perform a transactional execution. -impl<'a, U: UpdatableState> TransactionalState<'a, U> { +impl TransactionalState<'_, U> { /// Commits changes in the child (wrapping) state to its parent. pub fn commit(self) { let state = self.state.0; let child_cache = self.cache.into_inner(); - state.apply_writes( - &child_cache.writes, - &self.class_hash_to_class.into_inner(), - &self.visited_pcs, - ) + state.apply_writes(&child_cache.writes, &self.class_hash_to_class.into_inner()) } } @@ -573,8 +596,7 @@ type StorageDiff = IndexMap>; /// Holds uncommitted changes induced on Starknet contracts. #[cfg_attr(feature = "transaction_serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(any(feature = "testing", test), derive(Clone))] -#[derive(Debug, Default, Eq, PartialEq)] +#[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct CommitmentStateDiff { // Contract instance attributes (per address). pub address_to_class_hash: IndexMap, @@ -687,18 +709,6 @@ impl StateChangesKeys { pub struct AllocatedKeys(HashSet); impl AllocatedKeys { - /// Extends the set of allocated keys with the allocated_keys of the given state changes. - /// Removes storage keys that are set back to zero. - pub fn update(&mut self, state_change: &StateChanges) { - self.0.extend(&state_change.allocated_keys.0); - // Remove keys that are set back to zero. - state_change.state_maps.storage.iter().for_each(|(k, v)| { - if v == &Felt::ZERO { - self.0.remove(k); - } - }); - } - pub fn len(&self) -> usize { self.0.len() } @@ -733,23 +743,12 @@ pub struct StateChanges { } impl StateChanges { - /// Merges the given state changes into a single one. Note that the order of the state changes - /// is important. The state changes are merged in the order they appear in the given vector. - pub fn merge(state_changes: Vec) -> Self { - let mut merged_state_changes = Self::default(); - for state_change in state_changes { - merged_state_changes.state_maps.extend(&state_change.state_maps); - merged_state_changes.allocated_keys.update(&state_change); - } - merged_state_changes - } - pub fn count_for_fee_charge( &self, sender_address: Option, fee_token_address: ContractAddress, ) -> StateChangesCountForFee { - let mut modified_contracts = self.state_maps.get_modified_contracts(); + let mut modified_contracts = self.state_maps.get_contract_addresses(); // For account transactions, we need to compute the transaction fee before we can execute // the fee transfer, and the fee should cover the state changes that happen in the diff --git a/crates/blockifier/src/state/cached_state_test.rs b/crates/blockifier/src/state/cached_state_test.rs index bcc91ab2f57..04b7f31e9e8 100644 --- a/crates/blockifier/src/state/cached_state_test.rs +++ b/crates/blockifier/src/state/cached_state_test.rs @@ -1,18 +1,30 @@ use std::collections::HashMap; use assert_matches::assert_matches; +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; +use blockifier_test_utils::calldata::create_calldata; +use blockifier_test_utils::contracts::FeatureContract; use indexmap::indexmap; use pretty_assertions::assert_eq; use rstest::rstest; -use starknet_api::transaction::fields::Fee; -use starknet_api::{class_hash, compiled_class_hash, contract_address, felt, nonce, storage_key}; +use starknet_api::transaction::fields::{Fee, TransactionSignature, ValidResourceBounds}; +use starknet_api::{ + class_hash, + compiled_class_hash, + contract_address, + felt, + invoke_tx_args, + nonce, + storage_key, +}; use crate::context::{BlockContext, ChainInfo}; use crate::state::cached_state::*; -use crate::test_utils::contracts::FeatureContract; +use crate::test_utils::contracts::FeatureContractTrait; use crate::test_utils::dict_state_reader::DictStateReader; use crate::test_utils::initial_test_state::test_state; -use crate::test_utils::CairoVersion; +use crate::test_utils::BALANCE; +use crate::transaction::test_utils::{default_all_resource_bounds, run_invoke_tx, STORAGE_WRITE}; const CONTRACT_ADDRESS: &str = "0x100"; fn set_initial_state_values( @@ -115,7 +127,7 @@ fn declare_contract() { // Reading an undeclared contract class. assert_matches!( - state.get_compiled_contract_class(class_hash).unwrap_err(), + state.get_compiled_class(class_hash).unwrap_err(), StateError::UndeclaredClassHash(undeclared_class_hash) if undeclared_class_hash == class_hash ); @@ -166,14 +178,14 @@ fn get_contract_class() { let test_contract = FeatureContract::TestContract(CairoVersion::Cairo0); let state = test_state(&ChainInfo::create_for_testing(), Fee(0), &[(test_contract, 0)]); assert_eq!( - state.get_compiled_contract_class(test_contract.get_class_hash()).unwrap(), + state.get_compiled_class(test_contract.get_class_hash()).unwrap(), test_contract.get_runnable_class() ); // Negative flow. let missing_class_hash = class_hash!("0x101"); assert_matches!( - state.get_compiled_contract_class(missing_class_hash).unwrap_err(), + state.get_compiled_class(missing_class_hash).unwrap_err(), StateError::UndeclaredClassHash(undeclared) if undeclared == missing_class_hash ); } @@ -261,7 +273,7 @@ fn cached_state_state_diff_conversion() { let class_hash = FeatureContract::Empty(CairoVersion::Cairo0).get_class_hash(); let compiled_class_hash = compiled_class_hash!(1_u8); // Cache the initial read value, as in regular declare flow. - state.get_compiled_contract_class(class_hash).unwrap_err(); + state.get_compiled_class(class_hash).unwrap_err(); state.set_compiled_class_hash(class_hash, compiled_class_hash).unwrap(); // Write the initial value using key contract_address1. @@ -289,11 +301,11 @@ fn cached_state_state_diff_conversion() { assert_eq!(expected_state_diff, state.to_state_diff().unwrap().state_maps.into()); } -fn create_state_changes_for_test( +fn create_state_cache_for_test( state: &mut CachedState, sender_address: Option, fee_token_address: ContractAddress, -) -> StateChanges { +) -> StateCache { let contract_address = contract_address!(CONTRACT_ADDRESS); let contract_address2 = contract_address!("0x101"); let class_hash = class_hash!("0x10"); @@ -309,7 +321,7 @@ fn create_state_changes_for_test( state.increment_nonce(contract_address2).unwrap(); // Fill the initial read value, as in regular flow. - state.get_compiled_contract_class(class_hash).unwrap_err(); + state.get_compiled_class(class_hash).unwrap_err(); state.set_compiled_class_hash(class_hash, compiled_class_hash).unwrap(); // Assign the existing value to the storage (this shouldn't be considered a change). @@ -323,7 +335,7 @@ fn create_state_changes_for_test( let sender_balance_key = get_fee_token_var_address(sender_address); state.set_storage_at(fee_token_address, sender_balance_key, felt!("0x1999")).unwrap(); } - state.get_actual_state_changes().unwrap() + state.borrow_updated_state_cache().unwrap().clone() } #[rstest] @@ -333,7 +345,7 @@ fn test_from_state_changes_for_fee_charge( let mut state: CachedState = CachedState::default(); let fee_token_address = contract_address!("0x17"); let state_changes = - create_state_changes_for_test(&mut state, sender_address, fee_token_address); + create_state_cache_for_test(&mut state, sender_address, fee_token_address).to_state_diff(); let state_changes_count = state_changes.count_for_fee_charge(sender_address, fee_token_address); let n_expected_storage_updates = 1 + usize::from(sender_address.is_some()); let expected_state_changes_count = StateChangesCountForFee { @@ -350,37 +362,32 @@ fn test_from_state_changes_for_fee_charge( } #[rstest] -fn test_state_changes_merge( +fn test_state_cache_merge( #[values(Some(contract_address!("0x102")), None)] sender_address: Option, ) { // Create a transactional state containing the `create_state_changes_for_test` logic, get the - // state changes and then commit. + // state cache and then commit. let mut state: CachedState = CachedState::default(); let mut transactional_state = TransactionalState::create_transactional(&mut state); let block_context = BlockContext::create_for_testing(); let fee_token_address = block_context.chain_info.fee_token_addresses.eth_fee_token_address; - let state_changes1 = - create_state_changes_for_test(&mut transactional_state, sender_address, fee_token_address); + let state_cache1 = + create_state_cache_for_test(&mut transactional_state, sender_address, fee_token_address); transactional_state.commit(); // After performing `commit`, the transactional state is moved (into state). We need to create // a new transactional state that wraps `state` to continue. let mut transactional_state = TransactionalState::create_transactional(&mut state); - // Make sure that `get_actual_state_changes` on a newly created transactional state returns null - // state changes and that merging null state changes with non-null state changes results in the - // non-null state changes, no matter the order. - let state_changes2 = transactional_state.get_actual_state_changes().unwrap(); - assert_eq!(state_changes2, StateChanges::default()); - assert_eq!( - StateChanges::merge(vec![state_changes1.clone(), state_changes2.clone()]), - state_changes1 - ); - assert_eq!( - StateChanges::merge(vec![state_changes2.clone(), state_changes1.clone()]), - state_changes1 - ); - - // Get the storage updates addresses and keys from the state_changes1, to overwrite. + // Make sure that the state_changes of a newly created transactional state returns null + // state cache and that merging null state cache with non-null state cache results in the + // non-null state cache, no matter the order. + let state_cache2 = transactional_state.borrow_updated_state_cache().unwrap().clone(); + assert_eq!(state_cache2, StateCache::default()); + assert_eq!(StateCache::squash_state_caches(vec![&state_cache1, &state_cache2]), state_cache1); + assert_eq!(StateCache::squash_state_caches(vec![&state_cache2, &state_cache1]), state_cache1); + + // Get the storage updates addresses and keys from the state_cache1, to overwrite. + let state_changes1 = state_cache1.to_state_diff(); let mut storage_updates_keys = state_changes1.state_maps.storage.keys(); let &(contract_address, storage_key) = storage_updates_keys .find(|(contract_address, _)| contract_address == &contract_address!(CONTRACT_ADDRESS)) @@ -394,8 +401,8 @@ fn test_state_changes_merge( .set_storage_at(new_contract_address, storage_key, felt!("0x43210")) .unwrap(); transactional_state.increment_nonce(contract_address).unwrap(); - // Get the new state changes and then commit the transactional state. - let state_changes3 = transactional_state.get_actual_state_changes().unwrap(); + // Get the new state cache and then commit the transactional state. + let state_cache3 = transactional_state.borrow_updated_state_cache().unwrap().clone(); transactional_state.commit(); // Get the total state changes of the CachedState underlying all the temporary transactional @@ -403,15 +410,13 @@ fn test_state_changes_merge( // states, but only when done in the right order. let state_changes_final = state.get_actual_state_changes().unwrap(); assert_eq!( - StateChanges::merge(vec![ - state_changes1.clone(), - state_changes2.clone(), - state_changes3.clone() - ]), + StateCache::squash_state_caches(vec![&state_cache1, &state_cache2, &state_cache3]) + .to_state_diff(), state_changes_final ); assert_ne!( - StateChanges::merge(vec![state_changes3, state_changes1, state_changes2]), + StateCache::squash_state_caches(vec![&state_cache3, &state_cache1, &state_cache2]) + .to_state_diff(), state_changes_final ); } @@ -422,67 +427,105 @@ fn test_state_changes_merge( #[case(true, vec![felt!("0x7")], true)] #[case(false, vec![felt!("0x7")], false)] #[case(true, vec![felt!("0x7"), felt!("0x0")], false)] -#[case(false, vec![felt!("0x0"), felt!("0x8")], true)] +#[case(false, vec![felt!("0x7"), felt!("0x1")], false)] +#[case(false, vec![felt!("0x0"), felt!("0x8")], false)] #[case(false, vec![felt!("0x0"), felt!("0x8"), felt!("0x0")], false)] -fn test_allocated_keys_commit_and_merge( +fn test_state_cache_commit_and_merge( #[case] is_base_empty: bool, #[case] storage_updates: Vec, #[case] charged: bool, + #[values(true, false)] comprehensive_state_diff: bool, ) { let contract_address = contract_address!(CONTRACT_ADDRESS); let storage_key = StorageKey::from(0x10_u16); // Set initial state let mut state: CachedState = CachedState::default(); + + let non_empty_base_value = felt!("0x1"); if !is_base_empty { - state.set_storage_at(contract_address, storage_key, felt!("0x1")).unwrap(); + state.set_storage_at(contract_address, storage_key, non_empty_base_value).unwrap(); } - let mut state_changes = vec![]; + let mut state_caches = vec![]; - for value in storage_updates { + for value in storage_updates.iter() { // In the end of the previous loop, state has moved into the transactional state. let mut transactional_state = TransactionalState::create_transactional(&mut state); // Update state and collect the state changes. - transactional_state.set_storage_at(contract_address, storage_key, value).unwrap(); - state_changes.push(transactional_state.get_actual_state_changes().unwrap()); + transactional_state.set_storage_at(contract_address, storage_key, *value).unwrap(); + state_caches.push(transactional_state.borrow_updated_state_cache().unwrap().clone()); transactional_state.commit(); } - let merged_changes = StateChanges::merge(state_changes); - assert_ne!(merged_changes.allocated_keys.is_empty(), charged); + let merged_changes = + StateCache::squash_state_diff(state_caches.iter().collect(), comprehensive_state_diff); + if comprehensive_state_diff { + // The comprehensive_state_diff is needed for backward compatibility of versions before the + // allocated keys feature was inserted. + assert_ne!(merged_changes.allocated_keys.is_empty(), charged); + } + + // Test the storage diff. + let base_value = if is_base_empty { Felt::ZERO } else { non_empty_base_value }; + let last_value = storage_updates.last().unwrap(); + let expected_storage_diff = if (&base_value == last_value) && comprehensive_state_diff { + None + } else { + Some(last_value) + }; + assert_eq!( + merged_changes.state_maps.storage.get(&(contract_address, storage_key)), + expected_storage_diff, + ); } // Test that allocations in validate and execute phases are properly squashed. #[rstest] -#[case(false, felt!("0x7"), felt!("0x8"), false)] -#[case(true, felt!("0x0"), felt!("0x8"), true)] -#[case(true, felt!("0x7"), felt!("0x7"), true)] -// TODO: not charge in the following case. -#[case(false, felt!("0x0"), felt!("0x8"), true)] -#[case(true, felt!("0x7"), felt!("0x0"), false)] -fn test_allocated_keys_two_transactions( +#[case::update_twice(false, felt!("0x7"), felt!("0x8"), false)] +#[case::set_zero_and_value(true, felt!("0x0"), felt!("0x8"), true)] +#[case::set_and_trivial_update(true, felt!("0x7"), felt!("0x7"), true)] +#[case::remove_and_set(false, felt!("0x0"), felt!("0x8"), false)] +#[case::set_and_remove(true, felt!("0x7"), felt!("0x0"), false)] +fn test_write_at_validate_and_execute( #[case] is_base_empty: bool, #[case] validate_value: Felt, #[case] execute_value: Felt, #[case] charged: bool, + #[values(CairoVersion::Cairo0, CairoVersion::Cairo1(RunnableCairo1::Casm))] + cairo_version: CairoVersion, + default_all_resource_bounds: ValidResourceBounds, ) { - let contract_address = contract_address!(CONTRACT_ADDRESS); - let storage_key = StorageKey::from(0x10_u16); - // Set initial state - let mut state: CachedState = CachedState::default(); + let block_context = BlockContext::create_for_testing(); + let chain_info = &block_context.chain_info; + let faulty_account_feature_contract = FeatureContract::FaultyAccount(cairo_version); + let contract_address = faulty_account_feature_contract.get_instance_address(0); + + // Set initial state. + let mut state = test_state(chain_info, BALANCE, &[(faulty_account_feature_contract, 1)]); if !is_base_empty { - state.set_storage_at(contract_address, storage_key, felt!("0x1")).unwrap(); + state.set_storage_at(contract_address, 15_u8.into(), felt!("0x1")).unwrap(); } - let mut first_state = TransactionalState::create_transactional(&mut state); - first_state.set_storage_at(contract_address, storage_key, validate_value).unwrap(); - let first_state_changes = first_state.get_actual_state_changes().unwrap(); - - let mut second_state = TransactionalState::create_transactional(&mut first_state); - second_state.set_storage_at(contract_address, storage_key, execute_value).unwrap(); - let second_state_changes = second_state.get_actual_state_changes().unwrap(); - - let merged_changes = StateChanges::merge(vec![first_state_changes, second_state_changes]); - assert_ne!(merged_changes.allocated_keys.is_empty(), charged); + let signature = + TransactionSignature(vec![Felt::from(STORAGE_WRITE), validate_value, execute_value]); + let tx_execution_info = run_invoke_tx( + &mut state, + &block_context, + invoke_tx_args! { + signature, + sender_address: contract_address, + resource_bounds: default_all_resource_bounds, + calldata: create_calldata(contract_address, "foo", &[]), + }, + ) + .unwrap(); + let n_allocated_keys = tx_execution_info + .receipt + .resources + .starknet_resources + .state + .state_changes_for_fee + .n_allocated_keys; + assert_eq!(n_allocated_keys > 0, charged); } #[test] @@ -500,14 +543,14 @@ fn test_contract_cache_is_used() { assert!(state.class_hash_to_class.borrow().get(&class_hash).is_none()); // Check state uses the cache. - assert_eq!(state.get_compiled_contract_class(class_hash).unwrap(), contract_class); + assert_eq!(state.get_compiled_class(class_hash).unwrap(), contract_class); assert_eq!(state.class_hash_to_class.borrow().get(&class_hash).unwrap(), &contract_class); } #[test] fn test_cache_get_write_keys() { // Trivial case. - assert_eq!(StateMaps::default().into_keys(), StateChangesKeys::default()); + assert_eq!(StateMaps::default().keys(), StateChangesKeys::default()); // Interesting case. let some_felt = felt!("0x1"); @@ -552,7 +595,7 @@ fn test_cache_get_write_keys() { ]), }; - assert_eq!(state_maps.into_keys(), expected_keys); + assert_eq!(state_maps.keys(), expected_keys); } #[test] diff --git a/crates/blockifier/src/state/contract_class_manager.rs b/crates/blockifier/src/state/contract_class_manager.rs new file mode 100644 index 00000000000..f7328847982 --- /dev/null +++ b/crates/blockifier/src/state/contract_class_manager.rs @@ -0,0 +1,60 @@ +pub const DEFAULT_COMPILATION_REQUEST_CHANNEL_SIZE: usize = 2000; + +#[cfg(feature = "cairo_native")] +pub use crate::state::native_class_manager::NativeClassManager as ContractClassManager; + +#[cfg(not(feature = "cairo_native"))] +pub mod trivial_class_manager { + #[cfg(any(feature = "testing", test))] + use cached::Cached; + use starknet_api::core::ClassHash; + + use crate::blockifier::config::ContractClassManagerConfig; + use crate::execution::contract_class::RunnableCompiledClass; + use crate::state::global_cache::{CachedClass, RawClassCache}; + + #[derive(Clone)] + pub struct TrivialClassManager { + cache: RawClassCache, + } + + // Trivial implementation of the class manager for Native-less projects. + impl TrivialClassManager { + pub fn start(config: ContractClassManagerConfig) -> Self { + assert!( + !config.cairo_native_run_config.run_cairo_native, + "Cairo Native feature is off." + ); + Self { cache: RawClassCache::new(config.contract_cache_size) } + } + + pub fn get_runnable(&self, class_hash: &ClassHash) -> Option { + Some(self.cache.get(class_hash)?.to_runnable()) + } + + pub fn set_and_compile(&self, class_hash: ClassHash, compiled_class: CachedClass) { + self.cache.set(class_hash, compiled_class); + } + + pub fn clear(&mut self) { + self.cache.clear(); + } + + #[cfg(any(feature = "testing", test))] + pub fn get_cache_size(&self) -> usize { + self.cache.lock().cache_size() + } + + // TODO(Aviv): consider support cache miss metrics. + pub fn take_cache_miss_counter(&self) -> u64 { + 0 + } + + pub fn take_cache_hit_counter(&self) -> u64 { + 0 + } + } +} + +#[cfg(not(feature = "cairo_native"))] +pub use trivial_class_manager::TrivialClassManager as ContractClassManager; diff --git a/crates/blockifier/src/state/errors.rs b/crates/blockifier/src/state/errors.rs index 1eba9b18bfb..c3ad9fbf0d9 100644 --- a/crates/blockifier/src/state/errors.rs +++ b/crates/blockifier/src/state/errors.rs @@ -1,6 +1,8 @@ +use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass; use cairo_vm::types::errors::program_errors::ProgramError; use num_bigint::{BigUint, TryFromBigIntError}; use starknet_api::core::{ClassHash, ContractAddress}; +use starknet_api::state::SierraContractClass; use starknet_api::StarknetApiError; use thiserror::Error; @@ -8,6 +10,8 @@ use crate::abi::constants; #[derive(Debug, Error)] pub enum StateError { + #[error("CASM and Sierra mismatch for class hash {:#064x}: {message}.", class_hash.0)] + CasmAndSierraMismatch { class_hash: ClassHash, message: String }, #[error(transparent)] FromBigUint(#[from] TryFromBigIntError), #[error( @@ -29,3 +33,25 @@ pub enum StateError { #[error("Failed to read from state: {0}.")] StateReadError(String), } + +/// Ensures that the CASM and Sierra classes are coupled - Meaning that they both exist or are +/// missing. Returns a `CasmAndSierraMismatch` error when there is an inconsistency in their +/// existence. +pub fn couple_casm_and_sierra( + class_hash: ClassHash, + option_casm: Option, + option_sierra: Option, +) -> Result, StateError> { + match (option_casm, option_sierra) { + (Some(casm), Some(sierra)) => Ok(Some((casm, sierra))), + (Some(_), None) => Err(StateError::CasmAndSierraMismatch { + class_hash, + message: "Class exists in CASM but not in Sierra".to_string(), + }), + (None, Some(_)) => Err(StateError::CasmAndSierraMismatch { + class_hash, + message: "Class exists in Sierra but not in CASM".to_string(), + }), + (None, None) => Ok(None), + } +} diff --git a/crates/blockifier/src/state/global_cache.rs b/crates/blockifier/src/state/global_cache.rs index 040b1163375..534555cf4ba 100644 --- a/crates/blockifier/src/state/global_cache.rs +++ b/crates/blockifier/src/state/global_cache.rs @@ -1,100 +1,49 @@ -use std::sync::{Arc, Mutex, MutexGuard}; +use std::sync::Arc; -use cached::{Cached, SizedCache}; -#[cfg(feature = "cairo_native")] -use cairo_native::executor::AotContractExecutor; -use starknet_api::core::ClassHash; -#[cfg(feature = "cairo_native")] +use starknet_api::class_cache::GlobalContractCache; use starknet_api::state::SierraContractClass; +use crate::execution::contract_class::{CompiledClassV0, CompiledClassV1, RunnableCompiledClass}; #[cfg(feature = "cairo_native")] -use crate::execution::contract_class::RunnableContractClass; +use crate::execution::native::contract_class::NativeCompiledClassV1; -type ContractClassLRUCache = SizedCache; -pub type LockedContractClassCache<'a, T> = MutexGuard<'a, ContractClassLRUCache>; -#[derive(Debug, Clone)] -// Thread-safe LRU cache for contract classes, optimized for inter-language sharing when -// `blockifier` compiles as a shared library. -// TODO(Yoni, 1/1/2025): consider defining CachedStateReader. -pub struct GlobalContractCache(pub Arc>>); +pub const GLOBAL_CONTRACT_CACHE_SIZE_FOR_TEST: usize = 600; -#[cfg(feature = "cairo_native")] #[derive(Debug, Clone)] -pub enum CachedCairoNative { - Compiled(AotContractExecutor), - CompilationFailed, +pub enum CachedClass { + V0(CompiledClassV0), + V1(CompiledClassV1, Arc), + #[cfg(feature = "cairo_native")] + V1Native(CachedCairoNative), } - -pub const GLOBAL_CONTRACT_CACHE_SIZE_FOR_TEST: usize = 100; - -impl GlobalContractCache { - /// Locks the cache for atomic access. Although conceptually shared, writing to this cache is - /// only possible for one writer at a time. - pub fn lock(&self) -> LockedContractClassCache<'_, T> { - self.0.lock().expect("Global contract cache is poisoned.") - } - - pub fn get(&self, class_hash: &ClassHash) -> Option { - self.lock().cache_get(class_hash).cloned() - } - - pub fn set(&self, class_hash: ClassHash, contract_class: T) { - self.lock().cache_set(class_hash, contract_class); - } - - pub fn clear(&mut self) { - self.lock().cache_clear(); - } - - pub fn new(cache_size: usize) -> Self { - Self(Arc::new(Mutex::new(ContractClassLRUCache::::with_size(cache_size)))) +impl CachedClass { + pub fn to_runnable(&self) -> RunnableCompiledClass { + match self { + CachedClass::V0(compiled_class_v0) => { + RunnableCompiledClass::V0(compiled_class_v0.clone()) + } + CachedClass::V1(compiled_class_v1, _sierra_contract_class) => { + RunnableCompiledClass::V1(compiled_class_v1.clone()) + } + #[cfg(feature = "cairo_native")] + CachedClass::V1Native(cached_cairo_native) => match cached_cairo_native { + CachedCairoNative::Compiled(native_compiled_class_v1) => { + RunnableCompiledClass::V1Native(native_compiled_class_v1.clone()) + } + CachedCairoNative::CompilationFailed(compiled_class_v1) => { + RunnableCompiledClass::V1(compiled_class_v1.clone()) + } + }, + } } } -#[cfg(feature = "cairo_native")] -pub struct GlobalContractCacheManager { - pub casm_cache: GlobalContractCache, - pub native_cache: GlobalContractCache, - pub sierra_cache: GlobalContractCache>, -} +pub type RawClassCache = GlobalContractCache; #[cfg(feature = "cairo_native")] -impl GlobalContractCacheManager { - pub fn get_casm(&self, class_hash: &ClassHash) -> Option { - self.casm_cache.get(class_hash) - } - - pub fn set_casm(&self, class_hash: ClassHash, contract_class: RunnableContractClass) { - self.casm_cache.set(class_hash, contract_class); - } - - pub fn get_native(&self, class_hash: &ClassHash) -> Option { - self.native_cache.get(class_hash) - } - - pub fn set_native(&self, class_hash: ClassHash, contract_executor: CachedCairoNative) { - self.native_cache.set(class_hash, contract_executor); - } - - pub fn get_sierra(&self, class_hash: &ClassHash) -> Option> { - self.sierra_cache.get(class_hash) - } - - pub fn set_sierra(&self, class_hash: ClassHash, contract_class: Arc) { - self.sierra_cache.set(class_hash, contract_class); - } - - pub fn new(cache_size: usize) -> Self { - Self { - casm_cache: GlobalContractCache::new(cache_size), - native_cache: GlobalContractCache::new(cache_size), - sierra_cache: GlobalContractCache::new(cache_size), - } - } - - pub fn clear(&mut self) { - self.casm_cache.clear(); - self.native_cache.clear(); - self.sierra_cache.clear(); - } +#[derive(Debug, Clone)] +#[cfg_attr(test, derive(PartialEq))] +pub enum CachedCairoNative { + Compiled(NativeCompiledClassV1), + CompilationFailed(CompiledClassV1), } diff --git a/crates/blockifier/src/state/native_class_manager.rs b/crates/blockifier/src/state/native_class_manager.rs new file mode 100644 index 00000000000..f7361c0d8b0 --- /dev/null +++ b/crates/blockifier/src/state/native_class_manager.rs @@ -0,0 +1,322 @@ +use std::sync::atomic::{AtomicU64, Ordering}; +use std::sync::mpsc::{sync_channel, Receiver, SyncSender, TrySendError}; +use std::sync::Arc; + +#[cfg(any(feature = "testing", test))] +use cached::Cached; +use log; +use starknet_api::core::ClassHash; +use starknet_api::state::SierraContractClass; +use starknet_sierra_multicompile::command_line_compiler::CommandLineCompiler; +use starknet_sierra_multicompile::errors::CompilationUtilError; +use starknet_sierra_multicompile::utils::into_contract_class_for_compilation; +use starknet_sierra_multicompile::SierraToNativeCompiler; +use thiserror::Error; + +use crate::blockifier::config::{ + CairoNativeRunConfig, + ContractClassManagerConfig, + NativeClassesWhitelist, +}; +use crate::execution::contract_class::{CompiledClassV1, RunnableCompiledClass}; +use crate::execution::native::contract_class::NativeCompiledClassV1; +use crate::state::global_cache::{CachedCairoNative, CachedClass, RawClassCache}; + +#[cfg(test)] +#[path = "native_class_manager_test.rs"] +mod native_class_manager_test; + +#[derive(Clone, Debug, Error, PartialEq, Eq)] +pub enum ContractClassManagerError { + #[error("Error compiling contract class: {0}")] + CompilationError(CompilationUtilError), + #[error("Error when sending request: {0}")] + TrySendError(TrySendError), +} + +/// Represents a request to compile a sierra contract class to a native compiled class. +/// +/// # Fields: +/// * `class_hash` - used to identify the contract class in the cache. +/// * `sierra_contract_class` - the sierra contract class to be compiled. +/// * `casm_compiled_class` - stored in [`NativeCompiledClassV1`] to allow fallback to cairo_vm +/// execution in case of unexpected failure during native execution. +type CompilationRequest = (ClassHash, Arc, CompiledClassV1); + +/// Manages the global cache of contract classes and handles sierra-to-native compilation requests. +#[derive(Clone)] +pub struct NativeClassManager { + cairo_native_run_config: CairoNativeRunConfig, + /// The global cache of raw contract classes. + cache: RawClassCache, + /// The sending half of the compilation request channel. Set to `None` if native compilation is + /// disabled. + sender: Option>, + /// The sierra-to-native compiler. + compiler: Option>, + /// cache_miss_rate + cache_metrics: Arc, +} + +#[derive(Default)] +pub struct CacheMetrics { + pub cache_misses: AtomicU64, + pub cache_hits: AtomicU64, +} + +impl CacheMetrics { + pub fn new() -> Self { + Self { cache_misses: AtomicU64::new(0), cache_hits: AtomicU64::new(0) } + } + + pub fn record_miss(&self) { + self.cache_misses.fetch_add(1, Ordering::Relaxed); + } + + pub fn record_hit(&self) { + self.cache_hits.fetch_add(1, Ordering::Relaxed); + } +} + +impl NativeClassManager { + /// Creates a new contract class manager and spawns a thread that listens for compilation + /// requests and processes them (a.k.a. the compilation worker). + /// Returns the contract class manager. + /// NOTE: the compilation worker is not spawned if one of the following conditions is met: + /// 1. The feature `cairo_native` is not enabled. + /// 2. `config.run_cairo_native` is `false`. + /// 3. `config.wait_on_native_compilation` is `true`. + pub fn start(config: ContractClassManagerConfig) -> NativeClassManager { + // TODO(Avi, 15/12/2024): Add the size of the channel to the config. + let cache = RawClassCache::new(config.contract_cache_size); + let cairo_native_run_config = config.cairo_native_run_config; + if !cairo_native_run_config.run_cairo_native { + // Native compilation is disabled - no need to start the compilation worker. + return NativeClassManager { + cairo_native_run_config, + cache, + sender: None, + compiler: None, + cache_metrics: Arc::new(CacheMetrics::new()), + }; + } + + let compiler_config = config.native_compiler_config.clone(); + let compiler = Arc::new(CommandLineCompiler::new(compiler_config)); + if cairo_native_run_config.wait_on_native_compilation { + // Compilation requests are processed synchronously. No need to start the worker. + return NativeClassManager { + cairo_native_run_config, + cache, + sender: None, + compiler: Some(compiler), + cache_metrics: Arc::new(CacheMetrics::new()), + }; + } + + let (sender, receiver) = sync_channel(cairo_native_run_config.channel_size); + + std::thread::spawn({ + let cache = cache.clone(); + move || run_compilation_worker(cache, receiver, compiler) + }); + + // TODO(AVIV): Add private constructor with default values. + NativeClassManager { + cairo_native_run_config, + cache, + sender: Some(sender), + compiler: None, + cache_metrics: Arc::new(CacheMetrics::new()), + } + } + + /// Returns the runnable compiled class for the given class hash, if it exists in cache. + pub fn get_runnable(&self, class_hash: &ClassHash) -> Option { + let cached_class = match self.cache.get(class_hash) { + Some(class) => { + self.cache_metrics.record_hit(); + class + } + None => { + self.cache_metrics.record_miss(); + return None; + } + }; + + let cached_class = match cached_class { + CachedClass::V1(_, _) => { + // TODO(Yoni): make sure `wait_on_native_compilation` cannot be set to true while + // `run_cairo_native` is false. + assert!( + !self.wait_on_native_compilation(), + "Manager did not wait on native compilation." + ); + cached_class + } + CachedClass::V1Native(CachedCairoNative::Compiled(native)) + if !self.run_class_with_cairo_native(class_hash) => + { + CachedClass::V1(native.casm(), Arc::new(SierraContractClass::default())) + } + _ => cached_class, + }; + + Some(cached_class.to_runnable()) + } + + /// Caches the compiled class. + /// For Cairo 1 classes: + /// * if Native mode is enabled, triggers compilation to Native that will eventually be cached. + /// * If `wait_on_native_compilation` is true, caches the Native variant immediately. + pub fn set_and_compile(&self, class_hash: ClassHash, compiled_class: CachedClass) { + match compiled_class { + CachedClass::V0(_) => self.cache.set(class_hash, compiled_class), + CachedClass::V1(compiled_class_v1, sierra_contract_class) => { + // TODO(Yoni): instead of these two flag, use an enum. + if self.wait_on_native_compilation() { + assert!(self.run_cairo_native(), "Native compilation is disabled."); + let compiler = self.compiler.as_ref().expect("Compiler not available."); + // After this point, the Native class should be cached and available through + // `get_runnable` access. + // Ignore compilation errors for now. + process_compilation_request( + self.cache.clone(), + compiler.clone(), + (class_hash, sierra_contract_class, compiled_class_v1), + ) + .unwrap_or(()); + return; + } + + // Cache the V1 class. + self.cache.set( + class_hash, + CachedClass::V1(compiled_class_v1.clone(), sierra_contract_class.clone()), + ); + if self.run_cairo_native() { + // Send a non-blocking compilation request. + // Ignore compilation errors for now. + self.send_compilation_request(( + class_hash, + sierra_contract_class, + compiled_class_v1, + )) + .unwrap_or(()); + } + } + // TODO(Yoni): consider panic since this flow should not be reachable. + CachedClass::V1Native(_) => self.cache.set(class_hash, compiled_class), + } + } + + /// Sends a compilation request to the compilation worker. Does not block the sender. Logs an + /// error if the channel is full. + fn send_compilation_request( + &self, + request: CompilationRequest, + ) -> Result<(), ContractClassManagerError> { + let sender = self.sender.as_ref().expect("Compilation channel not available."); + // TODO(Avi, 15/12/2024): Check for duplicated requests. + sender.try_send(request).map_err(|err| match err { + TrySendError::Full((class_hash, _, _)) => { + log::debug!( + "Compilation request channel is full (size: {}). Compilation request for \ + class hash {} was not sent.", + self.cairo_native_run_config.channel_size, + class_hash + ); + ContractClassManagerError::TrySendError(TrySendError::Full(class_hash)) + } + TrySendError::Disconnected(_) => { + panic!("Compilation request channel is closed.") + } + }) + } + + fn run_cairo_native(&self) -> bool { + self.cairo_native_run_config.run_cairo_native + } + + fn wait_on_native_compilation(&self) -> bool { + self.cairo_native_run_config.wait_on_native_compilation + } + + /// Determines if a contract should run with cairo native based on the whitelist. + pub fn run_class_with_cairo_native(&self, class_hash: &ClassHash) -> bool { + match &self.cairo_native_run_config.native_classes_whitelist { + NativeClassesWhitelist::All => true, + NativeClassesWhitelist::Limited(contracts) => contracts.contains(class_hash), + } + } + + /// Clears the contract cache. + pub fn clear(&mut self) { + self.cache.clear(); + } + + #[cfg(any(feature = "testing", test))] + pub fn get_cache_size(&self) -> usize { + self.cache.lock().cache_size() + } + + /// Retrieves the current cache miss counter and resets it to zero. + pub fn take_cache_miss_counter(&self) -> u64 { + self.cache_metrics.cache_misses.swap(0, Ordering::Relaxed) + } + + /// Retrieves the current cache hit counter and resets it to zero. + pub fn take_cache_hit_counter(&self) -> u64 { + self.cache_metrics.cache_hits.swap(0, Ordering::Relaxed) + } +} + +/// Handles compilation requests from the channel, holding the receiver end of the channel. +/// If no request is available, non-busy-waits until a request is available. +/// When the sender is dropped, the worker processes all pending requests and terminates. +fn run_compilation_worker( + cache: RawClassCache, + receiver: Receiver, + compiler: Arc, +) { + log::info!("Compilation worker started."); + for compilation_request in receiver.iter() { + process_compilation_request(cache.clone(), compiler.clone(), compilation_request) + .unwrap_or(()); + } + log::info!("Compilation worker terminated."); +} + +/// Processes a compilation request and caches the result. +fn process_compilation_request( + cache: RawClassCache, + compiler: Arc, + compilation_request: CompilationRequest, +) -> Result<(), CompilationUtilError> { + let (class_hash, sierra, casm) = compilation_request; + if let Some(CachedClass::V1Native(_)) = cache.get(&class_hash) { + // The contract class is already compiled to native - skip the compilation. + return Ok(()); + } + let sierra_for_compilation = into_contract_class_for_compilation(sierra.as_ref()); + let compilation_result = compiler.compile_to_native(sierra_for_compilation); + match compilation_result { + Ok(executor) => { + let native_compiled_class = NativeCompiledClassV1::new(executor, casm); + cache.set( + class_hash, + CachedClass::V1Native(CachedCairoNative::Compiled(native_compiled_class)), + ); + Ok(()) + } + Err(err) => { + cache + .set(class_hash, CachedClass::V1Native(CachedCairoNative::CompilationFailed(casm))); + log::debug!("Error compiling contract class: {}", err); + if compiler.panic_on_compilation_failure() { + panic!("Compilation failed: {}", err); + } + Err(err) + } + } +} diff --git a/crates/blockifier/src/state/native_class_manager_test.rs b/crates/blockifier/src/state/native_class_manager_test.rs new file mode 100644 index 00000000000..1aa524b4b17 --- /dev/null +++ b/crates/blockifier/src/state/native_class_manager_test.rs @@ -0,0 +1,269 @@ +use std::sync::mpsc::{sync_channel, TrySendError}; +use std::sync::Arc; +use std::thread::sleep; + +use assert_matches::assert_matches; +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; +use blockifier_test_utils::contracts::FeatureContract; +use rstest::rstest; +use starknet_api::core::ClassHash; +use starknet_sierra_multicompile::config::DEFAULT_MAX_CPU_TIME; +use starknet_sierra_multicompile::errors::CompilationUtilError; + +use crate::blockifier::config::{CairoNativeRunConfig, NativeClassesWhitelist}; +use crate::execution::contract_class::{CompiledClassV1, RunnableCompiledClass}; +use crate::state::global_cache::{ + CachedCairoNative, + CachedClass, + RawClassCache, + GLOBAL_CONTRACT_CACHE_SIZE_FOR_TEST, +}; +use crate::state::native_class_manager::{ + process_compilation_request, + CacheMetrics, + CompilationRequest, + ContractClassManagerError, + NativeClassManager, +}; +use crate::test_utils::contracts::FeatureContractTrait; + +const TEST_CHANNEL_SIZE: usize = 10; + +fn get_casm(test_contract: FeatureContract) -> CompiledClassV1 { + match test_contract.get_runnable_class() { + RunnableCompiledClass::V1(casm) => casm, + _ => panic!("Expected CompiledClassV1"), + } +} + +fn create_test_request_from_contract(test_contract: FeatureContract) -> CompilationRequest { + let class_hash = test_contract.get_class_hash(); + let sierra = Arc::new(test_contract.get_sierra()); + let casm = get_casm(test_contract); + + (class_hash, sierra, casm) +} + +fn get_test_contract_class_hash() -> ClassHash { + FeatureContract::TestContract(CairoVersion::Cairo1(RunnableCairo1::Casm)).get_class_hash() +} + +fn create_test_request() -> CompilationRequest { + let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1(RunnableCairo1::Casm)); + create_test_request_from_contract(test_contract) +} + +fn create_faulty_request() -> CompilationRequest { + let (class_hash, sierra, casm) = create_test_request(); + let mut sierra = sierra.as_ref().clone(); + + // Truncate the sierra program to trigger an error. + sierra.sierra_program = sierra.sierra_program[..100].to_vec(); + (class_hash, Arc::new(sierra), casm) +} + +#[rstest] +#[case::run_native_while_waiting(true, true)] +#[case::run_native_without_waiting(true, false)] +#[case::run_without_native(false, false)] +fn test_start(#[case] run_cairo_native: bool, #[case] wait_on_native_compilation: bool) { + let native_config = + CairoNativeRunConfig { run_cairo_native, wait_on_native_compilation, ..Default::default() }; + let manager = NativeClassManager::create_for_testing(native_config.clone()); + + assert_eq!(manager.cairo_native_run_config.clone(), native_config); + if run_cairo_native { + if wait_on_native_compilation { + assert!( + manager.sender.is_none(), + "Sender should be None - the compilation worker is not used." + ); + assert!( + manager.compiler.is_some(), + "Compiler should be Some - compilation is not offloaded to the compilation worker." + ); + } else { + assert!( + manager.sender.is_some(), + "Sender should be Some - the compilation worker is used." + ); + assert!( + manager.compiler.is_none(), + "Compiler should be None - compilation is offloaded to the compilation worker." + ); + } + } else { + assert!(manager.sender.is_none(), "Sender should be None- Cairo native is disabled."); + assert!(manager.compiler.is_none(), "Compiler should be None - Cairo native is disabled."); + } +} + +#[rstest] +#[case::run_native_while_waiting(true, true)] +#[case::run_native_without_waiting(true, false)] +#[should_panic(expected = "Native compilation is disabled.")] +#[case::run_without_native(false, true)] +#[case::run_without_native(false, false)] +fn test_set_and_compile( + #[case] run_cairo_native: bool, + #[case] wait_on_native_compilation: bool, + #[values(true, false)] should_pass: bool, +) { + let native_config = + CairoNativeRunConfig { run_cairo_native, wait_on_native_compilation, ..Default::default() }; + let manager = NativeClassManager::create_for_testing(native_config); + let request = if should_pass { create_test_request() } else { create_faulty_request() }; + let class_hash = request.0; + let (_class_hash, sierra, casm) = request.clone(); + let cached_class = CachedClass::V1(casm, sierra); + + manager.set_and_compile(class_hash, cached_class); + if !run_cairo_native { + assert_matches!(manager.cache.get(&class_hash).unwrap(), CachedClass::V1(_, _)); + return; + } + + if !wait_on_native_compilation { + assert_matches!(manager.cache.get(&class_hash).unwrap(), CachedClass::V1(_, _)); + let seconds_to_sleep = 2; + let max_n_retries = DEFAULT_MAX_CPU_TIME / seconds_to_sleep + 1; + for _ in 0..max_n_retries { + sleep(std::time::Duration::from_secs(seconds_to_sleep)); + if matches!(manager.cache.get(&class_hash), Some(CachedClass::V1Native(_))) { + break; + } + } + } + + match manager.cache.get(&class_hash).unwrap() { + CachedClass::V1Native(CachedCairoNative::Compiled(_)) => { + assert!(should_pass, "Compilation should have passed."); + } + CachedClass::V1Native(CachedCairoNative::CompilationFailed(_)) => { + assert!(!should_pass, "Compilation should have failed."); + } + CachedClass::V1(_, _) | CachedClass::V0(_) => { + panic!("Unexpected cached class."); + } + } +} + +#[test] +#[should_panic(expected = "Compilation request channel is closed.")] +fn test_send_compilation_request_channel_disconnected() { + // We use the channel to send native compilation requests. + let native_config = CairoNativeRunConfig { + run_cairo_native: true, + wait_on_native_compilation: false, + channel_size: TEST_CHANNEL_SIZE, + ..CairoNativeRunConfig::default() + }; + let (sender, receiver) = sync_channel(native_config.channel_size); + let manager = NativeClassManager { + cairo_native_run_config: native_config, + cache: RawClassCache::new(GLOBAL_CONTRACT_CACHE_SIZE_FOR_TEST), + sender: Some(sender), + compiler: None, + cache_metrics: Arc::new(CacheMetrics::new()), + }; + // Disconnect the channel by dropping the receiver. + drop(receiver); + + // Sending request with a disconnected channel should panic. + let request = create_test_request(); + manager.send_compilation_request(request).unwrap(); +} + +#[test] +fn test_send_compilation_request_channel_full() { + let native_config = CairoNativeRunConfig { + run_cairo_native: true, + wait_on_native_compilation: false, + channel_size: 0, + ..CairoNativeRunConfig::default() + }; + let manager = NativeClassManager::create_for_testing(native_config); + let request = create_test_request(); + assert!(manager.sender.is_some(), "Sender should be Some"); + + // Fill the channel (it can only hold 1 message). + manager.send_compilation_request(request.clone()).unwrap(); + let result = manager.send_compilation_request(request.clone()); + assert_eq!( + result.unwrap_err(), + ContractClassManagerError::TrySendError(TrySendError::Full(request.0)) + ); +} + +#[rstest] +#[case::success(create_test_request(), true)] +#[case::failure(create_faulty_request(), false)] +fn test_process_compilation_request( + #[case] request: CompilationRequest, + #[case] should_pass: bool, +) { + let manager = NativeClassManager::create_for_testing(CairoNativeRunConfig { + wait_on_native_compilation: true, + run_cairo_native: true, + channel_size: TEST_CHANNEL_SIZE, + ..CairoNativeRunConfig::default() + }); + let res = process_compilation_request( + manager.clone().cache, + manager.clone().compiler.unwrap(), + request.clone(), + ); + + if should_pass { + assert!( + res.is_ok(), + "Compilation request failed with the following error: {}.", + res.unwrap_err() + ); + assert_matches!( + manager.cache.get(&request.0).unwrap(), + CachedClass::V1Native(CachedCairoNative::Compiled(_)) + ); + } else { + assert_matches!(res.unwrap_err(), CompilationUtilError::CompilationError(_)); + assert_matches!( + manager.cache.get(&request.0).unwrap(), + CachedClass::V1Native(CachedCairoNative::CompilationFailed(_)) + ); + } +} + +#[rstest] +#[case::all_classes(NativeClassesWhitelist::All, true)] +#[case::only_selected_class_hash(NativeClassesWhitelist::Limited(vec![get_test_contract_class_hash()]), true)] +#[case::no_allowed_classes(NativeClassesWhitelist::Limited(vec![]), false)] +// Test the config that allows us to run only limited selection of class hashes in native. +fn test_native_classes_whitelist( + #[case] whitelist: NativeClassesWhitelist, + #[case] allow_run_native: bool, +) { + let native_config = CairoNativeRunConfig { + run_cairo_native: true, + wait_on_native_compilation: true, + channel_size: TEST_CHANNEL_SIZE, + native_classes_whitelist: whitelist, + }; + let manager = NativeClassManager::create_for_testing(native_config); + + let (class_hash, sierra, casm) = create_test_request(); + + manager.set_and_compile(class_hash, CachedClass::V1(casm, sierra)); + + match allow_run_native { + true => assert_matches!( + manager.get_runnable(&class_hash), + Some(RunnableCompiledClass::V1Native(_)) + ), + false => { + assert_matches!( + manager.get_runnable(&class_hash).unwrap(), + RunnableCompiledClass::V1(_) + ) + } + } +} diff --git a/crates/blockifier/src/state/state_api.rs b/crates/blockifier/src/state/state_api.rs index 2b4464d6ab1..32544db04d9 100644 --- a/crates/blockifier/src/state/state_api.rs +++ b/crates/blockifier/src/state/state_api.rs @@ -1,12 +1,10 @@ -use std::collections::{HashMap, HashSet}; - use starknet_api::abi::abi_utils::get_fee_token_var_address; use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; use starknet_api::state::StorageKey; use starknet_types_core::felt::Felt; use super::cached_state::{ContractClassMapping, StateMaps}; -use crate::execution::contract_class::RunnableContractClass; +use crate::execution::contract_class::RunnableCompiledClass; use crate::state::errors::StateError; pub type StateResult = Result; @@ -21,6 +19,7 @@ pub enum DataAvailabilityMode { /// /// The `self` argument is mutable for flexibility during reads (for example, caching reads), /// and to allow for the `State` trait below to also be considered a `StateReader`. +#[cfg_attr(any(test, feature = "testing"), mockall::automock)] pub trait StateReader { /// Returns the storage value under the given key in the given contract instance (represented by /// its address). @@ -39,11 +38,8 @@ pub trait StateReader { /// Default: 0 (uninitialized class hash) for an uninitialized contract address. fn get_class_hash_at(&self, contract_address: ContractAddress) -> StateResult; - /// Returns the contract class of the given class hash. - fn get_compiled_contract_class( - &self, - class_hash: ClassHash, - ) -> StateResult; + /// Returns the compiled class of the given class hash. + fn get_compiled_class(&self, class_hash: ClassHash) -> StateResult; /// Returns the compiled class hash of the given class hash. fn get_compiled_class_hash(&self, class_hash: ClassHash) -> StateResult; @@ -96,7 +92,7 @@ pub trait State: StateReader { fn set_contract_class( &mut self, class_hash: ClassHash, - contract_class: RunnableContractClass, + contract_class: RunnableCompiledClass, ) -> StateResult<()>; /// Sets the given compiled class hash under the given class hash. @@ -105,19 +101,9 @@ pub trait State: StateReader { class_hash: ClassHash, compiled_class_hash: CompiledClassHash, ) -> StateResult<()>; - - /// Marks the given set of PC values as visited for the given class hash. - // TODO(lior): Once we have a BlockResources object, move this logic there. Make sure reverted - // entry points do not affect the final set of PCs. - fn add_visited_pcs(&mut self, _class_hash: ClassHash, _pcs: &HashSet) {} } /// A class defining the API for updating a state with transactions writes. pub trait UpdatableState: StateReader { - fn apply_writes( - &mut self, - writes: &StateMaps, - class_hash_to_class: &ContractClassMapping, - visited_pcs: &HashMap>, - ); + fn apply_writes(&mut self, writes: &StateMaps, class_hash_to_class: &ContractClassMapping); } diff --git a/crates/blockifier/src/state/stateful_compression.rs b/crates/blockifier/src/state/stateful_compression.rs new file mode 100644 index 00000000000..e04504ee6aa --- /dev/null +++ b/crates/blockifier/src/state/stateful_compression.rs @@ -0,0 +1,210 @@ +use std::collections::{BTreeSet, HashMap}; + +use starknet_api::core::{ContractAddress, PatriciaKey}; +use starknet_api::state::StorageKey; +use starknet_api::StarknetApiError; +use starknet_types_core::felt::Felt; +use thiserror::Error; + +use super::cached_state::{CachedState, StateMaps}; +use super::errors::StateError; +use super::state_api::{State, StateReader, StateResult}; + +#[cfg(test)] +#[path = "stateful_compression_test.rs"] +pub mod stateful_compression_test; + +type Alias = Felt; +type AliasKey = StorageKey; + +#[derive(Debug, Error)] +pub enum CompressionError { + #[error("Missing key in alias contract: {:#064x}", ***.0)] + MissedAlias(AliasKey), + #[error(transparent)] + StateError(#[from] StateError), + #[error(transparent)] + StarknetApiError(#[from] StarknetApiError), +} +pub type CompressionResult = Result; + +// The initial alias available for allocation. +const INITIAL_AVAILABLE_ALIAS_HEX: &str = "0x80"; +pub const INITIAL_AVAILABLE_ALIAS: Felt = Felt::from_hex_unchecked(INITIAL_AVAILABLE_ALIAS_HEX); + +// The storage key of the alias counter in the alias contract. +pub const ALIAS_COUNTER_STORAGE_KEY: StorageKey = StorageKey(PatriciaKey::ZERO); +// The maximal contract address for which aliases are not used and all keys are serialized as is, +// without compression. +pub const MAX_NON_COMPRESSED_CONTRACT_ADDRESS: ContractAddress = + ContractAddress(PatriciaKey::from_hex_unchecked("0xf")); +// The minimal value for a key to be allocated an alias. Smaller keys are serialized as is (their +// alias is identical to the key). +pub const MIN_VALUE_FOR_ALIAS_ALLOC: PatriciaKey = + PatriciaKey::from_hex_unchecked(INITIAL_AVAILABLE_ALIAS_HEX); + +/// Allocates aliases for the new addresses and storage keys in the alias contract. +/// Iterates over the addresses in ascending order. For each address, sets an alias for the new +/// storage keys (in ascending order) and for the address itself. +pub fn allocate_aliases_in_storage( + state: &mut CachedState, + alias_contract_address: ContractAddress, +) -> StateResult<()> { + let state_diff = state.to_state_diff()?.state_maps; + + // Collect the contract addresses and the storage keys that need aliases. + let contract_addresses: BTreeSet = + state_diff.get_contract_addresses().into_iter().collect(); + let mut contract_address_to_sorted_storage_keys = HashMap::new(); + for (contract_address, storage_key) in state_diff.storage.keys() { + if contract_address > &MAX_NON_COMPRESSED_CONTRACT_ADDRESS { + contract_address_to_sorted_storage_keys + .entry(contract_address) + .or_insert_with(BTreeSet::new) + .insert(storage_key); + } + } + + // Iterate over the addresses and the storage keys and update the aliases. + let mut alias_updater = AliasUpdater::new(state, alias_contract_address)?; + for contract_address in contract_addresses { + if let Some(storage_keys) = contract_address_to_sorted_storage_keys.get(&contract_address) { + for key in storage_keys { + alias_updater.insert_alias(key)?; + } + } + alias_updater.insert_alias(&StorageKey(contract_address.0))?; + } + + alias_updater.finalize_updates() +} + +/// Updates the alias contract with the new keys. +struct AliasUpdater<'a, S: State> { + state: &'a mut S, + is_alias_inserted: bool, + next_free_alias: Option, + alias_contract_address: ContractAddress, +} + +impl<'a, S: State> AliasUpdater<'a, S> { + fn new(state: &'a mut S, alias_contract_address: ContractAddress) -> StateResult { + let stored_counter = + state.get_storage_at(alias_contract_address, ALIAS_COUNTER_STORAGE_KEY)?; + Ok(Self { + state, + is_alias_inserted: false, + next_free_alias: if stored_counter == Felt::ZERO { None } else { Some(stored_counter) }, + alias_contract_address, + }) + } + + fn set_alias_in_storage(&mut self, alias_key: AliasKey, alias: Alias) -> StateResult<()> { + self.state.set_storage_at(self.alias_contract_address, alias_key, alias) + } + + /// Inserts the alias key to the updates if it's not already aliased. + fn insert_alias(&mut self, alias_key: &AliasKey) -> StateResult<()> { + if alias_key.0 >= MIN_VALUE_FOR_ALIAS_ALLOC + && self.state.get_storage_at(self.alias_contract_address, *alias_key)? == Felt::ZERO + { + let alias_to_allocate = self.next_free_alias.unwrap_or(INITIAL_AVAILABLE_ALIAS); + self.set_alias_in_storage(*alias_key, alias_to_allocate)?; + self.is_alias_inserted = true; + self.next_free_alias = Some(alias_to_allocate + Felt::ONE); + } + Ok(()) + } + + /// Inserts the counter of the alias contract. + fn finalize_updates(mut self) -> StateResult<()> { + match self.next_free_alias { + None => { + self.set_alias_in_storage(ALIAS_COUNTER_STORAGE_KEY, INITIAL_AVAILABLE_ALIAS)?; + } + Some(alias) => { + if self.is_alias_inserted { + self.set_alias_in_storage(ALIAS_COUNTER_STORAGE_KEY, alias)?; + } + } + } + Ok(()) + } +} + +/// Compresses the state diff by replacing the addresses and storage keys with aliases. +pub fn compress( + state_diff: &StateMaps, + state: &S, + alias_contract_address: ContractAddress, +) -> CompressionResult { + let alias_compressor = AliasCompressor { state, alias_contract_address }; + + let nonces = state_diff + .nonces + .iter() + .map(|(contract_address, nonce)| { + Ok((alias_compressor.compress_address(contract_address)?, *nonce)) + }) + .collect::>()?; + let class_hashes = state_diff + .class_hashes + .iter() + .map(|(contract_address, class_hash)| { + Ok((alias_compressor.compress_address(contract_address)?, *class_hash)) + }) + .collect::>()?; + let storage = state_diff + .storage + .iter() + .map(|((contract_address, key), value)| { + Ok(( + ( + alias_compressor.compress_address(contract_address)?, + alias_compressor.compress_storage_key(key, contract_address)?, + ), + *value, + )) + }) + .collect::>()?; + + Ok(StateMaps { nonces, class_hashes, storage, ..state_diff.clone() }) +} + +/// Replaces contact addresses and storage keys with aliases. +struct AliasCompressor<'a, S: StateReader> { + state: &'a S, + alias_contract_address: ContractAddress, +} + +impl AliasCompressor<'_, S> { + fn compress_address( + &self, + contract_address: &ContractAddress, + ) -> CompressionResult { + if contract_address.0 >= MIN_VALUE_FOR_ALIAS_ALLOC { + Ok(self.get_alias(StorageKey(contract_address.0))?.try_into()?) + } else { + Ok(*contract_address) + } + } + + fn compress_storage_key( + &self, + storage_key: &StorageKey, + contract_address: &ContractAddress, + ) -> CompressionResult { + if storage_key.0 >= MIN_VALUE_FOR_ALIAS_ALLOC + && contract_address > &MAX_NON_COMPRESSED_CONTRACT_ADDRESS + { + Ok(self.get_alias(*storage_key)?.try_into()?) + } else { + Ok(*storage_key) + } + } + + fn get_alias(&self, alias_key: AliasKey) -> CompressionResult { + let alias = self.state.get_storage_at(self.alias_contract_address, alias_key)?; + if alias == Felt::ZERO { Err(CompressionError::MissedAlias(alias_key)) } else { Ok(alias) } + } +} diff --git a/crates/blockifier/src/state/stateful_compression_test.rs b/crates/blockifier/src/state/stateful_compression_test.rs new file mode 100644 index 00000000000..c6bc7ea4875 --- /dev/null +++ b/crates/blockifier/src/state/stateful_compression_test.rs @@ -0,0 +1,403 @@ +use std::collections::{HashMap, HashSet}; +use std::sync::LazyLock; + +use assert_matches::assert_matches; +use rstest::rstest; +use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce, PatriciaKey}; +use starknet_api::felt; +use starknet_api::state::StorageKey; +use starknet_types_core::felt::Felt; + +use super::{ + allocate_aliases_in_storage, + compress, + Alias, + AliasKey, + AliasUpdater, + ALIAS_COUNTER_STORAGE_KEY, + INITIAL_AVAILABLE_ALIAS, + MAX_NON_COMPRESSED_CONTRACT_ADDRESS, + MIN_VALUE_FOR_ALIAS_ALLOC, +}; +use crate::state::cached_state::{CachedState, StateMaps, StorageEntry}; +use crate::state::state_api::{State, StateReader}; +use crate::state::stateful_compression::{AliasCompressor, CompressionError}; +use crate::test_utils::dict_state_reader::DictStateReader; + +static ALIAS_CONTRACT_ADDRESS: LazyLock = + LazyLock::new(|| ContractAddress(PatriciaKey::try_from(Felt::TWO).unwrap())); + +/// Decompresses the state diff by replacing the aliases with addresses and storage keys. +fn decompress( + state_diff: &StateMaps, + state: &S, + alias_contract_address: ContractAddress, + alias_keys: HashSet, +) -> StateMaps { + let alias_decompressor = AliasDecompressorUtil::new(state, alias_contract_address, alias_keys); + + let mut nonces = HashMap::new(); + for (alias_contract_address, nonce) in state_diff.nonces.iter() { + nonces.insert(alias_decompressor.decompress_address(alias_contract_address), *nonce); + } + let mut class_hashes = HashMap::new(); + for (alias_contract_address, class_hash) in state_diff.class_hashes.iter() { + class_hashes + .insert(alias_decompressor.decompress_address(alias_contract_address), *class_hash); + } + let mut storage = HashMap::new(); + for ((alias_contract_address, alias_storage_key), value) in state_diff.storage.iter() { + let contract_address = alias_decompressor.decompress_address(alias_contract_address); + storage.insert( + ( + contract_address, + alias_decompressor.decompress_storage_key(alias_storage_key, &contract_address), + ), + *value, + ); + } + + StateMaps { nonces, class_hashes, storage, ..state_diff.clone() } +} + +/// Replaces aliases with the original contact addresses and storage keys. +struct AliasDecompressorUtil { + reversed_alias_mapping: HashMap, +} + +impl AliasDecompressorUtil { + fn new( + state: &S, + alias_contract_address: ContractAddress, + alias_keys: HashSet, + ) -> Self { + let mut reversed_alias_mapping = HashMap::new(); + for alias_key in alias_keys.into_iter() { + reversed_alias_mapping.insert( + state.get_storage_at(alias_contract_address, alias_key).unwrap(), + alias_key, + ); + } + Self { reversed_alias_mapping } + } + + fn decompress_address(&self, contract_address_alias: &ContractAddress) -> ContractAddress { + if contract_address_alias.0 >= MIN_VALUE_FOR_ALIAS_ALLOC { + ContractAddress::try_from( + *self.restore_alias_key(Felt::from(*contract_address_alias)).key(), + ) + .unwrap() + } else { + *contract_address_alias + } + } + + fn decompress_storage_key( + &self, + storage_key_alias: &StorageKey, + contact_address: &ContractAddress, + ) -> StorageKey { + if storage_key_alias.0 >= MIN_VALUE_FOR_ALIAS_ALLOC + && contact_address > &MAX_NON_COMPRESSED_CONTRACT_ADDRESS + { + self.restore_alias_key(*storage_key_alias.0) + } else { + *storage_key_alias + } + } + + fn restore_alias_key(&self, alias: Alias) -> AliasKey { + *self.reversed_alias_mapping.get(&alias).unwrap() + } +} + +fn insert_to_alias_contract( + storage: &mut HashMap, + key: StorageKey, + value: Felt, +) { + storage.insert((*ALIAS_CONTRACT_ADDRESS, key), value); +} + +fn initial_state(n_existing_aliases: u8) -> CachedState { + let mut state_reader = DictStateReader::default(); + if n_existing_aliases > 0 { + let high_alias_key = INITIAL_AVAILABLE_ALIAS * Felt::TWO; + insert_to_alias_contract( + &mut state_reader.storage_view, + ALIAS_COUNTER_STORAGE_KEY, + INITIAL_AVAILABLE_ALIAS + Felt::from(n_existing_aliases), + ); + for i in 0..n_existing_aliases { + insert_to_alias_contract( + &mut state_reader.storage_view, + (high_alias_key + Felt::from(i)).try_into().unwrap(), + INITIAL_AVAILABLE_ALIAS + Felt::from(i), + ); + } + } + + CachedState::new(state_reader) +} + +/// Tests the alias contract updater with an empty state. +#[rstest] +#[case::no_update(vec![], vec![])] +#[case::low_update(vec![INITIAL_AVAILABLE_ALIAS - 1], vec![])] +#[case::single_update(vec![INITIAL_AVAILABLE_ALIAS], vec![INITIAL_AVAILABLE_ALIAS])] +#[case::some_update( + vec![ + INITIAL_AVAILABLE_ALIAS + 1, + INITIAL_AVAILABLE_ALIAS - 1, + INITIAL_AVAILABLE_ALIAS, + INITIAL_AVAILABLE_ALIAS + 2, + INITIAL_AVAILABLE_ALIAS, + ], + vec![ + INITIAL_AVAILABLE_ALIAS + 1, + INITIAL_AVAILABLE_ALIAS, + INITIAL_AVAILABLE_ALIAS + 2, + ] +)] +fn test_alias_updater( + #[case] keys: Vec, + #[case] expected_alias_keys: Vec, + #[values(0, 2)] n_existing_aliases: u8, +) { + let mut state = initial_state(n_existing_aliases); + + // Insert the keys into the alias contract updater and finalize the updates. + let mut alias_contract_updater = + AliasUpdater::new(&mut state, *ALIAS_CONTRACT_ADDRESS).unwrap(); + for key in keys { + alias_contract_updater.insert_alias(&StorageKey::try_from(key).unwrap()).unwrap(); + } + alias_contract_updater.finalize_updates().unwrap(); + let storage_diff = state.to_state_diff().unwrap().state_maps.storage; + + // Test the new aliases. + let mut expected_storage_diff = HashMap::new(); + let mut expected_next_alias = INITIAL_AVAILABLE_ALIAS + Felt::from(n_existing_aliases); + for key in &expected_alias_keys { + insert_to_alias_contract( + &mut expected_storage_diff, + StorageKey::try_from(*key).unwrap(), + expected_next_alias, + ); + expected_next_alias += Felt::ONE; + } + if !expected_alias_keys.is_empty() || n_existing_aliases == 0 { + insert_to_alias_contract( + &mut expected_storage_diff, + ALIAS_COUNTER_STORAGE_KEY, + expected_next_alias, + ); + } + + assert_eq!(storage_diff, expected_storage_diff); +} + +#[test] +fn test_iterate_aliases() { + let mut state = initial_state(0); + state + .set_storage_at(ContractAddress::from(0x201_u16), StorageKey::from(0x307_u16), Felt::ONE) + .unwrap(); + state + .set_storage_at(ContractAddress::from(0x201_u16), StorageKey::from(0x309_u16), Felt::TWO) + .unwrap(); + state + .set_storage_at(ContractAddress::from(0x201_u16), StorageKey::from(0x304_u16), Felt::THREE) + .unwrap(); + state + .set_storage_at(MAX_NON_COMPRESSED_CONTRACT_ADDRESS, StorageKey::from(0x301_u16), Felt::ONE) + .unwrap(); + state.get_class_hash_at(ContractAddress::from(0x202_u16)).unwrap(); + state.set_class_hash_at(ContractAddress::from(0x202_u16), ClassHash(Felt::ONE)).unwrap(); + state.increment_nonce(ContractAddress::from(0x200_u16)).unwrap(); + + allocate_aliases_in_storage(&mut state, *ALIAS_CONTRACT_ADDRESS).unwrap(); + let storage_diff = state.to_state_diff().unwrap().state_maps.storage; + + assert_eq!( + storage_diff, + vec![ + ( + (*ALIAS_CONTRACT_ADDRESS, ALIAS_COUNTER_STORAGE_KEY), + INITIAL_AVAILABLE_ALIAS + Felt::from(6_u8) + ), + ((*ALIAS_CONTRACT_ADDRESS, StorageKey::from(0x200_u16)), INITIAL_AVAILABLE_ALIAS), + ( + (*ALIAS_CONTRACT_ADDRESS, StorageKey::from(0x304_u16)), + INITIAL_AVAILABLE_ALIAS + Felt::ONE + ), + ( + (*ALIAS_CONTRACT_ADDRESS, StorageKey::from(0x307_u16)), + INITIAL_AVAILABLE_ALIAS + Felt::TWO + ), + ( + (*ALIAS_CONTRACT_ADDRESS, StorageKey::from(0x309_u16)), + INITIAL_AVAILABLE_ALIAS + Felt::THREE + ), + ( + (*ALIAS_CONTRACT_ADDRESS, StorageKey::from(0x201_u16)), + INITIAL_AVAILABLE_ALIAS + Felt::from(4_u8) + ), + ( + (*ALIAS_CONTRACT_ADDRESS, StorageKey::from(0x202_u16)), + INITIAL_AVAILABLE_ALIAS + Felt::from(5_u8) + ), + ((ContractAddress::from(0x201_u16), StorageKey::from(0x304_u16)), Felt::THREE), + ((ContractAddress::from(0x201_u16), StorageKey::from(0x307_u16)), Felt::ONE), + ((ContractAddress::from(0x201_u16), StorageKey::from(0x309_u16)), Felt::TWO), + ((MAX_NON_COMPRESSED_CONTRACT_ADDRESS, StorageKey::from(0x301_u16)), Felt::ONE), + ] + .into_iter() + .collect() + ); +} + +#[rstest] +fn test_read_only_state(#[values(0, 2)] n_existing_aliases: u8) { + let mut state = initial_state(n_existing_aliases); + state + .set_storage_at(ContractAddress::from(0x200_u16), StorageKey::from(0x300_u16), Felt::ZERO) + .unwrap(); + state.get_nonce_at(ContractAddress::from(0x201_u16)).unwrap(); + state.get_class_hash_at(ContractAddress::from(0x202_u16)).unwrap(); + allocate_aliases_in_storage(&mut state, *ALIAS_CONTRACT_ADDRESS).unwrap(); + let storage_diff = state.to_state_diff().unwrap().state_maps.storage; + + let expected_storage_diff = if n_existing_aliases == 0 { + HashMap::from([( + (*ALIAS_CONTRACT_ADDRESS, ALIAS_COUNTER_STORAGE_KEY), + INITIAL_AVAILABLE_ALIAS, + )]) + } else { + HashMap::new() + }; + assert_eq!(storage_diff, expected_storage_diff); +} + +/// Tests the range of alias keys that should be compressed. +#[test] +fn test_alias_compressor() { + let alias = Felt::from(500_u16); + + let high_key = 200_u16; + let high_storage_key = StorageKey::from(high_key); + let high_contract_address = ContractAddress::from(high_key); + + let no_aliasing_key = 50_u16; + let no_aliasing_storage_key = StorageKey::from(no_aliasing_key); + let no_aliasing_contract_address = ContractAddress::from(no_aliasing_key); + + let no_compression_contract_address = ContractAddress::from(10_u16); + + let mut state_reader = DictStateReader::default(); + insert_to_alias_contract(&mut state_reader.storage_view, high_storage_key, alias); + let alias_compressor = + AliasCompressor { state: &state_reader, alias_contract_address: *ALIAS_CONTRACT_ADDRESS }; + + assert_eq!( + alias_compressor.compress_address(&high_contract_address).unwrap(), + ContractAddress::try_from(alias).unwrap(), + ); + assert_eq!( + alias_compressor.compress_address(&no_aliasing_contract_address).unwrap(), + no_aliasing_contract_address, + ); + + assert_eq!( + alias_compressor.compress_storage_key(&high_storage_key, &high_contract_address).unwrap(), + StorageKey::try_from(alias).unwrap(), + ); + assert_eq!( + alias_compressor + .compress_storage_key(&no_aliasing_storage_key, &high_contract_address) + .unwrap(), + no_aliasing_storage_key, + ); + assert_eq!( + alias_compressor + .compress_storage_key(&high_storage_key, &no_compression_contract_address) + .unwrap(), + high_storage_key, + ); + + let missed_key = 300_u16; + let err = alias_compressor.compress_address(&ContractAddress::from(missed_key)); + assert_matches!( + err, + Err(CompressionError::MissedAlias(key)) if key == missed_key.into() + ); +} + +#[test] +fn test_compression() { + let state_reader = DictStateReader { + storage_view: (200_u16..206) + .map(|x| ((*ALIAS_CONTRACT_ADDRESS, StorageKey::from(x)), Felt::from(x + 100))) + .collect(), + ..Default::default() + }; + + // State diff with values that should not be compressed. + let base_state_diff = StateMaps { + nonces: vec![(ContractAddress::from(30_u16), Nonce(Felt::ONE))].into_iter().collect(), + class_hashes: vec![(ContractAddress::from(31_u16), ClassHash(Felt::ONE))] + .into_iter() + .collect(), + storage: vec![((ContractAddress::from(10_u16), StorageKey::from(205_u16)), Felt::TWO)] + .into_iter() + .collect(), + compiled_class_hashes: vec![(ClassHash(felt!("0x400")), CompiledClassHash(felt!("0x401")))] + .into_iter() + .collect(), + declared_contracts: vec![(ClassHash(felt!("0x402")), true)].into_iter().collect(), + }; + + let compressed_base_state_diff = + compress(&base_state_diff, &state_reader, *ALIAS_CONTRACT_ADDRESS).unwrap(); + assert_eq!(compressed_base_state_diff, base_state_diff); + + // Add to the state diff values that should be compressed. + let mut state_diff = base_state_diff.clone(); + state_diff.extend(&StateMaps { + nonces: vec![(ContractAddress::from(200_u16), Nonce(Felt::ZERO))].into_iter().collect(), + class_hashes: vec![(ContractAddress::from(201_u16), ClassHash(Felt::ZERO))] + .into_iter() + .collect(), + storage: vec![ + ((ContractAddress::from(202_u16), StorageKey::from(203_u16)), Felt::ZERO), + ((ContractAddress::from(32_u16), StorageKey::from(204_u16)), Felt::ONE), + ] + .into_iter() + .collect(), + ..Default::default() + }); + + let mut expected_compressed_state_diff = base_state_diff.clone(); + expected_compressed_state_diff.extend(&StateMaps { + nonces: vec![(ContractAddress::from(300_u16), Nonce(Felt::ZERO))].into_iter().collect(), + class_hashes: vec![(ContractAddress::from(301_u16), ClassHash(Felt::ZERO))] + .into_iter() + .collect(), + storage: vec![ + ((ContractAddress::from(302_u16), StorageKey::from(303_u16)), Felt::ZERO), + ((ContractAddress::from(32_u16), StorageKey::from(304_u16)), Felt::ONE), + ] + .into_iter() + .collect(), + ..Default::default() + }); + + let compressed_state_diff = + compress(&state_diff, &state_reader, *ALIAS_CONTRACT_ADDRESS).unwrap(); + assert_eq!(compressed_state_diff, expected_compressed_state_diff); + + let alias_keys = state_reader.storage_view.keys().map(|(_, key)| *key).collect(); + let decompressed_state_diff = + decompress(&compressed_state_diff, &state_reader, *ALIAS_CONTRACT_ADDRESS, alias_keys); + assert_eq!(decompressed_state_diff, state_diff); +} diff --git a/crates/blockifier/src/test_utils.rs b/crates/blockifier/src/test_utils.rs index 94ac0644891..c68896a86e2 100644 --- a/crates/blockifier/src/test_utils.rs +++ b/crates/blockifier/src/test_utils.rs @@ -1,110 +1,82 @@ -pub mod cairo_compile; pub mod contracts; -pub mod declare; -pub mod deploy_account; pub mod dict_state_reader; pub mod initial_test_state; -pub mod invoke; pub mod l1_handler; pub mod prices; pub mod struct_impls; pub mod syscall; +#[cfg(test)] +pub mod test_templates; pub mod transfers_generator; use std::collections::HashMap; -use std::fs; -use std::path::PathBuf; +use std::slice::Iter; +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; +use blockifier_test_utils::contracts::FeatureContract; use cairo_vm::types::builtin_name::BuiltinName; use cairo_vm::vm::runners::cairo_runner::ExecutionResources; -use starknet_api::abi::abi_utils::{get_fee_token_var_address, selector_from_name}; -use starknet_api::block::{BlockHash, BlockHashAndNumber, BlockNumber, GasPrice, NonzeroGasPrice}; +use starknet_api::abi::abi_utils::get_fee_token_var_address; +use starknet_api::block::{BlockHash, BlockHashAndNumber, BlockNumber}; use starknet_api::core::{ClassHash, ContractAddress}; use starknet_api::execution_resources::{GasAmount, GasVector}; use starknet_api::hash::StarkHash; use starknet_api::state::StorageKey; +use starknet_api::test_utils::{ + DEFAULT_L1_DATA_GAS_MAX_AMOUNT, + DEFAULT_L1_GAS_AMOUNT, + DEFAULT_L2_GAS_MAX_AMOUNT, + DEFAULT_STRK_L1_DATA_GAS_PRICE, + DEFAULT_STRK_L1_GAS_PRICE, + DEFAULT_STRK_L2_GAS_PRICE, + MAX_FEE, + TEST_SEQUENCER_ADDRESS, +}; use starknet_api::transaction::fields::{ Calldata, ContractAddressSalt, Fee, GasVectorComputationMode, }; -use starknet_api::transaction::TransactionVersion; use starknet_api::{contract_address, felt}; use starknet_types_core::felt::Felt; +use strum::EnumCount; +use strum_macros::EnumCount as EnumCountMacro; use crate::abi::constants; +use crate::blockifier_versioned_constants::VersionedConstants; use crate::execution::call_info::ExecutionSummary; use crate::execution::contract_class::TrackedResource; -use crate::execution::deprecated_syscalls::hint_processor::SyscallCounter; use crate::execution::entry_point::CallEntryPoint; +use crate::execution::syscalls::hint_processor::{SyscallUsage, SyscallUsageMap}; use crate::execution::syscalls::SyscallSelector; use crate::fee::resources::{StarknetResources, StateResources}; -use crate::test_utils::contracts::FeatureContract; use crate::transaction::transaction_types::TransactionType; use crate::utils::{const_max, u64_from_usize}; -use crate::versioned_constants::VersionedConstants; -// TODO(Dori, 1/2/2024): Remove these constants once all tests use the `contracts` and -// `initial_test_state` modules for testing. -// Addresses. -pub const TEST_SEQUENCER_ADDRESS: &str = "0x1000"; -pub const TEST_ERC20_CONTRACT_ADDRESS: &str = "0x1001"; -pub const TEST_ERC20_CONTRACT_ADDRESS2: &str = "0x1002"; - // Class hashes. // TODO(Adi, 15/01/2023): Remove and compute the class hash corresponding to the ERC20 contract in // starkgate once we use the real ERC20 contract. pub const TEST_ERC20_CONTRACT_CLASS_HASH: &str = "0x1010"; // Paths. -pub const ERC20_CONTRACT_PATH: &str = "./ERC20/ERC20_Cairo0/ERC20_without_some_syscalls/ERC20/\ +pub const ERC20_CONTRACT_PATH: &str = "../blockifier_test_utils/resources/ERC20/ERC20_Cairo0/\ + ERC20_without_some_syscalls/ERC20/\ erc20_contract_without_some_syscalls_compiled.json"; -// TODO(Aviv, 14/7/2024): Move from test utils module, and use it in ContractClassVersionMismatch -// error. -#[derive(Clone, Hash, PartialEq, Eq, Copy, Debug)] -pub enum CairoVersion { - Cairo0, - Cairo1, - #[cfg(feature = "cairo_native")] - Native, -} - -impl Default for CairoVersion { - fn default() -> Self { - Self::Cairo0 - } +#[derive(Clone, Copy, EnumCountMacro, PartialEq, Eq, Debug)] +pub enum CompilerBasedVersion { + CairoVersion(CairoVersion), + OldCairo1, } -impl CairoVersion { - // A declare transaction of the given version, can be used to declare contracts of the returned - // cairo version. - // TODO: Make TransactionVersion an enum and use match here. - pub fn from_declare_tx_version(tx_version: TransactionVersion) -> Self { - if tx_version == TransactionVersion::ZERO || tx_version == TransactionVersion::ONE { - CairoVersion::Cairo0 - } else if tx_version == TransactionVersion::TWO || tx_version == TransactionVersion::THREE { - CairoVersion::Cairo1 - } else { - panic!("Transaction version {:?} is not supported.", tx_version) - } - } - - pub fn other(&self) -> Self { - match self { - Self::Cairo0 => Self::Cairo1, - Self::Cairo1 => Self::Cairo0, - #[cfg(feature = "cairo_native")] - Self::Native => panic!("There is no other version for native"), +impl From for CairoVersion { + fn from(compiler_based_version: CompilerBasedVersion) -> Self { + match compiler_based_version { + CompilerBasedVersion::CairoVersion(version) => version, + CompilerBasedVersion::OldCairo1 => CairoVersion::Cairo1(RunnableCairo1::Casm), } } } -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub enum CompilerBasedVersion { - CairoVersion(CairoVersion), - OldCairo1, -} - impl CompilerBasedVersion { pub fn get_test_contract(&self) -> FeatureContract { match self { @@ -120,11 +92,20 @@ impl CompilerBasedVersion { Self::CairoVersion(CairoVersion::Cairo0) | Self::OldCairo1 => { TrackedResource::CairoSteps } - Self::CairoVersion(CairoVersion::Cairo1) => TrackedResource::SierraGas, - #[cfg(feature = "cairo_native")] - Self::CairoVersion(CairoVersion::Native) => TrackedResource::SierraGas, + Self::CairoVersion(CairoVersion::Cairo1(_)) => TrackedResource::SierraGas, } } + + /// Returns an iterator over all of the enum variants. + pub fn iter() -> Iter<'static, Self> { + assert_eq!(Self::COUNT, 2); + static VERSIONS: [CompilerBasedVersion; 3] = [ + CompilerBasedVersion::CairoVersion(CairoVersion::Cairo0), + CompilerBasedVersion::OldCairo1, + CompilerBasedVersion::CairoVersion(CairoVersion::Cairo1(RunnableCairo1::Casm)), + ]; + VERSIONS.iter() + } } // Storage keys. @@ -132,29 +113,6 @@ pub fn test_erc20_sequencer_balance_key() -> StorageKey { get_fee_token_var_address(contract_address!(TEST_SEQUENCER_ADDRESS)) } -// The max_fee / resource bounds used for txs in this test. -// V3 transactions: -pub const DEFAULT_L1_GAS_AMOUNT: GasAmount = GasAmount(u64::pow(10, 6)); -pub const DEFAULT_L1_DATA_GAS_MAX_AMOUNT: GasAmount = GasAmount(u64::pow(10, 6)); -pub const DEFAULT_L2_GAS_MAX_AMOUNT: GasAmount = GasAmount(u64::pow(10, 9)); -pub const MAX_L1_GAS_PRICE: NonzeroGasPrice = DEFAULT_STRK_L1_GAS_PRICE; -pub const MAX_L2_GAS_PRICE: NonzeroGasPrice = DEFAULT_STRK_L2_GAS_PRICE; -pub const MAX_L1_DATA_GAS_PRICE: NonzeroGasPrice = DEFAULT_STRK_L1_DATA_GAS_PRICE; - -pub const DEFAULT_ETH_L1_GAS_PRICE: NonzeroGasPrice = - NonzeroGasPrice::new_unchecked(GasPrice(100 * u128::pow(10, 9))); // Given in units of Wei. -pub const DEFAULT_STRK_L1_GAS_PRICE: NonzeroGasPrice = - NonzeroGasPrice::new_unchecked(GasPrice(100 * u128::pow(10, 9))); // Given in units of STRK. -pub const DEFAULT_ETH_L1_DATA_GAS_PRICE: NonzeroGasPrice = - NonzeroGasPrice::new_unchecked(GasPrice(u128::pow(10, 6))); // Given in units of Wei. -pub const DEFAULT_STRK_L1_DATA_GAS_PRICE: NonzeroGasPrice = - NonzeroGasPrice::new_unchecked(GasPrice(u128::pow(10, 9))); // Given in units of STRK. -pub const DEFAULT_STRK_L2_GAS_PRICE: NonzeroGasPrice = - NonzeroGasPrice::new_unchecked(GasPrice(u128::pow(10, 9))); - -// Deprecated transactions: -pub const MAX_FEE: Fee = DEFAULT_L1_GAS_AMOUNT.nonzero_saturating_mul(DEFAULT_ETH_L1_GAS_PRICE); - // Commitment fee bounds. const DEFAULT_L1_BOUNDS_COMMITTED_FEE: Fee = DEFAULT_L1_GAS_AMOUNT.nonzero_saturating_mul(DEFAULT_STRK_L1_GAS_PRICE); @@ -171,14 +129,6 @@ pub const BALANCE: Fee = Fee(10 MAX_FEE.0, )); -// The block number of the BlockContext being used for testing. -pub const CURRENT_BLOCK_NUMBER: u64 = 2001; -pub const CURRENT_BLOCK_NUMBER_FOR_VALIDATE: u64 = 2000; - -// The block timestamp of the BlockContext being used for testing. -pub const CURRENT_BLOCK_TIMESTAMP: u64 = 1072023; -pub const CURRENT_BLOCK_TIMESTAMP_FOR_VALIDATE: u64 = 1069200; - #[derive(Default)] pub struct SaltManager { next_salt: u8, @@ -197,11 +147,6 @@ pub fn pad_address_to_64(address: &str) -> String { String::from("0x") + format!("{trimmed_address:0>64}").as_str() } -pub fn get_raw_contract_class(contract_path: &str) -> String { - let path: PathBuf = [env!("CARGO_MANIFEST_DIR"), contract_path].iter().collect(); - fs::read_to_string(path).unwrap() -} - pub fn trivial_external_entry_point_new(contract: FeatureContract) -> CallEntryPoint { let address = contract.get_instance_address(0); trivial_external_entry_point_with_address(address) @@ -216,6 +161,7 @@ pub fn trivial_external_entry_point_with_address( initial_gas: VersionedConstants::create_for_testing() .os_constants .gas_costs + .base .default_initial_gas_cost, ..Default::default() } @@ -333,19 +279,8 @@ macro_rules! check_tx_execution_error_for_invalid_scenario { $validate_constructor, ); } - CairoVersion::Cairo1 => { - if let $crate::transaction::errors::TransactionExecutionError::ValidateTransactionError { - error, .. - } = $error { - assert_eq!( - error.to_string(), - "Execution failed. Failure reason: 0x496e76616c6964207363656e6172696f \ - ('Invalid scenario')." - ) - } - } - #[cfg(feature = "cairo_native")] - CairoVersion::Native => { + + CairoVersion::Cairo1(_) => { if let $crate::transaction::errors::TransactionExecutionError::ValidateTransactionError { error, .. } = $error { @@ -360,10 +295,12 @@ macro_rules! check_tx_execution_error_for_invalid_scenario { }; } -pub fn get_syscall_resources(syscall_selector: SyscallSelector) -> ExecutionResources { +/// Returns the const syscall resources for the given syscall selector. +pub fn get_const_syscall_resources(syscall_selector: SyscallSelector) -> ExecutionResources { let versioned_constants = VersionedConstants::create_for_testing(); - let syscall_counter: SyscallCounter = HashMap::from([(syscall_selector, 1)]); - versioned_constants.get_additional_os_syscall_resources(&syscall_counter) + let syscalls_usage: SyscallUsageMap = + HashMap::from([(syscall_selector, SyscallUsage::new(1, 0))]); + versioned_constants.get_additional_os_syscall_resources(&syscalls_usage) } pub fn get_tx_resources(tx_type: TransactionType) -> ExecutionResources { @@ -409,45 +346,6 @@ pub fn calldata_for_deploy_test( ) } -/// Creates the calldata for the "__execute__" entry point in the featured contracts -/// AccountWithLongValidate and AccountWithoutValidations. The format of the returned calldata is: -/// [ -/// contract_address, -/// entry_point_name, -/// calldata_length, -/// *calldata, -/// ] -/// The contract_address is the address of the called contract, the entry_point_name is the -/// name of the called entry point in said contract, and the calldata is the calldata for the called -/// entry point. -pub fn create_calldata( - contract_address: ContractAddress, - entry_point_name: &str, - entry_point_args: &[Felt], -) -> Calldata { - Calldata( - [ - vec![ - *contract_address.0.key(), // Contract address. - selector_from_name(entry_point_name).0, // EP selector name. - felt!(u64_from_usize(entry_point_args.len())), - ], - entry_point_args.into(), - ] - .concat() - .into(), - ) -} - -/// Calldata for a trivial entry point in the test contract. -pub fn create_trivial_calldata(test_contract_address: ContractAddress) -> Calldata { - create_calldata( - test_contract_address, - "return_result", - &[felt!(2_u8)], // Calldata: num. - ) -} - pub fn update_json_value(base: &mut serde_json::Value, update: serde_json::Value) { match (base, update) { (serde_json::Value::Object(base_map), serde_json::Value::Object(update_map)) => { @@ -465,7 +363,7 @@ pub fn gas_vector_from_vm_usage( match computation_mode { GasVectorComputationMode::NoL2Gas => GasVector::from_l1_gas(vm_usage_in_l1_gas), GasVectorComputationMode::All => GasVector::from_l2_gas( - versioned_constants.convert_l1_to_l2_gas_amount_round_up(vm_usage_in_l1_gas), + versioned_constants.l1_gas_to_sierra_gas_amount_round_up(vm_usage_in_l1_gas), ), } } diff --git a/crates/blockifier/src/test_utils/contracts.rs b/crates/blockifier/src/test_utils/contracts.rs index 7a4bb8fa93d..e66d8b4fb76 100644 --- a/crates/blockifier/src/test_utils/contracts.rs +++ b/crates/blockifier/src/test_utils/contracts.rs @@ -1,360 +1,24 @@ +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; +use blockifier_test_utils::contracts::FeatureContract; use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass; use starknet_api::abi::abi_utils::selector_from_name; use starknet_api::abi::constants::CONSTRUCTOR_ENTRY_POINT_NAME; use starknet_api::contract_class::{ContractClass, EntryPointType}; -use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, EntryPointSelector}; +use starknet_api::core::{ClassHash, ContractAddress, EntryPointSelector}; use starknet_api::deprecated_contract_class::{ ContractClass as DeprecatedContractClass, EntryPointOffset, }; -use starknet_api::{class_hash, contract_address, felt}; -use starknet_types_core::felt::Felt; -use strum::IntoEnumIterator; -use strum_macros::EnumIter; -use crate::execution::contract_class::RunnableContractClass; -use crate::execution::entry_point::CallEntryPoint; +use crate::execution::contract_class::RunnableCompiledClass; +use crate::execution::entry_point::EntryPointTypeAndSelector; #[cfg(feature = "cairo_native")] -use crate::execution::native::contract_class::NativeContractClassV1; -#[cfg(feature = "cairo_native")] -use crate::test_utils::cairo_compile::starknet_compile; -use crate::test_utils::cairo_compile::{cairo0_compile, cairo1_compile}; +use crate::execution::native::contract_class::NativeCompiledClassV1; use crate::test_utils::struct_impls::LoadContractFromFile; -use crate::test_utils::{get_raw_contract_class, CairoVersion}; - -// This file contains featured contracts, used for tests. Use the function 'test_state' in -// initial_test_state.rs to initialize a state with these contracts. -// -// Use the mock class hashes and addresses to interact with the contracts in tests. -// The structure of such mock address / class hash is as follows: -// +-+-+-----------+---------------+---------------+---------------+ -// |v|a| reserved | 8 bits: class | 16 bits : address | -// +-+-+-----------+---------------+---------------+---------------+ -// v: 1 bit. 0 for Cairo0, 1 for Cairo1. bit 31. -// a: 1 bit. 0 for class hash, 1 for address. bit 30. -// reserved: Must be 0. bit 29-24. -// class: 8 bits. The class hash of the contract. bit 23-16. allows up to 256 unique contracts. -// address: 16 bits. The instance ID of the contract. bit 15-0. allows up to 65536 instances of each -// contract. - -// Bit to set on class hashes and addresses of feature contracts to indicate the Cairo1 variant. -const CAIRO1_BIT: u32 = 1 << 31; - -// Bit to set on a class hash to convert it to the respective address. -const ADDRESS_BIT: u32 = 1 << 30; - -// Mock class hashes of the feature contract. Keep the bottom 16 bits of each class hash unset, to -// allow up to 65536 deployed instances of each contract. -const CLASS_HASH_BASE: u32 = 1 << 16; -const ACCOUNT_LONG_VALIDATE_BASE: u32 = CLASS_HASH_BASE; -const ACCOUNT_WITHOUT_VALIDATIONS_BASE: u32 = 2 * CLASS_HASH_BASE; -const EMPTY_CONTRACT_BASE: u32 = 3 * CLASS_HASH_BASE; -const FAULTY_ACCOUNT_BASE: u32 = 4 * CLASS_HASH_BASE; -const LEGACY_CONTRACT_BASE: u32 = 5 * CLASS_HASH_BASE; -const SECURITY_TEST_CONTRACT_BASE: u32 = 6 * CLASS_HASH_BASE; -const TEST_CONTRACT_BASE: u32 = 7 * CLASS_HASH_BASE; -const ERC20_CONTRACT_BASE: u32 = 8 * CLASS_HASH_BASE; -const CAIRO_STEPS_TEST_CONTRACT_BASE: u32 = 9 * CLASS_HASH_BASE; -#[cfg(feature = "cairo_native")] -const SIERRA_EXECUTION_INFO_V1_CONTRACT_BASE: u32 = 10 * CLASS_HASH_BASE; - -// Contract names. -const ACCOUNT_LONG_VALIDATE_NAME: &str = "account_with_long_validate"; -const ACCOUNT_WITHOUT_VALIDATIONS_NAME: &str = "account_with_dummy_validate"; -const EMPTY_CONTRACT_NAME: &str = "empty_contract"; -const FAULTY_ACCOUNT_NAME: &str = "account_faulty"; -const LEGACY_CONTRACT_NAME: &str = "legacy_test_contract"; -const SECURITY_TEST_CONTRACT_NAME: &str = "security_tests_contract"; -const TEST_CONTRACT_NAME: &str = "test_contract"; -const CAIRO_STEPS_TEST_CONTRACT_NAME: &str = "cairo_steps_test_contract"; -#[cfg(feature = "cairo_native")] -const EXECUTION_INFO_V1_CONTRACT_NAME: &str = "test_contract_execution_info_v1"; - -// ERC20 contract is in a unique location. -const ERC20_CAIRO0_CONTRACT_SOURCE_PATH: &str = - "./ERC20/ERC20_Cairo0/ERC20_without_some_syscalls/ERC20/ERC20.cairo"; -const ERC20_CAIRO0_CONTRACT_PATH: &str = "./ERC20/ERC20_Cairo0/ERC20_without_some_syscalls/ERC20/\ - erc20_contract_without_some_syscalls_compiled.json"; -const ERC20_CAIRO1_CONTRACT_SOURCE_PATH: &str = "./ERC20/ERC20_Cairo1/ERC20.cairo"; -const ERC20_CAIRO1_CONTRACT_PATH: &str = "./ERC20/ERC20_Cairo1/erc20.casm.json"; - -// The following contracts are compiled with a fixed version of the compiler. This compiler version -// no longer compiles with stable rust, so the toolchain is also fixed. -const LEGACY_CONTRACT_COMPILER_TAG: &str = "v2.1.0"; -const LEGACY_CONTRACT_RUST_TOOLCHAIN: &str = "2023-07-05"; - -const CAIRO_STEPS_TEST_CONTRACT_COMPILER_TAG: &str = "v2.7.0"; -const CAIRO_STEPS_TEST_CONTRACT_RUST_TOOLCHAIN: &str = "2024-04-29"; - -/// Enum representing all feature contracts. -/// The contracts that are implemented in both Cairo versions include a version field. -#[derive(Clone, Copy, Debug, EnumIter, Hash, PartialEq, Eq)] -pub enum FeatureContract { - AccountWithLongValidate(CairoVersion), - AccountWithoutValidations(CairoVersion), - ERC20(CairoVersion), - Empty(CairoVersion), - FaultyAccount(CairoVersion), - LegacyTestContract, - SecurityTests, - TestContract(CairoVersion), - CairoStepsTestContract, - #[cfg(feature = "cairo_native")] - SierraExecutionInfoV1Contract, -} - -impl FeatureContract { - pub fn cairo_version(&self) -> CairoVersion { - match self { - Self::AccountWithLongValidate(version) - | Self::AccountWithoutValidations(version) - | Self::Empty(version) - | Self::FaultyAccount(version) - | Self::TestContract(version) - | Self::ERC20(version) => *version, - Self::SecurityTests => CairoVersion::Cairo0, - Self::LegacyTestContract | Self::CairoStepsTestContract => CairoVersion::Cairo1, - #[cfg(feature = "cairo_native")] - Self::SierraExecutionInfoV1Contract => CairoVersion::Native, - } - } - - fn has_two_versions(&self) -> bool { - match self { - Self::AccountWithLongValidate(_) - | Self::AccountWithoutValidations(_) - | Self::Empty(_) - | Self::FaultyAccount(_) - | Self::TestContract(_) - | Self::ERC20(_) => true, - #[cfg(feature = "cairo_native")] - Self::SierraExecutionInfoV1Contract => false, - Self::SecurityTests | Self::LegacyTestContract | Self::CairoStepsTestContract => false, - } - } - - pub fn set_cairo_version(&mut self, version: CairoVersion) { - match self { - Self::AccountWithLongValidate(v) - | Self::AccountWithoutValidations(v) - | Self::Empty(v) - | Self::FaultyAccount(v) - | Self::TestContract(v) - | Self::ERC20(v) => *v = version, - Self::LegacyTestContract | Self::SecurityTests | Self::CairoStepsTestContract => { - panic!("{self:?} contract has no configurable version.") - } - #[cfg(feature = "cairo_native")] - Self::SierraExecutionInfoV1Contract => { - panic!("{self:?} contract has no configurable version.") - } - } - } - - pub fn get_class_hash(&self) -> ClassHash { - class_hash!(self.get_integer_base()) - } - - pub fn get_compiled_class_hash(&self) -> CompiledClassHash { - match self.cairo_version() { - CairoVersion::Cairo0 => CompiledClassHash(Felt::ZERO), - CairoVersion::Cairo1 => CompiledClassHash(felt!(self.get_integer_base())), - #[cfg(feature = "cairo_native")] - CairoVersion::Native => CompiledClassHash(felt!(self.get_integer_base())), - } - } - - /// Returns the address of the instance with the given instance ID. - pub fn get_instance_address(&self, instance_id: u16) -> ContractAddress { - let instance_id_as_u32: u32 = instance_id.into(); - contract_address!(self.get_integer_base() + instance_id_as_u32 + ADDRESS_BIT) - } - - pub fn get_class(&self) -> ContractClass { - match self.cairo_version() { - CairoVersion::Cairo0 => { - ContractClass::V0(DeprecatedContractClass::from_file(&self.get_compiled_path())) - } - CairoVersion::Cairo1 => { - ContractClass::V1(CasmContractClass::from_file(&self.get_compiled_path())) - } - #[cfg(feature = "cairo_native")] - CairoVersion::Native => { - panic!("Native contracts are not supported by this function.") - } - } - } - - pub fn get_runnable_class(&self) -> RunnableContractClass { - #[cfg(feature = "cairo_native")] - if CairoVersion::Native == self.cairo_version() { - let native_contract_class = - NativeContractClassV1::compile_or_get_cached(&self.get_compiled_path()); - return RunnableContractClass::V1Native(native_contract_class); - } - - self.get_class().try_into().unwrap() - } - - pub fn get_raw_class(&self) -> String { - get_raw_contract_class(&self.get_compiled_path()) - } - fn get_cairo_version_bit(&self) -> u32 { - match self.cairo_version() { - CairoVersion::Cairo0 => 0, - CairoVersion::Cairo1 => CAIRO1_BIT, - #[cfg(feature = "cairo_native")] - CairoVersion::Native => CAIRO1_BIT, - } - } - - /// Some contracts are designed to test behavior of code compiled with a - /// specific (old) compiler tag. To run the (old) compiler, older rust - /// version is required. - pub fn fixed_tag_and_rust_toolchain(&self) -> (Option, Option) { - match self { - Self::LegacyTestContract => ( - Some(LEGACY_CONTRACT_COMPILER_TAG.into()), - Some(LEGACY_CONTRACT_RUST_TOOLCHAIN.into()), - ), - Self::CairoStepsTestContract => ( - Some(CAIRO_STEPS_TEST_CONTRACT_COMPILER_TAG.into()), - Some(CAIRO_STEPS_TEST_CONTRACT_RUST_TOOLCHAIN.into()), - ), - _ => (None, None), - } - } - - /// Unique integer representing each unique contract. Used to derive "class hash" and "address". - fn get_integer_base(self) -> u32 { - self.get_cairo_version_bit() - + match self { - Self::AccountWithLongValidate(_) => ACCOUNT_LONG_VALIDATE_BASE, - Self::AccountWithoutValidations(_) => ACCOUNT_WITHOUT_VALIDATIONS_BASE, - Self::Empty(_) => EMPTY_CONTRACT_BASE, - Self::ERC20(_) => ERC20_CONTRACT_BASE, - Self::FaultyAccount(_) => FAULTY_ACCOUNT_BASE, - Self::LegacyTestContract => LEGACY_CONTRACT_BASE, - Self::SecurityTests => SECURITY_TEST_CONTRACT_BASE, - Self::TestContract(_) => TEST_CONTRACT_BASE, - Self::CairoStepsTestContract => CAIRO_STEPS_TEST_CONTRACT_BASE, - #[cfg(feature = "cairo_native")] - Self::SierraExecutionInfoV1Contract => SIERRA_EXECUTION_INFO_V1_CONTRACT_BASE, - } - } - - fn get_non_erc20_base_name(&self) -> &str { - match self { - Self::AccountWithLongValidate(_) => ACCOUNT_LONG_VALIDATE_NAME, - Self::AccountWithoutValidations(_) => ACCOUNT_WITHOUT_VALIDATIONS_NAME, - Self::Empty(_) => EMPTY_CONTRACT_NAME, - Self::FaultyAccount(_) => FAULTY_ACCOUNT_NAME, - Self::LegacyTestContract => LEGACY_CONTRACT_NAME, - Self::SecurityTests => SECURITY_TEST_CONTRACT_NAME, - Self::TestContract(_) => TEST_CONTRACT_NAME, - Self::CairoStepsTestContract => CAIRO_STEPS_TEST_CONTRACT_NAME, - #[cfg(feature = "cairo_native")] - Self::SierraExecutionInfoV1Contract => EXECUTION_INFO_V1_CONTRACT_NAME, - Self::ERC20(_) => unreachable!(), - } - } - - pub fn get_source_path(&self) -> String { - // Special case: ERC20 contract in a different location. - if let Self::ERC20(cairo_version) = self { - match cairo_version { - CairoVersion::Cairo0 => ERC20_CAIRO0_CONTRACT_SOURCE_PATH, - CairoVersion::Cairo1 => ERC20_CAIRO1_CONTRACT_SOURCE_PATH, - #[cfg(feature = "cairo_native")] - CairoVersion::Native => todo!("ERC20 contract is not supported by Native yet"), - } - .into() - } else { - format!( - "feature_contracts/cairo{}/{}.cairo", - match self.cairo_version() { - CairoVersion::Cairo0 => "0", - CairoVersion::Cairo1 => "1", - #[cfg(feature = "cairo_native")] - CairoVersion::Native => "_native", - }, - self.get_non_erc20_base_name() - ) - } - } - - pub fn get_compiled_path(&self) -> String { - // ERC20 is a special case - not in the feature_contracts directory. - if let Self::ERC20(cairo_version) = self { - match cairo_version { - CairoVersion::Cairo0 => ERC20_CAIRO0_CONTRACT_PATH, - CairoVersion::Cairo1 => ERC20_CAIRO1_CONTRACT_PATH, - #[cfg(feature = "cairo_native")] - CairoVersion::Native => todo!("ERC20 cannot be tested with Native"), - } - .into() - } else { - let cairo_version = self.cairo_version(); - format!( - "feature_contracts/cairo{}/compiled/{}{}.json", - match cairo_version { - CairoVersion::Cairo0 => "0", - CairoVersion::Cairo1 => "1", - #[cfg(feature = "cairo_native")] - CairoVersion::Native => "_native", - }, - self.get_non_erc20_base_name(), - match cairo_version { - CairoVersion::Cairo0 => "_compiled", - CairoVersion::Cairo1 => ".casm", - #[cfg(feature = "cairo_native")] - CairoVersion::Native => ".sierra", - } - ) - } - } - - /// Compiles the feature contract and returns the compiled contract as a byte vector. - /// Panics if the contract is ERC20, as ERC20 contract recompilation is not supported. - pub fn compile(&self) -> Vec { - if matches!(self, Self::ERC20(_)) { - panic!("ERC20 contract recompilation not supported."); - } - match self.cairo_version() { - CairoVersion::Cairo0 => { - let extra_arg: Option = match self { - // Account contracts require the account_contract flag. - FeatureContract::AccountWithLongValidate(_) - | FeatureContract::AccountWithoutValidations(_) - | FeatureContract::FaultyAccount(_) => Some("--account_contract".into()), - FeatureContract::SecurityTests => Some("--disable_hint_validation".into()), - FeatureContract::Empty(_) - | FeatureContract::TestContract(_) - | FeatureContract::LegacyTestContract - | FeatureContract::CairoStepsTestContract => None, - #[cfg(feature = "cairo_native")] - FeatureContract::SierraExecutionInfoV1Contract => None, - FeatureContract::ERC20(_) => unreachable!(), - }; - cairo0_compile(self.get_source_path(), extra_arg, false) - } - CairoVersion::Cairo1 => { - let (tag_override, cargo_nightly_arg) = self.fixed_tag_and_rust_toolchain(); - cairo1_compile(self.get_source_path(), tag_override, cargo_nightly_arg) - } - #[cfg(feature = "cairo_native")] - CairoVersion::Native => { - let (tag_override, cargo_nightly_arg) = self.fixed_tag_and_rust_toolchain(); - starknet_compile( - self.get_source_path(), - tag_override, - cargo_nightly_arg, - &mut vec![], - ) - } - } - } +pub trait FeatureContractTrait { + fn get_class(&self) -> ContractClass; + fn get_runnable_class(&self) -> RunnableCompiledClass; /// Fetch PC locations from the compiled contract to compute the expected PC locations in the /// traceback. Computation is not robust, but as long as the cairo function itself is not @@ -365,7 +29,7 @@ impl FeatureContract { entry_point_type: EntryPointType, ) -> EntryPointOffset { match self.get_runnable_class() { - RunnableContractClass::V0(class) => { + RunnableCompiledClass::V0(class) => { class .entry_points_by_type .get(&entry_point_type) @@ -375,32 +39,28 @@ impl FeatureContract { .unwrap() .offset } - RunnableContractClass::V1(class) => { + RunnableCompiledClass::V1(class) => { class .entry_points_by_type - .get_entry_point(&CallEntryPoint { + .get_entry_point(&EntryPointTypeAndSelector { entry_point_type, entry_point_selector, - ..Default::default() }) .unwrap() .offset } #[cfg(feature = "cairo_native")] - RunnableContractClass::V1Native(_) => { + RunnableCompiledClass::V1Native(_) => { panic!("Not implemented for cairo native contracts") } } } - pub fn get_entry_point_offset( - &self, - entry_point_selector: EntryPointSelector, - ) -> EntryPointOffset { + fn get_entry_point_offset(&self, entry_point_selector: EntryPointSelector) -> EntryPointOffset { self.get_offset(entry_point_selector, EntryPointType::External) } - pub fn get_ctor_offset( + fn get_ctor_offset( &self, entry_point_selector: Option, ) -> EntryPointOffset { @@ -408,23 +68,67 @@ impl FeatureContract { entry_point_selector.unwrap_or(selector_from_name(CONSTRUCTOR_ENTRY_POINT_NAME)); self.get_offset(selector, EntryPointType::Constructor) } +} - pub fn all_contracts() -> impl Iterator { - // EnumIter iterates over all variants with Default::default() as the cairo - // version. - Self::iter().flat_map(|contract| { - if contract.has_two_versions() { - let mut other_contract = contract; - other_contract.set_cairo_version(contract.cairo_version().other()); - vec![contract, other_contract].into_iter() - } else { - vec![contract].into_iter() +impl FeatureContractTrait for FeatureContract { + fn get_class(&self) -> ContractClass { + match self.cairo_version() { + CairoVersion::Cairo0 => { + ContractClass::V0(DeprecatedContractClass::from_file(&self.get_compiled_path())) + } + CairoVersion::Cairo1(RunnableCairo1::Casm) => ContractClass::V1(( + CasmContractClass::from_file(&self.get_compiled_path()), + self.get_sierra_version(), + )), + #[cfg(feature = "cairo_native")] + CairoVersion::Cairo1(RunnableCairo1::Native) => { + panic!("Native contracts are not supported by this function.") } - }) + } + } + + fn get_runnable_class(&self) -> RunnableCompiledClass { + #[cfg(feature = "cairo_native")] + if CairoVersion::Cairo1(RunnableCairo1::Native) == self.cairo_version() { + let native_contract_class = + NativeCompiledClassV1::compile_or_get_cached(&self.get_compiled_path()); + return RunnableCompiledClass::V1Native(native_contract_class); + } + + self.get_class().try_into().unwrap() } +} - pub fn all_feature_contracts() -> impl Iterator { - // ERC20 is a special case - not in the feature_contracts directory. - Self::all_contracts().filter(|contract| !matches!(contract, Self::ERC20(_))) +/// The information needed to test a [FeatureContract]. +pub struct FeatureContractData { + pub class_hash: ClassHash, + pub runnable_class: RunnableCompiledClass, + pub require_funding: bool, + integer_base: u32, +} +impl FeatureContractData { + pub fn get_instance_address(&self, instance: u16) -> ContractAddress { + // If a test requires overriding the contract address, replace storing `integer_base` in the + // struct with storing a callback function that computes the address. + // A test will then be able to override the callback function to return the desired address. + FeatureContract::instance_address(self.integer_base, instance.into()) + } +} + +impl From for FeatureContractData { + fn from(contract: FeatureContract) -> Self { + let require_funding = matches!( + contract, + FeatureContract::AccountWithLongValidate(_) + | FeatureContract::AccountWithoutValidations(_) + | FeatureContract::FaultyAccount(_) + ); + + Self { + class_hash: contract.get_class_hash(), + runnable_class: contract.get_runnable_class(), + require_funding, + integer_base: contract.get_integer_base(), + } } } diff --git a/crates/blockifier/src/test_utils/declare.rs b/crates/blockifier/src/test_utils/declare.rs deleted file mode 100644 index aaaf9b8e24a..00000000000 --- a/crates/blockifier/src/test_utils/declare.rs +++ /dev/null @@ -1,10 +0,0 @@ -use starknet_api::contract_class::ClassInfo; -use starknet_api::test_utils::declare::{executable_declare_tx, DeclareTxArgs}; - -use crate::transaction::account_transaction::AccountTransaction; - -pub fn declare_tx(declare_tx_args: DeclareTxArgs, class_info: ClassInfo) -> AccountTransaction { - let declare_tx = executable_declare_tx(declare_tx_args, class_info); - - declare_tx.into() -} diff --git a/crates/blockifier/src/test_utils/deploy_account.rs b/crates/blockifier/src/test_utils/deploy_account.rs deleted file mode 100644 index e2d6ed36fee..00000000000 --- a/crates/blockifier/src/test_utils/deploy_account.rs +++ /dev/null @@ -1,13 +0,0 @@ -use starknet_api::test_utils::deploy_account::{executable_deploy_account_tx, DeployAccountTxArgs}; -use starknet_api::test_utils::NonceManager; - -use crate::transaction::account_transaction::AccountTransaction; - -pub fn deploy_account_tx( - deploy_tx_args: DeployAccountTxArgs, - nonce_manager: &mut NonceManager, -) -> AccountTransaction { - let deploy_account_tx = executable_deploy_account_tx(deploy_tx_args, nonce_manager); - - deploy_account_tx.into() -} diff --git a/crates/blockifier/src/test_utils/dict_state_reader.rs b/crates/blockifier/src/test_utils/dict_state_reader.rs index 469e6cbdb7d..16e3b3ed83f 100644 --- a/crates/blockifier/src/test_utils/dict_state_reader.rs +++ b/crates/blockifier/src/test_utils/dict_state_reader.rs @@ -4,7 +4,7 @@ use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; use starknet_api::state::StorageKey; use starknet_types_core::felt::Felt; -use crate::execution::contract_class::RunnableContractClass; +use crate::execution::contract_class::RunnableCompiledClass; use crate::state::cached_state::StorageEntry; use crate::state::errors::StateError; use crate::state::state_api::{StateReader, StateResult}; @@ -15,7 +15,7 @@ pub struct DictStateReader { pub storage_view: HashMap, pub address_to_nonce: HashMap, pub address_to_class_hash: HashMap, - pub class_hash_to_class: HashMap, + pub class_hash_to_class: HashMap, pub class_hash_to_compiled_class_hash: HashMap, } @@ -35,10 +35,7 @@ impl StateReader for DictStateReader { Ok(nonce) } - fn get_compiled_contract_class( - &self, - class_hash: ClassHash, - ) -> StateResult { + fn get_compiled_class(&self, class_hash: ClassHash) -> StateResult { let contract_class = self.class_hash_to_class.get(&class_hash).cloned(); match contract_class { Some(contract_class) => Ok(contract_class), diff --git a/crates/blockifier/src/test_utils/initial_test_state.rs b/crates/blockifier/src/test_utils/initial_test_state.rs index 094fdca6ad7..32e6b1f3f70 100644 --- a/crates/blockifier/src/test_utils/initial_test_state.rs +++ b/crates/blockifier/src/test_utils/initial_test_state.rs @@ -1,6 +1,9 @@ use std::collections::HashMap; +use blockifier_test_utils::cairo_versions::CairoVersion; +use blockifier_test_utils::contracts::FeatureContract; use starknet_api::abi::abi_utils::get_fee_token_var_address; +use starknet_api::block::FeeType; use starknet_api::core::ContractAddress; use starknet_api::felt; use starknet_api::transaction::fields::Fee; @@ -8,10 +11,8 @@ use strum::IntoEnumIterator; use crate::context::ChainInfo; use crate::state::cached_state::CachedState; -use crate::test_utils::contracts::FeatureContract; +use crate::test_utils::contracts::{FeatureContractData, FeatureContractTrait}; use crate::test_utils::dict_state_reader::DictStateReader; -use crate::test_utils::CairoVersion; -use crate::transaction::objects::FeeType; /// Utility to fund an account. pub fn fund_account( @@ -41,7 +42,7 @@ pub fn fund_account( pub fn test_state_inner( chain_info: &ChainInfo, initial_balances: Fee, - contract_instances: &[(FeatureContract, u16)], + contract_instances: &[(FeatureContractData, u16)], erc20_contract_version: CairoVersion, ) -> CachedState { let mut class_hash_to_class = HashMap::new(); @@ -57,8 +58,8 @@ pub fn test_state_inner( // Set up the rest of the requested contracts. for (contract, n_instances) in contract_instances.iter() { - let class_hash = contract.get_class_hash(); - class_hash_to_class.insert(class_hash, contract.get_runnable_class()); + let class_hash = contract.class_hash; + class_hash_to_class.insert(class_hash, contract.runnable_class.clone()); for instance in 0..*n_instances { let instance_address = contract.get_instance_address(instance); address_to_class_hash.insert(instance_address, class_hash); @@ -72,13 +73,8 @@ pub fn test_state_inner( for (contract, n_instances) in contract_instances.iter() { for instance in 0..*n_instances { let instance_address = contract.get_instance_address(instance); - match contract { - FeatureContract::AccountWithLongValidate(_) - | FeatureContract::AccountWithoutValidations(_) - | FeatureContract::FaultyAccount(_) => { - fund_account(chain_info, instance_address, initial_balances, &mut state_reader); - } - _ => (), + if contract.require_funding { + fund_account(chain_info, instance_address, initial_balances, &mut state_reader); } } } @@ -90,6 +86,18 @@ pub fn test_state( chain_info: &ChainInfo, initial_balances: Fee, contract_instances: &[(FeatureContract, u16)], +) -> CachedState { + let contract_instances_vec: Vec<(FeatureContractData, u16)> = contract_instances + .iter() + .map(|(feature_contract, i)| ((*feature_contract).into(), *i)) + .collect(); + test_state_ex(chain_info, initial_balances, &contract_instances_vec[..]) +} + +pub fn test_state_ex( + chain_info: &ChainInfo, + initial_balances: Fee, + contract_instances: &[(FeatureContractData, u16)], ) -> CachedState { test_state_inner(chain_info, initial_balances, contract_instances, CairoVersion::Cairo0) } diff --git a/crates/blockifier/src/test_utils/invoke.rs b/crates/blockifier/src/test_utils/invoke.rs deleted file mode 100644 index 569ca98861d..00000000000 --- a/crates/blockifier/src/test_utils/invoke.rs +++ /dev/null @@ -1,14 +0,0 @@ -use starknet_api::executable_transaction::AccountTransaction as ExecutableTransaction; -use starknet_api::test_utils::invoke::{executable_invoke_tx, InvokeTxArgs}; - -use crate::transaction::account_transaction::AccountTransaction; - -pub fn invoke_tx(invoke_args: InvokeTxArgs) -> AccountTransaction { - let only_query = invoke_args.only_query; - let invoke_tx = ExecutableTransaction::Invoke(executable_invoke_tx(invoke_args)); - - match only_query { - true => AccountTransaction::new_for_query(invoke_tx), - false => AccountTransaction::new(invoke_tx), - } -} diff --git a/crates/blockifier/src/test_utils/l1_handler.rs b/crates/blockifier/src/test_utils/l1_handler.rs index a57d08b8b6a..20116839d64 100644 --- a/crates/blockifier/src/test_utils/l1_handler.rs +++ b/crates/blockifier/src/test_utils/l1_handler.rs @@ -4,7 +4,6 @@ use starknet_api::core::ContractAddress; use starknet_api::executable_transaction::L1HandlerTransaction; use starknet_api::test_utils::l1_handler::{executable_l1_handler_tx, L1HandlerTxArgs}; use starknet_api::transaction::fields::Fee; -use starknet_api::transaction::TransactionVersion; use starknet_types_core::felt::Felt; pub fn l1handler_tx(l1_fee: Fee, contract_address: ContractAddress) -> L1HandlerTransaction { @@ -15,7 +14,6 @@ pub fn l1handler_tx(l1_fee: Fee, contract_address: ContractAddress) -> L1Handler ]; executable_l1_handler_tx(L1HandlerTxArgs { - version: TransactionVersion::ZERO, contract_address, entry_point_selector: selector_from_name("l1_handler_set_value"), calldata, diff --git a/crates/blockifier/src/test_utils/prices.rs b/crates/blockifier/src/test_utils/prices.rs index 47fba5e7eb6..91a6325b026 100644 --- a/crates/blockifier/src/test_utils/prices.rs +++ b/crates/blockifier/src/test_utils/prices.rs @@ -3,19 +3,24 @@ use std::sync::Arc; use cached::proc_macro::cached; use cairo_vm::vm::runners::cairo_runner::ExecutionResources; use starknet_api::abi::abi_utils::{get_fee_token_var_address, selector_from_name}; +use starknet_api::block::FeeType; use starknet_api::core::ContractAddress; +use starknet_api::execution_resources::GasAmount; use starknet_api::test_utils::invoke::InvokeTxArgs; use starknet_api::transaction::constants; use starknet_api::{calldata, felt}; use crate::context::BlockContext; use crate::execution::common_hints::ExecutionMode; -use crate::execution::entry_point::{CallEntryPoint, EntryPointExecutionContext}; +use crate::execution::entry_point::{ + CallEntryPoint, + EntryPointExecutionContext, + SierraGasRevertTracker, +}; use crate::state::state_api::State; use crate::test_utils::initial_test_state::test_state; use crate::test_utils::BALANCE; -use crate::transaction::objects::FeeType; -use crate::transaction::test_utils::account_invoke_tx; +use crate::transaction::test_utils::invoke_tx_with_default_flags; /// Enum for all resource costs. pub enum Prices { @@ -71,13 +76,17 @@ fn fee_transfer_resources( .execute( state, &mut EntryPointExecutionContext::new( - Arc::new(block_context.to_tx_context(&account_invoke_tx(InvokeTxArgs::default()))), + Arc::new( + block_context + .to_tx_context(&invoke_tx_with_default_flags(InvokeTxArgs::default())), + ), ExecutionMode::Execute, false, + // No need to limit gas in fee transfer. + SierraGasRevertTracker::new(GasAmount::MAX), ), &mut remaining_gas, ) .unwrap() - .charged_resources - .vm_resources + .resources } diff --git a/crates/blockifier/src/test_utils/struct_impls.rs b/crates/blockifier/src/test_utils/struct_impls.rs index 581263a05ca..647eaeb2d38 100644 --- a/crates/blockifier/src/test_utils/struct_impls.rs +++ b/crates/blockifier/src/test_utils/struct_impls.rs @@ -4,58 +4,55 @@ use std::sync::Arc; #[cfg(feature = "cairo_native")] use std::sync::{LazyLock, RwLock}; +use blockifier_test_utils::contracts::get_raw_contract_class; use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass; #[cfg(feature = "cairo_native")] use cairo_lang_starknet_classes::contract_class::ContractClass as SierraContractClass; #[cfg(feature = "cairo_native")] use cairo_native::executor::AotContractExecutor; use serde_json::Value; -use starknet_api::block::{BlockNumber, BlockTimestamp, NonzeroGasPrice}; +use starknet_api::block::BlockInfo; use starknet_api::contract_address; -use starknet_api::core::{ChainId, ClassHash}; +#[cfg(feature = "cairo_native")] +use starknet_api::contract_class::SierraVersion; +use starknet_api::core::ClassHash; use starknet_api::deprecated_contract_class::ContractClass as DeprecatedContractClass; - -use super::{ - update_json_value, +use starknet_api::execution_resources::GasAmount; +use starknet_api::test_utils::{ + CHAIN_ID_FOR_TESTS, TEST_ERC20_CONTRACT_ADDRESS, TEST_ERC20_CONTRACT_ADDRESS2, - TEST_SEQUENCER_ADDRESS, }; -use crate::blockifier::block::{BlockInfo, GasPrices}; -use crate::bouncer::{BouncerConfig, BouncerWeights, BuiltinCount}; + +use crate::blockifier::config::{CairoNativeRunConfig, ContractClassManagerConfig}; +use crate::blockifier_versioned_constants::{ + GasCosts, + OsConstants, + VersionedConstants, + VERSIONED_CONSTANTS_LATEST_JSON, +}; +use crate::bouncer::{BouncerConfig, BouncerWeights}; use crate::context::{BlockContext, ChainInfo, FeeTokenAddresses, TransactionContext}; use crate::execution::call_info::{CallExecution, CallInfo, Retdata}; use crate::execution::common_hints::ExecutionMode; #[cfg(feature = "cairo_native")] -use crate::execution::contract_class::ContractClassV1; +use crate::execution::contract_class::CompiledClassV1; use crate::execution::entry_point::{ CallEntryPoint, EntryPointExecutionContext, EntryPointExecutionResult, + SierraGasRevertTracker, }; #[cfg(feature = "cairo_native")] -use crate::execution::native::contract_class::NativeContractClassV1; +use crate::execution::native::contract_class::NativeCompiledClassV1; +use crate::state::contract_class_manager::ContractClassManager; use crate::state::state_api::State; -use crate::test_utils::{ - get_raw_contract_class, - CURRENT_BLOCK_NUMBER, - CURRENT_BLOCK_TIMESTAMP, - DEFAULT_ETH_L1_DATA_GAS_PRICE, - DEFAULT_ETH_L1_GAS_PRICE, - DEFAULT_STRK_L1_DATA_GAS_PRICE, - DEFAULT_STRK_L1_GAS_PRICE, -}; +use crate::test_utils::update_json_value; use crate::transaction::objects::{ CurrentTransactionInfo, DeprecatedTransactionInfo, TransactionInfo, }; -use crate::versioned_constants::{ - GasCosts, - OsConstants, - VersionedConstants, - VERSIONED_CONSTANTS_LATEST_JSON, -}; impl CallEntryPoint { /// Executes the call directly, without account context. Limits the number of steps by resource @@ -66,24 +63,50 @@ impl CallEntryPoint { self.execute_directly_given_tx_info( state, TransactionInfo::Current(CurrentTransactionInfo::create_for_testing()), + None, limit_steps_by_resources, ExecutionMode::Execute, ) } + pub fn execute_directly_given_block_context( + self, + state: &mut dyn State, + block_context: BlockContext, + ) -> EntryPointExecutionResult { + // Do not limit steps by resources as we use default resources. + let limit_steps_by_resources = false; + let tx_context = TransactionContext { + block_context: Arc::new(block_context), + tx_info: TransactionInfo::Current(CurrentTransactionInfo::create_for_testing()), + }; + + let mut context = EntryPointExecutionContext::new( + Arc::new(tx_context), + ExecutionMode::Execute, + limit_steps_by_resources, + SierraGasRevertTracker::new(GasAmount(self.initial_gas)), + ); + let mut remaining_gas = self.initial_gas; + self.execute(state, &mut context, &mut remaining_gas) + } + pub fn execute_directly_given_tx_info( self, state: &mut dyn State, tx_info: TransactionInfo, + block_context: Option>, limit_steps_by_resources: bool, execution_mode: ExecutionMode, ) -> EntryPointExecutionResult { - let tx_context = - TransactionContext { block_context: BlockContext::create_for_testing(), tx_info }; + let block_context = + block_context.unwrap_or_else(|| Arc::new(BlockContext::create_for_testing())); + let tx_context = TransactionContext { block_context, tx_info }; let mut context = EntryPointExecutionContext::new( Arc::new(tx_context), execution_mode, limit_steps_by_resources, + SierraGasRevertTracker::new(GasAmount(self.initial_gas)), ); let mut remaining_gas = self.initial_gas; self.execute(state, &mut context, &mut remaining_gas) @@ -100,6 +123,7 @@ impl CallEntryPoint { state, // TODO(Yoni, 1/12/2024): change the default to V3. TransactionInfo::Deprecated(DeprecatedTransactionInfo::default()), + None, limit_steps_by_resources, ExecutionMode::Validate, ) @@ -137,7 +161,7 @@ impl GasCosts { impl ChainInfo { pub fn create_for_testing() -> Self { Self { - chain_id: ChainId::create_for_testing(), + chain_id: CHAIN_ID_FOR_TESTS.clone(), fee_token_addresses: FeeTokenAddresses { eth_fee_token_address: contract_address!(TEST_ERC20_CONTRACT_ADDRESS), strk_fee_token_address: contract_address!(TEST_ERC20_CONTRACT_ADDRESS2), @@ -146,37 +170,6 @@ impl ChainInfo { } } -impl BlockInfo { - pub fn create_for_testing() -> Self { - Self { - block_number: BlockNumber(CURRENT_BLOCK_NUMBER), - block_timestamp: BlockTimestamp(CURRENT_BLOCK_TIMESTAMP), - sequencer_address: contract_address!(TEST_SEQUENCER_ADDRESS), - gas_prices: GasPrices::new( - DEFAULT_ETH_L1_GAS_PRICE, - DEFAULT_STRK_L1_GAS_PRICE, - DEFAULT_ETH_L1_DATA_GAS_PRICE, - DEFAULT_STRK_L1_DATA_GAS_PRICE, - NonzeroGasPrice::new( - VersionedConstants::latest_constants() - .convert_l1_to_l2_gas_price_round_up(DEFAULT_ETH_L1_GAS_PRICE.into()), - ) - .unwrap(), - NonzeroGasPrice::new( - VersionedConstants::latest_constants() - .convert_l1_to_l2_gas_price_round_up(DEFAULT_STRK_L1_GAS_PRICE.into()), - ) - .unwrap(), - ), - use_kzg_da: false, - } - } - - pub fn create_for_testing_with_kzg(use_kzg_da: bool) -> Self { - Self { use_kzg_da, ..Self::create_for_testing() } - } -} - impl BlockContext { pub fn create_for_testing() -> Self { Self { @@ -222,6 +215,15 @@ impl CallExecution { } } +impl ContractClassManager { + pub fn create_for_testing(native_config: CairoNativeRunConfig) -> Self { + let config = ContractClassManagerConfig { + cairo_native_run_config: native_config, + ..Default::default() + }; + ContractClassManager::start(config) + } +} // Contract loaders. // TODO(Noa): Consider using PathBuf. @@ -235,19 +237,13 @@ pub trait LoadContractFromFile: serde::de::DeserializeOwned { impl LoadContractFromFile for CasmContractClass {} impl LoadContractFromFile for DeprecatedContractClass {} -impl BouncerWeights { - pub fn create_for_testing(builtin_count: BuiltinCount) -> Self { - Self { builtin_count, ..Self::empty() } - } -} - #[cfg(feature = "cairo_native")] -static COMPILED_NATIVE_CONTRACT_CACHE: LazyLock>> = +static COMPILED_NATIVE_CONTRACT_CACHE: LazyLock>> = LazyLock::new(|| RwLock::new(HashMap::new())); #[cfg(feature = "cairo_native")] -impl NativeContractClassV1 { - /// Convenience function to construct a NativeContractClassV1 from a raw contract class. +impl NativeCompiledClassV1 { + /// Convenience function to construct a NativeCompiledClassV1 from a raw contract class. /// If control over the compilation is desired use [Self::new] instead. pub fn try_from_json_string(raw_sierra_contract_class: &str) -> Self { let sierra_contract_class: SierraContractClass = @@ -257,9 +253,20 @@ impl NativeContractClassV1 { .extract_sierra_program() .expect("Cannot extract sierra program from sierra contract class"); + let sierra_version_values = sierra_contract_class + .sierra_program + .iter() + .take(3) + .map(|x| x.value.clone()) + .collect::>(); + + let sierra_version = SierraVersion::extract_from_program(&sierra_version_values) + .expect("Cannot extract sierra version from sierra program"); + let executor = AotContractExecutor::new( &sierra_program, &sierra_contract_class.entry_points_by_type, + sierra_version.clone().into(), cairo_native::OptLevel::Default, ) .expect("Cannot compile sierra into native"); @@ -268,10 +275,10 @@ impl NativeContractClassV1 { let casm_contract_class = CasmContractClass::from_contract_class(sierra_contract_class, false, usize::MAX) .expect("Cannot compile sierra contract class into casm contract class"); - let casm = ContractClassV1::try_from(casm_contract_class) - .expect("Cannot get ContractClassV1 from CasmContractClass"); + let casm = CompiledClassV1::try_from((casm_contract_class, sierra_version)) + .expect("Cannot get CompiledClassV1 from CasmContractClass"); - NativeContractClassV1::new(executor, casm) + NativeCompiledClassV1::new(executor, casm) } pub fn from_file(contract_path: &str) -> Self { @@ -287,7 +294,7 @@ impl NativeContractClassV1 { } std::mem::drop(cache); - let class = NativeContractClassV1::from_file(path); + let class = NativeCompiledClassV1::from_file(path); let mut cache = COMPILED_NATIVE_CONTRACT_CACHE.write().unwrap(); cache.insert(path.to_string(), class.clone()); class diff --git a/crates/blockifier/src/test_utils/syscall.rs b/crates/blockifier/src/test_utils/syscall.rs index 81db2822d65..bcd3407d161 100644 --- a/crates/blockifier/src/test_utils/syscall.rs +++ b/crates/blockifier/src/test_utils/syscall.rs @@ -1,7 +1,8 @@ +use blockifier_test_utils::calldata::create_calldata; use starknet_api::felt; use starknet_api::transaction::fields::Calldata; -use crate::test_utils::{create_calldata, CompilerBasedVersion}; +use crate::test_utils::CompilerBasedVersion; /// Returns the calldata for N recursive call contract syscalls, where N is the length of versions. /// versions determines the cairo version of the called contract in each recursive call. Final call diff --git a/crates/blockifier/src/test_utils/test_templates.rs b/crates/blockifier/src/test_utils/test_templates.rs new file mode 100644 index 00000000000..310e069a773 --- /dev/null +++ b/crates/blockifier/src/test_utils/test_templates.rs @@ -0,0 +1,89 @@ +#[cfg(test)] +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; +use rstest::rstest; +use rstest_reuse::{apply, template}; + +#[cfg(not(feature = "cairo_native"))] +#[template] +#[rstest] +fn cairo_version( + #[values(CairoVersion::Cairo0, CairoVersion::Cairo1(RunnableCairo1::Casm))] + cairo_version: CairoVersion, +) { +} + +#[cfg(feature = "cairo_native")] +#[template] +#[rstest] +fn cairo_version( + #[values( + CairoVersion::Cairo0, + CairoVersion::Cairo1(RunnableCairo1::Casm), + CairoVersion::Cairo1(RunnableCairo1::Native) + )] + cairo_version: CairoVersion, +) { +} + +#[cfg(not(feature = "cairo_native"))] +#[template] +#[rstest] +fn runnable_version(#[values(RunnableCairo1::Casm)] runnable_version: RunnableCairo1) {} + +#[cfg(feature = "cairo_native")] +#[template] +#[rstest] +fn runnable_version( + #[values(RunnableCairo1::Casm, RunnableCairo1::Native)] runnable_version: RunnableCairo1, +) { +} + +#[cfg(not(feature = "cairo_native"))] +#[template] +#[rstest] +fn two_cairo_versions( + #[values(CairoVersion::Cairo0, CairoVersion::Cairo1(RunnableCairo1::Casm))] + cairo_version1: CairoVersion, + #[values(CairoVersion::Cairo0, CairoVersion::Cairo1(RunnableCairo1::Casm))] + cairo_version2: CairoVersion, +) { +} + +#[cfg(feature = "cairo_native")] +#[template] +#[rstest] +fn two_cairo_versions( + #[values( + CairoVersion::Cairo0, + CairoVersion::Cairo1(RunnableCairo1::Casm), + CairoVersion::Cairo1(RunnableCairo1::Native) + )] + cairo_version1: CairoVersion, + #[values( + CairoVersion::Cairo0, + CairoVersion::Cairo1(RunnableCairo1::Casm), + CairoVersion::Cairo1(RunnableCairo1::Native) + )] + cairo_version2: CairoVersion, +) { +} + +// When creating a function using a template, every function name is slightly different to avoid +// having multiple functions with the same name in the same scope. This means that the fact that we +// do not use the template in the file it's in makes the compiler think it is an unused macro. +// To avoid this we created a dummy test that uses the template. + +#[apply(cairo_version)] +fn test_cairo_version(cairo_version: CairoVersion) { + println!("test {:?}", cairo_version); +} + +#[apply(two_cairo_versions)] +fn test_two_cairo_version(cairo_version1: CairoVersion, cairo_version2: CairoVersion) { + println!("test {:?} {:?}", cairo_version1, cairo_version2); +} + +#[apply(runnable_version)] +fn test_runnable_version(runnable_version: RunnableCairo1) { + println!("test {:?}", runnable_version); +} diff --git a/crates/blockifier/src/test_utils/transfers_generator.rs b/crates/blockifier/src/test_utils/transfers_generator.rs index 0915dc82f1b..4f70da02e9d 100644 --- a/crates/blockifier/src/test_utils/transfers_generator.rs +++ b/crates/blockifier/src/test_utils/transfers_generator.rs @@ -1,7 +1,11 @@ +use blockifier_test_utils::cairo_versions::CairoVersion; +use blockifier_test_utils::contracts::FeatureContract; use rand::rngs::StdRng; use rand::{Rng, SeedableRng}; use starknet_api::abi::abi_utils::selector_from_name; use starknet_api::core::ContractAddress; +use starknet_api::executable_transaction::AccountTransaction as ApiExecutableTransaction; +use starknet_api::test_utils::invoke::executable_invoke_tx; use starknet_api::test_utils::NonceManager; use starknet_api::transaction::constants::TRANSFER_ENTRY_POINT_NAME; use starknet_api::transaction::fields::Fee; @@ -10,20 +14,17 @@ use starknet_api::{calldata, felt, invoke_tx_args}; use starknet_types_core::felt::Felt; use crate::blockifier::config::{ConcurrencyConfig, TransactionExecutorConfig}; -use crate::blockifier::transaction_executor::TransactionExecutor; +use crate::blockifier::transaction_executor::{TransactionExecutor, DEFAULT_STACK_SIZE}; use crate::context::{BlockContext, ChainInfo}; -use crate::test_utils::contracts::FeatureContract; use crate::test_utils::dict_state_reader::DictStateReader; use crate::test_utils::initial_test_state::test_state; -use crate::test_utils::invoke::invoke_tx; -use crate::test_utils::{CairoVersion, BALANCE, MAX_FEE}; +use crate::test_utils::{RunnableCairo1, BALANCE, MAX_FEE}; use crate::transaction::account_transaction::AccountTransaction; use crate::transaction::transaction_execution::Transaction; - const N_ACCOUNTS: u16 = 10000; const N_TXS: usize = 1000; const RANDOMIZATION_SEED: u64 = 0; -const CAIRO_VERSION: CairoVersion = CairoVersion::Cairo0; +const CAIRO_VERSION: CairoVersion = CairoVersion::Cairo1(RunnableCairo1::Casm); const TRANSACTION_VERSION: TransactionVersion = TransactionVersion(Felt::THREE); const RECIPIENT_GENERATOR_TYPE: RecipientGeneratorType = RecipientGeneratorType::RoundRobin; @@ -37,10 +38,12 @@ pub struct TransfersGeneratorConfig { pub tx_version: TransactionVersion, pub recipient_generator_type: RecipientGeneratorType, pub concurrency_config: ConcurrencyConfig, + pub stack_size: usize, } impl Default for TransfersGeneratorConfig { fn default() -> Self { + let concurrency_enabled = true; Self { n_accounts: N_ACCOUNTS, balance: Fee(BALANCE.0 * 1000), @@ -50,7 +53,8 @@ impl Default for TransfersGeneratorConfig { cairo_version: CAIRO_VERSION, tx_version: TRANSACTION_VERSION, recipient_generator_type: RECIPIENT_GENERATOR_TYPE, - concurrency_config: ConcurrencyConfig::create_for_testing(false), + concurrency_config: ConcurrencyConfig::create_for_testing(concurrency_enabled), + stack_size: DEFAULT_STACK_SIZE, } } } @@ -79,8 +83,10 @@ impl TransfersGenerator { let chain_info = block_context.chain_info().clone(); let state = test_state(&chain_info, config.balance, &[(account_contract, config.n_accounts)]); - let executor_config = - TransactionExecutorConfig { concurrency_config: config.concurrency_config.clone() }; + let executor_config = TransactionExecutorConfig { + concurrency_config: config.concurrency_config.clone(), + stack_size: config.stack_size, + }; let executor = TransactionExecutor::new(state, block_context, executor_config); let account_addresses = (0..config.n_accounts) .map(|instance_id| account_contract.get_instance_address(instance_id)) @@ -143,13 +149,14 @@ impl TransfersGenerator { let recipient_address = self.get_next_recipient(); self.sender_index = (self.sender_index + 1) % self.account_addresses.len(); - let account_tx = self.generate_transfer(sender_address, recipient_address); + let tx = self.generate_transfer(sender_address, recipient_address); + let account_tx = AccountTransaction::new_for_sequencing(tx); txs.push(Transaction::Account(account_tx)); } let results = self.executor.execute_txs(&txs); assert_eq!(results.len(), self.config.n_txs); for result in results { - assert!(!result.unwrap().is_reverted()); + assert!(!result.unwrap().0.is_reverted()); } // TODO(Avi, 01/06/2024): Run the same transactions concurrently on a new state and compare // the state diffs. @@ -159,7 +166,7 @@ impl TransfersGenerator { &mut self, sender_address: ContractAddress, recipient_address: ContractAddress, - ) -> AccountTransaction { + ) -> ApiExecutableTransaction { let nonce = self.nonce_manager.next(sender_address); let entry_point_selector = selector_from_name(TRANSFER_ENTRY_POINT_NAME); @@ -180,7 +187,7 @@ impl TransfersGenerator { felt!(0_u8) // Calldata: msb amount. ]; - invoke_tx(invoke_tx_args! { + executable_invoke_tx(invoke_tx_args! { max_fee: self.config.max_fee, sender_address, calldata: execute_calldata, diff --git a/crates/blockifier/src/transaction/account_transaction.rs b/crates/blockifier/src/transaction/account_transaction.rs index a4b245dd0d3..f255a48f724 100644 --- a/crates/blockifier/src/transaction/account_transaction.rs +++ b/crates/blockifier/src/transaction/account_transaction.rs @@ -6,12 +6,8 @@ use starknet_api::calldata; use starknet_api::contract_class::EntryPointType; use starknet_api::core::{ClassHash, ContractAddress, EntryPointSelector, Nonce}; use starknet_api::data_availability::DataAvailabilityMode; -use starknet_api::executable_transaction::{ - AccountTransaction as Transaction, - DeclareTransaction, - DeployAccountTransaction, - InvokeTransaction, -}; +use starknet_api::executable_transaction::AccountTransaction as Transaction; +use starknet_api::execution_resources::GasAmount; use starknet_api::transaction::fields::Resource::{L1DataGas, L1Gas, L2Gas}; use starknet_api::transaction::fields::{ AccountDeploymentData, @@ -26,10 +22,17 @@ use starknet_api::transaction::fields::{ use starknet_api::transaction::{constants, TransactionHash, TransactionVersion}; use starknet_types_core::felt::Felt; -use crate::context::{BlockContext, TransactionContext}; +use super::errors::ResourceBoundsError; +use crate::context::{BlockContext, GasCounter, TransactionContext}; use crate::execution::call_info::CallInfo; -use crate::execution::contract_class::RunnableContractClass; -use crate::execution::entry_point::{CallEntryPoint, CallType, EntryPointExecutionContext}; +use crate::execution::common_hints::ExecutionMode; +use crate::execution::contract_class::RunnableCompiledClass; +use crate::execution::entry_point::{ + CallEntryPoint, + CallType, + EntryPointExecutionContext, + SierraGasRevertTracker, +}; use crate::execution::stack_trace::{ extract_trailing_cairo1_revert_trace, gen_tx_execution_error_trace, @@ -40,11 +43,12 @@ use crate::fee::fee_utils::{ get_fee_by_gas_vector, get_sequencer_balance_keys, verify_can_pay_committed_bounds, + GasVectorToL1GasForFee, }; use crate::fee::gas_usage::estimate_minimal_gas_vector; use crate::fee::receipt::TransactionReceipt; use crate::retdata; -use crate::state::cached_state::{StateChanges, TransactionalState}; +use crate::state::cached_state::{StateCache, TransactionalState}; use crate::state::state_api::{State, StateReader, UpdatableState}; use crate::transaction::errors::{ TransactionExecutionError, @@ -64,9 +68,9 @@ use crate::transaction::objects::{ }; use crate::transaction::transaction_types::TransactionType; use crate::transaction::transactions::{ + enforce_fee, Executable, ExecutableTransaction, - ExecutionFlags, ValidatableTransaction, }; @@ -82,11 +86,25 @@ mod flavors_test; #[path = "post_execution_test.rs"] mod post_execution_test; +#[derive(Clone, Debug, derive_more::From)] +pub struct ExecutionFlags { + pub only_query: bool, + pub charge_fee: bool, + pub validate: bool, + pub strict_nonce_check: bool, +} + +impl Default for ExecutionFlags { + fn default() -> Self { + Self { only_query: false, charge_fee: true, validate: true, strict_nonce_check: true } + } +} + /// Represents a paid Starknet transaction. #[derive(Clone, Debug, derive_more::From)] pub struct AccountTransaction { pub tx: Transaction, - only_query: bool, + pub execution_flags: ExecutionFlags, } // TODO(AvivG): create additional macro that returns a reference. macro_rules! implement_tx_getter_calls { @@ -97,30 +115,6 @@ macro_rules! implement_tx_getter_calls { }; } -impl From for AccountTransaction { - fn from(tx: Transaction) -> Self { - Self::new(tx) - } -} - -impl From for AccountTransaction { - fn from(tx: DeclareTransaction) -> Self { - Transaction::Declare(tx).into() - } -} - -impl From for AccountTransaction { - fn from(tx: DeployAccountTransaction) -> Self { - Transaction::DeployAccount(tx).into() - } -} - -impl From for AccountTransaction { - fn from(tx: InvokeTransaction) -> Self { - Transaction::Invoke(tx).into() - } -} - impl HasRelatedFeeType for AccountTransaction { fn version(&self) -> TransactionVersion { self.tx.version() @@ -144,12 +138,18 @@ impl AccountTransaction { (paymaster_data, PaymasterData) ); - pub fn new(tx: starknet_api::executable_transaction::AccountTransaction) -> Self { - AccountTransaction { tx, only_query: false } + pub fn new_with_default_flags(tx: Transaction) -> Self { + Self { tx, execution_flags: ExecutionFlags::default() } } - pub fn new_for_query(tx: starknet_api::executable_transaction::AccountTransaction) -> Self { - AccountTransaction { tx, only_query: true } + pub fn new_for_sequencing(tx: Transaction) -> Self { + let execution_flags = ExecutionFlags { + only_query: false, + charge_fee: enforce_fee(&tx, false), + validate: true, + strict_nonce_check: true, + }; + AccountTransaction { tx, execution_flags } } pub fn class_hash(&self) -> Option { @@ -253,13 +253,11 @@ impl AccountTransaction { &self, state: &mut S, tx_context: &TransactionContext, - charge_fee: bool, - strict_nonce_check: bool, ) -> TransactionPreValidationResult<()> { let tx_info = &tx_context.tx_info; - Self::handle_nonce(state, tx_info, strict_nonce_check)?; + Self::handle_nonce(state, tx_info, self.execution_flags.strict_nonce_check)?; - if charge_fee { + if self.execution_flags.charge_fee { self.check_fee_bounds(tx_context)?; verify_can_pay_committed_bounds(state, tx_context)?; @@ -272,7 +270,6 @@ impl AccountTransaction { &self, tx_context: &TransactionContext, ) -> TransactionPreValidationResult<()> { - // TODO(Aner): seprate to cases based on context.resource_bounds type let minimal_gas_amount_vector = estimate_minimal_gas_vector( &tx_context.block_context, self, @@ -287,8 +284,11 @@ impl AccountTransaction { ValidResourceBounds::L1Gas(l1_gas_resource_bounds) => vec![( L1Gas, l1_gas_resource_bounds, - minimal_gas_amount_vector.to_discounted_l1_gas(tx_context.get_gas_prices()), - block_info.gas_prices.get_l1_gas_price_by_fee_type(fee_type), + minimal_gas_amount_vector.to_l1_gas_for_fee( + tx_context.get_gas_prices(), + &tx_context.block_context.versioned_constants, + ), + block_info.gas_prices.l1_gas_price(fee_type), )], ValidResourceBounds::AllResources(AllResourceBounds { l1_gas: l1_gas_resource_bounds, @@ -296,7 +296,7 @@ impl AccountTransaction { l1_data_gas: l1_data_gas_resource_bounds, }) => { let GasPriceVector { l1_gas_price, l1_data_gas_price, l2_gas_price } = - block_info.gas_prices.get_gas_prices_by_fee_type(fee_type); + block_info.gas_prices.gas_price_vector(fee_type); vec![ ( L1Gas, @@ -319,26 +319,37 @@ impl AccountTransaction { ] } }; - for (resource, resource_bounds, minimal_gas_amount, actual_gas_price) in - resources_amount_tuple - { - // TODO(Aner): refactor to indicate both amount and price are too low. - // TODO(Aner): refactor to return all amounts that are too low. - if minimal_gas_amount > resource_bounds.max_amount { - return Err(TransactionFeeError::MaxGasAmountTooLow { - resource, - max_gas_amount: resource_bounds.max_amount, - minimal_gas_amount, - })?; - } - // TODO(Aner): refactor to return all prices that are too low. - if resource_bounds.max_price_per_unit < actual_gas_price.get() { - return Err(TransactionFeeError::MaxGasPriceTooLow { - resource, - max_gas_price: resource_bounds.max_price_per_unit, - actual_gas_price: actual_gas_price.into(), - })?; - } + let insufficiencies = resources_amount_tuple + .iter() + .flat_map( + |(resource, resource_bounds, minimal_gas_amount, actual_gas_price)| { + let mut insufficiencies_resource = vec![]; + if minimal_gas_amount > &resource_bounds.max_amount { + insufficiencies_resource.push( + ResourceBoundsError::MaxGasAmountTooLow { + resource: *resource, + max_gas_amount: resource_bounds.max_amount, + minimal_gas_amount: *minimal_gas_amount, + }, + ); + } + if resource_bounds.max_price_per_unit < actual_gas_price.get() { + insufficiencies_resource.push( + ResourceBoundsError::MaxGasPriceTooLow { + resource: *resource, + max_gas_price: resource_bounds.max_price_per_unit, + actual_gas_price: (*actual_gas_price).into(), + }, + ); + } + insufficiencies_resource + }, + ) + .collect::>(); + if !insufficiencies.is_empty() { + return Err(TransactionFeeError::InsufficientResourceBounds { + errors: insufficiencies, + })?; } } TransactionInfo::Deprecated(context) => { @@ -346,7 +357,9 @@ impl AccountTransaction { let min_fee = get_fee_by_gas_vector(block_info, minimal_gas_amount_vector, fee_type); if max_fee < min_fee { - return Err(TransactionFeeError::MaxFeeTooLow { min_fee, max_fee })?; + return Err(TransactionPreValidationError::TransactionFeeError( + TransactionFeeError::MaxFeeTooLow { min_fee, max_fee }, + )); } } }; @@ -384,12 +397,17 @@ impl AccountTransaction { &self, state: &mut dyn State, tx_context: Arc, - remaining_gas: &mut u64, - validate: bool, - limit_steps_by_resources: bool, + remaining_gas: &mut GasCounter, ) -> TransactionExecutionResult> { - if validate { - self.validate_tx(state, tx_context, remaining_gas, limit_steps_by_resources) + if self.execution_flags.validate { + let remaining_validation_gas = &mut remaining_gas.limit_usage( + tx_context.block_context.versioned_constants.os_constants.validate_max_sierra_gas, + ); + Ok(self.validate_tx(state, tx_context, remaining_validation_gas)?.inspect( + |call_info| { + remaining_gas.subtract_used_gas(call_info); + }, + )) } else { Ok(None) } @@ -456,7 +474,7 @@ impl AccountTransaction { // The fee contains the cost of running this transfer, and the token contract is // well known to the sequencer, so there is no need to limit its run. let mut remaining_gas_for_fee_transfer = - block_context.versioned_constants.os_constants.gas_costs.default_initial_gas_cost; + block_context.versioned_constants.os_constants.gas_costs.base.default_initial_gas_cost; let fee_transfer_call = CallEntryPoint { class_hash: None, code_address: None, @@ -473,7 +491,11 @@ impl AccountTransaction { initial_gas: remaining_gas_for_fee_transfer, }; - let mut context = EntryPointExecutionContext::new_invoke(tx_context, true); + let mut context = EntryPointExecutionContext::new_invoke( + tx_context, + true, + SierraGasRevertTracker::new(GasAmount(remaining_gas_for_fee_transfer)), + ); Ok(fee_transfer_call .execute(state, &mut context, &mut remaining_gas_for_fee_transfer) @@ -516,49 +538,61 @@ impl AccountTransaction { &self, state: &mut S, context: &mut EntryPointExecutionContext, - remaining_gas: &mut u64, + remaining_gas: &mut GasCounter, ) -> TransactionExecutionResult> { - match &self.tx { - Transaction::Declare(tx) => tx.run_execute(state, context, remaining_gas), - Transaction::DeployAccount(tx) => tx.run_execute(state, context, remaining_gas), - Transaction::Invoke(tx) => tx.run_execute(state, context, remaining_gas), - } + let remaining_execution_gas = &mut remaining_gas + .limit_usage(context.tx_context.sierra_gas_limit(&context.execution_mode)); + Ok(match &self.tx { + Transaction::Declare(tx) => tx.run_execute(state, context, remaining_execution_gas), + Transaction::DeployAccount(tx) => { + tx.run_execute(state, context, remaining_execution_gas) + } + Transaction::Invoke(tx) => tx.run_execute(state, context, remaining_execution_gas), + }? + .inspect(|call_info| { + remaining_gas.subtract_used_gas(call_info); + })) } fn run_non_revertible( &self, state: &mut TransactionalState<'_, S>, tx_context: Arc, - remaining_gas: &mut u64, - validate: bool, - charge_fee: bool, + remaining_gas: &mut GasCounter, ) -> TransactionExecutionResult { let validate_call_info: Option; let execute_call_info: Option; if matches!(&self.tx, Transaction::DeployAccount(_)) { // Handle `DeployAccount` transactions separately, due to different order of things. - // Also, the execution context required form the `DeployAccount` execute phase is + // Also, the execution context required for the `DeployAccount` execute phase is // validation context. - let mut execution_context = - EntryPointExecutionContext::new_validate(tx_context.clone(), charge_fee); - execute_call_info = self.run_execute(state, &mut execution_context, remaining_gas)?; - validate_call_info = self.handle_validate_tx( - state, + let mut execution_context = EntryPointExecutionContext::new_validate( tx_context.clone(), - remaining_gas, - validate, - charge_fee, - )?; + self.execution_flags.charge_fee, + // TODO(Dori): Reduce code dup (the gas usage limit is computed in run_execute). + // We initialize the revert gas tracker here for completeness - the value will not + // be used, as this tx is non-revertible. + SierraGasRevertTracker::new(GasAmount( + remaining_gas + .limit_usage(tx_context.sierra_gas_limit(&ExecutionMode::Validate)), + )), + ); + execute_call_info = self.run_execute(state, &mut execution_context, remaining_gas)?; + validate_call_info = + self.handle_validate_tx(state, tx_context.clone(), remaining_gas)?; } else { - let mut execution_context = - EntryPointExecutionContext::new_invoke(tx_context.clone(), charge_fee); - validate_call_info = self.handle_validate_tx( - state, + validate_call_info = + self.handle_validate_tx(state, tx_context.clone(), remaining_gas)?; + let mut execution_context = EntryPointExecutionContext::new_invoke( tx_context.clone(), - remaining_gas, - validate, - charge_fee, - )?; + self.execution_flags.charge_fee, + // TODO(Dori): Reduce code dup (the gas usage limit is computed in run_execute). + // We initialize the revert gas tracker here for completeness - the value will not + // be used, as this tx is non-revertible. + SierraGasRevertTracker::new(GasAmount( + remaining_gas.limit_usage(tx_context.sierra_gas_limit(&ExecutionMode::Execute)), + )), + ); execute_call_info = self.run_execute(state, &mut execution_context, remaining_gas)?; } @@ -571,10 +605,15 @@ impl AccountTransaction { &tx_context.block_context.versioned_constants, ), 0, + GasAmount(0), ); - let post_execution_report = - PostExecutionReport::new(state, &tx_context, &tx_receipt, charge_fee)?; + let post_execution_report = PostExecutionReport::new( + state, + &tx_context, + &tx_receipt, + self.execution_flags.charge_fee, + )?; match post_execution_report.error() { Some(error) => Err(error.into()), None => Ok(ValidateExecuteCallInfo::new_accepted( @@ -589,21 +628,20 @@ impl AccountTransaction { &self, state: &mut TransactionalState<'_, S>, tx_context: Arc, - remaining_gas: &mut u64, - validate: bool, - charge_fee: bool, + remaining_gas: &mut GasCounter, ) -> TransactionExecutionResult { - let mut execution_context = - EntryPointExecutionContext::new_invoke(tx_context.clone(), charge_fee); // Run the validation, and if execution later fails, only keep the validation diff. - let validate_call_info = self.handle_validate_tx( - state, - tx_context.clone(), - remaining_gas, - validate, - charge_fee, - )?; + let validate_call_info = + self.handle_validate_tx(state, tx_context.clone(), remaining_gas)?; + let mut execution_context = EntryPointExecutionContext::new_invoke( + tx_context.clone(), + self.execution_flags.charge_fee, + // TODO(Dori): Reduce code dup (the gas usage limit is computed in run_execute). + SierraGasRevertTracker::new(GasAmount( + remaining_gas.limit_usage(tx_context.sierra_gas_limit(&ExecutionMode::Execute)), + )), + ); let n_allotted_execution_steps = execution_context.subtract_validation_and_overhead_steps( &validate_call_info, &self.tx_type(), @@ -612,7 +650,7 @@ impl AccountTransaction { // Save the state changes resulting from running `validate_tx`, to be used later for // resource and fee calculation. - let validate_state_changes = state.get_actual_state_changes()?; + let validate_state_cache = state.borrow_updated_state_cache()?.clone(); // Create copies of state and validate_resources for the execution. // Both will be rolled back if the execution is reverted or committed upon success. @@ -622,19 +660,22 @@ impl AccountTransaction { self.run_execute(&mut execution_state, &mut execution_context, remaining_gas); // Pre-compute cost in case of revert. - // TODO(tzahi): add reverted_l2_gas to the receipt. let execution_steps_consumed = n_allotted_execution_steps - execution_context.n_remaining_steps(); - let revert_receipt = TransactionReceipt::from_account_tx( - self, - &tx_context, - &validate_state_changes, - CallInfo::summarize_many( - validate_call_info.iter(), - &tx_context.block_context.versioned_constants, - ), - execution_steps_consumed, - ); + // Get the receipt only in case of revert. + let get_revert_receipt = || { + TransactionReceipt::from_account_tx( + self, + &tx_context, + &validate_state_cache.to_state_diff(), + CallInfo::summarize_many( + validate_call_info.iter(), + &tx_context.block_context.versioned_constants, + ), + execution_steps_consumed, + execution_context.sierra_gas_revert_tracker.get_gas_consumed(), + ) + }; match execution_result { Ok(execute_call_info) => { @@ -643,22 +684,26 @@ impl AccountTransaction { let tx_receipt = TransactionReceipt::from_account_tx( self, &tx_context, - &StateChanges::merge(vec![ - validate_state_changes, - execution_state.get_actual_state_changes()?, - ]), + &StateCache::squash_state_diff( + vec![ + &validate_state_cache, + &execution_state.borrow_updated_state_cache()?.clone(), + ], + tx_context.block_context.versioned_constants.comprehensive_state_diff, + ), CallInfo::summarize_many( validate_call_info.iter().chain(execute_call_info.iter()), &tx_context.block_context.versioned_constants, ), 0, + GasAmount(0), ); // Post-execution checks. let post_execution_report = PostExecutionReport::new( &mut execution_state, &tx_context, &tx_receipt, - charge_fee, + self.execution_flags.charge_fee, )?; match post_execution_report.error() { Some(post_execution_error) => { @@ -667,13 +712,14 @@ impl AccountTransaction { // revert case, compute resources by adding consumed execution steps to // validation resources). execution_state.abort(); + let tx_receipt = TransactionReceipt { + fee: post_execution_report.recommended_fee(), + ..get_revert_receipt() + }; Ok(ValidateExecuteCallInfo::new_reverted( validate_call_info, post_execution_error.into(), - TransactionReceipt { - fee: post_execution_report.recommended_fee(), - ..revert_receipt - }, + tx_receipt, )) } None => { @@ -688,10 +734,15 @@ impl AccountTransaction { } } Err(execution_error) => { + let revert_receipt = get_revert_receipt(); // Error during execution. Revert, even if the error is sequencer-related. execution_state.abort(); - let post_execution_report = - PostExecutionReport::new(state, &tx_context, &revert_receipt, charge_fee)?; + let post_execution_report = PostExecutionReport::new( + state, + &tx_context, + &revert_receipt, + self.execution_flags.charge_fee, + )?; Ok(ValidateExecuteCallInfo::new_reverted( validate_call_info, gen_tx_execution_error_trace(&execution_error).into(), @@ -727,16 +778,14 @@ impl AccountTransaction { fn run_or_revert( &self, state: &mut TransactionalState<'_, S>, - remaining_gas: &mut u64, + remaining_gas: &mut GasCounter, tx_context: Arc, - validate: bool, - charge_fee: bool, ) -> TransactionExecutionResult { if self.is_non_revertible(&tx_context.tx_info) { - return self.run_non_revertible(state, tx_context, remaining_gas, validate, charge_fee); + return self.run_non_revertible(state, tx_context, remaining_gas); } - self.run_revertible(state, tx_context, remaining_gas, validate, charge_fee) + self.run_revertible(state, tx_context, remaining_gas) } } @@ -745,22 +794,16 @@ impl ExecutableTransaction for AccountTransaction { &self, state: &mut TransactionalState<'_, U>, block_context: &BlockContext, - execution_flags: ExecutionFlags, + concurrency_mode: bool, ) -> TransactionExecutionResult { let tx_context = Arc::new(block_context.to_tx_context(self)); self.verify_tx_version(tx_context.tx_info.version())?; // Nonce and fee check should be done before running user code. - let strict_nonce_check = true; - self.perform_pre_validation_stage( - state, - &tx_context, - execution_flags.charge_fee, - strict_nonce_check, - )?; + self.perform_pre_validation_stage(state, &tx_context)?; // Run validation and execution. - let mut remaining_gas = tx_context.initial_sierra_gas(); + let initial_gas = tx_context.initial_sierra_gas(); let ValidateExecuteCallInfo { validate_call_info, execute_call_info, @@ -772,19 +815,13 @@ impl ExecutableTransaction for AccountTransaction { resources: final_resources, gas: total_gas, }, - } = self.run_or_revert( - state, - &mut remaining_gas, - tx_context.clone(), - execution_flags.validate, - execution_flags.charge_fee, - )?; + } = self.run_or_revert(state, &mut GasCounter::new(initial_gas), tx_context.clone())?; let fee_transfer_call_info = Self::handle_fee( state, tx_context, final_fee, - execution_flags.charge_fee, - execution_flags.concurrency_mode, + self.execution_flags.charge_fee, + concurrency_mode, )?; let tx_execution_info = TransactionExecutionInfo { @@ -805,11 +842,7 @@ impl ExecutableTransaction for AccountTransaction { impl TransactionInfoCreator for AccountTransaction { fn create_tx_info(&self) -> TransactionInfo { - match &self.tx { - Transaction::Declare(tx) => tx.create_tx_info(self.only_query), - Transaction::DeployAccount(tx) => tx.create_tx_info(self.only_query), - Transaction::Invoke(tx) => tx.create_tx_info(self.only_query), - } + self.tx.create_tx_info(self.execution_flags.only_query) } } @@ -850,10 +883,13 @@ impl ValidatableTransaction for AccountTransaction { state: &mut dyn State, tx_context: Arc, remaining_gas: &mut u64, - limit_steps_by_resources: bool, ) -> TransactionExecutionResult> { - let mut context = - EntryPointExecutionContext::new_validate(tx_context, limit_steps_by_resources); + let limit_steps_by_resources = self.execution_flags.charge_fee; + let mut context = EntryPointExecutionContext::new_validate( + tx_context, + limit_steps_by_resources, + SierraGasRevertTracker::new(GasAmount(*remaining_gas)), + ); let tx_info = &context.tx_context.tx_info; if tx_info.is_v0() { return Ok(None); @@ -885,8 +921,8 @@ impl ValidatableTransaction for AccountTransaction { })?; // Validate return data. - let contract_class = state.get_compiled_contract_class(class_hash)?; - if is_cairo1(&contract_class) { + let compiled_class = state.get_compiled_class(class_hash)?; + if is_cairo1(&compiled_class) { // The account contract class is a Cairo 1.0 contract; the `validate` entry point should // return `VALID`. let expected_retdata = retdata![*constants::VALIDATE_RETDATA]; @@ -910,11 +946,11 @@ impl ValidatableTransaction for AccountTransaction { } } -pub fn is_cairo1(contract_class: &RunnableContractClass) -> bool { - match contract_class { - RunnableContractClass::V0(_) => false, - RunnableContractClass::V1(_) => true, +pub fn is_cairo1(compiled_class: &RunnableCompiledClass) -> bool { + match compiled_class { + RunnableCompiledClass::V0(_) => false, + RunnableCompiledClass::V1(_) => true, #[cfg(feature = "cairo_native")] - RunnableContractClass::V1Native(_) => true, + RunnableCompiledClass::V1Native(_) => true, } } diff --git a/crates/blockifier/src/transaction/account_transactions_test.rs b/crates/blockifier/src/transaction/account_transactions_test.rs index 5870922b473..de1e907ff3a 100644 --- a/crates/blockifier/src/transaction/account_transactions_test.rs +++ b/crates/blockifier/src/transaction/account_transactions_test.rs @@ -1,27 +1,42 @@ use std::collections::{HashMap, HashSet}; use std::sync::Arc; +use assert_matches::assert_matches; +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; +use blockifier_test_utils::calldata::{create_calldata, create_trivial_calldata}; +use blockifier_test_utils::contracts::FeatureContract; use cairo_vm::types::builtin_name::BuiltinName; use cairo_vm::vm::runners::cairo_runner::ResourceTracker; use num_traits::Inv; use pretty_assertions::{assert_eq, assert_ne}; use rstest::rstest; +use rstest_reuse::apply; use starknet_api::abi::abi_utils::{ get_fee_token_var_address, get_storage_var_address, selector_from_name, }; -use starknet_api::block::GasPrice; +use starknet_api::block::{FeeType, GasPrice}; use starknet_api::core::{calculate_contract_address, ClassHash, ContractAddress}; use starknet_api::executable_transaction::{ AccountTransaction as ApiExecutableTransaction, DeclareTransaction as ApiExecutableDeclareTransaction, }; -use starknet_api::execution_resources::GasAmount; +use starknet_api::execution_resources::{GasAmount, GasVector}; use starknet_api::hash::StarkHash; use starknet_api::state::StorageKey; -use starknet_api::test_utils::invoke::InvokeTxArgs; -use starknet_api::test_utils::NonceManager; +use starknet_api::test_utils::declare::executable_declare_tx; +use starknet_api::test_utils::deploy_account::executable_deploy_account_tx; +use starknet_api::test_utils::invoke::{executable_invoke_tx, InvokeTxArgs}; +use starknet_api::test_utils::{ + NonceManager, + DEFAULT_L1_DATA_GAS_MAX_AMOUNT, + DEFAULT_L1_GAS_AMOUNT, + DEFAULT_L2_GAS_MAX_AMOUNT, + DEFAULT_STRK_L1_GAS_PRICE, + DEFAULT_STRK_L2_GAS_PRICE, + MAX_FEE, +}; use starknet_api::transaction::constants::TRANSFER_ENTRY_POINT_NAME; use starknet_api::transaction::fields::{ AllResourceBounds, @@ -56,46 +71,44 @@ use crate::check_tx_execution_error_for_invalid_scenario; use crate::context::{BlockContext, TransactionContext}; use crate::execution::call_info::CallInfo; use crate::execution::contract_class::TrackedResource; -use crate::execution::entry_point::EntryPointExecutionContext; +use crate::execution::entry_point::{EntryPointExecutionContext, SierraGasRevertTracker}; use crate::execution::syscalls::SyscallSelector; -use crate::fee::fee_utils::{get_fee_by_gas_vector, get_sequencer_balance_keys}; +use crate::fee::fee_utils::{ + get_fee_by_gas_vector, + get_sequencer_balance_keys, + GasVectorToL1GasForFee, +}; use crate::fee::gas_usage::estimate_minimal_gas_vector; use crate::state::cached_state::{StateChangesCount, StateChangesCountForFee, TransactionalState}; use crate::state::state_api::{State, StateReader}; -use crate::test_utils::contracts::FeatureContract; -use crate::test_utils::declare::declare_tx; -use crate::test_utils::deploy_account::deploy_account_tx; +use crate::test_utils::contracts::FeatureContractTrait; use crate::test_utils::initial_test_state::{fund_account, test_state}; use crate::test_utils::syscall::build_recurse_calldata; +use crate::test_utils::test_templates::cairo_version; use crate::test_utils::{ - create_calldata, - create_trivial_calldata, - get_syscall_resources, + get_const_syscall_resources, get_tx_resources, - CairoVersion, CompilerBasedVersion, BALANCE, - DEFAULT_L1_DATA_GAS_MAX_AMOUNT, - DEFAULT_L1_GAS_AMOUNT, - DEFAULT_L2_GAS_MAX_AMOUNT, - DEFAULT_STRK_L1_DATA_GAS_PRICE, - DEFAULT_STRK_L1_GAS_PRICE, - DEFAULT_STRK_L2_GAS_PRICE, - MAX_FEE, }; -use crate::transaction::account_transaction::AccountTransaction; -use crate::transaction::objects::{FeeType, HasRelatedFeeType, TransactionInfoCreator}; +use crate::transaction::account_transaction::{ + AccountTransaction, + ExecutionFlags as AccountExecutionFlags, +}; +use crate::transaction::errors::{TransactionExecutionError, TransactionPreValidationError}; +use crate::transaction::objects::{HasRelatedFeeType, TransactionInfoCreator}; use crate::transaction::test_utils::{ - account_invoke_tx, all_resource_bounds, block_context, calculate_class_info_for_testing, create_account_tx_for_validate_test_nonce_0, create_all_resource_bounds, + create_gas_amount_bounds_with_default_price, create_test_init_data, default_all_resource_bounds, default_l1_resource_bounds, deploy_and_fund_account, + invoke_tx_with_default_flags, l1_resource_bounds, max_fee, run_invoke_tx, @@ -104,31 +117,35 @@ use crate::transaction::test_utils::{ INVALID, }; use crate::transaction::transaction_types::TransactionType; -use crate::transaction::transactions::{ExecutableTransaction, ExecutionFlags}; +use crate::transaction::transactions::ExecutableTransaction; use crate::utils::u64_from_usize; #[rstest] -fn test_circuit(block_context: BlockContext, default_all_resource_bounds: ValidResourceBounds) { - let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1); - let account = FeatureContract::AccountWithoutValidations(CairoVersion::Cairo1); - let chain_info = &block_context.chain_info; - let state = &mut test_state(chain_info, BALANCE, &[(test_contract, 1), (account, 1)]); - let test_contract_address = test_contract.get_instance_address(0); - let account_address = account.get_instance_address(0); - let mut nonce_manager = NonceManager::default(); +#[case::cairo1(CairoVersion::Cairo1(RunnableCairo1::Casm))] +#[cfg_attr( + feature = "cairo_native", + case::cairo1_native(CairoVersion::Cairo1(RunnableCairo1::Native)) +)] +fn test_circuit( + block_context: BlockContext, + default_all_resource_bounds: ValidResourceBounds, + #[case] cairo_version: CairoVersion, +) { + let TestInitData { mut state, account_address, contract_address, mut nonce_manager } = + create_test_init_data(&block_context.chain_info, cairo_version); // Invoke a function that changes the state and reverts. let tx_args = invoke_tx_args! { sender_address: account_address, calldata: create_calldata( - test_contract_address, + contract_address, "test_circuit", &[] ), nonce: nonce_manager.next(account_address) }; let tx_execution_info = run_invoke_tx( - state, + &mut state, &block_context, invoke_tx_args! { resource_bounds: default_all_resource_bounds, @@ -141,41 +158,49 @@ fn test_circuit(block_context: BlockContext, default_all_resource_bounds: ValidR } #[rstest] -fn test_rc96_holes(block_context: BlockContext, default_all_resource_bounds: ValidResourceBounds) { - let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1); - let account = FeatureContract::AccountWithoutValidations(CairoVersion::Cairo1); - let chain_info = &block_context.chain_info; - let state = &mut test_state(chain_info, BALANCE, &[(test_contract, 1), (account, 1)]); - let test_contract_address = test_contract.get_instance_address(0); - let account_address = account.get_instance_address(0); - let mut nonce_manager = NonceManager::default(); +#[case::vm(default_l1_resource_bounds(), CairoVersion::Cairo1(RunnableCairo1::Casm))] +#[case::gas(default_all_resource_bounds(), CairoVersion::Cairo1(RunnableCairo1::Casm))] +#[cfg_attr( + feature = "cairo_native", + case::gas_native(default_all_resource_bounds(), CairoVersion::Cairo1(RunnableCairo1::Native)) +)] +fn test_rc96_holes( + block_context: BlockContext, + #[case] resource_bounds: ValidResourceBounds, + #[case] cairo_version: CairoVersion, +) { + let TestInitData { mut state, account_address, contract_address, mut nonce_manager } = + create_test_init_data(&block_context.chain_info, cairo_version); // Invoke a function that changes the state and reverts. let tx_args = invoke_tx_args! { sender_address: account_address, calldata: create_calldata( - test_contract_address, + contract_address, "test_rc96_holes", &[] ), nonce: nonce_manager.next(account_address) }; let tx_execution_info = run_invoke_tx( - state, + &mut state, &block_context, invoke_tx_args! { - resource_bounds: default_all_resource_bounds, + resource_bounds: resource_bounds, ..tx_args }, ) .unwrap(); assert!(!tx_execution_info.is_reverted()); - assert_eq!( - tx_execution_info.receipt.resources.computation.vm_resources.builtin_instance_counter - [&BuiltinName::range_check96], - 24 - ); + if tx_execution_info.validate_call_info.unwrap().tracked_resource == TrackedResource::CairoSteps + { + assert_eq!( + tx_execution_info.receipt.resources.computation.vm_resources.builtin_instance_counter + [&BuiltinName::range_check96], + 24 + ); + } } #[rstest] @@ -190,35 +215,41 @@ fn test_fee_enforcement( ) { let account = FeatureContract::AccountWithoutValidations(CairoVersion::Cairo0); let state = &mut test_state(&block_context.chain_info, BALANCE, &[(account, 1)]); - let deploy_account_tx = deploy_account_tx( - deploy_account_tx_args! { - class_hash: account.get_class_hash(), - max_fee: Fee(if zero_bounds { 0 } else { MAX_FEE.0 }), - resource_bounds: match gas_bounds_mode { - GasVectorComputationMode::NoL2Gas => l1_resource_bounds( - (if zero_bounds { 0 } else { DEFAULT_L1_GAS_AMOUNT.0 }).into(), - DEFAULT_STRK_L1_GAS_PRICE.into() - ), - GasVectorComputationMode::All => create_all_resource_bounds( - (if zero_bounds { 0 } else { DEFAULT_L1_GAS_AMOUNT.0 }).into(), - DEFAULT_STRK_L1_GAS_PRICE.into(), - (if zero_bounds { 0 } else { DEFAULT_L2_GAS_MAX_AMOUNT.0 }).into(), - DEFAULT_STRK_L2_GAS_PRICE.into(), - (if zero_bounds { 0 } else { DEFAULT_L1_DATA_GAS_MAX_AMOUNT.0 }).into(), - DEFAULT_STRK_L1_DATA_GAS_PRICE.into(), - ), - }, - version, + let tx = executable_deploy_account_tx(deploy_account_tx_args! { + class_hash: account.get_class_hash(), + max_fee: Fee(if zero_bounds { 0 } else { MAX_FEE.0 }), + resource_bounds: match gas_bounds_mode { + GasVectorComputationMode::NoL2Gas => l1_resource_bounds( + (if zero_bounds { 0 } else { DEFAULT_L1_GAS_AMOUNT.0 }).into(), + DEFAULT_STRK_L1_GAS_PRICE.into() + ), + GasVectorComputationMode::All => create_gas_amount_bounds_with_default_price( + GasVector{ + l1_gas: (if zero_bounds { 0 } else { DEFAULT_L1_GAS_AMOUNT.0 }).into(), + l2_gas: (if zero_bounds { 0 } else { DEFAULT_L2_GAS_MAX_AMOUNT.0 }).into(), + l1_data_gas: (if zero_bounds { 0 } else { DEFAULT_L1_DATA_GAS_MAX_AMOUNT.0 }).into(), + }, + ), }, - &mut NonceManager::default(), - ); + version, + }); + let deploy_account_tx = AccountTransaction::new_for_sequencing(tx); let enforce_fee = deploy_account_tx.enforce_fee(); assert_ne!(zero_bounds, enforce_fee); - let result = deploy_account_tx.execute(state, &block_context, enforce_fee, true); - // Execution should fail if the fee is enforced because the account doesn't have sufficient + let result = deploy_account_tx.execute(state, &block_context); + // When fee is enforced, execution should fail because the account doesn't have sufficient // balance. - assert_eq!(result.is_err(), enforce_fee); + if enforce_fee { + assert_matches!( + result, + Err(TransactionExecutionError::TransactionPreValidationError( + TransactionPreValidationError::TransactionFeeError(_) + )) + ); + } else { + assert!(result.is_ok()); + } } #[rstest] @@ -228,15 +259,14 @@ fn test_all_bounds_combinations_enforce_fee( #[values(0, 1)] l2_gas_bound: u64, ) { let expected_enforce_fee = l1_gas_bound + l1_data_gas_bound + l2_gas_bound > 0; - let account_tx = account_invoke_tx(invoke_tx_args! { + let account_tx = invoke_tx_with_default_flags(invoke_tx_args! { version: TransactionVersion::THREE, - resource_bounds: create_all_resource_bounds( - l1_gas_bound.into(), - DEFAULT_STRK_L1_GAS_PRICE.into(), - l2_gas_bound.into(), - DEFAULT_STRK_L2_GAS_PRICE.into(), - l1_data_gas_bound.into(), - DEFAULT_STRK_L1_DATA_GAS_PRICE.into(), + resource_bounds: create_gas_amount_bounds_with_default_price( + GasVector { + l1_gas: l1_gas_bound.into(), + l2_gas: l2_gas_bound.into(), + l1_data_gas: l1_data_gas_bound.into(), + }, ), }); assert_eq!(account_tx.enforce_fee(), expected_enforce_fee); @@ -257,7 +287,9 @@ fn test_assert_actual_fee_in_bounds( let actual_fee_offset = Fee(if positive_flow { 0 } else { 1 }); if deprecated_tx { let max_fee = Fee(100); - let tx = account_invoke_tx(invoke_tx_args! { max_fee, version: TransactionVersion::ONE }); + let tx = invoke_tx_with_default_flags( + invoke_tx_args! { max_fee, version: TransactionVersion::ONE }, + ); let context = Arc::new(block_context.to_tx_context(&tx)); AccountTransaction::assert_actual_fee_in_bounds(&context, max_fee + actual_fee_offset); } else { @@ -281,7 +313,7 @@ fn test_assert_actual_fee_in_bounds( for (bounds, actual_fee) in [(all_resource_bounds, all_resource_fee), (l1_resource_bounds, l1_resource_fee)] { - let tx = account_invoke_tx(invoke_tx_args! { + let tx = invoke_tx_with_default_flags(invoke_tx_args! { resource_bounds: bounds, version: TransactionVersion::THREE, }); @@ -302,7 +334,6 @@ fn test_account_flow_test( max_fee: Fee, #[case] tx_version: TransactionVersion, #[case] resource_bounds: ValidResourceBounds, - #[values(true, false)] only_query: bool, ) { let TestInitData { mut state, account_address, contract_address, mut nonce_manager } = create_test_init_data(&block_context.chain_info, CairoVersion::Cairo0); @@ -318,7 +349,6 @@ fn test_account_flow_test( version: tx_version, resource_bounds, nonce: nonce_manager.next(account_address), - only_query, }, ) .unwrap(); @@ -384,7 +414,7 @@ fn test_infinite_recursion( resource_bounds: ValidResourceBounds, ) { // Limit the number of execution steps (so we quickly hit the limit). - block_context.versioned_constants.invoke_tx_max_n_steps = 4200; + block_context.versioned_constants.invoke_tx_max_n_steps = 4700; let TestInitData { mut state, account_address, contract_address, mut nonce_manager } = create_test_init_data(&block_context.chain_info, CairoVersion::Cairo0); @@ -429,29 +459,27 @@ fn test_infinite_recursion( } } -/// Tests that validation fails on insufficient steps if max fee is too low. +/// Tests that validation fails on out-of-gas if L2 gas bound is too low. #[rstest] -#[case::v1(TransactionVersion::ONE, default_l1_resource_bounds())] -#[case::v3_l1_bounds_only(TransactionVersion::THREE, default_l1_resource_bounds())] -#[case::v3_all_bounds(TransactionVersion::THREE, default_all_resource_bounds())] fn test_max_fee_limit_validate( mut block_context: BlockContext, - #[case] version: TransactionVersion, - #[case] resource_bounds: ValidResourceBounds, + default_all_resource_bounds: ValidResourceBounds, #[values(true, false)] use_kzg_da: bool, ) { + let resource_bounds = default_all_resource_bounds; block_context.block_info.use_kzg_da = use_kzg_da; - let chain_info = &block_context.chain_info; + let chain_info = block_context.chain_info.clone(); let gas_computation_mode = resource_bounds.get_gas_vector_computation_mode(); let TestInitData { mut state, account_address, contract_address, mut nonce_manager } = - create_test_init_data(chain_info, CairoVersion::Cairo1); - let grindy_validate_account = FeatureContract::AccountWithLongValidate(CairoVersion::Cairo1); + create_test_init_data(&chain_info, CairoVersion::Cairo1(RunnableCairo1::Casm)); + let grindy_validate_account = + FeatureContract::AccountWithLongValidate(CairoVersion::Cairo1(RunnableCairo1::Casm)); let grindy_class_hash = grindy_validate_account.get_class_hash(); - let block_info = &block_context.block_info; + let block_info = block_context.block_info.clone(); let class_info = calculate_class_info_for_testing(grindy_validate_account.get_class()); // Declare the grindy-validation account. - let account_tx = declare_tx( + let tx = executable_declare_tx( declare_tx_args! { class_hash: grindy_class_hash, sender_address: account_address, @@ -460,19 +488,24 @@ fn test_max_fee_limit_validate( }, class_info, ); - account_tx.execute(&mut state, &block_context, true, true).unwrap(); + let account_tx = AccountTransaction::new_with_default_flags(tx); + account_tx.execute(&mut state, &block_context).unwrap(); // Deploy grindy account with a lot of grind in the constructor. // Expect this to fail without bumping nonce, so pass a temporary nonce manager. - // We want to test the block step bounds here - so set them to something low. + // We want to test the block step / gas bounds here - so set them to something low. let old_validate_max_n_steps = block_context.versioned_constants.validate_max_n_steps; block_context.versioned_constants.validate_max_n_steps = 1000; + let old_validate_max_gas = + block_context.versioned_constants.os_constants.validate_max_sierra_gas; + block_context.set_sierra_gas_limits(None, Some(GasAmount(100000))); + let mut ctor_grind_arg = felt!(1_u8); // Grind in deploy phase. let ctor_storage_arg = felt!(1_u8); // Not relevant for this test. let (deploy_account_tx, _) = deploy_and_fund_account( &mut state, &mut NonceManager::default(), - chain_info, + &chain_info, deploy_account_tx_args! { class_hash: grindy_class_hash, resource_bounds, @@ -480,23 +513,24 @@ fn test_max_fee_limit_validate( }, ); let error_trace = - deploy_account_tx.execute(&mut state, &block_context, true, true).unwrap_err().to_string(); - assert!(error_trace.contains("no remaining steps")); + deploy_account_tx.execute(&mut state, &block_context).unwrap_err().to_string(); + assert!(error_trace.contains("Out of gas")); block_context.versioned_constants.validate_max_n_steps = old_validate_max_n_steps; + block_context.set_sierra_gas_limits(None, Some(old_validate_max_gas)); // Deploy grindy account successfully this time. ctor_grind_arg = felt!(0_u8); // Do not grind in deploy phase. let (deploy_account_tx, grindy_account_address) = deploy_and_fund_account( &mut state, &mut nonce_manager, - chain_info, + &chain_info, deploy_account_tx_args! { class_hash: grindy_class_hash, resource_bounds, constructor_calldata: calldata![ctor_grind_arg, ctor_storage_arg], }, ); - deploy_account_tx.execute(&mut state, &block_context, true, true).unwrap(); + deploy_account_tx.execute(&mut state, &block_context).unwrap(); // Invoke a function that grinds validate (any function will do); set bounds low enough to fail // on this grind. @@ -507,11 +541,11 @@ fn test_max_fee_limit_validate( let tx_args = invoke_tx_args! { sender_address: grindy_account_address, calldata: create_calldata(contract_address, "return_result", &[1000_u32.into()]), - version, + version: TransactionVersion::THREE, nonce: nonce_manager.next(grindy_account_address) }; - let account_tx = account_invoke_tx(invoke_tx_args! { + let account_tx = invoke_tx_with_default_flags(invoke_tx_args! { // Temporary upper bounds; just for gas estimation. max_fee: MAX_FEE, resource_bounds, @@ -520,7 +554,7 @@ fn test_max_fee_limit_validate( let estimated_min_gas_usage_vector = estimate_minimal_gas_vector(&block_context, &account_tx, &gas_computation_mode); let estimated_min_fee = - get_fee_by_gas_vector(block_info, estimated_min_gas_usage_vector, &account_tx.fee_type()); + get_fee_by_gas_vector(&block_info, estimated_min_gas_usage_vector, &account_tx.fee_type()); // Make sure the resource bounds are the limiting factor by blowing up the block bounds. let old_validate_max_n_steps = block_context.versioned_constants.validate_max_n_steps; @@ -536,25 +570,27 @@ fn test_max_fee_limit_validate( // not include DA. To cover minimal cost with only an L1 gas bound, need to // convert the L1 data gas to L1 gas. let tx_context = TransactionContext { - block_context: block_context.clone(), + block_context: Arc::new(block_context.clone()), tx_info: account_tx.create_tx_info(), }; let gas_prices = tx_context.get_gas_prices(); l1_resource_bounds( - estimated_min_gas_usage_vector.to_discounted_l1_gas(gas_prices), + estimated_min_gas_usage_vector.to_l1_gas_for_fee( + gas_prices, &tx_context.block_context.versioned_constants + ), gas_prices.l1_gas_price.into(), ) } GasVectorComputationMode::All => create_all_resource_bounds( estimated_min_gas_usage_vector.l1_gas, block_info.gas_prices - .get_l1_gas_price_by_fee_type(&account_tx.fee_type()).into(), + .l1_gas_price(&account_tx.fee_type()).into(), estimated_min_gas_usage_vector.l2_gas, block_info.gas_prices - .get_l2_gas_price_by_fee_type(&account_tx.fee_type()).into(), + .l2_gas_price(&account_tx.fee_type()).into(), estimated_min_gas_usage_vector.l1_data_gas, block_info.gas_prices - .get_l1_data_gas_price_by_fee_type(&account_tx.fee_type()).into(), + .l1_data_gas_price(&account_tx.fee_type()).into(), ), }, ..tx_args @@ -566,13 +602,13 @@ fn test_max_fee_limit_validate( assert!(error_trace.contains("no remaining steps") | error_trace.contains("Out of gas")) } -#[rstest] +#[apply(cairo_version)] #[case::v1(TransactionVersion::ONE, default_all_resource_bounds())] #[case::l1_bounds(TransactionVersion::THREE, default_l1_resource_bounds())] #[case::all_bounds(TransactionVersion::THREE, default_all_resource_bounds())] fn test_recursion_depth_exceeded( #[case] tx_version: TransactionVersion, - #[values(CairoVersion::Cairo0, CairoVersion::Cairo1)] cairo_version: CairoVersion, + cairo_version: CairoVersion, block_context: BlockContext, max_fee: Fee, #[case] resource_bounds: ValidResourceBounds, @@ -654,25 +690,20 @@ fn test_revert_invoke( #[case] transaction_version: TransactionVersion, #[case] fee_type: FeeType, ) { - let test_contract = FeatureContract::TestContract(CairoVersion::Cairo0); - let account = FeatureContract::AccountWithoutValidations(CairoVersion::Cairo0); - let chain_info = &block_context.chain_info; - let state = &mut test_state(chain_info, BALANCE, &[(test_contract, 1), (account, 1)]); - let test_contract_address = test_contract.get_instance_address(0); - let account_address = account.get_instance_address(0); - let mut nonce_manager = NonceManager::default(); + let TestInitData { mut state, account_address, contract_address, mut nonce_manager } = + create_test_init_data(&block_context.chain_info, CairoVersion::Cairo0); // Invoke a function that changes the state and reverts. let storage_key = felt!(9_u8); let tx_execution_info = run_invoke_tx( - state, + &mut state, &block_context, invoke_tx_args! { max_fee, resource_bounds: all_resource_bounds, sender_address: account_address, calldata: create_calldata( - test_contract_address, + contract_address, "write_and_revert", // Write some non-zero value. &[storage_key, felt!(99_u8)] @@ -692,7 +723,10 @@ fn test_revert_invoke( // Check that the nonce was increased and the fee was deducted. assert_eq!( state - .get_fee_token_balance(account_address, chain_info.fee_token_address(&fee_type)) + .get_fee_token_balance( + account_address, + block_context.chain_info.fee_token_address(&fee_type) + ) .unwrap(), (felt!(BALANCE.0 - tx_execution_info.receipt.fee.0), felt!(0_u8)) ); @@ -704,17 +738,21 @@ fn test_revert_invoke( // Check that execution state changes were reverted. assert_eq!( felt!(0_u8), - state - .get_storage_at(test_contract_address, StorageKey::try_from(storage_key).unwrap()) - .unwrap() + state.get_storage_at(contract_address, StorageKey::try_from(storage_key).unwrap()).unwrap() ); } #[rstest] +#[case::cairo0(CairoVersion::Cairo0)] +#[case::cairo1(CairoVersion::Cairo1(RunnableCairo1::Casm))] +#[cfg_attr( + feature = "cairo_native", + case::cairo1_native(CairoVersion::Cairo1(RunnableCairo1::Native)) +)] /// Tests that failing account deployment should not change state (no fee charge or nonce bump). fn test_fail_deploy_account( block_context: BlockContext, - #[values(CairoVersion::Cairo0, CairoVersion::Cairo1)] cairo_version: CairoVersion, + #[case] cairo_version: CairoVersion, #[values(TransactionVersion::ONE, TransactionVersion::THREE)] tx_version: TransactionVersion, ) { let chain_info = &block_context.chain_info; @@ -742,7 +780,7 @@ fn test_fail_deploy_account( let initial_balance = state.get_fee_token_balance(deploy_address, fee_token_address).unwrap(); - let error = deploy_account_tx.execute(state, &block_context, true, true).unwrap_err(); + let error = deploy_account_tx.execute(state, &block_context).unwrap_err(); // Check the error is as expected. Assure the error message is not nonce or fee related. check_tx_execution_error_for_invalid_scenario!(cairo_version, error, false); @@ -762,7 +800,8 @@ fn test_fail_declare(block_context: BlockContext, max_fee: Fee) { let TestInitData { mut state, account_address, mut nonce_manager, .. } = create_test_init_data(chain_info, CairoVersion::Cairo0); let class_hash = class_hash!(0xdeadeadeaf72_u128); - let contract_class = FeatureContract::Empty(CairoVersion::Cairo1).get_class(); + let contract_class = + FeatureContract::Empty(CairoVersion::Cairo1(RunnableCairo1::Casm)).get_class(); let next_nonce = nonce_manager.next(account_address); // Cannot fail executing a declare tx unless it's V2 or above, and already declared. @@ -775,19 +814,21 @@ fn test_fail_declare(block_context: BlockContext, max_fee: Fee) { state.set_contract_class(class_hash, contract_class.clone().try_into().unwrap()).unwrap(); state.set_compiled_class_hash(class_hash, declare_tx_v2.compiled_class_hash).unwrap(); let class_info = calculate_class_info_for_testing(contract_class); - let declare_account_tx: AccountTransaction = ApiExecutableDeclareTransaction { + let executable_declare = ApiExecutableDeclareTransaction { tx: DeclareTransaction::V2(DeclareTransactionV2 { nonce: next_nonce, ..declare_tx_v2 }), tx_hash: TransactionHash::default(), class_info, - } - .into(); + }; + let declare_account_tx = AccountTransaction::new_with_default_flags( + ApiExecutableTransaction::Declare(executable_declare), + ); // Fail execution, assert nonce and balance are unchanged. let tx_info = declare_account_tx.create_tx_info(); let initial_balance = state .get_fee_token_balance(account_address, chain_info.fee_token_address(&tx_info.fee_type())) .unwrap(); - declare_account_tx.execute(&mut state, &block_context, true, true).unwrap_err(); + declare_account_tx.execute(&mut state, &block_context).unwrap_err(); assert_eq!(state.get_nonce_at(account_address).unwrap(), next_nonce); assert_eq!( @@ -813,25 +854,27 @@ fn recursive_function_calldata( ) } -#[rstest] +#[apply(cairo_version)] /// Tests that reverted transactions are charged more fee and steps than their (recursive) prefix /// successful counterparts. /// In this test reverted transactions are valid function calls that got insufficient steps limit. #[case::v1(TransactionVersion::ONE, default_all_resource_bounds())] #[case::l1_bounds(TransactionVersion::THREE, default_l1_resource_bounds())] #[case::all_bounds(TransactionVersion::THREE, default_all_resource_bounds())] -fn test_reverted_reach_steps_limit( +fn test_reverted_reach_computation_limit( max_fee: Fee, mut block_context: BlockContext, #[case] version: TransactionVersion, #[case] resource_bounds: ValidResourceBounds, - #[values(CairoVersion::Cairo0, CairoVersion::Cairo1)] cairo_version: CairoVersion, + cairo_version: CairoVersion, ) { let TestInitData { mut state, account_address, contract_address, mut nonce_manager } = create_test_init_data(&block_context.chain_info, cairo_version); + let tracked_resource = CompilerBasedVersion::CairoVersion(cairo_version).own_tracked_resource(); - // Limit the number of execution steps (so we quickly hit the limit). + // Limit the max amount of computation units (so we quickly hit the limit). block_context.versioned_constants.invoke_tx_max_n_steps = 6000; + block_context.set_sierra_gas_limits(Some(GasAmount(600000)), None); let recursion_base_args = invoke_tx_args! { max_fee, resource_bounds, @@ -850,8 +893,10 @@ fn test_reverted_reach_steps_limit( }, ) .unwrap(); - let n_steps_0 = result.receipt.resources.computation.total_charged_steps(); + let n_units_0 = + result.receipt.resources.computation.total_charged_computation_units(tracked_resource); let actual_fee_0 = result.receipt.fee.0; + // Ensure the transaction was not reverted. assert!(!result.is_reverted()); @@ -866,21 +911,33 @@ fn test_reverted_reach_steps_limit( }, ) .unwrap(); - let n_steps_1 = result.receipt.resources.computation.total_charged_steps(); + let n_units_1 = + result.receipt.resources.computation.total_charged_computation_units(tracked_resource); let actual_fee_1 = result.receipt.fee.0; // Ensure the transaction was not reverted. assert!(!result.is_reverted()); - // Make sure that the n_steps and actual_fee are higher as the recursion depth increases. - assert!(n_steps_1 > n_steps_0); + // Make sure that the n_units and actual_fee are higher as the recursion depth increases. + let validate_tracked_resource = result.validate_call_info.unwrap().tracked_resource; + assert_eq!(tracked_resource, validate_tracked_resource); + assert!(n_units_1 > n_units_0); assert!(actual_fee_1 > actual_fee_0); // Calculate a recursion depth where the transaction will surely fail (not a minimal depth, as // base costs are neglected here). - let steps_diff = n_steps_1 - n_steps_0; + let units_diff = n_units_1 - n_units_0; // TODO(Ori, 1/2/2024): Write an indicative expect message explaining why the conversion works. - let steps_diff_as_u32: u32 = steps_diff.try_into().expect("Failed to convert usize to u32."); - let fail_depth = block_context.versioned_constants.invoke_tx_max_n_steps / steps_diff_as_u32; + let units_diff_as_u32: u32 = units_diff.try_into().expect("Failed to convert usize to u32."); + let fail_depth = match tracked_resource { + TrackedResource::CairoSteps => { + block_context.versioned_constants.invoke_tx_max_n_steps / units_diff_as_u32 + } + TrackedResource::SierraGas => { + u32::try_from(block_context.versioned_constants.os_constants.execute_max_sierra_gas.0) + .unwrap() + / units_diff_as_u32 + } + }; // Invoke the `recurse` function with `fail_depth` iterations. This call should fail. let result = run_invoke_tx( @@ -893,16 +950,19 @@ fn test_reverted_reach_steps_limit( }, ) .unwrap(); - let n_steps_fail = result.receipt.resources.computation.total_charged_steps(); + let n_units_fail = + result.receipt.resources.computation.total_charged_computation_units(tracked_resource); let actual_fee_fail: u128 = result.receipt.fee.0; // Ensure the transaction was reverted. assert!(result.is_reverted()); - // Make sure that the failed transaction gets charged for the extra steps taken, compared with + // Make sure that the failed transaction gets charged for the extra computation, compared with // the smaller valid transaction. - // If this fail, try to increase the `invoke_tx_max_n_steps` above. - assert!(n_steps_fail > n_steps_1); + // If this assert fails, it may be due to the max computation limit being too low - i.e. this + // new failure cannot run long enough to consume more computation units than the "1" case. + // If this is the issue, try to increase the max computation limit on the block context above. + assert!(n_units_fail > n_units_1); assert!(actual_fee_fail > actual_fee_1); // Invoke the `recurse` function with `fail_depth`+1 iterations. This call should fail. @@ -916,32 +976,42 @@ fn test_reverted_reach_steps_limit( }, ) .unwrap(); - let n_steps_fail_next = result.receipt.resources.computation.total_charged_steps(); + let n_units_fail_next = + result.receipt.resources.computation.total_charged_computation_units(tracked_resource); let actual_fee_fail_next: u128 = result.receipt.fee.0; // Ensure the transaction was reverted. assert!(result.is_reverted()); // Test that the two reverted transactions behave the same. - assert!(n_steps_fail == n_steps_fail_next); - assert!(actual_fee_fail == actual_fee_fail_next); + assert_eq!(n_units_fail, n_units_fail_next); + assert_eq!(actual_fee_fail, actual_fee_fail_next); } #[rstest] -/// Tests that n_steps and actual_fees of reverted transactions invocations are consistent. -/// In this test reverted transactions are recursive function invocations where the innermost call -/// asserts false. We test deltas between consecutive depths, and further depths. -fn test_n_reverted_steps( +#[case::cairo0(CompilerBasedVersion::CairoVersion(CairoVersion::Cairo0))] +#[case::cairo1(CompilerBasedVersion::CairoVersion(CairoVersion::Cairo1(RunnableCairo1::Casm)))] +#[cfg_attr( + feature = "cairo_native", + case::cairo1_native(CompilerBasedVersion::CairoVersion(CairoVersion::Cairo1( + RunnableCairo1::Native + ))) +)] +/// Tests that n_steps / n_reverted_gas and actual_fees of reverted transactions invocations are +/// consistent. In this test reverted transactions are recursive function invocations where the +/// innermost call asserts false. We test deltas between consecutive depths, and further depths. +fn test_n_reverted_computation_units( block_context: BlockContext, #[values(default_l1_resource_bounds(), default_all_resource_bounds())] resource_bounds: ValidResourceBounds, - #[values(CairoVersion::Cairo0, CairoVersion::Cairo1)] cairo_version: CairoVersion, + #[case] cairo_version: CompilerBasedVersion, ) { let TestInitData { mut state, account_address, contract_address, mut nonce_manager } = - create_test_init_data(&block_context.chain_info, cairo_version); + create_test_init_data(&block_context.chain_info, cairo_version.into()); let recursion_base_args = invoke_tx_args! { resource_bounds, sender_address: account_address, }; + let tracked_resource = cairo_version.own_tracked_resource(); // Invoke the `recursive_fail` function with 0 iterations. This call should fail. let result = run_invoke_tx( @@ -957,7 +1027,8 @@ fn test_n_reverted_steps( // Ensure the transaction was reverted. assert!(result.is_reverted()); let mut actual_resources_0 = result.receipt.resources.computation.clone(); - let n_steps_0 = result.receipt.resources.computation.total_charged_steps(); + let n_units_0 = + result.receipt.resources.computation.total_charged_computation_units(tracked_resource); let actual_fee_0 = result.receipt.fee.0; // Invoke the `recursive_fail` function with 1 iterations. This call should fail. @@ -974,7 +1045,7 @@ fn test_n_reverted_steps( // Ensure the transaction was reverted. assert!(result.is_reverted()); let actual_resources_1 = result.receipt.resources.computation; - let n_steps_1 = actual_resources_1.total_charged_steps(); + let n_units_1 = actual_resources_1.total_charged_computation_units(tracked_resource); let actual_fee_1 = result.receipt.fee.0; // Invoke the `recursive_fail` function with 2 iterations. This call should fail. @@ -988,26 +1059,51 @@ fn test_n_reverted_steps( }, ) .unwrap(); - let n_steps_2 = result.receipt.resources.computation.total_charged_steps(); + let n_units_2 = + result.receipt.resources.computation.total_charged_computation_units(tracked_resource); let actual_fee_2 = result.receipt.fee.0; // Ensure the transaction was reverted. assert!(result.is_reverted()); - // Make sure that n_steps and actual_fee diffs are the same for two consecutive reverted calls. - assert!(n_steps_1 - n_steps_0 == n_steps_2 - n_steps_1); - assert!(actual_fee_1 - actual_fee_0 == actual_fee_2 - actual_fee_1); + // Make sure that n_units and actual_fee diffs are the same for two consecutive reverted calls. + assert_eq!(n_units_1 - n_units_0, n_units_2 - n_units_1); + match (tracked_resource, resource_bounds.get_gas_vector_computation_mode()) { + // If we are tracking sierra gas, but the user signed on L1 gas bounds only, we may have + // rounding differences in the number of L1 gas units the user is charged for. + // This rounding error can result in at most one unit of L1 gas difference, so the final fee + // can differ by at most the L1 gas price. + (TrackedResource::SierraGas, GasVectorComputationMode::NoL2Gas) => { + assert!( + (i128::try_from(actual_fee_1 - actual_fee_0).unwrap() + - i128::try_from(actual_fee_2 - actual_fee_1).unwrap()) + .unsigned_abs() + <= block_context.block_info.gas_prices.l1_gas_price(&FeeType::Strk).get().0 + ); + } + _ => { + assert_eq!(actual_fee_1 - actual_fee_0, actual_fee_2 - actual_fee_1); + } + } // Save the delta between two consecutive calls to be tested against a much larger recursion. - let single_call_steps_delta = n_steps_1 - n_steps_0; + let single_call_units_delta = n_units_1 - n_units_0; let single_call_fee_delta = actual_fee_1 - actual_fee_0; - assert!(single_call_steps_delta > 0); + assert!(single_call_units_delta > 0); assert!(single_call_fee_delta > 0); - // Make sure the resources in block of invocation 0 and 1 are the same, except for the number - // of cairo steps. - actual_resources_0.n_reverted_steps += single_call_steps_delta; - assert_eq!(actual_resources_0, actual_resources_1); - actual_resources_0.vm_resources.n_steps = n_steps_0; + // Make sure the resources in block of invocation 0 and 1 are the same, except for tracked + // resource count. + match tracked_resource { + TrackedResource::CairoSteps => { + actual_resources_0.n_reverted_steps += single_call_units_delta; + assert_eq!(actual_resources_0, actual_resources_1); + } + TrackedResource::SierraGas => { + actual_resources_0.reverted_sierra_gas.0 += + u64::try_from(single_call_units_delta).unwrap(); + assert_eq!(actual_resources_0, actual_resources_1); + } + }; // Invoke the `recursive_fail` function with 100 iterations. This call should fail. let result = run_invoke_tx( @@ -1020,14 +1116,31 @@ fn test_n_reverted_steps( }, ) .unwrap(); - let n_steps_100 = result.receipt.resources.computation.total_charged_steps(); + let n_units_100 = + result.receipt.resources.computation.total_charged_computation_units(tracked_resource); let actual_fee_100 = result.receipt.fee.0; // Ensure the transaction was reverted. assert!(result.is_reverted()); - // Make sure that n_steps and actual_fee grew as expected. - assert!(n_steps_100 - n_steps_0 == 100 * single_call_steps_delta); - assert!(actual_fee_100 - actual_fee_0 == 100 * single_call_fee_delta); + // Make sure that n_units and actual_fee grew as expected. + assert_eq!(n_units_100 - n_units_0, 100 * single_call_units_delta); + // When charging for sierra gas with no L2 gas user bound, due to rounding errors in converting + // L2 gas units to L1 gas, the fee may be a bit off. We may have an error of one L1 gas units + // per recursion, so the fee diff is at most 100 times the price of an L1 gas unit. + match (tracked_resource, resource_bounds.get_gas_vector_computation_mode()) { + (TrackedResource::SierraGas, GasVectorComputationMode::NoL2Gas) => { + assert!( + (i128::try_from(100 * single_call_fee_delta).unwrap() + - i128::try_from(actual_fee_100 - actual_fee_0).unwrap()) + .unsigned_abs() + < 100 + * block_context.block_info.gas_prices.l1_gas_price(&FeeType::Strk).get().0 + ); + } + _ => { + assert_eq!(actual_fee_100 - actual_fee_0, 100 * single_call_fee_delta); + } + } } #[rstest] @@ -1035,7 +1148,11 @@ fn test_max_fee_computation_from_tx_bounds(block_context: BlockContext) { macro_rules! assert_max_steps_as_expected { ($account_tx:expr, $expected_max_steps:expr $(,)?) => { let tx_context = Arc::new(block_context.to_tx_context(&$account_tx)); - let execution_context = EntryPointExecutionContext::new_invoke(tx_context, true); + let execution_context = EntryPointExecutionContext::new_invoke( + tx_context, + true, + SierraGasRevertTracker::new(GasAmount::MAX), + ); let max_steps = execution_context.vm_run_resources.get_n_steps().unwrap(); assert_eq!(u64::try_from(max_steps).unwrap(), $expected_max_steps); }; @@ -1044,7 +1161,7 @@ fn test_max_fee_computation_from_tx_bounds(block_context: BlockContext) { // V1 transaction: limit based on max fee. // Convert max fee to L1 gas units, and then to steps. let max_fee = Fee(100); - let account_tx_max_fee = account_invoke_tx(invoke_tx_args! { + let account_tx_max_fee = invoke_tx_with_default_flags(invoke_tx_args! { max_fee, version: TransactionVersion::ONE }); let steps_per_l1_gas = block_context.versioned_constants.vm_resource_fee_cost().n_steps.inv(); @@ -1052,9 +1169,7 @@ fn test_max_fee_computation_from_tx_bounds(block_context: BlockContext) { account_tx_max_fee, (steps_per_l1_gas * max_fee - .checked_div( - block_context.block_info.gas_prices.get_l1_gas_price_by_fee_type(&FeeType::Eth), - ) + .checked_div(block_context.block_info.gas_prices.eth_gas_prices.l1_gas_price,) .unwrap() .0) .to_integer(), @@ -1063,7 +1178,7 @@ fn test_max_fee_computation_from_tx_bounds(block_context: BlockContext) { // V3 transaction: limit based on L1 gas bounds. // Convert L1 gas units to steps. let l1_gas_bound = 200_u64; - let account_tx_l1_bounds = account_invoke_tx(invoke_tx_args! { + let account_tx_l1_bounds = invoke_tx_with_default_flags(invoke_tx_args! { resource_bounds: l1_resource_bounds(l1_gas_bound.into(), 1_u8.into()), version: TransactionVersion::THREE }); @@ -1075,7 +1190,7 @@ fn test_max_fee_computation_from_tx_bounds(block_context: BlockContext) { // V3 transaction: limit based on L2 gas bounds (all resource_bounds). // Convert L2 gas units to steps. let l2_gas_bound = 300_u64; - let account_tx_l2_bounds = account_invoke_tx(invoke_tx_args! { + let account_tx_l2_bounds = invoke_tx_with_default_flags(invoke_tx_args! { resource_bounds: ValidResourceBounds::AllResources(AllResourceBounds { l2_gas: ResourceBounds { max_amount: l2_gas_bound.into(), @@ -1087,7 +1202,7 @@ fn test_max_fee_computation_from_tx_bounds(block_context: BlockContext) { }); assert_max_steps_as_expected!( account_tx_l2_bounds, - l2_gas_bound / block_context.versioned_constants.os_constants.gas_costs.step_gas_cost, + l2_gas_bound / block_context.versioned_constants.os_constants.gas_costs.base.step_gas_cost, ); } @@ -1102,14 +1217,13 @@ fn test_max_fee_to_max_steps_conversion( let TestInitData { mut state, account_address, contract_address, mut nonce_manager } = create_test_init_data(&block_context.chain_info, CairoVersion::Cairo0); let actual_gas_used: GasAmount = u64_from_usize( - get_syscall_resources(SyscallSelector::CallContract).n_steps + get_const_syscall_resources(SyscallSelector::CallContract).n_steps + get_tx_resources(TransactionType::InvokeFunction).n_steps + 1751, ) .into(); let actual_fee = u128::from(actual_gas_used.0) * 100000000000; - let actual_strk_gas_price = - block_context.block_info.gas_prices.get_l1_gas_price_by_fee_type(&FeeType::Strk); + let actual_strk_gas_price = block_context.block_info.gas_prices.strk_gas_prices.l1_gas_price; let execute_calldata = create_calldata( contract_address, "with_arg", @@ -1117,7 +1231,7 @@ fn test_max_fee_to_max_steps_conversion( ); // First invocation of `with_arg` gets the exact pre-calculated actual fee as max_fee. - let account_tx1 = account_invoke_tx(invoke_tx_args! { + let account_tx1 = invoke_tx_with_default_flags(invoke_tx_args! { max_fee: Fee(actual_fee), sender_address: account_address, calldata: execute_calldata.clone(), @@ -1126,9 +1240,13 @@ fn test_max_fee_to_max_steps_conversion( nonce: nonce_manager.next(account_address), }); let tx_context1 = Arc::new(block_context.to_tx_context(&account_tx1)); - let execution_context1 = EntryPointExecutionContext::new_invoke(tx_context1, true); + let execution_context1 = EntryPointExecutionContext::new_invoke( + tx_context1, + true, + SierraGasRevertTracker::new(GasAmount::MAX), + ); let max_steps_limit1 = execution_context1.vm_run_resources.get_n_steps(); - let tx_execution_info1 = account_tx1.execute(&mut state, &block_context, true, true).unwrap(); + let tx_execution_info1 = account_tx1.execute(&mut state, &block_context).unwrap(); let n_steps1 = tx_execution_info1.receipt.resources.computation.vm_resources.n_steps; let gas_used_vector1 = tx_execution_info1.receipt.resources.to_gas_vector( &block_context.versioned_constants, @@ -1137,7 +1255,7 @@ fn test_max_fee_to_max_steps_conversion( ); // Second invocation of `with_arg` gets twice the pre-calculated actual fee as max_fee. - let account_tx2 = account_invoke_tx(invoke_tx_args! { + let account_tx2 = invoke_tx_with_default_flags(invoke_tx_args! { max_fee: Fee(2 * actual_fee), sender_address: account_address, calldata: execute_calldata, @@ -1147,9 +1265,13 @@ fn test_max_fee_to_max_steps_conversion( nonce: nonce_manager.next(account_address), }); let tx_context2 = Arc::new(block_context.to_tx_context(&account_tx2)); - let execution_context2 = EntryPointExecutionContext::new_invoke(tx_context2, true); + let execution_context2 = EntryPointExecutionContext::new_invoke( + tx_context2, + true, + SierraGasRevertTracker::new(GasAmount::MAX), + ); let max_steps_limit2 = execution_context2.vm_run_resources.get_n_steps(); - let tx_execution_info2 = account_tx2.execute(&mut state, &block_context, true, true).unwrap(); + let tx_execution_info2 = account_tx2.execute(&mut state, &block_context).unwrap(); let n_steps2 = tx_execution_info2.receipt.resources.computation.vm_resources.n_steps; let gas_used_vector2 = tx_execution_info2.receipt.resources.to_gas_vector( &block_context.versioned_constants, @@ -1175,7 +1297,8 @@ fn test_insufficient_max_fee_reverts( block_context: BlockContext, #[values(default_l1_resource_bounds(), default_all_resource_bounds())] resource_bounds: ValidResourceBounds, - #[values(CairoVersion::Cairo0, CairoVersion::Cairo1)] cairo_version: CairoVersion, + #[values(CairoVersion::Cairo0, CairoVersion::Cairo1(RunnableCairo1::Casm))] + cairo_version: CairoVersion, ) { let gas_mode = resource_bounds.get_gas_vector_computation_mode(); let TestInitData { mut state, account_address, contract_address, mut nonce_manager } = @@ -1205,11 +1328,11 @@ fn test_insufficient_max_fee_reverts( let resource_used_depth1 = match gas_mode { GasVectorComputationMode::NoL2Gas => l1_resource_bounds( tx_execution_info1.receipt.gas.l1_gas, - block_context.block_info.gas_prices.get_l1_gas_price_by_fee_type(&FeeType::Strk).into(), + block_context.block_info.gas_prices.strk_gas_prices.l1_gas_price.into(), ), GasVectorComputationMode::All => ValidResourceBounds::all_bounds_from_vectors( &tx_execution_info1.receipt.gas, - block_context.block_info.gas_prices.get_gas_prices_by_fee_type(&FeeType::Strk), + &block_context.block_info.gas_prices.strk_gas_prices, ), }; let tx_execution_info2 = run_invoke_tx( @@ -1260,16 +1383,60 @@ fn test_insufficient_max_fee_reverts( ) .unwrap(); assert!(tx_execution_info3.is_reverted()); + match (cairo_version, resource_used_depth1) { + (CairoVersion::Cairo0, _) => { + assert_eq!(tx_execution_info3.receipt.fee, tx_execution_info1.receipt.fee); + assert!( + tx_execution_info3.revert_error.unwrap().to_string().contains("no remaining steps") + ); + } + (CairoVersion::Cairo1(RunnableCairo1::Casm), ValidResourceBounds::AllResources(_)) => { + // There is no guarantee that out of gas errors result in maximal fee charge (as in - we + // do not always expect the max amount of L2 gas to be charged). Assert final fee is + // within a sane range. + assert!(tx_execution_info3.revert_error.unwrap().to_string().contains("Out of gas")); + assert!(Fee(2 * tx_execution_info3.receipt.fee.0) >= tx_execution_info1.receipt.fee); + assert!(tx_execution_info3.receipt.fee <= Fee(2 * tx_execution_info1.receipt.fee.0)); + } + (CairoVersion::Cairo1(RunnableCairo1::Casm), ValidResourceBounds::L1Gas(l1_bound)) => { + // If a user supplied L1 gas bounds only, sierra gas is not limited in proportion to the + // user bound; so we expect to revert in post-execution only. + assert!( + tx_execution_info3 + .revert_error + .unwrap() + .to_string() + .contains("Insufficient max L1Gas") + ); + assert_eq!( + tx_execution_info3.receipt.fee, + l1_bound + .max_amount + .checked_mul( + block_context.block_info.gas_prices.l1_gas_price(&FeeType::Strk).into() + ) + .unwrap() + ); + } + #[cfg(feature = "cairo_native")] + (CairoVersion::Cairo1(RunnableCairo1::Native), _) => { + panic!("Test not implemented for cairo native.") + } + } assert_eq!(tx_execution_info3.receipt.da_gas, tx_execution_info1.receipt.da_gas); - assert_eq!(tx_execution_info3.receipt.fee, tx_execution_info1.receipt.fee); - assert!(tx_execution_info3.revert_error.unwrap().to_string().contains("no remaining steps")); } #[rstest] +#[case::cairo0(CairoVersion::Cairo0)] +#[case::cairo1(CairoVersion::Cairo1(RunnableCairo1::Casm))] +#[cfg_attr( + feature = "cairo_native", + case::cairo1_native(CairoVersion::Cairo1(RunnableCairo1::Native)) +)] fn test_deploy_account_constructor_storage_write( default_all_resource_bounds: ValidResourceBounds, block_context: BlockContext, - #[values(CairoVersion::Cairo0, CairoVersion::Cairo1)] cairo_version: CairoVersion, + #[case] cairo_version: CairoVersion, ) { let grindy_account = FeatureContract::AccountWithLongValidate(cairo_version); let class_hash = grindy_account.get_class_hash(); @@ -1289,7 +1456,7 @@ fn test_deploy_account_constructor_storage_write( constructor_calldata: constructor_calldata.clone(), }, ); - deploy_account_tx.execute(state, &block_context, true, true).unwrap(); + deploy_account_tx.execute(state, &block_context).unwrap(); // Check that the constructor wrote ctor_arg to the storage. let storage_key = get_storage_var_address("ctor_arg", &[]); @@ -1305,7 +1472,7 @@ fn test_deploy_account_constructor_storage_write( } /// Test for counting actual storage changes. -#[rstest] +#[apply(cairo_version)] #[case::tx_version_1(TransactionVersion::ONE, FeeType::Eth)] #[case::tx_version_3(TransactionVersion::THREE, FeeType::Strk)] fn test_count_actual_storage_changes( @@ -1314,7 +1481,7 @@ fn test_count_actual_storage_changes( default_all_resource_bounds: ValidResourceBounds, #[case] version: TransactionVersion, #[case] fee_type: FeeType, - #[values(CairoVersion::Cairo0, CairoVersion::Cairo1)] cairo_version: CairoVersion, + cairo_version: CairoVersion, ) { // FeeType according to version. @@ -1322,12 +1489,8 @@ fn test_count_actual_storage_changes( let fee_token_address = chain_info.fee_token_address(&fee_type); // Create initial state - let test_contract = FeatureContract::TestContract(cairo_version); - let account_contract = FeatureContract::AccountWithoutValidations(cairo_version); - let mut state = test_state(chain_info, BALANCE, &[(account_contract, 1), (test_contract, 1)]); - let account_address = account_contract.get_instance_address(0); - let contract_address = test_contract.get_instance_address(0); - let mut nonce_manager = NonceManager::default(); + let TestInitData { mut state, account_address, contract_address, mut nonce_manager } = + create_test_init_data(&block_context.chain_info, cairo_version); let sequencer_address = block_context.block_info.sequencer_address; let initial_sequencer_balance = @@ -1360,11 +1523,10 @@ fn test_count_actual_storage_changes( calldata: write_1_calldata, nonce: nonce_manager.next(account_address), }; - let account_tx = account_invoke_tx(invoke_args.clone()); - let execution_flags = - ExecutionFlags { charge_fee: true, validate: true, concurrency_mode: false }; + let account_tx = invoke_tx_with_default_flags(invoke_args.clone()); + let concurrency_mode = false; let execution_info = - account_tx.execute_raw(&mut state, &block_context, execution_flags).unwrap(); + account_tx.execute_raw(&mut state, &block_context, concurrency_mode).unwrap(); let fee_1 = execution_info.receipt.fee; let state_changes_1 = state.get_actual_state_changes().unwrap(); @@ -1401,18 +1563,18 @@ fn test_count_actual_storage_changes( n_allocated_keys: 2, }; - assert_eq!(expected_modified_contracts, state_changes_1.state_maps.get_modified_contracts()); + assert_eq!(expected_modified_contracts, state_changes_1.state_maps.get_contract_addresses()); assert_eq!(expected_storage_updates_1, state_changes_1.state_maps.storage); assert_eq!(state_changes_count_1, expected_state_changes_count_1); // Second transaction: storage cell starts and ends with value 1. let mut state = TransactionalState::create_transactional(&mut state); - let account_tx = account_invoke_tx(InvokeTxArgs { + let account_tx = invoke_tx_with_default_flags(InvokeTxArgs { nonce: nonce_manager.next(account_address), ..invoke_args.clone() }); let execution_info = - account_tx.execute_raw(&mut state, &block_context, execution_flags).unwrap(); + account_tx.execute_raw(&mut state, &block_context, concurrency_mode).unwrap(); let fee_2 = execution_info.receipt.fee; let state_changes_2 = state.get_actual_state_changes().unwrap(); @@ -1441,19 +1603,19 @@ fn test_count_actual_storage_changes( n_allocated_keys: 0, }; - assert_eq!(expected_modified_contracts_2, state_changes_2.state_maps.get_modified_contracts()); + assert_eq!(expected_modified_contracts_2, state_changes_2.state_maps.get_contract_addresses()); assert_eq!(expected_storage_updates_2, state_changes_2.state_maps.storage); assert_eq!(state_changes_count_2, expected_state_changes_count_2); // Transfer transaction: transfer 1 ETH to recepient. let mut state = TransactionalState::create_transactional(&mut state); - let account_tx = account_invoke_tx(InvokeTxArgs { + let account_tx = invoke_tx_with_default_flags(InvokeTxArgs { nonce: nonce_manager.next(account_address), calldata: transfer_calldata, ..invoke_args }); let execution_info = - account_tx.execute_raw(&mut state, &block_context, execution_flags).unwrap(); + account_tx.execute_raw(&mut state, &block_context, concurrency_mode).unwrap(); let fee_transfer = execution_info.receipt.fee; let state_changes_transfer = state.get_actual_state_changes().unwrap(); @@ -1493,49 +1655,51 @@ fn test_count_actual_storage_changes( assert_eq!( expected_modified_contracts_transfer, - state_changes_transfer.state_maps.get_modified_contracts() + state_changes_transfer.state_maps.get_contract_addresses() ); assert_eq!(expected_storage_update_transfer, state_changes_transfer.state_maps.storage); assert_eq!(state_changes_count_3, expected_state_changes_count_3); } #[rstest] -#[case::tx_version_1(TransactionVersion::ONE)] -#[case::tx_version_3(TransactionVersion::THREE)] +#[case::tx_version_1(TransactionVersion::ONE, RunnableCairo1::Casm)] +#[case::tx_version_3(TransactionVersion::THREE, RunnableCairo1::Casm)] +#[cfg_attr( + feature = "cairo_native", + case::tx_version_3_native(TransactionVersion::THREE, RunnableCairo1::Native) +)] fn test_concurrency_execute_fee_transfer( + block_context: BlockContext, max_fee: Fee, default_all_resource_bounds: ValidResourceBounds, #[case] version: TransactionVersion, + #[case] runnable: RunnableCairo1, ) { // TODO(Meshi, 01/06/2024): make the test so it will include changes in // sequencer_balance_key_high. const TRANSFER_AMOUNT: u128 = 100; const SEQUENCER_BALANCE_LOW_INITIAL: u128 = 50; - - let block_context = BlockContext::create_for_account_testing(); - let account = FeatureContract::AccountWithoutValidations(CairoVersion::Cairo1); - let test_contract = FeatureContract::TestContract(CairoVersion::Cairo0); let chain_info = &block_context.chain_info; - let state = &mut test_state(chain_info, BALANCE, &[(account, 1), (test_contract, 1)]); + let TestInitData { mut state, account_address, contract_address, .. } = + create_test_init_data(chain_info, CairoVersion::Cairo1(runnable)); let (sequencer_balance_key_low, sequencer_balance_key_high) = get_sequencer_balance_keys(&block_context); - let account_tx = account_invoke_tx(invoke_tx_args! { - sender_address: account.get_instance_address(0), + let account_tx = invoke_tx_with_default_flags(invoke_tx_args! { + sender_address: account_address, max_fee, - calldata: create_trivial_calldata(test_contract.get_instance_address(0)), + calldata: create_trivial_calldata(contract_address), resource_bounds: default_all_resource_bounds, version }); let fee_type = &account_tx.fee_type(); - let fee_token_address = block_context.chain_info.fee_token_address(fee_type); + let fee_token_address = chain_info.fee_token_address(fee_type); - // Case 1: The transaction did not read form/ write to the sequenser balance before executing + // Case 1: The transaction did not read from/ write to the sequencer balance before executing // fee transfer. - let mut transactional_state = TransactionalState::create_transactional(state); - let execution_flags = - ExecutionFlags { charge_fee: true, validate: true, concurrency_mode: true }; + let mut transactional_state = TransactionalState::create_transactional(&mut state); + let concurrency_mode = true; let result = - account_tx.execute_raw(&mut transactional_state, &block_context, execution_flags).unwrap(); + account_tx.execute_raw(&mut transactional_state, &block_context, concurrency_mode).unwrap(); assert!(!result.is_reverted()); let transactional_cache = transactional_state.cache.borrow(); for storage in [ @@ -1547,7 +1711,7 @@ fn test_concurrency_execute_fee_transfer( } } - // Case 2: The transaction read from and write to the sequenser balance before executing fee + // Case 2: The transaction read from and write to the sequencer balance before executing fee // transfer. let transfer_calldata = create_calldata( @@ -1563,25 +1727,25 @@ fn test_concurrency_execute_fee_transfer( Fee(SEQUENCER_BALANCE_LOW_INITIAL), &mut state.state, ); - let mut transactional_state = TransactionalState::create_transactional(state); + let mut transactional_state = TransactionalState::create_transactional(&mut state); // Invokes transfer to the sequencer. - let account_tx = account_invoke_tx(invoke_tx_args! { - sender_address: account.get_instance_address(0), + let account_tx = invoke_tx_with_default_flags(invoke_tx_args! { + sender_address: account_address, calldata: transfer_calldata, max_fee, resource_bounds: default_all_resource_bounds, }); let execution_result = - account_tx.execute_raw(&mut transactional_state, &block_context, execution_flags); + account_tx.execute_raw(&mut transactional_state, &block_context, concurrency_mode); let result = execution_result.unwrap(); assert!(!result.is_reverted()); // Check that the sequencer balance was not updated. let storage_writes = transactional_state.cache.borrow().writes.storage.clone(); let storage_initial_reads = transactional_state.cache.borrow().initial_reads.storage.clone(); - for (seq_write_val, expexted_write_val) in [ + for (seq_write_val, expected_write_val) in [ ( storage_writes.get(&(fee_token_address, sequencer_balance_key_low)), // Balance after `execute` and without the fee transfer. @@ -1594,44 +1758,46 @@ fn test_concurrency_execute_fee_transfer( (storage_writes.get(&(fee_token_address, sequencer_balance_key_high)), Felt::ZERO), (storage_initial_reads.get(&(fee_token_address, sequencer_balance_key_high)), Felt::ZERO), ] { - assert_eq!(*seq_write_val.unwrap(), expexted_write_val); + assert_eq!(*seq_write_val.unwrap(), expected_write_val); } } // Check that when the sequencer is the sender, we run the sequential fee transfer. #[rstest] -#[case::tx_version_1(TransactionVersion::ONE)] -#[case::tx_version_3(TransactionVersion::THREE)] +#[case::tx_version_1(TransactionVersion::ONE, RunnableCairo1::Casm)] +#[case::tx_version_3(TransactionVersion::THREE, RunnableCairo1::Casm)] +#[cfg_attr( + feature = "cairo_native", + case::tx_version_3_native(TransactionVersion::THREE, RunnableCairo1::Native) +)] fn test_concurrent_fee_transfer_when_sender_is_sequencer( + mut block_context: BlockContext, max_fee: Fee, default_all_resource_bounds: ValidResourceBounds, #[case] version: TransactionVersion, + #[case] runnable: RunnableCairo1, ) { - let mut block_context = BlockContext::create_for_account_testing(); - let account = FeatureContract::AccountWithoutValidations(CairoVersion::Cairo1); - let account_address = account.get_instance_address(0_u16); + let chain_info = &block_context.chain_info; + let TestInitData { mut state, account_address, contract_address, .. } = + create_test_init_data(chain_info, CairoVersion::Cairo1(runnable)); block_context.block_info.sequencer_address = account_address; - let test_contract = FeatureContract::TestContract(CairoVersion::Cairo0); let sender_balance = BALANCE; - let chain_info = &block_context.chain_info; - let state = &mut test_state(chain_info, sender_balance, &[(account, 1), (test_contract, 1)]); let (sequencer_balance_key_low, sequencer_balance_key_high) = get_sequencer_balance_keys(&block_context); - let account_tx = account_invoke_tx(invoke_tx_args! { + let account_tx = invoke_tx_with_default_flags(invoke_tx_args! { max_fee, sender_address: account_address, - calldata: create_trivial_calldata(test_contract.get_instance_address(0)), + calldata: create_trivial_calldata(contract_address), resource_bounds: default_all_resource_bounds, version }); let fee_type = &account_tx.fee_type(); - let fee_token_address = block_context.chain_info.fee_token_address(fee_type); + let fee_token_address = chain_info.fee_token_address(fee_type); - let mut transactional_state = TransactionalState::create_transactional(state); - let execution_flags = - ExecutionFlags { charge_fee: true, validate: true, concurrency_mode: true }; + let mut transactional_state = TransactionalState::create_transactional(&mut state); + let concurrency_mode = true; let result = - account_tx.execute_raw(&mut transactional_state, &block_context, execution_flags).unwrap(); + account_tx.execute_raw(&mut transactional_state, &block_context, concurrency_mode).unwrap(); assert!(!result.is_reverted()); // Check that the sequencer balance was updated (in this case, was not changed). for (seq_key, seq_value) in @@ -1644,19 +1810,22 @@ fn test_concurrent_fee_transfer_when_sender_is_sequencer( /// Check initial gas is as expected according to the contract cairo+compiler version, and call /// history. #[rstest] -#[case(&[ - CompilerBasedVersion::CairoVersion(CairoVersion::Cairo1), - CompilerBasedVersion::CairoVersion(CairoVersion::Cairo1), +#[case::cairo0(&[ + CompilerBasedVersion::CairoVersion(CairoVersion::Cairo1(RunnableCairo1::Casm)), + CompilerBasedVersion::CairoVersion(CairoVersion::Cairo1(RunnableCairo1::Casm)), CompilerBasedVersion::CairoVersion(CairoVersion::Cairo0), - CompilerBasedVersion::CairoVersion(CairoVersion::Cairo1) -])] -// TODO(Tzahi, 1/12/2024): Add a case with OldCairo1 instead of Cairo0. + CompilerBasedVersion::CairoVersion(CairoVersion::Cairo1(RunnableCairo1::Casm))])] +#[case::old_cairo1(&[ + CompilerBasedVersion::CairoVersion(CairoVersion::Cairo1(RunnableCairo1::Casm)), + CompilerBasedVersion::CairoVersion(CairoVersion::Cairo1(RunnableCairo1::Casm)), + CompilerBasedVersion::OldCairo1, + CompilerBasedVersion::CairoVersion(CairoVersion::Cairo1(RunnableCairo1::Casm))])] fn test_initial_gas( + block_context: BlockContext, #[case] versions: &[CompilerBasedVersion], default_all_resource_bounds: ValidResourceBounds, ) { - let block_context = BlockContext::create_for_account_testing(); - let account_version = CairoVersion::Cairo1; + let account_version = CairoVersion::Cairo1(RunnableCairo1::Casm); let account = FeatureContract::AccountWithoutValidations(account_version); let account_address = account.get_instance_address(0_u16); let used_test_contracts: HashSet = @@ -1670,24 +1839,36 @@ fn test_initial_gas( sender_balance, &contracts.into_iter().map(|contract| (contract, 1u16)).collect::>(), ); - let account_tx = account_invoke_tx(invoke_tx_args! { + let account_tx = invoke_tx_with_default_flags(invoke_tx_args! { sender_address: account_address, calldata: build_recurse_calldata(versions), resource_bounds: default_all_resource_bounds, version: TransactionVersion::THREE }); + let user_gas_bound = block_context.to_tx_context(&account_tx).initial_sierra_gas(); - let transaction_ex_info = account_tx.execute(state, &block_context, true, true).unwrap(); + let transaction_ex_info = account_tx.execute(state, &block_context).unwrap(); let validate_call_info = &transaction_ex_info.validate_call_info.unwrap(); let validate_initial_gas = validate_call_info.call.initial_gas; - assert_eq!(validate_initial_gas, DEFAULT_L2_GAS_MAX_AMOUNT.0); + assert_eq!( + validate_initial_gas, + block_context.versioned_constants.os_constants.validate_max_sierra_gas.0 + ); let validate_gas_consumed = validate_call_info.execution.gas_consumed; assert!(validate_gas_consumed > 0, "New Cairo1 contract should consume gas."); let default_call_info = CallInfo::default(); - let mut prev_initial_gas = validate_initial_gas; let mut execute_call_info = &transaction_ex_info.execute_call_info.unwrap(); + // Initial gas for execution is the minimum between the max execution gas and the initial gas + // minus the gas consumed by validate. Need to add 1 as the check is strictly less than. + let mut prev_initial_gas = block_context + .versioned_constants + .os_constants + .execute_max_sierra_gas + .min(user_gas_bound - GasAmount(validate_gas_consumed) + GasAmount(1)) + .0; + let mut curr_initial_gas; let mut started_vm_mode = false; // The __validate__ call of a the account contract. @@ -1697,7 +1878,12 @@ fn test_initial_gas( curr_initial_gas = execute_call_info.call.initial_gas; match (prev_version, version, started_vm_mode) { - (CompilerBasedVersion::CairoVersion(CairoVersion::Cairo0), _, _) => { + ( + CompilerBasedVersion::CairoVersion(CairoVersion::Cairo0) + | CompilerBasedVersion::OldCairo1, + _, + _, + ) => { assert_eq!(started_vm_mode, true); assert_eq!(curr_initial_gas, prev_initial_gas); } @@ -1708,18 +1894,21 @@ fn test_initial_gas( false, ) => { // First time we are in VM mode. - assert_eq!(prev_version, &CompilerBasedVersion::CairoVersion(CairoVersion::Cairo1)); + assert_matches!( + prev_version, + &CompilerBasedVersion::CairoVersion(CairoVersion::Cairo1(_)) + ); assert_eq!( curr_initial_gas, - block_context.versioned_constants.default_initial_gas_cost() + block_context.versioned_constants.infinite_gas_for_vm_mode() ); started_vm_mode = true; } _ => { - // prev_version is a non Cairo0 contract, thus it consumes gas from the initial + // prev_version is a non CairoStep contract, thus it consumes gas from the initial // gas. assert!(curr_initial_gas < prev_initial_gas); - if version == &CompilerBasedVersion::CairoVersion(CairoVersion::Cairo1) { + if matches!(version, &CompilerBasedVersion::CairoVersion(CairoVersion::Cairo1(_))) { assert!(execute_call_info.execution.gas_consumed > 0); } else { assert!(execute_call_info.execution.gas_consumed == 0); @@ -1737,16 +1926,18 @@ fn test_initial_gas( } #[rstest] +#[case::cairo1(CairoVersion::Cairo1(RunnableCairo1::Casm))] +#[cfg_attr( + feature = "cairo_native", + case::cairo1_native(CairoVersion::Cairo1(RunnableCairo1::Native)) +)] fn test_revert_in_execute( block_context: BlockContext, default_all_resource_bounds: ValidResourceBounds, + #[case] cairo_version: CairoVersion, ) { - let account = FeatureContract::AccountWithoutValidations(CairoVersion::Cairo1); - let chain_info = &block_context.chain_info; - let state = &mut test_state(chain_info, BALANCE, &[(account, 1)]); - let account_address = account.get_instance_address(0); - let mut nonce_manager = NonceManager::default(); - + let TestInitData { mut state, account_address, mut nonce_manager, .. } = + create_test_init_data(&block_context.chain_info, cairo_version); // Invoke a function that changes the state and reverts. let tx_args = invoke_tx_args! { sender_address: account_address, @@ -1756,12 +1947,13 @@ fn test_revert_in_execute( // Skip validate phase, as we want to test the revert in the execute phase. let validate = false; - let tx_execution_info = account_invoke_tx(invoke_tx_args! { + let tx = executable_invoke_tx(invoke_tx_args! { resource_bounds: default_all_resource_bounds, ..tx_args - }) - .execute(state, &block_context, true, validate) - .unwrap(); + }); + let execution_flags = AccountExecutionFlags { validate, ..AccountExecutionFlags::default() }; + let account_tx = AccountTransaction { tx, execution_flags }; + let tx_execution_info = account_tx.execute(&mut state, &block_context).unwrap(); assert!(tx_execution_info.is_reverted()); assert!( @@ -1774,8 +1966,8 @@ fn test_revert_in_execute( } #[rstest] -#[cfg_attr(feature = "cairo_native", case::native(CairoVersion::Native))] -#[case::vm(CairoVersion::Cairo1)] +#[cfg_attr(feature = "cairo_native", case::native(CairoVersion::Cairo1(RunnableCairo1::Native)))] +#[case::vm(CairoVersion::Cairo1(RunnableCairo1::Casm))] fn test_call_contract_that_panics( #[case] cairo_version: CairoVersion, mut block_context: BlockContext, @@ -1785,36 +1977,32 @@ fn test_call_contract_that_panics( ) { // Override enable reverts. block_context.versioned_constants.enable_reverts = enable_reverts; - let test_contract = FeatureContract::TestContract(cairo_version); - // TODO(Yoni): use `class_version` here once the feature contract fully supports Native. - let account = FeatureContract::AccountWithoutValidations(CairoVersion::Cairo1); - let chain_info = &block_context.chain_info; - let state = &mut test_state(chain_info, BALANCE, &[(test_contract, 1), (account, 1)]); - let test_contract_address = test_contract.get_instance_address(0); - let account_address = account.get_instance_address(0); - let mut nonce_manager = NonceManager::default(); + let TestInitData { mut state, account_address, contract_address, mut nonce_manager } = + create_test_init_data(&block_context.chain_info, cairo_version); - let new_class_hash = test_contract.get_class_hash(); + let new_class_hash = FeatureContract::TestContract(cairo_version).get_class_hash(); + let to_panic = true.into(); let calldata = [ - *FeatureContract::TestContract(CairoVersion::Cairo1).get_instance_address(0).0.key(), + *contract_address.0.key(), selector_from_name(inner_selector).0, - felt!(1_u8), + felt!(2_u8), new_class_hash.0, + to_panic, ]; // Invoke a function that changes the state and reverts. let tx_args = invoke_tx_args! { sender_address: account_address, calldata: create_calldata( - test_contract_address, + contract_address, "test_call_contract_revert", &calldata ), nonce: nonce_manager.next(account_address) }; let tx_execution_info = run_invoke_tx( - state, + &mut state, &block_context, invoke_tx_args! { resource_bounds: default_all_resource_bounds, diff --git a/crates/blockifier/src/transaction/errors.rs b/crates/blockifier/src/transaction/errors.rs index e166d1ad654..b576626ae56 100644 --- a/crates/blockifier/src/transaction/errors.rs +++ b/crates/blockifier/src/transaction/errors.rs @@ -16,6 +16,24 @@ use crate::execution::stack_trace::{gen_tx_execution_error_trace, Cairo1RevertSu use crate::fee::fee_checks::FeeCheckError; use crate::state::errors::StateError; +#[derive(Debug, Error)] +pub enum ResourceBoundsError { + #[error( + "Max {resource} price ({max_gas_price}) is lower than the actual gas price: \ + {actual_gas_price}." + )] + MaxGasPriceTooLow { resource: Resource, max_gas_price: GasPrice, actual_gas_price: GasPrice }, + #[error( + "Max {resource} amount ({max_gas_amount}) is lower than the minimal gas amount: \ + {minimal_gas_amount}." + )] + MaxGasAmountTooLow { + resource: Resource, + max_gas_amount: GasAmount, + minimal_gas_amount: GasAmount, + }, +} + // TODO(Yoni, 1/9/2024): implement Display for Fee. #[derive(Debug, Error)] pub enum TransactionFeeError { @@ -43,20 +61,8 @@ pub enum TransactionFeeError { MaxFeeExceedsBalance { max_fee: Fee, balance: BigUint }, #[error("Max fee ({}) is too low. Minimum fee: {}.", max_fee.0, min_fee.0)] MaxFeeTooLow { min_fee: Fee, max_fee: Fee }, - #[error( - "Max {resource} price ({max_gas_price}) is lower than the actual gas price: \ - {actual_gas_price}." - )] - MaxGasPriceTooLow { resource: Resource, max_gas_price: GasPrice, actual_gas_price: GasPrice }, - #[error( - "Max {resource} amount ({max_gas_amount}) is lower than the minimal gas amount: \ - {minimal_gas_amount}." - )] - MaxGasAmountTooLow { - resource: Resource, - max_gas_amount: GasAmount, - minimal_gas_amount: GasAmount, - }, + #[error("Resource bounds were not satisfied: {}", errors.iter().map(|e| format!("{}", e)).collect::>().join("\n"))] + InsufficientResourceBounds { errors: Vec }, #[error("Missing L1 gas bounds in resource bounds.")] MissingL1GasBounds, #[error(transparent)] diff --git a/crates/blockifier/src/transaction/execution_flavors_test.rs b/crates/blockifier/src/transaction/execution_flavors_test.rs index 3f6a43b4d1b..7f712dd9e4d 100644 --- a/crates/blockifier/src/transaction/execution_flavors_test.rs +++ b/crates/blockifier/src/transaction/execution_flavors_test.rs @@ -1,10 +1,19 @@ use assert_matches::assert_matches; +use blockifier_test_utils::cairo_versions::CairoVersion; +use blockifier_test_utils::calldata::{create_calldata, create_trivial_calldata}; +use blockifier_test_utils::contracts::FeatureContract; use pretty_assertions::assert_eq; use rstest::rstest; +use starknet_api::block::FeeType; use starknet_api::core::ContractAddress; use starknet_api::execution_resources::{GasAmount, GasVector}; -use starknet_api::test_utils::invoke::InvokeTxArgs; -use starknet_api::test_utils::NonceManager; +use starknet_api::test_utils::invoke::{executable_invoke_tx, InvokeTxArgs}; +use starknet_api::test_utils::{ + NonceManager, + DEFAULT_L1_GAS_AMOUNT, + DEFAULT_STRK_L1_GAS_PRICE, + MAX_FEE, +}; use starknet_api::transaction::fields::{ Calldata, Fee, @@ -17,34 +26,26 @@ use starknet_api::transaction::TransactionVersion; use starknet_api::{felt, invoke_tx_args, nonce}; use starknet_types_core::felt::Felt; +use crate::blockifier_versioned_constants::AllocationCost; use crate::context::{BlockContext, ChainInfo}; use crate::execution::syscalls::SyscallSelector; use crate::fee::fee_utils::get_fee_by_gas_vector; use crate::state::cached_state::CachedState; use crate::state::state_api::StateReader; -use crate::test_utils::contracts::FeatureContract; use crate::test_utils::dict_state_reader::DictStateReader; use crate::test_utils::initial_test_state::test_state; -use crate::test_utils::{ - create_calldata, - create_trivial_calldata, - get_syscall_resources, - get_tx_resources, - CairoVersion, - BALANCE, - DEFAULT_L1_GAS_AMOUNT, - DEFAULT_STRK_L1_GAS_PRICE, - MAX_FEE, -}; +use crate::test_utils::{get_const_syscall_resources, get_tx_resources, BALANCE}; +use crate::transaction::account_transaction::{AccountTransaction, ExecutionFlags}; use crate::transaction::errors::{ + ResourceBoundsError, TransactionExecutionError, TransactionFeeError, TransactionPreValidationError, }; -use crate::transaction::objects::{FeeType, TransactionExecutionInfo, TransactionExecutionResult}; +use crate::transaction::objects::{TransactionExecutionInfo, TransactionExecutionResult}; use crate::transaction::test_utils::{ - account_invoke_tx, default_l1_resource_bounds, + invoke_tx_with_default_flags, l1_resource_bounds, INVALID, }; @@ -144,7 +145,6 @@ fn calculate_actual_gas( } /// Asserts gas used and reported fee are as expected. -// TODO(Aner, 21/01/24) modify for 4844 (taking blob_gas into account). fn check_gas_and_fee( block_context: &BlockContext, tx_execution_info: &TransactionExecutionInfo, @@ -181,7 +181,6 @@ fn recurse_calldata(contract_address: ContractAddress, fail: bool, depth: u32) - fn get_pre_validate_test_args( cairo_version: CairoVersion, version: TransactionVersion, - only_query: bool, ) -> (BlockContext, CachedState, InvokeTxArgs, NonceManager) { let block_context = BlockContext::create_for_account_testing(); let max_fee = MAX_FEE; @@ -199,7 +198,6 @@ fn get_pre_validate_test_args( sender_address: account_address, calldata: create_trivial_calldata(test_contract_address), version, - only_query, }; (block_context, state, pre_validation_base_args, nonce_manager) } @@ -215,15 +213,18 @@ fn test_invalid_nonce_pre_validate( #[values(TransactionVersion::ONE, TransactionVersion::THREE)] version: TransactionVersion, ) { let (block_context, mut state, pre_validation_base_args, _) = - get_pre_validate_test_args(cairo_version, version, only_query); + get_pre_validate_test_args(cairo_version, version); let account_address = pre_validation_base_args.sender_address; // First scenario: invalid nonce. Regardless of flags, should fail. let invalid_nonce = nonce!(7_u8); let account_nonce = state.get_nonce_at(account_address).unwrap(); - let result = - account_invoke_tx(invoke_tx_args! {nonce: invalid_nonce, ..pre_validation_base_args}) - .execute(&mut state, &block_context, charge_fee, validate); + let tx = + executable_invoke_tx(invoke_tx_args! {nonce: invalid_nonce, ..pre_validation_base_args}); + let execution_flags = + ExecutionFlags { only_query, charge_fee, validate, strict_nonce_check: true }; + let account_tx = AccountTransaction { tx, execution_flags }; + let result = account_tx.execute(&mut state, &block_context); assert_matches!( result.unwrap_err(), TransactionExecutionError::TransactionPreValidationError( @@ -256,17 +257,18 @@ fn test_simulate_validate_pre_validate_with_charge_fee( ) { let charge_fee = true; let (block_context, mut state, pre_validation_base_args, mut nonce_manager) = - get_pre_validate_test_args(cairo_version, version, only_query); + get_pre_validate_test_args(cairo_version, version); let account_address = pre_validation_base_args.sender_address; // First scenario: minimal fee not covered. Actual fee is precomputed. - let err = account_invoke_tx(invoke_tx_args! { + let err = invoke_tx_with_default_flags(invoke_tx_args! { max_fee: Fee(10), resource_bounds: l1_resource_bounds(10_u8.into(), 10_u8.into()), nonce: nonce_manager.next(account_address), + ..pre_validation_base_args.clone() }) - .execute(&mut state, &block_context, charge_fee, validate) + .execute(&mut state, &block_context) .unwrap_err(); nonce_manager.rollback(account_address); @@ -284,25 +286,40 @@ fn test_simulate_validate_pre_validate_with_charge_fee( err, TransactionExecutionError::TransactionPreValidationError( TransactionPreValidationError::TransactionFeeError( - TransactionFeeError::MaxGasAmountTooLow { resource , .. } + TransactionFeeError::InsufficientResourceBounds { errors } ) - ) if resource == Resource::L1Gas + ) => + assert_matches!( + errors[0], + ResourceBoundsError::MaxGasAmountTooLow { resource , .. } + if resource == Resource::L1Gas + ) ); } // Second scenario: resource bounds greater than balance. - let gas_price = block_context.block_info.gas_prices.get_l1_gas_price_by_fee_type(&fee_type); + let gas_price = block_context.block_info.gas_prices.l1_gas_price(&fee_type); let balance_over_gas_price = BALANCE.checked_div(gas_price).unwrap(); - let result = account_invoke_tx(invoke_tx_args! { + let tx = executable_invoke_tx(invoke_tx_args! { max_fee: Fee(BALANCE.0 + 1), resource_bounds: l1_resource_bounds( (balance_over_gas_price.0 + 10).into(), gas_price.into() ), nonce: nonce_manager.next(account_address), + ..pre_validation_base_args.clone() - }) - .execute(&mut state, &block_context, charge_fee, validate); + }); + let account_tx = AccountTransaction { + tx, + execution_flags: ExecutionFlags { + only_query, + charge_fee, + validate, + strict_nonce_check: true, + }, + }; + let result = account_tx.execute(&mut state, &block_context); nonce_manager.rollback(account_address); if is_deprecated { @@ -328,23 +345,36 @@ fn test_simulate_validate_pre_validate_with_charge_fee( // Third scenario: L1 gas price bound lower than the price on the block. if !is_deprecated { - let err = account_invoke_tx(invoke_tx_args! { + let tx = executable_invoke_tx(invoke_tx_args! { resource_bounds: l1_resource_bounds(DEFAULT_L1_GAS_AMOUNT, (gas_price.get().0 - 1).into()), nonce: nonce_manager.next(account_address), + ..pre_validation_base_args - }) - .execute(&mut state, &block_context, charge_fee, validate) - .unwrap_err(); + }); + let account_tx = AccountTransaction { + tx, + execution_flags: ExecutionFlags { + only_query, + charge_fee, + validate, + ..Default::default() + }, + }; + let err = account_tx.execute(&mut state, &block_context).unwrap_err(); nonce_manager.rollback(account_address); assert_matches!( err, TransactionExecutionError::TransactionPreValidationError( TransactionPreValidationError::TransactionFeeError( - TransactionFeeError::MaxGasPriceTooLow { resource, .. } + TransactionFeeError::InsufficientResourceBounds{ errors } ) + ) => + assert_matches!( + errors[0], + ResourceBoundsError::MaxGasPriceTooLow { resource, .. } + if resource == Resource::L1Gas ) - if resource == Resource::L1Gas ); } } @@ -364,20 +394,28 @@ fn test_simulate_validate_pre_validate_not_charge_fee( ) { let charge_fee = false; let (block_context, mut state, pre_validation_base_args, mut nonce_manager) = - get_pre_validate_test_args(cairo_version, version, only_query); + get_pre_validate_test_args(cairo_version, version); let account_address = pre_validation_base_args.sender_address; - let tx_execution_info = account_invoke_tx(invoke_tx_args! { + let tx = executable_invoke_tx(invoke_tx_args! { nonce: nonce_manager.next(account_address), ..pre_validation_base_args.clone() - }) - .execute(&mut state, &block_context, charge_fee, false) - .unwrap(); + }); + let account_tx = AccountTransaction { + tx, + execution_flags: ExecutionFlags { + only_query, + charge_fee, + validate: false, + ..Default::default() + }, + }; + let tx_execution_info = account_tx.execute(&mut state, &block_context).unwrap(); let base_gas = calculate_actual_gas(&tx_execution_info, &block_context, false); assert!( base_gas > u64_from_usize( - get_syscall_resources(SyscallSelector::CallContract).n_steps + get_const_syscall_resources(SyscallSelector::CallContract).n_steps + get_tx_resources(TransactionType::InvokeFunction).n_steps ) .into() @@ -386,14 +424,23 @@ fn test_simulate_validate_pre_validate_not_charge_fee( let (actual_gas_used, actual_fee) = gas_and_fee(base_gas, validate, &fee_type); macro_rules! execute_and_check_gas_and_fee { ($max_fee:expr, $resource_bounds:expr) => {{ - let tx_execution_info = account_invoke_tx(invoke_tx_args! { + let tx = executable_invoke_tx(invoke_tx_args! { max_fee: $max_fee, resource_bounds: $resource_bounds, nonce: nonce_manager.next(account_address), + ..pre_validation_base_args.clone() - }) - .execute(&mut state, &block_context, charge_fee, validate) - .unwrap(); + }); + let account_tx = AccountTransaction { + tx, + execution_flags: ExecutionFlags { + only_query, + charge_fee, + validate, + ..Default::default() + }, + }; + let tx_execution_info = account_tx.execute(&mut state, &block_context).unwrap(); check_gas_and_fee( &block_context, &tx_execution_info, @@ -409,7 +456,7 @@ fn test_simulate_validate_pre_validate_not_charge_fee( execute_and_check_gas_and_fee!(Fee(10), l1_resource_bounds(10_u8.into(), 10_u8.into())); // Second scenario: resource bounds greater than balance. - let gas_price = block_context.block_info.gas_prices.get_l1_gas_price_by_fee_type(&fee_type); + let gas_price = block_context.block_info.gas_prices.l1_gas_price(&fee_type); let balance_over_gas_price = BALANCE.checked_div(gas_price).unwrap(); execute_and_check_gas_and_fee!( Fee(BALANCE.0 + 1), @@ -446,7 +493,7 @@ fn execute_fail_validation( } = create_flavors_test_state(&block_context.chain_info, cairo_version); // Validation scenario: fallible validation. - account_invoke_tx(invoke_tx_args! { + let tx = executable_invoke_tx(invoke_tx_args! { max_fee, resource_bounds: max_resource_bounds, signature: TransactionSignature(vec![ @@ -457,9 +504,17 @@ fn execute_fail_validation( calldata: create_calldata(faulty_account_address, "foo", &[]), version, nonce: nonce_manager.next(faulty_account_address), - only_query, - }) - .execute(&mut falliable_state, &block_context, charge_fee, validate) + }); + let account_tx = AccountTransaction { + tx, + execution_flags: ExecutionFlags { + only_query, + charge_fee, + validate, + strict_nonce_check: true, + }, + }; + account_tx.execute(&mut falliable_state, &block_context) } /// Test simulate / charge_fee flag combinations in (fallible) validation stage. @@ -548,7 +603,7 @@ fn test_simulate_validate_charge_fee_mid_execution( ) { let block_context = BlockContext::create_for_account_testing(); let chain_info = &block_context.chain_info; - let gas_price = block_context.block_info.gas_prices.get_l1_gas_price_by_fee_type(&fee_type); + let gas_price = block_context.block_info.gas_prices.l1_gas_price(&fee_type); let FlavorTestInitialState { mut state, account_address, @@ -571,17 +626,24 @@ fn test_simulate_validate_charge_fee_mid_execution( resource_bounds: default_l1_resource_bounds, sender_address: account_address, version, - only_query, }; // First scenario: logic error. Should result in revert; actual fee should be shown. - let tx_execution_info = account_invoke_tx(invoke_tx_args! { + let tx = executable_invoke_tx(invoke_tx_args! { calldata: recurse_calldata(test_contract_address, true, 3), nonce: nonce_manager.next(account_address), ..execution_base_args.clone() - }) - .execute(&mut state, &block_context, charge_fee, validate) - .unwrap(); + }); + let account_tx = AccountTransaction { + tx, + execution_flags: ExecutionFlags { + only_query, + charge_fee, + validate, + strict_nonce_check: true, + }, + }; + let tx_execution_info = account_tx.execute(&mut state, &block_context).unwrap(); let base_gas = calculate_actual_gas(&tx_execution_info, &block_context, validate); let (revert_gas_used, revert_fee) = gas_and_fee(base_gas, validate, &fee_type); assert!( @@ -607,13 +669,13 @@ fn test_simulate_validate_charge_fee_mid_execution( // Second scenario: limit resources via sender bounds. Should revert if and only if step limit // is derived from sender bounds (`charge_fee` mode). - let (gas_bound, fee_bound) = gas_and_fee(6111_u32.into(), validate, &fee_type); + let (gas_bound, fee_bound) = gas_and_fee(6543_u32.into(), validate, &fee_type); // If `charge_fee` is true, execution is limited by sender bounds, so less resources will be // used. Otherwise, execution is limited by block bounds, so more resources will be used. - let (limited_gas_used, limited_fee) = gas_and_fee(7763_u32.into(), validate, &fee_type); + let (limited_gas_used, limited_fee) = gas_and_fee(8195_u32.into(), validate, &fee_type); let (unlimited_gas_used, unlimited_fee) = gas_and_fee( u64_from_usize( - get_syscall_resources(SyscallSelector::CallContract).n_steps + get_const_syscall_resources(SyscallSelector::CallContract).n_steps + get_tx_resources(TransactionType::InvokeFunction).n_steps + 5730, ) @@ -621,15 +683,23 @@ fn test_simulate_validate_charge_fee_mid_execution( validate, &fee_type, ); - let tx_execution_info = account_invoke_tx(invoke_tx_args! { + let tx = executable_invoke_tx(invoke_tx_args! { max_fee: fee_bound, resource_bounds: l1_resource_bounds(gas_bound, gas_price.into()), calldata: recurse_calldata(test_contract_address, false, 1000), nonce: nonce_manager.next(account_address), ..execution_base_args.clone() - }) - .execute(&mut state, &block_context, charge_fee, validate) - .unwrap(); + }); + let account_tx = AccountTransaction { + tx, + execution_flags: ExecutionFlags { + only_query, + charge_fee, + validate, + strict_nonce_check: true, + }, + }; + let tx_execution_info = account_tx.execute(&mut state, &block_context).unwrap(); assert_eq!(tx_execution_info.is_reverted(), charge_fee); if charge_fee { assert!( @@ -674,15 +744,24 @@ fn test_simulate_validate_charge_fee_mid_execution( GasVector::from_l1_gas(block_limit_gas), &fee_type, ); - let tx_execution_info = account_invoke_tx(invoke_tx_args! { + + let tx = executable_invoke_tx(invoke_tx_args! { max_fee: huge_fee, resource_bounds: l1_resource_bounds(huge_gas_limit, gas_price.into()), calldata: recurse_calldata(test_contract_address, false, 10000), nonce: nonce_manager.next(account_address), ..execution_base_args - }) - .execute(&mut state, &low_step_block_context, charge_fee, validate) - .unwrap(); + }); + let account_tx = AccountTransaction { + tx, + execution_flags: ExecutionFlags { + only_query, + charge_fee, + validate, + strict_nonce_check: true, + }, + }; + let tx_execution_info = account_tx.execute(&mut state, &low_step_block_context).unwrap(); assert!( tx_execution_info.revert_error.clone().unwrap().to_string().contains("no remaining steps") ); @@ -713,8 +792,9 @@ fn test_simulate_validate_charge_fee_post_execution( #[case] fee_type: FeeType, #[case] is_deprecated: bool, ) { - let block_context = BlockContext::create_for_account_testing(); - let gas_price = block_context.block_info.gas_prices.get_l1_gas_price_by_fee_type(&fee_type); + let mut block_context = BlockContext::create_for_account_testing(); + block_context.versioned_constants.allocation_cost = AllocationCost::ZERO; + let gas_price = block_context.block_info.gas_prices.l1_gas_price(&fee_type); let chain_info = &block_context.chain_info; let fee_token_address = chain_info.fee_token_address(&fee_type); @@ -738,37 +818,41 @@ fn test_simulate_validate_charge_fee_post_execution( // If `charge_fee` is false - we do not revert, and simply report the fee and resources as used. // If `charge_fee` is true, we revert, charge the maximal allowed fee (derived from sender // bounds), and report resources base on execution steps reverted + other overhead. - let base_gas_bound = 8010_u32.into(); + let invoke_steps = u64_from_usize(get_tx_resources(TransactionType::InvokeFunction).n_steps); + let base_gas_bound = (invoke_steps + 2485).into(); let (just_not_enough_gas_bound, just_not_enough_fee_bound) = gas_and_fee(base_gas_bound, validate, &fee_type); // `__validate__` and overhead resources + number of reverted steps, comes out slightly more // than the gas bound. - let (revert_gas_usage, revert_fee) = gas_and_fee( - (u64_from_usize(get_tx_resources(TransactionType::InvokeFunction).n_steps) + 5730).into(), - validate, - &fee_type, - ); + let (revert_gas_usage, revert_fee) = + gas_and_fee((invoke_steps + 4130).into(), validate, &fee_type); let (unlimited_gas_used, unlimited_fee) = gas_and_fee( - u64_from_usize( - get_syscall_resources(SyscallSelector::CallContract).n_steps - + get_tx_resources(TransactionType::InvokeFunction).n_steps - + 5730, - ) + (invoke_steps + + u64_from_usize( + get_const_syscall_resources(SyscallSelector::CallContract).n_steps + 4130, + )) .into(), validate, &fee_type, ); - let tx_execution_info = account_invoke_tx(invoke_tx_args! { + let tx = executable_invoke_tx(invoke_tx_args! { max_fee: just_not_enough_fee_bound, resource_bounds: l1_resource_bounds(just_not_enough_gas_bound, gas_price.into()), - calldata: recurse_calldata(test_contract_address, false, 1000), + calldata: recurse_calldata(test_contract_address, false, 600), nonce: nonce_manager.next(account_address), sender_address: account_address, version, - only_query, - }) - .execute(&mut state, &block_context, charge_fee, validate) - .unwrap(); + }); + let account_tx = AccountTransaction { + tx, + execution_flags: ExecutionFlags { + only_query, + charge_fee, + validate, + strict_nonce_check: true, + }, + }; + let tx_execution_info = account_tx.execute(&mut state, &block_context).unwrap(); assert_eq!(tx_execution_info.is_reverted(), charge_fee); if charge_fee { let expected_error_prefix = @@ -792,20 +876,15 @@ fn test_simulate_validate_charge_fee_post_execution( // Second scenario: balance too low. // Execute a transfer, and make sure we get the expected result. let (success_actual_gas, actual_fee) = gas_and_fee( - u64_from_usize( - get_syscall_resources(SyscallSelector::CallContract).n_steps - + get_tx_resources(TransactionType::InvokeFunction).n_steps - + 4260, - ) - .into(), - validate, - &fee_type, - ); - let (fail_actual_gas, fail_actual_fee) = gas_and_fee( - u64_from_usize(get_tx_resources(TransactionType::InvokeFunction).n_steps + 2252).into(), + (u64_from_usize(get_const_syscall_resources(SyscallSelector::CallContract).n_steps) + + invoke_steps + + 4328) + .into(), validate, &fee_type, ); + let (fail_actual_gas, fail_actual_fee) = + gas_and_fee((invoke_steps + 2252).into(), validate, &fee_type); assert!(felt!(actual_fee.0) < current_balance); let transfer_amount = current_balance - Felt::from(actual_fee.0 / 2); let recipient = felt!(7_u8); @@ -818,17 +897,24 @@ fn test_simulate_validate_charge_fee_post_execution( felt!(0_u8), ], ); - let tx_execution_info = account_invoke_tx(invoke_tx_args! { + let tx = executable_invoke_tx(invoke_tx_args! { max_fee: actual_fee, resource_bounds: l1_resource_bounds(success_actual_gas, gas_price.into()), calldata: transfer_calldata, nonce: nonce_manager.next(account_address), sender_address: account_address, version, - only_query, - }) - .execute(&mut state, &block_context, charge_fee, validate) - .unwrap(); + }); + let account_tx = AccountTransaction { + tx, + execution_flags: ExecutionFlags { + only_query, + charge_fee, + validate, + strict_nonce_check: true, + }, + }; + let tx_execution_info = account_tx.execute(&mut state, &block_context).unwrap(); assert_eq!(tx_execution_info.is_reverted(), charge_fee); if charge_fee { diff --git a/crates/blockifier/src/transaction/objects.rs b/crates/blockifier/src/transaction/objects.rs index 06e0e898352..a3c1e5b4f17 100644 --- a/crates/blockifier/src/transaction/objects.rs +++ b/crates/blockifier/src/transaction/objects.rs @@ -2,16 +2,15 @@ use std::collections::HashMap; use cairo_vm::types::builtin_name::BuiltinName; use cairo_vm::vm::runners::cairo_runner::ExecutionResources; +use starknet_api::block::{BlockInfo, FeeType}; use starknet_api::core::{ContractAddress, Nonce}; use starknet_api::data_availability::DataAvailabilityMode; use starknet_api::execution_resources::GasVector; use starknet_api::transaction::fields::{ AccountDeploymentData, - AllResourceBounds, Fee, GasVectorComputationMode, PaymasterData, - ResourceBounds, Tip, TransactionSignature, ValidResourceBounds, @@ -22,17 +21,15 @@ use starknet_api::transaction::{ TransactionOptions, TransactionVersion, }; -use strum_macros::EnumIter; use crate::abi::constants as abi_constants; -use crate::blockifier::block::BlockInfo; +use crate::blockifier_versioned_constants::VersionedConstants; use crate::execution::call_info::{CallInfo, ExecutionSummary}; use crate::execution::stack_trace::ErrorStack; use crate::fee::fee_checks::FeeCheckError; use crate::fee::fee_utils::get_fee_by_gas_vector; use crate::fee::receipt::TransactionReceipt; use crate::transaction::errors::{TransactionExecutionError, TransactionPreValidationError}; -use crate::versioned_constants::VersionedConstants; #[cfg(test)] #[path = "objects_test.rs"] @@ -130,18 +127,8 @@ pub struct CurrentTransactionInfo { pub account_deployment_data: AccountDeploymentData, } +#[cfg(any(test, feature = "testing"))] impl CurrentTransactionInfo { - /// Fetch the L1 resource bounds, if they exist. - // TODO(Nimrod): Consider removing this function and add equivalent method to - // `ValidResourceBounds`. - pub fn l1_resource_bounds(&self) -> ResourceBounds { - match self.resource_bounds { - ValidResourceBounds::L1Gas(bounds) => bounds, - ValidResourceBounds::AllResources(AllResourceBounds { l1_gas, .. }) => l1_gas, - } - } - - #[cfg(any(test, feature = "testing"))] pub fn create_for_testing() -> Self { Self { common_fields: CommonAccountFields::default(), @@ -240,6 +227,8 @@ impl ExecutionResourcesTraits for ExecutionResources { self.n_steps // Memory holes are slightly cheaper than actual steps, but we count them as such // for simplicity. + // TODO(AvivG): Compute memory_holes gas accurately while maintaining backward compatibility. + // Define memory_holes_gas version_constants as 100 gas (1 step) for previous versions. + self.n_memory_holes // The "segment arena" builtin is not part of the prover (not in any proof layout); // It is transformed into regular steps by the OS program - each instance requires @@ -279,12 +268,6 @@ pub trait HasRelatedFeeType { } } -#[derive(Clone, Copy, Hash, EnumIter, Eq, PartialEq)] -pub enum FeeType { - Strk, - Eth, -} - pub trait TransactionInfoCreator { fn create_tx_info(&self) -> TransactionInfo; } diff --git a/crates/blockifier/src/transaction/objects_test.rs b/crates/blockifier/src/transaction/objects_test.rs index 29ef00aed66..f0b92042e70 100644 --- a/crates/blockifier/src/transaction/objects_test.rs +++ b/crates/blockifier/src/transaction/objects_test.rs @@ -6,6 +6,7 @@ use starknet_api::transaction::L2ToL1Payload; use starknet_api::{class_hash, contract_address, storage_key}; use starknet_types_core::felt::Felt; +use crate::blockifier_versioned_constants::VersionedConstants; use crate::execution::call_info::{ CallExecution, CallInfo, @@ -15,14 +16,14 @@ use crate::execution::call_info::{ MessageToL1, OrderedEvent, OrderedL2ToL1Message, + StorageAccessTracker, }; use crate::execution::entry_point::CallEntryPoint; use crate::transaction::objects::TransactionExecutionInfo; -use crate::versioned_constants::VersionedConstants; #[derive(Debug, Default)] pub struct TestExecutionSummary { - pub gas_for_fee: GasAmount, + pub gas_consumed: GasAmount, pub num_of_events: usize, pub num_of_messages: usize, pub class_hash: ClassHash, @@ -32,7 +33,7 @@ pub struct TestExecutionSummary { impl TestExecutionSummary { pub fn new( - gas_for_fee: u64, + gas_consumed: u64, num_of_events: usize, num_of_messages: usize, class_hash: ClassHash, @@ -40,7 +41,7 @@ impl TestExecutionSummary { storage_key: &str, ) -> Self { TestExecutionSummary { - gas_for_fee: GasAmount(gas_for_fee), + gas_consumed: GasAmount(gas_consumed), num_of_events, num_of_messages, class_hash, @@ -67,13 +68,13 @@ impl TestExecutionSummary { }, }) .collect(), + gas_consumed: self.gas_consumed.0, ..Default::default() }, - charged_resources: ChargedResources { - gas_for_fee: self.gas_for_fee, + storage_access_tracker: StorageAccessTracker { + accessed_storage_keys: vec![self.storage_key].into_iter().collect(), ..Default::default() }, - accessed_storage_keys: vec![self.storage_key].into_iter().collect(), ..Default::default() } } @@ -201,9 +202,9 @@ fn test_summarize( let expected_summary = ExecutionSummary { charged_resources: ChargedResources { - gas_for_fee: validate_params.gas_for_fee - + execute_params.gas_for_fee - + fee_transfer_params.gas_for_fee, + gas_consumed: validate_params.gas_consumed + + execute_params.gas_consumed + + fee_transfer_params.gas_consumed, ..Default::default() }, executed_class_hashes: vec![ diff --git a/crates/blockifier/src/transaction/post_execution_test.rs b/crates/blockifier/src/transaction/post_execution_test.rs index 3ac147f0a36..127932198a7 100644 --- a/crates/blockifier/src/transaction/post_execution_test.rs +++ b/crates/blockifier/src/transaction/post_execution_test.rs @@ -1,8 +1,13 @@ use assert_matches::assert_matches; +use blockifier_test_utils::cairo_versions::CairoVersion; +use blockifier_test_utils::calldata::create_calldata; +use blockifier_test_utils::contracts::FeatureContract; use rstest::rstest; +use starknet_api::block::FeeType; use starknet_api::core::ContractAddress; -use starknet_api::execution_resources::GasAmount; +use starknet_api::execution_resources::{GasAmount, GasVector}; use starknet_api::state::StorageKey; +use starknet_api::test_utils::DEFAULT_STRK_L1_GAS_PRICE; use starknet_api::transaction::fields::{ AllResourceBounds, Calldata, @@ -16,28 +21,22 @@ use starknet_api::transaction::TransactionVersion; use starknet_api::{contract_address, felt, invoke_tx_args}; use starknet_types_core::felt::Felt; +use crate::blockifier_versioned_constants::AllocationCost; use crate::context::{BlockContext, ChainInfo}; use crate::fee::fee_checks::FeeCheckError; +use crate::fee::fee_utils::GasVectorToL1GasForFee; use crate::state::state_api::StateReader; -use crate::test_utils::contracts::FeatureContract; use crate::test_utils::initial_test_state::test_state; -use crate::test_utils::{ - create_calldata, - CairoVersion, - BALANCE, - DEFAULT_STRK_L1_DATA_GAS_PRICE, - DEFAULT_STRK_L1_GAS_PRICE, - DEFAULT_STRK_L2_GAS_PRICE, -}; +use crate::test_utils::BALANCE; use crate::transaction::account_transaction::AccountTransaction; use crate::transaction::errors::TransactionExecutionError; -use crate::transaction::objects::{FeeType, HasRelatedFeeType, TransactionInfoCreator}; +use crate::transaction::objects::{HasRelatedFeeType, TransactionInfoCreator}; use crate::transaction::test_utils::{ - account_invoke_tx, block_context, - create_all_resource_bounds, + create_gas_amount_bounds_with_default_price, default_all_resource_bounds, default_l1_resource_bounds, + invoke_tx_with_default_flags, l1_resource_bounds, max_fee, run_invoke_tx, @@ -86,11 +85,12 @@ fn calldata_for_write_and_transfer( fn test_revert_on_overdraft( max_fee: Fee, default_all_resource_bounds: ValidResourceBounds, - block_context: BlockContext, + mut block_context: BlockContext, #[case] version: TransactionVersion, #[case] fee_type: FeeType, #[values(CairoVersion::Cairo0)] cairo_version: CairoVersion, ) { + block_context.versioned_constants.allocation_cost = AllocationCost::ZERO; let chain_info = &block_context.chain_info; let fee_token_address = chain_info.fee_token_addresses.get_by_fee_type(&fee_type); // An address to be written into to observe state changes. @@ -122,7 +122,7 @@ fn test_revert_on_overdraft( ], ); - let approve_tx: AccountTransaction = account_invoke_tx(invoke_tx_args! { + let approve_tx: AccountTransaction = invoke_tx_with_default_flags(invoke_tx_args! { max_fee, sender_address: account_address, calldata: approve_calldata, @@ -131,8 +131,7 @@ fn test_revert_on_overdraft( nonce: nonce_manager.next(account_address), }); let tx_info = approve_tx.create_tx_info(); - let approval_execution_info = - approve_tx.execute(&mut state, &block_context, true, true).unwrap(); + let approval_execution_info = approve_tx.execute(&mut state, &block_context).unwrap(); assert!(!approval_execution_info.is_reverted()); // Transfer a valid amount of funds to compute the cost of a successful @@ -229,7 +228,7 @@ fn test_revert_on_overdraft( /// Tests that when a transaction requires more resources than what the sender bounds allow, the /// execution is reverted; in the non-revertible case, checks for the correct error. -// TODO(Aner, 21/01/24) modify for 4844 (taking blob_gas into account). +// TODO(Aner): modify for 4844 (taking blob_gas into account). #[rstest] #[case::v0_no_revert(TransactionVersion::ZERO, false, default_all_resource_bounds(), None)] #[case::v1_insufficient_max_fee(TransactionVersion::ONE, true, default_all_resource_bounds(), None)] @@ -267,9 +266,10 @@ fn test_revert_on_resource_overuse( #[values(CairoVersion::Cairo0)] cairo_version: CairoVersion, ) { block_context.block_info.use_kzg_da = true; + block_context.versioned_constants.allocation_cost = AllocationCost::ZERO; let gas_mode = resource_bounds.get_gas_vector_computation_mode(); let fee_type = if version == TransactionVersion::THREE { FeeType::Strk } else { FeeType::Eth }; - let gas_prices = block_context.block_info.gas_prices.get_gas_prices_by_fee_type(&fee_type); + let gas_prices = block_context.block_info.gas_prices.gas_price_vector(&fee_type); let TestInitData { mut state, account_address, contract_address, mut nonce_manager } = init_data_by_version(&block_context.chain_info, cairo_version); @@ -313,7 +313,7 @@ fn test_revert_on_resource_overuse( // units for bounds check in post-execution. let tight_resource_bounds = match gas_mode { GasVectorComputationMode::NoL2Gas => l1_resource_bounds( - actual_gas_usage.to_discounted_l1_gas(gas_prices), + actual_gas_usage.to_l1_gas_for_fee(gas_prices, &block_context.versioned_constants), DEFAULT_STRK_L1_GAS_PRICE.into(), ), GasVectorComputationMode::All => { @@ -371,14 +371,11 @@ fn test_revert_on_resource_overuse( Resource::L2Gas => l2_gas.0 -= 1, Resource::L1DataGas => l1_data_gas.0 -= 1, } - create_all_resource_bounds( + create_gas_amount_bounds_with_default_price(GasVector { l1_gas, - DEFAULT_STRK_L1_GAS_PRICE.into(), l2_gas, - DEFAULT_STRK_L2_GAS_PRICE.into(), l1_data_gas, - DEFAULT_STRK_L1_DATA_GAS_PRICE.into(), - ) + }) } } }; diff --git a/crates/blockifier/src/transaction/test_utils.rs b/crates/blockifier/src/transaction/test_utils.rs index fdefb138e69..e7d33357e71 100644 --- a/crates/blockifier/src/transaction/test_utils.rs +++ b/crates/blockifier/src/transaction/test_utils.rs @@ -1,12 +1,28 @@ +use blockifier_test_utils::cairo_versions::CairoVersion; +use blockifier_test_utils::calldata::create_calldata; +use blockifier_test_utils::contracts::FeatureContract; use rstest::fixture; use starknet_api::abi::abi_utils::get_fee_token_var_address; -use starknet_api::block::GasPrice; -use starknet_api::contract_class::{ClassInfo, ContractClass}; +use starknet_api::block::{FeeType, GasPrice}; +use starknet_api::contract_class::{ClassInfo, ContractClass, SierraVersion}; use starknet_api::core::{ClassHash, ContractAddress, Nonce}; -use starknet_api::execution_resources::GasAmount; -use starknet_api::test_utils::deploy_account::DeployAccountTxArgs; -use starknet_api::test_utils::invoke::InvokeTxArgs; -use starknet_api::test_utils::NonceManager; +use starknet_api::execution_resources::{GasAmount, GasVector}; +use starknet_api::test_utils::declare::executable_declare_tx; +use starknet_api::test_utils::deploy_account::{ + create_executable_deploy_account_tx_and_update_nonce, + DeployAccountTxArgs, +}; +use starknet_api::test_utils::invoke::{executable_invoke_tx, InvokeTxArgs}; +use starknet_api::test_utils::{ + NonceManager, + DEFAULT_L1_DATA_GAS_MAX_AMOUNT, + DEFAULT_L1_GAS_AMOUNT, + DEFAULT_L2_GAS_MAX_AMOUNT, + DEFAULT_STRK_L1_DATA_GAS_PRICE, + DEFAULT_STRK_L1_GAS_PRICE, + DEFAULT_STRK_L2_GAS_PRICE, + MAX_FEE, +}; use starknet_api::transaction::fields::{ AllResourceBounds, ContractAddressSalt, @@ -21,29 +37,16 @@ use starknet_api::{calldata, declare_tx_args, deploy_account_tx_args, felt, invo use starknet_types_core::felt::Felt; use strum::IntoEnumIterator; +use crate::blockifier_versioned_constants::VersionedConstants; use crate::context::{BlockContext, ChainInfo}; use crate::state::cached_state::CachedState; use crate::state::state_api::State; -use crate::test_utils::contracts::FeatureContract; -use crate::test_utils::declare::declare_tx; -use crate::test_utils::deploy_account::deploy_account_tx; +use crate::test_utils::contracts::FeatureContractTrait; use crate::test_utils::dict_state_reader::DictStateReader; use crate::test_utils::initial_test_state::test_state; -use crate::test_utils::invoke::invoke_tx; -use crate::test_utils::{ - create_calldata, - CairoVersion, - BALANCE, - DEFAULT_L1_DATA_GAS_MAX_AMOUNT, - DEFAULT_L1_GAS_AMOUNT, - DEFAULT_L2_GAS_MAX_AMOUNT, - DEFAULT_STRK_L1_DATA_GAS_PRICE, - DEFAULT_STRK_L1_GAS_PRICE, - DEFAULT_STRK_L2_GAS_PRICE, - MAX_FEE, -}; -use crate::transaction::account_transaction::AccountTransaction; -use crate::transaction::objects::{FeeType, TransactionExecutionInfo, TransactionExecutionResult}; +use crate::test_utils::BALANCE; +use crate::transaction::account_transaction::{AccountTransaction, ExecutionFlags}; +use crate::transaction::objects::{TransactionExecutionInfo, TransactionExecutionResult}; use crate::transaction::transaction_types::TransactionType; use crate::transaction::transactions::ExecutableTransaction; @@ -56,9 +59,20 @@ pub const GET_EXECUTION_INFO: u64 = 4; pub const GET_BLOCK_NUMBER: u64 = 5; pub const GET_BLOCK_TIMESTAMP: u64 = 6; pub const GET_SEQUENCER_ADDRESS: u64 = 7; +pub const STORAGE_WRITE: u64 = 8; /// Test fixtures. +#[fixture] +pub fn block_context() -> BlockContext { + BlockContext::create_for_account_testing() +} + +#[fixture] +pub fn versioned_constants(block_context: BlockContext) -> VersionedConstants { + block_context.versioned_constants().clone() +} + #[fixture] pub fn max_fee() -> Fee { MAX_FEE @@ -80,20 +94,25 @@ pub fn create_resource_bounds(computation_mode: &GasVectorComputationMode) -> Va GasVectorComputationMode::NoL2Gas => { l1_resource_bounds(DEFAULT_L1_GAS_AMOUNT, DEFAULT_STRK_L1_GAS_PRICE.into()) } - GasVectorComputationMode::All => create_all_resource_bounds( - DEFAULT_L1_GAS_AMOUNT, - DEFAULT_STRK_L1_GAS_PRICE.into(), - DEFAULT_L2_GAS_MAX_AMOUNT, - DEFAULT_STRK_L2_GAS_PRICE.into(), - DEFAULT_L1_DATA_GAS_MAX_AMOUNT, - DEFAULT_STRK_L1_DATA_GAS_PRICE.into(), - ), + GasVectorComputationMode::All => create_gas_amount_bounds_with_default_price(GasVector { + l1_gas: DEFAULT_L1_GAS_AMOUNT, + l1_data_gas: DEFAULT_L1_DATA_GAS_MAX_AMOUNT, + l2_gas: DEFAULT_L2_GAS_MAX_AMOUNT, + }), } } -#[fixture] -pub fn block_context() -> BlockContext { - BlockContext::create_for_account_testing() +pub fn create_gas_amount_bounds_with_default_price( + GasVector { l1_gas, l1_data_gas, l2_gas }: GasVector, +) -> ValidResourceBounds { + create_all_resource_bounds( + l1_gas, + DEFAULT_STRK_L1_GAS_PRICE.into(), + l2_gas, + DEFAULT_STRK_L2_GAS_PRICE.into(), + l1_data_gas, + DEFAULT_STRK_L1_DATA_GAS_PRICE.into(), + ) } /// Struct containing the data usually needed to initialize a test. @@ -113,7 +132,9 @@ pub fn deploy_and_fund_account( deploy_tx_args: DeployAccountTxArgs, ) -> (AccountTransaction, ContractAddress) { // Deploy an account contract. - let deploy_account_tx = deploy_account_tx(deploy_tx_args, nonce_manager); + let deploy_account_tx = AccountTransaction::new_with_default_flags( + create_executable_deploy_account_tx_and_update_nonce(deploy_tx_args, nonce_manager), + ); let account_address = deploy_account_tx.sender_address(); // Update the balance of the about-to-be deployed account contract in the erc20 contract, so it @@ -162,6 +183,10 @@ pub struct FaultyAccountTxCreatorArgs { pub validate_constructor: bool, // Should be used with tx_type Declare. pub declared_contract: Option, + // Execution flags. + pub validate: bool, + pub only_query: bool, + pub charge_fee: bool, } impl Default for FaultyAccountTxCreatorArgs { @@ -178,6 +203,9 @@ impl Default for FaultyAccountTxCreatorArgs { max_fee: Fee::default(), resource_bounds: ValidResourceBounds::create_for_testing_no_fee_enforcement(), declared_contract: None, + validate: true, + only_query: false, + charge_fee: true, } } } @@ -202,6 +230,7 @@ pub fn create_account_tx_for_validate_test( nonce_manager: &mut NonceManager, faulty_account_tx_creator_args: FaultyAccountTxCreatorArgs, ) -> AccountTransaction { + // TODO(Yoni): add `strict_nonce_check` to this struct. let FaultyAccountTxCreatorArgs { tx_type, tx_version, @@ -214,6 +243,9 @@ pub fn create_account_tx_for_validate_test( max_fee, resource_bounds, declared_contract, + validate, + only_query, + charge_fee, } = faulty_account_tx_creator_args; // The first felt of the signature is used to set the scenario. If the scenario is @@ -223,7 +255,8 @@ pub fn create_account_tx_for_validate_test( signature_vector.extend(additional_data); } let signature = TransactionSignature(signature_vector); - + let execution_flags = + ExecutionFlags { validate, charge_fee, only_query, strict_nonce_check: true }; match tx_type { TransactionType::Declare => { let declared_contract = match declared_contract { @@ -235,7 +268,7 @@ pub fn create_account_tx_for_validate_test( }; let class_hash = declared_contract.get_class_hash(); let class_info = calculate_class_info_for_testing(declared_contract.get_class()); - declare_tx( + let tx = executable_declare_tx( declare_tx_args! { max_fee, resource_bounds, @@ -247,7 +280,8 @@ pub fn create_account_tx_for_validate_test( compiled_class_hash: declared_contract.get_compiled_class_hash(), }, class_info, - ) + ); + AccountTransaction { tx, execution_flags } } TransactionType::DeployAccount => { // We do not use the sender address here because the transaction generates the actual @@ -256,7 +290,7 @@ pub fn create_account_tx_for_validate_test( true => constants::FELT_TRUE, false => constants::FELT_FALSE, })]; - deploy_account_tx( + let tx = create_executable_deploy_account_tx_and_update_nonce( deploy_account_tx_args! { max_fee, resource_bounds, @@ -267,11 +301,12 @@ pub fn create_account_tx_for_validate_test( constructor_calldata, }, nonce_manager, - ) + ); + AccountTransaction { tx, execution_flags } } TransactionType::InvokeFunction => { let execute_calldata = create_calldata(sender_address, "foo", &[]); - invoke_tx(invoke_tx_args! { + let tx = executable_invoke_tx(invoke_tx_args! { max_fee, resource_bounds, signature, @@ -279,14 +314,17 @@ pub fn create_account_tx_for_validate_test( calldata: execute_calldata, version: tx_version, nonce: nonce_manager.next(sender_address), - }) + + }); + AccountTransaction { tx, execution_flags } } _ => panic!("{tx_type:?} is not an account transaction."), } } -pub fn account_invoke_tx(invoke_args: InvokeTxArgs) -> AccountTransaction { - invoke_tx(invoke_args) +pub fn invoke_tx_with_default_flags(invoke_args: InvokeTxArgs) -> AccountTransaction { + let tx = executable_invoke_tx(invoke_args); + AccountTransaction::new_with_default_flags(tx) } pub fn run_invoke_tx( @@ -294,15 +332,15 @@ pub fn run_invoke_tx( block_context: &BlockContext, invoke_args: InvokeTxArgs, ) -> TransactionExecutionResult { - let tx = account_invoke_tx(invoke_args); - let charge_fee = tx.enforce_fee(); + let tx = executable_invoke_tx(invoke_args); + let account_tx = AccountTransaction::new_for_sequencing(tx); - tx.execute(state, block_context, charge_fee, true) + account_tx.execute(state, block_context) } /// Creates a `ResourceBoundsMapping` with the given `max_amount` and `max_price` for L1 gas limits. /// No guarantees on the values of the other resources bounds. -// TODO: Check usages of this function and update to using all gas bounds. +// TODO(Dori): Check usages of this function and update to using all gas bounds. pub fn l1_resource_bounds( max_amount: GasAmount, max_price_per_unit: GasPrice, @@ -348,11 +386,11 @@ pub fn create_all_resource_bounds( } pub fn calculate_class_info_for_testing(contract_class: ContractClass) -> ClassInfo { - let sierra_program_length = match contract_class { - ContractClass::V0(_) => 0, - ContractClass::V1(_) => 100, + let (sierra_program_length, sierra_version) = match contract_class { + ContractClass::V0(_) => (0, SierraVersion::DEPRECATED), + ContractClass::V1(_) => (100, SierraVersion::LATEST), }; - ClassInfo::new(&contract_class, sierra_program_length, 100).unwrap() + ClassInfo::new(&contract_class, sierra_program_length, 100, sierra_version).unwrap() } pub fn emit_n_events_tx( @@ -367,9 +405,11 @@ pub fn emit_n_events_tx( felt!(0_u32), // data length. ]; let calldata = create_calldata(contract_address, "test_emit_events", &entry_point_args); - account_invoke_tx(invoke_tx_args! { + let tx = executable_invoke_tx(invoke_tx_args! { sender_address: account_contract, calldata, nonce - }) + }); + + AccountTransaction::new_for_sequencing(tx) } diff --git a/crates/blockifier/src/transaction/transaction_execution.rs b/crates/blockifier/src/transaction/transaction_execution.rs index 864267d8a06..9abab167350 100644 --- a/crates/blockifier/src/transaction/transaction_execution.rs +++ b/crates/blockifier/src/transaction/transaction_execution.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use starknet_api::contract_class::ClassInfo; -use starknet_api::core::{calculate_contract_address, ContractAddress, Nonce}; +use starknet_api::core::{ContractAddress, Nonce}; use starknet_api::executable_transaction::{ AccountTransaction as ApiExecutableTransaction, DeclareTransaction, @@ -9,47 +9,54 @@ use starknet_api::executable_transaction::{ InvokeTransaction, L1HandlerTransaction, }; +use starknet_api::execution_resources::GasAmount; use starknet_api::transaction::fields::Fee; -use starknet_api::transaction::{Transaction as StarknetApiTransaction, TransactionHash}; +use starknet_api::transaction::{ + CalculateContractAddress, + Transaction as StarknetApiTransaction, + TransactionHash, +}; use crate::bouncer::verify_tx_weights_within_max_capacity; use crate::context::BlockContext; use crate::execution::call_info::CallInfo; -use crate::execution::entry_point::EntryPointExecutionContext; +use crate::execution::entry_point::{EntryPointExecutionContext, SierraGasRevertTracker}; +use crate::fee::fee_checks::FeeCheckReport; use crate::fee::receipt::TransactionReceipt; use crate::state::cached_state::TransactionalState; use crate::state::state_api::UpdatableState; -use crate::transaction::account_transaction::AccountTransaction; -use crate::transaction::errors::TransactionFeeError; +use crate::transaction::account_transaction::{ + AccountTransaction, + ExecutionFlags as AccountExecutionFlags, +}; +use crate::transaction::errors::{TransactionExecutionError, TransactionFeeError}; use crate::transaction::objects::{ TransactionExecutionInfo, TransactionExecutionResult, TransactionInfo, TransactionInfoCreator, }; -use crate::transaction::transactions::{Executable, ExecutableTransaction, ExecutionFlags}; +use crate::transaction::transactions::{Executable, ExecutableTransaction}; -// TODO: Move into transaction.rs, makes more sense to be defined there. +// TODO(Gilad): Move into transaction.rs, makes more sense to be defined there. #[derive(Clone, Debug, derive_more::From)] pub enum Transaction { Account(AccountTransaction), L1Handler(L1HandlerTransaction), } -impl From for Transaction { - fn from(value: starknet_api::executable_transaction::Transaction) -> Self { +impl Transaction { + pub fn new_for_sequencing(value: starknet_api::executable_transaction::Transaction) -> Self { match value { starknet_api::executable_transaction::Transaction::Account(tx) => { - Transaction::Account(tx.into()) + Transaction::Account(AccountTransaction::new_for_sequencing(tx)) } starknet_api::executable_transaction::Transaction::L1Handler(tx) => { Transaction::L1Handler(tx) } } } -} -impl Transaction { pub fn nonce(&self) -> Nonce { match self { Self::Account(tx) => tx.nonce(), @@ -77,7 +84,7 @@ impl Transaction { class_info: Option, paid_fee_on_l1: Option, deployed_contract_address: Option, - only_query: bool, + execution_flags: AccountExecutionFlags, ) -> TransactionExecutionResult { let executable_tx = match tx { StarknetApiTransaction::L1Handler(l1_handler) => { @@ -101,12 +108,7 @@ impl Transaction { StarknetApiTransaction::DeployAccount(deploy_account) => { let contract_address = match deployed_contract_address { Some(address) => address, - None => calculate_contract_address( - deploy_account.contract_address_salt(), - deploy_account.class_hash(), - &deploy_account.constructor_calldata(), - ContractAddress::default(), - )?, + None => deploy_account.calculate_contract_address()?, }; ApiExecutableTransaction::DeployAccount(DeployAccountTransaction { tx: deploy_account, @@ -119,11 +121,7 @@ impl Transaction { } _ => unimplemented!(), }; - let account_tx = match only_query { - true => AccountTransaction::new_for_query(executable_tx), - false => AccountTransaction::new(executable_tx), - }; - Ok(account_tx.into()) + Ok(AccountTransaction { tx: executable_tx, execution_flags }.into()) } } @@ -141,32 +139,38 @@ impl ExecutableTransaction for L1HandlerTransaction { &self, state: &mut TransactionalState<'_, U>, block_context: &BlockContext, - _execution_flags: ExecutionFlags, + _concurrency_mode: bool, ) -> TransactionExecutionResult { let tx_context = Arc::new(block_context.to_tx_context(self)); let limit_steps_by_resources = false; - let mut context = - EntryPointExecutionContext::new_invoke(tx_context.clone(), limit_steps_by_resources); - let mut remaining_gas = tx_context.initial_sierra_gas(); + let l1_handler_bounds = + block_context.versioned_constants.os_constants.l1_handler_max_amount_bounds; + + let mut remaining_gas = l1_handler_bounds.l2_gas.0; + let mut context = EntryPointExecutionContext::new_invoke( + tx_context.clone(), + limit_steps_by_resources, + SierraGasRevertTracker::new(GasAmount(remaining_gas)), + ); let execute_call_info = self.run_execute(state, &mut context, &mut remaining_gas)?; let l1_handler_payload_size = self.payload_size(); - let TransactionReceipt { - fee: actual_fee, - da_gas, - resources: actual_resources, - gas: total_gas, - } = TransactionReceipt::from_l1_handler( + let receipt = TransactionReceipt::from_l1_handler( &tx_context, l1_handler_payload_size, CallInfo::summarize_many(execute_call_info.iter(), &block_context.versioned_constants), &state.get_actual_state_changes()?, ); + // Enforce resource bounds. + FeeCheckReport::check_all_gas_amounts_within_bounds(&l1_handler_bounds, &receipt.gas)?; + let paid_fee = self.paid_fee_on_l1; // For now, assert only that any amount of fee was paid. // The error message still indicates the required fee. if paid_fee == Fee(0) { - return Err(TransactionFeeError::InsufficientFee { paid_fee, actual_fee })?; + return Err(TransactionExecutionError::TransactionFeeError( + TransactionFeeError::InsufficientFee { paid_fee, actual_fee: receipt.fee }, + )); } Ok(TransactionExecutionInfo { @@ -175,9 +179,9 @@ impl ExecutableTransaction for L1HandlerTransaction { fee_transfer_call_info: None, receipt: TransactionReceipt { fee: Fee::default(), - da_gas, - resources: actual_resources, - gas: total_gas, + da_gas: receipt.da_gas, + resources: receipt.resources, + gas: receipt.gas, }, revert_error: None, }) @@ -189,23 +193,22 @@ impl ExecutableTransaction for Transaction { &self, state: &mut TransactionalState<'_, U>, block_context: &BlockContext, - execution_flags: ExecutionFlags, + concurrency_mode: bool, ) -> TransactionExecutionResult { // TODO(Yoni, 1/8/2024): consider unimplementing the ExecutableTransaction trait for inner // types, since now running Transaction::execute_raw is not identical to // AccountTransaction::execute_raw. - let concurrency_mode = execution_flags.concurrency_mode; let tx_execution_info = match self { Self::Account(account_tx) => { - account_tx.execute_raw(state, block_context, execution_flags)? + account_tx.execute_raw(state, block_context, concurrency_mode)? } - Self::L1Handler(tx) => tx.execute_raw(state, block_context, execution_flags)?, + Self::L1Handler(tx) => tx.execute_raw(state, block_context, concurrency_mode)?, }; // Check if the transaction is too large to fit any block. // TODO(Yoni, 1/8/2024): consider caching these two. let tx_execution_summary = tx_execution_info.summarize(&block_context.versioned_constants); - let mut tx_state_changes_keys = state.get_actual_state_changes()?.state_maps.into_keys(); + let mut tx_state_changes_keys = state.get_actual_state_changes()?.state_maps.keys(); tx_state_changes_keys.update_sequencer_key_in_storage( &block_context.to_tx_context(self), &tx_execution_info, @@ -217,6 +220,7 @@ impl ExecutableTransaction for Transaction { &tx_execution_info.receipt.resources, &tx_state_changes_keys, &block_context.bouncer_config, + &block_context.versioned_constants, )?; Ok(tx_execution_info) diff --git a/crates/blockifier/src/transaction/transactions.rs b/crates/blockifier/src/transaction/transactions.rs index d570ebe6c49..bc420178710 100644 --- a/crates/blockifier/src/transaction/transactions.rs +++ b/crates/blockifier/src/transaction/transactions.rs @@ -4,6 +4,7 @@ use starknet_api::abi::abi_utils::selector_from_name; use starknet_api::contract_class::EntryPointType; use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress}; use starknet_api::executable_transaction::{ + AccountTransaction, DeclareTransaction, DeployAccountTransaction, InvokeTransaction, @@ -52,8 +53,6 @@ mod test; #[derive(Clone, Copy, Debug)] pub struct ExecutionFlags { - pub charge_fee: bool, - pub validate: bool, pub concurrency_mode: bool, } @@ -64,14 +63,12 @@ pub trait ExecutableTransaction: Sized { &self, state: &mut U, block_context: &BlockContext, - charge_fee: bool, - validate: bool, ) -> TransactionExecutionResult { log::debug!("Executing Transaction..."); let mut transactional_state = TransactionalState::create_transactional(state); - let execution_flags = ExecutionFlags { charge_fee, validate, concurrency_mode: false }; + let concurrency_mode = false; let execution_result = - self.execute_raw(&mut transactional_state, block_context, execution_flags); + self.execute_raw(&mut transactional_state, block_context, concurrency_mode); match execution_result { Ok(value) => { @@ -95,7 +92,7 @@ pub trait ExecutableTransaction: Sized { &self, state: &mut TransactionalState<'_, U>, block_context: &BlockContext, - execution_flags: ExecutionFlags, + concurrency_mode: bool, ) -> TransactionExecutionResult; } @@ -115,7 +112,6 @@ pub trait ValidatableTransaction { state: &mut dyn State, tx_context: Arc, remaining_gas: &mut u64, - limit_steps_by_resources: bool, ) -> TransactionExecutionResult>; } @@ -179,6 +175,16 @@ impl TransactionInfoCreator for L1HandlerTransaction { } } +impl TransactionInfoCreatorInner for AccountTransaction { + fn create_tx_info(&self, only_query: bool) -> TransactionInfo { + match self { + Self::Declare(tx) => tx.create_tx_info(only_query), + Self::DeployAccount(tx) => tx.create_tx_info(only_query), + Self::Invoke(tx) => tx.create_tx_info(only_query), + } + } +} + impl Executable for DeclareTransaction { fn run_execute( &self, @@ -393,6 +399,12 @@ impl TransactionInfoCreatorInner for InvokeTransaction { } } +/// Determines whether the fee should be enforced for the given transaction. +pub fn enforce_fee(tx: &AccountTransaction, only_query: bool) -> bool { + // TODO(AvivG): Consider implemetation without 'create_tx_info'. + tx.create_tx_info(only_query).enforce_fee() +} + /// Attempts to declare a contract class by setting the contract class in the state with the /// specified class hash. fn try_declare( @@ -401,7 +413,7 @@ fn try_declare( class_hash: ClassHash, compiled_class_hash: Option, ) -> TransactionExecutionResult<()> { - match state.get_compiled_contract_class(class_hash) { + match state.get_compiled_class(class_hash) { Err(StateError::UndeclaredClassHash(_)) => { // Class is undeclared; declare it. state.set_contract_class(class_hash, tx.contract_class().try_into()?)?; diff --git a/crates/blockifier/src/transaction/transactions_test.rs b/crates/blockifier/src/transaction/transactions_test.rs index 2a6d85ad98d..0f2b7efad97 100644 --- a/crates/blockifier/src/transaction/transactions_test.rs +++ b/crates/blockifier/src/transaction/transactions_test.rs @@ -2,25 +2,53 @@ use std::collections::{HashMap, HashSet}; use std::sync::{Arc, LazyLock}; use assert_matches::assert_matches; +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; +use blockifier_test_utils::calldata::{create_calldata, create_trivial_calldata}; +use blockifier_test_utils::contracts::FeatureContract; use cairo_vm::types::builtin_name::BuiltinName; use cairo_vm::vm::runners::cairo_runner::ExecutionResources; use num_bigint::BigUint; use pretty_assertions::assert_eq; use rstest::{fixture, rstest}; +use rstest_reuse::apply; use starknet_api::abi::abi_utils::{ get_fee_token_var_address, get_storage_var_address, selector_from_name, }; use starknet_api::abi::constants::CONSTRUCTOR_ENTRY_POINT_NAME; -use starknet_api::block::GasPriceVector; +use starknet_api::block::{FeeType, GasPriceVector}; use starknet_api::contract_class::EntryPointType; -use starknet_api::core::{ChainId, ClassHash, ContractAddress, EthAddress, Nonce}; -use starknet_api::executable_transaction::AccountTransaction as ApiExecutableTransaction; +use starknet_api::core::{ClassHash, ContractAddress, EthAddress, Nonce}; +use starknet_api::executable_transaction::{ + AccountTransaction as ApiExecutableTransaction, + DeployAccountTransaction, +}; use starknet_api::execution_resources::{GasAmount, GasVector}; use starknet_api::state::StorageKey; -use starknet_api::test_utils::invoke::InvokeTxArgs; -use starknet_api::test_utils::NonceManager; +use starknet_api::test_utils::declare::executable_declare_tx; +use starknet_api::test_utils::deploy_account::{ + create_executable_deploy_account_tx_and_update_nonce, + executable_deploy_account_tx, + DeployAccountTxArgs, +}; +use starknet_api::test_utils::invoke::{executable_invoke_tx, InvokeTxArgs}; +use starknet_api::test_utils::{ + NonceManager, + CHAIN_ID_FOR_TESTS, + CURRENT_BLOCK_NUMBER, + CURRENT_BLOCK_NUMBER_FOR_VALIDATE, + CURRENT_BLOCK_TIMESTAMP, + CURRENT_BLOCK_TIMESTAMP_FOR_VALIDATE, + DEFAULT_L1_DATA_GAS_MAX_AMOUNT, + DEFAULT_L1_GAS_AMOUNT, + DEFAULT_L2_GAS_MAX_AMOUNT, + DEFAULT_STRK_L1_DATA_GAS_PRICE, + DEFAULT_STRK_L1_GAS_PRICE, + DEFAULT_STRK_L2_GAS_PRICE, + MAX_FEE, + TEST_SEQUENCER_ADDRESS, +}; use starknet_api::transaction::fields::Resource::{L1DataGas, L1Gas, L2Gas}; use starknet_api::transaction::fields::{ AllResourceBounds, @@ -52,25 +80,27 @@ use starknet_api::{ nonce, }; use starknet_types_core::felt::Felt; -use strum::IntoEnumIterator; +use crate::blockifier_versioned_constants::{AllocationCost, VersionedConstants}; use crate::context::{BlockContext, ChainInfo, FeeTokenAddresses, TransactionContext}; use crate::execution::call_info::{ CallExecution, CallInfo, - ChargedResources, ExecutionSummary, MessageToL1, OrderedEvent, OrderedL2ToL1Message, Retdata, + StorageAccessTracker, }; use crate::execution::contract_class::TrackedResource; use crate::execution::entry_point::{CallEntryPoint, CallType}; use crate::execution::errors::{ConstructorEntryPointExecutionError, EntryPointExecutionError}; use crate::execution::syscalls::hint_processor::EmitEventError; +#[cfg(feature = "cairo_native")] +use crate::execution::syscalls::hint_processor::SyscallExecutionError; use crate::execution::syscalls::SyscallSelector; -use crate::fee::fee_utils::{balance_to_big_uint, get_fee_by_gas_vector}; +use crate::fee::fee_utils::{balance_to_big_uint, get_fee_by_gas_vector, GasVectorToL1GasForFee}; use crate::fee::gas_usage::{ estimate_minimal_gas_vector, get_da_gas_cost, @@ -86,60 +116,46 @@ use crate::fee::resources::{ use crate::state::cached_state::{CachedState, StateChangesCount, TransactionalState}; use crate::state::errors::StateError; use crate::state::state_api::{State, StateReader}; -use crate::test_utils::contracts::FeatureContract; -use crate::test_utils::declare::declare_tx; -use crate::test_utils::deploy_account::deploy_account_tx; +use crate::test_utils::contracts::FeatureContractTrait; use crate::test_utils::dict_state_reader::DictStateReader; -use crate::test_utils::initial_test_state::test_state; -use crate::test_utils::invoke::invoke_tx; +use crate::test_utils::initial_test_state::{fund_account, test_state}; use crate::test_utils::l1_handler::l1handler_tx; use crate::test_utils::prices::Prices; +use crate::test_utils::test_templates::{cairo_version, two_cairo_versions}; use crate::test_utils::{ - create_calldata, - create_trivial_calldata, - get_syscall_resources, + get_const_syscall_resources, get_tx_resources, test_erc20_sequencer_balance_key, - CairoVersion, SaltManager, BALANCE, - CURRENT_BLOCK_NUMBER, - CURRENT_BLOCK_NUMBER_FOR_VALIDATE, - CURRENT_BLOCK_TIMESTAMP, - CURRENT_BLOCK_TIMESTAMP_FOR_VALIDATE, - DEFAULT_L1_DATA_GAS_MAX_AMOUNT, - DEFAULT_L1_GAS_AMOUNT, - DEFAULT_L2_GAS_MAX_AMOUNT, - DEFAULT_STRK_L1_DATA_GAS_PRICE, - DEFAULT_STRK_L1_GAS_PRICE, - DEFAULT_STRK_L2_GAS_PRICE, - MAX_FEE, - TEST_SEQUENCER_ADDRESS, }; -use crate::transaction::account_transaction::AccountTransaction; +use crate::transaction::account_transaction::{AccountTransaction, ExecutionFlags}; use crate::transaction::errors::{ + ResourceBoundsError, TransactionExecutionError, TransactionFeeError, TransactionPreValidationError, }; use crate::transaction::objects::{ - FeeType, HasRelatedFeeType, TransactionExecutionInfo, TransactionInfo, TransactionInfoCreator, }; use crate::transaction::test_utils::{ - account_invoke_tx, block_context, calculate_class_info_for_testing, create_account_tx_for_validate_test, create_account_tx_for_validate_test_nonce_0, - create_all_resource_bounds, + create_gas_amount_bounds_with_default_price, + create_test_init_data, default_all_resource_bounds, default_l1_resource_bounds, + invoke_tx_with_default_flags, l1_resource_bounds, + versioned_constants, FaultyAccountTxCreatorArgs, + TestInitData, CALL_CONTRACT, GET_BLOCK_HASH, GET_BLOCK_NUMBER, @@ -151,19 +167,19 @@ use crate::transaction::test_utils::{ }; use crate::transaction::transaction_types::TransactionType; use crate::transaction::transactions::ExecutableTransaction; -use crate::versioned_constants::VersionedConstants; use crate::{ check_tx_execution_error_for_custom_hint, check_tx_execution_error_for_invalid_scenario, retdata, }; - +const DECLARE_REDEPOSIT_AMOUNT: u64 = 6860; +const DEPLOY_ACCOUNT_REDEPOSIT_AMOUNT: u64 = 6360; static VERSIONED_CONSTANTS: LazyLock = LazyLock::new(VersionedConstants::create_for_testing); #[fixture] -fn default_initial_gas_cost() -> u64 { - VERSIONED_CONSTANTS.default_initial_gas_cost() +fn infinite_gas_for_vm_mode() -> u64 { + VERSIONED_CONSTANTS.infinite_gas_for_vm_mode() } #[fixture] @@ -171,17 +187,26 @@ fn versioned_constants_for_account_testing() -> VersionedConstants { VERSIONED_CONSTANTS.clone() } +fn initial_gas_amount_from_block_context(block_context: Option<&BlockContext>) -> GasAmount { + match block_context { + Some(block_context) => block_context.versioned_constants.initial_gas_no_user_l2_bound(), + None => VERSIONED_CONSTANTS.initial_gas_no_user_l2_bound(), + } +} + struct ExpectedResultTestInvokeTx { resources: ExecutionResources, validate_gas_consumed: u64, execute_gas_consumed: u64, - inner_call_initial_gas: u64, } -fn user_initial_gas_from_bounds(bounds: ValidResourceBounds) -> Option { +fn user_initial_gas_from_bounds( + bounds: ValidResourceBounds, + block_context: Option<&BlockContext>, +) -> GasAmount { match bounds { - ValidResourceBounds::L1Gas(_) => None, - ValidResourceBounds::AllResources(bounds) => Some(bounds.l2_gas.max_amount), + ValidResourceBounds::L1Gas(_) => initial_gas_amount_from_block_context(block_context), + ValidResourceBounds::AllResources(bounds) => bounds.l2_gas.max_amount, } } @@ -198,39 +223,65 @@ fn expected_validate_call_info( ) -> Option { let retdata = match cairo_version { CairoVersion::Cairo0 => Retdata::default(), - CairoVersion::Cairo1 => retdata!(*constants::VALIDATE_RETDATA), - #[cfg(feature = "cairo_native")] - CairoVersion::Native => retdata!(*constants::VALIDATE_RETDATA), + CairoVersion::Cairo1(_) => retdata!(*constants::VALIDATE_RETDATA), }; // Extra range check in regular (invoke) validate call, due to passing the calldata as an array. - let n_range_checks = match cairo_version { - CairoVersion::Cairo0 => { - usize::from(entry_point_selector_name == constants::VALIDATE_ENTRY_POINT_NAME) - } - CairoVersion::Cairo1 => { - if entry_point_selector_name == constants::VALIDATE_ENTRY_POINT_NAME { 7 } else { 2 } - } - #[cfg(feature = "cairo_native")] - CairoVersion::Native => { - if entry_point_selector_name == constants::VALIDATE_ENTRY_POINT_NAME { 7 } else { 2 } + let vm_resources = match tracked_resource { + TrackedResource::SierraGas => ExecutionResources::default(), + TrackedResource::CairoSteps => { + let n_range_checks = match cairo_version { + CairoVersion::Cairo0 => { + usize::from(entry_point_selector_name == constants::VALIDATE_ENTRY_POINT_NAME) + } + CairoVersion::Cairo1(_) => { + if entry_point_selector_name == constants::VALIDATE_ENTRY_POINT_NAME { + 7 + } else { + 2 + } + } + }; + let n_steps = match (entry_point_selector_name, cairo_version) { + (constants::VALIDATE_DEPLOY_ENTRY_POINT_NAME, CairoVersion::Cairo0) => 13_usize, + ( + constants::VALIDATE_DEPLOY_ENTRY_POINT_NAME, + CairoVersion::Cairo1(RunnableCairo1::Casm), + ) => 32_usize, + (constants::VALIDATE_DECLARE_ENTRY_POINT_NAME, CairoVersion::Cairo0) => 12_usize, + ( + constants::VALIDATE_DECLARE_ENTRY_POINT_NAME, + CairoVersion::Cairo1(RunnableCairo1::Casm), + ) => 28_usize, + (constants::VALIDATE_ENTRY_POINT_NAME, CairoVersion::Cairo0) => 21_usize, + ( + constants::VALIDATE_ENTRY_POINT_NAME, + CairoVersion::Cairo1(RunnableCairo1::Casm), + ) => 100_usize, + (selector, _) => panic!("Selector {selector} is not a known validate selector."), + }; + ExecutionResources { + n_steps, + n_memory_holes: 0, + builtin_instance_counter: HashMap::from([( + BuiltinName::range_check, + n_range_checks, + )]), + } + .filter_unused_builtins() } }; - let n_steps = match (entry_point_selector_name, cairo_version) { - (constants::VALIDATE_DEPLOY_ENTRY_POINT_NAME, CairoVersion::Cairo0) => 13_usize, - (constants::VALIDATE_DEPLOY_ENTRY_POINT_NAME, CairoVersion::Cairo1) => 32_usize, - (constants::VALIDATE_DECLARE_ENTRY_POINT_NAME, CairoVersion::Cairo0) => 12_usize, - (constants::VALIDATE_DECLARE_ENTRY_POINT_NAME, CairoVersion::Cairo1) => 28_usize, - (constants::VALIDATE_ENTRY_POINT_NAME, CairoVersion::Cairo0) => 21_usize, - (constants::VALIDATE_ENTRY_POINT_NAME, CairoVersion::Cairo1) => 100_usize, - (selector, _) => panic!("Selector {selector} is not a known validate selector."), + let initial_gas = match cairo_version { + CairoVersion::Cairo0 => infinite_gas_for_vm_mode(), + CairoVersion::Cairo1(_) => match tracked_resource { + TrackedResource::CairoSteps => initial_gas_amount_from_block_context(None).0, + TrackedResource::SierraGas => { + user_initial_gas + .unwrap_or(initial_gas_amount_from_block_context(None)) + .min(VERSIONED_CONSTANTS.os_constants.validate_max_sierra_gas) + .0 + } + }, }; - let resources = ExecutionResources { - n_steps, - n_memory_holes: 0, - builtin_instance_counter: HashMap::from([(BuiltinName::range_check, n_range_checks)]), - } - .filter_unused_builtins(); - let initial_gas = user_initial_gas.unwrap_or(GasAmount(default_initial_gas_cost())).0; Some(CallInfo { call: CallEntryPoint { @@ -245,7 +296,7 @@ fn expected_validate_call_info( initial_gas, }, // The account contract we use for testing has trivial `validate` functions. - charged_resources: ChargedResources::from_execution_resources(resources), + resources: vm_resources, execution: CallExecution { retdata, gas_consumed, ..Default::default() }, tracked_resource, ..Default::default() @@ -284,6 +335,7 @@ fn expected_fee_transfer_call_info( .versioned_constants .os_constants .gas_costs + .base .default_initial_gas_cost, }; let expected_fee_sender_address = *account_address.0.key(); @@ -314,17 +366,18 @@ fn expected_fee_transfer_call_info( events: vec![expected_fee_transfer_event], ..Default::default() }, - charged_resources: ChargedResources::from_execution_resources( - Prices::FeeTransfer(account_address, *fee_type).into(), - ), + resources: Prices::FeeTransfer(account_address, *fee_type).into(), // We read sender and recipient balance - Uint256(BALANCE, 0) then Uint256(0, 0). - storage_read_values: vec![felt!(BALANCE.0), felt!(0_u8), felt!(0_u8), felt!(0_u8)], - accessed_storage_keys: HashSet::from_iter(vec![ - sender_balance_key_low, - sender_balance_key_high, - sequencer_balance_key_low, - sequencer_balance_key_high, - ]), + storage_access_tracker: StorageAccessTracker { + storage_read_values: vec![felt!(BALANCE.0), felt!(0_u8), felt!(0_u8), felt!(0_u8)], + accessed_storage_keys: HashSet::from_iter(vec![ + sender_balance_key_low, + sender_balance_key_high, + sequencer_balance_key_low, + sequencer_balance_key_high, + ]), + ..Default::default() + }, ..Default::default() }) } @@ -339,7 +392,7 @@ fn get_expected_cairo_resources( versioned_constants.get_additional_os_tx_resources(tx_type, starknet_resources, false); for call_info in call_infos { if let Some(call_info) = &call_info { - expected_cairo_resources += &call_info.charged_resources.vm_resources + expected_cairo_resources += &call_info.resources }; } @@ -407,32 +460,35 @@ fn add_kzg_da_resources_to_resources_mapping( }); } +// TODO(Dori): Add a test case that test cairo1 contract that uses VM resources. #[rstest] #[case::with_cairo0_account( ExpectedResultTestInvokeTx{ - resources: &get_syscall_resources(SyscallSelector::CallContract) + &ExecutionResources { + resources: &get_const_syscall_resources(SyscallSelector::CallContract) + &ExecutionResources { n_steps: 62, n_memory_holes: 0, builtin_instance_counter: HashMap::from([(BuiltinName::range_check, 1)]), }, validate_gas_consumed: 0, execute_gas_consumed: 0, - inner_call_initial_gas: versioned_constants_for_account_testing().default_initial_gas_cost(), }, CairoVersion::Cairo0)] #[case::with_cairo1_account( ExpectedResultTestInvokeTx{ - resources: &get_syscall_resources(SyscallSelector::CallContract) + &ExecutionResources { - n_steps: 207, - n_memory_holes: 0, - builtin_instance_counter: HashMap::from([(BuiltinName::range_check, 8)]), - }, - validate_gas_consumed: 4740, // The gas consumption results from parsing the input + resources: ExecutionResources::default(), + validate_gas_consumed: 11690, // The gas consumption results from parsing the input // arguments. - execute_gas_consumed: 162080, - inner_call_initial_gas: versioned_constants_for_account_testing().default_initial_gas_cost(), + execute_gas_consumed: 116450, }, - CairoVersion::Cairo1)] + CairoVersion::Cairo1(RunnableCairo1::Casm))] +#[cfg_attr(feature = "cairo_native", case::with_cairo1_native_account( + ExpectedResultTestInvokeTx{ + resources: ExecutionResources::default(), + validate_gas_consumed: 11690, // The gas consumption results from parsing the input + // arguments. + execute_gas_consumed: 116450, + }, + CairoVersion::Cairo1(RunnableCairo1::Native)))] // TODO(Tzahi): Add calls to cairo1 test contracts (where gas flows to and from the inner call). fn test_invoke_tx( #[values(default_l1_resource_bounds(), default_all_resource_bounds())] @@ -450,7 +506,7 @@ fn test_invoke_tx( let test_contract_address = test_contract.get_instance_address(0); let account_contract_address = account_contract.get_instance_address(0); let calldata = create_trivial_calldata(test_contract_address); - let invoke_tx = invoke_tx(invoke_tx_args! { + let invoke_tx = invoke_tx_with_default_flags(invoke_tx_args! { sender_address: account_contract_address, calldata: Calldata(Arc::clone(&calldata.0)), resource_bounds, @@ -477,20 +533,15 @@ fn test_invoke_tx( let tx_context = block_context.to_tx_context(&invoke_tx); - let actual_execution_info = invoke_tx.execute(state, block_context, true, true).unwrap(); + let actual_execution_info = invoke_tx.execute(state, block_context).unwrap(); - let tracked_resource = account_contract.get_runnable_class().tracked_resource( - &versioned_constants.min_compiler_version_for_sierra_gas, - tx_context.tx_info.gas_mode(), - ); - if tracked_resource == TrackedResource::CairoSteps { - // In CairoSteps mode, the initial gas is set to the default once before the validate call. - expected_arguments.inner_call_initial_gas -= - expected_arguments.validate_gas_consumed + expected_arguments.execute_gas_consumed - } + let tracked_resource = account_contract + .get_runnable_class() + .tracked_resource(&versioned_constants.min_sierra_version_for_sierra_gas, None); // Build expected validate call info. let expected_account_class_hash = account_contract.get_class_hash(); + let initial_gas = user_initial_gas_from_bounds(resource_bounds, Some(block_context)); let expected_validate_call_info = expected_validate_call_info( expected_account_class_hash, constants::VALIDATE_ENTRY_POINT_NAME, @@ -499,11 +550,30 @@ fn test_invoke_tx( sender_address, account_cairo_version, tracked_resource, - user_initial_gas_from_bounds(resource_bounds), + Some(initial_gas.min(versioned_constants.os_constants.validate_max_sierra_gas)), ); // Build expected execute call info. let expected_return_result_calldata = vec![felt!(2_u8)]; + + let expected_validated_call = expected_validate_call_info.as_ref().unwrap().call.clone(); + let expected_initial_execution_gas = versioned_constants + .os_constants + .execute_max_sierra_gas + .min(initial_gas - GasAmount(expected_arguments.validate_gas_consumed)) + .0; + let expected_execute_call = CallEntryPoint { + entry_point_selector: selector_from_name(constants::EXECUTE_ENTRY_POINT_NAME), + initial_gas: match account_cairo_version { + CairoVersion::Cairo0 => versioned_constants.infinite_gas_for_vm_mode(), + CairoVersion::Cairo1(_) => expected_initial_execution_gas, + }, + ..expected_validated_call + }; + + let expected_inner_call_vm_resources = + ExecutionResources { n_steps: 23, n_memory_holes: 0, ..Default::default() }; + let expected_return_result_call = CallEntryPoint { entry_point_selector: selector_from_name("return_result"), class_hash: Some(test_contract.get_class_hash()), @@ -513,33 +583,35 @@ fn test_invoke_tx( storage_address: test_contract_address, caller_address: sender_address, call_type: CallType::Call, - initial_gas: expected_arguments.inner_call_initial_gas, - }; - let expected_validated_call = expected_validate_call_info.as_ref().unwrap().call.clone(); - let expected_execute_call = CallEntryPoint { - entry_point_selector: selector_from_name(constants::EXECUTE_ENTRY_POINT_NAME), - initial_gas: expected_validated_call.initial_gas - expected_arguments.validate_gas_consumed, - ..expected_validated_call + initial_gas: versioned_constants.infinite_gas_for_vm_mode(), }; + let expected_return_result_retdata = Retdata(expected_return_result_calldata); + let expected_inner_calls = vec![CallInfo { + call: expected_return_result_call, + execution: CallExecution::from_retdata(expected_return_result_retdata.clone()), + resources: expected_inner_call_vm_resources.clone(), + ..Default::default() + }]; + let (expected_validate_gas_for_fee, expected_execute_gas_for_fee) = match tracked_resource { + TrackedResource::CairoSteps => (GasAmount::default(), GasAmount::default()), + TrackedResource::SierraGas => { + expected_arguments.resources = expected_inner_call_vm_resources; + ( + expected_arguments.validate_gas_consumed.into(), + expected_arguments.execute_gas_consumed.into(), + ) + } + }; let expected_execute_call_info = Some(CallInfo { call: expected_execute_call, execution: CallExecution { - retdata: Retdata(expected_return_result_retdata.0.clone()), + retdata: Retdata(expected_return_result_retdata.0), gas_consumed: expected_arguments.execute_gas_consumed, ..Default::default() }, - charged_resources: ChargedResources::from_execution_resources(expected_arguments.resources), - inner_calls: vec![CallInfo { - call: expected_return_result_call, - execution: CallExecution::from_retdata(expected_return_result_retdata), - charged_resources: ChargedResources::from_execution_resources(ExecutionResources { - n_steps: 23, - n_memory_holes: 0, - ..Default::default() - }), - ..Default::default() - }], + resources: expected_arguments.resources, + inner_calls: expected_inner_calls, tracked_resource, ..Default::default() }); @@ -554,7 +626,7 @@ fn test_invoke_tx( FeatureContract::ERC20(CairoVersion::Cairo0).get_class_hash(), ); - let da_gas = starknet_resources.state.to_gas_vector(use_kzg_da); + let da_gas = starknet_resources.state.da_gas_vector(use_kzg_da); let expected_cairo_resources = get_expected_cairo_resources( versioned_constants, @@ -562,10 +634,12 @@ fn test_invoke_tx( &starknet_resources, vec![&expected_validate_call_info, &expected_execute_call_info], ); + let mut expected_actual_resources = TransactionResources { starknet_resources, computation: ComputationResources { vm_resources: expected_cairo_resources, + sierra_gas: expected_validate_gas_for_fee + expected_execute_gas_for_fee, ..Default::default() }, }; @@ -647,18 +721,20 @@ fn verify_storage_after_invoke_advanced_operations( } #[rstest] +#[case::with_cairo0_account(CairoVersion::Cairo0)] +#[case::with_cairo1_account(CairoVersion::Cairo1(RunnableCairo1::Casm))] +#[cfg_attr( + feature = "cairo_native", + case::with_cairo1_native_account(CairoVersion::Cairo1(RunnableCairo1::Native)) +)] fn test_invoke_tx_advanced_operations( block_context: BlockContext, default_all_resource_bounds: ValidResourceBounds, - #[values(CairoVersion::Cairo0, CairoVersion::Cairo1)] cairo_version: CairoVersion, + #[case] cairo_version: CairoVersion, ) { let block_context = &block_context; - let account = FeatureContract::AccountWithoutValidations(cairo_version); - let test_contract = FeatureContract::TestContract(cairo_version); - let state = - &mut test_state(&block_context.chain_info, BALANCE, &[(account, 1), (test_contract, 1)]); - let account_address = account.get_instance_address(0); - let contract_address = test_contract.get_instance_address(0); + let TestInitData { mut state, account_address, contract_address, mut nonce_manager } = + create_test_init_data(&block_context.chain_info, cairo_version); let index = felt!(123_u32); let base_tx_args = invoke_tx_args! { resource_bounds: default_all_resource_bounds, @@ -666,23 +742,22 @@ fn test_invoke_tx_advanced_operations( }; // Invoke advance_counter function. - let mut nonce_manager = NonceManager::default(); let counter_diffs = [101_u32, 102_u32]; let initial_counters = [felt!(counter_diffs[0]), felt!(counter_diffs[1])]; let calldata_args = vec![index, initial_counters[0], initial_counters[1]]; - let account_tx = account_invoke_tx(invoke_tx_args! { + let account_tx = invoke_tx_with_default_flags(invoke_tx_args! { nonce: nonce_manager.next(account_address), calldata: create_calldata(contract_address, "advance_counter", &calldata_args), ..base_tx_args.clone() }); - account_tx.execute(state, block_context, true, true).unwrap(); + account_tx.execute(&mut state, block_context).unwrap(); let next_nonce = nonce_manager.next(account_address); let initial_ec_point = [Felt::ZERO, Felt::ZERO]; verify_storage_after_invoke_advanced_operations( - state, + &mut state, contract_address, account_address, index, @@ -696,19 +771,19 @@ fn test_invoke_tx_advanced_operations( let calldata_args = vec![*contract_address.0.key(), index, felt!(xor_values[0]), felt!(xor_values[1])]; - let account_tx = account_invoke_tx(invoke_tx_args! { + let account_tx = invoke_tx_with_default_flags(invoke_tx_args! { nonce: next_nonce, calldata: create_calldata(contract_address, "call_xor_counters", &calldata_args), ..base_tx_args.clone() }); - account_tx.execute(state, block_context, true, true).unwrap(); + account_tx.execute(&mut state, block_context).unwrap(); let expected_counters = [felt!(counter_diffs[0] ^ xor_values[0]), felt!(counter_diffs[1] ^ xor_values[1])]; let next_nonce = nonce_manager.next(account_address); verify_storage_after_invoke_advanced_operations( - state, + &mut state, contract_address, account_address, index, @@ -718,13 +793,13 @@ fn test_invoke_tx_advanced_operations( ); // Invoke test_ec_op function. - let account_tx = account_invoke_tx(invoke_tx_args! { + let account_tx = invoke_tx_with_default_flags(invoke_tx_args! { nonce: next_nonce, calldata: create_calldata(contract_address, "test_ec_op", &[]), ..base_tx_args.clone() }); - account_tx.execute(state, block_context, true, true).unwrap(); + account_tx.execute(&mut state, block_context).unwrap(); let expected_ec_point = [ Felt::from_bytes_be(&[ @@ -742,7 +817,7 @@ fn test_invoke_tx_advanced_operations( ]; let next_nonce = nonce_manager.next(account_address); verify_storage_after_invoke_advanced_operations( - state, + &mut state, contract_address, account_address, index, @@ -755,14 +830,14 @@ fn test_invoke_tx_advanced_operations( let signature_values = [Felt::from(200_u64), Felt::from(300_u64)]; let signature = TransactionSignature(signature_values.into()); - let account_tx = account_invoke_tx(invoke_tx_args! { + let account_tx = invoke_tx_with_default_flags(invoke_tx_args! { signature, nonce: next_nonce, calldata: create_calldata(contract_address, "add_signature_to_counters", &[index]), ..base_tx_args.clone() }); - account_tx.execute(state, block_context, true, true).unwrap(); + account_tx.execute(&mut state, block_context).unwrap(); let expected_counters = [ (expected_counters[0] + signature_values[0]), @@ -770,7 +845,7 @@ fn test_invoke_tx_advanced_operations( ]; let next_nonce = nonce_manager.next(account_address); verify_storage_after_invoke_advanced_operations( - state, + &mut state, contract_address, account_address, index, @@ -781,16 +856,16 @@ fn test_invoke_tx_advanced_operations( // Invoke send_message function that send a message to L1. let to_address = Felt::from(85); - let account_tx = account_invoke_tx(invoke_tx_args! { + let account_tx = invoke_tx_with_default_flags(invoke_tx_args! { nonce: next_nonce, calldata: create_calldata(contract_address, "send_message", &[to_address]), ..base_tx_args }); - let execution_info = account_tx.execute(state, block_context, true, true).unwrap(); + let execution_info = account_tx.execute(&mut state, block_context).unwrap(); let next_nonce = nonce_manager.next(account_address); verify_storage_after_invoke_advanced_operations( - state, + &mut state, contract_address, account_address, index, @@ -811,25 +886,21 @@ fn test_invoke_tx_advanced_operations( ); } -#[rstest] +#[apply(cairo_version)] #[case(TransactionVersion::ONE, FeeType::Eth)] #[case(TransactionVersion::THREE, FeeType::Strk)] fn test_state_get_fee_token_balance( block_context: BlockContext, #[case] tx_version: TransactionVersion, #[case] fee_type: FeeType, - #[values(CairoVersion::Cairo0, CairoVersion::Cairo1)] account_version: CairoVersion, + cairo_version: CairoVersion, ) { - let block_context = &block_context; - let chain_info = &block_context.chain_info; - let account = FeatureContract::AccountWithoutValidations(account_version); - let test_contract = FeatureContract::TestContract(CairoVersion::Cairo0); - let state = &mut test_state(chain_info, BALANCE, &[(account, 1), (test_contract, 1)]); - let account_address = account.get_instance_address(0); + let TestInitData { mut state, account_address, .. } = + create_test_init_data(&block_context.chain_info, cairo_version); let (mint_high, mint_low) = (felt!(54_u8), felt!(39_u8)); let recipient_int = 10_u8; let recipient = felt!(recipient_int); - let fee_token_address = chain_info.fee_token_address(&fee_type); + let fee_token_address = block_context.chain_info.fee_token_address(&fee_type); // Give the account mint privileges. state @@ -843,7 +914,7 @@ fn test_state_get_fee_token_balance( // Mint some tokens. let execute_calldata = create_calldata(fee_token_address, "permissionedMint", &[recipient, mint_low, mint_high]); - let account_tx = account_invoke_tx(invoke_tx_args! { + let account_tx = invoke_tx_with_default_flags(invoke_tx_args! { max_fee: MAX_FEE, resource_bounds: default_l1_resource_bounds(), sender_address: account_address, @@ -851,7 +922,7 @@ fn test_state_get_fee_token_balance( version: tx_version, nonce: Nonce::default(), }); - account_tx.execute(state, block_context, true, true).unwrap(); + account_tx.execute(&mut state, &block_context).unwrap(); // Get balance from state, and validate. let (low, high) = @@ -866,7 +937,7 @@ fn assert_resource_bounds_exceed_balance_failure( block_context: &BlockContext, invalid_tx: AccountTransaction, ) { - let tx_error = invalid_tx.execute(state, block_context, true, true).unwrap_err(); + let tx_error = invalid_tx.execute(state, block_context).unwrap_err(); match invalid_tx.create_tx_info() { TransactionInfo::Deprecated(context) => { assert_matches!( @@ -909,28 +980,33 @@ fn assert_resource_bounds_exceed_balance_failure( } #[rstest] +#[case::with_cairo0_account(CairoVersion::Cairo0)] +#[case::with_cairo1_account(CairoVersion::Cairo1(RunnableCairo1::Casm))] +#[cfg_attr( + feature = "cairo_native", + case::with_cairo1_native_account(CairoVersion::Cairo1(RunnableCairo1::Native)) +)] fn test_estimate_minimal_gas_vector( mut block_context: BlockContext, #[values(true, false)] use_kzg_da: bool, #[values(GasVectorComputationMode::NoL2Gas, GasVectorComputationMode::All)] gas_vector_computation_mode: GasVectorComputationMode, - #[values(CairoVersion::Cairo0, CairoVersion::Cairo1)] account_cairo_version: CairoVersion, + #[case] cairo_version: CairoVersion, ) { block_context.block_info.use_kzg_da = use_kzg_da; - let block_context = &block_context; - let account_contract = FeatureContract::AccountWithoutValidations(account_cairo_version); - let test_contract = FeatureContract::TestContract(CairoVersion::Cairo0); + let TestInitData { account_address, contract_address, .. } = + create_test_init_data(&block_context.chain_info, cairo_version); let valid_invoke_tx_args = invoke_tx_args! { - sender_address: account_contract.get_instance_address(0), - calldata: create_trivial_calldata(test_contract.get_instance_address(0)), + sender_address: account_address, + calldata: create_trivial_calldata(contract_address), max_fee: MAX_FEE }; // The minimal gas estimate does not depend on tx version. - let tx = &account_invoke_tx(valid_invoke_tx_args); + let tx = &invoke_tx_with_default_flags(valid_invoke_tx_args); let minimal_gas_vector = - estimate_minimal_gas_vector(block_context, tx, &gas_vector_computation_mode); + estimate_minimal_gas_vector(&block_context, tx, &gas_vector_computation_mode); let minimal_l1_gas = minimal_gas_vector.l1_gas; let minimal_l2_gas = minimal_gas_vector.l2_gas; let minimal_l1_data_gas = minimal_gas_vector.l1_data_gas; @@ -945,69 +1021,68 @@ fn test_estimate_minimal_gas_vector( } #[rstest] +#[case::with_cairo0_account(CairoVersion::Cairo0)] +#[case::with_cairo1_account(CairoVersion::Cairo1(RunnableCairo1::Casm))] +#[cfg_attr( + feature = "cairo_native", + case::with_cairo1_native_account(CairoVersion::Cairo1(RunnableCairo1::Native)) +)] fn test_max_fee_exceeds_balance( mut block_context: BlockContext, #[values(default_l1_resource_bounds(), default_all_resource_bounds())] resource_bounds: ValidResourceBounds, #[values(true, false)] use_kzg_da: bool, - #[values(CairoVersion::Cairo0, CairoVersion::Cairo1)] account_cairo_version: CairoVersion, + #[case] cairo_version: CairoVersion, ) { block_context.block_info.use_kzg_da = use_kzg_da; - let block_context = &block_context; - let account_contract = FeatureContract::AccountWithoutValidations(account_cairo_version); - let test_contract = FeatureContract::TestContract(CairoVersion::Cairo0); - let state = &mut test_state( - &block_context.chain_info, - BALANCE, - &[(account_contract, 1), (test_contract, 1)], - ); - let sender_address = account_contract.get_instance_address(0); + let TestInitData { mut state, account_address, contract_address, .. } = + create_test_init_data(&block_context.chain_info, cairo_version); let default_invoke_args = invoke_tx_args! { - sender_address, - calldata: create_trivial_calldata(test_contract.get_instance_address(0) - )}; + sender_address: account_address, + calldata: create_trivial_calldata(contract_address) + }; // Deploy. - let invalid_tx = deploy_account_tx( + let invalid_tx = AccountTransaction::new_with_default_flags(executable_deploy_account_tx( deploy_account_tx_args! { resource_bounds, - class_hash: test_contract.get_class_hash() + class_hash: FeatureContract::TestContract(cairo_version).get_class_hash() }, - &mut NonceManager::default(), - ); - assert_resource_bounds_exceed_balance_failure(state, block_context, invalid_tx); + )); + assert_resource_bounds_exceed_balance_failure(&mut state, &block_context, invalid_tx); // V1 Invoke. let invalid_max_fee = Fee(BALANCE.0 + 1); - let invalid_tx = account_invoke_tx(invoke_tx_args! { + let invalid_tx = invoke_tx_with_default_flags(invoke_tx_args! { max_fee: invalid_max_fee, version: TransactionVersion::ONE, ..default_invoke_args.clone() }); - assert_resource_bounds_exceed_balance_failure(state, block_context, invalid_tx); + assert_resource_bounds_exceed_balance_failure(&mut state, &block_context, invalid_tx); // V3 txs. macro_rules! assert_resource_overdraft { ($invalid_resource_bounds:expr) => { // V3 invoke. - let invalid_tx = account_invoke_tx(invoke_tx_args! { + let invalid_tx = invoke_tx_with_default_flags(invoke_tx_args! { resource_bounds: $invalid_resource_bounds, ..default_invoke_args.clone() }); - assert_resource_bounds_exceed_balance_failure(state, block_context, invalid_tx); + assert_resource_bounds_exceed_balance_failure(&mut state, &block_context, invalid_tx); // Declare. - let contract_to_declare = FeatureContract::Empty(CairoVersion::Cairo1); + let contract_to_declare = + FeatureContract::Empty(CairoVersion::Cairo1(RunnableCairo1::Casm)); let class_info = calculate_class_info_for_testing(contract_to_declare.get_class()); - let invalid_tx = declare_tx( + let invalid_tx = AccountTransaction::new_with_default_flags(executable_declare_tx( declare_tx_args! { class_hash: contract_to_declare.get_class_hash(), compiled_class_hash: contract_to_declare.get_compiled_class_hash(), - sender_address, + sender_address: account_address, resource_bounds: $invalid_resource_bounds, }, class_info, - ); - assert_resource_bounds_exceed_balance_failure(state, block_context, invalid_tx); + )); + assert_resource_bounds_exceed_balance_failure(&mut state, &block_context, invalid_tx); }; } @@ -1029,14 +1104,11 @@ fn test_max_fee_exceeds_balance( let l1_data_gas_amount = partial_balance.checked_div(DEFAULT_STRK_L1_DATA_GAS_PRICE).unwrap(); let ValidResourceBounds::AllResources(mut base_resource_bounds) = - create_all_resource_bounds( - l1_gas_amount, - DEFAULT_STRK_L1_GAS_PRICE.into(), - l2_gas_amount, - DEFAULT_STRK_L2_GAS_PRICE.into(), - l1_data_gas_amount, - DEFAULT_STRK_L1_DATA_GAS_PRICE.into(), - ) + create_gas_amount_bounds_with_default_price(GasVector { + l1_gas: l1_gas_amount, + l2_gas: l2_gas_amount, + l1_data_gas: l1_data_gas_amount, + }) else { panic!("Invalid resource bounds."); }; @@ -1057,36 +1129,37 @@ fn test_max_fee_exceeds_balance( } #[rstest] +#[case::with_cairo0_account(CairoVersion::Cairo0)] +#[case::with_cairo1_account(CairoVersion::Cairo1(RunnableCairo1::Casm))] +#[cfg_attr( + feature = "cairo_native", + case::with_cairo1_native_account(CairoVersion::Cairo1(RunnableCairo1::Native)) +)] fn test_insufficient_new_resource_bounds_pre_validation( mut block_context: BlockContext, #[values(true, false)] use_kzg_da: bool, - #[values(CairoVersion::Cairo0, CairoVersion::Cairo1)] account_cairo_version: CairoVersion, + #[case] cairo_version: CairoVersion, ) { block_context.block_info.use_kzg_da = use_kzg_da; - let block_context = &block_context; - let account_contract = FeatureContract::AccountWithoutValidations(account_cairo_version); - let test_contract = FeatureContract::TestContract(CairoVersion::Cairo0); - let state = &mut test_state( - &block_context.chain_info, - BALANCE, - &[(account_contract, 1), (test_contract, 1)], - ); + let TestInitData { mut state, account_address, contract_address, .. } = + create_test_init_data(&block_context.chain_info, cairo_version); + let valid_invoke_tx_args = invoke_tx_args! { - sender_address: account_contract.get_instance_address(0), - calldata: create_trivial_calldata(test_contract.get_instance_address(0)), + sender_address: account_address, + calldata: create_trivial_calldata(contract_address), max_fee: MAX_FEE }; - let tx = &account_invoke_tx(valid_invoke_tx_args.clone()); + let tx = &invoke_tx_with_default_flags(valid_invoke_tx_args.clone()); // V3 transaction. let GasPriceVector { l1_gas_price: actual_strk_l1_gas_price, l1_data_gas_price: actual_strk_l1_data_gas_price, l2_gas_price: actual_strk_l2_gas_price, - } = block_context.block_info.gas_prices.get_gas_prices_by_fee_type(&FeeType::Strk); + } = block_context.block_info.gas_prices.strk_gas_prices; let minimal_gas_vector = - estimate_minimal_gas_vector(block_context, tx, &GasVectorComputationMode::All); + estimate_minimal_gas_vector(&block_context, tx, &GasVectorComputationMode::All); let default_resource_bounds = AllResourceBounds { l1_gas: ResourceBounds { @@ -1104,33 +1177,26 @@ fn test_insufficient_new_resource_bounds_pre_validation( }; // Verify successful execution on default resource bounds. - let valid_resources_tx = account_invoke_tx(InvokeTxArgs { + let valid_resources_tx = invoke_tx_with_default_flags(InvokeTxArgs { resource_bounds: ValidResourceBounds::AllResources(default_resource_bounds), ..valid_invoke_tx_args.clone() }) - .execute(state, block_context, true, true); + .execute(&mut state, &block_context); let next_nonce = match valid_resources_tx { Ok(_) => 1, Err(err) => match err { TransactionExecutionError::TransactionPreValidationError( TransactionPreValidationError::TransactionFeeError( - TransactionFeeError::MaxGasAmountTooLow { .. }, - ), - ) => panic!("Transaction failed with expected minimal amount."), - TransactionExecutionError::TransactionPreValidationError( - TransactionPreValidationError::TransactionFeeError( - TransactionFeeError::MaxGasPriceTooLow { .. }, + TransactionFeeError::InsufficientResourceBounds { .. }, ), - ) => panic!("Transaction failed with expected minimal price."), + ) => panic!("Transaction failed with expected minimal resource bounds."), // Ignore failures other than those above (e.g., post-validation errors). _ => 0, }, }; // Max gas amount too low, new resource bounds. - // TODO(Aner): add a test for more than 1 insufficient resource amount, after error message - // contains all insufficient resources. for (insufficient_resource, resource_bounds) in [ (L1Gas, default_resource_bounds.l1_gas), (L2Gas, default_resource_bounds.l2_gas), @@ -1145,20 +1211,25 @@ fn test_insufficient_new_resource_bounds_pre_validation( L2Gas => invalid_resources.l2_gas.max_amount.0 -= 1, L1DataGas => invalid_resources.l1_data_gas.max_amount.0 -= 1, } - let invalid_v3_tx = account_invoke_tx(InvokeTxArgs { + let invalid_v3_tx = invoke_tx_with_default_flags(InvokeTxArgs { resource_bounds: ValidResourceBounds::AllResources(invalid_resources), nonce: nonce!(next_nonce), ..valid_invoke_tx_args.clone() }); - let execution_error = invalid_v3_tx.execute(state, block_context, true, true).unwrap_err(); + let execution_error = invalid_v3_tx.execute(&mut state, &block_context).unwrap_err(); assert_matches!( execution_error, TransactionExecutionError::TransactionPreValidationError( TransactionPreValidationError::TransactionFeeError( - TransactionFeeError::MaxGasAmountTooLow{ - resource, - ..})) - if resource == insufficient_resource + TransactionFeeError::InsufficientResourceBounds{errors} + ) + ) => { + assert_matches!( + errors[0], + ResourceBoundsError::MaxGasAmountTooLow{resource, ..} + if resource == insufficient_resource + ) + } ); } @@ -1171,61 +1242,107 @@ fn test_insufficient_new_resource_bounds_pre_validation( L1DataGas => invalid_resources.l1_data_gas.max_price_per_unit.0 -= 1, } - let invalid_v3_tx = account_invoke_tx(InvokeTxArgs { + let invalid_v3_tx = invoke_tx_with_default_flags(InvokeTxArgs { resource_bounds: ValidResourceBounds::AllResources(invalid_resources), nonce: nonce!(next_nonce), ..valid_invoke_tx_args.clone() }); - let execution_error = invalid_v3_tx.execute(state, block_context, true, true).unwrap_err(); + let execution_error = invalid_v3_tx.execute(&mut state, &block_context).unwrap_err(); assert_matches!( execution_error, TransactionExecutionError::TransactionPreValidationError( TransactionPreValidationError::TransactionFeeError( - TransactionFeeError::MaxGasPriceTooLow{ - resource, - ..})) - if resource == insufficient_resource + TransactionFeeError::InsufficientResourceBounds{ errors } + ) + ) => + assert_matches!( + errors[0], + ResourceBoundsError::MaxGasPriceTooLow{resource,..} + if resource == insufficient_resource + ) ); } + + // Test several insufficient resources in the same transaction. + let mut invalid_resources = default_resource_bounds; + invalid_resources.l2_gas.max_amount.0 -= 1; + invalid_resources.l1_gas.max_price_per_unit.0 -= 1; + invalid_resources.l2_gas.max_price_per_unit.0 -= 1; + invalid_resources.l1_data_gas.max_price_per_unit.0 -= 1; + let invalid_v3_tx = invoke_tx_with_default_flags(InvokeTxArgs { + resource_bounds: ValidResourceBounds::AllResources(invalid_resources), + nonce: nonce!(next_nonce), + ..valid_invoke_tx_args.clone() + }); + let execution_error = invalid_v3_tx.execute(&mut state, &block_context).unwrap_err(); + assert_matches!( + execution_error, + TransactionExecutionError::TransactionPreValidationError( + TransactionPreValidationError::TransactionFeeError( + TransactionFeeError::InsufficientResourceBounds{ errors } + ) + ) => { + assert_eq!(errors.len(), 4); + assert_matches!( + errors[0], + ResourceBoundsError::MaxGasPriceTooLow{resource,..} + if resource == L1Gas + ); + assert_matches!( + errors[1], + ResourceBoundsError::MaxGasPriceTooLow{resource,..} + if resource == L1DataGas + ); + assert_matches!( + errors[2], + ResourceBoundsError::MaxGasAmountTooLow{resource,..} + if resource == L2Gas + ); + assert_matches!( + errors[3], + ResourceBoundsError::MaxGasPriceTooLow{resource,..} + if resource == L2Gas + ); + } + ); } #[rstest] +#[case::with_cairo0_account(CairoVersion::Cairo0)] +#[case::with_cairo1_account(CairoVersion::Cairo1(RunnableCairo1::Casm))] +#[cfg_attr( + feature = "cairo_native", + case::with_cairo1_native_account(CairoVersion::Cairo1(RunnableCairo1::Native)) +)] fn test_insufficient_deprecated_resource_bounds_pre_validation( block_context: BlockContext, - #[values(CairoVersion::Cairo0, CairoVersion::Cairo1)] account_cairo_version: CairoVersion, + #[case] cairo_version: CairoVersion, ) { - let block_context = &block_context; - let account_contract = FeatureContract::AccountWithoutValidations(account_cairo_version); - let test_contract = FeatureContract::TestContract(CairoVersion::Cairo0); - let state = &mut test_state( - &block_context.chain_info, - BALANCE, - &[(account_contract, 1), (test_contract, 1)], - ); + let TestInitData { mut state, account_address, contract_address, .. } = + create_test_init_data(&block_context.chain_info, cairo_version); let valid_invoke_tx_args = invoke_tx_args! { - sender_address: account_contract.get_instance_address(0), - calldata: create_trivial_calldata(test_contract.get_instance_address(0)), + sender_address: account_address, + calldata: create_trivial_calldata(contract_address), max_fee: MAX_FEE }; // The minimal gas estimate does not depend on tx version. - let tx = &account_invoke_tx(valid_invoke_tx_args.clone()); + let tx = &invoke_tx_with_default_flags(valid_invoke_tx_args.clone()); let minimal_l1_gas = - estimate_minimal_gas_vector(block_context, tx, &GasVectorComputationMode::NoL2Gas).l1_gas; + estimate_minimal_gas_vector(&block_context, tx, &GasVectorComputationMode::NoL2Gas).l1_gas; // Test V1 transaction. let gas_prices = &block_context.block_info.gas_prices; - // TODO(Aner, 21/01/24) change to linear combination. - let minimal_fee = minimal_l1_gas - .checked_mul(gas_prices.get_l1_gas_price_by_fee_type(&FeeType::Eth).into()) - .unwrap(); + // TODO(Aner): change to linear combination. + let minimal_fee = + minimal_l1_gas.checked_mul(gas_prices.eth_gas_prices.l1_gas_price.get()).unwrap(); // Max fee too low (lower than minimal estimated fee). let invalid_max_fee = Fee(minimal_fee.0 - 1); - let invalid_v1_tx = account_invoke_tx( + let invalid_v1_tx = invoke_tx_with_default_flags( invoke_tx_args! { max_fee: invalid_max_fee, version: TransactionVersion::ONE, ..valid_invoke_tx_args.clone() }, ); - let execution_error = invalid_v1_tx.execute(state, block_context, true, true).unwrap_err(); + let execution_error = invalid_v1_tx.execute(&mut state, &block_context).unwrap_err(); // Test error. assert_matches!( @@ -1237,46 +1354,59 @@ fn test_insufficient_deprecated_resource_bounds_pre_validation( ); // Test V3 transaction. - let actual_strk_l1_gas_price = gas_prices.get_l1_gas_price_by_fee_type(&FeeType::Strk); + let actual_strk_l1_gas_price = gas_prices.strk_gas_prices.l1_gas_price; // Max L1 gas amount too low, old resource bounds. // TODO(Ori, 1/2/2024): Write an indicative expect message explaining why the conversion works. let insufficient_max_l1_gas_amount = (minimal_l1_gas.0 - 1).into(); - let invalid_v3_tx = account_invoke_tx(invoke_tx_args! { + let invalid_v3_tx = invoke_tx_with_default_flags(invoke_tx_args! { resource_bounds: l1_resource_bounds(insufficient_max_l1_gas_amount, actual_strk_l1_gas_price.into()), ..valid_invoke_tx_args.clone() }); - let execution_error = invalid_v3_tx.execute(state, block_context, true, true).unwrap_err(); + let execution_error = invalid_v3_tx.execute(&mut state, &block_context).unwrap_err(); assert_matches!( execution_error, TransactionExecutionError::TransactionPreValidationError( TransactionPreValidationError::TransactionFeeError( - TransactionFeeError::MaxGasAmountTooLow{ - resource, - max_gas_amount, - minimal_gas_amount})) - if max_gas_amount == insufficient_max_l1_gas_amount && - minimal_gas_amount == minimal_l1_gas && resource == L1Gas + TransactionFeeError::InsufficientResourceBounds{ errors } + ) + ) => + assert_matches!( + errors[0], + ResourceBoundsError::MaxGasAmountTooLow{ + resource, + max_gas_amount, + minimal_gas_amount} + if max_gas_amount == insufficient_max_l1_gas_amount && + minimal_gas_amount == minimal_l1_gas && resource == L1Gas + ) ); // Max L1 gas price too low, old resource bounds. let insufficient_max_l1_gas_price = (actual_strk_l1_gas_price.get().0 - 1).into(); - let invalid_v3_tx = account_invoke_tx(invoke_tx_args! { + let invalid_v3_tx = invoke_tx_with_default_flags(invoke_tx_args! { resource_bounds: l1_resource_bounds(minimal_l1_gas, insufficient_max_l1_gas_price), ..valid_invoke_tx_args.clone() }); - let execution_error = invalid_v3_tx.execute(state, block_context, true, true).unwrap_err(); + let execution_error = invalid_v3_tx.execute(&mut state, &block_context).unwrap_err(); assert_matches!( execution_error, TransactionExecutionError::TransactionPreValidationError( TransactionPreValidationError::TransactionFeeError( - TransactionFeeError::MaxGasPriceTooLow{ resource: L1Gas ,max_gas_price: max_l1_gas_price, actual_gas_price: actual_l1_gas_price })) - if max_l1_gas_price == insufficient_max_l1_gas_price && - actual_l1_gas_price == actual_strk_l1_gas_price.into() + TransactionFeeError::InsufficientResourceBounds{errors,..} + ) + ) => { + assert_matches!( + errors[0], + ResourceBoundsError::MaxGasPriceTooLow{ resource: L1Gas ,max_gas_price: max_l1_gas_price, actual_gas_price: actual_l1_gas_price } + if max_l1_gas_price == insufficient_max_l1_gas_price && + actual_l1_gas_price == actual_strk_l1_gas_price.into() + ) + } ); } -#[rstest] +#[apply(cairo_version)] #[case::l1_bounds(default_l1_resource_bounds(), Resource::L1Gas)] #[case::all_bounds_l1_gas_overdraft(default_all_resource_bounds(), Resource::L1Gas)] #[case::all_bounds_l2_gas_overdraft(default_all_resource_bounds(), Resource::L2Gas)] @@ -1285,13 +1415,15 @@ fn test_actual_fee_gt_resource_bounds( mut block_context: BlockContext, #[case] resource_bounds: ValidResourceBounds, #[case] overdraft_resource: Resource, - #[values(CairoVersion::Cairo0, CairoVersion::Cairo1)] account_cairo_version: CairoVersion, + cairo_version: CairoVersion, ) { + let account_cairo_version = cairo_version; let block_context = &mut block_context; + block_context.versioned_constants.allocation_cost = AllocationCost::ZERO; block_context.block_info.use_kzg_da = true; let mut nonce_manager = NonceManager::default(); let gas_mode = resource_bounds.get_gas_vector_computation_mode(); - let gas_prices = block_context.block_info.gas_prices.get_gas_prices_by_fee_type(&FeeType::Strk); + let gas_prices = &block_context.block_info.gas_prices.strk_gas_prices; let account_contract = FeatureContract::AccountWithoutValidations(account_cairo_version); let test_contract = FeatureContract::TestContract(CairoVersion::Cairo0); let state = &mut test_state( @@ -1311,14 +1443,16 @@ fn test_actual_fee_gt_resource_bounds( }; // Execute the tx to compute the final gas costs. - let tx = &account_invoke_tx(tx_args.clone()); - let execution_result = tx.execute(state, block_context, true, true).unwrap(); + let tx = &invoke_tx_with_default_flags(tx_args.clone()); + let execution_result = tx.execute(state, block_context).unwrap(); let mut actual_gas = execution_result.receipt.gas; // Create new gas bounds that are lower than the actual gas. let (expected_fee, overdraft_resource_bounds) = match gas_mode { GasVectorComputationMode::NoL2Gas => { - let l1_gas_bound = GasAmount(actual_gas.to_discounted_l1_gas(gas_prices).0 - 1); + let l1_gas_bound = GasAmount( + actual_gas.to_l1_gas_for_fee(gas_prices, &block_context.versioned_constants).0 - 1, + ); ( GasVector::from_l1_gas(l1_gas_bound).cost(gas_prices), l1_resource_bounds(l1_gas_bound, gas_prices.l1_gas_price.into()), @@ -1336,7 +1470,7 @@ fn test_actual_fee_gt_resource_bounds( ) } }; - let invalid_tx = account_invoke_tx(invoke_tx_args! { + let invalid_tx = invoke_tx_with_default_flags(invoke_tx_args! { sender_address: sender_address1, resource_bounds: overdraft_resource_bounds, // To get the same DA cost, write a different value. @@ -1345,7 +1479,7 @@ fn test_actual_fee_gt_resource_bounds( ), nonce: nonce_manager.next(sender_address1), }); - let execution_result = invalid_tx.execute(state, block_context, true, true).unwrap(); + let execution_result = invalid_tx.execute(state, block_context).unwrap(); let execution_error = execution_result.revert_error.unwrap(); // Test error and that fee was charged. Should be at most the fee charged in a successful @@ -1357,32 +1491,36 @@ fn test_actual_fee_gt_resource_bounds( } #[rstest] +#[case::with_cairo0_account(CairoVersion::Cairo0)] +#[case::with_cairo1_account(CairoVersion::Cairo1(RunnableCairo1::Casm))] +#[cfg_attr( + feature = "cairo_native", + case::with_cairo1_native_account(CairoVersion::Cairo1(RunnableCairo1::Native)) +)] fn test_invalid_nonce( block_context: BlockContext, default_all_resource_bounds: ValidResourceBounds, - #[values(CairoVersion::Cairo0, CairoVersion::Cairo1)] account_cairo_version: CairoVersion, + #[case] cairo_version: CairoVersion, ) { - let account_contract = FeatureContract::AccountWithoutValidations(account_cairo_version); - let test_contract = FeatureContract::TestContract(CairoVersion::Cairo0); - let state = &mut test_state( - &block_context.chain_info, - BALANCE, - &[(account_contract, 1), (test_contract, 1)], - ); + let TestInitData { mut state, account_address, contract_address, .. } = + create_test_init_data(&block_context.chain_info, cairo_version); let valid_invoke_tx_args = invoke_tx_args! { - sender_address: account_contract.get_instance_address(0), - calldata: create_trivial_calldata(test_contract.get_instance_address(0)), + sender_address: account_address, + calldata: create_trivial_calldata(contract_address), resource_bounds: default_all_resource_bounds, }; - let mut transactional_state = TransactionalState::create_transactional(state); + let mut transactional_state = TransactionalState::create_transactional(&mut state); // Strict, negative flow: account nonce = 0, incoming tx nonce = 1. let invalid_nonce = nonce!(1_u8); - let invalid_tx = - account_invoke_tx(invoke_tx_args! { nonce: invalid_nonce, ..valid_invoke_tx_args.clone() }); + let mut invalid_tx = invoke_tx_with_default_flags( + invoke_tx_args! { nonce: invalid_nonce, ..valid_invoke_tx_args.clone() }, + ); let invalid_tx_context = block_context.to_tx_context(&invalid_tx); + + invalid_tx.execution_flags.strict_nonce_check = true; let pre_validation_err = invalid_tx - .perform_pre_validation_stage(&mut transactional_state, &invalid_tx_context, false, true) + .perform_pre_validation_stage(&mut transactional_state, &invalid_tx_context) .unwrap_err(); // Test error. @@ -1397,21 +1535,25 @@ fn test_invalid_nonce( // Positive flow: account nonce = 0, incoming tx nonce = 1. let valid_nonce = nonce!(1_u8); - let valid_tx = - account_invoke_tx(invoke_tx_args! { nonce: valid_nonce, ..valid_invoke_tx_args.clone() }); + let mut valid_tx = invoke_tx_with_default_flags( + invoke_tx_args! { nonce: valid_nonce, ..valid_invoke_tx_args.clone() }, + ); let valid_tx_context = block_context.to_tx_context(&valid_tx); - valid_tx - .perform_pre_validation_stage(&mut transactional_state, &valid_tx_context, false, false) - .unwrap(); + + valid_tx.execution_flags.strict_nonce_check = false; + valid_tx.perform_pre_validation_stage(&mut transactional_state, &valid_tx_context).unwrap(); // Negative flow: account nonce = 1, incoming tx nonce = 0. let invalid_nonce = nonce!(0_u8); - let invalid_tx = - account_invoke_tx(invoke_tx_args! { nonce: invalid_nonce, ..valid_invoke_tx_args.clone() }); + let mut invalid_tx = invoke_tx_with_default_flags( + invoke_tx_args! { nonce: invalid_nonce, ..valid_invoke_tx_args.clone() }, + ); let invalid_tx_context = block_context.to_tx_context(&invalid_tx); + + invalid_tx.execution_flags.strict_nonce_check = false; let pre_validation_err = invalid_tx - .perform_pre_validation_stage(&mut transactional_state, &invalid_tx_context, false, false) + .perform_pre_validation_stage(&mut transactional_state, &invalid_tx_context) .unwrap_err(); // Test error. @@ -1437,10 +1579,21 @@ fn declare_validate_callinfo( if version == TransactionVersion::ZERO { None } else { + let gas_consumed = match declared_contract_version { + CairoVersion::Cairo0 => 0, + CairoVersion::Cairo1(_) => { + VersionedConstants::create_for_testing() + .os_constants + .gas_costs + .base + .entry_point_initial_budget + - DECLARE_REDEPOSIT_AMOUNT + } + }; expected_validate_call_info( account_class_hash, constants::VALIDATE_DECLARE_ENTRY_POINT_NAME, - 0, + gas_consumed, calldata![declared_class_hash.0], account_address, declared_contract_version, @@ -1453,7 +1606,7 @@ fn declare_validate_callinfo( /// Returns the expected used L1 gas and blob gas (according to use_kzg_da flag) due to execution of /// a declare transaction. fn declare_expected_state_changes_count(version: TransactionVersion) -> StateChangesCount { - // TODO: Make TransactionVersion an enum and use match here. + // TODO(Dori): Make TransactionVersion an enum and use match here. if version == TransactionVersion::ZERO { StateChangesCount { n_storage_updates: 1, // Sender balance. @@ -1477,18 +1630,19 @@ fn declare_expected_state_changes_count(version: TransactionVersion) -> StateCha } } -#[rstest] +#[apply(cairo_version)] #[case(TransactionVersion::ZERO, CairoVersion::Cairo0)] #[case(TransactionVersion::ONE, CairoVersion::Cairo0)] -#[case(TransactionVersion::TWO, CairoVersion::Cairo1)] -#[case(TransactionVersion::THREE, CairoVersion::Cairo1)] +#[case(TransactionVersion::TWO, CairoVersion::Cairo1(RunnableCairo1::Casm))] +#[case(TransactionVersion::THREE, CairoVersion::Cairo1(RunnableCairo1::Casm))] fn test_declare_tx( default_all_resource_bounds: ValidResourceBounds, - #[values(CairoVersion::Cairo0, CairoVersion::Cairo1)] account_cairo_version: CairoVersion, + cairo_version: CairoVersion, #[case] tx_version: TransactionVersion, #[case] empty_contract_version: CairoVersion, #[values(false, true)] use_kzg_da: bool, ) { + let account_cairo_version = cairo_version; let block_context = &BlockContext::create_for_account_testing_with_kzg(use_kzg_da); let versioned_constants = &block_context.versioned_constants; let empty_contract = FeatureContract::Empty(empty_contract_version); @@ -1509,7 +1663,7 @@ fn test_declare_tx( None, ExecutionSummary::default(), ); - let account_tx = declare_tx( + let account_tx = AccountTransaction::new_with_default_flags(executable_declare_tx( declare_tx_args! { max_fee: MAX_FEE, sender_address, @@ -1520,17 +1674,17 @@ fn test_declare_tx( nonce: nonce_manager.next(sender_address), }, class_info.clone(), - ); + )); // Check state before transaction application. assert_matches!( - state.get_compiled_contract_class(class_hash).unwrap_err(), + state.get_compiled_class(class_hash).unwrap_err(), StateError::UndeclaredClassHash(undeclared_class_hash) if undeclared_class_hash == class_hash ); let fee_type = &account_tx.fee_type(); let tx_context = &block_context.to_tx_context(&account_tx); - let actual_execution_info = account_tx.execute(state, block_context, true, true).unwrap(); + let actual_execution_info = account_tx.execute(state, block_context).unwrap(); assert_eq!(actual_execution_info.revert_error, None); // Build expected validate call info. @@ -1540,12 +1694,11 @@ fn test_declare_tx( class_hash, account.get_class_hash(), sender_address, - account.get_runnable_class().tracked_resource( - &versioned_constants.min_compiler_version_for_sierra_gas, - tx_context.tx_info.gas_mode(), - ), + account + .get_runnable_class() + .tracked_resource(&versioned_constants.min_sierra_version_for_sierra_gas, None), if tx_version >= TransactionVersion::THREE { - user_initial_gas_from_bounds(default_all_resource_bounds) + Some(user_initial_gas_from_bounds(default_all_resource_bounds, Some(block_context))) } else { None }, @@ -1565,17 +1718,35 @@ fn test_declare_tx( ) }; - let da_gas = starknet_resources.state.to_gas_vector(use_kzg_da); + let da_gas = starknet_resources.state.da_gas_vector(use_kzg_da); let expected_cairo_resources = get_expected_cairo_resources( versioned_constants, TransactionType::Declare, &starknet_resources, vec![&expected_validate_call_info], ); + let initial_gas = VersionedConstants::create_for_testing() + .os_constants + .gas_costs + .base + .entry_point_initial_budget; + let expected_gas_consumed = match account_cairo_version { + CairoVersion::Cairo0 => GasAmount(0), + CairoVersion::Cairo1(_) => { + // V0 transactions do not handle fee. + if tx_version == TransactionVersion::ZERO { + GasAmount(0) + } else { + GasAmount(initial_gas - DECLARE_REDEPOSIT_AMOUNT) + } + } + }; + let mut expected_actual_resources = TransactionResources { starknet_resources, computation: ComputationResources { vm_resources: expected_cairo_resources, + sierra_gas: expected_gas_consumed, ..Default::default() }, }; @@ -1626,11 +1797,11 @@ fn test_declare_tx( ); // Verify class declaration. - let contract_class_from_state = state.get_compiled_contract_class(class_hash).unwrap(); + let contract_class_from_state = state.get_compiled_class(class_hash).unwrap(); assert_eq!(contract_class_from_state, class_info.contract_class().try_into().unwrap()); // Checks that redeclaring the same contract fails. - let account_tx2 = declare_tx( + let account_tx2 = AccountTransaction::new_with_default_flags(executable_declare_tx( declare_tx_args! { max_fee: MAX_FEE, sender_address, @@ -1641,8 +1812,8 @@ fn test_declare_tx( nonce: nonce_manager.next(sender_address), }, class_info.clone(), - ); - let result = account_tx2.execute(state, block_context, true, true); + )); + let result = account_tx2.execute(state, block_context); assert_matches!( result.unwrap_err(), TransactionExecutionError::DeclareTransactionError{ class_hash:already_declared_class_hash } if @@ -1651,42 +1822,60 @@ fn test_declare_tx( } #[rstest] -fn test_declare_tx_v0(default_l1_resource_bounds: ValidResourceBounds) { - let tx_version = TransactionVersion::ZERO; - let block_context = &BlockContext::create_for_account_testing(); +fn test_declare_tx_v0( + block_context: BlockContext, + default_l1_resource_bounds: ValidResourceBounds, +) { + let TestInitData { mut state, account_address, mut nonce_manager, .. } = create_test_init_data( + &block_context.chain_info, + CairoVersion::Cairo1(RunnableCairo1::Casm), + ); let empty_contract = FeatureContract::Empty(CairoVersion::Cairo0); - let account = FeatureContract::AccountWithoutValidations(CairoVersion::Cairo1); - let chain_info = &block_context.chain_info; - let state = &mut test_state(chain_info, BALANCE, &[(account, 1)]); let class_hash = empty_contract.get_class_hash(); let compiled_class_hash = empty_contract.get_compiled_class_hash(); let class_info = calculate_class_info_for_testing(empty_contract.get_class()); - let sender_address = account.get_instance_address(0); - let mut nonce_manager = NonceManager::default(); - let account_tx = declare_tx( + let tx = executable_declare_tx( declare_tx_args! { max_fee: Fee(0), - sender_address, - version: tx_version, + sender_address: account_address, + version: TransactionVersion::ZERO, resource_bounds: default_l1_resource_bounds, class_hash, compiled_class_hash, - nonce: nonce_manager.next(sender_address), + nonce: nonce_manager.next(account_address), }, class_info.clone(), ); + let account_tx = AccountTransaction { + tx, + execution_flags: ExecutionFlags { charge_fee: false, ..ExecutionFlags::default() }, + }; - let actual_execution_info = account_tx.execute(state, block_context, false, true).unwrap(); // fee not charged for declare v0. + // fee not charged for declare v0. + let actual_execution_info = account_tx.execute(&mut state, &block_context).unwrap(); assert_eq!(actual_execution_info.fee_transfer_call_info, None, "not none"); assert_eq!(actual_execution_info.receipt.fee, Fee(0)); } #[rstest] +#[case::with_cairo0_account(CairoVersion::Cairo0, 0)] +#[case::with_cairo1_account( + CairoVersion::Cairo1(RunnableCairo1::Casm), + VersionedConstants::create_for_testing().os_constants.gas_costs.base.entry_point_initial_budget - DEPLOY_ACCOUNT_REDEPOSIT_AMOUNT +)] +#[cfg_attr( + feature = "cairo_native", + case::with_cairo1_native_account( + CairoVersion::Cairo1(RunnableCairo1::Native), + VersionedConstants::create_for_testing().os_constants.gas_costs.base.entry_point_initial_budget - DEPLOY_ACCOUNT_REDEPOSIT_AMOUNT + ) +)] fn test_deploy_account_tx( - #[values(CairoVersion::Cairo0, CairoVersion::Cairo1)] cairo_version: CairoVersion, + #[case] cairo_version: CairoVersion, #[values(false, true)] use_kzg_da: bool, + #[case] expected_gas_consumed: u64, default_all_resource_bounds: ValidResourceBounds, ) { let block_context = &BlockContext::create_for_account_testing_with_kzg(use_kzg_da); @@ -1696,36 +1885,32 @@ fn test_deploy_account_tx( let account = FeatureContract::AccountWithoutValidations(cairo_version); let account_class_hash = account.get_class_hash(); let state = &mut test_state(chain_info, BALANCE, &[(account, 1)]); - let deploy_account = deploy_account_tx( - deploy_account_tx_args! { - resource_bounds: default_all_resource_bounds, - class_hash: account_class_hash - }, - &mut nonce_manager, + let deploy_account = AccountTransaction::new_with_default_flags( + create_executable_deploy_account_tx_and_update_nonce( + deploy_account_tx_args! { + resource_bounds: default_all_resource_bounds, + class_hash: account_class_hash + }, + &mut nonce_manager, + ), ); // Extract deploy account transaction fields for testing, as it is consumed when creating an // account transaction. let class_hash = deploy_account.class_hash().unwrap(); let deployed_account_address = deploy_account.sender_address(); - let user_initial_gas = user_initial_gas_from_bounds(default_all_resource_bounds); + let user_initial_gas = + user_initial_gas_from_bounds(default_all_resource_bounds, Some(block_context)); // Update the balance of the about to be deployed account contract in the erc20 contract, so it // can pay for the transaction execution. let deployed_account_balance_key = get_fee_token_var_address(deployed_account_address); - for fee_type in FeeType::iter() { - state - .set_storage_at( - chain_info.fee_token_address(&fee_type), - deployed_account_balance_key, - felt!(BALANCE.0), - ) - .unwrap(); - } + + fund_account(chain_info, deploy_account.tx.contract_address(), BALANCE, &mut state.state); let fee_type = &deploy_account.fee_type(); let tx_context = &block_context.to_tx_context(&deploy_account); - let actual_execution_info = deploy_account.execute(state, block_context, true, true).unwrap(); + let actual_execution_info = deploy_account.execute(state, block_context).unwrap(); // Build expected validate call info. let validate_calldata = if let ApiExecutableTransaction::DeployAccount(tx) = &deploy_account.tx @@ -1742,7 +1927,9 @@ fn test_deploy_account_tx( panic!("Expected DeployAccount transaction.") }; - let expected_gas_consumed = 0; + let tracked_resource = account + .get_runnable_class() + .tracked_resource(&versioned_constants.min_sierra_version_for_sierra_gas, None); let expected_validate_call_info = expected_validate_call_info( account_class_hash, constants::VALIDATE_DEPLOY_ENTRY_POINT_NAME, @@ -1750,14 +1937,20 @@ fn test_deploy_account_tx( validate_calldata, deployed_account_address, cairo_version, - account.get_runnable_class().tracked_resource( - &versioned_constants.min_compiler_version_for_sierra_gas, - tx_context.tx_info.gas_mode(), - ), - user_initial_gas, + tracked_resource, + Some(user_initial_gas), ); // Build expected execute call info. + let expected_execute_initial_gas = match tracked_resource { + TrackedResource::CairoSteps => versioned_constants.infinite_gas_for_vm_mode(), + TrackedResource::SierraGas => { + user_initial_gas + // Note that in the case of deploy account, the initial gas in "execute" is limited by + // max_validation_sierra_gas. + .min(versioned_constants.os_constants.validate_max_sierra_gas).0 + } + }; let expected_execute_call_info = Some(CallInfo { call: CallEntryPoint { class_hash: Some(account_class_hash), @@ -1765,9 +1958,10 @@ fn test_deploy_account_tx( entry_point_type: EntryPointType::Constructor, entry_point_selector: selector_from_name(CONSTRUCTOR_ENTRY_POINT_NAME), storage_address: deployed_account_address, - initial_gas: user_initial_gas.unwrap_or(GasAmount(default_initial_gas_cost())).0, + initial_gas: expected_execute_initial_gas, ..Default::default() }, + tracked_resource, ..Default::default() }); @@ -1799,6 +1993,7 @@ fn test_deploy_account_tx( starknet_resources, computation: ComputationResources { vm_resources: expected_cairo_resources, + sierra_gas: expected_gas_consumed.into(), ..Default::default() }, }; @@ -1853,14 +2048,22 @@ fn test_deploy_account_tx( // Negative flow. // Deploy to an existing address. - let deploy_account = deploy_account_tx( - deploy_account_tx_args! { - resource_bounds: default_all_resource_bounds, - class_hash: account_class_hash - }, - &mut nonce_manager, - ); - let error = deploy_account.execute(state, block_context, true, true).unwrap_err(); + let mut tx: ApiExecutableTransaction = executable_deploy_account_tx(deploy_account_tx_args! { + resource_bounds: default_all_resource_bounds, + class_hash: account_class_hash + }); + let nonce = nonce_manager.next(tx.contract_address()); + if let ApiExecutableTransaction::DeployAccount(DeployAccountTransaction { + ref mut tx, .. + }) = tx + { + match tx { + starknet_api::transaction::DeployAccountTransaction::V1(ref mut tx) => tx.nonce = nonce, + starknet_api::transaction::DeployAccountTransaction::V3(ref mut tx) => tx.nonce = nonce, + } + } + let deploy_account = AccountTransaction::new_with_default_flags(tx); + let error = deploy_account.execute(state, block_context).unwrap_err(); assert_matches!( error, TransactionExecutionError::ContractConstructorExecutionFailed( @@ -1882,14 +2085,12 @@ fn test_fail_deploy_account_undeclared_class_hash( let block_context = &block_context; let chain_info = &block_context.chain_info; let state = &mut test_state(chain_info, BALANCE, &[]); - let mut nonce_manager = NonceManager::default(); let undeclared_hash = class_hash!("0xdeadbeef"); - let deploy_account = deploy_account_tx( + let deploy_account = AccountTransaction::new_with_default_flags(executable_deploy_account_tx( deploy_account_tx_args! { resource_bounds: default_all_resource_bounds, class_hash: undeclared_hash }, - &mut nonce_manager, - ); + )); let tx_context = block_context.to_tx_context(&deploy_account); let fee_type = tx_context.tx_info.fee_type(); @@ -1902,7 +2103,7 @@ fn test_fail_deploy_account_undeclared_class_hash( ) .unwrap(); - let error = deploy_account.execute(state, block_context, true, true).unwrap_err(); + let error = deploy_account.execute(state, block_context).unwrap_err(); assert_matches!( error, TransactionExecutionError::ContractConstructorExecutionFailed( @@ -1917,9 +2118,37 @@ fn test_fail_deploy_account_undeclared_class_hash( ); } +#[cfg(feature = "cairo_native")] +fn check_native_validate_error( + error: TransactionExecutionError, + error_msg: &str, + validate_constructor: bool, +) { + let syscall_error = match error { + TransactionExecutionError::ValidateTransactionError { + error: EntryPointExecutionError::NativeUnrecoverableError(boxed_syscall_error), + .. + } => { + assert!(!validate_constructor); + *boxed_syscall_error + } + TransactionExecutionError::ContractConstructorExecutionFailed( + ConstructorEntryPointExecutionError::ExecutionError { + error: EntryPointExecutionError::NativeUnrecoverableError(boxed_syscall_error), + .. + }, + ) => { + assert!(validate_constructor); + *boxed_syscall_error + } + _ => panic!("Unexpected error: {:?}", error), + }; + assert_matches!(syscall_error, SyscallExecutionError::InvalidSyscallInExecutionMode { .. }); + assert!(syscall_error.to_string().contains(error_msg)); +} // TODO(Arni, 1/5/2024): Cover other versions of declare transaction. // TODO(Arni, 1/5/2024): Consider version 0 invoke. -#[rstest] +#[apply(cairo_version)] #[case::validate_version_1(TransactionType::InvokeFunction, false, TransactionVersion::ONE)] #[case::validate_version_3(TransactionType::InvokeFunction, false, TransactionVersion::THREE)] #[case::validate_declare_version_1(TransactionType::Declare, false, TransactionVersion::ONE)] @@ -1934,7 +2163,7 @@ fn test_validate_accounts_tx( #[case] tx_type: TransactionType, #[case] validate_constructor: bool, #[case] tx_version: TransactionVersion, - #[values(CairoVersion::Cairo0, CairoVersion::Cairo1)] cairo_version: CairoVersion, + cairo_version: CairoVersion, ) { let block_context = &block_context; let account_balance = Fee(0); @@ -1950,6 +2179,8 @@ fn test_validate_accounts_tx( sender_address, class_hash, validate_constructor, + validate: true, + charge_fee: false, // We test `__validate__`, and don't care about the charge fee flow. ..Default::default() }; @@ -1962,10 +2193,8 @@ fn test_validate_accounts_tx( additional_data: None, ..default_args }); - // We test `__validate__`, and don't care about the cahrge fee flow. - let charge_fee = false; - let error = account_tx.execute(state, block_context, charge_fee, true).unwrap_err(); + let error = account_tx.execute(state, block_context).unwrap_err(); check_tx_execution_error_for_invalid_scenario!(cairo_version, error, validate_constructor,); // Try to call another contract (forbidden). @@ -1978,14 +2207,26 @@ fn test_validate_accounts_tx( resource_bounds: ValidResourceBounds::create_for_testing_no_fee_enforcement(), ..default_args }); - let error = account_tx.execute(state, block_context, charge_fee, true).unwrap_err(); - check_tx_execution_error_for_custom_hint!( - &error, - "Unauthorized syscall call_contract in execution mode Validate.", - validate_constructor, - ); + let error = account_tx.execute(state, block_context).unwrap_err(); + match cairo_version { + CairoVersion::Cairo0 | CairoVersion::Cairo1(RunnableCairo1::Casm) => { + check_tx_execution_error_for_custom_hint!( + &error, + "Unauthorized syscall call_contract in execution mode Validate.", + validate_constructor, + ); + } + #[cfg(feature = "cairo_native")] + CairoVersion::Cairo1(RunnableCairo1::Native) => { + check_native_validate_error( + error, + "Unauthorized syscall call_contract in execution mode Validate.", + validate_constructor, + ); + } + } - if let CairoVersion::Cairo1 = cairo_version { + if let CairoVersion::Cairo1(runnable_cairo1) = cairo_version { // Try to use the syscall get_block_hash (forbidden). let account_tx = create_account_tx_for_validate_test_nonce_0(FaultyAccountTxCreatorArgs { scenario: GET_BLOCK_HASH, @@ -1994,12 +2235,26 @@ fn test_validate_accounts_tx( resource_bounds: ValidResourceBounds::create_for_testing_no_fee_enforcement(), ..default_args }); - let error = account_tx.execute(state, block_context, charge_fee, true).unwrap_err(); - check_tx_execution_error_for_custom_hint!( - &error, - "Unauthorized syscall get_block_hash in execution mode Validate.", - validate_constructor, - ); + let error = account_tx.execute(state, block_context).unwrap_err(); + match runnable_cairo1 { + RunnableCairo1::Casm => { + check_tx_execution_error_for_custom_hint!( + &error, + "Unauthorized syscall get_block_hash on recent blocks in execution mode \ + Validate.", + validate_constructor, + ); + } + #[cfg(feature = "cairo_native")] + RunnableCairo1::Native => { + check_native_validate_error( + error, + "Unauthorized syscall get_block_hash on recent blocks in execution mode \ + Validate.", + validate_constructor, + ); + } + } } if let CairoVersion::Cairo0 = cairo_version { // Try to use the syscall get_sequencer_address (forbidden). @@ -2009,7 +2264,7 @@ fn test_validate_accounts_tx( resource_bounds: ValidResourceBounds::create_for_testing_no_fee_enforcement(), ..default_args }); - let error = account_tx.execute(state, block_context, charge_fee, true).unwrap_err(); + let error = account_tx.execute(state, block_context).unwrap_err(); check_tx_execution_error_for_custom_hint!( &error, "Unauthorized syscall get_sequencer_address in execution mode Validate.", @@ -2033,7 +2288,7 @@ fn test_validate_accounts_tx( ..default_args }, ); - let result = account_tx.execute(state, block_context, charge_fee, true); + let result = account_tx.execute(state, block_context); assert!(result.is_ok(), "Execution failed: {:?}", result.unwrap_err()); if tx_type != TransactionType::DeployAccount { @@ -2050,7 +2305,7 @@ fn test_validate_accounts_tx( ..default_args }, ); - let result = account_tx.execute(state, block_context, charge_fee, true); + let result = account_tx.execute(state, block_context); assert!(result.is_ok(), "Execution failed: {:?}", result.unwrap_err()); } @@ -2070,7 +2325,7 @@ fn test_validate_accounts_tx( ..default_args }, ); - let result = account_tx.execute(state, block_context, charge_fee, true); + let result = account_tx.execute(state, block_context); assert!(result.is_ok(), "Execution failed: {:?}", result.unwrap_err()); // Call the syscall get_block_timestamp and assert the returned timestamp was modified @@ -2086,11 +2341,11 @@ fn test_validate_accounts_tx( ..default_args }, ); - let result = account_tx.execute(state, block_context, charge_fee, true); + let result = account_tx.execute(state, block_context); assert!(result.is_ok(), "Execution failed: {:?}", result.unwrap_err()); } - if let CairoVersion::Cairo1 = cairo_version { + if let CairoVersion::Cairo1(RunnableCairo1::Casm) = cairo_version { let account_tx = create_account_tx_for_validate_test( // Call the syscall get_execution_info and assert the returned block_info was // modified for validate. @@ -2108,18 +2363,20 @@ fn test_validate_accounts_tx( ..default_args }, ); - let result = account_tx.execute(state, block_context, charge_fee, true); + let result = account_tx.execute(state, block_context); assert!(result.is_ok(), "Execution failed: {:?}", result.unwrap_err()); } } -#[rstest] +#[apply(two_cairo_versions)] fn test_valid_flag( block_context: BlockContext, default_all_resource_bounds: ValidResourceBounds, - #[values(CairoVersion::Cairo0, CairoVersion::Cairo1)] account_cairo_version: CairoVersion, - #[values(CairoVersion::Cairo0, CairoVersion::Cairo1)] test_contract_cairo_version: CairoVersion, + cairo_version1: CairoVersion, + cairo_version2: CairoVersion, ) { + let account_cairo_version = cairo_version1; + let test_contract_cairo_version = cairo_version2; let block_context = &block_context; let account_contract = FeatureContract::AccountWithoutValidations(account_cairo_version); let test_contract = FeatureContract::TestContract(test_contract_cairo_version); @@ -2129,13 +2386,17 @@ fn test_valid_flag( &[(account_contract, 1), (test_contract, 1)], ); - let account_tx = account_invoke_tx(invoke_tx_args! { + let tx = executable_invoke_tx(invoke_tx_args! { sender_address: account_contract.get_instance_address(0), calldata: create_trivial_calldata(test_contract.get_instance_address(0)), resource_bounds: default_all_resource_bounds, }); + let account_tx = AccountTransaction { + tx, + execution_flags: ExecutionFlags { validate: false, ..ExecutionFlags::default() }, + }; - let actual_execution_info = account_tx.execute(state, block_context, true, false).unwrap(); + let actual_execution_info = account_tx.execute(state, block_context).unwrap(); assert!(actual_execution_info.validate_call_info.is_none()); } @@ -2147,29 +2408,22 @@ fn test_only_query_flag( default_all_resource_bounds: ValidResourceBounds, #[values(true, false)] only_query: bool, ) { - let account_balance = BALANCE; - let block_context = &block_context; - let account = FeatureContract::AccountWithoutValidations(CairoVersion::Cairo1); - let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1); - let state = &mut test_state( + let TestInitData { mut state, account_address, contract_address, .. } = create_test_init_data( &block_context.chain_info, - account_balance, - &[(account, 1), (test_contract, 1)], + CairoVersion::Cairo1(RunnableCairo1::Casm), ); let mut version = Felt::from(3_u8); if only_query { version += *QUERY_VERSION_BASE; } - let sender_address = account.get_instance_address(0); - let test_contract_address = test_contract.get_instance_address(0); let expected_tx_info = vec![ - version, // Transaction version. - *sender_address.0.key(), // Account address. - Felt::ZERO, // Max fee. - Felt::ZERO, // Signature. - Felt::ZERO, // Transaction hash. - felt!(&*ChainId::create_for_testing().as_hex()), // Chain ID. - Felt::ZERO, // Nonce. + version, // Transaction version. + *account_address.0.key(), // Account address. + Felt::ZERO, // Max fee. + Felt::ZERO, // Signature. + Felt::ZERO, // Transaction hash. + felt!(&*CHAIN_ID_FOR_TESTS.as_hex()), // Chain ID. + Felt::ZERO, // Nonce. ]; let expected_resource_bounds = vec![ @@ -2195,9 +2449,9 @@ fn test_only_query_flag( let entry_point_selector = selector_from_name("test_get_execution_info"); let expected_call_info = vec![ - *sender_address.0.key(), // Caller address. - *test_contract_address.0.key(), // Storage address. - entry_point_selector.0, // Entry point selector. + *account_address.0.key(), // Caller address. + *contract_address.0.key(), // Storage address. + entry_point_selector.0, // Entry point selector. ]; let expected_block_info = [ felt!(CURRENT_BLOCK_NUMBER), // Block number. @@ -2210,8 +2464,8 @@ fn test_only_query_flag( + expected_unsupported_fields.len() + expected_call_info.len(); let execute_calldata = vec![ - *test_contract_address.0.key(), // Contract address. - entry_point_selector.0, // EP selector. + *contract_address.0.key(), // Contract address. + entry_point_selector.0, // EP selector. // TODO(Ori, 1/2/2024): Write an indicative expect message explaining why the conversion // works. felt!(u64::try_from(calldata_len).expect("Failed to convert usize to u64.")), /* Calldata length. */ @@ -2228,24 +2482,25 @@ fn test_only_query_flag( .concat() .into(), ); - let invoke_tx = crate::test_utils::invoke::invoke_tx(invoke_tx_args! { + let tx = executable_invoke_tx(invoke_tx_args! { calldata: execute_calldata, resource_bounds: default_all_resource_bounds, - sender_address, - only_query, + sender_address: account_address, }); + let execution_flags = ExecutionFlags { only_query, ..Default::default() }; + let invoke_tx = AccountTransaction { tx, execution_flags }; - let tx_execution_info = invoke_tx.execute(state, block_context, true, true).unwrap(); + let tx_execution_info = invoke_tx.execute(&mut state, &block_context).unwrap(); assert_eq!(tx_execution_info.revert_error, None); } #[rstest] fn test_l1_handler(#[values(false, true)] use_kzg_da: bool) { - let gas_mode = GasVectorComputationMode::NoL2Gas; - let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1); - let chain_info = &ChainInfo::create_for_testing(); - let state = &mut test_state(chain_info, BALANCE, &[(test_contract, 1)]); + let gas_mode = GasVectorComputationMode::All; + let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1(RunnableCairo1::Casm)); let block_context = &BlockContext::create_for_account_testing_with_kzg(use_kzg_da); + let chain_info = &block_context.chain_info; + let state = &mut test_state(chain_info, BALANCE, &[(test_contract, 1)]); let contract_address = test_contract.get_instance_address(0); let versioned_constants = &block_context.versioned_constants; let tx = l1handler_tx(Fee(1), contract_address); @@ -2253,10 +2508,11 @@ fn test_l1_handler(#[values(false, true)] use_kzg_da: bool) { let key = calldata.0[1]; let value = calldata.0[2]; let payload_size = tx.payload_size(); - let actual_execution_info = tx.execute(state, block_context, false, true).unwrap(); // Do not charge fee as L1Handler's resource bounds (/max fee) is 0. + let actual_execution_info = tx.execute(state, block_context).unwrap(); // Build the expected call info. let accessed_storage_key = StorageKey::try_from(key).unwrap(); + let gas_consumed = GasAmount(16950); let expected_call_info = CallInfo { call: CallEntryPoint { class_hash: Some(test_contract.get_class_hash()), @@ -2267,36 +2523,43 @@ fn test_l1_handler(#[values(false, true)] use_kzg_da: bool) { storage_address: contract_address, caller_address: ContractAddress::default(), call_type: CallType::Call, - initial_gas: default_initial_gas_cost(), + initial_gas: block_context + .versioned_constants + .os_constants + .l1_handler_max_amount_bounds + .l2_gas + .0, }, execution: CallExecution { retdata: Retdata(vec![value]), - gas_consumed: 6120, + gas_consumed: gas_consumed.0, ..Default::default() }, - charged_resources: ChargedResources::from_execution_resources(ExecutionResources { - n_steps: 151, - n_memory_holes: 0, - builtin_instance_counter: HashMap::from([(BuiltinName::range_check, 6)]), - }), - accessed_storage_keys: HashSet::from_iter(vec![accessed_storage_key]), - tracked_resource: test_contract.get_runnable_class().tracked_resource( - &versioned_constants.min_compiler_version_for_sierra_gas, - GasVectorComputationMode::NoL2Gas, - ), + storage_access_tracker: StorageAccessTracker { + accessed_storage_keys: HashSet::from_iter(vec![accessed_storage_key]), + ..Default::default() + }, + tracked_resource: test_contract + .get_runnable_class() + .tracked_resource(&versioned_constants.min_sierra_version_for_sierra_gas, None), ..Default::default() }; // Build the expected resource mapping. + // l2_gas is 0 in the receipt even though execution resources is not, as we're in NoL2Gas mode. // TODO(Nimrod, 1/5/2024): Change these hard coded values to match to the transaction resources // (currently matches only starknet resources). let expected_gas = match use_kzg_da { true => GasVector { - l1_gas: 17988_u32.into(), - l1_data_gas: 128_u32.into(), - l2_gas: 0_u32.into(), + l1_gas: 16023_u32.into(), + l1_data_gas: 160_u32.into(), + l2_gas: 205875_u32.into(), + }, + false => GasVector { + l1_gas: 18226_u32.into(), + l1_data_gas: 0_u32.into(), + l2_gas: 154975_u32.into(), }, - false => GasVector::from_l1_gas(19131_u32.into()), }; let expected_da_gas = match use_kzg_da { @@ -2316,11 +2579,10 @@ fn test_l1_handler(#[values(false, true)] use_kzg_da: bool) { ( BuiltinName::range_check, get_tx_resources(TransactionType::L1Handler).builtin_instance_counter - [&BuiltinName::range_check] - + 6, + [&BuiltinName::range_check], ), ]), - n_steps: get_tx_resources(TransactionType::L1Handler).n_steps + 164, + n_steps: get_tx_resources(TransactionType::L1Handler).n_steps + 13, n_memory_holes: 0, }; @@ -2336,18 +2598,19 @@ fn test_l1_handler(#[values(false, true)] use_kzg_da: bool) { starknet_resources: actual_execution_info.receipt.resources.starknet_resources.clone(), computation: ComputationResources { vm_resources: expected_execution_resources, + sierra_gas: gas_consumed, ..Default::default() }, }; assert_eq!(actual_execution_info.receipt.resources, expected_tx_resources); assert_eq!( - expected_gas, actual_execution_info.receipt.resources.to_gas_vector( versioned_constants, use_kzg_da, &gas_mode, - ) + ), + expected_gas ); let total_gas = expected_tx_resources.to_gas_vector( @@ -2382,10 +2645,10 @@ fn test_l1_handler(#[values(false, true)] use_kzg_da: bool) { // set the storage back to 0, so the fee will also include the storage write. // TODO(Meshi, 15/6/2024): change the l1_handler_set_value cairo function to - // always uptade the storage instad. + // always update the storage instead. state.set_storage_at(contract_address, StorageKey::try_from(key).unwrap(), Felt::ZERO).unwrap(); let tx_no_fee = l1handler_tx(Fee(0), contract_address); - let error = tx_no_fee.execute(state, block_context, false, true).unwrap_err(); // Do not charge fee as L1Handler's resource bounds (/max fee) is 0. + let error = tx_no_fee.execute(state, block_context).unwrap_err(); // Do not charge fee as L1Handler's resource bounds (/max fee) is 0. // Today, we check that the paid_fee is positive, no matter what was the actual fee. let expected_actual_fee = get_fee_by_gas_vector(&block_context.block_info, total_gas, &FeeType::Eth); @@ -2404,25 +2667,17 @@ fn test_execute_tx_with_invalid_tx_version( block_context: BlockContext, default_all_resource_bounds: ValidResourceBounds, ) { - let cairo_version = CairoVersion::Cairo0; - let account = FeatureContract::AccountWithoutValidations(cairo_version); - let test_contract = FeatureContract::TestContract(cairo_version); - let block_context = &block_context; - let state = - &mut test_state(&block_context.chain_info, BALANCE, &[(account, 1), (test_contract, 1)]); + let TestInitData { mut state, account_address, contract_address, .. } = + create_test_init_data(&block_context.chain_info, CairoVersion::Cairo0); let invalid_version = 12345_u64; - let calldata = create_calldata( - test_contract.get_instance_address(0), - "test_tx_version", - &[felt!(invalid_version)], - ); - let account_tx = account_invoke_tx(invoke_tx_args! { + let calldata = create_calldata(contract_address, "test_tx_version", &[felt!(invalid_version)]); + let account_tx = invoke_tx_with_default_flags(invoke_tx_args! { resource_bounds: default_all_resource_bounds, - sender_address: account.get_instance_address(0), + sender_address: account_address, calldata, }); - let execution_info = account_tx.execute(state, block_context, true, true).unwrap(); + let execution_info = account_tx.execute(&mut state, &block_context).unwrap(); assert!( execution_info .revert_error @@ -2444,7 +2699,7 @@ fn max_event_data() -> usize { VERSIONED_CONSTANTS.tx_event_limits.max_data_length } -#[rstest] +#[apply(cairo_version)] #[case::positive_flow( vec![felt!(1_u16); max_event_keys()], vec![felt!(2_u16); max_event_data()], @@ -2481,16 +2736,10 @@ fn test_emit_event_exceeds_limit( #[case] event_data: Vec, #[case] n_emitted_events: usize, #[case] expected_error: Option, - #[values(CairoVersion::Cairo0, CairoVersion::Cairo1)] cairo_version: CairoVersion, + cairo_version: CairoVersion, ) { - let test_contract = FeatureContract::TestContract(cairo_version); - let account_contract = FeatureContract::AccountWithoutValidations(CairoVersion::Cairo1); - let block_context = &block_context; - let state = &mut test_state( - &block_context.chain_info, - BALANCE, - &[(test_contract, 1), (account_contract, 1)], - ); + let TestInitData { mut state, account_address, contract_address, .. } = + create_test_init_data(&block_context.chain_info, cairo_version); let calldata = [ vec![felt!(u16::try_from(n_emitted_events).expect("Failed to convert usize to u16."))] @@ -2503,7 +2752,7 @@ fn test_emit_event_exceeds_limit( .concat(); let execute_calldata = Calldata( [ - vec![test_contract.get_instance_address(0).into()], + vec![contract_address.into()], vec![selector_from_name("test_emit_events").0], vec![felt!(u16::try_from(calldata.len()).expect("Failed to convert usize to u16."))], calldata.clone(), @@ -2512,13 +2761,13 @@ fn test_emit_event_exceeds_limit( .into(), ); - let account_tx = account_invoke_tx(invoke_tx_args! { - sender_address: account_contract.get_instance_address(0), + let account_tx = invoke_tx_with_default_flags(invoke_tx_args! { + sender_address: account_address, calldata: execute_calldata, resource_bounds: default_all_resource_bounds, nonce: nonce!(0_u8), }); - let execution_info = account_tx.execute(state, block_context, true, true).unwrap(); + let execution_info = account_tx.execute(&mut state, &block_context).unwrap(); match &expected_error { Some(expected_error) => { let error_string = execution_info.revert_error.unwrap().to_string(); @@ -2535,3 +2784,221 @@ fn test_balance_print() { let int = balance_to_big_uint(&Felt::from(16_u64), &Felt::from(1_u64)); assert!(format!("{}", int) == (BigUint::from(u128::MAX) + BigUint::from(17_u128)).to_string()); } + +#[apply(two_cairo_versions)] +#[case::small_user_bounds(invoke_tx_args! { + version: TransactionVersion::THREE, + resource_bounds: create_gas_amount_bounds_with_default_price( + GasVector{ l1_gas: GasAmount(1652), l2_gas: GasAmount(654321), l1_data_gas: GasAmount(0) } + ), +})] +#[case::user_bounds_between_validate_and_execute(invoke_tx_args! { + version: TransactionVersion::THREE, + resource_bounds: create_gas_amount_bounds_with_default_price( + GasVector{ + l1_gas: GasAmount(1652), + l2_gas: versioned_constants.os_constants.validate_max_sierra_gas + GasAmount(1234567), + l1_data_gas: GasAmount(0), + } + ), +})] +#[case::large_user_bounds(invoke_tx_args! { + version: TransactionVersion::THREE, + resource_bounds: default_all_resource_bounds(), +})] +#[case::l1_user_bounds(invoke_tx_args! { + version: TransactionVersion::THREE, + resource_bounds: default_l1_resource_bounds(), +})] +#[case::deprecated_tx_version(invoke_tx_args! { + version: TransactionVersion::ONE, + max_fee: Fee(1000000000000000), +})] +fn test_invoke_max_sierra_gas_validate_execute( + block_context: BlockContext, + versioned_constants: VersionedConstants, + #[case] tx_args: InvokeTxArgs, + cairo_version1: CairoVersion, + cairo_version2: CairoVersion, +) { + let account_cairo_version = cairo_version1; + let contract_cairo_version = cairo_version2; + let account_contract = FeatureContract::AccountWithoutValidations(account_cairo_version); + let test_contract = FeatureContract::TestContract(contract_cairo_version); + let chain_info = &block_context.chain_info; + let state = &mut test_state(chain_info, BALANCE, &[(account_contract, 1), (test_contract, 1)]); + let test_contract_address = test_contract.get_instance_address(0); + let account_contract_address = account_contract.get_instance_address(0); + let calldata = create_calldata(test_contract_address, "recurse", &[felt!(10_u8)]); + let invoke_tx = invoke_tx_with_default_flags(invoke_tx_args! { + sender_address: account_contract_address, calldata: Calldata(Arc::clone(&calldata.0)), .. tx_args + }); + let user_initial_gas = if tx_args.version == TransactionVersion::THREE { + user_initial_gas_from_bounds(tx_args.resource_bounds, Some(&block_context)) + } else { + initial_gas_amount_from_block_context(Some(&block_context)) + }; + + let actual_execution_info = invoke_tx.execute(state, &block_context).unwrap(); + + let account_tracked_resource = account_contract + .get_runnable_class() + .tracked_resource(&versioned_constants.min_sierra_version_for_sierra_gas, None); + + let contract_tracked_resource = test_contract.get_runnable_class().tracked_resource( + &versioned_constants.min_sierra_version_for_sierra_gas, + Some(&account_tracked_resource), + ); + + let actual_validate_initial_gas = + actual_execution_info.validate_call_info.as_ref().unwrap().call.initial_gas; + let expected_validate_initial_gas = match account_tracked_resource { + TrackedResource::CairoSteps => VERSIONED_CONSTANTS.infinite_gas_for_vm_mode(), + TrackedResource::SierraGas => { + versioned_constants.os_constants.validate_max_sierra_gas.min(user_initial_gas).0 + } + }; + + assert_eq!(actual_validate_initial_gas, expected_validate_initial_gas); + + let actual_execute_initial_gas = + actual_execution_info.execute_call_info.as_ref().unwrap().call.initial_gas; + let expected_execute_initial_gas = match account_tracked_resource { + TrackedResource::CairoSteps => VERSIONED_CONSTANTS.infinite_gas_for_vm_mode(), + TrackedResource::SierraGas => { + versioned_constants + .os_constants + .execute_max_sierra_gas + .min( + user_initial_gas + - GasAmount( + actual_execution_info + .validate_call_info + .as_ref() + .unwrap() + .execution + .gas_consumed, + ), + ) + .0 + } + }; + assert_eq!(actual_execute_initial_gas, expected_execute_initial_gas); + + let actual_inner_call_initial_gas = + actual_execution_info.execute_call_info.as_ref().unwrap().inner_calls[0].call.initial_gas; + if contract_tracked_resource == TrackedResource::SierraGas { + assert!(actual_inner_call_initial_gas < actual_execute_initial_gas); + assert!( + actual_inner_call_initial_gas + > actual_execute_initial_gas + - actual_execution_info + .execute_call_info + .as_ref() + .unwrap() + .execution + .gas_consumed + ); + } else { + assert_eq!(actual_inner_call_initial_gas, versioned_constants.infinite_gas_for_vm_mode()); + }; +} + +#[apply(cairo_version)] +#[case::small_user_bounds(deploy_account_tx_args! { + version: TransactionVersion::THREE, + resource_bounds: create_gas_amount_bounds_with_default_price( + GasVector{ l1_gas: GasAmount(2203), l2_gas: GasAmount(654321), l1_data_gas: GasAmount(0) } + ), +})] +#[case::user_bounds_between_validate_and_execute(deploy_account_tx_args! { + version: TransactionVersion::THREE, + resource_bounds: create_gas_amount_bounds_with_default_price( + GasVector{ + l1_gas: GasAmount(2203), + l2_gas: versioned_constants.os_constants.validate_max_sierra_gas + GasAmount(1234567), + l1_data_gas: GasAmount(0), + } + ), +})] +#[case::large_user_bounds(deploy_account_tx_args! { + version: TransactionVersion::THREE, + resource_bounds: default_all_resource_bounds(), +})] +#[case::l1_user_bounds(deploy_account_tx_args! { + version: TransactionVersion::THREE, + resource_bounds: default_l1_resource_bounds(), +})] +#[case::deprecated_tx_version(deploy_account_tx_args! { + version: TransactionVersion::ONE, + max_fee: Fee(1000000000000000), +})] +fn test_deploy_max_sierra_gas_validate_execute( + block_context: BlockContext, + versioned_constants: VersionedConstants, + cairo_version: CairoVersion, + #[case] tx_args: DeployAccountTxArgs, +) { + let chain_info = &block_context.chain_info; + let account = FeatureContract::AccountWithoutValidations(cairo_version); + let account_class_hash = account.get_class_hash(); + let state = &mut test_state(chain_info, BALANCE, &[(account, 1)]); + let deploy_account = AccountTransaction::new_with_default_flags(executable_deploy_account_tx( + deploy_account_tx_args! { + class_hash: account_class_hash, + .. tx_args + }, + )); + + // Extract deploy account transaction fields for testing, as it is consumed when creating an + // account transaction. + let user_initial_gas = if tx_args.version == TransactionVersion::THREE { + user_initial_gas_from_bounds(tx_args.resource_bounds, Some(&block_context)) + } else { + initial_gas_amount_from_block_context(Some(&block_context)) + }; + + // Update the balance of the about to be deployed account contract in the erc20 contract, so it + // can pay for the transaction execution. + fund_account(chain_info, deploy_account.tx.contract_address(), BALANCE, &mut state.state); + + let account_tracked_resource = account + .get_runnable_class() + .tracked_resource(&versioned_constants.min_sierra_version_for_sierra_gas, None); + + let actual_execution_info = deploy_account.execute(state, &block_context).unwrap(); + + let actual_execute_initial_gas = + actual_execution_info.execute_call_info.as_ref().unwrap().call.initial_gas; + let expected_execute_initial_gas = match account_tracked_resource { + TrackedResource::CairoSteps => VERSIONED_CONSTANTS.infinite_gas_for_vm_mode(), + TrackedResource::SierraGas => { + versioned_constants.os_constants.validate_max_sierra_gas.min(user_initial_gas).0 + } + }; + assert_eq!(actual_execute_initial_gas, expected_execute_initial_gas); + + let actual_validate_initial_gas = + actual_execution_info.validate_call_info.as_ref().unwrap().call.initial_gas; + let expected_validate_initial_gas = match account_tracked_resource { + TrackedResource::CairoSteps => VERSIONED_CONSTANTS.infinite_gas_for_vm_mode(), + TrackedResource::SierraGas => { + versioned_constants + .os_constants + .validate_max_sierra_gas + .min( + user_initial_gas + - GasAmount( + actual_execution_info + .execute_call_info + .as_ref() + .unwrap() + .execution + .gas_consumed, + ), + ) + .0 + } + }; + assert_eq!(actual_validate_initial_gas, expected_validate_initial_gas); +} diff --git a/crates/blockifier/src/utils.rs b/crates/blockifier/src/utils.rs index b8b067f0d6a..bf0261d36d6 100644 --- a/crates/blockifier/src/utils.rs +++ b/crates/blockifier/src/utils.rs @@ -1,5 +1,8 @@ use std::collections::HashMap; +use cairo_vm::vm::runners::cairo_runner::ExecutionResources; + +use crate::blockifier_versioned_constants::GasCosts; use crate::transaction::errors::NumericConversionError; #[cfg(test)] @@ -48,6 +51,7 @@ pub const fn const_max(a: u128, b: u128) -> u128 { [a, b][(a < b) as usize] } +// TODO(Meshi): Move this code to starknet API. /// Conversion from u64 to usize. This conversion should only be used if the value came from a /// usize. pub fn usize_from_u64(val: u64) -> Result { @@ -59,3 +63,26 @@ pub fn usize_from_u64(val: u64) -> Result { pub fn u64_from_usize(val: usize) -> u64 { val.try_into().expect("Conversion from usize to u64 should not fail.") } + +pub fn get_gas_cost_from_vm_resources( + execution_resources: &ExecutionResources, + gas_costs: &GasCosts, +) -> u64 { + let n_steps = u64_from_usize(execution_resources.n_steps); + let n_memory_holes = u64_from_usize(execution_resources.n_memory_holes); + let total_builtin_gas_cost: u64 = execution_resources + .builtin_instance_counter + .iter() + .map(|(builtin, amount)| { + let builtin_cost = gas_costs + .builtins + .get_builtin_gas_cost(builtin) + .unwrap_or_else(|err| panic!("Failed to get gas cost: {}", err)); + builtin_cost * u64_from_usize(*amount) + }) + .sum(); + + n_steps * gas_costs.base.step_gas_cost + + n_memory_holes * gas_costs.base.memory_hole_gas_cost + + total_builtin_gas_cost +} diff --git a/crates/blockifier/src/versioned_constants_test.rs b/crates/blockifier/src/versioned_constants_test.rs index 7947afc52a7..324988a72fa 100644 --- a/crates/blockifier/src/versioned_constants_test.rs +++ b/crates/blockifier/src/versioned_constants_test.rs @@ -1,14 +1,18 @@ +use std::path::PathBuf; + use glob::{glob, Paths}; use pretty_assertions::assert_eq; +use starknet_api::block::StarknetVersion; +use starknet_infra_utils::compile_time_cargo_manifest_dir; use super::*; -// TODO: Test Starknet OS validation. -// TODO: Add an unallowed field scenario for GasCost parsing. +// TODO(Gilad): Test Starknet OS validation. +// TODO(OriF): Add an unallowed field scenario for GasCost parsing. /// Returns all JSON files in the resources directory (should be all versioned constants files). fn all_jsons_in_dir() -> Paths { - glob(format!("{}/resources/*.json", env!("CARGO_MANIFEST_DIR")).as_str()).unwrap() + glob(format!("{}/resources/*.json", compile_time_cargo_manifest_dir!()).as_str()).unwrap() } #[test] @@ -19,7 +23,7 @@ fn test_successful_gas_costs_parsing() { "entry_point_initial_budget": { "step_gas_cost": 3 }, - "entry_point_gas_cost": { + "syscall_base_gas_cost": { "entry_point_initial_budget": 4, "step_gas_cost": 5 }, @@ -29,11 +33,14 @@ fn test_successful_gas_costs_parsing() { let os_constants: Arc = Arc::new(OsConstants { gas_costs, ..Default::default() }); let versioned_constants = VersionedConstants { os_constants, ..Default::default() }; - assert_eq!(versioned_constants.os_constants.gas_costs.step_gas_cost, 2); - assert_eq!(versioned_constants.os_constants.gas_costs.entry_point_initial_budget, 2 * 3); // step_gas_cost * 3. + assert_eq!(versioned_constants.os_constants.gas_costs.base.step_gas_cost, 2); + assert_eq!(versioned_constants.os_constants.gas_costs.base.entry_point_initial_budget, 2 * 3); // step_gas_cost * 3. // entry_point_initial_budget * 4 + step_gas_cost * 5. - assert_eq!(versioned_constants.os_constants.gas_costs.entry_point_gas_cost, 6 * 4 + 2 * 5); + assert_eq!( + versioned_constants.os_constants.gas_costs.base.syscall_base_gas_cost, + 6 * 4 + 2 * 5 + ); } /// Assert versioned constants overrides are used when provided. @@ -43,18 +50,21 @@ fn test_versioned_constants_overrides() { let updated_invoke_tx_max_n_steps = versioned_constants.invoke_tx_max_n_steps + 1; let updated_validate_max_n_steps = versioned_constants.validate_max_n_steps + 1; let updated_max_recursion_depth = versioned_constants.max_recursion_depth + 1; + let updated_max_n_events = versioned_constants.tx_event_limits.max_n_emitted_events + 1; // Create a versioned constants copy with overriden values. let result = VersionedConstants::get_versioned_constants(VersionedConstantsOverrides { validate_max_n_steps: updated_validate_max_n_steps, max_recursion_depth: updated_max_recursion_depth, invoke_tx_max_n_steps: updated_invoke_tx_max_n_steps, + max_n_events: updated_max_n_events, }); // Assert the new values are used. assert_eq!(result.invoke_tx_max_n_steps, updated_invoke_tx_max_n_steps); assert_eq!(result.validate_max_n_steps, updated_validate_max_n_steps); assert_eq!(result.max_recursion_depth, updated_max_recursion_depth); + assert_eq!(result.tx_event_limits.max_n_emitted_events, updated_max_n_events); } #[test] @@ -76,8 +86,20 @@ fn test_string_inside_composed_field() { fn check_constants_serde_error(json_data: &str, expected_error_message: &str) { let mut json_data_raw: IndexMap = serde_json::from_str(json_data).unwrap(); - json_data_raw.insert("validate_block_number_rounding".to_string(), 0.into()); - json_data_raw.insert("validate_timestamp_rounding".to_string(), 0.into()); + json_data_raw.insert("validate_block_number_rounding".into(), 0.into()); + json_data_raw.insert("validate_timestamp_rounding".into(), 0.into()); + json_data_raw.insert( + "os_contract_addresses".into(), + serde_json::to_value(OsContractAddresses::default()).unwrap(), + ); + json_data_raw.insert("v1_bound_accounts_cairo0".into(), serde_json::Value::Array(vec![])); + json_data_raw.insert("v1_bound_accounts_cairo1".into(), serde_json::Value::Array(vec![])); + json_data_raw.insert("v1_bound_accounts_max_tip".into(), "0x0".into()); + json_data_raw.insert( + "l1_handler_max_amount_bounds".into(), + serde_json::to_value(GasVector::default()).unwrap(), + ); + json_data_raw.insert("data_gas_accounts".into(), serde_json::Value::Array(vec![])); let json_data = &serde_json::to_string(&json_data_raw).unwrap(); @@ -156,8 +178,9 @@ fn test_all_jsons_in_enum() { // Check that all JSON files are in the enum and can be loaded. for file in all_jsons { let filename = file.file_stem().unwrap().to_str().unwrap().to_string(); - assert!(filename.starts_with("versioned_constants_")); - let version_str = filename.trim_start_matches("versioned_constants_").replace("_", "."); + assert!(filename.starts_with("blockifier_versioned_constants_")); + let version_str = + filename.trim_start_matches("blockifier_versioned_constants_").replace("_", "."); let version = StarknetVersion::try_from(version_str).unwrap(); assert!(VersionedConstants::get(&version).is_ok()); } @@ -167,3 +190,34 @@ fn test_all_jsons_in_enum() { fn test_latest_no_panic() { VersionedConstants::latest_constants(); } + +#[test] +fn test_syscall_gas_cost_calculation() { + const EXPECTED_CALL_CONTRACT_GAS_COST: u64 = 91420; + const EXPECTED_SECP256K1MUL_GAS_COST: u64 = 8143850; + const EXPECTED_SHA256PROCESSBLOCK_GAS_COST: u64 = 841295; + + let versioned_constants = VersionedConstants::latest_constants().clone(); + + assert_eq!( + versioned_constants.get_syscall_gas_cost(&SyscallSelector::CallContract).base, + EXPECTED_CALL_CONTRACT_GAS_COST + ); + assert_eq!( + versioned_constants.get_syscall_gas_cost(&SyscallSelector::Secp256k1Mul).base, + EXPECTED_SECP256K1MUL_GAS_COST + ); + assert_eq!( + versioned_constants.get_syscall_gas_cost(&SyscallSelector::Sha256ProcessBlock).base, + EXPECTED_SHA256PROCESSBLOCK_GAS_COST + ); +} + +/// Linear gas cost factor of deploy syscall should not be trivial. +#[test] +fn test_call_data_factor_gas_cost_calculation() { + assert!( + VersionedConstants::latest_constants().os_constants.gas_costs.syscalls.deploy.linear_factor + > 0 + ) +} diff --git a/crates/blockifier/tests/feature_contracts_compatibility_test.rs b/crates/blockifier/tests/feature_contracts_compatibility_test.rs deleted file mode 100644 index 845e57b318e..00000000000 --- a/crates/blockifier/tests/feature_contracts_compatibility_test.rs +++ /dev/null @@ -1,134 +0,0 @@ -use std::fs; - -use blockifier::test_utils::contracts::FeatureContract; -use blockifier::test_utils::CairoVersion; -use pretty_assertions::assert_eq; -use rstest::rstest; - -const CAIRO0_FEATURE_CONTRACTS_DIR: &str = "feature_contracts/cairo0"; -const CAIRO1_FEATURE_CONTRACTS_DIR: &str = "feature_contracts/cairo1"; -#[cfg(feature = "cairo_native")] -const NATIVE_FEATURE_CONTRACTS_DIR: &str = "feature_contracts/cairo_native"; -const COMPILED_CONTRACTS_SUBDIR: &str = "compiled"; -const FIX_COMMAND: &str = "FIX_FEATURE_TEST=1 cargo test -p blockifier --test \ - feature_contracts_compatibility_test --features testing -- \ - --include-ignored"; - -// To fix Cairo0 feature contracts, first enter a python venv and install the requirements: -// ``` -// python -m venv tmp_venv -// . tmp_venv/bin/activate -// pip install -r crates/blockifier/tests/requirements.txt -// ``` -// Then, run the FIX_COMMAND above. - -// To fix Cairo1 feature contracts, first clone the Cairo repo and checkout the required tag. -// The repo should be located next to the sequencer repo: -// / -// - sequencer/ -// - cairo/ -// Then, run the FIX_COMMAND above. - -// Checks that: -// 1. `TEST_CONTRACTS` dir exists and contains only `.cairo` files and the subdirectory -// `COMPILED_CONTRACTS_SUBDIR`. -// 2. for each `X.cairo` file in `TEST_CONTRACTS` there exists an `X_compiled.json` file in -// `COMPILED_CONTRACTS_SUBDIR` which equals `starknet-compile-deprecated X.cairo --no_debug_info`. -fn verify_feature_contracts_compatibility(fix: bool, cairo_version: CairoVersion) { - // TODO(Dori, 1/10/2024): Parallelize this test. - for contract in FeatureContract::all_feature_contracts() - .filter(|contract| contract.cairo_version() == cairo_version) - { - // Compare output of cairo-file on file with existing compiled file. - let expected_compiled_output = contract.compile(); - let existing_compiled_path = contract.get_compiled_path(); - - if fix { - fs::write(&existing_compiled_path, &expected_compiled_output).unwrap(); - } - let existing_compiled_contents = fs::read_to_string(&existing_compiled_path) - .unwrap_or_else(|_| panic!("Cannot read {existing_compiled_path}.")); - - if String::from_utf8(expected_compiled_output).unwrap() != existing_compiled_contents { - panic!( - "{} does not compile to {existing_compiled_path}.\nRun `{FIX_COMMAND}` to fix the \ - existing file according to locally installed `starknet-compile-deprecated`.\n", - contract.get_source_path() - ); - } - } -} - -/// Verifies that the feature contracts directory contains the expected contents, and returns a list -/// of pairs (source_path, base_filename, compiled_path) for each contract. -fn verify_and_get_files(cairo_version: CairoVersion) -> Vec<(String, String, String)> { - let mut paths = vec![]; - let directory = match cairo_version { - CairoVersion::Cairo0 => CAIRO0_FEATURE_CONTRACTS_DIR, - CairoVersion::Cairo1 => CAIRO1_FEATURE_CONTRACTS_DIR, - #[cfg(feature = "cairo_native")] - CairoVersion::Native => NATIVE_FEATURE_CONTRACTS_DIR, - }; - let compiled_extension = match cairo_version { - CairoVersion::Cairo0 => "_compiled.json", - CairoVersion::Cairo1 => ".casm.json", - #[cfg(feature = "cairo_native")] - CairoVersion::Native => ".sierra.json", - }; - for file in fs::read_dir(directory).unwrap() { - let path = file.unwrap().path(); - - // Verify `TEST_CONTRACTS` file and directory structure. - if !path.is_file() { - if let Some(dir_name) = path.file_name() { - assert_eq!( - dir_name, - COMPILED_CONTRACTS_SUBDIR, - "Found directory '{}' in `{directory}`, which should contain only the \ - `{COMPILED_CONTRACTS_SUBDIR}` directory.", - dir_name.to_string_lossy() - ); - continue; - } - } - let path_str = path.to_string_lossy(); - assert_eq!( - path.extension().unwrap(), - "cairo", - "Found a non-Cairo file '{path_str}' in `{directory}`" - ); - - let file_name = path.file_stem().unwrap().to_string_lossy(); - let existing_compiled_path = - format!("{directory}/{COMPILED_CONTRACTS_SUBDIR}/{file_name}{compiled_extension}"); - - paths.push((path_str.to_string(), file_name.to_string(), existing_compiled_path)); - } - - paths -} - -#[test] -fn verify_feature_contracts_match_enum() { - let mut compiled_paths_from_enum: Vec = FeatureContract::all_feature_contracts() - .map(|contract| contract.get_compiled_path()) - .collect(); - let mut compiled_paths_on_filesystem: Vec = verify_and_get_files(CairoVersion::Cairo0) - .into_iter() - .chain(verify_and_get_files(CairoVersion::Cairo1)) - .map(|(_, _, compiled_path)| compiled_path) - .collect(); - compiled_paths_from_enum.sort(); - compiled_paths_on_filesystem.sort(); - assert_eq!(compiled_paths_from_enum, compiled_paths_on_filesystem); -} - -// todo(rdr): find the right way to feature verify native contracts as well -#[rstest] -#[ignore] -fn verify_feature_contracts( - #[values(CairoVersion::Cairo0, CairoVersion::Cairo1)] cairo_version: CairoVersion, -) { - let fix_features = std::env::var("FIX_FEATURE_TEST").is_ok(); - verify_feature_contracts_compatibility(fix_features, cairo_version) -} diff --git a/crates/blockifier_reexecution/Cargo.toml b/crates/blockifier_reexecution/Cargo.toml index d179975bb94..686790296f3 100644 --- a/crates/blockifier_reexecution/Cargo.toml +++ b/crates/blockifier_reexecution/Cargo.toml @@ -15,7 +15,7 @@ cairo-lang-starknet-classes.workspace = true cairo-lang-utils.workspace = true clap = { workspace = true, features = ["cargo", "derive"] } flate2.workspace = true -google-cloud-storage = "0.22.1" +google-cloud-storage.workspace = true indexmap = { workspace = true, features = ["serde"] } papyrus_execution.workspace = true pretty_assertions.workspace = true diff --git a/crates/blockifier_reexecution/README.md b/crates/blockifier_reexecution/README.md index fcaeec04af9..3be6ca4e292 100644 --- a/crates/blockifier_reexecution/README.md +++ b/crates/blockifier_reexecution/README.md @@ -24,9 +24,9 @@ cargo run --bin blockifier_reexecution write-to-file -n -d -d -b ... +cargo run --release --bin blockifier_reexecution reexecute -d -b ... ``` ### Downloading Offline Reexecution Files from the GC Bucket diff --git a/crates/blockifier_reexecution/src/main.rs b/crates/blockifier_reexecution/src/main.rs index a60c2f39fcd..9c3733e1283 100644 --- a/crates/blockifier_reexecution/src/main.rs +++ b/crates/blockifier_reexecution/src/main.rs @@ -1,16 +1,14 @@ use std::fs; use std::path::Path; -use blockifier_reexecution::state_reader::test_state_reader::{ - ConsecutiveTestStateReaders, - OfflineConsecutiveStateReaders, -}; +use blockifier_reexecution::state_reader::offline_state_reader::OfflineConsecutiveStateReaders; +use blockifier_reexecution::state_reader::test_state_reader::ConsecutiveTestStateReaders; use blockifier_reexecution::state_reader::utils::{ get_block_numbers_for_reexecution, guess_chain_id_from_node_url, reexecute_and_verify_correctness, write_block_reexecution_data_to_file, - JSON_RPC_VERSION, + FULL_RESOURCES_DIR, }; use clap::{Args, Parser, Subcommand}; use google_cloud_storage::client::{Client, ClientConfig}; @@ -23,7 +21,6 @@ use starknet_gateway::config::RpcStateReaderConfig; const BUCKET: &str = "reexecution_artifacts"; const RESOURCES_DIR: &str = "/resources"; -const FULL_RESOURCES_DIR: &str = "./crates/blockifier_reexecution/resources"; const FILE_NAME: &str = "/reexecution_data.json"; const OFFLINE_PREFIX_FILE: &str = "/offline_reexecution_files_prefix"; @@ -148,7 +145,7 @@ enum Command { fn parse_block_numbers_args(block_numbers: Option>) -> Vec { block_numbers .map(|block_numbers| block_numbers.into_iter().map(BlockNumber).collect()) - .unwrap_or(get_block_numbers_for_reexecution()) + .unwrap_or_else(|| get_block_numbers_for_reexecution(None)) } #[derive(Debug, Args)] @@ -183,10 +180,7 @@ async fn main() { rpc_args.node_url ); - let config = RpcStateReaderConfig { - url: rpc_args.node_url.clone(), - json_rpc_version: JSON_RPC_VERSION.to_string(), - }; + let config = RpcStateReaderConfig::from_url(rpc_args.node_url.clone()); // RPC calls are "synchronous IO" (see, e.g., https://stackoverflow.com/questions/74547541/when-should-you-use-tokios-spawn-blocking) // for details), so should be executed in a blocking thread. @@ -291,7 +285,7 @@ async fn main() { ..Default::default() }) .await - // TODO: check that the error is not found error. + // TODO(Aner): check that the error is not found error. .is_err(), "Block {block_number} reexecution data file already exists in bucket." ) diff --git a/crates/blockifier_reexecution/src/state_reader.rs b/crates/blockifier_reexecution/src/state_reader.rs index eadb24337f8..65e7dec1585 100644 --- a/crates/blockifier_reexecution/src/state_reader.rs +++ b/crates/blockifier_reexecution/src/state_reader.rs @@ -1,10 +1,12 @@ pub mod compile; mod errors; +pub mod offline_state_reader; #[cfg(test)] pub mod raw_rpc_json_test; pub mod reexecution_state_reader; #[cfg(test)] -#[cfg(feature = "blockifier_regression_https_testing")] +pub mod reexecution_test; +#[cfg(all(test, feature = "blockifier_regression_https_testing"))] pub mod rpc_https_test; pub mod serde_utils; pub mod test_state_reader; diff --git a/crates/blockifier_reexecution/src/state_reader/compile.rs b/crates/blockifier_reexecution/src/state_reader/compile.rs index 4088dcea60f..74ea4d12c9f 100644 --- a/crates/blockifier_reexecution/src/state_reader/compile.rs +++ b/crates/blockifier_reexecution/src/state_reader/compile.rs @@ -10,7 +10,7 @@ use cairo_lang_starknet_classes::contract_class::ContractEntryPoints; use cairo_lang_utils::bigint::BigUintAsHex; use flate2::bufread; use serde::Deserialize; -use starknet_api::contract_class::{ContractClass, EntryPointType}; +use starknet_api::contract_class::{ContractClass, EntryPointType, SierraVersion}; use starknet_api::core::EntryPointSelector; use starknet_api::deprecated_contract_class::{ ContractClass as DeprecatedContractClass, @@ -72,8 +72,11 @@ pub fn decode_reader(bytes: Vec) -> io::Result { Ok(s) } -/// Compile a FlattenedSierraClass to a ContractClass V1 (casm) using cairo_lang_starknet_classes. -pub fn sierra_to_contact_class_v1(sierra: FlattenedSierraClass) -> StateResult { +/// Compile a FlattenedSierraClass to a versioned ContractClass V1 (casm) using +/// cairo_lang_starknet_classes. +pub fn sierra_to_versioned_contract_class_v1( + sierra: FlattenedSierraClass, +) -> StateResult<(ContractClass, SierraVersion)> { let middle_sierra: MiddleSierraContractClass = { let v = serde_json::to_value(sierra).map_err(serde_err_to_state_err); serde_json::from_value(v?).map_err(serde_err_to_state_err)? @@ -86,6 +89,11 @@ pub fn sierra_to_contact_class_v1(sierra: FlattenedSierraClass) -> StateResult>(); + + let sierra_version = SierraVersion::extract_from_program(&sierra_program_values).unwrap(); + let casm = cairo_lang_starknet_classes::casm_contract_class::CasmContractClass::from_contract_class( sierra, @@ -94,7 +102,8 @@ pub fn sierra_to_contact_class_v1(sierra: FlattenedSierraClass) -> StateResult = Result; diff --git a/crates/blockifier_reexecution/src/state_reader/offline_state_reader.rs b/crates/blockifier_reexecution/src/state_reader/offline_state_reader.rs new file mode 100644 index 00000000000..5ec14aabfa8 --- /dev/null +++ b/crates/blockifier_reexecution/src/state_reader/offline_state_reader.rs @@ -0,0 +1,262 @@ +use std::fs; + +use blockifier::abi::constants; +use blockifier::blockifier::config::TransactionExecutorConfig; +use blockifier::blockifier::transaction_executor::TransactionExecutor; +use blockifier::blockifier_versioned_constants::VersionedConstants; +use blockifier::bouncer::BouncerConfig; +use blockifier::context::BlockContext; +use blockifier::execution::contract_class::RunnableCompiledClass; +use blockifier::state::cached_state::{CommitmentStateDiff, StateMaps}; +use blockifier::state::errors::StateError; +use blockifier::state::state_api::{StateReader, StateResult}; +use blockifier::transaction::transaction_execution::Transaction as BlockifierTransaction; +use serde::{Deserialize, Serialize}; +use starknet_api::block::{BlockHash, BlockHashAndNumber, BlockInfo, BlockNumber, StarknetVersion}; +use starknet_api::core::{ChainId, ClassHash, CompiledClassHash, ContractAddress, Nonce}; +use starknet_api::state::StorageKey; +use starknet_api::transaction::{Transaction, TransactionHash}; +use starknet_core::types::ContractClass as StarknetContractClass; +use starknet_types_core::felt::Felt; + +use crate::state_reader::compile::{ + legacy_to_contract_class_v0, + sierra_to_versioned_contract_class_v1, +}; +use crate::state_reader::errors::ReexecutionResult; +use crate::state_reader::reexecution_state_reader::{ + ConsecutiveReexecutionStateReaders, + ReexecutionStateReader, +}; +use crate::state_reader::test_state_reader::StarknetContractClassMapping; +use crate::state_reader::utils::{get_chain_info, ReexecutionStateMaps}; + +pub struct OfflineReexecutionData { + offline_state_reader_prev_block: OfflineStateReader, + block_context_next_block: BlockContext, + transactions_next_block: Vec, + state_diff_next_block: CommitmentStateDiff, +} + +#[derive(Serialize, Deserialize)] +pub struct SerializableDataNextBlock { + pub block_info_next_block: BlockInfo, + pub starknet_version: StarknetVersion, + pub transactions_next_block: Vec<(Transaction, TransactionHash)>, + pub state_diff_next_block: CommitmentStateDiff, + pub declared_classes: StarknetContractClassMapping, +} + +#[derive(Serialize, Deserialize)] +pub struct SerializableDataPrevBlock { + pub state_maps: ReexecutionStateMaps, + pub contract_class_mapping: StarknetContractClassMapping, +} + +#[derive(Serialize, Deserialize)] +pub struct SerializableOfflineReexecutionData { + pub serializable_data_prev_block: SerializableDataPrevBlock, + pub serializable_data_next_block: SerializableDataNextBlock, + pub chain_id: ChainId, + pub old_block_hash: BlockHash, +} + +impl SerializableOfflineReexecutionData { + pub fn write_to_file(&self, full_file_path: &str) -> ReexecutionResult<()> { + let file_path = full_file_path.rsplit_once('/').expect("Invalid file path.").0; + fs::create_dir_all(file_path) + .unwrap_or_else(|err| panic!("Failed to create directory {file_path}. Error: {err}")); + fs::write(full_file_path, serde_json::to_string_pretty(&self)?) + .unwrap_or_else(|err| panic!("Failed to write to file {full_file_path}. Error: {err}")); + Ok(()) + } + + pub fn read_from_file(full_file_path: &str) -> ReexecutionResult { + let file_content = fs::read_to_string(full_file_path).unwrap_or_else(|err| { + panic!("Failed to read reexecution data from file {full_file_path}. Error: {err}") + }); + Ok(serde_json::from_str(&file_content)?) + } +} + +impl From for OfflineReexecutionData { + fn from(value: SerializableOfflineReexecutionData) -> Self { + let SerializableOfflineReexecutionData { + serializable_data_prev_block: + SerializableDataPrevBlock { state_maps, contract_class_mapping }, + serializable_data_next_block: + SerializableDataNextBlock { + block_info_next_block, + starknet_version, + transactions_next_block, + state_diff_next_block, + declared_classes, + }, + chain_id, + old_block_hash, + } = value; + + let offline_state_reader_prev_block = OfflineStateReader { + state_maps: state_maps.try_into().expect("Failed to deserialize state maps."), + contract_class_mapping, + old_block_hash, + }; + + // Use the declared classes from the next block to allow retrieving the class info. + let transactions_next_block = + OfflineStateReader { contract_class_mapping: declared_classes, ..Default::default() } + .api_txs_to_blockifier_txs_next_block(transactions_next_block) + .expect("Failed to convert starknet-api transactions to blockifier transactions."); + + Self { + offline_state_reader_prev_block, + block_context_next_block: BlockContext::new( + block_info_next_block, + get_chain_info(&chain_id), + VersionedConstants::get(&starknet_version).unwrap().clone(), + BouncerConfig::max(), + ), + transactions_next_block, + state_diff_next_block, + } + } +} + +#[derive(Clone, Default)] +pub struct OfflineStateReader { + pub state_maps: StateMaps, + pub contract_class_mapping: StarknetContractClassMapping, + pub old_block_hash: BlockHash, +} + +impl StateReader for OfflineStateReader { + fn get_storage_at( + &self, + contract_address: ContractAddress, + key: StorageKey, + ) -> StateResult { + Ok(*self.state_maps.storage.get(&(contract_address, key)).ok_or( + StateError::StateReadError(format!( + "Missing Storage Value at contract_address: {}, key:{:?}", + contract_address, key + )), + )?) + } + + fn get_nonce_at(&self, contract_address: ContractAddress) -> StateResult { + Ok(*self.state_maps.nonces.get(&contract_address).ok_or(StateError::StateReadError( + format!("Missing nonce at contract_address: {contract_address}"), + ))?) + } + + fn get_class_hash_at(&self, contract_address: ContractAddress) -> StateResult { + Ok(*self.state_maps.class_hashes.get(&contract_address).ok_or( + StateError::StateReadError(format!( + "Missing class hash at contract_address: {contract_address}" + )), + )?) + } + + fn get_compiled_class(&self, class_hash: ClassHash) -> StateResult { + match self.get_contract_class(&class_hash)? { + StarknetContractClass::Sierra(sierra) => { + let (casm, _) = sierra_to_versioned_contract_class_v1(sierra).unwrap(); + Ok(casm.try_into().unwrap()) + } + StarknetContractClass::Legacy(legacy) => { + Ok(legacy_to_contract_class_v0(legacy).unwrap().try_into().unwrap()) + } + } + } + + fn get_compiled_class_hash(&self, class_hash: ClassHash) -> StateResult { + Ok(*self + .state_maps + .compiled_class_hashes + .get(&class_hash) + .ok_or(StateError::UndeclaredClassHash(class_hash))?) + } +} + +impl ReexecutionStateReader for OfflineStateReader { + fn get_contract_class(&self, class_hash: &ClassHash) -> StateResult { + Ok(self + .contract_class_mapping + .get(class_hash) + .ok_or(StateError::UndeclaredClassHash(*class_hash))? + .clone()) + } + + fn get_old_block_hash(&self, _old_block_number: BlockNumber) -> ReexecutionResult { + Ok(self.old_block_hash) + } +} + +impl OfflineStateReader { + pub fn get_transaction_executor( + self, + block_context_next_block: BlockContext, + transaction_executor_config: Option, + ) -> ReexecutionResult> { + let old_block_number = BlockNumber( + block_context_next_block.block_info().block_number.0 + - constants::STORED_BLOCK_HASH_BUFFER, + ); + let hash = self.old_block_hash; + Ok(TransactionExecutor::::pre_process_and_create( + self, + block_context_next_block, + Some(BlockHashAndNumber { number: old_block_number, hash }), + transaction_executor_config.unwrap_or_default(), + )?) + } +} + +pub struct OfflineConsecutiveStateReaders { + pub offline_state_reader_prev_block: OfflineStateReader, + pub block_context_next_block: BlockContext, + pub transactions_next_block: Vec, + pub state_diff_next_block: CommitmentStateDiff, +} + +impl OfflineConsecutiveStateReaders { + pub fn new_from_file(full_file_path: &str) -> ReexecutionResult { + let serializable_offline_reexecution_data = + SerializableOfflineReexecutionData::read_from_file(full_file_path)?; + Ok(Self::new(serializable_offline_reexecution_data.into())) + } + + pub fn new( + OfflineReexecutionData { + offline_state_reader_prev_block, + block_context_next_block, + transactions_next_block, + state_diff_next_block, + }: OfflineReexecutionData, + ) -> Self { + Self { + offline_state_reader_prev_block, + block_context_next_block, + transactions_next_block, + state_diff_next_block, + } + } +} + +impl ConsecutiveReexecutionStateReaders for OfflineConsecutiveStateReaders { + fn pre_process_and_create_executor( + self, + transaction_executor_config: Option, + ) -> ReexecutionResult> { + self.offline_state_reader_prev_block + .get_transaction_executor(self.block_context_next_block, transaction_executor_config) + } + + fn get_next_block_txs(&self) -> ReexecutionResult> { + Ok(self.transactions_next_block.clone()) + } + + fn get_next_block_state_diff(&self) -> ReexecutionResult { + Ok(self.state_diff_next_block.clone()) + } +} diff --git a/crates/blockifier_reexecution/src/state_reader/raw_rpc_json_test.rs b/crates/blockifier_reexecution/src/state_reader/raw_rpc_json_test.rs index a1d10da6cb8..04a422b9c87 100644 --- a/crates/blockifier_reexecution/src/state_reader/raw_rpc_json_test.rs +++ b/crates/blockifier_reexecution/src/state_reader/raw_rpc_json_test.rs @@ -1,11 +1,10 @@ use std::collections::HashMap; use assert_matches::assert_matches; -use blockifier::blockifier::block::BlockInfo; use blockifier::state::cached_state::StateMaps; use pretty_assertions::assert_eq; use rstest::{fixture, rstest}; -use starknet_api::block::BlockNumber; +use starknet_api::block::{BlockInfo, BlockNumber}; use starknet_api::test_utils::read_json_file; use starknet_api::transaction::{ DeclareTransaction, @@ -19,7 +18,7 @@ use starknet_gateway::rpc_objects::BlockHeader; use crate::state_reader::compile::legacy_to_contract_class_v0; use crate::state_reader::serde_utils::deserialize_transaction_json_to_starknet_api_tx; -use crate::state_reader::utils::{reexecute_block_for_testing, ReexecutionStateMaps}; +use crate::state_reader::utils::ReexecutionStateMaps; #[fixture] fn block_header() -> BlockHeader { @@ -162,22 +161,3 @@ fn serialize_state_maps() { assert_eq!(serializable_state_maps, deserialized_state_maps); assert_eq!(original_state_maps, deserialized_state_maps.try_into().unwrap()); } - -#[rstest] -#[case::v_0_13_0(600001)] -#[case::v_0_13_1(620978)] -#[case::v_0_13_1_1(649367)] -#[case::v_0_13_2(685878)] -#[case::v_0_13_2_1(700000)] -#[case::invoke_with_replace_class_syscall(780008)] -#[case::invoke_with_deploy_syscall(870136)] -#[case::example_deploy_account_v1(837408)] -#[case::example_deploy_account_v3(837792)] -#[case::example_declare_v1(837461)] -#[case::example_declare_v2(822636)] -#[case::example_declare_v3(825013)] -#[case::example_l1_handler(868429)] -#[ignore = "Requires downloading JSON files prior to running; Long test, run with --release flag."] -fn test_block_reexecution(#[case] block_number: u64) { - reexecute_block_for_testing(block_number); -} diff --git a/crates/blockifier_reexecution/src/state_reader/reexecution_state_reader.rs b/crates/blockifier_reexecution/src/state_reader/reexecution_state_reader.rs index c500344c84a..a2996d3c849 100644 --- a/crates/blockifier_reexecution/src/state_reader/reexecution_state_reader.rs +++ b/crates/blockifier_reexecution/src/state_reader/reexecution_state_reader.rs @@ -1,16 +1,22 @@ -use blockifier::state::state_api::StateResult; -use blockifier::test_utils::MAX_FEE; +use blockifier::blockifier::config::TransactionExecutorConfig; +use blockifier::blockifier::transaction_executor::TransactionExecutor; +use blockifier::state::cached_state::CommitmentStateDiff; +use blockifier::state::state_api::{StateReader, StateResult}; +use blockifier::transaction::account_transaction::ExecutionFlags; use blockifier::transaction::transaction_execution::Transaction as BlockifierTransaction; use papyrus_execution::DEPRECATED_CONTRACT_SIERRA_SIZE; use starknet_api::block::{BlockHash, BlockNumber}; -use starknet_api::contract_class::ClassInfo; +use starknet_api::contract_class::{ClassInfo, SierraVersion}; use starknet_api::core::ClassHash; +use starknet_api::test_utils::MAX_FEE; use starknet_api::transaction::{Transaction, TransactionHash}; use starknet_core::types::ContractClass as StarknetContractClass; -use super::compile::{legacy_to_contract_class_v0, sierra_to_contact_class_v1}; -use crate::state_reader::errors::ReexecutionError; -use crate::state_reader::test_state_reader::ReexecutionResult; +use crate::state_reader::compile::{ + legacy_to_contract_class_v0, + sierra_to_versioned_contract_class_v1, +}; +use crate::state_reader::errors::ReexecutionResult; pub trait ReexecutionStateReader { fn get_contract_class(&self, class_hash: &ClassHash) -> StateResult; @@ -20,7 +26,11 @@ pub trait ReexecutionStateReader { StarknetContractClass::Sierra(sierra) => { let abi_length = sierra.abi.len(); let sierra_length = sierra.sierra_program.len(); - Ok(ClassInfo::new(&sierra_to_contact_class_v1(sierra)?, sierra_length, abi_length)?) + + let (contract_class, sierra_version) = + sierra_to_versioned_contract_class_v1(sierra)?; + + Ok(ClassInfo::new(&contract_class, sierra_length, abi_length, sierra_version)?) } StarknetContractClass::Legacy(legacy) => { let abi_length = @@ -29,6 +39,7 @@ pub trait ReexecutionStateReader { &legacy_to_contract_class_v0(legacy)?, DEPRECATED_CONTRACT_SIERRA_SIZE, abi_length, + SierraVersion::DEPRECATED, )?) } } @@ -39,23 +50,29 @@ pub trait ReexecutionStateReader { &self, txs_and_hashes: Vec<(Transaction, TransactionHash)>, ) -> ReexecutionResult> { + let execution_flags = ExecutionFlags::default(); txs_and_hashes .into_iter() .map(|(tx, tx_hash)| match tx { Transaction::Invoke(_) | Transaction::DeployAccount(_) => { - Ok(BlockifierTransaction::from_api(tx, tx_hash, None, None, None, false)?) + Ok(BlockifierTransaction::from_api( + tx, + tx_hash, + None, + None, + None, + execution_flags.clone(), + )?) } Transaction::Declare(ref declare_tx) => { - let class_info = self - .get_class_info(declare_tx.class_hash()) - .map_err(ReexecutionError::from)?; + let class_info = self.get_class_info(declare_tx.class_hash())?; Ok(BlockifierTransaction::from_api( tx, tx_hash, Some(class_info), None, None, - false, + execution_flags.clone(), )?) } Transaction::L1Handler(_) => Ok(BlockifierTransaction::from_api( @@ -64,7 +81,7 @@ pub trait ReexecutionStateReader { None, Some(MAX_FEE), None, - false, + execution_flags.clone(), )?), Transaction::Deploy(_) => { @@ -76,3 +93,15 @@ pub trait ReexecutionStateReader { fn get_old_block_hash(&self, old_block_number: BlockNumber) -> ReexecutionResult; } + +/// Trait of the functions \ queries required for reexecution. +pub trait ConsecutiveReexecutionStateReaders { + fn pre_process_and_create_executor( + self, + transaction_executor_config: Option, + ) -> ReexecutionResult>; + + fn get_next_block_txs(&self) -> ReexecutionResult>; + + fn get_next_block_state_diff(&self) -> ReexecutionResult; +} diff --git a/crates/blockifier_reexecution/src/state_reader/reexecution_test.rs b/crates/blockifier_reexecution/src/state_reader/reexecution_test.rs new file mode 100644 index 00000000000..13b9fb7935e --- /dev/null +++ b/crates/blockifier_reexecution/src/state_reader/reexecution_test.rs @@ -0,0 +1,28 @@ +use rstest::rstest; +use starknet_api::block::BlockNumber; + +use crate::state_reader::utils::{get_block_numbers_for_reexecution, reexecute_block_for_testing}; + +#[rstest] +#[case::v_0_13_0(600001)] +#[case::v_0_13_1(620978)] +#[case::v_0_13_1_1(649367)] +#[case::v_0_13_2(685878)] +#[case::v_0_13_2_1(700000)] +#[case::invoke_with_replace_class_syscall(780008)] +#[case::invoke_with_deploy_syscall(870136)] +#[case::example_deploy_account_v1(837408)] +#[case::example_deploy_account_v3(837792)] +#[case::example_declare_v1(837461)] +#[case::example_declare_v2(822636)] +#[case::example_declare_v3(825013)] +#[case::example_l1_handler(868429)] +#[ignore = "Requires downloading JSON files prior to running; Long test, run with --release flag."] +fn test_block_reexecution(#[case] block_number: u64) { + // Assert that the block number exists in the json file. + assert!( + get_block_numbers_for_reexecution(Some("../../".to_owned())) + .contains(&BlockNumber(block_number)) + ); + reexecute_block_for_testing(block_number); +} diff --git a/crates/blockifier_reexecution/src/state_reader/rpc_https_test.rs b/crates/blockifier_reexecution/src/state_reader/rpc_https_test.rs index d3595d67a68..49084ecdb68 100644 --- a/crates/blockifier_reexecution/src/state_reader/rpc_https_test.rs +++ b/crates/blockifier_reexecution/src/state_reader/rpc_https_test.rs @@ -13,9 +13,8 @@ use std::env; use std::sync::{Arc, Mutex}; use assert_matches::assert_matches; -use blockifier::blockifier::block::BlockInfo; use rstest::{fixture, rstest}; -use starknet_api::block::BlockNumber; +use starknet_api::block::{BlockInfo, BlockNumber}; use starknet_api::class_hash; use starknet_api::core::ChainId; use starknet_api::transaction::{ @@ -78,7 +77,7 @@ fn get_test_url() -> String { url } -/// Retrieves the test block_number from the `TEST_URL` environment variable, +/// Retrieves the test block_number from the `BLOCK_NUMBER` environment variable, /// falling back to the latest block if not provided. pub fn get_test_block_id() -> BlockId { match env::var("BLOCK_NUMBER") { @@ -90,7 +89,7 @@ pub fn get_test_block_id() -> BlockId { } pub fn get_test_rpc_config() -> RpcStateReaderConfig { - RpcStateReaderConfig { url: get_test_url(), json_rpc_version: "2.0".to_string() } + RpcStateReaderConfig::from_url(get_test_url()) } #[fixture] diff --git a/crates/blockifier_reexecution/src/state_reader/serde_utils.rs b/crates/blockifier_reexecution/src/state_reader/serde_utils.rs index 568da2b3b1f..95d5f4937a8 100644 --- a/crates/blockifier_reexecution/src/state_reader/serde_utils.rs +++ b/crates/blockifier_reexecution/src/state_reader/serde_utils.rs @@ -8,7 +8,7 @@ use starknet_api::transaction::{ Transaction, }; -use crate::state_reader::test_state_reader::ReexecutionResult; +use crate::state_reader::errors::ReexecutionResult; /// In old transaction, the resource bounds names are lowercase. /// need to convert to uppercase for deserialization to work. @@ -27,6 +27,10 @@ pub fn upper_case_resource_bounds_names(raw_transaction: &mut Value) { .expect("If tx contains l1_gas, it should contain l2_gas"); resource_bounds.insert("L2_GAS".to_string(), l2_gas_value); } + + if let Some(l1_data_gas_value) = resource_bounds.remove("l1_data_gas") { + resource_bounds.insert("L1_DATA_GAS".to_string(), l1_data_gas_value); + } } pub fn deserialize_transaction_json_to_starknet_api_tx( diff --git a/crates/blockifier_reexecution/src/state_reader/test_state_reader.rs b/crates/blockifier_reexecution/src/state_reader/test_state_reader.rs index 5362a6ef638..df605e0c072 100644 --- a/crates/blockifier_reexecution/src/state_reader/test_state_reader.rs +++ b/crates/blockifier_reexecution/src/state_reader/test_state_reader.rs @@ -1,42 +1,49 @@ use std::collections::HashMap; -use std::fs; use std::sync::{Arc, Mutex}; use assert_matches::assert_matches; use blockifier::abi::constants; -use blockifier::blockifier::block::BlockInfo; use blockifier::blockifier::config::TransactionExecutorConfig; use blockifier::blockifier::transaction_executor::TransactionExecutor; +use blockifier::blockifier_versioned_constants::VersionedConstants; use blockifier::bouncer::BouncerConfig; use blockifier::context::BlockContext; -use blockifier::execution::contract_class::RunnableContractClass; -use blockifier::state::cached_state::{CommitmentStateDiff, StateMaps}; +use blockifier::execution::contract_class::RunnableCompiledClass; +use blockifier::state::cached_state::CommitmentStateDiff; use blockifier::state::errors::StateError; use blockifier::state::state_api::{StateReader, StateResult}; use blockifier::transaction::transaction_execution::Transaction as BlockifierTransaction; -use blockifier::versioned_constants::VersionedConstants; -use serde::{Deserialize, Serialize}; +use serde::Serialize; use serde_json::{json, to_value}; -use starknet_api::block::{BlockHash, BlockHashAndNumber, BlockNumber, StarknetVersion}; +use starknet_api::block::{ + BlockHash, + BlockHashAndNumber, + BlockInfo, + BlockNumber, + GasPricePerToken, + StarknetVersion, +}; use starknet_api::core::{ChainId, ClassHash, CompiledClassHash, ContractAddress, Nonce}; use starknet_api::state::StorageKey; use starknet_api::transaction::{Transaction, TransactionHash}; use starknet_core::types::ContractClass as StarknetContractClass; use starknet_gateway::config::RpcStateReaderConfig; use starknet_gateway::errors::{serde_err_to_state_err, RPCStateReaderError}; -use starknet_gateway::rpc_objects::{ - BlockHeader, - BlockId, - GetBlockWithTxHashesParams, - ResourcePrice, -}; +use starknet_gateway::rpc_objects::{BlockHeader, BlockId, GetBlockWithTxHashesParams}; use starknet_gateway::rpc_state_reader::RpcStateReader; use starknet_types_core::felt::Felt; use crate::retry_request; -use crate::state_reader::compile::{legacy_to_contract_class_v0, sierra_to_contact_class_v1}; -use crate::state_reader::errors::ReexecutionError; -use crate::state_reader::reexecution_state_reader::ReexecutionStateReader; +use crate::state_reader::compile::{ + legacy_to_contract_class_v0, + sierra_to_versioned_contract_class_v1, +}; +use crate::state_reader::errors::ReexecutionResult; +use crate::state_reader::offline_state_reader::SerializableDataNextBlock; +use crate::state_reader::reexecution_state_reader::{ + ConsecutiveReexecutionStateReaders, + ReexecutionStateReader, +}; use crate::state_reader::serde_utils::{ deserialize_transaction_json_to_starknet_api_tx, hashmap_from_raw, @@ -46,7 +53,6 @@ use crate::state_reader::utils::{ disjoint_hashmap_union, get_chain_info, get_rpc_state_reader_config, - ReexecutionStateMaps, }; pub const DEFAULT_RETRY_COUNT: usize = 3; @@ -55,101 +61,8 @@ pub const DEFAULT_EXPECTED_ERROR_STRINGS: [&str; 3] = ["Connection error", "RPCError", "429 Too Many Requests"]; pub const DEFAULT_RETRY_FAILURE_MESSAGE: &str = "Failed to connect to the RPC node."; -pub type ReexecutionResult = Result; - pub type StarknetContractClassMapping = HashMap; -pub struct OfflineReexecutionData { - offline_state_reader_prev_block: OfflineStateReader, - block_context_next_block: BlockContext, - transactions_next_block: Vec, - state_diff_next_block: CommitmentStateDiff, -} - -#[derive(Serialize, Deserialize)] -pub struct SerializableDataNextBlock { - pub block_info_next_block: BlockInfo, - pub starknet_version: StarknetVersion, - pub transactions_next_block: Vec<(Transaction, TransactionHash)>, - pub state_diff_next_block: CommitmentStateDiff, - pub declared_classes: StarknetContractClassMapping, -} - -#[derive(Serialize, Deserialize)] -pub struct SerializableDataPrevBlock { - pub state_maps: ReexecutionStateMaps, - pub contract_class_mapping: StarknetContractClassMapping, -} - -#[derive(Serialize, Deserialize)] -pub struct SerializableOfflineReexecutionData { - pub serializable_data_prev_block: SerializableDataPrevBlock, - pub serializable_data_next_block: SerializableDataNextBlock, - pub chain_id: ChainId, - pub old_block_hash: BlockHash, -} - -impl SerializableOfflineReexecutionData { - pub fn write_to_file(&self, full_file_path: &str) -> ReexecutionResult<()> { - let file_path = full_file_path.rsplit_once('/').expect("Invalid file path.").0; - fs::create_dir_all(file_path) - .unwrap_or_else(|err| panic!("Failed to create directory {file_path}. Error: {err}")); - fs::write(full_file_path, serde_json::to_string_pretty(&self)?) - .unwrap_or_else(|err| panic!("Failed to write to file {full_file_path}. Error: {err}")); - Ok(()) - } - - pub fn read_from_file(full_file_path: &str) -> ReexecutionResult { - let file_content = fs::read_to_string(full_file_path).unwrap_or_else(|err| { - panic!("Failed to read reexecution data from file {full_file_path}. Error: {err}") - }); - Ok(serde_json::from_str(&file_content)?) - } -} - -impl From for OfflineReexecutionData { - fn from(value: SerializableOfflineReexecutionData) -> Self { - let SerializableOfflineReexecutionData { - serializable_data_prev_block: - SerializableDataPrevBlock { state_maps, contract_class_mapping }, - serializable_data_next_block: - SerializableDataNextBlock { - block_info_next_block, - starknet_version, - transactions_next_block, - state_diff_next_block, - declared_classes, - }, - chain_id, - old_block_hash, - } = value; - - let offline_state_reader_prev_block = OfflineStateReader { - state_maps: state_maps.try_into().expect("Failed to deserialize state maps."), - contract_class_mapping, - old_block_hash, - }; - - // Use the declared classes from the next block to allow retrieving the class info. - let transactions_next_block = - OfflineStateReader { contract_class_mapping: declared_classes, ..Default::default() } - .api_txs_to_blockifier_txs_next_block(transactions_next_block) - .expect("Failed to convert starknet-api transactions to blockifier transactions."); - - Self { - offline_state_reader_prev_block, - block_context_next_block: BlockContext::new( - block_info_next_block, - get_chain_info(&chain_id), - VersionedConstants::get(&starknet_version).unwrap().clone(), - BouncerConfig::max(), - ), - transactions_next_block, - state_diff_next_block, - } - } -} - // TODO(Aviv): Consider moving to the gateway state reader. /// Params for the RPC request "starknet_getTransactionByHash". #[derive(Serialize)] @@ -157,6 +70,7 @@ pub struct GetTransactionByHashParams { pub transaction_hash: String, } +#[derive(Clone)] pub struct RetryConfig { pub(crate) n_retries: usize, pub(crate) retry_interval_milliseconds: u64, @@ -175,6 +89,7 @@ impl Default for RetryConfig { } } +#[derive(Clone)] pub struct TestStateReader { pub(crate) rpc_state_reader: RpcStateReader, pub(crate) retry_config: RetryConfig, @@ -217,16 +132,14 @@ impl StateReader for TestStateReader { /// Returns the contract class of the given class hash. /// Compile the contract class if it is Sierra. - fn get_compiled_contract_class( - &self, - class_hash: ClassHash, - ) -> StateResult { + fn get_compiled_class(&self, class_hash: ClassHash) -> StateResult { let contract_class = retry_request!(self.retry_config, || self.get_contract_class(&class_hash))?; match contract_class { StarknetContractClass::Sierra(sierra) => { - Ok(sierra_to_contact_class_v1(sierra).unwrap().try_into().unwrap()) + let (casm, _) = sierra_to_versioned_contract_class_v1(sierra).unwrap(); + Ok(RunnableCompiledClass::try_from(casm).unwrap()) } StarknetContractClass::Legacy(legacy) => { Ok(legacy_to_contract_class_v0(legacy).unwrap().try_into().unwrap()) @@ -280,7 +193,10 @@ impl TestStateReader { // In old blocks, the l2_gas_price field is not present. block_header_map.insert( "l2_gas_price".to_string(), - to_value(ResourcePrice { price_in_wei: 1_u8.into(), price_in_fri: 1_u8.into() })?, + to_value(GasPricePerToken { + price_in_wei: 1_u8.into(), + price_in_fri: 1_u8.into(), + })?, ); } @@ -457,18 +373,6 @@ impl ReexecutionStateReader for TestStateReader { } } -/// Trait of the functions \ queries required for reexecution. -pub trait ConsecutiveStateReaders { - fn pre_process_and_create_executor( - self, - transaction_executor_config: Option, - ) -> ReexecutionResult>; - - fn get_next_block_txs(&self) -> ReexecutionResult>; - - fn get_next_block_state_diff(&self) -> ReexecutionResult; -} - pub struct ConsecutiveTestStateReaders { pub last_block_state_reader: TestStateReader, pub next_block_state_reader: TestStateReader, @@ -534,7 +438,7 @@ impl ConsecutiveTestStateReaders { } } -impl ConsecutiveStateReaders for ConsecutiveTestStateReaders { +impl ConsecutiveReexecutionStateReaders for ConsecutiveTestStateReaders { fn pre_process_and_create_executor( self, transaction_executor_config: Option, @@ -555,144 +459,3 @@ impl ConsecutiveStateReaders for ConsecutiveTestStateReaders { self.next_block_state_reader.get_state_diff() } } - -#[derive(Default)] -pub struct OfflineStateReader { - pub state_maps: StateMaps, - pub contract_class_mapping: StarknetContractClassMapping, - pub old_block_hash: BlockHash, -} - -impl StateReader for OfflineStateReader { - fn get_storage_at( - &self, - contract_address: ContractAddress, - key: StorageKey, - ) -> StateResult { - Ok(*self.state_maps.storage.get(&(contract_address, key)).ok_or( - StateError::StateReadError(format!( - "Missing Storage Value at contract_address: {}, key:{:?}", - contract_address, key - )), - )?) - } - - fn get_nonce_at(&self, contract_address: ContractAddress) -> StateResult { - Ok(*self.state_maps.nonces.get(&contract_address).ok_or(StateError::StateReadError( - format!("Missing nonce at contract_address: {contract_address}"), - ))?) - } - - fn get_class_hash_at(&self, contract_address: ContractAddress) -> StateResult { - Ok(*self.state_maps.class_hashes.get(&contract_address).ok_or( - StateError::StateReadError(format!( - "Missing class hash at contract_address: {contract_address}" - )), - )?) - } - - fn get_compiled_contract_class( - &self, - class_hash: ClassHash, - ) -> StateResult { - match self.get_contract_class(&class_hash)? { - StarknetContractClass::Sierra(sierra) => { - Ok(sierra_to_contact_class_v1(sierra).unwrap().try_into().unwrap()) - } - StarknetContractClass::Legacy(legacy) => { - Ok(legacy_to_contract_class_v0(legacy).unwrap().try_into().unwrap()) - } - } - } - - fn get_compiled_class_hash(&self, class_hash: ClassHash) -> StateResult { - Ok(*self - .state_maps - .compiled_class_hashes - .get(&class_hash) - .ok_or(StateError::UndeclaredClassHash(class_hash))?) - } -} - -impl ReexecutionStateReader for OfflineStateReader { - fn get_contract_class(&self, class_hash: &ClassHash) -> StateResult { - Ok(self - .contract_class_mapping - .get(class_hash) - .ok_or(StateError::UndeclaredClassHash(*class_hash))? - .clone()) - } - - fn get_old_block_hash(&self, _old_block_number: BlockNumber) -> ReexecutionResult { - Ok(self.old_block_hash) - } -} - -impl OfflineStateReader { - pub fn get_transaction_executor( - self, - block_context_next_block: BlockContext, - transaction_executor_config: Option, - ) -> ReexecutionResult> { - let old_block_number = BlockNumber( - block_context_next_block.block_info().block_number.0 - - constants::STORED_BLOCK_HASH_BUFFER, - ); - let hash = self.old_block_hash; - Ok(TransactionExecutor::::pre_process_and_create( - self, - block_context_next_block, - Some(BlockHashAndNumber { number: old_block_number, hash }), - transaction_executor_config.unwrap_or_default(), - )?) - } -} - -pub struct OfflineConsecutiveStateReaders { - pub offline_state_reader_prev_block: OfflineStateReader, - pub block_context_next_block: BlockContext, - pub transactions_next_block: Vec, - pub state_diff_next_block: CommitmentStateDiff, -} - -impl OfflineConsecutiveStateReaders { - pub fn new_from_file(full_file_path: &str) -> ReexecutionResult { - let serializable_offline_reexecution_data = - SerializableOfflineReexecutionData::read_from_file(full_file_path)?; - Ok(Self::new(serializable_offline_reexecution_data.into())) - } - - pub fn new( - OfflineReexecutionData { - offline_state_reader_prev_block, - block_context_next_block, - transactions_next_block, - state_diff_next_block, - }: OfflineReexecutionData, - ) -> Self { - Self { - offline_state_reader_prev_block, - block_context_next_block, - transactions_next_block, - state_diff_next_block, - } - } -} - -impl ConsecutiveStateReaders for OfflineConsecutiveStateReaders { - fn pre_process_and_create_executor( - self, - transaction_executor_config: Option, - ) -> ReexecutionResult> { - self.offline_state_reader_prev_block - .get_transaction_executor(self.block_context_next_block, transaction_executor_config) - } - - fn get_next_block_txs(&self) -> ReexecutionResult> { - Ok(self.transactions_next_block.clone()) - } - - fn get_next_block_state_diff(&self) -> ReexecutionResult { - Ok(self.state_diff_next_block.clone()) - } -} diff --git a/crates/blockifier_reexecution/src/state_reader/utils.rs b/crates/blockifier_reexecution/src/state_reader/utils.rs index 8a6d55801a2..6c4da4e816d 100644 --- a/crates/blockifier_reexecution/src/state_reader/utils.rs +++ b/crates/blockifier_reexecution/src/state_reader/utils.rs @@ -1,5 +1,6 @@ use std::collections::{BTreeMap, HashMap}; use std::env; +use std::fs::read_to_string; use std::sync::LazyLock; use assert_matches::assert_matches; @@ -13,26 +14,25 @@ use serde::{Deserialize, Serialize}; use starknet_api::block::BlockNumber; use starknet_api::core::{ChainId, ClassHash, CompiledClassHash, ContractAddress, Nonce}; use starknet_api::state::StorageKey; -use starknet_api::test_utils::read_json_file; use starknet_gateway::config::RpcStateReaderConfig; use starknet_types_core::felt::Felt; use crate::assert_eq_state_diff; -use crate::state_reader::errors::ReexecutionError; -use crate::state_reader::test_state_reader::{ - ConsecutiveStateReaders, - ConsecutiveTestStateReaders, +use crate::state_reader::errors::{ReexecutionError, ReexecutionResult}; +use crate::state_reader::offline_state_reader::{ OfflineConsecutiveStateReaders, - ReexecutionResult, SerializableDataPrevBlock, SerializableOfflineReexecutionData, }; +use crate::state_reader::reexecution_state_reader::ConsecutiveReexecutionStateReaders; +use crate::state_reader::test_state_reader::ConsecutiveTestStateReaders; + +pub const FULL_RESOURCES_DIR: &str = "./crates/blockifier_reexecution/resources"; pub static RPC_NODE_URL: LazyLock = LazyLock::new(|| { env::var("TEST_URL") .unwrap_or_else(|_| "https://free-rpc.nethermind.io/mainnet-juno/".to_string()) }); -pub const JSON_RPC_VERSION: &str = "2.0"; pub fn guess_chain_id_from_node_url(node_url: &str) -> ReexecutionResult { match ( @@ -60,12 +60,9 @@ pub fn get_fee_token_addresses(chain_id: &ChainId) -> FeeTokenAddresses { } } -/// Returns the RPC state reader configuration with the constants RPC_NODE_URL and JSON_RPC_VERSION. +/// Returns the RPC state reader configuration with the constant RPC_NODE_URL. pub fn get_rpc_state_reader_config() -> RpcStateReaderConfig { - RpcStateReaderConfig { - url: RPC_NODE_URL.clone(), - json_rpc_version: JSON_RPC_VERSION.to_string(), - } + RpcStateReaderConfig::from_url(RPC_NODE_URL.clone()) } /// Returns the chain info of mainnet. @@ -217,8 +214,8 @@ impl From for ComparableStateDiff { } pub fn reexecute_and_verify_correctness< - S: StateReader + Send + Sync, - T: ConsecutiveStateReaders, + S: StateReader + Send + Sync + Clone, + T: ConsecutiveReexecutionStateReaders, >( consecutive_state_readers: T, ) -> Option> { @@ -235,9 +232,10 @@ pub fn reexecute_and_verify_correctness< assert_matches!(res, Ok(_)); } - // Finalize block and read actual statediff. - let (actual_state_diff, _, _) = - transaction_executor.finalize().expect("Couldn't finalize block"); + // Finalize block and read actual statediff; using non_consuming_finalize to keep the + // block_state. + let actual_state_diff = + transaction_executor.non_consuming_finalize().expect("Couldn't finalize block").state_diff; assert_eq_state_diff!(expected_state_diff, actual_state_diff); @@ -261,8 +259,7 @@ pub fn write_block_reexecution_data_to_file( node_url: String, chain_id: ChainId, ) { - let config = - RpcStateReaderConfig { url: node_url, json_rpc_version: JSON_RPC_VERSION.to_string() }; + let config = RpcStateReaderConfig::from_url(node_url); let consecutive_state_readers = ConsecutiveTestStateReaders::new( block_number.prev().expect("Should not run with block 0"), @@ -309,11 +306,15 @@ macro_rules! assert_eq_state_diff { } /// Returns the block numbers for re-execution. -/// There is block number for each Starknet Version (starting v0.13) -/// And some additional block with specific transactions. -pub fn get_block_numbers_for_reexecution() -> Vec { +/// There is a block number for each Starknet Version (starting v0.13) +/// And some additional blocks with specific transactions. +pub fn get_block_numbers_for_reexecution(relative_path: Option) -> Vec { + let file_path = relative_path.unwrap_or_default() + + &(FULL_RESOURCES_DIR.to_string() + "/block_numbers_for_reexecution.json"); let block_numbers_examples: HashMap = - serde_json::from_value(read_json_file("block_numbers_for_reexecution.json")) - .expect("Failed to deserialize block header"); + serde_json::from_str(&read_to_string(file_path.clone()).expect( + &("Failed to read the block_numbers_for_reexecution file at ".to_string() + &file_path), + )) + .expect("Failed to deserialize block header"); block_numbers_examples.values().cloned().map(BlockNumber).collect() } diff --git a/crates/blockifier_test_utils/Cargo.toml b/crates/blockifier_test_utils/Cargo.toml new file mode 100644 index 00000000000..bdf3ac13d81 --- /dev/null +++ b/crates/blockifier_test_utils/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "blockifier_test_utils" +version.workspace = true +edition.workspace = true +repository.workspace = true +license-file.workspace = true +description = "Test utilities for the blockifier." + +[features] +cairo_native = [] + +[dependencies] +cairo-lang-starknet-classes.workspace = true +itertools.workspace = true +pretty_assertions.workspace = true +rstest.workspace = true +serde_json = { workspace = true, features = ["arbitrary_precision"] } +starknet-types-core.workspace = true +starknet_api = { workspace = true, features = ["testing"] } +starknet_infra_utils = { workspace = true, features = ["testing"] } +strum.workspace = true +strum_macros.workspace = true +tempfile.workspace = true +tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } +tracing.workspace = true +tracing-test.workspace = true + +[lints] +workspace = true + +[[test]] +name = "feature_contracts_compatibility_test" +path = "tests/feature_contracts_compatibility_test.rs" diff --git a/crates/blockifier/ERC20/ERC20_Cairo0/ERC20_without_some_syscalls/ERC20/ERC20.cairo b/crates/blockifier_test_utils/resources/ERC20/ERC20_Cairo0/ERC20_without_some_syscalls/ERC20/ERC20.cairo similarity index 100% rename from crates/blockifier/ERC20/ERC20_Cairo0/ERC20_without_some_syscalls/ERC20/ERC20.cairo rename to crates/blockifier_test_utils/resources/ERC20/ERC20_Cairo0/ERC20_without_some_syscalls/ERC20/ERC20.cairo diff --git a/crates/blockifier/ERC20/ERC20_Cairo0/ERC20_without_some_syscalls/ERC20/ERC20_base.cairo b/crates/blockifier_test_utils/resources/ERC20/ERC20_Cairo0/ERC20_without_some_syscalls/ERC20/ERC20_base.cairo similarity index 100% rename from crates/blockifier/ERC20/ERC20_Cairo0/ERC20_without_some_syscalls/ERC20/ERC20_base.cairo rename to crates/blockifier_test_utils/resources/ERC20/ERC20_Cairo0/ERC20_without_some_syscalls/ERC20/ERC20_base.cairo diff --git a/crates/blockifier/ERC20/ERC20_Cairo0/ERC20_without_some_syscalls/ERC20/erc20_contract_without_some_syscalls_compiled.json b/crates/blockifier_test_utils/resources/ERC20/ERC20_Cairo0/ERC20_without_some_syscalls/ERC20/erc20_contract_without_some_syscalls_compiled.json similarity index 100% rename from crates/blockifier/ERC20/ERC20_Cairo0/ERC20_without_some_syscalls/ERC20/erc20_contract_without_some_syscalls_compiled.json rename to crates/blockifier_test_utils/resources/ERC20/ERC20_Cairo0/ERC20_without_some_syscalls/ERC20/erc20_contract_without_some_syscalls_compiled.json diff --git a/crates/blockifier/ERC20/ERC20_Cairo0/ERC20_without_some_syscalls/ERC20/permitted.cairo b/crates/blockifier_test_utils/resources/ERC20/ERC20_Cairo0/ERC20_without_some_syscalls/ERC20/permitted.cairo similarity index 100% rename from crates/blockifier/ERC20/ERC20_Cairo0/ERC20_without_some_syscalls/ERC20/permitted.cairo rename to crates/blockifier_test_utils/resources/ERC20/ERC20_Cairo0/ERC20_without_some_syscalls/ERC20/permitted.cairo diff --git a/crates/blockifier/ERC20/ERC20_Cairo0/upgradability_proxy/initializable.cairo b/crates/blockifier_test_utils/resources/ERC20/ERC20_Cairo0/upgradability_proxy/initializable.cairo similarity index 100% rename from crates/blockifier/ERC20/ERC20_Cairo0/upgradability_proxy/initializable.cairo rename to crates/blockifier_test_utils/resources/ERC20/ERC20_Cairo0/upgradability_proxy/initializable.cairo diff --git a/crates/blockifier/ERC20/ERC20_Cairo1/ERC20_cairo1.cairo b/crates/blockifier_test_utils/resources/ERC20/ERC20_Cairo1/ERC20_cairo1.cairo similarity index 99% rename from crates/blockifier/ERC20/ERC20_Cairo1/ERC20_cairo1.cairo rename to crates/blockifier_test_utils/resources/ERC20/ERC20_Cairo1/ERC20_cairo1.cairo index 61aed45e3b6..8a2b8b20381 100644 --- a/crates/blockifier/ERC20/ERC20_Cairo1/ERC20_cairo1.cairo +++ b/crates/blockifier_test_utils/resources/ERC20/ERC20_Cairo1/ERC20_cairo1.cairo @@ -266,7 +266,7 @@ mod ERC20 { let activation_time = get_block_timestamp() + self.get_upgrade_delay(); let expiration_time = activation_time + IMPLEMENTATION_EXPIRATION; - // TODO - add an assertion that the `implementation_data.impl_hash` is declared. + // TODO(Meshi): add an assertion that the `implementation_data.impl_hash` is declared. self.set_impl_activation_time(:implementation_data, :activation_time); self.set_impl_expiration_time(:implementation_data, :expiration_time); self.emit(ImplementationAdded { implementation_data: implementation_data }); diff --git a/crates/blockifier/ERC20/ERC20_Cairo1/erc20.casm.json b/crates/blockifier_test_utils/resources/ERC20/ERC20_Cairo1/erc20.casm.json similarity index 100% rename from crates/blockifier/ERC20/ERC20_Cairo1/erc20.casm.json rename to crates/blockifier_test_utils/resources/ERC20/ERC20_Cairo1/erc20.casm.json diff --git a/crates/blockifier_test_utils/resources/ERC20/ERC20_Cairo1/erc20.sierra.json b/crates/blockifier_test_utils/resources/ERC20/ERC20_Cairo1/erc20.sierra.json new file mode 100644 index 00000000000..b0c6823b4e3 --- /dev/null +++ b/crates/blockifier_test_utils/resources/ERC20/ERC20_Cairo1/erc20.sierra.json @@ -0,0 +1,3880 @@ +{ + "sierra_program": [ + "0x1", + "0x6", + "0x0", + "0x2", + "0x7", + "0x0", + "0x302", + "0xfe", + "0x53", + "0x52616e6765436865636b", + "0x800000000000000100000000000000000000000000000000", + "0x436f6e7374", + "0x800000000000000000000000000000000000000000000002", + "0x1", + "0xa", + "0x2", + "0x134692b230b9e1ffa39098904722134159652b09c5bc41d88d6698779d228ff", + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9", + "0x45524332303a206d696e7420746f2074686520302061646472657373", + "0x436f6e747261637441646472657373", + "0x800000000000000700000000000000000000000000000000", + "0x75313238", + "0x537472756374", + "0x800000000000000700000000000000000000000000000003", + "0x0", + "0x25e2ca4b84968c2d8b83ef476ca8549410346b00836ce79beaf538155990bb2", + "0x5", + "0x800000000000000700000000000000000000000000000004", + "0x1051fce1176db22fe657487f168047a0b3e168863bea30db21d507d12e33681", + "0x4", + "0x6", + "0x45524332303a20617070726f76652066726f6d2030", + "0xffffffffffffffffffffffffffffffff", + "0x66656c74323532", + "0x800000000000000700000000000000000000000000000002", + "0x20c573050f4f72ab687d1e30ab9e3112f066656a1db232d4e8d586e1bc52772", + "0x753235365f737562204f766572666c6f77", + "0x753235365f616464204f766572666c6f77", + "0x33a32bc739412cec48c0291b76ed61bbe7c9d3a349015650f99cdc4ed9d2e04", + "0x456e756d", + "0x3fd53fc455b85adf3bca466f69d21202561f799eb9b5a23813bb3659ac4946a", + "0xe", + "0x7", + "0x800000000000000f00000000000000000000000000000001", + "0x2ee1e2b1b89f8c495f200e4956278a4d47395fe262f27b52e5865c9524c08c3", + "0x3288d594b9a45d15bb2fcb7903f06cdb06b27f0ba88186ec4cfaa98307cb972", + "0x11", + "0x53746f726167654261736541646472657373", + "0x1802098ad3a768b9070752b9c76d78739119b657863faee996237047e2cd718", + "0x13", + "0x11956ef5427d8b17839ef1ab259882b25c0eabf6d6a15c034942faee6617e37", + "0x45524332303a207472616e7366657220746f2030", + "0x45524332303a207472616e736665722066726f6d2030", + "0x4e6f6e5a65726f", + "0x800000000000000700000000000000000000000000000001", + "0x53746f726555313238202d206e6f6e2075313238", + "0x47", + "0x350d9416f58c95be8ef9cdc9ecb299df23021512fdc0110a670111a3553ab86", + "0x4661696c656420746f20646573657269616c697a6520706172616d202334", + "0x4661696c656420746f20646573657269616c697a6520706172616d202335", + "0x4661696c656420746f20646573657269616c697a6520706172616d202333", + "0x2f3fd47d2dd288bfeeffd3691afceae84c0f55c0d45a7194665c5837fa4e7f7", + "0x800000000000000f00000000000000000000000000000003", + "0x1f", + "0x16a4c8d7c05909052238a862d8cc3e7975bf05a07b3a69c6b28951083a6d672", + "0x4172726179", + "0x800000000000000300000000000000000000000000000001", + "0x800000000000000300000000000000000000000000000003", + "0x21", + "0x22", + "0x39617af083606a3784747e03219a53c59dfe642003a40b0beb01896005de01", + "0x20", + "0x23", + "0x426f78", + "0x2d", + "0x2f", + "0x536e617073686f74", + "0x1baeba72e79e9db2587cf44fedb2f3700b2075a5e8e39a562584862c4b71f62", + "0x27", + "0x30", + "0x29", + "0x1597b831feeb60c71f259624b79cf66995ea4f7e383403583674ab9c33b9cec", + "0x2a", + "0x753332", + "0x80000000000000070000000000000000000000000000000e", + "0x348a62b7a38c0673e61e888d83a3ac1bf334ee7361a8514593d3d9532ed8b39", + "0x28", + "0x2b", + "0x2c", + "0x753634", + "0x3808c701a5d13e100ab11b6c02f91f752ecae7e420d21b56c90ec0a475cc7e5", + "0x2e", + "0x3342418ef16b3e2799b906b1e4e89dbb9b111332dd44f72458ce44f9895b508", + "0x800000000000000700000000000000000000000000000006", + "0x7d4d99e9ed8d285b5c61b493cedb63976bc3d9da867933d829f49ce838b5e7", + "0x26", + "0x25", + "0x31", + "0x12867ecd09c884a5cf1f6d9eb0193b4695ce3bb3b2d796a8367d0c371f59cb2", + "0x29d7d57c04a880978e7b3689f6218e507f3be17588744b58dc17762447ad0e7", + "0x34", + "0x4661696c656420746f20646573657269616c697a6520706172616d202332", + "0x1166fe35572d4e7764dac0caf1fd7fc591901fd01156db2561a07b68ab8dca2", + "0x141ea21bd03254e41074504de8465806cb179228cd769ab9e55224c660a57c4", + "0x38", + "0x2a69c3f2ee27bbe2624c4ffcb3563ad31a1d6caee2eef9aed347284f5f8a34d", + "0xbf4c436d6f8521e5c6189511c75075de702ad597ce22c1786275e8e5167ec7", + "0x4661696c656420746f20646573657269616c697a6520706172616d202331", + "0x12ec76808d96ca2583b0dd3fb55396ab8783beaa30b8e3bf084a606e215849e", + "0x2b22539ea90e179bb2e7ef5f6db1255a5f497b922386e746219ec855ba7ab0c", + "0x25b1ef8ee6544359221f3cf316f768360e83448109193bdcef77f52a79d95c4", + "0x506564657273656e", + "0x11c6d8087e00642489f92d2821ad6ebd6532ad1a3b6d12833da6d6810391511", + "0x2ce4352eafa6073ab4ecf9445ae96214f99c2c33a29c01fcae68ba501d10e2c", + "0x42", + "0x268e4078627d9364ab472ed410c0ea6fe44919b24eafd69d665019c5a1c0c88", + "0x1557182e4359a1f0c6301278e8f5b35a776ab58d39892581e357578fb287836", + "0x53746f72655538202d206e6f6e207538", + "0x7538", + "0x30df86604b54525ae11ba1b715c090c35576488a1286b0453186a976e6c9a32", + "0x4f7574206f6620676173", + "0x53746f7261676541646472657373", + "0x145cc613954179acf89d43c94ed0e091828cbddcca83f5b408785785036d36d", + "0x4275696c74696e436f737473", + "0x53797374656d", + "0x9931c641b913035ae674b400b61a51476d506bbe8bba2ff8a6272790aba9e6", + "0x4a", + "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", + "0x4761734275696c74696e", + "0xde", + "0x7265766f6b655f61705f747261636b696e67", + "0x77697468647261775f676173", + "0x6272616e63685f616c69676e", + "0x7374727563745f6465636f6e737472756374", + "0x73746f72655f74656d70", + "0x61727261795f736e617073686f745f706f705f66726f6e74", + "0x64726f70", + "0x61727261795f6e6577", + "0x636f6e73745f61735f696d6d656469617465", + "0x51", + "0x61727261795f617070656e64", + "0x7374727563745f636f6e737472756374", + "0x656e756d5f696e6974", + "0x50", + "0x52", + "0x4f", + "0x6765745f6275696c74696e5f636f737473", + "0x4e", + "0x77697468647261775f6761735f616c6c", + "0x73746f726167655f626173655f616464726573735f636f6e7374", + "0x361458367e696363fbcc70777d07ebbd2394e89fd0adcaf147faccd1d294d60", + "0x4d", + "0x736e617073686f745f74616b65", + "0x72656e616d65", + "0x73746f726167655f616464726573735f66726f6d5f62617365", + "0x4b", + "0x4c", + "0x73746f726167655f726561645f73797363616c6c", + "0x49", + "0x216b05c387bab9ac31918a3e61672f4618601f3c598a2f3f2710f37053e1ea4", + "0x4c4fb1ab068f6039d5780c68dd0fa2f8742cceb3426d19667778ca7f3518a9", + "0x48", + "0x75385f7472795f66726f6d5f66656c74323532", + "0x75385f746f5f66656c74323532", + "0x46", + "0x6a756d70", + "0x45", + "0x44", + "0x66756e6374696f6e5f63616c6c", + "0x3", + "0xc", + "0x656e756d5f6d61746368", + "0x43", + "0x647570", + "0x753132385f746f5f66656c74323532", + "0x656e61626c655f61705f747261636b696e67", + "0x756e626f78", + "0x41", + "0x21adb5788e32c84f69a1863d85ef9394b7bf761a0ce1190f826984e5075c371", + "0x64697361626c655f61705f747261636b696e67", + "0x40", + "0x3f", + "0x3e", + "0x3d", + "0xd", + "0x3c", + "0x3b", + "0x3a", + "0x39", + "0x37", + "0x36", + "0x35", + "0x75313238735f66726f6d5f66656c74323532", + "0x33", + "0x6765745f657865637574696f6e5f696e666f5f76325f73797363616c6c", + "0x32", + "0xf", + "0x24", + "0x10", + "0x1e", + "0x12", + "0x14", + "0x1d", + "0x1c", + "0xad292db4ff05a993c318438c1b6c8a8303266af2da151aa28ccece6726f1f1", + "0x1b", + "0x1a", + "0x2679d68052ccd03a53755ca9169677965fbd93e489df62f5f40d4f03c24f7a4", + "0x19", + "0x636f6e74726163745f616464726573735f746f5f66656c74323532", + "0x706564657273656e", + "0x66656c743235325f69735f7a65726f", + "0x17", + "0x18", + "0x16", + "0x15", + "0x753132385f6f766572666c6f77696e675f737562", + "0x73746f726167655f77726974655f73797363616c6c", + "0x753132385f6f766572666c6f77696e675f616464", + "0x656d69745f6576656e745f73797363616c6c", + "0xb", + "0x9", + "0x753132385f6571", + "0x8", + "0x636f6e74726163745f616464726573735f636f6e7374", + "0x110f", + "0xffffffffffffffff", + "0xa4", + "0x6e", + "0x97", + "0x8e", + "0x110", + "0xc7", + "0x103", + "0xf6", + "0xec", + "0xfb", + "0x171", + "0x133", + "0x164", + "0x15d", + "0x209", + "0x18d", + "0x192", + "0x1f7", + "0x1f3", + "0x1aa", + "0x1e4", + "0x54", + "0x55", + "0x56", + "0x57", + "0x1dc", + "0x1fb", + "0x58", + "0x59", + "0x5a", + "0x5b", + "0x5c", + "0x5d", + "0x2d0", + "0x226", + "0x22b", + "0x2be", + "0x2ba", + "0x238", + "0x23d", + "0x2a7", + "0x2a2", + "0x256", + "0x291", + "0x5e", + "0x5f", + "0x60", + "0x61", + "0x62", + "0x63", + "0x289", + "0x2ac", + "0x64", + "0x65", + "0x66", + "0x67", + "0x68", + "0x2c2", + "0x69", + "0x6a", + "0x6b", + "0x6c", + "0x6d", + "0x6f", + "0x70", + "0x71", + "0x72", + "0x73", + "0x74", + "0x3d2", + "0x2ed", + "0x2f2", + "0x3c0", + "0x3bc", + "0x2fd", + "0x302", + "0x337", + "0x332", + "0x310", + "0x315", + "0x328", + "0x322", + "0x33f", + "0x32c", + "0x33a", + "0x3aa", + "0x355", + "0x399", + "0x387", + "0x75", + "0x76", + "0x77", + "0x78", + "0x79", + "0x7a", + "0x37e", + "0x7b", + "0x7c", + "0x7d", + "0x390", + "0x7e", + "0x7f", + "0x80", + "0x81", + "0x82", + "0x83", + "0x84", + "0x85", + "0x86", + "0x3c4", + "0x87", + "0x88", + "0x89", + "0x8a", + "0x8b", + "0x8c", + "0x8d", + "0x8f", + "0x90", + "0x91", + "0x92", + "0x51d", + "0x3ef", + "0x3f4", + "0x50b", + "0x507", + "0x401", + "0x406", + "0x4f4", + "0x4ef", + "0x411", + "0x416", + "0x44b", + "0x446", + "0x424", + "0x429", + "0x43c", + "0x436", + "0x453", + "0x440", + "0x44e", + "0x4dc", + "0x46a", + "0x4ca", + "0x4b7", + "0x4aa", + "0x4a1", + "0x4c1", + "0x93", + "0x94", + "0x95", + "0x96", + "0x98", + "0x99", + "0x9a", + "0x9b", + "0x9c", + "0x9d", + "0x9e", + "0x9f", + "0xa0", + "0xa1", + "0xa2", + "0x4f9", + "0xa3", + "0xa5", + "0xa6", + "0xa7", + "0xa8", + "0xa9", + "0x50f", + "0xaa", + "0xab", + "0xac", + "0xad", + "0xae", + "0xaf", + "0xb0", + "0xb1", + "0xb2", + "0xb3", + "0xb4", + "0xb5", + "0x61f", + "0x53a", + "0x53f", + "0x60d", + "0x609", + "0x54a", + "0x54f", + "0x584", + "0x57f", + "0x55d", + "0x562", + "0x575", + "0x56f", + "0x58c", + "0x579", + "0x587", + "0x5f7", + "0x5a2", + "0x5e6", + "0x5d4", + "0x5cb", + "0x5dd", + "0x611", + "0x703", + "0x63c", + "0x641", + "0x6f1", + "0x6ed", + "0x64c", + "0x651", + "0x686", + "0x681", + "0x65f", + "0x664", + "0x677", + "0x671", + "0x68e", + "0x67b", + "0x689", + "0x6db", + "0x6a4", + "0x6ca", + "0x6c2", + "0x6f5", + "0x7e7", + "0x720", + "0x725", + "0x7d5", + "0x7d1", + "0x730", + "0x735", + "0x76a", + "0x765", + "0x743", + "0x748", + "0x75b", + "0x755", + "0x772", + "0x75f", + "0x76d", + "0x7bf", + "0x788", + "0x7ae", + "0x7a6", + "0x7d9", + "0x94c", + "0x804", + "0x809", + "0x93b", + "0x813", + "0x818", + "0x929", + "0x820", + "0x825", + "0x915", + "0x90f", + "0x833", + "0x838", + "0x86d", + "0x868", + "0x846", + "0x84b", + "0x85e", + "0x858", + "0x875", + "0x862", + "0x870", + "0x8fb", + "0x87f", + "0x884", + "0x8e5", + "0x8dd", + "0x8a0", + "0x8c9", + "0x8c1", + "0x8ed", + "0x91b", + "0xb6", + "0xb7", + "0x9ad", + "0x998", + "0x991", + "0x984", + "0x9a5", + "0x9b4", + "0xa14", + "0x9fe", + "0x9f7", + "0x9ea", + "0xa0b", + "0xa1b", + "0xa80", + "0xa6a", + "0xa63", + "0xa56", + "0xa77", + "0xa87", + "0xaa5", + "0xabc", + "0xcb2", + "0xc9c", + "0xc91", + "0xc80", + "0xaf5", + "0xafb", + "0xb02", + "0xb14", + "0xb0c", + "0xc6a", + "0xb8", + "0xc56", + "0xc4d", + "0xc35", + "0xc1f", + "0xc14", + "0xc03", + "0xb9", + "0xb6b", + "0xba", + "0xbb", + "0xbc", + "0xbd", + "0xbe", + "0xb71", + "0xbf", + "0xc0", + "0xc1", + "0xc2", + "0xb78", + "0xc3", + "0xc4", + "0xc5", + "0xc6", + "0xc8", + "0xb8a", + "0xc9", + "0xca", + "0xcb", + "0xb82", + "0xcc", + "0xcd", + "0xce", + "0xcf", + "0xd0", + "0xbed", + "0xd1", + "0xd2", + "0xd3", + "0xd4", + "0xd5", + "0xd6", + "0xd7", + "0xd8", + "0xd9", + "0xda", + "0xdb", + "0xdc", + "0xdd", + "0xdf", + "0xe0", + "0xe1", + "0xe2", + "0xbd9", + "0xe3", + "0xe4", + "0xe5", + "0xe6", + "0xe7", + "0xe8", + "0xe9", + "0xea", + "0xbd0", + "0xeb", + "0xed", + "0xee", + "0xef", + "0xf0", + "0xf1", + "0xf2", + "0xf3", + "0xf4", + "0xf5", + "0xf7", + "0xf8", + "0xf9", + "0xfa", + "0xfc", + "0xfd", + "0xbc5", + "0xfe", + "0xff", + "0x100", + "0x101", + "0x102", + "0x104", + "0x105", + "0x106", + "0x107", + "0x108", + "0x109", + "0xbe4", + "0x10a", + "0x10b", + "0x10c", + "0x10d", + "0x10e", + "0x10f", + "0x111", + "0x112", + "0x113", + "0x114", + "0x115", + "0x116", + "0x117", + "0x118", + "0x119", + "0xc30", + "0x11a", + "0x11b", + "0x11c", + "0x11d", + "0xc40", + "0x11e", + "0x11f", + "0x120", + "0x121", + "0x122", + "0x123", + "0x124", + "0xc44", + "0x125", + "0x126", + "0x127", + "0x128", + "0x129", + "0x12a", + "0xc61", + "0x12b", + "0x12c", + "0x12d", + "0x12e", + "0x12f", + "0x130", + "0x131", + "0x132", + "0x134", + "0x135", + "0x136", + "0x137", + "0x138", + "0x139", + "0x13a", + "0xcad", + "0x13b", + "0x13c", + "0x13d", + "0x13e", + "0xcbd", + "0x13f", + "0x140", + "0x141", + "0x142", + "0x143", + "0x144", + "0x145", + "0xcc1", + "0x146", + "0x147", + "0x148", + "0xd8f", + "0xd79", + "0xd6e", + "0xd5d", + "0xd01", + "0xd05", + "0xd4e", + "0xd0e", + "0xd14", + "0xd1b", + "0xd2d", + "0xd25", + "0xd3a", + "0xd8a", + "0xd9a", + "0xd9e", + "0xdbc", + "0xe12", + "0xe09", + "0xdfe", + "0xe1d", + "0xef3", + "0xedb", + "0xec5", + "0xeba", + "0xea9", + "0xe69", + "0xe6f", + "0xe76", + "0xe88", + "0xe80", + "0xe95", + "0xed6", + "0xee6", + "0xeea", + "0xfcd", + "0xfb5", + "0xf9f", + "0xf94", + "0xf83", + "0xf43", + "0xf49", + "0xf50", + "0xf62", + "0xf5a", + "0xf6f", + "0xfb0", + "0xfc0", + "0xfc4", + "0x10b9", + "0x10ab", + "0x109e", + "0x1008", + "0x108b", + "0x1083", + "0x1070", + "0x1068", + "0x105d", + "0x107a", + "0x1095", + "0x10ec", + "0x17f", + "0x218", + "0x2df", + "0x3e1", + "0x52c", + "0x62e", + "0x712", + "0x7f6", + "0x95b", + "0x9bc", + "0xa24", + "0xa90", + "0xcca", + "0xda7", + "0xe26", + "0xf00", + "0xfda", + "0x10c8", + "0x8d48", + "0xc0340c02c0a01c060140400c0901c060140400c0801c060140400c0200400", + "0x305c0701805010030580505405054050501004c0e04805048050441003c0e", + "0x1d01c060140400c1c01c060140400c060141b0401a0380c0641801c1201404", + "0xe01407048050100308805084050801003c1f0580505405054050781004c0e", + "0x60142a0401a03829014280401a0380c09c2601426014250400f07c2404023", + "0x5010030bc070180501003018050b82d0b00701805010030ac070180501003", + "0x60140400c3301c060140400c3201c060140400c29014310401a0380501c30", + "0x100ec0e018050e8390e01008c0e098050dc05090100d80e0d41008c0e0d007", + "0x3d0142e110430142e104420142e104400143f0143e0403b07c3d0143c01424", + "0x101300e0304b12805124100680e120050b84411c050e83911805114100680e", + "0x50014500144e014120144f0140601406014060144e0141201415014060144d", + "0xe0480514c05018051501004c0e0540514c0514c051481004c0e0305113805", + "0x26014160145a0400f07c590142e10406014150141501458014570145604055", + "0x5054050901003c0e174070180501003098051700516c1003c1f018050b841", + "0x6201c060140400c06014610401a038600145f0401a038060145e0401a03815", + "0x6719807018050100301805194100680e18005190100680e18c070180501003", + "0x1a038400146a014690403b07c16014240401a0382601406014680400f07c02", + "0x30a4051bc100680e0306e1b40701805010031b0070180501003018051ac10", + "0x29014720401a0380c1c41001c500140400c4e014240401a0387001c0601404", + "0x101ec101e879008781dc070180501003100051d8051d4100ec1f0087403073", + "0x50148117005014801180501480018050147f040050147e138050147d0407c", + "0x870140721840014052143c01405214060140521006014051f8830140520806", + "0x70148d0408c22c050147e0408a21c050147e224050147e220050147e01407", + "0x52081024829014052448f014051f48f014052008f014052408f014052148e", + "0x8513805014850f405014800f4050149004095250050147e140050147e24c05", + "0x9801c052349701c052344e0140520096014052081001c87014072187601405", + "0x7e27005014820409b0409a264050147d264050148026405014902640501485", + "0x9f014051f89f014052009f014052409f014052149e01405208102743d01405", + "0x7d05805014a5058050148005805014901a8050147d29005014a3288a1014a0", + "0x7218060140524406014052a01029c10298120140524412014052001601405", + "0x5014a3014072a40501c8609805014852a4050147e118050147e040072a405", + "0xae01405240ae01405214ad01405208ac014051f81501405200102ac102a8a9", + "0xa0054050147e2bc050147e2bc050148518005014852b8050147d2b80501480", + "0x5200b301405240b301405214b201405208b1014052082601405200b028405", + "0xa1014a02d4050147e2d0050147e2d405014852d005014852cc050147d2cc05", + "0xb70140528c0501cb701407218b7014051f81001cb701407218b60140520821", + "0x501491014072e40501c862e4050147e040072e40501c860580501485040b8", + "0x5200570140520059014051f459014052a0bb014051f8102e8b90140528c10", + "0x5014802f405014a32f0a1014a0058050147e0dc0501485018050148016005", + "0xbf014052083f014051f4be2840528015014052943c0140520040014051f43f", + "0x82304a1014a00c0050147e0c005014800a4a1014a0300a1014a0098a1014a0", + "0xc501405200c501405240c501405214103109f014051f4c301405208c201405", + "0x501c861a80501485040c7318050148214005014a50a405014a5314050147d", + "0x501ca40140721850014052002901405200c801405208a4014051f81001ca4", + "0x501480040cb2d0050147d2d4050147d040ca180050147d2bc050147d040c9", + "0x5214ce01405208cd01405200bd014051f80501cbd01407218cc0140520837", + "0x5014803040501490304050148533c050147d33c050148033c050149033c05", + "0xc001407218c0014051f812014051f81001cc00140721810340c1014051f4c1", + "0x501c860840501485040d2040d130005014a330005014802f8050148201407", + "0x3f014052141034ccf28405280bc014051f8bc01405200bc014052401001cbc", + "0x5014820f40501491224050149122005014912c00501482040072f40501c86", + "0x1201405294d501405208d4014051f4d401405200d401405240d401405214a2", + "0x7e1b0070148d2840501482014072f00501c86088050148535c0501482040d6", + "0x524421014051f421014052940701405208bc0140528c1001c053602901405", + "0x1001c05040103680504010040d9088050147d08805014a5014050148205405", + "0x1035c05368052840528410040da0141001c100881601c930481501cda01c05", + "0x103680504007040d4014cf018d501cda01cd70141204015014da0141501415", + "0x5040d5040a2014da0141035c10040da014060142204010368053540505810", + "0xda014102881008405368052c0a201cd4040b0014da014b001406040b0014da", + "0xda014150141504026014da014be01421040be014da014212f0072c0102f005", + "0x536805098050981001c053680501c052f8100480536805048052f01005405", + "0xda0141030010040da014d4014160401036805040070402601c120541501426", + "0xce33c072b8c10a4073680730012054a1304103000536805300050a41030005", + "0xcd014cc040cd014da014cc014ce040cc014da0141033c10040da0141001c10", + "0x5314053181031405368053180532010040da014c8014cd040c63200736805", + "0x5368052fc05308102fc0536805040c3040c2014da014c3014c5040c3014da", + "0x7308bf01cc10543704029014da0142901415040c2014da014c2014bf040bf", + "0x604058014da0141035c10040da0141001c102f4400f4a12dc3c0fc37284da", + "0x101384601cda014570143f04057014da0143c16007350100f005368050f005", + "0x52f410128053680512005100101200536805138050f410040da014460143c", + "0x3f014be04037014da01437014bc04029014da01429014150404f014da0144a", + "0x10040da0141001c1013c3f0dc290540513c053680513c05098100fc0536805", + "0x1504053014da014420142104042014da014bd140072c0101400536805040a2", + "0x5098101000536805100052f8100f405368050f4052f0100a405368050a405", + "0x1010c0536805040d7040103680504007040531003d0a41501453014da01453", + "0xa204059014da0144710c073501011c053680511c050181011c053680504058", + "0x50541017005368052e405084102e40536805164bb01cb0040bb014da01410", + "0x5c0142604007014da01407014be040ce014da014ce014bc040cf014da014cf", + "0xd704010368052840515c10040da0141001c1017007338cf054051700536805", + "0xb62dc07350102d805368052d805018102d8053680504058040b7014da01410", + "0x52d005084102d005368052d46001cb004060014da01410288102d40536805", + "0xda01407014be04022014da01422014bc04016014da0141601415040b3014da", + "0x701410040da01410040102cc0708816054052cc05368052cc050981001c05", + "0xd7014da014a1014a1040103680504007040220580736c12054073680701410", + "0xda0141001c103500537006354073680735c050481005405368050540505410", + "0x10354102880536805040d704010368050180508810040da014d50141604010", + "0x5040a204021014da014b028807350102c005368052c005018102c00536805", + "0x5054050541009805368052f805084102f80536805084bc01cb0040bc014da", + "0xda014260142604007014da01407014be04012014da01412014bc04015014da", + "0x5040c004010368053500505810040da0141001c1009807048150540509805", + "0xcf01cdd3042901cda01cc004815284c1040c0014da014c001429040c0014da", + "0x53301033405368053300533810330053680504046040103680504007040ce", + "0xc5014c6040c5014da014c6014c804010368053200533410318c801cda014cd", + "0xda014bf014c2040bf014da0141030c10308053680530c053141030c0536805", + "0xc22fc07304150dc100a405368050a405054103080536805308052fc102fc05", + "0x101600536805040d7040103680504007040bd1003d284de0f03f0dca136807", + "0x4e118073680515c050fc1015c05368050f05801cd40403c014da0143c01406", + "0xbd0404a014da014480144004048014da0144e0143d0401036805118050f010", + "0x52f8100dc05368050dc052f0100a405368050a4050541013c053680512805", + "0x1036805040070404f0fc370a4150144f014da0144f014260403f014da0143f", + "0x1014c0536805108050841010805368052f45001cb004050014da0141028810", + "0x2604040014da01440014be0403d014da0143d014bc04029014da0142901415", + "0x43014da0141035c10040da0141001c1014c400f4290540514c053680514c05", + "0x10164053680511c4301cd404047014da014470140604047014da0141016010", + "0x150405c014da014b901421040b9014da014592ec072c0102ec0536805040a2", + "0x50981001c053680501c052f8103380536805338052f01033c053680533c05", + "0x10040da014a1014570401036805040070405c01cce33c150145c014da0145c", + "0xb701cd4040b6014da014b601406040b6014da01410160102dc0536805040d7", + "0xb401421040b4014da014b5180072c0101800536805040a2040b5014da014b6", + "0x501c052f8100880536805088052f010058053680505805054102cc0536805", + "0x5040103680504010040b301c2205815014b3014da014b30142604007014da", + "0x5368052840528410040da0141001c100881601cdf0481501cda01c0504007", + "0x504007040d4014e0018d501cda01cd70141204015014da0141501415040d7", + "0xd5040a2014da0141035c10040da014060142204010368053540505810040da", + "0x102881008405368052c0a201cd4040b0014da014b001406040b0014da01410", + "0x150141504026014da014be01421040be014da014212f0072c0102f00536805", + "0x5098050981001c053680501c052f8100480536805048052f0100540536805", + "0x1030010040da014d4014160401036805040070402601c120541501426014da", + "0x7384c10a4073680730012054a1304103000536805300050a4103000536805", + "0x4a040cd014da014cc01448040cc014da0141013810040da0141001c10338cf", + "0x53181031405368053180514010040da014c80144f040c6320073680533405", + "0x52fc05308102fc0536805040c3040c2014da014c3014c5040c3014da014c5", + "0xbf01cc10543704029014da0142901415040c2014da014c2014bf040bf014da", + "0x5368050f00501810040da0141001c102f4400f4a13883c0fc37284da01cc2", + "0x7368070f02901c420403f014da0143f014be04037014da01437014bc0403c", + "0x53680515c0514c101380536805040d704010368050400704046014e315c58", + "0xda0144f0143c0405013c0736805128050fc1012805368051204e01cd404048", + "0x43014da01453014bd04053014da014420144004042014da014500143d04010", + "0x100fc05368050fc052f8100dc05368050dc052f01016005368051600505410", + "0x536805040d7040103680504007040430fc371601501443014da0144301426", + "0xbb014da0145911c07350101640536805164050181016405368050404304047", + "0x102dc05368050fc052f81017005368050dc052f0102e405368051180505410", + "0xda0142901415040103680504007040103900504059040b6014da014bb01447", + "0x5368052f40511c102dc0536805100052f81017005368050f4052f0102e405", + "0xb4014da014600142104060014da014b62d4072c0102d40536805040a2040b6", + "0x102dc05368052dc052f8101700536805170052f0102e405368052e40505410", + "0x536805040d7040103680504007040b42dc5c2e415014b4014da014b401426", + "0xb1014da014b22cc07350102c805368052c805018102c8053680504058040b3", + "0x102b405368052b805084102b805368052c4af01cb0040af014da0141028810", + "0x2604007014da01407014be040ce014da014ce014bc040cf014da014cf01415", + "0x10368052840515c10040da0141001c102b407338cf054052b405368052b405", + "0x7350102a405368052a405018102a4053680504058040ac014da0141035c10", + "0x50841027c05368051a8a401cb0040a4014da01410288101a805368052a4ac", + "0x7014be04022014da01422014bc04016014da01416014150409e014da0149f", + "0x10040da01410040102780708816054052780536805278050981001c0536805", + "0xda014a1014a104010368050400704022058073941205407368070141001c05", + "0x1001c103500539806354073680735c05048100540536805054050541035c05", + "0x102880536805040d704010368050180508810040da014d5014160401036805", + "0xa204021014da014b028807350102c005368052c005018102c00536805040d5", + "0x50541009805368052f805084102f80536805084bc01cb0040bc014da01410", + "0x260142604007014da01407014be04012014da01412014bc04015014da01415", + "0xc004010368053500505810040da0141001c100980704815054050980536805", + "0xe73042901cda01cc004815284c1040c0014da014c001429040c0014da01410", + "0x103340536805330052e4103300536805040bb040103680504007040ce33c07", + "0xbc04029014da01429014150401036805320052dc10318c801cda014cd0145c", + "0x152d4103180536805318052d81001c053680501c052f810304053680530405", + "0x1001c100fc053a037014da01cbf01460040bf308c331415368053180730429", + "0x7368050f4052cc100f405368050dc052d0100f00536805040d70401036805", + "0x736805160052bc10160bd01cda014bd014b10401036805100052c8102f440", + "0x48014da0144e014ac0404e014da01457014ad0401036805118052b81011857", + "0x103680513c052b8101404f01cda014bd014af0404a014da014480f00735010", + "0x43014da01453128073501014c0536805108052b0101080536805140052b410", + "0x102ec0536805164050f410040da014470143c0405911c073680510c050fc10", + "0xbc040c5014da014c5014150405c014da014b9014bd040b9014da014bb01440", + "0xc505405170053680517005098103080536805308052f81030c053680530c05", + "0xc5014da014c501415040b7014da0143f014210401036805040070405c308c3", + "0x52dc05368052dc05098103080536805308052f81030c053680530c052f010", + "0xb5014da01410160102d80536805040d7040103680504007040b7308c331415", + "0x102d00536805040a204060014da014b52d807350102d405368052d40501810", + "0x1033c053680533c05054102c805368052cc05084102cc0536805180b401cb0", + "0x15014b2014da014b20142604007014da01407014be040ce014da014ce014bc", + "0x102c40536805040d704010368052840515c10040da0141001c102c807338cf", + "0xa2040ae014da014af2c407350102bc05368052bc05018102bc053680504058", + "0x5054102a405368052b005084102b005368052b8ad01cb0040ad014da01410", + "0xa90142604007014da01407014be04022014da01422014bc04016014da01416", + "0x1201cda01c070140701410040da01410040102a40708816054052a40536805", + "0x1036805040a9040d5014da01415014a1040103680504007040d7088073a416", + "0xda0141001c10288053a8d40180736807354050481004805368050480505410", + "0xbc014da014210149f04021014da014b0014a4040b0014da014d40146a04010", + "0x1001c10040eb014101641009805368052f005270102f805368050180527810", + "0x53680528805278100a4053680530005264103000536805040300401036805", + "0xda0141001c1033c053b0c1014da01c260149604026014da014290149c040be", + "0x53380505410040da0141001c10334053b4cc33807368073041201c7604010", + "0x504093040103680504007040c5014ee318c801cda01cbe01412040ce014da", + "0xd704010368053300525010040da014c60142204010368053200505810040da", + "0xc230c0735010308053680530805018103080536805040d5040c3014da01410", + "0x50fc05084100fc05368052fc3701cb004037014da01410288102fc0536805", + "0xda01416014bc040ce014da014ce0141504010014da014100148f0403c014da", + "0x3c2841633810048050f005368050f005098102840536805284052f81005805", + "0x536805040c004010368053140505810040da0141024c10040da0141001c10", + "0x1015c5801cef2f44001cda01c3d058ce284c10403d014da0143d014290403d", + "0x51380521c101380536805118052241011805368050408b040103680504007", + "0xda0144f014a40404f014da0144a0148804010368051200520c101284801cda", + "0x536805100050541014c0536805108053c0101080536805140050001014005", + "0xa1014da014a1014be04010014da014100148f040bd014da014bd014bc04040", + "0xcc14ca1040bd100163cc103300536805330053c81014c053680514c053c410", + "0x103680504007040b7014f417005368072e405180102e4bb1644710c1236805", + "0x102d06001cda014b5014b3040b5014da0145c014b4040b6014da0141035c10", + "0x102c4b201cda014b3014af040b32d007368052d0052c410040da01460014b2", + "0x7350102b805368052bc052b0102bc05368052c8052b410040da014b1014ae", + "0x52b410040da014ac014ae040a92b007368052d0052bc102b405368052b8b6", + "0x50fc1027c0536805290ad01cd4040a4014da0146a014ac0406a014da014a9", + "0x300144004030014da0149c0143d0401036805278050f0102709e01cda0149f", + "0x510c050541016405368051640523c102580536805264052f4102640536805", + "0xda0149601426040bb014da014bb014be04047014da01447014bc04043014da", + "0x8f04076014da014b701421040103680504007040962ec4710c590480525805", + "0x52f81011c053680511c052f01010c053680510c0505410164053680516405", + "0xda0141001c101d8bb11c431641201476014da0147601426040bb014da014bb", + "0x50181025005368050405804093014da0141035c10040da014cc0149404010", + "0x8b01cb00408b014da014102881023c05368052509301cd404094014da01494", + "0x580141504010014da014100148f04087014da014890142104089014da0148f", + "0x521c05098102840536805284052f81015c053680515c052f0101600536805", + "0x1504010368052f80505810040da0141001c1021ca115c580401201487014da", + "0x103680533c053d810040da0141001c10040f5014101641020c053680533405", + "0x5040d704010368050409304083014da014120141504010368052f80505810", + "0xda014002200735010000053680500005018100000536805040f704088014da", + "0x5368053c805084103c805368053c0f101cb0040f1014da01410288103c005", + "0x16014da01416014bc04083014da014830141504010014da014100148f040f3", + "0x7040f32841620c10048053cc05368053cc05098102840536805284052f810", + "0xf7014da01410160103d80536805040d704010368050540515c10040da01410", + "0x103e40536805040a2040f8014da014f73d807350103dc05368053dc0501810", + "0x1004005368050400523c103ec05368053e805084103e805368053e0f901cb0", + "0x26040a1014da014a1014be040d7014da014d7014bc04022014da0142201415", + "0x701c0501c05040103680504010040fb284d708810048053ec05368053ec05", + "0x102a41035405368050540528410040da0141001c1035c2201cfc0581201cda", + "0x7040a2014fd3500601cda01cd50141204012014da01412014150401036805", + "0x50840527c1008405368052c005290102c00536805350051a810040da01410", + "0x103f8050405904026014da014bc0149c040be014da014060149e040bc014da", + "0xa20149e04029014da014c001499040c0014da014100c010040da0141001c10", + "0x7040cf014ff3040536807098052581009805368050a405270102f80536805", + "0x15040103680504007040cd01500330ce01cda01cc1048071d810040da01410", + "0x10040da0141001c1031405404c632007368072f80504810338053680533805", + "0x9e040bf014da014c20149f040c2014da014c3014a4040c3014da014c60146a", + "0xda0141001c100410201410164100fc05368052fc05270100dc053680532005", + "0x100dc053680531405278100f405368050f005264100f005368050403004010", + "0x10040da0141001c102f40540c40014da01c3f014960403f014da0143d0149c", + "0x5368051600505410040da0141001c1011805410571600736807100ce01c76", + "0x1036805040930401036805040070404a015051204e01cda01c370141204058", + "0xcc01494040103680515c0525010040da014480142204010368051380505810", + "0x50014da014500140604050014da014103541013c0536805040d70401036805", + "0x43014da0144214c072c01014c0536805040a204042014da0145013c0735010", + "0x101600536805160050541004005368050400523c1011c053680510c0508410", + "0x1201447014da0144701426040a1014da014a1014be04016014da01416014bc", + "0x59014da0141030010040da0144a01416040103680504007040472841616010", + "0x7040b717007418b92ec073680716416160a1304101640536805164050a410", + "0xb5014da014b6014f9040b6014da014103e010040da0141024c10040da01410", + "0x102cc05368052d00541c10040da01460014fb040b418007368052d4053e810", + "0x109040af014da014b101508040b1014da014b201400040b2014da014b3014a4", + "0x8f040b9014da014b9014bc040bb014da014bb01415040ae014da0145733007", + "0x542c102bc05368052bc05428102840536805284052f810040053680504005", + "0x5180102906a2a4ac2b412368052b8af284102e4bb0590c040ae014da014ae", + "0x9f014b40409c014da0141035c10040da0141001c10278054349f014da01ca4", + "0x5258052c410040da01499014b20409626407368050c0052cc100c00536805", + "0x524c052b410040da01494014ae0409424c07368051d8052bc101d89601cda", + "0x5258052bc10224053680522c9c01cd40408b014da0148f014ac0408f014da", + "0xda01488014ac04088014da01483014ad040103680521c052b81020c8701cda", + "0x53c4050f0103c8f101cda014f00143f040f0014da01400224073501000005", + "0x5368053d8052f4103d805368053cc05100103cc05368053c8050f410040da", + "0xac014da014ac014bc040ad014da014ad01415040a9014da014a90148f040f7", + "0x7040f71a8ac2b4a9048053dc05368053dc05098101a805368051a8052f810", + "0x52b405054102a405368052a40523c103e005368052780508410040da01410", + "0xda014f8014260406a014da0146a014be040ac014da014ac014bc040ad014da", + "0x5701494040103680504093040103680504007040f81a8ac2b4a9048053e005", + "0x103e8053680504058040f9014da0141035c10040da014cc014940401036805", + "0xb004107014da01410288103ec05368053e8f901cd4040fa014da014fa01406", + "0x1504010014da014100148f04109014da015080142104108014da014fb41c07", + "0x5098102840536805284052f8102dc05368052dc052f010170053680517005", + "0x10368050dc0505810040da0141001c10424a12dc5c0401201509014da01509", + "0x5040070401043805040590410a014da014460141504010368053300525010", + "0x1504010368053300525010040da014370141604010368052f4053d810040da", + "0x5368050410f0410b014da0141035c10040da0141024c10428053680533805", + "0x110014da014102881043c05368054310b01cd40410c014da0150c014060410c", + "0x10014da014100148f04112014da015110142104111014da0150f440072c010", + "0x102840536805284052f8100580536805058052f01042805368054280505410", + "0x52f80505810040da0141001c10448a10590a0401201512014da0151201426", + "0x53d810040da0141001c1004114014101641044c05368053340505410040da", + "0x10368050409304113014da014120141504010368052f80505810040da014cf", + "0x735010458053680545805018104580536805040f704115014da0141035c10", + "0x508410464053680545d1801cb004118014da014102881045c053680545915", + "0x16014bc04113014da015130141504010014da014100148f040dc014da01519", + "0x1644c1004805370053680537005098102840536805284052f8100580536805", + "0x10160104680536805040d704010368050540515c10040da0141001c10370a1", + "0x5040a20411c014da0151b468073501046c053680546c050181046c0536805", + "0x50400523c1047c0536805478050841047805368054711d01cb00411d014da", + "0xda014a1014be040d7014da014d7014bc04022014da014220141504010014da", + "0x50401036805040100411f284d7088100480547c053680547c050981028405", + "0x5368050540528410040da0141001c1035c2201d200581201cda01c0701407", + "0x1213500601cda01cd50141204012014da01412014150401036805040a9040d5", + "0x1008405368052c005290102c00536805350051a810040da0141001c1028805", + "0x5904026014da014bc0149c040be014da014060149e040bc014da014210149f", + "0x29014da014c001499040c0014da014100c010040da0141001c100412201410", + "0x1233040536807098052581009805368050a405270102f805368052880527810", + "0x504007040cd01524330ce01cda01cc1048071d810040da0141001c1033c05", + "0x1001c1031405494c632007368072f8050481033805368053380505410040da", + "0xda014c301511040c2014da014c80149e040c3014da014c6015100401036805", + "0x370151204037014da014100c010040da0141001c100412601410164102fc05", + "0x72fc0544c102fc05368050fc0544410308053680531405278100fc0536805", + "0x5100052901010005368050f0051a810040da0141001c100f40549c3c014da", + "0x4e118a14a05716007368072f4ce01d15040bd014da014bd01406040bd014da", + "0x12913c4a01cda01cc20141204058014da014580141504010368050400704048", + "0x1014c05368051280527810108053680513c0544010040da0141001c1014005", + "0x53680504030040103680504007040104a8050405904043014da0144201511", + "0x43014da014590151104053014da014500149e04059014da014470151204047", + "0x5c014da014bb0146a040103680504007040b90152b2ec053680710c0544c10", + "0xb601cda01cb716007454102dc05368052dc05018102dc05368051700529010", + "0xb201517040b2014da014b515c0745810040da0141001c102ccb4180a14b0b5", + "0x52c405460102b8053680514c05278102bc05368052d805054102c40536805", + "0x52b810040da014b4014ae040103680504007040104b40504059040ad014da", + "0x104b80504059040ac014da0146001415040103680515c052b810040da014b3", + "0x51600505410040da01457014ae04010368052e4053d810040da0141001c10", + "0x5368052b005370101a805368052a405464102a4053680504030040ac014da", + "0x7040104b40504059040ad014da0146a01518040ae014da014530149e040af", + "0x5368051180505410040da01448014ae0401036805138052b810040da01410", + "0x53380505410040da0143d014f6040103680504007040104bc0504059040a4", + "0x5368052900537010278053680527c054641027c053680504030040a4014da", + "0x9c014da01cad0151a040ad014da0149e01518040ae014da014c20149e040af", + "0x50400704076015312589901cda01cae014120401036805040070403001530", + "0x52c810040da014960142204010368052640505810040da0141024c10040da", + "0x94014da014103541024c0536805040d704010368053300525010040da0149c", + "0x1022c0536805040a20408f014da0149424c073501025005368052500501810", + "0x1004005368050400523c1021c05368052240508410224053680523c8b01cb0", + "0x26040a1014da014a1014be04016014da01416014bc040af014da014af01415", + "0xda014760141604010368050400704087284162bc100480521c053680521c05", + "0x73680720c162bca13041020c053680520c050a41020c0536805040c004010", + "0xa10000746c1022005368052200505410040da0141001c103c4f001d3200088", + "0x11c040103680504093040103680504007040f93e0f7285333d8f33c8a136807", + "0x109421073ec12368053e805478103e805368053d805474103d805368053d805", + "0x54d410040da0150901494040103680541c054d010040da014fb0151f0410a", + "0xda014f2014bc04088014da01488014150410b014da014104d810040da0150a", + "0x536805420053c8103cc05368053cc052f81004005368050400523c103c805", + "0x10b3cc103c88835d380409c014da0149c01537040cc014da014cc014f204108", + "0x1001c10454054e913014da01d1201539041124451043d0c048da0149c33108", + "0x11701cda015160143f04116014da0141035c10040da015130153b0401036805", + "0x10370053680546405100104640536805460050f410040da015170143c04118", + "0xbc0410c014da0150c0141504110014da015100148f0411a014da014dc014bd", + "0x11004805468053680546805098104440536805444052f81043c053680543c05", + "0xda0151b0153d0411c46c0736805454054f010040da0141001c104691143d0c", + "0x11f014da0150f014bc0411e014da0150c014150411d014da015100148f04010", + "0x1001c100413e01410164104d405368054700511c104d00536805444052f810", + "0x8f04010368053300525010040da0149c014b20401036805040930401036805", + "0x52f81047c05368053dc052f01047805368052200505410474053680504005", + "0x1354d8072c0104d80536805040a204135014da014f90144704134014da014f8", + "0x5478050541047405368054740523c104e005368054dc05084104dc0536805", + "0xda015380142604134014da01534014be0411f014da0151f014bc0411e014da", + "0x9c014b2040103680504093040103680504007041384d11f4791d048054e005", + "0x104ec05368050405804139014da0141035c10040da014cc014940401036805", + "0xb00413d014da01410288104f005368054ed3901cd40413b014da0153b01406", + "0x1504010014da014100148f04140014da0153f014210413f014da0153c4f407", + "0x5098102840536805284052f8103c405368053c4052f0103c005368053c005", + "0x10040da0141024c10040da0141001c10500a13c4f00401201540014da01540", + "0xda0141035c10040da014cc0149404010368052b80505810040da01430014f6", + "0x5368055094101cd404142014da015420140604142014da0141043c1050405", + "0x146014da015450142104145014da01543510072c0105100536805040a204143", + "0x100580536805058052f0102bc05368052bc050541004005368050400523c10", + "0x1001c10518a1058af0401201546014da0154601426040a1014da014a1014be", + "0x1004148014101641051c05368053340505410040da014be014160401036805", + "0xda014120141504010368052f80505810040da014cf014f6040103680504007", + "0x5018105280536805040f704149014da0141035c10040da0141024c1051c05", + "0x14c01cb00414c014da014102881052c05368055294901cd40414a014da0154a", + "0x1470141504010014da014100148f0414e014da0154d014210414d014da0154b", + "0x553805098102840536805284052f8100580536805058052f01051c0536805", + "0xd704010368050540515c10040da0141001c10538a105947040120154e014da", + "0xde53c0735010378053680537805018103780536805040580414f014da01410", + "0x5548050841054805368055415101cb004151014da01410288105400536805", + "0xda014d7014bc04022014da014220141504010014da014100148f04153014da", + "0x153284d7088100480554c053680554c05098102840536805284052f81035c05", + "0xda0141001c1035c2201d540581201cda01c070140701410040da0141004010", + "0x1204012014da01412014150401036805040a9040d5014da01415014a104010", + "0x102c00536805350051a810040da0141001c1028805554d4018073680735405", + "0x9c040be014da014060149e040bc014da014210149f04021014da014b0014a4", + "0xc0014da014100c010040da0141001c1004156014101641009805368052f005", + "0x1009805368050a405270102f8053680528805278100a405368053000526410", + "0xce01cda01cc1048071d810040da0141001c1033c0555cc1014da01c2601496", + "0x7368072f8050481033805368053380505410040da0141001c1033405560cc", + "0xda014c3014a4040c3014da014c60146a040103680504007040c501559318c8", + "0x5368052fc05270100dc053680532005278102fc05368053080527c1030805", + "0x50f005264100f00536805040300401036805040070401056805040590403f", + "0xda01c3f014960403f014da0143d0149c04037014da014c50149e0403d014da", + "0x1011805570571600736807100ce01c76040103680504007040bd0155b10005", + "0x4a0155d1204e01cda01c370141204058014da0145801415040103680504007", + "0x5444101400536805138052781013c05368051200544010040da0141001c10", + "0x1014c05368050403004010368050400704010578050405904042014da0144f", + "0x11304042014da014430151104050014da0144a0149e04043014da0145301512", + "0xa4040bb014da014470146a040103680504007040590155f11c053680710805", + "0x1602dc5c01cda01cb916007454102e405368052e405018102e405368052ec05", + "0x736807140050481017005368051700505410040da0141001c10180b52d8a1", + "0xda014b40149e040b1014da014b301510040103680504007040b2015612ccb4", + "0x100c010040da0141001c100416201410164102b805368052c405444102bc05", + "0x52b005444102bc05368052c805278102b005368052b405448102b40536805", + "0x52a4051a810040da0141001c101a80558ca9014da01cae01513040ae014da", + "0x727c5c01d150409f014da0149f014060409f014da014a4014a4040a4014da", + "0x101d80536805270b701d160401036805040070409626430285642709e01cda", + "0x1180408f014da014af0149e04094014da0149e0141504093014da0147601517", + "0x1036805264052b810040da0141001c1004165014101641022c053680524c05", + "0x101641022405368050c00505410040da014b7014ae0401036805258052b810", + "0x1504010368052dc052b810040da0146a014f60401036805040070401059805", + "0x89014dc04083014da014870151904087014da014100c010224053680517005", + "0x165014101641022c053680520c054601023c05368052bc05278102500536805", + "0xb6014150401036805180052b810040da014b5014ae04010368050400704010", + "0x150401036805164053d810040da0141001c100416701410164102200536805", + "0x88014dc040f0014da014000151904000014da014100c010220053680516005", + "0x722c054681022c05368053c0054601023c053680514005278102500536805", + "0x103dc055a4f63cc073680723c0504810040da0141001c103c8055a0f1014da", + "0x10368053d80508810040da014f301416040103680504093040103680504007", + "0x5040d704010368053300525010040da014570149404010368053c4052c810", + "0xda014f93e007350103e405368053e405018103e40536805040d5040f8014da", + "0x53680541c050841041c05368053e8fb01cb0040fb014da01410288103e805", + "0x16014da01416014bc04094014da014940141504010014da014100148f04108", + "0x704108284162501004805420053680542005098102840536805284052f810", + "0x536805424050a4104240536805040c004010368053dc0505810040da01410", + "0x505410040da0141001c1043d0c01d6a42d0a01cda01d0905894284c104109", + "0x50400704116455132856b44911440a1368072850b01d1b0410a014da0150a", + "0x123680545c054781045c0536805448054741044805368054480547010040da", + "0xda0151a014940401036805464054d010040da015180151f0411b468dc46518", + "0xbc0410a014da0150a014150411c014da014104d810040da0151b0153504010", + "0x54fc104440536805444052f81004005368050400523c10440053680544005", + "0x52c4103700536805370053c8104740536805474053c810474cc01cda014cc", + "0x11e3711d4711104110428d7500104780536805478054dc10478f101cda014f1", + "0x103680504007041390156c4e005368074dc054e4104dd364d53447c1236805", + "0x505410040da0153c014f60413c4ec07368054e00550410040da0141024c10", + "0x136014be04135014da015350148f04134014da01534014bc0411f014da0151f", + "0x53c4054dc1015c053680515c053c8103300536805330053c8104d80536805", + "0x54e410509415013f4f412368053c4573313b4d9354d11f35d38040f1014da", + "0x5040d7040103680550c054ec10040da0141001c10510055b543014da01d42", + "0xda015470143d0401036805518050f01051d4601cda015450143f04145014da", + "0x5368055000523c1052c0536805528052f4105280536805524051001052405", + "0x141014da01541014be0413f014da0153f014bc0413d014da0153d0141504140", + "0x1440153c0401036805040070414b5053f4f5400480552c053680552c0509810", + "0x54f4050541053805368055000523c10040da0154c0153d0414d5300736805", + "0xda0154d0144704150014da01541014be040de014da0153f014bc0414f014da", + "0x53c4052c810040da0141024c10040da0141001c100416e014101641054405", + "0x15354807368054e4054f010040da014cc01494040103680515c0525010040da", + "0xbc0414f014da0151f014150414e014da015350148f0401036805548054f410", + "0x1016410544053680554c0511c1054005368054d8052f81037805368054d005", + "0x525010040da014f1014b2040103680504093040103680504007040105b805", + "0xda0150a014150414e014da014100148f04010368053300525010040da01457", + "0x5368054580511c105400536805454052f810378053680544c052f01053c05", + "0x171014da015700142104170014da015515bc072c0105bc0536805040a204151", + "0x103780536805378052f01053c053680553c050541053805368055380523c10", + "0x1001c105c5503794f5381201571014da015710142604150014da01550014be", + "0x94040103680515c0525010040da014f1014b20401036805040930401036805", + "0xda014dd01406040dd014da01410160105c80536805040d7040103680533005", + "0xda015735d0072c0105d00536805040a204173014da014dd5c8073501037405", + "0x536805430050541004005368050400523c105d805368055d405084105d405", + "0x176014da0157601426040a1014da014a1014be0410f014da0150f014bc0410c", + "0xda014f2014f6040103680504093040103680504007041762850f4301004805", + "0x1035c10040da014cc01494040103680515c0525010040da0148f0141604010", + "0x55e17701cd404178014da015780140604178014da01410508105dc0536805", + "0xda0157b014210417b014da015795e8072c0105e80536805040a204179014da", + "0x536805058052f0102500536805250050541004005368050400523c105f005", + "0x105f0a105894040120157c014da0157c01426040a1014da014a1014be04016", + "0xda014460141504010368053300525010040da0143701416040103680504007", + "0x370141604010368052f4053d810040da0141001c100417e01410164105f405", + "0x10040da0141024c105f405368053380505410040da014cc014940401036805", + "0x17f01cd4040db014da014db01406040db014da0141043c105fc0536805040d7", + "0x1820142104182014da01580604072c0106040536805040a204180014da014db", + "0x5058052f0105f405368055f4050541004005368050400523c1060c0536805", + "0xa10597d0401201583014da0158301426040a1014da014a1014be04016014da", + "0x101641061005368053340505410040da014be0141604010368050400704183", + "0x1504010368052f80505810040da014cf014f60401036805040070401061405", + "0x536805040f704186014da0141035c10040da0141024c10610053680504805", + "0x189014da0141028810620053680561d8601cd404187014da015870140604187", + "0x10014da014100148f0418b014da0158a014210418a014da01588624072c010", + "0x102840536805284052f8100580536805058052f01061005368056100505410", + "0x50540515c10040da0141001c1062ca105984040120158b014da0158b01426", + "0x10634053680563405018106340536805040580418c014da0141035c10040da", + "0x1064005368056398f01cb00418f014da014102881063805368056358c01cd4", + "0xbc04022014da014220141504010014da014100148f04191014da0159001421", + "0x1004805644053680564405098102840536805284052f81035c053680535c05", + "0x1035c2201d920581201cda01c070140701410040da0141004010644a135c22", + "0xda01412014150401036805040a9040d5014da01415014a1040103680504007", + "0x5350051a810040da0141001c102880564cd40180736807354050481004805", + "0xda014060149e040bc014da014210149f04021014da014b0014a4040b0014da", + "0x100c010040da0141001c1004194014101641009805368052f005270102f805", + "0x50a405270102f8053680528805278100a4053680530005264103000536805", + "0xc1048071d810040da0141001c1033c05654c1014da01c260149604026014da", + "0x50481033805368053380505410040da0141001c1033405658cc3380736807", + "0x9e040c3014da014c601510040103680504007040c501597318c801cda01cbe", + "0xda0141001c100419801410164102fc053680530c0544410308053680532005", + "0x10308053680531405278100fc05368050dc05448100dc05368050403004010", + "0x10040da0141001c100f4056643c014da01cbf01513040bf014da0143f01511", + "0x115040bd014da014bd01406040bd014da01440014a404040014da0143c0146a", + "0xda014580141504010368050400704048138462859a15c5801cda01cbd33807", + "0x513c0544010040da0141001c101400566c4f1280736807308050481016005", + "0x10670050405904043014da014420151104053014da0144a0149e04042014da", + "0x500149e04059014da014470151204047014da014100c010040da0141001c10", + "0x7040b90159d2ec053680710c0544c1010c0536805164054441014c0536805", + "0x52dc05018102dc0536805170052901017005368052ec051a810040da01410", + "0x10040da0141001c102ccb4180a1678b52d807368072dc5801d15040b7014da", + "0x102bc05368052d805054102c405368052c80545c102c805368052d45701d16", + "0x5040070401067c0504059040ad014da014b101518040ae014da014530149e", + "0x15040103680515c052b810040da014b3014ae04010368052d0052b810040da", + "0x10368052e4053d810040da0141001c10041a001410164102b0053680518005", + "0x5464102a4053680504030040ac014da0145801415040103680515c052b810", + "0x6a01518040ae014da014530149e040af014da014ac014dc0406a014da014a9", + "0xae0401036805138052b810040da0141001c100419f01410164102b40536805", + "0x103680504007040106840504059040a4014da0144601415040103680512005", + "0x54641027c053680504030040a4014da014ce0141504010368050f4053d810", + "0x9e01518040ae014da014c20149e040af014da014a4014dc0409e014da0149f", + "0xae0141204010368050400704030015a227005368072b405468102b40536805", + "0x52640505810040da0141024c10040da0141001c101d80568c962640736807", + "0xd704010368053300525010040da0149c014b204010368052580508810040da", + "0x9424c0735010250053680525005018102500536805040d504093014da01410", + "0x52240508410224053680523c8b01cb00408b014da014102881023c0536805", + "0xda01416014bc040af014da014af0141504010014da014100148f04087014da", + "0x87284162bc100480521c053680521c05098102840536805284052f81005805", + "0x520c050a41020c0536805040c004010368051d80505810040da0141001c10", + "0x10040da0141001c103c4f001da40008801cda01c83058af284c104083014da", + "0x7040f93e0f7285a53d8f33c8a1368072840001d1b04088014da0148801415", + "0x5368053d805474103d805368053d80547010040da0141024c10040da01410", + "0x541c054d010040da014fb0151f0410a4250841cfb048da014fa0151e040fa", + "0x150410b014da014104d810040da0150a0153504010368054240525010040da", + "0x52f81004005368050400523c103c805368053c8052f010220053680522005", + "0x9c01537040cc014da014cc014f204108014da01508014f2040f3014da014f3", + "0x139041124451043d0c048da0149c3310842cf3040f2220d750c102700536805", + "0x1035c10040da015130153b04010368050400704115015a644c053680744805", + "0x5460050f410040da015170143c0411845c0736805458050fc104580536805", + "0xda015100148f0411a014da014dc014bd040dc014da015190144004119014da", + "0x536805444052f81043c053680543c052f0104300536805430050541044005", + "0x54f010040da0141001c104691143d0c440120151a014da0151a0142604111", + "0x10c014150411d014da015100148f040103680546c054f4104711b01cda01515", + "0x54700511c104d00536805444052f81047c053680543c052f0104780536805", + "0x9c014b20401036805040930401036805040070401069c050405904135014da", + "0x536805220050541047405368050400523c10040da014cc014940401036805", + "0x135014da014f90144704134014da014f8014be0411f014da014f7014bc0411e", + "0x104e005368054dc05084104dc05368054d53601cb004136014da0141028810", + "0xbe0411f014da0151f014bc0411e014da0151e014150411d014da0151d0148f", + "0x504007041384d11f4791d048054e005368054e005098104d005368054d005", + "0x1035c10040da014cc014940401036805270052c810040da0141024c10040da", + "0x54ed3901cd40413b014da0153b014060413b014da01410160104e40536805", + "0xda0153f014210413f014da0153c4f4072c0104f40536805040a20413c014da", + "0x5368053c4052f0103c005368053c0050541004005368050400523c1050005", + "0x10500a13c4f00401201540014da0154001426040a1014da014a1014be040f1", + "0x10368052b80505810040da01430014f6040103680504093040103680504007", + "0x1420140604142014da0141043c105040536805040d704010368053300525010", + "0x143510072c0105100536805040a204143014da0154250407350105080536805", + "0x52bc050541004005368050400523c10518053680551405084105140536805", + "0xda0154601426040a1014da014a1014be04016014da01416014bc040af014da", + "0x505410040da014be0141604010368050400704146284162bc100480551805", + "0x10040da014cf014f6040103680504007040106a0050405904147014da014cd", + "0xda0141035c10040da0141024c1051c05368050480505410040da014be01416", + "0x5368055294901cd40414a014da0154a014060414a014da014103dc1052405", + "0x14e014da0154d014210414d014da0154b530072c0105300536805040a20414b", + "0x100580536805058052f01051c053680551c050541004005368050400523c10", + "0x1001c10538a105947040120154e014da0154e01426040a1014da014a1014be", + "0x103780536805040580414f014da0141035c10040da01415014570401036805", + "0xb004151014da014102881054005368053794f01cd4040de014da014de01406", + "0x1504010014da014100148f04153014da015520142104152014da0155054407", + "0x5098102840536805284052f81035c053680535c052f010088053680508805", + "0xda01c070140701410040da014100401054ca135c220401201553014da01553", + "0x5040a9040d5014da01415014a1040103680504007040d7088076a41604807", + "0x1001c10288056a8d40180736807354050481004805368050480505410040da", + "0xda014210149f04021014da014b0014a4040b0014da014d40146a0401036805", + "0x10041ab014101641009805368052f005270102f8053680501805278102f005", + "0x528805278100a405368053000526410300053680504030040103680504007", + "0x1001c1033c056b0c1014da01c260149604026014da014290149c040be014da", + "0x505410040da0141001c10334056b4cc33807368073041201c760401036805", + "0x110040103680504007040c5015ae318c801cda01cbe01412040ce014da014ce", + "0x10164102fc053680530c05444103080536805320052781030c053680531805", + "0x100fc05368050dc05448100dc053680504030040103680504007040106bc05", + "0x56c03c014da01cbf01513040bf014da0143f01511040c2014da014c50149e", + "0x6040bd014da01440014a404040014da0143c0146a0401036805040070403d", + "0x5040070404813846285b115c5801cda01cbd33807454102f405368052f405", + "0x1001c10140056c84f1280736807308050481016005368051600505410040da", + "0xda014420151104053014da0144a0149e04042014da0144f015100401036805", + "0x470151204047014da014100c010040da0141001c10041b3014101641010c05", + "0x710c0544c1010c0536805164054441014c053680514005278101640536805", + "0x5170052901017005368052ec051a810040da0141001c102e4056d0bb014da", + "0xb4180a16d4b52d807368072dc5801d15040b7014da014b701406040b7014da", + "0x102c405368052c80545c102c805368052d45701d16040103680504007040b3", + "0x59040ad014da014b101518040ae014da014530149e040af014da014b601415", + "0x10040da014b3014ae04010368052d0052b810040da0141001c10041b601410", + "0xda0141001c10041b701410164102b005368051800505410040da01457014ae", + "0x30040ac014da0145801415040103680515c052b810040da014b9014f604010", + "0x530149e040af014da014ac014dc0406a014da014a901519040a9014da01410", + "0x10040da0141001c10041b601410164102b405368051a805460102b80536805", + "0x504059040a4014da01446014150401036805120052b810040da0144e014ae", + "0x30040a4014da014ce0141504010368050f4053d810040da0141001c10041b8", + "0xc20149e040af014da014a4014dc0409e014da0149f015190409f014da01410", + "0x704030015b927005368072b405468102b4053680527805460102b80536805", + "0x1024c10040da0141001c101d8056e89626407368072b80504810040da01410", + "0x10040da0149c014b204010368052580508810040da01499014160401036805", + "0x525005018102500536805040d504093014da0141035c10040da014cc01494", + "0x523c8b01cb00408b014da014102881023c05368052509301cd404094014da", + "0xda014af0141504010014da014100148f04087014da014890142104089014da", + "0x53680521c05098102840536805284052f8100580536805058052f0102bc05", + "0x5040c004010368051d80505810040da0141001c1021ca1058af0401201487", + "0xf001dbb0008801cda01c83058af284c104083014da014830142904083014da", + "0x522005054103c8053680504136040103680504093040103680504007040f1", + "0xda014a1014be04010014da014100148f04000014da01400014bc04088014da", + "0xa10400022022510102700536805270054dc103300536805330053c81028405", + "0x1001c103ec056f0fa014da01cf901539040f93e0f73d8f3048da0149c330f2", + "0x10801cda015070143f04107014da0141035c10040da014fa0153b0401036805", + "0x1042c053680542805100104280536805424050f410040da015080143c04109", + "0xbc040f3014da014f301415040f7014da014f70148f0410c014da0150b014bd", + "0xf704805430053680543005098103e005368053e0052f8103d805368053d805", + "0x5368053dc0523c1043c05368053ec0508410040da0141001c10430f83d8f3", + "0xf8014da014f8014be040f6014da014f6014bc040f3014da014f301415040f7", + "0x5040930401036805040070410f3e0f63ccf70480543c053680543c0509810", + "0x5804110014da0141035c10040da014cc014940401036805270052c810040da", + "0x102881044805368054451001cd404111014da015110140604111014da01410", + "0x100148f04116014da015150142104115014da0151244c072c01044c0536805", + "0x5284052f8103c405368053c4052f0103c005368053c005054100400536805", + "0x10040da0141001c10458a13c4f00401201516014da0151601426040a1014da", + "0xda014cc0149404010368052b80505810040da01430014f6040103680504093", + "0xd404118014da015180140604118014da0141043c1045c0536805040d704010", + "0x210411a014da01519370072c0103700536805040a204119014da0151845c07", + "0x52f0102bc05368052bc050541004005368050400523c1046c053680546805", + "0xaf040120151b014da0151b01426040a1014da014a1014be04016014da01416", + "0x1047005368053340505410040da014be014160401036805040070411b28416", + "0x10368052f80505810040da014cf014f6040103680504007040106f40504059", + "0x5040f70411d014da0141035c10040da0141024c1047005368050480505410", + "0xda014102881047c05368054791d01cd40411e014da0151e014060411e014da", + "0xda014100148f04136014da015350142104135014da0151f4d0072c0104d005", + "0x536805284052f8100580536805058052f0104700536805470050541004005", + "0x515c10040da0141001c104d8a10591c0401201536014da0153601426040a1", + "0x5368054e005018104e005368050405804137014da0141035c10040da01415", + "0x5368054e53b01cb00413b014da01410288104e405368054e13701cd404138", + "0x22014da014220141504010014da014100148f0413d014da0153c014210413c", + "0x54f405368054f405098102840536805284052f81035c053680535c052f010", + "0x2201dbe0581201cda01c070140701410040da01410040104f4a135c2204012", + "0x12014150401036805040a9040d5014da01415014a1040103680504007040d7", + "0x51a810040da0141001c10288056fcd4018073680735405048100480536805", + "0x60149e040bc014da014210149f04021014da014b0014a4040b0014da014d4", + "0x10040da0141001c10041c0014101641009805368052f005270102f80536805", + "0x5270102f8053680528805278100a405368053000526410300053680504030", + "0x71d810040da0141001c1033c05704c1014da01c260149604026014da01429", + "0x1033805368053380505410040da0141001c1033405708cc338073680730412", + "0xc3014da014c601510040103680504007040c5015c3318c801cda01cbe01412", + "0x1001c10041c401410164102fc053680530c054441030805368053200527810", + "0x53680531405278100fc05368050dc05448100dc0536805040300401036805", + "0xda0141001c100f4057143c014da01cbf01513040bf014da0143f01511040c2", + "0xbd014da014bd01406040bd014da01440014a404040014da0143c0146a04010", + "0x58014150401036805040070404813846285c615c5801cda01cbd3380745410", + "0x544010040da0141001c101400571c4f128073680730805048101600536805", + "0x50405904043014da014420151104053014da0144a0149e04042014da0144f", + "0x9e04059014da014470151204047014da014100c010040da0141001c10041c8", + "0xb9015c92ec053680710c0544c1010c0536805164054441014c053680514005", + "0x5018102dc0536805170052901017005368052ec051a810040da0141001c10", + "0xda0141001c102ccb4180a1728b52d807368072dc5801d15040b7014da014b7", + "0x5368052d805054102c405368052c80545c102c805368052d45701d1604010", + "0x70401072c0504059040ad014da014b101518040ae014da014530149e040af", + "0x103680515c052b810040da014b3014ae04010368052d0052b810040da01410", + "0x52e4053d810040da0141001c10041cc01410164102b005368051800505410", + "0x102a4053680504030040ac014da0145801415040103680515c052b810040da", + "0x118040ae014da014530149e040af014da014ac014dc0406a014da014a901519", + "0x1036805138052b810040da0141001c10041cb01410164102b405368051a805", + "0x504007040107340504059040a4014da01446014150401036805120052b810", + "0x1027c053680504030040a4014da014ce0141504010368050f4053d810040da", + "0x118040ae014da014c20149e040af014da014a4014dc0409e014da0149f01519", + "0x1204010368050400704030015ce27005368072b405468102b4053680527805", + "0x505810040da0141024c10040da0141001c101d80573c9626407368072b805", + "0x10368053300525010040da0149c014b204010368052580508810040da01499", + "0x735010250053680525005018102500536805040d504093014da0141035c10", + "0x508410224053680523c8b01cb00408b014da014102881023c053680525093", + "0x16014bc040af014da014af0141504010014da014100148f04087014da01489", + "0x162bc100480521c053680521c05098102840536805284052f8100580536805", + "0x50a41020c0536805040c004010368051d80505810040da0141001c1021ca1", + "0xda0141001c103c4f001dd00008801cda01c83058af284c104083014da01483", + "0x52f010220053680522005054103c805368050413604010368050409304010", + "0xcc014f2040a1014da014a1014be04010014da014100148f04000014da01400", + "0x1236805270cc3c8a10400022022514102700536805270054dc103300536805", + "0x54ec10040da0141001c103ec05744fa014da01cf901539040f93e0f73d8f3", + "0x5420050f0104250801cda015070143f04107014da0141035c10040da014fa", + "0x53680542c052f41042c053680542805100104280536805424050f410040da", + "0xf6014da014f6014bc040f3014da014f301415040f7014da014f70148f0410c", + "0x70410c3e0f63ccf704805430053680543005098103e005368053e0052f810", + "0x53cc05054103dc05368053dc0523c1043c05368053ec0508410040da01410", + "0xda0150f01426040f8014da014f8014be040f6014da014f6014bc040f3014da", + "0x9c014b20401036805040930401036805040070410f3e0f63ccf70480543c05", + "0x1044405368050405804110014da0141035c10040da014cc014940401036805", + "0xb004113014da014102881044805368054451001cd404111014da0151101406", + "0x1504010014da014100148f04116014da015150142104115014da0151244c07", + "0x5098102840536805284052f8103c405368053c4052f0103c005368053c005", + "0x10040da0141024c10040da0141001c10458a13c4f00401201516014da01516", + "0xda0141035c10040da014cc0149404010368052b80505810040da01430014f6", + "0x5368054611701cd404118014da015180140604118014da0141043c1045c05", + "0x11b014da0151a014210411a014da01519370072c0103700536805040a204119", + "0x100580536805058052f0102bc05368052bc050541004005368050400523c10", + "0x1001c1046ca1058af040120151b014da0151b01426040a1014da014a1014be", + "0x10041d2014101641047005368053340505410040da014be014160401036805", + "0xda014120141504010368052f80505810040da014cf014f6040103680504007", + "0x5018104780536805040f70411d014da0141035c10040da0141024c1047005", + "0x13401cb004134014da014102881047c05368054791d01cd40411e014da0151e", + "0x11c0141504010014da014100148f04136014da015350142104135014da0151f", + "0x54d805098102840536805284052f8100580536805058052f0104700536805", + "0xd704010368050540515c10040da0141001c104d8a10591c0401201536014da", + "0x1384dc07350104e005368054e005018104e005368050405804137014da01410", + "0x54f005084104f005368054e53b01cb00413b014da01410288104e40536805", + "0xda014d7014bc04022014da014220141504010014da014100148f0413d014da", + "0x13d284d708810048054f405368054f405098102840536805284052f81035c05", + "0xda0141001c1035c2201dd30581201cda01c070140701410040da0141004010", + "0x1204012014da01412014150401036805040a9040d5014da01415014a104010", + "0x102c00536805350051a810040da0141001c1028805750d4018073680735405", + "0x9c040be014da014060149e040bc014da014210149f04021014da014b0014a4", + "0xc0014da014100c010040da0141001c10041d5014101641009805368052f005", + "0x1009805368050a405270102f8053680528805278100a405368053000526410", + "0xcc33807368072f80504810040da0141001c1033c05758c1014da01c2601496", + "0xc6014da014c8014a4040c8014da014cc0146a040103680504007040cd015d7", + "0x103080536805314052701030c0536805338052781031405368053180527c10", + "0x5368052fc05264102fc053680504030040103680504007040107600504059", + "0x3f014da01cc201496040c2014da014370149c040c3014da014cd0149e04037", + "0x504007040bd015da1003d01cda01cc3014120401036805040070403c015d9", + "0x536805160054441015c05368050f4052781016005368051000544010040da", + "0x513805448101380536805040300401036805040070401076c050405904046", + "0xda01c460151304046014da014480151104057014da014bd0149e04048014da", + "0xda01450014a404050014da0144a0146a0401036805040070404f015dc12805", + "0x704047015dd10c5301cda01c4204807108101080536805108050181010805", + "0x102e405778bb164073680715c050481014c053680514c0505410040da01410", + "0x5c01511040b7014da014590149e0405c014da014bb01510040103680504007", + "0x112040b5014da014100c010040da0141001c10041df01410164102d80536805", + "0x544c102d8053680518005444102dc05368052e4052781018005368052d405", + "0x5290102c805368052d0051a810040da0141001c102cc05780b4014da01cb6", + "0xa1784ae2bc07368072c45301d15040b1014da014b101406040b1014da014b2", + "0x6a01cda01cb701412040af014da014af01415040103680504007040a92b0ad", + "0x5368051a8052781027805368052900544010040da0141001c1027c05788a4", + "0x5040300401036805040070401078c050405904030014da0149e015110409c", + "0xda01496015110409c014da0149f0149e04096014da014990151204099014da", + "0xda014760146a04010368050400704093015e41d805368070c00544c100c005", + "0xda01c8f2bc074541023c053680523c050181023c0536805250052901025005", + "0x11704000014da014892b80745810040da0141001c102208321ca17948922c07", + "0x5460103c8053680527005278103c4053680522c05054103c0053680500005", + "0x10040da01483014ae040103680504007040107980504059040f3014da014f0", + "0x504059040f6014da014870141504010368052b8052b810040da01488014ae", + "0x505410040da014ae014ae040103680524c053d810040da0141001c10041e7", + "0x53d805370103e005368053dc05464103dc053680504030040f6014da014af", + "0x107980504059040f3014da014f801518040f2014da0149c0149e040f1014da", + "0x52b40505410040da014a9014ae04010368052b0052b810040da0141001c10", + "0x505410040da014b3014f6040103680504007040107a00504059040f9014da", + "0x53e405370103ec05368053e805464103e8053680504030040f9014da01453", + "0xda01cf30151a040f3014da014fb01518040f2014da014b70149e040f1014da", + "0x70410b015ea4290901cda01cf20141204010368050400704108015e941c05", + "0x543c0527c1043c053680543005290104300536805428051a810040da01410", + "0x107ac050405904112014da015100149c04111014da015090149e04110014da", + "0x10b0149e04115014da015130149904113014da014100c010040da0141001c10", + "0x704117015ec45805368074480525810448053680545405270104440536805", + "0x15040103680504007040dc015ed4651801cda01d163c4071d810040da01410", + "0x10040da0141001c10470057b91b46807368074440504810460053680546005", + "0xda0151901494040103680546c0508810040da0151a01416040103680504093", + "0x54d410040da0143f01535040103680510c0551810040da01507014b204010", + "0x53680547805018104780536805040d50411d014da0141035c10040da014c1", + "0x53680547d3401cb004134014da014102881047c05368054791d01cd40411e", + "0x118014da015180141504010014da014100148f04136014da015350142104135", + "0x54d805368054d805098102840536805284052f8100580536805058052f010", + "0x536805040c004010368054700505810040da0141001c104d8a10591804012", + "0x104f13b01def4e53801cda01d3705918284c104137014da015370142904137", + "0x5368054e005054104f4053680504136040103680504093040103680504007", + "0xa1014da014a1014be04010014da014100148f04139014da01539014bc04138", + "0x1010c053680510c0551c100fc05368050fc050181030405368053040501810", + "0x3f3053d284104e5380194904119014da01519014f204107014da0150701537", + "0x1001c10514057c144014da01d430153904143509415013f048da0151941c43", + "0x14701cda015460143f04146014da0141035c10040da015440153b0401036805", + "0x1052c053680552805100105280536805524050f410040da015470143c04149", + "0xbc0413f014da0153f0141504141014da015410148f0414c014da0154b014bd", + "0x14104805530053680553005098105080536805508052f810500053680550005", + "0x5368055040523c1053405368055140508410040da0141001c10531425013f", + "0x142014da01542014be04140014da01540014bc0413f014da0153f0141504141", + "0x5040930401036805040070414d509404fd410480553405368055340509810", + "0x135040103680510c0551810040da01507014b204010368054640525010040da", + "0x536805040580414e014da0141035c10040da014c10153504010368050fc05", + "0x150014da0141028810378053680553d4e01cd40414f014da0154f014060414f", + "0x10014da014100148f04152014da015510142104151014da014de540072c010", + "0x102840536805284052f8104f005368054f0052f0104ec05368054ec0505410", + "0x54440505810040da0141001c10548a14f13b0401201552014da0155201426", + "0x135040103680510c0551810040da01507014b20401036805304054d410040da", + "0x103680504007040107c4050405904153014da014dc0141504010368050fc05", + "0x107014b20401036805304054d410040da0151101416040103680545c053d810", + "0x153014da014f10141504010368050fc054d410040da01443015460401036805", + "0x55c005018105c005368050414a0416f014da0141035c10040da0141024c10", + "0x55c57201cb004172014da01410288105c405368055c16f01cd404170014da", + "0xda015530141504010014da014100148f04173014da014dd01421040dd014da", + "0x5368055cc05098102840536805284052f8100580536805058052f01054c05", + "0x5420053d810040da0141024c10040da0141001c105cca1059530401201573", + "0x135040103680510c0551810040da014f2014160401036805304054d410040da", + "0xda015750140604175014da0141052c105d00536805040d704010368050fc05", + "0xda015765dc072c0105dc0536805040a204176014da015755d007350105d405", + "0x5368053c4050541004005368050400523c105e405368055e005084105e005", + "0x179014da0157901426040a1014da014a1014be04016014da01416014bc040f1", + "0x5304054d410040da014570141604010368050400704179284163c41004805", + "0x7040107c805040590417a014da014470141504010368050fc054d410040da", + "0x1036805304054d410040da0145701416040103680513c053d810040da01410", + "0x5040d70401036805040930417a014da014120141504010368050fc054d410", + "0xda0157c5ec07350105f005368055f005018105f00536805041420417b014da", + "0x53680536c050841036c05368055f57f01cb00417f014da01410288105f405", + "0x16014da01416014bc0417a014da0157a0141504010014da014100148f04180", + "0x704180284165e81004805600053680560005098102840536805284052f810", + "0x10040da014c10153504010368050f0053d810040da0141024c10040da01410", + "0x5608050181060805368050410f04181014da0141035c10040da014c301416", + "0x560d8401cb004184014da014102881060c05368056098101cd404182014da", + "0xda014120141504010014da014100148f04187014da015860142104186014da", + "0x53680561c05098102840536805284052f8100580536805058052f01004805", + "0x533c053d810040da0141024c10040da0141001c1061ca1058120401201587", + "0x604189014da014103dc106200536805040d704010368052f80505810040da", + "0x72c01062c0536805040a20418a014da015896200735010624053680562405", + "0x50541004005368050400523c106340536805630050841063005368056298b", + "0x18d01426040a1014da014a1014be04016014da01416014bc04012014da01412", + "0x10040da01415014570401036805040070418d2841604810048056340536805", + "0x18e01cd40418f014da0158f014060418f014da01410160106380536805040d7", + "0x1f301421041f3014da01590644072c0106440536805040a204190014da0158f", + "0x535c052f0100880536805088050541004005368050400523c107d00536805", + "0xa135c2204012015f4014da015f401426040a1014da014a1014be040d7014da", + "0x7368050481001d4d04012014da01415014a404015014da014a10154c041f4", + "0xda014d5014de04006354073680535c0553c1035c0536805088055381008816", + "0xa201cda014a201551040a2014da014d4014c6040d4014da014060155004010", + "0xbe2f007368052f005548102f00536805040c304021014da014b0014c5040b0", + "0xda01c212f807014150dc10058053680505805054102f805368052f80530810", + "0xbc04029014da0142901406040103680504007040ce33cc1285f50a4c0098a1", + "0x1f6334cc01cda01c2905807454103000536805300052f810098053680509805", + "0x53680530ca201d6f040c3014da0141054c10040da0141001c10314c6320a1", + "0xcc014da014cc01415040c2014da014c2014bf040bc014da014bc014c2040c2", + "0x10040da0141001c101003d0f0a17dc3f0dcbf284da01cc22f0c0098150dc10", + "0x11504037014da01437014be040bf014da014bf014bc0403f014da0143f01406", + "0x5160cd01d160401036805040070404e11857285f8160bd01cda01c3f33007", + "0xda014bd014150404f014da0144a015710404a014da014480157004048014da", + "0x53680513c055c8100dc05368050dc052f8102fc05368052fc052f0102f405", + "0x5138052b810040da01446014ae0401036805040070404f0dcbf2f4150144f", + "0x604042014da01410374101400536805040d70401036805334052b810040da", + "0xbc04043014da014570141504053014da014421400735010108053680510805", + "0x10164102ec053680514c0511c1016405368050dc052f81011c05368052fc05", + "0x102e405368053300505410040da014cd014ae040103680504007040107e405", + "0x59040b6014da0144001447040b7014da0143d014be0405c014da0143c014bc", + "0x10040da014c5014ae0401036805318052b810040da0141001c10041fa01410", + "0xda01410374102d40536805040d704010368052f0055d010040da014a201573", + "0xda014c801415040b4014da014602d407350101800536805180050181018005", + "0x5368052d00511c101640536805300052f81011c0536805098052f01010c05", + "0xb1014da014b201575040b2014da014bb2cc072c0102cc0536805040a2040bb", + "0x101640536805164052f81011c053680511c052f01010c053680510c0505410", + "0xda014bc01574040103680504007040b11644710c15014b1014da014b101572", + "0x101700536805304052f0102e405368050580505410040da014a20157304010", + "0x72c0102bc0536805040a2040b6014da014ce01447040b7014da014cf014be", + "0x52f0102e405368052e405054102b405368052b8055d4102b805368052d8af", + "0x5c2e415014ad014da014ad01572040b7014da014b7014be0405c014da0145c", + "0x536805088055e0100880536805054055dc100580536805048055d8102b4b7", + "0x6040075341001805368050180501810018d501cda0141635c0728579040d7", + "0x5378102f02101cda014b00154f040b0014da014a20154e040a23500736805", + "0x5098055441009805368052f805318102f805368052f00554010040da01421", + "0xda014c101552040c1014da0141030c100a4053680530005314103002601cda", + "0xda014d401415040d5014da014d50148f040cf014da014cf014c2040cf30407", + "0xda0141001c10314c6320a17eccd330ce284da01c2933ca1014150dc1035005", + "0xcc014da014cc014be040ce014da014ce014bc040cd014da014cd0140604010", + "0x5041530401036805040070403f0dcbf285fc308c301cda01ccd3500745410", + "0x50f4052fc10304053680530405308100f405368050f02601d6f0403c014da", + "0x1fd160bd100a1368070f4c1330ce05437040c3014da014c3014150403d014da", + "0x536805100052f01016005368051600501810040da0141001c101384615ca1", + "0x101085013ca17f84a1200736807160c301d15040bd014da014bd014be04040", + "0x55c41010c053680514c055c01014c0536805128c201d16040103680504007", + "0xd50148f04040014da01440014bc04048014da014480141504047014da01443", + "0xd5100480480511c053680511c055c8102f405368052f4052f8103540536805", + "0x52b810040da01442014ae0401036805140052b810040da0141001c1011cbd", + "0x5368052ec05018102ec0536805040dd04059014da0141035c10040da014c2", + "0x536805100052f010170053680513c05054102e405368052ec5901cd4040bb", + "0x7040107fc0504059040b5014da014b901447040b6014da014bd014be040b7", + "0xda01457014bc04060014da014c3014150401036805308052b810040da01410", + "0x100420001410164102c805368051380511c102cc0536805118052f8102d005", + "0xda014260157304010368050fc052b810040da01437014ae040103680504007", + "0x5018102bc0536805040dd040b1014da0141035c10040da014c10157404010", + "0x52f01017005368052fc05054102b805368052bcb101cd4040af014da014af", + "0x5040a2040b5014da014ae01447040b6014da014cc014be040b7014da014ce", + "0x517005054102a405368052b0055d4102b005368052d4ad01cb0040ad014da", + "0xda014b6014be040d5014da014d50148f040b7014da014b7014bc0405c014da", + "0x174040103680504007040a92d8d52dc5c048052a405368052a4055c8102d805", + "0x5320052f01018005368053500505410040da0142601573040103680530405", + "0x536805040a2040b2014da014c501447040b3014da014c6014be040b4014da", + "0x536805180050541027c0536805290055d41029005368052c86a01cb00406a", + "0xb3014da014b3014be040d5014da014d50148f040b4014da014b4014bc04060", + "0x100881601cda014120157a0409f2ccd52d0600480527c053680527c055c810", + "0x17904006014da014d501578040d5014da014150157b040d7014da0141601576", + "0xa2014da014a201406040b0014da0142201576040a2350073680535c0601ca1", + "0x52f01001d4d040bc014da014bc01406040bc08407368052c0a2350a15e410", + "0x29014de040c10a407368053000553c1030005368050980553810098be01cda", + "0xda014ce01551040ce014da014cf014c6040cf014da014c1015500401036805", + "0x73680532005548103200536805040c3040cd014da014cc014c5040cc33807", + "0x5368052f8050541008405368050840523c1031805368053180530810318c8", + "0x1036805040070403f0dcbf28601308c3314a136807334c62840505437040be", + "0x1030c053680530c052f8103140536805314052f01030805368053080501810", + "0xda0141054c10040da0141001c10160bd100a18083d0f00736807308be01d15", + "0xda01446014bf040c8014da014c8014c204046014da01457338075bc1015c05", + "0xa180c4a1204e284da01c46320c3314150dc100f005368050f0050541011805", + "0x4e014da0144e014bc0404a014da0144a01406040103680504007040421404f", + "0x7040bb164472860410c5301cda01c4a0f007454101200536805120052f810", + "0x5c015710405c014da014b901570040b9014da014430f40745810040da01410", + "0x50840523c101380536805138052f01014c053680514c05054102dc0536805", + "0x480844e14c12014b7014da014b70157204048014da01448014be04021014da", + "0x3d014ae04010368052ec052b810040da01459014ae040103680504007040b7", + "0xb5014da014b501406040b5014da01410374102d80536805040d70401036805", + "0xb3014da0144e014bc040b4014da014470141504060014da014b52d80735010", + "0x1001c100420501410164102c405368051800511c102c80536805120052f810", + "0x53680513c052f0102bc05368050f00505410040da0143d014ae0401036805", + "0x7040108180504059040ac014da0144201447040ad014da01450014be040ae", + "0x1036805338055cc10040da01458014ae04010368052f4052b810040da01410", + "0x6a014060406a014da01410374102a40536805040d70401036805320055d010", + "0xc5014bc040b4014da0144001415040a4014da0146a2a407350101a80536805", + "0xda01410288102c405368052900511c102c8053680530c052f8102cc0536805", + "0xda014b4014150409c014da0149e015750409e014da014b127c072c01027c05", + "0x5368052c8052f81008405368050840523c102cc05368052cc052f0102d005", + "0x55d010040da0141001c10270b2084b32d0120149c014da0149c01572040b2", + "0xda014bf014bc040af014da014be014150401036805338055cc10040da014c8", + "0x30014da01410288102b005368050fc0511c102b405368050dc052f8102b805", + "0xaf014da014af0141504096014da014990157504099014da014ac0c0072c010", + "0x102b405368052b4052f81008405368050840523c102b805368052b8052f010", + "0x176040d70480736805048054fc10258ad084ae2bc1201496014da0149601572", + "0x55f410040da0141001c100180581c1036807354055f010354053680535c05", + "0x10368050480525010040da01416014940401036805088052c810040da01415", + "0x7350102880536805288050181028805368050417f040d4014da0141035c10", + "0x536c102f005368052c02101cb004021014da01410288102c00536805288d4", + "0x70148f04005014da01405014bc04010014da0141001415040be014da014bc", + "0x701410048052f805368052f805600102840536805284052f81001c0536805", + "0x100981601cda014160153f04010368050180560410040da0141001c102f8a1", + "0x17d0401036805040070402901608040da01cc00157c040c0014da0142601576", + "0xda014120149404010368050580525010040da01422014b2040103680505405", + "0xd4040cf014da014cf01406040cf014da01410608103040536805040d704010", + "0xdb040cd014da014ce330072c0103300536805040a2040ce014da014cf30407", + "0x523c100140536805014052f01004005368050400505410320053680533405", + "0x504012014c8014da014c801580040a1014da014a1014be04007014da01407", + "0xc60480736805048054fc10040da0142901581040103680504007040c828407", + "0x184040c2014da014c301583040c3014da0141022c103140536805318055d810", + "0x5290100fc05368050dc0561c10040da014bf01586040372fc073680530805", + "0x101003d01cda014c50f007285790403c014da0143c014060403c014da0143f", + "0x57014da0145801588040582f407368051001001d4d04040014da0144001406", + "0x1012005368051380562c10040da014460158a0404e118073680515c0562410", + "0x10140053680513c053141013c4a01cda0144a015510404a014da01448014c6", + "0x8f04053014da01453014c204053108073680510805548101080536805040c3", + "0x43284da01c5014ca1014150dc102f405368052f405054100f405368050f405", + "0x43014bc04059014da01459014060401036805040070405c2e4bb2860916447", + "0xb52860a2d8b701cda01c592f4074541011c053680511c052f81010c0536805", + "0x102c805368052cc4a01d6f040b3014da0141054c10040da0141001c102d060", + "0x37040b7014da014b701415040b2014da014b2014bf04042014da01442014c2", + "0x501810040da0141001c102a4ac2b4a182cae2bcb1284da01cb21084710c15", + "0xb701d15040af014da014af014be040b1014da014b1014bc040ae014da014ae", + "0x100c005368050408b0401036805040070409c2789f2860c2906a01cda01cae", + "0x931d80736805258052bc102582201cda01422014b104099014da0143001583", + "0x5040300401036805040070408922c078348f250073680724ca41a8a163010", + "0xda0148f0158e04088014da014940141504083014da014870158d04087014da", + "0x100c010040da0141001c100420e01410164103c0053680520c0563c1000005", + "0x52240563810220053680522c05054103c805368053c405640103c40536805", + "0xf701e0f3d8f301cda01c762d8882858c040f0014da014f20158f04000014da", + "0x18e040fa014da014f60158e040f9014da014f301415040103680504007040f8", + "0xda0141001c1004210014101641041c05368053c00563c103ec053680500005", + "0x736807420003dca1630104200536805420056381042005368050419104010", + "0x53e005638103e405368054240505410040da0141001c104310b01e1142909", + "0x10840050405904107014da014f00158f040fb014da0150a0158e040fa014da", + "0x543c056401043c05368050403004010368053c0057cc10040da0141001c10", + "0xda0150c0158e040fa014da014f80158e040f9014da0150b0141504110014da", + "0x5040070411201612444053680741c057d01041c05368054400563c103ec05", + "0x53680544c055d81044c1201cda014120153f0401036805444053d810040da", + "0x118014da01517015870401036805458056181045d1601cda014990158404115", + "0x736805455190f4a15e4104640536805464050181046405368054600529010", + "0x53e8052b0104711b01cda0151a3e4075341046805368054680501810468dc", + "0xda0141030c1047c053680547805314104791c01cda0151c015510411d014da", + "0xda014dc0148f04135014da01535014c2041354d007368054d005548104d005", + "0xa1851374d807368074751f4d4af2c41284c1046c053680546c050541037005", + "0x104f40536805041530413c014da014fb014ac0401036805040070413b4e538", + "0x104d005368054d005308104d805368054d8052f0104fc05368054f51c01d6f", + "0x14450d42286155054001cda01d3c4fd344dd3604a130413f014da0153f014bf", + "0x8b04146014da0154501576041450580736805058054fc10040da0141001c10", + "0x56181052d4a01cda015490158404149014da015470158304147014da01410", + "0x5534050181053405368055300529010530053680552c0561c10040da0154a", + "0x75341053c053680553c050181053d4e01cda01546534dc285790414d014da", + "0x1054d5201cda015510158904151014da015500158804150378073680553d1b", + "0x5544105c005368055bc05318105bc053680554c0562c10040da015520158a", + "0xdd01552040dd014da0141030c105c805368055c405314105c57001cda01570", + "0x14e0148f04173014da01573014c204140014da01540014bc041733740736805", + "0x1765d574284da01d725cd41500150dc10378053680537805054105380536805", + "0xda01574014bc04176014da0157601406040103680504007041795e17728616", + "0x17f5f57c286175ed7a01cda01d7637807454105d405368055d4052f8105d005", + "0x530810600053680536d7001d6f040db014da0141054c10040da0141001c10", + "0x174054370417a014da0157a0141504180014da01580014bf040dd014da014dd", + "0x560c0501810040da0141001c1061d86610a18618360981284da01d8037575", + "0x760d7a01d1504182014da01582014be04181014da01581014bc04183014da", + "0x560c1063405368050408b0401036805040070418c62d8a286196258801cda", + "0x21a04191640073680563c052bc1063c2201cda01422014b10418e014da0158d", + "0x536805040300401036805040070421a84c0786df47cc073680764589620a1", + "0x21f014da015f40158e0421e014da015f3014150421d014da0161c0158d0421c", + "0xda014100c010040da0141001c1004221014101641088005368058740563c10", + "0x5368058680563810878053680584c050541088c0536805888056401088805", + "0x108a22701e268962401cda01d905ee1e2861a04220014da016230158f0421f", + "0x21f0158e0422a014da016250158e04229014da0162401415040103680504007", + "0x10040da0141001c100422c01410164108ac05368058800563c103800536805", + "0x22f8b807368078b61f89ca1868108b405368058b405638108b4053680504191", + "0x5368058a005638108a405368058b80505410040da0141001c108ca3101e30", + "0x7040108b005040590422b014da016200158f040e0014da0162f0158e0422a", + "0x5368058cc05640108cc0536805040300401036805880057cc10040da01410", + "0xe0014da016320158e0422a014da016280158e04229014da016310141504234", + "0x10368050400704237016368d405368078ac057d0108ac05368058d00563c10", + "0x108e405368058e0055d8108e01601cda014160153f04010368058d4053d810", + "0xa40423c014da0163b0158704010368058e805618108ee3a01cda0158e01584", + "0x23f8f807368058e63d538a15e4108f405368058f405018108f405368058f005", + "0x5368058a8052b0109064001cda0163f8a407534108fc05368058fc0501810", + "0x244014da0141030c101e4053680590c053141090e4101cda016410155104242", + "0x23e014da0163e0148f04245014da01645014c20424591007368059100554810", + "0x24a924a192247918073680790879915826041284c1090005368059000505410", + "0x75bc109340536805041530424c014da014e0014ac0401036805040070424b", + "0x52fc10910053680591005308109180536805918052f010938053680593641", + "0x70425338e52286519424f01cda01e4c93a4491e4604a130424e014da0164e", + "0x508816048a1870109540536805040d704254014da0141035c10040da01410", + "0x59600587c109665801cda016570161e04257014da016560161d04256014da", + "0x5368059540511c1095005368059500511c1096405368059640588010040da", + "0xe20143c0425c3880736805968050fc1096e5a01cda01655952592862204255", + "0xda0165c0143d0401036805974050f01097a5d01cda0165b0143f0401036805", + "0xe497e5093c1588c1093c053680593c052f0103900536805978050f41097c05", + "0x22404266014da014100c010040da0141001c109966498ca198a619800736807", + "0xbc04240014da0164001415040e1014da016670162504267014da0166605407", + "0x5600109840536805984052f8108f805368058f80523c10980053680598005", + "0x1036805054055f410040da0141001c10386618fa6090012014e1014da014e1", + "0x109a805368059a40536c109a405368059966801cb004268014da0141028810", + "0xbe0423e014da0163e0148f04263014da01663014bc04240014da0164001415", + "0x5040070426a9923e98e40048059a805368059a80560010990053680599005", + "0x9404010368050580525010040da01422014b20401036805054055f410040da", + "0x253014470426c014da014e3014be0426b014da01652014bc040103680504805", + "0xb20401036805054055f410040da0141001c100426e01410164109b40536805", + "0xda016410157304010368050480525010040da0141601494040103680508805", + "0xbe0426b014da01649014bc0401036805910055d010040da014e0014ae04010", + "0x26f01cb00426f014da01410288109b4053680592c0511c109b0053680592805", + "0x26b014bc04240014da016400141504271014da01670014db04270014da0166d", + "0x59c405600109b005368059b0052f8108f805368058f80523c109ac0536805", + "0xae04010368058dc053d810040da0141001c109c66c8fa6b9001201671014da", + "0xda01416014940401036805088052c810040da014150157d04010368058a805", + "0x1035c10040da0158e015860401036805380052b810040da014120149404010", + "0x59ce7201cd404273014da016730140604273014da0141089c109c80536805", + "0xda01675014db04275014da0167437c072c01037c0536805040a204274014da", + "0x5368055380523c106040536805604052f0108a405368058a405054109d805", + "0x109d982539818a41201676014da016760158004182014da01582014be0414e", + "0xda0157b014ae0401036805630052b810040da0158b014ae040103680504007", + "0x525010040da01416014940401036805088052c810040da014150157d04010", + "0x5368059e005018109e00536805040dd04277014da0141035c10040da01412", + "0x536805604052f0109e8053680562805054109e405368059e27701cd404278", + "0x7040109f805040590427d014da01679014470427c014da01582014be0427b", + "0x1036805088052c810040da014150157d04010368055ec052b810040da01410", + "0x52f0109fc05368055e80505410040da014120149404010368050580525010", + "0x50405904282014da015870144704281014da01586014be04280014da01584", + "0x55f410040da0157f014ae04010368055f4052b810040da0141001c1004283", + "0x10368050480525010040da01416014940401036805088052c810040da01415", + "0x5040dd04284014da0141035c10040da014dd0157404010368055c0055cc10", + "0x55f00505410a180536805a168401cd404285014da016850140604285014da", + "0xda01686014470427c014da01575014be0427b014da01574014bc0427a014da", + "0x5368059f0058a410a2005368059ec058a010a1c05368059e805370109f405", + "0xdd0157404010368050400704010a2c05040590428a014da0167d0162a04289", + "0x10040da01416014940401036805088052c810040da014150157d0401036805", + "0x177014bc0427f014da014de0141504010368055c0055cc10040da0141201494", + "0x59fc0537010a0805368055e40511c10a0405368055e0052f810a000536805", + "0xda016820162a04289014da016810162904288014da016800162804287014da", + "0x536805a340536c10a340536805a2a8c01cb00428c014da0141028810a2805", + "0x14e014da0154e0148f04288014da01688014bc04287014da01687014150428e", + "0x70428ea254ea228704805a380536805a380560010a240536805a24052f810", + "0x10368050580525010040da01422014b20401036805054055f410040da01410", + "0x4704290014da01543014be0428f014da01542014bc04010368050480525010", + "0x1036805054055f410040da0141001c10042920141016410a44053680551005", + "0x11c0157304010368050480525010040da01416014940401036805088052c810", + "0x28f014da01538014bc04010368054d0055d010040da014fb014ae0401036805", + "0xb004293014da0141028810a4405368054ec0511c10a4005368054e4052f810", + "0xbc0411b014da0151b0141504295014da01694014db04294014da01691a4c07", + "0x560010a400536805a40052f81037005368053700523c10a3c0536805a3c05", + "0x1036805448053d810040da0141001c10a56903728f46c1201695014da01695", + "0x16014940401036805088052c810040da014fa014ae0401036805054055f410", + "0x10040da014990158604010368053ec052b810040da01412014940401036805", + "0x29601cd404297014da016970140604297014da0141038010a580536805040d7", + "0x29a014db0429a014da01698a64072c010a640536805040a204298014da01697", + "0x50f40523c102c405368052c4052f0103e405368053e405054103980536805", + "0xaf0f4b13e412014e6014da014e601580040af014da014af014be0403d014da", + "0x150157d0401036805270052b810040da0149e014ae040103680504007040e6", + "0x10040da01416014940401036805088052c810040da014b6014ae0401036805", + "0x5a700501810a700536805040dd0429b014da0141035c10040da0141201494", + "0x52c4052f010a78053680527c0505410a740536805a729b01cd40429c014da", + "0x10a880504059042a1014da0169d01447042a0014da014af014be0429f014da", + "0x5088052c810040da014b6014ae0401036805054055f410040da0141001c10", + "0x10a8c05368052dc0505410040da014120149404010368050580525010040da", + "0x59042a6014da014a901447042a5014da014ac014be042a4014da014ad014bc", + "0x10040da014b4014ae0401036805180052b810040da0141001c10042a701410", + "0x50480525010040da01416014940401036805088052c810040da014150157d", + "0xdd042a8014da0141035c10040da01442015740401036805128055cc10040da", + "0x505410aa80536805aa6a801cd4042a9014da016a901406042a9014da01410", + "0x2aa01447042a0014da01447014be0429f014da01443014bc0429e014da014b5", + "0x5a80058a410ab00536805a7c058a010aac0536805a780537010a840536805", + "0x17d04010368050400704010abc0504059042ae014da016a10162a042ad014da", + "0xda01416014940401036805088052c810040da0144201574040103680505405", + "0xbc042a3014da014bd014150401036805128055cc10040da014120149404010", + "0x537010a9805368051700511c10a9405368052e4052f810a9005368052ec05", + "0x2a60162a042ad014da016a501629042ac014da016a401628042ab014da016a3", + "0x5ac40536c10ac40536805abab001cb0042b0014da0141028810ab80536805", + "0xda0143d0148f042ac014da016ac014bc042ab014da016ab01415042b2014da", + "0x2b2ab43dab2ab04805ac80536805ac80560010ab40536805ab4052f8100f405", + "0x100180536805040f8040d5014da014d701576040d70480736805048054fc10", + "0x22f0401036805288058b8102c0a201cda014d40162d040d4014da014060162b", + "0xa15e4102f005368052f005018102f00536805084052901008405368052c005", + "0x29014da014c001576040c00580736805058054fc10098be01cda014d52f007", + "0xda014cf01406040cf30407368050a4262f8a15e41009805368050980501810", + "0x5334056241033405368053300562010330ce01cda014cf040075341033c05", + "0xda014c5014c6040c5014da014c60158b04010368053200562810318c801cda", + "0x536805040c3040bf014da014c2014c5040c230c073680530c055441030c05", + "0x5368053040523c100fc05368050fc05308100fc3701cda014370155204037", + "0xbd286b31003d0f0a1368072fc3f2840505437040ce014da014ce01415040c1", + "0x100f005368050f0052f01010005368051000501810040da0141001c1015c58", + "0x1001c1013c4a120a1ad04e1180736807100ce01d150403d014da0143d014be", + "0xda01437014c204042014da0145030c075bc101400536805041530401036805", + "0x420dc3d0f0150dc10118053680511805054101080536805108052fc100dc05", + "0x47014da0144701406040103680504007040b92ec59286b511c4314ca136807", + "0x5c01cda01c47118074541010c053680510c052f81014c053680514c052f010", + "0xda0144e01632040b4014da014108c410040da0141001c10180b52d8a1ad8b7", + "0xb22cc078cc10170053680517005054102c8b401cda014b401632040b313807", + "0x10042b80141016410040da014b4014ae04010368050400704010adc1036807", + "0x10042b9040da01cb42c4078cc102c4b701cda014b701632040103680504007", + "0xac2b407368072b8b7170a1630102b8af01cda01422014af040103680504007", + "0x9f014da014a40158d040a4014da014100c010040da0141001c101a8a901eba", + "0x100c0053680527c0563c1027005368052b0056381027805368052b40505410", + "0x536805264056401026405368050403004010368050400704010aec0504059", + "0x30014da014960158f0409c014da0146a0158e0409e014da014a90141504096", + "0x76014150401036805040070408f25007af0931d807368072bc4e278a163010", + "0x50c00563c1021c05368052700563810224053680524c056381022c0536805", + "0x56381022005368050419104010368050400704010af4050405904083014da", + "0xda0141001c103c8f101ebe3c00001cda01c88270942858c04088014da01488", + "0x87014da014f00158e04089014da0148f0158e0408b014da014000141504010", + "0x50c0057cc10040da0141001c10042bd014101641020c05368050c00563c10", + "0x8b014da014f101415040f6014da014f301590040f3014da014100c010040da", + "0x1020c05368053d80563c1021c05368053c80563810224053680523c0563810", + "0x11604010368053dc053d810040da0141001c103e005afcf7014da01c83015f4", + "0x8f04053014da01453014bc0408b014da0148b01415040f9014da0148722407", + "0x53c8100480536805048053c81010c053680510c052f810304053680530405", + "0x53e4160481510cc114c8b35d43040f9014da014f90153704016014da01416", + "0x53e0053d810040da0141001c104250841cfb3e81201509421073ecfa048da", + "0xae0401036805054055f410040da014120149404010368050580525010040da", + "0x536805040e00410a014da0141035c10040da01489014ae040103680521c05", + "0x10f014da0141028810430053680542d0a01cd40410b014da0150b014060410b", + "0x8b014da0148b0141504111014da01510014db04110014da0150c43c072c010", + "0x1010c053680510c052f81030405368053040523c1014c053680514c052f010", + "0x5138052b810040da0141001c10444433045322c1201511014da0151101580", + "0xb204010368052dc052b810040da014120149404010368050580525010040da", + "0x1130162504113014da015120540789010448053680504030040103680508805", + "0x53040523c1014c053680514c052f010170053680517005054104540536805", + "0x43304531701201515014da015150158004043014da01443014be040c1014da", + "0x4e014ae0401036805180052b810040da014b5014ae04010368050400704115", + "0x10040da014150157d04010368050480525010040da01416014940401036805", + "0x545c050181045c0536805040dd04116014da0141035c10040da01422014b2", + "0x514c052f01046405368052d80505410460053680545d1601cd404117014da", + "0x10b0005040590411b014da01518014470411a014da01443014be040dc014da", + "0x50480525010040da01416014940401036805138052b810040da0141001c10", + "0x1047005368051180505410040da01422014b20401036805054055f410040da", + "0x590411f014da014b9014470411e014da014bb014be0411d014da01459014bc", + "0x10040da0144f014ae0401036805128052b810040da0141001c10042c101410", + "0x5088052c810040da014150157d04010368050480525010040da0141601494", + "0xdd04134014da0141035c10040da0143701574040103680530c055cc10040da", + "0x5054104d805368054d53401cd404135014da015350140604135014da01410", + "0x136014470411a014da0143d014be040dc014da0143c014bc04119014da01448", + "0x5468058a4104e00536805370058a0104dc0536805464053701046c0536805", + "0x17404010368050400704010b0805040590413b014da0151b0162a04139014da", + "0xda014150157d04010368050480525010040da014160149404010368050dc05", + "0xbc0411c014da014ce01415040103680530c055cc10040da01422014b204010", + "0x53701047c053680515c0511c104780536805160052f81047405368052f405", + "0x11f0162a04139014da0151e0162904138014da0151d0162804137014da0151c", + "0x54f40536c104f405368054ed3c01cb00413c014da01410288104ec0536805", + "0xda014c10148f04138014da01538014bc04137014da01537014150413f014da", + "0x13f4e4c14e137048054fc05368054fc05600104e405368054e4052f81030405", + "0x2c3040da01cd50157c040d5014da014d701576040d70580736805058054fc10", + "0x525010040da01422014b20401036805054055f410040da0141001c1001805", + "0xa2014da014108d0103500536805040d704010368050480525010040da01416", + "0x100840536805040a2040b0014da014a2350073501028805368052880501810", + "0x10040053680504005054102f805368052f00536c102f005368052c02101cb0", + "0x180040a1014da014a1014be04007014da014070148f04005014da01405014bc", + "0xda0140601581040103680504007040be2840701410048052f805368052f805", + "0x29014da014103e0103000536805098055d8100981201cda014120153f04010", + "0x10040da014cf0162e040ce33c0736805304058b41030405368050a4058ac10", + "0x179040cd014da014cd01406040cd014da014cc014a4040cc014da014ce0162f", + "0x536805314055d8103141601cda014160153f040c63200736805300cd01ca1", + "0x52fc05018102fcc201cda014c3318c828579040c6014da014c601406040c3", + "0x52bc100f02201cda01422014b10403f0dc07368052fc1001d4d040bf014da", + "0xc5040580fc07368050fc05544102f405368050f4052b0101003d01cda0143c", + "0x5308101384601cda014460155204046014da0141030c1015c053680516005", + "0x504a1304037014da0143701415040c2014da014c20148f0404e014da0144e", + "0x5100052b010040da0141001c101085013ca1b104a12007368072f457138a1", + "0xda01448014bc04047014da014430fc075bc1010c05368050415304053014da", + "0x471184a1201284c1011c053680511c052fc101180536805118053081012005", + "0x102d80536805040d7040103680504007040b7170b9286c52ec5901cda01c53", + "0x102d00536805180058dc10180053680508816048a18d4102d40536805040d7", + "0x47040b2014da014b20162004010368052cc0587c102c8b301cda014b40161e", + "0xaf2c407368052d4b62c8a1888102d405368052d40511c102d805368052d805", + "0xa92b007368052bc050fc10040da014ae0143c040ad2b807368052c4050fc10", + "0xbc040a4014da014a90143d0406a014da014ad0143d04010368052b0050f010", + "0x7040990c09c286c62789f01cda01ca41a8bb1641588c10164053680516405", + "0x51d805894101d805368052581501e2404096014da014100c010040da01410", + "0xda014c20148f0409f014da0149f014bc04037014da014370141504093014da", + "0x93278c227c370480524c053680524c05600102780536805278052f81030805", + "0x99250072c0102500536805040a20401036805054055f410040da0141001c10", + "0x5270052f0100dc05368050dc050541022c053680523c0536c1023c0536805", + "0xda0148b0158004030014da01430014be040c2014da014c20148f0409c014da", + "0x52c810040da014150157d0401036805040070408b0c0c2270370480522c05", + "0x5368052e4052f010040da014120149404010368050580525010040da01422", + "0x704010b1c050405904083014da014b70144704087014da0145c014be04089", + "0x10368050580525010040da01422014b20401036805054055f410040da01410", + "0x46015740401036805100052b810040da0143f0157304010368050480525010", + "0xda014420144704087014da01450014be04089014da0144f014bc0401036805", + "0x5368050000536c10000053680520c8801cb004088014da014102881020c05", + "0xc2014da014c20148f04089014da01489014bc04037014da0143701415040f0", + "0x11b040f021cc222437048053c005368053c0056001021c053680521c052f810", + "0x53540547010040da0141001c10288d4018a1b20d535c22284da01ca101407", + "0x11f040c0098be2f021048da014b00151e040b0014da014d50151d040d5014da", + "0xda014c00153504010368050980525010040da014bc01534040103680508405", + "0x5368050a4055d8100a4be01cda014be0153f040be014da014be014f204010", + "0xcd3300736805338058b410338053680533c058ac1033c0536805040f8040c1", + "0x6040c6014da014c8014a4040c8014da014cd0162f0401036805330058b810", + "0x1201cda014120153f040c33140736805304c601ca15e410318053680531805", + "0xda014bf30cc528579040c3014da014c301406040bf014da014c201576040c2", + "0x3d015880403d0f007368050fc1001d4d0403f014da0143f014060403f0dc07", + "0x51600562c10040da014bd0158a040582f4073680510005624101000536805", + "0x513805314101384601cda014460155104046014da01457014c604057014da", + "0xda01422014bc0404f128073680512805548101280536805040c304048014da", + "0x5368050f005054100dc05368050dc0523c1013c053680513c053081008805", + "0x1036805040070405911c43286c914c42140a1368071204f35c22054370403c", + "0x101080536805108052f8101400536805140052f01014c053680514c0501810", + "0xda0141054c10040da0141001c102d8b7170a1b28b92ec073680714c3c01d15", + "0xda01460014bf0404a014da0144a014c204060014da014b5118075bc102d405", + "0xa1b2cb22ccb4284da01c6012842140150dc102ec05368052ec050541018005", + "0xb4014da014b4014bc040b2014da014b201406040103680504007040ae2bcb1", + "0x7040a41a8a9286cc2b0ad01cda01cb22ec07454102cc05368052cc052f810", + "0x2cd0c09c01cda01c9e2b0ad2861a0409e27c0736805058052bc10040da01410", + "0x1024c05368051d805634101d80536805040300401036805040070409626407", + "0x590408b014da014930158f0408f014da014300158e04094014da0149c01415", + "0x87014da014890159004089014da014100c010040da0141001c10042ce01410", + "0x1022c053680521c0563c1023c0536805258056381025005368052640505410", + "0x520c0505410040da0141001c103c00001ecf2208301cda01c9f2e4942861a", + "0xda0148b0158f040f3014da0148f0158e040f2014da014880158e040f1014da", + "0xf70158e040f7014da0141064410040da0141001c10042d001410164103d805", + "0x103680504007040fb3e807b44f93e007368073dc8f000a1868103dc0536805", + "0x103cc05368053e405638103c805368053c005638103c405368053e00505410", + "0xda0148b015f304010368050400704010b400504059040f6014da0148b0158f", + "0x103c405368053e80505410420053680541c056401041c05368050403004010", + "0x1f4040f6014da015080158f040f3014da014fb0158e040f2014da014f00158e", + "0x745810040da01509014f60401036805040070410a016d242405368073d805", + "0x523c102d005368052d0052f0103c405368053c4050541042c05368053ccf2", + "0x12014f2040be014da014be014f2040b3014da014b3014be04037014da01437", + "0xda0150b048be054b30dcb43c4d750c1042c053680542c054dc100480536805", + "0xda0150a014f6040103680504007041124451043d0c04805449114410f43012", + "0x52b810040da014150157d04010368052f80525010040da014120149404010", + "0x115014da0141089c1044c0536805040d704010368053c8052b810040da014f3", + "0x1045c0536805040a204116014da0151544c073501045405368054540501810", + "0x103c405368053c4050541046405368054600536c1046005368054591701cb0", + "0x180040b3014da014b3014be04037014da014370148f040b4014da014b4014bc", + "0xda0146a014ae040103680504007041192cc372d0f104805464053680546405", + "0x525010040da014120149404010368052e4052b810040da014a4014ae04010", + "0xdc014da0141035c10040da01416014b20401036805054055f410040da014be", + "0x1046c0536805468dc01cd40411a014da0151a014060411a014da0141037410", + "0x470411e014da014b3014be0411d014da014b4014bc0411c014da014a901415", + "0x10368052e4052b810040da0141001c10042d3014101641047c053680546c05", + "0x16014b20401036805054055f410040da014be0149404010368050480525010", + "0xda014af014be04135014da014b1014bc04134014da014bb014150401036805", + "0x52b810040da0141001c10042d401410164104dc05368052b80511c104d805", + "0x10368052f80525010040da014120149404010368052d8052b810040da014b7", + "0x4a015740401036805118055cc10040da01416014b20401036805054055f410", + "0x139014da015390140604139014da01410374104e00536805040d70401036805", + "0x11d014da01450014bc0411c014da0145c014150413b014da015394e00735010", + "0x104f00536805470053701047c05368054ec0511c104780536805108052f810", + "0x5904140014da0151f0162a0413f014da0151e016290413d014da0151d01628", + "0x10040da01412014940401036805128055d010040da0141001c10042d501410", + "0x5118055cc10040da01416014b20401036805054055f410040da014be01494", + "0x53680511c052f8104d4053680510c052f0104d005368050f00505410040da", + "0x13d014da01535016280413c014da01534014dc04137014da014590144704136", + "0xb004141014da014102881050005368054dc058a8104fc05368054d8058a410", + "0xbc0413c014da0153c0141504143014da01542014db04142014da0154050407", + "0x5600104fc05368054fc052f8100dc05368050dc0523c104f405368054f405", + "0x10368050480525010040da0141001c1050d3f0dd3d4f01201543014da01543", + "0x14401cb004144014da0141028810040da01416014b20401036805054055f410", + "0x6014bc04010014da014100141504146014da01545014db04145014da014a2", + "0x551805600103500536805350052f81001c053680501c0523c100180536805", + "0xd4018a1b58d535c22284da01ca10140746c10518d401c060401201546014da", + "0x11e040b0014da014d50151d040d5014da014d50151c040103680504007040a2", + "0x10040da014bc0153404010368050840547c10300262f8bc08412368052c005", + "0xbe0153f040be014da014be014f20401036805300054d410040da0142601494", + "0x533c058ac1033c0536805040f8040c1014da0142901576040292f80736805", + "0xda014cd0162f0401036805330058b810334cc01cda014ce0162d040ce014da", + "0x5304c601ca15e410318053680531805018103180536805320052901032005", + "0xc301406040bf014da014c201576040c20480736805048054fc1030cc501cda", + "0x14d0403f014da0143f014060403f0dc07368052fcc3314a15e41030c0536805", + "0x582f40736805100056241010005368050f405620100f43c01cda0143f04007", + "0x15104046014da01457014c604057014da014580158b04010368052f40562810", + "0x5548101280536805040c304048014da0144e014c50404e118073680511805", + "0x523c1013c053680513c05308100880536805088052f01013c4a01cda0144a", + "0x42140a1368071204f35c22054370403c014da0143c0141504037014da01437", + "0x5140052f01014c053680514c0501810040da0141001c101644710ca1b5c53", + "0xb7170a1b60b92ec073680714c3c01d1504042014da01442014be04050014da", + "0xc204060014da014b5118075bc102d4053680504153040103680504007040b6", + "0x150dc102ec05368052ec05054101800536805180052fc10128053680512805", + "0xb201406040103680504007040ae2bcb1286d92c8b32d0a1368071804a10850", + "0xb22ec07454102cc05368052cc052f8102d005368052d0052f0102c80536805", + "0x9e27c0736805058052bc10040da0141001c102906a2a4a1b68ac2b40736807", + "0x5040300401036805040070409626407b6c302700736807278ac2b4a163010", + "0xda014300158e04094014da0149c0141504093014da014760158d04076014da", + "0x100c010040da0141001c10042dc014101641022c053680524c0563c1023c05", + "0x525805638102500536805264050541021c053680522405640102240536805", + "0x1edd2208301cda01c9f2e4942858c0408b014da014870158f0408f014da", + "0x18e040f2014da014880158e040f1014da0148301415040103680504007040f0", + "0xda0141001c10042de01410164103d8053680522c0563c103cc053680523c05", + "0x7368073dc8f000a1630103dc05368053dc05638103dc05368050419104010", + "0x53c005638103c405368053e00505410040da0141001c103ecfa01edf3e4f8", + "0x10b780504059040f6014da0148b0158f040f3014da014f90158e040f2014da", + "0x541c056401041c053680504030040103680522c057cc10040da0141001c10", + "0xda014fb0158e040f2014da014f00158e040f1014da014fa0141504108014da", + "0x5040070410a016e042405368073d8057d0103d805368054200563c103cc05", + "0x5368053c4050541042c05368053ccf201d160401036805424053d810040da", + "0xb3014da014b3014be04037014da014370148f040b4014da014b4014bc040f1", + "0x1042c053680542c054dc100480536805048053c8102f805368052f8053c810", + "0x1124451043d0c04805449114410f430123680542c122f8152cc372d0f135d43", + "0x52f80525010040da01412014940401036805428053d810040da0141001c10", + "0xd704010368053c8052b810040da014f3014ae0401036805054055f410040da", + "0x11544c0735010454053680545405018104540536805040e004113014da01410", + "0x54600536c1046005368054591701cb004117014da01410288104580536805", + "0xda014370148f040b4014da014b4014bc040f1014da014f10141504119014da", + "0x1192cc372d0f104805464053680546405600102cc05368052cc052f8100dc05", + "0x52e4052b810040da014a4014ae04010368051a8052b810040da0141001c10", + "0xb20401036805054055f410040da014be0149404010368050480525010040da", + "0xda0151a014060411a014da01410374103700536805040d7040103680505805", + "0xda014b4014bc0411c014da014a9014150411b014da0151a370073501046805", + "0x10042e1014101641047c053680546c0511c1047805368052cc052f81047405", + "0xda014be0149404010368050480525010040da014b9014ae040103680504007", + "0xbc04134014da014bb014150401036805058052c810040da014150157d04010", + "0x10164104dc05368052b80511c104d805368052bc052f8104d405368052c405", + "0x9404010368052d8052b810040da014b7014ae04010368050400704010b8805", + "0xda01416014b20401036805054055f410040da014be01494040103680504805", + "0x10374104e00536805040d70401036805128055d010040da014460157304010", + "0x5c014150413b014da015394e007350104e405368054e405018104e40536805", + "0x54ec0511c104780536805108052f8104740536805140052f0104700536805", + "0xda0151e016290413d014da0151d016280413c014da0151c014dc0411f014da", + "0x55d010040da0141001c10042e30141016410500053680547c058a8104fc05", + "0x1036805054055f410040da014be0149404010368050480525010040da0144a", + "0x52f0104d005368050f00505410040da01446015730401036805058052c810", + "0x134014dc04137014da014590144704136014da01447014be04135014da01443", + "0x54dc058a8104fc05368054d8058a4104f405368054d4058a0104f00536805", + "0xda01542014db04142014da01540504072c0105040536805040a204140014da", + "0x5368050dc0523c104f405368054f4052f0104f005368054f0050541050c05", + "0x1050d3f0dd3d4f01201543014da01543015800413f014da0153f014be04037", + "0xda01416014b20401036805054055f410040da0141201494040103680504007", + "0x146014da01545014db04145014da014a2510072c0105100536805040a204010", + "0x1001c053680501c0523c100180536805018052f01004005368050400505410", + "0x1033c10518d401c060401201546014da0154601580040d4014da014d4014be", + "0xda014a2014c2040a2014da0141030c10350053680501805314100180536805", + "0xa1b90212c00736807048d4288a10141284c103500536805350052fc1028805", + "0x100a405368053000531410300053680504046040103680504007040262f8bc", + "0x52fc10304053680530405308102c005368052c0052f0103040536805040c3", + "0x7040c8334cc286e5338cf01cda01c160a4c1084b004a1304029014da01429", + "0xda014c6014c5040c5014da0142201453040c6014da0141013810040da01410", + "0xc2014da014c2014c2040cf014da014cf014bc040c2014da0141030c1030c05", + "0x3c0fca1b98372fc0736807314c3308ce33c1284c1030c053680530c052fc10", + "0x102f40536805100055d810100d501cda014d50153f0401036805040070403d", + "0x58016e7040da01cbd0157c04037014da01437014be040bf014da014bf014bc", + "0x535c052c810040da014d5014940401036805054055f410040da0141001c10", + "0x101180536805118050181011805368050423804057014da0141035c10040da", + "0x1012805368051384801cb004048014da014102881013805368051185701cd4", + "0x8f040bf014da014bf014bc04010014da01410014150404f014da0144a014db", + "0x100480513c053680513c05600100dc05368050dc052f81001c053680501c05", + "0x1014005368050423904010368051600560410040da0141001c1013c3701cbf", + "0x47014da01453014ac0404314c0736805108052bc10108d701cda014d7014b1", + "0x102e40536805040c3040bb014da01459014c50405914007368051400554410", + "0x102ec05368052ec052fc1017005368051700530810170b901cda014b901552", + "0xac040103680504007040b4180b5286e82d8b701cda01c472ec5c0dcbf04a13", + "0x5001d6f04050014da014500163a040b2014da0141054c102cc053680510c05", + "0xb1014bf040b9014da014b9014c2040b7014da014b7014bc040b1014da014b2", + "0x1001c102a4ac2b4a1ba4ae2bc07368072ccb12e4b62dc1284c102c40536805", + "0xda0141022c1029005368051a8055d8101a8d501cda014d50153f0401036805", + "0xda0149c015860403027007368052780561010278053680527c0560c1027c05", + "0x96014da014960140604096014da01499014a404099014da014300158704010", + "0x524c1001d4d04093014da0149301406040931d807368052909601ca15e410", + "0x52b01021c8901cda0148b014af0408b35c073680535c052c41023c9401cda", + "0x1030c10000053680522005314102208f01cda0148f0155104083014da01489", + "0xf1014c2040af014da014af014bc040f13c007368053c005548103c00536805", + "0xae2bc1284c10250053680525005054101d805368051d80523c103c40536805", + "0xda01487014ac040103680504007040f83dcf6286ea3ccf201cda01c83000f1", + "0x5368053c8052f0103ec05368053e88f01d6f040fa014da0141054c103e405", + "0xf93ecf03ccf204a13040fb014da014fb014bf040f0014da014f0014c2040f2", + "0xd70410c014da014108ec10040da0141001c1042d0a424a1bad0841c0736807", + "0x587410444053680535cd5430a1870104400536805040d70410f014da01410", + "0x11501620040103680544c0587c104551301cda015120161e04112014da01511", + "0x10f454a18881044005368054400511c1043c053680543c0511c104540536805", + "0x50fc10040da015180143c041194600736805458050fc1045d1601cda01510", + "0x11a0143d0411b014da015190143d0401036805370050f010468dc01cda01517", + "0x2ec4791d01cda01d1c46d0841c1588c1041c053680541c052f0104700536805", + "0x5368054d81501e2404136014da014100c010040da0141001c104d53447ca1", + "0x11d014da0151d014bc04094014da014940141504138014da015370162504137", + "0x54e005368054e005600104780536805478052f8101d805368051d80523c10", + "0x536805040a20401036805054055f410040da0141001c104e11e1d91d25012", + "0x53680525005054104f005368054ec0536c104ec05368054d53901cb004139", + "0x134014da01534014be04076014da014760148f0411f014da0151f014bc04094", + "0x150157d0401036805040070413c4d07647c94048054f005368054f00560010", + "0x13d014da01509014bc040103680535c052c810040da014d5014940401036805", + "0x1001c10042ed0141016410500053680542c0511c104fc0536805428052f810", + "0x10040da014d7014b204010368053540525010040da014150157d0401036805", + "0x53d8052f010040da014f001574040103680521c052b810040da0148f01573", + "0x536805040a204140014da014f8014470413f014da014f7014be0413d014da", + "0x536805250050541050c05368055080536c1050805368055014101cb004141", + "0x13f014da0153f014be04076014da014760148f0413d014da0153d014bc04094", + "0x150157d040103680504007041434fc764f4940480550c053680550c0560010", + "0x144014da014ad014bc040103680535c052c810040da014d5014940401036805", + "0x1001c10042ee014101641051805368052a40511c1051405368052b0052f810", + "0x10040da014d7014b204010368053540525010040da014150157d0401036805", + "0x52d4052f010040da014b901574040103680510c052b810040da0145001573", + "0x536805040a204146014da014b40144704145014da01460014be04144014da", + "0x536805040050541052805368055240536c1052405368055194701cb004147", + "0x145014da01545014be04007014da014070148f04144014da01544014bc04010", + "0xd5014940401036805040070414a51407510100480552805368055280560010", + "0x1052c0536805040a20401036805054055f410040da014d7014b20401036805", + "0x100400536805040050541053405368055300536c1053005368050f54b01cb0", + "0x1800403c014da0143c014be04007014da014070148f0403f014da0143f014bc", + "0xda014d5014940401036805040070414d0f0070fc1004805534053680553405", + "0x1028810040da01422015460401036805054055f410040da014d7014b204010", + "0x1001415040de014da0154f014db0414f014da014c8538072c0105380536805", + "0x5334052f81001c053680501c0523c103300536805330052f0100400536805", + "0x10040da0141001c10378cd01ccc04012014de014da014de01580040cd014da", + "0x50880551810040da014150157d040103680535c052c810040da014d501494", + "0x151014da01426540072c0105400536805040a20401036805058054d410040da", + "0x102f005368052f0052f0100400536805040050541054805368055440536c10", + "0x1201552014da0155201580040be014da014be014be04007014da014070148f", + "0x108f410040da0141001c1005405bbca1014da01c100163c041522f8072f010", + "0xa10163e04016014da014120140735010048053680504805018100480536805", + "0x52c810040da014d50149404006354d7284da014220163f040222840736805", + "0xa201c07350102880536805350055d810350053680535c0590010040da01406", + "0x94040262f8bc284da014210163f040212840736805284058f8102c00536805", + "0x5300055d81030005368052f80590010040da01426014b204010368052f005", + "0x525010330ce33ca136805284058fc1030405368050a4b001cd404029014da", + "0x5334052bc10334cc01cda014cc014b104010368053380525010040da014cf", + "0xda014c5014ac040c5014da014c8014ad0401036805318052b810318c801cda", + "0x52fc052b8100dcbf01cda014cc014af040c2014da014c3304073501030c05", + "0xda0143c30807350100f005368050fc052b0100fc05368050dc052b410040da", + "0x1001c100f41601c050f405368050f40511c1005805368050580511c100f405", + "0xda014400140735010100053680510005018101000536805042410401036805", + "0x46014940404e11857284da014580164304058054073680505405908102f405", + "0x536805120055d810120053680515c0590010040da0144e014b20401036805", + "0xda0145001643040500540736805054059081013c05368051280701cd40404a", + "0x53680514c0590010040da01443014b20401036805108052501010c53108a1", + "0xa1368050540590c102ec05368051644f01cd404059014da014470157604047", + "0xb701cda014b7014b104010368051700525010040da014b901494040b7170b9", + "0xb4014da014b5014ad0401036805180052b810180b501cda014b6014af040b6", + "0xb101cda014b7014af040b2014da014b32ec07350102cc05368052d0052b010", + "0x102b405368052b8052b0102b805368052bc052b410040da014b1014ae040af", + "0x52b005368052b00511c102f405368052f40511c102b005368052b4b201cd4", + "0x15138892201005410284070141021c89220100544e2248804015338ac2f407", + "0x15638a101c050408722488040151388922010054f7284070141021c8922010", + "0x89220102b01213889220102b012a10a101c050408722488040151388922010", + "0x2f1054a101c050408722488040ac0484e22488040ac04af0054a101c0504087", + "0x1213889220102b012bc815284070141021c89220102b01213889220102b012", + "0x50408722488040ac0484e22488040ac04af3054a101c050408722488040ac", + "0x102b012bd415284070141021c89220102b01213889220102b012bd01528407", + "0x88040ac0484e22488040ac04af6054a101c050408722488040ac0484e22488", + "0x1005af8284070141029089220100549f2248804015bdc15284070141021c89", + "0xb52d0892b08804016be412054a101c05040a4224ac22010048152bc892b088", + "0x88040120581505437224ac2201035efa048152840701410290892b08804012", + "0xac2201004816054150dc892b088040d7bec2205812054a101c05040bd224ac", + "0x892b088040120581505437224ac2201035efc088160481528407014102f489", + "0x102f4892b08804012058150dc892b08804022bf42205812054a101c05040bd", + "0xa101c05040bd224ac220100481605437224ac2201008afe05812054a101c05", + "0xa101c05040bd224ac220100481505830018060dc892b08804006bfc1604815", + "0xc0407014100f43d01c3d0f4bc28700354d70881604815" + ], + "sierra_program_debug_info": { + "type_names": [ + [ + 0, + "RangeCheck" + ], + [ + 1, + "Const" + ], + [ + 2, + "Const" + ], + [ + 3, + "Const" + ], + [ + 4, + "ContractAddress" + ], + [ + 5, + "u128" + ], + [ + 6, + "core::integer::u256" + ], + [ + 7, + "cairo_level_tests::contracts::erc20::erc_20::Approval" + ], + [ + 8, + "Const" + ], + [ + 9, + "Const" + ], + [ + 10, + "felt252" + ], + [ + 11, + "core::starknet::storage::storage_base::StorageBase::>>" + ], + [ + 12, + "Const" + ], + [ + 13, + "Const" + ], + [ + 14, + "cairo_level_tests::contracts::erc20::erc_20::Transfer" + ], + [ + 15, + "cairo_level_tests::contracts::erc20::erc_20::Event" + ], + [ + 16, + "Const" + ], + [ + 17, + "Unit" + ], + [ + 18, + "core::bool" + ], + [ + 19, + "StorageBaseAddress" + ], + [ + 20, + "core::starknet::storage::StoragePointer0Offset::>" + ], + [ + 21, + "core::starknet::storage::storage_base::StorageBase::>>" + ], + [ + 22, + "Const" + ], + [ + 23, + "Const" + ], + [ + 24, + "NonZero" + ], + [ + 25, + "Const" + ], + [ + 26, + "Const" + ], + [ + 27, + "core::starknet::storage::StoragePointer0Offset::" + ], + [ + 28, + "Const" + ], + [ + 29, + "Const" + ], + [ + 30, + "Const" + ], + [ + 31, + "cairo_level_tests::contracts::erc20::erc_20::ContractState" + ], + [ + 32, + "Tuple" + ], + [ + 33, + "core::panics::Panic" + ], + [ + 34, + "Array" + ], + [ + 35, + "Tuple>" + ], + [ + 36, + "core::panics::PanicResult::<(cairo_level_tests::contracts::erc20::erc_20::ContractState, ())>" + ], + [ + 37, + "Box" + ], + [ + 38, + "Box" + ], + [ + 39, + "Snapshot>" + ], + [ + 40, + "core::array::Span::" + ], + [ + 41, + "Array" + ], + [ + 42, + "Snapshot>" + ], + [ + 43, + "core::array::Span::" + ], + [ + 44, + "u32" + ], + [ + 45, + "core::starknet::info::v2::TxInfo" + ], + [ + 46, + "u64" + ], + [ + 47, + "core::starknet::info::BlockInfo" + ], + [ + 48, + "core::starknet::info::v2::ResourceBounds" + ], + [ + 49, + "core::starknet::info::v2::ExecutionInfo" + ], + [ + 50, + "Box" + ], + [ + 51, + "core::option::Option::" + ], + [ + 52, + "Box" + ], + [ + 53, + "core::option::Option::>" + ], + [ + 54, + "Const" + ], + [ + 55, + "Tuple" + ], + [ + 56, + "core::pedersen::HashState" + ], + [ + 57, + "core::starknet::storage::StoragePath::>" + ], + [ + 58, + "core::starknet::storage::storage_base::StorageBase::>" + ], + [ + 59, + "Const" + ], + [ + 60, + "Const" + ], + [ + 61, + "core::starknet::storage::StoragePath::>" + ], + [ + 62, + "core::starknet::storage::storage_base::StorageBase::>" + ], + [ + 63, + "Const" + ], + [ + 64, + "Pedersen" + ], + [ + 65, + "core::option::Option::" + ], + [ + 66, + "Tuple" + ], + [ + 67, + "core::panics::PanicResult::<(core::integer::u256,)>" + ], + [ + 68, + "core::starknet::storage::storage_base::StorageBase::" + ], + [ + 69, + "Const" + ], + [ + 70, + "Const" + ], + [ + 71, + "u8" + ], + [ + 72, + "core::starknet::storage::StoragePointer0Offset::" + ], + [ + 73, + "Const" + ], + [ + 74, + "Tuple>" + ], + [ + 75, + "Const" + ], + [ + 76, + "StorageAddress" + ], + [ + 77, + "core::starknet::storage::StoragePointer0Offset::" + ], + [ + 78, + "BuiltinCosts" + ], + [ + 79, + "System" + ], + [ + 80, + "core::panics::PanicResult::<(core::array::Span::,)>" + ], + [ + 81, + "Const" + ], + [ + 82, + "GasBuiltin" + ] + ], + "libfunc_names": [ + [ + 0, + "revoke_ap_tracking" + ], + [ + 1, + "withdraw_gas" + ], + [ + 2, + "branch_align" + ], + [ + 3, + "struct_deconstruct>" + ], + [ + 4, + "store_temp" + ], + [ + 5, + "array_snapshot_pop_front" + ], + [ + 6, + "drop>>" + ], + [ + 7, + "drop>" + ], + [ + 8, + "array_new" + ], + [ + 9, + "const_as_immediate>" + ], + [ + 10, + "store_temp" + ], + [ + 11, + "array_append" + ], + [ + 12, + "struct_construct" + ], + [ + 13, + "struct_construct>>" + ], + [ + 14, + "enum_init,)>, 1>" + ], + [ + 15, + "store_temp" + ], + [ + 16, + "store_temp" + ], + [ + 17, + "store_temp,)>>" + ], + [ + 18, + "get_builtin_costs" + ], + [ + 19, + "store_temp" + ], + [ + 20, + "withdraw_gas_all" + ], + [ + 21, + "storage_base_address_const<1528802474226268325865027367859591458315299653151958663884057507666229546336>" + ], + [ + 22, + "struct_construct>" + ], + [ + 23, + "snapshot_take>" + ], + [ + 24, + "drop>" + ], + [ + 25, + "struct_deconstruct>" + ], + [ + 26, + "rename" + ], + [ + 27, + "storage_address_from_base" + ], + [ + 28, + "const_as_immediate>" + ], + [ + 29, + "store_temp" + ], + [ + 30, + "store_temp" + ], + [ + 31, + "storage_read_syscall" + ], + [ + 32, + "snapshot_take>" + ], + [ + 33, + "drop>" + ], + [ + 34, + "struct_construct>" + ], + [ + 35, + "struct_construct>>" + ], + [ + 36, + "enum_init,)>, 0>" + ], + [ + 37, + "const_as_immediate>" + ], + [ + 38, + "drop>" + ], + [ + 39, + "storage_base_address_const<944713526212149105522785400348068751682982210605126537021911324578866405028>" + ], + [ + 40, + "storage_base_address_const<134830404806214277570220174593674215737759987247891306080029841794115377321>" + ], + [ + 41, + "struct_construct>" + ], + [ + 42, + "snapshot_take>" + ], + [ + 43, + "drop>" + ], + [ + 44, + "struct_deconstruct>" + ], + [ + 45, + "u8_try_from_felt252" + ], + [ + 46, + "u8_to_felt252" + ], + [ + 47, + "const_as_immediate>" + ], + [ + 48, + "store_temp>" + ], + [ + 49, + "jump" + ], + [ + 50, + "const_as_immediate>" + ], + [ + 51, + "struct_construct>" + ], + [ + 52, + "snapshot_take>" + ], + [ + 53, + "drop>" + ], + [ + 54, + "store_temp>" + ], + [ + 55, + "function_call, core::starknet::storage::StorablePathableStorageAsPointer::, core::starknet::storage::storage_base::StorageBaseAsPath::, core::starknet::storage::StorableStoragePathAsPointer::, core::starknet::storage_access::StoreUsingPacking::, core::starknet::storage_access::StoreUsingPacking::<(core::integer::u128,), core::integer::u128, core::starknet::storage_access::StorePackingTuple1::, core::starknet::storage_access::StoreUsingPacking::>, core::integer::u128Drop, core::traits::TupleNextDrop::<(core::integer::u128,), core::metaprogramming::TupleSplitTupleSize1::, core::metaprogramming::IsTupleTupleSize1::, core::integer::u128Drop, core::traits::TupleSize0Drop>, core::metaprogramming::TupleSplitTupleSize1::>>>>, core::starknet::storage::StorableStoragePointer0OffsetReadAccess::, core::starknet::storage_access::StoreUsingPacking::, core::starknet::storage_access::StoreUsingPacking::<(core::integer::u128,), core::integer::u128, core::starknet::storage_access::StorePackingTuple1::, core::starknet::storage_access::StoreUsingPacking::>, core::integer::u128Drop, core::traits::TupleNextDrop::<(core::integer::u128,), core::metaprogramming::TupleSplitTupleSize1::, core::metaprogramming::IsTupleTupleSize1::, core::integer::u128Drop, core::traits::TupleSize0Drop>, core::metaprogramming::TupleSplitTupleSize1::>>>>::read>" + ], + [ + 56, + "enum_match>" + ], + [ + 57, + "struct_deconstruct>" + ], + [ + 58, + "snapshot_take" + ], + [ + 59, + "drop" + ], + [ + 60, + "dup" + ], + [ + 61, + "struct_deconstruct" + ], + [ + 62, + "drop" + ], + [ + 63, + "rename" + ], + [ + 64, + "u128_to_felt252" + ], + [ + 65, + "enable_ap_tracking" + ], + [ + 66, + "unbox" + ], + [ + 67, + "rename" + ], + [ + 68, + "enum_init, 0>" + ], + [ + 69, + "store_temp>>" + ], + [ + 70, + "store_temp>" + ], + [ + 71, + "struct_construct" + ], + [ + 72, + "enum_init, 1>" + ], + [ + 73, + "enum_match>" + ], + [ + 74, + "contract_address_try_from_felt252" + ], + [ + 75, + "disable_ap_tracking" + ], + [ + 76, + "drop" + ], + [ + 77, + "store_temp" + ], + [ + 78, + "const_as_immediate>" + ], + [ + 79, + "struct_construct>>" + ], + [ + 80, + "snapshot_take>>" + ], + [ + 81, + "drop>>" + ], + [ + 82, + "struct_deconstruct>>" + ], + [ + 83, + "struct_construct" + ], + [ + 84, + "struct_construct>>" + ], + [ + 85, + "store_temp>>" + ], + [ + 86, + "store_temp" + ], + [ + 87, + "function_call, core::starknet::storage::map::EntryInfoImpl::, core::hash::into_felt252_based::HashImpl::, core::starknet::storage_access::StoreUsingPacking::, core::starknet::storage_access::StoreUsingPacking::, core::starknet::storage_access::StoreUsingPacking::<(core::integer::u128,), core::integer::u128, core::starknet::storage_access::StorePackingTuple1::, core::starknet::storage_access::StoreUsingPacking::>, core::integer::u128Drop, core::traits::TupleNextDrop::<(core::integer::u128,), core::metaprogramming::TupleSplitTupleSize1::, core::metaprogramming::IsTupleTupleSize1::, core::integer::u128Drop, core::traits::TupleSize0Drop>, core::metaprogramming::TupleSplitTupleSize1::>>>::read>" + ], + [ + 88, + "drop" + ], + [ + 89, + "const_as_immediate>" + ], + [ + 90, + "const_as_immediate>" + ], + [ + 91, + "struct_construct>>" + ], + [ + 92, + "snapshot_take>>" + ], + [ + 93, + "drop>>" + ], + [ + 94, + "struct_deconstruct>>" + ], + [ + 95, + "struct_construct>>" + ], + [ + 96, + "struct_construct>" + ], + [ + 97, + "store_temp>>" + ], + [ + 98, + "store_temp>" + ], + [ + 99, + "function_call, core::starknet::storage::map::EntryInfoImpl::<(core::starknet::contract_address::ContractAddress, core::starknet::contract_address::ContractAddress), core::integer::u256>, core::hash::TupleNextHash::<(core::starknet::contract_address::ContractAddress, core::starknet::contract_address::ContractAddress), core::pedersen::HashState, core::pedersen::HashStateImpl, core::metaprogramming::TupleSplitTupleSize2::, core::hash::into_felt252_based::HashImpl::, core::hash::TupleNextHash::<(core::starknet::contract_address::ContractAddress,), core::pedersen::HashState, core::pedersen::HashStateImpl, core::metaprogramming::TupleSplitTupleSize1::, core::hash::into_felt252_based::HashImpl::, core::hash::TupleSize0Hash::, core::traits::TupleSize0Drop>, core::traits::TupleNextDrop::<(core::starknet::contract_address::ContractAddress,), core::metaprogramming::TupleSplitTupleSize1::, core::metaprogramming::IsTupleTupleSize1::, core::starknet::contract_address::ContractAddressDrop, core::traits::TupleSize0Drop>>, core::starknet::storage_access::StoreUsingPacking::, core::starknet::storage_access::StoreUsingPacking::, core::starknet::storage_access::StoreUsingPacking::<(core::integer::u128,), core::integer::u128, core::starknet::storage_access::StorePackingTuple1::, core::starknet::storage_access::StoreUsingPacking::>, core::integer::u128Drop, core::traits::TupleNextDrop::<(core::integer::u128,), core::metaprogramming::TupleSplitTupleSize1::, core::metaprogramming::IsTupleTupleSize1::, core::integer::u128Drop, core::traits::TupleSize0Drop>, core::metaprogramming::TupleSplitTupleSize1::>>>::read>" + ], + [ + 100, + "const_as_immediate>" + ], + [ + 101, + "enum_init>, 0>" + ], + [ + 102, + "store_temp>>" + ], + [ + 103, + "enum_init>, 1>" + ], + [ + 104, + "enum_match>>" + ], + [ + 105, + "u128s_from_felt252" + ], + [ + 106, + "struct_construct" + ], + [ + 107, + "enum_init, 0>" + ], + [ + 108, + "store_temp>" + ], + [ + 109, + "enum_init, 1>" + ], + [ + 110, + "rename" + ], + [ + 111, + "enum_match>" + ], + [ + 112, + "get_execution_info_v2_syscall" + ], + [ + 113, + "store_temp>" + ], + [ + 114, + "unbox" + ], + [ + 115, + "struct_deconstruct" + ], + [ + 116, + "drop>" + ], + [ + 117, + "drop>" + ], + [ + 118, + "drop" + ], + [ + 119, + "struct_construct" + ], + [ + 120, + "store_temp" + ], + [ + 121, + "function_call" + ], + [ + 122, + "enum_match>" + ], + [ + 123, + "drop>" + ], + [ + 124, + "struct_deconstruct>>" + ], + [ + 125, + "drop" + ], + [ + 126, + "dup" + ], + [ + 127, + "function_call" + ], + [ + 128, + "struct_deconstruct>" + ], + [ + 129, + "const_as_immediate>" + ], + [ + 130, + "function_call" + ], + [ + 131, + "function_call" + ], + [ + 132, + "function_call" + ], + [ + 133, + "drop" + ], + [ + 134, + "store_temp" + ], + [ + 135, + "function_call" + ], + [ + 136, + "const_as_immediate>" + ], + [ + 137, + "const_as_immediate>" + ], + [ + 138, + "struct_deconstruct>" + ], + [ + 139, + "storage_base_address_from_felt252" + ], + [ + 140, + "struct_construct>" + ], + [ + 141, + "snapshot_take>" + ], + [ + 142, + "drop>" + ], + [ + 143, + "struct_deconstruct>" + ], + [ + 144, + "dup" + ], + [ + 145, + "dup" + ], + [ + 146, + "const_as_immediate>" + ], + [ + 147, + "storage_address_from_base_and_offset" + ], + [ + 148, + "struct_construct>" + ], + [ + 149, + "enum_init, 0>" + ], + [ + 150, + "store_temp>" + ], + [ + 151, + "const_as_immediate>" + ], + [ + 152, + "drop" + ], + [ + 153, + "drop" + ], + [ + 154, + "enum_init, 1>" + ], + [ + 155, + "contract_address_to_felt252" + ], + [ + 156, + "struct_deconstruct>>" + ], + [ + 157, + "struct_deconstruct" + ], + [ + 158, + "pedersen" + ], + [ + 159, + "struct_deconstruct>" + ], + [ + 160, + "struct_deconstruct>>" + ], + [ + 161, + "felt252_is_zero" + ], + [ + 162, + "drop" + ], + [ + 163, + "const_as_immediate>" + ], + [ + 164, + "enum_init, 1>" + ], + [ + 165, + "store_temp>" + ], + [ + 166, + "drop>" + ], + [ + 167, + "const_as_immediate>" + ], + [ + 168, + "struct_construct>>>" + ], + [ + 169, + "snapshot_take>>>" + ], + [ + 170, + "drop>>>" + ], + [ + 171, + "struct_deconstruct>>>" + ], + [ + 172, + "struct_construct>>" + ], + [ + 173, + "snapshot_take>>" + ], + [ + 174, + "drop>>" + ], + [ + 175, + "struct_deconstruct>>" + ], + [ + 176, + "u128_overflowing_sub" + ], + [ + 177, + "enum_init" + ], + [ + 178, + "store_temp" + ], + [ + 179, + "store_temp" + ], + [ + 180, + "enum_init" + ], + [ + 181, + "const_as_immediate>" + ], + [ + 182, + "drop" + ], + [ + 183, + "enum_match" + ], + [ + 184, + "storage_write_syscall" + ], + [ + 185, + "u128_overflowing_add" + ], + [ + 186, + "struct_construct" + ], + [ + 187, + "enum_init" + ], + [ + 188, + "snapshot_take" + ], + [ + 189, + "drop" + ], + [ + 190, + "store_temp" + ], + [ + 191, + "function_call" + ], + [ + 192, + "emit_event_syscall" + ], + [ + 193, + "struct_construct>" + ], + [ + 194, + "enum_init, 0>" + ], + [ + 195, + "const_as_immediate>" + ], + [ + 196, + "rename" + ], + [ + 197, + "rename" + ], + [ + 198, + "rename>" + ], + [ + 199, + "const_as_immediate>" + ], + [ + 200, + "struct_construct>>>" + ], + [ + 201, + "snapshot_take>>>" + ], + [ + 202, + "drop>>>" + ], + [ + 203, + "struct_deconstruct>>>" + ], + [ + 204, + "const_as_immediate>" + ], + [ + 205, + "dup" + ], + [ + 206, + "u128_eq" + ], + [ + 207, + "const_as_immediate>" + ], + [ + 208, + "struct_construct" + ], + [ + 209, + "enum_init" + ], + [ + 210, + "const_as_immediate>" + ], + [ + 211, + "storage_base_address_const<603278275252936218847294002513349627170936020082667936993356353388973422646>" + ], + [ + 212, + "store_temp" + ], + [ + 213, + "contract_address_const<0>" + ], + [ + 214, + "enum_match" + ], + [ + 215, + "const_as_immediate>" + ], + [ + 216, + "dup" + ], + [ + 217, + "struct_deconstruct" + ], + [ + 218, + "rename" + ], + [ + 219, + "const_as_immediate>" + ], + [ + 220, + "dup" + ], + [ + 221, + "struct_deconstruct" + ] + ], + "user_func_names": [ + [ + 0, + "cairo_level_tests::contracts::erc20::erc_20::__wrapper__IERC20Impl__get_name" + ], + [ + 1, + "cairo_level_tests::contracts::erc20::erc_20::__wrapper__IERC20Impl__get_symbol" + ], + [ + 2, + "cairo_level_tests::contracts::erc20::erc_20::__wrapper__IERC20Impl__get_decimals" + ], + [ + 3, + "cairo_level_tests::contracts::erc20::erc_20::__wrapper__IERC20Impl__get_total_supply" + ], + [ + 4, + "cairo_level_tests::contracts::erc20::erc_20::__wrapper__IERC20Impl__balance_of" + ], + [ + 5, + "cairo_level_tests::contracts::erc20::erc_20::__wrapper__IERC20Impl__allowance" + ], + [ + 6, + "cairo_level_tests::contracts::erc20::erc_20::__wrapper__IERC20Impl__transfer" + ], + [ + 7, + "cairo_level_tests::contracts::erc20::erc_20::__wrapper__IERC20Impl__transfer_from" + ], + [ + 8, + "cairo_level_tests::contracts::erc20::erc_20::__wrapper__IERC20Impl__approve" + ], + [ + 9, + "cairo_level_tests::contracts::erc20::erc_20::__wrapper__IERC20Impl__increase_allowance" + ], + [ + 10, + "cairo_level_tests::contracts::erc20::erc_20::__wrapper__IERC20Impl__decrease_allowance" + ], + [ + 11, + "cairo_level_tests::contracts::erc20::erc_20::__wrapper__constructor" + ], + [ + 12, + "core::starknet::storage::StorablePointerReadAccessImpl::, core::starknet::storage::StorablePathableStorageAsPointer::, core::starknet::storage::storage_base::StorageBaseAsPath::, core::starknet::storage::StorableStoragePathAsPointer::, core::starknet::storage_access::StoreUsingPacking::, core::starknet::storage_access::StoreUsingPacking::<(core::integer::u128,), core::integer::u128, core::starknet::storage_access::StorePackingTuple1::, core::starknet::storage_access::StoreUsingPacking::>, core::integer::u128Drop, core::traits::TupleNextDrop::<(core::integer::u128,), core::metaprogramming::TupleSplitTupleSize1::, core::metaprogramming::IsTupleTupleSize1::, core::integer::u128Drop, core::traits::TupleSize0Drop>, core::metaprogramming::TupleSplitTupleSize1::>>>>, core::starknet::storage::StorableStoragePointer0OffsetReadAccess::, core::starknet::storage_access::StoreUsingPacking::, core::starknet::storage_access::StoreUsingPacking::<(core::integer::u128,), core::integer::u128, core::starknet::storage_access::StorePackingTuple1::, core::starknet::storage_access::StoreUsingPacking::>, core::integer::u128Drop, core::traits::TupleNextDrop::<(core::integer::u128,), core::metaprogramming::TupleSplitTupleSize1::, core::metaprogramming::IsTupleTupleSize1::, core::integer::u128Drop, core::traits::TupleSize0Drop>, core::metaprogramming::TupleSplitTupleSize1::>>>>::read" + ], + [ + 13, + "core::starknet::storage::map::StorableEntryReadAccess::, core::starknet::storage::map::EntryInfoImpl::, core::hash::into_felt252_based::HashImpl::, core::starknet::storage_access::StoreUsingPacking::, core::starknet::storage_access::StoreUsingPacking::, core::starknet::storage_access::StoreUsingPacking::<(core::integer::u128,), core::integer::u128, core::starknet::storage_access::StorePackingTuple1::, core::starknet::storage_access::StoreUsingPacking::>, core::integer::u128Drop, core::traits::TupleNextDrop::<(core::integer::u128,), core::metaprogramming::TupleSplitTupleSize1::, core::metaprogramming::IsTupleTupleSize1::, core::integer::u128Drop, core::traits::TupleSize0Drop>, core::metaprogramming::TupleSplitTupleSize1::>>>::read" + ], + [ + 14, + "core::starknet::storage::map::StorableEntryReadAccess::, core::starknet::storage::map::EntryInfoImpl::<(core::starknet::contract_address::ContractAddress, core::starknet::contract_address::ContractAddress), core::integer::u256>, core::hash::TupleNextHash::<(core::starknet::contract_address::ContractAddress, core::starknet::contract_address::ContractAddress), core::pedersen::HashState, core::pedersen::HashStateImpl, core::metaprogramming::TupleSplitTupleSize2::, core::hash::into_felt252_based::HashImpl::, core::hash::TupleNextHash::<(core::starknet::contract_address::ContractAddress,), core::pedersen::HashState, core::pedersen::HashStateImpl, core::metaprogramming::TupleSplitTupleSize1::, core::hash::into_felt252_based::HashImpl::, core::hash::TupleSize0Hash::, core::traits::TupleSize0Drop>, core::traits::TupleNextDrop::<(core::starknet::contract_address::ContractAddress,), core::metaprogramming::TupleSplitTupleSize1::, core::metaprogramming::IsTupleTupleSize1::, core::starknet::contract_address::ContractAddressDrop, core::traits::TupleSize0Drop>>, core::starknet::storage_access::StoreUsingPacking::, core::starknet::storage_access::StoreUsingPacking::, core::starknet::storage_access::StoreUsingPacking::<(core::integer::u128,), core::integer::u128, core::starknet::storage_access::StorePackingTuple1::, core::starknet::storage_access::StoreUsingPacking::>, core::integer::u128Drop, core::traits::TupleNextDrop::<(core::integer::u128,), core::metaprogramming::TupleSplitTupleSize1::, core::metaprogramming::IsTupleTupleSize1::, core::integer::u128Drop, core::traits::TupleSize0Drop>, core::metaprogramming::TupleSplitTupleSize1::>>>::read" + ], + [ + 15, + "cairo_level_tests::contracts::erc20::erc_20::StorageImpl::transfer_helper" + ], + [ + 16, + "cairo_level_tests::contracts::erc20::erc_20::StorageImpl::spend_allowance" + ], + [ + 17, + "cairo_level_tests::contracts::erc20::erc_20::StorageImpl::approve_helper" + ], + [ + 18, + "cairo_level_tests::contracts::erc20::erc_20::IERC20Impl::increase_allowance" + ], + [ + 19, + "cairo_level_tests::contracts::erc20::erc_20::IERC20Impl::decrease_allowance" + ], + [ + 20, + "cairo_level_tests::contracts::erc20::erc_20::constructor" + ], + [ + 21, + "cairo_level_tests::contracts::erc20::erc_20::EventIsEvent::append_keys_and_data" + ] + ] + }, + "contract_class_version": "0.1.0", + "entry_points_by_type": { + "EXTERNAL": [ + { + "selector": "0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e", + "function_idx": 6 + }, + { + "selector": "0x16d9d5d83f8eecc5d7450519aad7e6e649be1a6c9d6df85bd0b177cc59a926a", + "function_idx": 2 + }, + { + "selector": "0x1d13ab0a76d7407b1d5faccd4b3d8a9efe42f3d3c21766431d4fafb30f45bd4", + "function_idx": 9 + }, + { + "selector": "0x1e888a1026b19c8c0b57c72d63ed1737106aa10034105b980ba117bd0c29fe1", + "function_idx": 5 + }, + { + "selector": "0x219209e083275171774dab1df80982e9df2096516f06319c5c6d71ae0a8480c", + "function_idx": 8 + }, + { + "selector": "0x2819e8b2b82ee4c56798709651ab9e8537f644c0823e42ba017efce4f2077e4", + "function_idx": 3 + }, + { + "selector": "0x31341177714d81ad9ccd0c903211bc056a60e8af988d0fd918cc43874549653", + "function_idx": 0 + }, + { + "selector": "0x351ccc9e7b13b17e701a7d4f5f85b525bac37b7648419fe194e6c15bc73da47", + "function_idx": 1 + }, + { + "selector": "0x35a73cd311a05d46deda634c5ee045db92f811b4e74bca4437fcb5302b7af33", + "function_idx": 4 + }, + { + "selector": "0x3704ffe8fba161be0e994951751a5033b1462b918ff785c0a636be718dfdb68", + "function_idx": 7 + }, + { + "selector": "0x3b076186c19fe96221e4dfacd40c519f612eae02e0555e4e115a2a6cf2f1c1f", + "function_idx": 10 + } + ], + "L1_HANDLER": [], + "CONSTRUCTOR": [ + { + "selector": "0x28ffe4ff0f226a9107253e17a904099aa4f63a02a5621de0576e5aa71bc5194", + "function_idx": 11 + } + ] + }, + "abi": [ + { + "type": "impl", + "name": "IERC20Impl", + "interface_name": "cairo_level_tests::contracts::erc20::IERC20" + }, + { + "type": "struct", + "name": "core::integer::u256", + "members": [ + { + "name": "low", + "type": "core::integer::u128" + }, + { + "name": "high", + "type": "core::integer::u128" + } + ] + }, + { + "type": "interface", + "name": "cairo_level_tests::contracts::erc20::IERC20", + "items": [ + { + "type": "function", + "name": "get_name", + "inputs": [], + "outputs": [ + { + "type": "core::felt252" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "get_symbol", + "inputs": [], + "outputs": [ + { + "type": "core::felt252" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "get_decimals", + "inputs": [], + "outputs": [ + { + "type": "core::integer::u8" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "get_total_supply", + "inputs": [], + "outputs": [ + { + "type": "core::integer::u256" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "balance_of", + "inputs": [ + { + "name": "account", + "type": "core::starknet::contract_address::ContractAddress" + } + ], + "outputs": [ + { + "type": "core::integer::u256" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "allowance", + "inputs": [ + { + "name": "owner", + "type": "core::starknet::contract_address::ContractAddress" + }, + { + "name": "spender", + "type": "core::starknet::contract_address::ContractAddress" + } + ], + "outputs": [ + { + "type": "core::integer::u256" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "transfer", + "inputs": [ + { + "name": "recipient", + "type": "core::starknet::contract_address::ContractAddress" + }, + { + "name": "amount", + "type": "core::integer::u256" + } + ], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "transfer_from", + "inputs": [ + { + "name": "sender", + "type": "core::starknet::contract_address::ContractAddress" + }, + { + "name": "recipient", + "type": "core::starknet::contract_address::ContractAddress" + }, + { + "name": "amount", + "type": "core::integer::u256" + } + ], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "approve", + "inputs": [ + { + "name": "spender", + "type": "core::starknet::contract_address::ContractAddress" + }, + { + "name": "amount", + "type": "core::integer::u256" + } + ], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "increase_allowance", + "inputs": [ + { + "name": "spender", + "type": "core::starknet::contract_address::ContractAddress" + }, + { + "name": "added_value", + "type": "core::integer::u256" + } + ], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "decrease_allowance", + "inputs": [ + { + "name": "spender", + "type": "core::starknet::contract_address::ContractAddress" + }, + { + "name": "subtracted_value", + "type": "core::integer::u256" + } + ], + "outputs": [], + "state_mutability": "external" + } + ] + }, + { + "type": "constructor", + "name": "constructor", + "inputs": [ + { + "name": "name_", + "type": "core::felt252" + }, + { + "name": "symbol_", + "type": "core::felt252" + }, + { + "name": "decimals_", + "type": "core::integer::u8" + }, + { + "name": "initial_supply", + "type": "core::integer::u256" + }, + { + "name": "recipient", + "type": "core::starknet::contract_address::ContractAddress" + } + ] + }, + { + "type": "event", + "name": "cairo_level_tests::contracts::erc20::erc_20::Transfer", + "kind": "struct", + "members": [ + { + "name": "from", + "type": "core::starknet::contract_address::ContractAddress", + "kind": "data" + }, + { + "name": "to", + "type": "core::starknet::contract_address::ContractAddress", + "kind": "data" + }, + { + "name": "value", + "type": "core::integer::u256", + "kind": "data" + } + ] + }, + { + "type": "event", + "name": "cairo_level_tests::contracts::erc20::erc_20::Approval", + "kind": "struct", + "members": [ + { + "name": "owner", + "type": "core::starknet::contract_address::ContractAddress", + "kind": "data" + }, + { + "name": "spender", + "type": "core::starknet::contract_address::ContractAddress", + "kind": "data" + }, + { + "name": "value", + "type": "core::integer::u256", + "kind": "data" + } + ] + }, + { + "type": "event", + "name": "cairo_level_tests::contracts::erc20::erc_20::Event", + "kind": "enum", + "variants": [ + { + "name": "Transfer", + "type": "cairo_level_tests::contracts::erc20::erc_20::Transfer", + "kind": "nested" + }, + { + "name": "Approval", + "type": "cairo_level_tests::contracts::erc20::erc_20::Approval", + "kind": "nested" + } + ] + } + ] +} \ No newline at end of file diff --git a/crates/blockifier/feature_contracts/cairo0/account_faulty.cairo b/crates/blockifier_test_utils/resources/feature_contracts/cairo0/account_faulty.cairo similarity index 86% rename from crates/blockifier/feature_contracts/cairo0/account_faulty.cairo rename to crates/blockifier_test_utils/resources/feature_contracts/cairo0/account_faulty.cairo index 968f477b347..f35451194d1 100644 --- a/crates/blockifier/feature_contracts/cairo0/account_faulty.cairo +++ b/crates/blockifier_test_utils/resources/feature_contracts/cairo0/account_faulty.cairo @@ -11,7 +11,8 @@ from starkware.starknet.common.syscalls import ( get_block_number, get_block_timestamp, get_sequencer_address, - get_tx_info + get_tx_info, + storage_write ) from starkware.starknet.common.messages import send_message_to_l1 @@ -29,11 +30,15 @@ const GET_BLOCK_NUMBER = 5; const GET_BLOCK_TIMESTAMP = 6; // Use get_sequencer_address syscall. const GET_SEQUENCER_ADDRESS = 7; +// Write to the storage. +const STORAGE_WRITE = 8; // get_selector_from_name('foo'). const FOO_ENTRY_POINT_SELECTOR = ( 0x1b1a0649752af1b28b3dc29a1556eee781e4a4c3a1f7f53f90fa834de098c4d); +const STORAGE_WRITE_KEY = 15; + @external func __validate_declare__{syscall_ptr: felt*}(class_hash: felt) { faulty_validate(); @@ -68,6 +73,14 @@ func __validate__{syscall_ptr: felt*}( func __execute__{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( contract_address: felt, selector: felt, calldata_len: felt, calldata: felt* ) { + let (tx_info: TxInfo*) = get_tx_info(); + let scenario = tx_info.signature[0]; + if (scenario == STORAGE_WRITE) { + let value = tx_info.signature[2]; + storage_write(address=STORAGE_WRITE_KEY, value=value); + return (); + } + let to_address = 0; send_message_to_l1(to_address, calldata_len, calldata); @@ -120,6 +133,11 @@ func faulty_validate{syscall_ptr: felt*}() { assert block_timestamp = expected_block_timestamp; return (); } + if (scenario == STORAGE_WRITE) { + let value = tx_info.signature[1]; + storage_write(address=STORAGE_WRITE_KEY, value=value); + return (); + } assert scenario = GET_SEQUENCER_ADDRESS; let sequencer_address = get_sequencer_address(); diff --git a/crates/blockifier/feature_contracts/cairo0/account_with_dummy_validate.cairo b/crates/blockifier_test_utils/resources/feature_contracts/cairo0/account_with_dummy_validate.cairo similarity index 100% rename from crates/blockifier/feature_contracts/cairo0/account_with_dummy_validate.cairo rename to crates/blockifier_test_utils/resources/feature_contracts/cairo0/account_with_dummy_validate.cairo diff --git a/crates/blockifier/feature_contracts/cairo0/account_with_long_validate.cairo b/crates/blockifier_test_utils/resources/feature_contracts/cairo0/account_with_long_validate.cairo similarity index 100% rename from crates/blockifier/feature_contracts/cairo0/account_with_long_validate.cairo rename to crates/blockifier_test_utils/resources/feature_contracts/cairo0/account_with_long_validate.cairo diff --git a/crates/blockifier/feature_contracts/cairo0/compiled/account_faulty_compiled.json b/crates/blockifier_test_utils/resources/feature_contracts/cairo0/compiled/account_faulty_compiled.json similarity index 93% rename from crates/blockifier/feature_contracts/cairo0/compiled/account_faulty_compiled.json rename to crates/blockifier_test_utils/resources/feature_contracts/cairo0/compiled/account_faulty_compiled.json index e774d7d8491..e07aa00dc91 100644 --- a/crates/blockifier/feature_contracts/cairo0/compiled/account_faulty_compiled.json +++ b/crates/blockifier_test_utils/resources/feature_contracts/cairo0/compiled/account_faulty_compiled.json @@ -97,29 +97,29 @@ "entry_points_by_type": { "CONSTRUCTOR": [ { - "offset": 188, + "offset": 215, "selector": "0x28ffe4ff0f226a9107253e17a904099aa4f63a02a5621de0576e5aa71bc5194" } ], "EXTERNAL": [ { - "offset": 145, + "offset": 172, "selector": "0x15d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad" }, { - "offset": 108, + "offset": 116, "selector": "0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775" }, { - "offset": 283, + "offset": 324, "selector": "0x1b1a0649752af1b28b3dc29a1556eee781e4a4c3a1f7f53f90fa834de098c4d" }, { - "offset": 56, + "offset": 64, "selector": "0x289da278a8dc833409cabfdad1581e8e7d40e42dcaed693fa4008dcdb4963b3" }, { - "offset": 80, + "offset": 88, "selector": "0x36fcbf06cd96843058359e1a75928beacfac10727dab22a3972f0af8aa92895" } ], @@ -170,6 +170,14 @@ "0x480280017ffd8000", "0x208b7fff7fff7ffe", "0x480680017fff8000", + "0x53746f726167655772697465", + "0x400280007ffb7fff", + "0x400380017ffb7ffc", + "0x400380027ffb7ffd", + "0x482680017ffb8000", + "0x3", + "0x208b7fff7fff7ffe", + "0x480680017fff8000", "0x4765745478496e666f", "0x400280007ffd7fff", "0x482680017ffd8000", @@ -187,7 +195,7 @@ "0x208b7fff7fff7ffe", "0x480a7ffc7fff8000", "0x1104800180018000", - "0x99", + "0xac", "0x208b7fff7fff7ffe", "0x482680017ffd8000", "0x1", @@ -209,7 +217,7 @@ "0x6", "0x480a7ffa7fff8000", "0x1104800180018000", - "0x83", + "0x96", "0x208b7fff7fff7ffe", "0x480a7ffa7fff8000", "0x208b7fff7fff7ffe", @@ -239,7 +247,7 @@ "0x1104800180018000", "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffc5", "0x1104800180018000", - "0x65", + "0x78", "0x208b7fff7fff7ffe", "0x480280027ffb8000", "0x480280027ffd8000", @@ -269,12 +277,31 @@ "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", "0x480a7ff77fff8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffff9d", + "0x480080047fff8000", + "0x480080007fff8000", + "0x482480017fff8000", + "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffff9", + "0x20680017fff7fff", + "0xc", + "0x480080047ffc8000", + "0x48127ffa7fff8000", + "0x480680017fff8000", + "0xf", + "0x480080027ffd8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffff88", + "0x480a7ff87fff8000", + "0x480a7ff97fff8000", + "0x208b7fff7fff7ffe", + "0x48127ffb7fff8000", "0x480680017fff8000", "0x0", "0x480a7ffc7fff8000", "0x480a7ffd7fff8000", "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffa0", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffff8d", "0x480a7ff87fff8000", "0x480a7ff97fff8000", "0x208b7fff7fff7ffe", @@ -297,7 +324,7 @@ "0x482680017ffd8000", "0x3", "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffe5", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffd2", "0x40780017fff7fff", "0x1", "0x48127ffc7fff8000", @@ -341,7 +368,7 @@ "0x208b7fff7fff7ffe", "0x480a7ffd7fff8000", "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffff56", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffff43", "0x480080047fff8000", "0x480080007fff8000", "0x20680017fff7fff", @@ -367,7 +394,7 @@ "0x20680017fff7fff", "0x10", "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffff18", + "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffefd", "0x480080047ff48000", "0x48127ff27fff8000", "0x480080017ffe8000", @@ -377,7 +404,7 @@ "0x0", "0x48127ffa7fff8000", "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffff11", + "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffef6", "0x48127ffd7fff8000", "0x208b7fff7fff7ffe", "0x480080047ff78000", @@ -388,7 +415,7 @@ "0x9", "0x48127ff37fff8000", "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffff19", + "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffefe", "0x480080047fee8000", "0x400080017fff7ffe", "0x48127ffd7fff8000", @@ -401,18 +428,32 @@ "0x9", "0x48127ff07fff8000", "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffff13", + "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffef8", "0x480080047feb8000", "0x400080017fff7ffe", "0x48127ffd7fff8000", "0x208b7fff7fff7ffe", "0x480080047ff18000", + "0x480080007fff8000", + "0x482480017fff8000", + "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffff9", + "0x20680017fff7fff", + "0xa", + "0x480080047fee8000", + "0x48127fec7fff8000", + "0x480680017fff8000", + "0xf", + "0x480080017ffd8000", + "0x1104800180018000", + "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffeee", + "0x208b7fff7fff7ffe", + "0x480080047fee8000", "0x480680017fff8000", "0x7", "0x400080007ffe7fff", - "0x48127fee7fff8000", + "0x48127feb7fff8000", "0x1104800180018000", - "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffefa", + "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffed1", "0x48127ffe7fff8000", "0x208b7fff7fff7ffe", "0x208b7fff7fff7ffe", @@ -519,7 +560,25 @@ } } ], - "39": [ + "41": [ + { + "accessible_scopes": [ + "starkware.starknet.common.syscalls", + "starkware.starknet.common.syscalls.storage_write" + ], + "code": "syscall_handler.storage_write(segments=segments, syscall_ptr=ids.syscall_ptr)", + "flow_tracking_data": { + "ap_tracking": { + "group": 5, + "offset": 1 + }, + "reference_ids": { + "starkware.starknet.common.syscalls.storage_write.syscall_ptr": 4 + } + } + } + ], + "47": [ { "accessible_scopes": [ "starkware.starknet.common.syscalls", @@ -528,16 +587,16 @@ "code": "syscall_handler.get_tx_info(segments=segments, syscall_ptr=ids.syscall_ptr)", "flow_tracking_data": { "ap_tracking": { - "group": 5, + "group": 6, "offset": 1 }, "reference_ids": { - "starkware.starknet.common.syscalls.get_tx_info.syscall_ptr": 4 + "starkware.starknet.common.syscalls.get_tx_info.syscall_ptr": 5 } } } ], - "49": [ + "57": [ { "accessible_scopes": [ "starkware.starknet.common.messages", @@ -546,16 +605,16 @@ "code": "syscall_handler.send_message_to_l1(segments=segments, syscall_ptr=ids.syscall_ptr)", "flow_tracking_data": { "ap_tracking": { - "group": 6, + "group": 7, "offset": 1 }, "reference_ids": { - "starkware.starknet.common.messages.send_message_to_l1.syscall_ptr": 5 + "starkware.starknet.common.messages.send_message_to_l1.syscall_ptr": 6 } } } ], - "63": [ + "71": [ { "accessible_scopes": [ "__main__", @@ -566,14 +625,14 @@ "code": "memory[ap] = segments.add()", "flow_tracking_data": { "ap_tracking": { - "group": 10, + "group": 11, "offset": 0 }, "reference_ids": {} } } ], - "89": [ + "97": [ { "accessible_scopes": [ "__main__", @@ -584,14 +643,14 @@ "code": "memory[ap] = segments.add()", "flow_tracking_data": { "ap_tracking": { - "group": 14, + "group": 15, "offset": 0 }, "reference_ids": {} } } ], - "124": [ + "132": [ { "accessible_scopes": [ "__main__", @@ -602,14 +661,14 @@ "code": "memory[ap] = segments.add()", "flow_tracking_data": { "ap_tracking": { - "group": 18, + "group": 19, "offset": 0 }, "reference_ids": {} } } ], - "165": [ + "192": [ { "accessible_scopes": [ "__main__", @@ -620,14 +679,14 @@ "code": "memory[ap] = segments.add()", "flow_tracking_data": { "ap_tracking": { - "group": 20, - "offset": 25 + "group": 21, + "offset": 34 }, "reference_ids": {} } } ], - "197": [ + "224": [ { "accessible_scopes": [ "__main__", @@ -638,14 +697,14 @@ "code": "memory[ap] = segments.add()", "flow_tracking_data": { "ap_tracking": { - "group": 24, + "group": 25, "offset": 0 }, "reference_ids": {} } } ], - "286": [ + "327": [ { "accessible_scopes": [ "__main__", @@ -656,7 +715,7 @@ "code": "memory[ap] = segments.add()", "flow_tracking_data": { "ap_tracking": { - "group": 27, + "group": 28, "offset": 2 }, "reference_ids": {} @@ -697,6 +756,14 @@ "type": "const", "value": 1 }, + "__main__.STORAGE_WRITE": { + "type": "const", + "value": 8 + }, + "__main__.STORAGE_WRITE_KEY": { + "type": "const", + "value": 15 + }, "__main__.TRUE": { "destination": "starkware.cairo.common.bool.TRUE", "type": "alias" @@ -713,7 +780,7 @@ "decorators": [ "external" ], - "pc": 135, + "pc": 143, "type": "function" }, "__main__.__execute__.Args": { @@ -770,7 +837,7 @@ "decorators": [ "external" ], - "pc": 98, + "pc": 106, "type": "function" }, "__main__.__validate__.Args": { @@ -819,7 +886,7 @@ "decorators": [ "external" ], - "pc": 52, + "pc": 60, "type": "function" }, "__main__.__validate_declare__.Args": { @@ -856,7 +923,7 @@ "decorators": [ "external" ], - "pc": 72, + "pc": 80, "type": "function" }, "__main__.__validate_deploy__.Args": { @@ -909,7 +976,7 @@ "decorators": [ "constructor" ], - "pc": 174, + "pc": 201, "type": "function" }, "__main__.constructor.Args": { @@ -952,7 +1019,7 @@ }, "__main__.faulty_validate": { "decorators": [], - "pc": 206, + "pc": 233, "type": "function" }, "__main__.faulty_validate.Args": { @@ -984,7 +1051,7 @@ "decorators": [ "external" ], - "pc": 282, + "pc": 323, "type": "function" }, "__main__.foo.Args": { @@ -1027,11 +1094,15 @@ "destination": "starkware.starknet.common.messages.send_message_to_l1", "type": "alias" }, + "__main__.storage_write": { + "destination": "starkware.starknet.common.syscalls.storage_write", + "type": "alias" + }, "__wrappers__.__execute__": { "decorators": [ "external" ], - "pc": 145, + "pc": 172, "type": "function" }, "__wrappers__.__execute__.Args": { @@ -1066,7 +1137,7 @@ "decorators": [ "external" ], - "pc": 108, + "pc": 116, "type": "function" }, "__wrappers__.__validate__.Args": { @@ -1101,7 +1172,7 @@ "decorators": [ "external" ], - "pc": 56, + "pc": 64, "type": "function" }, "__wrappers__.__validate_declare__.Args": { @@ -1136,7 +1207,7 @@ "decorators": [ "external" ], - "pc": 80, + "pc": 88, "type": "function" }, "__wrappers__.__validate_deploy__.Args": { @@ -1171,7 +1242,7 @@ "decorators": [ "constructor" ], - "pc": 188, + "pc": 215, "type": "function" }, "__wrappers__.constructor.Args": { @@ -1206,7 +1277,7 @@ "decorators": [ "external" ], - "pc": 283, + "pc": 324, "type": "function" }, "__wrappers__.foo.Args": { @@ -1510,7 +1581,7 @@ }, "starkware.starknet.common.messages.send_message_to_l1": { "decorators": [], - "pc": 43, + "pc": 51, "type": "function" }, "starkware.starknet.common.messages.send_message_to_l1.Args": { @@ -1557,18 +1628,18 @@ "references": [ { "ap_tracking_data": { - "group": 6, + "group": 7, "offset": 0 }, - "pc": 43, + "pc": 51, "value": "[cast(fp + (-6), felt**)]" }, { "ap_tracking_data": { - "group": 6, + "group": 7, "offset": 1 }, - "pc": 49, + "pc": 57, "value": "cast([fp + (-6)] + 4, felt*)" } ], @@ -2484,7 +2555,7 @@ }, "starkware.starknet.common.syscalls.get_tx_info": { "decorators": [], - "pc": 36, + "pc": 44, "type": "function" }, "starkware.starknet.common.syscalls.get_tx_info.Args": { @@ -2515,6 +2586,68 @@ "starkware.starknet.common.syscalls.get_tx_info.syscall_ptr": { "cairo_type": "felt*", "full_name": "starkware.starknet.common.syscalls.get_tx_info.syscall_ptr", + "references": [ + { + "ap_tracking_data": { + "group": 6, + "offset": 0 + }, + "pc": 44, + "value": "[cast(fp + (-3), felt**)]" + }, + { + "ap_tracking_data": { + "group": 6, + "offset": 1 + }, + "pc": 47, + "value": "cast([fp + (-3)] + 2, felt*)" + } + ], + "type": "reference" + }, + "starkware.starknet.common.syscalls.storage_write": { + "decorators": [], + "pc": 36, + "type": "function" + }, + "starkware.starknet.common.syscalls.storage_write.Args": { + "full_name": "starkware.starknet.common.syscalls.storage_write.Args", + "members": { + "address": { + "cairo_type": "felt", + "offset": 0 + }, + "value": { + "cairo_type": "felt", + "offset": 1 + } + }, + "size": 2, + "type": "struct" + }, + "starkware.starknet.common.syscalls.storage_write.ImplicitArgs": { + "full_name": "starkware.starknet.common.syscalls.storage_write.ImplicitArgs", + "members": { + "syscall_ptr": { + "cairo_type": "felt*", + "offset": 0 + } + }, + "size": 1, + "type": "struct" + }, + "starkware.starknet.common.syscalls.storage_write.Return": { + "cairo_type": "()", + "type": "type_definition" + }, + "starkware.starknet.common.syscalls.storage_write.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "starkware.starknet.common.syscalls.storage_write.syscall_ptr": { + "cairo_type": "felt*", + "full_name": "starkware.starknet.common.syscalls.storage_write.syscall_ptr", "references": [ { "ap_tracking_data": { @@ -2522,15 +2655,15 @@ "offset": 0 }, "pc": 36, - "value": "[cast(fp + (-3), felt**)]" + "value": "[cast(fp + (-5), felt**)]" }, { "ap_tracking_data": { "group": 5, "offset": 1 }, - "pc": 39, - "value": "cast([fp + (-3)] + 2, felt*)" + "pc": 41, + "value": "cast([fp + (-5)] + 3, felt*)" } ], "type": "reference" @@ -2578,14 +2711,22 @@ "offset": 0 }, "pc": 36, - "value": "[cast(fp + (-3), felt**)]" + "value": "[cast(fp + (-5), felt**)]" }, { "ap_tracking_data": { "group": 6, "offset": 0 }, - "pc": 43, + "pc": 44, + "value": "[cast(fp + (-3), felt**)]" + }, + { + "ap_tracking_data": { + "group": 7, + "offset": 0 + }, + "pc": 51, "value": "[cast(fp + (-6), felt**)]" } ] diff --git a/crates/blockifier/feature_contracts/cairo0/compiled/account_with_dummy_validate_compiled.json b/crates/blockifier_test_utils/resources/feature_contracts/cairo0/compiled/account_with_dummy_validate_compiled.json similarity index 100% rename from crates/blockifier/feature_contracts/cairo0/compiled/account_with_dummy_validate_compiled.json rename to crates/blockifier_test_utils/resources/feature_contracts/cairo0/compiled/account_with_dummy_validate_compiled.json diff --git a/crates/blockifier/feature_contracts/cairo0/compiled/account_with_long_validate_compiled.json b/crates/blockifier_test_utils/resources/feature_contracts/cairo0/compiled/account_with_long_validate_compiled.json similarity index 100% rename from crates/blockifier/feature_contracts/cairo0/compiled/account_with_long_validate_compiled.json rename to crates/blockifier_test_utils/resources/feature_contracts/cairo0/compiled/account_with_long_validate_compiled.json diff --git a/crates/blockifier/feature_contracts/cairo0/compiled/empty_contract_compiled.json b/crates/blockifier_test_utils/resources/feature_contracts/cairo0/compiled/empty_contract_compiled.json similarity index 100% rename from crates/blockifier/feature_contracts/cairo0/compiled/empty_contract_compiled.json rename to crates/blockifier_test_utils/resources/feature_contracts/cairo0/compiled/empty_contract_compiled.json diff --git a/crates/blockifier/feature_contracts/cairo0/compiled/security_tests_contract_compiled.json b/crates/blockifier_test_utils/resources/feature_contracts/cairo0/compiled/security_tests_contract_compiled.json similarity index 100% rename from crates/blockifier/feature_contracts/cairo0/compiled/security_tests_contract_compiled.json rename to crates/blockifier_test_utils/resources/feature_contracts/cairo0/compiled/security_tests_contract_compiled.json diff --git a/crates/blockifier/feature_contracts/cairo0/compiled/test_contract_compiled.json b/crates/blockifier_test_utils/resources/feature_contracts/cairo0/compiled/test_contract_compiled.json similarity index 100% rename from crates/blockifier/feature_contracts/cairo0/compiled/test_contract_compiled.json rename to crates/blockifier_test_utils/resources/feature_contracts/cairo0/compiled/test_contract_compiled.json diff --git a/crates/blockifier/feature_contracts/cairo0/empty_contract.cairo b/crates/blockifier_test_utils/resources/feature_contracts/cairo0/empty_contract.cairo similarity index 100% rename from crates/blockifier/feature_contracts/cairo0/empty_contract.cairo rename to crates/blockifier_test_utils/resources/feature_contracts/cairo0/empty_contract.cairo diff --git a/crates/blockifier/feature_contracts/cairo0/security_tests_contract.cairo b/crates/blockifier_test_utils/resources/feature_contracts/cairo0/security_tests_contract.cairo similarity index 100% rename from crates/blockifier/feature_contracts/cairo0/security_tests_contract.cairo rename to crates/blockifier_test_utils/resources/feature_contracts/cairo0/security_tests_contract.cairo diff --git a/crates/blockifier/feature_contracts/cairo0/test_contract.cairo b/crates/blockifier_test_utils/resources/feature_contracts/cairo0/test_contract.cairo similarity index 100% rename from crates/blockifier/feature_contracts/cairo0/test_contract.cairo rename to crates/blockifier_test_utils/resources/feature_contracts/cairo0/test_contract.cairo diff --git a/crates/blockifier/feature_contracts/cairo1/account_faulty.cairo b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/account_faulty.cairo similarity index 83% rename from crates/blockifier/feature_contracts/cairo1/account_faulty.cairo rename to crates/blockifier_test_utils/resources/feature_contracts/cairo1/account_faulty.cairo index 76e9b1e6b4f..dda81581527 100644 --- a/crates/blockifier/feature_contracts/cairo1/account_faulty.cairo +++ b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/account_faulty.cairo @@ -26,12 +26,16 @@ mod Account { const GET_BLOCK_HASH: felt252 = 3; // Use get_execution_info syscall. const GET_EXECUTION_INFO: felt252 = 4; + // Write to the storage. + const STORAGE_WRITE: felt252 = 8; // get_selector_from_name('foo'). const FOO_ENTRY_POINT_SELECTOR: felt252 = ( 0x1b1a0649752af1b28b3dc29a1556eee781e4a4c3a1f7f53f90fa834de098c4d ); + const STORAGE_WRITE_KEY: felt252 = 15; + #[storage] struct Storage { } @@ -80,6 +84,18 @@ mod Account { selector: felt252, calldata: Array ) -> felt252 { + let tx_info = starknet::get_tx_info().unbox(); + let signature = tx_info.signature; + let scenario = *signature[0_u32]; + + if (scenario == STORAGE_WRITE) { + let key = STORAGE_WRITE_KEY.try_into().unwrap(); + let value: felt252 = *signature[2_u32]; + starknet::syscalls::storage_write_syscall(0, key, value).unwrap_syscall(); + + return starknet::VALIDATED; + } + let to_address = 0; send_message_to_l1_syscall( @@ -124,11 +140,18 @@ mod Account { return starknet::VALIDATED; } if (scenario == GET_BLOCK_HASH){ - let block_number: u64 = 0; + let block_number: u64 = 1992; get_block_hash_syscall(block_number).unwrap_syscall(); return starknet::VALIDATED; } + if (scenario == STORAGE_WRITE) { + let key = STORAGE_WRITE_KEY.try_into().unwrap(); + let value: felt252 = *signature[1_u32]; + starknet::syscalls::storage_write_syscall(0, key, value).unwrap_syscall(); + return starknet::VALIDATED; + } + assert (scenario == GET_EXECUTION_INFO, 'Unknown scenario'); let block_number: felt252 = *signature[1_u32]; diff --git a/crates/blockifier/feature_contracts/cairo1/account_with_dummy_validate.cairo b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/account_with_dummy_validate.cairo similarity index 100% rename from crates/blockifier/feature_contracts/cairo1/account_with_dummy_validate.cairo rename to crates/blockifier_test_utils/resources/feature_contracts/cairo1/account_with_dummy_validate.cairo diff --git a/crates/blockifier/feature_contracts/cairo1/account_with_long_validate.cairo b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/account_with_long_validate.cairo similarity index 100% rename from crates/blockifier/feature_contracts/cairo1/account_with_long_validate.cairo rename to crates/blockifier_test_utils/resources/feature_contracts/cairo1/account_with_long_validate.cairo diff --git a/crates/blockifier/feature_contracts/cairo1/cairo_steps_test_contract.cairo b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/cairo_steps_test_contract.cairo similarity index 100% rename from crates/blockifier/feature_contracts/cairo1/cairo_steps_test_contract.cairo rename to crates/blockifier_test_utils/resources/feature_contracts/cairo1/cairo_steps_test_contract.cairo diff --git a/crates/blockifier/feature_contracts/cairo1/compiled/account_faulty.casm.json b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/compiled/account_faulty.casm.json similarity index 69% rename from crates/blockifier/feature_contracts/cairo1/compiled/account_faulty.casm.json rename to crates/blockifier_test_utils/resources/feature_contracts/cairo1/compiled/account_faulty.casm.json index f7f13f02751..eb33c788b0e 100644 --- a/crates/blockifier/feature_contracts/cairo1/compiled/account_faulty.casm.json +++ b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/compiled/account_faulty.casm.json @@ -1,6 +1,6 @@ { "prime": "0x800000000000011000000000000000000000000000000000000000000000001", - "compiler_version": "2.9.0", + "compiler_version": "2.11.0", "bytecode": [ "0xa0680017fff8000", "0x7", @@ -8,32 +8,36 @@ "0x100000000000000000000000000000000", "0x400280007ff97fff", "0x10780017fff7fff", - "0x6c", + "0x73", "0x4825800180007ffa", "0x0", "0x400280007ff97fff", "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0x1a04", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x54", + "0x58", "0x482680017ffc8000", "0x1", "0x480a7ffd7fff8000", - "0x48307ffe80007fff", + "0x48127ffc7fff8000", + "0x48307ffd80007ffe", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ff97fff8000", "0x48127ff77fff8000", + "0x482480017ffb8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -42,28 +46,29 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x684", + "0x84d", "0x482480017fff8000", - "0x683", - "0x480080007fff8000", + "0x84c", + "0x48127ffb7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007ff5", - "0x55a0", + "0x4824800180007ffd", + "0x7472", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007ff47fff", + "0x400080007ff17fff", "0x10780017fff7fff", - "0x21", - "0x4824800180007ff5", - "0x55a0", - "0x400080007ff57fff", - "0x482480017ff58000", + "0x22", + "0x4824800180007ffd", + "0x7472", + "0x400080007ff27fff", + "0x482480017ff28000", "0x1", "0x48127ffe7fff8000", "0x480a7ffb7fff8000", "0x1104800180018000", - "0x439", + "0x492", "0x20680017fff7ffd", "0xe", "0x40780017fff7fff", @@ -79,7 +84,8 @@ "0x1", "0x208b7fff7fff7ffe", "0x48127ffa7fff8000", - "0x48127ffa7fff8000", + "0x482480017ffa8000", + "0xc8", "0x48127ffa7fff8000", "0x480680017fff8000", "0x1", @@ -91,9 +97,9 @@ "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482480017ff28000", + "0x482480017fef8000", "0x1", - "0x48127ff07fff8000", + "0x48127ff87fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -106,8 +112,9 @@ "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202331", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127ffa7fff8000", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x622", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -122,7 +129,8 @@ "0x400080007ffe7fff", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x21b6", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -136,57 +144,66 @@ "0x100000000000000000000000000000000", "0x400280007ff97fff", "0x10780017fff7fff", - "0xbe", + "0xd1", "0x4825800180007ffa", "0x0", "0x400280007ff97fff", "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0x1428", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa6", + "0xb6", "0x482680017ffc8000", "0x1", "0x480a7ffd7fff8000", - "0x48307ffe80007fff", + "0x48127ffc7fff8000", + "0x48307ffd80007ffe", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x90", - "0x482480017ffd8000", + "0x9e", + "0x482480017ffc8000", "0x1", - "0x48127ffd7fff8000", - "0x48307ffe80007fff", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", + "0x48307ffd80007ffe", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x7a", - "0x480080007ffd8000", - "0x482480017ffc8000", + "0x86", + "0x480080007ffc8000", + "0x482480017ffb8000", "0x1", - "0x48127ffc7fff8000", - "0x20680017fff7ffd", - "0x6", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x20680017fff7ffc", + "0x7", + "0x48127fff7fff8000", "0x480680017fff8000", "0x1", "0x10780017fff7fff", - "0x4", + "0x6", + "0x482480017fff8000", + "0x64", "0x480680017fff8000", "0x0", - "0x48307ffd80007ffe", + "0x48307ffb80007ffc", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ff17fff8000", - "0x48127fef7fff8000", + "0x48127fec7fff8000", + "0x482480017ffa8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -195,53 +212,59 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x5eb", + "0x7a7", "0x482480017fff8000", - "0x5ea", - "0x480080007fff8000", + "0x7a6", + "0x48127ffa7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007fed", - "0x5f64", + "0x4824800180007ffd", + "0x7a4e", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007fec7fff", + "0x400080007fe67fff", "0x10780017fff7fff", - "0x3e", - "0x4824800180007fed", - "0x5f64", - "0x400080007fed7fff", + "0x44", + "0x4824800180007ffd", + "0x7a4e", + "0x400080007fe77fff", "0x480680017fff8000", "0x1", - "0x48307ff780007fff", - "0x482480017feb8000", + "0x48307ff680007fff", + "0x482480017fe58000", "0x1", + "0x48127ffc7fff8000", "0x480680017fff8000", "0x0", - "0x20680017fff7ffd", - "0x7", + "0x20680017fff7ffc", + "0x8", "0x480680017fff8000", "0x1", - "0x48307ffe80007fff", + "0x48127ffd7fff8000", + "0x48307ffd80007ffe", "0x10780017fff7fff", - "0x5", + "0x7", "0x40780017fff7fff", "0x1", - "0x48127ffe7fff8000", + "0x482480017ffd8000", + "0x5a", + "0x48127ffd7fff8000", "0x20680017fff7fff", - "0x9", - "0x48127ffc7fff8000", - "0x48127ff87fff8000", + "0xa", + "0x48127ffa7fff8000", + "0x482480017ffd8000", + "0x753a", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x56414c4944", "0x10780017fff7fff", "0xd", - "0x48127ffc7fff8000", - "0x48127ff87fff8000", + "0x48127ffa7fff8000", + "0x48127ffd7fff8000", "0x480a7ffb7fff8000", "0x1104800180018000", - "0x387", + "0x3ce", "0x20680017fff7ffd", "0x12", "0x48127ffa7fff8000", @@ -261,7 +284,8 @@ "0x1", "0x208b7fff7fff7ffe", "0x48127ffa7fff8000", - "0x48127ffa7fff8000", + "0x482480017ffa8000", + "0x258", "0x48127ffa7fff8000", "0x480680017fff8000", "0x1", @@ -273,9 +297,9 @@ "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482480017fea8000", + "0x482480017fe48000", "0x1", - "0x48127fe87fff8000", + "0x48127ff87fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -288,8 +312,9 @@ "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202333", "0x400080007ffe7fff", - "0x48127ff67fff8000", - "0x48127ff47fff8000", + "0x48127ff37fff8000", + "0x482480017ffb8000", + "0x816", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -302,8 +327,9 @@ "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202332", "0x400080007ffe7fff", - "0x48127ff97fff8000", "0x48127ff77fff8000", + "0x482480017ffb8000", + "0xa0a", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -316,8 +342,9 @@ "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202331", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127ffa7fff8000", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0xbfe", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -332,7 +359,8 @@ "0x400080007ffe7fff", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x21b6", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -346,17 +374,20 @@ "0x100000000000000000000000000000000", "0x400280007ff97fff", "0x10780017fff7fff", - "0x109", + "0x121", "0x4825800180007ffa", "0x0", "0x400280007ff97fff", "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0x2a8", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", + "0xb", + "0x48127ffe7fff8000", "0x482680017ffc8000", "0x1", "0x480a7ffd7fff8000", @@ -364,7 +395,8 @@ "0x0", "0x480280007ffc8000", "0x10780017fff7fff", - "0x8", + "0x9", + "0x48127ffe7fff8000", "0x480a7ffc7fff8000", "0x480a7ffd7fff8000", "0x480680017fff8000", @@ -372,87 +404,95 @@ "0x480680017fff8000", "0x0", "0x20680017fff7ffe", - "0xde", + "0xf2", + "0x48127ffb7fff8000", "0xa0680017fff8004", "0xe", - "0x4824800180047ffe", + "0x4824800180047ffd", "0x800000000000000000000000000000000000000000000000000000000000000", "0x484480017ffe8000", "0x110000000000000000", "0x48307ffe7fff8002", - "0x480080007ff67ffc", - "0x480080017ff57ffc", + "0x480080007ff37ffc", + "0x480080017ff27ffc", "0x402480017ffb7ffd", "0xffffffffffffffeeffffffffffffffff", - "0x400080027ff47ffd", + "0x400080027ff17ffd", "0x10780017fff7fff", - "0xcc", + "0xdd", "0x484480017fff8001", "0x8000000000000000000000000000000", - "0x48307fff80007ffd", - "0x480080007ff77ffd", - "0x480080017ff67ffd", + "0x48307fff80007ffc", + "0x480080007ff47ffd", + "0x480080017ff37ffd", "0x402480017ffc7ffe", "0xf8000000000000000000000000000000", - "0x400080027ff57ffe", - "0x482480017ff58000", + "0x400080027ff27ffe", + "0x482480017ff28000", "0x3", - "0x48307ff680007ff7", + "0x48127ff97fff8000", + "0x48307ff480007ff5", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xaf", - "0x482480017ff58000", + "0xbe", + "0x482480017ff38000", "0x1", - "0x48127ff57fff8000", - "0x48307ffe80007fff", + "0x48127ff37fff8000", + "0x48127ffc7fff8000", + "0x48307ffd80007ffe", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", - "0x482480017ffd8000", + "0xb", + "0x48127ffe7fff8000", + "0x482480017ffb8000", "0x1", - "0x48127ffd7fff8000", + "0x48127ffb7fff8000", "0x480680017fff8000", "0x0", - "0x48127ffa7fff8000", + "0x48127ff87fff8000", "0x10780017fff7fff", - "0x8", - "0x48127ffd7fff8000", - "0x48127ffd7fff8000", + "0x9", + "0x48127ffe7fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", "0x480680017fff8000", "0x1", "0x480680017fff8000", "0x0", "0x20680017fff7ffe", - "0x87", + "0x92", "0x40780017fff7fff", "0x1", - "0x48127ff67fff8000", - "0x48127fe97fff8000", + "0x48127ff37fff8000", + "0x48127ff97fff8000", "0x48127ff97fff8000", "0x48127ff97fff8000", "0x48127ffb7fff8000", "0x48127ffa7fff8000", "0x480080007ff88000", "0x1104800180018000", - "0x49e", + "0x56e", "0x20680017fff7ffa", - "0x72", - "0x20680017fff7ffd", - "0x6c", - "0x48307ffb80007ffc", + "0x7c", + "0x48127ff97fff8000", + "0x20680017fff7ffc", + "0x74", + "0x48127fff7fff8000", + "0x48307ff980007ffa", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ff57fff8000", - "0x48127ff57fff8000", + "0x48127ff37fff8000", + "0x482480017ffb8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -461,49 +501,53 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x4e1", + "0x686", "0x482480017fff8000", - "0x4e0", - "0x480080007fff8000", + "0x685", + "0x48127ffb7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007ff3", - "0x972c", + "0x4824800180007ffd", + "0xa1c2", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007ff07fff", + "0x400080007fed7fff", "0x10780017fff7fff", - "0x3c", - "0x4824800180007ff3", - "0x972c", - "0x400080007ff17fff", + "0x41", + "0x4824800180007ffd", + "0xa1c2", + "0x400080007fee7fff", + "0x48127fff7fff8000", "0x480680017fff8000", "0x0", - "0x482480017ff08000", + "0x482480017fec8000", "0x1", "0x480680017fff8000", "0x53656e644d657373616765546f4c31", "0x400280007ffb7fff", "0x400280017ffb7ffc", "0x400280027ffb7ffd", - "0x400280037ffb7ff4", - "0x400280047ffb7ff5", + "0x400280037ffb7ff0", + "0x400280047ffb7ff1", "0x480280067ffb8000", "0x20680017fff7fff", - "0x1d", - "0x48127ffd7fff8000", + "0x1f", "0x480280057ffb8000", + "0x48127ffc7fff8000", + "0x48127ffe7fff8000", "0x482680017ffb8000", "0x7", "0x1104800180018000", - "0x288", + "0x2bb", "0x20680017fff7ffd", - "0xe", + "0xf", "0x40780017fff7fff", "0x1", "0x400080007fff7ffe", "0x48127ff97fff8000", - "0x48127ff97fff8000", + "0x482480017ff98000", + "0x190", "0x48127ff97fff8000", "0x480680017fff8000", "0x0", @@ -517,9 +561,11 @@ "0x48127ffb7fff8000", "0x48127ffb7fff8000", "0x10780017fff7fff", - "0x8", - "0x48127ffd7fff8000", + "0xa", "0x480280057ffb8000", + "0x48127ffc7fff8000", + "0x482480017ffe8000", + "0x7602", "0x482680017ffb8000", "0x9", "0x480280077ffb8000", @@ -537,9 +583,9 @@ "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482480017fee8000", + "0x482480017feb8000", "0x1", - "0x48127fee7fff8000", + "0x48127ff87fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -547,20 +593,23 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x48127ff87fff8000", - "0x48127ff87fff8000", + "0x48127ff77fff8000", + "0x482480017ffe8000", + "0x492", "0x10780017fff7fff", - "0xc", - "0x48127ff87fff8000", + "0xe", "0x48127ff87fff8000", + "0x482480017ff88000", + "0x7b2", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", "0x48127ffa7fff8000", "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", - "0x48127ff77fff8000", - "0x48127fea7fff8000", + "0x48127ff47fff8000", + "0x482480017ffa8000", + "0x102c", "0x40780017fff7fff", "0x1", "0x480680017fff8000", @@ -580,8 +629,9 @@ "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202332", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127fef7fff8000", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x1540", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -589,20 +639,22 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x482480017ff48000", + "0x482480017ff18000", "0x3", + "0x482480017ff88000", + "0x1540", "0x10780017fff7fff", "0x5", - "0x40780017fff7fff", - "0x6", - "0x48127ff47fff8000", + "0x48127ff87fff8000", + "0x482480017ffa8000", + "0x1a5e", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202331", "0x400080007ffe7fff", - "0x48127ffd7fff8000", - "0x48127fef7fff8000", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -617,7 +669,8 @@ "0x400080007ffe7fff", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x21b6", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -625,23 +678,28 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x2", "0xa0680017fff8000", "0x7", "0x482680017ffa8000", "0x100000000000000000000000000000000", "0x400280007ff97fff", "0x10780017fff7fff", - "0xf8", + "0x108", "0x4825800180007ffa", "0x0", "0x400280007ff97fff", "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0x17c", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", + "0xb", + "0x48127ffe7fff8000", "0x482680017ffc8000", "0x1", "0x480a7ffd7fff8000", @@ -649,7 +707,8 @@ "0x0", "0x480280007ffc8000", "0x10780017fff7fff", - "0x8", + "0x9", + "0x48127ffe7fff8000", "0x480a7ffc7fff8000", "0x480a7ffd7fff8000", "0x480680017fff8000", @@ -657,87 +716,97 @@ "0x480680017fff8000", "0x0", "0x20680017fff7ffe", - "0xcd", + "0xd9", + "0x40137fff7fff8001", + "0x48127ffb7fff8000", "0xa0680017fff8004", "0xe", - "0x4824800180047ffe", + "0x4825800180048001", "0x800000000000000000000000000000000000000000000000000000000000000", "0x484480017ffe8000", "0x110000000000000000", "0x48307ffe7fff8002", - "0x480080007ff67ffc", - "0x480080017ff57ffc", + "0x480080007ff37ffc", + "0x480080017ff27ffc", "0x402480017ffb7ffd", "0xffffffffffffffeeffffffffffffffff", - "0x400080027ff47ffd", + "0x400080027ff17ffd", "0x10780017fff7fff", - "0xbb", + "0xc3", "0x484480017fff8001", "0x8000000000000000000000000000000", - "0x48307fff80007ffd", - "0x480080007ff77ffd", - "0x480080017ff67ffd", + "0x48317fff80008001", + "0x480080007ff47ffd", + "0x480080017ff37ffd", "0x402480017ffc7ffe", "0xf8000000000000000000000000000000", - "0x400080027ff57ffe", - "0x482480017ff58000", + "0x400080027ff27ffe", + "0x482480017ff28000", "0x3", - "0x48307ff680007ff7", + "0x48127ff97fff8000", + "0x48307ff480007ff5", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x9e", - "0x482480017ff58000", + "0xa4", + "0x400180007ff38000", + "0x482480017ff38000", "0x1", - "0x48127ff57fff8000", - "0x48307ffe80007fff", + "0x48127ff37fff8000", + "0x48127ffc7fff8000", + "0x48307ffd80007ffe", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", - "0x482480017ffd8000", + "0xb", + "0x48127ffe7fff8000", + "0x482480017ffb8000", "0x1", - "0x48127ffd7fff8000", + "0x48127ffb7fff8000", "0x480680017fff8000", "0x0", - "0x48127ffa7fff8000", + "0x48127ff87fff8000", "0x10780017fff7fff", - "0x8", - "0x48127ffd7fff8000", - "0x48127ffd7fff8000", + "0x9", + "0x48127ffe7fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", "0x480680017fff8000", "0x1", "0x480680017fff8000", "0x0", "0x20680017fff7ffe", - "0x76", + "0x77", "0x40780017fff7fff", "0x1", - "0x48127ff67fff8000", - "0x48127fe97fff8000", + "0x48127ff37fff8000", + "0x48127ff97fff8000", "0x48127ff97fff8000", "0x48127ff97fff8000", "0x48127ffb7fff8000", "0x48127ffa7fff8000", "0x480080007ff88000", "0x1104800180018000", - "0x381", + "0x434", "0x20680017fff7ffa", "0x61", - "0x20680017fff7ffd", - "0x5b", - "0x48307ffb80007ffc", + "0x48127ff97fff8000", + "0x20680017fff7ffc", + "0x59", + "0x48127fff7fff8000", + "0x48307ff980007ffa", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ff57fff8000", - "0x48127ff57fff8000", + "0x48127ff37fff8000", + "0x482480017ffb8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -746,68 +815,64 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x3c4", + "0x54c", "0x482480017fff8000", - "0x3c3", - "0x480080007fff8000", + "0x54b", + "0x48127ffb7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007ff3", - "0x2404", + "0x4824800180007ffd", + "0x67d4", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007ff07fff", + "0x400080007fed7fff", "0x10780017fff7fff", - "0x2b", - "0x4824800180007ff3", - "0x2404", - "0x400080007ff17fff", - "0x480680017fff8000", - "0x0", - "0x482480017ff08000", + "0x26", + "0x4824800180007ffd", + "0x67d4", + "0x400080007fee7fff", + "0x482480017fee8000", "0x1", - "0x480680017fff8000", - "0x53656e644d657373616765546f4c31", - "0x400280007ffb7fff", - "0x400280017ffb7ffc", - "0x400280027ffb7ffd", - "0x400280037ffb7ff4", - "0x400280047ffb7ff5", - "0x480280067ffb8000", - "0x20680017fff7fff", - "0x11", + "0x48127ffe7fff8000", + "0x480a7ffb7fff8000", + "0x480a80017fff8000", + "0x480a80007fff8000", + "0x48127fef7fff8000", + "0x48127fef7fff8000", + "0x1104800180018000", + "0x460", + "0x20680017fff7ffd", + "0xe", "0x40780017fff7fff", "0x1", + "0x400080007fff7ffe", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x48127ff97fff8000", "0x480680017fff8000", - "0x56414c4944", - "0x400080007ffe7fff", + "0x0", "0x48127ffb7fff8000", - "0x480280057ffb8000", - "0x482680017ffb8000", - "0x7", - "0x480680017fff8000", - "0x0", - "0x48127ffa7fff8000", - "0x482480017ff98000", + "0x482480017ffa8000", "0x1", "0x208b7fff7fff7ffe", - "0x48127ffd7fff8000", - "0x480280057ffb8000", - "0x482680017ffb8000", - "0x9", + "0x48127ffa7fff8000", + "0x482480017ffa8000", + "0xc8", + "0x48127ffa7fff8000", "0x480680017fff8000", "0x1", - "0x480280077ffb8000", - "0x480280087ffb8000", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482480017fee8000", + "0x482480017feb8000", "0x1", - "0x48127fee7fff8000", + "0x48127ff87fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -815,20 +880,23 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x48127ff87fff8000", - "0x48127ff87fff8000", + "0x48127ff77fff8000", + "0x482480017ffe8000", + "0x492", "0x10780017fff7fff", - "0xc", - "0x48127ff87fff8000", + "0xe", "0x48127ff87fff8000", + "0x482480017ff88000", + "0x7b2", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", "0x48127ffa7fff8000", "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", - "0x48127ff77fff8000", - "0x48127fea7fff8000", + "0x48127ff47fff8000", + "0x482480017ffa8000", + "0x102c", "0x40780017fff7fff", "0x1", "0x480680017fff8000", @@ -848,8 +916,9 @@ "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202332", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127fef7fff8000", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x159a", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -857,20 +926,22 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x482480017ff48000", + "0x482480017ff18000", "0x3", + "0x482480017ff88000", + "0x159a", "0x10780017fff7fff", "0x5", - "0x40780017fff7fff", - "0x6", - "0x48127ff47fff8000", + "0x48127ff87fff8000", + "0x482480017ffa8000", + "0x1b12", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202331", "0x400080007ffe7fff", - "0x48127ffd7fff8000", - "0x48127fef7fff8000", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -885,7 +956,8 @@ "0x400080007ffe7fff", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x213e", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -899,24 +971,27 @@ "0x100000000000000000000000000000000", "0x400280007ff97fff", "0x10780017fff7fff", - "0x45", + "0x4a", "0x4825800180007ffa", "0x0", "0x400280007ff97fff", "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0x1bf8", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127ffa7fff8000", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -925,27 +1000,29 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x311", + "0x493", "0x482480017fff8000", - "0x310", - "0x480080007fff8000", + "0x492", + "0x48127ffb7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007ff8", + "0x4824800180007ffd", "0x0", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007ff77fff", + "0x400080007ff57fff", "0x10780017fff7fff", - "0x10", - "0x4824800180007ff8", + "0x11", + "0x4824800180007ffd", "0x0", - "0x400080007ff87fff", + "0x400080007ff67fff", "0x40780017fff7fff", "0x1", - "0x482480017ff78000", + "0x482480017ff58000", "0x1", - "0x48127ffd7fff8000", + "0x482480017ffd8000", + "0x190", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x0", @@ -957,9 +1034,9 @@ "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482480017ff58000", + "0x482480017ff38000", "0x1", - "0x48127ff37fff8000", + "0x48127ff87fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -974,7 +1051,8 @@ "0x400080007ffe7fff", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x21b6", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -988,41 +1066,48 @@ "0x100000000000000000000000000000000", "0x400280007ff97fff", "0x10780017fff7fff", - "0x8d", + "0x9c", "0x4825800180007ffa", "0x0", "0x400280007ff97fff", "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0x1810", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x75", + "0x81", "0x480280007ffc8000", "0x482680017ffc8000", "0x1", "0x480a7ffd7fff8000", - "0x20680017fff7ffd", - "0x6", + "0x48127ffb7fff8000", + "0x20680017fff7ffc", + "0x7", + "0x48127fff7fff8000", "0x480680017fff8000", "0x1", "0x10780017fff7fff", - "0x4", + "0x6", + "0x482480017fff8000", + "0x64", "0x480680017fff8000", "0x0", - "0x48307ffd80007ffe", + "0x48307ffb80007ffc", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ff77fff8000", - "0x48127ff57fff8000", + "0x48127ff47fff8000", + "0x482480017ffa8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -1031,51 +1116,57 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x2a7", + "0x41f", "0x482480017fff8000", - "0x2a6", - "0x480080007fff8000", + "0x41e", + "0x48127ffa7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007ff3", - "0x5b7c", + "0x4824800180007ffd", + "0x7986", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007ff27fff", + "0x400080007fee7fff", "0x10780017fff7fff", - "0x39", - "0x4824800180007ff3", - "0x5b7c", - "0x400080007ff37fff", + "0x3f", + "0x4824800180007ffd", + "0x7986", + "0x400080007fef7fff", "0x480680017fff8000", "0x1", - "0x48307ff780007fff", - "0x482480017ff18000", + "0x48307ff680007fff", + "0x482480017fed8000", "0x1", + "0x48127ffc7fff8000", "0x480680017fff8000", "0x1", - "0x20680017fff7ffd", - "0x7", + "0x20680017fff7ffc", + "0x8", "0x480680017fff8000", "0x1", - "0x48307ffe80007fff", + "0x48127ffd7fff8000", + "0x48307ffd80007ffe", "0x10780017fff7fff", - "0x5", + "0x7", "0x40780017fff7fff", "0x1", - "0x48127ffe7fff8000", + "0x482480017ffd8000", + "0x5a", + "0x48127ffd7fff8000", "0x20680017fff7fff", - "0x7", - "0x48127ffc7fff8000", - "0x48127ff87fff8000", + "0x8", + "0x48127ffa7fff8000", + "0x482480017ffd8000", + "0x753a", "0x480a7ffb7fff8000", "0x10780017fff7fff", "0xc", - "0x48127ffc7fff8000", - "0x48127ff87fff8000", + "0x48127ffa7fff8000", + "0x48127ffd7fff8000", "0x480a7ffb7fff8000", "0x1104800180018000", - "0x45", + "0x48", "0x20680017fff7ffd", "0xf", "0x48127ffa7fff8000", @@ -1092,7 +1183,8 @@ "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", "0x48127ffa7fff8000", - "0x48127ffa7fff8000", + "0x482480017ffa8000", + "0x190", "0x48127ffa7fff8000", "0x480680017fff8000", "0x1", @@ -1104,9 +1196,9 @@ "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482480017ff08000", + "0x482480017fec8000", "0x1", - "0x48127fee7fff8000", + "0x48127ff87fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -1119,8 +1211,9 @@ "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202331", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127ffa7fff8000", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x816", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -1135,7 +1228,8 @@ "0x400080007ffe7fff", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x21b6", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -1149,40 +1243,32 @@ "0x400380017ffd7ffc", "0x480280037ffd8000", "0x20680017fff7fff", - "0x1ca", + "0x25f", + "0x480280027ffd8000", "0x480280047ffd8000", "0x480080017fff8000", "0x480080037fff8000", "0x480080047ffe8000", - "0x480680017fff8000", - "0x0", - "0x480280027ffd8000", "0x482680017ffd8000", "0x5", - "0x480080037ffa8000", - "0x480080047ff98000", - "0x48307ff980007ffa", - "0xa0680017fff8000", - "0x6", - "0x48307ffe80007ff9", - "0x400280007ffb7fff", + "0x48127ffa7fff8000", + "0x480080037ffb8000", + "0x480080047ffa8000", + "0x48307ffa80007ffb", + "0x20680017fff7fff", + "0x4", "0x10780017fff7fff", - "0x1a7", - "0x482480017ff98000", - "0x1", - "0x48307fff80007ffd", - "0x400280007ffb7fff", - "0x48307ff77ff58000", - "0x480080007fff8000", - "0x482680017ffb8000", - "0x1", + "0x23f", + "0x480080007ff98000", + "0x48127ffb7fff8000", "0x20680017fff7ffe", - "0xe", + "0xf", "0x40780017fff7fff", - "0x28", - "0x48127fd77fff8000", - "0x48127fcc7fff8000", - "0x48127fcc7fff8000", + "0x35", + "0x480a7ffb7fff8000", + "0x482480017fc98000", + "0x3ffc", + "0x48127fc27fff8000", "0x480680017fff8000", "0x0", "0x480680017fff8000", @@ -1192,21 +1278,25 @@ "0x208b7fff7fff7ffe", "0x4824800180007ffe", "0x1", - "0x20680017fff7fff", - "0x24", + "0x48127ffe7fff8000", + "0x20680017fff7ffe", + "0x27", "0x40780017fff7fff", - "0x23", + "0x2e", "0x480680017fff8000", "0x0", "0x4824800180007fff", "0x1", - "0x20680017fff7fff", - "0xe", + "0x482480017fcf8000", + "0x3c5a", + "0x20680017fff7ffe", + "0xf", "0x40780017fff7fff", "0x2", - "0x48127fd77fff8000", - "0x48127fcc7fff8000", - "0x48127fcc7fff8000", + "0x480a7ffb7fff8000", + "0x482480017ffc8000", + "0xb4", + "0x48127fc27fff8000", "0x480680017fff8000", "0x0", "0x480680017fff8000", @@ -1219,78 +1309,84 @@ "0x480680017fff8000", "0x496e76616c6964207363656e6172696f", "0x400080007ffe7fff", - "0x48127fd77fff8000", - "0x48127fcc7fff8000", - "0x48127fcc7fff8000", + "0x480a7ffb7fff8000", + "0x48127ffc7fff8000", + "0x48127fc27fff8000", "0x480680017fff8000", "0x1", "0x48127ffa7fff8000", "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x4824800180007ffd", + "0x4824800180007ffc", "0x2", - "0x20680017fff7fff", - "0x70", + "0x48127ffe7fff8000", + "0x20680017fff7ffe", + "0x78", "0x40780017fff7fff", - "0x15", + "0x1c", "0x480680017fff8000", "0x1", - "0x48307fdf80007fe0", + "0x482480017fe28000", + "0xa5a", + "0x48307fd980007fda", "0xa0680017fff8000", "0x6", - "0x48307ffe80007ffd", - "0x400080007fe47fff", + "0x48307ffe80007ffc", + "0x400280007ffb7fff", "0x10780017fff7fff", - "0x54", - "0x482480017ffd8000", + "0x59", + "0x482480017ffc8000", "0x1", "0x48307fff80007ffd", - "0x400080007fe37fff", - "0x48307ffb7fdb8000", + "0x400280007ffb7fff", + "0x48307ffa7fd58000", "0x40780017fff7fff", "0x1", "0x480080007ffe8000", + "0x48127ff87fff8000", "0xa0680017fff8004", "0xe", - "0x4824800180047ffe", + "0x4824800180047ffd", "0x800000000000000000000000000000000000000000000000000000000000000", "0x484480017ffe8000", "0x110000000000000000", "0x48307ffe7fff8002", - "0x480080017fdc7ffc", - "0x480080027fdb7ffc", + "0x480280017ffb7ffc", + "0x480280027ffb7ffc", "0x402480017ffb7ffd", "0xffffffffffffffeeffffffffffffffff", - "0x400080037fda7ffd", + "0x400280037ffb7ffd", "0x10780017fff7fff", - "0x2d", + "0x30", "0x484480017fff8001", "0x8000000000000000000000000000000", - "0x48307fff80007ffd", - "0x480080017fdd7ffd", - "0x480080027fdc7ffd", + "0x48307fff80007ffc", + "0x480280017ffb7ffd", + "0x480280027ffb7ffd", "0x402480017ffc7ffe", "0xf8000000000000000000000000000000", - "0x400080037fdb7ffe", + "0x400280037ffb7ffe", + "0x48127ffa7fff8000", "0x480680017fff8000", "0x1b1a0649752af1b28b3dc29a1556eee781e4a4c3a1f7f53f90fa834de098c4d", - "0x482480017fda8000", + "0x482680017ffb8000", "0x4", "0x480680017fff8000", "0x43616c6c436f6e7472616374", - "0x400080007fcf7fff", - "0x400080017fcf7fce", - "0x400080027fcf7ff7", - "0x400080037fcf7ffd", - "0x400080047fcf7ff6", - "0x400080057fcf7ff6", - "0x480080077fcf8000", + "0x400080007fc67fff", + "0x400080017fc67ffc", + "0x400080027fc67ff5", + "0x400080037fc67ffd", + "0x400080047fc67ff4", + "0x400080057fc67ff4", + "0x480080077fc68000", "0x20680017fff7fff", - "0xd", - "0x48127ffd7fff8000", - "0x480080067fcd8000", - "0x482480017fcc8000", + "0xe", + "0x480080067fc58000", + "0x48127ffc7fff8000", + "0x48127ffe7fff8000", + "0x482480017fc28000", "0xa", "0x480680017fff8000", "0x0", @@ -1299,26 +1395,28 @@ "0x480680017fff8000", "0x56414c4944", "0x208b7fff7fff7ffe", - "0x48127ffd7fff8000", - "0x480080067fcd8000", - "0x482480017fcc8000", + "0x480080067fc58000", + "0x48127ffc7fff8000", + "0x48127ffe7fff8000", + "0x482480017fc28000", "0xa", "0x480680017fff8000", "0x1", - "0x480080087fca8000", - "0x480080097fc98000", + "0x480080087fc08000", + "0x480080097fbf8000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0x1", + "0x3", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4f7074696f6e3a3a756e77726170206661696c65642e", "0x400080007ffe7fff", - "0x482480017fd78000", + "0x482680017ffb8000", "0x4", - "0x48127fcc7fff8000", - "0x48127fcc7fff8000", + "0x482480017ff38000", + "0x29ae", + "0x48127fc27fff8000", "0x480680017fff8000", "0x1", "0x48127ffa7fff8000", @@ -1326,41 +1424,46 @@ "0x1", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0xb", + "0xe", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e646578206f7574206f6620626f756e6473", "0x400080007ffe7fff", - "0x482480017fd78000", + "0x482680017ffb8000", "0x1", - "0x48127fcc7fff8000", - "0x48127fcc7fff8000", + "0x482480017feb8000", + "0x2f26", + "0x48127fc27fff8000", "0x480680017fff8000", "0x1", "0x48127ffa7fff8000", "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x4824800180007ffc", + "0x4824800180007ffa", "0x3", - "0x20680017fff7fff", - "0x22", + "0x48127ffe7fff8000", + "0x20680017fff7ffe", + "0x26", "0x40780017fff7fff", - "0x22", + "0x2a", + "0x482480017fd58000", + "0x1252", "0x480680017fff8000", - "0x0", + "0x7c8", "0x480680017fff8000", "0x476574426c6f636b48617368", - "0x400080007fcf7fff", - "0x400080017fcf7fce", - "0x400080027fcf7ffe", - "0x480080047fcf8000", + "0x400080007fc67fff", + "0x400080017fc67ffd", + "0x400080027fc67ffe", + "0x480080047fc68000", "0x20680017fff7fff", - "0xd", - "0x48127fd77fff8000", - "0x480080037fcd8000", - "0x482480017fcc8000", + "0xe", + "0x480080037fc58000", + "0x480a7ffb7fff8000", + "0x48127ffe7fff8000", + "0x482480017fc28000", "0x6", "0x480680017fff8000", "0x0", @@ -1369,95 +1472,227 @@ "0x480680017fff8000", "0x56414c4944", "0x208b7fff7fff7ffe", - "0x48127fd77fff8000", - "0x480080037fcd8000", - "0x482480017fcc8000", + "0x480080037fc58000", + "0x480a7ffb7fff8000", + "0x48127ffe7fff8000", + "0x482480017fc28000", "0x7", "0x480680017fff8000", "0x1", - "0x480080057fca8000", - "0x480080067fc98000", + "0x480080057fc08000", + "0x480080067fbf8000", "0x208b7fff7fff7ffe", - "0x4824800180007ffb", - "0x4", - "0x20680017fff7fff", - "0xc1", + "0x4824800180007ff8", + "0x8", + "0x48127ffe7fff8000", + "0x20680017fff7ffe", + "0x77", + "0x40780017fff7fff", + "0x18", "0x480680017fff8000", - "0x1", - "0x48307ff280007ff3", - "0xa0680017fff8000", - "0x6", - "0x48307ffe80007ffd", - "0x400080007ff77fff", + "0xf", + "0x482480017fe68000", + "0x88e", + "0xa0680017fff8004", + "0xe", + "0x4824800180047ffd", + "0x800000000000000000000000000000000000000000000000000000000000000", + "0x484480017ffe8000", + "0x110000000000000000", + "0x48307ffe7fff8002", + "0x480280007ffb7ffc", + "0x480280017ffb7ffc", + "0x402480017ffb7ffd", + "0xffffffffffffffeeffffffffffffffff", + "0x400280027ffb7ffd", "0x10780017fff7fff", - "0xa7", - "0x482480017ffd8000", - "0x1", - "0x48307fff80007ffd", - "0x400080007ff67fff", - "0x48307ffb7fee8000", + "0x51", + "0x484480017fff8001", + "0x8000000000000000000000000000000", + "0x48307fff80007ffc", + "0x480280007ffb7ffd", + "0x480280017ffb7ffd", + "0x402480017ffc7ffe", + "0xf8000000000000000000000000000000", + "0x400280027ffb7ffe", "0x480680017fff8000", - "0x2", - "0x480080007ffe8000", - "0x48307feb80007fec", - "0xa0680017fff8000", - "0x6", - "0x48307ffe80007ffc", - "0x400080017ff07fff", - "0x10780017fff7fff", - "0x87", - "0x482480017ffc8000", "0x1", - "0x48307fff80007ffd", - "0x400080017fef7fff", - "0x48307ffa7fe78000", - "0x480680017fff8000", - "0x3", - "0x480080007ffe8000", - "0x48307fe480007fe5", + "0x48127ff97fff8000", + "0x48307fd280007fd3", "0xa0680017fff8000", "0x6", "0x48307ffe80007ffc", - "0x400080027fe97fff", + "0x400280037ffb7fff", "0x10780017fff7fff", - "0x67", + "0x2d", "0x482480017ffc8000", "0x1", "0x48307fff80007ffd", - "0x400080027fe87fff", - "0x48307ffa7fe08000", - "0x482480017fe78000", - "0x3", - "0x480080007ffe8000", + "0x400280037ffb7fff", + "0x48307ffa7fce8000", + "0x48127ffa7fff8000", "0x480680017fff8000", - "0x476574457865637574696f6e496e666f", - "0x400080007fdb7fff", - "0x400080017fdb7fda", - "0x480080037fdb8000", + "0x0", + "0x480080007ffd8000", + "0x482680017ffb8000", + "0x4", + "0x480680017fff8000", + "0x53746f726167655772697465", + "0x400080007fc67fff", + "0x400080017fc67ffb", + "0x400080027fc67ffc", + "0x400080037fc67fed", + "0x400080047fc67ffd", + "0x480080067fc68000", "0x20680017fff7fff", - "0x4d", - "0x480080047fda8000", - "0x480080007fff8000", - "0x480080007fff8000", - "0x48307fec80007fff", - "0x480080027fd68000", - "0x482480017fd58000", + "0xe", + "0x480080057fc58000", + "0x48127ffc7fff8000", + "0x48127ffe7fff8000", + "0x482480017fc28000", + "0x7", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x56414c4944", + "0x208b7fff7fff7ffe", + "0x480080057fc58000", + "0x48127ffc7fff8000", + "0x48127ffe7fff8000", + "0x482480017fc28000", + "0x9", + "0x480680017fff8000", + "0x1", + "0x480080077fc08000", + "0x480080087fbf8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x7", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x496e646578206f7574206f6620626f756e6473", + "0x400080007ffe7fff", + "0x482680017ffb8000", + "0x4", + "0x482480017ff28000", + "0x2ab2", + "0x48127fc27fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0xb", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x400080007ffe7fff", + "0x482680017ffb8000", + "0x3", + "0x482480017feb8000", + "0x2cc4", + "0x48127fc27fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x4824800180007ff6", + "0x4", + "0x48127ffe7fff8000", + "0x20680017fff7ffe", + "0xd0", + "0x480680017fff8000", + "0x1", + "0x48127ffe7fff8000", + "0x48307fef80007ff0", + "0xa0680017fff8000", + "0x6", + "0x48307ffe80007ffc", + "0x400280007ffb7fff", + "0x10780017fff7fff", + "0xb4", + "0x482480017ffc8000", + "0x1", + "0x48307fff80007ffd", + "0x400280007ffb7fff", + "0x48307ffa7feb8000", + "0x480680017fff8000", + "0x2", + "0x48127ff97fff8000", + "0x480080007ffd8000", + "0x48307fe780007fe8", + "0xa0680017fff8000", + "0x6", + "0x48307ffe80007ffb", + "0x400280017ffb7fff", + "0x10780017fff7fff", + "0x92", + "0x482480017ffb8000", + "0x1", + "0x48307fff80007ffd", + "0x400280017ffb7fff", + "0x48307ff97fe38000", + "0x480680017fff8000", + "0x3", + "0x48127ff87fff8000", + "0x480080007ffd8000", + "0x48307fdf80007fe0", + "0xa0680017fff8000", + "0x6", + "0x48307ffe80007ffb", + "0x400280027ffb7fff", + "0x10780017fff7fff", + "0x70", + "0x482480017ffb8000", + "0x1", + "0x48307fff80007ffd", + "0x400280027ffb7fff", + "0x48307ff97fdb8000", + "0x48127ff97fff8000", + "0x482680017ffb8000", + "0x3", + "0x480080007ffd8000", + "0x480680017fff8000", + "0x476574457865637574696f6e496e666f", + "0x400080007fd47fff", + "0x400080017fd47ffc", + "0x480080037fd48000", + "0x20680017fff7fff", + "0x53", + "0x480080027fd38000", + "0x480080047fd28000", + "0x480080007fff8000", + "0x480080007fff8000", + "0x48307fe980007fff", + "0x482480017fce8000", "0x5", + "0x48127ffa7fff8000", "0x480080017ffb8000", "0x480080027ffa8000", "0x20680017fff7ffb", - "0x32", - "0x48307fee80007ffe", - "0x20680017fff7fff", - "0x1f", - "0x48307ff480007ffe", - "0x20680017fff7fff", - "0xe", + "0x36", + "0x48307fec80007ffe", + "0x48127ffc7fff8000", + "0x20680017fff7ffe", + "0x21", + "0x48307ff280007ffd", + "0x48127ffe7fff8000", + "0x20680017fff7ffe", + "0xf", "0x40780017fff7fff", "0x2", - "0x48127ff07fff8000", - "0x48127ff77fff8000", - "0x48127ff77fff8000", + "0x48127fed7fff8000", + "0x482480017ffc8000", + "0xb4", + "0x48127ff47fff8000", "0x480680017fff8000", "0x0", "0x480680017fff8000", @@ -1470,9 +1705,9 @@ "0x480680017fff8000", "0x53455155454e4345525f4d49534d41544348", "0x400080007ffe7fff", - "0x48127ff07fff8000", - "0x48127ff77fff8000", - "0x48127ff77fff8000", + "0x48127fed7fff8000", + "0x48127ffc7fff8000", + "0x48127ff47fff8000", "0x480680017fff8000", "0x1", "0x48127ffa7fff8000", @@ -1480,15 +1715,16 @@ "0x1", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0x1", + "0x2", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x424c4f434b5f54494d455354414d505f4d49534d41544348", "0x400080007ffe7fff", - "0x48127ff07fff8000", - "0x48127ff77fff8000", - "0x48127ff77fff8000", + "0x48127fed7fff8000", + "0x482480017ffa8000", + "0xb4", + "0x48127ff47fff8000", "0x480680017fff8000", "0x1", "0x48127ffa7fff8000", @@ -1496,15 +1732,16 @@ "0x1", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0x2", + "0x4", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x424c4f434b5f4e554d4245525f4d49534d41544348", "0x400080007ffe7fff", - "0x48127ff07fff8000", - "0x48127ff77fff8000", - "0x48127ff77fff8000", + "0x48127fed7fff8000", + "0x482480017ff68000", + "0x1cc", + "0x48127ff47fff8000", "0x480680017fff8000", "0x1", "0x48127ffa7fff8000", @@ -1512,27 +1749,30 @@ "0x1", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0xc", - "0x48127ff07fff8000", - "0x480080027fcd8000", - "0x482480017fcc8000", + "0xe", + "0x480080027fc58000", + "0x48127fed7fff8000", + "0x482480017ffe8000", + "0x618", + "0x482480017fc28000", "0x6", "0x480680017fff8000", "0x1", - "0x480080047fca8000", - "0x480080057fc98000", + "0x480080047fc08000", + "0x480080057fbf8000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0x10", + "0x14", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e646578206f7574206f6620626f756e6473", "0x400080007ffe7fff", - "0x482480017fd78000", + "0x482680017ffb8000", "0x3", - "0x48127fcc7fff8000", - "0x48127fcc7fff8000", + "0x482480017fe48000", + "0x2fa8", + "0x48127fc27fff8000", "0x480680017fff8000", "0x1", "0x48127ffa7fff8000", @@ -1540,16 +1780,17 @@ "0x1", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0x17", + "0x1c", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e646578206f7574206f6620626f756e6473", "0x400080007ffe7fff", - "0x482480017fd78000", + "0x482680017ffb8000", "0x2", - "0x48127fcc7fff8000", - "0x48127fcc7fff8000", + "0x482480017fdc8000", + "0x3322", + "0x48127fc27fff8000", "0x480680017fff8000", "0x1", "0x48127ffa7fff8000", @@ -1557,16 +1798,17 @@ "0x1", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0x1e", + "0x24", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e646578206f7574206f6620626f756e6473", "0x400080007ffe7fff", - "0x482480017fd78000", + "0x482680017ffb8000", "0x1", - "0x48127fcc7fff8000", - "0x48127fcc7fff8000", + "0x482480017fd58000", + "0x369c", + "0x48127fc27fff8000", "0x480680017fff8000", "0x1", "0x48127ffa7fff8000", @@ -1574,15 +1816,16 @@ "0x1", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0x22", + "0x29", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x556e6b6e6f776e207363656e6172696f", "0x400080007ffe7fff", - "0x48127fd77fff8000", - "0x48127fcc7fff8000", - "0x48127fcc7fff8000", + "0x480a7ffb7fff8000", + "0x482480017fd38000", + "0x396c", + "0x48127fc27fff8000", "0x480680017fff8000", "0x1", "0x48127ffa7fff8000", @@ -1590,16 +1833,16 @@ "0x1", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0x2a", + "0x35", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e646578206f7574206f6620626f756e6473", "0x400080007ffe7fff", - "0x482680017ffb8000", - "0x1", - "0x48127fcc7fff8000", - "0x48127fcc7fff8000", + "0x480a7ffb7fff8000", + "0x482480017fc48000", + "0x3f98", + "0x48127fc27fff8000", "0x480680017fff8000", "0x1", "0x48127ffa7fff8000", @@ -1607,9 +1850,11 @@ "0x1", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0x38", - "0x480a7ffb7fff8000", + "0x40", "0x480280027ffd8000", + "0x480a7ffb7fff8000", + "0x482480017ffe8000", + "0x44a2", "0x482680017ffd8000", "0x6", "0x480680017fff8000", @@ -1620,19 +1865,21 @@ "0xa0680017fff8000", "0x7", "0x482680017ff88000", - "0xfffffffffffffffffffffffffffff6be", + "0xfffffffffffffffffffffffffffff592", "0x400280007ff77fff", "0x10780017fff7fff", - "0x43", + "0x49", "0x4825800180007ff8", - "0x942", + "0xa6e", "0x400280007ff77fff", "0x482680017ff78000", "0x1", + "0x48127ffe7fff8000", "0x20780017fff7ffd", - "0xd", - "0x48127fff7fff8000", - "0x48127ffd7fff8000", + "0xe", + "0x48127ffe7fff8000", + "0x482480017ffe8000", + "0xad2", "0x480680017fff8000", "0x0", "0x480a7ff97fff8000", @@ -1642,11 +1889,13 @@ "0x480a7ffb7fff8000", "0x480a7ffc7fff8000", "0x208b7fff7fff7ffe", + "0x48127fff7fff8000", "0x48297ff980007ffa", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", + "0xb", + "0x48127ffe7fff8000", "0x482680017ff98000", "0x1", "0x480a7ffa7fff8000", @@ -1654,7 +1903,8 @@ "0x0", "0x480280007ff98000", "0x10780017fff7fff", - "0x8", + "0x9", + "0x48127ffe7fff8000", "0x480a7ff97fff8000", "0x480a7ffa7fff8000", "0x480680017fff8000", @@ -1664,8 +1914,8 @@ "0x20680017fff7ffe", "0xf", "0x400280007ffc7fff", + "0x48127ff77fff8000", "0x48127ffa7fff8000", - "0x48127ff87fff8000", "0x48127ffa7fff8000", "0x48127ffa7fff8000", "0x480a7ffb7fff8000", @@ -1674,10 +1924,11 @@ "0x4825800180007ffd", "0x1", "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffc9", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffc4", "0x208b7fff7fff7ffe", - "0x48127ffa7fff8000", - "0x48127ff87fff8000", + "0x48127ff77fff8000", + "0x482480017ffa8000", + "0x6ea", "0x480680017fff8000", "0x0", "0x48127ff97fff8000", @@ -1708,17 +1959,228 @@ "0x48127ff87fff8000", "0x482480017ff78000", "0x1", + "0x208b7fff7fff7ffe", + "0x480680017fff8000", + "0x476574457865637574696f6e496e666f", + "0x400280007ff97fff", + "0x400380017ff97ff8", + "0x480280037ff98000", + "0x20680017fff7fff", + "0xc0", + "0x480280027ff98000", + "0x480280047ff98000", + "0x480080017fff8000", + "0x480080037fff8000", + "0x480080047ffe8000", + "0x482680017ff98000", + "0x5", + "0x48127ffa7fff8000", + "0x480080037ffb8000", + "0x480080047ffa8000", + "0x48307ffa80007ffb", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xa0", + "0x480080007ff98000", + "0x4824800180007fff", + "0x8", + "0x48127ffa7fff8000", + "0x20680017fff7ffe", + "0x74", + "0x480680017fff8000", + "0xf", + "0x48127ffe7fff8000", + "0xa0680017fff8004", + "0xe", + "0x4824800180047ffd", + "0x800000000000000000000000000000000000000000000000000000000000000", + "0x484480017ffe8000", + "0x110000000000000000", + "0x48307ffe7fff8002", + "0x480280007ff77ffc", + "0x480280017ff77ffc", + "0x402480017ffb7ffd", + "0xffffffffffffffeeffffffffffffffff", + "0x400280027ff77ffd", + "0x10780017fff7fff", + "0x51", + "0x484480017fff8001", + "0x8000000000000000000000000000000", + "0x48307fff80007ffc", + "0x480280007ff77ffd", + "0x480280017ff77ffd", + "0x402480017ffc7ffe", + "0xf8000000000000000000000000000000", + "0x400280027ff77ffe", + "0x480680017fff8000", + "0x2", + "0x48127ff97fff8000", + "0x48307ff180007ff2", + "0xa0680017fff8000", + "0x6", + "0x48307ffe80007ffc", + "0x400280037ff77fff", + "0x10780017fff7fff", + "0x2d", + "0x482480017ffc8000", + "0x1", + "0x48307fff80007ffd", + "0x400280037ff77fff", + "0x48307ffa7fed8000", + "0x48127ffa7fff8000", + "0x480680017fff8000", + "0x0", + "0x480080007ffd8000", + "0x482680017ff78000", + "0x4", + "0x480680017fff8000", + "0x53746f726167655772697465", + "0x400080007fe57fff", + "0x400080017fe57ffb", + "0x400080027fe57ffc", + "0x400080037fe57fed", + "0x400080047fe57ffd", + "0x480080067fe58000", + "0x20680017fff7fff", + "0xe", + "0x480080057fe48000", + "0x48127ffc7fff8000", + "0x48127ffe7fff8000", + "0x482480017fe18000", + "0x7", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x56414c4944", + "0x208b7fff7fff7ffe", + "0x480080057fe48000", + "0x48127ffc7fff8000", + "0x48127ffe7fff8000", + "0x482480017fe18000", + "0x9", + "0x480680017fff8000", + "0x1", + "0x480080077fdf8000", + "0x480080087fde8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x7", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x496e646578206f7574206f6620626f756e6473", + "0x400080007ffe7fff", + "0x482680017ff78000", + "0x4", + "0x482480017ff28000", + "0x2ab2", + "0x48127fe17fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0xb", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x400080007ffe7fff", + "0x482680017ff78000", + "0x3", + "0x482480017feb8000", + "0x2cc4", + "0x48127fe17fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x10", + "0x482480017fef8000", + "0x780", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x53656e644d657373616765546f4c31", + "0x400080007fe57fff", + "0x400080017fe57ffd", + "0x400080027fe57ffe", + "0x400180037fe57ffc", + "0x400180047fe57ffd", + "0x480080067fe58000", + "0x20680017fff7fff", + "0xe", + "0x480080057fe48000", + "0x480a7ff77fff8000", + "0x48127ffe7fff8000", + "0x482480017fe18000", + "0x7", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x56414c4944", + "0x208b7fff7fff7ffe", + "0x480080057fe48000", + "0x480a7ff77fff8000", + "0x48127ffe7fff8000", + "0x482480017fe18000", + "0x9", + "0x480680017fff8000", + "0x1", + "0x480080077fdf8000", + "0x480080087fde8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x16", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x496e646578206f7574206f6620626f756e6473", + "0x400080007ffe7fff", + "0x480a7ff77fff8000", + "0x482480017fe38000", + "0x32a0", + "0x48127fe17fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x21", + "0x480280027ff98000", + "0x480a7ff77fff8000", + "0x482480017ffe8000", + "0x37aa", + "0x482680017ff98000", + "0x6", + "0x480680017fff8000", + "0x1", + "0x480280047ff98000", + "0x480280057ff98000", "0x208b7fff7fff7ffe" ], "bytecode_segment_lengths": [ - 128, - 210, - 285, - 268, - 89, - 161, - 474, - 92 + 136, + 230, + 310, + 287, + 95, + 177, + 625, + 98, + 210 ], "hints": [ [ @@ -1744,7 +2206,7 @@ ] ], [ - 25, + 28, [ { "AllocSegment": { @@ -1757,17 +2219,17 @@ ] ], [ - 44, + 49, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x55a0" + "Immediate": "0x7472" }, "rhs": { "Deref": { "register": "AP", - "offset": -10 + "offset": -2 } }, "dst": { @@ -1779,7 +2241,7 @@ ] ], [ - 64, + 69, [ { "AllocSegment": { @@ -1792,7 +2254,7 @@ ] ], [ - 84, + 90, [ { "AllocSegment": { @@ -1805,7 +2267,7 @@ ] ], [ - 99, + 105, [ { "AllocSegment": { @@ -1818,7 +2280,7 @@ ] ], [ - 113, + 120, [ { "AllocSegment": { @@ -1831,7 +2293,7 @@ ] ], [ - 128, + 136, [ { "TestLessThanOrEqual": { @@ -1853,7 +2315,7 @@ ] ], [ - 178, + 194, [ { "AllocSegment": { @@ -1866,17 +2328,17 @@ ] ], [ - 197, + 215, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x5f64" + "Immediate": "0x7a4e" }, "rhs": { "Deref": { "register": "AP", - "offset": -18 + "offset": -2 } }, "dst": { @@ -1888,7 +2350,7 @@ ] ], [ - 246, + 269, [ { "AllocSegment": { @@ -1901,7 +2363,7 @@ ] ], [ - 266, + 290, [ { "AllocSegment": { @@ -1914,7 +2376,7 @@ ] ], [ - 281, + 305, [ { "AllocSegment": { @@ -1927,7 +2389,7 @@ ] ], [ - 295, + 320, [ { "AllocSegment": { @@ -1940,7 +2402,7 @@ ] ], [ - 309, + 335, [ { "AllocSegment": { @@ -1953,7 +2415,7 @@ ] ], [ - 323, + 350, [ { "AllocSegment": { @@ -1966,7 +2428,7 @@ ] ], [ - 338, + 366, [ { "TestLessThanOrEqual": { @@ -1988,14 +2450,14 @@ ] ], [ - 371, + 404, [ { "TestLessThan": { "lhs": { "Deref": { "register": "AP", - "offset": -1 + "offset": -2 } }, "rhs": { @@ -2010,7 +2472,7 @@ ] ], [ - 375, + 408, [ { "LinearSplit": { @@ -2039,14 +2501,14 @@ ] ], [ - 385, + 418, [ { "LinearSplit": { "value": { "Deref": { "register": "AP", - "offset": -2 + "offset": -3 } }, "scalar": { @@ -2068,7 +2530,7 @@ ] ], [ - 424, + 461, [ { "AllocSegment": { @@ -2081,7 +2543,7 @@ ] ], [ - 444, + 483, [ { "AllocSegment": { @@ -2094,17 +2556,17 @@ ] ], [ - 463, + 504, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x972c" + "Immediate": "0xa1c2" }, "rhs": { "Deref": { "register": "AP", - "offset": -12 + "offset": -2 } }, "dst": { @@ -2116,7 +2578,7 @@ ] ], [ - 486, + 528, [ { "SystemCall": { @@ -2131,7 +2593,7 @@ ] ], [ - 497, + 540, [ { "AllocSegment": { @@ -2144,7 +2606,7 @@ ] ], [ - 530, + 576, [ { "AllocSegment": { @@ -2157,7 +2619,7 @@ ] ], [ - 559, + 608, [ { "AllocSegment": { @@ -2170,7 +2632,7 @@ ] ], [ - 573, + 622, [ { "AllocSegment": { @@ -2183,7 +2645,7 @@ ] ], [ - 594, + 646, [ { "AllocSegment": { @@ -2196,7 +2658,7 @@ ] ], [ - 608, + 660, [ { "AllocSegment": { @@ -2209,7 +2671,7 @@ ] ], [ - 623, + 678, [ { "TestLessThanOrEqual": { @@ -2231,14 +2693,14 @@ ] ], [ - 656, + 717, [ { "TestLessThan": { "lhs": { "Deref": { - "register": "AP", - "offset": -1 + "register": "FP", + "offset": 1 } }, "rhs": { @@ -2253,7 +2715,7 @@ ] ], [ - 660, + 721, [ { "LinearSplit": { @@ -2282,14 +2744,14 @@ ] ], [ - 670, + 731, [ { "LinearSplit": { "value": { "Deref": { - "register": "AP", - "offset": -2 + "register": "FP", + "offset": 1 } }, "scalar": { @@ -2311,7 +2773,7 @@ ] ], [ - 709, + 775, [ { "AllocSegment": { @@ -2324,7 +2786,7 @@ ] ], [ - 729, + 797, [ { "AllocSegment": { @@ -2337,17 +2799,17 @@ ] ], [ - 748, + 818, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x2404" + "Immediate": "0x67d4" }, "rhs": { "Deref": { "register": "AP", - "offset": -12 + "offset": -2 } }, "dst": { @@ -2359,22 +2821,7 @@ ] ], [ - 771, - [ - { - "SystemCall": { - "system": { - "Deref": { - "register": "FP", - "offset": -5 - } - } - } - } - ] - ], - [ - 774, + 842, [ { "AllocSegment": { @@ -2387,7 +2834,7 @@ ] ], [ - 798, + 863, [ { "AllocSegment": { @@ -2400,7 +2847,7 @@ ] ], [ - 827, + 895, [ { "AllocSegment": { @@ -2413,7 +2860,7 @@ ] ], [ - 841, + 909, [ { "AllocSegment": { @@ -2426,7 +2873,7 @@ ] ], [ - 862, + 933, [ { "AllocSegment": { @@ -2439,7 +2886,7 @@ ] ], [ - 876, + 947, [ { "AllocSegment": { @@ -2452,7 +2899,7 @@ ] ], [ - 891, + 963, [ { "TestLessThanOrEqual": { @@ -2474,7 +2921,7 @@ ] ], [ - 908, + 982, [ { "AllocSegment": { @@ -2487,7 +2934,7 @@ ] ], [ - 927, + 1003, [ { "TestLessThanOrEqual": { @@ -2497,7 +2944,7 @@ "rhs": { "Deref": { "register": "AP", - "offset": -7 + "offset": -2 } }, "dst": { @@ -2509,7 +2956,7 @@ ] ], [ - 939, + 1015, [ { "AllocSegment": { @@ -2522,7 +2969,7 @@ ] ], [ - 950, + 1027, [ { "AllocSegment": { @@ -2535,7 +2982,7 @@ ] ], [ - 965, + 1042, [ { "AllocSegment": { @@ -2548,7 +2995,7 @@ ] ], [ - 980, + 1058, [ { "TestLessThanOrEqual": { @@ -2570,7 +3017,7 @@ ] ], [ - 1014, + 1098, [ { "AllocSegment": { @@ -2583,17 +3030,17 @@ ] ], [ - 1033, + 1119, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x5b7c" + "Immediate": "0x7986" }, "rhs": { "Deref": { "register": "AP", - "offset": -12 + "offset": -2 } }, "dst": { @@ -2605,7 +3052,7 @@ ] ], [ - 1079, + 1170, [ { "AllocSegment": { @@ -2618,7 +3065,7 @@ ] ], [ - 1097, + 1189, [ { "AllocSegment": { @@ -2631,7 +3078,7 @@ ] ], [ - 1112, + 1204, [ { "AllocSegment": { @@ -2644,7 +3091,7 @@ ] ], [ - 1126, + 1219, [ { "AllocSegment": { @@ -2657,7 +3104,7 @@ ] ], [ - 1145, + 1239, [ { "SystemCall": { @@ -2672,32 +3119,153 @@ ] ], [ - 1160, + 1302, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1328, + [ + { + "TestLessThan": { + "lhs": { + "Deref": { + "register": "AP", + "offset": -3 + } + }, + "rhs": { + "Deref": { + "register": "AP", + "offset": -1 + } + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1339, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1343, [ { "TestLessThan": { "lhs": { "Deref": { "register": "AP", - "offset": -6 + "offset": -2 } }, "rhs": { + "Immediate": "0x800000000000000000000000000000000000000000000000000000000000000" + }, + "dst": { + "register": "AP", + "offset": 4 + } + } + } + ] + ], + [ + 1347, + [ + { + "LinearSplit": { + "value": { + "Deref": { + "register": "AP", + "offset": 3 + } + }, + "scalar": { + "Immediate": "0x110000000000000000" + }, + "max_x": { + "Immediate": "0xffffffffffffffffffffffffffffffff" + }, + "x": { + "register": "AP", + "offset": -2 + }, + "y": { + "register": "AP", + "offset": -1 + } + } + } + ] + ], + [ + 1357, + [ + { + "LinearSplit": { + "value": { + "Deref": { + "register": "AP", + "offset": -3 + } + }, + "scalar": { + "Immediate": "0x8000000000000000000000000000000" + }, + "max_x": { + "Immediate": "0xffffffffffffffffffffffffffffffff" + }, + "x": { + "register": "AP", + "offset": -1 + }, + "y": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1378, + [ + { + "SystemCall": { + "system": { "Deref": { "register": "AP", - "offset": -1 + "offset": -58 } - }, - "dst": { - "register": "AP", - "offset": 0 } } } ] ], [ - 1212, + 1405, [ { "AllocSegment": { @@ -2710,22 +3278,10 @@ ] ], [ - 1235, + 1423, [ { - "TestLessThan": { - "lhs": { - "Deref": { - "register": "AP", - "offset": -2 - } - }, - "rhs": { - "Deref": { - "register": "AP", - "offset": -1 - } - }, + "AllocSegment": { "dst": { "register": "AP", "offset": 0 @@ -2735,27 +3291,29 @@ ] ], [ - 1246, + 1455, [ { - "AllocSegment": { - "dst": { - "register": "AP", - "offset": 0 + "SystemCall": { + "system": { + "Deref": { + "register": "AP", + "offset": -58 + } } } } ] ], [ - 1249, + 1491, [ { "TestLessThan": { "lhs": { "Deref": { "register": "AP", - "offset": -1 + "offset": -2 } }, "rhs": { @@ -2770,7 +3328,7 @@ ] ], [ - 1253, + 1495, [ { "LinearSplit": { @@ -2799,14 +3357,14 @@ ] ], [ - 1263, + 1505, [ { "LinearSplit": { "value": { "Deref": { "register": "AP", - "offset": -2 + "offset": -3 } }, "scalar": { @@ -2828,35 +3386,47 @@ ] ], [ - 1283, + 1517, [ { - "SystemCall": { - "system": { + "TestLessThan": { + "lhs": { + "Deref": { + "register": "AP", + "offset": -3 + } + }, + "rhs": { "Deref": { "register": "AP", - "offset": -49 + "offset": -1 } + }, + "dst": { + "register": "AP", + "offset": 0 } } } ] ], [ - 1308, + 1541, [ { - "AllocSegment": { - "dst": { - "register": "AP", - "offset": 0 + "SystemCall": { + "system": { + "Deref": { + "register": "AP", + "offset": -58 + } } } } ] ], [ - 1325, + 1568, [ { "AllocSegment": { @@ -2869,29 +3439,27 @@ ] ], [ - 1353, + 1586, [ { - "SystemCall": { - "system": { - "Deref": { - "register": "AP", - "offset": -49 - } + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 } } } ] ], [ - 1383, + 1611, [ { "TestLessThan": { "lhs": { "Deref": { "register": "AP", - "offset": -2 + "offset": -3 } }, "rhs": { @@ -2909,14 +3477,14 @@ ] ], [ - 1398, + 1627, [ { "TestLessThan": { "lhs": { "Deref": { "register": "AP", - "offset": -3 + "offset": -4 } }, "rhs": { @@ -2934,14 +3502,14 @@ ] ], [ - 1413, + 1643, [ { "TestLessThan": { "lhs": { "Deref": { "register": "AP", - "offset": -3 + "offset": -4 } }, "rhs": { @@ -2959,14 +3527,14 @@ ] ], [ - 1431, + 1662, [ { "SystemCall": { "system": { "Deref": { "register": "AP", - "offset": -37 + "offset": -44 } } } @@ -2974,7 +3542,7 @@ ] ], [ - 1463, + 1698, [ { "AllocSegment": { @@ -2987,7 +3555,7 @@ ] ], [ - 1479, + 1714, [ { "AllocSegment": { @@ -3000,7 +3568,7 @@ ] ], [ - 1495, + 1731, [ { "AllocSegment": { @@ -3013,7 +3581,7 @@ ] ], [ - 1522, + 1761, [ { "AllocSegment": { @@ -3026,7 +3594,7 @@ ] ], [ - 1539, + 1779, [ { "AllocSegment": { @@ -3039,7 +3607,7 @@ ] ], [ - 1556, + 1797, [ { "AllocSegment": { @@ -3052,7 +3620,7 @@ ] ], [ - 1573, + 1815, [ { "AllocSegment": { @@ -3065,7 +3633,7 @@ ] ], [ - 1589, + 1832, [ { "AllocSegment": { @@ -3078,12 +3646,12 @@ ] ], [ - 1615, + 1860, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x942" + "Immediate": "0xa6e" }, "rhs": { "Deref": { @@ -3100,7 +3668,196 @@ ] ], [ - 1687, + 1938, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1962, + [ + { + "SystemCall": { + "system": { + "Deref": { + "register": "FP", + "offset": -7 + } + } + } + } + ] + ], + [ + 1989, + [ + { + "TestLessThan": { + "lhs": { + "Deref": { + "register": "AP", + "offset": -2 + } + }, + "rhs": { + "Immediate": "0x800000000000000000000000000000000000000000000000000000000000000" + }, + "dst": { + "register": "AP", + "offset": 4 + } + } + } + ] + ], + [ + 1993, + [ + { + "LinearSplit": { + "value": { + "Deref": { + "register": "AP", + "offset": 3 + } + }, + "scalar": { + "Immediate": "0x110000000000000000" + }, + "max_x": { + "Immediate": "0xffffffffffffffffffffffffffffffff" + }, + "x": { + "register": "AP", + "offset": -2 + }, + "y": { + "register": "AP", + "offset": -1 + } + } + } + ] + ], + [ + 2003, + [ + { + "LinearSplit": { + "value": { + "Deref": { + "register": "AP", + "offset": -3 + } + }, + "scalar": { + "Immediate": "0x8000000000000000000000000000000" + }, + "max_x": { + "Immediate": "0xffffffffffffffffffffffffffffffff" + }, + "x": { + "register": "AP", + "offset": -1 + }, + "y": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 2015, + [ + { + "TestLessThan": { + "lhs": { + "Deref": { + "register": "AP", + "offset": -3 + } + }, + "rhs": { + "Deref": { + "register": "AP", + "offset": -1 + } + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 2039, + [ + { + "SystemCall": { + "system": { + "Deref": { + "register": "AP", + "offset": -27 + } + } + } + } + ] + ], + [ + 2066, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 2084, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 2113, + [ + { + "SystemCall": { + "system": { + "Deref": { + "register": "AP", + "offset": -27 + } + } + } + } + ] + ], + [ + 2140, [ { "AllocSegment": { @@ -3117,21 +3874,21 @@ "EXTERNAL": [ { "selector": "0x15d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad", - "offset": 623, + "offset": 676, "builtins": [ "range_check" ] }, { "selector": "0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775", - "offset": 338, + "offset": 366, "builtins": [ "range_check" ] }, { "selector": "0x1b1a0649752af1b28b3dc29a1556eee781e4a4c3a1f7f53f90fa834de098c4d", - "offset": 891, + "offset": 963, "builtins": [ "range_check" ] @@ -3145,7 +3902,7 @@ }, { "selector": "0x36fcbf06cd96843058359e1a75928beacfac10727dab22a3972f0af8aa92895", - "offset": 128, + "offset": 136, "builtins": [ "range_check" ] @@ -3155,7 +3912,7 @@ "CONSTRUCTOR": [ { "selector": "0x28ffe4ff0f226a9107253e17a904099aa4f63a02a5621de0576e5aa71bc5194", - "offset": 980, + "offset": 1058, "builtins": [ "range_check" ] diff --git a/crates/blockifier/feature_contracts/cairo1/compiled/account_with_dummy_validate.casm.json b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/compiled/account_with_dummy_validate.casm.json similarity index 83% rename from crates/blockifier/feature_contracts/cairo1/compiled/account_with_dummy_validate.casm.json rename to crates/blockifier_test_utils/resources/feature_contracts/cairo1/compiled/account_with_dummy_validate.casm.json index 1c823028c65..7834d504d6f 100644 --- a/crates/blockifier/feature_contracts/cairo1/compiled/account_with_dummy_validate.casm.json +++ b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/compiled/account_with_dummy_validate.casm.json @@ -1,6 +1,6 @@ { "prime": "0x800000000000011000000000000000000000000000000000000000000000001", - "compiler_version": "2.9.0", + "compiler_version": "2.11.0", "bytecode": [ "0xa0680017fff8000", "0x7", @@ -8,40 +8,45 @@ "0x100000000000000000000000000000000", "0x400280007ff97fff", "0x10780017fff7fff", - "0x75", + "0x7e", "0x4825800180007ffa", "0x0", "0x400280007ff97fff", "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0x1810", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x5d", + "0x63", "0x482680017ffc8000", "0x1", "0x480a7ffd7fff8000", - "0x48307ffe80007fff", + "0x48127ffc7fff8000", + "0x48307ffd80007ffe", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x47", - "0x482480017ffd8000", + "0x4b", + "0x482480017ffc8000", "0x1", - "0x48127ffd7fff8000", - "0x48307ffe80007fff", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", + "0x48307ffd80007ffe", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ff67fff8000", - "0x48127ff47fff8000", + "0x48127ff37fff8000", + "0x482480017ffb8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -50,30 +55,32 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x45d", + "0x4b9", "0x482480017fff8000", - "0x45c", - "0x480080007fff8000", + "0x4b8", + "0x48127ffb7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007ff2", + "0x4824800180007ffd", "0x0", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007ff17fff", + "0x400080007fed7fff", "0x10780017fff7fff", - "0x14", - "0x4824800180007ff2", + "0x15", + "0x4824800180007ffd", "0x0", - "0x400080007ff27fff", + "0x400080007fee7fff", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x56414c4944", "0x400080007ffe7fff", - "0x482480017ff08000", + "0x482480017fec8000", "0x1", - "0x48127ffc7fff8000", + "0x482480017ffc8000", + "0xc8", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x0", @@ -86,9 +93,9 @@ "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482480017fef8000", + "0x482480017feb8000", "0x1", - "0x48127fed7fff8000", + "0x48127ff87fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -101,8 +108,9 @@ "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202332", "0x400080007ffe7fff", - "0x48127ff97fff8000", "0x48127ff77fff8000", + "0x482480017ffb8000", + "0x622", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -115,8 +123,9 @@ "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202331", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127ffa7fff8000", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x816", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -131,7 +140,8 @@ "0x400080007ffe7fff", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x21b6", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -145,32 +155,36 @@ "0x100000000000000000000000000000000", "0x400280007ff97fff", "0x10780017fff7fff", - "0x5f", + "0x66", "0x4825800180007ffa", "0x0", "0x400280007ff97fff", "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0x1a04", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x47", + "0x4b", "0x482680017ffc8000", "0x1", "0x480a7ffd7fff8000", - "0x48307ffe80007fff", + "0x48127ffc7fff8000", + "0x48307ffd80007ffe", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ff97fff8000", "0x48127ff77fff8000", + "0x482480017ffb8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -179,30 +193,32 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x3dc", + "0x42f", "0x482480017fff8000", - "0x3db", - "0x480080007fff8000", + "0x42e", + "0x48127ffb7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007ff5", + "0x4824800180007ffd", "0x0", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007ff47fff", + "0x400080007ff17fff", "0x10780017fff7fff", - "0x14", - "0x4824800180007ff5", + "0x15", + "0x4824800180007ffd", "0x0", - "0x400080007ff57fff", + "0x400080007ff27fff", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x56414c4944", "0x400080007ffe7fff", - "0x482480017ff38000", + "0x482480017ff08000", "0x1", - "0x48127ffc7fff8000", + "0x482480017ffc8000", + "0xc8", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x0", @@ -215,9 +231,9 @@ "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482480017ff28000", + "0x482480017fef8000", "0x1", - "0x48127ff07fff8000", + "0x48127ff87fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -230,8 +246,9 @@ "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202331", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127ffa7fff8000", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x622", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -246,7 +263,8 @@ "0x400080007ffe7fff", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x21b6", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -260,17 +278,20 @@ "0x100000000000000000000000000000000", "0x400280007ff97fff", "0x10780017fff7fff", - "0xe1", + "0xf5", "0x4825800180007ffa", "0x0", "0x400280007ff97fff", "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0x2a8", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", + "0xb", + "0x48127ffe7fff8000", "0x482680017ffc8000", "0x1", "0x480a7ffd7fff8000", @@ -278,7 +299,8 @@ "0x0", "0x480280007ffc8000", "0x10780017fff7fff", - "0x8", + "0x9", + "0x48127ffe7fff8000", "0x480a7ffc7fff8000", "0x480a7ffd7fff8000", "0x480680017fff8000", @@ -286,87 +308,95 @@ "0x480680017fff8000", "0x0", "0x20680017fff7ffe", - "0xb6", + "0xc6", + "0x48127ffb7fff8000", "0xa0680017fff8004", "0xe", - "0x4824800180047ffe", + "0x4824800180047ffd", "0x800000000000000000000000000000000000000000000000000000000000000", "0x484480017ffe8000", "0x110000000000000000", "0x48307ffe7fff8002", - "0x480080007ff67ffc", - "0x480080017ff57ffc", + "0x480080007ff37ffc", + "0x480080017ff27ffc", "0x402480017ffb7ffd", "0xffffffffffffffeeffffffffffffffff", - "0x400080027ff47ffd", + "0x400080027ff17ffd", "0x10780017fff7fff", - "0xa4", + "0xb1", "0x484480017fff8001", "0x8000000000000000000000000000000", - "0x48307fff80007ffd", - "0x480080007ff77ffd", - "0x480080017ff67ffd", + "0x48307fff80007ffc", + "0x480080007ff47ffd", + "0x480080017ff37ffd", "0x402480017ffc7ffe", "0xf8000000000000000000000000000000", - "0x400080027ff57ffe", - "0x482480017ff58000", + "0x400080027ff27ffe", + "0x482480017ff28000", "0x3", - "0x48307ff680007ff7", + "0x48127ff97fff8000", + "0x48307ff480007ff5", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x87", - "0x482480017ff58000", + "0x92", + "0x482480017ff38000", "0x1", - "0x48127ff57fff8000", - "0x48307ffe80007fff", + "0x48127ff37fff8000", + "0x48127ffc7fff8000", + "0x48307ffd80007ffe", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", - "0x482480017ffd8000", + "0xb", + "0x48127ffe7fff8000", + "0x482480017ffb8000", "0x1", - "0x48127ffd7fff8000", + "0x48127ffb7fff8000", "0x480680017fff8000", "0x0", - "0x48127ffa7fff8000", + "0x48127ff87fff8000", "0x10780017fff7fff", - "0x8", - "0x48127ffd7fff8000", - "0x48127ffd7fff8000", + "0x9", + "0x48127ffe7fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", "0x480680017fff8000", "0x1", "0x480680017fff8000", "0x0", "0x20680017fff7ffe", - "0x5f", + "0x66", "0x40780017fff7fff", "0x1", - "0x48127ff67fff8000", - "0x48127fe97fff8000", + "0x48127ff37fff8000", + "0x48127ff97fff8000", "0x48127ff97fff8000", "0x48127ff97fff8000", "0x48127ffb7fff8000", "0x48127ffa7fff8000", "0x480080007ff88000", "0x1104800180018000", - "0x2d5", + "0x315", "0x20680017fff7ffa", - "0x4a", - "0x20680017fff7ffd", - "0x44", - "0x48307ffb80007ffc", + "0x50", + "0x48127ff97fff8000", + "0x20680017fff7ffc", + "0x48", + "0x48127fff7fff8000", + "0x48307ff980007ffa", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ff57fff8000", - "0x48127ff57fff8000", + "0x48127ff37fff8000", + "0x482480017ffb8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -375,30 +405,32 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x318", + "0x35b", "0x482480017fff8000", - "0x317", - "0x480080007fff8000", + "0x35a", + "0x48127ffb7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007ff3", + "0x4824800180007ffd", "0x0", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007ff07fff", + "0x400080007fed7fff", "0x10780017fff7fff", - "0x14", - "0x4824800180007ff3", + "0x15", + "0x4824800180007ffd", "0x0", - "0x400080007ff17fff", + "0x400080007fee7fff", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x56414c4944", "0x400080007ffe7fff", - "0x482480017fef8000", + "0x482480017fec8000", "0x1", - "0x48127ffc7fff8000", + "0x482480017ffc8000", + "0xc8", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x0", @@ -411,9 +443,9 @@ "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482480017fee8000", + "0x482480017feb8000", "0x1", - "0x48127fee7fff8000", + "0x48127ff87fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -421,20 +453,23 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x48127ff87fff8000", - "0x48127ff87fff8000", + "0x48127ff77fff8000", + "0x482480017ffe8000", + "0x492", "0x10780017fff7fff", - "0xc", - "0x48127ff87fff8000", + "0xe", "0x48127ff87fff8000", + "0x482480017ff88000", + "0x7b2", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", "0x48127ffa7fff8000", "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", - "0x48127ff77fff8000", - "0x48127fea7fff8000", + "0x48127ff47fff8000", + "0x482480017ffa8000", + "0x102c", "0x40780017fff7fff", "0x1", "0x480680017fff8000", @@ -454,8 +489,9 @@ "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202332", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127fef7fff8000", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x1540", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -463,20 +499,22 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x482480017ff48000", + "0x482480017ff18000", "0x3", + "0x482480017ff88000", + "0x1540", "0x10780017fff7fff", "0x5", - "0x40780017fff7fff", - "0x6", - "0x48127ff47fff8000", + "0x48127ff87fff8000", + "0x482480017ffa8000", + "0x1a5e", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202331", "0x400080007ffe7fff", - "0x48127ffd7fff8000", - "0x48127fef7fff8000", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -491,7 +529,8 @@ "0x400080007ffe7fff", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x21b6", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -507,17 +546,20 @@ "0x100000000000000000000000000000000", "0x400280007ff97fff", "0x10780017fff7fff", - "0x118", + "0x133", "0x4825800180007ffa", "0x0", "0x400280007ff97fff", "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0x17c", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", + "0xb", + "0x48127ffe7fff8000", "0x482680017ffc8000", "0x1", "0x480a7ffd7fff8000", @@ -525,7 +567,8 @@ "0x0", "0x480280007ffc8000", "0x10780017fff7fff", - "0x8", + "0x9", + "0x48127ffe7fff8000", "0x480a7ffc7fff8000", "0x480a7ffd7fff8000", "0x480680017fff8000", @@ -533,89 +576,97 @@ "0x480680017fff8000", "0x0", "0x20680017fff7ffe", - "0xed", - "0x40137fff7fff8000", + "0x104", + "0x40137fff7fff8001", + "0x48127ffb7fff8000", "0xa0680017fff8004", "0xe", - "0x4825800180048000", + "0x4825800180048001", "0x800000000000000000000000000000000000000000000000000000000000000", "0x484480017ffe8000", "0x110000000000000000", "0x48307ffe7fff8002", - "0x480080007ff67ffc", - "0x480080017ff57ffc", + "0x480080007ff37ffc", + "0x480080017ff27ffc", "0x402480017ffb7ffd", "0xffffffffffffffeeffffffffffffffff", - "0x400080027ff47ffd", + "0x400080027ff17ffd", "0x10780017fff7fff", - "0xda", + "0xee", "0x484480017fff8001", "0x8000000000000000000000000000000", - "0x48317fff80008000", - "0x480080007ff77ffd", - "0x480080017ff67ffd", + "0x48317fff80008001", + "0x480080007ff47ffd", + "0x480080017ff37ffd", "0x402480017ffc7ffe", "0xf8000000000000000000000000000000", - "0x400080027ff57ffe", - "0x482480017ff58000", + "0x400080027ff27ffe", + "0x482480017ff28000", "0x3", - "0x48307ff680007ff7", + "0x48127ff97fff8000", + "0x48307ff480007ff5", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xbd", - "0x400180007ff58001", - "0x482480017ff58000", + "0xcf", + "0x400180007ff38000", + "0x482480017ff38000", "0x1", - "0x48127ff57fff8000", - "0x48307ffe80007fff", + "0x48127ff37fff8000", + "0x48127ffc7fff8000", + "0x48307ffd80007ffe", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", - "0x482480017ffd8000", + "0xb", + "0x48127ffe7fff8000", + "0x482480017ffb8000", "0x1", - "0x48127ffd7fff8000", + "0x48127ffb7fff8000", "0x480680017fff8000", "0x0", - "0x48127ffa7fff8000", + "0x48127ff87fff8000", "0x10780017fff7fff", - "0x8", - "0x48127ffd7fff8000", - "0x48127ffd7fff8000", + "0x9", + "0x48127ffe7fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", "0x480680017fff8000", "0x1", "0x480680017fff8000", "0x0", "0x20680017fff7ffe", - "0x94", + "0xa2", "0x40780017fff7fff", "0x1", - "0x48127ff67fff8000", - "0x48127fe97fff8000", + "0x48127ff37fff8000", + "0x48127ff97fff8000", "0x48127ff97fff8000", "0x48127ff97fff8000", "0x48127ffb7fff8000", "0x48127ffa7fff8000", "0x480080007ff88000", "0x1104800180018000", - "0x1dc", + "0x207", "0x20680017fff7ffa", - "0x7f", - "0x20680017fff7ffd", - "0x79", - "0x48307ffb80007ffc", + "0x8c", + "0x48127ff97fff8000", + "0x20680017fff7ffc", + "0x84", + "0x48127fff7fff8000", + "0x48307ff980007ffa", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ff57fff8000", - "0x48127ff57fff8000", + "0x48127ff37fff8000", + "0x482480017ffb8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -624,23 +675,25 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x21f", + "0x24d", "0x482480017fff8000", - "0x21e", - "0x480080007fff8000", + "0x24c", + "0x48127ffb7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007ff3", - "0x4efc", + "0x4824800180007ffd", + "0x558c", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007ff07fff", + "0x400080007fed7fff", "0x10780017fff7fff", - "0x49", - "0x4824800180007ff3", - "0x4efc", - "0x400080007ff17fff", - "0x482480017ff18000", + "0x51", + "0x4824800180007ffd", + "0x558c", + "0x400080007fee7fff", + "0x48127fff7fff8000", + "0x482480017fed8000", "0x1", "0x480680017fff8000", "0x476574457865637574696f6e496e666f", @@ -648,59 +701,66 @@ "0x400280017ffb7ffd", "0x480280037ffb8000", "0x20680017fff7fff", - "0x34", + "0x39", + "0x480280027ffb8000", "0x480280047ffb8000", "0x480080027fff8000", - "0x480280027ffb8000", "0x482680017ffb8000", "0x5", + "0x48127ffc7fff8000", "0x20680017fff7ffd", - "0x1f", + "0x22", + "0x48127fff7fff8000", "0x480680017fff8000", "0x43616c6c436f6e7472616374", - "0x400080007ffe7fff", - "0x400080017ffe7ffd", - "0x400180027ffe8000", - "0x400180037ffe8001", - "0x400080047ffe7fef", - "0x400080057ffe7ff0", - "0x480080077ffe8000", + "0x400080007ffc7fff", + "0x400080017ffc7ffe", + "0x400180027ffc8001", + "0x400180037ffc8000", + "0x400080047ffc7fe9", + "0x400080057ffc7fea", + "0x480080077ffc8000", "0x20680017fff7fff", - "0xb", - "0x48127ff77fff8000", - "0x480080067ffc8000", - "0x482480017ffb8000", + "0xc", + "0x480080067ffb8000", + "0x48127ff47fff8000", + "0x48127ffe7fff8000", + "0x482480017ff88000", "0xa", "0x480680017fff8000", "0x0", - "0x480080087ff98000", - "0x480080097ff88000", + "0x480080087ff68000", + "0x480080097ff58000", "0x208b7fff7fff7ffe", - "0x48127ff77fff8000", - "0x480080067ffc8000", - "0x482480017ffb8000", + "0x480080067ffb8000", + "0x48127ff47fff8000", + "0x48127ffe7fff8000", + "0x482480017ff88000", "0xa", "0x480680017fff8000", "0x1", - "0x480080087ff98000", - "0x480080097ff88000", + "0x480080087ff68000", + "0x480080097ff58000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x494e56414c49445f43414c4c4552", "0x400080007ffe7fff", - "0x48127ff77fff8000", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", + "0x48127ff67fff8000", + "0x482480017ffc8000", + "0x2a30", + "0x48127ffa7fff8000", "0x480680017fff8000", "0x1", "0x48127ffa7fff8000", "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x48127ffd7fff8000", "0x480280027ffb8000", + "0x48127ffc7fff8000", + "0x482480017ffe8000", + "0x2d50", "0x482680017ffb8000", "0x6", "0x480680017fff8000", @@ -713,9 +773,9 @@ "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482480017fee8000", + "0x482480017feb8000", "0x1", - "0x48127fee7fff8000", + "0x48127ff87fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -723,20 +783,23 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x48127ff87fff8000", - "0x48127ff87fff8000", + "0x48127ff77fff8000", + "0x482480017ffe8000", + "0x492", "0x10780017fff7fff", - "0xc", - "0x48127ff87fff8000", + "0xe", "0x48127ff87fff8000", + "0x482480017ff88000", + "0x7b2", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", "0x48127ffa7fff8000", "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", - "0x48127ff77fff8000", - "0x48127fea7fff8000", + "0x48127ff47fff8000", + "0x482480017ffa8000", + "0x102c", "0x40780017fff7fff", "0x1", "0x480680017fff8000", @@ -756,8 +819,9 @@ "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202332", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127fef7fff8000", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x159a", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -765,20 +829,22 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x482480017ff48000", + "0x482480017ff18000", "0x3", + "0x482480017ff88000", + "0x159a", "0x10780017fff7fff", "0x5", - "0x40780017fff7fff", - "0x6", - "0x48127ff47fff8000", + "0x48127ff87fff8000", + "0x482480017ffa8000", + "0x1b12", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202331", "0x400080007ffe7fff", - "0x48127ffd7fff8000", - "0x48127fef7fff8000", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -793,7 +859,8 @@ "0x400080007ffe7fff", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x213e", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -809,17 +876,20 @@ "0x100000000000000000000000000000000", "0x400280007ff97fff", "0x10780017fff7fff", - "0xfb", + "0x112", "0x4825800180007ffa", "0x0", "0x400280007ff97fff", "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0x17c", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", + "0xb", + "0x48127ffe7fff8000", "0x482680017ffc8000", "0x1", "0x480a7ffd7fff8000", @@ -827,7 +897,8 @@ "0x0", "0x480280007ffc8000", "0x10780017fff7fff", - "0x8", + "0x9", + "0x48127ffe7fff8000", "0x480a7ffc7fff8000", "0x480a7ffd7fff8000", "0x480680017fff8000", @@ -835,89 +906,97 @@ "0x480680017fff8000", "0x0", "0x20680017fff7ffe", - "0xd0", - "0x40137fff7fff8001", + "0xe3", + "0x40137fff7fff8000", + "0x48127ffb7fff8000", "0xa0680017fff8004", "0xe", - "0x4825800180048001", + "0x4825800180048000", "0x800000000000000000000000000000000000000000000000000000000000000", "0x484480017ffe8000", "0x110000000000000000", "0x48307ffe7fff8002", - "0x480080007ff67ffc", - "0x480080017ff57ffc", + "0x480080007ff37ffc", + "0x480080017ff27ffc", "0x402480017ffb7ffd", "0xffffffffffffffeeffffffffffffffff", - "0x400080027ff47ffd", + "0x400080027ff17ffd", "0x10780017fff7fff", - "0xbd", + "0xcd", "0x484480017fff8001", "0x8000000000000000000000000000000", - "0x48317fff80008001", - "0x480080007ff77ffd", - "0x480080017ff67ffd", + "0x48317fff80008000", + "0x480080007ff47ffd", + "0x480080017ff37ffd", "0x402480017ffc7ffe", "0xf8000000000000000000000000000000", - "0x400080027ff57ffe", - "0x482480017ff58000", + "0x400080027ff27ffe", + "0x482480017ff28000", "0x3", - "0x48307ff680007ff7", + "0x48127ff97fff8000", + "0x48307ff480007ff5", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa0", - "0x400180007ff58000", - "0x482480017ff58000", + "0xae", + "0x400180007ff38001", + "0x482480017ff38000", "0x1", - "0x48127ff57fff8000", - "0x48307ffe80007fff", + "0x48127ff37fff8000", + "0x48127ffc7fff8000", + "0x48307ffd80007ffe", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", - "0x482480017ffd8000", + "0xb", + "0x48127ffe7fff8000", + "0x482480017ffb8000", "0x1", - "0x48127ffd7fff8000", + "0x48127ffb7fff8000", "0x480680017fff8000", "0x0", - "0x48127ffa7fff8000", + "0x48127ff87fff8000", "0x10780017fff7fff", - "0x8", - "0x48127ffd7fff8000", - "0x48127ffd7fff8000", + "0x9", + "0x48127ffe7fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", "0x480680017fff8000", "0x1", "0x480680017fff8000", "0x0", "0x20680017fff7ffe", - "0x77", + "0x81", "0x40780017fff7fff", "0x1", - "0x48127ff67fff8000", - "0x48127fe97fff8000", + "0x48127ff37fff8000", + "0x48127ff97fff8000", "0x48127ff97fff8000", "0x48127ff97fff8000", "0x48127ffb7fff8000", "0x48127ffa7fff8000", "0x480080007ff88000", "0x1104800180018000", - "0xae", + "0xbd", "0x20680017fff7ffa", - "0x62", - "0x20680017fff7ffd", - "0x5c", - "0x48307ffb80007ffc", + "0x6b", + "0x48127ff97fff8000", + "0x20680017fff7ffc", + "0x63", + "0x48127fff7fff8000", + "0x48307ff980007ffa", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ff57fff8000", - "0x48127ff57fff8000", + "0x48127ff37fff8000", + "0x482480017ffb8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -926,44 +1005,47 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0xf1", + "0x103", "0x482480017fff8000", - "0xf0", - "0x480080007fff8000", + "0x102", + "0x48127ffb7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007ff3", - "0x25f8", + "0x4824800180007ffd", + "0x2bc0", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007ff07fff", + "0x400080007fed7fff", "0x10780017fff7fff", - "0x2c", - "0x4824800180007ff3", - "0x25f8", - "0x400080007ff17fff", + "0x30", + "0x4824800180007ffd", + "0x2bc0", + "0x400080007fee7fff", + "0x48127fff7fff8000", "0x480680017fff8000", "0x0", - "0x482480017ff08000", + "0x482480017fec8000", "0x1", "0x480680017fff8000", "0x4465706c6f79", "0x400280007ffb7fff", "0x400280017ffb7ffc", - "0x400380027ffb8001", - "0x400380037ffb8000", - "0x400280047ffb7ff4", - "0x400280057ffb7ff5", + "0x400380027ffb8000", + "0x400380037ffb8001", + "0x400280047ffb7ff0", + "0x400280057ffb7ff1", "0x400280067ffb7ffd", "0x480280087ffb8000", "0x20680017fff7fff", - "0x10", + "0x11", + "0x480280077ffb8000", "0x40780017fff7fff", "0x1", "0x480280097ffb8000", "0x400080007ffe7fff", - "0x48127ffb7fff8000", - "0x480280077ffb8000", + "0x48127ffa7fff8000", + "0x48127ffc7fff8000", "0x482680017ffb8000", "0xc", "0x480680017fff8000", @@ -972,8 +1054,10 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x48127ffd7fff8000", "0x480280077ffb8000", + "0x48127ffc7fff8000", + "0x482480017ffe8000", + "0x12c", "0x482680017ffb8000", "0xb", "0x480680017fff8000", @@ -986,9 +1070,9 @@ "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482480017fee8000", + "0x482480017feb8000", "0x1", - "0x48127fee7fff8000", + "0x48127ff87fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -996,20 +1080,23 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x48127ff87fff8000", - "0x48127ff87fff8000", + "0x48127ff77fff8000", + "0x482480017ffe8000", + "0x492", "0x10780017fff7fff", - "0xc", - "0x48127ff87fff8000", + "0xe", "0x48127ff87fff8000", + "0x482480017ff88000", + "0x7b2", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", "0x48127ffa7fff8000", "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", - "0x48127ff77fff8000", - "0x48127fea7fff8000", + "0x48127ff47fff8000", + "0x482480017ffa8000", + "0x102c", "0x40780017fff7fff", "0x1", "0x480680017fff8000", @@ -1029,8 +1116,9 @@ "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202332", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127fef7fff8000", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x159a", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -1038,20 +1126,22 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x482480017ff48000", + "0x482480017ff18000", "0x3", + "0x482480017ff88000", + "0x159a", "0x10780017fff7fff", "0x5", - "0x40780017fff7fff", - "0x6", - "0x48127ff47fff8000", + "0x48127ff87fff8000", + "0x482480017ffa8000", + "0x1b12", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202331", "0x400080007ffe7fff", - "0x48127ffd7fff8000", - "0x48127fef7fff8000", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -1066,7 +1156,8 @@ "0x400080007ffe7fff", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x213e", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -1077,19 +1168,21 @@ "0xa0680017fff8000", "0x7", "0x482680017ff88000", - "0xfffffffffffffffffffffffffffff6be", + "0xfffffffffffffffffffffffffffff592", "0x400280007ff77fff", "0x10780017fff7fff", - "0x43", + "0x49", "0x4825800180007ff8", - "0x942", + "0xa6e", "0x400280007ff77fff", "0x482680017ff78000", "0x1", + "0x48127ffe7fff8000", "0x20780017fff7ffd", - "0xd", - "0x48127fff7fff8000", - "0x48127ffd7fff8000", + "0xe", + "0x48127ffe7fff8000", + "0x482480017ffe8000", + "0xad2", "0x480680017fff8000", "0x0", "0x480a7ff97fff8000", @@ -1099,11 +1192,13 @@ "0x480a7ffb7fff8000", "0x480a7ffc7fff8000", "0x208b7fff7fff7ffe", + "0x48127fff7fff8000", "0x48297ff980007ffa", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", + "0xb", + "0x48127ffe7fff8000", "0x482680017ff98000", "0x1", "0x480a7ffa7fff8000", @@ -1111,7 +1206,8 @@ "0x0", "0x480280007ff98000", "0x10780017fff7fff", - "0x8", + "0x9", + "0x48127ffe7fff8000", "0x480a7ff97fff8000", "0x480a7ffa7fff8000", "0x480680017fff8000", @@ -1121,8 +1217,8 @@ "0x20680017fff7ffe", "0xf", "0x400280007ffc7fff", + "0x48127ff77fff8000", "0x48127ffa7fff8000", - "0x48127ff87fff8000", "0x48127ffa7fff8000", "0x48127ffa7fff8000", "0x480a7ffb7fff8000", @@ -1131,10 +1227,11 @@ "0x4825800180007ffd", "0x1", "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffc9", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffc4", "0x208b7fff7fff7ffe", - "0x48127ffa7fff8000", - "0x48127ff87fff8000", + "0x48127ff77fff8000", + "0x482480017ffa8000", + "0x6ea", "0x480680017fff8000", "0x0", "0x48127ff97fff8000", @@ -1168,12 +1265,12 @@ "0x208b7fff7fff7ffe" ], "bytecode_segment_lengths": [ - 137, - 115, - 245, - 302, - 273, - 92 + 147, + 123, + 266, + 330, + 297, + 98 ], "hints": [ [ @@ -1199,7 +1296,7 @@ ] ], [ - 33, + 37, [ { "AllocSegment": { @@ -1212,7 +1309,7 @@ ] ], [ - 52, + 58, [ { "TestLessThanOrEqual": { @@ -1222,7 +1319,7 @@ "rhs": { "Deref": { "register": "AP", - "offset": -13 + "offset": -2 } }, "dst": { @@ -1234,7 +1331,7 @@ ] ], [ - 64, + 70, [ { "AllocSegment": { @@ -1247,7 +1344,7 @@ ] ], [ - 79, + 86, [ { "AllocSegment": { @@ -1260,7 +1357,7 @@ ] ], [ - 94, + 101, [ { "AllocSegment": { @@ -1273,7 +1370,7 @@ ] ], [ - 108, + 116, [ { "AllocSegment": { @@ -1286,7 +1383,7 @@ ] ], [ - 122, + 131, [ { "AllocSegment": { @@ -1299,7 +1396,7 @@ ] ], [ - 137, + 147, [ { "TestLessThanOrEqual": { @@ -1321,7 +1418,7 @@ ] ], [ - 162, + 175, [ { "AllocSegment": { @@ -1334,7 +1431,7 @@ ] ], [ - 181, + 196, [ { "TestLessThanOrEqual": { @@ -1344,7 +1441,7 @@ "rhs": { "Deref": { "register": "AP", - "offset": -10 + "offset": -2 } }, "dst": { @@ -1356,7 +1453,7 @@ ] ], [ - 193, + 208, [ { "AllocSegment": { @@ -1369,7 +1466,7 @@ ] ], [ - 208, + 224, [ { "AllocSegment": { @@ -1382,7 +1479,7 @@ ] ], [ - 223, + 239, [ { "AllocSegment": { @@ -1395,7 +1492,7 @@ ] ], [ - 237, + 254, [ { "AllocSegment": { @@ -1408,7 +1505,7 @@ ] ], [ - 252, + 270, [ { "TestLessThanOrEqual": { @@ -1430,14 +1527,14 @@ ] ], [ - 285, + 308, [ { "TestLessThan": { "lhs": { "Deref": { "register": "AP", - "offset": -1 + "offset": -2 } }, "rhs": { @@ -1452,7 +1549,7 @@ ] ], [ - 289, + 312, [ { "LinearSplit": { @@ -1481,14 +1578,14 @@ ] ], [ - 299, + 322, [ { "LinearSplit": { "value": { "Deref": { "register": "AP", - "offset": -2 + "offset": -3 } }, "scalar": { @@ -1510,7 +1607,7 @@ ] ], [ - 338, + 365, [ { "AllocSegment": { @@ -1523,7 +1620,7 @@ ] ], [ - 358, + 387, [ { "AllocSegment": { @@ -1536,7 +1633,7 @@ ] ], [ - 377, + 408, [ { "TestLessThanOrEqual": { @@ -1546,7 +1643,7 @@ "rhs": { "Deref": { "register": "AP", - "offset": -12 + "offset": -2 } }, "dst": { @@ -1558,7 +1655,7 @@ ] ], [ - 389, + 420, [ { "AllocSegment": { @@ -1571,7 +1668,7 @@ ] ], [ - 404, + 436, [ { "AllocSegment": { @@ -1584,7 +1681,7 @@ ] ], [ - 433, + 468, [ { "AllocSegment": { @@ -1597,7 +1694,7 @@ ] ], [ - 447, + 482, [ { "AllocSegment": { @@ -1610,7 +1707,7 @@ ] ], [ - 468, + 506, [ { "AllocSegment": { @@ -1623,7 +1720,7 @@ ] ], [ - 482, + 520, [ { "AllocSegment": { @@ -1636,7 +1733,7 @@ ] ], [ - 499, + 538, [ { "TestLessThanOrEqual": { @@ -1658,14 +1755,14 @@ ] ], [ - 533, + 577, [ { "TestLessThan": { "lhs": { "Deref": { "register": "FP", - "offset": 0 + "offset": 1 } }, "rhs": { @@ -1680,7 +1777,7 @@ ] ], [ - 537, + 581, [ { "LinearSplit": { @@ -1709,14 +1806,14 @@ ] ], [ - 547, + 591, [ { "LinearSplit": { "value": { "Deref": { "register": "FP", - "offset": 0 + "offset": 1 } }, "scalar": { @@ -1738,7 +1835,7 @@ ] ], [ - 587, + 635, [ { "AllocSegment": { @@ -1751,7 +1848,7 @@ ] ], [ - 607, + 657, [ { "AllocSegment": { @@ -1764,17 +1861,17 @@ ] ], [ - 626, + 678, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x4efc" + "Immediate": "0x558c" }, "rhs": { "Deref": { "register": "AP", - "offset": -12 + "offset": -2 } }, "dst": { @@ -1786,7 +1883,7 @@ ] ], [ - 644, + 697, [ { "SystemCall": { @@ -1801,14 +1898,14 @@ ] ], [ - 662, + 717, [ { "SystemCall": { "system": { "Deref": { "register": "AP", - "offset": -2 + "offset": -4 } } } @@ -1816,7 +1913,7 @@ ] ], [ - 683, + 740, [ { "AllocSegment": { @@ -1829,7 +1926,7 @@ ] ], [ - 706, + 766, [ { "AllocSegment": { @@ -1842,7 +1939,7 @@ ] ], [ - 735, + 798, [ { "AllocSegment": { @@ -1855,7 +1952,7 @@ ] ], [ - 749, + 812, [ { "AllocSegment": { @@ -1868,7 +1965,7 @@ ] ], [ - 770, + 836, [ { "AllocSegment": { @@ -1881,7 +1978,7 @@ ] ], [ - 784, + 850, [ { "AllocSegment": { @@ -1894,7 +1991,7 @@ ] ], [ - 801, + 868, [ { "TestLessThanOrEqual": { @@ -1916,14 +2013,14 @@ ] ], [ - 835, + 907, [ { "TestLessThan": { "lhs": { "Deref": { "register": "FP", - "offset": 1 + "offset": 0 } }, "rhs": { @@ -1938,7 +2035,7 @@ ] ], [ - 839, + 911, [ { "LinearSplit": { @@ -1967,14 +2064,14 @@ ] ], [ - 849, + 921, [ { "LinearSplit": { "value": { "Deref": { "register": "FP", - "offset": 1 + "offset": 0 } }, "scalar": { @@ -1996,7 +2093,7 @@ ] ], [ - 889, + 965, [ { "AllocSegment": { @@ -2009,7 +2106,7 @@ ] ], [ - 909, + 987, [ { "AllocSegment": { @@ -2022,17 +2119,17 @@ ] ], [ - 928, + 1008, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x25f8" + "Immediate": "0x2bc0" }, "rhs": { "Deref": { "register": "AP", - "offset": -12 + "offset": -2 } }, "dst": { @@ -2044,7 +2141,7 @@ ] ], [ - 953, + 1034, [ { "SystemCall": { @@ -2059,7 +2156,7 @@ ] ], [ - 956, + 1038, [ { "AllocSegment": { @@ -2072,7 +2169,7 @@ ] ], [ - 979, + 1063, [ { "AllocSegment": { @@ -2085,7 +2182,7 @@ ] ], [ - 1008, + 1095, [ { "AllocSegment": { @@ -2098,7 +2195,7 @@ ] ], [ - 1022, + 1109, [ { "AllocSegment": { @@ -2111,7 +2208,7 @@ ] ], [ - 1043, + 1133, [ { "AllocSegment": { @@ -2124,7 +2221,7 @@ ] ], [ - 1057, + 1147, [ { "AllocSegment": { @@ -2137,12 +2234,12 @@ ] ], [ - 1072, + 1163, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x942" + "Immediate": "0xa6e" }, "rhs": { "Deref": { @@ -2159,7 +2256,7 @@ ] ], [ - 1144, + 1241, [ { "AllocSegment": { @@ -2176,28 +2273,28 @@ "EXTERNAL": [ { "selector": "0x15d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad", - "offset": 497, + "offset": 536, "builtins": [ "range_check" ] }, { "selector": "0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775", - "offset": 252, + "offset": 270, "builtins": [ "range_check" ] }, { "selector": "0x2730079d734ee55315f4f141eaed376bddd8c2133523d223a344c5604e0f7f8", - "offset": 799, + "offset": 866, "builtins": [ "range_check" ] }, { "selector": "0x289da278a8dc833409cabfdad1581e8e7d40e42dcaed693fa4008dcdb4963b3", - "offset": 137, + "offset": 147, "builtins": [ "range_check" ] diff --git a/crates/blockifier/feature_contracts/cairo1/compiled/account_with_long_validate.casm.json b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/compiled/account_with_long_validate.casm.json similarity index 83% rename from crates/blockifier/feature_contracts/cairo1/compiled/account_with_long_validate.casm.json rename to crates/blockifier_test_utils/resources/feature_contracts/cairo1/compiled/account_with_long_validate.casm.json index 50e8e15a8b9..a19adace477 100644 --- a/crates/blockifier/feature_contracts/cairo1/compiled/account_with_long_validate.casm.json +++ b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/compiled/account_with_long_validate.casm.json @@ -1,6 +1,6 @@ { "prime": "0x800000000000011000000000000000000000000000000000000000000000001", - "compiler_version": "2.9.0", + "compiler_version": "2.11.0", "bytecode": [ "0xa0680017fff8000", "0x7", @@ -8,57 +8,64 @@ "0x100000000000000000000000000000000", "0x400280007ff97fff", "0x10780017fff7fff", - "0xbb", + "0xca", "0x4825800180007ffa", "0x0", "0x400280007ff97fff", "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0x13c4", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa3", + "0xaf", "0x482680017ffc8000", "0x1", "0x480a7ffd7fff8000", - "0x48307ffe80007fff", + "0x48127ffc7fff8000", + "0x48307ffd80007ffe", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x8d", - "0x482480017ffd8000", + "0x97", + "0x482480017ffc8000", "0x1", - "0x48127ffd7fff8000", - "0x48307ffe80007fff", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", + "0x48307ffd80007ffe", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x77", - "0x482480017ffd8000", + "0x7f", + "0x482480017ffc8000", "0x1", - "0x48127ffd7fff8000", - "0x480080007ffb8000", - "0x48307ffd80007ffe", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", + "0x480080007ff98000", + "0x48307ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x60", - "0x482480017ffc8000", + "0x66", + "0x482480017ffb8000", "0x1", - "0x48127ffc7fff8000", - "0x48307ffe80007fff", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x48307ffd80007ffe", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127fef7fff8000", - "0x48127fed7fff8000", + "0x48127fea7fff8000", + "0x482480017ffb8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -67,36 +74,39 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x490", + "0x4e1", "0x482480017fff8000", - "0x48f", - "0x480080007fff8000", + "0x4e0", + "0x48127ffb7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007feb", - "0x0", + "0x4824800180007ffd", + "0x87a", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007fea7fff", + "0x400080007fe47fff", "0x10780017fff7fff", - "0x2d", - "0x4824800180007feb", - "0x0", - "0x400080007feb7fff", - "0x482480017feb8000", + "0x30", + "0x4824800180007ffd", + "0x87a", + "0x400080007fe57fff", + "0x482480017fe58000", "0x1", - "0x20680017fff7ff4", - "0x6", - "0x48127fff7fff8000", - "0x48127ffd7fff8000", + "0x48127ffe7fff8000", + "0x20680017fff7ff1", + "0x7", + "0x48127ffe7fff8000", + "0x482480017ffe8000", + "0x6ea", "0x10780017fff7fff", "0xc", - "0x48127fff7fff8000", - "0x48127ffd7fff8000", + "0x48127ffe7fff8000", + "0x48127ffe7fff8000", "0x480680017fff8000", "0x989680", "0x1104800180018000", - "0x3eb", + "0x431", "0x20680017fff7ffd", "0x12", "0x48127ffb7fff8000", @@ -116,7 +126,8 @@ "0x1", "0x208b7fff7fff7ffe", "0x48127ffb7fff8000", - "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x1f4", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -128,9 +139,9 @@ "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482480017fe88000", + "0x482480017fe28000", "0x1", - "0x48127fe67fff8000", + "0x48127ff87fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -143,8 +154,9 @@ "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202334", "0x400080007ffe7fff", - "0x48127ff27fff8000", - "0x48127ff07fff8000", + "0x48127fee7fff8000", + "0x482480017ffa8000", + "0x622", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -157,8 +169,9 @@ "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202333", "0x400080007ffe7fff", - "0x48127ff67fff8000", - "0x48127ff47fff8000", + "0x48127ff37fff8000", + "0x482480017ffb8000", + "0x87a", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -171,8 +184,9 @@ "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202332", "0x400080007ffe7fff", - "0x48127ff97fff8000", "0x48127ff77fff8000", + "0x482480017ffb8000", + "0xa6e", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -185,8 +199,9 @@ "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202331", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127ffa7fff8000", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0xc62", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -201,7 +216,8 @@ "0x400080007ffe7fff", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x21b6", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -215,32 +231,36 @@ "0x100000000000000000000000000000000", "0x400280007ff97fff", "0x10780017fff7fff", - "0x6f", + "0x76", "0x4825800180007ffa", "0x0", "0x400280007ff97fff", "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0x1a04", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x57", + "0x5b", "0x482680017ffc8000", "0x1", "0x480a7ffd7fff8000", - "0x48307ffe80007fff", + "0x48127ffc7fff8000", + "0x48307ffd80007ffe", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ff97fff8000", "0x48127ff77fff8000", + "0x482480017ffb8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -249,29 +269,30 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x3da", + "0x41e", "0x482480017fff8000", - "0x3d9", - "0x480080007fff8000", + "0x41d", + "0x48127ffb7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007ff5", - "0x0", + "0x4824800180007ffd", + "0x686", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007ff47fff", + "0x400080007ff17fff", "0x10780017fff7fff", - "0x24", - "0x4824800180007ff5", - "0x0", - "0x400080007ff57fff", - "0x482480017ff58000", + "0x25", + "0x4824800180007ffd", + "0x686", + "0x400080007ff27fff", + "0x482480017ff28000", "0x1", "0x48127ffe7fff8000", "0x480680017fff8000", "0x989680", "0x1104800180018000", - "0x33c", + "0x377", "0x20680017fff7ffd", "0x10", "0x40780017fff7fff", @@ -289,7 +310,8 @@ "0x1", "0x208b7fff7fff7ffe", "0x48127ffb7fff8000", - "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x12c", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -301,9 +323,9 @@ "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482480017ff28000", + "0x482480017fef8000", "0x1", - "0x48127ff07fff8000", + "0x48127ff87fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -316,8 +338,9 @@ "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202331", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127ffa7fff8000", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x622", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -332,7 +355,8 @@ "0x400080007ffe7fff", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x21b6", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -346,17 +370,20 @@ "0x100000000000000000000000000000000", "0x400280007ff97fff", "0x10780017fff7fff", - "0x10f", + "0x11c", "0x4825800180007ffa", "0x0", "0x400280007ff97fff", "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0x2a8", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", + "0xb", + "0x48127ffe7fff8000", "0x482680017ffc8000", "0x1", "0x480a7ffd7fff8000", @@ -364,7 +391,8 @@ "0x0", "0x480280007ffc8000", "0x10780017fff7fff", - "0x8", + "0x9", + "0x48127ffe7fff8000", "0x480a7ffc7fff8000", "0x480a7ffd7fff8000", "0x480680017fff8000", @@ -372,54 +400,59 @@ "0x480680017fff8000", "0x0", "0x20680017fff7ffe", - "0xe4", + "0xed", + "0x48127ffb7fff8000", "0xa0680017fff8004", "0xe", - "0x4824800180047ffe", + "0x4824800180047ffd", "0x800000000000000000000000000000000000000000000000000000000000000", "0x484480017ffe8000", "0x110000000000000000", "0x48307ffe7fff8002", - "0x480080007ff67ffc", - "0x480080017ff57ffc", + "0x480080007ff37ffc", + "0x480080017ff27ffc", "0x402480017ffb7ffd", "0xffffffffffffffeeffffffffffffffff", - "0x400080027ff47ffd", + "0x400080027ff17ffd", "0x10780017fff7fff", - "0xd2", + "0xd8", "0x484480017fff8001", "0x8000000000000000000000000000000", - "0x48307fff80007ffd", - "0x480080007ff77ffd", - "0x480080017ff67ffd", + "0x48307fff80007ffc", + "0x480080007ff47ffd", + "0x480080017ff37ffd", "0x402480017ffc7ffe", "0xf8000000000000000000000000000000", - "0x400080027ff57ffe", - "0x482480017ff58000", + "0x400080027ff27ffe", + "0x482480017ff28000", "0x3", - "0x48307ff680007ff7", + "0x48127ff97fff8000", + "0x48307ff480007ff5", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xb5", - "0x482480017ff58000", + "0xb9", + "0x482480017ff38000", "0x1", - "0x48127ff57fff8000", - "0x48307ffe80007fff", + "0x48127ff37fff8000", + "0x48127ffc7fff8000", + "0x48307ffd80007ffe", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", - "0x482480017ffd8000", + "0xb", + "0x48127ffe7fff8000", + "0x482480017ffb8000", "0x1", - "0x48127ffd7fff8000", + "0x48127ffb7fff8000", "0x480680017fff8000", "0x0", - "0x48127ffa7fff8000", + "0x48127ff87fff8000", "0x10780017fff7fff", - "0x8", - "0x48127ffd7fff8000", - "0x48127ffd7fff8000", + "0x9", + "0x48127ffe7fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", "0x480680017fff8000", "0x1", "0x480680017fff8000", @@ -428,31 +461,34 @@ "0x8d", "0x40780017fff7fff", "0x1", - "0x48127ff67fff8000", - "0x48127fe97fff8000", + "0x48127ff37fff8000", + "0x48127ff97fff8000", "0x48127ff97fff8000", "0x48127ff97fff8000", "0x48127ffb7fff8000", "0x48127ffa7fff8000", "0x480080007ff88000", "0x1104800180018000", - "0x2c3", + "0x2f4", "0x20680017fff7ffa", - "0x78", - "0x20680017fff7ffd", - "0x72", - "0x48307ffb80007ffc", + "0x77", + "0x48127ff97fff8000", + "0x20680017fff7ffc", + "0x6f", + "0x48127fff7fff8000", + "0x48307ff980007ffa", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ff57fff8000", - "0x48127ff57fff8000", + "0x48127ff37fff8000", + "0x482480017ffb8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -461,51 +497,46 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x306", + "0x33a", "0x482480017fff8000", - "0x305", - "0x480080007fff8000", + "0x339", + "0x48127ffb7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007ff3", - "0x424", + "0x4824800180007ffd", + "0x8de", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007ff07fff", - "0x10780017fff7fff", - "0x42", - "0x4824800180007ff3", - "0x424", - "0x400080007ff17fff", - "0x480680017fff8000", - "0x0", - "0x48307ff680007ff7", - "0xa0680017fff8000", - "0x6", - "0x48307ffe80007ffd", - "0x400080017fed7fff", + "0x400080007fed7fff", "0x10780017fff7fff", - "0x23", - "0x482480017ffd8000", + "0x3c", + "0x4824800180007ffd", + "0x8de", + "0x400080007fee7fff", + "0x482480017fee8000", "0x1", - "0x48307fff80007ffd", - "0x400080017fec7fff", - "0x48307ffb7ff28000", - "0x482480017feb8000", - "0x2", - "0x48127ff87fff8000", - "0x480080007ffd8000", + "0x48127ffe7fff8000", + "0x48307ff280007ff3", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x1e", + "0x48127ffd7fff8000", + "0x48127ffd7fff8000", + "0x480080007fef8000", "0x1104800180018000", - "0x25b", + "0x28d", "0x20680017fff7ffd", - "0x10", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x56414c4944", "0x400080007ffe7fff", "0x48127ff97fff8000", - "0x48127ff97fff8000", + "0x482480017ff98000", + "0xc8", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x0", @@ -524,9 +555,9 @@ "0x480680017fff8000", "0x496e646578206f7574206f6620626f756e6473", "0x400080007ffe7fff", - "0x482480017feb8000", - "0x2", - "0x48127ff87fff8000", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x622", "0x48127ffc7fff8000", "0x482480017ffb8000", "0x1", @@ -543,9 +574,9 @@ "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482480017fee8000", + "0x482480017feb8000", "0x1", - "0x48127fee7fff8000", + "0x48127ff87fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -553,20 +584,23 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x48127ff87fff8000", - "0x48127ff87fff8000", + "0x48127ff77fff8000", + "0x482480017ffe8000", + "0x492", "0x10780017fff7fff", - "0xc", - "0x48127ff87fff8000", + "0xe", "0x48127ff87fff8000", + "0x482480017ff88000", + "0x7b2", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", "0x48127ffa7fff8000", "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", - "0x48127ff77fff8000", - "0x48127fea7fff8000", + "0x48127ff47fff8000", + "0x482480017ffa8000", + "0x102c", "0x40780017fff7fff", "0x1", "0x480680017fff8000", @@ -586,8 +620,9 @@ "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202332", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127fef7fff8000", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x1540", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -595,20 +630,22 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x482480017ff48000", + "0x482480017ff18000", "0x3", + "0x482480017ff88000", + "0x1540", "0x10780017fff7fff", "0x5", - "0x40780017fff7fff", - "0x6", - "0x48127ff47fff8000", + "0x48127ff87fff8000", + "0x482480017ffa8000", + "0x1a5e", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202331", "0x400080007ffe7fff", - "0x48127ffd7fff8000", - "0x48127fef7fff8000", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -623,7 +660,8 @@ "0x400080007ffe7fff", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x21b6", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -639,17 +677,20 @@ "0x100000000000000000000000000000000", "0x400280007ff97fff", "0x10780017fff7fff", - "0x11e", + "0x13a", "0x4825800180007ffa", "0x0", "0x400280007ff97fff", "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0x17c", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", + "0xb", + "0x48127ffe7fff8000", "0x482680017ffc8000", "0x1", "0x480a7ffd7fff8000", @@ -657,7 +698,8 @@ "0x0", "0x480280007ffc8000", "0x10780017fff7fff", - "0x8", + "0x9", + "0x48127ffe7fff8000", "0x480a7ffc7fff8000", "0x480a7ffd7fff8000", "0x480680017fff8000", @@ -665,89 +707,97 @@ "0x480680017fff8000", "0x0", "0x20680017fff7ffe", - "0xf3", - "0x40137fff7fff8000", + "0x10b", + "0x40137fff7fff8001", + "0x48127ffb7fff8000", "0xa0680017fff8004", "0xe", - "0x4825800180048000", + "0x4825800180048001", "0x800000000000000000000000000000000000000000000000000000000000000", "0x484480017ffe8000", "0x110000000000000000", "0x48307ffe7fff8002", - "0x480080007ff67ffc", - "0x480080017ff57ffc", + "0x480080007ff37ffc", + "0x480080017ff27ffc", "0x402480017ffb7ffd", "0xffffffffffffffeeffffffffffffffff", - "0x400080027ff47ffd", + "0x400080027ff17ffd", "0x10780017fff7fff", - "0xe0", + "0xf5", "0x484480017fff8001", "0x8000000000000000000000000000000", - "0x48317fff80008000", - "0x480080007ff77ffd", - "0x480080017ff67ffd", + "0x48317fff80008001", + "0x480080007ff47ffd", + "0x480080017ff37ffd", "0x402480017ffc7ffe", "0xf8000000000000000000000000000000", - "0x400080027ff57ffe", - "0x482480017ff58000", + "0x400080027ff27ffe", + "0x482480017ff28000", "0x3", - "0x48307ff680007ff7", + "0x48127ff97fff8000", + "0x48307ff480007ff5", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xc3", - "0x400180007ff58001", - "0x482480017ff58000", + "0xd6", + "0x400180007ff38000", + "0x482480017ff38000", "0x1", - "0x48127ff57fff8000", - "0x48307ffe80007fff", + "0x48127ff37fff8000", + "0x48127ffc7fff8000", + "0x48307ffd80007ffe", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", - "0x482480017ffd8000", + "0xb", + "0x48127ffe7fff8000", + "0x482480017ffb8000", "0x1", - "0x48127ffd7fff8000", + "0x48127ffb7fff8000", "0x480680017fff8000", "0x0", - "0x48127ffa7fff8000", + "0x48127ff87fff8000", "0x10780017fff7fff", - "0x8", - "0x48127ffd7fff8000", - "0x48127ffd7fff8000", + "0x9", + "0x48127ffe7fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", "0x480680017fff8000", "0x1", "0x480680017fff8000", "0x0", "0x20680017fff7ffe", - "0x9a", + "0xa9", "0x40780017fff7fff", "0x1", - "0x48127ff67fff8000", - "0x48127fe97fff8000", + "0x48127ff37fff8000", + "0x48127ff97fff8000", "0x48127ff97fff8000", "0x48127ff97fff8000", "0x48127ffb7fff8000", "0x48127ffa7fff8000", "0x480080007ff88000", "0x1104800180018000", - "0x19c", + "0x1bf", "0x20680017fff7ffa", - "0x85", - "0x20680017fff7ffd", - "0x7f", - "0x48307ffb80007ffc", + "0x93", + "0x48127ff97fff8000", + "0x20680017fff7ffc", + "0x8b", + "0x48127fff7fff8000", + "0x48307ff980007ffa", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ff57fff8000", - "0x48127ff57fff8000", + "0x48127ff37fff8000", + "0x482480017ffb8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -756,23 +806,25 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x1df", + "0x205", "0x482480017fff8000", - "0x1de", - "0x480080007fff8000", + "0x204", + "0x48127ffb7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007ff3", - "0x5028", + "0x4824800180007ffd", + "0x56b8", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007ff07fff", + "0x400080007fed7fff", "0x10780017fff7fff", - "0x4f", - "0x4824800180007ff3", - "0x5028", - "0x400080007ff17fff", - "0x482480017ff18000", + "0x58", + "0x4824800180007ffd", + "0x56b8", + "0x400080007fee7fff", + "0x48127fff7fff8000", + "0x482480017fed8000", "0x1", "0x480680017fff8000", "0x476574457865637574696f6e496e666f", @@ -780,42 +832,47 @@ "0x400280017ffb7ffd", "0x480280037ffb8000", "0x20680017fff7fff", - "0x3a", + "0x40", + "0x480280027ffb8000", "0x480280047ffb8000", "0x480080027fff8000", - "0x480280027ffb8000", "0x482680017ffb8000", "0x5", + "0x48127ffc7fff8000", "0x20680017fff7ffd", - "0x25", + "0x29", + "0x48127fff7fff8000", "0x480680017fff8000", "0x43616c6c436f6e7472616374", - "0x400080007ffe7fff", - "0x400080017ffe7ffd", - "0x400180027ffe8000", - "0x400180037ffe8001", - "0x400080047ffe7fef", - "0x400080057ffe7ff0", - "0x480080077ffe8000", + "0x400080007ffc7fff", + "0x400080017ffc7ffe", + "0x400180027ffc8001", + "0x400180037ffc8000", + "0x400080047ffc7fe9", + "0x400080057ffc7fea", + "0x480080077ffc8000", "0x20680017fff7fff", - "0xb", - "0x48127ff77fff8000", - "0x480080067ffc8000", - "0x482480017ffb8000", + "0xd", + "0x480080067ffb8000", + "0x48127ff47fff8000", + "0x482480017ffe8000", + "0x12c", + "0x482480017ff88000", "0xa", "0x480680017fff8000", "0x0", - "0x480080087ff98000", - "0x480080097ff88000", + "0x480080087ff68000", + "0x480080097ff58000", "0x208b7fff7fff7ffe", + "0x480080067ffb8000", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x526573756c743a3a756e77726170206661696c65642e", "0x400080007ffe7fff", - "0x48127ff57fff8000", - "0x480080067ffa8000", - "0x482480017ff98000", + "0x48127ff27fff8000", + "0x48127ffc7fff8000", + "0x482480017ff68000", "0xa", "0x480680017fff8000", "0x1", @@ -828,17 +885,20 @@ "0x480680017fff8000", "0x494e56414c49445f43414c4c4552", "0x400080007ffe7fff", - "0x48127ff77fff8000", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", + "0x48127ff67fff8000", + "0x482480017ffc8000", + "0x2b5c", + "0x48127ffa7fff8000", "0x480680017fff8000", "0x1", "0x48127ffa7fff8000", "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x48127ffd7fff8000", "0x480280027ffb8000", + "0x48127ffc7fff8000", + "0x482480017ffe8000", + "0x2e7c", "0x482680017ffb8000", "0x6", "0x480680017fff8000", @@ -851,9 +911,9 @@ "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482480017fee8000", + "0x482480017feb8000", "0x1", - "0x48127fee7fff8000", + "0x48127ff87fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -861,20 +921,23 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x48127ff87fff8000", - "0x48127ff87fff8000", + "0x48127ff77fff8000", + "0x482480017ffe8000", + "0x492", "0x10780017fff7fff", - "0xc", - "0x48127ff87fff8000", + "0xe", "0x48127ff87fff8000", + "0x482480017ff88000", + "0x7b2", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", "0x48127ffa7fff8000", "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", - "0x48127ff77fff8000", - "0x48127fea7fff8000", + "0x48127ff47fff8000", + "0x482480017ffa8000", + "0x102c", "0x40780017fff7fff", "0x1", "0x480680017fff8000", @@ -894,8 +957,9 @@ "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202332", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127fef7fff8000", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x159a", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -903,20 +967,22 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x482480017ff48000", + "0x482480017ff18000", "0x3", + "0x482480017ff88000", + "0x159a", "0x10780017fff7fff", "0x5", - "0x40780017fff7fff", - "0x6", - "0x48127ff47fff8000", + "0x48127ff87fff8000", + "0x482480017ffa8000", + "0x1b12", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202331", "0x400080007ffe7fff", - "0x48127ffd7fff8000", - "0x48127fef7fff8000", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -931,7 +997,8 @@ "0x400080007ffe7fff", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x213e", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -945,41 +1012,46 @@ "0x100000000000000000000000000000000", "0x400280007ff97fff", "0x10780017fff7fff", - "0x8b", + "0x97", "0x4825800180007ffa", "0x0", "0x400280007ff97fff", "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0x17ac", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x73", + "0x7c", "0x482680017ffc8000", "0x1", "0x480a7ffd7fff8000", - "0x48307ffe80007fff", + "0x48127ffc7fff8000", + "0x48307ffd80007ffe", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x5d", - "0x482480017ffd8000", + "0x64", + "0x482480017ffc8000", "0x1", - "0x48127ffd7fff8000", - "0x480080007ffb8000", - "0x48307ffd80007ffe", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", + "0x480080007ff98000", + "0x48307ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ff57fff8000", - "0x48127ff37fff8000", + "0x48127ff27fff8000", + "0x482480017ffa8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -988,27 +1060,29 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0xf7", + "0x107", "0x482480017fff8000", - "0xf6", - "0x480080007fff8000", + "0x106", + "0x48127ffa7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007ff1", - "0x1090", + "0x4824800180007ffd", + "0x2a94", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007ff07fff", + "0x400080007fec7fff", "0x10780017fff7fff", - "0x29", - "0x4824800180007ff1", - "0x1090", - "0x400080007ff17fff", + "0x2d", + "0x4824800180007ffd", + "0x2a94", + "0x400080007fed7fff", + "0x48127fff7fff8000", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x38077b29e57bba3aa860b08652a77bd1076d0f70e38f019ba9920b820cf78f6", - "0x482480017fef8000", + "0x482480017fea8000", "0x1", "0x480680017fff8000", "0x53746f726167655772697465", @@ -1016,14 +1090,15 @@ "0x400280017ffb7ffb", "0x400280027ffb7ffc", "0x400280037ffb7ffd", - "0x400280047ffb7ff4", + "0x400280047ffb7ff2", "0x480280067ffb8000", "0x20680017fff7fff", - "0xd", + "0xe", + "0x480280057ffb8000", "0x40780017fff7fff", "0x1", - "0x48127ffc7fff8000", - "0x480280057ffb8000", + "0x48127ffb7fff8000", + "0x48127ffd7fff8000", "0x482680017ffb8000", "0x7", "0x480680017fff8000", @@ -1031,8 +1106,10 @@ "0x48127ffb7fff8000", "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", - "0x48127ffd7fff8000", "0x480280057ffb8000", + "0x48127ffc7fff8000", + "0x482480017ffe8000", + "0x64", "0x482680017ffb8000", "0x9", "0x480680017fff8000", @@ -1045,9 +1122,9 @@ "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482480017fee8000", + "0x482480017fea8000", "0x1", - "0x48127fec7fff8000", + "0x48127ff87fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -1060,8 +1137,9 @@ "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202332", "0x400080007ffe7fff", - "0x48127ff97fff8000", "0x48127ff77fff8000", + "0x482480017ffb8000", + "0x686", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -1074,8 +1152,9 @@ "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202331", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127ffa7fff8000", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x87a", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -1090,7 +1169,8 @@ "0x400080007ffe7fff", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x21b6", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -1101,19 +1181,21 @@ "0xa0680017fff8000", "0x7", "0x482680017ffc8000", - "0xfffffffffffffffffffffffffffffbd2", + "0xfffffffffffffffffffffffffffffb6e", "0x400280007ffb7fff", "0x10780017fff7fff", - "0x19", + "0x1b", "0x4825800180007ffc", - "0x42e", + "0x492", "0x400280007ffb7fff", "0x482680017ffb8000", "0x1", + "0x48127ffe7fff8000", "0x20780017fff7ffd", - "0xb", - "0x48127fff7fff8000", - "0x48127ffd7fff8000", + "0xc", + "0x48127ffe7fff8000", + "0x482480017ffe8000", + "0x4f6", "0x480680017fff8000", "0x0", "0x480680017fff8000", @@ -1121,12 +1203,12 @@ "0x480680017fff8000", "0x0", "0x208b7fff7fff7ffe", - "0x48127fff7fff8000", - "0x48127ffd7fff8000", + "0x48127ffe7fff8000", + "0x48127ffe7fff8000", "0x4825800180007ffd", "0x1", "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffe6", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffe4", "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1", @@ -1145,19 +1227,21 @@ "0xa0680017fff8000", "0x7", "0x482680017ff88000", - "0xfffffffffffffffffffffffffffff6be", + "0xfffffffffffffffffffffffffffff592", "0x400280007ff77fff", "0x10780017fff7fff", - "0x43", + "0x49", "0x4825800180007ff8", - "0x942", + "0xa6e", "0x400280007ff77fff", "0x482680017ff78000", "0x1", + "0x48127ffe7fff8000", "0x20780017fff7ffd", - "0xd", - "0x48127fff7fff8000", - "0x48127ffd7fff8000", + "0xe", + "0x48127ffe7fff8000", + "0x482480017ffe8000", + "0xad2", "0x480680017fff8000", "0x0", "0x480a7ff97fff8000", @@ -1167,11 +1251,13 @@ "0x480a7ffb7fff8000", "0x480a7ffc7fff8000", "0x208b7fff7fff7ffe", + "0x48127fff7fff8000", "0x48297ff980007ffa", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", + "0xb", + "0x48127ffe7fff8000", "0x482680017ff98000", "0x1", "0x480a7ffa7fff8000", @@ -1179,7 +1265,8 @@ "0x0", "0x480280007ff98000", "0x10780017fff7fff", - "0x8", + "0x9", + "0x48127ffe7fff8000", "0x480a7ff97fff8000", "0x480a7ffa7fff8000", "0x480680017fff8000", @@ -1189,8 +1276,8 @@ "0x20680017fff7ffe", "0xf", "0x400280007ffc7fff", + "0x48127ff77fff8000", "0x48127ffa7fff8000", - "0x48127ff87fff8000", "0x48127ffa7fff8000", "0x48127ffa7fff8000", "0x480a7ffb7fff8000", @@ -1199,10 +1286,11 @@ "0x4825800180007ffd", "0x1", "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffc9", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffc4", "0x208b7fff7fff7ffe", - "0x48127ffa7fff8000", - "0x48127ff87fff8000", + "0x48127ff77fff8000", + "0x482480017ffa8000", + "0x6ea", "0x480680017fff8000", "0x0", "0x48127ff97fff8000", @@ -1236,13 +1324,13 @@ "0x208b7fff7fff7ffe" ], "bytecode_segment_lengths": [ - 207, - 131, - 291, - 308, - 159, - 44, - 92 + 223, + 139, + 305, + 337, + 172, + 46, + 98 ], "hints": [ [ @@ -1268,7 +1356,7 @@ ] ], [ - 50, + 56, [ { "AllocSegment": { @@ -1281,17 +1369,17 @@ ] ], [ - 69, + 77, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x0" + "Immediate": "0x87a" }, "rhs": { "Deref": { "register": "AP", - "offset": -20 + "offset": -2 } }, "dst": { @@ -1303,7 +1391,7 @@ ] ], [ - 99, + 109, [ { "AllocSegment": { @@ -1316,7 +1404,7 @@ ] ], [ - 121, + 132, [ { "AllocSegment": { @@ -1329,7 +1417,7 @@ ] ], [ - 136, + 147, [ { "AllocSegment": { @@ -1342,7 +1430,7 @@ ] ], [ - 150, + 162, [ { "AllocSegment": { @@ -1355,7 +1443,7 @@ ] ], [ - 164, + 177, [ { "AllocSegment": { @@ -1368,7 +1456,7 @@ ] ], [ - 178, + 192, [ { "AllocSegment": { @@ -1381,7 +1469,7 @@ ] ], [ - 192, + 207, [ { "AllocSegment": { @@ -1394,7 +1482,7 @@ ] ], [ - 207, + 223, [ { "TestLessThanOrEqual": { @@ -1416,7 +1504,7 @@ ] ], [ - 232, + 251, [ { "AllocSegment": { @@ -1429,17 +1517,17 @@ ] ], [ - 251, + 272, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x0" + "Immediate": "0x686" }, "rhs": { "Deref": { "register": "AP", - "offset": -10 + "offset": -2 } }, "dst": { @@ -1451,7 +1539,7 @@ ] ], [ - 272, + 293, [ { "AllocSegment": { @@ -1464,7 +1552,7 @@ ] ], [ - 294, + 316, [ { "AllocSegment": { @@ -1477,7 +1565,7 @@ ] ], [ - 309, + 331, [ { "AllocSegment": { @@ -1490,7 +1578,7 @@ ] ], [ - 323, + 346, [ { "AllocSegment": { @@ -1503,7 +1591,7 @@ ] ], [ - 338, + 362, [ { "TestLessThanOrEqual": { @@ -1525,14 +1613,14 @@ ] ], [ - 371, + 400, [ { "TestLessThan": { "lhs": { "Deref": { "register": "AP", - "offset": -1 + "offset": -2 } }, "rhs": { @@ -1547,7 +1635,7 @@ ] ], [ - 375, + 404, [ { "LinearSplit": { @@ -1576,14 +1664,14 @@ ] ], [ - 385, + 414, [ { "LinearSplit": { "value": { "Deref": { "register": "AP", - "offset": -2 + "offset": -3 } }, "scalar": { @@ -1605,7 +1693,7 @@ ] ], [ - 424, + 457, [ { "AllocSegment": { @@ -1618,7 +1706,7 @@ ] ], [ - 444, + 479, [ { "AllocSegment": { @@ -1631,44 +1719,19 @@ ] ], [ - 463, + 500, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x424" + "Immediate": "0x8de" }, "rhs": { - "Deref": { - "register": "AP", - "offset": -12 - } - }, - "dst": { - "register": "AP", - "offset": 0 - } - } - } - ] - ], - [ - 478, - [ - { - "TestLessThan": { - "lhs": { "Deref": { "register": "AP", "offset": -2 } }, - "rhs": { - "Deref": { - "register": "AP", - "offset": -1 - } - }, "dst": { "register": "AP", "offset": 0 @@ -1678,7 +1741,7 @@ ] ], [ - 497, + 527, [ { "AllocSegment": { @@ -1691,7 +1754,7 @@ ] ], [ - 517, + 548, [ { "AllocSegment": { @@ -1704,7 +1767,7 @@ ] ], [ - 536, + 567, [ { "AllocSegment": { @@ -1717,7 +1780,7 @@ ] ], [ - 565, + 599, [ { "AllocSegment": { @@ -1730,7 +1793,7 @@ ] ], [ - 579, + 613, [ { "AllocSegment": { @@ -1743,7 +1806,7 @@ ] ], [ - 600, + 637, [ { "AllocSegment": { @@ -1756,7 +1819,7 @@ ] ], [ - 614, + 651, [ { "AllocSegment": { @@ -1769,7 +1832,7 @@ ] ], [ - 631, + 669, [ { "TestLessThanOrEqual": { @@ -1791,14 +1854,14 @@ ] ], [ - 665, + 708, [ { "TestLessThan": { "lhs": { "Deref": { "register": "FP", - "offset": 0 + "offset": 1 } }, "rhs": { @@ -1813,7 +1876,7 @@ ] ], [ - 669, + 712, [ { "LinearSplit": { @@ -1842,14 +1905,14 @@ ] ], [ - 679, + 722, [ { "LinearSplit": { "value": { "Deref": { "register": "FP", - "offset": 0 + "offset": 1 } }, "scalar": { @@ -1871,7 +1934,7 @@ ] ], [ - 719, + 766, [ { "AllocSegment": { @@ -1884,7 +1947,7 @@ ] ], [ - 739, + 788, [ { "AllocSegment": { @@ -1897,17 +1960,17 @@ ] ], [ - 758, + 809, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x5028" + "Immediate": "0x56b8" }, "rhs": { "Deref": { "register": "AP", - "offset": -12 + "offset": -2 } }, "dst": { @@ -1919,7 +1982,7 @@ ] ], [ - 776, + 828, [ { "SystemCall": { @@ -1934,14 +1997,14 @@ ] ], [ - 794, + 848, [ { "SystemCall": { "system": { "Deref": { "register": "AP", - "offset": -2 + "offset": -4 } } } @@ -1949,7 +2012,7 @@ ] ], [ - 806, + 863, [ { "AllocSegment": { @@ -1962,7 +2025,7 @@ ] ], [ - 821, + 878, [ { "AllocSegment": { @@ -1975,7 +2038,7 @@ ] ], [ - 844, + 904, [ { "AllocSegment": { @@ -1988,7 +2051,7 @@ ] ], [ - 873, + 936, [ { "AllocSegment": { @@ -2001,7 +2064,7 @@ ] ], [ - 887, + 950, [ { "AllocSegment": { @@ -2014,7 +2077,7 @@ ] ], [ - 908, + 974, [ { "AllocSegment": { @@ -2027,7 +2090,7 @@ ] ], [ - 922, + 988, [ { "AllocSegment": { @@ -2040,7 +2103,7 @@ ] ], [ - 937, + 1004, [ { "TestLessThanOrEqual": { @@ -2062,7 +2125,7 @@ ] ], [ - 971, + 1042, [ { "AllocSegment": { @@ -2075,17 +2138,17 @@ ] ], [ - 990, + 1063, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x1090" + "Immediate": "0x2a94" }, "rhs": { "Deref": { "register": "AP", - "offset": -14 + "offset": -2 } }, "dst": { @@ -2097,7 +2160,7 @@ ] ], [ - 1015, + 1089, [ { "SystemCall": { @@ -2112,7 +2175,7 @@ ] ], [ - 1018, + 1093, [ { "AllocSegment": { @@ -2125,7 +2188,7 @@ ] ], [ - 1038, + 1115, [ { "AllocSegment": { @@ -2138,7 +2201,7 @@ ] ], [ - 1053, + 1130, [ { "AllocSegment": { @@ -2151,7 +2214,7 @@ ] ], [ - 1067, + 1145, [ { "AllocSegment": { @@ -2164,7 +2227,7 @@ ] ], [ - 1081, + 1160, [ { "AllocSegment": { @@ -2177,12 +2240,12 @@ ] ], [ - 1096, + 1176, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x42e" + "Immediate": "0x492" }, "rhs": { "Deref": { @@ -2199,7 +2262,7 @@ ] ], [ - 1126, + 1208, [ { "AllocSegment": { @@ -2212,12 +2275,12 @@ ] ], [ - 1140, + 1222, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x942" + "Immediate": "0xa6e" }, "rhs": { "Deref": { @@ -2234,7 +2297,7 @@ ] ], [ - 1212, + 1300, [ { "AllocSegment": { @@ -2251,21 +2314,21 @@ "EXTERNAL": [ { "selector": "0x15d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad", - "offset": 629, + "offset": 667, "builtins": [ "range_check" ] }, { "selector": "0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775", - "offset": 338, + "offset": 362, "builtins": [ "range_check" ] }, { "selector": "0x289da278a8dc833409cabfdad1581e8e7d40e42dcaed693fa4008dcdb4963b3", - "offset": 207, + "offset": 223, "builtins": [ "range_check" ] @@ -2282,7 +2345,7 @@ "CONSTRUCTOR": [ { "selector": "0x28ffe4ff0f226a9107253e17a904099aa4f63a02a5621de0576e5aa71bc5194", - "offset": 937, + "offset": 1004, "builtins": [ "range_check" ] diff --git a/crates/blockifier/feature_contracts/cairo1/compiled/cairo_steps_test_contract.casm.json b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/compiled/cairo_steps_test_contract.casm.json similarity index 100% rename from crates/blockifier/feature_contracts/cairo1/compiled/cairo_steps_test_contract.casm.json rename to crates/blockifier_test_utils/resources/feature_contracts/cairo1/compiled/cairo_steps_test_contract.casm.json diff --git a/crates/blockifier/feature_contracts/cairo1/compiled/empty_contract.casm.json b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/compiled/empty_contract.casm.json similarity index 88% rename from crates/blockifier/feature_contracts/cairo1/compiled/empty_contract.casm.json rename to crates/blockifier_test_utils/resources/feature_contracts/cairo1/compiled/empty_contract.casm.json index b50ce4c3bf9..dcd0f38daa0 100644 --- a/crates/blockifier/feature_contracts/cairo1/compiled/empty_contract.casm.json +++ b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/compiled/empty_contract.casm.json @@ -1,6 +1,6 @@ { "prime": "0x800000000000011000000000000000000000000000000000000000000000001", - "compiler_version": "2.9.0", + "compiler_version": "2.11.0", "bytecode": [], "bytecode_segment_lengths": 0, "hints": [], diff --git a/crates/blockifier/feature_contracts/cairo1/compiled/legacy_test_contract.casm.json b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/compiled/legacy_test_contract.casm.json similarity index 100% rename from crates/blockifier/feature_contracts/cairo1/compiled/legacy_test_contract.casm.json rename to crates/blockifier_test_utils/resources/feature_contracts/cairo1/compiled/legacy_test_contract.casm.json diff --git a/crates/blockifier_test_utils/resources/feature_contracts/cairo1/compiled/meta_tx_test_contract.casm.json b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/compiled/meta_tx_test_contract.casm.json new file mode 100644 index 00000000000..e0769e0fbbd --- /dev/null +++ b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/compiled/meta_tx_test_contract.casm.json @@ -0,0 +1,3020 @@ +{ + "prime": "0x800000000000011000000000000000000000000000000000000000000000001", + "compiler_version": "2.11.0", + "bytecode": [ + "0xa0680017fff8000", + "0x7", + "0x482680017ffa8000", + "0x100000000000000000000000000000000", + "0x400280007ff97fff", + "0x10780017fff7fff", + "0x7a", + "0x4825800180007ffa", + "0x0", + "0x400280007ff97fff", + "0x482680017ff98000", + "0x1", + "0x482480017ffe8000", + "0x1874", + "0x48297ffc80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x5e", + "0x482680017ffc8000", + "0x1", + "0x480a7ffd7fff8000", + "0x48127ffc7fff8000", + "0x480280007ffc8000", + "0x48307ffc80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x12", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", + "0x400080007ffe7fff", + "0x480a7ff87fff8000", + "0x48127ff57fff8000", + "0x482480017ff98000", + "0x55a", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0x1104800180018000", + "0x625", + "0x482480017fff8000", + "0x624", + "0x48127ffa7fff8000", + "0x480080007ffe8000", + "0x480080007fff8000", + "0x482480017fff8000", + "0x27ee8", + "0xa0680017fff8000", + "0x8", + "0x48307ffe80007ffb", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400080007fee7fff", + "0x10780017fff7fff", + "0x23", + "0x48307ffe80007ffb", + "0x400080007fef7fff", + "0x482480017fef8000", + "0x1", + "0x48127ffe7fff8000", + "0x480a7ff87fff8000", + "0x480a7ffb7fff8000", + "0x48127ff17fff8000", + "0x1104800180018000", + "0x19a", + "0x20680017fff7ffd", + "0xd", + "0x40780017fff7fff", + "0x1", + "0x48127ffa7fff8000", + "0x48127ff77fff8000", + "0x48127ff77fff8000", + "0x48127ff87fff8000", + "0x480680017fff8000", + "0x0", + "0x48127ffa7fff8000", + "0x48127ff97fff8000", + "0x208b7fff7fff7ffe", + "0x48127ffb7fff8000", + "0x48127ff87fff8000", + "0x482480017ff88000", + "0x64", + "0x48127ff97fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x480a7ff87fff8000", + "0x482480017feb8000", + "0x1", + "0x48127ff57fff8000", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4661696c656420746f20646573657269616c697a6520706172616d202331", + "0x400080007ffe7fff", + "0x480a7ff87fff8000", + "0x48127ffa7fff8000", + "0x482480017ffa8000", + "0x74e", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x480a7ff87fff8000", + "0x482680017ff98000", + "0x1", + "0x482680017ffa8000", + "0x2152", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0xa0680017fff8000", + "0x7", + "0x482680017ffa8000", + "0xffffffffffffffffffffffffffffe66a", + "0x400280007ff97fff", + "0x10780017fff7fff", + "0x13a", + "0x4825800180007ffa", + "0x1996", + "0x400280007ff97fff", + "0x482680017ff98000", + "0x1", + "0x48127ffe7fff8000", + "0x48297ffc80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xb", + "0x48127ffe7fff8000", + "0x482680017ffc8000", + "0x1", + "0x480a7ffd7fff8000", + "0x480680017fff8000", + "0x0", + "0x480280007ffc8000", + "0x10780017fff7fff", + "0x9", + "0x48127ffe7fff8000", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x20680017fff7ffe", + "0x10b", + "0x48127ffb7fff8000", + "0xa0680017fff8004", + "0xe", + "0x4824800180047ffd", + "0x800000000000000000000000000000000000000000000000000000000000000", + "0x484480017ffe8000", + "0x110000000000000000", + "0x48307ffe7fff8002", + "0x480080007ff37ffc", + "0x480080017ff27ffc", + "0x402480017ffb7ffd", + "0xffffffffffffffeeffffffffffffffff", + "0x400080027ff17ffd", + "0x10780017fff7fff", + "0xf6", + "0x484480017fff8001", + "0x8000000000000000000000000000000", + "0x48307fff80007ffc", + "0x480080007ff47ffd", + "0x480080017ff37ffd", + "0x402480017ffc7ffe", + "0xf8000000000000000000000000000000", + "0x400080027ff27ffe", + "0x482480017ff28000", + "0x3", + "0x48127ff97fff8000", + "0x48307ff480007ff5", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xd6", + "0x48127ffd7fff8000", + "0x482480017ff28000", + "0x1", + "0x48127ff27fff8000", + "0x1104800180018000", + "0x1df", + "0x48127fd97fff8000", + "0x480080007fcd8000", + "0x20680017fff7ff8", + "0xc2", + "0x48127ffe7fff8000", + "0x20680017fff7ffa", + "0xaf", + "0x48127ff67fff8000", + "0x48127ff77fff8000", + "0x48127ff77fff8000", + "0x1104800180018000", + "0x1d3", + "0x48127fda7fff8000", + "0x20680017fff7ff9", + "0x9d", + "0x48127fff7fff8000", + "0x20680017fff7ffb", + "0x8a", + "0x48127fff7fff8000", + "0x48307ff880007ff9", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x12", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", + "0x400080007ffe7fff", + "0x480a7ff87fff8000", + "0x48127ff27fff8000", + "0x482480017ffa8000", + "0x55a", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0x1104800180018000", + "0x551", + "0x482480017fff8000", + "0x550", + "0x48127ffb7fff8000", + "0x480080007ffe8000", + "0x480080007fff8000", + "0x482480017fff8000", + "0x2adc8", + "0xa0680017fff8000", + "0x8", + "0x48307ffe80007ffb", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400080007feb7fff", + "0x10780017fff7fff", + "0x53", + "0x48307ffe80007ffb", + "0x400080007fec7fff", + "0x48127fff7fff8000", + "0x482480017feb8000", + "0x1", + "0x480680017fff8000", + "0x4d65746154785630", + "0x400280007ffb7fff", + "0x400280017ffb7ffd", + "0x400280027ffb7f99", + "0x400280037ffb7fc9", + "0x400280047ffb7fc6", + "0x400280057ffb7fc7", + "0x400280067ffb7fee", + "0x400280077ffb7fef", + "0x480280097ffb8000", + "0x20680017fff7fff", + "0x22", + "0x480280087ffb8000", + "0x48127ffc7fff8000", + "0x48127ffe7fff8000", + "0x480a7ff87fff8000", + "0x482680017ffb8000", + "0xc", + "0x480680017fff8000", + "0x4e4f5f415247554d454e54", + "0x1104800180018000", + "0xb4", + "0x20680017fff7ffd", + "0xe", + "0x40780017fff7fff", + "0x1", + "0x48127ffa7fff8000", + "0x48127ff77fff8000", + "0x482480017ff78000", + "0x258", + "0x48127ff87fff8000", + "0x480680017fff8000", + "0x0", + "0x48127ffa7fff8000", + "0x48127ff97fff8000", + "0x208b7fff7fff7ffe", + "0x48127ffb7fff8000", + "0x48127ff87fff8000", + "0x48127ff87fff8000", + "0x48127ff97fff8000", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x10780017fff7fff", + "0x18", + "0x480280087ffb8000", + "0x1104800180018000", + "0x50d", + "0x482480017fff8000", + "0x50c", + "0x480080007fff8000", + "0x480080007fff8000", + "0x482480017fff8000", + "0x27d58", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x526573756c743a3a756e77726170206661696c65642e", + "0x400080007ffe7fff", + "0x480a7ff87fff8000", + "0x48127ff37fff8000", + "0x48307ffb7ff58000", + "0x482680017ffb8000", + "0xc", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x480a7ff87fff8000", + "0x482480017fe88000", + "0x1", + "0x48127ff57fff8000", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4661696c656420746f20646573657269616c697a6520706172616d202334", + "0x400080007ffe7fff", + "0x480a7ff87fff8000", + "0x48127ff47fff8000", + "0x482480017ffb8000", + "0x686", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0x480a7ff87fff8000", + "0x48127ff77fff8000", + "0x482480017ffd8000", + "0x87a", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ff87fff8000", + "0x48127ff87fff8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4661696c656420746f20646573657269616c697a6520706172616d202333", + "0x400080007ffe7fff", + "0x480a7ff87fff8000", + "0x48127ff37fff8000", + "0x482480017ffb8000", + "0x1bd0", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0x480a7ff87fff8000", + "0x48127ff67fff8000", + "0x482480017ffc8000", + "0x1dc4", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ff77fff8000", + "0x48127ff77fff8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4661696c656420746f20646573657269616c697a6520706172616d202332", + "0x400080007ffe7fff", + "0x480a7ff87fff8000", + "0x48127ffa7fff8000", + "0x482480017ffa8000", + "0x311a", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0x482480017ff18000", + "0x3", + "0x482480017ff88000", + "0x311a", + "0x10780017fff7fff", + "0x5", + "0x48127ff87fff8000", + "0x482480017ffa8000", + "0x3638", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4661696c656420746f20646573657269616c697a6520706172616d202331", + "0x400080007ffe7fff", + "0x480a7ff87fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x480a7ff87fff8000", + "0x482680017ff98000", + "0x1", + "0x482680017ffa8000", + "0x2152", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0x480680017fff8000", + "0x476574457865637574696f6e496e666f", + "0x400280007ffc7fff", + "0x400380017ffc7ffa", + "0x480280037ffc8000", + "0x20680017fff7fff", + "0xbc", + "0x480280027ffc8000", + "0x480280047ffc8000", + "0x480080017fff8000", + "0x480080037fff8000", + "0x480080047ffe8000", + "0x482680017ffc8000", + "0x5", + "0x48127ffa7fff8000", + "0x480080007ffb8000", + "0x480080017ffa8000", + "0x480080027ff98000", + "0x480080037ff88000", + "0x480080047ff78000", + "0x480080057ff68000", + "0x480080067ff58000", + "0x480080077ff48000", + "0x480080087ff38000", + "0x480080097ff28000", + "0x4800800a7ff18000", + "0x4800800b7ff08000", + "0x4800800c7fef8000", + "0x4800800d7fee8000", + "0x4800800e7fed8000", + "0x4800800f7fec8000", + "0x480080107feb8000", + "0x48307feb80007fec", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x6", + "0x48127fed7fff8000", + "0x480080007fe98000", + "0x10780017fff7fff", + "0x5", + "0x48127fed7fff8000", + "0x480680017fff8000", + "0x4e4f5f5349474e4154555245", + "0x480680017fff8000", + "0x476574457865637574696f6e496e666f", + "0x400080007fe97fff", + "0x400080017fe97ffd", + "0x480080037fe98000", + "0x20680017fff7fff", + "0x7b", + "0x480080027fe88000", + "0x480080047fe78000", + "0x48307ff080007ff1", + "0x480a7ff97fff8000", + "0x48127ffc7fff8000", + "0x480a7ffb7fff8000", + "0x482480017fe28000", + "0x5", + "0x480680017fff8000", + "0x36a4d0ecc8e01060df131b5f5774626c4b28788f6c84c50a387e5fc27d640e9", + "0x1104800180018000", + "0x152", + "0x480080007fc78000", + "0x480080017fc68000", + "0x480080027fc58000", + "0x480080037fc48000", + "0x480080047fc38000", + "0x4844800180007fc3", + "0x3", + "0x20680017fff7ff7", + "0x55", + "0xa0680017fff8005", + "0xe", + "0x4824800180057ff8", + "0x7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00", + "0x484480017ffe8000", + "0x110000000000000000", + "0x48307ffe7fff8003", + "0x480080007fef7ffc", + "0x480080017fee7ffc", + "0x482480017ffb7ffd", + "0xffffffffffffffeefffffffffffffeff", + "0x400080027fec7ffc", + "0x10780017fff7fff", + "0x11", + "0x48127ff87fff8005", + "0x484480017ffe8000", + "0x8000000000000000000000000000000", + "0x48307ffe7fff8003", + "0x480080007fef7ffd", + "0x482480017ffc7ffe", + "0xf0000000000000000000000000000100", + "0x480080017fed7ffd", + "0x400080027fec7ff9", + "0x402480017ffd7ff9", + "0xffffffffffffffffffffffffffffffff", + "0x20680017fff7ffd", + "0x4", + "0x402780017fff7fff", + "0x1", + "0x482480017fec8000", + "0x3", + "0x48127fec7fff8000", + "0x48127fed7fff8000", + "0x480680017fff8000", + "0x0", + "0x48127ffb7fff8000", + "0x48127ff07fff8000", + "0x48127f9e7fff8000", + "0x48127f9c7fff8000", + "0x480a7ffd7fff8000", + "0x48127f9f7fff8000", + "0x48127fac7fff8000", + "0x48127f9a7fff8000", + "0x48127fec7fff8000", + "0x48127f9d7fff8000", + "0x1104800180018000", + "0x20b", + "0x20680017fff7ffc", + "0x1a", + "0x48127ffa7fff8000", + "0x20680017fff7ffc", + "0x10", + "0x40780017fff7fff", + "0x5", + "0x48127ff37fff8000", + "0x482480017ff98000", + "0x1c2", + "0x48127f797fff8000", + "0x48127ff27fff8000", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x208b7fff7fff7ffe", + "0x48127ff87fff8000", + "0x48127ffe7fff8000", + "0x48127ff87fff8000", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x10780017fff7fff", + "0x14", + "0x40780017fff7fff", + "0x1", + "0x48127ff87fff8000", + "0x482480017ff88000", + "0x5a", + "0x48127ff87fff8000", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x10780017fff7fff", + "0xa", + "0x40780017fff7fff", + "0x75", + "0x48127f7e7fff8000", + "0x482480017f7e8000", + "0x1a48c", + "0x48127f7f7fff8000", + "0x48127f807fff8000", + "0x48127f807fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x48127f797fff8000", + "0x48127ffa7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0xb3", + "0x480080027f358000", + "0x1104800180018000", + "0x3c3", + "0x482480017fff8000", + "0x3c2", + "0x480080007fff8000", + "0x480080007fff8000", + "0x482480017fff8000", + "0x21322", + "0x480a7ff97fff8000", + "0x48307ffe7ff88000", + "0x480a7ffb7fff8000", + "0x482480017f2b8000", + "0x6", + "0x480680017fff8000", + "0x1", + "0x480080047f298000", + "0x480080057f288000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0xd0", + "0x480280027ffc8000", + "0x1104800180018000", + "0x3ae", + "0x482480017fff8000", + "0x3ad", + "0x480080007fff8000", + "0x480080007fff8000", + "0x482480017fff8000", + "0x24658", + "0x480a7ff97fff8000", + "0x48307ffe7ff88000", + "0x480a7ffb7fff8000", + "0x482680017ffc8000", + "0x6", + "0x480680017fff8000", + "0x1", + "0x480280047ffc8000", + "0x480280057ffc8000", + "0x208b7fff7fff7ffe", + "0x48297ffc80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xa", + "0x482680017ffc8000", + "0x1", + "0x480a7ffd7fff8000", + "0x480680017fff8000", + "0x0", + "0x480a7ffc7fff8000", + "0x10780017fff7fff", + "0x8", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x20680017fff7ffe", + "0x98", + "0x480080007fff8000", + "0xa0680017fff8000", + "0x12", + "0x4824800180007ffe", + "0x100000000", + "0x4844800180008002", + "0x8000000000000110000000000000000", + "0x4830800080017ffe", + "0x480280007ffb7fff", + "0x482480017ffe8000", + "0xefffffffffffffde00000000ffffffff", + "0x480280017ffb7fff", + "0x400280027ffb7ffb", + "0x402480017fff7ffb", + "0xffffffffffffffffffffffffffffffff", + "0x20680017fff7fff", + "0x78", + "0x402780017fff7fff", + "0x1", + "0x400280007ffb7ffe", + "0x482480017ffe8000", + "0xffffffffffffffffffffffff00000000", + "0x400280017ffb7fff", + "0x480680017fff8000", + "0x0", + "0x48307ff880007ff9", + "0x48307ffb7ffe8000", + "0xa0680017fff8000", + "0x8", + "0x482480017ffd8000", + "0x1", + "0x48307fff80007ffd", + "0x400280027ffb7fff", + "0x10780017fff7fff", + "0x51", + "0x48307ffe80007ffd", + "0x400280027ffb7fff", + "0x48307ff480007ff5", + "0x48307ffa7ff38000", + "0x48307ffb7ff28000", + "0x48307ff580017ffd", + "0xa0680017fff7fff", + "0x7", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400280037ffb7fff", + "0x10780017fff7fff", + "0x2f", + "0x400280037ffb7fff", + "0x48307fef80007ff0", + "0x48307ffe7ff28000", + "0xa0680017fff8000", + "0x8", + "0x482480017ffd8000", + "0x1", + "0x48307fff80007ffd", + "0x400280047ffb7fff", + "0x10780017fff7fff", + "0x11", + "0x48307ffe80007ffd", + "0x400280047ffb7fff", + "0x40780017fff7fff", + "0x3", + "0x482680017ffb8000", + "0x5", + "0x480680017fff8000", + "0x0", + "0x48307fea7fe68000", + "0x48307ff77fe58000", + "0x480680017fff8000", + "0x0", + "0x48127ff07fff8000", + "0x48127ff07fff8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x496e646578206f7574206f6620626f756e6473", + "0x400080007ffe7fff", + "0x482680017ffb8000", + "0x5", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x4", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x7533325f737562204f766572666c6f77", + "0x400080007ffe7fff", + "0x482680017ffb8000", + "0x4", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x9", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x496e646578206f7574206f6620626f756e6473", + "0x400080007ffe7fff", + "0x482680017ffb8000", + "0x3", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0xc", + "0x482680017ffb8000", + "0x3", + "0x480680017fff8000", + "0x0", + "0x48127fe67fff8000", + "0x48127fe67fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x14", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x0", + "0x48127fe67fff8000", + "0x48127fe67fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x208b7fff7fff7ffe", + "0xa0680017fff8005", + "0xe", + "0x4825800180057ffd", + "0x7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00", + "0x484480017ffe8000", + "0x110000000000000000", + "0x48307ffe7fff8003", + "0x480280007ff97ffc", + "0x480280017ff97ffc", + "0x482480017ffb7ffd", + "0xffffffffffffffeefffffffffffffeff", + "0x400280027ff97ffc", + "0x10780017fff7fff", + "0x11", + "0x480a7ffd7fff8005", + "0x484480017ffe8000", + "0x8000000000000000000000000000000", + "0x48307ffe7fff8003", + "0x480280007ff97ffd", + "0x482480017ffc7ffe", + "0xf0000000000000000000000000000100", + "0x480280017ff97ffd", + "0x400280027ff97ff9", + "0x402480017ffd7ff9", + "0xffffffffffffffffffffffffffffffff", + "0x20680017fff7ffd", + "0x4", + "0x402780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x0", + "0x482680017ff98000", + "0x3", + "0x480680017fff8000", + "0x53746f7261676552656164", + "0x400280007ffc7fff", + "0x400380017ffc7ffa", + "0x400280027ffc7ffd", + "0x400280037ffc7ffc", + "0x480280057ffc8000", + "0x20680017fff7fff", + "0xaf", + "0x480280047ffc8000", + "0x480280067ffc8000", + "0x482680017ffc8000", + "0x7", + "0x48127ffd7fff8000", + "0xa0680017fff8000", + "0x12", + "0x4824800180007ffc", + "0x10000000000000000", + "0x4844800180008002", + "0x8000000000000110000000000000000", + "0x4830800080017ffe", + "0x480080007ff57fff", + "0x482480017ffe8000", + "0xefffffffffffffdeffffffffffffffff", + "0x480080017ff37fff", + "0x400080027ff27ffb", + "0x402480017fff7ffb", + "0xffffffffffffffffffffffffffffffff", + "0x20680017fff7fff", + "0x82", + "0x402780017fff7fff", + "0x1", + "0x400080007ff87ffc", + "0x482480017ffc8000", + "0xffffffffffffffff0000000000000000", + "0x400080017ff77fff", + "0xa0680017fff8005", + "0xe", + "0x4825800180057ffd", + "0x7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00", + "0x484480017ffe8000", + "0x110000000000000000", + "0x48307ffe7fff8003", + "0x480080027ff37ffc", + "0x480080037ff27ffc", + "0x482480017ffb7ffd", + "0xffffffffffffffeefffffffffffffeff", + "0x400080047ff07ffc", + "0x10780017fff7fff", + "0x11", + "0x480a7ffd7fff8005", + "0x484480017ffe8000", + "0x8000000000000000000000000000000", + "0x48307ffe7fff8003", + "0x480080027ff37ffd", + "0x482480017ffc7ffe", + "0xf0000000000000000000000000000100", + "0x480080037ff17ffd", + "0x400080047ff07ff9", + "0x402480017ffd7ff9", + "0xffffffffffffffffffffffffffffffff", + "0x20680017fff7ffd", + "0x4", + "0x402780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x1", + "0x48127ff57fff8000", + "0xa0680017fff8000", + "0x8", + "0x48307ffd7ff18000", + "0x4824800180007fff", + "0x10000000000000000", + "0x400080057feb7fff", + "0x10780017fff7fff", + "0x3a", + "0x48307ffd7ff18001", + "0x4824800180007fff", + "0xffffffffffffffff0000000000000000", + "0x400080057feb7ffe", + "0x48127ffc7fff8000", + "0x480680017fff8000", + "0x0", + "0x482480017fe98000", + "0x6", + "0x480680017fff8000", + "0x53746f726167655772697465", + "0x400080007fec7fff", + "0x400080017fec7ffc", + "0x400080027fec7ffd", + "0x400080037fec7ff6", + "0x400080047fec7ffb", + "0x480080067fec8000", + "0x20680017fff7fff", + "0x14", + "0x40780017fff7fff", + "0x6", + "0x480080057fe58000", + "0x400380007ffb7ffd", + "0x400280017ffb7fe3", + "0x48127ff67fff8000", + "0x482480017ffe8000", + "0xf0", + "0x482680017ffb8000", + "0x3", + "0x482480017fe18000", + "0x7", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480280027ffb8000", + "0x208b7fff7fff7ffe", + "0x480080057feb8000", + "0x1104800180018000", + "0x250", + "0x482480017fff8000", + "0x24f", + "0x480080007fff8000", + "0x480080007fff8000", + "0x482480017fff8000", + "0x0", + "0x48127ff67fff8000", + "0x48307ffe7ff88000", + "0x480a7ffb7fff8000", + "0x482480017fe18000", + "0x9", + "0x480680017fff8000", + "0x1", + "0x480080077fdf8000", + "0x480080087fde8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x4", + "0x1104800180018000", + "0x23c", + "0x482480017fff8000", + "0x23b", + "0x480080007fff8000", + "0x480080007fff8000", + "0x482480017fff8000", + "0x29a4", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x7536345f616464204f766572666c6f77", + "0x400080007ffe7fff", + "0x482480017fdf8000", + "0x6", + "0x48307ffc7fef8000", + "0x480a7ffb7fff8000", + "0x48127fe17fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x6", + "0x1104800180018000", + "0x222", + "0x482480017fff8000", + "0x221", + "0x480080007fff8000", + "0x480080007fff8000", + "0x482480017fff8000", + "0x2c56", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x53746f7265553634202d206e6f6e20753634", + "0x400080007ffe7fff", + "0x482480017fe48000", + "0x3", + "0x48307ffc7fe98000", + "0x48127fe77fff8000", + "0x48127ffb7fff8000", + "0x482480017ffa8000", + "0x1", + "0x10780017fff7fff", + "0x13", + "0x40780017fff7fff", + "0x12", + "0x480280047ffc8000", + "0x1104800180018000", + "0x209", + "0x482480017fff8000", + "0x208", + "0x480080007fff8000", + "0x480080007fff8000", + "0x482480017fff8000", + "0x3354", + "0x48127fe47fff8000", + "0x48307ffe7ff88000", + "0x482680017ffc8000", + "0x8", + "0x480280067ffc8000", + "0x480280077ffc8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x480a7ffb7fff8000", + "0x48127ffa7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x208b7fff7fff7ffe", + "0x480680017fff8000", + "0x53746f726167655772697465", + "0x400280007ff27fff", + "0x400380017ff27ff1", + "0x400380027ff27ff3", + "0x400380037ff27ff4", + "0x400380047ff27ff5", + "0x480280067ff28000", + "0x20680017fff7fff", + "0x1db", + "0x480280057ff28000", + "0x48127fff7fff8000", + "0x482680017ff48000", + "0x1", + "0x480680017fff8000", + "0x53746f726167655772697465", + "0x400280077ff27fff", + "0x400280087ff27ffd", + "0x400380097ff27ff3", + "0x4002800a7ff27ffe", + "0x4003800b7ff27ff6", + "0x4802800d7ff28000", + "0x20680017fff7fff", + "0x1be", + "0x4802800c7ff28000", + "0x48127fff7fff8000", + "0x482680017ff48000", + "0x2", + "0x480680017fff8000", + "0x53746f726167655772697465", + "0x4002800e7ff27fff", + "0x4002800f7ff27ffd", + "0x400380107ff27ff3", + "0x400280117ff27ffe", + "0x400380127ff27ff7", + "0x480280147ff28000", + "0x20680017fff7fff", + "0x1a1", + "0x480280137ff28000", + "0x480680017fff8000", + "0x2", + "0x480680017fff8000", + "0x1", + "0x482680017ff28000", + "0x15", + "0x48127ffc7fff8000", + "0xa0680017fff8000", + "0x8", + "0x48307ffc7ffb8000", + "0x4824800180007fff", + "0x100", + "0x400280007ff07fff", + "0x10780017fff7fff", + "0x17d", + "0x48307ffc7ffb8001", + "0x4824800180007fff", + "0xffffffffffffffffffffffffffffff00", + "0x400280007ff07ffe", + "0x48127ffc7fff8000", + "0x48327ffe7ff48000", + "0x482680017ff08000", + "0x1", + "0x480680017fff8000", + "0x53746f726167655772697465", + "0x400080007ff77fff", + "0x400080017ff77ffc", + "0x400180027ff77ff3", + "0x400080037ff77ffd", + "0x400180047ff77ff8", + "0x480080067ff78000", + "0x20680017fff7fff", + "0x15c", + "0x480080057ff68000", + "0x480680017fff8000", + "0x1", + "0x482480017ff48000", + "0x7", + "0x48127ffd7fff8000", + "0xa0680017fff8000", + "0x8", + "0x48307ffc7ff58000", + "0x4824800180007fff", + "0x100", + "0x400080007ff67fff", + "0x10780017fff7fff", + "0x13a", + "0x48307ffc7ff58001", + "0x4824800180007fff", + "0xffffffffffffffffffffffffffffff00", + "0x400080007ff67ffe", + "0x48127ffc7fff8000", + "0x48327ffe7ff48000", + "0x482480017ff48000", + "0x1", + "0x480680017fff8000", + "0x53746f726167655772697465", + "0x400080007ff77fff", + "0x400080017ff77ffc", + "0x400180027ff77ff3", + "0x400080037ff77ffd", + "0x400180047ff77ff9", + "0x480080067ff78000", + "0x20680017fff7fff", + "0x119", + "0x480080057ff68000", + "0x480680017fff8000", + "0x1", + "0x482480017ff48000", + "0x7", + "0x48127ffd7fff8000", + "0xa0680017fff8000", + "0x8", + "0x48307ffc7ff58000", + "0x4824800180007fff", + "0x100", + "0x400080007ff67fff", + "0x10780017fff7fff", + "0xf7", + "0x48307ffc7ff58001", + "0x4824800180007fff", + "0xffffffffffffffffffffffffffffff00", + "0x400080007ff67ffe", + "0x48127ffc7fff8000", + "0x48327ffe7ff48000", + "0x482480017ff48000", + "0x1", + "0x480680017fff8000", + "0x53746f726167655772697465", + "0x400080007ff77fff", + "0x400080017ff77ffc", + "0x400180027ff77ff3", + "0x400080037ff77ffd", + "0x400180047ff77ffa", + "0x480080067ff78000", + "0x20680017fff7fff", + "0xd6", + "0x480080057ff68000", + "0x480680017fff8000", + "0x1", + "0x482480017ff48000", + "0x7", + "0x48127ffd7fff8000", + "0xa0680017fff8000", + "0x8", + "0x48307ffc7ff58000", + "0x4824800180007fff", + "0x100", + "0x400080007ff67fff", + "0x10780017fff7fff", + "0xb4", + "0x48307ffc7ff58001", + "0x4824800180007fff", + "0xffffffffffffffffffffffffffffff00", + "0x400080007ff67ffe", + "0x48127ffc7fff8000", + "0x48327ffe7ff48000", + "0x482480017ff48000", + "0x1", + "0x480680017fff8000", + "0x53746f726167655772697465", + "0x400080007ff77fff", + "0x400080017ff77ffc", + "0x400180027ff77ff3", + "0x400080037ff77ffd", + "0x400180047ff77ffb", + "0x480080067ff78000", + "0x20680017fff7fff", + "0x93", + "0x480080057ff68000", + "0x480680017fff8000", + "0x1", + "0x482480017ff48000", + "0x7", + "0x48127ffd7fff8000", + "0xa0680017fff8000", + "0x8", + "0x48307ffc7ff58000", + "0x4824800180007fff", + "0x100", + "0x400080007ff67fff", + "0x10780017fff7fff", + "0x71", + "0x48307ffc7ff58001", + "0x4824800180007fff", + "0xffffffffffffffffffffffffffffff00", + "0x400080007ff67ffe", + "0x48127ffc7fff8000", + "0x48327ffe7ff48000", + "0x482480017ff48000", + "0x1", + "0x480680017fff8000", + "0x53746f726167655772697465", + "0x400080007ff77fff", + "0x400080017ff77ffc", + "0x400180027ff77ff3", + "0x400080037ff77ffd", + "0x400180047ff77ffc", + "0x480080067ff78000", + "0x20680017fff7fff", + "0x50", + "0x480080057ff68000", + "0x480680017fff8000", + "0x1", + "0x482480017ff48000", + "0x7", + "0x48127ffd7fff8000", + "0xa0680017fff8000", + "0x8", + "0x48307ffc7ff58000", + "0x4824800180007fff", + "0x100", + "0x400080007ff67fff", + "0x10780017fff7fff", + "0x2e", + "0x48307ffc7ff58001", + "0x4824800180007fff", + "0xffffffffffffffffffffffffffffff00", + "0x400080007ff67ffe", + "0x48127ffc7fff8000", + "0x48327ffe7ff48000", + "0x482480017ff48000", + "0x1", + "0x480680017fff8000", + "0x53746f726167655772697465", + "0x400080007ff77fff", + "0x400080017ff77ffc", + "0x400180027ff77ff3", + "0x400080037ff77ffd", + "0x400180047ff77ffd", + "0x480080067ff78000", + "0x20680017fff7fff", + "0x10", + "0x480080057ff68000", + "0x48127ffc7fff8000", + "0x48127ffe7fff8000", + "0x482480017ff38000", + "0x7", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x208b7fff7fff7ffe", + "0x480080057ff68000", + "0x48127ffc7fff8000", + "0x48127ffe7fff8000", + "0x482480017ff38000", + "0x9", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x1", + "0x480080077ff08000", + "0x480080087fef8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x4", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x75385f616464204f766572666c6f77", + "0x400080007ffe7fff", + "0x482480017ff08000", + "0x1", + "0x482480017ff58000", + "0x29a4", + "0x48127ff37fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0xc", + "0x480080057fea8000", + "0x48127ff07fff8000", + "0x482480017ffe8000", + "0x2de6", + "0x482480017fe78000", + "0x9", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x1", + "0x480080077fe48000", + "0x480080087fe38000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x10", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x75385f616464204f766572666c6f77", + "0x400080007ffe7fff", + "0x482480017fe48000", + "0x1", + "0x482480017fe98000", + "0x57ee", + "0x48127fe77fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x18", + "0x480080057fde8000", + "0x48127fe47fff8000", + "0x482480017ffe8000", + "0x5c30", + "0x482480017fdb8000", + "0x9", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x1", + "0x480080077fd88000", + "0x480080087fd78000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1c", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x75385f616464204f766572666c6f77", + "0x400080007ffe7fff", + "0x482480017fd88000", + "0x1", + "0x482480017fdd8000", + "0x8638", + "0x48127fdb7fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x24", + "0x480080057fd28000", + "0x48127fd87fff8000", + "0x482480017ffe8000", + "0x8a7a", + "0x482480017fcf8000", + "0x9", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x1", + "0x480080077fcc8000", + "0x480080087fcb8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x28", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x75385f616464204f766572666c6f77", + "0x400080007ffe7fff", + "0x482480017fcc8000", + "0x1", + "0x482480017fd18000", + "0xb482", + "0x48127fcf7fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x30", + "0x480080057fc68000", + "0x48127fcc7fff8000", + "0x482480017ffe8000", + "0xb8c4", + "0x482480017fc38000", + "0x9", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x1", + "0x480080077fc08000", + "0x480080087fbf8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x34", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x75385f616464204f766572666c6f77", + "0x400080007ffe7fff", + "0x482480017fc08000", + "0x1", + "0x482480017fc58000", + "0xe2cc", + "0x48127fc37fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x3c", + "0x480080057fba8000", + "0x48127fc07fff8000", + "0x482480017ffe8000", + "0xe70e", + "0x482480017fb78000", + "0x9", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x1", + "0x480080077fb48000", + "0x480080087fb38000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x40", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x75385f616464204f766572666c6f77", + "0x400080007ffe7fff", + "0x482680017ff08000", + "0x1", + "0x482480017fb98000", + "0x11116", + "0x48127fb77fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x49", + "0x480280137ff28000", + "0x480a7ff07fff8000", + "0x482480017ffe8000", + "0x115b2", + "0x482680017ff28000", + "0x17", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x1", + "0x480280157ff28000", + "0x480280167ff28000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x4e", + "0x4802800c7ff28000", + "0x480a7ff07fff8000", + "0x482480017ffe8000", + "0x140dc", + "0x482680017ff28000", + "0x10", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x1", + "0x4802800e7ff28000", + "0x4802800f7ff28000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x53", + "0x480280057ff28000", + "0x480a7ff07fff8000", + "0x482480017ffe8000", + "0x16c06", + "0x482680017ff28000", + "0x9", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x1", + "0x480280077ff28000", + "0x480280087ff28000", + "0x208b7fff7fff7ffe" + ], + "bytecode_segment_lengths": [ + 144, + 336, + 214, + 185, + 241, + 498 + ], + "hints": [ + [ + 0, + [ + { + "TestLessThanOrEqual": { + "lhs": { + "Immediate": "0x0" + }, + "rhs": { + "Deref": { + "register": "FP", + "offset": -6 + } + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 29, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 54, + [ + { + "TestLessThanOrEqual": { + "lhs": { + "Deref": { + "register": "AP", + "offset": -1 + } + }, + "rhs": { + "Deref": { + "register": "AP", + "offset": -4 + } + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 74, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 95, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 111, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 127, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 144, + [ + { + "TestLessThanOrEqual": { + "lhs": { + "Immediate": "0x1996" + }, + "rhs": { + "Deref": { + "register": "FP", + "offset": -6 + } + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 181, + [ + { + "TestLessThan": { + "lhs": { + "Deref": { + "register": "AP", + "offset": -2 + } + }, + "rhs": { + "Immediate": "0x800000000000000000000000000000000000000000000000000000000000000" + }, + "dst": { + "register": "AP", + "offset": 4 + } + } + } + ] + ], + [ + 185, + [ + { + "LinearSplit": { + "value": { + "Deref": { + "register": "AP", + "offset": 3 + } + }, + "scalar": { + "Immediate": "0x110000000000000000" + }, + "max_x": { + "Immediate": "0xffffffffffffffffffffffffffffffff" + }, + "x": { + "register": "AP", + "offset": -2 + }, + "y": { + "register": "AP", + "offset": -1 + } + } + } + ] + ], + [ + 195, + [ + { + "LinearSplit": { + "value": { + "Deref": { + "register": "AP", + "offset": -3 + } + }, + "scalar": { + "Immediate": "0x8000000000000000000000000000000" + }, + "max_x": { + "Immediate": "0xffffffffffffffffffffffffffffffff" + }, + "x": { + "register": "AP", + "offset": -1 + }, + "y": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 241, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 266, + [ + { + "TestLessThanOrEqual": { + "lhs": { + "Deref": { + "register": "AP", + "offset": -1 + } + }, + "rhs": { + "Deref": { + "register": "AP", + "offset": -4 + } + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 289, + [ + { + "SystemCall": { + "system": { + "Deref": { + "register": "FP", + "offset": -5 + } + } + } + } + ] + ], + [ + 304, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 333, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 355, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 371, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 397, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 423, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 448, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 463, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 484, + [ + { + "SystemCall": { + "system": { + "Deref": { + "register": "FP", + "offset": -4 + } + } + } + } + ] + ], + [ + 528, + [ + { + "SystemCall": { + "system": { + "Deref": { + "register": "AP", + "offset": -23 + } + } + } + } + ] + ], + [ + 552, + [ + { + "TestLessThan": { + "lhs": { + "Deref": { + "register": "AP", + "offset": -7 + } + }, + "rhs": { + "Immediate": "0x7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00" + }, + "dst": { + "register": "AP", + "offset": 5 + } + } + } + ] + ], + [ + 556, + [ + { + "LinearSplit": { + "value": { + "Deref": { + "register": "AP", + "offset": 4 + } + }, + "scalar": { + "Immediate": "0x110000000000000000" + }, + "max_x": { + "Immediate": "0xffffffffffffffffffffffffffffffff" + }, + "x": { + "register": "AP", + "offset": -2 + }, + "y": { + "register": "AP", + "offset": -1 + } + } + } + ] + ], + [ + 567, + [ + { + "LinearSplit": { + "value": { + "Deref": { + "register": "AP", + "offset": 4 + } + }, + "scalar": { + "Immediate": "0x8000000000000000000000000000000" + }, + "max_x": { + "Immediate": "0xfffffffffffffffffffffffffffffffe" + }, + "x": { + "register": "AP", + "offset": -2 + }, + "y": { + "register": "AP", + "offset": -1 + } + } + } + ] + ], + [ + 716, + [ + { + "TestLessThan": { + "lhs": { + "BinOp": { + "op": "Add", + "a": { + "register": "AP", + "offset": -1 + }, + "b": { + "Immediate": "0x0" + } + } + }, + "rhs": { + "Immediate": "0x100000000" + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 720, + [ + { + "LinearSplit": { + "value": { + "Deref": { + "register": "AP", + "offset": -1 + } + }, + "scalar": { + "Immediate": "0x8000000000000110000000000000000" + }, + "max_x": { + "Immediate": "0xfffffffffffffffffffffffffffffffe" + }, + "x": { + "register": "AP", + "offset": 0 + }, + "y": { + "register": "AP", + "offset": 1 + } + } + } + ] + ], + [ + 742, + [ + { + "TestLessThanOrEqual": { + "lhs": { + "Deref": { + "register": "AP", + "offset": -1 + } + }, + "rhs": { + "Deref": { + "register": "AP", + "offset": -2 + } + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 756, + [ + { + "TestLessThan": { + "lhs": { + "Deref": { + "register": "AP", + "offset": 0 + } + }, + "rhs": { + "Immediate": "0x100000000" + }, + "dst": { + "register": "AP", + "offset": -1 + } + } + } + ] + ], + [ + 766, + [ + { + "TestLessThanOrEqual": { + "lhs": { + "Deref": { + "register": "AP", + "offset": -1 + } + }, + "rhs": { + "Deref": { + "register": "AP", + "offset": -2 + } + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 789, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 810, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 831, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 879, + [ + { + "TestLessThan": { + "lhs": { + "Deref": { + "register": "FP", + "offset": -3 + } + }, + "rhs": { + "Immediate": "0x7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00" + }, + "dst": { + "register": "AP", + "offset": 5 + } + } + } + ] + ], + [ + 883, + [ + { + "LinearSplit": { + "value": { + "Deref": { + "register": "AP", + "offset": 4 + } + }, + "scalar": { + "Immediate": "0x110000000000000000" + }, + "max_x": { + "Immediate": "0xffffffffffffffffffffffffffffffff" + }, + "x": { + "register": "AP", + "offset": -2 + }, + "y": { + "register": "AP", + "offset": -1 + } + } + } + ] + ], + [ + 894, + [ + { + "LinearSplit": { + "value": { + "Deref": { + "register": "AP", + "offset": 4 + } + }, + "scalar": { + "Immediate": "0x8000000000000000000000000000000" + }, + "max_x": { + "Immediate": "0xfffffffffffffffffffffffffffffffe" + }, + "x": { + "register": "AP", + "offset": -2 + }, + "y": { + "register": "AP", + "offset": -1 + } + } + } + ] + ], + [ + 918, + [ + { + "SystemCall": { + "system": { + "Deref": { + "register": "FP", + "offset": -4 + } + } + } + } + ] + ], + [ + 926, + [ + { + "TestLessThan": { + "lhs": { + "BinOp": { + "op": "Add", + "a": { + "register": "AP", + "offset": -3 + }, + "b": { + "Immediate": "0x0" + } + } + }, + "rhs": { + "Immediate": "0x10000000000000000" + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 930, + [ + { + "LinearSplit": { + "value": { + "Deref": { + "register": "AP", + "offset": -1 + } + }, + "scalar": { + "Immediate": "0x8000000000000110000000000000000" + }, + "max_x": { + "Immediate": "0xfffffffffffffffffffffffffffffffe" + }, + "x": { + "register": "AP", + "offset": 0 + }, + "y": { + "register": "AP", + "offset": 1 + } + } + } + ] + ], + [ + 948, + [ + { + "TestLessThan": { + "lhs": { + "Deref": { + "register": "FP", + "offset": -3 + } + }, + "rhs": { + "Immediate": "0x7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00" + }, + "dst": { + "register": "AP", + "offset": 5 + } + } + } + ] + ], + [ + 952, + [ + { + "LinearSplit": { + "value": { + "Deref": { + "register": "AP", + "offset": 4 + } + }, + "scalar": { + "Immediate": "0x110000000000000000" + }, + "max_x": { + "Immediate": "0xffffffffffffffffffffffffffffffff" + }, + "x": { + "register": "AP", + "offset": -2 + }, + "y": { + "register": "AP", + "offset": -1 + } + } + } + ] + ], + [ + 963, + [ + { + "LinearSplit": { + "value": { + "Deref": { + "register": "AP", + "offset": 4 + } + }, + "scalar": { + "Immediate": "0x8000000000000000000000000000000" + }, + "max_x": { + "Immediate": "0xfffffffffffffffffffffffffffffffe" + }, + "x": { + "register": "AP", + "offset": -2 + }, + "y": { + "register": "AP", + "offset": -1 + } + } + } + ] + ], + [ + 980, + [ + { + "TestLessThan": { + "lhs": { + "BinOp": { + "op": "Add", + "a": { + "register": "AP", + "offset": -14 + }, + "b": { + "Deref": { + "register": "AP", + "offset": -2 + } + } + } + }, + "rhs": { + "Immediate": "0x10000000000000000" + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1004, + [ + { + "SystemCall": { + "system": { + "Deref": { + "register": "AP", + "offset": -20 + } + } + } + } + ] + ], + [ + 1054, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1080, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1127, + [ + { + "SystemCall": { + "system": { + "Deref": { + "register": "FP", + "offset": -14 + } + } + } + } + ] + ], + [ + 1141, + [ + { + "SystemCall": { + "system": { + "BinOp": { + "op": "Add", + "a": { + "register": "FP", + "offset": -14 + }, + "b": { + "Immediate": "0x7" + } + } + } + } + } + ] + ], + [ + 1155, + [ + { + "SystemCall": { + "system": { + "BinOp": { + "op": "Add", + "a": { + "register": "FP", + "offset": -14 + }, + "b": { + "Immediate": "0xe" + } + } + } + } + } + ] + ], + [ + 1166, + [ + { + "TestLessThan": { + "lhs": { + "BinOp": { + "op": "Add", + "a": { + "register": "AP", + "offset": -4 + }, + "b": { + "Deref": { + "register": "AP", + "offset": -3 + } + } + } + }, + "rhs": { + "Immediate": "0x100" + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1189, + [ + { + "SystemCall": { + "system": { + "Deref": { + "register": "AP", + "offset": -9 + } + } + } + } + ] + ], + [ + 1198, + [ + { + "TestLessThan": { + "lhs": { + "BinOp": { + "op": "Add", + "a": { + "register": "AP", + "offset": -10 + }, + "b": { + "Deref": { + "register": "AP", + "offset": -3 + } + } + } + }, + "rhs": { + "Immediate": "0x100" + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1221, + [ + { + "SystemCall": { + "system": { + "Deref": { + "register": "AP", + "offset": -9 + } + } + } + } + ] + ], + [ + 1230, + [ + { + "TestLessThan": { + "lhs": { + "BinOp": { + "op": "Add", + "a": { + "register": "AP", + "offset": -10 + }, + "b": { + "Deref": { + "register": "AP", + "offset": -3 + } + } + } + }, + "rhs": { + "Immediate": "0x100" + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1253, + [ + { + "SystemCall": { + "system": { + "Deref": { + "register": "AP", + "offset": -9 + } + } + } + } + ] + ], + [ + 1262, + [ + { + "TestLessThan": { + "lhs": { + "BinOp": { + "op": "Add", + "a": { + "register": "AP", + "offset": -10 + }, + "b": { + "Deref": { + "register": "AP", + "offset": -3 + } + } + } + }, + "rhs": { + "Immediate": "0x100" + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1285, + [ + { + "SystemCall": { + "system": { + "Deref": { + "register": "AP", + "offset": -9 + } + } + } + } + ] + ], + [ + 1294, + [ + { + "TestLessThan": { + "lhs": { + "BinOp": { + "op": "Add", + "a": { + "register": "AP", + "offset": -10 + }, + "b": { + "Deref": { + "register": "AP", + "offset": -3 + } + } + } + }, + "rhs": { + "Immediate": "0x100" + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1317, + [ + { + "SystemCall": { + "system": { + "Deref": { + "register": "AP", + "offset": -9 + } + } + } + } + ] + ], + [ + 1326, + [ + { + "TestLessThan": { + "lhs": { + "BinOp": { + "op": "Add", + "a": { + "register": "AP", + "offset": -10 + }, + "b": { + "Deref": { + "register": "AP", + "offset": -3 + } + } + } + }, + "rhs": { + "Immediate": "0x100" + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1349, + [ + { + "SystemCall": { + "system": { + "Deref": { + "register": "AP", + "offset": -9 + } + } + } + } + ] + ], + [ + 1380, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1415, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1450, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1485, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1520, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1555, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ] + ], + "entry_points_by_type": { + "EXTERNAL": [ + { + "selector": "0x1b1a0649752af1b28b3dc29a1556eee781e4a4c3a1f7f53f90fa834de098c4d", + "offset": 0, + "builtins": [ + "pedersen", + "range_check" + ] + }, + { + "selector": "0x3c513a024b5b519831b4e843b5a5413ed78c89f8136329eb8b835f82743a32e", + "offset": 144, + "builtins": [ + "pedersen", + "range_check" + ] + } + ], + "L1_HANDLER": [], + "CONSTRUCTOR": [] + } +} diff --git a/crates/blockifier/feature_contracts/cairo1/compiled/test_contract.casm.json b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/compiled/test_contract.casm.json similarity index 81% rename from crates/blockifier/feature_contracts/cairo1/compiled/test_contract.casm.json rename to crates/blockifier_test_utils/resources/feature_contracts/cairo1/compiled/test_contract.casm.json index ce3d793a9ec..c61a2149296 100644 --- a/crates/blockifier/feature_contracts/cairo1/compiled/test_contract.casm.json +++ b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/compiled/test_contract.casm.json @@ -1,6 +1,6 @@ { "prime": "0x800000000000011000000000000000000000000000000000000000000000001", - "compiler_version": "2.9.0", + "compiler_version": "2.11.0", "bytecode": [ "0xa0680017fff8000", "0x7", @@ -8,17 +8,20 @@ "0x100000000000000000000000000000000", "0x400280007ff97fff", "0x10780017fff7fff", - "0xd1", + "0xe4", "0x4825800180007ffa", "0x0", "0x400280007ff97fff", "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0x1162", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", + "0xb", + "0x48127ffe7fff8000", "0x482680017ffc8000", "0x1", "0x480a7ffd7fff8000", @@ -26,7 +29,8 @@ "0x0", "0x480280007ffc8000", "0x10780017fff7fff", - "0x8", + "0x9", + "0x48127ffe7fff8000", "0x480a7ffc7fff8000", "0x480a7ffd7fff8000", "0x480680017fff8000", @@ -34,52 +38,56 @@ "0x480680017fff8000", "0x0", "0x20680017fff7ffe", - "0xa6", + "0xb5", + "0x48127ffb7fff8000", "0xa0680017fff8004", "0xe", - "0x4824800180047ffe", + "0x4824800180047ffd", "0x800000000000000000000000000000000000000000000000000000000000000", "0x484480017ffe8000", "0x110000000000000000", "0x48307ffe7fff8002", - "0x480080007ff67ffc", - "0x480080017ff57ffc", + "0x480080007ff37ffc", + "0x480080017ff27ffc", "0x402480017ffb7ffd", "0xffffffffffffffeeffffffffffffffff", - "0x400080027ff47ffd", + "0x400080027ff17ffd", "0x10780017fff7fff", - "0x94", + "0xa0", "0x484480017fff8001", "0x8000000000000000000000000000000", - "0x48307fff80007ffd", - "0x480080007ff77ffd", - "0x480080017ff67ffd", + "0x48307fff80007ffc", + "0x480080007ff47ffd", + "0x480080017ff37ffd", "0x402480017ffc7ffe", "0xf8000000000000000000000000000000", - "0x400080027ff57ffe", - "0x482480017ff58000", + "0x400080027ff27ffe", + "0x482480017ff28000", "0x3", - "0x48307ff680007ff7", + "0x48127ff97fff8000", + "0x48307ff480007ff5", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x77", - "0x482480017ff58000", + "0x81", + "0x482480017ff38000", "0x1", - "0x48127ff57fff8000", - "0x480080007ff38000", - "0x48307ffd80007ffe", + "0x48127ff37fff8000", + "0x48127ffc7fff8000", + "0x480080007ff08000", + "0x48307ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ff87fff8000", - "0x48127feb7fff8000", + "0x48127ff67fff8000", + "0x482480017ffa8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -88,37 +96,40 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x4ba0", + "0x5970", "0x482480017fff8000", - "0x4b9f", - "0x480080007fff8000", + "0x596f", + "0x48127ffa7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007fe9", - "0x41d2", + "0x4824800180007ffd", + "0x56b8", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007ff37fff", + "0x400080007ff07fff", "0x10780017fff7fff", - "0x43", - "0x4824800180007fe9", - "0x41d2", - "0x400080007ff47fff", + "0x4a", + "0x4824800180007ffd", + "0x56b8", + "0x400080007ff17fff", + "0x48127fff7fff8000", "0x480680017fff8000", "0x0", - "0x482480017ff38000", + "0x482480017fef8000", "0x1", "0x480680017fff8000", "0x53746f726167655772697465", "0x400280007ffb7fff", "0x400280017ffb7ffc", "0x400280027ffb7ffd", - "0x400280037ffb7feb", - "0x400280047ffb7ff5", + "0x400280037ffb7fe6", + "0x400280047ffb7ff3", "0x480280067ffb8000", "0x20680017fff7fff", - "0x23", + "0x27", "0x480280057ffb8000", + "0x48127fff7fff8000", "0x480680017fff8000", "0x0", "0x480680017fff8000", @@ -126,16 +137,18 @@ "0x400280077ffb7fff", "0x400280087ffb7ffd", "0x400280097ffb7ffe", - "0x4002800a7ffb7fe7", + "0x4002800a7ffb7fe1", "0x4802800c7ffb8000", "0x20680017fff7fff", - "0x10", + "0x12", + "0x4802800b7ffb8000", "0x40780017fff7fff", "0x1", "0x4802800d7ffb8000", "0x400080007ffe7fff", - "0x48127ff77fff8000", - "0x4802800b7ffb8000", + "0x48127ff57fff8000", + "0x482480017ffc8000", + "0xc8", "0x482680017ffb8000", "0xe", "0x480680017fff8000", @@ -145,20 +158,23 @@ "0x1", "0x208b7fff7fff7ffe", "0x4802800b7ffb8000", + "0x48127fff7fff8000", "0x482680017ffb8000", "0xf", "0x4802800d7ffb8000", "0x4802800e7ffb8000", "0x10780017fff7fff", - "0x9", + "0xb", "0x40780017fff7fff", - "0x4", + "0x5", "0x480280057ffb8000", + "0x482480017fff8000", + "0x2ac6", "0x482680017ffb8000", "0x9", "0x480280077ffb8000", "0x480280087ffb8000", - "0x48127ff57fff8000", + "0x48127ff37fff8000", "0x48127ffb7fff8000", "0x48127ffb7fff8000", "0x480680017fff8000", @@ -171,9 +187,9 @@ "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482480017ff18000", + "0x482480017fee8000", "0x1", - "0x48127fe47fff8000", + "0x48127ff87fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -186,8 +202,9 @@ "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202332", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127fef7fff8000", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x686", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -195,20 +212,22 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x482480017ff48000", + "0x482480017ff18000", "0x3", + "0x482480017ff88000", + "0x686", "0x10780017fff7fff", "0x5", - "0x40780017fff7fff", - "0x6", - "0x48127ff47fff8000", + "0x48127ff87fff8000", + "0x482480017ffa8000", + "0xba4", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202331", "0x400080007ffe7fff", - "0x48127ffd7fff8000", - "0x48127fef7fff8000", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -223,7 +242,8 @@ "0x400080007ffe7fff", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x21b6", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -237,24 +257,27 @@ "0x100000000000000000000000000000000", "0x400280007ff97fff", "0x10780017fff7fff", - "0xa0", + "0xad", "0x4825800180007ffa", "0x0", "0x400280007ff97fff", "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0x1bf8", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127ffa7fff8000", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -263,63 +286,67 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x4af1", + "0x58b2", "0x482480017fff8000", - "0x4af0", - "0x480080007fff8000", + "0x58b1", + "0x48127ffb7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007ff8", - "0x3e4e", + "0x4824800180007ffd", + "0x5c9e", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007ff77fff", + "0x400080007ff57fff", "0x10780017fff7fff", - "0x6b", - "0x4824800180007ff8", - "0x3e4e", - "0x400080007ff87fff", + "0x74", + "0x4824800180007ffd", + "0x5c9e", + "0x400080007ff67fff", "0x480680017fff8000", "0xf", + "0x48127ffe7fff8000", "0xa0680017fff8004", "0xe", - "0x4824800180047ffe", + "0x4824800180047ffd", "0x800000000000000000000000000000000000000000000000000000000000000", "0x484480017ffe8000", "0x110000000000000000", "0x48307ffe7fff8002", - "0x480080017ff37ffc", - "0x480080027ff27ffc", + "0x480080017ff07ffc", + "0x480080027fef7ffc", "0x402480017ffb7ffd", "0xffffffffffffffeeffffffffffffffff", - "0x400080037ff17ffd", + "0x400080037fee7ffd", "0x10780017fff7fff", - "0x44", + "0x4b", "0x484480017fff8001", "0x8000000000000000000000000000000", - "0x48307fff80007ffd", - "0x480080017ff47ffd", - "0x480080027ff37ffd", + "0x48307fff80007ffc", + "0x480080017ff17ffd", + "0x480080027ff07ffd", "0x402480017ffc7ffe", "0xf8000000000000000000000000000000", - "0x400080037ff27ffe", + "0x400080037fef7ffe", + "0x48127ffa7fff8000", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", - "0x482480017ff08000", + "0x482480017fec8000", "0x4", "0x480680017fff8000", "0x53746f726167655772697465", "0x400280007ffb7fff", - "0x400280017ffb7ff5", + "0x400280017ffb7ffb", "0x400280027ffb7ffc", - "0x400280037ffb7ff6", + "0x400280037ffb7ff4", "0x400280047ffb7ffd", "0x480280067ffb8000", "0x20680017fff7fff", - "0x24", + "0x28", "0x480280057ffb8000", + "0x48127fff7fff8000", "0x480680017fff8000", "0x0", "0x480680017fff8000", @@ -329,15 +356,17 @@ "0x400280077ffb7fff", "0x400280087ffb7ffc", "0x400280097ffb7ffd", - "0x4002800a7ffb7ff1", + "0x4002800a7ffb7fee", "0x4002800b7ffb7ffe", "0x4802800d7ffb8000", "0x20680017fff7fff", - "0xd", + "0xf", + "0x4802800c7ffb8000", "0x40780017fff7fff", "0x1", - "0x48127ff77fff8000", - "0x4802800c7ffb8000", + "0x48127ff57fff8000", + "0x482480017ffd8000", + "0x1f4", "0x482680017ffb8000", "0xe", "0x480680017fff8000", @@ -345,30 +374,34 @@ "0x48127ffb7fff8000", "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", - "0x48127ff87fff8000", "0x4802800c7ffb8000", + "0x48127ff67fff8000", + "0x48127ffe7fff8000", "0x482680017ffb8000", "0x10", "0x4802800e7ffb8000", "0x4802800f7ffb8000", "0x10780017fff7fff", - "0x16", - "0x48127ffd7fff8000", + "0x19", "0x480280057ffb8000", + "0x48127ffc7fff8000", + "0x482480017ffe8000", + "0x2bc0", "0x482680017ffb8000", "0x9", "0x480280077ffb8000", "0x480280087ffb8000", "0x10780017fff7fff", - "0xe", + "0xf", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4f7074696f6e3a3a756e77726170206661696c65642e", "0x400080007ffe7fff", - "0x482480017fef8000", + "0x482480017fec8000", "0x4", - "0x48127ff57fff8000", + "0x482480017ff68000", + "0x5654", "0x480a7ffb7fff8000", "0x48127ffb7fff8000", "0x482480017ffa8000", @@ -386,9 +419,9 @@ "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482480017ff58000", + "0x482480017ff38000", "0x1", - "0x48127ff37fff8000", + "0x48127ff87fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -403,7 +436,8 @@ "0x400080007ffe7fff", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x21b6", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -419,17 +453,20 @@ "0x100000000000000000000000000000000", "0x400280007ff97fff", "0x10780017fff7fff", - "0xf3", + "0x109", "0x4825800180007ffa", "0x0", "0x400280007ff97fff", "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0x17c", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", + "0xb", + "0x48127ffe7fff8000", "0x482680017ffc8000", "0x1", "0x480a7ffd7fff8000", @@ -437,7 +474,8 @@ "0x0", "0x480280007ffc8000", "0x10780017fff7fff", - "0x8", + "0x9", + "0x48127ffe7fff8000", "0x480a7ffc7fff8000", "0x480a7ffd7fff8000", "0x480680017fff8000", @@ -445,89 +483,97 @@ "0x480680017fff8000", "0x0", "0x20680017fff7ffe", - "0xc8", - "0x40137fff7fff8000", + "0xda", + "0x40137fff7fff8001", + "0x48127ffb7fff8000", "0xa0680017fff8004", "0xe", - "0x4825800180048000", + "0x4825800180048001", "0x800000000000000000000000000000000000000000000000000000000000000", "0x484480017ffe8000", "0x110000000000000000", "0x48307ffe7fff8002", - "0x480080007ff67ffc", - "0x480080017ff57ffc", + "0x480080007ff37ffc", + "0x480080017ff27ffc", "0x402480017ffb7ffd", "0xffffffffffffffeeffffffffffffffff", - "0x400080027ff47ffd", + "0x400080027ff17ffd", "0x10780017fff7fff", - "0xb5", + "0xc4", "0x484480017fff8001", "0x8000000000000000000000000000000", - "0x48317fff80008000", - "0x480080007ff77ffd", - "0x480080017ff67ffd", + "0x48317fff80008001", + "0x480080007ff47ffd", + "0x480080017ff37ffd", "0x402480017ffc7ffe", "0xf8000000000000000000000000000000", - "0x400080027ff57ffe", - "0x482480017ff58000", + "0x400080027ff27ffe", + "0x482480017ff28000", "0x3", - "0x48307ff680007ff7", + "0x48127ff97fff8000", + "0x48307ff480007ff5", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x98", - "0x400180007ff58001", - "0x482480017ff58000", + "0xa5", + "0x400180007ff38000", + "0x482480017ff38000", "0x1", - "0x48127ff57fff8000", - "0x48307ffe80007fff", + "0x48127ff37fff8000", + "0x48127ffc7fff8000", + "0x48307ffd80007ffe", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", - "0x482480017ffd8000", + "0xb", + "0x48127ffe7fff8000", + "0x482480017ffb8000", "0x1", - "0x48127ffd7fff8000", + "0x48127ffb7fff8000", "0x480680017fff8000", "0x0", - "0x48127ffa7fff8000", + "0x48127ff87fff8000", "0x10780017fff7fff", - "0x8", - "0x48127ffd7fff8000", - "0x48127ffd7fff8000", + "0x9", + "0x48127ffe7fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", "0x480680017fff8000", "0x1", "0x480680017fff8000", "0x0", "0x20680017fff7ffe", - "0x6f", + "0x78", "0x40780017fff7fff", "0x1", - "0x48127ff67fff8000", - "0x48127fe97fff8000", + "0x48127ff37fff8000", + "0x48127ff97fff8000", "0x48127ff97fff8000", "0x48127ff97fff8000", "0x48127ffb7fff8000", "0x48127ffa7fff8000", "0x480080007ff88000", "0x1104800180018000", - "0x1a3e", + "0x2279", "0x20680017fff7ffa", + "0x62", + "0x48127ff97fff8000", + "0x20680017fff7ffc", "0x5a", - "0x20680017fff7ffd", - "0x54", - "0x48307ffb80007ffc", + "0x48127fff7fff8000", + "0x48307ff980007ffa", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ff57fff8000", - "0x48127ff57fff8000", + "0x48127ff37fff8000", + "0x482480017ffb8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -536,37 +582,40 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x49e0", + "0x578a", "0x482480017fff8000", - "0x49df", - "0x480080007fff8000", + "0x5789", + "0x48127ffb7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007ff3", - "0x2404", + "0x4824800180007ffd", + "0x29cc", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007ff07fff", + "0x400080007fed7fff", "0x10780017fff7fff", - "0x24", - "0x4824800180007ff3", - "0x2404", - "0x400080007ff17fff", - "0x482480017ff18000", + "0x27", + "0x4824800180007ffd", + "0x29cc", + "0x400080007fee7fff", + "0x48127fff7fff8000", + "0x482480017fed8000", "0x1", "0x480680017fff8000", "0x43616c6c436f6e7472616374", "0x400280007ffb7fff", "0x400280017ffb7ffd", - "0x400380027ffb8000", - "0x400380037ffb8001", - "0x400280047ffb7ff5", - "0x400280057ffb7ff6", + "0x400380027ffb8001", + "0x400380037ffb8000", + "0x400280047ffb7ff1", + "0x400280057ffb7ff2", "0x480280077ffb8000", "0x20680017fff7fff", - "0xb", - "0x48127ffd7fff8000", + "0xc", "0x480280067ffb8000", + "0x48127ffc7fff8000", + "0x48127ffe7fff8000", "0x482680017ffb8000", "0xa", "0x480680017fff8000", @@ -574,8 +623,9 @@ "0x480280087ffb8000", "0x480280097ffb8000", "0x208b7fff7fff7ffe", - "0x48127ffd7fff8000", "0x480280067ffb8000", + "0x48127ffc7fff8000", + "0x48127ffe7fff8000", "0x482680017ffb8000", "0xa", "0x480680017fff8000", @@ -588,9 +638,9 @@ "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482480017fee8000", + "0x482480017feb8000", "0x1", - "0x48127fee7fff8000", + "0x48127ff87fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -598,20 +648,23 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x48127ff87fff8000", - "0x48127ff87fff8000", + "0x48127ff77fff8000", + "0x482480017ffe8000", + "0x492", "0x10780017fff7fff", - "0xc", - "0x48127ff87fff8000", + "0xe", "0x48127ff87fff8000", + "0x482480017ff88000", + "0x7b2", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", "0x48127ffa7fff8000", "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", - "0x48127ff77fff8000", - "0x48127fea7fff8000", + "0x48127ff47fff8000", + "0x482480017ffa8000", + "0x102c", "0x40780017fff7fff", "0x1", "0x480680017fff8000", @@ -631,8 +684,9 @@ "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202332", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127fef7fff8000", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x159a", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -640,20 +694,22 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x482480017ff48000", + "0x482480017ff18000", "0x3", + "0x482480017ff88000", + "0x159a", "0x10780017fff7fff", "0x5", - "0x40780017fff7fff", - "0x6", - "0x48127ff47fff8000", + "0x48127ff87fff8000", + "0x482480017ffa8000", + "0x1b12", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202331", "0x400080007ffe7fff", - "0x48127ffd7fff8000", - "0x48127fef7fff8000", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -668,7 +724,8 @@ "0x400080007ffe7fff", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x213e", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -681,20 +738,22 @@ "0xa0680017fff8000", "0x7", "0x482680017ffa8000", - "0xffffffffffffffffffffffffffffecbe", + "0xffffffffffffffffffffffffffffe67e", "0x400280007ff97fff", "0x10780017fff7fff", - "0x1e8", + "0x212", "0x4825800180007ffa", - "0x1342", + "0x1982", "0x400280007ff97fff", "0x482680017ff98000", "0x1", + "0x48127ffe7fff8000", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", + "0xb", + "0x48127ffe7fff8000", "0x482680017ffc8000", "0x1", "0x480a7ffd7fff8000", @@ -702,7 +761,8 @@ "0x0", "0x480280007ffc8000", "0x10780017fff7fff", - "0x8", + "0x9", + "0x48127ffe7fff8000", "0x480a7ffc7fff8000", "0x480a7ffd7fff8000", "0x480680017fff8000", @@ -710,182 +770,199 @@ "0x480680017fff8000", "0x0", "0x20680017fff7ffe", - "0x1bd", - "0x40137fff7fff8008", + "0x1e4", + "0x40137fff7fff8005", + "0x48127ffb7fff8000", "0xa0680017fff8004", "0xe", - "0x4825800180048008", + "0x4825800180048005", "0x800000000000000000000000000000000000000000000000000000000000000", "0x484480017ffe8000", "0x110000000000000000", "0x48307ffe7fff8002", - "0x480080007ff67ffc", - "0x480080017ff57ffc", + "0x480080007ff37ffc", + "0x480080017ff27ffc", "0x402480017ffb7ffd", "0xffffffffffffffeeffffffffffffffff", - "0x400080027ff47ffd", + "0x400080027ff17ffd", "0x10780017fff7fff", - "0x1aa", + "0x1ce", "0x484480017fff8001", "0x8000000000000000000000000000000", - "0x48317fff80008008", - "0x480080007ff77ffd", - "0x480080017ff67ffd", + "0x48317fff80008005", + "0x480080007ff47ffd", + "0x480080017ff37ffd", "0x402480017ffc7ffe", "0xf8000000000000000000000000000000", - "0x400080027ff57ffe", - "0x482480017ff58000", + "0x400080027ff27ffe", + "0x482480017ff28000", "0x3", - "0x48307ff680007ff7", + "0x48127ff97fff8000", + "0x48307ff480007ff5", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x18d", - "0x400180007ff58004", - "0x482480017ff58000", + "0x1af", + "0x400180007ff38007", + "0x482480017ff38000", "0x1", - "0x48127ff57fff8000", - "0x48307ffe80007fff", + "0x48127ff37fff8000", + "0x48127ffc7fff8000", + "0x48307ffd80007ffe", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", - "0x482480017ffd8000", + "0xb", + "0x48127ffe7fff8000", + "0x482480017ffb8000", "0x1", - "0x48127ffd7fff8000", + "0x48127ffb7fff8000", "0x480680017fff8000", "0x0", - "0x48127ffa7fff8000", + "0x48127ff87fff8000", "0x10780017fff7fff", - "0x8", - "0x48127ffd7fff8000", - "0x48127ffd7fff8000", + "0x9", + "0x48127ffe7fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", "0x480680017fff8000", "0x1", "0x480680017fff8000", "0x0", "0x20680017fff7ffe", - "0x164", + "0x182", "0x40780017fff7fff", "0x1", - "0x48127ff67fff8000", - "0x48127fe97fff8000", + "0x48127ff37fff8000", + "0x48127ff97fff8000", "0x48127ff97fff8000", "0x48127ff97fff8000", "0x48127ffb7fff8000", "0x48127ffa7fff8000", "0x480080007ff88000", "0x1104800180018000", - "0x1935", + "0x215a", "0x20680017fff7ffa", - "0x14f", - "0x20680017fff7ffd", - "0x149", - "0x40137ffe7fff8005", - "0x40137fff7fff8006", - "0x48307ffb80007ffc", + "0x16c", + "0x48127ff97fff8000", + "0x20680017fff7ffc", + "0x164", + "0x40137ffd7fff8003", + "0x40137ffe7fff8004", + "0x48127fff7fff8000", + "0x48307ff980007ffa", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", - "0x482480017ffa8000", + "0xb", + "0x48127ffe7fff8000", + "0x482480017ff78000", "0x1", - "0x48127ffa7fff8000", + "0x48127ff77fff8000", "0x480680017fff8000", "0x0", - "0x480080007ff78000", + "0x480080007ff48000", "0x10780017fff7fff", - "0x8", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", + "0x9", + "0x48127ffe7fff8000", + "0x48127ff77fff8000", + "0x48127ff77fff8000", "0x480680017fff8000", "0x1", "0x480680017fff8000", "0x0", "0x20680017fff7ffe", - "0x121", - "0x40137fff7fff8007", + "0x139", + "0x40137fff7fff8006", + "0x48127ffb7fff8000", "0xa0680017fff8004", "0xe", - "0x4825800180048007", + "0x4825800180048006", "0x800000000000000000000000000000000000000000000000000000000000000", "0x484480017ffe8000", "0x110000000000000000", "0x48307ffe7fff8002", - "0x480080007fef7ffc", - "0x480080017fee7ffc", + "0x480080007feb7ffc", + "0x480080017fea7ffc", "0x402480017ffb7ffd", "0xffffffffffffffeeffffffffffffffff", - "0x400080027fed7ffd", + "0x400080027fe97ffd", "0x10780017fff7fff", - "0x10e", + "0x123", "0x484480017fff8001", "0x8000000000000000000000000000000", - "0x48317fff80008007", - "0x480080007ff07ffd", - "0x480080017fef7ffd", + "0x48317fff80008006", + "0x480080007fec7ffd", + "0x480080017feb7ffd", "0x402480017ffc7ffe", "0xf8000000000000000000000000000000", - "0x400080027fee7ffe", - "0x482480017fee8000", + "0x400080027fea7ffe", + "0x482480017fea8000", "0x3", - "0x48307ff680007ff7", + "0x48127ff97fff8000", + "0x48307ff480007ff5", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xf1", - "0x400180007ff58003", - "0x482480017ff58000", + "0x104", + "0x400180007ff38008", + "0x482480017ff38000", "0x1", - "0x48127ff57fff8000", - "0x48307ffe80007fff", + "0x48127ff37fff8000", + "0x48127ffc7fff8000", + "0x48307ffd80007ffe", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", - "0x482480017ffd8000", + "0xb", + "0x48127ffe7fff8000", + "0x482480017ffb8000", "0x1", - "0x48127ffd7fff8000", + "0x48127ffb7fff8000", "0x480680017fff8000", "0x0", - "0x48127ffa7fff8000", + "0x48127ff87fff8000", "0x10780017fff7fff", - "0x8", - "0x48127ffd7fff8000", - "0x48127ffd7fff8000", + "0x9", + "0x48127ffe7fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", "0x480680017fff8000", "0x1", "0x480680017fff8000", "0x0", "0x20680017fff7ffe", - "0xc8", + "0xd7", "0x40780017fff7fff", "0x1", - "0x48127ff67fff8000", - "0x48127fe47fff8000", + "0x48127ff37fff8000", + "0x48127ff97fff8000", "0x48127ff97fff8000", "0x48127ff97fff8000", "0x48127ffb7fff8000", "0x48127ffa7fff8000", "0x480080007ff88000", "0x1104800180018000", - "0x18d8", + "0x20f4", "0x20680017fff7ffa", - "0xb3", - "0x20680017fff7ffd", - "0xad", - "0x48307ffb80007ffc", + "0xc1", + "0x48127ff97fff8000", + "0x20680017fff7ffc", + "0xb9", + "0x48127fff7fff8000", + "0x48307ff980007ffa", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ff57fff8000", - "0x48127ff57fff8000", + "0x48127ff37fff8000", + "0x482480017ffb8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -894,65 +971,69 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x487a", + "0x5605", "0x482480017fff8000", - "0x4879", - "0x480080007fff8000", + "0x5604", + "0x48127ffb7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007ff3", - "0x70d0", + "0x4824800180007ffd", + "0x71fc", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007ff07fff", + "0x400080007fed7fff", "0x10780017fff7fff", - "0x7d", - "0x4824800180007ff3", - "0x70d0", - "0x400080007ff17fff", - "0x482480017ff18000", + "0x86", + "0x4824800180007ffd", + "0x71fc", + "0x400080007fee7fff", + "0x48127fff7fff8000", + "0x482480017fed8000", "0x1", "0x480680017fff8000", "0x43616c6c436f6e7472616374", "0x400280007ffb7fff", "0x400280017ffb7ffd", - "0x400380027ffb8008", - "0x400380037ffb8004", - "0x400380047ffb8005", - "0x400380057ffb8006", + "0x400380027ffb8005", + "0x400380037ffb8007", + "0x400380047ffb8003", + "0x400380057ffb8004", "0x480280077ffb8000", "0x20680017fff7fff", - "0x5f", + "0x65", "0x480280067ffb8000", + "0x48127fff7fff8000", "0x480280087ffb8000", "0x480280097ffb8000", "0x480680017fff8000", "0x43616c6c436f6e7472616374", "0x4002800a7ffb7fff", "0x4002800b7ffb7ffc", - "0x4003800c7ffb8007", - "0x4003800d7ffb8003", - "0x4002800e7ffb7ff0", - "0x4002800f7ffb7ff1", + "0x4003800c7ffb8006", + "0x4003800d7ffb8008", + "0x4002800e7ffb7feb", + "0x4002800f7ffb7fec", "0x480280117ffb8000", "0x20680017fff7fff", - "0x49", + "0x4c", + "0x480280107ffb8000", "0x40780017fff7fff", "0x1", - "0x48127ff77fff8000", - "0x480280107ffb8000", + "0x48127ff57fff8000", + "0x48127ffd7fff8000", "0x48127ffd7fff8000", "0x48127ffc7fff8000", - "0x48127ff77fff8000", - "0x48127ff77fff8000", + "0x48127ff67fff8000", + "0x48127ff67fff8000", "0x402780017ffb8000", "0x14", "0x400380127ffb8001", "0x400380137ffb8002", "0x1104800180018000", - "0x18e3", + "0x20fe", "0x20680017fff7ffd", - "0x32", + "0x33", "0x48127ffb7fff8000", "0x48127ffb7fff8000", "0x48127ffc7fff8000", @@ -960,7 +1041,7 @@ "0x480a80017fff8000", "0x480a80027fff8000", "0x1104800180018000", - "0x18d9", + "0x20f4", "0x20680017fff7ffd", "0x21", "0x40780017fff7fff", @@ -975,7 +1056,7 @@ "0x482480017ff98000", "0x1", "0x1104800180018000", - "0x18fd", + "0x211a", "0x20680017fff7ffd", "0xa", "0x48127ffb7fff8000", @@ -995,29 +1076,35 @@ "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", "0x48127ffb7fff8000", - "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x74e", "0x480a80007fff8000", "0x48127ffb7fff8000", "0x48127ffb7fff8000", "0x10780017fff7fff", - "0x17", - "0x48127ffb7fff8000", + "0x1c", "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0xfc8", "0x480a80007fff8000", "0x48127ffb7fff8000", "0x48127ffb7fff8000", "0x10780017fff7fff", - "0x10", - "0x48127ff87fff8000", + "0x14", "0x480280107ffb8000", + "0x48127ff67fff8000", + "0x482480017ffe8000", + "0x19b4", "0x482680017ffb8000", "0x14", "0x480280127ffb8000", "0x480280137ffb8000", "0x10780017fff7fff", - "0x8", - "0x48127ffd7fff8000", + "0xa", "0x480280067ffb8000", + "0x48127ffc7fff8000", + "0x482480017ffe8000", + "0x463c", "0x482680017ffb8000", "0xa", "0x480280087ffb8000", @@ -1035,9 +1122,9 @@ "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482480017fee8000", + "0x482480017feb8000", "0x1", - "0x48127fee7fff8000", + "0x48127ff87fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -1045,20 +1132,23 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x48127ff87fff8000", - "0x48127ff87fff8000", + "0x48127ff77fff8000", + "0x482480017ffe8000", + "0x492", "0x10780017fff7fff", - "0xc", - "0x48127ff87fff8000", + "0xe", "0x48127ff87fff8000", + "0x482480017ff88000", + "0x7b2", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", "0x48127ffa7fff8000", "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", - "0x48127ff77fff8000", - "0x48127fe57fff8000", + "0x48127ff47fff8000", + "0x482480017ffa8000", + "0x102c", "0x40780017fff7fff", "0x1", "0x480680017fff8000", @@ -1078,8 +1168,9 @@ "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202335", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127fea7fff8000", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x159a", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -1087,20 +1178,22 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x482480017fed8000", + "0x482480017fe98000", "0x3", + "0x482480017ff88000", + "0x159a", "0x10780017fff7fff", "0x5", - "0x40780017fff7fff", - "0x6", - "0x48127fed7fff8000", + "0x48127ff07fff8000", + "0x482480017ffa8000", + "0x1b12", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202334", "0x400080007ffe7fff", - "0x48127ffd7fff8000", - "0x48127fea7fff8000", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -1108,20 +1201,23 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x48127ff87fff8000", - "0x48127ff87fff8000", + "0x48127ff77fff8000", + "0x482480017ffe8000", + "0x1f4a", "0x10780017fff7fff", - "0xc", - "0x48127ff87fff8000", + "0xe", "0x48127ff87fff8000", + "0x482480017ff88000", + "0x226a", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", "0x48127ffa7fff8000", "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", - "0x48127ff77fff8000", - "0x48127fea7fff8000", + "0x48127ff47fff8000", + "0x482480017ffa8000", + "0x2ae4", "0x40780017fff7fff", "0x1", "0x480680017fff8000", @@ -1141,8 +1237,9 @@ "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202332", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127fef7fff8000", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x3052", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -1150,20 +1247,22 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x482480017ff48000", + "0x482480017ff18000", "0x3", + "0x482480017ff88000", + "0x3052", "0x10780017fff7fff", "0x5", - "0x40780017fff7fff", - "0x6", - "0x48127ff47fff8000", + "0x48127ff87fff8000", + "0x482480017ffa8000", + "0x35ca", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202331", "0x400080007ffe7fff", - "0x48127ffd7fff8000", - "0x48127fef7fff8000", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -1178,7 +1277,8 @@ "0x400080007ffe7fff", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x20f8", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -1192,17 +1292,20 @@ "0x100000000000000000000000000000000", "0x400280007ff97fff", "0x10780017fff7fff", - "0x97", + "0xc9", "0x4825800180007ffa", "0x0", "0x400280007ff97fff", "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0xfd2", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", + "0xb", + "0x48127ffe7fff8000", "0x482680017ffc8000", "0x1", "0x480a7ffd7fff8000", @@ -1210,7 +1313,8 @@ "0x0", "0x480280007ffc8000", "0x10780017fff7fff", - "0x8", + "0x9", + "0x48127ffe7fff8000", "0x480a7ffc7fff8000", "0x480a7ffd7fff8000", "0x480680017fff8000", @@ -1218,43 +1322,67 @@ "0x480680017fff8000", "0x0", "0x20680017fff7ffe", - "0x6c", + "0x9a", + "0x48127ffb7fff8000", "0xa0680017fff8004", "0xe", - "0x4824800180047ffe", + "0x4824800180047ffd", "0x800000000000000000000000000000000000000000000000000000000000000", "0x484480017ffe8000", "0x110000000000000000", "0x48307ffe7fff8002", - "0x480080007ff67ffc", - "0x480080017ff57ffc", + "0x480080007ff37ffc", + "0x480080017ff27ffc", "0x402480017ffb7ffd", "0xffffffffffffffeeffffffffffffffff", - "0x400080027ff47ffd", + "0x400080027ff17ffd", "0x10780017fff7fff", - "0x5a", + "0x85", "0x484480017fff8001", "0x8000000000000000000000000000000", - "0x48307fff80007ffd", - "0x480080007ff77ffd", - "0x480080017ff67ffd", + "0x48307fff80007ffc", + "0x480080007ff47ffd", + "0x480080017ff37ffd", "0x402480017ffc7ffe", "0xf8000000000000000000000000000000", - "0x400080027ff57ffe", - "0x482480017ff58000", + "0x400080027ff27ffe", + "0x482480017ff28000", "0x3", - "0x48307ff680007ff7", + "0x48127ff97fff8000", + "0x48307ff480007ff5", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0x66", + "0x480080007ff38000", + "0x482480017ff28000", + "0x1", + "0x48127ff27fff8000", + "0x48127ffb7fff8000", + "0x20680017fff7ffc", + "0x7", + "0x48127fff7fff8000", + "0x480680017fff8000", + "0x1", + "0x10780017fff7fff", + "0x6", + "0x482480017fff8000", + "0x64", + "0x480680017fff8000", + "0x0", + "0x48307ffb80007ffc", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127fef7fff8000", + "0x48127ff47fff8000", + "0x482480017ffa8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -1263,57 +1391,62 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x4709", + "0x5461", "0x482480017fff8000", - "0x4708", - "0x480080007fff8000", + "0x5460", + "0x48127ffa7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007fed", - "0x9c0e", + "0x4824800180007ffd", + "0xb4dc", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007ff77fff", + "0x400080007fee7fff", "0x10780017fff7fff", - "0x20", - "0x4824800180007fed", - "0x9c0e", - "0x400080007ff87fff", - "0x482480017ff88000", + "0x24", + "0x4824800180007ffd", + "0xb4dc", + "0x400080007fef7fff", + "0x480680017fff8000", "0x1", "0x48127ffe7fff8000", "0x480a7ffb7fff8000", - "0x48127fef7fff8000", + "0x48127fe57fff8000", + "0x48307ff380007ffc", "0x1104800180018000", - "0x17fa", - "0x20680017fff7ffd", + "0x1fe8", + "0x482480017fc88000", + "0x1", + "0x20680017fff7ffc", "0xc", "0x40780017fff7fff", "0x1", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x48127ff97fff8000", + "0x48127ffe7fff8000", + "0x48127ff87fff8000", + "0x48127ff87fff8000", "0x480680017fff8000", "0x0", "0x48127ffb7fff8000", "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", + "0x48127fff7fff8000", + "0x482480017ff98000", + "0x64", + "0x48127ff97fff8000", "0x480680017fff8000", "0x1", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", + "0x48127ff97fff8000", + "0x48127ff97fff8000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482480017ff58000", + "0x482480017fec8000", "0x1", - "0x48127fe87fff8000", + "0x48127ff87fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -1321,20 +1454,37 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x482480017ff48000", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4661696c656420746f20646573657269616c697a6520706172616d202332", + "0x400080007ffe7fff", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x816", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x482480017ff18000", "0x3", + "0x482480017ff88000", + "0x816", "0x10780017fff7fff", "0x5", - "0x40780017fff7fff", - "0x6", - "0x48127ff47fff8000", + "0x48127ff87fff8000", + "0x482480017ffa8000", + "0xd34", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202331", "0x400080007ffe7fff", - "0x48127ffd7fff8000", - "0x48127fef7fff8000", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -1349,7 +1499,8 @@ "0x400080007ffe7fff", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x21b6", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -1357,152 +1508,33 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x3", "0xa0680017fff8000", "0x7", "0x482680017ffa8000", - "0xfffffffffffffffffffffffffffff9ac", + "0x100000000000000000000000000000000", "0x400280007ff97fff", "0x10780017fff7fff", - "0x120", + "0x68", "0x4825800180007ffa", - "0x654", + "0x0", "0x400280007ff97fff", "0x482680017ff98000", "0x1", - "0x48297ffc80007ffd", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0xa", - "0x482680017ffc8000", - "0x1", - "0x480a7ffd7fff8000", - "0x480680017fff8000", - "0x0", - "0x480a7ffc7fff8000", - "0x10780017fff7fff", - "0x8", - "0x480a7ffc7fff8000", - "0x480a7ffd7fff8000", - "0x480680017fff8000", - "0x1", - "0x480680017fff8000", - "0x0", - "0x20680017fff7ffe", - "0xf5", - "0x400180007fff8002", - "0xa0680017fff8000", - "0x12", - "0x4825800180008002", - "0x10000000000000000", - "0x4844800180008002", - "0x8000000000000110000000000000000", - "0x4830800080017ffe", - "0x480080007ff67fff", "0x482480017ffe8000", - "0xefffffffffffffdeffffffffffffffff", - "0x480080017ff47fff", - "0x400080027ff37ffb", - "0x402480017fff7ffb", - "0xffffffffffffffffffffffffffffffff", - "0x20680017fff7fff", - "0xe0", - "0x402780017fff7fff", - "0x1", - "0x400180007ff98002", - "0x4826800180028000", - "0xffffffffffffffff0000000000000000", - "0x400080017ff87fff", - "0x482480017ff88000", - "0x2", - "0x48307ff980007ffa", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0xa", - "0x482480017ff88000", - "0x1", - "0x48127ff87fff8000", - "0x480680017fff8000", - "0x0", - "0x48127ff57fff8000", - "0x10780017fff7fff", - "0x8", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x480680017fff8000", - "0x1", - "0x480680017fff8000", - "0x0", - "0x20680017fff7ffe", - "0xb3", - "0x40780017fff7fff", - "0x1", - "0x48127ff97fff8000", - "0x48127fef7fff8000", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x48127ffb7fff8000", - "0x48127ffa7fff8000", - "0x480080007ff88000", - "0x1104800180018000", - "0x1695", - "0x20680017fff7ffa", - "0x9e", - "0x20680017fff7ffd", - "0x98", - "0x40137ffe7fff8000", - "0x40137fff7fff8001", - "0x48307ffb80007ffc", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0xa", - "0x482480017ffa8000", - "0x1", - "0x48127ffa7fff8000", - "0x480680017fff8000", - "0x0", - "0x48127ff77fff8000", - "0x10780017fff7fff", - "0x8", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", - "0x480680017fff8000", - "0x1", - "0x480680017fff8000", - "0x0", - "0x20680017fff7ffe", - "0x71", - "0x40780017fff7fff", - "0x1", - "0x48127ff27fff8000", - "0x48127ff27fff8000", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x48127ffb7fff8000", - "0x48127ffa7fff8000", - "0x480080007ff88000", - "0x1104800180018000", - "0x166f", - "0x20680017fff7ffa", - "0x5c", - "0x20680017fff7ffd", - "0x56", - "0x48307ffb80007ffc", + "0x1bf8", + "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ff57fff8000", - "0x48127ff57fff8000", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -1511,140 +1543,73 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x4611", + "0x53c9", "0x482480017fff8000", - "0x4610", - "0x480080007fff8000", + "0x53c8", + "0x48127ffb7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007ff3", - "0x87a", + "0x4824800180007ffd", + "0x2af8", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007ff07fff", + "0x400080007ff57fff", "0x10780017fff7fff", - "0x26", - "0x4824800180007ff3", - "0x87a", - "0x400080007ff17fff", - "0x482480017ff18000", - "0x1", - "0x48127ffe7fff8000", - "0x480a7ffb7fff8000", - "0x480680017fff8000", - "0x0", - "0x48127ff37fff8000", - "0x48127ff37fff8000", - "0x480a80027fff8000", - "0x480a80007fff8000", - "0x480a80017fff8000", - "0x1104800180018000", - "0x1771", - "0x20680017fff7ffd", - "0xc", - "0x40780017fff7fff", - "0x1", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x48127ff97fff8000", + "0x2f", + "0x4824800180007ffd", + "0x2af8", + "0x400080007ff67fff", + "0x48127fff7fff8000", "0x480680017fff8000", "0x0", - "0x48127ffb7fff8000", - "0x48127ffa7fff8000", - "0x208b7fff7fff7ffe", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", - "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", "0x480680017fff8000", - "0x4f7574206f6620676173", - "0x400080007ffe7fff", - "0x482480017fee8000", - "0x1", - "0x48127fee7fff8000", - "0x480a7ffb7fff8000", + "0x1275130f95dda36bcbb6e9d28796c1d7e10b6e9fd5ed083e0ede4b12f613528", "0x480680017fff8000", + "0xa", + "0x482480017ff28000", "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x10780017fff7fff", - "0xc", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x480a7ffb7fff8000", "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", - "0x208b7fff7fff7ffe", - "0x48127ff37fff8000", - "0x48127ff37fff8000", + "0x53746f726167655772697465", + "0x400280007ffb7fff", + "0x400280017ffb7ffa", + "0x400280027ffb7ffb", + "0x400280037ffb7ffc", + "0x400280047ffb7ffd", + "0x480280067ffb8000", + "0x20680017fff7fff", + "0xe", + "0x480280057ffb8000", "0x40780017fff7fff", "0x1", + "0x48127ffb7fff8000", + "0x48127ffd7fff8000", + "0x482680017ffb8000", + "0x7", "0x480680017fff8000", - "0x4661696c656420746f20646573657269616c697a6520706172616d202333", - "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127ffc7fff8000", - "0x480a7ffb7fff8000", - "0x480680017fff8000", - "0x1", + "0x0", + "0x48127ffb7fff8000", "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", "0x208b7fff7fff7ffe", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x10780017fff7fff", - "0xc", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x480a7ffb7fff8000", + "0x480280057ffb8000", + "0x48127ffc7fff8000", + "0x482480017ffe8000", + "0x64", + "0x482680017ffb8000", + "0x9", "0x480680017fff8000", "0x1", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", + "0x480280077ffb8000", + "0x480280087ffb8000", "0x208b7fff7fff7ffe", - "0x48127ffa7fff8000", - "0x48127ff07fff8000", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4661696c656420746f20646573657269616c697a6520706172616d202332", + "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127ffc7fff8000", - "0x480a7ffb7fff8000", - "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", "0x482480017ff38000", - "0x3", - "0x10780017fff7fff", - "0x5", - "0x40780017fff7fff", - "0x7", - "0x48127ff37fff8000", - "0x40780017fff7fff", "0x1", - "0x480680017fff8000", - "0x4661696c656420746f20646573657269616c697a6520706172616d202331", - "0x400080007ffe7fff", - "0x48127ffd7fff8000", - "0x48127fee7fff8000", + "0x48127ff87fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -1659,7 +1624,8 @@ "0x400080007ffe7fff", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x21b6", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -1673,17 +1639,20 @@ "0x100000000000000000000000000000000", "0x400280007ff97fff", "0x10780017fff7fff", - "0xf4", + "0xeb", "0x4825800180007ffa", "0x0", "0x400280007ff97fff", "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0xb7c", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", + "0xb", + "0x48127ffe7fff8000", "0x482680017ffc8000", "0x1", "0x480a7ffd7fff8000", @@ -1691,7 +1660,8 @@ "0x0", "0x480280007ffc8000", "0x10780017fff7fff", - "0x8", + "0x9", + "0x48127ffe7fff8000", "0x480a7ffc7fff8000", "0x480a7ffd7fff8000", "0x480680017fff8000", @@ -1699,88 +1669,95 @@ "0x480680017fff8000", "0x0", "0x20680017fff7ffe", - "0xc9", + "0xbc", + "0x48127ffb7fff8000", "0xa0680017fff8004", "0xe", - "0x4824800180047ffe", + "0x4824800180047ffd", "0x800000000000000000000000000000000000000000000000000000000000000", "0x484480017ffe8000", "0x110000000000000000", "0x48307ffe7fff8002", - "0x480080007ff67ffc", - "0x480080017ff57ffc", + "0x480080007ff37ffc", + "0x480080017ff27ffc", "0x402480017ffb7ffd", "0xffffffffffffffeeffffffffffffffff", - "0x400080027ff47ffd", + "0x400080027ff17ffd", "0x10780017fff7fff", - "0xb7", + "0xa7", "0x484480017fff8001", "0x8000000000000000000000000000000", - "0x48307fff80007ffd", - "0x480080007ff77ffd", - "0x480080017ff67ffd", + "0x48307fff80007ffc", + "0x480080007ff47ffd", + "0x480080017ff37ffd", "0x402480017ffc7ffe", "0xf8000000000000000000000000000000", - "0x400080027ff57ffe", - "0x482480017ff58000", + "0x400080027ff27ffe", + "0x482480017ff28000", "0x3", - "0x48307ff680007ff7", + "0x48127ff97fff8000", + "0x48307ff480007ff5", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", - "0x482480017ff58000", + "0xb", + "0x48127ffe7fff8000", + "0x482480017ff28000", "0x1", - "0x48127ff57fff8000", + "0x48127ff27fff8000", "0x480680017fff8000", "0x0", - "0x480080007ff28000", + "0x480080007fef8000", "0x10780017fff7fff", - "0x8", - "0x48127ff57fff8000", - "0x48127ff57fff8000", + "0x9", + "0x48127ffe7fff8000", + "0x48127ff27fff8000", + "0x48127ff27fff8000", "0x480680017fff8000", "0x1", "0x480680017fff8000", "0x0", "0x20680017fff7ffe", - "0x87", + "0x74", + "0x48127ffb7fff8000", "0xa0680017fff8004", "0xe", - "0x4824800180047ffe", + "0x4824800180047ffd", "0x800000000000000000000000000000000000000000000000000000000000000", "0x484480017ffe8000", "0x110000000000000000", "0x48307ffe7fff8002", - "0x480080007ff67ffc", - "0x480080017ff57ffc", + "0x480080007ff37ffc", + "0x480080017ff27ffc", "0x402480017ffb7ffd", "0xffffffffffffffeeffffffffffffffff", - "0x400080027ff47ffd", + "0x400080027ff17ffd", "0x10780017fff7fff", - "0x75", + "0x5f", "0x484480017fff8001", "0x8000000000000000000000000000000", - "0x48307fff80007ffd", - "0x480080007ff77ffd", - "0x480080017ff67ffd", + "0x48307fff80007ffc", + "0x480080007ff47ffd", + "0x480080017ff37ffd", "0x402480017ffc7ffe", "0xf8000000000000000000000000000000", - "0x400080027ff57ffe", - "0x482480017ff58000", + "0x400080027ff27ffe", + "0x482480017ff28000", "0x3", - "0x48307ff680007ff7", + "0x48127ff97fff8000", + "0x48307ff480007ff5", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127fe47fff8000", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -1789,84 +1766,60 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x44fb", + "0x52ea", "0x482480017fff8000", - "0x44fa", - "0x480080007fff8000", + "0x52e9", + "0x48127ffb7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007fe2", - "0x1e50", + "0x4824800180007ffd", + "0x8bd8", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007ff77fff", + "0x400080007ff57fff", "0x10780017fff7fff", - "0x3b", - "0x4824800180007fe2", - "0x1e50", - "0x400080007ff87fff", - "0x482480017ff88000", - "0x1", - "0x480680017fff8000", - "0x476574436c617373486173684174", - "0x400280007ffb7fff", - "0x400280017ffb7ffd", - "0x400280027ffb7fe5", - "0x480280047ffb8000", - "0x20680017fff7fff", - "0x1f", - "0x480280057ffb8000", - "0x48307fee80007fff", - "0x480280037ffb8000", - "0x482680017ffb8000", - "0x6", - "0x20680017fff7ffd", + "0x22", + "0x4824800180007ffd", + "0x8bd8", + "0x400080007ff67fff", + "0x48127fff7fff8000", + "0x480a7ffb7fff8000", + "0x48127fdf7fff8000", + "0x48127fec7fff8000", + "0x1104800180018000", + "0x1eff", + "0x482480017fd18000", + "0x1", + "0x20680017fff7ffc", "0xc", "0x40780017fff7fff", "0x1", + "0x48127ffe7fff8000", + "0x48127ff87fff8000", "0x48127ff87fff8000", - "0x48127ffc7fff8000", - "0x48127ffc7fff8000", "0x480680017fff8000", "0x0", "0x48127ffb7fff8000", "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", - "0x480680017fff8000", - "0x57524f4e475f434c4153535f48415348", - "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127ffc7fff8000", - "0x48127ffc7fff8000", - "0x482480017ffb8000", - "0x1", - "0x10780017fff7fff", - "0x9", - "0x40780017fff7fff", - "0x6", - "0x480280037ffb8000", - "0x482680017ffb8000", - "0x7", - "0x480280057ffb8000", - "0x480280067ffb8000", - "0x48127ff37fff8000", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", + "0x48127fff7fff8000", + "0x482480017ff98000", + "0x64", + "0x48127ff97fff8000", "0x480680017fff8000", "0x1", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", + "0x48127ff97fff8000", + "0x48127ff97fff8000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482480017ff58000", + "0x482480017ff38000", "0x1", - "0x48127fdd7fff8000", + "0x48127ff87fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -1874,20 +1827,22 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x482480017ff48000", + "0x482480017ff18000", "0x3", + "0x482480017ff88000", + "0x42e", "0x10780017fff7fff", "0x5", - "0x40780017fff7fff", - "0x6", - "0x48127ff47fff8000", + "0x48127ff87fff8000", + "0x482480017ffa8000", + "0x94c", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202332", "0x400080007ffe7fff", - "0x48127ffd7fff8000", - "0x48127fe47fff8000", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -1895,20 +1850,22 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x482480017ff48000", + "0x482480017ff18000", "0x3", + "0x482480017ff88000", + "0xc6c", "0x10780017fff7fff", "0x5", - "0x40780017fff7fff", - "0x6", - "0x48127ff47fff8000", + "0x48127ff87fff8000", + "0x482480017ffa8000", + "0x118a", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202331", "0x400080007ffe7fff", - "0x48127ffd7fff8000", - "0x48127fef7fff8000", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -1923,7 +1880,8 @@ "0x400080007ffe7fff", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x21b6", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -1931,31 +1889,37 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x2", "0xa0680017fff8000", "0x7", "0x482680017ffa8000", "0x100000000000000000000000000000000", "0x400280007ff97fff", "0x10780017fff7fff", - "0x9e", + "0x114", "0x4825800180007ffa", "0x0", "0x400280007ff97fff", "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0x17c", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", + "0xb", + "0x48127ffe7fff8000", "0x482680017ffc8000", "0x1", "0x480a7ffd7fff8000", "0x480680017fff8000", "0x0", - "0x480a7ffc7fff8000", + "0x480280007ffc8000", "0x10780017fff7fff", - "0x8", + "0x9", + "0x48127ffe7fff8000", "0x480a7ffc7fff8000", "0x480a7ffd7fff8000", "0x480680017fff8000", @@ -1963,44 +1927,97 @@ "0x480680017fff8000", "0x0", "0x20680017fff7ffe", - "0x73", - "0x480080007fff8000", - "0xa0680017fff8000", - "0x12", - "0x4824800180007ffe", - "0x10000000000000000", - "0x4844800180008002", - "0x8000000000000110000000000000000", - "0x4830800080017ffe", - "0x480080007ff57fff", - "0x482480017ffe8000", - "0xefffffffffffffdeffffffffffffffff", - "0x480080017ff37fff", - "0x400080027ff27ffb", - "0x402480017fff7ffb", - "0xffffffffffffffffffffffffffffffff", + "0xe5", + "0x40137fff7fff8001", + "0x48127ffb7fff8000", + "0xa0680017fff8004", + "0xe", + "0x4825800180048001", + "0x800000000000000000000000000000000000000000000000000000000000000", + "0x484480017ffe8000", + "0x110000000000000000", + "0x48307ffe7fff8002", + "0x480080007ff37ffc", + "0x480080017ff27ffc", + "0x402480017ffb7ffd", + "0xffffffffffffffeeffffffffffffffff", + "0x400080027ff17ffd", + "0x10780017fff7fff", + "0xcf", + "0x484480017fff8001", + "0x8000000000000000000000000000000", + "0x48317fff80008001", + "0x480080007ff47ffd", + "0x480080017ff37ffd", + "0x402480017ffc7ffe", + "0xf8000000000000000000000000000000", + "0x400080027ff27ffe", + "0x482480017ff28000", + "0x3", + "0x48127ff97fff8000", + "0x48307ff480007ff5", "0x20680017fff7fff", - "0x5e", - "0x402780017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xb0", + "0x400180007ff38000", + "0x482480017ff38000", "0x1", - "0x400080007ff87ffe", - "0x482480017ffe8000", - "0xffffffffffffffff0000000000000000", - "0x400080017ff77fff", - "0x482480017ff78000", - "0x2", - "0x48307ff880007ff9", + "0x48127ff37fff8000", + "0x48127ffc7fff8000", + "0x48307ffd80007ffe", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0xb", + "0x48127ffe7fff8000", + "0x482480017ffb8000", + "0x1", + "0x48127ffb7fff8000", + "0x480680017fff8000", + "0x0", + "0x48127ff87fff8000", + "0x10780017fff7fff", + "0x9", + "0x48127ffe7fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x20680017fff7ffe", + "0x83", + "0x40780017fff7fff", + "0x1", + "0x48127ff37fff8000", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x48127ffb7fff8000", + "0x48127ffa7fff8000", + "0x480080007ff88000", + "0x1104800180018000", + "0x1cd5", + "0x20680017fff7ffa", + "0x6d", + "0x48127ff97fff8000", + "0x20680017fff7ffc", + "0x65", + "0x48127fff7fff8000", + "0x48307ff980007ffa", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127ff17fff8000", + "0x48127ff37fff8000", + "0x482480017ffb8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -2009,63 +2026,122 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x441f", + "0x51e6", "0x482480017fff8000", - "0x441e", - "0x480080007fff8000", + "0x51e5", + "0x48127ffb7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007fef", - "0x1248", + "0x4824800180007ffd", + "0x2cec", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007ff77fff", + "0x400080007fed7fff", "0x10780017fff7fff", - "0x26", - "0x4824800180007fef", - "0x1248", - "0x400080007ff87fff", - "0x482480017ff88000", + "0x32", + "0x4824800180007ffd", + "0x2cec", + "0x400080007fee7fff", + "0x48127fff7fff8000", + "0x482480017fed8000", "0x1", "0x480680017fff8000", - "0x476574426c6f636b48617368", + "0x43616c6c436f6e7472616374", "0x400280007ffb7fff", "0x400280017ffb7ffd", - "0x400280027ffb7ff3", - "0x480280047ffb8000", + "0x400380027ffb8001", + "0x400380037ffb8000", + "0x400280047ffb7ff1", + "0x400280057ffb7ff2", + "0x480280077ffb8000", "0x20680017fff7fff", "0x10", + "0x480280067ffb8000", "0x40780017fff7fff", "0x1", - "0x480280057ffb8000", + "0x480680017fff8000", + "0x657865637574655f616e645f726576657274", "0x400080007ffe7fff", - "0x48127ffb7fff8000", - "0x480280037ffb8000", + "0x48127ffd7fff8000", "0x482680017ffb8000", - "0x6", + "0xa", + "0x48127ffc7fff8000", + "0x482480017ffb8000", + "0x1", + "0x10780017fff7fff", + "0xb", + "0x40780017fff7fff", + "0x2", + "0x480280067ffb8000", + "0x482480017fff8000", + "0x118", + "0x482680017ffb8000", + "0xa", + "0x480280087ffb8000", + "0x480280097ffb8000", + "0x48127ff67fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", "0x480680017fff8000", - "0x0", + "0x1", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x482480017feb8000", + "0x1", + "0x48127ff87fff8000", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", "0x48127ffa7fff8000", "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x48127ffd7fff8000", - "0x480280037ffb8000", - "0x482680017ffb8000", - "0x7", + "0x48127ff77fff8000", + "0x482480017ffe8000", + "0x492", + "0x10780017fff7fff", + "0xe", + "0x48127ff87fff8000", + "0x482480017ff88000", + "0x7b2", + "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x480280057ffb8000", - "0x480280067ffb8000", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", + "0x48127ff47fff8000", + "0x482480017ffa8000", + "0x102c", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4f7574206f6620676173", + "0x4661696c656420746f20646573657269616c697a6520706172616d202333", "0x400080007ffe7fff", - "0x482480017ff58000", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", + "0x480a7ffb7fff8000", + "0x480680017fff8000", "0x1", - "0x48127fea7fff8000", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4661696c656420746f20646573657269616c697a6520706172616d202332", + "0x400080007ffe7fff", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x159a", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -2073,20 +2149,22 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x482480017ff28000", + "0x482480017ff18000", "0x3", + "0x482480017ff88000", + "0x159a", "0x10780017fff7fff", "0x5", - "0x40780017fff7fff", - "0x8", - "0x48127ff27fff8000", + "0x48127ff87fff8000", + "0x482480017ffa8000", + "0x1b12", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202331", "0x400080007ffe7fff", - "0x48127ffd7fff8000", - "0x48127fed7fff8000", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -2101,7 +2179,8 @@ "0x400080007ffe7fff", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x213e", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -2114,73 +2193,161 @@ "0xa0680017fff8000", "0x7", "0x482680017ffa8000", - "0xffffffffffffffffffffffffffff7d38", + "0xfffffffffffffffffffffffffffff560", "0x400280007ff97fff", "0x10780017fff7fff", - "0xe7", + "0x138", "0x4825800180007ffa", - "0x82c8", + "0xaa0", "0x400280007ff97fff", "0x482680017ff98000", "0x1", - "0x480a7ffc7fff8000", - "0x480a7ffd7fff8000", - "0x1104800180018000", - "0x1590", - "0x20680017fff7ffc", - "0xce", - "0x48127ff97fff8000", - "0x48127fd57fff8000", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x40137ff97fff8000", - "0x40137ffa7fff8001", - "0x40137ffb7fff8002", - "0x1104800180018000", - "0x1652", - "0x20680017fff7feb", - "0xbb", - "0x20680017fff7fee", - "0xab", - "0x48307fec80007fed", + "0x48127ffe7fff8000", + "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x98", - "0x482480017feb8000", + "0xb", + "0x48127ffe7fff8000", + "0x482680017ffc8000", "0x1", - "0x48127feb7fff8000", - "0x480080007fe98000", - "0x48307ffd80007ffe", + "0x480a7ffd7fff8000", + "0x480680017fff8000", + "0x0", + "0x480a7ffc7fff8000", + "0x10780017fff7fff", + "0x9", + "0x48127ffe7fff8000", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x20680017fff7ffe", + "0x10a", + "0x400180007fff8002", + "0x48127ffb7fff8000", + "0xa0680017fff8000", + "0x12", + "0x4825800180008002", + "0x10000000000000000", + "0x4844800180008002", + "0x8000000000000110000000000000000", + "0x4830800080017ffe", + "0x480080007ff37fff", + "0x482480017ffe8000", + "0xefffffffffffffdeffffffffffffffff", + "0x480080017ff17fff", + "0x400080027ff07ffb", + "0x402480017fff7ffb", + "0xffffffffffffffffffffffffffffffff", + "0x20680017fff7fff", + "0xf2", + "0x402780017fff7fff", + "0x1", + "0x400180007ff68002", + "0x4826800180028000", + "0xffffffffffffffff0000000000000000", + "0x400080017ff57fff", + "0x482480017ff58000", + "0x2", + "0x48127ffc7fff8000", + "0x48307ff780007ff8", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x81", - "0x482480017ffc8000", + "0xb", + "0x48127ffe7fff8000", + "0x482480017ff58000", "0x1", - "0x48127ffc7fff8000", - "0x480080007ffa8000", - "0x48307ffd80007ffe", + "0x48127ff57fff8000", + "0x480680017fff8000", + "0x0", + "0x48127ff27fff8000", + "0x10780017fff7fff", + "0x9", + "0x48127ffe7fff8000", + "0x48127ff57fff8000", + "0x48127ff57fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x20680017fff7ffe", + "0xc1", + "0x40780017fff7fff", + "0x1", + "0x48127ff77fff8000", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x48127ffb7fff8000", + "0x48127ffa7fff8000", + "0x480080007ff88000", + "0x1104800180018000", + "0x1bb5", + "0x20680017fff7ffa", + "0xab", + "0x48127ff97fff8000", + "0x20680017fff7ffc", + "0xa3", + "0x40137ffd7fff8000", + "0x40137ffe7fff8001", + "0x48127fff7fff8000", + "0x48307ff980007ffa", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x6a", - "0x482480017ffc8000", + "0xb", + "0x48127ffe7fff8000", + "0x482480017ff78000", "0x1", - "0x48127ffc7fff8000", - "0x480080007ffa8000", - "0x48307ffd80007ffe", + "0x48127ff77fff8000", + "0x480680017fff8000", + "0x0", + "0x48127ff47fff8000", + "0x10780017fff7fff", + "0x9", + "0x48127ffe7fff8000", + "0x48127ff77fff8000", + "0x48127ff77fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x20680017fff7ffe", + "0x78", + "0x40780017fff7fff", + "0x1", + "0x48127fef7fff8000", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x48127ffb7fff8000", + "0x48127ffa7fff8000", + "0x480080007ff88000", + "0x1104800180018000", + "0x1b8b", + "0x20680017fff7ffa", + "0x62", + "0x48127ff97fff8000", + "0x20680017fff7ffc", + "0x5a", + "0x48127fff7fff8000", + "0x48307ff980007ffa", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127fda7fff8000", - "0x48127fda7fff8000", + "0x48127ff37fff8000", + "0x482480017ffb8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -2189,51 +2356,36 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x436b", + "0x509c", "0x482480017fff8000", - "0x436a", - "0x480080007fff8000", + "0x509b", + "0x48127ffb7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007fd8", - "0x8070", + "0x4824800180007ffd", + "0x87a", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007fd57fff", + "0x400080007fed7fff", "0x10780017fff7fff", - "0x36", - "0x4824800180007fd8", - "0x8070", - "0x400080007fd67fff", - "0x482480017fd68000", + "0x27", + "0x4824800180007ffd", + "0x87a", + "0x400080007fee7fff", + "0x482480017fee8000", "0x1", "0x48127ffe7fff8000", "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x0", + "0x48127ff07fff8000", + "0x48127ff07fff8000", + "0x480a80027fff8000", "0x480a80007fff8000", "0x480a80017fff8000", - "0x480a80027fff8000", - "0x48127fd67fff8000", - "0x48127fd67fff8000", - "0x48127fd67fff8000", - "0x48127fd67fff8000", - "0x48127fd67fff8000", - "0x48127fd67fff8000", - "0x48127fd67fff8000", - "0x48127fd67fff8000", - "0x48127fd67fff8000", - "0x48127fd67fff8000", - "0x48127fd67fff8000", - "0x48127fd67fff8000", - "0x48127fd67fff8000", - "0x48127fd67fff8000", - "0x48127fd67fff8000", - "0x48127fd67fff8000", - "0x48127fd67fff8000", - "0x48127fd97fff8000", - "0x48127fdc7fff8000", - "0x48127fdf7fff8000", "0x1104800180018000", - "0x1a6d", + "0x1d2c", "0x20680017fff7ffd", "0xc", "0x40780017fff7fff", @@ -2247,7 +2399,8 @@ "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", "0x48127ffa7fff8000", - "0x48127ffa7fff8000", + "0x482480017ffa8000", + "0x64", "0x48127ffa7fff8000", "0x480680017fff8000", "0x1", @@ -2259,9 +2412,9 @@ "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482480017fd38000", + "0x482480017feb8000", "0x1", - "0x48127fd37fff8000", + "0x48127ff87fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -2269,13 +2422,30 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", + "0x48127ff77fff8000", + "0x482480017ffe8000", + "0x492", + "0x10780017fff7fff", + "0xe", + "0x48127ff87fff8000", + "0x482480017ff88000", + "0x7b2", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x208b7fff7fff7ffe", + "0x48127ff07fff8000", + "0x482480017ffa8000", + "0x102c", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4661696c656420746f20646573657269616c697a6520706172616d202335", + "0x4661696c656420746f20646573657269616c697a6520706172616d202333", "0x400080007ffe7fff", - "0x48127fde7fff8000", - "0x48127fde7fff8000", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -2283,41 +2453,30 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", - "0x480680017fff8000", - "0x4661696c656420746f20646573657269616c697a6520706172616d202334", - "0x400080007ffe7fff", - "0x48127fe27fff8000", - "0x48127fe27fff8000", + "0x48127ff77fff8000", + "0x482480017ffe8000", + "0x1464", + "0x10780017fff7fff", + "0xe", + "0x48127ff87fff8000", + "0x482480017ff88000", + "0x1784", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", - "0x480680017fff8000", - "0x4661696c656420746f20646573657269616c697a6520706172616d202333", - "0x400080007ffe7fff", - "0x48127fe67fff8000", - "0x48127fe67fff8000", - "0x480a7ffb7fff8000", - "0x480680017fff8000", - "0x1", "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", "0x208b7fff7fff7ffe", + "0x48127ff87fff8000", + "0x482480017ffa8000", + "0x1ffe", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202332", "0x400080007ffe7fff", - "0x48127fe77fff8000", - "0x48127fe77fff8000", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -2325,21 +2484,22 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x48127fe97fff8000", - "0x48127fe97fff8000", - "0x480a7ffb7fff8000", - "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", - "0x208b7fff7fff7ffe", + "0x482480017ff08000", + "0x3", + "0x482480017ff78000", + "0x2148", + "0x10780017fff7fff", + "0x5", + "0x48127ff87fff8000", + "0x482480017ffa8000", + "0x2724", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202331", "0x400080007ffe7fff", - "0x48127ff77fff8000", - "0x48127fd37fff8000", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -2354,7 +2514,8 @@ "0x400080007ffe7fff", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x2134", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -2362,25 +2523,26 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x2", "0xa0680017fff8000", "0x7", "0x482680017ffa8000", "0x100000000000000000000000000000000", "0x400280007ff97fff", "0x10780017fff7fff", - "0xf3", + "0x109", "0x4825800180007ffa", "0x0", "0x400280007ff97fff", "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0xb7c", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", + "0xb", + "0x48127ffe7fff8000", "0x482680017ffc8000", "0x1", "0x480a7ffd7fff8000", @@ -2388,7 +2550,8 @@ "0x0", "0x480280007ffc8000", "0x10780017fff7fff", - "0x8", + "0x9", + "0x48127ffe7fff8000", "0x480a7ffc7fff8000", "0x480a7ffd7fff8000", "0x480680017fff8000", @@ -2396,89 +2559,95 @@ "0x480680017fff8000", "0x0", "0x20680017fff7ffe", - "0xc8", - "0x40137fff7fff8000", + "0xda", + "0x48127ffb7fff8000", "0xa0680017fff8004", "0xe", - "0x4825800180048000", + "0x4824800180047ffd", "0x800000000000000000000000000000000000000000000000000000000000000", "0x484480017ffe8000", "0x110000000000000000", "0x48307ffe7fff8002", - "0x480080007ff67ffc", - "0x480080017ff57ffc", + "0x480080007ff37ffc", + "0x480080017ff27ffc", "0x402480017ffb7ffd", "0xffffffffffffffeeffffffffffffffff", - "0x400080027ff47ffd", + "0x400080027ff17ffd", "0x10780017fff7fff", - "0xb5", + "0xc5", "0x484480017fff8001", "0x8000000000000000000000000000000", - "0x48317fff80008000", - "0x480080007ff77ffd", - "0x480080017ff67ffd", + "0x48307fff80007ffc", + "0x480080007ff47ffd", + "0x480080017ff37ffd", "0x402480017ffc7ffe", "0xf8000000000000000000000000000000", - "0x400080027ff57ffe", - "0x482480017ff58000", + "0x400080027ff27ffe", + "0x482480017ff28000", "0x3", - "0x48307ff680007ff7", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x98", - "0x400180007ff58001", - "0x482480017ff58000", - "0x1", - "0x48127ff57fff8000", - "0x48307ffe80007fff", + "0x48127ff97fff8000", + "0x48307ff480007ff5", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", - "0x482480017ffd8000", + "0xb", + "0x48127ffe7fff8000", + "0x482480017ff28000", "0x1", - "0x48127ffd7fff8000", + "0x48127ff27fff8000", "0x480680017fff8000", "0x0", - "0x48127ffa7fff8000", + "0x480080007fef8000", "0x10780017fff7fff", - "0x8", - "0x48127ffd7fff8000", - "0x48127ffd7fff8000", + "0x9", + "0x48127ffe7fff8000", + "0x48127ff27fff8000", + "0x48127ff27fff8000", "0x480680017fff8000", "0x1", "0x480680017fff8000", "0x0", "0x20680017fff7ffe", - "0x6f", - "0x40780017fff7fff", - "0x1", - "0x48127ff67fff8000", - "0x48127fe97fff8000", - "0x48127ff97fff8000", - "0x48127ff97fff8000", + "0x92", "0x48127ffb7fff8000", - "0x48127ffa7fff8000", - "0x480080007ff88000", - "0x1104800180018000", - "0x129f", - "0x20680017fff7ffa", - "0x5a", - "0x20680017fff7ffd", - "0x54", - "0x48307ffb80007ffc", + "0xa0680017fff8004", + "0xe", + "0x4824800180047ffd", + "0x800000000000000000000000000000000000000000000000000000000000000", + "0x484480017ffe8000", + "0x110000000000000000", + "0x48307ffe7fff8002", + "0x480080007ff37ffc", + "0x480080017ff27ffc", + "0x402480017ffb7ffd", + "0xffffffffffffffeeffffffffffffffff", + "0x400080027ff17ffd", + "0x10780017fff7fff", + "0x7d", + "0x484480017fff8001", + "0x8000000000000000000000000000000", + "0x48307fff80007ffc", + "0x480080007ff47ffd", + "0x480080017ff37ffd", + "0x402480017ffc7ffe", + "0xf8000000000000000000000000000000", + "0x400080027ff27ffe", + "0x482480017ff28000", + "0x3", + "0x48127ff97fff8000", + "0x48307ff480007ff5", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ff57fff8000", - "0x48127ff57fff8000", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -2487,89 +2656,90 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x4241", + "0x4f70", "0x482480017fff8000", - "0x4240", - "0x480080007fff8000", + "0x4f6f", + "0x48127ffb7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007ff3", - "0x2404", + "0x4824800180007ffd", + "0x2db4", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007ff07fff", + "0x400080007ff57fff", "0x10780017fff7fff", - "0x24", - "0x4824800180007ff3", - "0x2404", - "0x400080007ff17fff", - "0x482480017ff18000", + "0x40", + "0x4824800180007ffd", + "0x2db4", + "0x400080007ff67fff", + "0x48127fff7fff8000", + "0x482480017ff58000", "0x1", "0x480680017fff8000", - "0x4c69627261727943616c6c", + "0x476574436c617373486173684174", "0x400280007ffb7fff", "0x400280017ffb7ffd", - "0x400380027ffb8000", - "0x400380037ffb8001", - "0x400280047ffb7ff5", - "0x400280057ffb7ff6", - "0x480280077ffb8000", + "0x400280027ffb7fde", + "0x480280047ffb8000", "0x20680017fff7fff", - "0xb", - "0x48127ffd7fff8000", - "0x480280067ffb8000", + "0x21", + "0x480280037ffb8000", + "0x480280057ffb8000", + "0x48307fe980007fff", "0x482680017ffb8000", - "0xa", + "0x6", + "0x48127ffc7fff8000", + "0x20680017fff7ffd", + "0xd", + "0x40780017fff7fff", + "0x1", + "0x48127ff77fff8000", + "0x482480017ffd8000", + "0x2bc", + "0x48127ffb7fff8000", "0x480680017fff8000", "0x0", - "0x480280087ffb8000", - "0x480280097ffb8000", - "0x208b7fff7fff7ffe", - "0x48127ffd7fff8000", - "0x480280067ffb8000", - "0x482680017ffb8000", - "0xa", - "0x480680017fff8000", - "0x1", - "0x480280087ffb8000", - "0x480280097ffb8000", + "0x48127ffb7fff8000", + "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4f7574206f6620676173", + "0x57524f4e475f434c4153535f48415348", "0x400080007ffe7fff", - "0x482480017fee8000", - "0x1", - "0x48127fee7fff8000", - "0x480a7ffb7fff8000", - "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", + "0x48127ffd7fff8000", + "0x48127ffb7fff8000", + "0x48127ffc7fff8000", + "0x482480017ffb8000", "0x1", - "0x208b7fff7fff7ffe", - "0x48127ff87fff8000", - "0x48127ff87fff8000", "0x10780017fff7fff", - "0xc", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x480a7ffb7fff8000", + "0xb", + "0x40780017fff7fff", + "0x6", + "0x480280037ffb8000", + "0x482480017fff8000", + "0x2e4", + "0x482680017ffb8000", + "0x7", + "0x480280057ffb8000", + "0x480280067ffb8000", + "0x48127ff27fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", "0x480680017fff8000", "0x1", "0x48127ffa7fff8000", "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", - "0x48127ff77fff8000", - "0x48127fea7fff8000", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4661696c656420746f20646573657269616c697a6520706172616d202333", + "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127ffc7fff8000", + "0x482480017ff38000", + "0x1", + "0x48127ff87fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -2577,13 +2747,22 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", + "0x482480017ff18000", + "0x3", + "0x482480017ff88000", + "0x42e", + "0x10780017fff7fff", + "0x5", + "0x48127ff87fff8000", + "0x482480017ffa8000", + "0x94c", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202332", "0x400080007ffe7fff", "0x48127ffc7fff8000", - "0x48127fef7fff8000", + "0x48127ffc7fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -2591,20 +2770,22 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x482480017ff48000", + "0x482480017ff18000", "0x3", + "0x482480017ff88000", + "0xc6c", "0x10780017fff7fff", "0x5", - "0x40780017fff7fff", - "0x6", - "0x48127ff47fff8000", + "0x48127ff87fff8000", + "0x482480017ffa8000", + "0x118a", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202331", "0x400080007ffe7fff", - "0x48127ffd7fff8000", - "0x48127fef7fff8000", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -2619,7 +2800,8 @@ "0x400080007ffe7fff", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x21b6", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -2633,25 +2815,29 @@ "0x100000000000000000000000000000000", "0x400280007ff97fff", "0x10780017fff7fff", - "0xe9", + "0xac", "0x4825800180007ffa", "0x0", "0x400280007ff97fff", "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0x14c8", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", + "0xb", + "0x48127ffe7fff8000", "0x482680017ffc8000", "0x1", "0x480a7ffd7fff8000", "0x480680017fff8000", "0x0", - "0x480280007ffc8000", + "0x480a7ffc7fff8000", "0x10780017fff7fff", - "0x8", + "0x9", + "0x48127ffe7fff8000", "0x480a7ffc7fff8000", "0x480a7ffd7fff8000", "0x480680017fff8000", @@ -2659,79 +2845,47 @@ "0x480680017fff8000", "0x0", "0x20680017fff7ffe", - "0xbe", - "0xa0680017fff8004", - "0xe", - "0x4824800180047ffe", - "0x800000000000000000000000000000000000000000000000000000000000000", - "0x484480017ffe8000", - "0x110000000000000000", - "0x48307ffe7fff8002", - "0x480080007ff67ffc", - "0x480080017ff57ffc", - "0x402480017ffb7ffd", - "0xffffffffffffffeeffffffffffffffff", - "0x400080027ff47ffd", - "0x10780017fff7fff", - "0xac", - "0x484480017fff8001", - "0x8000000000000000000000000000000", - "0x48307fff80007ffd", - "0x480080007ff77ffd", - "0x480080017ff67ffd", - "0x402480017ffc7ffe", - "0xf8000000000000000000000000000000", - "0x400080027ff57ffe", - "0x482480017ff58000", - "0x3", - "0x48307ff680007ff7", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x8f", - "0x482480017ff58000", - "0x1", - "0x48127ff57fff8000", - "0x480080007ff38000", - "0x48307ffd80007ffe", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x78", - "0x482480017ffc8000", - "0x1", - "0x48127ffc7fff8000", - "0x480080007ffa8000", - "0x48307ffd80007ffe", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x61", - "0x482480017ffc8000", - "0x1", - "0x48127ffc7fff8000", - "0x480080007ffa8000", - "0x48307ffd80007ffe", + "0x7d", + "0x480080007fff8000", + "0x48127ffa7fff8000", + "0xa0680017fff8000", + "0x12", + "0x4824800180007ffd", + "0x10000000000000000", + "0x4844800180008002", + "0x8000000000000110000000000000000", + "0x4830800080017ffe", + "0x480080007ff27fff", + "0x482480017ffe8000", + "0xefffffffffffffdeffffffffffffffff", + "0x480080017ff07fff", + "0x400080027fef7ffb", + "0x402480017fff7ffb", + "0xffffffffffffffffffffffffffffffff", "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x4a", - "0x482480017ffc8000", + "0x65", + "0x402780017fff7fff", "0x1", + "0x400080007ff57ffd", + "0x482480017ffd8000", + "0xffffffffffffffff0000000000000000", + "0x400080017ff47fff", + "0x482480017ff48000", + "0x2", "0x48127ffc7fff8000", - "0x480080007ffa8000", - "0x48307ffd80007ffe", + "0x48307ff680007ff7", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127fec7fff8000", - "0x48127fdf7fff8000", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -2740,103 +2894,68 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x4144", + "0x4e82", "0x482480017fff8000", - "0x4143", - "0x480080007fff8000", + "0x4e81", + "0x48127ffb7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007fdd", - "0x5172", + "0x4824800180007ffd", + "0x29cc", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007fe77fff", + "0x400080007ff57fff", "0x10780017fff7fff", - "0x16", - "0x4824800180007fdd", - "0x5172", - "0x400080007fe87fff", + "0x2a", + "0x4824800180007ffd", + "0x29cc", + "0x400080007ff67fff", "0x48127fff7fff8000", - "0x480a7ffb7fff8000", - "0x48127fe07fff8000", - "0x48127fe97fff8000", - "0x48127fec7fff8000", - "0x48127fef7fff8000", - "0x48127ff27fff8000", - "0x1104800180018000", - "0x19ca", - "0x482480017fcc8000", - "0x1", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", - "0x480680017fff8000", - "0x4f7574206f6620676173", - "0x400080007ffe7fff", - "0x482480017fe58000", + "0x482480017ff58000", "0x1", - "0x48127fd87fff8000", - "0x480a7ffb7fff8000", "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", + "0x476574426c6f636b48617368", + "0x400280007ffb7fff", + "0x400280017ffb7ffd", + "0x400280027ffb7fef", + "0x480280047ffb8000", + "0x20680017fff7fff", + "0x11", + "0x480280037ffb8000", "0x40780017fff7fff", "0x1", - "0x480680017fff8000", - "0x4661696c656420746f20646573657269616c697a6520706172616d202335", + "0x480280057ffb8000", "0x400080007ffe7fff", - "0x48127ff07fff8000", - "0x48127fe37fff8000", - "0x480a7ffb7fff8000", - "0x480680017fff8000", - "0x1", "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", - "0x480680017fff8000", - "0x4661696c656420746f20646573657269616c697a6520706172616d202334", - "0x400080007ffe7fff", - "0x48127ff47fff8000", - "0x48127fe77fff8000", - "0x480a7ffb7fff8000", + "0x48127ffc7fff8000", + "0x482680017ffb8000", + "0x6", "0x480680017fff8000", - "0x1", + "0x0", "0x48127ffa7fff8000", "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", - "0x480680017fff8000", - "0x4661696c656420746f20646573657269616c697a6520706172616d202333", - "0x400080007ffe7fff", - "0x48127ff87fff8000", - "0x48127feb7fff8000", - "0x480a7ffb7fff8000", + "0x480280037ffb8000", + "0x48127ffc7fff8000", + "0x482480017ffe8000", + "0x12c", + "0x482680017ffb8000", + "0x7", "0x480680017fff8000", "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", + "0x480280057ffb8000", + "0x480280067ffb8000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4661696c656420746f20646573657269616c697a6520706172616d202332", + "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127fef7fff8000", + "0x482480017ff38000", + "0x1", + "0x48127ff87fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -2844,20 +2963,22 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x482480017ff48000", + "0x482480017fef8000", "0x3", + "0x482480017ff78000", + "0x258", "0x10780017fff7fff", "0x5", - "0x40780017fff7fff", - "0x6", - "0x48127ff47fff8000", + "0x48127ff87fff8000", + "0x482480017ffa8000", + "0x83e", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202331", "0x400080007ffe7fff", - "0x48127ffd7fff8000", - "0x48127fef7fff8000", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -2872,7 +2993,8 @@ "0x400080007ffe7fff", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x21b6", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -2880,75 +3002,85 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x3", "0xa0680017fff8000", "0x7", "0x482680017ffa8000", - "0x100000000000000000000000000000000", + "0xffffffffffffffffffffffffffff6f8c", "0x400280007ff97fff", "0x10780017fff7fff", - "0x9a", + "0xf6", "0x4825800180007ffa", - "0x0", + "0x9074", "0x400280007ff97fff", "0x482680017ff98000", "0x1", - "0x48297ffc80007ffd", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", + "0x1104800180018000", + "0x1b23", + "0x48127fd67fff8000", + "0x20680017fff7ffb", + "0xdb", + "0x48127ff87fff8000", + "0x48127ffe7fff8000", + "0x48127ff77fff8000", + "0x48127ff77fff8000", + "0x40137ff87fff8000", + "0x40137ff97fff8001", + "0x40137ffa7fff8002", + "0x1104800180018000", + "0x1be4", + "0x20680017fff7feb", + "0xc7", + "0x48127fea7fff8000", + "0x20680017fff7fed", + "0xb5", + "0x48127fff7fff8000", + "0x48307fea80007feb", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", - "0x482680017ffc8000", + "0xa0", + "0x482480017fe98000", "0x1", - "0x480a7ffd7fff8000", - "0x480680017fff8000", - "0x0", - "0x480280007ffc8000", + "0x48127fe97fff8000", + "0x48127ffc7fff8000", + "0x480080007fe68000", + "0x48307ffc80007ffd", + "0x20680017fff7fff", + "0x4", "0x10780017fff7fff", - "0x8", - "0x480a7ffc7fff8000", - "0x480a7ffd7fff8000", - "0x480680017fff8000", - "0x1", - "0x480680017fff8000", - "0x0", - "0x20680017fff7ffe", - "0x6f", - "0xa0680017fff8004", - "0xe", - "0x4824800180047ffe", - "0x800000000000000000000000000000000000000000000000000000000000000", - "0x484480017ffe8000", - "0x110000000000000000", - "0x48307ffe7fff8002", - "0x480080007ff67ffc", - "0x480080017ff57ffc", - "0x402480017ffb7ffd", - "0xffffffffffffffeeffffffffffffffff", - "0x400080027ff47ffd", + "0x87", + "0x482480017ffb8000", + "0x1", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x480080007ff88000", + "0x48307ffc80007ffd", + "0x20680017fff7fff", + "0x4", "0x10780017fff7fff", - "0x5d", - "0x484480017fff8001", - "0x8000000000000000000000000000000", - "0x48307fff80007ffd", - "0x480080007ff77ffd", - "0x480080017ff67ffd", - "0x402480017ffc7ffe", - "0xf8000000000000000000000000000000", - "0x400080027ff57ffe", - "0x482480017ff58000", - "0x3", - "0x48307ff680007ff7", + "0x6e", + "0x482480017ffb8000", + "0x1", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x480080007ff88000", + "0x48307ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127fef7fff8000", + "0x48127fd57fff8000", + "0x482480017ffa8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -2957,60 +3089,81 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x406b", + "0x4dbf", "0x482480017fff8000", - "0x406a", - "0x480080007fff8000", + "0x4dbe", + "0x48127ffa7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007fed", - "0x128e", + "0x4824800180007ffd", + "0x896c", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007ff77fff", + "0x400080007fcf7fff", "0x10780017fff7fff", - "0x23", - "0x4824800180007fed", - "0x128e", - "0x400080007ff87fff", - "0x482480017ff88000", + "0x37", + "0x4824800180007ffd", + "0x896c", + "0x400080007fd07fff", + "0x482480017fd08000", "0x1", - "0x480680017fff8000", - "0x5265706c616365436c617373", - "0x400280007ffb7fff", - "0x400280017ffb7ffd", - "0x400280027ffb7ff0", - "0x480280047ffb8000", - "0x20680017fff7fff", - "0xd", + "0x48127ffe7fff8000", + "0x480a7ffb7fff8000", + "0x480a80007fff8000", + "0x480a80017fff8000", + "0x480a80027fff8000", + "0x48127fd07fff8000", + "0x48127fd07fff8000", + "0x48127fd07fff8000", + "0x48127fd07fff8000", + "0x48127fd07fff8000", + "0x48127fd07fff8000", + "0x48127fd07fff8000", + "0x48127fd07fff8000", + "0x48127fd07fff8000", + "0x48127fd07fff8000", + "0x48127fd07fff8000", + "0x48127fd07fff8000", + "0x48127fd07fff8000", + "0x48127fd07fff8000", + "0x48127fd07fff8000", + "0x48127fd07fff8000", + "0x48127fd07fff8000", + "0x48127fd67fff8000", + "0x48127fda7fff8000", + "0x48127fde7fff8000", + "0x1104800180018000", + "0x2037", + "0x20680017fff7ffd", + "0xc", "0x40780017fff7fff", "0x1", - "0x48127ffc7fff8000", - "0x480280037ffb8000", - "0x482680017ffb8000", - "0x5", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x48127ff97fff8000", "0x480680017fff8000", "0x0", "0x48127ffb7fff8000", "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", - "0x48127ffd7fff8000", - "0x480280037ffb8000", - "0x482680017ffb8000", - "0x7", + "0x48127ffa7fff8000", + "0x482480017ffa8000", + "0x64", + "0x48127ffa7fff8000", "0x480680017fff8000", "0x1", - "0x480280057ffb8000", - "0x480280067ffb8000", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482480017ff58000", + "0x482480017fcd8000", "0x1", - "0x48127fe87fff8000", + "0x48127ff87fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -3018,20 +3171,83 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x482480017ff48000", - "0x3", - "0x10780017fff7fff", - "0x5", "0x40780017fff7fff", - "0x6", - "0x48127ff47fff8000", + "0x1", + "0x480680017fff8000", + "0x4661696c656420746f20646573657269616c697a6520706172616d202335", + "0x400080007ffe7fff", + "0x48127fda7fff8000", + "0x482480017ffa8000", + "0x686", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4661696c656420746f20646573657269616c697a6520706172616d202334", + "0x400080007ffe7fff", + "0x48127fdf7fff8000", + "0x482480017ffa8000", + "0x8de", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4661696c656420746f20646573657269616c697a6520706172616d202333", + "0x400080007ffe7fff", + "0x48127fe47fff8000", + "0x482480017ffb8000", + "0xb36", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4661696c656420746f20646573657269616c697a6520706172616d202332", + "0x400080007ffe7fff", + "0x48127fe67fff8000", + "0x482480017ffc8000", + "0xcc6", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x48127fe97fff8000", + "0x482480017fe98000", + "0xeba", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202331", "0x400080007ffe7fff", - "0x48127ffd7fff8000", - "0x48127fef7fff8000", + "0x48127ff67fff8000", + "0x482480017ffc8000", + "0x98b2", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -3046,7 +3262,8 @@ "0x400080007ffe7fff", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x2134", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -3055,76 +3272,134 @@ "0x1", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0x1", + "0x2", "0xa0680017fff8000", "0x7", "0x482680017ffa8000", "0x100000000000000000000000000000000", "0x400280007ff97fff", "0x10780017fff7fff", - "0xb1", + "0x109", "0x4825800180007ffa", "0x0", "0x400280007ff97fff", "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0x17c", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x99", - "0x400380007ffc8000", + "0xb", + "0x48127ffe7fff8000", "0x482680017ffc8000", "0x1", "0x480a7ffd7fff8000", - "0x48307ffe80007fff", + "0x480680017fff8000", + "0x0", + "0x480280007ffc8000", + "0x10780017fff7fff", + "0x9", + "0x48127ffe7fff8000", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x20680017fff7ffe", + "0xda", + "0x40137fff7fff8001", + "0x48127ffb7fff8000", + "0xa0680017fff8004", + "0xe", + "0x4825800180048001", + "0x800000000000000000000000000000000000000000000000000000000000000", + "0x484480017ffe8000", + "0x110000000000000000", + "0x48307ffe7fff8002", + "0x480080007ff37ffc", + "0x480080017ff27ffc", + "0x402480017ffb7ffd", + "0xffffffffffffffeeffffffffffffffff", + "0x400080027ff17ffd", + "0x10780017fff7fff", + "0xc4", + "0x484480017fff8001", + "0x8000000000000000000000000000000", + "0x48317fff80008001", + "0x480080007ff47ffd", + "0x480080017ff37ffd", + "0x402480017ffc7ffe", + "0xf8000000000000000000000000000000", + "0x400080027ff27ffe", + "0x482480017ff28000", + "0x3", + "0x48127ff97fff8000", + "0x48307ff480007ff5", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", - "0x482480017ffd8000", + "0xa5", + "0x400180007ff38000", + "0x482480017ff38000", "0x1", - "0x48127ffd7fff8000", + "0x48127ff37fff8000", + "0x48127ffc7fff8000", + "0x48307ffd80007ffe", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xb", + "0x48127ffe7fff8000", + "0x482480017ffb8000", + "0x1", + "0x48127ffb7fff8000", "0x480680017fff8000", "0x0", - "0x48127ffa7fff8000", + "0x48127ff87fff8000", "0x10780017fff7fff", - "0x8", - "0x48127ffd7fff8000", - "0x48127ffd7fff8000", + "0x9", + "0x48127ffe7fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", "0x480680017fff8000", "0x1", "0x480680017fff8000", "0x0", "0x20680017fff7ffe", - "0x70", + "0x78", "0x40780017fff7fff", "0x1", - "0x48127ff67fff8000", - "0x48127ff47fff8000", + "0x48127ff37fff8000", + "0x48127ff97fff8000", "0x48127ff97fff8000", "0x48127ff97fff8000", "0x48127ffb7fff8000", "0x48127ffa7fff8000", "0x480080007ff88000", "0x1104800180018000", - "0x1019", + "0x176f", "0x20680017fff7ffa", - "0x5b", - "0x20680017fff7ffd", - "0x55", - "0x48307ffb80007ffc", + "0x62", + "0x48127ff97fff8000", + "0x20680017fff7ffc", + "0x5a", + "0x48127fff7fff8000", + "0x48307ff980007ffa", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ff57fff8000", - "0x48127ff57fff8000", + "0x48127ff37fff8000", + "0x482480017ffb8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -3133,62 +3408,65 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x3fbb", + "0x4c80", "0x482480017fff8000", - "0x3fba", - "0x480080007fff8000", + "0x4c7f", + "0x48127ffb7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007ff3", - "0x1c8e", + "0x4824800180007ffd", + "0x29cc", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007ff07fff", + "0x400080007fed7fff", "0x10780017fff7fff", - "0x25", - "0x4824800180007ff3", - "0x1c8e", - "0x400080007ff17fff", - "0x482480017ff18000", + "0x27", + "0x4824800180007ffd", + "0x29cc", + "0x400080007fee7fff", + "0x48127fff7fff8000", + "0x482480017fed8000", "0x1", "0x480680017fff8000", - "0x53656e644d657373616765546f4c31", + "0x4c69627261727943616c6c", "0x400280007ffb7fff", "0x400280017ffb7ffd", - "0x400380027ffb8000", - "0x400280037ffb7ff5", - "0x400280047ffb7ff6", - "0x480280067ffb8000", + "0x400380027ffb8001", + "0x400380037ffb8000", + "0x400280047ffb7ff1", + "0x400280057ffb7ff2", + "0x480280077ffb8000", "0x20680017fff7fff", - "0xd", - "0x40780017fff7fff", - "0x1", + "0xc", + "0x480280067ffb8000", "0x48127ffc7fff8000", - "0x480280057ffb8000", + "0x48127ffe7fff8000", "0x482680017ffb8000", - "0x7", + "0xa", "0x480680017fff8000", "0x0", - "0x48127ffb7fff8000", - "0x48127ffa7fff8000", + "0x480280087ffb8000", + "0x480280097ffb8000", "0x208b7fff7fff7ffe", - "0x48127ffd7fff8000", - "0x480280057ffb8000", + "0x480280067ffb8000", + "0x48127ffc7fff8000", + "0x48127ffe7fff8000", "0x482680017ffb8000", - "0x9", + "0xa", "0x480680017fff8000", "0x1", - "0x480280077ffb8000", "0x480280087ffb8000", + "0x480280097ffb8000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482480017fee8000", + "0x482480017feb8000", "0x1", - "0x48127fee7fff8000", + "0x48127ff87fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -3196,24 +3474,27 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x48127ff87fff8000", - "0x48127ff87fff8000", + "0x48127ff77fff8000", + "0x482480017ffe8000", + "0x492", "0x10780017fff7fff", - "0xc", - "0x48127ff87fff8000", + "0xe", "0x48127ff87fff8000", + "0x482480017ff88000", + "0x7b2", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", "0x48127ffa7fff8000", "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", - "0x48127ff77fff8000", - "0x48127ff57fff8000", + "0x48127ff47fff8000", + "0x482480017ffa8000", + "0x102c", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4661696c656420746f20646573657269616c697a6520706172616d202332", + "0x4661696c656420746f20646573657269616c697a6520706172616d202333", "0x400080007ffe7fff", "0x48127ffc7fff8000", "0x48127ffc7fff8000", @@ -3227,25 +3508,11 @@ "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4661696c656420746f20646573657269616c697a6520706172616d202331", - "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127ffa7fff8000", - "0x480a7ffb7fff8000", - "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", - "0x480680017fff8000", - "0x4f7574206f6620676173", + "0x4661696c656420746f20646573657269616c697a6520706172616d202332", "0x400080007ffe7fff", - "0x482680017ff98000", - "0x1", - "0x480a7ffa7fff8000", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x159a", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -3253,99 +3520,27 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0xa0680017fff8000", - "0x7", - "0x482680017ffa8000", - "0x100000000000000000000000000000000", - "0x400280007ff87fff", - "0x10780017fff7fff", - "0x5a", - "0x4825800180007ffa", - "0x0", - "0x400280007ff87fff", - "0x482680017ff88000", - "0x1", - "0x48297ffc80007ffd", - "0x20680017fff7fff", - "0x4", + "0x482480017ff18000", + "0x3", + "0x482480017ff88000", + "0x159a", "0x10780017fff7fff", - "0x11", + "0x5", + "0x48127ff87fff8000", + "0x482480017ffa8000", + "0x1b12", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", + "0x4661696c656420746f20646573657269616c697a6520706172616d202331", "0x400080007ffe7fff", "0x48127ffc7fff8000", - "0x480a7ff97fff8000", - "0x48127ff97fff8000", + "0x48127ffc7fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x48127ff97fff8000", - "0x482480017ff88000", - "0x1", - "0x208b7fff7fff7ffe", - "0x1104800180018000", - "0x3f22", - "0x482480017fff8000", - "0x3f21", - "0x480080007fff8000", - "0xa0680017fff8000", - "0x9", - "0x4824800180007ff8", - "0x41a", - "0x482480017fff8000", - "0x100000000000000000000000000000000", - "0x400080007ff77fff", - "0x10780017fff7fff", - "0x23", - "0x4824800180007ff8", - "0x41a", - "0x400080007ff87fff", - "0x48027ffd7ff98000", - "0x48027ffe7ff98000", - "0x48027fff7ff98000", - "0x400280007ff97ffd", - "0x482480017ffe8000", - "0x1", - "0x400280017ff97fff", - "0x400280027ff97ffe", - "0x484480017ffd8000", - "0x3", - "0x48307fff7ffb8000", - "0x482480017ff28000", - "0x1", - "0x482680017ff98000", - "0x3", - "0x48127ff77fff8000", - "0x480080007ffc8000", - "0x1104800180018000", - "0x17e6", - "0x40780017fff7fff", - "0x1", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", - "0x480a7ffb7fff8000", - "0x480680017fff8000", - "0x0", "0x48127ffa7fff8000", - "0x48127ff97fff8000", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", - "0x480680017fff8000", - "0x4f7574206f6620676173", - "0x400080007ffe7fff", - "0x482480017ff58000", - "0x1", - "0x480a7ff97fff8000", - "0x48127ff27fff8000", - "0x480a7ffb7fff8000", - "0x480680017fff8000", - "0x1", - "0x48127ff97fff8000", - "0x482480017ff88000", + "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", "0x40780017fff7fff", @@ -3353,36 +3548,37 @@ "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482680017ff88000", + "0x482680017ff98000", "0x1", - "0x480a7ff97fff8000", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x213e", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x48127ff97fff8000", - "0x482480017ff88000", + "0x48127ffa7fff8000", + "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x2", "0xa0680017fff8000", "0x7", "0x482680017ffa8000", "0x100000000000000000000000000000000", "0x400280007ff97fff", "0x10780017fff7fff", - "0x118", + "0xfb", "0x4825800180007ffa", "0x0", "0x400280007ff97fff", "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0xa5a", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", + "0xb", + "0x48127ffe7fff8000", "0x482680017ffc8000", "0x1", "0x480a7ffd7fff8000", @@ -3390,7 +3586,8 @@ "0x0", "0x480280007ffc8000", "0x10780017fff7fff", - "0x8", + "0x9", + "0x48127ffe7fff8000", "0x480a7ffc7fff8000", "0x480a7ffd7fff8000", "0x480680017fff8000", @@ -3398,106 +3595,86 @@ "0x480680017fff8000", "0x0", "0x20680017fff7ffe", - "0xed", - "0x40137fff7fff8000", + "0xcc", + "0x48127ffb7fff8000", "0xa0680017fff8004", "0xe", - "0x4825800180048000", + "0x4824800180047ffd", "0x800000000000000000000000000000000000000000000000000000000000000", "0x484480017ffe8000", "0x110000000000000000", "0x48307ffe7fff8002", - "0x480080007ff67ffc", - "0x480080017ff57ffc", + "0x480080007ff37ffc", + "0x480080017ff27ffc", "0x402480017ffb7ffd", "0xffffffffffffffeeffffffffffffffff", - "0x400080027ff47ffd", + "0x400080027ff17ffd", "0x10780017fff7fff", - "0xda", + "0xb7", "0x484480017fff8001", "0x8000000000000000000000000000000", - "0x48317fff80008000", - "0x480080007ff77ffd", - "0x480080017ff67ffd", + "0x48307fff80007ffc", + "0x480080007ff47ffd", + "0x480080017ff37ffd", "0x402480017ffc7ffe", "0xf8000000000000000000000000000000", - "0x400080027ff57ffe", - "0x482480017ff58000", + "0x400080027ff27ffe", + "0x482480017ff28000", "0x3", - "0x48307ff680007ff7", + "0x48127ff97fff8000", + "0x48307ff480007ff5", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xbd", - "0x400180007ff58001", - "0x482480017ff58000", + "0x98", + "0x482480017ff38000", "0x1", - "0x48127ff57fff8000", - "0x48307ffe80007fff", + "0x48127ff37fff8000", + "0x48127ffc7fff8000", + "0x480080007ff08000", + "0x48307ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", - "0x482480017ffd8000", + "0x7f", + "0x482480017ffb8000", "0x1", - "0x48127ffd7fff8000", - "0x480680017fff8000", - "0x0", - "0x48127ffa7fff8000", - "0x10780017fff7fff", - "0x8", - "0x48127ffd7fff8000", - "0x48127ffd7fff8000", - "0x480680017fff8000", - "0x1", - "0x480680017fff8000", - "0x0", - "0x20680017fff7ffe", - "0x94", - "0x40780017fff7fff", - "0x1", - "0x48127ff67fff8000", - "0x48127fe97fff8000", - "0x48127ff97fff8000", - "0x48127ff97fff8000", "0x48127ffb7fff8000", - "0x48127ffa7fff8000", + "0x48127ffb7fff8000", "0x480080007ff88000", - "0x1104800180018000", - "0xeb5", - "0x20680017fff7ffa", - "0x7f", - "0x20680017fff7ffd", - "0x79", - "0x48307ffb80007ffc", + "0x48307ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", "0x66", - "0x480080007ffa8000", - "0x482480017ff98000", - "0x1", - "0x48127ff97fff8000", - "0x20680017fff7ffd", - "0x6", - "0x480680017fff8000", + "0x482480017ffb8000", "0x1", - "0x10780017fff7fff", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x480080007ff88000", + "0x48307ffc80007ffd", + "0x20680017fff7fff", "0x4", - "0x480680017fff8000", - "0x0", - "0x48307ffd80007ffe", + "0x10780017fff7fff", + "0x4d", + "0x482480017ffb8000", + "0x1", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x480080007ff88000", + "0x48307ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ff07fff8000", - "0x48127ff07fff8000", + "0x48127fe77fff8000", + "0x482480017ffa8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -3506,67 +3683,48 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x3e46", + "0x4b6d", "0x482480017fff8000", - "0x3e45", - "0x480080007fff8000", + "0x4b6c", + "0x48127ffa7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007fee", - "0x28b4", + "0x4824800180007ffd", + "0x6018", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007feb7fff", + "0x400080007fe17fff", "0x10780017fff7fff", - "0x2a", - "0x4824800180007fee", - "0x28b4", - "0x400080007fec7fff", - "0x480680017fff8000", - "0x1", - "0x48307ff780007fff", - "0x482480017fea8000", - "0x1", - "0x480680017fff8000", - "0x4465706c6f79", - "0x400280007ffb7fff", - "0x400280017ffb7ffb", - "0x400380027ffb8000", - "0x400380037ffb8001", - "0x400280047ffb7fee", - "0x400280057ffb7fef", - "0x400280067ffb7ffd", - "0x480280087ffb8000", - "0x20680017fff7fff", - "0xd", - "0x40780017fff7fff", + "0x16", + "0x4824800180007ffd", + "0x6018", + "0x400080007fe27fff", + "0x48127fff7fff8000", + "0x480a7ffb7fff8000", + "0x48127fd97fff8000", + "0x48127fe57fff8000", + "0x48127fe97fff8000", + "0x48127fed7fff8000", + "0x48127ff17fff8000", + "0x1104800180018000", + "0x1f9b", + "0x482480017fc48000", "0x1", - "0x48127ffc7fff8000", - "0x480280077ffb8000", - "0x482680017ffb8000", - "0xc", - "0x480680017fff8000", - "0x0", - "0x48127ffb7fff8000", "0x48127ffa7fff8000", - "0x208b7fff7fff7ffe", - "0x48127ffd7fff8000", - "0x480280077ffb8000", - "0x482680017ffb8000", - "0xb", - "0x480680017fff8000", - "0x1", - "0x480280097ffb8000", - "0x4802800a7ffb8000", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482480017fe98000", + "0x482480017fdf8000", "0x1", - "0x48127fe97fff8000", + "0x48127ff87fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -3577,10 +3735,11 @@ "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4661696c656420746f20646573657269616c697a6520706172616d202334", + "0x4661696c656420746f20646573657269616c697a6520706172616d202335", "0x400080007ffe7fff", - "0x48127ff57fff8000", - "0x48127ff57fff8000", + "0x48127fec7fff8000", + "0x482480017ffa8000", + "0x686", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -3588,27 +3747,29 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x10780017fff7fff", - "0xc", - "0x48127ff87fff8000", - "0x48127ff87fff8000", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4661696c656420746f20646573657269616c697a6520706172616d202334", + "0x400080007ffe7fff", + "0x48127ff17fff8000", + "0x482480017ffa8000", + "0x8de", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", "0x48127ffa7fff8000", - "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", "0x208b7fff7fff7ffe", - "0x48127ff77fff8000", - "0x48127fea7fff8000", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202333", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127ffc7fff8000", + "0x48127ff67fff8000", + "0x482480017ffa8000", + "0xb36", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -3621,8 +3782,9 @@ "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202332", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127fef7fff8000", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0xd8e", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -3630,20 +3792,22 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x482480017ff48000", + "0x482480017ff18000", "0x3", + "0x482480017ff88000", + "0xd8e", "0x10780017fff7fff", "0x5", - "0x40780017fff7fff", - "0x6", - "0x48127ff47fff8000", + "0x48127ff87fff8000", + "0x482480017ffa8000", + "0x12ac", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202331", "0x400080007ffe7fff", - "0x48127ffd7fff8000", - "0x48127fef7fff8000", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -3658,7 +3822,8 @@ "0x400080007ffe7fff", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x21b6", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -3672,24 +3837,76 @@ "0x100000000000000000000000000000000", "0x400280007ff97fff", "0x10780017fff7fff", - "0x54", + "0xa8", "0x4825800180007ffa", "0x0", "0x400280007ff97fff", "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0x13ba", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0xb", + "0x48127ffe7fff8000", + "0x482680017ffc8000", + "0x1", + "0x480a7ffd7fff8000", + "0x480680017fff8000", + "0x0", + "0x480280007ffc8000", + "0x10780017fff7fff", + "0x9", + "0x48127ffe7fff8000", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x20680017fff7ffe", + "0x79", + "0x48127ffb7fff8000", + "0xa0680017fff8004", + "0xe", + "0x4824800180047ffd", + "0x800000000000000000000000000000000000000000000000000000000000000", + "0x484480017ffe8000", + "0x110000000000000000", + "0x48307ffe7fff8002", + "0x480080007ff37ffc", + "0x480080017ff27ffc", + "0x402480017ffb7ffd", + "0xffffffffffffffeeffffffffffffffff", + "0x400080027ff17ffd", + "0x10780017fff7fff", + "0x64", + "0x484480017fff8001", + "0x8000000000000000000000000000000", + "0x48307fff80007ffc", + "0x480080007ff47ffd", + "0x480080017ff37ffd", + "0x402480017ffc7ffe", + "0xf8000000000000000000000000000000", + "0x400080027ff27ffe", + "0x482480017ff28000", + "0x3", + "0x48127ff97fff8000", + "0x48307ff480007ff5", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127ffa7fff8000", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -3698,56 +3915,88 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x3d86", + "0x4a85", "0x482480017fff8000", - "0x3d85", - "0x480080007fff8000", + "0x4a84", + "0x48127ffb7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007ff8", - "0x7602", + "0x4824800180007ffd", + "0x2904", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007ff77fff", + "0x400080007ff57fff", "0x10780017fff7fff", - "0x1f", - "0x4824800180007ff8", - "0x7602", - "0x400080007ff87fff", - "0x482480017ff88000", + "0x27", + "0x4824800180007ffd", + "0x2904", + "0x400080007ff67fff", + "0x48127fff7fff8000", + "0x482480017ff58000", "0x1", - "0x48127ffe7fff8000", - "0x480a7ffb7fff8000", - "0x1104800180018000", - "0x1715", - "0x20680017fff7ffd", - "0xc", + "0x480680017fff8000", + "0x5265706c616365436c617373", + "0x400280007ffb7fff", + "0x400280017ffb7ffd", + "0x400280027ffb7fec", + "0x480280047ffb8000", + "0x20680017fff7fff", + "0xe", + "0x480280037ffb8000", "0x40780017fff7fff", "0x1", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x48127ff97fff8000", + "0x48127ffb7fff8000", + "0x48127ffd7fff8000", + "0x482680017ffb8000", + "0x5", "0x480680017fff8000", "0x0", "0x48127ffb7fff8000", "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", + "0x480280037ffb8000", + "0x48127ffc7fff8000", + "0x482480017ffe8000", + "0x64", + "0x482680017ffb8000", + "0x7", "0x480680017fff8000", "0x1", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", + "0x480280057ffb8000", + "0x480280067ffb8000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482480017ff58000", + "0x482480017ff38000", "0x1", - "0x48127ff37fff8000", + "0x48127ff87fff8000", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x482480017ff18000", + "0x3", + "0x482480017ff88000", + "0x42e", + "0x10780017fff7fff", + "0x5", + "0x48127ff87fff8000", + "0x482480017ffa8000", + "0x94c", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4661696c656420746f20646573657269616c697a6520706172616d202331", + "0x400080007ffe7fff", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -3762,7 +4011,8 @@ "0x400080007ffe7fff", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x21b6", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -3770,30 +4020,85 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", "0xa0680017fff8000", "0x7", "0x482680017ffa8000", "0x100000000000000000000000000000000", "0x400280007ff97fff", "0x10780017fff7fff", - "0x54", + "0xc2", "0x4825800180007ffa", "0x0", "0x400280007ff97fff", "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0xa1e", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0xa7", + "0x400380007ffc8000", + "0x482680017ffc8000", + "0x1", + "0x480a7ffd7fff8000", + "0x48127ffc7fff8000", + "0x48307ffd80007ffe", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xb", + "0x48127ffe7fff8000", + "0x482480017ffb8000", + "0x1", + "0x48127ffb7fff8000", + "0x480680017fff8000", + "0x0", + "0x48127ff87fff8000", + "0x10780017fff7fff", + "0x9", + "0x48127ffe7fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x20680017fff7ffe", + "0x7a", + "0x40780017fff7fff", + "0x1", + "0x48127ff37fff8000", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x48127ffb7fff8000", + "0x48127ffa7fff8000", + "0x480080007ff88000", + "0x1104800180018000", + "0x14b4", + "0x20680017fff7ffa", + "0x64", + "0x48127ff97fff8000", + "0x20680017fff7ffc", + "0x5c", + "0x48127fff7fff8000", + "0x48307ff980007ffa", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127ffa7fff8000", + "0x48127ff37fff8000", + "0x482480017ffb8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -3802,56 +4107,113 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x3d1e", + "0x49c5", "0x482480017fff8000", - "0x3d1d", - "0x480080007fff8000", + "0x49c4", + "0x48127ffb7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007ff8", - "0x3b92", + "0x4824800180007ffd", + "0x29cc", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007ff77fff", + "0x400080007fed7fff", "0x10780017fff7fff", - "0x1f", - "0x4824800180007ff8", - "0x3b92", - "0x400080007ff87fff", - "0x482480017ff88000", + "0x29", + "0x4824800180007ffd", + "0x29cc", + "0x400080007fee7fff", + "0x48127fff7fff8000", + "0x482480017fed8000", "0x1", - "0x48127ffe7fff8000", - "0x480a7ffb7fff8000", - "0x1104800180018000", - "0x1781", - "0x20680017fff7ffd", - "0xc", + "0x480680017fff8000", + "0x53656e644d657373616765546f4c31", + "0x400280007ffb7fff", + "0x400280017ffb7ffd", + "0x400380027ffb8000", + "0x400280037ffb7ff1", + "0x400280047ffb7ff2", + "0x480280067ffb8000", + "0x20680017fff7fff", + "0xe", + "0x480280057ffb8000", "0x40780017fff7fff", "0x1", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x48127ff97fff8000", + "0x48127ffb7fff8000", + "0x48127ffd7fff8000", + "0x482680017ffb8000", + "0x7", "0x480680017fff8000", "0x0", "0x48127ffb7fff8000", "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", + "0x480280057ffb8000", + "0x48127ffc7fff8000", + "0x482480017ffe8000", + "0x64", + "0x482680017ffb8000", + "0x9", + "0x480680017fff8000", + "0x1", + "0x480280077ffb8000", + "0x480280087ffb8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x482480017feb8000", + "0x1", + "0x48127ff87fff8000", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", "0x48127ffa7fff8000", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x48127ff77fff8000", + "0x482480017ffe8000", + "0x492", + "0x10780017fff7fff", + "0xe", + "0x48127ff87fff8000", + "0x482480017ff88000", + "0x7b2", + "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", "0x48127ffa7fff8000", "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", + "0x48127ff47fff8000", + "0x482480017ffa8000", + "0x102c", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4f7574206f6620676173", + "0x4661696c656420746f20646573657269616c697a6520706172616d202332", "0x400080007ffe7fff", - "0x482480017ff58000", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", + "0x480a7ffb7fff8000", + "0x480680017fff8000", "0x1", - "0x48127ff37fff8000", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4661696c656420746f20646573657269616c697a6520706172616d202331", + "0x400080007ffe7fff", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x159a", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -3866,7 +4228,8 @@ "0x400080007ffe7fff", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x2148", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -3880,25 +4243,28 @@ "0x100000000000000000000000000000000", "0x400280007ff87fff", "0x10780017fff7fff", - "0x5c", + "0x5e", "0x4825800180007ffa", "0x0", "0x400280007ff87fff", "0x482680017ff88000", "0x1", + "0x482480017ffe8000", + "0x1b94", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x11", + "0x12", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ffc7fff8000", + "0x48127ffb7fff8000", "0x480a7ff97fff8000", - "0x48127ff97fff8000", + "0x482480017ffa8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -3907,52 +4273,51 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x3cb5", - "0x482480017fff8000", - "0x3cb4", - "0x480080007fff8000", - "0x480080017fff8000", - "0x484480017fff8000", - "0x8", + "0x491f", "0x482480017fff8000", - "0x3f9bc", + "0x491e", + "0x48127ffb7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", - "0x8", - "0x48307ffe80007ff5", + "0x9", + "0x4824800180007ffd", + "0x2076", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007ff47fff", - "0x10780017fff7fff", - "0x21", - "0x48307ffe80007ff5", "0x400080007ff57fff", - "0x482480017ff58000", + "0x10780017fff7fff", + "0x23", + "0x4824800180007ffd", + "0x2076", + "0x400080007ff67fff", + "0x48027ffd7ff98000", + "0x48027ffe7ff98000", + "0x48027fff7ff98000", + "0x400280007ff97ffd", + "0x482480017ffe8000", "0x1", - "0x48127ffe7fff8000", - "0x480a7ff97fff8000", - "0x480a7ffb7fff8000", + "0x400280017ff97fff", + "0x400280027ff97ffe", + "0x484480017ffd8000", + "0x3", + "0x48307fff7ffb8000", + "0x482480017ff08000", + "0x1", + "0x482680017ff98000", + "0x3", + "0x48127ff77fff8000", + "0x480080007ffc8000", "0x1104800180018000", - "0x1767", - "0x20680017fff7ffd", - "0xd", + "0x1d90", "0x40780017fff7fff", "0x1", - "0x48127ff87fff8000", - "0x48127ff97fff8000", - "0x48127ff77fff8000", - "0x48127ff87fff8000", - "0x480680017fff8000", - "0x0", "0x48127ffa7fff8000", - "0x48127ff97fff8000", - "0x208b7fff7fff7ffe", - "0x48127ff97fff8000", "0x48127ffa7fff8000", - "0x48127ff87fff8000", - "0x48127ff97fff8000", + "0x48127ffa7fff8000", + "0x480a7ffb7fff8000", "0x480680017fff8000", - "0x1", - "0x48127ff97fff8000", + "0x0", + "0x48127ffa7fff8000", "0x48127ff97fff8000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", @@ -3960,10 +4325,10 @@ "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482480017ff28000", + "0x482480017ff38000", "0x1", "0x480a7ff97fff8000", - "0x48127fef7fff8000", + "0x48127ff77fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -3979,7 +4344,8 @@ "0x482680017ff88000", "0x1", "0x480a7ff97fff8000", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x2152", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -3987,152 +4353,155 @@ "0x482480017ff88000", "0x1", "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x2", "0xa0680017fff8000", "0x7", "0x482680017ffa8000", - "0x100000000000000000000000000000000", + "0xfffffffffffffffffffffffffffffd94", "0x400280007ff97fff", "0x10780017fff7fff", - "0x54", + "0x133", "0x4825800180007ffa", - "0x0", + "0x26c", "0x400280007ff97fff", "0x482680017ff98000", "0x1", + "0x48127ffe7fff8000", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", - "0x40780017fff7fff", + "0xb", + "0x48127ffe7fff8000", + "0x482680017ffc8000", "0x1", + "0x480a7ffd7fff8000", "0x480680017fff8000", - "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", - "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127ffa7fff8000", - "0x480a7ffb7fff8000", + "0x0", + "0x480280007ffc8000", + "0x10780017fff7fff", + "0x9", + "0x48127ffe7fff8000", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", "0x480680017fff8000", "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", - "0x1104800180018000", - "0x3c45", - "0x482480017fff8000", - "0x3c44", - "0x480080007fff8000", - "0xa0680017fff8000", - "0x9", - "0x4824800180007ff8", - "0x36998", - "0x482480017fff8000", - "0x100000000000000000000000000000000", - "0x400080007ff77fff", + "0x480680017fff8000", + "0x0", + "0x20680017fff7ffe", + "0x105", + "0x40137fff7fff8001", + "0x48127ffb7fff8000", + "0xa0680017fff8004", + "0xe", + "0x4825800180048001", + "0x800000000000000000000000000000000000000000000000000000000000000", + "0x484480017ffe8000", + "0x110000000000000000", + "0x48307ffe7fff8002", + "0x480080007ff37ffc", + "0x480080017ff27ffc", + "0x402480017ffb7ffd", + "0xffffffffffffffeeffffffffffffffff", + "0x400080027ff17ffd", "0x10780017fff7fff", - "0x1f", - "0x4824800180007ff8", - "0x36998", - "0x400080007ff87fff", - "0x482480017ff88000", + "0xef", + "0x484480017fff8001", + "0x8000000000000000000000000000000", + "0x48317fff80008001", + "0x480080007ff47ffd", + "0x480080017ff37ffd", + "0x402480017ffc7ffe", + "0xf8000000000000000000000000000000", + "0x400080027ff27ffe", + "0x482480017ff28000", + "0x3", + "0x48127ff97fff8000", + "0x48307ff480007ff5", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xd0", + "0x400180007ff38000", + "0x482480017ff38000", "0x1", + "0x48127ff37fff8000", + "0x48127ffc7fff8000", + "0x48307ffd80007ffe", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xb", "0x48127ffe7fff8000", - "0x480a7ffb7fff8000", - "0x1104800180018000", - "0x1847", - "0x20680017fff7ffd", - "0xc", - "0x40780017fff7fff", + "0x482480017ffb8000", "0x1", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x48127ff97fff8000", + "0x48127ffb7fff8000", "0x480680017fff8000", "0x0", + "0x48127ff87fff8000", + "0x10780017fff7fff", + "0x9", + "0x48127ffe7fff8000", + "0x48127ffb7fff8000", "0x48127ffb7fff8000", - "0x48127ffa7fff8000", - "0x208b7fff7fff7ffe", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", - "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", "0x480680017fff8000", - "0x4f7574206f6620676173", - "0x400080007ffe7fff", - "0x482480017ff58000", "0x1", - "0x48127ff37fff8000", - "0x480a7ffb7fff8000", "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", + "0x0", + "0x20680017fff7ffe", + "0xa3", "0x40780017fff7fff", "0x1", - "0x480680017fff8000", - "0x4f7574206f6620676173", - "0x400080007ffe7fff", - "0x482680017ff98000", - "0x1", - "0x480a7ffa7fff8000", - "0x480a7ffb7fff8000", - "0x480680017fff8000", - "0x1", + "0x48127ff37fff8000", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x48127ffb7fff8000", "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", - "0xa0680017fff8000", - "0x7", - "0x482680017ffa8000", - "0x100000000000000000000000000000000", - "0x400280007ff97fff", - "0x10780017fff7fff", - "0x89", - "0x4825800180007ffa", - "0x0", - "0x400280007ff97fff", - "0x482680017ff98000", - "0x1", - "0x48297ffc80007ffd", + "0x480080007ff88000", + "0x1104800180018000", + "0x1336", + "0x20680017fff7ffa", + "0x8d", + "0x48127ff97fff8000", + "0x20680017fff7ffc", + "0x85", + "0x48127fff7fff8000", + "0x48307ff980007ffa", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x71", - "0x482680017ffc8000", + "0x70", + "0x480080007ff88000", + "0x482480017ff78000", "0x1", - "0x480a7ffd7fff8000", - "0x480280007ffc8000", - "0x48307ffd80007ffe", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x5a", - "0x482480017ffc8000", + "0x48127ff77fff8000", + "0x48127ffb7fff8000", + "0x20680017fff7ffc", + "0x7", + "0x48127fff7fff8000", + "0x480680017fff8000", "0x1", - "0x48127ffc7fff8000", - "0x480080007ffa8000", - "0x48307ffd80007ffe", + "0x10780017fff7fff", + "0x6", + "0x482480017fff8000", + "0x64", + "0x480680017fff8000", + "0x0", + "0x48307ffb80007ffc", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ff47fff8000", - "0x48127ff27fff8000", + "0x48127fec7fff8000", + "0x482480017ffa8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -4141,37 +4510,75 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x3bcb", + "0x4832", "0x482480017fff8000", - "0x3bca", - "0x480080007fff8000", + "0x4831", + "0x48127ffa7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007ff0", - "0x0", + "0x4824800180007ffd", + "0x2b5c", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007fef7fff", + "0x400080007fe67fff", "0x10780017fff7fff", - "0x26", - "0x4824800180007ff0", + "0x2e", + "0x4824800180007ffd", + "0x2b5c", + "0x400080007fe77fff", + "0x480680017fff8000", + "0x1", + "0x48127ffe7fff8000", + "0x48307ff580007ffe", + "0x482480017fe48000", + "0x1", + "0x480680017fff8000", + "0x4465706c6f79", + "0x400280007ffb7fff", + "0x400280017ffb7ffc", + "0x400380027ffb8001", + "0x400380037ffb8000", + "0x400280047ffb7fe8", + "0x400280057ffb7fe9", + "0x400280067ffb7ffd", + "0x480280087ffb8000", + "0x20680017fff7fff", + "0xe", + "0x480280077ffb8000", + "0x40780017fff7fff", + "0x1", + "0x48127ffb7fff8000", + "0x48127ffd7fff8000", + "0x482680017ffb8000", + "0xc", + "0x480680017fff8000", "0x0", - "0x400080007ff07fff", - "0x48307ff880007ff4", - "0x482480017fef8000", + "0x48127ffb7fff8000", + "0x48127ffa7fff8000", + "0x208b7fff7fff7ffe", + "0x480280077ffb8000", + "0x48127ffc7fff8000", + "0x482480017ffe8000", + "0x64", + "0x482680017ffb8000", + "0xb", + "0x480680017fff8000", "0x1", - "0x20680017fff7ffe", - "0x10", + "0x480280097ffb8000", + "0x4802800a7ffb8000", + "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x73756363657373", + "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x48127ffd7fff8000", - "0x48127ffa7fff8000", + "0x482480017fe48000", + "0x1", + "0x48127ff87fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", - "0x0", + "0x1", "0x48127ffa7fff8000", "0x482480017ff98000", "0x1", @@ -4179,10 +4586,11 @@ "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x7820213d2079", + "0x4661696c656420746f20646573657269616c697a6520706172616d202334", "0x400080007ffe7fff", - "0x48127ffd7fff8000", - "0x48127ffa7fff8000", + "0x48127ff37fff8000", + "0x482480017ffb8000", + "0x816", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -4190,14 +4598,30 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", + "0x48127ff77fff8000", + "0x482480017ffe8000", + "0x87a", + "0x10780017fff7fff", + "0xe", + "0x48127ff87fff8000", + "0x482480017ff88000", + "0xb9a", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x208b7fff7fff7ffe", + "0x48127ff47fff8000", + "0x482480017ffa8000", + "0x1414", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4f7574206f6620676173", + "0x4661696c656420746f20646573657269616c697a6520706172616d202333", "0x400080007ffe7fff", - "0x482480017fed8000", - "0x1", - "0x48127feb7fff8000", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -4210,8 +4634,9 @@ "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202332", "0x400080007ffe7fff", - "0x48127ff87fff8000", - "0x48127ff67fff8000", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x1982", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -4219,13 +4644,22 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", + "0x482480017ff18000", + "0x3", + "0x482480017ff88000", + "0x1982", + "0x10780017fff7fff", + "0x5", + "0x48127ff87fff8000", + "0x482480017ffa8000", + "0x1efa", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202331", "0x400080007ffe7fff", "0x48127ffc7fff8000", - "0x48127ffa7fff8000", + "0x48127ffc7fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -4240,7 +4674,8 @@ "0x400080007ffe7fff", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x213e", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -4254,17 +4689,20 @@ "0x100000000000000000000000000000000", "0x400280007ff97fff", "0x10780017fff7fff", - "0x98", + "0xa5", "0x4825800180007ffa", "0x0", "0x400280007ff97fff", "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0x15d6", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", + "0xb", + "0x48127ffe7fff8000", "0x482680017ffc8000", "0x1", "0x480a7ffd7fff8000", @@ -4272,7 +4710,8 @@ "0x0", "0x480a7ffc7fff8000", "0x10780017fff7fff", - "0x8", + "0x9", + "0x48127ffe7fff8000", "0x480a7ffc7fff8000", "0x480a7ffd7fff8000", "0x480680017fff8000", @@ -4280,34 +4719,48 @@ "0x480680017fff8000", "0x0", "0x20680017fff7ffe", - "0x6e", - "0x40780017fff7fff", - "0x1", - "0x48127ff97fff8000", - "0x48127ff77fff8000", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x48127ffb7fff8000", + "0x76", + "0x480080007fff8000", "0x48127ffa7fff8000", - "0x480080007ff88000", - "0x1104800180018000", - "0xb7a", - "0x20680017fff7ffa", - "0x59", - "0x20680017fff7ffd", - "0x53", - "0x48307ffb80007ffc", + "0xa0680017fff8000", + "0x16", + "0x480080007ff58003", + "0x480080017ff48003", + "0x4844800180017ffe", + "0x100000000000000000000000000000000", + "0x483080017ffd7ffa", + "0x482480017fff7ffd", + "0x800000000000010fffffffffffffffff7ffffffffffffef0000000000000001", + "0x20680017fff7ffc", + "0x6", + "0x402480017fff7ffd", + "0xffffffffffffffffffffffffffffffff", + "0x10780017fff7fff", + "0x4", + "0x402480017ffe7ffd", + "0xf7ffffffffffffef0000000000000000", + "0x400080027ff07ffd", + "0x20680017fff7ffe", + "0x5a", + "0x402780017fff7fff", + "0x1", + "0x400080007ff57ffd", + "0x482480017ff58000", + "0x1", + "0x48127ffd7fff8000", + "0x48307ff780007ff8", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ff57fff8000", - "0x48127ff57fff8000", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -4316,47 +4769,47 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x3b1c", + "0x472f", "0x482480017fff8000", - "0x3b1b", - "0x480080007fff8000", + "0x472e", + "0x48127ffb7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007ff3", - "0x0", + "0x4824800180007ffd", + "0x690", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007ff07fff", + "0x400080007ff57fff", "0x10780017fff7fff", - "0x23", - "0x4824800180007ff3", - "0x0", - "0x400080007ff17fff", - "0x482480017ff18000", + "0x22", + "0x4824800180007ffd", + "0x690", + "0x400080007ff67fff", + "0x482480017ff68000", "0x1", "0x48127ffe7fff8000", - "0x480a7ffb7fff8000", - "0x48127ff47fff8000", - "0x48127ff47fff8000", + "0x48127ff17fff8000", "0x1104800180018000", - "0x188e", + "0x1c6b", "0x20680017fff7ffd", "0xe", "0x40780017fff7fff", "0x1", "0x400080007fff7ffe", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x48127ff97fff8000", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x480a7ffb7fff8000", "0x480680017fff8000", "0x0", "0x48127ffb7fff8000", "0x482480017ffa8000", "0x1", "0x208b7fff7fff7ffe", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0xc8", + "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", "0x48127ffa7fff8000", @@ -4367,9 +4820,9 @@ "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482480017fee8000", + "0x482480017ff38000", "0x1", - "0x48127fee7fff8000", + "0x48127ff87fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -4377,20 +4830,15 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x48127ff87fff8000", - "0x48127ff87fff8000", + "0x482480017ff08000", + "0x3", + "0x482480017ff88000", + "0xe6", "0x10780017fff7fff", - "0xc", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x480a7ffb7fff8000", - "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", - "0x208b7fff7fff7ffe", - "0x48127ffa7fff8000", + "0x5", "0x48127ff87fff8000", + "0x482480017ffa8000", + "0x730", "0x40780017fff7fff", "0x1", "0x480680017fff8000", @@ -4412,7 +4860,8 @@ "0x400080007ffe7fff", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x21b6", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -4426,24 +4875,27 @@ "0x100000000000000000000000000000000", "0x400280007ff97fff", "0x10780017fff7fff", - "0x49", + "0x59", "0x4825800180007ffa", "0x0", "0x400280007ff97fff", "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0x1bf8", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127ffa7fff8000", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -4452,45 +4904,58 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x3a94", + "0x46a8", "0x482480017fff8000", - "0x3a93", - "0x480080007fff8000", + "0x46a7", + "0x48127ffb7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007ff8", - "0x0", + "0x4824800180007ffd", + "0x96c8", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007ff77fff", + "0x400080007ff57fff", "0x10780017fff7fff", - "0x14", - "0x4824800180007ff8", - "0x0", - "0x400080007ff87fff", - "0x40780017fff7fff", - "0x1", - "0x480680017fff8000", - "0x6661696c", - "0x400080007ffe7fff", + "0x20", + "0x4824800180007ffd", + "0x96c8", + "0x400080007ff67fff", "0x482480017ff68000", "0x1", - "0x48127ffc7fff8000", + "0x48127ffe7fff8000", "0x480a7ffb7fff8000", - "0x480680017fff8000", + "0x1104800180018000", + "0x1cac", + "0x20680017fff7ffd", + "0xc", + "0x40780017fff7fff", "0x1", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x480680017fff8000", + "0x0", + "0x48127ffb7fff8000", "0x48127ffa7fff8000", - "0x482480017ff98000", + "0x208b7fff7fff7ffe", + "0x48127ffa7fff8000", + "0x482480017ffa8000", + "0x64", + "0x48127ffa7fff8000", + "0x480680017fff8000", "0x1", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482480017ff58000", + "0x482480017ff38000", "0x1", - "0x48127ff37fff8000", + "0x48127ff87fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -4505,7 +4970,8 @@ "0x400080007ffe7fff", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x21b6", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -4519,33 +4985,27 @@ "0x100000000000000000000000000000000", "0x400280007ff97fff", "0x10780017fff7fff", - "0x6b", + "0x59", "0x4825800180007ffa", "0x0", "0x400280007ff97fff", "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0x1bf8", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x53", - "0x482680017ffc8000", - "0x1", - "0x480a7ffd7fff8000", - "0x480280007ffc8000", - "0x48307ffd80007ffe", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x10", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ff87fff8000", - "0x48127ff67fff8000", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -4554,43 +5014,45 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x3a2e", + "0x463a", "0x482480017fff8000", - "0x3a2d", - "0x480080007fff8000", + "0x4639", + "0x48127ffb7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007ff4", - "0x0", + "0x4824800180007ffd", + "0x58b6", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007ff37fff", + "0x400080007ff57fff", "0x10780017fff7fff", - "0x1f", - "0x4824800180007ff4", - "0x0", - "0x400080007ff47fff", - "0x482480017ff48000", + "0x20", + "0x4824800180007ffd", + "0x58b6", + "0x400080007ff67fff", + "0x482480017ff68000", "0x1", "0x48127ffe7fff8000", - "0x48127ff67fff8000", + "0x480a7ffb7fff8000", "0x1104800180018000", - "0x18cd", + "0x1d16", "0x20680017fff7ffd", "0xc", "0x40780017fff7fff", "0x1", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", - "0x480a7ffb7fff8000", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x48127ff97fff8000", "0x480680017fff8000", "0x0", "0x48127ffb7fff8000", "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", - "0x480a7ffb7fff8000", + "0x48127ffa7fff8000", + "0x482480017ffa8000", + "0x64", + "0x48127ffa7fff8000", "0x480680017fff8000", "0x1", "0x48127ffa7fff8000", @@ -4601,9 +5063,9 @@ "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482480017ff18000", + "0x482480017ff38000", "0x1", - "0x48127fef7fff8000", + "0x48127ff87fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -4614,10 +5076,12 @@ "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4661696c656420746f20646573657269616c697a6520706172616d202331", + "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127ffa7fff8000", + "0x482680017ff98000", + "0x1", + "0x482680017ffa8000", + "0x21b6", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -4625,19 +5089,123 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", + "0xa0680017fff8000", + "0x7", + "0x482680017ffa8000", + "0x100000000000000000000000000000000", + "0x400280007ff87fff", + "0x10780017fff7fff", + "0x61", + "0x4825800180007ffa", + "0x0", + "0x400280007ff87fff", + "0x482680017ff88000", + "0x1", + "0x482480017ffe8000", + "0x1a68", + "0x48297ffc80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x12", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", + "0x400080007ffe7fff", + "0x48127ffb7fff8000", + "0x480a7ff97fff8000", + "0x482480017ffa8000", + "0x5be", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0x1104800180018000", + "0x45cb", + "0x482480017fff8000", + "0x45ca", + "0x48127ffb7fff8000", + "0x480080007ffe8000", + "0x480080017fff8000", + "0x484480017fff8000", + "0x8", + "0x482480017fff8000", + "0x425d6", + "0xa0680017fff8000", + "0x8", + "0x48307ffe80007ffa", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400080007ff27fff", + "0x10780017fff7fff", + "0x22", + "0x48307ffe80007ffa", + "0x400080007ff37fff", + "0x482480017ff38000", + "0x1", + "0x48127ffe7fff8000", + "0x480a7ff97fff8000", + "0x480a7ffb7fff8000", + "0x1104800180018000", + "0x1cfa", + "0x20680017fff7ffd", + "0xd", + "0x40780017fff7fff", + "0x1", + "0x48127ff87fff8000", + "0x48127ff97fff8000", + "0x48127ff77fff8000", + "0x48127ff87fff8000", + "0x480680017fff8000", + "0x0", + "0x48127ffa7fff8000", + "0x48127ff97fff8000", + "0x208b7fff7fff7ffe", + "0x48127ff97fff8000", + "0x48127ffa7fff8000", + "0x482480017ff88000", + "0x64", + "0x48127ff97fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482680017ff98000", + "0x482480017ff08000", "0x1", - "0x480a7ffa7fff8000", + "0x480a7ff97fff8000", + "0x48127ff47fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x482680017ff88000", + "0x1", + "0x480a7ff97fff8000", + "0x482680017ffa8000", + "0x2152", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ff97fff8000", + "0x482480017ff88000", "0x1", "0x208b7fff7fff7ffe", "0xa0680017fff8000", @@ -4646,33 +5214,27 @@ "0x100000000000000000000000000000000", "0x400280007ff97fff", "0x10780017fff7fff", - "0x6b", + "0x59", "0x4825800180007ffa", "0x0", "0x400280007ff97fff", "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0x1bf8", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x53", - "0x482680017ffc8000", - "0x1", - "0x480a7ffd7fff8000", - "0x480280007ffc8000", - "0x48307ffd80007ffe", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x10", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ff87fff8000", - "0x48127ff67fff8000", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -4681,43 +5243,45 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x39af", + "0x4555", "0x482480017fff8000", - "0x39ae", - "0x480080007fff8000", + "0x4554", + "0x48127ffb7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007ff4", - "0x0", + "0x4824800180007ffd", + "0x3909e", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007ff37fff", + "0x400080007ff57fff", "0x10780017fff7fff", - "0x1f", - "0x4824800180007ff4", - "0x0", - "0x400080007ff47fff", - "0x482480017ff48000", + "0x20", + "0x4824800180007ffd", + "0x3909e", + "0x400080007ff67fff", + "0x482480017ff68000", "0x1", "0x48127ffe7fff8000", - "0x48127ff67fff8000", + "0x480a7ffb7fff8000", "0x1104800180018000", - "0x187e", + "0x1e58", "0x20680017fff7ffd", "0xc", "0x40780017fff7fff", "0x1", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", - "0x480a7ffb7fff8000", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x48127ff97fff8000", "0x480680017fff8000", "0x0", "0x48127ffb7fff8000", "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", - "0x480a7ffb7fff8000", + "0x48127ffa7fff8000", + "0x482480017ffa8000", + "0x64", + "0x48127ffa7fff8000", "0x480680017fff8000", "0x1", "0x48127ffa7fff8000", @@ -4728,23 +5292,9 @@ "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482480017ff18000", - "0x1", - "0x48127fef7fff8000", - "0x480a7ffb7fff8000", - "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", + "0x482480017ff38000", "0x1", - "0x480680017fff8000", - "0x4661696c656420746f20646573657269616c697a6520706172616d202331", - "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127ffa7fff8000", + "0x48127ff87fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -4759,7 +5309,8 @@ "0x400080007ffe7fff", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x21b6", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -4773,87 +5324,47 @@ "0x100000000000000000000000000000000", "0x400280007ff97fff", "0x10780017fff7fff", - "0xdf", + "0x92", "0x4825800180007ffa", "0x0", "0x400280007ff97fff", "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0x1748", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", + "0x77", "0x482680017ffc8000", "0x1", "0x480a7ffd7fff8000", - "0x480680017fff8000", - "0x0", + "0x48127ffc7fff8000", "0x480280007ffc8000", - "0x10780017fff7fff", - "0x8", - "0x480a7ffc7fff8000", - "0x480a7ffd7fff8000", - "0x480680017fff8000", - "0x1", - "0x480680017fff8000", - "0x0", - "0x20680017fff7ffe", - "0xb4", - "0xa0680017fff8004", - "0xe", - "0x4824800180047ffe", - "0x800000000000000000000000000000000000000000000000000000000000000", - "0x484480017ffe8000", - "0x110000000000000000", - "0x48307ffe7fff8002", - "0x480080007ff67ffc", - "0x480080017ff57ffc", - "0x402480017ffb7ffd", - "0xffffffffffffffeeffffffffffffffff", - "0x400080027ff47ffd", - "0x10780017fff7fff", - "0xa2", - "0x484480017fff8001", - "0x8000000000000000000000000000000", - "0x48307fff80007ffd", - "0x480080007ff77ffd", - "0x480080017ff67ffd", - "0x402480017ffc7ffe", - "0xf8000000000000000000000000000000", - "0x400080027ff57ffe", - "0x482480017ff58000", - "0x3", - "0x48307ff680007ff7", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x85", - "0x482480017ff58000", - "0x1", - "0x48127ff57fff8000", - "0x480080007ff38000", - "0x48307ffd80007ffe", + "0x48307ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x6e", - "0x482480017ffc8000", + "0x5e", + "0x482480017ffb8000", "0x1", - "0x48127ffc7fff8000", - "0x480080007ffa8000", - "0x48307ffd80007ffe", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x480080007ff88000", + "0x48307ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ff47fff8000", - "0x48127fe77fff8000", + "0x48127ff17fff8000", + "0x482480017ffa8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -4862,83 +5373,50 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x38fa", + "0x44d3", "0x482480017fff8000", - "0x38f9", - "0x480080007fff8000", + "0x44d2", + "0x48127ffa7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007fe5", - "0x1b8a", + "0x4824800180007ffd", + "0xc8", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007fef7fff", + "0x400080007feb7fff", "0x10780017fff7fff", - "0x3a", - "0x4824800180007fe5", - "0x1b8a", - "0x400080007ff07fff", - "0x482480017ff08000", + "0x27", + "0x4824800180007ffd", + "0xc8", + "0x400080007fec7fff", + "0x48307ff780007ff2", + "0x482480017feb8000", "0x1", - "0x20680017fff7ff7", - "0x8", - "0x40780017fff7fff", - "0x6", - "0x48127ff87fff8000", - "0x480a7ffb7fff8000", - "0x10780017fff7fff", - "0x1a", + "0x48127ffd7fff8000", + "0x20680017fff7ffd", + "0x10", "0x40780017fff7fff", "0x1", - "0x400080007fff7fe8", - "0x400080017fff7ff2", - "0x4824800180007ff6", - "0x1", - "0x400080027ffe7fff", - "0x48127ffe7fff8000", - "0x482480017ffd8000", - "0x3", "0x480680017fff8000", - "0x43616c6c436f6e7472616374", - "0x400280007ffb7fff", - "0x400280017ffb7ff9", - "0x400280027ffb7fe4", - "0x400280037ffb7fee", - "0x400280047ffb7ffd", - "0x400280057ffb7ffe", - "0x480280077ffb8000", - "0x20680017fff7fff", - "0xf", - "0x480280067ffb8000", - "0x482680017ffb8000", - "0xa", - "0x40780017fff7fff", - "0x1", - "0x48127ff67fff8000", + "0x73756363657373", + "0x400080007ffe7fff", "0x48127ffc7fff8000", "0x48127ffc7fff8000", + "0x480a7ffb7fff8000", "0x480680017fff8000", "0x0", - "0x48127ffb7fff8000", "0x48127ffa7fff8000", - "0x208b7fff7fff7ffe", - "0x48127ff97fff8000", - "0x480280067ffb8000", - "0x482680017ffb8000", - "0xa", - "0x480680017fff8000", + "0x482480017ff98000", "0x1", - "0x480280087ffb8000", - "0x480280097ffb8000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4f7574206f6620676173", + "0x7820213d2079", "0x400080007ffe7fff", - "0x482480017fed8000", - "0x1", - "0x48127fe07fff8000", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -4949,10 +5427,11 @@ "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4661696c656420746f20646573657269616c697a6520706172616d202333", + "0x4f7574206f6620676173", "0x400080007ffe7fff", + "0x482480017fe98000", + "0x1", "0x48127ff87fff8000", - "0x48127feb7fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -4965,8 +5444,9 @@ "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202332", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127fef7fff8000", + "0x48127ff67fff8000", + "0x482480017ffa8000", + "0x686", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -4974,20 +5454,14 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x482480017ff48000", - "0x3", - "0x10780017fff7fff", - "0x5", - "0x40780017fff7fff", - "0x6", - "0x48127ff47fff8000", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202331", "0x400080007ffe7fff", - "0x48127ffd7fff8000", - "0x48127fef7fff8000", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x8de", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -5002,7 +5476,8 @@ "0x400080007ffe7fff", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x21b6", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -5016,40 +5491,55 @@ "0x100000000000000000000000000000000", "0x400280007ff97fff", "0x10780017fff7fff", - "0xa7", + "0xa4", "0x4825800180007ffa", "0x0", "0x400280007ff97fff", "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0xcda", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x8e", + "0xb", + "0x48127ffe7fff8000", "0x482680017ffc8000", "0x1", "0x480a7ffd7fff8000", - "0x480280007ffc8000", - "0x48307ffd80007ffe", - "0x20680017fff7fff", - "0x4", + "0x480680017fff8000", + "0x0", + "0x480a7ffc7fff8000", "0x10780017fff7fff", - "0x76", - "0x482480017ffc8000", + "0x9", + "0x48127ffe7fff8000", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", + "0x480680017fff8000", "0x1", - "0x48127ffc7fff8000", - "0x480080007ffa8000", - "0x48307ffd80007ffe", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x5e", - "0x482480017ffc8000", + "0x480680017fff8000", + "0x0", + "0x20680017fff7ffe", + "0x75", + "0x40780017fff7fff", "0x1", - "0x48127ffc7fff8000", - "0x480080007ffa8000", - "0x48307ffd80007ffe", + "0x48127ff77fff8000", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x48127ffb7fff8000", + "0x48127ffa7fff8000", + "0x480080007ff88000", + "0x1104800180018000", + "0xf07", + "0x20680017fff7ffa", + "0x5f", + "0x48127ff97fff8000", + "0x20680017fff7ffc", + "0x57", + "0x48127fff7fff8000", + "0x48307ff980007ffa", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", @@ -5059,127 +5549,109 @@ "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x480a7ff87fff8000", - "0x48127fef7fff8000", - "0x48127fed7fff8000", + "0x48127ff37fff8000", + "0x482480017ffb8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x48127ff97fff8000", - "0x482480017ff88000", + "0x48127ffa7fff8000", + "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x382a", - "0x482480017fff8000", - "0x3829", - "0x480080007fff8000", - "0x480080007fff8000", - "0x484480017fff8000", - "0x2", + "0x4418", "0x482480017fff8000", - "0xace4", + "0x4417", + "0x48127ffb7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", - "0x8", - "0x48307ffe80007fe9", + "0x9", + "0x4824800180007ffd", + "0x74e", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007fe87fff", + "0x400080007fed7fff", "0x10780017fff7fff", "0x24", - "0x48307ffe80007fe9", - "0x400080007fe97fff", - "0x482480017fe98000", + "0x4824800180007ffd", + "0x74e", + "0x400080007fee7fff", + "0x482480017fee8000", "0x1", "0x48127ffe7fff8000", - "0x480a7ff87fff8000", "0x480a7ffb7fff8000", - "0x48127fe97fff8000", - "0x48127fec7fff8000", - "0x48127fef7fff8000", + "0x48127ff17fff8000", + "0x48127ff17fff8000", "0x1104800180018000", - "0x171e", + "0x1ea3", "0x20680017fff7ffd", - "0xd", + "0xe", "0x40780017fff7fff", "0x1", - "0x48127ffa7fff8000", - "0x48127ff77fff8000", - "0x48127ff77fff8000", - "0x48127ff87fff8000", - "0x480680017fff8000", - "0x0", - "0x48127ffa7fff8000", - "0x48127ff97fff8000", - "0x208b7fff7fff7ffe", - "0x48127ffb7fff8000", - "0x48127ff87fff8000", - "0x48127ff87fff8000", + "0x400080007fff7ffe", "0x48127ff97fff8000", - "0x480680017fff8000", - "0x1", "0x48127ff97fff8000", "0x48127ff97fff8000", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", "0x480680017fff8000", - "0x4f7574206f6620676173", - "0x400080007ffe7fff", - "0x480a7ff87fff8000", - "0x482480017fe58000", + "0x0", + "0x48127ffb7fff8000", + "0x482480017ffa8000", "0x1", - "0x48127fe37fff8000", - "0x480a7ffb7fff8000", + "0x208b7fff7fff7ffe", + "0x48127ffa7fff8000", + "0x482480017ffa8000", + "0xc8", + "0x48127ffa7fff8000", "0x480680017fff8000", "0x1", - "0x48127ff97fff8000", - "0x482480017ff88000", - "0x1", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4661696c656420746f20646573657269616c697a6520706172616d202333", + "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x480a7ff87fff8000", - "0x48127ff37fff8000", - "0x48127ff17fff8000", + "0x482480017feb8000", + "0x1", + "0x48127ff87fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x48127ff97fff8000", - "0x482480017ff88000", + "0x48127ffa7fff8000", + "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", - "0x480680017fff8000", - "0x4661696c656420746f20646573657269616c697a6520706172616d202332", - "0x400080007ffe7fff", - "0x480a7ff87fff8000", "0x48127ff77fff8000", - "0x48127ff57fff8000", + "0x482480017ffe8000", + "0x492", + "0x10780017fff7fff", + "0xe", + "0x48127ff87fff8000", + "0x482480017ff88000", + "0x7b2", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x48127ff97fff8000", - "0x482480017ff88000", - "0x1", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", + "0x48127ff87fff8000", + "0x482480017ffa8000", + "0x102c", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202331", "0x400080007ffe7fff", - "0x480a7ff87fff8000", - "0x48127ffb7fff8000", - "0x48127ff97fff8000", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x48127ff97fff8000", - "0x482480017ff88000", + "0x48127ffa7fff8000", + "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", "0x40780017fff7fff", @@ -5187,266 +5659,98 @@ "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x480a7ff87fff8000", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x21b6", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x48127ff97fff8000", - "0x482480017ff88000", + "0x48127ffa7fff8000", + "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", "0xa0680017fff8000", "0x7", "0x482680017ffa8000", "0x100000000000000000000000000000000", - "0x400280007ff87fff", + "0x400280007ff97fff", "0x10780017fff7fff", - "0xf6", + "0x4e", "0x4825800180007ffa", "0x0", - "0x400280007ff87fff", - "0x482680017ff88000", + "0x400280007ff97fff", + "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0x1bf8", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xd9", - "0x482680017ffc8000", - "0x1", - "0x480a7ffd7fff8000", - "0x480280007ffc8000", - "0x48307ffd80007ffe", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0xa", - "0x482480017ffc8000", - "0x1", - "0x48127ffc7fff8000", - "0x480680017fff8000", - "0x0", - "0x48127ff97fff8000", - "0x10780017fff7fff", - "0x8", - "0x48127ffc7fff8000", - "0x48127ffc7fff8000", - "0x480680017fff8000", - "0x1", - "0x480680017fff8000", - "0x0", - "0x20680017fff7ffe", - "0xbb", - "0x480080007fff8000", - "0xa0680017fff8000", - "0x16", - "0x480080007ff48003", - "0x480080017ff38003", - "0x4844800180017ffe", - "0x100000000000000000000000000000000", - "0x483080017ffd7ffb", - "0x482480017fff7ffd", - "0x800000000000010fffffffffffffffff7ffffffffffffef0000000000000001", - "0x20680017fff7ffc", - "0x6", - "0x402480017fff7ffd", - "0xffffffffffffffffffffffffffffffff", - "0x10780017fff7fff", - "0x4", - "0x402480017ffe7ffd", - "0xf7ffffffffffffef0000000000000000", - "0x400080027fef7ffd", - "0x20680017fff7ffe", - "0xa0", - "0x402780017fff7fff", - "0x1", - "0x400080007ff47ffe", - "0x482480017ff48000", - "0x1", - "0x48307ff980007ffa", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0xa", - "0x482480017ff88000", - "0x1", - "0x48127ff87fff8000", - "0x480680017fff8000", - "0x0", - "0x48127ff57fff8000", - "0x10780017fff7fff", - "0x8", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x480680017fff8000", - "0x1", - "0x480680017fff8000", - "0x0", - "0x20680017fff7ffe", - "0x81", - "0x480080007fff8000", - "0xa0680017fff8000", - "0x16", - "0x480080007ff88003", - "0x480080017ff78003", - "0x4844800180017ffe", - "0x100000000000000000000000000000000", - "0x483080017ffd7ffb", - "0x482480017fff7ffd", - "0x800000000000010fffffffffffffffff7ffffffffffffef0000000000000001", - "0x20680017fff7ffc", - "0x6", - "0x402480017fff7ffd", - "0xffffffffffffffffffffffffffffffff", - "0x10780017fff7fff", - "0x4", - "0x402480017ffe7ffd", - "0xf7ffffffffffffef0000000000000000", - "0x400080027ff37ffd", - "0x20680017fff7ffe", - "0x68", - "0x402780017fff7fff", - "0x1", - "0x400080007ff87ffe", - "0x482480017ff88000", - "0x1", - "0x48307ff980007ffa", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x12", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x480a7ff77fff8000", "0x48127ffb7fff8000", - "0x480a7ff97fff8000", - "0x48127fe47fff8000", + "0x482480017ffb8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x48127ff87fff8000", - "0x482480017ff78000", + "0x48127ffa7fff8000", + "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x3721", - "0x482480017fff8000", - "0x3720", - "0x480080007fff8000", - "0x480080007fff8000", - "0x484480017fff8000", - "0x2", + "0x4387", "0x482480017fff8000", - "0xb9b4", - "0x480080017ffc8000", - "0x484480017fff8000", - "0x2", - "0x48307ffd7fff8000", + "0x4386", + "0x48127ffb7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", - "0x8", - "0x48307ffe80007fde", + "0x9", + "0x4824800180007ffd", + "0x0", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007ff17fff", + "0x400080007ff57fff", "0x10780017fff7fff", - "0x27", - "0x48307ffe80007fde", - "0x400080007ff27fff", - "0x482480017ff28000", - "0x1", - "0x48127ffe7fff8000", - "0x480a7ff97fff8000", - "0x480a7ff77fff8000", - "0x480a7ffb7fff8000", - "0x48127fdd7fff8000", - "0x48127fe27fff8000", - "0x48127fe97fff8000", - "0x1104800180018000", - "0x16d3", - "0x20680017fff7ffd", - "0xe", - "0x40780017fff7fff", - "0x1", - "0x48127ffa7fff8000", - "0x48127ff67fff8000", - "0x48127ff77fff8000", - "0x48127ff57fff8000", - "0x48127ff77fff8000", - "0x480680017fff8000", + "0x15", + "0x4824800180007ffd", "0x0", - "0x48127ff97fff8000", - "0x48127ff87fff8000", - "0x208b7fff7fff7ffe", - "0x48127ffb7fff8000", - "0x48127ff77fff8000", - "0x48127ff87fff8000", - "0x48127ff67fff8000", - "0x48127ff87fff8000", - "0x480680017fff8000", - "0x1", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x208b7fff7fff7ffe", + "0x400080007ff67fff", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4f7574206f6620676173", + "0x6661696c", "0x400080007ffe7fff", - "0x480a7ff77fff8000", - "0x482480017fee8000", + "0x482480017ff48000", "0x1", - "0x480a7ff97fff8000", - "0x48127fd77fff8000", + "0x482480017ffc8000", + "0xc8", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x48127ff87fff8000", - "0x482480017ff78000", + "0x48127ffa7fff8000", + "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x482480017ff38000", - "0x3", - "0x10780017fff7fff", - "0x5", - "0x40780017fff7fff", - "0x7", - "0x48127ff37fff8000", - "0x10780017fff7fff", - "0xb", - "0x40780017fff7fff", - "0x8", - "0x482480017fe78000", - "0x3", - "0x10780017fff7fff", - "0x5", - "0x40780017fff7fff", - "0xf", - "0x48127fe77fff8000", - "0x10780017fff7fff", - "0x5", - "0x40780017fff7fff", - "0x17", - "0x48127fe77fff8000", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4661696c656420746f20646573657269616c697a6520706172616d202331", + "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x480a7ff77fff8000", - "0x48127ffc7fff8000", - "0x480a7ff97fff8000", - "0x48127fe07fff8000", + "0x482480017ff38000", + "0x1", + "0x48127ff87fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x48127ff87fff8000", - "0x482480017ff78000", + "0x48127ffa7fff8000", + "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", "0x40780017fff7fff", @@ -5454,16 +5758,15 @@ "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x480a7ff77fff8000", - "0x482680017ff88000", + "0x482680017ff98000", "0x1", - "0x480a7ff97fff8000", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x21b6", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x48127ff87fff8000", - "0x482480017ff78000", + "0x48127ffa7fff8000", + "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", "0xa0680017fff8000", @@ -5472,172 +5775,37 @@ "0x100000000000000000000000000000000", "0x400280007ff97fff", "0x10780017fff7fff", - "0x136", + "0x72", "0x4825800180007ffa", "0x0", "0x400280007ff97fff", "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0x19a0", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", + "0x57", "0x482680017ffc8000", "0x1", "0x480a7ffd7fff8000", - "0x480680017fff8000", - "0x0", - "0x480280007ffc8000", - "0x10780017fff7fff", - "0x8", - "0x480a7ffc7fff8000", - "0x480a7ffd7fff8000", - "0x480680017fff8000", - "0x1", - "0x480680017fff8000", - "0x0", - "0x20680017fff7ffe", - "0x10b", - "0xa0680017fff8004", - "0xe", - "0x4824800180047ffe", - "0x800000000000000000000000000000000000000000000000000000000000000", - "0x484480017ffe8000", - "0x110000000000000000", - "0x48307ffe7fff8002", - "0x480080007ff67ffc", - "0x480080017ff57ffc", - "0x402480017ffb7ffd", - "0xffffffffffffffeeffffffffffffffff", - "0x400080027ff47ffd", - "0x10780017fff7fff", - "0xf9", - "0x484480017fff8001", - "0x8000000000000000000000000000000", - "0x48307fff80007ffd", - "0x480080007ff77ffd", - "0x480080017ff67ffd", - "0x402480017ffc7ffe", - "0xf8000000000000000000000000000000", - "0x400080027ff57ffe", - "0x482480017ff58000", - "0x3", - "0x48307ff680007ff7", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0xd9", - "0x482480017ff58000", - "0x1", - "0x48127ff57fff8000", - "0x480080007ff38000", - "0x48307ffd80007ffe", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0xa", - "0x482480017ffc8000", - "0x1", - "0x48127ffc7fff8000", - "0x480680017fff8000", - "0x0", - "0x48127ff97fff8000", - "0x10780017fff7fff", - "0x8", - "0x48127ffc7fff8000", "0x48127ffc7fff8000", - "0x480680017fff8000", - "0x1", - "0x480680017fff8000", - "0x0", - "0x20680017fff7ffe", - "0xbb", - "0x480080007fff8000", - "0xa0680017fff8000", - "0x16", - "0x480080007ff48003", - "0x480080017ff38003", - "0x4844800180017ffe", - "0x100000000000000000000000000000000", - "0x483080017ffd7ffb", - "0x482480017fff7ffd", - "0x800000000000010fffffffffffffffff7ffffffffffffef0000000000000001", - "0x20680017fff7ffc", - "0x6", - "0x402480017fff7ffd", - "0xffffffffffffffffffffffffffffffff", - "0x10780017fff7fff", - "0x4", - "0x402480017ffe7ffd", - "0xf7ffffffffffffef0000000000000000", - "0x400080027fef7ffd", - "0x20680017fff7ffe", - "0xa0", - "0x402780017fff7fff", - "0x1", - "0x400080007ff47ffe", - "0x482480017ff48000", - "0x1", - "0x48307ff980007ffa", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0xa", - "0x482480017ff88000", - "0x1", - "0x48127ff87fff8000", - "0x480680017fff8000", - "0x0", - "0x48127ff57fff8000", - "0x10780017fff7fff", - "0x8", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x480680017fff8000", - "0x1", - "0x480680017fff8000", - "0x0", - "0x20680017fff7ffe", - "0x81", - "0x480080007fff8000", - "0xa0680017fff8000", - "0x16", - "0x480080007ff88003", - "0x480080017ff78003", - "0x4844800180017ffe", - "0x100000000000000000000000000000000", - "0x483080017ffd7ffb", - "0x482480017fff7ffd", - "0x800000000000010fffffffffffffffff7ffffffffffffef0000000000000001", - "0x20680017fff7ffc", - "0x6", - "0x402480017fff7ffd", - "0xffffffffffffffffffffffffffffffff", - "0x10780017fff7fff", - "0x4", - "0x402480017ffe7ffd", - "0xf7ffffffffffffef0000000000000000", - "0x400080027ff37ffd", - "0x20680017fff7ffe", - "0x68", - "0x402780017fff7fff", - "0x1", - "0x400080007ff87ffe", - "0x482480017ff88000", - "0x1", - "0x48307ff980007ffa", + "0x480280007ffc8000", + "0x48307ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127fdb7fff8000", + "0x48127ff67fff8000", + "0x482480017ffa8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -5646,113 +5814,58 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x35ea", + "0x431a", "0x482480017fff8000", - "0x35e9", - "0x480080007fff8000", + "0x4319", + "0x48127ffa7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007fd9", - "0x2382", + "0x4824800180007ffd", + "0x5be", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007ff77fff", + "0x400080007ff07fff", "0x10780017fff7fff", - "0x33", - "0x4824800180007fd9", - "0x2382", - "0x400080007ff87fff", - "0x40780017fff7fff", - "0x1", - "0x48127fe77fff8000", - "0x48127fec7fff8000", - "0x48127ff37fff8000", - "0x400080007ffc7ffd", - "0x400080017ffc7ffe", - "0x400080027ffc7fff", - "0x480680017fff8000", - "0x7772be8b80a8a33dc6c1f9a6ab820c02e537c73e859de67f288c70f92571bb", - "0x48127ffb7fff8000", - "0x482480017ffa8000", - "0x3", + "0x20", + "0x4824800180007ffd", + "0x5be", + "0x400080007ff17fff", "0x482480017ff18000", "0x1", - "0x480680017fff8000", - "0x43616c6c436f6e7472616374", - "0x400280007ffb7fff", - "0x400280017ffb7ff6", - "0x400280027ffb7fd5", - "0x400280037ffb7ffb", - "0x400280047ffb7ffc", - "0x400280057ffb7ffd", - "0x480280077ffb8000", - "0x20680017fff7fff", - "0xd", + "0x48127ffe7fff8000", + "0x48127ff57fff8000", + "0x1104800180018000", + "0x1eee", + "0x20680017fff7ffd", + "0xc", "0x40780017fff7fff", "0x1", - "0x48127ffc7fff8000", - "0x480280067ffb8000", - "0x482680017ffb8000", - "0xa", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x480a7ffb7fff8000", "0x480680017fff8000", "0x0", "0x48127ffb7fff8000", "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", - "0x48127ffd7fff8000", - "0x480280067ffb8000", - "0x482680017ffb8000", - "0xa", - "0x480680017fff8000", - "0x1", - "0x480280087ffb8000", - "0x480280097ffb8000", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", - "0x480680017fff8000", - "0x4f7574206f6620676173", - "0x400080007ffe7fff", - "0x482480017ff58000", - "0x1", - "0x48127fd47fff8000", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x64", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", + "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", - "0x482480017ff38000", - "0x3", - "0x10780017fff7fff", - "0x5", - "0x40780017fff7fff", - "0x7", - "0x48127ff37fff8000", - "0x10780017fff7fff", - "0xb", - "0x40780017fff7fff", - "0x8", - "0x482480017fe78000", - "0x3", - "0x10780017fff7fff", - "0x5", - "0x40780017fff7fff", - "0xf", - "0x48127fe77fff8000", - "0x10780017fff7fff", - "0x5", - "0x40780017fff7fff", - "0x17", - "0x48127fe77fff8000", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4661696c656420746f20646573657269616c697a6520706172616d202332", + "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x48127ffd7fff8000", - "0x48127fd77fff8000", + "0x482480017fee8000", + "0x1", + "0x48127ff87fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -5760,20 +5873,14 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x482480017ff48000", - "0x3", - "0x10780017fff7fff", - "0x5", - "0x40780017fff7fff", - "0x6", - "0x48127ff47fff8000", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202331", "0x400080007ffe7fff", - "0x48127ffd7fff8000", - "0x48127fef7fff8000", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x686", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -5788,7 +5895,8 @@ "0x400080007ffe7fff", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x21b6", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -5800,218 +5908,104 @@ "0x7", "0x482680017ffa8000", "0x100000000000000000000000000000000", - "0x400280007ff87fff", + "0x400280007ff97fff", "0x10780017fff7fff", - "0x5a", + "0x72", "0x4825800180007ffa", "0x0", - "0x400280007ff87fff", - "0x482680017ff88000", + "0x400280007ff97fff", + "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0x19a0", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", + "0x57", + "0x482680017ffc8000", + "0x1", + "0x480a7ffd7fff8000", + "0x48127ffc7fff8000", + "0x480280007ffc8000", + "0x48307ffc80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x480a7ff97fff8000", - "0x48127ff97fff8000", + "0x48127ff67fff8000", + "0x482480017ffa8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x48127ff97fff8000", - "0x482480017ff88000", + "0x48127ffa7fff8000", + "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x3533", - "0x482480017fff8000", - "0x3532", - "0x480080007fff8000", - "0x480080027fff8000", + "0x4293", "0x482480017fff8000", - "0x6acc", + "0x4292", + "0x48127ffa7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", - "0x8", - "0x48307ffe80007ff6", + "0x9", + "0x4824800180007ffd", + "0x5be", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007ff57fff", + "0x400080007ff07fff", "0x10780017fff7fff", - "0x21", - "0x48307ffe80007ff6", - "0x400080007ff67fff", - "0x482480017ff68000", - "0x1", - "0x480a7ff97fff8000", - "0x48127ffd7fff8000", - "0x480a7ffb7fff8000", - "0x1104800180018000", - "0x1611", - "0x20680017fff7ffd", - "0xd", - "0x40780017fff7fff", - "0x1", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x480680017fff8000", - "0x0", - "0x48127ffa7fff8000", - "0x48127ff97fff8000", - "0x208b7fff7fff7ffe", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x480680017fff8000", - "0x1", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", - "0x480680017fff8000", - "0x4f7574206f6620676173", - "0x400080007ffe7fff", - "0x482480017ff38000", - "0x1", - "0x480a7ff97fff8000", - "0x48127ff07fff8000", - "0x480a7ffb7fff8000", - "0x480680017fff8000", - "0x1", - "0x48127ff97fff8000", - "0x482480017ff88000", - "0x1", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", - "0x480680017fff8000", - "0x4f7574206f6620676173", - "0x400080007ffe7fff", - "0x482680017ff88000", - "0x1", - "0x480a7ff97fff8000", - "0x480a7ffa7fff8000", - "0x480a7ffb7fff8000", - "0x480680017fff8000", - "0x1", - "0x48127ff97fff8000", - "0x482480017ff88000", - "0x1", - "0x208b7fff7fff7ffe", - "0xa0680017fff8000", - "0x7", - "0x482680017ffa8000", - "0x100000000000000000000000000000000", - "0x400280007ff97fff", - "0x10780017fff7fff", - "0x75", - "0x4825800180007ffa", - "0x0", - "0x400280007ff97fff", - "0x482680017ff98000", - "0x1", - "0x48297ffc80007ffd", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x5c", - "0x482680017ffc8000", - "0x1", - "0x480a7ffd7fff8000", - "0x480280007ffc8000", - "0x48307ffd80007ffe", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x11", - "0x40780017fff7fff", - "0x1", - "0x480680017fff8000", - "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", - "0x400080007ffe7fff", - "0x480a7ff87fff8000", - "0x48127ff77fff8000", - "0x48127ff57fff8000", - "0x480a7ffb7fff8000", - "0x480680017fff8000", - "0x1", - "0x48127ff97fff8000", - "0x482480017ff88000", - "0x1", - "0x208b7fff7fff7ffe", - "0x1104800180018000", - "0x34bb", - "0x482480017fff8000", - "0x34ba", - "0x480080007fff8000", - "0x480080007fff8000", - "0x484480017fff8000", - "0x2", - "0x482480017fff8000", - "0xe038", - "0xa0680017fff8000", - "0x8", - "0x48307ffe80007ff1", - "0x482480017fff8000", - "0x100000000000000000000000000000000", - "0x400080007ff07fff", - "0x10780017fff7fff", - "0x22", - "0x48307ffe80007ff1", + "0x20", + "0x4824800180007ffd", + "0x5be", "0x400080007ff17fff", "0x482480017ff18000", "0x1", "0x48127ffe7fff8000", - "0x480a7ff87fff8000", - "0x480a7ffb7fff8000", - "0x48127ff17fff8000", + "0x48127ff57fff8000", "0x1104800180018000", - "0x16b8", + "0x1e99", "0x20680017fff7ffd", - "0xd", + "0xc", "0x40780017fff7fff", "0x1", "0x48127ffa7fff8000", - "0x48127ff77fff8000", - "0x48127ff77fff8000", - "0x48127ff87fff8000", + "0x48127ffa7fff8000", + "0x480a7ffb7fff8000", "0x480680017fff8000", "0x0", + "0x48127ffb7fff8000", "0x48127ffa7fff8000", - "0x48127ff97fff8000", "0x208b7fff7fff7ffe", "0x48127ffb7fff8000", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x48127ff97fff8000", + "0x482480017ffb8000", + "0x64", + "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x48127ff97fff8000", - "0x48127ff97fff8000", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x480a7ff87fff8000", - "0x482480017fed8000", + "0x482480017fee8000", "0x1", - "0x48127feb7fff8000", + "0x48127ff87fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x48127ff97fff8000", - "0x482480017ff88000", + "0x48127ffa7fff8000", + "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", "0x40780017fff7fff", @@ -6019,14 +6013,14 @@ "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202331", "0x400080007ffe7fff", - "0x480a7ff87fff8000", "0x48127ffb7fff8000", - "0x48127ff97fff8000", + "0x482480017ffb8000", + "0x686", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x48127ff97fff8000", - "0x482480017ff88000", + "0x48127ffa7fff8000", + "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", "0x40780017fff7fff", @@ -6034,15 +6028,15 @@ "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x480a7ff87fff8000", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x21b6", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x48127ff97fff8000", - "0x482480017ff88000", + "0x48127ffa7fff8000", + "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", "0xa0680017fff8000", @@ -6051,33 +6045,96 @@ "0x100000000000000000000000000000000", "0x400280007ff97fff", "0x10780017fff7fff", - "0x7c", + "0xf3", "0x4825800180007ffa", "0x0", "0x400280007ff97fff", "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0xf0a", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x64", + "0xb", + "0x48127ffe7fff8000", "0x482680017ffc8000", "0x1", "0x480a7ffd7fff8000", + "0x480680017fff8000", + "0x0", "0x480280007ffc8000", - "0x48307ffd80007ffe", + "0x10780017fff7fff", + "0x9", + "0x48127ffe7fff8000", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x20680017fff7ffe", + "0xc4", + "0x48127ffb7fff8000", + "0xa0680017fff8004", + "0xe", + "0x4824800180047ffd", + "0x800000000000000000000000000000000000000000000000000000000000000", + "0x484480017ffe8000", + "0x110000000000000000", + "0x48307ffe7fff8002", + "0x480080007ff37ffc", + "0x480080017ff27ffc", + "0x402480017ffb7ffd", + "0xffffffffffffffeeffffffffffffffff", + "0x400080027ff17ffd", + "0x10780017fff7fff", + "0xaf", + "0x484480017fff8001", + "0x8000000000000000000000000000000", + "0x48307fff80007ffc", + "0x480080007ff47ffd", + "0x480080017ff37ffd", + "0x402480017ffc7ffe", + "0xf8000000000000000000000000000000", + "0x400080027ff27ffe", + "0x482480017ff28000", + "0x3", + "0x48127ff97fff8000", + "0x48307ff480007ff5", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0x90", + "0x482480017ff38000", + "0x1", + "0x48127ff37fff8000", + "0x48127ffc7fff8000", + "0x480080007ff08000", + "0x48307ffc80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x77", + "0x482480017ffb8000", + "0x1", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x480080007ff88000", + "0x48307ffc80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ff87fff8000", - "0x48127ff67fff8000", + "0x48127ff17fff8000", + "0x482480017ffa8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -6086,73 +6143,120 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x3432", + "0x41d1", "0x482480017fff8000", - "0x3431", - "0x480080007fff8000", + "0x41d0", + "0x48127ffa7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007ff4", - "0x10f4", + "0x4824800180007ffd", + "0x2e7c", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007ff37fff", + "0x400080007feb7fff", "0x10780017fff7fff", - "0x30", - "0x4824800180007ff4", - "0x10f4", - "0x400080007ff47fff", + "0x40", + "0x4824800180007ffd", + "0x2e7c", + "0x400080007fec7fff", + "0x482480017fec8000", + "0x1", + "0x48127ffe7fff8000", + "0x20680017fff7ff5", + "0x9", + "0x40780017fff7fff", + "0x8", + "0x482480017ff78000", + "0x2d00", + "0x480a7ffb7fff8000", + "0x10780017fff7fff", + "0x1c", "0x40780017fff7fff", "0x1", - "0x480680017fff8000", - "0xc", - "0x400080007ffe7fff", - "0x480680017fff8000", - "0x22", - "0x400080017ffd7fff", + "0x400080007fff7fe2", + "0x400080017fff7fef", + "0x4824800180007ff4", + "0x1", + "0x400080027ffe7fff", + "0x48127ffd7fff8000", "0x48127ffd7fff8000", "0x482480017ffc8000", - "0x2", - "0x482480017fef8000", - "0x1", + "0x3", "0x480680017fff8000", - "0x53656e644d657373616765546f4c31", + "0x43616c6c436f6e7472616374", "0x400280007ffb7fff", - "0x400280017ffb7ff8", - "0x400280027ffb7ff1", - "0x400280037ffb7ffc", + "0x400280017ffb7ffc", + "0x400280027ffb7fdd", + "0x400280037ffb7fea", "0x400280047ffb7ffd", - "0x480280067ffb8000", + "0x400280057ffb7ffe", + "0x480280077ffb8000", "0x20680017fff7fff", - "0xd", + "0x10", + "0x480280067ffb8000", + "0x48127fff7fff8000", + "0x482680017ffb8000", + "0xa", "0x40780017fff7fff", "0x1", + "0x48127ff37fff8000", + "0x48127ffc7fff8000", "0x48127ffc7fff8000", - "0x480280057ffb8000", - "0x482680017ffb8000", - "0x7", "0x480680017fff8000", "0x0", "0x48127ffb7fff8000", "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", - "0x48127ffd7fff8000", - "0x480280057ffb8000", + "0x480280067ffb8000", + "0x48127ff67fff8000", + "0x482480017ffe8000", + "0x12c", "0x482680017ffb8000", - "0x9", + "0xa", "0x480680017fff8000", "0x1", - "0x480280077ffb8000", "0x480280087ffb8000", + "0x480280097ffb8000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482480017ff18000", + "0x482480017fe98000", "0x1", - "0x48127fef7fff8000", + "0x48127ff87fff8000", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4661696c656420746f20646573657269616c697a6520706172616d202333", + "0x400080007ffe7fff", + "0x48127ff67fff8000", + "0x482480017ffa8000", + "0x686", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4661696c656420746f20646573657269616c697a6520706172616d202332", + "0x400080007ffe7fff", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x8de", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -6160,13 +6264,22 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", + "0x482480017ff18000", + "0x3", + "0x482480017ff88000", + "0x8de", + "0x10780017fff7fff", + "0x5", + "0x48127ff87fff8000", + "0x482480017ffa8000", + "0xdfc", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202331", "0x400080007ffe7fff", "0x48127ffc7fff8000", - "0x48127ffa7fff8000", + "0x48127ffc7fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -6181,7 +6294,8 @@ "0x400080007ffe7fff", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x21b6", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -6193,230 +6307,178 @@ "0x7", "0x482680017ffa8000", "0x100000000000000000000000000000000", - "0x400280007ff67fff", + "0x400280007ff97fff", "0x10780017fff7fff", - "0x69", + "0xb2", "0x4825800180007ffa", "0x0", - "0x400280007ff67fff", - "0x482680017ff68000", + "0x400280007ff97fff", + "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0x1360", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x13", + "0x96", + "0x482680017ffc8000", + "0x1", + "0x480a7ffd7fff8000", + "0x48127ffc7fff8000", + "0x480280007ffc8000", + "0x48307ffc80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x7c", + "0x482480017ffb8000", + "0x1", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x480080007ff88000", + "0x48307ffc80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x62", + "0x482480017ffb8000", + "0x1", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x480080007ff88000", + "0x48307ffc80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x12", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x480a7ff77fff8000", "0x480a7ff87fff8000", - "0x480a7ff97fff8000", - "0x48127ff77fff8000", + "0x48127feb7fff8000", + "0x482480017ff98000", + "0x5be", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x48127ff77fff8000", - "0x482480017ff68000", + "0x48127ff97fff8000", + "0x482480017ff88000", "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x33a8", + "0x40ef", "0x482480017fff8000", - "0x33a7", + "0x40ee", + "0x48127ffa7fff8000", + "0x480080007ffe8000", "0x480080007fff8000", - "0x480080047fff8000", "0x484480017fff8000", "0x2", "0x482480017fff8000", - "0x13fd0", - "0x480080057ffc8000", - "0x484480017fff8000", - "0x4", - "0x48307ffd7fff8000", + "0xc3c8", "0xa0680017fff8000", "0x8", - "0x48307ffe80007ff2", + "0x48307ffe80007ffa", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007ff17fff", + "0x400080007fe37fff", "0x10780017fff7fff", - "0x26", - "0x48307ffe80007ff2", - "0x400080007ff27fff", - "0x482480017ff28000", + "0x25", + "0x48307ffe80007ffa", + "0x400080007fe47fff", + "0x482480017fe48000", "0x1", + "0x48127ffe7fff8000", "0x480a7ff87fff8000", - "0x480a7ff97fff8000", - "0x480a7ff77fff8000", - "0x48127ffb7fff8000", + "0x480a7ffb7fff8000", + "0x48127fe67fff8000", + "0x48127fea7fff8000", + "0x48127fee7fff8000", "0x1104800180018000", - "0x16cf", + "0x1d1c", "0x20680017fff7ffd", - "0xf", + "0xd", "0x40780017fff7fff", "0x1", + "0x48127ffa7fff8000", "0x48127ff77fff8000", - "0x48127ff97fff8000", - "0x48127ff67fff8000", - "0x48127ff67fff8000", "0x48127ff77fff8000", - "0x480a7ffb7fff8000", + "0x48127ff87fff8000", "0x480680017fff8000", "0x0", - "0x48127ff87fff8000", - "0x48127ff77fff8000", - "0x208b7fff7fff7ffe", - "0x48127ff87fff8000", "0x48127ffa7fff8000", - "0x48127ff77fff8000", - "0x48127ff77fff8000", + "0x48127ff97fff8000", + "0x208b7fff7fff7ffe", + "0x48127ffb7fff8000", "0x48127ff87fff8000", - "0x480a7ffb7fff8000", + "0x482480017ff88000", + "0x64", + "0x48127ff97fff8000", "0x480680017fff8000", "0x1", - "0x48127ff77fff8000", - "0x48127ff77fff8000", + "0x48127ff97fff8000", + "0x48127ff97fff8000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482480017fef8000", - "0x1", - "0x480a7ff77fff8000", "0x480a7ff87fff8000", - "0x480a7ff97fff8000", - "0x48127fea7fff8000", + "0x482480017fe08000", + "0x1", + "0x48127ff47fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x48127ff77fff8000", - "0x482480017ff68000", + "0x48127ff97fff8000", + "0x482480017ff88000", "0x1", "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4f7574206f6620676173", + "0x4661696c656420746f20646573657269616c697a6520706172616d202333", "0x400080007ffe7fff", - "0x482680017ff68000", - "0x1", - "0x480a7ff77fff8000", "0x480a7ff87fff8000", - "0x480a7ff97fff8000", - "0x480a7ffa7fff8000", + "0x48127ff07fff8000", + "0x482480017ff98000", + "0x7b2", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x48127ff77fff8000", - "0x482480017ff68000", + "0x48127ff97fff8000", + "0x482480017ff88000", "0x1", "0x208b7fff7fff7ffe", - "0xa0680017fff8000", - "0x7", - "0x482680017ffa8000", - "0x100000000000000000000000000000000", - "0x400280007ff87fff", - "0x10780017fff7fff", - "0x66", - "0x4825800180007ffa", - "0x0", - "0x400280007ff87fff", - "0x482680017ff88000", - "0x1", - "0x48297ffc80007ffd", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", + "0x4661696c656420746f20646573657269616c697a6520706172616d202332", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x480a7ff97fff8000", + "0x480a7ff87fff8000", + "0x48127ff57fff8000", + "0x482480017ff98000", + "0xa0a", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", "0x48127ff97fff8000", - "0x480a7ffb7fff8000", - "0x480680017fff8000", - "0x1", - "0x48127ff97fff8000", - "0x482480017ff88000", - "0x1", - "0x208b7fff7fff7ffe", - "0x1104800180018000", - "0x332a", - "0x482480017fff8000", - "0x3329", - "0x480080007fff8000", - "0xa0680017fff8000", - "0x9", - "0x4824800180007ff8", - "0x0", - "0x482480017fff8000", - "0x100000000000000000000000000000000", - "0x400080007ff77fff", - "0x10780017fff7fff", - "0x2f", - "0x4824800180007ff8", - "0x0", - "0x400080007ff87fff", - "0x480a7ff97fff8000", - "0x1104800180018000", - "0x181a", - "0x482480017fe88000", - "0x1", - "0x20680017fff7ffc", - "0x17", - "0x48127ffb7fff8000", - "0x1104800180018000", - "0x1813", - "0x20680017fff7ffd", - "0xd", - "0x40780017fff7fff", - "0x1", - "0x48127fee7fff8000", - "0x48127ffa7fff8000", - "0x48127fdb7fff8000", - "0x480a7ffb7fff8000", - "0x480680017fff8000", - "0x0", - "0x48127ffa7fff8000", - "0x48127ff97fff8000", - "0x208b7fff7fff7ffe", - "0x48127ffc7fff8000", - "0x48127ffd7fff8000", - "0x48127ffd7fff8000", - "0x10780017fff7fff", - "0x7", - "0x40780017fff7fff", - "0x10", - "0x48127feb7fff8000", - "0x48127fec7fff8000", - "0x48127fec7fff8000", - "0x48127fec7fff8000", - "0x48127ffc7fff8000", - "0x48127fd97fff8000", - "0x480a7ffb7fff8000", - "0x480680017fff8000", - "0x1", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", - "0x480680017fff8000", - "0x4f7574206f6620676173", - "0x400080007ffe7fff", - "0x482480017ff58000", - "0x1", - "0x480a7ff97fff8000", - "0x48127ff27fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4661696c656420746f20646573657269616c697a6520706172616d202331", + "0x400080007ffe7fff", + "0x480a7ff87fff8000", + "0x48127ffa7fff8000", + "0x482480017ffa8000", + "0xc62", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -6429,10 +6491,11 @@ "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482680017ff88000", + "0x480a7ff87fff8000", + "0x482680017ff98000", "0x1", - "0x480a7ff97fff8000", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x2152", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -6440,389 +6503,271 @@ "0x482480017ff88000", "0x1", "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x2", "0xa0680017fff8000", "0x7", "0x482680017ffa8000", "0x100000000000000000000000000000000", - "0x400280007ff97fff", + "0x400280007ff87fff", "0x10780017fff7fff", - "0xf2", + "0x106", "0x4825800180007ffa", "0x0", - "0x400280007ff97fff", - "0x482680017ff98000", + "0x400280007ff87fff", + "0x482680017ff88000", "0x1", + "0x482480017ffe8000", + "0xa3c", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", + "0xe7", "0x482680017ffc8000", "0x1", "0x480a7ffd7fff8000", + "0x48127ffc7fff8000", + "0x480280007ffc8000", + "0x48307ffc80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xb", + "0x48127ffd7fff8000", + "0x482480017ffa8000", + "0x1", + "0x48127ffa7fff8000", "0x480680017fff8000", "0x0", - "0x480280007ffc8000", + "0x48127ff77fff8000", "0x10780017fff7fff", - "0x8", - "0x480a7ffc7fff8000", - "0x480a7ffd7fff8000", + "0x9", + "0x48127ffd7fff8000", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", "0x480680017fff8000", "0x1", "0x480680017fff8000", "0x0", "0x20680017fff7ffe", - "0xc7", - "0x40137fff7fff8000", - "0xa0680017fff8004", - "0xe", - "0x4825800180048000", - "0x800000000000000000000000000000000000000000000000000000000000000", - "0x484480017ffe8000", - "0x110000000000000000", - "0x48307ffe7fff8002", - "0x480080007ff67ffc", - "0x480080017ff57ffc", - "0x402480017ffb7ffd", - "0xffffffffffffffeeffffffffffffffff", - "0x400080027ff47ffd", + "0xc6", + "0x480080007fff8000", + "0x48127ffa7fff8000", + "0xa0680017fff8000", + "0x16", + "0x480080007ff08003", + "0x480080017fef8003", + "0x4844800180017ffe", + "0x100000000000000000000000000000000", + "0x483080017ffd7ffa", + "0x482480017fff7ffd", + "0x800000000000010fffffffffffffffff7ffffffffffffef0000000000000001", + "0x20680017fff7ffc", + "0x6", + "0x402480017fff7ffd", + "0xffffffffffffffffffffffffffffffff", "0x10780017fff7fff", - "0xb4", - "0x484480017fff8001", - "0x8000000000000000000000000000000", - "0x48317fff80008000", - "0x480080007ff77ffd", - "0x480080017ff67ffd", - "0x402480017ffc7ffe", - "0xf8000000000000000000000000000000", - "0x400080027ff57ffe", - "0x482480017ff58000", - "0x3", - "0x48307ff680007ff7", - "0x20680017fff7fff", "0x4", - "0x10780017fff7fff", - "0x97", - "0x400180007ff58001", - "0x482480017ff58000", + "0x402480017ffe7ffd", + "0xf7ffffffffffffef0000000000000000", + "0x400080027feb7ffd", + "0x20680017fff7ffe", + "0xaa", + "0x402780017fff7fff", "0x1", - "0x48127ff57fff8000", - "0x48307ffe80007fff", + "0x400080007ff07ffd", + "0x482480017ff08000", + "0x1", + "0x48127ffd7fff8000", + "0x48307ff780007ff8", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", - "0x482480017ffd8000", + "0xb", + "0x48127ffe7fff8000", + "0x482480017ff58000", "0x1", - "0x48127ffd7fff8000", + "0x48127ff57fff8000", "0x480680017fff8000", "0x0", - "0x48127ffa7fff8000", + "0x48127ff27fff8000", "0x10780017fff7fff", - "0x8", - "0x48127ffd7fff8000", - "0x48127ffd7fff8000", + "0x9", + "0x48127ffe7fff8000", + "0x48127ff57fff8000", + "0x48127ff57fff8000", "0x480680017fff8000", "0x1", "0x480680017fff8000", "0x0", "0x20680017fff7ffe", - "0x6e", - "0x40780017fff7fff", - "0x1", - "0x48127ff67fff8000", - "0x48127fe97fff8000", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x48127ffb7fff8000", + "0x88", + "0x480080007fff8000", "0x48127ffa7fff8000", - "0x480080007ff88000", - "0x1104800180018000", - "0x2b1", - "0x20680017fff7ffa", - "0x59", - "0x20680017fff7ffd", - "0x53", - "0x48307ffb80007ffc", + "0xa0680017fff8000", + "0x16", + "0x480080007ff58003", + "0x480080017ff48003", + "0x4844800180017ffe", + "0x100000000000000000000000000000000", + "0x483080017ffd7ffa", + "0x482480017fff7ffd", + "0x800000000000010fffffffffffffffff7ffffffffffffef0000000000000001", + "0x20680017fff7ffc", + "0x6", + "0x402480017fff7ffd", + "0xffffffffffffffffffffffffffffffff", + "0x10780017fff7fff", + "0x4", + "0x402480017ffe7ffd", + "0xf7ffffffffffffef0000000000000000", + "0x400080027ff07ffd", + "0x20680017fff7ffe", + "0x6c", + "0x402780017fff7fff", + "0x1", + "0x400080007ff57ffd", + "0x482480017ff58000", + "0x1", + "0x48127ffd7fff8000", + "0x48307ff780007ff8", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0x13", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ff57fff8000", - "0x48127ff57fff8000", + "0x480a7ff77fff8000", + "0x48127ffa7fff8000", + "0x480a7ff97fff8000", + "0x482480017ff98000", + "0x6ea", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", + "0x48127ff87fff8000", + "0x482480017ff78000", "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x3253", + "0x3fd4", "0x482480017fff8000", - "0x3252", + "0x3fd3", + "0x48127ffb7fff8000", + "0x480080007ffe8000", "0x480080007fff8000", + "0x484480017fff8000", + "0x2", + "0x482480017fff8000", + "0xc9cc", + "0x480080017ffc8000", + "0x484480017fff8000", + "0x2", + "0x48307ffd7fff8000", "0xa0680017fff8000", - "0x9", - "0x4824800180007ff3", - "0xb4f0", + "0x8", + "0x48307ffe80007ff7", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007ff07fff", + "0x400080007fef7fff", "0x10780017fff7fff", - "0x23", - "0x4824800180007ff3", - "0xb4f0", - "0x400080007ff17fff", - "0x482480017ff18000", + "0x28", + "0x48307ffe80007ff7", + "0x400080007ff07fff", + "0x482480017ff08000", "0x1", "0x48127ffe7fff8000", + "0x480a7ff97fff8000", + "0x480a7ff77fff8000", "0x480a7ffb7fff8000", - "0x480a80007fff8000", - "0x480a80017fff8000", - "0x48127ff27fff8000", - "0x48127ff27fff8000", + "0x48127fd67fff8000", + "0x48127fdc7fff8000", + "0x48127fe67fff8000", "0x1104800180018000", - "0x175d", + "0x1cd9", "0x20680017fff7ffd", - "0xc", + "0xe", "0x40780017fff7fff", "0x1", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x480680017fff8000", - "0x0", - "0x48127ffb7fff8000", - "0x48127ffa7fff8000", - "0x208b7fff7fff7ffe", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", - "0x480680017fff8000", - "0x1", "0x48127ffa7fff8000", - "0x48127ffa7fff8000", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", - "0x480680017fff8000", - "0x4f7574206f6620676173", - "0x400080007ffe7fff", - "0x482480017fee8000", - "0x1", - "0x48127fee7fff8000", - "0x480a7ffb7fff8000", + "0x48127ff67fff8000", + "0x48127ff77fff8000", + "0x48127ff57fff8000", + "0x48127ff77fff8000", "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", - "0x48127ff87fff8000", + "0x0", + "0x48127ff97fff8000", "0x48127ff87fff8000", - "0x10780017fff7fff", - "0xc", + "0x208b7fff7fff7ffe", + "0x48127ffb7fff8000", + "0x48127ff77fff8000", "0x48127ff87fff8000", + "0x482480017ff68000", + "0x64", "0x48127ff87fff8000", - "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", + "0x48127ff87fff8000", + "0x48127ff87fff8000", "0x208b7fff7fff7ffe", - "0x48127ff77fff8000", - "0x48127fea7fff8000", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4661696c656420746f20646573657269616c697a6520706172616d202333", + "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127ffc7fff8000", - "0x480a7ffb7fff8000", - "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", + "0x480a7ff77fff8000", + "0x482480017fec8000", "0x1", - "0x480680017fff8000", - "0x4661696c656420746f20646573657269616c697a6520706172616d202332", - "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127fef7fff8000", + "0x480a7ff97fff8000", + "0x48127ff07fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", + "0x48127ff87fff8000", + "0x482480017ff78000", "0x1", "0x208b7fff7fff7ffe", - "0x482480017ff48000", + "0x482480017ff08000", "0x3", + "0x482480017ff88000", + "0x276", "0x10780017fff7fff", "0x5", - "0x40780017fff7fff", - "0x6", - "0x48127ff47fff8000", - "0x40780017fff7fff", - "0x1", - "0x480680017fff8000", - "0x4661696c656420746f20646573657269616c697a6520706172616d202331", - "0x400080007ffe7fff", - "0x48127ffd7fff8000", - "0x48127fef7fff8000", - "0x480a7ffb7fff8000", - "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", - "0x480680017fff8000", - "0x4f7574206f6620676173", - "0x400080007ffe7fff", - "0x482680017ff98000", - "0x1", - "0x480a7ffa7fff8000", - "0x480a7ffb7fff8000", - "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", - "0xa0680017fff8000", - "0x7", - "0x482680017ffa8000", - "0x100000000000000000000000000000000", - "0x400280007ff97fff", - "0x10780017fff7fff", - "0x74", - "0x4825800180007ffa", - "0x0", - "0x400280007ff97fff", - "0x482680017ff98000", - "0x1", - "0x48297ffc80007ffd", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x5c", - "0x482680017ffc8000", - "0x1", - "0x480a7ffd7fff8000", - "0x48307ffe80007fff", - "0x20680017fff7fff", - "0x4", + "0x48127ff87fff8000", + "0x482480017ffa8000", + "0x8c0", "0x10780017fff7fff", - "0x46", - "0x482480017ffd8000", - "0x1", - "0x48127ffd7fff8000", - "0x480080007ffb8000", - "0x48307ffd80007ffe", - "0x20680017fff7fff", - "0x4", + "0xb", + "0x482480017feb8000", + "0x3", + "0x482480017ff88000", + "0x8fc", "0x10780017fff7fff", - "0x10", - "0x40780017fff7fff", - "0x1", - "0x480680017fff8000", - "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", - "0x400080007ffe7fff", - "0x48127ff57fff8000", + "0x5", "0x48127ff37fff8000", - "0x480a7ffb7fff8000", - "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", - "0x1104800180018000", - "0x3197", - "0x482480017fff8000", - "0x3196", - "0x480080007fff8000", - "0xa0680017fff8000", - "0x9", - "0x4824800180007ff1", - "0x0", - "0x482480017fff8000", - "0x100000000000000000000000000000000", - "0x400080007ff07fff", + "0x482480017ffa8000", + "0xf46", "0x10780017fff7fff", - "0x12", - "0x4824800180007ff1", - "0x0", - "0x400080007ff17fff", - "0x40780017fff7fff", - "0x1", - "0x400080007fff7ff7", - "0x482480017ff08000", - "0x1", + "0x5", "0x48127ffd7fff8000", - "0x480a7ffb7fff8000", - "0x480680017fff8000", - "0x0", - "0x48127ffb7fff8000", - "0x482480017ffa8000", - "0x1", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", - "0x480680017fff8000", - "0x4f7574206f6620676173", - "0x400080007ffe7fff", - "0x482480017fee8000", - "0x1", - "0x48127fec7fff8000", - "0x480a7ffb7fff8000", - "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", - "0x480680017fff8000", - "0x4661696c656420746f20646573657269616c697a6520706172616d202332", - "0x400080007ffe7fff", - "0x48127ff97fff8000", - "0x48127ff77fff8000", - "0x480a7ffb7fff8000", - "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", + "0x482480017ffd8000", + "0x145a", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202331", "0x400080007ffe7fff", - "0x48127ffc7fff8000", + "0x480a7ff77fff8000", + "0x48127ffb7fff8000", + "0x480a7ff97fff8000", "0x48127ffa7fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", + "0x48127ff87fff8000", + "0x482480017ff78000", "0x1", "0x208b7fff7fff7ffe", "0x40780017fff7fff", @@ -6830,14 +6775,17 @@ "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482680017ff98000", + "0x480a7ff77fff8000", + "0x482680017ff88000", "0x1", - "0x480a7ffa7fff8000", + "0x480a7ff97fff8000", + "0x482680017ffa8000", + "0x20ee", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", + "0x48127ff87fff8000", + "0x482480017ff78000", "0x1", "0x208b7fff7fff7ffe", "0xa0680017fff8000", @@ -6846,44 +6794,41 @@ "0x100000000000000000000000000000000", "0x400280007ff97fff", "0x10780017fff7fff", - "0xcd", + "0x14f", "0x4825800180007ffa", "0x0", "0x400280007ff97fff", "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0x51e", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xb5", + "0xb", + "0x48127ffe7fff8000", "0x482680017ffc8000", "0x1", "0x480a7ffd7fff8000", - "0x48307ffe80007fff", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0xa", - "0x482480017ffd8000", - "0x1", - "0x48127ffd7fff8000", "0x480680017fff8000", "0x0", - "0x480080007ffa8000", + "0x480280007ffc8000", "0x10780017fff7fff", - "0x8", - "0x48127ffd7fff8000", - "0x48127ffd7fff8000", + "0x9", + "0x48127ffe7fff8000", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", "0x480680017fff8000", "0x1", "0x480680017fff8000", "0x0", "0x20680017fff7ffe", - "0x8c", + "0x120", + "0x48127ffb7fff8000", "0xa0680017fff8004", "0xe", - "0x4824800180047ffe", + "0x4824800180047ffd", "0x800000000000000000000000000000000000000000000000000000000000000", "0x484480017ffe8000", "0x110000000000000000", @@ -6894,10 +6839,10 @@ "0xffffffffffffffeeffffffffffffffff", "0x400080027ff17ffd", "0x10780017fff7fff", - "0x7a", + "0x10b", "0x484480017fff8001", "0x8000000000000000000000000000000", - "0x48307fff80007ffd", + "0x48307fff80007ffc", "0x480080007ff47ffd", "0x480080017ff37ffd", "0x402480017ffc7ffe", @@ -6905,27 +6850,132 @@ "0x400080027ff27ffe", "0x482480017ff28000", "0x3", - "0x48307ff680007ff7", + "0x48127ff97fff8000", + "0x48307ff480007ff5", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x5d", + "0xea", + "0x482480017ff38000", + "0x1", + "0x48127ff37fff8000", + "0x48127ffc7fff8000", + "0x480080007ff08000", + "0x48307ffc80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xb", + "0x48127ffd7fff8000", + "0x482480017ffa8000", + "0x1", + "0x48127ffa7fff8000", + "0x480680017fff8000", + "0x0", + "0x48127ff77fff8000", + "0x10780017fff7fff", + "0x9", + "0x48127ffd7fff8000", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x20680017fff7ffe", + "0xc9", + "0x480080007fff8000", + "0x48127ffa7fff8000", + "0xa0680017fff8000", + "0x16", + "0x480080007ff08003", + "0x480080017fef8003", + "0x4844800180017ffe", + "0x100000000000000000000000000000000", + "0x483080017ffd7ffa", + "0x482480017fff7ffd", + "0x800000000000010fffffffffffffffff7ffffffffffffef0000000000000001", + "0x20680017fff7ffc", + "0x6", + "0x402480017fff7ffd", + "0xffffffffffffffffffffffffffffffff", + "0x10780017fff7fff", + "0x4", + "0x402480017ffe7ffd", + "0xf7ffffffffffffef0000000000000000", + "0x400080027feb7ffd", + "0x20680017fff7ffe", + "0xad", + "0x402780017fff7fff", + "0x1", + "0x400080007ff07ffd", + "0x482480017ff08000", + "0x1", + "0x48127ffd7fff8000", + "0x48307ff780007ff8", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xb", + "0x48127ffe7fff8000", "0x482480017ff58000", "0x1", "0x48127ff57fff8000", - "0x480080007ff38000", - "0x48307ffd80007ffe", + "0x480680017fff8000", + "0x0", + "0x48127ff27fff8000", + "0x10780017fff7fff", + "0x9", + "0x48127ffe7fff8000", + "0x48127ff57fff8000", + "0x48127ff57fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x20680017fff7ffe", + "0x8b", + "0x480080007fff8000", + "0x48127ffa7fff8000", + "0xa0680017fff8000", + "0x16", + "0x480080007ff58003", + "0x480080017ff48003", + "0x4844800180017ffe", + "0x100000000000000000000000000000000", + "0x483080017ffd7ffa", + "0x482480017fff7ffd", + "0x800000000000010fffffffffffffffff7ffffffffffffef0000000000000001", + "0x20680017fff7ffc", + "0x6", + "0x402480017fff7ffd", + "0xffffffffffffffffffffffffffffffff", + "0x10780017fff7fff", + "0x4", + "0x402480017ffe7ffd", + "0xf7ffffffffffffef0000000000000000", + "0x400080027ff07ffd", + "0x20680017fff7ffe", + "0x6f", + "0x402780017fff7fff", + "0x1", + "0x400080007ff57ffd", + "0x482480017ff58000", + "0x1", + "0x48127ffd7fff8000", + "0x48307ff780007ff8", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ff87fff8000", - "0x48127fe87fff8000", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x492", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -6934,66 +6984,81 @@ "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x30e2", + "0x3e88", "0x482480017fff8000", - "0x30e1", - "0x480080007fff8000", + "0x3e87", + "0x48127ffb7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", "0x9", - "0x4824800180007fe6", - "0x17a2", + "0x4824800180007ffd", + "0x2e18", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007ff37fff", + "0x400080007ff57fff", "0x10780017fff7fff", - "0x29", - "0x4824800180007fe6", - "0x17a2", - "0x400080007ff47fff", + "0x37", + "0x4824800180007ffd", + "0x2e18", + "0x400080007ff67fff", + "0x40780017fff7fff", + "0x1", + "0x48127fe07fff8000", + "0x48127fe67fff8000", + "0x48127ff07fff8000", + "0x400080007ffc7ffd", + "0x400080017ffc7ffe", + "0x400080027ffc7fff", + "0x48127ffb7fff8000", "0x480680017fff8000", - "0x0", - "0x482480017ff38000", + "0x7772be8b80a8a33dc6c1f9a6ab820c02e537c73e859de67f288c70f92571bb", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x3", + "0x482480017fee8000", "0x1", "0x480680017fff8000", - "0x53746f726167655772697465", + "0x43616c6c436f6e7472616374", "0x400280007ffb7fff", - "0x400280017ffb7ffc", - "0x400280027ffb7ffd", - "0x400280037ffb7feb", - "0x400280047ffb7ff5", - "0x480280067ffb8000", + "0x400280017ffb7ffa", + "0x400280027ffb7fca", + "0x400280037ffb7ffb", + "0x400280047ffb7ffc", + "0x400280057ffb7ffd", + "0x480280077ffb8000", "0x20680017fff7fff", - "0xf", + "0xe", + "0x480280067ffb8000", "0x40780017fff7fff", "0x1", - "0x400080007fff7ff3", - "0x48127ffc7fff8000", - "0x480280057ffb8000", + "0x48127ffb7fff8000", + "0x48127ffd7fff8000", "0x482680017ffb8000", - "0x7", + "0xa", "0x480680017fff8000", "0x0", "0x48127ffb7fff8000", - "0x482480017ffa8000", - "0x1", + "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", - "0x48127ffd7fff8000", - "0x480280057ffb8000", + "0x480280067ffb8000", + "0x48127ffc7fff8000", + "0x482480017ffe8000", + "0x64", "0x482680017ffb8000", - "0x9", + "0xa", "0x480680017fff8000", "0x1", - "0x480280077ffb8000", "0x480280087ffb8000", + "0x480280097ffb8000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482480017ff18000", + "0x482480017ff38000", "0x1", - "0x48127fe17fff8000", + "0x48127ff87fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -7001,13 +7066,38 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", + "0x482480017ff08000", + "0x3", + "0x482480017ff88000", + "0x1e", + "0x10780017fff7fff", + "0x5", + "0x48127ff87fff8000", + "0x482480017ffa8000", + "0x668", + "0x10780017fff7fff", + "0xb", + "0x482480017feb8000", + "0x3", + "0x482480017ff88000", + "0x6a4", + "0x10780017fff7fff", + "0x5", + "0x48127ff37fff8000", + "0x482480017ffa8000", + "0xcee", + "0x10780017fff7fff", + "0x5", + "0x48127ffd7fff8000", + "0x482480017ffd8000", + "0x1202", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4661696c656420746f20646573657269616c697a6520706172616d202333", + "0x4661696c656420746f20646573657269616c697a6520706172616d202332", "0x400080007ffe7fff", "0x48127ffc7fff8000", - "0x48127fec7fff8000", + "0x48127ffc7fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -7017,18 +7107,20 @@ "0x208b7fff7fff7ffe", "0x482480017ff18000", "0x3", + "0x482480017ff88000", + "0x12ca", "0x10780017fff7fff", "0x5", - "0x40780017fff7fff", - "0x6", - "0x48127ff17fff8000", + "0x48127ff87fff8000", + "0x482480017ffa8000", + "0x17e8", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4661696c656420746f20646573657269616c697a6520706172616d202332", + "0x4661696c656420746f20646573657269616c697a6520706172616d202331", "0x400080007ffe7fff", - "0x48127ffd7fff8000", - "0x48127fec7fff8000", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -7039,10 +7131,12 @@ "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4661696c656420746f20646573657269616c697a6520706172616d202331", + "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127ffa7fff8000", + "0x482680017ff98000", + "0x1", + "0x482680017ffa8000", + "0x21b6", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", @@ -7050,19 +7144,121 @@ "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", + "0xa0680017fff8000", + "0x7", + "0x482680017ffa8000", + "0x100000000000000000000000000000000", + "0x400280007ff87fff", + "0x10780017fff7fff", + "0x5f", + "0x4825800180007ffa", + "0x0", + "0x400280007ff87fff", + "0x482680017ff88000", + "0x1", + "0x482480017ffe8000", + "0x1acc", + "0x48297ffc80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x12", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", + "0x400080007ffe7fff", + "0x48127ffb7fff8000", + "0x480a7ff97fff8000", + "0x482480017ffa8000", + "0x55a", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0x1104800180018000", + "0x3dc4", + "0x482480017fff8000", + "0x3dc3", + "0x48127ffb7fff8000", + "0x480080007ffe8000", + "0x480080027fff8000", + "0x482480017fff8000", + "0x89e4", + "0xa0680017fff8000", + "0x8", + "0x48307ffe80007ffb", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400080007ff37fff", + "0x10780017fff7fff", + "0x22", + "0x48307ffe80007ffb", + "0x400080007ff47fff", + "0x480a7ff97fff8000", + "0x48127ffe7fff8000", + "0x480a7ffb7fff8000", + "0x1104800180018000", + "0x1c33", + "0x482480017f778000", + "0x1", + "0x20680017fff7ffc", + "0xd", + "0x40780017fff7fff", + "0x1", + "0x48127ffe7fff8000", + "0x48127ff77fff8000", + "0x48127ff77fff8000", + "0x48127ff77fff8000", + "0x480680017fff8000", + "0x0", + "0x48127ffa7fff8000", + "0x48127ff97fff8000", + "0x208b7fff7fff7ffe", + "0x48127fff7fff8000", + "0x48127ff87fff8000", + "0x482480017ff88000", + "0x64", + "0x48127ff87fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ff87fff8000", + "0x48127ff87fff8000", + "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482680017ff98000", + "0x482480017ff18000", "0x1", - "0x480a7ffa7fff8000", + "0x480a7ff97fff8000", + "0x48127ff57fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x482680017ff88000", + "0x1", + "0x480a7ff97fff8000", + "0x482680017ffa8000", + "0x2152", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ff97fff8000", + "0x482480017ff88000", "0x1", "0x208b7fff7fff7ffe", "0xa0680017fff8000", @@ -7071,132 +7267,111 @@ "0x100000000000000000000000000000000", "0x400280007ff97fff", "0x10780017fff7fff", - "0x8f", + "0x7c", "0x4825800180007ffa", "0x0", "0x400280007ff97fff", "0x482680017ff98000", "0x1", + "0x482480017ffe8000", + "0x1810", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x77", + "0x60", "0x482680017ffc8000", "0x1", "0x480a7ffd7fff8000", - "0x480280007ffc8000", - "0x48307ffd80007ffe", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x60", - "0x482480017ffc8000", - "0x1", "0x48127ffc7fff8000", - "0x480080007ffa8000", - "0x48307ffd80007ffe", + "0x480280007ffc8000", + "0x48307ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x10", + "0x12", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x48127ff47fff8000", - "0x48127ff27fff8000", + "0x480a7ff87fff8000", + "0x48127ff57fff8000", + "0x482480017ff98000", + "0x5be", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", + "0x48127ff97fff8000", + "0x482480017ff88000", "0x1", "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x302d", + "0x3d45", "0x482480017fff8000", - "0x302c", + "0x3d44", + "0x48127ffa7fff8000", + "0x480080007ffe8000", "0x480080007fff8000", + "0x484480017fff8000", + "0x2", + "0x482480017fff8000", + "0xf9f6", "0xa0680017fff8000", - "0x9", - "0x4824800180007ff0", - "0x11bc", + "0x8", + "0x48307ffe80007ffa", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080007fef7fff", + "0x400080007fed7fff", "0x10780017fff7fff", - "0x2c", - "0x4824800180007ff0", - "0x11bc", - "0x400080007ff07fff", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x1275130f95dda36bcbb6e9d28796c1d7e10b6e9fd5ed083e0ede4b12f613528", - "0x48307ff67ff28000", - "0x482480017fed8000", + "0x23", + "0x48307ffe80007ffa", + "0x400080007fee7fff", + "0x482480017fee8000", "0x1", - "0x480680017fff8000", - "0x53746f726167655772697465", - "0x400280007ffb7fff", - "0x400280017ffb7ffa", - "0x400280027ffb7ffb", - "0x400280037ffb7ffc", - "0x400280047ffb7ffd", - "0x480280067ffb8000", - "0x20680017fff7fff", - "0xf", + "0x48127ffe7fff8000", + "0x480a7ff87fff8000", + "0x480a7ffb7fff8000", + "0x48127ff07fff8000", + "0x1104800180018000", + "0x1cfc", + "0x20680017fff7ffd", + "0xd", "0x40780017fff7fff", "0x1", - "0x400080007fff7fed", - "0x48127ffc7fff8000", - "0x480280057ffb8000", - "0x482680017ffb8000", - "0x7", + "0x48127ffa7fff8000", + "0x48127ff77fff8000", + "0x48127ff77fff8000", + "0x48127ff87fff8000", "0x480680017fff8000", "0x0", - "0x48127ffb7fff8000", - "0x482480017ffa8000", - "0x1", + "0x48127ffa7fff8000", + "0x48127ff97fff8000", "0x208b7fff7fff7ffe", - "0x48127ffd7fff8000", - "0x480280057ffb8000", - "0x482680017ffb8000", - "0x9", + "0x48127ffb7fff8000", + "0x48127ff87fff8000", + "0x482480017ff88000", + "0x64", + "0x48127ff97fff8000", "0x480680017fff8000", "0x1", - "0x480280077ffb8000", - "0x480280087ffb8000", + "0x48127ff97fff8000", + "0x48127ff97fff8000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482480017fed8000", - "0x1", - "0x48127feb7fff8000", - "0x480a7ffb7fff8000", - "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", + "0x480a7ff87fff8000", + "0x482480017fea8000", "0x1", - "0x480680017fff8000", - "0x4661696c656420746f20646573657269616c697a6520706172616d202332", - "0x400080007ffe7fff", - "0x48127ff87fff8000", - "0x48127ff67fff8000", + "0x48127ff47fff8000", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", + "0x48127ff97fff8000", + "0x482480017ff88000", "0x1", "0x208b7fff7fff7ffe", "0x40780017fff7fff", @@ -7204,13 +7379,15 @@ "0x480680017fff8000", "0x4661696c656420746f20646573657269616c697a6520706172616d202331", "0x400080007ffe7fff", - "0x48127ffc7fff8000", + "0x480a7ff87fff8000", "0x48127ffa7fff8000", + "0x482480017ffa8000", + "0x7b2", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", + "0x48127ff97fff8000", + "0x482480017ff88000", "0x1", "0x208b7fff7fff7ffe", "0x40780017fff7fff", @@ -7218,446 +7395,472 @@ "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", + "0x480a7ff87fff8000", "0x482680017ff98000", "0x1", - "0x480a7ffa7fff8000", + "0x482680017ffa8000", + "0x2152", "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", + "0x48127ff97fff8000", + "0x482480017ff88000", "0x1", "0x208b7fff7fff7ffe", "0xa0680017fff8000", "0x7", - "0x482680017ff88000", - "0xfffffffffffffffffffffffffffff6be", - "0x400280007ff77fff", + "0x482680017ffa8000", + "0x100000000000000000000000000000000", + "0x400280007ff97fff", "0x10780017fff7fff", - "0x43", - "0x4825800180007ff8", - "0x942", - "0x400280007ff77fff", - "0x482680017ff78000", - "0x1", - "0x20780017fff7ffd", - "0xd", - "0x48127fff7fff8000", - "0x48127ffd7fff8000", - "0x480680017fff8000", - "0x0", - "0x480a7ff97fff8000", - "0x480a7ffa7fff8000", - "0x480680017fff8000", + "0x86", + "0x4825800180007ffa", "0x0", - "0x480a7ffb7fff8000", - "0x480a7ffc7fff8000", - "0x208b7fff7fff7ffe", - "0x48297ff980007ffa", + "0x400280007ff97fff", + "0x482680017ff98000", + "0x1", + "0x482480017ffe8000", + "0x19a0", + "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", - "0x482680017ff98000", + "0x6b", + "0x482680017ffc8000", "0x1", - "0x480a7ffa7fff8000", - "0x480680017fff8000", - "0x0", - "0x480280007ff98000", + "0x480a7ffd7fff8000", + "0x48127ffc7fff8000", + "0x480280007ffc8000", + "0x48307ffc80007ffd", + "0x20680017fff7fff", + "0x4", "0x10780017fff7fff", - "0x8", - "0x480a7ff97fff8000", - "0x480a7ffa7fff8000", - "0x480680017fff8000", + "0x11", + "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x0", - "0x20680017fff7ffe", - "0xf", - "0x400280007ffc7fff", - "0x48127ffa7fff8000", - "0x48127ff87fff8000", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", + "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", + "0x400080007ffe7fff", + "0x48127ff67fff8000", + "0x482480017ffa8000", + "0x492", "0x480a7ffb7fff8000", - "0x482680017ffc8000", + "0x480680017fff8000", "0x1", - "0x4825800180007ffd", + "0x48127ffa7fff8000", + "0x482480017ff98000", "0x1", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffc9", "0x208b7fff7fff7ffe", + "0x1104800180018000", + "0x3cb4", + "0x482480017fff8000", + "0x3cb3", "0x48127ffa7fff8000", - "0x48127ff87fff8000", + "0x480080007ffe8000", + "0xa0680017fff8000", + "0x9", + "0x4824800180007ffd", + "0x2c88", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400080007ff07fff", + "0x10780017fff7fff", + "0x34", + "0x4824800180007ffd", + "0x2c88", + "0x400080007ff17fff", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", - "0x48127ff97fff8000", - "0x48127ff97fff8000", + "0xc", + "0x400080007ffe7fff", "0x480680017fff8000", + "0x22", + "0x400080017ffd7fff", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", + "0x482480017ffb8000", + "0x2", + "0x482480017feb8000", "0x1", "0x480680017fff8000", - "0x0", + "0x53656e644d657373616765546f4c31", + "0x400280007ffb7fff", + "0x400280017ffb7ffb", + "0x400280027ffb7fef", + "0x400280037ffb7ffc", + "0x400280047ffb7ffd", + "0x480280067ffb8000", + "0x20680017fff7fff", + "0xe", + "0x480280057ffb8000", + "0x40780017fff7fff", + "0x1", + "0x48127ffb7fff8000", + "0x48127ffd7fff8000", + "0x482680017ffb8000", + "0x7", "0x480680017fff8000", "0x0", + "0x48127ffb7fff8000", + "0x48127ffa7fff8000", + "0x208b7fff7fff7ffe", + "0x480280057ffb8000", + "0x48127ffc7fff8000", + "0x482480017ffe8000", + "0x64", + "0x482680017ffb8000", + "0x9", + "0x480680017fff8000", + "0x1", + "0x480280077ffb8000", + "0x480280087ffb8000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482680017ff78000", + "0x482480017fee8000", "0x1", - "0x480a7ff87fff8000", + "0x48127ff87fff8000", + "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x48127ff87fff8000", - "0x482480017ff78000", + "0x48127ffa7fff8000", + "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0xa0680017fff8000", - "0x7", - "0x482680017ff98000", - "0xfffffffffffffffffffffffffffff97a", - "0x400280007ff87fff", - "0x10780017fff7fff", - "0x20", - "0x4825800180007ff9", - "0x686", - "0x400280007ff87fff", - "0x482680017ff88000", + "0x40780017fff7fff", "0x1", - "0x48297ffc80007ffd", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0xf", - "0x480280007ffc8000", - "0x400280007ffb7fff", - "0x48127ffd7fff8000", + "0x480680017fff8000", + "0x4661696c656420746f20646573657269616c697a6520706172616d202331", + "0x400080007ffe7fff", "0x48127ffb7fff8000", - "0x480a7ffa7fff8000", - "0x482680017ffb8000", + "0x482480017ffb8000", + "0x686", + "0x480a7ffb7fff8000", + "0x480680017fff8000", "0x1", - "0x482680017ffc8000", + "0x48127ffa7fff8000", + "0x482480017ff98000", "0x1", - "0x480a7ffd7fff8000", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffe6", - "0x208b7fff7fff7ffe", - "0x48127ffe7fff8000", - "0x48127ffc7fff8000", - "0x480680017fff8000", - "0x0", - "0x480a7ffa7fff8000", - "0x480a7ffb7fff8000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482680017ff88000", + "0x482680017ff98000", "0x1", - "0x480a7ff97fff8000", + "0x482680017ffa8000", + "0x21b6", + "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x48127ffb7fff8000", - "0x482480017ffa8000", + "0x48127ffa7fff8000", + "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", "0xa0680017fff8000", "0x7", - "0x482680017ff98000", - "0xfffffffffffffffffffffffffffff97a", - "0x400280007ff87fff", + "0x482680017ffa8000", + "0x100000000000000000000000000000000", + "0x400280007ff67fff", "0x10780017fff7fff", - "0x20", - "0x4825800180007ff9", - "0x686", - "0x400280007ff87fff", - "0x482680017ff88000", + "0x6e", + "0x4825800180007ffa", + "0x0", + "0x400280007ff67fff", + "0x482680017ff68000", "0x1", - "0x48297ffa80007ffb", + "0x482480017ffe8000", + "0x1874", + "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xf", - "0x480280007ffa8000", - "0x400280007ffd7fff", - "0x48127ffd7fff8000", - "0x48127ffb7fff8000", - "0x482680017ffa8000", - "0x1", - "0x480a7ffb7fff8000", - "0x480a7ffc7fff8000", - "0x482680017ffd8000", - "0x1", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffe6", - "0x208b7fff7fff7ffe", - "0x48127ffe7fff8000", - "0x48127ffc7fff8000", - "0x480680017fff8000", - "0x0", - "0x480a7ffc7fff8000", - "0x480a7ffd7fff8000", - "0x208b7fff7fff7ffe", + "0x14", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4f7574206f6620676173", + "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", "0x400080007ffe7fff", - "0x482680017ff88000", - "0x1", + "0x48127ffb7fff8000", + "0x480a7ff77fff8000", + "0x480a7ff87fff8000", "0x480a7ff97fff8000", + "0x482480017ff88000", + "0x6ea", + "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x48127ffb7fff8000", - "0x482480017ffa8000", + "0x48127ff77fff8000", + "0x482480017ff68000", "0x1", "0x208b7fff7fff7ffe", - "0x40780017fff7fff", + "0x1104800180018000", + "0x3c20", + "0x482480017fff8000", + "0x3c1f", + "0x48127ffb7fff8000", + "0x480080007ffe8000", + "0x480080047fff8000", + "0x484480017fff8000", + "0x2", + "0x482480017fff8000", + "0x15c2c", + "0x480080057ffc8000", + "0x484480017fff8000", + "0x4", + "0x48307ffd7fff8000", + "0xa0680017fff8000", + "0x8", + "0x48307ffe80007ff7", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400080007fef7fff", + "0x10780017fff7fff", + "0x27", + "0x48307ffe80007ff7", + "0x400080007ff07fff", + "0x482480017ff08000", "0x1", - "0x480680017fff8000", - "0x0", - "0x400080007ffe7fff", - "0x48127ffe7fff8000", - "0x482480017ffd8000", + "0x480a7ff87fff8000", + "0x480a7ff97fff8000", + "0x480a7ff77fff8000", + "0x48127ffb7fff8000", + "0x1104800180018000", + "0x1d2f", + "0x20680017fff7ffd", + "0xf", + "0x40780017fff7fff", "0x1", - "0x480680017fff8000", - "0x456d69744576656e74", - "0x400280007ffc7fff", - "0x400380017ffc7ffb", - "0x400280027ffc7ffd", - "0x400280037ffc7ffe", - "0x400280047ffc7ffd", - "0x400280057ffc7ffe", - "0x480280077ffc8000", - "0x20680017fff7fff", - "0x59", - "0x480280067ffc8000", - "0x480680017fff8000", - "0x5265706c616365436c617373", - "0x400280087ffc7fff", - "0x400280097ffc7ffe", - "0x4003800a7ffc7ffd", - "0x4802800c7ffc8000", - "0x20680017fff7fff", - "0x45", - "0x4802800b7ffc8000", - "0x480680017fff8000", - "0x11", - "0x480680017fff8000", - "0x53656e644d657373616765546f4c31", - "0x4002800d7ffc7fff", - "0x4002800e7ffc7ffd", - "0x4002800f7ffc7ffe", - "0x400280107ffc7ff6", - "0x400280117ffc7ff7", - "0x480280137ffc8000", - "0x20680017fff7fff", - "0x2d", - "0x480280127ffc8000", + "0x48127ff77fff8000", + "0x48127ff97fff8000", + "0x48127ff67fff8000", + "0x48127ff67fff8000", + "0x48127ff77fff8000", + "0x480a7ffb7fff8000", "0x480680017fff8000", "0x0", + "0x48127ff87fff8000", + "0x48127ff77fff8000", + "0x208b7fff7fff7ffe", + "0x48127ff87fff8000", + "0x48127ffa7fff8000", + "0x48127ff77fff8000", + "0x48127ff77fff8000", + "0x482480017ff88000", + "0x64", + "0x480a7ffb7fff8000", "0x480680017fff8000", - "0x1275130f95dda36bcbb6e9d28796c1d7e10b6e9fd5ed083e0ede4b12f613528", - "0x480680017fff8000", - "0x11", - "0x480680017fff8000", - "0x53746f726167655772697465", - "0x400280147ffc7fff", - "0x400280157ffc7ffb", - "0x400280167ffc7ffc", - "0x400280177ffc7ffd", - "0x400280187ffc7ffe", - "0x4802801a7ffc8000", - "0x20680017fff7fff", - "0x11", + "0x1", + "0x48127ff77fff8000", + "0x48127ff77fff8000", + "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x746573745f7265766572745f68656c706572", + "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x480a7ffa7fff8000", - "0x480280197ffc8000", - "0x482680017ffc8000", - "0x1b", + "0x482480017fed8000", + "0x1", + "0x480a7ff77fff8000", + "0x480a7ff87fff8000", + "0x480a7ff97fff8000", + "0x48127fef7fff8000", + "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", + "0x48127ff77fff8000", + "0x482480017ff68000", "0x1", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0x2", - "0x480a7ffa7fff8000", - "0x480280197ffc8000", - "0x482680017ffc8000", - "0x1d", - "0x480680017fff8000", "0x1", - "0x4802801b7ffc8000", - "0x4802801c7ffc8000", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x8", - "0x480a7ffa7fff8000", - "0x480280127ffc8000", - "0x482680017ffc8000", - "0x16", "0x480680017fff8000", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x482680017ff68000", "0x1", - "0x480280147ffc8000", - "0x480280157ffc8000", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0xc", - "0x480a7ffa7fff8000", - "0x4802800b7ffc8000", - "0x482680017ffc8000", - "0xf", + "0x480a7ff77fff8000", + "0x480a7ff87fff8000", + "0x480a7ff97fff8000", + "0x482680017ffa8000", + "0x208a", + "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x4802800d7ffc8000", - "0x4802800e7ffc8000", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0xf", - "0x480a7ffa7fff8000", - "0x480280067ffc8000", - "0x482680017ffc8000", - "0xa", - "0x480680017fff8000", + "0x48127ff77fff8000", + "0x482480017ff68000", "0x1", - "0x480280087ffc8000", - "0x480280097ffc8000", "0x208b7fff7fff7ffe", "0xa0680017fff8000", "0x7", - "0x482680017ff68000", - "0xffffffffffffffffffffffffffffcb80", - "0x400280007ff57fff", + "0x482680017ffa8000", + "0x100000000000000000000000000000000", + "0x400280007ff87fff", "0x10780017fff7fff", - "0x56", - "0x4825800180007ff6", - "0x3480", - "0x400280007ff57fff", - "0x482680017ff58000", + "0x70", + "0x4825800180007ffa", + "0x0", + "0x400280007ff87fff", + "0x482680017ff88000", "0x1", - "0x48297ffb80007ff8", + "0x482480017ffe8000", + "0x1b94", + "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x43", + "0x12", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x456d69744576656e74", - "0x400280007ff77fff", - "0x400280017ff77ffc", - "0x400380027ff77ffc", - "0x400380037ff77ffd", - "0x400380047ff77ff9", - "0x400380057ff77ffa", - "0x480280077ff78000", - "0x20680017fff7fff", - "0x2f", + "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", + "0x400080007ffe7fff", + "0x48127ffb7fff8000", + "0x480a7ff97fff8000", + "0x482480017ffa8000", + "0x492", + "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x480280067ff78000", - "0x482680017ff78000", - "0x8", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0x1104800180018000", + "0x3b9c", + "0x482480017fff8000", + "0x3b9b", + "0x48127ffb7fff8000", + "0x480080007ffe8000", "0xa0680017fff8000", - "0x8", - "0x48327ffc7ff88000", - "0x4824800180007fff", - "0x10000000000000000", - "0x400080007ff67fff", + "0x9", + "0x4824800180007ffd", + "0x1864", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400080007ff57fff", "0x10780017fff7fff", - "0x13", - "0x48327ffc7ff88001", - "0x4824800180007fff", - "0xffffffffffffffff0000000000000000", - "0x400080007ff67ffe", - "0x482480017ff68000", + "0x35", + "0x4824800180007ffd", + "0x1864", + "0x400080007ff67fff", + "0x480a7ff97fff8000", + "0x1104800180018000", + "0x1ec0", + "0x482480017fe68000", "0x1", + "0x48127fee7fff8000", + "0x20680017fff7ffb", + "0x1a", "0x48127ffa7fff8000", - "0x48127ffa7fff8000", - "0x48127ffc7fff8000", - "0x480a7ff97fff8000", - "0x480a7ffa7fff8000", - "0x480a7ffb7fff8000", - "0x480a7ffc7fff8000", - "0x480a7ffd7fff8000", "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffca", - "0x208b7fff7fff7ffe", + "0x1eb8", + "0x48127fef7fff8000", + "0x20680017fff7ffc", + "0xe", "0x40780017fff7fff", "0x1", + "0x48127fec7fff8000", + "0x48127ff97fff8000", + "0x482480017ffc8000", + "0x190", + "0x480a7ffb7fff8000", "0x480680017fff8000", - "0x7536345f616464204f766572666c6f77", - "0x400080007ffe7fff", - "0x482480017ff48000", - "0x1", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x480680017fff8000", - "0x1", + "0x0", "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", + "0x48127ff97fff8000", "0x208b7fff7fff7ffe", - "0x48127ffc7fff8000", - "0x480280067ff78000", - "0x482680017ff78000", - "0xa", + "0x48127ffb7fff8000", + "0x48127ffe7fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x10780017fff7fff", + "0x9", + "0x40780017fff7fff", + "0x11", + "0x48127fe97fff8000", + "0x482480017fed8000", + "0xb56", + "0x48127fe97fff8000", + "0x48127fe97fff8000", + "0x48127fe97fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x480280087ff78000", - "0x480280097ff78000", + "0x48127ff97fff8000", + "0x48127ff97fff8000", "0x208b7fff7fff7ffe", - "0x48127ffe7fff8000", - "0x48127ffc7fff8000", - "0x480a7ff77fff8000", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x482480017ff38000", + "0x1", + "0x480a7ff97fff8000", + "0x48127ff77fff8000", + "0x480a7ffb7fff8000", "0x480680017fff8000", - "0x0", - "0x480a7ff87fff8000", + "0x1", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482680017ff58000", + "0x482680017ff88000", "0x1", - "0x480a7ff67fff8000", - "0x480a7ff77fff8000", + "0x480a7ff97fff8000", + "0x482680017ffa8000", + "0x2152", + "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", + "0x48127ff97fff8000", + "0x482480017ff88000", "0x1", "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x2", + "0xa0680017fff8000", + "0x7", + "0x482680017ffa8000", + "0x100000000000000000000000000000000", + "0x400280007ff97fff", + "0x10780017fff7fff", + "0x106", + "0x4825800180007ffa", + "0x0", + "0x400280007ff97fff", + "0x482680017ff98000", + "0x1", + "0x482480017ffe8000", + "0x17c", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", + "0xb", + "0x48127ffe7fff8000", "0x482680017ffc8000", "0x1", "0x480a7ffd7fff8000", "0x480680017fff8000", "0x0", - "0x480a7ffc7fff8000", + "0x480280007ffc8000", "0x10780017fff7fff", - "0x8", + "0x9", + "0x48127ffe7fff8000", "0x480a7ffc7fff8000", "0x480a7ffd7fff8000", "0x480680017fff8000", @@ -7665,975 +7868,1792 @@ "0x480680017fff8000", "0x0", "0x20680017fff7ffe", - "0xac", - "0x480080007fff8000", - "0xa0680017fff8000", - "0x12", - "0x4824800180007ffe", - "0x10000000000000000", - "0x4844800180008002", - "0x8000000000000110000000000000000", - "0x4830800080017ffe", - "0x480280007ffb7fff", - "0x482480017ffe8000", - "0xefffffffffffffdeffffffffffffffff", - "0x480280017ffb7fff", - "0x400280027ffb7ffb", - "0x402480017fff7ffb", - "0xffffffffffffffffffffffffffffffff", - "0x20680017fff7fff", - "0x95", - "0x402780017fff7fff", - "0x1", - "0x400280007ffb7ffe", - "0x482480017ffe8000", - "0xffffffffffffffff0000000000000000", - "0x400280017ffb7fff", - "0x482680017ffb8000", - "0x2", - "0x48307ff880007ff9", + "0xd7", + "0x40137fff7fff8001", + "0x48127ffb7fff8000", + "0xa0680017fff8004", + "0xe", + "0x4825800180048001", + "0x800000000000000000000000000000000000000000000000000000000000000", + "0x484480017ffe8000", + "0x110000000000000000", + "0x48307ffe7fff8002", + "0x480080007ff37ffc", + "0x480080017ff27ffc", + "0x402480017ffb7ffd", + "0xffffffffffffffeeffffffffffffffff", + "0x400080027ff17ffd", + "0x10780017fff7fff", + "0xc1", + "0x484480017fff8001", + "0x8000000000000000000000000000000", + "0x48317fff80008001", + "0x480080007ff47ffd", + "0x480080017ff37ffd", + "0x402480017ffc7ffe", + "0xf8000000000000000000000000000000", + "0x400080027ff27ffe", + "0x482480017ff28000", + "0x3", + "0x48127ff97fff8000", + "0x48307ff480007ff5", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", - "0x482480017ff78000", - "0x1", - "0x48127ff77fff8000", - "0x480680017fff8000", - "0x0", - "0x48127ff47fff8000", - "0x10780017fff7fff", - "0x8", - "0x48127ff77fff8000", - "0x48127ff77fff8000", - "0x480680017fff8000", - "0x1", - "0x480680017fff8000", - "0x0", - "0x20680017fff7ffe", - "0x6a", - "0x480080007fff8000", - "0xa0680017fff8000", - "0x12", - "0x4824800180007ffe", - "0x10000000000000000", - "0x4844800180008002", - "0x8000000000000110000000000000000", - "0x4830800080017ffe", - "0x480080007ff57fff", - "0x482480017ffe8000", - "0xefffffffffffffdeffffffffffffffff", - "0x480080017ff37fff", - "0x400080027ff27ffb", - "0x402480017fff7ffb", - "0xffffffffffffffffffffffffffffffff", - "0x20680017fff7fff", - "0x53", - "0x402780017fff7fff", + "0xa2", + "0x400180007ff38000", + "0x482480017ff38000", "0x1", - "0x400080007ff87ffe", - "0x482480017ffe8000", - "0xffffffffffffffff0000000000000000", - "0x400080017ff77fff", - "0x482480017ff78000", - "0x2", - "0x48307ff880007ff9", + "0x48127ff37fff8000", + "0x48127ffc7fff8000", + "0x48307ffd80007ffe", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", - "0x482480017ff78000", + "0xb", + "0x48127ffe7fff8000", + "0x482480017ffb8000", "0x1", - "0x48127ff77fff8000", + "0x48127ffb7fff8000", "0x480680017fff8000", "0x0", - "0x480080007ff48000", + "0x48127ff87fff8000", "0x10780017fff7fff", - "0x8", - "0x48127ff77fff8000", - "0x48127ff77fff8000", + "0x9", + "0x48127ffe7fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", "0x480680017fff8000", "0x1", "0x480680017fff8000", "0x0", "0x20680017fff7ffe", - "0x28", - "0xa0680017fff8004", - "0xe", - "0x4824800180047ffe", - "0x800000000000000000000000000000000000000000000000000000000000000", - "0x484480017ffe8000", - "0x110000000000000000", - "0x48307ffe7fff8002", - "0x480080007ff67ffc", - "0x480080017ff57ffc", - "0x402480017ffb7ffd", - "0xffffffffffffffeeffffffffffffffff", - "0x400080027ff47ffd", + "0x75", + "0x40780017fff7fff", + "0x1", + "0x48127ff37fff8000", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x48127ffb7fff8000", + "0x48127ffa7fff8000", + "0x480080007ff88000", + "0x1104800180018000", + "0x5a0", + "0x20680017fff7ffa", + "0x5f", + "0x48127ff97fff8000", + "0x20680017fff7ffc", + "0x57", + "0x48127fff7fff8000", + "0x48307ff980007ffa", + "0x20680017fff7fff", + "0x4", "0x10780017fff7fff", - "0x16", - "0x484480017fff8001", - "0x8000000000000000000000000000000", - "0x48307fff80007ffd", - "0x480080007ff77ffd", - "0x480080017ff67ffd", - "0x402480017ffc7ffe", - "0xf8000000000000000000000000000000", - "0x400080027ff57ffe", + "0x11", "0x40780017fff7fff", "0x1", - "0x482480017ff48000", - "0x3", - "0x48127ff57fff8000", - "0x48127ff57fff8000", "0x480680017fff8000", - "0x0", - "0x48127fe47fff8000", - "0x48127fec7fff8000", + "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", + "0x400080007ffe7fff", "0x48127ff37fff8000", + "0x482480017ffb8000", + "0x492", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", "0x208b7fff7fff7ffe", - "0x482480017ff48000", - "0x3", + "0x1104800180018000", + "0x3ab1", + "0x482480017fff8000", + "0x3ab0", + "0x48127ffb7fff8000", + "0x480080007ffe8000", + "0xa0680017fff8000", + "0x9", + "0x4824800180007ffd", + "0x118dc", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400080007fed7fff", "0x10780017fff7fff", - "0x5", + "0x24", + "0x4824800180007ffd", + "0x118dc", + "0x400080007fee7fff", + "0x48127fff7fff8000", + "0x480a7ffb7fff8000", + "0x480a80017fff8000", + "0x480a80007fff8000", + "0x48127ff07fff8000", + "0x48127ff07fff8000", + "0x1104800180018000", + "0x1df1", + "0x482480017f9f8000", + "0x1", + "0x20680017fff7ffc", + "0xc", "0x40780017fff7fff", - "0x6", - "0x48127ff47fff8000", - "0x48127ff57fff8000", - "0x48127ff57fff8000", - "0x480680017fff8000", "0x1", + "0x48127ffe7fff8000", + "0x48127ff87fff8000", + "0x48127ff87fff8000", "0x480680017fff8000", "0x0", + "0x48127ffb7fff8000", + "0x48127ffa7fff8000", + "0x208b7fff7fff7ffe", + "0x48127fff7fff8000", + "0x482480017ff98000", + "0x64", + "0x48127ff97fff8000", "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", + "0x1", + "0x48127ff97fff8000", + "0x48127ff97fff8000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0x7", + "0x1", + "0x480680017fff8000", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", "0x482480017feb8000", - "0x3", - "0x10780017fff7fff", - "0x5", - "0x40780017fff7fff", - "0xf", - "0x48127feb7fff8000", - "0x48127fec7fff8000", - "0x48127fec7fff8000", + "0x1", + "0x48127ff87fff8000", + "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x48127ff77fff8000", + "0x482480017ffe8000", + "0x492", + "0x10780017fff7fff", + "0xe", + "0x48127ff87fff8000", + "0x482480017ff88000", + "0x7b2", + "0x480a7ffb7fff8000", "0x480680017fff8000", - "0x0", + "0x1", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x208b7fff7fff7ffe", + "0x48127ff47fff8000", + "0x482480017ffa8000", + "0x102c", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", + "0x4661696c656420746f20646573657269616c697a6520706172616d202333", + "0x400080007ffe7fff", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", + "0x480a7ffb7fff8000", "0x480680017fff8000", - "0x0", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0x10", - "0x482680017ffb8000", + "0x1", + "0x480680017fff8000", + "0x4661696c656420746f20646573657269616c697a6520706172616d202332", + "0x400080007ffe7fff", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x159a", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x482480017ff18000", "0x3", + "0x482480017ff88000", + "0x159a", "0x10780017fff7fff", "0x5", + "0x48127ff87fff8000", + "0x482480017ffa8000", + "0x1b12", "0x40780017fff7fff", - "0x18", + "0x1", + "0x480680017fff8000", + "0x4661696c656420746f20646573657269616c697a6520706172616d202331", + "0x400080007ffe7fff", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", "0x480a7ffb7fff8000", - "0x48127fe37fff8000", - "0x48127fe37fff8000", "0x480680017fff8000", "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x482680017ff98000", + "0x1", + "0x482680017ffa8000", + "0x213e", + "0x480a7ffb7fff8000", "0x480680017fff8000", - "0x0", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x8", + "0xa0680017fff8000", + "0x7", + "0x482680017ffa8000", + "0x100000000000000000000000000000000", + "0x400280007ff97fff", + "0x10780017fff7fff", + "0x65", + "0x4825800180007ffa", + "0x0", + "0x400280007ff97fff", + "0x482680017ff98000", + "0x1", + "0x482480017ffe8000", + "0x19a0", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x44b", - "0x400380007ffc8003", + "0x4a", "0x482680017ffc8000", "0x1", "0x480a7ffd7fff8000", - "0x48307ffe80007fff", + "0x48127ffc7fff8000", + "0x480280007ffc8000", + "0x48307ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", - "0x482480017ffd8000", + "0x11", + "0x40780017fff7fff", "0x1", - "0x48127ffd7fff8000", "0x480680017fff8000", - "0x0", - "0x480080007ffa8000", - "0x10780017fff7fff", - "0x8", - "0x48127ffd7fff8000", - "0x48127ffd7fff8000", + "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", + "0x400080007ffe7fff", + "0x48127ff67fff8000", + "0x482480017ffa8000", + "0x492", + "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x480680017fff8000", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x1104800180018000", + "0x39f0", + "0x482480017fff8000", + "0x39ef", + "0x48127ffa7fff8000", + "0x480080007ffe8000", + "0xa0680017fff8000", + "0x9", + "0x4824800180007ffd", "0x0", - "0x20680017fff7ffe", - "0x405", - "0x40137fff7fff8002", - "0xa0680017fff8004", - "0xe", - "0x4825800180048002", - "0x800000000000000000000000000000000000000000000000000000000000000", - "0x484480017ffe8000", - "0x110000000000000000", - "0x48307ffe7fff8002", - "0x480280007ffa7ffc", - "0x480280017ffa7ffc", - "0x402480017ffb7ffd", - "0xffffffffffffffeeffffffffffffffff", - "0x400280027ffa7ffd", - "0x10780017fff7fff", - "0x3f2", - "0x484480017fff8001", - "0x8000000000000000000000000000000", - "0x48317fff80008002", - "0x480280007ffa7ffd", - "0x480280017ffa7ffd", - "0x402480017ffc7ffe", - "0xf8000000000000000000000000000000", - "0x400280027ffa7ffe", - "0x482680017ffa8000", - "0x3", - "0x48307ff680007ff7", - "0x20680017fff7fff", - "0x4", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400080007ff07fff", "0x10780017fff7fff", - "0xa", - "0x482480017ff58000", + "0x13", + "0x4824800180007ffd", + "0x0", + "0x400080007ff17fff", + "0x40780017fff7fff", "0x1", - "0x48127ff57fff8000", + "0x400080007fff7ff6", + "0x482480017ff08000", + "0x1", + "0x482480017ffd8000", + "0x12c", + "0x480a7ffb7fff8000", "0x480680017fff8000", "0x0", - "0x48127ff27fff8000", - "0x10780017fff7fff", - "0x8", - "0x48127ff57fff8000", - "0x48127ff57fff8000", + "0x48127ffb7fff8000", + "0x482480017ffa8000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x482480017fee8000", "0x1", + "0x48127ff87fff8000", + "0x480a7ffb7fff8000", "0x480680017fff8000", - "0x0", - "0x20680017fff7ffe", - "0x3a6", - "0x400180007fff8000", - "0xa0680017fff8000", - "0x16", - "0x480080007ff98003", - "0x480080017ff88003", - "0x4844800180017ffe", - "0x100000000000000000000000000000000", - "0x483180017ffd8000", - "0x482480017fff7ffd", - "0x800000000000010fffffffffffffffff7ffffffffffffef0000000000000001", - "0x20680017fff7ffc", - "0x6", - "0x402480017fff7ffd", - "0xffffffffffffffffffffffffffffffff", - "0x10780017fff7fff", - "0x4", - "0x402480017ffe7ffd", - "0xf7ffffffffffffef0000000000000000", - "0x400080027ff47ffd", - "0x20680017fff7ffe", - "0x38d", - "0x402780017fff7fff", "0x1", - "0x400180007ff98000", + "0x48127ffa7fff8000", "0x482480017ff98000", "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4661696c656420746f20646573657269616c697a6520706172616d202331", + "0x400080007ffe7fff", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x686", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", "0x48127ffa7fff8000", - "0x48127ffa7fff8000", - "0x1104800180018000", - "0x131a", - "0x20680017fff7ffa", - "0x357", - "0x20680017fff7ffd", - "0x32a", - "0x40137ffe7fff8005", - "0x40137fff7fff8006", - "0x48307ffb80007ffc", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x2f8", - "0x482480017ffa8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x482680017ff98000", + "0x1", + "0x482680017ffa8000", + "0x21b6", + "0x480a7ffb7fff8000", + "0x480680017fff8000", "0x1", "0x48127ffa7fff8000", - "0x400180007ff88007", - "0x48307ffe80007fff", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x2c4", - "0x482480017ffd8000", + "0x482480017ff98000", "0x1", - "0x48127ffd7fff8000", - "0x400180007ffb8004", - "0x48307ffe80007fff", - "0x20680017fff7fff", - "0x4", + "0x208b7fff7fff7ffe", + "0xa0680017fff8000", + "0x7", + "0x482680017ffa8000", + "0x100000000000000000000000000000000", + "0x400280007ff97fff", "0x10780017fff7fff", - "0x290", - "0x400180007ffd8001", - "0x482480017ffd8000", + "0x4a", + "0x4825800180007ffa", + "0x0", + "0x400280007ff97fff", + "0x482680017ff98000", "0x1", - "0x48127ffd7fff8000", - "0x48307ffe80007fff", + "0x482480017ffe8000", + "0x1bf8", + "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", - "0x482480017ffd8000", + "0x11", + "0x40780017fff7fff", "0x1", - "0x48127ffd7fff8000", - "0x480680017fff8000", - "0x0", - "0x48127ffa7fff8000", - "0x10780017fff7fff", - "0x8", - "0x48127ffd7fff8000", - "0x48127ffd7fff8000", "0x480680017fff8000", - "0x1", + "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", + "0x400080007ffe7fff", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x492", + "0x480a7ffb7fff8000", "0x480680017fff8000", - "0x0", - "0x20680017fff7ffe", - "0x248", - "0x40780017fff7fff", "0x1", - "0x48127fea7fff8000", - "0x480a7ffb7fff8000", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x48127ffb7fff8000", "0x48127ffa7fff8000", - "0x480080007ff88000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", "0x1104800180018000", - "0x1392", - "0x20680017fff7ffa", - "0x210", - "0x20680017fff7ffd", - "0xa", - "0x48127ffb7fff8000", + "0x3980", + "0x482480017fff8000", + "0x397f", "0x48127ffb7fff8000", - "0x480680017fff8000", + "0x480080007ffe8000", + "0xa0680017fff8000", + "0x9", + "0x4824800180007ffd", "0x0", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400080007ff57fff", "0x10780017fff7fff", - "0xa", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", - "0x480680017fff8000", + "0x11", + "0x4824800180007ffd", + "0x0", + "0x400080007ff67fff", + "0x40780017fff7fff", "0x1", + "0x482480017ff58000", + "0x1", + "0x482480017ffd8000", + "0x190", + "0x480a7ffb7fff8000", "0x480680017fff8000", "0x0", + "0x48127ffb7fff8000", + "0x48127ffa7fff8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", - "0x20680017fff7ffd", - "0x1f6", - "0x48307ffb80007ffc", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0xa", - "0x482480017ffa8000", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x482480017ff38000", "0x1", - "0x48127ffa7fff8000", + "0x48127ff87fff8000", + "0x480a7ffb7fff8000", "0x480680017fff8000", - "0x0", - "0x48127ff77fff8000", - "0x10780017fff7fff", - "0x8", - "0x48127ffa7fff8000", + "0x1", "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x482680017ff98000", "0x1", + "0x482680017ffa8000", + "0x21b6", + "0x480a7ffb7fff8000", "0x480680017fff8000", - "0x0", - "0x20680017fff7ffe", - "0x1b4", - "0x480080007fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", "0xa0680017fff8000", - "0x16", - "0x480080007fec8003", - "0x480080017feb8003", - "0x4844800180017ffe", + "0x7", + "0x482680017ffa8000", "0x100000000000000000000000000000000", - "0x483080017ffd7ffb", - "0x482480017fff7ffd", - "0x800000000000010fffffffffffffffff7ffffffffffffef0000000000000001", - "0x20680017fff7ffc", - "0x6", - "0x402480017fff7ffd", - "0xffffffffffffffffffffffffffffffff", + "0x400280007ff87fff", "0x10780017fff7fff", - "0x4", - "0x402480017ffe7ffd", - "0xf7ffffffffffffef0000000000000000", - "0x400080027fe77ffd", - "0x20680017fff7ffe", - "0x19b", - "0x402780017fff7fff", - "0x1", - "0x400080007fec7ffe", - "0x482480017fec8000", + "0x54", + "0x4825800180007ffa", + "0x0", + "0x400280007ff87fff", + "0x482680017ff88000", "0x1", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x1104800180018000", - "0x1290", - "0x20680017fff7ffa", - "0x165", - "0x20680017fff7ffd", - "0x138", - "0x48307ffb80007ffc", + "0x482480017ffe8000", + "0x1acc", + "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", - "0x482480017ffa8000", + "0x12", + "0x40780017fff7fff", "0x1", - "0x48127ffa7fff8000", "0x480680017fff8000", + "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", + "0x400080007ffe7fff", + "0x48127ffb7fff8000", + "0x480a7ff97fff8000", + "0x482480017ffa8000", + "0x55a", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0x1104800180018000", + "0x3920", + "0x482480017fff8000", + "0x391f", + "0x48127ffb7fff8000", + "0x480080007ffe8000", + "0x480080017fff8000", + "0x482480017fff8000", "0x0", - "0x48127ff77fff8000", - "0x10780017fff7fff", + "0xa0680017fff8000", "0x8", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", + "0x48307ffe80007ffb", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400080007ff37fff", + "0x10780017fff7fff", + "0x17", + "0x48307ffe80007ffb", + "0x400080007ff47fff", "0x480680017fff8000", "0x1", "0x480680017fff8000", - "0x0", - "0x20680017fff7ffe", - "0xf6", - "0x480080007fff8000", - "0xa0680017fff8000", - "0x12", - "0x4824800180007ffe", - "0x100000000", - "0x4844800180008002", - "0x8000000000000110000000000000000", - "0x4830800080017ffe", - "0x480080007fef7fff", - "0x482480017ffe8000", - "0xefffffffffffffde00000000ffffffff", - "0x480080017fed7fff", - "0x400080027fec7ffb", - "0x402480017fff7ffb", - "0xffffffffffffffffffffffffffffffff", - "0x20680017fff7fff", - "0xe1", - "0x402780017fff7fff", + "0x2", + "0x400280007ff97ffe", + "0x400280017ff97fff", + "0x40780017fff7fff", "0x1", - "0x400080007ff27ffe", - "0x482480017ffe8000", - "0xffffffffffffffffffffffff00000000", - "0x400080017ff17fff", "0x482480017ff18000", - "0x2", - "0x48307ff880007ff9", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0xa", - "0x482480017ff78000", "0x1", - "0x48127ff77fff8000", + "0x482680017ff98000", + "0x5", + "0x48127ffa7fff8000", + "0x480a7ffb7fff8000", "0x480680017fff8000", "0x0", - "0x48127ff47fff8000", - "0x10780017fff7fff", - "0x8", - "0x48127ff77fff8000", - "0x48127ff77fff8000", + "0x48127ffa7fff8000", + "0x48127ff97fff8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x482480017ff18000", "0x1", + "0x480a7ff97fff8000", + "0x48127ff57fff8000", + "0x480a7ffb7fff8000", "0x480680017fff8000", - "0x0", - "0x20680017fff7ffe", - "0x97", - "0x480080007fff8000", - "0xa0680017fff8000", - "0x12", - "0x4824800180007ffe", - "0x100000000", - "0x4844800180008002", - "0x8000000000000110000000000000000", - "0x4830800080017ffe", - "0x480080007ff57fff", - "0x482480017ffe8000", - "0xefffffffffffffde00000000ffffffff", - "0x480080017ff37fff", - "0x400080027ff27ffb", - "0x402480017fff7ffb", - "0xffffffffffffffffffffffffffffffff", - "0x20680017fff7fff", - "0x82", - "0x402780017fff7fff", "0x1", - "0x400080007ff87ffe", - "0x482480017ffe8000", - "0xffffffffffffffffffffffff00000000", - "0x400080017ff77fff", - "0x482480017ff78000", - "0x2", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x1104800180018000", - "0x122c", - "0x20680017fff7ffa", - "0x49", - "0x20680017fff7ffd", - "0x1c", "0x48127ff97fff8000", - "0x48127f917fff8000", - "0x480680017fff8000", - "0x0", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x480680017fff8000", - "0x0", - "0x480a80037fff8000", - "0x480a80027fff8000", - "0x480a80007fff8000", - "0x480a80057fff8000", - "0x480a80067fff8000", - "0x480a80077fff8000", - "0x480a80047fff8000", - "0x480a80017fff8000", - "0x48127f8e7fff8000", - "0x48127f8e7fff8000", - "0x48127f937fff8000", - "0x48127fb77fff8000", - "0x48127fb77fff8000", - "0x48127fbc7fff8000", - "0x48127fc47fff8000", - "0x48127fe97fff8000", - "0x48127fe97fff8000", + "0x482480017ff88000", + "0x1", "0x208b7fff7fff7ffe", - "0x48127ff97fff8000", - "0x48127f917fff8000", - "0x480680017fff8000", - "0x0", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x480680017fff8000", + "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x482680017ff88000", + "0x1", + "0x480a7ff97fff8000", + "0x482680017ffa8000", + "0x2152", + "0x480a7ffb7fff8000", "0x480680017fff8000", + "0x1", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0xa0680017fff8000", + "0x7", + "0x482680017ffa8000", + "0x100000000000000000000000000000000", + "0x400280007ff97fff", + "0x10780017fff7fff", + "0x54", + "0x4825800180007ffa", "0x0", + "0x400280007ff97fff", + "0x482680017ff98000", + "0x1", + "0x482480017ffe8000", + "0x1acc", + "0x48297ffc80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x12", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", + "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", + "0x400080007ffe7fff", + "0x480a7ff87fff8000", + "0x48127ffa7fff8000", + "0x482480017ffa8000", + "0x55a", + "0x480a7ffb7fff8000", "0x480680017fff8000", - "0x0", - "0x208b7fff7fff7ffe", + "0x1", "0x48127ff97fff8000", - "0x48127f917fff8000", - "0x480680017fff8000", + "0x482480017ff88000", "0x1", - "0x480680017fff8000", + "0x208b7fff7fff7ffe", + "0x1104800180018000", + "0x38b6", + "0x482480017fff8000", + "0x38b5", + "0x48127ffb7fff8000", + "0x480080007ffe8000", + "0x480080007fff8000", + "0x482480017fff8000", "0x0", + "0xa0680017fff8000", + "0x8", + "0x48307ffe80007ffb", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400080007ff37fff", + "0x10780017fff7fff", + "0x17", + "0x48307ffe80007ffb", + "0x400080007ff47fff", "0x480680017fff8000", "0x0", "0x480680017fff8000", - "0x0", + "0x1", + "0x400280007ff87ffe", + "0x400280017ff87fff", + "0x40780017fff7fff", + "0x1", + "0x482680017ff88000", + "0x3", + "0x482480017ff08000", + "0x1", + "0x48127ffa7fff8000", + "0x480a7ffb7fff8000", "0x480680017fff8000", "0x0", + "0x48127ffa7fff8000", + "0x48127ff97fff8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x480a7ff87fff8000", + "0x482480017ff08000", + "0x1", + "0x48127ff57fff8000", + "0x480a7ffb7fff8000", "0x480680017fff8000", - "0x0", + "0x1", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x480a7ff87fff8000", + "0x482680017ff98000", + "0x1", + "0x482680017ffa8000", + "0x2152", + "0x480a7ffb7fff8000", "0x480680017fff8000", + "0x1", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0xa0680017fff8000", + "0x7", + "0x482680017ffa8000", + "0x100000000000000000000000000000000", + "0x400280007ff87fff", + "0x10780017fff7fff", + "0x5b", + "0x4825800180007ffa", "0x0", + "0x400280007ff87fff", + "0x482680017ff88000", + "0x1", + "0x482480017ffe8000", + "0x1acc", + "0x48297ffc80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x12", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", + "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", + "0x400080007ffe7fff", + "0x48127ffb7fff8000", + "0x480a7ff97fff8000", + "0x482480017ffa8000", + "0x55a", + "0x480a7ffb7fff8000", "0x480680017fff8000", - "0x0", + "0x1", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0x1104800180018000", + "0x384c", + "0x482480017fff8000", + "0x384b", + "0x48127ffb7fff8000", + "0x480080007ffe8000", + "0x480080037fff8000", + "0x482480017fff8000", + "0x190", + "0xa0680017fff8000", + "0x8", + "0x48307ffe80007ffb", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400080007ff37fff", + "0x10780017fff7fff", + "0x1e", + "0x48307ffe80007ffb", + "0x400080007ff47fff", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", + "0x482480017ffe8000", + "0x1", + "0x482480017ffe8000", + "0x1", "0x480680017fff8000", "0x0", + "0x400280007ff97ffd", + "0x400280017ff97ffe", + "0x400280027ff97fff", + "0x40780017fff7fff", + "0x1", + "0x482480017fee8000", + "0x1", + "0x482680017ff98000", + "0x6", + "0x48127ff77fff8000", + "0x480a7ffb7fff8000", "0x480680017fff8000", "0x0", + "0x48127ffa7fff8000", + "0x48127ff97fff8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x482480017ff18000", + "0x1", + "0x480a7ff97fff8000", + "0x48127ff57fff8000", + "0x480a7ffb7fff8000", "0x480680017fff8000", - "0x0", + "0x1", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x482680017ff88000", + "0x1", + "0x480a7ff97fff8000", + "0x482680017ffa8000", + "0x2152", + "0x480a7ffb7fff8000", "0x480680017fff8000", - "0x0", - "0x48127fe97fff8000", - "0x48127fe97fff8000", + "0x1", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", "0x208b7fff7fff7ffe", - "0x482480017ff28000", - "0x3", + "0xa0680017fff8000", + "0x7", + "0x482680017ffa8000", + "0x100000000000000000000000000000000", + "0x400280007ff87fff", "0x10780017fff7fff", - "0x5", + "0x85", + "0x4825800180007ffa", + "0x0", + "0x400280007ff87fff", + "0x482680017ff88000", + "0x1", + "0x482480017ffe8000", + "0x1acc", + "0x48297ffc80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x12", "0x40780017fff7fff", - "0x8", - "0x48127ff27fff8000", - "0x48127fb17fff8000", + "0x1", "0x480680017fff8000", - "0x0", - "0x48127ff17fff8000", - "0x48127ff17fff8000", + "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", + "0x400080007ffe7fff", + "0x48127ffb7fff8000", + "0x480a7ff97fff8000", + "0x482480017ffa8000", + "0x55a", + "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", "0x208b7fff7fff7ffe", - "0x482480017fec8000", - "0x3", - "0x10780017fff7fff", - "0x5", - "0x40780017fff7fff", + "0x1104800180018000", + "0x37db", + "0x482480017fff8000", + "0x37da", + "0x48127ffb7fff8000", + "0x480080007ffe8000", + "0x480080027fff8000", + "0x482480017fff8000", + "0x898", + "0xa0680017fff8000", "0x8", - "0x48127fec7fff8000", - "0x48127fba7fff8000", + "0x48307ffe80007ffb", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400080007ff37fff", + "0x10780017fff7fff", + "0x48", + "0x48307ffe80007ffb", + "0x400080007ff47fff", "0x480680017fff8000", - "0x0", - "0x48127ff17fff8000", - "0x48127ff17fff8000", + "0xbe96d72eb4f94078192c2e84d5230cde2a70f4b45c8797e2c907acff5060bb", "0x480680017fff8000", + "0x3c5906a3bc4858a3fc46f5d63a29ff95f31b816586c35b221405f884cb17bc3", + "0x482480017ff28000", "0x1", + "0x48127ffc7fff8000", + "0x48507ffd7ffd8000", + "0x48507ffb7ffb8001", + "0x48507ffa80008001", + "0x482480017ff98001", + "0x6f21413efbe40de150e596d72f7a8c5609ad26c15c915c1f4cdfcb99cee9e89", + "0x483080007fff7ffd", + "0x48307ffc80007ffb", + "0x20680017fff7fff", + "0x1f", + "0x4800800080068004", + "0x4800800180058004", + "0x4850800380037ffe", + "0x4850800180017ffe", + "0x485080007ffd7ffe", + "0x482480017fff7ffe", + "0x6f21413efbe40de150e596d72f7a8c5609ad26c15c915c1f4cdfcb99cee9e89", + "0x48307ffd7ffc7ffa", "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", + "0x2", + "0x48127fee7fff8000", + "0x48127fee7fff8000", + "0x400280007ff97ffa", + "0x400280017ff97ffb", + "0x400280027ff97ffe", + "0x400280037ff97fff", + "0x400280047ff97ffd", + "0x40780017fff7fff", + "0x1", + "0x48127fed7fff8000", + "0x482680017ff98000", + "0x7", + "0x48127fec7fff8000", + "0x480a7ffb7fff8000", "0x480680017fff8000", "0x0", + "0x48127ffa7fff8000", + "0x48127ff97fff8000", + "0x208b7fff7fff7ffe", + "0x1104800180018000", + "0x379b", + "0x482480017fff8000", + "0x379a", + "0x480080007fff8000", + "0x480080027fff8000", + "0x482480017fff8000", + "0x2bc", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", + "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x400080007ffe7fff", + "0x48127ff07fff8000", + "0x480a7ff97fff8000", + "0x48307ffb7fef8000", + "0x480a7ffb7fff8000", "0x480680017fff8000", - "0x0", + "0x1", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x482480017ff18000", + "0x1", + "0x480a7ff97fff8000", + "0x48127ff57fff8000", + "0x480a7ffb7fff8000", "0x480680017fff8000", - "0x0", + "0x1", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x482680017ff88000", + "0x1", + "0x480a7ff97fff8000", + "0x482680017ffa8000", + "0x2152", + "0x480a7ffb7fff8000", "0x480680017fff8000", + "0x1", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0xa0680017fff8000", + "0x7", + "0x482680017ffa8000", + "0x100000000000000000000000000000000", + "0x400280007ff97fff", + "0x10780017fff7fff", + "0x7d", + "0x4825800180007ffa", "0x0", + "0x400280007ff97fff", + "0x482680017ff98000", + "0x1", + "0x482480017ffe8000", + "0x17ac", + "0x48297ffc80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x62", + "0x482680017ffc8000", + "0x1", + "0x480a7ffd7fff8000", + "0x48127ffc7fff8000", + "0x48307ffd80007ffe", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x4a", + "0x482480017ffc8000", + "0x1", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", + "0x480080007ff98000", + "0x48307ffc80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x11", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", + "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", + "0x400080007ffe7fff", + "0x48127ff27fff8000", + "0x482480017ffa8000", + "0x492", + "0x480a7ffb7fff8000", "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x1104800180018000", + "0x372e", + "0x482480017fff8000", + "0x372d", + "0x48127ffa7fff8000", + "0x480080007ffe8000", + "0xa0680017fff8000", + "0x9", + "0x4824800180007ffd", "0x0", - "0x480680017fff8000", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400080007fec7fff", + "0x10780017fff7fff", + "0x13", + "0x4824800180007ffd", "0x0", + "0x400080007fed7fff", + "0x40780017fff7fff", + "0x1", + "0x400080007fff7ff6", + "0x482480017fec8000", + "0x1", + "0x482480017ffd8000", + "0x12c", + "0x480a7ffb7fff8000", "0x480680017fff8000", "0x0", + "0x48127ffb7fff8000", + "0x482480017ffa8000", + "0x1", "0x208b7fff7fff7ffe", - "0x48127ff97fff8000", - "0x48127fc77fff8000", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", - "0x48127ff87fff8000", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x482480017fea8000", + "0x1", "0x48127ff87fff8000", + "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", + "0x4661696c656420746f20646573657269616c697a6520706172616d202332", + "0x400080007ffe7fff", + "0x48127ff77fff8000", + "0x482480017ffb8000", + "0x686", + "0x480a7ffb7fff8000", "0x480680017fff8000", - "0x0", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", "0x208b7fff7fff7ffe", - "0x48127ff97fff8000", - "0x48127fc77fff8000", - "0x480680017fff8000", + "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", + "0x4661696c656420746f20646573657269616c697a6520706172616d202331", + "0x400080007ffe7fff", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x87a", + "0x480a7ffb7fff8000", "0x480680017fff8000", - "0x0", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x482680017ff98000", + "0x1", + "0x482680017ffa8000", + "0x21b6", + "0x480a7ffb7fff8000", "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0xa0680017fff8000", + "0x7", + "0x482680017ffa8000", + "0x100000000000000000000000000000000", + "0x400280007ff97fff", + "0x10780017fff7fff", + "0xdf", + "0x4825800180007ffa", "0x0", + "0x400280007ff97fff", + "0x482680017ff98000", + "0x1", + "0x482480017ffe8000", + "0xf6e", + "0x48297ffc80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xc4", + "0x482680017ffc8000", + "0x1", + "0x480a7ffd7fff8000", + "0x48127ffc7fff8000", + "0x48307ffd80007ffe", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xb", + "0x48127ffe7fff8000", + "0x482480017ffb8000", + "0x1", + "0x48127ffb7fff8000", "0x480680017fff8000", "0x0", + "0x480080007ff88000", + "0x10780017fff7fff", + "0x9", + "0x48127ffe7fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", "0x480680017fff8000", - "0x0", + "0x1", "0x480680017fff8000", "0x0", + "0x20680017fff7ffe", + "0x98", + "0x48127ffb7fff8000", + "0xa0680017fff8004", + "0xe", + "0x4824800180047ffd", + "0x800000000000000000000000000000000000000000000000000000000000000", + "0x484480017ffe8000", + "0x110000000000000000", + "0x48307ffe7fff8002", + "0x480080007fef7ffc", + "0x480080017fee7ffc", + "0x402480017ffb7ffd", + "0xffffffffffffffeeffffffffffffffff", + "0x400080027fed7ffd", + "0x10780017fff7fff", + "0x83", + "0x484480017fff8001", + "0x8000000000000000000000000000000", + "0x48307fff80007ffc", + "0x480080007ff07ffd", + "0x480080017fef7ffd", + "0x402480017ffc7ffe", + "0xf8000000000000000000000000000000", + "0x400080027fee7ffe", + "0x482480017fee8000", + "0x3", + "0x48127ff97fff8000", + "0x48307ff480007ff5", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x64", + "0x482480017ff38000", + "0x1", + "0x48127ff37fff8000", + "0x48127ffc7fff8000", + "0x480080007ff08000", + "0x48307ffc80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x11", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", + "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", + "0x400080007ffe7fff", + "0x48127ff67fff8000", + "0x482480017ffa8000", + "0x492", + "0x480a7ffb7fff8000", "0x480680017fff8000", - "0x0", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x1104800180018000", + "0x366b", + "0x482480017fff8000", + "0x366a", + "0x48127ffa7fff8000", + "0x480080007ffe8000", + "0xa0680017fff8000", + "0x9", + "0x4824800180007ffd", + "0x2a94", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400080007ff07fff", + "0x10780017fff7fff", + "0x2d", + "0x4824800180007ffd", + "0x2a94", + "0x400080007ff17fff", + "0x48127fff7fff8000", "0x480680017fff8000", "0x0", + "0x482480017fef8000", + "0x1", "0x480680017fff8000", - "0x0", + "0x53746f726167655772697465", + "0x400280007ffb7fff", + "0x400280017ffb7ffc", + "0x400280027ffb7ffd", + "0x400280037ffb7fe6", + "0x400280047ffb7ff3", + "0x480280067ffb8000", + "0x20680017fff7fff", + "0x10", + "0x480280057ffb8000", + "0x40780017fff7fff", + "0x1", + "0x400080007fff7ff0", + "0x48127ffb7fff8000", + "0x48127ffd7fff8000", + "0x482680017ffb8000", + "0x7", "0x480680017fff8000", "0x0", + "0x48127ffb7fff8000", + "0x482480017ffa8000", + "0x1", + "0x208b7fff7fff7ffe", + "0x480280057ffb8000", + "0x48127ffc7fff8000", + "0x482480017ffe8000", + "0xc8", + "0x482680017ffb8000", + "0x9", "0x480680017fff8000", - "0x0", + "0x1", + "0x480280077ffb8000", + "0x480280087ffb8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x482480017fee8000", + "0x1", + "0x48127ff87fff8000", + "0x480a7ffb7fff8000", "0x480680017fff8000", - "0x0", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", + "0x4661696c656420746f20646573657269616c697a6520706172616d202333", + "0x400080007ffe7fff", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x686", + "0x480a7ffb7fff8000", "0x480680017fff8000", - "0x0", - "0x48127fe97fff8000", - "0x48127fe97fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", "0x208b7fff7fff7ffe", - "0x482480017fe78000", + "0x482480017fed8000", "0x3", + "0x482480017ff88000", + "0x686", "0x10780017fff7fff", "0x5", + "0x48127ff47fff8000", + "0x482480017ffa8000", + "0xba4", "0x40780017fff7fff", - "0x7", - "0x48127fe77fff8000", - "0x48127fe77fff8000", - "0x480680017fff8000", - "0x0", - "0x48127ff27fff8000", - "0x48127ff27fff8000", - "0x480680017fff8000", "0x1", "0x480680017fff8000", - "0x0", + "0x4661696c656420746f20646573657269616c697a6520706172616d202332", + "0x400080007ffe7fff", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", + "0x480a7ffb7fff8000", "0x480680017fff8000", - "0x0", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", + "0x4661696c656420746f20646573657269616c697a6520706172616d202331", + "0x400080007ffe7fff", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x10b8", + "0x480a7ffb7fff8000", "0x480680017fff8000", - "0x0", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x482680017ff98000", + "0x1", + "0x482680017ffa8000", + "0x21b6", + "0x480a7ffb7fff8000", "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0xa0680017fff8000", + "0x7", + "0x482680017ffa8000", + "0x100000000000000000000000000000000", + "0x400280007ff97fff", + "0x10780017fff7fff", + "0x9b", + "0x4825800180007ffa", "0x0", + "0x400280007ff97fff", + "0x482680017ff98000", + "0x1", + "0x482480017ffe8000", + "0x1748", + "0x48297ffc80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x80", + "0x482680017ffc8000", + "0x1", + "0x480a7ffd7fff8000", + "0x48127ffc7fff8000", + "0x480280007ffc8000", + "0x48307ffc80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x67", + "0x482480017ffb8000", + "0x1", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x480080007ff88000", + "0x48307ffc80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x11", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", + "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", + "0x400080007ffe7fff", + "0x48127ff17fff8000", + "0x482480017ffa8000", + "0x492", + "0x480a7ffb7fff8000", "0x480680017fff8000", - "0x0", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x1104800180018000", + "0x35a7", + "0x482480017fff8000", + "0x35a6", + "0x48127ffa7fff8000", + "0x480080007ffe8000", + "0xa0680017fff8000", + "0x9", + "0x4824800180007ffd", + "0x2b5c", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400080007feb7fff", + "0x10780017fff7fff", + "0x30", + "0x4824800180007ffd", + "0x2b5c", + "0x400080007fec7fff", + "0x48127fff7fff8000", "0x480680017fff8000", "0x0", "0x480680017fff8000", - "0x0", + "0x1275130f95dda36bcbb6e9d28796c1d7e10b6e9fd5ed083e0ede4b12f613528", + "0x48307ff47fef8000", + "0x482480017fe88000", + "0x1", "0x480680017fff8000", - "0x0", + "0x53746f726167655772697465", + "0x400280007ffb7fff", + "0x400280017ffb7ffa", + "0x400280027ffb7ffb", + "0x400280037ffb7ffc", + "0x400280047ffb7ffd", + "0x480280067ffb8000", + "0x20680017fff7fff", + "0x10", + "0x480280057ffb8000", + "0x40780017fff7fff", + "0x1", + "0x400080007fff7fe9", + "0x48127ffb7fff8000", + "0x48127ffd7fff8000", + "0x482680017ffb8000", + "0x7", "0x480680017fff8000", "0x0", + "0x48127ffb7fff8000", + "0x482480017ffa8000", + "0x1", + "0x208b7fff7fff7ffe", + "0x480280057ffb8000", + "0x48127ffc7fff8000", + "0x482480017ffe8000", + "0xc8", + "0x482680017ffb8000", + "0x9", "0x480680017fff8000", - "0x0", + "0x1", + "0x480280077ffb8000", + "0x480280087ffb8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x482480017fe98000", + "0x1", + "0x48127ff87fff8000", + "0x480a7ffb7fff8000", "0x480680017fff8000", - "0x0", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", + "0x4661696c656420746f20646573657269616c697a6520706172616d202332", + "0x400080007ffe7fff", + "0x48127ff67fff8000", + "0x482480017ffa8000", + "0x686", + "0x480a7ffb7fff8000", "0x480680017fff8000", - "0x0", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", "0x208b7fff7fff7ffe", - "0x48127ff37fff8000", - "0x48127ff37fff8000", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x10780017fff7fff", - "0x31", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x480680017fff8000", + "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x0", + "0x4661696c656420746f20646573657269616c697a6520706172616d202331", + "0x400080007ffe7fff", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x8de", + "0x480a7ffb7fff8000", "0x480680017fff8000", - "0x0", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x482680017ff98000", + "0x1", + "0x482680017ffa8000", + "0x21b6", + "0x480a7ffb7fff8000", "0x480680017fff8000", - "0x0", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0xa0680017fff8000", + "0x7", + "0x482680017ff88000", + "0xfffffffffffffffffffffffffffff592", + "0x400280007ff77fff", + "0x10780017fff7fff", + "0x49", + "0x4825800180007ff8", + "0xa6e", + "0x400280007ff77fff", + "0x482680017ff78000", + "0x1", + "0x48127ffe7fff8000", + "0x20780017fff7ffd", + "0xe", + "0x48127ffe7fff8000", + "0x482480017ffe8000", + "0xad2", "0x480680017fff8000", "0x0", + "0x480a7ff97fff8000", + "0x480a7ffa7fff8000", "0x480680017fff8000", "0x0", + "0x480a7ffb7fff8000", + "0x480a7ffc7fff8000", + "0x208b7fff7fff7ffe", + "0x48127fff7fff8000", + "0x48297ff980007ffa", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xb", + "0x48127ffe7fff8000", + "0x482680017ff98000", + "0x1", + "0x480a7ffa7fff8000", "0x480680017fff8000", "0x0", + "0x480280007ff98000", + "0x10780017fff7fff", + "0x9", + "0x48127ffe7fff8000", + "0x480a7ff97fff8000", + "0x480a7ffa7fff8000", "0x480680017fff8000", - "0x0", + "0x1", "0x480680017fff8000", "0x0", + "0x20680017fff7ffe", + "0xf", + "0x400280007ffc7fff", + "0x48127ff77fff8000", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x480a7ffb7fff8000", + "0x482680017ffc8000", + "0x1", + "0x4825800180007ffd", + "0x1", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffc4", + "0x208b7fff7fff7ffe", + "0x48127ff77fff8000", + "0x482480017ffa8000", + "0x6ea", "0x480680017fff8000", "0x0", + "0x48127ff97fff8000", + "0x48127ff97fff8000", "0x480680017fff8000", - "0x0", + "0x1", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x482680017ff78000", + "0x1", + "0x480a7ff87fff8000", "0x480680017fff8000", - "0x0", + "0x1", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", - "0x48127fe97fff8000", - "0x48127fe97fff8000", + "0x48127ff87fff8000", + "0x482480017ff78000", + "0x1", "0x208b7fff7fff7ffe", - "0x48127feb7fff8000", - "0x480a7ffb7fff8000", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", + "0xa0680017fff8000", + "0x7", + "0x482680017ff98000", + "0xfffffffffffffffffffffffffffff916", + "0x400280007ff87fff", + "0x10780017fff7fff", + "0x22", + "0x4825800180007ff9", + "0x6ea", + "0x400280007ff87fff", + "0x482680017ff88000", + "0x1", + "0x48127ffe7fff8000", + "0x48297ffc80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xf", + "0x480280007ffc8000", + "0x400280007ffb7fff", "0x48127ffc7fff8000", "0x48127ffc7fff8000", + "0x480a7ffa7fff8000", + "0x482680017ffb8000", + "0x1", + "0x482680017ffc8000", + "0x1", + "0x480a7ffd7fff8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffe5", + "0x208b7fff7fff7ffe", + "0x48127ffd7fff8000", + "0x482480017ffd8000", + "0x686", "0x480680017fff8000", "0x0", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", - "0x480680017fff8000", + "0x480a7ffa7fff8000", + "0x480a7ffb7fff8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x0", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x482680017ff88000", + "0x1", + "0x480a7ff97fff8000", "0x480680017fff8000", - "0x0", + "0x1", + "0x48127ffb7fff8000", + "0x482480017ffa8000", + "0x1", + "0x208b7fff7fff7ffe", + "0xa0680017fff8000", + "0x7", + "0x482680017ff98000", + "0xfffffffffffffffffffffffffffff916", + "0x400280007ff87fff", + "0x10780017fff7fff", + "0x22", + "0x4825800180007ff9", + "0x6ea", + "0x400280007ff87fff", + "0x482680017ff88000", + "0x1", + "0x48127ffe7fff8000", + "0x48297ffa80007ffb", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xf", + "0x480280007ffa8000", + "0x400280007ffd7fff", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", + "0x482680017ffa8000", + "0x1", + "0x480a7ffb7fff8000", + "0x480a7ffc7fff8000", + "0x482680017ffd8000", + "0x1", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffe5", + "0x208b7fff7fff7ffe", + "0x48127ffd7fff8000", + "0x482480017ffd8000", + "0x686", "0x480680017fff8000", "0x0", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x482680017ff88000", + "0x1", + "0x480a7ff97fff8000", "0x480680017fff8000", - "0x0", + "0x1", + "0x48127ffb7fff8000", + "0x482480017ffa8000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", "0x0", + "0x400080007ffe7fff", + "0x48127ffe7fff8000", + "0x482480017ffd8000", + "0x1", "0x480680017fff8000", - "0x0", + "0x456d69744576656e74", + "0x400280007ffb7fff", + "0x400380017ffb7ffa", + "0x400280027ffb7ffd", + "0x400280037ffb7ffe", + "0x400280047ffb7ffd", + "0x400280057ffb7ffe", + "0x480280077ffb8000", + "0x20680017fff7fff", + "0x6f", + "0x480280067ffb8000", + "0x48127fff7fff8000", "0x480680017fff8000", - "0x0", + "0x5265706c616365436c617373", + "0x400280087ffb7fff", + "0x400280097ffb7ffe", + "0x4003800a7ffb7ffc", + "0x4802800c7ffb8000", + "0x20680017fff7fff", + "0x59", + "0x4802800b7ffb8000", + "0x48127fff7fff8000", "0x480680017fff8000", - "0x0", + "0x11", "0x480680017fff8000", - "0x0", + "0x53656e644d657373616765546f4c31", + "0x4002800d7ffb7fff", + "0x4002800e7ffb7ffd", + "0x4002800f7ffb7ffe", + "0x400280107ffb7ff4", + "0x400280117ffb7ff5", + "0x480280137ffb8000", + "0x20680017fff7fff", + "0x3f", + "0x480280127ffb8000", + "0x48127fff7fff8000", "0x480680017fff8000", "0x0", "0x480680017fff8000", - "0x0", + "0x1275130f95dda36bcbb6e9d28796c1d7e10b6e9fd5ed083e0ede4b12f613528", "0x480680017fff8000", - "0x0", + "0x11", "0x480680017fff8000", - "0x0", + "0x53746f726167655772697465", + "0x400280147ffb7fff", + "0x400280157ffb7ffb", + "0x400280167ffb7ffc", + "0x400280177ffb7ffd", + "0x400280187ffb7ffe", + "0x4802801a7ffb8000", + "0x20680017fff7fff", + "0x21", + "0x480280197ffb8000", + "0x482680017ffb8000", + "0x1b", + "0x48127ffe7fff8000", + "0x20780017fff7ffd", + "0xe", + "0x40780017fff7fff", + "0x2", + "0x482480017ffd8000", + "0xb4", + "0x48127ffb7fff8000", "0x480680017fff8000", "0x0", "0x480680017fff8000", @@ -8641,85 +9661,153 @@ "0x480680017fff8000", "0x0", "0x208b7fff7fff7ffe", - "0x48127ff27fff8000", - "0x480a7ffb7fff8000", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", + "0x746573745f7265766572745f68656c706572", + "0x400080007ffe7fff", + "0x48127ffd7fff8000", + "0x48127ffb7fff8000", "0x480680017fff8000", "0x1", + "0x48127ffb7fff8000", + "0x482480017ffa8000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x4", + "0x480280197ffb8000", + "0x482480017fff8000", + "0x1cc", + "0x482680017ffb8000", + "0x1d", "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", + "0x1", + "0x4802801b7ffb8000", + "0x4802801c7ffb8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0xb", + "0x480280127ffb8000", + "0x482480017fff8000", + "0x2daa", + "0x482680017ffb8000", + "0x16", "0x480680017fff8000", - "0x0", + "0x1", + "0x480280147ffb8000", + "0x480280157ffb8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x10", + "0x4802800b7ffb8000", + "0x482480017fff8000", + "0x58d4", + "0x482680017ffb8000", + "0xf", "0x480680017fff8000", - "0x0", + "0x1", + "0x4802800d7ffb8000", + "0x4802800e7ffb8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x14", + "0x480280067ffb8000", + "0x482480017fff8000", + "0x82dc", + "0x482680017ffb8000", + "0xa", "0x480680017fff8000", - "0x0", + "0x1", + "0x480280087ffb8000", + "0x480280097ffb8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", + "0x25ff849c52d40a7f29c9849fbe0064575d61c84ddc0ef562bf05bc599abe0ae", "0x480680017fff8000", - "0x0", + "0x43616c6c436f6e7472616374", + "0x400280007ffb7fff", + "0x400380017ffb7ffa", + "0x400380027ffb7ffc", + "0x400280037ffb7ffe", + "0x400280047ffb7ffd", + "0x400280057ffb7ffd", + "0x480280077ffb8000", + "0x20680017fff7fff", + "0x69", + "0x480280067ffb8000", + "0x40780017fff7fff", + "0x1", + "0x400180007fff7ffd", "0x480680017fff8000", - "0x0", + "0x1", + "0x400080017ffe7fff", + "0x48127ffd7fff8000", "0x480680017fff8000", - "0x0", + "0x1e4089d1f1349077b1970f9937c904e27c4582b49a60b6078946dba95bc3c08", + "0x48127ffc7fff8000", + "0x482480017ffb8000", + "0x2", "0x480680017fff8000", - "0x0", + "0x43616c6c436f6e7472616374", + "0x4002800a7ffb7fff", + "0x4002800b7ffb7ffb", + "0x4003800c7ffb7ffc", + "0x4002800d7ffb7ffc", + "0x4002800e7ffb7ffd", + "0x4002800f7ffb7ffe", + "0x480280117ffb8000", + "0x20680017fff7fff", + "0x14", + "0x40780017fff7fff", + "0xa", + "0x480280107ffb8000", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x208b7fff7fff7ffe", - "0x48127ff57fff8000", - "0x480a7ffb7fff8000", - "0x480680017fff8000", - "0x0", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", + "0x73686f756c645f70616e6963", + "0x400080007ffe7fff", + "0x482480017ffd8000", + "0x2c88", + "0x482680017ffb8000", + "0x14", "0x480680017fff8000", "0x1", + "0x48127ffb7fff8000", + "0x482480017ffa8000", + "0x1", + "0x208b7fff7fff7ffe", + "0x480280107ffb8000", + "0x48127fff7fff8000", "0x480680017fff8000", "0x0", "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", + "0x1275130f95dda36bcbb6e9d28796c1d7e10b6e9fd5ed083e0ede4b12f613528", "0x480680017fff8000", - "0x0", + "0x53746f7261676552656164", + "0x400280147ffb7fff", + "0x400280157ffb7ffc", + "0x400280167ffb7ffd", + "0x400280177ffb7ffe", + "0x480280197ffb8000", + "0x20680017fff7fff", + "0x24", + "0x480280187ffb8000", + "0x4802801a7ffb8000", + "0x4824800180007fff", + "0xa", + "0x482680017ffb8000", + "0x1b", + "0x48127ffc7fff8000", + "0x20680017fff7ffd", + "0xe", + "0x40780017fff7fff", + "0x2", + "0x482480017ffd8000", + "0xb4", + "0x48127ffb7fff8000", "0x480680017fff8000", "0x0", "0x480680017fff8000", @@ -8727,134 +9815,302 @@ "0x480680017fff8000", "0x0", "0x208b7fff7fff7ffe", - "0x48127ff87fff8000", - "0x480a7ffb7fff8000", - "0x480680017fff8000", - "0x0", - "0x48127ff77fff8000", - "0x48127ff77fff8000", - "0x480680017fff8000", + "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", + "0x57726f6e675f73746f726167655f76616c75652e", + "0x400080007ffe7fff", + "0x48127ffd7fff8000", + "0x48127ffb7fff8000", "0x480680017fff8000", - "0x0", + "0x1", + "0x48127ffb7fff8000", + "0x482480017ffa8000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x6", + "0x480280187ffb8000", + "0x482480017fff8000", + "0x280", + "0x482680017ffb8000", + "0x1c", "0x480680017fff8000", - "0x0", + "0x1", + "0x4802801a7ffb8000", + "0x4802801b7ffb8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x15", + "0x480280067ffb8000", + "0x482480017fff8000", + "0x5b5e", + "0x482680017ffb8000", + "0xa", "0x480680017fff8000", - "0x0", + "0x1", + "0x480280087ffb8000", + "0x480280097ffb8000", + "0x208b7fff7fff7ffe", + "0xa0680017fff8000", + "0x7", + "0x482680017ff68000", + "0xffffffffffffffffffffffffffffca54", + "0x400280007ff57fff", + "0x10780017fff7fff", + "0x5d", + "0x4825800180007ff6", + "0x35ac", + "0x400280007ff57fff", + "0x482680017ff58000", + "0x1", + "0x48127ffe7fff8000", + "0x48297ffb80007ff8", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x48", + "0x48127ffe7fff8000", "0x480680017fff8000", - "0x0", + "0x456d69744576656e74", + "0x400280007ff77fff", + "0x400280017ff77ffe", + "0x400380027ff77ffc", + "0x400380037ff77ffd", + "0x400380047ff77ff9", + "0x400380057ff77ffa", + "0x480280077ff78000", + "0x20680017fff7fff", + "0x31", + "0x480280067ff78000", "0x480680017fff8000", - "0x0", - "0x208b7fff7fff7ffe", + "0x1", + "0x482680017ff78000", + "0x8", + "0x48127ffd7fff8000", + "0xa0680017fff8000", + "0x8", + "0x48327ffc7ff88000", + "0x4824800180007fff", + "0x10000000000000000", + "0x400080007ff37fff", + "0x10780017fff7fff", + "0x13", + "0x48327ffc7ff88001", + "0x4824800180007fff", + "0xffffffffffffffff0000000000000000", + "0x400080007ff37ffe", + "0x482480017ff38000", + "0x1", + "0x48127ffb7fff8000", "0x48127ff97fff8000", + "0x48127ffc7fff8000", + "0x480a7ff97fff8000", + "0x480a7ffa7fff8000", "0x480a7ffb7fff8000", - "0x480680017fff8000", - "0x0", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x480680017fff8000", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffc7", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", + "0x7536345f616464204f766572666c6f77", + "0x400080007ffe7fff", + "0x482480017ff18000", + "0x1", + "0x482480017ff98000", + "0x5be", + "0x48127ff77fff8000", "0x480680017fff8000", - "0x0", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", "0x208b7fff7fff7ffe", + "0x480280067ff78000", "0x48127ff97fff8000", - "0x480a7ffb7fff8000", + "0x482480017ffe8000", + "0xa50", + "0x482680017ff78000", + "0xa", "0x480680017fff8000", "0x1", + "0x480280087ff78000", + "0x480280097ff78000", + "0x208b7fff7fff7ffe", + "0x48127ffd7fff8000", + "0x482480017ffd8000", + "0x3548", + "0x480a7ff77fff8000", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", + "0x480a7ff87fff8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x482680017ff58000", + "0x1", + "0x480a7ff67fff8000", + "0x480a7ff77fff8000", "0x480680017fff8000", - "0x0", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x48297ffc80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xa", + "0x482680017ffc8000", + "0x1", + "0x480a7ffd7fff8000", "0x480680017fff8000", "0x0", + "0x480a7ffc7fff8000", + "0x10780017fff7fff", + "0x8", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", "0x480680017fff8000", - "0x0", + "0x1", "0x480680017fff8000", "0x0", + "0x20680017fff7ffe", + "0xac", + "0x480080007fff8000", + "0xa0680017fff8000", + "0x12", + "0x4824800180007ffe", + "0x10000000000000000", + "0x4844800180008002", + "0x8000000000000110000000000000000", + "0x4830800080017ffe", + "0x480280007ffb7fff", + "0x482480017ffe8000", + "0xefffffffffffffdeffffffffffffffff", + "0x480280017ffb7fff", + "0x400280027ffb7ffb", + "0x402480017fff7ffb", + "0xffffffffffffffffffffffffffffffff", + "0x20680017fff7fff", + "0x95", + "0x402780017fff7fff", + "0x1", + "0x400280007ffb7ffe", + "0x482480017ffe8000", + "0xffffffffffffffff0000000000000000", + "0x400280017ffb7fff", + "0x482680017ffb8000", + "0x2", + "0x48307ff880007ff9", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xa", + "0x482480017ff78000", + "0x1", + "0x48127ff77fff8000", "0x480680017fff8000", "0x0", + "0x48127ff47fff8000", + "0x10780017fff7fff", + "0x8", + "0x48127ff77fff8000", + "0x48127ff77fff8000", "0x480680017fff8000", - "0x0", + "0x1", "0x480680017fff8000", "0x0", + "0x20680017fff7ffe", + "0x6a", + "0x480080007fff8000", + "0xa0680017fff8000", + "0x12", + "0x4824800180007ffe", + "0x10000000000000000", + "0x4844800180008002", + "0x8000000000000110000000000000000", + "0x4830800080017ffe", + "0x480080007ff57fff", + "0x482480017ffe8000", + "0xefffffffffffffdeffffffffffffffff", + "0x480080017ff37fff", + "0x400080027ff27ffb", + "0x402480017fff7ffb", + "0xffffffffffffffffffffffffffffffff", + "0x20680017fff7fff", + "0x53", + "0x402780017fff7fff", + "0x1", + "0x400080007ff87ffe", + "0x482480017ffe8000", + "0xffffffffffffffff0000000000000000", + "0x400080017ff77fff", + "0x482480017ff78000", + "0x2", + "0x48307ff880007ff9", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xa", + "0x482480017ff78000", + "0x1", + "0x48127ff77fff8000", "0x480680017fff8000", "0x0", + "0x480080007ff48000", + "0x10780017fff7fff", + "0x8", + "0x48127ff77fff8000", + "0x48127ff77fff8000", "0x480680017fff8000", - "0x0", + "0x1", "0x480680017fff8000", "0x0", + "0x20680017fff7ffe", + "0x28", + "0xa0680017fff8004", + "0xe", + "0x4824800180047ffe", + "0x800000000000000000000000000000000000000000000000000000000000000", + "0x484480017ffe8000", + "0x110000000000000000", + "0x48307ffe7fff8002", + "0x480080007ff67ffc", + "0x480080017ff57ffc", + "0x402480017ffb7ffd", + "0xffffffffffffffeeffffffffffffffff", + "0x400080027ff47ffd", + "0x10780017fff7fff", + "0x16", + "0x484480017fff8001", + "0x8000000000000000000000000000000", + "0x48307fff80007ffd", + "0x480080007ff77ffd", + "0x480080017ff67ffd", + "0x402480017ffc7ffe", + "0xf8000000000000000000000000000000", + "0x400080027ff57ffe", + "0x40780017fff7fff", + "0x1", + "0x482480017ff48000", + "0x3", + "0x48127ff57fff8000", + "0x48127ff57fff8000", "0x480680017fff8000", "0x0", - "0x48127fe97fff8000", - "0x48127fe97fff8000", + "0x48127fe47fff8000", + "0x48127fec7fff8000", + "0x48127ff37fff8000", "0x208b7fff7fff7ffe", "0x482480017ff48000", "0x3", @@ -8863,11 +10119,8 @@ "0x40780017fff7fff", "0x6", "0x48127ff47fff8000", - "0x480a7ffb7fff8000", - "0x480680017fff8000", - "0x0", - "0x48127ff37fff8000", - "0x48127ff37fff8000", + "0x48127ff57fff8000", + "0x48127ff57fff8000", "0x480680017fff8000", "0x1", "0x480680017fff8000", @@ -8876,28 +10129,20 @@ "0x0", "0x480680017fff8000", "0x0", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x7", + "0x482480017feb8000", + "0x3", + "0x10780017fff7fff", + "0x5", + "0x40780017fff7fff", + "0xf", + "0x48127feb7fff8000", + "0x48127fec7fff8000", + "0x48127fec7fff8000", "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", + "0x1", "0x480680017fff8000", "0x0", "0x480680017fff8000", @@ -8905,18 +10150,17 @@ "0x480680017fff8000", "0x0", "0x208b7fff7fff7ffe", - "0x482680017ffa8000", + "0x40780017fff7fff", + "0x10", + "0x482680017ffb8000", "0x3", "0x10780017fff7fff", "0x5", "0x40780017fff7fff", - "0x6", - "0x480a7ffa7fff8000", + "0x18", "0x480a7ffb7fff8000", - "0x480680017fff8000", - "0x0", - "0x48127ff37fff8000", - "0x48127ff37fff8000", + "0x48127fe37fff8000", + "0x48127fe37fff8000", "0x480680017fff8000", "0x1", "0x480680017fff8000", @@ -8925,856 +10169,455 @@ "0x0", "0x480680017fff8000", "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", "0x208b7fff7fff7ffe", - "0x480a7ffa7fff8000", - "0x480a7ffb7fff8000", - "0x480680017fff8000", - "0x0", - "0x480a7ffc7fff8000", + "0x40780017fff7fff", + "0x8", + "0x48297ffc80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x489", + "0x400380007ffc8001", + "0x482680017ffc8000", + "0x1", "0x480a7ffd7fff8000", - "0x480680017fff8000", + "0x480a7ffb7fff8000", + "0x48307ffd80007ffe", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xb", + "0x48127ffe7fff8000", + "0x482480017ffb8000", "0x1", + "0x48127ffb7fff8000", "0x480680017fff8000", "0x0", + "0x480080007ff88000", + "0x10780017fff7fff", + "0x9", + "0x48127ffe7fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", + "0x1", "0x480680017fff8000", "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x15", - "0x480680017fff8000", - "0x476574457865637574696f6e496e666f", - "0x400280007fe67fff", - "0x400380017fe67fe5", - "0x480280037fe68000", - "0x20680017fff7fff", - "0x160", - "0x480280047fe68000", - "0x480080007fff8000", - "0x480080007fff8000", - "0x480080017ffe8000", - "0x480080027ffd8000", - "0x480280027fe68000", - "0x402780017fe68001", - "0x5", - "0x480080017ffa8000", - "0x400180027ff98000", - "0x400180037ff98003", - "0x400180047ff98002", - "0x48287fe780007ffb", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x6", - "0x40780017fff7fff", - "0x2", + "0x20680017fff7ffe", + "0x43f", + "0x40137fff7fff8002", + "0x48127ffb7fff8000", + "0xa0680017fff8004", + "0xe", + "0x4825800180048002", + "0x800000000000000000000000000000000000000000000000000000000000000", + "0x484480017ffe8000", + "0x110000000000000000", + "0x48307ffe7fff8002", + "0x480280007ffa7ffc", + "0x480280017ffa7ffc", + "0x402480017ffb7ffd", + "0xffffffffffffffeeffffffffffffffff", + "0x400280027ffa7ffd", "0x10780017fff7fff", - "0x9", - "0x48287fe880007ffb", + "0x429", + "0x484480017fff8001", + "0x8000000000000000000000000000000", + "0x48317fff80008002", + "0x480280007ffa7ffd", + "0x480280017ffa7ffd", + "0x402480017ffc7ffe", + "0xf8000000000000000000000000000000", + "0x400280027ffa7ffe", + "0x482680017ffa8000", + "0x3", + "0x48127ff97fff8000", + "0x48307ff480007ff5", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x6", - "0x40780017fff7fff", + "0xb", + "0x48127ffe7fff8000", + "0x482480017ff28000", "0x1", + "0x48127ff27fff8000", + "0x480680017fff8000", + "0x0", + "0x48127fef7fff8000", "0x10780017fff7fff", - "0x134", - "0x48287fe980007ffb", - "0x20680017fff7fff", - "0x131", - "0x400180007ffc8004", - "0x400180017ffc8005", - "0x400180027ffc8006", - "0x400180037ffc8007", - "0x400180047ffc8008", - "0x400180057ffc8009", - "0x400180067ffc800a", - "0x400180077ffc800b", - "0x400180087ffc800c", - "0x400180097ffc800d", - "0x4001800a7ffc800e", - "0x4001800b7ffc800f", - "0x4001800c7ffc8010", - "0x4001800d7ffc8011", - "0x4001800e7ffc8012", - "0x4001800f7ffc8013", - "0x400180107ffc8014", - "0x48297fea80008004", - "0x20680017fff7fff", - "0x10b", - "0x48297feb80008005", - "0x20680017fff7fff", - "0x104", - "0x48297fec80008006", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x103", - "0x4829800780008008", - "0x48297fed80007fee", - "0x48307fff80007ffe", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x6", - "0x480a7fe47fff8000", - "0x48127ff47fff8000", - "0x10780017fff7fff", - "0x10", - "0x480a7fe47fff8000", - "0x48127ff47fff8000", - "0x480a80077fff8000", - "0x480a80087fff8000", - "0x480a7fed7fff8000", - "0x480a7fee7fff8000", - "0x1104800180018000", - "0xfb9", - "0x20680017fff7ffa", - "0xdc", - "0x20680017fff7fff", + "0x9", + "0x48127ffe7fff8000", + "0x48127ff27fff8000", + "0x48127ff27fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x20680017fff7ffe", + "0x3d9", + "0x400180007fff8000", + "0x48127ffb7fff8000", + "0xa0680017fff8000", + "0x16", + "0x480080007ff68003", + "0x480080017ff58003", + "0x4844800180017ffe", + "0x100000000000000000000000000000000", + "0x483180017ffd8000", + "0x482480017fff7ffd", + "0x800000000000010fffffffffffffffff7ffffffffffffef0000000000000001", + "0x20680017fff7ffc", "0x6", - "0x48127ff87fff8000", - "0x48127ff87fff8000", + "0x402480017fff7ffd", + "0xffffffffffffffffffffffffffffffff", "0x10780017fff7fff", - "0xea", - "0x48297fef80008009", - "0x20680017fff7fff", - "0xcf", - "0x48297ff08000800a", - "0x20680017fff7fff", - "0xc8", - "0x48297ff18000800b", - "0x20680017fff7fff", - "0xc1", - "0x4829800c8000800d", - "0x48297ff280007ff3", - "0x4844800180007ffe", - "0x3", - "0x4844800180007ffe", - "0x3", - "0x48307fff80007ffe", - "0x20680017fff7fff", "0x4", - "0x10780017fff7fff", - "0x6", - "0x48127ff07fff8000", - "0x48127ff07fff8000", - "0x10780017fff7fff", - "0x10", - "0x48127ff07fff8000", - "0x48127ff07fff8000", - "0x480a800c7fff8000", - "0x480a800d7fff8000", - "0x480a7ff27fff8000", - "0x480a7ff37fff8000", + "0x402480017ffe7ffd", + "0xf7ffffffffffffef0000000000000000", + "0x400080027ff17ffd", + "0x20680017fff7ffe", + "0x3bd", + "0x402780017fff7fff", + "0x1", + "0x400180007ff68000", + "0x482480017ff68000", + "0x1", + "0x48127ff97fff8000", + "0x48127ff97fff8000", "0x1104800180018000", - "0x1005", - "0x20680017fff7ffa", - "0xa2", - "0x20680017fff7fff", - "0x6", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x10780017fff7fff", - "0xc2", - "0x48297ff48000800e", + "0x16a7", + "0x48127fd97fff8000", + "0x20680017fff7ff9", + "0x385", + "0x48127fff7fff8000", + "0x20680017fff7ffb", + "0x356", + "0x40137ffc7fff8005", + "0x40137ffd7fff8006", + "0x48127fff7fff8000", + "0x48307ff880007ff9", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x6", - "0x48127ff77fff8000", + "0x322", + "0x482480017ff78000", + "0x1", "0x48127ff77fff8000", - "0x10780017fff7fff", - "0xb9", - "0x4829800f80008010", - "0x48297ff580007ff6", - "0x48307fff80007ffe", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x6", - "0x48127ff47fff8000", - "0x48127ff47fff8000", - "0x10780017fff7fff", - "0x10", - "0x48127ff47fff8000", - "0x48127ff47fff8000", - "0x480a800f7fff8000", - "0x480a80107fff8000", - "0x480a7ff57fff8000", - "0x480a7ff67fff8000", - "0x1104800180018000", - "0xf6d", - "0x20680017fff7ffa", - "0x78", - "0x20680017fff7fff", - "0x6", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x10780017fff7fff", - "0x9e", - "0x48297ff780008011", + "0x48127ffc7fff8000", + "0x400180007ff48004", + "0x48307ffd80007ffe", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x6", - "0x48127ff77fff8000", - "0x48127ff77fff8000", - "0x10780017fff7fff", - "0x95", - "0x48297ff880008012", + "0x2ec", + "0x482480017ffc8000", + "0x1", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", + "0x400180007ff98003", + "0x48307ffd80007ffe", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x6", - "0x48127ff67fff8000", - "0x48127ff67fff8000", - "0x10780017fff7fff", - "0x8c", - "0x4829801380008014", - "0x48297ff980007ffa", - "0x48307fff80007ffe", + "0x2b6", + "0x400180007ffc8007", + "0x482480017ffc8000", + "0x1", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", + "0x48307ffd80007ffe", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x6", - "0x48127ff37fff8000", - "0x48127ff37fff8000", - "0x10780017fff7fff", - "0x81", - "0x48127ff37fff8000", - "0x48127ff37fff8000", - "0x480a80137fff8000", - "0x480a80147fff8000", - "0x480a7ff97fff8000", - "0x480a7ffa7fff8000", - "0x1104800180018000", - "0xf40", - "0x20680017fff7ffa", - "0x45", - "0x20680017fff7fff", - "0x6", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x10780017fff7fff", - "0x71", - "0x48297ffb80008000", - "0x20680017fff7fff", - "0x2e", - "0x48297ffc80008003", - "0x20680017fff7fff", - "0x1d", - "0x48297ffd80008002", - "0x20680017fff7fff", - "0xc", - "0x48127ff57fff8000", - "0x48127ff57fff8000", - "0x480a80017fff8000", + "0xb", + "0x48127ffe7fff8000", + "0x482480017ffb8000", + "0x1", + "0x48127ffb7fff8000", "0x480680017fff8000", "0x0", + "0x48127ff87fff8000", + "0x10780017fff7fff", + "0x9", + "0x48127ffe7fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", "0x480680017fff8000", - "0x0", + "0x1", "0x480680017fff8000", "0x0", - "0x208b7fff7fff7ffe", + "0x20680017fff7ffe", + "0x26a", "0x40780017fff7fff", "0x1", - "0x480680017fff8000", - "0x53454c4543544f525f4d49534d41544348", - "0x400080007ffe7fff", - "0x48127ff37fff8000", - "0x48127ff37fff8000", - "0x480a80017fff8000", - "0x480680017fff8000", - "0x1", + "0x48127fe37fff8000", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x48127ffb7fff8000", "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", + "0x480080007ff88000", + "0x1104800180018000", + "0x1717", + "0x20680017fff7ffa", + "0x231", + "0x48127ff97fff8000", + "0x20680017fff7ffc", + "0xb", + "0x48127fff7fff8000", + "0x48127ff97fff8000", + "0x48127ff97fff8000", "0x480680017fff8000", - "0x434f4e54524143545f4d49534d41544348", - "0x400080007ffe7fff", - "0x48127ff47fff8000", - "0x48127ff47fff8000", - "0x480a80017fff8000", + "0x0", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x10780017fff7fff", + "0xc", + "0x482480017fff8000", + "0x64", + "0x48127ff97fff8000", + "0x48127ff97fff8000", "0x480680017fff8000", "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", "0x480680017fff8000", - "0x43414c4c45525f4d49534d41544348", - "0x400080007ffe7fff", - "0x48127ff57fff8000", - "0x48127ff57fff8000", - "0x480a80017fff8000", + "0x0", "0x480680017fff8000", - "0x1", + "0x0", + "0x20680017fff7ffd", + "0x212", "0x48127ffa7fff8000", - "0x482480017ff98000", + "0x48307ffa80007ffb", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xb", + "0x48127ffe7fff8000", + "0x482480017ff88000", "0x1", - "0x208b7fff7fff7ffe", "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x48127ffc7fff8000", - "0x48127ffc7fff8000", + "0x480680017fff8000", + "0x0", + "0x48127ff57fff8000", "0x10780017fff7fff", - "0x1e", + "0x9", + "0x48127ffe7fff8000", "0x48127ff87fff8000", "0x48127ff87fff8000", - "0x48127ffc7fff8000", - "0x48127ffc7fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x20680017fff7ffe", + "0x1cc", + "0x480080007fff8000", + "0x48127ffa7fff8000", + "0xa0680017fff8000", + "0x16", + "0x480080007fe78003", + "0x480080017fe68003", + "0x4844800180017ffe", + "0x100000000000000000000000000000000", + "0x483080017ffd7ffa", + "0x482480017fff7ffd", + "0x800000000000010fffffffffffffffff7ffffffffffffef0000000000000001", + "0x20680017fff7ffc", + "0x6", + "0x402480017fff7ffd", + "0xffffffffffffffffffffffffffffffff", "0x10780017fff7fff", - "0x18", + "0x4", + "0x402480017ffe7ffd", + "0xf7ffffffffffffef0000000000000000", + "0x400080027fe27ffd", + "0x20680017fff7ffe", + "0x1b0", + "0x402780017fff7fff", + "0x1", + "0x400080007fe77ffd", + "0x482480017fe78000", + "0x1", "0x48127ff87fff8000", "0x48127ff87fff8000", - "0x48127ffc7fff8000", - "0x48127ffc7fff8000", + "0x1104800180018000", + "0x160d", + "0x48127fd97fff8000", + "0x20680017fff7ff9", + "0x178", + "0x48127fff7fff8000", + "0x20680017fff7ffb", + "0x149", + "0x48127fff7fff8000", + "0x48307ff880007ff9", + "0x20680017fff7fff", + "0x4", "0x10780017fff7fff", - "0x12", - "0x48127ff57fff8000", - "0x48127ff57fff8000", + "0xb", + "0x48127ffe7fff8000", + "0x482480017ff68000", + "0x1", + "0x48127ff67fff8000", + "0x480680017fff8000", + "0x0", + "0x48127ff37fff8000", "0x10780017fff7fff", - "0x1e", + "0x9", + "0x48127ffe7fff8000", "0x48127ff67fff8000", "0x48127ff67fff8000", - "0x10780017fff7fff", - "0x1a", - "0x48127ff77fff8000", - "0x48127ff77fff8000", - "0x10780017fff7fff", - "0x16", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x48127ffc7fff8000", - "0x48127ffc7fff8000", - "0x48127ffc7fff8000", - "0x48127ffc7fff8000", - "0x480a80017fff8000", "0x480680017fff8000", "0x1", + "0x480680017fff8000", + "0x0", + "0x20680017fff7ffe", + "0x103", + "0x480080007fff8000", "0x48127ffa7fff8000", - "0x48127ffa7fff8000", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", + "0xa0680017fff8000", + "0x12", + "0x4824800180007ffd", + "0x100000000", + "0x4844800180008002", + "0x8000000000000110000000000000000", + "0x4830800080017ffe", + "0x480080007fea7fff", + "0x482480017ffe8000", + "0xefffffffffffffde00000000ffffffff", + "0x480080017fe87fff", + "0x400080027fe77ffb", + "0x402480017fff7ffb", + "0xffffffffffffffffffffffffffffffff", + "0x20680017fff7fff", + "0xeb", + "0x402780017fff7fff", "0x1", - "0x10780017fff7fff", - "0x4", - "0x40780017fff7fff", + "0x400080007fed7ffd", + "0x482480017ffd8000", + "0xffffffffffffffffffffffff00000000", + "0x400080017fec7fff", + "0x482480017fec8000", "0x2", - "0x480a7fe47fff8000", - "0x48127ff77fff8000", - "0x40780017fff7fff", - "0x1", - "0x480680017fff8000", - "0x54585f494e464f5f4d49534d41544348", - "0x400080007ffe7fff", "0x48127ffc7fff8000", - "0x48127ffc7fff8000", - "0x480a80017fff8000", - "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", + "0x48307ff680007ff7", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xb", + "0x48127ffe7fff8000", + "0x482480017ff48000", "0x1", + "0x48127ff47fff8000", "0x480680017fff8000", - "0x424c4f434b5f494e464f5f4d49534d41544348", - "0x400080007ffe7fff", - "0x480a7fe47fff8000", - "0x48127ff87fff8000", - "0x480a80017fff8000", + "0x0", + "0x48127ff17fff8000", + "0x10780017fff7fff", + "0x9", + "0x48127ffe7fff8000", + "0x48127ff47fff8000", + "0x48127ff47fff8000", "0x480680017fff8000", "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", - "0x480a7fe47fff8000", - "0x480280027fe68000", - "0x482680017fe68000", - "0x6", - "0x480680017fff8000", - "0x1", - "0x480280047fe68000", - "0x480280057fe68000", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", - "0x400180007fff7ff9", - "0x400180017fff7ffb", - "0x480680017fff8000", - "0x2", - "0x400080027ffe7fff", - "0x482680017ffc8000", - "0x1", - "0x400080037ffd7fff", - "0x482680017ffd8000", - "0x1", - "0x400080047ffc7fff", - "0x48127ffc7fff8000", - "0x482480017ffb8000", - "0x5", "0x480680017fff8000", - "0x4c69627261727943616c6c", - "0x400280007ff87fff", - "0x400380017ff87ff7", - "0x400380027ff87ff9", - "0x400380037ff87ffa", - "0x400280047ff87ffd", - "0x400280057ff87ffe", - "0x480280077ff88000", + "0x0", + "0x20680017fff7ffe", + "0x9d", + "0x480080007fff8000", + "0x48127ffa7fff8000", + "0xa0680017fff8000", + "0x12", + "0x4824800180007ffd", + "0x100000000", + "0x4844800180008002", + "0x8000000000000110000000000000000", + "0x4830800080017ffe", + "0x480080007ff27fff", + "0x482480017ffe8000", + "0xefffffffffffffde00000000ffffffff", + "0x480080017ff07fff", + "0x400080027fef7ffb", + "0x402480017fff7ffb", + "0xffffffffffffffffffffffffffffffff", "0x20680017fff7fff", - "0x25", - "0x40780017fff7fff", + "0x85", + "0x402780017fff7fff", "0x1", - "0x400180007fff7ffc", - "0x400180017fff7ffd", - "0x480280067ff88000", - "0x48127ffe7fff8000", + "0x400080007ff57ffd", "0x482480017ffd8000", + "0xffffffffffffffffffffffff00000000", + "0x400080017ff47fff", + "0x482480017ff48000", "0x2", - "0x480680017fff8000", - "0x4c69627261727943616c6c", - "0x4002800a7ff87fff", - "0x4002800b7ff87ffc", - "0x4003800c7ff87ff9", - "0x4003800d7ff87ffb", - "0x4002800e7ff87ffd", - "0x4002800f7ff87ffe", - "0x480280117ff88000", - "0x20680017fff7fff", - "0xa", - "0x480280107ff88000", - "0x482680017ff88000", - "0x14", + "0x48127ff77fff8000", + "0x48127ff77fff8000", + "0x1104800180018000", + "0x159f", + "0x48127fd87fff8000", + "0x20680017fff7ff9", + "0x4a", + "0x48127fff7fff8000", + "0x20680017fff7ffb", + "0x1c", + "0x48127ff77fff8000", + "0x48127ffe7fff8000", "0x480680017fff8000", "0x0", - "0x480280127ff88000", - "0x480280137ff88000", - "0x208b7fff7fff7ffe", - "0x480280107ff88000", - "0x482680017ff88000", - "0x14", - "0x480680017fff8000", - "0x1", - "0x480280127ff88000", - "0x480280137ff88000", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x6", - "0x480280067ff88000", - "0x482680017ff88000", - "0xa", - "0x480680017fff8000", - "0x1", - "0x480280087ff88000", - "0x480280097ff88000", - "0x208b7fff7fff7ffe", - "0x480a7ffa7fff8000", - "0x480a7ffc7fff8000", - "0x480a7ffb7fff8000", - "0x480a7ffd7fff8000", - "0x1104800180018000", - "0x4", - "0x10780017fff7fff", - "0xb2", - "0x48037ffd7ffc8002", - "0x48037ffe7ffc8003", - "0x48037fff7ffc8004", - "0x480380007ffa8000", - "0x4825800180018003", - "0x1", - "0x4828800080018000", - "0x480280017ffa8000", - "0x4846800180008000", - "0x3", - "0x48327fff80028000", - "0x400180027fff8004", - "0x400180017fff7ffd", - "0x400380007ffc8002", - "0x400380017ffc8003", - "0x4826800180048000", - "0x1", - "0x400280027ffc7fff", - "0x482680017ffa8000", - "0x2", - "0x480080007ffd8000", - "0x480a7ffd7fff8000", - "0x40337ffe80017ffd", - "0x1104800180018000", - "0xf", - "0x48307fff80007ffe", - "0x48317fff80008001", - "0x4844800180007fff", - "0x3", - "0x484480017fff8000", - "0xfd2", - "0x48127ff97fff8000", - "0x48327ffe7ffb8000", - "0x482680017ffc8000", - "0x3", - "0x48127ff87fff8000", "0x48127ff67fff8000", - "0x208b7fff7fff7ffe", - "0x482b7ffc80007ffd", - "0x40780017fff7fff", - "0x3", - "0x20780017fff8000", - "0x6", - "0x480a7ffb7fff8000", - "0x480a80037fff8000", - "0x480a80037fff8000", - "0x208b7fff7fff7ffe", - "0x4845800180008000", - "0x3", - "0xa0780017fff8002", - "0x7", - "0x400380007ffb8001", - "0x402680017ffb7fff", - "0x1", - "0x10780017fff7fff", - "0x3", - "0x400a7ffb7fff7fff", - "0x480a7ffc7fff8000", - "0x4825800180007ffd", - "0x1", + "0x48127ff67fff8000", + "0x480680017fff8000", + "0x0", "0x480a80017fff8000", - "0x48127ffb7fff8000", - "0x480a80037fff8000", "0x480a80027fff8000", - "0x1104800180018000", - "0x4", + "0x480a80007fff8000", + "0x480a80057fff8000", + "0x480a80067fff8000", + "0x480a80047fff8000", "0x480a80037fff8000", + "0x480a80077fff8000", + "0x48127f817fff8000", + "0x48127f817fff8000", + "0x48127f887fff8000", + "0x48127fad7fff8000", + "0x48127fad7fff8000", + "0x48127fb67fff8000", + "0x48127fc17fff8000", + "0x48127fe77fff8000", + "0x48127fe77fff8000", "0x208b7fff7fff7ffe", - "0x480280007ff78002", - "0x4844800180018002", - "0x3", - "0x483280017ff88004", - "0x4800800280038004", - "0x482680017ff78004", - "0x1", - "0x4801800080017ffa", - "0x480380007ffc7ffa", - "0x480080017fff7ffd", - "0x480280017ffc7ffc", - "0x400680017fff7ffb", + "0x48127ff77fff8000", + "0x48127ffe7fff8000", + "0x480680017fff8000", "0x0", - "0x20680017fff7ffc", - "0xf", - "0x480080007fff8000", - "0x482480017fff8000", - "0x1", - "0x484480017fff8000", - "0x3", - "0x48307fff7ffa8001", - "0x4800800180007ffa", - "0x480080027fff8000", - "0x480180007ffe7ffa", - "0x402480017ff87fff", - "0x1", - "0x20680017fff7ffc", - "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffff6", - "0x48317ffd80007ff9", - "0x400080007ffe7fff", - "0x48287ff780007ffe", - "0x400280027ffc7ffc", - "0x40337fff80017ffb", - "0x20780017fff8001", - "0x7", - "0x482480017ffd8000", - "0x1", - "0x482680017ffc8000", - "0x3", - "0x208b7fff7fff7ffe", - "0x20780017fff7ffd", - "0xe", - "0x482680017ffa8000", - "0x1", - "0x48317fff80008000", - "0x400080017ffb7fff", - "0x482480017ffb8000", - "0x2", - "0x480a7ff87fff8000", - "0x480a7ff97fff8000", - "0x480a80007fff8000", - "0x480a80017fff8000", - "0x10780017fff7fff", - "0x32", - "0x4829800080007ffa", - "0x20680017fff7fff", - "0x4", - "0x402780017fff7fff", - "0x1", - "0x480080017ffc8000", - "0x480080027ffb8000", - "0x484480017fff8000", - "0x2aaaaaaaaaaaab05555555555555556", - "0x48307fff7ffd8000", - "0x480080037ff88000", - "0x480080047ff78000", - "0x484480017fff8000", - "0x4000000000000088000000000000001", - "0x48307fff7ffd8000", - "0x48307fff7ffb8000", - "0x48507ffe7ffa8000", - "0xa0680017fff8000", - "0xc", - "0x484680017ffa8000", - "0x800000000000011000000000000000000000000000000000000000000000000", - "0x402480017fff7ffc", - "0x800000000000011000000000000000000000000000000000000000000000000", - "0x4829800080007ffa", - "0x4826800180008000", - "0x1", - "0x40507fff7ffe7ffb", - "0x10780017fff7fff", - "0xf", - "0xa0680017fff8000", - "0xa", - "0x4846800180008000", - "0x800000000000011000000000000000000000000000000000000000000000000", - "0x482480017fff8000", - "0x800000000000011000000000000000000000000000000000000000000000000", - "0x40327fff7ffa7ffa", - "0x40527fff7ffa7ffb", - "0x10780017fff7fff", - "0x5", - "0x480a80007fff7ffc", - "0x48297ffa80008000", - "0x40527fff7ffa7ffb", - "0x482480017fee8000", - "0x5", - "0x480a7ff87fff8000", - "0x480a7ff97fff8000", - "0x480a80007fff8000", - "0x480a80017fff8000", - "0x482680017ffc8000", - "0x3", - "0x480a7ffd7fff8000", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffff98", - "0x208b7fff7fff7ffe", - "0x48127ffb7fff8000", - "0x48127ffc7fff8000", - "0x48127ffa7fff8000", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", + "0x48127ff67fff8000", + "0x48127ff67fff8000", "0x480680017fff8000", "0x1", "0x480680017fff8000", "0x0", - "0x400080007ffd7ffe", - "0x400080017ffd7fff", - "0x40780017fff7fff", - "0x1", - "0x480a7ffb7fff8000", - "0x480a7ffc7fff8000", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x2", - "0x48127ffb7fff8000", - "0x48127ffa7fff8000", - "0x1104800180018000", - "0xe89", - "0x20680017fff7ffb", - "0xb4", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x48127ffc7fff8000", - "0x48127ffc7fff8000", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", - "0x1104800180018000", - "0xed6", - "0x20680017fff7ffd", - "0xa1", "0x480680017fff8000", - "0x4b656363616b", - "0x400280007ffd7fff", - "0x400280017ffd7ffb", - "0x400280027ffd7ffd", - "0x400280037ffd7ffe", - "0x480280057ffd8000", - "0x20680017fff7fff", - "0x90", - "0x480280067ffd8000", - "0x480280047ffd8000", - "0x482680017ffd8000", - "0x8", - "0x480280077ffd8000", - "0x4824800180007ffc", - "0x587f7cc3722e9654ea3963d5fe8c0748", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x10", - "0x40780017fff7fff", - "0x1", + "0x0", "0x480680017fff8000", - "0x57726f6e6720686173682076616c7565", - "0x400080007ffe7fff", - "0x48127ff27fff8000", - "0x48127ff97fff8000", - "0x48127ff97fff8000", + "0x0", "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", - "0x4824800180007ffe", - "0xa5963aa610cb75ba273817bce5f8c48f", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x10", - "0x40780017fff7fff", - "0x1", + "0x0", "0x480680017fff8000", - "0x57726f6e6720686173682076616c7565", - "0x400080007ffe7fff", - "0x48127ff17fff8000", - "0x48127ff87fff8000", - "0x48127ff87fff8000", + "0x0", "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", + "0x0", "0x480680017fff8000", - "0x1", - "0x400080007ffe7fff", - "0x48127ffe7fff8000", - "0x482480017ffd8000", - "0x1", + "0x0", "0x480680017fff8000", - "0x4b656363616b", - "0x400080007ff77fff", - "0x400080017ff77ff6", - "0x400080027ff77ffd", - "0x400080037ff77ffe", - "0x480080057ff78000", - "0x20680017fff7fff", - "0x11", - "0x40780017fff7fff", - "0x1", + "0x0", "0x480680017fff8000", - "0x53686f756c64206661696c", - "0x400080007ffe7fff", - "0x48127feb7fff8000", - "0x480080047ff38000", - "0x482480017ff28000", - "0x8", + "0x0", "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", - "0x480080067ff68000", - "0x480080077ff58000", + "0x0", + "0x480680017fff8000", + "0x0", "0x480680017fff8000", "0x0", - "0x480080047ff38000", - "0x482480017ff28000", - "0x8", - "0x48307ffb80007ffc", - "0xa0680017fff8000", - "0x6", - "0x48307ffe80007ffb", - "0x400080007fe57fff", - "0x10780017fff7fff", - "0x26", - "0x482480017ffb8000", - "0x1", - "0x48307fff80007ffd", - "0x400080007fe47fff", - "0x48307ff97ff78000", - "0x480080007fff8000", - "0x4824800180007fff", - "0x496e76616c696420696e707574206c656e677468", - "0x482480017fe18000", - "0x1", - "0x20680017fff7ffe", - "0xc", - "0x48127fff7fff8000", - "0x48127ff57fff8000", - "0x48127ff57fff8000", "0x480680017fff8000", "0x0", "0x480680017fff8000", @@ -9782,374 +10625,147 @@ "0x480680017fff8000", "0x0", "0x208b7fff7fff7ffe", - "0x40780017fff7fff", + "0x48127ff87fff8000", + "0x482480017ffe8000", + "0xc8", + "0x480680017fff8000", "0x1", "0x480680017fff8000", - "0x57726f6e67206572726f72206d7367", - "0x400080007ffe7fff", - "0x48127ffd7fff8000", - "0x48127ff37fff8000", - "0x48127ff37fff8000", + "0x0", "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", + "0x0", "0x480680017fff8000", - "0x496e646578206f7574206f6620626f756e6473", - "0x400080007ffe7fff", - "0x482480017fe38000", - "0x1", - "0x48127ff87fff8000", - "0x48127ff87fff8000", + "0x0", "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", - "0x48127ff97fff8000", - "0x480280047ffd8000", - "0x482680017ffd8000", - "0x8", - "0x480280067ffd8000", - "0x480280077ffd8000", - "0x10780017fff7fff", - "0xe", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", - "0x480a7ffd7fff8000", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", - "0x10780017fff7fff", - "0x7", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x480a7ffd7fff8000", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", + "0x0", "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", + "0x0", "0x480680017fff8000", - "0x61616161", - "0x400080007ffe7fff", - "0x480a7ffb7fff8000", - "0x48127ffd7fff8000", - "0x482480017ffc8000", - "0x1", + "0x0", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", - "0x1104800180018000", - "0xf0b", - "0x20680017fff7ffd", - "0x37", - "0x1104800180018000", - "0x255b", - "0x482480017fff8000", - "0x255a", - "0x48127ff97fff8000", - "0x480a7ffc7fff8000", - "0x480a7ffd7fff8000", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x48127ffa7fff8000", - "0x1104800180018000", - "0xffb", - "0x20680017fff7ffc", - "0x22", - "0x48127fff7fff8000", - "0x480080007fff8000", - "0x4824800180007fff", - "0x61be55a8", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x10", - "0x40780017fff7fff", - "0x1", - "0x480680017fff8000", - "0x57726f6e6720686173682076616c7565", - "0x400080007ffe7fff", - "0x48127ff47fff8000", - "0x48127ff47fff8000", - "0x48127ff47fff8000", "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", - "0x48127ff67fff8000", - "0x48127ff67fff8000", - "0x48127ff67fff8000", + "0x0", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", - "0x208b7fff7fff7ffe", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", - "0x10780017fff7fff", - "0x7", - "0x48127ffc7fff8000", - "0x480a7ffc7fff8000", - "0x480a7ffd7fff8000", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", - "0x208b7fff7fff7ffe", + "0x0", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", "0x480680017fff8000", - "0x1", + "0x0", "0x480680017fff8000", "0x0", "0x480680017fff8000", - "0x536563703235366b314e6577", - "0x400280007ffd7fff", - "0x400380017ffd7ffb", - "0x400280027ffd7ffb", - "0x400280037ffd7ffc", - "0x400280047ffd7ffd", - "0x400280057ffd7ffe", - "0x480280077ffd8000", - "0x20680017fff7fff", - "0x131", - "0x480280087ffd8000", - "0x480280097ffd8000", - "0x480280067ffd8000", - "0x482680017ffd8000", - "0xa", - "0x20680017fff7ffc", - "0x11", + "0x0", + "0x48127fe87fff8000", + "0x48127fe87fff8000", + "0x208b7fff7fff7ffe", + "0x482480017fef8000", + "0x3", + "0x482480017ff78000", + "0x1248", + "0x10780017fff7fff", + "0x7", "0x40780017fff7fff", - "0x1", + "0x9", + "0x48127fef7fff8000", + "0x482480017ff18000", + "0x1770", "0x480680017fff8000", - "0x53686f756c64206265206e6f6e65", - "0x400080007ffe7fff", - "0x480a7ffa7fff8000", - "0x48127ffb7fff8000", - "0x480a7ffc7fff8000", - "0x48127ffa7fff8000", + "0x0", + "0x48127ff07fff8000", + "0x48127ff07fff8000", "0x480680017fff8000", "0x1", - "0x48127ff97fff8000", - "0x482480017ff88000", - "0x1", - "0x208b7fff7fff7ffe", "0x480680017fff8000", - "0xfffffffffffffffffffffffefffffc2f", + "0x0", "0x480680017fff8000", - "0xffffffffffffffffffffffffffffffff", + "0x0", "0x480680017fff8000", - "0x1", + "0x0", "0x480680017fff8000", "0x0", "0x480680017fff8000", - "0x536563703235366b314e6577", - "0x400080007ffa7fff", - "0x400080017ffa7ff9", - "0x400080027ffa7ffb", - "0x400080037ffa7ffc", - "0x400080047ffa7ffd", - "0x400080057ffa7ffe", - "0x480080077ffa8000", - "0x20680017fff7fff", - "0x12", - "0x40780017fff7fff", - "0x1", + "0x0", "0x480680017fff8000", - "0x53686f756c64206661696c", - "0x400080007ffe7fff", - "0x480a7ffa7fff8000", - "0x480080067ff68000", - "0x480a7ffc7fff8000", - "0x482480017ff48000", - "0xa", + "0x0", "0x480680017fff8000", - "0x1", - "0x48127ff97fff8000", - "0x482480017ff88000", - "0x1", - "0x208b7fff7fff7ffe", - "0x480080087ff98000", - "0x480080097ff88000", + "0x0", "0x480680017fff8000", "0x0", - "0x480080067ff68000", - "0x482480017ff58000", - "0xa", - "0x48307ffb80007ffc", - "0xa0680017fff8000", - "0x6", - "0x48307ffe80007ffb", - "0x400280007ffa7fff", - "0x10780017fff7fff", - "0xda", - "0x482480017ffb8000", - "0x1", - "0x48307fff80007ffd", - "0x400280007ffa7fff", - "0x48307ff97ff78000", - "0x480080007fff8000", - "0x4824800180007fff", - "0x496e76616c696420617267756d656e74", - "0x482680017ffa8000", - "0x1", - "0x20680017fff7ffe", - "0xbf", "0x480680017fff8000", - "0xe3e70682c2094cac629f6fbed82c07cd", + "0x0", "0x480680017fff8000", - "0xf728b4fa42485e3a0a5d2f346baa9455", + "0x0", "0x480680017fff8000", - "0x8e031ab54fc0c4a8f0dc94fad0d0611", + "0x0", "0x480680017fff8000", - "0x8e182ca967f38e1bd6a49583f43f1876", + "0x0", "0x480680017fff8000", - "0x536563703235366b314e6577", - "0x400080007ff27fff", - "0x400080017ff27ff1", - "0x400080027ff27ffb", - "0x400080037ff27ffc", - "0x400080047ff27ffd", - "0x400080057ff27ffe", - "0x480080077ff28000", - "0x20680017fff7fff", - "0xa2", - "0x480080087ff18000", - "0x480080097ff08000", - "0x480080067fef8000", - "0x482480017fee8000", - "0xa", - "0x20680017fff7ffc", - "0x8c", + "0x0", "0x480680017fff8000", - "0x536563703235366b314765745879", - "0x400080007ffe7fff", - "0x400080017ffe7ffd", - "0x400080027ffe7ffc", - "0x480080047ffe8000", - "0x20680017fff7fff", - "0x7a", - "0x480080057ffd8000", - "0x480080067ffc8000", - "0x480080037ffb8000", - "0x482480017ffa8000", - "0x9", - "0x480080077ff98000", - "0x480080087ff88000", - "0x4824800180007ffa", - "0xe3e70682c2094cac629f6fbed82c07cd", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x6", - "0x40780017fff7fff", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x208b7fff7fff7ffe", + "0x482480017fe78000", "0x3", + "0x482480017ff78000", + "0x1978", "0x10780017fff7fff", - "0xa", - "0x4824800180007ffa", - "0xf728b4fa42485e3a0a5d2f346baa9455", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x6", - "0x40780017fff7fff", - "0x2", - "0x10780017fff7fff", - "0x12", - "0x4824800180007ffc", - "0x8e031ab54fc0c4a8f0dc94fad0d0611", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x6", - "0x40780017fff7fff", - "0x1", - "0x10780017fff7fff", - "0x8", - "0x4824800180007ffc", - "0x8e182ca967f38e1bd6a49583f43f1876", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x11", + "0x7", "0x40780017fff7fff", - "0x1", - "0x480680017fff8000", - "0x556e657870656374656420636f6f7264696e61746573", - "0x400080007ffe7fff", + "0x9", "0x48127fe77fff8000", - "0x48127ff57fff8000", - "0x480a7ffc7fff8000", - "0x48127ff47fff8000", + "0x482480017ff18000", + "0x1ea0", + "0x480680017fff8000", + "0x0", + "0x48127ff07fff8000", + "0x48127ff07fff8000", "0x480680017fff8000", "0x1", - "0x48127ff97fff8000", - "0x482480017ff88000", - "0x1", - "0x208b7fff7fff7ffe", "0x480680017fff8000", - "0x767410c1", - "0x484480017fff8000", - "0x100000000000000000000000000000000", - "0x48127fe77fff8000", - "0x48127ff57fff8000", - "0x480a7ffc7fff8000", - "0x48127ff47fff8000", + "0x0", "0x480680017fff8000", - "0x788f195a6f509ca3e934f78d7a71dd85", + "0x0", "0x480680017fff8000", - "0xe888fbb4cf9ae6254f19ba12e6d9af54", + "0x0", "0x480680017fff8000", - "0x7a5f81cf3ee10044320a0d03b62d3e9a", + "0x0", "0x480680017fff8000", - "0x4c8e4fbc1fbb1dece52185e532812c4f", + "0x0", "0x480680017fff8000", - "0xc2b7f60e6a8b84965830658f08f7410c", + "0x0", "0x480680017fff8000", - "0x4ac5e5c0c0e8a4871583cc131f35fb49", + "0x0", "0x480680017fff8000", - "0x1", - "0x482480017ff48000", - "0xbb448978bd42b984d7de5970bcaf5c43", - "0x1104800180018000", - "0xf4a", - "0x20680017fff7ffd", - "0x17", - "0x20680017fff7ffe", - "0xd", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x48127ff97fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", "0x480680017fff8000", "0x0", "0x480680017fff8000", @@ -10157,1838 +10773,510 @@ "0x480680017fff8000", "0x0", "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", - "0x400080007fff7ffe", - "0x48127fff7fff8000", + "0x48127ff77fff8000", "0x482480017ffe8000", - "0x1", - "0x10780017fff7fff", - "0x6", - "0x40780017fff7fff", - "0x1", - "0x48127ffd7fff8000", - "0x48127ffd7fff8000", - "0x48127ff67fff8000", - "0x48127ff67fff8000", + "0x2346", + "0x480680017fff8000", + "0x0", "0x48127ff67fff8000", "0x48127ff67fff8000", "0x480680017fff8000", "0x1", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x208b7fff7fff7ffe", - "0x48127ff37fff8000", - "0x480080037ffc8000", - "0x480a7ffc7fff8000", - "0x482480017ffa8000", - "0x7", "0x480680017fff8000", - "0x1", - "0x480080057ff88000", - "0x480080067ff78000", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", + "0x0", "0x480680017fff8000", - "0x4f7074696f6e3a3a756e77726170206661696c65642e", - "0x400080007ffe7fff", - "0x48127ff37fff8000", - "0x48127ffb7fff8000", - "0x480a7ffc7fff8000", - "0x48127ffa7fff8000", + "0x0", "0x480680017fff8000", - "0x1", - "0x48127ff97fff8000", - "0x482480017ff88000", - "0x1", - "0x208b7fff7fff7ffe", - "0x48127ff97fff8000", - "0x480080067ff08000", - "0x480a7ffc7fff8000", - "0x482480017fee8000", - "0xa", + "0x0", "0x480680017fff8000", - "0x1", - "0x480080087fec8000", - "0x480080097feb8000", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", + "0x0", "0x480680017fff8000", - "0x57726f6e67206572726f72206d7367", - "0x400080007ffe7fff", - "0x48127ffd7fff8000", - "0x48127ff37fff8000", - "0x480a7ffc7fff8000", - "0x48127ff27fff8000", + "0x0", "0x480680017fff8000", - "0x1", - "0x48127ff97fff8000", - "0x482480017ff88000", - "0x1", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", + "0x0", "0x480680017fff8000", - "0x496e646578206f7574206f6620626f756e6473", - "0x400080007ffe7fff", - "0x482680017ffa8000", - "0x1", - "0x48127ff87fff8000", - "0x480a7ffc7fff8000", - "0x48127ff77fff8000", + "0x0", "0x480680017fff8000", - "0x1", - "0x48127ff97fff8000", - "0x482480017ff88000", - "0x1", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", "0x208b7fff7fff7ffe", - "0x480a7ffa7fff8000", - "0x480280067ffd8000", - "0x480a7ffc7fff8000", - "0x482680017ffd8000", - "0xa", + "0x48127ff87fff8000", + "0x482480017ffe8000", + "0x240e", "0x480680017fff8000", "0x1", - "0x480280087ffd8000", - "0x480280097ffd8000", - "0x208b7fff7fff7ffe", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", "0x480680017fff8000", - "0x1", + "0x0", "0x480680017fff8000", "0x0", "0x480680017fff8000", - "0x5365637032353672314e6577", - "0x400280007ffd7fff", - "0x400380017ffd7ffc", - "0x400280027ffd7ffb", - "0x400280037ffd7ffc", - "0x400280047ffd7ffd", - "0x400280057ffd7ffe", - "0x480280077ffd8000", - "0x20680017fff7fff", - "0x156", - "0x480280087ffd8000", - "0x480280097ffd8000", - "0x480280067ffd8000", - "0x482680017ffd8000", - "0xa", - "0x20680017fff7ffc", - "0x12", - "0x40780017fff7fff", - "0x2fe", - "0x40780017fff7fff", - "0x1", + "0x0", "0x480680017fff8000", - "0x53686f756c64206265206e6f6e65", - "0x400080007ffe7fff", - "0x480a7ffb7fff8000", - "0x48127cfd7fff8000", - "0x48127cfd7fff8000", + "0x0", "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", + "0x0", "0x480680017fff8000", - "0xffffffffffffffffffffffff", + "0x0", "0x480680017fff8000", - "0xffffffff000000010000000000000000", + "0x0", "0x480680017fff8000", - "0x1", + "0x0", "0x480680017fff8000", "0x0", "0x480680017fff8000", - "0x5365637032353672314e6577", - "0x400080007ffa7fff", - "0x400080017ffa7ff9", - "0x400080027ffa7ffb", - "0x400080037ffa7ffc", - "0x400080047ffa7ffd", - "0x400080057ffa7ffe", - "0x480080077ffa8000", - "0x20680017fff7fff", - "0x13", - "0x40780017fff7fff", - "0x2f8", - "0x40780017fff7fff", - "0x1", + "0x0", "0x480680017fff8000", - "0x53686f756c64206661696c", - "0x400080007ffe7fff", - "0x480a7ffb7fff8000", - "0x480080067cfe8000", - "0x482480017cfd8000", - "0xa", + "0x0", "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", - "0x480080087ff98000", - "0x480080097ff88000", + "0x0", "0x480680017fff8000", "0x0", - "0x480080067ff68000", - "0x482480017ff58000", - "0xa", - "0x48307ffb80007ffc", - "0xa0680017fff8000", - "0x6", - "0x48307ffe80007ffb", - "0x400280007ffb7fff", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x48127fe87fff8000", + "0x48127fe87fff8000", + "0x208b7fff7fff7ffe", + "0x482480017fe28000", + "0x3", + "0x482480017ff88000", + "0x341c", "0x10780017fff7fff", - "0xfc", - "0x482480017ffb8000", - "0x1", - "0x48307fff80007ffd", - "0x400280007ffb7fff", - "0x48307ff97ff78000", - "0x480080007fff8000", - "0x4824800180007fff", - "0x496e76616c696420617267756d656e74", - "0x482680017ffb8000", + "0x7", + "0x40780017fff7fff", + "0x8", + "0x48127fe27fff8000", + "0x482480017ff28000", + "0x39b2", + "0x480680017fff8000", + "0x0", + "0x48127ff17fff8000", + "0x48127ff17fff8000", + "0x480680017fff8000", "0x1", - "0x20680017fff7ffe", - "0xe0", "0x480680017fff8000", - "0x2d483fe223b12b91047d83258a958b0f", + "0x0", "0x480680017fff8000", - "0x502a43ce77c6f5c736a82f847fa95f8c", + "0x0", "0x480680017fff8000", - "0xce729c7704f4ddf2eaaf0b76209fe1b0", + "0x0", "0x480680017fff8000", - "0xdb0a2e6710c71ba80afeb3abdf69d306", + "0x0", "0x480680017fff8000", - "0x5365637032353672314e6577", - "0x400080007ff27fff", - "0x400080017ff27ff1", - "0x400080027ff27ffb", - "0x400080037ff27ffc", - "0x400080047ff27ffd", - "0x400080057ff27ffe", - "0x480080077ff28000", - "0x20680017fff7fff", - "0xc2", - "0x480080087ff18000", - "0x480080097ff08000", - "0x480080067fef8000", - "0x482480017fee8000", - "0xa", - "0x20680017fff7ffc", - "0xab", + "0x0", "0x480680017fff8000", - "0x5365637032353672314765745879", - "0x400080007ffe7fff", - "0x400080017ffe7ffd", - "0x400080027ffe7ffc", - "0x480080047ffe8000", - "0x20680017fff7fff", - "0x98", - "0x480080057ffd8000", - "0x480080067ffc8000", - "0x480080037ffb8000", - "0x482480017ffa8000", - "0x9", - "0x480080077ff98000", - "0x480080087ff88000", - "0x4824800180007ffa", - "0x2d483fe223b12b91047d83258a958b0f", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x6", - "0x40780017fff7fff", - "0x2d8", - "0x10780017fff7fff", - "0xa", - "0x4824800180007ffa", - "0x502a43ce77c6f5c736a82f847fa95f8c", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x6", - "0x40780017fff7fff", - "0x2d7", - "0x10780017fff7fff", - "0x14", - "0x4824800180007ffc", - "0xce729c7704f4ddf2eaaf0b76209fe1b0", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x6", - "0x40780017fff7fff", - "0x2d6", - "0x10780017fff7fff", - "0xa", - "0x4824800180007ffc", - "0xdb0a2e6710c71ba80afeb3abdf69d306", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x12", - "0x40780017fff7fff", - "0x2d5", - "0x40780017fff7fff", - "0x1", + "0x0", "0x480680017fff8000", - "0x556e657870656374656420636f6f7264696e61746573", - "0x400080007ffe7fff", - "0x48127d127fff8000", - "0x48127d207fff8000", - "0x48127d207fff8000", + "0x0", "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x208b7fff7fff7ffe", + "0x48127ff17fff8000", "0x482480017ff98000", + "0x3c5a", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x10780017fff7fff", + "0x33", + "0x48127ff87fff8000", + "0x482480017ff88000", + "0x4236", + "0x480680017fff8000", "0x1", - "0x208b7fff7fff7ffe", "0x480680017fff8000", - "0x32e41495a944d0045b522eba7240fad5", + "0x0", "0x480680017fff8000", - "0x4aaec73635726f213fb8a9e64da3b86", + "0x0", "0x480680017fff8000", - "0xaaf7b4e09fc81d6d1aa546e8365d525d", + "0x0", "0x480680017fff8000", - "0x87d9315798aaa3a5ba01775787ced05e", + "0x0", "0x480680017fff8000", - "0x5365637032353672314e6577", - "0x400080007ff47fff", - "0x400080017ff47ff3", - "0x400080027ff47ffb", - "0x400080037ff47ffc", - "0x400080047ff47ffd", - "0x400080057ff47ffe", - "0x480080077ff48000", - "0x20680017fff7fff", - "0x3f", - "0x480080087ff38000", - "0x480080097ff28000", - "0x480080067ff18000", - "0x482480017ff08000", - "0xa", - "0x20680017fff7ffc", - "0x28", - "0x48127fdf7fff8000", - "0x48127ffd7fff8000", - "0x48127ffd7fff8000", + "0x0", "0x480680017fff8000", - "0x27ae41e4649b934ca495991b7852b855", + "0x0", "0x480680017fff8000", - "0xe3b0c44298fc1c149afbf4c8996fb924", + "0x0", "0x480680017fff8000", - "0x42d16e47f219f9e98e76e09d8770b34a", + "0x0", "0x480680017fff8000", - "0xb292a619339f6e567a305c951c0dcbcc", + "0x0", "0x480680017fff8000", - "0xe59ec2a17ce5bd2dab2abebdf89a62e2", + "0x0", "0x480680017fff8000", - "0x177e60492c5a8242f76f07bfe3661bd", - "0x48127ff47fff8000", - "0x1104800180018000", - "0xeb3", - "0x20680017fff7ffd", - "0xc", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", + "0x48127fe97fff8000", + "0x48127fe97fff8000", "0x208b7fff7fff7ffe", + "0x48127fe47fff8000", + "0x482480017ffa8000", + "0x4b14", "0x48127ffa7fff8000", "0x48127ffa7fff8000", - "0x48127ffa7fff8000", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", + "0x480680017fff8000", + "0x0", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x2cb", - "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4f7074696f6e3a3a756e77726170206661696c65642e", - "0x400080007ffe7fff", - "0x48127d127fff8000", - "0x48127d307fff8000", - "0x48127d307fff8000", + "0x0", "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x2d1", - "0x48127d127fff8000", - "0x480080067d218000", - "0x482480017d208000", - "0xa", + "0x0", "0x480680017fff8000", - "0x1", - "0x480080087d1e8000", - "0x480080097d1d8000", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x2e1", - "0x48127d127fff8000", - "0x480080037d1b8000", - "0x482480017d1a8000", - "0x7", + "0x0", "0x480680017fff8000", - "0x1", - "0x480080057d188000", - "0x480080067d178000", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x2e1", - "0x40780017fff7fff", - "0x1", + "0x0", "0x480680017fff8000", - "0x4f7074696f6e3a3a756e77726170206661696c65642e", - "0x400080007ffe7fff", - "0x48127d127fff8000", - "0x48127d1a7fff8000", - "0x48127d1a7fff8000", + "0x0", "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x2e7", - "0x48127d127fff8000", - "0x480080067d098000", - "0x482480017d088000", - "0xa", + "0x0", "0x480680017fff8000", - "0x1", - "0x480080087d068000", - "0x480080097d058000", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x2eb", - "0x40780017fff7fff", - "0x1", + "0x0", "0x480680017fff8000", - "0x57726f6e67206572726f72206d7367", - "0x400080007ffe7fff", - "0x48127d127fff8000", - "0x48127d087fff8000", - "0x48127d087fff8000", + "0x0", "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x2f0", - "0x40780017fff7fff", - "0x1", + "0x0", "0x480680017fff8000", - "0x496e646578206f7574206f6620626f756e6473", - "0x400080007ffe7fff", - "0x482680017ffb8000", - "0x1", - "0x48127d087fff8000", - "0x48127d087fff8000", + "0x0", "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x304", - "0x480a7ffb7fff8000", - "0x480280067ffd8000", - "0x482680017ffd8000", - "0xa", + "0x0", "0x480680017fff8000", - "0x1", - "0x480280087ffd8000", - "0x480280097ffd8000", - "0x208b7fff7fff7ffe", - "0xa0680017fff8000", - "0x7", - "0x482680017ffa8000", - "0xffffffffffffffffffffffffffffc900", - "0x400280007ff97fff", - "0x10780017fff7fff", - "0x117", - "0x4825800180007ffa", - "0x3700", - "0x400280007ff97fff", - "0x48297ffc80007ffd", + "0x0", "0x480680017fff8000", - "0x3", - "0x48307fff80017ffe", - "0xa0680017fff7fff", - "0x7", - "0x482480017fff8000", - "0x100000000000000000000000000000000", - "0x400280017ff97fff", - "0x10780017fff7fff", - "0xfa", - "0x400280017ff97fff", - "0x482680017ff98000", - "0x2", - "0x48297ffc80007ffd", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0xe4", - "0x482680017ffc8000", - "0x1", - "0x480a7ffd7fff8000", - "0x480280007ffc8000", - "0x48307ffd80007ffe", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0xcd", - "0x482480017ffc8000", - "0x1", - "0x48127ffc7fff8000", - "0x480080007ffa8000", - "0x48307ffd80007ffe", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0xb6", - "0x480080007ffc8000", - "0x482480017ffb8000", - "0x1", - "0x48127ffb7fff8000", - "0x20680017fff7ffd", - "0x43", - "0xa0680017fff8004", - "0xe", - "0x4824800180047ff6", - "0x800000000000000000000000000000000000000000000000000000000000000", - "0x484480017ffe8000", - "0x110000000000000000", - "0x48307ffe7fff8002", - "0x480080007fef7ffc", - "0x480080017fee7ffc", - "0x402480017ffb7ffd", - "0xffffffffffffffeeffffffffffffffff", - "0x400080027fed7ffd", - "0x10780017fff7fff", - "0x26", - "0x484480017fff8001", - "0x8000000000000000000000000000000", - "0x48307fff80007ff5", - "0x480080007ff07ffd", - "0x480080017fef7ffd", - "0x402480017ffc7ffe", - "0xf8000000000000000000000000000000", - "0x400080027fee7ffe", - "0x482480017fee8000", - "0x3", + "0x0", "0x480680017fff8000", - "0x43616c6c436f6e7472616374", - "0x400280007ffb7fff", - "0x400280017ffb7fe7", - "0x400280027ffb7ff0", - "0x400280037ffb7ff4", - "0x400280047ffb7ff7", - "0x400280057ffb7ff8", - "0x480280077ffb8000", - "0x20680017fff7fff", - "0x8", - "0x48127ffd7fff8000", - "0x480280067ffb8000", - "0x482680017ffb8000", - "0xa", - "0x10780017fff7fff", - "0x80", - "0x48127ffd7fff8000", - "0x480280067ffb8000", - "0x482680017ffb8000", - "0xa", + "0x0", "0x480680017fff8000", - "0x1", - "0x480280087ffb8000", - "0x480280097ffb8000", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", + "0x0", "0x480680017fff8000", - "0x4f7074696f6e3a3a756e77726170206661696c65642e", - "0x400080007ffe7fff", - "0x482480017feb8000", - "0x3", - "0x48127fe57fff8000", - "0x480a7ffb7fff8000", + "0x0", "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", + "0x0", "0x208b7fff7fff7ffe", - "0x4824800180007ffd", - "0x1", - "0x20680017fff7fff", - "0x43", - "0xa0680017fff8004", - "0xe", - "0x4824800180047ff5", - "0x800000000000000000000000000000000000000000000000000000000000000", - "0x484480017ffe8000", - "0x110000000000000000", - "0x48307ffe7fff8002", - "0x480080007fee7ffc", - "0x480080017fed7ffc", - "0x402480017ffb7ffd", - "0xffffffffffffffeeffffffffffffffff", - "0x400080027fec7ffd", - "0x10780017fff7fff", - "0x26", - "0x484480017fff8001", - "0x8000000000000000000000000000000", - "0x48307fff80007ff4", - "0x480080007fef7ffd", - "0x480080017fee7ffd", - "0x402480017ffc7ffe", - "0xf8000000000000000000000000000000", - "0x400080027fed7ffe", - "0x482480017fed8000", - "0x3", + "0x48127fed7fff8000", + "0x482480017ffd8000", + "0x514a", "0x480680017fff8000", - "0x4c69627261727943616c6c", - "0x400280007ffb7fff", - "0x400280017ffb7fe6", - "0x400280027ffb7fef", - "0x400280037ffb7ff3", - "0x400280047ffb7ff6", - "0x400280057ffb7ff7", - "0x480280077ffb8000", - "0x20680017fff7fff", - "0x8", - "0x48127ffd7fff8000", - "0x480280067ffb8000", - "0x482680017ffb8000", - "0xa", - "0x10780017fff7fff", - "0x3b", - "0x48127ffd7fff8000", - "0x480280067ffb8000", - "0x482680017ffb8000", - "0xa", + "0x0", + "0x48127ff97fff8000", + "0x48127ff97fff8000", "0x480680017fff8000", "0x1", - "0x480280087ffb8000", - "0x480280097ffb8000", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", "0x480680017fff8000", - "0x4f7074696f6e3a3a756e77726170206661696c65642e", - "0x400080007ffe7fff", - "0x482480017fea8000", - "0x3", - "0x48127fe47fff8000", - "0x480a7ffb7fff8000", + "0x0", "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", "0x208b7fff7fff7ffe", - "0x4824800180007ffa", - "0x62c83572d28cb834a3de3c1e94977a4191469a4a8c26d1d7bc55305e640ed5", - "0x20680017fff7fff", - "0xa", "0x48127ff17fff8000", - "0x48127feb7fff8000", - "0x480a7ffb7fff8000", + "0x482480017ffd8000", + "0x5398", + "0x480680017fff8000", + "0x0", "0x48127ff97fff8000", "0x48127ff97fff8000", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffff3d", - "0x208b7fff7fff7ffe", - "0x4824800180007ff9", - "0x32564d7e0fe091d49b4c20f4632191e4ed6986bf993849879abfef9465def25", - "0x20680017fff7fff", - "0x10", - "0x40780017fff7fff", + "0x480680017fff8000", "0x1", "0x480680017fff8000", - "0x6661696c", - "0x400080007ffe7fff", - "0x48127fee7fff8000", - "0x48127fe87fff8000", - "0x480a7ffb7fff8000", + "0x0", "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", - "0x48127ff07fff8000", - "0x48127fea7fff8000", - "0x480a7ffb7fff8000", + "0x0", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", "0x480680017fff8000", - "0x4f7074696f6e3a3a756e77726170206661696c65642e", - "0x400080007ffe7fff", - "0x48127ff47fff8000", - "0x48127fee7fff8000", - "0x480a7ffb7fff8000", + "0x0", "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", + "0x0", "0x480680017fff8000", - "0x4f7074696f6e3a3a756e77726170206661696c65642e", - "0x400080007ffe7fff", - "0x48127ff87fff8000", - "0x48127ff27fff8000", - "0x480a7ffb7fff8000", + "0x0", "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", + "0x0", "0x480680017fff8000", - "0x4f7074696f6e3a3a756e77726170206661696c65642e", - "0x400080007ffe7fff", - "0x48127ffc7fff8000", - "0x48127ff67fff8000", - "0x480a7ffb7fff8000", + "0x0", "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", + "0x0", "0x480680017fff8000", - "0x4469766973696f6e2062792030", - "0x400080007ffe7fff", - "0x482680017ff98000", - "0x2", - "0x48127ff77fff8000", - "0x480a7ffb7fff8000", + "0x0", "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", + "0x0", "0x480680017fff8000", - "0x4f7574206f6620676173", - "0x400080007ffe7fff", - "0x482680017ff98000", - "0x1", - "0x480a7ffa7fff8000", - "0x480a7ffb7fff8000", + "0x0", "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", - "0xa0680017fff8000", - "0x7", - "0x482680017ffc8000", - "0xfffffffffffffffffffffffffffffbd2", - "0x400280007ffb7fff", - "0x10780017fff7fff", - "0x1d", - "0x4825800180007ffc", - "0x42e", - "0x400280007ffb7fff", - "0x482680017ffb8000", - "0x1", - "0x20780017fff7ffd", - "0xf", - "0x40780017fff7fff", - "0x1", + "0x0", "0x480680017fff8000", - "0x7265637572736976655f6661696c", - "0x400080007ffe7fff", - "0x48127ffd7fff8000", - "0x48127ffb7fff8000", + "0x0", "0x480680017fff8000", - "0x1", - "0x48127ffb7fff8000", - "0x482480017ffa8000", - "0x1", - "0x208b7fff7fff7ffe", - "0x48127fff7fff8000", - "0x48127ffd7fff8000", - "0x4825800180007ffd", - "0x1", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffe2", + "0x0", "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", + "0x48127ff57fff8000", + "0x482480017ffd8000", + "0x55e6", "0x480680017fff8000", - "0x4f7574206f6620676173", - "0x400080007ffe7fff", - "0x482680017ffb8000", - "0x1", - "0x480a7ffc7fff8000", + "0x0", + "0x48127ff47fff8000", + "0x48127ff47fff8000", "0x480680017fff8000", "0x1", - "0x48127ffb7fff8000", - "0x482480017ffa8000", - "0x1", - "0x208b7fff7fff7ffe", - "0xa0680017fff8000", - "0x7", - "0x482680017ffc8000", - "0xfffffffffffffffffffffffffffffbd2", - "0x400280007ffb7fff", - "0x10780017fff7fff", - "0x19", - "0x4825800180007ffc", - "0x42e", - "0x400280007ffb7fff", - "0x482680017ffb8000", - "0x1", - "0x20780017fff7ffd", - "0xb", - "0x48127fff7fff8000", - "0x48127ffd7fff8000", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", - "0x208b7fff7fff7ffe", - "0x48127fff7fff8000", - "0x48127ffd7fff8000", - "0x4825800180007ffd", - "0x1", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffe6", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", - "0x480680017fff8000", - "0x4f7574206f6620676173", - "0x400080007ffe7fff", - "0x482680017ffb8000", - "0x1", - "0x480a7ffc7fff8000", - "0x480680017fff8000", - "0x1", - "0x48127ffb7fff8000", - "0x482480017ffa8000", - "0x1", - "0x208b7fff7fff7ffe", "0x480680017fff8000", - "0x2691cb735b18f3f656c3b82bd97a32b65d15019b64117513f8604d1e06fe58b", - "0x400280007ff97fff", - "0x400380017ff97ffb", - "0x480280027ff98000", - "0xa0680017fff8005", - "0xe", - "0x4824800180057ffe", - "0x7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00", - "0x484480017ffe8000", - "0x110000000000000000", - "0x48307ffe7fff8003", - "0x480280007ff77ffc", - "0x480280017ff77ffc", - "0x482480017ffb7ffd", - "0xffffffffffffffeefffffffffffffeff", - "0x400280027ff77ffc", - "0x10780017fff7fff", - "0x11", - "0x48127ffe7fff8005", - "0x484480017ffe8000", - "0x8000000000000000000000000000000", - "0x48307ffe7fff8003", - "0x480280007ff77ffd", - "0x482480017ffc7ffe", - "0xf0000000000000000000000000000100", - "0x480280017ff77ffd", - "0x400280027ff77ff9", - "0x402480017ffd7ff9", - "0xffffffffffffffffffffffffffffffff", - "0x20680017fff7ffd", - "0x4", - "0x402780017fff7fff", - "0x1", + "0x0", "0x480680017fff8000", "0x0", - "0x482680017ff98000", - "0x3", - "0x482680017ff78000", - "0x3", "0x480680017fff8000", - "0x53746f7261676552656164", - "0x400280007ffa7fff", - "0x400380017ffa7ff8", - "0x400280027ffa7ffc", - "0x400280037ffa7ffb", - "0x480280057ffa8000", - "0x20680017fff7fff", - "0x84", - "0x480280047ffa8000", + "0x0", "0x480680017fff8000", "0x0", - "0x482480017ff88000", - "0x1", - "0x480280067ffa8000", "0x480680017fff8000", - "0x53746f7261676552656164", - "0x400280077ffa7fff", - "0x400280087ffa7ffb", - "0x400280097ffa7ffc", - "0x4002800a7ffa7ffd", - "0x4802800c7ffa8000", - "0x20680017fff7fff", - "0x6c", + "0x0", "0x480680017fff8000", - "0x2691cb735b18f3f656c3b82bd97a32b65d15019b64117513f8604d1e06fe58b", - "0x400080007ff57fff", - "0x400180017ff57ffb", - "0x480080027ff58000", - "0xa0680017fff8005", - "0xe", - "0x4824800180057ffe", - "0x7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00", - "0x484480017ffe8000", - "0x110000000000000000", - "0x48307ffe7fff8003", - "0x480080007ff17ffc", - "0x480080017ff07ffc", - "0x482480017ffb7ffd", - "0xffffffffffffffeefffffffffffffeff", - "0x400080027fee7ffc", - "0x10780017fff7fff", - "0x11", - "0x48127ffe7fff8005", - "0x484480017ffe8000", - "0x8000000000000000000000000000000", - "0x48307ffe7fff8003", - "0x480080007ff17ffd", - "0x482480017ffc7ffe", - "0xf0000000000000000000000000000100", - "0x480080017fef7ffd", - "0x400080027fee7ff9", - "0x402480017ffd7ff9", - "0xffffffffffffffffffffffffffffffff", - "0x20680017fff7ffd", - "0x4", - "0x402780017fff7fff", - "0x1", - "0x4802800b7ffa8000", + "0x0", "0x480680017fff8000", "0x0", - "0x48287ffc7ff28000", - "0x4802800d7ffa8000", - "0x482480017fe98000", - "0x3", - "0x482480017fe98000", - "0x3", "0x480680017fff8000", - "0x53746f726167655772697465", - "0x4002800e7ffa7fff", - "0x4002800f7ffa7ff9", - "0x400280107ffa7ffa", - "0x400280117ffa7ff8", - "0x400280127ffa7ffb", - "0x480280147ffa8000", - "0x20680017fff7fff", - "0x27", - "0x480280137ffa8000", + "0x0", "0x480680017fff8000", "0x0", - "0x482480017ff58000", - "0x1", - "0x48287ffd7ff88000", "0x480680017fff8000", - "0x53746f726167655772697465", - "0x400280157ffa7fff", - "0x400280167ffa7ffb", - "0x400280177ffa7ffc", - "0x400280187ffa7ffd", - "0x400280197ffa7ffe", - "0x4802801b7ffa8000", - "0x20680017fff7fff", - "0x10", - "0x40780017fff7fff", - "0x4", - "0x48127ff37fff8000", - "0x4802801a7ffa8000", - "0x48127ff07fff8000", - "0x482680017ffa8000", - "0x1c", + "0x0", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", - "0x208b7fff7fff7ffe", - "0x4802801a7ffa8000", - "0x482680017ffa8000", - "0x1e", - "0x4802801c7ffa8000", - "0x4802801d7ffa8000", - "0x10780017fff7fff", - "0x9", - "0x40780017fff7fff", - "0x6", - "0x480280137ffa8000", - "0x482680017ffa8000", - "0x17", - "0x480280157ffa8000", - "0x480280167ffa8000", - "0x48127ff37fff8000", - "0x48127ffb7fff8000", - "0x48127ff07fff8000", - "0x48127ffa7fff8000", "0x480680017fff8000", - "0x1", - "0x48127ff97fff8000", - "0x48127ff97fff8000", + "0x0", "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x17", - "0x4802800b7ffa8000", - "0x482680017ffa8000", - "0xf", - "0x4802800d7ffa8000", - "0x4802800e7ffa8000", - "0x10780017fff7fff", - "0x9", - "0x40780017fff7fff", - "0x1d", - "0x480280047ffa8000", - "0x482680017ffa8000", - "0x8", - "0x480280067ffa8000", - "0x480280077ffa8000", - "0x48127fdc7fff8000", - "0x48127ffb7fff8000", - "0x48127fd97fff8000", - "0x48127ffa7fff8000", + "0x48127ff77fff8000", + "0x482480017ffe8000", + "0x582a", "0x480680017fff8000", - "0x1", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x208b7fff7fff7ffe", + "0x0", + "0x48127ff67fff8000", + "0x48127ff67fff8000", "0x480680017fff8000", - "0x2691cb735b18f3f656c3b82bd97a32b65d15019b64117513f8604d1e06fe58b", - "0x400280007ff97fff", - "0x400380017ff97ffb", - "0x480280027ff98000", - "0xa0680017fff8005", - "0xe", - "0x4824800180057ffe", - "0x7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00", - "0x484480017ffe8000", - "0x110000000000000000", - "0x48307ffe7fff8003", - "0x480280007ff67ffc", - "0x480280017ff67ffc", - "0x482480017ffb7ffd", - "0xffffffffffffffeefffffffffffffeff", - "0x400280027ff67ffc", - "0x10780017fff7fff", - "0x11", - "0x48127ffe7fff8005", - "0x484480017ffe8000", - "0x8000000000000000000000000000000", - "0x48307ffe7fff8003", - "0x480280007ff67ffd", - "0x482480017ffc7ffe", - "0xf0000000000000000000000000000100", - "0x480280017ff67ffd", - "0x400280027ff67ff9", - "0x402480017ffd7ff9", - "0xffffffffffffffffffffffffffffffff", - "0x20680017fff7ffd", - "0x4", - "0x402780017fff7fff", "0x1", "0x480680017fff8000", "0x0", - "0x482680017ff98000", - "0x3", - "0x482680017ff68000", - "0x3", "0x480680017fff8000", - "0x53746f7261676552656164", - "0x400280007ffa7fff", - "0x400380017ffa7ff7", - "0x400280027ffa7ffc", - "0x400280037ffa7ffb", - "0x480280057ffa8000", - "0x20680017fff7fff", - "0xe2", - "0x480280047ffa8000", + "0x0", "0x480680017fff8000", "0x0", - "0x482480017ff88000", - "0x1", - "0x480280067ffa8000", "0x480680017fff8000", - "0x53746f7261676552656164", - "0x400280077ffa7fff", - "0x400280087ffa7ffb", - "0x400280097ffa7ffc", - "0x4002800a7ffa7ffd", - "0x4802800c7ffa8000", - "0x20680017fff7fff", - "0xca", - "0x4802800b7ffa8000", - "0x482680017ffa8000", - "0xe", - "0x4802800d7ffa8000", - "0xa0680017fff8000", - "0x16", - "0x480080007ff38003", - "0x480080017ff28003", - "0x4844800180017ffe", - "0x100000000000000000000000000000000", - "0x483080017ffd7ff6", - "0x482480017fff7ffd", - "0x800000000000010fffffffffffffffff7ffffffffffffef0000000000000001", - "0x20680017fff7ffc", - "0x6", - "0x402480017fff7ffd", - "0xffffffffffffffffffffffffffffffff", - "0x10780017fff7fff", - "0x4", - "0x402480017ffe7ffd", - "0xf7ffffffffffffef0000000000000000", - "0x400080027fee7ffd", - "0x20680017fff7ffe", - "0x9f", - "0x402780017fff7fff", - "0x1", - "0x400080007ff37ff9", - "0xa0680017fff8000", - "0x16", - "0x480080017ff28003", - "0x480080027ff18003", - "0x4844800180017ffe", - "0x100000000000000000000000000000000", - "0x483080017ffd7ffa", - "0x482480017fff7ffd", - "0x800000000000010fffffffffffffffff7ffffffffffffef0000000000000001", - "0x20680017fff7ffc", - "0x6", - "0x402480017fff7ffd", - "0xffffffffffffffffffffffffffffffff", - "0x10780017fff7fff", - "0x4", - "0x402480017ffe7ffd", - "0xf7ffffffffffffef0000000000000000", - "0x400080037fed7ffd", - "0x20680017fff7ffe", - "0x75", - "0x402780017fff7fff", - "0x1", - "0x400080017ff27ffd", - "0x400280007ff87ff8", - "0x400380017ff87ffc", - "0x400280057ff87ffd", - "0x400380067ff87ffd", + "0x0", "0x480680017fff8000", - "0x2691cb735b18f3f656c3b82bd97a32b65d15019b64117513f8604d1e06fe58b", - "0x400080007ff07fff", - "0x400180017ff07ffb", - "0x480080027ff08000", - "0xa0680017fff8005", - "0xe", - "0x4824800180057ffe", - "0x7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00", - "0x484480017ffe8000", - "0x110000000000000000", - "0x48307ffe7fff8003", - "0x480080027fec7ffc", - "0x480080037feb7ffc", - "0x482480017ffb7ffd", - "0xffffffffffffffeefffffffffffffeff", - "0x400080047fe97ffc", - "0x10780017fff7fff", - "0x11", - "0x48127ffe7fff8005", - "0x484480017ffe8000", - "0x8000000000000000000000000000000", - "0x48307ffe7fff8003", - "0x480080027fec7ffd", - "0x482480017ffc7ffe", - "0xf0000000000000000000000000000100", - "0x480080037fea7ffd", - "0x400080047fe97ff9", - "0x402480017ffd7ff9", - "0xffffffffffffffffffffffffffffffff", - "0x20680017fff7ffd", - "0x4", - "0x402780017fff7fff", - "0x1", + "0x0", "0x480680017fff8000", "0x0", - "0x480280037ff88000", - "0x482680017ff88000", - "0xa", - "0x480280087ff88000", - "0x482480017fe48000", - "0x3", - "0x482480017fe48000", - "0x5", "0x480680017fff8000", - "0x53746f726167655772697465", - "0x400080007fec7fff", - "0x400080017fec7feb", - "0x400080027fec7ff9", - "0x400080037fec7ff8", - "0x400080047fec7ffa", - "0x480080067fec8000", - "0x20680017fff7fff", - "0x27", - "0x480080057feb8000", + "0x0", "0x480680017fff8000", "0x0", - "0x482480017ff58000", - "0x1", "0x480680017fff8000", - "0x53746f726167655772697465", - "0x400080077fe77fff", - "0x400080087fe77ffc", - "0x400080097fe77ffd", - "0x4000800a7fe77ffe", - "0x4000800b7fe77ff7", - "0x4800800d7fe78000", - "0x20680017fff7fff", - "0x11", - "0x40780017fff7fff", - "0x4", - "0x48127ff47fff8000", - "0x4800800c7fe18000", - "0x48127fef7fff8000", - "0x48127ff07fff8000", - "0x482480017fde8000", - "0xe", + "0x0", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", - "0x208b7fff7fff7ffe", - "0x4800800c7fe68000", - "0x482480017fe58000", - "0x10", - "0x4800800e7fe48000", - "0x4800800f7fe38000", - "0x10780017fff7fff", - "0x9", - "0x40780017fff7fff", - "0x5", - "0x480080057fe68000", - "0x482480017fe58000", - "0x9", - "0x480080077fe48000", - "0x480080087fe38000", - "0x48127ff47fff8000", - "0x48127ffb7fff8000", - "0x48127fef7fff8000", - "0x48127ff07fff8000", - "0x48127ff97fff8000", "0x480680017fff8000", - "0x1", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x13", - "0x40780017fff7fff", - "0x1", + "0x0", "0x480680017fff8000", - "0x4f7074696f6e3a3a756e77726170206661696c65642e", - "0x400080007ffe7fff", - "0x482480017fd88000", - "0x4", - "0x48127fe07fff8000", - "0x480a7ff87fff8000", - "0x48127fd47fff8000", - "0x48127fde7fff8000", + "0x0", "0x480680017fff8000", - "0x1", - "0x48127ff87fff8000", - "0x482480017ff78000", - "0x1", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x14", - "0x40780017fff7fff", - "0x1", + "0x0", "0x480680017fff8000", - "0x4f7074696f6e3a3a756e77726170206661696c65642e", - "0x400080007ffe7fff", - "0x482480017fd88000", - "0x3", - "0x48127fe07fff8000", - "0x480a7ff87fff8000", - "0x48127fd47fff8000", - "0x48127fde7fff8000", + "0x0", "0x480680017fff8000", - "0x1", - "0x48127ff87fff8000", - "0x482480017ff78000", - "0x1", + "0x0", "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1b", - "0x4802800b7ffa8000", - "0x482680017ffa8000", - "0xf", - "0x4802800d7ffa8000", - "0x4802800e7ffa8000", - "0x10780017fff7fff", - "0x9", - "0x40780017fff7fff", - "0x21", - "0x480280047ffa8000", - "0x482680017ffa8000", - "0x8", - "0x480280067ffa8000", - "0x480280077ffa8000", - "0x48127fd87fff8000", - "0x48127ffb7fff8000", - "0x480a7ff87fff8000", - "0x48127fd47fff8000", - "0x48127ff97fff8000", + "0x48127ff87fff8000", + "0x482480017ffe8000", + "0x58f2", "0x480680017fff8000", "0x1", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x208b7fff7fff7ffe", "0x480680017fff8000", - "0x654fd7e67a123dd13868093b3b7777f1ffef596c2e324f25ceaf9146698482c", + "0x0", "0x480680017fff8000", - "0x4fad269cbf860980e38768fe9cb6b0b9ab03ee3fe84cfde2eccce597c874fd8", - "0x48507fff7fff8000", - "0x48507ffd7ffd8001", - "0x48507ffc80008001", - "0x482480017ffb8001", - "0x6f21413efbe40de150e596d72f7a8c5609ad26c15c915c1f4cdfcb99cee9e89", - "0x483080007fff7ffd", - "0x48307ffc80007ffb", - "0x20680017fff7fff", - "0x106", - "0x48127ff87fff8000", - "0x48127ff87fff8000", + "0x0", "0x480680017fff8000", - "0x3dbce56de34e1cfe252ead5a1f14fd261d520d343ff6b7652174e62976ef44d", - "0x480680017fff8000", - "0x4b5810004d9272776dec83ecc20c19353453b956e594188890b48467cb53c19", - "0x48507fff7fff8000", - "0x48507ffd7ffd8001", - "0x48507ffc80008001", - "0x482480017ffb8001", - "0x6f21413efbe40de150e596d72f7a8c5609ad26c15c915c1f4cdfcb99cee9e89", - "0x483080007fff7ffd", - "0x48307ffc80007ffb", - "0x20680017fff7fff", - "0xe6", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x20680017fff7fff", - "0x9", - "0x40780017fff7fff", - "0x17", - "0x480a7ffb7fff8000", - "0x48127fe67fff8000", - "0x48127fe67fff8000", - "0x10780017fff7fff", - "0x32", - "0x4800800080068004", - "0x4800800180058004", - "0x4850800380037ffe", - "0x4850800180017ffe", - "0x485080007ffd7ffe", - "0x482480017fff7ffe", - "0x6f21413efbe40de150e596d72f7a8c5609ad26c15c915c1f4cdfcb99cee9e89", - "0x48307ffd7ffc7ffa", - "0x480680017fff8000", - "0x6d232c016ef1b12aec4b7f88cc0b3ab662be3b7dd7adbce5209fcfdbd42a504", - "0x400280007ffb7ffc", - "0x400280017ffb7ffd", - "0x400280027ffb7ff6", - "0x400280037ffb7ff7", - "0x400280047ffb7fff", - "0x480280057ffb8000", - "0x480280067ffb8000", - "0x48127ffc7fff8000", - "0x482680017ffb8000", - "0x7", - "0x480080007ffe8000", - "0x480080017ffd8000", - "0x48307ffe80007ffa", - "0x20680017fff7fff", - "0x5", - "0x40127ffe7fff7ffa", - "0x10780017fff7fff", - "0xf", - "0x48307ffe7ffa8000", - "0x48507ffe80007fff", - "0x48507fff7fff8000", - "0x48307ffa7ff68000", - "0x48307fff80027ffe", - "0x483080017fff7ff4", - "0x48507ffe7ffb7fff", - "0x48307ff380007ffe", - "0x48127ff47fff8000", - "0x48127ffd7fff8000", - "0x48127ffd7fff8000", - "0x10780017fff7fff", - "0x9", - "0x40780017fff7fff", - "0x8", - "0x48127ff47fff8000", + "0x0", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", - "0x20680017fff7fff", - "0x8", - "0x40780017fff7fff", - "0x2a", - "0x48127fb07fff8000", - "0x48127fb07fff8000", - "0x10780017fff7fff", - "0x4c", - "0x20680017fff7fdb", - "0x8", - "0x40780017fff7fff", - "0x2a", - "0x48127fd47fff8000", - "0x48127fd47fff8000", - "0x10780017fff7fff", - "0x44", - "0x4800800080068004", - "0x4800800180058004", - "0x4850800380037ffe", - "0x4850800180017ffe", - "0x485080007ffd7ffe", - "0x482480017fff7ffe", - "0x6f21413efbe40de150e596d72f7a8c5609ad26c15c915c1f4cdfcb99cee9e89", - "0x48307ffd7ffc7ffa", - "0x48307ffd80007ff7", - "0x20680017fff7fff", - "0x4", - "0x402780017fff7fff", - "0x1", - "0x48307ffd80007ff7", - "0x48507ffe80007fff", - "0x48507fff7fff8000", - "0x48307ff97ff38000", - "0x48307fff80027ffe", - "0x483080017fff7ff1", - "0x48507ffe7ffb7fff", - "0x48307ff080007ffe", - "0x48127ffe7fff8000", - "0x48127ffe7fff8000", - "0x48127ff47fff8000", - "0x48307ffd80007fc7", - "0x20680017fff7fff", - "0x4", - "0x402780017fff7fff", - "0x1", - "0x48307ffd80007fc7", - "0x48507ffe80007fff", - "0x48507fff7fff8000", - "0x48307ff97fc38000", - "0x48307fff80027ffe", - "0x483080017fff7fc1", - "0x48507ffe7ffb7fff", - "0x48307fc080007ffe", - "0x48127ffe7fff8000", - "0x48127ffe7fff8000", - "0x48127ff47fff8000", - "0x480080007fff8000", - "0x480080017ffe8000", - "0x48307ffe80007ffb", - "0x20680017fff7fff", - "0x5", - "0x40127ffe7fff7ffb", - "0x10780017fff7fff", - "0xe", - "0x48307ffe7ffb8000", - "0x48507ffe80007fff", - "0x48507fff7fff8000", - "0x48307ffa7ff78000", - "0x48307fff80027ffe", - "0x483080017fff7ff5", - "0x48507ffe7ffb7fff", - "0x48307ff480007ffe", - "0x48127ffe7fff8000", - "0x48127ffe7fff8000", - "0x10780017fff7fff", - "0x8", - "0x40780017fff7fff", - "0x8", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", - "0x20680017fff7fff", - "0x13", - "0x40780017fff7fff", - "0xc", - "0x40780017fff7fff", - "0x1", "0x480680017fff8000", - "0x4f7074696f6e3a3a756e77726170206661696c65642e", - "0x400080007ffe7fff", - "0x480a7ffa7fff8000", - "0x48127fc27fff8000", - "0x480a7ffc7fff8000", - "0x480a7ffd7fff8000", + "0x0", "0x480680017fff8000", - "0x1", - "0x48127ff97fff8000", - "0x482480017ff88000", - "0x1", - "0x208b7fff7fff7ffe", + "0x0", "0x480680017fff8000", "0x0", "0x480680017fff8000", - "0x161bc82433cf4a92809836390ccd14921dfc4dc410cf3d2adbfee5e21ecfec8", + "0x0", "0x480680017fff8000", - "0x53746f726167655772697465", - "0x400280007ffd7fff", - "0x400380017ffd7ffc", - "0x400280027ffd7ffd", - "0x400280037ffd7ffe", - "0x400280047ffd7ffb", - "0x480280067ffd8000", - "0x20680017fff7fff", - "0x28", + "0x0", "0x480680017fff8000", - "0x161bc82433cf4a92809836390ccd14921dfc4dc410cf3d2adbfee5e21ecfec8", - "0x480280057ffd8000", + "0x0", "0x480680017fff8000", "0x0", - "0x482480017ffd8000", - "0x1", "0x480680017fff8000", - "0x53746f726167655772697465", - "0x400280077ffd7fff", - "0x400280087ffd7ffc", - "0x400280097ffd7ffd", - "0x4002800a7ffd7ffe", - "0x4002800b7ffd7ff6", - "0x4802800d7ffd8000", - "0x20680017fff7fff", - "0x10", - "0x40780017fff7fff", - "0x4", - "0x480a7ffa7fff8000", - "0x48127fc27fff8000", - "0x4802800c7ffd8000", - "0x482680017ffd8000", - "0xe", + "0x0", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", + "0x48127fe87fff8000", + "0x48127fe87fff8000", "0x208b7fff7fff7ffe", - "0x4802800c7ffd8000", - "0x482680017ffd8000", - "0x10", - "0x4802800e7ffd8000", - "0x4802800f7ffd8000", + "0x482480017ff18000", + "0x3", + "0x482480017ff88000", + "0x6900", "0x10780017fff7fff", - "0x9", - "0x40780017fff7fff", - "0x6", - "0x480280057ffd8000", - "0x482680017ffd8000", - "0x9", - "0x480280077ffd8000", - "0x480280087ffd8000", - "0x480a7ffa7fff8000", - "0x48127fc27fff8000", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", - "0x480680017fff8000", - "0x1", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x54", + "0x7", "0x40780017fff7fff", - "0x1", + "0x7", + "0x48127ff17fff8000", + "0x482480017ff38000", + "0x6e96", "0x480680017fff8000", - "0x4f7074696f6e3a3a756e77726170206661696c65642e", - "0x400080007ffe7fff", - "0x480a7ffa7fff8000", - "0x480a7ffb7fff8000", - "0x480a7ffc7fff8000", - "0x480a7ffd7fff8000", + "0x0", + "0x48127ff27fff8000", + "0x48127ff27fff8000", "0x480680017fff8000", "0x1", - "0x48127ff97fff8000", - "0x482480017ff88000", - "0x1", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x5e", - "0x40780017fff7fff", - "0x1", - "0x480680017fff8000", - "0x4f7074696f6e3a3a756e77726170206661696c65642e", - "0x400080007ffe7fff", - "0x480a7ffa7fff8000", - "0x480a7ffb7fff8000", - "0x480a7ffc7fff8000", - "0x480a7ffd7fff8000", "0x480680017fff8000", - "0x1", - "0x48127ff97fff8000", - "0x482480017ff88000", - "0x1", - "0x208b7fff7fff7ffe", + "0x0", "0x480680017fff8000", - "0x476574457865637574696f6e496e666f", - "0x400280007ffc7fff", - "0x400380017ffc7ffa", - "0x480280037ffc8000", - "0x20680017fff7fff", - "0x11d", - "0x480280047ffc8000", - "0x480080017fff8000", + "0x0", "0x480680017fff8000", - "0x2691cb735b18f3f656c3b82bd97a32b65d15019b64117513f8604d1e06fe58b", - "0x400280007ffb7fff", - "0x400380017ffb7ffd", - "0x480280027ffb8000", - "0xa0680017fff8005", - "0xe", - "0x4824800180057ffe", - "0x7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00", - "0x484480017ffe8000", - "0x110000000000000000", - "0x48307ffe7fff8003", - "0x480280007ff97ffc", - "0x480280017ff97ffc", - "0x482480017ffb7ffd", - "0xffffffffffffffeefffffffffffffeff", - "0x400280027ff97ffc", - "0x10780017fff7fff", - "0x11", - "0x48127ffe7fff8005", - "0x484480017ffe8000", - "0x8000000000000000000000000000000", - "0x48307ffe7fff8003", - "0x480280007ff97ffd", - "0x482480017ffc7ffe", - "0xf0000000000000000000000000000100", - "0x480280017ff97ffd", - "0x400280027ff97ff9", - "0x402480017ffd7ff9", - "0xffffffffffffffffffffffffffffffff", - "0x20680017fff7ffd", - "0x4", - "0x402780017fff7fff", - "0x1", - "0x480280027ffc8000", + "0x0", "0x480680017fff8000", "0x0", - "0x480080007ff48000", - "0x480080017ff38000", - "0x480080027ff28000", - "0x480080037ff18000", - "0x480080047ff08000", - "0x480080057fef8000", - "0x480080067fee8000", - "0x480080077fed8000", - "0x480080087fec8000", - "0x480080097feb8000", - "0x4800800a7fea8000", - "0x4800800b7fe98000", - "0x4800800c7fe88000", - "0x4800800d7fe78000", - "0x4800800e7fe68000", - "0x4800800f7fe58000", - "0x480080107fe48000", - "0x482680017ffb8000", - "0x3", - "0x482680017ff98000", - "0x3", "0x480680017fff8000", - "0x53746f7261676552656164", - "0x400280057ffc7fff", - "0x400280067ffc7fea", - "0x400280077ffc7feb", - "0x400280087ffc7fe9", - "0x4802800a7ffc8000", - "0x20680017fff7fff", - "0xc8", - "0x480280097ffc8000", + "0x0", "0x480680017fff8000", "0x0", - "0x482480017fe68000", - "0x1", - "0x4802800b7ffc8000", "0x480680017fff8000", - "0x53746f7261676552656164", - "0x4002800c7ffc7fff", - "0x4002800d7ffc7ffb", - "0x4002800e7ffc7ffc", - "0x4002800f7ffc7ffd", - "0x480280117ffc8000", - "0x20680017fff7fff", - "0xb0", + "0x0", "0x480680017fff8000", "0x0", - "0x480280107ffc8000", - "0x482680017ffc8000", - "0x13", - "0x480280127ffc8000", - "0x48307fe480007fe5", - "0xa0680017fff8000", - "0x6", - "0x48307ffe80007ffa", - "0x400080007ff07fff", - "0x10780017fff7fff", - "0x91", - "0x482480017ffa8000", - "0x1", - "0x48307fff80007ffd", - "0x400080007fef7fff", - "0x48307ff87fe08000", "0x480680017fff8000", - "0x1", - "0x480080007ffe8000", - "0x48307fdd80007fde", - "0xa0680017fff8000", - "0x6", - "0x48307ffe80007ffc", - "0x400080017fe97fff", - "0x10780017fff7fff", - "0x70", - "0x482480017ffc8000", - "0x1", - "0x48307fff80007ffd", - "0x400080017fe87fff", - "0x48307ffa7fd98000", + "0x0", "0x480680017fff8000", - "0x2691cb735b18f3f656c3b82bd97a32b65d15019b64117513f8604d1e06fe58b", - "0x400080007fe57fff", - "0x400180017fe57ffd", - "0x480080027fe58000", - "0xa0680017fff8005", - "0xe", - "0x4824800180057ffe", - "0x7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00", - "0x484480017ffe8000", - "0x110000000000000000", - "0x48307ffe7fff8003", - "0x480080027fe17ffc", - "0x480080037fe07ffc", - "0x482480017ffb7ffd", - "0xffffffffffffffeefffffffffffffeff", - "0x400080047fde7ffc", - "0x10780017fff7fff", - "0x11", - "0x48127ffe7fff8005", - "0x484480017ffe8000", - "0x8000000000000000000000000000000", - "0x48307ffe7fff8003", - "0x480080027fe17ffd", - "0x482480017ffc7ffe", - "0xf0000000000000000000000000000100", - "0x480080037fdf7ffd", - "0x400080047fde7ff9", - "0x402480017ffd7ff9", - "0xffffffffffffffffffffffffffffffff", - "0x20680017fff7ffd", - "0x4", - "0x402780017fff7fff", - "0x1", + "0x0", "0x480680017fff8000", "0x0", - "0x48307ff07fe38000", - "0x480080007ff48000", - "0x482480017fda8000", - "0x3", - "0x482480017fda8000", - "0x5", "0x480680017fff8000", - "0x53746f726167655772697465", - "0x400080007fe37fff", - "0x400080017fe37fe2", - "0x400080027fe37ffa", - "0x400080037fe37ff9", - "0x400080047fe37ffb", - "0x480080067fe38000", - "0x20680017fff7fff", - "0x27", - "0x480080057fe28000", + "0x0", "0x480680017fff8000", "0x0", - "0x482480017ff68000", - "0x1", - "0x48307ff87fe08000", "0x480680017fff8000", - "0x53746f726167655772697465", - "0x400080077fdd7fff", - "0x400080087fdd7ffb", - "0x400080097fdd7ffc", - "0x4000800a7fdd7ffd", - "0x4000800b7fdd7ffe", - "0x4800800d7fdd8000", - "0x20680017fff7fff", - "0x10", - "0x40780017fff7fff", - "0x4", - "0x48127ff37fff8000", - "0x4800800c7fd78000", - "0x48127ff07fff8000", - "0x482480017fd58000", - "0xe", + "0x0", "0x480680017fff8000", "0x0", "0x480680017fff8000", @@ -11996,416 +11284,95 @@ "0x480680017fff8000", "0x0", "0x208b7fff7fff7ffe", - "0x4800800c7fdc8000", - "0x482480017fdb8000", - "0x10", - "0x4800800e7fda8000", - "0x4800800f7fd98000", + "0x482680017ffa8000", + "0x3", + "0x482480017ff88000", + "0x7260", "0x10780017fff7fff", - "0x9", + "0x7", "0x40780017fff7fff", - "0x6", - "0x480080057fdc8000", - "0x482480017fdb8000", - "0x9", - "0x480080077fda8000", - "0x480080087fd98000", - "0x48127ff37fff8000", - "0x48127ffb7fff8000", - "0x48127ff07fff8000", - "0x48127ffa7fff8000", + "0x7", + "0x480a7ffa7fff8000", + "0x482480017ff38000", + "0x772e", + "0x480680017fff8000", + "0x0", + "0x48127ff27fff8000", + "0x48127ff27fff8000", "0x480680017fff8000", - "0x1", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1a", - "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x496e646578206f7574206f6620626f756e6473", - "0x400080007ffe7fff", - "0x482480017fcd8000", - "0x2", - "0x48127fd67fff8000", - "0x48127fca7fff8000", - "0x48127fd57fff8000", + "0x0", "0x480680017fff8000", - "0x1", - "0x48127ff97fff8000", - "0x482480017ff88000", - "0x1", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x21", - "0x40780017fff7fff", - "0x1", + "0x0", "0x480680017fff8000", - "0x496e646578206f7574206f6620626f756e6473", - "0x400080007ffe7fff", - "0x482480017fcd8000", - "0x1", - "0x48127fd67fff8000", - "0x48127fca7fff8000", - "0x48127fd57fff8000", + "0x0", "0x480680017fff8000", - "0x1", - "0x48127ff97fff8000", - "0x482480017ff88000", - "0x1", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x26", - "0x480280107ffc8000", - "0x482680017ffc8000", - "0x14", - "0x480280127ffc8000", - "0x480280137ffc8000", - "0x10780017fff7fff", - "0x9", - "0x40780017fff7fff", - "0x2c", - "0x480280097ffc8000", - "0x482680017ffc8000", - "0xd", - "0x4802800b7ffc8000", - "0x4802800c7ffc8000", - "0x48127fcd7fff8000", - "0x48127ffb7fff8000", - "0x48127fca7fff8000", - "0x48127ffa7fff8000", + "0x0", "0x480680017fff8000", - "0x1", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x52", - "0x480a7ff97fff8000", - "0x480280027ffc8000", - "0x480a7ffb7fff8000", - "0x482680017ffc8000", - "0x6", + "0x0", "0x480680017fff8000", - "0x1", - "0x480280047ffc8000", - "0x480280057ffc8000", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x7", + "0x0", "0x480680017fff8000", - "0x7", + "0x0", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", - "0xa0680017fff7fff", - "0x10", - "0x20680017fff7ffd", - "0xe", - "0x20680017fff7ffc", - "0xc", - "0x20680017fff7ffb", - "0x4", - "0x10780017fff7fff", - "0x19b", - "0x402480017fff7ffb", - "0x1", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x195", - "0x482680017ffc8000", - "0x4", - "0x482680017ffc8000", - "0xc", - "0x480680017fff8000", - "0x3", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", - "0x482680017ffc8000", - "0x24", - "0x400080007ff97ffb", - "0x400080017ff97ffc", - "0x400080027ff97ffd", - "0x400080037ff97ffe", - "0x482480017ff98000", - "0x4", - "0x48307fff80007ff9", - "0x20680017fff7fff", - "0x12", - "0x40780017fff7fff", - "0x1", - "0x480680017fff8000", - "0x416c6c20696e707574732068617665206265656e2066696c6c6564", - "0x400080007ffe7fff", - "0x480a7ff97fff8000", - "0x480a7ffa7fff8000", - "0x480a7ffb7fff8000", - "0x48127ff87fff8000", - "0x480a7ffd7fff8000", - "0x480680017fff8000", - "0x1", - "0x48127ff87fff8000", - "0x482480017ff78000", - "0x1", - "0x208b7fff7fff7ffe", - "0x480680017fff8000", - "0x6", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", - "0x400080007ffa7ffc", - "0x400080017ffa7ffd", - "0x400080027ffa7ffe", - "0x400080037ffa7fff", - "0x482480017ffa8000", - "0x4", - "0x48307fff80007ff3", - "0x20680017fff7fff", - "0x14d", - "0x1104800180018000", - "0x1c56", - "0x482480017fff8000", - "0x1c55", "0x480680017fff8000", - "0x2", - "0x482480017ffe8000", - "0x6", - "0x480680017fff8000", - "0x4", + "0x0", + "0x208b7fff7fff7ffe", + "0x480a7ffa7fff8000", + "0x482680017ffb8000", + "0x7c7e", "0x480680017fff8000", "0x0", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", "0x480680017fff8000", "0x1", - "0x4824800180007fea", - "0xc", - "0x400080007fff7ffe", - "0x400080017fff7ffd", - "0x400080027fff7ffd", - "0x400080037fff7ffd", - "0x400280007ffa7fe3", - "0x400280017ffa7fe4", - "0x400280027ffa7fe5", - "0x400280037ffa7fe6", - "0x400280047ffa7fff", - "0x400280057ffa7ff9", - "0x400280067ffa7ffa", - "0x400280007ffb7fe3", - "0x400280017ffb7fe4", - "0x400280027ffb7fe5", - "0x400280037ffb7fe6", - "0x400280047ffb7fff", - "0x400280057ffb7ffb", - "0x480280067ffb8000", - "0x484480017fff8000", - "0x7", - "0x48307ffe80007ffa", - "0x20680017fff7fff", - "0xca", - "0x482480017ffc8000", - "0x20", - "0x480080007fff8000", - "0x480080017ffe8000", - "0x480080027ffd8000", - "0x480080037ffc8000", - "0x402780017ffa8000", - "0xe", - "0x40337ff97ffb8006", - "0x48307fff80007fde", - "0x20680017fff7fff", - "0x13", - "0x48307ffd80007fdc", - "0x20680017fff7fff", - "0xb", - "0x48307ffb80007fda", - "0x20680017fff7fff", - "0x5", - "0x48307ff980007fd8", - "0x10780017fff7fff", - "0xd", - "0x48127fff7fff8000", - "0x10780017fff7fff", - "0xa", - "0x40780017fff7fff", - "0x1", - "0x48127ffe7fff8000", - "0x10780017fff7fff", - "0x5", - "0x40780017fff7fff", - "0x2", - "0x48127ffd7fff8000", - "0x400080007fe27fff", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x480680017fff8000", - "0x6", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", - "0x1104800180018000", - "0xc94", - "0x402580017fd38005", - "0x1", - "0x20680017fff7fff", - "0x8b", - "0x40780017fff7fff", - "0x1", - "0x480a7ff97fff8000", - "0x48127ffe7fff8000", - "0x48127ffd7fff8000", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", "0x480680017fff8000", - "0x617373657274696f6e206661696c65643a20606f7574707574732e6765745f", - "0x480680017fff8000", - "0x1f", - "0x1104800180018000", - "0xca0", - "0x20680017fff7ffb", - "0x70", - "0x48127ffa7fff8000", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", - "0x480680017fff8000", - "0x6f7574707574286d756c29203d3d2075333834207b206c696d62303a20362c", - "0x480680017fff8000", - "0x1f", - "0x1104800180018000", - "0xc93", - "0x20680017fff7ffb", - "0x59", - "0x48127ffa7fff8000", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", - "0x480680017fff8000", - "0x206c696d62313a20302c206c696d62323a20302c206c696d62333a2030207d", - "0x480680017fff8000", - "0x1f", - "0x1104800180018000", - "0xc86", - "0x20680017fff7ffb", - "0x42", - "0x48127ffa7fff8000", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", + "0x0", "0x480680017fff8000", - "0x602e", + "0x0", "0x480680017fff8000", - "0x2", - "0x1104800180018000", - "0xc79", - "0x20680017fff7ffb", - "0x2b", - "0x40780017fff7fff", - "0x1", + "0x0", "0x480680017fff8000", - "0x46a6158a16a947e5916b2a2ca68501a45e93d7110e81aa2d6438b1c57c879a3", - "0x400080007ffe7fff", - "0x40137ffa7fff8001", - "0x40137ffb7fff8002", - "0x40137ffc7fff8003", - "0x40137ffd7fff8004", - "0x4829800180008002", - "0x400080017ffd7fff", - "0x48127ff77fff8000", - "0x480a7ffd7fff8000", - "0x480a80017fff8000", - "0x480a80027fff8000", - "0x48127ff97fff8000", - "0x482480017ff88000", - "0x2", - "0x1104800180018000", - "0x10cb", - "0x20680017fff7ffd", - "0x9", - "0x400180007fff8003", - "0x400180017fff8004", - "0x48127ffe7fff8000", - "0x482480017ffe8000", - "0x2", - "0x10780017fff7fff", - "0x4", - "0x48127ffe7fff8000", - "0x48127ffe7fff8000", - "0x48127ff97fff8000", - "0x480a80007fff8000", - "0x480a80067fff8000", - "0x480a80057fff8000", - "0x48127ff67fff8000", + "0x0", "0x480680017fff8000", - "0x1", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x208b7fff7fff7ffe", - "0x48127ffa7fff8000", - "0x480a80007fff8000", - "0x480a80067fff8000", - "0x480a80057fff8000", - "0x480a7ffd7fff8000", + "0x0", "0x480680017fff8000", - "0x1", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x208b7fff7fff7ffe", - "0x48127ffa7fff8000", - "0x480a80007fff8000", - "0x480a80067fff8000", - "0x480a80057fff8000", - "0x480a7ffd7fff8000", + "0x0", "0x480680017fff8000", - "0x1", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x208b7fff7fff7ffe", - "0x48127ffa7fff8000", - "0x480a80007fff8000", - "0x480a80067fff8000", - "0x480a80057fff8000", - "0x480a7ffd7fff8000", + "0x0", "0x480680017fff8000", - "0x1", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x208b7fff7fff7ffe", - "0x48127ffa7fff8000", - "0x480a80007fff8000", - "0x480a80067fff8000", - "0x480a80057fff8000", - "0x480a7ffd7fff8000", + "0x0", "0x480680017fff8000", - "0x1", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x208b7fff7fff7ffe", - "0x480a7ff97fff8000", - "0x480a80007fff8000", - "0x480a80067fff8000", - "0x480a80057fff8000", - "0x480a7ffd7fff8000", + "0x0", "0x480680017fff8000", "0x0", "0x480680017fff8000", @@ -12414,1797 +11381,2295 @@ "0x0", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0x1", - "0x480680017fff8000", - "0x526573756c743a3a756e77726170206661696c65642e", - "0x400080007ffe7fff", - "0x48327ffc7ffb8000", - "0x480680017fff8000", - "0x0", + "0x15", "0x480680017fff8000", - "0x1", - "0x484480017ff88000", - "0x3", - "0x48307fff7ff28000", - "0x400080027fff7ffc", - "0x480080017fff8000", - "0x480080007ffe8000", - "0x48307ff380007fe2", - "0x400080007fe17ff9", - "0x400080017fe17ff9", - "0x400080027fe17ff9", - "0x400080037fe17ff9", - "0x4800800080007ffe", - "0x400080017fff7ffc", - "0x400080027fff7ffe", - "0x400080047fe07ff2", - "0x48307ff280007fee", - "0x400080057fdf7fff", - "0x400080007ff67fd4", - "0x400080017ff67fd5", - "0x400080027ff67fd6", - "0x400080037ff67fd7", - "0x400080047ff67ff0", - "0x400080057ff67ffe", - "0x400080067ff67ff8", - "0x48307ffc7ff08000", + "0x476574457865637574696f6e496e666f", + "0x400280007fe67fff", + "0x400380017fe67fe5", + "0x480280037fe68000", + "0x20680017fff7fff", + "0x190", + "0x480280027fe68000", + "0x480280047fe68000", + "0x480080007fff8000", "0x480080007fff8000", "0x480080017ffe8000", "0x480080027ffd8000", - "0x480080037ffc8000", - "0x20680017fff7ffc", - "0x9", - "0x20680017fff7ffd", - "0x7", - "0x20680017fff7ffe", + "0x402780017fe68001", "0x5", + "0x48127ffa7fff8000", + "0x480080017ffa8000", + "0x400180027ff98000", + "0x400180037ff98003", + "0x400180047ff98002", + "0x48287fe780007ffb", "0x20680017fff7fff", - "0x3", - "0x40127ff27fff7ff3", - "0x482680017ffa8000", - "0xe", - "0x48127fee7fff8000", - "0x482480017fed8000", - "0x1", - "0x482480017fd78000", + "0x4", + "0x10780017fff7fff", "0x6", - "0x482480017fed8000", + "0x482480017ffd8000", + "0x4b6e", + "0x10780017fff7fff", + "0xa", + "0x48127ffd7fff8000", + "0x48287fe880007ffa", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x6", + "0x482480017ffe8000", + "0x4a42", + "0x10780017fff7fff", + "0x162", + "0x48287fe980007ffa", + "0x48127ffd7fff8000", + "0x20680017fff7ffe", + "0x15c", + "0x400180007ffa8004", + "0x400180017ffa8005", + "0x400180027ffa8006", + "0x400180037ffa8007", + "0x400180047ffa8008", + "0x400180057ffa8009", + "0x400180067ffa800a", + "0x400180077ffa800b", + "0x400180087ffa800c", + "0x400180097ffa800d", + "0x4001800a7ffa800e", + "0x4001800b7ffa800f", + "0x4001800c7ffa8010", + "0x4001800d7ffa8011", + "0x4001800e7ffa8012", + "0x4001800f7ffa8013", + "0x400180107ffa8014", + "0x48297fea80008004", + "0x48127ffe7fff8000", + "0x20680017fff7ffe", + "0x135", + "0x48297feb80008005", + "0x48127ffe7fff8000", + "0x20680017fff7ffe", + "0x12d", + "0x48127fff7fff8000", + "0x48297fec80008006", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x6", + "0x482480017ffe8000", + "0x3e6c", + "0x10780017fff7fff", + "0x129", + "0x4829800780008008", + "0x48297fed80007fee", + "0x48127ffc7fff8000", + "0x48307ffe80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x7", + "0x480a7fe47fff8000", + "0x482480017ffd8000", + "0x3c14", + "0x10780017fff7fff", + "0x12", + "0x480a7fe47fff8000", + "0x48127ffd7fff8000", + "0x480a80077fff8000", + "0x480a80087fff8000", + "0x480a7fed7fff8000", + "0x480a7fee7fff8000", + "0x1104800180018000", + "0x1309", + "0x20680017fff7ffa", + "0xff", + "0x48127ff97fff8000", + "0x20680017fff7ffe", "0x7", - "0x48307ffa80007fcd", + "0x48127ff77fff8000", + "0x482480017ffe8000", + "0x31a6", + "0x10780017fff7fff", + "0x10c", + "0x48297fef80008009", + "0x48127ffe7fff8000", + "0x20680017fff7ffe", + "0xee", + "0x48297ff08000800a", + "0x48127ffe7fff8000", + "0x20680017fff7ffe", + "0xe5", + "0x48297ff18000800b", + "0x48127ffe7fff8000", + "0x20680017fff7ffe", + "0xdc", + "0x4829800c8000800d", + "0x48297ff280007ff3", + "0x4844800180007ffe", + "0x3", + "0x4844800180007ffe", + "0x3", + "0x48127ffb7fff8000", + "0x48307ffe80007ffd", "0x20680017fff7fff", - "0x13", - "0x48307ff880007fcb", + "0x4", + "0x10780017fff7fff", + "0x7", + "0x48127feb7fff8000", + "0x482480017ffd8000", + "0x2b02", + "0x10780017fff7fff", + "0x12", + "0x48127feb7fff8000", + "0x48127ffd7fff8000", + "0x480a800c7fff8000", + "0x480a800d7fff8000", + "0x480a7ff27fff8000", + "0x480a7ff37fff8000", + "0x1104800180018000", + "0x1356", + "0x20680017fff7ffa", + "0xba", + "0x48127ff97fff8000", + "0x20680017fff7ffe", + "0x7", + "0x48127ff77fff8000", + "0x482480017ffe8000", + "0x2094", + "0x10780017fff7fff", + "0xdd", + "0x48127fff7fff8000", + "0x48297ff48000800e", "0x20680017fff7fff", - "0xb", - "0x48307ff680007fc9", + "0x4", + "0x10780017fff7fff", + "0x7", + "0x48127ff57fff8000", + "0x482480017ffd8000", + "0x1f68", + "0x10780017fff7fff", + "0xd2", + "0x4829800f80008010", + "0x48297ff580007ff6", + "0x48127ffc7fff8000", + "0x48307ffe80007ffd", "0x20680017fff7fff", - "0x5", - "0x48307ff480007fc7", + "0x4", "0x10780017fff7fff", - "0xd", + "0x7", + "0x48127ff17fff8000", + "0x482480017ffd8000", + "0x1cac", + "0x10780017fff7fff", + "0x12", + "0x48127ff17fff8000", + "0x48127ffd7fff8000", + "0x480a800f7fff8000", + "0x480a80107fff8000", + "0x480a7ff57fff8000", + "0x480a7ff67fff8000", + "0x1104800180018000", + "0x12b0", + "0x20680017fff7ffa", + "0x89", + "0x48127ff97fff8000", + "0x20680017fff7ffe", + "0x7", + "0x48127ff77fff8000", + "0x482480017ffe8000", + "0x123e", + "0x10780017fff7fff", + "0xb3", "0x48127fff7fff8000", + "0x48297ff780008011", + "0x20680017fff7fff", + "0x4", "0x10780017fff7fff", - "0xa", - "0x40780017fff7fff", - "0x1", + "0x7", + "0x48127ff57fff8000", + "0x482480017ffd8000", + "0x1112", + "0x10780017fff7fff", + "0xa8", "0x48127ffe7fff8000", + "0x48297ff880008012", + "0x20680017fff7fff", + "0x4", "0x10780017fff7fff", - "0x5", - "0x40780017fff7fff", - "0x2", + "0x7", + "0x48127ff37fff8000", + "0x482480017ffd8000", + "0xf82", + "0x10780017fff7fff", + "0x9d", + "0x4829801380008014", + "0x48297ff980007ffa", + "0x48127ffc7fff8000", + "0x48307ffe80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x7", + "0x48127fef7fff8000", + "0x482480017ffd8000", + "0xd2a", + "0x10780017fff7fff", + "0x90", + "0x48127fef7fff8000", "0x48127ffd7fff8000", - "0x400080007ffa7fff", + "0x480a80137fff8000", + "0x480a80147fff8000", "0x480a7ff97fff8000", - "0x48127ff67fff8000", + "0x480a7ffa7fff8000", + "0x1104800180018000", + "0x127b", + "0x20680017fff7ffa", + "0x4d", "0x48127ff97fff8000", - "0x482480017ff78000", - "0x1", - "0x480a7ffd7fff8000", + "0x20680017fff7ffe", + "0x7", + "0x48127ff77fff8000", + "0x482480017ffe8000", + "0x258", + "0x10780017fff7fff", + "0x7e", + "0x48297ffb80008000", + "0x48127ffe7fff8000", + "0x20680017fff7ffe", + "0x32", + "0x48297ffc80008003", + "0x48127ffe7fff8000", + "0x20680017fff7ffe", + "0x1f", + "0x48297ffd80008002", + "0x48127ffe7fff8000", + "0x20680017fff7ffe", + "0xd", + "0x48127ff17fff8000", + "0x482480017ffe8000", + "0x12c", + "0x480a80017fff8000", "0x480680017fff8000", - "0x1", - "0x48127ff27fff8000", - "0x48127ff27fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4e6f7420616c6c20696e707574732068617665206265656e2066696c6c6564", + "0x53454c4543544f525f4d49534d41544348", "0x400080007ffe7fff", - "0x480a7ff97fff8000", - "0x480a7ffa7fff8000", - "0x480a7ffb7fff8000", - "0x48127ff27fff8000", - "0x480a7ffd7fff8000", + "0x48127fef7fff8000", + "0x48127ffc7fff8000", + "0x480a80017fff8000", "0x480680017fff8000", "0x1", - "0x48127ff87fff8000", - "0x482480017ff78000", + "0x48127ffa7fff8000", + "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x434f4e54524143545f4d49534d41544348", "0x400080007ffe7fff", - "0x480a7ff97fff8000", - "0x480a7ffa7fff8000", - "0x480a7ffb7fff8000", - "0x480a7ffc7fff8000", - "0x480a7ffd7fff8000", + "0x48127ff17fff8000", + "0x482480017ffc8000", + "0x12c", + "0x480a80017fff8000", "0x480680017fff8000", "0x1", - "0x48127ff87fff8000", - "0x482480017ff78000", - "0x1", - "0x208b7fff7fff7ffe", - "0x482680017ffd8000", - "0x4", - "0x482680017ffd8000", - "0x8", - "0x480680017fff8000", - "0x3", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x482680017ffd8000", - "0xc", - "0x400080007ff97ffb", - "0x400080017ff97ffc", - "0x400080027ff97ffd", - "0x400080037ff97ffe", + "0x48127ffa7fff8000", "0x482480017ff98000", - "0x4", - "0x48307fff80007ff9", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x2", - "0x48127ffd7fff8000", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", + "0x1", "0x208b7fff7fff7ffe", - "0x480680017fff8000", - "0x476574436c617373486173684174", - "0x400280007ff97fff", - "0x400380017ff97ff8", - "0x400380027ff97ffa", - "0x480280047ff98000", - "0x20680017fff7fff", - "0x103", - "0x480280037ff98000", - "0x480280057ff98000", - "0x480680017fff8000", - "0x43616c6c436f6e7472616374", - "0x400280067ff97fff", - "0x400280077ff97ffd", - "0x400380087ff97ffa", - "0x400380097ff97ffb", - "0x4003800a7ff97ffc", - "0x4003800b7ff97ffd", - "0x4802800d7ff98000", - "0x20680017fff7fff", - "0x1c", - "0x40780017fff7fff", - "0x18", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x46a6158a16a947e5916b2a2ca68501a45e93d7110e81aa2d6438b1c57c879a3", + "0x43414c4c45525f4d49534d41544348", "0x400080007ffe7fff", - "0x480680017fff8000", - "0x0", - "0x400080017ffd7fff", - "0x480680017fff8000", - "0x457870656374656420726576657274", - "0x400080027ffc7fff", - "0x480680017fff8000", - "0xf", - "0x400080037ffb7fff", - "0x480a7ff77fff8000", - "0x4802800c7ff98000", - "0x482680017ff98000", - "0x10", + "0x48127ff37fff8000", + "0x482480017ffc8000", + "0x258", + "0x480a80017fff8000", "0x480680017fff8000", "0x1", - "0x48127ff77fff8000", - "0x482480017ff68000", - "0x4", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", "0x208b7fff7fff7ffe", - "0x4802800e7ff98000", - "0x4802800f7ff98000", - "0x4802800c7ff98000", - "0x482680017ff98000", - "0x10", - "0x48307ffc80007ffd", - "0x20680017fff7fff", - "0x4", + "0x48127ff87fff8000", + "0x482480017ff88000", + "0x384", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", "0x10780017fff7fff", - "0xc2", - "0x4824800180007ffc", - "0x1", - "0x480080007fff8000", - "0x4824800180007fff", - "0x454e545259504f494e545f4641494c4544", + "0x24", "0x48127ff87fff8000", - "0x4824800180007ff8", - "0x1", - "0x20680017fff7ffd", - "0xa8", - "0x48307ffe80007fff", - "0x20680017fff7fff", - "0x4", + "0x482480017ff88000", + "0x136a", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", "0x10780017fff7fff", - "0x93", - "0x4824800180007ffe", - "0x1", - "0x4825800180007ffb", - "0x1c4e1062ccac759d9786c18a401086aa7ab90fde340fffd5cbd792d11daa7e7", - "0x480080007ffe8000", - "0x20680017fff7ffe", - "0x18", - "0x4824800180007fff", - "0x454e545259504f494e545f4e4f545f464f554e44", - "0x20680017fff7fff", - "0x4", + "0x1d", + "0x48127ff87fff8000", + "0x482480017ff88000", + "0x21c0", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", "0x10780017fff7fff", "0x16", - "0x40780017fff7fff", - "0xc", - "0x40780017fff7fff", - "0x1", - "0x480680017fff8000", - "0x556e6578706563746564206572726f72", - "0x400080007ffe7fff", - "0x480a7ff77fff8000", - "0x48127fe47fff8000", - "0x48127fe47fff8000", + "0x48127ff17fff8000", + "0x482480017ffe8000", + "0x2e22", + "0x10780017fff7fff", + "0x21", + "0x48127ff37fff8000", + "0x482480017ffe8000", + "0x2f4e", + "0x10780017fff7fff", + "0x1c", + "0x48127ff57fff8000", + "0x482480017ffe8000", + "0x307a", + "0x10780017fff7fff", + "0x17", + "0x48127ff87fff8000", + "0x482480017ff88000", + "0x3336", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", + "0x480a80017fff8000", "0x480680017fff8000", "0x1", "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", - "0x4824800180007fff", - "0x746573745f7265766572745f68656c706572", - "0x20680017fff7fff", - "0x62", - "0x480680017fff8000", - "0x476574436c617373486173684174", - "0x400080007ff37fff", - "0x400080017ff37ff2", - "0x400180027ff37ffa", - "0x480080047ff38000", - "0x20680017fff7fff", - "0x4f", - "0x480080037ff28000", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x1275130f95dda36bcbb6e9d28796c1d7e10b6e9fd5ed083e0ede4b12f613528", - "0x480080057fef8000", - "0x480680017fff8000", - "0x53746f7261676552656164", - "0x400080067fed7fff", - "0x400080077fed7ffb", - "0x400080087fed7ffc", - "0x400080097fed7ffd", - "0x4800800b7fed8000", - "0x20680017fff7fff", - "0x35", - "0x4800800c7fec8000", - "0x4800800a7feb8000", - "0x482480017fea8000", - "0xd", - "0x20680017fff7ffd", - "0x1f", - "0x48307ffa80007fe3", - "0x20680017fff7fff", - "0xe", - "0x40780017fff7fff", - "0x2", - "0x480a7ff77fff8000", - "0x48127ffa7fff8000", "0x48127ffa7fff8000", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", "0x208b7fff7fff7ffe", + "0x482480017fff8000", + "0x3f98", + "0x10780017fff7fff", + "0x4", + "0x482480017fff8000", + "0x4128", + "0x480a7fe47fff8000", + "0x48127ffe7fff8000", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x636c61737320686173682073686f756c64206e6f74206368616e67652e", + "0x54585f494e464f5f4d49534d41544348", "0x400080007ffe7fff", - "0x480a7ff77fff8000", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", + "0x480a80017fff8000", "0x480680017fff8000", "0x1", "0x48127ffa7fff8000", "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", + "0x482480017fff8000", + "0x4916", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x76616c7565732073686f756c64206e6f74206368616e67652e", + "0x424c4f434b5f494e464f5f4d49534d41544348", "0x400080007ffe7fff", - "0x480a7ff77fff8000", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", + "0x480a7fe47fff8000", + "0x48127ffc7fff8000", + "0x480a80017fff8000", "0x480680017fff8000", "0x1", "0x48127ffa7fff8000", "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x40780017fff7fff", + "0x480280027fe68000", + "0x480a7fe47fff8000", + "0x482480017ffe8000", + "0x52b2", + "0x482680017fe68000", "0x6", - "0x480a7ff77fff8000", - "0x4800800a7fe58000", - "0x482480017fe48000", - "0xe", - "0x480680017fff8000", - "0x1", - "0x4800800c7fe28000", - "0x4800800d7fe18000", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0xc", - "0x480a7ff77fff8000", - "0x480080037fe58000", - "0x482480017fe48000", - "0x7", "0x480680017fff8000", "0x1", - "0x480080057fe28000", - "0x480080067fe18000", + "0x480280047fe68000", + "0x480280057fe68000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0xc", - "0x40780017fff7fff", "0x1", + "0x400180007fff7ff9", + "0x400180017fff7ffb", "0x480680017fff8000", - "0x556e6578706563746564206572726f72", - "0x400080007ffe7fff", - "0x480a7ff77fff8000", - "0x48127fe47fff8000", - "0x48127fe47fff8000", - "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", + "0x2", + "0x400080027ffe7fff", + "0x482680017ffc8000", "0x1", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x10", - "0x40780017fff7fff", + "0x400080037ffd7fff", + "0x482680017ffd8000", "0x1", + "0x400080047ffc7fff", + "0x48127ffc7fff8000", + "0x482480017ffb8000", + "0x5", "0x480680017fff8000", - "0x4f7074696f6e3a3a756e77726170206661696c65642e", - "0x400080007ffe7fff", - "0x480a7ff77fff8000", - "0x48127fe47fff8000", - "0x48127fe47fff8000", - "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x11", + "0x4c69627261727943616c6c", + "0x400280007ff87fff", + "0x400380017ff87ff7", + "0x400380027ff87ff9", + "0x400380037ff87ffa", + "0x400280047ff87ffd", + "0x400280057ff87ffe", + "0x480280077ff88000", + "0x20680017fff7fff", + "0x28", + "0x480280067ff88000", "0x40780017fff7fff", "0x1", + "0x400180007fff7ffc", + "0x400180017fff7ffd", + "0x48127ffe7fff8000", + "0x48127ffe7fff8000", + "0x482480017ffd8000", + "0x2", "0x480680017fff8000", - "0x556e6578706563746564206572726f72", - "0x400080007ffe7fff", - "0x480a7ff77fff8000", - "0x48127fe47fff8000", - "0x48127fe47fff8000", + "0x4c69627261727943616c6c", + "0x4002800a7ff87fff", + "0x4002800b7ff87ffc", + "0x4003800c7ff87ff9", + "0x4003800d7ff87ffb", + "0x4002800e7ff87ffd", + "0x4002800f7ff87ffe", + "0x480280117ff88000", + "0x20680017fff7fff", + "0xb", + "0x480280107ff88000", + "0x48127fff7fff8000", + "0x482680017ff88000", + "0x14", "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", + "0x0", + "0x480280127ff88000", + "0x480280137ff88000", "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x16", - "0x40780017fff7fff", - "0x1", - "0x480680017fff8000", - "0x4f7074696f6e3a3a756e77726170206661696c65642e", - "0x400080007ffe7fff", - "0x480a7ff77fff8000", - "0x48127fe47fff8000", - "0x48127fe47fff8000", + "0x480280107ff88000", + "0x48127fff7fff8000", + "0x482680017ff88000", + "0x14", "0x480680017fff8000", "0x1", - "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", + "0x480280127ff88000", + "0x480280137ff88000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0x21", - "0x480a7ff77fff8000", - "0x480280037ff98000", - "0x482680017ff98000", "0x7", + "0x480280067ff88000", + "0x482480017fff8000", + "0x2ca6", + "0x482680017ff88000", + "0xa", "0x480680017fff8000", "0x1", - "0x480280057ff98000", - "0x480280067ff98000", + "0x480280087ff88000", + "0x480280097ff88000", "0x208b7fff7fff7ffe", - "0x48297ffc80007ffd", - "0x20680017fff7fff", + "0x480a7ffa7fff8000", + "0x480a7ffc7fff8000", + "0x480a7ffb7fff8000", + "0x480a7ffd7fff8000", + "0x1104800180018000", "0x4", "0x10780017fff7fff", - "0xa", - "0x482680017ffc8000", + "0xb2", + "0x48037ffd7ffc8002", + "0x48037ffe7ffc8003", + "0x48037fff7ffc8004", + "0x480380007ffa8000", + "0x4825800180018003", + "0x1", + "0x4828800080018000", + "0x480280017ffa8000", + "0x4846800180008000", + "0x3", + "0x48327fff80028000", + "0x400180027fff8004", + "0x400180017fff7ffd", + "0x400380007ffc8002", + "0x400380017ffc8003", + "0x4826800180048000", "0x1", + "0x400280027ffc7fff", + "0x482680017ffa8000", + "0x2", + "0x480080007ffd8000", "0x480a7ffd7fff8000", - "0x480680017fff8000", - "0x0", - "0x480a7ffc7fff8000", + "0x40337ffe80017ffd", + "0x1104800180018000", + "0xf", + "0x48307fff80007ffe", + "0x48317fff80008001", + "0x4844800180007fff", + "0x3", + "0x484480017fff8000", + "0xfd2", + "0x48127ff97fff8000", + "0x48327ffe7ffb8000", + "0x482680017ffc8000", + "0x3", + "0x48127ff87fff8000", + "0x48127ff67fff8000", + "0x208b7fff7fff7ffe", + "0x482b7ffc80007ffd", + "0x40780017fff7fff", + "0x3", + "0x20780017fff8000", + "0x6", + "0x480a7ffb7fff8000", + "0x480a80037fff8000", + "0x480a80037fff8000", + "0x208b7fff7fff7ffe", + "0x4845800180008000", + "0x3", + "0xa0780017fff8002", + "0x7", + "0x400380007ffb8001", + "0x402680017ffb7fff", + "0x1", "0x10780017fff7fff", - "0x8", + "0x3", + "0x400a7ffb7fff7fff", "0x480a7ffc7fff8000", - "0x480a7ffd7fff8000", - "0x480680017fff8000", + "0x4825800180007ffd", "0x1", - "0x480680017fff8000", + "0x480a80017fff8000", + "0x48127ffb7fff8000", + "0x480a80037fff8000", + "0x480a80027fff8000", + "0x1104800180018000", + "0x4", + "0x480a80037fff8000", + "0x208b7fff7fff7ffe", + "0x480280007ff78002", + "0x4844800180018002", + "0x3", + "0x483280017ff88004", + "0x4800800280038004", + "0x482680017ff78004", + "0x1", + "0x4801800080017ffa", + "0x480380007ffc7ffa", + "0x480080017fff7ffd", + "0x480280017ffc7ffc", + "0x400680017fff7ffb", "0x0", - "0x20680017fff7ffe", - "0x98", + "0x20680017fff7ffc", + "0xf", "0x480080007fff8000", - "0xa0680017fff8000", - "0x12", - "0x4824800180007ffe", - "0x100000000", - "0x4844800180008002", - "0x8000000000000110000000000000000", - "0x4830800080017ffe", - "0x480280007ffb7fff", - "0x482480017ffe8000", - "0xefffffffffffffde00000000ffffffff", - "0x480280017ffb7fff", - "0x400280027ffb7ffb", - "0x402480017fff7ffb", - "0xffffffffffffffffffffffffffffffff", - "0x20680017fff7fff", - "0x78", - "0x402780017fff7fff", + "0x482480017fff8000", "0x1", - "0x400280007ffb7ffe", - "0x482480017ffe8000", - "0xffffffffffffffffffffffff00000000", - "0x400280017ffb7fff", - "0x480680017fff8000", - "0x0", - "0x48307ff880007ff9", - "0x48307ffb7ffe8000", - "0xa0680017fff8000", - "0x8", - "0x482480017ffd8000", + "0x484480017fff8000", + "0x3", + "0x48307fff7ffa8001", + "0x4800800180007ffa", + "0x480080027fff8000", + "0x480180007ffe7ffa", + "0x402480017ff87fff", "0x1", - "0x48307fff80007ffd", - "0x400280027ffb7fff", - "0x10780017fff7fff", - "0x51", - "0x48307ffe80007ffd", - "0x400280027ffb7fff", - "0x48307ff480007ff5", - "0x48307ffa7ff38000", - "0x48307ffb7ff28000", - "0x48307ff580017ffd", - "0xa0680017fff7fff", + "0x20680017fff7ffc", + "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffff6", + "0x48317ffd80007ff9", + "0x400080007ffe7fff", + "0x48287ff780007ffe", + "0x400280027ffc7ffc", + "0x40337fff80017ffb", + "0x20780017fff8001", "0x7", - "0x482480017fff8000", - "0x100000000000000000000000000000000", - "0x400280037ffb7fff", - "0x10780017fff7fff", - "0x2f", - "0x400280037ffb7fff", - "0x48307fef80007ff0", - "0x48307ffe7ff28000", - "0xa0680017fff8000", - "0x8", "0x482480017ffd8000", "0x1", - "0x48307fff80007ffd", - "0x400280047ffb7fff", - "0x10780017fff7fff", - "0x11", - "0x48307ffe80007ffd", - "0x400280047ffb7fff", - "0x40780017fff7fff", + "0x482680017ffc8000", "0x3", - "0x482680017ffb8000", + "0x208b7fff7fff7ffe", + "0x20780017fff7ffd", + "0xe", + "0x482680017ffa8000", + "0x1", + "0x48317fff80008000", + "0x400080017ffb7fff", + "0x482480017ffb8000", + "0x2", + "0x480a7ff87fff8000", + "0x480a7ff97fff8000", + "0x480a80007fff8000", + "0x480a80017fff8000", + "0x10780017fff7fff", + "0x32", + "0x4829800080007ffa", + "0x20680017fff7fff", + "0x4", + "0x402780017fff7fff", + "0x1", + "0x480080017ffc8000", + "0x480080027ffb8000", + "0x484480017fff8000", + "0x2aaaaaaaaaaaab05555555555555556", + "0x48307fff7ffd8000", + "0x480080037ff88000", + "0x480080047ff78000", + "0x484480017fff8000", + "0x4000000000000088000000000000001", + "0x48307fff7ffd8000", + "0x48307fff7ffb8000", + "0x48507ffe7ffa8000", + "0xa0680017fff8000", + "0xc", + "0x484680017ffa8000", + "0x800000000000011000000000000000000000000000000000000000000000000", + "0x402480017fff7ffc", + "0x800000000000011000000000000000000000000000000000000000000000000", + "0x4829800080007ffa", + "0x4826800180008000", + "0x1", + "0x40507fff7ffe7ffb", + "0x10780017fff7fff", + "0xf", + "0xa0680017fff8000", + "0xa", + "0x4846800180008000", + "0x800000000000011000000000000000000000000000000000000000000000000", + "0x482480017fff8000", + "0x800000000000011000000000000000000000000000000000000000000000000", + "0x40327fff7ffa7ffa", + "0x40527fff7ffa7ffb", + "0x10780017fff7fff", "0x5", - "0x480680017fff8000", - "0x0", - "0x48307fea7fe68000", - "0x48307ff77fe58000", - "0x480680017fff8000", - "0x0", - "0x48127ff07fff8000", - "0x48127ff07fff8000", + "0x480a80007fff7ffc", + "0x48297ffa80008000", + "0x40527fff7ffa7ffb", + "0x482480017fee8000", + "0x5", + "0x480a7ff87fff8000", + "0x480a7ff97fff8000", + "0x480a80007fff8000", + "0x480a80017fff8000", + "0x482680017ffc8000", + "0x3", + "0x480a7ffd7fff8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffff98", + "0x208b7fff7fff7ffe", + "0x48127ffb7fff8000", + "0x48127ffc7fff8000", + "0x48127ffa7fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1", + "0xa0680017fff8000", + "0x7", + "0x482680017ffc8000", + "0xffffffffffffffffffffffffffffdc1a", + "0x400280007ffb7fff", + "0x10780017fff7fff", + "0xb3", + "0x4825800180007ffc", + "0x23e6", + "0x400280007ffb7fff", "0x480680017fff8000", - "0x496e646578206f7574206f6620626f756e6473", - "0x400080007ffe7fff", + "0x1", + "0x48127ffe7fff8000", + "0x48317ffe80017ffd", + "0xa0680017fff7fff", + "0x7", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400280017ffb7fff", + "0x10780017fff7fff", + "0x96", + "0x400280017ffb7fff", "0x482680017ffb8000", - "0x5", + "0x2", + "0x48127ffc7fff8000", + "0x48127ffd7fff8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffe5", + "0x20680017fff7ffd", + "0x85", + "0x480680017fff8000", + "0x2", + "0x40137ffe7fff8000", + "0x48127ffb7fff8000", + "0x48317ffe80017ffd", + "0xa0680017fff7fff", + "0x7", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400080007ff67fff", + "0x10780017fff7fff", + "0x6a", + "0x400080007ff77fff", + "0x482480017ff78000", + "0x1", + "0x48127ffc7fff8000", + "0x48127ffd7fff8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffd0", + "0x20680017fff7ffd", + "0x59", "0x480680017fff8000", + "0x2", + "0x40780017fff7fff", + "0x2", + "0x4824800180008002", + "0xffffffffffffffff0000000000000000", + "0x480080007ff78001", + "0x480080017ff67ffe", + "0x400080027ff57ffe", + "0x484480017ffe8000", + "0x10000000000000000", + "0x40307ffc7fff7ff9", + "0x48507ff87ffc8000", + "0x48507ff77ffc8000", + "0x4824800180018002", + "0xffffffffffffffff0000000000000000", + "0x480080037ff18001", + "0x480080047ff07fff", + "0x400080057fef7ffd", + "0x484480017ffd8000", + "0x10000000000000000", + "0x40307ffd7fff7ffb", + "0x484480017ffd8000", + "0x10000000000000000", + "0x48307fff7ff98003", + "0x482480017fff8000", + "0xfffffffffffffffe0000000000000000", + "0x480080067feb7fff", + "0x480080077fea7ffd", + "0x400080087fe97ff0", + "0x404480017ffc7ffe", + "0x100000000000000000000000000000000", + "0x40307ff07ffe7fff", + "0x40307ffc7ff77fef", + "0x48127fea7fff8000", + "0x482480017fe88000", + "0x9", + "0x20680017fff7fed", + "0x24", + "0x48127ffe7fff8000", + "0x48327fed80008001", + "0xa0680017fff7fff", + "0x7", + "0x4824800180007fff", + "0x100000000000000000000000000000000", + "0x400080007ffb7fff", + "0x10780017fff7fff", + "0xd", + "0x400080007ffc7fff", + "0x482480017ffc8000", "0x1", + "0x482480017ffc8000", + "0x1f4", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", + "0x48127ffb7fff8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", + "0x753132385f616464204f766572666c6f77", + "0x400080007ffe7fff", + "0x482480017ff98000", + "0x1", "0x48127ff97fff8000", - "0x482480017ff88000", + "0x480680017fff8000", + "0x1", + "0x48127ffb7fff8000", + "0x482480017ffa8000", "0x1", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0x4", - "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x7533325f737562204f766572666c6f77", + "0x753132385f6d756c204f766572666c6f77", "0x400080007ffe7fff", - "0x482680017ffb8000", - "0x4", + "0x48127ffd7fff8000", + "0x482480017ffb8000", + "0x29e", "0x480680017fff8000", "0x1", + "0x48127ffb7fff8000", + "0x482480017ffa8000", + "0x1", + "0x208b7fff7fff7ffe", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x1130", "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x48127ff97fff8000", - "0x482480017ff88000", "0x1", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0x9", - "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x496e646578206f7574206f6620626f756e6473", + "0x753132385f737562204f766572666c6f77", "0x400080007ffe7fff", - "0x482680017ffb8000", - "0x3", - "0x480680017fff8000", + "0x482480017ff48000", "0x1", + "0x482480017ff98000", + "0x16f8", "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", + "0x1", + "0x48127ffb7fff8000", + "0x482480017ffa8000", + "0x1", + "0x208b7fff7fff7ffe", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x1b80", "0x480680017fff8000", - "0x0", - "0x48127ff97fff8000", - "0x482480017ff88000", "0x1", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0xc", - "0x482680017ffb8000", - "0x3", - "0x480680017fff8000", - "0x0", - "0x48127fe67fff8000", - "0x48127fe67fff8000", - "0x480680017fff8000", "0x1", "0x480680017fff8000", - "0x0", + "0x753132385f737562204f766572666c6f77", + "0x400080007ffe7fff", + "0x482680017ffb8000", + "0x2", + "0x482480017ff98000", + "0x2148", "0x480680017fff8000", - "0x0", + "0x1", + "0x48127ffb7fff8000", + "0x482480017ffa8000", + "0x1", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0x14", - "0x480a7ffb7fff8000", - "0x480680017fff8000", - "0x0", - "0x48127fe67fff8000", - "0x48127fe67fff8000", - "0x480680017fff8000", "0x1", "0x480680017fff8000", - "0x0", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x482680017ffb8000", + "0x1", + "0x480a7ffc7fff8000", "0x480680017fff8000", - "0x0", + "0x1", + "0x48127ffb7fff8000", + "0x482480017ffa8000", + "0x1", "0x208b7fff7fff7ffe", - "0xa0680017fff8000", - "0x7", - "0x482680017ff88000", - "0xffffffffffffffffffffffffffffe304", - "0x400280007ff77fff", - "0x10780017fff7fff", - "0x37", - "0x4825800180007ff8", - "0x1cfc", - "0x400280007ff77fff", - "0x482680017ff78000", + "0x40780017fff7fff", "0x1", - "0x20780017fff7ffd", - "0xd", - "0x48127fff7fff8000", - "0x48127ffd7fff8000", "0x480680017fff8000", - "0x0", - "0x480a7ff97fff8000", - "0x480a7ffa7fff8000", + "0x1", "0x480680017fff8000", "0x0", + "0x400080007ffd7ffe", + "0x400080017ffd7fff", + "0x40780017fff7fff", + "0x1", "0x480a7ffb7fff8000", "0x480a7ffc7fff8000", - "0x208b7fff7fff7ffe", - "0x48127fff7fff8000", - "0x480a7ff97fff8000", - "0x480a7ffa7fff8000", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x2", + "0x48127ffb7fff8000", + "0x48127ffa7fff8000", "0x1104800180018000", - "0xe2d", - "0x20680017fff7ffc", - "0x11", - "0x400280007ffc7ffd", - "0x400280017ffc7ffe", - "0x400280027ffc7fff", + "0x10fb", + "0x20680017fff7ffb", + "0xb7", "0x48127ff97fff8000", - "0x48127fd87fff8000", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x480a7ffb7fff8000", - "0x482680017ffc8000", - "0x3", - "0x4825800180007ffd", - "0x1", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffd5", - "0x208b7fff7fff7ffe", "0x48127ff97fff8000", - "0x48127fd87fff8000", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", "0x480680017fff8000", "0x0", - "0x48127ff77fff8000", - "0x48127ff77fff8000", - "0x480680017fff8000", - "0x1", "0x480680017fff8000", "0x0", + "0x1104800180018000", + "0x114e", + "0x20680017fff7ffd", + "0xa3", + "0x48127ffc7fff8000", "0x480680017fff8000", - "0x0", - "0x208b7fff7fff7ffe", + "0x4b656363616b", + "0x400280007ffd7fff", + "0x400280017ffd7ffe", + "0x400280027ffd7ffc", + "0x400280037ffd7ffd", + "0x480280057ffd8000", + "0x20680017fff7fff", + "0x8f", + "0x480280047ffd8000", + "0x480280067ffd8000", + "0x482680017ffd8000", + "0x8", + "0x48127ffd7fff8000", + "0x480280077ffd8000", + "0x4824800180007ffc", + "0x587f7cc3722e9654ea3963d5fe8c0748", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x11", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4f7574206f6620676173", + "0x57726f6e6720686173682076616c7565", "0x400080007ffe7fff", - "0x482680017ff78000", - "0x1", - "0x480a7ff87fff8000", + "0x48127ff07fff8000", + "0x482480017ffa8000", + "0x3264", + "0x48127ff87fff8000", "0x480680017fff8000", "0x1", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x48127ff87fff8000", - "0x482480017ff78000", + "0x48127ffa7fff8000", + "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0xa0680017fff8000", - "0x7", - "0x482680017ff98000", - "0xfffffffffffffffffffffffffffff4ca", - "0x400280007ff87fff", - "0x10780017fff7fff", - "0x5b", - "0x4825800180007ff9", - "0xb36", - "0x400280007ff87fff", - "0x482680017ff88000", - "0x1", - "0x48297ffa80007ffb", + "0x48127ffd7fff8000", + "0x4824800180007ffd", + "0xa5963aa610cb75ba273817bce5f8c48f", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xa", - "0x482680017ffa8000", + "0x11", + "0x40780017fff7fff", "0x1", - "0x480a7ffb7fff8000", "0x480680017fff8000", - "0x0", - "0x480a7ffa7fff8000", - "0x10780017fff7fff", - "0x8", - "0x480a7ffa7fff8000", - "0x480a7ffb7fff8000", - "0x480680017fff8000", - "0x1", + "0x57726f6e6720686173682076616c7565", + "0x400080007ffe7fff", + "0x48127fee7fff8000", + "0x482480017ffb8000", + "0x30d4", + "0x48127ff67fff8000", "0x480680017fff8000", - "0x0", - "0x20680017fff7ffe", - "0x36", - "0x480080007fff8000", - "0x48297ffc80007ffd", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x1d", - "0x480280007ffc8000", - "0x48307fff80007ffd", - "0x482680017ffc8000", "0x1", - "0x480a7ffd7fff8000", - "0x20680017fff7ffd", - "0xb", - "0x48127ff47fff8000", - "0x48127ff27fff8000", - "0x48127ff47fff8000", - "0x48127ff47fff8000", "0x48127ffa7fff8000", - "0x48127ffa7fff8000", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffcd", + "0x482480017ff98000", + "0x1", "0x208b7fff7fff7ffe", - "0x48127ff47fff8000", - "0x48127ff27fff8000", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", - "0x48127ff37fff8000", - "0x48127ff37fff8000", - "0x48127ff97fff8000", - "0x48127ff97fff8000", + "0x1", + "0x400080007ffe7fff", + "0x48127ffc7fff8000", + "0x48127ffd7fff8000", + "0x482480017ffc8000", + "0x1", "0x480680017fff8000", - "0x0", - "0x208b7fff7fff7ffe", + "0x4b656363616b", + "0x400080007ff47fff", + "0x400080017ff47ffc", + "0x400080027ff47ffd", + "0x400080037ff47ffe", + "0x480080057ff48000", + "0x20680017fff7fff", + "0x13", + "0x480080047ff38000", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x53686f756c64206661696c", "0x400080007ffe7fff", - "0x48127ff67fff8000", - "0x48127ff47fff8000", + "0x48127fe67fff8000", + "0x482480017ffc8000", + "0x3e8", + "0x482480017fee8000", + "0x8", "0x480680017fff8000", "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x480080047ff38000", + "0x480080067ff28000", + "0x480080077ff18000", + "0x482480017ff08000", + "0x8", + "0x48127ffc7fff8000", + "0x48307ffc80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x21", + "0x480080007ffb8000", + "0x4824800180007fff", + "0x496e76616c696420696e707574206c656e677468", + "0x48127ffc7fff8000", + "0x20680017fff7ffe", + "0xd", + "0x48127fe07fff8000", + "0x482480017ffe8000", + "0x12c", + "0x48127ff87fff8000", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", - "0x48127ff87fff8000", - "0x482480017ff78000", - "0x1", "0x208b7fff7fff7ffe", - "0x48127ffa7fff8000", - "0x48127ff87fff8000", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x480a7ffc7fff8000", - "0x480a7ffd7fff8000", + "0x57726f6e67206572726f72206d7367", + "0x400080007ffe7fff", + "0x48127fde7fff8000", + "0x48127ffc7fff8000", + "0x48127ff67fff8000", "0x480680017fff8000", "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4f7574206f6620676173", + "0x496e646578206f7574206f6620626f756e6473", "0x400080007ffe7fff", - "0x482680017ff88000", - "0x1", - "0x480a7ff97fff8000", + "0x48127fe17fff8000", + "0x482480017ffb8000", + "0x12c", + "0x48127ff97fff8000", "0x480680017fff8000", "0x1", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x48127ff87fff8000", - "0x482480017ff78000", + "0x48127ffa7fff8000", + "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0xa0680017fff8000", - "0x7", - "0x482680017ff98000", - "0xfffffffffffffffffffffffffffff0e2", - "0x400280007ff87fff", - "0x10780017fff7fff", - "0x71", - "0x4825800180007ff9", - "0xf1e", - "0x400280007ff87fff", - "0x482680017ff88000", - "0x1", - "0x48297ffa80007ffb", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0xa", - "0x482680017ffa8000", - "0x3", - "0x480a7ffb7fff8000", - "0x480680017fff8000", - "0x0", - "0x480a7ffa7fff8000", - "0x10780017fff7fff", + "0x480280047ffd8000", + "0x48127ff77fff8000", + "0x482480017ffe8000", + "0x3390", + "0x482680017ffd8000", "0x8", - "0x480a7ffa7fff8000", - "0x480a7ffb7fff8000", - "0x480680017fff8000", - "0x1", - "0x480680017fff8000", - "0x0", - "0x20680017fff7ffe", - "0x4c", - "0x480080007fff8000", - "0x480080017ffe8000", - "0x480080027ffd8000", - "0x48297ffc80007ffd", - "0x20680017fff7fff", - "0x4", + "0x480280067ffd8000", + "0x480280077ffd8000", "0x10780017fff7fff", - "0x31", - "0x480280007ffc8000", - "0x480280017ffc8000", - "0x480280027ffc8000", - "0x48307ffd80007ff9", - "0x482680017ffc8000", - "0x3", + "0x10", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x5e24", "0x480a7ffd7fff8000", - "0x20680017fff7ffd", - "0x1b", - "0x48307ffb80007ff7", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x6", - "0x40780017fff7fff", - "0x1", - "0x10780017fff7fff", - "0x14", - "0x48307ffb80007ff7", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x4", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", "0x10780017fff7fff", - "0xd", - "0x48127fee7fff8000", - "0x48127fec7fff8000", - "0x48127fee7fff8000", - "0x48127fee7fff8000", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffb9", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x2", - "0x48127fee7fff8000", - "0x48127fec7fff8000", - "0x480680017fff8000", - "0x0", - "0x48127fed7fff8000", - "0x48127fed7fff8000", - "0x48127ff77fff8000", - "0x48127ff77fff8000", + "0x8", + "0x48127ff97fff8000", + "0x482480017ff98000", + "0x861a", + "0x480a7ffd7fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", "0x480680017fff8000", - "0x0", + "0x1", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x61616161", "0x400080007ffe7fff", - "0x48127ff47fff8000", - "0x48127ff27fff8000", - "0x480680017fff8000", + "0x480a7ffb7fff8000", + "0x48127ffd7fff8000", + "0x482480017ffc8000", "0x1", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", - "0x480680017fff8000", - "0x0", - "0x48127ff87fff8000", - "0x482480017ff78000", - "0x1", - "0x208b7fff7fff7ffe", - "0x48127ffa7fff8000", - "0x48127ff87fff8000", - "0x480680017fff8000", - "0x0", - "0x48127ff97fff8000", + "0x1104800180018000", + "0x119f", + "0x20680017fff7ffd", + "0x3a", + "0x1104800180018000", + "0x28e1", + "0x482480017fff8000", + "0x28e0", "0x48127ff97fff8000", "0x480a7ffc7fff8000", "0x480a7ffd7fff8000", - "0x480680017fff8000", - "0x1", - "0x208b7fff7fff7ffe", + "0x48127ff87fff8000", + "0x48127ff87fff8000", + "0x48127ffa7fff8000", + "0x1104800180018000", + "0x128f", + "0x20680017fff7ffc", + "0x24", + "0x48127fff7fff8000", + "0x480080007fff8000", + "0x48127ff87fff8000", + "0x4824800180007ffe", + "0x61be55a8", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x10", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4f7574206f6620676173", + "0x57726f6e6720686173682076616c7565", "0x400080007ffe7fff", - "0x482680017ff88000", - "0x1", - "0x480a7ff97fff8000", + "0x48127ff37fff8000", + "0x48127ffb7fff8000", + "0x48127ff37fff8000", "0x480680017fff8000", "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x48127ff57fff8000", + "0x482480017ffd8000", + "0xc8", + "0x48127ff57fff8000", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", - "0x48127ff87fff8000", - "0x482480017ff78000", - "0x1", "0x208b7fff7fff7ffe", - "0xa0680017fff8000", - "0x7", - "0x482680017ff98000", - "0xffffffffffffffffffffffffffffdd32", - "0x400280007ff87fff", - "0x10780017fff7fff", - "0x42", - "0x4825800180007ff9", - "0x22ce", - "0x400280007ff87fff", - "0x482680017ff88000", - "0x1", - "0x48297ffa80007ffb", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0xa", - "0x482680017ffa8000", - "0x2", - "0x480a7ffb7fff8000", - "0x480680017fff8000", - "0x0", - "0x480a7ffa7fff8000", + "0x48127ff97fff8000", + "0x482480017ff98000", + "0xc8", + "0x48127ff97fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", "0x10780017fff7fff", "0x8", - "0x480a7ffa7fff8000", - "0x480a7ffb7fff8000", + "0x48127ffc7fff8000", + "0x482680017ffc8000", + "0xb9a", + "0x480a7ffd7fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", "0x480680017fff8000", "0x1", - "0x480680017fff8000", - "0x0", - "0x20680017fff7ffe", - "0x1f", - "0x48127ffa7fff8000", - "0x480a7ffc7fff8000", - "0x480a7ffd7fff8000", - "0x480080007ffc8000", - "0x480080017ffb8000", - "0x1104800180018000", - "0xd79", - "0x20680017fff7ffd", - "0xb", - "0x48127ffc7fff8000", - "0x48127fce7fff8000", - "0x48127fd07fff8000", - "0x48127fd07fff8000", "0x48127ffa7fff8000", "0x48127ffa7fff8000", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffd1", "0x208b7fff7fff7ffe", - "0x48127ffc7fff8000", - "0x48127fce7fff8000", - "0x480680017fff8000", - "0x1", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x208b7fff7fff7ffe", - "0x48127ffa7fff8000", - "0x48127ff87fff8000", + "0x480680017fff8000", + "0x1", "0x480680017fff8000", "0x0", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x480a7ffc7fff8000", - "0x480a7ffd7fff8000", - "0x208b7fff7fff7ffe", + "0x480680017fff8000", + "0x536563703235366b314e6577", + "0x400280007ffd7fff", + "0x400380017ffd7ffb", + "0x400280027ffd7ffb", + "0x400280037ffd7ffc", + "0x400280047ffd7ffd", + "0x400280057ffd7ffe", + "0x480280077ffd8000", + "0x20680017fff7fff", + "0x1aa", + "0x480280067ffd8000", + "0x480280087ffd8000", + "0x480280097ffd8000", + "0x482680017ffd8000", + "0xa", + "0x48127ffc7fff8000", + "0x20680017fff7ffc", + "0x1b", + "0x1104800180018000", + "0x289c", + "0x482480017fff8000", + "0x289b", + "0x480080007fff8000", + "0x480080017fff8000", + "0x484480017fff8000", + "0x8", + "0x482480017fff8000", + "0x3ef8a", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4f7574206f6620676173", + "0x53686f756c64206265206e6f6e65", "0x400080007ffe7fff", - "0x482680017ff88000", - "0x1", - "0x480a7ff97fff8000", + "0x480a7ffa7fff8000", + "0x48307ffc7ff58000", + "0x480a7ffc7fff8000", + "0x48127ff27fff8000", "0x480680017fff8000", "0x1", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", "0x48127ff97fff8000", "0x482480017ff88000", "0x1", "0x208b7fff7fff7ffe", - "0x48297ffa80007ffb", + "0x48127fff7fff8000", + "0x480680017fff8000", + "0xfffffffffffffffffffffffefffffc2f", + "0x480680017fff8000", + "0xffffffffffffffffffffffffffffffff", "0x480680017fff8000", - "0x11", - "0x480280007ff88004", - "0x4824800180037fff", "0x1", - "0x48307ffe7fff7ffd", - "0x480280017ff87ffe", - "0x480280027ff87fff", - "0x40507ffe7ffa7ffd", - "0x40307fff7ffd7ff9", - "0x482680017ff88000", - "0x3", - "0x20780017fff7ffd", - "0x9", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x536563703235366b314e6577", + "0x400080007ff87fff", + "0x400080017ff87ffa", + "0x400080027ff87ffb", + "0x400080037ff87ffc", + "0x400080047ff87ffd", + "0x400080057ff87ffe", + "0x480080077ff88000", + "0x20680017fff7fff", + "0x1d", + "0x480080067ff78000", + "0x1104800180018000", + "0x286e", + "0x482480017fff8000", + "0x286d", + "0x480080007fff8000", + "0x480080017fff8000", + "0x484480017fff8000", + "0x8", + "0x482480017fff8000", + "0x3c29e", "0x40780017fff7fff", - "0x10", - "0x48127fef7fff8000", + "0x1", + "0x480680017fff8000", + "0x53686f756c64206661696c", + "0x400080007ffe7fff", + "0x480a7ffa7fff8000", + "0x48307ffc7ff58000", + "0x480a7ffc7fff8000", + "0x482480017fea8000", + "0xa", "0x480680017fff8000", "0x1", - "0x10780017fff7fff", - "0x85", - "0x4825800180007ffd", + "0x48127ff97fff8000", + "0x482480017ff88000", "0x1", + "0x208b7fff7fff7ffe", + "0x480080067ff78000", + "0x480080087ff68000", + "0x480080097ff58000", + "0x482480017ff48000", + "0xa", + "0x48127ffc7fff8000", + "0x48307ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x55", - "0x4825800180007ffd", - "0x2", + "0x136", + "0x480080007ffb8000", + "0x4824800180007fff", + "0x496e76616c696420617267756d656e74", + "0x48127ffc7fff8000", + "0x20680017fff7ffe", + "0x117", + "0x48127fff7fff8000", + "0x480680017fff8000", + "0xe3e70682c2094cac629f6fbed82c07cd", + "0x480680017fff8000", + "0xf728b4fa42485e3a0a5d2f346baa9455", + "0x480680017fff8000", + "0x8e031ab54fc0c4a8f0dc94fad0d0611", + "0x480680017fff8000", + "0x8e182ca967f38e1bd6a49583f43f1876", + "0x480680017fff8000", + "0x536563703235366b314e6577", + "0x400080007ff47fff", + "0x400080017ff47ffa", + "0x400080027ff47ffb", + "0x400080037ff47ffc", + "0x400080047ff47ffd", + "0x400080057ff47ffe", + "0x480080077ff48000", "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x49", - "0x4825800180007ffd", - "0x3", + "0xee", + "0x480080067ff38000", + "0x480080087ff28000", + "0x480080097ff18000", + "0x482480017ff08000", + "0xa", + "0x48127ffc7fff8000", + "0x20680017fff7ffc", + "0xcd", + "0x48127fff7fff8000", + "0x480680017fff8000", + "0x536563703235366b314765745879", + "0x400080007ffc7fff", + "0x400080017ffc7ffe", + "0x400080027ffc7ffb", + "0x480080047ffc8000", + "0x20680017fff7fff", + "0xaf", + "0x480080037ffb8000", + "0x480080057ffa8000", + "0x480080067ff98000", + "0x482480017ff88000", + "0x9", + "0x480080077ff78000", + "0x480080087ff68000", + "0x48127ffa7fff8000", + "0x4824800180007ffa", + "0xe3e70682c2094cac629f6fbed82c07cd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x3d", - "0x4825800180007ffd", - "0x4", + "0x11", + "0x40780017fff7fff", + "0x6", + "0x1104800180018000", + "0x280e", + "0x482480017fff8000", + "0x280d", + "0x480080007fff8000", + "0x480080017fff8000", + "0x484480017fff8000", + "0x8", + "0x482480017fff8000", + "0x360ba", + "0x48307fff7ff18000", + "0x10780017fff7fff", + "0x16", + "0x48127ffe7fff8000", + "0x4824800180007ff9", + "0xf728b4fa42485e3a0a5d2f346baa9455", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x31", - "0x4825800180007ffd", - "0x5", - "0x20680017fff7fff", + "0x11", + "0x40780017fff7fff", "0x4", + "0x1104800180018000", + "0x27f8", + "0x482480017fff8000", + "0x27f7", + "0x480080007fff8000", + "0x480080017fff8000", + "0x484480017fff8000", + "0x8", + "0x482480017fff8000", + "0x35fa2", + "0x48307fff7ff38000", "0x10780017fff7fff", - "0x25", - "0x4825800180007ffd", - "0x6", + "0x2a", + "0x48127ffe7fff8000", + "0x4824800180007ff9", + "0x8e031ab54fc0c4a8f0dc94fad0d0611", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x19", - "0x4825800180007ffd", - "0x7", + "0x11", + "0x40780017fff7fff", + "0x2", + "0x1104800180018000", + "0x27e2", + "0x482480017fff8000", + "0x27e1", + "0x480080007fff8000", + "0x480080017fff8000", + "0x484480017fff8000", + "0x8", + "0x482480017fff8000", + "0x35e26", + "0x48307fff7ff58000", + "0x10780017fff7fff", + "0x14", + "0x48127ffe7fff8000", + "0x4824800180007ff8", + "0x8e182ca967f38e1bd6a49583f43f1876", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0xf", + "0x1c", + "0x1104800180018000", + "0x27ce", + "0x482480017fff8000", + "0x27cd", + "0x480080007fff8000", + "0x480080017fff8000", + "0x484480017fff8000", + "0x8", + "0x482480017fff8000", + "0x35d72", + "0x48307fff7ff78000", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4b656363616b206c61737420696e70757420776f7264203e3762", + "0x556e657870656374656420636f6f7264696e61746573", "0x400080007ffe7fff", - "0x48127ff67fff8000", - "0x480a7ff97fff8000", + "0x480a7ffa7fff8000", + "0x48127ffc7fff8000", + "0x480a7ffc7fff8000", + "0x48127fe87fff8000", "0x480680017fff8000", "0x1", - "0x48127ffb7fff8000", - "0x482480017ffa8000", + "0x48127ff97fff8000", + "0x482480017ff88000", "0x1", "0x208b7fff7fff7ffe", "0x480680017fff8000", - "0x100000000000000", - "0x10780017fff7fff", - "0x6", - "0x40780017fff7fff", - "0x1", + "0x767410c1", + "0x484480017fff8000", + "0x100000000000000000000000000000000", + "0x480a7ffa7fff8000", + "0x48127ffb7fff8000", + "0x480a7ffc7fff8000", + "0x48127ff07fff8000", "0x480680017fff8000", - "0x1000000000000", - "0x10780017fff7fff", - "0x6", - "0x40780017fff7fff", - "0x2", + "0x788f195a6f509ca3e934f78d7a71dd85", "0x480680017fff8000", - "0x10000000000", - "0x10780017fff7fff", - "0x6", - "0x40780017fff7fff", - "0x3", + "0xe888fbb4cf9ae6254f19ba12e6d9af54", "0x480680017fff8000", - "0x100000000", - "0x10780017fff7fff", - "0x6", - "0x40780017fff7fff", - "0x4", + "0x7a5f81cf3ee10044320a0d03b62d3e9a", "0x480680017fff8000", - "0x1000000", - "0x10780017fff7fff", - "0x6", - "0x40780017fff7fff", - "0x5", + "0x4c8e4fbc1fbb1dece52185e532812c4f", "0x480680017fff8000", - "0x10000", - "0x10780017fff7fff", - "0x6", - "0x40780017fff7fff", - "0x6", + "0xc2b7f60e6a8b84965830658f08f7410c", + "0x480680017fff8000", + "0x4ac5e5c0c0e8a4871583cc131f35fb49", "0x480680017fff8000", - "0x100", - "0x20680017fff7fff", - "0xf", - "0x40780017fff7fff", "0x1", + "0x482480017ff48000", + "0xbb448978bd42b984d7de5970bcaf5c43", + "0x1104800180018000", + "0x11a1", + "0x20680017fff7ffd", + "0x1a", + "0x48127ffa7fff8000", + "0x20680017fff7ffd", + "0xe", + "0x48127ff87fff8000", + "0x482480017ffe8000", + "0x258", + "0x48127ff87fff8000", + "0x48127ff87fff8000", "0x480680017fff8000", - "0x4f7074696f6e3a3a756e77726170206661696c65642e", - "0x400080007ffe7fff", - "0x48127ff57fff8000", - "0x480a7ff97fff8000", + "0x0", "0x480680017fff8000", - "0x1", - "0x48127ffb7fff8000", - "0x482480017ffa8000", - "0x1", + "0x0", + "0x480680017fff8000", + "0x0", "0x208b7fff7fff7ffe", - "0x480080007ff78004", - "0x4824800180037fff", + "0x40780017fff7fff", "0x1", - "0x48307ffe7fff7ffd", - "0x480080017ff47ffe", - "0x480080027ff37fff", - "0x40507ffe7ffa7ffd", - "0x40317fff7ffd7ffc", - "0xa0680017fff8000", - "0x8", - "0x48307ffe7ff98000", - "0x4824800180007fff", - "0x10000000000000000", - "0x400080037fef7fff", - "0x10780017fff7fff", - "0x5b", - "0x48307ffe7ff98001", - "0x4824800180007fff", - "0xffffffffffffffff0000000000000000", - "0x400080037fef7ffe", - "0x482480017fef8000", - "0x4", + "0x400080007fff7ffd", "0x48127ffe7fff8000", - "0x4824800180007fec", - "0x10", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x28", - "0x400280007ffb7ffe", - "0x480680017fff8000", - "0x10", - "0x480a7ffa7fff8000", - "0x482680017ffb8000", + "0x48127ffe7fff8000", + "0x482480017ffd8000", "0x1", - "0x48307fe880017ffd", - "0xa0680017fff7fff", - "0x7", - "0x482480017fff8000", - "0x100000000000000000000000000000000", - "0x400080007ff77fff", "0x10780017fff7fff", - "0xc", - "0x400080007ff87fff", + "0x8", + "0x40780017fff7fff", + "0x2", "0x482480017ff88000", - "0x1", - "0x480a7ff97fff8000", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", + "0x17c", "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x48127ff47fff8000", + "0x48127ffc7fff8000", + "0x48127ff47fff8000", + "0x48127ff47fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x208b7fff7fff7ffe", + "0x480080037ffb8000", "0x1104800180018000", - "0xd2f", + "0x2770", + "0x482480017fff8000", + "0x276f", + "0x480080007fff8000", + "0x480080017fff8000", + "0x484480017fff8000", + "0x8", + "0x482480017fff8000", + "0x366d2", + "0x480a7ffa7fff8000", + "0x48307ffe7ff78000", + "0x480a7ffc7fff8000", + "0x482480017ff08000", + "0x7", + "0x480680017fff8000", + "0x1", + "0x480080057fee8000", + "0x480080067fed8000", "0x208b7fff7fff7ffe", + "0x1104800180018000", + "0x275c", + "0x482480017fff8000", + "0x275b", + "0x480080007fff8000", + "0x480080017fff8000", + "0x484480017fff8000", + "0x8", + "0x482480017fff8000", + "0x38fd6", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x7533325f737562204f766572666c6f77", + "0x4f7074696f6e3a3a756e77726170206661696c65642e", "0x400080007ffe7fff", - "0x482480017ff58000", - "0x1", - "0x480a7ff97fff8000", + "0x480a7ffa7fff8000", + "0x48307ffc7ff58000", + "0x480a7ffc7fff8000", + "0x48127ff27fff8000", "0x480680017fff8000", "0x1", - "0x48127ffb7fff8000", - "0x482480017ffa8000", + "0x48127ff97fff8000", + "0x482480017ff88000", "0x1", "0x208b7fff7fff7ffe", - "0x480680017fff8000", - "0x8000000000000000", - "0xa0680017fff8000", + "0x480080067ff38000", + "0x1104800180018000", + "0x2742", + "0x482480017fff8000", + "0x2741", + "0x480080007fff8000", + "0x480080017fff8000", + "0x484480017fff8000", "0x8", - "0x48307ffc7ffe8000", - "0x4824800180007fff", - "0x10000000000000000", - "0x400080007ff97fff", - "0x10780017fff7fff", - "0x10", - "0x48307ffc7ffe8001", - "0x4824800180007fff", - "0xffffffffffffffff0000000000000000", - "0x400080007ff97ffe", - "0x400280007ffb7fff", - "0x482480017ff98000", - "0x1", - "0x480a7ff97fff8000", - "0x480680017fff8000", - "0x0", + "0x482480017fff8000", + "0x392f6", "0x480a7ffa7fff8000", - "0x482680017ffb8000", + "0x48307ffe7ff78000", + "0x480a7ffc7fff8000", + "0x482480017fe88000", + "0xa", + "0x480680017fff8000", "0x1", + "0x480080087fe68000", + "0x480080097fe58000", "0x208b7fff7fff7ffe", + "0x1104800180018000", + "0x272e", + "0x482480017fff8000", + "0x272d", + "0x480080007fff8000", + "0x480080017fff8000", + "0x484480017fff8000", + "0x8", + "0x482480017fff8000", + "0x3beb6", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x7536345f616464204f766572666c6f77", + "0x57726f6e67206572726f72206d7367", "0x400080007ffe7fff", - "0x482480017ff78000", - "0x1", - "0x480a7ff97fff8000", + "0x480a7ffa7fff8000", + "0x48307ffc7ff58000", + "0x480a7ffc7fff8000", + "0x48127fee7fff8000", "0x480680017fff8000", "0x1", - "0x48127ffb7fff8000", - "0x482480017ffa8000", + "0x48127ff97fff8000", + "0x482480017ff88000", "0x1", "0x208b7fff7fff7ffe", + "0x1104800180018000", + "0x2715", + "0x482480017fff8000", + "0x2714", + "0x480080007fff8000", + "0x480080017fff8000", + "0x484480017fff8000", + "0x8", + "0x482480017fff8000", + "0x3bfe2", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x7536345f616464204f766572666c6f77", + "0x496e646578206f7574206f6620626f756e6473", "0x400080007ffe7fff", - "0x482480017fed8000", - "0x4", - "0x480a7ff97fff8000", + "0x480a7ffa7fff8000", + "0x48307ffc7ff48000", + "0x480a7ffc7fff8000", + "0x48127ff17fff8000", "0x480680017fff8000", "0x1", - "0x48127ffb7fff8000", - "0x482480017ffa8000", + "0x48127ff97fff8000", + "0x482480017ff88000", "0x1", "0x208b7fff7fff7ffe", - "0x48297ffa80007ffb", - "0x20780017fff7ffd", - "0xd", - "0x40780017fff7fff", - "0xf", - "0x480680017fff8000", - "0x80000000", - "0x400280007ffb7fff", - "0x480a7ff97fff8000", + "0x480280067ffd8000", + "0x1104800180018000", + "0x26fb", + "0x482480017fff8000", + "0x26fa", + "0x480080007fff8000", + "0x480080017fff8000", + "0x484480017fff8000", + "0x8", + "0x482480017fff8000", + "0x3f2aa", "0x480a7ffa7fff8000", - "0x482680017ffb8000", - "0x1", - "0x10780017fff7fff", - "0x4b", - "0x4825800180007ffd", - "0x1", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x18", - "0x4825800180007ffd", - "0x2", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", + "0x48307ffe7ff78000", + "0x480a7ffc7fff8000", + "0x482680017ffd8000", "0xa", "0x480680017fff8000", - "0x1000000", + "0x1", + "0x480280087ffd8000", + "0x480280097ffd8000", + "0x208b7fff7fff7ffe", "0x480680017fff8000", - "0x100", + "0x0", "0x480680017fff8000", - "0x80", - "0x10780017fff7fff", - "0x8", + "0x0", "0x480680017fff8000", - "0x10000", + "0x1", "0x480680017fff8000", - "0x10000", + "0x0", "0x480680017fff8000", - "0x8000", - "0x10780017fff7fff", + "0x5365637032353672314e6577", + "0x400280007ffd7fff", + "0x400380017ffd7ffc", + "0x400280027ffd7ffb", + "0x400280037ffd7ffc", + "0x400280047ffd7ffd", + "0x400280057ffd7ffe", + "0x480280077ffd8000", + "0x20680017fff7fff", + "0x16c", + "0x480280067ffd8000", + "0x480280087ffd8000", + "0x480280097ffd8000", + "0x482680017ffd8000", "0xa", + "0x48127ffc7fff8000", + "0x20680017fff7ffc", + "0x13", + "0x40780017fff7fff", + "0x318", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x100", - "0x480680017fff8000", - "0x1000000", + "0x53686f756c64206265206e6f6e65", + "0x400080007ffe7fff", + "0x480a7ffb7fff8000", + "0x482480017ce48000", + "0x33e82", + "0x48127ce27fff8000", "0x480680017fff8000", - "0x800000", - "0x480280007ff98004", - "0x4824800180037fff", "0x1", - "0x48307ffe7fff7ffb", - "0x480280017ff97ffe", - "0x480280027ff97fff", - "0x40507ffe7ff87ffd", - "0x40317fff7ffd7ffc", - "0x48507ff97fff8000", - "0xa0680017fff8000", - "0x7", - "0x4824800180007ffe", - "0x100000000", - "0x400280037ff97fff", - "0x10780017fff7fff", - "0xaf", - "0x482480017ffe8000", - "0xffffffffffffffffffffffff00000000", - "0x400280037ff97fff", - "0xa0680017fff8000", - "0x8", - "0x48307ff67ffc8000", - "0x4824800180007fff", - "0x100000000", - "0x400280047ff97fff", - "0x10780017fff7fff", - "0x95", - "0x48307ff67ffc8001", - "0x4824800180007fff", - "0xffffffffffffffffffffffff00000000", - "0x400280047ff97ffe", - "0x400280007ffb7fff", - "0x482680017ff98000", - "0x5", - "0x480a7ffa7fff8000", - "0x482680017ffb8000", + "0x48127ffa7fff8000", + "0x482480017ff98000", "0x1", - "0x48307ffe80007fff", + "0x208b7fff7fff7ffe", + "0x48127fff7fff8000", + "0x480680017fff8000", + "0xffffffffffffffffffffffff", + "0x480680017fff8000", + "0xffffffff000000010000000000000000", "0x480680017fff8000", "0x1", - "0xa0680017fff8000", - "0x8", - "0x48307ffe7ffd8000", - "0x4824800180007fff", - "0x100000000", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x5365637032353672314e6577", "0x400080007ff87fff", + "0x400080017ff87ffa", + "0x400080027ff87ffb", + "0x400080037ff87ffc", + "0x400080047ff87ffd", + "0x400080057ff87ffe", + "0x480080077ff88000", + "0x20680017fff7fff", + "0x15", + "0x40780017fff7fff", + "0x310", + "0x480080067ce78000", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x53686f756c64206661696c", + "0x400080007ffe7fff", + "0x480a7ffb7fff8000", + "0x482480017ffc8000", + "0x311e6", + "0x482480017ce28000", + "0xa", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x480080067ff78000", + "0x480080087ff68000", + "0x480080097ff58000", + "0x482480017ff48000", + "0xa", + "0x48127ffc7fff8000", + "0x48307ffc80007ffd", + "0x20680017fff7fff", + "0x4", "0x10780017fff7fff", - "0x71", - "0x48307ffe7ffd8001", + "0x110", + "0x480080007ffb8000", "0x4824800180007fff", - "0xffffffffffffffffffffffff00000000", - "0x400080007ff87ffe", + "0x496e76616c696420617267756d656e74", + "0x48127ffc7fff8000", + "0x20680017fff7ffe", + "0xf9", + "0x48127fff7fff8000", "0x480680017fff8000", - "0x10", - "0x480080017ff78004", - "0x4824800180037fff", - "0x1", - "0x48307ffe7fff7ffd", - "0x480080027ff47ffe", - "0x480080037ff37fff", - "0x40507ffe7ffa7ffd", - "0x40307fff7ffd7ff9", + "0x2d483fe223b12b91047d83258a958b0f", "0x480680017fff8000", - "0x10", - "0x48127ff27fff8000", - "0x48127ff27fff8000", - "0x48307ffc80007ffd", - "0x1104800180018000", - "0xcc8", - "0x484480017f9c8000", - "0x20", - "0xa0680017fff8000", - "0x7", - "0x4824800180007ffe", - "0x100000000", - "0x400080047faa7fff", + "0x502a43ce77c6f5c736a82f847fa95f8c", + "0x480680017fff8000", + "0xce729c7704f4ddf2eaaf0b76209fe1b0", + "0x480680017fff8000", + "0xdb0a2e6710c71ba80afeb3abdf69d306", + "0x480680017fff8000", + "0x5365637032353672314e6577", + "0x400080007ff47fff", + "0x400080017ff47ffa", + "0x400080027ff47ffb", + "0x400080037ff47ffc", + "0x400080047ff47ffd", + "0x400080057ff47ffe", + "0x480080077ff48000", + "0x20680017fff7fff", + "0xd8", + "0x480080067ff38000", + "0x480080087ff28000", + "0x480080097ff18000", + "0x482480017ff08000", + "0xa", + "0x48127ffc7fff8000", + "0x20680017fff7ffc", + "0xbf", + "0x48127fff7fff8000", + "0x480680017fff8000", + "0x5365637032353672314765745879", + "0x400080007ffc7fff", + "0x400080017ffc7ffe", + "0x400080027ffc7ffb", + "0x480080047ffc8000", + "0x20680017fff7fff", + "0xa9", + "0x480080037ffb8000", + "0x480080057ffa8000", + "0x480080067ff98000", + "0x482480017ff88000", + "0x9", + "0x480080077ff78000", + "0x480080087ff68000", + "0x48127ffa7fff8000", + "0x4824800180007ffa", + "0x2d483fe223b12b91047d83258a958b0f", + "0x20680017fff7fff", + "0x4", "0x10780017fff7fff", - "0x44", - "0x482480017ffe8000", - "0xffffffffffffffffffffffff00000000", - "0x400080047faa7fff", - "0x484680017ffd8000", "0x8", - "0xa0680017fff8000", - "0x7", - "0x4824800180007ffe", - "0x100000000", - "0x400080057fa77fff", + "0x40780017fff7fff", + "0x2f0", + "0x482480017d0e8000", + "0x2b1e2", + "0x10780017fff7fff", + "0xd", + "0x48127ffe7fff8000", + "0x4824800180007ff9", + "0x502a43ce77c6f5c736a82f847fa95f8c", + "0x20680017fff7fff", + "0x4", "0x10780017fff7fff", - "0x29", - "0x482480017ffe8000", - "0xffffffffffffffffffffffff00000000", - "0x400080057fa77fff", - "0xa0680017fff8000", "0x8", - "0x48307ffc7ff98000", - "0x4824800180007fff", - "0x100000000", - "0x400080067fa47fff", + "0x40780017fff7fff", + "0x2ee", + "0x482480017d108000", + "0x2b0ca", "0x10780017fff7fff", - "0x11", - "0x48307ffc7ff98001", - "0x4824800180007fff", - "0xffffffffffffffffffffffff00000000", - "0x400080067fa47ffe", + "0x1a", + "0x48127ffe7fff8000", + "0x4824800180007ff9", + "0xce729c7704f4ddf2eaaf0b76209fe1b0", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x8", "0x40780017fff7fff", - "0x2", - "0x400080007ff47ffd", - "0x482480017fa28000", - "0x7", - "0x480680017fff8000", - "0x0", - "0x48127ff17fff8000", - "0x482480017ff18000", - "0x1", - "0x208b7fff7fff7ffe", + "0x2ec", + "0x482480017d128000", + "0x2af4e", + "0x10780017fff7fff", + "0xd", + "0x48127ffe7fff8000", + "0x4824800180007ff8", + "0xdb0a2e6710c71ba80afeb3abdf69d306", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x14", + "0x40780017fff7fff", + "0x2ea", + "0x482480017d148000", + "0x2ae36", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x7533325f616464204f766572666c6f77", + "0x556e657870656374656420636f6f7264696e61746573", "0x400080007ffe7fff", - "0x482480017fa28000", - "0x7", + "0x480a7ffb7fff8000", + "0x48127ffc7fff8000", + "0x48127d067fff8000", "0x480680017fff8000", "0x1", - "0x48127ffc7fff8000", - "0x482480017ffb8000", + "0x48127ffa7fff8000", + "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x3", - "0x40780017fff7fff", - "0x1", + "0x48127ffe7fff8000", "0x480680017fff8000", - "0x7533325f6d756c204f766572666c6f77", - "0x400080007ffe7fff", - "0x482480017fa28000", - "0x6", + "0x32e41495a944d0045b522eba7240fad5", "0x480680017fff8000", - "0x1", + "0x4aaec73635726f213fb8a9e64da3b86", + "0x480680017fff8000", + "0xaaf7b4e09fc81d6d1aa546e8365d525d", + "0x480680017fff8000", + "0x87d9315798aaa3a5ba01775787ced05e", + "0x480680017fff8000", + "0x5365637032353672314e6577", + "0x400080007fef7fff", + "0x400080017fef7ffa", + "0x400080027fef7ffb", + "0x400080037fef7ffc", + "0x400080047fef7ffd", + "0x400080057fef7ffe", + "0x480080077fef8000", + "0x20680017fff7fff", + "0x41", + "0x480080067fee8000", + "0x480080087fed8000", + "0x480080097fec8000", + "0x482480017feb8000", + "0xa", "0x48127ffc7fff8000", - "0x482480017ffb8000", + "0x20680017fff7ffc", + "0x28", + "0x480a7ffb7fff8000", + "0x48127ffe7fff8000", + "0x48127ffc7fff8000", + "0x480680017fff8000", + "0x27ae41e4649b934ca495991b7852b855", + "0x480680017fff8000", + "0xe3b0c44298fc1c149afbf4c8996fb924", + "0x480680017fff8000", + "0x42d16e47f219f9e98e76e09d8770b34a", + "0x480680017fff8000", + "0xb292a619339f6e567a305c951c0dcbcc", + "0x480680017fff8000", + "0xe59ec2a17ce5bd2dab2abebdf89a62e2", + "0x480680017fff8000", + "0x177e60492c5a8242f76f07bfe3661bd", + "0x48127ff47fff8000", + "0x1104800180018000", + "0x1124", + "0x20680017fff7ffd", + "0xc", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x208b7fff7fff7ffe", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x480680017fff8000", "0x1", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0x6", + "0x2df", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x7533325f6d756c204f766572666c6f77", + "0x4f7074696f6e3a3a756e77726170206661696c65642e", "0x400080007ffe7fff", - "0x482480017fa28000", - "0x5", + "0x480a7ffb7fff8000", + "0x482480017d1d8000", + "0x27fc4", + "0x48127d1b7fff8000", "0x480680017fff8000", "0x1", - "0x48127ffc7fff8000", - "0x482480017ffb8000", - "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0x54", - "0x40780017fff7fff", - "0x1", - "0x480680017fff8000", - "0x7533325f616464204f766572666c6f77", - "0x400080007ffe7fff", - "0x482480017fa28000", - "0x1", + "0x2e5", + "0x480080067d098000", + "0x480a7ffb7fff8000", + "0x482480017ffe8000", + "0x282a8", + "0x482480017d068000", + "0xa", "0x480680017fff8000", "0x1", - "0x48127ffc7fff8000", - "0x482480017ffb8000", - "0x1", + "0x480080087d048000", + "0x480080097d038000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0x5c", - "0x40780017fff7fff", - "0x1", - "0x480680017fff8000", - "0x7533325f616464204f766572666c6f77", - "0x400080007ffe7fff", - "0x482680017ff98000", - "0x5", + "0x2fa", + "0x480080037d018000", + "0x480a7ffb7fff8000", + "0x482480017ffe8000", + "0x2b6f6", + "0x482480017cfe8000", + "0x7", "0x480680017fff8000", "0x1", - "0x48127ffc7fff8000", - "0x482480017ffb8000", - "0x1", + "0x480080057cfc8000", + "0x480080067cfb8000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0x5f", + "0x2fc", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x7533325f6d756c204f766572666c6f77", + "0x4f7074696f6e3a3a756e77726170206661696c65642e", "0x400080007ffe7fff", - "0x482680017ff98000", - "0x4", + "0x480a7ffb7fff8000", + "0x482480017d008000", + "0x2dfe6", + "0x48127cfe7fff8000", "0x480680017fff8000", "0x1", - "0x48127ffc7fff8000", - "0x482480017ffb8000", + "0x48127ffa7fff8000", + "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0xa0680017fff8000", - "0x7", - "0x482680017ff98000", - "0xffffffffffffffffffffffffffffcd10", - "0x400280007ff87fff", - "0x10780017fff7fff", - "0x4b", - "0x4825800180007ff9", - "0x32f0", - "0x400280007ff87fff", - "0xa0680017fff8000", - "0x8", - "0x48297ffc80007ffb", - "0x482480017fff8000", - "0xf", - "0x400280017ff87fff", - "0x10780017fff7fff", - "0xf", - "0x482680017ffb8001", - "0x10", - "0x483180007fff7ffc", - "0x400280017ff87ffe", - "0x482680017ff88000", - "0x2", - "0x48127ffe7fff8000", - "0x480a7ffc7fff8000", - "0x480680017fff8000", - "0x0", + "0x40780017fff7fff", + "0x302", + "0x480080067cf18000", "0x480a7ffb7fff8000", - "0x10780017fff7fff", + "0x482480017ffe8000", + "0x2e2ca", + "0x482480017cee8000", "0xa", - "0x482680017ff88000", - "0x2", - "0x480a7ffb7fff8000", - "0x480a7ffc7fff8000", "0x480680017fff8000", "0x1", - "0x480680017fff8000", - "0x0", - "0x20680017fff7ffe", - "0x20", - "0x480680017fff8000", - "0x53686132353650726f63657373426c6f636b", - "0x400280007ffa7fff", - "0x400280017ffa7ff6", - "0x400380027ffa7ffd", - "0x400280037ffa7ffe", - "0x480280057ffa8000", - "0x20680017fff7fff", - "0xc", - "0x48127ff97fff8000", - "0x480280047ffa8000", - "0x482680017ffa8000", - "0x7", - "0x48127ff77fff8000", - "0x48127ff77fff8000", - "0x480280067ffa8000", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffc8", + "0x480080087cec8000", + "0x480080097ceb8000", "0x208b7fff7fff7ffe", - "0x48127ff97fff8000", - "0x480280047ffa8000", - "0x482680017ffa8000", - "0x8", - "0x480680017fff8000", + "0x40780017fff7fff", + "0x308", + "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x0", - "0x480280067ffa8000", - "0x480280077ffa8000", - "0x208b7fff7fff7ffe", - "0x48127ffb7fff8000", - "0x48127ff67fff8000", - "0x480a7ffa7fff8000", + "0x57726f6e67206572726f72206d7367", + "0x400080007ffe7fff", + "0x480a7ffb7fff8000", + "0x482480017cf48000", + "0x30e4e", + "0x48127cee7fff8000", "0x480680017fff8000", - "0x0", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x480a7ffd7fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", "0x208b7fff7fff7ffe", "0x40780017fff7fff", + "0x30b", + "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4f7574206f6620676173", + "0x496e646578206f7574206f6620626f756e6473", "0x400080007ffe7fff", - "0x482680017ff88000", - "0x1", - "0x480a7ff97fff8000", - "0x480a7ffa7fff8000", + "0x480a7ffb7fff8000", + "0x482480017cf08000", + "0x30f5c", + "0x48127cee7fff8000", "0x480680017fff8000", "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x31e", + "0x480280067ffd8000", + "0x480a7ffb7fff8000", + "0x482480017ffe8000", + "0x34166", + "0x482680017ffd8000", + "0xa", "0x480680017fff8000", - "0x0", - "0x48127ff97fff8000", - "0x482480017ff88000", "0x1", + "0x480280087ffd8000", + "0x480280097ffd8000", "0x208b7fff7fff7ffe", - "0x20780017fff7ff8", - "0x9", - "0x20780017fff7ff9", - "0x5", - "0x480a7ff27fff8000", - "0x10780017fff7fff", - "0x27", + "0xa0680017fff8000", + "0x7", + "0x482680017ffa8000", + "0xffffffffffffffffffffffffffffc57c", + "0x400280007ff97fff", "0x10780017fff7fff", - "0x2", + "0x133", + "0x4825800180007ffa", + "0x3a84", + "0x400280007ff97fff", + "0x48297ffc80007ffd", "0x480680017fff8000", - "0xfffffffffffffffffffffffffffffffe", - "0x48317fff80017ff9", + "0x3", + "0x48127ffd7fff8000", + "0x48307ffe80017ffd", "0xa0680017fff7fff", "0x7", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400280007ff27fff", + "0x400280017ff97fff", "0x10780017fff7fff", - "0x29", - "0x400280007ff27fff", - "0x482680017ff28000", + "0x114", + "0x400280017ff97fff", + "0x482680017ff98000", + "0x2", + "0x48127ffc7fff8000", + "0x48297ffc80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xfc", + "0x482680017ffc8000", "0x1", - "0x4825800180007ff9", - "0xfffffffffffffffffffffffffffffffe", + "0x480a7ffd7fff8000", + "0x48127ffc7fff8000", + "0x480280007ffc8000", + "0x48307ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x5", - "0x48127ffe7fff8000", + "0xe3", + "0x482480017ffb8000", + "0x1", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x480080007ff88000", + "0x48307ffc80007ffd", + "0x20680017fff7fff", + "0x4", "0x10780017fff7fff", - "0xf", - "0x480680017fff8000", - "0xbaaedce6af48a03bbfd25e8cd0364141", - "0x48317fff80017ff8", - "0xa0680017fff7fff", - "0x7", + "0xca", + "0x480080007ffb8000", + "0x482480017ffa8000", + "0x1", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x20680017fff7ffc", + "0x4a", "0x482480017fff8000", - "0x100000000000000000000000000000000", - "0x400080007ffa7fff", + "0x12c", + "0xa0680017fff8004", + "0xe", + "0x4824800180047ff3", + "0x800000000000000000000000000000000000000000000000000000000000000", + "0x484480017ffe8000", + "0x110000000000000000", + "0x48307ffe7fff8002", + "0x480080007fea7ffc", + "0x480080017fe97ffc", + "0x402480017ffb7ffd", + "0xffffffffffffffeeffffffffffffffff", + "0x400080027fe87ffd", "0x10780017fff7fff", - "0xf", - "0x400080007ffb7fff", - "0x482480017ffb8000", - "0x1", - "0x480a7ff37fff8000", - "0x480a7ff47fff8000", - "0x480a7ff57fff8000", + "0x2a", + "0x484480017fff8001", + "0x8000000000000000000000000000000", + "0x48307fff80007ff2", + "0x480080007feb7ffd", + "0x480080017fea7ffd", + "0x402480017ffc7ffe", + "0xf8000000000000000000000000000000", + "0x400080027fe97ffe", + "0x48127ffa7fff8000", + "0x482480017fe88000", + "0x3", "0x480680017fff8000", - "0x0", + "0x43616c6c436f6e7472616374", + "0x400280007ffb7fff", + "0x400280017ffb7ffd", + "0x400280027ffb7fec", + "0x400280037ffb7ff1", + "0x400280047ffb7ff4", + "0x400280057ffb7ff5", + "0x480280077ffb8000", + "0x20680017fff7fff", + "0x9", + "0x480280067ffb8000", + "0x48127ffc7fff8000", + "0x48127ffe7fff8000", + "0x482680017ffb8000", + "0xa", + "0x10780017fff7fff", + "0x8f", + "0x480280067ffb8000", + "0x48127ffc7fff8000", + "0x482480017ffe8000", + "0x64", + "0x482680017ffb8000", + "0xa", "0x480680017fff8000", "0x1", - "0x480680017fff8000", - "0x5369676e6174757265206f7574206f662072616e6765", + "0x480280087ffb8000", + "0x480280097ffb8000", "0x208b7fff7fff7ffe", - "0x482480017ffa8000", + "0x40780017fff7fff", "0x1", - "0x10780017fff7fff", - "0x4", - "0x482680017ff28000", + "0x480680017fff8000", + "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x400080007ffe7fff", + "0x482480017fe68000", + "0x3", + "0x482480017ff68000", + "0x2a30", + "0x480a7ffb7fff8000", + "0x480680017fff8000", "0x1", - "0x20780017fff7ffa", - "0x9", - "0x20780017fff7ffb", - "0x5", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x4824800180007ffc", + "0x1", + "0x48127ffe7fff8000", + "0x20680017fff7ffe", + "0x49", "0x48127fff7fff8000", + "0xa0680017fff8004", + "0xe", + "0x4824800180047ff1", + "0x800000000000000000000000000000000000000000000000000000000000000", + "0x484480017ffe8000", + "0x110000000000000000", + "0x48307ffe7fff8002", + "0x480080007fe87ffc", + "0x480080017fe77ffc", + "0x402480017ffb7ffd", + "0xffffffffffffffeeffffffffffffffff", + "0x400080027fe67ffd", "0x10780017fff7fff", - "0x27", - "0x10780017fff7fff", - "0x2", + "0x2a", + "0x484480017fff8001", + "0x8000000000000000000000000000000", + "0x48307fff80007ff0", + "0x480080007fe97ffd", + "0x480080017fe87ffd", + "0x402480017ffc7ffe", + "0xf8000000000000000000000000000000", + "0x400080027fe77ffe", + "0x48127ffa7fff8000", + "0x482480017fe68000", + "0x3", "0x480680017fff8000", - "0xfffffffffffffffffffffffffffffffe", - "0x48317fff80017ffb", - "0xa0680017fff7fff", - "0x7", - "0x482480017fff8000", - "0x100000000000000000000000000000000", - "0x400080007ffb7fff", - "0x10780017fff7fff", - "0x29", - "0x400080007ffc7fff", - "0x482480017ffc8000", - "0x1", - "0x4825800180007ffb", - "0xfffffffffffffffffffffffffffffffe", + "0x4c69627261727943616c6c", + "0x400280007ffb7fff", + "0x400280017ffb7ffd", + "0x400280027ffb7fea", + "0x400280037ffb7fef", + "0x400280047ffb7ff2", + "0x400280057ffb7ff3", + "0x480280077ffb8000", "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x5", + "0x9", + "0x480280067ffb8000", + "0x48127ffc7fff8000", "0x48127ffe7fff8000", + "0x482680017ffb8000", + "0xa", "0x10780017fff7fff", - "0xf", + "0x43", + "0x480280067ffb8000", + "0x48127ffc7fff8000", + "0x482480017ffe8000", + "0x64", + "0x482680017ffb8000", + "0xa", "0x480680017fff8000", - "0xbaaedce6af48a03bbfd25e8cd0364141", - "0x48317fff80017ffa", - "0xa0680017fff7fff", - "0x7", - "0x482480017fff8000", - "0x100000000000000000000000000000000", - "0x400080007ffa7fff", - "0x10780017fff7fff", - "0xf", - "0x400080007ffb7fff", - "0x482480017ffb8000", "0x1", - "0x480a7ff37fff8000", - "0x480a7ff47fff8000", - "0x480a7ff57fff8000", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", + "0x480280087ffb8000", + "0x480280097ffb8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x5369676e6174757265206f7574206f662072616e6765", - "0x208b7fff7fff7ffe", - "0x482480017ffa8000", + "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x400080007ffe7fff", + "0x482480017fe48000", + "0x3", + "0x482480017ff68000", + "0x2a30", + "0x480a7ffb7fff8000", + "0x480680017fff8000", "0x1", - "0x10780017fff7fff", - "0x4", - "0x482480017ffb8000", + "0x48127ffa7fff8000", + "0x482480017ff98000", "0x1", - "0x480a7ff37fff8000", - "0x480a7ff57fff8000", - "0x480a7ff67fff8000", - "0x480a7ff77fff8000", - "0x480a7ff87fff8000", - "0x480a7ff97fff8000", - "0x480a7ffa7fff8000", + "0x208b7fff7fff7ffe", + "0x4824800180007ff8", + "0x62c83572d28cb834a3de3c1e94977a4191469a4a8c26d1d7bc55305e640ed5", + "0x482480017ffe8000", + "0x292c", + "0x20680017fff7ffe", + "0xa", + "0x48127feb7fff8000", + "0x48127ffe7fff8000", "0x480a7ffb7fff8000", - "0x480a7ffc7fff8000", + "0x48127ff67fff8000", + "0x48127ff67fff8000", "0x1104800180018000", - "0xc4c", - "0x20680017fff7ffd", - "0x3e", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffff28", + "0x208b7fff7fff7ffe", + "0x4824800180007ff6", + "0x32564d7e0fe091d49b4c20f4632191e4ed6986bf993849879abfef9465def25", + "0x482480017ffe8000", + "0x366", "0x20680017fff7ffe", - "0x2d", - "0x48127ffa7fff8000", + "0x10", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x6661696c", + "0x400080007ffe7fff", + "0x48127fe77fff8000", + "0x48127ffc7fff8000", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", "0x48127ffa7fff8000", - "0x480a7ff47fff8000", - "0x48127ff97fff8000", - "0x48127ffb7fff8000", - "0x1104800180018000", - "0x10c0", - "0x20680017fff7ffd", - "0x1b", - "0x48317fff80007ffd", - "0x20680017fff7fff", - "0xd", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x48127ff87fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x48127fe97fff8000", + "0x482480017ffe8000", + "0x12c", + "0x480a7ffb7fff8000", "0x480680017fff8000", "0x0", "0x480680017fff8000", @@ -14212,2603 +13677,2514 @@ "0x480680017fff8000", "0x0", "0x208b7fff7fff7ffe", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x48127ff87fff8000", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", + "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x400080007ffe7fff", + "0x48127ff17fff8000", + "0x482480017ffa8000", + "0x31a6", + "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x480680017fff8000", - "0x496e76616c6964207369676e6174757265", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", "0x208b7fff7fff7ffe", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x48127ff97fff8000", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x400080007ffe7fff", + "0x48127ff67fff8000", + "0x482480017ffa8000", + "0x33fe", + "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x48127ff97fff8000", - "0x48127ff97fff8000", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4f7074696f6e3a3a756e77726170206661696c65642e", "0x400080007ffe7fff", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x480a7ff47fff8000", - "0x48127ff77fff8000", + "0x48127ffb7fff8000", + "0x482480017ffb8000", + "0x3656", + "0x480a7ffb7fff8000", "0x480680017fff8000", "0x1", - "0x48127ff97fff8000", - "0x482480017ff88000", + "0x48127ffa7fff8000", + "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4469766973696f6e2062792030", + "0x400080007ffe7fff", + "0x482680017ff98000", + "0x2", + "0x482480017ff98000", + "0x3782", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", "0x48127ffa7fff8000", - "0x48127ffa7fff8000", - "0x480a7ff47fff8000", - "0x48127ff97fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x482680017ff98000", + "0x1", + "0x480a7ffa7fff8000", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", "0x1", - "0x48127ff97fff8000", - "0x48127ff97fff8000", "0x208b7fff7fff7ffe", - "0x20780017fff7ff9", - "0xb", - "0x20780017fff7ffa", + "0xa0680017fff8000", "0x7", - "0x40780017fff7fff", - "0x2bb", - "0x480a7ff47fff8000", + "0x482680017ffc8000", + "0xfffffffffffffffffffffffffffffb6e", + "0x400280007ffb7fff", "0x10780017fff7fff", - "0x2b", - "0x10780017fff7fff", - "0x2", - "0x480680017fff8000", - "0xffffffff00000000ffffffffffffffff", - "0x48317fff80017ffa", - "0xa0680017fff7fff", - "0x7", - "0x482480017fff8000", - "0x100000000000000000000000000000000", - "0x400280007ff47fff", - "0x10780017fff7fff", - "0x25", - "0x400280007ff47fff", - "0x482680017ff48000", + "0x1f", + "0x4825800180007ffc", + "0x492", + "0x400280007ffb7fff", + "0x482680017ffb8000", "0x1", - "0x4825800180007ffa", - "0xffffffff00000000ffffffffffffffff", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x7", + "0x48127ffe7fff8000", + "0x20780017fff7ffd", + "0x10", "0x40780017fff7fff", - "0x2b6", - "0x48127d487fff8000", - "0x10780017fff7fff", - "0x11", + "0x1", + "0x480680017fff8000", + "0x7265637572736976655f6661696c", + "0x400080007ffe7fff", + "0x48127ffc7fff8000", + "0x482480017ffc8000", + "0x3ca", "0x480680017fff8000", - "0xbce6faada7179e84f3b9cac2fc632551", - "0x48317fff80017ff9", - "0xa0680017fff7fff", - "0x7", - "0x482480017fff8000", - "0x100000000000000000000000000000000", - "0x400080007ffa7fff", - "0x10780017fff7fff", - "0x9", - "0x400080007ffb7fff", - "0x40780017fff7fff", - "0x2b3", - "0x482480017d488000", "0x1", - "0x10780017fff7fff", - "0x48b", + "0x48127ffb7fff8000", "0x482480017ffa8000", "0x1", - "0x10780017fff7fff", - "0x6", - "0x40780017fff7fff", - "0x5", - "0x482680017ff48000", + "0x208b7fff7fff7ffe", + "0x48127ffe7fff8000", + "0x48127ffe7fff8000", + "0x4825800180007ffd", "0x1", - "0x20780017fff7ffb", - "0xd", - "0x20780017fff7ffc", - "0x9", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffe0", + "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0x9", - "0x48127ff67fff8000", + "0x1", "0x480680017fff8000", - "0x0", - "0x10780017fff7fff", - "0x3d", - "0x10780017fff7fff", - "0x2", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x482680017ffb8000", + "0x1", + "0x480a7ffc7fff8000", "0x480680017fff8000", - "0xffffffff00000000ffffffffffffffff", - "0x48317fff80017ffc", - "0xa0680017fff7fff", + "0x1", + "0x48127ffb7fff8000", + "0x482480017ffa8000", + "0x1", + "0x208b7fff7fff7ffe", + "0xa0680017fff8000", "0x7", - "0x482480017fff8000", - "0x100000000000000000000000000000000", - "0x400080007ffb7fff", + "0x482680017ffc8000", + "0xfffffffffffffffffffffffffffffb6e", + "0x400280007ffb7fff", "0x10780017fff7fff", - "0x2b", - "0x400080007ffc7fff", - "0x482480017ffc8000", - "0x1", + "0x1b", "0x4825800180007ffc", - "0xffffffff00000000ffffffffffffffff", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x9", - "0x40780017fff7fff", - "0x4", - "0x48127ffa7fff8000", + "0x492", + "0x400280007ffb7fff", + "0x482680017ffb8000", + "0x1", + "0x48127ffe7fff8000", + "0x20780017fff7ffd", + "0xc", + "0x48127ffe7fff8000", + "0x482480017ffe8000", + "0x4f6", "0x480680017fff8000", "0x0", - "0x10780017fff7fff", - "0x21", "0x480680017fff8000", - "0xbce6faada7179e84f3b9cac2fc632551", - "0x48317fff80017ffb", - "0xa0680017fff7fff", - "0x7", - "0x482480017fff8000", - "0x100000000000000000000000000000000", - "0x400080007ffa7fff", - "0x10780017fff7fff", - "0xb", - "0x400080007ffb7fff", + "0x0", + "0x480680017fff8000", + "0x0", + "0x208b7fff7fff7ffe", + "0x48127ffe7fff8000", + "0x48127ffe7fff8000", + "0x4825800180007ffd", + "0x1", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffe4", + "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1", + "0x480680017fff8000", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x482680017ffb8000", + "0x1", + "0x480a7ffc7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffb7fff8000", "0x482480017ffa8000", "0x1", + "0x208b7fff7fff7ffe", "0x480680017fff8000", - "0x0", - "0x10780017fff7fff", + "0x2691cb735b18f3f656c3b82bd97a32b65d15019b64117513f8604d1e06fe58b", + "0x400280007ff97fff", + "0x400380017ff97ffb", + "0x480280027ff98000", + "0xa0680017fff8005", "0xe", - "0x482480017ffa8000", + "0x4824800180057ffe", + "0x7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00", + "0x484480017ffe8000", + "0x110000000000000000", + "0x48307ffe7fff8003", + "0x480280007ff77ffc", + "0x480280017ff77ffc", + "0x482480017ffb7ffd", + "0xffffffffffffffeefffffffffffffeff", + "0x400280027ff77ffc", + "0x10780017fff7fff", + "0x11", + "0x48127ffe7fff8005", + "0x484480017ffe8000", + "0x8000000000000000000000000000000", + "0x48307ffe7fff8003", + "0x480280007ff77ffd", + "0x482480017ffc7ffe", + "0xf0000000000000000000000000000100", + "0x480280017ff77ffd", + "0x400280027ff77ff9", + "0x402480017ffd7ff9", + "0xffffffffffffffffffffffffffffffff", + "0x20680017fff7ffd", + "0x4", + "0x402780017fff7fff", "0x1", "0x480680017fff8000", + "0x0", + "0x482680017ff98000", + "0x3", + "0x482680017ff78000", + "0x3", + "0x480680017fff8000", + "0x53746f7261676552656164", + "0x400280007ffa7fff", + "0x400380017ffa7ff8", + "0x400280027ffa7ffc", + "0x400280037ffa7ffb", + "0x480280057ffa8000", + "0x20680017fff7fff", + "0x95", + "0x480280047ffa8000", + "0x48127fff7fff8000", + "0x480680017fff8000", + "0x0", + "0x482480017ff78000", "0x1", + "0x480280067ffa8000", + "0x480680017fff8000", + "0x53746f7261676552656164", + "0x400280077ffa7fff", + "0x400280087ffa7ffb", + "0x400280097ffa7ffc", + "0x4002800a7ffa7ffd", + "0x4802800c7ffa8000", + "0x20680017fff7fff", + "0x73", + "0x4802800b7ffa8000", + "0x480680017fff8000", + "0x2691cb735b18f3f656c3b82bd97a32b65d15019b64117513f8604d1e06fe58b", + "0x400080007ff37fff", + "0x400180017ff37ffb", + "0x480080027ff38000", + "0xa0680017fff8005", + "0xe", + "0x4824800180057ffe", + "0x7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00", + "0x484480017ffe8000", + "0x110000000000000000", + "0x48307ffe7fff8003", + "0x480080007fef7ffc", + "0x480080017fee7ffc", + "0x482480017ffb7ffd", + "0xffffffffffffffeefffffffffffffeff", + "0x400080027fec7ffc", "0x10780017fff7fff", - "0x8", - "0x40780017fff7fff", - "0x5", - "0x482480017ff68000", + "0x11", + "0x48127ffe7fff8005", + "0x484480017ffe8000", + "0x8000000000000000000000000000000", + "0x48307ffe7fff8003", + "0x480080007fef7ffd", + "0x482480017ffc7ffe", + "0xf0000000000000000000000000000100", + "0x480080017fed7ffd", + "0x400080027fec7ff9", + "0x402480017ffd7ff9", + "0xffffffffffffffffffffffffffffffff", + "0x20680017fff7ffd", + "0x4", + "0x402780017fff7fff", "0x1", + "0x48127ff67fff8000", "0x480680017fff8000", - "0x1", + "0x0", + "0x48287ffc7ff18000", + "0x4802800d7ffa8000", + "0x482480017fe78000", + "0x3", + "0x482480017fe78000", + "0x3", + "0x480680017fff8000", + "0x53746f726167655772697465", + "0x4002800e7ffa7fff", + "0x4002800f7ffa7ff9", + "0x400280107ffa7ffa", + "0x400280117ffa7ff8", + "0x400280127ffa7ffb", + "0x480280147ffa8000", + "0x20680017fff7fff", + "0x2b", + "0x480280137ffa8000", + "0x48127fff7fff8000", "0x480680017fff8000", + "0x0", + "0x482480017ff48000", "0x1", - "0x48307ffe80007fff", + "0x48287ffd7ff78000", + "0x480680017fff8000", + "0x53746f726167655772697465", + "0x400280157ffa7fff", + "0x400280167ffa7ffb", + "0x400280177ffa7ffc", + "0x400280187ffa7ffd", + "0x400280197ffa7ffe", + "0x4802801b7ffa8000", "0x20680017fff7fff", - "0x435", + "0x12", + "0x40780017fff7fff", + "0x4", + "0x4802801a7ffa8000", + "0x48127ff17fff8000", + "0x482480017ffe8000", + "0x168", + "0x48127fee7fff8000", + "0x482680017ffa8000", + "0x1c", "0x480680017fff8000", - "0xbce6faada7179e84f3b9cac2fc632551", + "0x0", "0x480680017fff8000", - "0xffffffff00000000ffffffffffffffff", - "0xa0680017fff8000", - "0x37", - "0x480080007ff98001", - "0x480080017ff88001", - "0x480080027ff78001", - "0x480080037ff68001", - "0x48307ffe80017ffa", + "0x0", + "0x480680017fff8000", + "0x0", + "0x208b7fff7fff7ffe", + "0x4802801a7ffa8000", + "0x48127fff7fff8000", + "0x482680017ffa8000", + "0x1e", + "0x4802801c7ffa8000", + "0x4802801d7ffa8000", + "0x10780017fff7fff", + "0xb", "0x40780017fff7fff", - "0x12", - "0x20680017fff7fee", - "0x8", - "0x40307fea7fef7fe6", - "0x402480017ff07fef", + "0x7", + "0x480280137ffa8000", + "0x482480017fff8000", + "0x2bde", + "0x482680017ffa8000", + "0x17", + "0x480280157ffa8000", + "0x480280167ffa8000", + "0x48127ff17fff8000", + "0x48127ffb7fff8000", + "0x48127fee7fff8000", + "0x48127ffa7fff8000", + "0x480680017fff8000", "0x1", - "0x400080047fe27ff0", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x13", + "0x4802800b7ffa8000", + "0x1104800180018000", + "0x2301", + "0x482480017fff8000", + "0x2300", + "0x480080007fff8000", + "0x480080007fff8000", + "0x482480017fff8000", + "0x5be0", + "0x48307fff7ff98000", + "0x482680017ffa8000", + "0xf", + "0x4802800d7ffa8000", + "0x4802800e7ffa8000", "0x10780017fff7fff", - "0x3", - "0x400080047fe27fee", - "0x482480017ff98001", + "0x12", + "0x40780017fff7fff", + "0x1a", + "0x480280047ffa8000", + "0x1104800180018000", + "0x22ef", + "0x482480017fff8000", + "0x22ee", + "0x480080007fff8000", + "0x480080007fff8000", + "0x482480017fff8000", + "0x87be", + "0x48307fff7ff98000", + "0x482680017ffa8000", + "0x8", + "0x480280067ffa8000", + "0x480280077ffa8000", + "0x48127fd87fff8000", + "0x48127ffb7fff8000", + "0x48127fd57fff8000", + "0x48127ffa7fff8000", + "0x480680017fff8000", "0x1", - "0x48307ff080018000", - "0x4844800180018000", - "0x100000000000000000000000000000000", - "0x4850800080008000", - "0x48307fff7ff68000", - "0x48307ff67fff8000", - "0x48307ff77fff8000", - "0x48307feb80007fff", - "0x48307feb80007fff", - "0x48307fec80007fff", - "0x4844800180007fff", - "0x100000000000000000000000000000000", - "0x4824800180007fff", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffff8001", - "0x400080057fd67fff", - "0x482480017ffe8000", - "0xffffffffffffffffffffffffffff8000", - "0x400080067fd57fff", - "0x48307ffd7fef8000", - "0x48307ff07fff8000", - "0x48307ff07fff8000", - "0x48307fe680007fff", - "0x48307fe380007fff", - "0x48307fe580007fff", - "0x4844800180007fff", - "0x100000000000000000000000000000000", - "0x4824800180007fff", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffff8001", - "0x400080077fcd7fff", - "0x482480017ffe8000", - "0xffffffffffffffffffffffffffff8000", - "0x400080087fcc7fff", - "0x40307ffd7fea7fe2", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x208b7fff7fff7ffe", + "0x480680017fff8000", + "0x2691cb735b18f3f656c3b82bd97a32b65d15019b64117513f8604d1e06fe58b", + "0x400280007ff97fff", + "0x400380017ff97ffb", + "0x480280027ff98000", + "0xa0680017fff8005", + "0xe", + "0x4824800180057ffe", + "0x7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00", + "0x484480017ffe8000", + "0x110000000000000000", + "0x48307ffe7fff8003", + "0x480280007ff67ffc", + "0x480280017ff67ffc", + "0x482480017ffb7ffd", + "0xffffffffffffffeefffffffffffffeff", + "0x400280027ff67ffc", "0x10780017fff7fff", - "0x31", - "0x480080007ff97fff", - "0x480080017ff87fff", - "0x480080027ff77fff", - "0x480080037ff67fff", - "0x480080047ff57fff", - "0x400080057ff47fff", - "0xa0680017fff7ffb", - "0xa", - "0x402480017fff7ff9", + "0x11", + "0x48127ffe7fff8005", + "0x484480017ffe8000", + "0x8000000000000000000000000000000", + "0x48307ffe7fff8003", + "0x480280007ff67ffd", + "0x482480017ffc7ffe", + "0xf0000000000000000000000000000100", + "0x480280017ff67ffd", + "0x400280027ff67ff9", + "0x402480017ffd7ff9", + "0xffffffffffffffffffffffffffffffff", + "0x20680017fff7ffd", + "0x4", + "0x402780017fff7fff", "0x1", + "0x480680017fff8000", + "0x0", + "0x482680017ff98000", + "0x3", + "0x482680017ff68000", + "0x3", + "0x480680017fff8000", + "0x53746f7261676552656164", + "0x400280007ffa7fff", + "0x400380017ffa7ff7", + "0x400280027ffa7ffc", + "0x400280037ffa7ffb", + "0x480280057ffa8000", "0x20680017fff7fff", - "0x6", - "0x400680017fff7ff8", + "0x111", + "0x480280047ffa8000", + "0x48127fff7fff8000", + "0x480680017fff8000", "0x0", - "0x400680017fff7ff7", + "0x482480017ff78000", "0x1", - "0xa0680017fff7ffa", - "0xc", - "0x48507ff87ffb8001", - "0x48507ff77ffc8001", - "0xa0680017fff8002", - "0x5", - "0x48307ffa7ff88000", - "0x90780017fff7fff", - "0x11", - "0x48127ff57fff8000", - "0x90780017fff7fff", + "0x480280067ffa8000", + "0x480680017fff8000", + "0x53746f7261676552656164", + "0x400280077ffa7fff", + "0x400280087ffa7ffb", + "0x400280097ffa7ffc", + "0x4002800a7ffa7ffd", + "0x4802800c7ffa8000", + "0x20680017fff7fff", + "0xeb", + "0x4802800b7ffa8000", + "0x482680017ffa8000", "0xe", - "0x48507ff97ffa8001", - "0x48507ff87ffb8001", - "0x480680017fff7ff9", - "0x0", - "0x480680017fff7ffa", - "0x0", + "0x4802800d7ffa8000", + "0x48127ffd7fff8000", "0xa0680017fff8000", - "0x5", - "0x40307ff77ff57ffe", - "0x10780017fff7fff", - "0x3", - "0x40127ff47fff7ffe", - "0x482480017ffe8000", - "0xfffffffffffffffe0000000000000000", - "0x400080067fec7fff", - "0x40317ff97ffb7ffc", - "0x40307ffa7ffc7ff1", + "0x16", + "0x480080007ff18003", + "0x480080017ff08003", + "0x4844800180017ffe", + "0x100000000000000000000000000000000", + "0x483080017ffd7ff5", + "0x482480017fff7ffd", + "0x800000000000010fffffffffffffffff7ffffffffffffef0000000000000001", + "0x20680017fff7ffc", + "0x6", + "0x402480017fff7ffd", + "0xffffffffffffffffffffffffffffffff", "0x10780017fff7fff", - "0x37e", - "0x4824800180008002", - "0xffffffffffffffff0000000000000000", - "0x480080097fcb8001", - "0x4800800a7fca7ffe", - "0x4000800b7fc97ffe", - "0x484480017ffe8000", - "0x10000000000000000", - "0x40307ffc7fff7fcd", - "0x48507fd37ffc8000", - "0x48507fd27ffc8000", - "0x4824800180018002", - "0xffffffffffffffff0000000000000000", - "0x4800800c7fc58001", - "0x4800800d7fc47fff", - "0x4000800e7fc37ffd", - "0x484480017ffd8000", - "0x10000000000000000", - "0x40307ffd7fff7ffb", - "0x484480017ffd8000", - "0x10000000000000000", - "0x48307fff7ff98003", - "0x482480017fff8000", - "0xfffffffffffffffe0000000000000000", - "0x4800800f7fbf7fff", - "0x480080107fbe7ffd", - "0x400080117fbd7fda", - "0x404480017ffc7ffe", + "0x4", + "0x402480017ffe7ffd", + "0xf7ffffffffffffef0000000000000000", + "0x400080027fec7ffd", + "0x20680017fff7ffe", + "0xb3", + "0x402780017fff7fff", + "0x1", + "0x400080007ff17ff8", + "0x48127ffe7fff8000", + "0xa0680017fff8000", + "0x16", + "0x480080017fef8003", + "0x480080027fee8003", + "0x4844800180017ffe", "0x100000000000000000000000000000000", - "0x40307fda7ffe7fff", - "0x40307ffc7ff77fdb", - "0x4824800180008002", - "0xffffffffffffffff0000000000000000", - "0x480080127fbc8001", - "0x480080137fbb7ffe", - "0x400080147fba7ffe", - "0x484480017ffe8000", - "0x10000000000000000", - "0x40307ffc7fff7fbe", - "0x48507fc37ffc8000", - "0x48507fc27ffc8000", - "0x4824800180018002", - "0xffffffffffffffff0000000000000000", - "0x480080157fb68001", - "0x480080167fb57fff", - "0x400080177fb47ffd", - "0x484480017ffd8000", - "0x10000000000000000", - "0x40307ffd7fff7ffb", - "0x484480017ffd8000", - "0x10000000000000000", - "0x48307fff7ff98003", - "0x482480017fff8000", - "0xfffffffffffffffe0000000000000000", - "0x480080187fb07fff", - "0x480080197faf7ffd", - "0x4000801a7fae7fc9", - "0x404480017ffc7ffe", - "0x100000000000000000000000000000000", - "0x40307fc97ffe7fff", - "0x40307ffc7ff77fca", - "0x4824800180008002", - "0xffffffffffffffff0000000000000000", - "0x4800801b7fad8001", - "0x4800801c7fac7ffe", - "0x4000801d7fab7ffe", - "0x484480017ffe8000", - "0x10000000000000000", - "0x40307ffc7fff7fae", - "0x48507fb57ffc8000", - "0x48507fb47ffc8000", - "0x4824800180018002", - "0xffffffffffffffff0000000000000000", - "0x4800801e7fa78001", - "0x4800801f7fa67fff", - "0x400080207fa57ffd", - "0x484480017ffd8000", - "0x10000000000000000", - "0x40307ffd7fff7ffb", - "0x484480017ffd8000", - "0x10000000000000000", - "0x48307fff7ff98003", - "0x482480017fff8000", - "0xfffffffffffffffe0000000000000000", - "0x480080217fa17fff", - "0x480080227fa07ffd", - "0x400080237f9f7fb8", - "0x404480017ffc7ffe", - "0x100000000000000000000000000000000", - "0x40307fb87ffe7fff", - "0x40307ffc7ff77fb9", - "0x4824800180008002", - "0xffffffffffffffff0000000000000000", - "0x480080247f9e8001", - "0x480080257f9d7ffe", - "0x400080267f9c7ffe", - "0x484480017ffe8000", - "0x10000000000000000", - "0x40307ffc7fff7f9f", - "0x48507fa57ffc8000", - "0x48507fa47ffc8000", - "0x4824800180018002", - "0xffffffffffffffff0000000000000000", - "0x480080277f988001", - "0x480080287f977fff", - "0x400080297f967ffd", - "0x484480017ffd8000", - "0x10000000000000000", - "0x40307ffd7fff7ffb", - "0x484480017ffd8000", - "0x10000000000000000", - "0x48307fff7ff98003", - "0x482480017fff8000", - "0xfffffffffffffffe0000000000000000", - "0x4800802a7f927fff", - "0x4800802b7f917ffd", - "0x4000802c7f907fa7", - "0x404480017ffc7ffe", - "0x100000000000000000000000000000000", - "0x40307fa77ffe7fff", - "0x40307ffc7ff77fa8", - "0x4824800180008002", - "0xffffffffffffffff0000000000000000", - "0x4800802d7f8f8001", - "0x4800802e7f8e7ffe", - "0x4000802f7f8d7ffe", + "0x483080017ffd7ff8", + "0x482480017fff7ffd", + "0x800000000000010fffffffffffffffff7ffffffffffffef0000000000000001", + "0x20680017fff7ffc", + "0x6", + "0x402480017fff7ffd", + "0xffffffffffffffffffffffffffffffff", + "0x10780017fff7fff", + "0x4", + "0x402480017ffe7ffd", + "0xf7ffffffffffffef0000000000000000", + "0x400080037fea7ffd", + "0x20680017fff7ffe", + "0x7c", + "0x402780017fff7fff", + "0x1", + "0x400080017fef7ffb", + "0x400280007ff87ff6", + "0x400380017ff87ffc", + "0x400280057ff87ffb", + "0x400380067ff87ffd", + "0x480680017fff8000", + "0x2691cb735b18f3f656c3b82bd97a32b65d15019b64117513f8604d1e06fe58b", + "0x400080007fed7fff", + "0x400180017fed7ffb", + "0x480080027fed8000", + "0xa0680017fff8005", + "0xe", + "0x4824800180057ffe", + "0x7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00", "0x484480017ffe8000", - "0x10000000000000000", - "0x40307ffc7fff7f95", - "0x48487ffc7ffc8000", - "0x48487ffc7ffc8000", - "0x4824800180018002", - "0xffffffffffffffff0000000000000000", - "0x480080307f898001", - "0x480080317f887fff", - "0x400080327f877ffd", - "0x484480017ffd8000", - "0x10000000000000000", - "0x40307ffd7fff7ffb", - "0x484480017ffd8000", - "0x10000000000000000", - "0x48307fff7ff98003", - "0x482480017fff8000", - "0xfffffffffffffffe0000000000000000", - "0x480080337f837fff", - "0x480080347f827ffd", - "0x400080357f817f96", - "0x404480017ffc7ffe", - "0x100000000000000000000000000000000", - "0x40307f967ffe7fff", - "0x40307ffc7ff77f97", - "0x4824800180008002", - "0xffffffffffffffff0000000000000000", - "0x480080367f808001", - "0x480080377f7f7ffe", - "0x400080387f7e7ffe", + "0x110000000000000000", + "0x48307ffe7fff8003", + "0x480080027fe97ffc", + "0x480080037fe87ffc", + "0x482480017ffb7ffd", + "0xffffffffffffffeefffffffffffffeff", + "0x400080047fe67ffc", + "0x10780017fff7fff", + "0x11", + "0x48127ffe7fff8005", "0x484480017ffe8000", - "0x10000000000000000", - "0x40307ffc7fff7f86", - "0x48487ffb7ffc8000", - "0x48487ffb7ffc8000", - "0x4824800180018002", - "0xffffffffffffffff0000000000000000", - "0x480080397f7a8001", - "0x4800803a7f797fff", - "0x4000803b7f787ffd", - "0x484480017ffd8000", - "0x10000000000000000", - "0x40307ffd7fff7ffb", - "0x484480017ffd8000", - "0x10000000000000000", - "0x48307fff7ff98003", + "0x8000000000000000000000000000000", + "0x48307ffe7fff8003", + "0x480080027fe97ffd", + "0x482480017ffc7ffe", + "0xf0000000000000000000000000000100", + "0x480080037fe77ffd", + "0x400080047fe67ff9", + "0x402480017ffd7ff9", + "0xffffffffffffffffffffffffffffffff", + "0x20680017fff7ffd", + "0x4", + "0x402780017fff7fff", + "0x1", + "0x48127ff57fff8000", + "0x480680017fff8000", + "0x0", + "0x480280037ff88000", + "0x482680017ff88000", + "0xa", + "0x480280087ff88000", + "0x482480017fe08000", + "0x3", + "0x482480017fe08000", + "0x5", + "0x480680017fff8000", + "0x53746f726167655772697465", + "0x400080007fe97fff", + "0x400080017fe97ff8", + "0x400080027fe97ff9", + "0x400080037fe97ff7", + "0x400080047fe97ffa", + "0x480080067fe98000", + "0x20680017fff7fff", + "0x2b", + "0x480080057fe88000", + "0x48127fff7fff8000", + "0x480680017fff8000", + "0x0", + "0x482480017ff38000", + "0x1", + "0x480680017fff8000", + "0x53746f726167655772697465", + "0x400080077fe37fff", + "0x400080087fe37ffc", + "0x400080097fe37ffd", + "0x4000800a7fe37ffe", + "0x4000800b7fe37ff6", + "0x4800800d7fe38000", + "0x20680017fff7fff", + "0x13", + "0x40780017fff7fff", + "0x4", + "0x4800800c7fde8000", + "0x48127ff27fff8000", + "0x482480017ffe8000", + "0x168", + "0x48127fed7fff8000", + "0x48127fee7fff8000", + "0x482480017fd98000", + "0xe", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x208b7fff7fff7ffe", + "0x4800800c7fe28000", + "0x48127fff7fff8000", + "0x482480017fe08000", + "0x10", + "0x4800800e7fdf8000", + "0x4800800f7fde8000", + "0x10780017fff7fff", + "0xb", + "0x40780017fff7fff", + "0x6", + "0x480080057fe28000", "0x482480017fff8000", - "0xfffffffffffffffe0000000000000000", - "0x4800803c7f747fff", - "0x4800803d7f737ffd", - "0x4000803e7f727f85", - "0x404480017ffc7ffe", - "0x100000000000000000000000000000000", - "0x40307f857ffe7fff", - "0x40307ffc7ff77f86", - "0x4824800180008002", - "0xffffffffffffffff0000000000000000", - "0x4800803f7f718001", - "0x480080407f707ffe", - "0x400080417f6f7ffe", - "0x484480017ffe8000", - "0x10000000000000000", - "0x40307ffc7fff7f76", - "0x48487ffc7ffc8000", - "0x48487ffc7ffc8000", - "0x4824800180018002", - "0xffffffffffffffff0000000000000000", - "0x480080427f6b8001", - "0x480080437f6a7fff", - "0x400080447f697ffd", - "0x484480017ffd8000", - "0x10000000000000000", - "0x40307ffd7fff7ffb", - "0x484480017ffd8000", - "0x10000000000000000", - "0x48307fff7ff98003", + "0x2b84", + "0x482480017fe08000", + "0x9", + "0x480080077fdf8000", + "0x480080087fde8000", + "0x48127ff27fff8000", + "0x48127ffb7fff8000", + "0x48127fed7fff8000", + "0x48127fee7fff8000", + "0x48127ff97fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ff87fff8000", + "0x48127ff87fff8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0xd", + "0x1104800180018000", + "0x21eb", "0x482480017fff8000", - "0xfffffffffffffffe0000000000000000", - "0x480080457f657fff", - "0x480080467f647ffd", - "0x400080477f637f74", - "0x404480017ffc7ffe", - "0x100000000000000000000000000000000", - "0x40307f747ffe7fff", - "0x40307ffc7ff77f75", - "0x4824800180008002", - "0xffffffffffffffff0000000000000000", - "0x480080487f628001", - "0x480080497f617ffe", - "0x4000804a7f607ffe", - "0x484480017ffe8000", - "0x10000000000000000", - "0x40307ffc7fff7f67", - "0x48487ffb7ffc8000", - "0x48487ffb7ffc8000", - "0x4824800180018002", - "0xffffffffffffffff0000000000000000", - "0x4800804b7f5c8001", - "0x4800804c7f5b7fff", - "0x4000804d7f5a7ffd", - "0x484480017ffd8000", - "0x10000000000000000", - "0x40307ffd7fff7ffb", - "0x484480017ffd8000", - "0x10000000000000000", - "0x48307fff7ff98003", + "0x21ea", + "0x480080007fff8000", + "0x480080007fff8000", "0x482480017fff8000", - "0xfffffffffffffffe0000000000000000", - "0x4800804e7f567fff", - "0x4800804f7f557ffd", - "0x400080507f547f63", - "0x404480017ffc7ffe", - "0x100000000000000000000000000000000", - "0x40307f637ffe7fff", - "0x40307ffc7ff77f64", - "0x482480017f548000", - "0x51", - "0x480a7ff77fff8000", + "0x5938", + "0x480080017ffd8000", + "0x484480017fff8000", + "0x2", + "0x48307ffd7fff8000", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x400080007ffe7fff", + "0x482480017fd28000", + "0x4", + "0x48307ffc7fe08000", "0x480a7ff87fff8000", - "0x48127f597fff8000", - "0x48127f597fff8000", + "0x48127fce7fff8000", + "0x48127fd97fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ff87fff8000", + "0x482480017ff78000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0xf", "0x1104800180018000", - "0xf62", + "0x21cc", + "0x482480017fff8000", + "0x21cb", + "0x480080007fff8000", + "0x480080007fff8000", + "0x482480017fff8000", + "0x5a96", + "0x480080017ffd8000", + "0x484480017fff8000", + "0x2", + "0x48307ffd7fff8000", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0xbce6faada7179e84f3b9cac2fc632551", + "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x400080007ffe7fff", + "0x482480017fd28000", + "0x3", + "0x48307ffc7fde8000", + "0x480a7ff87fff8000", + "0x48127fce7fff8000", + "0x48127fd97fff8000", "0x480680017fff8000", - "0xffffffff00000000ffffffffffffffff", - "0x480080007ff98000", - "0x480080017ff88000", - "0x480080027ff78000", - "0x480080037ff68000", - "0x480080047ff58000", - "0x480080057ff48000", - "0x48307fff80007ff9", + "0x1", + "0x48127ff87fff8000", + "0x482480017ff78000", + "0x1", + "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0xc", - "0x20680017fff7ff3", + "0x16", + "0x4802800b7ffa8000", + "0x1104800180018000", + "0x21ac", + "0x482480017fff8000", + "0x21ab", + "0x480080007fff8000", + "0x480080007fff8000", + "0x482480017fff8000", + "0x5fd2", + "0x480080017ffd8000", + "0x484480017fff8000", + "0x2", + "0x48307ffd7fff8000", + "0x48307fff7ff68000", + "0x482680017ffa8000", + "0xf", + "0x4802800d7ffa8000", + "0x4802800e7ffa8000", + "0x10780017fff7fff", + "0x16", + "0x40780017fff7fff", + "0x1d", + "0x480280047ffa8000", + "0x1104800180018000", + "0x2196", + "0x482480017fff8000", + "0x2195", + "0x480080007fff8000", + "0x480080007fff8000", + "0x482480017fff8000", + "0x8bb0", + "0x480080017ffd8000", + "0x484480017fff8000", + "0x2", + "0x48307ffd7fff8000", + "0x48307fff7ff68000", + "0x482680017ffa8000", "0x8", - "0x40307ff17ff47feb", - "0x402480017ff57ff4", + "0x480280067ffa8000", + "0x480280077ffa8000", + "0x48127fd27fff8000", + "0x48127ffb7fff8000", + "0x480a7ff87fff8000", + "0x48127fce7fff8000", + "0x48127ff97fff8000", + "0x480680017fff8000", "0x1", - "0x400080067fe67ff5", - "0x10780017fff7fff", - "0x3", - "0x400080067fe67ff3", - "0x48307ff17ff68000", - "0x48307fe680007fff", - "0x4844800180007fff", - "0x100000000000000000000000000000000", - "0x40507fff7fff7fff", - "0x48307ff47fff8000", - "0x48307ff47fff8000", - "0x48307ff57fff8000", - "0x48307fec7fff8000", - "0x48307fe180007fff", - "0x4844800180007fff", - "0x100000000000000000000000000000000", - "0x400080077fdd7fff", + "0x48127ff87fff8000", + "0x48127ff87fff8000", + "0x208b7fff7fff7ffe", + "0x480680017fff8000", + "0x654fd7e67a123dd13868093b3b7777f1ffef596c2e324f25ceaf9146698482c", + "0x480680017fff8000", + "0x4fad269cbf860980e38768fe9cb6b0b9ab03ee3fe84cfde2eccce597c874fd8", + "0x48507fff7fff8000", + "0x48507ffd7ffd8001", + "0x48507ffc80008001", + "0x482480017ffb8001", + "0x6f21413efbe40de150e596d72f7a8c5609ad26c15c915c1f4cdfcb99cee9e89", + "0x483080007fff7ffd", + "0x48307ffc80007ffb", + "0x20680017fff7fff", + "0x12a", + "0x48127ff87fff8000", + "0x48127ff87fff8000", + "0x480680017fff8000", + "0x3dbce56de34e1cfe252ead5a1f14fd261d520d343ff6b7652174e62976ef44d", + "0x480680017fff8000", + "0x4b5810004d9272776dec83ecc20c19353453b956e594188890b48467cb53c19", + "0x480a7ffc7fff8000", + "0x48507ffe7ffe8000", + "0x48507ffc7ffc8001", + "0x48507ffb80008001", + "0x482480017ffa8001", + "0x6f21413efbe40de150e596d72f7a8c5609ad26c15c915c1f4cdfcb99cee9e89", + "0x483080007fff7ffd", + "0x48307ffc80007ffb", + "0x20680017fff7fff", + "0x102", + "0x48127ff77fff8000", + "0x48127ff77fff8000", + "0x48127ff77fff8000", + "0x20680017fff7ffe", + "0x12", + "0x40780017fff7fff", + "0x12", + "0x1104800180018000", + "0x2157", "0x482480017fff8000", - "0xfffffffffffffffffffffffffffffffc", - "0x400080087fdc7fff", - "0x48307fef7ffe8000", - "0x48307ff07fff8000", - "0x48307ff07fff8000", - "0x48307ff17fff8000", - "0x48307fdb80007fff", - "0x4844800180007fff", - "0x100000000000000000000000000000000", - "0x400080097fd67fff", + "0x2156", + "0x480080007fff8000", + "0x480080027fff8000", "0x482480017fff8000", - "0xfffffffffffffffffffffffffffffffc", - "0x4000800a7fd57fff", - "0xa0680017fff7fdf", - "0xc", - "0xa0680017fff8001", - "0x6", - "0x48127fd97fff7ffe", - "0x40127fdb7fff7ffe", + "0x848", + "0x480a7ffb7fff8000", + "0x48307ffe7fe68000", + "0x48127fe37fff8000", + "0x48127fe37fff8000", + "0x10780017fff7fff", + "0x36", + "0x4800800080068004", + "0x4800800180058004", + "0x4850800380037ffe", + "0x4850800180017ffe", + "0x485080007ffd7ffe", + "0x482480017fff7ffe", + "0x6f21413efbe40de150e596d72f7a8c5609ad26c15c915c1f4cdfcb99cee9e89", + "0x48307ffd7ffc7ffa", + "0x480680017fff8000", + "0x6d232c016ef1b12aec4b7f88cc0b3ab662be3b7dd7adbce5209fcfdbd42a504", + "0x400280007ffb7ffc", + "0x400280017ffb7ffd", + "0x400280027ffb7ff5", + "0x400280037ffb7ff6", + "0x400280047ffb7fff", + "0x480280057ffb8000", + "0x480280067ffb8000", + "0x48127ffc7fff8000", + "0x48127ff47fff8000", + "0x482680017ffb8000", + "0x7", + "0x480080007ffd8000", + "0x480080017ffc8000", + "0x48307ffe80007ff9", + "0x20680017fff7fff", + "0x5", + "0x40127ffe7fff7ff9", "0x10780017fff7fff", "0x10", - "0x48127fdc7fff7ffe", - "0x40127fd87fff7ffe", + "0x48307ffe7ff98000", + "0x48507ffe80007fff", + "0x48507fff7fff8000", + "0x48307ffa7ff58000", + "0x48307fff80027ffe", + "0x483080017fff7ff3", + "0x48507ffe7ffb7fff", + "0x48307ff280007ffe", + "0x48127ff47fff8000", + "0x48127ff27fff8000", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", "0x10780017fff7fff", - "0xc", - "0x480680017fff7fda", + "0xb", + "0x40780017fff7fff", + "0x8", + "0x48127ff47fff8000", + "0x482480017ff28000", + "0x208", + "0x480680017fff8000", "0x0", - "0xa0680017fff8000", - "0x6", - "0x40127fd77fff7ffd", - "0x40127fdc7fff7ffe", + "0x480680017fff8000", + "0x0", + "0x20680017fff7fff", + "0xa", + "0x40780017fff7fff", + "0x2c", + "0x482480017fd18000", + "0x10a4", + "0x48127fa97fff8000", + "0x48127fa97fff8000", + "0x10780017fff7fff", + "0x53", + "0x48127ffd7fff8000", + "0x20680017fff7fd6", + "0xa", + "0x40780017fff7fff", + "0x2b", + "0x482480017fd48000", + "0xfe6", + "0x48127fd17fff8000", + "0x48127fd17fff8000", "0x10780017fff7fff", + "0x48", + "0x4800800080068004", + "0x4800800180058004", + "0x4850800380037ffe", + "0x4850800180017ffe", + "0x485080007ffd7ffe", + "0x482480017fff7ffe", + "0x6f21413efbe40de150e596d72f7a8c5609ad26c15c915c1f4cdfcb99cee9e89", + "0x48307ffd7ffc7ffa", + "0x48307ffd80007ff6", + "0x20680017fff7fff", "0x4", - "0x40127fdc7fff7ffd", - "0x40127fd77fff7ffe", - "0x482480017ffd8000", - "0xffffffffffffffff0000000000000000", - "0x4000800b7fd17fff", - "0x48507ffd7ffc8000", - "0x48307fe97ff98000", - "0x48307fe67fff8000", - "0x40307ffd7fff7fd2", - "0x4824800180008002", - "0xffffffffffffffff0000000000000000", - "0x4800800c7fcd8001", - "0x4800800d7fcc7ffe", - "0x4000800e7fcb7ffe", - "0x484480017ffe8000", - "0x10000000000000000", - "0x40307ffc7fff7fd3", - "0x48507fcf7ffc8000", - "0x48507fce7ffc8000", - "0x4824800180018002", - "0xffffffffffffffff0000000000000000", - "0x4800800f7fc78001", - "0x480080107fc67fff", - "0x400080117fc57ffd", - "0x484480017ffd8000", - "0x10000000000000000", - "0x40307ffd7fff7ffb", - "0x484480017ffd8000", - "0x10000000000000000", - "0x48307fff7ff98003", - "0x482480017fff8000", - "0xfffffffffffffffe0000000000000000", - "0x480080127fc17fff", - "0x480080137fc07ffd", - "0x400080147fbf7fd7", - "0x404480017ffc7ffe", - "0x100000000000000000000000000000000", - "0x40307fd77ffe7fff", - "0x40307ffc7ff77fd8", - "0x4824800180008002", - "0xffffffffffffffff0000000000000000", - "0x480080157fbe8001", - "0x480080167fbd7ffe", - "0x400080177fbc7ffe", - "0x484480017ffe8000", - "0x10000000000000000", - "0x40307ffc7fff7fc3", - "0x48507fc17ffc8000", - "0x48507fc07ffc8000", - "0x4824800180018002", - "0xffffffffffffffff0000000000000000", - "0x480080187fb88001", - "0x480080197fb77fff", - "0x4000801a7fb67ffd", - "0x484480017ffd8000", - "0x10000000000000000", - "0x40307ffd7fff7ffb", - "0x484480017ffd8000", - "0x10000000000000000", - "0x48307fff7ff98003", - "0x482480017fff8000", - "0xfffffffffffffffe0000000000000000", - "0x4800801b7fb27fff", - "0x4800801c7fb17ffd", - "0x4000801d7fb07fc6", - "0x404480017ffc7ffe", - "0x100000000000000000000000000000000", - "0x40307fc67ffe7fff", - "0x40307ffc7ff77fc7", - "0x4824800180008002", - "0xffffffffffffffff0000000000000000", - "0x4800801e7faf8001", - "0x4800801f7fae7ffe", - "0x400080207fad7ffe", - "0x484480017ffe8000", - "0x10000000000000000", - "0x40307ffc7fff7fb4", - "0x48507fb17ffc8000", - "0x48507fb07ffc8000", - "0x4824800180018002", - "0xffffffffffffffff0000000000000000", - "0x480080217fa98001", - "0x480080227fa87fff", - "0x400080237fa77ffd", - "0x484480017ffd8000", - "0x10000000000000000", - "0x40307ffd7fff7ffb", - "0x484480017ffd8000", - "0x10000000000000000", - "0x48307fff7ff98003", - "0x482480017fff8000", - "0xfffffffffffffffe0000000000000000", - "0x480080247fa37fff", - "0x480080257fa27ffd", - "0x400080267fa17fb3", - "0x404480017ffc7ffe", - "0x100000000000000000000000000000000", - "0x40307fb37ffe7fff", - "0x40307ffc7ff77fb4", - "0x4824800180008002", - "0xffffffffffffffff0000000000000000", - "0x480080277fa08001", - "0x480080287f9f7ffe", - "0x400080297f9e7ffe", - "0x484480017ffe8000", - "0x10000000000000000", - "0x40307ffc7fff7fa4", - "0x48507fa37ffc8000", - "0x48507fa27ffc8000", - "0x4824800180018002", - "0xffffffffffffffff0000000000000000", - "0x4800802a7f9a8001", - "0x4800802b7f997fff", - "0x4000802c7f987ffd", - "0x484480017ffd8000", - "0x10000000000000000", - "0x40307ffd7fff7ffb", - "0x484480017ffd8000", - "0x10000000000000000", - "0x48307fff7ff98003", - "0x482480017fff8000", - "0xfffffffffffffffe0000000000000000", - "0x4800802d7f947fff", - "0x4800802e7f937ffd", - "0x4000802f7f927fa6", - "0x404480017ffc7ffe", - "0x100000000000000000000000000000000", - "0x40307fa67ffe7fff", - "0x40307ffc7ff77fa7", - "0x4824800180008002", - "0xffffffffffffffff0000000000000000", - "0x480080307f918001", - "0x480080317f907ffe", - "0x400080327f8f7ffe", - "0x484480017ffe8000", - "0x10000000000000000", - "0x40307ffc7fff7f95", - "0x48507f937ffc8000", - "0x48507f927ffc8000", - "0x4824800180018002", - "0xffffffffffffffff0000000000000000", - "0x480080337f8b8001", - "0x480080347f8a7fff", - "0x400080357f897ffd", - "0x484480017ffd8000", - "0x10000000000000000", - "0x40307ffd7fff7ffb", - "0x484480017ffd8000", - "0x10000000000000000", - "0x48307fff7ff98003", - "0x482480017fff8000", - "0xfffffffffffffffe0000000000000000", - "0x480080367f857fff", - "0x480080377f847ffd", - "0x400080387f837f93", - "0x404480017ffc7ffe", - "0x100000000000000000000000000000000", - "0x40307f937ffe7fff", - "0x40307ffc7ff77f94", - "0x482480017f838000", - "0x39", - "0x480a7ff97fff8000", - "0x480a7ffa7fff8000", - "0x48127e6b7fff8000", - "0x48127e6b7fff8000", - "0x1104800180018000", - "0xe76", - "0x480680017fff8000", - "0xbce6faada7179e84f3b9cac2fc632551", - "0x480680017fff8000", - "0xffffffff00000000ffffffffffffffff", - "0x480080007ff98000", - "0x480080017ff88000", - "0x480080027ff78000", - "0x480080037ff68000", - "0x480080047ff58000", - "0x480080057ff48000", - "0x48307fff80007ff9", - "0x40780017fff7fff", - "0xc", - "0x20680017fff7ff3", - "0x8", - "0x40307ff17ff47feb", - "0x402480017ff57ff4", + "0x402780017fff7fff", "0x1", - "0x400080067fe67ff5", - "0x10780017fff7fff", - "0x3", - "0x400080067fe67ff3", - "0x48307ff17ff68000", - "0x48307fe680007fff", - "0x4844800180007fff", - "0x100000000000000000000000000000000", - "0x40507fff7fff7fff", - "0x48307ff47fff8000", - "0x48307ff47fff8000", - "0x48307ff57fff8000", - "0x48307fec7fff8000", - "0x48307fe180007fff", - "0x4844800180007fff", - "0x100000000000000000000000000000000", - "0x400080077fdd7fff", - "0x482480017fff8000", - "0xfffffffffffffffffffffffffffffffc", - "0x400080087fdc7fff", - "0x48307fef7ffe8000", - "0x48307ff07fff8000", - "0x48307ff07fff8000", - "0x48307ff17fff8000", - "0x48307fdb80007fff", - "0x4844800180007fff", - "0x100000000000000000000000000000000", - "0x400080097fd67fff", - "0x482480017fff8000", - "0xfffffffffffffffffffffffffffffffc", - "0x4000800a7fd57fff", - "0xa0680017fff7fdf", - "0xc", - "0xa0680017fff8001", - "0x6", - "0x48127fd97fff7ffe", - "0x40127fdb7fff7ffe", - "0x10780017fff7fff", - "0x10", - "0x48127fdc7fff7ffe", - "0x40127fd87fff7ffe", + "0x48307ffd80007ff6", + "0x48507ffe80007fff", + "0x48507fff7fff8000", + "0x48307ff97ff28000", + "0x48307fff80027ffe", + "0x483080017fff7ff0", + "0x48507ffe7ffb7fff", + "0x48307fef80007ffe", + "0x48127ffe7fff8000", + "0x48127ffe7fff8000", + "0x48127ff47fff8000", + "0x48307ffd80007fc2", + "0x20680017fff7fff", + "0x4", + "0x402780017fff7fff", + "0x1", + "0x48307ffd80007fc2", + "0x48507ffe80007fff", + "0x48507fff7fff8000", + "0x48307ff97fbe8000", + "0x48307fff80027ffe", + "0x483080017fff7fbc", + "0x48507ffe7ffb7fff", + "0x48307fbb80007ffe", + "0x48127ffe7fff8000", + "0x48127ffe7fff8000", + "0x48127ff47fff8000", + "0x48127fe07fff8000", + "0x480080007ffe8000", + "0x480080017ffd8000", + "0x48307ffe80007ffa", + "0x20680017fff7fff", + "0x5", + "0x40127ffe7fff7ffa", "0x10780017fff7fff", - "0xc", - "0x480680017fff7fda", - "0x0", - "0xa0680017fff8000", - "0x6", - "0x40127fd77fff7ffd", - "0x40127fdc7fff7ffe", + "0xf", + "0x48307ffe7ffa8000", + "0x48507ffe80007fff", + "0x48507fff7fff8000", + "0x48307ffa7ff68000", + "0x48307fff80027ffe", + "0x483080017fff7ff4", + "0x48507ffe7ffb7fff", + "0x48307ff380007ffe", + "0x48127ff47fff8000", + "0x48127ffd7fff8000", + "0x48127ffd7fff8000", "0x10780017fff7fff", - "0x4", - "0x40127fdc7fff7ffd", - "0x40127fd77fff7ffe", - "0x482480017ffd8000", - "0xffffffffffffffff0000000000000000", - "0x4000800b7fd17fff", - "0x48507ffd7ffc8000", - "0x48307fe97ff98000", - "0x48307fe67fff8000", - "0x40307ffd7fff7fd2", - "0x4824800180008002", - "0xffffffffffffffff0000000000000000", - "0x4800800c7fcd8001", - "0x4800800d7fcc7ffe", - "0x4000800e7fcb7ffe", - "0x484480017ffe8000", - "0x10000000000000000", - "0x40307ffc7fff7fd3", - "0x48507fcf7ffc8000", - "0x48507fce7ffc8000", - "0x4824800180018002", - "0xffffffffffffffff0000000000000000", - "0x4800800f7fc78001", - "0x480080107fc67fff", - "0x400080117fc57ffd", - "0x484480017ffd8000", - "0x10000000000000000", - "0x40307ffd7fff7ffb", - "0x484480017ffd8000", - "0x10000000000000000", - "0x48307fff7ff98003", - "0x482480017fff8000", - "0xfffffffffffffffe0000000000000000", - "0x480080127fc17fff", - "0x480080137fc07ffd", - "0x400080147fbf7fd7", - "0x404480017ffc7ffe", - "0x100000000000000000000000000000000", - "0x40307fd77ffe7fff", - "0x40307ffc7ff77fd8", - "0x4824800180008002", - "0xffffffffffffffff0000000000000000", - "0x480080157fbe8001", - "0x480080167fbd7ffe", - "0x400080177fbc7ffe", - "0x484480017ffe8000", - "0x10000000000000000", - "0x40307ffc7fff7fc3", - "0x48507fc17ffc8000", - "0x48507fc07ffc8000", - "0x4824800180018002", - "0xffffffffffffffff0000000000000000", - "0x480080187fb88001", - "0x480080197fb77fff", - "0x4000801a7fb67ffd", - "0x484480017ffd8000", - "0x10000000000000000", - "0x40307ffd7fff7ffb", - "0x484480017ffd8000", - "0x10000000000000000", - "0x48307fff7ff98003", - "0x482480017fff8000", - "0xfffffffffffffffe0000000000000000", - "0x4800801b7fb27fff", - "0x4800801c7fb17ffd", - "0x4000801d7fb07fc6", - "0x404480017ffc7ffe", - "0x100000000000000000000000000000000", - "0x40307fc67ffe7fff", - "0x40307ffc7ff77fc7", - "0x4824800180008002", - "0xffffffffffffffff0000000000000000", - "0x4800801e7faf8001", - "0x4800801f7fae7ffe", - "0x400080207fad7ffe", - "0x484480017ffe8000", - "0x10000000000000000", - "0x40307ffc7fff7fb4", - "0x48507fb17ffc8000", - "0x48507fb07ffc8000", - "0x4824800180018002", - "0xffffffffffffffff0000000000000000", - "0x480080217fa98001", - "0x480080227fa87fff", - "0x400080237fa77ffd", - "0x484480017ffd8000", - "0x10000000000000000", - "0x40307ffd7fff7ffb", - "0x484480017ffd8000", - "0x10000000000000000", - "0x48307fff7ff98003", - "0x482480017fff8000", - "0xfffffffffffffffe0000000000000000", - "0x480080247fa37fff", - "0x480080257fa27ffd", - "0x400080267fa17fb3", - "0x404480017ffc7ffe", - "0x100000000000000000000000000000000", - "0x40307fb37ffe7fff", - "0x40307ffc7ff77fb4", - "0x4824800180008002", - "0xffffffffffffffff0000000000000000", - "0x480080277fa08001", - "0x480080287f9f7ffe", - "0x400080297f9e7ffe", - "0x484480017ffe8000", - "0x10000000000000000", - "0x40307ffc7fff7fa4", - "0x48507fa37ffc8000", - "0x48507fa27ffc8000", - "0x4824800180018002", - "0xffffffffffffffff0000000000000000", - "0x4800802a7f9a8001", - "0x4800802b7f997fff", - "0x4000802c7f987ffd", - "0x484480017ffd8000", - "0x10000000000000000", - "0x40307ffd7fff7ffb", - "0x484480017ffd8000", - "0x10000000000000000", - "0x48307fff7ff98003", - "0x482480017fff8000", - "0xfffffffffffffffe0000000000000000", - "0x4800802d7f947fff", - "0x4800802e7f937ffd", - "0x4000802f7f927fa6", - "0x404480017ffc7ffe", - "0x100000000000000000000000000000000", - "0x40307fa67ffe7fff", - "0x40307ffc7ff77fa7", - "0x4824800180008002", - "0xffffffffffffffff0000000000000000", - "0x480080307f918001", - "0x480080317f907ffe", - "0x400080327f8f7ffe", - "0x484480017ffe8000", - "0x10000000000000000", - "0x40307ffc7fff7f95", - "0x48507f937ffc8000", - "0x48507f927ffc8000", - "0x4824800180018002", - "0xffffffffffffffff0000000000000000", - "0x480080337f8b8001", - "0x480080347f8a7fff", - "0x400080357f897ffd", - "0x484480017ffd8000", - "0x10000000000000000", - "0x40307ffd7fff7ffb", - "0x484480017ffd8000", - "0x10000000000000000", - "0x48307fff7ff98003", - "0x482480017fff8000", - "0xfffffffffffffffe0000000000000000", - "0x480080367f857fff", - "0x480080377f847ffd", - "0x400080387f837f93", - "0x404480017ffc7ffe", - "0x100000000000000000000000000000000", - "0x40307f937ffe7fff", - "0x40307ffc7ff77f94", + "0xa", + "0x40780017fff7fff", + "0x8", + "0x482480017ff48000", + "0x208", "0x480680017fff8000", - "0x77037d812deb33a0f4a13945d898c296", + "0x0", "0x480680017fff8000", - "0x6b17d1f2e12c4247f8bce6e563a440f2", + "0x0", + "0x20680017fff7fff", + "0x13", + "0x40780017fff7fff", + "0xf", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x2bce33576b315ececbb6406837bf51f5", + "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x400080007ffe7fff", + "0x48127fbc7fff8000", + "0x482480017feb8000", + "0x57b2", + "0x480a7ffd7fff8000", "0x480680017fff8000", - "0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e16", - "0x482480017f7f8000", - "0x39", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x48127ffd7fff8000", "0x480680017fff8000", - "0x5365637032353672314e6577", - "0x400280007ff67fff", - "0x400380017ff67ff5", - "0x400280027ff67ffa", - "0x400280037ff67ffb", - "0x400280047ff67ffc", - "0x400280057ff67ffd", - "0x480280077ff68000", - "0x20680017fff7fff", - "0x92", - "0x480280087ff68000", - "0x480280097ff68000", - "0x480280067ff68000", - "0x482680017ff68000", - "0xa", - "0x20680017fff7ffc", - "0x7d", + "0x0", "0x480680017fff8000", - "0x5365637032353672314d756c", - "0x400080007ffe7fff", - "0x400080017ffe7ffd", - "0x400080027ffe7ffc", - "0x400080037ffe7e94", - "0x400080047ffe7e95", - "0x480080067ffe8000", - "0x20680017fff7fff", - "0x68", - "0x480080057ffd8000", - "0x480080077ffc8000", + "0x161bc82433cf4a92809836390ccd14921dfc4dc410cf3d2adbfee5e21ecfec8", "0x480680017fff8000", - "0x5365637032353672314d756c", - "0x400080087ffa7fff", - "0x400080097ffa7ffd", - "0x4001800a7ffa7ffd", - "0x4000800b7ffa7f7e", - "0x4000800c7ffa7f7f", - "0x4800800e7ffa8000", + "0x53746f726167655772697465", + "0x400280007ffd7fff", + "0x400280017ffd7ffc", + "0x400280027ffd7ffd", + "0x400280037ffd7ffe", + "0x400280047ffd7ffa", + "0x480280067ffd8000", "0x20680017fff7fff", - "0x51", - "0x4800800d7ff98000", - "0x4800800f7ff88000", + "0x2b", + "0x480280057ffd8000", "0x480680017fff8000", - "0x536563703235367231416464", - "0x400080107ff67fff", - "0x400080117ff67ffd", - "0x400080127ff67ffa", - "0x400080137ff67ffe", - "0x480080157ff68000", - "0x20680017fff7fff", - "0x3b", - "0x480080147ff58000", - "0x480080167ff48000", + "0x161bc82433cf4a92809836390ccd14921dfc4dc410cf3d2adbfee5e21ecfec8", + "0x48127ffe7fff8000", "0x480680017fff8000", - "0x5365637032353672314765745879", - "0x400080177ff27fff", - "0x400080187ff27ffd", - "0x400080197ff27ffe", - "0x4800801b7ff28000", - "0x20680017fff7fff", - "0x26", - "0x4800801c7ff18000", - "0x4800801d7ff08000", - "0x4800801a7fef8000", - "0x482480017fee8000", - "0x20", - "0x48287ff980007ffc", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x8", - "0x40780017fff7fff", + "0x0", + "0x482480017ffd8000", "0x1", "0x480680017fff8000", - "0x0", - "0x10780017fff7fff", - "0xd", - "0x48287ffa80007ffc", + "0x53746f726167655772697465", + "0x400280077ffd7fff", + "0x400280087ffd7ffc", + "0x400280097ffd7ffd", + "0x4002800a7ffd7ffe", + "0x4002800b7ffd7ff4", + "0x4802800d7ffd8000", "0x20680017fff7fff", + "0x11", + "0x40780017fff7fff", "0x4", - "0x10780017fff7fff", - "0x6", + "0x4802800c7ffd8000", + "0x48127fbc7fff8000", + "0x482480017ffe8000", + "0x168", + "0x482680017ffd8000", + "0xe", "0x480680017fff8000", "0x0", - "0x10780017fff7fff", - "0x4", - "0x480680017fff8000", - "0x1", - "0x48127fe47fff8000", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", - "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x7", - "0x48127fe47fff8000", - "0x4800801a7fe98000", - "0x482480017fe88000", - "0x1e", - "0x480680017fff8000", - "0x1", - "0x4800801c7fe68000", - "0x4800801d7fe58000", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", + "0x4802800c7ffd8000", + "0x48127fff7fff8000", + "0x482680017ffd8000", + "0x10", + "0x4802800e7ffd8000", + "0x4802800f7ffd8000", + "0x10780017fff7fff", "0xb", - "0x48127fe47fff8000", - "0x480080147fe98000", - "0x482480017fe88000", - "0x18", - "0x480680017fff8000", - "0x1", - "0x480080167fe68000", - "0x480080177fe58000", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0xf", - "0x48127fe47fff8000", - "0x4800800d7fe98000", - "0x482480017fe88000", - "0x11", - "0x480680017fff8000", - "0x1", - "0x4800800f7fe68000", - "0x480080107fe58000", - "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0x13", - "0x48127fe47fff8000", - "0x480080057fe98000", - "0x482480017fe88000", + "0x7", + "0x480280057ffd8000", + "0x482480017fff8000", + "0x2bde", + "0x482680017ffd8000", "0x9", + "0x480280077ffd8000", + "0x480280087ffd8000", + "0x48127fbc7fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", "0x480680017fff8000", "0x1", - "0x480080077fe68000", - "0x480080087fe58000", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0xf", + "0x57", + "0x1104800180018000", + "0x205c", + "0x482480017fff8000", + "0x205b", + "0x480080007fff8000", + "0x480080027fff8000", + "0x482480017fff8000", + "0x76de", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4f7074696f6e3a3a756e77726170206661696c65642e", "0x400080007ffe7fff", - "0x48127fed7fff8000", - "0x48127fed7fff8000", - "0x48127ffc7fff8000", - "0x482480017ffb8000", - "0x1", - "0x10780017fff7fff", - "0x9", - "0x40780017fff7fff", - "0x15", - "0x480280067ff68000", - "0x482680017ff68000", - "0xa", - "0x480280087ff68000", - "0x480280097ff68000", - "0x48127fe47fff8000", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", + "0x480a7ffb7fff8000", + "0x48307ffc7f998000", + "0x480a7ffd7fff8000", "0x480680017fff8000", "0x1", "0x48127ffa7fff8000", - "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0x274", - "0x4824800180008002", - "0xffffffffffffffff0000000000000000", - "0x480080077d778001", - "0x480080087d767ffe", - "0x400080097d757ffe", - "0x484480017ffe8000", - "0x10000000000000000", - "0x40307ffc7fff7d7a", - "0x48507d7e7ffc8000", - "0x48507d7d7ffc8000", - "0x4824800180018002", - "0xffffffffffffffff0000000000000000", - "0x4800800a7d718001", - "0x4800800b7d707fff", - "0x4000800c7d6f7ffd", - "0x484480017ffd8000", - "0x10000000000000000", - "0x40307ffd7fff7ffb", - "0x484480017ffd8000", - "0x10000000000000000", - "0x48307fff7ff98003", + "0x62", + "0x1104800180018000", + "0x2044", "0x482480017fff8000", - "0xfffffffffffffffe0000000000000000", - "0x4800800d7d6b7fff", - "0x4800800e7d6a7ffd", - "0x4000800f7d697d6d", - "0x404480017ffc7ffe", - "0x100000000000000000000000000000000", - "0x40307d6d7ffe7fff", - "0x40307ffc7ff77d77", - "0x4824800180008002", - "0xffffffffffffffff0000000000000000", - "0x480080107d688001", - "0x480080117d677ffe", - "0x400080127d667ffe", - "0x484480017ffe8000", - "0x10000000000000000", - "0x40307ffc7fff7d6b", - "0x48507d6d7ffc8000", - "0x48507d6c7ffc8000", - "0x4824800180018002", - "0xffffffffffffffff0000000000000000", - "0x480080137d628001", - "0x480080147d617fff", - "0x400080157d607ffd", - "0x484480017ffd8000", - "0x10000000000000000", - "0x40307ffd7fff7ffb", - "0x484480017ffd8000", - "0x10000000000000000", - "0x48307fff7ff98003", + "0x2043", + "0x480080007fff8000", + "0x480080027fff8000", "0x482480017fff8000", - "0xfffffffffffffffe0000000000000000", - "0x480080167d5c7fff", - "0x480080177d5b7ffd", - "0x400180187d5a7ffb", - "0x404480017ffc7ffe", - "0x100000000000000000000000000000000", - "0x40287ffb7ffe7fff", - "0x40307ffc7ff77d67", + "0x7b20", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4f7074696f6e3a3a756e77726170206661696c65642e", "0x400080007ffe7fff", - "0x482480017d588000", - "0x19", - "0x480a7ff57fff8000", - "0x480a7ff67fff8000", + "0x480a7ffb7fff8000", + "0x48327ffc7ffc8000", + "0x480a7ffd7fff8000", "0x480680017fff8000", "0x1", "0x48127ffa7fff8000", "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x2a4", - "0x48127d587fff8000", - "0x480a7ff57fff8000", - "0x480a7ff67fff8000", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", "0x480680017fff8000", - "0x0", - "0x208b7fff7fff7ffe", - "0x48297ffa80007ff6", - "0x20680017fff7fff", - "0x19", - "0x48297ffb80007ff7", - "0x20680017fff7fff", - "0x12", - "0x48297ffc80007ff8", - "0x20680017fff7fff", - "0xb", - "0x48297ffd80007ff9", + "0x476574457865637574696f6e496e666f", + "0x400280007ffc7fff", + "0x400380017ffc7ffa", + "0x480280037ffc8000", "0x20680017fff7fff", - "0x5", + "0x140", + "0x480280027ffc8000", + "0x480280047ffc8000", + "0x480080017fff8000", "0x480680017fff8000", + "0x2691cb735b18f3f656c3b82bd97a32b65d15019b64117513f8604d1e06fe58b", + "0x400280007ffb7fff", + "0x400380017ffb7ffd", + "0x480280027ffb8000", + "0xa0680017fff8005", + "0xe", + "0x4824800180057ffe", + "0x7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00", + "0x484480017ffe8000", + "0x110000000000000000", + "0x48307ffe7fff8003", + "0x480280007ff97ffc", + "0x480280017ff97ffc", + "0x482480017ffb7ffd", + "0xffffffffffffffeefffffffffffffeff", + "0x400280027ff97ffc", + "0x10780017fff7fff", + "0x11", + "0x48127ffe7fff8005", + "0x484480017ffe8000", + "0x8000000000000000000000000000000", + "0x48307ffe7fff8003", + "0x480280007ff97ffd", + "0x482480017ffc7ffe", + "0xf0000000000000000000000000000100", + "0x480280017ff97ffd", + "0x400280027ff97ff9", + "0x402480017ffd7ff9", + "0xffffffffffffffffffffffffffffffff", + "0x20680017fff7ffd", + "0x4", + "0x402780017fff7fff", "0x1", - "0x208b7fff7fff7ffe", + "0x48127ff47fff8000", "0x480680017fff8000", "0x0", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", - "0x10780017fff7fff", - "0x8", - "0x40780017fff7fff", - "0x2", - "0x10780017fff7fff", - "0x4", - "0x40780017fff7fff", + "0x480080007ff48000", + "0x480080017ff38000", + "0x480080027ff28000", + "0x480080037ff18000", + "0x480080047ff08000", + "0x480080057fef8000", + "0x480080067fee8000", + "0x480080077fed8000", + "0x480080087fec8000", + "0x480080097feb8000", + "0x4800800a7fea8000", + "0x4800800b7fe98000", + "0x4800800c7fe88000", + "0x4800800d7fe78000", + "0x4800800e7fe68000", + "0x4800800f7fe58000", + "0x480080107fe48000", + "0x482680017ffb8000", + "0x3", + "0x482680017ff98000", "0x3", "0x480680017fff8000", - "0x0", - "0x208b7fff7fff7ffe", - "0x20780017fff7ffd", - "0xc", - "0x40780017fff7fff", - "0x68", - "0x480a7ff77fff8000", + "0x53746f7261676552656164", + "0x400280057ffc7fff", + "0x400280067ffc7fea", + "0x400280077ffc7feb", + "0x400280087ffc7fe9", + "0x4802800a7ffc8000", + "0x20680017fff7fff", + "0xe1", + "0x480280097ffc8000", + "0x48127fff7fff8000", "0x480680017fff8000", "0x0", - "0x480a7ff87fff8000", - "0x480a7ff97fff8000", - "0x480a7ffa7fff8000", - "0x480a7ffb7fff8000", - "0x208b7fff7fff7ffe", - "0xa0680017fff8000", - "0x8", - "0x482a7ffd7ffb8000", - "0x4824800180007fff", - "0x100000000", - "0x400280007ff77fff", - "0x10780017fff7fff", - "0x443", - "0x482a7ffd7ffb8001", - "0x4824800180007fff", - "0xffffffffffffffffffffffff00000000", - "0x400280007ff77ffe", + "0x482480017fe58000", + "0x1", + "0x4802800b7ffc8000", "0x480680017fff8000", - "0x1f", - "0x48307fff80017ffe", - "0xa0680017fff7fff", - "0x7", - "0x482480017fff8000", - "0x100000000000000000000000000000000", - "0x400280017ff77fff", - "0x10780017fff7fff", - "0x3ab", - "0x400280017ff77fff", - "0x482680017ff78000", - "0x2", - "0x4824800180007ffb", - "0x1f", + "0x53746f7261676552656164", + "0x4002800c7ffc7fff", + "0x4002800d7ffc7ffb", + "0x4002800e7ffc7ffc", + "0x4002800f7ffc7ffd", + "0x480280117ffc8000", + "0x20680017fff7fff", + "0xbf", + "0x480280107ffc8000", + "0x482680017ffc8000", + "0x13", + "0x480280127ffc8000", + "0x48127ffd7fff8000", + "0x48307fe380007fe4", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x317", + "0x9c", "0x480680017fff8000", - "0x1f", - "0x48307fff80017ff9", - "0xa0680017fff7fff", - "0x7", - "0x482480017fff8000", - "0x100000000000000000000000000000000", - "0x400080007ffa7fff", + "0x1", + "0x48127ffd7fff8000", + "0x480080007fe08000", + "0x48307fdf80007fe0", + "0xa0680017fff8000", + "0x6", + "0x48307ffe80007ffb", + "0x400080007feb7fff", "0x10780017fff7fff", - "0x2fa", - "0x400080007ffb7fff", + "0x77", "0x482480017ffb8000", "0x1", - "0x4824800180007ffe", - "0x10", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0x22b", + "0x48307fff80007ffd", + "0x400080007fea7fff", + "0x48307ff97fdb8000", "0x480680017fff8000", - "0x10", - "0x48307fff80017ffc", - "0xa0680017fff7fff", - "0x7", - "0x482480017fff8000", - "0x100000000000000000000000000000000", - "0x400080007ffa7fff", + "0x2691cb735b18f3f656c3b82bd97a32b65d15019b64117513f8604d1e06fe58b", + "0x400080007fe77fff", + "0x400180017fe77ffd", + "0x480080027fe78000", + "0xa0680017fff8005", + "0xe", + "0x4824800180057ffe", + "0x7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00", + "0x484480017ffe8000", + "0x110000000000000000", + "0x48307ffe7fff8003", + "0x480080017fe37ffc", + "0x480080027fe27ffc", + "0x482480017ffb7ffd", + "0xffffffffffffffeefffffffffffffeff", + "0x400080037fe07ffc", "0x10780017fff7fff", - "0x10d", - "0x400080007ffb7fff", - "0x40780017fff7fff", - "0xf", - "0xa0680017fff8000", - "0x16", - "0x480080017feb8003", - "0x480080027fea8003", - "0x4844800180017ffe", - "0x100000000000000000000000000000000", - "0x483180017ffd7ffc", - "0x482480017fff7ffd", - "0x800000000000010fffffffffffffffff7ffffffffffffef0000000000000001", - "0x20680017fff7ffc", - "0x6", - "0x402480017fff7ffd", + "0x11", + "0x48127ffe7fff8005", + "0x484480017ffe8000", + "0x8000000000000000000000000000000", + "0x48307ffe7fff8003", + "0x480080017fe37ffd", + "0x482480017ffc7ffe", + "0xf0000000000000000000000000000100", + "0x480080027fe17ffd", + "0x400080037fe07ff9", + "0x402480017ffd7ff9", "0xffffffffffffffffffffffffffffffff", - "0x10780017fff7fff", + "0x20680017fff7ffd", "0x4", - "0x402480017ffe7ffd", - "0xf7ffffffffffffef0000000000000000", - "0x400080037fe67ffd", - "0x20680017fff7ffe", - "0xe", "0x402780017fff7fff", "0x1", - "0x400180017feb7ffc", - "0x40780017fff7fff", - "0x5", - "0x482480017fe68000", - "0x2", - "0x480a7ffc7fff8000", + "0x48127ff07fff8000", "0x480680017fff8000", "0x0", - "0x10780017fff7fff", - "0x6", - "0x482480017fe68000", + "0x48307fef7fe58000", + "0x480080007ff38000", + "0x482480017fdb8000", + "0x3", + "0x482480017fdb8000", "0x4", - "0x48127ffe7fff8000", - "0x48127ffc7fff8000", "0x480680017fff8000", - "0x10", - "0x48307fff80017fe1", - "0xa0680017fff7fff", - "0x7", - "0x482480017fff8000", - "0x100000000000000000000000000000000", - "0x400080007ff97fff", - "0x10780017fff7fff", - "0xc6", - "0x400080007ffa7fff", - "0x482480017ffa8000", - "0x1", - "0x48127ffe7fff8000", - "0x1104800180018000", - "0xcf6", - "0x20680017fff7ffd", - "0xb7", + "0x53746f726167655772697465", + "0x400080007fe47fff", + "0x400080017fe47ff9", + "0x400080027fe47ffa", + "0x400080037fe47ff8", + "0x400080047fe47ffb", + "0x480080067fe48000", "0x20680017fff7fff", - "0xf", - "0x40780017fff7fff", - "0x2a", - "0x40780017fff7fff", - "0x1", + "0x2b", + "0x480080057fe38000", + "0x48127fff7fff8000", "0x480680017fff8000", - "0x4f7074696f6e3a3a756e77726170206661696c65642e", - "0x400080007ffe7fff", - "0x48127fd07fff8000", - "0x48127ffd7fff8000", - "0x482480017ffc8000", - "0x1", - "0x10780017fff7fff", - "0xbb", - "0x480080007ffc8005", - "0x480080017ffb8005", - "0x4824800180047ffe", + "0x0", + "0x482480017ff48000", "0x1", - "0x48307ffd7ffe7ffc", - "0x480080027ff87ffd", - "0xa0680017fff7ffd", - "0x6", - "0x482480017ff97ffd", - "0xffffffffffffffff0000000000000000", - "0x10780017fff7fff", + "0x48307ff77fe08000", + "0x480680017fff8000", + "0x53746f726167655772697465", + "0x400080077fdd7fff", + "0x400080087fdd7ffb", + "0x400080097fdd7ffc", + "0x4000800a7fdd7ffd", + "0x4000800b7fdd7ffe", + "0x4800800d7fdd8000", + "0x20680017fff7fff", + "0x12", + "0x40780017fff7fff", "0x4", - "0x482480017fff7ffd", - "0xffffffffffffffff0000000000000000", - "0x400080037ff57ffc", - "0x40507ffe7ff87ffd", - "0x40307fff7ffd7fe7", + "0x4800800c7fd88000", + "0x48127ff17fff8000", + "0x482480017ffe8000", + "0x168", + "0x48127fee7fff8000", + "0x482480017fd48000", + "0xe", "0x480680017fff8000", - "0x1f", - "0x48287ffb80017fff", - "0xa0680017fff7fff", - "0x7", - "0x482480017fff8000", - "0x100000000000000000000000000000000", - "0x400080047ff17fff", - "0x10780017fff7fff", - "0x7f", - "0x400080047ff27fff", - "0x484480017ffc8000", - "0x100000000000000000000000000000000", + "0x0", "0x480680017fff8000", - "0x10", - "0x48307fe17ffe8000", - "0x48307ffe80017ffc", - "0xa0680017fff7fff", - "0x7", - "0x482480017fff8000", - "0x100000000000000000000000000000000", - "0x400080057fec7fff", - "0x10780017fff7fff", - "0x2f", - "0x400080057fed7fff", + "0x0", "0x480680017fff8000", + "0x0", + "0x208b7fff7fff7ffe", + "0x4800800c7fdc8000", + "0x48127fff7fff8000", + "0x482480017fda8000", "0x10", - "0x48307fff80017ff9", - "0xa0680017fff7fff", - "0x7", - "0x482480017fff8000", - "0x100000000000000000000000000000000", - "0x400080067fe97fff", - "0x10780017fff7fff", - "0x16", - "0x400080067fea7fff", - "0x482480017fea8000", - "0x7", - "0x48127ffe7fff8000", - "0x1104800180018000", - "0xcab", - "0x20680017fff7ffd", - "0x7", - "0x48127ffc7fff8000", - "0x484480017ffe8000", - "0x100000000000000000000000000000000", + "0x4800800e7fd98000", + "0x4800800f7fd88000", "0x10780017fff7fff", - "0x22", + "0xb", "0x40780017fff7fff", - "0xc", - "0x48127ff07fff8000", - "0x48127ff17fff8000", + "0x7", + "0x480080057fdc8000", + "0x482480017fff8000", + "0x2bde", + "0x482480017fda8000", + "0x9", + "0x480080077fd98000", + "0x480080087fd88000", "0x48127ff17fff8000", - "0x10780017fff7fff", - "0x50", + "0x48127ffb7fff8000", + "0x48127fee7fff8000", + "0x48127ffa7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x17", + "0x1104800180018000", + "0x1f45", + "0x482480017fff8000", + "0x1f44", + "0x480080007fff8000", + "0x480080007fff8000", + "0x482480017fff8000", + "0x5ce4", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x7533325f737562204f766572666c6f77", + "0x496e646578206f7574206f6620626f756e6473", "0x400080007ffe7fff", - "0x482480017fd08000", - "0x7", - "0x48127ffd7fff8000", - "0x482480017ffc8000", + "0x482480017fcc8000", "0x1", - "0x10780017fff7fff", - "0x42", + "0x48307ffc7fdb8000", + "0x48127fc97fff8000", + "0x48127fd47fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0x2", - "0x482480017fea8000", - "0x6", - "0x48127ff67fff8000", + "0x1d", "0x1104800180018000", - "0xc88", - "0x20680017fff7ffd", - "0x34", - "0x48127ffc7fff8000", - "0x48127ffe7fff8000", - "0x48527fff7ffa8000", - "0x48307fff7fe28000", - "0xa0680017fff8004", - "0xe", - "0x4824800180047ffe", - "0x100000000000000000000000000000000000000000000000000000000000000", - "0x484480017ffe8000", - "0x7000000000000110000000000000000", - "0x48307ffe7fff8002", - "0x480080007ff87ffc", - "0x480080017ff77ffc", - "0x402480017ffb7ffd", - "0xf8ffffffffffffeeffffffffffffffff", - "0x400080027ff67ffd", - "0x10780017fff7fff", - "0x16", - "0x484480017fff8001", - "0x1000000000000000000000000000000", - "0x48307fff80007ffd", - "0x480080007ff97ffd", - "0x480080017ff87ffd", - "0x402480017ffc7ffe", - "0xff000000000000000000000000000000", - "0x400080027ff77ffe", - "0x40780017fff7fff", - "0x1", - "0x400280007ff97ff9", - "0x482480017ff68000", - "0x3", - "0x480a7ff87fff8000", - "0x482680017ff98000", - "0x1", - "0x48127fdf7fff8000", - "0x480a7ffb7fff8000", - "0x10780017fff7fff", - "0x10d", + "0x1f2b", + "0x482480017fff8000", + "0x1f2a", + "0x480080007fff8000", + "0x480080007fff8000", + "0x482480017fff8000", + "0x5faa", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x496e646578206f7574206f6620626f756e6473", "0x400080007ffe7fff", - "0x482480017ff48000", - "0x3", - "0x48127ffd7fff8000", - "0x482480017ffc8000", + "0x48127fcc7fff8000", + "0x48307ffc7fd88000", + "0x48127fc97fff8000", + "0x48127fd47fff8000", + "0x480680017fff8000", "0x1", - "0x10780017fff7fff", - "0x2a", - "0x40780017fff7fff", - "0xc", - "0x48127ff07fff8000", - "0x48127ff17fff8000", - "0x48127ff17fff8000", - "0x10780017fff7fff", - "0x23", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1f", + "0x480280107ffc8000", + "0x1104800180018000", + "0x1f11", + "0x482480017fff8000", + "0x1f10", + "0x480080007fff8000", + "0x480080007fff8000", + "0x482480017fff8000", + "0x6126", + "0x48307fff7ff98000", + "0x482680017ffc8000", + "0x14", + "0x480280127ffc8000", + "0x480280137ffc8000", + "0x10780017fff7fff", + "0x12", "0x40780017fff7fff", - "0x1", + "0x26", + "0x480280097ffc8000", + "0x1104800180018000", + "0x1eff", + "0x482480017fff8000", + "0x1efe", + "0x480080007fff8000", + "0x480080007fff8000", + "0x482480017fff8000", + "0x8d04", + "0x48307fff7ff98000", + "0x482680017ffc8000", + "0xd", + "0x4802800b7ffc8000", + "0x4802800c7ffc8000", + "0x48127fcc7fff8000", + "0x48127ffb7fff8000", + "0x48127fc97fff8000", + "0x48127ffa7fff8000", "0x480680017fff8000", - "0x7533325f737562204f766572666c6f77", - "0x400080007ffe7fff", - "0x482480017fd08000", - "0x5", - "0x48127ffd7fff8000", - "0x482480017ffc8000", "0x1", - "0x10780017fff7fff", - "0x15", - "0x40780017fff7fff", - "0x2c", - "0x48127fd07fff8000", - "0x48127fd17fff8000", - "0x48127fd17fff8000", - "0x10780017fff7fff", - "0xe", - "0x40780017fff7fff", - "0x37", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0x1", + "0x4c", + "0x480280027ffc8000", + "0x1104800180018000", + "0x1ee6", + "0x482480017fff8000", + "0x1ee5", + "0x480080007fff8000", + "0x480080007fff8000", + "0x484480017fff8000", + "0x2", + "0x482480017fff8000", + "0xc62a", + "0x480a7ff97fff8000", + "0x48307ffe7ff78000", + "0x480a7ffb7fff8000", + "0x482680017ffc8000", + "0x6", "0x480680017fff8000", - "0x7533325f737562204f766572666c6f77", - "0x400080007ffe7fff", - "0x482480017fc08000", - "0x1", - "0x48127ffd7fff8000", - "0x482480017ffc8000", "0x1", - "0x48127ffd7fff8000", + "0x480280047ffc8000", + "0x480280057ffc8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x7", "0x480680017fff8000", - "0x1", + "0x7", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", - "0x208b7fff7fff7ffe", - "0xa0680017fff8000", - "0x16", - "0x480080017ff98003", - "0x480080027ff88003", - "0x4844800180017ffe", - "0x100000000000000000000000000000000", - "0x483180017ffd7ffc", - "0x482480017fff7ffd", - "0x800000000000010fffffffffffffffff7ffffffffffffef0000000000000001", + "0x480680017fff8000", + "0x0", + "0xa0680017fff7fff", + "0x10", + "0x20680017fff7ffd", + "0xe", "0x20680017fff7ffc", - "0x6", - "0x402480017fff7ffd", - "0xffffffffffffffffffffffffffffffff", - "0x10780017fff7fff", + "0xc", + "0x20680017fff7ffb", "0x4", - "0x402480017ffe7ffd", - "0xf7ffffffffffffef0000000000000000", - "0x400080037ff47ffd", - "0x20680017fff7ffe", - "0xe", - "0x402780017fff7fff", + "0x10780017fff7fff", + "0x1d9", + "0x402480017fff7ffb", "0x1", - "0x400180017ff97ffc", - "0x40780017fff7fff", - "0x5", - "0x482480017ff48000", - "0x2", - "0x480a7ffc7fff8000", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x1d3", + "0x482680017ffc8000", + "0x4", + "0x482680017ffc8000", + "0xc", + "0x480680017fff8000", + "0x3", "0x480680017fff8000", "0x0", - "0x10780017fff7fff", - "0x6", - "0x482480017ff48000", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480a7ffd7fff8000", + "0x482680017ffc8000", + "0x24", + "0x400080007ff87ffa", + "0x400080017ff87ffb", + "0x400080027ff87ffc", + "0x400080037ff87ffd", + "0x482480017ff88000", "0x4", - "0x48127ffe7fff8000", - "0x48127ffc7fff8000", - "0x48127ffd7fff8000", - "0x48127fef7fff8000", - "0x1104800180018000", - "0xbfa", - "0x20680017fff7ffd", - "0xdd", + "0x48307fff80007ff8", "0x20680017fff7fff", - "0xf", - "0x40780017fff7fff", - "0x3b", + "0x20", + "0x1104800180018000", + "0x1ea0", + "0x482480017fff8000", + "0x1e9f", + "0x480080007fff8000", + "0x480080047fff8000", + "0x484480017fff8000", + "0x2", + "0x482480017fff8000", + "0x1401a", + "0x480080057ffc8000", + "0x484480017fff8000", + "0x4", + "0x48307ffd7fff8000", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x416c6c20696e707574732068617665206265656e2066696c6c6564", "0x400080007ffe7fff", - "0x48127fbf7fff8000", - "0x48127ffd7fff8000", - "0x482480017ffc8000", + "0x480a7ff97fff8000", + "0x480a7ffa7fff8000", + "0x480a7ffb7fff8000", + "0x48127fee7fff8000", + "0x48307ff97fec8000", + "0x480680017fff8000", "0x1", - "0x10780017fff7fff", - "0xd3", - "0x480080007ffc8005", - "0x480080017ffb8005", - "0x4824800180047ffe", + "0x48127ff87fff8000", + "0x482480017ff78000", "0x1", - "0x48307ffd7ffe7ffc", - "0x480080027ff87ffd", - "0xa0680017fff7ffd", + "0x208b7fff7fff7ffe", + "0x480680017fff8000", "0x6", - "0x482480017ff97ffd", - "0xffffffffffffffff0000000000000000", - "0x10780017fff7fff", - "0x4", - "0x482480017fff7ffd", - "0xffffffffffffffff0000000000000000", - "0x400080037ff57ffc", - "0x40507ffe7ff87ffd", - "0x40307fff7ffd7fe9", "0x480680017fff8000", - "0x10", - "0x48307fda80017fff", - "0xa0680017fff7fff", - "0x7", - "0x482480017fff8000", - "0x100000000000000000000000000000000", - "0x400080047ff17fff", - "0x10780017fff7fff", - "0xa5", - "0x400080047ff27fff", - "0x482480017ff28000", - "0x5", - "0x48127ffe7fff8000", - "0x1104800180018000", - "0xbc8", - "0x20680017fff7ffd", - "0x96", + "0x0", "0x480680017fff8000", - "0x1f", - "0x48287ffb80017fff", - "0xa0680017fff7fff", - "0x7", - "0x482480017fff8000", - "0x100000000000000000000000000000000", - "0x400080007ff87fff", - "0x10780017fff7fff", - "0x7e", - "0x400080007ff97fff", - "0x48507ffc7fd68000", + "0x0", "0x480680017fff8000", - "0x10", - "0x48307fe87ffe8000", - "0x48307ffe80017ffc", - "0xa0680017fff7fff", - "0x7", + "0x0", + "0x48127ff87fff8000", + "0x400080007ff97ffb", + "0x400080017ff97ffc", + "0x400080027ff97ffd", + "0x400080037ff97ffe", + "0x482480017ff98000", + "0x4", + "0x48307fff80007ff1", + "0x20680017fff7fff", + "0x16d", + "0x1104800180018000", + "0x1e5d", "0x482480017fff8000", - "0x100000000000000000000000000000000", - "0x400080017ff37fff", - "0x10780017fff7fff", - "0x2f", - "0x400080017ff47fff", + "0x1e5c", "0x480680017fff8000", - "0x10", - "0x48307fff80017ff9", - "0xa0680017fff7fff", - "0x7", - "0x482480017fff8000", - "0x100000000000000000000000000000000", - "0x400080027ff07fff", - "0x10780017fff7fff", - "0x16", - "0x400080027ff17fff", - "0x482480017ff18000", - "0x3", - "0x48127ffe7fff8000", - "0x1104800180018000", - "0xb9e", - "0x20680017fff7ffd", - "0x7", - "0x48127ffc7fff8000", - "0x484480017ffe8000", - "0x100000000000000000000000000000000", - "0x10780017fff7fff", - "0x22", - "0x40780017fff7fff", - "0xc", - "0x48127ff07fff8000", - "0x48127ff17fff8000", - "0x48127ff17fff8000", - "0x10780017fff7fff", - "0x50", - "0x40780017fff7fff", - "0x17", - "0x40780017fff7fff", - "0x1", + "0x2", + "0x482480017ffe8000", + "0x6", + "0x480680017fff8000", + "0x4", + "0x480680017fff8000", + "0x0", "0x480680017fff8000", - "0x7533325f737562204f766572666c6f77", - "0x400080007ffe7fff", - "0x482480017fd78000", - "0x3", - "0x48127ffd7fff8000", - "0x482480017ffc8000", "0x1", - "0x10780017fff7fff", - "0x42", - "0x40780017fff7fff", - "0x2", - "0x482480017ff18000", - "0x2", + "0x48127ff57fff8000", + "0x4824800180007fe7", + "0xc", + "0x400080007fff7ffd", + "0x400080017fff7ffc", + "0x400080027fff7ffc", + "0x400080037fff7ffc", + "0x400280007ffa7fe0", + "0x400280017ffa7fe1", + "0x400280027ffa7fe2", + "0x400280037ffa7fe3", + "0x400280047ffa7fff", + "0x400280057ffa7ff8", + "0x400280067ffa7ff9", + "0x400280007ffb7fe0", + "0x400280017ffb7fe1", + "0x400280027ffb7fe2", + "0x400280037ffb7fe3", + "0x400280047ffb7fff", + "0x400280057ffb7ffa", + "0x480280067ffb8000", + "0x484480017fff8000", + "0x7", + "0x48307ffe80007ff9", + "0x20680017fff7fff", + "0xdf", + "0x482480017ffc8000", + "0x20", + "0x480080007fff8000", + "0x480080017ffe8000", + "0x480080027ffd8000", + "0x480080037ffc8000", + "0x402780017ffa8000", + "0xe", + "0x40337ff97ffb8006", "0x48127ff67fff8000", - "0x1104800180018000", - "0xb7b", - "0x20680017fff7ffd", - "0x34", - "0x48127ffc7fff8000", + "0x48307ffe80007fda", + "0x20680017fff7fff", + "0x19", "0x48127ffe7fff8000", - "0x48527fff7ffa8000", - "0x48307fff7fe98000", - "0xa0680017fff8004", + "0x48307ffb80007fd7", + "0x20680017fff7fff", "0xe", - "0x4824800180047ffe", - "0x100000000000000000000000000000000000000000000000000000000000000", - "0x484480017ffe8000", - "0x7000000000000110000000000000000", - "0x48307ffe7fff8002", - "0x480080007ff87ffc", - "0x480080017ff77ffc", - "0x402480017ffb7ffd", - "0xf8ffffffffffffeeffffffffffffffff", - "0x400080027ff67ffd", + "0x48127ffe7fff8000", + "0x48307ff880007fd4", + "0x20680017fff7fff", + "0x6", + "0x48127ffe7fff8000", + "0x48307ff580007fd1", "0x10780017fff7fff", - "0x16", - "0x484480017fff8001", - "0x1000000000000000000000000000000", - "0x48307fff80007ffd", - "0x480080007ff97ffd", - "0x480080017ff87ffd", - "0x402480017ffc7ffe", - "0xff000000000000000000000000000000", - "0x400080027ff77ffe", - "0x40780017fff7fff", - "0x1", - "0x400280007ff97ff9", - "0x482480017ff68000", - "0x3", - "0x480a7ff87fff8000", - "0x482680017ff98000", - "0x1", - "0x48127fc87fff8000", - "0x480a7ffb7fff8000", + "0x12", + "0x48127ffe7fff8000", + "0x48127ffe7fff8000", "0x10780017fff7fff", - "0xdc", + "0xe", "0x40780017fff7fff", - "0x1", - "0x480680017fff8000", - "0x4f7074696f6e3a3a756e77726170206661696c65642e", - "0x400080007ffe7fff", - "0x482480017ff48000", - "0x3", - "0x48127ffd7fff8000", + "0x2", "0x482480017ffc8000", - "0x1", - "0x10780017fff7fff", - "0x31", - "0x40780017fff7fff", - "0xc", - "0x48127ff07fff8000", - "0x48127ff17fff8000", - "0x48127ff17fff8000", + "0xb4", + "0x48127ffc7fff8000", "0x10780017fff7fff", - "0x2a", - "0x40780017fff7fff", - "0x1f", + "0x7", "0x40780017fff7fff", - "0x1", + "0x4", + "0x482480017ffa8000", + "0x230", + "0x48127ffa7fff8000", + "0x400080007fdc7fff", + "0x48127ff47fff8000", + "0x48127ff47fff8000", + "0x48127ff47fff8000", + "0x48127ff47fff8000", "0x480680017fff8000", - "0x7533325f737562204f766572666c6f77", - "0x400080007ffe7fff", - "0x482480017fd78000", - "0x1", - "0x48127ffd7fff8000", - "0x482480017ffc8000", - "0x1", - "0x10780017fff7fff", - "0x1c", - "0x40780017fff7fff", - "0x25", - "0x48127fd77fff8000", - "0x48127fd87fff8000", - "0x48127fd87fff8000", - "0x10780017fff7fff", - "0x15", - "0x40780017fff7fff", - "0x30", - "0x40780017fff7fff", - "0x1", + "0x6", "0x480680017fff8000", - "0x7533325f737562204f766572666c6f77", - "0x400080007ffe7fff", - "0x482480017fbf8000", - "0x5", - "0x48127ffd7fff8000", - "0x482480017ffc8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x1104800180018000", + "0xe4d", + "0x402580017fcd8005", "0x1", - "0x10780017fff7fff", - "0x7", + "0x20680017fff7fff", + "0x96", "0x40780017fff7fff", - "0x3d", - "0x48127fbf7fff8000", - "0x48127fc07fff8000", - "0x48127fc07fff8000", - "0x48127ffd7fff8000", - "0x480680017fff8000", "0x1", + "0x480a7ff97fff8000", + "0x48127ffe7fff8000", + "0x48127ffd7fff8000", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", + "0x480680017fff8000", + "0x617373657274696f6e206661696c65643a20606f7574707574732e6765745f", + "0x480680017fff8000", + "0x1f", + "0x1104800180018000", + "0xe59", + "0x48127f777fff8000", + "0x20680017fff7ffa", + "0x79", + "0x48127ff97fff8000", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", "0x48127ffa7fff8000", "0x48127ffa7fff8000", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x2c", - "0xa0680017fff8000", - "0x16", - "0x480080007fd18003", - "0x480080017fd08003", - "0x4844800180017ffe", - "0x100000000000000000000000000000000", - "0x483180017ffd7ffc", - "0x482480017fff7ffd", - "0x800000000000010fffffffffffffffff7ffffffffffffef0000000000000001", - "0x20680017fff7ffc", - "0x6", - "0x402480017fff7ffd", - "0xffffffffffffffffffffffffffffffff", - "0x10780017fff7fff", - "0x4", - "0x402480017ffe7ffd", - "0xf7ffffffffffffef0000000000000000", - "0x400080027fcc7ffd", - "0x20680017fff7ffe", - "0xe", - "0x402780017fff7fff", - "0x1", - "0x400180007fd17ffc", - "0x40780017fff7fff", - "0x5", - "0x482480017fcc8000", - "0x1", - "0x480a7ffc7fff8000", "0x480680017fff8000", - "0x0", - "0x10780017fff7fff", - "0x6", - "0x482480017fcc8000", - "0x3", - "0x48127ffe7fff8000", - "0x48127ffc7fff8000", + "0x6f7574707574286d756c29203d3d2075333834207b206c696d62303a20362c", "0x480680017fff8000", "0x1f", - "0x48287ffb80017fff", - "0xa0680017fff7fff", - "0x7", - "0x482480017fff8000", - "0x100000000000000000000000000000000", - "0x400080007ff97fff", - "0x10780017fff7fff", - "0x82", - "0x400080007ffa7fff", + "0x1104800180018000", + "0xe4b", + "0x48127f887fff8000", + "0x20680017fff7ffa", + "0x60", + "0x48127ff97fff8000", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", "0x480680017fff8000", - "0x10", - "0x48307fff80017ffe", - "0xa0680017fff7fff", - "0x7", - "0x482480017fff8000", - "0x100000000000000000000000000000000", - "0x400080017ff67fff", - "0x10780017fff7fff", - "0x2f", - "0x400080017ff77fff", + "0x206c696d62313a20302c206c696d62323a20302c206c696d62333a2030207d", "0x480680017fff8000", - "0x10", - "0x48307fff80017ffb", - "0xa0680017fff7fff", - "0x7", - "0x482480017fff8000", - "0x100000000000000000000000000000000", - "0x400080027ff37fff", - "0x10780017fff7fff", - "0x16", - "0x400080027ff47fff", - "0x482480017ff48000", - "0x3", - "0x48127ffe7fff8000", + "0x1f", "0x1104800180018000", - "0xac2", - "0x20680017fff7ffd", - "0x7", - "0x48127ffc7fff8000", - "0x484480017ffe8000", - "0x100000000000000000000000000000000", - "0x10780017fff7fff", - "0x22", - "0x40780017fff7fff", - "0xc", - "0x48127ff07fff8000", - "0x48127ff17fff8000", - "0x48127ff17fff8000", - "0x10780017fff7fff", - "0x56", - "0x40780017fff7fff", - "0x17", + "0xe3d", + "0x48127f887fff8000", + "0x20680017fff7ffa", + "0x47", + "0x48127ff97fff8000", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x480680017fff8000", + "0x602e", + "0x480680017fff8000", + "0x2", + "0x1104800180018000", + "0xe2f", + "0x48127f887fff8000", + "0x20680017fff7ffa", + "0x2e", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x7533325f737562204f766572666c6f77", + "0x46a6158a16a947e5916b2a2ca68501a45e93d7110e81aa2d6438b1c57c879a3", "0x400080007ffe7fff", - "0x482480017fda8000", - "0x3", - "0x48127ffd7fff8000", - "0x482480017ffc8000", - "0x1", - "0x10780017fff7fff", - "0x48", - "0x40780017fff7fff", - "0x2", - "0x482480017ff48000", + "0x40137ff97fff8001", + "0x40137ffa7fff8002", + "0x40137ffb7fff8003", + "0x40137ffc7fff8004", + "0x4829800180008002", + "0x400080017ffd7fff", + "0x48127ff67fff8000", + "0x48127ffb7fff8000", + "0x480a80017fff8000", + "0x480a80027fff8000", + "0x48127ff97fff8000", + "0x482480017ff88000", "0x2", - "0x48127ff87fff8000", "0x1104800180018000", - "0xa9f", + "0x1262", "0x20680017fff7ffd", - "0x3a", + "0xa", + "0x400180007fff8003", + "0x400180017fff8004", "0x48127ffc7fff8000", - "0x48127ffe7fff8000", - "0x48527fff7ffa8000", - "0x48307fff7fe58000", - "0xa0680017fff8004", - "0xe", - "0x4824800180047ffe", - "0x100000000000000000000000000000000000000000000000000000000000000", - "0x484480017ffe8000", - "0x7000000000000110000000000000000", - "0x48307ffe7fff8002", - "0x480080007ff87ffc", - "0x480080017ff77ffc", - "0x402480017ffb7ffd", - "0xf8ffffffffffffeeffffffffffffffff", - "0x400080027ff67ffd", + "0x48127ffd7fff8000", + "0x482480017ffd8000", + "0x2", "0x10780017fff7fff", - "0x1c", - "0x484480017fff8001", - "0x1000000000000000000000000000000", - "0x48307fff80007ffd", - "0x480080007ff97ffd", - "0x480080017ff87ffd", - "0x402480017ffc7ffe", - "0xff000000000000000000000000000000", - "0x400080027ff77ffe", - "0x40780017fff7fff", - "0x1", - "0x400280007ff97ff9", - "0x482480017ff68000", - "0x3", - "0x480a7ff87fff8000", - "0x482680017ff98000", - "0x1", - "0x48127fda7fff8000", - "0x480a7ffb7fff8000", - "0x48127ffb7fff8000", + "0x6", + "0x482480017ffc8000", + "0x12c", + "0x48127ffd7fff8000", + "0x48127ffd7fff8000", + "0x48127ff87fff8000", + "0x480a80007fff8000", + "0x480a80067fff8000", + "0x480a80057fff8000", + "0x48127ff97fff8000", "0x480680017fff8000", - "0x0", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", - "0x48127f9d7fff8000", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", "0x1", + "0x48127ff87fff8000", + "0x48127ff87fff8000", + "0x208b7fff7fff7ffe", + "0x48127ff97fff8000", + "0x480a80007fff8000", + "0x480a80067fff8000", + "0x480a80057fff8000", + "0x482480017ffb8000", + "0xe2e", "0x480680017fff8000", - "0x4f7074696f6e3a3a756e77726170206661696c65642e", - "0x400080007ffe7fff", - "0x482480017ff48000", - "0x3", - "0x48127ffd7fff8000", - "0x482480017ffc8000", - "0x1", - "0x10780017fff7fff", - "0x15", - "0x40780017fff7fff", - "0xc", - "0x48127ff07fff8000", - "0x48127ff17fff8000", - "0x48127ff17fff8000", - "0x10780017fff7fff", - "0xe", - "0x40780017fff7fff", - "0x1d", - "0x40780017fff7fff", "0x1", + "0x48127ff77fff8000", + "0x48127ff77fff8000", + "0x208b7fff7fff7ffe", + "0x48127ff97fff8000", + "0x480a80007fff8000", + "0x480a80067fff8000", + "0x480a80057fff8000", + "0x482480017ffb8000", + "0x5398", "0x480680017fff8000", - "0x7533325f737562204f766572666c6f77", - "0x400080007ffe7fff", - "0x482480017fda8000", "0x1", - "0x48127ffd7fff8000", - "0x482480017ffc8000", + "0x48127ff77fff8000", + "0x48127ff77fff8000", + "0x208b7fff7fff7ffe", + "0x48127ff97fff8000", + "0x480a80007fff8000", + "0x480a80067fff8000", + "0x480a80057fff8000", + "0x482480017ffb8000", + "0x9902", + "0x480680017fff8000", "0x1", - "0x48127ffd7fff8000", + "0x48127ff77fff8000", + "0x48127ff77fff8000", + "0x208b7fff7fff7ffe", + "0x48127ff97fff8000", + "0x480a80007fff8000", + "0x480a80067fff8000", + "0x480a80057fff8000", + "0x482480017ffb8000", + "0xde6c", "0x480680017fff8000", "0x1", + "0x48127ff77fff8000", + "0x48127ff77fff8000", + "0x208b7fff7fff7ffe", + "0x480a7ff97fff8000", + "0x480a80007fff8000", + "0x480a80067fff8000", + "0x480a80057fff8000", + "0x482480017feb8000", + "0x1243a", + "0x480680017fff8000", + "0x0", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0x5a", - "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x7533325f737562204f766572666c6f77", + "0x526573756c743a3a756e77726170206661696c65642e", "0x400080007ffe7fff", - "0x482480017f9e8000", - "0x1", - "0x480680017fff8000", - "0x1", + "0x48327ffc7ffb8000", "0x480680017fff8000", "0x0", "0x480680017fff8000", - "0x0", - "0x48127ffa7fff8000", - "0x482480017ff98000", "0x1", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x40", - "0x480680017fff8000", - "0x10", - "0x48317fff80017ffd", - "0xa0680017fff7fff", + "0x484480017ff88000", + "0x3", + "0x48307fff7ff18000", + "0x400080027fff7ffc", + "0x480080017fff8000", + "0x480080007ffe8000", + "0x48307ff380007fe0", + "0x400080007fdf7ff9", + "0x400080017fdf7ff9", + "0x400080027fdf7ff9", + "0x400080037fdf7ff9", + "0x4800800080007ffe", + "0x400080017fff7ffc", + "0x400080027fff7ffe", + "0x400080047fde7ff2", + "0x48307ff280007fed", + "0x400080057fdd7fff", + "0x400080007ff67fd1", + "0x400080017ff67fd2", + "0x400080027ff67fd3", + "0x400080037ff67fd4", + "0x400080047ff67ff0", + "0x400080057ff67ffe", + "0x400080067ff67ff8", + "0x48307ffc7ff08000", + "0x480080007fff8000", + "0x480080017ffe8000", + "0x480080027ffd8000", + "0x480080037ffc8000", + "0x20680017fff7ffc", + "0x9", + "0x20680017fff7ffd", "0x7", - "0x482480017fff8000", - "0x100000000000000000000000000000000", - "0x400080007fba7fff", - "0x10780017fff7fff", - "0x2f", - "0x400080007fbb7fff", - "0x480680017fff8000", - "0x10", - "0x48317fff80017ffd", - "0xa0680017fff7fff", + "0x20680017fff7ffe", + "0x5", + "0x20680017fff7fff", + "0x3", + "0x40127ff27fff7ff3", + "0x482680017ffa8000", + "0xe", + "0x482480017fe98000", + "0x11cfa", + "0x48127fed7fff8000", + "0x482480017fec8000", + "0x1", + "0x482480017fd48000", + "0x6", + "0x482480017fec8000", "0x7", - "0x482480017fff8000", - "0x100000000000000000000000000000000", - "0x400080017fb77fff", - "0x10780017fff7fff", - "0x16", - "0x400080017fb87fff", - "0x482480017fb88000", - "0x2", + "0x48307ff980007fc9", + "0x20680017fff7fff", + "0x19", + "0x48127ffa7fff8000", + "0x48307ff680007fc6", + "0x20680017fff7fff", + "0xe", "0x48127ffe7fff8000", - "0x1104800180018000", - "0xa18", - "0x20680017fff7ffd", - "0x7", - "0x48127ffc7fff8000", - "0x484480017ffe8000", - "0x100000000000000000000000000000000", + "0x48307ff380007fc3", + "0x20680017fff7fff", + "0x6", + "0x48127ffe7fff8000", + "0x48307ff080007fc0", "0x10780017fff7fff", - "0x22", - "0x40780017fff7fff", - "0x9", - "0x48127ff37fff8000", - "0x48127ff47fff8000", - "0x48127ff47fff8000", + "0x12", + "0x48127ffe7fff8000", + "0x48127ffe7fff8000", "0x10780017fff7fff", - "0x58", - "0x40780017fff7fff", - "0x14", + "0xe", "0x40780017fff7fff", - "0x1", - "0x480680017fff8000", - "0x7533325f737562204f766572666c6f77", - "0x400080007ffe7fff", - "0x482480017fa18000", "0x2", - "0x48127ffd7fff8000", "0x482480017ffc8000", - "0x1", - "0x10780017fff7fff", - "0x4a", - "0x40780017fff7fff", - "0x2", - "0x482480017fb88000", - "0x1", - "0x480a7ffd7fff8000", - "0x1104800180018000", - "0x9f5", - "0x20680017fff7ffd", - "0x3c", + "0xb4", "0x48127ffc7fff8000", - "0x48127ffe7fff8000", - "0x48527fff7ffa8000", - "0x48327fff7ffc8000", - "0xa0680017fff8004", - "0xe", - "0x4824800180047ffe", - "0x100000000000000000000000000000000000000000000000000000000000000", - "0x484480017ffe8000", - "0x7000000000000110000000000000000", - "0x48307ffe7fff8002", - "0x480080007ff87ffc", - "0x480080017ff77ffc", - "0x402480017ffb7ffd", - "0xf8ffffffffffffeeffffffffffffffff", - "0x400080027ff67ffd", "0x10780017fff7fff", - "0x19", - "0x484480017fff8001", - "0x1000000000000000000000000000000", - "0x48307fff80007ffd", - "0x480080007ff97ffd", - "0x480080017ff87ffd", - "0x402480017ffc7ffe", - "0xff000000000000000000000000000000", - "0x400080027ff77ffe", + "0x7", "0x40780017fff7fff", - "0x3", - "0x400280007ff97ff7", + "0x4", + "0x482480017ff68000", + "0x230", + "0x48127ffa7fff8000", + "0x400080007ff77fff", + "0x480a7ff97fff8000", + "0x48127ff27fff8000", + "0x48127ff67fff8000", "0x482480017ff48000", - "0x3", + "0x1", + "0x48127ffa7fff8000", "0x480680017fff8000", - "0x0", - "0x480a7ff87fff8000", - "0x482680017ff98000", + "0x1", + "0x48127fef7fff8000", + "0x48127fef7fff8000", + "0x208b7fff7fff7ffe", + "0x1104800180018000", + "0x1d05", + "0x482480017fff8000", + "0x1d04", + "0x480080007fff8000", + "0x480080047fff8000", + "0x484480017fff8000", + "0x2", + "0x482480017fff8000", + "0x13b6a", + "0x480080057ffc8000", + "0x484480017fff8000", + "0x4", + "0x48307ffd7fff8000", + "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x0", + "0x4e6f7420616c6c20696e707574732068617665206265656e2066696c6c6564", + "0x400080007ffe7fff", + "0x480a7ff97fff8000", + "0x480a7ffa7fff8000", + "0x480a7ffb7fff8000", + "0x48127fe77fff8000", + "0x48307ff97fed8000", "0x480680017fff8000", - "0x0", + "0x1", + "0x48127ff87fff8000", + "0x482480017ff78000", + "0x1", "0x208b7fff7fff7ffe", + "0x1104800180018000", + "0x1ce7", + "0x482480017fff8000", + "0x1ce6", + "0x480080007fff8000", + "0x480080047fff8000", + "0x484480017fff8000", + "0x2", + "0x482480017fff8000", + "0x14d72", + "0x480080057ffc8000", + "0x484480017fff8000", + "0x4", + "0x48307ffd7fff8000", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4f7074696f6e3a3a756e77726170206661696c65642e", "0x400080007ffe7fff", - "0x482480017ff48000", - "0x3", + "0x480a7ff97fff8000", + "0x480a7ffa7fff8000", + "0x480a7ffb7fff8000", + "0x480a7ffc7fff8000", + "0x48327ff97ffd8000", "0x480680017fff8000", "0x1", + "0x48127ff87fff8000", + "0x482480017ff78000", + "0x1", + "0x208b7fff7fff7ffe", + "0x482680017ffd8000", + "0x4", + "0x482680017ffd8000", + "0x8", + "0x480680017fff8000", + "0x3", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", - "0x48127ffa7fff8000", + "0x480680017fff8000", + "0x0", + "0x482680017ffd8000", + "0xc", + "0x400080007ff97ffb", + "0x400080017ff97ffc", + "0x400080027ff97ffd", + "0x400080037ff97ffe", "0x482480017ff98000", - "0x1", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x9", - "0x48127ff37fff8000", - "0x48127ff47fff8000", - "0x48127ff47fff8000", + "0x4", + "0x48307fff80007ff9", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x2", "0x48127ffd7fff8000", "0x480680017fff8000", - "0x1", + "0x0", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x45", - "0x482680017ff78000", - "0x2", - "0x20780017fff7ffb", - "0xc", - "0x40780017fff7fff", - "0x1b", - "0x48127fe47fff8000", + "0x480680017fff8000", + "0x476574436c617373486173684174", + "0x400280007ff97fff", + "0x400380017ff97ff8", + "0x400380027ff97ffa", + "0x480280047ff98000", + "0x20680017fff7fff", + "0x19a", + "0x480280037ff98000", + "0x48127fff7fff8000", "0x480680017fff8000", "0x0", - "0x480a7ff87fff8000", - "0x480a7ff97fff8000", - "0x480a7ffc7fff8000", - "0x480a7ffd7fff8000", - "0x208b7fff7fff7ffe", "0x480680017fff8000", - "0x10", - "0x48317fff80017ffd", - "0xa0680017fff7fff", - "0x7", - "0x482480017fff8000", - "0x100000000000000000000000000000000", - "0x400080007ffb7fff", - "0x10780017fff7fff", - "0x2f", - "0x400080007ffc7fff", + "0x995a1546f96051a2b911879c7b314d53d580bd592e7ea51593aaec427e3c9b", "0x480680017fff8000", - "0x10", - "0x48317fff80017ffd", - "0xa0680017fff7fff", - "0x7", - "0x482480017fff8000", - "0x100000000000000000000000000000000", - "0x400080017ff87fff", - "0x10780017fff7fff", - "0x16", - "0x400080017ff97fff", - "0x482480017ff98000", - "0x2", - "0x48127ffe7fff8000", - "0x1104800180018000", - "0x97f", - "0x20680017fff7ffd", "0x7", - "0x48127ffc7fff8000", - "0x484480017ffe8000", - "0x100000000000000000000000000000000", - "0x10780017fff7fff", - "0x22", + "0x480280057ff98000", + "0x480680017fff8000", + "0x53746f726167655772697465", + "0x400280067ff97fff", + "0x400280077ff97ffa", + "0x400280087ff97ffb", + "0x400280097ff97ffc", + "0x4002800a7ff97ffd", + "0x4802800c7ff98000", + "0x20680017fff7fff", + "0x17b", + "0x4802800b7ff98000", + "0x48127fff7fff8000", + "0x480680017fff8000", + "0x43616c6c436f6e7472616374", + "0x4002800d7ff97fff", + "0x4002800e7ff97ffe", + "0x4003800f7ff97ffa", + "0x400380107ff97ffb", + "0x400380117ff97ffc", + "0x400380127ff97ffd", + "0x480280147ff98000", + "0x20680017fff7fff", + "0x1d", + "0x40780017fff7fff", + "0x2e", + "0x480280137ff98000", "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x46a6158a16a947e5916b2a2ca68501a45e93d7110e81aa2d6438b1c57c879a3", + "0x400080007ffe7fff", + "0x480680017fff8000", + "0x0", + "0x400080017ffd7fff", + "0x480680017fff8000", + "0x457870656374656420726576657274", + "0x400080027ffc7fff", + "0x480680017fff8000", + "0xf", + "0x400080037ffb7fff", + "0x482480017ffa8000", + "0x8d2c", + "0x482680017ff98000", + "0x17", + "0x480680017fff8000", + "0x1", + "0x48127ff87fff8000", + "0x482480017ff78000", + "0x4", + "0x208b7fff7fff7ffe", + "0x480280137ff98000", + "0x480280157ff98000", + "0x480280167ff98000", + "0x482680017ff98000", + "0x17", + "0x48127ffc7fff8000", + "0x48307ffc80007ffd", + "0x20680017fff7fff", "0x4", + "0x10780017fff7fff", + "0x138", + "0x4824800180007ffc", + "0x1", + "0x480080007fff8000", + "0x4824800180007fff", + "0x454e545259504f494e545f4641494c4544", "0x48127ff87fff8000", + "0x4824800180007ff8", + "0x1", "0x48127ff97fff8000", - "0x48127ff97fff8000", + "0x20680017fff7ffc", + "0x11d", + "0x48127fff7fff8000", + "0x48307ffc80007ffd", + "0x20680017fff7fff", + "0x4", "0x10780017fff7fff", - "0x49", + "0x107", + "0x4824800180007ffc", + "0x1", + "0x4825800180007ffb", + "0x1c4e1062ccac759d9786c18a401086aa7ab90fde340fffd5cbd792d11daa7e7", + "0x48127ffc7fff8000", + "0x480080007ffd8000", + "0x20680017fff7ffd", + "0x1d", "0x40780017fff7fff", - "0xf", + "0x4", + "0x4824800180007ffb", + "0x454e545259504f494e545f4e4f545f464f554e44", + "0x482480017ff98000", + "0x168", + "0x20680017fff7ffe", + "0x5", + "0x48127fff7fff8000", + "0x10780017fff7fff", + "0x3d", + "0x40780017fff7fff", + "0x1a", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x7533325f737562204f766572666c6f77", + "0x556e6578706563746564206572726f72", "0x400080007ffe7fff", - "0x482480017fe78000", - "0x2", + "0x482480017fe38000", + "0x84f8", + "0x48127fce7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffb7fff8000", + "0x482480017ffa8000", + "0x1", + "0x208b7fff7fff7ffe", + "0x4825800180007ffb", + "0x1e4089d1f1349077b1970f9937c904e27c4582b49a60b6078946dba95bc3c08", "0x48127ffd7fff8000", + "0x20680017fff7ffe", + "0x1d", + "0x40780017fff7fff", + "0x2", + "0x4824800180007ffb", + "0x746573745f7265766572745f68656c706572", "0x482480017ffc8000", - "0x1", + "0x50", + "0x20680017fff7ffe", + "0x5", + "0x48127fff7fff8000", "0x10780017fff7fff", - "0x3b", + "0x1d", + "0x40780017fff7fff", + "0x1a", "0x40780017fff7fff", - "0x2", - "0x482480017ff98000", "0x1", - "0x480a7ffd7fff8000", - "0x1104800180018000", - "0x95c", + "0x480680017fff8000", + "0x556e6578706563746564206572726f72", + "0x400080007ffe7fff", + "0x482480017fe38000", + "0x84f8", + "0x48127fce7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffb7fff8000", + "0x482480017ffa8000", + "0x1", + "0x208b7fff7fff7ffe", + "0x4825800180007ffb", + "0x311fb2a7f01403971aca6ae0a12b8ad0602e7a5ec48ad48951969942e99d788", + "0x48127ffe7fff8000", + "0x20680017fff7ffe", + "0xaf", + "0x4824800180007ffb", + "0x657865637574655f616e645f726576657274", + "0x48127ffe7fff8000", + "0x20680017fff7ffe", + "0x9a", + "0x48127fff7fff8000", + "0x480680017fff8000", + "0x476574436c617373486173684174", + "0x400080007fe97fff", + "0x400080017fe97ffe", + "0x400180027fe97ffa", + "0x480080047fe98000", + "0x20680017fff7fff", + "0x85", + "0x480080037fe88000", + "0x48127fff7fff8000", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x1275130f95dda36bcbb6e9d28796c1d7e10b6e9fd5ed083e0ede4b12f613528", + "0x480080057fe48000", + "0x480680017fff8000", + "0x53746f7261676552656164", + "0x400080067fe27fff", + "0x400080077fe27ffb", + "0x400080087fe27ffc", + "0x400080097fe27ffd", + "0x4800800b7fe28000", + "0x20680017fff7fff", + "0x69", + "0x4800800a7fe18000", + "0x4800800c7fe08000", + "0x482480017fdf8000", + "0xd", + "0x48127ffd7fff8000", "0x20680017fff7ffd", - "0x2d", - "0x48127ffc7fff8000", + "0x52", + "0x48307ff980007fd3", "0x48127ffe7fff8000", - "0xa0680017fff8000", - "0x8", - "0x482a7ffd7ffb8000", - "0x4824800180007fff", - "0x100000000", - "0x400080007ffb7fff", - "0x10780017fff7fff", - "0x12", - "0x482a7ffd7ffb8001", + "0x20680017fff7ffe", + "0x3e", + "0x48127fff7fff8000", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x995a1546f96051a2b911879c7b314d53d580bd592e7ea51593aaec427e3c9b", + "0x480680017fff8000", + "0x53746f7261676552656164", + "0x400080007ff87fff", + "0x400080017ff87ffc", + "0x400080027ff87ffd", + "0x400080037ff87ffe", + "0x480080057ff88000", + "0x20680017fff7fff", + "0x24", + "0x480080047ff78000", + "0x480080067ff68000", "0x4824800180007fff", - "0xffffffffffffffffffffffff00000000", - "0x400080007ffb7ffe", + "0x7", + "0x482480017ff48000", + "0x7", + "0x48127ffc7fff8000", + "0x20680017fff7ffd", + "0xe", "0x40780017fff7fff", - "0x1", - "0x48527ffb7ffa8000", - "0x482480017ff98000", - "0x1", + "0x2", + "0x482480017ffd8000", + "0xb4", + "0x48127ffb7fff8000", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", "0x480680017fff8000", "0x0", - "0x480a7ff87fff8000", - "0x480a7ff97fff8000", - "0x48327ffb7ffc8000", - "0x48127ff87fff8000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x7533325f616464204f766572666c6f77", + "0x746573745f73746f726167655f7661725f6368616e6765642e", "0x400080007ffe7fff", - "0x482480017ff98000", + "0x48127ffd7fff8000", + "0x48127ffb7fff8000", + "0x480680017fff8000", "0x1", + "0x48127ffb7fff8000", + "0x482480017ffa8000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x6", + "0x480080047ff18000", + "0x482480017fff8000", + "0x280", + "0x482480017fef8000", + "0x8", "0x480680017fff8000", "0x1", + "0x480080067fed8000", + "0x480080077fec8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0xa", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", + "0x636c61737320686173682073686f756c64206e6f74206368616e67652e", + "0x400080007ffe7fff", + "0x482480017ff38000", + "0x2c88", + "0x48127fef7fff8000", "0x480680017fff8000", - "0x0", - "0x48127ffa7fff8000", - "0x482480017ff98000", + "0x1", + "0x48127ffb7fff8000", + "0x482480017ffa8000", "0x1", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0x4", - "0x48127ff87fff8000", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x48127ffd7fff8000", + "0xc", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x76616c7565732073686f756c64206e6f74206368616e67652e", + "0x400080007ffe7fff", + "0x482480017ff18000", + "0x2da0", + "0x48127fef7fff8000", "0x480680017fff8000", "0x1", + "0x48127ffb7fff8000", + "0x482480017ffa8000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x11", + "0x4800800a7fd08000", + "0x482480017fff8000", + "0x302a", + "0x482480017fce8000", + "0xe", "0x480680017fff8000", - "0x0", + "0x1", + "0x4800800c7fcc8000", + "0x4800800d7fcb8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x18", + "0x480080037fd08000", + "0x482480017fff8000", + "0x5ba4", + "0x482480017fce8000", + "0x7", "0x480680017fff8000", - "0x0", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", + "0x1", + "0x480080057fcc8000", + "0x480080067fcb8000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0x63", + "0x1a", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x7533325f616464204f766572666c6f77", + "0x57726f6e675f6572726f72", "0x400080007ffe7fff", - "0x482680017ff78000", - "0x1", + "0x482480017fe38000", + "0x8494", + "0x48127fce7fff8000", "0x480680017fff8000", "0x1", + "0x48127ffb7fff8000", + "0x482480017ffa8000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1c", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", + "0x57726f6e6720456e74727920506f696e74", + "0x400080007ffe7fff", + "0x482480017fe18000", + "0x85ac", + "0x48127fce7fff8000", "0x480680017fff8000", - "0x0", - "0x48127ffa7fff8000", - "0x482480017ff98000", + "0x1", + "0x48127ffb7fff8000", + "0x482480017ffa8000", "0x1", "0x208b7fff7fff7ffe", - "0xa0680017fff8000", - "0x7", - "0x482680017ff98000", - "0xfffffffffffffffffffffffffffff97a", - "0x400280007ff87fff", - "0x10780017fff7fff", - "0x20", - "0x4825800180007ff9", - "0x686", - "0x400280007ff87fff", - "0x482680017ff88000", + "0x40780017fff7fff", + "0x24", + "0x40780017fff7fff", "0x1", - "0x48297ffa80007ffb", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0xf", - "0x480280007ffa8000", - "0x400280007ffd7fff", - "0x48127ffd7fff8000", - "0x48127ffb7fff8000", - "0x482680017ffa8000", + "0x480680017fff8000", + "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x400080007ffe7fff", + "0x482480017fd88000", + "0x8944", + "0x48127fce7fff8000", + "0x480680017fff8000", "0x1", - "0x480a7ffb7fff8000", - "0x480a7ffc7fff8000", - "0x482680017ffd8000", + "0x48127ffb7fff8000", + "0x482480017ffa8000", "0x1", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffe6", "0x208b7fff7fff7ffe", - "0x48127ffe7fff8000", - "0x48127ffc7fff8000", + "0x40780017fff7fff", + "0x26", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", - "0x480a7ffc7fff8000", - "0x480a7ffd7fff8000", + "0x556e6578706563746564206572726f72", + "0x400080007ffe7fff", + "0x482480017fd78000", + "0x8ac0", + "0x48127fce7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffb7fff8000", + "0x482480017ffa8000", + "0x1", "0x208b7fff7fff7ffe", "0x40780017fff7fff", + "0x2c", + "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4f7574206f6620676173", + "0x4f7074696f6e3a3a756e77726170206661696c65642e", "0x400080007ffe7fff", - "0x482680017ff88000", - "0x1", - "0x480a7ff97fff8000", + "0x482480017fd08000", + "0x8cdc", + "0x48127fce7fff8000", "0x480680017fff8000", "0x1", "0x48127ffb7fff8000", "0x482480017ffa8000", "0x1", "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x37", + "0x4802800b7ff98000", + "0x482480017fff8000", + "0xbbb2", + "0x482680017ff98000", + "0xf", + "0x480680017fff8000", + "0x1", + "0x4802800d7ff98000", + "0x4802800e7ff98000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x3f", + "0x480280037ff98000", + "0x482480017fff8000", + "0xe7ea", + "0x482680017ff98000", + "0x7", + "0x480680017fff8000", + "0x1", + "0x480280057ff98000", + "0x480280067ff98000", + "0x208b7fff7fff7ffe", "0x48297ffc80007ffd", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x93", + "0xa", "0x482680017ffc8000", "0x1", "0x480a7ffd7fff8000", - "0x480280007ffc8000", - "0x48307ffd80007ffe", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0xa", - "0x482480017ffc8000", - "0x1", - "0x48127ffc7fff8000", "0x480680017fff8000", "0x0", - "0x48127ff97fff8000", + "0x480a7ffc7fff8000", "0x10780017fff7fff", "0x8", - "0x48127ffc7fff8000", - "0x48127ffc7fff8000", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", "0x480680017fff8000", "0x1", "0x480680017fff8000", "0x0", "0x20680017fff7ffe", - "0x6c", + "0x98", "0x480080007fff8000", "0xa0680017fff8000", "0x12", "0x4824800180007ffe", - "0x10000000000000000", + "0x100000000", "0x4844800180008002", "0x8000000000000110000000000000000", "0x4830800080017ffe", "0x480280007ffb7fff", "0x482480017ffe8000", - "0xefffffffffffffdeffffffffffffffff", + "0xefffffffffffffde00000000ffffffff", "0x480280017ffb7fff", "0x400280027ffb7ffb", "0x402480017fff7ffb", "0xffffffffffffffffffffffffffffffff", "0x20680017fff7fff", - "0x55", + "0x78", "0x402780017fff7fff", "0x1", "0x400280007ffb7ffe", "0x482480017ffe8000", - "0xffffffffffffffff0000000000000000", + "0xffffffffffffffffffffffff00000000", "0x400280017ffb7fff", - "0x482680017ffb8000", - "0x2", - "0x48307ff880007ff9", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0xa", - "0x482480017ff78000", - "0x1", - "0x48127ff77fff8000", "0x480680017fff8000", "0x0", - "0x48127ff47fff8000", - "0x10780017fff7fff", + "0x48307ff880007ff9", + "0x48307ffb7ffe8000", + "0xa0680017fff8000", "0x8", - "0x48127ff77fff8000", - "0x48127ff77fff8000", - "0x480680017fff8000", + "0x482480017ffd8000", "0x1", - "0x480680017fff8000", - "0x0", - "0x20680017fff7ffe", - "0x2a", - "0x480080007fff8000", - "0xa0680017fff8000", - "0x16", - "0x480080007ff88003", - "0x480080017ff78003", - "0x4844800180017ffe", + "0x48307fff80007ffd", + "0x400280027ffb7fff", + "0x10780017fff7fff", + "0x51", + "0x48307ffe80007ffd", + "0x400280027ffb7fff", + "0x48307ff480007ff5", + "0x48307ffa7ff38000", + "0x48307ffb7ff28000", + "0x48307ff580017ffd", + "0xa0680017fff7fff", + "0x7", + "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x483080017ffd7ffb", - "0x482480017fff7ffd", - "0x800000000000010fffffffffffffffff7ffffffffffffef0000000000000001", - "0x20680017fff7ffc", - "0x6", - "0x402480017fff7ffd", - "0xffffffffffffffffffffffffffffffff", + "0x400280037ffb7fff", "0x10780017fff7fff", - "0x4", - "0x402480017ffe7ffd", - "0xf7ffffffffffffef0000000000000000", - "0x400080027ff37ffd", - "0x20680017fff7ffe", - "0x11", - "0x402780017fff7fff", + "0x2f", + "0x400280037ffb7fff", + "0x48307fef80007ff0", + "0x48307ffe7ff28000", + "0xa0680017fff8000", + "0x8", + "0x482480017ffd8000", "0x1", - "0x400080007ff87ffe", + "0x48307fff80007ffd", + "0x400280047ffb7fff", + "0x10780017fff7fff", + "0x11", + "0x48307ffe80007ffd", + "0x400280047ffb7fff", "0x40780017fff7fff", + "0x3", + "0x482680017ffb8000", "0x5", - "0x482480017ff38000", - "0x1", - "0x48127ff47fff8000", - "0x48127ff47fff8000", "0x480680017fff8000", "0x0", - "0x48127fe67fff8000", - "0x48127feb7fff8000", - "0x48127ff37fff8000", + "0x48307fea7fe68000", + "0x48307ff77fe58000", + "0x480680017fff8000", + "0x0", + "0x48127ff07fff8000", + "0x48127ff07fff8000", "0x208b7fff7fff7ffe", - "0x482480017ff38000", - "0x3", - "0x10780017fff7fff", - "0x5", "0x40780017fff7fff", - "0x7", - "0x48127ff37fff8000", - "0x48127ff47fff8000", - "0x48127ff47fff8000", + "0x1", + "0x480680017fff8000", + "0x496e646578206f7574206f6620626f756e6473", + "0x400080007ffe7fff", + "0x482680017ffb8000", + "0x5", "0x480680017fff8000", "0x1", "0x480680017fff8000", @@ -16817,18 +16193,19 @@ "0x0", "0x480680017fff8000", "0x0", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0x8", - "0x482680017ffb8000", - "0x3", - "0x10780017fff7fff", - "0x5", + "0x4", "0x40780017fff7fff", - "0x10", - "0x480a7ffb7fff8000", - "0x48127feb7fff8000", - "0x48127feb7fff8000", + "0x1", + "0x480680017fff8000", + "0x7533325f737562204f766572666c6f77", + "0x400080007ffe7fff", + "0x482680017ffb8000", + "0x4", "0x480680017fff8000", "0x1", "0x480680017fff8000", @@ -16837,12 +16214,19 @@ "0x0", "0x480680017fff8000", "0x0", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0x18", - "0x480a7ffb7fff8000", - "0x480a7ffc7fff8000", - "0x480a7ffd7fff8000", + "0x9", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x496e646578206f7574206f6620626f756e6473", + "0x400080007ffe7fff", + "0x482680017ffb8000", + "0x3", "0x480680017fff8000", "0x1", "0x480680017fff8000", @@ -16851,231 +16235,225 @@ "0x0", "0x480680017fff8000", "0x0", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0xc", + "0x482680017ffb8000", + "0x3", "0x480680017fff8000", - "0x10000000000000000", - "0x480280007ff98005", - "0x480280017ff98005", - "0x4824800180047ffe", - "0x1", - "0x48307ffd7ffe7ffc", - "0x480280027ff97ffd", - "0xa0680017fff7ffd", - "0x6", - "0x482480017ff97ffd", - "0xffffffffffffffff0000000000000000", - "0x10780017fff7fff", - "0x4", - "0x482480017fff7ffd", - "0xffffffffffffffff0000000000000000", - "0x400280037ff97ffc", - "0x40507ffe7ff87ffd", - "0x40317fff7ffd7ffc", - "0xa0680017fff8000", - "0x7", - "0x4824800180007ffd", - "0x10000000000000000", - "0x400280047ff97fff", - "0x10780017fff7fff", - "0x73", - "0x482480017ffd8000", - "0xffffffffffffffff0000000000000000", - "0x400280047ff97fff", - "0xa0680017fff8000", - "0x7", - "0x4824800180007ffc", - "0x10000000000000000", - "0x400280057ff97fff", - "0x10780017fff7fff", - "0x5b", - "0x482480017ffc8000", - "0xffffffffffffffff0000000000000000", - "0x400280057ff97fff", - "0x400280007ffb7ffb", - "0x400280017ffb7ffa", + "0x0", + "0x48127fe67fff8000", + "0x48127fe67fff8000", "0x480680017fff8000", - "0x10000000000000000", - "0x480280067ff98005", - "0x480280077ff98005", - "0x4824800180047ffe", "0x1", - "0x48307ffd7ffe7ffc", - "0x480280087ff97ffd", - "0xa0680017fff7ffd", - "0x6", - "0x482480017ff97ffd", - "0xffffffffffffffff0000000000000000", - "0x10780017fff7fff", - "0x4", - "0x482480017fff7ffd", - "0xffffffffffffffff0000000000000000", - "0x400280097ff97ffc", - "0x40507ffe7ff87ffd", - "0x40317fff7ffd7ffd", - "0x480a7ffa7fff8000", - "0x482680017ffb8000", - "0x2", - "0xa0680017fff8000", - "0x7", - "0x4824800180007ffb", - "0x10000000000000000", - "0x4002800a7ff97fff", - "0x10780017fff7fff", - "0x27", - "0x482480017ffb8000", - "0xffffffffffffffff0000000000000000", - "0x4002800a7ff97fff", - "0xa0680017fff8000", - "0x7", - "0x4824800180007ffa", - "0x10000000000000000", - "0x4002800b7ff97fff", - "0x10780017fff7fff", - "0x11", - "0x482480017ffa8000", - "0xffffffffffffffff0000000000000000", - "0x4002800b7ff97fff", - "0x40780017fff7fff", - "0x5", - "0x400080007ff67ff4", - "0x400080017ff67ff3", - "0x482680017ff98000", - "0xc", "0x480680017fff8000", "0x0", - "0x48127ff37fff8000", - "0x482480017ff38000", - "0x2", + "0x480680017fff8000", + "0x0", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0x1", + "0x14", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x0", + "0x48127fe67fff8000", + "0x48127fe67fff8000", "0x480680017fff8000", - "0x4f7074696f6e3a3a756e77726170206661696c65642e", - "0x400080007ffe7fff", - "0x482680017ff98000", - "0xc", - "0x48127ffd7fff8000", - "0x482480017ffc8000", "0x1", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x208b7fff7fff7ffe", + "0xa0680017fff8000", + "0x7", + "0x482680017ff88000", + "0xffffffffffffffffffffffffffffe23c", + "0x400280007ff77fff", "0x10780017fff7fff", - "0xe", - "0x40780017fff7fff", - "0x2", - "0x40780017fff7fff", + "0x3b", + "0x4825800180007ff8", + "0x1dc4", + "0x400280007ff77fff", + "0x482680017ff78000", "0x1", + "0x48127ffe7fff8000", + "0x20780017fff7ffd", + "0xe", + "0x48127ffe7fff8000", + "0x482480017ffe8000", + "0x1e28", "0x480680017fff8000", - "0x4f7074696f6e3a3a756e77726170206661696c65642e", - "0x400080007ffe7fff", - "0x482680017ff98000", - "0xb", - "0x48127ffd7fff8000", - "0x482480017ffc8000", + "0x0", + "0x480a7ff97fff8000", + "0x480a7ffa7fff8000", + "0x480680017fff8000", + "0x0", + "0x480a7ffb7fff8000", + "0x480a7ffc7fff8000", + "0x208b7fff7fff7ffe", + "0x48127ffe7fff8000", + "0x480a7ff97fff8000", + "0x480a7ffa7fff8000", + "0x1104800180018000", + "0xefe", + "0x48127fda7fff8000", + "0x20680017fff7ffb", + "0x11", + "0x400280007ffc7ffc", + "0x400280017ffc7ffd", + "0x400280027ffc7ffe", + "0x48127ff87fff8000", + "0x48127ffe7fff8000", + "0x48127ff77fff8000", + "0x48127ff77fff8000", + "0x480a7ffb7fff8000", + "0x482680017ffc8000", + "0x3", + "0x4825800180007ffd", "0x1", - "0x48127ffd7fff8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffd2", + "0x208b7fff7fff7ffe", + "0x48127ff87fff8000", + "0x482480017ffe8000", + "0x7b2", + "0x480680017fff8000", + "0x0", + "0x48127ff67fff8000", + "0x48127ff67fff8000", "0x480680017fff8000", "0x1", - "0x48127ffc7fff8000", - "0x48127ffc7fff8000", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0xe", - "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482680017ff98000", - "0x6", - "0x48127ffd7fff8000", - "0x482480017ffc8000", - "0x1", - "0x10780017fff7fff", - "0xe", - "0x40780017fff7fff", - "0x10", - "0x40780017fff7fff", + "0x482680017ff78000", "0x1", + "0x480a7ff87fff8000", "0x480680017fff8000", - "0x4f7074696f6e3a3a756e77726170206661696c65642e", - "0x400080007ffe7fff", - "0x482680017ff98000", - "0x5", - "0x48127ffd7fff8000", - "0x482480017ffc8000", "0x1", - "0x48127ffd7fff8000", "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x48127ff87fff8000", + "0x482480017ff78000", "0x1", - "0x48127ffc7fff8000", - "0x48127ffc7fff8000", "0x208b7fff7fff7ffe", "0xa0680017fff8000", "0x7", - "0x482680017ffa8000", - "0xfffffffffffffffffffffffffffff740", - "0x400280007ff97fff", - "0x10780017fff7fff", - "0x40", - "0x4825800180007ffa", - "0x8c0", - "0x400280007ff97fff", "0x482680017ff98000", + "0xfffffffffffffffffffffffffffff33a", + "0x400280007ff87fff", + "0x10780017fff7fff", + "0x63", + "0x4825800180007ff9", + "0xcc6", + "0x400280007ff87fff", + "0x482680017ff88000", "0x1", - "0x4825800180007ffd", - "0x1", + "0x48127ffe7fff8000", + "0x48297ffa80007ffb", "0x20680017fff7fff", "0x4", "0x10780017fff7fff", - "0x2a", + "0xb", + "0x48127ffe7fff8000", + "0x482680017ffa8000", + "0x1", + "0x480a7ffb7fff8000", "0x480680017fff8000", "0x0", - "0x400280007ffc7fff", - "0x480680017fff8000", - "0x1", + "0x480a7ffa7fff8000", + "0x10780017fff7fff", + "0x9", + "0x48127ffe7fff8000", + "0x480a7ffa7fff8000", "0x480a7ffb7fff8000", - "0x482680017ffc8000", + "0x480680017fff8000", "0x1", - "0x48317ffd80017ffd", - "0xa0680017fff7fff", - "0x7", - "0x482480017fff8000", - "0x100000000000000000000000000000000", - "0x400080007ff77fff", + "0x480680017fff8000", + "0x0", + "0x20680017fff7ffe", + "0x3a", + "0x48127ffb7fff8000", + "0x480080007ffe8000", + "0x48297ffc80007ffd", + "0x20680017fff7fff", + "0x4", "0x10780017fff7fff", - "0xc", - "0x400080007ff87fff", - "0x482480017ff88000", + "0x1f", + "0x480280007ffc8000", + "0x48307fff80007ffd", + "0x48127ffb7fff8000", + "0x482680017ffc8000", "0x1", - "0x48127ff67fff8000", + "0x480a7ffd7fff8000", + "0x20680017fff7ffc", + "0xb", + "0x48127ff07fff8000", + "0x48127ffc7fff8000", + "0x48127ff27fff8000", + "0x48127ff27fff8000", "0x48127ffa7fff8000", "0x48127ffa7fff8000", - "0x48127ffb7fff8000", "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffd8", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffc8", + "0x208b7fff7fff7ffe", + "0x48127ff07fff8000", + "0x482480017ffc8000", + "0x622", + "0x480680017fff8000", + "0x0", + "0x48127ff17fff8000", + "0x48127ff17fff8000", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x480680017fff8000", + "0x0", "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x7533325f737562204f766572666c6f77", + "0x4f7074696f6e3a3a756e77726170206661696c65642e", "0x400080007ffe7fff", - "0x482480017ff58000", - "0x1", "0x48127ff37fff8000", + "0x482480017ffa8000", + "0x6ea", "0x480680017fff8000", "0x1", - "0x48127ffb7fff8000", - "0x482480017ffa8000", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x48127ff87fff8000", + "0x482480017ff78000", "0x1", "0x208b7fff7fff7ffe", - "0x480680017fff8000", - "0x8000000000000000", - "0x400280007ffc7fff", - "0x48127ffd7fff8000", - "0x48127ffb7fff8000", + "0x48127ff87fff8000", + "0x482480017ffa8000", + "0xa0a", "0x480680017fff8000", "0x0", - "0x480a7ffb7fff8000", - "0x482680017ffc8000", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", + "0x480680017fff8000", "0x1", "0x208b7fff7fff7ffe", "0x40780017fff7fff", @@ -17083,538 +16461,1508 @@ "0x480680017fff8000", "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x482680017ff98000", + "0x482680017ff88000", "0x1", - "0x480a7ffa7fff8000", + "0x480a7ff97fff8000", "0x480680017fff8000", "0x1", - "0x48127ffb7fff8000", - "0x482480017ffa8000", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x48127ff87fff8000", + "0x482480017ff78000", "0x1", "0x208b7fff7fff7ffe", - "0x20780017fff7ffd", + "0xa0680017fff8000", "0x7", - "0x40780017fff7fff", - "0x3d", + "0x482680017ff98000", + "0xffffffffffffffffffffffffffffee8a", + "0x400280007ff87fff", + "0x10780017fff7fff", + "0x80", + "0x4825800180007ff9", + "0x1176", + "0x400280007ff87fff", + "0x482680017ff88000", + "0x1", + "0x48127ffe7fff8000", + "0x48297ffa80007ffb", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xb", + "0x48127ffe7fff8000", + "0x482680017ffa8000", + "0x3", "0x480a7ffb7fff8000", - "0x480a7ffc7fff8000", - "0x208b7fff7fff7ffe", "0x480680017fff8000", "0x0", - "0x400280007ffc7fff", - "0x4825800180007ffd", - "0x1", + "0x480a7ffa7fff8000", + "0x10780017fff7fff", + "0x9", + "0x48127ffe7fff8000", + "0x480a7ffa7fff8000", "0x480a7ffb7fff8000", - "0x482680017ffc8000", + "0x480680017fff8000", "0x1", - "0x20680017fff7ffd", - "0x7", - "0x40780017fff7fff", - "0x39", - "0x48127fc57fff8000", - "0x48127fc57fff8000", - "0x208b7fff7fff7ffe", "0x480680017fff8000", "0x0", - "0x400080007ffe7fff", - "0x4825800180007ffd", + "0x20680017fff7ffe", + "0x57", + "0x48127ffb7fff8000", + "0x480080007ffe8000", + "0x480080017ffd8000", + "0x480080027ffc8000", + "0x48297ffc80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x3a", + "0x480280007ffc8000", + "0x480280017ffc8000", + "0x480280027ffc8000", + "0x48307ffd80007ff9", + "0x48127ff77fff8000", + "0x482680017ffc8000", + "0x3", + "0x480a7ffd7fff8000", + "0x20680017fff7ffc", + "0x21", + "0x48127ffd7fff8000", + "0x48307ff980007ff5", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x8", + "0x40780017fff7fff", "0x2", - "0x48127ffc7fff8000", "0x482480017ffc8000", - "0x1", - "0x20680017fff7ffd", - "0x7", - "0x40780017fff7fff", - "0x35", - "0x48127fc97fff8000", - "0x48127fc97fff8000", + "0x6d6", + "0x10780017fff7fff", + "0x19", + "0x48127ffe7fff8000", + "0x48307ff880007ff4", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x6", + "0x482480017ffe8000", + "0x5be", + "0x10780017fff7fff", + "0xf", + "0x48127fe87fff8000", + "0x48127ffd7fff8000", + "0x48127fea7fff8000", + "0x48127fea7fff8000", + "0x48127ff67fff8000", + "0x48127ff67fff8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffae", "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x4", + "0x482480017ff98000", + "0x852", + "0x48127fe77fff8000", + "0x48127ffe7fff8000", "0x480680017fff8000", "0x0", - "0x400080007ffe7fff", - "0x4825800180007ffd", - "0x3", - "0x48127ffc7fff8000", - "0x482480017ffc8000", - "0x1", - "0x20680017fff7ffd", - "0x7", - "0x40780017fff7fff", - "0x31", - "0x48127fcd7fff8000", - "0x48127fcd7fff8000", - "0x208b7fff7fff7ffe", + "0x48127fe87fff8000", + "0x48127fe87fff8000", + "0x48127ff47fff8000", + "0x48127ff47fff8000", "0x480680017fff8000", "0x0", - "0x400080007ffe7fff", - "0x4825800180007ffd", - "0x4", - "0x48127ffc7fff8000", - "0x482480017ffc8000", - "0x1", - "0x20680017fff7ffd", - "0x7", - "0x40780017fff7fff", - "0x2d", - "0x48127fd17fff8000", - "0x48127fd17fff8000", "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", + "0x4f7074696f6e3a3a756e77726170206661696c65642e", "0x400080007ffe7fff", - "0x4825800180007ffd", - "0x5", - "0x48127ffc7fff8000", - "0x482480017ffc8000", + "0x48127ff17fff8000", + "0x482480017ff88000", + "0xad2", + "0x480680017fff8000", "0x1", - "0x20680017fff7ffd", - "0x7", - "0x40780017fff7fff", - "0x29", - "0x48127fd57fff8000", - "0x48127fd57fff8000", - "0x208b7fff7fff7ffe", "0x480680017fff8000", "0x0", - "0x400080007ffe7fff", - "0x4825800180007ffd", - "0x6", - "0x48127ffc7fff8000", - "0x482480017ffc8000", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x48127ff87fff8000", + "0x482480017ff78000", "0x1", - "0x20680017fff7ffd", - "0x7", - "0x40780017fff7fff", - "0x25", - "0x48127fd97fff8000", - "0x48127fd97fff8000", "0x208b7fff7fff7ffe", + "0x48127ff87fff8000", + "0x482480017ffa8000", + "0xeba", "0x480680017fff8000", "0x0", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", + "0x480680017fff8000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x4825800180007ffd", - "0x7", - "0x48127ffc7fff8000", - "0x482480017ffc8000", + "0x482680017ff88000", "0x1", - "0x20680017fff7ffd", + "0x480a7ff97fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x48127ff87fff8000", + "0x482480017ff78000", + "0x1", + "0x208b7fff7fff7ffe", + "0xa0680017fff8000", "0x7", - "0x40780017fff7fff", + "0x482680017ff98000", + "0xffffffffffffffffffffffffffffdc06", + "0x400280007ff87fff", + "0x10780017fff7fff", + "0x48", + "0x4825800180007ff9", + "0x23fa", + "0x400280007ff87fff", + "0x482680017ff88000", + "0x1", + "0x48127ffe7fff8000", + "0x48297ffa80007ffb", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xb", + "0x48127ffe7fff8000", + "0x482680017ffa8000", + "0x2", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x0", + "0x480a7ffa7fff8000", + "0x10780017fff7fff", + "0x9", + "0x48127ffe7fff8000", + "0x480a7ffa7fff8000", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x20680017fff7ffe", "0x21", - "0x48127fdd7fff8000", - "0x48127fdd7fff8000", + "0x48127ff87fff8000", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", + "0x480080007ffc8000", + "0x480080017ffb8000", + "0x1104800180018000", + "0xe2e", + "0x48127fd17fff8000", + "0x20680017fff7ffc", + "0xb", + "0x48127ffb7fff8000", + "0x48127ffe7fff8000", + "0x48127fcf7fff8000", + "0x48127fcf7fff8000", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffcd", "0x208b7fff7fff7ffe", + "0x48127ffb7fff8000", + "0x482480017ffe8000", + "0x622", "0x480680017fff8000", - "0x0", - "0x400080007ffe7fff", - "0x4825800180007ffd", - "0x8", - "0x48127ffc7fff8000", - "0x482480017ffc8000", "0x1", - "0x20680017fff7ffd", - "0x7", - "0x40780017fff7fff", - "0x1d", - "0x48127fe17fff8000", - "0x48127fe17fff8000", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x48127ff87fff8000", + "0x48127ff87fff8000", "0x208b7fff7fff7ffe", + "0x48127ff87fff8000", + "0x482480017ffa8000", + "0x213e", "0x480680017fff8000", "0x0", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4f7574206f6620676173", "0x400080007ffe7fff", - "0x4825800180007ffd", - "0x9", - "0x48127ffc7fff8000", - "0x482480017ffc8000", + "0x482680017ff88000", "0x1", - "0x20680017fff7ffd", - "0x7", + "0x480a7ff97fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0x48297ffa80007ffb", + "0x480680017fff8000", + "0x11", + "0x480280007ff88004", + "0x4824800180037fff", + "0x1", + "0x48307ffe7fff7ffd", + "0x480280017ff87ffe", + "0x480280027ff87fff", + "0x40507ffe7ffa7ffd", + "0x40307fff7ffd7ff9", + "0x482680017ff88000", + "0x3", + "0x20780017fff7ffd", + "0xb", "0x40780017fff7fff", "0x19", - "0x48127fe57fff8000", - "0x48127fe57fff8000", - "0x208b7fff7fff7ffe", + "0x48127fe67fff8000", + "0x482680017ff98000", + "0x1022", "0x480680017fff8000", - "0x0", - "0x400080007ffe7fff", + "0x1", + "0x10780017fff7fff", + "0x9d", + "0x480a7ff97fff8000", "0x4825800180007ffd", - "0xa", - "0x48127ffc7fff8000", - "0x482480017ffc8000", "0x1", - "0x20680017fff7ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x67", + "0x48127ffe7fff8000", + "0x4825800180007ffd", + "0x2", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x58", + "0x48127ffe7fff8000", + "0x4825800180007ffd", + "0x3", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x49", + "0x48127ffe7fff8000", + "0x4825800180007ffd", + "0x4", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x3a", + "0x48127ffe7fff8000", + "0x4825800180007ffd", + "0x5", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x2b", + "0x48127ffe7fff8000", + "0x4825800180007ffd", + "0x6", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x1c", + "0x48127ffe7fff8000", + "0x4825800180007ffd", "0x7", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x10", "0x40780017fff7fff", - "0x15", - "0x48127fe97fff8000", - "0x48127fe97fff8000", - "0x208b7fff7fff7ffe", + "0x1", "0x480680017fff8000", - "0x0", + "0x4b656363616b206c61737420696e70757420776f7264203e3762", "0x400080007ffe7fff", - "0x4825800180007ffd", - "0xb", - "0x48127ffc7fff8000", - "0x482480017ffc8000", + "0x48127fef7fff8000", + "0x482480017ffb8000", + "0x139c", + "0x480680017fff8000", "0x1", - "0x20680017fff7ffd", - "0x7", + "0x48127ffb7fff8000", + "0x482480017ffa8000", + "0x1", + "0x208b7fff7fff7ffe", + "0x48127ffe7fff8000", + "0x480680017fff8000", + "0x100000000000000", + "0x10780017fff7fff", + "0x8", "0x40780017fff7fff", - "0x11", - "0x48127fed7fff8000", + "0x2", + "0x482480017ffc8000", + "0x118", + "0x480680017fff8000", + "0x1000000000000", + "0x10780017fff7fff", + "0x8", + "0x40780017fff7fff", + "0x4", + "0x482480017ffa8000", + "0x294", + "0x480680017fff8000", + "0x10000000000", + "0x10780017fff7fff", + "0x8", + "0x40780017fff7fff", + "0x6", + "0x482480017ff88000", + "0x410", + "0x480680017fff8000", + "0x100000000", + "0x10780017fff7fff", + "0x8", + "0x40780017fff7fff", + "0x8", + "0x482480017ff68000", + "0x58c", + "0x480680017fff8000", + "0x1000000", + "0x10780017fff7fff", + "0x8", + "0x40780017fff7fff", + "0xa", + "0x482480017ff48000", + "0x708", + "0x480680017fff8000", + "0x10000", + "0x10780017fff7fff", + "0x8", + "0x40780017fff7fff", + "0xc", + "0x482480017ff28000", + "0x884", + "0x480680017fff8000", + "0x100", + "0x20680017fff7fff", + "0x10", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x400080007ffe7fff", "0x48127fed7fff8000", + "0x482480017ffb8000", + "0xfb4", + "0x480680017fff8000", + "0x1", + "0x48127ffb7fff8000", + "0x482480017ffa8000", + "0x1", "0x208b7fff7fff7ffe", + "0x480080007fef8004", + "0x4824800180037fff", + "0x1", + "0x48307ffe7fff7ffd", + "0x480080017fec7ffe", + "0x480080027feb7fff", + "0x40507ffe7ffa7ffd", + "0x40317fff7ffd7ffc", + "0x48127ff97fff8000", + "0xa0680017fff8000", + "0x8", + "0x48307ffd7ff88000", + "0x4824800180007fff", + "0x10000000000000000", + "0x400080037fe67fff", + "0x10780017fff7fff", + "0x61", + "0x48307ffd7ff88001", + "0x4824800180007fff", + "0xffffffffffffffff0000000000000000", + "0x400080037fe67ffe", + "0x482480017fe68000", + "0x4", + "0x48127ffb7fff8000", + "0x48127ffd7fff8000", + "0x4824800180007fe2", + "0x10", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x2a", + "0x400280007ffb7ffe", "0x480680017fff8000", - "0x0", - "0x400080007ffe7fff", - "0x4825800180007ffd", - "0xc", + "0x10", "0x48127ffc7fff8000", - "0x482480017ffc8000", + "0x480a7ffa7fff8000", + "0x482680017ffb8000", "0x1", - "0x20680017fff7ffd", + "0x48307fdd80017ffc", + "0xa0680017fff7fff", "0x7", - "0x40780017fff7fff", - "0xd", - "0x48127ff17fff8000", - "0x48127ff17fff8000", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400080007ff57fff", + "0x10780017fff7fff", + "0xc", + "0x400080007ff67fff", + "0x482480017ff68000", + "0x1", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x48127ffb7fff8000", + "0x1104800180018000", + "0xdc6", "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", + "0x7533325f737562204f766572666c6f77", "0x400080007ffe7fff", - "0x4825800180007ffd", - "0xd", - "0x48127ffc7fff8000", - "0x482480017ffc8000", + "0x482480017ff38000", + "0x1", + "0x482480017ff78000", + "0x3ca", + "0x480680017fff8000", + "0x1", + "0x48127ffb7fff8000", + "0x482480017ffa8000", "0x1", - "0x20680017fff7ffd", - "0x7", - "0x40780017fff7fff", - "0x9", - "0x48127ff57fff8000", - "0x48127ff57fff8000", "0x208b7fff7fff7ffe", "0x480680017fff8000", - "0x0", - "0x400080007ffe7fff", - "0x4825800180007ffd", - "0xe", - "0x48127ffc7fff8000", + "0x8000000000000000", "0x482480017ffc8000", + "0x492", + "0xa0680017fff8000", + "0x8", + "0x48307ffb7ffd8000", + "0x4824800180007fff", + "0x10000000000000000", + "0x400080007ff77fff", + "0x10780017fff7fff", + "0x11", + "0x48307ffb7ffd8001", + "0x4824800180007fff", + "0xffffffffffffffff0000000000000000", + "0x400080007ff77ffe", + "0x400280007ffb7fff", + "0x482480017ff78000", "0x1", - "0x20680017fff7ffd", - "0x7", - "0x40780017fff7fff", - "0x5", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x208b7fff7fff7ffe", + "0x482480017ffb8000", + "0x12c", "0x480680017fff8000", "0x0", - "0x400080007ffe7fff", - "0x4825800180007ffd", - "0xf", - "0x48127ffc7fff8000", - "0x482480017ffc8000", + "0x480a7ffa7fff8000", + "0x482680017ffb8000", "0x1", - "0x20680017fff7ffd", - "0x7", + "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1", - "0x48127ffd7fff8000", - "0x48127ffd7fff8000", + "0x480680017fff8000", + "0x7536345f616464204f766572666c6f77", + "0x400080007ffe7fff", + "0x482480017ff58000", + "0x1", + "0x48127ff97fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffb7fff8000", + "0x482480017ffa8000", + "0x1", "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x0", + "0x7536345f616464204f766572666c6f77", "0x400080007ffe7fff", - "0x48127ffd7fff8000", - "0x482480017ffd8000", + "0x482480017fe48000", + "0x4", + "0x482480017ff98000", + "0x988", + "0x480680017fff8000", + "0x1", + "0x48127ffb7fff8000", + "0x482480017ffa8000", "0x1", "0x208b7fff7fff7ffe", + "0x48297ffa80007ffb", + "0x20780017fff7ffd", + "0xd", + "0x40780017fff7fff", + "0xf", "0x480680017fff8000", - "0x536563703235366b31476574506f696e7446726f6d58", - "0x400280007ff67fff", - "0x400380017ff67ff5", - "0x400380027ff67ff9", - "0x400380037ff67ffa", - "0x400380047ff67ffd", - "0x480280067ff68000", + "0x80000000", + "0x400280007ffb7fff", + "0x480a7ff97fff8000", + "0x480a7ffa7fff8000", + "0x482680017ffb8000", + "0x1", + "0x10780017fff7fff", + "0x4b", + "0x4825800180007ffd", + "0x1", "0x20680017fff7fff", - "0x46c", - "0x480280077ff68000", - "0x480280087ff68000", - "0x480280057ff68000", - "0x482680017ff68000", - "0x9", - "0x20680017fff7ffc", - "0x459", - "0x480680017fff8000", - "0x29bfcdb2dce28d959f2815b16f81798", + "0x4", + "0x10780017fff7fff", + "0x18", + "0x4825800180007ffd", + "0x2", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xa", "0x480680017fff8000", - "0x79be667ef9dcbbac55a06295ce870b07", + "0x1000000", "0x480680017fff8000", - "0xfd17b448a68554199c47d08ffb10d4b8", + "0x100", "0x480680017fff8000", - "0x483ada7726a3c4655da4fbfc0e1108a8", + "0x80", + "0x10780017fff7fff", + "0x8", "0x480680017fff8000", - "0x536563703235366b314e6577", - "0x400080007ffa7fff", - "0x400080017ffa7ff9", - "0x400080027ffa7ffb", - "0x400080037ffa7ffc", - "0x400080047ffa7ffd", - "0x400080057ffa7ffe", - "0x480080077ffa8000", - "0x20680017fff7fff", - "0x437", - "0x480080087ff98000", - "0x480080097ff88000", - "0x480080067ff78000", - "0x482480017ff68000", - "0xa", - "0x20680017fff7ffc", - "0x422", + "0x10000", "0x480680017fff8000", - "0xbaaedce6af48a03bbfd25e8cd0364141", + "0x10000", "0x480680017fff8000", - "0xfffffffffffffffffffffffffffffffe", - "0xa0680017fff8000", - "0x37", - "0x480280007ff48001", - "0x480280017ff48001", - "0x480280027ff48001", - "0x480280037ff48001", - "0x48307ffe80017ffa", + "0x8000", + "0x10780017fff7fff", + "0xa", "0x40780017fff7fff", - "0x12", - "0x20680017fff7fee", - "0x8", - "0x40307fea7fef7fe6", - "0x402480017ff07fef", "0x1", - "0x400280047ff47ff0", + "0x480680017fff8000", + "0x100", + "0x480680017fff8000", + "0x1000000", + "0x480680017fff8000", + "0x800000", + "0x480280007ff98004", + "0x4824800180037fff", + "0x1", + "0x48307ffe7fff7ffb", + "0x480280017ff97ffe", + "0x480280027ff97fff", + "0x40507ffe7ff87ffd", + "0x40317fff7ffd7ffc", + "0x48507ff97fff8000", + "0xa0680017fff8000", + "0x7", + "0x4824800180007ffe", + "0x100000000", + "0x400280037ff97fff", "0x10780017fff7fff", - "0x3", - "0x400280047ff47fee", - "0x482480017ff98001", + "0xaf", + "0x482480017ffe8000", + "0xffffffffffffffffffffffff00000000", + "0x400280037ff97fff", + "0xa0680017fff8000", + "0x8", + "0x48307ff67ffc8000", + "0x4824800180007fff", + "0x100000000", + "0x400280047ff97fff", + "0x10780017fff7fff", + "0x95", + "0x48307ff67ffc8001", + "0x4824800180007fff", + "0xffffffffffffffffffffffff00000000", + "0x400280047ff97ffe", + "0x400280007ffb7fff", + "0x482680017ff98000", + "0x5", + "0x480a7ffa7fff8000", + "0x482680017ffb8000", "0x1", - "0x48307ff080018000", - "0x4844800180018000", - "0x100000000000000000000000000000000", - "0x4850800080008000", - "0x48307fff7ff68000", - "0x48307ff67fff8000", - "0x48307ff77fff8000", - "0x48307feb80007fff", - "0x48307feb80007fff", - "0x48307fec80007fff", - "0x4844800180007fff", - "0x100000000000000000000000000000000", + "0x48307ffe80007fff", + "0x480680017fff8000", + "0x1", + "0xa0680017fff8000", + "0x8", + "0x48307ffe7ffd8000", "0x4824800180007fff", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffff8001", - "0x400280057ff47fff", - "0x482480017ffe8000", - "0xffffffffffffffffffffffffffff8000", - "0x400280067ff47fff", - "0x48307ffd7fef8000", - "0x48307ff07fff8000", - "0x48307ff07fff8000", - "0x48307fe680007fff", - "0x48307fe380007fff", - "0x48307fe580007fff", - "0x4844800180007fff", - "0x100000000000000000000000000000000", + "0x100000000", + "0x400080007ff87fff", + "0x10780017fff7fff", + "0x71", + "0x48307ffe7ffd8001", "0x4824800180007fff", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffff8001", - "0x400280077ff47fff", + "0xffffffffffffffffffffffff00000000", + "0x400080007ff87ffe", + "0x480680017fff8000", + "0x10", + "0x480080017ff78004", + "0x4824800180037fff", + "0x1", + "0x48307ffe7fff7ffd", + "0x480080027ff47ffe", + "0x480080037ff37fff", + "0x40507ffe7ffa7ffd", + "0x40307fff7ffd7ff9", + "0x480680017fff8000", + "0x10", + "0x48127ff27fff8000", + "0x48127ff27fff8000", + "0x48307ffc80007ffd", + "0x1104800180018000", + "0xd5e", + "0x484480017f9c8000", + "0x20", + "0xa0680017fff8000", + "0x7", + "0x4824800180007ffe", + "0x100000000", + "0x400080047faa7fff", + "0x10780017fff7fff", + "0x44", "0x482480017ffe8000", - "0xffffffffffffffffffffffffffff8000", - "0x400280087ff47fff", - "0x40307ffd7fea7fe2", + "0xffffffffffffffffffffffff00000000", + "0x400080047faa7fff", + "0x484680017ffd8000", + "0x8", + "0xa0680017fff8000", + "0x7", + "0x4824800180007ffe", + "0x100000000", + "0x400080057fa77fff", "0x10780017fff7fff", - "0x31", - "0x480280007ff47fff", - "0x480280017ff47fff", - "0x480280027ff47fff", - "0x480280037ff47fff", - "0x480280047ff47fff", - "0x400280057ff47fff", - "0xa0680017fff7ffb", - "0xa", - "0x402480017fff7ff9", + "0x29", + "0x482480017ffe8000", + "0xffffffffffffffffffffffff00000000", + "0x400080057fa77fff", + "0xa0680017fff8000", + "0x8", + "0x48307ffc7ff98000", + "0x4824800180007fff", + "0x100000000", + "0x400080067fa47fff", + "0x10780017fff7fff", + "0x11", + "0x48307ffc7ff98001", + "0x4824800180007fff", + "0xffffffffffffffffffffffff00000000", + "0x400080067fa47ffe", + "0x40780017fff7fff", + "0x2", + "0x400080007ff47ffd", + "0x482480017fa28000", + "0x7", + "0x480680017fff8000", + "0x0", + "0x48127ff17fff8000", + "0x482480017ff18000", "0x1", - "0x20680017fff7fff", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x7533325f616464204f766572666c6f77", + "0x400080007ffe7fff", + "0x482480017fa28000", + "0x7", + "0x480680017fff8000", + "0x1", + "0x48127ffc7fff8000", + "0x482480017ffb8000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x3", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x7533325f6d756c204f766572666c6f77", + "0x400080007ffe7fff", + "0x482480017fa28000", "0x6", - "0x400680017fff7ff8", - "0x0", - "0x400680017fff7ff7", + "0x480680017fff8000", "0x1", - "0xa0680017fff7ffa", - "0xc", - "0x48507ff87ffb8001", - "0x48507ff77ffc8001", - "0xa0680017fff8002", + "0x48127ffc7fff8000", + "0x482480017ffb8000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x6", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x7533325f6d756c204f766572666c6f77", + "0x400080007ffe7fff", + "0x482480017fa28000", "0x5", - "0x48307ffa7ff88000", - "0x90780017fff7fff", - "0x11", + "0x480680017fff8000", + "0x1", + "0x48127ffc7fff8000", + "0x482480017ffb8000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x54", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x7533325f616464204f766572666c6f77", + "0x400080007ffe7fff", + "0x482480017fa28000", + "0x1", + "0x480680017fff8000", + "0x1", + "0x48127ffc7fff8000", + "0x482480017ffb8000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x5c", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x7533325f616464204f766572666c6f77", + "0x400080007ffe7fff", + "0x482680017ff98000", + "0x5", + "0x480680017fff8000", + "0x1", + "0x48127ffc7fff8000", + "0x482480017ffb8000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x5f", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x7533325f6d756c204f766572666c6f77", + "0x400080007ffe7fff", + "0x482680017ff98000", + "0x4", + "0x480680017fff8000", + "0x1", + "0x48127ffc7fff8000", + "0x482480017ffb8000", + "0x1", + "0x208b7fff7fff7ffe", + "0xa0680017fff8000", + "0x7", + "0x482680017ff98000", + "0xffffffffffffffffffffffffffffcb80", + "0x400280007ff87fff", + "0x10780017fff7fff", + "0x53", + "0x4825800180007ff9", + "0x3480", + "0x400280007ff87fff", + "0x48127fff7fff8000", + "0xa0680017fff8000", + "0x8", + "0x48297ffc80007ffb", + "0x482480017fff8000", + "0xf", + "0x400280017ff87fff", + "0x10780017fff7fff", + "0x10", + "0x482680017ffb8001", + "0x10", + "0x483180007fff7ffc", + "0x400280017ff87ffe", + "0x482680017ff88000", + "0x2", + "0x48127ffb7fff8000", + "0x48127ffd7fff8000", + "0x480a7ffc7fff8000", + "0x480680017fff8000", + "0x0", + "0x480a7ffb7fff8000", + "0x10780017fff7fff", + "0xb", + "0x482680017ff88000", + "0x2", + "0x48127ffb7fff8000", + "0x480a7ffb7fff8000", + "0x480a7ffc7fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x20680017fff7ffe", + "0x24", + "0x48127ffb7fff8000", + "0x480680017fff8000", + "0x53686132353650726f63657373426c6f636b", + "0x400280007ffa7fff", + "0x400280017ffa7ffe", + "0x400380027ffa7ffd", + "0x400280037ffa7ffd", + "0x480280057ffa8000", + "0x20680017fff7fff", + "0xd", + "0x480280047ffa8000", + "0x48127ff67fff8000", + "0x48127ffe7fff8000", + "0x482680017ffa8000", + "0x7", "0x48127ff57fff8000", - "0x90780017fff7fff", - "0xe", - "0x48507ff97ffa8001", - "0x48507ff87ffb8001", - "0x480680017fff7ff9", + "0x48127ff57fff8000", + "0x480280067ffa8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffc3", + "0x208b7fff7fff7ffe", + "0x480280047ffa8000", + "0x48127ff67fff8000", + "0x482480017ffe8000", + "0x622", + "0x482680017ffa8000", + "0x8", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", "0x0", - "0x480680017fff7ffa", + "0x480280067ffa8000", + "0x480280077ffa8000", + "0x208b7fff7fff7ffe", + "0x48127ffa7fff8000", + "0x482480017ffa8000", + "0x30b6", + "0x480a7ffa7fff8000", + "0x480680017fff8000", "0x0", - "0xa0680017fff8000", - "0x5", - "0x40307ff77ff57ffe", + "0x48127ff87fff8000", + "0x48127ff87fff8000", + "0x480a7ffd7fff8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x482680017ff88000", + "0x1", + "0x480a7ff97fff8000", + "0x480a7ffa7fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0x20780017fff7ff8", + "0x16", + "0x480a7ff37fff8000", + "0x20780017fff7ff9", + "0x10", + "0x1104800180018000", + "0x15f6", + "0x482480017fff8000", + "0x15f5", + "0x480080007fff8000", + "0x480080017fff8000", + "0x484480017fff8000", + "0x8", + "0x482480017fff8000", + "0x3508e", + "0x480a7ff27fff8000", + "0x48307ffe7ff78000", "0x10780017fff7fff", - "0x3", - "0x40127ff47fff7ffe", - "0x482480017ffe8000", - "0xfffffffffffffffe0000000000000000", - "0x400280067ff47fff", - "0x40317ff97ffb7ffa", - "0x40307ffa7ffc7ff1", + "0x42", + "0x48127fff7fff8000", "0x10780017fff7fff", - "0x36b", - "0x4824800180008002", - "0xffffffffffffffff0000000000000000", - "0x480280097ff48001", - "0x4802800a7ff47ffe", - "0x4002800b7ff47ffe", - "0x484480017ffe8000", - "0x10000000000000000", - "0x40307ffc7fff7fcd", - "0x48507fd37ffc8000", - "0x48507fd27ffc8000", - "0x4824800180018002", - "0xffffffffffffffff0000000000000000", - "0x4802800c7ff48001", - "0x4802800d7ff47fff", - "0x4002800e7ff47ffd", - "0x484480017ffd8000", - "0x10000000000000000", - "0x40307ffd7fff7ffb", - "0x484480017ffd8000", - "0x10000000000000000", - "0x48307fff7ff98003", + "0x4", + "0x482680017ff38000", + "0x12c", + "0x480680017fff8000", + "0xfffffffffffffffffffffffffffffffe", + "0x48317fff80017ff9", + "0xa0680017fff7fff", + "0x7", "0x482480017fff8000", - "0xfffffffffffffffe0000000000000000", - "0x4802800f7ff47fff", - "0x480280107ff47ffd", - "0x400280117ff47fda", - "0x404480017ffc7ffe", "0x100000000000000000000000000000000", - "0x40307fda7ffe7fff", - "0x40307ffc7ff77fdb", - "0x4824800180008002", - "0xffffffffffffffff0000000000000000", - "0x480280127ff48001", - "0x480280137ff47ffe", - "0x400280147ff47ffe", - "0x484480017ffe8000", - "0x10000000000000000", - "0x40307ffc7fff7fbe", - "0x48507fc37ffc8000", - "0x48507fc27ffc8000", - "0x4824800180018002", - "0xffffffffffffffff0000000000000000", - "0x480280157ff48001", - "0x480280167ff47fff", - "0x400280177ff47ffd", - "0x484480017ffd8000", - "0x10000000000000000", - "0x40307ffd7fff7ffb", - "0x484480017ffd8000", - "0x10000000000000000", - "0x48307fff7ff98003", + "0x400280007ff27fff", + "0x10780017fff7fff", + "0x41", + "0x400280007ff27fff", + "0x482680017ff28000", + "0x1", + "0x48127ffb7fff8000", + "0x4825800180007ff9", + "0xfffffffffffffffffffffffffffffffe", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x10", + "0x1104800180018000", + "0x15cf", "0x482480017fff8000", - "0xfffffffffffffffe0000000000000000", - "0x480280187ff47fff", - "0x480280197ff47ffd", - "0x4002801a7ff47fc9", - "0x404480017ffc7ffe", - "0x100000000000000000000000000000000", - "0x40307fc97ffe7fff", - "0x40307ffc7ff77fca", - "0x4824800180008002", - "0xffffffffffffffff0000000000000000", - "0x4802801b7ff48001", - "0x4802801c7ff47ffe", - "0x4002801d7ff47ffe", - "0x484480017ffe8000", - "0x10000000000000000", - "0x40307ffc7fff7fae", - "0x48507fb57ffc8000", - "0x48507fb47ffc8000", - "0x4824800180018002", - "0xffffffffffffffff0000000000000000", - "0x4802801e7ff48001", - "0x4802801f7ff47fff", - "0x400280207ff47ffd", - "0x484480017ffd8000", - "0x10000000000000000", - "0x40307ffd7fff7ffb", - "0x484480017ffd8000", - "0x10000000000000000", - "0x48307fff7ff98003", + "0x15ce", + "0x480080007fff8000", + "0x480080017fff8000", + "0x484480017fff8000", + "0x8", + "0x482480017fff8000", + "0x34c60", + "0x48127ff67fff8000", + "0x48307ffe7ff68000", + "0x10780017fff7fff", + "0x1b", + "0x480680017fff8000", + "0xbaaedce6af48a03bbfd25e8cd0364141", + "0x48127ffd7fff8000", + "0x48317ffe80017ff8", + "0xa0680017fff7fff", + "0x7", "0x482480017fff8000", - "0xfffffffffffffffe0000000000000000", - "0x480280217ff47fff", - "0x480280227ff47ffd", - "0x400280237ff47fb8", - "0x404480017ffc7ffe", "0x100000000000000000000000000000000", - "0x40307fb87ffe7fff", - "0x40307ffc7ff77fb9", - "0x4824800180008002", - "0xffffffffffffffff0000000000000000", - "0x480280247ff48001", - "0x480280257ff47ffe", - "0x400280267ff47ffe", - "0x484480017ffe8000", - "0x10000000000000000", - "0x40307ffc7fff7f9f", - "0x48507fa57ffc8000", - "0x48507fa47ffc8000", - "0x4824800180018002", - "0xffffffffffffffff0000000000000000", - "0x480280277ff48001", - "0x480280287ff47fff", - "0x400280297ff47ffd", - "0x484480017ffd8000", - "0x10000000000000000", - "0x40307ffd7fff7ffb", - "0x484480017ffd8000", - "0x10000000000000000", - "0x48307fff7ff98003", + "0x400080007ff87fff", + "0x10780017fff7fff", + "0x19", + "0x400080007ff97fff", + "0x1104800180018000", + "0x15b5", + "0x482480017fff8000", + "0x15b4", + "0x480080007fff8000", + "0x480080017fff8000", + "0x484480017fff8000", + "0x8", + "0x482480017fff8000", + "0x34a26", + "0x482480017ff28000", + "0x1", + "0x48307ffe7ff58000", + "0x480a7ff47fff8000", + "0x480a7ff57fff8000", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x5369676e6174757265206f7574206f662072616e6765", + "0x208b7fff7fff7ffe", + "0x482480017ff88000", + "0x1", + "0x48127ffb7fff8000", + "0x10780017fff7fff", + "0x6", + "0x482680017ff28000", + "0x1", + "0x482480017ffa8000", + "0x492", + "0x20780017fff7ffa", + "0x16", + "0x48127fff7fff8000", + "0x20780017fff7ffb", + "0x10", + "0x1104800180018000", + "0x1591", + "0x482480017fff8000", + "0x1590", + "0x480080007fff8000", + "0x480080017fff8000", + "0x484480017fff8000", + "0x8", + "0x482480017fff8000", + "0x346a2", + "0x48127ff67fff8000", + "0x48307ffe7ff78000", + "0x10780017fff7fff", + "0x44", + "0x48127fff7fff8000", + "0x10780017fff7fff", + "0x6", + "0x40780017fff7fff", + "0x1", + "0x482480017ffe8000", + "0xbe", + "0x480680017fff8000", + "0xfffffffffffffffffffffffffffffffe", + "0x48317fff80017ffb", + "0xa0680017fff7fff", + "0x7", "0x482480017fff8000", - "0xfffffffffffffffe0000000000000000", - "0x4802802a7ff47fff", - "0x4802802b7ff47ffd", - "0x4002802c7ff47fa7", - "0x404480017ffc7ffe", "0x100000000000000000000000000000000", - "0x40307fa77ffe7fff", - "0x40307ffc7ff77fa8", + "0x400080007ff87fff", + "0x10780017fff7fff", + "0x41", + "0x400080007ff97fff", + "0x482480017ff98000", + "0x1", + "0x48127ffb7fff8000", + "0x4825800180007ffb", + "0xfffffffffffffffffffffffffffffffe", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x10", + "0x1104800180018000", + "0x1568", + "0x482480017fff8000", + "0x1567", + "0x480080007fff8000", + "0x480080017fff8000", + "0x484480017fff8000", + "0x8", + "0x482480017fff8000", + "0x34274", + "0x48127ff67fff8000", + "0x48307ffe7ff68000", + "0x10780017fff7fff", + "0x1b", + "0x480680017fff8000", + "0xbaaedce6af48a03bbfd25e8cd0364141", + "0x48127ffd7fff8000", + "0x48317ffe80017ffa", + "0xa0680017fff7fff", + "0x7", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400080007ff87fff", + "0x10780017fff7fff", + "0x19", + "0x400080007ff97fff", + "0x1104800180018000", + "0x154e", + "0x482480017fff8000", + "0x154d", + "0x480080007fff8000", + "0x480080017fff8000", + "0x484480017fff8000", + "0x8", + "0x482480017fff8000", + "0x3403a", + "0x482480017ff28000", + "0x1", + "0x48307ffe7ff58000", + "0x480a7ff47fff8000", + "0x480a7ff57fff8000", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x5369676e6174757265206f7574206f662072616e6765", + "0x208b7fff7fff7ffe", + "0x482480017ff88000", + "0x1", + "0x48127ffb7fff8000", + "0x10780017fff7fff", + "0x6", + "0x482480017ff88000", + "0x1", + "0x482480017ffa8000", + "0x492", + "0x480a7ff57fff8000", + "0x480a7ff67fff8000", + "0x480a7ff77fff8000", + "0x480a7ff87fff8000", + "0x480a7ff97fff8000", + "0x480a7ffa7fff8000", + "0x480a7ffb7fff8000", + "0x480a7ffc7fff8000", + "0x1104800180018000", + "0xc87", + "0x20680017fff7ffd", + "0x4b", + "0x48127ffb7fff8000", + "0x20680017fff7ffd", + "0x2f", + "0x48127ff97fff8000", + "0x48127ffe7fff8000", + "0x480a7ff47fff8000", + "0x48127ff87fff8000", + "0x48127ffa7fff8000", + "0x1104800180018000", + "0x111a", + "0x20680017fff7ffd", + "0x1c", + "0x48317fff80007ffd", + "0x48127ff97fff8000", + "0x20680017fff7ffe", + "0xd", + "0x48127ff77fff8000", + "0x48127ffe7fff8000", + "0x48127ff77fff8000", + "0x48127ff77fff8000", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x208b7fff7fff7ffe", + "0x48127ff77fff8000", + "0x48127ffe7fff8000", + "0x48127ff77fff8000", + "0x48127ff77fff8000", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x496e76616c6964207369676e6174757265", + "0x208b7fff7fff7ffe", + "0x48127ff97fff8000", + "0x482480017ff98000", + "0x12c", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x208b7fff7fff7ffe", + "0x1104800180018000", + "0x14f3", + "0x482480017fff8000", + "0x14f2", + "0x480080007fff8000", + "0x480080017fff8000", + "0x484480017fff8000", + "0x8", + "0x482480017fff8000", + "0xab68", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x400080007ffe7fff", + "0x48127ff07fff8000", + "0x48307ffc7ff58000", + "0x480a7ff47fff8000", + "0x48127fef7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0x1104800180018000", + "0x14da", + "0x482480017fff8000", + "0x14d9", + "0x480080007fff8000", + "0x480080017fff8000", + "0x484480017fff8000", + "0x8", + "0x482480017fff8000", + "0xad5c", + "0x48127ff37fff8000", + "0x48307ffe7ff38000", + "0x480a7ff47fff8000", + "0x48127ff27fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ff27fff8000", + "0x48127ff27fff8000", + "0x208b7fff7fff7ffe", + "0x20780017fff7ff9", + "0xf", + "0x480a7ff57fff8000", + "0x20780017fff7ffa", + "0x9", + "0x40780017fff7fff", + "0x2ce", + "0x480a7ff47fff8000", + "0x482480017d308000", + "0x2783a", + "0x10780017fff7fff", + "0x36", + "0x48127fff7fff8000", + "0x10780017fff7fff", + "0x6", + "0x40780017fff7fff", + "0x1", + "0x482680017ff58000", + "0xbe", + "0x480680017fff8000", + "0xffffffff00000000ffffffffffffffff", + "0x48317fff80017ffa", + "0xa0680017fff7fff", + "0x7", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400280007ff47fff", + "0x10780017fff7fff", + "0x2c", + "0x400280007ff47fff", + "0x482680017ff48000", + "0x1", + "0x48127ffb7fff8000", + "0x4825800180007ffa", + "0xffffffff00000000ffffffffffffffff", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x9", + "0x40780017fff7fff", + "0x2c7", + "0x48127d367fff8000", + "0x482480017d368000", + "0x27452", + "0x10780017fff7fff", + "0x14", + "0x480680017fff8000", + "0xbce6faada7179e84f3b9cac2fc632551", + "0x48127ffd7fff8000", + "0x48317ffe80017ff9", + "0xa0680017fff7fff", + "0x7", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400080007ff87fff", + "0x10780017fff7fff", + "0xb", + "0x400080007ff97fff", + "0x40780017fff7fff", + "0x2c3", + "0x482480017d368000", + "0x1", + "0x482480017d398000", + "0x27240", + "0x10780017fff7fff", + "0x4ba", + "0x482480017ff88000", + "0x1", + "0x48127ffb7fff8000", + "0x10780017fff7fff", + "0x8", + "0x40780017fff7fff", + "0x7", + "0x482680017ff48000", + "0x1", + "0x482480017ff38000", + "0x3e8", + "0x20780017fff7ffb", + "0x11", + "0x48127fff7fff8000", + "0x20780017fff7ffc", + "0xb", + "0x40780017fff7fff", + "0xc", + "0x48127ff17fff8000", + "0x482480017ff28000", + "0x6b8", + "0x480680017fff8000", + "0x0", + "0x10780017fff7fff", + "0x4b", + "0x48127fff7fff8000", + "0x10780017fff7fff", + "0x6", + "0x40780017fff7fff", + "0x1", + "0x482480017ffe8000", + "0xbe", + "0x480680017fff8000", + "0xffffffff00000000ffffffffffffffff", + "0x48317fff80017ffc", + "0xa0680017fff7fff", + "0x7", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400080007ff87fff", + "0x10780017fff7fff", + "0x32", + "0x400080007ff97fff", + "0x482480017ff98000", + "0x1", + "0x48127ffb7fff8000", + "0x4825800180007ffc", + "0xffffffff00000000ffffffffffffffff", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xb", + "0x40780017fff7fff", + "0x5", + "0x48127ff87fff8000", + "0x482480017ff88000", + "0x2d0", + "0x480680017fff8000", + "0x0", + "0x10780017fff7fff", + "0x27", + "0x480680017fff8000", + "0xbce6faada7179e84f3b9cac2fc632551", + "0x48127ffd7fff8000", + "0x48317ffe80017ffb", + "0xa0680017fff7fff", + "0x7", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400080007ff87fff", + "0x10780017fff7fff", + "0xd", + "0x400080007ff97fff", + "0x40780017fff7fff", + "0x1", + "0x482480017ff88000", + "0x1", + "0x482480017ffb8000", + "0x5a", + "0x480680017fff8000", + "0x0", + "0x10780017fff7fff", + "0x11", + "0x482480017ff88000", + "0x1", + "0x48127ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x10780017fff7fff", + "0xa", + "0x40780017fff7fff", + "0x7", + "0x482480017ff18000", + "0x1", + "0x482480017ff38000", + "0x3e8", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x1", + "0x48307ffe80007fff", + "0x20680017fff7fff", + "0x44e", + "0x480680017fff8000", + "0xbce6faada7179e84f3b9cac2fc632551", + "0x480680017fff8000", + "0xffffffff00000000ffffffffffffffff", + "0x48127ffa7fff8000", + "0xa0680017fff8000", + "0x37", + "0x480080007ff78001", + "0x480080017ff68001", + "0x480080027ff58001", + "0x480080037ff48001", + "0x48307ffe80017ff9", + "0x40780017fff7fff", + "0x12", + "0x20680017fff7fee", + "0x8", + "0x40307fea7fef7fe5", + "0x402480017ff07fef", + "0x1", + "0x400080047fe07ff0", + "0x10780017fff7fff", + "0x3", + "0x400080047fe07fee", + "0x482480017ff98001", + "0x1", + "0x48307ff080018000", + "0x4844800180018000", + "0x100000000000000000000000000000000", + "0x4850800080008000", + "0x48307fff7ff68000", + "0x48307ff67fff8000", + "0x48307ff77fff8000", + "0x48307feb80007fff", + "0x48307feb80007fff", + "0x48307fec80007fff", + "0x4844800180007fff", + "0x100000000000000000000000000000000", + "0x4824800180007fff", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffff8001", + "0x400080057fd47fff", + "0x482480017ffe8000", + "0xffffffffffffffffffffffffffff8000", + "0x400080067fd37fff", + "0x48307ffd7fef8000", + "0x48307ff07fff8000", + "0x48307ff07fff8000", + "0x48307fe680007fff", + "0x48307fe380007fff", + "0x48307fe580007fff", + "0x4844800180007fff", + "0x100000000000000000000000000000000", + "0x4824800180007fff", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffff8001", + "0x400080077fcb7fff", + "0x482480017ffe8000", + "0xffffffffffffffffffffffffffff8000", + "0x400080087fca7fff", + "0x40307ffd7fea7fe2", + "0x10780017fff7fff", + "0x31", + "0x480080007ff77fff", + "0x480080017ff67fff", + "0x480080027ff57fff", + "0x480080037ff47fff", + "0x480080047ff37fff", + "0x400080057ff27fff", + "0xa0680017fff7ffb", + "0xa", + "0x402480017fff7ff9", + "0x1", + "0x20680017fff7fff", + "0x6", + "0x400680017fff7ff7", + "0x0", + "0x400680017fff7ff6", + "0x1", + "0xa0680017fff7ffa", + "0xc", + "0x48507ff87ffb8001", + "0x48507ff77ffc8001", + "0xa0680017fff8002", + "0x5", + "0x48307ffa7ff88000", + "0x90780017fff7fff", + "0x11", + "0x48127ff57fff8000", + "0x90780017fff7fff", + "0xe", + "0x48507ff97ffa8001", + "0x48507ff87ffb8001", + "0x480680017fff7ff9", + "0x0", + "0x480680017fff7ffa", + "0x0", + "0xa0680017fff8000", + "0x5", + "0x40307ff77ff57ffe", + "0x10780017fff7fff", + "0x3", + "0x40127ff47fff7ffe", + "0x482480017ffe8000", + "0xfffffffffffffffe0000000000000000", + "0x400080067fea7fff", + "0x40317ff97ffb7ffc", + "0x40307ffa7ffc7ff0", + "0x10780017fff7fff", + "0x395", "0x4824800180008002", "0xffffffffffffffff0000000000000000", - "0x4802802d7ff48001", - "0x4802802e7ff47ffe", - "0x4002802f7ff47ffe", + "0x480080097fc98001", + "0x4800800a7fc87ffe", + "0x4000800b7fc77ffe", "0x484480017ffe8000", "0x10000000000000000", - "0x40307ffc7fff7f95", - "0x48487ffa7ffc8000", - "0x48487ffa7ffc8000", + "0x40307ffc7fff7fcc", + "0x48507fd37ffc8000", + "0x48507fd27ffc8000", "0x4824800180018002", "0xffffffffffffffff0000000000000000", - "0x480280307ff48001", - "0x480280317ff47fff", - "0x400280327ff47ffd", + "0x4800800c7fc38001", + "0x4800800d7fc27fff", + "0x4000800e7fc17ffd", "0x484480017ffd8000", "0x10000000000000000", "0x40307ffd7fff7ffb", @@ -17623,28 +17971,28 @@ "0x48307fff7ff98003", "0x482480017fff8000", "0xfffffffffffffffe0000000000000000", - "0x480280337ff47fff", - "0x480280347ff47ffd", - "0x400280357ff47f96", + "0x4800800f7fbd7fff", + "0x480080107fbc7ffd", + "0x400080117fbb7fda", "0x404480017ffc7ffe", "0x100000000000000000000000000000000", - "0x40307f967ffe7fff", - "0x40307ffc7ff77f97", + "0x40307fda7ffe7fff", + "0x40307ffc7ff77fdb", "0x4824800180008002", "0xffffffffffffffff0000000000000000", - "0x480280367ff48001", - "0x480280377ff47ffe", - "0x400280387ff47ffe", + "0x480080127fba8001", + "0x480080137fb97ffe", + "0x400080147fb87ffe", "0x484480017ffe8000", "0x10000000000000000", - "0x40307ffc7fff7f86", - "0x48487ff97ffc8000", - "0x48487ff97ffc8000", + "0x40307ffc7fff7fbd", + "0x48507fc37ffc8000", + "0x48507fc27ffc8000", "0x4824800180018002", "0xffffffffffffffff0000000000000000", - "0x480280397ff48001", - "0x4802803a7ff47fff", - "0x4002803b7ff47ffd", + "0x480080157fb48001", + "0x480080167fb37fff", + "0x400080177fb27ffd", "0x484480017ffd8000", "0x10000000000000000", "0x40307ffd7fff7ffb", @@ -17653,28 +18001,28 @@ "0x48307fff7ff98003", "0x482480017fff8000", "0xfffffffffffffffe0000000000000000", - "0x4802803c7ff47fff", - "0x4802803d7ff47ffd", - "0x4002803e7ff47f85", + "0x480080187fae7fff", + "0x480080197fad7ffd", + "0x4000801a7fac7fc9", "0x404480017ffc7ffe", "0x100000000000000000000000000000000", - "0x40307f857ffe7fff", - "0x40307ffc7ff77f86", + "0x40307fc97ffe7fff", + "0x40307ffc7ff77fca", "0x4824800180008002", "0xffffffffffffffff0000000000000000", - "0x4802803f7ff48001", - "0x480280407ff47ffe", - "0x400280417ff47ffe", + "0x4800801b7fab8001", + "0x4800801c7faa7ffe", + "0x4000801d7fa97ffe", "0x484480017ffe8000", "0x10000000000000000", - "0x40307ffc7fff7f76", - "0x48487ffa7ffc8000", - "0x48487ffa7ffc8000", + "0x40307ffc7fff7fad", + "0x48507fb57ffc8000", + "0x48507fb47ffc8000", "0x4824800180018002", "0xffffffffffffffff0000000000000000", - "0x480280427ff48001", - "0x480280437ff47fff", - "0x400280447ff47ffd", + "0x4800801e7fa58001", + "0x4800801f7fa47fff", + "0x400080207fa37ffd", "0x484480017ffd8000", "0x10000000000000000", "0x40307ffd7fff7ffb", @@ -17683,28 +18031,148 @@ "0x48307fff7ff98003", "0x482480017fff8000", "0xfffffffffffffffe0000000000000000", - "0x480280457ff47fff", - "0x480280467ff47ffd", - "0x400280477ff47f74", + "0x480080217f9f7fff", + "0x480080227f9e7ffd", + "0x400080237f9d7fb8", "0x404480017ffc7ffe", "0x100000000000000000000000000000000", - "0x40307f747ffe7fff", - "0x40307ffc7ff77f75", + "0x40307fb87ffe7fff", + "0x40307ffc7ff77fb9", "0x4824800180008002", "0xffffffffffffffff0000000000000000", - "0x480280487ff48001", - "0x480280497ff47ffe", - "0x4002804a7ff47ffe", + "0x480080247f9c8001", + "0x480080257f9b7ffe", + "0x400080267f9a7ffe", + "0x484480017ffe8000", + "0x10000000000000000", + "0x40307ffc7fff7f9e", + "0x48507fa57ffc8000", + "0x48507fa47ffc8000", + "0x4824800180018002", + "0xffffffffffffffff0000000000000000", + "0x480080277f968001", + "0x480080287f957fff", + "0x400080297f947ffd", + "0x484480017ffd8000", + "0x10000000000000000", + "0x40307ffd7fff7ffb", + "0x484480017ffd8000", + "0x10000000000000000", + "0x48307fff7ff98003", + "0x482480017fff8000", + "0xfffffffffffffffe0000000000000000", + "0x4800802a7f907fff", + "0x4800802b7f8f7ffd", + "0x4000802c7f8e7fa7", + "0x404480017ffc7ffe", + "0x100000000000000000000000000000000", + "0x40307fa77ffe7fff", + "0x40307ffc7ff77fa8", + "0x4824800180008002", + "0xffffffffffffffff0000000000000000", + "0x4800802d7f8d8001", + "0x4800802e7f8c7ffe", + "0x4000802f7f8b7ffe", + "0x484480017ffe8000", + "0x10000000000000000", + "0x40307ffc7fff7f95", + "0x48487ffc7ffc8000", + "0x48487ffc7ffc8000", + "0x4824800180018002", + "0xffffffffffffffff0000000000000000", + "0x480080307f878001", + "0x480080317f867fff", + "0x400080327f857ffd", + "0x484480017ffd8000", + "0x10000000000000000", + "0x40307ffd7fff7ffb", + "0x484480017ffd8000", + "0x10000000000000000", + "0x48307fff7ff98003", + "0x482480017fff8000", + "0xfffffffffffffffe0000000000000000", + "0x480080337f817fff", + "0x480080347f807ffd", + "0x400080357f7f7f96", + "0x404480017ffc7ffe", + "0x100000000000000000000000000000000", + "0x40307f967ffe7fff", + "0x40307ffc7ff77f97", + "0x4824800180008002", + "0xffffffffffffffff0000000000000000", + "0x480080367f7e8001", + "0x480080377f7d7ffe", + "0x400080387f7c7ffe", + "0x484480017ffe8000", + "0x10000000000000000", + "0x40307ffc7fff7f86", + "0x48487ffb7ffc8000", + "0x48487ffb7ffc8000", + "0x4824800180018002", + "0xffffffffffffffff0000000000000000", + "0x480080397f788001", + "0x4800803a7f777fff", + "0x4000803b7f767ffd", + "0x484480017ffd8000", + "0x10000000000000000", + "0x40307ffd7fff7ffb", + "0x484480017ffd8000", + "0x10000000000000000", + "0x48307fff7ff98003", + "0x482480017fff8000", + "0xfffffffffffffffe0000000000000000", + "0x4800803c7f727fff", + "0x4800803d7f717ffd", + "0x4000803e7f707f85", + "0x404480017ffc7ffe", + "0x100000000000000000000000000000000", + "0x40307f857ffe7fff", + "0x40307ffc7ff77f86", + "0x4824800180008002", + "0xffffffffffffffff0000000000000000", + "0x4800803f7f6f8001", + "0x480080407f6e7ffe", + "0x400080417f6d7ffe", + "0x484480017ffe8000", + "0x10000000000000000", + "0x40307ffc7fff7f76", + "0x48487ffc7ffc8000", + "0x48487ffc7ffc8000", + "0x4824800180018002", + "0xffffffffffffffff0000000000000000", + "0x480080427f698001", + "0x480080437f687fff", + "0x400080447f677ffd", + "0x484480017ffd8000", + "0x10000000000000000", + "0x40307ffd7fff7ffb", + "0x484480017ffd8000", + "0x10000000000000000", + "0x48307fff7ff98003", + "0x482480017fff8000", + "0xfffffffffffffffe0000000000000000", + "0x480080457f637fff", + "0x480080467f627ffd", + "0x400080477f617f74", + "0x404480017ffc7ffe", + "0x100000000000000000000000000000000", + "0x40307f747ffe7fff", + "0x40307ffc7ff77f75", + "0x4824800180008002", + "0xffffffffffffffff0000000000000000", + "0x480080487f608001", + "0x480080497f5f7ffe", + "0x4000804a7f5e7ffe", "0x484480017ffe8000", "0x10000000000000000", "0x40307ffc7fff7f67", - "0x48487ff97ffc8000", - "0x48487ff97ffc8000", + "0x48487ffb7ffc8000", + "0x48487ffb7ffc8000", "0x4824800180018002", "0xffffffffffffffff0000000000000000", - "0x4802804b7ff48001", - "0x4802804c7ff47fff", - "0x4002804d7ff47ffd", + "0x4800804b7f5a8001", + "0x4800804c7f597fff", + "0x4000804d7f587ffd", "0x484480017ffd8000", "0x10000000000000000", "0x40307ffd7fff7ffb", @@ -17713,25 +18181,25 @@ "0x48307fff7ff98003", "0x482480017fff8000", "0xfffffffffffffffe0000000000000000", - "0x4802804e7ff47fff", - "0x4802804f7ff47ffd", - "0x400280507ff47f63", + "0x4800804e7f547fff", + "0x4800804f7f537ffd", + "0x400080507f527f63", "0x404480017ffc7ffe", "0x100000000000000000000000000000000", "0x40307f637ffe7fff", "0x40307ffc7ff77f64", - "0x482680017ff48000", + "0x482480017f528000", "0x51", "0x480a7ff77fff8000", "0x480a7ff87fff8000", "0x48127f597fff8000", "0x48127f597fff8000", "0x1104800180018000", - "0x3bb", + "0xfb0", "0x480680017fff8000", - "0xbaaedce6af48a03bbfd25e8cd0364141", + "0xbce6faada7179e84f3b9cac2fc632551", "0x480680017fff8000", - "0xfffffffffffffffffffffffffffffffe", + "0xffffffff00000000ffffffffffffffff", "0x480080007ff98000", "0x480080017ff88000", "0x480080027ff78000", @@ -17956,78 +18424,18 @@ "0x100000000000000000000000000000000", "0x40307f937ffe7fff", "0x40307ffc7ff77f94", - "0x480680017fff8000", - "0xfffffffffffffffffffffffffffffffe", - "0x48307f8e80017fff", - "0xa0680017fff7fff", - "0x7", - "0x482480017fff8000", - "0x100000000000000000000000000000000", - "0x400080397f7f7fff", - "0x10780017fff7fff", - "0xc", - "0x400080397f807fff", - "0x40780017fff7fff", - "0x1", - "0x482480017f7f8000", - "0x3a", - "0x48127ffd7fff8000", - "0x480680017fff8000", - "0x0", - "0x10780017fff7fff", - "0x7", - "0x482480017f7f8000", - "0x3a", - "0x48127ffe7fff8000", - "0x480680017fff8000", - "0x1", - "0x480680017fff8000", - "0xbaaedce6af48a03bbfd25e8cd0364141", - "0x48307f8680017fff", - "0xa0680017fff7fff", - "0x7", - "0x482480017fff8000", - "0x100000000000000000000000000000000", - "0x400080007ff97fff", - "0x10780017fff7fff", - "0xb", - "0x400080007ffa7fff", - "0x40780017fff7fff", - "0x4", - "0x482480017ff68000", - "0x1", - "0x48127ffa7fff8000", - "0x48127ff57fff8000", - "0x10780017fff7fff", - "0x11", - "0x480680017fff8000", - "0x1", - "0x48307fff80017ff9", - "0xa0680017fff7fff", - "0x7", - "0x482480017fff8000", - "0x100000000000000000000000000000000", - "0x400080017ff57fff", - "0x10780017fff7fff", - "0x147", - "0x400080017ff67fff", - "0x482480017ff68000", - "0x2", - "0x48127ffb7fff8000", - "0x48127ffd7fff8000", - "0x20680017fff7ff5", - "0x13b", - "0x48127ffd7fff8000", - "0x480a7ffb7fff8000", - "0x480a7ffc7fff8000", - "0x48127e5a7fff8000", - "0x48127e5a7fff8000", + "0x482480017f838000", + "0x39", + "0x480a7ff97fff8000", + "0x480a7ffa7fff8000", + "0x48127e6b7fff8000", + "0x48127e6b7fff8000", "0x1104800180018000", - "0x293", + "0xec4", "0x480680017fff8000", - "0xbaaedce6af48a03bbfd25e8cd0364141", + "0xbce6faada7179e84f3b9cac2fc632551", "0x480680017fff8000", - "0xfffffffffffffffffffffffffffffffe", + "0xffffffff00000000ffffffffffffffff", "0x480080007ff98000", "0x480080017ff88000", "0x480080027ff78000", @@ -18252,124 +18660,226 @@ "0x100000000000000000000000000000000", "0x40307f937ffe7fff", "0x40307ffc7ff77f94", - "0x48127f107fff8000", - "0x48127f107fff8000", - "0x482480017f818000", + "0x48127d7d7fff8000", + "0x480680017fff8000", + "0x77037d812deb33a0f4a13945d898c296", + "0x480680017fff8000", + "0x6b17d1f2e12c4247f8bce6e563a440f2", + "0x480680017fff8000", + "0x2bce33576b315ececbb6406837bf51f5", + "0x480680017fff8000", + "0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e16", + "0x482480017f7e8000", "0x39", "0x480680017fff8000", - "0x536563703235366b314d756c", - "0x400080007d667fff", - "0x400080017d667d65", - "0x400080027d667d64", - "0x400080037d667ffc", - "0x400080047d667ffd", - "0x480080067d668000", + "0x5365637032353672314e6577", + "0x400280007ff67fff", + "0x400280017ff67ff9", + "0x400280027ff67ffa", + "0x400280037ff67ffb", + "0x400280047ff67ffc", + "0x400280057ff67ffd", + "0x480280077ff68000", "0x20680017fff7fff", - "0x37", - "0x480080057d658000", - "0x480080077d648000", + "0xa6", + "0x480280067ff68000", + "0x480280087ff68000", + "0x480280097ff68000", + "0x482680017ff68000", + "0xa", + "0x48127ffc7fff8000", + "0x20680017fff7ffc", + "0x8f", + "0x48127fff7fff8000", "0x480680017fff8000", - "0x536563703235366b314d756c", - "0x400080087d627fff", - "0x400080097d627ffd", - "0x4000800a7d627d56", - "0x4000800b7d627f86", - "0x4000800c7d627f87", - "0x4800800e7d628000", + "0x5365637032353672314d756c", + "0x400080007ffc7fff", + "0x400080017ffc7ffe", + "0x400080027ffc7ffb", + "0x400080037ffc7e91", + "0x400080047ffc7e92", + "0x480080067ffc8000", + "0x20680017fff7fff", + "0x77", + "0x480080057ffb8000", + "0x48127fff7fff8000", + "0x480080077ff98000", + "0x480680017fff8000", + "0x5365637032353672314d756c", + "0x400080087ff77fff", + "0x400080097ff77ffd", + "0x4001800a7ff77ffd", + "0x4000800b7ff77f7a", + "0x4000800c7ff77f7b", + "0x4800800e7ff78000", + "0x20680017fff7fff", + "0x5d", + "0x4800800d7ff68000", + "0x48127fff7fff8000", + "0x4800800f7ff48000", + "0x480680017fff8000", + "0x536563703235367231416464", + "0x400080107ff27fff", + "0x400080117ff27ffd", + "0x400080127ff27ff9", + "0x400080137ff27ffe", + "0x480080157ff28000", + "0x20680017fff7fff", + "0x44", + "0x480080147ff18000", + "0x48127fff7fff8000", + "0x480080167fef8000", + "0x480680017fff8000", + "0x5365637032353672314765745879", + "0x400080177fed7fff", + "0x400080187fed7ffd", + "0x400080197fed7ffe", + "0x4800801b7fed8000", "0x20680017fff7fff", + "0x2c", + "0x4800801a7fec8000", + "0x4800801c7feb8000", + "0x4800801d7fea8000", + "0x482480017fe98000", "0x20", - "0x4800800d7d618000", - "0x4800800f7d608000", + "0x48127ffc7fff8000", + "0x48287ff980007ffc", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xa", + "0x40780017fff7fff", + "0x2", + "0x482480017ffc8000", + "0x118", "0x480680017fff8000", - "0x536563703235366b31416464", - "0x400080107d5e7fff", - "0x400080117d5e7ffd", - "0x400080127d5e7ffa", - "0x400080137d5e7ffe", - "0x480080157d5e8000", + "0x0", + "0x10780017fff7fff", + "0x10", + "0x48127ffe7fff8000", + "0x48287ffa80007ffb", "0x20680017fff7fff", - "0xc", - "0x48127ff57fff8000", - "0x480080147d5c8000", - "0x482480017d5b8000", - "0x17", + "0x4", + "0x10780017fff7fff", + "0x7", + "0x48127ffe7fff8000", + "0x480680017fff8000", + "0x0", + "0x10780017fff7fff", + "0x5", + "0x48127ffe7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127fdc7fff8000", + "0x48127ffd7fff8000", + "0x48127ff77fff8000", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", - "0x480080167d588000", + "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", - "0x48127ff57fff8000", - "0x480080147d5c8000", - "0x482480017d5b8000", + "0x40780017fff7fff", + "0x9", + "0x4800801a7fe38000", + "0x48127fdc7fff8000", + "0x482480017ffe8000", + "0x456", + "0x482480017fe08000", + "0x1e", + "0x480680017fff8000", + "0x1", + "0x4800801c7fde8000", + "0x4800801d7fdd8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0xe", + "0x480080147fe38000", + "0x48127fdc7fff8000", + "0x482480017ffe8000", + "0x2eb8", + "0x482480017fe08000", "0x18", "0x480680017fff8000", "0x1", - "0x480080167d598000", - "0x480080177d588000", + "0x480080167fde8000", + "0x480080177fdd8000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0x4", - "0x48127ff57fff8000", - "0x4800800d7d5c8000", - "0x482480017d5b8000", + "0x13", + "0x4800800d7fe38000", + "0x48127fdc7fff8000", + "0x482480017ffe8000", + "0x597e", + "0x482480017fe08000", "0x11", "0x480680017fff8000", "0x1", - "0x4800800f7d598000", - "0x480080107d588000", + "0x4800800f7fde8000", + "0x480080107fdd8000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0x8", - "0x48127ff57fff8000", - "0x480080057d5c8000", - "0x482480017d5b8000", + "0x18", + "0x480080057fe38000", + "0x48127fdc7fff8000", + "0x482480017ffe8000", + "0x84a8", + "0x482480017fe08000", "0x9", "0x480680017fff8000", "0x1", - "0x480080077d598000", - "0x480080087d588000", + "0x480080077fde8000", + "0x480080087fdd8000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0xf8", - "0x48127f057fff8000", - "0x10780017fff7fff", - "0x6", - "0x40780017fff7fff", - "0xfa", - "0x482480017efb8000", - "0x2", + "0x16", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x753235365f737562204f766572666c6f77", + "0x4f7074696f6e3a3a756e77726170206661696c65642e", "0x400080007ffe7fff", - "0x48127ffd7fff8000", - "0x48127d5b7fff8000", - "0x48127d5b7fff8000", + "0x482480017fe78000", + "0xac94", + "0x48127fe57fff8000", + "0x48127ffc7fff8000", + "0x482480017ffb8000", + "0x1", + "0x10780017fff7fff", + "0xb", + "0x40780017fff7fff", + "0x1c", + "0x480280067ff68000", + "0x482480017fff8000", + "0xafdc", + "0x482680017ff68000", + "0xa", + "0x480280087ff68000", + "0x480280097ff68000", + "0x48127fdc7fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", "0x480680017fff8000", "0x1", "0x48127ffa7fff8000", - "0x482480017ff98000", - "0x1", + "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0x272", + "0x27d", "0x4824800180008002", "0xffffffffffffffff0000000000000000", - "0x480280077ff48001", - "0x480280087ff47ffe", - "0x400280097ff47ffe", + "0x480080077d6c8001", + "0x480080087d6b7ffe", + "0x400080097d6a7ffe", "0x484480017ffe8000", "0x10000000000000000", - "0x40307ffc7fff7d7c", - "0x48507d807ffc8000", - "0x48507d7f7ffc8000", + "0x40307ffc7fff7d71", + "0x48507d757ffc8000", + "0x48507d747ffc8000", "0x4824800180018002", "0xffffffffffffffff0000000000000000", - "0x4802800a7ff48001", - "0x4802800b7ff47fff", - "0x4002800c7ff47ffd", + "0x4800800a7d668001", + "0x4800800b7d657fff", + "0x4000800c7d647ffd", "0x484480017ffd8000", "0x10000000000000000", "0x40307ffd7fff7ffb", @@ -18378,28 +18888,28 @@ "0x48307fff7ff98003", "0x482480017fff8000", "0xfffffffffffffffe0000000000000000", - "0x4802800d7ff47fff", - "0x4802800e7ff47ffd", - "0x4002800f7ff47d6f", + "0x4800800d7d607fff", + "0x4800800e7d5f7ffd", + "0x4000800f7d5e7d63", "0x404480017ffc7ffe", "0x100000000000000000000000000000000", - "0x40307d6f7ffe7fff", - "0x40307ffc7ff77d79", + "0x40307d637ffe7fff", + "0x40307ffc7ff77d6e", "0x4824800180008002", "0xffffffffffffffff0000000000000000", - "0x480280107ff48001", - "0x480280117ff47ffe", - "0x400280127ff47ffe", + "0x480080107d5d8001", + "0x480080117d5c7ffe", + "0x400080127d5b7ffe", "0x484480017ffe8000", "0x10000000000000000", - "0x40307ffc7fff7d6d", - "0x48507d6f7ffc8000", - "0x48507d6e7ffc8000", + "0x40307ffc7fff7d62", + "0x48507d647ffc8000", + "0x48507d637ffc8000", "0x4824800180018002", "0xffffffffffffffff0000000000000000", - "0x480280137ff48001", - "0x480280147ff47fff", - "0x400280157ff47ffd", + "0x480080137d578001", + "0x480080147d567fff", + "0x400080157d557ffd", "0x484480017ffd8000", "0x10000000000000000", "0x40307ffd7fff7ffb", @@ -18408,22 +18918,23 @@ "0x48307fff7ff98003", "0x482480017fff8000", "0xfffffffffffffffe0000000000000000", - "0x480280167ff47fff", - "0x480280177ff47ffd", - "0x400380187ff47ff9", + "0x480080167d517fff", + "0x480080177d507ffd", + "0x400180187d4f7ffb", "0x404480017ffc7ffe", "0x100000000000000000000000000000000", - "0x40287ff97ffe7fff", - "0x40307ffc7ff77d69", + "0x40287ffb7ffe7fff", + "0x40307ffc7ff77d5e", "0x40780017fff7fff", "0x1", "0x480680017fff8000", "0x4f7074696f6e3a3a756e77726170206661696c65642e", "0x400080007ffe7fff", - "0x482680017ff48000", + "0x482480017d4d8000", "0x19", - "0x48127d5b7fff8000", - "0x48127d5b7fff8000", + "0x482480017d538000", + "0x24306", + "0x480a7ff67fff8000", "0x480680017fff8000", "0x1", "0x48127ffa7fff8000", @@ -18431,189 +18942,184 @@ "0x1", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0x29c", - "0x40780017fff7fff", - "0x1", + "0x2ae", + "0x48127d4d7fff8000", + "0x482480017d4d8000", + "0x26606", + "0x480a7ff67fff8000", "0x480680017fff8000", - "0x4f7074696f6e3a3a756e77726170206661696c65642e", - "0x400080007ffe7fff", - "0x48127d607fff8000", - "0x48127d607fff8000", - "0x48127ffc7fff8000", - "0x482480017ffb8000", - "0x1", - "0x10780017fff7fff", - "0x9", - "0x40780017fff7fff", - "0x2a2", - "0x480080067d578000", - "0x482480017d568000", - "0xa", - "0x480080087d558000", - "0x480080097d548000", - "0x480a7ff47fff8000", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", + "0x0", "0x480680017fff8000", - "0x1", - "0x48127ffa7fff8000", - "0x48127ffa7fff8000", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x2ac", - "0x480a7ff47fff8000", - "0x48127d517fff8000", - "0x48127d517fff8000", + "0x0", "0x480680017fff8000", "0x0", + "0x208b7fff7fff7ffe", + "0x48297ffa80007ff6", + "0x20680017fff7fff", + "0x19", + "0x48297ffb80007ff7", + "0x20680017fff7fff", + "0x12", + "0x48297ffc80007ff8", + "0x20680017fff7fff", + "0xb", + "0x48297ffd80007ff9", + "0x20680017fff7fff", + "0x5", "0x480680017fff8000", "0x1", + "0x208b7fff7fff7ffe", "0x480680017fff8000", "0x0", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0x2b0", - "0x480a7ff47fff8000", - "0x480280057ff68000", - "0x482680017ff68000", - "0x9", - "0x480680017fff8000", "0x1", - "0x480280077ff68000", - "0x480280087ff68000", - "0x208b7fff7fff7ffe", + "0x10780017fff7fff", + "0x8", "0x40780017fff7fff", "0x2", - "0x480680017fff8000", - "0x536563703235366b314765745879", - "0x400280007ffc7fff", - "0x400380017ffc7ffa", - "0x400380027ffc7ffd", - "0x480280047ffc8000", - "0x20680017fff7fff", - "0xb5", - "0x480280057ffc8000", - "0x480280067ffc8000", - "0x480280077ffc8000", - "0x480280087ffc8000", - "0x4800800080007ffc", - "0x400080017fff7ffc", - "0x400080027fff7ffd", - "0x400080037fff7ffe", - "0x40780017fff7fff", - "0x1", - "0x480a7ff97fff8000", - "0x480280037ffc8000", - "0x480a7ffb7fff8000", - "0x48127ffb7fff8000", - "0x482480017ffa8000", + "0x10780017fff7fff", "0x4", - "0x48127ffa7fff8000", - "0x48127ff97fff8000", - "0x402780017ffc8001", - "0x9", - "0x1104800180018000", - "0x23b", - "0x40137ffa7fff8000", - "0x20680017fff7ffb", - "0x8e", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x48127ffc7fff8000", - "0x48127ffc7fff8000", + "0x40780017fff7fff", + "0x3", "0x480680017fff8000", "0x0", + "0x208b7fff7fff7ffe", + "0x20780017fff7ffd", + "0xc", + "0x40780017fff7fff", + "0x68", + "0x480a7ff77fff8000", "0x480680017fff8000", "0x0", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffec32", - "0x20680017fff7ffd", - "0x7b", + "0x480a7ff87fff8000", + "0x480a7ff97fff8000", + "0x480a7ffa7fff8000", + "0x480a7ffb7fff8000", + "0x208b7fff7fff7ffe", + "0xa0680017fff8000", + "0x8", + "0x482a7ffd7ffb8000", + "0x4824800180007fff", + "0x100000000", + "0x400280007ff77fff", + "0x10780017fff7fff", + "0x425", + "0x482a7ffd7ffb8001", + "0x4824800180007fff", + "0xffffffffffffffffffffffff00000000", + "0x400280007ff77ffe", "0x480680017fff8000", - "0x4b656363616b", - "0x4002800080017fff", - "0x4002800180017ffb", - "0x4002800280017ffd", - "0x4002800380017ffe", - "0x4802800580018000", + "0x1f", + "0x48307fff80017ffe", + "0xa0680017fff7fff", + "0x7", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400280017ff77fff", + "0x10780017fff7fff", + "0x38d", + "0x400280017ff77fff", + "0x482680017ff78000", + "0x2", + "0x4824800180007ffb", + "0x1f", "0x20680017fff7fff", - "0x6a", - "0x4802800780018000", - "0x4002800080007fff", - "0x480680017fff8000", - "0xff00ff00ff00ff00ff00ff00ff00ff", - "0x4002800180007fff", - "0x4802800280008000", - "0x484480017fff8000", - "0xffff", - "0x48307fff7ffc8000", - "0x4002800580007fff", - "0x480680017fff8000", - "0xffff0000ffff0000ffff0000ffff00", - "0x4002800680007fff", - "0x4802800780008000", - "0x484480017fff8000", - "0xffffffff", - "0x48307fff7ffc8000", - "0x4002800a80007fff", - "0x480680017fff8000", - "0xffffffff00000000ffffffff000000", - "0x4002800b80007fff", - "0x4802800c80008000", - "0x484480017fff8000", - "0xffffffffffffffff", - "0x48307fff7ffc8000", - "0x4002800f80007fff", + "0x4", + "0x10780017fff7fff", + "0x2f9", "0x480680017fff8000", - "0xffffffffffffffff00000000000000", - "0x4002801080007fff", - "0x4802801180008000", - "0x484480017fff8000", - "0xffffffffffffffffffffffffffffffff", - "0x48307fff7ffc8000", - "0x4802800680018000", - "0x4002801480007fff", + "0x1f", + "0x48307fff80017ff9", + "0xa0680017fff7fff", + "0x7", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400080007ffa7fff", + "0x10780017fff7fff", + "0x2dc", + "0x400080007ffb7fff", + "0x482480017ffb8000", + "0x1", + "0x4824800180007ffe", + "0x10", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x20d", "0x480680017fff8000", - "0xff00ff00ff00ff00ff00ff00ff00ff", - "0x4002801580007fff", - "0x4802801680008000", - "0x484480017fff8000", - "0xffff", - "0x48307fff7ffc8000", - "0x4002801980007fff", - "0x480680017fff8000", - "0xffff0000ffff0000ffff0000ffff00", - "0x4002801a80007fff", - "0x4802801b80008000", - "0x484480017fff8000", - "0xffffffff", - "0x48307fff7ffc8000", - "0x4002801e80007fff", - "0x480680017fff8000", - "0xffffffff00000000ffffffff000000", - "0x4002801f80007fff", - "0x4802802080008000", - "0x484480017fff8000", - "0xffffffffffffffff", - "0x48307fff7ffc8000", - "0x4002802380007fff", - "0x480680017fff8000", - "0xffffffffffffffff00000000000000", - "0x4002802480007fff", - "0x4802802580008000", - "0x484480017fff8000", + "0x10", + "0x48307fff80017ffc", + "0xa0680017fff7fff", + "0x7", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400080007ffa7fff", + "0x10780017fff7fff", + "0xfe", + "0x400080007ffb7fff", + "0x40780017fff7fff", + "0xf", + "0xa0680017fff8000", + "0x16", + "0x480080017feb8003", + "0x480080027fea8003", + "0x4844800180017ffe", + "0x100000000000000000000000000000000", + "0x483180017ffd7ffc", + "0x482480017fff7ffd", + "0x800000000000010fffffffffffffffff7ffffffffffffef0000000000000001", + "0x20680017fff7ffc", + "0x6", + "0x402480017fff7ffd", "0xffffffffffffffffffffffffffffffff", - "0x48307fff7ffc8000", - "0x484480017fff8000", - "0x800000000000010fffffffffffffff7ffffffffffffef000000000000000001", + "0x10780017fff7fff", + "0x4", + "0x402480017ffe7ffd", + "0xf7ffffffffffffef0000000000000000", + "0x400080037fe67ffd", + "0x20680017fff7ffe", + "0xe", + "0x402780017fff7fff", + "0x1", + "0x400180017feb7ffc", + "0x40780017fff7fff", + "0x5", + "0x482480017fe68000", + "0x2", + "0x480a7ffc7fff8000", "0x480680017fff8000", - "0x100000000", - "0x480080007fd58005", - "0x480080017fd48005", + "0x0", + "0x10780017fff7fff", + "0x6", + "0x482480017fe68000", + "0x4", + "0x48127ffe7fff8000", + "0x48127ffc7fff8000", + "0x480680017fff8000", + "0x10", + "0x48307fff80017fe1", + "0xa0680017fff7fff", + "0x7", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400080007ff97fff", + "0x10780017fff7fff", + "0xb7", + "0x400080007ffa7fff", + "0x482480017ffa8000", + "0x1", + "0x48127ffe7fff8000", + "0x1104800180018000", + "0xd2b", + "0x20680017fff7ffd", + "0xa8", + "0x480080007ffc8005", + "0x480080017ffb8005", "0x4824800180047ffe", "0x1", "0x48307ffd7ffe7ffc", - "0x480080027fd17ffd", + "0x480080027ff87ffd", "0xa0680017fff7ffd", "0x6", "0x482480017ff97ffd", @@ -18622,923 +19128,5075 @@ "0x4", "0x482480017fff7ffd", "0xffffffffffffffff0000000000000000", - "0x400080037fce7ffc", + "0x400080037ff57ffc", "0x40507ffe7ff87ffd", - "0x40307fff7ffd7ff7", - "0x484480017fff8000", - "0x100000000000000000000000000000000", - "0x484480017fe48000", - "0x800000000000010fffffffffffffff7ffffffffffffef000000000000000001", - "0x482480017fcc8000", - "0x4", - "0x4802800480018000", - "0x4826800180008000", - "0x28", - "0x4826800180018000", - "0x8", - "0x480680017fff8000", - "0x0", - "0x480680017fff8000", - "0x0", - "0x48307ff97ff88000", - "0x208b7fff7fff7ffe", - "0x48127ff97fff8000", - "0x4802800480018000", - "0x4826800180018000", - "0x8", - "0x4802800680018000", - "0x4802800780018000", - "0x10780017fff7fff", - "0xe", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", - "0x480a80017fff8000", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", - "0x10780017fff7fff", - "0x7", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x480a80017fff8000", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", - "0x480a80007fff8000", - "0x48127ffa7fff8000", + "0x40307fff7ffd7fe7", "0x480680017fff8000", - "0x1", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x208b7fff7fff7ffe", - "0x480a7ff97fff8000", - "0x480280037ffc8000", - "0x480a7ffb7fff8000", - "0x482680017ffc8000", + "0x1f", + "0x48287ffb80017fff", + "0xa0680017fff7fff", "0x7", - "0x480680017fff8000", - "0x1", - "0x480280057ffc8000", - "0x480280067ffc8000", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x2", - "0x4824800180008002", - "0xffffffffffffffff0000000000000000", - "0x480280007ff98001", - "0x480280017ff97ffe", - "0x400280027ff97ffe", - "0x484480017ffe8000", - "0x10000000000000000", - "0x40317ffc7fff7ffa", - "0x48487ffc7ffc8000", - "0x48487ffc7ffc8000", - "0x4824800180018002", - "0xffffffffffffffff0000000000000000", - "0x480280037ff98001", - "0x480280047ff97fff", - "0x400280057ff97ffd", - "0x484480017ffd8000", - "0x10000000000000000", - "0x40307ffd7fff7ffb", - "0x484480017ffd8000", - "0x10000000000000000", - "0x48307fff7ff98003", "0x482480017fff8000", - "0xfffffffffffffffe0000000000000000", - "0x480280067ff97fff", - "0x480280077ff97ffd", - "0x400280087ff97ff0", - "0x404480017ffc7ffe", "0x100000000000000000000000000000000", - "0x40307ff07ffe7fff", - "0x40307ffc7ff77fef", - "0x40780017fff7fff", - "0x2", - "0x4824800180008002", - "0xffffffffffffffff0000000000000000", - "0x480280097ff98001", - "0x4802800a7ff97ffe", - "0x4002800b7ff97ffe", - "0x484480017ffe8000", - "0x10000000000000000", - "0x40317ffc7fff7ffa", - "0x48487ffd7ffc8000", - "0x48487ffd7ffc8000", - "0x4824800180018002", - "0xffffffffffffffff0000000000000000", - "0x4802800c7ff98001", - "0x4802800d7ff97fff", - "0x4002800e7ff97ffd", - "0x484480017ffd8000", - "0x10000000000000000", - "0x40307ffd7fff7ffb", - "0x484480017ffd8000", - "0x10000000000000000", - "0x48307fff7ff98003", - "0x482480017fff8000", - "0xfffffffffffffffe0000000000000000", - "0x4802800f7ff97fff", - "0x480280107ff97ffd", - "0x400280117ff97ff0", - "0x404480017ffc7ffe", + "0x400080047ff17fff", + "0x10780017fff7fff", + "0x7f", + "0x400080047ff27fff", + "0x484480017ffc8000", "0x100000000000000000000000000000000", - "0x40307ff07ffe7fff", - "0x40307ffc7ff77fef", - "0x48307ff07fde8001", + "0x480680017fff8000", + "0x10", + "0x48307fe17ffe8000", + "0x48307ffe80017ffc", "0xa0680017fff7fff", "0x7", - "0x4824800180007fff", + "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400280127ff97fff", - "0x10780017fff7fff", - "0xc", - "0x400280127ff97fff", - "0x40780017fff7fff", - "0x1", - "0x482680017ff98000", - "0x13", - "0x48127ffd7fff8000", - "0x480680017fff8000", - "0x0", + "0x400080057fec7fff", "0x10780017fff7fff", - "0x7", - "0x482680017ff98000", - "0x13", - "0x48127ffe7fff8000", + "0x2f", + "0x400080057fed7fff", "0x480680017fff8000", - "0x1", - "0x40780017fff7fff", - "0x2", - "0x4824800180008002", - "0xffffffffffffffff0000000000000000", - "0x480080007ffa8001", - "0x480080017ff97ffe", - "0x400080027ff87ffe", - "0x484480017ffe8000", - "0x10000000000000000", - "0x40317ffc7fff7ffb", - "0x48487ffc7ffc8000", - "0x48487ffc7ffc8000", - "0x4824800180018002", - "0xffffffffffffffff0000000000000000", - "0x480080037ff48001", - "0x480080047ff37fff", - "0x400080057ff27ffd", - "0x484480017ffd8000", - "0x10000000000000000", - "0x40307ffd7fff7ffb", - "0x484480017ffd8000", - "0x10000000000000000", - "0x48307fff7ff98003", - "0x482480017fff8000", - "0xfffffffffffffffe0000000000000000", - "0x480080067fee7fff", - "0x480080077fed7ffd", - "0x400080087fec7ff0", - "0x404480017ffc7ffe", - "0x100000000000000000000000000000000", - "0x40307ff07ffe7fff", - "0x40307ffc7ff77fef", - "0x48307ff07fed8001", + "0x10", + "0x48307fff80017ff9", "0xa0680017fff7fff", "0x7", - "0x4824800180007fff", + "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400080097fe97fff", - "0x10780017fff7fff", - "0xc", - "0x400080097fea7fff", - "0x40780017fff7fff", - "0x1", - "0x482480017fe98000", - "0xa", - "0x48127ffd7fff8000", - "0x480680017fff8000", - "0x0", + "0x400080067fe97fff", "0x10780017fff7fff", + "0x16", + "0x400080067fea7fff", + "0x482480017fea8000", "0x7", - "0x482480017fe98000", - "0xa", "0x48127ffe7fff8000", - "0x480680017fff8000", - "0x1", - "0x48307fe97fd28001", - "0xa0680017fff7fff", + "0x1104800180018000", + "0xcef", + "0x20680017fff7ffd", "0x7", - "0x4824800180007fff", + "0x48127ffc7fff8000", + "0x484480017ffe8000", "0x100000000000000000000000000000000", - "0x400080007ffa7fff", "0x10780017fff7fff", + "0x22", + "0x40780017fff7fff", "0xc", - "0x400080007ffb7fff", + "0x48127ff07fff8000", + "0x48127ff17fff8000", + "0x48127ff17fff8000", + "0x10780017fff7fff", + "0x50", + "0x40780017fff7fff", + "0x17", "0x40780017fff7fff", "0x1", - "0x482480017ffa8000", - "0x1", - "0x48127ffd7fff8000", "0x480680017fff8000", - "0x0", - "0x10780017fff7fff", + "0x7533325f737562204f766572666c6f77", + "0x400080007ffe7fff", + "0x482480017fd08000", "0x7", - "0x482480017ffa8000", - "0x1", - "0x48127ffe7fff8000", - "0x480680017fff8000", + "0x48127ffd7fff8000", + "0x482480017ffc8000", "0x1", + "0x10780017fff7fff", + "0x42", "0x40780017fff7fff", "0x2", - "0x4824800180008002", - "0xffffffffffffffff0000000000000000", - "0x480080007ffa8001", - "0x480080017ff97ffe", - "0x400080027ff87ffe", + "0x482480017fea8000", + "0x6", + "0x48127ff67fff8000", + "0x1104800180018000", + "0xccc", + "0x20680017fff7ffd", + "0x34", + "0x48127ffc7fff8000", + "0x48127ffe7fff8000", + "0x48527fff7ffa8000", + "0x48307fff7fe28000", + "0xa0680017fff8004", + "0xe", + "0x4824800180047ffe", + "0x100000000000000000000000000000000000000000000000000000000000000", "0x484480017ffe8000", - "0x10000000000000000", - "0x40317ffc7fff7ffb", - "0x48487ffd7ffc8000", - "0x48487ffd7ffc8000", - "0x4824800180018002", - "0xffffffffffffffff0000000000000000", - "0x480080037ff48001", - "0x480080047ff37fff", - "0x400080057ff27ffd", - "0x484480017ffd8000", - "0x10000000000000000", - "0x40307ffd7fff7ffb", - "0x484480017ffd8000", - "0x10000000000000000", - "0x48307fff7ff98003", - "0x482480017fff8000", - "0xfffffffffffffffe0000000000000000", - "0x480080067fee7fff", - "0x480080077fed7ffd", - "0x400080087fec7ff0", - "0x404480017ffc7ffe", - "0x100000000000000000000000000000000", - "0x40307ff07ffe7fff", - "0x40307ffc7ff77fef", - "0x48307ff07fed8001", - "0xa0680017fff7fff", - "0x7", - "0x4824800180007fff", - "0x100000000000000000000000000000000", - "0x400080097fe97fff", + "0x7000000000000110000000000000000", + "0x48307ffe7fff8002", + "0x480080007ff87ffc", + "0x480080017ff77ffc", + "0x402480017ffb7ffd", + "0xf8ffffffffffffeeffffffffffffffff", + "0x400080027ff67ffd", "0x10780017fff7fff", - "0xc", - "0x400080097fea7fff", + "0x16", + "0x484480017fff8001", + "0x1000000000000000000000000000000", + "0x48307fff80007ffd", + "0x480080007ff97ffd", + "0x480080017ff87ffd", + "0x402480017ffc7ffe", + "0xff000000000000000000000000000000", + "0x400080027ff77ffe", "0x40780017fff7fff", "0x1", - "0x482480017fe98000", - "0xa", - "0x48127ffd7fff8000", - "0x480680017fff8000", - "0x0", - "0x10780017fff7fff", - "0x7", - "0x482480017fe98000", - "0xa", - "0x48127ffe7fff8000", - "0x480680017fff8000", + "0x400280007ff97ff9", + "0x482480017ff68000", + "0x3", + "0x480a7ff87fff8000", + "0x482680017ff98000", "0x1", - "0x48307fe27fcb8000", - "0x48307fff7ffd8001", - "0xa0680017fff7fff", - "0x7", - "0x4824800180007fff", - "0x100000000000000000000000000000000", - "0x400080007ff97fff", + "0x48127fdf7fff8000", + "0x480a7ffb7fff8000", "0x10780017fff7fff", - "0xc", - "0x400080007ffa7fff", + "0xfe", "0x40780017fff7fff", "0x1", - "0x482480017ff98000", - "0x1", - "0x48127ffd7fff8000", "0x480680017fff8000", - "0x0", + "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x400080007ffe7fff", + "0x482480017ff48000", + "0x3", + "0x48127ffd7fff8000", + "0x482480017ffc8000", + "0x1", "0x10780017fff7fff", - "0x7", - "0x482480017ff98000", + "0x2a", + "0x40780017fff7fff", + "0xc", + "0x48127ff07fff8000", + "0x48127ff17fff8000", + "0x48127ff17fff8000", + "0x10780017fff7fff", + "0x23", + "0x40780017fff7fff", + "0x1f", + "0x40780017fff7fff", "0x1", - "0x48127ffe7fff8000", "0x480680017fff8000", + "0x7533325f737562204f766572666c6f77", + "0x400080007ffe7fff", + "0x482480017fd08000", + "0x5", + "0x48127ffd7fff8000", + "0x482480017ffc8000", "0x1", - "0x48307ff87fe18000", - "0x48307ffe7fff8000", - "0x48307fff7fe08001", - "0xa0680017fff7fff", - "0x7", - "0x4824800180007fff", - "0x100000000000000000000000000000000", - "0x400080007ff87fff", "0x10780017fff7fff", - "0xa", - "0x400080007ff97fff", + "0x15", + "0x40780017fff7fff", + "0x2c", + "0x48127fd07fff8000", + "0x48127fd17fff8000", + "0x48127fd17fff8000", + "0x10780017fff7fff", + "0xe", + "0x40780017fff7fff", + "0x37", "0x40780017fff7fff", "0x1", - "0x482480017ff88000", + "0x480680017fff8000", + "0x7533325f737562204f766572666c6f77", + "0x400080007ffe7fff", + "0x482480017fc08000", "0x1", "0x48127ffd7fff8000", - "0x10780017fff7fff", - "0x5", - "0x482480017ff88000", + "0x482480017ffc8000", "0x1", - "0x48127ffe7fff8000", - "0x48127ffe7fff8000", - "0x48127f967fff8000", - "0x48127fd17fff8000", - "0x48127ff47fff8000", - "0x48127ffb7fff8000", + "0x48127ffd7fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", "0xa0680017fff8000", - "0x7", - "0x4825800180007ffd", - "0x10", - "0x400280007ffc7fff", - "0x10780017fff7fff", - "0x6f", - "0x482680017ffd8000", - "0xfffffffffffffffffffffffffffffff0", - "0x400280007ffc7fff", - "0x4825800180007ffd", - "0x400000000000008800000000000000000000000000000000000000000000010", - "0x484480017fff8000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffff", - "0x482680017ffc8000", - "0x1", - "0x1137ffe7fff7fff", - "0x10780017fff7fff", - "0x5a", + "0x16", + "0x480080017ff98003", + "0x480080027ff88003", + "0x4844800180017ffe", + "0x100000000000000000000000000000000", + "0x483180017ffd7ffc", + "0x482480017fff7ffd", + "0x800000000000010fffffffffffffffff7ffffffffffffef0000000000000001", + "0x20680017fff7ffc", + "0x6", + "0x402480017fff7ffd", + "0xffffffffffffffffffffffffffffffff", "0x10780017fff7fff", - "0x54", + "0x4", + "0x402480017ffe7ffd", + "0xf7ffffffffffffef0000000000000000", + "0x400080037ff47ffd", + "0x20680017fff7ffe", + "0xe", + "0x402780017fff7fff", + "0x1", + "0x400180017ff97ffc", + "0x40780017fff7fff", + "0x5", + "0x482480017ff48000", + "0x2", + "0x480a7ffc7fff8000", + "0x480680017fff8000", + "0x0", "0x10780017fff7fff", - "0x4e", + "0x6", + "0x482480017ff48000", + "0x4", + "0x48127ffe7fff8000", + "0x48127ffc7fff8000", + "0x48127ffd7fff8000", + "0x48127fef7fff8000", + "0x1104800180018000", + "0xc3e", + "0x20680017fff7ffd", + "0xce", + "0x480080007ffc8005", + "0x480080017ffb8005", + "0x4824800180047ffe", + "0x1", + "0x48307ffd7ffe7ffc", + "0x480080027ff87ffd", + "0xa0680017fff7ffd", + "0x6", + "0x482480017ff97ffd", + "0xffffffffffffffff0000000000000000", "0x10780017fff7fff", - "0x48", + "0x4", + "0x482480017fff7ffd", + "0xffffffffffffffff0000000000000000", + "0x400080037ff57ffc", + "0x40507ffe7ff87ffd", + "0x40307fff7ffd7fe9", + "0x480680017fff8000", + "0x10", + "0x48307fda80017fff", + "0xa0680017fff7fff", + "0x7", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400080047ff17fff", "0x10780017fff7fff", - "0x42", + "0xa5", + "0x400080047ff27fff", + "0x482480017ff28000", + "0x5", + "0x48127ffe7fff8000", + "0x1104800180018000", + "0xc1b", + "0x20680017fff7ffd", + "0x96", + "0x480680017fff8000", + "0x1f", + "0x48287ffb80017fff", + "0xa0680017fff7fff", + "0x7", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400080007ff87fff", "0x10780017fff7fff", - "0x3c", + "0x7e", + "0x400080007ff97fff", + "0x48507ffc7fd68000", + "0x480680017fff8000", + "0x10", + "0x48307fe87ffe8000", + "0x48307ffe80017ffc", + "0xa0680017fff7fff", + "0x7", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400080017ff37fff", "0x10780017fff7fff", - "0x36", + "0x2f", + "0x400080017ff47fff", + "0x480680017fff8000", + "0x10", + "0x48307fff80017ff9", + "0xa0680017fff7fff", + "0x7", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400080027ff07fff", "0x10780017fff7fff", - "0x30", + "0x16", + "0x400080027ff17fff", + "0x482480017ff18000", + "0x3", + "0x48127ffe7fff8000", + "0x1104800180018000", + "0xbf1", + "0x20680017fff7ffd", + "0x7", + "0x48127ffc7fff8000", + "0x484480017ffe8000", + "0x100000000000000000000000000000000", "0x10780017fff7fff", - "0x2a", + "0x22", + "0x40780017fff7fff", + "0xc", + "0x48127ff07fff8000", + "0x48127ff17fff8000", + "0x48127ff17fff8000", "0x10780017fff7fff", - "0x24", + "0x50", + "0x40780017fff7fff", + "0x17", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x7533325f737562204f766572666c6f77", + "0x400080007ffe7fff", + "0x482480017fd78000", + "0x3", + "0x48127ffd7fff8000", + "0x482480017ffc8000", + "0x1", "0x10780017fff7fff", - "0x1e", + "0x42", + "0x40780017fff7fff", + "0x2", + "0x482480017ff18000", + "0x2", + "0x48127ff67fff8000", + "0x1104800180018000", + "0xbce", + "0x20680017fff7ffd", + "0x34", + "0x48127ffc7fff8000", + "0x48127ffe7fff8000", + "0x48527fff7ffa8000", + "0x48307fff7fe98000", + "0xa0680017fff8004", + "0xe", + "0x4824800180047ffe", + "0x100000000000000000000000000000000000000000000000000000000000000", + "0x484480017ffe8000", + "0x7000000000000110000000000000000", + "0x48307ffe7fff8002", + "0x480080007ff87ffc", + "0x480080017ff77ffc", + "0x402480017ffb7ffd", + "0xf8ffffffffffffeeffffffffffffffff", + "0x400080027ff67ffd", "0x10780017fff7fff", - "0x18", + "0x16", + "0x484480017fff8001", + "0x1000000000000000000000000000000", + "0x48307fff80007ffd", + "0x480080007ff97ffd", + "0x480080017ff87ffd", + "0x402480017ffc7ffe", + "0xff000000000000000000000000000000", + "0x400080027ff77ffe", + "0x40780017fff7fff", + "0x1", + "0x400280007ff97ff9", + "0x482480017ff68000", + "0x3", + "0x480a7ff87fff8000", + "0x482680017ff98000", + "0x1", + "0x48127fc87fff8000", + "0x480a7ffb7fff8000", "0x10780017fff7fff", - "0x12", + "0xdc", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x400080007ffe7fff", + "0x482480017ff48000", + "0x3", + "0x48127ffd7fff8000", + "0x482480017ffc8000", + "0x1", "0x10780017fff7fff", + "0x31", + "0x40780017fff7fff", "0xc", + "0x48127ff07fff8000", + "0x48127ff17fff8000", + "0x48127ff17fff8000", "0x10780017fff7fff", - "0x6", + "0x2a", + "0x40780017fff7fff", + "0x1f", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", + "0x7533325f737562204f766572666c6f77", + "0x400080007ffe7fff", + "0x482480017fd78000", + "0x1", + "0x48127ffd7fff8000", + "0x482480017ffc8000", "0x1", "0x10780017fff7fff", - "0x3c", - "0x480680017fff8000", - "0x100", + "0x1c", + "0x40780017fff7fff", + "0x25", + "0x48127fd77fff8000", + "0x48127fd87fff8000", + "0x48127fd87fff8000", "0x10780017fff7fff", - "0x38", + "0x15", + "0x40780017fff7fff", + "0x30", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x10000", + "0x7533325f737562204f766572666c6f77", + "0x400080007ffe7fff", + "0x482480017fbf8000", + "0x5", + "0x48127ffd7fff8000", + "0x482480017ffc8000", + "0x1", "0x10780017fff7fff", - "0x34", + "0x7", + "0x40780017fff7fff", + "0x3d", + "0x48127fbf7fff8000", + "0x48127fc07fff8000", + "0x48127fc07fff8000", + "0x48127ffd7fff8000", "0x480680017fff8000", - "0x1000000", - "0x10780017fff7fff", - "0x30", + "0x1", "0x480680017fff8000", - "0x100000000", - "0x10780017fff7fff", - "0x2c", + "0x0", "0x480680017fff8000", - "0x10000000000", + "0x0", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x2c", + "0xa0680017fff8000", + "0x16", + "0x480080007fd18003", + "0x480080017fd08003", + "0x4844800180017ffe", + "0x100000000000000000000000000000000", + "0x483180017ffd7ffc", + "0x482480017fff7ffd", + "0x800000000000010fffffffffffffffff7ffffffffffffef0000000000000001", + "0x20680017fff7ffc", + "0x6", + "0x402480017fff7ffd", + "0xffffffffffffffffffffffffffffffff", "0x10780017fff7fff", - "0x28", + "0x4", + "0x402480017ffe7ffd", + "0xf7ffffffffffffef0000000000000000", + "0x400080027fcc7ffd", + "0x20680017fff7ffe", + "0xe", + "0x402780017fff7fff", + "0x1", + "0x400180007fd17ffc", + "0x40780017fff7fff", + "0x5", + "0x482480017fcc8000", + "0x1", + "0x480a7ffc7fff8000", "0x480680017fff8000", - "0x1000000000000", + "0x0", "0x10780017fff7fff", - "0x24", + "0x6", + "0x482480017fcc8000", + "0x3", + "0x48127ffe7fff8000", + "0x48127ffc7fff8000", "0x480680017fff8000", - "0x100000000000000", + "0x1f", + "0x48287ffb80017fff", + "0xa0680017fff7fff", + "0x7", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400080007ff97fff", "0x10780017fff7fff", - "0x20", + "0x82", + "0x400080007ffa7fff", "0x480680017fff8000", - "0x10000000000000000", + "0x10", + "0x48307fff80017ffe", + "0xa0680017fff7fff", + "0x7", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400080017ff67fff", "0x10780017fff7fff", - "0x1c", + "0x2f", + "0x400080017ff77fff", "0x480680017fff8000", - "0x1000000000000000000", + "0x10", + "0x48307fff80017ffb", + "0xa0680017fff7fff", + "0x7", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400080027ff37fff", "0x10780017fff7fff", - "0x18", - "0x480680017fff8000", - "0x100000000000000000000", + "0x16", + "0x400080027ff47fff", + "0x482480017ff48000", + "0x3", + "0x48127ffe7fff8000", + "0x1104800180018000", + "0xb15", + "0x20680017fff7ffd", + "0x7", + "0x48127ffc7fff8000", + "0x484480017ffe8000", + "0x100000000000000000000000000000000", "0x10780017fff7fff", - "0x14", + "0x22", + "0x40780017fff7fff", + "0xc", + "0x48127ff07fff8000", + "0x48127ff17fff8000", + "0x48127ff17fff8000", + "0x10780017fff7fff", + "0x56", + "0x40780017fff7fff", + "0x17", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x10000000000000000000000", + "0x7533325f737562204f766572666c6f77", + "0x400080007ffe7fff", + "0x482480017fda8000", + "0x3", + "0x48127ffd7fff8000", + "0x482480017ffc8000", + "0x1", "0x10780017fff7fff", - "0x10", + "0x48", + "0x40780017fff7fff", + "0x2", + "0x482480017ff48000", + "0x2", + "0x48127ff87fff8000", + "0x1104800180018000", + "0xaf2", + "0x20680017fff7ffd", + "0x3a", + "0x48127ffc7fff8000", + "0x48127ffe7fff8000", + "0x48527fff7ffa8000", + "0x48307fff7fe58000", + "0xa0680017fff8004", + "0xe", + "0x4824800180047ffe", + "0x100000000000000000000000000000000000000000000000000000000000000", + "0x484480017ffe8000", + "0x7000000000000110000000000000000", + "0x48307ffe7fff8002", + "0x480080007ff87ffc", + "0x480080017ff77ffc", + "0x402480017ffb7ffd", + "0xf8ffffffffffffeeffffffffffffffff", + "0x400080027ff67ffd", + "0x10780017fff7fff", + "0x1c", + "0x484480017fff8001", + "0x1000000000000000000000000000000", + "0x48307fff80007ffd", + "0x480080007ff97ffd", + "0x480080017ff87ffd", + "0x402480017ffc7ffe", + "0xff000000000000000000000000000000", + "0x400080027ff77ffe", + "0x40780017fff7fff", + "0x1", + "0x400280007ff97ff9", + "0x482480017ff68000", + "0x3", + "0x480a7ff87fff8000", + "0x482680017ff98000", + "0x1", + "0x48127fda7fff8000", + "0x480a7ffb7fff8000", + "0x48127ffb7fff8000", "0x480680017fff8000", - "0x1000000000000000000000000", + "0x0", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x48127f9d7fff8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x400080007ffe7fff", + "0x482480017ff48000", + "0x3", + "0x48127ffd7fff8000", + "0x482480017ffc8000", + "0x1", "0x10780017fff7fff", + "0x15", + "0x40780017fff7fff", "0xc", - "0x480680017fff8000", - "0x100000000000000000000000000", + "0x48127ff07fff8000", + "0x48127ff17fff8000", + "0x48127ff17fff8000", "0x10780017fff7fff", - "0x8", + "0xe", + "0x40780017fff7fff", + "0x1d", + "0x40780017fff7fff", + "0x1", "0x480680017fff8000", - "0x10000000000000000000000000000", - "0x10780017fff7fff", - "0x4", + "0x7533325f737562204f766572666c6f77", + "0x400080007ffe7fff", + "0x482480017fda8000", + "0x1", + "0x48127ffd7fff8000", + "0x482480017ffc8000", + "0x1", + "0x48127ffd7fff8000", "0x480680017fff8000", - "0x1000000000000000000000000000000", - "0x48127ffe7fff8000", + "0x1", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", - "0x48127ffc7fff8000", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0x2", + "0x5a", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x6e5f627974657320746f6f20626967", + "0x7533325f737562204f766572666c6f77", "0x400080007ffe7fff", - "0x482680017ffc8000", + "0x482480017f9e8000", "0x1", "0x480680017fff8000", "0x1", - "0x48127ffc7fff8000", - "0x482480017ffb8000", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x48127ffa7fff8000", + "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x1104800180018000", - "0x16c", - "0x482480017fff8000", - "0x16b", - "0x480080007fff8000", - "0x480080017fff8000", - "0x484480017fff8000", - "0x8", + "0x40780017fff7fff", + "0x40", + "0x480680017fff8000", + "0x10", + "0x48317fff80017ffd", + "0xa0680017fff7fff", + "0x7", "0x482480017fff8000", - "0x3b06", - "0xa0680017fff8000", - "0x8", - "0x48317ffe80007ff8", + "0x100000000000000000000000000000000", + "0x400080007fba7fff", + "0x10780017fff7fff", + "0x2f", + "0x400080007fbb7fff", + "0x480680017fff8000", + "0x10", + "0x48317fff80017ffd", + "0xa0680017fff7fff", + "0x7", "0x482480017fff8000", "0x100000000000000000000000000000000", - "0x400280007ff77fff", + "0x400080017fb77fff", "0x10780017fff7fff", - "0x45", - "0x48317ffe80007ff8", - "0x400280007ff77fff", - "0x482680017ff78000", - "0x1", - "0x48297ffa80007ffb", - "0x20680017fff7fff", - "0x4", - "0x10780017fff7fff", - "0xa", - "0x482680017ffa8000", + "0x16", + "0x400080017fb87fff", + "0x482480017fb88000", "0x2", - "0x480a7ffb7fff8000", - "0x480680017fff8000", - "0x0", - "0x480a7ffa7fff8000", + "0x48127ffe7fff8000", + "0x1104800180018000", + "0xa6b", + "0x20680017fff7ffd", + "0x7", + "0x48127ffc7fff8000", + "0x484480017ffe8000", + "0x100000000000000000000000000000000", "0x10780017fff7fff", - "0x8", - "0x480a7ffa7fff8000", - "0x480a7ffb7fff8000", - "0x480680017fff8000", + "0x22", + "0x40780017fff7fff", + "0x9", + "0x48127ff37fff8000", + "0x48127ff47fff8000", + "0x48127ff47fff8000", + "0x10780017fff7fff", + "0x58", + "0x40780017fff7fff", + "0x14", + "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x0", - "0x20680017fff7ffe", - "0x22", - "0x48127ffa7fff8000", - "0x480a7ff97fff8000", - "0x480a7ffc7fff8000", + "0x7533325f737562204f766572666c6f77", + "0x400080007ffe7fff", + "0x482480017fa18000", + "0x2", + "0x48127ffd7fff8000", + "0x482480017ffc8000", + "0x1", + "0x10780017fff7fff", + "0x4a", + "0x40780017fff7fff", + "0x2", + "0x482480017fb88000", + "0x1", "0x480a7ffd7fff8000", - "0x480080007ffb8000", - "0x480080017ffa8000", "0x1104800180018000", - "0x37", + "0xa48", "0x20680017fff7ffd", - "0xc", - "0x48127ffb7fff8000", - "0x48127fa87fff8000", - "0x48127ffa7fff8000", - "0x48127fa97fff8000", - "0x48127fa97fff8000", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffc5", - "0x208b7fff7fff7ffe", - "0x48127ffb7fff8000", - "0x48127fa87fff8000", - "0x48127ffa7fff8000", - "0x480680017fff8000", - "0x1", + "0x3c", + "0x48127ffc7fff8000", + "0x48127ffe7fff8000", + "0x48527fff7ffa8000", + "0x48327fff7ffc8000", + "0xa0680017fff8004", + "0xe", + "0x4824800180047ffe", + "0x100000000000000000000000000000000000000000000000000000000000000", + "0x484480017ffe8000", + "0x7000000000000110000000000000000", + "0x48307ffe7fff8002", + "0x480080007ff87ffc", + "0x480080017ff77ffc", + "0x402480017ffb7ffd", + "0xf8ffffffffffffeeffffffffffffffff", + "0x400080027ff67ffd", + "0x10780017fff7fff", + "0x19", + "0x484480017fff8001", + "0x1000000000000000000000000000000", + "0x48307fff80007ffd", + "0x480080007ff97ffd", + "0x480080017ff87ffd", + "0x402480017ffc7ffe", + "0xff000000000000000000000000000000", + "0x400080027ff77ffe", + "0x40780017fff7fff", + "0x3", + "0x400280007ff97ff7", + "0x482480017ff48000", + "0x3", "0x480680017fff8000", "0x0", + "0x480a7ff87fff8000", + "0x482680017ff98000", + "0x1", "0x480680017fff8000", "0x0", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x208b7fff7fff7ffe", - "0x48127ffa7fff8000", - "0x48127ff87fff8000", - "0x480a7ff97fff8000", "0x480680017fff8000", "0x0", - "0x48127ff87fff8000", - "0x48127ff87fff8000", - "0x480a7ffc7fff8000", - "0x480a7ffd7fff8000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4f7574206f6620676173", + "0x4f7074696f6e3a3a756e77726170206661696c65642e", "0x400080007ffe7fff", - "0x482680017ff78000", - "0x1", - "0x480a7ff87fff8000", - "0x480a7ff97fff8000", + "0x482480017ff48000", + "0x3", "0x480680017fff8000", "0x1", "0x480680017fff8000", "0x0", "0x480680017fff8000", "0x0", - "0x48127ff87fff8000", - "0x482480017ff78000", + "0x48127ffa7fff8000", + "0x482480017ff98000", "0x1", "0x208b7fff7fff7ffe", - "0x400380007ff97ffd", + "0x40780017fff7fff", + "0x9", + "0x48127ff37fff8000", + "0x48127ff47fff8000", + "0x48127ff47fff8000", + "0x48127ffd7fff8000", "0x480680017fff8000", - "0xff00ff00ff00ff00ff00ff00ff00ff", - "0x400280017ff97fff", - "0x480280027ff98000", - "0x484480017fff8000", - "0xffff", - "0x48327fff7ffd8000", - "0x400280057ff97fff", + "0x1", "0x480680017fff8000", - "0xffff0000ffff0000ffff0000ffff00", - "0x400280067ff97fff", - "0x480280077ff98000", - "0x484480017fff8000", - "0xffffffff", - "0x48307fff7ffc8000", - "0x4002800a7ff97fff", + "0x0", "0x480680017fff8000", - "0xffffffff00000000ffffffff000000", - "0x4002800b7ff97fff", - "0x4802800c7ff98000", - "0x484480017fff8000", - "0xffffffffffffffff", - "0x48307fff7ffc8000", - "0x4002800f7ff97fff", + "0x0", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x45", + "0x482680017ff78000", + "0x2", + "0x20780017fff7ffb", + "0xc", + "0x40780017fff7fff", + "0x1b", + "0x48127fe47fff8000", "0x480680017fff8000", - "0xffffffffffffffff00000000000000", - "0x400280107ff97fff", - "0x480280117ff98000", - "0x484480017fff8000", - "0xffffffffffffffffffffffffffffffff", - "0x48307fff7ffc8000", - "0x484480017fff8000", - "0x800000000000010fffffffffffffff7ffffffffffffef000000000000000001", + "0x0", + "0x480a7ff87fff8000", + "0x480a7ff97fff8000", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", + "0x208b7fff7fff7ffe", "0x480680017fff8000", - "0x10000000000000000", - "0x480280007ff88005", - "0x480280017ff88005", - "0x4824800180047ffe", - "0x1", - "0x48307ffd7ffe7ffc", - "0x480280027ff87ffd", - "0xa0680017fff7ffd", - "0x6", - "0x482480017ff97ffd", - "0xffffffffffffffff0000000000000000", - "0x10780017fff7fff", - "0x4", - "0x482480017fff7ffd", - "0xffffffffffffffff0000000000000000", - "0x400280037ff87ffc", - "0x40507ffe7ff87ffd", - "0x40307fff7ffd7ff7", - "0x482680017ff98000", - "0x14", - "0xa0680017fff8000", - "0x7", - "0x4824800180007ffc", - "0x10000000000000000", - "0x400280047ff87fff", - "0x10780017fff7fff", - "0x99", - "0x482480017ffc8000", - "0xffffffffffffffff0000000000000000", - "0x400280047ff87fff", - "0xa0680017fff8000", + "0x10", + "0x48317fff80017ffd", + "0xa0680017fff7fff", "0x7", - "0x4824800180007ffb", - "0x10000000000000000", - "0x400280057ff87fff", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400080007ffb7fff", "0x10780017fff7fff", - "0x81", - "0x482480017ffb8000", - "0xffffffffffffffff0000000000000000", - "0x400280057ff87fff", - "0x400280007ffb7ffa", - "0x400280017ffb7ff9", - "0x400180007ffb7ffc", - "0x480680017fff8000", - "0xff00ff00ff00ff00ff00ff00ff00ff", - "0x400080017ffa7fff", - "0x480080027ffa8000", - "0x484480017fff8000", - "0xffff", - "0x48327fff7ffc8000", - "0x400080057ff77fff", - "0x480680017fff8000", - "0xffff0000ffff0000ffff0000ffff00", - "0x400080067ff67fff", - "0x480080077ff68000", - "0x484480017fff8000", - "0xffffffff", - "0x48307fff7ffc8000", - "0x4000800a7ff37fff", - "0x480680017fff8000", - "0xffffffff00000000ffffffff000000", - "0x4000800b7ff27fff", - "0x4800800c7ff28000", - "0x484480017fff8000", - "0xffffffffffffffff", - "0x48307fff7ffc8000", - "0x4000800f7fef7fff", - "0x480680017fff8000", - "0xffffffffffffffff00000000000000", - "0x400080107fee7fff", - "0x480080117fee8000", - "0x484480017fff8000", - "0xffffffffffffffffffffffffffffffff", - "0x48307fff7ffc8000", - "0x484480017fff8000", - "0x800000000000010fffffffffffffff7ffffffffffffef000000000000000001", + "0x2f", + "0x400080007ffc7fff", "0x480680017fff8000", - "0x10000000000000000", - "0x480280067ff88005", - "0x480280077ff88005", - "0x4824800180047ffe", - "0x1", - "0x48307ffd7ffe7ffc", - "0x480280087ff87ffd", - "0xa0680017fff7ffd", - "0x6", - "0x482480017ff97ffd", - "0xffffffffffffffff0000000000000000", + "0x10", + "0x48317fff80017ffd", + "0xa0680017fff7fff", + "0x7", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400080017ff87fff", "0x10780017fff7fff", - "0x4", - "0x482480017fff7ffd", - "0xffffffffffffffff0000000000000000", - "0x400280097ff87ffc", - "0x40507ffe7ff87ffd", - "0x40307fff7ffd7ff7", - "0x480a7ffa7fff8000", - "0x482680017ffb8000", + "0x16", + "0x400080017ff97fff", + "0x482480017ff98000", "0x2", - "0x482480017fe08000", - "0x14", - "0xa0680017fff8000", + "0x48127ffe7fff8000", + "0x1104800180018000", + "0x9d2", + "0x20680017fff7ffd", "0x7", - "0x4824800180007ffa", - "0x10000000000000000", - "0x4002800a7ff87fff", + "0x48127ffc7fff8000", + "0x484480017ffe8000", + "0x100000000000000000000000000000000", "0x10780017fff7fff", - "0x28", - "0x482480017ffa8000", - "0xffffffffffffffff0000000000000000", - "0x4002800a7ff87fff", - "0xa0680017fff8000", - "0x7", - "0x4824800180007ff9", - "0x10000000000000000", - "0x4002800b7ff87fff", + "0x22", + "0x40780017fff7fff", + "0x4", + "0x48127ff87fff8000", + "0x48127ff97fff8000", + "0x48127ff97fff8000", "0x10780017fff7fff", - "0x12", - "0x482480017ff98000", - "0xffffffffffffffff0000000000000000", - "0x4002800b7ff87fff", + "0x49", "0x40780017fff7fff", - "0x5", - "0x400080007ff57ff3", - "0x400080017ff57ff2", - "0x482680017ff88000", - "0xc", - "0x48127ff57fff8000", - "0x480680017fff8000", - "0x0", - "0x48127ff17fff8000", - "0x482480017ff18000", - "0x2", - "0x208b7fff7fff7ffe", + "0xf", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x7533325f737562204f766572666c6f77", "0x400080007ffe7fff", - "0x482680017ff88000", - "0xc", + "0x482480017fe78000", + "0x2", "0x48127ffd7fff8000", "0x482480017ffc8000", "0x1", "0x10780017fff7fff", - "0xe", + "0x3b", "0x40780017fff7fff", "0x2", + "0x482480017ff98000", + "0x1", + "0x480a7ffd7fff8000", + "0x1104800180018000", + "0x9af", + "0x20680017fff7ffd", + "0x2d", + "0x48127ffc7fff8000", + "0x48127ffe7fff8000", + "0xa0680017fff8000", + "0x8", + "0x482a7ffd7ffb8000", + "0x4824800180007fff", + "0x100000000", + "0x400080007ffb7fff", + "0x10780017fff7fff", + "0x12", + "0x482a7ffd7ffb8001", + "0x4824800180007fff", + "0xffffffffffffffffffffffff00000000", + "0x400080007ffb7ffe", "0x40780017fff7fff", "0x1", + "0x48527ffb7ffa8000", + "0x482480017ff98000", + "0x1", "0x480680017fff8000", - "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x0", + "0x480a7ff87fff8000", + "0x480a7ff97fff8000", + "0x48327ffb7ffc8000", + "0x48127ff87fff8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x7533325f616464204f766572666c6f77", "0x400080007ffe7fff", - "0x482680017ff88000", - "0xb", - "0x48127ffd7fff8000", - "0x482480017ffc8000", + "0x482480017ff98000", + "0x1", + "0x480680017fff8000", "0x1", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x4", + "0x48127ff87fff8000", + "0x48127ff97fff8000", + "0x48127ff97fff8000", "0x48127ffd7fff8000", - "0x48127ff57fff8000", "0x480680017fff8000", "0x1", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", "0x208b7fff7fff7ffe", "0x40780017fff7fff", - "0x20", + "0x63", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x7533325f616464204f766572666c6f77", "0x400080007ffe7fff", - "0x482680017ff88000", - "0x6", - "0x48127ffd7fff8000", - "0x482480017ffc8000", + "0x482680017ff78000", + "0x1", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x48127ffa7fff8000", + "0x482480017ff98000", "0x1", + "0x208b7fff7fff7ffe", + "0xa0680017fff8000", + "0x7", + "0x482680017ff98000", + "0xfffffffffffffffffffffffffffff916", + "0x400280007ff87fff", "0x10780017fff7fff", - "0xe", - "0x40780017fff7fff", "0x22", + "0x4825800180007ff9", + "0x6ea", + "0x400280007ff87fff", + "0x482680017ff88000", + "0x1", + "0x48127ffe7fff8000", + "0x48297ffa80007ffb", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xf", + "0x480280007ffa8000", + "0x400280007ffd7fff", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", + "0x482680017ffa8000", + "0x1", + "0x480a7ffb7fff8000", + "0x480a7ffc7fff8000", + "0x482680017ffd8000", + "0x1", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffe5", + "0x208b7fff7fff7ffe", + "0x48127ffd7fff8000", + "0x482480017ffd8000", + "0x686", + "0x480680017fff8000", + "0x0", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", + "0x208b7fff7fff7ffe", "0x40780017fff7fff", "0x1", "0x480680017fff8000", - "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x4f7574206f6620676173", "0x400080007ffe7fff", "0x482680017ff88000", - "0x5", - "0x48127ffd7fff8000", - "0x482480017ffc8000", "0x1", - "0x48127ffd7fff8000", - "0x48127fd57fff8000", + "0x480a7ff97fff8000", "0x480680017fff8000", "0x1", "0x48127ffb7fff8000", - "0x48127ffb7fff8000", - "0x208b7fff7fff7ffe", - "0x208b7fff7fff7ffe", - "0x6a09e667", - "0xbb67ae85", - "0x3c6ef372", - "0xa54ff53a", - "0x510e527f", - "0x9b05688c", - "0x1f83d9ab", - "0x5be0cd19", + "0x482480017ffa8000", + "0x1", "0x208b7fff7fff7ffe", - "0xc", - "0x10", - "0x14", - "0x1c", - "0x10", - "0x18", - "0x0", + "0x48297ffc80007ffd", + "0x20680017fff7fff", "0x4", - "0xc", - "0x0", - "0x8", - "0x10", - "0x18", - "0x14", - "0x0", - "0x18", - "0x1c", - "0x20" - ], - "bytecode_segment_lengths": [ - 229, - 180, - 265, - 510, - 171, - 310, - 264, - 178, - 253, - 265, - 253, - 174, - 199, - 111, - 302, - 104, - 104, - 113, - 104, - 157, - 172, - 93, - 127, - 127, - 243, - 188, - 268, + "0x10780017fff7fff", + "0x93", + "0x482680017ffc8000", + "0x1", + "0x480a7ffd7fff8000", + "0x480280007ffc8000", + "0x48307ffd80007ffe", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xa", + "0x482480017ffc8000", + "0x1", + "0x48127ffc7fff8000", + "0x480680017fff8000", + "0x0", + "0x48127ff97fff8000", + "0x10780017fff7fff", + "0x8", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x20680017fff7ffe", + "0x6c", + "0x480080007fff8000", + "0xa0680017fff8000", + "0x12", + "0x4824800180007ffe", + "0x10000000000000000", + "0x4844800180008002", + "0x8000000000000110000000000000000", + "0x4830800080017ffe", + "0x480280007ffb7fff", + "0x482480017ffe8000", + "0xefffffffffffffdeffffffffffffffff", + "0x480280017ffb7fff", + "0x400280027ffb7ffb", + "0x402480017fff7ffb", + "0xffffffffffffffffffffffffffffffff", + "0x20680017fff7fff", + "0x55", + "0x402780017fff7fff", + "0x1", + "0x400280007ffb7ffe", + "0x482480017ffe8000", + "0xffffffffffffffff0000000000000000", + "0x400280017ffb7fff", + "0x482680017ffb8000", + "0x2", + "0x48307ff880007ff9", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xa", + "0x482480017ff78000", + "0x1", + "0x48127ff77fff8000", + "0x480680017fff8000", + "0x0", + "0x48127ff47fff8000", + "0x10780017fff7fff", + "0x8", + "0x48127ff77fff8000", + "0x48127ff77fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x20680017fff7ffe", + "0x2a", + "0x480080007fff8000", + "0xa0680017fff8000", + "0x16", + "0x480080007ff88003", + "0x480080017ff78003", + "0x4844800180017ffe", + "0x100000000000000000000000000000000", + "0x483080017ffd7ffb", + "0x482480017fff7ffd", + "0x800000000000010fffffffffffffffff7ffffffffffffef0000000000000001", + "0x20680017fff7ffc", + "0x6", + "0x402480017fff7ffd", + "0xffffffffffffffffffffffffffffffff", + "0x10780017fff7fff", + "0x4", + "0x402480017ffe7ffd", + "0xf7ffffffffffffef0000000000000000", + "0x400080027ff37ffd", + "0x20680017fff7ffe", + "0x11", + "0x402780017fff7fff", + "0x1", + "0x400080007ff87ffe", + "0x40780017fff7fff", + "0x5", + "0x482480017ff38000", + "0x1", + "0x48127ff47fff8000", + "0x48127ff47fff8000", + "0x480680017fff8000", + "0x0", + "0x48127fe67fff8000", + "0x48127feb7fff8000", + "0x48127ff37fff8000", + "0x208b7fff7fff7ffe", + "0x482480017ff38000", + "0x3", + "0x10780017fff7fff", + "0x5", + "0x40780017fff7fff", + "0x7", + "0x48127ff37fff8000", + "0x48127ff47fff8000", + "0x48127ff47fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x8", + "0x482680017ffb8000", + "0x3", + "0x10780017fff7fff", + "0x5", + "0x40780017fff7fff", + "0x10", + "0x480a7ffb7fff8000", + "0x48127feb7fff8000", + "0x48127feb7fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x18", + "0x480a7ffb7fff8000", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x208b7fff7fff7ffe", + "0x480680017fff8000", + "0x10000000000000000", + "0x480280007ff98005", + "0x480280017ff98005", + "0x4824800180047ffe", + "0x1", + "0x48307ffd7ffe7ffc", + "0x480280027ff97ffd", + "0xa0680017fff7ffd", + "0x6", + "0x482480017ff97ffd", + "0xffffffffffffffff0000000000000000", + "0x10780017fff7fff", + "0x4", + "0x482480017fff7ffd", + "0xffffffffffffffff0000000000000000", + "0x400280037ff97ffc", + "0x40507ffe7ff87ffd", + "0x40317fff7ffd7ffc", + "0xa0680017fff8000", + "0x7", + "0x4824800180007ffd", + "0x10000000000000000", + "0x400280047ff97fff", + "0x10780017fff7fff", + "0x73", + "0x482480017ffd8000", + "0xffffffffffffffff0000000000000000", + "0x400280047ff97fff", + "0xa0680017fff8000", + "0x7", + "0x4824800180007ffc", + "0x10000000000000000", + "0x400280057ff97fff", + "0x10780017fff7fff", + "0x5b", + "0x482480017ffc8000", + "0xffffffffffffffff0000000000000000", + "0x400280057ff97fff", + "0x400280007ffb7ffb", + "0x400280017ffb7ffa", + "0x480680017fff8000", + "0x10000000000000000", + "0x480280067ff98005", + "0x480280077ff98005", + "0x4824800180047ffe", + "0x1", + "0x48307ffd7ffe7ffc", + "0x480280087ff97ffd", + "0xa0680017fff7ffd", + "0x6", + "0x482480017ff97ffd", + "0xffffffffffffffff0000000000000000", + "0x10780017fff7fff", + "0x4", + "0x482480017fff7ffd", + "0xffffffffffffffff0000000000000000", + "0x400280097ff97ffc", + "0x40507ffe7ff87ffd", + "0x40317fff7ffd7ffd", + "0x480a7ffa7fff8000", + "0x482680017ffb8000", + "0x2", + "0xa0680017fff8000", + "0x7", + "0x4824800180007ffb", + "0x10000000000000000", + "0x4002800a7ff97fff", + "0x10780017fff7fff", + "0x27", + "0x482480017ffb8000", + "0xffffffffffffffff0000000000000000", + "0x4002800a7ff97fff", + "0xa0680017fff8000", + "0x7", + "0x4824800180007ffa", + "0x10000000000000000", + "0x4002800b7ff97fff", + "0x10780017fff7fff", + "0x11", + "0x482480017ffa8000", + "0xffffffffffffffff0000000000000000", + "0x4002800b7ff97fff", + "0x40780017fff7fff", + "0x5", + "0x400080007ff67ff4", + "0x400080017ff67ff3", + "0x482680017ff98000", + "0xc", + "0x480680017fff8000", + "0x0", + "0x48127ff37fff8000", + "0x482480017ff38000", + "0x2", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x400080007ffe7fff", + "0x482680017ff98000", + "0xc", + "0x48127ffd7fff8000", + "0x482480017ffc8000", + "0x1", + "0x10780017fff7fff", + "0xe", + "0x40780017fff7fff", + "0x2", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x400080007ffe7fff", + "0x482680017ff98000", + "0xb", + "0x48127ffd7fff8000", + "0x482480017ffc8000", + "0x1", + "0x48127ffd7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0xe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x400080007ffe7fff", + "0x482680017ff98000", + "0x6", + "0x48127ffd7fff8000", + "0x482480017ffc8000", + "0x1", + "0x10780017fff7fff", + "0xe", + "0x40780017fff7fff", + "0x10", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x400080007ffe7fff", + "0x482680017ff98000", + "0x5", + "0x48127ffd7fff8000", + "0x482480017ffc8000", + "0x1", + "0x48127ffd7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", + "0x208b7fff7fff7ffe", + "0xa0680017fff8000", + "0x7", + "0x482680017ffa8000", + "0xfffffffffffffffffffffffffffff678", + "0x400280007ff97fff", + "0x10780017fff7fff", + "0x44", + "0x4825800180007ffa", + "0x988", + "0x400280007ff97fff", + "0x482680017ff98000", + "0x1", + "0x48127ffe7fff8000", + "0x4825800180007ffd", + "0x1", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x2c", + "0x480680017fff8000", + "0x0", + "0x400280007ffc7fff", + "0x480680017fff8000", + "0x1", + "0x48127ffc7fff8000", + "0x480a7ffb7fff8000", + "0x482680017ffc8000", + "0x1", + "0x48317ffc80017ffd", + "0xa0680017fff7fff", + "0x7", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400080007ff57fff", + "0x10780017fff7fff", + "0xc", + "0x400080007ff67fff", + "0x482480017ff68000", + "0x1", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x48127ffb7fff8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffd6", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x7533325f737562204f766572666c6f77", + "0x400080007ffe7fff", + "0x482480017ff38000", + "0x1", + "0x482480017ff78000", + "0x3ca", + "0x480680017fff8000", + "0x1", + "0x48127ffb7fff8000", + "0x482480017ffa8000", + "0x1", + "0x208b7fff7fff7ffe", + "0x480680017fff8000", + "0x8000000000000000", + "0x400280007ffc7fff", + "0x48127ffc7fff8000", + "0x482480017ffc8000", + "0x85c", + "0x480680017fff8000", + "0x0", + "0x480a7ffb7fff8000", + "0x482680017ffc8000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x482680017ff98000", + "0x1", + "0x480a7ffa7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffb7fff8000", + "0x482480017ffa8000", + "0x1", + "0x208b7fff7fff7ffe", + "0x20780017fff7ffd", + "0x7", + "0x40780017fff7fff", + "0x3d", + "0x480a7ffb7fff8000", + "0x480a7ffc7fff8000", + "0x208b7fff7fff7ffe", + "0x480680017fff8000", + "0x0", + "0x400280007ffc7fff", + "0x4825800180007ffd", + "0x1", + "0x480a7ffb7fff8000", + "0x482680017ffc8000", + "0x1", + "0x20680017fff7ffd", + "0x7", + "0x40780017fff7fff", + "0x39", + "0x48127fc57fff8000", + "0x48127fc57fff8000", + "0x208b7fff7fff7ffe", + "0x480680017fff8000", + "0x0", + "0x400080007ffe7fff", + "0x4825800180007ffd", + "0x2", + "0x48127ffc7fff8000", + "0x482480017ffc8000", + "0x1", + "0x20680017fff7ffd", + "0x7", + "0x40780017fff7fff", + "0x35", + "0x48127fc97fff8000", + "0x48127fc97fff8000", + "0x208b7fff7fff7ffe", + "0x480680017fff8000", + "0x0", + "0x400080007ffe7fff", + "0x4825800180007ffd", + "0x3", + "0x48127ffc7fff8000", + "0x482480017ffc8000", + "0x1", + "0x20680017fff7ffd", + "0x7", + "0x40780017fff7fff", + "0x31", + "0x48127fcd7fff8000", + "0x48127fcd7fff8000", + "0x208b7fff7fff7ffe", + "0x480680017fff8000", + "0x0", + "0x400080007ffe7fff", + "0x4825800180007ffd", + "0x4", + "0x48127ffc7fff8000", + "0x482480017ffc8000", + "0x1", + "0x20680017fff7ffd", + "0x7", + "0x40780017fff7fff", + "0x2d", + "0x48127fd17fff8000", + "0x48127fd17fff8000", + "0x208b7fff7fff7ffe", + "0x480680017fff8000", + "0x0", + "0x400080007ffe7fff", + "0x4825800180007ffd", + "0x5", + "0x48127ffc7fff8000", + "0x482480017ffc8000", + "0x1", + "0x20680017fff7ffd", + "0x7", + "0x40780017fff7fff", + "0x29", + "0x48127fd57fff8000", + "0x48127fd57fff8000", + "0x208b7fff7fff7ffe", + "0x480680017fff8000", + "0x0", + "0x400080007ffe7fff", + "0x4825800180007ffd", + "0x6", + "0x48127ffc7fff8000", + "0x482480017ffc8000", + "0x1", + "0x20680017fff7ffd", + "0x7", + "0x40780017fff7fff", + "0x25", + "0x48127fd97fff8000", + "0x48127fd97fff8000", + "0x208b7fff7fff7ffe", + "0x480680017fff8000", + "0x0", + "0x400080007ffe7fff", + "0x4825800180007ffd", + "0x7", + "0x48127ffc7fff8000", + "0x482480017ffc8000", + "0x1", + "0x20680017fff7ffd", + "0x7", + "0x40780017fff7fff", + "0x21", + "0x48127fdd7fff8000", + "0x48127fdd7fff8000", + "0x208b7fff7fff7ffe", + "0x480680017fff8000", + "0x0", + "0x400080007ffe7fff", + "0x4825800180007ffd", + "0x8", + "0x48127ffc7fff8000", + "0x482480017ffc8000", + "0x1", + "0x20680017fff7ffd", + "0x7", + "0x40780017fff7fff", + "0x1d", + "0x48127fe17fff8000", + "0x48127fe17fff8000", + "0x208b7fff7fff7ffe", + "0x480680017fff8000", + "0x0", + "0x400080007ffe7fff", + "0x4825800180007ffd", + "0x9", + "0x48127ffc7fff8000", + "0x482480017ffc8000", + "0x1", + "0x20680017fff7ffd", + "0x7", + "0x40780017fff7fff", + "0x19", + "0x48127fe57fff8000", + "0x48127fe57fff8000", + "0x208b7fff7fff7ffe", + "0x480680017fff8000", + "0x0", + "0x400080007ffe7fff", + "0x4825800180007ffd", + "0xa", + "0x48127ffc7fff8000", + "0x482480017ffc8000", + "0x1", + "0x20680017fff7ffd", + "0x7", + "0x40780017fff7fff", + "0x15", + "0x48127fe97fff8000", + "0x48127fe97fff8000", + "0x208b7fff7fff7ffe", + "0x480680017fff8000", + "0x0", + "0x400080007ffe7fff", + "0x4825800180007ffd", + "0xb", + "0x48127ffc7fff8000", + "0x482480017ffc8000", + "0x1", + "0x20680017fff7ffd", + "0x7", + "0x40780017fff7fff", + "0x11", + "0x48127fed7fff8000", + "0x48127fed7fff8000", + "0x208b7fff7fff7ffe", + "0x480680017fff8000", + "0x0", + "0x400080007ffe7fff", + "0x4825800180007ffd", + "0xc", + "0x48127ffc7fff8000", + "0x482480017ffc8000", + "0x1", + "0x20680017fff7ffd", + "0x7", + "0x40780017fff7fff", + "0xd", + "0x48127ff17fff8000", + "0x48127ff17fff8000", + "0x208b7fff7fff7ffe", + "0x480680017fff8000", + "0x0", + "0x400080007ffe7fff", + "0x4825800180007ffd", + "0xd", + "0x48127ffc7fff8000", + "0x482480017ffc8000", + "0x1", + "0x20680017fff7ffd", + "0x7", + "0x40780017fff7fff", + "0x9", + "0x48127ff57fff8000", + "0x48127ff57fff8000", + "0x208b7fff7fff7ffe", + "0x480680017fff8000", + "0x0", + "0x400080007ffe7fff", + "0x4825800180007ffd", + "0xe", + "0x48127ffc7fff8000", + "0x482480017ffc8000", + "0x1", + "0x20680017fff7ffd", + "0x7", + "0x40780017fff7fff", + "0x5", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x208b7fff7fff7ffe", + "0x480680017fff8000", + "0x0", + "0x400080007ffe7fff", + "0x4825800180007ffd", + "0xf", + "0x48127ffc7fff8000", + "0x482480017ffc8000", + "0x1", + "0x20680017fff7ffd", + "0x7", + "0x40780017fff7fff", + "0x1", + "0x48127ffd7fff8000", + "0x48127ffd7fff8000", + "0x208b7fff7fff7ffe", + "0x480680017fff8000", + "0x0", + "0x400080007ffe7fff", + "0x48127ffd7fff8000", + "0x482480017ffd8000", + "0x1", + "0x208b7fff7fff7ffe", + "0x480680017fff8000", + "0x536563703235366b31476574506f696e7446726f6d58", + "0x400280007ff67fff", + "0x400380017ff67ff5", + "0x400380027ff67ff9", + "0x400380037ff67ffa", + "0x400380047ff67ffd", + "0x480280067ff68000", + "0x20680017fff7fff", + "0x48a", + "0x480280057ff68000", + "0x480280077ff68000", + "0x480280087ff68000", + "0x482680017ff68000", + "0x9", + "0x48127ffc7fff8000", + "0x20680017fff7ffc", + "0x475", + "0x48127fff7fff8000", + "0x480680017fff8000", + "0x29bfcdb2dce28d959f2815b16f81798", + "0x480680017fff8000", + "0x79be667ef9dcbbac55a06295ce870b07", + "0x480680017fff8000", + "0xfd17b448a68554199c47d08ffb10d4b8", + "0x480680017fff8000", + "0x483ada7726a3c4655da4fbfc0e1108a8", + "0x480680017fff8000", + "0x536563703235366b314e6577", + "0x400080007ff87fff", + "0x400080017ff87ffa", + "0x400080027ff87ffb", + "0x400080037ff87ffc", + "0x400080047ff87ffd", + "0x400080057ff87ffe", + "0x480080077ff88000", + "0x20680017fff7fff", + "0x450", + "0x480080067ff78000", + "0x480080087ff68000", + "0x480080097ff58000", + "0x482480017ff48000", + "0xa", + "0x48127ffc7fff8000", + "0x20680017fff7ffc", + "0x439", + "0x480680017fff8000", + "0xbaaedce6af48a03bbfd25e8cd0364141", + "0x480680017fff8000", + "0xfffffffffffffffffffffffffffffffe", + "0x48127ffd7fff8000", + "0xa0680017fff8000", + "0x37", + "0x480280007ff48001", + "0x480280017ff48001", + "0x480280027ff48001", + "0x480280037ff48001", + "0x48307ffe80017ff9", + "0x40780017fff7fff", + "0x12", + "0x20680017fff7fee", + "0x8", + "0x40307fea7fef7fe5", + "0x402480017ff07fef", + "0x1", + "0x400280047ff47ff0", + "0x10780017fff7fff", + "0x3", + "0x400280047ff47fee", + "0x482480017ff98001", + "0x1", + "0x48307ff080018000", + "0x4844800180018000", + "0x100000000000000000000000000000000", + "0x4850800080008000", + "0x48307fff7ff68000", + "0x48307ff67fff8000", + "0x48307ff77fff8000", + "0x48307feb80007fff", + "0x48307feb80007fff", + "0x48307fec80007fff", + "0x4844800180007fff", + "0x100000000000000000000000000000000", + "0x4824800180007fff", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffff8001", + "0x400280057ff47fff", + "0x482480017ffe8000", + "0xffffffffffffffffffffffffffff8000", + "0x400280067ff47fff", + "0x48307ffd7fef8000", + "0x48307ff07fff8000", + "0x48307ff07fff8000", + "0x48307fe680007fff", + "0x48307fe380007fff", + "0x48307fe580007fff", + "0x4844800180007fff", + "0x100000000000000000000000000000000", + "0x4824800180007fff", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffff8001", + "0x400280077ff47fff", + "0x482480017ffe8000", + "0xffffffffffffffffffffffffffff8000", + "0x400280087ff47fff", + "0x40307ffd7fea7fe2", + "0x10780017fff7fff", + "0x31", + "0x480280007ff47fff", + "0x480280017ff47fff", + "0x480280027ff47fff", + "0x480280037ff47fff", + "0x480280047ff47fff", + "0x400280057ff47fff", + "0xa0680017fff7ffb", + "0xa", + "0x402480017fff7ff9", + "0x1", + "0x20680017fff7fff", + "0x6", + "0x400680017fff7ff7", + "0x0", + "0x400680017fff7ff6", + "0x1", + "0xa0680017fff7ffa", + "0xc", + "0x48507ff87ffb8001", + "0x48507ff77ffc8001", + "0xa0680017fff8002", + "0x5", + "0x48307ffa7ff88000", + "0x90780017fff7fff", + "0x11", + "0x48127ff57fff8000", + "0x90780017fff7fff", + "0xe", + "0x48507ff97ffa8001", + "0x48507ff87ffb8001", + "0x480680017fff7ff9", + "0x0", + "0x480680017fff7ffa", + "0x0", + "0xa0680017fff8000", + "0x5", + "0x40307ff77ff57ffe", + "0x10780017fff7fff", + "0x3", + "0x40127ff47fff7ffe", + "0x482480017ffe8000", + "0xfffffffffffffffe0000000000000000", + "0x400280067ff47fff", + "0x40317ff97ffb7ffa", + "0x40307ffa7ffc7ff0", + "0x10780017fff7fff", + "0x380", + "0x4824800180008002", + "0xffffffffffffffff0000000000000000", + "0x480280097ff48001", + "0x4802800a7ff47ffe", + "0x4002800b7ff47ffe", + "0x484480017ffe8000", + "0x10000000000000000", + "0x40307ffc7fff7fcc", + "0x48507fd37ffc8000", + "0x48507fd27ffc8000", + "0x4824800180018002", + "0xffffffffffffffff0000000000000000", + "0x4802800c7ff48001", + "0x4802800d7ff47fff", + "0x4002800e7ff47ffd", + "0x484480017ffd8000", + "0x10000000000000000", + "0x40307ffd7fff7ffb", + "0x484480017ffd8000", + "0x10000000000000000", + "0x48307fff7ff98003", + "0x482480017fff8000", + "0xfffffffffffffffe0000000000000000", + "0x4802800f7ff47fff", + "0x480280107ff47ffd", + "0x400280117ff47fda", + "0x404480017ffc7ffe", + "0x100000000000000000000000000000000", + "0x40307fda7ffe7fff", + "0x40307ffc7ff77fdb", + "0x4824800180008002", + "0xffffffffffffffff0000000000000000", + "0x480280127ff48001", + "0x480280137ff47ffe", + "0x400280147ff47ffe", + "0x484480017ffe8000", + "0x10000000000000000", + "0x40307ffc7fff7fbd", + "0x48507fc37ffc8000", + "0x48507fc27ffc8000", + "0x4824800180018002", + "0xffffffffffffffff0000000000000000", + "0x480280157ff48001", + "0x480280167ff47fff", + "0x400280177ff47ffd", + "0x484480017ffd8000", + "0x10000000000000000", + "0x40307ffd7fff7ffb", + "0x484480017ffd8000", + "0x10000000000000000", + "0x48307fff7ff98003", + "0x482480017fff8000", + "0xfffffffffffffffe0000000000000000", + "0x480280187ff47fff", + "0x480280197ff47ffd", + "0x4002801a7ff47fc9", + "0x404480017ffc7ffe", + "0x100000000000000000000000000000000", + "0x40307fc97ffe7fff", + "0x40307ffc7ff77fca", + "0x4824800180008002", + "0xffffffffffffffff0000000000000000", + "0x4802801b7ff48001", + "0x4802801c7ff47ffe", + "0x4002801d7ff47ffe", + "0x484480017ffe8000", + "0x10000000000000000", + "0x40307ffc7fff7fad", + "0x48507fb57ffc8000", + "0x48507fb47ffc8000", + "0x4824800180018002", + "0xffffffffffffffff0000000000000000", + "0x4802801e7ff48001", + "0x4802801f7ff47fff", + "0x400280207ff47ffd", + "0x484480017ffd8000", + "0x10000000000000000", + "0x40307ffd7fff7ffb", + "0x484480017ffd8000", + "0x10000000000000000", + "0x48307fff7ff98003", + "0x482480017fff8000", + "0xfffffffffffffffe0000000000000000", + "0x480280217ff47fff", + "0x480280227ff47ffd", + "0x400280237ff47fb8", + "0x404480017ffc7ffe", + "0x100000000000000000000000000000000", + "0x40307fb87ffe7fff", + "0x40307ffc7ff77fb9", + "0x4824800180008002", + "0xffffffffffffffff0000000000000000", + "0x480280247ff48001", + "0x480280257ff47ffe", + "0x400280267ff47ffe", + "0x484480017ffe8000", + "0x10000000000000000", + "0x40307ffc7fff7f9e", + "0x48507fa57ffc8000", + "0x48507fa47ffc8000", + "0x4824800180018002", + "0xffffffffffffffff0000000000000000", + "0x480280277ff48001", + "0x480280287ff47fff", + "0x400280297ff47ffd", + "0x484480017ffd8000", + "0x10000000000000000", + "0x40307ffd7fff7ffb", + "0x484480017ffd8000", + "0x10000000000000000", + "0x48307fff7ff98003", + "0x482480017fff8000", + "0xfffffffffffffffe0000000000000000", + "0x4802802a7ff47fff", + "0x4802802b7ff47ffd", + "0x4002802c7ff47fa7", + "0x404480017ffc7ffe", + "0x100000000000000000000000000000000", + "0x40307fa77ffe7fff", + "0x40307ffc7ff77fa8", + "0x4824800180008002", + "0xffffffffffffffff0000000000000000", + "0x4802802d7ff48001", + "0x4802802e7ff47ffe", + "0x4002802f7ff47ffe", + "0x484480017ffe8000", + "0x10000000000000000", + "0x40307ffc7fff7f95", + "0x48487ffa7ffc8000", + "0x48487ffa7ffc8000", + "0x4824800180018002", + "0xffffffffffffffff0000000000000000", + "0x480280307ff48001", + "0x480280317ff47fff", + "0x400280327ff47ffd", + "0x484480017ffd8000", + "0x10000000000000000", + "0x40307ffd7fff7ffb", + "0x484480017ffd8000", + "0x10000000000000000", + "0x48307fff7ff98003", + "0x482480017fff8000", + "0xfffffffffffffffe0000000000000000", + "0x480280337ff47fff", + "0x480280347ff47ffd", + "0x400280357ff47f96", + "0x404480017ffc7ffe", + "0x100000000000000000000000000000000", + "0x40307f967ffe7fff", + "0x40307ffc7ff77f97", + "0x4824800180008002", + "0xffffffffffffffff0000000000000000", + "0x480280367ff48001", + "0x480280377ff47ffe", + "0x400280387ff47ffe", + "0x484480017ffe8000", + "0x10000000000000000", + "0x40307ffc7fff7f86", + "0x48487ff97ffc8000", + "0x48487ff97ffc8000", + "0x4824800180018002", + "0xffffffffffffffff0000000000000000", + "0x480280397ff48001", + "0x4802803a7ff47fff", + "0x4002803b7ff47ffd", + "0x484480017ffd8000", + "0x10000000000000000", + "0x40307ffd7fff7ffb", + "0x484480017ffd8000", + "0x10000000000000000", + "0x48307fff7ff98003", + "0x482480017fff8000", + "0xfffffffffffffffe0000000000000000", + "0x4802803c7ff47fff", + "0x4802803d7ff47ffd", + "0x4002803e7ff47f85", + "0x404480017ffc7ffe", + "0x100000000000000000000000000000000", + "0x40307f857ffe7fff", + "0x40307ffc7ff77f86", + "0x4824800180008002", + "0xffffffffffffffff0000000000000000", + "0x4802803f7ff48001", + "0x480280407ff47ffe", + "0x400280417ff47ffe", + "0x484480017ffe8000", + "0x10000000000000000", + "0x40307ffc7fff7f76", + "0x48487ffa7ffc8000", + "0x48487ffa7ffc8000", + "0x4824800180018002", + "0xffffffffffffffff0000000000000000", + "0x480280427ff48001", + "0x480280437ff47fff", + "0x400280447ff47ffd", + "0x484480017ffd8000", + "0x10000000000000000", + "0x40307ffd7fff7ffb", + "0x484480017ffd8000", + "0x10000000000000000", + "0x48307fff7ff98003", + "0x482480017fff8000", + "0xfffffffffffffffe0000000000000000", + "0x480280457ff47fff", + "0x480280467ff47ffd", + "0x400280477ff47f74", + "0x404480017ffc7ffe", + "0x100000000000000000000000000000000", + "0x40307f747ffe7fff", + "0x40307ffc7ff77f75", + "0x4824800180008002", + "0xffffffffffffffff0000000000000000", + "0x480280487ff48001", + "0x480280497ff47ffe", + "0x4002804a7ff47ffe", + "0x484480017ffe8000", + "0x10000000000000000", + "0x40307ffc7fff7f67", + "0x48487ff97ffc8000", + "0x48487ff97ffc8000", + "0x4824800180018002", + "0xffffffffffffffff0000000000000000", + "0x4802804b7ff48001", + "0x4802804c7ff47fff", + "0x4002804d7ff47ffd", + "0x484480017ffd8000", + "0x10000000000000000", + "0x40307ffd7fff7ffb", + "0x484480017ffd8000", + "0x10000000000000000", + "0x48307fff7ff98003", + "0x482480017fff8000", + "0xfffffffffffffffe0000000000000000", + "0x4802804e7ff47fff", + "0x4802804f7ff47ffd", + "0x400280507ff47f63", + "0x404480017ffc7ffe", + "0x100000000000000000000000000000000", + "0x40307f637ffe7fff", + "0x40307ffc7ff77f64", + "0x482680017ff48000", + "0x51", + "0x480a7ff77fff8000", + "0x480a7ff87fff8000", + "0x48127f597fff8000", + "0x48127f597fff8000", + "0x1104800180018000", + "0x404", + "0x480680017fff8000", + "0xbaaedce6af48a03bbfd25e8cd0364141", + "0x480680017fff8000", + "0xfffffffffffffffffffffffffffffffe", + "0x480080007ff98000", + "0x480080017ff88000", + "0x480080027ff78000", + "0x480080037ff68000", + "0x480080047ff58000", + "0x480080057ff48000", + "0x48307fff80007ff9", + "0x40780017fff7fff", + "0xc", + "0x20680017fff7ff3", + "0x8", + "0x40307ff17ff47feb", + "0x402480017ff57ff4", + "0x1", + "0x400080067fe67ff5", + "0x10780017fff7fff", + "0x3", + "0x400080067fe67ff3", + "0x48307ff17ff68000", + "0x48307fe680007fff", + "0x4844800180007fff", + "0x100000000000000000000000000000000", + "0x40507fff7fff7fff", + "0x48307ff47fff8000", + "0x48307ff47fff8000", + "0x48307ff57fff8000", + "0x48307fec7fff8000", + "0x48307fe180007fff", + "0x4844800180007fff", + "0x100000000000000000000000000000000", + "0x400080077fdd7fff", + "0x482480017fff8000", + "0xfffffffffffffffffffffffffffffffc", + "0x400080087fdc7fff", + "0x48307fef7ffe8000", + "0x48307ff07fff8000", + "0x48307ff07fff8000", + "0x48307ff17fff8000", + "0x48307fdb80007fff", + "0x4844800180007fff", + "0x100000000000000000000000000000000", + "0x400080097fd67fff", + "0x482480017fff8000", + "0xfffffffffffffffffffffffffffffffc", + "0x4000800a7fd57fff", + "0xa0680017fff7fdf", + "0xc", + "0xa0680017fff8001", + "0x6", + "0x48127fd97fff7ffe", + "0x40127fdb7fff7ffe", + "0x10780017fff7fff", + "0x10", + "0x48127fdc7fff7ffe", + "0x40127fd87fff7ffe", + "0x10780017fff7fff", + "0xc", + "0x480680017fff7fda", + "0x0", + "0xa0680017fff8000", + "0x6", + "0x40127fd77fff7ffd", + "0x40127fdc7fff7ffe", + "0x10780017fff7fff", + "0x4", + "0x40127fdc7fff7ffd", + "0x40127fd77fff7ffe", + "0x482480017ffd8000", + "0xffffffffffffffff0000000000000000", + "0x4000800b7fd17fff", + "0x48507ffd7ffc8000", + "0x48307fe97ff98000", + "0x48307fe67fff8000", + "0x40307ffd7fff7fd2", + "0x4824800180008002", + "0xffffffffffffffff0000000000000000", + "0x4800800c7fcd8001", + "0x4800800d7fcc7ffe", + "0x4000800e7fcb7ffe", + "0x484480017ffe8000", + "0x10000000000000000", + "0x40307ffc7fff7fd3", + "0x48507fcf7ffc8000", + "0x48507fce7ffc8000", + "0x4824800180018002", + "0xffffffffffffffff0000000000000000", + "0x4800800f7fc78001", + "0x480080107fc67fff", + "0x400080117fc57ffd", + "0x484480017ffd8000", + "0x10000000000000000", + "0x40307ffd7fff7ffb", + "0x484480017ffd8000", + "0x10000000000000000", + "0x48307fff7ff98003", + "0x482480017fff8000", + "0xfffffffffffffffe0000000000000000", + "0x480080127fc17fff", + "0x480080137fc07ffd", + "0x400080147fbf7fd7", + "0x404480017ffc7ffe", + "0x100000000000000000000000000000000", + "0x40307fd77ffe7fff", + "0x40307ffc7ff77fd8", + "0x4824800180008002", + "0xffffffffffffffff0000000000000000", + "0x480080157fbe8001", + "0x480080167fbd7ffe", + "0x400080177fbc7ffe", + "0x484480017ffe8000", + "0x10000000000000000", + "0x40307ffc7fff7fc3", + "0x48507fc17ffc8000", + "0x48507fc07ffc8000", + "0x4824800180018002", + "0xffffffffffffffff0000000000000000", + "0x480080187fb88001", + "0x480080197fb77fff", + "0x4000801a7fb67ffd", + "0x484480017ffd8000", + "0x10000000000000000", + "0x40307ffd7fff7ffb", + "0x484480017ffd8000", + "0x10000000000000000", + "0x48307fff7ff98003", + "0x482480017fff8000", + "0xfffffffffffffffe0000000000000000", + "0x4800801b7fb27fff", + "0x4800801c7fb17ffd", + "0x4000801d7fb07fc6", + "0x404480017ffc7ffe", + "0x100000000000000000000000000000000", + "0x40307fc67ffe7fff", + "0x40307ffc7ff77fc7", + "0x4824800180008002", + "0xffffffffffffffff0000000000000000", + "0x4800801e7faf8001", + "0x4800801f7fae7ffe", + "0x400080207fad7ffe", + "0x484480017ffe8000", + "0x10000000000000000", + "0x40307ffc7fff7fb4", + "0x48507fb17ffc8000", + "0x48507fb07ffc8000", + "0x4824800180018002", + "0xffffffffffffffff0000000000000000", + "0x480080217fa98001", + "0x480080227fa87fff", + "0x400080237fa77ffd", + "0x484480017ffd8000", + "0x10000000000000000", + "0x40307ffd7fff7ffb", + "0x484480017ffd8000", + "0x10000000000000000", + "0x48307fff7ff98003", + "0x482480017fff8000", + "0xfffffffffffffffe0000000000000000", + "0x480080247fa37fff", + "0x480080257fa27ffd", + "0x400080267fa17fb3", + "0x404480017ffc7ffe", + "0x100000000000000000000000000000000", + "0x40307fb37ffe7fff", + "0x40307ffc7ff77fb4", + "0x4824800180008002", + "0xffffffffffffffff0000000000000000", + "0x480080277fa08001", + "0x480080287f9f7ffe", + "0x400080297f9e7ffe", + "0x484480017ffe8000", + "0x10000000000000000", + "0x40307ffc7fff7fa4", + "0x48507fa37ffc8000", + "0x48507fa27ffc8000", + "0x4824800180018002", + "0xffffffffffffffff0000000000000000", + "0x4800802a7f9a8001", + "0x4800802b7f997fff", + "0x4000802c7f987ffd", + "0x484480017ffd8000", + "0x10000000000000000", + "0x40307ffd7fff7ffb", + "0x484480017ffd8000", + "0x10000000000000000", + "0x48307fff7ff98003", + "0x482480017fff8000", + "0xfffffffffffffffe0000000000000000", + "0x4800802d7f947fff", + "0x4800802e7f937ffd", + "0x4000802f7f927fa6", + "0x404480017ffc7ffe", + "0x100000000000000000000000000000000", + "0x40307fa67ffe7fff", + "0x40307ffc7ff77fa7", + "0x4824800180008002", + "0xffffffffffffffff0000000000000000", + "0x480080307f918001", + "0x480080317f907ffe", + "0x400080327f8f7ffe", + "0x484480017ffe8000", + "0x10000000000000000", + "0x40307ffc7fff7f95", + "0x48507f937ffc8000", + "0x48507f927ffc8000", + "0x4824800180018002", + "0xffffffffffffffff0000000000000000", + "0x480080337f8b8001", + "0x480080347f8a7fff", + "0x400080357f897ffd", + "0x484480017ffd8000", + "0x10000000000000000", + "0x40307ffd7fff7ffb", + "0x484480017ffd8000", + "0x10000000000000000", + "0x48307fff7ff98003", + "0x482480017fff8000", + "0xfffffffffffffffe0000000000000000", + "0x480080367f857fff", + "0x480080377f847ffd", + "0x400080387f837f93", + "0x404480017ffc7ffe", + "0x100000000000000000000000000000000", + "0x40307f937ffe7fff", + "0x40307ffc7ff77f94", + "0x480680017fff8000", + "0xfffffffffffffffffffffffffffffffe", + "0x48127e6a7fff8000", + "0x48307f8d80017ffe", + "0xa0680017fff7fff", + "0x7", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400080397f7e7fff", + "0x10780017fff7fff", + "0xd", + "0x400080397f7f7fff", + "0x40780017fff7fff", + "0x1", + "0x482480017f7e8000", + "0x3a", + "0x48127ffb7fff8000", + "0x48127ffc7fff8000", + "0x480680017fff8000", + "0x0", + "0x10780017fff7fff", + "0x9", + "0x482480017f7e8000", + "0x3a", + "0x482480017ffb8000", + "0xa", + "0x48127ffd7fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0xbaaedce6af48a03bbfd25e8cd0364141", + "0x48307f8480017fff", + "0xa0680017fff7fff", + "0x7", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400080007ff87fff", + "0x10780017fff7fff", + "0xd", + "0x400080007ff97fff", + "0x40780017fff7fff", + "0x5", + "0x482480017ff48000", + "0x1", + "0x482480017ff48000", + "0x208", + "0x48127ff87fff8000", + "0x48127ff37fff8000", + "0x10780017fff7fff", + "0x13", + "0x480680017fff8000", + "0x1", + "0x48127ff87fff8000", + "0x48307ffe80017ff8", + "0xa0680017fff7fff", + "0x7", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400080017ff37fff", + "0x10780017fff7fff", + "0x153", + "0x400080017ff47fff", + "0x482480017ff48000", + "0x2", + "0x48127ffc7fff8000", + "0x48127ff97fff8000", + "0x48127ffc7fff8000", + "0x20680017fff7ff3", + "0x144", + "0x48127ffc7fff8000", + "0x480a7ffb7fff8000", + "0x480a7ffc7fff8000", + "0x48127e567fff8000", + "0x48127e567fff8000", + "0x1104800180018000", + "0x2d4", + "0x480680017fff8000", + "0xbaaedce6af48a03bbfd25e8cd0364141", + "0x480680017fff8000", + "0xfffffffffffffffffffffffffffffffe", + "0x480080007ff98000", + "0x480080017ff88000", + "0x480080027ff78000", + "0x480080037ff68000", + "0x480080047ff58000", + "0x480080057ff48000", + "0x48307fff80007ff9", + "0x40780017fff7fff", + "0xc", + "0x20680017fff7ff3", + "0x8", + "0x40307ff17ff47feb", + "0x402480017ff57ff4", + "0x1", + "0x400080067fe67ff5", + "0x10780017fff7fff", + "0x3", + "0x400080067fe67ff3", + "0x48307ff17ff68000", + "0x48307fe680007fff", + "0x4844800180007fff", + "0x100000000000000000000000000000000", + "0x40507fff7fff7fff", + "0x48307ff47fff8000", + "0x48307ff47fff8000", + "0x48307ff57fff8000", + "0x48307fec7fff8000", + "0x48307fe180007fff", + "0x4844800180007fff", + "0x100000000000000000000000000000000", + "0x400080077fdd7fff", + "0x482480017fff8000", + "0xfffffffffffffffffffffffffffffffc", + "0x400080087fdc7fff", + "0x48307fef7ffe8000", + "0x48307ff07fff8000", + "0x48307ff07fff8000", + "0x48307ff17fff8000", + "0x48307fdb80007fff", + "0x4844800180007fff", + "0x100000000000000000000000000000000", + "0x400080097fd67fff", + "0x482480017fff8000", + "0xfffffffffffffffffffffffffffffffc", + "0x4000800a7fd57fff", + "0xa0680017fff7fdf", + "0xc", + "0xa0680017fff8001", + "0x6", + "0x48127fd97fff7ffe", + "0x40127fdb7fff7ffe", + "0x10780017fff7fff", + "0x10", + "0x48127fdc7fff7ffe", + "0x40127fd87fff7ffe", + "0x10780017fff7fff", + "0xc", + "0x480680017fff7fda", + "0x0", + "0xa0680017fff8000", + "0x6", + "0x40127fd77fff7ffd", + "0x40127fdc7fff7ffe", + "0x10780017fff7fff", + "0x4", + "0x40127fdc7fff7ffd", + "0x40127fd77fff7ffe", + "0x482480017ffd8000", + "0xffffffffffffffff0000000000000000", + "0x4000800b7fd17fff", + "0x48507ffd7ffc8000", + "0x48307fe97ff98000", + "0x48307fe67fff8000", + "0x40307ffd7fff7fd2", + "0x4824800180008002", + "0xffffffffffffffff0000000000000000", + "0x4800800c7fcd8001", + "0x4800800d7fcc7ffe", + "0x4000800e7fcb7ffe", + "0x484480017ffe8000", + "0x10000000000000000", + "0x40307ffc7fff7fd3", + "0x48507fcf7ffc8000", + "0x48507fce7ffc8000", + "0x4824800180018002", + "0xffffffffffffffff0000000000000000", + "0x4800800f7fc78001", + "0x480080107fc67fff", + "0x400080117fc57ffd", + "0x484480017ffd8000", + "0x10000000000000000", + "0x40307ffd7fff7ffb", + "0x484480017ffd8000", + "0x10000000000000000", + "0x48307fff7ff98003", + "0x482480017fff8000", + "0xfffffffffffffffe0000000000000000", + "0x480080127fc17fff", + "0x480080137fc07ffd", + "0x400080147fbf7fd7", + "0x404480017ffc7ffe", + "0x100000000000000000000000000000000", + "0x40307fd77ffe7fff", + "0x40307ffc7ff77fd8", + "0x4824800180008002", + "0xffffffffffffffff0000000000000000", + "0x480080157fbe8001", + "0x480080167fbd7ffe", + "0x400080177fbc7ffe", + "0x484480017ffe8000", + "0x10000000000000000", + "0x40307ffc7fff7fc3", + "0x48507fc17ffc8000", + "0x48507fc07ffc8000", + "0x4824800180018002", + "0xffffffffffffffff0000000000000000", + "0x480080187fb88001", + "0x480080197fb77fff", + "0x4000801a7fb67ffd", + "0x484480017ffd8000", + "0x10000000000000000", + "0x40307ffd7fff7ffb", + "0x484480017ffd8000", + "0x10000000000000000", + "0x48307fff7ff98003", + "0x482480017fff8000", + "0xfffffffffffffffe0000000000000000", + "0x4800801b7fb27fff", + "0x4800801c7fb17ffd", + "0x4000801d7fb07fc6", + "0x404480017ffc7ffe", + "0x100000000000000000000000000000000", + "0x40307fc67ffe7fff", + "0x40307ffc7ff77fc7", + "0x4824800180008002", + "0xffffffffffffffff0000000000000000", + "0x4800801e7faf8001", + "0x4800801f7fae7ffe", + "0x400080207fad7ffe", + "0x484480017ffe8000", + "0x10000000000000000", + "0x40307ffc7fff7fb4", + "0x48507fb17ffc8000", + "0x48507fb07ffc8000", + "0x4824800180018002", + "0xffffffffffffffff0000000000000000", + "0x480080217fa98001", + "0x480080227fa87fff", + "0x400080237fa77ffd", + "0x484480017ffd8000", + "0x10000000000000000", + "0x40307ffd7fff7ffb", + "0x484480017ffd8000", + "0x10000000000000000", + "0x48307fff7ff98003", + "0x482480017fff8000", + "0xfffffffffffffffe0000000000000000", + "0x480080247fa37fff", + "0x480080257fa27ffd", + "0x400080267fa17fb3", + "0x404480017ffc7ffe", + "0x100000000000000000000000000000000", + "0x40307fb37ffe7fff", + "0x40307ffc7ff77fb4", + "0x4824800180008002", + "0xffffffffffffffff0000000000000000", + "0x480080277fa08001", + "0x480080287f9f7ffe", + "0x400080297f9e7ffe", + "0x484480017ffe8000", + "0x10000000000000000", + "0x40307ffc7fff7fa4", + "0x48507fa37ffc8000", + "0x48507fa27ffc8000", + "0x4824800180018002", + "0xffffffffffffffff0000000000000000", + "0x4800802a7f9a8001", + "0x4800802b7f997fff", + "0x4000802c7f987ffd", + "0x484480017ffd8000", + "0x10000000000000000", + "0x40307ffd7fff7ffb", + "0x484480017ffd8000", + "0x10000000000000000", + "0x48307fff7ff98003", + "0x482480017fff8000", + "0xfffffffffffffffe0000000000000000", + "0x4800802d7f947fff", + "0x4800802e7f937ffd", + "0x4000802f7f927fa6", + "0x404480017ffc7ffe", + "0x100000000000000000000000000000000", + "0x40307fa67ffe7fff", + "0x40307ffc7ff77fa7", + "0x4824800180008002", + "0xffffffffffffffff0000000000000000", + "0x480080307f918001", + "0x480080317f907ffe", + "0x400080327f8f7ffe", + "0x484480017ffe8000", + "0x10000000000000000", + "0x40307ffc7fff7f95", + "0x48507f937ffc8000", + "0x48507f927ffc8000", + "0x4824800180018002", + "0xffffffffffffffff0000000000000000", + "0x480080337f8b8001", + "0x480080347f8a7fff", + "0x400080357f897ffd", + "0x484480017ffd8000", + "0x10000000000000000", + "0x40307ffd7fff7ffb", + "0x484480017ffd8000", + "0x10000000000000000", + "0x48307fff7ff98003", + "0x482480017fff8000", + "0xfffffffffffffffe0000000000000000", + "0x480080367f857fff", + "0x480080377f847ffd", + "0x400080387f837f93", + "0x404480017ffc7ffe", + "0x100000000000000000000000000000000", + "0x40307f937ffe7fff", + "0x40307ffc7ff77f94", + "0x48127f0f7fff8000", + "0x48127f0f7fff8000", + "0x48127f0f7fff8000", + "0x482480017f808000", + "0x39", + "0x480680017fff8000", + "0x536563703235366b314d756c", + "0x400080007d5f7fff", + "0x400080017d5f7ffb", + "0x400080027d5f7d5e", + "0x400080037d5f7ffc", + "0x400080047d5f7ffd", + "0x480080067d5f8000", + "0x20680017fff7fff", + "0x3d", + "0x480080057d5e8000", + "0x48127fff7fff8000", + "0x480080077d5c8000", + "0x480680017fff8000", + "0x536563703235366b314d756c", + "0x400080087d5a7fff", + "0x400080097d5a7ffd", + "0x4000800a7d5a7d4d", + "0x4000800b7d5a7f84", + "0x4000800c7d5a7f85", + "0x4800800e7d5a8000", + "0x20680017fff7fff", + "0x23", + "0x4800800d7d598000", + "0x48127fff7fff8000", + "0x4800800f7d578000", + "0x480680017fff8000", + "0x536563703235366b31416464", + "0x400080107d557fff", + "0x400080117d557ffd", + "0x400080127d557ff9", + "0x400080137d557ffe", + "0x480080157d558000", + "0x20680017fff7fff", + "0xd", + "0x480080147d548000", + "0x48127ff27fff8000", + "0x48127ffe7fff8000", + "0x482480017d518000", + "0x17", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480080167d4e8000", + "0x208b7fff7fff7ffe", + "0x480080147d548000", + "0x48127ff27fff8000", + "0x48127ffe7fff8000", + "0x482480017d518000", + "0x18", + "0x480680017fff8000", + "0x1", + "0x480080167d4f8000", + "0x480080177d4e8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x5", + "0x4800800d7d548000", + "0x48127ff27fff8000", + "0x482480017ffe8000", + "0x2a62", + "0x482480017d518000", + "0x11", + "0x480680017fff8000", + "0x1", + "0x4800800f7d4f8000", + "0x480080107d4e8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0xa", + "0x480080057d548000", + "0x48127ff27fff8000", + "0x482480017ffe8000", + "0x558c", + "0x482480017d518000", + "0x9", + "0x480680017fff8000", + "0x1", + "0x480080077d4f8000", + "0x480080087d4e8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0xfb", + "0x48127f017fff8000", + "0x482480017f018000", + "0x10f04", + "0x10780017fff7fff", + "0x8", + "0x40780017fff7fff", + "0xfe", + "0x482480017ef58000", + "0x2", + "0x482480017efd8000", + "0x11076", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x753235365f737562204f766572666c6f77", + "0x400080007ffe7fff", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", + "0x48127d517fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x27a", + "0x4824800180008002", + "0xffffffffffffffff0000000000000000", + "0x480280077ff48001", + "0x480280087ff47ffe", + "0x400280097ff47ffe", + "0x484480017ffe8000", + "0x10000000000000000", + "0x40307ffc7fff7d74", + "0x48507d787ffc8000", + "0x48507d777ffc8000", + "0x4824800180018002", + "0xffffffffffffffff0000000000000000", + "0x4802800a7ff48001", + "0x4802800b7ff47fff", + "0x4002800c7ff47ffd", + "0x484480017ffd8000", + "0x10000000000000000", + "0x40307ffd7fff7ffb", + "0x484480017ffd8000", + "0x10000000000000000", + "0x48307fff7ff98003", + "0x482480017fff8000", + "0xfffffffffffffffe0000000000000000", + "0x4802800d7ff47fff", + "0x4802800e7ff47ffd", + "0x4002800f7ff47d66", + "0x404480017ffc7ffe", + "0x100000000000000000000000000000000", + "0x40307d667ffe7fff", + "0x40307ffc7ff77d71", + "0x4824800180008002", + "0xffffffffffffffff0000000000000000", + "0x480280107ff48001", + "0x480280117ff47ffe", + "0x400280127ff47ffe", + "0x484480017ffe8000", + "0x10000000000000000", + "0x40307ffc7fff7d65", + "0x48507d677ffc8000", + "0x48507d667ffc8000", + "0x4824800180018002", + "0xffffffffffffffff0000000000000000", + "0x480280137ff48001", + "0x480280147ff47fff", + "0x400280157ff47ffd", + "0x484480017ffd8000", + "0x10000000000000000", + "0x40307ffd7fff7ffb", + "0x484480017ffd8000", + "0x10000000000000000", + "0x48307fff7ff98003", + "0x482480017fff8000", + "0xfffffffffffffffe0000000000000000", + "0x480280167ff47fff", + "0x480280177ff47ffd", + "0x400380187ff47ff9", + "0x404480017ffc7ffe", + "0x100000000000000000000000000000000", + "0x40287ff97ffe7fff", + "0x40307ffc7ff77d61", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x400080007ffe7fff", + "0x482680017ff48000", + "0x19", + "0x482480017d568000", + "0x1f0cc", + "0x48127d517fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x2a5", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x400080007ffe7fff", + "0x482480017d588000", + "0x210e8", + "0x48127d567fff8000", + "0x48127ffc7fff8000", + "0x482480017ffb8000", + "0x1", + "0x10780017fff7fff", + "0xb", + "0x40780017fff7fff", + "0x2ab", + "0x480080067d4c8000", + "0x482480017fff8000", + "0x21430", + "0x482480017d4a8000", + "0xa", + "0x480080087d498000", + "0x480080097d488000", + "0x480a7ff47fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x2b7", + "0x480a7ff47fff8000", + "0x482480017d478000", + "0x24234", + "0x48127d457fff8000", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x2bb", + "0x480280057ff68000", + "0x480a7ff47fff8000", + "0x482480017ffe8000", + "0x24400", + "0x482680017ff68000", + "0x9", + "0x480680017fff8000", + "0x1", + "0x480280077ff68000", + "0x480280087ff68000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x2", + "0x480680017fff8000", + "0x536563703235366b314765745879", + "0x400280007ffc7fff", + "0x400380017ffc7ffa", + "0x400380027ffc7ffd", + "0x480280047ffc8000", + "0x20680017fff7fff", + "0xd7", + "0x480280037ffc8000", + "0x480280057ffc8000", + "0x480280067ffc8000", + "0x480280077ffc8000", + "0x480280087ffc8000", + "0x4800800080007ffc", + "0x400080017fff7ffc", + "0x400080027fff7ffd", + "0x400080037fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480a7ff97fff8000", + "0x48127ff87fff8000", + "0x480a7ffb7fff8000", + "0x48127ffb7fff8000", + "0x482480017ffa8000", + "0x4", + "0x48127ffa7fff8000", + "0x48127ff97fff8000", + "0x402780017ffc8001", + "0x9", + "0x1104800180018000", + "0x267", + "0x40137ffa7fff8000", + "0x20680017fff7ffb", + "0xa5", + "0x48127ff87fff8000", + "0x48127ff87fff8000", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffeb5b", + "0x20680017fff7ffd", + "0x88", + "0x48127ffc7fff8000", + "0x480680017fff8000", + "0x4b656363616b", + "0x4002800080017fff", + "0x4002800180017ffe", + "0x4002800280017ffc", + "0x4002800380017ffd", + "0x4802800580018000", + "0x20680017fff7fff", + "0x6b", + "0x4802800480018000", + "0x4802800780018000", + "0x4002800080007fff", + "0x480680017fff8000", + "0xff00ff00ff00ff00ff00ff00ff00ff", + "0x4002800180007fff", + "0x4802800280008000", + "0x484480017fff8000", + "0xffff", + "0x48307fff7ffc8000", + "0x4002800580007fff", + "0x480680017fff8000", + "0xffff0000ffff0000ffff0000ffff00", + "0x4002800680007fff", + "0x4802800780008000", + "0x484480017fff8000", + "0xffffffff", + "0x48307fff7ffc8000", + "0x4002800a80007fff", + "0x480680017fff8000", + "0xffffffff00000000ffffffff000000", + "0x4002800b80007fff", + "0x4802800c80008000", + "0x484480017fff8000", + "0xffffffffffffffff", + "0x48307fff7ffc8000", + "0x4002800f80007fff", + "0x480680017fff8000", + "0xffffffffffffffff00000000000000", + "0x4002801080007fff", + "0x4802801180008000", + "0x484480017fff8000", + "0xffffffffffffffffffffffffffffffff", + "0x48307fff7ffc8000", + "0x4802800680018000", + "0x4002801480007fff", + "0x480680017fff8000", + "0xff00ff00ff00ff00ff00ff00ff00ff", + "0x4002801580007fff", + "0x4802801680008000", + "0x484480017fff8000", + "0xffff", + "0x48307fff7ffc8000", + "0x4002801980007fff", + "0x480680017fff8000", + "0xffff0000ffff0000ffff0000ffff00", + "0x4002801a80007fff", + "0x4802801b80008000", + "0x484480017fff8000", + "0xffffffff", + "0x48307fff7ffc8000", + "0x4002801e80007fff", + "0x480680017fff8000", + "0xffffffff00000000ffffffff000000", + "0x4002801f80007fff", + "0x4802802080008000", + "0x484480017fff8000", + "0xffffffffffffffff", + "0x48307fff7ffc8000", + "0x4002802380007fff", + "0x480680017fff8000", + "0xffffffffffffffff00000000000000", + "0x4002802480007fff", + "0x4802802580008000", + "0x484480017fff8000", + "0xffffffffffffffffffffffffffffffff", + "0x48307fff7ffc8000", + "0x484480017fff8000", + "0x800000000000010fffffffffffffff7ffffffffffffef000000000000000001", + "0x480680017fff8000", + "0x100000000", + "0x480080007fd38005", + "0x480080017fd28005", + "0x4824800180047ffe", + "0x1", + "0x48307ffd7ffe7ffc", + "0x480080027fcf7ffd", + "0xa0680017fff7ffd", + "0x6", + "0x482480017ff97ffd", + "0xffffffffffffffff0000000000000000", + "0x10780017fff7fff", + "0x4", + "0x482480017fff7ffd", + "0xffffffffffffffff0000000000000000", + "0x400080037fcc7ffc", + "0x40507ffe7ff87ffd", + "0x40307fff7ffd7ff7", + "0x484480017fff8000", + "0x100000000000000000000000000000000", + "0x484480017fe48000", + "0x800000000000010fffffffffffffff7ffffffffffffef000000000000000001", + "0x482480017fca8000", + "0x4", + "0x48127fd17fff8000", + "0x4826800180008000", + "0x28", + "0x4826800180018000", + "0x8", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x48307ff97ff88000", + "0x208b7fff7fff7ffe", + "0x4802800480018000", + "0x1104800180018000", + "0x35d", + "0x482480017fff8000", + "0x35c", + "0x480080007fff8000", + "0x480080017fff8000", + "0x484480017fff8000", + "0x8", + "0x482480017fff8000", + "0x1568", + "0x48127ff07fff8000", + "0x48307ffe7ff78000", + "0x4826800180018000", + "0x8", + "0x4802800680018000", + "0x4802800780018000", + "0x10780017fff7fff", + "0x22", + "0x1104800180018000", + "0x34b", + "0x482480017fff8000", + "0x34a", + "0x480080007fff8000", + "0x480080017fff8000", + "0x484480017fff8000", + "0x8", + "0x482480017fff8000", + "0x3ffc", + "0x48127ff47fff8000", + "0x48307ffe7ff48000", + "0x480a80017fff8000", + "0x48127ff47fff8000", + "0x48127ff47fff8000", + "0x10780017fff7fff", + "0x11", + "0x1104800180018000", + "0x33a", + "0x482480017fff8000", + "0x339", + "0x480080007fff8000", + "0x480080017fff8000", + "0x484480017fff8000", + "0x8", + "0x482480017fff8000", + "0x67f2", + "0x48127ff17fff8000", + "0x48307ffe7ff18000", + "0x480a80017fff8000", + "0x48127ff47fff8000", + "0x48127ff47fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x480a80007fff8000", + "0x48127ffa7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x208b7fff7fff7ffe", + "0x480280037ffc8000", + "0x1104800180018000", + "0x321", + "0x482480017fff8000", + "0x320", + "0x480080007fff8000", + "0x480080017fff8000", + "0x484480017fff8000", + "0x8", + "0x482480017fff8000", + "0x7b48", + "0x480a7ff97fff8000", + "0x48307ffe7ff78000", + "0x480a7ffb7fff8000", + "0x482680017ffc8000", + "0x7", + "0x480680017fff8000", + "0x1", + "0x480280057ffc8000", + "0x480280067ffc8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x2", + "0x4824800180008002", + "0xffffffffffffffff0000000000000000", + "0x480280007ff98001", + "0x480280017ff97ffe", + "0x400280027ff97ffe", + "0x484480017ffe8000", + "0x10000000000000000", + "0x40317ffc7fff7ffa", + "0x48487ffc7ffc8000", + "0x48487ffc7ffc8000", + "0x4824800180018002", + "0xffffffffffffffff0000000000000000", + "0x480280037ff98001", + "0x480280047ff97fff", + "0x400280057ff97ffd", + "0x484480017ffd8000", + "0x10000000000000000", + "0x40307ffd7fff7ffb", + "0x484480017ffd8000", + "0x10000000000000000", + "0x48307fff7ff98003", + "0x482480017fff8000", + "0xfffffffffffffffe0000000000000000", + "0x480280067ff97fff", + "0x480280077ff97ffd", + "0x400280087ff97ff0", + "0x404480017ffc7ffe", + "0x100000000000000000000000000000000", + "0x40307ff07ffe7fff", + "0x40307ffc7ff77fef", + "0x40780017fff7fff", + "0x2", + "0x4824800180008002", + "0xffffffffffffffff0000000000000000", + "0x480280097ff98001", + "0x4802800a7ff97ffe", + "0x4002800b7ff97ffe", + "0x484480017ffe8000", + "0x10000000000000000", + "0x40317ffc7fff7ffa", + "0x48487ffd7ffc8000", + "0x48487ffd7ffc8000", + "0x4824800180018002", + "0xffffffffffffffff0000000000000000", + "0x4802800c7ff98001", + "0x4802800d7ff97fff", + "0x4002800e7ff97ffd", + "0x484480017ffd8000", + "0x10000000000000000", + "0x40307ffd7fff7ffb", + "0x484480017ffd8000", + "0x10000000000000000", + "0x48307fff7ff98003", + "0x482480017fff8000", + "0xfffffffffffffffe0000000000000000", + "0x4802800f7ff97fff", + "0x480280107ff97ffd", + "0x400280117ff97ff0", + "0x404480017ffc7ffe", + "0x100000000000000000000000000000000", + "0x40307ff07ffe7fff", + "0x40307ffc7ff77fef", + "0x48307ff07fde8001", + "0xa0680017fff7fff", + "0x7", + "0x4824800180007fff", + "0x100000000000000000000000000000000", + "0x400280127ff97fff", + "0x10780017fff7fff", + "0xc", + "0x400280127ff97fff", + "0x40780017fff7fff", + "0x1", + "0x482680017ff98000", + "0x13", + "0x48127ffd7fff8000", + "0x480680017fff8000", + "0x0", + "0x10780017fff7fff", + "0x7", + "0x482680017ff98000", + "0x13", + "0x48127ffe7fff8000", + "0x480680017fff8000", + "0x1", + "0x40780017fff7fff", + "0x2", + "0x4824800180008002", + "0xffffffffffffffff0000000000000000", + "0x480080007ffa8001", + "0x480080017ff97ffe", + "0x400080027ff87ffe", + "0x484480017ffe8000", + "0x10000000000000000", + "0x40317ffc7fff7ffb", + "0x48487ffc7ffc8000", + "0x48487ffc7ffc8000", + "0x4824800180018002", + "0xffffffffffffffff0000000000000000", + "0x480080037ff48001", + "0x480080047ff37fff", + "0x400080057ff27ffd", + "0x484480017ffd8000", + "0x10000000000000000", + "0x40307ffd7fff7ffb", + "0x484480017ffd8000", + "0x10000000000000000", + "0x48307fff7ff98003", + "0x482480017fff8000", + "0xfffffffffffffffe0000000000000000", + "0x480080067fee7fff", + "0x480080077fed7ffd", + "0x400080087fec7ff0", + "0x404480017ffc7ffe", + "0x100000000000000000000000000000000", + "0x40307ff07ffe7fff", + "0x40307ffc7ff77fef", + "0x48307ff07fed8001", + "0xa0680017fff7fff", + "0x7", + "0x4824800180007fff", + "0x100000000000000000000000000000000", + "0x400080097fe97fff", + "0x10780017fff7fff", + "0xc", + "0x400080097fea7fff", + "0x40780017fff7fff", + "0x1", + "0x482480017fe98000", + "0xa", + "0x48127ffd7fff8000", + "0x480680017fff8000", + "0x0", + "0x10780017fff7fff", + "0x7", + "0x482480017fe98000", + "0xa", + "0x48127ffe7fff8000", + "0x480680017fff8000", + "0x1", + "0x48307fe97fd28001", + "0xa0680017fff7fff", + "0x7", + "0x4824800180007fff", + "0x100000000000000000000000000000000", + "0x400080007ffa7fff", + "0x10780017fff7fff", + "0xc", + "0x400080007ffb7fff", + "0x40780017fff7fff", + "0x1", + "0x482480017ffa8000", + "0x1", + "0x48127ffd7fff8000", + "0x480680017fff8000", + "0x0", + "0x10780017fff7fff", + "0x7", + "0x482480017ffa8000", + "0x1", + "0x48127ffe7fff8000", + "0x480680017fff8000", + "0x1", + "0x40780017fff7fff", + "0x2", + "0x4824800180008002", + "0xffffffffffffffff0000000000000000", + "0x480080007ffa8001", + "0x480080017ff97ffe", + "0x400080027ff87ffe", + "0x484480017ffe8000", + "0x10000000000000000", + "0x40317ffc7fff7ffb", + "0x48487ffd7ffc8000", + "0x48487ffd7ffc8000", + "0x4824800180018002", + "0xffffffffffffffff0000000000000000", + "0x480080037ff48001", + "0x480080047ff37fff", + "0x400080057ff27ffd", + "0x484480017ffd8000", + "0x10000000000000000", + "0x40307ffd7fff7ffb", + "0x484480017ffd8000", + "0x10000000000000000", + "0x48307fff7ff98003", + "0x482480017fff8000", + "0xfffffffffffffffe0000000000000000", + "0x480080067fee7fff", + "0x480080077fed7ffd", + "0x400080087fec7ff0", + "0x404480017ffc7ffe", + "0x100000000000000000000000000000000", + "0x40307ff07ffe7fff", + "0x40307ffc7ff77fef", + "0x48307ff07fed8001", + "0xa0680017fff7fff", + "0x7", + "0x4824800180007fff", + "0x100000000000000000000000000000000", + "0x400080097fe97fff", + "0x10780017fff7fff", + "0xc", + "0x400080097fea7fff", + "0x40780017fff7fff", + "0x1", + "0x482480017fe98000", + "0xa", + "0x48127ffd7fff8000", + "0x480680017fff8000", + "0x0", + "0x10780017fff7fff", + "0x7", + "0x482480017fe98000", + "0xa", + "0x48127ffe7fff8000", + "0x480680017fff8000", + "0x1", + "0x48307fe27fcb8000", + "0x48307fff7ffd8001", + "0xa0680017fff7fff", + "0x7", + "0x4824800180007fff", + "0x100000000000000000000000000000000", + "0x400080007ff97fff", + "0x10780017fff7fff", + "0xc", + "0x400080007ffa7fff", + "0x40780017fff7fff", + "0x1", + "0x482480017ff98000", + "0x1", + "0x48127ffd7fff8000", + "0x480680017fff8000", + "0x0", + "0x10780017fff7fff", + "0x7", + "0x482480017ff98000", + "0x1", + "0x48127ffe7fff8000", + "0x480680017fff8000", + "0x1", + "0x48307ff87fe18000", + "0x48307ffe7fff8000", + "0x48307fff7fe08001", + "0xa0680017fff7fff", + "0x7", + "0x4824800180007fff", + "0x100000000000000000000000000000000", + "0x400080007ff87fff", + "0x10780017fff7fff", + "0xa", + "0x400080007ff97fff", + "0x40780017fff7fff", + "0x1", + "0x482480017ff88000", + "0x1", + "0x48127ffd7fff8000", + "0x10780017fff7fff", + "0x5", + "0x482480017ff88000", + "0x1", + "0x48127ffe7fff8000", + "0x48127ffe7fff8000", + "0x48127f967fff8000", + "0x48127fd17fff8000", + "0x48127ff47fff8000", + "0x48127ffb7fff8000", + "0x208b7fff7fff7ffe", + "0xa0680017fff8000", + "0x7", + "0x4825800180007ffd", + "0x10", + "0x400280007ffc7fff", + "0x10780017fff7fff", + "0x6f", + "0x482680017ffd8000", + "0xfffffffffffffffffffffffffffffff0", + "0x400280007ffc7fff", + "0x4825800180007ffd", + "0x400000000000008800000000000000000000000000000000000000000000010", + "0x484480017fff8000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffff", + "0x482680017ffc8000", + "0x1", + "0x1137ffe7fff7fff", + "0x10780017fff7fff", + "0x5a", + "0x10780017fff7fff", + "0x54", + "0x10780017fff7fff", + "0x4e", + "0x10780017fff7fff", + "0x48", + "0x10780017fff7fff", + "0x42", + "0x10780017fff7fff", + "0x3c", + "0x10780017fff7fff", + "0x36", + "0x10780017fff7fff", + "0x30", + "0x10780017fff7fff", + "0x2a", + "0x10780017fff7fff", + "0x24", + "0x10780017fff7fff", + "0x1e", + "0x10780017fff7fff", + "0x18", + "0x10780017fff7fff", + "0x12", + "0x10780017fff7fff", + "0xc", + "0x10780017fff7fff", + "0x6", + "0x480680017fff8000", + "0x1", + "0x10780017fff7fff", + "0x3c", + "0x480680017fff8000", + "0x100", + "0x10780017fff7fff", + "0x38", + "0x480680017fff8000", + "0x10000", + "0x10780017fff7fff", + "0x34", + "0x480680017fff8000", + "0x1000000", + "0x10780017fff7fff", + "0x30", + "0x480680017fff8000", + "0x100000000", + "0x10780017fff7fff", + "0x2c", + "0x480680017fff8000", + "0x10000000000", + "0x10780017fff7fff", + "0x28", + "0x480680017fff8000", + "0x1000000000000", + "0x10780017fff7fff", + "0x24", + "0x480680017fff8000", + "0x100000000000000", + "0x10780017fff7fff", + "0x20", + "0x480680017fff8000", + "0x10000000000000000", + "0x10780017fff7fff", + "0x1c", + "0x480680017fff8000", + "0x1000000000000000000", + "0x10780017fff7fff", + "0x18", + "0x480680017fff8000", + "0x100000000000000000000", + "0x10780017fff7fff", + "0x14", + "0x480680017fff8000", + "0x10000000000000000000000", + "0x10780017fff7fff", + "0x10", + "0x480680017fff8000", + "0x1000000000000000000000000", + "0x10780017fff7fff", + "0xc", + "0x480680017fff8000", + "0x100000000000000000000000000", + "0x10780017fff7fff", + "0x8", + "0x480680017fff8000", + "0x10000000000000000000000000000", + "0x10780017fff7fff", + "0x4", + "0x480680017fff8000", + "0x1000000000000000000000000000000", + "0x48127ffe7fff8000", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x48127ffc7fff8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x2", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x6e5f627974657320746f6f20626967", + "0x400080007ffe7fff", + "0x482680017ffc8000", + "0x1", + "0x480680017fff8000", + "0x1", + "0x48127ffc7fff8000", + "0x482480017ffb8000", + "0x1", + "0x208b7fff7fff7ffe", + "0x1104800180018000", + "0x17b", + "0x482480017fff8000", + "0x17a", + "0x480080007fff8000", + "0x480080017fff8000", + "0x484480017fff8000", + "0x8", + "0x482480017fff8000", + "0x3c32", + "0xa0680017fff8000", + "0x8", + "0x48317ffe80007ff8", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400280007ff77fff", + "0x10780017fff7fff", + "0x54", + "0x48317ffe80007ff8", + "0x400280007ff77fff", + "0x482680017ff78000", + "0x1", + "0x48127ffe7fff8000", + "0x48297ffa80007ffb", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xb", + "0x48127ffe7fff8000", + "0x482680017ffa8000", + "0x2", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x0", + "0x480a7ffa7fff8000", + "0x10780017fff7fff", + "0x9", + "0x48127ffe7fff8000", + "0x480a7ffa7fff8000", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x20680017fff7ffe", + "0x24", + "0x48127ff87fff8000", + "0x480a7ff97fff8000", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", + "0x480080007ffb8000", + "0x480080017ffa8000", + "0x1104800180018000", + "0x43", + "0x48127fab7fff8000", + "0x20680017fff7ffc", + "0xc", + "0x48127ffa7fff8000", + "0x48127ffe7fff8000", + "0x48127ff97fff8000", + "0x48127fa87fff8000", + "0x48127fa87fff8000", + "0x48127ff87fff8000", + "0x48127ff87fff8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffc1", + "0x208b7fff7fff7ffe", + "0x48127ffa7fff8000", + "0x482480017ffe8000", + "0x9a6", + "0x48127ff97fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x48127ff77fff8000", + "0x48127ff77fff8000", + "0x208b7fff7fff7ffe", + "0x1104800180018000", + "0x12b", + "0x482480017fff8000", + "0x12a", + "0x480080007fff8000", + "0x480080017fff8000", + "0x484480017fff8000", + "0x8", + "0x482480017fff8000", + "0x371e", + "0x48127ff17fff8000", + "0x48307ffe7ff38000", + "0x480a7ff97fff8000", + "0x480680017fff8000", + "0x0", + "0x48127ff17fff8000", + "0x48127ff17fff8000", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x482680017ff78000", + "0x1", + "0x480a7ff87fff8000", + "0x480a7ff97fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x48127ff87fff8000", + "0x482480017ff78000", + "0x1", + "0x208b7fff7fff7ffe", + "0x400380007ff97ffd", + "0x480680017fff8000", + "0xff00ff00ff00ff00ff00ff00ff00ff", + "0x400280017ff97fff", + "0x480280027ff98000", + "0x484480017fff8000", + "0xffff", + "0x48327fff7ffd8000", + "0x400280057ff97fff", + "0x480680017fff8000", + "0xffff0000ffff0000ffff0000ffff00", + "0x400280067ff97fff", + "0x480280077ff98000", + "0x484480017fff8000", + "0xffffffff", + "0x48307fff7ffc8000", + "0x4002800a7ff97fff", + "0x480680017fff8000", + "0xffffffff00000000ffffffff000000", + "0x4002800b7ff97fff", + "0x4802800c7ff98000", + "0x484480017fff8000", + "0xffffffffffffffff", + "0x48307fff7ffc8000", + "0x4002800f7ff97fff", + "0x480680017fff8000", + "0xffffffffffffffff00000000000000", + "0x400280107ff97fff", + "0x480280117ff98000", + "0x484480017fff8000", + "0xffffffffffffffffffffffffffffffff", + "0x48307fff7ffc8000", + "0x484480017fff8000", + "0x800000000000010fffffffffffffff7ffffffffffffef000000000000000001", + "0x480680017fff8000", + "0x10000000000000000", + "0x480280007ff88005", + "0x480280017ff88005", + "0x4824800180047ffe", + "0x1", + "0x48307ffd7ffe7ffc", + "0x480280027ff87ffd", + "0xa0680017fff7ffd", + "0x6", + "0x482480017ff97ffd", + "0xffffffffffffffff0000000000000000", + "0x10780017fff7fff", + "0x4", + "0x482480017fff7ffd", + "0xffffffffffffffff0000000000000000", + "0x400280037ff87ffc", + "0x40507ffe7ff87ffd", + "0x40307fff7ffd7ff7", + "0x482680017ff98000", + "0x14", + "0xa0680017fff8000", + "0x7", + "0x4824800180007ffc", + "0x10000000000000000", + "0x400280047ff87fff", + "0x10780017fff7fff", + "0x99", + "0x482480017ffc8000", + "0xffffffffffffffff0000000000000000", + "0x400280047ff87fff", + "0xa0680017fff8000", + "0x7", + "0x4824800180007ffb", + "0x10000000000000000", + "0x400280057ff87fff", + "0x10780017fff7fff", + "0x81", + "0x482480017ffb8000", + "0xffffffffffffffff0000000000000000", + "0x400280057ff87fff", + "0x400280007ffb7ffa", + "0x400280017ffb7ff9", + "0x400180007ffb7ffc", + "0x480680017fff8000", + "0xff00ff00ff00ff00ff00ff00ff00ff", + "0x400080017ffa7fff", + "0x480080027ffa8000", + "0x484480017fff8000", + "0xffff", + "0x48327fff7ffc8000", + "0x400080057ff77fff", + "0x480680017fff8000", + "0xffff0000ffff0000ffff0000ffff00", + "0x400080067ff67fff", + "0x480080077ff68000", + "0x484480017fff8000", + "0xffffffff", + "0x48307fff7ffc8000", + "0x4000800a7ff37fff", + "0x480680017fff8000", + "0xffffffff00000000ffffffff000000", + "0x4000800b7ff27fff", + "0x4800800c7ff28000", + "0x484480017fff8000", + "0xffffffffffffffff", + "0x48307fff7ffc8000", + "0x4000800f7fef7fff", + "0x480680017fff8000", + "0xffffffffffffffff00000000000000", + "0x400080107fee7fff", + "0x480080117fee8000", + "0x484480017fff8000", + "0xffffffffffffffffffffffffffffffff", + "0x48307fff7ffc8000", + "0x484480017fff8000", + "0x800000000000010fffffffffffffff7ffffffffffffef000000000000000001", + "0x480680017fff8000", + "0x10000000000000000", + "0x480280067ff88005", + "0x480280077ff88005", + "0x4824800180047ffe", + "0x1", + "0x48307ffd7ffe7ffc", + "0x480280087ff87ffd", + "0xa0680017fff7ffd", + "0x6", + "0x482480017ff97ffd", + "0xffffffffffffffff0000000000000000", + "0x10780017fff7fff", + "0x4", + "0x482480017fff7ffd", + "0xffffffffffffffff0000000000000000", + "0x400280097ff87ffc", + "0x40507ffe7ff87ffd", + "0x40307fff7ffd7ff7", + "0x480a7ffa7fff8000", + "0x482680017ffb8000", + "0x2", + "0x482480017fe08000", + "0x14", + "0xa0680017fff8000", + "0x7", + "0x4824800180007ffa", + "0x10000000000000000", + "0x4002800a7ff87fff", + "0x10780017fff7fff", + "0x28", + "0x482480017ffa8000", + "0xffffffffffffffff0000000000000000", + "0x4002800a7ff87fff", + "0xa0680017fff8000", + "0x7", + "0x4824800180007ff9", + "0x10000000000000000", + "0x4002800b7ff87fff", + "0x10780017fff7fff", + "0x12", + "0x482480017ff98000", + "0xffffffffffffffff0000000000000000", + "0x4002800b7ff87fff", + "0x40780017fff7fff", + "0x5", + "0x400080007ff57ff3", + "0x400080017ff57ff2", + "0x482680017ff88000", + "0xc", + "0x48127ff57fff8000", + "0x480680017fff8000", + "0x0", + "0x48127ff17fff8000", + "0x482480017ff18000", + "0x2", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x400080007ffe7fff", + "0x482680017ff88000", + "0xc", + "0x48127ffd7fff8000", + "0x482480017ffc8000", + "0x1", + "0x10780017fff7fff", + "0xe", + "0x40780017fff7fff", + "0x2", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x400080007ffe7fff", + "0x482680017ff88000", + "0xb", + "0x48127ffd7fff8000", + "0x482480017ffc8000", + "0x1", + "0x48127ffd7fff8000", + "0x48127ff57fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x20", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x400080007ffe7fff", + "0x482680017ff88000", + "0x6", + "0x48127ffd7fff8000", + "0x482480017ffc8000", + "0x1", + "0x10780017fff7fff", + "0xe", + "0x40780017fff7fff", + "0x22", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x400080007ffe7fff", + "0x482680017ff88000", + "0x5", + "0x48127ffd7fff8000", + "0x482480017ffc8000", + "0x1", + "0x48127ffd7fff8000", + "0x48127fd57fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x208b7fff7fff7ffe", + "0x208b7fff7fff7ffe", + "0x6a09e667", + "0xbb67ae85", + "0x3c6ef372", + "0xa54ff53a", + "0x510e527f", + "0x9b05688c", + "0x1f83d9ab", + "0x5be0cd19", + "0x208b7fff7fff7ffe", + "0xc", + "0x10", + "0x14", + "0x1c", + "0x10", + "0x18", + "0x0", + "0x4", + "0xc", + "0x0", + "0x8", + "0x10", + "0x18", + "0x14", + "0x0", + "0x18", + "0x1c", + "0x20" + ], + "bytecode_segment_lengths": [ + 249, + 194, + 288, + 553, + 222, + 125, + 256, + 299, + 335, + 286, + 193, + 269, + 288, + 272, + 189, + 217, + 116, 330, - 111, - 138, - 144, - 128, - 123, + 186, + 110, + 110, + 119, + 110, + 167, + 185, + 99, + 135, + 135, 264, - 136, - 225, - 163, - 92, - 51, - 51, + 200, + 285, + 356, 117, + 146, + 155, + 134, + 134, + 285, + 122, + 95, + 106, 106, + 113, + 155, + 146, + 244, + 176, + 98, + 53, + 53, + 140, + 130, + 113, 205, - 1147, - 368, - 72, + 1210, + 418, + 77, 190, - 212, - 83, - 332, - 370, - 299, - 48, - 44, - 195, - 290, - 290, - 302, - 445, + 200, + 216, + 87, + 464, + 394, + 327, + 50, + 46, + 221, + 350, + 333, + 348, + 521, 33, - 276, + 428, 185, - 80, - 116, - 138, - 89, - 249, + 84, + 124, + 153, + 95, + 281, 254, - 97, - 202, - 1222, + 105, + 308, + 1282, 31, - 1128, - 51, + 1098, + 53, 164, 157, - 83, + 87, 239, - 1151, - 199, + 1183, + 244, 271, 131, - 104, + 119, 232, 9, 19 ], "hints": [ [ - 0, + 0, + [ + { + "TestLessThanOrEqual": { + "lhs": { + "Immediate": "0x0" + }, + "rhs": { + "Deref": { + "register": "FP", + "offset": -6 + } + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 38, + [ + { + "TestLessThan": { + "lhs": { + "Deref": { + "register": "AP", + "offset": -2 + } + }, + "rhs": { + "Immediate": "0x800000000000000000000000000000000000000000000000000000000000000" + }, + "dst": { + "register": "AP", + "offset": 4 + } + } + } + ] + ], + [ + 42, + [ + { + "LinearSplit": { + "value": { + "Deref": { + "register": "AP", + "offset": 3 + } + }, + "scalar": { + "Immediate": "0x110000000000000000" + }, + "max_x": { + "Immediate": "0xffffffffffffffffffffffffffffffff" + }, + "x": { + "register": "AP", + "offset": -2 + }, + "y": { + "register": "AP", + "offset": -1 + } + } + } + ] + ], + [ + 52, + [ + { + "LinearSplit": { + "value": { + "Deref": { + "register": "AP", + "offset": -3 + } + }, + "scalar": { + "Immediate": "0x8000000000000000000000000000000" + }, + "max_x": { + "Immediate": "0xffffffffffffffffffffffffffffffff" + }, + "x": { + "register": "AP", + "offset": -1 + }, + "y": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 78, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 99, + [ + { + "TestLessThanOrEqual": { + "lhs": { + "Immediate": "0x56b8" + }, + "rhs": { + "Deref": { + "register": "AP", + "offset": -2 + } + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 123, + [ + { + "SystemCall": { + "system": { + "Deref": { + "register": "FP", + "offset": -5 + } + } + } + } + ] + ], + [ + 136, + [ + { + "SystemCall": { + "system": { + "BinOp": { + "op": "Add", + "a": { + "register": "FP", + "offset": -5 + }, + "b": { + "Immediate": "0x7" + } + } + } + } + } + ] + ], + [ + 140, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 180, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 195, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 219, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 233, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 249, + [ + { + "TestLessThanOrEqual": { + "lhs": { + "Immediate": "0x0" + }, + "rhs": { + "Deref": { + "register": "FP", + "offset": -6 + } + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 268, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 289, + [ + { + "TestLessThanOrEqual": { + "lhs": { + "Immediate": "0x5c9e" + }, + "rhs": { + "Deref": { + "register": "AP", + "offset": -2 + } + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 304, + [ + { + "TestLessThan": { + "lhs": { + "Deref": { + "register": "AP", + "offset": -2 + } + }, + "rhs": { + "Immediate": "0x800000000000000000000000000000000000000000000000000000000000000" + }, + "dst": { + "register": "AP", + "offset": 4 + } + } + } + ] + ], + [ + 308, + [ + { + "LinearSplit": { + "value": { + "Deref": { + "register": "AP", + "offset": 3 + } + }, + "scalar": { + "Immediate": "0x110000000000000000" + }, + "max_x": { + "Immediate": "0xffffffffffffffffffffffffffffffff" + }, + "x": { + "register": "AP", + "offset": -2 + }, + "y": { + "register": "AP", + "offset": -1 + } + } + } + ] + ], + [ + 318, + [ + { + "LinearSplit": { + "value": { + "Deref": { + "register": "AP", + "offset": -3 + } + }, + "scalar": { + "Immediate": "0x8000000000000000000000000000000" + }, + "max_x": { + "Immediate": "0xffffffffffffffffffffffffffffffff" + }, + "x": { + "register": "AP", + "offset": -1 + }, + "y": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 340, + [ + { + "SystemCall": { + "system": { + "Deref": { + "register": "FP", + "offset": -5 + } + } + } + } + ] + ], + [ + 356, + [ + { + "SystemCall": { + "system": { + "BinOp": { + "op": "Add", + "a": { + "register": "FP", + "offset": -5 + }, + "b": { + "Immediate": "0x7" + } + } + } + } + } + ] + ], + [ + 360, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 391, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 412, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 427, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 445, + [ + { + "TestLessThanOrEqual": { + "lhs": { + "Immediate": "0x0" + }, + "rhs": { + "Deref": { + "register": "FP", + "offset": -6 + } + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 484, + [ + { + "TestLessThan": { + "lhs": { + "Deref": { + "register": "FP", + "offset": 1 + } + }, + "rhs": { + "Immediate": "0x800000000000000000000000000000000000000000000000000000000000000" + }, + "dst": { + "register": "AP", + "offset": 4 + } + } + } + ] + ], + [ + 488, + [ + { + "LinearSplit": { + "value": { + "Deref": { + "register": "AP", + "offset": 3 + } + }, + "scalar": { + "Immediate": "0x110000000000000000" + }, + "max_x": { + "Immediate": "0xffffffffffffffffffffffffffffffff" + }, + "x": { + "register": "AP", + "offset": -2 + }, + "y": { + "register": "AP", + "offset": -1 + } + } + } + ] + ], + [ + 498, + [ + { + "LinearSplit": { + "value": { + "Deref": { + "register": "FP", + "offset": 1 + } + }, + "scalar": { + "Immediate": "0x8000000000000000000000000000000" + }, + "max_x": { + "Immediate": "0xffffffffffffffffffffffffffffffff" + }, + "x": { + "register": "AP", + "offset": -1 + }, + "y": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 542, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 564, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 585, + [ + { + "TestLessThanOrEqual": { + "lhs": { + "Immediate": "0x29cc" + }, + "rhs": { + "Deref": { + "register": "AP", + "offset": -2 + } + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 608, + [ + { + "SystemCall": { + "system": { + "Deref": { + "register": "FP", + "offset": -5 + } + } + } + } + ] + ], + [ + 631, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 663, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 677, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 701, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 715, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 733, + [ + { + "TestLessThanOrEqual": { + "lhs": { + "Immediate": "0x1982" + }, + "rhs": { + "Deref": { + "register": "FP", + "offset": -6 + } + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 771, + [ + { + "TestLessThan": { + "lhs": { + "Deref": { + "register": "FP", + "offset": 5 + } + }, + "rhs": { + "Immediate": "0x800000000000000000000000000000000000000000000000000000000000000" + }, + "dst": { + "register": "AP", + "offset": 4 + } + } + } + ] + ], + [ + 775, + [ + { + "LinearSplit": { + "value": { + "Deref": { + "register": "AP", + "offset": 3 + } + }, + "scalar": { + "Immediate": "0x110000000000000000" + }, + "max_x": { + "Immediate": "0xffffffffffffffffffffffffffffffff" + }, + "x": { + "register": "AP", + "offset": -2 + }, + "y": { + "register": "AP", + "offset": -1 + } + } + } + ] + ], + [ + 785, + [ + { + "LinearSplit": { + "value": { + "Deref": { + "register": "FP", + "offset": 5 + } + }, + "scalar": { + "Immediate": "0x8000000000000000000000000000000" + }, + "max_x": { + "Immediate": "0xffffffffffffffffffffffffffffffff" + }, + "x": { + "register": "AP", + "offset": -1 + }, + "y": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 829, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 873, + [ + { + "TestLessThan": { + "lhs": { + "Deref": { + "register": "FP", + "offset": 6 + } + }, + "rhs": { + "Immediate": "0x800000000000000000000000000000000000000000000000000000000000000" + }, + "dst": { + "register": "AP", + "offset": 4 + } + } + } + ] + ], + [ + 877, + [ + { + "LinearSplit": { + "value": { + "Deref": { + "register": "AP", + "offset": 3 + } + }, + "scalar": { + "Immediate": "0x110000000000000000" + }, + "max_x": { + "Immediate": "0xffffffffffffffffffffffffffffffff" + }, + "x": { + "register": "AP", + "offset": -2 + }, + "y": { + "register": "AP", + "offset": -1 + } + } + } + ] + ], + [ + 887, + [ + { + "LinearSplit": { + "value": { + "Deref": { + "register": "FP", + "offset": 6 + } + }, + "scalar": { + "Immediate": "0x8000000000000000000000000000000" + }, + "max_x": { + "Immediate": "0xffffffffffffffffffffffffffffffff" + }, + "x": { + "register": "AP", + "offset": -1 + }, + "y": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 931, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 953, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 974, + [ + { + "TestLessThanOrEqual": { + "lhs": { + "Immediate": "0x71fc" + }, + "rhs": { + "Deref": { + "register": "AP", + "offset": -2 + } + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 997, + [ + { + "SystemCall": { + "system": { + "Deref": { + "register": "FP", + "offset": -5 + } + } + } + } + ] + ], + [ + 1012, + [ + { + "SystemCall": { + "system": { + "BinOp": { + "op": "Add", + "a": { + "register": "FP", + "offset": -5 + }, + "b": { + "Immediate": "0xa" + } + } + } + } + } + ] + ], + [ + 1016, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1042, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1115, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1147, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1161, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1185, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1216, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1230, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1254, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1268, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1284, [ { "TestLessThanOrEqual": { @@ -19560,14 +24218,327 @@ ] ], [ - 33, + 1322, [ { "TestLessThan": { "lhs": { "Deref": { "register": "AP", - "offset": -1 + "offset": -2 + } + }, + "rhs": { + "Immediate": "0x800000000000000000000000000000000000000000000000000000000000000" + }, + "dst": { + "register": "AP", + "offset": 4 + } + } + } + ] + ], + [ + 1326, + [ + { + "LinearSplit": { + "value": { + "Deref": { + "register": "AP", + "offset": 3 + } + }, + "scalar": { + "Immediate": "0x110000000000000000" + }, + "max_x": { + "Immediate": "0xffffffffffffffffffffffffffffffff" + }, + "x": { + "register": "AP", + "offset": -2 + }, + "y": { + "register": "AP", + "offset": -1 + } + } + } + ] + ], + [ + 1336, + [ + { + "LinearSplit": { + "value": { + "Deref": { + "register": "AP", + "offset": -3 + } + }, + "scalar": { + "Immediate": "0x8000000000000000000000000000000" + }, + "max_x": { + "Immediate": "0xffffffffffffffffffffffffffffffff" + }, + "x": { + "register": "AP", + "offset": -1 + }, + "y": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1373, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1394, + [ + { + "TestLessThanOrEqual": { + "lhs": { + "Immediate": "0xb4dc" + }, + "rhs": { + "Deref": { + "register": "AP", + "offset": -2 + } + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1418, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1437, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1452, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1476, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1490, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1506, + [ + { + "TestLessThanOrEqual": { + "lhs": { + "Immediate": "0x0" + }, + "rhs": { + "Deref": { + "register": "FP", + "offset": -6 + } + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1525, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1546, + [ + { + "TestLessThanOrEqual": { + "lhs": { + "Immediate": "0x2af8" + }, + "rhs": { + "Deref": { + "register": "AP", + "offset": -2 + } + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1574, + [ + { + "SystemCall": { + "system": { + "Deref": { + "register": "FP", + "offset": -5 + } + } + } + } + ] + ], + [ + 1578, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1600, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1615, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1631, + [ + { + "TestLessThanOrEqual": { + "lhs": { + "Immediate": "0x0" + }, + "rhs": { + "Deref": { + "register": "FP", + "offset": -6 + } + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1669, + [ + { + "TestLessThan": { + "lhs": { + "Deref": { + "register": "AP", + "offset": -2 } }, "rhs": { @@ -19582,7 +24553,7 @@ ] ], [ - 37, + 1673, [ { "LinearSplit": { @@ -19611,14 +24582,14 @@ ] ], [ - 47, + 1683, [ { "LinearSplit": { "value": { "Deref": { "register": "AP", - "offset": -2 + "offset": -3 } }, "scalar": { @@ -19640,78 +24611,87 @@ ] ], [ - 71, + 1718, [ { - "AllocSegment": { - "dst": { - "register": "AP", - "offset": 0 - } - } - } - ] - ], - [ - 90, - [ - { - "TestLessThanOrEqual": { + "TestLessThan": { "lhs": { - "Immediate": "0x41d2" - }, - "rhs": { "Deref": { "register": "AP", - "offset": -22 + "offset": -2 } }, + "rhs": { + "Immediate": "0x800000000000000000000000000000000000000000000000000000000000000" + }, "dst": { "register": "AP", - "offset": 0 + "offset": 4 } } } ] ], [ - 113, + 1722, [ { - "SystemCall": { - "system": { + "LinearSplit": { + "value": { "Deref": { - "register": "FP", - "offset": -5 + "register": "AP", + "offset": 3 } + }, + "scalar": { + "Immediate": "0x110000000000000000" + }, + "max_x": { + "Immediate": "0xffffffffffffffffffffffffffffffff" + }, + "x": { + "register": "AP", + "offset": -2 + }, + "y": { + "register": "AP", + "offset": -1 } } } ] ], [ - 125, + 1732, [ { - "SystemCall": { - "system": { - "BinOp": { - "op": "Add", - "a": { - "register": "FP", - "offset": -5 - }, - "b": { - "Immediate": "0x7" - } + "LinearSplit": { + "value": { + "Deref": { + "register": "AP", + "offset": -3 } + }, + "scalar": { + "Immediate": "0x8000000000000000000000000000000" + }, + "max_x": { + "Immediate": "0xffffffffffffffffffffffffffffffff" + }, + "x": { + "register": "AP", + "offset": -1 + }, + "y": { + "register": "AP", + "offset": 0 } } } ] ], [ - 128, + 1748, [ { "AllocSegment": { @@ -19724,10 +24704,19 @@ ] ], [ - 164, + 1769, [ { - "AllocSegment": { + "TestLessThanOrEqual": { + "lhs": { + "Immediate": "0x8bd8" + }, + "rhs": { + "Deref": { + "register": "AP", + "offset": -2 + } + }, "dst": { "register": "AP", "offset": 0 @@ -19737,7 +24726,7 @@ ] ], [ - 179, + 1791, [ { "AllocSegment": { @@ -19750,7 +24739,7 @@ ] ], [ - 200, + 1810, [ { "AllocSegment": { @@ -19763,7 +24752,7 @@ ] ], [ - 214, + 1834, [ { "AllocSegment": { @@ -19776,19 +24765,10 @@ ] ], [ - 229, + 1857, [ { - "TestLessThanOrEqual": { - "lhs": { - "Immediate": "0x0" - }, - "rhs": { - "Deref": { - "register": "FP", - "offset": -6 - } - }, + "AllocSegment": { "dst": { "register": "AP", "offset": 0 @@ -19798,7 +24778,7 @@ ] ], [ - 246, + 1871, [ { "AllocSegment": { @@ -19811,17 +24791,17 @@ ] ], [ - 265, + 1889, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x3e4e" + "Immediate": "0x0" }, "rhs": { "Deref": { - "register": "AP", - "offset": -7 + "register": "FP", + "offset": -6 } }, "dst": { @@ -19833,14 +24813,14 @@ ] ], [ - 279, + 1928, [ { "TestLessThan": { "lhs": { "Deref": { - "register": "AP", - "offset": -1 + "register": "FP", + "offset": 1 } }, "rhs": { @@ -19855,7 +24835,7 @@ ] ], [ - 283, + 1932, [ { "LinearSplit": { @@ -19884,14 +24864,14 @@ ] ], [ - 293, + 1942, [ { "LinearSplit": { "value": { "Deref": { - "register": "AP", - "offset": -2 + "register": "FP", + "offset": 1 } }, "scalar": { @@ -19913,7 +24893,55 @@ ] ], [ - 314, + 1986, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 2008, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 2029, + [ + { + "TestLessThanOrEqual": { + "lhs": { + "Immediate": "0x2cec" + }, + "rhs": { + "Deref": { + "register": "AP", + "offset": -2 + } + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 2052, [ { "SystemCall": { @@ -19928,28 +24956,33 @@ ] ], [ - 329, + 2056, [ { - "SystemCall": { - "system": { - "BinOp": { - "op": "Add", - "a": { - "register": "FP", - "offset": -5 - }, - "b": { - "Immediate": "0x7" - } - } + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 2086, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 } } } ] ], [ - 332, + 2118, [ { "AllocSegment": { @@ -19962,7 +24995,7 @@ ] ], [ - 359, + 2132, [ { "AllocSegment": { @@ -19975,7 +25008,7 @@ ] ], [ - 379, + 2156, [ { "AllocSegment": { @@ -19988,7 +25021,7 @@ ] ], [ - 394, + 2170, [ { "AllocSegment": { @@ -20001,12 +25034,12 @@ ] ], [ - 411, + 2188, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x0" + "Immediate": "0xaa0" }, "rhs": { "Deref": { @@ -20023,78 +25056,68 @@ ] ], [ - 445, + 2226, [ { "TestLessThan": { "lhs": { - "Deref": { - "register": "FP", - "offset": 0 + "BinOp": { + "op": "Add", + "a": { + "register": "FP", + "offset": 2 + }, + "b": { + "Immediate": "0x0" + } } }, "rhs": { - "Immediate": "0x800000000000000000000000000000000000000000000000000000000000000" + "Immediate": "0x10000000000000000" }, "dst": { "register": "AP", - "offset": 4 + "offset": 0 } } } ] ], [ - 449, + 2230, [ { "LinearSplit": { "value": { "Deref": { "register": "AP", - "offset": 3 + "offset": -1 } }, "scalar": { - "Immediate": "0x110000000000000000" + "Immediate": "0x8000000000000110000000000000000" }, "max_x": { - "Immediate": "0xffffffffffffffffffffffffffffffff" + "Immediate": "0xfffffffffffffffffffffffffffffffe" }, "x": { "register": "AP", - "offset": -2 + "offset": 0 }, "y": { "register": "AP", - "offset": -1 + "offset": 1 } } } ] ], [ - 459, + 2274, [ { - "LinearSplit": { - "value": { - "Deref": { - "register": "FP", - "offset": 0 - } - }, - "scalar": { - "Immediate": "0x8000000000000000000000000000000" - }, - "max_x": { - "Immediate": "0xffffffffffffffffffffffffffffffff" - }, - "x": { - "register": "AP", - "offset": -1 - }, - "y": { + "AllocSegment": { + "dst": { "register": "AP", "offset": 0 } @@ -20103,7 +25126,7 @@ ] ], [ - 499, + 2316, [ { "AllocSegment": { @@ -20116,7 +25139,7 @@ ] ], [ - 519, + 2338, [ { "AllocSegment": { @@ -20129,17 +25152,17 @@ ] ], [ - 538, + 2359, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x2404" + "Immediate": "0x87a" }, "rhs": { "Deref": { "register": "AP", - "offset": -12 + "offset": -2 } }, "dst": { @@ -20151,22 +25174,20 @@ ] ], [ - 560, + 2386, [ { - "SystemCall": { - "system": { - "Deref": { - "register": "FP", - "offset": -5 - } + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 } } } ] ], [ - 581, + 2405, [ { "AllocSegment": { @@ -20179,7 +25200,7 @@ ] ], [ - 610, + 2437, [ { "AllocSegment": { @@ -20192,7 +25213,7 @@ ] ], [ - 624, + 2468, [ { "AllocSegment": { @@ -20205,7 +25226,7 @@ ] ], [ - 645, + 2491, [ { "AllocSegment": { @@ -20218,7 +25239,7 @@ ] ], [ - 659, + 2505, [ { "AllocSegment": { @@ -20231,12 +25252,12 @@ ] ], [ - 676, + 2521, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x1342" + "Immediate": "0x0" }, "rhs": { "Deref": { @@ -20253,14 +25274,14 @@ ] ], [ - 710, + 2559, [ { "TestLessThan": { "lhs": { "Deref": { - "register": "FP", - "offset": 8 + "register": "AP", + "offset": -2 } }, "rhs": { @@ -20275,7 +25296,7 @@ ] ], [ - 714, + 2563, [ { "LinearSplit": { @@ -20304,14 +25325,14 @@ ] ], [ - 724, + 2573, [ { "LinearSplit": { "value": { "Deref": { - "register": "FP", - "offset": 8 + "register": "AP", + "offset": -3 } }, "scalar": { @@ -20333,27 +25354,14 @@ ] ], [ - 764, - [ - { - "AllocSegment": { - "dst": { - "register": "AP", - "offset": 0 - } - } - } - ] - ], - [ - 803, + 2608, [ { "TestLessThan": { "lhs": { "Deref": { - "register": "FP", - "offset": 7 + "register": "AP", + "offset": -2 } }, "rhs": { @@ -20368,7 +25376,7 @@ ] ], [ - 807, + 2612, [ { "LinearSplit": { @@ -20397,14 +25405,14 @@ ] ], [ - 817, + 2622, [ { "LinearSplit": { "value": { "Deref": { - "register": "FP", - "offset": 7 + "register": "AP", + "offset": -3 } }, "scalar": { @@ -20426,7 +25434,7 @@ ] ], [ - 857, + 2638, [ { "AllocSegment": { @@ -20439,30 +25447,17 @@ ] ], [ - 877, - [ - { - "AllocSegment": { - "dst": { - "register": "AP", - "offset": 0 - } - } - } - ] - ], - [ - 896, + 2659, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x70d0" + "Immediate": "0x2db4" }, "rhs": { "Deref": { "register": "AP", - "offset": -12 + "offset": -2 } }, "dst": { @@ -20474,7 +25469,7 @@ ] ], [ - 918, + 2679, [ { "SystemCall": { @@ -20489,28 +25484,20 @@ ] ], [ - 932, + 2690, [ { - "SystemCall": { - "system": { - "BinOp": { - "op": "Add", - "a": { - "register": "FP", - "offset": -5 - }, - "b": { - "Immediate": "0xa" - } - } + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 } } } ] ], [ - 935, + 2701, [ { "AllocSegment": { @@ -20523,7 +25510,7 @@ ] ], [ - 961, + 2730, [ { "AllocSegment": { @@ -20536,7 +25523,7 @@ ] ], [ - 1028, + 2754, [ { "AllocSegment": { @@ -20549,7 +25536,7 @@ ] ], [ - 1057, + 2777, [ { "AllocSegment": { @@ -20562,7 +25549,7 @@ ] ], [ - 1071, + 2791, [ { "AllocSegment": { @@ -20575,7 +25562,86 @@ ] ], [ - 1092, + 2807, + [ + { + "TestLessThanOrEqual": { + "lhs": { + "Immediate": "0x0" + }, + "rhs": { + "Deref": { + "register": "FP", + "offset": -6 + } + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 2846, + [ + { + "TestLessThan": { + "lhs": { + "BinOp": { + "op": "Add", + "a": { + "register": "AP", + "offset": -2 + }, + "b": { + "Immediate": "0x0" + } + } + }, + "rhs": { + "Immediate": "0x10000000000000000" + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 2850, + [ + { + "LinearSplit": { + "value": { + "Deref": { + "register": "AP", + "offset": -1 + } + }, + "scalar": { + "Immediate": "0x8000000000000110000000000000000" + }, + "max_x": { + "Immediate": "0xfffffffffffffffffffffffffffffffe" + }, + "x": { + "register": "AP", + "offset": 0 + }, + "y": { + "register": "AP", + "offset": 1 + } + } + } + ] + ], + [ + 2876, [ { "AllocSegment": { @@ -20588,7 +25654,44 @@ ] ], [ - 1120, + 2897, + [ + { + "TestLessThanOrEqual": { + "lhs": { + "Immediate": "0x29cc" + }, + "rhs": { + "Deref": { + "register": "AP", + "offset": -2 + } + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 2917, + [ + { + "SystemCall": { + "system": { + "Deref": { + "register": "FP", + "offset": -5 + } + } + } + } + ] + ], + [ + 2921, [ { "AllocSegment": { @@ -20601,7 +25704,7 @@ ] ], [ - 1134, + 2946, [ { "AllocSegment": { @@ -20614,7 +25717,7 @@ ] ], [ - 1155, + 2970, [ { "AllocSegment": { @@ -20627,7 +25730,7 @@ ] ], [ - 1169, + 2984, [ { "AllocSegment": { @@ -20640,12 +25743,12 @@ ] ], [ - 1184, + 3002, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x0" + "Immediate": "0x9074" }, "rhs": { "Deref": { @@ -20662,78 +25765,59 @@ ] ], [ - 1217, + 3071, [ { - "TestLessThan": { - "lhs": { - "Deref": { - "register": "AP", - "offset": -1 - } - }, - "rhs": { - "Immediate": "0x800000000000000000000000000000000000000000000000000000000000000" - }, + "AllocSegment": { "dst": { "register": "AP", - "offset": 4 + "offset": 0 } } } ] ], [ - 1221, + 3092, [ { - "LinearSplit": { - "value": { + "TestLessThanOrEqual": { + "lhs": { + "Immediate": "0x896c" + }, + "rhs": { "Deref": { "register": "AP", - "offset": 3 + "offset": -2 } }, - "scalar": { - "Immediate": "0x110000000000000000" - }, - "max_x": { - "Immediate": "0xffffffffffffffffffffffffffffffff" - }, - "x": { - "register": "AP", - "offset": -2 - }, - "y": { + "dst": { "register": "AP", - "offset": -1 + "offset": 0 } } } ] ], [ - 1231, + 3135, [ { - "LinearSplit": { - "value": { - "Deref": { - "register": "AP", - "offset": -2 - } - }, - "scalar": { - "Immediate": "0x8000000000000000000000000000000" - }, - "max_x": { - "Immediate": "0xffffffffffffffffffffffffffffffff" - }, - "x": { + "AllocSegment": { + "dst": { "register": "AP", - "offset": -1 - }, - "y": { + "offset": 0 + } + } + } + ] + ], + [ + 3154, + [ + { + "AllocSegment": { + "dst": { "register": "AP", "offset": 0 } @@ -20742,7 +25826,7 @@ ] ], [ - 1246, + 3169, [ { "AllocSegment": { @@ -20755,19 +25839,10 @@ ] ], [ - 1265, + 3184, [ { - "TestLessThanOrEqual": { - "lhs": { - "Immediate": "0x9c0e" - }, - "rhs": { - "Deref": { - "register": "AP", - "offset": -18 - } - }, + "AllocSegment": { "dst": { "register": "AP", "offset": 0 @@ -20777,7 +25852,7 @@ ] ], [ - 1286, + 3199, [ { "AllocSegment": { @@ -20790,7 +25865,7 @@ ] ], [ - 1304, + 3214, [ { "AllocSegment": { @@ -20803,7 +25878,7 @@ ] ], [ - 1326, + 3238, [ { "AllocSegment": { @@ -20816,7 +25891,7 @@ ] ], [ - 1340, + 3253, [ { "AllocSegment": { @@ -20829,12 +25904,12 @@ ] ], [ - 1357, + 3271, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x654" + "Immediate": "0x0" }, "rhs": { "Deref": { @@ -20851,68 +25926,78 @@ ] ], [ - 1391, + 3310, [ { "TestLessThan": { "lhs": { - "BinOp": { - "op": "Add", - "a": { - "register": "FP", - "offset": 2 - }, - "b": { - "Immediate": "0x0" - } + "Deref": { + "register": "FP", + "offset": 1 } }, "rhs": { - "Immediate": "0x10000000000000000" + "Immediate": "0x800000000000000000000000000000000000000000000000000000000000000" }, "dst": { "register": "AP", - "offset": 0 + "offset": 4 } } } ] ], [ - 1395, + 3314, [ { "LinearSplit": { "value": { "Deref": { "register": "AP", - "offset": -1 + "offset": 3 } }, "scalar": { - "Immediate": "0x8000000000000110000000000000000" + "Immediate": "0x110000000000000000" }, "max_x": { - "Immediate": "0xfffffffffffffffffffffffffffffffe" + "Immediate": "0xffffffffffffffffffffffffffffffff" }, "x": { "register": "AP", - "offset": 0 + "offset": -2 }, "y": { "register": "AP", - "offset": 1 + "offset": -1 } } } ] ], [ - 1436, + 3324, [ { - "AllocSegment": { - "dst": { + "LinearSplit": { + "value": { + "Deref": { + "register": "FP", + "offset": 1 + } + }, + "scalar": { + "Immediate": "0x8000000000000000000000000000000" + }, + "max_x": { + "Immediate": "0xffffffffffffffffffffffffffffffff" + }, + "x": { + "register": "AP", + "offset": -1 + }, + "y": { "register": "AP", "offset": 0 } @@ -20921,7 +26006,7 @@ ] ], [ - 1474, + 3368, [ { "AllocSegment": { @@ -20934,7 +26019,7 @@ ] ], [ - 1494, + 3390, [ { "AllocSegment": { @@ -20947,17 +26032,17 @@ ] ], [ - 1513, + 3411, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x87a" + "Immediate": "0x29cc" }, "rhs": { "Deref": { "register": "AP", - "offset": -12 + "offset": -2 } }, "dst": { @@ -20969,33 +26054,22 @@ ] ], [ - 1540, + 3434, [ { - "AllocSegment": { - "dst": { - "register": "AP", - "offset": 0 - } - } - } - ] - ], - [ - 1558, - [ - { - "AllocSegment": { - "dst": { - "register": "AP", - "offset": 0 + "SystemCall": { + "system": { + "Deref": { + "register": "FP", + "offset": -5 + } } } } ] ], [ - 1587, + 3457, [ { "AllocSegment": { @@ -21008,7 +26082,7 @@ ] ], [ - 1615, + 3489, [ { "AllocSegment": { @@ -21021,7 +26095,7 @@ ] ], [ - 1636, + 3503, [ { "AllocSegment": { @@ -21034,7 +26108,7 @@ ] ], [ - 1650, + 3527, [ { "AllocSegment": { @@ -21047,19 +26121,10 @@ ] ], [ - 1665, + 3541, [ { - "TestLessThanOrEqual": { - "lhs": { - "Immediate": "0x0" - }, - "rhs": { - "Deref": { - "register": "FP", - "offset": -6 - } - }, + "AllocSegment": { "dst": { "register": "AP", "offset": 0 @@ -21069,78 +26134,20 @@ ] ], [ - 1698, + 3557, [ { - "TestLessThan": { + "TestLessThanOrEqual": { "lhs": { - "Deref": { - "register": "AP", - "offset": -1 - } + "Immediate": "0x0" }, "rhs": { - "Immediate": "0x800000000000000000000000000000000000000000000000000000000000000" - }, - "dst": { - "register": "AP", - "offset": 4 - } - } - } - ] - ], - [ - 1702, - [ - { - "LinearSplit": { - "value": { - "Deref": { - "register": "AP", - "offset": 3 - } - }, - "scalar": { - "Immediate": "0x110000000000000000" - }, - "max_x": { - "Immediate": "0xffffffffffffffffffffffffffffffff" - }, - "x": { - "register": "AP", - "offset": -2 - }, - "y": { - "register": "AP", - "offset": -1 - } - } - } - ] - ], - [ - 1712, - [ - { - "LinearSplit": { - "value": { "Deref": { - "register": "AP", - "offset": -2 + "register": "FP", + "offset": -6 } }, - "scalar": { - "Immediate": "0x8000000000000000000000000000000" - }, - "max_x": { - "Immediate": "0xffffffffffffffffffffffffffffffff" - }, - "x": { - "register": "AP", - "offset": -1 - }, - "y": { + "dst": { "register": "AP", "offset": 0 } @@ -21149,14 +26156,14 @@ ] ], [ - 1743, + 3595, [ { "TestLessThan": { "lhs": { "Deref": { "register": "AP", - "offset": -1 + "offset": -2 } }, "rhs": { @@ -21171,7 +26178,7 @@ ] ], [ - 1747, + 3599, [ { "LinearSplit": { @@ -21200,14 +26207,14 @@ ] ], [ - 1757, + 3609, [ { "LinearSplit": { "value": { "Deref": { "register": "AP", - "offset": -2 + "offset": -3 } }, "scalar": { @@ -21229,7 +26236,7 @@ ] ], [ - 1772, + 3665, [ { "AllocSegment": { @@ -21242,17 +26249,17 @@ ] ], [ - 1791, + 3686, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x1e50" + "Immediate": "0x6018" }, "rhs": { "Deref": { "register": "AP", - "offset": -29 + "offset": -2 } }, "dst": { @@ -21264,22 +26271,20 @@ ] ], [ - 1810, + 3715, [ { - "SystemCall": { - "system": { - "Deref": { - "register": "FP", - "offset": -5 - } + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 } } } ] ], [ - 1820, + 3730, [ { "AllocSegment": { @@ -21292,7 +26297,7 @@ ] ], [ - 1830, + 3745, [ { "AllocSegment": { @@ -21305,7 +26310,7 @@ ] ], [ - 1857, + 3760, [ { "AllocSegment": { @@ -21318,7 +26323,7 @@ ] ], [ - 1879, + 3775, [ { "AllocSegment": { @@ -21331,7 +26336,7 @@ ] ], [ - 1900, + 3799, [ { "AllocSegment": { @@ -21344,7 +26349,7 @@ ] ], [ - 1914, + 3813, [ { "AllocSegment": { @@ -21357,7 +26362,7 @@ ] ], [ - 1929, + 3829, [ { "TestLessThanOrEqual": { @@ -21379,64 +26384,87 @@ ] ], [ - 1963, + 3867, [ { "TestLessThan": { "lhs": { - "BinOp": { - "op": "Add", - "a": { - "register": "AP", - "offset": -1 - }, - "b": { - "Immediate": "0x0" - } + "Deref": { + "register": "AP", + "offset": -2 } }, "rhs": { - "Immediate": "0x10000000000000000" + "Immediate": "0x800000000000000000000000000000000000000000000000000000000000000" }, "dst": { "register": "AP", - "offset": 0 + "offset": 4 } } } ] ], [ - 1967, + 3871, [ { "LinearSplit": { "value": { "Deref": { "register": "AP", - "offset": -1 + "offset": 3 } }, "scalar": { - "Immediate": "0x8000000000000110000000000000000" + "Immediate": "0x110000000000000000" }, "max_x": { - "Immediate": "0xfffffffffffffffffffffffffffffffe" + "Immediate": "0xffffffffffffffffffffffffffffffff" }, "x": { "register": "AP", - "offset": 0 + "offset": -2 }, "y": { "register": "AP", - "offset": 1 + "offset": -1 } } } ] ], [ - 1992, + 3881, + [ + { + "LinearSplit": { + "value": { + "Deref": { + "register": "AP", + "offset": -3 + } + }, + "scalar": { + "Immediate": "0x8000000000000000000000000000000" + }, + "max_x": { + "Immediate": "0xffffffffffffffffffffffffffffffff" + }, + "x": { + "register": "AP", + "offset": -1 + }, + "y": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 3897, [ { "AllocSegment": { @@ -21449,17 +26477,17 @@ ] ], [ - 2011, + 3918, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x1248" + "Immediate": "0x2904" }, "rhs": { "Deref": { "register": "AP", - "offset": -16 + "offset": -2 } }, "dst": { @@ -21471,7 +26499,7 @@ ] ], [ - 2030, + 3938, [ { "SystemCall": { @@ -21486,7 +26514,7 @@ ] ], [ - 2033, + 3942, [ { "AllocSegment": { @@ -21499,7 +26527,7 @@ ] ], [ - 2056, + 3964, [ { "AllocSegment": { @@ -21512,7 +26540,7 @@ ] ], [ - 2078, + 3988, [ { "AllocSegment": { @@ -21525,7 +26553,7 @@ ] ], [ - 2092, + 4002, [ { "AllocSegment": { @@ -21538,12 +26566,12 @@ ] ], [ - 2109, + 4020, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x82c8" + "Immediate": "0x0" }, "rhs": { "Deref": { @@ -21560,7 +26588,20 @@ ] ], [ - 2172, + 4067, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 4089, [ { "AllocSegment": { @@ -21573,17 +26614,17 @@ ] ], [ - 2191, + 4110, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x8070" + "Immediate": "0x29cc" }, "rhs": { "Deref": { "register": "AP", - "offset": -39 + "offset": -2 } }, "dst": { @@ -21595,20 +26636,22 @@ ] ], [ - 2234, + 4132, [ { - "AllocSegment": { - "dst": { - "register": "AP", - "offset": 0 + "SystemCall": { + "system": { + "Deref": { + "register": "FP", + "offset": -5 + } } } } ] ], [ - 2252, + 4136, [ { "AllocSegment": { @@ -21621,7 +26664,7 @@ ] ], [ - 2267, + 4158, [ { "AllocSegment": { @@ -21634,7 +26677,7 @@ ] ], [ - 2281, + 4190, [ { "AllocSegment": { @@ -21647,7 +26690,7 @@ ] ], [ - 2295, + 4204, [ { "AllocSegment": { @@ -21660,7 +26703,7 @@ ] ], [ - 2309, + 4219, [ { "AllocSegment": { @@ -21673,10 +26716,19 @@ ] ], [ - 2331, + 4235, [ { - "AllocSegment": { + "TestLessThanOrEqual": { + "lhs": { + "Immediate": "0x0" + }, + "rhs": { + "Deref": { + "register": "FP", + "offset": -6 + } + }, "dst": { "register": "AP", "offset": 0 @@ -21686,7 +26738,7 @@ ] ], [ - 2345, + 4254, [ { "AllocSegment": { @@ -21699,17 +26751,17 @@ ] ], [ - 2362, + 4276, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x0" + "Immediate": "0x2076" }, "rhs": { "Deref": { - "register": "FP", - "offset": -6 + "register": "AP", + "offset": -2 } }, "dst": { @@ -21721,78 +26773,26 @@ ] ], [ - 2396, + 4288, [ { - "TestLessThan": { - "lhs": { + "AllocFelt252Dict": { + "segment_arena_ptr": { "Deref": { "register": "FP", - "offset": 0 - } - }, - "rhs": { - "Immediate": "0x800000000000000000000000000000000000000000000000000000000000000" - }, - "dst": { - "register": "AP", - "offset": 4 - } - } - } - ] - ], - [ - 2400, - [ - { - "LinearSplit": { - "value": { - "Deref": { - "register": "AP", - "offset": 3 + "offset": -7 } - }, - "scalar": { - "Immediate": "0x110000000000000000" - }, - "max_x": { - "Immediate": "0xffffffffffffffffffffffffffffffff" - }, - "x": { - "register": "AP", - "offset": -2 - }, - "y": { - "register": "AP", - "offset": -1 } } } ] ], [ - 2410, + 4307, [ { - "LinearSplit": { - "value": { - "Deref": { - "register": "FP", - "offset": 0 - } - }, - "scalar": { - "Immediate": "0x8000000000000000000000000000000" - }, - "max_x": { - "Immediate": "0xffffffffffffffffffffffffffffffff" - }, - "x": { - "register": "AP", - "offset": -1 - }, - "y": { + "AllocSegment": { + "dst": { "register": "AP", "offset": 0 } @@ -21801,7 +26801,7 @@ ] ], [ - 2450, + 4318, [ { "AllocSegment": { @@ -21814,7 +26814,7 @@ ] ], [ - 2470, + 4334, [ { "AllocSegment": { @@ -21827,114 +26827,12 @@ ] ], [ - 2489, + 4353, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x2404" - }, - "rhs": { - "Deref": { - "register": "AP", - "offset": -12 - } - }, - "dst": { - "register": "AP", - "offset": 0 - } - } - } - ] - ], - [ - 2511, - [ - { - "SystemCall": { - "system": { - "Deref": { - "register": "FP", - "offset": -5 - } - } - } - } - ] - ], - [ - 2532, - [ - { - "AllocSegment": { - "dst": { - "register": "AP", - "offset": 0 - } - } - } - ] - ], - [ - 2561, - [ - { - "AllocSegment": { - "dst": { - "register": "AP", - "offset": 0 - } - } - } - ] - ], - [ - 2575, - [ - { - "AllocSegment": { - "dst": { - "register": "AP", - "offset": 0 - } - } - } - ] - ], - [ - 2596, - [ - { - "AllocSegment": { - "dst": { - "register": "AP", - "offset": 0 - } - } - } - ] - ], - [ - 2610, - [ - { - "AllocSegment": { - "dst": { - "register": "AP", - "offset": 0 - } - } - } - ] - ], - [ - 2625, - [ - { - "TestLessThanOrEqual": { - "lhs": { - "Immediate": "0x0" + "Immediate": "0x26c" }, "rhs": { "Deref": { @@ -21951,14 +26849,14 @@ ] ], [ - 2658, + 4391, [ { "TestLessThan": { "lhs": { "Deref": { - "register": "AP", - "offset": -1 + "register": "FP", + "offset": 1 } }, "rhs": { @@ -21973,7 +26871,7 @@ ] ], [ - 2662, + 4395, [ { "LinearSplit": { @@ -22002,14 +26900,14 @@ ] ], [ - 2672, + 4405, [ { "LinearSplit": { "value": { "Deref": { - "register": "AP", - "offset": -2 + "register": "FP", + "offset": 1 } }, "scalar": { @@ -22031,7 +26929,7 @@ ] ], [ - 2723, + 4449, [ { "AllocSegment": { @@ -22044,17 +26942,30 @@ ] ], [ - 2742, + 4492, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 4513, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x5172" + "Immediate": "0x2b5c" }, "rhs": { "Deref": { "register": "AP", - "offset": -34 + "offset": -2 } }, "dst": { @@ -22066,7 +26977,22 @@ ] ], [ - 2771, + 4540, + [ + { + "SystemCall": { + "system": { + "Deref": { + "register": "FP", + "offset": -5 + } + } + } + } + ] + ], + [ + 4544, [ { "AllocSegment": { @@ -22079,7 +27005,7 @@ ] ], [ - 2786, + 4566, [ { "AllocSegment": { @@ -22092,7 +27018,7 @@ ] ], [ - 2800, + 4581, [ { "AllocSegment": { @@ -22105,7 +27031,7 @@ ] ], [ - 2814, + 4613, [ { "AllocSegment": { @@ -22118,7 +27044,7 @@ ] ], [ - 2828, + 4627, [ { "AllocSegment": { @@ -22131,7 +27057,7 @@ ] ], [ - 2849, + 4651, [ { "AllocSegment": { @@ -22144,7 +27070,7 @@ ] ], [ - 2863, + 4665, [ { "AllocSegment": { @@ -22157,7 +27083,7 @@ ] ], [ - 2878, + 4681, [ { "TestLessThanOrEqual": { @@ -22179,87 +27105,55 @@ ] ], [ - 2911, + 4720, [ { "TestLessThan": { "lhs": { "Deref": { "register": "AP", - "offset": -1 + "offset": -2 } }, "rhs": { - "Immediate": "0x800000000000000000000000000000000000000000000000000000000000000" + "Immediate": "0x100000000000000000000000000000000" }, "dst": { "register": "AP", - "offset": 4 - } - } - } - ] - ], - [ - 2915, - [ - { - "LinearSplit": { - "value": { - "Deref": { - "register": "AP", - "offset": 3 - } - }, - "scalar": { - "Immediate": "0x110000000000000000" - }, - "max_x": { - "Immediate": "0xffffffffffffffffffffffffffffffff" - }, - "x": { - "register": "AP", - "offset": -2 - }, - "y": { - "register": "AP", - "offset": -1 + "offset": 0 } } } ] ], [ - 2925, + 4722, [ { - "LinearSplit": { - "value": { + "DivMod": { + "lhs": { "Deref": { "register": "AP", - "offset": -2 + "offset": -3 } }, - "scalar": { - "Immediate": "0x8000000000000000000000000000000" - }, - "max_x": { - "Immediate": "0xffffffffffffffffffffffffffffffff" + "rhs": { + "Immediate": "0x100000000000000000000000000000000" }, - "x": { + "quotient": { "register": "AP", - "offset": -1 + "offset": 3 }, - "y": { + "remainder": { "register": "AP", - "offset": 0 + "offset": 4 } } } ] ], [ - 2940, + 4751, [ { "AllocSegment": { @@ -22272,17 +27166,17 @@ ] ], [ - 2959, + 4772, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x128e" + "Immediate": "0x690" }, "rhs": { "Deref": { "register": "AP", - "offset": -18 + "offset": -2 } }, "dst": { @@ -22294,22 +27188,20 @@ ] ], [ - 2978, + 4792, [ { - "SystemCall": { - "system": { - "Deref": { - "register": "FP", - "offset": -5 - } + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 } } } ] ], [ - 2981, + 4813, [ { "AllocSegment": { @@ -22322,7 +27214,7 @@ ] ], [ - 3001, + 4837, [ { "AllocSegment": { @@ -22335,7 +27227,7 @@ ] ], [ - 3023, + 4851, [ { "AllocSegment": { @@ -22348,7 +27240,29 @@ ] ], [ - 3037, + 4867, + [ + { + "TestLessThanOrEqual": { + "lhs": { + "Immediate": "0x0" + }, + "rhs": { + "Deref": { + "register": "FP", + "offset": -6 + } + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 4886, [ { "AllocSegment": { @@ -22361,17 +27275,17 @@ ] ], [ - 3054, + 4907, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x0" + "Immediate": "0x96c8" }, "rhs": { "Deref": { - "register": "FP", - "offset": -6 + "register": "AP", + "offset": -2 } }, "dst": { @@ -22383,7 +27297,7 @@ ] ], [ - 3096, + 4927, [ { "AllocSegment": { @@ -22396,7 +27310,7 @@ ] ], [ - 3116, + 4946, [ { "AllocSegment": { @@ -22409,19 +27323,10 @@ ] ], [ - 3135, + 4961, [ { - "TestLessThanOrEqual": { - "lhs": { - "Immediate": "0x1c8e" - }, - "rhs": { - "Deref": { - "register": "AP", - "offset": -12 - } - }, + "AllocSegment": { "dst": { "register": "AP", "offset": 0 @@ -22431,22 +27336,29 @@ ] ], [ - 3156, + 4977, [ { - "SystemCall": { - "system": { + "TestLessThanOrEqual": { + "lhs": { + "Immediate": "0x0" + }, + "rhs": { "Deref": { "register": "FP", - "offset": -5 + "offset": -6 } + }, + "dst": { + "register": "AP", + "offset": 0 } } } ] ], [ - 3159, + 4996, [ { "AllocSegment": { @@ -22459,10 +27371,19 @@ ] ], [ - 3179, + 5017, [ { - "AllocSegment": { + "TestLessThanOrEqual": { + "lhs": { + "Immediate": "0x58b6" + }, + "rhs": { + "Deref": { + "register": "AP", + "offset": -2 + } + }, "dst": { "register": "AP", "offset": 0 @@ -22472,7 +27393,7 @@ ] ], [ - 3208, + 5037, [ { "AllocSegment": { @@ -22485,7 +27406,7 @@ ] ], [ - 3222, + 5056, [ { "AllocSegment": { @@ -22498,7 +27419,7 @@ ] ], [ - 3236, + 5071, [ { "AllocSegment": { @@ -22511,7 +27432,7 @@ ] ], [ - 3251, + 5087, [ { "TestLessThanOrEqual": { @@ -22533,7 +27454,7 @@ ] ], [ - 3268, + 5106, [ { "AllocSegment": { @@ -22546,17 +27467,20 @@ ] ], [ - 3288, + 5133, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x41a" + "Deref": { + "register": "AP", + "offset": -1 + } }, "rhs": { "Deref": { "register": "AP", - "offset": -7 + "offset": -5 } }, "dst": { @@ -22568,22 +27492,7 @@ ] ], [ - 3300, - [ - { - "AllocFelt252Dict": { - "segment_arena_ptr": { - "Deref": { - "register": "FP", - "offset": -7 - } - } - } - } - ] - ], - [ - 3319, + 5152, [ { "AllocSegment": { @@ -22596,7 +27505,7 @@ ] ], [ - 3330, + 5173, [ { "AllocSegment": { @@ -22609,7 +27518,7 @@ ] ], [ - 3346, + 5189, [ { "AllocSegment": { @@ -22622,7 +27531,7 @@ ] ], [ - 3364, + 5206, [ { "TestLessThanOrEqual": { @@ -22644,78 +27553,46 @@ ] ], [ - 3398, + 5225, [ { - "TestLessThan": { - "lhs": { - "Deref": { - "register": "FP", - "offset": 0 - } - }, - "rhs": { - "Immediate": "0x800000000000000000000000000000000000000000000000000000000000000" - }, + "AllocSegment": { "dst": { "register": "AP", - "offset": 4 + "offset": 0 } } } ] ], [ - 3402, + 5246, [ { - "LinearSplit": { - "value": { + "TestLessThanOrEqual": { + "lhs": { + "Immediate": "0x3909e" + }, + "rhs": { "Deref": { "register": "AP", - "offset": 3 + "offset": -2 } }, - "scalar": { - "Immediate": "0x110000000000000000" - }, - "max_x": { - "Immediate": "0xffffffffffffffffffffffffffffffff" - }, - "x": { - "register": "AP", - "offset": -2 - }, - "y": { + "dst": { "register": "AP", - "offset": -1 + "offset": 0 } } } ] ], [ - 3412, + 5266, [ { - "LinearSplit": { - "value": { - "Deref": { - "register": "FP", - "offset": 0 - } - }, - "scalar": { - "Immediate": "0x8000000000000000000000000000000" - }, - "max_x": { - "Immediate": "0xffffffffffffffffffffffffffffffff" - }, - "x": { - "register": "AP", - "offset": -1 - }, - "y": { + "AllocSegment": { + "dst": { "register": "AP", "offset": 0 } @@ -22724,7 +27601,7 @@ ] ], [ - 3452, + 5285, [ { "AllocSegment": { @@ -22737,7 +27614,7 @@ ] ], [ - 3489, + 5300, [ { "AllocSegment": { @@ -22750,17 +27627,17 @@ ] ], [ - 3508, + 5316, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x28b4" + "Immediate": "0x0" }, "rhs": { "Deref": { - "register": "AP", - "offset": -17 + "register": "FP", + "offset": -6 } }, "dst": { @@ -22772,25 +27649,32 @@ ] ], [ - 3534, + 5355, [ { - "SystemCall": { - "system": { - "Deref": { - "register": "FP", - "offset": -5 - } + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 } } } ] ], [ - 3537, + 5376, [ { - "AllocSegment": { + "TestLessThanOrEqual": { + "lhs": { + "Immediate": "0xc8" + }, + "rhs": { + "Deref": { + "register": "AP", + "offset": -2 + } + }, "dst": { "register": "AP", "offset": 0 @@ -22800,7 +27684,7 @@ ] ], [ - 3557, + 5394, [ { "AllocSegment": { @@ -22813,7 +27697,7 @@ ] ], [ - 3572, + 5408, [ { "AllocSegment": { @@ -22826,7 +27710,7 @@ ] ], [ - 3600, + 5422, [ { "AllocSegment": { @@ -22839,7 +27723,7 @@ ] ], [ - 3614, + 5437, [ { "AllocSegment": { @@ -22852,7 +27736,7 @@ ] ], [ - 3635, + 5452, [ { "AllocSegment": { @@ -22865,7 +27749,7 @@ ] ], [ - 3649, + 5467, [ { "AllocSegment": { @@ -22878,7 +27762,7 @@ ] ], [ - 3664, + 5483, [ { "TestLessThanOrEqual": { @@ -22900,7 +27784,20 @@ ] ], [ - 3681, + 5520, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 5542, [ { "AllocSegment": { @@ -22913,17 +27810,17 @@ ] ], [ - 3700, + 5563, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x7602" + "Immediate": "0x74e" }, "rhs": { "Deref": { "register": "AP", - "offset": -7 + "offset": -2 } }, "dst": { @@ -22935,7 +27832,7 @@ ] ], [ - 3720, + 5585, [ { "AllocSegment": { @@ -22948,7 +27845,7 @@ ] ], [ - 3738, + 5606, [ { "AllocSegment": { @@ -22961,7 +27858,7 @@ ] ], [ - 3753, + 5638, [ { "AllocSegment": { @@ -22974,7 +27871,20 @@ ] ], [ - 3768, + 5652, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 5668, [ { "TestLessThanOrEqual": { @@ -22996,7 +27906,7 @@ ] ], [ - 3785, + 5687, [ { "AllocSegment": { @@ -23009,17 +27919,17 @@ ] ], [ - 3804, + 5708, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x3b92" + "Immediate": "0x0" }, "rhs": { "Deref": { "register": "AP", - "offset": -7 + "offset": -2 } }, "dst": { @@ -23031,7 +27941,7 @@ ] ], [ - 3824, + 5720, [ { "AllocSegment": { @@ -23044,7 +27954,7 @@ ] ], [ - 3842, + 5736, [ { "AllocSegment": { @@ -23057,7 +27967,7 @@ ] ], [ - 3857, + 5751, [ { "AllocSegment": { @@ -23070,7 +27980,7 @@ ] ], [ - 3872, + 5767, [ { "TestLessThanOrEqual": { @@ -23092,7 +28002,7 @@ ] ], [ - 3889, + 5796, [ { "AllocSegment": { @@ -23105,20 +28015,17 @@ ] ], [ - 3914, + 5817, [ { "TestLessThanOrEqual": { "lhs": { - "Deref": { - "register": "AP", - "offset": -1 - } + "Immediate": "0x5be" }, "rhs": { "Deref": { "register": "AP", - "offset": -10 + "offset": -2 } }, "dst": { @@ -23130,7 +28037,20 @@ ] ], [ - 3933, + 5837, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 5856, [ { "AllocSegment": { @@ -23143,7 +28063,7 @@ ] ], [ - 3953, + 5871, [ { "AllocSegment": { @@ -23156,7 +28076,7 @@ ] ], [ - 3969, + 5886, [ { "AllocSegment": { @@ -23169,7 +28089,7 @@ ] ], [ - 3985, + 5902, [ { "TestLessThanOrEqual": { @@ -23191,7 +28111,7 @@ ] ], [ - 4002, + 5931, [ { "AllocSegment": { @@ -23204,17 +28124,17 @@ ] ], [ - 4021, + 5952, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x36998" + "Immediate": "0x5be" }, "rhs": { "Deref": { "register": "AP", - "offset": -7 + "offset": -2 } }, "dst": { @@ -23226,7 +28146,7 @@ ] ], [ - 4041, + 5972, [ { "AllocSegment": { @@ -23239,7 +28159,7 @@ ] ], [ - 4059, + 5991, [ { "AllocSegment": { @@ -23252,7 +28172,7 @@ ] ], [ - 4074, + 6006, [ { "AllocSegment": { @@ -23265,29 +28185,7 @@ ] ], [ - 4089, - [ - { - "TestLessThanOrEqual": { - "lhs": { - "Immediate": "0x0" - }, - "rhs": { - "Deref": { - "register": "FP", - "offset": -6 - } - }, - "dst": { - "register": "AP", - "offset": 0 - } - } - } - ] - ], - [ - 4124, + 6021, [ { "AllocSegment": { @@ -23300,7 +28198,7 @@ ] ], [ - 4143, + 6037, [ { "TestLessThanOrEqual": { @@ -23309,8 +28207,8 @@ }, "rhs": { "Deref": { - "register": "AP", - "offset": -15 + "register": "FP", + "offset": -6 } }, "dst": { @@ -23322,37 +28220,78 @@ ] ], [ - 4160, + 6075, [ { - "AllocSegment": { + "TestLessThan": { + "lhs": { + "Deref": { + "register": "AP", + "offset": -2 + } + }, + "rhs": { + "Immediate": "0x800000000000000000000000000000000000000000000000000000000000000" + }, "dst": { "register": "AP", - "offset": 0 + "offset": 4 } } } ] ], [ - 4174, + 6079, [ { - "AllocSegment": { - "dst": { + "LinearSplit": { + "value": { + "Deref": { + "register": "AP", + "offset": 3 + } + }, + "scalar": { + "Immediate": "0x110000000000000000" + }, + "max_x": { + "Immediate": "0xffffffffffffffffffffffffffffffff" + }, + "x": { "register": "AP", - "offset": 0 + "offset": -2 + }, + "y": { + "register": "AP", + "offset": -1 } } } ] ], [ - 4188, + 6089, [ { - "AllocSegment": { - "dst": { + "LinearSplit": { + "value": { + "Deref": { + "register": "AP", + "offset": -3 + } + }, + "scalar": { + "Immediate": "0x8000000000000000000000000000000" + }, + "max_x": { + "Immediate": "0xffffffffffffffffffffffffffffffff" + }, + "x": { + "register": "AP", + "offset": -1 + }, + "y": { "register": "AP", "offset": 0 } @@ -23361,7 +28300,7 @@ ] ], [ - 4203, + 6125, [ { "AllocSegment": { @@ -23374,10 +28313,19 @@ ] ], [ - 4217, + 6146, [ { - "AllocSegment": { + "TestLessThanOrEqual": { + "lhs": { + "Immediate": "0x2e7c" + }, + "rhs": { + "Deref": { + "register": "AP", + "offset": -2 + } + }, "dst": { "register": "AP", "offset": 0 @@ -23387,7 +28335,7 @@ ] ], [ - 4231, + 6170, [ { "AllocSegment": { @@ -23400,29 +28348,22 @@ ] ], [ - 4246, + 6189, [ { - "TestLessThanOrEqual": { - "lhs": { - "Immediate": "0x0" - }, - "rhs": { + "SystemCall": { + "system": { "Deref": { "register": "FP", - "offset": -6 + "offset": -5 } - }, - "dst": { - "register": "AP", - "offset": 0 } } } ] ], [ - 4279, + 6196, [ { "AllocSegment": { @@ -23435,7 +28376,7 @@ ] ], [ - 4299, + 6217, [ { "AllocSegment": { @@ -23448,29 +28389,7 @@ ] ], [ - 4318, - [ - { - "TestLessThanOrEqual": { - "lhs": { - "Immediate": "0x0" - }, - "rhs": { - "Deref": { - "register": "AP", - "offset": -12 - } - }, - "dst": { - "register": "AP", - "offset": 0 - } - } - } - ] - ], - [ - 4340, + 6232, [ { "AllocSegment": { @@ -23483,7 +28402,7 @@ ] ], [ - 4360, + 6247, [ { "AllocSegment": { @@ -23496,7 +28415,7 @@ ] ], [ - 4389, + 6271, [ { "AllocSegment": { @@ -23509,7 +28428,7 @@ ] ], [ - 4403, + 6285, [ { "AllocSegment": { @@ -23522,7 +28441,7 @@ ] ], [ - 4418, + 6301, [ { "TestLessThanOrEqual": { @@ -23544,7 +28463,7 @@ ] ], [ - 4435, + 6350, [ { "AllocSegment": { @@ -23557,17 +28476,20 @@ ] ], [ - 4454, + 6377, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x0" + "Deref": { + "register": "AP", + "offset": -1 + } }, "rhs": { "Deref": { "register": "AP", - "offset": -7 + "offset": -5 } }, "dst": { @@ -23579,7 +28501,7 @@ ] ], [ - 4466, + 6399, [ { "AllocSegment": { @@ -23592,7 +28514,7 @@ ] ], [ - 4481, + 6420, [ { "AllocSegment": { @@ -23605,7 +28527,7 @@ ] ], [ - 4496, + 6436, [ { "AllocSegment": { @@ -23618,19 +28540,10 @@ ] ], [ - 4511, + 6452, [ { - "TestLessThanOrEqual": { - "lhs": { - "Immediate": "0x0" - }, - "rhs": { - "Deref": { - "register": "FP", - "offset": -6 - } - }, + "AllocSegment": { "dst": { "register": "AP", "offset": 0 @@ -23640,7 +28553,7 @@ ] ], [ - 4537, + 6468, [ { "AllocSegment": { @@ -23653,19 +28566,10 @@ ] ], [ - 4556, + 6484, [ { - "TestLessThanOrEqual": { - "lhs": { - "Immediate": "0x0" - }, - "rhs": { - "Deref": { - "register": "AP", - "offset": -11 - } - }, + "AllocSegment": { "dst": { "register": "AP", "offset": 0 @@ -23675,10 +28579,19 @@ ] ], [ - 4576, + 6501, [ { - "AllocSegment": { + "TestLessThanOrEqual": { + "lhs": { + "Immediate": "0x0" + }, + "rhs": { + "Deref": { + "register": "FP", + "offset": -6 + } + }, "dst": { "register": "AP", "offset": 0 @@ -23688,10 +28601,19 @@ ] ], [ - 4594, + 6550, [ { - "AllocSegment": { + "TestLessThan": { + "lhs": { + "Deref": { + "register": "AP", + "offset": -2 + } + }, + "rhs": { + "Immediate": "0x100000000000000000000000000000000" + }, "dst": { "register": "AP", "offset": 0 @@ -23701,23 +28623,45 @@ ] ], [ - 4609, + 6552, [ { - "AllocSegment": { - "dst": { + "DivMod": { + "lhs": { + "Deref": { + "register": "AP", + "offset": -3 + } + }, + "rhs": { + "Immediate": "0x100000000000000000000000000000000" + }, + "quotient": { "register": "AP", - "offset": 0 + "offset": 3 + }, + "remainder": { + "register": "AP", + "offset": 4 } } } ] ], [ - 4623, + 6601, [ { - "AllocSegment": { + "TestLessThan": { + "lhs": { + "Deref": { + "register": "AP", + "offset": -2 + } + }, + "rhs": { + "Immediate": "0x100000000000000000000000000000000" + }, "dst": { "register": "AP", "offset": 0 @@ -23727,29 +28671,33 @@ ] ], [ - 4638, + 6603, [ { - "TestLessThanOrEqual": { + "DivMod": { "lhs": { - "Immediate": "0x0" - }, - "rhs": { "Deref": { - "register": "FP", - "offset": -6 + "register": "AP", + "offset": -3 } }, - "dst": { + "rhs": { + "Immediate": "0x100000000000000000000000000000000" + }, + "quotient": { "register": "AP", - "offset": 0 + "offset": 3 + }, + "remainder": { + "register": "AP", + "offset": 4 } } } ] ], [ - 4664, + 6632, [ { "AllocSegment": { @@ -23762,17 +28710,20 @@ ] ], [ - 4683, + 6664, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x0" + "Deref": { + "register": "AP", + "offset": -1 + } }, "rhs": { "Deref": { "register": "AP", - "offset": -11 + "offset": -8 } }, "dst": { @@ -23784,7 +28735,7 @@ ] ], [ - 4703, + 6687, [ { "AllocSegment": { @@ -23797,7 +28748,7 @@ ] ], [ - 4721, + 6710, [ { "AllocSegment": { @@ -23810,7 +28761,7 @@ ] ], [ - 4736, + 6752, [ { "AllocSegment": { @@ -23823,7 +28774,7 @@ ] ], [ - 4750, + 6768, [ { "AllocSegment": { @@ -23836,7 +28787,7 @@ ] ], [ - 4765, + 6786, [ { "TestLessThanOrEqual": { @@ -23858,14 +28809,14 @@ ] ], [ - 4798, + 6824, [ { "TestLessThan": { "lhs": { "Deref": { "register": "AP", - "offset": -1 + "offset": -2 } }, "rhs": { @@ -23880,7 +28831,7 @@ ] ], [ - 4802, + 6828, [ { "LinearSplit": { @@ -23909,14 +28860,14 @@ ] ], [ - 4812, + 6838, [ { "LinearSplit": { "value": { "Deref": { "register": "AP", - "offset": -2 + "offset": -3 } }, "scalar": { @@ -23938,32 +28889,19 @@ ] ], [ - 4845, + 6884, [ { - "AllocSegment": { - "dst": { - "register": "AP", - "offset": 0 - } - } - } - ] - ], - [ - 4864, - [ - { - "TestLessThanOrEqual": { + "TestLessThan": { "lhs": { - "Immediate": "0x1b8a" - }, - "rhs": { "Deref": { "register": "AP", - "offset": -26 + "offset": -2 } }, + "rhs": { + "Immediate": "0x100000000000000000000000000000000" + }, "dst": { "register": "AP", "offset": 0 @@ -23973,64 +28911,45 @@ ] ], [ - 4886, - [ - { - "AllocSegment": { - "dst": { - "register": "AP", - "offset": 0 - } - } - } - ] - ], - [ - 4904, + 6886, [ { - "SystemCall": { - "system": { + "DivMod": { + "lhs": { "Deref": { - "register": "FP", - "offset": -5 + "register": "AP", + "offset": -3 } - } - } - } - ] - ], - [ - 4910, - [ - { - "AllocSegment": { - "dst": { + }, + "rhs": { + "Immediate": "0x100000000000000000000000000000000" + }, + "quotient": { "register": "AP", - "offset": 0 - } - } - } - ] - ], - [ - 4929, - [ - { - "AllocSegment": { - "dst": { + "offset": 3 + }, + "remainder": { "register": "AP", - "offset": 0 + "offset": 4 } } } ] ], [ - 4944, + 6935, [ { - "AllocSegment": { + "TestLessThan": { + "lhs": { + "Deref": { + "register": "AP", + "offset": -2 + } + }, + "rhs": { + "Immediate": "0x100000000000000000000000000000000" + }, "dst": { "register": "AP", "offset": 0 @@ -24040,33 +28959,33 @@ ] ], [ - 4958, + 6937, [ { - "AllocSegment": { - "dst": { + "DivMod": { + "lhs": { + "Deref": { + "register": "AP", + "offset": -3 + } + }, + "rhs": { + "Immediate": "0x100000000000000000000000000000000" + }, + "quotient": { "register": "AP", - "offset": 0 - } - } - } - ] - ], - [ - 4979, - [ - { - "AllocSegment": { - "dst": { + "offset": 3 + }, + "remainder": { "register": "AP", - "offset": 0 + "offset": 4 } } } ] ], [ - 4993, + 6966, [ { "AllocSegment": { @@ -24079,17 +28998,17 @@ ] ], [ - 5008, + 6987, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x0" + "Immediate": "0x2e18" }, "rhs": { "Deref": { - "register": "FP", - "offset": -6 + "register": "AP", + "offset": -2 } }, "dst": { @@ -24101,7 +29020,7 @@ ] ], [ - 5052, + 6999, [ { "AllocSegment": { @@ -24114,45 +29033,22 @@ ] ], [ - 5077, + 7023, [ { - "TestLessThanOrEqual": { - "lhs": { - "Deref": { - "register": "AP", - "offset": -1 - } - }, - "rhs": { + "SystemCall": { + "system": { "Deref": { - "register": "AP", - "offset": -22 + "register": "FP", + "offset": -5 } - }, - "dst": { - "register": "AP", - "offset": 0 - } - } - } - ] - ], - [ - 5099, - [ - { - "AllocSegment": { - "dst": { - "register": "AP", - "offset": 0 } } } ] ], [ - 5119, + 7027, [ { "AllocSegment": { @@ -24165,7 +29061,7 @@ ] ], [ - 5135, + 7049, [ { "AllocSegment": { @@ -24178,7 +29074,7 @@ ] ], [ - 5150, + 7089, [ { "AllocSegment": { @@ -24191,7 +29087,7 @@ ] ], [ - 5165, + 7112, [ { "AllocSegment": { @@ -24204,7 +29100,7 @@ ] ], [ - 5180, + 7126, [ { "AllocSegment": { @@ -24217,7 +29113,7 @@ ] ], [ - 5196, + 7142, [ { "TestLessThanOrEqual": { @@ -24239,10 +29135,23 @@ ] ], [ - 5239, + 7161, [ { - "TestLessThan": { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 7186, + [ + { + "TestLessThanOrEqual": { "lhs": { "Deref": { "register": "AP", @@ -24250,7 +29159,10 @@ } }, "rhs": { - "Immediate": "0x100000000000000000000000000000000" + "Deref": { + "register": "AP", + "offset": -4 + } }, "dst": { "register": "AP", @@ -24261,45 +29173,36 @@ ] ], [ - 5241, + 7205, [ { - "DivMod": { - "lhs": { - "Deref": { - "register": "AP", - "offset": -2 - } - }, - "rhs": { - "Immediate": "0x100000000000000000000000000000000" - }, - "quotient": { + "AllocSegment": { + "dst": { "register": "AP", - "offset": 3 - }, - "remainder": { + "offset": 0 + } + } + } + ] + ], + [ + 7226, + [ + { + "AllocSegment": { + "dst": { "register": "AP", - "offset": 4 + "offset": 0 } } } ] ], [ - 5286, + 7242, [ { - "TestLessThan": { - "lhs": { - "Deref": { - "register": "AP", - "offset": -1 - } - }, - "rhs": { - "Immediate": "0x100000000000000000000000000000000" - }, + "AllocSegment": { "dst": { "register": "AP", "offset": 0 @@ -24309,33 +29212,29 @@ ] ], [ - 5288, + 7259, [ { - "DivMod": { + "TestLessThanOrEqual": { "lhs": { - "Deref": { - "register": "AP", - "offset": -2 - } + "Immediate": "0x0" }, "rhs": { - "Immediate": "0x100000000000000000000000000000000" - }, - "quotient": { - "register": "AP", - "offset": 3 + "Deref": { + "register": "FP", + "offset": -6 + } }, - "remainder": { + "dst": { "register": "AP", - "offset": 4 + "offset": 0 } } } ] ], [ - 5316, + 7288, [ { "AllocSegment": { @@ -24348,7 +29247,7 @@ ] ], [ - 5346, + 7315, [ { "TestLessThanOrEqual": { @@ -24361,7 +29260,7 @@ "rhs": { "Deref": { "register": "AP", - "offset": -33 + "offset": -5 } }, "dst": { @@ -24373,7 +29272,7 @@ ] ], [ - 5369, + 7335, [ { "AllocSegment": { @@ -24386,7 +29285,7 @@ ] ], [ - 5391, + 7356, [ { "AllocSegment": { @@ -24399,7 +29298,7 @@ ] ], [ - 5431, + 7372, [ { "AllocSegment": { @@ -24412,7 +29311,7 @@ ] ], [ - 5447, + 7388, [ { "AllocSegment": { @@ -24425,7 +29324,7 @@ ] ], [ - 5464, + 7405, [ { "TestLessThanOrEqual": { @@ -24447,78 +29346,46 @@ ] ], [ - 5497, + 7434, [ { - "TestLessThan": { - "lhs": { - "Deref": { - "register": "AP", - "offset": -1 - } - }, - "rhs": { - "Immediate": "0x800000000000000000000000000000000000000000000000000000000000000" - }, + "AllocSegment": { "dst": { "register": "AP", - "offset": 4 + "offset": 0 } } } ] ], [ - 5501, + 7455, [ { - "LinearSplit": { - "value": { + "TestLessThanOrEqual": { + "lhs": { + "Immediate": "0x2c88" + }, + "rhs": { "Deref": { "register": "AP", - "offset": 3 + "offset": -2 } }, - "scalar": { - "Immediate": "0x110000000000000000" - }, - "max_x": { - "Immediate": "0xffffffffffffffffffffffffffffffff" - }, - "x": { - "register": "AP", - "offset": -2 - }, - "y": { + "dst": { "register": "AP", - "offset": -1 + "offset": 0 } } } ] ], [ - 5511, + 7467, [ { - "LinearSplit": { - "value": { - "Deref": { - "register": "AP", - "offset": -2 - } - }, - "scalar": { - "Immediate": "0x8000000000000000000000000000000" - }, - "max_x": { - "Immediate": "0xffffffffffffffffffffffffffffffff" - }, - "x": { - "register": "AP", - "offset": -1 - }, - "y": { + "AllocSegment": { + "dst": { "register": "AP", "offset": 0 } @@ -24527,19 +29394,25 @@ ] ], [ - 5552, + 7488, [ { - "TestLessThan": { - "lhs": { + "SystemCall": { + "system": { "Deref": { - "register": "AP", - "offset": -1 + "register": "FP", + "offset": -5 } - }, - "rhs": { - "Immediate": "0x100000000000000000000000000000000" - }, + } + } + } + ] + ], + [ + 7492, + [ + { + "AllocSegment": { "dst": { "register": "AP", "offset": 0 @@ -24549,45 +29422,36 @@ ] ], [ - 5554, + 7514, [ { - "DivMod": { - "lhs": { - "Deref": { - "register": "AP", - "offset": -2 - } - }, - "rhs": { - "Immediate": "0x100000000000000000000000000000000" - }, - "quotient": { + "AllocSegment": { + "dst": { "register": "AP", - "offset": 3 - }, - "remainder": { + "offset": 0 + } + } + } + ] + ], + [ + 7529, + [ + { + "AllocSegment": { + "dst": { "register": "AP", - "offset": 4 + "offset": 0 } } } ] ], [ - 5599, + 7544, [ { - "TestLessThan": { - "lhs": { - "Deref": { - "register": "AP", - "offset": -1 - } - }, - "rhs": { - "Immediate": "0x100000000000000000000000000000000" - }, + "AllocSegment": { "dst": { "register": "AP", "offset": 0 @@ -24597,33 +29461,29 @@ ] ], [ - 5601, + 7560, [ { - "DivMod": { + "TestLessThanOrEqual": { "lhs": { - "Deref": { - "register": "AP", - "offset": -2 - } + "Immediate": "0x0" }, "rhs": { - "Immediate": "0x100000000000000000000000000000000" - }, - "quotient": { - "register": "AP", - "offset": 3 + "Deref": { + "register": "FP", + "offset": -6 + } }, - "remainder": { + "dst": { "register": "AP", - "offset": 4 + "offset": 0 } } } ] ], [ - 5629, + 7579, [ { "AllocSegment": { @@ -24636,17 +29496,20 @@ ] ], [ - 5648, + 7612, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x2382" + "Deref": { + "register": "AP", + "offset": -1 + } }, "rhs": { "Deref": { "register": "AP", - "offset": -38 + "offset": -8 } }, "dst": { @@ -24658,7 +29521,7 @@ ] ], [ - 5660, + 7632, [ { "AllocSegment": { @@ -24671,22 +29534,55 @@ ] ], [ - 5683, + 7657, [ { - "SystemCall": { - "system": { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 7675, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 7694, + [ + { + "TestLessThanOrEqual": { + "lhs": { + "Immediate": "0x0" + }, + "rhs": { "Deref": { "register": "FP", - "offset": -5 + "offset": -6 } + }, + "dst": { + "register": "AP", + "offset": 0 } } } ] ], [ - 5686, + 7713, [ { "AllocSegment": { @@ -24699,10 +29595,19 @@ ] ], [ - 5706, + 7735, [ { - "AllocSegment": { + "TestLessThanOrEqual": { + "lhs": { + "Immediate": "0x1864" + }, + "rhs": { + "Deref": { + "register": "AP", + "offset": -2 + } + }, "dst": { "register": "AP", "offset": 0 @@ -24712,7 +29617,7 @@ ] ], [ - 5744, + 7761, [ { "AllocSegment": { @@ -24725,7 +29630,7 @@ ] ], [ - 5765, + 7795, [ { "AllocSegment": { @@ -24738,7 +29643,7 @@ ] ], [ - 5779, + 7811, [ { "AllocSegment": { @@ -24751,7 +29656,7 @@ ] ], [ - 5794, + 7830, [ { "TestLessThanOrEqual": { @@ -24773,49 +29678,78 @@ ] ], [ - 5811, + 7869, [ { - "AllocSegment": { + "TestLessThan": { + "lhs": { + "Deref": { + "register": "FP", + "offset": 1 + } + }, + "rhs": { + "Immediate": "0x800000000000000000000000000000000000000000000000000000000000000" + }, "dst": { "register": "AP", - "offset": 0 + "offset": 4 } } } ] ], [ - 5834, + 7873, [ { - "TestLessThanOrEqual": { - "lhs": { + "LinearSplit": { + "value": { "Deref": { "register": "AP", - "offset": -1 + "offset": 3 } }, - "rhs": { - "Deref": { - "register": "AP", - "offset": -9 - } + "scalar": { + "Immediate": "0x110000000000000000" }, - "dst": { + "max_x": { + "Immediate": "0xffffffffffffffffffffffffffffffff" + }, + "x": { "register": "AP", - "offset": 0 + "offset": -2 + }, + "y": { + "register": "AP", + "offset": -1 } } } ] ], [ - 5853, + 7883, [ { - "AllocSegment": { - "dst": { + "LinearSplit": { + "value": { + "Deref": { + "register": "FP", + "offset": 1 + } + }, + "scalar": { + "Immediate": "0x8000000000000000000000000000000" + }, + "max_x": { + "Immediate": "0xffffffffffffffffffffffffffffffff" + }, + "x": { + "register": "AP", + "offset": -1 + }, + "y": { "register": "AP", "offset": 0 } @@ -24824,7 +29758,7 @@ ] ], [ - 5873, + 7927, [ { "AllocSegment": { @@ -24837,7 +29771,7 @@ ] ], [ - 5889, + 7949, [ { "AllocSegment": { @@ -24850,17 +29784,17 @@ ] ], [ - 5905, + 7970, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x0" + "Immediate": "0x118dc" }, "rhs": { "Deref": { - "register": "FP", - "offset": -6 + "register": "AP", + "offset": -2 } }, "dst": { @@ -24872,7 +29806,7 @@ ] ], [ - 5931, + 7994, [ { "AllocSegment": { @@ -24885,22 +29819,10 @@ ] ], [ - 5956, + 8013, [ { - "TestLessThanOrEqual": { - "lhs": { - "Deref": { - "register": "AP", - "offset": -1 - } - }, - "rhs": { - "Deref": { - "register": "AP", - "offset": -14 - } - }, + "AllocSegment": { "dst": { "register": "AP", "offset": 0 @@ -24910,7 +29832,7 @@ ] ], [ - 5976, + 8045, [ { "AllocSegment": { @@ -24923,7 +29845,7 @@ ] ], [ - 5996, + 8059, [ { "AllocSegment": { @@ -24936,7 +29858,7 @@ ] ], [ - 6012, + 8083, [ { "AllocSegment": { @@ -24949,7 +29871,7 @@ ] ], [ - 6027, + 8097, [ { "AllocSegment": { @@ -24962,7 +29884,7 @@ ] ], [ - 6043, + 8113, [ { "TestLessThanOrEqual": { @@ -24984,7 +29906,42 @@ ] ], [ - 6069, + 8142, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 8163, + [ + { + "TestLessThanOrEqual": { + "lhs": { + "Immediate": "0x0" + }, + "rhs": { + "Deref": { + "register": "AP", + "offset": -2 + } + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 8175, [ { "AllocSegment": { @@ -24997,19 +29954,10 @@ ] ], [ - 6088, + 8189, [ { - "TestLessThanOrEqual": { - "lhs": { - "Immediate": "0x10f4" - }, - "rhs": { - "Deref": { - "register": "AP", - "offset": -11 - } - }, + "AllocSegment": { "dst": { "register": "AP", "offset": 0 @@ -25019,7 +29967,7 @@ ] ], [ - 6100, + 8204, [ { "AllocSegment": { @@ -25032,22 +29980,42 @@ ] ], [ - 6120, + 8219, [ { - "SystemCall": { - "system": { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 8235, + [ + { + "TestLessThanOrEqual": { + "lhs": { + "Immediate": "0x0" + }, + "rhs": { "Deref": { "register": "FP", - "offset": -5 + "offset": -6 } + }, + "dst": { + "register": "AP", + "offset": 0 } } } ] ], [ - 6123, + 8254, [ { "AllocSegment": { @@ -25060,7 +30028,29 @@ ] ], [ - 6143, + 8275, + [ + { + "TestLessThanOrEqual": { + "lhs": { + "Immediate": "0x0" + }, + "rhs": { + "Deref": { + "register": "AP", + "offset": -2 + } + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 8287, [ { "AllocSegment": { @@ -25073,7 +30063,7 @@ ] ], [ - 6158, + 8299, [ { "AllocSegment": { @@ -25086,7 +30076,7 @@ ] ], [ - 6172, + 8314, [ { "AllocSegment": { @@ -25099,7 +30089,7 @@ ] ], [ - 6187, + 8330, [ { "TestLessThanOrEqual": { @@ -25121,7 +30111,7 @@ ] ], [ - 6204, + 8349, [ { "AllocSegment": { @@ -25134,7 +30124,7 @@ ] ], [ - 6235, + 8374, [ { "TestLessThanOrEqual": { @@ -25147,7 +30137,7 @@ "rhs": { "Deref": { "register": "AP", - "offset": -13 + "offset": -4 } }, "dst": { @@ -25159,7 +30149,7 @@ ] ], [ - 6255, + 8390, [ { "AllocSegment": { @@ -25172,7 +30162,7 @@ ] ], [ - 6279, + 8403, [ { "AllocSegment": { @@ -25185,7 +30175,7 @@ ] ], [ - 6297, + 8419, [ { "AllocSegment": { @@ -25198,7 +30188,7 @@ ] ], [ - 6315, + 8436, [ { "TestLessThanOrEqual": { @@ -25220,7 +30210,7 @@ ] ], [ - 6332, + 8455, [ { "AllocSegment": { @@ -25233,17 +30223,20 @@ ] ], [ - 6352, + 8480, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x0" + "Deref": { + "register": "AP", + "offset": -1 + } }, "rhs": { "Deref": { "register": "AP", - "offset": -7 + "offset": -4 } }, "dst": { @@ -25255,7 +30248,7 @@ ] ], [ - 6376, + 8496, [ { "AllocSegment": { @@ -25268,7 +30261,7 @@ ] ], [ - 6406, + 8509, [ { "AllocSegment": { @@ -25281,7 +30274,7 @@ ] ], [ - 6422, + 8525, [ { "AllocSegment": { @@ -25294,7 +30287,7 @@ ] ], [ - 6440, + 8542, [ { "TestLessThanOrEqual": { @@ -25316,78 +30309,49 @@ ] ], [ - 6474, + 8561, [ { - "TestLessThan": { - "lhs": { - "Deref": { - "register": "FP", - "offset": 0 - } - }, - "rhs": { - "Immediate": "0x800000000000000000000000000000000000000000000000000000000000000" - }, + "AllocSegment": { "dst": { "register": "AP", - "offset": 4 + "offset": 0 } } } ] ], [ - 6478, + 8586, [ { - "LinearSplit": { - "value": { + "TestLessThanOrEqual": { + "lhs": { "Deref": { "register": "AP", - "offset": 3 + "offset": -1 } }, - "scalar": { - "Immediate": "0x110000000000000000" - }, - "max_x": { - "Immediate": "0xffffffffffffffffffffffffffffffff" - }, - "x": { - "register": "AP", - "offset": -2 + "rhs": { + "Deref": { + "register": "AP", + "offset": -4 + } }, - "y": { + "dst": { "register": "AP", - "offset": -1 + "offset": 0 } } } ] ], [ - 6488, + 8609, [ { - "LinearSplit": { - "value": { - "Deref": { - "register": "FP", - "offset": 0 - } - }, - "scalar": { - "Immediate": "0x8000000000000000000000000000000" - }, - "max_x": { - "Immediate": "0xffffffffffffffffffffffffffffffff" - }, - "x": { - "register": "AP", - "offset": -1 - }, - "y": { + "AllocSegment": { + "dst": { "register": "AP", "offset": 0 } @@ -25396,7 +30360,7 @@ ] ], [ - 6528, + 8622, [ { "AllocSegment": { @@ -25409,7 +30373,7 @@ ] ], [ - 6548, + 8638, [ { "AllocSegment": { @@ -25422,17 +30386,17 @@ ] ], [ - 6567, + 8655, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0xb4f0" + "Immediate": "0x0" }, "rhs": { "Deref": { - "register": "AP", - "offset": -12 + "register": "FP", + "offset": -6 } }, "dst": { @@ -25444,7 +30408,7 @@ ] ], [ - 6591, + 8674, [ { "AllocSegment": { @@ -25457,10 +30421,22 @@ ] ], [ - 6609, + 8699, [ { - "AllocSegment": { + "TestLessThanOrEqual": { + "lhs": { + "Deref": { + "register": "AP", + "offset": -1 + } + }, + "rhs": { + "Deref": { + "register": "AP", + "offset": -4 + } + }, "dst": { "register": "AP", "offset": 0 @@ -25470,7 +30446,35 @@ ] ], [ - 6638, + 8725, + [ + { + "RandomEcPoint": { + "x": { + "register": "AP", + "offset": 4 + }, + "y": { + "register": "AP", + "offset": 5 + } + } + }, + { + "AllocConstantSize": { + "size": { + "Immediate": "0x2" + }, + "dst": { + "register": "AP", + "offset": 6 + } + } + } + ] + ], + [ + 8742, [ { "AllocSegment": { @@ -25483,7 +30487,7 @@ ] ], [ - 6652, + 8762, [ { "AllocSegment": { @@ -25496,7 +30500,7 @@ ] ], [ - 6673, + 8777, [ { "AllocSegment": { @@ -25509,7 +30513,7 @@ ] ], [ - 6687, + 8793, [ { "AllocSegment": { @@ -25522,7 +30526,7 @@ ] ], [ - 6702, + 8810, [ { "TestLessThanOrEqual": { @@ -25544,7 +30548,7 @@ ] ], [ - 6736, + 8848, [ { "AllocSegment": { @@ -25557,7 +30561,7 @@ ] ], [ - 6755, + 8869, [ { "TestLessThanOrEqual": { @@ -25567,7 +30571,7 @@ "rhs": { "Deref": { "register": "AP", - "offset": -14 + "offset": -2 } }, "dst": { @@ -25579,7 +30583,7 @@ ] ], [ - 6767, + 8881, [ { "AllocSegment": { @@ -25592,7 +30596,7 @@ ] ], [ - 6780, + 8895, [ { "AllocSegment": { @@ -25605,7 +30609,7 @@ ] ], [ - 6795, + 8910, [ { "AllocSegment": { @@ -25618,7 +30622,7 @@ ] ], [ - 6809, + 8925, [ { "AllocSegment": { @@ -25631,7 +30635,7 @@ ] ], [ - 6823, + 8940, [ { "AllocSegment": { @@ -25644,7 +30648,7 @@ ] ], [ - 6838, + 8956, [ { "TestLessThanOrEqual": { @@ -25666,14 +30670,14 @@ ] ], [ - 6879, + 9003, [ { "TestLessThan": { "lhs": { "Deref": { "register": "AP", - "offset": -1 + "offset": -2 } }, "rhs": { @@ -25688,7 +30692,7 @@ ] ], [ - 6883, + 9007, [ { "LinearSplit": { @@ -25717,14 +30721,14 @@ ] ], [ - 6893, + 9017, [ { "LinearSplit": { "value": { "Deref": { "register": "AP", - "offset": -2 + "offset": -3 } }, "scalar": { @@ -25746,7 +30750,7 @@ ] ], [ - 6917, + 9043, [ { "AllocSegment": { @@ -25759,17 +30763,17 @@ ] ], [ - 6936, + 9064, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x17a2" + "Immediate": "0x2a94" }, "rhs": { "Deref": { "register": "AP", - "offset": -25 + "offset": -2 } }, "dst": { @@ -25781,7 +30785,7 @@ ] ], [ - 6959, + 9088, [ { "SystemCall": { @@ -25796,7 +30800,7 @@ ] ], [ - 6962, + 9092, [ { "AllocSegment": { @@ -25809,7 +30813,7 @@ ] ], [ - 6984, + 9116, [ { "AllocSegment": { @@ -25822,7 +30826,7 @@ ] ], [ - 6999, + 9131, [ { "AllocSegment": { @@ -25835,7 +30839,7 @@ ] ], [ - 7020, + 9155, [ { "AllocSegment": { @@ -25848,7 +30852,7 @@ ] ], [ - 7034, + 9169, [ { "AllocSegment": { @@ -25861,7 +30865,7 @@ ] ], [ - 7048, + 9184, [ { "AllocSegment": { @@ -25874,7 +30878,7 @@ ] ], [ - 7063, + 9200, [ { "TestLessThanOrEqual": { @@ -25896,7 +30900,7 @@ ] ], [ - 7098, + 9239, [ { "AllocSegment": { @@ -25909,17 +30913,17 @@ ] ], [ - 7117, + 9260, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x11bc" + "Immediate": "0x2b5c" }, "rhs": { "Deref": { "register": "AP", - "offset": -15 + "offset": -2 } }, "dst": { @@ -25931,7 +30935,7 @@ ] ], [ - 7143, + 9287, [ { "SystemCall": { @@ -25946,7 +30950,7 @@ ] ], [ - 7146, + 9291, [ { "AllocSegment": { @@ -25959,7 +30963,7 @@ ] ], [ - 7168, + 9315, [ { "AllocSegment": { @@ -25972,7 +30976,7 @@ ] ], [ - 7183, + 9330, [ { "AllocSegment": { @@ -25985,7 +30989,7 @@ ] ], [ - 7197, + 9345, [ { "AllocSegment": { @@ -25998,7 +31002,7 @@ ] ], [ - 7211, + 9360, [ { "AllocSegment": { @@ -26011,12 +31015,12 @@ ] ], [ - 7226, + 9376, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x942" + "Immediate": "0xa6e" }, "rhs": { "Deref": { @@ -26033,7 +31037,90 @@ ] ], [ - 7298, + 9454, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 9474, + [ + { + "TestLessThanOrEqual": { + "lhs": { + "Immediate": "0x6ea" + }, + "rhs": { + "Deref": { + "register": "FP", + "offset": -7 + } + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 9513, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 9527, + [ + { + "TestLessThanOrEqual": { + "lhs": { + "Immediate": "0x6ea" + }, + "rhs": { + "Deref": { + "register": "FP", + "offset": -7 + } + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 9566, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 9580, [ { "AllocSegment": { @@ -26046,64 +31133,85 @@ ] ], [ - 7318, + 9596, [ { - "TestLessThanOrEqual": { - "lhs": { - "Immediate": "0x686" - }, - "rhs": { + "SystemCall": { + "system": { "Deref": { "register": "FP", - "offset": -7 + "offset": -5 } - }, - "dst": { - "register": "AP", - "offset": 0 } } } ] ], [ - 7355, + 9606, [ { - "AllocSegment": { - "dst": { - "register": "AP", - "offset": 0 + "SystemCall": { + "system": { + "BinOp": { + "op": "Add", + "a": { + "register": "FP", + "offset": -5 + }, + "b": { + "Immediate": "0x8" + } + } } } } ] ], [ - 7369, + 9620, [ { - "TestLessThanOrEqual": { - "lhs": { - "Immediate": "0x686" - }, - "rhs": { - "Deref": { - "register": "FP", - "offset": -7 + "SystemCall": { + "system": { + "BinOp": { + "op": "Add", + "a": { + "register": "FP", + "offset": -5 + }, + "b": { + "Immediate": "0xd" + } } - }, - "dst": { - "register": "AP", - "offset": 0 } } } ] ], [ - 7406, + 9638, + [ + { + "SystemCall": { + "system": { + "BinOp": { + "op": "Add", + "a": { + "register": "FP", + "offset": -5 + }, + "b": { + "Immediate": "0x14" + } + } + } + } + } + ] + ], + [ + 9659, [ { "AllocSegment": { @@ -26116,7 +31224,7 @@ ] ], [ - 7420, + 9720, [ { "AllocSegment": { @@ -26129,14 +31237,14 @@ ] ], [ - 7436, + 9732, [ { "SystemCall": { "system": { "Deref": { "register": "FP", - "offset": -4 + "offset": -5 } } } @@ -26144,28 +31252,20 @@ ] ], [ - 7445, + 9736, [ { - "SystemCall": { - "system": { - "BinOp": { - "op": "Add", - "a": { - "register": "FP", - "offset": -4 - }, - "b": { - "Immediate": "0x8" - } - } + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 } } } ] ], [ - 7458, + 9756, [ { "SystemCall": { @@ -26174,10 +31274,10 @@ "op": "Add", "a": { "register": "FP", - "offset": -4 + "offset": -5 }, "b": { - "Immediate": "0xd" + "Immediate": "0xa" } } } @@ -26186,7 +31286,20 @@ ] ], [ - 7475, + 9762, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 9789, [ { "SystemCall": { @@ -26195,7 +31308,7 @@ "op": "Add", "a": { "register": "FP", - "offset": -4 + "offset": -5 }, "b": { "Immediate": "0x14" @@ -26207,7 +31320,7 @@ ] ], [ - 7478, + 9813, [ { "AllocSegment": { @@ -26220,12 +31333,12 @@ ] ], [ - 7537, + 9850, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x3480" + "Immediate": "0x35ac" }, "rhs": { "Deref": { @@ -26242,7 +31355,7 @@ ] ], [ - 7562, + 9877, [ { "SystemCall": { @@ -26257,7 +31370,7 @@ ] ], [ - 7570, + 9886, [ { "TestLessThan": { @@ -26288,7 +31401,7 @@ ] ], [ - 7595, + 9911, [ { "AllocSegment": { @@ -26301,7 +31414,7 @@ ] ], [ - 7628, + 9948, [ { "AllocSegment": { @@ -26314,7 +31427,7 @@ ] ], [ - 7665, + 9985, [ { "TestLessThan": { @@ -26342,7 +31455,7 @@ ] ], [ - 7669, + 9989, [ { "LinearSplit": { @@ -26371,7 +31484,7 @@ ] ], [ - 7711, + 10031, [ { "TestLessThan": { @@ -26399,7 +31512,7 @@ ] ], [ - 7715, + 10035, [ { "LinearSplit": { @@ -26428,7 +31541,7 @@ ] ], [ - 7756, + 10076, [ { "TestLessThan": { @@ -26450,7 +31563,7 @@ ] ], [ - 7760, + 10080, [ { "LinearSplit": { @@ -26479,7 +31592,7 @@ ] ], [ - 7770, + 10090, [ { "LinearSplit": { @@ -26508,7 +31621,7 @@ ] ], [ - 7881, + 10205, [ { "TestLessThan": { @@ -26530,7 +31643,7 @@ ] ], [ - 7885, + 10209, [ { "LinearSplit": { @@ -26559,7 +31672,7 @@ ] ], [ - 7895, + 10219, [ { "LinearSplit": { @@ -26588,7 +31701,7 @@ ] ], [ - 7927, + 10255, [ { "TestLessThan": { @@ -26610,7 +31723,7 @@ ] ], [ - 7929, + 10257, [ { "DivMod": { @@ -26636,7 +31749,7 @@ ] ], [ - 8010, + 10346, [ { "AllocSegment": { @@ -26649,14 +31762,14 @@ ] ], [ - 8065, + 10409, [ { "TestLessThan": { "lhs": { "Deref": { "register": "AP", - "offset": -1 + "offset": -2 } }, "rhs": { @@ -26671,14 +31784,14 @@ ] ], [ - 8067, + 10411, [ { "DivMod": { "lhs": { "Deref": { "register": "AP", - "offset": -2 + "offset": -3 } }, "rhs": { @@ -26697,7 +31810,7 @@ ] ], [ - 8120, + 10470, [ { "TestLessThan": { @@ -26706,7 +31819,7 @@ "op": "Add", "a": { "register": "AP", - "offset": -1 + "offset": -2 }, "b": { "Immediate": "0x0" @@ -26725,7 +31838,7 @@ ] ], [ - 8124, + 10474, [ { "LinearSplit": { @@ -26754,7 +31867,7 @@ ] ], [ - 8166, + 10520, [ { "TestLessThan": { @@ -26763,7 +31876,7 @@ "op": "Add", "a": { "register": "AP", - "offset": -1 + "offset": -2 }, "b": { "Immediate": "0x0" @@ -26782,7 +31895,7 @@ ] ], [ - 8170, + 10524, [ { "LinearSplit": { @@ -26811,7 +31924,7 @@ ] ], [ - 9001, + 11384, [ { "SystemCall": { @@ -26826,7 +31939,7 @@ ] ], [ - 9234, + 11654, [ { "AllocSegment": { @@ -26839,7 +31952,7 @@ ] ], [ - 9248, + 11668, [ { "AllocSegment": { @@ -26852,7 +31965,7 @@ ] ], [ - 9262, + 11683, [ { "AllocSegment": { @@ -26865,7 +31978,7 @@ ] ], [ - 9326, + 11755, [ { "AllocSegment": { @@ -26878,7 +31991,7 @@ ] ], [ - 9340, + 11771, [ { "AllocSegment": { @@ -26891,7 +32004,7 @@ ] ], [ - 9363, + 11796, [ { "AllocSegment": { @@ -26904,7 +32017,7 @@ ] ], [ - 9387, + 11820, [ { "SystemCall": { @@ -26919,7 +32032,7 @@ ] ], [ - 9390, + 11824, [ { "AllocSegment": { @@ -26932,7 +32045,7 @@ ] ], [ - 9406, + 11840, [ { "SystemCall": { @@ -26953,7 +32066,7 @@ ] ], [ - 9443, + 11881, [ { "GetSegmentArenaIndex": { @@ -26972,7 +32085,7 @@ ] ], [ - 9484, + 11922, [ { "AllocSegment": { @@ -26985,7 +32098,7 @@ ] ], [ - 9492, + 11930, [ { "InitSquashData": { @@ -27020,7 +32133,7 @@ ] ], [ - 9511, + 11949, [ { "GetCurrentAccessIndex": { @@ -27035,7 +32148,7 @@ ] ], [ - 9524, + 11962, [ { "ShouldSkipSquashLoop": { @@ -27048,7 +32161,7 @@ ] ], [ - 9526, + 11964, [ { "GetCurrentAccessDelta": { @@ -27061,7 +32174,7 @@ ] ], [ - 9537, + 11975, [ { "ShouldContinueSquashLoop": { @@ -27074,7 +32187,7 @@ ] ], [ - 9551, + 11989, [ { "GetNextDictKey": { @@ -27087,7 +32200,7 @@ ] ], [ - 9570, + 12008, [ { "AssertLeFindSmallArcs": { @@ -27120,7 +32233,7 @@ ] ], [ - 9582, + 12020, [ { "AssertLeIsFirstArcExcluded": { @@ -27133,7 +32246,7 @@ ] ], [ - 9594, + 12032, [ { "AssertLeIsSecondArcExcluded": { @@ -27146,10 +32259,19 @@ ] ], [ - 9625, + 12065, [ { - "AllocSegment": { + "TestLessThanOrEqual": { + "lhs": { + "Immediate": "0x23e6" + }, + "rhs": { + "Deref": { + "register": "FP", + "offset": -4 + } + }, "dst": { "register": "AP", "offset": 0 @@ -27159,52 +32281,97 @@ ] ], [ - 9633, + 12079, [ { - "AllocSegment": { + "TestLessThan": { + "lhs": { + "Deref": { + "register": "AP", + "offset": 0 + } + }, + "rhs": { + "Immediate": "0x100000000000000000000000000000000" + }, "dst": { "register": "AP", - "offset": 0 + "offset": -1 } } } ] ], [ - 9664, + 12100, [ { - "SystemCall": { - "system": { + "TestLessThan": { + "lhs": { "Deref": { - "register": "FP", - "offset": -3 + "register": "AP", + "offset": 0 } + }, + "rhs": { + "Immediate": "0x100000000000000000000000000000000" + }, + "dst": { + "register": "AP", + "offset": -1 } } } ] ], [ - 9678, + 12118, [ { - "AllocSegment": { - "dst": { + "WideMul128": { + "lhs": { + "Deref": { + "register": "AP", + "offset": -1 + } + }, + "rhs": { + "Deref": { + "register": "AP", + "offset": -2 + } + }, + "high": { "register": "AP", "offset": 0 + }, + "low": { + "register": "AP", + "offset": 1 } } } ] ], [ - 9698, + 12120, [ { - "AllocSegment": { - "dst": { + "DivMod": { + "lhs": { + "Deref": { + "register": "AP", + "offset": -3 + } + }, + "rhs": { + "Immediate": "0x10000000000000000" + }, + "quotient": { + "register": "AP", + "offset": 1 + }, + "remainder": { "register": "AP", "offset": 0 } @@ -27213,35 +32380,81 @@ ] ], [ - 9712, + 12130, [ { - "AllocSegment": { - "dst": { + "DivMod": { + "lhs": { + "Deref": { + "register": "AP", + "offset": -1 + } + }, + "rhs": { + "Immediate": "0x10000000000000000" + }, + "quotient": { "register": "AP", "offset": 0 + }, + "remainder": { + "register": "AP", + "offset": 1 } } } ] ], [ - 9726, + 12141, [ { - "SystemCall": { - "system": { + "DivMod": { + "lhs": { "Deref": { "register": "AP", - "offset": -9 + "offset": 2 + } + }, + "rhs": { + "Immediate": "0x100000000000000000000000000000000" + }, + "quotient": { + "register": "AP", + "offset": -1 + }, + "remainder": { + "register": "AP", + "offset": -13 + } + } + } + ] + ], + [ + 12157, + [ + { + "TestLessThan": { + "lhs": { + "Deref": { + "register": "AP", + "offset": 0 } + }, + "rhs": { + "Immediate": "0x100000000000000000000000000000000" + }, + "dst": { + "register": "AP", + "offset": -1 } } } ] ], [ - 9729, + 12175, [ { "AllocSegment": { @@ -27254,22 +32467,10 @@ ] ], [ - 9752, + 12189, [ { - "TestLessThan": { - "lhs": { - "Deref": { - "register": "AP", - "offset": -4 - } - }, - "rhs": { - "Deref": { - "register": "AP", - "offset": -1 - } - }, + "AllocSegment": { "dst": { "register": "AP", "offset": 0 @@ -27279,7 +32480,7 @@ ] ], [ - 9780, + 12211, [ { "AllocSegment": { @@ -27292,7 +32493,7 @@ ] ], [ - 9794, + 12234, [ { "AllocSegment": { @@ -27305,7 +32506,7 @@ ] ], [ - 9837, + 12249, [ { "AllocSegment": { @@ -27318,7 +32519,7 @@ ] ], [ - 9876, + 12263, [ { "AllocSegment": { @@ -27331,7 +32532,20 @@ ] ], [ - 9936, + 12271, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 12303, [ { "SystemCall": { @@ -27346,7 +32560,33 @@ ] ], [ - 9946, + 12318, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 12340, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 12355, [ { "AllocSegment": { @@ -27359,14 +32599,14 @@ ] ], [ - 9977, + 12370, [ { "SystemCall": { "system": { "Deref": { "register": "AP", - "offset": -6 + "offset": -12 } } } @@ -27374,7 +32614,7 @@ ] ], [ - 9980, + 12374, [ { "AllocSegment": { @@ -27387,22 +32627,105 @@ ] ], [ - 10004, + 12418, [ { - "TestLessThan": { - "lhs": { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 12432, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 12479, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 12519, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 12582, + [ + { + "SystemCall": { + "system": { "Deref": { - "register": "AP", - "offset": -4 + "register": "FP", + "offset": -3 } - }, - "rhs": { + } + } + } + ] + ], + [ + 12603, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 12635, + [ + { + "SystemCall": { + "system": { "Deref": { "register": "AP", - "offset": -1 + "offset": -8 } - }, + } + } + } + ] + ], + [ + 12649, + [ + { + "AllocSegment": { "dst": { "register": "AP", "offset": 0 @@ -27412,14 +32735,14 @@ ] ], [ - 10038, + 12699, [ { "SystemCall": { "system": { "Deref": { "register": "AP", - "offset": -14 + "offset": -12 } } } @@ -27427,14 +32750,14 @@ ] ], [ - 10053, + 12716, [ { "SystemCall": { "system": { "Deref": { "register": "AP", - "offset": -2 + "offset": -4 } } } @@ -27442,7 +32765,7 @@ ] ], [ - 10099, + 12810, [ { "AllocSegment": { @@ -27455,7 +32778,7 @@ ] ], [ - 10155, + 12868, [ { "AllocSegment": { @@ -27468,7 +32791,7 @@ ] ], [ - 10186, + 12923, [ { "AllocSegment": { @@ -27481,7 +32804,7 @@ ] ], [ - 10211, + 12969, [ { "AllocSegment": { @@ -27494,7 +32817,7 @@ ] ], [ - 10226, + 12994, [ { "AllocSegment": { @@ -27507,7 +32830,7 @@ ] ], [ - 10268, + 13046, [ { "SystemCall": { @@ -27522,7 +32845,7 @@ ] ], [ - 10280, + 13059, [ { "AllocSegment": { @@ -27535,14 +32858,14 @@ ] ], [ - 10310, + 13091, [ { "SystemCall": { "system": { "Deref": { "register": "AP", - "offset": -6 + "offset": -8 } } } @@ -27550,7 +32873,7 @@ ] ], [ - 10315, + 13097, [ { "AllocSegment": { @@ -27563,39 +32886,14 @@ ] ], [ - 10338, - [ - { - "TestLessThan": { - "lhs": { - "Deref": { - "register": "AP", - "offset": -4 - } - }, - "rhs": { - "Deref": { - "register": "AP", - "offset": -1 - } - }, - "dst": { - "register": "AP", - "offset": 0 - } - } - } - ] - ], - [ - 10372, + 13147, [ { "SystemCall": { "system": { "Deref": { "register": "AP", - "offset": -14 + "offset": -12 } } } @@ -27603,14 +32901,14 @@ ] ], [ - 10387, + 13164, [ { "SystemCall": { "system": { "Deref": { "register": "AP", - "offset": -2 + "offset": -4 } } } @@ -27618,7 +32916,7 @@ ] ], [ - 10435, + 13224, [ { "AllocSegment": { @@ -27631,14 +32929,14 @@ ] ], [ - 10465, + 13255, [ { "SystemCall": { "system": { "Deref": { "register": "AP", - "offset": -12 + "offset": -17 } } } @@ -27646,7 +32944,7 @@ ] ], [ - 10515, + 13306, [ { "AllocSegment": { @@ -27659,7 +32957,7 @@ ] ], [ - 10553, + 13349, [ { "AllocSegment": { @@ -27672,7 +32970,7 @@ ] ], [ - 10580, + 13379, [ { "AllocSegment": { @@ -27685,7 +32983,7 @@ ] ], [ - 10596, + 13396, [ { "AllocSegment": { @@ -27698,12 +32996,12 @@ ] ], [ - 10622, + 13424, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x3700" + "Immediate": "0x3a84" }, "rhs": { "Deref": { @@ -27720,7 +33018,7 @@ ] ], [ - 10636, + 13439, [ { "TestLessThan": { @@ -27742,14 +33040,14 @@ ] ], [ - 10675, + 13484, [ { "TestLessThan": { "lhs": { "Deref": { "register": "AP", - "offset": -9 + "offset": -12 } }, "rhs": { @@ -27764,7 +33062,7 @@ ] ], [ - 10679, + 13488, [ { "LinearSplit": { @@ -27793,14 +33091,14 @@ ] ], [ - 10689, + 13498, [ { "LinearSplit": { "value": { "Deref": { "register": "AP", - "offset": -10 + "offset": -13 } }, "scalar": { @@ -27822,7 +33120,7 @@ ] ], [ - 10707, + 13517, [ { "SystemCall": { @@ -27837,7 +33135,7 @@ ] ], [ - 10725, + 13538, [ { "AllocSegment": { @@ -27850,14 +33148,14 @@ ] ], [ - 10744, + 13560, [ { "TestLessThan": { "lhs": { "Deref": { "register": "AP", - "offset": -10 + "offset": -14 } }, "rhs": { @@ -27872,7 +33170,7 @@ ] ], [ - 10748, + 13564, [ { "LinearSplit": { @@ -27901,14 +33199,14 @@ ] ], [ - 10758, + 13574, [ { "LinearSplit": { "value": { "Deref": { "register": "AP", - "offset": -11 + "offset": -15 } }, "scalar": { @@ -27930,7 +33228,7 @@ ] ], [ - 10776, + 13593, [ { "SystemCall": { @@ -27945,7 +33243,7 @@ ] ], [ - 10794, + 13614, [ { "AllocSegment": { @@ -27958,7 +33256,7 @@ ] ], [ - 10825, + 13650, [ { "AllocSegment": { @@ -27971,7 +33269,7 @@ ] ], [ - 10849, + 13675, [ { "AllocSegment": { @@ -27984,7 +33282,7 @@ ] ], [ - 10863, + 13690, [ { "AllocSegment": { @@ -27997,7 +33295,7 @@ ] ], [ - 10877, + 13705, [ { "AllocSegment": { @@ -28010,7 +33308,7 @@ ] ], [ - 10891, + 13720, [ { "AllocSegment": { @@ -28023,7 +33321,7 @@ ] ], [ - 10906, + 13736, [ { "AllocSegment": { @@ -28036,12 +33334,12 @@ ] ], [ - 10921, + 13751, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x42e" + "Immediate": "0x492" }, "rhs": { "Deref": { @@ -28058,7 +33356,7 @@ ] ], [ - 10935, + 13766, [ { "AllocSegment": { @@ -28071,7 +33369,7 @@ ] ], [ - 10955, + 13787, [ { "AllocSegment": { @@ -28084,12 +33382,12 @@ ] ], [ - 10969, + 13801, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x42e" + "Immediate": "0x492" }, "rhs": { "Deref": { @@ -28106,7 +33404,7 @@ ] ], [ - 10999, + 13833, [ { "AllocSegment": { @@ -28119,7 +33417,7 @@ ] ], [ - 11018, + 13852, [ { "TestLessThan": { @@ -28141,7 +33439,7 @@ ] ], [ - 11022, + 13856, [ { "LinearSplit": { @@ -28170,7 +33468,7 @@ ] ], [ - 11033, + 13867, [ { "LinearSplit": { @@ -28199,7 +33497,7 @@ ] ], [ - 11059, + 13893, [ { "SystemCall": { @@ -28214,7 +33512,7 @@ ] ], [ - 11074, + 13909, [ { "SystemCall": { @@ -28235,7 +33533,7 @@ ] ], [ - 11082, + 13918, [ { "TestLessThan": { @@ -28257,7 +33555,7 @@ ] ], [ - 11086, + 13922, [ { "LinearSplit": { @@ -28286,7 +33584,7 @@ ] ], [ - 11097, + 13933, [ { "LinearSplit": { @@ -28315,7 +33613,7 @@ ] ], [ - 11127, + 13963, [ { "SystemCall": { @@ -28336,7 +33634,7 @@ ] ], [ - 11143, + 13980, [ { "SystemCall": { @@ -28357,7 +33655,7 @@ ] ], [ - 11213, + 14073, [ { "TestLessThan": { @@ -28379,7 +33677,7 @@ ] ], [ - 11217, + 14077, [ { "LinearSplit": { @@ -28408,7 +33706,7 @@ ] ], [ - 11228, + 14088, [ { "LinearSplit": { @@ -28437,7 +33735,7 @@ ] ], [ - 11254, + 14114, [ { "SystemCall": { @@ -28452,7 +33750,7 @@ ] ], [ - 11269, + 14130, [ { "SystemCall": { @@ -28473,14 +33771,14 @@ ] ], [ - 11276, + 14138, [ { "TestLessThan": { "lhs": { "Deref": { "register": "AP", - "offset": -6 + "offset": -7 } }, "rhs": { @@ -28495,14 +33793,14 @@ ] ], [ - 11278, + 14140, [ { "DivMod": { "lhs": { "Deref": { "register": "AP", - "offset": -7 + "offset": -8 } }, "rhs": { @@ -28521,14 +33819,14 @@ ] ], [ - 11299, + 14162, [ { "TestLessThan": { "lhs": { "Deref": { "register": "AP", - "offset": -2 + "offset": -4 } }, "rhs": { @@ -28543,14 +33841,14 @@ ] ], [ - 11301, + 14164, [ { "DivMod": { "lhs": { "Deref": { "register": "AP", - "offset": -3 + "offset": -5 } }, "rhs": { @@ -28569,7 +33867,7 @@ ] ], [ - 11331, + 14194, [ { "TestLessThan": { @@ -28591,7 +33889,7 @@ ] ], [ - 11335, + 14198, [ { "LinearSplit": { @@ -28620,7 +33918,7 @@ ] ], [ - 11346, + 14209, [ { "LinearSplit": { @@ -28649,14 +33947,14 @@ ] ], [ - 11377, + 14241, [ { "SystemCall": { "system": { "Deref": { "register": "AP", - "offset": -20 + "offset": -23 } } } @@ -28664,7 +33962,7 @@ ] ], [ - 11392, + 14257, [ { "SystemCall": { @@ -28673,7 +33971,7 @@ "op": "Add", "a": { "register": "AP", - "offset": -25 + "offset": -29 }, "b": { "Immediate": "0x7" @@ -28685,7 +33983,7 @@ ] ], [ - 11436, + 14318, [ { "AllocSegment": { @@ -28698,7 +33996,7 @@ ] ], [ - 11455, + 14349, [ { "AllocSegment": { @@ -28711,7 +34009,7 @@ ] ], [ - 11537, + 14468, [ { "RandomEcPoint": { @@ -28739,7 +34037,7 @@ ] ], [ - 11601, + 14541, [ { "RandomEcPoint": { @@ -28767,7 +34065,7 @@ ] ], [ - 11671, + 14615, [ { "AllocSegment": { @@ -28780,7 +34078,7 @@ ] ], [ - 11697, + 14642, [ { "SystemCall": { @@ -28795,7 +34093,7 @@ ] ], [ - 11714, + 14660, [ { "SystemCall": { @@ -28816,7 +34114,7 @@ ] ], [ - 11756, + 14713, [ { "AllocSegment": { @@ -28829,7 +34127,7 @@ ] ], [ - 11773, + 14737, [ { "AllocSegment": { @@ -28842,7 +34140,7 @@ ] ], [ - 11792, + 14755, [ { "SystemCall": { @@ -28857,7 +34155,7 @@ ] ], [ - 11802, + 14766, [ { "TestLessThan": { @@ -28879,7 +34177,7 @@ ] ], [ - 11806, + 14770, [ { "LinearSplit": { @@ -28908,7 +34206,7 @@ ] ], [ - 11817, + 14781, [ { "LinearSplit": { @@ -28937,7 +34235,7 @@ ] ], [ - 11861, + 14825, [ { "SystemCall": { @@ -28958,7 +34256,7 @@ ] ], [ - 11876, + 14841, [ { "SystemCall": { @@ -28979,39 +34277,14 @@ ] ], [ - 11886, + 14859, [ { "TestLessThan": { "lhs": { "Deref": { "register": "AP", - "offset": -5 - } - }, - "rhs": { - "Deref": { - "register": "AP", - "offset": -1 - } - }, - "dst": { - "register": "AP", - "offset": 0 - } - } - } - ] - ], - [ - 11901, - [ - { - "TestLessThan": { - "lhs": { - "Deref": { - "register": "AP", - "offset": -3 + "offset": -4 } }, "rhs": { @@ -29029,7 +34302,7 @@ ] ], [ - 11917, + 14875, [ { "TestLessThan": { @@ -29051,7 +34324,7 @@ ] ], [ - 11921, + 14879, [ { "LinearSplit": { @@ -29080,7 +34353,7 @@ ] ], [ - 11932, + 14890, [ { "LinearSplit": { @@ -29109,14 +34382,14 @@ ] ], [ - 11961, + 14920, [ { "SystemCall": { "system": { "Deref": { "register": "AP", - "offset": -29 + "offset": -28 } } } @@ -29124,7 +34397,7 @@ ] ], [ - 11977, + 14937, [ { "SystemCall": { @@ -29145,7 +34418,92 @@ ] ], [ - 12019, + 14992, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 15018, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 15163, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 15231, + [ + { + "EvalCircuit": { + "n_add_mods": { + "Deref": { + "register": "AP", + "offset": -7 + } + }, + "add_mod_builtin": { + "Deref": { + "register": "FP", + "offset": -6 + } + }, + "n_mul_mods": { + "Deref": { + "register": "AP", + "offset": -5 + } + }, + "mul_mod_builtin": { + "Deref": { + "register": "FP", + "offset": -5 + } + } + } + } + ] + ], + [ + 15297, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 15357, [ { "AllocSegment": { @@ -29158,7 +34516,7 @@ ] ], [ - 12037, + 15458, [ { "AllocSegment": { @@ -29171,7 +34529,7 @@ ] ], [ - 12139, + 15479, [ { "AllocSegment": { @@ -29184,40 +34542,20 @@ ] ], [ - 12205, + 15574, [ { - "EvalCircuit": { - "n_add_mods": { - "Deref": { - "register": "AP", - "offset": -6 - } - }, - "add_mod_builtin": { - "Deref": { - "register": "FP", - "offset": -6 - } - }, - "n_mul_mods": { - "Deref": { - "register": "AP", - "offset": -4 - } - }, - "mul_mod_builtin": { - "Deref": { - "register": "FP", - "offset": -5 - } + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 } } } ] ], [ - 12262, + 15604, [ { "AllocSegment": { @@ -29230,33 +34568,64 @@ ] ], [ - 12318, + 15658, [ { - "AllocSegment": { - "dst": { - "register": "AP", - "offset": 0 + "SystemCall": { + "system": { + "Deref": { + "register": "FP", + "offset": -7 + } } } } ] ], [ - 12411, + 15677, [ { - "AllocSegment": { - "dst": { - "register": "AP", - "offset": 0 + "SystemCall": { + "system": { + "BinOp": { + "op": "Add", + "a": { + "register": "FP", + "offset": -7 + }, + "b": { + "Immediate": "0x6" + } + } } } } ] ], [ - 12432, + 15690, + [ + { + "SystemCall": { + "system": { + "BinOp": { + "op": "Add", + "a": { + "register": "FP", + "offset": -7 + }, + "b": { + "Immediate": "0xd" + } + } + } + } + } + ] + ], + [ + 15696, [ { "AllocSegment": { @@ -29269,7 +34638,7 @@ ] ], [ - 12503, + 15769, [ { "AllocSegment": { @@ -29282,7 +34651,7 @@ ] ], [ - 12519, + 15801, [ { "AllocSegment": { @@ -29295,14 +34664,14 @@ ] ], [ - 12573, + 15831, [ { "SystemCall": { "system": { "Deref": { - "register": "FP", - "offset": -7 + "register": "AP", + "offset": -23 } } } @@ -29310,7 +34679,7 @@ ] ], [ - 12586, + 15847, [ { "SystemCall": { @@ -29318,8 +34687,8 @@ "BinOp": { "op": "Add", "a": { - "register": "FP", - "offset": -7 + "register": "AP", + "offset": -30 }, "b": { "Immediate": "0x6" @@ -29331,20 +34700,22 @@ ] ], [ - 12591, + 15872, [ { - "AllocSegment": { - "dst": { - "register": "AP", - "offset": 0 + "SystemCall": { + "system": { + "Deref": { + "register": "AP", + "offset": -8 + } } } } ] ], [ - 12655, + 15896, [ { "AllocSegment": { @@ -29357,43 +34728,20 @@ ] ], [ - 12678, - [ - { - "SystemCall": { - "system": { - "Deref": { - "register": "AP", - "offset": -13 - } - } - } - } - ] - ], - [ - 12693, + 15923, [ { - "SystemCall": { - "system": { - "BinOp": { - "op": "Add", - "a": { - "register": "AP", - "offset": -19 - }, - "b": { - "Immediate": "0x6" - } - } + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 } } } ] ], [ - 12717, + 15939, [ { "AllocSegment": { @@ -29406,7 +34754,7 @@ ] ], [ - 12733, + 15979, [ { "AllocSegment": { @@ -29419,7 +34767,7 @@ ] ], [ - 12771, + 15995, [ { "AllocSegment": { @@ -29432,7 +34780,7 @@ ] ], [ - 12787, + 16011, [ { "AllocSegment": { @@ -29445,7 +34793,7 @@ ] ], [ - 12803, + 16027, [ { "AllocSegment": { @@ -29458,7 +34806,7 @@ ] ], [ - 12819, + 16043, [ { "AllocSegment": { @@ -29471,7 +34819,7 @@ ] ], [ - 12866, + 16103, [ { "TestLessThan": { @@ -29499,7 +34847,7 @@ ] ], [ - 12870, + 16107, [ { "LinearSplit": { @@ -29528,7 +34876,7 @@ ] ], [ - 12892, + 16129, [ { "TestLessThanOrEqual": { @@ -29553,7 +34901,7 @@ ] ], [ - 12906, + 16143, [ { "TestLessThan": { @@ -29575,7 +34923,7 @@ ] ], [ - 12916, + 16153, [ { "TestLessThanOrEqual": { @@ -29600,7 +34948,7 @@ ] ], [ - 12939, + 16176, [ { "AllocSegment": { @@ -29613,7 +34961,7 @@ ] ], [ - 12960, + 16197, [ { "AllocSegment": { @@ -29626,7 +34974,7 @@ ] ], [ - 12981, + 16218, [ { "AllocSegment": { @@ -29639,12 +34987,12 @@ ] ], [ - 13029, + 16266, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x1cfc" + "Immediate": "0x1dc4" }, "rhs": { "Deref": { @@ -29661,7 +35009,7 @@ ] ], [ - 13089, + 16330, [ { "AllocSegment": { @@ -29674,12 +35022,12 @@ ] ], [ - 13109, + 16350, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0xb36" + "Immediate": "0xcc6" }, "rhs": { "Deref": { @@ -29696,7 +35044,7 @@ ] ], [ - 13175, + 16422, [ { "AllocSegment": { @@ -29709,7 +35057,7 @@ ] ], [ - 13205, + 16454, [ { "AllocSegment": { @@ -29722,12 +35070,12 @@ ] ], [ - 13225, + 16474, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0xf1e" + "Immediate": "0x1176" }, "rhs": { "Deref": { @@ -29744,7 +35092,7 @@ ] ], [ - 13313, + 16575, [ { "AllocSegment": { @@ -29757,7 +35105,7 @@ ] ], [ - 13343, + 16607, [ { "AllocSegment": { @@ -29770,12 +35118,12 @@ ] ], [ - 13363, + 16627, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x22ce" + "Immediate": "0x23fa" }, "rhs": { "Deref": { @@ -29792,7 +35140,7 @@ ] ], [ - 13434, + 16704, [ { "AllocSegment": { @@ -29805,7 +35153,7 @@ ] ], [ - 13455, + 16725, [ { "DivMod": { @@ -29834,7 +35182,7 @@ ] ], [ - 13516, + 16795, [ { "AllocSegment": { @@ -29847,7 +35195,7 @@ ] ], [ - 13569, + 16862, [ { "AllocSegment": { @@ -29860,7 +35208,7 @@ ] ], [ - 13582, + 16876, [ { "DivMod": { @@ -29889,7 +35237,7 @@ ] ], [ - 13590, + 16885, [ { "TestLessThan": { @@ -29898,12 +35246,12 @@ "op": "Add", "a": { "register": "AP", - "offset": -6 + "offset": -7 }, "b": { "Deref": { "register": "AP", - "offset": -1 + "offset": -2 } } } @@ -29920,7 +35268,7 @@ ] ], [ - 13618, + 16915, [ { "TestLessThan": { @@ -29942,7 +35290,7 @@ ] ], [ - 13635, + 16932, [ { "AllocSegment": { @@ -29955,7 +35303,7 @@ ] ], [ - 13651, + 16951, [ { "TestLessThan": { @@ -29964,12 +35312,12 @@ "op": "Add", "a": { "register": "AP", - "offset": -1 + "offset": -2 }, "b": { "Deref": { "register": "AP", - "offset": -3 + "offset": -4 } } } @@ -29986,7 +35334,7 @@ ] ], [ - 13673, + 16974, [ { "AllocSegment": { @@ -29999,7 +35347,7 @@ ] ], [ - 13687, + 16988, [ { "AllocSegment": { @@ -30012,7 +35360,7 @@ ] ], [ - 13751, + 17053, [ { "DivMod": { @@ -30041,7 +35389,7 @@ ] ], [ - 13760, + 17062, [ { "TestLessThan": { @@ -30063,7 +35411,7 @@ ] ], [ - 13770, + 17072, [ { "TestLessThan": { @@ -30094,7 +35442,7 @@ ] ], [ - 13791, + 17093, [ { "TestLessThan": { @@ -30125,7 +35473,7 @@ ] ], [ - 13805, + 17107, [ { "DivMod": { @@ -30154,7 +35502,7 @@ ] ], [ - 13822, + 17124, [ { "TestLessThan": { @@ -30176,7 +35524,7 @@ ] ], [ - 13834, + 17136, [ { "TestLessThan": { @@ -30198,7 +35546,7 @@ ] ], [ - 13844, + 17146, [ { "TestLessThan": { @@ -30229,7 +35577,7 @@ ] ], [ - 13867, + 17169, [ { "AllocSegment": { @@ -30242,7 +35590,7 @@ ] ], [ - 13882, + 17184, [ { "AllocSegment": { @@ -30255,7 +35603,7 @@ ] ], [ - 13897, + 17199, [ { "AllocSegment": { @@ -30268,7 +35616,7 @@ ] ], [ - 13912, + 17214, [ { "AllocSegment": { @@ -30281,7 +35629,7 @@ ] ], [ - 13927, + 17229, [ { "AllocSegment": { @@ -30294,7 +35642,7 @@ ] ], [ - 13942, + 17244, [ { "AllocSegment": { @@ -30307,12 +35655,12 @@ ] ], [ - 13955, + 17257, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x32f0" + "Immediate": "0x3480" }, "rhs": { "Deref": { @@ -30329,7 +35677,7 @@ ] ], [ - 13965, + 17268, [ { "TestLessThanOrEqualAddress": { @@ -30360,7 +35708,7 @@ ] ], [ - 14002, + 17308, [ { "SystemCall": { @@ -30375,7 +35723,7 @@ ] ], [ - 14035, + 17345, [ { "AllocSegment": { @@ -30388,7 +35736,7 @@ ] ], [ - 14064, + 17389, [ { "TestLessThan": { @@ -30410,7 +35758,7 @@ ] ], [ - 14086, + 17424, [ { "TestLessThan": { @@ -30432,7 +35780,7 @@ ] ], [ - 14124, + 17492, [ { "TestLessThan": { @@ -30454,7 +35802,7 @@ ] ], [ - 14146, + 17527, [ { "TestLessThan": { @@ -30476,7 +35824,7 @@ ] ], [ - 14230, + 17636, [ { "AllocSegment": { @@ -30489,7 +35837,7 @@ ] ], [ - 14268, + 17692, [ { "TestLessThan": { @@ -30511,7 +35859,7 @@ ] ], [ - 14292, + 17720, [ { "TestLessThan": { @@ -30533,7 +35881,7 @@ ] ], [ - 14330, + 17771, [ { "TestLessThan": { @@ -30555,7 +35903,7 @@ ] ], [ - 14356, + 17801, [ { "TestLessThan": { @@ -30577,7 +35925,7 @@ ] ], [ - 14393, + 17844, [ { "U256InvModN": { @@ -30596,13 +35944,13 @@ "n0": { "Deref": { "register": "AP", - "offset": -2 + "offset": -3 } }, "n1": { "Deref": { "register": "AP", - "offset": -1 + "offset": -2 } }, "g0_or_no_inv": { @@ -30634,7 +35982,7 @@ ] ], [ - 14411, + 17862, [ { "WideMul128": { @@ -30737,7 +36085,7 @@ "lhs": { "Deref": { "register": "AP", - "offset": -26 + "offset": -27 } }, "rhs": { @@ -30761,7 +36109,7 @@ "lhs": { "Deref": { "register": "AP", - "offset": -26 + "offset": -27 } }, "rhs": { @@ -30785,7 +36133,7 @@ "lhs": { "Deref": { "register": "AP", - "offset": -25 + "offset": -26 } }, "rhs": { @@ -30809,7 +36157,7 @@ "lhs": { "Deref": { "register": "AP", - "offset": -25 + "offset": -26 } }, "rhs": { @@ -30831,7 +36179,7 @@ ] ], [ - 14464, + 17915, [ { "WideMul128": { @@ -30877,14 +36225,14 @@ }, "low": { "register": "AP", - "offset": -9 + "offset": -10 } } } ] ], [ - 14468, + 17919, [ { "TestLessThan": { @@ -30906,7 +36254,7 @@ ] ], [ - 14482, + 17933, [ { "TestLessThan": { @@ -30928,14 +36276,14 @@ ] ], [ - 14495, + 17946, [ { "DivMod": { "lhs": { "Deref": { "register": "AP", - "offset": -47 + "offset": -48 } }, "rhs": { @@ -30954,7 +36302,7 @@ ] ], [ - 14505, + 17956, [ { "DivMod": { @@ -30980,7 +36328,7 @@ ] ], [ - 14516, + 17967, [ { "DivMod": { @@ -31006,14 +36354,14 @@ ] ], [ - 14525, + 17976, [ { "DivMod": { "lhs": { "Deref": { "register": "AP", - "offset": -62 + "offset": -63 } }, "rhs": { @@ -31032,7 +36380,7 @@ ] ], [ - 14535, + 17986, [ { "DivMod": { @@ -31058,7 +36406,7 @@ ] ], [ - 14546, + 17997, [ { "DivMod": { @@ -31084,14 +36432,14 @@ ] ], [ - 14555, + 18006, [ { "DivMod": { "lhs": { "Deref": { "register": "AP", - "offset": -78 + "offset": -79 } }, "rhs": { @@ -31110,7 +36458,7 @@ ] ], [ - 14565, + 18016, [ { "DivMod": { @@ -31136,7 +36484,7 @@ ] ], [ - 14576, + 18027, [ { "DivMod": { @@ -31162,14 +36510,14 @@ ] ], [ - 14585, + 18036, [ { "DivMod": { "lhs": { "Deref": { "register": "AP", - "offset": -93 + "offset": -94 } }, "rhs": { @@ -31188,7 +36536,7 @@ ] ], [ - 14595, + 18046, [ { "DivMod": { @@ -31214,7 +36562,7 @@ ] ], [ - 14606, + 18057, [ { "DivMod": { @@ -31240,7 +36588,7 @@ ] ], [ - 14615, + 18066, [ { "DivMod": { @@ -31266,7 +36614,7 @@ ] ], [ - 14625, + 18076, [ { "DivMod": { @@ -31292,7 +36640,7 @@ ] ], [ - 14636, + 18087, [ { "DivMod": { @@ -31318,7 +36666,7 @@ ] ], [ - 14645, + 18096, [ { "DivMod": { @@ -31344,7 +36692,7 @@ ] ], [ - 14655, + 18106, [ { "DivMod": { @@ -31370,7 +36718,7 @@ ] ], [ - 14666, + 18117, [ { "DivMod": { @@ -31396,7 +36744,7 @@ ] ], [ - 14675, + 18126, [ { "DivMod": { @@ -31422,7 +36770,7 @@ ] ], [ - 14685, + 18136, [ { "DivMod": { @@ -31448,7 +36796,7 @@ ] ], [ - 14696, + 18147, [ { "DivMod": { @@ -31474,7 +36822,7 @@ ] ], [ - 14705, + 18156, [ { "DivMod": { @@ -31500,7 +36848,7 @@ ] ], [ - 14715, + 18166, [ { "DivMod": { @@ -31526,7 +36874,7 @@ ] ], [ - 14726, + 18177, [ { "DivMod": { @@ -31552,7 +36900,7 @@ ] ], [ - 14747, + 18198, [ { "Uint512DivModByUint256": { @@ -31621,7 +36969,7 @@ ] ], [ - 14765, + 18216, [ { "WideMul128": { @@ -31746,7 +37094,7 @@ ] ], [ - 14794, + 18245, [ { "TestLessThan": { @@ -31771,7 +37119,7 @@ ] ], [ - 14806, + 18257, [ { "TestLessThan": { @@ -31796,7 +37144,7 @@ ] ], [ - 14821, + 18272, [ { "DivMod": { @@ -31822,7 +37170,7 @@ ] ], [ - 14831, + 18282, [ { "DivMod": { @@ -31848,7 +37196,7 @@ ] ], [ - 14842, + 18293, [ { "DivMod": { @@ -31874,7 +37222,7 @@ ] ], [ - 14851, + 18302, [ { "DivMod": { @@ -31900,7 +37248,7 @@ ] ], [ - 14861, + 18312, [ { "DivMod": { @@ -31926,7 +37274,7 @@ ] ], [ - 14872, + 18323, [ { "DivMod": { @@ -31952,7 +37300,7 @@ ] ], [ - 14881, + 18332, [ { "DivMod": { @@ -31978,7 +37326,7 @@ ] ], [ - 14891, + 18342, [ { "DivMod": { @@ -32004,7 +37352,7 @@ ] ], [ - 14902, + 18353, [ { "DivMod": { @@ -32030,7 +37378,7 @@ ] ], [ - 14911, + 18362, [ { "DivMod": { @@ -32056,7 +37404,7 @@ ] ], [ - 14921, + 18372, [ { "DivMod": { @@ -32082,7 +37430,7 @@ ] ], [ - 14932, + 18383, [ { "DivMod": { @@ -32108,7 +37456,7 @@ ] ], [ - 14941, + 18392, [ { "DivMod": { @@ -32134,7 +37482,7 @@ ] ], [ - 14951, + 18402, [ { "DivMod": { @@ -32160,7 +37508,7 @@ ] ], [ - 14962, + 18413, [ { "DivMod": { @@ -32186,7 +37534,7 @@ ] ], [ - 14983, + 18434, [ { "Uint512DivModByUint256": { @@ -32255,7 +37603,7 @@ ] ], [ - 15001, + 18452, [ { "WideMul128": { @@ -32380,7 +37728,7 @@ ] ], [ - 15030, + 18481, [ { "TestLessThan": { @@ -32405,7 +37753,7 @@ ] ], [ - 15042, + 18493, [ { "TestLessThan": { @@ -32430,7 +37778,7 @@ ] ], [ - 15057, + 18508, [ { "DivMod": { @@ -32456,7 +37804,7 @@ ] ], [ - 15067, + 18518, [ { "DivMod": { @@ -32482,7 +37830,7 @@ ] ], [ - 15078, + 18529, [ { "DivMod": { @@ -32508,7 +37856,7 @@ ] ], [ - 15087, + 18538, [ { "DivMod": { @@ -32534,7 +37882,7 @@ ] ], [ - 15097, + 18548, [ { "DivMod": { @@ -32560,7 +37908,7 @@ ] ], [ - 15108, + 18559, [ { "DivMod": { @@ -32586,7 +37934,7 @@ ] ], [ - 15117, + 18568, [ { "DivMod": { @@ -32612,7 +37960,7 @@ ] ], [ - 15127, + 18578, [ { "DivMod": { @@ -32638,7 +37986,7 @@ ] ], [ - 15138, + 18589, [ { "DivMod": { @@ -32664,7 +38012,7 @@ ] ], [ - 15147, + 18598, [ { "DivMod": { @@ -32690,7 +38038,7 @@ ] ], [ - 15157, + 18608, [ { "DivMod": { @@ -32716,7 +38064,7 @@ ] ], [ - 15168, + 18619, [ { "DivMod": { @@ -32742,7 +38090,7 @@ ] ], [ - 15177, + 18628, [ { "DivMod": { @@ -32768,7 +38116,7 @@ ] ], [ - 15187, + 18638, [ { "DivMod": { @@ -32794,7 +38142,7 @@ ] ], [ - 15198, + 18649, [ { "DivMod": { @@ -32820,7 +38168,7 @@ ] ], [ - 15225, + 18677, [ { "SystemCall": { @@ -32835,14 +38183,14 @@ ] ], [ - 15242, + 18696, [ { "SystemCall": { "system": { "Deref": { "register": "AP", - "offset": -2 + "offset": -4 } } } @@ -32850,7 +38198,7 @@ ] ], [ - 15254, + 18709, [ { "SystemCall": { @@ -32859,7 +38207,7 @@ "op": "Add", "a": { "register": "AP", - "offset": -6 + "offset": -9 }, "b": { "Immediate": "0x8" @@ -32871,7 +38219,7 @@ ] ], [ - 15265, + 18721, [ { "SystemCall": { @@ -32880,7 +38228,7 @@ "op": "Add", "a": { "register": "AP", - "offset": -10 + "offset": -14 }, "b": { "Immediate": "0x10" @@ -32892,7 +38240,7 @@ ] ], [ - 15275, + 18732, [ { "SystemCall": { @@ -32901,7 +38249,7 @@ "op": "Add", "a": { "register": "AP", - "offset": -14 + "offset": -19 }, "b": { "Immediate": "0x17" @@ -32913,7 +38261,7 @@ ] ], [ - 15360, + 18831, [ { "AllocSegment": { @@ -32926,14 +38274,14 @@ ] ], [ - 15389, + 18863, [ { "DivMod": { "lhs": { "Deref": { "register": "AP", - "offset": -642 + "offset": -651 } }, "rhs": { @@ -32952,7 +38300,7 @@ ] ], [ - 15399, + 18873, [ { "DivMod": { @@ -32978,7 +38326,7 @@ ] ], [ - 15410, + 18884, [ { "DivMod": { @@ -32997,21 +38345,21 @@ }, "remainder": { "register": "AP", - "offset": -656 + "offset": -666 } } } ] ], [ - 15419, + 18893, [ { "DivMod": { "lhs": { "Deref": { "register": "AP", - "offset": -657 + "offset": -666 } }, "rhs": { @@ -33030,7 +38378,7 @@ ] ], [ - 15429, + 18903, [ { "DivMod": { @@ -33056,7 +38404,7 @@ ] ], [ - 15440, + 18914, [ { "DivMod": { @@ -33082,7 +38430,7 @@ ] ], [ - 15449, + 18923, [ { "AllocSegment": { @@ -33095,7 +38443,7 @@ ] ], [ - 15519, + 18995, [ { "TestLessThan": { @@ -33126,7 +38474,7 @@ ] ], [ - 15534, + 19010, [ { "TestLessThan": { @@ -33148,7 +38496,7 @@ ] ], [ - 15553, + 19029, [ { "TestLessThan": { @@ -33170,7 +38518,7 @@ ] ], [ - 15572, + 19048, [ { "TestLessThan": { @@ -33192,7 +38540,7 @@ ] ], [ - 15582, + 19058, [ { "TestLessThan": { @@ -33214,7 +38562,7 @@ ] ], [ - 15584, + 19060, [ { "DivMod": { @@ -33240,7 +38588,7 @@ ] ], [ - 15621, + 19097, [ { "TestLessThan": { @@ -33262,20 +38610,7 @@ ] ], [ - 15640, - [ - { - "AllocSegment": { - "dst": { - "register": "AP", - "offset": 0 - } - } - } - ] - ], - [ - 15651, + 19112, [ { "DivMod": { @@ -33304,7 +38639,7 @@ ] ], [ - 15657, + 19118, [ { "TestLessThan": { @@ -33326,7 +38661,7 @@ ] ], [ - 15671, + 19132, [ { "TestLessThan": { @@ -33348,7 +38683,7 @@ ] ], [ - 15685, + 19146, [ { "TestLessThan": { @@ -33370,7 +38705,7 @@ ] ], [ - 15696, + 19157, [ { "TestLessThan": { @@ -33392,7 +38727,7 @@ ] ], [ - 15725, + 19186, [ { "AllocSegment": { @@ -33405,7 +38740,7 @@ ] ], [ - 15750, + 19211, [ { "TestLessThan": { @@ -33427,7 +38762,7 @@ ] ], [ - 15754, + 19215, [ { "LinearSplit": { @@ -33456,7 +38791,7 @@ ] ], [ - 15764, + 19225, [ { "LinearSplit": { @@ -33485,7 +38820,7 @@ ] ], [ - 15784, + 19245, [ { "AllocSegment": { @@ -33498,7 +38833,7 @@ ] ], [ - 15805, + 19266, [ { "AllocSegment": { @@ -33511,7 +38846,7 @@ ] ], [ - 15826, + 19287, [ { "AllocSegment": { @@ -33524,7 +38859,7 @@ ] ], [ - 15846, + 19307, [ { "TestLessThan": { @@ -33546,7 +38881,7 @@ ] ], [ - 15848, + 19309, [ { "DivMod": { @@ -33572,20 +38907,7 @@ ] ], [ - 15892, - [ - { - "AllocSegment": { - "dst": { - "register": "AP", - "offset": 0 - } - } - } - ] - ], - [ - 15903, + 19349, [ { "DivMod": { @@ -33614,7 +38936,7 @@ ] ], [ - 15909, + 19355, [ { "TestLessThan": { @@ -33636,7 +38958,7 @@ ] ], [ - 15923, + 19369, [ { "TestLessThan": { @@ -33658,7 +38980,7 @@ ] ], [ - 15941, + 19387, [ { "TestLessThan": { @@ -33680,7 +39002,7 @@ ] ], [ - 15954, + 19400, [ { "TestLessThan": { @@ -33702,7 +39024,7 @@ ] ], [ - 15965, + 19411, [ { "TestLessThan": { @@ -33724,7 +39046,7 @@ ] ], [ - 15994, + 19440, [ { "AllocSegment": { @@ -33737,7 +39059,7 @@ ] ], [ - 16019, + 19465, [ { "TestLessThan": { @@ -33759,7 +39081,7 @@ ] ], [ - 16023, + 19469, [ { "LinearSplit": { @@ -33788,7 +39110,7 @@ ] ], [ - 16033, + 19479, [ { "LinearSplit": { @@ -33817,7 +39139,7 @@ ] ], [ - 16053, + 19499, [ { "AllocSegment": { @@ -33830,7 +39152,7 @@ ] ], [ - 16074, + 19520, [ { "AllocSegment": { @@ -33843,7 +39165,7 @@ ] ], [ - 16095, + 19541, [ { "AllocSegment": { @@ -33856,7 +39178,7 @@ ] ], [ - 16124, + 19570, [ { "TestLessThan": { @@ -33878,7 +39200,7 @@ ] ], [ - 16126, + 19572, [ { "DivMod": { @@ -33904,7 +39226,7 @@ ] ], [ - 16163, + 19609, [ { "TestLessThan": { @@ -33926,7 +39248,7 @@ ] ], [ - 16174, + 19620, [ { "TestLessThan": { @@ -33948,7 +39270,7 @@ ] ], [ - 16185, + 19631, [ { "TestLessThan": { @@ -33970,7 +39292,7 @@ ] ], [ - 16214, + 19660, [ { "AllocSegment": { @@ -33983,7 +39305,7 @@ ] ], [ - 16239, + 19685, [ { "TestLessThan": { @@ -34005,7 +39327,7 @@ ] ], [ - 16243, + 19689, [ { "LinearSplit": { @@ -34034,7 +39356,7 @@ ] ], [ - 16253, + 19699, [ { "LinearSplit": { @@ -34063,7 +39385,7 @@ ] ], [ - 16279, + 19725, [ { "AllocSegment": { @@ -34076,7 +39398,7 @@ ] ], [ - 16300, + 19746, [ { "AllocSegment": { @@ -34089,7 +39411,7 @@ ] ], [ - 16322, + 19768, [ { "AllocSegment": { @@ -34102,7 +39424,7 @@ ] ], [ - 16344, + 19790, [ { "TestLessThan": { @@ -34124,7 +39446,7 @@ ] ], [ - 16355, + 19801, [ { "TestLessThan": { @@ -34146,7 +39468,7 @@ ] ], [ - 16384, + 19830, [ { "AllocSegment": { @@ -34159,7 +39481,7 @@ ] ], [ - 16409, + 19855, [ { "TestLessThan": { @@ -34181,7 +39503,7 @@ ] ], [ - 16413, + 19859, [ { "LinearSplit": { @@ -34210,7 +39532,7 @@ ] ], [ - 16423, + 19869, [ { "LinearSplit": { @@ -34239,7 +39561,7 @@ ] ], [ - 16446, + 19892, [ { "AllocSegment": { @@ -34252,7 +39574,7 @@ ] ], [ - 16497, + 19943, [ { "TestLessThan": { @@ -34274,7 +39596,7 @@ ] ], [ - 16508, + 19954, [ { "TestLessThan": { @@ -34296,7 +39618,7 @@ ] ], [ - 16537, + 19983, [ { "AllocSegment": { @@ -34309,7 +39631,7 @@ ] ], [ - 16560, + 20006, [ { "TestLessThan": { @@ -34340,7 +39662,7 @@ ] ], [ - 16584, + 20030, [ { "AllocSegment": { @@ -34353,7 +39675,7 @@ ] ], [ - 16618, + 20064, [ { "AllocSegment": { @@ -34366,12 +39688,12 @@ ] ], [ - 16635, + 20081, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x686" + "Immediate": "0x6ea" }, "rhs": { "Deref": { @@ -34388,7 +39710,7 @@ ] ], [ - 16672, + 20120, [ { "AllocSegment": { @@ -34401,7 +39723,7 @@ ] ], [ - 16717, + 20165, [ { "TestLessThan": { @@ -34429,7 +39751,7 @@ ] ], [ - 16721, + 20169, [ { "LinearSplit": { @@ -34458,7 +39780,7 @@ ] ], [ - 16763, + 20211, [ { "TestLessThan": { @@ -34480,7 +39802,7 @@ ] ], [ - 16765, + 20213, [ { "DivMod": { @@ -34506,7 +39828,7 @@ ] ], [ - 16852, + 20300, [ { "DivMod": { @@ -34535,7 +39857,7 @@ ] ], [ - 16858, + 20306, [ { "TestLessThan": { @@ -34557,7 +39879,7 @@ ] ], [ - 16869, + 20317, [ { "TestLessThan": { @@ -34579,7 +39901,7 @@ ] ], [ - 16879, + 20327, [ { "TestLessThan": { @@ -34601,7 +39923,7 @@ ] ], [ - 16893, + 20341, [ { "DivMod": { @@ -34630,7 +39952,7 @@ ] ], [ - 16899, + 20347, [ { "TestLessThan": { @@ -34652,7 +39974,7 @@ ] ], [ - 16913, + 20361, [ { "TestLessThan": { @@ -34674,7 +39996,7 @@ ] ], [ - 16923, + 20371, [ { "TestLessThan": { @@ -34696,7 +40018,7 @@ ] ], [ - 16945, + 20393, [ { "AllocSegment": { @@ -34709,7 +40031,7 @@ ] ], [ - 16959, + 20407, [ { "AllocSegment": { @@ -34722,7 +40044,7 @@ ] ], [ - 16977, + 20425, [ { "AllocSegment": { @@ -34735,7 +40057,7 @@ ] ], [ - 16991, + 20439, [ { "AllocSegment": { @@ -34748,12 +40070,12 @@ ] ], [ - 17007, + 20455, [ { "TestLessThanOrEqual": { "lhs": { - "Immediate": "0x8c0" + "Immediate": "0x988" }, "rhs": { "Deref": { @@ -34770,7 +40092,7 @@ ] ], [ - 17034, + 20484, [ { "TestLessThan": { @@ -34792,7 +40114,7 @@ ] ], [ - 17051, + 20501, [ { "AllocSegment": { @@ -34805,7 +40127,7 @@ ] ], [ - 17076, + 20528, [ { "AllocSegment": { @@ -34818,7 +40140,7 @@ ] ], [ - 17336, + 20788, [ { "SystemCall": { @@ -34833,14 +40155,14 @@ ] ], [ - 17362, + 20816, [ { "SystemCall": { "system": { "Deref": { "register": "AP", - "offset": -6 + "offset": -8 } } } @@ -34848,7 +40170,7 @@ ] ], [ - 17376, + 20832, [ { "U256InvModN": { @@ -34867,13 +40189,13 @@ "n0": { "Deref": { "register": "AP", - "offset": -2 + "offset": -3 } }, "n1": { "Deref": { "register": "AP", - "offset": -1 + "offset": -2 } }, "g0_or_no_inv": { @@ -34905,7 +40227,7 @@ ] ], [ - 17394, + 20850, [ { "WideMul128": { @@ -35008,7 +40330,7 @@ "lhs": { "Deref": { "register": "AP", - "offset": -26 + "offset": -27 } }, "rhs": { @@ -35032,7 +40354,7 @@ "lhs": { "Deref": { "register": "AP", - "offset": -26 + "offset": -27 } }, "rhs": { @@ -35056,7 +40378,7 @@ "lhs": { "Deref": { "register": "AP", - "offset": -25 + "offset": -26 } }, "rhs": { @@ -35080,7 +40402,7 @@ "lhs": { "Deref": { "register": "AP", - "offset": -25 + "offset": -26 } }, "rhs": { @@ -35102,7 +40424,7 @@ ] ], [ - 17447, + 20903, [ { "WideMul128": { @@ -35148,14 +40470,14 @@ }, "low": { "register": "AP", - "offset": -9 + "offset": -10 } } } ] ], [ - 17451, + 20907, [ { "TestLessThan": { @@ -35177,7 +40499,7 @@ ] ], [ - 17465, + 20921, [ { "TestLessThan": { @@ -35199,14 +40521,14 @@ ] ], [ - 17478, + 20934, [ { "DivMod": { "lhs": { "Deref": { "register": "AP", - "offset": -47 + "offset": -48 } }, "rhs": { @@ -35225,7 +40547,7 @@ ] ], [ - 17488, + 20944, [ { "DivMod": { @@ -35251,7 +40573,7 @@ ] ], [ - 17499, + 20955, [ { "DivMod": { @@ -35277,14 +40599,14 @@ ] ], [ - 17508, + 20964, [ { "DivMod": { "lhs": { "Deref": { "register": "AP", - "offset": -62 + "offset": -63 } }, "rhs": { @@ -35303,7 +40625,7 @@ ] ], [ - 17518, + 20974, [ { "DivMod": { @@ -35329,7 +40651,7 @@ ] ], [ - 17529, + 20985, [ { "DivMod": { @@ -35355,14 +40677,14 @@ ] ], [ - 17538, + 20994, [ { "DivMod": { "lhs": { "Deref": { "register": "AP", - "offset": -78 + "offset": -79 } }, "rhs": { @@ -35381,7 +40703,7 @@ ] ], [ - 17548, + 21004, [ { "DivMod": { @@ -35407,7 +40729,7 @@ ] ], [ - 17559, + 21015, [ { "DivMod": { @@ -35433,14 +40755,14 @@ ] ], [ - 17568, + 21024, [ { "DivMod": { "lhs": { "Deref": { "register": "AP", - "offset": -93 + "offset": -94 } }, "rhs": { @@ -35459,7 +40781,7 @@ ] ], [ - 17578, + 21034, [ { "DivMod": { @@ -35485,7 +40807,7 @@ ] ], [ - 17589, + 21045, [ { "DivMod": { @@ -35511,7 +40833,7 @@ ] ], [ - 17598, + 21054, [ { "DivMod": { @@ -35537,7 +40859,7 @@ ] ], [ - 17608, + 21064, [ { "DivMod": { @@ -35563,7 +40885,7 @@ ] ], [ - 17619, + 21075, [ { "DivMod": { @@ -35589,7 +40911,7 @@ ] ], [ - 17628, + 21084, [ { "DivMod": { @@ -35615,7 +40937,7 @@ ] ], [ - 17638, + 21094, [ { "DivMod": { @@ -35641,7 +40963,7 @@ ] ], [ - 17649, + 21105, [ { "DivMod": { @@ -35667,7 +40989,7 @@ ] ], [ - 17658, + 21114, [ { "DivMod": { @@ -35693,7 +41015,7 @@ ] ], [ - 17668, + 21124, [ { "DivMod": { @@ -35719,7 +41041,7 @@ ] ], [ - 17679, + 21135, [ { "DivMod": { @@ -35745,7 +41067,7 @@ ] ], [ - 17688, + 21144, [ { "DivMod": { @@ -35771,7 +41093,7 @@ ] ], [ - 17698, + 21154, [ { "DivMod": { @@ -35797,7 +41119,7 @@ ] ], [ - 17709, + 21165, [ { "DivMod": { @@ -35823,7 +41145,7 @@ ] ], [ - 17730, + 21186, [ { "Uint512DivModByUint256": { @@ -35892,7 +41214,7 @@ ] ], [ - 17748, + 21204, [ { "WideMul128": { @@ -36017,7 +41339,7 @@ ] ], [ - 17777, + 21233, [ { "TestLessThan": { @@ -36042,7 +41364,7 @@ ] ], [ - 17789, + 21245, [ { "TestLessThan": { @@ -36067,7 +41389,7 @@ ] ], [ - 17804, + 21260, [ { "DivMod": { @@ -36093,7 +41415,7 @@ ] ], [ - 17814, + 21270, [ { "DivMod": { @@ -36119,7 +41441,7 @@ ] ], [ - 17825, + 21281, [ { "DivMod": { @@ -36145,7 +41467,7 @@ ] ], [ - 17834, + 21290, [ { "DivMod": { @@ -36171,7 +41493,7 @@ ] ], [ - 17844, + 21300, [ { "DivMod": { @@ -36197,7 +41519,7 @@ ] ], [ - 17855, + 21311, [ { "DivMod": { @@ -36223,7 +41545,7 @@ ] ], [ - 17864, + 21320, [ { "DivMod": { @@ -36249,7 +41571,7 @@ ] ], [ - 17874, + 21330, [ { "DivMod": { @@ -36275,7 +41597,7 @@ ] ], [ - 17885, + 21341, [ { "DivMod": { @@ -36301,7 +41623,7 @@ ] ], [ - 17894, + 21350, [ { "DivMod": { @@ -36327,7 +41649,7 @@ ] ], [ - 17904, + 21360, [ { "DivMod": { @@ -36353,7 +41675,7 @@ ] ], [ - 17915, + 21371, [ { "DivMod": { @@ -36379,7 +41701,7 @@ ] ], [ - 17924, + 21380, [ { "DivMod": { @@ -36405,7 +41727,7 @@ ] ], [ - 17934, + 21390, [ { "DivMod": { @@ -36431,7 +41753,7 @@ ] ], [ - 17945, + 21401, [ { "DivMod": { @@ -36457,7 +41779,7 @@ ] ], [ - 17957, + 21414, [ { "TestLessThan": { @@ -36479,7 +41801,7 @@ ] ], [ - 17982, + 21442, [ { "TestLessThan": { @@ -36501,7 +41823,7 @@ ] ], [ - 18001, + 21464, [ { "TestLessThan": { @@ -36523,7 +41845,7 @@ ] ], [ - 18026, + 21490, [ { "Uint512DivModByUint256": { @@ -36592,7 +41914,7 @@ ] ], [ - 18044, + 21508, [ { "WideMul128": { @@ -36717,7 +42039,7 @@ ] ], [ - 18073, + 21537, [ { "TestLessThan": { @@ -36742,7 +42064,7 @@ ] ], [ - 18085, + 21549, [ { "TestLessThan": { @@ -36767,7 +42089,7 @@ ] ], [ - 18100, + 21564, [ { "DivMod": { @@ -36793,7 +42115,7 @@ ] ], [ - 18110, + 21574, [ { "DivMod": { @@ -36819,7 +42141,7 @@ ] ], [ - 18121, + 21585, [ { "DivMod": { @@ -36845,7 +42167,7 @@ ] ], [ - 18130, + 21594, [ { "DivMod": { @@ -36871,7 +42193,7 @@ ] ], [ - 18140, + 21604, [ { "DivMod": { @@ -36897,7 +42219,7 @@ ] ], [ - 18151, + 21615, [ { "DivMod": { @@ -36923,7 +42245,7 @@ ] ], [ - 18160, + 21624, [ { "DivMod": { @@ -36949,7 +42271,7 @@ ] ], [ - 18170, + 21634, [ { "DivMod": { @@ -36975,7 +42297,7 @@ ] ], [ - 18181, + 21645, [ { "DivMod": { @@ -37001,7 +42323,7 @@ ] ], [ - 18190, + 21654, [ { "DivMod": { @@ -37027,7 +42349,7 @@ ] ], [ - 18200, + 21664, [ { "DivMod": { @@ -37053,7 +42375,7 @@ ] ], [ - 18211, + 21675, [ { "DivMod": { @@ -37079,7 +42401,7 @@ ] ], [ - 18220, + 21684, [ { "DivMod": { @@ -37105,7 +42427,7 @@ ] ], [ - 18230, + 21694, [ { "DivMod": { @@ -37131,7 +42453,7 @@ ] ], [ - 18241, + 21705, [ { "DivMod": { @@ -37157,14 +42479,14 @@ ] ], [ - 18261, + 21726, [ { "SystemCall": { "system": { "Deref": { "register": "AP", - "offset": -666 + "offset": -673 } } } @@ -37172,7 +42494,7 @@ ] ], [ - 18273, + 21739, [ { "SystemCall": { @@ -37181,7 +42503,7 @@ "op": "Add", "a": { "register": "AP", - "offset": -670 + "offset": -678 }, "b": { "Immediate": "0x8" @@ -37193,7 +42515,7 @@ ] ], [ - 18284, + 21751, [ { "SystemCall": { @@ -37202,7 +42524,7 @@ "op": "Add", "a": { "register": "AP", - "offset": -674 + "offset": -683 }, "b": { "Immediate": "0x10" @@ -37214,7 +42536,7 @@ ] ], [ - 18337, + 21814, [ { "AllocSegment": { @@ -37227,14 +42549,14 @@ ] ], [ - 18353, + 21830, [ { "DivMod": { "lhs": { "Deref": { "register": "AP", - "offset": -640 + "offset": -648 } }, "rhs": { @@ -37253,7 +42575,7 @@ ] ], [ - 18363, + 21840, [ { "DivMod": { @@ -37279,7 +42601,7 @@ ] ], [ - 18374, + 21851, [ { "DivMod": { @@ -37298,21 +42620,21 @@ }, "remainder": { "register": "AP", - "offset": -654 + "offset": -663 } } } ] ], [ - 18383, + 21860, [ { "DivMod": { "lhs": { "Deref": { "register": "AP", - "offset": -655 + "offset": -663 } }, "rhs": { @@ -37331,7 +42653,7 @@ ] ], [ - 18393, + 21870, [ { "DivMod": { @@ -37357,7 +42679,7 @@ ] ], [ - 18404, + 21881, [ { "DivMod": { @@ -37383,7 +42705,7 @@ ] ], [ - 18413, + 21890, [ { "AllocSegment": { @@ -37396,7 +42718,7 @@ ] ], [ - 18430, + 21908, [ { "AllocSegment": { @@ -37409,7 +42731,7 @@ ] ], [ - 18487, + 21971, [ { "SystemCall": { @@ -37424,7 +42746,7 @@ ] ], [ - 18494, + 21979, [ { "AllocConstantSize": { @@ -37440,7 +42762,7 @@ ] ], [ - 18498, + 21983, [ { "AllocSegment": { @@ -37453,7 +42775,7 @@ ] ], [ - 18533, + 22019, [ { "SystemCall": { @@ -37468,7 +42790,7 @@ ] ], [ - 18606, + 22093, [ { "DivMod": { @@ -37497,7 +42819,7 @@ ] ], [ - 18612, + 22099, [ { "TestLessThan": { @@ -37519,7 +42841,7 @@ ] ], [ - 18679, + 22208, [ { "WideMul128": { @@ -37548,7 +42870,7 @@ ] ], [ - 18681, + 22210, [ { "DivMod": { @@ -37574,7 +42896,7 @@ ] ], [ - 18691, + 22220, [ { "DivMod": { @@ -37600,7 +42922,7 @@ ] ], [ - 18702, + 22231, [ { "DivMod": { @@ -37626,7 +42948,7 @@ ] ], [ - 18711, + 22240, [ { "WideMul128": { @@ -37655,7 +42977,7 @@ ] ], [ - 18713, + 22242, [ { "DivMod": { @@ -37681,7 +43003,7 @@ ] ], [ - 18723, + 22252, [ { "DivMod": { @@ -37707,7 +43029,7 @@ ] ], [ - 18734, + 22263, [ { "DivMod": { @@ -37733,7 +43055,7 @@ ] ], [ - 18744, + 22273, [ { "TestLessThan": { @@ -37755,7 +43077,7 @@ ] ], [ - 18766, + 22295, [ { "WideMul128": { @@ -37784,7 +43106,7 @@ ] ], [ - 18768, + 22297, [ { "DivMod": { @@ -37810,7 +43132,7 @@ ] ], [ - 18778, + 22307, [ { "DivMod": { @@ -37836,7 +43158,7 @@ ] ], [ - 18789, + 22318, [ { "DivMod": { @@ -37862,7 +43184,7 @@ ] ], [ - 18799, + 22328, [ { "TestLessThan": { @@ -37884,7 +43206,7 @@ ] ], [ - 18822, + 22351, [ { "TestLessThan": { @@ -37906,7 +43228,7 @@ ] ], [ - 18844, + 22373, [ { "WideMul128": { @@ -37935,7 +43257,7 @@ ] ], [ - 18846, + 22375, [ { "DivMod": { @@ -37961,7 +43283,7 @@ ] ], [ - 18856, + 22385, [ { "DivMod": { @@ -37987,7 +43309,7 @@ ] ], [ - 18867, + 22396, [ { "DivMod": { @@ -38013,7 +43335,7 @@ ] ], [ - 18877, + 22406, [ { "TestLessThan": { @@ -38035,7 +43357,7 @@ ] ], [ - 18901, + 22430, [ { "TestLessThan": { @@ -38057,7 +43379,7 @@ ] ], [ - 18926, + 22455, [ { "TestLessThan": { @@ -38079,7 +43401,7 @@ ] ], [ - 18950, + 22479, [ { "TestLessThan": { @@ -38101,7 +43423,7 @@ ] ], [ - 19068, + 22597, [ { "AllocSegment": { @@ -38114,7 +43436,7 @@ ] ], [ - 19091, + 22620, [ { "TestLessThanOrEqual": { @@ -38139,7 +43461,7 @@ ] ], [ - 19166, + 22710, [ { "AllocSegment": { @@ -38152,7 +43474,7 @@ ] ], [ - 19221, + 22765, [ { "DivMod": { @@ -38181,7 +43503,7 @@ ] ], [ - 19227, + 22771, [ { "TestLessThan": { @@ -38203,7 +43525,7 @@ ] ], [ - 19240, + 22784, [ { "TestLessThan": { @@ -38225,7 +43547,7 @@ ] ], [ - 19250, + 22794, [ { "TestLessThan": { @@ -38247,7 +43569,7 @@ ] ], [ - 19298, + 22842, [ { "DivMod": { @@ -38276,7 +43598,7 @@ ] ], [ - 19304, + 22848, [ { "TestLessThan": { @@ -38298,7 +43620,7 @@ ] ], [ - 19320, + 22864, [ { "TestLessThan": { @@ -38320,7 +43642,7 @@ ] ], [ - 19330, + 22874, [ { "TestLessThan": { @@ -38342,7 +43664,7 @@ ] ], [ - 19353, + 22897, [ { "AllocSegment": { @@ -38355,7 +43677,7 @@ ] ], [ - 19367, + 22911, [ { "AllocSegment": { @@ -38368,7 +43690,7 @@ ] ], [ - 19386, + 22930, [ { "AllocSegment": { @@ -38381,7 +43703,7 @@ ] ], [ - 19400, + 22944, [ { "AllocSegment": { @@ -38398,14 +43720,14 @@ "EXTERNAL": [ { "selector": "0x1143aa89c8e3ebf8ed14df2a3606c1cd2dd513fac8040b0f8ab441f5c52fe4", - "offset": 4638, + "offset": 5902, "builtins": [ "range_check" ] }, { "selector": "0x3541591104188daef4379e06e92ecce09094a3b381da2e654eb041d00566d8", - "offset": 6315, + "offset": 7694, "builtins": [ "range_check", "range_check96" @@ -38413,35 +43735,35 @@ }, { "selector": "0x3c118a68e16e12e97ed25cb4901c12f4d3162818669cc44c391d8049924c14", - "offset": 2107, + "offset": 3000, "builtins": [ "range_check" ] }, { "selector": "0x5562b3e932b4d139366854d5a2e578382e6a3b6572ac9943d55e7efbe43d00", - "offset": 4089, + "offset": 5316, "builtins": [ "range_check" ] }, { "selector": "0x600c98a299d72ef1e09a2e1503206fbc76081233172c65f7e2438ef0069d8d", - "offset": 4765, + "offset": 6037, "builtins": [ "range_check" ] }, { "selector": "0x62c83572d28cb834a3de3c1e94977a4191469a4a8c26d1d7bc55305e640ed5", - "offset": 4246, + "offset": 5483, "builtins": [ "range_check" ] }, { "selector": "0x679c22735055a10db4f275395763a3752a1e3a3043c192299ab6b574fba8d6", - "offset": 5794, + "offset": 7142, "builtins": [ "range_check", "ec_op" @@ -38449,37 +43771,45 @@ }, { "selector": "0x7772be8b80a8a33dc6c1f9a6ab820c02e537c73e859de67f288c70f92571bb", - "offset": 5196, + "offset": 6501, "builtins": [ "pedersen", "range_check", "bitwise" ] }, + { + "selector": "0xca779dd628d0206eda15b718936109101fcdee458be409b230a64462c4bf23", + "offset": 8655, + "builtins": [ + "range_check", + "ec_op" + ] + }, { "selector": "0xd47144c49bce05b6de6bce9d5ff0cc8da9420f8945453e20ef779cbea13ad4", - "offset": 229, + "offset": 249, "builtins": [ "range_check" ] }, { "selector": "0xe7510edcf6e9f1b70f7bd1f488767b50f0363422f3c563160ab77adf62467b", - "offset": 2878, + "offset": 3829, "builtins": [ "range_check" ] }, { "selector": "0xf818e4530ec36b83dfe702489b4df537308c3b798b0cc120e32c2056d68b7d", - "offset": 3664, + "offset": 4867, "builtins": [ "range_check" ] }, { "selector": "0x10d2fede95e3ec06a875a67219425c27c5bd734d57f1b221d729a2337b6b556", - "offset": 3251, + "offset": 4235, "builtins": [ "range_check", "segment_arena" @@ -38487,35 +43817,42 @@ }, { "selector": "0x12ead94ae9d3f9d2bdb6b847cf255f1f398193a1f88884a0ae8e18f24a037b6", - "offset": 6043, + "offset": 7405, + "builtins": [ + "range_check" + ] + }, + { + "selector": "0x1469798554697a4c50c64f933147bd163500204d4ae206eee1a9b9bf6c228de", + "offset": 4681, "builtins": [ "range_check" ] }, { "selector": "0x14dae1999ae9ab799bc72def6dc6e90890cf8ac0d64525021b7e71d05cb13e8", - "offset": 1355, + "offset": 2186, "builtins": [ "range_check" ] }, { "selector": "0x169f135eddda5ab51886052d777a57f2ea9c162d713691b5e04a6d4ed71d47f", - "offset": 3362, + "offset": 4351, "builtins": [ "range_check" ] }, { "selector": "0x1995689b6aedab51ad67bc2ae0b0ee3fe1ffc433f96179953e6a6b7210b9e13", - "offset": 1665, + "offset": 2521, "builtins": [ "range_check" ] }, { "selector": "0x1ae1a515cf2d214b29bdf63a79ee2d490efd4dd1acc99d383a8e549c3cecb5d", - "offset": 5905, + "offset": 7259, "builtins": [ "pedersen", "range_check" @@ -38523,56 +43860,84 @@ }, { "selector": "0x1e4089d1f1349077b1970f9937c904e27c4582b49a60b6078946dba95bc3c08", - "offset": 1184, + "offset": 1284, + "builtins": [ + "range_check" + ] + }, + { + "selector": "0x227ac0f3ce8083231605cb10be915be2004456b618e44b56067e27fc6f8c84f", + "offset": 8235, "builtins": [ "range_check" ] }, { "selector": "0x23039bef544cff56442d9f61ae9b13cf9e36fcce009102c5b678aac93f37b36", - "offset": 1929, + "offset": 2807, + "builtins": [ + "range_check" + ] + }, + { + "selector": "0x25ff849c52d40a7f29c9849fbe0064575d61c84ddc0ef562bf05bc599abe0ae", + "offset": 1506, "builtins": [ "range_check" ] }, { "selector": "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", - "offset": 409, + "offset": 443, "builtins": [ "range_check" ] }, { "selector": "0x298e03955860424b6a946506da72353a645f653dc1879f6b55fd756f3d20a59", - "offset": 674, + "offset": 731, "builtins": [ "range_check" ] }, { "selector": "0x2d7cf5d5a324a320f9f37804b1615a533fde487400b41af80f13f7ac5581325", - "offset": 3052, + "offset": 4018, + "builtins": [ + "range_check" + ] + }, + { + "selector": "0x2f8b66957adc4564548f3832947bf264a065874e087c21b9e7cf969e2874c0c", + "offset": 1631, "builtins": [ "range_check" ] }, { "selector": "0x30f842021fbf02caf80d09a113997c1e00a32870eee0c6136bed27acb348bea", - "offset": 5464, + "offset": 6786, + "builtins": [ + "range_check" + ] + }, + { + "selector": "0x311fb2a7f01403971aca6ae0a12b8ad0602e7a5ec48ad48951969942e99d788", + "offset": 1887, "builtins": [ "range_check" ] }, { "selector": "0x31401f504973a5e8e1bb41e9c592519e3aa0b8cf6bbfb9c91b532aab8db54b0", - "offset": 6438, + "offset": 7828, "builtins": [ "range_check" ] }, { "selector": "0x317eb442b72a9fae758d4fb26830ed0d9f31c8e7da4dbff4e8c59ea6a158e7f", - "offset": 5008, + "offset": 6301, "builtins": [ "pedersen", "range_check" @@ -38580,36 +43945,59 @@ }, { "selector": "0x32564d7e0fe091d49b4c20f4632191e4ed6986bf993849879abfef9465def25", - "offset": 4418, + "offset": 5668, + "builtins": [ + "range_check" + ] + }, + { + "selector": "0x3502249e98d12b6c72951d280360de19ac166d0f18c620addb78491a669c826", + "offset": 8542, + "builtins": [ + "range_check", + "poseidon" + ] + }, + { + "selector": "0x3555d7ef6849c9f3e3c3b07e7b36395a40bba49ef095d4a8c41467b76a03501", + "offset": 8436, "builtins": [ + "pedersen", "range_check" ] }, { "selector": "0x3604cea1cdb094a73a31144f14a3e5861613c008e1e879939ebc4827d10cd50", - "offset": 2360, + "offset": 3269, "builtins": [ "range_check" ] }, { "selector": "0x382be990ca34815134e64a9ac28f41a907c62e5ad10547f97174362ab94dc89", - "offset": 3768, + "offset": 4977, "builtins": [ "range_check" ] }, { "selector": "0x38be5d5f7bf135b52888ba3e440a457d11107aca3f6542e574b016bf3f074d8", - "offset": 3872, + "offset": 5087, "builtins": [ "range_check", "bitwise" ] }, + { + "selector": "0x39a1491f76903a16feed0a6433bec78de4c73194944e1118e226820ad479701", + "offset": 8113, + "builtins": [ + "range_check" + ] + }, { "selector": "0x3a6a8bae4c51d5959683ae246347ffdd96aa5b2bfa68cc8c3a6a7c2ed0be331", - "offset": 2625, + "offset": 3557, "builtins": [ "range_check" ] @@ -38621,9 +44009,17 @@ "range_check" ] }, + { + "selector": "0x3b756ccfc32a375b48e673ccd8447bcb3fc271415d0b92a7fb837747606c1f8", + "offset": 8330, + "builtins": [ + "range_check", + "bitwise" + ] + }, { "selector": "0x3d3da80997f8be5d16e9ae7ee6a4b5f7191d60765a1a6c219ab74269c85cf97", - "offset": 6187, + "offset": 7560, "builtins": [ "range_check", "range_check96", @@ -38633,14 +44029,14 @@ }, { "selector": "0x3d95049b565ec2d4197a55108ef03996381d31c84acf392a0a42b28163d69d1", - "offset": 3985, + "offset": 5206, "builtins": [ "range_check" ] }, { "selector": "0x3eb640b15f75fcc06d43182cdb94ed38c8e71755d5fb57c16dd673b466db1d4", - "offset": 4511, + "offset": 5767, "builtins": [ "range_check" ] @@ -38649,14 +44045,14 @@ "L1_HANDLER": [ { "selector": "0x205500a208d0d49d79197fea83cc3f5fde99ac2e1909ae0a5d9f394c0c52ed0", - "offset": 6838, + "offset": 8956, "builtins": [ "range_check" ] }, { "selector": "0x39edbbb129ad752107a94d40c3873cae369a46fd2fc578d075679aa67e85d12", - "offset": 6702, + "offset": 8810, "builtins": [ "range_check" ] @@ -38665,7 +44061,7 @@ "CONSTRUCTOR": [ { "selector": "0x28ffe4ff0f226a9107253e17a904099aa4f63a02a5621de0576e5aa71bc5194", - "offset": 7063, + "offset": 9200, "builtins": [ "range_check" ] diff --git a/crates/blockifier_test_utils/resources/feature_contracts/cairo1/compiled/test_contract_execution_info_v1.casm.json b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/compiled/test_contract_execution_info_v1.casm.json new file mode 100644 index 00000000000..2af9f181247 --- /dev/null +++ b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/compiled/test_contract_execution_info_v1.casm.json @@ -0,0 +1,2414 @@ +{ + "prime": "0x800000000000011000000000000000000000000000000000000000000000001", + "compiler_version": "2.11.0", + "bytecode": [ + "0xa0680017fff8000", + "0x7", + "0x482680017ffa8000", + "0xffffffffffffffffffffffffffffccfc", + "0x400280007ff97fff", + "0x10780017fff7fff", + "0x1ad", + "0x4825800180007ffa", + "0x3304", + "0x400280007ff97fff", + "0x482680017ff98000", + "0x1", + "0x48127ffe7fff8000", + "0x48297ffc80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xb", + "0x48127ffe7fff8000", + "0x482680017ffc8000", + "0x1", + "0x480a7ffd7fff8000", + "0x480680017fff8000", + "0x0", + "0x480a7ffc7fff8000", + "0x10780017fff7fff", + "0x9", + "0x48127ffe7fff8000", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x20680017fff7ffe", + "0x17f", + "0x480080007fff8000", + "0x48127ffa7fff8000", + "0xa0680017fff8000", + "0x12", + "0x4824800180007ffd", + "0x10000000000000000", + "0x4844800180008002", + "0x8000000000000110000000000000000", + "0x4830800080017ffe", + "0x480080007ff27fff", + "0x482480017ffe8000", + "0xefffffffffffffdeffffffffffffffff", + "0x480080017ff07fff", + "0x400080027fef7ffb", + "0x402480017fff7ffb", + "0xffffffffffffffffffffffffffffffff", + "0x20680017fff7fff", + "0x167", + "0x402780017fff7fff", + "0x1", + "0x400080007ff57ffd", + "0x482480017ffd8000", + "0xffffffffffffffff0000000000000000", + "0x400080017ff47fff", + "0x482480017ff48000", + "0x2", + "0x48127ffc7fff8000", + "0x48307ff680007ff7", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xb", + "0x48127ffe7fff8000", + "0x482480017ff48000", + "0x1", + "0x48127ff47fff8000", + "0x480680017fff8000", + "0x0", + "0x48127ff17fff8000", + "0x10780017fff7fff", + "0x9", + "0x48127ffe7fff8000", + "0x48127ff47fff8000", + "0x48127ff47fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x20680017fff7ffe", + "0x136", + "0x480080007fff8000", + "0x48127ffa7fff8000", + "0xa0680017fff8000", + "0x12", + "0x4824800180007ffd", + "0x10000000000000000", + "0x4844800180008002", + "0x8000000000000110000000000000000", + "0x4830800080017ffe", + "0x480080007ff27fff", + "0x482480017ffe8000", + "0xefffffffffffffdeffffffffffffffff", + "0x480080017ff07fff", + "0x400080027fef7ffb", + "0x402480017fff7ffb", + "0xffffffffffffffffffffffffffffffff", + "0x20680017fff7fff", + "0x11e", + "0x402780017fff7fff", + "0x1", + "0x400080007ff57ffd", + "0x482480017ffd8000", + "0xffffffffffffffff0000000000000000", + "0x400080017ff47fff", + "0x482480017ff48000", + "0x2", + "0x48127ffc7fff8000", + "0x48307ff680007ff7", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xb", + "0x48127ffe7fff8000", + "0x482480017ff48000", + "0x1", + "0x48127ff47fff8000", + "0x480680017fff8000", + "0x0", + "0x480080007ff18000", + "0x10780017fff7fff", + "0x9", + "0x48127ffe7fff8000", + "0x48127ff47fff8000", + "0x48127ff47fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x20680017fff7ffe", + "0xed", + "0x48127ffb7fff8000", + "0xa0680017fff8004", + "0xe", + "0x4824800180047ffd", + "0x800000000000000000000000000000000000000000000000000000000000000", + "0x484480017ffe8000", + "0x110000000000000000", + "0x48307ffe7fff8002", + "0x480080007ff37ffc", + "0x480080017ff27ffc", + "0x402480017ffb7ffd", + "0xffffffffffffffeeffffffffffffffff", + "0x400080027ff17ffd", + "0x10780017fff7fff", + "0xd8", + "0x484480017fff8001", + "0x8000000000000000000000000000000", + "0x48307fff80007ffc", + "0x480080007ff47ffd", + "0x480080017ff37ffd", + "0x402480017ffc7ffe", + "0xf8000000000000000000000000000000", + "0x400080027ff27ffe", + "0x482480017ff28000", + "0x3", + "0x48127ff57fff8000", + "0x48127ff57fff8000", + "0x1104800180018000", + "0x11f", + "0x48127fa07fff8000", + "0x20680017fff7ff3", + "0xbe", + "0x48127fff7fff8000", + "0x20680017fff7ff5", + "0xac", + "0x48127fff7fff8000", + "0x48307ff280007ff3", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x97", + "0x482480017ff18000", + "0x1", + "0x48127ff17fff8000", + "0x48127ffc7fff8000", + "0x480080007fee8000", + "0x48307ffc80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x7e", + "0x482480017ffb8000", + "0x1", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x480080007ff88000", + "0x48307ffc80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x65", + "0x482480017ffb8000", + "0x1", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x480080007ff88000", + "0x48307ffc80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x11", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", + "0x400080007ffe7fff", + "0x48127fde7fff8000", + "0x482480017ffa8000", + "0x492", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x1104800180018000", + "0x4e7", + "0x482480017fff8000", + "0x4e6", + "0x48127ffa7fff8000", + "0x480080007ffe8000", + "0xa0680017fff8000", + "0x9", + "0x4824800180007ffd", + "0x569a", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400080007fd87fff", + "0x10780017fff7fff", + "0x2e", + "0x4824800180007ffd", + "0x569a", + "0x400080007fd97fff", + "0x482480017fd98000", + "0x1", + "0x48127ffe7fff8000", + "0x480a7ffb7fff8000", + "0x48127f6b7fff8000", + "0x48127f767fff8000", + "0x48127f807fff8000", + "0x48127fd87fff8000", + "0x48127fd87fff8000", + "0x48127fd87fff8000", + "0x48127fd87fff8000", + "0x48127fd87fff8000", + "0x48127fd87fff8000", + "0x48127fd87fff8000", + "0x48127fd87fff8000", + "0x48127fdf7fff8000", + "0x48127fe37fff8000", + "0x48127fe77fff8000", + "0x1104800180018000", + "0x23e", + "0x20680017fff7ffd", + "0xc", + "0x40780017fff7fff", + "0x1", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x480680017fff8000", + "0x0", + "0x48127ffb7fff8000", + "0x48127ffa7fff8000", + "0x208b7fff7fff7ffe", + "0x48127ffa7fff8000", + "0x482480017ffa8000", + "0x64", + "0x48127ffa7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x482480017fd68000", + "0x1", + "0x48127ff87fff8000", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4661696c656420746f20646573657269616c697a6520706172616d202337", + "0x400080007ffe7fff", + "0x48127fe37fff8000", + "0x482480017ffa8000", + "0x686", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4661696c656420746f20646573657269616c697a6520706172616d202336", + "0x400080007ffe7fff", + "0x48127fe87fff8000", + "0x482480017ffa8000", + "0x8de", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4661696c656420746f20646573657269616c697a6520706172616d202335", + "0x400080007ffe7fff", + "0x48127fed7fff8000", + "0x482480017ffb8000", + "0xb36", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4661696c656420746f20646573657269616c697a6520706172616d202334", + "0x400080007ffe7fff", + "0x48127fef7fff8000", + "0x482480017ffc8000", + "0xcc6", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x48127ff27fff8000", + "0x482480017ffe8000", + "0xeba", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x208b7fff7fff7ffe", + "0x482480017ff18000", + "0x3", + "0x482480017ff88000", + "0x3c8c", + "0x10780017fff7fff", + "0x5", + "0x48127ff87fff8000", + "0x482480017ffa8000", + "0x41aa", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4661696c656420746f20646573657269616c697a6520706172616d202333", + "0x400080007ffe7fff", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x482480017fef8000", + "0x3", + "0x482480017ff78000", + "0x42f4", + "0x10780017fff7fff", + "0x5", + "0x48127ff87fff8000", + "0x482480017ffa8000", + "0x48da", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4661696c656420746f20646573657269616c697a6520706172616d202332", + "0x400080007ffe7fff", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x482480017fef8000", + "0x3", + "0x482480017ff78000", + "0x4a24", + "0x10780017fff7fff", + "0x5", + "0x48127ff87fff8000", + "0x482480017ffa8000", + "0x500a", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4661696c656420746f20646573657269616c697a6520706172616d202331", + "0x400080007ffe7fff", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x482680017ff98000", + "0x1", + "0x482680017ffa8000", + "0x21b6", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x48297ffc80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x161", + "0x482680017ffc8000", + "0x1", + "0x480a7ffd7fff8000", + "0x480280007ffc8000", + "0x48307ffd80007ffe", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xa", + "0x482480017ffc8000", + "0x1", + "0x48127ffc7fff8000", + "0x480680017fff8000", + "0x0", + "0x480080007ff98000", + "0x10780017fff7fff", + "0x8", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x20680017fff7ffe", + "0x12e", + "0xa0680017fff8004", + "0xe", + "0x4824800180047ffe", + "0x800000000000000000000000000000000000000000000000000000000000000", + "0x484480017ffe8000", + "0x110000000000000000", + "0x48307ffe7fff8002", + "0x480280007ffb7ffc", + "0x480280017ffb7ffc", + "0x402480017ffb7ffd", + "0xffffffffffffffeeffffffffffffffff", + "0x400280027ffb7ffd", + "0x10780017fff7fff", + "0x11a", + "0x484480017fff8001", + "0x8000000000000000000000000000000", + "0x48307fff80007ffd", + "0x480280007ffb7ffd", + "0x480280017ffb7ffd", + "0x402480017ffc7ffe", + "0xf8000000000000000000000000000000", + "0x400280027ffb7ffe", + "0x482680017ffb8000", + "0x3", + "0x48307ff680007ff7", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xa", + "0x482480017ff58000", + "0x1", + "0x48127ff57fff8000", + "0x480680017fff8000", + "0x0", + "0x48127ff27fff8000", + "0x10780017fff7fff", + "0x8", + "0x48127ff57fff8000", + "0x48127ff57fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x20680017fff7ffe", + "0xe1", + "0x480080007fff8000", + "0xa0680017fff8000", + "0x16", + "0x480080007ff88003", + "0x480080017ff78003", + "0x4844800180017ffe", + "0x100000000000000000000000000000000", + "0x483080017ffd7ffb", + "0x482480017fff7ffd", + "0x800000000000010fffffffffffffffff7ffffffffffffef0000000000000001", + "0x20680017fff7ffc", + "0x6", + "0x402480017fff7ffd", + "0xffffffffffffffffffffffffffffffff", + "0x10780017fff7fff", + "0x4", + "0x402480017ffe7ffd", + "0xf7ffffffffffffef0000000000000000", + "0x400080027ff37ffd", + "0x20680017fff7ffe", + "0xc6", + "0x402780017fff7fff", + "0x1", + "0x400080007ff87ffe", + "0x482480017ff88000", + "0x1", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x1104800180018000", + "0x267", + "0x20680017fff7ffa", + "0xa1", + "0x20680017fff7ffd", + "0x85", + "0x48307ffb80007ffc", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x66", + "0x482480017ffa8000", + "0x1", + "0x48127ffa7fff8000", + "0x480080007ff88000", + "0x48307ffd80007ffe", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x43", + "0x482480017ffc8000", + "0x1", + "0x48127ffc7fff8000", + "0x480080007ffa8000", + "0x48307ffd80007ffe", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xa", + "0x482480017ffc8000", + "0x1", + "0x48127ffc7fff8000", + "0x480680017fff8000", + "0x0", + "0x480080007ff98000", + "0x10780017fff7fff", + "0x8", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x20680017fff7ffe", + "0x12", + "0x48127fec7fff8000", + "0x480680017fff8000", + "0x0", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x480680017fff8000", + "0x0", + "0x48127fb67fff8000", + "0x48127fba7fff8000", + "0x48127fc57fff8000", + "0x48127fe97fff8000", + "0x48127fe97fff8000", + "0x48127fec7fff8000", + "0x48127fef7fff8000", + "0x48127ff37fff8000", + "0x208b7fff7fff7ffe", + "0x48127fec7fff8000", + "0x480680017fff8000", + "0x0", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x8", + "0x48127fec7fff8000", + "0x480680017fff8000", + "0x0", + "0x48127ff27fff8000", + "0x48127ff27fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0xc", + "0x48127fec7fff8000", + "0x480680017fff8000", + "0x0", + "0x48127fec7fff8000", + "0x48127fec7fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0xd", + "0x48127fec7fff8000", + "0x480680017fff8000", + "0x0", + "0x48127fec7fff8000", + "0x48127fec7fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0xd", + "0x48127fec7fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x48127fe67fff8000", + "0x48127fe67fff8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x2d", + "0x482480017fc68000", + "0x3", + "0x10780017fff7fff", + "0x5", + "0x40780017fff7fff", + "0x34", + "0x48127fc67fff8000", + "0x480680017fff8000", + "0x0", + "0x48127fc67fff8000", + "0x48127fc67fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x39", + "0x482680017ffb8000", + "0x3", + "0x10780017fff7fff", + "0x5", + "0x40780017fff7fff", + "0x3f", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x0", + "0x48127fbb7fff8000", + "0x48127fbb7fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x47", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x0", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x7", + "0x480680017fff8000", + "0x476574457865637574696f6e496e666f", + "0x400280007fef7fff", + "0x400380017fef7fee", + "0x480280037fef8000", + "0x20680017fff7fff", + "0x13e", + "0x480280027fef8000", + "0x480280047fef8000", + "0x480080007fff8000", + "0x480080007fff8000", + "0x402780017fef8001", + "0x5", + "0x48127ffc7fff8000", + "0x480080017ffc8000", + "0x400180027ffb8004", + "0x400180037ffb8003", + "0x400180047ffb8002", + "0x480080017ffc8000", + "0x480080027ffb8000", + "0x48287ff080007ffb", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x11", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x424c4f434b5f4e554d4245525f4d49534d41544348", + "0x400080007ffe7fff", + "0x480a7fed7fff8000", + "0x482480017ff88000", + "0x1dd8", + "0x480a80017fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x48127ffb7fff8000", + "0x48287ff180007ffc", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x11", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x424c4f434b5f54494d455354414d505f4d49534d41544348", + "0x400080007ffe7fff", + "0x480a7fed7fff8000", + "0x482480017ffb8000", + "0x1c48", + "0x480a80017fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x48287ff280007ffc", + "0x48127ffd7fff8000", + "0x20680017fff7ffe", + "0xf5", + "0x480080007ff88000", + "0x48287ff380007fff", + "0x48127ffd7fff8000", + "0x480080017ff58000", + "0x480080027ff48000", + "0x480080037ff38000", + "0x480080047ff28000", + "0x400180057ff18000", + "0x400180067ff18006", + "0x400180077ff18005", + "0x20680017fff7ffa", + "0xda", + "0x48287ff480007ffc", + "0x48127ffa7fff8000", + "0x20680017fff7ffe", + "0xc7", + "0x48127fff7fff8000", + "0x48287ff580007ffa", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x11", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x54585f494e464f5f4d41585f4645455f4d49534d41544348", + "0x400080007ffe7fff", + "0x480a7fed7fff8000", + "0x482480017ffb8000", + "0x1432", + "0x480a80017fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x48307ffa80007ffb", + "0x48297ff680007ff7", + "0x48127ffc7fff8000", + "0x48307ffe80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x7", + "0x480a7fed7fff8000", + "0x482480017ffd8000", + "0x10ae", + "0x10780017fff7fff", + "0x12", + "0x480a7fed7fff8000", + "0x48127ffd7fff8000", + "0x48127ff47fff8000", + "0x48127ff47fff8000", + "0x480a7ff67fff8000", + "0x480a7ff77fff8000", + "0x1104800180018000", + "0x18e", + "0x20680017fff7ffa", + "0x92", + "0x48127ff97fff8000", + "0x20680017fff7ffe", + "0x13", + "0x48127ff77fff8000", + "0x482480017ffe8000", + "0x640", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x54585f494e464f5f5349474e41545552455f4d49534d41544348", + "0x400080007ffe7fff", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", + "0x480a80017fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x48297ff880008000", + "0x48127ffe7fff8000", + "0x20680017fff7ffe", + "0x6b", + "0x48297ff980008006", + "0x48127ffe7fff8000", + "0x20680017fff7ffe", + "0x58", + "0x48297ffa80008005", + "0x48127ffe7fff8000", + "0x20680017fff7ffe", + "0x45", + "0x48297ffb80008004", + "0x48127ffe7fff8000", + "0x20680017fff7ffe", + "0x32", + "0x48297ffc80008003", + "0x48127ffe7fff8000", + "0x20680017fff7ffe", + "0x1f", + "0x48297ffd80008002", + "0x48127ffe7fff8000", + "0x20680017fff7ffe", + "0xd", + "0x48127feb7fff8000", + "0x482480017ffe8000", + "0x12c", + "0x480a80017fff8000", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x53454c4543544f525f4d49534d41544348", + "0x400080007ffe7fff", + "0x48127fe97fff8000", + "0x48127ffc7fff8000", + "0x480a80017fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x434f4e54524143545f4d49534d41544348", + "0x400080007ffe7fff", + "0x48127feb7fff8000", + "0x482480017ffc8000", + "0x12c", + "0x480a80017fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x43414c4c45525f4d49534d41544348", + "0x400080007ffe7fff", + "0x48127fed7fff8000", + "0x482480017ffc8000", + "0x258", + "0x480a80017fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x54585f494e464f5f4e4f4e43455f4d49534d41544348", + "0x400080007ffe7fff", + "0x48127fef7fff8000", + "0x482480017ffc8000", + "0x384", + "0x480a80017fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x54585f494e464f5f434841494e5f49445f4d49534d41544348", + "0x400080007ffe7fff", + "0x48127ff17fff8000", + "0x482480017ffc8000", + "0x4b0", + "0x480a80017fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x54585f494e464f5f484153485f4d49534d41544348", + "0x400080007ffe7fff", + "0x48127ff37fff8000", + "0x482480017ffc8000", + "0x5dc", + "0x480a80017fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x48127ff87fff8000", + "0x482480017ff88000", + "0x8fc", + "0x480a80017fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4143434f554e545f435f414444524553535f4d49534d41544348", + "0x400080007ffe7fff", + "0x480a7fed7fff8000", + "0x482480017ffc8000", + "0x155e", + "0x480a80017fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x54585f494e464f5f56455253494f4e5f4d49534d41544348", + "0x400080007ffe7fff", + "0x480a7fed7fff8000", + "0x482480017ff88000", + "0x168a", + "0x480a80017fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x53455155454e4345525f4d49534d41544348", + "0x400080007ffe7fff", + "0x480a7fed7fff8000", + "0x482480017ffc8000", + "0x1ab8", + "0x480a80017fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x480280027fef8000", + "0x480a7fed7fff8000", + "0x482480017ffe8000", + "0x23f0", + "0x482680017fef8000", + "0x6", + "0x480680017fff8000", + "0x1", + "0x480280047fef8000", + "0x480280057fef8000", + "0x208b7fff7fff7ffe", + "0x48297ffc80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xa", + "0x482680017ffc8000", + "0x1", + "0x480a7ffd7fff8000", + "0x480680017fff8000", + "0x0", + "0x480a7ffc7fff8000", + "0x10780017fff7fff", + "0x8", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x20680017fff7ffe", + "0x98", + "0x480080007fff8000", + "0xa0680017fff8000", + "0x12", + "0x4824800180007ffe", + "0x100000000", + "0x4844800180008002", + "0x8000000000000110000000000000000", + "0x4830800080017ffe", + "0x480280007ffb7fff", + "0x482480017ffe8000", + "0xefffffffffffffde00000000ffffffff", + "0x480280017ffb7fff", + "0x400280027ffb7ffb", + "0x402480017fff7ffb", + "0xffffffffffffffffffffffffffffffff", + "0x20680017fff7fff", + "0x78", + "0x402780017fff7fff", + "0x1", + "0x400280007ffb7ffe", + "0x482480017ffe8000", + "0xffffffffffffffffffffffff00000000", + "0x400280017ffb7fff", + "0x480680017fff8000", + "0x0", + "0x48307ff880007ff9", + "0x48307ffb7ffe8000", + "0xa0680017fff8000", + "0x8", + "0x482480017ffd8000", + "0x1", + "0x48307fff80007ffd", + "0x400280027ffb7fff", + "0x10780017fff7fff", + "0x51", + "0x48307ffe80007ffd", + "0x400280027ffb7fff", + "0x48307ff480007ff5", + "0x48307ffa7ff38000", + "0x48307ffb7ff28000", + "0x48307ff580017ffd", + "0xa0680017fff7fff", + "0x7", + "0x482480017fff8000", + "0x100000000000000000000000000000000", + "0x400280037ffb7fff", + "0x10780017fff7fff", + "0x2f", + "0x400280037ffb7fff", + "0x48307fef80007ff0", + "0x48307ffe7ff28000", + "0xa0680017fff8000", + "0x8", + "0x482480017ffd8000", + "0x1", + "0x48307fff80007ffd", + "0x400280047ffb7fff", + "0x10780017fff7fff", + "0x11", + "0x48307ffe80007ffd", + "0x400280047ffb7fff", + "0x40780017fff7fff", + "0x3", + "0x482680017ffb8000", + "0x5", + "0x480680017fff8000", + "0x0", + "0x48307fea7fe68000", + "0x48307ff77fe58000", + "0x480680017fff8000", + "0x0", + "0x48127ff07fff8000", + "0x48127ff07fff8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x496e646578206f7574206f6620626f756e6473", + "0x400080007ffe7fff", + "0x482680017ffb8000", + "0x5", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x4", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x7533325f737562204f766572666c6f77", + "0x400080007ffe7fff", + "0x482680017ffb8000", + "0x4", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x9", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x496e646578206f7574206f6620626f756e6473", + "0x400080007ffe7fff", + "0x482680017ffb8000", + "0x3", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x48127ff97fff8000", + "0x482480017ff88000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0xc", + "0x482680017ffb8000", + "0x3", + "0x480680017fff8000", + "0x0", + "0x48127fe67fff8000", + "0x48127fe67fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x14", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x0", + "0x48127fe67fff8000", + "0x48127fe67fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x208b7fff7fff7ffe", + "0xa0680017fff8000", + "0x7", + "0x482680017ff98000", + "0xfffffffffffffffffffffffffffff33a", + "0x400280007ff87fff", + "0x10780017fff7fff", + "0x63", + "0x4825800180007ff9", + "0xcc6", + "0x400280007ff87fff", + "0x482680017ff88000", + "0x1", + "0x48127ffe7fff8000", + "0x48297ffa80007ffb", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0xb", + "0x48127ffe7fff8000", + "0x482680017ffa8000", + "0x1", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x0", + "0x480a7ffa7fff8000", + "0x10780017fff7fff", + "0x9", + "0x48127ffe7fff8000", + "0x480a7ffa7fff8000", + "0x480a7ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x20680017fff7ffe", + "0x3a", + "0x48127ffb7fff8000", + "0x480080007ffe8000", + "0x48297ffc80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x1f", + "0x480280007ffc8000", + "0x48307fff80007ffd", + "0x48127ffb7fff8000", + "0x482680017ffc8000", + "0x1", + "0x480a7ffd7fff8000", + "0x20680017fff7ffc", + "0xb", + "0x48127ff07fff8000", + "0x48127ffc7fff8000", + "0x48127ff27fff8000", + "0x48127ff27fff8000", + "0x48127ffa7fff8000", + "0x48127ffa7fff8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffc8", + "0x208b7fff7fff7ffe", + "0x48127ff07fff8000", + "0x482480017ffc8000", + "0x622", + "0x480680017fff8000", + "0x0", + "0x48127ff17fff8000", + "0x48127ff17fff8000", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x480680017fff8000", + "0x0", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x400080007ffe7fff", + "0x48127ff37fff8000", + "0x482480017ffa8000", + "0x6ea", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x48127ff87fff8000", + "0x482480017ff78000", + "0x1", + "0x208b7fff7fff7ffe", + "0x48127ff87fff8000", + "0x482480017ffa8000", + "0xa0a", + "0x480680017fff8000", + "0x0", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", + "0x480680017fff8000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4f7574206f6620676173", + "0x400080007ffe7fff", + "0x482680017ff88000", + "0x1", + "0x480a7ff97fff8000", + "0x480680017fff8000", + "0x1", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x48127ff87fff8000", + "0x482480017ff78000", + "0x1", + "0x208b7fff7fff7ffe" + ], + "bytecode_segment_lengths": [ + 450, + 382, + 336, + 185, + 124 + ], + "hints": [ + [ + 0, + [ + { + "TestLessThanOrEqual": { + "lhs": { + "Immediate": "0x3304" + }, + "rhs": { + "Deref": { + "register": "FP", + "offset": -6 + } + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 38, + [ + { + "TestLessThan": { + "lhs": { + "BinOp": { + "op": "Add", + "a": { + "register": "AP", + "offset": -2 + }, + "b": { + "Immediate": "0x0" + } + } + }, + "rhs": { + "Immediate": "0x10000000000000000" + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 42, + [ + { + "LinearSplit": { + "value": { + "Deref": { + "register": "AP", + "offset": -1 + } + }, + "scalar": { + "Immediate": "0x8000000000000110000000000000000" + }, + "max_x": { + "Immediate": "0xfffffffffffffffffffffffffffffffe" + }, + "x": { + "register": "AP", + "offset": 0 + }, + "y": { + "register": "AP", + "offset": 1 + } + } + } + ] + ], + [ + 88, + [ + { + "TestLessThan": { + "lhs": { + "BinOp": { + "op": "Add", + "a": { + "register": "AP", + "offset": -2 + }, + "b": { + "Immediate": "0x0" + } + } + }, + "rhs": { + "Immediate": "0x10000000000000000" + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 92, + [ + { + "LinearSplit": { + "value": { + "Deref": { + "register": "AP", + "offset": -1 + } + }, + "scalar": { + "Immediate": "0x8000000000000110000000000000000" + }, + "max_x": { + "Immediate": "0xfffffffffffffffffffffffffffffffe" + }, + "x": { + "register": "AP", + "offset": 0 + }, + "y": { + "register": "AP", + "offset": 1 + } + } + } + ] + ], + [ + 137, + [ + { + "TestLessThan": { + "lhs": { + "Deref": { + "register": "AP", + "offset": -2 + } + }, + "rhs": { + "Immediate": "0x800000000000000000000000000000000000000000000000000000000000000" + }, + "dst": { + "register": "AP", + "offset": 4 + } + } + } + ] + ], + [ + 141, + [ + { + "LinearSplit": { + "value": { + "Deref": { + "register": "AP", + "offset": 3 + } + }, + "scalar": { + "Immediate": "0x110000000000000000" + }, + "max_x": { + "Immediate": "0xffffffffffffffffffffffffffffffff" + }, + "x": { + "register": "AP", + "offset": -2 + }, + "y": { + "register": "AP", + "offset": -1 + } + } + } + ] + ], + [ + 151, + [ + { + "LinearSplit": { + "value": { + "Deref": { + "register": "AP", + "offset": -3 + } + }, + "scalar": { + "Immediate": "0x8000000000000000000000000000000" + }, + "max_x": { + "Immediate": "0xffffffffffffffffffffffffffffffff" + }, + "x": { + "register": "AP", + "offset": -1 + }, + "y": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 207, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 228, + [ + { + "TestLessThanOrEqual": { + "lhs": { + "Immediate": "0x569a" + }, + "rhs": { + "Deref": { + "register": "AP", + "offset": -2 + } + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 262, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 281, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 296, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 311, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 326, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 341, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 374, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 397, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 420, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 434, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 480, + [ + { + "TestLessThan": { + "lhs": { + "Deref": { + "register": "AP", + "offset": -1 + } + }, + "rhs": { + "Immediate": "0x800000000000000000000000000000000000000000000000000000000000000" + }, + "dst": { + "register": "AP", + "offset": 4 + } + } + } + ] + ], + [ + 484, + [ + { + "LinearSplit": { + "value": { + "Deref": { + "register": "AP", + "offset": 3 + } + }, + "scalar": { + "Immediate": "0x110000000000000000" + }, + "max_x": { + "Immediate": "0xffffffffffffffffffffffffffffffff" + }, + "x": { + "register": "AP", + "offset": -2 + }, + "y": { + "register": "AP", + "offset": -1 + } + } + } + ] + ], + [ + 494, + [ + { + "LinearSplit": { + "value": { + "Deref": { + "register": "AP", + "offset": -2 + } + }, + "scalar": { + "Immediate": "0x8000000000000000000000000000000" + }, + "max_x": { + "Immediate": "0xffffffffffffffffffffffffffffffff" + }, + "x": { + "register": "AP", + "offset": -1 + }, + "y": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 526, + [ + { + "TestLessThan": { + "lhs": { + "Deref": { + "register": "AP", + "offset": -1 + } + }, + "rhs": { + "Immediate": "0x100000000000000000000000000000000" + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 528, + [ + { + "DivMod": { + "lhs": { + "Deref": { + "register": "AP", + "offset": -2 + } + }, + "rhs": { + "Immediate": "0x100000000000000000000000000000000" + }, + "quotient": { + "register": "AP", + "offset": 3 + }, + "remainder": { + "register": "AP", + "offset": 4 + } + } + } + ] + ], + [ + 838, + [ + { + "SystemCall": { + "system": { + "Deref": { + "register": "FP", + "offset": -17 + } + } + } + } + ] + ], + [ + 859, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 880, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 921, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 965, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1014, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1028, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1043, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1058, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1073, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1088, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1112, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1127, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1142, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1190, + [ + { + "TestLessThan": { + "lhs": { + "BinOp": { + "op": "Add", + "a": { + "register": "AP", + "offset": -1 + }, + "b": { + "Immediate": "0x0" + } + } + }, + "rhs": { + "Immediate": "0x100000000" + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1194, + [ + { + "LinearSplit": { + "value": { + "Deref": { + "register": "AP", + "offset": -1 + } + }, + "scalar": { + "Immediate": "0x8000000000000110000000000000000" + }, + "max_x": { + "Immediate": "0xfffffffffffffffffffffffffffffffe" + }, + "x": { + "register": "AP", + "offset": 0 + }, + "y": { + "register": "AP", + "offset": 1 + } + } + } + ] + ], + [ + 1216, + [ + { + "TestLessThanOrEqual": { + "lhs": { + "Deref": { + "register": "AP", + "offset": -1 + } + }, + "rhs": { + "Deref": { + "register": "AP", + "offset": -2 + } + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1230, + [ + { + "TestLessThan": { + "lhs": { + "Deref": { + "register": "AP", + "offset": 0 + } + }, + "rhs": { + "Immediate": "0x100000000" + }, + "dst": { + "register": "AP", + "offset": -1 + } + } + } + ] + ], + [ + 1240, + [ + { + "TestLessThanOrEqual": { + "lhs": { + "Deref": { + "register": "AP", + "offset": -1 + } + }, + "rhs": { + "Deref": { + "register": "AP", + "offset": -2 + } + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1263, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1284, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1305, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1353, + [ + { + "TestLessThanOrEqual": { + "lhs": { + "Immediate": "0xcc6" + }, + "rhs": { + "Deref": { + "register": "FP", + "offset": -7 + } + }, + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1425, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 1457, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 0 + } + } + } + ] + ] + ], + "entry_points_by_type": { + "EXTERNAL": [ + { + "selector": "0x3c118a68e16e12e97ed25cb4901c12f4d3162818669cc44c391d8049924c14", + "offset": 0, + "builtins": [ + "range_check" + ] + } + ], + "L1_HANDLER": [], + "CONSTRUCTOR": [] + } +} diff --git a/crates/blockifier/feature_contracts/cairo1/empty_contract.cairo b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/empty_contract.cairo similarity index 100% rename from crates/blockifier/feature_contracts/cairo1/empty_contract.cairo rename to crates/blockifier_test_utils/resources/feature_contracts/cairo1/empty_contract.cairo diff --git a/crates/blockifier/feature_contracts/cairo1/legacy_test_contract.cairo b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/legacy_test_contract.cairo similarity index 100% rename from crates/blockifier/feature_contracts/cairo1/legacy_test_contract.cairo rename to crates/blockifier_test_utils/resources/feature_contracts/cairo1/legacy_test_contract.cairo diff --git a/crates/blockifier_test_utils/resources/feature_contracts/cairo1/meta_tx_test_contract.cairo b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/meta_tx_test_contract.cairo new file mode 100644 index 00000000000..07f1d07896b --- /dev/null +++ b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/meta_tx_test_contract.cairo @@ -0,0 +1,74 @@ +use starknet::ContractAddress; + +#[derive(Drop, starknet::Store)] +struct CallData { + caller_address: ContractAddress, + account_contract_address: ContractAddress, + tx_version: felt252, + argument: felt252, + transaction_hash: felt252, + signature: felt252, + max_fee: u128, + resource_bounds_len: usize, + nonce: felt252, +} + +#[starknet::contract] +mod MetaTxTestContract { + use starknet::storage::MutableVecTrait; + use starknet::ContractAddress; + use super::CallData; + + #[storage] + struct Storage { + call_data: starknet::storage::Vec::, + } + + #[generate_trait] + impl InternalFunctions of InternalFunctionsTrait { + fn add_call_info(ref self: ContractState, argument: felt252) { + let execution_info = starknet::get_execution_info().unbox(); + let tx_info = execution_info.tx_info.unbox(); + + let mut tx_signature = execution_info.tx_info.signature; + let signature = *tx_signature.pop_front().unwrap_or(@'NO_SIGNATURE'); + + let call_data = CallData { + caller_address: starknet::get_caller_address(), + account_contract_address: tx_info.account_contract_address, + tx_version: tx_info.version, + argument, + transaction_hash: tx_info.transaction_hash, + signature, + max_fee: tx_info.max_fee, + resource_bounds_len: tx_info.resource_bounds.len(), + nonce: tx_info.nonce, + }; + self.call_data.push(call_data); + } + } + + #[external(v0)] + fn foo(ref self: ContractState, argument: felt252) { + self.add_call_info(:argument); + } + + extern fn meta_tx_v0_syscall( + address: ContractAddress, + entry_point_selector: felt252, + calldata: Span, + signature: Span, + ) -> starknet::SyscallResult> implicits(GasBuiltin, System) nopanic; + + #[external(v0)] + fn execute_meta_tx_v0( + ref self: ContractState, + address: ContractAddress, + entry_point_selector: felt252, + calldata: Span, + signature: Span, + ) { + meta_tx_v0_syscall(:address, :entry_point_selector, :calldata, :signature).unwrap(); + self.add_call_info(argument: 'NO_ARGUMENT'); + } +} diff --git a/crates/blockifier_test_utils/resources/feature_contracts/cairo1/sierra/account_faulty.sierra.json b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/sierra/account_faulty.sierra.json new file mode 100644 index 00000000000..0bf08ee57fd --- /dev/null +++ b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/sierra/account_faulty.sierra.json @@ -0,0 +1,1355 @@ +{ + "sierra_program": [ + "0x1", + "0x7", + "0x0", + "0x2", + "0xb", + "0x0", + "0x209", + "0x1f7", + "0x43", + "0x52616e6765436865636b", + "0x800000000000000100000000000000000000000000000000", + "0x436f6e7374", + "0x800000000000000000000000000000000000000000000002", + "0x1", + "0x1e", + "0x2", + "0x556e6b6e6f776e207363656e6172696f", + "0x424c4f434b5f4e554d4245525f4d49534d41544348", + "0x424c4f434b5f54494d455354414d505f4d49534d41544348", + "0x53455155454e4345525f4d49534d41544348", + "0x753634", + "0x800000000000000700000000000000000000000000000000", + "0x436f6e747261637441646472657373", + "0x537472756374", + "0x800000000000000700000000000000000000000000000004", + "0x0", + "0x3808c701a5d13e100ab11b6c02f91f752ecae7e420d21b56c90ec0a475cc7e5", + "0x5", + "0x6", + "0x19", + "0x3", + "0x4", + "0x53746f7261676541646472657373", + "0xf", + "0x8", + "0x7c8", + "0x496e646578206f7574206f6620626f756e6473", + "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x1b1a0649752af1b28b3dc29a1556eee781e4a4c3a1f7f53f90fa834de098c4d", + "0x496e76616c6964207363656e6172696f", + "0x494e56414c4944", + "0x753332", + "0x4172726179", + "0x800000000000000300000000000000000000000000000001", + "0x1f", + "0x536e617073686f74", + "0x800000000000000700000000000000000000000000000001", + "0x1a", + "0x800000000000000700000000000000000000000000000002", + "0x1597b831feeb60c71f259624b79cf66995ea4f7e383403583674ab9c33b9cec", + "0x1b", + "0x75313238", + "0x66656c74323532", + "0x3342418ef16b3e2799b906b1e4e89dbb9b111332dd44f72458ce44f9895b508", + "0x1d", + "0x20", + "0x1baeba72e79e9db2587cf44fedb2f3700b2075a5e8e39a562584862c4b71f62", + "0x21", + "0x80000000000000070000000000000000000000000000000e", + "0x348a62b7a38c0673e61e888d83a3ac1bf334ee7361a8514593d3d9532ed8b39", + "0x22", + "0x1c", + "0x426f78", + "0x23", + "0x7", + "0x800000000000000700000000000000000000000000000006", + "0x7d4d99e9ed8d285b5c61b493cedb63976bc3d9da867933d829f49ce838b5e7", + "0x25", + "0x24", + "0x26", + "0x800000000000000f00000000000000000000000000000001", + "0x29a02530bac70a6d5878fc0c5cb42f1926cd91d9162685c15f1be12819caf78", + "0x556e696e697469616c697a6564", + "0x800000000000000200000000000000000000000000000001", + "0x2ee1e2b1b89f8c495f200e4956278a4d47395fe262f27b52e5865c9524c08c3", + "0x456e756d", + "0x800000000000000300000000000000000000000000000003", + "0x17b6ecc31946835b0d9d92c2dd7a9c14f29af0371571ae74a1b228828b2242", + "0x2b", + "0x2c", + "0x16a4c8d7c05909052238a862d8cc3e7975bf05a07b3a69c6b28951083a6d672", + "0x2e", + "0x34f9bd7c6cb2dd4263175964ad75f1ff1461ddc332fbfb274e0fb2a5d7ab968", + "0x2d", + "0x2f", + "0x800000000000000700000000000000000000000000000003", + "0x29d7d57c04a880978e7b3689f6218e507f3be17588744b58dc17762447ad0e7", + "0x31", + "0x11c6d8087e00642489f92d2821ad6ebd6532ad1a3b6d12833da6d6810391511", + "0x4661696c656420746f20646573657269616c697a6520706172616d202332", + "0x4661696c656420746f20646573657269616c697a6520706172616d202333", + "0x56414c4944", + "0x3288d594b9a45d15bb2fcb7903f06cdb06b27f0ba88186ec4cfaa98307cb972", + "0x4e6f6e5a65726f", + "0x4661696c656420746f20646573657269616c697a6520706172616d202331", + "0x4f7574206f6620676173", + "0x10203be321c62a7bd4c060d69539c1fbe065baa9e253c74d2cc48be163e259", + "0x3c", + "0x4275696c74696e436f737473", + "0x53797374656d", + "0x9931c641b913035ae674b400b61a51476d506bbe8bba2ff8a6272790aba9e6", + "0x3b", + "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", + "0x4761734275696c74696e", + "0x91", + "0x7265766f6b655f61705f747261636b696e67", + "0x77697468647261775f676173", + "0x6272616e63685f616c69676e", + "0x72656465706f7369745f676173", + "0x7374727563745f6465636f6e737472756374", + "0x73746f72655f74656d70", + "0x42", + "0x61727261795f736e617073686f745f706f705f66726f6e74", + "0x756e626f78", + "0x64726f70", + "0x61727261795f6e6577", + "0x636f6e73745f61735f696d6d656469617465", + "0x41", + "0x61727261795f617070656e64", + "0x7374727563745f636f6e737472756374", + "0x656e756d5f696e6974", + "0x40", + "0x3f", + "0x6765745f6275696c74696e5f636f737473", + "0x3e", + "0x77697468647261775f6761735f616c6c", + "0x66756e6374696f6e5f63616c6c", + "0x656e756d5f6d61746368", + "0x3d", + "0x736e617073686f745f74616b65", + "0x3a", + "0x39", + "0x72656e616d65", + "0x656e61626c655f61705f747261636b696e67", + "0x66656c743235325f69735f7a65726f", + "0x37", + "0x6a756d70", + "0x38", + "0x64697361626c655f61705f747261636b696e67", + "0x626f6f6c5f6e6f745f696d706c", + "0x36", + "0x35", + "0x34", + "0x33", + "0x21adb5788e32c84f69a1863d85ef9394b7bf761a0ce1190f826984e5075c371", + "0x32", + "0x30", + "0x2a", + "0x73656e645f6d6573736167655f746f5f6c315f73797363616c6c", + "0x616c6c6f635f6c6f63616c", + "0x66696e616c697a655f6c6f63616c73", + "0x73746f72655f6c6f63616c", + "0x28", + "0x29", + "0x6765745f657865637574696f6e5f696e666f5f76325f73797363616c6c", + "0x27", + "0x647570", + "0x18", + "0x66656c743235325f737562", + "0x17", + "0x16", + "0x15", + "0x14", + "0x61727261795f676574", + "0x13", + "0x63616c6c5f636f6e74726163745f73797363616c6c", + "0x12", + "0x11", + "0x10", + "0x6765745f626c6f636b5f686173685f73797363616c6c", + "0xe", + "0xd", + "0x1ad5911ecb88aa4a50482c4de3232f196cfcaf7bd4e9c96d22b283733045007", + "0xb", + "0x73746f726167655f77726974655f73797363616c6c", + "0xc", + "0xa", + "0x9", + "0x7536345f746f5f66656c74323532", + "0x636f6e74726163745f616464726573735f746f5f66656c74323532", + "0x7a9", + "0xffffffffffffffff", + "0x61", + "0x52", + "0x44", + "0x45", + "0x13c", + "0x12d", + "0x11e", + "0x10f", + "0x96", + "0x9d", + "0xb0", + "0x100", + "0xcc", + "0xd1", + "0xdc", + "0x46", + "0x47", + "0xec", + "0x48", + "0x49", + "0x4a", + "0x4b", + "0x4c", + "0x4d", + "0xf8", + "0x4e", + "0x4f", + "0x50", + "0x51", + "0x53", + "0x54", + "0x55", + "0x56", + "0x57", + "0x58", + "0x59", + "0x5a", + "0x5b", + "0x5c", + "0x5d", + "0x5e", + "0x5f", + "0x60", + "0x62", + "0x63", + "0x64", + "0x65", + "0x66", + "0x67", + "0x68", + "0x69", + "0x6a", + "0x6b", + "0x6c", + "0x6d", + "0x6e", + "0x6f", + "0x70", + "0x71", + "0x72", + "0x73", + "0x74", + "0x75", + "0x76", + "0x77", + "0x78", + "0x79", + "0x7a", + "0x7b", + "0x7c", + "0x249", + "0x15d", + "0x164", + "0x236", + "0x230", + "0x221", + "0x17f", + "0x186", + "0x20e", + "0x206", + "0x1ff", + "0x1b0", + "0x1f0", + "0x1e1", + "0x1d8", + "0x1e8", + "0x7d", + "0x7e", + "0x7f", + "0x215", + "0x80", + "0x81", + "0x82", + "0x83", + "0x84", + "0x85", + "0x86", + "0x87", + "0x88", + "0x89", + "0x8a", + "0x8b", + "0x8c", + "0x8d", + "0x8e", + "0x8f", + "0x90", + "0x92", + "0x23d", + "0x93", + "0x94", + "0x95", + "0x97", + "0x98", + "0x99", + "0x9a", + "0x9b", + "0x9c", + "0x9e", + "0x9f", + "0xa0", + "0x354", + "0x26d", + "0x274", + "0x33f", + "0x338", + "0x327", + "0x290", + "0x297", + "0x312", + "0x308", + "0x2ff", + "0x2c3", + "0x2ee", + "0x2e6", + "0x31b", + "0x348", + "0x39f", + "0x37d", + "0x391", + "0x44a", + "0x43b", + "0x3c6", + "0x3cd", + "0x3e0", + "0x42c", + "0x3fc", + "0x401", + "0x40a", + "0x419", + "0x424", + "0x68c", + "0x67c", + "0x490", + "0x4bd", + "0x4ae", + "0x518", + "0x50a", + "0x4fb", + "0x4f0", + "0x540", + "0x535", + "0x599", + "0x58a", + "0x57b", + "0xa1", + "0xa2", + "0xa3", + "0xa4", + "0xa5", + "0xa6", + "0x570", + "0xa7", + "0xa8", + "0xa9", + "0xaa", + "0xab", + "0xac", + "0xad", + "0xae", + "0xaf", + "0xb1", + "0xb2", + "0xb3", + "0xb4", + "0xb5", + "0xb6", + "0xb7", + "0xb8", + "0xb9", + "0xba", + "0xbb", + "0xbc", + "0xbd", + "0xbe", + "0xbf", + "0xc0", + "0xc1", + "0xc2", + "0x66c", + "0xc3", + "0xc4", + "0xc5", + "0xc6", + "0xc7", + "0xc8", + "0xc9", + "0xca", + "0xcb", + "0x65d", + "0xcd", + "0xce", + "0xcf", + "0xd0", + "0xd2", + "0xd3", + "0xd4", + "0xd5", + "0x64d", + "0xd6", + "0xd7", + "0xd8", + "0xd9", + "0xda", + "0xdb", + "0xdd", + "0xde", + "0xdf", + "0x63d", + "0xe0", + "0xe1", + "0xe2", + "0xe3", + "0xe4", + "0xe5", + "0x62f", + "0xe6", + "0xe7", + "0xe8", + "0xe9", + "0xea", + "0xeb", + "0xed", + "0xee", + "0xef", + "0xf0", + "0xf1", + "0xf2", + "0xf3", + "0xf4", + "0xf5", + "0xf6", + "0x61c", + "0xf7", + "0xf9", + "0xfa", + "0xfb", + "0x60b", + "0xfc", + "0xfd", + "0xfe", + "0xff", + "0x5fc", + "0x101", + "0x102", + "0x103", + "0x104", + "0x105", + "0x106", + "0x107", + "0x108", + "0x109", + "0x10a", + "0x10b", + "0x10c", + "0x10d", + "0x10e", + "0x110", + "0x111", + "0x112", + "0x113", + "0x114", + "0x115", + "0x116", + "0x117", + "0x118", + "0x119", + "0x11a", + "0x11b", + "0x11c", + "0x11d", + "0x11f", + "0x120", + "0x121", + "0x122", + "0x123", + "0x124", + "0x125", + "0x126", + "0x127", + "0x128", + "0x129", + "0x12a", + "0x12b", + "0x12c", + "0x12e", + "0x12f", + "0x130", + "0x131", + "0x132", + "0x133", + "0x134", + "0x135", + "0x136", + "0x137", + "0x138", + "0x139", + "0x13a", + "0x13b", + "0x13d", + "0x13e", + "0x13f", + "0x140", + "0x141", + "0x142", + "0x143", + "0x144", + "0x145", + "0x6db", + "0x6a9", + "0x6b9", + "0x6c0", + "0x6cf", + "0x79d", + "0x78c", + "0x76b", + "0x75c", + "0x74d", + "0x742", + "0x781", + "0x14b", + "0x258", + "0x365", + "0x3ae", + "0x459", + "0x697", + "0x6eb", + "0x4014", + "0x60140400c0a01c060140400c0901c060140400c0801c060140400c0200400", + "0x5010030580705405010030500504c0504c05048110400f0340e0340c02c07", + "0x400c1901c060140400c0d0601101c150140400c1701c060140400c0701c15", + "0x50100307007018050100305807018050100306c0704c05010030680701805", + "0x60140400c0701c060140400c0501c150140400c1e01c060140400c1d01c06", + "0xf09c05098250900508c220342101407018050100308007018050100307c07", + "0x2609406014230882e01413014060142d0441003c0d0b00d0ac2a0142904428", + "0x501805018050d0050b80505005018050cc110c80f0c4050c0110a00f0bc05", + "0x3a0443903c38014260d837014260d8340141501415014340142e0143501406", + "0x50100301805104400fc110f80f0f405098360180505005050050f0050ec05", + "0x3e03c4701434014420444403c460142f014450444410c420443e03c1101c06", + "0x111344301805098361300512c0512811110430bc0512405108111100f12011", + "0x5201c060140400c5101c060140400c4601406014500444d10c460144f0144e", + "0x315807018050100301805098551180511805150111344314c070180501003", + "0x4c01459014580444410c06014420442803c34014420442803c5701c0601404", + "0x1118811184600085f178070180501003130051740517011110430085b0345a", + "0x6a0180501469018050146819c050146604405014660d005014650446404463", + "0x51986d014051b006014051ac4f014051a831014051a831014051980601405", + "0x661c80501466014071c40501c70130050146f124050146f018050146e01805", + "0x51e4590140519478014051dc14058051d8111d47401405198111cc7101405", + "0x6c1e8050146c044071c40501c70174050146f0d0050146f0bc050146a0bc05", + "0x501c7f014071c046014051bc111f8111f406014051f034014051a87b01405", + "0x79044831fc050146a04482044071fc0501c70204050146a044801fc0501466", + "0x71c086014051b085014051b084014051b046014051a87f014051dc7f01405", + "0x70050050146a0448821c05014770140721c0501c7021c05014660440721c05", + "0x5198340140519889014051dc0501c89014071c089014051981101c8901407", + "0x650448c22c050146c11c050147712c050146522805014770e016014760bc05", + "0x90014051e490014051bc060140523c11238060140523449014051a84c01405", + "0x50146604492164050146a244050146a06816014760500501466240050146a", + "0x370140519437014051a43c014051983b014051a83d014051943d014051a493", + "0x6f01805014940c4050147c0d00501479054050146a0d4050146a0b8050146a", + "0x51b097014051b01125895014051b078014051981101c78014071c05901405", + "0x66018050149b0540501466268050146c264050146c014071e00501c7026005", + "0x19014051b0a0014051b09f014051b09e014051b0112749c014051b04f01405", + "0x50146a044a6294050146c044a428c050146c288050146c044a104c0501466", + "0x38014051a43b014051983c014051a81a014051b0a9014051b0a8014051b0a7", + "0x6c01c050146c04c050146a058050146c05c050146c044ab044aa0e00501465", + "0x71c08a014051981101c8a014071c04b014051bc1101c47014071c00501405", + "0x72b4070141101c05044112b40504411044ac014072280501c700140711c05", + "0x50580505c11068052b40504c0505811044ad0141101c110e01401cae04c17", + "0xad01ca9014380441a014ad0141a0141404417014ad0141701413044a9014ad", + "0x5294050681128c052b4050680505811044ad0141101c1129c052bca52a007", + "0x52b40528c05050112a0052b4052a0052a011044ad014a2014a9044a2014ad", + "0xad01419014a5044112b405044070449f014242801901cad01ca801438044a3", + "0xa20449c014ad0141128c11278052b40528c0505811044ad014a0014a704411", + "0x1127c11264052b4052689c01ca00449a014ad0149a014190449a014ad01411", + "0x170141304495014ad014970149c04497014ad014992600727811260052b405", + "0x5254052641101c052b40501c0526811278052b405278050501105c052b405", + "0x505811044ad0149f014a5044112b405044070449501c9e05c1701495014ad", + "0x509c0525c11054052b405054050501109c052b4050449804415014ad014a3", + "0x11044ad0141101c110182e01cb00d42a01cad01c27054170589504427014ad", + "0x9a04424014ad01424014140442a014ad0142a0141304424014ad0143501416", + "0xad01c3701427044370d0310bc172b40501c240a8160541101c052b40501c05", + "0x52b405044a30443d014ad0143101416044112b405044070443b014590f005", + "0x72b405244050d411244052b4052409301ca004490014ad0143c0142a04493", + "0x4b014ad014470142404447014ad0144601406044112b40522c050b8111188b", + "0x110f4052b4050f405050110bc052b4050bc0504c11124052b40512c050bc11", + "0x504407044490d03d0bc1701449014ad014490149904434014ad014340149a", + "0x52b4050bc0504c11228052b4050ec0527011130052b4050c40505811044ad", + "0x8a014ad0148a0149904434014ad014340149a0444c014ad0144c014140442f", + "0xad0141128c1113c052b4050180505811044ad0141101c11228341302f05c05", + "0x52b40521c8901ca004487014ad014870141904487014ad014110c41122405", + "0x7f014ad014840149c04484014ad014862140727811214052b4050449f04486", + "0x1101c052b40501c052681113c052b40513c05050110b8052b4050b80504c11", + "0xad014a7014a5044112b405044070447f01c4f0b8170147f014ad0147f01499", + "0x190447a014ad014110d0111ec052b405044a304481014ad0141a0141604411", + "0x727811164052b4050449f0445d014ad0147a1ec07280111e8052b4051e805", + "0x50501105c052b40505c0504c111d0052b4051e005270111e0052b40517459", + "0x8105c1701474014ad014740149904407014ad014070149a04481014ad01481", + "0xa304472014ad0143801416044112b405058050dc11044ad0141101c111d007", + "0x6d1c407280111b4052b4051b405064111b4052b4050443104471014ad01411", + "0x52c005270112c0052b40519c0001c9e04400014ad0141127c1119c052b405", + "0xad014070149a04472014ad014720141404414014ad0141401413044b1014ad", + "0x701411044ad01411044112c4071c81405c052c4052b4052c4052641101c05", + "0x1a014ad0141301416044112b4050440704438050072c81305c072b40701411", + "0x11068052b405068050501105c052b40505c0504c112a4052b4050580505c11", + "0xa3014ad0141a01416044112b40504407044a7014b3294a801cad01ca901438", + "0x14044a8014ad014a8014a8044112b405288052a411288052b4052940506811", + "0x11044ad0141101c1127c052d0a0064072b4072a0050e01128c052b40528c05", + "0x52a011044ad0149c014a90449c014ad014a00141a0449e014ad014a301416", + "0x98014b52649a01cad01c19014380449e014ad0149e0141404419014ad01419", + "0x50f011254052b405264050681125c052b4052780505811044ad0141101c11", + "0xad0149a014a804415014ad0141501419044112b4050443b04415014ad01495", + "0xad0141101c1109c052d8112b407054050f41125c052b40525c050501126805", + "0x110b8052b4050d405240110d4052b405044930442a014ad014970141604411", + "0x504407044112dc050448b04424014ad0142e0149104406014ad0142a01414", + "0x110c4052b405044930442f014ad0149701416044112b40509c0511811044ad", + "0x3804424014ad014340149104406014ad0142f0141404434014ad0143101447", + "0x529411044ad0141112c11044ad0141101c110ec052e03c0dc072b40726805", + "0x52b4050180505811044ad0142401449044112b4050f00529c11044ad01437", + "0xa004490014ad014900141904490014ad014112881124c052b405044a30443d", + "0x9c04446014ad0149122c072781122c052b4050449f04491014ad0149024c07", + "0x5268110f4052b4050f4050501105c052b40505c0504c1111c052b40511805", + "0x112b405044070444701c3d05c1701447014ad014470149904407014ad01407", + "0x5044980444b014ad0140601416044112b4050ec0529411044ad0141112c11", + "0x4912c170589504449014ad01449014970444b014ad0144b0141404449014ad", + "0x9304487014ad0148a01416044112b405044070448913c072e48a130072b407", + "0x840148a04484014ad014240144c04485014ad014860144704486014ad01411", + "0x52b4052040524411044ad014110ec11044ad0147f01449044811fc072b405", + "0x85014ad014850149104487014ad01487014140444c014ad0144c0141304481", + "0x11044ad0147b01489044112b405044070447a014ba1ec052b4072040513c11", + "0x9104478014ad0145d0141404459014ad014850144c0445d014ad0148701416", + "0x112b4051e80522411044ad0141101c11044bb0141122c111d0052b40516405", + "0x111d0052b40521405244111e0052b4051c805050111c8052b40521c0505811", + "0x522411044ad0141112c11044ad0141101c111b4052f071014ad01c740144f", + "0xad0144c0141304400014ad0141121c1119c052b4051e00505811044ad01471", + "0x52b40500005064112f4052b40501c05268112c4052b40519c05050112c005", + "0xad0146d01489044112b4050444b044112b40504407044112fc050448b044be", + "0xc0014ad014c0014140444c014ad0144c01413044c0014ad014780141604411", + "0xc401427044c430cc2304172b40501cc0130160541101c052b40501c0526811", + "0xc50142a044c8014ad014c201416044112b40504407044c7014c6314052b407", + "0x530c05268112c4052b40532005050112c0052b4053040504c11324052b405", + "0xad014be3280728011328052b405044a3044be014ad014c901419044bd014ad", + "0x52b4053300501811044ad014cb0142e044cc32c072b4052bc050d4112bc05", + "0xb0014ad014b001413044cf014ad014ce0142f044ce014ad014cd01424044cd", + "0x533c052b40533c05264112f4052b4052f405268112c4052b4052c40505011", + "0xad014c70149c044d0014ad014c201416044112b40504407044cf2f4b12c017", + "0x52b40530c0526811340052b4053400505011304052b4053040504c1134405", + "0x2401449044112b40504407044d130cd030417014d1014ad014d101499044c3", + "0xd4014ad014110c41134c052b405044a3044d2014ad0148901416044112b405", + "0x11358052b4050449f044d5014ad014d434c0728011350052b4053500506411", + "0x1113c052b40513c0504c11360052b40535c052701135c052b405354d601c9e", + "0x17014d8014ad014d80149904407014ad014070149a044d2014ad014d201414", + "0xae014ad0149e01416044112b4052600529411044ad0141101c11360073484f", + "0x728011368052b4053680506411368052b40504486044d9014ad0141128c11", + "0x527011374052b40536cdc01c9e044dc014ad0141127c1136c052b405368d9", + "0x70149a044ae014ad014ae0141404417014ad0141701413044de014ad014dd", + "0x11044ad0141101c11378072b81705c05378052b405378052641101c052b405", + "0x504485044e0014ad0141128c1137c052b40528c0505811044ad0149f014a5", + "0xad0141127c11388052b405384e001ca0044e1014ad014e101419044e1014ad", + "0xad0141701413044e5014ad014e40149c044e4014ad014e238c072781138c05", + "0x52b405394052641101c052b40501c052681137c052b40537c050501105c05", + "0x50680505811044ad014a7014a5044112b40504407044e501cdf05c17014e5", + "0xe8014ad014e801419044e8014ad014110d01139c052b405044a3044e6014ad", + "0xeb014ad014e93a807278113a8052b4050449f044e9014ad014e839c0728011", + "0x11398052b405398050501105c052b40505c0504c113b0052b4053ac0527011", + "0x504407044ec01ce605c17014ec014ad014ec0149904407014ad014070149a", + "0x113b8052b405044a3044ed014ad0143801416044112b405058050dc11044ad", + "0x9f044f0014ad014ef3b807280113bc052b4053bc05064113bc052b40504431", + "0x504c113cc052b4053c805270113c8052b4053c0f101c9e044f1014ad01411", + "0xf30149904407014ad014070149a044ed014ad014ed0141404414014ad01414", + "0x1701cad01c050440701411044ad01411044113cc073b41405c053cc052b405", + "0xad01416014170441a014ad0141301416044112b4050440704438050073d013", + "0x11068052b405068050501105c052b40505c0504c11044ad014110ec112a405", + "0xa3014ad0141a01416044112b40504407044a7014f5294a801cad01ca901438", + "0x11280052b4050640521011064052b405288050f011288052b4052940506811", + "0x8b0449c014ad014a00147f0449e014ad014a8014a80449f014ad014a301414", + "0x99014ad0141124c11268052b4050680505811044ad0141101c11044f601411", + "0x11278052b40529c052a01127c052b4052680505011260052b4052640520411", + "0x11044ad0141101c11254053dc97014ad01c9c0147b0449c014ad014980147f", + "0x1701c7a04415014ad014150141404415014ad0149f01416044112b4050444b", + "0x505811044ad0142a0145d044112b4050440704435014f80a82701cad01c97", + "0x9e014380442e014ad0142e0141404427014ad01427014130442e014ad01415", + "0x5068110c4052b4050b80505811044ad0141101c110bc053e424018072b407", + "0x52b405018052a011044ad014110ec11044ad01434014a904434014ad01424", + "0x5044070443b014fa0f03701cad01c060143804431014ad014310141404406", + "0x52b4050f4050501124c052b4050f005164110f4052b4050c40505811044ad", + "0x7044113ec050448b0448b014ad014930147804491014ad01437014a804490", + "0xad014470147404447014ad0141124c11118052b4050c40505811044ad01411", + "0x52b40512c051e011244052b4050ec052a011240052b405118050501112c05", + "0x11044ad0141112c11044ad0141101c11130053f049014ad01c8b014720448b", + "0x501811224052b405044a30444f014ad014490141a0448a014ad0149001416", + "0x8a0141404427014ad014270141304486014ad0144f0143c04487014ad01491", + "0x52180506411224052b405224051b41121c052b40521c051c411228052b405", + "0x81014ad01c7f014000447f21085058ad01486224872282704c6704486014ad", + "0x5d01cad01481014b00447a014ad0148401416044112b405044070447b014fd", + "0xad0141101c111d0053f878014ad01c59014b10447a014ad0147a0141404459", + "0x72014ad014720141404471014ad0145d0141704472014ad0147a0141604411", + "0x112b4051b40529411044ad0141101c11000053fc671b4072b4071c4050e011", + "0x1128c112c0052b4051c80505811044ad014780142e044112b40519c0529c11", + "0x52f4b101ca0044bd014ad014bd01419044bd014ad01411288112c4052b405", + "0xad014c10149c044c1014ad014be3000727811300052b4050449f044be014ad", + "0x52b40501c05268112c0052b4052c00505011214052b4052140504c1130805", + "0x14a5044112b40504407044c201cb021417014c2014ad014c20149904407", + "0x52b40530c0505011310052b40504498044c3014ad0147201416044112b405", + "0x11324c801d0031cc501cad01cc430c8505895044c4014ad014c401497044c3", + "0x51e0050d4112bc052b405044bd044ca014ad014c701416044112b40504407", + "0xad014ca01414044cd014ad014cc01406044112b40532c050b811330cb01cad", + "0xcd2bc07328172f811314052b4053140504c112bc052b4052bc050641132805", + "0x11338052b4053380505011044ad0141101c11348d134016404cf338072b407", + "0x9a044d3014ad014d301414044c5014ad014c501413044d3014ad014ce01416", + "0xad01cd701427044d7358d5350172b40533cd3314160541133c052b40533c05", + "0x52b405044a3044d9014ad014d501416044112b40504407044ae0150236005", + "0x72b405370050d411370052b40536cda01ca0044db014ad014d80142a044da", + "0xe0014ad014df01424044df014ad014de01406044112b405374050b811378dd", + "0x11364052b4053640505011350052b4053500504c11384052b405380050bc11", + "0x504407044e1358d935017014e1014ad014e101499044d6014ad014d60149a", + "0xad014e3014c1044e438c072b4052b80530011388052b4053540505811044ad", + "0xe7014ad014d60149a044e6014ad014e201414044e5014ad014d40141304411", + "0x53400505011044ad0141101c11045030141122c113a0052b405390051b411", + "0xad014e901414044e5014ad014c501413044e9014ad014d001416044d0014ad", + "0xea014ad0141127c113a0052b405348051b41139c052b405344052681139805", + "0xe5014ad014e501413044ec014ad014eb0149c044eb014ad014e83a80727811", + "0x53b0052b4053b0052641139c052b40539c0526811398052b4053980505011", + "0x52b4053240505811044ad014780142e044112b40504407044ec39ce639417", + "0xa0044ef014ad014ef01419044ef014ad014110c4113b8052b405044a3044ed", + "0x9c044f2014ad014f03c407278113c4052b4050449f044f0014ad014ef3b807", + "0x5268113b4052b4053b40505011320052b4053200504c113cc052b4053c805", + "0x112b40504407044f301ced32017014f3014ad014f30149904407014ad01407", + "0x504c11410052b4051e80505811044ad0145d01437044112b4051d00522411", + "0x112b405044070441141c050448b04506014ad015040141404505014ad01485", + "0x11214052b4052140504c11424052b4051ec0527011420052b4052100505811", + "0x1701509014ad015090149904407014ad014070149a04508014ad0150801414", + "0xa5044112b4051300522411044ad0141112c11044ad0141101c114240742085", + "0x10a0141404505014ad01427014130450a014ad0149001416044112b40524405", + "0x52b4054300506411430052b405044860450b014ad0141128c11418052b405", + "0x52b4054350e01c9e0450e014ad0141127c11434052b4054310b01ca00450c", + "0x106014ad015060141404505014ad015050141304510014ad0150f0149c0450f", + "0x1101c11440074190505c05440052b405440052641101c052b40501c0526811", + "0x112014ad0141128c11444052b4050b80505811044ad0142f014a5044112b405", + "0x11450052b40544d1201ca004513014ad015130141904513014ad0141121411", + "0x1304517014ad015160149c04516014ad015144540727811454052b4050449f", + "0x52641101c052b40501c0526811444052b405444050501109c052b40509c05", + "0x11044ad0149e014a5044112b405044070451701d1109c1701517014ad01517", + "0x8b04519014ad015180141404460014ad014350141304518014ad0141501416", + "0xa5044112b4052540522411044ad0141112c11044ad0141101c110451a01411", + "0x11b0141404460014ad01417014130451b014ad0149f01416044112b40527805", + "0x52b4054740506411474052b405044340451c014ad0141128c11464052b405", + "0x52b4052d91e01c9e0451e014ad0141127c112d8052b4054751c01ca00451d", + "0x119014ad015190141404460014ad014600141304520014ad0151f0149c0451f", + "0x1101c11480074646005c05480052b405480052641101c052b40501c0526811", + "0x122014ad0141128c11484052b4050e00505811044ad0141601437044112b405", + "0x112dc052b40548d2201ca004523014ad015230141904523014ad014110c411", + "0x1304526014ad015250149c04525014ad014b74900727811490052b4050449f", + "0x52641101c052b40501c0526811484052b4054840505011050052b40505005", + "0x38014ad014113081104c052b405044c20452601d210501701526014ad01526", + "0xa801d272a41a01cad01c050440701411044ad0141104411044ad0141130c11", + "0x3b044a3014ad0141601417044a7014ad014a901416044112b40504407044a5", + "0x728c050e01129c052b40529c0505011068052b4050680504c11044ad01411", + "0x190141a0449f014ad014a701416044112b40504407044a001528064a201cad", + "0x527c0505011268052b4052700521011270052b405278050f011278052b405", + "0x114a4050448b04497014ad0149a0147f04498014ad014a2014a804499014ad", + "0x150148104415014ad0141124c11254052b40529c0505811044ad0141101c11", + "0x509c051fc11260052b405280052a011264052b405254050501109c052b405", + "0xad0141112c11044ad0141101c110a8054a814014ad01c970147b04497014ad", + "0x52b4050d40505011050052b4050503801cc404435014ad014990141604411", + "0x50d40505811044ad0141101c11090054ac060b8072b4070501a01c7a04435", + "0xad01c98014380442f014ad0142f014140442e014ad0142e014130442f014ad", + "0x50d005068110f0052b4050bc0505811044ad0141101c110dc054b0340c407", + "0xad014110ec110ec052b40505c050f01105c052b40505c1301cc404417014ad", + "0x3d01cad01c31014380443c014ad0143c0141404431014ad01431014a804411", + "0x52b40524c0516411244052b4050f00505811044ad0141101c11240054b493", + "0x4b014ad0148b0147804447014ad0143d014a804446014ad01491014140448b", + "0xad0141124c11124052b4050f00505811044ad0141101c110452e0141122c11", + "0x52b405240052a011118052b4051240505011228052b405130051d01113005", + "0xad0141101c11224054bc4f014ad01c4b014720444b014ad0148a0147804447", + "0xa304486014ad0144f0141a04487014ad0144601416044112b4050444b04411", + "0x2e014130447f014ad014860143c04484014ad014470140604485014ad01411", + "0x5214051b411210052b405210051c41121c052b40521c05050110b8052b405", + "0x7a1ec81058ad0147f2148421c2e04c670447f014ad0147f0141904485014ad", + "0x78014ad0147b01416044112b405044070445901530174052b4071e80500011", + "0x71014ad01c72014b104478014ad0147801414044721d0072b405174052c011", + "0x14ad014740141704467014ad0147801416044112b405044070446d01531", + "0xad0141101c112f4054c8b12c0072b407000050e01119c052b40519c0505011", + "0x52a411044ad014710142e044112b4052c40529c11044ad014b0014a504411", + "0x52b405044a3044be014ad0146701416044112b4050180517411044ad0143b", + "0xc2014ad014c13000728011304052b4053040506411304052b405044a2044c0", + "0x11314052b4053100527011310052b405308c301c9e044c3014ad0141127c11", + "0x9904407014ad014070149a044be014ad014be0141404481014ad0148101413", + "0x112b4052f40529411044ad0141101c11314072f88105c05314052b40531405", + "0x97044c7014ad014c701414044c8014ad014112601131c052b40519c0505811", + "0x504407044cb2bc074ccca324072b407320c72041625411320052b40532005", + "0xce01cad014cd014c7044cd014ad0141131411330052b4053280505811044ad", + "0x11330052b4053300505011324052b4053240504c11044ad014ce014c8044cf", + "0x6d0443b014ad0143b0141904406014ad01406014c904407014ad014070149a", + "0x27044d3348d1340172b4051c43b018cf01ccc32438328111c4052b4051c405", + "0xa3044d6014ad014d101416044112b40504407044d501534350052b40734c05", + "0x50d4112b8052b405360d701ca0044d8014ad014d40142a044d7014ad01411", + "0xdb01424044db014ad014da01406044112b405364050b811368d901cad014ae", + "0x53580505011340052b4053400504c11374052b405370050bc11370052b405", + "0xdd348d634017014dd014ad014dd01499044d2014ad014d20149a044d6014ad", + "0x504c1137c052b4053540527011378052b4053440505811044ad0141101c11", + "0xdf01499044d2014ad014d20149a044de014ad014de01414044d0014ad014d0", + "0xa9044112b4051c4050b811044ad0141101c1137cd2378d005c0537c052b405", + "0xad0141128c11380052b40532c0505811044ad014060145d044112b4050ec05", + "0x52b405388e101ca0044e2014ad014e201419044e2014ad014110c41138405", + "0xe6014ad014e50149c044e5014ad014e33900727811390052b4050449f044e3", + "0x1101c052b40501c0526811380052b40538005050112bc052b4052bc0504c11", + "0xad0146d01489044112b40504407044e601ce02bc17014e6014ad014e601499", + "0x505811044ad014060145d044112b4050ec052a411044ad014740143704411", + "0x50448b044e9014ad014e701414044e8014ad0148101413044e7014ad01478", + "0x505811044ad0143b014a9044112b4050180517411044ad0141101c1104535", + "0xea0141404481014ad0148101413044eb014ad014590149c044ea014ad0147b", + "0x73a88105c053ac052b4053ac052641101c052b40501c05268113a8052b405", + "0x50ec052a411044ad0148901489044112b4050444b044112b40504407044eb", + "0x113b0052b4051180505811044ad01447014a5044112b4050180517411044ad", + "0x11218113b4052b405044a3044e9014ad014ec01414044e8014ad0142e01413", + "0x50449f044ef014ad014ee3b407280113b8052b4053b805064113b8052b405", + "0x53a00504c113c8052b4053c405270113c4052b4053bcf001c9e044f0014ad", + "0xad014f20149904407014ad014070149a044e9014ad014e901414044e8014ad", + "0x60145d044112b4050dc0529411044ad0141101c113c8073a4e805c053c805", + "0x104014ad0141128c113cc052b4050bc0505811044ad01413014af044112b405", + "0x11418052b4054150401ca004505014ad015050141904505014ad0141121411", + "0x130450a014ad015090149c04509014ad015064200727811420052b4050449f", + "0x52641101c052b40501c05268113cc052b4053cc05050110b8052b4050b805", + "0x11044ad01498014a5044112b405044070450a01cf30b8170150a014ad0150a", + "0x505011430052b4050900504c1142c052b4050d40505811044ad01413014af", + "0x89044112b4050444b044112b40504407044114d8050448b0450d014ad0150b", + "0xad01438014af044112b40504c052bc11044ad01498014a5044112b4050a805", + "0x10d014ad0150e014140450c014ad0141a014130450e014ad014990141604411", + "0x728011440052b4054400506411440052b405044340450f014ad0141128c11", + "0x52701144c052b4054451201c9e04512014ad0141127c11444052b4054410f", + "0x70149a0450d014ad0150d014140450c014ad0150c0141304514014ad01513", + "0x11044ad0141101c11450074350c05c05450052b405450052641101c052b405", + "0x52940505811044ad0141601437044112b40504c052bc11044ad01438014af", + "0x117014ad015170141904517014ad014110c411458052b405044a304515014ad", + "0x119014ad015181800727811180052b4050449f04518014ad015174580728011", + "0x11454052b40545405050112a0052b4052a00504c1146c052b4054640527011", + "0x5044110451b01d152a0170151b014ad0151b0149904407014ad014070149a", + "0x505811044ad0141101c110e01401d3704c1701cad01c050440701411044ad", + "0x1a0141404417014ad0141701413044a9014ad01416014170441a014ad01413", + "0x529411044ad0141101c1129c054e0a52a0072b4072a4050e011068052b405", + "0x52b405044a3044a3014ad0141a01416044112b4052940529c11044ad014a8", + "0xa0014ad014192880728011064052b4050640506411064052b405044a2044a2", + "0x11270052b4052780527011278052b4052809f01c9e0449f014ad0141127c11", + "0x9904407014ad014070149a044a3014ad014a30141404417014ad0141701413", + "0x112b40529c0529411044ad0141101c112700728c1705c05270052b40527005", + "0x970449a014ad0149a0141404499014ad0141126011268052b4050680505811", + "0x50440704415254074e497260072b4072649a05c1625411264052b40526405", + "0x3501cad0142a014350442a014ad0141128c1109c052b40525c0505811044ad", + "0x11090052b4050180509011018052b4050b80501811044ad014350142e0442e", + "0x9a04427014ad014270141404498014ad01498014130442f014ad014240142f", + "0xad0141101c110bc0709c9805c050bc052b4050bc052641101c052b40501c05", + "0x1904437014ad014110c4110d0052b405044a304431014ad014150141604411", + "0x7278110ec052b4050449f0443c014ad014370d007280110dc052b4050dc05", + "0x505011254052b4052540504c1124c052b4050f405270110f4052b4050f03b", + "0x312541701493014ad014930149904407014ad014070149a04431014ad01431", + "0xa304490014ad0143801416044112b405058050dc11044ad0141101c1124c07", + "0x8b244072801122c052b40522c050641122c052b4050443104491014ad01411", + "0x512c052701112c052b4051184701c9e04447014ad0141127c11118052b405", + "0xad014070149a04490014ad014900141404414014ad014140141304449014ad", + "0x701411044ad0141104411124072401405c05124052b405124052641101c05", + "0x1a014ad0141301416044112b4050440704438050074e81305c072b40701411", + "0x11068052b405068050501105c052b40505c0504c112a4052b4050580505c11", + "0xa3014ad0141a01416044112b40504407044a70153b294a801cad01ca901438", + "0x506411044ad014110ec11064052b405288050f011288052b4052940506811", + "0x190143d044a3014ad014a301414044a8014ad014a8014a804419014ad01419", + "0xad0141124c1127c052b40528c0505811044ad0141101c11280054f0112b407", + "0x52b4052700524411268052b40527c0505011270052b405278052401127805", + "0x528c0505811044ad014a001446044112b40504407044114f4050448b04499", + "0x52b4052600505011254052b40525c0511c1125c052b4050449304498014ad", + "0x5044070442a0153e09c1501cad01ca80143804499014ad01495014910449a", + "0x512411044ad01427014a7044112b4050540529411044ad0141112c11044ad", + "0x52b405044a20442e014ad0141128c110d4052b4052680505811044ad01499", + "0x2f014ad0141127c11090052b4050182e01ca004406014ad014060141904406", + "0x17014ad014170141304434014ad014310149c04431014ad014240bc0727811", + "0x50d0052b4050d0052641101c052b40501c05268110d4052b4050d40505011", + "0x11044ad0142a014a5044112b4050444b044112b405044070443401c3505c17", + "0x525c110dc052b4050dc05050110f0052b4050449804437014ad0149a01416", + "0xad0141101c112409301d3f0f43b01cad01c3c0dc17058950443c014ad0143c", + "0x11118052b40522c052401122c052b4050449304491014ad0143d0141604411", + "0x3b044112b40512c05124111244b01cad014470148a04447014ad014990144c", + "0x524405050110ec052b4050ec0504c11124052b4051240524411044ad01411", + "0x1101c11228055004c014ad01c490144f04446014ad014460149104491014ad", + "0x52b405118051301113c052b4052440505811044ad0144c01489044112b405", + "0x704411504050448b04486014ad014890149104487014ad0144f0141404489", + "0xad014850141404485014ad0149101416044112b4052280522411044ad01411", + "0x5044070447f01542210052b4072180513c11218052b405118052441121c05", + "0x1304481014ad0148701416044112b4052100522411044ad0141112c11044ad", + "0x1122c11174052b40501c05268111e8052b40520405050111ec052b4050ec05", + "0x505811044ad0147f01489044112b4050444b044112b405044070441150c05", + "0x70149a04459014ad01459014140443b014ad0143b0141304459014ad01487", + "0x6d014ad01c7101427044711c8741e0172b40501c590ec160541101c052b405", + "0x11000052b4051d00505811044ad0146d014cb044112b405044070446701544", + "0xa30445d014ad014720149a0447a014ad01400014140447b014ad0147801413", + "0xbd01406044112b4052c4050b8112f4b101cad014b001435044b0014ad01411", + "0x51ec0504c11304052b405300050bc11300052b4052f805090112f8052b405", + "0xad014c1014990445d014ad0145d0149a0447a014ad0147a014140447b014ad", + "0x527011308052b4051d00505811044ad0141101c113045d1e87b05c0530405", + "0x720149a044c2014ad014c20141404478014ad0147801413044c3014ad01467", + "0x11044ad0141101c1130c723087805c0530c052b40530c05264111c8052b405", + "0x504431044c5014ad0141128c11310052b4052400505811044ad0149901449", + "0xad0141127c11320052b40531cc501ca0044c7014ad014c701419044c7014ad", + "0xad0149301413044af014ad014ca0149c044ca014ad014c8324072781132405", + "0x52b4052bc052641101c052b40501c0526811310052b405310050501124c05", + "0x50680505811044ad014a7014a5044112b40504407044af01cc424c17014af", + "0xcd014ad014cd01419044cd014ad014110d011330052b405044a3044cb014ad", + "0xd0014ad014ce33c072781133c052b4050449f044ce014ad014cd3300728011", + "0x1132c052b40532c050501105c052b40505c0504c11344052b4053400527011", + "0x504407044d101ccb05c17014d1014ad014d10149904407014ad014070149a", + "0x1134c052b405044a3044d2014ad0143801416044112b405058050dc11044ad", + "0x9f044d5014ad014d434c0728011350052b4053500506411350052b40504431", + "0x504c11360052b40535c052701135c052b405354d601c9e044d6014ad01411", + "0xd80149904407014ad014070149a044d2014ad014d20141404414014ad01414", + "0x38050165141305c16058ad01c070140733011360073481405c05360052b405", + "0xcd044a9014ad014160141604416014ad0141601414044112b405044070441a", + "0xa228ca7294132b4052a00533c112a0052b40504c053381104c052b40504c05", + "0x52a411044ad014a20145d044112b40528c0517411044ad014a5014d004419", + "0x52800534c11280052b40529c053481129c052b40529c0534411044ad01419", + "0x517411044ad0149f014a90442e0d42a09c1525497260992689c2789f28cad", + "0x112b405260052a411044ad01499014a9044112b4052700535011044ad0149e", + "0x2701437044112b4050540535011044ad01495014d5044112b40525c052a411", + "0x11044ad0142e01437044112b4050d40535811044ad0142a014d6044112b405", + "0x110c4052b4050bc05360110bc052b4050900505c110900601cad0149a014d7", + "0x71044a9014ad014a90141404417014ad014170149a04431014ad01431014a8", + "0x11044ad0141101c110f005518370d0072b4070c4050e011018052b40501805", + "0x50f0110f4052b4050dc05068110ec052b4052a40505811044ad01434014a5", + "0x5050112409301cad01493014ae04493014ad014930141904493014ad0143d", + "0x93014a9044112b405044070449101547044ad01c900143d0443b014ad0143b", + "0x46014ad0141121c1122c052b4050ec0505811044ad0140601437044112b405", + "0x11044052b4050440504c1112c052b40511c053681111c052b4051180536411", + "0x170144b014ad0144b014db04417014ad014170149a0448b014ad0148b01414", + "0x49014ad0143b01416044112b4052440511811044ad0141101c1112c1722c11", + "0x4f014ad0144c22807374112289301cad01493014ae0444c014ad0141137011", + "0x5520112b40713c050f411124052b405124050501113c052b40513c0506411", + "0x4901416044112b40524c052a411044ad0140601437044112b4050440704489", + "0x52b4052180506411214052b405044dc04486014ad014112f41121c052b405", + "0x52b40521c0505011210052b4052100506411210052b4052148601cdd04486", + "0x81014ad0148701416044112b405044070447f01549044ad01c840143d04487", + "0x130445d014ad0147a014da0447a014ad0147b014d90447b014ad0141137811", + "0x536c1105c052b40505c0526811204052b4052040505011044052b40504405", + "0x11044ad0147f01446044112b405044070445d05c81044170145d014ad0145d", + "0x740141904474014ad0141137c111e0052b405044a304459014ad0148701416", + "0x721c407278111c4052b4050449f04472014ad014741e007280111d0052b405", + "0x51640505011044052b4050440504c1119c052b4051b405380111b4052b405", + "0x6705c590441701467014ad01467014db04417014ad014170149a04459014ad", + "0x5044e104400014ad0144901416044112b4052240511811044ad0141101c11", + "0xbd01419044bd014ad014b02c407374112c49301cad01493014ae044b0014ad", + "0x1101c112f805528112b4072f4050f411000052b40500005050112f4052b405", + "0x72b4050180535c11300052b4050000505811044ad01493014a9044112b405", + "0x11310052b4053080505c1130c052b405044e2044112b405304050dc11308c1", + "0xe4044c0014ad014c001414044c3014ad014c3014e3044c5014ad014c4014d8", + "0x52b4053000505811044ad0141101c113240552cc831c072b40730cc504416", + "0x1132c052b405044a3044af014ad014c80141a044c8014ad014c8014e5044ca", + "0x7a044ca014ad014ca01414044cc014ad014cc01419044cc014ad014af0143c", + "0xd0014ad014ca01416044112b40504407044cf0154c338cd01cad01ccc31c07", + "0x6044112b405348050b81134cd201cad014cb01435044d1014ad0141139811", + "0x504c11344052b4053440506411340052b4053400505011350052b40534c05", + "0x11364ae36016534d7358d5058ad01cd4344ce05cd004ce7044cd014ad014cd", + "0x53540505811354052b4053540505011044ad014d701437044112b40504407", + "0x52b4053700536811370052b40536c053641136c052b40504487044da014ad", + "0xd6014ad014d60149a044da014ad014da01414044cd014ad014cd01413044dd", + "0x53600505011044ad0141101c11374d6368cd05c05374052b4053740536c11", + "0xad014d937c072781137c052b4050449f044de014ad014d801416044d8014ad", + "0x52b4053780505011334052b4053340504c11384052b405380053801138005", + "0x7044e12b8de33417014e1014ad014e1014db044ae014ad014ae0149a044de", + "0x52b405044a3044e2014ad014ca01416044112b40532c050b811044ad01411", + "0xe5014ad014e438c0728011390052b4053900506411390052b405044e8044e3", + "0x113a0052b40539c053801139c052b405394e601c9e044e6014ad0141127c11", + "0xdb04417014ad014170149a044e2014ad014e201414044cf014ad014cf01413", + "0x52b4053000505811044ad0141101c113a017388cf05c053a0052b4053a005", + "0xa0044eb014ad014eb01419044eb014ad014113a4113a8052b405044a3044e9", + "0xe0044ee014ad014ec3b407278113b4052b4050449f044ec014ad014eb3a807", + "0x5268113a4052b4053a40505011324052b4053240504c113bc052b4053b805", + "0x112b40504407044ef05ce932417014ef014ad014ef014db04417014ad01417", + "0x52b8113c4052b405044ea044f0014ad0140001416044112b4052f80511811", + "0x14044f3014ad014f301419044f3014ad014f13c807374113c89301cad01493", + "0x50dc11044ad0141101c1141005538112b4073cc050f4113c0052b4053c005", + "0x52b405044eb04505014ad014f001416044112b40524c052a411044ad01406", + "0xad01d0605d05058ed04506014ad01506014ec04505014ad015050141404506", + "0x505011044ad0150a014a9044112b405044070450d4310b0594f4290942016", + "0x543c053641143c052b405044870450e014ad015080141604508014ad01508", + "0xad0150e0141404411014ad014110141304511014ad01510014da04510014ad", + "0x11445094381105c05444052b4054440536c11424052b405424052681143805", + "0x50449f04512014ad0150b014160450b014ad0150b01414044112b40504407", + "0x50440504c11454052b4054500538011450052b4054351301c9e04513014ad", + "0xad01515014db0450c014ad0150c0149a04512014ad015120141404411014ad", + "0xf001416044112b4054100511811044ad0141101c114550c4481105c0545405", + "0x11746007374114609301cad01493014ae04517014ad014113b811458052b405", + "0x7180050f411458052b4054580505011180052b4051800506411180052b405", + "0x52b4054580505811044ad01493014a9044112b405044070451901550044ad", + "0x1146c052b40546c0505011470052b4054700506411470052b405044ef0451b", + "0x52b40546c0505811044ad0141101c1147805544b6474072b4074701101cf0", + "0x11488052b405044e2044112b405480050dc114852001cad01406014d70451f", + "0x1404522014ad01522014e3044b7014ad01523014d804523014ad0152101417", + "0xad0141101c114980554925490072b407488b7474163901147c052b40547c05", + "0x154014ad015250141a04525014ad01525014e504553014ad0151f0141604411", + "0xe304553014ad015530141404556014ad014113c411554052b405550050f011", + "0x133c811490052b4054900504c11554052b4055540506411558052b40555805", + "0x15701414044112b405044070455c56d5a059595615701cad01d552d95605d53", + "0xad0155e014d90455e014ad0141121c11574052b40555c050581155c052b405", + "0x52b4055740505011490052b4054900504c11580052b40557c053681157c05", + "0x7045605615d4901701560014ad01560014db04558014ad015580149a0455d", + "0xad0141127c11584052b4055680505811568052b4055680505011044ad01411", + "0xad015240141304563014ad014b8014e0044b8014ad0155c588072781158805", + "0x52b40558c0536c1156c052b40556c0526811584052b405584050501149005", + "0x547c0505811044ad014b6014f3044112b405044070456356d614901701563", + "0x166014ad015660141904566014ad014113a411594052b405044a304564014ad", + "0x169014ad015675a007278115a0052b4050449f04567014ad015665940728011", + "0x11590052b4055900505011498052b4054980504c115a8052b4055a40538011", + "0x5044070456a05d64498170156a014ad0156a014db04417014ad014170149a", + "0x115b0052b405044a30456b014ad0151b01416044112b405018050dc11044ad", + "0x9f0456e014ad0156d5b007280115b4052b4055b405064115b4052b405044e8", + "0x504c115c4052b4055c005380115c0052b4055b96f01c9e0456f014ad01411", + "0x171014db04417014ad014170149a0456b014ad0156b014140451e014ad0151e", + "0x16044112b4054640511811044ad0141101c115c4175ad1e05c055c4052b405", + "0x5064115d0052b4055cc9301cdd04573014ad01411410115c8052b40545805", + "0x70457601575044ad01d740143d04572014ad015720141404574014ad01574", + "0x5044e2045795e0072b4050180535c115dc052b4055c80505811044ad01411", + "0xad0157a014e30457c014ad0157b014d80457b014ad01579014170457a014ad", + "0x112e8055fd7e5f4072b4075e97c04416390115dc052b4055dc05050115e805", + "0x17e0141a0457e014ad0157e014e504580014ad0157701416044112b40504407", + "0x560c0505c112ec052b4050450504583608072b4055e00535c11604052b405", + "0xad0158001414044bb014ad014bb014e304585014ad01584014d804584014ad", + "0x116240562187618072b4072ed855f41639011604052b405604050641160005", + "0x1870141a04587014ad01587014e50458a014ad0158001416044112b40504407", + "0xad0141141811044ad0158c014370458d630072b4056080535c1162c052b405", + "0x52b4056380538c1163c052b4052f005360112f0052b4056340505c1163805", + "0xad01d8e63d86058e40458b014ad0158b014190458a014ad0158a014140458e", + "0x56440539411650052b4056280505811044ad0141101c1164c056499164007", + "0xad015900141304594014ad015940141404595014ad015910141a04591014ad", + "0x19b668166659865d96058ad01c176500733011654052b405654050641164005", + "0xcd0459d014ad015960141604596014ad0159601414044112b405044070459c", + "0x1a1680bf67c132b4056780533c11678052b4056600533811660052b40566005", + "0x52a411044ad015a10145d044112b4056800517411044ad014bf01508045a2", + "0x568c0542c1168c052b40567c054281167c052b40567c0542411044ad015a2", + "0x1a701419045a8014ad015810143c045a7014ad015a40150c045a6695a4058ad", + "0x1970149a045a9014ad015a901419045a9014ad015a869c073741169c052b405", + "0x56980532411694052b405694053b011674052b405674050501165c052b405", + "0xad0159d01416044112b40504407045ab015aa044ad01da90143d045a6014ad", + "0xad015ad6b007374116b4052b40562c050f0116b0052b405694054301131805", + "0x112b4076b8050f411318052b40531805050116b8052b4056b805064116b805", + "0x1b2014ad015a60150d045b1014ad014c601416044112b40504407045b0015af", + "0xb9014ad014b901419044b9014ad015b36c807374116cc052b405654050f011", + "0x11044ad0141101c116d4056d0112b4072e4050f4116c4052b4056c40505011", + "0x5368116e0052b4056dc05364116dc052b40504487045b6014ad015b101416", + "0x1970149a045b6014ad015b60141404590014ad0159001413045b9014ad015b8", + "0x11044ad0141101c116e5976d99005c056e4052b4056e40536c1165c052b405", + "0x50450e045bb014ad0141128c116e8052b4056c40505811044ad015b501446", + "0xad0141127c116f4052b4056f1bb01ca0045bc014ad015bc01419045bc014ad", + "0xad0159001413045c0014ad015bf014e0045bf014ad015bd6f807278116f805", + "0x52b4057000536c1165c052b40565c05268116e8052b4056e8050501164005", + "0x56980517411044ad015b001446044112b40504407045c065dba64017015c0", + "0x11708052b405044a3045c1014ad014c601416044112b405654052a411044ad", + "0x9f045c3014ad014b570807280112d4052b4052d405064112d4052b4050450f", + "0x504c11718052b4057140538011714052b40570dc401c9e045c4014ad01411", + "0x1c6014db04597014ad015970149a045c1014ad015c10141404590014ad01590", + "0x5d044112b4056ac0511811044ad0141101c11719977059005c05718052b405", + "0xad0158b014a9044112b4056940544011044ad01595014a9044112b40569805", + "0x19045c9014ad0141144411720052b405044a3045c7014ad0159d0141604411", + "0x72781172c052b4050449f045ca014ad015c97200728011724052b40572405", + "0x505011640052b4056400504c11734052b4057300538011730052b405729cb", + "0x1c764017015cd014ad015cd014db04597014ad015970149a045c7014ad015c7", + "0x52a411044ad01581014a9044112b40562c052a411044ad0141101c1173597", + "0xad0141127c11738052b4056680505811668052b4056680505011044ad01595", + "0xad0159001413044b4014ad015d0014e0045d0014ad0159c73c072781173c05", + "0x52b4052d00536c1166c052b40566c0526811738052b405738050501164005", + "0x5604052a411044ad0158b014a9044112b40504407044b466dce64017014b4", + "0x1174c052b405044e9045d2014ad0141128c11744052b4056280505811044ad", + "0x9e045d5014ad0141127c11750052b40574dd201ca0045d3014ad015d301419", + "0x1404593014ad0159301413045d7014ad015d6014e0045d6014ad015d475407", + "0x19305c0575c052b40575c0536c1105c052b40505c0526811744052b40574405", + "0x16044112b405604052a411044ad0158201437044112b40504407045d705dd1", + "0x57680506411768052b405044e9045d9014ad0141128c11760052b40560005", + "0x576ddc01c9e045dc014ad0141127c1176c052b405769d901ca0045da014ad", + "0xad015d80141404589014ad0158901413045de014ad015dd014e0045dd014ad", + "0x11778177618905c05778052b4057780536c1105c052b40505c052681176005", + "0xad0141128c112cc052b4055dc0505811044ad0157801437044112b40504407", + "0x52b405781df01ca0045e0014ad015e001419045e0014ad014113a41177c05", + "0x1e4014ad015e3014e0045e3014ad015e17880727811788052b4050449f045e1", + "0x1105c052b40505c05268112cc052b4052cc05050112e8052b4052e80504c11", + "0xad0157601446044112b40504407045e405cb32e817015e4014ad015e4014db", + "0x112045e6014ad0141128c11794052b4055c80505811044ad014060143704411", + "0x1127c117a0052b40579de601ca0045e7014ad015e701419045e7014ad01411", + "0x1101413045eb014ad015ea014e0045ea014ad015e87a407278117a4052b405", + "0x57ac0536c1105c052b40505c0526811794052b4057940505011044052b405", + "0x50dc11044ad0143c014a5044112b40504407045eb05de504417015eb014ad", + "0x52b405044e9044b2014ad0141128c117b0052b4052a40505811044ad01406", + "0x1ef014ad0141127c117b8052b4057b4b201ca0045ed014ad015ed01419045ed", + "0x11014ad0141101413045f1014ad015f0014e0045f0014ad015ee7bc0727811", + "0x57c4052b4057c40536c1105c052b40505c05268117b0052b4057b00505011", + "0xad014140141604414014ad0141401414044112b40504407045f105dec04417", + "0x52b4057d005380117d0052b405069f301c9e045f3014ad0141127c117c805", + "0x38014ad014380149a045f2014ad015f20141404411014ad0141101413045f5", + "0x50440701411044ad0141112c117d4387c81105c057d4052b4057d40536c11", + "0xae044a9014ad0141401416044112b405044070441a0e0077d81404c072b407", + "0x3d044a9014ad014a90141404413014ad0141301413044a805c072b40505c05", + "0xa901416044112b40505c052a411044ad0141101c11294057dc112b4072a005", + "0xa201515044a2014ad014a301c074501128c052b4050580544c1129c052b405", + "0x5064054581129c052b40529c050501104c052b40504c0504c11064052b405", + "0xa901416044112b4052940511811044ad0141101c11064a704c1601419014ad", + "0x52b4052800505011044ad014110ec1127c052b40501c0505c11280052b405", + "0xad014a001416044112b405044070449a015f82709e01cad01c9f01438044a0", + "0x52b40525c052101125c052b405260050f011260052b405270050681126405", + "0x2a014ad014950147f04427014ad0149e014a804415014ad014990141404495", + "0xad0141124c110d4052b4052800505811044ad0141101c11045f90141122c11", + "0x52b405268052a011054052b4050d40505011018052b4050b805204110b805", + "0x2f014ad01c2a0147b04424014ad01427014060442a014ad014060147f04427", + "0xa004434014ad0141501416044112b4050444b044112b4050440704431015fa", + "0x130443b014ad0143c05c07374110f0052b405044dc04437014ad0142f05807", + "0x51b411090052b405090051c4110d0052b4050d0050501104c052b40504c05", + "0x3d058ad0143b0dc240d01304c670443b014ad0143b0141904437014ad01437", + "0xad01417014a9044112b4050444b044112b405044070449024c3d0580524093", + "0x1122c052b4050c40545c11244052b4050540505811044ad014160142e04411", + "0x1104c052b40504c0504c1111c052b4051180545411118052b40522c2401d14", + "0xad0141101c1111c9104c1601447014ad014470151604491014ad0149101414", + "0x505811044ad0140701437044112b405058050b811044ad01417014a904411", + "0xad0144c014190444c014ad014110c411124052b405044a30444b014ad0141a", + "0xad0148a13c072781113c052b4050449f0448a014ad0144c124072801113005", + "0x52b40512c05050110e0052b4050e00504c1121c052b405224054601122405", + "0x170145d044112b405058053201121c4b0e01601487014ad01487015160444b", + "0xa52a0167eca906838058ad01c070140733011044ad01413014a9044112b405", + "0xcd044a3014ad014380141604438014ad0143801414044112b40504407044a7", + "0x9e27ca0064132b4052880533c11288052b4052a405338112a4052b4052a405", + "0x52a411044ad0149e0145d044112b40527c0517411044ad01419014d00449c", + "0x52680534c11268052b4052800534811280052b4052800534411044ad0149c", + "0x517411044ad01499014a9044310bc240182e0d42a09c15254972609928cad", + "0x112b40509c052a411044ad01415014a9044112b40525c0535011044ad01498", + "0x601437044112b4050b80535011044ad01435014d5044112b4050a8052a411", + "0x11044ad0143101437044112b4050bc0535811044ad01424014d6044112b405", + "0x110ec052b4050f005360110f0052b4050dc0505c110dc3401cad01495014d7", + "0x71044a3014ad014a3014140441a014ad0141a0149a0443b014ad0143b014a8", + "0x11044ad0141101c11240057f0930f4072b4070ec050e0110d0052b4050d005", + "0x50f01122c052b40524c0506811244052b40528c0505811044ad0143d014a5", + "0x471180737411118052b405118050641111c052b405044ee04446014ad0148b", + "0x712c050f411244052b405244050501112c052b40512c050641112c052b405", + "0x52b4052440505811044ad014140142e044112b4050440704449015fd044ad", + "0x11130052b4051300505011228052b4052280506411228052b405044ef0444c", + "0x52b4051300505811044ad0141101c1121c057f88913c072b4072281101cf0", + "0x111fc052b40504505044112b405214050dc112108501cad01434014d704486", + "0x140447f014ad0147f014e30447b014ad01481014d804481014ad0148401417", + "0xad0141101c11164057fc5d1e8072b4071fc7b13c1639011218052b40521805", + "0x74014ad0145d0141a0445d014ad0145d014e504478014ad014860141604411", + "0xe304478014ad014780141404471014ad014113c4111c8052b4051d0050f011", + "0x133c8111e8052b4051e80504c111c8052b4051c805064111c4052b4051c405", + "0x6d01414044112b40504407044b12c00005a0019c6d01cad01c722247106878", + "0xad014be014d9044be014ad0141121c112f4052b4051b405058111b4052b405", + "0x52b4052f405050111e8052b4051e80504c11304052b405300053681130005", + "0x7044c119cbd1e817014c1014ad014c1014db04467014ad014670149a044bd", + "0xad0141127c11308052b4050000505811000052b4050000505011044ad01411", + "0xad0147a01413044c5014ad014c4014e0044c4014ad014b130c072781130c05", + "0x52b4053140536c112c0052b4052c00526811308052b40530805050111e805", + "0x52180505811044ad01489014f3044112b40504407044c52c0c21e817014c5", + "0xc9014ad014c901419044c9014ad014113a411320052b405044a3044c7014ad", + "0xcb014ad014ca2bc07278112bc052b4050449f044ca014ad014c93200728011", + "0x1131c052b40531c0505011164052b4051640504c11330052b40532c0538011", + "0x504407044cc068c716417014cc014ad014cc014db0441a014ad0141a0149a", + "0x11338052b405044a3044cd014ad0144c01416044112b4050d0050dc11044ad", + "0x9f044d0014ad014cf338072801133c052b40533c050641133c052b405044e8", + "0x504c1134c052b4053480538011348052b405340d101c9e044d1014ad01411", + "0xd3014db0441a014ad0141a0149a044cd014ad014cd0141404487014ad01487", + "0x37044112b4051240511811044ad0141101c1134c1a3348705c0534c052b405", + "0x5050050d411354052b405044bd044d4014ad0149101416044112b4050d005", + "0xad014d401414044d8014ad014d701406044112b405358050b81135cd601cad", + "0xda05a01364ae01cad01cd83541a350172f811354052b405354050641135005", + "0x11374052b4052b805058112b8052b4052b80505011044ad0141101c11370db", + "0x504c11380052b40537c053681137c052b4053780536411378052b40504487", + "0xe0014db044d9014ad014d90149a044dd014ad014dd0141404411014ad01411", + "0x11368052b4053680505011044ad0141101c11380d93741105c05380052b405", + "0xe0044e3014ad014dc3880727811388052b4050449f044e1014ad014da01416", + "0x526811384052b4053840505011044052b4050440504c11390052b40538c05", + "0x112b40504407044e436ce104417014e4014ad014e4014db044db014ad014db", + "0xa301416044112b405050050b811044ad0143401437044112b4052400529411", + "0x52b40539c050641139c052b405044e9044e6014ad0141128c11394052b405", + "0x52b4053a0e901c9e044e9014ad0141127c113a0052b40539ce601ca0044e7", + "0xe5014ad014e50141404411014ad0141101413044eb014ad014ea014e0044ea", + "0x1101c113ac1a3941105c053ac052b4053ac0536c11068052b4050680526811", + "0x52b4052a005058112a0052b4052a00505011044ad014140142e044112b405", + "0xef014ad014ee014e0044ee014ad014a73b407278113b4052b4050449f044ec", + "0x11294052b40529405268113b0052b4053b00505011044052b4050440504c11", + "0x111c47219c1105c341c867044172a4ef294ec04417014ef014ad014ef014db", + "0x170d07219c1105ce705807014111c47219c1105c341c867044170441601c05", + "0x1780c1601c05044711c867044170d07219c1105e0205807014111c47219c11", + "0x111c47219c1105c341c867044178101601c05044711c867044170d07219c11", + "0x11058060bc3419c1104e0601c05044781c867044171c867044168141601c05", + "0x1601c05044781c867044170bc06050901c8670443881c17058070141122867", + "0x8201404c17" + ], + "sierra_program_debug_info": { + "type_names": [], + "libfunc_names": [], + "user_func_names": [] + }, + "contract_class_version": "0.1.0", + "entry_points_by_type": { + "EXTERNAL": [ + { + "selector": "0x15d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad", + "function_idx": 3 + }, + { + "selector": "0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775", + "function_idx": 2 + }, + { + "selector": "0x1b1a0649752af1b28b3dc29a1556eee781e4a4c3a1f7f53f90fa834de098c4d", + "function_idx": 4 + }, + { + "selector": "0x289da278a8dc833409cabfdad1581e8e7d40e42dcaed693fa4008dcdb4963b3", + "function_idx": 0 + }, + { + "selector": "0x36fcbf06cd96843058359e1a75928beacfac10727dab22a3972f0af8aa92895", + "function_idx": 1 + } + ], + "L1_HANDLER": [], + "CONSTRUCTOR": [ + { + "selector": "0x28ffe4ff0f226a9107253e17a904099aa4f63a02a5621de0576e5aa71bc5194", + "function_idx": 5 + } + ] + }, + "abi": [ + { + "type": "function", + "name": "__validate_declare__", + "inputs": [ + { + "name": "class_hash", + "type": "core::felt252" + } + ], + "outputs": [ + { + "type": "core::felt252" + } + ], + "state_mutability": "view" + }, + { + "type": "enum", + "name": "core::bool", + "variants": [ + { + "name": "False", + "type": "()" + }, + { + "name": "True", + "type": "()" + } + ] + }, + { + "type": "function", + "name": "__validate_deploy__", + "inputs": [ + { + "name": "class_hash", + "type": "core::felt252" + }, + { + "name": "contract_address_salt", + "type": "core::felt252" + }, + { + "name": "validate_constructor", + "type": "core::bool" + } + ], + "outputs": [ + { + "type": "core::felt252" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "__validate__", + "inputs": [ + { + "name": "contract_address", + "type": "core::starknet::contract_address::ContractAddress" + }, + { + "name": "selector", + "type": "core::felt252" + }, + { + "name": "calldata", + "type": "core::array::Array::" + } + ], + "outputs": [ + { + "type": "core::felt252" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "__execute__", + "inputs": [ + { + "name": "contract_address", + "type": "core::starknet::contract_address::ContractAddress" + }, + { + "name": "selector", + "type": "core::felt252" + }, + { + "name": "calldata", + "type": "core::array::Array::" + } + ], + "outputs": [ + { + "type": "core::felt252" + } + ], + "state_mutability": "view" + }, + { + "type": "constructor", + "name": "constructor", + "inputs": [ + { + "name": "validate_constructor", + "type": "core::bool" + } + ] + }, + { + "type": "function", + "name": "foo", + "inputs": [], + "outputs": [], + "state_mutability": "view" + }, + { + "type": "event", + "name": "account_faulty::account_faulty::Account::Event", + "kind": "enum", + "variants": [] + } + ] +} diff --git a/crates/blockifier_test_utils/resources/feature_contracts/cairo1/sierra/account_with_dummy_validate.sierra.json b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/sierra/account_with_dummy_validate.sierra.json new file mode 100644 index 00000000000..247da129d63 --- /dev/null +++ b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/sierra/account_with_dummy_validate.sierra.json @@ -0,0 +1,839 @@ +{ + "sierra_program": [ + "0x1", + "0x7", + "0x0", + "0x2", + "0xb", + "0x0", + "0x141", + "0xbf", + "0x2d", + "0x52616e6765436865636b", + "0x800000000000000100000000000000000000000000000000", + "0x436f6e7374", + "0x800000000000000000000000000000000000000000000002", + "0x1", + "0x6", + "0x2", + "0x537472756374", + "0x800000000000000f00000000000000000000000000000001", + "0x0", + "0x2ee1e2b1b89f8c495f200e4956278a4d47395fe262f27b52e5865c9524c08c3", + "0x456e756d", + "0x800000000000000700000000000000000000000000000003", + "0x3288d594b9a45d15bb2fcb7903f06cdb06b27f0ba88186ec4cfaa98307cb972", + "0x436c61737348617368", + "0x800000000000000700000000000000000000000000000000", + "0x494e56414c49445f43414c4c4552", + "0x66656c74323532", + "0x4e6f6e5a65726f", + "0x800000000000000700000000000000000000000000000001", + "0x426f78", + "0x13", + "0x15", + "0x436f6e747261637441646472657373", + "0x75313238", + "0x4172726179", + "0x800000000000000300000000000000000000000000000001", + "0x536e617073686f74", + "0xc", + "0x800000000000000700000000000000000000000000000002", + "0x1baeba72e79e9db2587cf44fedb2f3700b2075a5e8e39a562584862c4b71f62", + "0xd", + "0x16", + "0xf", + "0x1597b831feeb60c71f259624b79cf66995ea4f7e383403583674ab9c33b9cec", + "0x10", + "0x753332", + "0x80000000000000070000000000000000000000000000000e", + "0x348a62b7a38c0673e61e888d83a3ac1bf334ee7361a8514593d3d9532ed8b39", + "0xa", + "0xb", + "0xe", + "0x11", + "0x12", + "0x753634", + "0x800000000000000700000000000000000000000000000004", + "0x3808c701a5d13e100ab11b6c02f91f752ecae7e420d21b56c90ec0a475cc7e5", + "0x14", + "0x3342418ef16b3e2799b906b1e4e89dbb9b111332dd44f72458ce44f9895b508", + "0x800000000000000700000000000000000000000000000006", + "0x7d4d99e9ed8d285b5c61b493cedb63976bc3d9da867933d829f49ce838b5e7", + "0x9", + "0x8", + "0x17", + "0x556e696e697469616c697a6564", + "0x800000000000000200000000000000000000000000000001", + "0x4661696c656420746f20646573657269616c697a6520706172616d202333", + "0x800000000000000300000000000000000000000000000003", + "0x17b6ecc31946835b0d9d92c2dd7a9c14f29af0371571ae74a1b228828b2242", + "0x1b", + "0x16a4c8d7c05909052238a862d8cc3e7975bf05a07b3a69c6b28951083a6d672", + "0x1d", + "0x34f9bd7c6cb2dd4263175964ad75f1ff1461ddc332fbfb274e0fb2a5d7ab968", + "0x1c", + "0x1e", + "0x29d7d57c04a880978e7b3689f6218e507f3be17588744b58dc17762447ad0e7", + "0x20", + "0x11c6d8087e00642489f92d2821ad6ebd6532ad1a3b6d12833da6d6810391511", + "0x4661696c656420746f20646573657269616c697a6520706172616d202331", + "0x4661696c656420746f20646573657269616c697a6520706172616d202332", + "0x4f7574206f6620676173", + "0x56414c4944", + "0x4275696c74696e436f737473", + "0x53797374656d", + "0x9931c641b913035ae674b400b61a51476d506bbe8bba2ff8a6272790aba9e6", + "0x26", + "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", + "0x4761734275696c74696e", + "0x57", + "0x7265766f6b655f61705f747261636b696e67", + "0x77697468647261775f676173", + "0x6272616e63685f616c69676e", + "0x72656465706f7369745f676173", + "0x7374727563745f6465636f6e737472756374", + "0x73746f72655f74656d70", + "0x2c", + "0x61727261795f736e617073686f745f706f705f66726f6e74", + "0x756e626f78", + "0x64726f70", + "0x61727261795f6e6577", + "0x636f6e73745f61735f696d6d656469617465", + "0x2b", + "0x61727261795f617070656e64", + "0x7374727563745f636f6e737472756374", + "0x656e756d5f696e6974", + "0x2a", + "0x29", + "0x6765745f6275696c74696e5f636f737473", + "0x28", + "0x77697468647261775f6761735f616c6c", + "0x27", + "0x736e617073686f745f74616b65", + "0x25", + "0x24", + "0x23", + "0x656e61626c655f61705f747261636b696e67", + "0x72656e616d65", + "0x22", + "0x6a756d70", + "0x656e756d5f6d61746368", + "0x64697361626c655f61705f747261636b696e67", + "0x21adb5788e32c84f69a1863d85ef9394b7bf761a0ce1190f826984e5075c371", + "0x21", + "0x66756e6374696f6e5f63616c6c", + "0x3", + "0x5", + "0x1f", + "0x1a", + "0x616c6c6f635f6c6f63616c", + "0x66696e616c697a655f6c6f63616c73", + "0x73746f72655f6c6f63616c", + "0x6765745f657865637574696f6e5f696e666f5f76325f73797363616c6c", + "0x18", + "0x636f6e74726163745f616464726573735f746f5f66656c74323532", + "0x66656c743235325f69735f7a65726f", + "0x63616c6c5f636f6e74726163745f73797363616c6c", + "0x7", + "0x19", + "0x636c6173735f686173685f7472795f66726f6d5f66656c74323532", + "0x4", + "0x6465706c6f795f73797363616c6c", + "0x647570", + "0x66656c743235325f737562", + "0x45b", + "0xffffffffffffffff", + "0x69", + "0x5a", + "0x4b", + "0x3d", + "0x2e", + "0x2f", + "0x30", + "0x31", + "0x32", + "0x33", + "0x34", + "0x35", + "0x36", + "0x37", + "0x38", + "0x39", + "0x3a", + "0x3b", + "0x3c", + "0x3e", + "0x3f", + "0x40", + "0x41", + "0x42", + "0x43", + "0x44", + "0x45", + "0x46", + "0x47", + "0x48", + "0xcb", + "0xbc", + "0x97", + "0xae", + "0x1ae", + "0xec", + "0xf3", + "0x19b", + "0x195", + "0x186", + "0x10e", + "0x115", + "0x173", + "0x16b", + "0x164", + "0x13f", + "0x49", + "0x4a", + "0x4c", + "0x4d", + "0x4e", + "0x156", + "0x4f", + "0x50", + "0x51", + "0x52", + "0x53", + "0x54", + "0x55", + "0x56", + "0x58", + "0x59", + "0x5b", + "0x5c", + "0x5d", + "0x5e", + "0x5f", + "0x60", + "0x61", + "0x62", + "0x63", + "0x17a", + "0x64", + "0x65", + "0x66", + "0x67", + "0x68", + "0x6a", + "0x6b", + "0x6c", + "0x6d", + "0x6e", + "0x6f", + "0x70", + "0x71", + "0x72", + "0x73", + "0x74", + "0x75", + "0x76", + "0x1a2", + "0x77", + "0x78", + "0x79", + "0x7a", + "0x7b", + "0x7c", + "0x7d", + "0x7e", + "0x7f", + "0x80", + "0x81", + "0x82", + "0x83", + "0x84", + "0x2e5", + "0x1d2", + "0x1d9", + "0x2d0", + "0x2c9", + "0x2b8", + "0x1f5", + "0x1fc", + "0x2a3", + "0x299", + "0x290", + "0x228", + "0x27f", + "0x271", + "0x25f", + "0x254", + "0x85", + "0x86", + "0x87", + "0x88", + "0x89", + "0x2ac", + "0x8a", + "0x8b", + "0x8c", + "0x8d", + "0x8e", + "0x8f", + "0x90", + "0x91", + "0x92", + "0x93", + "0x94", + "0x95", + "0x96", + "0x98", + "0x99", + "0x9a", + "0x9b", + "0x9c", + "0x2d9", + "0x9d", + "0x9e", + "0x9f", + "0xa0", + "0xa1", + "0xa2", + "0xa3", + "0xa4", + "0xa5", + "0xa6", + "0xa7", + "0xa8", + "0xa9", + "0xaa", + "0x3f6", + "0x30b", + "0x312", + "0x3e1", + "0x3da", + "0x3c9", + "0x32e", + "0x335", + "0x3b4", + "0x3aa", + "0x3a1", + "0x361", + "0x390", + "0x385", + "0x3bd", + "0x3ea", + "0x44b", + "0x419", + "0x429", + "0x430", + "0x43f", + "0xda", + "0x1bd", + "0x2f6", + "0x407", + "0x2483", + "0x180a04018401e070281c0a0e05034180b050241005038180a04018080200", + "0x14281c03014361a0806420180b81428150b0142815030142813080482207", + "0x9c1426040404a240288c141e040880a140e0840a1b0d0800a1f05078101d", + "0xb45405160145805150145205158140c05030140c05150145205140140c05", + "0xd00a33050c81029028c00a06028c4142e040a00a30028c00a2f050b81010", + "0x14760a1d03072070301408030301470371b0142815030145005140146a05", + "0xfc143a060740a3e0282c143a040f41409040f00a2a0282c143a0401c0a1d", + "0x140803038140c05220281a0c038148605210281a0c030142815208148005", + "0x1200e0602810062a0282c141e0411c0e06028100646038180a04019140e06", + "0x28a40a28828a04f011389a0703014080320814980525828740c011282049", + "0x1540c05029640c05029600c050295cac05029541405029545405029501453", + "0x180a052e8180a052a9700a052d8180a052d10c0a052c8800a052c8800a05", + "0x140a5505188c00502954c205029540a07300140e5f208140a5e1f0140a5e", + "0x1800a072f9300a052f0a80a052f0740a052c8740a05331940a052d828c863", + "0x140e5f030140a6b051a8540502964d2050296cd0050296cce050296c1407", + "0x28e00a379b00a05370140e6c0281cbe0702814bc0a369b00a052a8280e6c", + "0x140a55388140a6e0281ce2050397ce205029541407388140e5f140140a59", + "0x14b60702814b23c02814dc4002814a87502814dc7439814e41d02814aa2a", + "0x1646c05029506c0502960f60502954147a030140a79051e00c05029dcec05", + "0x29028002814b27402814b67f02814b20a3f028fa0a3e0d40a052c8d00a05", + "0x17814071e0140e5f030140a840520ce605029541407398140e5f410140a59", + "0x1cbe05038f00a072f8290a0502814b67502814aa0a039d40a072f9000a05", + "0x1c147f0301d10744101d0e07028280e05050290e050502814860281cea05", + "0x150e0541014e80a1a0150e0539815040a1a8150e053a014e60a0521c0a0a", + "0x290e050501c141d02a24522803a1c0e34029fc143502a1c0a35028181482", + "0xa00a28050290e0515014680a150150e05148146a0a100150e051a814e60a", + "0x280e0a1581514241101d0e0714014fe0a100150e05100140c0a140150e05", + "0x281487028580a34050580a87028900a35050b00a87028800a73050290e05", + "0x840a4c0b8c00e87038880a7f050b00a87028b00a06050880a87028880a28", + "0x150e0516014e60a0521c0a1702874140a438146005148281487028280e0a", + "0x1ec0e24052000a8702a000a22052000a8702828540a3d8150e05050801436", + "0x21c0a4002858144002a1c0a761e01c580a1e0150e05050ac147602a1c0a80", + "0x280e05438140e05180286c05438146c050302904054381504053a0287c05", + "0x281487028840a29050290e050501c143e038d90482028f80a87028f80a17", + "0x14ea051b028820543814820503028ea05438141421051040a87028b00a73", + "0x14e60a0521c0a0a03828d26c03a2ce24303a1c0e7520a08e67b051d40a87", + "0x1300a87029300a22051300a8702829000a338150e0505080146802a1c0a71", + "0x100140a43814c6051e028c26303a1c0a65029d8146502a1c0a4c3381c480a", + "0x1486053a028ac0543814b80520828b80543814c0051f028c00543814c205", + "0x1580a87029580a170501c0a870281c0a30051a00a87029a00a060510c0a87", + "0x2300a8702828400a000150e0534814e60a0521c0a0a03828ac073410d0405", + "0x28560a470150e0546a300e24052340a8702a340a22052340a8702828ea0a", + "0x21c0a6c029d0149102a1c0a9002858149002a1c0a8e4781c580a478150e05", + "0x1522054381522050b8280e05438140e0518028000543814000503028d805", + "0x292405438144005398281487028ac0a29050290e050501c149103800d882", + "0x15289303890149402a1c0a9402888149402a1c0a0a218292605438141420", + "0x2600a8702a5c0a160525c0a8702a552c07160292c0543814142b052540a87", + "0x142e0a038150e0503814600a490150e05490140c0a410150e0541014e80a", + "0x14e60a0521c0a1d028a4140a438141407052600e92412080a9802a1c0a98", + "0x22c0a8702a2c0a220522c0a8702828e20a4d0150e0505080149902a1c0a35", + "0x58149d02a1c0a9b4e01c580a4e0150e05050ac149b02a1c0a8b4d01c480a", + "0x140e051802932054381532050302904054381504053a0293c05438153a05", + "0x1cc0a6c050290e050501c149e03a65048202a780a8702a780a170501c0a87", + "0x8814a102a1c0a0a3a82940054381414200527c0a87029fc0a73050290e05", + "0x289460716029460543814142b052880a8702a854007120294205438154205", + "0x150e054f8140c0a030150e0503014e80a528150e05520142c0a520150e05", + "0x14140a052940e9f032080aa502a1c0aa50285c140702a1c0a07028c0149f", + "0x14e805398281487028280e0a3f8180ea63a2080e87038141407028281487", + "0xd40a87028d40a06052080a8702a080a74050d00a87029cc0a82050d40a87", + "0x284005438146a05398281487028280e0a0e8154e291401d0e071a014fe0a", + "0x144005030285005438145005140281487028a80a34050a80a87028a40a35", + "0x21c0a22028a4140a438141407050ac0aa8120880e87038a00a7f050800a87", + "0x14142a050580a8702828400a160150e0510014e60a0521c0a2402874140a", + "0x840a8702828560a0b8150e05180580e24050c00a87028c00a22050c00a87", + "0x18148202a1c0a82029d0147b02a1c0a3602858143602a1c0a171081c580a", + "0x1c588241014f60543814f6050b8280e05438140e05180285805438145805", + "0x21c0a0a108290005438144005398281487028ac0a29050290e050501c147b", + "0x1d0e073b20104733d828ec0543814ec051b029000543815000503028ec05", + "0x10c0a8702828400a3a8150e0520014e60a0521c0a0a03828823e03aa4803c", + "0x14ec0a360150e053890c0e24051c40a87029c40a22051c40a8702829000a", + "0x21c0a67028f8146702a1c0a6802900140a43814d2051e028d06903a1c0a6c", + "0x28ea0543814ea050302878054381478053a028ca05438149805208289805", + "0x290e050501c1465039d47882029940a87029940a170501c0a870281c0a30", + "0x14c00511028c005438141475051840a8702828400a318150e0520814e60a", + "0x150e052e1580e2c051580a8702828560a2e0150e05301840e24051800a87", + "0xc0146302a1c0a6302818143e02a1c0a3e029d0148c02a1c0a00028581400", + "0x281487028280e0a4601cc63e4101518054381518050b8280e05438140e05", + "0x150e05051c4148e02a1c0a0a100291a05438146a05398281487028740a29", + "0xb0149102a1c0a0a158292005438151e8e03890148f02a1c0a8f02888148f", + "0x2340a06052080a8702a080a740524c0a8702a480a16052480a8702a412207", + "0x29260746a090405498150e05498142e0a038150e0503814600a468150e05", + "0x2540a8702828400a4a0150e053f814e60a0521c0a73029b0140a438141407", + "0x28560a4b8150e054b2540e24052580a8702a580a22052580a8702828ea0a", + "0x21c0a06029d0149a02a1c0a9902858149902a1c0a974c01c580a4c0150e05", + "0x1534054381534050b8280e05438140e05180292805438152805030280c05", + "0x1c147f0301d54744101d0e07028280e05050290e0505028149a03a500c82", + "0x28148702828d20a1a0150e0539815040a1a8150e053a014e60a0521c0a0a", + "0x740aab148a00e87038d00a7f050d40a87028d40a06052080a8702a080a74", + "0x1454053402854054381452051a8284005438146a05398281487028280e0a", + "0xb00a87028a00a28050ac0a87028800a06050900a87028880a67050880a87", + "0x150e051a814e60a0521c0a0a0382814ac02828ca0a0b0150e0512014980a", + "0x14500a158150e05180140c0a108150e050b814c20a0b8150e050518c1430", + "0x280e0a3d8155a3602a1c0e1602980141602a1c0a2102930142c02a1c0a1d", + "0x158148002a1c0a8002818148002a1c0a2b029cc140a43814145c050290e05", + "0x14e60a0521c0a3c02800140a438141407051000aae1e1d80e87038d90407", + "0x21c0e2c029fc143e02a1c0a3e02818147602a1c0a76029d0143e02a1c0a80", + "0x150e053a8146a0a388150e051f014e60a0521c0a0a038288605579d48207", + "0x14e20503028820543814820514028148702828d20a0521c0a6c028d0146c", + "0x21c0a71029cc140a4381414070519c0ab0341a40e87039040a7f051c40a87", + "0x28c20543814d20514028c60543814980503028ca0543814d005460289805", + "0x1700a87029c40a73050290e050501c140a588141465051800a87029940a8d", + "0x19c0a280518c0a87029700a06050000a87029580a8e051580a8702828c60a", + "0x141407052340ab2460150e07300151e0a300150e05000151a0a308150e05", + "0x28400a478150e05460146a0a470150e0531814e60a0521c0a0a2e0281487", + "0x150e053b014e80a490150e0547814d00a488150e0530814800a480150e05", + "0x88149002a1c0a9002a44149102a1c0a9102a40148e02a1c0a8e028181476", + "0x150e074a815260a4aa51267343815249048a38ec74490292405438152405", + "0x2693207438152c054a0293005438152805398281487028280e0a4b8156696", + "0xf0140a4381414070526c0ab4458150e074d0152a0a4c0150e054c0140c0a", + "0x21c0a9c02818149d02a1c0a9902a08149c02a1c0a98029cc140a438151605", + "0x290e054f014520a0521c0a0a0382940055aa7d3c074381d3a053f8293805", + "0x21c0a0a150294405438141420052840a8702a700a73050290e054f8143a0a", + "0x294a0543814142b052900a8702a8d4407120294605438154605110294605", + "0x140c0a498150e0549814e80a5b8150e055b0142c0a5b0150e05522940e2c", + "0x2dc0ea149a080ab702a1c0ab70285c140702a1c0a07028c014a102a1c0aa1", + "0x150e0505084148a02a1c0a9c029cc140a438154005148281487028280e0a", + "0x2e40e8703ae11493399ec14b802a1c0ab8028d8148a02a1c0a8a0281814b8", + "0x297e05438141420052f80a8702ae80a73050290e050501c14bd5e01d76ba", + "0x3040a76053040a8702b017e07120298005438158005110298005438141480", + "0x150e05278147c0a278150e0561814800a0521c0ac2028f014c36101d0e05", + "0xc014be02a1c0abe0281814b902a1c0ab9029d014c502a1c0ac40290414c4", + "0x281487028280e0a6281d7cb9410158a05438158a050b8280e05438140e05", + "0x21c0ac70288814c702a1c0a0a3a8298c05438141420052240a8702af40a73", + "0x3280a8702b21920716029920543814142b053200a8702b1d8c07120298e05", + "0x14600a448150e05448140c0a5e0150e055e014e80a658150e05650142c0a", + "0x258140a4381414070532c0e895e2080acb02a1c0acb0285c140702a1c0a07", + "0x150e0549814e80a660150e054c014e60a0521c0a99029b0140a438153605", + "0x21c0a94029cc140a438141407050299e050519414ce02a1c0acc0281814cd", + "0x29a00543815a0050302926054381526053a029a205438152e050b029a005", + "0x290e050501c14d103b41268202b440a8702b440a170501c0a870281c0a30", + "0x150e0531814e60a0521c0a61028a4140a438151a054b028148702828b80a", + "0x292e0a698150e050508014ce02a1c0ad20281814cd02a1c0a76029d014d2", + "0x150e05050ac148802a1c0ad46981c480a6a0150e056a014440a6a0150e05", + "0x299a05438159a053a029ae0543815ac050b029ac054381510d5038b014d5", + "0x3399a8202b5c0a8702b5c0a170501c0a870281c0a30053380a8702b380a06", + "0x141420053600a87028f80a73050290e0521814520a0521c0a0a03829ae07", + "0x36c0a8702b69b20712029b40543815b40511029b405438141443053640a87", + "0x14e80a6f0150e056e8142c0a6e8150e056db700e2c053700a8702828560a", + "0x21c0ade0285c140702a1c0a07028c014d802a1c0ad802818147602a1c0a76", + "0x21c0a80029cc140a438145805148281487028280e0a6f01db07641015bc05", + "0x280e0a053880a0a32829c20543815be0503029c0054381480053a029be05", + "0xac0a73050290e0516014520a0521c0a7b02a58140a43814145c050290e05", + "0x3900a8702828400a708150e05718140c0a700150e0541014e80a718150e05", + "0x28560a730150e0572b900e24053940a8702b940a22053940a8702828e20a", + "0x21c0ae0029d014e902a1c0ae80285814e802a1c0ae67381c580a738150e05", + "0x15d20543815d2050b8280e05438140e0518029c20543815c20503029c005", + "0x29d40543814fe05398281487029cc0a6c050290e050501c14e903b85c082", + "0x15d8eb0389014ec02a1c0aec0288814ec02a1c0a0a3a829d605438141420", + "0x3c00a8702bbc0a16053bc0a8702bb5dc0716029dc0543814142b053b40a87", + "0x142e0a038150e0503814600a750150e05750140c0a030150e0503014e80a", + "0x264147f02a1c0a0a4c028e805438141498053c00eea032080af002a1c0af0", + "0x280e0a148a00ef11a0d40e8703814140702828148702828140a0521c0a0a", + "0x1d0140a438141469050800a87029cc0a82050740a87028d00a73050290e05", + "0x2848057908854074381c40053f8283a05438143a05030286a05438146a05", + "0x21c0a2c029a0142c02a1c0a22028d4142b02a1c0a1d029cc140a438141407", + "0x284205438145405140282e05438145605030286005438142c05338282c05", + "0x1ec0a87028740a73050290e050501c140a798141465050d80a87028c00a4c", + "0x900a280505c0a87029ec0a06051d80a8702a000a61052000a8702828c60a", + "0x141407050f00af4030150e071b014c00a1b0150e053b014980a108150e05", + "0x18140602a1c0a063f81d340a200150e050b814e60a0521c0a0a2e0281487", + "0x1cc140a438141407051d40af5208f80e87038186a072b0288005438148005", + "0x1c42053f8288605438148605030287c05438147c053a0288605438148005", + "0x21c0a6c028d4146802a1c0a43029cc140a438141407051a40af6361c40e87", + "0xa0140a4381414690519c0a8702a080a68052080a8702a08e8074d0290405", + "0x28c6057b99498074381ce2053f828d00543814d00503028e20543814e205", + "0x21c0a6102818146002a1c0a6502a30146102a1c0a68029cc140a438141407", + "0x280e0a053e00a0a32828000543814c00546828ac0543814980514028b805", + "0x291c05438151a05470291a05438141463052300a87029a00a73050290e05", + "0xa8f050000a8702a380a8d051580a870298c0a28051700a8702a300a06", + "0x2440a87029700a73050290e0505170140a438141407052400af9478150e07", + "0x2480a68052500a87029580a400524c0a8702828400a490150e05478146a0a", + "0x150e054a015200a488150e05488140c0a1f0150e051f014e80a4a8150e05", + "0x21c0a9549a51223e3a248149502a1c0a9502888149302a1c0a9302a441494", + "0x21c0a97029cc140a438141407052680afa4c8150e074c015260a4c25d2c73", + "0x2740a8703a700a950522c0a8702a2c0a060527136074381532054a0291605", + "0x1814a002a1c0a9b02a08149f02a1c0a8b029cc140a438141407052780afb", + "0x14520a0521c0a0a0382946057e28942074381d40053f8293e05438153e05", + "0x140a43814ce051a028148702a740a3c050290e05510143a0a0521c0aa1", + "0x2d80a8702828540a528150e050508014a402a1c0a9f029cc140a438148205", + "0x1c580a450150e05050ac14b702a1c0ab65281c480a5b0150e055b014440a", + "0x154805030292c05438152c053a02972054381570050b0297005438156e8a", + "0x1c14b903a912c8202ae40a8702ae40a170501c0a870281c0a30052900a87", + "0x297805438141421052e80a8702a7c0a73050290e0551814520a0521c0a0a", + "0x3f57cbd03a1c0ebc5d258e67b052f00a8702af00a36052e80a8702ae80a06", + "0x1d014c102a1c0ac10281814c102a1c0abe029cc140a438141407053017e07", + "0x21c0a0a0382912c5621cdfc4f61b08e6870381d8207458297a05438157a05", + "0x270144f02a1c0a4f02a6c14c602a1c0ac2029cc14c202a1c0ac202818140a", + "0x27c140a4381590054f02998cb653259074438158e054e8298e05438149e05", + "0x3340a8702b280aa0050290e0566014680a0521c0acb02800140a438159205", + "0x15420a630150e05630140c0a618150e0561814600a668150e0566814440a", + "0x21c0a9d029d814d002a1c0ac6029cc140a438141407053380aff0521c0ecd", + "0x29a00543815a00503029a60543815a40520028148702b440a3c05349a207", + "0x140c0a0521c0a0a03829b0d76b1ce00d544350e68703b4cce4161b40e8a2", + "0x21c0ada0290414da02a1c0ad5028f814d902a1c0ad4029cc14d402a1c0ad4", + "0x29100543815100518029b20543815b205030297a05438157a053a029b605", + "0x3580a8702b580a06050290e050501c14db443657a8202b6c0a8702b6c0a17", + "0x142c0a6f0150e056c3740e2c053740a8702828560a6e0150e056b014e60a", + "0x21c0ad7028c014dc02a1c0adc0281814bd02a1c0abd029d014df02a1c0ade", + "0x159c05518281487028280e0a6fb5db8bd41015be0543815be050b829ae05", + "0x3180a73050290e0520814000a0521c0a67028d0140a438153a051e0281487", + "0x29c60543815c60511029c6054381414a4053840a8702828400a700150e05", + "0x142c0a730150e05723940e2c053940a8702828560a720150e0571b840e24", + "0x21c0ac3028c014e002a1c0ae00281814bd02a1c0abd029d014e702a1c0ae6", + "0x153a051e0281487028280e0a73b0dc0bd41015ce0543815ce050b8298605", + "0x14e60a620150e05620140c0a0521c0a4102800140a43814ce051a0281487", + "0x21c0aea0285814ea02a1c0a897481c580a748150e05050ac14e802a1c0ac4", + "0x298a05438158a0518029d00543815d005030297a05438157a053a029d605", + "0x28148702a740a3c050290e050501c14eb62ba17a8202bac0a8702bac0a17", + "0x150e050508014ec02a1c0ac0029cc140a4381482050002814870299c0a34", + "0xac14ef02a1c0aee7681c480a770150e0577014440a770150e05051d414ed", + "0x157e053a02a04054381602050b02a020543815def0038b014f002a1c0a0a", + "0x4080a8702c080a170501c0a870281c0a30053b00a8702bb00a06052fc0a87", + "0x28148702a6c0a6c050290e054f0152c0a0521c0a0a0382a0407762fd0405", + "0x21c0a96029d0150302a1c0a8b029cc140a4381482050002814870299c0a34", + "0x148205000281487028280e0a054180a0a3282a0a054381606050302a0805", + "0x1d0150802a1c0a9a02858150702a1c0a97029cc140a43814ce051a0281487", + "0x1610050b8280e05438140e051802a0e05438160e05030292c05438152c05", + "0x21c0a9002a58140a43814145c050290e050501c150803c1d2c8202c200a87", + "0x14b805398281487029580a29050290e0520814000a0521c0a67028d0140a", + "0x2a1405438141420054140a8702c240a06054100a87028f80a74054240a87", + "0x14142b054300a8702c2e14071202a16054381616051102a1605438141497", + "0x150e0582014e80a878150e05870142c0a870150e05864340e2c054340a87", + "0x2080b0f02a1c0b0f0285c140702a1c0a07028c0150502a1c0b05028181504", + "0x154a0a0521c0a4102800140a43814d205148281487028280e0a8781e0b04", + "0x2a2405438141443054440a8702828400a880150e0521814e60a0521c0a74", + "0x2a00e2c052a00a8702828560a898150e05894440e24054480a8702c480a22", + "0x21c0b1002818143e02a1c0a3e029d0151502a1c0b1402858151402a1c0b13", + "0x280e0a8a81e203e410162a05438162a050b8280e05438140e051802a2005", + "0x1d0151602a1c0a40029cc140a43814e805528281487028840a29050290e05", + "0x281487028280e0a054640a0a3282a3005438162c050302a2e0543814ea05", + "0x281487029d00aa5050290e0510814520a0521c0a3c02a58140a43814145c", + "0x1634050302a2e05438146a053a02a3405438142e05398281487029fc0aa5", + "0x90151c02a1c0b1c02888151c02a1c0a0a3882a3605438141420054600a87", + "0x47c0a160547c0a8702c763c071602a3c0543814142b054740a8702c723607", + "0x150e0503814600a8c0150e058c0140c0a8b8150e058b814e80a900150e05", + "0x21c0a7f02a94140a438141407054800f188ba080b2002a1c0b200285c1407", + "0x141420054840a87028a40a73050290e0539814d80a0521c0a7402a94140a", + "0x4900a8702c8e44071202a46054381646051102a4605438141475054880a87", + "0x14e80a938150e05930142c0a930150e05924940e2c054940a8702828560a", + "0x21c0b270285c140702a1c0a07028c0152102a1c0b2102818142802a1c0a28", + "0x21c0a0a4c828fe05438141498051d00a8702829300a9381e4228410164e05", + "0x290e050501c14291401e50341a81d0e07028280e05050290e0505028140a", + "0x146a053a028148702828d20a100150e0539815040a0e8150e051a014e60a", + "0x141407050900b29110a80e87038800a7f050740a87028740a06050d40a87", + "0x282c054381458053402858054381444051a8285605438143a05398281487", + "0xc00a4c050840a87028a80a280505c0a87028ac0a06050c00a87028580a67", + "0x28c60a3d8150e050e814e60a0521c0a0a03828152a02828ca0a1b0150e05", + "0x150e0512014500a0b8150e053d8140c0a3b0150e0540014c20a400150e05", + "0x281487028280e0a1e016568202a1c0e3602980143602a1c0a76029301421", + "0x14800503029040543815047403a68144002a1c0a17029cc140a43814145c", + "0x148005398281487028280e0a3a81658411f01d0e07410d40eb6051000a87", + "0x1c40e87038840a7f0510c0a870290c0a06050f80a87028f80a740510c0a87", + "0x280c0543814d8051a828d005438148605398281487028280e0a348165a6c", + "0x14e20514028148702828d20a338150e0503014d00a030150e05031fc0e9a", + "0x1414070518c0b2e329300e87039c40a7f051a00a87029a00a06051c40a87", + "0x28b80543814c20503028c00543814ca0546028c20543814d005398281487", + "0x290e050501c140a978141465050000a87029800a8d051580a87029300a28", + "0x2300a06052380a8702a340a8e052340a8702828c60a460150e0534014e60a", + "0x150e07000151e0a000150e05470151a0a2b0150e0531814500a2e0150e05", + "0x146a0a488150e052e014e60a0521c0a0a2e0281487028280e0a48016608f", + "0x150e0549014d00a4a0150e052b014800a498150e0505080149202a1c0a8f", + "0x244149402a1c0a9402a40149102a1c0a9102818143e02a1c0a3e029d01495", + "0x25d2c73438152a934a2447c74490292a05438152a05110292605438152605", + "0x291605438152e05398281487028280e0a4d016629902a1c0e9802a4c1498", + "0x2780b324e8150e074e0152a0a458150e05458140c0a4e26c0e8702a640a94", + "0x153e05030294005438153605410293e05438151605398281487028280e0a", + "0x21c0aa1028a4140a4381414070528c0b33512840e8703a800a7f0527c0a87", + "0x14ce051a028148702a740a3c050290e05208156e0a0521c0aa202874140a", + "0x14440a5b0150e05050a814a502a1c0a0a100294805438153e05398281487", + "0x156e8a038b0148a02a1c0a0a158296e05438156ca50389014b602a1c0ab6", + "0x2900a8702a900a06052580a8702a580a74052e40a8702ae00a16052e00a87", + "0x21c0a0a0382972075225904055c8150e055c8142e0a038150e0503814600a", + "0x2e80a06052f00a8702828420a5d0150e054f814e60a0521c0aa3028a4140a", + "0x3017e079a2f97a074381d78ba4b1ccf60a5e0150e055e0146c0a5d0150e05", + "0x3080a3c0530d8407438153a053b0298205438157c05398281487028280e0a", + "0x298a05438158605200298805438149e05450289e05438141463050290e05", + "0x3040cb9052f40a8702af40a74053100a8702b100ab8053040a8702b040a06", + "0x3200a6c050290e050501c14cb65324e7356431d8c894121c0ec46299c8207", + "0x299a05438141420053300a8702a240a73052240a8702a240a06050290e05", + "0x14ec0a680150e05673340e24053380a8702b380a22053380a8702b1c0aa0", + "0x21c0ad3028f814d302a1c0ad202900140a43815a2051e029a4d103a1c0ad0", + "0x299805438159805030297a05438157a053a029100543815a80520829a805", + "0x290e050501c1488633317a8202a200a8702a200a17053180a8702b180a30", + "0x3580e2c053580a8702828560a6a8150e0564814e60a648150e05648140c0a", + "0x21c0ad50281814bd02a1c0abd029d014d802a1c0ad70285814d702a1c0acb", + "0x280e0a6c329aabd41015b00543815b0050b829940543815940518029aa05", + "0x14e60a0521c0a67028d0140a438153a051e0281487029040ab7050290e05", + "0x36c0a8702b6c0a220536c0a8702828ea0a6d0150e050508014d902a1c0ac0", + "0x5814de02a1c0adc6e81c580a6e8150e05050ac14dc02a1c0adb6d01c480a", + "0x140e0518029b20543815b205030297e05438157e053a029be0543815bc05", + "0x2780a96050290e050501c14df03b657e8202b7c0a8702b7c0a170501c0a87", + "0x14e60a0521c0a67028d0140a4381482055b828148702a6c0a6c050290e05", + "0x2a6c050519414e302a1c0ae00281814e102a1c0a96029d014e002a1c0a8b", + "0x150e054b814e60a0521c0a4102adc140a43814ce051a0281487028280e0a", + "0xc014e402a1c0ae402818149602a1c0a96029d014e502a1c0a9a0285814e4", + "0x281487028280e0a7281dc89641015ca0543815ca050b8280e05438140e05", + "0x2814870299c0a34050290e05208156e0a0521c0a9002a58140a43814145c", + "0x15cc0503029c205438147c053a029cc0543814b805398281487029580a29", + "0x9014e802a1c0ae80288814e802a1c0a0a4b829ce054381414200538c0a87", + "0x3ac0a16053ac0a8702ba5d40716029d40543814142b053a40a8702ba1ce07", + "0x150e0503814600a718150e05718140c0a708150e0570814e80a760150e05", + "0x21c0a69028a4140a438141407053b00ee370a080aec02a1c0aec0285c1407", + "0x141420053b40a870290c0a73050290e053f8154a0a0521c0a4102adc140a", + "0x3c00a8702bbddc0712029de0543815de0511029de05438141443053b80a87", + "0x14e80a818150e05810142c0a810150e05784040e2c054040a8702828560a", + "0x21c0b030285c140702a1c0a07028c014ed02a1c0aed02818143e02a1c0a3e", + "0x21c0a21028a4140a43814fe05528281487028280e0a8181dda3e410160605", + "0x194150702a1c0b0402818150502a1c0a75029d0150402a1c0a40029cc140a", + "0x1fc0aa5050290e051e0152c0a0521c0a0a2e0281487028280e0a054dc0a0a", + "0x1d0150802a1c0a17029cc140a43814e805528281487028840a29050290e05", + "0x150e05051c4150902a1c0a0a1002a0e054381610050302a0a05438146a05", + "0xb0150c02a1c0a0a1582a160543816150903890150a02a1c0b0a02888150a", + "0x41c0a06054140a8702c140a74054380a8702c340a16054340a8702c2e1807", + "0x2a1c0783c150405870150e05870142e0a038150e0503814600a838150e05", + "0x281487029cc0a6c050290e053a0154a0a0521c0a7f02a94140a438141407", + "0x21c0b1102888151102a1c0a0a3a82a20054381414200543c0a87028a40a73", + "0x2a00a8702c4a26071602a260543814142b054480a8702c4620071202a2205", + "0x14600a878150e05878140c0a140150e0514014e80a8a0150e05540142c0a", + "0x14140a43814145c054500f0f142080b1402a1c0b140285c140702a1c0a07", + "0x286805438140c05398281487028280e0a1a9fc0f38031d00e87038141407", + "0x15420a1a0150e051a0140c0a3a0150e053a014e80a142080e8702a080aba", + "0x150e051a014e60a0521c0a82028d0140a438141407050a40b390521c0e28", + "0x2844054381454055f028540543814400703af4142002a1c0a7302af0141d", + "0x74e873028880a87028880abf050740a87028740a06051d00a87029d00a74", + "0x140e05410284805438146805398281487028a40aa3050290e050501c1422", + "0x4e82c2c03a1c0e2b029fc142402a1c0a2402818140a438141469050ac0a87", + "0x14d00a108150e050b0146a0a0b8150e0512014e60a0521c0a0a038286005", + "0x21c0a2c028a0148002a1c0a1702818147b02a1c0a360299c143602a1c0a21", + "0x144805398281487028280e0a054ec0a0a32828780543814f60526028ec05", + "0x290005438148005030288205438147c05308287c05438141463051000a87", + "0xf00a60051d40a87029d80a40050f00a87029040a4c051d80a87028c00a28", + "0x1b00a8702a000a73050290e0505170140a438141407051c40b3c218150e07", + "0x1d0146702a1c0a684101d820a340150e0505300146902a1c0a433981c480a", + "0x14d20548828ea0543814ea0548028d80543814d80503028e80543814e805", + "0x1cc0a6332930e6870299cd275361d0e8920519c0a870299c0a22051a40a87", + "0x14e6051e028148702a080a34050290e0505170140a4381414070518cca4c", + "0x1700a8702980ea075e828c00543814e20561028c205438150005398281487", + "0x157e0a308150e05308140c0a3a0150e053a014e80a2b0150e052e0157c0a", + "0x1cc0a3c050290e0541014680a0521c0a0a03828ac613a1cc0a5602a1c0a56", + "0x1d4148c02a1c0a0a100280005438146a053982814870281c0a6c050290e05", + "0x21c0a0a158291c05438151a8c03890148d02a1c0a8d02888148d02a1c0a0a", + "0x1fc0a87029fc0a74052440a8702a400ac3052400a8702a391e07160291e05", + "0xa8c256052080c91001fce605488150e05488157e0a000150e05000140c0a", + "0x2904e43981c0a0a30184ac0a410a8c256052081473038141460309581482", + "0x1cc0e0505180c2560520854612b029053d3981c0a0a30184ac0a410a8c256", + "0x28ea56051cc0c1d1515814749f9cc0e0505180c2560520854612b029053e", + "0x140411cc0e05" + ], + "sierra_program_debug_info": { + "type_names": [], + "libfunc_names": [], + "user_func_names": [] + }, + "contract_class_version": "0.1.0", + "entry_points_by_type": { + "EXTERNAL": [ + { + "selector": "0x15d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad", + "function_idx": 3 + }, + { + "selector": "0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775", + "function_idx": 2 + }, + { + "selector": "0x2730079d734ee55315f4f141eaed376bddd8c2133523d223a344c5604e0f7f8", + "function_idx": 4 + }, + { + "selector": "0x289da278a8dc833409cabfdad1581e8e7d40e42dcaed693fa4008dcdb4963b3", + "function_idx": 1 + }, + { + "selector": "0x36fcbf06cd96843058359e1a75928beacfac10727dab22a3972f0af8aa92895", + "function_idx": 0 + } + ], + "L1_HANDLER": [], + "CONSTRUCTOR": [] + }, + "abi": [ + { + "type": "function", + "name": "__validate_deploy__", + "inputs": [ + { + "name": "class_hash", + "type": "core::felt252" + }, + { + "name": "contract_address_salt", + "type": "core::felt252" + } + ], + "outputs": [ + { + "type": "core::felt252" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "__validate_declare__", + "inputs": [ + { + "name": "class_hash", + "type": "core::felt252" + } + ], + "outputs": [ + { + "type": "core::felt252" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "__validate__", + "inputs": [ + { + "name": "contract_address", + "type": "core::starknet::contract_address::ContractAddress" + }, + { + "name": "selector", + "type": "core::felt252" + }, + { + "name": "calldata", + "type": "core::array::Array::" + } + ], + "outputs": [ + { + "type": "core::felt252" + } + ], + "state_mutability": "view" + }, + { + "type": "struct", + "name": "core::array::Span::", + "members": [ + { + "name": "snapshot", + "type": "@core::array::Array::" + } + ] + }, + { + "type": "function", + "name": "__execute__", + "inputs": [ + { + "name": "contract_address", + "type": "core::starknet::contract_address::ContractAddress" + }, + { + "name": "selector", + "type": "core::felt252" + }, + { + "name": "calldata", + "type": "core::array::Array::" + } + ], + "outputs": [ + { + "type": "core::array::Span::" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "deploy_contract", + "inputs": [ + { + "name": "class_hash", + "type": "core::starknet::class_hash::ClassHash" + }, + { + "name": "contract_address_salt", + "type": "core::felt252" + }, + { + "name": "calldata", + "type": "core::array::Array::" + } + ], + "outputs": [ + { + "type": "core::starknet::contract_address::ContractAddress" + } + ], + "state_mutability": "view" + }, + { + "type": "event", + "name": "account_with_dummy_validate::account_with_dummy_validate::Account::Event", + "kind": "enum", + "variants": [] + } + ] +} diff --git a/crates/blockifier_test_utils/resources/feature_contracts/cairo1/sierra/account_with_long_validate.sierra.json b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/sierra/account_with_long_validate.sierra.json new file mode 100644 index 00000000000..7c7a730432e --- /dev/null +++ b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/sierra/account_with_long_validate.sierra.json @@ -0,0 +1,869 @@ +{ + "sierra_program": [ + "0x1", + "0x7", + "0x0", + "0x2", + "0xb", + "0x0", + "0x14c", + "0xb4", + "0x34", + "0x52616e6765436865636b", + "0x800000000000000100000000000000000000000000000000", + "0x436f6e7374", + "0x800000000000000000000000000000000000000000000002", + "0x1", + "0xa", + "0x2", + "0x3", + "0x0", + "0x753332", + "0x800000000000000700000000000000000000000000000000", + "0x53746f7261676541646472657373", + "0x53746f726167654261736541646472657373", + "0x494e56414c49445f43414c4c4552", + "0x526573756c743a3a756e77726170206661696c65642e", + "0x426f78", + "0x800000000000000700000000000000000000000000000001", + "0x13", + "0x15", + "0x66656c74323532", + "0x436f6e747261637441646472657373", + "0x75313238", + "0x4172726179", + "0x800000000000000300000000000000000000000000000001", + "0x536e617073686f74", + "0xd", + "0x537472756374", + "0x800000000000000700000000000000000000000000000002", + "0x1baeba72e79e9db2587cf44fedb2f3700b2075a5e8e39a562584862c4b71f62", + "0xe", + "0x16", + "0x10", + "0x1597b831feeb60c71f259624b79cf66995ea4f7e383403583674ab9c33b9cec", + "0x11", + "0x80000000000000070000000000000000000000000000000e", + "0x348a62b7a38c0673e61e888d83a3ac1bf334ee7361a8514593d3d9532ed8b39", + "0xb", + "0xc", + "0xf", + "0x12", + "0x753634", + "0x800000000000000700000000000000000000000000000004", + "0x3808c701a5d13e100ab11b6c02f91f752ecae7e420d21b56c90ec0a475cc7e5", + "0x14", + "0x3342418ef16b3e2799b906b1e4e89dbb9b111332dd44f72458ce44f9895b508", + "0x800000000000000700000000000000000000000000000006", + "0x7d4d99e9ed8d285b5c61b493cedb63976bc3d9da867933d829f49ce838b5e7", + "0x9", + "0x8", + "0x17", + "0x556e696e697469616c697a6564", + "0x800000000000000200000000000000000000000000000001", + "0x496e646578206f7574206f6620626f756e6473", + "0x800000000000000f00000000000000000000000000000001", + "0x2ee1e2b1b89f8c495f200e4956278a4d47395fe262f27b52e5865c9524c08c3", + "0x456e756d", + "0x800000000000000300000000000000000000000000000003", + "0x17b6ecc31946835b0d9d92c2dd7a9c14f29af0371571ae74a1b228828b2242", + "0x1b", + "0x1c", + "0x16a4c8d7c05909052238a862d8cc3e7975bf05a07b3a69c6b28951083a6d672", + "0x1e", + "0x34f9bd7c6cb2dd4263175964ad75f1ff1461ddc332fbfb274e0fb2a5d7ab968", + "0x1d", + "0x1f", + "0x800000000000000700000000000000000000000000000003", + "0x29d7d57c04a880978e7b3689f6218e507f3be17588744b58dc17762447ad0e7", + "0x21", + "0x11c6d8087e00642489f92d2821ad6ebd6532ad1a3b6d12833da6d6810391511", + "0x4661696c656420746f20646573657269616c697a6520706172616d202331", + "0x4661696c656420746f20646573657269616c697a6520706172616d202332", + "0x4661696c656420746f20646573657269616c697a6520706172616d202333", + "0x4661696c656420746f20646573657269616c697a6520706172616d202334", + "0x4f7574206f6620676173", + "0x56414c4944", + "0x800000000000000f00000000000000000000000000000002", + "0xcc5e86243f861d2d64b08c35db21013e773ac5cf10097946fe0011304886d5", + "0x2b", + "0x989680", + "0x4e6f6e5a65726f", + "0x4275696c74696e436f737473", + "0x53797374656d", + "0x9931c641b913035ae674b400b61a51476d506bbe8bba2ff8a6272790aba9e6", + "0x29", + "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", + "0x4761734275696c74696e", + "0x65", + "0x7265766f6b655f61705f747261636b696e67", + "0x77697468647261775f676173", + "0x6272616e63685f616c69676e", + "0x72656465706f7369745f676173", + "0x7374727563745f6465636f6e737472756374", + "0x73746f72655f74656d70", + "0x33", + "0x61727261795f736e617073686f745f706f705f66726f6e74", + "0x756e626f78", + "0x64726f70", + "0x61727261795f6e6577", + "0x636f6e73745f61735f696d6d656469617465", + "0x32", + "0x61727261795f617070656e64", + "0x7374727563745f636f6e737472756374", + "0x656e756d5f696e6974", + "0x31", + "0x30", + "0x6765745f6275696c74696e5f636f737473", + "0x2f", + "0x77697468647261775f6761735f616c6c", + "0x72656e616d65", + "0x66656c743235325f69735f7a65726f", + "0x6a756d70", + "0x2e", + "0x2d", + "0x66756e6374696f6e5f63616c6c", + "0x5", + "0x656e756d5f6d61746368", + "0x2c", + "0x2a", + "0x736e617073686f745f74616b65", + "0x28", + "0x27", + "0x26", + "0x25", + "0x24", + "0x656e61626c655f61705f747261636b696e67", + "0x23", + "0x64697361626c655f61705f747261636b696e67", + "0x21adb5788e32c84f69a1863d85ef9394b7bf761a0ce1190f826984e5075c371", + "0x22", + "0x6", + "0x20", + "0x1a", + "0x616c6c6f635f6c6f63616c", + "0x66696e616c697a655f6c6f63616c73", + "0x73746f72655f6c6f63616c", + "0x6765745f657865637574696f6e5f696e666f5f76325f73797363616c6c", + "0x18", + "0x636f6e74726163745f616464726573735f746f5f66656c74323532", + "0x63616c6c5f636f6e74726163745f73797363616c6c", + "0x7", + "0x19", + "0x73746f726167655f626173655f616464726573735f636f6e7374", + "0x38077b29e57bba3aa860b08652a77bd1076d0f70e38f019ba9920b820cf78f6", + "0x73746f726167655f616464726573735f66726f6d5f62617365", + "0x4", + "0x73746f726167655f77726974655f73797363616c6c", + "0x647570", + "0x66656c743235325f737562", + "0x493", + "0xffffffffffffffff", + "0xb7", + "0xa8", + "0x99", + "0x8a", + "0x7a", + "0x35", + "0x6b", + "0x47", + "0x55", + "0x36", + "0x37", + "0x38", + "0x39", + "0x63", + "0x3a", + "0x3b", + "0x3c", + "0x3d", + "0x3e", + "0x3f", + "0x40", + "0x41", + "0x42", + "0x43", + "0x44", + "0x45", + "0x46", + "0x48", + "0x49", + "0x4a", + "0x4b", + "0x4c", + "0x4d", + "0x4e", + "0x4f", + "0x50", + "0x51", + "0x52", + "0x53", + "0x54", + "0x56", + "0x57", + "0x58", + "0x59", + "0x5a", + "0x5b", + "0x5c", + "0x5d", + "0x5e", + "0x5f", + "0x60", + "0x61", + "0x62", + "0x64", + "0x66", + "0x67", + "0x68", + "0x69", + "0x6a", + "0x6c", + "0x6d", + "0x6e", + "0x6f", + "0x12a", + "0x11b", + "0xe5", + "0x10d", + "0x105", + "0x23a", + "0x14b", + "0x152", + "0x227", + "0x221", + "0x212", + "0x16d", + "0x174", + "0x1ff", + "0x1f7", + "0x1f0", + "0x19e", + "0x1e1", + "0x1cf", + "0x1c7", + "0x1d9", + "0x70", + "0x71", + "0x72", + "0x73", + "0x74", + "0x75", + "0x76", + "0x77", + "0x78", + "0x79", + "0x7b", + "0x7c", + "0x7d", + "0x7e", + "0x206", + "0x7f", + "0x80", + "0x81", + "0x82", + "0x83", + "0x84", + "0x85", + "0x86", + "0x87", + "0x88", + "0x89", + "0x8b", + "0x8c", + "0x8d", + "0x8e", + "0x8f", + "0x90", + "0x91", + "0x22e", + "0x92", + "0x93", + "0x94", + "0x95", + "0x96", + "0x97", + "0x98", + "0x9a", + "0x9b", + "0x9c", + "0x9d", + "0x9e", + "0x9f", + "0x376", + "0x25e", + "0x265", + "0x361", + "0x35a", + "0x349", + "0x281", + "0x288", + "0x334", + "0x32a", + "0x321", + "0x2b4", + "0x310", + "0x302", + "0x2f0", + "0x2e0", + "0x33d", + "0x36a", + "0xa0", + "0xa1", + "0xa2", + "0xa3", + "0xa4", + "0xa5", + "0xa6", + "0xa7", + "0xa9", + "0xaa", + "0xab", + "0xac", + "0xad", + "0x406", + "0x3f7", + "0x3e8", + "0x3ae", + "0x3d9", + "0x3ce", + "0x431", + "0x427", + "0x483", + "0x451", + "0x461", + "0x468", + "0x477", + "0xc6", + "0x139", + "0x249", + "0x387", + "0x415", + "0x43f", + "0x26b5", + "0x380e0602810060b0682c180b050240e08028100605038180a04018080200", + "0x142219030143017058581615058502605088402405088401e07030140803", + "0x180a240488c362202884121c0d8800a110c87c0a180b8780a1d04870361a", + "0x6c1629138141005040144e05130145005030140c05030144e05130144a05", + "0xc40a30028bc122e0d8980a2c028180a2d048a83625028b00a2c028ac122a", + "0x2472381b8246c1b1a81c0c050200c0c051a0cc6405088400c05128144a05", + "0xe4701a028f80a37048e4363d048d8363c0289c0a37048e4363b028680a3a", + "0xc7605030148a09210e07605220148609210e00c05088408205200147e09", + "0x180a04019240e06028100648038180a040191c0e06028100646038180a04", + "0x149c052682472381d8146e092606c9607030140803138146e090e06c9407", + "0x180a04019040a540294c12391c008a40b288180a112813c0e06028100641", + "0x14be5e02814ba0902814ba2702814b8092d824b4092c824b05701158aa07", + "0x1888805029843c05029840c05029743c05029740c05029840c05029800c05", + "0x14ba05039a00a07339040a05330f80a05330180a05329900a05318180a05", + "0x18ce00502984126f049b80c05029b4126c358140a5d049a8d00502974d205", + "0x680a05308680a053b9d80a05319380a05309d40a053a1cc1005391c40a05", + "0x18cf4050298cf2050298cf0050298c1207340140e672a0140a66138140a66", + "0xec0a05331f80a052e8240e7e0281cce093e89c0a05309f00a05319ec0a05", + "0x140a5d0481d02050399c4a05029841280049fcfc05029d00a073f0140e67", + "0x20c0a053a2081005390680a052e89c0a052ea040a053a0140e810281cce81", + "0x140a851d8140a61420140a631f0140a61208140a5c1e0140a74200140a5c", + "0x14c23002814c23202814b83202814c08902814ba09440180a05438250c06", + "0x140a6304a411e0702a391a050298504050298d18050298c128b04a286205", + "0x14ba09039d40a07339380a05330180a0549825249102814ba0802814ba07", + "0x140e67200140a660481c78050399c0a073a8140e6704a500a050298cea05", + "0x2412960282412094a8140e830281cce05038f00a0733a0c0a052e8240e83", + "0xc40a96029cc0a08048252c050481c128c4101d2e734881d2c07028240e05", + "0x151809188152c05188150409488152c0548814e609180152c05040152209", + "0x940a31048680a96028c40a08048252c050481c122602a604a0603a580e30", + "0x680a96028680a82048180a96028180a06048252c050f01460090f0152c05", + "0x2450054b0143405040241296028240e091101532201381d2c07030151809", + "0x145005410244e054b0144e05030241296028480a30048480a96028800a31", + "0x2580a280282012094b01412070487c0a9a098b00e960389c0a8c048a00a96", + "0x2464054b01464054102458054b01458050302512054b0142605188246405", + "0x2012094b0141207048ec0a9b422340e96038b00a8c04a240a9602a240a25", + "0x2580a8d0281812094b01480051802480054b01508051882478054b0146405", + "0x2580a090382506054e1047c074b01d1a054602478054b0147805410251a05", + "0x14780504024129602a240a30048252c0520814340904a580a3e028981209", + "0x80127e02a580a7e02894127e02a580a091382502054b014121e049100a96", + "0x1e80a12049e80a96029f0f60714024f6054b0141222049f00a96029f90207", + "0x152c05038145809220152c05220150409488152c0548814e6093c8152c05", + "0x2580a830289812094b0141207049e40e4448a440a7902a580a790284c1207", + "0x1464093c0152c053c01504092a0152c050487c127802a580a3c028201209", + "0x241296028240e09389d40e9d271d80e9603950f09104224125402a580a54", + "0x1c00a82049d80a96029d80a73049ac0a9602a240a8d049c00a96029380a08", + "0x152c0538014100904a580a0903824d2054f0252c07358150809380152c05", + "0x141207048253e05048ec125e02a580a6802a08126402a580a76029cc1268", + "0x14e6094e0152c0504900120002a580a700282012094b014d2051e0241296", + "0x2700076040f8129c02a580a9c02894120002a580a0002a08127602a580a76", + "0x28c0a83048252c050481c12a502a9146054b01d44052082544a1500212c05", + "0x1780a9602a980a82049900a9602a800a7304a980a9602a840a08048252c05", + "0x2a14e071002550054b01550051282550054b014124404a9c0a96028243c09", + "0x152c0555814f80904a580aaa029f812ab5501d2c05548150209548152c05", + "0x208126402a580a64029cc12ae02a580aad029e812ad02a580aac029ec12ac", + "0x1cbc64488155c054b0155c05098240e054b0140e0516024bc054b014bc05", + "0x2800a7304ac00a9602a940a1204abc0a9602a840a08048252c050481c12ae", + "0x152c05580142609038152c05038145809578152c05578150409500152c05", + "0x152c0538814100904a580a89028c012094b014120704ac00eaf502440ab0", + "0x2780e2004ac80a9602ac80a2504ac80a9602824f2094f0152c050487812b1", + "0x2580ab50284812b502a580ab35a01c50095a0152c050488812b302a580ab2", + "0x240e054b0140e051602562054b015620541024ea054b014ea05398256c05", + "0x241296028ec0a26048252c050481c12b603ac4ea9102ad80a9602ad80a13", + "0x152c05049e012b802a580a090f0256e054b014640504024129602a240a30", + "0xa012bb02a580a091102574054b01572b80388012b902a580ab90289412b9", + "0x2dc0a8204a440a9602a440a7304af40a9602af00a1204af00a9602ae97607", + "0x257a075ba4522055e8152c055e8142609038152c050381458095b8152c05", + "0x27c0a96028243c095f0152c0514014100904a580a1f0289812094b0141207", + "0x244409600152c055fa7c0e2004afc0a9602afc0a2504afc0a9602824a809", + "0x2580a91029cc12c302a580ac20284812c202a580ac06081c5009608152c05", + "0x1586054b0158605098240e054b0140e05160257c054b0157c05410252205", + "0x2588054b0143405040241296028880a26048252c050481c12c303af92291", + "0x158cc50388012c602a580ac60289412c602a580a093b0258a054b014121e", + "0x3280a9602b240a1204b240a9602b1d90071402590054b014122204b1c0a96", + "0x142609038152c05038145809620152c05620150409488152c0548814e609", + "0x14100904a580a260289812094b014120704b280ec448a440aca02a580aca", + "0x3300a9602b300a2504b300a96028249c09520152c050487812cb02a580a31", + "0x4812ce02a580a576681c5009668152c0504888125702a580acc5201c4009", + "0x140e051602596054b01596054102522054b0152205398259e054b0159c05", + "0x200a75048252c050481c12cf03b2d229102b3c0a9602b3c0a130481c0a96", + "0x94129d02a580a093c825a2054b014121e04b400a9602a300a08048252c05", + "0x349a60714025a6054b014122204b480a9602a75a207100253a054b0153a05", + "0x152c05680150409410152c0541014e6096a8152c056a01424096a0152c05", + "0x14120904b540ed0412440ad502a580ad50284c120702a580a07028b012d0", + "0x14e605040241296028240e09462080ed639a440e96038141207028241296", + "0xc40a96028c40a8204a440a9602a440a73048c00a96028200a91048c40a96", + "0x2434054b0146205040241296028240e0913015ae250301d2c07180151809", + "0x143405410240c054b0140c05030241296028780a30048780a96028940a31", + "0x2580a270289812094b0141207048880ad81009c0e96038180a8c048680a96", + "0x141227048480a96028243c09140152c050d014100904a580a20028681209", + "0x7c0a96028244409098152c05160480e20048b00a96028b00a25048b00a96", + "0x208129102a580a91029cc128902a580a3202848123202a580a130f81c5009", + "0x1c50914881512054b0151205098240e054b0140e051602450054b0145005", + "0x2580a090f8251a054b0143405040241296028880a26048252c050481c1289", + "0x1d2c074223522084482508054b0150805190251a054b0151a05410250805", + "0x20c0a96028248009208152c051e014100904a580a09038247c4003b64783b", + "0x207c09418152c05418144a09208152c052081504091d8152c051d814e609", + "0x241296028240e093d815b47c02a580e7e02904127e40910109602a0c823b", + "0x152c0504910127902a580a090f024f4054b0150205040241296029f00a83", + "0x138ec074b014a80540824a8054b014f07903880127802a580a78028941278", + "0x1c40a7a049c40a96029d40a7b049d40a96029380a7c048252c053b014fc09", + "0x152c050381458093d0152c053d0150409220152c0522014e609380152c05", + "0x2580a810282012094b0141207049c00e7a222440a7002a580a700284c1207", + "0x24d6054b014d6054102488054b014880539824d2054b014f60509024d605", + "0x252c050481c1269039ac8891029a40a96029a40a130481c0a960281c0a2c", + "0x14bc0512824bc054b0141279049900a96028243c09340152c051f0141009", + "0x152c05002700e2804a700a96028244409000152c052f1900e20049780a96", + "0xb0126802a580a6802a08124002a580a40029cc12a102a580aa00284812a0", + "0x241296028240e095081cd0404881542054b0154205098240e054b0140e05", + "0x152c050493812a302a580a090f02544054b0146205040241296028980a26", + "0xa012a702a580a09110254c054b0154aa30388012a502a580aa50289412a5", + "0x2880a8204a440a9602a440a7304aa40a9602aa00a1204aa00a9602a994e07", + "0x255207512452205548152c05548142609038152c05038145809510152c05", + "0x2ac0a96028243c09550152c0546014100904a580a08029d412094b0141207", + "0x244409568152c05562ac0e2004ab00a9602ab00a2504ab00a9602824f209", + "0x2580a82029cc12b002a580aaf0284812af02a580aad5701c5009570152c05", + "0x1560054b0156005098240e054b0140e051602554054b0155405410250405", + "0x1c128c4101db6734881d2c07028240e05048252c050482412b003aa90491", + "0x24129602824e209180152c05040152209188152c0539814100904a580a09", + "0x980adc128180e96038c00a8c048c40a96028c40a8204a440a9602a440a73", + "0x143c05468243c054b0144a051882434054b0146205040241296028240e09", + "0xa00a96028180a06048880a96028680a82048800a960289c0a700489c0a96", + "0x152c0518814100904a580a090382412dd028247609090152c0510014d609", + "0x140c09110152c051601504090f8152c0509814d009098152c05049a4122c", + "0x240e0944815bc3202a580e1202990121202a580a1f029ac122802a580a26", + "0x128d02a580a8d02a08128d02a580a220282012094b014125e048252c05", + "0x14100904a580a3b02a7012094b0141207048f00adf1da100e96038c92207", + "0x2580e2802a30124002a580a4002a08128402a580a84029cc124002a580a8d", + "0x152c05208146209220152c0520014100904a580a09038250605701047c07", + "0x148805410247c054b0147c0503024129602824e20904a580a81028c01281", + "0x2580a440282012094b0141207049ec0ae13e1f80e96038f80a8c049100a96", + "0x24a8054b014fc0503024f0054b014f40541024f2054b014f80550024f405", + "0x1380a96029100a08048252c050481c120971014123b049d80a96029e40aa1", + "0x1ec0a06049e00a96029380a82049c40a96029d40aa2049d40a9602824d209", + "0x141207049ac0ae3380152c073b01546093b0152c053881542092a0152c05", + "0x243c09340152c05380146209348152c053c014100904a580a092f0241296", + "0x152c0542014e609000152c05340151a092f0152c052a014f809320152c05", + "0x94126402a580a6402a98125e02a580a5e02a94126902a580a6902a081284", + "0x152c0750815500950a8138084b01400642f1a508735382400054b0140005", + "0x29d4c074b0154405548254a054b0154005040241296028240e0951815c8a2", + "0x2012094b014120704aa40ae5540152c07538155409528152c05528150409", + "0x1d56054602554054b01554054102556054b0154c054882554054b0154a05", + "0x252c0556814340904a580aac0289812094b014120704ab80ae656ab00e96", + "0x2580a091382560054b014121e04abc0a9602aa80a08048252c0554014fc09", + "0x2564054b014122204a780a9602ac560071002562054b0156205128256205", + "0x1504094e0152c054e014e6095a0152c05598142409598152c054f2c80e28", + "0x2d00eaf4e2440ab402a580ab40284c120702a580a07028b012af02a580aaf", + "0x152c050487c12b502a580aaa0282012094b0155c05130241296028240e09", + "0x2dc0e9603ad96a9c0422412b602a580ab6028c812b502a580ab502a0812b6", + "0x2f00e9602aa00a8104aec0a9602ae00a08048252c050481c12ba5c81dceb8", + "0x1518095d8152c055d81504095b8152c055b814e60904a580abc029f812bd", + "0x15760504024129602af80a26048252c050481c12bf02ba13ebe03a580ebd", + "0x2dc0a9602adc0a7304b080a9602b040a8d04b040a9602a7c0a3104b000a96", + "0x31186084b01584c05b8207c09610152c05610144a09600152c05600150409", + "0x2012094b0158c05418241296028240e0963815d2c602a580ec50290412c5", + "0x152c05650144a09650152c050491012c902a580a090f02590054b0158805", + "0x24129602a900a7e04b3148074b01596054082596054b01594c90388012ca", + "0x30c0a7304b380a9602b340a7a04b340a960295c0a7b0495c0a9602b300a7c", + "0x152c05670142609038152c05038145809640152c05640150409618152c05", + "0x2580ac702aac12cf02a580ac40282012094b014120704b380ec861a440ace", + "0x25a4054b0159e05410253a054b015860539824129602b400aac04b45a007", + "0x24129602afc0a26048252c050481c120975014123b04b4c0a9602b440aa6", + "0x2580aeb0289412eb02a580a0956825aa054b014121e04b500a9602aec0a08", + "0x3480a9602b500a8204a740a9602adc0a7304bb00a9602badaa0710025d605", + "0x142409770152c0569bb40e2804bb40a96028244409698152c05760154c09", + "0x2580a07028b012d202a580ad202a08129d02a580a9d029cc12ef02a580aee", + "0x1550053f0241296028240e097781da49d48815de054b015de05098240e05", + "0x144a09790152c05049e412f102a580a090f025e0054b0157405040241296", + "0x15e6f4038a012f402a580a0911025e6054b015e4f10388012f202a580af2", + "0x3c00a9602bc00a8204ae40a9602ae40a7304bd40a9602a6c0a1204a6c0a96", + "0x2580a0903825ea07782e522057a8152c057a8142609038152c05038145809", + "0x2700a7304bd80a9602a940a08048252c0553014ea0904a580aa902ab81209", + "0x14100904a580a090382412f90282476097c0152c057b01504097b8152c05", + "0x2580afa02a08129c02a580a9c029cc12fb02a580aa30284812fa02a580aa0", + "0x240e097d81df49c48815f6054b015f605098240e054b0140e0516025f405", + "0x1e00a08048252c052a0144c0904a580a6b02ab812094b014125e048252c05", + "0x3f40a96028243c097c0152c057e01504097b8152c0542014e6097e0152c05", + "0x2444097f8152c057f3f40e2004bf80a9602bf80a2504bf80a9602824a809", + "0x2580af7029cc130202a580b0102848130102a580aff8001c5009800152c05", + "0x1604054b0160405098240e054b0140e0516025f0054b015f00541025ee05", + "0x2606054b014800504024129602a0c0a26048252c050481c130203be1ee91", + "0x15350403880129a02a580a9a02894129a02a580a093b02608054b014121e", + "0x4200a9602c1c0a1204c1c0a9602c160c07140260c054b014122204c140a96", + "0x142609038152c05038145809818152c05818150409420152c0542014e609", + "0x14100904a580a280289812094b014120704c200f03422440b0802a580b08", + "0x261805048ec130b02a580b0902a08130a02a580a3c029cc130902a580a8d", + "0x241296028a00a26048252c05448155c0904a580a092f0241296028240e09", + "0x14121e04c2c0a9602c340a8204c280a9602a440a7304c340a96028880a08", + "0x4400a9602c3e1c07100261e054b0161e05128261e054b014124e04c380a96", + "0x14e609898152c05890142409890152c05884440e2804c440a96028244409", + "0x2580b130284c120702a580a07028b0130b02a580b0b02a08130a02a580b0a", + "0x2580a8c0282012094b01410053a8241296028240e098981e170a488162605", + "0x1c40098a8152c058a8144a098a8152c05049e4131402a580a090f0253205", + "0x1630050902630054b0162d17038a0131702a580a09110262c054b0162b14", + "0x1c0a960281c0a2c04a640a9602a640a8204a080a9602a080a7304c640a96", + "0x152c0504abc127302a580a095782632074ca0922058c8152c058c8142609", + "0x940c078d0c062074b01c0a090381412094b0141209048252c0504ac0128c", + "0x2580a093882434054b0141005488244c054b0146005040241296028240e09", + "0x46c4e1e03a580e1a02a30122602a580a2602a08123102a580a31029cc1209", + "0x151a09140152c05138146209110152c0513014100904a580a09038244005", + "0x2580a1e02818121302a580a2202a08122c02a580a12029c0121202a580a28", + "0x144c05040241296028240e0904c700a091d82464054b0145805358243e05", + "0x2426054b01512054102508054b0151a05340251a054b014126904a240a96", + "0x2476058ea080a96038c80a64048c80a9602a100a6b0487c0a96028800a06", + "0x152c05412300eb1048f00a960284c0a08048252c050497812094b0141207", + "0x2580a090382482058f0f880074b01d043103800123c02a580a3c02a081282", + "0x230128302a580a8302a08124002a580a40029cc128302a580a3c028201209", + "0x1462093e0152c0541814100904a580a0903824fc058fa0488074b01c3e05", + "0x2580a0938824f6054b01522054682522054b015227303ac4129102a580a81", + "0x480f27a03a580e4402a30127c02a580a7c02a08124402a580a44028181209", + "0x1504093b0152c053c81540092a0152c053e014100904a580a0903824f005", + "0x264205048ec127102a580a7602a84127502a580a7a02818124e02a580a54", + "0x2580a6b02a88126b02a580a0934824e0054b014f805040241296028240e09", + "0x24e2054b014d20550824ea054b014f005030249c054b014e00541024d205", + "0x149c0504024129602824bc0904a580a0903824c805911a00a96039c40aa3", + "0x2540054b014ea053e02538054b014121e048000a96029a00a31049780a96", + "0x2800aa5049780a96029780a82049000a96029000a7304a840a96028000a8d", + "0x271405e201cd4e09508152c05508144a094e0152c054e0154c09500152c05", + "0x14100904a580a09038254e0591a980a9603a940aa804a9546a2042580aa1", + "0x1d54055502550054b01550054102554a903a580aa602aa412a802a580aa3", + "0x152c05548152209568152c0554014100904a580a09038255805922ac0a96", + "0x252c050481c12b102c9560af03a580eae02a3012ad02a580aad02a0812ae", + "0x2580a7b028c012094b01556053f024129602ac00a1a048252c05578144c09", + "0x14122704ac80a96028243c094f0152c0556814100904a580a3e02a701209", + "0x2d40a960282444095a0152c0559ac80e2004acc0a9602acc0a2504acc0a96", + "0x20812a202a580aa2029cc12b702a580ab60284812b602a580ab45a81c5009", + "0x1d3ca2488156e054b0156e05098240e054b0140e05160253c054b0153c05", + "0x2580a090f82570054b0155a0504024129602ac40a26048252c050481c12b7", + "0x1d2c075cae144084482572054b01572051902570054b0157005410257205", + "0x152c055f01504095f0152c055d814100904a580a09038257abc03c9976ba", + "0x1c12c3613041127602fd3e084b01c0ebe03a7812ba02a580aba029cc12be", + "0x152c05600156409620152c054f81410094f8152c054f815040904a580a09", + "0x2580ac602ad412ca64b218ec639a580ac502ad012c502a580ac002acc12c0", + "0x1590055b824129602b280a30048252c0564815380904a580ac702ad81209", + "0x3100a9602b100a8204afc0a9602afc0a2c04b2c0a9602b2c0a2504b2c0a96", + "0x150209660152c0562014100904a580a09038254805940252c07658150809", + "0x2580acc02a0812ce02a580acd029f012094b014ae053f0259a5703a580aab", + "0x252c050481c12d369274112968b419e084b01d9c7b1f2fd98735c0259805", + "0x14f4096a8152c0568814f6096a0152c05678141009678152c05678150409", + "0x2580ad0028b012d402a580ad402a0812ba02a580aba029cc12eb02a580ad5", + "0x15a6053f0241296028240e0975b41a8ba48815d6054b015d60509825a005", + "0x2e412ed02a580a090f025d8054b0153a05040253a054b0153a05410241296", + "0x2580a0911025de054b015dced0388012ee02a580aee0289412ee02a580a09", + "0x2e80a9602ae80a7304bc80a9602bc40a1204bc40a9602bbde00714025e005", + "0x2e92205790152c05790142609690152c05690145809760152c05760150409", + "0x1ec0a30048252c0555814fc0904a580aa4028f012094b014120704bc9a4ec", + "0x2e812f402a580a090f025e6054b0158805040241296028f80a9c048252c05", + "0x2580a0911025ea054b01536f403880129b02a580a9b02894129b02a580a09", + "0x2e80a9602ae80a7304be00a9602bdc0a1204bdc0a9602bd5ec0714025ec05", + "0x2e922057c0152c057c01426095f8152c055f8145809798152c05798150409", + "0xf80a9c048252c053d814600904a580aab029f812094b014120704be17ef3", + "0x25f6054b014122204be80a9602b040a0804b040a9602b040a82048252c05", + "0x1504095d0152c055d014e6097e8152c057e01424097e0152c0561bec0e28", + "0x3f584fa5d2440afd02a580afd0284c12c202a580ac2028b012fa02a580afa", + "0x252c051f015380904a580a7b028c012094b01556053f0241296028240e09", + "0x1600051282600054b014127904bfc0a96028243c097f0152c055e8141009", + "0x152c0580c080e2804c080a96028244409808152c05803fc0e2004c000a96", + "0xb012fe02a580afe02a0812bc02a580abc029cc130402a580b03028481303", + "0x241296028240e098201dfcbc4881608054b0160805098240e054b0140e05", + "0x252c051f015380904a580a7b028c012094b01552053a824129602ab00aae", + "0x247609830152c054d0150409828152c0551014e6094d0152c05540141009", + "0x28c0a08048252c053d814600904a580a3e02a7012094b0141207048265405", + "0x152c05838150409510152c0551014e609840152c05538142409838152c05", + "0x14120704c200f07512440b0802a580b080284c120702a580a07028b01307", + "0x147c054e0241296029ec0a30048252c05320155c0904a580a092f0241296", + "0x208130502a580a40029cc130902a580a4e0282012094b014ea05130241296", + "0x152c05858144a09858152c0504950130a02a580a090f0260c054b0161205", + "0x261e054b0161b0e038a0130e02a580a09110261a054b016170a03880130b", + "0x1c0a2c04c180a9602c180a8204c140a9602c140a7304c400a9602c3c0a12", + "0x144c0904a580a09038262007834152205880152c05880142609038152c05", + "0x2622054b0150605040241296029cc0abb048252c051f015380904a580a7e", + "0x16271203880131302a580b1302894131302a580a093b02624054b014121e", + "0x4580a9602c540a1204c540a9602a6628071402628054b014122204a640a96", + "0x142609038152c05038145809888152c05888150409200152c0520014e609", + "0x15760904a580a1f0289812094b014120704c580f11202440b1602a580b16", + "0x152c058b81504098c0152c0520814e6098b8152c051e014100904a580a73", + "0x241296028ec0aae048252c050497812094b0141207048265605048ec1319", + "0x152c0509814100904a580a8c02aec12094b014e6055d82412960287c0a26", + "0x249c09968152c0504878131902a580b2c02a08131802a580a31029cc132c", + "0x152c0504888132f02a580b2e9681c4009970152c05970144a09970152c05", + "0x2630054b01630053982664054b01662050902662054b0165f30038a01330", + "0x466309102cc80a9602cc80a130481c0a960281c0a2c04c640a9602c640a82", + "0x1410053a8241296029cc0abb048252c0546015760904a580a09038266407", + "0x144a099a0152c05049e4129802a580a090f02666054b0144a05040241296", + "0x166b36038a0133602a580a09110266a054b016689803880133402a580b34", + "0x4cc0a9602ccc0a82048180a96028180a7304ce00a9602cdc0a1204cdc0a96", + "0x2580a090482670079981922059c0152c059c0142609038152c05038145809", + "0x2580a730282012094b014120704a3104079c9cd22074b01c0a09038141209", + "0x2462054b01462054102522054b01522053982460054b0141005488246205", + "0xc4121a02a580a310282012094b0141207048980b3a128180e96038c00a8c", + "0x2580a1a02a08120602a580a060281812094b0143c05180243c054b0144a05", + "0x152c050d014100904a580a090382444059d8804e074b01c0c05460243405", + "0x94122802a580a2802a08122702a580a2702818121202a580a20028c41228", + "0x144c0904a580a09038243e059e04c58074b01c4e054602424054b0142405", + "0x2464054b0145005040241296028480a30048252c0509814340904a580a2c", + "0x151a8903880128d02a580a8d02894128d02a580a091382512054b014121e", + "0x1000a96028f00a12048f00a9602a1076071402476054b014122204a100a96", + "0x142609038152c05038145809190152c05190150409488152c0548814e609", + "0x14100904a580a1f0289812094b0141207049000e3248a440a4002a580a40", + "0x152c052081464091f0152c051f0150409208152c050487c123e02a580a28", + "0x148805040241296028240e093f2040f3d2220c0e96039047c91042241241", + "0x24f2054b014240546824f4054b014f6055e824f6054b01412bc049f00a96", + "0x14f4055f824f0054b014f0054f824f8054b014f80541024f0054b01412be", + "0x138113e3b1500e96039e4f478039f0e6c004a0c0a9602a0c0a73049e80a96", + "0x243c09380152c052a01410092a0152c052a015040904a580a0903824e275", + "0x152c0534014f80904a580a69029f812683481d2c05358150209358152c05", + "0x208128302a580a83029cc120002a580a5e029e8125e02a580a64029ec1264", + "0x1d8e0834881400054b014000509824ec054b014ec0516024e0054b014e005", + "0x14122204a700a96029380a08049380a96029380a82048252c050481c1200", + "0x152c0541814e609510152c05508142409508152c0538a800e2804a800a96", + "0x2440aa202a580aa20284c127502a580a75028b0129c02a580a9c02a081283", + "0x7812a302a580a7e0282012094b0142405180241296028240e09511d53883", + "0x2580aa65281c4009530152c05530144a09530152c05049e412a502a580a09", + "0x2554054b01552050902552054b0154ea8038a012a802a580a09110254e05", + "0x2a80a130481c0a960281c0a2c04a8c0a9602a8c0a8204a040a9602a040a73", + "0x680a08048252c05110144c0904a580a0903825540751a052205550152c05", + "0x255a054b0155a05128255a054b014127604ab00a96028243c09558152c05", + "0x142409580152c05572bc0e2804abc0a96028244409570152c0556ab00e20", + "0x2580a07028b012ab02a580aab02a08129102a580a91029cc12b102a580ab0", + "0x144c05130241296028240e095881d56914881562054b0156205098240e05", + "0x144a09598152c050493812b202a580a090f0253c054b0146205040241296", + "0x1568b5038a012b502a580a091102568054b01566b20388012b302a580ab3", + "0x2780a9602a780a8204a440a9602a440a7304adc0a9602ad80a1204ad80a96", + "0x2580a09038256e074f24522055b8152c055b8142609038152c05038145809", + "0x14127904ae40a96028243c095c0152c0546014100904a580a08029d41209", + "0x2f00a960282444095d8152c055d2e40e2004ae80a9602ae80a2504ae80a96", + "0x208128202a580a82029cc12be02a580abd0284812bd02a580abb5e01c5009", + "0x1d7082488157c054b0157c05098240e054b0140e051602570054b0157005", + "0x252c050481c12823981e7e910401d2c07028240e05048252c050497812be", + "0x208120802a580a08029cc12310381d2c05038158209460152c05488141009", + "0x140e05180241296028240e091801680094b01c62054202518054b0151805", + "0x30c122602a580a2502b08122502a580a09348240c054b0151805040241296", + "0x143405620240c054b0140c054102410054b01410053982434054b0144c05", + "0x2580a8c0282012094b01460051e0241296028240e090d0181008028680a96", + "0x2410054b01410053982440054b0144e0703b18122702a580a09628243c05", + "0x485022042580a200f020103e048800a96028800a25048780a96028780a82", + "0x2458054b01504050402412960281c0a30048252c050481c1212140881005", + "0x143e1303880121f02a580a1f02894121f02a580a093c82426054b014121e", + "0x2100a9602a340ac704a340a96028c912071402512054b0141222048c80a96", + "0x1cc1005420152c05420158809160152c05160150409398152c0539814e609", + "0x2580a0903824628c03d05047303a580e050481c0a0904a580a092f025082c", + "0x24e6054b014e605398240c9103a580a9102b04123002a580a82028201209", + "0x2440a30048252c050481c122502d081296038180a84048c00a96028c00a82", + "0x152c050d01c0ec9048680a96028200ac8048980a96028c00a08048252c05", + "0x32c122602a580a2602a08127302a580a73029cc122702a580a1e02b28121e", + "0x14100904a580a25028f012094b01412070489c4c73040144e054b0144e05", + "0x800a96028800a82048252c05049c4122202a580a0702a44122002a580a30", + "0x2426054b0144005040241296028240e091601686121401d2c07110151809", + "0x4c0a8204a240a96028c80a70048c80a960287c0a8d0487c0a96028480a31", + "0x2413440282476091d8152c0544814d609420152c05140140c09468152c05", + "0x152c0520014d009200152c05049a4123c02a580a200282012094b0141207", + "0x1f0123b02a580a3e029ac128402a580a2c02818128d02a580a3c02a08123e", + "0x14125e048252c050481c124402d1506054b01c76053202482054b0150805", + "0x24f8054b01412c5049f80a9602a0c10071002502054b0151a05040241296", + "0x154a09408152c05408150409398152c0539814e6093d8152c053e2440ec6", + "0x105027339a9c127b02a580a7b02894127e02a580a7e02a98124102a580a41", + "0xc012094b014125e048252c050481c12783c9e810053c1e4f4084b014f67e", + "0x152c052201548092a0152c0546814100904a580a08029f812094b0152205", + "0x24e6054b014e60539824ea054b0149c05650249c054b014ec4103b241276", + "0x241296028240e093a950e608029d40a96029d40acb049500a96029500a82", + "0x152c0518814100904a580a07029d412094b01410053f024129602a440a30", + "0x1c00e20049ac0a96029ac0a25049ac0a9602824f209380152c05048781271", + "0x2580a6402b30126402a580a693401c5009340152c0504888126902a580a6b", + "0x14bc054b014bc0565824e2054b014e2054102518054b015180539824bc05", + "0x252227349781291048200e05049a0d25e04a444e692f025228c2f1c51808", + "0x1a4bc0948d1c100702824d0692f0252227349781291a30200e05049a0d25e", + "0x229208038141268349781291139a4bc0948d20100702824d0692f0252227", + "0x52d22080381412832f02410060d09cbc0939d280e05049d4bc0904018bc09" + ], + "sierra_program_debug_info": { + "type_names": [], + "libfunc_names": [], + "user_func_names": [] + }, + "contract_class_version": "0.1.0", + "entry_points_by_type": { + "EXTERNAL": [ + { + "selector": "0x15d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad", + "function_idx": 3 + }, + { + "selector": "0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775", + "function_idx": 2 + }, + { + "selector": "0x289da278a8dc833409cabfdad1581e8e7d40e42dcaed693fa4008dcdb4963b3", + "function_idx": 1 + }, + { + "selector": "0x36fcbf06cd96843058359e1a75928beacfac10727dab22a3972f0af8aa92895", + "function_idx": 0 + } + ], + "L1_HANDLER": [], + "CONSTRUCTOR": [ + { + "selector": "0x28ffe4ff0f226a9107253e17a904099aa4f63a02a5621de0576e5aa71bc5194", + "function_idx": 4 + } + ] + }, + "abi": [ + { + "type": "constructor", + "name": "constructor", + "inputs": [ + { + "name": "grind_on_deploy", + "type": "core::felt252" + }, + { + "name": "arg", + "type": "core::felt252" + } + ] + }, + { + "type": "function", + "name": "__validate_deploy__", + "inputs": [ + { + "name": "class_hash", + "type": "core::felt252" + }, + { + "name": "contract_address_salt", + "type": "core::felt252" + }, + { + "name": "grind_on_deploy", + "type": "core::felt252" + }, + { + "name": "arg", + "type": "core::felt252" + } + ], + "outputs": [ + { + "type": "core::felt252" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "__validate_declare__", + "inputs": [ + { + "name": "class_hash", + "type": "core::felt252" + } + ], + "outputs": [ + { + "type": "core::felt252" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "__validate__", + "inputs": [ + { + "name": "contract_address", + "type": "core::starknet::contract_address::ContractAddress" + }, + { + "name": "selector", + "type": "core::felt252" + }, + { + "name": "calldata", + "type": "core::array::Array::" + } + ], + "outputs": [ + { + "type": "core::felt252" + } + ], + "state_mutability": "view" + }, + { + "type": "struct", + "name": "core::array::Span::", + "members": [ + { + "name": "snapshot", + "type": "@core::array::Array::" + } + ] + }, + { + "type": "function", + "name": "__execute__", + "inputs": [ + { + "name": "contract_address", + "type": "core::starknet::contract_address::ContractAddress" + }, + { + "name": "selector", + "type": "core::felt252" + }, + { + "name": "calldata", + "type": "core::array::Array::" + } + ], + "outputs": [ + { + "type": "core::array::Span::" + } + ], + "state_mutability": "view" + }, + { + "type": "event", + "name": "account_with_long_validate::account_with_long_validate::Account::Event", + "kind": "enum", + "variants": [] + } + ] +} diff --git a/crates/blockifier_test_utils/resources/feature_contracts/cairo1/sierra/cairo_steps_test_contract.sierra.json b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/sierra/cairo_steps_test_contract.sierra.json new file mode 100644 index 00000000000..92c3efe5a3b --- /dev/null +++ b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/sierra/cairo_steps_test_contract.sierra.json @@ -0,0 +1,9134 @@ +{ + "sierra_program": [ + "0x1", + "0x6", + "0x0", + "0x2", + "0x7", + "0x0", + "0x8bf", + "0x741", + "0x1a0", + "0x52616e6765436865636b", + "0x800000000000000100000000000000000000000000000000", + "0x436f6e7374", + "0x800000000000000000000000000000000000000000000002", + "0x1", + "0x44", + "0x2", + "0x6e5f627974657320746f6f20626967", + "0x14", + "0x1000000000000000000000000000000", + "0x10000000000000000000000000000", + "0x100000000000000000000000000", + "0x1000000000000000000000000", + "0x10000000000000000000000", + "0x100000000000000000000", + "0x1000000000000000000", + "0x10000000000000000", + "0x100000000000000", + "0x1000000000000", + "0x10000000000", + "0x100000000", + "0x1000000", + "0x10000", + "0x100", + "0x537472756374", + "0x800000000000000f00000000000000000000000000000001", + "0x0", + "0x2ee1e2b1b89f8c495f200e4956278a4d47395fe262f27b52e5865c9524c08c3", + "0x456e756d", + "0x800000000000000700000000000000000000000000000011", + "0x14cb65c06498f4a8e9db457528e9290f453897bdb216ce18347fff8fef2cd11", + "0x11", + "0x426f756e646564496e74", + "0x800000000000000700000000000000000000000000000002", + "0xf", + "0x75313238", + "0x800000000000000700000000000000000000000000000000", + "0x800000000000000700000000000000000000000000000005", + "0x2907a9767b8e0b68c23345eea8650b1366373b598791523a07fddaa450ba526", + "0x426f78", + "0x800000000000000700000000000000000000000000000001", + "0x18", + "0x800000000000000700000000000000000000000000000003", + "0x25e2ca4b84968c2d8b83ef476ca8549410346b00836ce79beaf538155990bb2", + "0x17", + "0x42697477697365", + "0x556e696e697469616c697a6564", + "0x800000000000000200000000000000000000000000000001", + "0x19", + "0x753235365f737562204f766572666c6f77", + "0x3e", + "0x4c", + "0x800000000000000000000000000000000000000000000003", + "0x22", + "0x1f", + "0x21", + "0x20", + "0x483ada7726a3c4655da4fbfc0e1108a8", + "0x79be667ef9dcbbac55a06295ce870b07", + "0x29bfcdb2dce28d959f2815b16f81798", + "0xfd17b448a68554199c47d08ffb10d4b8", + "0xe", + "0xd", + "0xb", + "0xa", + "0x9", + "0x8", + "0x7", + "0x6", + "0x5", + "0x4", + "0x3", + "0x104", + "0x97", + "0x18ef5e2178ac6be59ceafd15e6995810f636807e02c51d309c3f65e37000fc5", + "0x2f", + "0x16a4c8d7c05909052238a862d8cc3e7975bf05a07b3a69c6b28951083a6d672", + "0x4172726179", + "0x800000000000000300000000000000000000000000000001", + "0x800000000000000300000000000000000000000000000003", + "0x32", + "0x33", + "0x2f23416cc60464d4158423619ba713070eb82b686c9d621a22c67bd37f6e0a9", + "0x31", + "0x34", + "0x3b", + "0x38", + "0x3a", + "0x39", + "0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e16", + "0x6b17d1f2e12c4247f8bce6e563a440f2", + "0x77037d812deb33a0f4a13945d898c296", + "0x2bce33576b315ececbb6406837bf51f5", + "0x553132384d756c47756172616e746565", + "0x3f", + "0x4e6f6e5a65726f", + "0x42", + "0x41", + "0x5369676e6174757265206f7574206f662072616e6765", + "0xffffffff00000000ffffffffffffffff", + "0xbce6faada7179e84f3b9cac2fc632551", + "0x496e76616c6964207369676e6174757265", + "0x66656c74323532", + "0x3233063c5dc6197e9bf4ddc53b925e10907665cf58255b7899f8212442d4605", + "0x45", + "0x1d8a68005db1b26d0d9f54faae1798d540e7df6326fae758cc2cf8f7ee88e72", + "0x46", + "0x536563703235366b31506f696e74", + "0x3179e7829d19e62b12c79010203ceee40c98166e97eb104c25ad1adb6b9675a", + "0x48", + "0x49", + "0x3c7b5436891664778e6019991e6bd154eeab5d43a552b1f19485dec008095d3", + "0x4a", + "0x50", + "0x4f", + "0x52", + "0x14ef93a95bec47ff4e55863055b7a948870fa13be1cbddd481656bdaf5facc2", + "0x4d", + "0xfffffffffffffffffffffffffffffffe", + "0xbaaedce6af48a03bbfd25e8cd0364141", + "0x753332", + "0x51", + "0x10", + "0x74", + "0x64", + "0x80000000", + "0x7533325f6d756c204f766572666c6f77", + "0x7533325f616464204f766572666c6f77", + "0x800000", + "0x61", + "0x8000", + "0x5e", + "0x80", + "0x5b", + "0x65", + "0x8000000000000000", + "0x753634", + "0x4b656363616b206c61737420696e70757420776f7264203e3762", + "0x75", + "0x313d53fcef2616901e3fd6801087e8d55f5cb59357e1fc8b603b82ae0af064c", + "0x76", + "0x7a", + "0x38b0179dda7eba3d95708820abf10d3d4f66e97d9a9013dc38d712dce2af15", + "0x78", + "0x800000000000000700000000000000000000000000000004", + "0x3342418ef16b3e2799b906b1e4e89dbb9b111332dd44f72458ce44f9895b508", + "0x38f1b5bca324642b144da837412e9d82e31937ed4bbe21a1ebccb0c3d3d8d36", + "0x7533325f737562204f766572666c6f77", + "0x556e6578706563746564206572726f72", + "0x76616c7565732073686f756c64206e6f74206368616e67652e", + "0x53746f726167654261736541646472657373", + "0x31448060506164e4d1df7635613bacfbea8af9c3dc85ea9a55935292a4acddc", + "0x7f", + "0x454e545259504f494e545f4641494c4544", + "0x457870656374656420726576657274", + "0x4369726375697444617461", + "0x84", + "0x43697263756974", + "0x800000000000000800000000000000000000000000000001", + "0x87", + "0x43697263756974496e707574416363756d756c61746f72", + "0x43697263756974496e707574", + "0x800000000000000800000000000000000000000000000002", + "0x86", + "0x4e6f7420616c6c20696e707574732068617665206265656e2066696c6c6564", + "0x526573756c743a3a756e77726170206661696c65642e", + "0x536e617073686f74", + "0x8a", + "0x149ee8c97f9cdd259b09b6ca382e10945af23ee896a644de8c7b57da1779da7", + "0x8b", + "0x800000000000000300000000000000000000000000000004", + "0x36775737a2dc48f3b19f9a1f4bc3ab9cb367d1e2e827cef96323826fd39f53f", + "0x8d", + "0x602e", + "0x206c696d62313a20302c206c696d62323a20302c206c696d62333a2030207d", + "0x6f7574707574286d756c29203d3d2075333834207b206c696d62303a20362c", + "0x679ea9c5b65e40ad9da80f5a4150d36f3b6af3e88305e2e3ae5eccbc5743d9", + "0x93", + "0x617373657274696f6e206661696c65643a20606f7574707574732e6765745f", + "0x62797465733331", + "0x5539364c696d62734c7447756172616e746565", + "0x800000000000000100000000000000000000000000000001", + "0x4d756c4d6f6447617465", + "0x9e", + "0x9d", + "0x5375624d6f6447617465", + "0x9f", + "0x496e766572736547617465", + "0xa0", + "0x4164644d6f6447617465", + "0xffffffffffffffffffffffff", + "0x35de1f6419a35f1a8c6f276f09c80570ebf482614031777c6d07679cf95b8bb", + "0xa1", + "0x436972637569744661696c75726547756172616e746565", + "0x436972637569745061727469616c4f757470757473", + "0xb2", + "0x436972637569744f757470757473", + "0xa7", + "0xa9", + "0x4369726375697444657363726970746f72", + "0x1b", + "0x416c6c20696e707574732068617665206265656e2066696c6c6564", + "0x55393647756172616e746565", + "0x800000000000000100000000000000000000000000000005", + "0xaf", + "0xb4", + "0x9b", + "0x436972637569744d6f64756c7573", + "0x4d756c4d6f64", + "0xb9", + "0x52616e6765436865636b3936", + "0xbb", + "0x4164644d6f64", + "0xbe", + "0x6d232c016ef1b12aec4b7f88cc0b3ab662be3b7dd7adbce5209fcfdbd42a504", + "0x45635374617465", + "0x4b5810004d9272776dec83ecc20c19353453b956e594188890b48467cb53c19", + "0x3dbce56de34e1cfe252ead5a1f14fd261d520d343ff6b7652174e62976ef44d", + "0x4563506f696e74", + "0xc5", + "0x4fad269cbf860980e38768fe9cb6b0b9ab03ee3fe84cfde2eccce597c874fd8", + "0x654fd7e67a123dd13868093b3b7777f1ffef596c2e324f25ceaf9146698482c", + "0x1671f96113fa573e5b6df9aef6a004dbf7cc3c475398dd3be1b2590f1f9cdd9", + "0xc9", + "0xcc", + "0x7538", + "0x3c4930bb381033105f3ca15ccded195c90cd2af5baa0e1ceb36fde292df7652", + "0x34482b42d8542e3c880c5c93d387fb8b01fe2a5d54b6f50d62fe82d9e6c2526", + "0x2691cb735b18f3f656c3b82bd97a32b65d15019b64117513f8604d1e06fe58b", + "0x7265637572736976655f6661696c", + "0x4469766973696f6e2062792030", + "0x32564d7e0fe091d49b4c20f4632191e4ed6986bf993849879abfef9465def25", + "0x62c83572d28cb834a3de3c1e94977a4191469a4a8c26d1d7bc55305e640ed5", + "0x3288d594b9a45d15bb2fcb7903f06cdb06b27f0ba88186ec4cfaa98307cb972", + "0xd5", + "0xa853c166304d20fb0711becf2cbdf482dee3cac4e9717d040b7a7ab1df7eec", + "0xd6", + "0xdd", + "0xda", + "0xdc", + "0xdb", + "0x177e60492c5a8242f76f07bfe3661bd", + "0xb292a619339f6e567a305c951c0dcbcc", + "0x42d16e47f219f9e98e76e09d8770b34a", + "0xe59ec2a17ce5bd2dab2abebdf89a62e2", + "0xe3", + "0xe0", + "0xe2", + "0xe1", + "0xe3b0c44298fc1c149afbf4c8996fb924", + "0x87d9315798aaa3a5ba01775787ced05e", + "0xaaf7b4e09fc81d6d1aa546e8365d525d", + "0x27ae41e4649b934ca495991b7852b855", + "0xe9", + "0xe6", + "0xe8", + "0xe7", + "0x4aaec73635726f213fb8a9e64da3b86", + "0x49288242", + "0x6e1cda979008bfaf874ff796eb3bb1c0", + "0x32e41495a944d0045b522eba7240fad5", + "0xef", + "0xec", + "0xee", + "0xed", + "0xdb0a2e6710c71ba80afeb3abdf69d306", + "0x502a43ce77c6f5c736a82f847fa95f8c", + "0x2d483fe223b12b91047d83258a958b0f", + "0xce729c7704f4ddf2eaaf0b76209fe1b0", + "0xf3", + "0xf2", + "0x536563703235367231506f696e74", + "0xffffffff000000010000000000000000", + "0xcb47311929e7a903ce831cb2b3e67fe265f121b394a36bc46c17cf352547fc", + "0xf1", + "0x185fda19bc33857e9f1d92d61312b69416f20cf740fa3993dcc2de228a6671d", + "0xf5", + "0xf83fa82126e7aeaf5fe12fff6a0f4a02d8a185bf5aaee3d10d1c4e751399b4", + "0xf6", + "0x107a3e65b6e33d1b25fa00c80dfe693f414350005bc697782c25eaac141fedd", + "0xfe", + "0xfb", + "0xfd", + "0xfc", + "0x4ac5e5c0c0e8a4871583cc131f35fb49", + "0x4c8e4fbc1fbb1dece52185e532812c4f", + "0x7a5f81cf3ee10044320a0d03b62d3e9a", + "0xc2b7f60e6a8b84965830658f08f7410c", + "0x102", + "0x101", + "0x100000000000000000000000000000000", + "0xe888fbb4cf9ae6254f19ba12e6d9af54", + "0x788f195a6f509ca3e934f78d7a71dd85", + "0x108", + "0x107", + "0x556e657870656374656420636f6f7264696e61746573", + "0x767410c1", + "0xbb448978bd42b984d7de5970bcaf5c43", + "0x10e", + "0x10b", + "0x10d", + "0x10c", + "0x8e182ca967f38e1bd6a49583f43f1876", + "0xf728b4fa42485e3a0a5d2f346baa9455", + "0xe3e70682c2094cac629f6fbed82c07cd", + "0x8e031ab54fc0c4a8f0dc94fad0d0611", + "0x496e76616c696420617267756d656e74", + "0x113", + "0x112", + "0x53686f756c64206265206e6f6e65", + "0xffffffffffffffffffffffffffffffff", + "0xfffffffffffffffffffffffefffffc2f", + "0x13d", + "0x13c", + "0x61be55a8", + "0x800000000000000700000000000000000000000000000009", + "0x118", + "0x336711c2797eda3aaf8c07c5cf7b92162501924a7090b25482d45dd3a24ddce", + "0x119", + "0x536861323536537461746548616e646c65", + "0x11a", + "0x11b", + "0x324f33e2d695adb91665eafd5b62ec62f181e09c2e0e60401806dcc4bb3fa1", + "0x11c", + "0x800000000000000000000000000000000000000000000009", + "0x117", + "0x127", + "0x126", + "0x125", + "0x124", + "0x123", + "0x122", + "0x121", + "0x120", + "0x5be0cd19", + "0x1f83d9ab", + "0x9b05688c", + "0x510e527f", + "0xa54ff53a", + "0x3c6ef372", + "0xbb67ae85", + "0x6a09e667", + "0x176a53827827a9b5839f3d68f1c2ed4673066bf89e920a3d4110d3e191ce66b", + "0x128", + "0x61616161", + "0x496e646578206f7574206f6620626f756e6473", + "0x57726f6e67206572726f72206d7367", + "0x496e76616c696420696e707574206c656e677468", + "0x53686f756c64206661696c", + "0xa5963aa610cb75ba273817bce5f8c48f", + "0x57726f6e6720686173682076616c7565", + "0x587f7cc3722e9654ea3963d5fe8c0748", + "0x132", + "0x3f829a4bc463d91621ba418d447cc38c95ddc483f9ccfebae79050eb7b3dcb6", + "0x133", + "0x25e50662218619229b3f53f1dc3253192a0f68ca423d900214253db415a90b4", + "0x135", + "0x137", + "0x38b507bf259d96f5c53e8ab8f187781c3d096482729ec2d57f3366318a8502f", + "0x138", + "0x139", + "0x3c5ce4d28d473343dbe52c630edf038a582af9574306e1d609e379cd17fc87a", + "0x13a", + "0x424c4f434b5f494e464f5f4d49534d41544348", + "0x54585f494e464f5f4d49534d41544348", + "0x43414c4c45525f4d49534d41544348", + "0x434f4e54524143545f4d49534d41544348", + "0x53454c4543544f525f4d49534d41544348", + "0x144", + "0x1597b831feeb60c71f259624b79cf66995ea4f7e383403583674ab9c33b9cec", + "0x145", + "0x146", + "0x21afb2f280564fc34ddb766bf42f7ca36154bbba994fbc0f0235cd873ace36a", + "0x147", + "0x1baeba72e79e9db2587cf44fedb2f3700b2075a5e8e39a562584862c4b71f62", + "0x149", + "0x14a", + "0x45b67c75542d42836cef6c02cca4dbff4a80a8621fa521cbfff1b2dd4af35a", + "0x14b", + "0x152", + "0x178", + "0x436f6e747261637441646472657373", + "0x800000000000000700000000000000000000000000000006", + "0x7d4d99e9ed8d285b5c61b493cedb63976bc3d9da867933d829f49ce838b5e7", + "0x14e", + "0x14d", + "0x14f", + "0x150", + "0x80000000000000070000000000000000000000000000000e", + "0x348a62b7a38c0673e61e888d83a3ac1bf334ee7361a8514593d3d9532ed8b39", + "0x1ce0be45cbaa9547dfece0f040e22ec60de2d0d5a6c79fa5514066dfdbb7ca6", + "0x3128e9bfd21b6f544f537413d7dd38a8f2e017a3b81c1a4bcf8f51a64d0dc3d", + "0x156", + "0x33ecdfa3f249457fb2ae8b6a6713b3069fa0c38450e972297821b52ba929029", + "0x157", + "0x1d49f7a4b277bf7b55a2664ce8cef5d6922b5ffb806b89644b9e0cdbbcac378", + "0x159", + "0x13fdd7105045794a99550ae1c4ac13faa62610dfab62c16422bfcf5803baa6e", + "0x15a", + "0x7536345f616464204f766572666c6f77", + "0x12", + "0x746573745f7265766572745f68656c706572", + "0x46a6158a16a947e5916b2a2ca68501a45e93d7110e81aa2d6438b1c57c879a3", + "0xc", + "0x45634f70", + "0x7772be8b80a8a33dc6c1f9a6ab820c02e537c73e859de67f288c70f92571bb", + "0x8441aec937a8bc42f322081e69950d87c6bc0bf8db4bf9fa30a4f93a1a9df6", + "0x1735c8952e18cedd2eecf0d9d8c0f71c59482020ff21fc5a800a240032d198c", + "0x166", + "0x506564657273656e", + "0x6661696c", + "0x3d4c1d72b5898077c704a8e84bed7f5e72117b38ac1cd367f43e580c7d97c0", + "0x16a", + "0x158bafd9f0cb6c89680a1a997e2eb4d5639998f8abb6982920b84b3b99fd55d", + "0x16b", + "0x7820213d2079", + "0x73756363657373", + "0x537175617368656446656c7432353244696374", + "0x46656c7432353244696374", + "0x5365676d656e744172656e61", + "0x800000000000000f00000000000000000000000000000002", + "0xcc5e86243f861d2d64b08c35db21013e773ac5cf10097946fe0011304886d5", + "0x173", + "0x2271e6a0c1b1931cf78a8bfd030df986f9544c426af3bd6023dc55382237cf7", + "0x175", + "0x1d2ae7ecff8f8db67bf542f1d1f8201ff21e9f36f780ef569bcc7bc74ab634c", + "0x176", + "0x3808c701a5d13e100ab11b6c02f91f752ecae7e420d21b56c90ec0a475cc7e5", + "0x1cbd0cd3f779a7c0d3cdc804f89c39bcf71a85b43d3cf8a042111f0bc2ddf63", + "0x909b0519d7c88c554565d942b48b326c8dcbd2e2915301868fb8159e606aa3", + "0x17b", + "0x800000000000000f00000000000000000000000000000003", + "0x213e34fc43c648233f74758fd35f0000d7ca76cbb5966cf9aae174ef0e5367", + "0x17e", + "0x436c61737348617368", + "0x4661696c656420746f20646573657269616c697a6520706172616d202334", + "0x4661696c656420746f20646573657269616c697a6520706172616d202335", + "0x4661696c656420746f20646573657269616c697a6520706172616d202336", + "0x74584e9f10ffb1a40aa5a3582e203f6758defc4a497d1a2d5a89f274a320e9", + "0x184", + "0x53797374656d", + "0x188", + "0x4661696c656420746f20646573657269616c697a6520706172616d202333", + "0x17b6ecc31946835b0d9d92c2dd7a9c14f29af0371571ae74a1b228828b2242", + "0x18b", + "0x34f9bd7c6cb2dd4263175964ad75f1ff1461ddc332fbfb274e0fb2a5d7ab968", + "0x18c", + "0x29d7d57c04a880978e7b3689f6218e507f3be17588744b58dc17762447ad0e7", + "0x18e", + "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x4661696c656420746f20646573657269616c697a6520706172616d202331", + "0x4661696c656420746f20646573657269616c697a6520706172616d202332", + "0x4f7574206f6620676173", + "0x4275696c74696e436f737473", + "0x9931c641b913035ae674b400b61a51476d506bbe8bba2ff8a6272790aba9e6", + "0x198", + "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", + "0x53746f7261676541646472657373", + "0x11c6d8087e00642489f92d2821ad6ebd6532ad1a3b6d12833da6d6810391511", + "0x4761734275696c74696e", + "0x348", + "0x7265766f6b655f61705f747261636b696e67", + "0x77697468647261775f676173", + "0x6272616e63685f616c69676e", + "0x7374727563745f6465636f6e737472756374", + "0x656e61626c655f61705f747261636b696e67", + "0x73746f72655f74656d70", + "0x61727261795f736e617073686f745f706f705f66726f6e74", + "0x756e626f78", + "0x72656e616d65", + "0x656e756d5f696e6974", + "0x19e", + "0x6a756d70", + "0x7374727563745f636f6e737472756374", + "0x656e756d5f6d61746368", + "0x1ad5911ecb88aa4a50482c4de3232f196cfcaf7bd4e9c96d22b283733045007", + "0x64697361626c655f61705f747261636b696e67", + "0x64726f70", + "0x19d", + "0x61727261795f6e6577", + "0x636f6e73745f61735f696d6d656469617465", + "0x19c", + "0x61727261795f617070656e64", + "0x19b", + "0x19f", + "0x6765745f6275696c74696e5f636f737473", + "0x19a", + "0x77697468647261775f6761735f616c6c", + "0x199", + "0x647570", + "0x73746f726167655f77726974655f73797363616c6c", + "0x73746f726167655f726561645f73797363616c6c", + "0x736e617073686f745f74616b65", + "0x197", + "0x196", + "0x195", + "0x194", + "0x193", + "0x192", + "0x191", + "0x616c6c6f635f6c6f63616c", + "0x66696e616c697a655f6c6f63616c73", + "0x73746f72655f6c6f63616c", + "0x21adb5788e32c84f69a1863d85ef9394b7bf761a0ce1190f826984e5075c371", + "0x18f", + "0x66756e6374696f6e5f63616c6c", + "0x24", + "0x18d", + "0x63616c6c5f636f6e74726163745f73797363616c6c", + "0x18a", + "0x190", + "0x186", + "0x189", + "0x187", + "0x25", + "0x185", + "0x61727261795f6c656e", + "0x7533325f746f5f66656c74323532", + "0x26", + "0x183", + "0x182", + "0x181", + "0x636c6173735f686173685f7472795f66726f6d5f66656c74323532", + "0x180", + "0x27", + "0x17f", + "0x7536345f7472795f66726f6d5f66656c74323532", + "0x17d", + "0x28", + "0x17c", + "0x6765745f626c6f636b5f686173685f73797363616c6c", + "0x29", + "0x179", + "0x2a", + "0x177", + "0x2b", + "0x174", + "0x17a", + "0x6c6962726172795f63616c6c5f73797363616c6c", + "0x2c", + "0x7265706c6163655f636c6173735f73797363616c6c", + "0x73656e645f6d6573736167655f746f5f6c315f73797363616c6c", + "0x172", + "0x66656c743235325f646963745f6e6577", + "0x171", + "0x2d", + "0x170", + "0x66656c743235325f69735f7a65726f", + "0x16f", + "0x626f6f6c5f6e6f745f696d706c", + "0x6465706c6f795f73797363616c6c", + "0x2e", + "0x30", + "0x66656c743235325f737562", + "0x16e", + "0x16d", + "0x16c", + "0x169", + "0x636f6e74726163745f616464726573735f746f5f66656c74323532", + "0x168", + "0x35", + "0x36", + "0x167", + "0x37", + "0x753132385f746f5f66656c74323532", + "0x165", + "0x164", + "0x163", + "0x162", + "0x3c", + "0x73746f726167655f626173655f616464726573735f636f6e7374", + "0x1275130f95dda36bcbb6e9d28796c1d7e10b6e9fd5ed083e0ede4b12f613528", + "0x73746f726167655f616464726573735f66726f6d5f62617365", + "0x66656c743235325f616464", + "0x656d69745f6576656e745f73797363616c6c", + "0x161", + "0x160", + "0x15f", + "0x15e", + "0x7536345f6571", + "0x15d", + "0x7536345f6f766572666c6f77696e675f616464", + "0x15c", + "0x75313238735f66726f6d5f66656c74323532", + "0x3d", + "0x15b", + "0x158", + "0x155", + "0x7533325f7472795f66726f6d5f66656c74323532", + "0x6765745f657865637574696f6e5f696e666f5f76325f73797363616c6c", + "0x151", + "0x153", + "0x753132385f6571", + "0x7533325f6571", + "0x14c", + "0x40", + "0x148", + "0x143", + "0x142", + "0x141", + "0x140", + "0x13f", + "0x154", + "0x636c6173735f686173685f746f5f66656c74323532", + "0x13e", + "0x66656c743235325f646963745f737175617368", + "0x13b", + "0x136", + "0x134", + "0x6b656363616b5f73797363616c6c", + "0x131", + "0x130", + "0x12f", + "0x12e", + "0x61727261795f676574", + "0x12d", + "0x12c", + "0x12b", + "0x12a", + "0x43", + "0x129", + "0x636f6e73745f61735f626f78", + "0x11e", + "0x7368613235365f73746174655f68616e646c655f696e6974", + "0x11d", + "0x7368613235365f73746174655f68616e646c655f646967657374", + "0x11f", + "0x116", + "0x115", + "0x114", + "0x736563703235366b315f6e65775f73797363616c6c", + "0x111", + "0x110", + "0x10f", + "0x10a", + "0x109", + "0x736563703235366b315f6765745f78795f73797363616c6c", + "0x106", + "0x105", + "0x103", + "0x753132385f736166655f6469766d6f64", + "0x66656c743235325f6d756c", + "0xff", + "0xfa", + "0xf9", + "0xf8", + "0xf7", + "0x7365637032353672315f6e65775f73797363616c6c", + "0xf4", + "0xf0", + "0xeb", + "0xea", + "0x7365637032353672315f6765745f78795f73797363616c6c", + "0xe5", + "0xe4", + "0xdf", + "0xde", + "0xd9", + "0xd8", + "0xd7", + "0xd4", + "0x7533325f6f766572666c6f77696e675f737562", + "0x61727261795f706f705f66726f6e74", + "0xd3", + "0xd2", + "0xd1", + "0xd0", + "0xcf", + "0xce", + "0x706564657273656e", + "0xad292db4ff05a993c318438c1b6c8a8303266af2da151aa28ccece6726f1f1", + "0xcd", + "0xcb", + "0x2679d68052ccd03a53755ca9169677965fbd93e489df62f5f40d4f03c24f7a4", + "0xca", + "0x62697477697365", + "0xc8", + "0xc7", + "0x65635f706f696e745f7472795f6e65775f6e7a", + "0xc6", + "0x756e777261705f6e6f6e5f7a65726f", + "0xc4", + "0xc3", + "0x65635f706f696e745f69735f7a65726f", + "0x65635f73746174655f696e6974", + "0xc1", + "0x65635f73746174655f6164645f6d756c", + "0xc2", + "0x65635f73746174655f7472795f66696e616c697a655f6e7a", + "0x65635f706f696e745f7a65726f", + "0x65635f73746174655f616464", + "0x65635f706f696e745f756e77726170", + "0x161bc82433cf4a92809836390ccd14921dfc4dc410cf3d2adbfee5e21ecfec8", + "0xc0", + "0xb8", + "0xb7", + "0xb6", + "0x7472795f696e746f5f636972637569745f6d6f64756c7573", + "0x696e69745f636972637569745f64617461", + "0xb1", + "0x696e746f5f7539365f67756172616e746565", + "0xb0", + "0xb3", + "0x6164645f636972637569745f696e707574", + "0xae", + "0xbc", + "0xbd", + "0xbf", + "0xba", + "0xb5", + "0xad", + "0xac", + "0xab", + "0x6765745f636972637569745f64657363726970746f72", + "0xa8", + "0xa6", + "0x6576616c5f63697263756974", + "0x6765745f636972637569745f6f7574707574", + "0x3ec1c84a1511eed894537833882a965abdddafab0d627a3ee76e01e6b57f37a", + "0x1d1238f44227bdf67f367571e4dec83368c54054d98ccf71a67381f7c51f1c4", + "0x7539365f67756172616e7465655f766572696679", + "0xa2", + "0x47", + "0x96", + "0x95", + "0x94", + "0x92", + "0x91", + "0x90", + "0x8f", + "0x8e", + "0x7374727563745f736e617073686f745f6465636f6e737472756374", + "0x8c", + "0xa4", + "0x89", + "0x4ef3b3bc4d34db6611aef96d643937624ebee01d56eae5bde6f3b158e32b15", + "0x88", + "0x85", + "0x83", + "0x82", + "0x61727261795f736e617073686f745f706f705f6261636b", + "0x81", + "0x7e", + "0x7d", + "0x61727261795f736c696365", + "0x7c", + "0x7b", + "0x79", + "0x77", + "0x4b", + "0x73", + "0x7533325f736166655f6469766d6f64", + "0x72", + "0x71", + "0x70", + "0x6f", + "0x6e", + "0x6d", + "0x6c", + "0x6b", + "0x6a", + "0x69", + "0x68", + "0x67", + "0x7536345f69735f7a65726f", + "0x7536345f736166655f6469766d6f64", + "0x63", + "0x62", + "0x60", + "0x5f", + "0x5d", + "0x5c", + "0x5a", + "0x7533325f776964655f6d756c", + "0x646f776e63617374", + "0x7533325f6f766572666c6f77696e675f616464", + "0x59", + "0x58", + "0x57", + "0x56", + "0x55", + "0x54", + "0x53", + "0x61727261795f736e617073686f745f6d756c74695f706f705f66726f6e74", + "0x4e", + "0x7368613235365f70726f636573735f626c6f636b5f73797363616c6c", + "0x753132385f6f766572666c6f77696e675f737562", + "0x753235365f67756172616e7465655f696e765f6d6f645f6e", + "0x753132385f6d756c5f67756172616e7465655f766572696679", + "0x7365637032353672315f6d756c5f73797363616c6c", + "0x7365637032353672315f6164645f73797363616c6c", + "0x757063617374", + "0x753132385f69735f7a65726f", + "0x627974657333315f7472795f66726f6d5f66656c74323532", + "0x627974657333315f746f5f66656c74323532", + "0x23", + "0x393d13543d6033e70e218aad8050e8de40a1dfbac0e80459811df56e3716ce6", + "0x1e", + "0x1d", + "0x1c", + "0x736563703235366b315f6d756c5f73797363616c6c", + "0x736563703235366b315f6164645f73797363616c6c", + "0x696e746f5f626f78", + "0x7370616e5f66726f6d5f7475706c65", + "0x753132385f627974655f72657665727365", + "0x1a", + "0x753132385f67756172616e7465655f6d756c", + "0x753132385f6f766572666c6f77696e675f616464", + "0x15", + "0x753531325f736166655f6469766d6f645f62795f75323536", + "0x13", + "0x656e756d5f66726f6d5f626f756e6465645f696e74", + "0x38d9", + "0xffffffffffffffff", + "0xa3", + "0x16", + "0x1ff", + "0x1ec", + "0x1e7", + "0x1d5", + "0x1c4", + "0x1b4", + "0x1ab", + "0x66", + "0x1f2", + "0x41b", + "0x225", + "0x22a", + "0x403", + "0x3f9", + "0x238", + "0x23d", + "0x3e2", + "0x246", + "0x24b", + "0x26f", + "0x261", + "0x278", + "0x3cc", + "0x284", + "0x289", + "0x3b4", + "0x3aa", + "0x297", + "0x29c", + "0x393", + "0x2a5", + "0x2aa", + "0x2ce", + "0x2c0", + "0x2d7", + "0x37d", + "0x2f1", + "0x368", + "0x98", + "0x99", + "0x356", + "0x9a", + "0x9c", + "0x34d", + "0xa5", + "0x344", + "0xaa", + "0x33c", + "0x335", + "0x360", + "0x3bf", + "0x40e", + "0x49f", + "0x43e", + "0x443", + "0x48e", + "0x48a", + "0x45a", + "0x47c", + "0x475", + "0x492", + "0x5bc", + "0x4bc", + "0x4c1", + "0x5a9", + "0x5a4", + "0x4cf", + "0x4d4", + "0x4f3", + "0x4ea", + "0x4fc", + "0x593", + "0x506", + "0x50b", + "0x52a", + "0x521", + "0x533", + "0x582", + "0x548", + "0x572", + "0x56b", + "0x5af", + "0x63a", + "0x5d8", + "0x5dd", + "0x629", + "0x625", + "0x5f7", + "0x617", + "0x60e", + "0x62d", + "0x73d", + "0x72d", + "0x725", + "0x715", + "0x666", + "0x66b", + "0x703", + "0x675", + "0x67a", + "0x6f0", + "0x684", + "0x689", + "0x6dc", + "0x6a1", + "0x6c9", + "0x6c2", + "0x827", + "0x75d", + "0x762", + "0x814", + "0x80f", + "0x770", + "0x775", + "0x7fd", + "0x77e", + "0x783", + "0x7a2", + "0x799", + "0x7ab", + "0x7ec", + "0x7c0", + "0x7dc", + "0x7d3", + "0x81a", + "0x92a", + "0x845", + "0x84a", + "0x919", + "0x915", + "0x857", + "0x85c", + "0x904", + "0x866", + "0x86b", + "0x8f2", + "0x875", + "0x87a", + "0x8df", + "0x884", + "0x889", + "0x8cb", + "0x8a1", + "0x8b8", + "0x91d", + "0x9a3", + "0x946", + "0x94b", + "0x992", + "0x98e", + "0x962", + "0x980", + "0x977", + "0x996", + "0xa5f", + "0x9c1", + "0x9c6", + "0xa4e", + "0x9cf", + "0x9d4", + "0x9f2", + "0x9ea", + "0x9fb", + "0xa3e", + "0xa0f", + "0xa2f", + "0xa26", + "0xaab", + "0xa84", + "0xa9d", + "0xbd1", + "0xacb", + "0xad0", + "0xbbe", + "0xbb9", + "0xade", + "0xae3", + "0xba7", + "0xaec", + "0xaf1", + "0xb10", + "0xb07", + "0xb19", + "0xb96", + "0xb22", + "0xb27", + "0xb83", + "0xb32", + "0xb37", + "0xb4c", + "0xb71", + "0xb68", + "0xbc4", + "0xc23", + "0xbf6", + "0xc16", + "0xc0f", + "0xc73", + "0xc46", + "0xc66", + "0xc5f", + "0xcc8", + "0xc97", + "0xcba", + "0xcb2", + "0xd19", + "0xcec", + "0xd0c", + "0xd05", + "0xdb7", + "0xd35", + "0xd3a", + "0xda7", + "0xd44", + "0xd49", + "0xd96", + "0xd5e", + "0xd86", + "0xd78", + "0xe4f", + "0xdd1", + "0xdd6", + "0xdf3", + "0xdec", + "0xdfc", + "0xe40", + "0xe0f", + "0xe32", + "0xe2b", + "0xe91", + "0xe72", + "0xe84", + "0xf05", + "0xead", + "0xeb2", + "0xef5", + "0xec6", + "0xee7", + "0xee0", + "0xf79", + "0xf21", + "0xf26", + "0xf69", + "0xf3a", + "0xf5b", + "0xf54", + "0x1055", + "0xf95", + "0xf9a", + "0x1044", + "0x1040", + "0xfa7", + "0xfac", + "0x102f", + "0xfb6", + "0xfbb", + "0x101d", + "0xfd1", + "0x100c", + "0xfe1", + "0xff6", + "0x1002", + "0x1048", + "0x111a", + "0x1071", + "0x1076", + "0x1109", + "0x1080", + "0x1085", + "0x10f7", + "0x108f", + "0x1094", + "0x10e4", + "0x10ab", + "0x10d2", + "0x10ca", + "0x118d", + "0x117c", + "0x1145", + "0x116c", + "0x1163", + "0x1239", + "0x11ab", + "0x11b0", + "0x1228", + "0x1224", + "0x1213", + "0x11ce", + "0x1204", + "0x11fb", + "0x122c", + "0x128e", + "0x125d", + "0x1280", + "0x1278", + "0x130a", + "0x12ab", + "0x12b0", + "0x12f9", + "0x12c5", + "0x12ea", + "0x12e2", + "0x1387", + "0x1327", + "0x132c", + "0x1377", + "0x1340", + "0x1369", + "0x1360", + "0x13e5", + "0x13ad", + "0x13d5", + "0x13cb", + "0x1448", + "0x140c", + "0x143a", + "0x142f", + "0x142b", + "0x1432", + "0x1539", + "0x1468", + "0x146d", + "0x1526", + "0x1521", + "0x147b", + "0x1480", + "0x150f", + "0x1489", + "0x148e", + "0x14ad", + "0x14a4", + "0x14b6", + "0x14fe", + "0x14cb", + "0x14ee", + "0x14e7", + "0x152c", + "0x15c1", + "0x1557", + "0x155c", + "0x15b1", + "0x1567", + "0x156c", + "0x15a1", + "0x1580", + "0x1593", + "0x1682", + "0x15dd", + "0x15e2", + "0x1672", + "0x15ed", + "0x15f2", + "0x1661", + "0x165d", + "0x15ff", + "0x1604", + "0x164c", + "0x1619", + "0x163c", + "0x1632", + "0x1665", + "0x1721", + "0x169e", + "0x16a3", + "0x1711", + "0x16ad", + "0x16b2", + "0x1700", + "0x16c7", + "0x16f0", + "0x16e5", + "0x1768", + "0x173e", + "0x174a", + "0x174f", + "0x175d", + "0x17a1", + "0x1783", + "0x1788", + "0x1796", + "0x17d9", + "0x17bb", + "0x17c0", + "0x17ce", + "0x1837", + "0x182d", + "0x1824", + "0x181b", + "0x188a", + "0x187e", + "0x1871", + "0x1860", + "0x18a2", + "0x18a7", + "0x1902", + "0x18fe", + "0x18b8", + "0x18bd", + "0x18f4", + "0x18ef", + "0x18d0", + "0x18d5", + "0x18e5", + "0x18e0", + "0x18ea", + "0x18f9", + "0x1906", + "0x191d", + "0x1922", + "0x1b74", + "0x192d", + "0x1932", + "0x1b61", + "0x1b57", + "0x1942", + "0x1947", + "0x1b45", + "0x1b3a", + "0x1b2c", + "0x1b1c", + "0x1961", + "0x1966", + "0x1b0b", + "0x1971", + "0x1976", + "0x1afa", + "0x1981", + "0x1986", + "0x1ae9", + "0x198f", + "0x1994", + "0x19c5", + "0x19b8", + "0x19b0", + "0x19ce", + "0x1ad9", + "0x19d7", + "0x19dc", + "0x1ac6", + "0x1ab9", + "0x1aa9", + "0x1a97", + "0x19f3", + "0x19f8", + "0x1a81", + "0x1a73", + "0x1a09", + "0x1a0e", + "0x1a5d", + "0x1a4f", + "0x1a3c", + "0x1a27", + "0x1a6b", + "0x1a8f", + "0x1ad1", + "0x1b4f", + "0x1b6c", + "0x1f73", + "0x1bb7", + "0x1bcf", + "0x1bd0", + "0x1f66", + "0x1f5b", + "0x1f30", + "0x1f25", + "0x1c54", + "0x1f3a", + "0x1c8b", + "0x1ca4", + "0x1f13", + "0x1ca7", + "0x1f3d", + "0x1f06", + "0x1ef9", + "0x1eec", + "0x1d44", + "0x1d5c", + "0x1edf", + "0x1d5f", + "0x1f45", + "0x1d8c", + "0x1f47", + "0x1a1", + "0x1a2", + "0x1a3", + "0x1a4", + "0x1a5", + "0x1a6", + "0x1a7", + "0x1a8", + "0x1a9", + "0x1aa", + "0x1dc2", + "0x1ac", + "0x1ad", + "0x1dda", + "0x1ae", + "0x1af", + "0x1b0", + "0x1b1", + "0x1ed2", + "0x1b2", + "0x1b3", + "0x1b5", + "0x1b6", + "0x1ddd", + "0x1b7", + "0x1b8", + "0x1b9", + "0x1f49", + "0x1ba", + "0x1bb", + "0x1bc", + "0x1bd", + "0x1be", + "0x1bf", + "0x1c0", + "0x1c1", + "0x1c2", + "0x1c3", + "0x1c5", + "0x1c6", + "0x1c7", + "0x1c8", + "0x1c9", + "0x1ca", + "0x1cb", + "0x1cc", + "0x1cd", + "0x1ce", + "0x1cf", + "0x1d0", + "0x1d1", + "0x1d2", + "0x1d3", + "0x1d4", + "0x1d6", + "0x1d7", + "0x1e0a", + "0x1d8", + "0x1d9", + "0x1f4b", + "0x1da", + "0x1db", + "0x1dc", + "0x1dd", + "0x1de", + "0x1df", + "0x1e0", + "0x1e1", + "0x1e2", + "0x1e3", + "0x1e4", + "0x1e5", + "0x1e6", + "0x1e8", + "0x1e9", + "0x1ea", + "0x1eb", + "0x1ed", + "0x1ee", + "0x1ef", + "0x1f0", + "0x1f1", + "0x1f3", + "0x1f4", + "0x1f5", + "0x1f6", + "0x1f7", + "0x1e36", + "0x1f8", + "0x1f9", + "0x1f4d", + "0x1fa", + "0x1fb", + "0x1fc", + "0x1fd", + "0x1fe", + "0x200", + "0x201", + "0x202", + "0x203", + "0x204", + "0x205", + "0x206", + "0x207", + "0x208", + "0x209", + "0x20a", + "0x20b", + "0x20c", + "0x20d", + "0x20e", + "0x20f", + "0x210", + "0x211", + "0x212", + "0x213", + "0x214", + "0x215", + "0x216", + "0x217", + "0x218", + "0x219", + "0x21a", + "0x21b", + "0x1e68", + "0x21c", + "0x21d", + "0x1f4f", + "0x21e", + "0x21f", + "0x220", + "0x221", + "0x1ec7", + "0x222", + "0x223", + "0x224", + "0x226", + "0x1e7f", + "0x227", + "0x228", + "0x229", + "0x1eb5", + "0x22b", + "0x22c", + "0x1ea5", + "0x22d", + "0x22e", + "0x1e97", + "0x22f", + "0x230", + "0x231", + "0x232", + "0x233", + "0x234", + "0x235", + "0x236", + "0x237", + "0x239", + "0x23a", + "0x23b", + "0x23c", + "0x23e", + "0x23f", + "0x240", + "0x241", + "0x242", + "0x243", + "0x244", + "0x245", + "0x247", + "0x1f1f", + "0x248", + "0x249", + "0x1f43", + "0x24a", + "0x1f41", + "0x24c", + "0x24d", + "0x1f3f", + "0x24e", + "0x24f", + "0x250", + "0x251", + "0x252", + "0x253", + "0x254", + "0x255", + "0x256", + "0x257", + "0x258", + "0x259", + "0x25a", + "0x25b", + "0x25c", + "0x25d", + "0x1fba", + "0x1fb2", + "0x207c", + "0x2073", + "0x206c", + "0x2009", + "0x201a", + "0x2033", + "0x205e", + "0x204f", + "0x2084", + "0x20d8", + "0x20d1", + "0x20c8", + "0x20de", + "0x221a", + "0x2101", + "0x2118", + "0x220b", + "0x21fb", + "0x21ee", + "0x21dc", + "0x21cf", + "0x2154", + "0x2160", + "0x2161", + "0x217e", + "0x2174", + "0x218c", + "0x21c0", + "0x21ba", + "0x21c5", + "0x235c", + "0x2240", + "0x2256", + "0x234e", + "0x233f", + "0x2333", + "0x2322", + "0x2316", + "0x2291", + "0x229d", + "0x229e", + "0x22bb", + "0x22b1", + "0x22c7", + "0x230c", + "0x22fd", + "0x22f5", + "0x2475", + "0x2465", + "0x237a", + "0x237f", + "0x2454", + "0x2388", + "0x238d", + "0x2442", + "0x2396", + "0x239b", + "0x242f", + "0x23ca", + "0x23b9", + "0x23af", + "0x242a", + "0x23fa", + "0x23e9", + "0x23df", + "0x2427", + "0x240b", + "0x2421", + "0x24a1", + "0x2498", + "0x24c7", + "0x24be", + "0x2541", + "0x2537", + "0x2525", + "0x251f", + "0x252e", + "0x254b", + "0x255d", + "0x2562", + "0x25bc", + "0x256a", + "0x256f", + "0x25a4", + "0x259f", + "0x257d", + "0x2582", + "0x2595", + "0x258f", + "0x25ac", + "0x2599", + "0x25a7", + "0x25b5", + "0x2667", + "0x265e", + "0x2649", + "0x2634", + "0x2622", + "0x261c", + "0x262a", + "0x2670", + "0x2710", + "0x2700", + "0x2690", + "0x26a2", + "0x269e", + "0x26a8", + "0x26bd", + "0x26ae", + "0x26ba", + "0x26cd", + "0x26ef", + "0x26e9", + "0x26f7", + "0x27f0", + "0x27de", + "0x27d5", + "0x27c2", + "0x27af", + "0x279d", + "0x2797", + "0x27a6", + "0x27e7", + "0x2966", + "0x2837", + "0x2944", + "0x2911", + "0x285e", + "0x285b", + "0x2858", + "0x2860", + "0x2904", + "0x28fa", + "0x28f0", + "0x28e6", + "0x28dc", + "0x28cc", + "0x28d1", + "0x2936", + "0x2933", + "0x2930", + "0x2938", + "0x298b", + "0x298d", + "0x29af", + "0x2a02", + "0x29f3", + "0x29e9", + "0x29da", + "0x2a18", + "0x2a1d", + "0x2a6f", + "0x2a66", + "0x2a59", + "0x2a4a", + "0x2a3e", + "0x2aa3", + "0x2a88", + "0x2a99", + "0x2b0d", + "0x2abe", + "0x2ac3", + "0x2b02", + "0x2acf", + "0x2ad4", + "0x2af1", + "0x2ae6", + "0x2b9c", + "0x2b27", + "0x2b2c", + "0x2b91", + "0x2b38", + "0x2b3d", + "0x2b80", + "0x25e", + "0x25f", + "0x2b73", + "0x2b5f", + "0x260", + "0x2b77", + "0x2b6b", + "0x262", + "0x263", + "0x264", + "0x265", + "0x2be1", + "0x266", + "0x267", + "0x2bb6", + "0x268", + "0x269", + "0x26a", + "0x2bbb", + "0x26b", + "0x26c", + "0x2bd7", + "0x26d", + "0x26e", + "0x2bcf", + "0x270", + "0x271", + "0x272", + "0x273", + "0x274", + "0x275", + "0x276", + "0x277", + "0x2c78", + "0x2c49", + "0x2c43", + "0x2c3d", + "0x2c37", + "0x279", + "0x2c31", + "0x27a", + "0x2c2b", + "0x27b", + "0x2c27", + "0x27c", + "0x27d", + "0x27e", + "0x27f", + "0x2c2f", + "0x280", + "0x2c35", + "0x281", + "0x2c3b", + "0x282", + "0x2c41", + "0x283", + "0x2c47", + "0x2c4d", + "0x285", + "0x286", + "0x2c60", + "0x287", + "0x2c68", + "0x2c7e", + "0x288", + "0x2c9d", + "0x2c8f", + "0x28a", + "0x2cac", + "0x28b", + "0x28c", + "0x28d", + "0x2d0c", + "0x2cdb", + "0x2cd0", + "0x28e", + "0x28f", + "0x290", + "0x2cd7", + "0x291", + "0x292", + "0x293", + "0x294", + "0x2ce2", + "0x295", + "0x296", + "0x298", + "0x299", + "0x2cfd", + "0x29a", + "0x2cee", + "0x2d13", + "0x29b", + "0x29d", + "0x29e", + "0x29f", + "0x2d5f", + "0x2a0", + "0x2a1", + "0x2a2", + "0x2a3", + "0x2d52", + "0x2a4", + "0x2d45", + "0x2d38", + "0x2a6", + "0x2da3", + "0x2a7", + "0x2a8", + "0x2d7a", + "0x2a9", + "0x2ab", + "0x2d80", + "0x2ac", + "0x2ad", + "0x2d98", + "0x2ae", + "0x2af", + "0x2d8e", + "0x2b0", + "0x2b1", + "0x2b2", + "0x2b3", + "0x2b4", + "0x2b5", + "0x2b6", + "0x2dc7", + "0x2dd0", + "0x2ea5", + "0x2b7", + "0x2b8", + "0x2b9", + "0x2df3", + "0x2de4", + "0x2ba", + "0x2bb", + "0x2eac", + "0x2def", + "0x2dfa", + "0x2e0c", + "0x2e15", + "0x2e95", + "0x2e37", + "0x2e29", + "0x2e9c", + "0x2e33", + "0x2e3e", + "0x2bc", + "0x2bd", + "0x2e8c", + "0x2be", + "0x2e7c", + "0x2bf", + "0x2c1", + "0x2e73", + "0x2c2", + "0x2c3", + "0x2c4", + "0x2e67", + "0x2c5", + "0x2c6", + "0x2c7", + "0x2c8", + "0x2c9", + "0x2ca", + "0x2cb", + "0x2cc", + "0x2ec7", + "0x2ed0", + "0x3017", + "0x2cd", + "0x2ef3", + "0x2ee4", + "0x301e", + "0x2eef", + "0x2efa", + "0x2f0c", + "0x2f15", + "0x2f44", + "0x2f39", + "0x2f28", + "0x2f4a", + "0x2f32", + "0x300f", + "0x2cf", + "0x2d0", + "0x2d1", + "0x2ffc", + "0x2d2", + "0x2d3", + "0x2d4", + "0x2d5", + "0x2d6", + "0x2fec", + "0x2fde", + "0x2fd2", + "0x2fc7", + "0x2d8", + "0x2fbd", + "0x2fb3", + "0x2f9b", + "0x2fac", + "0x2fa8", + "0x2d9", + "0x2da", + "0x2db", + "0x2dc", + "0x2ff4", + "0x2dd", + "0x301f", + "0x2de", + "0x2df", + "0x2e0", + "0x2e1", + "0x2e2", + "0x3081", + "0x307c", + "0x3077", + "0x3071", + "0x3085", + "0x33df", + "0x2e3", + "0x33ce", + "0x3354", + "0x32f1", + "0x32e1", + "0x3251", + "0x3172", + "0x30b4", + "0x30b8", + "0x315e", + "0x2e4", + "0x2e5", + "0x3152", + "0x2e6", + "0x2e7", + "0x30d2", + "0x2e8", + "0x316c", + "0x3142", + "0x3112", + "0x3103", + "0x30f7", + "0x311d", + "0x313f", + "0x3134", + "0x2e9", + "0x3128", + "0x2ea", + "0x31f5", + "0x2eb", + "0x2ec", + "0x2ed", + "0x317b", + "0x317f", + "0x3240", + "0x3195", + "0x324b", + "0x3230", + "0x3223", + "0x3212", + "0x31e0", + "0x31d1", + "0x31c5", + "0x31eb", + "0x320f", + "0x3204", + "0x31f8", + "0x2ee", + "0x32aa", + "0x3259", + "0x325d", + "0x32cd", + "0x3295", + "0x3286", + "0x327a", + "0x32a0", + "0x32ca", + "0x32bf", + "0x32b3", + "0x2ef", + "0x2f0", + "0x32db", + "0x331f", + "0x3313", + "0x330a", + "0x332a", + "0x334e", + "0x3346", + "0x333a", + "0x33c4", + "0x338c", + "0x337e", + "0x3373", + "0x3398", + "0x33be", + "0x33b4", + "0x33a4", + "0x3413", + "0x2f2", + "0x33f4", + "0x2f3", + "0x2f4", + "0x2f5", + "0x33f9", + "0x2f6", + "0x2f7", + "0x3408", + "0x2f8", + "0x2f9", + "0x2fa", + "0x2fb", + "0x342a", + "0x342f", + "0x3480", + "0x3437", + "0x343c", + "0x3476", + "0x3471", + "0x344d", + "0x3452", + "0x3467", + "0x3460", + "0x2fc", + "0x2fd", + "0x2fe", + "0x346c", + "0x2ff", + "0x347b", + "0x300", + "0x301", + "0x34c5", + "0x34ba", + "0x34ab", + "0x34a1", + "0x34b4", + "0x34cf", + "0x3505", + "0x34f9", + "0x34eb", + "0x3519", + "0x3528", + "0x3537", + "0x302", + "0x3546", + "0x303", + "0x3555", + "0x304", + "0x3564", + "0x305", + "0x3573", + "0x306", + "0x3582", + "0x307", + "0x3591", + "0x308", + "0x35a0", + "0x309", + "0x35af", + "0x30a", + "0x35be", + "0x35cd", + "0x30b", + "0x35dc", + "0x30c", + "0x35eb", + "0x35f8", + "0x30d", + "0x36e1", + "0x36d5", + "0x30e", + "0x30f", + "0x36c5", + "0x36b7", + "0x310", + "0x36a3", + "0x3634", + "0x363a", + "0x3642", + "0x3654", + "0x364c", + "0x368e", + "0x311", + "0x3683", + "0x3679", + "0x312", + "0x3670", + "0x313", + "0x314", + "0x315", + "0x316", + "0x317", + "0x318", + "0x36cd", + "0x319", + "0x31a", + "0x3751", + "0x31b", + "0x31c", + "0x31d", + "0x31e", + "0x31f", + "0x320", + "0x321", + "0x322", + "0x3741", + "0x3739", + "0x3733", + "0x323", + "0x324", + "0x325", + "0x326", + "0x3748", + "0x327", + "0x328", + "0x329", + "0x32a", + "0x376d", + "0x3772", + "0x377c", + "0x3781", + "0x3788", + "0x378d", + "0x3794", + "0x3797", + "0x379e", + "0x37a3", + "0x37a8", + "0x37ab", + "0x37b0", + "0x37b3", + "0x37ba", + "0x37bf", + "0x37c4", + "0x37c7", + "0x32b", + "0x32c", + "0x32d", + "0x32e", + "0x32f", + "0x382d", + "0x330", + "0x331", + "0x332", + "0x37de", + "0x37e3", + "0x37e8", + "0x37ed", + "0x37f2", + "0x37f7", + "0x37fc", + "0x3801", + "0x3806", + "0x380b", + "0x3810", + "0x3815", + "0x381a", + "0x381f", + "0x3824", + "0x3828", + "0x333", + "0x334", + "0x336", + "0x337", + "0x338", + "0x339", + "0x33a", + "0x33b", + "0x33d", + "0x33e", + "0x33f", + "0x340", + "0x341", + "0x342", + "0x343", + "0x345", + "0x346", + "0x3873", + "0x3844", + "0x3849", + "0x3868", + "0x347", + "0x385f", + "0x38c8", + "0x38bd", + "0x38ad", + "0x38a3", + "0x38b6", + "0x38d2", + "0x430", + "0x4ad", + "0x5cc", + "0x648", + "0x74c", + "0x837", + "0x938", + "0x9b1", + "0xa6e", + "0xaba", + "0xbe1", + "0xc31", + "0xc81", + "0xcd7", + "0xd27", + "0xdc5", + "0xe5d", + "0xe9f", + "0xf13", + "0xf87", + "0x1063", + "0x1129", + "0x119d", + "0x1247", + "0x129d", + "0x1319", + "0x1395", + "0x13f6", + "0x1457", + "0x1549", + "0x15cf", + "0x1690", + "0x172f", + "0x1777", + "0x17af", + "0x17e7", + "0x1842", + "0x189b", + "0x190b", + "0x1b84", + "0x1f86", + "0x1fc6", + "0x1fcd", + "0x208c", + "0x20e4", + "0x2225", + "0x2366", + "0x2484", + "0x24af", + "0x24d5", + "0x2554", + "0x25c3", + "0x267a", + "0x271f", + "0x27fc", + "0x297a", + "0x2993", + "0x2a11", + "0x2a79", + "0x2ab2", + "0x2b1b", + "0x2baa", + "0x2bef", + "0x2cba", + "0x2d6e", + "0x2db2", + "0x2eb5", + "0x3027", + "0x3089", + "0x33e8", + "0x3421", + "0x3487", + "0x34d5", + "0x3513", + "0x35ff", + "0x36ed", + "0x375d", + "0x37d3", + "0x3838", + "0x3882", + "0x1d587", + "0x700900500400300a007009005004003008007006005004003002001000", + "0x300e00700900500400300d00700900500400300c00700900500400300b", + "0x500400301100700900500400301000700900500400300f007009005004", + "0x7009005004003014007009005004003013007009005004003012007009", + "0x19018007009005004003017007009005004003016007009005004003015", + "0x502000502000502000502000502000502000501f01b01e01d01c01b01a", + "0x21020005020005020005020005020005020005020005020005020005020", + "0x2800900500900500900500900502701b02601902502402300701b007022", + "0x2e02d00502d00501c01b02b01900900500900502c01b02b01902a005029", + "0x503500303400503300500400303200700600500400303100503002f002", + "0x303a00700900500400303900503800502d00503500303700503600502d", + "0x500400303d00700900500400303c00700900500400303b007009005004", + "0x700600500400304000700600500400303f00700600500400303e007006", + "0x3044007006005004003043007006005004003042007006005004003041", + "0x5004003047007006005004003046007006005004003045007006005004", + "0x504c00504b01b02b01d04a005029028042005049005004003048007006", + "0x501c01b05001900600504f04e04d01b01a01900900501c01b022019020", + "0x305700505600502d00503500305500505400505301b05001d052005051", + "0x305b00700900500400305a00700900500400305900505800502d005035", + "0x6005f00503300500400300205e05d00700900500400305c007009005004", + "0x500400306300700600500400306200506100502d00503500302d005029", + "0x1b022019025067066007006005004003065007009005004003064007009", + "0x1d02506c05500506b00506a01b05001d06900501c01b022019006005068", + "0x507100507001b05001d06f00501c01b02201902000506e00506d01b02b", + "0x507600507501b02b01d07400502902807300507200502d005035003055", + "0x501c01b01e019025079078007009005004003077007009005004003020", + "0x507a00507a00507a00507a00507a00507a00507a00507a00507a00507a", + "0x500400304300707a00500400307a00507a00507a00507a00507a00507a", + "0x707a00500400307d00507c00500400307b00700600500400303900707a", + "0x308100707a00500400308000700600500400307f00700600500400307e", + "0x500400308300707a00500400308200507c00500400301600707a005004", + "0x707a00500400308500707a00500400308400507c00500400301700707a", + "0x8907b00707a00500400308800708700500400308600507c005004003018", + "0x5004003017007087005004003018007087005004003087005029060025", + "0x7087005004003014007087005004003015007087005004003016007087", + "0x304400707a00500400308a007006005004003012007087005004003013", + "0x500400304700707a00500400304600707a00500400304500707a005004", + "0x1b02b01d02d00502902802000707a00500400307a00502906008b00507c", + "0x1b09101902000509000508f01b02b01d08e00502902802000508d00508c", + "0x700600500400302000508e00509301b02b01d009005087005006005092", + "0x509801b022019025097096007006005004003095007006005004003094", + "0x509f09e09d00504f09c09b00700600500400309a007006005004003099", + "0x70060050040030a400501c01b0a301901b00709f0a209d00504f0a10a0", + "0x50a901b0220190a80050290a704a00504f04e0a60070060050040030a5", + "0x707a0050040030ad0050290a707a0050060050a80050ac01b0ab0190aa", + "0x190b00070060050040030af0070060050040030ae007006005004003007", + "0x707a0050040030550050b20050b101b05001d0200050ad00501c01b050", + "0x70b60b50070070b60b50050070b60b50250b40b3007006005004003037", + "0x509f0bc0bb0050b80050a30ba0470070b60b50b90050b80050a30b7048", + "0x1b0260190bf00701b0070220210bb0050a40050a30be00500709f0a20bd", + "0x30c40050290c50c400504f0c30020c20c10050c10050c10050c10050c0", + "0x702202101b0070c70050040030050070050070220210050070c6005004", + "0x30c90070060050040030450070c10050040030c40050290c801b00701b", + "0x50cd0050cd00501c01b0cc0190020cb0c400504f09c0ca007006005004", + "0x1b0a30190c400504f0a10ce00509f09e0480070c10050040030cd0050cd", + "0x50040030c10050c10050c10050c100501c01b0260190250d00cf00501c", + "0x503002f0020d30d200503002f0020d10440070c100500400301b0070c1", + "0x500400300500707a0050040030d600503002f0020d50ad00503002f0d4", + "0x600250db0da0070060050040030d90070060050040030250d80d7007006", + "0x501c01b02b0190de0070060050040030dd0070060050040030dc005029", + "0x190250e20050070e10050040030200050e00050df01b02b01d009005009", + "0x50040030e50070060050040030060050e401b0220190990050e301b022", + "0x70060050040030e80070060050040030e70070060050040030e6007006", + "0x501c01b0220190200050200050ea01b02b01d04800707a0050040030e9", + "0x50350030ef0050ee00502d0050350030550050ed0050ec01b05001d0eb", + "0x50040030f30070090050040030f20070090050040030f10050f000502d", + "0x50350030f70050f600502d0050350030f50070090050040030f4007009", + "0x50040030fb0070090050040030fa0070090050040030f90050f800502d", + "0x50350030ff0050fe00502d0050350030fd0070090050040030fc007009", + "0x500400310300700900500400310200700900500400310100510000502d", + "0x503500310700510600502d005035003105007009005004003104007009", + "0x500400310b00700900500400310a00700900500400310900510800502d", + "0x302511010f00510e00502d00503500310d00700900500400310c007009", + "0x1d02000511300511201b02b01d0bf007009005004003111007009005004", + "0x511700511601b05001d11500501c01b02201900600502000511401b02b", + "0x311a00511900502d0050350030eb00502d00502d00511801b091019055", + "0x311e00700900500400311d00700900500400311c00511b00502d005035", + "0x312200512100502d00503500312000700900500400311f007009005004", + "0x5004003125007009005004003124007009005004003123007006005004", + "0x700600500400312700512600502d00503500300900502906003f005049", + "0x512b00502d00503500312a007009005004003129007009005004003128", + "0x700900500400312f00700900500400312e00512d00502d00503500312c", + "0x3133007006005004003132007009005004003131007009005004003130", + "0x313700700900500400313600700600500400313500513400502d005035", + "0x513a00502d00503500313a00513900502d005035003138007009005004", + "0x507a00507a00507a00507a00501c01b13c01913b00707a00500400313a", + "0x513e01b02201913d0050290a707a00504f04e07a00507a00507a00507a", + "0x514400514301b05001d02000514200514100501c01b09101902514013f", + "0x514d00514c00514b00514a005149005148005147005146005145003055", + "0x500400315000707a00500400314f00707a00500400314600502902814e", + "0x707a00500400315300707a00500400315200707a00500400315100707a", + "0x513d00501c01b05001915600707a00500400315500707a005004003154", + "0x700600500400315900707a00500400305500515800515701b05001d020", + "0x315d00700600500400315c00700600500400315b00700600500400315a", + "0x504f04e16000700900500400315f00700600500400315e007009005004", + "0x1d02000516100501c01b05001916300516201b0220191610050290a7087", + "0x516701b0220191660050290a702d00504f04e05500516500516401b050", + "0x305500516b00516a01b05001d02000516100516900501c01b0ab019168", + "0x500400300700700600500400300500700900500400301b007009005004", + "0x700600500400316e00700600500400316d00700600500400316c007006", + "0x517201b0220191710050290a708e00504f04e17000700600500400316f", + "0xa705500517600517501b05001d0eb00517400517400501c01b091019173", + "0x1d0eb00517900517900501c01b09101917800517701b022019052005029", + "0x1b17f01902517e17d00502902817c00502902805500517b00517a01b050", + "0x518601b185019184005029028006005183005183005182005181005180", + "0x5179005009005174005006005006005006005179005009005183005006", + "0x517400518701b02b01d18300503002f17c00503002f17900507a00507a", + "0x1b05001d18900517900501c01b05001902000517100518801b05001d020", + "0x517900501c01b02b01902000517900518c01b02b01d05500518b00518a", + "0x708700500400319000700600500400305500518f00518e01b05001d18d", + "0x3193007006005004003192007006005004003191007006005004003005", + "0x3002195194007006005004003036007006005004003020007006005004", + "0x519900519801b02b01d0e000500600519701b02b019196007006005004", + "0x519d00501c01b02b01919c01b01a01919b00700600500400300219a020", + "0x70060050040031a000700600500400305500519f00519e01b05001d006", + "0x501c01b1a50190021a40060050b61a300600504f1a20060050290601a1", + "0x1b02b01902000517c0051a801b02b01d0550051a70051a601b05001d020", + "0x50870051ac01b0910190550051ab0051aa01b05001d1a900517900501c", + "0x501c01b02b01917d00503002f02000517d0051ad01b02b01d183005087", + "0x1b1b001901b0070870050040030550051af0051ae01b05001d020005087", + "0x70060050040030251b30550051b20051b101b05001d02000519d00501c", + "0x505200501c01b0500191b60070060050040031b50070060050040031b4", + "0x2f0021b917900503002f05200503002f0550051b80051b701b05001d020", + "0x1b0500190200050520051bc01b05001d1bb0070060050040031ba005030", + "0x1b02b01d0060050290280550051bf0051be01b05001d1bd00517900501c", + "0x70060050040031c200700600500400300600503002f0200051c10051c0", + "0x31c300700600500400302300700600500400301b007006005004003005", + "0x500400317900501c01b0220191c50070060050040031c4007006005004", + "0x1ca1c90070060050040030550051c80051c701b05001d0251c601b00707a", + "0x51d101b1d001b1cf01b1ce1cd0021cc0200050060051cb01b02b01d025", + "0x60050051d60060050051d50060050051d401b0050051d301b1d2179005", + "0x200050051da01b1d91d80050051d31780050051d301b0071d80050071d7", + "0x51de1780050051de01b1dd01b1dc1d80050051db0050071d80050071d7", + "0x51d31e20050051e10060050051e00060050051de1df0050051de1c1005", + "0x50071e40050071d70550050051da0510050051da0060050051e3006005", + "0x1b1e81e70050051d301b1e61e40050051d31ba0050051d31e50050051d3", + "0x1b1ec01b1eb07a0050051d31df0050051ea07a0050051ea1e90050051e1", + "0x1e40050071d71c80050051da1790050051da0520050051de0520050051ed", + "0x51e10200050051de1ee0050051e107a0050051de0520050051d301b007", + "0x51e11f20050051e11f10050051e11790050051de1f00050051e11ef005", + "0x71d701b1f80060050051f701b1f60060050051f51f40050051e11f3005", + "0x51d31f90050051db0050071f90050071d71f90050051d301b0071f9005", + "0x51de1bd0050051d31bf0050051d11fc0050051db1fb0480051fa179005", + "0x51de1fe0050051e101b1fd1bd0050051db0050071bd0050071d7183005", + "0x51de2000050051de0520050051f51790050051f51ba0050051f51ff005", + "0x51fa1790050051f71ba0050051f70520050051f72020050051de201005", + "0x1b2060060050052051780050051ea1b80050051d12040050051db203048", + "0x2090050051e12080050051e10510050051de0550050051d12070480051fa", + "0x51fa20c0050051d319d0050051da20c0050051de01b20b20a0050051e1", + "0x2100050051e10870050051de01b20f1b20050051de20e0050051db20d048", + "0x1af0050051de2120050051db2110480051fa0870050051d30870050051ed", + "0x51fa17d0050051f72150050051db2140480051fa17d0050051f501b213", + "0x51de17c0050051de1a90050051db1ab0050051d12170050051db216048", + "0x51fa17c0050051d317d0050051d319d0050051de19d0050051ed17d005", + "0x21c0480051fa01b21b21a0050051de1a70050051de2190050051db218048", + "0x2220480051fa2210050051d300600500522021f0050051d301b21e01b21d", + "0x2250050051de0eb0050051d30050070eb0050071d701b2242230050051de", + "0x51fa2280480051fa01b22701b2260eb0050051de01b0070eb0050071d7", + "0x22b0050051e101b22a0540480051fa2290480051fa0310050051d304c048", + "0x22e0050051e119f0050051d122d0050051db0510480051fa22c0050051e1", + "0x51d301b22f1830050051ea0060050051ea0550480051fa0520480051fa", + "0x51d31990050051de2330050051db2320480051fa2310480051fa230005", + "0x51de1990050051d11990050051ea1990050051ed2340480051fa199005", + "0x2370050051d32360050051e101b2350090050051d60e00050051d10e0005", + "0xd40050051d32390050051e12380050051e10590480051fa0570480051fa", + "0x550050051d30560480051fa0580480051fa0d20050051d30d60050051d3", + "0x1df0050051d301b23e01b23d23c00700523b23a0480051fa1830050051d3", + "0x1fc0050051d301b0071fc0050071d71bf0050051da01b0071bd0050071d7", + "0x2040050051d301b0072040050071d71b80050051da0050071fc0050071d7", + "0x2410050051e12400050051e101b23f1790050051ea0050072040050071d7", + "0x51ea20e0050051d300500720e0050071d72430050051e12420050051e1", + "0x71d72470050051e101b2462450050051e101b2440870050051d6087005", + "0x51da01b0072120050071d71af0050051da2120050051d3005007212005", + "0x1b2480050072150050071d72150050051d301b0072150050071d717d005", + "0x8e0050051e018d0050051db18f0050051d124a0050051db2490480051fa", + "0x1890050051db18b0050051d124b0050051db0330480051fa1710050051d3", + "0x51d301b00724c0050071d71740050051da1710050051de1710050051ed", + "0x51d30050072170050071d70090050051de00500724c0050071d724c005", + "0x51da01b0071a90050071d717c0050051da01b24d24c0050051db217005", + "0x51f50050071a90050071d71740050051de01b0072170050071d71ab005", + "0x1840050051d11840050051d524f0050051d301b24e17c0050051f5183005", + "0x17d0050051d117d0050051ea17d0050051ed17d0050051d51810050051d3", + "0x1830050051d61820050051de2500050051de1830050051f71820050051d3", + "0x17c0050051d117c0050051ea17c0050051ed17c0050051f717c0050051d5", + "0x17b0050051d12530050051db05f0480051fa01b2521790050051d601b251", + "0x1740050051ea1740050051d61e50050051d601b0050051d60eb0050051db", + "0x2550050051db2540480051fa1740050051d308e0050052051740050051d1", + "0x51d301b0072190050071d71a70050051da07a0050051d61760050051d1", + "0x2580050051e12570050051e10050072190050071d72560050051e1219005", + "0x51e101b25c20c0050051ea25b0050051de25a0050051e12590050051e1", + "0x51e11390050051e102d0050051e02230050051d300600500525e25d005", + "0x51ed0870050051e002d0050051e302d0050051d302d0050051da13a005", + "0x51fa1610050051d31690050051d31690050051da1660050051de166005", + "0x51db0610480051fa1690050051de16b0050051d125f0050051db062048", + "0x1b2622610050051da1610050051de1610050051ed1650050051d1260005", + "0x2650050051e12640050051e10090050051d32630050051e102d0050051d1", + "0x60050052672660050051e102d0050051de2610050051d30870050051e3", + "0x51e101b00720e0050071d71b20050051da2680050051e11c10050051d3", + "0x51d307a0050051e326b0050051e107a0050051e026a0050051e1269005", + "0x51d101b27001b00726f00500726e26d0050051db26c0480051fa13d005", + "0x51d31410050051d31410050051da13d0050051de13d0050051ed158005", + "0x1b2721410050051de1440050051d12710050051db0060480051fa142005", + "0x2750050051e12740050051e11460050051d11460050051d52730050051d3", + "0x51db06f0050051d306f0050051de06f0050051ed01b2772760050051e1", + "0x51e127a0050051e12790050051e12780050051e106e0050051de06f005", + "0x27e0050051e102d0050051ed01b27d02d0050051ea27c0050051e127b005", + "0x1b2820180050051e101b2810490050051d32800050051e127f0050051e1", + "0x690050051da2860050051da2850050051e12840050051e12830050051e1", + "0x1170050051d12870050051db0690480051fa0690050051d32860050051d3", + "0x51db2890050051d32890050051de2890050051ed01b2881150050051db", + "0x1b28d28c0050051e128b0050051e128a0050051e11130050051de289005", + "0x2920050051e12910050051e12900050051e128f0050051e128e0050051e1", + "0xed0050051de2940050051db06b0480051fa1130050051d32930050051e1", + "0x22d0050051d300500722d0050071d700600500529701b2962950050051e1", + "0x22d0050071d719f0050051da1ba0050051d62990050051e12980050051e1", + "0x51ed29d0050051da29c0050051e129b0050051e129a0050051e101b007", + "0x51ed2a00050051da01b29f01b29e29d0050051d129d0050051de29d005", + "0x51e10990050051ea0990050051d62a00050051d12a00050051de2a0005", + "0x51d301b0072a30050071d70e00050051da0990050051de01b2a22a1005", + "0x2330050071d71990050051da2a30050051db0050072a30050071d72a3005", + "0x51e12a50050051e101b2a40050072330050071d72330050051d301b007", + "0x2ab0050051e12aa0050051e10dc0050052a92a80050051d301b2a72a6005", + "0x2ae0050051e101b2ad0dc0050051de0dc0050051d301b2ac0dc0050051ea", + "0x523b01b2b401b2b32a80050051de01b2b201b2b12b00050051d301b2af", + "0x51f50d60050051f52b60050051e11810050051de0990050051d32b5007", + "0x51da2b80050051e12b70050051e10d20050051f50d40050051f50ad005", + "0xc10050052bd2bc0050051e10c40050052bb01b2ba2b90050051d32b9005", + "0x2c10050051de0c40050052c02be0050051d32bf0050051d32be0050051da", + "0x2c60050051de2c50050051de2c40050051de2c30050051de2c20050051de", + "0x2cb0050051e10c40050052ca2c90050051e12c80050051e12c70050051e1", + "0xc40050072ce0c40050052cd0c60050051d30c70050051d32cc0050051e1", + "0x52cf0480070052cf0470070052cf0d20050051f70d60050051f70cf005", + "0x51da2d20050051de2d20050051ed01b2d10cd0050051d301b2d0007007", + "0x51e104a0050051e00d40050051f72d30480051fa2d20050051d32d2005", + "0x51db06e0480051fa0ad0050051d30ad0050051da2d50050051e12d4005", + "0x51e12d90050051e12d80050051e12d70050051e10b20050051d12d6005", + "0x52dc2db0050051ea0ad0050051de0ad0050051ed0ad0050051f72da005", + "0x51fa2dd0050051d32dd0050051da04a0050052050aa0050051ea0ad005", + "0x1b2e02df0050051e12de0050051de2db0050051de0aa0050051de06f048", + "0x9d0050052c02e20050051d309d0050052bb2e10050051e12bf0050051de", + "0x2e60050051e10060050052e52e40050051e12e20050051de2e30050051de", + "0x2e70050051e10850050051d10850050051de0850050051ed0850050051da", + "0x71d718f0050051da01b00718d0050071d70060050052e92e80050051e1", + "0x71d72ea0050051e100500724a0050071d724a0050051d301b00724a005", + "0x1b00724b0050071d718b0050051da01b0071890050071d700500718d005", + "0x1890050071d708e0050051e32eb0050051db0710480051fa24b0050051d3", + "0x51d301b0072530050071d717b0050051da00500724b0050071d7005007", + "0x51d301b0072ec0050071d708e0050051d40050072530050071d7253005", + "0x8e0050051d52ec0050051db0050072ec0050071d72ec0050051d3173005", + "0x1760050051da08e0050051de08e0050051d108e0050051ea08e0050051d3", + "0x50072550050071d71730050051de2550050051d301b0072550050071d7", + "0x51d31680050051d301b0072ed0050071d702d0050051d41690050051d1", + "0x2d0050051d602d0050051d52ed0050051db0050072ed0050071d72ed005", + "0x71d716b0050051da25f0050051d300500725f0050071d72ee0480051fa", + "0x51e101b2f007c0050051d32ef0050051e108700500520501b00725f005", + "0x71d72f50050051e12f40050051e12f30050051e12f20050051e12f1005", + "0x2f80050051e12f70050051e12f60050051e12600050051d3005007260005", + "0x1b2fe01b2fd2fc0050051e12fb0050051e12fa0050051e12f90050051e1", + "0x2600050071d71650050051da2ff0050051e10340480051fa07d0050051e1", + "0x51e13010050051e10820050051e13000050051e107a00500520501b007", + "0x51e13040050051e107c0050051d63030050051e10840050051e1302005", + "0x3090050051e101b30807a00508700500730701b3063050050051e1086005", + "0x51e130b0050051e130a0050051e126d0050051d300500726d0050071d7", + "0x51da30f0050051e130e0050051e10760480051fa30d0050051e130c005", + "0x3110050071d70740050053101410050051d101b00726d0050071d7158005", + "0x3110050051db0050073110050071d73110050051d313f0050051d301b007", + "0x1440050051da2710050051d30050072710050071d701b3120760050051d6", + "0x51e12860050051d12860050051ea1420050051de01b0072710050071d7", + "0x3110480051fa2860050051de0690050051de01b3130090050051ea034005", + "0x2d30050051db0730480051fa06e0050051d30710050051d12ee0050051db", + "0x51da01b0071150050071d70690050051d10690050051ed06b0050051d1", + "0x1150050071d726c0050051e12870050051d301b0072870050071d7117005", + "0x2490050051e105f0050051e12540050051e10050072870050071d7005007", + "0x720480051fa02d0050052a901b31501b3140330050051d30330050051ea", + "0x2940050071d70ed0050051da01b31701b3162320050051e12340050051e1", + "0x2d20050051ea0330050051de0050072940050071d72940050051d301b007", + "0x51d10060050c10050073180c10050051d60c10050051de2d20050051d1", + "0xa80050051de01b3190540050051d12310050051db07a0480051fa0ad005", + "0x2d60050051d30050072d60050071d70520050051d604a0050051e301b31a", + "0x51d42dd0050051d101b0072d60050071d70b20050051da0ad0050051d6", + "0x2290050071d72290050051d30aa0050051d301b0072290050071d704a005", + "0x2dd0050051de01b31b04a0050051d604a0050051d52290050051db005007", + "0x50072eb0050071d72eb0050051d301b0072eb0050071d708e0050051da", + "0x51e121c0050051e12220050051e10870050090050073072280050051e1", + "0x51e120d0050051e12110050051e12140050051e12160050051e1218005", + "0x31e0050051e101b31d31c0050051e11fb0050051e12030050051e1207005", + "0x51da01b00706f0050071d701b32201b3213200050051e131f0050051e1", + "0x51e10050072ee0050071d72ee0050051d301b0072ee0050071d7071005", + "0x2a0050051ed02a0050051da0310050051f500500706f0050071d70c9005", + "0x740480051fa02a00500532402a00500532302a0050051d302a0050051de", + "0x2d30050051d301b0072d30050071d706b0050051da01b3250310050051f7", + "0x51d33290050051da01b32801b3273260050051de0050072d30050071d7", + "0x51d319100500532c32b00507a0050073073290050051de01b32a329005", + "0x51e103e0050051e10230050051e107b0050051e11910050051db191005", + "0x51e10420050051e10410050051e10400050051e11940050051e103f005", + "0x51e10470050051e10460050051e10450050051e10440050051e1043005", + "0x2310050051d301b0072310050071d70540050051da0070050051e1048005", + "0x32e00501b01b01b32d30f0480051fa0050072310050071d70050050051e1", + "0x32e00501b00701b04404500732f04604700732e00700501b00700501b01b", + "0x504700504601b01b32e00501b04701b04300532e00504800504801b01b", + "0x32e00501b00701b04000503e04104200732e00704300504501b04700532e", + "0x504201b03f00532e00519400504301b19400532e00504100504401b01b", + "0x532e00503e00504001b02300532e00504200504101b03e00532e00503f", + "0x2000532e00501b03f01b01b32e00501b00701b01b32b00501b19401b07b", + "0x19100504001b02300532e00504000504101b19100532e00502000503e01b", + "0x32e00501b00701b0090052d732b00532e00707b00502301b07b00532e005", + "0x1b32e00501b00701b02d0052db33032900732e00732b04700707b01b01b", + "0x32600503903102a00732e00702300504501b32900532e00532900504601b", + "0x32e0050c900504301b0c900532e00503100504401b01b32e00501b00701b", + "0x4001b31e00532e00502a00504101b31f00532e00532000504201b320005", + "0x3f01b01b32e00501b00701b01b20300501b19401b03700532e00531f005", + "0x532e00532600504101b03800532e00503900503e01b03900532e00501b", + "0x31c0052e803600532e00703700502301b03700532e00503800504001b31e", + "0x701b2070050582031fb00732e00731e00504501b01b32e00501b00701b", + "0x532b01b01b32e0051fb00519101b01b32e00501b02001b01b32e00501b", + "0x33001b01b32e00503600532901b01b32e00533000500901b01b32e005203", + "0x21100532e00521100502a01b21100532e00501b02d01b20d00532e00501b", + "0x2160070c901b21600532e00501b32601b21400532e00521120d00703101b", + "0x532e00532900504601b21c00532e00521800532001b21800532e005214", + "0x503701b00700532e00500700531e01b04600532e00504600531f01b329", + "0x519101b01b32e00501b00701b21c00704632904700521c00532e00521c", + "0x1b22200532e00522200503801b22200532e00501b03901b01b32e005207", + "0x1b32e00501b00701b0542290072f604c22800732e007222046329048036", + "0x33000520301b05205100732e0050510051fb01b05100532e00501b31c01b", + "0x532e00522800504601b05200532e00505200520701b05533000732e005", + "0x1b05905723404808423223100732e00703605505200704c04620d01b228", + "0x532e00505100520701b23100532e00523100531f01b01b32e00501b007", + "0x1b05f03324904830923a05605804832e00733005123223104721101b051", + "0x2a01b25400532e00501b33001b01b32e00501b02001b01b32e00501b007", + "0x506200521401b06200532e00523a25400703101b23a00532e00523a005", + "0x1b00600532e00526c00521801b01b32e00506100521601b26c06100732e", + "0x522800504601b06b00532e00506900522201b06900532e00500600521c", + "0x1b05600532e00505600531e01b05800532e00505800531f01b22800532e", + "0x1b01b32e00501b00701b06b05605822804700506b00532e00506b005037", + "0x505f00522801b06e00532e00503300531e01b2d300532e00524900531f", + "0x533000500901b01b32e00501b00701b01b07d00501b19401b06f00532e", + "0x531e01b2d300532e00523400531f01b01b32e00505100504c01b01b32e", + "0x1b01b32e00501b02001b06f00532e00505900522801b06e00532e005057", + "0x52ee00532001b2ee00532e00506f0710070c901b07100532e00501b326", + "0x1b2d300532e0052d300531f01b22800532e00522800504601b03400532e", + "0x6e2d322804700503400532e00503400503701b06e00532e00506e00531e", + "0x1b32e00533000500901b01b32e00501b02001b01b32e00501b00701b034", + "0x532e00501b22901b07600532e00501b33001b01b32e00503600532901b", + "0x32601b07300532e00531107600703101b31100532e00531100502a01b311", + "0x32e00507a00532001b07a00532e0050730720070c901b07200532e00501b", + "0x31e01b05400532e00505400531f01b22900532e00522900504601b074005", + "0x7400705422904700507400532e00507400503701b00700532e005007005", + "0x1b01b32e00531c00505401b01b32e00501b02001b01b32e00501b00701b", + "0x30f00532e00501b33001b01b32e00531e00519101b01b32e005330005009", + "0x30e30f00703101b30e00532e00530e00502a01b30e00532e00501b05101b", + "0x30b00532e00530d30c0070c901b30c00532e00501b32601b30d00532e005", + "0x4600531f01b32900532e00532900504601b30a00532e00530b00532001b", + "0x30a00532e00530a00503701b00700532e00500700531e01b04600532e005", + "0x1b01b32e00502300519101b01b32e00501b00701b30a007046329047005", + "0x1b01b32e00501b00701b01b2d400501b19401b30900532e00502d005046", + "0x532e00504700504601b01b32e00502300519101b01b32e005009005054", + "0x532e00501b05201b30500532e00501b33001b01b32e00501b02001b309", + "0x32601b30400532e00508630500703101b08600532e00508600502a01b086", + "0x32e00508400532001b08400532e0053043030070c901b30300532e00501b", + "0x31e01b04600532e00504600531f01b30900532e00530900504601b302005", + "0x30200704630904700530200532e00530200503701b00700532e005007005", + "0x30100532e00501b33001b01b32e00504800505501b01b32e00501b00701b", + "0x8230100703101b08200532e00508200502a01b08200532e00501b22901b", + "0x7d00532e0053002ff0070c901b2ff00532e00501b32601b30000532e005", + "0x4400531f01b04500532e00504500504601b08700532e00507d00532001b", + "0x8700532e00508700503701b00700532e00500700531e01b04400532e005", + "0x732e00700501b00700501b01b32e00501b01b01b087007044045047005", + "0x4300532e00504800504801b01b32e00501b00701b044045007274046047", + "0x400052a804104200732e00704300504501b04700532e00504700504601b", + "0x1b32e00504100532b01b01b32e00504200519101b01b32e00501b00701b", + "0x32e00503f00502a01b03f00532e00501b02d01b19400532e00501b33001b", + "0xc901b02300532e00501b32601b03e00532e00503f19400703101b03f005", + "0x504700504601b02000532e00507b00532001b07b00532e00503e023007", + "0x1b00700532e00500700531e01b04600532e00504600531f01b04700532e", + "0x1b01b32e00501b00701b02000704604704700502000532e005020005037", + "0x532e00519100503801b19100532e00501b03901b01b32e005040005191", + "0x501b00701b33032900727c00932b00732e00719104604704803601b191", + "0x707b01b02d00532e00502d00502a01b02d00532e00501b23101b01b32e", + "0x501b31c01b01b32e00501b00701b32600528603102a00732e00702d32b", + "0x1b31f0c900732e0050c90051fb01b32000532e00501b23201b0c900532e", + "0x32000502a01b31f00532e00531f00520701b31e03100732e005031005203", + "0x32031e31f00700904620d01b02a00532e00502a00504601b32000532e005", + "0x501b23401b01b32e00501b00701b31c03603804828a03903700732e007", + "0x1b0c900532e0050c900520701b03700532e00503700531f01b1fb00532e", + "0x20720300732e0071fb0310c903903704620d01b1fb00532e0051fb00502a", + "0x21401b21600532e00501b33001b01b32e00501b00701b21421120d04828c", + "0x32e00521c00521801b01b32e00521800521601b21c21800732e005216005", + "0x4601b04c00532e00522800522201b22800532e00522200521c01b222005", + "0x32e00520700531e01b20300532e00520300531f01b02a00532e00502a005", + "0x501b00701b04c20720302a04700504c00532e00504c00503701b207005", + "0x31e01b05400532e00520d00531f01b22900532e00502a00504601b01b32e", + "0x1b12200501b19401b05200532e00521400522801b05100532e005211005", + "0x1b32e00503100500901b01b32e0050c900504c01b01b32e00501b00701b", + "0x3600531e01b05400532e00503800531f01b22900532e00502a00504601b", + "0x701b01b12200501b19401b05200532e00531c00522801b05100532e005", + "0x2a01b23100532e00501b05701b05500532e00501b33001b01b32e00501b", + "0x532600504601b23200532e00523105500703101b23100532e005231005", + "0x1b05100532e00500700531e01b05400532e00500900531f01b22900532e", + "0x50522340070c901b23400532e00501b32601b05200532e005232005228", + "0x1b22900532e00522900504601b05900532e00505700532001b05700532e", + "0x505900503701b05100532e00505100531e01b05400532e00505400531f", + "0x32e00501b33001b01b32e00501b00701b05905105422904700505900532e", + "0x703101b05600532e00505600502a01b05600532e00501b22901b058005", + "0x32e00523a2490070c901b24900532e00501b32601b23a00532e005056058", + "0x31f01b32900532e00532900504601b05f00532e00503300532001b033005", + "0x32e00505f00503701b00700532e00500700531e01b33000532e005330005", + "0x32e00504800505501b01b32e00501b00701b05f00733032904700505f005", + "0x506200502a01b06200532e00501b22901b25400532e00501b33001b01b", + "0x1b26c00532e00501b32601b06100532e00506225400703101b06200532e", + "0x4500504601b06900532e00500600532001b00600532e00506126c0070c9", + "0x700532e00500700531e01b04400532e00504400531f01b04500532e005", + "0x532e00501b05901b06900704404504700506900532e00506900503701b", + "0x1b32e00501b01b01b01b32e00501b05801b04400532e00501b05901b046", + "0x1b32e00501b00701b04004100733104204300732e00700501b00700501b", + "0x32e00504300504601b01b32e00501b04701b19400532e00504800504801b", + "0x1b32e00501b00701b02300516503e03f00732e00719400504501b043005", + "0x2000504201b02000532e00507b00504301b07b00532e00503e00504401b", + "0x900532e00519100504001b32b00532e00503f00504101b19100532e005", + "0x1b32900532e00501b03f01b01b32e00501b00701b01b16b00501b19401b", + "0x533000504001b32b00532e00502300504101b33000532e00532900503e", + "0x1b32e00501b00701b02d00533204500532e00700900502301b00900532e", + "0x33303102a00732e00704504300723a01b04500532e00504504400705601b", + "0x32b00504501b02a00532e00502a00504601b01b32e00501b00701b326005", + "0x32e00532000504401b01b32e00501b00701b31f0052553200c900732e007", + "0x4101b03900532e00503700504201b03700532e00531e00504301b31e005", + "0x1b18200501b19401b03600532e00503900504001b03800532e0050c9005", + "0x532e00531c00503e01b31c00532e00501b03f01b01b32e00501b00701b", + "0x502301b03600532e0051fb00504001b03800532e00531f00504101b1fb", + "0x504704600705601b01b32e00501b00701b20300533404700532e007036", + "0x32e00501b00701b21100518920d20700732e00703800504501b04700532e", + "0x503301b21600532e00520700504101b21400532e00520d00524901b01b", + "0x1b03f01b01b32e00501b00701b01b24a00501b19401b21800532e005214", + "0x21600532e00521100504101b22200532e00521c00505f01b21c00532e005", + "0x1b04c00521a22800532e00721800525401b21800532e00522200503301b", + "0x1b22900532e00522800504401b01b32e00501b02001b01b32e00501b007", + "0x32e00522900504301b05100532e00521600521801b05400532e00501b330", + "0x6201b04200532e00504200531f01b02a00532e00502a00504601b052005", + "0x32e00505200502a01b05400532e00505400522801b05100532e005051005", + "0x23200526c01b23223105504832e00505205405104202a04606101b052005", + "0x732e00523400500601b01b32e00501b00701b05700522123400532e007", + "0x31f01b23a00532e00505500504601b05600532e00505900504801b058059", + "0x32e00505800506901b03300532e00505600504101b24900532e005231005", + "0x32e00503100506b01b01b32e00501b00701b01b20800501b19401b05f005", + "0x5500504601b25400532e00505700532001b01b32e00504700532901b01b", + "0x700532e00500700531e01b23100532e00523100531f01b05500532e005", + "0x1b32e00501b00701b25400723105504700525400532e00525400503701b", + "0x6200532e00501b03f01b01b32e00504c00505401b01b32e00501b02001b", + "0x4200531f01b23a00532e00502a00504601b06100532e0050620052d301b", + "0x5f00532e00506100506901b03300532e00521600504101b24900532e005", + "0x504501b01b32e00501b00701b00600533526c00532e00705f00506e01b", + "0x506900519101b01b32e00501b00701b2d30051c806b06900732e007033", + "0x4700532901b01b32e00526c00521601b01b32e00506b00532b01b01b32e", + "0x1b02d01b06e00532e00501b33001b01b32e00503100506b01b01b32e005", + "0x532e00506f06e00703101b06f00532e00506f00502a01b06f00532e005", + "0x532001b03400532e0050712ee0070c901b2ee00532e00501b32601b071", + "0x532e00524900531f01b23a00532e00523a00504601b07600532e005034", + "0x23a04700507600532e00507600503701b00700532e00500700531e01b249", + "0x501b03901b01b32e0052d300519101b01b32e00501b00701b076007249", + "0x732e00731124923a04803601b31100532e00531100503801b31100532e", + "0x30f00732e00526c00521401b01b32e00501b00701b07407a007336072073", + "0x7300504601b30d00532e00530e00521801b01b32e00530f00521601b30e", + "0x4833730a30b30c04832e00730d04703100707204606f01b07300532e005", + "0x522201b30400532e00530a00521c01b01b32e00501b00701b086305309", + "0x532e00530c00531f01b07300532e00507300504601b30300532e005304", + "0x7304700530300532e00530300503701b30b00532e00530b00531e01b30c", + "0x840070c901b08400532e00501b32601b01b32e00501b00701b30330b30c", + "0x532e00507300504601b30100532e00530200532001b30200532e005086", + "0x503701b30500532e00530500531e01b30900532e00530900531f01b073", + "0x521601b01b32e00501b00701b30130530907304700530100532e005301", + "0x33001b01b32e00503100506b01b01b32e00504700532901b01b32e00526c", + "0x30000532e00530000502a01b30000532e00501b22901b08200532e00501b", + "0x7d0070c901b07d00532e00501b32601b2ff00532e00530008200703101b", + "0x532e00507a00504601b33800532e00508700532001b08700532e0052ff", + "0x503701b00700532e00500700531e01b07400532e00507400531f01b07a", + "0x505401b01b32e00501b00701b33800707407a04700533800532e005338", + "0x6b01b01b32e00504700532901b01b32e00503300519101b01b32e005006", + "0x1b2fb00532e00501b07101b2fc00532e00501b33001b01b32e005031005", + "0x501b32601b2fa00532e0052fb2fc00703101b2fb00532e0052fb00502a", + "0x2f700532e0052f800532001b2f800532e0052fa2f90070c901b2f900532e", + "0x700531e01b24900532e00524900531f01b23a00532e00523a00504601b", + "0x701b2f700724923a0470052f700532e0052f700503701b00700532e005", + "0x519101b01b32e00520300505401b01b32e00501b02001b01b32e00501b", + "0x33001b01b32e0050460052ee01b01b32e00503100506b01b01b32e005038", + "0x2f500532e0052f500502a01b2f500532e00501b05101b2f600532e00501b", + "0x2f30070c901b2f300532e00501b32601b2f400532e0052f52f600703101b", + "0x532e00502a00504601b2f100532e0052f200532001b2f200532e0052f4", + "0x503701b00700532e00500700531e01b04200532e00504200531f01b02a", + "0x52ee01b01b32e00501b00701b2f100704202a0470052f100532e0052f1", + "0x1b2ef00532e00532600504601b01b32e00532b00519101b01b32e005046", + "0x2ee01b01b32e00502d00505401b01b32e00501b00701b01b33900501b194", + "0x1b01b32e0050440052ee01b01b32e00532b00519101b01b32e005046005", + "0x7c00532e00501b33001b01b32e00501b02001b2ef00532e005043005046", + "0x8b07c00703101b08b00532e00508b00502a01b08b00532e00501b05201b", + "0x9000532e00508d2ed0070c901b2ed00532e00501b32601b08d00532e005", + "0x4200531f01b2ef00532e0052ef00504601b2ec00532e00509000532001b", + "0x2ec00532e0052ec00503701b00700532e00500700531e01b04200532e005", + "0x1b01b32e0050460052ee01b01b32e00501b00701b2ec0070422ef047005", + "0x8e00532e00501b33001b01b32e0050440052ee01b01b32e005048005055", + "0x2eb08e00703101b2eb00532e0052eb00502a01b2eb00532e00501b22901b", + "0x2e700532e0052ea2e80070c901b2e800532e00501b32601b2ea00532e005", + "0x4000531f01b04100532e00504100504601b09900532e0052e700532001b", + "0x9900532e00509900503701b00700532e00500700531e01b04000532e005", + "0x4400532e00501b07601b04600532e00501b03401b099007040041047005", + "0x532e00501b31101b04000532e00501b05901b04200532e00501b05901b", + "0x32e00501b05801b02000532e00501b05901b02300532e00501b05901b03f", + "0x900733a32b19100732e00700501b00700501b01b32e00501b01b01b01b", + "0x32e00501b04701b33000532e00504800504801b01b32e00501b00701b329", + "0x533b02a02d00732e00733000504501b19100532e00519100504601b01b", + "0x532600504301b32600532e00502a00504401b01b32e00501b00701b031", + "0x1b31f00532e00502d00504101b32000532e0050c900504201b0c900532e", + "0x1b01b32e00501b00701b01b33c00501b19401b31e00532e005320005040", + "0x32e00503100504101b03900532e00503700503e01b03700532e00501b03f", + "0x533d07b00532e00731e00502301b31e00532e00503900504001b31f005", + "0x19100723a01b07b00532e00507b02000705601b01b32e00501b00701b038", + "0x503600504601b01b32e00501b00701b1fb00533e31c03600732e00707b", + "0x32e00501b00701b20d00533f20720300732e00731f00504501b03600532e", + "0x504201b21400532e00521100504301b21100532e00520700504401b01b", + "0x532e00521600504001b21800532e00520300504101b21600532e005214", + "0x22200532e00501b03f01b01b32e00501b00701b01b34000501b19401b21c", + "0x22800504001b21800532e00520d00504101b22800532e00522200503e01b", + "0x32e00501b00701b04c00534104300532e00721c00502301b21c00532e005", + "0x34205422900732e00721800504501b04300532e00504304200705601b01b", + "0x22900504101b05200532e00505400524901b01b32e00501b00701b051005", + "0x701b01b34300501b19401b23100532e00505200503301b05500532e005", + "0x1b23400532e00523200505f01b23200532e00501b03f01b01b32e00501b", + "0x723100525401b23100532e00523400503301b05500532e005051005041", + "0x4401b01b32e00501b02001b01b32e00501b00701b05900534405700532e", + "0x532e00505500521801b05600532e00501b33001b05800532e005057005", + "0x531f01b03600532e00503600504601b24900532e00505800504301b23a", + "0x532e00505600522801b23a00532e00523a00506201b32b00532e00532b", + "0x4832e00524905623a32b03604606101b24900532e00524900502a01b056", + "0x1b32e00501b00701b06100534506200532e00725400526c01b25405f033", + "0x504601b06900532e00526c00504801b00626c00732e00506200500601b", + "0x532e00506900504101b2d300532e00505f00531f01b06b00532e005033", + "0x32e00501b00701b01b34600501b19401b06f00532e00500600506901b06e", + "0x503f00507301b01b32e0050400052ee01b01b32e00504300532901b01b", + "0x31c00506b01b01b32e00504400507a01b01b32e00504600507201b01b32e", + "0x4601b07100532e00506100532001b01b32e0050230052ee01b01b32e005", + "0x32e00500700531e01b05f00532e00505f00531f01b03300532e005033005", + "0x501b00701b07100705f03304700507100532e00507100503701b007005", + "0x32e00501b03f01b01b32e00505900505401b01b32e00501b02001b01b32e", + "0x31f01b06b00532e00503600504601b03400532e0052ee0052d301b2ee005", + "0x32e00503400506901b06e00532e00505500504101b2d300532e00532b005", + "0x1b01b32e00501b00701b07600534719400532e00706f00506e01b06f005", + "0x32e00706e00504501b19400532e00519403f00707401b01b32e00501b047", + "0x7a00532e00507300504401b01b32e00501b00701b072005348073311007", + "0x31100504101b30f00532e00507400504201b07400532e00507a00504301b", + "0x701b01b34900501b19401b30d00532e00530f00504001b30e00532e005", + "0x1b30b00532e00530c00503e01b30c00532e00501b03f01b01b32e00501b", + "0x730d00502301b30d00532e00530b00504001b30e00532e005072005041", + "0x532e00503e02300705601b01b32e00501b00701b30a00534a03e00532e", + "0x1b32e00501b00701b08600534b30530900732e00703e06b00723a01b03e", + "0x8400534c30330400732e00730e00504501b30900532e00530900504601b", + "0x32e00530200504301b30200532e00530300504401b01b32e00501b00701b", + "0x4001b30000532e00530400504101b08200532e00530100504201b301005", + "0x3f01b01b32e00501b00701b01b34d00501b19401b2ff00532e005082005", + "0x532e00508400504101b08700532e00507d00503e01b07d00532e00501b", + "0x33800534e04100532e0072ff00502301b2ff00532e00508700504001b300", + "0x730000504501b04100532e00504104000705601b01b32e00501b00701b", + "0x532e0052fb00524901b01b32e00501b00701b2fa00534f2fb2fc00732e", + "0x1b19401b2f700532e0052f900503301b2f800532e0052fc00504101b2f9", + "0x2f600505f01b2f600532e00501b03f01b01b32e00501b00701b01b350005", + "0x2f700532e0052f500503301b2f800532e0052fa00504101b2f500532e005", + "0x1b02001b01b32e00501b00701b2f30053512f400532e0072f700525401b", + "0x21801b2f100532e00501b33001b2f200532e0052f400504401b01b32e005", + "0x32e00530900504601b07c00532e0052f200504301b2ef00532e0052f8005", + "0x22801b2ef00532e0052ef00506201b2d300532e0052d300531f01b309005", + "0x2ef2d330904606101b07c00532e00507c00502a01b2f100532e0052f1005", + "0x1b2ec00535209000532e0072ed00526c01b2ed08d08b04832e00507c2f1", + "0x32e00508e00504801b2eb08e00732e00509000500601b01b32e00501b007", + "0x4101b2e700532e00508d00531f01b2e800532e00508b00504601b2ea005", + "0x1b35300501b19401b08500532e0052eb00506901b09900532e0052ea005", + "0x1b32e00530500506b01b01b32e00519400521601b01b32e00501b00701b", + "0x32e00531c00506b01b01b32e00504400507a01b01b32e00504600507201b", + "0x52ec00532001b01b32e00504300532901b01b32e00504100532901b01b", + "0x1b08d00532e00508d00531f01b08b00532e00508b00504601b2e600532e", + "0x708d08b0470052e600532e0052e600503701b00700532e00500700531e", + "0x1b32e0052f300505401b01b32e00501b02001b01b32e00501b00701b2e6", + "0x530900504601b2e300532e0052e40052d301b2e400532e00501b03f01b", + "0x1b09900532e0052f800504101b2e700532e0052d300531f01b2e800532e", + "0x701b2e200535409d00532e00708500506e01b08500532e0052e3005069", + "0x501b00701b2e10053550a00a400732e00709900504501b01b32e00501b", + "0x19400521601b01b32e0050a000532b01b01b32e0050a400519101b01b32e", + "0x507a01b01b32e00504600507201b01b32e00530500506b01b01b32e005", + "0x32901b01b32e00504100532901b01b32e00509d00521601b01b32e005044", + "0x1b2df00532e00501b33001b01b32e00531c00506b01b01b32e005043005", + "0x50a82df00703101b0a800532e0050a800502a01b0a800532e00501b02d", + "0x1b0ad00532e0050aa2dd0070c901b2dd00532e00501b32601b0aa00532e", + "0x52e700531f01b2e800532e0052e800504601b2db00532e0050ad005320", + "0x52db00532e0052db00503701b00700532e00500700531e01b2e700532e", + "0x3901b01b32e0052e100519101b01b32e00501b00701b2db0072e72e8047", + "0x72da2e72e804803601b2da00532e0052da00503801b2da00532e00501b", + "0x32e00519400521401b01b32e00501b00701b0b22d70073562d82d900732e", + "0x4601b2d400532e0052d500521801b01b32e0052d600521601b2d52d6007", + "0x35835704a04832e0072d404331c0072d804606f01b2d900532e0052d9005", + "0xb80b900732e00509d00521401b01b32e00501b00701b35b0cf35a048359", + "0x504a00531f01b0bb00532e0050b800521801b01b32e0050b900521601b", + "0x70bb04130535704a04606f01b35800532e00535800506201b04a00532e", + "0x501b33001b01b32e00501b00701b32f2d20c104835c0450470bd04832e", + "0x1b0bd00532e0050bd00531f01b2d900532e0052d900504601b2de00532e", + "0x4704600730f01b35800532e00535800506201b2de00532e0052de005228", + "0x3582de0bd2d904730d01b04500532e00504504400730e01b04700532e005", + "0x1b00701b0c700535e2cb00532e0070c600530c01b0c62cc35d04832e005", + "0x1b01b32e0052c900505401b2c935f00732e0052cb00530b01b01b32e005", + "0x535f00522801b2cc00532e0052cc00531f01b35d00532e00535d005046", + "0x32e00504535f2cc35d04730d01b04500532e00504500506201b35f00532e", + "0x32e00501b00701b2be0053600cd00532e0072c100530c01b2c12c72c8048", + "0x505401b2bf0c400732e0050cd00530b01b2bc00532e00501b33001b01b", + "0x1b32e0050ce00521601b2c60ce00732e0050c400521401b01b32e0052bf", + "0x530501b2b800532e0052b900530901b2b92c600732e0052c600530a01b", + "0x32e0052b72bc00703101b2b700532e0052b700502a01b2b700532e0052b8", + "0x31f01b2c800532e0052c800504601b2c500532e0052c600521801b0d2005", + "0x32e0050d200522801b2c500532e0052c500506201b2c700532e0052c7005", + "0x72c300530c01b2c32c20d404832e0050d22c52c72c804708601b0d2005", + "0x2b600732e0050d600530b01b01b32e00501b00701b2c40053610d600532e", + "0x521601b2ab2b000732e0052b600521401b01b32e0052ae00505401b2ae", + "0xdc00532e0052aa00521c01b2aa00532e0052ab00521801b01b32e0052b0", + "0x2c200531f01b0d400532e0050d400504601b2a800532e0050dc00522201b", + "0x2a800532e0052a800503701b04700532e00504700531e01b2c200532e005", + "0x2a600532e0052c400532001b01b32e00501b00701b2a80472c20d4047005", + "0x4700531e01b2c200532e0052c200531f01b0d400532e0050d400504601b", + "0x701b2a60472c20d40470052a600532e0052a600503701b04700532e005", + "0x1b32e0052a500530301b0e02a500732e0052be00530401b01b32e00501b", + "0x4700531e01b2a100532e0052c700531f01b2a300532e0052c800504601b", + "0x701b01b36200501b19401b2a000532e0050e000522801b0e100532e005", + "0x29c29d00732e0050c700530401b01b32e00504500505501b01b32e00501b", + "0x52cc00531f01b2a300532e00535d00504601b01b32e00529d00530301b", + "0x1b2a000532e00529c00522801b0e100532e00504700531e01b2a100532e", + "0x7201b01b32e00535800505501b01b32e00501b00701b01b36200501b194", + "0x2a300532e0052d900504601b01b32e00504400507a01b01b32e005046005", + "0x32f00522801b0e100532e0052d200531e01b2a100532e0050c100531f01b", + "0x30500506b01b01b32e00501b00701b01b36200501b19401b2a000532e005", + "0x521601b01b32e00504400507a01b01b32e00504600507201b01b32e005", + "0x1b2a300532e0052d900504601b01b32e00504100532901b01b32e00509d", + "0x535b00522801b0e100532e0050cf00531e01b2a100532e00535a00531f", + "0x1b29a00532e0052a029b0070c901b29b00532e00501b32601b2a000532e", + "0x52a100531f01b2a300532e0052a300504601b29900532e00529a005320", + "0x529900532e00529900503701b0e100532e0050e100531e01b2a100532e", + "0x6b01b01b32e00519400521601b01b32e00501b00701b2990e12a12a3047", + "0x1b01b32e00504400507a01b01b32e00504600507201b01b32e005305005", + "0x1b32e00504300532901b01b32e00504100532901b01b32e00509d005216", + "0x532e00501b22901b29800532e00501b33001b01b32e00531c00506b01b", + "0x32601b0eb00532e00529529800703101b29500532e00529500502a01b295", + "0x32e00529400532001b29400532e0050eb0ed0070c901b0ed00532e00501b", + "0x31e01b0b200532e0050b200531f01b2d700532e0052d700504601b293005", + "0x2930070b22d704700529300532e00529300503701b00700532e005007005", + "0x1b32e00519400521601b01b32e0052e200505401b01b32e00501b00701b", + "0x32e00504400507a01b01b32e00504600507201b01b32e00530500506b01b", + "0x504300532901b01b32e00504100532901b01b32e00509900519101b01b", + "0x501b08401b29200532e00501b33001b01b32e00531c00506b01b01b32e", + "0xf100532e0050ef29200703101b0ef00532e0050ef00502a01b0ef00532e", + "0xee00532001b0ee00532e0050f10f00070c901b0f000532e00501b32601b", + "0x2e700532e0052e700531f01b2e800532e0052e800504601b29100532e005", + "0x2e72e804700529100532e00529100503701b00700532e00500700531e01b", + "0x32e00533800505401b01b32e00501b02001b01b32e00501b00701b291007", + "0x519400521601b01b32e00530000519101b01b32e00504300532901b01b", + "0x4400507a01b01b32e00504600507201b01b32e00530500506b01b01b32e", + "0x1b33001b01b32e0050400052ee01b01b32e00531c00506b01b01b32e005", + "0x1b0f700532e0050f700502a01b0f700532e00501b30201b29000532e005", + "0xf90f80070c901b0f800532e00501b32601b0f900532e0050f7290007031", + "0x30900532e00530900504601b28f00532e0050f600532001b0f600532e005", + "0x28f00503701b00700532e00500700531e01b2d300532e0052d300531f01b", + "0x4300532901b01b32e00501b00701b28f0072d330904700528f00532e005", + "0x507201b01b32e00519400521601b01b32e0050400052ee01b01b32e005", + "0x19101b01b32e00531c00506b01b01b32e00504400507a01b01b32e005046", + "0x1b01b36300501b19401b28e00532e00508600504601b01b32e00530e005", + "0x1b01b32e00504300532901b01b32e00530a00505401b01b32e00501b007", + "0x1b32e00504600507201b01b32e00519400521601b01b32e0050400052ee", + "0x32e00530e00519101b01b32e00531c00506b01b01b32e00504400507a01b", + "0x501b02001b28e00532e00506b00504601b01b32e0050230052ee01b01b", + "0x10100502a01b10100532e00501b30101b0ff00532e00501b33001b01b32e", + "0xfe00532e00501b32601b10000532e0051010ff00703101b10100532e005", + "0x504601b28b00532e00528c00532001b28c00532e0051000fe0070c901b", + "0x532e00500700531e01b2d300532e0052d300531f01b28e00532e00528e", + "0x32e00501b00701b28b0072d328e04700528b00532e00528b00503701b007", + "0x50400052ee01b01b32e00504300532901b01b32e00507600505401b01b", + "0x4400507a01b01b32e00504600507201b01b32e00506e00519101b01b32e", + "0x507301b01b32e0050230052ee01b01b32e00531c00506b01b01b32e005", + "0x2a01b10900532e00501b07101b10700532e00501b33001b01b32e00503f", + "0x32e00501b32601b10800532e00510910700703101b10900532e005109005", + "0x1b11300532e00528a00532001b28a00532e0051081060070c901b106005", + "0x500700531e01b2d300532e0052d300531f01b06b00532e00506b005046", + "0x1b00701b1130072d306b04700511300532e00511300503701b00700532e", + "0x21800519101b01b32e00504c00505401b01b32e00501b02001b01b32e005", + "0x52ee01b01b32e00503f00507301b01b32e0050400052ee01b01b32e005", + "0x6b01b01b32e00504400507a01b01b32e00504600507201b01b32e005023", + "0x1b10f00532e00501b33001b01b32e0050420052ee01b01b32e00531c005", + "0x510e10f00703101b10e00532e00510e00502a01b10e00532e00501b051", + "0x1b11700532e0052891150070c901b11500532e00501b32601b28900532e", + "0x532b00531f01b03600532e00503600504601b28700532e005117005320", + "0x528700532e00528700503701b00700532e00500700531e01b32b00532e", + "0x2ee01b01b32e0050420052ee01b01b32e00501b00701b28700732b036047", + "0x1b01b32e0050230052ee01b01b32e00503f00507301b01b32e005040005", + "0x1b32e00531f00519101b01b32e00504400507a01b01b32e005046005072", + "0x1b32e00501b00701b01b36400501b19401b28600532e0051fb00504601b", + "0x32e0050400052ee01b01b32e0050420052ee01b01b32e00503800505401b", + "0x504600507201b01b32e0050230052ee01b01b32e00503f00507301b01b", + "0x200052ee01b01b32e00531f00519101b01b32e00504400507a01b01b32e", + "0x1b33001b01b32e00501b02001b28600532e00519100504601b01b32e005", + "0x1b28400532e00528400502a01b28400532e00501b05201b28500532e005", + "0x11a11c0070c901b11c00532e00501b32601b11a00532e005284285007031", + "0x28600532e00528600504601b11900532e00511b00532001b11b00532e005", + "0x11900503701b00700532e00500700531e01b32b00532e00532b00531f01b", + "0x420052ee01b01b32e00501b00701b11900732b28604700511900532e005", + "0x52ee01b01b32e00503f00507301b01b32e0050400052ee01b01b32e005", + "0x5501b01b32e00504400507a01b01b32e00504600507201b01b32e005023", + "0x1b28300532e00501b33001b01b32e0050200052ee01b01b32e005048005", + "0x501828300703101b01800532e00501800502a01b01800532e00501b229", + "0x1b28000532e0051221210070c901b12100532e00501b32601b12200532e", + "0x532900531f01b00900532e00500900504601b04900532e005280005320", + "0x504900532e00504900503701b00700532e00500700531e01b32900532e", + "0x4700732e00700501b00700501b01b32e00501b01b01b049007329009047", + "0x1b04300532e00504800504801b01b32e00501b00701b044045007365046", + "0x732e00704300504501b04700532e00504700504601b01b32e00501b047", + "0x1b19400532e00504100504401b01b32e00501b00701b040005366041042", + "0x504200504101b03e00532e00503f00504201b03f00532e005194005043", + "0x1b00701b01b36700501b19401b07b00532e00503e00504001b02300532e", + "0x4101b19100532e00502000503e01b02000532e00501b03f01b01b32e005", + "0x32e00707b00502301b07b00532e00519100504001b02300532e005040005", + "0x32900732e00732b04700708201b01b32e00501b00701b00900536832b005", + "0x4501b32900532e00532900504601b01b32e00501b00701b02d005369330", + "0x501b02001b01b32e00501b00701b32600536a03102a00732e007023005", + "0x33000530001b01b32e00503100532b01b01b32e00502a00519101b01b32e", + "0x502a01b32000532e00501b02d01b0c900532e00501b33001b01b32e005", + "0x532e00501b32601b31f00532e0053200c900703101b32000532e005320", + "0x4601b03900532e00503700532001b03700532e00531f31e0070c901b31e", + "0x32e00500700531e01b04600532e00504600531f01b32900532e005329005", + "0x501b00701b03900704632904700503900532e00503900503701b007005", + "0x32e00501b03901b01b32e00532600519101b01b32e00501b02001b01b32e", + "0x3600732e00703804632904803601b03800532e00503800503801b038005", + "0x4601b20700532e00501b2ff01b01b32e00501b00701b2031fb00736b31c", + "0x32e00500700531e01b31c00532e00531c00531f01b03600532e005036005", + "0x32e00533020700731c03604608701b33000532e00533000507d01b007005", + "0x501b00701b21c00536c21800532e00721600533801b21621421120d047", + "0x22200521401b22200532e00501b33001b01b32e0052180052fc01b01b32e", + "0x22900532e00504c00521801b01b32e00522800521601b04c22800732e005", + "0x20d00504601b05100532e00505400522201b05400532e00522900521c01b", + "0x21400532e00521400531e01b21100532e00521100531f01b20d00532e005", + "0x1b32e00501b00701b05121421120d04700505100532e00505100503701b", + "0x21100531f01b20d00532e00520d00504601b05200532e00521c00532001b", + "0x5200532e00505200503701b21400532e00521400531e01b21100532e005", + "0x1b01b32e00533000530001b01b32e00501b00701b05221421120d047005", + "0x532e00523100502a01b23100532e00501b22901b05500532e00501b330", + "0x70c901b23400532e00501b32601b23200532e00523105500703101b231", + "0x32e0051fb00504601b05900532e00505700532001b05700532e005232234", + "0x3701b00700532e00500700531e01b20300532e00520300531f01b1fb005", + "0x19101b01b32e00501b00701b0590072031fb04700505900532e005059005", + "0x1b01b36d00501b19401b05800532e00502d00504601b01b32e005023005", + "0x1b01b32e00502300519101b01b32e00500900505401b01b32e00501b007", + "0x5600532e00501b33001b01b32e00501b02001b05800532e005047005046", + "0x23a05600703101b23a00532e00523a00502a01b23a00532e00501b05201b", + "0x5f00532e0052490330070c901b03300532e00501b32601b24900532e005", + "0x4600531f01b05800532e00505800504601b25400532e00505f00532001b", + "0x25400532e00525400503701b00700532e00500700531e01b04600532e005", + "0x1b01b32e00504800505501b01b32e00501b00701b254007046058047005", + "0x532e00506100502a01b06100532e00501b22901b06200532e00501b330", + "0x70c901b00600532e00501b32601b26c00532e00506106200703101b061", + "0x32e00504500504601b06b00532e00506900532001b06900532e00526c006", + "0x3701b00700532e00500700531e01b04400532e00504400531f01b045005", + "0x1b04600532e00501b05901b06b00704404504700506b00532e00506b005", + "0x501b01b32e00501b01b01b01b32e00501b05801b04400532e00501b311", + "0x4801b01b32e00501b00701b04004100736e04204300732e00700501b007", + "0x4300532e00504300504601b01b32e00501b04701b19400532e005048005", + "0x24901b01b32e00501b00701b02300536f03e03f00732e00719400504501b", + "0x32e00507b00503301b02000532e00503f00504101b07b00532e00503e005", + "0x532e00501b03f01b01b32e00501b00701b01b37000501b19401b191005", + "0x503301b02000532e00502300504101b00900532e00532b00505f01b32b", + "0x501b00701b33000537132900532e00719100525401b19100532e005009", + "0x1b04700532e00504704600705601b04700532e00532900504401b01b32e", + "0x32600537203102a00732e00702d0430072fb01b02d00532e005047005043", + "0x32e00702000504501b02a00532e00502a00504601b01b32e00501b00701b", + "0x31e00532e00532000524901b01b32e00501b00701b31f0053733200c9007", + "0x501b19401b03900532e00531e00503301b03700532e0050c900504101b", + "0x503800505f01b03800532e00501b03f01b01b32e00501b00701b01b374", + "0x1b03900532e00503600503301b03700532e00531f00504101b03600532e", + "0x501b02001b01b32e00501b00701b1fb00537531c00532e007039005254", + "0x521801b20700532e00501b33001b20300532e00531c00504401b01b32e", + "0x532e00502a00504601b21100532e00520300504301b20d00532e005037", + "0x522801b20d00532e00520d00506201b04200532e00504200531f01b02a", + "0x20720d04202a04606101b21100532e00521100502a01b20700532e005207", + "0x701b22200537621c00532e00721800526c01b21821621404832e005211", + "0x532e00522800504801b04c22800732e00521c00500601b01b32e00501b", + "0x504101b05100532e00521600531f01b05400532e00521400504601b229", + "0x1b01b37700501b19401b05500532e00504c00506901b05200532e005229", + "0x1b01b32e00504400507301b01b32e0050310052fa01b01b32e00501b007", + "0x521600531f01b21400532e00521400504601b23100532e005222005320", + "0x523100532e00523100503701b00700532e00500700531e01b21600532e", + "0x505401b01b32e00501b02001b01b32e00501b00701b231007216214047", + "0x1b23400532e0052320052d301b23200532e00501b03f01b01b32e0051fb", + "0x503700504101b05100532e00504200531f01b05400532e00502a005046", + "0x37804500532e00705500506e01b05500532e00523400506901b05200532e", + "0x504504400707401b01b32e00501b04701b01b32e00501b00701b057005", + "0x32e00501b00701b05600537905805900732e00705200504501b04500532e", + "0x503301b24900532e00505900504101b23a00532e00505800524901b01b", + "0x1b03f01b01b32e00501b00701b01b37a00501b19401b03300532e00523a", + "0x24900532e00505600504101b25400532e00505f00505f01b05f00532e005", + "0x1b06100537b06200532e00703300525401b03300532e00525400503301b", + "0x1b26c00532e00506200504401b01b32e00501b02001b01b32e00501b007", + "0x32e00526c00504301b06900532e00524900521801b00600532e00501b330", + "0x6201b05100532e00505100531f01b05400532e00505400504601b06b005", + "0x32e00506b00502a01b00600532e00500600522801b06900532e005069005", + "0x6f00526c01b06f06e2d304832e00506b00606905105404606101b06b005", + "0x732e00507100500601b01b32e00501b00701b2ee00537c07100532e007", + "0x31f01b07300532e0052d300504601b31100532e00503400504801b076034", + "0x32e00507600506901b07a00532e00531100504101b07200532e00506e005", + "0x32e00504500521601b01b32e00501b00701b01b37d00501b19401b074005", + "0x2d300504601b30f00532e0052ee00532001b01b32e0050310052fa01b01b", + "0x700532e00500700531e01b06e00532e00506e00531f01b2d300532e005", + "0x1b32e00501b00701b30f00706e2d304700530f00532e00530f00503701b", + "0x30e00532e00501b03f01b01b32e00506100505401b01b32e00501b02001b", + "0x5100531f01b07300532e00505400504601b30d00532e00530e0052d301b", + "0x7400532e00530d00506901b07a00532e00524900504101b07200532e005", + "0x504501b01b32e00501b00701b30b00537e30c00532e00707400506e01b", + "0x530a00519101b01b32e00501b00701b30500537f30930a00732e00707a", + "0x310052fa01b01b32e00504500521601b01b32e00530900532b01b01b32e", + "0x1b02d01b08600532e00501b33001b01b32e00530c00521601b01b32e005", + "0x532e00530408600703101b30400532e00530400502a01b30400532e005", + "0x532001b30200532e0053030840070c901b08400532e00501b32601b303", + "0x532e00507200531f01b07300532e00507300504601b30100532e005302", + "0x7304700530100532e00530100503701b00700532e00500700531e01b072", + "0x501b03901b01b32e00530500519101b01b32e00501b00701b301007072", + "0x732e00708207207304803601b08200532e00508200503801b08200532e", + "0x1b33800532e00501b2f901b01b32e00501b00701b08707d0073802ff300", + "0x50310052f801b01b32e0052fc00521601b2fb2fc00732e00530c005214", + "0x2f72f800732e00504500521401b01b32e0052fa0052fa01b2f92fa00732e", + "0x52ff00531f01b30000532e00530000504601b01b32e0052f800521601b", + "0x1b33800532e0053380052f701b00700532e00500700531e01b2ff00532e", + "0x52f700504101b2f900532e0052f90052f701b2fb00532e0052fb005041", + "0x2f32f42f52f604732e0052f72f92fb3380072ff3000442f601b2f700532e", + "0x52f401b01b32e00501b00701b2f10053812f200532e0072f30052f501b", + "0x8b07c00732e0052ef00521401b2ef00532e00501b33001b01b32e0052f2", + "0x508d00521c01b08d00532e00508b00521801b01b32e00507c00521601b", + "0x1b2f600532e0052f600504601b09000532e0052ed00522201b2ed00532e", + "0x509000503701b2f400532e0052f400531e01b2f500532e0052f500531f", + "0x52f100532001b01b32e00501b00701b0902f42f52f604700509000532e", + "0x1b2f500532e0052f500531f01b2f600532e0052f600504601b2ec00532e", + "0x2f42f52f60470052ec00532e0052ec00503701b2f400532e0052f400531e", + "0x32e0050310052fa01b01b32e00504500521601b01b32e00501b00701b2ec", + "0x32e00501b22901b08e00532e00501b33001b01b32e00530c00521601b01b", + "0x1b2ea00532e0052eb08e00703101b2eb00532e0052eb00502a01b2eb005", + "0x52e700532001b2e700532e0052ea2e80070c901b2e800532e00501b326", + "0x1b08700532e00508700531f01b07d00532e00507d00504601b09900532e", + "0x708707d04700509900532e00509900503701b00700532e00500700531e", + "0x32e00504500521601b01b32e00530b00505401b01b32e00501b00701b099", + "0x32e00501b33001b01b32e00507a00519101b01b32e0050310052fa01b01b", + "0x703101b2e600532e0052e600502a01b2e600532e00501b07101b085005", + "0x32e0052e42e30070c901b2e300532e00501b32601b2e400532e0052e6085", + "0x31f01b07300532e00507300504601b2e200532e00509d00532001b09d005", + "0x32e0052e200503701b00700532e00500700531e01b07200532e005072005", + "0x32e00505700505401b01b32e00501b00701b2e20070720730470052e2005", + "0x504400507301b01b32e00505200519101b01b32e0050310052fa01b01b", + "0xa000502a01b0a000532e00501b05101b0a400532e00501b33001b01b32e", + "0x2df00532e00501b32601b2e100532e0050a00a400703101b0a000532e005", + "0x504601b0aa00532e0050a800532001b0a800532e0052e12df0070c901b", + "0x532e00500700531e01b05100532e00505100531f01b05400532e005054", + "0x32e00501b00701b0aa0070510540470050aa00532e0050aa00503701b007", + "0x532600504601b01b32e00502000519101b01b32e00504400507301b01b", + "0x533000505401b01b32e00501b00701b01b38200501b19401b2dd00532e", + "0x460052ee01b01b32e00502000519101b01b32e00504400507301b01b32e", + "0x1b33001b01b32e00501b02001b2dd00532e00504300504601b01b32e005", + "0x1b2db00532e0052db00502a01b2db00532e00501b05201b0ad00532e005", + "0x2da2d90070c901b2d900532e00501b32601b2da00532e0052db0ad007031", + "0x2dd00532e0052dd00504601b2d700532e0052d800532001b2d800532e005", + "0x2d700503701b00700532e00500700531e01b04200532e00504200531f01b", + "0x4800505501b01b32e00501b00701b2d70070422dd0470052d700532e005", + "0x1b33001b01b32e0050460052ee01b01b32e00504400507301b01b32e005", + "0x1b2d600532e0052d600502a01b2d600532e00501b22901b0b200532e005", + "0x2d52d40070c901b2d400532e00501b32601b2d500532e0052d60b2007031", + "0x4100532e00504100504601b35700532e00504a00532001b04a00532e005", + "0x35700503701b00700532e00500700531e01b04000532e00504000531f01b", + "0x1b00700501b01b32e00501b01b01b35700704004104700535700532e005", + "0x4800504801b01b32e00501b00701b04404500738304604700732e007005", + "0x4501b04700532e00504700504601b01b32e00501b04701b04300532e005", + "0x4100524901b01b32e00501b00701b04000538404104200732e007043005", + "0x3e00532e00519400503301b03f00532e00504200504101b19400532e005", + "0x1b02300532e00501b03f01b01b32e00501b00701b01b38500501b19401b", + "0x507b00503301b03f00532e00504000504101b07b00532e00502300505f", + "0x1b32e00501b00701b19100538602000532e00703e00525401b03e00532e", + "0x900502a01b00900532e00532b00504301b32b00532e00502000504401b", + "0x1b00701b02d00538733032900732e0070090470072fb01b00900532e005", + "0x3102a00732e00703f00504501b32900532e00532900504601b01b32e005", + "0x502a00519101b01b32e00501b02001b01b32e00501b00701b326005388", + "0x501b33001b01b32e0053300052fa01b01b32e00503100532b01b01b32e", + "0x3101b32000532e00532000502a01b32000532e00501b02d01b0c900532e", + "0x531f31e0070c901b31e00532e00501b32601b31f00532e0053200c9007", + "0x1b32900532e00532900504601b03900532e00503700532001b03700532e", + "0x503900503701b00700532e00500700531e01b04600532e00504600531f", + "0x32e00501b02001b01b32e00501b00701b03900704632904700503900532e", + "0x503800503801b03800532e00501b03901b01b32e00532600519101b01b", + "0x701b2031fb00738931c03600732e00703804632904803601b03800532e", + "0x32e00733000731c0482f301b03600532e00503600504601b01b32e00501b", + "0x32e00501b33001b01b32e00501b00701b21821621404838a21120d207048", + "0x1b22200532e00521121c00703101b21100532e00521100502a01b21c005", + "0x504c00521801b01b32e00522800521601b04c22800732e005222005214", + "0x1b05100532e00505400522201b05400532e00522900521c01b22900532e", + "0x520d00531e01b20700532e00520700531f01b03600532e005036005046", + "0x1b00701b05120d20703604700505100532e00505100503701b20d00532e", + "0x1b05500532e0052180520070c901b05200532e00501b32601b01b32e005", + "0x521400531f01b03600532e00503600504601b23100532e005055005320", + "0x523100532e00523100503701b21600532e00521600531e01b21400532e", + "0x33001b01b32e0053300052fa01b01b32e00501b00701b231216214036047", + "0x23400532e00523400502a01b23400532e00501b22901b23200532e00501b", + "0x590070c901b05900532e00501b32601b05700532e00523423200703101b", + "0x532e0051fb00504601b05600532e00505800532001b05800532e005057", + "0x503701b00700532e00500700531e01b20300532e00520300531f01b1fb", + "0x519101b01b32e00501b00701b0560072031fb04700505600532e005056", + "0x701b01b38b00501b19401b23a00532e00502d00504601b01b32e00503f", + "0x4601b01b32e00503f00519101b01b32e00519100505401b01b32e00501b", + "0x1b24900532e00501b33001b01b32e00501b02001b23a00532e005047005", + "0x503324900703101b03300532e00503300502a01b03300532e00501b052", + "0x1b06200532e00505f2540070c901b25400532e00501b32601b05f00532e", + "0x504600531f01b23a00532e00523a00504601b06100532e005062005320", + "0x506100532e00506100503701b00700532e00500700531e01b04600532e", + "0x33001b01b32e00504800505501b01b32e00501b00701b06100704623a047", + "0x600532e00500600502a01b00600532e00501b22901b26c00532e00501b", + "0x6b0070c901b06b00532e00501b32601b06900532e00500626c00703101b", + "0x532e00504500504601b06e00532e0052d300532001b2d300532e005069", + "0x503701b00700532e00500700531e01b04400532e00504400531f01b045", + "0x5801b04600532e00501b2f201b06e00704404504700506e00532e00506e", + "0x4404500732e00700501b00700501b01b32e00501b01b01b01b32e00501b", + "0x6201b04500532e00504500504601b01b32e00501b00701b04204300738c", + "0x52ef01b19404004104832e0050480450072f101b04800532e005048005", + "0x32e00504100504601b01b32e00501b00701b03f00538d04700532e007194", + "0x7c01b04000532e00504000506201b04400532e00504400531f01b041005", + "0x1b07b02303e04832e00504004404104808b01b04700532e005047046007", + "0x200052ed01b01b32e00501b00701b19100538e02000532e00707b00508d", + "0x501b00701b33000538f32900532e00700900509001b00932b00732e005", + "0x2d00504501b01b32e00501b04701b02d00532e00532b00504801b01b32e", + "0x32e00503100504401b01b32e00501b00701b32600539003102a00732e007", + "0x4101b31f00532e00532000504201b32000532e0050c900504301b0c9005", + "0x1b39100501b19401b03700532e00531f00504001b31e00532e00502a005", + "0x532e00503900503e01b03900532e00501b03f01b01b32e00501b00701b", + "0x502301b03700532e00503800504001b31e00532e00532600504101b038", + "0x32e00731e00504501b01b32e00501b00701b31c00539203600532e007037", + "0x20d00532e00520300504401b01b32e00501b00701b2070053932031fb007", + "0x1fb00504101b21400532e00521100504201b21100532e00520d00504301b", + "0x701b01b39400501b19401b21800532e00521400504001b21600532e005", + "0x1b22200532e00521c00503e01b21c00532e00501b03f01b01b32e00501b", + "0x721800502301b21800532e00522200504001b21600532e005207005041", + "0x22900732e00721600504501b01b32e00501b00701b04c00539522800532e", + "0x4301b05200532e00505400504401b01b32e00501b00701b051005396054", + "0x32e00522900504101b23100532e00505500504201b05500532e005052005", + "0x501b00701b01b39700501b19401b23400532e00523100504001b232005", + "0x504101b05900532e00505700503e01b05700532e00501b03f01b01b32e", + "0x532e00723400502301b23400532e00505900504001b23200532e005051", + "0x39924923a00732e00723200504501b01b32e00501b00701b056005398058", + "0x32e00523a00519101b01b32e00501b02001b01b32e00501b00701b033005", + "0x522800532901b01b32e00505800532901b01b32e00524900532b01b01b", + "0x4700508e01b01b32e0053290052ec01b01b32e00503600532901b01b32e", + "0x502a01b25400532e00501b02d01b05f00532e00501b33001b01b32e005", + "0x532e00501b32601b06200532e00525405f00703101b25400532e005254", + "0x4601b00600532e00526c00532001b26c00532e0050620610070c901b061", + "0x32e00500700531e01b02300532e00502300531f01b03e00532e00503e005", + "0x501b00701b00600702303e04700500600532e00500600503701b007005", + "0x6900503801b06900532e00501b03901b01b32e00503300519101b01b32e", + "0x1b06f06e00739a2d306b00732e00706902303e04803601b06900532e005", + "0x2eb01b07100532e00501b2ff01b01b32e00501b02001b01b32e00501b007", + "0x32e00506b00504601b01b32e0052ee0052ea01b0342ee00732e005071005", + "0x2e801b00700532e00500700531e01b2d300532e0052d300531f01b06b005", + "0x32e00503600502a01b32900532e0053290052e701b04700532e005047005", + "0x9901b05800532e00505800502a01b22800532e00522800502a01b036005", + "0x508501b07207331107604732e0050582280363290470340072d306b042", + "0x32e00507a0052e601b01b32e00501b00701b07400539b07a00532e007072", + "0x521601b30d30e00732e00530f00521401b30f00532e00501b33001b01b", + "0x30b00532e00530c00521c01b30c00532e00530d00521801b01b32e00530e", + "0x31100531f01b07600532e00507600504601b30a00532e00530b00522201b", + "0x30a00532e00530a00503701b07300532e00507300531e01b31100532e005", + "0x30900532e00507400532001b01b32e00501b00701b30a073311076047005", + "0x7300531e01b31100532e00531100531f01b07600532e00507600504601b", + "0x701b30907331107604700530900532e00530900503701b07300532e005", + "0x532901b01b32e00505800532901b01b32e00501b02001b01b32e00501b", + "0x8e01b01b32e0053290052ec01b01b32e00503600532901b01b32e005228", + "0x1b08600532e00501b22901b30500532e00501b33001b01b32e005047005", + "0x501b32601b30400532e00508630500703101b08600532e00508600502a", + "0x30200532e00508400532001b08400532e0053043030070c901b30300532e", + "0x700531e01b06f00532e00506f00531f01b06e00532e00506e00504601b", + "0x701b30200706f06e04700530200532e00530200503701b00700532e005", + "0x519101b01b32e00505600505401b01b32e00501b02001b01b32e00501b", + "0x2ec01b01b32e00503600532901b01b32e00522800532901b01b32e005232", + "0x1b30100532e00501b33001b01b32e00504700508e01b01b32e005329005", + "0x508230100703101b08200532e00508200502a01b08200532e00501b302", + "0x1b07d00532e0053002ff0070c901b2ff00532e00501b32601b30000532e", + "0x502300531f01b03e00532e00503e00504601b08700532e00507d005320", + "0x508700532e00508700503701b00700532e00500700531e01b02300532e", + "0x505401b01b32e00501b02001b01b32e00501b00701b08700702303e047", + "0x32901b01b32e00521600519101b01b32e00504700508e01b01b32e00504c", + "0x1b33800532e00501b33001b01b32e0053290052ec01b01b32e005036005", + "0x52fc33800703101b2fc00532e0052fc00502a01b2fc00532e00501b301", + "0x1b2f900532e0052fb2fa0070c901b2fa00532e00501b32601b2fb00532e", + "0x502300531f01b03e00532e00503e00504601b2f800532e0052f9005320", + "0x52f800532e0052f800503701b00700532e00500700531e01b02300532e", + "0x505401b01b32e00501b02001b01b32e00501b00701b2f800702303e047", + "0x19101b01b32e0053290052ec01b01b32e00504700508e01b01b32e00531c", + "0x1b2f600532e00501b07101b2f700532e00501b33001b01b32e00531e005", + "0x501b32601b2f500532e0052f62f700703101b2f600532e0052f600502a", + "0x2f200532e0052f300532001b2f300532e0052f52f40070c901b2f400532e", + "0x700531e01b02300532e00502300531f01b03e00532e00503e00504601b", + "0x701b2f200702303e0470052f200532e0052f200503701b00700532e005", + "0x5501b01b32e00504700508e01b01b32e00533000505401b01b32e00501b", + "0x1b2ef00532e00501b05101b2f100532e00501b33001b01b32e00532b005", + "0x501b32601b07c00532e0052ef2f100703101b2ef00532e0052ef00502a", + "0x2ed00532e00508d00532001b08d00532e00507c08b0070c901b08b00532e", + "0x700531e01b02300532e00502300531f01b03e00532e00503e00504601b", + "0x701b2ed00702303e0470052ed00532e0052ed00503701b00700532e005", + "0x1b09000532e00519100532001b01b32e00504700508e01b01b32e00501b", + "0x500700531e01b02300532e00502300531f01b03e00532e00503e005046", + "0x1b00701b09000702303e04700509000532e00509000503701b00700532e", + "0x52e401b01b32e00504000505501b01b32e00503f00505401b01b32e005", + "0x2a01b08e00532e00501b05201b2ec00532e00501b33001b01b32e005046", + "0x32e00501b32601b2eb00532e00508e2ec00703101b08e00532e00508e005", + "0x1b2e700532e0052e800532001b2e800532e0052eb2ea0070c901b2ea005", + "0x500700531e01b04400532e00504400531f01b04100532e005041005046", + "0x1b00701b2e70070440410470052e700532e0052e700503701b00700532e", + "0x1b33001b01b32e0050460052e401b01b32e00504800505501b01b32e005", + "0x1b08500532e00508500502a01b08500532e00501b22901b09900532e005", + "0x2e62e40070c901b2e400532e00501b32601b2e600532e005085099007031", + "0x4300532e00504300504601b09d00532e0052e300532001b2e300532e005", + "0x9d00503701b00700532e00500700531e01b04200532e00504200531f01b", + "0x1b05901b04600532e00501b05901b09d00704204304700509d00532e005", + "0x1b00700501b01b32e00501b01b01b01b32e00501b05801b04400532e005", + "0x4800504801b01b32e00501b00701b04004100739c04204300732e007005", + "0x4501b04300532e00504300504601b01b32e00501b04701b19400532e005", + "0x3e00504401b01b32e00501b00701b02300539d03e03f00732e007194005", + "0x19100532e00502000504201b02000532e00507b00504301b07b00532e005", + "0x501b19401b00900532e00519100504001b32b00532e00503f00504101b", + "0x532900503e01b32900532e00501b03f01b01b32e00501b00701b01b39e", + "0x1b00900532e00533000504001b32b00532e00502300504101b33000532e", + "0x4400705601b01b32e00501b00701b02d00539f04500532e007009005023", + "0x701b3260053a003102a00732e00704504300708201b04500532e005045", + "0xc900732e00732b00504501b02a00532e00502a00504601b01b32e00501b", + "0x4301b31e00532e00532000504401b01b32e00501b00701b31f0053a1320", + "0x32e0050c900504101b03900532e00503700504201b03700532e00531e005", + "0x501b00701b01b3a200501b19401b03600532e00503900504001b038005", + "0x504101b1fb00532e00531c00503e01b31c00532e00501b03f01b01b32e", + "0x532e00703600502301b03600532e0051fb00504001b03800532e00531f", + "0x1b04700532e00504704600705601b01b32e00501b00701b2030053a3047", + "0x524901b01b32e00501b00701b2110053a420d20700732e007038005045", + "0x532e00521400503301b21600532e00520700504101b21400532e00520d", + "0x21c00532e00501b03f01b01b32e00501b00701b01b3a500501b19401b218", + "0x22200503301b21600532e00521100504101b22200532e00521c00505f01b", + "0x32e00501b00701b04c0053a622800532e00721800525401b21800532e005", + "0x32e00501b33001b22900532e00522800504401b01b32e00501b02001b01b", + "0x4601b05200532e00522900504301b05100532e00521600521801b054005", + "0x32e00505100506201b04200532e00504200531f01b02a00532e00502a005", + "0x6101b05200532e00505200502a01b05400532e00505400522801b051005", + "0x23400532e00723200526c01b23223105504832e00505205405104202a046", + "0x4801b05805900732e00523400500601b01b32e00501b00701b0570053a7", + "0x32e00523100531f01b23a00532e00505500504601b05600532e005059005", + "0x19401b05f00532e00505800506901b03300532e00505600504101b249005", + "0x532901b01b32e00503100530001b01b32e00501b00701b01b3a800501b", + "0x5500532e00505500504601b25400532e00505700532001b01b32e005047", + "0x25400503701b00700532e00500700531e01b23100532e00523100531f01b", + "0x501b02001b01b32e00501b00701b25400723105504700525400532e005", + "0x620052d301b06200532e00501b03f01b01b32e00504c00505401b01b32e", + "0x24900532e00504200531f01b23a00532e00502a00504601b06100532e005", + "0x5f00506e01b05f00532e00506100506901b03300532e00521600504101b", + "0x732e00703300504501b01b32e00501b00701b0060053a926c00532e007", + "0x32b01b01b32e00506900519101b01b32e00501b00701b2d30053aa06b069", + "0x1b01b32e00504700532901b01b32e00526c00521601b01b32e00506b005", + "0x6f00532e00501b02d01b06e00532e00501b33001b01b32e005031005300", + "0x1b32601b07100532e00506f06e00703101b06f00532e00506f00502a01b", + "0x532e00503400532001b03400532e0050712ee0070c901b2ee00532e005", + "0x531e01b24900532e00524900531f01b23a00532e00523a00504601b076", + "0x1b07600724923a04700507600532e00507600503701b00700532e005007", + "0x1b31100532e00501b03901b01b32e0052d300519101b01b32e00501b007", + "0x73ab07207300732e00731124923a04803601b31100532e005311005038", + "0x521601b30e30f00732e00526c00521401b01b32e00501b00701b07407a", + "0x7300532e00507300504601b30d00532e00530e00521801b01b32e00530f", + "0x1b0863053090483ac30a30b30c04832e00730d0470310070720462e301b", + "0x532e00530400522201b30400532e00530a00521c01b01b32e00501b007", + "0x531e01b30c00532e00530c00531f01b07300532e00507300504601b303", + "0x1b30330b30c07304700530300532e00530300503701b30b00532e00530b", + "0x532e0050860840070c901b08400532e00501b32601b01b32e00501b007", + "0x531f01b07300532e00507300504601b30100532e00530200532001b302", + "0x532e00530100503701b30500532e00530500531e01b30900532e005309", + "0x1b32e00526c00521601b01b32e00501b00701b301305309073047005301", + "0x532e00501b33001b01b32e00503100530001b01b32e00504700532901b", + "0x8200703101b30000532e00530000502a01b30000532e00501b22901b082", + "0x532e0052ff07d0070c901b07d00532e00501b32601b2ff00532e005300", + "0x531f01b07a00532e00507a00504601b33800532e00508700532001b087", + "0x532e00533800503701b00700532e00500700531e01b07400532e005074", + "0x1b32e00500600505401b01b32e00501b00701b33800707407a047005338", + "0x32e00503100530001b01b32e00504700532901b01b32e00503300519101b", + "0x52fb00502a01b2fb00532e00501b07101b2fc00532e00501b33001b01b", + "0x1b2f900532e00501b32601b2fa00532e0052fb2fc00703101b2fb00532e", + "0x23a00504601b2f700532e0052f800532001b2f800532e0052fa2f90070c9", + "0x700532e00500700531e01b24900532e00524900531f01b23a00532e005", + "0x1b32e00501b00701b2f700724923a0470052f700532e0052f700503701b", + "0x1b32e00503800519101b01b32e00520300505401b01b32e00501b02001b", + "0x532e00501b33001b01b32e0050460052ee01b01b32e00503100530001b", + "0x2f600703101b2f500532e0052f500502a01b2f500532e00501b05101b2f6", + "0x532e0052f42f30070c901b2f300532e00501b32601b2f400532e0052f5", + "0x531f01b02a00532e00502a00504601b2f100532e0052f200532001b2f2", + "0x532e0052f100503701b00700532e00500700531e01b04200532e005042", + "0x1b32e0050460052ee01b01b32e00501b00701b2f100704202a0470052f1", + "0x3ad00501b19401b2ef00532e00532600504601b01b32e00532b00519101b", + "0x32e0050460052ee01b01b32e00502d00505401b01b32e00501b00701b01b", + "0x504300504601b01b32e0050440052ee01b01b32e00532b00519101b01b", + "0x501b05201b07c00532e00501b33001b01b32e00501b02001b2ef00532e", + "0x8d00532e00508b07c00703101b08b00532e00508b00502a01b08b00532e", + "0x9000532001b09000532e00508d2ed0070c901b2ed00532e00501b32601b", + "0x4200532e00504200531f01b2ef00532e0052ef00504601b2ec00532e005", + "0x422ef0470052ec00532e0052ec00503701b00700532e00500700531e01b", + "0x504800505501b01b32e0050460052ee01b01b32e00501b00701b2ec007", + "0x501b22901b08e00532e00501b33001b01b32e0050440052ee01b01b32e", + "0x2ea00532e0052eb08e00703101b2eb00532e0052eb00502a01b2eb00532e", + "0x2e700532001b2e700532e0052ea2e80070c901b2e800532e00501b32601b", + "0x4000532e00504000531f01b04100532e00504100504601b09900532e005", + "0x4004104700509900532e00509900503701b00700532e00500700531e01b", + "0x73ae04604700732e00700501b00700501b01b32e00501b01b01b099007", + "0x501b04701b04300532e00504800504801b01b32e00501b00701b044045", + "0x3af04104200732e00704300504501b04700532e00504700504601b01b32e", + "0x19400504301b19400532e00504100504401b01b32e00501b00701b040005", + "0x2300532e00504200504101b03e00532e00503f00504201b03f00532e005", + "0x1b32e00501b00701b01b3b000501b19401b07b00532e00503e00504001b", + "0x504000504101b19100532e00502000503e01b02000532e00501b03f01b", + "0x3b132b00532e00707b00502301b07b00532e00519100504001b02300532e", + "0x53b233032900732e00732b04700708201b01b32e00501b00701b009005", + "0x702300504501b32900532e00532900504601b01b32e00501b00701b02d", + "0x532e00503100504401b01b32e00501b00701b3260053b303102a00732e", + "0x504101b31f00532e00532000504201b32000532e0050c900504301b0c9", + "0x1b01b3b400501b19401b03700532e00531f00504001b31e00532e00502a", + "0x3800532e00503900503e01b03900532e00501b03f01b01b32e00501b007", + "0x3700502301b03700532e00503800504001b31e00532e00532600504101b", + "0x732e00731e00504501b01b32e00501b00701b31c0053b503600532e007", + "0x1b20d00532e00520300504401b01b32e00501b00701b2070053b62031fb", + "0x51fb00504101b21400532e00521100504201b21100532e00520d005043", + "0x1b00701b01b3b700501b19401b21800532e00521400504001b21600532e", + "0x4101b22200532e00521c00503e01b21c00532e00501b03f01b01b32e005", + "0x32e00721800502301b21800532e00522200504001b21600532e005207005", + "0x5422900732e00721600504501b01b32e00501b00701b04c0053b8228005", + "0x504301b05200532e00505400504401b01b32e00501b00701b0510053b9", + "0x532e00522900504101b23100532e00505500504201b05500532e005052", + "0x32e00501b00701b01b3ba00501b19401b23400532e00523100504001b232", + "0x5100504101b05900532e00505700503e01b05700532e00501b03f01b01b", + "0x5800532e00723400502301b23400532e00505900504001b23200532e005", + "0x53bc24923a00732e00723200504501b01b32e00501b00701b0560053bb", + "0x505f00504301b05f00532e00524900504401b01b32e00501b00701b033", + "0x1b06100532e00523a00504101b06200532e00525400504201b25400532e", + "0x1b01b32e00501b00701b01b3bd00501b19401b26c00532e005062005040", + "0x32e00503300504101b06900532e00500600503e01b00600532e00501b03f", + "0x53be06b00532e00726c00502301b26c00532e00506900504001b061005", + "0x1b0710053bf06f06e00732e00706100504501b01b32e00501b00701b2d3", + "0x32b01b01b32e00506e00519101b01b32e00501b02001b01b32e00501b007", + "0x1b01b32e00505800532901b01b32e00506b00532901b01b32e00506f005", + "0x1b32e00533000530001b01b32e00503600532901b01b32e005228005329", + "0x32e00503400502a01b03400532e00501b02d01b2ee00532e00501b33001b", + "0xc901b31100532e00501b32601b07600532e0050342ee00703101b034005", + "0x532900504601b07200532e00507300532001b07300532e005076311007", + "0x1b00700532e00500700531e01b04600532e00504600531f01b32900532e", + "0x1b01b32e00501b00701b07200704632904700507200532e005072005037", + "0x532e00507a00503801b07a00532e00501b03901b01b32e005071005191", + "0x501b00701b30d30e0073c030f07400732e00707a04632904803601b07a", + "0x530c0052eb01b30c00532e00501b2ff01b01b32e00501b02001b01b32e", + "0x1b30f00532e00530f00531f01b01b32e00530b0052ea01b30a30b00732e", + "0x503600502a01b33000532e00533000507d01b00700532e00500700531e", + "0x1b05800532e00505800502a01b22800532e00522800502a01b03600532e", + "0x32e00506b05822803633030a00730f04309d01b06b00532e00506b00502a", + "0x30900532e00530900531f01b07400532e00507400504601b086305309048", + "0x30907404700508600532e00508600503701b30500532e00530500531e01b", + "0x32e00506b00532901b01b32e00501b02001b01b32e00501b00701b086305", + "0x503600532901b01b32e00522800532901b01b32e00505800532901b01b", + "0x501b22901b30400532e00501b33001b01b32e00533000530001b01b32e", + "0x8400532e00530330400703101b30300532e00530300502a01b30300532e", + "0x30100532001b30100532e0050843020070c901b30200532e00501b32601b", + "0x30d00532e00530d00531f01b30e00532e00530e00504601b08200532e005", + "0x30d30e04700508200532e00508200503701b00700532e00500700531e01b", + "0x32e0052d300505401b01b32e00501b02001b01b32e00501b00701b082007", + "0x522800532901b01b32e00505800532901b01b32e00506100519101b01b", + "0x501b33001b01b32e00533000530001b01b32e00503600532901b01b32e", + "0x3101b2ff00532e0052ff00502a01b2ff00532e00501b30201b30000532e", + "0x507d0870070c901b08700532e00501b32601b07d00532e0052ff300007", + "0x1b32900532e00532900504601b2fc00532e00533800532001b33800532e", + "0x52fc00503701b00700532e00500700531e01b04600532e00504600531f", + "0x32e00501b02001b01b32e00501b00701b2fc0070463290470052fc00532e", + "0x523200519101b01b32e00533000530001b01b32e00505600505401b01b", + "0x501b33001b01b32e00503600532901b01b32e00522800532901b01b32e", + "0x3101b2fa00532e0052fa00502a01b2fa00532e00501b30101b2fb00532e", + "0x52f92f80070c901b2f800532e00501b32601b2f900532e0052fa2fb007", + "0x1b32900532e00532900504601b2f600532e0052f700532001b2f700532e", + "0x52f600503701b00700532e00500700531e01b04600532e00504600531f", + "0x32e00501b02001b01b32e00501b00701b2f60070463290470052f600532e", + "0x503600532901b01b32e00533000530001b01b32e00504c00505401b01b", + "0x501b07101b2f500532e00501b33001b01b32e00521600519101b01b32e", + "0x2f300532e0052f42f500703101b2f400532e0052f400502a01b2f400532e", + "0x2f100532001b2f100532e0052f32f20070c901b2f200532e00501b32601b", + "0x4600532e00504600531f01b32900532e00532900504601b2ef00532e005", + "0x463290470052ef00532e0052ef00503701b00700532e00500700531e01b", + "0x32e00531c00505401b01b32e00501b02001b01b32e00501b00701b2ef007", + "0x32e00501b33001b01b32e00531e00519101b01b32e00533000530001b01b", + "0x703101b08b00532e00508b00502a01b08b00532e00501b05101b07c005", + "0x32e00508d2ed0070c901b2ed00532e00501b32601b08d00532e00508b07c", + "0x31f01b32900532e00532900504601b2ec00532e00509000532001b090005", + "0x32e0052ec00503701b00700532e00500700531e01b04600532e005046005", + "0x32e00502300519101b01b32e00501b00701b2ec0070463290470052ec005", + "0x32e00501b00701b01b3c100501b19401b08e00532e00502d00504601b01b", + "0x504700504601b01b32e00502300519101b01b32e00500900505401b01b", + "0x501b05201b2eb00532e00501b33001b01b32e00501b02001b08e00532e", + "0x2e800532e0052ea2eb00703101b2ea00532e0052ea00502a01b2ea00532e", + "0x9900532001b09900532e0052e82e70070c901b2e700532e00501b32601b", + "0x4600532e00504600531f01b08e00532e00508e00504601b08500532e005", + "0x4608e04700508500532e00508500503701b00700532e00500700531e01b", + "0x32e00501b33001b01b32e00504800505501b01b32e00501b00701b085007", + "0x703101b2e400532e0052e400502a01b2e400532e00501b22901b2e6005", + "0x32e0052e309d0070c901b09d00532e00501b32601b2e300532e0052e42e6", + "0x31f01b04500532e00504500504601b0a400532e0052e200532001b2e2005", + "0x32e0050a400503701b00700532e00500700531e01b04400532e005044005", + "0x700501b00700501b01b32e00501b01b01b0a40070440450470050a4005", + "0x32e00504800504801b01b32e00501b00701b0440450073c204604700732e", + "0x4300504501b04700532e00504700504601b01b32e00501b04701b043005", + "0x32e00504100504401b01b32e00501b00701b0400053c304104200732e007", + "0x4101b03e00532e00503f00504201b03f00532e00519400504301b194005", + "0x1b3c400501b19401b07b00532e00503e00504001b02300532e005042005", + "0x532e00502000503e01b02000532e00501b03f01b01b32e00501b00701b", + "0x502301b07b00532e00519100504001b02300532e00504000504101b191", + "0x732b04700708201b01b32e00501b00701b0090053c532b00532e00707b", + "0x532e00532900504601b01b32e00501b00701b02d0053c633032900732e", + "0x1b01b32e00501b00701b3260053c703102a00732e00702300504501b329", + "0x1b01b32e00503100532b01b01b32e00502a00519101b01b32e00501b020", + "0x32000532e00501b02d01b0c900532e00501b33001b01b32e005330005300", + "0x1b32601b31f00532e0053200c900703101b32000532e00532000502a01b", + "0x532e00503700532001b03700532e00531f31e0070c901b31e00532e005", + "0x531e01b04600532e00504600531f01b32900532e00532900504601b039", + "0x1b03900704632904700503900532e00503900503701b00700532e005007", + "0x3901b01b32e00532600519101b01b32e00501b02001b01b32e00501b007", + "0x703804632904803601b03800532e00503800503801b03800532e00501b", + "0x32e00503600504601b01b32e00501b00701b2031fb0073c831c03600732e", + "0x701b2162142110483c920d20700732e00733000731c0482e201b036005", + "0x22221c00732e00521800521401b21800532e00501b33001b01b32e00501b", + "0x522800521c01b22800532e00522200521801b01b32e00521c00521601b", + "0x1b03600532e00503600504601b22900532e00504c00522201b04c00532e", + "0x522900503701b20d00532e00520d00531e01b20700532e00520700531f", + "0x32e00501b32601b01b32e00501b00701b22920d20703604700522900532e", + "0x1b05200532e00505100532001b05100532e0052160540070c901b054005", + "0x521400531e01b21100532e00521100531f01b03600532e005036005046", + "0x1b00701b05221421103604700505200532e00505200503701b21400532e", + "0x1b22901b05500532e00501b33001b01b32e00533000530001b01b32e005", + "0x532e00523105500703101b23100532e00523100502a01b23100532e005", + "0x532001b05700532e0052322340070c901b23400532e00501b32601b232", + "0x532e00520300531f01b1fb00532e0051fb00504601b05900532e005057", + "0x1fb04700505900532e00505900503701b00700532e00500700531e01b203", + "0x2d00504601b01b32e00502300519101b01b32e00501b00701b059007203", + "0x900505401b01b32e00501b00701b01b3ca00501b19401b05800532e005", + "0x2001b05800532e00504700504601b01b32e00502300519101b01b32e005", + "0x2a01b23a00532e00501b05201b05600532e00501b33001b01b32e00501b", + "0x32e00501b32601b24900532e00523a05600703101b23a00532e00523a005", + "0x1b25400532e00505f00532001b05f00532e0052490330070c901b033005", + "0x500700531e01b04600532e00504600531f01b05800532e005058005046", + "0x1b00701b25400704605804700525400532e00525400503701b00700532e", + "0x1b22901b06200532e00501b33001b01b32e00504800505501b01b32e005", + "0x532e00506106200703101b06100532e00506100502a01b06100532e005", + "0x532001b06900532e00526c0060070c901b00600532e00501b32601b26c", + "0x532e00504400531f01b04500532e00504500504601b06b00532e005069", + "0x4504700506b00532e00506b00503701b00700532e00500700531e01b044", + "0x501b01b01b01b32e00501b05801b04600532e00501b05901b06b007044", + "0x501b00701b0420430073cb04404500732e00700501b00700501b01b32e", + "0x4500504601b01b32e00501b04701b04100532e00504800504801b01b32e", + "0x501b00701b03f0053cc19404000732e00704100504501b04500532e005", + "0x4201b02300532e00503e00504301b03e00532e00519400504401b01b32e", + "0x32e00507b00504001b02000532e00504000504101b07b00532e005023005", + "0x532e00501b03f01b01b32e00501b00701b01b3cd00501b19401b191005", + "0x504001b02000532e00503f00504101b00900532e00532b00503e01b32b", + "0x501b00701b3290053ce04700532e00719100502301b19100532e005009", + "0x2d33000732e00702000504501b04700532e00504704600705601b01b32e", + "0x504101b03100532e00502d00524901b01b32e00501b00701b02a0053cf", + "0x1b01b3d000501b19401b0c900532e00503100503301b32600532e005330", + "0x31f00532e00532000505f01b32000532e00501b03f01b01b32e00501b007", + "0xc900525401b0c900532e00531f00503301b32600532e00502a00504101b", + "0x1b01b32e00501b02001b01b32e00501b00701b0370053d131e00532e007", + "0x32e00532600521801b03800532e00501b33001b03900532e00531e005044", + "0x31f01b04500532e00504500504601b31c00532e00503900504301b036005", + "0x32e00503800522801b03600532e00503600506201b04400532e005044005", + "0x32e00531c03803604404504606101b31c00532e00531c00502a01b038005", + "0x32e00501b00701b2110053d220d00532e00720700526c01b2072031fb048", + "0x4601b21800532e00521400504801b21621400732e00520d00500601b01b", + "0x32e00521800504101b22200532e00520300531f01b21c00532e0051fb005", + "0x501b00701b01b3d300501b19401b04c00532e00521600506901b228005", + "0x504601b22900532e00521100532001b01b32e00504700532901b01b32e", + "0x532e00500700531e01b20300532e00520300531f01b1fb00532e0051fb", + "0x32e00501b00701b2290072031fb04700522900532e00522900503701b007", + "0x532e00501b03f01b01b32e00503700505401b01b32e00501b02001b01b", + "0x531f01b21c00532e00504500504601b05100532e0050540052d301b054", + "0x532e00505100506901b22800532e00532600504101b22200532e005044", + "0x4501b01b32e00501b00701b0550053d405200532e00704c00506e01b04c", + "0x23100519101b01b32e00501b00701b2340053d523223100732e007228005", + "0x532901b01b32e00505200521601b01b32e00523200532b01b01b32e005", + "0x2a01b05900532e00501b02d01b05700532e00501b33001b01b32e005047", + "0x32e00501b32601b05800532e00505905700703101b05900532e005059005", + "0x1b24900532e00523a00532001b23a00532e0050580560070c901b056005", + "0x500700531e01b22200532e00522200531f01b21c00532e00521c005046", + "0x1b00701b24900722221c04700524900532e00524900503701b00700532e", + "0x503801b03300532e00501b03901b01b32e00523400519101b01b32e005", + "0x610620073d625405f00732e00703322221c04803601b03300532e005033", + "0x526c00521601b00626c00732e00505200521401b01b32e00501b00701b", + "0xa401b05f00532e00505f00504601b06900532e00500600521801b01b32e", + "0x32e00501b00701b07106f06e0483d72d306b00732e007069047007254047", + "0x521601b07603400732e0052ee00521401b2ee00532e00501b33001b01b", + "0x7300532e00531100521c01b31100532e00507600521801b01b32e005034", + "0x6b00531f01b05f00532e00505f00504601b07200532e00507300522201b", + "0x7200532e00507200503701b2d300532e0052d300531e01b06b00532e005", + "0x1b07a00532e00501b32601b01b32e00501b00701b0722d306b05f047005", + "0x5f00504601b30f00532e00507400532001b07400532e00507107a0070c9", + "0x6f00532e00506f00531e01b06e00532e00506e00531f01b05f00532e005", + "0x1b32e00501b00701b30f06f06e05f04700530f00532e00530f00503701b", + "0x532e00501b33001b01b32e00504700532901b01b32e00505200521601b", + "0x30e00703101b30d00532e00530d00502a01b30d00532e00501b22901b30e", + "0x532e00530c30b0070c901b30b00532e00501b32601b30c00532e00530d", + "0x531f01b06200532e00506200504601b30900532e00530a00532001b30a", + "0x532e00530900503701b00700532e00500700531e01b06100532e005061", + "0x1b32e00505500505401b01b32e00501b00701b309007061062047005309", + "0x532e00501b33001b01b32e00504700532901b01b32e00522800519101b", + "0x30500703101b08600532e00508600502a01b08600532e00501b05101b305", + "0x532e0053043030070c901b30300532e00501b32601b30400532e005086", + "0x531f01b21c00532e00521c00504601b30200532e00508400532001b084", + "0x532e00530200503701b00700532e00500700531e01b22200532e005222", + "0x1b01b32e00501b02001b01b32e00501b00701b30200722221c047005302", + "0x1b32e0050460052ee01b01b32e00502000519101b01b32e005329005054", + "0x32e00508200502a01b08200532e00501b05201b30100532e00501b33001b", + "0xc901b2ff00532e00501b32601b30000532e00508230100703101b082005", + "0x504500504601b08700532e00507d00532001b07d00532e0053002ff007", + "0x1b00700532e00500700531e01b04400532e00504400531f01b04500532e", + "0x1b01b32e00501b00701b08700704404504700508700532e005087005037", + "0x33800532e00501b33001b01b32e00504800505501b01b32e0050460052ee", + "0x2fc33800703101b2fc00532e0052fc00502a01b2fc00532e00501b22901b", + "0x2f900532e0052fb2fa0070c901b2fa00532e00501b32601b2fb00532e005", + "0x4200531f01b04300532e00504300504601b2f800532e0052f900532001b", + "0x2f800532e0052f800503701b00700532e00500700531e01b04200532e005", + "0x732e00700701b00700501b01b32e00501b01b01b2f8007042043047005", + "0x4200532e00504700504801b01b32e00501b00701b0430440073d8045046", + "0x1940053d904004100732e00704200504501b04600532e00504600504601b", + "0x1b32e00504000532b01b01b32e00504100519101b01b32e00501b00701b", + "0x32e00503e00502a01b03e00532e00501b02d01b03f00532e00501b33001b", + "0xc901b07b00532e00501b32601b02300532e00503e03f00703101b03e005", + "0x504600504601b19100532e00502000532001b02000532e00502307b007", + "0x1b04500532e00504500531f01b00500532e0050050050a001b04600532e", + "0x4500504604600519100532e00519100503701b04800532e00504800531e", + "0x32e00501b03901b01b32e00519400519101b01b32e00501b00701b191048", + "0x900732e00732b04504604803601b32b00532e00532b00503801b32b005", + "0x3102a00732e0050050052e101b01b32e00501b00701b02d3300073da329", + "0x32900531f01b02a00532e00502a0050a001b00900532e00500900504601b", + "0x503132902a0090470a801b03100532e0050310052df01b32900532e005", + "0x31e00532e00501b33001b01b32e00531f0050aa01b31f3200c932604732e", + "0x3900521801b01b32e00503700521601b03903700732e00531e00521401b", + "0x31c00532e00503600522201b03600532e00503800521c01b03800532e005", + "0x32000531f01b0c900532e0050c90050a001b32600532e00532600504601b", + "0x31c00532e00531c00503701b04800532e00504800531e01b32000532e005", + "0x1fb00532e00501b33001b01b32e00501b00701b31c0483200c9326046005", + "0x2031fb00703101b20300532e00520300502a01b20300532e00501b22901b", + "0x21100532e00520720d0070c901b20d00532e00501b32601b20700532e005", + "0x50050a001b33000532e00533000504601b21400532e00521100532001b", + "0x4800532e00504800531e01b02d00532e00502d00531f01b00500532e005", + "0x32e00501b00701b21404802d00533004600521400532e00521400503701b", + "0x32e00501b22901b21600532e00501b33001b01b32e00504700505501b01b", + "0x1b21c00532e00521821600703101b21800532e00521800502a01b218005", + "0x522800532001b22800532e00521c2220070c901b22200532e00501b326", + "0x1b00500532e0050050050a001b04400532e00504400504601b04c00532e", + "0x504c00503701b04800532e00504800531e01b04300532e00504300531f", + "0x1b05901b04600532e00501b05901b04c04804300504404600504c00532e", + "0x1b00700501b01b32e00501b01b01b01b32e00501b05801b04400532e005", + "0x4800504801b01b32e00501b00701b0400410073db04204300732e007005", + "0x4501b04300532e00504300504601b01b32e00501b04701b19400532e005", + "0x3e00504401b01b32e00501b00701b0230053dc03e03f00732e007194005", + "0x19100532e00502000504201b02000532e00507b00504301b07b00532e005", + "0x501b19401b00900532e00519100504001b32b00532e00503f00504101b", + "0x532900503e01b32900532e00501b03f01b01b32e00501b00701b01b3dd", + "0x1b00900532e00533000504001b32b00532e00502300504101b33000532e", + "0x4400705601b01b32e00501b00701b02d0053de04500532e007009005023", + "0x701b3260053df03102a00732e00704504300708201b04500532e005045", + "0xc900732e00732b00504501b02a00532e00502a00504601b01b32e00501b", + "0x4301b31e00532e00532000504401b01b32e00501b00701b31f0053e0320", + "0x32e0050c900504101b03900532e00503700504201b03700532e00531e005", + "0x501b00701b01b3e100501b19401b03600532e00503900504001b038005", + "0x504101b1fb00532e00531c00503e01b31c00532e00501b03f01b01b32e", + "0x532e00703600502301b03600532e0051fb00504001b03800532e00531f", + "0x1b04700532e00504704600705601b01b32e00501b00701b2030053e2047", + "0x524901b01b32e00501b00701b2110053e320d20700732e007038005045", + "0x532e00521400503301b21600532e00520700504101b21400532e00520d", + "0x21c00532e00501b03f01b01b32e00501b00701b01b3e400501b19401b218", + "0x22200503301b21600532e00521100504101b22200532e00521c00505f01b", + "0x32e00501b00701b04c0053e522800532e00721800525401b21800532e005", + "0x32e00501b33001b22900532e00522800504401b01b32e00501b02001b01b", + "0x4601b05200532e00522900504301b05100532e00521600521801b054005", + "0x32e00505100506201b04200532e00504200531f01b02a00532e00502a005", + "0x6101b05200532e00505200502a01b05400532e00505400522801b051005", + "0x23400532e00723200526c01b23223105504832e00505205405104202a046", + "0x4801b05805900732e00523400500601b01b32e00501b00701b0570053e6", + "0x32e00523100531f01b23a00532e00505500504601b05600532e005059005", + "0x19401b05f00532e00505800506901b03300532e00505600504101b249005", + "0x532901b01b32e00503100530001b01b32e00501b00701b01b3e700501b", + "0x5500532e00505500504601b25400532e00505700532001b01b32e005047", + "0x25400503701b00700532e00500700531e01b23100532e00523100531f01b", + "0x501b02001b01b32e00501b00701b25400723105504700525400532e005", + "0x620052d301b06200532e00501b03f01b01b32e00504c00505401b01b32e", + "0x24900532e00504200531f01b23a00532e00502a00504601b06100532e005", + "0x5f00506e01b05f00532e00506100506901b03300532e00521600504101b", + "0x1b01b32e00501b04701b01b32e00501b00701b0060053e826c00532e007", + "0x524901b01b32e00501b00701b2d30053e906b06900732e007033005045", + "0x532e00506e00503301b06f00532e00506900504101b06e00532e00506b", + "0x2ee00532e00501b03f01b01b32e00501b00701b01b3ea00501b19401b071", + "0x3400503301b06f00532e0052d300504101b03400532e0052ee00505f01b", + "0x32e00501b00701b3110053eb07600532e00707100525401b07100532e005", + "0x502a01b07200532e00507300504301b07300532e00507600504401b01b", + "0x32e00501b00701b07a0053ec01b32e0070720052dd01b07200532e005072", + "0x30f0052db01b30f00532e0050740050ad01b07400532e00501b03f01b01b", + "0x7a0052da01b01b32e00501b00701b01b3ed00501b19401b30e00532e005", + "0x2db01b30c00532e00530d0052d901b30d00532e00501b03f01b01b32e005", + "0x701b3090053ee30a30b00732e00706f00504501b30e00532e00530c005", + "0x532b01b01b32e00530b00519101b01b32e00501b02001b01b32e00501b", + "0x32901b01b32e00526c00521601b01b32e00530e0052d801b01b32e00530a", + "0x1b30500532e00501b33001b01b32e00503100530001b01b32e005047005", + "0x508630500703101b08600532e00508600502a01b08600532e00501b02d", + "0x1b08400532e0053043030070c901b30300532e00501b32601b30400532e", + "0x524900531f01b23a00532e00523a00504601b30200532e005084005320", + "0x530200532e00530200503701b00700532e00500700531e01b24900532e", + "0x3901b01b32e00530900519101b01b32e00501b00701b30200724923a047", + "0x730124923a04803601b30100532e00530100503801b30100532e00501b", + "0x1b32e00501b02001b01b32e00501b00701b07d2ff0073ef30008200732e", + "0x521601b2fc33800732e00526c00521401b08700532e00530e0052d701b", + "0x8700532e0050870052db01b2fb00532e0052fc00521801b01b32e005338", + "0x4732e0070872fb0470310073000450b201b08200532e00508200504601b", + "0x52f800506b01b01b32e00501b00701b2f42f52f60483f02f72f82f92fa", + "0x2f300521401b2f300532e00501b33001b01b32e0052f700505501b01b32e", + "0x2ef00532e0052f100521801b01b32e0052f200521601b2f12f200732e005", + "0x8200504601b08b00532e00507c00522201b07c00532e0052ef00521c01b", + "0x2f900532e0052f900531e01b2fa00532e0052fa00531f01b08200532e005", + "0x1b32e00501b00701b08b2f92fa08204700508b00532e00508b00503701b", + "0x2ed00532001b2ed00532e0052f408d0070c901b08d00532e00501b32601b", + "0x2f600532e0052f600531f01b08200532e00508200504601b09000532e005", + "0x2f608204700509000532e00509000503701b2f500532e0052f500531e01b", + "0x32e00530e0052d801b01b32e00501b02001b01b32e00501b00701b0902f5", + "0x503100530001b01b32e00504700532901b01b32e00526c00521601b01b", + "0x8e00502a01b08e00532e00501b22901b2ec00532e00501b33001b01b32e", + "0x2ea00532e00501b32601b2eb00532e00508e2ec00703101b08e00532e005", + "0x504601b2e700532e0052e800532001b2e800532e0052eb2ea0070c901b", + "0x532e00500700531e01b07d00532e00507d00531f01b2ff00532e0052ff", + "0x32e00501b00701b2e700707d2ff0470052e700532e0052e700503701b007", + "0x32e00506f00519101b01b32e00531100505401b01b32e00501b02001b01b", + "0x503100530001b01b32e00504700532901b01b32e00526c00521601b01b", + "0x8500502a01b08500532e00501b30101b09900532e00501b33001b01b32e", + "0x2e400532e00501b32601b2e600532e00508509900703101b08500532e005", + "0x504601b09d00532e0052e300532001b2e300532e0052e62e40070c901b", + "0x532e00500700531e01b24900532e00524900531f01b23a00532e00523a", + "0x32e00501b00701b09d00724923a04700509d00532e00509d00503701b007", + "0x503300519101b01b32e00503100530001b01b32e00500600505401b01b", + "0x501b07101b2e200532e00501b33001b01b32e00504700532901b01b32e", + "0xa000532e0050a42e200703101b0a400532e0050a400502a01b0a400532e", + "0x2df00532001b2df00532e0050a02e10070c901b2e100532e00501b32601b", + "0x24900532e00524900531f01b23a00532e00523a00504601b0a800532e005", + "0x24923a0470050a800532e0050a800503701b00700532e00500700531e01b", + "0x32e00520300505401b01b32e00501b02001b01b32e00501b00701b0a8007", + "0x50460052ee01b01b32e00503100530001b01b32e00503800519101b01b", + "0x2dd00502a01b2dd00532e00501b05101b0aa00532e00501b33001b01b32e", + "0x2db00532e00501b32601b0ad00532e0052dd0aa00703101b2dd00532e005", + "0x504601b2d900532e0052da00532001b2da00532e0050ad2db0070c901b", + "0x532e00500700531e01b04200532e00504200531f01b02a00532e00502a", + "0x32e00501b00701b2d900704202a0470052d900532e0052d900503701b007", + "0x532600504601b01b32e00532b00519101b01b32e0050460052ee01b01b", + "0x502d00505401b01b32e00501b00701b01b3f100501b19401b2d800532e", + "0x440052ee01b01b32e00532b00519101b01b32e0050460052ee01b01b32e", + "0x1b33001b01b32e00501b02001b2d800532e00504300504601b01b32e005", + "0x1b0b200532e0050b200502a01b0b200532e00501b05201b2d700532e005", + "0x2d62d50070c901b2d500532e00501b32601b2d600532e0050b22d7007031", + "0x2d800532e0052d800504601b04a00532e0052d400532001b2d400532e005", + "0x4a00503701b00700532e00500700531e01b04200532e00504200531f01b", + "0x460052ee01b01b32e00501b00701b04a0070422d804700504a00532e005", + "0x1b33001b01b32e0050440052ee01b01b32e00504800505501b01b32e005", + "0x1b35800532e00535800502a01b35800532e00501b22901b35700532e005", + "0x35a0cf0070c901b0cf00532e00501b32601b35a00532e005358357007031", + "0x4100532e00504100504601b0b900532e00535b00532001b35b00532e005", + "0xb900503701b00700532e00500700531e01b04000532e00504000531f01b", + "0x1b00700501b01b32e00501b01b01b0b90070400410470050b900532e005", + "0x4800504801b01b32e00501b00701b0440450073f204604700732e007005", + "0x4200732e00704300504501b04700532e00504700504601b04300532e005", + "0x532b01b01b32e00504200519101b01b32e00501b00701b0400053f3041", + "0x2a01b03f00532e00501b02d01b19400532e00501b33001b01b32e005041", + "0x32e00501b32601b03e00532e00503f19400703101b03f00532e00503f005", + "0x1b02000532e00507b00532001b07b00532e00503e0230070c901b023005", + "0x500700531e01b04600532e00504600531f01b04700532e005047005046", + "0x1b00701b02000704604704700502000532e00502000503701b00700532e", + "0x503801b19100532e00501b03901b01b32e00504000519101b01b32e005", + "0x3303290073f400932b00732e00719104604704803601b19100532e005191", + "0x532e00532b00504601b02d00532e00501b2ff01b01b32e00501b00701b", + "0x472d601b00700532e00500700531e01b00900532e00500900531f01b32b", + "0x3f532000532e0070c900533801b0c932603102a04732e00502d00700932b", + "0x32e00501b33001b01b32e0053200052fc01b01b32e00501b00701b31f005", + "0x21801b01b32e00503700521601b03903700732e00531e00521401b31e005", + "0x32e00503600522201b03600532e00503800521c01b03800532e005039005", + "0x31e01b03100532e00503100531f01b02a00532e00502a00504601b31c005", + "0x31c32603102a04700531c00532e00531c00503701b32600532e005326005", + "0x32e00502a00504601b1fb00532e00531f00532001b01b32e00501b00701b", + "0x3701b32600532e00532600531e01b03100532e00503100531f01b02a005", + "0x33001b01b32e00501b00701b1fb32603102a0470051fb00532e0051fb005", + "0x20700532e00520700502a01b20700532e00501b22901b20300532e00501b", + "0x2110070c901b21100532e00501b32601b20d00532e00520720300703101b", + "0x532e00532900504601b21600532e00521400532001b21400532e00520d", + "0x503701b00700532e00500700531e01b33000532e00533000531f01b329", + "0x505501b01b32e00501b00701b21600733032904700521600532e005216", + "0x2a01b21c00532e00501b22901b21800532e00501b33001b01b32e005048", + "0x32e00501b32601b22200532e00521c21800703101b21c00532e00521c005", + "0x1b22900532e00504c00532001b04c00532e0052222280070c901b228005", + "0x500700531e01b04400532e00504400531f01b04500532e005045005046", + "0x1b01b01b22900704404504700522900532e00522900503701b00700532e", + "0x1b00701b0440450073f604604700732e00700501b00700501b01b32e005", + "0x1b04700532e00504700504601b04300532e00504800504801b01b32e005", + "0x519101b01b32e00501b00701b0400053f704104200732e007043005045", + "0x2d01b19400532e00501b33001b01b32e00504100532b01b01b32e005042", + "0x32e00503f19400703101b03f00532e00503f00502a01b03f00532e00501b", + "0x32001b07b00532e00503e0230070c901b02300532e00501b32601b03e005", + "0x32e00504600531f01b04700532e00504700504601b02000532e00507b005", + "0x4700502000532e00502000503701b00700532e00500700531e01b046005", + "0x1b03901b01b32e00504000519101b01b32e00501b00701b020007046047", + "0x32e00719104604704803601b19100532e00519100503801b19100532e005", + "0x2d00532e00501b2ff01b01b32e00501b00701b3303290073f800932b007", + "0x700531e01b00900532e00500900531f01b32b00532e00532b00504601b", + "0x33801b0c932603102a04732e00502d00700932b0472d501b00700532e005", + "0x53200052fc01b01b32e00501b00701b31f0053f932000532e0070c9005", + "0x21601b03903700732e00531e00521401b31e00532e00501b33001b01b32e", + "0x532e00503800521c01b03800532e00503900521801b01b32e005037005", + "0x531f01b02a00532e00502a00504601b31c00532e00503600522201b036", + "0x532e00531c00503701b32600532e00532600531e01b03100532e005031", + "0x532e00531f00532001b01b32e00501b00701b31c32603102a04700531c", + "0x531e01b03100532e00503100531f01b02a00532e00502a00504601b1fb", + "0x1b1fb32603102a0470051fb00532e0051fb00503701b32600532e005326", + "0x1b20700532e00501b22901b20300532e00501b33001b01b32e00501b007", + "0x501b32601b20d00532e00520720300703101b20700532e00520700502a", + "0x21600532e00521400532001b21400532e00520d2110070c901b21100532e", + "0x700531e01b33000532e00533000531f01b32900532e00532900504601b", + "0x701b21600733032904700521600532e00521600503701b00700532e005", + "0x22901b21800532e00501b33001b01b32e00504800505501b01b32e00501b", + "0x32e00521c21800703101b21c00532e00521c00502a01b21c00532e00501b", + "0x32001b04c00532e0052222280070c901b22800532e00501b32601b222005", + "0x32e00504400531f01b04500532e00504500504601b22900532e00504c005", + "0x4700522900532e00522900503701b00700532e00500700531e01b044005", + "0x4504600732e00700701b00700501b01b32e00501b01b01b229007044045", + "0x4601b04200532e00504700504801b01b32e00501b00701b0430440073fa", + "0x701b1940053fb04004100732e00704200504501b04600532e005046005", + "0x33001b01b32e00504000532b01b01b32e00504100519101b01b32e00501b", + "0x3e00532e00503e00502a01b03e00532e00501b02d01b03f00532e00501b", + "0x7b0070c901b07b00532e00501b32601b02300532e00503e03f00703101b", + "0x532e00504600504601b19100532e00502000532001b02000532e005023", + "0x531e01b04500532e00504500531f01b00500532e0050050052d401b046", + "0x19104804500504604600519100532e00519100503701b04800532e005048", + "0x32b00532e00501b03901b01b32e00519400519101b01b32e00501b00701b", + "0x3fc32900900732e00732b04504604803601b32b00532e00532b00503801b", + "0x900504601b02a00532e00501b2ff01b01b32e00501b00701b02d330007", + "0x500532e0050050052d401b32900532e00532900531f01b00900532e005", + "0x3104632e00502a04800532900904604a01b04800532e00504800531e01b", + "0x32e00501b00701b0370053fd31e00532e00731f00533801b31f3200c9326", + "0x503900521401b03900532e00501b33001b01b32e00531e0052fc01b01b", + "0x1b31c00532e00503600521801b01b32e00503800521601b03603800732e", + "0x503100504601b20300532e0051fb00522201b1fb00532e00531c00521c", + "0x1b32600532e00532600531f01b0c900532e0050c90052d401b03100532e", + "0x3260c903104600520300532e00520300503701b32000532e00532000531e", + "0x3100504601b20700532e00503700532001b01b32e00501b00701b203320", + "0x32600532e00532600531f01b0c900532e0050c90052d401b03100532e005", + "0xc903104600520700532e00520700503701b32000532e00532000531e01b", + "0x501b22901b20d00532e00501b33001b01b32e00501b00701b207320326", + "0x21400532e00521120d00703101b21100532e00521100502a01b21100532e", + "0x21800532001b21800532e0052142160070c901b21600532e00501b32601b", + "0x500532e0050050052d401b33000532e00533000504601b21c00532e005", + "0x21c00503701b04800532e00504800531e01b02d00532e00502d00531f01b", + "0x505501b01b32e00501b00701b21c04802d00533004600521c00532e005", + "0x2a01b22800532e00501b22901b22200532e00501b33001b01b32e005047", + "0x32e00501b32601b04c00532e00522822200703101b22800532e005228005", + "0x1b05100532e00505400532001b05400532e00504c2290070c901b229005", + "0x504300531f01b00500532e0050050052d401b04400532e005044005046", + "0x505100532e00505100503701b04800532e00504800531e01b04300532e", + "0x732e00700501b00700501b01b32e00501b01b01b051048043005044046", + "0x4300532e00504800504801b01b32e00501b00701b0440450073fe046047", + "0x400053ff04104200732e00704300504501b04700532e00504700504601b", + "0x1b32e00504100532b01b01b32e00504200519101b01b32e00501b00701b", + "0x32e00503f00502a01b03f00532e00501b02d01b19400532e00501b33001b", + "0xc901b02300532e00501b32601b03e00532e00503f19400703101b03f005", + "0x504700504601b02000532e00507b00532001b07b00532e00503e023007", + "0x1b00700532e00500700531e01b04600532e00504600531f01b04700532e", + "0x1b01b32e00501b00701b02000704604704700502000532e005020005037", + "0x532e00519100503801b19100532e00501b03901b01b32e005040005191", + "0x501b00701b33032900740000932b00732e00719104604704803601b191", + "0x531f01b32b00532e00532b00504601b02d00532e00501b2ff01b01b32e", + "0x2d00700932b04735701b00700532e00500700531e01b00900532e005009", + "0x701b31f00540132000532e0070c900533801b0c932603102a04732e005", + "0x21401b31e00532e00501b33001b01b32e0053200052fc01b01b32e00501b", + "0x32e00503900521801b01b32e00503700521601b03903700732e00531e005", + "0x4601b31c00532e00503600522201b03600532e00503800521c01b038005", + "0x32e00532600531e01b03100532e00503100531f01b02a00532e00502a005", + "0x501b00701b31c32603102a04700531c00532e00531c00503701b326005", + "0x31f01b02a00532e00502a00504601b1fb00532e00531f00532001b01b32e", + "0x32e0051fb00503701b32600532e00532600531e01b03100532e005031005", + "0x532e00501b33001b01b32e00501b00701b1fb32603102a0470051fb005", + "0x20300703101b20700532e00520700502a01b20700532e00501b22901b203", + "0x532e00520d2110070c901b21100532e00501b32601b20d00532e005207", + "0x531f01b32900532e00532900504601b21600532e00521400532001b214", + "0x532e00521600503701b00700532e00500700531e01b33000532e005330", + "0x1b32e00504800505501b01b32e00501b00701b216007330329047005216", + "0x32e00521c00502a01b21c00532e00501b22901b21800532e00501b33001b", + "0xc901b22800532e00501b32601b22200532e00521c21800703101b21c005", + "0x504500504601b22900532e00504c00532001b04c00532e005222228007", + "0x1b00700532e00500700531e01b04400532e00504400531f01b04500532e", + "0x1b01b32e00501b01b01b22900704404504700522900532e005229005037", + "0x1b01b32e00501b00701b04404500740204604700732e00700501b007005", + "0x532e00504700504601b01b32e00501b04701b04300532e005048005048", + "0x1b01b32e00501b00701b04000540304104200732e00704300504501b047", + "0x503f00504201b03f00532e00519400504301b19400532e005041005044", + "0x1b07b00532e00503e00504001b02300532e00504200504101b03e00532e", + "0x3e01b02000532e00501b03f01b01b32e00501b00701b01b40400501b194", + "0x32e00519100504001b02300532e00504000504101b19100532e005020005", + "0x1b01b32e00501b00701b00900540532b00532e00707b00502301b07b005", + "0x504401b01b32e00501b00701b02d00540633032900732e007023005045", + "0x532e00503100504201b03100532e00502a00504301b02a00532e005330", + "0x1b19401b32000532e00532600504001b0c900532e00532900504101b326", + "0x31f00503e01b31f00532e00501b03f01b01b32e00501b00701b01b407005", + "0x32000532e00531e00504001b0c900532e00502d00504101b31e00532e005", + "0x504501b01b32e00501b00701b03900540803700532e00732000502301b", + "0x32e00501b02001b01b32e00501b00701b31c00540903603800732e0070c9", + "0x532b00532901b01b32e00503600532b01b01b32e00503800519101b01b", + "0x501b02d01b1fb00532e00501b33001b01b32e00503700532901b01b32e", + "0x20700532e0052031fb00703101b20300532e00520300502a01b20300532e", + "0x21100532001b21100532e00520720d0070c901b20d00532e00501b32601b", + "0x4600532e00504600531f01b04700532e00504700504601b21400532e005", + "0x4604704700521400532e00521400503701b00700532e00500700531e01b", + "0x32e00501b03901b01b32e00531c00519101b01b32e00501b00701b214007", + "0x21800732e00721604604704803601b21600532e00521600503801b216005", + "0x735801b01b32e00501b02001b01b32e00501b00701b22822200740a21c", + "0x32e00521800504601b04c00532e00504c00502a01b04c00532e00503732b", + "0x33001b01b32e00501b00701b22900540b01b32e00704c0052dd01b218005", + "0x5100532e00505100502a01b05100532e00501b35a01b05400532e00501b", + "0x21601b23105500732e00505200521401b05200532e00505105400703101b", + "0x532e00523200521c01b23200532e00523100521801b01b32e005055005", + "0x531f01b21800532e00521800504601b05700532e00523400522201b234", + "0x532e00505700503701b00700532e00500700531e01b21c00532e00521c", + "0x1b32e0052290052da01b01b32e00501b00701b05700721c218047005057", + "0x32e00505800502a01b05800532e00501b0cf01b05900532e00501b33001b", + "0xc901b23a00532e00501b32601b05600532e00505805900703101b058005", + "0x521800504601b03300532e00524900532001b24900532e00505623a007", + "0x1b00700532e00500700531e01b21c00532e00521c00531f01b21800532e", + "0x1b01b32e00501b00701b03300721c21804700503300532e005033005037", + "0x1b01b32e00503700532901b01b32e00532b00532901b01b32e00501b020", + "0x532e00525400502a01b25400532e00501b22901b05f00532e00501b330", + "0x70c901b06100532e00501b32601b06200532e00525405f00703101b254", + "0x32e00522200504601b00600532e00526c00532001b26c00532e005062061", + "0x3701b00700532e00500700531e01b22800532e00522800531f01b222005", + "0x2001b01b32e00501b00701b00600722822204700500600532e005006005", + "0x19101b01b32e00532b00532901b01b32e00503900505401b01b32e00501b", + "0x1b06b00532e00501b05101b06900532e00501b33001b01b32e0050c9005", + "0x501b32601b2d300532e00506b06900703101b06b00532e00506b00502a", + "0x7100532e00506f00532001b06f00532e0052d306e0070c901b06e00532e", + "0x700531e01b04600532e00504600531f01b04700532e00504700504601b", + "0x701b07100704604704700507100532e00507100503701b00700532e005", + "0x519101b01b32e00500900505401b01b32e00501b02001b01b32e00501b", + "0x2a01b03400532e00501b05201b2ee00532e00501b33001b01b32e005023", + "0x32e00501b32601b07600532e0050342ee00703101b03400532e005034005", + "0x1b07200532e00507300532001b07300532e0050763110070c901b311005", + "0x500700531e01b04600532e00504600531f01b04700532e005047005046", + "0x1b00701b07200704604704700507200532e00507200503701b00700532e", + "0x1b22901b07a00532e00501b33001b01b32e00504800505501b01b32e005", + "0x532e00507407a00703101b07400532e00507400502a01b07400532e005", + "0x532001b30d00532e00530f30e0070c901b30e00532e00501b32601b30f", + "0x532e00504400531f01b04500532e00504500504601b30c00532e00530d", + "0x4504700530c00532e00530c00503701b00700532e00500700531e01b044", + "0x40c04604700732e00700501b00700501b01b32e00501b01b01b30c007044", + "0x1b04701b04300532e00504800504801b01b32e00501b00701b044045007", + "0x4104200732e00704300504501b04700532e00504700504601b01b32e005", + "0x504101b19400532e00504100524901b01b32e00501b00701b04000540d", + "0x1b01b40e00501b19401b03e00532e00519400503301b03f00532e005042", + "0x7b00532e00502300505f01b02300532e00501b03f01b01b32e00501b007", + "0x3e00525401b03e00532e00507b00503301b03f00532e00504000504101b", + "0x1b01b32e00501b02001b01b32e00501b00701b19100540f02000532e007", + "0x32e00503f00521801b00900532e00501b33001b32b00532e005020005044", + "0x31f01b04700532e00504700504601b33000532e00532b00504301b329005", + "0x32e00500900522801b32900532e00532900506201b04600532e005046005", + "0x32e00533000932904604704606101b33000532e00533000502a01b009005", + "0x32e00501b00701b0c900541032600532e00703100526c01b03102a02d048", + "0x4601b31e00532e00532000504801b31f32000732e00532600500601b01b", + "0x32e00531e00504101b03900532e00502a00531f01b03700532e00502d005", + "0x501b00701b01b41100501b19401b03600532e00531f00506901b038005", + "0x31f01b02d00532e00502d00504601b31c00532e0050c900532001b01b32e", + "0x32e00531c00503701b00700532e00500700531e01b02a00532e00502a005", + "0x1b32e00501b02001b01b32e00501b00701b31c00702a02d04700531c005", + "0x32e0051fb0052d301b1fb00532e00501b03f01b01b32e00519100505401b", + "0x4101b03900532e00504600531f01b03700532e00504700504601b203005", + "0x32e00703600506e01b03600532e00520300506901b03800532e00503f005", + "0x21421100732e00703800504501b01b32e00501b00701b20d005412207005", + "0x21400532b01b01b32e00521100519101b01b32e00501b00701b216005413", + "0x1b02d01b21800532e00501b33001b01b32e00520700521601b01b32e005", + "0x532e00521c21800703101b21c00532e00521c00502a01b21c00532e005", + "0x532001b04c00532e0052222280070c901b22800532e00501b32601b222", + "0x532e00503900531f01b03700532e00503700504601b22900532e00504c", + "0x3704700522900532e00522900503701b00700532e00500700531e01b039", + "0x501b03901b01b32e00521600519101b01b32e00501b00701b229007039", + "0x732e00705403903704803601b05400532e00505400503801b05400532e", + "0x1b23200532e00501b2ff01b01b32e00501b00701b231055007414052051", + "0x500700531e01b05200532e00505200531f01b05100532e005051005046", + "0x520723200705205104635b01b20700532e00520700522801b00700532e", + "0x1b00701b23a00541505600532e0070580050b901b05805905723404732e", + "0x1b05f03300732e0050560050b801b24900532e00501b33001b01b32e005", + "0x525400521401b25400532e00505f24900703101b01b32e0050330052ea", + "0x1b26c00532e00506100521801b01b32e00506200521601b06106200732e", + "0x523400504601b06900532e00500600522201b00600532e00526c00521c", + "0x1b05900532e00505900531e01b05700532e00505700531f01b23400532e", + "0x1b01b32e00501b00701b06905905723404700506900532e005069005037", + "0x505700531f01b23400532e00523400504601b06b00532e00523a005320", + "0x506b00532e00506b00503701b05900532e00505900531e01b05700532e", + "0x33001b01b32e00520700521601b01b32e00501b00701b06b059057234047", + "0x6e00532e00506e00502a01b06e00532e00501b22901b2d300532e00501b", + "0x710070c901b07100532e00501b32601b06f00532e00506e2d300703101b", + "0x532e00505500504601b03400532e0052ee00532001b2ee00532e00506f", + "0x503701b00700532e00500700531e01b23100532e00523100531f01b055", + "0x505401b01b32e00501b00701b03400723105504700503400532e005034", + "0x5201b07600532e00501b33001b01b32e00503800519101b01b32e00520d", + "0x32e00531107600703101b31100532e00531100502a01b31100532e00501b", + "0x32001b07a00532e0050730720070c901b07200532e00501b32601b073005", + "0x32e00503900531f01b03700532e00503700504601b07400532e00507a005", + "0x4700507400532e00507400503701b00700532e00500700531e01b039005", + "0x1b33001b01b32e00504800505501b01b32e00501b00701b074007039037", + "0x1b30e00532e00530e00502a01b30e00532e00501b22901b30f00532e005", + "0x30d30c0070c901b30c00532e00501b32601b30d00532e00530e30f007031", + "0x4500532e00504500504601b30a00532e00530b00532001b30b00532e005", + "0x30a00503701b00700532e00500700531e01b04400532e00504400531f01b", + "0x1b00700501b01b32e00501b01b01b30a00704404504700530a00532e005", + "0x4800504801b01b32e00501b00701b04404500741604604700732e007005", + "0x4200732e00704300504501b04700532e00504700504601b04300532e005", + "0x532b01b01b32e00504200519101b01b32e00501b00701b040005417041", + "0x2a01b03f00532e00501b02d01b19400532e00501b33001b01b32e005041", + "0x32e00501b32601b03e00532e00503f19400703101b03f00532e00503f005", + "0x1b02000532e00507b00532001b07b00532e00503e0230070c901b023005", + "0x500700531e01b04600532e00504600531f01b04700532e005047005046", + "0x1b00701b02000704604704700502000532e00502000503701b00700532e", + "0x503801b19100532e00501b03901b01b32e00504000519101b01b32e005", + "0x33032900741800932b00732e00719104604704803601b19100532e005191", + "0x2a00532e00501b0bb01b02d00532e00501b33001b01b32e00501b00701b", + "0x1b32601b03100532e00502a02d00703101b02a00532e00502a00502a01b", + "0x532e0050c900532001b0c900532e0050313260070c901b32600532e005", + "0x531e01b00900532e00500900531f01b32b00532e00532b00504601b320", + "0x1b32000700932b04700532000532e00532000503701b00700532e005007", + "0x1b31e00532e00501b22901b31f00532e00501b33001b01b32e00501b007", + "0x501b32601b03700532e00531e31f00703101b31e00532e00531e00502a", + "0x3600532e00503800532001b03800532e0050370390070c901b03900532e", + "0x700531e01b33000532e00533000531f01b32900532e00532900504601b", + "0x701b03600733032904700503600532e00503600503701b00700532e005", + "0x22901b31c00532e00501b33001b01b32e00504800505501b01b32e00501b", + "0x32e0051fb31c00703101b1fb00532e0051fb00502a01b1fb00532e00501b", + "0x32001b20d00532e0052032070070c901b20700532e00501b32601b203005", + "0x32e00504400531f01b04500532e00504500504601b21100532e00520d005", + "0x4700521100532e00521100503701b00700532e00500700531e01b044005", + "0x4604700732e00700501b00700501b01b32e00501b01b01b211007044045", + "0x4701b04300532e00504800504801b01b32e00501b00701b044045007419", + "0x4200732e00704300504501b04700532e00504700504601b01b32e00501b", + "0x4301b19400532e00504100504401b01b32e00501b00701b04000541a041", + "0x32e00504200504101b03e00532e00503f00504201b03f00532e005194005", + "0x501b00701b01b41b00501b19401b07b00532e00503e00504001b023005", + "0x504101b19100532e00502000503e01b02000532e00501b03f01b01b32e", + "0x532e00707b00502301b07b00532e00519100504001b02300532e005040", + "0x41d33032900732e00702300504501b01b32e00501b00701b00900541c32b", + "0x32e00532900519101b01b32e00501b02001b01b32e00501b00701b02d005", + "0x32e00501b33001b01b32e00532b00532901b01b32e00533000532b01b01b", + "0x703101b03100532e00503100502a01b03100532e00501b02d01b02a005", + "0x32e0053260c90070c901b0c900532e00501b32601b32600532e00503102a", + "0x31f01b04700532e00504700504601b31f00532e00532000532001b320005", + "0x32e00531f00503701b00700532e00500700531e01b04600532e005046005", + "0x1b32e00501b02001b01b32e00501b00701b31f00704604704700531f005", + "0x32e00531e00503801b31e00532e00501b03901b01b32e00502d00519101b", + "0x1b00701b03603800741e03903700732e00731e04604704803601b31e005", + "0x31f01b03700532e00503700504601b31c00532e00501b2ff01b01b32e005", + "0x31c0390370470bd01b32b00532e00532b00502a01b03900532e005039005", + "0x701b21100541f20d00532e00720700533801b2072031fb04832e00532b", + "0x21401b21400532e00501b33001b01b32e00520d0052fc01b01b32e00501b", + "0x32e00521800521801b01b32e00521600521601b21821600732e005214005", + "0x4601b22800532e00522200522201b22200532e00521c00521c01b21c005", + "0x32e00500700531e01b20300532e00520300531f01b1fb00532e0051fb005", + "0x501b00701b2280072031fb04700522800532e00522800503701b007005", + "0x31f01b1fb00532e0051fb00504601b04c00532e00521100532001b01b32e", + "0x32e00504c00503701b00700532e00500700531e01b20300532e005203005", + "0x32e00532b00532901b01b32e00501b00701b04c0072031fb04700504c005", + "0x505400502a01b05400532e00501b22901b22900532e00501b33001b01b", + "0x1b05200532e00501b32601b05100532e00505422900703101b05400532e", + "0x3800504601b23100532e00505500532001b05500532e0050510520070c9", + "0x700532e00500700531e01b03600532e00503600531f01b03800532e005", + "0x1b32e00501b00701b23100703603804700523100532e00523100503701b", + "0x1b32e00502300519101b01b32e00500900505401b01b32e00501b02001b", + "0x32e00523400502a01b23400532e00501b05201b23200532e00501b33001b", + "0xc901b05900532e00501b32601b05700532e00523423200703101b234005", + "0x504700504601b05600532e00505800532001b05800532e005057059007", + "0x1b00700532e00500700531e01b04600532e00504600531f01b04700532e", + "0x1b01b32e00501b00701b05600704604704700505600532e005056005037", + "0x24900532e00501b22901b23a00532e00501b33001b01b32e005048005055", + "0x1b32601b03300532e00524923a00703101b24900532e00524900502a01b", + "0x532e00525400532001b25400532e00503305f0070c901b05f00532e005", + "0x531e01b04400532e00504400531f01b04500532e00504500504601b062", + "0x1b06200704404504700506200532e00506200503701b00700532e005007", + "0x1b04404500742004604700732e00700501b00700501b01b32e00501b01b", + "0x1b01b32e00501b04701b04300532e00504800504801b01b32e00501b007", + "0x1b04000542104104200732e00704300504501b04700532e005047005046", + "0x532e00519400504301b19400532e00504100504401b01b32e00501b007", + "0x504001b02300532e00504200504101b03e00532e00503f00504201b03f", + "0x1b03f01b01b32e00501b00701b01b42200501b19401b07b00532e00503e", + "0x2300532e00504000504101b19100532e00502000503e01b02000532e005", + "0x1b00900542332b00532e00707b00502301b07b00532e00519100504001b", + "0x1b00701b02d00542433032900732e00702300504501b01b32e00501b007", + "0x33000532b01b01b32e00532900519101b01b32e00501b02001b01b32e005", + "0x1b02d01b02a00532e00501b33001b01b32e00532b00532901b01b32e005", + "0x532e00503102a00703101b03100532e00503100502a01b03100532e005", + "0x532001b32000532e0053260c90070c901b0c900532e00501b32601b326", + "0x532e00504600531f01b04700532e00504700504601b31f00532e005320", + "0x4704700531f00532e00531f00503701b00700532e00500700531e01b046", + "0x502d00519101b01b32e00501b02001b01b32e00501b00701b31f007046", + "0x4803601b31e00532e00531e00503801b31e00532e00501b03901b01b32e", + "0x2ff01b01b32e00501b00701b03603800742503903700732e00731e046047", + "0x532e00503900531f01b03700532e00503700504601b31c00532e00501b", + "0x1fb04832e00532b31c0390370470c101b32b00532e00532b00502a01b039", + "0x1b01b32e00501b00701b21100542620d00532e00720700533801b207203", + "0x732e00521400521401b21400532e00501b33001b01b32e00520d0052fc", + "0x521c01b21c00532e00521800521801b01b32e00521600521601b218216", + "0x532e0051fb00504601b22800532e00522200522201b22200532e00521c", + "0x503701b00700532e00500700531e01b20300532e00520300531f01b1fb", + "0x532001b01b32e00501b00701b2280072031fb04700522800532e005228", + "0x532e00520300531f01b1fb00532e0051fb00504601b04c00532e005211", + "0x1fb04700504c00532e00504c00503701b00700532e00500700531e01b203", + "0x501b33001b01b32e00532b00532901b01b32e00501b00701b04c007203", + "0x3101b05400532e00505400502a01b05400532e00501b22901b22900532e", + "0x50510520070c901b05200532e00501b32601b05100532e005054229007", + "0x1b03800532e00503800504601b23100532e00505500532001b05500532e", + "0x523100503701b00700532e00500700531e01b03600532e00503600531f", + "0x32e00501b02001b01b32e00501b00701b23100703603804700523100532e", + "0x32e00501b33001b01b32e00502300519101b01b32e00500900505401b01b", + "0x703101b23400532e00523400502a01b23400532e00501b05201b232005", + "0x32e0050570590070c901b05900532e00501b32601b05700532e005234232", + "0x31f01b04700532e00504700504601b05600532e00505800532001b058005", + "0x32e00505600503701b00700532e00500700531e01b04600532e005046005", + "0x32e00504800505501b01b32e00501b00701b056007046047047005056005", + "0x524900502a01b24900532e00501b22901b23a00532e00501b33001b01b", + "0x1b05f00532e00501b32601b03300532e00524923a00703101b24900532e", + "0x4500504601b06200532e00525400532001b25400532e00503305f0070c9", + "0x700532e00500700531e01b04400532e00504400531f01b04500532e005", + "0x1b32e00501b01b01b06200704404504700506200532e00506200503701b", + "0x1b32e00501b00701b04404500742704604700732e00700501b00700501b", + "0x32e00504700504601b01b32e00501b04701b04300532e00504800504801b", + "0x1b32e00501b00701b04000542804104200732e00704300504501b047005", + "0x3f00504201b03f00532e00519400504301b19400532e00504100504401b", + "0x7b00532e00503e00504001b02300532e00504200504101b03e00532e005", + "0x1b02000532e00501b03f01b01b32e00501b00701b01b42900501b19401b", + "0x519100504001b02300532e00504000504101b19100532e00502000503e", + "0x1b32e00501b00701b00900542a32b00532e00707b00502301b07b00532e", + "0x1b01b32e00501b00701b02d00542b33032900732e00732b04700723a01b", + "0x1b32600542c03102a00732e00702300504501b32900532e005329005046", + "0x532e0050c900504301b0c900532e00503100504401b01b32e00501b007", + "0x504001b31e00532e00502a00504101b31f00532e00532000504201b320", + "0x1b03f01b01b32e00501b00701b01b42d00501b19401b03700532e00531f", + "0x31e00532e00532600504101b03800532e00503900503e01b03900532e005", + "0x1b31c00542e03600532e00703700502301b03700532e00503800504001b", + "0x1b00701b20700542f2031fb00732e00731e00504501b01b32e00501b007", + "0x1b21100532e00520d00504301b20d00532e00520300504401b01b32e005", + "0x521400504001b21600532e0051fb00504101b21400532e005211005042", + "0x32e00501b03f01b01b32e00501b00701b01b43000501b19401b21800532e", + "0x4001b21600532e00520700504101b22200532e00521c00503e01b21c005", + "0x1b00701b04c00543122800532e00721800502301b21800532e005222005", + "0x32e00501b00701b05100543205422900732e00721600504501b01b32e005", + "0x32e00505400532b01b01b32e00522900519101b01b32e00501b02001b01b", + "0x503600532901b01b32e00533000506b01b01b32e00522800532901b01b", + "0x5500502a01b05500532e00501b02d01b05200532e00501b33001b01b32e", + "0x23200532e00501b32601b23100532e00505505200703101b05500532e005", + "0x504601b05700532e00523400532001b23400532e0052312320070c901b", + "0x532e00500700531e01b04600532e00504600531f01b32900532e005329", + "0x32e00501b00701b05700704632904700505700532e00505700503701b007", + "0x505900503801b05900532e00501b03901b01b32e00505100519101b01b", + "0x701b24923a00743305605800732e00705904632904803601b05900532e", + "0x532e00505800504601b03322800732e0052280052d201b01b32e00501b", + "0x532901b01b32e00501b00701b05f00543401b32e0070330052dd01b058", + "0x31f01b01b32e00522800532901b01b32e00533000506b01b01b32e005036", + "0x1b43500501b19401b06200532e00500700531e01b25400532e005056005", + "0x6100532e00501b33001b01b32e00505f0052da01b01b32e00501b00701b", + "0x703101b00600532e00526c0052de01b26c33000732e00533000532f01b", + "0x6b06900703101b06b03600732e0050360052d201b06900532e005006061", + "0x6f00532e00506e22800735801b06e00532e00501b23401b2d300532e005", + "0x521401b07100532e00506f2d300703101b06f00532e00506f00502a01b", + "0x532e00503400521801b01b32e0052ee00521601b0342ee00732e005071", + "0x4832e00707603633000705604606f01b07600532e00507600506201b076", + "0x32e00507200505501b01b32e00501b00701b30f07407a048436072073311", + "0x1b02001b06200532e00507300531e01b25400532e00531100531f01b01b", + "0x1b30c30d00732e00530e00521401b30e00532e00501b33001b01b32e005", + "0x32e00530b00521c01b30b00532e00530c00521801b01b32e00530d005216", + "0x31f01b05800532e00505800504601b30900532e00530a00522201b30a005", + "0x32e00530900503701b06200532e00506200531e01b25400532e005254005", + "0x1b32e00501b02001b01b32e00501b00701b309062254058047005309005", + "0x8600532001b08600532e00530f3050070c901b30500532e00501b32601b", + "0x7a00532e00507a00531f01b05800532e00505800504601b30400532e005", + "0x7a05804700530400532e00530400503701b07400532e00507400531e01b", + "0x32e00522800532901b01b32e00501b02001b01b32e00501b00701b304074", + "0x32e00501b33001b01b32e00503600532901b01b32e00533000506b01b01b", + "0x703101b08400532e00508400502a01b08400532e00501b22901b303005", + "0x32e0053023010070c901b30100532e00501b32601b30200532e005084303", + "0x31f01b23a00532e00523a00504601b30000532e00508200532001b082005", + "0x32e00530000503701b00700532e00500700531e01b24900532e005249005", + "0x1b32e00501b02001b01b32e00501b00701b30000724923a047005300005", + "0x32e00533000506b01b01b32e00521600519101b01b32e00504c00505401b", + "0x32e00501b07101b2ff00532e00501b33001b01b32e00503600532901b01b", + "0x1b08700532e00507d2ff00703101b07d00532e00507d00502a01b07d005", + "0x52fc00532001b2fc00532e0050873380070c901b33800532e00501b326", + "0x1b04600532e00504600531f01b32900532e00532900504601b2fb00532e", + "0x70463290470052fb00532e0052fb00503701b00700532e00500700531e", + "0x1b32e00531c00505401b01b32e00501b02001b01b32e00501b00701b2fb", + "0x532e00501b33001b01b32e00533000506b01b01b32e00531e00519101b", + "0x2fa00703101b2f900532e0052f900502a01b2f900532e00501b05101b2fa", + "0x532e0052f82f70070c901b2f700532e00501b32601b2f800532e0052f9", + "0x531f01b32900532e00532900504601b2f500532e0052f600532001b2f6", + "0x532e0052f500503701b00700532e00500700531e01b04600532e005046", + "0x1b32e00502300519101b01b32e00501b00701b2f50070463290470052f5", + "0x1b32e00501b00701b01b43700501b19401b2f400532e00502d00504601b", + "0x32e00504700504601b01b32e00502300519101b01b32e00500900505401b", + "0x32e00501b05201b2f300532e00501b33001b01b32e00501b02001b2f4005", + "0x1b2f100532e0052f22f300703101b2f200532e0052f200502a01b2f2005", + "0x507c00532001b07c00532e0052f12ef0070c901b2ef00532e00501b326", + "0x1b04600532e00504600531f01b2f400532e0052f400504601b08b00532e", + "0x70462f404700508b00532e00508b00503701b00700532e00500700531e", + "0x532e00501b33001b01b32e00504800505501b01b32e00501b00701b08b", + "0x8d00703101b2ed00532e0052ed00502a01b2ed00532e00501b22901b08d", + "0x532e0050902ec0070c901b2ec00532e00501b32601b09000532e0052ed", + "0x531f01b04500532e00504500504601b2eb00532e00508e00532001b08e", + "0x532e0052eb00503701b00700532e00500700531e01b04400532e005044", + "0x32e00700700500700501b01b32e00501b01b01b2eb0070440450470052eb", + "0x532e00504700504801b01b32e00501b00701b043044007438045046007", + "0x704200504501b04600532e00504600504601b01b32e00501b04701b042", + "0x532e00504000504401b01b32e00501b00701b19400543904004100732e", + "0x504101b02300532e00503e00504201b03e00532e00503f00504301b03f", + "0x1b01b43a00501b19401b02000532e00502300504001b07b00532e005041", + "0x32b00532e00519100503e01b19100532e00501b03f01b01b32e00501b007", + "0x2000502301b02000532e00532b00504001b07b00532e00519400504101b", + "0x732e00707b00504501b01b32e00501b00701b32900543b00900532e007", + "0x1b03100532e00502d00504401b01b32e00501b00701b02a00543c02d330", + "0x533000504101b0c900532e00532600504201b32600532e005031005043", + "0x1b00701b01b43d00501b19401b31f00532e0050c900504001b32000532e", + "0x4101b03700532e00531e00503e01b31e00532e00501b03f01b01b32e005", + "0x32e00731f00502301b31f00532e00503700504001b32000532e00502a005", + "0x31c03600732e00732000504501b01b32e00501b00701b03800543e039005", + "0x504301b20300532e00531c00504401b01b32e00501b00701b1fb00543f", + "0x532e00503600504101b20d00532e00520700504201b20700532e005203", + "0x32e00501b00701b01b44000501b19401b21400532e00520d00504001b211", + "0x1fb00504101b21800532e00521600503e01b21600532e00501b03f01b01b", + "0x21c00532e00721400502301b21400532e00521800504001b21100532e005", + "0x544204c22800732e00721100504501b01b32e00501b00701b222005441", + "0x1b32e00522800519101b01b32e00501b02001b01b32e00501b00701b229", + "0x32e00503900532901b01b32e00521c00532901b01b32e00504c00532b01b", + "0x32e00501b02d01b05400532e00501b33001b01b32e00500900532901b01b", + "0x1b05200532e00505105400703101b05100532e00505100502a01b051005", + "0x523100532001b23100532e0050520550070c901b05500532e00501b326", + "0x1b04600532e00504600504601b01b00532e00501b00535d01b23200532e", + "0x523200503701b04800532e00504800531e01b04500532e00504500531f", + "0x22900519101b01b32e00501b00701b23204804504601b04600523200532e", + "0x3601b23400532e00523400503801b23400532e00501b03901b01b32e005", + "0x1b01b32e00501b00701b05605800744305905700732e007234045046048", + "0x5700532e00505700504601b23a00532e00501b2ff01b01b32e00501b020", + "0x4800531e01b01b00532e00501b00535d01b05900532e00505900531f01b", + "0x3900532e00503900502a01b00900532e00500900502a01b04800532e005", + "0x521c03900923a04801b0590570432cc01b21c00532e00521c00502a01b", + "0x701b26c00544406100532e00706200533801b06225405f03324904632e", + "0x21401b00600532e00501b33001b01b32e0050610052fc01b01b32e00501b", + "0x32e00506b00521801b01b32e00506900521601b06b06900732e005006005", + "0x35d01b06f00532e00506e00522201b06e00532e0052d300521c01b2d3005", + "0x32e00503300531f01b24900532e00524900504601b05f00532e00505f005", + "0x4600506f00532e00506f00503701b25400532e00525400531e01b033005", + "0x1b07100532e00526c00532001b01b32e00501b00701b06f25403324905f", + "0x503300531f01b24900532e00524900504601b05f00532e00505f00535d", + "0x507100532e00507100503701b25400532e00525400531e01b03300532e", + "0x32901b01b32e00501b02001b01b32e00501b00701b07125403324905f046", + "0x1b01b32e00500900532901b01b32e00503900532901b01b32e00521c005", + "0x532e00503400502a01b03400532e00501b22901b2ee00532e00501b330", + "0x70c901b31100532e00501b32601b07600532e0050342ee00703101b034", + "0x32e00501b00535d01b07200532e00507300532001b07300532e005076311", + "0x31e01b05600532e00505600531f01b05800532e00505800504601b01b005", + "0x4805605801b04600507200532e00507200503701b04800532e005048005", + "0x1b32e00522200505401b01b32e00501b02001b01b32e00501b00701b072", + "0x32e00500900532901b01b32e00503900532901b01b32e00521100519101b", + "0x507400502a01b07400532e00501b07101b07a00532e00501b33001b01b", + "0x1b30e00532e00501b32601b30f00532e00507407a00703101b07400532e", + "0x1b00535d01b30c00532e00530d00532001b30d00532e00530f30e0070c9", + "0x4500532e00504500531f01b04600532e00504600504601b01b00532e005", + "0x4601b04600530c00532e00530c00503701b04800532e00504800531e01b", + "0x503800505401b01b32e00501b02001b01b32e00501b00701b30c048045", + "0x501b33001b01b32e00532000519101b01b32e00500900532901b01b32e", + "0x3101b30a00532e00530a00502a01b30a00532e00501b05101b30b00532e", + "0x53093050070c901b30500532e00501b32601b30900532e00530a30b007", + "0x1b01b00532e00501b00535d01b30400532e00508600532001b08600532e", + "0x504800531e01b04500532e00504500531f01b04600532e005046005046", + "0x701b30404804504601b04600530400532e00530400503701b04800532e", + "0x519101b01b32e00532900505401b01b32e00501b02001b01b32e00501b", + "0x2a01b08400532e00501b05201b30300532e00501b33001b01b32e00507b", + "0x32e00501b32601b30200532e00508430300703101b08400532e005084005", + "0x1b30000532e00508200532001b08200532e0053023010070c901b301005", + "0x504500531f01b04600532e00504600504601b01b00532e00501b00535d", + "0x530000532e00530000503701b04800532e00504800531e01b04500532e", + "0x1b01b32e00504700505501b01b32e00501b00701b30004804504601b046", + "0x532e00507d00502a01b07d00532e00501b22901b2ff00532e00501b330", + "0x70c901b33800532e00501b32601b08700532e00507d2ff00703101b07d", + "0x32e00501b00535d01b2fb00532e0052fc00532001b2fc00532e005087338", + "0x31e01b04300532e00504300531f01b04400532e00504400504601b01b005", + "0x4804304401b0460052fb00532e0052fb00503701b04800532e005048005", + "0x4300744504404500732e00704800500700501b01b32e00501b01b01b2fb", + "0x504600506201b04500532e00504500504601b01b32e00501b00701b042", + "0x32e0071940052cb01b19404004104832e0050460450070c601b04600532e", + "0x1b02300532e00504000504801b01b32e00501b00701b03e00544603f005", + "0x519101b01b32e00501b00701b19100544702007b00732e007023005045", + "0x33001b01b32e00503f0050c701b01b32e00502000532b01b01b32e00507b", + "0x900532e00500900502a01b00900532e00501b02d01b32b00532e00501b", + "0x3300070c901b33000532e00501b32601b32900532e00500932b00703101b", + "0x532e00501b00535d01b02a00532e00502d00532001b02d00532e005329", + "0x531f01b00700532e0050070052d401b04100532e00504100504601b01b", + "0x532e00502a00503701b04700532e00504700531e01b04400532e005044", + "0x519100519101b01b32e00501b00701b02a04704400704101b04500502a", + "0x4803601b03100532e00503100503801b03100532e00501b03901b01b32e", + "0x2ff01b01b32e00501b00701b31f3200074480c932600732e007031044041", + "0x532e0050c900531f01b32600532e00532600504601b31e00532e00501b", + "0x531e01b01b00532e00501b00535d01b00700532e0050070052d401b0c9", + "0x1b0070c93260442c901b03f00532e00503f00535f01b04700532e005047", + "0x20300532e0071fb00533801b1fb31c03603803903704532e00503f31e047", + "0x501b33001b01b32e0052030052fc01b01b32e00501b00701b207005449", + "0x1b01b32e00521100521601b21421100732e00520d00521401b20d00532e", + "0x521800522201b21800532e00521600521c01b21600532e005214005218", + "0x1b03700532e00503700504601b03600532e00503600535d01b21c00532e", + "0x531c00531e01b03900532e00503900531f01b03800532e0050380052d4", + "0x1b21c31c03903803703604500521c00532e00521c00503701b31c00532e", + "0x532e00503600535d01b22200532e00520700532001b01b32e00501b007", + "0x531f01b03800532e0050380052d401b03700532e00503700504601b036", + "0x532e00522200503701b31c00532e00531c00531e01b03900532e005039", + "0x503f0050c701b01b32e00501b00701b22231c039038037036045005222", + "0x4c00502a01b04c00532e00501b22901b22800532e00501b33001b01b32e", + "0x5400532e00501b32601b22900532e00504c22800703101b04c00532e005", + "0x535d01b05200532e00505100532001b05100532e0052290540070c901b", + "0x532e0050070052d401b32000532e00532000504601b01b00532e00501b", + "0x503701b04700532e00504700531e01b31f00532e00531f00531f01b007", + "0x1b01b32e00501b00701b05204731f00732001b04500505200532e005052", + "0x5500532e00501b33001b01b32e00504000505501b01b32e00503e005054", + "0x23105500703101b23100532e00523100502a01b23100532e00501b05201b", + "0x5700532e0052322340070c901b23400532e00501b32601b23200532e005", + "0x4100504601b01b00532e00501b00535d01b05900532e00505700532001b", + "0x4400532e00504400531f01b00700532e0050070052d401b04100532e005", + "0x4101b04500505900532e00505900503701b04700532e00504700531e01b", + "0x1b33001b01b32e00504600505501b01b32e00501b00701b059047044007", + "0x1b05600532e00505600502a01b05600532e00501b22901b05800532e005", + "0x23a2490070c901b24900532e00501b32601b23a00532e005056058007031", + "0x1b00532e00501b00535d01b05f00532e00503300532001b03300532e005", + "0x4200531f01b00700532e0050070052d401b04300532e00504300504601b", + "0x5f00532e00505f00503701b04700532e00504700531e01b04200532e005", + "0x700501b00700501b01b32e00501b01b01b05f04704200704301b045005", + "0x32e00504800504801b01b32e00501b00701b04404500744a04604700732e", + "0x4300504501b04700532e00504700504601b01b32e00501b04701b043005", + "0x32e00504100504401b01b32e00501b00701b04000544b04104200732e007", + "0x4101b03e00532e00503f00504201b03f00532e00519400504301b194005", + "0x1b44c00501b19401b07b00532e00503e00504001b02300532e005042005", + "0x532e00502000503e01b02000532e00501b03f01b01b32e00501b00701b", + "0x502301b07b00532e00519100504001b02300532e00504000504101b191", + "0x732b04700723a01b01b32e00501b00701b00900544d32b00532e00707b", + "0x532e00502300521801b01b32e00501b00701b02d00544e33032900732e", + "0x70c601b02a00532e00502a00506201b32900532e00532900504601b02a", + "0x1b31f00544f32000532e0070c90052cb01b0c932603104832e00502a329", + "0x732e00731e00504501b31e00532e00532600504801b01b32e00501b007", + "0x519101b01b32e00501b02001b01b32e00501b00701b038005450039037", + "0x6b01b01b32e0053200050c701b01b32e00503900532b01b01b32e005037", + "0x1b31c00532e00501b02d01b03600532e00501b33001b01b32e005330005", + "0x501b32601b1fb00532e00531c03600703101b31c00532e00531c00502a", + "0x20d00532e00520700532001b20700532e0051fb2030070c901b20300532e", + "0x700531e01b04600532e00504600531f01b03100532e00503100504601b", + "0x701b20d00704603104700520d00532e00520d00503701b00700532e005", + "0x1b03901b01b32e00503800519101b01b32e00501b02001b01b32e00501b", + "0x32e00721104603104803601b21100532e00521100503801b21100532e005", + "0x22200532e00501b33001b01b32e00501b00701b21c218007451216214007", + "0x4c0052c701b01b32e0052280050c701b04c22800732e0053200052c801b", + "0x32e0050510050cd01b05105400732e0052290052c101b22904c00732e005", + "0x2c101b05500532e00505222200703101b05200532e00505400504301b01b", + "0x32e0052320052be01b01b32e00523100532901b23223100732e00504c005", + "0x1b05800532e0050590050c401b05900532e0052340052bc01b057234007", + "0x23a0050c401b23a00532e0050570052bc01b05600532e005058055007031", + "0x5f00532e00501b2bf01b03300532e00524905600703101b24900532e005", + "0x6200521801b01b32e00525400521601b06225400732e00503300521401b", + "0x6100532e00506100506201b05f00532e00505f00502a01b06100532e005", + "0x26c04832e00706105f33000721604606f01b21400532e00521400504601b", + "0x1b32e00506900505501b01b32e00501b00701b06e2d306b048452069006", + "0x7100521601b2ee07100732e00506f00521401b06f00532e00501b33001b", + "0x1b07600532e00503400521c01b03400532e0052ee00521801b01b32e005", + "0x526c00531f01b21400532e00521400504601b31100532e005076005222", + "0x531100532e00531100503701b00600532e00500600531e01b26c00532e", + "0xc901b07300532e00501b32601b01b32e00501b00701b31100626c214047", + "0x521400504601b07a00532e00507200532001b07200532e00506e073007", + "0x1b2d300532e0052d300531e01b06b00532e00506b00531f01b21400532e", + "0x1b01b32e00501b00701b07a2d306b21404700507a00532e00507a005037", + "0x7400532e00501b33001b01b32e00533000506b01b01b32e0053200050c7", + "0x30f07400703101b30f00532e00530f00502a01b30f00532e00501b22901b", + "0x30c00532e00530e30d0070c901b30d00532e00501b32601b30e00532e005", + "0x21c00531f01b21800532e00521800504601b30b00532e00530c00532001b", + "0x30b00532e00530b00503701b00700532e00500700531e01b21c00532e005", + "0x5401b01b32e00501b02001b01b32e00501b00701b30b00721c218047005", + "0x1b01b32e00533000506b01b01b32e00532600505501b01b32e00531f005", + "0x532e00530900502a01b30900532e00501b05101b30a00532e00501b330", + "0x70c901b08600532e00501b32601b30500532e00530930a00703101b309", + "0x32e00503100504601b30300532e00530400532001b30400532e005305086", + "0x3701b00700532e00500700531e01b04600532e00504600531f01b031005", + "0x19101b01b32e00501b00701b30300704603104700530300532e005303005", + "0x1b01b45300501b19401b08400532e00502d00504601b01b32e005023005", + "0x1b01b32e00502300519101b01b32e00500900505401b01b32e00501b007", + "0x30200532e00501b33001b01b32e00501b02001b08400532e005047005046", + "0x30130200703101b30100532e00530100502a01b30100532e00501b05201b", + "0x2ff00532e0050823000070c901b30000532e00501b32601b08200532e005", + "0x4600531f01b08400532e00508400504601b07d00532e0052ff00532001b", + "0x7d00532e00507d00503701b00700532e00500700531e01b04600532e005", + "0x1b01b32e00504800505501b01b32e00501b00701b07d007046084047005", + "0x532e00533800502a01b33800532e00501b22901b08700532e00501b330", + "0x70c901b2fb00532e00501b32601b2fc00532e00533808700703101b338", + "0x32e00504500504601b2f900532e0052fa00532001b2fa00532e0052fc2fb", + "0x3701b00700532e00500700531e01b04400532e00504400531f01b045005", + "0x501b01b32e00501b01b01b2f90070440450470052f900532e0052f9005", + "0x4801b01b32e00501b00701b04304400745404504600732e00700701b007", + "0x32e00704200504501b04600532e00504600504601b04200532e005047005", + "0x1b01b32e00504100519101b01b32e00501b00701b194005455040041007", + "0x3e00532e00501b02d01b03f00532e00501b33001b01b32e00504000532b", + "0x1b32601b02300532e00503e03f00703101b03e00532e00503e00502a01b", + "0x532e00502000532001b02000532e00502307b0070c901b07b00532e005", + "0x531f01b00500532e0050050050ce01b04600532e00504600504601b191", + "0x532e00519100503701b04800532e00504800531e01b04500532e005045", + "0x32e00519400519101b01b32e00501b00701b191048045005046046005191", + "0x4604803601b32b00532e00532b00503801b32b00532e00501b03901b01b", + "0x1b2ff01b01b32e00501b00701b02d33000745632900900732e00732b045", + "0x500532e0050050050ce01b00900532e00500900504601b02a00532e005", + "0x90462c601b04800532e00504800531e01b32900532e00532900531f01b", + "0x31e00532e00731f00533801b31f3200c932603104632e00502a048329005", + "0x501b33001b01b32e00531e0052fc01b01b32e00501b00701b037005457", + "0x1b01b32e00503800521601b03603800732e00503900521401b03900532e", + "0x51fb00522201b1fb00532e00531c00521c01b31c00532e005036005218", + "0x1b32600532e0053260050ce01b03100532e00503100504601b20300532e", + "0x520300503701b32000532e00532000531e01b0c900532e0050c900531f", + "0x3700532001b01b32e00501b00701b2033200c932603104600520300532e", + "0x32600532e0053260050ce01b03100532e00503100504601b20700532e005", + "0x20700503701b32000532e00532000531e01b0c900532e0050c900531f01b", + "0x1b33001b01b32e00501b00701b2073200c932603104600520700532e005", + "0x1b21100532e00521100502a01b21100532e00501b22901b20d00532e005", + "0x2142160070c901b21600532e00501b32601b21400532e00521120d007031", + "0x33000532e00533000504601b21c00532e00521800532001b21800532e005", + "0x4800531e01b02d00532e00502d00531f01b00500532e0050050050ce01b", + "0x1b21c04802d00533004600521c00532e00521c00503701b04800532e005", + "0x1b22200532e00501b33001b01b32e00504700505501b01b32e00501b007", + "0x522822200703101b22800532e00522800502a01b22800532e00501b229", + "0x1b05400532e00504c2290070c901b22900532e00501b32601b04c00532e", + "0x50050050ce01b04400532e00504400504601b05100532e005054005320", + "0x1b04800532e00504800531e01b04300532e00504300531f01b00500532e", + "0x1b32e00501b01b01b05104804300504404600505100532e005051005037", + "0x1b32e00501b00701b04304400745804504600732e00700700500700501b", + "0x32e00504600504601b01b32e00501b04701b04200532e00504700504801b", + "0x1b32e00501b00701b19400545904004100732e00704200504501b046005", + "0x3e00504201b03e00532e00503f00504301b03f00532e00504000504401b", + "0x2000532e00502300504001b07b00532e00504100504101b02300532e005", + "0x1b19100532e00501b03f01b01b32e00501b00701b01b45a00501b19401b", + "0x532b00504001b07b00532e00519400504101b32b00532e00519100503e", + "0x1b32e00501b00701b32900545b00900532e00702000502301b02000532e", + "0x2001b01b32e00501b00701b02a00545c02d33000732e00707b00504501b", + "0x32901b01b32e00502d00532b01b01b32e00533000519101b01b32e00501b", + "0x1b32600532e00501b02d01b03100532e00501b33001b01b32e005009005", + "0x501b32601b0c900532e00532603100703101b32600532e00532600502a", + "0x31e00532e00531f00532001b31f00532e0050c93200070c901b32000532e", + "0x4500531f01b04600532e00504600504601b01b00532e00501b00535d01b", + "0x31e00532e00531e00503701b04800532e00504800531e01b04500532e005", + "0x1b01b32e00501b02001b01b32e00501b00701b31e04804504601b046005", + "0x532e00503700503801b03700532e00501b03901b01b32e00502a005191", + "0x501b00701b31c03600745d03803900732e00703704504604803601b037", + "0x531f01b03900532e00503900504601b1fb00532e00501b2ff01b01b32e", + "0x532e00504800531e01b01b00532e00501b00535d01b03800532e005038", + "0x32e0050091fb04801b0380390452b901b00900532e00500900502a01b048", + "0x1b00701b21800545e21600532e00721400533801b21421120d207203046", + "0x521401b21c00532e00501b33001b01b32e0052160052fc01b01b32e005", + "0x532e00522800521801b01b32e00522200521601b22822200732e00521c", + "0x535d01b05400532e00522900522201b22900532e00504c00521c01b04c", + "0x532e00520700531f01b20300532e00520300504601b20d00532e00520d", + "0x20d04600505400532e00505400503701b21100532e00521100531e01b207", + "0x35d01b05100532e00521800532001b01b32e00501b00701b054211207203", + "0x32e00520700531f01b20300532e00520300504601b20d00532e00520d005", + "0x4600505100532e00505100503701b21100532e00521100531e01b207005", + "0x33001b01b32e00500900532901b01b32e00501b00701b05121120720320d", + "0x5500532e00505500502a01b05500532e00501b22901b05200532e00501b", + "0x2320070c901b23200532e00501b32601b23100532e00505505200703101b", + "0x532e00501b00535d01b05700532e00523400532001b23400532e005231", + "0x531e01b31c00532e00531c00531f01b03600532e00503600504601b01b", + "0x5704831c03601b04600505700532e00505700503701b04800532e005048", + "0x1b01b32e00532900505401b01b32e00501b02001b01b32e00501b00701b", + "0x5800532e00501b05201b05900532e00501b33001b01b32e00507b005191", + "0x1b32601b05600532e00505805900703101b05800532e00505800502a01b", + "0x532e00524900532001b24900532e00505623a0070c901b23a00532e005", + "0x531f01b04600532e00504600504601b01b00532e00501b00535d01b033", + "0x532e00503300503701b04800532e00504800531e01b04500532e005045", + "0x32e00504700505501b01b32e00501b00701b03304804504601b046005033", + "0x525400502a01b25400532e00501b22901b05f00532e00501b33001b01b", + "0x1b06100532e00501b32601b06200532e00525405f00703101b25400532e", + "0x1b00535d01b00600532e00526c00532001b26c00532e0050620610070c9", + "0x4300532e00504300531f01b04400532e00504400504601b01b00532e005", + "0x4401b04600500600532e00500600503701b04800532e00504800531e01b", + "0x45f04604700732e00700501b00700501b01b32e00501b01b01b006048043", + "0x1b04701b04300532e00504800504801b01b32e00501b00701b044045007", + "0x4104200732e00704300504501b04700532e00504700504601b01b32e005", + "0x504301b19400532e00504100504401b01b32e00501b00701b040005460", + "0x532e00504200504101b03e00532e00503f00504201b03f00532e005194", + "0x32e00501b00701b01b46100501b19401b07b00532e00503e00504001b023", + "0x4000504101b19100532e00502000503e01b02000532e00501b03f01b01b", + "0x32b00532e00707b00502301b07b00532e00519100504001b02300532e005", + "0x546333032900732e00702300504501b01b32e00501b00701b009005462", + "0x1b32e00532900519101b01b32e00501b02001b01b32e00501b00701b02d", + "0x532e00501b33001b01b32e00532b00532901b01b32e00533000532b01b", + "0x2a00703101b03100532e00503100502a01b03100532e00501b02d01b02a", + "0x532e0053260c90070c901b0c900532e00501b32601b32600532e005031", + "0x531f01b04700532e00504700504601b31f00532e00532000532001b320", + "0x532e00531f00503701b00700532e00500700531e01b04600532e005046", + "0x1b01b32e00501b02001b01b32e00501b00701b31f00704604704700531f", + "0x532e00531e00503801b31e00532e00501b03901b01b32e00502d005191", + "0x501b00701b03603800746403903700732e00731e04604704803601b31e", + "0x1fb00502a01b1fb00532e00501b2b801b31c00532e00501b33001b01b32e", + "0x20700532e00501b2b701b20300532e0051fb31c00703101b1fb00532e005", + "0x521401b20d00532e00520720300703101b20700532e00520700502a01b", + "0x532e00521400521801b01b32e00521100521601b21421100732e00520d", + "0x470a401b03700532e00503700504601b21600532e00521600506201b216", + "0x1b32e00501b00701b04c22822204846521c21800732e00721632b007039", + "0x5400521601b05105400732e00522900521401b22900532e00501b33001b", + "0x1b05500532e00505200521c01b05200532e00505100521801b01b32e005", + "0x521800531f01b03700532e00503700504601b23100532e005055005222", + "0x523100532e00523100503701b21c00532e00521c00531e01b21800532e", + "0xc901b23200532e00501b32601b01b32e00501b00701b23121c218037047", + "0x503700504601b05700532e00523400532001b23400532e00504c232007", + "0x1b22800532e00522800531e01b22200532e00522200531f01b03700532e", + "0x1b01b32e00501b00701b05722822203704700505700532e005057005037", + "0x5800532e00501b22901b05900532e00501b33001b01b32e00532b005329", + "0x1b32601b05600532e00505805900703101b05800532e00505800502a01b", + "0x532e00524900532001b24900532e00505623a0070c901b23a00532e005", + "0x531e01b03600532e00503600531f01b03800532e00503800504601b033", + "0x1b03300703603804700503300532e00503300503701b00700532e005007", + "0x19101b01b32e00500900505401b01b32e00501b02001b01b32e00501b007", + "0x1b25400532e00501b05201b05f00532e00501b33001b01b32e005023005", + "0x501b32601b06200532e00525405f00703101b25400532e00525400502a", + "0x600532e00526c00532001b26c00532e0050620610070c901b06100532e", + "0x700531e01b04600532e00504600531f01b04700532e00504700504601b", + "0x701b00600704604704700500600532e00500600503701b00700532e005", + "0x22901b06900532e00501b33001b01b32e00504800505501b01b32e00501b", + "0x32e00506b06900703101b06b00532e00506b00502a01b06b00532e00501b", + "0x32001b06f00532e0052d306e0070c901b06e00532e00501b32601b2d3005", + "0x32e00504400531f01b04500532e00504500504601b07100532e00506f005", + "0x4700507100532e00507100503701b00700532e00500700531e01b044005", + "0x4304400732e00704701b00700501b01b32e00501b01b01b071007044045", + "0x4601b04000532e00504500504801b01b32e00501b00701b041042007466", + "0x701b03e00546703f19400732e00704000504501b04400532e005044005", + "0x33001b01b32e00503f00532b01b01b32e00519400519101b01b32e00501b", + "0x7b00532e00507b00502a01b07b00532e00501b02d01b02300532e00501b", + "0x1910070c901b19100532e00501b32601b02000532e00507b02300703101b", + "0x532e00504400504601b00900532e00532b00532001b32b00532e005020", + "0x50d401b00700532e0050070052c501b00500532e0050050050d201b044", + "0x532e00504600531e01b04300532e00504300531f01b04800532e005048", + "0x701b00904604304800700504404400500900532e00500900503701b046", + "0x3801b32900532e00501b03901b01b32e00503e00519101b01b32e00501b", + "0x2a00746802d33000732e00732904304404803601b32900532e005329005", + "0x32e00533000504601b32600532e00501b2ff01b01b32e00501b00701b031", + "0xd201b04800532e0050480050d401b00700532e0050070052c501b330005", + "0x480073300452c201b02d00532e00502d00531f01b00500532e005005005", + "0x3800532e00703900533801b03903731e31f3200c904532e00532602d005", + "0x501b33001b01b32e0050380052fc01b01b32e00501b00701b036005469", + "0x1b01b32e0051fb00521601b2031fb00732e00531c00521401b31c00532e", + "0x520d00522201b20d00532e00520700521c01b20700532e005203005218", + "0x1b31e00532e00531e0050d201b0c900532e0050c900504601b21100532e", + "0x503700531f01b31f00532e00531f0050d401b32000532e0053200052c5", + "0x521100532e00521100503701b04600532e00504600531e01b03700532e", + "0x32e00503600532001b01b32e00501b00701b21104603731f32031e0c9044", + "0x2c501b31e00532e00531e0050d201b0c900532e0050c900504601b214005", + "0x32e00503700531f01b31f00532e00531f0050d401b32000532e005320005", + "0x4400521400532e00521400503701b04600532e00504600531e01b037005", + "0x21600532e00501b33001b01b32e00501b00701b21404603731f32031e0c9", + "0x21821600703101b21800532e00521800502a01b21800532e00501b22901b", + "0x22800532e00521c2220070c901b22200532e00501b32601b21c00532e005", + "0x50050d201b02a00532e00502a00504601b04c00532e00522800532001b", + "0x4800532e0050480050d401b00700532e0050070052c501b00500532e005", + "0x4c00503701b04600532e00504600531e01b03100532e00503100531f01b", + "0x1b01b32e00501b00701b04c04603104800700502a04400504c00532e005", + "0x5400532e00501b22901b22900532e00501b33001b01b32e005045005055", + "0x1b32601b05100532e00505422900703101b05400532e00505400502a01b", + "0x532e00505500532001b05500532e0050510520070c901b05200532e005", + "0x52c501b00500532e0050050050d201b04200532e00504200504601b231", + "0x532e00504100531f01b04800532e0050480050d401b00700532e005007", + "0x4204400523100532e00523100503701b04600532e00504600531e01b041", + "0x732e00700701b00700501b01b32e00501b01b01b231046041048007005", + "0x4200532e00504700504801b01b32e00501b00701b04304400746a045046", + "0x19400546b04004100732e00704200504501b04600532e00504600504601b", + "0x1b32e00504000532b01b01b32e00504100519101b01b32e00501b00701b", + "0x32e00503e00502a01b03e00532e00501b02d01b03f00532e00501b33001b", + "0xc901b07b00532e00501b32601b02300532e00503e03f00703101b03e005", + "0x504600504601b19100532e00502000532001b02000532e00502307b007", + "0x1b04500532e00504500531f01b00500532e0050050050d201b04600532e", + "0x4500504604600519100532e00519100503701b04800532e00504800531e", + "0x32e00501b03901b01b32e00519400519101b01b32e00501b00701b191048", + "0x900732e00732b04504604803601b32b00532e00532b00503801b32b005", + "0x1b00500532e0050050050d201b01b32e00501b00701b02d33000746c329", + "0x32e00500900504601b01b32e00501b04701b03102a00732e0050050052c3", + "0x1b01b32e00501b00701b0c900546d32600532e00703100508501b009005", + "0x32e00502a0052c301b02a00532e00502a0050d201b01b32e0053260052e6", + "0x1b32e00501b00701b03700546e31e00532e00731f00508501b31f320007", + "0x3900532e00501b33001b01b32e00531e0052e601b01b32e00501b02001b", + "0x3600521801b01b32e00503800521601b03603800732e00503900521401b", + "0x20300532e0051fb00522201b1fb00532e00531c00521c01b31c00532e005", + "0x32900531f01b32000532e0053200050d201b00900532e00500900504601b", + "0x20300532e00520300503701b04800532e00504800531e01b32900532e005", + "0x532e0053200050d201b01b32e00501b00701b203048329320009046005", + "0x32e00501b00701b01b46f00501b19401b20d00532e0050370050d601b207", + "0x1b02001b20d00532e0050c90050d601b20700532e00502a0050d201b01b", + "0x1b00900532e00500900504601b21100532e00520d00532001b01b32e005", + "0x504800531e01b32900532e00532900531f01b20700532e0052070050d2", + "0x701b21104832920700904600521100532e00521100503701b04800532e", + "0x2a01b21600532e00501b22901b21400532e00501b33001b01b32e00501b", + "0x32e00501b32601b21800532e00521621400703101b21600532e005216005", + "0x1b22800532e00522200532001b22200532e00521821c0070c901b21c005", + "0x502d00531f01b00500532e0050050050d201b33000532e005330005046", + "0x522800532e00522800503701b04800532e00504800531e01b02d00532e", + "0x1b01b32e00504700505501b01b32e00501b00701b22804802d005330046", + "0x532e00522900502a01b22900532e00501b22901b04c00532e00501b330", + "0x70c901b05100532e00501b32601b05400532e00522904c00703101b229", + "0x32e00504400504601b05500532e00505200532001b05200532e005054051", + "0x31e01b04300532e00504300531f01b00500532e0050050050d201b044005", + "0x4804300504404600505500532e00505500503701b04800532e005048005", + "0x32e00501b05801b04400532e00501b05901b04600532e00501b05901b055", + "0x4100747004204300732e00700501b00700501b01b32e00501b01b01b01b", + "0x32e00501b04701b19400532e00504800504801b01b32e00501b00701b040", + "0x547103e03f00732e00719400504501b04300532e00504300504601b01b", + "0x507b00504301b07b00532e00503e00504401b01b32e00501b00701b023", + "0x1b32b00532e00503f00504101b19100532e00502000504201b02000532e", + "0x1b01b32e00501b00701b01b47200501b19401b00900532e005191005040", + "0x32e00502300504101b33000532e00532900503e01b32900532e00501b03f", + "0x547304500532e00700900502301b00900532e00533000504001b32b005", + "0x4300723a01b04500532e00504504400705601b01b32e00501b00701b02d", + "0x502a00504601b01b32e00501b00701b32600547403102a00732e007045", + "0x32e00501b00701b31f0054753200c900732e00732b00504501b02a00532e", + "0x504201b03700532e00531e00504301b31e00532e00532000504401b01b", + "0x532e00503900504001b03800532e0050c900504101b03900532e005037", + "0x31c00532e00501b03f01b01b32e00501b00701b01b47600501b19401b036", + "0x1fb00504001b03800532e00531f00504101b1fb00532e00531c00503e01b", + "0x32e00501b00701b20300547704700532e00703600502301b03600532e005", + "0x47820d20700732e00703800504501b04700532e00504704600705601b01b", + "0x20700504101b21400532e00520d00524901b01b32e00501b00701b211005", + "0x701b01b47900501b19401b21800532e00521400503301b21600532e005", + "0x1b22200532e00521c00505f01b21c00532e00501b03f01b01b32e00501b", + "0x721800525401b21800532e00522200503301b21600532e005211005041", + "0x4401b01b32e00501b02001b01b32e00501b00701b04c00547a22800532e", + "0x532e00521600521801b05400532e00501b33001b22900532e005228005", + "0x531f01b02a00532e00502a00504601b05200532e00522900504301b051", + "0x532e00505400522801b05100532e00505100506201b04200532e005042", + "0x4832e00505205405104202a04606101b05200532e00505200502a01b054", + "0x1b32e00501b00701b05700547b23400532e00723200526c01b232231055", + "0x504601b05600532e00505900504801b05805900732e00523400500601b", + "0x532e00505600504101b24900532e00523100531f01b23a00532e005055", + "0x32e00501b00701b01b47c00501b19401b05f00532e00505800506901b033", + "0x505700532001b01b32e00504700532901b01b32e00503100506b01b01b", + "0x1b23100532e00523100531f01b05500532e00505500504601b25400532e", + "0x723105504700525400532e00525400503701b00700532e00500700531e", + "0x1b32e00504c00505401b01b32e00501b02001b01b32e00501b00701b254", + "0x502a00504601b06100532e0050620052d301b06200532e00501b03f01b", + "0x1b03300532e00521600504101b24900532e00504200531f01b23a00532e", + "0x701b00600547d26c00532e00705f00506e01b05f00532e005061005069", + "0x501b00701b2d300547e06b06900732e00703300504501b01b32e00501b", + "0x26c00521601b01b32e00506b00532b01b01b32e00506900519101b01b32e", + "0x1b33001b01b32e00503100506b01b01b32e00504700532901b01b32e005", + "0x1b06f00532e00506f00502a01b06f00532e00501b02d01b06e00532e005", + "0x712ee0070c901b2ee00532e00501b32601b07100532e00506f06e007031", + "0x23a00532e00523a00504601b07600532e00503400532001b03400532e005", + "0x7600503701b00700532e00500700531e01b24900532e00524900531f01b", + "0x2d300519101b01b32e00501b00701b07600724923a04700507600532e005", + "0x3601b31100532e00531100503801b31100532e00501b03901b01b32e005", + "0x1b01b32e00501b00701b07407a00747f07207300732e00731124923a048", + "0x32e00507200531f01b07300532e00507300504601b30f00532e00501b2ff", + "0x2a01b03100532e0050310052c401b00700532e00500700531e01b072005", + "0x70720730442b601b26c00532e00526c00522801b04700532e005047005", + "0x48030a00532e00730b00533801b30b30c30d30e04732e00526c04703130f", + "0x32e00501b33001b01b32e00530a0052fc01b01b32e00501b00701b309005", + "0x21801b01b32e00508600521601b30408600732e00530500521401b305005", + "0x32e00508400522201b08400532e00530300521c01b30300532e005304005", + "0x31e01b30d00532e00530d00531f01b30e00532e00530e00504601b302005", + "0x30230c30d30e04700530200532e00530200503701b30c00532e00530c005", + "0x32e00530e00504601b30100532e00530900532001b01b32e00501b00701b", + "0x3701b30c00532e00530c00531e01b30d00532e00530d00531f01b30e005", + "0x21601b01b32e00501b00701b30130c30d30e04700530100532e005301005", + "0x1b01b32e00503100506b01b01b32e00504700532901b01b32e00526c005", + "0x532e00530000502a01b30000532e00501b22901b08200532e00501b330", + "0x70c901b07d00532e00501b32601b2ff00532e00530008200703101b300", + "0x32e00507a00504601b33800532e00508700532001b08700532e0052ff07d", + "0x3701b00700532e00500700531e01b07400532e00507400531f01b07a005", + "0x5401b01b32e00501b00701b33800707407a04700533800532e005338005", + "0x1b01b32e00504700532901b01b32e00503300519101b01b32e005006005", + "0x2fb00532e00501b07101b2fc00532e00501b33001b01b32e00503100506b", + "0x1b32601b2fa00532e0052fb2fc00703101b2fb00532e0052fb00502a01b", + "0x532e0052f800532001b2f800532e0052fa2f90070c901b2f900532e005", + "0x531e01b24900532e00524900531f01b23a00532e00523a00504601b2f7", + "0x1b2f700724923a0470052f700532e0052f700503701b00700532e005007", + "0x19101b01b32e00520300505401b01b32e00501b02001b01b32e00501b007", + "0x1b01b32e0050460052ee01b01b32e00503100506b01b01b32e005038005", + "0x532e0052f500502a01b2f500532e00501b05101b2f600532e00501b330", + "0x70c901b2f300532e00501b32601b2f400532e0052f52f600703101b2f5", + "0x32e00502a00504601b2f100532e0052f200532001b2f200532e0052f42f3", + "0x3701b00700532e00500700531e01b04200532e00504200531f01b02a005", + "0x2ee01b01b32e00501b00701b2f100704202a0470052f100532e0052f1005", + "0x2ef00532e00532600504601b01b32e00532b00519101b01b32e005046005", + "0x1b01b32e00502d00505401b01b32e00501b00701b01b48100501b19401b", + "0x1b32e0050440052ee01b01b32e00532b00519101b01b32e0050460052ee", + "0x532e00501b33001b01b32e00501b02001b2ef00532e00504300504601b", + "0x7c00703101b08b00532e00508b00502a01b08b00532e00501b05201b07c", + "0x532e00508d2ed0070c901b2ed00532e00501b32601b08d00532e00508b", + "0x531f01b2ef00532e0052ef00504601b2ec00532e00509000532001b090", + "0x532e0052ec00503701b00700532e00500700531e01b04200532e005042", + "0x1b32e0050460052ee01b01b32e00501b00701b2ec0070422ef0470052ec", + "0x532e00501b33001b01b32e0050440052ee01b01b32e00504800505501b", + "0x8e00703101b2eb00532e0052eb00502a01b2eb00532e00501b22901b08e", + "0x532e0052ea2e80070c901b2e800532e00501b32601b2ea00532e0052eb", + "0x531f01b04100532e00504100504601b09900532e0052e700532001b2e7", + "0x532e00509900503701b00700532e00500700531e01b04000532e005040", + "0x32e00700501b00700501b01b32e00501b01b01b099007040041047005099", + "0x532e00504800504801b01b32e00501b00701b044045007482046047007", + "0x704300504501b04700532e00504700504601b01b32e00501b04701b043", + "0x532e00504100504401b01b32e00501b00701b04000548304104200732e", + "0x504101b03e00532e00503f00504201b03f00532e00519400504301b194", + "0x1b01b48400501b19401b07b00532e00503e00504001b02300532e005042", + "0x19100532e00502000503e01b02000532e00501b03f01b01b32e00501b007", + "0x7b00502301b07b00532e00519100504001b02300532e00504000504101b", + "0x1b32e00532b00532901b01b32e00501b00701b00900548532b00532e007", + "0x4401b01b32e00501b00701b02d00548633032900732e00702300504501b", + "0x32e00503100504201b03100532e00502a00504301b02a00532e005330005", + "0x19401b32000532e00532600504001b0c900532e00532900504101b326005", + "0x503e01b31f00532e00501b03f01b01b32e00501b00701b01b48700501b", + "0x532e00531e00504001b0c900532e00502d00504101b31e00532e00531f", + "0x4501b01b32e00501b00701b03900548803700532e00732000502301b320", + "0x501b02001b01b32e00501b00701b31c00548903603800732e0070c9005", + "0x3700532901b01b32e00503600532b01b01b32e00503800519101b01b32e", + "0x502a01b20300532e00501b02d01b1fb00532e00501b33001b01b32e005", + "0x532e00501b32601b20700532e0052031fb00703101b20300532e005203", + "0x4601b21400532e00521100532001b21100532e00520720d0070c901b20d", + "0x32e00500700531e01b04600532e00504600531f01b04700532e005047005", + "0x501b00701b21400704604704700521400532e00521400503701b007005", + "0x32e00501b03901b01b32e00531c00519101b01b32e00501b02001b01b32e", + "0x21800732e00721604604704803601b21600532e00521600503801b216005", + "0x3101b04c00532e00501b33001b01b32e00501b00701b22822200748a21c", + "0x5400521601b05105400732e00522900521401b22900532e00503704c007", + "0x1b05500532e00505200521c01b05200532e00505100521801b01b32e005", + "0x521c00531f01b21800532e00521800504601b23100532e005055005222", + "0x523100532e00523100503701b00700532e00500700531e01b21c00532e", + "0x33001b01b32e00503700532901b01b32e00501b00701b23100721c218047", + "0x23400532e00523400502a01b23400532e00501b22901b23200532e00501b", + "0x590070c901b05900532e00501b32601b05700532e00523423200703101b", + "0x532e00522200504601b05600532e00505800532001b05800532e005057", + "0x503701b00700532e00500700531e01b22800532e00522800531f01b222", + "0x1b02001b01b32e00501b00701b05600722822204700505600532e005056", + "0x1b33001b01b32e0050c900519101b01b32e00503900505401b01b32e005", + "0x1b24900532e00524900502a01b24900532e00501b05101b23a00532e005", + "0x3305f0070c901b05f00532e00501b32601b03300532e00524923a007031", + "0x4700532e00504700504601b06200532e00525400532001b25400532e005", + "0x6200503701b00700532e00500700531e01b04600532e00504600531f01b", + "0x501b02001b01b32e00501b00701b06200704604704700506200532e005", + "0x501b33001b01b32e00502300519101b01b32e00500900505401b01b32e", + "0x3101b26c00532e00526c00502a01b26c00532e00501b05201b06100532e", + "0x50060690070c901b06900532e00501b32601b00600532e00526c061007", + "0x1b04700532e00504700504601b2d300532e00506b00532001b06b00532e", + "0x52d300503701b00700532e00500700531e01b04600532e00504600531f", + "0x504800505501b01b32e00501b00701b2d30070460470470052d300532e", + "0x6f00502a01b06f00532e00501b22901b06e00532e00501b33001b01b32e", + "0x2ee00532e00501b32601b07100532e00506f06e00703101b06f00532e005", + "0x504601b07600532e00503400532001b03400532e0050712ee0070c901b", + "0x532e00500700531e01b04400532e00504400531f01b04500532e005045", + "0x32e00501b01b01b07600704404504700507600532e00507600503701b007", + "0x32e00501b00701b04404500748b04604700732e00700501b00700501b01b", + "0x504700504601b01b32e00501b04701b04300532e00504800504801b01b", + "0x32e00501b00701b04000548c04104200732e00704300504501b04700532e", + "0x504201b03f00532e00519400504301b19400532e00504100504401b01b", + "0x532e00503e00504001b02300532e00504200504101b03e00532e00503f", + "0x2000532e00501b03f01b01b32e00501b00701b01b48d00501b19401b07b", + "0x19100504001b02300532e00504000504101b19100532e00502000503e01b", + "0x32e00501b00701b00900548e32b00532e00707b00502301b07b00532e005", + "0x2d00548f33032900732e00702300504501b01b32e00532b00532901b01b", + "0x32e00502a00504301b02a00532e00533000504401b01b32e00501b00701b", + "0x4001b0c900532e00532900504101b32600532e00503100504201b031005", + "0x3f01b01b32e00501b00701b01b49000501b19401b32000532e005326005", + "0x532e00502d00504101b31e00532e00531f00503e01b31f00532e00501b", + "0x3900549103700532e00732000502301b32000532e00531e00504001b0c9", + "0x1b31c00549203603800732e00703704700707b01b01b32e00501b00701b", + "0x732e0070c900504501b03800532e00503800504601b01b32e00501b007", + "0x1b20d00532e00520300504401b01b32e00501b00701b2070054932031fb", + "0x51fb00504101b21400532e00521100504201b21100532e00520d005043", + "0x1b00701b01b49400501b19401b21800532e00521400504001b21600532e", + "0x4101b22200532e00521c00503e01b21c00532e00501b03f01b01b32e005", + "0x32e00721800502301b21800532e00522200504001b21600532e005207005", + "0x5422900732e00721600504501b01b32e00501b00701b04c005495228005", + "0x522900519101b01b32e00501b02001b01b32e00501b00701b051005496", + "0x3600500901b01b32e00522800532901b01b32e00505400532b01b01b32e", + "0x502a01b05500532e00501b02d01b05200532e00501b33001b01b32e005", + "0x532e00501b32601b23100532e00505505200703101b05500532e005055", + "0x4601b05700532e00523400532001b23400532e0052312320070c901b232", + "0x32e00500700531e01b04600532e00504600531f01b03800532e005038005", + "0x501b00701b05700704603804700505700532e00505700503701b007005", + "0x5900503801b05900532e00501b03901b01b32e00505100519101b01b32e", + "0x1b24923a00749705605800732e00705904603804803601b05900532e005", + "0x2d201b03300532e00501b31c01b01b32e00501b02001b01b32e00501b007", + "0x505800504601b03300532e00503300520701b05f22800732e005228005", + "0x26c06104849806225400732e00705f03603300705604620d01b05800532e", + "0x522806900703101b06900532e00501b33001b01b32e00501b00701b006", + "0x1b01b32e0052d300521601b06e2d300732e00506b00521401b06b00532e", + "0x507100522201b07100532e00506f00521c01b06f00532e00506e005218", + "0x1b25400532e00525400531f01b05800532e00505800504601b2ee00532e", + "0x622540580470052ee00532e0052ee00503701b06200532e00506200531e", + "0x532e00501b32601b01b32e00522800532901b01b32e00501b00701b2ee", + "0x4601b31100532e00507600532001b07600532e0050060340070c901b034", + "0x32e00526c00531e01b06100532e00506100531f01b05800532e005058005", + "0x501b00701b31126c06105804700531100532e00531100503701b26c005", + "0x503600500901b01b32e00522800532901b01b32e00501b02001b01b32e", + "0x7200502a01b07200532e00501b22901b07300532e00501b33001b01b32e", + "0x7400532e00501b32601b07a00532e00507207300703101b07200532e005", + "0x504601b30e00532e00530f00532001b30f00532e00507a0740070c901b", + "0x532e00500700531e01b24900532e00524900531f01b23a00532e00523a", + "0x32e00501b00701b30e00724923a04700530e00532e00530e00503701b007", + "0x32e00521600519101b01b32e00504c00505401b01b32e00501b02001b01b", + "0x32e00501b07101b30d00532e00501b33001b01b32e00503600500901b01b", + "0x1b30b00532e00530c30d00703101b30c00532e00530c00502a01b30c005", + "0x530900532001b30900532e00530b30a0070c901b30a00532e00501b326", + "0x1b04600532e00504600531f01b03800532e00503800504601b30500532e", + "0x704603804700530500532e00530500503701b00700532e00500700531e", + "0x32e00531c00504601b01b32e0050c900519101b01b32e00501b00701b305", + "0x32e00503900505401b01b32e00501b00701b01b49900501b19401b086005", + "0x501b02001b08600532e00504700504601b01b32e0050c900519101b01b", + "0x30300502a01b30300532e00501b05101b30400532e00501b33001b01b32e", + "0x30200532e00501b32601b08400532e00530330400703101b30300532e005", + "0x504601b08200532e00530100532001b30100532e0050843020070c901b", + "0x532e00500700531e01b04600532e00504600531f01b08600532e005086", + "0x32e00501b00701b08200704608604700508200532e00508200503701b007", + "0x32e00502300519101b01b32e00500900505401b01b32e00501b02001b01b", + "0x52ff00502a01b2ff00532e00501b05201b30000532e00501b33001b01b", + "0x1b08700532e00501b32601b07d00532e0052ff30000703101b2ff00532e", + "0x4700504601b2fc00532e00533800532001b33800532e00507d0870070c9", + "0x700532e00500700531e01b04600532e00504600531f01b04700532e005", + "0x1b32e00501b00701b2fc0070460470470052fc00532e0052fc00503701b", + "0x532e00501b22901b2fb00532e00501b33001b01b32e00504800505501b", + "0x32601b2f900532e0052fa2fb00703101b2fa00532e0052fa00502a01b2fa", + "0x32e0052f700532001b2f700532e0052f92f80070c901b2f800532e00501b", + "0x31e01b04400532e00504400531f01b04500532e00504500504601b2f6005", + "0x2f60070440450470052f600532e0052f600503701b00700532e005007005", + "0x4404500749a04604700732e00700501b00700501b01b32e00501b01b01b", + "0x1b32e00501b04701b04300532e00504800504801b01b32e00501b00701b", + "0x4000549b04104200732e00704300504501b04700532e00504700504601b", + "0x32e00519400504301b19400532e00504100504401b01b32e00501b00701b", + "0x4001b02300532e00504200504101b03e00532e00503f00504201b03f005", + "0x3f01b01b32e00501b00701b01b49c00501b19401b07b00532e00503e005", + "0x532e00504000504101b19100532e00502000503e01b02000532e00501b", + "0x900549d32b00532e00707b00502301b07b00532e00519100504001b023", + "0x701b02d00549e33032900732e00702300504501b01b32e00501b00701b", + "0x3100532e00502a00504301b02a00532e00533000504401b01b32e00501b", + "0x32600504001b0c900532e00532900504101b32600532e00503100504201b", + "0x501b03f01b01b32e00501b00701b01b49f00501b19401b32000532e005", + "0x1b0c900532e00502d00504101b31e00532e00531f00503e01b31f00532e", + "0x701b0390054a003700532e00732000502301b32000532e00531e005040", + "0x501b00701b31c0054a103603800732e0070c900504501b01b32e00501b", + "0x503600532b01b01b32e00503800519101b01b32e00501b02001b01b32e", + "0x501b33001b01b32e00532b00532901b01b32e00503700532901b01b32e", + "0x3101b20300532e00520300502a01b20300532e00501b02d01b1fb00532e", + "0x520720d0070c901b20d00532e00501b32601b20700532e0052031fb007", + "0x1b04700532e00504700504601b21400532e00521100532001b21100532e", + "0x521400503701b00700532e00500700531e01b04600532e00504600531f", + "0x531c00519101b01b32e00501b00701b21400704604704700521400532e", + "0x4803601b21600532e00521600503801b21600532e00501b03901b01b32e", + "0x2ae01b01b32e00501b00701b2282220074a221c21800732e007216046047", + "0x732e00532b0052d201b22900532e00504c0052b001b04c00532e00501b", + "0x20701b05200532e00501b31c01b05100532e0050370540072ab01b05432b", + "0x32e00505100502a01b22900532e0052290052aa01b05200532e005052005", + "0x32e00705122905200721c04620d01b21800532e00521800504601b051005", + "0x1b32e00501b02001b01b32e00501b00701b0572342320484a3231055007", + "0x5800521401b05800532e00532b05900703101b05900532e00501b33001b", + "0x24900532e00523a00521801b01b32e00505600521601b23a05600732e005", + "0x21800504601b05f00532e00503300522201b03300532e00524900521c01b", + "0x23100532e00523100531e01b05500532e00505500531f01b21800532e005", + "0x1b32e00501b00701b05f23105521804700505f00532e00505f00503701b", + "0x25400532e00501b32601b01b32e00532b00532901b01b32e00501b02001b", + "0x504601b06100532e00506200532001b06200532e0050572540070c901b", + "0x532e00523400531e01b23200532e00523200531f01b21800532e005218", + "0x32e00501b00701b06123423221804700506100532e00506100503701b234", + "0x32e00532b00532901b01b32e00503700532901b01b32e00501b02001b01b", + "0x500600502a01b00600532e00501b22901b26c00532e00501b33001b01b", + "0x1b06b00532e00501b32601b06900532e00500626c00703101b00600532e", + "0x22200504601b06e00532e0052d300532001b2d300532e00506906b0070c9", + "0x700532e00500700531e01b22800532e00522800531f01b22200532e005", + "0x1b32e00501b00701b06e00722822204700506e00532e00506e00503701b", + "0x1b32e0050c900519101b01b32e00503900505401b01b32e00501b02001b", + "0x532e00501b05101b06f00532e00501b33001b01b32e00532b00532901b", + "0x32601b2ee00532e00507106f00703101b07100532e00507100502a01b071", + "0x32e00507600532001b07600532e0052ee0340070c901b03400532e00501b", + "0x31e01b04600532e00504600531f01b04700532e00504700504601b311005", + "0x31100704604704700531100532e00531100503701b00700532e005007005", + "0x1b01b32e00500900505401b01b32e00501b02001b01b32e00501b00701b", + "0x7200532e00501b05201b07300532e00501b33001b01b32e005023005191", + "0x1b32601b07a00532e00507207300703101b07200532e00507200502a01b", + "0x532e00530f00532001b30f00532e00507a0740070c901b07400532e005", + "0x531e01b04600532e00504600531f01b04700532e00504700504601b30e", + "0x1b30e00704604704700530e00532e00530e00503701b00700532e005007", + "0x1b30d00532e00501b33001b01b32e00504800505501b01b32e00501b007", + "0x530c30d00703101b30c00532e00530c00502a01b30c00532e00501b229", + "0x1b30900532e00530b30a0070c901b30a00532e00501b32601b30b00532e", + "0x504400531f01b04500532e00504500504601b30500532e005309005320", + "0x530500532e00530500503701b00700532e00500700531e01b04400532e", + "0x4600732e00700501b00700501b01b32e00501b02001b305007044045047", + "0x4204700732e0050470052d201b01b32e00501b00701b0430440074a4045", + "0x701b0410054a501b32e0070420052dd01b04600532e00504600504601b", + "0x1b04000532e0050480050dc01b01b32e00504700532901b01b32e00501b", + "0x4600504601b03f00532e0051940052a601b19400532e0050400070072a8", + "0x3f00532e00503f0052a501b04500532e00504500531f01b04600532e005", + "0x4801b01b32e0050410052da01b01b32e00501b00701b03f045046048005", + "0x2300732e00703e00504501b01b32e00501b04701b03e00532e005007005", + "0x4301b19100532e00507b00504401b01b32e00501b00701b0200054a607b", + "0x32e00502300504101b00900532e00532b00504201b32b00532e005191005", + "0x501b00701b01b4a700501b19401b33000532e00500900504001b329005", + "0x504101b02a00532e00502d00503e01b02d00532e00501b03f01b01b32e", + "0x532e00532900521801b33000532e00502a00504001b32900532e005020", + "0x2001b01b32e00501b00701b0c90054a832600532e00733000502301b031", + "0x31f00532e00501b23401b32000532e00532604800703101b01b32e00501b", + "0x531f01b04600532e00504600504601b31e00532e00531f04700735801b", + "0x532e00532000522801b03100532e00503100506201b04500532e005045", + "0x4832e00531e32003104504604606101b31e00532e00531e00502a01b320", + "0x1b32e00501b02001b01b32e00501b00701b038039037048005038039037", + "0x32e0050c90052d301b01b32e00504800521601b01b32e00504700532901b", + "0x1b1fb00532e00531c0052a601b31c00532e0050360310072a801b036005", + "0x51fb0052a501b04500532e00504500531f01b04600532e005046005046", + "0x32e00504700532901b01b32e00501b00701b1fb0450460480051fb00532e", + "0x32e00501b33001b01b32e00500700505501b01b32e00504800521601b01b", + "0x703101b20700532e00520700502a01b20700532e00501b22901b203005", + "0x32e00520d2110070c901b21100532e00501b32601b20d00532e005207203", + "0x31f01b04400532e00504400504601b21600532e0052140050e001b214005", + "0x1b21604304404800521600532e0052160052a501b04300532e005043005", + "0x1b0440450074a904604700732e00700501b00700501b01b32e00501b020", + "0x1b01b32e00501b04701b04300532e00504800504801b01b32e00501b007", + "0x1b0400054aa04104200732e00704300504501b04700532e005047005046", + "0x532e00504200504101b19400532e00504100524901b01b32e00501b007", + "0x32e00501b00701b01b4ab00501b19401b03e00532e00519400503301b03f", + "0x4000504101b07b00532e00502300505f01b02300532e00501b03f01b01b", + "0x2000532e00703e00525401b03e00532e00507b00503301b03f00532e005", + "0x502000504401b01b32e00501b02001b01b32e00501b00701b1910054ac", + "0x1b00900532e00500900502a01b00900532e00532b00504301b32b00532e", + "0x4700504601b33000532e00503f00521801b32900532e005009007007031", + "0x32900532e00532900522801b04600532e00504600531f01b04700532e005", + "0x2a02d04832e00533032904604704730d01b33000532e00533000506201b", + "0x5401b01b32e00501b02001b01b32e00501b00701b03102a02d048005031", + "0x1b32600532e00501b03f01b01b32e00503f00519101b01b32e005191005", + "0x4700504601b32000532e0050c90052a101b0c900532e0053260070072a3", + "0x32000532e0053200050e101b04600532e00504600531f01b04700532e005", + "0x21601b01b32e00504800505501b01b32e00501b00701b320046047048005", + "0x1b31e00532e00501b22901b31f00532e00501b33001b01b32e005007005", + "0x501b32601b03700532e00531e31f00703101b31e00532e00531e00502a", + "0x3600532e0050380052a001b03800532e0050370390070c901b03900532e", + "0x360050e101b04400532e00504400531f01b04500532e00504500504601b", + "0x501b00700501b01b32e00501b02001b03604404504800503600532e005", + "0x500700504801b01b32e00501b00701b0440450074ad04604700732e007", + "0x504501b04700532e00504700504601b01b32e00501b04701b04300532e", + "0x504100524901b01b32e00501b00701b0400054ae04104200732e007043", + "0x1b03e00532e00519400503301b03f00532e00504200504101b19400532e", + "0x5f01b02300532e00501b03f01b01b32e00501b00701b01b4af00501b194", + "0x32e00507b00503301b03f00532e00504000504101b07b00532e005023005", + "0x1b01b32e00501b00701b1910054b002000532e00703e00525401b03e005", + "0x532e00532b00504301b32b00532e00502000504401b01b32e00501b020", + "0x21801b32900532e00500904800703101b00900532e00500900502a01b009", + "0x32e00504600531f01b04700532e00504700504601b33000532e00503f005", + "0x8601b32900532e00532900522801b33000532e00533000506201b046005", + "0x501b00701b03102a02d04800503102a02d04832e005329330046047047", + "0x503f00519101b01b32e00519100505401b01b32e00501b02001b01b32e", + "0x2a101b0c900532e0053260480072a301b32600532e00501b03f01b01b32e", + "0x32e00504600531f01b04700532e00504700504601b32000532e0050c9005", + "0x32e00501b00701b32004604704800532000532e0053200050e101b046005", + "0x32e00501b33001b01b32e00500700505501b01b32e00504800521601b01b", + "0x703101b31e00532e00531e00502a01b31e00532e00501b22901b31f005", + "0x32e0050370390070c901b03900532e00501b32601b03700532e00531e31f", + "0x31f01b04500532e00504500504601b03600532e0050380052a001b038005", + "0x1b03604404504800503600532e0050360050e101b04400532e005044005", + "0x4500532e00501b23201b04600532e00501b33001b01b32e0050480052ea", + "0x521401b04400532e00504504600703101b04500532e00504500502a01b", + "0x532e00504200521801b01b32e00504300521601b04204300732e005044", + "0x29d01b04004100732e00504100529d01b04100532e00504100506201b041", + "0x4b103e03f00732e00719404000700504729c01b19404100732e005041005", + "0x2e201b03f00532e00503f00531f01b01b32e00501b00701b02007b023048", + "0x1b32e00501b00701b3303290090484b232b19100732e00704703e03f048", + "0x502d00502a01b19100532e00519100531f01b02d00532e00501b29b01b", + "0x3200c93260484b303102a00732e00704102d32b1910470a401b02d00532e", + "0x532e00531f0052b001b31f00532e00501b2ae01b01b32e00501b00701b", + "0x502a00531f01b03900532e00501b31c01b03700532e00501b29b01b31e", + "0x1b31e00532e00531e0052aa01b03900532e00503900520701b02a00532e", + "0x3603800732e00703731e03903102a04620d01b03700532e00503700502a", + "0x29a01b20700532e00501b33001b01b32e00501b00701b2031fb31c0484b4", + "0x32e00520d20700703101b20d00532e00520d00502a01b20d00532e00501b", + "0x703101b21400532e00521400502a01b21400532e00501b23201b211005", + "0x532e00521800502a01b21800532e00501b29901b21600532e005214211", + "0x502a01b22200532e00501b29801b21c00532e00521821600703101b218", + "0x532e00501b32601b22800532e00522221c00703101b22200532e005222", + "0x4601b05400532e00522900529501b22900532e00522804c0070c901b04c", + "0x32e00503600531e01b03800532e00503800531f01b01b00532e00501b005", + "0x501b00701b05403603801b04700505400532e0050540050eb01b036005", + "0x29501b05200532e0052030510070c901b05100532e00501b32601b01b32e", + "0x32e00531c00531f01b01b00532e00501b00504601b05500532e005052005", + "0x4700505500532e0050550050eb01b1fb00532e0051fb00531e01b31c005", + "0x70c901b23100532e00501b32601b01b32e00501b00701b0551fb31c01b", + "0x32e00501b00504601b23400532e00523200529501b23200532e005320231", + "0xeb01b0c900532e0050c900531e01b32600532e00532600531f01b01b005", + "0x5501b01b32e00501b00701b2340c932601b04700523400532e005234005", + "0x532e0053300570070c901b05700532e00501b32601b01b32e005041005", + "0x531f01b01b00532e00501b00504601b05800532e00505900529501b059", + "0x532e0050580050eb01b32900532e00532900531e01b00900532e005009", + "0x1b32e00504100505501b01b32e00501b00701b05832900901b047005058", + "0x50200560070c901b05600532e00501b32601b01b32e00504700530001b", + "0x1b01b00532e00501b00504601b24900532e00523a00529501b23a00532e", + "0x52490050eb01b07b00532e00507b00531e01b02300532e00502300531f", + "0x501b00700501b01b32e00501b02001b24907b02301b04700524900532e", + "0x50460050ed01b01b32e00501b00701b0410420074b504304400732e007", + "0x4800732e0050480050ed01b19400532e00504000529401b04004600732e", + "0x1b01b4b601b32e00719403f00729301b04400532e00504400504601b03f", + "0x32e00503e00521801b03e04500732e00504500530a01b01b32e00501b007", + "0x1b02000532e00507b00521801b07b04700732e00504700530a01b023005", + "0x501b00701b3303290090484b732b19100732e00702002300704304729c", + "0x531f01b02d00532e00502d0052f701b02d00532e00501b29201b01b32e", + "0x702d0480440480ef01b32b00532e00532b00531e01b19100532e005191", + "0x32e00502a00504601b01b32e00501b00701b0c93260074b803102a00732e", + "0x2f701b32b00532e00532b00531e01b19100532e00519100531f01b02a005", + "0x32e0050460052f701b04700532e00504700504101b03100532e005031005", + "0x4504604703132b19102a0442f601b04500532e00504500504101b046005", + "0x1b01b32e00501b00701b03731e31f32004700503731e31f32004732e005", + "0x1b32e0050460052fa01b01b32e00504500519101b01b32e0050c90052fa", + "0x532e00501b0f101b03900532e00501b33001b01b32e00504700519101b", + "0x32601b03600532e00503803900703101b03800532e00503800502a01b038", + "0x32e0051fb0050f001b1fb00532e00503631c0070c901b31c00532e00501b", + "0x31e01b19100532e00519100531f01b32600532e00532600504601b203005", + "0x20332b19132604700520300532e0052030050ee01b32b00532e00532b005", + "0x1b32e0050460052fa01b01b32e00504500519101b01b32e00501b00701b", + "0x532e00501b32601b01b32e0050480052fa01b01b32e00504700519101b", + "0x4601b21100532e00520d0050f001b20d00532e0053302070070c901b207", + "0x32e00532900531e01b00900532e00500900531f01b04400532e005044005", + "0x501b00701b21132900904404700521100532e0052110050ee01b329005", + "0x4700519101b01b32e0050460052fa01b01b32e00504500519101b01b32e", + "0x1b21600532e00521404800729101b21400532e00501b03f01b01b32e005", + "0x504300531f01b04400532e00504400504601b21800532e005216005290", + "0x521800532e0052180050ee01b00700532e00500700531e01b04300532e", + "0x2fa01b01b32e00504500519101b01b32e00501b00701b218007043044047", + "0x1b01b32e0050480052fa01b01b32e00504700519101b01b32e005046005", + "0x532e00522200502a01b22200532e00501b22901b21c00532e00501b330", + "0x70c901b04c00532e00501b32601b22800532e00522221c00703101b222", + "0x32e00504200504601b05400532e0052290050f001b22900532e00522804c", + "0xee01b00700532e00500700531e01b04100532e00504100531f01b042005", + "0x700532e00500500504801b05400704104204700505400532e005054005", + "0x24901b01b32e00501b00701b0460054b904704800732e00700700504501b", + "0x32e00504500503301b04400532e00504800504101b04500532e005047005", + "0x532e00501b03f01b01b32e00501b00701b01b4ba00501b19401b043005", + "0x503301b04400532e00504600504101b04100532e00504200505f01b042", + "0x32e00504000521801b04004400732e00504400530a01b04300532e005041", + "0x1b01b32e00501b00701b03e0054bb03f00532e00704300525401b194005", + "0x507b00502a01b07b00532e00502300504301b02300532e00503f005044", + "0x501b00701b32b0054bc19102000732e00707b01b0072fb01b07b00532e", + "0x504501b02000532e00502000504601b01b32e00519400505501b01b32e", + "0x532900524901b01b32e00501b00701b3300054bd32900900732e007044", + "0x1b03100532e00502d00503301b02a00532e00500900504101b02d00532e", + "0x5f01b32600532e00501b03f01b01b32e00501b00701b01b4be00501b194", + "0x32e0050c900503301b02a00532e00533000504101b0c900532e005326005", + "0x1b31f00532e00532000521801b32002a00732e00502a00530a01b031005", + "0x31e00504401b01b32e00501b00701b0370054bf31e00532e007031005254", + "0x3800532e00503800502a01b03800532e00503900504301b03900532e005", + "0x1b01b32e00501b00701b1fb0054c031c03600732e0070380200072fb01b", + "0x32e00702a00504501b03600532e00503600504601b01b32e00531f005055", + "0x21100532e00520700504401b01b32e00501b00701b20d0054c1207203007", + "0x20300504101b21600532e00521400504201b21400532e00521100504301b", + "0x701b01b4c200501b19401b21c00532e00521600504001b21800532e005", + "0x1b22800532e00522200503e01b22200532e00501b03f01b01b32e00501b", + "0x521800521801b21c00532e00522800504001b21800532e00520d005041", + "0x1b32e00501b00701b0540054c322900532e00721c00502301b04c00532e", + "0x1b01b32e00501b00701b0550054c405205100732e00722903600723a01b", + "0x504601b23200532e0052310050f901b23100532e00505231c1910480f7", + "0x532e0052320050f801b04c00532e00504c00506201b05100532e005051", + "0x1b01b32e0051910052fa01b01b32e00501b00701b23204c051048005232", + "0x1b4c500501b19401b23400532e00505500504601b01b32e00531c0052fa", + "0x1b32e0051910052fa01b01b32e00505400505401b01b32e00501b00701b", + "0x32e00501b03f01b23400532e00503600504601b01b32e00531c0052fa01b", + "0xf801b04c00532e00504c00506201b05900532e0050570050f601b057005", + "0x52fa01b01b32e00501b00701b05904c23404800505900532e005059005", + "0x1b05800532e0051fb00504601b01b32e00502a00519101b01b32e005191", + "0x2fa01b01b32e00503700505401b01b32e00501b00701b01b4c600501b194", + "0x5800532e00502000504601b01b32e00502a00519101b01b32e005191005", + "0x531f00506201b23a00532e0050560050f601b05600532e00501b03f01b", + "0x501b00701b23a31f05804800523a00532e00523a0050f801b31f00532e", + "0x1b19401b24900532e00532b00504601b01b32e00504400519101b01b32e", + "0x4400519101b01b32e00503e00505401b01b32e00501b00701b01b4c7005", + "0xf601b03300532e00501b03f01b24900532e00501b00504601b01b32e005", + "0x32e00505f0050f801b19400532e00519400506201b05f00532e005033005", + "0x532e00501b05901b04700532e00501b05901b05f19424904800505f005", + "0x32e00501b05901b04100532e00501b05901b04300532e00501b05901b045", + "0x501b05801b07b00532e00501b05901b03e00532e00501b07601b194005", + "0x2000504501b02000532e00500700504801b01b32e00501b02001b01b32e", + "0x32e00532b00504401b01b32e00501b00701b0090054c832b19100732e007", + "0x4101b02d00532e00533000504201b33000532e00532900504301b329005", + "0x1b4c900501b19401b03100532e00502d00504001b02a00532e005191005", + "0x532e00532600503e01b32600532e00501b03f01b01b32e00501b00701b", + "0x502301b03100532e0050c900504001b02a00532e00500900504101b0c9", + "0x504204100705601b01b32e00501b00701b3200054ca04200532e007031", + "0x32e00501b00701b0370054cb31e31f00732e00702a00504501b04200532e", + "0x504201b03800532e00503900504301b03900532e00531e00504401b01b", + "0x532e00503600504001b31c00532e00531f00504101b03600532e005038", + "0x20300532e00501b03f01b01b32e00501b00701b01b4cc00501b19401b1fb", + "0x20700504001b31c00532e00503700504101b20700532e00520300503e01b", + "0x532e00520d00521801b20d31c00732e00531c00530a01b1fb00532e005", + "0x701b2140054cd04400532e0071fb00502301b01b32e00501b04701b211", + "0x32e00704401b00723a01b04400532e00504404300705601b01b32e00501b", + "0x1b01b32e00521100505501b01b32e00501b00701b21c0054ce218216007", + "0x1b04c0054cf22822200732e00731c00504501b21600532e005216005046", + "0x532e00522200504101b22900532e00522800524901b01b32e00501b007", + "0x32e00501b00701b01b4d000501b19401b05100532e00522900503301b054", + "0x4c00504101b05500532e00505200505f01b05200532e00501b03f01b01b", + "0x23100532e00505400521801b05100532e00505500503301b05400532e005", + "0x504401b01b32e00501b00701b2340054d123200532e00705100525401b", + "0x32e00504800504301b04800532e00504804700705601b04800532e005232", + "0x1b00701b24923a0560484d205805900732e00705721600728f01b057005", + "0x1b23100532e00523100506201b05900532e00505900504601b01b32e005", + "0x620054d325400532e00705f0050ff01b05f03300732e00523105900728e", + "0x726c00510001b26c06100732e00525400510101b01b32e00501b00701b", + "0x6900532e00506100504801b01b32e00501b00701b0060054d403f00532e", + "0x54d52d306b00732e00706900504501b03f00532e00503f03e00730e01b", + "0x506f00504301b06f00532e0052d300504401b01b32e00501b00701b06e", + "0x1b03400532e00506b00504101b2ee00532e00507100504201b07100532e", + "0x1b01b32e00501b00701b01b4d600501b19401b07600532e0052ee005040", + "0x32e00506e00504101b07300532e00531100503e01b31100532e00501b03f", + "0x54d702300532e00707600502301b07600532e00507300504001b034005", + "0x3400504501b02300532e00502307b00705601b01b32e00501b00701b072", + "0x32e00507400504401b01b32e00501b00701b30f0054d807407a00732e007", + "0x4101b30c00532e00530d00504201b30d00532e00530e00504301b30e005", + "0x1b4d900501b19401b30a00532e00530c00504001b30b00532e00507a005", + "0x532e00530900503e01b30900532e00501b03f01b01b32e00501b00701b", + "0x502301b30a00532e00530500504001b30b00532e00530f00504101b305", + "0x504019400705601b01b32e00501b00701b0860054da04000532e00730a", + "0x32e00501b00701b0840054db30330400732e00730b00504501b04000532e", + "0x504201b30100532e00530200504301b30200532e00530300504401b01b", + "0x532e00508200504001b30000532e00530400504101b08200532e005301", + "0x7d00532e00501b03f01b01b32e00501b00701b01b4dc00501b19401b2ff", + "0x8700504001b30000532e00508400504101b08700532e00507d00503e01b", + "0x32e00501b00701b3380054dd04600532e0072ff00502301b2ff00532e005", + "0x4de2fb2fc00732e00730000504501b04600532e00504604500705601b01b", + "0x2fc00504101b2f900532e0052fb00524901b01b32e00501b00701b2fa005", + "0x701b01b4df00501b19401b2f700532e0052f900503301b2f800532e005", + "0x1b2f500532e0052f600505f01b2f600532e00501b03f01b01b32e00501b", + "0x72f700525401b2f700532e0052f500503301b2f800532e0052fa005041", + "0x4401b01b32e00501b02001b01b32e00501b00701b2f30054e02f400532e", + "0x532e0052f800521801b2f100532e00501b0fe01b2f200532e0052f4005", + "0x531f01b03300532e00503300504601b07c00532e0052f200504301b2ef", + "0x532e0052f100528c01b2ef00532e0052ef00506201b00500532e005005", + "0x4832e00507c2f12ef00503304628b01b07c00532e00507c00502a01b2f1", + "0x1b32e00501b00701b2ec0054e109000532e0072ed00510701b2ed08d08b", + "0x2e80054e22ea00532e0072eb00510801b2eb08e00732e00509000510901b", + "0x52e700528a01b0992e700732e0052ea00510601b01b32e00501b00701b", + "0x4801b2e600532e00508500510f01b08500532e00509900511301b01b32e", + "0x32e00508d00531f01b2e300532e00508b00504601b2e400532e00508e005", + "0x19401b0a400532e0052e600510e01b2e200532e0052e400504101b09d005", + "0x4801b0a000532e0052e800528901b01b32e00501b00701b01b4e300501b", + "0x32e00508d00531f01b2e300532e00508b00504601b2e100532e00508e005", + "0x19401b0a400532e0050a000510e01b2e200532e0052e100504101b09d005", + "0x506b01b01b32e00505800511501b01b32e00501b00701b01b4e300501b", + "0x5501b01b32e00504000532901b01b32e00504200532901b01b32e005218", + "0x1b01b32e00504600532901b01b32e00502300532901b01b32e00503f005", + "0x508d00531f01b08b00532e00508b00504601b2df00532e0052ec005117", + "0x501b00701b2df08d08b0480052df00532e0052df00528701b08d00532e", + "0x32e00501b03f01b01b32e0052f300505401b01b32e00501b02001b01b32e", + "0x31f01b2e300532e00503300504601b0aa00532e0050a800528901b0a8005", + "0x32e0050aa00510e01b2e200532e0052f800504101b09d00532e005005005", + "0x1b01b32e00501b00701b0ad0054e42dd00532e0070a400528601b0a4005", + "0x1b00701b2d90054e52da2db00732e0072e200504501b01b32e00501b047", + "0x1b2d700532e0052db00504101b2d800532e0052da00524901b01b32e005", + "0x1b01b32e00501b00701b01b4e600501b19401b0b200532e0052d8005033", + "0x32e0052d900504101b2d500532e0052d600505f01b2d600532e00501b03f", + "0x25401b2d400532e0052d700521801b0b200532e0052d500503301b2d7005", + "0x504a00504401b01b32e00501b00701b3570054e704a00532e0070b2005", + "0x1b35a00532e00535a00502a01b35a00532e00535800504301b35800532e", + "0x1b32e00501b00701b0bb0b80b90484e835b0cf00732e00735a2e300728f", + "0xcf00728e01b2d400532e0052d400506201b0cf00532e0050cf00504601b", + "0x1b00701b32f0054e92d200532e0070c10050ff01b0c10bd00732e0052d4", + "0x2cc00532e00735d00510001b35d2de00732e0052d200510101b01b32e005", + "0x504501b2cb00532e0052de00504801b01b32e00501b00701b0c60054ea", + "0x535f00524901b01b32e00501b00701b2c90054eb35f0c700732e0072cb", + "0x1b2c100532e0052c800503301b2c700532e0050c700504101b2c800532e", + "0x5f01b0cd00532e00501b03f01b01b32e00501b00701b01b4ec00501b194", + "0x32e0052be00503301b2c700532e0052c900504101b2be00532e0050cd005", + "0x1b0c400532e0052bc00521801b2bc2c700732e0052c700530a01b2c1005", + "0x2bf00504401b01b32e00501b00701b0ce0054ed2bf00532e0072c1005254", + "0x2b900532e0052b900502a01b2b900532e0052c600504301b2c600532e005", + "0x1b01b32e00501b00701b0d20054ee2b72b800732e0072b90bd00728501b", + "0x32e0072c700504501b2b800532e0052b800504601b01b32e0050c4005055", + "0x2c300532e0050d400524901b01b32e00501b00701b2c20054ef0d42c5007", + "0x501b19401b2c400532e0052c300503301b0d600532e0052c500504101b", + "0x52b600505f01b2b600532e00501b03f01b01b32e00501b00701b01b4f0", + "0x1b2c400532e0052ae00503301b0d600532e0052c200504101b2ae00532e", + "0x701b2aa0054f12ab00532e0072c400525401b2b000532e0050d6005218", + "0x2a800532e0050dc00504301b0dc00532e0052ab00504401b01b32e00501b", + "0x54f22a52a600732e0072a82b800728501b2a800532e0052a800502a01b", + "0x52b000506201b2a600532e0052a600504601b01b32e00501b00701b0e0", + "0x532e0072a10050ff01b2a12a300732e0052b02a600728e01b2b000532e", + "0x1b29c29d00732e0050e100510101b01b32e00501b00701b2a00054f30e1", + "0x501b02001b01b32e00501b00701b29a0054f429b00532e00729c005100", + "0x32e00529b2a52b72cc35b2dd04604002303f05821804203f28401b01b32e", + "0x1b29500532e00529829d00711c01b29800532e00529900511a01b299005", + "0x509d00531f01b2a300532e0052a300504601b0eb00532e00529500511b", + "0x501b00701b0eb09d2a30480050eb00532e0050eb00528701b09d00532e", + "0x52a500504c01b01b32e00504200532901b01b32e00501b02001b01b32e", + "0x35b00511501b01b32e0052cc00505501b01b32e0052b700504c01b01b32e", + "0x532901b01b32e00504600532901b01b32e0052dd00511901b01b32e005", + "0x11501b01b32e00503f00505501b01b32e00502300532901b01b32e005040", + "0xed00532e00529a00528301b01b32e00521800506b01b01b32e005058005", + "0x504601b29300532e00529400511b01b29400532e0050ed29d00711c01b", + "0x532e00529300528701b09d00532e00509d00531f01b2a300532e0052a3", + "0x6b01b01b32e00501b02001b01b32e00501b00701b29309d2a3048005293", + "0x1b01b32e0052a500504c01b01b32e00504200532901b01b32e005218005", + "0x1b32e00535b00511501b01b32e0052cc00505501b01b32e0052b700504c", + "0x32e00504000532901b01b32e00504600532901b01b32e0052dd00511901b", + "0x505800511501b01b32e00503f00505501b01b32e00502300532901b01b", + "0x31f01b2a300532e0052a300504601b29200532e0052a000511701b01b32e", + "0x1b29209d2a304800529200532e00529200528701b09d00532e00509d005", + "0x1b01b32e00521800506b01b01b32e00505800511501b01b32e00501b007", + "0x1b32e0052cc00505501b01b32e0052b700504c01b01b32e005042005329", + "0x32e00504600532901b01b32e0052dd00511901b01b32e00535b00511501b", + "0x503f00505501b01b32e00502300532901b01b32e00504000532901b01b", + "0x501b00701b01b4f500501b19401b0ef00532e0050e000504601b01b32e", + "0x21800506b01b01b32e00505800511501b01b32e0052aa00505401b01b32e", + "0x505501b01b32e0052b700504c01b01b32e00504200532901b01b32e005", + "0x32901b01b32e0052dd00511901b01b32e00535b00511501b01b32e0052cc", + "0x1b01b32e00502300532901b01b32e00504000532901b01b32e005046005", + "0x1b32e00501b02001b0ef00532e0052b800504601b01b32e00503f005055", + "0xf02b000711c01b0f000532e0050f100528301b0f100532e00501b03f01b", + "0x9d00532e00509d00531f01b29100532e0050ee00511b01b0ee00532e005", + "0x1b01b32e00501b00701b29109d0ef04800529100532e00529100528701b", + "0x1b32e00504200532901b01b32e00521800506b01b01b32e005058005115", + "0x32e0052cc00505501b01b32e00503f00505501b01b32e0052c700519101b", + "0x504600532901b01b32e0052dd00511901b01b32e00535b00511501b01b", + "0xd200504601b01b32e00502300532901b01b32e00504000532901b01b32e", + "0xce00505401b01b32e00501b00701b01b4f600501b19401b29000532e005", + "0x532901b01b32e00521800506b01b01b32e00505800511501b01b32e005", + "0x5501b01b32e00503f00505501b01b32e0052c700519101b01b32e005042", + "0x1b01b32e0052dd00511901b01b32e00535b00511501b01b32e0052cc005", + "0x1b32e00502300532901b01b32e00504000532901b01b32e005046005329", + "0x532e00501b03f01b01b32e00501b02001b29000532e0050bd00504601b", + "0x11b01b0f800532e0050f90c400711c01b0f900532e0050f700528301b0f7", + "0x32e0050f600528701b09d00532e00509d00531f01b0f600532e0050f8005", + "0x1b01b32e00501b02001b01b32e00501b00701b0f609d2900480050f6005", + "0x1b32e00504200532901b01b32e00521800506b01b01b32e005058005115", + "0x32e0052dd00511901b01b32e00535b00511501b01b32e00503f00505501b", + "0x502300532901b01b32e00504000532901b01b32e00504600532901b01b", + "0x1b28e00532e00528f2de00711c01b28f00532e0050c600528301b01b32e", + "0x509d00531f01b0bd00532e0050bd00504601b0ff00532e00528e00511b", + "0x501b00701b0ff09d0bd0480050ff00532e0050ff00528701b09d00532e", + "0x521800506b01b01b32e00505800511501b01b32e00501b02001b01b32e", + "0x2300532901b01b32e00503f00505501b01b32e00504200532901b01b32e", + "0x532901b01b32e0052dd00511901b01b32e00535b00511501b01b32e005", + "0x1b10100532e00532f00511701b01b32e00504000532901b01b32e005046", + "0x510100528701b09d00532e00509d00531f01b0bd00532e0050bd005046", + "0x32e0050b800511501b01b32e00501b00701b10109d0bd04800510100532e", + "0x521800506b01b01b32e00505800511501b01b32e0050bb00511501b01b", + "0x3f00505501b01b32e00504000532901b01b32e00504200532901b01b32e", + "0x532901b01b32e0052dd00511901b01b32e00502300532901b01b32e005", + "0x701b01b4f700501b19401b10000532e0050b900504601b01b32e005046", + "0x6b01b01b32e00505800511501b01b32e00535700505401b01b32e00501b", + "0x1b01b32e00504000532901b01b32e00504200532901b01b32e005218005", + "0x1b32e0052dd00511901b01b32e00502300532901b01b32e00503f005055", + "0x32e00501b02001b10000532e0052e300504601b01b32e00504600532901b", + "0x2d400711c01b28c00532e0050fe00528301b0fe00532e00501b03f01b01b", + "0x532e00509d00531f01b10700532e00528b00511b01b28b00532e00528c", + "0x1b32e00501b00701b10709d10004800510700532e00510700528701b09d", + "0x32e00504200532901b01b32e00521800506b01b01b32e00505800511501b", + "0x502300532901b01b32e00503f00505501b01b32e00504000532901b01b", + "0x528301b10900532e0052e200521801b01b32e00504600532901b01b32e", + "0x32e00510600511b01b10600532e00510810900711c01b10800532e0050ad", + "0x28701b09d00532e00509d00531f01b2e300532e0052e300504601b28a005", + "0x1b02001b01b32e00501b00701b28a09d2e304800528a00532e00528a005", + "0x532901b01b32e00521800506b01b01b32e00505800511501b01b32e005", + "0x32901b01b32e00503f00505501b01b32e00504000532901b01b32e005042", + "0x11300532e00530000521801b01b32e0050450052ee01b01b32e005023005", + "0x511b01b10e00532e00510f11300711c01b10f00532e00533800528301b", + "0x532e00500500531f01b03300532e00503300504601b28900532e00510e", + "0x1b32e00501b00701b28900503304800528900532e00528900528701b005", + "0x1b32e0050450052ee01b01b32e00505800511501b01b32e00501b02001b", + "0x32e00503f00505501b01b32e00504200532901b01b32e00521800506b01b", + "0x530b00521801b01b32e0051940052ee01b01b32e00502300532901b01b", + "0x28700532e00511711500711c01b11700532e00508600528301b11500532e", + "0x500531f01b03300532e00503300504601b28600532e00528700511b01b", + "0x1b00701b28600503304800528600532e00528600528701b00500532e005", + "0x450052ee01b01b32e00505800511501b01b32e00501b02001b01b32e005", + "0x52ee01b01b32e00504200532901b01b32e00521800506b01b01b32e005", + "0x21801b01b32e00507b0052ee01b01b32e00503f00505501b01b32e005194", + "0x528428500711c01b28400532e00507200528301b28500532e005034005", + "0x1b03300532e00503300504601b11c00532e00511a00511b01b11a00532e", + "0x11c00503304800511c00532e00511c00528701b00500532e00500500531f", + "0x1b01b32e00505800511501b01b32e00501b02001b01b32e00501b00701b", + "0x1b32e00504200532901b01b32e00521800506b01b01b32e0050450052ee", + "0x32e00503e00507a01b01b32e00507b0052ee01b01b32e0051940052ee01b", + "0x11b01b11900532e00511b06100711c01b11b00532e00500600528301b01b", + "0x32e00500500531f01b03300532e00503300504601b28300532e005119005", + "0x32e00501b00701b28300503304800528300532e00528300528701b005005", + "0x32e0050450052ee01b01b32e00505800511501b01b32e00501b02001b01b", + "0x51940052ee01b01b32e00504200532901b01b32e00521800506b01b01b", + "0x6200511701b01b32e00507b0052ee01b01b32e00503e00507a01b01b32e", + "0x500532e00500500531f01b03300532e00503300504601b01800532e005", + "0x1b01b32e00501b00701b01800503304800501800532e00501800528701b", + "0x1b32e0050450052ee01b01b32e00524900511501b01b32e00523a005115", + "0x32e0051940052ee01b01b32e00504200532901b01b32e00521800506b01b", + "0x505600504601b01b32e00507b0052ee01b01b32e00503e00507a01b01b", + "0x523400505401b01b32e00501b00701b01b4f800501b19401b12200532e", + "0x4200532901b01b32e00521800506b01b01b32e0050450052ee01b01b32e", + "0x52ee01b01b32e00503e00507a01b01b32e0051940052ee01b01b32e005", + "0x1b12200532e00521600504601b01b32e0050470052ee01b01b32e00507b", + "0x28000532e00512100528301b12100532e00501b03f01b01b32e00501b020", + "0x531f01b27f00532e00504900511b01b04900532e00528023100711c01b", + "0x701b27f00512204800527f00532e00527f00528701b00500532e005005", + "0x19101b01b32e0050450052ee01b01b32e0050470052ee01b01b32e00501b", + "0x1b01b32e0051940052ee01b01b32e00504200532901b01b32e00531c005", + "0x532e00521c00504601b01b32e00507b0052ee01b01b32e00503e00507a", + "0x1b32e00521400505401b01b32e00501b00701b01b4f900501b19401b27e", + "0x32e00531c00519101b01b32e0050450052ee01b01b32e0050470052ee01b", + "0x503e00507a01b01b32e0051940052ee01b01b32e00504200532901b01b", + "0x1b00504601b01b32e0050430052ee01b01b32e00507b0052ee01b01b32e", + "0x528301b12700532e00501b03f01b01b32e00501b02001b27e00532e005", + "0x32e00527c00511b01b27c00532e00512621100711c01b12600532e005127", + "0x4800527b00532e00527b00528701b00500532e00500500531f01b27b005", + "0x450052ee01b01b32e0050470052ee01b01b32e00501b00701b27b00527e", + "0x52ee01b01b32e00503e00507a01b01b32e0051940052ee01b01b32e005", + "0x21801b01b32e0050410052ee01b01b32e0050430052ee01b01b32e00507b", + "0x512e12c00711c01b12e00532e00532000528301b12c00532e00502a005", + "0x1b01b00532e00501b00504601b12b00532e00512d00511b01b12d00532e", + "0x12b00501b04800512b00532e00512b00528701b00500532e00500500531f", + "0x532e00501b05901b19400532e00501b03401b04100532e00501b01801b", + "0x32e00501b05801b19100532e00501b12201b07b00532e00501b01801b03e", + "0x700700500712101b01b32e0050480052ea01b01b32e00501b02001b01b", + "0x900528001b01b32e00501b00701b02d3303290484fa00904032b04832e", + "0x3104632e00502a00527f01b02a00532e00500900504901b00900532e005", + "0xc900532e00503100512701b03100532e00503100527e01b03f023042326", + "0x4700512601b01b32e00532000508e01b31f32000732e0050c900512601b", + "0x31f00532e00531f0052e801b01b32e00531e00508e01b03731e00732e005", + "0x1b31c03603804832e00503900527b01b03931f00732e00531f00527c01b", + "0x532e00503800529401b01b32e00531c00506b01b01b32e0050360052fa", + "0x21120d20704832e00520300527b01b20303700732e00503700527c01b1fb", + "0x32e00520700529401b01b32e00521100506b01b01b32e00520d0052fa01b", + "0x19400730f01b32b00532e00532b00531f01b01b32e00501b04701b214005", + "0x32e00504204100712e01b32600532e00532600512c01b04000532e005040", + "0x3f00532e00503f03e00705601b02300532e00502307b00712e01b042005", + "0x3f00532901b01b32e00501b00701b01b4fb01b32e0072141fb00729301b", + "0x532901b01b32e00502300506b01b01b32e00504300532901b01b32e005", + "0x6b01b01b32e00504500532901b01b32e0050460052ec01b01b32e005044", + "0x1b01b32e00532600512b01b01b32e00519100512d01b01b32e005042005", + "0x1b01b4fc00501b19401b01b32e00531f00508e01b01b32e00503700508e", + "0x32e00521600527b01b21631f00732e00531f00527c01b01b32e00501b007", + "0x29401b01b32e00522200506b01b01b32e0052180052fa01b22221c218048", + "0x504c00527b01b04c03700732e00503700527c01b22800532e00521c005", + "0x1b01b32e00505100506b01b01b32e0052290052fa01b05105422904832e", + "0x1b00701b01b4fd01b32e00705222800729301b05200532e005054005294", + "0x506b01b01b32e00504300532901b01b32e00503f00532901b01b32e005", + "0x32901b01b32e0050460052ec01b01b32e00504400532901b01b32e005023", + "0x1b01b32e00519100512d01b01b32e00504200506b01b01b32e005045005", + "0x1b32e00531f00508e01b01b32e00503700508e01b01b32e00532600512b", + "0x5504832e00531f00527b01b01b32e00501b00701b01b4fe00501b19401b", + "0x23200527a01b01b32e0052310052fa01b01b32e0050550052fa01b232231", + "0x5904832e00503700527b01b05700532e0052340052de01b23400532e005", + "0x5600527a01b01b32e0050580052fa01b01b32e0050590052fa01b056058", + "0x532e00524905700735801b24900532e00523a0052de01b23a00532e005", + "0x1b05f0054ff01b32e0070330052dd01b03300532e00503300502a01b033", + "0x32e00502019100727801b02000532e00532600527901b01b32e00501b007", + "0x13501b01b32e0052540052ec01b06225400732e00502000513501b020005", + "0x32e00506200513401b01b32e0050610052ec01b26c06100732e005046005", + "0x3110760342ee07106f06e2d306b06903f32e00500600527601b006062007", + "0x505501b01b32e0052d300511501b01b32e00506b00506b01b07a072073", + "0x32901b01b32e00507100532901b01b32e00506f00532901b01b32e00506e", + "0x1b01b32e00507600511501b01b32e00503400511901b01b32e0052ee005", + "0x1b32e00507200504c01b01b32e00507300504c01b01b32e005311005055", + "0x526c00513401b07400532e00506900504301b01b32e00507a00505501b", + "0x30408630530930a30b30c30d30e03f32e00530f00527601b30f26c00732e", + "0x5501b01b32e00530c00511501b01b32e00530d00506b01b301302084303", + "0x1b01b32e00530900532901b01b32e00530a00532901b01b32e00530b005", + "0x1b32e00530400511501b01b32e00508600511901b01b32e005305005329", + "0x32e00530200504c01b01b32e00508400504c01b01b32e00530300505501b", + "0x7400735801b08200532e00530e00504301b01b32e00530100505501b01b", + "0x1b32e0073000052dd01b30000532e00530000502a01b30000532e005082", + "0x27601b07d06200732e00506200513401b01b32e00501b00701b2ff005500", + "0x32901b2f22f32f42f52f62f72f82f92fa2fb2fc33808703f32e00507d005", + "0x1b01b32e0052fb00505501b01b32e0052fc00511501b01b32e005087005", + "0x1b32e0052f800532901b01b32e0052f900532901b01b32e0052fa005329", + "0x32e0052f500505501b01b32e0052f600511501b01b32e0052f700511901b", + "0x52f200505501b01b32e0052f300504c01b01b32e0052f400504c01b01b", + "0x13401b2ef00532e0052f10052de01b2f100532e00533800527a01b01b32e", + "0x8e2ec0902ed08d08b03f32e00507c00527601b07c26c00732e00526c005", + "0x32e0052ed00511501b01b32e00508b00532901b2e60850992e72e82ea2eb", + "0x508e00532901b01b32e0052ec00532901b01b32e00509000505501b01b", + "0x2e800511501b01b32e0052ea00511901b01b32e0052eb00532901b01b32e", + "0x504c01b01b32e00509900504c01b01b32e0052e700505501b01b32e005", + "0x1b2e400532e00508d00527a01b01b32e0052e600505501b01b32e005085", + "0x9d00502a01b09d00532e0052e32ef00735801b2e300532e0052e40052de", + "0x1b32e00501b00701b2e200550101b32e00709d0052dd01b09d00532e005", + "0xa82df2e10a003f32e0050a400527601b0a406200732e00506200513401b", + "0x2e100506b01b01b32e0050a000532901b0b22d72d82d92da2db0ad2dd0aa", + "0x532901b01b32e0050aa00532901b01b32e0050a800505501b01b32e005", + "0x11501b01b32e0052db00511901b01b32e0050ad00532901b01b32e0052dd", + "0x1b01b32e0052d800504c01b01b32e0052d900505501b01b32e0052da005", + "0x532e0052df0052bc01b01b32e0050b200505501b01b32e0052d700504c", + "0x35704a2d403f32e0052d500527601b2d526c00732e00526c00513401b2d6", + "0x506b01b01b32e0052d400532901b2d20c10bd0bb0b80b935b0cf35a358", + "0x32901b01b32e00535a00532901b01b32e00535800505501b01b32e00504a", + "0x1b01b32e0050b900511901b01b32e00535b00532901b01b32e0050cf005", + "0x1b32e0050bd00504c01b01b32e0050bb00505501b01b32e0050b8005115", + "0x32e0053570052bc01b01b32e0052d200505501b01b32e0050c100504c01b", + "0x32901b01b32e00501b00701b01b50201b32e00732f2d600727501b32f005", + "0x1b01b32e00502300506b01b01b32e00504300532901b01b32e00503f005", + "0x1b32e00526c0052ec01b01b32e0050620052ec01b01b32e005044005329", + "0x1b50300501b19401b01b32e00504500532901b01b32e00504200506b01b", + "0x52de00527601b2de06200732e00506200513401b01b32e00501b00701b", + "0x535d00532901b2bc2be0cd2c12c72c82c935f0c72cb0c62cc35d03f32e", + "0xc700532901b01b32e0050c600511501b01b32e0052cc00506b01b01b32e", + "0x511901b01b32e0052c900532901b01b32e00535f00532901b01b32e005", + "0x4c01b01b32e0052c100505501b01b32e0052c700511501b01b32e0052c8", + "0x1b01b32e0052bc00505501b01b32e0052be00504c01b01b32e0050cd005", + "0x2bf00504801b2bf0c400732e0050c400529d01b0c400532e0052cb005274", + "0x26c00732e00526c00513401b2c600532e0050ce00530901b0ce00532e005", + "0x2b02ae2b62c40d62c32c20d42c50d22b72b803f32e0052b900527601b2b9", + "0x50d200511501b01b32e0052b700506b01b01b32e0052b800532901b2ab", + "0x2c300532901b01b32e0052c200532901b01b32e0050d400532901b01b32e", + "0x505501b01b32e0052c400511501b01b32e0050d600511901b01b32e005", + "0x5501b01b32e0052b000504c01b01b32e0052ae00504c01b01b32e0052b6", + "0x732e0052aa00529d01b2aa00532e0052c500527401b01b32e0052ab005", + "0x20701b2a600532e0052a800530901b2a800532e0050dc00504801b0dc2aa", + "0x72a62c600714601b2a600532e0052a600520701b2c600532e0052c6005", + "0x3f00532901b01b32e00501b02001b01b32e00501b00701b01b50401b32e", + "0x532901b01b32e00502300506b01b01b32e00504300532901b01b32e005", + "0x6b01b01b32e00526c0052ec01b01b32e0050620052ec01b01b32e005044", + "0x1b01b32e0052aa00505501b01b32e00504500532901b01b32e005042005", + "0x32e00532b00531f01b2a500532e00501b00504601b01b32e0050c4005055", + "0x1b32e00501b02001b01b32e00501b00701b01b50500501b19401b0e0005", + "0xc400506201b32b00532e00532b00531f01b01b00532e00501b00504601b", + "0x52aa0c432b01b04713d01b2aa00532e0052aa00506201b0c400532e005", + "0x501b00701b29d0055062a000532e0070e100513f01b0e12a12a304832e", + "0x1b01b32e00529c00505501b29a29b29c04832e0052a000514101b01b32e", + "0x1b00701b29800550729900532e00729a00514201b01b32e00529b005055", + "0x532901b01b32e00502300506b01b01b32e00529900505401b01b32e005", + "0x6b01b01b32e00526c0052ec01b01b32e0050620052ec01b01b32e005044", + "0x1b01b32e00504300532901b01b32e00504500532901b01b32e005042005", + "0x32e0052a100531f01b2a500532e0052a300504601b01b32e00503f005329", + "0x19401b0eb00532e0050e000527101b29500532e0052a500514401b0e0005", + "0x513401b01b32e00529800505401b01b32e00501b00701b01b50800501b", + "0xee0f00f10ef29229329403f32e0050ed00527601b0ed06200732e005062", + "0x1b32e00529300506b01b01b32e00529400532901b0f60f80f90f7290291", + "0x32e0050f000532901b01b32e0050ef00505501b01b32e00529200511501b", + "0x529000511501b01b32e00529100511901b01b32e0050ee00532901b01b", + "0xf800504c01b01b32e0050f900504c01b01b32e0050f700505501b01b32e", + "0x13401b28f00532e0050f100504301b01b32e0050f600505501b01b32e005", + "0x28b28c0fe1001010ff03f32e00528e00527601b28e26c00732e00526c005", + "0x32e00510100506b01b01b32e0050ff00532901b10f11328a106108109107", + "0x528b00532901b01b32e0050fe00505501b01b32e00510000511501b01b", + "0x10800511501b01b32e00510900511901b01b32e00510700532901b01b32e", + "0x504c01b01b32e00528a00504c01b01b32e00510600505501b01b32e005", + "0x1b10e00532e00528c00504301b01b32e00510f00505501b01b32e005113", + "0x2890052dd01b28900532e00528900502a01b28900532e00510e28f007358", + "0x6200732e00506200513401b01b32e00501b00701b11500550901b32e007", + "0x12112201828311911b11c11a28428528628703f32e00511700527601b117", + "0x528500511501b01b32e00528600506b01b01b32e00528700532901b280", + "0x11b00532901b01b32e00511a00532901b01b32e00528400505501b01b32e", + "0x505501b01b32e00528300511501b01b32e00511900511901b01b32e005", + "0x5501b01b32e00512100504c01b01b32e00512200504c01b01b32e005018", + "0x732e00526c00513401b04900532e00511c00504301b01b32e005280005", + "0x27927a12b12d12e12c27b27c12612727e03f32e00527f00527601b27f26c", + "0x12600511501b01b32e00512700506b01b01b32e00527e00532901b135278", + "0x532901b01b32e00527b00532901b01b32e00527c00505501b01b32e005", + "0x5501b01b32e00512b00511501b01b32e00512d00511901b01b32e00512e", + "0x1b01b32e00527800504c01b01b32e00527900504c01b01b32e00527a005", + "0x513404900735801b13400532e00512c00504301b01b32e005135005055", + "0x550a01b32e0072760052dd01b27600532e00527600502a01b27600532e", + "0x27400527601b27406200732e00506200513401b01b32e00501b00701b275", + "0x14600532901b14b14c14d14e27326f27114414214113f13d14603f32e005", + "0x505501b01b32e00513f00511501b01b32e00513d00506b01b01b32e005", + "0x11901b01b32e00514400532901b01b32e00514200532901b01b32e005141", + "0x1b01b32e00514e00505501b01b32e00527300511501b01b32e00526f005", + "0x1b32e00514b00505501b01b32e00514c00504c01b01b32e00514d00504c", + "0x527601b14926c00732e00526c00513401b14a00532e00527100504301b", + "0x532901b16126326426526626826926a26b26d15814714803f32e005149", + "0x5501b01b32e00515800511501b01b32e00514700506b01b01b32e005148", + "0x1b01b32e00526a00532901b01b32e00526b00532901b01b32e00526d005", + "0x1b32e00526500505501b01b32e00526600511501b01b32e005268005119", + "0x32e00516100505501b01b32e00526300504c01b01b32e00526400504c01b", + "0x2a01b26100532e00516314a00735801b16300532e00526900504301b01b", + "0x501b00701b16500550b01b32e0072610052dd01b26100532e005261005", + "0x16816603f32e00526000527601b26006200732e00506200513401b01b32e", + "0x6b01b01b32e00516600532901b25625725825925a25d13913a25f16b169", + "0x1b01b32e00516b00505501b01b32e00516900511501b01b32e005168005", + "0x1b32e00513900532901b01b32e00513a00532901b01b32e00525f005329", + "0x32e00525800504c01b01b32e00525900505501b01b32e00525a00511501b", + "0x525d00526f01b01b32e00525600505501b01b32e00525700504c01b01b", + "0x17400532e00517300514e01b17317100732e00517100527301b17100532e", + "0x527601b25526c00732e00526c00513401b17600532e00517400514d01b", + "0x532901b24c25b25017c24f18418318118225317b17917803f32e005255", + "0x5501b01b32e00517b00511501b01b32e00517900506b01b01b32e005178", + "0x1b01b32e00518100532901b01b32e00518200532901b01b32e005253005", + "0x1b32e00517c00505501b01b32e00524f00511501b01b32e005183005329", + "0x32e00524c00505501b01b32e00525b00504c01b01b32e00525000504c01b", + "0x14e01b18b18900732e00518900527301b18900532e00518400526f01b01b", + "0x32e00517600520701b18d00532e00524b00514d01b24b00532e00518b005", + "0x1b50c01b32e00718d17600714601b18d00532e00518d00520701b176005", + "0x1b32e00504400532901b01b32e00502300506b01b01b32e00501b00701b", + "0x32e00504200506b01b01b32e00526c0052ec01b01b32e0050620052ec01b", + "0x503f00532901b01b32e00504300532901b01b32e00504500532901b01b", + "0x2a300504601b01b32e00517100511901b01b32e00518900511901b01b32e", + "0x701b01b50d00501b19401b24a00532e0052a100531f01b18f00532e005", + "0x2a100532e0052a100531f01b2a300532e0052a300504601b01b32e00501b", + "0x2a304714b01b18900532e00518900514c01b17100532e00517100514c01b", + "0x24100550e24200532e00724300514a01b24324524704832e0051891712a1", + "0x24000511901b23823924004832e00524200514901b01b32e00501b00701b", + "0x550f23700532e00723800514201b01b32e00523900511901b01b32e005", + "0x32e0050620052ec01b01b32e00523700505401b01b32e00501b00701b236", + "0x504500532901b01b32e00504200506b01b01b32e00526c0052ec01b01b", + "0x4400532901b01b32e00503f00532901b01b32e00504300532901b01b32e", + "0x31f01b18f00532e00524700504601b01b32e00502300506b01b01b32e005", + "0x32e00524a00527101b19900532e00518f00514401b24a00532e005245005", + "0x32e00523600505401b01b32e00501b00701b01b51000501b19401b233005", + "0x19f19d22e03f32e00523000527601b23006200732e00506200513401b01b", + "0x506b01b01b32e00522e00532901b1a92191a721f22122322522b22c22d", + "0x32901b01b32e00522d00505501b01b32e00519f00511501b01b32e00519d", + "0x1b01b32e00522500532901b01b32e00522b00532901b01b32e00522c005", + "0x1b32e0051a700504c01b01b32e00521f00505501b01b32e005223005119", + "0x32e0052210052bc01b01b32e0051a900505501b01b32e00521900504c01b", + "0x21517d03f32e00521700527601b21726c00732e00526c00513401b1ab005", + "0x6b01b01b32e00517d00532901b1b820820920a20c20e1b22102121af21a", + "0x1b01b32e0051af00505501b01b32e00521a00511501b01b32e005215005", + "0x1b32e0051b200532901b01b32e00521000532901b01b32e005212005329", + "0x32e00520900504c01b01b32e00520a00505501b01b32e00520e00511901b", + "0x520c0052bc01b01b32e0051b800505501b01b32e00520800504c01b01b", + "0x1b01b32e00501b00701b01b51101b32e0072041ab00727501b20400532e", + "0x1b32e00504200506b01b01b32e00526c0052ec01b01b32e0050620052ec", + "0x32e00503f00532901b01b32e00504300532901b01b32e00504500532901b", + "0x524700504601b01b32e00502300506b01b01b32e00504400532901b01b", + "0x1b00701b01b51200501b19401b20200532e00524500531f01b20000532e", + "0x20103f32e0051ba00527601b1ba06200732e00506200513401b01b32e005", + "0x1b01b32e00520100532901b1f01f11f21f31f41ff1f91c11fc1bf1bd1fe", + "0x1b32e0051bf00505501b01b32e0051bd00511501b01b32e0051fe00506b", + "0x32e0051f900532901b01b32e0051c100532901b01b32e0051fc00532901b", + "0x51f200504c01b01b32e0051f400511501b01b32e0051ff00511901b01b", + "0x1f300527401b01b32e0051f000505501b01b32e0051f100504c01b01b32e", + "0x532e0051ee00504801b1ee1ef00732e0051ef00529d01b1ef00532e005", + "0x27601b1e726c00732e00526c00513401b1e900532e0051c800530901b1c8", + "0x32901b5195185175165155145130001e51d81df1e21e403f32e0051e7005", + "0x1b01b32e0051df00511501b01b32e0051e200506b01b01b32e0051e4005", + "0x1b32e00500000532901b01b32e0051e500532901b01b32e0051d8005055", + "0x32e00551500511501b01b32e00551400511901b01b32e00551300532901b", + "0x551900505501b01b32e00551800504c01b01b32e00551700504c01b01b", + "0x1b51b51a00732e00551a00529d01b51a00532e00551600527401b01b32e", + "0x51e900520701b33700532e00551c00530901b51c00532e00551b005048", + "0x51d01b32e0073371e900714601b33700532e00533700520701b1e900532e", + "0x32e00526c0052ec01b01b32e0050620052ec01b01b32e00501b00701b01b", + "0x504300532901b01b32e00504500532901b01b32e00504200506b01b01b", + "0x2300506b01b01b32e00504400532901b01b32e00503f00532901b01b32e", + "0x504601b01b32e0051ef00505501b01b32e00551a00505501b01b32e005", + "0x1b01b52000501b19401b51f00532e00524500531f01b51e00532e005247", + "0x532e00524500531f01b24700532e00524700504601b01b32e00501b007", + "0x4713d01b51a00532e00551a00506201b1ef00532e0051ef00506201b245", + "0x552552400532e00752300513f01b52352252104832e00551a1ef245247", + "0x505501b52833652704832e00552400514101b01b32e00501b00701b526", + "0x52a52900532e00752800514201b01b32e00533600505501b01b32e005527", + "0x504200506b01b01b32e00552900505401b01b32e00501b00701b52b005", + "0x3f00532901b01b32e00504300532901b01b32e00504500532901b01b32e", + "0x52ec01b01b32e00502300506b01b01b32e00504400532901b01b32e005", + "0x1b51e00532e00552100504601b01b32e0050620052ec01b01b32e00526c", + "0x551f00527101b52c00532e00551e00514401b51f00532e00552200531f", + "0x552b00505401b01b32e00501b00701b01b52e00501b19401b52d00532e", + "0x53153003f32e00552f00527601b52f06200732e00506200513401b01b32e", + "0x6b01b01b32e00553000532901b53b53a539335538537536535534533532", + "0x1b01b32e00553300505501b01b32e00553200511501b01b32e005531005", + "0x1b32e00553600532901b01b32e00553500532901b01b32e005534005329", + "0x32e00533500505501b01b32e00553800511501b01b32e00553700511901b", + "0x553900514801b01b32e00553b00505501b01b32e00553a00504c01b01b", + "0x53e03f32e00553d00527601b53d26c00732e00526c00513401b53c00532e", + "0x1b01b32e00553e00532901b54933454854754654554454354254154053f", + "0x1b32e00554100505501b01b32e00554000511501b01b32e00553f00506b", + "0x32e00554400532901b01b32e00554300532901b01b32e00554200532901b", + "0x554700505501b01b32e00554600511501b01b32e00554500511901b01b", + "0x54800514801b01b32e00554900505501b01b32e00533400504c01b01b32e", + "0x1b32e00501b00701b01b54b01b32e00754a53c00714601b54a00532e005", + "0x32e00504300532901b01b32e00504500532901b01b32e00504200506b01b", + "0x502300506b01b01b32e00504400532901b01b32e00503f00532901b01b", + "0x52100504601b01b32e0050620052ec01b01b32e00526c0052ec01b01b32e", + "0x701b01b54e00501b19401b54d00532e00552200531f01b54c00532e005", + "0x3f32e00554f00527601b54f06200732e00506200513401b01b32e00501b", + "0x1b32e00555000532901b33355b55a559558557556555554553552551550", + "0x32e00555300505501b01b32e00555200511501b01b32e00555100506b01b", + "0x555600532901b01b32e00555500532901b01b32e00555400532901b01b", + "0x55900505501b01b32e00555800511501b01b32e00555700511901b01b32e", + "0x514801b01b32e00533300505501b01b32e00555a00504c01b01b32e005", + "0x32e00555d00527601b55d26c00732e00526c00513401b55c00532e00555b", + "0x32e00555e00532901b56856756656533956456356256156033255f55e03f", + "0x556000505501b01b32e00533200511501b01b32e00555f00506b01b01b", + "0x56300532901b01b32e00556200532901b01b32e00556100532901b01b32e", + "0x505501b01b32e00533900511501b01b32e00556400511901b01b32e005", + "0x14801b01b32e00556800505501b01b32e00556600504c01b01b32e005565", + "0x501b00701b01b56a01b32e00756955c00714601b56900532e005567005", + "0x4300532901b01b32e00504500532901b01b32e00504200506b01b01b32e", + "0x506b01b01b32e00504400532901b01b32e00503f00532901b01b32e005", + "0x4601b01b32e0050620052ec01b01b32e00526c0052ec01b01b32e005023", + "0x1b56d00501b19401b56c00532e00552200531f01b56b00532e005521005", + "0x57333157257157056f56e03f32e00506200527601b01b32e00501b00701b", + "0x1b32e00556f00506b01b01b32e00556e00532901b579578577576575574", + "0x32e00557200532901b01b32e00557100505501b01b32e00557000511501b", + "0x557400511901b01b32e00557300532901b01b32e00533100532901b01b", + "0x57700504c01b01b32e00557600505501b01b32e00557500511501b01b32e", + "0x29d01b57a00532e00557900527401b01b32e00557800504c01b01b32e005", + "0x557c00530901b57c00532e00557b00504801b57b57a00732e00557a005", + "0x58758658558458358258158057f57e03f32e00526c00527601b57d00532e", + "0x511501b01b32e00557f00506b01b01b32e00557e00532901b58a589588", + "0x32901b01b32e00558200532901b01b32e00558100505501b01b32e005580", + "0x1b01b32e00558500511901b01b32e00558400532901b01b32e005583005", + "0x1b32e00558800504c01b01b32e00558700505501b01b32e005586005115", + "0x558b00529d01b58b00532e00558a00527401b01b32e00558900504c01b", + "0x58e00532e00558d00530901b58d00532e00558c00504801b58c58b00732e", + "0x57d00714601b58e00532e00558e00520701b57d00532e00557d00520701b", + "0x1b01b32e00504200506b01b01b32e00501b00701b01b58f01b32e00758e", + "0x1b32e00503f00532901b01b32e00504300532901b01b32e005045005329", + "0x32e00558b00505501b01b32e00502300506b01b01b32e00504400532901b", + "0x52200531f01b59000532e00552100504601b01b32e00557a00505501b01b", + "0x52100504601b01b32e00501b00701b01b59200501b19401b59100532e005", + "0x57a00532e00557a00506201b52200532e00552200531f01b52100532e005", + "0x59459304832e00558b57a52252104713d01b58b00532e00558b00506201b", + "0x14101b01b32e00501b00701b59800559759600532e00759500513f01b595", + "0x559a00505501b01b32e00559900505501b33b59a59904832e005596005", + "0x1b01b32e00501b00701b59d00559c59b00532e00733b00514201b01b32e", + "0x1b32e00503f00532901b01b32e00504300532901b01b32e00559b005054", + "0x32e00504500532901b01b32e00502300506b01b01b32e00504400532901b", + "0x59400531f01b59000532e00559300504601b01b32e00504200506b01b01b", + "0x59d00505401b01b32e00501b00701b01b59200501b19401b59100532e005", + "0x59f00532e00504559e00735801b59e00532e0050420052de01b01b32e005", + "0x701b33c0055a001b32e00759f0052dd01b59f00532e00559f00502a01b", + "0x532e0050445a100735801b5a100532e0050230052de01b01b32e00501b", + "0x1b5a40055a301b32e0075a20052dd01b5a200532e0055a200502a01b5a2", + "0x32e0055a500502a01b5a500532e00504303f00735801b01b32e00501b007", + "0x3f01b01b32e00501b00701b5a70055a601b32e0075a50052dd01b5a5005", + "0x532e0055a900515801b5a900532e0055a800514701b5a800532e00501b", + "0x531e01b59400532e00559400531f01b59300532e00559300504601b5aa", + "0x1b5aa0405945930470055aa00532e0055aa00526d01b04000532e005040", + "0x1b5ab00532e00501b33001b01b32e0055a70052da01b01b32e00501b007", + "0x55ac5ab00703101b5ac00532e0055ac00502a01b5ac00532e00501b26b", + "0x1b5af00532e0055ad5ae0070c901b5ae00532e00501b32601b5ad00532e", + "0x559400531f01b59300532e00559300504601b33f00532e0055af00526a", + "0x533f00532e00533f00526d01b04000532e00504000531e01b59400532e", + "0x32901b01b32e0055a40052da01b01b32e00501b00701b33f040594593047", + "0x1b5b000532e00501b33001b01b32e00503f00532901b01b32e005043005", + "0x55b15b000703101b5b100532e0055b100502a01b5b100532e00501b269", + "0x1b34000532e0055b25b30070c901b5b300532e00501b32601b5b200532e", + "0x559400531f01b59300532e00559300504601b5b400532e00534000526a", + "0x55b400532e0055b400526d01b04000532e00504000531e01b59400532e", + "0x32901b01b32e00533c0052da01b01b32e00501b00701b5b4040594593047", + "0x1b01b32e00504400532901b01b32e00503f00532901b01b32e005043005", + "0x5b600532e00501b26801b5b500532e00501b33001b01b32e00502300506b", + "0x1b32601b5b700532e0055b65b500703101b5b600532e0055b600502a01b", + "0x532e0055b900526a01b5b900532e0055b75b80070c901b5b800532e005", + "0x531e01b59400532e00559400531f01b59300532e00559300504601b5ba", + "0x1b5ba0405945930470055ba00532e0055ba00526d01b04000532e005040", + "0x1b01b32e00503f00532901b01b32e00504300532901b01b32e00501b007", + "0x1b32e00504500532901b01b32e00502300506b01b01b32e005044005329", + "0x559400531f01b5bb00532e00559300504601b01b32e00504200506b01b", + "0x1b00701b01b5bd00501b19401b5bc00532e0055980050d601b34200532e", + "0x532901b01b32e00504500532901b01b32e00504200506b01b01b32e005", + "0x6b01b01b32e00504400532901b01b32e00503f00532901b01b32e005043", + "0x1b01b32e0050620052ec01b01b32e00526c0052ec01b01b32e005023005", + "0x55260050d601b34200532e00552200531f01b5bb00532e005521005046", + "0x50620052ec01b01b32e00501b00701b01b5bd00501b19401b5bc00532e", + "0x4500532901b01b32e00504200506b01b01b32e00526c0052ec01b01b32e", + "0x532901b01b32e00503f00532901b01b32e00504300532901b01b32e005", + "0x1b5bb00532e00524700504601b01b32e00502300506b01b01b32e005044", + "0x5bd00501b19401b5bc00532e0052410050d601b34200532e00524500531f", + "0x32e00502300506b01b01b32e0051650052da01b01b32e00501b00701b01b", + "0x526c0052ec01b01b32e0050620052ec01b01b32e00504400532901b01b", + "0x4300532901b01b32e00504500532901b01b32e00504200506b01b01b32e", + "0x31f01b5be00532e0052a300504601b01b32e00503f00532901b01b32e005", + "0x2da01b01b32e00501b00701b01b5c000501b19401b5bf00532e0052a1005", + "0x1b01b32e00504400532901b01b32e00502300506b01b01b32e005275005", + "0x1b32e00504200506b01b01b32e00526c0052ec01b01b32e0050620052ec", + "0x32e00503f00532901b01b32e00504300532901b01b32e00504500532901b", + "0x1b19401b34300532e0052a100531f01b5c100532e0052a300504601b01b", + "0x2300506b01b01b32e0051150052da01b01b32e00501b00701b01b5c2005", + "0x52ec01b01b32e0050620052ec01b01b32e00504400532901b01b32e005", + "0x32901b01b32e00504500532901b01b32e00504200506b01b01b32e00526c", + "0x5c300532e0052a300504601b01b32e00503f00532901b01b32e005043005", + "0x1b32e00501b00701b01b5c500501b19401b5c400532e0052a100531f01b", + "0x32e0050620052ec01b01b32e00504400532901b01b32e00502300506b01b", + "0x504500532901b01b32e00504200506b01b01b32e00526c0052ec01b01b", + "0x2a300504601b01b32e00503f00532901b01b32e00504300532901b01b32e", + "0x5bc00532e00529d0050d601b34200532e0052a100531f01b5bb00532e005", + "0x34200531f01b5bb00532e0055bb00504601b5c600532e0055bc00526a01b", + "0x5c600532e0055c600526d01b04000532e00504000531e01b34200532e005", + "0x1b01b32e0052e20052da01b01b32e00501b00701b5c60403425bb047005", + "0x1b32e00502300506b01b01b32e00504300532901b01b32e00503f005329", + "0x32e00526c0052ec01b01b32e0050620052ec01b01b32e00504400532901b", + "0x50300501b19401b01b32e00504500532901b01b32e00504200506b01b01b", + "0x32e00503f00532901b01b32e0052ff0052da01b01b32e00501b00701b01b", + "0x504400532901b01b32e00502300506b01b01b32e00504300532901b01b", + "0x4200506b01b01b32e00526c0052ec01b01b32e0050620052ec01b01b32e", + "0x1b00504601b01b32e00501b02001b01b32e00504500532901b01b32e005", + "0x5c300532e00529500514401b0eb00532e00532b00531f01b29500532e005", + "0x5c400527101b5c100532e0055c300514401b5c400532e0050eb00527101b", + "0x5bf00532e00534300527101b5be00532e0055c100514401b34300532e005", + "0x19900514401b23300532e0055bf00527101b19900532e0055be00514401b", + "0x52c00532e00520000514401b20200532e00523300527101b20000532e005", + "0x52d00527101b54c00532e00552c00514401b52d00532e00520200527101b", + "0x56c00532e00554d00527101b56b00532e00554c00514401b54d00532e005", + "0x501b33001b59100532e00556c00527101b59000532e00556b00514401b", + "0x3101b5c800532e0055c800502a01b5c800532e00501b26601b5c700532e", + "0x55c95ca0070c901b5ca00532e00501b32601b5c900532e0055c85c7007", + "0x1b59000532e00559000504601b5cc00532e0055cb00526a01b5cb00532e", + "0x55cc00526d01b04000532e00504000531e01b59100532e00559100531f", + "0x505f0052da01b01b32e00501b00701b5cc0405915900470055cc00532e", + "0x2300506b01b01b32e00504300532901b01b32e00503f00532901b01b32e", + "0x532901b01b32e0050460052ec01b01b32e00504400532901b01b32e005", + "0x12b01b01b32e00519100512d01b01b32e00504200506b01b01b32e005045", + "0x26501b5cd00532e00501b33001b01b32e00501b02001b01b32e005326005", + "0x32e0055ce5cd00703101b5ce00532e0055ce00502a01b5ce00532e00501b", + "0x26a01b5d100532e0055cf5d00070c901b5d000532e00501b32601b5cf005", + "0x32e00532b00531f01b01b00532e00501b00504601b5d200532e0055d1005", + "0x470055d200532e0055d200526d01b04000532e00504000531e01b32b005", + "0x526401b01b32e00503e0052ee01b01b32e00501b00701b5d204032b01b", + "0x12d01b01b32e00504300532901b01b32e00504700508e01b01b32e00507b", + "0x1b01b32e0050460052ec01b01b32e00504400532901b01b32e005191005", + "0x1b32e00519400507201b01b32e00504100526401b01b32e005045005329", + "0x5d400526a01b5d400532e00502d5d30070c901b5d300532e00501b32601b", + "0x32900532e00532900531f01b01b00532e00501b00504601b5d500532e005", + "0x32901b0470055d500532e0055d500526d01b33000532e00533000531e01b", + "0x4800526301b04300532e00501b33001b01b32e0050070052ea01b5d5330", + "0x32e00504104300703101b04100532e00504200516101b04204800732e005", + "0x3f00532e00519404000703101b19404600732e0050460052d201b040005", + "0x3e03f00703101b03e00532e00503e00502a01b03e00532e00501b16301b", + "0x2004500732e0050450052d201b07b00532e00501b23401b02300532e005", + "0x703101b19100532e00519100502a01b19100532e00507b0200072ab01b", + "0x732e0050440052d201b00900532e00501b23401b32b00532e005191023", + "0x1b33000532e00533000502a01b33000532e0050093290072ab01b329044", + "0x521601b03102a00732e00502d00521401b02d00532e00533032b007031", + "0x4800732e00504800526301b32600532e00503100521801b01b32e00502a", + "0x4832e0073260470c900501b0462e301b32600532e00532600506201b0c9", + "0x32e00531e00505501b01b32e00501b00701b0380390370485d631e31f320", + "0x703101b31c00532e00504503600703101b03600532e00501b33001b01b", + "0x520300521601b20720300732e0051fb00521401b1fb00532e00504431c", + "0x6201b32000532e00532000531f01b20d00532e00520700521801b01b32e", + "0x21621421104832e00720d04604831f3200462e301b20d00532e00520d005", + "0x1b22800532e00521600521c01b01b32e00501b00701b22221c2180485d7", + "0x521400531e01b21100532e00521100531f01b04c00532e005228005222", + "0x501b00701b04c21421104800504c00532e00504c00503701b21400532e", + "0x32001b05400532e0052222290070c901b22900532e00501b32601b01b32e", + "0x32e00521c00531e01b21800532e00521800531f01b05100532e005054005", + "0x32e00501b00701b05121c21804800505100532e00505100503701b21c005", + "0x504800530001b01b32e00504600532901b01b32e00504500532901b01b", + "0x520070c901b05200532e00501b32601b01b32e00504400532901b01b32e", + "0x532e00503700531f01b23100532e00505500532001b05500532e005038", + "0x3704800523100532e00523100503701b03900532e00503900531e01b037", + "0x4604704732e00504800500701b04726101b01b32e00501b02001b231039", + "0x31f01b04500532e0050450050a001b04700532e00504700504601b044045", + "0x4404604504704700504400532e00504400516501b04600532e005046005", + "0x4600532e00501b16601b04700532e00501b26001b01b32e00501b02001b", + "0x4400516b01b04400532e00504504600716901b04500532e00501b16801b", + "0x4200532e00501b13a01b04300532e00504404700725f01b04400532e005", + "0x4000525a01b01b32e00504100525d01b04004100732e00504300513901b", + "0x500532e00500500531f01b01b00532e00501b00504601b19400532e005", + "0x1b04725701b04200532e00504200525801b19400532e00519400525901b", + "0x200055d807b00532e00702300525601b02303e03f04832e005042194005", + "0x19100517301b00932b19104832e00507b00517101b01b32e00501b00701b", + "0x1b31c01b32900532e00501b2f901b01b32e00500900505401b01b32e005", + "0x3e00532e00503e00531f01b03f00532e00503f00504601b33000532e005", + "0x33000520701b32900532e0053290052f701b32b00532e00532b00525801b", + "0x17601b03102a02d04832e00533032932b03e03f04617401b33000532e005", + "0x532600525501b01b32e00501b00701b0c90055d932600532e007031005", + "0x3731e00732e00532000517801b01b32e00531f00505401b31f32000732e", + "0x702a04825301b03900532e00503700517b01b01b32e00531e00517901b", + "0x18201b01b32e00501b00701b2072031fb0485da31c03603804832e007039", + "0x32e00520d00518301b21400532e00501b18101b21120d00732e00531c005", + "0x18301b03600532e00503600531e01b03800532e00503800531f01b20d005", + "0x501b00701b01b5db01b32e00721420d00727501b21100532e005211005", + "0x501b33001b01b32e00521100511501b01b32e0050480052ea01b01b32e", + "0x3101b21800532e00521800502a01b21800532e00501b18401b21600532e", + "0x521c2220070c901b22200532e00501b32601b21c00532e005218216007", + "0x1b02d00532e00502d00504601b04c00532e00522800529501b22800532e", + "0x504c0050eb01b03600532e00503600531e01b03800532e00503800531f", + "0x32e00501b24f01b01b32e00501b00701b04c03603802d04700504c00532e", + "0x2ea01b01b32e00501b00701b01b5dc01b32e00722921100727501b229005", + "0x1b05100532e00501b18401b05400532e00501b33001b01b32e005048005", + "0x501b32601b05200532e00505105400703101b05100532e00505100502a", + "0x23200532e00523100529501b23100532e0050520550070c901b05500532e", + "0x3600531e01b03800532e00503800531f01b02d00532e00502d00504601b", + "0x701b23203603802d04700523200532e0052320050eb01b03600532e005", + "0x2f701b05700532e00501b29201b23400532e00501b13a01b01b32e00501b", + "0x505900517801b05900532e00505723400717c01b05700532e005057005", + "0x1b23a00532e00505600517b01b01b32e00505800517901b05605800732e", + "0x5dd05f03324904832e00723a03603804825301b23a00532e00523a005250", + "0x52ea01b01b32e00505f00525b01b01b32e00501b00701b061062254048", + "0x2a01b00600532e00501b24c01b26c00532e00501b33001b01b32e005048", + "0x32e00501b32601b06900532e00500626c00703101b00600532e005006005", + "0x1b06e00532e0052d300529501b2d300532e00506906b0070c901b06b005", + "0x503300531e01b24900532e00524900531f01b02d00532e00502d005046", + "0x1b00701b06e03324902d04700506e00532e00506e0050eb01b03300532e", + "0x1b01b32e00506f00521601b07106f00732e00506100521401b01b32e005", + "0x32e0052ee00520701b07100532e00507100504101b2ee00532e00501b31c", + "0x18901b06200532e00506200531e01b25400532e00525400531f01b2ee005", + "0x18b01b01b32e00501b00701b3110055de07603400732e0072ee07102d048", + "0x32e00507300504301b07300532e00507600504401b07600532e005076005", + "0x735801b07200532e00507200502a01b07a00532e00501b24b01b072005", + "0x32e00503400504601b07400532e00507400502a01b07400532e00507a072", + "0x3f01b01b32e00501b00701b30f0055df01b32e0070740052dd01b034005", + "0x32e00530d00518f01b30d00532e00530e04800718d01b30e00532e00501b", + "0x31e01b25400532e00525400531f01b03400532e00503400504601b30c005", + "0x30c06225403404700530c00532e00530c0050eb01b06200532e005062005", + "0x1b32e0050480052ea01b01b32e00530f0052da01b01b32e00501b00701b", + "0x32e00530a00502a01b30a00532e00501b24a01b30b00532e00501b33001b", + "0xc901b30500532e00501b32601b30900532e00530a30b00703101b30a005", + "0x503400504601b30400532e00508600529501b08600532e005309305007", + "0x1b06200532e00506200531e01b25400532e00525400531f01b03400532e", + "0x1b01b32e00501b00701b30406225403404700530400532e0053040050eb", + "0x8400532e00501b24701b30300532e00501b33001b01b32e0050480052ea", + "0x1b32601b30200532e00508430300703101b08400532e00508400502a01b", + "0x532e00508200529501b08200532e0053023010070c901b30100532e005", + "0x531e01b25400532e00525400531f01b31100532e00531100504601b300", + "0x1b30006225431104700530000532e0053000050eb01b06200532e005062", + "0x2ff00532e00502d00504601b01b32e0050480052ea01b01b32e00501b007", + "0x20700522801b08700532e00520300531e01b07d00532e0051fb00531f01b", + "0x480052ea01b01b32e00501b00701b01b5e000501b19401b33800532e005", + "0x1b01b32e0052fc00530301b2fb2fc00732e0050c900530401b01b32e005", + "0x500700531e01b07d00532e00502a00531f01b2ff00532e00502d005046", + "0x1b00701b01b5e000501b19401b33800532e0052fb00522801b08700532e", + "0x1b2f92fa00732e00502000530401b01b32e0050480052ea01b01b32e005", + "0x32e00503e00531f01b2ff00532e00503f00504601b01b32e0052fa005303", + "0x32601b33800532e0052f900522801b08700532e00500700531e01b07d005", + "0x32e0052f700529501b2f700532e0053382f80070c901b2f800532e00501b", + "0x31e01b07d00532e00507d00531f01b2ff00532e0052ff00504601b2f6005", + "0x2f608707d2ff0470052f600532e0052f60050eb01b08700532e005087005", + "0x4600532e00501b24301b04700532e00501b24501b01b32e00501b02001b", + "0x1b31c01b04500532e00504604700724201b04600532e00504600520701b", + "0x1b01b00532e00501b00504601b04300532e00501b31c01b04400532e005", + "0x504300520701b04400532e00504400520701b04500532e005045005241", + "0x704100523901b04104200732e00504304404501b04724001b04300532e", + "0x1b03f00532e00501b23801b01b32e00501b00701b1940055e104000532e", + "0x7b00505401b07b02300732e00504000523601b03e00532e00503f005237", + "0x1b01b32e00502000523301b19102000732e00502300519901b01b32e005", + "0x500500531f01b04200532e00504200504601b32b00532e005191005230", + "0x1b32b00532e00532b00522e01b00700532e00500700531e01b00500532e", + "0x32900904732e00503e32b00700504204619f01b03e00532e00503e00519d", + "0x1b01b32e00501b00701b0310055e202a00532e00702d00522d01b02d330", + "0x32000505401b01b32e00532600522b01b3200c932604832e00502a00522c", + "0x1b31f00532e00531f00522301b31f00532e0050c900522501b01b32e005", + "0x1fb31c03603803903704332e00531e00521f01b31e00532e00531f005221", + "0x3600504c01b01b32e00503800504c01b01b32e00503900504c01b207203", + "0x504c01b01b32e0051fb00504c01b01b32e00531c00504c01b01b32e005", + "0x20701b20d00532e00501b1a701b01b32e00520700504c01b01b32e005203", + "0x501b00701b01b5e301b32e00720d03700714601b03700532e005037005", + "0x501b18401b21100532e00501b33001b01b32e0050480052ea01b01b32e", + "0x21600532e00521421100703101b21400532e00521400502a01b21400532e", + "0x21c00529501b21c00532e0052162180070c901b21800532e00501b32601b", + "0x32900532e00532900531f01b00900532e00500900504601b22200532e005", + "0x32900904700522200532e0052220050eb01b33000532e00533000531e01b", + "0x22804800718d01b22800532e00501b03f01b01b32e00501b00701b222330", + "0x900532e00500900504601b22900532e00504c00518f01b04c00532e005", + "0x2290050eb01b33000532e00533000531e01b32900532e00532900531f01b", + "0x480052ea01b01b32e00501b00701b22933032900904700522900532e005", + "0x1b05100532e00532900531f01b05400532e00500900504601b01b32e005", + "0x5e400501b19401b05500532e0050310050d601b05200532e00533000531e", + "0x32e00504200504601b01b32e0050480052ea01b01b32e00501b00701b01b", + "0xd601b05200532e00500700531e01b05100532e00500500531f01b054005", + "0x32e00505400504601b23100532e00505500529501b05500532e005194005", + "0xeb01b05200532e00505200531e01b05100532e00505100531f01b054005", + "0x21901b01b32e00501b02001b23105205105404700523100532e005231005", + "0x4600532e00504600516b01b04500532e00501b1a901b04600532e00501b", + "0x4304404832e0070450460480050471ab01b04500532e00504500516b01b", + "0x3f00732e00504200521701b01b32e00501b00701b1940400410485e5042", + "0x4400531f01b03e00532e00503e00521501b01b32e00503f00517d01b03e", + "0x2300532e00703e00521a01b04300532e00504300531e01b04400532e005", + "0x470052ea01b01b32e0050230051af01b01b32e00501b00701b07b0055e6", + "0x502a01b19100532e00501b21201b02000532e00501b33001b01b32e005", + "0x532e00501b32601b32b00532e00519102000703101b19100532e005191", + "0x4601b33000532e00532900529501b32900532e00532b0090070c901b009", + "0x32e0050070052d401b04400532e00504400531f01b01b00532e00501b005", + "0x4600533000532e0053300050eb01b04300532e00504300531e01b007005", + "0x21001b01b32e00507b00505401b01b32e00501b00701b33004300704401b", + "0x2d00532e00502d00516b01b02a00532e00501b1a901b02d00532e00501b", + "0x32603104832e00702a02d0430440471ab01b02a00532e00502a00516b01b", + "0x1b01b32e0050c900517d01b01b32e00501b00701b31e31f3200485e70c9", + "0x3900532e00501b24c01b03700532e00501b33001b01b32e0050470052ea", + "0x1b32601b03800532e00503903700703101b03900532e00503900502a01b", + "0x532e00531c00529501b31c00532e0050380360070c901b03600532e005", + "0x52d401b03100532e00503100531f01b01b00532e00501b00504601b1fb", + "0x532e0051fb0050eb01b32600532e00532600531e01b00700532e005007", + "0x32e00531e00521401b01b32e00501b00701b1fb32600703101b0460051fb", + "0x504101b20d00532e00501b31c01b01b32e00520300521601b207203007", + "0x532e00532000531f01b20d00532e00520d00520701b20700532e005207", + "0x21421100732e00720d20701b04818901b31f00532e00531f00531e01b320", + "0x504401b21400532e00521400518b01b01b32e00501b00701b2160055e8", + "0x22200532e00501b1b201b21c00532e00521800504301b21800532e005214", + "0x502a01b22800532e00522221c00735801b21c00532e00521c00502a01b", + "0x1b32e0072280052dd01b21100532e00521100504601b22800532e005228", + "0x501b20c01b22900532e00501b20e01b01b32e00501b00701b04c0055e9", + "0x5400732e00505400520a01b05122900732e00522900520a01b05400532e", + "0x471ab01b05200532e00505200516b01b05100532e00505100516b01b052", + "0x32e00501b00701b0590572340485ea23223105504832e00705205131f320", + "0x531e01b05500532e00505500531f01b23200532e00523200521501b01b", + "0x501b00701b0560055eb05800532e00723200521a01b23100532e005231", + "0x610622540485ec05f03324923a04732e00705823105504820901b01b32e", + "0x526c00525b01b00626c00732e00503300520801b01b32e00501b00701b", + "0x16b01b01b32e00506900525b01b06b06900732e00522900520801b01b32e", + "0x52d300518201b2d300600732e00500600520a01b00600532e005006005", + "0x7106b00732e00506b00520a01b01b32e00506f00511501b06f06e00732e", + "0x6e0052bc01b01b32e00503400511501b0342ee00732e00507100518201b", + "0x31f01b01b32e00501b04701b31100532e0052ee0052bc01b07600532e005", + "0x32e00505f00516b01b24900532e00524900531e01b23a00532e00523a005", + "0x2ea01b01b32e00501b00701b01b5ed01b32e00731107600727501b05f005", + "0x1b01b32e00505f00525b01b01b32e00505400525b01b01b32e005047005", + "0x1b01b5ee00501b19401b01b32e00500600525b01b01b32e00506b00525b", + "0x32e00507300511501b07207300732e00500600518201b01b32e00501b007", + "0x52bc01b01b32e00507a00511501b07407a00732e00506b00518201b01b", + "0x32e00730e30f00727501b30e00532e0050740052bc01b30f00532e005072", + "0x5400525b01b01b32e0050470052ea01b01b32e00501b00701b01b5ef01b", + "0x501b00701b01b5f000501b19401b01b32e00505f00525b01b01b32e005", + "0x20801b01b32e00530d00525b01b30c30d00732e00505f00520801b01b32e", + "0x32e00530c00520a01b01b32e00530b00525b01b30a30b00732e005054005", + "0x1b01b32e00508600511501b08630500732e00530900518201b30930c007", + "0x511501b08430300732e00530400518201b30430a00732e00530a00520a", + "0x30100532e0053030052bc01b30200532e0053050052bc01b01b32e005084", + "0x470052ea01b01b32e00501b00701b01b5f101b32e00730130200727501b", + "0x1b19401b01b32e00530c00525b01b01b32e00530a00525b01b01b32e005", + "0x11501b30008200732e00530c00518201b01b32e00501b00701b01b5f0005", + "0x32e0052ff00511501b07d2ff00732e00530a00518201b01b32e005082005", + "0x727501b33800532e00507d0052bc01b08700532e0053000052bc01b01b", + "0x1b32e0050470052ea01b01b32e00501b00701b01b5f201b32e007338087", + "0x2fb00532e00501b1b801b2fc00532e00501b33001b01b32e00501b02001b", + "0x1b32601b2fa00532e0052fb2fc00703101b2fb00532e0052fb00502a01b", + "0x532e0052f800529501b2f800532e0052fa2f90070c901b2f900532e005", + "0x52d401b23a00532e00523a00531f01b21100532e00521100504601b2f7", + "0x532e0052f70050eb01b24900532e00524900531e01b00700532e005007", + "0x532e00501b20401b01b32e00501b00701b2f724900723a2110460052f7", + "0x518301b2f300532e00501b20001b2f42f500732e0052f600518201b2f6", + "0x52f32f42110481ba01b2f300532e0052f300520201b2f400532e0052f4", + "0x7c00532e0052ef0050c401b01b32e0052f100511501b2ef2f12f204832e", + "0x8d07c0071fe01b08d00532e00501b20101b08b00532e0052f50050c401b", + "0x532e00508b2ed0072ab01b2ed00532e0052ed00502a01b2ed00532e005", + "0x32e00501b1fc01b08e00532e00501b1bf01b2ec00532e00501b1bd01b090", + "0x481c101b2e800532e0052ea0050ad01b2ea00532e00501b03f01b2eb005", + "0x52f200504601b09900532e0050900051f901b2e700532e0052e82eb08e", + "0x1b00700532e0050070052d401b23a00532e00523a00531f01b2f200532e", + "0x52e70051ff01b2ec00532e0052ec00516b01b24900532e00524900531e", + "0x2e72ec24900723a2f20441f301b09900532e0050990051f401b2e700532e", + "0x709d0051f201b01b32e00501b04701b09d2e32e42e608504632e005099", + "0xa000532e0052e20051f101b01b32e00501b00701b0a40055f32e200532e", + "0x1b02001b01b32e00501b00701b2df0055f42e100532e0070a00051f001b", + "0x718d01b0a800532e00501b03f01b01b32e0052e100505401b01b32e005", + "0x32e00508500504601b2dd00532e0050aa00518f01b0aa00532e0050a8047", + "0x31e01b2e400532e0052e40052d401b2e600532e0052e600531f01b085005", + "0x2e32e42e60850460052dd00532e0052dd0050eb01b2e300532e0052e3005", + "0x532e00501b33001b01b32e0050470052ea01b01b32e00501b00701b2dd", + "0x19401b2da00532e0052db00522801b2db00532e0052df0ad00703101b0ad", + "0x530401b01b32e0050470052ea01b01b32e00501b00701b01b5f500501b", + "0x532e0052d800522801b01b32e0052d900530301b2d82d900732e0050a4", + "0x52da2d70070c901b2d700532e00501b32601b01b32e00501b02001b2da", + "0x1b08500532e00508500504601b2d600532e0050b200529501b0b200532e", + "0x52e300531e01b2e400532e0052e40052d401b2e600532e0052e600531f", + "0x701b2d62e32e42e60850460052d600532e0052d60050eb01b2e300532e", + "0x2ea01b01b32e00505400525b01b01b32e00522900525b01b01b32e00501b", + "0x532e0050612d50070c901b2d500532e00501b32601b01b32e005047005", + "0x531f01b21100532e00521100504601b04a00532e0052d400529501b2d4", + "0x532e00506200531e01b00700532e0050070052d401b25400532e005254", + "0x501b00701b04a06200725421104600504a00532e00504a0050eb01b062", + "0x5400525b01b01b32e00522900525b01b01b32e00505600505401b01b32e", + "0x1b05701b35700532e00501b33001b01b32e0050470052ea01b01b32e005", + "0x532e00535835700703101b35800532e00535800502a01b35800532e005", + "0x529501b35b00532e00535a0cf0070c901b0cf00532e00501b32601b35a", + "0x532e00505500531f01b21100532e00521100504601b0b900532e00535b", + "0x50eb01b23100532e00523100531e01b00700532e0050070052d401b055", + "0x25b01b01b32e00501b00701b0b92310070552110460050b900532e0050b9", + "0x1b01b32e0050470052ea01b01b32e00505400525b01b01b32e005229005", + "0x50bb00529501b0bb00532e0050590b80070c901b0b800532e00501b326", + "0x1b23400532e00523400531f01b21100532e00521100504601b0bd00532e", + "0x50bd0050eb01b05700532e00505700531e01b00700532e0050070052d4", + "0x4c0052da01b01b32e00501b00701b0bd0570072342110460050bd00532e", + "0x1b24a01b0c100532e00501b33001b01b32e0050470052ea01b01b32e005", + "0x532e0052d20c100703101b2d200532e0052d200502a01b2d200532e005", + "0x529501b35d00532e00532f2de0070c901b2de00532e00501b32601b32f", + "0x532e00532000531f01b21100532e00521100504601b2cc00532e00535d", + "0x50eb01b31f00532e00531f00531e01b00700532e0050070052d401b320", + "0x2ea01b01b32e00501b00701b2cc31f0073202110460052cc00532e0052cc", + "0x1b2cb00532e00501b24701b0c600532e00501b33001b01b32e005047005", + "0x501b32601b0c700532e0052cb0c600703101b2cb00532e0052cb00502a", + "0x2c800532e0052c900529501b2c900532e0050c735f0070c901b35f00532e", + "0x70052d401b32000532e00532000531f01b21600532e00521600504601b", + "0x2c800532e0052c80050eb01b31f00532e00531f00531e01b00700532e005", + "0x1b32e0050470052ea01b01b32e00501b00701b2c831f007320216046005", + "0x2c100529501b2c100532e0051942c70070c901b2c700532e00501b32601b", + "0x4100532e00504100531f01b01b00532e00501b00504601b0cd00532e005", + "0xcd0050eb01b04000532e00504000531e01b00700532e0050070052d401b", + "0x1a901b04700532e00501b21901b0cd04000704101b0460050cd00532e005", + "0x532e00504600516b01b04700532e00504700516b01b04600532e00501b", + "0x1b0400410420485f604304404504832e0070460470070050471ef01b046", + "0x32e0051940051c801b03f19400732e0050430051ee01b01b32e00501b007", + "0x531e01b04500532e00504500531f01b03f00532e00503f0051e901b01b", + "0x501b00701b0230055f703e00532e00703f0051e701b04400532e005044", + "0x501b33001b01b32e0050480052ea01b01b32e00503e0051e401b01b32e", + "0x3101b02000532e00502000502a01b02000532e00501b21201b07b00532e", + "0x519132b0070c901b32b00532e00501b32601b19100532e00502007b007", + "0x1b01b00532e00501b00504601b32900532e00500900529501b00900532e", + "0x53290050eb01b04400532e00504400531e01b04500532e00504500531f", + "0x502300505401b01b32e00501b00701b32904404501b04700532900532e", + "0x33000516b01b02d00532e00501b1a901b33000532e00501b1e201b01b32e", + "0x702d3300440450471ef01b02d00532e00502d00516b01b33000532e005", + "0x3260051c801b01b32e00501b00701b31f3200c90485f832603102a04832e", + "0x1b24c01b31e00532e00501b33001b01b32e0050480052ea01b01b32e005", + "0x532e00503731e00703101b03700532e00503700502a01b03700532e005", + "0x529501b03600532e0050390380070c901b03800532e00501b32601b039", + "0x532e00502a00531f01b01b00532e00501b00504601b31c00532e005036", + "0x1b04700531c00532e00531c0050eb01b03100532e00503100531e01b02a", + "0x21601b2031fb00732e00531f00521401b01b32e00501b00701b31c03102a", + "0x20300532e00520300504101b20700532e00501b31c01b01b32e0051fb005", + "0x32000531e01b0c900532e0050c900531f01b20700532e00520700520701b", + "0x701b2140055f921120d00732e00720720301b04818901b32000532e005", + "0x21600532e00521100504401b21100532e00521100518b01b01b32e00501b", + "0x521800502a01b21c00532e00501b1b201b21800532e00521600504301b", + "0x22200532e00522200502a01b22200532e00521c21800735801b21800532e", + "0x701b2280055fa01b32e0072220052dd01b20d00532e00520d00504601b", + "0x20a01b22900532e00501b1d801b04c00532e00501b1df01b01b32e00501b", + "0x5400516b01b05122900732e00522900520a01b05404c00732e00504c005", + "0x70510543200c90471ef01b05100532e00505100516b01b05400532e005", + "0x2310051e901b01b32e00501b00701b0572342320485fb23105505204832e", + "0x5500532e00505500531e01b05200532e00505200531f01b23100532e005", + "0x481e501b01b32e00501b00701b0580055fc05900532e0072310051e701b", + "0x32e00501b00701b06225405f0485fd03324923a05604732e007059055052", + "0x520801b01b32e00506100525b01b26c06100732e00524900520801b01b", + "0x532e00526c00516b01b01b32e00500600525b01b06900600732e00504c", + "0x1b06e2d300732e00506b00518201b06b26c00732e00526c00520a01b26c", + "0x506f00518201b06f06900732e00506900520a01b01b32e00506e005115", + "0x1b03400532e0052d30052bc01b01b32e0052ee00511501b2ee07100732e", + "0x523a00531e01b05600532e00505600531f01b07600532e0050710052bc", + "0x5fe01b32e00707603400727501b03300532e00503300516b01b23a00532e", + "0x32e00522900525b01b01b32e0050480052ea01b01b32e00501b00701b01b", + "0x526c00525b01b01b32e00506900525b01b01b32e00503300525b01b01b", + "0x32e00526c00518201b01b32e00501b00701b01b5ff00501b19401b01b32e", + "0x1b07a07200732e00506900518201b01b32e00531100511501b073311007", + "0x32e00507a0052bc01b07400532e0050730052bc01b01b32e005072005115", + "0x2ea01b01b32e00501b00701b01b60001b32e00730f07400727501b30f005", + "0x1b01b32e00503300525b01b01b32e00522900525b01b01b32e005048005", + "0x30d30e00732e00503300520801b01b32e00501b00701b01b60100501b194", + "0x30c00525b01b30b30c00732e00522900520801b01b32e00530e00525b01b", + "0x30900732e00530a00518201b30a30d00732e00530d00520a01b01b32e005", + "0x518201b08630b00732e00530b00520a01b01b32e00530500511501b305", + "0x532e0053090052bc01b01b32e00530300511501b30330400732e005086", + "0x1b01b60201b32e00730208400727501b30200532e0053040052bc01b084", + "0x1b01b32e00530b00525b01b01b32e0050480052ea01b01b32e00501b007", + "0x18201b01b32e00501b00701b01b60100501b19401b01b32e00530d00525b", + "0x32e00530b00518201b01b32e00530100511501b08230100732e00530d005", + "0x2bc01b07d00532e0050820052bc01b01b32e00530000511501b2ff300007", + "0x501b00701b01b60301b32e00708707d00727501b08700532e0052ff005", + "0x501b1b801b33800532e00501b33001b01b32e0050480052ea01b01b32e", + "0x2fb00532e0052fc33800703101b2fc00532e0052fc00502a01b2fc00532e", + "0x2f900529501b2f900532e0052fb2fa0070c901b2fa00532e00501b32601b", + "0x5600532e00505600531f01b20d00532e00520d00504601b2f800532e005", + "0x5620d0470052f800532e0052f80050eb01b23a00532e00523a00531e01b", + "0x52f700518201b2f700532e00501b00001b01b32e00501b00701b2f823a", + "0x1b2f500532e0052f500518301b2f400532e00501b20001b2f52f600732e", + "0x1b2f12f22f304832e0052f42f520d0481ba01b2f400532e0052f4005202", + "0x32e0052ef00532901b2ef00532e0052f10050c401b01b32e0052f2005115", + "0x501b51301b01b32e00507c00532901b07c00532e0052f60050c401b01b", + "0x16b01b08b00532e00508b00516b01b08d00532e00501b51401b08b00532e", + "0x8b23a0560471ef01b2f300532e0052f300504601b08d00532e00508d005", + "0x1e901b01b32e00501b00701b2ea2eb08e0486042ec0902ed04832e00708d", + "0x32e00509000531e01b2ed00532e0052ed00531f01b2ec00532e0052ec005", + "0x1b01b32e00501b00701b2e70056052e800532e0072ec0051e701b090005", + "0x2e600532e00501b51701b08500532e00501b51601b09900532e00501b515", + "0x9000531e01b2ed00532e0052ed00531f01b2f300532e0052f300504601b", + "0x8500532e00508500516b01b09900532e00509900516b01b09000532e005", + "0x2f304451901b2e800532e0052e800551801b2e600532e0052e600516b01b", + "0x532e0072e200551a01b2e209d2e32e404732e0052e82e60850990902ed", + "0x1b03f01b01b32e0050a400551b01b01b32e00501b00701b0a00056060a4", + "0x532e0052df00518f01b2df00532e0052e104800718d01b2e100532e005", + "0x531e01b2e300532e0052e300531f01b2e400532e0052e400504601b0a8", + "0x1b0a809d2e32e40470050a800532e0050a80050eb01b09d00532e00509d", + "0xaa00532e0050a000529501b01b32e0050480052ea01b01b32e00501b007", + "0x9d00531e01b2e300532e0052e300531f01b2e400532e0052e400504601b", + "0x701b0aa09d2e32e40470050aa00532e0050aa0050eb01b09d00532e005", + "0x33001b01b32e0050480052ea01b01b32e0052e700505401b01b32e00501b", + "0xad00532e0050ad00502a01b0ad00532e00501b05701b2dd00532e00501b", + "0x2da0070c901b2da00532e00501b32601b2db00532e0050ad2dd00703101b", + "0x532e0052f300504601b2d800532e0052d900529501b2d900532e0052db", + "0x50eb01b09000532e00509000531e01b2ed00532e0052ed00531f01b2f3", + "0x52ea01b01b32e00501b00701b2d80902ed2f30470052d800532e0052d8", + "0xb200532e0052ea2d70070c901b2d700532e00501b32601b01b32e005048", + "0x8e00531f01b2f300532e0052f300504601b2d600532e0050b200529501b", + "0x2d600532e0052d60050eb01b2eb00532e0052eb00531e01b08e00532e005", + "0x1b01b32e00504c00525b01b01b32e00501b00701b2d62eb08e2f3047005", + "0x2d500532e00501b32601b01b32e0050480052ea01b01b32e00522900525b", + "0x504601b04a00532e0052d400529501b2d400532e0050622d50070c901b", + "0x532e00525400531e01b05f00532e00505f00531f01b20d00532e00520d", + "0x32e00501b00701b04a25405f20d04700504a00532e00504a0050eb01b254", + "0x522900525b01b01b32e00504c00525b01b01b32e00505800505401b01b", + "0x501b05701b35700532e00501b33001b01b32e0050480052ea01b01b32e", + "0x35a00532e00535835700703101b35800532e00535800502a01b35800532e", + "0x35b00529501b35b00532e00535a0cf0070c901b0cf00532e00501b32601b", + "0x5200532e00505200531f01b20d00532e00520d00504601b0b900532e005", + "0x5220d0470050b900532e0050b90050eb01b05500532e00505500531e01b", + "0x522900525b01b01b32e00504c00525b01b01b32e00501b00701b0b9055", + "0xb80070c901b0b800532e00501b32601b01b32e0050480052ea01b01b32e", + "0x532e00520d00504601b0bd00532e0050bb00529501b0bb00532e005057", + "0x50eb01b23400532e00523400531e01b23200532e00523200531f01b20d", + "0x52da01b01b32e00501b00701b0bd23423220d0470050bd00532e0050bd", + "0x24a01b0c100532e00501b33001b01b32e0050480052ea01b01b32e005228", + "0x32e0052d20c100703101b2d200532e0052d200502a01b2d200532e00501b", + "0x29501b35d00532e00532f2de0070c901b2de00532e00501b32601b32f005", + "0x32e0050c900531f01b20d00532e00520d00504601b2cc00532e00535d005", + "0x470052cc00532e0052cc0050eb01b32000532e00532000531e01b0c9005", + "0x1b33001b01b32e0050480052ea01b01b32e00501b00701b2cc3200c920d", + "0x1b2cb00532e0052cb00502a01b2cb00532e00501b24701b0c600532e005", + "0xc735f0070c901b35f00532e00501b32601b0c700532e0052cb0c6007031", + "0x21400532e00521400504601b2c800532e0052c900529501b2c900532e005", + "0x2c80050eb01b32000532e00532000531e01b0c900532e0050c900531f01b", + "0x480052ea01b01b32e00501b00701b2c83200c92140470052c800532e005", + "0x1b2c100532e0050402c70070c901b2c700532e00501b32601b01b32e005", + "0x504200531f01b01b00532e00501b00504601b0cd00532e0052c1005295", + "0x50cd00532e0050cd0050eb01b04100532e00504100531e01b04200532e", + "0x4600732e00700501b00700501b01b32e00501b02001b0cd04104201b047", + "0x4104200732e00504700521401b01b32e00501b00701b043044007607045", + "0x504000520701b19400532e00501b51c01b04000532e00504100530901b", + "0x732e00719404004604833701b19400532e00519400520701b04000532e", + "0x1b01b32e00503e00504c01b01b32e00501b00701b07b02300760803e03f", + "0x732e00704200551e01b03f00532e00503f00504601b01b32e00501b047", + "0x1b00900532e00519100504401b01b32e00501b00701b32b005609191020", + "0x532900504001b33000532e00502000522801b32900532e005009005042", + "0x32e00501b03f01b01b32e00501b00701b01b60a00501b19401b02d00532e", + "0x4001b33000532e00532b00522801b03100532e00502a00503e01b02a005", + "0x1b00701b0c900560b32600532e00702d00502301b02d00532e005031005", + "0x32e00501b00701b31e00560c31f32000732e00733000551e01b01b32e005", + "0x522801b03900532e00503700504201b03700532e00531f00504401b01b", + "0x1b01b60d00501b19401b03600532e00503900504001b03800532e005320", + "0x1fb00532e00531c00503e01b31c00532e00501b03f01b01b32e00501b007", + "0x3600502301b03600532e0051fb00504001b03800532e00531e00522801b", + "0x732e00703800551e01b01b32e00501b00701b20700560e20300532e007", + "0x1b21600532e00521100504401b01b32e00501b00701b21400560f21120d", + "0x521800504001b21c00532e00520d00522801b21800532e005216005042", + "0x32e00501b03f01b01b32e00501b00701b01b61000501b19401b22200532e", + "0x4001b21c00532e00521400522801b04c00532e00522800503e01b228005", + "0x1b00701b05400561122900532e00722200502301b22200532e00504c005", + "0x61201b32e0070510052dd01b05122900732e0052290052d201b01b32e005", + "0x32603f00723a01b01b32e00522900532901b01b32e00501b00701b052005", + "0x1b32e00501b02001b01b32e00501b00701b23200561323105500732e007", + "0x5700521801b01b32e00523400521601b05723400732e00521c00521401b", + "0x5920323100704504606f01b05500532e00505500504601b05900532e005", + "0x505501b01b32e00501b00701b05f03324904861423a05605804832e007", + "0x6200532e00505800531f01b25400532e00505500504601b01b32e00523a", + "0x1b32e00501b00701b01b61500501b19401b06100532e00505600531e01b", + "0x505f26c0070c901b26c00532e00501b32601b01b32e0050480052ea01b", + "0x1b05500532e00505500504601b06900532e00500600551f01b00600532e", + "0x506900552101b03300532e00503300531e01b24900532e00524900531f", + "0x32e00501b02001b01b32e00501b00701b06903324905504700506900532e", + "0x520300532901b01b32e0050480052ea01b01b32e00521c00521601b01b", + "0x2d300502a01b2d300532e00501b05701b06b00532e00501b33001b01b32e", + "0x6f00532e00501b32601b06e00532e0052d306b00703101b2d300532e005", + "0x504601b2ee00532e00507100551f01b07100532e00506e06f0070c901b", + "0x532e00500700531e01b04500532e00504500531f01b23200532e005232", + "0x32e00501b00701b2ee0070452320470052ee00532e0052ee00552101b007", + "0x3422900735801b03400532e00501b23401b01b32e0050520052da01b01b", + "0x61601b32e0070760052dd01b07600532e00507600502a01b07600532e005", + "0x561707207300732e00732603f00708201b01b32e00501b00701b311005", + "0x732e00521c00521401b01b32e00501b02001b01b32e00501b00701b07a", + "0x504601b30e00532e00530f00521801b01b32e00507400521601b30f074", + "0x61830b30c30d04832e00730e2030720070450462e301b07300532e005073", + "0x504601b01b32e00530b00505501b01b32e00501b00701b30530930a048", + "0x532e00530c00531e01b30400532e00530d00531f01b08600532e005073", + "0x1b32e0050480052ea01b01b32e00501b00701b01b61900501b19401b303", + "0x30200551f01b30200532e0053050840070c901b08400532e00501b32601b", + "0x30a00532e00530a00531f01b07300532e00507300504601b30100532e005", + "0x30a07304700530100532e00530100552101b30900532e00530900531e01b", + "0x32e00521c00521601b01b32e00501b02001b01b32e00501b00701b301309", + "0x32e00501b33001b01b32e00520300532901b01b32e0050480052ea01b01b", + "0x703101b30000532e00530000502a01b30000532e00501b05701b082005", + "0x32e0052ff07d0070c901b07d00532e00501b32601b2ff00532e005300082", + "0x31f01b07a00532e00507a00504601b33800532e00508700551f01b087005", + "0x32e00533800552101b00700532e00500700531e01b04500532e005045005", + "0x32e0053110052da01b01b32e00501b00701b33800704507a047005338005", + "0x52030052d201b2fc00532e00501b52201b01b32e00532600532901b01b", + "0x532e0052fa00502a01b2fa00532e0052fc2fb00735801b2fb20300732e", + "0x1b02001b01b32e00501b00701b2f900561a01b32e0072fa0052dd01b2fa", + "0x31f01b03f00532e00503f00504601b01b32e00520300532901b01b32e005", + "0x32e00521c00522801b00700532e00500700531e01b04500532e005045005", + "0x2f80470052f52f62f72f804732e00521c04800704503f04635b01b21c005", + "0x21c00521601b01b32e0052f90052da01b01b32e00501b00701b2f52f62f7", + "0x1b2f300532e0052f420300735801b2f400532e00501b52301b01b32e005", + "0x1b00701b2f200561b01b32e0072f30052dd01b2f300532e0052f300502a", + "0x501b33001b01b32e0050480052ea01b01b32e00501b02001b01b32e005", + "0x3101b2ef00532e0052ef00502a01b2ef00532e00501b0bb01b2f100532e", + "0x507c08b0070c901b08b00532e00501b32601b07c00532e0052ef2f1007", + "0x1b03f00532e00503f00504601b2ed00532e00508d00551f01b08d00532e", + "0x52ed00552101b00700532e00500700531e01b04500532e00504500531f", + "0x32e00501b02001b01b32e00501b00701b2ed00704503f0470052ed00532e", + "0x4500531f01b08600532e00503f00504601b01b32e0052f20052da01b01b", + "0x25400532e00508600514401b30300532e00500700531e01b30400532e005", + "0x501b23201b06100532e00530300552401b06200532e00530400527101b", + "0x8e00532e0052ec00552701b2ec00532e00509004800752601b09000532e", + "0x1b32e00501b00701b08e06106225404700508e00532e00508e00552101b", + "0x1b32e00521c00521601b01b32e00505400505401b01b32e00501b02001b", + "0x32e00532600532901b01b32e00520300532901b01b32e0050480052ea01b", + "0x52ea00502a01b2ea00532e00501b05701b2eb00532e00501b33001b01b", + "0x1b2e700532e00501b32601b2e800532e0052ea2eb00703101b2ea00532e", + "0x3f00504601b08500532e00509900551f01b09900532e0052e82e70070c9", + "0x700532e00500700531e01b04500532e00504500531f01b03f00532e005", + "0x1b32e00501b00701b08500704503f04700508500532e00508500552101b", + "0x1b32e0050480052ea01b01b32e00520700505401b01b32e00501b02001b", + "0x532e00501b33001b01b32e00532600532901b01b32e00503800521601b", + "0x2e600703101b2e400532e0052e400502a01b2e400532e00501b05701b2e6", + "0x532e0052e309d0070c901b09d00532e00501b32601b2e300532e0052e4", + "0x531f01b03f00532e00503f00504601b0a400532e0052e200551f01b2e2", + "0x532e0050a400552101b00700532e00500700531e01b04500532e005045", + "0x1b01b32e00501b02001b01b32e00501b00701b0a400704503f0470050a4", + "0x1b32e00533000521601b01b32e0050480052ea01b01b32e0050c9005054", + "0x32e0052e100502a01b2e100532e00501b05701b0a000532e00501b33001b", + "0xc901b0a800532e00501b32601b2df00532e0052e10a000703101b2e1005", + "0x503f00504601b2dd00532e0050aa00551f01b0aa00532e0052df0a8007", + "0x1b00700532e00500700531e01b04500532e00504500531f01b03f00532e", + "0x1b01b32e00501b00701b2dd00704503f0470052dd00532e0052dd005521", + "0x1b32e0050480052ea01b01b32e00504200521601b01b32e00507b00504c", + "0x32e0052db00502a01b2db00532e00501b33601b0ad00532e00501b33001b", + "0xc901b2d900532e00501b32601b2da00532e0052db0ad00703101b2db005", + "0x502300504601b2d700532e0052d800551f01b2d800532e0052da2d9007", + "0x1b00700532e00500700531e01b04500532e00504500531f01b02300532e", + "0x1b01b32e00501b00701b2d70070450230470052d700532e0052d7005521", + "0xb200532e00501b33001b01b32e0050480052ea01b01b32e005047005216", + "0x2d60b200703101b2d600532e0052d600502a01b2d600532e00501b22901b", + "0x4a00532e0052d52d40070c901b2d400532e00501b32601b2d500532e005", + "0x4300531f01b04400532e00504400504601b35700532e00504a00551f01b", + "0x35700532e00535700552101b00700532e00500700531e01b04300532e005", + "0x732e00700501b00700501b01b32e00501b02001b357007043044047005", + "0x4800732e0050480052d201b01b32e00501b00701b04404500761c046047", + "0x1b04200561d01b32e0070430052dd01b04700532e00504700504601b043", + "0x1b01b32e00504800532901b01b32e0050070052ea01b01b32e00501b007", + "0x532e00504000502a01b04000532e00501b52801b04100532e00501b330", + "0x70c901b03f00532e00501b32601b19400532e00504004100703101b040", + "0x32e00504700504601b02300532e00503e00529501b03e00532e00519403f", + "0x4800502300532e0050230050eb01b04600532e00504600531f01b047005", + "0x501b23401b01b32e0050420052da01b01b32e00501b00701b023046047", + "0x4700532e00504700504601b02000532e00507b04800735801b07b00532e", + "0x470470bd01b02000532e00502000502a01b04600532e00504600531f01b", + "0x1b32e00501b00701b00932b19104800500932b19104832e005020007046", + "0x532e00501b33001b01b32e0050070052ea01b01b32e00504800532901b", + "0x32900703101b33000532e00533000502a01b33000532e00501b22901b329", + "0x532e00502d02a0070c901b02a00532e00501b32601b02d00532e005330", + "0x531f01b04500532e00504500504601b32600532e00503100529501b031", + "0x2001b32604404504800532600532e0053260050eb01b04400532e005044", + "0x701b04404500761e04604700732e00700501b00700501b01b32e00501b", + "0x532e00504700504601b04304800732e0050480052d201b01b32e00501b", + "0x532901b01b32e00501b00701b04200561f01b32e0070430052dd01b047", + "0x4000532e00504100700718d01b04100532e00501b03f01b01b32e005048", + "0x4600531f01b04700532e00504700504601b19400532e00504000518f01b", + "0x1b00701b19404604704800519400532e0051940050eb01b04600532e005", + "0x735801b03f00532e00501b23401b01b32e0050420052da01b01b32e005", + "0x32e00504600531f01b04700532e00504700504601b03e00532e00503f048", + "0x4832e00503e0070460470470c101b03e00532e00503e00502a01b046005", + "0x32e00504800532901b01b32e00501b00701b02007b02304800502007b023", + "0x32e00501b22901b19100532e00501b33001b01b32e0050070052ea01b01b", + "0x1b00900532e00532b19100703101b32b00532e00532b00502a01b32b005", + "0x533000529501b33000532e0050093290070c901b32900532e00501b326", + "0x1b04400532e00504400531f01b04500532e00504500504601b02d00532e", + "0x1b04300532e00501b52901b02d04404504800502d00532e00502d0050eb", + "0x4100552d01b04004100732e00504200552c01b04200532e00504300552b", + "0x1b03f00532e00519400504301b19400532e00504000552f01b01b32e005", + "0x704853001b03f00532e00503f00502a01b03e04600732e0050460052d2", + "0x7b01b00753101b07b00532e00507b00502a01b07b02300732e00503e03f", + "0x732e00532b00553301b32b00532e00519100553201b19102000732e005", + "0x553601b33000532e00532900553501b01b32e00500900553401b329009", + "0x32e00502a0052b001b02a02d00732e00502d00553701b02d00532e005330", + "0x20701b0c932600732e0053260051fb01b32600532e00501b31c01b031005", + "0x32e00502000504601b02300532e00502300535d01b0c900532e0050c9005", + "0x3803903704862031e31f32004832e0070310c904800504721101b020005", + "0x32e00503602d00733501b03600532e00501b53801b01b32e00501b00701b", + "0x2aa01b32600532e00532600520701b32000532e00532000531f01b31c005", + "0x32631f32004721101b31e00532e00531e00502a01b31c00532e00531c005", + "0x52901b01b32e00501b00701b21421120d0486212072031fb04832e00731c", + "0x732e00521800552c01b21800532e00521600552b01b21600532e00501b", + "0x504301b22800532e00522200552f01b01b32e00521c00552d01b22221c", + "0x504604c02304853001b04c00532e00504c00502a01b04c00532e005228", + "0x732e00505402000753101b05400532e00505400502a01b05422900732e", + "0x1b23100532e0050550052b001b05505200732e00505200553701b052051", + "0x52340051fb01b23400532e00501b31c01b23200532e00504531e0072ab", + "0x5700532e00505700520701b1fb00532e0051fb00531f01b05723400732e", + "0x22900535d01b20700532e00520700502a01b23200532e00523200502a01b", + "0x2322310572031fb04620d01b05100532e00505100504601b22900532e005", + "0x501b53801b01b32e00501b00701b24923a05604862205805900732e007", + "0x532e0050442070072ab01b05f00532e00503305200733501b03300532e", + "0x52aa01b23400532e00523400520701b05900532e00505900531f01b254", + "0x5f23405805904620d01b25400532e00525400502a01b05f00532e00505f", + "0x1b03f01b01b32e00501b00701b06900626c04862306106200732e007254", + "0x532e0052d300518f01b2d300532e00506b04700718d01b06b00532e005", + "0x535d01b06200532e00506200531f01b05100532e00505100504601b06e", + "0x532e00506e0050eb01b06100532e00506100531e01b22900532e005229", + "0x32e0050470052ea01b01b32e00501b00701b06e06122906205104600506e", + "0x522801b07100532e00500600531e01b06f00532e00526c00531f01b01b", + "0x52ea01b01b32e00501b00701b01b62400501b19401b2ee00532e005069", + "0x4c01b01b32e00520700532901b01b32e00505200553901b01b32e005047", + "0x6f00532e00505600531f01b01b32e00504400532901b01b32e005234005", + "0x501b32601b2ee00532e00524900522801b07100532e00523a00531e01b", + "0x31100532e00507600529501b07600532e0052ee0340070c901b03400532e", + "0x22900535d01b06f00532e00506f00531f01b05100532e00505100504601b", + "0x31100532e0053110050eb01b07100532e00507100531e01b22900532e005", + "0x1b32e00504500532901b01b32e00501b00701b31107122906f051046005", + "0x32e00504600532901b01b32e00531e00532901b01b32e0050470052ea01b", + "0x21100531e01b07300532e00520d00531f01b01b32e00504400532901b01b", + "0x701b01b62500501b19401b07a00532e00521400522801b07200532e005", + "0x4c01b01b32e0050470052ea01b01b32e00504500532901b01b32e00501b", + "0x1b01b32e00504400532901b01b32e00504600532901b01b32e005326005", + "0x32e00503900531e01b07300532e00503700531f01b01b32e00502d005539", + "0x70c901b07400532e00501b32601b07a00532e00503800522801b072005", + "0x32e00502000504601b30e00532e00530f00529501b30f00532e00507a074", + "0x31e01b02300532e00502300535d01b07300532e00507300531f01b020005", + "0x7202307302004600530e00532e00530e0050eb01b07200532e005072005", + "0x562604704800732e00700700504501b00700532e00500500504801b30e", + "0x504500504301b04500532e00504700504401b01b32e00501b00701b046", + "0x1b04200532e00504800504101b04300532e00504400504201b04400532e", + "0x1b01b32e00501b00701b01b62700501b19401b04100532e005043005040", + "0x32e00504600504101b19400532e00504000503e01b04000532e00501b03f", + "0x562803f00532e00704100502301b04100532e00519400504001b042005", + "0x1b02000562907b02300732e00704200504501b01b32e00501b00701b03e", + "0x532e00502300504101b19100532e00507b00524901b01b32e00501b007", + "0x32e00501b00701b01b62a00501b19401b00900532e00519100503301b32b", + "0x2000504101b33000532e00532900505f01b32900532e00501b03f01b01b", + "0x2d00532e00700900525401b00900532e00533000503301b32b00532e005", + "0x504301b03100532e00502d00504401b01b32e00501b00701b02a00562b", + "0x32e00732601b00728f01b32600532e00532600502a01b32600532e005031", + "0x32e0050c900504601b01b32e00501b00701b03731e31f04862c3200c9007", + "0x1b32e00501b00701b03600562d03803900732e00732b00504501b0c9005", + "0x31c00503301b1fb00532e00503900504101b31c00532e00503800524901b", + "0x501b03f01b01b32e00501b00701b01b62e00501b19401b20300532e005", + "0x1b1fb00532e00503600504101b20d00532e00520700505f01b20700532e", + "0x701b21400562f21100532e00720300525401b20300532e00520d005033", + "0x21800532e00521600504301b21600532e00521100504401b01b32e00501b", + "0x4863022221c00732e0072180c900728f01b21800532e00521800502a01b", + "0x53b01b05400532e00522232000753a01b01b32e00501b00701b22904c228", + "0x32e0051fb00504101b05200532e00521c00504601b05100532e005054005", + "0x501b00701b01b63100501b19401b23100532e00505100553c01b055005", + "0x32000511501b01b32e00522900511501b01b32e00504c00511501b01b32e", + "0x1b00701b01b63200501b19401b23200532e00522800504601b01b32e005", + "0x504601b01b32e00532000511501b01b32e00521400505401b01b32e005", + "0x5700532e00523400553d01b23400532e00501b03f01b23200532e0050c9", + "0x5700553c01b05500532e0051fb00504101b05200532e00523200514401b", + "0x31e00511501b01b32e00501b00701b01b63100501b19401b23100532e005", + "0x19401b05900532e00531f00504601b01b32e00503700511501b01b32e005", + "0x504601b01b32e00502a00505401b01b32e00501b00701b01b63300501b", + "0x5600532e00505800553d01b05800532e00501b03f01b05900532e00501b", + "0x5600553c01b05500532e00532b00504101b05200532e00505900514401b", + "0x24900532e00723100553e01b23a00532e00505500521801b23100532e005", + "0x54001b05f00532e00524903f00753f01b01b32e00501b00701b033005634", + "0x32e00523a00506201b05200532e00505200504601b25400532e00505f005", + "0x32e00501b00701b25423a05204800525400532e00525400554101b23a005", + "0x5200504601b06200532e00503300554201b01b32e00503f00532901b01b", + "0x6200532e00506200554101b23a00532e00523a00506201b05200532e005", + "0x1b06100532e00504200521801b01b32e00501b00701b06223a052048005", + "0x506100506201b01b00532e00501b00504601b26c00532e00503e005542", + "0x450052c101b26c06101b04800526c00532e00526c00554101b06100532e", + "0x4100532e00504200552b01b04200532e00501b52901b04304400732e005", + "0x19400552f01b01b32e00504000552d01b19404000732e00504100552c01b", + "0x4400732e0050440052d201b03e00532e00503f00504301b03f00532e005", + "0x2007b00732e00502303e04804853001b03e00532e00503e00502a01b023", + "0x53201b32b19100732e00502001b00753101b02000532e00502000502a01b", + "0x532900553401b33032900732e00500900553301b00900532e00532b005", + "0x53701b02a00532e00502d00553601b02d00532e00533000553501b01b32e", + "0x32e00501b31c01b32600532e0050310052b001b03102a00732e00502a005", + "0x1b32000532e00532000520701b3200c900732e0050c90051fb01b0c9005", + "0x4700504721101b19100532e00519100504601b07b00532e00507b00535d", + "0x1b01b32e00501b00701b03603803904863503731e31f04832e007326320", + "0x531f00531f01b1fb00532e00531c02a00733501b31c00532e00501b538", + "0x1b1fb00532e0051fb0052aa01b0c900532e0050c900520701b31f00532e", + "0x20d20720304832e0071fb0c931e31f04721101b03700532e00503700502a", + "0x1b20300532e00520300531f01b01b32e00501b00701b216214211048636", + "0x3719100728f01b20d00532e00520d00502a01b20700532e00520700531e", + "0x21800728f01b01b32e00501b00701b04c22822204863721c21800732e007", + "0x52be01b01b32e00501b00701b05505205104863805422900732e00720d", + "0x1b05805905723404732e00523121c00704854301b23223100732e005043", + "0x532e0050590050c401b01b32e00505800511501b01b32e005057005115", + "0x32e00524900511501b05f03324923a04732e00523205423404854301b056", + "0x501b52901b25400532e0050330050c401b01b32e00505f00511501b01b", + "0x626c00732e00506100552c01b06100532e00506200552b01b06200532e", + "0x506900504301b06900532e00500600552f01b01b32e00526c00552d01b", + "0x732e00504406b07b04853001b06b00532e00506b00502a01b06b00532e", + "0x7106f00732e00506e22900753101b06e00532e00506e00502a01b06e2d3", + "0x1b31c01b03400532e0052ee0052b001b2ee07100732e00507100553701b", + "0x532e00531100520701b31107600732e0050760051fb01b07600532e005", + "0x502a01b23a00532e00523a0052d401b05600532e00505600502a01b311", + "0x532e00506f00504601b2d300532e0052d300535d01b25400532e005254", + "0x1b30f07407a04863907207300732e00705603431120720304620d01b06f", + "0x532e00530e07100733501b30e00532e00501b53801b01b32e00501b007", + "0x52aa01b07600532e00507600520701b07300532e00507300531f01b30d", + "0x4863a30b30c00732e00725430d07607207304620d01b30d00532e00530d", + "0x4600718d01b08600532e00501b03f01b01b32e00501b00701b30530930a", + "0x532e00506f00504601b30300532e00530400518f01b30400532e005086", + "0x535d01b23a00532e00523a0052d401b30c00532e00530c00531f01b06f", + "0x532e0053030050eb01b30b00532e00530b00531e01b2d300532e0052d3", + "0x50460052ea01b01b32e00501b00701b30330b2d323a30c06f045005303", + "0x22801b30200532e00530900531e01b08400532e00530a00531f01b01b32e", + "0x2ea01b01b32e00501b00701b01b63b00501b19401b30100532e005305005", + "0x1b01b32e00507100553901b01b32e00525400532901b01b32e005046005", + "0x32e00507400531e01b08400532e00507a00531f01b01b32e00507600504c", + "0x70c901b08200532e00501b32601b30100532e00530f00522801b302005", + "0x32e00506f00504601b2ff00532e00530000529501b30000532e005301082", + "0x35d01b23a00532e00523a0052d401b08400532e00508400531f01b06f005", + "0x32e0052ff0050eb01b30200532e00530200531e01b2d300532e0052d3005", + "0x5200511501b01b32e00501b00701b2ff3022d323a08406f0450052ff005", + "0x50cd01b01b32e0050460052ea01b01b32e00505500511501b01b32e005", + "0x33001b01b32e00521c00511501b01b32e00504400532901b01b32e005043", + "0x8700532e00508700502a01b08700532e00501b05701b07d00532e00501b", + "0x2fc0070c901b2fc00532e00501b32601b33800532e00508707d00703101b", + "0x532e00505100504601b2fa00532e0052fb00529501b2fb00532e005338", + "0x535d01b00700532e0050070052d401b20300532e00520300531f01b051", + "0x532e0052fa0050eb01b20700532e00520700531e01b07b00532e00507b", + "0x522800511501b01b32e00501b00701b2fa20707b0072030510450052fa", + "0x430050cd01b01b32e0050460052ea01b01b32e00504c00511501b01b32e", + "0x1b33001b01b32e00520d00532901b01b32e00504400532901b01b32e005", + "0x1b2f800532e0052f800502a01b2f800532e00501b05701b2f900532e005", + "0x2f72f60070c901b2f600532e00501b32601b2f700532e0052f82f9007031", + "0x22200532e00522200504601b2f400532e0052f500529501b2f500532e005", + "0x7b00535d01b00700532e0050070052d401b20300532e00520300531f01b", + "0x2f400532e0052f40050eb01b20700532e00520700531e01b07b00532e005", + "0x32e00503700532901b01b32e00501b00701b2f420707b007203222045005", + "0x504400532901b01b32e0050430050cd01b01b32e0050460052ea01b01b", + "0x22801b2f200532e00521400531e01b2f300532e00521100531f01b01b32e", + "0x4c01b01b32e00501b00701b01b63c00501b19401b2f100532e005216005", + "0x1b01b32e0050430050cd01b01b32e0050460052ea01b01b32e0050c9005", + "0x532e00503900531f01b01b32e00502a00553901b01b32e005044005329", + "0x1b32601b2f100532e00503600522801b2f200532e00503800531e01b2f3", + "0x532e00507c00529501b07c00532e0052f12ef0070c901b2ef00532e005", + "0x52d401b2f300532e0052f300531f01b19100532e00519100504601b08b", + "0x532e0052f200531e01b07b00532e00507b00535d01b00700532e005007", + "0x1b54401b08b2f207b0072f319104500508b00532e00508b0050eb01b2f2", + "0x1b04600532e00504600502a01b04500532e00501b54501b04600532e005", + "0x701b01b63d04400532e00704504600754601b04500532e00504500502a", + "0x4300532e00504400554801b04400532e00504400554701b01b32e00501b", + "0x32e00504200502a01b04100532e00501b54901b04200532e00501b33401b", + "0x63e04000532e00704104200754601b04100532e00504100502a01b042005", + "0x504000554801b04000532e00504000554701b01b32e00501b00701b01b", + "0x63f01b32e00703f00554c01b03f19400732e00519400554a01b19400532e", + "0x19400554d01b02300532e0050050050ce01b01b32e00501b00701b03e005", + "0x19400554f01b01b32e00501b00701b01b64000501b19401b07b00532e005", + "0x502a01b19100532e00501b55101b02000532e00501b55001b01b32e005", + "0x555301b00932b00732e00503e19102000504755201b19100532e005191", + "0x532e00700900555401b32b00532e00532b0050ce01b00900532e005009", + "0x50ce01b33000532e00532900554801b01b32e00501b00701b01b641329", + "0x1b01b64000501b19401b07b00532e00533000554d01b02300532e00532b", + "0x2300532e00532b0050ce01b02d00532e00501b55501b01b32e00501b007", + "0x554c01b02a07b00732e00507b00554a01b07b00532e00502d00554d01b", + "0x1b32e00507b00554f01b01b32e00501b00701b03100564201b32e00702a", + "0x1b32e00501b00701b01b64300501b19401b32600532e00504300554d01b", + "0x3100555601b01b32e00501b00701b0c900564401b32e00704300554c01b", + "0x1b00701b01b64300501b19401b32600532e00507b00554d01b01b32e005", + "0x755701b32000532e00501b55001b01b32e00507b00554f01b01b32e005", + "0x50c931f00755701b31f00532e00531f00555301b31f00532e005031320", + "0x64503700532e00731e00555401b31e00532e00531e00555301b31e00532e", + "0x503900554d01b03900532e00503700554801b01b32e00501b00701b01b", + "0x32e00501b55501b01b32e00501b00701b01b64300501b19401b32600532e", + "0x3600564601b32e00732600554c01b32600532e00503800554d01b038005", + "0x31c00532e00501b33001b01b32e0050470052ea01b01b32e00501b00701b", + "0x1fb31c00703101b1fb00532e0051fb00502a01b1fb00532e00501b05701b", + "0x20d00532e0052032070070c901b20700532e00501b32601b20300532e005", + "0x230050ce01b01b00532e00501b00504601b21100532e00520d00529501b", + "0x4800532e00504800531e01b00700532e00500700531f01b02300532e005", + "0x32e00501b00701b21104800702301b04600521100532e0052110050eb01b", + "0x553701b21800532e00501b55901b21621400732e00503600555801b01b", + "0x532e00501b31c01b22200532e00521c0052b001b21c21800732e005218", + "0x2aa01b04c00532e00504c00520701b04c22800732e0052280051fb01b228", + "0x64705422900732e00721422204c04800704620d01b22200532e005222005", + "0x555a01b23100532e00501b53801b01b32e00501b00701b055052051048", + "0x32e00522900531f01b23200532e00523121800733501b21800532e005218", + "0x20d01b23200532e0052320052aa01b22800532e00522800520701b229005", + "0x501b00701b05605805904864805723400732e007216232228054229046", + "0x18f01b24900532e00523a04700718d01b23a00532e00501b03f01b01b32e", + "0x32e0050230050ce01b01b00532e00501b00504601b03300532e005249005", + "0xeb01b05700532e00505700531e01b23400532e00523400531f01b023005", + "0x1b01b32e00501b00701b03305723402301b04600503300532e005033005", + "0x32e00505800531e01b05f00532e00505900531f01b01b32e0050470052ea", + "0x501b00701b01b64900501b19401b06200532e00505600522801b254005", + "0x21800553901b01b32e00521600532901b01b32e0050470052ea01b01b32e", + "0x31e01b05f00532e00505100531f01b01b32e00522800504c01b01b32e005", + "0x532e00501b32601b06200532e00505500522801b25400532e005052005", + "0x4601b00600532e00526c00529501b26c00532e0050620610070c901b061", + "0x32e00505f00531f01b02300532e0050230050ce01b01b00532e00501b005", + "0x4600500600532e0050060050eb01b25400532e00525400531e01b05f005", + "0x54f01b01b32e0050470052ea01b01b32e00501b00701b00625405f02301b", + "0x1b06b00532e00501b05701b06900532e00501b33001b01b32e005043005", + "0x501b32601b2d300532e00506b06900703101b06b00532e00506b00502a", + "0x7100532e00506f00529501b06f00532e0052d306e0070c901b06e00532e", + "0x700531f01b00500532e0050050050ce01b01b00532e00501b00504601b", + "0x7100532e0050710050eb01b04800532e00504800531e01b00700532e005", + "0x1b32e0050470052ea01b01b32e00501b00701b07104800700501b046005", + "0x32e00503400502a01b03400532e00501b05701b2ee00532e00501b33001b", + "0xc901b31100532e00501b32601b07600532e0050342ee00703101b034005", + "0x501b00504601b07200532e00507300529501b07300532e005076311007", + "0x1b00700532e00500700531f01b00500532e0050050050ce01b01b00532e", + "0x700501b04600507200532e0050720050eb01b04800532e00504800531e", + "0x701b04004104204864a04304404504832e00704800500712101b072048", + "0x19400532e00504300504901b04300532e00504300528001b01b32e00501b", + "0x1b01b32e00503f00555b01b02007b02303e03f04632e00519400527f01b", + "0x1b32e00502000532901b01b32e00507b00506b01b01b32e00502300506b", + "0x501b52901b19100532e00503e00527901b03e00532e00503e00512c01b", + "0x33032900732e00500900552c01b00900532e00532b00552b01b32b00532e", + "0x502d00504301b02d00532e00533000552f01b01b32e00532900552d01b", + "0x2a00532e00502a00502a01b03104600732e0050460052d201b02a00532e", + "0x1b0c900532e0050c900502a01b0c932600732e00503102a00704853001b", + "0x553301b31e00532e00531f00553201b31f32000732e0050c901b007531", + "0x532e00503900553501b01b32e00503700553401b03903700732e00531e", + "0x2b001b31c03600732e00503600553701b03600532e00503800553601b038", + "0x732e0052030051fb01b20300532e00501b31c01b1fb00532e00531c005", + "0x2e701b20700532e00520700520701b04500532e00504500531f01b207203", + "0x32e00532000504601b32600532e00532600535d01b19100532e005191005", + "0x21c21821604864b21421120d04832e0071fb20704404504721101b320005", + "0x32e00522203600733501b22200532e00501b53801b01b32e00501b00701b", + "0x2aa01b20300532e00520300520701b20d00532e00520d00531f01b228005", + "0x20321120d04721101b21400532e00521400502a01b22800532e005228005", + "0x27601b01b32e00501b00701b05505205104864c05422904c04832e007228", + "0x32901b06225405f03324923a05605805905723423223103f32e005191005", + "0x1b01b32e00523400511501b01b32e00523200506b01b01b32e005231005", + "0x1b32e00505600532901b01b32e00505800532901b01b32e005059005329", + "0x32e00503300505501b01b32e00524900511501b01b32e00523a00511901b", + "0x506200505501b01b32e00525400504c01b01b32e00505f00504c01b01b", + "0x4801b26c05700732e00505700529d01b06100532e00501b31c01b01b32e", + "0x32e00504c00531f01b06100532e00506100520701b00600532e00526c005", + "0x18901b05400532e00505400502a01b22900532e00522900531e01b04c005", + "0x18b01b01b32e00501b00701b2d300564d06b06900732e007061006320048", + "0x532e00501b33301b06e00532e00506b00504401b06b00532e00506b005", + "0x502a01b06f00532e00506f00520701b07100532e00505700504801b06f", + "0x1b07600564e0342ee00732e00706f07106904818901b06e00532e00506e", + "0x532e00503400504401b03400532e00503400518b01b01b32e00501b007", + "0x7200552c01b07200532e00507300552b01b07300532e00501b52901b311", + "0x30f00532e00507400552f01b01b32e00507a00552d01b07407a00732e005", + "0x32604853001b30e00532e00530e00502a01b30e00532e00530f00504301b", + "0x30c2ee00753101b30c00532e00530c00502a01b30c30d00732e00504630e", + "0x32e0053090052b001b30930a00732e00530a00553701b30a30b00732e005", + "0x1b30400532e0050862140072ab01b08600532e00506e00504301b305005", + "0x508400520701b08430300732e0053030051fb01b30300532e00501b31c", + "0x1b31100532e00531100502a01b30400532e00530400502a01b08400532e", + "0x22904c04620d01b30b00532e00530b00504601b30d00532e00530d00535d", + "0x1b01b32e00501b00701b2ff30008204864f30130200732e007304305084", + "0x531100504301b08700532e00507d30a00733501b07d00532e00501b538", + "0x30200532e00530200531f01b2fc00532e0053380540072ab01b33800532e", + "0x2fc00502a01b08700532e0050870052aa01b30300532e00530300520701b", + "0x2f90486502fa2fb00732e0072fc08730330130204620d01b2fc00532e005", + "0x2f604700718d01b2f600532e00501b03f01b01b32e00501b00701b2f72f8", + "0x30b00532e00530b00504601b2f400532e0052f500518f01b2f500532e005", + "0x2fa00531e01b30d00532e00530d00535d01b2fb00532e0052fb00531f01b", + "0x1b2f42fa30d2fb30b0460052f400532e0052f40050eb01b2fa00532e005", + "0x2f300532e0052f900531f01b01b32e0050470052ea01b01b32e00501b007", + "0x501b19401b2f100532e0052f700522801b2f200532e0052f800531e01b", + "0x530a00553901b01b32e0050470052ea01b01b32e00501b00701b01b651", + "0x5400532901b01b32e00530300504c01b01b32e00531100532901b01b32e", + "0x1b2f200532e00530000531e01b2f300532e00508200531f01b01b32e005", + "0x52f12ef0070c901b2ef00532e00501b32601b2f100532e0052ff005228", + "0x1b30b00532e00530b00504601b08b00532e00507c00529501b07c00532e", + "0x52f200531e01b30d00532e00530d00535d01b2f300532e0052f300531f", + "0x701b08b2f230d2f330b04600508b00532e00508b0050eb01b2f200532e", + "0x32901b01b32e0050470052ea01b01b32e00521400532901b01b32e00501b", + "0x1b01b32e00505400532901b01b32e00506e00532901b01b32e005046005", + "0x532e0052ed00502a01b2ed00532e00501b24701b08d00532e00501b330", + "0x70c901b2ec00532e00501b32601b09000532e0052ed08d00703101b2ed", + "0x32e00507600504601b2eb00532e00508e00529501b08e00532e0050902ec", + "0x31e01b32600532e00532600535d01b04c00532e00504c00531f01b076005", + "0x22932604c0760460052eb00532e0052eb0050eb01b22900532e005229005", + "0x32e0050470052ea01b01b32e00521400532901b01b32e00501b00701b2eb", + "0x505400532901b01b32e00505700505501b01b32e00504600532901b01b", + "0x2e800502a01b2e800532e00501b24701b2ea00532e00501b33001b01b32e", + "0x9900532e00501b32601b2e700532e0052e82ea00703101b2e800532e005", + "0x504601b2e600532e00508500529501b08500532e0052e70990070c901b", + "0x532e00532600535d01b04c00532e00504c00531f01b2d300532e0052d3", + "0x2d30460052e600532e0052e60050eb01b22900532e00522900531e01b326", + "0x52ea01b01b32e00521400532901b01b32e00501b00701b2e622932604c", + "0x31f01b01b32e0051910052ec01b01b32e00504600532901b01b32e005047", + "0x32e00505500522801b2e300532e00505200531e01b2e400532e005051005", + "0x32e00520300504c01b01b32e00501b00701b01b65200501b19401b09d005", + "0x51910052ec01b01b32e00504600532901b01b32e0050470052ea01b01b", + "0x531e01b2e400532e00521600531f01b01b32e00503600553901b01b32e", + "0x2e200532e00501b32601b09d00532e00521c00522801b2e300532e005218", + "0x504601b0a000532e0050a400529501b0a400532e00509d2e20070c901b", + "0x532e00532600535d01b2e400532e0052e400531f01b32000532e005320", + "0x3200460050a000532e0050a00050eb01b2e300532e0052e300531e01b326", + "0x532901b01b32e0050470052ea01b01b32e00501b00701b0a02e33262e4", + "0x2df00532e0050402e10070c901b2e100532e00501b32601b01b32e005046", + "0x4200531f01b01b00532e00501b00504601b0a800532e0052df00529501b", + "0x4100532e00504100531e01b00700532e00500700535d01b04200532e005", + "0x32e00501b55c01b0a804100704201b0460050a800532e0050a80050eb01b", + "0x501b55f01b04000532e00501b55e01b04200532e00501b55d01b044005", + "0x32e00501b33201b01b32e00501b02001b01b32e00501b05801b03f00532e", + "0x501b56001b07b00532e00501b56001b02300532e00501b56001b03e005", + "0x32e00519100556201b19100532e00502007b02303e04756101b02000532e", + "0x56401b01b32e00501b00701b01b65332b00532e00719100556301b191005", + "0x32e00533000556501b33000532e00501b33901b32900900732e005048005", + "0x1b56001b03100532e00502a00556501b02a00532e00501b56001b02d005", + "0x1b32000532e00501b56001b0c900532e00532600556501b32600532e005", + "0x56701b31e00532e00531f0c903102d04756601b31f00532e005320005565", + "0x32e0050090050d201b31e00532e00531e00556801b32900532e005329005", + "0x1b32e00501b00701b03900565403700532e00731e32900756901b009005", + "0x32e00504000556c01b01b32e0050460052ea01b01b32e00503700556b01b", + "0x503f00557001b01b32e00504400556f01b01b32e00504200556e01b01b", + "0x501b29a01b03800532e00501b33001b01b32e00532b00557101b01b32e", + "0x31c00532e00503603800703101b03600532e00503600502a01b03600532e", + "0x1fb31c00703101b1fb00532e0051fb00502a01b1fb00532e00501b23201b", + "0x1b20700532e00520700502a01b20700532e00501b57201b20300532e005", + "0x521100502a01b21100532e00501b33101b20d00532e005207203007031", + "0x1b21600532e00501b32601b21400532e00521120d00703101b21100532e", + "0x1b00504601b21c00532e00521800529501b21800532e0052142160070c9", + "0x700532e0050070050d401b00500532e0050050052c501b01b00532e005", + "0x21c0050eb01b04700532e00504700531f01b00900532e0050090050d201b", + "0x57301b01b32e00501b00701b21c04700900700501b04500521c00532e005", + "0x4c00532e00501b56001b22800532e00522200556501b22200532e00501b", + "0x505400556501b05400532e00501b56001b22900532e00504c00556501b", + "0x56601b05500532e00505200556501b05200532e00501b56001b05100532e", + "0x756901b23100532e00523100556801b23100532e005055051229228047", + "0x32e00501b57401b01b32e00501b00701b23400565523200532e007231039", + "0x5900557701b05800532e00501b57601b05900532e00501b57501b057005", + "0x32b23205700700504457901b05800532e00505800557801b05900532e005", + "0x1b32e00501b00701b05f03324923a04765605619404504832e007058059", + "0x4504400757b01b01b32e00501b04701b06225400732e00505600557a01b", + "0x532e00706200557d01b19400532e00519403f00757c01b04500532e005", + "0x565800600532e00706100557e01b01b32e00501b00701b26c005657061", + "0x701b2d300565906b00532e00700600557f01b01b32e00501b00701b069", + "0x6f00532e00506e00558101b06e00532e00506b00558001b01b32e00501b", + "0x6f00532e0052d300558101b01b32e00501b00701b01b65a00501b19401b", + "0x6f00532e00506900558101b01b32e00501b00701b01b65a00501b19401b", + "0x6f00532e00526c00558101b01b32e00501b00701b01b65a00501b19401b", + "0x525400558301b04100532e00506f00900758201b01b32e00501b02001b", + "0x56001b03400532e00501b57301b01b32e00507100558401b2ee07100732e", + "0x1b07300532e00501b56001b31100532e00501b56001b07600532e00501b", + "0x1b07407a00732e00507200558301b07200532e005073311076034047585", + "0x32e00507400558601b2ee00532e0052ee00558601b01b32e00507a005584", + "0x4100532e00504104000758801b30f00532e0050742ee00758701b074005", + "0x505401b01b32e00501b00701b30d00565b30e00532e00730f00514201b", + "0x23201b30c00532e00501b58901b01b32e0050460052ea01b01b32e00530e", + "0x1b30900532e00501b58a01b30a00532e00501b31c01b30b00532e00501b", + "0x1b00504601b08600532e00530a30b30c04858c01b30500532e00501b58b", + "0x30900532e00530900502a01b08600532e00508600558d01b01b00532e005", + "0x30330400732e00530530908601b04758e01b30500532e00530500520701b", + "0x559101b01b32e00501b00701b30200565c08400532e00730300559001b", + "0x30000532e00501b59301b01b32e00508200505401b08230100732e005084", + "0x530100558d01b30400532e00530400504601b2ff00532e00501b58b01b", + "0x1b2ff00532e0052ff00520701b30000532e00530000502a01b30100532e", + "0x65d33800532e00708700559001b08707d00732e0052ff30030130404758e", + "0x505401b2fa2fb00732e00533800559101b01b32e00501b00701b2fc005", + "0x4601b2f800532e00501b58b01b2f900532e00501b59401b01b32e0052fa", + "0x32e0052f900502a01b2fb00532e0052fb00558d01b07d00532e00507d005", + "0x732e0052f82f92fb07d04758e01b2f800532e0052f800520701b2f9005", + "0x1b01b32e00501b00701b2f400565e2f500532e0072f600559001b2f62f7", + "0x32e00501b59501b01b32e0052f200505401b2f22f300732e0052f5005591", + "0x558d01b2f700532e0052f700504601b2ef00532e00501b59601b2f1005", + "0x532e0052ef00520701b2f100532e0052f100502a01b2f300532e0052f3", + "0x532e00708b00559001b08b07c00732e0052ef2f12f32f704758e01b2ef", + "0x1b29a01b09000532e00501b33001b01b32e00501b00701b2ed00565f08d", + "0x532e0052ec09000703101b2ec00532e0052ec00502a01b2ec00532e005", + "0x759801b01b32e0052eb00505401b2eb04300732e00508d00559101b08e", + "0x52ea00559a01b2e82ea00732e00504300559901b04300532e005043042", + "0x8509904832e0052e700559b01b2e72e800732e0052e800533b01b01b32e", + "0x509900559d01b01b32e0052e600504c01b01b32e00508500532901b2e6", + "0x9d00532e0052e300530501b2e300532e0052e400559e01b2e409900732e", + "0x559f01b2e200532e00509d08e00703101b09d00532e00509d00502a01b", + "0x532e00504700531f01b07c00532e00507c00504601b0a400532e005099", + "0x475a101b2e200532e0052e200522801b0a400532e0050a400533c01b047", + "0x2df00530c01b01b32e00501b04701b2df2e10a004832e0052e20a404707c", + "0x732e0050a800530b01b01b32e00501b00701b0aa0056600a800532e007", + "0x59b01b2db2e800732e0052e800533b01b01b32e0050ad00505401b0ad2dd", + "0x52d800504c01b01b32e0052da0055a201b2d82d92da04832e0052db005", + "0x1b0b200532e0052d72dd00703101b2d700532e0052d900504301b01b32e", + "0x2d500532901b01b32e0052d60055a201b2d42d52d604832e0052e800559b", + "0x1b35700532e00504a00530501b04a00532e0052d400514801b01b32e005", + "0x501b19401b35a00532e00535800522801b35800532e0053570b2007031", + "0x50aa00530401b01b32e0052e80055a401b01b32e00501b00701b01b661", + "0x1b35a00532e00535b00522801b01b32e0050cf00530301b35b0cf00732e", + "0x532e00535a0b90070c901b0b900532e00501b32601b01b32e00501b020", + "0x52c501b0a000532e0050a000504601b0bb00532e0050b800529501b0b8", + "0x532e0050410050d201b19400532e0051940050d401b04500532e005045", + "0xa00450050bb00532e0050bb0050eb01b2e100532e0052e100531f01b041", + "0x29501b01b32e00504200556e01b01b32e00501b00701b0bb2e1041194045", + "0x32e0050450052c501b07c00532e00507c00504601b0bd00532e0052ed005", + "0x31f01b04100532e0050410050d201b19400532e0051940050d401b045005", + "0x4119404507c0450050bd00532e0050bd0050eb01b04700532e005047005", + "0x52f400529501b01b32e00504200556e01b01b32e00501b00701b0bd047", + "0x1b04500532e0050450052c501b2f700532e0052f700504601b0c100532e", + "0x504700531f01b04100532e0050410050d201b19400532e0051940050d4", + "0x1b0c10470411940452f70450050c100532e0050c10050eb01b04700532e", + "0x2d200532e0052fc00529501b01b32e00504200556e01b01b32e00501b007", + "0x1940050d401b04500532e0050450052c501b07d00532e00507d00504601b", + "0x4700532e00504700531f01b04100532e0050410050d201b19400532e005", + "0x501b00701b2d204704119404507d0450052d200532e0052d20050eb01b", + "0x504601b32f00532e00530200529501b01b32e00504200556e01b01b32e", + "0x532e0051940050d401b04500532e0050450052c501b30400532e005304", + "0x50eb01b04700532e00504700531f01b04100532e0050410050d201b194", + "0x1b01b32e00501b00701b32f04704119404530404500532f00532e00532f", + "0x2de00532e00501b03f01b01b32e00504200556e01b01b32e00530d005054", + "0x504601b2cc00532e00535d00518f01b35d00532e0052de04600718d01b", + "0x532e0051940050d401b04500532e0050450052c501b01b00532e00501b", + "0x50eb01b04700532e00504700531f01b04100532e0050410050d201b194", + "0x1b01b32e00501b00701b2cc04704119404501b0450052cc00532e0052cc", + "0x1b32e00504000556c01b01b32e0050460052ea01b01b32e0050330055a5", + "0x32e00503f00557001b01b32e00504400556f01b01b32e00504200556e01b", + "0x52cb00502a01b2cb00532e00501b5a701b0c600532e00501b33001b01b", + "0x1b35f00532e00501b57501b0c700532e0052cb0c600703101b2cb00532e", + "0x32e00535f00557701b24900532e0052490050d401b2c900532e00501b576", + "0x32e0052c935f05f2490090465a801b2c900532e0052c900557801b35f005", + "0x22801b23a00532e00523a0052c501b01b32e00501b04701b2c12c72c8048", + "0x32e0052c70050d401b2c800532e0052c80050d201b0c700532e0050c7005", + "0x1b01b32e00501b00701b2be0056620cd00532e0072c100557d01b2c7005", + "0x2bc00557f01b01b32e00501b00701b0c40056632bc00532e0070cd00557e", + "0x532e0052bf00558001b01b32e00501b00701b0ce0056642bf00532e007", + "0x32e00501b00701b01b66500501b19401b2b900532e0052c600558101b2c6", + "0x32e00501b00701b01b66500501b19401b2b900532e0050ce00558101b01b", + "0x32e00501b00701b01b66500501b19401b2b900532e0050c400558101b01b", + "0x2b92c800758201b01b32e00501b02001b2b900532e0052be00558101b01b", + "0xd200532e0050c72b70070c901b2b700532e00501b32601b2b800532e005", + "0x23a0052c501b01b00532e00501b00504601b2c500532e0050d200529501b", + "0x2b800532e0052b80050d201b2c700532e0052c70050d401b23a00532e005", + "0x23a01b0450052c500532e0052c50050eb01b04700532e00504700531f01b", + "0x52ea01b01b32e0052340055a901b01b32e00501b00701b2c50472b82c7", + "0x56f01b01b32e00504200556e01b01b32e00504000556c01b01b32e005046", + "0x1b01b32e00532b00557101b01b32e00503f00557001b01b32e005044005", + "0x532e0052c200502a01b2c200532e00501b29a01b0d400532e00501b330", + "0x502a01b0d600532e00501b23401b2c300532e0052c20d400703101b2c2", + "0x532e00501b5aa01b2c400532e0050d62c300703101b0d600532e0050d6", + "0x23201b2ae00532e0052b62c400703101b2b600532e0052b600502a01b2b6", + "0x32e0052b02ae00703101b2b000532e0052b000502a01b2b000532e00501b", + "0x703101b2aa00532e0052aa00502a01b2aa00532e00501b23201b2ab005", + "0x32e0050dc2a80070c901b2a800532e00501b32601b0dc00532e0052aa2ab", + "0x2c501b01b00532e00501b00504601b2a500532e0052a600529501b2a6005", + "0x32e0050090050d201b00700532e0050070050d401b00500532e005005005", + "0x450052a500532e0052a50050eb01b04700532e00504700531f01b009005", + "0x1b01b32e0050460052ea01b01b32e00501b00701b2a504700900700501b", + "0x1b32e00504400556f01b01b32e00504200556e01b01b32e00504000556c", + "0x532e00501b05701b0e000532e00501b33001b01b32e00503f00557001b", + "0x32601b2a100532e0052a30e000703101b2a300532e0052a300502a01b2a3", + "0x32e0052a000529501b2a000532e0052a10e10070c901b0e100532e00501b", + "0xd401b00500532e0050050052c501b01b00532e00501b00504601b29d005", + "0x32e00504700531f01b04800532e0050480050d201b00700532e005007005", + "0x5ab01b29d04704800700501b04500529d00532e00529d0050eb01b047005", + "0x32e00504800556501b04800532e00501b33901b00700500732e00501b005", + "0x1b56001b04500532e00504600556501b04600532e00501b56001b047005", + "0x1b04200532e00501b56001b04300532e00504400556501b04400532e005", + "0x5ac01b04000532e00504104304504704756601b04100532e005042005565", + "0x32e0050050050d201b04000532e00504000556801b00700532e005007005", + "0x1b32e00501b00701b03f00566619400532e0070400070075ad01b005005", + "0x1b01b32e00501b00701b01b66700501b19401b01b32e0051940055ae01b", + "0x532e00503e00514701b03e00532e00501b03f01b01b32e00503f0055af", + "0x526d01b00500532e0050050050d201b07b00532e00502300515801b023", + "0x21601b04304400732e00504500521401b07b00500700507b00532e00507b", + "0x4604700700504606f01b04200532e00504300521801b01b32e005044005", + "0x5501b01b32e00501b00701b02303e03f04866819404004104832e007042", + "0x1b07b00532e00501b33001b01b32e0050480052ea01b01b32e005194005", + "0x502007b00703101b02000532e00502000502a01b02000532e00501b29a", + "0x3101b32b00532e00532b00502a01b32b00532e00501b23201b19100532e", + "0x32e00532900502a01b32900532e00501b33f01b00900532e00532b191007", + "0x2a01b02d00532e00501b23101b33000532e00532900900703101b329005", + "0x32e00501b32601b02a00532e00502d33000703101b02d00532e00502d005", + "0x1b0c900532e00532600529501b32600532e00502a0310070c901b031005", + "0x504000531e01b04100532e00504100531f01b01b00532e00501b005046", + "0x1b00701b0c904004101b0470050c900532e0050c90050eb01b04000532e", + "0x1b01b32e00532000521601b31f32000732e00502300521401b01b32e005", + "0x503e00531e01b03f00532e00503f00531f01b31f00532e00531f005041", + "0x32e00501b00701b03900566903731e00732e00731f0055b001b03e00532e", + "0x3700504401b03700532e00503700518b01b01b32e00531e00519101b01b", + "0x1b31c00532e00501b5b101b03600532e00503800504301b03800532e005", + "0x1fb00502a01b1fb00532e00531c03600735801b03600532e00503600502a", + "0x1b32e00501b00701b20300566a01b32e0071fb0052dd01b1fb00532e005", + "0x520d0055b301b20d00532e0052070055b201b20700532e00501b2ae01b", + "0x1b21600532e0052140055b401b01b32e00521100534001b21421100732e", + "0x32e00501b31c01b21c00532e0052180052b001b21800532e005216005536", + "0x21101b21c00532e00521c0052aa01b22200532e00522200520701b222005", + "0x501b00701b05205105404866b22904c22804832e00721c22203e03f047", + "0x31e01b22800532e00522800531f01b22900532e00522900502a01b01b32e", + "0x501b00701b05500566c01b32e0072290052dd01b04c00532e00504c005", + "0x18f01b23200532e00523104800718d01b23100532e00501b03f01b01b32e", + "0x32e00522800531f01b01b00532e00501b00504601b23400532e005232005", + "0x4700523400532e0052340050eb01b04c00532e00504c00531e01b228005", + "0x52ea01b01b32e0050550052da01b01b32e00501b00701b23404c22801b", + "0x2a01b05900532e00501b5b501b05700532e00501b33001b01b32e005048", + "0x32e00501b32601b05800532e00505905700703101b05900532e005059005", + "0x1b24900532e00523a00529501b23a00532e0050580560070c901b056005", + "0x504c00531e01b22800532e00522800531f01b01b00532e00501b005046", + "0x1b00701b24904c22801b04700524900532e0052490050eb01b04c00532e", + "0x70c901b03300532e00501b32601b01b32e0050480052ea01b01b32e005", + "0x32e00501b00504601b25400532e00505f00529501b05f00532e005052033", + "0xeb01b05100532e00505100531e01b05400532e00505400531f01b01b005", + "0x2da01b01b32e00501b00701b25405105401b04700525400532e005254005", + "0x1b06200532e00501b33001b01b32e0050480052ea01b01b32e005203005", + "0x506106200703101b06100532e00506100502a01b06100532e00501b5b6", + "0x1b06900532e00526c0060070c901b00600532e00501b32601b26c00532e", + "0x503f00531f01b01b00532e00501b00504601b06b00532e005069005295", + "0x506b00532e00506b0050eb01b03e00532e00503e00531e01b03f00532e", + "0x2ea01b01b32e00503900519101b01b32e00501b00701b06b03e03f01b047", + "0x1b06e00532e00501b05701b2d300532e00501b33001b01b32e005048005", + "0x501b32601b06f00532e00506e2d300703101b06e00532e00506e00502a", + "0x3400532e0052ee00529501b2ee00532e00506f0710070c901b07100532e", + "0x3e00531e01b03f00532e00503f00531f01b01b00532e00501b00504601b", + "0x4801b03403e03f01b04700503400532e0050340050eb01b03e00532e005", + "0x701b04600566d04704800732e00700700504501b00700532e005005005", + "0x4400532e00504800504101b04500532e00504700524901b01b32e00501b", + "0x1b32e00501b00701b01b66e00501b19401b04300532e00504500503301b", + "0x504600504101b04100532e00504200505f01b04200532e00501b03f01b", + "0x4004400732e00504400530a01b04300532e00504100503301b04400532e", + "0x1b03e00566f03f00532e00704300525401b19400532e00504000521801b", + "0x532e00502300504301b02300532e00503f00504401b01b32e00501b007", + "0x67019102000732e00707b01b00728501b07b00532e00507b00502a01b07b", + "0x32e00501b31c01b01b32e00519400505501b01b32e00501b00701b32b005", + "0x33019100732e0051910051fb01b32904400732e00504400530a01b009005", + "0x2a02d00732e0073300093290200475b701b00900532e00500900520701b", + "0x30901b32604400732e00504400530a01b01b32e00501b00701b031005671", + "0x50c900520701b32019100732e0051910051fb01b0c900532e005326005", + "0x732e0073200c902d04833701b02a00532e00502a00504101b0c900532e", + "0x731e19104431f0475b701b01b32e00501b00701b03903700767231e31f", + "0x532e00502a00521801b01b32e00501b00701b31c00567303603800732e", + "0x75b901b20700532e00503600521801b20300532e0051fb0055b801b1fb", + "0x32e00503800504601b21100532e00520d0055ba01b20d00532e005203207", + "0x1b32e00501b00701b21103800700521100532e0052110055bb01b038005", + "0x532e00501b24701b21400532e00501b33001b01b32e00502a00519101b", + "0x32601b21800532e00521621400703101b21600532e00521600502a01b216", + "0x32e00522200534201b22200532e00521821c0070c901b21c00532e00501b", + "0x700522800532e0052280055bb01b31c00532e00531c00504601b228005", + "0x502a00519101b01b32e00503900504c01b01b32e00501b00701b22831c", + "0x501b33001b01b32e00519100504c01b01b32e00504400519101b01b32e", + "0x3101b22900532e00522900502a01b22900532e00501b5bc01b04c00532e", + "0x50540510070c901b05100532e00501b32601b05400532e00522904c007", + "0x1b03700532e00503700504601b05500532e00505200534201b05200532e", + "0x504c01b01b32e00501b00701b05503700700505500532e0050550055bb", + "0x24701b23100532e00501b33001b01b32e00504400519101b01b32e005191", + "0x32e00523223100703101b23200532e00523200502a01b23200532e00501b", + "0x34201b05900532e0052340570070c901b05700532e00501b32601b234005", + "0x32e0050580055bb01b03100532e00503100504601b05800532e005059005", + "0x1b01b32e00504400519101b01b32e00501b00701b058031007005058005", + "0x523a1940075b901b23a00532e0050560055be01b05600532e00501b03f", + "0x1b32b00532e00532b00504601b03300532e0052490055ba01b24900532e", + "0x505401b01b32e00501b00701b03332b00700503300532e0050330055bb", + "0x5be01b05f00532e00501b03f01b01b32e00504400519101b01b32e00503e", + "0x50620055ba01b06200532e0052541940075b901b25400532e00505f005", + "0x506100532e0050610055bb01b01b00532e00501b00504601b06100532e", + "0x67404504600732e00700501b00700501b01b32e00501b02001b06101b007", + "0x4601b04204700732e0050470052d201b01b32e00501b00701b043044007", + "0x501b00701b04100567501b32e0070420052dd01b04600532e005046005", + "0x75c101b04000532e0050480055bf01b01b32e00504700532901b01b32e", + "0x32e00504600504601b03f00532e00519400534301b19400532e005040007", + "0x4800503f00532e00503f0055c301b04500532e00504500531f01b046005", + "0x4600504601b01b32e0050410052da01b01b32e00501b00701b03f045046", + "0x4832e0050070460075c401b00700532e00500700506201b04600532e005", + "0x1b32e00501b00701b19100567602000532e00707b0055c601b07b02303e", + "0x4700735801b00900532e00501b23401b32b00532e0050200480075c701b", + "0x532e00504500531f01b03e00532e00503e00504601b32900532e005009", + "0x502a01b32b00532e00532b00528c01b02300532e00502300506201b045", + "0x502a02d33004832e00532932b02304503e04628b01b32900532e005329", + "0x528a01b01b32e00504700532901b01b32e00501b00701b02a02d330048", + "0x532e0050310230075c101b03100532e0051910055c801b01b32e005048", + "0x531f01b03e00532e00503e00504601b0c900532e00532600534301b326", + "0x701b0c904503e0480050c900532e0050c90055c301b04500532e005045", + "0x5501b01b32e00504800528a01b01b32e00504700532901b01b32e00501b", + "0x1b31f00532e00501b22901b32000532e00501b33001b01b32e005007005", + "0x501b32601b31e00532e00531f32000703101b31f00532e00531f00502a", + "0x3800532e0050390055c901b03900532e00531e0370070c901b03700532e", + "0x380055c301b04300532e00504300531f01b04400532e00504400504601b", + "0x501b00700501b01b32e00501b02001b03804304404800503800532e005", + "0x500700504801b01b32e00501b00701b04404500767704604700732e007", + "0x504501b04700532e00504700504601b01b32e00501b04701b04300532e", + "0x504100524901b01b32e00501b00701b04000567804104200732e007043", + "0x1b03e00532e00519400503301b03f00532e00504200504101b19400532e", + "0x5f01b02300532e00501b03f01b01b32e00501b00701b01b67900501b194", + "0x32e00507b00503301b03f00532e00504000504101b07b00532e005023005", + "0x567a19100532e00703e00525401b02000532e00503f00521801b03e005", + "0x504800504801b00900532e00519100504401b01b32e00501b00701b32b", + "0x2d33000732e00732900504501b00900532e00500900502a01b32900532e", + "0x504101b03100532e00502d00524901b01b32e00501b00701b02a00567b", + "0x1b01b67c00501b19401b0c900532e00503100503301b32600532e005330", + "0x31f00532e00532000505f01b32000532e00501b03f01b01b32e00501b007", + "0xc900525401b0c900532e00531f00503301b32600532e00502a00504101b", + "0x532e00531e00504401b01b32e00501b00701b03700567d31e00532e007", + "0x504301b03600532e00500900504301b03800532e00532600521801b039", + "0x32e00531c03600735801b31c00532e00531c00502a01b31c00532e005039", + "0x20300567e01b32e0071fb0052dd01b1fb00532e0051fb00502a01b1fb005", + "0x4700532e00504700504601b01b32e00501b02001b01b32e00501b00701b", + "0x3800506201b02000532e00502000506201b04600532e00504600531f01b", + "0x20704800521120d20704832e00503802004604704713d01b03800532e005", + "0x32e0052030052da01b01b32e00501b02001b01b32e00501b00701b21120d", + "0x200485ca01b21600532e0052140052d901b21400532e00501b03f01b01b", + "0x32e00504700504601b21c00532e0052180055cb01b21800532e005216038", + "0x4800521c00532e00521c0055cc01b04600532e00504600531f01b047005", + "0x503700505401b01b32e00501b02001b01b32e00501b00701b21c046047", + "0x32600519101b01b32e00502000505501b01b32e00500900532901b01b32e", + "0x502a01b22800532e00501b05701b22200532e00501b33001b01b32e005", + "0x532e00501b32601b04c00532e00522822200703101b22800532e005228", + "0x4601b05100532e0050540055cd01b05400532e00504c2290070c901b229", + "0x32e0050510055cc01b04600532e00504600531f01b04700532e005047005", + "0x1b01b32e00501b02001b01b32e00501b00701b051046047048005051005", + "0x532e0050520050ad01b05200532e00501b03f01b01b32e00532b005054", + "0x1b23200532e0052310055cb01b23100532e0050550480200485ca01b055", + "0x52320055cc01b04600532e00504600531f01b04700532e005047005046", + "0x32e00504800505501b01b32e00501b00701b23204604704800523200532e", + "0x32e00501b22901b23400532e00501b33001b01b32e00500700505501b01b", + "0x1b05900532e00505723400703101b05700532e00505700502a01b057005", + "0x50560055cd01b05600532e0050590580070c901b05800532e00501b326", + "0x1b04400532e00504400531f01b04500532e00504500504601b23a00532e", + "0x501b01b32e00501b02001b23a04404504800523a00532e00523a0055cc", + "0x14e01b01b32e00501b00701b04404500767f04604700732e00700501b007", + "0x4700532e00504700504601b01b32e00501b04701b04300532e005007005", + "0x5cf01b01b32e00501b00701b04000568004104200732e0070430055ce01b", + "0x32e0051940055d101b03f00532e0050420055d001b19400532e005041005", + "0x532e00501b03f01b01b32e00501b00701b01b68100501b19401b03e005", + "0x55d101b03f00532e0050400055d001b07b00532e0050230055d201b023", + "0x532e00703e0055d301b02000532e00503f00511301b03e00532e00507b", + "0x14e01b00900532e0051910055d401b01b32e00501b00701b32b005682191", + "0x32e0073290055ce01b00900532e0050090055d501b32900532e005048005", + "0x3100532e00502d0055cf01b01b32e00501b00701b02a00568302d330007", + "0x501b19401b0c900532e0050310055d101b32600532e0053300055d001b", + "0x53200055d201b32000532e00501b03f01b01b32e00501b00701b01b684", + "0x1b0c900532e00531f0055d101b32600532e00502a0055d001b31f00532e", + "0x31e0055d401b01b32e00501b00701b03700568531e00532e0070c90055d3", + "0x900732e00500900568601b03800532e00532600511301b03900532e005", + "0x11501b01b32e0051fb0052fa01b2031fb31c04832e00503600568701b036", + "0x532e0050390055d501b20700532e00531c00504301b01b32e005203005", + "0x21621421104832e00520d00568701b20d03900732e00503900568601b039", + "0x32e00521100504301b01b32e00521600511501b01b32e0052140052fa01b", + "0x1b21c00532e00521c00502a01b21c00532e00521820700735801b218005", + "0x500900568601b01b32e00501b00701b22200568801b32e00721c0052dd", + "0x32e00504c00532901b05422904c04832e00522800568701b22800900732e", + "0x3900568601b05100532e00522900529401b01b32e00505400511501b01b", + "0x505500532901b23223105504832e00505200568701b05203900732e005", + "0x729301b23400532e00523100529401b01b32e00523200511501b01b32e", + "0x1b32e00503900568a01b01b32e00501b00701b01b68901b32e007234051", + "0x1b01b32e00501b00701b01b68b00501b19401b01b32e00500900568a01b", + "0x590052fa01b01b32e00505700532901b05805905704832e005009005687", + "0x24923a04832e00503900568701b05600532e0050580052bc01b01b32e005", + "0x50330052bc01b01b32e0052490052fa01b01b32e00523a00532901b033", + "0x1b01b32e00501b00701b01b68c01b32e00705f05600727501b05f00532e", + "0x504601b01b32e00501b02001b01b32e00501b00701b01b68b00501b194", + "0x532e00502000514c01b04600532e00504600531f01b04700532e005047", + "0x25404832e00503802004604704714b01b03800532e00503800514c01b020", + "0x1b32e0052220052da01b01b32e00501b00701b061062254048005061062", + "0x1b32e00501b02001b01b32e00500900568a01b01b32e00503900568a01b", + "0x3802004834501b00600532e00526c0052d901b26c00532e00501b03f01b", + "0x532e00504700504601b06b00532e00506900568d01b06900532e005006", + "0x4704800506b00532e00506b00568e01b04600532e00504600531f01b047", + "0x32e00503700505401b01b32e00501b02001b01b32e00501b00701b06b046", + "0x532600568f01b01b32e00500900568a01b01b32e00502000511901b01b", + "0x6e00502a01b06e00532e00501b05701b2d300532e00501b33001b01b32e", + "0x7100532e00501b32601b06f00532e00506e2d300703101b06e00532e005", + "0x504601b03400532e0052ee00569001b2ee00532e00506f0710070c901b", + "0x532e00503400568e01b04600532e00504600531f01b04700532e005047", + "0x5401b01b32e00501b02001b01b32e00501b00701b034046047048005034", + "0x31100532e0050760050ad01b07600532e00501b03f01b01b32e00532b005", + "0x4601b07200532e00507300568d01b07300532e00531104802004834501b", + "0x32e00507200568e01b04600532e00504600531f01b04700532e005047005", + "0x1b32e00500700511901b01b32e00501b00701b072046047048005072005", + "0x532e00501b22901b07a00532e00501b33001b01b32e00504800511901b", + "0x32601b30f00532e00507407a00703101b07400532e00507400502a01b074", + "0x32e00530d00569001b30d00532e00530f30e0070c901b30e00532e00501b", + "0x68e01b04400532e00504400531f01b04500532e00504500504601b30c005", + "0x700501b01b32e00501b02001b30c04404504800530c00532e00530c005", + "0x569201b01b32e00501b00701b04404500769104604700732e00700501b", + "0x1b04700532e00504700504601b01b32e00501b04701b04300532e005007", + "0x569501b01b32e00501b00701b04000569404104200732e007043005693", + "0x532e00519400569701b03f00532e00504200569601b19400532e005041", + "0x2300532e00501b03f01b01b32e00501b00701b01b69800501b19401b03e", + "0x7b00569701b03f00532e00504000569601b07b00532e00502300569901b", + "0x19100532e00703e00569a01b02000532e00503f00525a01b03e00532e005", + "0x569d01b00900532e00519100569c01b01b32e00501b00701b32b00569b", + "0x532e00504800525801b04700532e00504700504601b32900532e005009", + "0x2d33000732e00532904804704834401b32900532e00532900516b01b048", + "0x1b02001b01b32e00501b00701b03100569e02a00532e00702d00517601b", + "0x1b01b32e0050c900505401b0c932600732e00502a00525501b01b32e005", + "0x502000525901b04600532e00504600531f01b33000532e005330005046", + "0x32e00532602004633004725701b32600532e00532600525801b02000532e", + "0x32e00501b02001b01b32e00501b00701b31e31f32004800531e31f320048", + "0x33000504601b03700532e00503100569f01b01b32e00502000517301b01b", + "0x3700532e0050370056a001b04600532e00504600531f01b33000532e005", + "0x505401b01b32e00501b02001b01b32e00501b00701b037046330048005", + "0x532e0050390480200486a101b03900532e00501b03f01b01b32e00532b", + "0x531f01b04700532e00504700504601b03600532e0050380056a201b038", + "0x701b03604604704800503600532e0050360056a001b04600532e005046", + "0x33001b01b32e00504800517901b01b32e00500700517301b01b32e00501b", + "0x1fb00532e0051fb00502a01b1fb00532e00501b22901b31c00532e00501b", + "0x2070070c901b20700532e00501b32601b20300532e0051fb31c00703101b", + "0x532e00504500504601b21100532e00520d00569f01b20d00532e005203", + "0x4504800521100532e0052110056a001b04400532e00504400531f01b045", + "0x56a301b04504600732e00500700517801b01b32e00501b02001b211044", + "0x4400532e00504400520701b04300532e00501b6a401b04400532e005045", + "0x4004104204832e00504304401b0486a601b04300532e0050430056a501b", + "0x1b32e00501b04701b19400532e00501b31c01b01b32e00504100504c01b", + "0x714601b04200532e00504200504601b03f04700732e0050470051fb01b", + "0x3e00532e00501b33301b01b32e00501b00701b01b6a701b32e00719403f", + "0x1b01b6a801b32e00703e02300714601b02304700732e0050470051fb01b", + "0x4700732e0050470051fb01b07b00532e00501b59601b01b32e00501b007", + "0x1b51c01b01b32e00501b00701b01b6a901b32e00707b02000714601b020", + "0x32e00719132b00714601b32b04700732e0050470051fb01b19100532e005", + "0x470051fb01b00900532e00501b34601b01b32e00501b00701b01b6aa01b", + "0x32e00501b00701b01b6ab01b32e00700932900714601b32904700732e005", + "0x714601b02d04700732e0050470051fb01b33000532e00501b6ac01b01b", + "0x2a00532e00501b6ae01b01b32e00501b00701b01b6ad01b32e00733002d", + "0x1b01b6af01b32e00702a03100714601b03104700732e0050470051fb01b", + "0x1b32e00732604700714601b32600532e00501b6b001b01b32e00501b007", + "0x32e00504600517901b01b32e00501b02001b01b32e00501b00701b01b6b1", + "0x32e00501b33001b01b32e0050480052fa01b01b32e00504000504c01b01b", + "0x703101b32000532e00532000502a01b32000532e00501b6b201b0c9005", + "0x32e00531f31e0070c901b31e00532e00501b32601b31f00532e0053200c9", + "0x31f01b04200532e00504200504601b03900532e0050370056b301b037005", + "0x1b03900504204800503900532e0050390056b401b00500532e005005005", + "0x3600532e0050380052f701b03800532e00501b6b501b01b32e00501b007", + "0x1b01b32e00504700504c01b01b32e00501b00701b01b6b600501b19401b", + "0x32e00503600529401b03600532e00531c0052f701b31c00532e00501b6b7", + "0x32e00504700504c01b01b32e00501b00701b01b6b800501b19401b1fb005", + "0x1fb00529401b1fb00532e0052030052f701b20300532e00501b6b901b01b", + "0x4700504c01b01b32e00501b00701b01b6ba00501b19401b20700532e005", + "0x29401b20700532e00520d0052f701b20d00532e00501b6bb01b01b32e005", + "0x4c01b01b32e00501b00701b01b6bc00501b19401b21100532e005207005", + "0x21100532e0052140052f701b21400532e00501b6bd01b01b32e005047005", + "0x1b32e00501b00701b01b6be00501b19401b21600532e00521100529401b", + "0x32e0052180052f701b21800532e00501b34801b01b32e00504700504c01b", + "0x501b00701b01b6bf00501b19401b21c00532e00521600529401b216005", + "0x2220052f701b22200532e00501b6c001b01b32e00504700504c01b01b32e", + "0x1b32e0072280056c101b22821c00732e00521c0050ed01b21c00532e005", + "0x504600517901b01b32e00501b02001b01b32e00501b00701b04c0056c2", + "0x480052fa01b01b32e00521c0052fa01b01b32e00504000504c01b01b32e", + "0x502a01b05400532e00501b05701b22900532e00501b33001b01b32e005", + "0x532e00501b32601b05100532e00505422900703101b05400532e005054", + "0x4601b23100532e0050550056b301b05500532e0050510520070c901b052", + "0x32e0052310056b401b00500532e00500500531f01b04200532e005042005", + "0x504c0480420486c301b01b32e00501b00701b231005042048005231005", + "0x32e00705721c2320480ef01b01b32e0052340052fa01b05723423204832e", + "0x532e00505900504601b01b32e00501b00701b23a0560076c4058059007", + "0x32e00501b00701b01b6c500501b19401b03300532e0050580052f701b249", + "0x32e00504600517901b01b32e00523a0052fa01b01b32e00501b02001b01b", + "0x32e00501b0f101b05f00532e00501b33001b01b32e00504000504c01b01b", + "0x1b06200532e00525405f00703101b25400532e00525400502a01b254005", + "0x526c0056b301b26c00532e0050620610070c901b06100532e00501b326", + "0x1b00500532e00500500531f01b05600532e00505600504601b00600532e", + "0x2fa01b01b32e00501b00701b00600505604800500600532e0050060056b4", + "0x1b06900532e00501b29201b01b32e00504700504c01b01b32e005048005", + "0x32e00501b6c601b03300532e0050690052f701b24900532e005042005046", + "0x6c701b32e00706b2d300714601b2d304000732e0050400051fb01b06b005", + "0x32e00503304600717c01b01b32e00501b02001b01b32e00501b00701b01b", + "0x525801b06f00532e00506f00520701b06f00532e00501b6c601b06e005", + "0x760340076c82ee07100732e00704006f24904833701b06e00532e00506e", + "0x32e00500500531f01b07100532e00507100504601b01b32e00501b00701b", + "0x34901b2ee00532e0052ee00520701b06e00532e00506e00525801b005005", + "0x501b00701b07207331104800507207331104832e0052ee06e005071047", + "0x501b33001b01b32e00506e00517901b01b32e00507600504c01b01b32e", + "0x3101b07400532e00507400502a01b07400532e00501b5bc01b07a00532e", + "0x530f30e0070c901b30e00532e00501b32601b30f00532e00507407a007", + "0x1b03400532e00503400504601b30c00532e00530d0056b301b30d00532e", + "0x30c00503404800530c00532e00530c0056b401b00500532e00500500531f", + "0x1b01b32e00504000504c01b01b32e00501b02001b01b32e00501b00701b", + "0x3330b2490480ef01b30b00532e00530b0052f701b30b00532e00501b6c9", + "0x30904600717c01b01b32e00501b00701b0863050076ca30930a00732e007", + "0x8400532e0053033040076cb01b30300532e00501b03f01b30400532e005", + "0x500531f01b30a00532e00530a00504601b30200532e0050840056cc01b", + "0x1b00701b30200530a04800530200532e0053020056b401b00500532e005", + "0x1b33001b01b32e00504600517901b01b32e0050860052fa01b01b32e005", + "0x1b08200532e00508200502a01b08200532e00501b0f101b30100532e005", + "0x3002ff0070c901b2ff00532e00501b32601b30000532e005082301007031", + "0x30500532e00530500504601b08700532e00507d0056b301b07d00532e005", + "0x530504800508700532e0050870056b401b00500532e00500500531f01b", + "0x31c01b04500532e0050460056cd01b04604700732e00500500519901b087", + "0x32e00504500520701b04304800732e0050480051fb01b04400532e00501b", + "0x33301b01b32e00501b00701b01b6ce01b32e00704404300714601b045005", + "0x704204100714601b04104800732e0050480051fb01b04200532e00501b", + "0x51fb01b04000532e00501b59601b01b32e00501b00701b01b6cf01b32e", + "0x501b00701b01b6d001b32e00704019400714601b19404800732e005048", + "0x501b6d301b03e00532e00501b6d201b03f00532e00501b6d101b01b32e", + "0x1b02000532e00503e00520701b07b00532e00503f0056a501b02300532e", + "0x1b01b32e00501b00701b01b6d400501b19401b19100532e005023005207", + "0x32900532e00501b6d701b00900532e00501b6d601b32b00532e00501b6d5", + "0x32900520701b02000532e00500900520701b07b00532e00532b0056a501b", + "0x2d00532e00502000514801b33000532e00507b0056d801b19100532e005", + "0x1b32e00501b00701b01b6d900501b19401b02a00532e00519100514801b", + "0x532e00501b34c01b32600532e00501b6db01b03100532e00501b6da01b", + "0x520701b02d00532e00532600520701b33000532e0050310056a501b0c9", + "0x504c01b31e31f32004832e00533000701b0486a601b02a00532e0050c9", + "0x532e0050370052f701b03700532e00502d31e0076dc01b01b32e00531f", + "0x1b32e00501b00701b0360056de03803900732e0070373200076dd01b037", + "0x32e00501b00701b2072030076e01fb31c00732e00702a0380390486df01b", + "0x24101b21100532e00531c00504601b20d00532e0051fb04700724201b01b", + "0x4c01b01b32e00501b00701b01b6e100501b19401b21400532e00520d005", + "0x1b01b32e00504800504c01b01b32e00504500504c01b01b32e005207005", + "0x21800532e00501b6e201b21600532e00501b33001b01b32e005047005233", + "0x1b32601b21c00532e00521821600703101b21800532e00521800502a01b", + "0x532e00522800534d01b22800532e00521c2220070c901b22200532e005", + "0x20300700504c00532e00504c0056e301b20300532e00520300504601b04c", + "0x32e00504800504c01b01b32e00504500504c01b01b32e00501b00701b04c", + "0x32e00501b33001b01b32e00502a00504c01b01b32e00504700523301b01b", + "0x703101b05400532e00505400502a01b05400532e00501b6e401b229005", + "0x32e0050510520070c901b05200532e00501b32601b05100532e005054229", + "0x6e301b03600532e00503600504601b23100532e00505500534d01b055005", + "0x700504c01b01b32e00501b00701b23103600700523100532e005231005", + "0x24201b23200532e00523200520701b23200532e00501b6e501b01b32e005", + "0x523400524101b21100532e00501b00504601b23400532e005232047007", + "0x5800532e0050590056cd01b05905700732e00521400519901b21400532e", + "0x505600520701b05800532e00505800520701b05600532e00501b33301b", + "0x701b05f0330076e624923a00732e0070560582110486df01b05600532e", + "0x1b25400532e0052540056a501b25400532e00501b6e701b01b32e00501b", + "0x30501b01b32e00506100504c01b26c06106204832e00525424923a0486a6", + "0x532e00506900502a01b06900532e00501b6e801b00600532e00526c005", + "0x2a01b05700532e00505700524101b06b00532e00500606900735801b069", + "0x32e00501b6ea01b2d300532e00506b0570076e901b06b00532e00506b005", + "0x1b06f00532e00506f0052f701b06f00532e00506e0450076dc01b06e005", + "0x6ec01b01b32e00501b00701b0340056eb2ee07100732e00706f0620076dd", + "0x32e0053110052f701b31100532e0050760480076dc01b07600532e00501b", + "0x32e00501b00701b07a0056ed07207300732e0073110710076dd01b311005", + "0x501b00701b30d30e0076ee30f07400732e0070722ee0730486df01b01b", + "0x34f01b30b00532e00501b03f01b30c00532e00530f2d300724201b01b32e", + "0x507400504601b30900532e00530a0056ef01b30a00532e00530b30c007", + "0x32e00501b00701b30907400700530900532e0053090056e301b07400532e", + "0x32e00501b33001b01b32e0052d300523301b01b32e00530d00504c01b01b", + "0x703101b08600532e00508600502a01b08600532e00501b6e201b305005", + "0x32e0053043030070c901b30300532e00501b32601b30400532e005086305", + "0x6e301b30e00532e00530e00504601b30200532e00508400534d01b084005", + "0x2d300523301b01b32e00501b00701b30230e00700530200532e005302005", + "0x1b6e401b30100532e00501b33001b01b32e0052ee00504c01b01b32e005", + "0x532e00508230100703101b08200532e00508200502a01b08200532e005", + "0x534d01b07d00532e0053002ff0070c901b2ff00532e00501b32601b300", + "0x532e0050870056e301b07a00532e00507a00504601b08700532e00507d", + "0x4c01b01b32e0052d300523301b01b32e00501b00701b08707a007005087", + "0x1b2fc00532e00501b6e401b33800532e00501b33001b01b32e005048005", + "0x501b32601b2fb00532e0052fc33800703101b2fc00532e0052fc00502a", + "0x2f800532e0052f900534d01b2f900532e0052fb2fa0070c901b2fa00532e", + "0x2f80340070052f800532e0052f80056e301b03400532e00503400504601b", + "0x1b32e00504500504c01b01b32e00505f00504c01b01b32e00501b00701b", + "0x532e00501b33001b01b32e00505700523301b01b32e00504800504c01b", + "0x2f700703101b2f600532e0052f600502a01b2f600532e00501b6e201b2f7", + "0x532e0052f52f40070c901b2f400532e00501b32601b2f500532e0052f6", + "0x56e301b03300532e00503300504601b2f200532e0052f300534d01b2f3", + "0x501b00700501b01b32e00501b02001b2f20330070052f200532e0052f2", + "0x50480056f101b01b32e00501b00701b0430440076f004504600732e007", + "0x19404004104832e0070420460076f201b01b32e00501b04701b04200532e", + "0x4601b02300532e0051940056f401b01b32e00501b00701b03e03f0076f3", + "0x32e0050230056f501b02000532e00504000535001b07b00532e005041005", + "0x532e00501b03f01b01b32e00501b00701b01b6f600501b19401b191005", + "0x535001b07b00532e00503f00504601b00900532e00532b0056f701b32b", + "0x532e00502000523001b19100532e0050090056f501b02000532e00503e", + "0x2001b01b32e00501b00701b02d0056f933000532e0071910056f801b329", + "0x702a0470070450476fb01b02a00532e0053300056fa01b01b32e00501b", + "0x7b00504601b01b32e00501b00701b31e31f3200486fc0c932603104832e", + "0x32600532e00532600531e01b03100532e00503100531f01b07b00532e005", + "0x7b04619f01b0c900532e0050c900519d01b32900532e00532900522e01b", + "0x1b00701b03603803903704700503603803903704732e0050c9329326031", + "0x70c901b31c00532e00501b32601b01b32e00532900522b01b01b32e005", + "0x32e00507b00504601b20300532e0051fb0056fd01b1fb00532e00531e31c", + "0x6fe01b31f00532e00531f00531e01b32000532e00532000531f01b07b005", + "0x2001b01b32e00501b00701b20331f32007b04700520300532e005203005", + "0x6ff01b20700532e00501b03f01b01b32e00502d00505401b01b32e00501b", + "0x7b00504601b21100532e00520d00570001b20d00532e005207047329048", + "0x700532e00500700531e01b04500532e00504500531f01b07b00532e005", + "0x1b32e00501b00701b21100704507b04700521100532e0052110056fe01b", + "0x532e00501b33001b01b32e00504800522b01b01b32e00504700570101b", + "0x21400703101b21600532e00521600502a01b21600532e00501b22901b214", + "0x532e00521821c0070c901b21c00532e00501b32601b21800532e005216", + "0x531f01b04400532e00504400504601b22800532e0052220056fd01b222", + "0x532e0052280056fe01b00700532e00500700531e01b04300532e005043", + "0x732e00504600570201b01b32e00501b02001b228007043044047005228", + "0x1b01b32e0050410052d801b04104204304832e00504400570301b044046", + "0x503f00520801b03f00532e00501b21901b19404000732e005043005208", + "0x7b19400732e00519400520a01b01b32e00503e00525b01b02303e00732e", + "0x2300520a01b01b32e00519100511501b19102000732e00507b00518201b", + "0x32e00532900511501b32900900732e00532b00518201b32b02300732e005", + "0x727501b02d00532e0050090052bc01b33000532e0050200052bc01b01b", + "0x1b32e00502300525b01b01b32e00501b00701b01b70401b32e00702d330", + "0x1b01b32e00501b00701b01b70500501b19401b01b32e00519400525b01b", + "0x502300518201b01b32e00502a00511501b03102a00732e005194005182", + "0x1b32000532e0050310052bc01b01b32e00532600511501b0c932600732e", + "0x1b00701b01b70601b32e00731f32000727501b31f00532e0050c90052bc", + "0x1b03900532e00501b70701b03731e00732e00504000518201b01b32e005", + "0x570801b31c03700732e00503700570801b03603800732e005039005182", + "0x1fb31c01b04870901b1fb00532e0051fb00518301b1fb03600732e005036", + "0x520700511501b01b32e00501b00701b21120d00770a20720300732e007", + "0x1b70b01b32e00703603700727501b20300532e00520300504601b01b32e", + "0x1b32e00504500570c01b01b32e00504200525b01b01b32e00501b00701b", + "0x32e00503800511501b01b32e00504700525b01b01b32e00504600570d01b", + "0x501b19401b21400532e00520300504601b01b32e00531e00511501b01b", + "0x20304870901b03800532e00503800518301b01b32e00501b00701b01b70e", + "0x511501b01b32e00501b00701b22221c00770f21821600732e00703831e", + "0x70d01b01b32e00504500570c01b01b32e00504200525b01b01b32e005218", + "0x21400532e00521600504601b01b32e00504700525b01b01b32e005046005", + "0x1b01b32e00522200511501b01b32e00501b00701b01b70e00501b19401b", + "0x1b01b32e00501b00701b01b71000501b19401b22800532e00521c005046", + "0x1b32e00503800511501b01b32e00503700511501b01b32e005211005115", + "0x32e00520d00504601b01b32e00503600511501b01b32e00531e00511501b", + "0x20801b05400532e00501b21901b22904c00732e00504200520801b228005", + "0x32e00522900520a01b01b32e00505100525b01b05205100732e005054005", + "0x1b01b32e00523200511501b23223100732e00505500518201b055229007", + "0x511501b05905700732e00523400518201b23405200732e00505200520a", + "0x5600532e0050570052bc01b05800532e0052310052bc01b01b32e005059", + "0x501b00701b01b71101b32e00705605800727501b01b32e00501b04701b", + "0x501b19401b01b32e00522900525b01b01b32e00505200525b01b01b32e", + "0x511501b24923a00732e00522900518201b01b32e00501b00701b01b712", + "0x1b32e00503300511501b05f03300732e00505200518201b01b32e00523a", + "0x25400727501b06200532e00505f0052bc01b25400532e0052490052bc01b", + "0x18201b01b32e00501b02001b01b32e00501b00701b01b71301b32e007062", + "0x32e00500600518201b00600532e00501b70701b26c06100732e00504c005", + "0x6b00732e00506b00570801b2d326c00732e00526c00570801b06b069007", + "0x7106f00732e00706e2d322804870901b06e00532e00506e00518301b06e", + "0x504601b01b32e00507100511501b01b32e00501b00701b0342ee007714", + "0x32e00501b00701b01b71501b32e00706b26c00727501b06f00532e00506f", + "0x504700525b01b01b32e00504600570d01b01b32e00504500570c01b01b", + "0x6f00504601b01b32e00506100511501b01b32e00506900511501b01b32e", + "0x6900518301b01b32e00501b00701b01b71600501b19401b07600532e005", + "0x1b07a07200771707331100732e00706906106f04870901b06900532e005", + "0x1b01b32e00504500570c01b01b32e00507300511501b01b32e00501b007", + "0x532e00531100504601b01b32e00504700525b01b01b32e00504600570d", + "0x1b32e00507a00511501b01b32e00501b00701b01b71600501b19401b076", + "0x1b32e00501b00701b01b71800501b19401b07400532e00507200504601b", + "0x32e00506900511501b01b32e00526c00511501b01b32e00503400511501b", + "0x52ee00504601b01b32e00506b00511501b01b32e00506100511501b01b", + "0x1b04800532e00504800531e01b00500532e00500500531f01b07400532e", + "0x507404671901b04600532e0050460051ff01b04700532e00504700516b", + "0x571b30b00532e00730c00571a01b30c30d30e30f04732e005046047048", + "0x730900521a01b30900532e00530b00571c01b01b32e00501b00701b30a", + "0x30f00532e00530f00504601b01b32e00501b00701b08600571d30500532e", + "0x30d00531e01b00700532e0050070052d401b30e00532e00530e00531f01b", + "0x30530d00730e30f04635201b30500532e00530500571e01b30d00532e005", + "0x1b30000572008200532e00730100571f01b30130208430330404632e005", + "0x732e00504500572201b2ff00532e00508200572101b01b32e00501b007", + "0x70c01b2fc33800732e0052ff00572201b01b32e00507d00570c01b08707d", + "0x532e0052fc00572301b2fb00532e00508700572301b01b32e005338005", + "0x735801b2f800532e0052fa00504301b2f900532e0052fb00504301b2fa", + "0x32e0072f70052dd01b2f700532e0052f700502a01b2f700532e0052f82f9", + "0x572501b2f500532e00501b03f01b01b32e00501b00701b2f600572401b", + "0x532e0052f300572701b2f300532e0052f400572601b2f400532e0052f5", + "0x52d401b30300532e00530300531f01b30400532e00530400504601b2f2", + "0x532e0052f200572801b30200532e00530200531e01b08400532e005084", + "0x32e0052f60052da01b01b32e00501b00701b2f23020843033040460052f2", + "0x2ef00572601b2ef00532e0052f100572a01b2f100532e00501b72901b01b", + "0x30400532e00530400504601b08b00532e00507c00572701b07c00532e005", + "0x30200531e01b08400532e0050840052d401b30300532e00530300531f01b", + "0x1b08b30208430330404600508b00532e00508b00572801b30200532e005", + "0x8d00532e00530000572b01b01b32e00504500570c01b01b32e00501b007", + "0x840052d401b30300532e00530300531f01b30400532e00530400504601b", + "0x8d00532e00508d00572801b30200532e00530200531e01b08400532e005", + "0x1b32e00508600505401b01b32e00501b00701b08d302084303304046005", + "0x532e00501b05701b2ed00532e00501b33001b01b32e00504500570c01b", + "0x32601b2ec00532e0050902ed00703101b09000532e00509000502a01b090", + "0x32e0052eb00572b01b2eb00532e0052ec08e0070c901b08e00532e00501b", + "0x2d401b30e00532e00530e00531f01b30f00532e00530f00504601b2ea005", + "0x32e0052ea00572801b30d00532e00530d00531e01b00700532e005007005", + "0x504500570c01b01b32e00501b00701b2ea30d00730e30f0460052ea005", + "0x31f01b30f00532e00530f00504601b2e800532e00530a00572b01b01b32e", + "0x32e00530d00531e01b00700532e0050070052d401b30e00532e00530e005", + "0x1b00701b2e830d00730e30f0460052e800532e0052e800572801b30d005", + "0x4600570d01b01b32e00504500570c01b01b32e00501b02001b01b32e005", + "0x504601b01b32e00504c00525b01b01b32e00504700525b01b01b32e005", + "0x9900532e0052e700572a01b2e700532e00501b72c01b07600532e005228", + "0x500531f01b2e600532e00508500572701b08500532e00509900572601b", + "0x4800532e00504800531e01b00700532e0050070052d401b00500532e005", + "0x32e00501b00701b2e60480070050760460052e600532e0052e600572801b", + "0x504600570d01b01b32e00504500570c01b01b32e00504200525b01b01b", + "0x1b00504601b01b32e00504000525b01b01b32e00504700525b01b01b32e", + "0x1b2e300532e0052e400572a01b2e400532e00501b72c01b21400532e005", + "0x500500531f01b2e200532e00509d00572701b09d00532e0052e3005726", + "0x1b04800532e00504800531e01b00700532e0050070052d401b00500532e", + "0x32e00504700520a01b2e20480070052140460052e200532e0052e2005728", + "0x1b04100532e00501b21901b04204300732e00504400520801b044047007", + "0x504200520a01b01b32e00504000525b01b19404000732e005041005208", + "0x1b32e00502300511501b02303e00732e00503f00518201b03f04200732e", + "0x11501b19102000732e00507b00518201b07b19400732e00519400520a01b", + "0x532e0050200052bc01b32b00532e00503e0052bc01b01b32e005191005", + "0x525b01b01b32e00501b00701b01b72d01b32e00700932b00727501b009", + "0x1b00701b01b72e00501b19401b01b32e00504200525b01b01b32e005194", + "0x1b01b32e00532900511501b33032900732e00504200518201b01b32e005", + "0x53300052bc01b01b32e00502d00511501b02a02d00732e005194005182", + "0x72f01b32e00732603100727501b32600532e00502a0052bc01b03100532e", + "0x501b73001b3200c900732e00504300518201b01b32e00501b00701b01b", + "0x32000732e00532000570801b03731e00732e00531f00518201b31f00532e", + "0x70901b03800532e00503800518301b03803700732e00503700570801b039", + "0x1b01b32e00501b00701b2031fb00773131c03600732e00703803901b048", + "0x703732000727501b03600532e00503600504601b01b32e00531c005115", + "0x51e401b01b32e00504700525b01b01b32e00501b00701b01b73201b32e", + "0x11501b01b32e00504600525b01b01b32e00504800525b01b01b32e005045", + "0x20700532e00503600504601b01b32e0050c900511501b01b32e00531e005", + "0x31e00532e00531e00518301b01b32e00501b00701b01b73300501b19401b", + "0x32e00501b00701b21621400773421120d00732e00731e0c903604870901b", + "0x50450051e401b01b32e00504700525b01b01b32e00521100511501b01b", + "0x20d00504601b01b32e00504600525b01b01b32e00504800525b01b01b32e", + "0x21600511501b01b32e00501b00701b01b73300501b19401b20700532e005", + "0x1b00701b01b73500501b19401b21800532e00521400504601b01b32e005", + "0x511501b01b32e00532000511501b01b32e00520300511501b01b32e005", + "0x4601b01b32e00503700511501b01b32e0050c900511501b01b32e00531e", + "0x521c00520801b21c04600732e00504600520a01b21800532e0051fb005", + "0x5422900732e00504c00520801b04c00532e00501b21901b22822200732e", + "0x5100518201b05122800732e00522800520a01b01b32e00522900525b01b", + "0x5400732e00505400520a01b01b32e00505500511501b05505200732e005", + "0x52bc01b01b32e00523400511501b23423200732e00523100518201b231", + "0x32e00705905700727501b05900532e0052320052bc01b05700532e005052", + "0x22800525b01b01b32e00505400525b01b01b32e00501b00701b01b73601b", + "0x522800518201b01b32e00501b00701b01b73700501b19401b01b32e005", + "0x24923a00732e00505400518201b01b32e00505800511501b05605800732e", + "0x52490052bc01b03300532e0050560052bc01b01b32e00523a00511501b", + "0x1b01b32e00501b00701b01b73801b32e00705f03300727501b05f00532e", + "0x506100518201b06100532e00501b73001b06225400732e005222005182", + "0x732e00500600570801b06906200732e00506200570801b00626c00732e", + "0x2d300732e00706b06921804870901b06b00532e00506b00518301b06b006", + "0x4601b01b32e00506e00511501b01b32e00501b00701b07106f00773906e", + "0x501b00701b01b73a01b32e00700606200727501b2d300532e0052d3005", + "0x501b03f01b01b32e00525400511501b01b32e00526c00511501b01b32e", + "0x1b07600532e0052d300504601b03400532e0052ee0052d901b2ee00532e", + "0x1b01b32e00501b00701b01b73b00501b19401b31100532e0050340052db", + "0x773c07207300732e00726c2542d304870901b26c00532e00526c005183", + "0x32e00501b03f01b01b32e00507200511501b01b32e00501b00701b07407a", + "0x2db01b07600532e00507300504601b30e00532e00530f0052d901b30f005", + "0x11501b01b32e00501b00701b01b73b00501b19401b31100532e00530e005", + "0x30c00532e00530d0050ad01b30d00532e00501b03f01b01b32e005074005", + "0x501b19401b31100532e00530c0052db01b07600532e00507a00504601b", + "0x506200511501b01b32e00507100511501b01b32e00501b00701b01b73b", + "0x600511501b01b32e00525400511501b01b32e00526c00511501b01b32e", + "0x4601b30a00532e00530b0050ad01b30b00532e00501b03f01b01b32e005", + "0x1b73b00501b19401b31100532e00530a0052db01b07600532e00506f005", + "0x30900532e00501b03f01b01b32e00522200525b01b01b32e00501b00701b", + "0x3050052db01b07600532e00521800504601b30500532e0053090052d901b", + "0x8600532e0050860052db01b08600532e0053110052d701b31100532e005", + "0x505401b01b32e00501b00701b30300573d30400532e00708600514201b", + "0x30208400732e00508400573e01b08400532e00501b35101b01b32e005304", + "0x30008230104132e00730204607604874001b30200532e00530200573f01b", + "0x74201b01b32e00501b00701b2f72f82f90487412fa2fb2fc33808707d2ff", + "0x2f500774201b2f500532e0052fb2f600774201b2f600532e0052fa301007", + "0x50872f300774201b2f300532e0053382f400774201b2f400532e0052fc", + "0x532e0052ff2f100774201b2f100532e00507d2f200774201b2f200532e", + "0x4601b08b00532e00508200574301b07c00532e0053002ef00774201b2ef", + "0x32e00508b00520a01b04800532e00504800516b01b07c00532e00507c005", + "0x2ed08400732e00508400573e01b08d00532e00508d00516b01b08d08b007", + "0x2ec09000732e0052ed08d04807c04774401b2ed00532e0052ed00573f01b", + "0x516b01b08e04700732e00504700520a01b09000532e00509000504601b", + "0x532e00508400573f01b08b00532e00508b00516b01b08e00532e00508e", + "0x2e800532e00501b74501b2ea2eb00732e00508408b08e09004774401b084", + "0x52e700516b01b2e800532e0052e800516b01b2e700532e00501b74601b", + "0x2e32e40487472e608509904832e0072e72e80070050471ef01b2e700532e", + "0x509900531f01b2e600532e0052e60051e901b01b32e00501b00701b09d", + "0x7482e200532e0072e60051e701b08500532e00508500531e01b09900532e", + "0x2e10a004832e0072ec2e208509904735301b01b32e00501b00701b0a4005", + "0xa000532e0050a000531f01b01b32e00501b00701b2dd0aa0a80487492df", + "0x2db0ad04832e0072ea0452e10a004735301b2df00532e0052df00551801b", + "0xad00532e0050ad00531f01b01b32e00501b00701b2d72d82d904874a2da", + "0x2d60b204832e0072da2df2db0ad04774b01b2da00532e0052da00551801b", + "0xb200532e0050b200531f01b01b32e00501b00701b35704a2d404874c2d5", + "0xcf35a35804732e0072d52d60b20481e501b2d500532e0052d500551801b", + "0x1b01b32e00535b00525b01b01b32e00501b00701b0bb0b80b904874d35b", + "0x504700520801b01b32e0050bd00525b01b0c10bd00732e0050cf005208", + "0x1b0c100532e0050c100516b01b01b32e0052d200525b01b32f2d200732e", + "0x511501b2cc35d00732e0052de00518201b2de0c100732e0050c100520a", + "0x732e0050c600518201b0c632f00732e00532f00520a01b01b32e0052cc", + "0x52bc01b35f00532e00535d0052bc01b01b32e0050c700511501b0c72cb", + "0x532e00535a00531e01b35800532e00535800531f01b2c900532e0052cb", + "0x525b01b01b32e00501b00701b01b74e01b32e0072c935f00727501b35a", + "0x2d901b2c800532e00501b03f01b01b32e0050c100525b01b01b32e00532f", + "0x1b74f00501b19401b2c100532e0052c70052db01b2c700532e0052c8005", + "0x50cd00511501b2be0cd00732e0050c100518201b01b32e00501b00701b", + "0x2bc01b01b32e0052bc00511501b0c42bc00732e00532f00518201b01b32e", + "0x70ce2bf00727501b0ce00532e0050c40052bc01b2bf00532e0052be005", + "0x52d901b2c600532e00501b03f01b01b32e00501b00701b01b75001b32e", + "0x1b01b74f00501b19401b2c100532e0052b90052db01b2b900532e0052c6", + "0x2b700532e0052b80050ad01b2b800532e00501b03f01b01b32e00501b007", + "0xd200575201b0d200532e0052c100575101b2c100532e0052b70052db01b", + "0x35800532e00535800531f01b2eb00532e0052eb00504601b2c500532e005", + "0x3582eb0470052c500532e0052c500575301b35a00532e00535a00531e01b", + "0x32e00501b32601b01b32e00504700525b01b01b32e00501b00701b2c535a", + "0x1b2c300532e0052c200575401b2c200532e0050bb0d40070c901b0d4005", + "0x50b800531e01b0b900532e0050b900531f01b2eb00532e0052eb005046", + "0x1b00701b2c30b80b92eb0470052c300532e0052c300575301b0b800532e", + "0x70c901b0d600532e00501b32601b01b32e00504700525b01b01b32e005", + "0x32e0052eb00504601b2b600532e0052c400575401b2c400532e0053570d6", + "0x75301b04a00532e00504a00531e01b2d400532e0052d400531f01b2eb005", + "0x25b01b01b32e00501b00701b2b604a2d42eb0470052b600532e0052b6005", + "0x1b2ae00532e00501b32601b01b32e0052df0051e401b01b32e005047005", + "0x2eb00504601b2ab00532e0052b000575401b2b000532e0052d72ae0070c9", + "0x2d800532e0052d800531e01b2d900532e0052d900531f01b2eb00532e005", + "0x1b32e00501b00701b2ab2d82d92eb0470052ab00532e0052ab00575301b", + "0x32e0052ea00525b01b01b32e0050450051e401b01b32e00504700525b01b", + "0x575401b0dc00532e0052dd2aa0070c901b2aa00532e00501b32601b01b", + "0x532e0050a800531f01b2eb00532e0052eb00504601b2a800532e0050dc", + "0x2eb0470052a800532e0052a800575301b0aa00532e0050aa00531e01b0a8", + "0x4700525b01b01b32e0050a400505401b01b32e00501b00701b2a80aa0a8", + "0x525b01b01b32e0052ea00525b01b01b32e0050450051e401b01b32e005", + "0x2a01b2a500532e00501b05701b2a600532e00501b33001b01b32e0052ec", + "0x509900531f01b0e000532e0052a52a600703101b2a500532e0052a5005", + "0x1b0e100532e0050e000522801b2a100532e00508500531e01b2a300532e", + "0x1e401b01b32e00504700525b01b01b32e00501b00701b01b75500501b194", + "0x1b01b32e0052ec00525b01b01b32e0052ea00525b01b01b32e005045005", + "0x509d00522801b2a100532e0052e300531e01b2a300532e0052e400531f", + "0x1b29d00532e0050e12a00070c901b2a000532e00501b32601b0e100532e", + "0x52a300531f01b2eb00532e0052eb00504601b29c00532e00529d005754", + "0x529c00532e00529c00575301b2a100532e0052a100531e01b2a300532e", + "0x1e401b01b32e00504700525b01b01b32e00501b00701b29c2a12a32eb047", + "0x1b01b32e00508400575601b01b32e00504800525b01b01b32e005045005", + "0x1b33001b29a00532e0052f829b00774201b29b00532e0052f72f9007742", + "0x1b29800532e00529800502a01b29800532e00501b05701b29900532e005", + "0x2950eb0070c901b0eb00532e00501b32601b29500532e005298299007031", + "0x29a00532e00529a00504601b29400532e0050ed00575401b0ed00532e005", + "0x29400575301b00700532e00500700531e01b00500532e00500500531f01b", + "0x30300505401b01b32e00501b00701b29400700529a04700529400532e005", + "0x525b01b01b32e0050450051e401b01b32e00504700525b01b01b32e005", + "0x1b29300532e00507600504601b01b32e00504600525b01b01b32e005048", + "0x1e401b01b32e00504700525b01b01b32e00501b00701b01b75700501b194", + "0x1b01b32e00504600525b01b01b32e00504800525b01b01b32e005045005", + "0x32e00520700514401b20700532e00501b00504601b01b32e00504300525b", + "0x575101b0ef00532e0052920052d901b29200532e00501b03f01b293005", + "0x532e00500500531f01b0f000532e0050f100575201b0f100532e0050ef", + "0x2930470050f000532e0050f000575301b00700532e00500700531e01b005", + "0x4804732e00500700575901b00701b00732e00501b00575801b0f0007005", + "0x575a01b01b32e00504600575a01b01b32e00504700575a01b045046047", + "0x4300532e00504400575c01b04400532e00504800575b01b01b32e005045", + "0x3f19404004104732e00504200575901b04200500732e00500500575801b", + "0x32e00503f00575a01b01b32e00519400575a01b01b32e00504000575a01b", + "0x735801b02300532e00503e00575c01b03e00532e00504100575b01b01b", + "0x32e00707b0052dd01b07b00532e00507b00502a01b07b00532e005023043", + "0x1b19101b00732e00501b00575801b01b32e00501b00701b02000575d01b", + "0x575a01b01b32e00532b00575a01b33032900932b04732e005191005759", + "0x1b02d00532e00500900575b01b01b32e00533000575a01b01b32e005329", + "0x3100575901b03100500732e00500500575801b02a00532e00502d00575c", + "0x32e00532000575a01b01b32e00532600575a01b31f3200c932604732e005", + "0x31e00575c01b31e00532e0050c900575b01b01b32e00531f00575a01b01b", + "0x532e00503900502a01b03900532e00503702a00735801b03700532e005", + "0x575801b01b32e00501b00701b03800575e01b32e0070390052dd01b039", + "0x575a01b2072031fb31c04732e00503600575901b03601b00732e00501b", + "0x75b01b01b32e00520700575a01b01b32e0051fb00575a01b01b32e00531c", + "0x32e00500500575801b21100532e00520d00575c01b20d00532e005203005", + "0x32e00521600575a01b22221c21821604732e00521400575901b214005007", + "0x521c00575b01b01b32e00522200575a01b01b32e00521800575a01b01b", + "0x22900532e00504c21100735801b04c00532e00522800575c01b22800532e", + "0x701b05400575f01b32e0072290052dd01b22900532e00522900502a01b", + "0x505100575a01b23105505205104732e00501b00575901b01b32e00501b", + "0x23100575b01b01b32e00505500575a01b01b32e00505200575a01b01b32e", + "0x5704732e00500500575901b23400532e00523200575c01b23200532e005", + "0x575a01b01b32e00505900575a01b01b32e00505700575a01b056058059", + "0x24900532e00523a00575c01b23a00532e00505600575b01b01b32e005058", + "0x52dd01b03300532e00503300502a01b03300532e00524923400735801b", + "0x25400532e00501b03f01b01b32e00501b00701b05f00576001b32e007033", + "0x1b06200500506200532e0050620052db01b06200532e0052540050ad01b", + "0x1b06100532e00501b03f01b01b32e00505f0052da01b01b32e00501b007", + "0x701b26c00500526c00532e00526c0052db01b26c00532e0050610052d9", + "0x58401b01b32e00500500558401b01b32e0050540052da01b01b32e00501b", + "0x52da01b01b32e00501b00701b01b76100501b19401b01b32e00501b005", + "0x19401b01b32e00501b00558401b01b32e00500500558401b01b32e005038", + "0x558401b01b32e0050200052da01b01b32e00501b00701b01b76100501b", + "0x2d901b00600532e00501b03f01b01b32e00501b00558401b01b32e005005", + "0x1b31c01b06900500506900532e0050690052db01b06900532e005006005", + "0x32e00704704600714601b04604800732e0050480051fb01b04700532e005", + "0x1b04304404504832e00500500576301b01b32e00501b00701b01b76201b", + "0x486df01b04104800732e0050480051fb01b04204300732e0050430051fb", + "0x58b01b01b32e00501b00701b03e03f00776419404000732e00704104201b", + "0x32e00502300520701b07b19400732e0051940051fb01b02300532e00501b", + "0x1b00701b00932b00776519102000732e00702307b04004833701b023005", + "0x51fb01b32900532e00501b58b01b01b32e00519100504c01b01b32e005", + "0x732933000714601b02000532e00502000504601b33019400732e005194", + "0x1b58b01b01b32e00504800504c01b01b32e00501b00701b01b76601b32e", + "0x32e00702d19402004833701b02d00532e00502d00520701b02d00532e005", + "0x32000532e00501b6c601b01b32e00501b00701b0c932600776703102a007", + "0x714601b02a00532e00502a00504601b31f03100732e0050310051fb01b", + "0x31e00532e00501b6c601b01b32e00501b00701b01b76801b32e00732031f", + "0x4833701b31e00532e00531e00520701b03703100732e0050310051fb01b", + "0x4c01b01b32e00501b00701b31c03600776903803900732e00731e03702a", + "0x21120d20704876a2031fb00732e00700703900728f01b01b32e005038005", + "0x532e0051fb00504601b21400532e00501b16801b01b32e00501b00701b", + "0x1b19401b21c00532e00521400518301b21800532e00520300518301b216", + "0x518301b21600532e00520700504601b01b32e00501b00701b01b76b005", + "0x22200532e00501b6c601b21c00532e00520d00518301b21800532e005211", + "0x4833701b22200532e00522200520701b22803100732e0050310051fb01b", + "0x4601b01b32e00501b00701b05105400776c22904c00732e007222228216", + "0x522904c00776d01b22900532e00522900520701b04c00532e00504c005", + "0x32e00501b00701b23200576f23100532e00705500576e01b05505200732e", + "0x1b05700577201b32e00723400577101b23400532e00523100577001b01b", + "0x1b01b32e00503100504c01b01b32e00504500577301b01b32e00501b007", + "0x1b32e00504400532901b01b32e00521800511501b01b32e00504300504c", + "0x532e00501b05701b05900532e00501b33001b01b32e00521c00511501b", + "0x4601b05600532e00505805900703101b05800532e00505800502a01b058", + "0x1b77400501b19401b24900532e00505600522801b23a00532e005052005", + "0xc401b25405f03304832e00505721c0520481ba01b01b32e00501b00701b", + "0x32e00505f0050c401b06100532e0052180050c401b06200532e005254005", + "0x20701b06904300732e0050430051fb01b00600532e00501b58b01b26c005", + "0x6e0077752d306b00732e00706900603304833701b00600532e005006005", + "0x50710620071fe01b07100532e00501b20101b01b32e00501b00701b06f", + "0x3400532e0050612ee0072ab01b2ee00532e0052ee00502a01b2ee00532e", + "0x7600520701b3112d300732e0052d30051fb01b07600532e00501b6c601b", + "0x32e00707631106b04833701b03400532e00503400502a01b07600532e005", + "0x1b32e00507200504c01b01b32e00501b00701b07407a007776072073007", + "0x2d307304833701b30f00532e00530f00520701b30f00532e00501b6c601b", + "0x30e00504601b01b32e00501b00701b30b30c00777730d30e00732e00730f", + "0x732e00530d30e00776d01b30d00532e00530d00520701b30e00532e005", + "0x1b01b32e00501b00701b08600577830500532e00730900576e01b30930a", + "0x32e00501b20101b30300532e0053040050c401b30400532e005305005770", + "0x1b30100532e00530a00504601b30200532e0050843030071fe01b084005", + "0x1b01b32e00501b00701b01b77900501b19401b08200532e00530200502a", + "0x1b32e00504300504c01b01b32e00503100504c01b01b32e005045005773", + "0x32e00504400532901b01b32e00526c00532901b01b32e00503400532901b", + "0x504601b01b32e00530000530301b2ff30000732e00508600530401b01b", + "0x1b01b77a00501b19401b08700532e0052ff00522801b07d00532e00530a", + "0x1b01b32e00504500577301b01b32e00530b00504c01b01b32e00501b007", + "0x1b32e00503400532901b01b32e00504300504c01b01b32e00503100504c", + "0x532e00501b33001b01b32e00526c00532901b01b32e00504400532901b", + "0x33800703101b2fc00532e0052fc00502a01b2fc00532e00501b5bc01b338", + "0x532e0052fb00522801b07d00532e00530c00504601b2fb00532e0052fc", + "0x1b32e00507400504c01b01b32e00501b00701b01b77a00501b19401b087", + "0x7a00776d01b2d300532e0052d300520701b07a00532e00507a00504601b", + "0x1b00701b2f700577b2f800532e0072f900576e01b2f92fa00732e0052d3", + "0x1b2f500532e0052f60050c401b2f600532e0052f800577001b01b32e005", + "0x820440071fe01b08200532e0052f500502a01b30100532e0052fa005046", + "0x532e0052f426c0072ab01b2f400532e0052f400502a01b2f400532e005", + "0x77d2f12f200732e0072f330100777c01b2f300532e0052f300502a01b2f3", + "0x4858c01b07c00532e0052f104500777e01b01b32e00501b00701b2ef005", + "0x508b00558d01b08d00532e0052f200504601b08b00532e00504303407c", + "0x504500577301b01b32e00501b00701b01b77f00501b19401b2ed00532e", + "0x3400532901b01b32e00504300504c01b01b32e00503100504c01b01b32e", + "0x502a01b2ec00532e00501b05701b09000532e00501b33001b01b32e005", + "0x32e0052ef00504601b08e00532e0052ec09000703101b2ec00532e0052ec", + "0x501b00701b01b77400501b19401b24900532e00508e00522801b23a005", + "0x4300504c01b01b32e00503100504c01b01b32e00504500577301b01b32e", + "0x532901b01b32e00526c00532901b01b32e00503400532901b01b32e005", + "0x1b32e0052eb00530301b2ea2eb00732e0052f700530401b01b32e005044", + "0x7d00514401b08700532e0052ea00522801b07d00532e0052fa00504601b", + "0x701b01b77400501b19401b24900532e00508700578001b23a00532e005", + "0x4c01b01b32e00504500577301b01b32e00506f00504c01b01b32e00501b", + "0x1b01b32e00506200532901b01b32e00504300504c01b01b32e005031005", + "0x1b32e00506100532901b01b32e00526c00532901b01b32e005044005329", + "0x32e0052e700502a01b2e700532e00501b5bc01b2e800532e00501b33001b", + "0x1b23a00532e00506e00504601b09900532e0052e72e800703101b2e7005", + "0x1b01b32e00501b00701b01b77400501b19401b24900532e005099005228", + "0x1b32e00504300504c01b01b32e00503100504c01b01b32e005045005773", + "0x32e00521c00511501b01b32e00504400532901b01b32e00521800511501b", + "0x504601b01b32e00508500530301b2e608500732e00523200530401b01b", + "0x1b01b77400501b19401b24900532e0052e600522801b23a00532e005052", + "0x1b01b32e00521c00511501b01b32e00505100504c01b01b32e00501b007", + "0x1b32e00504300504c01b01b32e00503100504c01b01b32e005045005773", + "0x532e00501b33001b01b32e00504400532901b01b32e00521800511501b", + "0x2e400703101b2e300532e0052e300502a01b2e300532e00501b5bc01b2e4", + "0x532e00509d00522801b23a00532e00505400504601b09d00532e0052e3", + "0x578101b0a400532e0052492e20070c901b2e200532e00501b32601b249", + "0x532e0050a000578201b23a00532e00523a00504601b0a000532e0050a4", + "0x28f01b01b32e00531c00504c01b01b32e00501b00701b0a023a0070050a0", + "0x1b01b32e00501b00701b2dd0aa0a80487832df2e100732e007007036007", + "0x32e0052df00518301b2db00532e0052e100504601b0ad00532e00501b168", + "0x501b00701b01b78400501b19401b2d900532e0050ad00518301b2da005", + "0x18301b2da00532e0052dd00518301b2db00532e0050a800504601b01b32e", + "0x32e0050310051fb01b2db00532e0052db00504601b2d900532e0050aa005", + "0x2d700732e0052d82db00776d01b2d800532e0052d800520701b2d8031007", + "0x77001b01b32e00501b00701b2d50057852d600532e0070b200576e01b0b2", + "0x501b00701b04a00578601b32e0072d400577101b2d400532e0052d6005", + "0x4300504c01b01b32e00503100504c01b01b32e00504500577301b01b32e", + "0x511501b01b32e00504400532901b01b32e0052d900511501b01b32e005", + "0x2a01b35800532e00501b05701b35700532e00501b33001b01b32e0052da", + "0x52d700504601b35a00532e00535835700703101b35800532e005358005", + "0x1b00701b01b78700501b19401b35b00532e00535a00522801b0cf00532e", + "0x52d90050c401b0bb0b80b904832e00504a2da2d70481ba01b01b32e005", + "0x1b2d203100732e0050310051fb01b0c100532e00501b6c601b0bd00532e", + "0x77882de32f00732e0072d20c10b904833701b0c100532e0050c1005207", + "0x2de00520701b32f00532e00532f00504601b01b32e00501b00701b2cc35d", + "0x32e0072cb00576e01b2cb0c600732e0052de32f00776d01b2de00532e005", + "0x1b2c900532e0050c700577001b01b32e00501b00701b35f0057890c7005", + "0x50bb0050c401b2c700532e0050b80050c401b2c800532e0052c90050c4", + "0x1b2be04300732e0050430051fb01b0cd00532e00501b58b01b2c100532e", + "0x778a0c42bc00732e0072be0cd0c604833701b0cd00532e0050cd005207", + "0x502a01b2c600532e0052c80bd0071fe01b01b32e00501b00701b0ce2bf", + "0x532e00501b6c601b2b900532e0052c72c60072ab01b2c600532e0052c6", + "0x2a01b2b800532e0052b800520701b2b70c400732e0050c40051fb01b2b8", + "0xd400778b2c50d200732e0072b82b72bc04833701b2b900532e0052b9005", + "0x532e00501b6c601b01b32e0052c500504c01b01b32e00501b00701b2c2", + "0x2c40d600732e0072c30c40d204833701b2c300532e0052c300520701b2c3", + "0x20701b0d600532e0050d600504601b01b32e00501b00701b2ae2b600778c", + "0x2ab00576e01b2ab2b000732e0052c40d600776d01b2c400532e0052c4005", + "0x532e0052aa00577001b01b32e00501b00701b0dc00578d2aa00532e007", + "0x2a60071fe01b2a500532e00501b20101b2a600532e0052a80050c401b2a8", + "0x532e0050e000502a01b2a300532e0052b000504601b0e000532e0052a5", + "0x1b32e00504500577301b01b32e00501b00701b01b78e00501b19401b2a1", + "0x32e0052c100532901b01b32e00504300504c01b01b32e00503100504c01b", + "0x50dc00530401b01b32e00504400532901b01b32e0052b900532901b01b", + "0x1b29d00532e0052b000504601b01b32e0050e100530301b2a00e100732e", + "0x1b01b32e00501b00701b01b78f00501b19401b29c00532e0052a0005228", + "0x1b32e00503100504c01b01b32e00504500577301b01b32e0052ae00504c", + "0x32e00504400532901b01b32e0052c100532901b01b32e00504300504c01b", + "0x32e00501b5bc01b29b00532e00501b33001b01b32e0052b900532901b01b", + "0x1b29900532e00529a29b00703101b29a00532e00529a00502a01b29a005", + "0x78f00501b19401b29c00532e00529900522801b29d00532e0052b6005046", + "0x32e0050d400504601b01b32e0052c200504c01b01b32e00501b00701b01b", + "0x29529800732e0050c40d400776d01b0c400532e0050c400520701b0d4005", + "0x577001b01b32e00501b00701b0ed0057900eb00532e00729500576e01b", + "0x532e00529800504601b29300532e0052940050c401b29400532e0050eb", + "0x2a01b29200532e0052a10440071fe01b2a100532e00529300502a01b2a3", + "0x50ef00502a01b0ef00532e0052922b90072ab01b29200532e005292005", + "0x501b00701b0ee0057910f00f100732e0070ef2a300777c01b0ef00532e", + "0x532e0050432c129104858c01b29100532e0050f004500777e01b01b32e", + "0x514401b2ed00532e00529000558d01b08d00532e0050f100504601b290", + "0x1b01b79300501b19401b0f900532e0052ed00579201b0f700532e00508d", + "0x1b01b32e00503100504c01b01b32e00504500577301b01b32e00501b007", + "0xf800532e00501b33001b01b32e0052c100532901b01b32e00504300504c", + "0xf60f800703101b0f600532e0050f600502a01b0f600532e00501b05701b", + "0x35b00532e00528f00522801b0cf00532e0050ee00504601b28f00532e005", + "0x1b01b32e00504500577301b01b32e00501b00701b01b78700501b19401b", + "0x1b32e0052c100532901b01b32e00504300504c01b01b32e00503100504c", + "0x32e0050ed00530401b01b32e00504400532901b01b32e0052b900532901b", + "0x22801b29d00532e00529800504601b01b32e00528e00530301b0ff28e007", + "0x32e00529c00578001b0cf00532e00529d00514401b29c00532e0050ff005", + "0x32e0050ce00504c01b01b32e00501b00701b01b78700501b19401b35b005", + "0x504300504c01b01b32e00503100504c01b01b32e00504500577301b01b", + "0xbd00532901b01b32e00504400532901b01b32e0052c100532901b01b32e", + "0x1b33001b01b32e0052c700532901b01b32e0052c800532901b01b32e005", + "0x1b10000532e00510000502a01b10000532e00501b5bc01b10100532e005", + "0xfe00522801b0cf00532e0052bf00504601b0fe00532e005100101007031", + "0x4500577301b01b32e00501b00701b01b78700501b19401b35b00532e005", + "0x532901b01b32e00504300504c01b01b32e00503100504c01b01b32e005", + "0x11501b01b32e0050b800511501b01b32e0050bd00532901b01b32e005044", + "0x32e00528c00530301b28b28c00732e00535f00530401b01b32e0050bb005", + "0x1b19401b35b00532e00528b00522801b0cf00532e0050c600504601b01b", + "0x4500577301b01b32e0052cc00504c01b01b32e00501b00701b01b787005", + "0x511501b01b32e00504300504c01b01b32e00503100504c01b01b32e005", + "0x11501b01b32e0050bd00532901b01b32e00504400532901b01b32e0050bb", + "0x1b10900532e00501b5bc01b10700532e00501b33001b01b32e0050b8005", + "0x35d00504601b10800532e00510910700703101b10900532e00510900502a", + "0x701b01b78700501b19401b35b00532e00510800522801b0cf00532e005", + "0x4c01b01b32e00503100504c01b01b32e00504500577301b01b32e00501b", + "0x1b01b32e00504400532901b01b32e0052d900511501b01b32e005043005", + "0x510600530301b28a10600732e0052d500530401b01b32e0052da005115", + "0x32601b35b00532e00528a00522801b0cf00532e0052d700504601b01b32e", + "0x32e00510f00578101b10f00532e00535b1130070c901b11300532e00501b", + "0x700510e00532e00510e00578201b0cf00532e0050cf00504601b10e005", + "0x4879411528900732e00700702a00728f01b01b32e00501b00701b10e0cf", + "0x28900504601b28500532e00501b16801b01b32e00501b00701b286287117", + "0x11c00532e00528500518301b11a00532e00511500518301b28400532e005", + "0x28400532e00511700504601b01b32e00501b00701b01b79500501b19401b", + "0x11c0050c401b11c00532e00528700518301b11a00532e00528600518301b", + "0x1b28300532e00501b58b01b11900532e00511a0050c401b11b00532e005", + "0x28404833701b28300532e00528300520701b01804300732e0050430051fb", + "0x1b6c601b01b32e00501b00701b04928000779612112200732e007018283", + "0x532e00527f00520701b27e12100732e0051210051fb01b27f00532e005", + "0x501b00701b27b27c00779712612700732e00727f27e12204833701b27f", + "0x12c00520701b12c00532e00501b6c601b01b32e00512600504c01b01b32e", + "0x1b27a12b00779812d12e00732e00712c12112704833701b12c00532e005", + "0x532e00512d00520701b12e00532e00512e00504601b01b32e00501b007", + "0x79913500532e00727800576e01b27827900732e00512d12e00776d01b12d", + "0x2760050c401b27600532e00513500577001b01b32e00501b00701b134005", + "0x14600532e0052742750071fe01b27400532e00501b20101b27500532e005", + "0x501b19401b13f00532e00514600502a01b13d00532e00527900504601b", + "0x503100504c01b01b32e00504500577301b01b32e00501b00701b01b79a", + "0x11b00532901b01b32e00511900532901b01b32e00504300504c01b01b32e", + "0x1b14214100732e00513400530401b01b32e00504400532901b01b32e005", + "0x32e00514200522801b14400532e00527900504601b01b32e005141005303", + "0x32e00527a00504c01b01b32e00501b00701b01b79b00501b19401b271005", + "0x504300504c01b01b32e00503100504c01b01b32e00504500577301b01b", + "0x11b00532901b01b32e00504400532901b01b32e00511900532901b01b32e", + "0x502a01b27300532e00501b5bc01b26f00532e00501b33001b01b32e005", + "0x32e00512b00504601b14e00532e00527326f00703101b27300532e005273", + "0x501b00701b01b79b00501b19401b27100532e00514e00522801b144005", + "0x520701b27c00532e00527c00504601b01b32e00527b00504c01b01b32e", + "0x714c00576e01b14c14d00732e00512127c00776d01b12100532e005121", + "0x14900532e00514b00577001b01b32e00501b00701b14a00579c14b00532e", + "0x14800502a01b13d00532e00514d00504601b14800532e0051490050c401b", + "0x532e00514700502a01b14700532e00513f0440071fe01b13f00532e005", + "0x77c01b15800532e00515800502a01b15800532e00514711b0072ab01b147", + "0x777e01b01b32e00501b00701b26a00579d26b26d00732e00715813d007", + "0x26d00504601b26800532e00504311926904858c01b26900532e00526b045", + "0x26604832e0050f900576301b0f900532e00526800558d01b0f700532e005", + "0x1b26300532e00503126526604858c01b01b32e00526400504c01b264265", + "0x516300579f01b16300532e00516126300779e01b16100532e00501b03f", + "0x526100532e00526100578201b0f700532e0050f700504601b26100532e", + "0x3100504c01b01b32e00504500577301b01b32e00501b00701b2610f7007", + "0x1b33001b01b32e00511900532901b01b32e00504300504c01b01b32e005", + "0x1b26000532e00526000502a01b26000532e00501b05701b16500532e005", + "0x16600522801b16800532e00526a00504601b16600532e005260165007031", + "0x4500577301b01b32e00501b00701b01b7a000501b19401b16900532e005", + "0x532901b01b32e00504300504c01b01b32e00503100504c01b01b32e005", + "0x30401b01b32e00504400532901b01b32e00511b00532901b01b32e005119", + "0x32e00514d00504601b01b32e00516b00530301b25f16b00732e00514a005", + "0x78001b16800532e00514400514401b27100532e00525f00522801b144005", + "0x4c01b01b32e00501b00701b01b7a000501b19401b16900532e005271005", + "0x1b01b32e00503100504c01b01b32e00504500577301b01b32e005049005", + "0x1b32e00504400532901b01b32e00511900532901b01b32e00504300504c", + "0x532e00501b5bc01b13a00532e00501b33001b01b32e00511b00532901b", + "0x4601b25d00532e00513913a00703101b13900532e00513900502a01b139", + "0x532e00501b32601b16900532e00525d00522801b16800532e005280005", + "0x4601b25800532e00525900578101b25900532e00516925a0070c901b25a", + "0x701b25816800700525800532e00525800578201b16800532e005168005", + "0x77301b01b32e00504400532901b01b32e0050c900504c01b01b32e00501b", + "0x1b01b32e00504300504c01b01b32e00500700532901b01b32e005045005", + "0x532e00525600502a01b25600532e00501b5bc01b25700532e00501b330", + "0x70c901b17300532e00501b32601b17100532e00525625700703101b256", + "0x32e00532600504601b17600532e00517400578101b17400532e005171173", + "0x1b32e00501b00701b17632600700517600532e00517600578201b326005", + "0x532e00501b6c601b01b32e00519400504c01b01b32e00504300504c01b", + "0x33701b25500532e00525500520701b17804800732e0050480051fb01b255", + "0x1b01b32e00501b00701b1822530077a117b17900732e007255178020048", + "0x532e00518100520701b18100532e00501b6c601b01b32e00517b00504c", + "0x501b00701b17c24f0077a218418300732e00718104817904833701b181", + "0x76d01b18400532e00518400520701b18300532e00518300504601b01b32e", + "0x1b1890057a324c00532e00725b00576e01b25b25000732e005184183007", + "0x532e00518b0050c401b18b00532e00524c00577001b01b32e00501b007", + "0x504601b18f00532e00518d24b0071fe01b18d00532e00501b20101b24b", + "0x1b01b7a400501b19401b24700532e00518f00502a01b24a00532e005250", + "0x1b01b32e00500700532901b01b32e00504500577301b01b32e00501b007", + "0x524500530301b24324500732e00518900530401b01b32e005044005329", + "0x19401b24100532e00524300522801b24200532e00525000504601b01b32e", + "0x577301b01b32e00517c00504c01b01b32e00501b00701b01b7a500501b", + "0x33001b01b32e00500700532901b01b32e00504400532901b01b32e005045", + "0x23900532e00523900502a01b23900532e00501b5bc01b24000532e00501b", + "0x522801b24200532e00524f00504601b23800532e00523924000703101b", + "0x504c01b01b32e00501b00701b01b7a500501b19401b24100532e005238", + "0x4800532e00504800520701b25300532e00525300504601b01b32e005182", + "0x57a619900532e00723600576e01b23623700732e00504825300776d01b", + "0x52300050c401b23000532e00519900577001b01b32e00501b00701b233", + "0x1b24700532e00522e00502a01b24a00532e00523700504601b22e00532e", + "0x70072ab01b19d00532e00519d00502a01b19d00532e0052470440071fe", + "0x32e00719f24a00777c01b19f00532e00519f00502a01b19f00532e00519d", + "0x532e00522c04500777e01b01b32e00501b00701b22b0057a722c22d007", + "0x22322504858c01b22100532e00501b31c01b22300532e00501b23201b225", + "0x532e0051a721f00779e01b1a700532e00501b03f01b21f00532e005221", + "0x578201b22d00532e00522d00504601b1a900532e00521900579f01b219", + "0x504500577301b01b32e00501b00701b1a922d0070051a900532e0051a9", + "0x21700502a01b21700532e00501b05701b1ab00532e00501b33001b01b32e", + "0x21500532e00501b32601b17d00532e0052171ab00703101b21700532e005", + "0x504601b1af00532e00521a00578101b21a00532e00517d2150070c901b", + "0x1b00701b1af22b0070051af00532e0051af00578201b22b00532e00522b", + "0x532901b01b32e00500700532901b01b32e00504500577301b01b32e005", + "0x1b32e00521200530301b21021200732e00523300530401b01b32e005044", + "0x501b32601b24100532e00521000522801b24200532e00523700504601b", + "0x20c00532e00520e00578101b20e00532e0052411b20070c901b1b200532e", + "0x20c24200700520c00532e00520c00578201b24200532e00524200504601b", + "0x1b32e00519400504c01b01b32e00500900504c01b01b32e00501b00701b", + "0x32b00504601b20904300732e0050430051fb01b20a00532e00501b31c01b", + "0x1b32e00501b00701b01b7a801b32e00720a20900714601b32b00532e005", + "0x20800520701b1b804800732e0050480051fb01b20800532e00501b6c601b", + "0x1b1ba2020077a920020400732e0072081b832b04833701b20800532e005", + "0x1b20100532e00501b6c601b01b32e00520000504c01b01b32e00501b007", + "0x20404833701b20100532e00520100520701b1fe04800732e0050480051fb", + "0x504601b01b32e00501b00701b1c11fc0077aa1bf1bd00732e0072011fe", + "0x32e0051bf1bd00776d01b1bf00532e0051bf00520701b1bd00532e0051bd", + "0x1b32e00501b00701b1f30057ab1f400532e0071ff00576e01b1ff1f9007", + "0x501b20101b1f100532e0051f20050c401b1f200532e0051f400577001b", + "0x1ee00532e0051f900504601b1ef00532e0051f01f10071fe01b1f000532e", + "0x1b32e00501b00701b01b7ac00501b19401b1c800532e0051ef00502a01b", + "0x32e00500700532901b01b32e00504500577301b01b32e00504400532901b", + "0x51f300530401b01b32e00504300504c01b01b32e00504800504c01b01b", + "0x1b1e400532e0051f900504601b01b32e0051e900530301b1e71e900732e", + "0x1b01b32e00501b00701b01b7ad00501b19401b1e200532e0051e7005228", + "0x1b32e00504300504c01b01b32e00504400532901b01b32e0051c100504c", + "0x32e00504800504c01b01b32e00500700532901b01b32e00504500577301b", + "0x51d800502a01b1d800532e00501b5bc01b1df00532e00501b33001b01b", + "0x1e400532e0051fc00504601b1e500532e0051d81df00703101b1d800532e", + "0x1b32e00501b00701b01b7ad00501b19401b1e200532e0051e500522801b", + "0x50480051fb01b20200532e00520200504601b01b32e0051ba00504c01b", + "0x732e00500020200776d01b00000532e00500000520701b00004800732e", + "0x1b01b32e00501b00701b5160057ae51500532e00751400576e01b514513", + "0x551300504601b51800532e0055170050c401b51700532e005515005770", + "0x732e0070480431ee0486df01b1c800532e00551800502a01b1ee00532e", + "0x532e0051c80440071fe01b01b32e00501b00701b51c51b0077af51a519", + "0x58c01b51e00532e0053370070072ab01b33700532e00533700502a01b337", + "0x52151f00779e01b52100532e00501b03f01b51f00532e00551a51e045048", + "0x51900532e00551900504601b52300532e00552200579f01b52200532e005", + "0x4c01b01b32e00501b00701b52351900700552300532e00552300578201b", + "0x1b01b32e0051c800532901b01b32e00504400532901b01b32e00551c005", + "0x52400532e00501b33001b01b32e00500700532901b01b32e005045005773", + "0x52652400703101b52600532e00552600502a01b52600532e00501b6e201b", + "0x52800532e0055273360070c901b33600532e00501b32601b52700532e005", + "0x52900578201b51b00532e00551b00504601b52900532e00552800578101b", + "0x32e00504400532901b01b32e00501b00701b52951b00700552900532e005", + "0x504800504c01b01b32e00500700532901b01b32e00504500577301b01b", + "0x30301b52c52b00732e00551600530401b01b32e00504300504c01b01b32e", + "0x532e00552c00522801b1e400532e00551300504601b01b32e00552b005", + "0x578101b52f00532e0051e252d0070c901b52d00532e00501b32601b1e2", + "0x532e00553000578201b1e400532e0051e400504601b53000532e00552f", + "0x4c01b01b32e00504400532901b01b32e00501b00701b5301e4007005530", + "0x32e00501b03f01b53100532e00504800704504858c01b01b32e005043005", + "0x1b53400532e00553300579f01b53300532e00553253100779e01b532005", + "0x1b53432b00700553400532e00553400578201b32b00532e00532b005046", + "0x1b01b32e00504400532901b01b32e00503e00504c01b01b32e00501b007", + "0x1b32e00504300504c01b01b32e00500700532901b01b32e005045005773", + "0x532e00501b6e201b53500532e00501b33001b01b32e00504800504c01b", + "0x32601b53700532e00553653500703101b53600532e00553600502a01b536", + "0x32e00533500578101b33500532e0055375380070c901b53800532e00501b", + "0x700553900532e00553900578201b03f00532e00503f00504601b539005", + "0x500700532901b01b32e00504800504c01b01b32e00501b00701b53903f", + "0x79f01b53b00532e00553a00500779e01b53a00532e00501b03f01b01b32e", + "0x32e00553c00578201b01b00532e00501b00504601b53c00532e00553b005", + "0x732e00700501b00700501b01b32e00501b02001b53c01b00700553c005", + "0x4300532e00500700535501b01b32e00501b00701b0440450077b0046047", + "0x32e0070430057b101b04700532e00504700504601b01b32e00501b04701b", + "0x19400532e0050410057b301b01b32e00501b00701b0400057b2041042007", + "0x501b19401b03e00532e0051940057b501b03f00532e0050420057b401b", + "0x50230057b701b02300532e00501b03f01b01b32e00501b00701b01b7b6", + "0x1b03e00532e00507b0057b501b03f00532e0050400057b401b07b00532e", + "0x501b02001b01b32e00501b00701b1910057b902000532e00703e0057b8", + "0x7bc01b00900532e00532b0057bb01b32b00532e0050200057ba01b01b32e", + "0x532904800703101b32900532e00532900502a01b32900532e005009005", + "0x1b04700532e00504700504601b02d00532e00503f00559f01b33000532e", + "0x533000522801b02d00532e00502d00533c01b04600532e00504600531f", + "0x3102a04800532603102a04832e00533002d0460470475a101b33000532e", + "0x1b32e00519100505401b01b32e00501b02001b01b32e00501b00701b326", + "0x50c90480072a301b0c900532e00501b03f01b01b32e00503f0055a201b", + "0x1b04700532e00504700504601b31f00532e0053200052a101b32000532e", + "0x31f04604704800531f00532e00531f0050e101b04600532e00504600531f", + "0x1b32e0050070057bd01b01b32e00504800521601b01b32e00501b00701b", + "0x32e00503700502a01b03700532e00501b22901b31e00532e00501b33001b", + "0xc901b03800532e00501b32601b03900532e00503731e00703101b037005", + "0x504500504601b31c00532e0050360052a001b03600532e005039038007", + "0x531c00532e00531c0050e101b04400532e00504400531f01b04500532e", + "0x4800732e00700700504501b00700532e00500500504801b31c044045048", + "0x4301b04500532e00504700504401b01b32e00501b00701b0460057be047", + "0x32e00504800504101b04300532e00504400504201b04400532e005045005", + "0x501b00701b01b7bf00501b19401b04100532e00504300504001b042005", + "0x504101b19400532e00504000503e01b04000532e00501b03f01b01b32e", + "0x532e00704100502301b04100532e00519400504001b04200532e005046", + "0x7c107b02300732e00704200504501b01b32e00501b00701b03e0057c003f", + "0x2300504101b19100532e00507b00524901b01b32e00501b00701b020005", + "0x701b01b7c200501b19401b00900532e00519100503301b32b00532e005", + "0x1b33000532e00532900505f01b32900532e00501b03f01b01b32e00501b", + "0x532b00530a01b00900532e00533000503301b32b00532e005020005041", + "0x3100532e00700900525401b02a00532e00502d00521801b02d32b00732e", + "0x504301b0c900532e00503100504401b01b32e00501b00701b3260057c3", + "0x32e00732001b0072fb01b32000532e00532000502a01b32000532e0050c9", + "0x1b01b32e00502a00505501b01b32e00501b00701b0370057c431e31f007", + "0x1b0360057c503803900732e00732b00504501b31f00532e00531f005046", + "0x532e00503900504101b31c00532e00503800524901b01b32e00501b007", + "0x32e00501b00701b01b7c600501b19401b20300532e00531c00503301b1fb", + "0x3600504101b20d00532e00520700505f01b20700532e00501b03f01b01b", + "0x21100532e0051fb00521801b20300532e00520d00503301b1fb00532e005", + "0x504401b01b32e00501b00701b2160057c721400532e00720300525401b", + "0x532e00521c00502a01b21c00532e00521800504301b21800532e005214", + "0x501b00701b05422904c0487c822822200732e00721c31f00728f01b21c", + "0x5200532e0050510057ca01b05100532e00522831e03f0487c901b01b32e", + "0x520057cb01b21100532e00521100506201b22200532e00522200504601b", + "0x522900511501b01b32e00501b00701b05221122204800505200532e005", + "0x31e0052fa01b01b32e00503f00532901b01b32e00505400511501b01b32e", + "0x1b00701b01b7cc00501b19401b05500532e00504c00504601b01b32e005", + "0x52fa01b01b32e00503f00532901b01b32e00521600505401b01b32e005", + "0x1b23100532e00501b03f01b05500532e00531f00504601b01b32e00531e", + "0x52320057cb01b21100532e00521100506201b23200532e0052310057cd", + "0x32e00503f00532901b01b32e00501b00701b23221105504800523200532e", + "0x501b19401b23400532e00503700504601b01b32e00532b00519101b01b", + "0x503f00532901b01b32e00532600505401b01b32e00501b00701b01b7ce", + "0x1b03f01b23400532e00501b00504601b01b32e00532b00519101b01b32e", + "0x2a00532e00502a00506201b05900532e0050570057cd01b05700532e005", + "0x1b01b32e00501b00701b05902a23404800505900532e0050590057cb01b", + "0x501b00504601b05600532e00503e0057cd01b05800532e005042005218", + "0x505600532e0050560057cb01b05800532e00505800506201b01b00532e", + "0x4600532e00501b7cf01b04704800732e00500700518201b05605801b048", + "0x4304404504832e00504604801b0481ba01b04600532e00504600520201b", + "0x1b01b32e00501b00701b0400057d104104200732e0070440450077d001b", + "0x17c01b01b32e00501b00701b03e0057d203f19400732e0070430420077d0", + "0x501b7cf01b07b00532e00504102300717c01b02300532e00503f005007", + "0x4832e0050200471940481ba01b02000532e00502000520201b02000532e", + "0x32900732e00732b1910077d001b07b00532e00507b00525801b00932b191", + "0x3102a00732e0070093290077d001b01b32e00501b00701b02d0057d3330", + "0x17c01b0c900532e00503107b00717c01b01b32e00501b00701b3260057d4", + "0x531f3200076cb01b31f00532e00501b03f01b32000532e0053300c9007", + "0x1b02a00532e00502a00504601b03700532e00531e0056cc01b31e00532e", + "0x517901b01b32e00501b00701b03702a00700503700532e0050370056b4", + "0x5701b03900532e00501b33001b01b32e0053300052fa01b01b32e00507b", + "0x32e00503803900703101b03800532e00503800502a01b03800532e00501b", + "0x19401b1fb00532e00503600522801b31c00532e00532600504601b036005", + "0x511501b01b32e00507b00517901b01b32e00501b00701b01b7d500501b", + "0x2a01b20700532e00501b05701b20300532e00501b33001b01b32e005009", + "0x502d00504601b20d00532e00520720300703101b20700532e005207005", + "0xc901b21100532e00501b32601b1fb00532e00520d00522801b31c00532e", + "0x531c00504601b21600532e0052140056b301b21400532e0051fb211007", + "0x32e00501b00701b21631c00700521600532e0052160056b401b31c00532e", + "0x50410052fa01b01b32e00500500517901b01b32e00504700511501b01b", + "0x21c00502a01b21c00532e00501b05701b21800532e00501b33001b01b32e", + "0x532e00503e00504601b22200532e00521c21800703101b21c00532e005", + "0x32e00501b00701b01b7d600501b19401b04c00532e00522200522801b228", + "0x504300511501b01b32e00500500517901b01b32e00504700511501b01b", + "0x5400502a01b05400532e00501b05701b22900532e00501b33001b01b32e", + "0x532e00504000504601b05100532e00505422900703101b05400532e005", + "0x520070c901b05200532e00501b32601b04c00532e00505100522801b228", + "0x532e00522800504601b23100532e0050550056b301b05500532e00504c", + "0x1b01b32e00501b02001b23122800700523100532e0052310056b401b228", + "0x1b01b32e00501b00701b0440450077d704604700732e00700501b007005", + "0x504700504601b04204800732e0050480051fb01b04300532e00501b333", + "0x1b01b32e00501b00701b01b7d801b32e00704304200714601b04700532e", + "0x504100700717c01b04100532e0050410052f701b04100532e00501b2f9", + "0x25801b19400532e00519400520701b19400532e00501b33301b04000532e", + "0x230077d903e03f00732e00719404804704833701b04000532e005040005", + "0x504600531f01b03f00532e00503f00504601b01b32e00501b00701b07b", + "0x1b03e00532e00503e00520701b04000532e00504000525801b04600532e", + "0x1b00701b32b19102004800532b19102004832e00503e04004603f047349", + "0x1b33001b01b32e00504000517901b01b32e00507b00504c01b01b32e005", + "0x1b32900532e00532900502a01b32900532e00501b5bc01b00900532e005", + "0x33002d0070c901b02d00532e00501b32601b33000532e005329009007031", + "0x2300532e00502300504601b03100532e00502a0056b301b02a00532e005", + "0x4602304800503100532e0050310056b401b04600532e00504600531f01b", + "0x532e00501b6c901b01b32e00504800504c01b01b32e00501b00701b031", + "0x3f01b0c900532e00532600700717c01b32600532e0053260052f701b326", + "0x32e00531f0056cc01b31f00532e0053200c90076cb01b32000532e00501b", + "0x6b401b04600532e00504600531f01b04700532e00504700504601b31e005", + "0x517901b01b32e00501b00701b31e04604704800531e00532e00531e005", + "0x22901b03700532e00501b33001b01b32e00504800504c01b01b32e005007", + "0x32e00503903700703101b03900532e00503900502a01b03900532e00501b", + "0x6b301b31c00532e0050380360070c901b03600532e00501b32601b038005", + "0x32e00504400531f01b04500532e00504500504601b1fb00532e00531c005", + "0x50050052d201b1fb0440450480051fb00532e0051fb0056b401b044005", + "0x1b32e00501b00701b0480057da01b32e0070070052dd01b00700500732e", + "0x701b01b00500501b00532e00501b00524101b01b32e00500500532901b", + "0x20701b04700532e00501b31c01b01b32e0050480052da01b01b32e00501b", + "0x32e00501b23401b04600532e00504701b00724201b04700532e005047005", + "0x4300532e00504504400735801b04400500732e0050050052d201b045005", + "0x430052dd01b04600532e00504600524101b04300532e00504300502a01b", + "0x1b01b32e00500500532901b01b32e00501b00701b0420057db01b32e007", + "0x420052da01b01b32e00501b00701b04600500504600532e005046005241", + "0x24201b04100532e00504100520701b04100532e00501b31c01b01b32e005", + "0x32e0050050052d201b19400532e00501b16301b04000532e005041046007", + "0x3e00532e00503e00502a01b03e00532e00519403f00735801b03f005007", + "0x701b0230057dc01b32e00703e0052dd01b04000532e00504000524101b", + "0x504000532e00504000524101b01b32e00500500532901b01b32e00501b", + "0x32e00501b31c01b01b32e0050230052da01b01b32e00501b00701b040005", + "0x1b02000532e00507b04000724201b07b00532e00507b00520701b07b005", + "0x19132b00735801b32b00500732e0050050052d201b19100532e00501b7dd", + "0x2000532e00502000524101b00900532e00500900502a01b00900532e005", + "0x500532901b01b32e00501b00701b3290057de01b32e0070090052dd01b", + "0x1b32e00501b00701b02000500502000532e00502000524101b01b32e005", + "0x32e00533000520701b33000532e00501b31c01b01b32e0053290052da01b", + "0x2d201b02a00532e00501b7df01b02d00532e00533002000724201b330005", + "0x32600502a01b32600532e00502a03100735801b03100500732e005005005", + "0x7e001b32e0073260052dd01b02d00532e00502d00524101b32600532e005", + "0x502d00524101b01b32e00500500532901b01b32e00501b00701b0c9005", + "0x1b01b32e0050c90052da01b01b32e00501b00701b02d00500502d00532e", + "0x532002d00724201b32000532e00532000520701b32000532e00501b31c", + "0x1b03700500732e0050050052d201b31e00532e00501b7e101b31f00532e", + "0x31f00524101b03900532e00503900502a01b03900532e00531e037007358", + "0x1b32e00501b00701b0380057e201b32e0070390052dd01b31f00532e005", + "0x701b31f00500531f00532e00531f00524101b01b32e00500500532901b", + "0x20701b03600532e00501b31c01b01b32e0050380052da01b01b32e00501b", + "0x32e00501b7e301b31c00532e00503631f00724201b03600532e005036005", + "0x20700532e0051fb20300735801b20300500732e0050050052d201b1fb005", + "0x2070052dd01b31c00532e00531c00524101b20700532e00520700502a01b", + "0x1b01b32e00500500532901b01b32e00501b00701b20d0057e401b32e007", + "0x20d0052da01b01b32e00501b00701b31c00500531c00532e00531c005241", + "0x24201b21100532e00521100520701b21100532e00501b31c01b01b32e005", + "0x32e0050050052d201b21600532e00501b7e501b21400532e00521131c007", + "0x21c00532e00521c00502a01b21c00532e00521621800735801b218005007", + "0x701b2220057e601b32e00721c0052dd01b21400532e00521400524101b", + "0x521400532e00521400524101b01b32e00500500532901b01b32e00501b", + "0x32e00501b31c01b01b32e0052220052da01b01b32e00501b00701b214005", + "0x1b04c00532e00522821400724201b22800532e00522800520701b228005", + "0x22905400735801b05400500732e0050050052d201b22900532e00501b7e7", + "0x4c00532e00504c00524101b05100532e00505100502a01b05100532e005", + "0x500532901b01b32e00501b00701b0520057e801b32e0070510052dd01b", + "0x1b32e00501b00701b04c00500504c00532e00504c00524101b01b32e005", + "0x32e00505500520701b05500532e00501b31c01b01b32e0050520052da01b", + "0x2d201b23200532e00501b7e901b23100532e00505504c00724201b055005", + "0x5700502a01b05700532e00523223400735801b23400500732e005005005", + "0x7ea01b32e0070570052dd01b23100532e00523100524101b05700532e005", + "0x523100524101b01b32e00500500532901b01b32e00501b00701b059005", + "0x1b01b32e0050590052da01b01b32e00501b00701b23100500523100532e", + "0x505823100724201b05800532e00505800520701b05800532e00501b31c", + "0x1b24900500732e0050050052d201b23a00532e00501b7eb01b05600532e", + "0x5600524101b03300532e00503300502a01b03300532e00523a249007358", + "0x1b32e00501b00701b05f0057ec01b32e0070330052dd01b05600532e005", + "0x701b05600500505600532e00505600524101b01b32e00500500532901b", + "0x20701b25400532e00501b31c01b01b32e00505f0052da01b01b32e00501b", + "0x32e00501b7ed01b06200532e00525405600724201b25400532e005254005", + "0x600532e00506126c00735801b26c00500732e0050050052d201b061005", + "0x60052dd01b06200532e00506200524101b00600532e00500600502a01b", + "0x1b01b32e00500500532901b01b32e00501b00701b0690057ee01b32e007", + "0x690052da01b01b32e00501b00701b06200500506200532e005062005241", + "0x24201b06b00532e00506b00520701b06b00532e00501b31c01b01b32e005", + "0x32e0050050052d201b06e00532e00501b2b801b2d300532e00506b062007", + "0x7100532e00507100502a01b07100532e00506e06f00735801b06f005007", + "0x701b2ee0057ef01b32e0070710052dd01b2d300532e0052d300524101b", + "0x52d300532e0052d300524101b01b32e00500500532901b01b32e00501b", + "0x32e00501b31c01b01b32e0052ee0052da01b01b32e00501b00701b2d3005", + "0x1b07600532e0050342d300724201b03400532e00503400520701b034005", + "0x31107300735801b07300500732e0050050052d201b31100532e00501b7f0", + "0x7600532e00507600524101b07200532e00507200502a01b07200532e005", + "0x500532901b01b32e00501b00701b07a0057f101b32e0070720052dd01b", + "0x1b32e00501b00701b07600500507600532e00507600524101b01b32e005", + "0x32e00507400520701b07400532e00501b31c01b01b32e00507a0052da01b", + "0x2d201b30e00532e00501b7f201b30f00532e00507407600724201b074005", + "0x30c00502a01b30c00532e00530e30d00735801b30d00500732e005005005", + "0x7f301b32e00730c0052dd01b30f00532e00530f00524101b30c00532e005", + "0x530f00524101b01b32e00500500532901b01b32e00501b00701b30b005", + "0x1b01b32e00530b0052da01b01b32e00501b00701b30f00500530f00532e", + "0x530a30f00724201b30a00532e00530a00520701b30a00532e00501b31c", + "0x1b08600532e00530500500735801b30500532e00501b23101b30900532e", + "0x70860052dd01b30900532e00530900524101b08600532e00508600502a", + "0x530900532e00530900524101b01b32e00501b00701b3040057f401b32e", + "0x32e00501b31c01b01b32e0053040052da01b01b32e00501b00701b309005", + "0x1b08400532e00530330900724201b30300532e00530300520701b303005", + "0x4404504604832e00504700570301b08400500508400532e005084005241", + "0x4204832e0070440430070050477f501b04304600732e00504600520a01b", + "0x532e00504000521501b01b32e00501b00701b03e03f1940487f6040041", + "0x521a01b04100532e00504100531e01b04200532e00504200531f01b040", + "0x532e00501b7f801b01b32e00501b00701b07b0057f702300532e007040", + "0x19100516b01b02000532e00502000516b01b19100532e00501b7f901b020", + "0x3300487fa32900932b04832e0071910200410420471ab01b19100532e005", + "0x32b00531f01b32900532e00532900521501b01b32e00501b00701b02a02d", + "0x3100532e00732900521a01b00900532e00500900531e01b32b00532e005", + "0xc900573e01b0c900532e00501b7fc01b01b32e00501b00701b3260057fb", + "0x732004601b04874001b32000532e00532000573f01b3200c900732e005", + "0x1b00701b21421120d0487fd2072031fb31c03603803903731e31f04132e", + "0x532e00520321600774201b21600532e00520731f00774201b01b32e005", + "0x1b22200532e00531c21c00774201b21c00532e0051fb21800774201b218", + "0x774201b04c00532e00503822800774201b22800532e005036222007742", + "0x531e00574301b05400532e00503722900774201b22900532e00503904c", + "0x1b04800532e00504800516b01b05400532e00505400504601b05100532e", + "0xc900573e01b05200532e00505200516b01b05205100732e00505100520a", + "0x5505204805404774401b05500532e00505500573f01b0550c900732e005", + "0x5700732e00523400518201b23400532e00501b70701b23223100732e005", + "0x70901b05900532e00505900518301b05605800732e00523200518201b059", + "0x1b01b32e00501b00701b05f0330077fe24923a00732e007056059231048", + "0x32e00523a00504601b06200532e0052540052d901b25400532e00501b03f", + "0x19401b00600532e0050620052db01b26c00532e00524900518301b061005", + "0x50ad01b06900532e00501b03f01b01b32e00501b00701b01b7ff00501b", + "0x532e00505f00518301b06100532e00503300504601b06b00532e005069", + "0x4870901b05700532e00505700518301b00600532e00506b0052db01b26c", + "0x4601b01b32e00501b00701b07106f00780006e2d300732e007058057061", + "0x32e00526c00518301b03400532e00506e00518301b2ee00532e0052d3005", + "0x501b00701b01b80100501b19401b31100532e0050060052db01b076005", + "0x4870901b07300532e00507300518301b07300532e00501b16601b01b32e", + "0x4601b01b32e00501b00701b30f07400780207a07200732e00707326c06f", + "0x32e00507a00518301b03400532e00507100518301b2ee00532e005072005", + "0x501b00701b01b80100501b19401b31100532e0050060052db01b076005", + "0x30e0050ad01b30e00532e00501b03f01b01b32e0050060052d801b01b32e", + "0x3400532e00507100518301b2ee00532e00507400504601b30d00532e005", + "0x31100514201b31100532e00530d0052db01b07600532e00530f00518301b", + "0x1b32e00530c00505401b01b32e00501b00701b30b00580330c00532e007", + "0x5100516b01b04500532e00504500516b01b2ee00532e0052ee00504601b", + "0x50c90510452ee04774401b0c900532e0050c900573f01b05100532e005", + "0x532e00530500516b01b30500532e00507603400716901b30930a00732e", + "0x1b30130208404880530330408604832e00730503100932b04780401b305", + "0x532e00530300571e01b08600532e00508600531f01b01b32e00501b007", + "0x1b33808707d0488062ff30008204832e00730902330408604780401b303", + "0x532e0052ff00571e01b08200532e00508200531f01b01b32e00501b007", + "0x1b2f72f82f90488082fa2fb2fc04832e0072ff30330008204780701b2ff", + "0x532e0052f600580a01b2f600532e0052fa00580901b01b32e00501b007", + "0x531f01b30a00532e00530a00504601b2f400532e0052f500580b01b2f5", + "0x532e0052f400580c01b2fb00532e0052fb00531e01b2fc00532e0052fc", + "0x2f300532e00501b32601b01b32e00501b00701b2f42fb2fc30a0470052f4", + "0x504601b2f100532e0052f200580d01b2f200532e0052f72f30070c901b", + "0x532e0052f800531e01b2f900532e0052f900531f01b30a00532e00530a", + "0x32e00501b00701b2f12f82f930a0470052f100532e0052f100580c01b2f8", + "0x3382ef0070c901b2ef00532e00501b32601b01b32e0053030051af01b01b", + "0x30a00532e00530a00504601b08b00532e00507c00580d01b07c00532e005", + "0x8b00580c01b08700532e00508700531e01b07d00532e00507d00531f01b", + "0x230051af01b01b32e00501b00701b08b08707d30a04700508b00532e005", + "0x70c901b08d00532e00501b32601b01b32e00530900525b01b01b32e005", + "0x32e00530a00504601b09000532e0052ed00580d01b2ed00532e00530108d", + "0x80c01b30200532e00530200531e01b08400532e00508400531f01b30a005", + "0x5401b01b32e00501b00701b09030208430a04700509000532e005090005", + "0x1b01b32e0050230051af01b01b32e00503400511501b01b32e00530b005", + "0x1b32e0050c900575601b01b32e0050310051af01b01b32e005076005115", + "0x532e00501b33001b01b32e00504500525b01b01b32e00505100525b01b", + "0x2ec00703101b08e00532e00508e00502a01b08e00532e00501b80e01b2ec", + "0x532e0052eb2ea0070c901b2ea00532e00501b32601b2eb00532e00508e", + "0x531f01b2ee00532e0052ee00504601b2e700532e0052e800580d01b2e8", + "0x532e0052e700580c01b00900532e00500900531e01b32b00532e00532b", + "0x1b32e00504800525b01b01b32e00501b00701b2e700932b2ee0470052e7", + "0x32e0050310051af01b01b32e00504500525b01b01b32e0050230051af01b", + "0x774201b09900532e00521420d00774201b01b32e0050c900575601b01b", + "0x2e400532e00501b05701b2e600532e00501b33001b08500532e005211099", + "0x1b32601b2e300532e0052e42e600703101b2e400532e0052e400502a01b", + "0x532e0052e200580d01b2e200532e0052e309d0070c901b09d00532e005", + "0x531e01b32b00532e00532b00531f01b08500532e00508500504601b0a4", + "0x1b0a400932b0850470050a400532e0050a400580c01b00900532e005009", + "0x1b01b32e00504800525b01b01b32e00532600505401b01b32e00501b007", + "0x1b32e00504600525b01b01b32e00504500525b01b01b32e0050230051af", + "0x32e0052e100502a01b2e100532e00501b05701b0a000532e00501b33001b", + "0x1b0a800532e00532b00531f01b2df00532e0052e10a000703101b2e1005", + "0x80f00501b19401b2dd00532e0052df00522801b0aa00532e00500900531e", + "0x32e0050230051af01b01b32e00504800525b01b01b32e00501b00701b01b", + "0x533000531f01b01b32e00504600525b01b01b32e00504500525b01b01b", + "0x1b2dd00532e00502a00522801b0aa00532e00502d00531e01b0a800532e", + "0x52db00580d01b2db00532e0052dd0ad0070c901b0ad00532e00501b326", + "0x1b0a800532e0050a800531f01b01b00532e00501b00504601b2da00532e", + "0xaa0a801b0470052da00532e0052da00580c01b0aa00532e0050aa00531e", + "0x32e00504500525b01b01b32e00504800525b01b01b32e00501b00701b2da", + "0x2d900580a01b2d900532e00507b00581001b01b32e00504600525b01b01b", + "0x1b00532e00501b00504601b2d700532e0052d800580b01b2d800532e005", + "0x2d700580c01b04100532e00504100531e01b04200532e00504200531f01b", + "0x4800525b01b01b32e00501b00701b2d704104201b0470052d700532e005", + "0x1b32601b01b32e00504500525b01b01b32e00504600525b01b01b32e005", + "0x532e0052d600580d01b2d600532e00503e0b20070c901b0b200532e005", + "0x531e01b19400532e00519400531f01b01b00532e00501b00504601b2d5", + "0x1b2d503f19401b0470052d500532e0052d500580c01b03f00532e00503f", + "0x1b01b32e00501b05801b04300532e00501b03401b04500532e00501b811", + "0x4881204004104404204732e00704704800504820901b01b32e00501b020", + "0x81401b02300532e00504004100781301b01b32e00501b00701b03e03f194", + "0x32e00502000581601b01b32e00507b00581501b02007b00732e005023005", + "0x13a01b32b00532e00519100581801b19100532e00502000581701b020005", + "0x532e00501b00504601b32900532e00532b00525a01b00900532e00501b", + "0x525901b00700532e0050070052d401b04200532e00504200531f01b01b", + "0x32e00504404300730f01b00900532e00500900525801b32900532e005329", + "0x781a01b02a04602d33004732e00500932900704201b04681901b044005", + "0x1b00701b32600581b03100532e00702a00525601b04600532e005046045", + "0x1b32e0050c900517301b31f3200c904832e00503100517101b01b32e005", + "0x532e00501b31c01b31e00532e00501b2f901b01b32e00531f00505401b", + "0x525801b02d00532e00502d00531f01b33000532e00533000504601b037", + "0x532e00503700520701b31e00532e00531e0052f701b32000532e005320", + "0x703600517601b03603803904832e00503731e32002d33004617401b037", + "0x20300732e00531c00525501b01b32e00501b00701b1fb00581c31c00532e", + "0x517901b21120d00732e00520300517801b01b32e00520700505401b207", + "0x32e00721404403804825301b21400532e00521100517b01b01b32e00520d", + "0x521c00518201b01b32e00501b00701b04c22822204881d21c218216048", + "0x732e00505404600781e01b05400532e00505400518301b05422900732e", + "0x23105500732e00522905100781e01b22900532e00522900518301b052051", + "0x523200520201b23100532e00523100518301b23200532e00501b20001b", + "0x505700511501b05905723404832e0052322310390481ba01b23200532e", + "0x20101b05600532e0050520050c401b05800532e0050590050c401b01b32e", + "0x32e00524900502a01b24900532e00523a0580071fe01b23a00532e00501b", + "0x1b03300532e0050562490072ab01b05600532e00505600502a01b249005", + "0x525400582001b25400532e00505f00581f01b05f00532e0050330051f9", + "0x1b21600532e00521600531f01b23400532e00523400504601b06200532e", + "0x506200582101b21800532e00521800531e01b05500532e0050550052d4", + "0x3900504601b01b32e00501b00701b06221805521623404600506200532e", + "0x600532e00522800531e01b26c00532e00522200531f01b06100532e005", + "0x1b32e00501b00701b01b82200501b19401b06900532e00504c00522801b", + "0x3900504601b01b32e00506b00530301b2d306b00732e0051fb00530401b", + "0x600532e00504400531e01b26c00532e00503800531f01b06100532e005", + "0x1b32e00501b00701b01b82200501b19401b06900532e0052d300522801b", + "0x33000504601b01b32e00506e00530301b06f06e00732e00532600530401b", + "0x600532e00504400531e01b26c00532e00502d00531f01b06100532e005", + "0x690710070c901b07100532e00501b32601b06900532e00506f00522801b", + "0x6100532e00506100504601b03400532e0052ee00582301b2ee00532e005", + "0x600531e01b04600532e0050460052d401b26c00532e00526c00531f01b", + "0x1b03400604626c06104600503400532e00503400582101b00600532e005", + "0x1b01b32e00504300507201b01b32e00504500582401b01b32e00501b007", + "0x531100582301b31100532e00503e0760070c901b07600532e00501b326", + "0x1b19400532e00519400531f01b01b00532e00501b00504601b07300532e", + "0x507300582101b03f00532e00503f00531e01b00700532e0050070052d4", + "0x1b04604700732e00500500518201b07303f00719401b04600507300532e", + "0x570801b04304700732e00504700570801b04404500732e005007005182", + "0x774201b19404004104832e00504204300782501b04204500732e005045", + "0x3e04700782501b03e04400732e00504400570801b03f00532e00519401b", + "0x4119104882601b19100532e00502003f00774201b02007b02304832e005", + "0x501b16801b01b32e00501b00701b33032900782700932b00732e00707b", + "0x1b03100532e00500900518301b02a00532e00532b00504601b02d00532e", + "0x1b01b32e00501b00701b01b82800501b19401b32600532e00502d005183", + "0x32e00533000518301b02a00532e00532900504601b0c900532e00501b166", + "0x1b32004600732e00504600570801b32600532e0050c900518301b031005", + "0x1b03900532e00503702a00774201b03731e31f04832e005045320007825", + "0x1b32e00501b00701b1fb31c00782903603800732e00731e031039048826", + "0x503600518301b20700532e00503800504601b20300532e00501b16801b", + "0x1b00701b01b82a00501b19401b21100532e00520300518301b20d00532e", + "0x18301b20700532e00531c00504601b21400532e00501b16601b01b32e005", + "0x31f02320704882601b21100532e00521400518301b20d00532e0051fb005", + "0x32e00501b16801b01b32e00501b00701b22221c00782b21821600732e007", + "0x18301b22900532e00521800518301b04c00532e00521600504601b228005", + "0x16601b01b32e00501b00701b01b82c00501b19401b05400532e005228005", + "0x532e00522200518301b04c00532e00521c00504601b05100532e00501b", + "0x23105505204832e00504404600782501b05400532e00505100518301b229", + "0x5723400732e00705405223204882601b23200532e00523104c00774201b", + "0x18301b05600532e00523400504601b01b32e00501b00701b05805900782d", + "0x4601b01b32e00501b00701b01b82e00501b19401b23a00532e005057005", + "0x5522905604882601b23a00532e00505800518301b05600532e005059005", + "0x32e00501b16801b01b32e00501b00701b25405f00782f03324900732e007", + "0x18301b26c00532e00503300518301b06100532e00524900504601b062005", + "0x16601b01b32e00501b00701b01b83000501b19401b00600532e005062005", + "0x532e00525400518301b06100532e00505f00504601b06900532e00501b", + "0x2d306b00732e00700623a06104882601b00600532e00506900518301b26c", + "0x18301b07100532e00506b00504601b01b32e00501b00701b06f06e007831", + "0x4601b01b32e00501b00701b01b83200501b19401b2ee00532e0052d3005", + "0x21132607104882601b2ee00532e00506f00518301b07100532e00506e005", + "0x503400504601b01b32e00501b00701b07331100783307603400732e007", + "0x1b00701b01b83400501b19401b07a00532e00507600518301b07200532e", + "0x1b07a00532e00507300518301b07200532e00531100504601b01b32e005", + "0x1b32e00501b00701b30d30e00783530f07400732e00707a26c072048826", + "0x530f00518301b30b00532e00507400504601b30c00532e00501b16801b", + "0x1b00701b01b83600501b19401b30900532e00530c00518301b30a00532e", + "0x18301b30b00532e00530e00504601b30500532e00501b16601b01b32e005", + "0x3092ee30b04882601b30900532e00530500518301b30a00532e00530d005", + "0x508600504601b01b32e00501b00701b08430300783730408600732e007", + "0x1b00701b01b83800501b19401b30100532e00530400518301b30200532e", + "0x1b30100532e00508400518301b30200532e00530300504601b01b32e005", + "0x83b01b08200532e00508200583a01b08200532e00530130a20d040047839", + "0x52ff00583c01b2fa2fb2fc33808707d2ff30004332e005048082302048", + "0x2f800532e0052fb2f900774201b2f900532e0052fa30000774201b01b32e", + "0x74201b2f600532e0053382f700774201b2f700532e0052fc2f800774201b", + "0x507d00516b01b2f500532e0052f500504601b2f500532e0050872f6007", + "0x4700583e04800700732e00700501b00783d01b07d2f500700507d00532e", + "0x32e00504600584001b04600532e00504800583f01b01b32e00501b00701b", + "0x584204500532e07b04600584101b00700532e00500700504601b046005", + "0x84903f005848194005847040005846041005845042005844043005843044", + "0x900584f32b00584e19100584d02000584c07b00584b02300584a03e005", + "0x501b16601b01b32e00504500505401b01b32e00501b00701b329005850", + "0x1b00701b01b85100501b19401b02d00532e00533000518301b33000532e", + "0x518301b02a00532e00501b85201b01b32e00504400505401b01b32e005", + "0x505401b01b32e00501b00701b01b85100501b19401b02d00532e00502a", + "0x1b02d00532e00503100518301b03100532e00501b85301b01b32e005043", + "0x36101b01b32e00504200505401b01b32e00501b00701b01b85100501b194", + "0x1b01b85100501b19401b02d00532e00532600518301b32600532e00501b", + "0x1b0c900532e00501b85401b01b32e00504100505401b01b32e00501b007", + "0x1b01b32e00501b00701b01b85100501b19401b02d00532e0050c9005183", + "0x532e00532000518301b32000532e00501b85501b01b32e005040005054", + "0x1b32e00519400505401b01b32e00501b00701b01b85100501b19401b02d", + "0x85100501b19401b02d00532e00531f00518301b31f00532e00501b85601b", + "0x532e00501b85701b01b32e00503f00505401b01b32e00501b00701b01b", + "0x32e00501b00701b01b85100501b19401b02d00532e00531e00518301b31e", + "0x503700518301b03700532e00501b85801b01b32e00503e00505401b01b", + "0x502300505401b01b32e00501b00701b01b85100501b19401b02d00532e", + "0x1b19401b02d00532e00503900518301b03900532e00501b85901b01b32e", + "0x501b36001b01b32e00507b00505401b01b32e00501b00701b01b851005", + "0x1b00701b01b85100501b19401b02d00532e00503800518301b03800532e", + "0x518301b03600532e00501b85a01b01b32e00502000505401b01b32e005", + "0x505401b01b32e00501b00701b01b85100501b19401b02d00532e005036", + "0x1b02d00532e00531c00518301b31c00532e00501b85b01b01b32e005191", + "0x85c01b01b32e00532b00505401b01b32e00501b00701b01b85100501b194", + "0x1b01b85100501b19401b02d00532e0051fb00518301b1fb00532e00501b", + "0x1b20300532e00501b85d01b01b32e00500900505401b01b32e00501b007", + "0x1b01b32e00501b00701b01b85100501b19401b02d00532e005203005183", + "0x532e00520700518301b20700532e00501b85e01b01b32e005329005054", + "0x504601b21100532e00520d00586001b20d00532e00502d00585f01b02d", + "0x1b00701b21100700700521100532e00521100535e01b00700532e005007", + "0x502a01b21600532e00501b86101b21400532e00501b33001b01b32e005", + "0x532e00501b32601b21800532e00521621400703101b21600532e005216", + "0x4601b22800532e00522200586201b22200532e00521821c0070c901b21c", + "0x2001b22804700700522800532e00522800535e01b04700532e005047005", + "0x701b04304400786304504600732e00700501b00700501b01b32e00501b", + "0x4601b01b32e00501b04701b04200532e00504800569201b01b32e00501b", + "0x701b19400586404004100732e00704200569301b04600532e005046005", + "0x3e00532e00504100569601b03f00532e00504000569501b01b32e00501b", + "0x1b32e00501b00701b01b86500501b19401b02300532e00503f00569701b", + "0x519400569601b02000532e00507b00569901b07b00532e00501b03f01b", + "0x1b19100532e00503e00525a01b02300532e00502000569701b03e00532e", + "0x32b00569c01b01b32e00501b00701b00900586632b00532e00702300569a", + "0x4600532e00504600504601b33000532e00532900569d01b32900532e005", + "0x33000516b01b04700532e00504700525801b00700532e0050070052d401b", + "0x517601b03102a02d04832e00533004700704604786701b33000532e005", + "0x1b32e00501b02001b01b32e00501b00701b0c900586832600532e007031", + "0x2d00504601b01b32e00531f00505401b31f32000732e00532600525501b", + "0x2a00532e00502a0052d401b04500532e00504500531f01b02d00532e005", + "0x2d04681901b32000532e00532000525801b19100532e00519100525901b", + "0x1b00701b03803903731e04700503803903731e04732e00532019102a045", + "0xc900569f01b01b32e00519100517301b01b32e00501b02001b01b32e005", + "0x4500532e00504500531f01b02d00532e00502d00504601b03600532e005", + "0x4502d04700503600532e0050360056a001b02a00532e00502a0052d401b", + "0x32e00500900505401b01b32e00501b02001b01b32e00501b00701b03602a", + "0x6a201b1fb00532e00531c0471910486a101b31c00532e00501b03f01b01b", + "0x32e00504500531f01b04600532e00504600504601b20300532e0051fb005", + "0x4700520300532e0052030056a001b00700532e0050070052d401b045005", + "0x517301b01b32e00504700517901b01b32e00501b00701b203007045046", + "0x2a01b20d00532e00501b22901b20700532e00501b33001b01b32e005048", + "0x32e00501b32601b21100532e00520d20700703101b20d00532e00520d005", + "0x1b21800532e00521600569f01b21600532e0052112140070c901b214005", + "0x50070052d401b04300532e00504300531f01b04400532e005044005046", + "0x518201b21800704304404700521800532e0052180056a001b00700532e", + "0x501b7cf01b04404500732e00504600500781e01b04604700732e005048", + "0x1b04300532e00504300520201b04400532e00504400518301b04300532e", + "0x1b04500532e0050450052d401b04004104204832e00504304401b0481ba", + "0x7d001b01b32e00501b00701b03e00586903f19400732e0070410420077d0", + "0x717c01b01b32e00501b00701b02000586a07b02300732e007040194007", + "0x4704500781e01b32b00532e00503f19100717c01b19100532e00507b007", + "0x32900532e00532900518301b33000532e00501b7cf01b32900900732e005", + "0x3102a02d04832e0053303290230481ba01b33000532e00533000520201b", + "0x2d0077d001b00900532e0050090052d401b32b00532e00532b00525801b", + "0x313260077d001b01b32e00501b00701b32000586b0c932600732e00702a", + "0x531e32b00717c01b01b32e00501b00701b03700586c31e31f00732e007", + "0x1b03600532e00501b03f01b03800532e0050c903900717c01b03900532e", + "0x31f00504601b1fb00532e00531c0056cc01b31c00532e0050360380076cb", + "0x1fb00532e0051fb0056b401b00900532e0050090052d401b31f00532e005", + "0x2fa01b01b32e00532b00517901b01b32e00501b00701b1fb00931f048005", + "0x1b20700532e00501b05701b20300532e00501b33001b01b32e0050c9005", + "0x3700504601b20d00532e00520720300703101b20700532e00520700502a", + "0x701b01b86d00501b19401b21400532e00520d00522801b21100532e005", + "0x33001b01b32e00503100511501b01b32e00532b00517901b01b32e00501b", + "0x21800532e00521800502a01b21800532e00501b05701b21600532e00501b", + "0x522801b21100532e00532000504601b21c00532e00521821600703101b", + "0x532e0052142220070c901b22200532e00501b32601b21400532e00521c", + "0x52d401b21100532e00521100504601b04c00532e0052280056b301b228", + "0x701b04c00921104800504c00532e00504c0056b401b00900532e005009", + "0x2fa01b01b32e00504700511501b01b32e00500700517901b01b32e00501b", + "0x1b05400532e00501b05701b22900532e00501b33001b01b32e00503f005", + "0x2000504601b05100532e00505422900703101b05400532e00505400502a", + "0x701b01b86e00501b19401b05500532e00505100522801b05200532e005", + "0x11501b01b32e00504700511501b01b32e00500700517901b01b32e00501b", + "0x1b23200532e00501b05701b23100532e00501b33001b01b32e005040005", + "0x3e00504601b23400532e00523223100703101b23200532e00523200502a", + "0x1b05700532e00501b32601b05500532e00523400522801b05200532e005", + "0x5200504601b05800532e0050590056b301b05900532e0050550570070c9", + "0x5800532e0050580056b401b04500532e0050450052d401b05200532e005", + "0x4800700501b1e41ba1e501b0471791ba1e501b04730e058045052048005", + "0x1ba1e501b0472bc04800700501b1e41ba1e501b0471791ba1e501b04701b", + "0x1ba1e501b0471791ba1e501b04714a04800700501b1e41ba1e501b047179", + "0x4800700501b1e41ba1e501b0471791ba1e501b04758204800700501b1e4", + "0x1ba1e501b04787004800700501b1e41ba1e501b0471791ba1e501b04786f", + "0x1ba1e501b0471791ba1e501b04787104800700501b1e41ba1e501b047179", + "0x4800700501b1e41ba1e501b0471791ba1e501b04787204800700501b1e4", + "0x1ba1e501b04787404800700501b1e41ba1e501b0471791ba1e501b047873", + "0x1ba1e501b0471791ba1e501b04787504800700501b1e41ba1e501b047179", + "0x501b1e41ba1e521f01b0461791ba1e521f01b04687604800700501b1e4", + "0x4787804800700501b1e41ba1e501b0471791ba1e501b047877047048007", + "0x471791ba1e501b04787904800700501b1e41ba1e501b0471791ba1e501b", + "0x1ba1e503101b0461791ba1e503101b04687a04800700501b1e41ba1e501b", + "0x700501b1e41ba1e501b0471791ba1e501b04787b04704800700501b1e4", + "0x1e501b04787d04800700501b1e41ba1e501b0471791ba1e501b04787c048", + "0x1e501b0471791ba1e501b04787e04800700501b1e41ba1e501b0471791ba", + "0x700501b1e41ba1e501b0471791ba1e501b04787f04800700501b1e41ba", + "0x1e501b04788104800700501b1e41ba1e501b0471791ba1e501b047880048", + "0x2300461791ba1e501b23004688204800700501b1e41ba1e501b0471791ba", + "0x1b2300451791ba1e503101b23004588304704800700501b1e41ba1e501b", + "0x1ba1e501b0471791ba1e501b04788404604704800700501b1e41ba1e5031", + "0x501b1e41ba1e523701b0461791ba1e523701b04688504800700501b1e4", + "0x4800700501b1e41ba1e501b2300461791ba1e501b230046886047048007", + "0xd401b04488804800700501b1e41ba1e501b0471791ba1e501b047887047", + "0x4504604704800700501b1e41ba1e50d20d60d401b0441791ba1e50d20d6", + "0x4788a04704800700501b1e41ba1e50d401b0461791ba1e50d401b046889", + "0x471791ba1e501b04788b04800700501b1e41ba1e501b0471791ba1e501b", + "0x1b1e41ba1e501b0471791ba1e501b04788c04800700501b1e41ba1e501b", + "0x4688e04800700501b1e41ba1e501b0471791ba1e501b04788d048007005", + "0x1790521e501b04788f04704800700501b1fc1e501b0480060521791e501b", + "0x501b2041e501b0480521791e501b04789004800700501b2041e501b048", + "0x89204704800700501b20e1ba1e501b04720c19d1ba1e501b046891048007", + "0x4504604704800700501b2121ba1e501b0471780871780871ba1e501b044", + "0x1b2171e501b0481791e501b04889400501b21517901b04817901b007893", + "0x501b2191ba1e501b04700600600617c17d19d1ba1e501b042895007005", + "0x1ba1e504800600600600620c19d1ba1e5043896043044045046047048007", + "0x2231e521f01b0472211e521f01b04789704404504604704800700501b1e4", + "0x89904800700501b20e1ba1e501b04719d1ba1e501b04789804800700501b", + "0x1ba0311e501b04689a04800700501b20e1ba1e501b04719d1ba1e501b047", + "0x1b04719d1ba1e501b04789b04704800700501b20e1ba0311e501b04619d", + "0x1b22d1ba1e501b04705219d1ba1e501b04689c04800700501b20e1ba1e5", + "0x4789e04800700501b20e1e501b04800619d1e501b04789d047048007005", + "0x619d1ba2301e501b04389f04800700501b20e1e501b04800619d1e501b", + "0x17901b0078a004404504604704800700501b20e1ba2301e501b046006006", + "0x2300311e501b04519919d1ba2300311e501b0448a100501b23317901b048", + "0x1e523701b04619d1ba1e523701b0468a204504604704800700501b20e1ba", + "0x1ba2301e501b04600619d1ba2301e501b0458a304704800700501b20e1ba", + "0xd40d20d601b04519d1e50d40d20d601b0458a404604704800700501b20e", + "0x1ba1e501b0448a601b2190d40070d40058a504604704800700501b20e1e5", + "0x17901b0078a704504604704800700501b20e1ba1e501b04705200618319d", + "0x4800700501b24b1e501b0480061711791e501b0468a800501b24a01b007", + "0x1741e501b0478aa04800700501b2531e501b0481791791e501b0478a9047", + "0x1b25f1e501b0481611691e501b0478ab04800700501b2551e501b048174", + "0x8ad04704800700501b2601e501b04807a0871611e501b0468ac048007005", + "0x471421411ba1e501b0468ae04800700501b26d01b00707a07a13d01b047", + "0x1b04606928602d1ba0311e501b0448af04704800700501b2711ba1e501b", + "0x11302d02d02d1ba1e501b0448b004504604704800700501b2871ba0311e5", + "0x501b0eb0052d22d20078b104504604704800700501b2941ba1e501b047", + "0x480522dd1e501b0478b304800700501b2d601b00707a0060ad01b0478b2", + "0x1b0488b500501b2eb17901b04817901b0078b404800700501b2041e501b", + "0x501b2601e501b04807a1611e501b0478b600700501b26001b00702d161", + "0x1e501b04728602d1ba1e501b0468b800501b13d00500613d0078b7048007", + "0x2d31ba0311e501b04606e1ba0311e501b0468b904704800700501b2ee1ba", + "0x78bb04800700501b02d01b00703302d02d01b0478ba04704800700501b", + "0x1b25f0311e501b0471611690311e501b0468bc00501b23101b00707a01b", + "0x8be04800700501b26003101b04802d16103101b0478bd047048007005" + ], + "sierra_program_debug_info": { + "type_names": [], + "libfunc_names": [], + "user_func_names": [] + }, + "contract_class_version": "0.1.0", + "entry_points_by_type": { + "EXTERNAL": [ + { + "selector": "0x1143aa89c8e3ebf8ed14df2a3606c1cd2dd513fac8040b0f8ab441f5c52fe4", + "function_idx": 22 + }, + { + "selector": "0x3541591104188daef4379e06e92ecce09094a3b381da2e654eb041d00566d8", + "function_idx": 31 + }, + { + "selector": "0x3c118a68e16e12e97ed25cb4901c12f4d3162818669cc44c391d8049924c14", + "function_idx": 7 + }, + { + "selector": "0x5562b3e932b4d139366854d5a2e578382e6a3b6572ac9943d55e7efbe43d00", + "function_idx": 18 + }, + { + "selector": "0x600c98a299d72ef1e09a2e1503206fbc76081233172c65f7e2438ef0069d8d", + "function_idx": 23 + }, + { + "selector": "0x62c83572d28cb834a3de3c1e94977a4191469a4a8c26d1d7bc55305e640ed5", + "function_idx": 19 + }, + { + "selector": "0x679c22735055a10db4f275395763a3752a1e3a3043c192299ab6b574fba8d6", + "function_idx": 27 + }, + { + "selector": "0x7772be8b80a8a33dc6c1f9a6ab820c02e537c73e859de67f288c70f92571bb", + "function_idx": 25 + }, + { + "selector": "0xd47144c49bce05b6de6bce9d5ff0cc8da9420f8945453e20ef779cbea13ad4", + "function_idx": 1 + }, + { + "selector": "0xe7510edcf6e9f1b70f7bd1f488767b50f0363422f3c563160ab77adf62467b", + "function_idx": 10 + }, + { + "selector": "0xf818e4530ec36b83dfe702489b4df537308c3b798b0cc120e32c2056d68b7d", + "function_idx": 14 + }, + { + "selector": "0x10d2fede95e3ec06a875a67219425c27c5bd734d57f1b221d729a2337b6b556", + "function_idx": 12 + }, + { + "selector": "0x12ead94ae9d3f9d2bdb6b847cf255f1f398193a1f88884a0ae8e18f24a037b6", + "function_idx": 29 + }, + { + "selector": "0x14dae1999ae9ab799bc72def6dc6e90890cf8ac0d64525021b7e71d05cb13e8", + "function_idx": 5 + }, + { + "selector": "0x169f135eddda5ab51886052d777a57f2ea9c162d713691b5e04a6d4ed71d47f", + "function_idx": 13 + }, + { + "selector": "0x1ae1a515cf2d214b29bdf63a79ee2d490efd4dd1acc99d383a8e549c3cecb5d", + "function_idx": 28 + }, + { + "selector": "0x1e4089d1f1349077b1970f9937c904e27c4582b49a60b6078946dba95bc3c08", + "function_idx": 4 + }, + { + "selector": "0x23039bef544cff56442d9f61ae9b13cf9e36fcce009102c5b678aac93f37b36", + "function_idx": 6 + }, + { + "selector": "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", + "function_idx": 2 + }, + { + "selector": "0x298e03955860424b6a946506da72353a645f653dc1879f6b55fd756f3d20a59", + "function_idx": 3 + }, + { + "selector": "0x2d7cf5d5a324a320f9f37804b1615a533fde487400b41af80f13f7ac5581325", + "function_idx": 11 + }, + { + "selector": "0x30f842021fbf02caf80d09a113997c1e00a32870eee0c6136bed27acb348bea", + "function_idx": 26 + }, + { + "selector": "0x31401f504973a5e8e1bb41e9c592519e3aa0b8cf6bbfb9c91b532aab8db54b0", + "function_idx": 32 + }, + { + "selector": "0x317eb442b72a9fae758d4fb26830ed0d9f31c8e7da4dbff4e8c59ea6a158e7f", + "function_idx": 24 + }, + { + "selector": "0x32564d7e0fe091d49b4c20f4632191e4ed6986bf993849879abfef9465def25", + "function_idx": 20 + }, + { + "selector": "0x3604cea1cdb094a73a31144f14a3e5861613c008e1e879939ebc4827d10cd50", + "function_idx": 8 + }, + { + "selector": "0x382be990ca34815134e64a9ac28f41a907c62e5ad10547f97174362ab94dc89", + "function_idx": 15 + }, + { + "selector": "0x38be5d5f7bf135b52888ba3e440a457d11107aca3f6542e574b016bf3f074d8", + "function_idx": 16 + }, + { + "selector": "0x3a6a8bae4c51d5959683ae246347ffdd96aa5b2bfa68cc8c3a6a7c2ed0be331", + "function_idx": 9 + }, + { + "selector": "0x3b097c62d3e4b85742aadd0dfb823f96134b886ec13bda57b68faf86f294d97", + "function_idx": 0 + }, + { + "selector": "0x3d3da80997f8be5d16e9ae7ee6a4b5f7191d60765a1a6c219ab74269c85cf97", + "function_idx": 30 + }, + { + "selector": "0x3d95049b565ec2d4197a55108ef03996381d31c84acf392a0a42b28163d69d1", + "function_idx": 17 + }, + { + "selector": "0x3eb640b15f75fcc06d43182cdb94ed38c8e71755d5fb57c16dd673b466db1d4", + "function_idx": 21 + } + ], + "L1_HANDLER": [ + { + "selector": "0x205500a208d0d49d79197fea83cc3f5fde99ac2e1909ae0a5d9f394c0c52ed0", + "function_idx": 34 + }, + { + "selector": "0x39edbbb129ad752107a94d40c3873cae369a46fd2fc578d075679aa67e85d12", + "function_idx": 33 + } + ], + "CONSTRUCTOR": [ + { + "selector": "0x28ffe4ff0f226a9107253e17a904099aa4f63a02a5621de0576e5aa71bc5194", + "function_idx": 35 + } + ] + }, + "abi": [ + { + "type": "constructor", + "name": "constructor", + "inputs": [ + { + "name": "arg1", + "type": "core::felt252" + }, + { + "name": "arg2", + "type": "core::felt252" + } + ] + }, + { + "type": "function", + "name": "test_storage_read_write", + "inputs": [ + { + "name": "address", + "type": "core::starknet::storage_access::StorageAddress" + }, + { + "name": "value", + "type": "core::felt252" + } + ], + "outputs": [ + { + "type": "core::felt252" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "test_count_actual_storage_changes", + "inputs": [], + "outputs": [], + "state_mutability": "view" + }, + { + "type": "struct", + "name": "core::array::Span::", + "members": [ + { + "name": "snapshot", + "type": "@core::array::Array::" + } + ] + }, + { + "type": "function", + "name": "test_call_contract", + "inputs": [ + { + "name": "contract_address", + "type": "core::starknet::contract_address::ContractAddress" + }, + { + "name": "entry_point_selector", + "type": "core::felt252" + }, + { + "name": "calldata", + "type": "core::array::Array::" + } + ], + "outputs": [ + { + "type": "core::array::Span::" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "test_call_two_contracts", + "inputs": [ + { + "name": "contract_address_0", + "type": "core::starknet::contract_address::ContractAddress" + }, + { + "name": "entry_point_selector_0", + "type": "core::felt252" + }, + { + "name": "calldata_0", + "type": "core::array::Array::" + }, + { + "name": "contract_address_1", + "type": "core::starknet::contract_address::ContractAddress" + }, + { + "name": "entry_point_selector_1", + "type": "core::felt252" + }, + { + "name": "calldata_1", + "type": "core::array::Array::" + } + ], + "outputs": [ + { + "type": "core::array::Span::" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "test_revert_helper", + "inputs": [ + { + "name": "class_hash", + "type": "core::starknet::class_hash::ClassHash" + } + ], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "test_emit_events", + "inputs": [ + { + "name": "events_number", + "type": "core::integer::u64" + }, + { + "name": "keys", + "type": "core::array::Array::" + }, + { + "name": "data", + "type": "core::array::Array::" + } + ], + "outputs": [], + "state_mutability": "view" + }, + { + "type": "function", + "name": "test_get_block_hash", + "inputs": [ + { + "name": "block_number", + "type": "core::integer::u64" + } + ], + "outputs": [ + { + "type": "core::felt252" + } + ], + "state_mutability": "view" + }, + { + "type": "struct", + "name": "core::starknet::info::BlockInfo", + "members": [ + { + "name": "block_number", + "type": "core::integer::u64" + }, + { + "name": "block_timestamp", + "type": "core::integer::u64" + }, + { + "name": "sequencer_address", + "type": "core::starknet::contract_address::ContractAddress" + } + ] + }, + { + "type": "struct", + "name": "core::starknet::info::v2::ResourceBounds", + "members": [ + { + "name": "resource", + "type": "core::felt252" + }, + { + "name": "max_amount", + "type": "core::integer::u64" + }, + { + "name": "max_price_per_unit", + "type": "core::integer::u128" + } + ] + }, + { + "type": "struct", + "name": "core::array::Span::", + "members": [ + { + "name": "snapshot", + "type": "@core::array::Array::" + } + ] + }, + { + "type": "struct", + "name": "core::starknet::info::v2::TxInfo", + "members": [ + { + "name": "version", + "type": "core::felt252" + }, + { + "name": "account_contract_address", + "type": "core::starknet::contract_address::ContractAddress" + }, + { + "name": "max_fee", + "type": "core::integer::u128" + }, + { + "name": "signature", + "type": "core::array::Span::" + }, + { + "name": "transaction_hash", + "type": "core::felt252" + }, + { + "name": "chain_id", + "type": "core::felt252" + }, + { + "name": "nonce", + "type": "core::felt252" + }, + { + "name": "resource_bounds", + "type": "core::array::Span::" + }, + { + "name": "tip", + "type": "core::integer::u128" + }, + { + "name": "paymaster_data", + "type": "core::array::Span::" + }, + { + "name": "nonce_data_availability_mode", + "type": "core::integer::u32" + }, + { + "name": "fee_data_availability_mode", + "type": "core::integer::u32" + }, + { + "name": "account_deployment_data", + "type": "core::array::Span::" + } + ] + }, + { + "type": "function", + "name": "test_get_execution_info", + "inputs": [ + { + "name": "expected_block_info", + "type": "core::starknet::info::BlockInfo" + }, + { + "name": "expected_tx_info", + "type": "core::starknet::info::v2::TxInfo" + }, + { + "name": "expected_caller_address", + "type": "core::felt252" + }, + { + "name": "expected_contract_address", + "type": "core::felt252" + }, + { + "name": "expected_entry_point_selector", + "type": "core::felt252" + } + ], + "outputs": [], + "state_mutability": "view" + }, + { + "type": "function", + "name": "test_library_call", + "inputs": [ + { + "name": "class_hash", + "type": "core::starknet::class_hash::ClassHash" + }, + { + "name": "function_selector", + "type": "core::felt252" + }, + { + "name": "calldata", + "type": "core::array::Array::" + } + ], + "outputs": [ + { + "type": "core::array::Span::" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "test_nested_library_call", + "inputs": [ + { + "name": "class_hash", + "type": "core::starknet::class_hash::ClassHash" + }, + { + "name": "lib_selector", + "type": "core::felt252" + }, + { + "name": "nested_selector", + "type": "core::felt252" + }, + { + "name": "a", + "type": "core::felt252" + }, + { + "name": "b", + "type": "core::felt252" + } + ], + "outputs": [ + { + "type": "core::array::Span::" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "test_replace_class", + "inputs": [ + { + "name": "class_hash", + "type": "core::starknet::class_hash::ClassHash" + } + ], + "outputs": [], + "state_mutability": "view" + }, + { + "type": "function", + "name": "test_send_message_to_l1", + "inputs": [ + { + "name": "to_address", + "type": "core::felt252" + }, + { + "name": "payload", + "type": "core::array::Array::" + } + ], + "outputs": [], + "state_mutability": "view" + }, + { + "type": "function", + "name": "segment_arena_builtin", + "inputs": [], + "outputs": [], + "state_mutability": "view" + }, + { + "type": "l1_handler", + "name": "l1_handle", + "inputs": [ + { + "name": "from_address", + "type": "core::felt252" + }, + { + "name": "arg", + "type": "core::felt252" + } + ], + "outputs": [ + { + "type": "core::felt252" + } + ], + "state_mutability": "view" + }, + { + "type": "l1_handler", + "name": "l1_handler_set_value", + "inputs": [ + { + "name": "from_address", + "type": "core::felt252" + }, + { + "name": "key", + "type": "core::starknet::storage_access::StorageAddress" + }, + { + "name": "value", + "type": "core::felt252" + } + ], + "outputs": [ + { + "type": "core::felt252" + } + ], + "state_mutability": "view" + }, + { + "type": "enum", + "name": "core::bool", + "variants": [ + { + "name": "False", + "type": "()" + }, + { + "name": "True", + "type": "()" + } + ] + }, + { + "type": "function", + "name": "test_deploy", + "inputs": [ + { + "name": "class_hash", + "type": "core::starknet::class_hash::ClassHash" + }, + { + "name": "contract_address_salt", + "type": "core::felt252" + }, + { + "name": "calldata", + "type": "core::array::Array::" + }, + { + "name": "deploy_from_zero", + "type": "core::bool" + } + ], + "outputs": [], + "state_mutability": "view" + }, + { + "type": "function", + "name": "test_keccak", + "inputs": [], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "test_sha256", + "inputs": [], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "test_secp256k1", + "inputs": [], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "test_secp256r1", + "inputs": [], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "assert_eq", + "inputs": [ + { + "name": "x", + "type": "core::felt252" + }, + { + "name": "y", + "type": "core::felt252" + } + ], + "outputs": [ + { + "type": "core::felt252" + } + ], + "state_mutability": "external" + }, + { + "type": "function", + "name": "invoke_call_chain", + "inputs": [ + { + "name": "call_chain", + "type": "core::array::Array::" + } + ], + "outputs": [ + { + "type": "core::felt252" + } + ], + "state_mutability": "external" + }, + { + "type": "function", + "name": "fail", + "inputs": [], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "recursive_fail", + "inputs": [ + { + "name": "depth", + "type": "core::felt252" + } + ], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "recurse", + "inputs": [ + { + "name": "depth", + "type": "core::felt252" + } + ], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "recursive_syscall", + "inputs": [ + { + "name": "contract_address", + "type": "core::starknet::contract_address::ContractAddress" + }, + { + "name": "function_selector", + "type": "core::felt252" + }, + { + "name": "depth", + "type": "core::felt252" + } + ], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "advance_counter", + "inputs": [ + { + "name": "index", + "type": "core::felt252" + }, + { + "name": "diff_0", + "type": "core::felt252" + }, + { + "name": "diff_1", + "type": "core::felt252" + } + ], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "struct", + "name": "cairo_steps_test_contract::cairo_steps_test_contract::TestContract::IndexAndValues", + "members": [ + { + "name": "index", + "type": "core::felt252" + }, + { + "name": "values", + "type": "(core::integer::u128, core::integer::u128)" + } + ] + }, + { + "type": "function", + "name": "xor_counters", + "inputs": [ + { + "name": "index_and_x", + "type": "cairo_steps_test_contract::cairo_steps_test_contract::TestContract::IndexAndValues" + } + ], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "call_xor_counters", + "inputs": [ + { + "name": "address", + "type": "core::starknet::contract_address::ContractAddress" + }, + { + "name": "index_and_x", + "type": "cairo_steps_test_contract::cairo_steps_test_contract::TestContract::IndexAndValues" + } + ], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "test_ec_op", + "inputs": [], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "add_signature_to_counters", + "inputs": [ + { + "name": "index", + "type": "core::felt252" + } + ], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "send_message", + "inputs": [ + { + "name": "to_address", + "type": "core::felt252" + } + ], + "outputs": [], + "state_mutability": "view" + }, + { + "type": "function", + "name": "test_circuit", + "inputs": [], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "test_rc96_holes", + "inputs": [], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "test_call_contract_revert", + "inputs": [ + { + "name": "contract_address", + "type": "core::starknet::contract_address::ContractAddress" + }, + { + "name": "entry_point_selector", + "type": "core::felt252" + }, + { + "name": "calldata", + "type": "core::array::Array::" + } + ], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "event", + "name": "cairo_steps_test_contract::cairo_steps_test_contract::TestContract::Event", + "kind": "enum", + "variants": [] + } + ] +} diff --git a/crates/blockifier_test_utils/resources/feature_contracts/cairo1/sierra/empty_contract.sierra.json b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/sierra/empty_contract.sierra.json new file mode 100644 index 00000000000..43876518c1b --- /dev/null +++ b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/sierra/empty_contract.sierra.json @@ -0,0 +1,34 @@ +{ + "sierra_program": [ + "0x1", + "0x7", + "0x0", + "0x2", + "0xb", + "0x0", + "0x1", + "0xff", + "0x0", + "0x4", + "0x0" + ], + "sierra_program_debug_info": { + "type_names": [], + "libfunc_names": [], + "user_func_names": [] + }, + "contract_class_version": "0.1.0", + "entry_points_by_type": { + "EXTERNAL": [], + "L1_HANDLER": [], + "CONSTRUCTOR": [] + }, + "abi": [ + { + "type": "event", + "name": "empty_contract::empty_contract::TestContract::Event", + "kind": "enum", + "variants": [] + } + ] +} diff --git a/crates/blockifier_test_utils/resources/feature_contracts/cairo1/sierra/legacy_test_contract.sierra.json b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/sierra/legacy_test_contract.sierra.json new file mode 100644 index 00000000000..6a64aa9a1cc --- /dev/null +++ b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/sierra/legacy_test_contract.sierra.json @@ -0,0 +1,926 @@ +{ + "sierra_program": [ + "0x1", + "0x3", + "0x0", + "0x2", + "0x1", + "0x0", + "0x1b9", + "0x47", + "0x29", + "0x66656c74323532", + "0x0", + "0x556e696e697469616c697a6564", + "0x1", + "0x52616e6765436865636b", + "0x4761734275696c74696e", + "0x4172726179", + "0x536e617073686f74", + "0x4", + "0x537472756374", + "0x2", + "0x1baeba72e79e9db2587cf44fedb2f3700b2075a5e8e39a562584862c4b71f62", + "0x5", + "0x2ee1e2b1b89f8c495f200e4956278a4d47395fe262f27b52e5865c9524c08c3", + "0x456e756d", + "0x3", + "0x11c6d8087e00642489f92d2821ad6ebd6532ad1a3b6d12833da6d6810391511", + "0x7", + "0x1d49f7a4b277bf7b55a2664ce8cef5d6922b5ffb806b89644b9e0cdbbcac378", + "0x6", + "0x9", + "0x16a4c8d7c05909052238a862d8cc3e7975bf05a07b3a69c6b28951083a6d672", + "0xb", + "0x13fdd7105045794a99550ae1c4ac13faa62610dfab62c16422bfcf5803baa6e", + "0xa", + "0xc", + "0x753332", + "0x53797374656d", + "0x9931c641b913035ae674b400b61a51476d506bbe8bba2ff8a6272790aba9e6", + "0x10", + "0x4275696c74696e436f737473", + "0x30cea1c6930088e98b734b3823806642c70fd6c1a2be12802d279650e2d2163", + "0x1686b306ab58809828afa4af40dc5d74846da19c9ab62a1524cb71708d4d1c", + "0x13", + "0xcc5e86243f861d2d64b08c35db21013e773ac5cf10097946fe0011304886d5", + "0x15", + "0x426f78", + "0x29d7d57c04a880978e7b3689f6218e507f3be17588744b58dc17762447ad0e7", + "0x17", + "0x17b6ecc31946835b0d9d92c2dd7a9c14f29af0371571ae74a1b228828b2242", + "0x19", + "0x34f9bd7c6cb2dd4263175964ad75f1ff1461ddc332fbfb274e0fb2a5d7ab968", + "0x1a", + "0x753634", + "0x436f6e747261637441646472657373", + "0x3808c701a5d13e100ab11b6c02f91f752ecae7e420d21b56c90ec0a475cc7e5", + "0x1c", + "0x1d", + "0x1e", + "0x75313238", + "0x8", + "0x2e655a7513158873ca2e5e659a9e175d23bf69a2325cdd0397ca3b8d864b967", + "0x20", + "0x21", + "0x19367431bdedfe09ea99eed9ade3de00f195dd97087ed511b8942ebb45dbc5a", + "0x1f", + "0x22", + "0x23", + "0x24", + "0x38f4af6e44b2e0a6ad228a4874672855e693db590abc7105a5a9819dbbf5ba6", + "0x25", + "0x4e6f6e5a65726f", + "0x2c7badf5cd070e89531ef781330a9554b04ce4ea21304b67a30ac3d43df84a2", + "0x8e", + "0x616c6c6f635f6c6f63616c", + "0x66696e616c697a655f6c6f63616c73", + "0x7265766f6b655f61705f747261636b696e67", + "0x77697468647261775f676173", + "0x6272616e63685f616c69676e", + "0x73746f72655f74656d70", + "0x66756e6374696f6e5f63616c6c", + "0x656e756d5f6d61746368", + "0x73746f72655f6c6f63616c", + "0xd", + "0x7374727563745f6465636f6e737472756374", + "0x61727261795f6c656e", + "0x736e617073686f745f74616b65", + "0xe", + "0x64726f70", + "0x7533325f636f6e7374", + "0x72656e616d65", + "0x7533325f6571", + "0xf", + "0x61727261795f6e6577", + "0x66656c743235325f636f6e7374", + "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", + "0x61727261795f617070656e64", + "0x7374727563745f636f6e737472756374", + "0x656e756d5f696e6974", + "0x11", + "0x6765745f6275696c74696e5f636f737473", + "0x12", + "0x77697468647261775f6761735f616c6c", + "0x14", + "0x16", + "0x4f7574206f6620676173", + "0x496e70757420746f6f2073686f727420666f7220617267756d656e7473", + "0x61727261795f736e617073686f745f706f705f66726f6e74", + "0x18", + "0x6a756d70", + "0x756e626f78", + "0x64697361626c655f61705f747261636b696e67", + "0x1b", + "0x26", + "0x7536345f746f5f66656c74323532", + "0x66656c743235325f737562", + "0x66656c743235325f69735f7a65726f", + "0x636f6e74726163745f616464726573735f746f5f66656c74323532", + "0x753132385f746f5f66656c74323532", + "0x5349474e41545552455f4d49534d41544348", + "0x27", + "0x53454c4543544f525f4d49534d41544348", + "0x434f4e54524143545f4d49534d41544348", + "0x43414c4c45525f4d49534d41544348", + "0x4e4f4e43455f4d49534d41544348", + "0x434841494e5f49445f4d49534d41544348", + "0x5452414e53414354494f4e5f484153485f4d49534d41544348", + "0x4d41585f4645455f4d49534d41544348", + "0x4143434f554e545f4d49534d41544348", + "0x56455253494f4e5f4d49534d41544348", + "0x53455155454e4345525f4d49534d41544348", + "0x424c4f434b5f54494d455354414d505f4d49534d41544348", + "0x424c4f434b5f4e554d4245525f4d49534d41544348", + "0x647570", + "0x6765745f657865637574696f6e5f696e666f5f73797363616c6c", + "0x28", + "0x4c3", + "0xffffffffffffffff", + "0x1ef", + "0x1da", + "0x1c5", + "0x1b0", + "0x19b", + "0x186", + "0x2a", + "0x171", + "0x2b", + "0x2f", + "0x30", + "0x31", + "0x2c", + "0x2d", + "0x2e", + "0x32", + "0x164", + "0x33", + "0x34", + "0x35", + "0x36", + "0x14f", + "0x37", + "0x3a", + "0x38", + "0x39", + "0x3b", + "0x139", + "0x3c", + "0x3f", + "0x3d", + "0x3e", + "0x40", + "0x122", + "0x41", + "0x44", + "0x42", + "0x43", + "0x45", + "0x10a", + "0x46", + "0x49", + "0x47", + "0x48", + "0x4a", + "0xf1", + "0x4b", + "0x4e", + "0x4c", + "0x4d", + "0x4f", + "0xd7", + "0x50", + "0x53", + "0x51", + "0x52", + "0x54", + "0xbc", + "0x55", + "0x56", + "0x57", + "0x58", + "0x59", + "0x5a", + "0x5b", + "0x5c", + "0x5d", + "0x5e", + "0x72", + "0x61", + "0x5f", + "0x60", + "0x62", + "0x63", + "0x64", + "0x65", + "0x66", + "0x67", + "0x68", + "0x69", + "0x6a", + "0x6b", + "0x6c", + "0x6d", + "0x6e", + "0xa2", + "0x6f", + "0x70", + "0x71", + "0x73", + "0x74", + "0x78", + "0x79", + "0x7a", + "0x7b", + "0x7c", + "0x7d", + "0x7e", + "0x7f", + "0x80", + "0x81", + "0x82", + "0x83", + "0x84", + "0x85", + "0x86", + "0x87", + "0x75", + "0x76", + "0x77", + "0x88", + "0x9b", + "0x89", + "0x8a", + "0x8b", + "0x8c", + "0x8d", + "0x8f", + "0x90", + "0x91", + "0x92", + "0x93", + "0x94", + "0x95", + "0x96", + "0x97", + "0x98", + "0x99", + "0x9a", + "0x9c", + "0x9d", + "0x9e", + "0x9f", + "0xa0", + "0xa1", + "0xa3", + "0xa4", + "0xa5", + "0xa6", + "0xa7", + "0xa8", + "0xa9", + "0xaa", + "0xab", + "0xac", + "0xad", + "0xae", + "0xaf", + "0xb0", + "0xb1", + "0xb2", + "0xb3", + "0xb4", + "0xb5", + "0xb6", + "0xb7", + "0xb8", + "0xb9", + "0xba", + "0xbb", + "0xbd", + "0xbe", + "0xbf", + "0xc0", + "0xc1", + "0xc2", + "0xc3", + "0xc4", + "0xc5", + "0xc6", + "0xc7", + "0xc8", + "0xc9", + "0xca", + "0xcb", + "0xcc", + "0xcd", + "0xce", + "0xcf", + "0xd0", + "0xd1", + "0xd2", + "0xd3", + "0xd4", + "0xd5", + "0xd6", + "0xd8", + "0xd9", + "0xda", + "0xdb", + "0xdc", + "0xdd", + "0xde", + "0xdf", + "0xe0", + "0xe1", + "0xe2", + "0xe3", + "0xe4", + "0xe5", + "0xe6", + "0xe7", + "0xe8", + "0xe9", + "0xea", + "0xeb", + "0xec", + "0xed", + "0xee", + "0xef", + "0xf0", + "0xf2", + "0xf3", + "0xf4", + "0xf5", + "0xf6", + "0xf7", + "0xf8", + "0xf9", + "0xfa", + "0xfb", + "0xfc", + "0xfd", + "0xfe", + "0xff", + "0x100", + "0x101", + "0x102", + "0x103", + "0x104", + "0x105", + "0x106", + "0x107", + "0x108", + "0x109", + "0x10b", + "0x10c", + "0x10d", + "0x10e", + "0x10f", + "0x110", + "0x111", + "0x112", + "0x113", + "0x114", + "0x115", + "0x116", + "0x117", + "0x118", + "0x119", + "0x11a", + "0x11b", + "0x11c", + "0x11d", + "0x11e", + "0x11f", + "0x120", + "0x121", + "0x123", + "0x124", + "0x125", + "0x126", + "0x127", + "0x128", + "0x129", + "0x12a", + "0x12b", + "0x12c", + "0x12d", + "0x12e", + "0x12f", + "0x130", + "0x131", + "0x132", + "0x133", + "0x20a", + "0x20f", + "0x219", + "0x228", + "0x22d", + "0x257", + "0x251", + "0x249", + "0x440", + "0x422", + "0x406", + "0x3ec", + "0x3ce", + "0x3b2", + "0x398", + "0x2e6", + "0x381", + "0x36c", + "0x359", + "0x348", + "0x339", + "0x32c", + "0x48b", + "0x463", + "0x481", + "0x47b", + "0x4a1", + "0x4a6", + "0x4b1", + "0x4bd", + "0x203", + "0x220", + "0x261", + "0x265", + "0x452", + "0x49a", + "0x4b7", + "0x27d6", + "0x10140d02030040b050240804040080804038080c02028080804018080200", + "0x282a040a0101c020802824040a01026020803c24040101022020803c1c02", + "0x38040b0500838020d8680819020600410078240817020380410050580404", + "0x101c0205828440410808160a10008080a0107c34040f0103a020803c2804", + "0x240828010401e120209c0826010401e02020104a1a020900823010401e12", + "0x105c0204828042d010b034041581054020803c52040a0101c02080282404", + "0x80802020500835020c00802020d00433050086431020104a30020bc082f", + "0x8160a1d01008250101060041801072041c0106e020a0286c04020940404", + "0x10084120024083b020fc04100780808041f068083d020f00410078ec080e", + "0x10923302010900b020108c04080108e14020108c02228088802218088402", + "0x13028040212c2a040212032040212c94040212016100211c2004021180404", + "0x109e02291380804231380804288081604281380804279380804268080804", + "0x118ac0b0215404040215024040213c20100211ca6040211828040213c0404", + "0x8b65a020108c0405968080b2c86808042c05c08042c00808042b8080804", + "0x11cbc0402118bc040213cbc0402134bc0402160440402160045d2e0100846", + "0x7808042c05008042c02408042782408042689008042797c0804240242004", + "0x2cc6040596404040218808040213cc20b02154c00b02154040b2d0101659", + "0x10ca630201090040598c080b2c84808042c008c863020108c0d020108c02", + "0x10084601198080b1981016591981008460102c6604059640404021440404", + "0x6408042c00816150202cb22902010902b02010966702010900d080108e09", + "0x11c240402118080b2501016590202c2a0405964940402118040b250101659", + "0xc40804328e00804230e80804258e80804328f40804259a00804240502004", + "0x1b0046b1781008461801008461c8100846011a8040402134046918810084b", + "0x17c080b2c9b816042a8c0080427808da35020108c3602010963602010ca02", + "0x2c08553802c085537810084f0102cbe0405964480402160be0402118080b", + "0x10aa35020109e7605810aa7505810aa7405810aa7305810aa7205810aa71", + "0x1f0f60b021545e040213cf40b02154f20b0215472040213cf00b02154ee0b", + "0x1016042a99c08042300816670202cb22b02010b002058a4080b2c8080804", + "0x1016593f01008460102cfc0405964047d0202c520405964080b338101659", + "0x2cb268020108c02059a0080b2c8f408042c0482004239f8080428810167e", + "0x10040201048088002008040206811000401008047f3f01008480202cd004", + "0x8080229811000401008044a022000802010082e04400100402010540880", + "0x10040901088b80b409683c0b4002c080205840040240010040b010090004", + "0x78088002078081201090bc0b40010be040a008be04400102004068080480", + "0x50042b02200085e0203404024001004090109c088219811000b120106602", + "0x19c08830c811000b148106602198110004198541615010a4c60b400105604", + "0x5c1615010c05e0b4001062040a008620440010c604068080480020081202", + "0x105e040680804800200812021c011081a022001630020cc0419022000819", + "0x2001636020cc041a02200081a2502c2a021b0d41680020e40814010e40880", + "0xec1680021a00814011a00880020d4080d01009000401024043a022149c04", + "0x9000401024046f0221812044002c7a04198089c04400109c5305854043d", + "0x8120440010120d0585404003f02d00044381028024381100041d8101a02", + "0x1032024501100040f0102402012000802048091204440500880058000833", + "0x22d14100b808280440010281205854048c02200087e02034048b02200085a", + "0x10940201200080204809240448a40088005a3c081a0123d1c8d08200088c", + "0x24c080d010090004010240497022592a044002d280427009289305a000890", + "0x812024e811389b02200169a020cc049a4c82d00044c01028024c0110004", + "0x11000b5001066025027c168002278081401278088002264080d010090004", + "0x2994a0b4001148040a0094804400113e040680804800200812025181144a1", + "0x5004aa0220008a5020340402400100409012a408a853811000b530106602", + "0x101a02012000802048095e04572b4088005ab00833012b1560b400115404", + "0x2404b5022d166044002d64041980964b105a0008b00205004b00220008ab", + "0x20016b8020cc04b85b82d00045b01028025b0110004588101a02012000802", + "0x2f40880022f0081e012f00880022dc08530100900040102404bb022e97204", + "0x300085a0130008800200844020120008be0217004bf5f02d00045e810b402", + "0x11000461010bc026181100045f810bc020120008c10217004c26082d0004", + "0x9c0402400100409010098a024002d88c30597c04c30220008c30209004c4", + "0x804800229c0827010090004568104e020120008b30209c0402400117204", + "0x900040a0104e020120008950218c0402400113604138080480022840827", + "0x20008190209c0402400103404138080480021380827010090004048104e02", + "0x19c04c86382d00046301056026301100040581052020120008330209c0402", + "0x3280880023280831013280880020086002648110004010bc0402400119004", + "0xe404cd0220008cb6602c6c02660110004010d404cb0220008ca6482c7002", + "0x118e0414809a004400111c040c8099e04400111a04090099c04400119a04", + "0x10043b0100900040102404d268b419e0902348088002338083a013440880", + "0x9b0d705b59aad405a0016d34723420680134c08800234c083d0134c0880", + "0x2d00046281000026281100046c810fc026c8110004011bc0402400100409", + "0x22404dd02200080b020a404dc0220008d502064040240011b40443809b6da", + "0x10340418809c00440010320418809be0440010660418809bc0440011b604", + "0x39008800205008310138c0880020240831013880880021380831013840880", + "0x1062027381100045081062027301100044d81062027281100044a8101a02", + "0x20008b9020c404ea0220008b3020c404e90220008ad020c404e80220008a7", + "0x3b9daec0820008eb753a5d0e773395c8e371385c0df6f375b81e46809d604", + "0x23c0402400100409013c408f077811000b770111c026a01100046a0102402", + "0x20008f30222c04f47982d0004790111402790110004010bc040240011de04", + "0x4804f60220008400224804400220008f50224004f50220008f4022300402", + "0x11ec041d009f20440011da0414809f00440011d8040c809ee0440011a804", + "0x3500812013ec0880023c408390100900040102404fa7cbe1ee09023e80880", + "0x1100047d81074027f01100047681052027e81100047601032027e0110004", + "0x90004598104e020120008b90209c0402400100409013fdfcfd7e02408ff", + "0x200089b0209c04024001142041380804800229c0827010090004568104e02", + "0x109c041380804800202408270100900040a0104e020120008950218c0402", + "0x10042f010090004198104e020120008190209c0402400103404138080480", + "0x3c0088002406000b1c00a02044001202041880a0204400100493014000880", + "0x102402820110004818107202818110004784081636014080880020086a02", + "0x2000904020e8050702200080b020a405060220008d80206405050220008d7", + "0x20008b70218c04024001176043380804800200812026b41e0d0504811ac04", + "0x1142041380804800229c0827010090004568104e020120008b30209c0402", + "0x2408270100900040a0104e020120008950218c0402400113604138080480", + "0x104e020120008190209c0402400103404138080480021380827010090004", + "0xa12044001212041880a1204400100494014200880020085e02012000833", + "0x1072028601100048542c16360142c0880020086a0285011000484c201638", + "0x200080b020a4050f02200088e02064050e02200088d02048050d02200090c", + "0x116a0433808048002008120288c421f0e048122204400121a041d00a2004", + "0x29c0827010090004568104e020120008b10218c0402400106604138080480", + "0x104e020120008950218c0402400113604138080480022840827010090004", + "0x9c0402400103404138080480021380827010090004048104e02012000814", + "0x44c08800244c08310144c0880020092802890110004010bc0402400103204", + "0xe405160220009148a82c6c028a8110004010d405140220009138902c7002", + "0x1016041480a3204400111c040c80a3004400111a040900a2e04400122c04", + "0x2bc086701009000401024051b8d46630090246c08800245c083a014680880", + "0x104e020120008ab0218c0402400103204138080480020cc0827010090004", + "0x9c0402400112a043180804800226c0827010090004508104e020120008a7", + "0x80480020680827010090004270104e020120008090209c0402400102804", + "0x123b1c058e0051d02200091d020c4051d0220008024a00a380440010042f", + "0x2e808800248008390148008800247a3e0b1b00a3e04400100435014780880", + "0x107402918110004058105202910110004470103202908110004468102402", + "0x104e020120008a90219c04024001004090149247229082409240220008ba", + "0x9c0402400114a043180804800206808270100900040c8104e02012000833", + "0x804800205008270100900044a810c60201200089b0209c0402400114204", + "0x4980880020092802928110004010bc0402400109c04138080480020240827", + "0x2c6c02940110004010d405270220009269282c7002930110004930106202", + "0x111c040c80a5604400111a040900a54044001252041c80a5204400124f28", + "0x24052e96cb25609024b80880024a8083a014b408800202c0829014b00880", + "0x9c0402400103204138080480020cc082701009000451810ce02012000802", + "0x804800226c08270100900044f810c60201200084e0209c0402400103404", + "0x4bc0880020085e020120008090209c0402400102804138080480022540863", + "0x86a02988110004984bc1638014c00880024c00831014c00880020092802", + "0x200088d020480534022000933020e405330220009319902c6c02990110004", + "0x1270044001268041d00a6e044001016041480a6c04400111c040c80a6a04", + "0x9c04024001066041380804800227408670100900040102405389bcda6a09", + "0x80480020240827010090004270104e0201200081a0209c0402400103204", + "0x4e40880020085e020120008140209c0402400112a04318080480022640863", + "0x86a025a01100049d4e41638014e80880024e80831014e80880020092802", + "0x200088d02048053d02200093c020e4053c0220008b49d82c6c029d8110004", + "0x128204400127a041d00a80044001016041480a7e04400111c040c80a7c04", + "0x9c04024001066041380804800225c0867010090004010240541a04fe7c09", + "0x80480020240827010090004270104e0201200081a0209c0402400103204", + "0x50c0880020092802a10110004010bc0402400112604318080480020500827", + "0x2c6c02a28110004010d40544022000943a102c7002a18110004a18106202", + "0x111c040c80a9004400111a040900a8e04400128c041c80a8c04400128945", + "0x24054ba552690090252c08800251c083a0152808800202c0829015240880", + "0x9c0402400103404138080480020640827010090004198104e02012000802", + "0x53008800224808390100900040a0104e020120008090209c0402400109c04", + "0x107402a78110004058105202a70110004470103202a68110004468102402", + "0x104e020120008890219c0402400100409015429f4ea6824095002200094c", + "0x9c0402400103404138080480020640827010090004198104e02012000809", + "0xaa20440010042f010090004090112a0201200087e0218c0402400109c04", + "0x1004350154c08800254aa20b1c00aa40440012a4041880aa404400100494", + "0x1100040f0102402aa8110004aa0107202aa0110004a9ab81636012b80880", + "0x240959022000955020e8055802200080b020a4055702200085a020640556", + "0x104e0201200083b0218c040240010de04338080480020081202acd62af56", + "0x2540402400109c041380804800206808270100900040c8104e02012000833", + "0xab604400100494015680880020085e0201200080d022540402400102404", + "0x5741636015740880020086a02ae0110004add6816380156c08800256c0831", + "0x200085a02064056002200081e02048055f02200095e020e4055e02200095c", + "0x81202b1d8ac36004812c60440012be041d00ac4044001016041480ac204", + "0x104e020120008330209c0402400101a044a8080480020e80867010090004", + "0x25404024001024044a8080480020d408630100900040d0104e02012000819", + "0x5940880025940831015940880020092802b20110004010bc040240010a604", + "0xe40568022000966b382c6c02b38110004010d40566022000965b202c7002", + "0x1016041480ad60440010b4040c80ad404400103c040900ad20440012d004", + "0xe0086701009000401024056c545aed409025b00880025a4083a012a00880", + "0x10c6020120008190209c0402400106604138080480020340895010090004", + "0xbc04024001094044a8080480020480895010090004298112a0201200082f", + "0x200096eb682c7002b70110004b70106202b7011000401250056d022000802", + "0xae40440012e2041c80ae20440012df70058d805700220008021a80ade04", + "0x5c8083a015d408800202c0829015d00880021680819015cc0880020780812", + "0x34089501009000433810ce020120008020480aed75ba5cc1204bb0110004", + "0x112a0201200084a02254040240010c604318080480020cc0827010090004", + "0x25005770220008021780804800205c0895010090004090112a02012000853", + "0x20008021a80af20440012f177058e00578022000978020c40578022000802", + "0x5f40880020780812015f00880025ec0839015ec0880025e6f40b1b00af404", + "0x5f41204c00110004be0107402bf8110004058105202bf01100042d0103202", + "0x1780863010090004068112a020120008270219c040240010040901602ff7e", + "0x112a020120008530225404024001094044a80804800205c0895010090004", + "0xc405820220008024a00b020440010042f0100900040a8112a02012000812", + "0x28b060b1b00b06044001004350128808800260b020b1c00b0404400130404", + "0x1100042d0103202c301100040f0102402c28110004c20107202c20110004", + "0x100409016271187c30240989022000985020e8058802200080b020a40587", + "0x5c08950100900040a8112a020120008100218c0402400101a044a8080480", + "0x85e0201200081202254040240010a6044a8080480021280895010090004", + "0x110004c5e2816380162c08800262c08310162c0880020092602c50110004", + "0x48058f02200098e020e4058e02200098cc682c6c02c68110004010d4058c", + "0x131e041d00b24044001016041480b22044001044040c80b200440010b804", + "0x650200b05a0016040225c04040220008020214c0593c964720090264c0880", + "0x1130020a0110004058113402068110004080113202012000802048081204", + "0x113e021981100040127404024001004090100b2a040126c041202200080d", + "0x2000814022300412022000815022600414022000809022680415022000833", + "0x9000401024041a026582e044002c2404500083204400103204068083204", + "0x101a022981100042701146022701100042501142022501100040b8113c02", + "0x68086701009000401024045a0f02c085a02200085302294041e022000819", + "0x8bc0440010320406808440440010b80453008b80440010049d010090004", + "0x25c041002200080b0214c04024001004a401090bc0b0209008800208808a5", + "0x113402090110004068113202012000802048082804cb834120b4002c2004", + "0x27404024001004090100b30040126c0415022000812022600433022000809", + "0x20008170226004330220008140226804170220008190227c0419022000802", + "0x66494044002c2a04500083404400103404068083404400106604460082a04", + "0x85e020f0110004298114202298110004250113c02012000802048089c04", + "0x1100040d0101a022f81100040201032021201100040101024022d0110004", + "0x20008293189cbe2406aa4042902200081e020c4046302200085a0229c0427", + "0x200082b022b004024001004090119c099a15811000b2f01156022f088b810", + "0x2d0004188111402012000802048087004cd8c40880058c008aa010c05e0b", + "0x2bc043a022000839022b40439022000836022300402400106a04458086c35", + "0x880819011a00880021700812010f40880020ec08b1010ec0880020e85e0b", + "0xe008b001009000401024047e379a020043f01100041e8116402378110004", + "0x200085c020480489022000887022c404870220008001782d5e02000110004", + "0x1004090123d1c8d080111e04400111204590091c044001044040c8091a04", + "0x918044001044040c809160440010b80409009140440010ce04598080480", + "0x2740402400109c043380804800200812024823116100224008800222808b2", + "0x11280458809280440011261a05abc0493022000892022c00492022000802", + "0x26808800225408b20126408800201008190125c0880020080812012540880", + "0x110004020116a0205811000401010520202011000401274049a4ca5c2004", + "0x8808800200808190100900040a810c60201200080b0221c04100582c0810", + "0x9008800597008b801170b41e08200085e1102d6e022f0110004020105202", + "0x2ec0463022000827022e40427022000824022d804024001004090117c099c", + "0x862044001052045e80852044001052045e008602f338ac520d40010c604", + "0x8763a05a000839023000439022000838022fc04361a8e02080020c408be", + "0x107604508080480020f40827011a07a0b400102004600080480020e80827", + "0x1100043f1bc16c1011bc0880021bc0831011f80880021a008a1011bc0880", + "0x30c042b02200082b023080430022000830020c40400022000800020c40400", + "0x106a04620086c04400106c04618085e04400105e0461808ce0440010ce04", + "0x2240880020d408bf0100900040102404870267404800580008c7010d40880", + "0x9c048a4782d000404811800201200088d0209c048e4682d0004448118002", + "0x11188b05b04048c02200088a02284048b02200088e022840402400111e04", + "0x9000401024049202678048005a4008c7012400880022400831012400880", + "0x1180020120008940209c04954a02d00044981180024981100041b0119002", + "0x200089902284049a022000895022840402400112e0413809329705a00080d", + "0x67c048005a6c08c70126c08800226c08310126c088002261340b608093004", + "0x28d429e5004900044f81192024f8110004158118c02012000802048093a04", + "0x2ac16800205008c0010090004538104e0254a9c16800228008c0012914ca5", + "0x1062025681100045601142025501100045481142020120008ab0209c04ac", + "0x114804188095e04400115e04188095e04400115aaa05b0404aa0220008aa", + "0x28c08800228c080d0128408800228408ca0127808800227808c3012900880", + "0x96204d0009000b578118e02530110004530106202528110004528106202", + "0x1160041380966b005a0008b20230004b202200089e023200402400100409", + "0x97004400116604508080480022d40827012dd6a0b400102404600080480", + "0x118e025c81100045c81062025c81100045b2e016c1012d80880022dc08a1", + "0x20008bc0230004bc0220008a10232c0402400100409012ec09a10120016b9", + "0x80480022fc0827013017e0b400106604600080480022f40827012f97a0b", + "0x1062026181100046130416c10130808800230008a1013040880022f808a1", + "0x20008a30214c04024001004090131009a20120016c30231c04c30220008c3", + "0x8048002318085c013258c0b4001190042d0099004400118e040f0098e04", + "0x1192042f00804800232c085c01331960b4001194042d0099404400100422", + "0x9000b67334165f01334088002334082401338088002330085e013340880", + "0x109c04138080480020c00827010090004298104e020120008020480805a3", + "0x68082701009000433811980201200084a0209c0402400105e04660080480", + "0x104e020120008a60209c0402400102e04138080480022900827010090004", + "0xc404d0022000802668099e0440010042f010090004528104e02012000819", + "0x345a40b1b009a404400100435013440880023419e0b1c009a00440011a004", + "0x1100042d01052026a81100040f01032026a0110004698119c02698110004", + "0x2d000452811800201200080204809b0d76a84008d80220008d40233c04d7", + "0x284040240011b40413809b6da05a00081902300040240011b204138098ad9", + "0x3b80831013b80880023b5d80b60809da0440011b60450809d804400118a04", + "0x2d000453011800201200080204809b804d2009000b770118e02770110004", + "0x284040240011be0413809c0df05a00081702300040240011ba0413809bcdd", + "0x38c08310138c088002389c20b60809c40440011c00450809c20440011bc04", + "0x2d000452011800201200080204809c804d2809000b718118e02718110004", + "0x284040240011ce0413809d0e705a00081a02300040240011ca0413809cce5", + "0x3ac0831013ac0880023a9d20b60809d40440011d00450809d20440011cc04", + "0x11000433811900201200080204809de04d3009000b758118e02758110004", + "0x9eaf405a00084a02300040240011e40413809e6f205a0008f10230004f1", + "0x3d8800b60809ec0440011ea0450808800440011e604508080480023d00827", + "0x200080204809f004d3809000b7b8118e027b81100047b81062027b8110004", + "0x300040240011f40413809f6fa05a0008f90230004f902200082f023200402", + "0x11fa0450809fc0440011f604508080480023f00827013f5f80b400109c04", + "0x9000b800118e028001100048001062028001100047fbf816c1013fc0880", + "0x300040240011e0041380a04f005a0008300230004024001004090140409a8", + "0x1208045080a0a044001204045080804800240c082701412060b40010a604", + "0x9000b838118e028381100048381062028381100048341416c1014180880", + "0x11a20284811000484011a0028401100040127404024001004090135809a9", + "0x200090a0233c050c02200085a020a4050b02200081e02064050a022000909", + "0x4380880020085e020120008d602348040240010040901436190b080121a04", + "0x86a0288011000487c3816380143c08800243c08310143c088002009a602", + "0x200081e0206405130220009120233805120220009108882c6c02888110004", + "0x1004090145a2b14080122c044001226046780a2a0440010b4041480a2804", + "0x10042f010090004180104e020120008530209c0402400120204690080480", + "0x4640880024622e0b1c00a30044001230041880a30044001004d40145c0880", + "0x1032028e01100048d8119c028d81100048cc681636014680880020086a02", + "0xa3f1e8e840091f02200091c0233c051e02200085a020a4051d02200081e", + "0x80480020c00827010090004298104e020120008f8023480402400100409", + "0x2e8088002009aa02900110004010bc0402400105e04660080480021380827", + "0x2c6c02910110004010d405210220008ba9002c70025d01100045d0106202", + "0x10b4041480a4a04400103c040c80a48044001246046700a4604400124322", + "0x11de0469008048002008120293c9a4a100249c08800249008cf014980880", + "0xbc08cc010090004270104e020120008300209c040240010a604138080480", + "0x9ae02940110004010bc040240010ce04660080480021280827010090004", + "0x110004010d4052a0220009299402c7002948110004948106202948110004", + "0xa5c04400103c040c80a5a044001258046700a580440012552b058d8052b", + "0x80480020081202984be5c10024c00880024b408cf014bc0880021680829", + "0x90004270104e020120008300209c040240010a6041380804800239008d2", + "0x200081a0209c040240010ce04660080480021280827010090004178119802", + "0x1264041880a64044001004d8014c40880020085e020120008a40209c0402", + "0x11000499cd01636014d00880020086a02998110004994c41638014c80880", + "0x33c053802200085a020a4053702200081e020640536022000935023380535", + "0x104e020120008dc023480402400100409014e67137080127204400126c04", + "0x9c0402400105e04660080480021380827010090004180104e02012000853", + "0x804800229008270100900040d0104e02012000867023300402400109404", + "0x2d0088002009b2029d0110004010bc0402400114c041380804800205c0827", + "0x2c6c029e0110004010d4053b0220008b49d02c70025a01100045a0106202", + "0x10b4041480a7e04400103c040c80a7c04400127a046700a7a0440012773c", + "0x118804690080480020081202a0d027e10025040880024f808cf015000880", + "0xbc08cc010090004270104e020120008300209c040240010a604138080480", + "0x104e0201200081a0209c040240010ce04660080480021280827010090004", + "0x9c04024001032041380804800229808270100900040b8104e020120008a4", + "0xa86044001004c5015080880020085e020120008a30218c0402400114a04", + "0x5141636015140880020086a02a20110004a1d0816380150c08800250c0831", + "0x200085a020a4054802200081e020640547022000946023380546022000944", + "0x20008bb0234804024001004090152a9348080129404400128e046780a9204", + "0x105e04660080480021380827010090004180104e020120008530209c0402", + "0x29008270100900040d0104e02012000867023300402400109404138080480", + "0x104e020120008190209c0402400114c041380804800205c0827010090004", + "0xbc04024001142046d0080480020cc082701009000451810c6020120008a5", + "0x200094ca582c7002a60110004a60106202a601100040136c054b022000802", + "0xaa004400129e046700a9e04400129b4e058d8054e0220008021a80a9a04", + "0x54aa2100254c08800254008cf015480880021680829015440880020780819", + "0x20008300209c040240010a604138080480022c408d2010090004010240553", + "0x10ce0466008048002128082701009000417811980201200084e0209c0402", + "0x29808270100900040b8104e020120008a40209c0402400103404138080480", + "0x104e020120008a30218c0402400114a04138080480020640827010090004", + "0xbc0402400113c0466008048002048082701009000450811b402012000833", + "0x20009545702c7002aa0110004aa0106202aa0110004013b004ae022000802", + "0xab00440012ae046700aae0440012ab56058d805560220008021a80aaa04", + "0x56ab2100256c08800256008cf015680880021680829015640880020780819", + "0x20008300209c040240010a6041380804800227408d201009000401024055b", + "0x10ce0466008048002128082701009000417811980201200084e0209c0402", + "0xcc08270100900040b8104e020120008120209c0402400103404138080480", + "0x85e0201200082b023b40402400102804138080480020640827010090004", + "0x110004aed70163801574088002574083101574088002009dc02ae0110004", + "0x64056102200096002338056002200095eaf82c6c02af8110004010d4055e", + "0x592c76208012c80440012c2046780ac60440010b4041480ac404400103c04", + "0x90004180104e020120008530209c0402400112404690080480020081202", + "0x2000867023300402400109404138080480020bc08cc010090004270104e02", + "0x1066041380804800205c0827010090004090104e0201200081a0209c0402", + "0x34082701009000415811da020120008140209c0402400103204138080480", + "0x106202b30110004013700565022000802178080480020d808cc010090004", + "0x12cf68058d805680220008021a80ace0440012cd65058e00566022000966", + "0x2a00880021680829015ac0880020780819015a80880025a408ce015a40880", + "0x804800221c08d201009000401024056c545ac2004b60110004b50119e02", + "0x9000417811980201200084e0209c04024001060041380804800214c0827", + "0x20008120209c04024001034041380804800219c08cc010090004250104e02", + "0x102804138080480020640827010090004198104e020120008170209c0402", + "0x2408270100900041b011980201200080d0209c0402400105604768080480", + "0x106202b7011000401378056d022000802178080480020d408dd010090004", + "0x12df70058d805700220008021a80ade0440012dd6d058e0056e02200096e", + "0x5d00880021680829015cc0880020780819015c80880025c408ce015c40880", + "0x804800214c0827010090004010240575ba5cc2004ba8110004b90119e02", + "0x90004250104e0201200080d0209c0402400109c04138080480020240827", + "0x20008170209c0402400102404138080480020680827010090004080104e02", + "0x10be046700804800205008270100900040c8104e020120008330209c0402", + "0x5e40880025d808cf015e00880021680829015dc0880020780819015d80880", + "0x81a04400101a041e8081a0440010043b010090004012900579bc5dc2004", + "0x2d000404811be02012000802048082a3305ea8241405a00160d020082068", + "0x804800200812020b81356024002c3204638082804400102804090083209", + "0x12808e201128088002068160b708083404400102004700080480020240827", + "0x11000427011c6020f01100040901032022981100040a0102402270110004", + "0x17808800202c080d0100900040b811a40201200080204808b41e29840085a", + "0x804800200812022f8135824022001622020cc04222e02d00042f0102802", + "0x1024021481100043182416c10118c088002009c802138110004120401638", + "0x20008270229c043802200085c020340431022000812020640430022000814", + "0x1156021799c5610400106c351c0c4600d548086c04400105204188086a04", + "0xec16e1010f4760b4001072045600804800200812021d0135a3902200162f", + "0x200086702064047e02200082b02048046f02200086802388046802200083d", + "0x200083a0239404024001004090121c007e080110e0440010de04718080004", + "0x111e04400111204718091c0440010ce040c8091a04400105604090091204", + "0x11cc020120008100222c040240010120413808048002008120247a391a10", + "0x10280409009180440011160471009160440011145c05b84048a02200085f", + "0x8120249a4920100224c08800223008e3012480880020480819012400880", + "0x85e0201200080b0218c0402400102004458080480020240827010090004", + "0x1100044aa5016380125408800225408310125408800200926024a0110004", + "0x48049802200089a02394049a0220008974c82c6c024c8110004010d40497", + "0x27d3a9b080113e04400113004718093a04400102a040c8093604400106604", + "0x101204740080480020081202090501a10d7024200b0820016040102dce02", + "0x5c0880020cc08e90106408800204008290105408800202c0819010cc0880", + "0x1100040681032020d011000409011d4020120008020480805af020093602", + "0x3bc044e022000817023ac041702200081a023a40419022000814020a40415", + "0x14c08b601009000401024041e026c0a6044002c94045c0089404400109c04", + "0x1100040a81032021101100042e011e4022e01100042d011e2022d0110004", + "0x200080204808be242f040085f022000822023cc0424022000819020a4045e", + "0x3cc0429022000819020a4046302200081502064042702200081e023d00402", + "0x2000802048081604d881008800580808f5010ac5263080105604400104e04", + "0x10080d022000809023cc0409022000810023c80410022000804023c40402", + "0x4808f40104808800202c280b1b008280440010043501009000401024040d", + "0x8b4530802c12142984016091985408040a811000419811e602198110004", + "0x14c1653026cc160401128200b08050200b086c804330a02c2804010401604", + "0x2c08022f94c201001008040201008280201008040201178a6100f6d00412", + "0x2c0802338401610010242810058376a532712834170c85466120a0341210", + "0x6e00468021f809b702008d05308040a61005ed81210" + ], + "sierra_program_debug_info": { + "type_names": [], + "libfunc_names": [], + "user_func_names": [] + }, + "contract_class_version": "0.1.0", + "entry_points_by_type": { + "EXTERNAL": [ + { + "selector": "0x3c118a68e16e12e97ed25cb4901c12f4d3162818669cc44c391d8049924c14", + "function_idx": 0 + } + ], + "L1_HANDLER": [], + "CONSTRUCTOR": [] + }, + "abi": [ + { + "type": "struct", + "name": "core::array::Span::", + "members": [ + { + "name": "snapshot", + "type": "@core::array::Array::" + } + ] + }, + { + "type": "function", + "name": "test_get_execution_info", + "inputs": [ + { + "name": "block_number", + "type": "core::felt252" + }, + { + "name": "block_timestamp", + "type": "core::felt252" + }, + { + "name": "sequencer_address", + "type": "core::felt252" + }, + { + "name": "version", + "type": "core::felt252" + }, + { + "name": "account_address", + "type": "core::felt252" + }, + { + "name": "max_fee", + "type": "core::felt252" + }, + { + "name": "signature", + "type": "core::array::Span::" + }, + { + "name": "transaction_hash", + "type": "core::felt252" + }, + { + "name": "chain_id", + "type": "core::felt252" + }, + { + "name": "nonce", + "type": "core::felt252" + }, + { + "name": "caller_address", + "type": "core::felt252" + }, + { + "name": "contract_address", + "type": "core::felt252" + }, + { + "name": "entry_point_selector", + "type": "core::felt252" + } + ], + "outputs": [], + "state_mutability": "view" + }, + { + "type": "event", + "name": "legacy_test_contract::legacy_test_contract::TestContract::Event", + "kind": "enum", + "variants": [] + } + ] +} diff --git a/crates/blockifier_test_utils/resources/feature_contracts/cairo1/sierra/meta_tx_test_contract.sierra.json b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/sierra/meta_tx_test_contract.sierra.json new file mode 100644 index 00000000000..13f35dfae9f --- /dev/null +++ b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/sierra/meta_tx_test_contract.sierra.json @@ -0,0 +1,901 @@ +{ + "sierra_program": [ + "0x1", + "0x7", + "0x0", + "0x2", + "0xb", + "0x0", + "0x18b", + "0x75", + "0x46", + "0x52616e6765436865636b", + "0x800000000000000100000000000000000000000000000000", + "0x436f6e7374", + "0x800000000000000000000000000000000000000000000002", + "0x1", + "0x18", + "0x2", + "0x75385f616464204f766572666c6f77", + "0x4", + "0x7538", + "0x800000000000000700000000000000000000000000000000", + "0x53746f7265553634202d206e6f6e20753634", + "0x7536345f616464204f766572666c6f77", + "0x8", + "0x753634", + "0x53746f7261676541646472657373", + "0x53746f726167654261736541646472657373", + "0x537472756374", + "0x800000000000000700000000000000000000000000000002", + "0x0", + "0x11a4edaf795586e09e79bc8a18af605ef6205fcf112e7067498f60ef982c054", + "0xa", + "0x7533325f737562204f766572666c6f77", + "0x496e646578206f7574206f6620626f756e6473", + "0x426f78", + "0x800000000000000700000000000000000000000000000001", + "0x800000000000000f00000000000000000000000000000001", + "0x2ee1e2b1b89f8c495f200e4956278a4d47395fe262f27b52e5865c9524c08c3", + "0x456e756d", + "0x800000000000000700000000000000000000000000000003", + "0x29d7d57c04a880978e7b3689f6218e507f3be17588744b58dc17762447ad0e7", + "0xe", + "0xf", + "0x4172726179", + "0x800000000000000300000000000000000000000000000001", + "0x800000000000000300000000000000000000000000000003", + "0x101dc0399934cc08fa0d6f6f2daead4e4a38cabeea1c743e1fc28d2d6e58e99", + "0x11", + "0x800000000000000300000000000000000000000000000002", + "0x12", + "0x16a4c8d7c05909052238a862d8cc3e7975bf05a07b3a69c6b28951083a6d672", + "0x14", + "0x5b9304f5e1c8e3109707ef96fc2ba4cf5360d21752ceb905d488f0aef67c7", + "0x13", + "0x15", + "0x436f6e747261637441646472657373", + "0x66656c74323532", + "0x75313238", + "0x753332", + "0x80000000000000070000000000000000000000000000000a", + "0x4e0d47224abd058bd90192c42493b48cf5f243fcba0654adecdce1301654a5", + "0x17", + "0x19", + "0x1a", + "0x1166fe35572d4e7764dac0caf1fd7fc591901fd01156db2561a07b68ab8dca2", + "0xaf4803c1915e59222675dcd896e757919ffe5d569fa9c60bbb47f95661845d", + "0x1d", + "0x1e", + "0x25a92f51abed22f1dfc8930f41f978d26924c1445fb3398225ccfb3d24377cf", + "0x1f", + "0x9312848b624a14a3b5eb7def2366ae76c63e8f1ef3a4640ee899b5ed21a1c4", + "0x1b360cc174a76b27b6489b84c9e1b068b875b6d842703a943e3744975892d80", + "0x36a4d0ecc8e01060df131b5f5774626c4b28788f6c84c50a387e5fc27d640e9", + "0x800000000000000700000000000000000000000000000004", + "0x3342418ef16b3e2799b906b1e4e89dbb9b111332dd44f72458ce44f9895b508", + "0x24", + "0x536e617073686f74", + "0x25", + "0x4e4f5f5349474e4154555245", + "0x1597b831feeb60c71f259624b79cf66995ea4f7e383403583674ab9c33b9cec", + "0x26", + "0x1baeba72e79e9db2587cf44fedb2f3700b2075a5e8e39a562584862c4b71f62", + "0x29", + "0x80000000000000070000000000000000000000000000000e", + "0x348a62b7a38c0673e61e888d83a3ac1bf334ee7361a8514593d3d9532ed8b39", + "0x2a", + "0x28", + "0x2b", + "0x2e", + "0x3808c701a5d13e100ab11b6c02f91f752ecae7e420d21b56c90ec0a475cc7e5", + "0x800000000000000700000000000000000000000000000006", + "0x7d4d99e9ed8d285b5c61b493cedb63976bc3d9da867933d829f49ce838b5e7", + "0x2d", + "0x2c", + "0x2f", + "0x4661696c656420746f20646573657269616c697a6520706172616d202332", + "0x4661696c656420746f20646573657269616c697a6520706172616d202333", + "0x4661696c656420746f20646573657269616c697a6520706172616d202334", + "0x526573756c743a3a756e77726170206661696c65642e", + "0x4e4f5f415247554d454e54", + "0x1d49f7a4b277bf7b55a2664ce8cef5d6922b5ffb806b89644b9e0cdbbcac378", + "0x36", + "0x13fdd7105045794a99550ae1c4ac13faa62610dfab62c16422bfcf5803baa6e", + "0x37", + "0x11c6d8087e00642489f92d2821ad6ebd6532ad1a3b6d12833da6d6810391511", + "0x4661696c656420746f20646573657269616c697a6520706172616d202331", + "0x4f7574206f6620676173", + "0x243ad66fb88b14a61b2ad89747f2714f071e786760b60279e59c9032112c213", + "0x800000000000000f00000000000000000000000000000003", + "0x3d", + "0x6f4b619013a246ca99c8b49e09bfd42357b265f642c876f3e1fa4a8c4f31e3", + "0x3e", + "0x4275696c74696e436f737473", + "0x53797374656d", + "0x506564657273656e", + "0x9931c641b913035ae674b400b61a51476d506bbe8bba2ff8a6272790aba9e6", + "0x3c", + "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", + "0x4761734275696c74696e", + "0xb2", + "0x7265766f6b655f61705f747261636b696e67", + "0x77697468647261775f676173", + "0x6272616e63685f616c69676e", + "0x72656465706f7369745f676173", + "0x7374727563745f6465636f6e737472756374", + "0x73746f72655f74656d70", + "0x45", + "0x61727261795f736e617073686f745f706f705f66726f6e74", + "0x756e626f78", + "0x64726f70", + "0x61727261795f6e6577", + "0x636f6e73745f61735f696d6d656469617465", + "0x44", + "0x61727261795f617070656e64", + "0x7374727563745f636f6e737472756374", + "0x656e756d5f696e6974", + "0x43", + "0x42", + "0x41", + "0x6765745f6275696c74696e5f636f737473", + "0x40", + "0x77697468647261775f6761735f616c6c", + "0x72656e616d65", + "0x66756e6374696f6e5f63616c6c", + "0x3", + "0x656e756d5f6d61746368", + "0x3f", + "0x736e617073686f745f74616b65", + "0x3b", + "0x3a", + "0x656e61626c655f61705f747261636b696e67", + "0x39", + "0x6a756d70", + "0x64697361626c655f61705f747261636b696e67", + "0x21adb5788e32c84f69a1863d85ef9394b7bf761a0ce1190f826984e5075c371", + "0x38", + "0x6d6574615f74785f76305f73797363616c6c", + "0x35", + "0x34", + "0x33", + "0x32", + "0x31", + "0x6765745f657865637574696f6e5f696e666f5f76325f73797363616c6c", + "0x30", + "0x647570", + "0x27", + "0x61727261795f6c656e", + "0x23", + "0x22", + "0x21", + "0x20", + "0xad292db4ff05a993c318438c1b6c8a8303266af2da151aa28ccece6726f1f1", + "0x1c", + "0x1b", + "0x5", + "0x16", + "0x10", + "0x7533325f7472795f66726f6d5f66656c74323532", + "0x61727261795f736c696365", + "0x7533325f6f766572666c6f77696e675f737562", + "0xd", + "0xc", + "0xb", + "0x73746f726167655f616464726573735f66726f6d5f62617365", + "0x73746f726167655f726561645f73797363616c6c", + "0x7536345f7472795f66726f6d5f66656c74323532", + "0x7", + "0x7536345f6f766572666c6f77696e675f616464", + "0x7536345f746f5f66656c74323532", + "0x73746f726167655f77726974655f73797363616c6c", + "0x706564657273656e", + "0x6", + "0x636f6e74726163745f616464726573735f746f5f66656c74323532", + "0x2679d68052ccd03a53755ca9169677965fbd93e489df62f5f40d4f03c24f7a4", + "0x9", + "0x75385f6f766572666c6f77696e675f616464", + "0x753132385f746f5f66656c74323532", + "0x7533325f746f5f66656c74323532", + "0x4f9", + "0xffffffffffffffff", + "0x6b", + "0x5b", + "0x4b", + "0x47", + "0x199", + "0x8d", + "0x94", + "0x185", + "0x17f", + "0x16e", + "0x163", + "0x150", + "0x144", + "0x130", + "0xd4", + "0x11d", + "0x48", + "0x49", + "0x4a", + "0x4c", + "0x4d", + "0x4e", + "0x107", + "0x4f", + "0x50", + "0x51", + "0x52", + "0x53", + "0x54", + "0x55", + "0x56", + "0x57", + "0x58", + "0x59", + "0x5a", + "0xfd", + "0x5c", + "0x5d", + "0x5e", + "0x5f", + "0x60", + "0x61", + "0x62", + "0x63", + "0x64", + "0x65", + "0x66", + "0x67", + "0x68", + "0x69", + "0x6a", + "0x114", + "0x6c", + "0x6d", + "0x6e", + "0x6f", + "0x70", + "0x71", + "0x72", + "0x73", + "0x74", + "0x75", + "0x76", + "0x77", + "0x78", + "0x79", + "0x7a", + "0x7b", + "0x7c", + "0x7d", + "0x7e", + "0x7f", + "0x80", + "0x81", + "0x82", + "0x83", + "0x84", + "0x85", + "0x86", + "0x87", + "0x88", + "0x89", + "0x8a", + "0x8b", + "0x8c", + "0x8e", + "0x8f", + "0x90", + "0x91", + "0x92", + "0x93", + "0x18c", + "0x95", + "0x96", + "0x97", + "0x98", + "0x99", + "0x9a", + "0x9b", + "0x9c", + "0x9d", + "0x9e", + "0x9f", + "0xa0", + "0xa1", + "0xa2", + "0x25f", + "0x1d2", + "0x1da", + "0x24f", + "0x234", + "0x22a", + "0x222", + "0x246", + "0x274", + "0x279", + "0x2cb", + "0x2c2", + "0x2b5", + "0x2a6", + "0x29a", + "0x33c", + "0x330", + "0x31d", + "0x30f", + "0x344", + "0x4e4", + "0xa3", + "0x4d0", + "0xa4", + "0xa5", + "0x4bc", + "0xa6", + "0xa7", + "0x4a5", + "0x492", + "0x47c", + "0x46a", + "0x455", + "0x444", + "0x430", + "0xa8", + "0x420", + "0x40d", + "0xa9", + "0x3fe", + "0x3ec", + "0x3e1", + "0xaa", + "0xab", + "0xac", + "0xad", + "0xae", + "0xaf", + "0xb0", + "0xb1", + "0xb3", + "0xb4", + "0xb5", + "0xb6", + "0xb7", + "0xb8", + "0xb9", + "0xba", + "0xbb", + "0xbc", + "0xbd", + "0xbe", + "0xbf", + "0xc0", + "0xc1", + "0xc2", + "0xc3", + "0xc4", + "0xc5", + "0xc6", + "0xc7", + "0xc8", + "0xc9", + "0xca", + "0xcb", + "0xcc", + "0xcd", + "0xce", + "0xcf", + "0xd0", + "0xd1", + "0xd2", + "0xd3", + "0xd5", + "0xd6", + "0xd7", + "0xd8", + "0xd9", + "0xda", + "0xdb", + "0xdc", + "0xdd", + "0xde", + "0xdf", + "0x1a9", + "0x26d", + "0x2d5", + "0x34d", + "0x2c24", + "0x180a040182c1405038240a040181c0e09028100608038180a04018080200", + "0xc2c050a85026120584416100583c0a070701408030681c0c050200c1807", + "0x840a200287c281e0e870281b090180a1a0c8600e06028100617038180a04", + "0x1438141204852140d84850050e0504e1213014420512850481d030144622", + "0xd00a34028cc28320902c620b1802c5e0b170b40a2c028ac28240e8980a2a", + "0x480c051b85026120a01c6c050200c0c051b0146a05030140c05030140c05", + "0x4c2439028f42813090b40a3c028ec28240e8e80a1c0a04c2439028e02813", + "0x1434432101446221a8141c05030148214200487e07030140803030147c14", + "0x12c284a091240a480a04c2426028688647029182813091140e06028100644", + "0x6498051b0146c05260146a05268140c05030140c05260146a051a0140c05", + "0xd00a540294c0a520a1442434028380a0e0294028400913c0a1a0c9380a1a", + "0xcb0070301408032b81c0c050200cac070301408032a8143419030146805", + "0x1700a4c02870281e090840a4c0296c281e0e9680e06028100659038180a04", + "0x1c0c050200cc007030140803108140c052f8503c1d16814bc052e850481d", + "0xb40a660299428240e8840a6402870286309188281b091300a1c0a04c2461", + "0x50e014379b8046d3601c0c050200c5a0535814d414120740469011a01667", + "0x140a74030140a77030140a763a8140a740a0140a74260140a730a1c82871", + "0x14f87b02814f40602814f20602814f02002814f04902814f00602814e849", + "0x140a74408140a74400140a740281cfe05039f85a05029f45405029f40c05", + "0x14f089028151007438150c6402814fa06028150a144220c0a053a051047f", + "0x140a7a0a01cfe05039f8d605029f49805029f44c05029e04c0502a28cc05", + "0x840a053e8511e8e02814e81403a380a073f0511a4c02814f08c02814f48b", + "0x1cd240502a210e8702a189805029d028910a2411c0502a200a07470140e7e", + "0x14e82a02814f02d02814e69402814f414498d00a053c1700a05441780a05", + "0x140a740a2653005029e92e05029e92c05029e84205029e12a05029e84c05", + "0x14e64e02814ee5402815365402814e85302814f05502814e65502814ee9a", + "0x1cc0c0502a293805029e89c05029d06c05029e09a05029e06a05029e09c05", + "0x27c0a0539a7c0a053c27c0a054527c0a053ea780a053d1080a054e9340a05", + "0x140a881b0140a742a8140a7404a1c0a86500140a74500140a7d1c8140a7d", + "0x2900a053ea8c0a053d1500a053c051443902814e63a02814e63c02814e6a1", + "0x140a7d140140a88160140a73530140a8852a1c0a86520140a740b0140a74", + "0x14f00503a240a073f1540a053c1900a053c2240a053a0500e890281cfc66", + "0x2a14e0502a20920502a6c0a07538140e7e538140a740a01d4e05039f89c05", + "0x1cfc5e02814fa14039700a073f0515406028153a06028155236028153614", + "0x1cb805039f95805029e80a07490140e7e558140a7a490140a740a01d2405", + "0x150aad02814e6ad02814f0ad0281514ad02814faa002814e6a0028153605", + "0x2d428b40a2cc28b2070140a74070140a9b588140a7a0a2c028af0a2b82c05", + "0x2800a053c0380a053c2840a053a0500ea10281cfc3c02814fa3a02814fa14", + "0x140a9b0a2dd4805029cd4a05029e96c05029e82c05029e00a07508140e7e", + "0x5176145d0240a053a0240a054d81c0a053d2e40a053a051708702814f416", + "0x1c5005039f94c05029d02807530140e7e160140a7d0a01c5005039f828bc", + "0x1c0a070285028be0285028145e8140ea60281cfc0502814f40902814f005", + "0x240a090a2e40abe02ad80a870a0517c050a01c280e5881d7eb65281d7c07", + "0x1d7c070b01562145c8157c055c8156c14528157c05528154a140b0157c05", + "0x840abe02ab00a0e0a0800abe02ae40a870a0517c050a01c28ab02b0158ad", + "0x156214108157c05108142c14100157c05100156c14568157c05568157214", + "0x144c055605028be02a9c0aad0a0517c050a01c282802a804ca703af80ead", + "0x504214150157c050a080282c02af80a2002a1c28145f01442055585028be", + "0x157c050a09828a602af80a2d1501d4e14168157c05168142c14168157c05", + "0x5028055f0142805150506a055f0140c05160500c055f0154c34038a02834", + "0xd40aa60a21c0abe02a1c0a2d0a0b00abe028b00ab60a2940abe02a940aa5", + "0x150e140a2f80a2802ab428145f01428070a0d50e2c528514a051a8157c05", + "0x157c05520140c141b0157c051b0156c14520157c050a0d0283602af80a20", + "0x1472054385028be028500e141e0e80ec11ca8c0ebe03a906ca5438d428a4", + "0x5146055f0154605528513e055f01428a40a2800abe028840a360a2840abe", + "0x2800a160a21c0abe02a1c0a2d0a0500abe028500a2a0a2840abe02a840ab6", + "0x2f80e9c028e4289c23910849e52af80aa04fa1c28a151ad94614500157c05", + "0x5098055f01484054385028be029340a3a0a0517c050a01c284902a009a05", + "0x14a6055005028be029500aa10a14ca8075f0149c051e0509c055f0142820", + "0x1100abe029100a2a0a2680abe029540a9e0a1540abe0293c0a9f0a13c0abe", + "0x154c14238157c05238145a14260157c05260156c144f0157c054f0154a14", + "0x5130055f01484054385028be028500e144d11c989e222940a9a02af80a9a", + "0x2600ab60a2780abe02a780aa50a1100abe029100a2a0a25c0abe029240a2c", + "0x25c8e984f1114a054b8157c054b8154c14238157c05238145a144c0157c05", + "0x157c050a080289602af80a3c02a1c28145f01442055585028be028500e14", + "0x98285c02af80a944a81d4e144a0157c054a0142c144a0157c050a1082895", + "0x142805150511c055f01524051605124055f014b85e038a0285e02af80a14", + "0x21c0abe02a1c0a2d0a2580abe02a580ab60a0e80abe028e80aa50a0500abe", + "0x2f80aab02ab428145f01428070a2390e961d0514a05470157c05470154c14", + "0x1ac0a160a1ac0abe028508814458157c050a080288c02af80ab902a1c2814", + "0x2f80a643301c5014330157c050a098286402af80a6b4581d4e14358157c05", + "0x514a055f0154a055285028055f01428051505106055f0151205160511205", + "0x29428a502a0c0abe02a0c0aa60a21c0abe02a1c0a2d0a2300abe02a300ab6", + "0x504014408157c05070150e140a2f80a090291c28145f01428070a20d0e8c", + "0x157c053fa000ea70a1fc0abe029fc0a160a1fc0abe028508414400157c05", + "0xa828c202af80a00028b0280002af80a7b3a81c50143a8157c050a098287b", + "0x150e051685102055f01502055b05162055f01562055285028055f0142805", + "0x1c0a140a2f80a140a051848740ac428a502b080abe02b080aa60a21c0abe", + "0x2428b902af80ab602a1c28145f01428070a039620761ad94a075f01c0e05", + "0x157c055c8156c14528157c05528154a140a2f80a144e0502c055f0141205", + "0x800abe02ae40a870a0517c050a01c28ab02b1158ad03af80e1602ac428b9", + "0x156c14130157c05538149a14538157c05108146c14108157c05560141c14", + "0x518a050a130282a02af80a2602924282c02af80aad02ae4282802af80a20", + "0x2f80aa60295028a602af80a14270505a055f01572054385028be028500e14", + "0x5054055f01468052485058055f01556055c85050055f0145a055b0506805", + "0x1450054385028be028509e140a2f80a14038506a05630180abe038a80a53", + "0x500e141c8158ea35201d7c07032940e550a0d80abe028d80ab60a0d80abe", + "0xe80abe028e80ab60a2900abe02a900aa50a0e80abe028d80a870a0517c05", + "0x513e055f01474054385028be028500e145001590a11e01d7c07160156214", + "0x1080a9a0a2900abe02a900aa50a1080abe028f00aa00a2780abe02a840a0e", + "0x153c050b0513e055f0153e055b0508e4403af80a425201d3014210157c05", + "0x157c054f8150e140a2f80a14038509a0564a700abe0391c0a970a2780abe", + "0x328a8055f01c9c054a85092055f01492055b0509c4c03af80a9c02a582849", + "0x153414220157c05220154a14278157c05248150e140a2f80a1403850a605", + "0x2680a970a13c0abe0293c0ab60a268aa075f014984403a60284c02af80a4c", + "0x2f80a9802a58289602af80a4f02a1c28145f01428070a25c0acb4c0157c07", + "0x2f80a1403850bc05661700abe03a500a950a2580abe02a580ab60a2512a07", + "0x2c4289202af80a9202ad8288e02af80a9502824289202af80a9602a1c2814", + "0x22c0aac0a0517c05460155a140a2f80a1403850d60566a2d18075f01d1c05", + "0x1528140a2f80a9e02aac28145f014a8052385028be029700a470a0517c05", + "0x5112055f01428210a1980abe028504014320157c05490150e140a2f80aa3", + "0x2040e280a2040abe028504c14418157c05449980ea70a2240abe02a240a16", + "0x2f80a5502a94281402af80a14028a8287f02af80a80028b0288002af80a83", + "0x14fe055f014fe05530510e055f0150e0516850c8055f014c8055b050aa05", + "0x1ec0abe02a480a870a0517c05358155a140a2f80a1403850fe873215428a5", + "0x1550e350a1d40abe029d40a060a1ec0abe029ec0ab60a1d40abe028506814", + "0xd828d102af80ac202a1c28145f01428070a3419e076730800075f01cea7b", + "0x21da2b62e05000055f014000552851a2055f015a2055b05182055f0153c05", + "0x2f80ad40291c28145f01428070a361aed643b55a8d36921d7c072e15182a3", + "0x5148146d0157c050a17828d902af80ad202a1c28d202af80ad202ad82814", + "0x157c050a01454146c8157c056c8156c14000157c05000154a146d8157c05", + "0x15b4db69851b2005b28c28da02af80ada0285828d302af80ad3028b42814", + "0x1474140a2f80a14038518005713840abe03b800a390a381bede6eb714abe", + "0x3940ebe02b900a3c0a3900abe028504014718157c056e8150e140a2f80ae1", + "0x153c14740157c05738153e14738157c057301540140a2f80ae502a8428e6", + "0x2f80ae302ad828dc02af80adc02a9428de02af80ade028a828e902af80ae8", + "0x1c28e96fb8db8de52815d2055f015d20553051be055f015be0516851c605", + "0x2f80aeb02a3828ec7581d7c05600152414750157c056e8150e140a2f80a14", + "0xb428ef02af80aea02ad828ee02af80adc02a9428ed02af80ade028a82814", + "0x5028be028500e140a3c80a1426051e2055f015d80546051e0055f015be05", + "0x2f80a14100517e055f015ac0543851ac055f015ac055b05028be02b600aa1", + "0x51ea055f015e8f303a9c28f402af80af40285828f402af80a1445851e605", + "0x35c0a2d0a3bc0abe02afc0ab60a3b80abe028000aa50a3b40abe028500a2a", + "0x157c0578bd80e280a3d80abe028504c14788157c057a8151814780157c05", + "0x2d828ee02af80aee02a9428ed02af80aed028a828f802af80af7028b028f7", + "0x3bddced52815f0055f015f00553051e0055f015e00516851de055f015de05", + "0x153c055585028be029500a470a0517c052e0148e140a2f80a1403851f0f0", + "0x5084147d0157c050a08028f902af80ad002a1c28145f01546054a05028be", + "0x157c050a09828fc02af80afb7d01d4e147d8157c057d8142c147d8157c05", + "0x5028055f014280515051fe055f015fc0516051fc055f015f8fd038a028fd", + "0x3fc0aa60a21c0abe02a1c0a2d0a3e40abe02be40ab60a33c0abe02b3c0aa5", + "0x148e140a2f80a5e029ac28145f01428070a3fd0ef9678514a057f8157c05", + "0x21c28145f01546054a05028be02a780aab0a0517c052a0148e140a2f80a95", + "0x157c05810142c14810157c050a190290102af80a141005200055f0152c05", + "0x520a055f0160704038a0290402af80a141305206055f016050103a9c2902", + "0x4000ab60a1540abe029540aa50a0500abe028500a2a0a4180abe02c140a2c", + "0x4190f002a8514a05830157c05830154c14438157c05438145a14800157c05", + "0x517c054f01556140a2f80a540291c28145f01546054a05028be028500e14", + "0x154a140a0157c050a0145414840157c054b8145814838157c05278150e14", + "0x2f80b0802a98288702af80a87028b4290702af80b0702ad8285502af80a55", + "0x153c055585028be0294c0a6b0a0517c050a01c290843c1caa14528161005", + "0x504014848157c05248150e140a2f80a4c0291c28145f01546054a05028be", + "0x157c0585c280ea70a42c0abe02c2c0a160a42c0abe02850cc14850157c05", + "0xa8290f02af80b0e028b0290e02af80b0c8681c5014868157c050a098290c", + "0x150e051685212055f01612055b05088055f01488055285028055f0142805", + "0x1556140a2f80a14038521e878491028a502c3c0abe02c3c0aa60a21c0abe", + "0x4440abe029340a2c0a4400abe02a7c0a870a0517c055181528140a2f80a9e", + "0x145a14880157c05880156c14220157c05220154a140a0157c050a0145414", + "0x5028be028500e1488a1e20440a2940b1102af80b1102a98288702af80a87", + "0x157c050a080291202af80a3a02a1c28145f01546054a05028be02a800aad", + "0x98291402af80ac48981d4e14620157c05620142c14620157c050a2242913", + "0x142805150522e055f0162c05160522c055f0162915038a0291502af80a14", + "0x21c0abe02a1c0a2d0a4480abe02c480ab60a2900abe02a900aa50a0500abe", + "0x2f80a2c02ab428145f01428070a45d0f12520514a058b8157c058b8154c14", + "0x13028c502af80b1802ad8291902af80a3902a94291802af80a3602a1c2814", + "0xb00aad0a0517c051a814d6140a2f80a142785028be028500e140a4680a14", + "0x3140abe02c6c0ab60a4640abe02a940aa50a46c0abe028a00a870a0517c05", + "0x4763807538523a055f0163a050b0523a055f01428440a4700abe028504014", + "0x157c05900145814900157c058f47c0e280a47c0abe028504c148f0157c05", + "0xb428c502af80ac502ad8291902af80b1902a94281402af80a14028a82921", + "0x517c050a01c292143b1632145281642055f0164205530510e055f0150e05", + "0x2f80a142105246055f01428200a4880abe028380a870a0517c05048148e14", + "0x524c055f01428260a4940abe02c9246075385248055f01648050b0524805", + "0x154a140a0157c050a0145414940157c05938145814938157c0592c980e28", + "0x2f80b2802a98288702af80a87028b4292202af80b2202ad828b102af80ab1", + "0x1c28ad0b2e50f29072c56c875f01d0e0503a0c292843c896214528165005", + "0x157c05070150214560157c055b0150e145b0157c055b0156c140a2f80a14", + "0x2f80a20029ec28281329c422052af80aab029fc28ab02af80a0e02a00280e", + "0x1442053a85028be028a00aab0a0517c051301528140a2f80aa702a502814", + "0x157c05108158414150157c05160158414160840ebe028840a000a0840abe", + "0x2f80aa602aac289f50284783a1ca8d48361a81868a655af80a2d02b3c282d", + "0x1548055585028be028d80aab0a0517c0503015a0140a2f80a3402a502814", + "0xf00a470a0517c051d015a0140a2f80a3902b4428145f01546055585028be", + "0x1412140a2f80a9f0291c28145f01540056085028be02a840ac10a0517c05", + "0x2f80aac02ad828b102af80ab1028b4289e02af80a9e02ae4289e02af80a35", + "0x2f80a14038508e059511084075f01d3c055885054055f0145405690515805", + "0x156c14268157c05220141c144e0157c05560150e140a2f80a4202ab42814", + "0x2b428145f01428070a05256050a130284c02af80a4d02858284902af80a9c", + "0x1d7c052a015a8142a0157c050a34c284e02af80aac02a1c28145f0148e05", + "0x20c284c02af80a4f02858284902af80a4e02ad828145f014a605558509e53", + "0x157c052a8156c140a2f80a14038512a964ba1e58984d1550ebe03ac49207", + "0x33c285c02af80a9802a00289802af80a9802a04289402af80a5502a1c2855", + "0x2ac28145f015180523850fe8040a0d1266321ad168c47248bcab5f0145405", + "0x5028be02a040ac10a0517c05418148e140a2f80a8902b4028145f014d605", + "0x2f80a7b02b5c287b02af80a6602b5828145f014fe052385028be02a000ac1", + "0x51a0cf03af80ac202b6828c202af80a0002b64280002af80a146c050ea05", + "0x1582056e85182055f015a2051b051a2055f015a0056e05028be02b3c0adb", + "0x2500abe02a500ab60a0500abe028500aa50a34c0abe02b480ade0a3480abe", + "0x295c014698157c0569815be144d0157c054d0145a14038157c05038145414", + "0x2f80a7502b00285c02af80a5c02b8428d96c35dacd452af80ad34d01d2814", + "0x3700abe02b580a870a0517c050a01c28db02cb5b4055f01db20571850ea05", + "0x1dce146f8157c056f015cc146f0157c056e815ca146e8157c056d015c814", + "0x39dcce57238d4abe029700a7f0a3000abe029300a360a385c0075f015bed4", + "0x2f80ae702aac28145f015cc054a05028be02b900ae80a0517c0571814f614", + "0x154a14748157c05321d51cc045a94bc9272ae5d414740157c050a3a42814", + "0x2f80ae802b0028d802af80ad8028b428dc02af80adc02ad828e002af80ae0", + "0x3a5c2e86c371c0b676851d2055f015d20576051c2055f015c20575851d005", + "0x150e140a2f80a1403851de05973b80abe03bb40aee0a3b5d8eb750257c05", + "0x2f80ef102bc028f002af80af002ad828f102af80aee02bbc28f002af80aeb", + "0x51e8055f015e0054385028be02afc0a6b0a0517c050a01c28f302cbd7e05", + "0x3a80aa50a3dc0abe02bd80abf0a3d80abe02bd4120778851ea055f014284e", + "0x157c05760145a146b8157c056b81454147a0157c057a0156c14750157c05", + "0x1412057a05028be028500e147bbb1aef4752940af702af80af702bcc28ec", + "0x51f4055f015f0055b051f2055f015d40552851f0055f015e0054385028be", + "0x517c050a01c281498014284c0a3f00abe02bcc0a8c0a3ec0abe02bb00a2d", + "0x151c147fbf80ebe02bbc0a920a3f40abe02bac0a870a0517c0504815e814", + "0x157c05760145a147d0157c057e8156c147c8157c05750154a140a2f80afe", + "0x2f80a0902bd028145f01428070a05260050a13028fc02af80aff02a3028fb", + "0x14c8055585028be02a480a940a0517c052f01556140a2f80a4c02aac2814", + "0x22c0aab0a0517c052e015ea140a2f80a8e02b4028145f014ea056085028be", + "0x40a02075f015b6054905200055f015ac054385028be02a940aab0a0517c05", + "0x3600a2d0a3e80abe02c000ab60a3e40abe02b500aa50a0517c05808151c14", + "0x157c057e40c0e280a40c0abe028504c147e0157c058101518147d8157c05", + "0xa828fa02af80afa02ad828f902af80af902a94290502af80b0402bd82904", + "0x35df4f9528160a055f0160a0579851f6055f015f60516851ae055f015ae05", + "0x1498055585028be028240af40a0517c055281556140a2f80a14038520afb", + "0x98290602af80a9702a1c289702af80a9702ad828145f01454057b85028be", + "0x1428055285212055f01610057b05210055f0152b07038a0290702af80a14", + "0x2580abe02a580a2d0a01c0abe0281c0a2a0a4180abe02c180ab60a0500abe", + "0x2f80aa502aac28145f01428070a4252c07830514a05848157c0584815e614", + "0x504c14850157c055c8150e145c8157c055c8156c140a2f80a0902bd02814", + "0x2f80a1402a94290d02af80b0c02bd8290c02af80aad8581c5014858157c05", + "0x502c055f0142c05168500e055f0140e051505214055f01614055b0502805", + "0x1c0e05588500e055f0140a05048521a1603c2828a502c340abe02c340af3", + "0x2f80a8702ae428b602af80a0902be028145f01428070a2940b3104a1c0ebe", + "0x2f80a142705028be028500e140a4c80a14260501c055f0156c057c8516205", + "0x501c055f0142c057c85162055f0154a055c8502c055f01572057d0517205", + "0x800b33558157c0707015f814560157c0556815401456ac40ebe02ac40afb", + "0x154e050b0514e055f01442051b05042055f01556050705028be028500e14", + "0x1558052385028be028500e141601668281301d7c07538500efd0a29c0abe", + "0x29850075f01450057f0505ab103af80ab102bec282a02af80a147485028be", + "0x1428070a0d40b35030d00ebe03a98542d13025fe14150157c05150158014", + "0xa00ebe028a00afe0a2900abe028d80b000a0d962075f01562057d85028be", + "0xe40ebe03a8d483443c04280602af80a0602ae428a402af80aa402b0028a3", + "0x513c059ba7d40075f01c7428588e412ff0a0517c050a01c28a11e01e6c3a", + "0x2f80a9f02a80284402af80a4202c08284202af80a0602a8028145f0142807", + "0x2800abe02a800aa50a1340abe02a700b040a2700abe029108e07818508e05", + "0x8028145f0140c055685028be028500e1426a800e05268157c05268160a14", + "0x2f80a4c2481d4e14260157c05260142c14260157c050a418284902af80a14", + "0x509e055f014a60583850a6055f0149c54038a0285402af80a14130509c05", + "0x30428145f01428070a13d3c070293c0abe0293c0b050a2780abe02a780aa5", + "0x5028be028a00ac10a0517c05588155a140a2f80a0602ab428145f0154205", + "0x15345503a9c289a02af80a9a02858289a02af80a1484050aa055f0142820", + "0x2540abe02a580b070a2580abe02a612e07140512e055f01428260a2600abe", + "0x5028be028500e144a8f00e054a8157c054a8160a141e0157c051e0154a14", + "0x1700abe028520c144a0157c050a08028145f01562055685028be028a00ac1", + "0x1c5014490157c050a098285e02af80a5c4a01d4e142e0157c052e0142c14", + "0x151805828506a055f0146a055285118055f0151c05838511c055f014bc92", + "0x22c0abe028509c140a2f80ab102ab428145f01428070a2306a0702a300abe", + "0x294286602af80a6402c10286402af80a6b5601e0614358157c05458161214", + "0x14d6140a2f80a1403850cc2c03814cc055f014cc058285058055f0145805", + "0x5106055f01512058485112055f014284e0a0517c05588155a140a2f80a20", + "0x160a140a0157c050a0154a14400157c05408160814408157c0541ab00f03", + "0x516c055f0154a05858514a0903af80a0902c2828800a01c0a8002af80a80", + "0x434281602af80ab902c3028b90701d7c05588500ee70a2c40abe02ad80ae6", + "0x1556058805156055f01558058785028be02ab40b0e0a2b15a075f0142c05", + "0x514e055f0154e05600514e055f01428e90a0840abe028800b110a0800abe", + "0x1c28a6168a90f38160a04c875f01c42a74381413120a0380abe028380aa5", + "0x157c05160142c141a0157c05130150e14130157c05130156c140a2f80a14", + "0xd40c075f01c580e03c4c283402af80a3402ad8282802af80a28028b4282c", + "0x51460903af80a0902c2828a402af80a3402a1c28145f01428070a0d80b39", + "0x31028a11e01d7c051d0180ee70a0e80abe028e40ae60a0e40abe02a8c0b0b", + "0x1548055b05140055f01540058a8513e3503af80a3502c5028a002af80a14", + "0x150e140a2f80a14038508e4403ce8849e03af80ea04f8f10f160a2900abe", + "0x157c050a3a4284902af80aa102c44284d02af80a4202c5c289c02af80aa4", + "0x460289e02af80a9e02a94284c02af80a4c02b00289c02af80a9c02ad8284c", + "0x149c055b05028be028500e142a93ca6879d9509c075f01c9a49260a138a5", + "0x25c0abe028240b0b0a2600abe028d40b170a2680abe029380a870a1380abe", + "0x1700abe02a500add0a2512a075f015309603a1e32144b0157c054b815cc14", + "0x154a14470157c05490163814490157c052f01636142f0157c052e0158a14", + "0x2f80a54028b4289502af80a95028a8289a02af80a9a02ad8289e02af80a9e", + "0xd40b1e0a0517c050a01c288e2a255349e528151c055f0151c058e850a805", + "0x5118055f014a60543850a6055f014a6055b05028be028240b1f0a0517c05", + "0x2780aa50a1900abe029ac0b200a1ac0abe0295516071405116055f0142826", + "0x157c05278145a14038157c05038145414460157c05460156c144f0157c05", + "0x148e058f05028be028500e143213c0e8c4f2940a6402af80a6402c74284f", + "0x2900a870a0517c055081642140a2f80a0902c7c28145f0146a058f05028be", + "0x5106055f01506050b05106055f01429220a2240abe028504014330157c05", + "0x1640143f8157c0540a000e280a2000abe028504c14408157c0541a240ea7", + "0x2f80a07028a8286602af80a6602ad8284402af80a4402a94287b02af80a7f", + "0x1c287b1401ccc4452814f6055f014f6058e85050055f0145005168500e05", + "0x5000055f01428200a1d40abe028d00a870a0517c05048163e140a2f80a14", + "0xd80aa50a33c0abe02b0800075385184055f01584050b05184055f0142923", + "0x157c05678151814608157c05140145a14688157c053a8156c14680157c05", + "0x157c05150156c140a2f80a0902c7c28145f01428070a05278050a13028d2", + "0xb428d102af80ad302ad828d002af80a0e02a9428d302af80a2a02a1c282a", + "0x15a4d4038a028d402af80a1413051a4055f0154c054605182055f0145a05", + "0x3440abe02b440ab60a3400abe02b400aa50a35c0abe02b580b200a3580abe", + "0x3414a056b8157c056b8163a14608157c05608145a14038157c05038145414", + "0x157c055b0164a14102ad58ad0b2e41cb15b2e57c055281648146bb040ed1", + "0xa10e075f0150e057f0504c055f0154e05888514e0903af80a0902c982821", + "0x156c140a2f80a140385068a616a1e7a2a1601d7c0710898500702a963014", + "0x157c050a49c283502af80ab102c94280602af80a2c02a1c282c02af80a2c", + "0x21c0ebe02a1c0afe0a28c0abe028d9480794051480903af80a0902c982836", + "0x2f80e35518e4540652c6028a302af80aa302cf8280602af80a0602ad82839", + "0x1474054385074055f01474055b05028be028500e144fa8142879f8f07407", + "0x1080ebe029080b410a11012075f01412059305084055f01429400a2780abe", + "0x2780abe02a780ab60a1350e075f0150e057f05138055f0148e4403ca02847", + "0x50a6542721e844c2481d7c07072709a3c4f29630144e0157c054e0167c14", + "0x157c050a49c284f02af80a4902a1c284902af80a4902ad828145f0142807", + "0x2d8284c02af80a4c028b4285502af80a5502d0c284202af80a4202d0c2855", + "0x517c050a01c28964b81e8a984d01d7c072a9082887a20509e055f0149e05", + "0x50b89803af80a9802d0428940481d7c05048164c144a8157c05278150e14", + "0x4f8289502af80a9502ad828924381d7c0543815fc142f0157c052e2500f28", + "0x2311c075f01d725e491312aa58c05134055f015340552850bc055f014bc05", + "0x1980abe02a380a870a2380abe02a380ab60a0517c050a01c286435a2d0f46", + "0x1980ab60a2300abe02a300a2d0a2240abe02a240b430a2240abe028524e14", + "0x21c28145f01428070a1fd0007a3a0506075f01d12984d21e8814330157c05", + "0x1e5014002040ebe02a040b410a1d412075f014120593050f6055f014cc05", + "0x3080b3e0a1ec0abe029ec0ab60a33d0e075f0150e057f05184055f0140075", + "0x21e90d16801d7c070b3099e8c3da963014418157c05418154a14610157c05", + "0x49c28d402af80ad002a1c28d002af80ad002ad828145f01428070a34da4c1", + "0x2f80ad402ad828d102af80ad1028b428d602af80ad602d0c28d602af80a14", + "0x3500a870a0517c050a01c28da6c81e92d86b81d7c076b2050687a2051a805", + "0x375b80794051bad803af80ad802d0428dc0481d7c05048164c146d8157c05", + "0x2f80ade02cf828db02af80adb02ad828df4381d7c0543815fc146f0157c05", + "0x38d8087a5385c0075f01d5ade6fb45b6a58c051ae055f015ae0552851bc05", + "0x1429270a3940abe02b800a870a3800abe02b800ab60a0517c050a01c28e4", + "0x3940abe02b940ab60a3840abe02b840a2d0a3980abe02b980b430a3980abe", + "0x2f80ae502a1c28145f01428070a3a9d207a5ba1ce075f01dccd86ba1e8814", + "0x3a00ebe02ba00b410a3b412075f014120593051d8055f0155805a6051d605", + "0x3ac0abe02bac0ab60a3c10e075f0150e057f051de055f015dced03ca028ee", + "0x1d7c07763bde0e175a963014738157c05738154a14778157c05778167c14", + "0x2f80af102a1c28f102af80af102ad828145f01428070a3d5e8f343d357ef1", + "0x2d828bf02af80abf028b428f702af80af702d0c28f702af80a1493851ec05", + "0x517c050a01c28fb7d01e9cf97c01d7c077bba1ce87a2051ec055f015ec05", + "0x50428fe0481d7c05048164c147e8157c05558169e147e0157c057b0150e14", + "0x2d829014381d7c0543815fc14800157c057fbf80f280a3fdf2075f015f205", + "0x2fdf8a58c051f0055f015f0055285200055f01600059f051f8055f015f805", + "0x4080abe02c080ab60a0517c050a01c290682c110f5081c080ebe03bf60101", + "0x40c0a2d0a4200abe02c200b430a4200abe028524e14838157c05810150e14", + "0x4321607a8c2a12075f01e10f97c21e8814838157c05838156c14818157c05", + "0x4340ab60a4380abe02c281207940521a055f0160e054385028be028500e14", + "0x4390f0386a963014848157c05848154a14870157c05870167c14868157c05", + "0x21c290f02af80b0f02ad828145f01428070a44e251143d4a210f03af80e20", + "0x2f80b1502d50291502af80b1402d4c291402af80a142705188055f0161e05", + "0x5188055f01588055b05212055f0161205528522e055f0162c05aa8522c05", + "0x517c050a01c291788312120902c5c0abe02c5c0b560a4400abe02c400a2d", + "0x16a8148c8157c0589816ae148c0157c05888150e14888157c05888156c14", + "0x2f80b1802ad8290902af80b0902a94291b02af80ac502d5428c502af80b19", + "0x500e148dc4a31090481636055f0163605ab05224055f0162405168523005", + "0x1582140a2f80a0902c8428145f01440055585028be02c300b580a0517c05", + "0x523c055f01429590a4740abe0285040148e0157c05838150e140a2f80a87", + "0x4800e280a4800abe028504c148f8157c058f4740ea70a4780abe02c780a16", + "0x2f80b1c02ad8290b02af80b0b02a94292202af80b2102d68292102af80b1f", + "0x500e149140e390b0481644055f0164405ab05206055f0160605168523805", + "0x1582140a2f80a0902c8428145f01440055585028be02be40b580a0517c05", + "0x157c0583016ae14918157c05820150e14820157c05820156c140a2f80a87", + "0x2d828f802af80af802a94292602af80b2502d54292502af80b2402d502924", + "0x41646f8048164c055f0164c05ab0520a055f0160a051685246055f0164605", + "0x2f80a2002aac28145f01556056085028be02bec0b580a0517c050a01c2926", + "0x1428200a49c0abe02bd80a870a0517c054381582140a2f80a0902c842814", + "0x5000abe02cfa5007538527c055f0167c050b0527c055f01429590a4a00abe", + "0x154a14a20157c05a1816b414a18157c05a05040e280a5040abe028504c14", + "0x2f80b4402d5828bf02af80abf028b4292702af80b2702ad828fa02af80afa", + "0x2f80a2002aac28145f01556056085028be028500e14a22fe4efa048168805", + "0x15e6055b05028be02ba00b580a0517c054381582140a2f80a0902c842814", + "0x54c0abe02d3c0b540a53c0abe02bd40b570a5300abe02bcc0a870a3cc0abe", + "0x145a14a60157c05a60156c14738157c05738154a14aa0157c05a9816aa14", + "0x56028145f01428070a551e94c738240b5402af80b5402d5828f402af80af4", + "0x5028be028240b210a0517c051001556140a2f80aab02b0428145f015d405", + "0x157c050a080295502af80ae502a1c28145f01558056805028be02a1c0ac1", + "0x98295802af80b57ab01d4e14ab8157c05ab8142c14ab8157c050a5642956", + "0x15d20552850dc055f016b405ad052b4055f016b159038a0295902af80a14", + "0x1b80abe029b80b560a3840abe02b840a2d0a5540abe02d540ab60a3a40abe", + "0x5028be028800aab0a0517c055581582140a2f80a1403850dce1aaba41205", + "0x517c056c016b0140a2f80aac02b4028145f0150e056085028be028240b21", + "0x16a814ae0157c0572016ae14ad8157c05600150e14600157c05600156c14", + "0x2f80b5b02ad828d702af80ad702a94295e02af80b5d02d54295d02af80b5c", + "0x500e14af38eb6d704816bc055f016bc05ab051c6055f015c60516852b605", + "0x1642140a2f80a2002aac28145f01556056085028be02b680b580a0517c05", + "0x21c28145f0155a055585028be02ab00ad00a0517c054381582140a2f80a09", + "0x157c05b08142c14b08157c050a564296002af80a1410052be055f015a805", + "0x52c8055f016c563038a0296302af80a1413052c4055f016c36003a9c2961", + "0x3440a2d0a57c0abe02d7c0ab60a3640abe02b640aa50a5940abe02d900b5a", + "0x1582140a2f80a1403852cad1afb641205b28157c05b2816ac14688157c05", + "0x34028145f0150e056085028be028240b210a0517c051001556140a2f80aab", + "0x3040abe02b040ab60a0517c055681556140a2f80a8102d6028145f0155805", + "0x16aa14b40157c05b3816a814b38157c0569816ae14b30157c05608150e14", + "0x2f80ad2028b4296602af80b6602ad8288302af80a8302a94296902af80b68", + "0x14fe05ac05028be028500e14b4b4acc8304816d2055f016d205ab051a405", + "0x21c0ac10a0517c050481642140a2f80a2002aac28145f01556056085028be", + "0x150e140a2f80a1602aac28145f0155a055585028be02ab00ad00a0517c05", + "0x5b00abe02db00a160a5b00abe02852b214b58157c050a080296a02af80a66", + "0x568296f02af80b6db701c5014b70157c050a098296d02af80b6cb581d4e14", + "0x15180516852d4055f016d4055b05100055f015000552852e0055f016de05", + "0x2ac0ac10a0517c050a01c2970465a9000902dc00abe02dc00b560a2300abe", + "0x15a0140a2f80a8702b0428145f01412059085028be028800aab0a0517c05", + "0x2d828145f0142c055585028be02ab40aab0a0517c054c016b0140a2f80aac", + "0x16e405aa052e4055f014c805ab852e2055f01516054385116055f0151605", + "0x5c40abe02dc40ab60a2680abe02a680aa50a5d00abe02dcc0b550a5cc0abe", + "0x2f80a1403852e86bb8a681205ba0157c05ba016ac14358157c05358145a14", + "0x1412059085028be028800aab0a0517c055581582140a2f80a9602d602814", + "0x580aab0a0517c055681556140a2f80aac02b4028145f0150e056085028be", + "0x564297602af80a1410052ea055f0149e054385028be02ae40aab0a0517c05", + "0x2f80a1413052f0055f016ef7603a9c297702af80b7702858297702af80a14", + "0x25c0abe02a5c0aa50a5ec0abe02de80b5a0a5e80abe02de2f20714052f205", + "0x25c1205bd8157c05bd816ac14260157c05260145a14ba8157c05ba8156c14", + "0x240b210a0517c051001556140a2f80aab02b0428145f01428070a5ec9975", + "0x1556140a2f80a4202d6028145f01558056805028be02a1c0ac10a0517c05", + "0x509c055f0149c055b05028be02ae40aab0a0517c050b01556140a2f80aad", + "0x5f40b550a5f40abe02df00b540a5f00abe0294c0b570a3340abe029380a87", + "0x157c052a0145a14668157c05668156c140a0157c050a0154a14bf0157c05", + "0x2f80aab02b0428145f01428070a5f8a8cd0a0240b7e02af80b7e02d582854", + "0x1558056805028be02a1c0ac10a0517c050481642140a2f80a2002aac2814", + "0x2e40aab0a0517c050b01556140a2f80aad02aac28145f0141c055585028be", + "0x6000abe02a7c0b570a5fc0abe02a840a870a2840abe02a840ab60a0517c05", + "0x156c140a0157c050a0154a14c10157c05c0816aa14c08157c05c0016a814", + "0x609417f0a0240b8202af80b8202d5828a002af80aa0028b4297f02af80b7f", + "0x517c050481642140a2f80a2002aac28145f01556056085028be028500e14", + "0x2f80aad02aac28145f0141c055585028be02ab00ad00a0517c05438158214", + "0x145a055b05028be02ac40a940a0517c055c81556140a2f80a1602aac2814", + "0x6140abe02e100b540a6100abe028d00b570a60c0abe028b40a870a0b40abe", + "0x145a14c18157c05c18156c140a0157c050a0154a14c30157c05c2816aa14", + "0x29498813a85100a55b6194d830a0240b8602af80b8602d5828a602af80aa6", + "0x21c0e050a1fd02750a2014a4c409d4288052850128703814287f409d42880", + "0x500e4c0a01f0ea504a1c0e050a22502803a8514a063220500750a2da0409", + "0xd902750a2db12094381c0a1450a0500750a2954081401d428a5c40142892", + "0x314a504a1c0e050a29902750a0254816" + ], + "sierra_program_debug_info": { + "type_names": [], + "libfunc_names": [], + "user_func_names": [] + }, + "contract_class_version": "0.1.0", + "entry_points_by_type": { + "EXTERNAL": [ + { + "selector": "0x1b1a0649752af1b28b3dc29a1556eee781e4a4c3a1f7f53f90fa834de098c4d", + "function_idx": 0 + }, + { + "selector": "0x3c513a024b5b519831b4e843b5a5413ed78c89f8136329eb8b835f82743a32e", + "function_idx": 1 + } + ], + "L1_HANDLER": [], + "CONSTRUCTOR": [] + }, + "abi": [ + { + "type": "function", + "name": "foo", + "inputs": [ + { + "name": "argument", + "type": "core::felt252" + } + ], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "struct", + "name": "core::array::Span::", + "members": [ + { + "name": "snapshot", + "type": "@core::array::Array::" + } + ] + }, + { + "type": "function", + "name": "execute_meta_tx_v0", + "inputs": [ + { + "name": "address", + "type": "core::starknet::contract_address::ContractAddress" + }, + { + "name": "entry_point_selector", + "type": "core::felt252" + }, + { + "name": "calldata", + "type": "core::array::Span::" + }, + { + "name": "signature", + "type": "core::array::Span::" + } + ], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "event", + "name": "meta_tx_test_contract::meta_tx_test_contract::MetaTxTestContract::Event", + "kind": "enum", + "variants": [] + } + ] +} diff --git a/crates/blockifier_test_utils/resources/feature_contracts/cairo1/sierra/test_contract.sierra.json b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/sierra/test_contract.sierra.json new file mode 100644 index 00000000000..6209a3b6cd7 --- /dev/null +++ b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/sierra/test_contract.sierra.json @@ -0,0 +1,10774 @@ +{ + "sierra_program": [ + "0x1", + "0x7", + "0x0", + "0x2", + "0xb", + "0x0", + "0x92e", + "0x6d2", + "0x1c5", + "0x52616e6765436865636b", + "0x800000000000000100000000000000000000000000000000", + "0x436f6e7374", + "0x800000000000000000000000000000000000000000000002", + "0x1", + "0x54", + "0x2", + "0x6e5f627974657320746f6f20626967", + "0x41", + "0x4", + "0x5", + "0x28", + "0x1000000000000000000000000000000", + "0x10000000000000000000000000000", + "0x8", + "0x9", + "0x100000000000000000000000000", + "0x1000000000000000000000000", + "0xc", + "0xd", + "0x10000000000000000000000", + "0x100000000000000000000", + "0x10", + "0x11", + "0x1000000000000000000", + "0x100000000000000", + "0x14", + "0x15", + "0x1000000000000", + "0x10000000000", + "0x18", + "0x19", + "0x1000000", + "0x10000", + "0x1c", + "0x152", + "0x100", + "0x537472756374", + "0x800000000000000f00000000000000000000000000000001", + "0x0", + "0x2ee1e2b1b89f8c495f200e4956278a4d47395fe262f27b52e5865c9524c08c3", + "0x456e756d", + "0x800000000000000700000000000000000000000000000011", + "0x14cb65c06498f4a8e9db457528e9290f453897bdb216ce18347fff8fef2cd11", + "0x1d", + "0x426f756e646564496e74", + "0x800000000000000700000000000000000000000000000002", + "0xf", + "0x3", + "0x24", + "0x27", + "0x426f78", + "0x800000000000000700000000000000000000000000000001", + "0x2a", + "0x100000000", + "0x75313238", + "0x800000000000000700000000000000000000000000000000", + "0x800000000000000700000000000000000000000000000003", + "0x25e2ca4b84968c2d8b83ef476ca8549410346b00836ce79beaf538155990bb2", + "0x29", + "0x42697477697365", + "0x556e696e697469616c697a6564", + "0x800000000000000200000000000000000000000000000001", + "0x2b", + "0x753235365f737562204f766572666c6f77", + "0x4f", + "0x5d", + "0x800000000000000000000000000000000000000000000003", + "0x34", + "0x31", + "0x33", + "0x32", + "0x483ada7726a3c4655da4fbfc0e1108a8", + "0x79be667ef9dcbbac55a06295ce870b07", + "0x29bfcdb2dce28d959f2815b16f81798", + "0xfd17b448a68554199c47d08ffb10d4b8", + "0xe", + "0xb", + "0x6", + "0x40", + "0xae", + "0x10000000000000000", + "0x4e6f6e5a65726f", + "0x16a4c8d7c05909052238a862d8cc3e7975bf05a07b3a69c6b28951083a6d672", + "0x4172726179", + "0x800000000000000300000000000000000000000000000001", + "0x800000000000000300000000000000000000000000000003", + "0x43", + "0x44", + "0x3e316790085ded77e618c7a06b4b2688f26416ea39c409a6ae51947c6668180", + "0x42", + "0x45", + "0x4c", + "0x49", + "0x4b", + "0x4a", + "0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e16", + "0x6b17d1f2e12c4247f8bce6e563a440f2", + "0x77037d812deb33a0f4a13945d898c296", + "0x2bce33576b315ececbb6406837bf51f5", + "0x800000000000000700000000000000000000000000000005", + "0x2907a9767b8e0b68c23345eea8650b1366373b598791523a07fddaa450ba526", + "0x50", + "0x53", + "0x52", + "0x496e76616c6964207369676e6174757265", + "0xffffffff00000000ffffffffffffffff", + "0xbce6faada7179e84f3b9cac2fc632551", + "0x66656c74323532", + "0x3233063c5dc6197e9bf4ddc53b925e10907665cf58255b7899f8212442d4605", + "0x55", + "0x1d8a68005db1b26d0d9f54faae1798d540e7df6326fae758cc2cf8f7ee88e72", + "0x56", + "0x536563703235366b31506f696e74", + "0x3179e7829d19e62b12c79010203ceee40c98166e97eb104c25ad1adb6b9675a", + "0x58", + "0x59", + "0x3c7b5436891664778e6019991e6bd154eeab5d43a552b1f19485dec008095d3", + "0x5a", + "0x5369676e6174757265206f7574206f662072616e6765", + "0x5f", + "0x5e", + "0xfffffffffffffffffffffffffffffffe", + "0xbaaedce6af48a03bbfd25e8cd0364141", + "0x63", + "0x14ef93a95bec47ff4e55863055b7a948870fa13be1cbddd481656bdaf5facc2", + "0x60", + "0x753332", + "0x62", + "0x7533325f6d756c204f766572666c6f77", + "0x7533325f616464204f766572666c6f77", + "0x20", + "0x85", + "0x75", + "0x800000", + "0x71", + "0x8000", + "0x6e", + "0x80", + "0x6b", + "0x80000000", + "0x76", + "0x8000000000000000", + "0x753634", + "0x4b656363616b206c61737420696e70757420776f7264203e3762", + "0x7", + "0x86", + "0x313d53fcef2616901e3fd6801087e8d55f5cb59357e1fc8b603b82ae0af064c", + "0x87", + "0x8b", + "0x38b0179dda7eba3d95708820abf10d3d4f66e97d9a9013dc38d712dce2af15", + "0x89", + "0x800000000000000700000000000000000000000000000004", + "0x3342418ef16b3e2799b906b1e4e89dbb9b111332dd44f72458ce44f9895b508", + "0x38f1b5bca324642b144da837412e9d82e31937ed4bbe21a1ebccb0c3d3d8d36", + "0x7533325f737562204f766572666c6f77", + "0x57726f6e6720456e74727920506f696e74", + "0x57726f6e675f6572726f72", + "0x76616c7565732073686f756c64206e6f74206368616e67652e", + "0x636c61737320686173682073686f756c64206e6f74206368616e67652e", + "0x746573745f73746f726167655f7661725f6368616e6765642e", + "0x311fb2a7f01403971aca6ae0a12b8ad0602e7a5ec48ad48951969942e99d788", + "0x556e6578706563746564206572726f72", + "0x454e545259504f494e545f4e4f545f464f554e44", + "0x1c4e1062ccac759d9786c18a401086aa7ab90fde340fffd5cbd792d11daa7e7", + "0x454e545259504f494e545f4641494c4544", + "0x457870656374656420726576657274", + "0x4369726375697444617461", + "0x9b", + "0x43697263756974", + "0x800000000000000800000000000000000000000000000001", + "0x9e", + "0x43697263756974496e707574416363756d756c61746f72", + "0x43697263756974496e707574", + "0x800000000000000800000000000000000000000000000002", + "0x9d", + "0x4e6f7420616c6c20696e707574732068617665206265656e2066696c6c6564", + "0x526573756c743a3a756e77726170206661696c65642e", + "0x536e617073686f74", + "0xa1", + "0x149ee8c97f9cdd259b09b6ca382e10945af23ee896a644de8c7b57da1779da7", + "0xa2", + "0x800000000000000300000000000000000000000000000004", + "0x36775737a2dc48f3b19f9a1f4bc3ab9cb367d1e2e827cef96323826fd39f53f", + "0xa4", + "0x46a6158a16a947e5916b2a2ca68501a45e93d7110e81aa2d6438b1c57c879a3", + "0x602e", + "0x206c696d62313a20302c206c696d62323a20302c206c696d62333a2030207d", + "0x6f7574707574286d756c29203d3d2075333834207b206c696d62303a20362c", + "0x679ea9c5b65e40ad9da80f5a4150d36f3b6af3e88305e2e3ae5eccbc5743d9", + "0xaa", + "0x1f", + "0x617373657274696f6e206661696c65643a20606f7574707574732e6765745f", + "0x62797465733331", + "0x5539364c696d62734c7447756172616e746565", + "0x800000000000000100000000000000000000000000000001", + "0x4d756c4d6f6447617465", + "0xb5", + "0xb4", + "0x5375624d6f6447617465", + "0xb6", + "0x496e766572736547617465", + "0xb7", + "0x4164644d6f6447617465", + "0xffffffffffffffffffffffff", + "0x35de1f6419a35f1a8c6f276f09c80570ebf482614031777c6d07679cf95b8bb", + "0xb8", + "0x436972637569744661696c75726547756172616e746565", + "0x436972637569745061727469616c4f757470757473", + "0xc8", + "0x436972637569744f757470757473", + "0xbe", + "0xc0", + "0x4369726375697444657363726970746f72", + "0x416c6c20696e707574732068617665206265656e2066696c6c6564", + "0x55393647756172616e746565", + "0x800000000000000100000000000000000000000000000005", + "0xc5", + "0xca", + "0xb2", + "0x436972637569744d6f64756c7573", + "0x4d756c4d6f64", + "0xcf", + "0x52616e6765436865636b3936", + "0xd1", + "0x4164644d6f64", + "0xd4", + "0x6d232c016ef1b12aec4b7f88cc0b3ab662be3b7dd7adbce5209fcfdbd42a504", + "0x4b5810004d9272776dec83ecc20c19353453b956e594188890b48467cb53c19", + "0x3dbce56de34e1cfe252ead5a1f14fd261d520d343ff6b7652174e62976ef44d", + "0x4563506f696e74", + "0x4fad269cbf860980e38768fe9cb6b0b9ab03ee3fe84cfde2eccce597c874fd8", + "0x654fd7e67a123dd13868093b3b7777f1ffef596c2e324f25ceaf9146698482c", + "0xdd", + "0x7538", + "0x53746f726167654261736541646472657373", + "0x3c4930bb381033105f3ca15ccded195c90cd2af5baa0e1ceb36fde292df7652", + "0xde", + "0x34482b42d8542e3c880c5c93d387fb8b01fe2a5d54b6f50d62fe82d9e6c2526", + "0x2691cb735b18f3f656c3b82bd97a32b65d15019b64117513f8604d1e06fe58b", + "0x7265637572736976655f6661696c", + "0x4469766973696f6e2062792030", + "0x32564d7e0fe091d49b4c20f4632191e4ed6986bf993849879abfef9465def25", + "0x62c83572d28cb834a3de3c1e94977a4191469a4a8c26d1d7bc55305e640ed5", + "0x3288d594b9a45d15bb2fcb7903f06cdb06b27f0ba88186ec4cfaa98307cb972", + "0xe7", + "0xa853c166304d20fb0711becf2cbdf482dee3cac4e9717d040b7a7ab1df7eec", + "0xe8", + "0xef", + "0xec", + "0xee", + "0xed", + "0x177e60492c5a8242f76f07bfe3661bd", + "0xb292a619339f6e567a305c951c0dcbcc", + "0x42d16e47f219f9e98e76e09d8770b34a", + "0xe59ec2a17ce5bd2dab2abebdf89a62e2", + "0xf5", + "0xf2", + "0xf4", + "0xf3", + "0xe3b0c44298fc1c149afbf4c8996fb924", + "0x87d9315798aaa3a5ba01775787ced05e", + "0xaaf7b4e09fc81d6d1aa546e8365d525d", + "0x27ae41e4649b934ca495991b7852b855", + "0xfa", + "0xf8", + "0xf9", + "0xfb", + "0x4aaec73635726f213fb8a9e64da3b86", + "0x6e1cda979008bfaf874ff796eb3bb1c0", + "0x32e41495a944d0045b522eba7240fad5", + "0x49288242", + "0x101", + "0xfe", + "0xff", + "0xdb0a2e6710c71ba80afeb3abdf69d306", + "0x502a43ce77c6f5c736a82f847fa95f8c", + "0x2d483fe223b12b91047d83258a958b0f", + "0xce729c7704f4ddf2eaaf0b76209fe1b0", + "0x105", + "0x104", + "0x536563703235367231506f696e74", + "0xffffffff000000010000000000000000", + "0xcb47311929e7a903ce831cb2b3e67fe265f121b394a36bc46c17cf352547fc", + "0x103", + "0x185fda19bc33857e9f1d92d61312b69416f20cf740fa3993dcc2de228a6671d", + "0x107", + "0xf83fa82126e7aeaf5fe12fff6a0f4a02d8a185bf5aaee3d10d1c4e751399b4", + "0x108", + "0x107a3e65b6e33d1b25fa00c80dfe693f414350005bc697782c25eaac141fedd", + "0x110", + "0x10d", + "0x10f", + "0x10e", + "0x4ac5e5c0c0e8a4871583cc131f35fb49", + "0x4c8e4fbc1fbb1dece52185e532812c4f", + "0x7a5f81cf3ee10044320a0d03b62d3e9a", + "0xc2b7f60e6a8b84965830658f08f7410c", + "0x114", + "0x113", + "0x100000000000000000000000000000000", + "0xe888fbb4cf9ae6254f19ba12e6d9af54", + "0x788f195a6f509ca3e934f78d7a71dd85", + "0x117", + "0x116", + "0x767410c1", + "0xbb448978bd42b984d7de5970bcaf5c43", + "0x556e657870656374656420636f6f7264696e61746573", + "0x11e", + "0x11b", + "0x11d", + "0x11c", + "0x8e182ca967f38e1bd6a49583f43f1876", + "0xf728b4fa42485e3a0a5d2f346baa9455", + "0xe3e70682c2094cac629f6fbed82c07cd", + "0x8e031ab54fc0c4a8f0dc94fad0d0611", + "0x496e76616c696420617267756d656e74", + "0x123", + "0x122", + "0x53686f756c64206265206e6f6e65", + "0xffffffffffffffffffffffffffffffff", + "0xfffffffffffffffffffffffefffffc2f", + "0x14c", + "0x61be55a8", + "0x800000000000000700000000000000000000000000000009", + "0x128", + "0x336711c2797eda3aaf8c07c5cf7b92162501924a7090b25482d45dd3a24ddce", + "0x129", + "0x536861323536537461746548616e646c65", + "0x12a", + "0x12b", + "0x324f33e2d695adb91665eafd5b62ec62f181e09c2e0e60401806dcc4bb3fa1", + "0x12c", + "0x800000000000000000000000000000000000000000000009", + "0x127", + "0x137", + "0x136", + "0x135", + "0x134", + "0x133", + "0x132", + "0x131", + "0x130", + "0x5be0cd19", + "0x1f83d9ab", + "0x9b05688c", + "0x510e527f", + "0xa54ff53a", + "0x3c6ef372", + "0xbb67ae85", + "0x6a09e667", + "0x176a53827827a9b5839f3d68f1c2ed4673066bf89e920a3d4110d3e191ce66b", + "0x138", + "0x61616161", + "0x496e646578206f7574206f6620626f756e6473", + "0x57726f6e67206572726f72206d7367", + "0x496e76616c696420696e707574206c656e677468", + "0x53686f756c64206661696c", + "0xa5963aa610cb75ba273817bce5f8c48f", + "0x57726f6e6720686173682076616c7565", + "0x587f7cc3722e9654ea3963d5fe8c0748", + "0x142", + "0x3f829a4bc463d91621ba418d447cc38c95ddc483f9ccfebae79050eb7b3dcb6", + "0x143", + "0x25e50662218619229b3f53f1dc3253192a0f68ca423d900214253db415a90b4", + "0x145", + "0x147", + "0x38b507bf259d96f5c53e8ab8f187781c3d096482729ec2d57f3366318a8502f", + "0x148", + "0x149", + "0x3c5ce4d28d473343dbe52c630edf038a582af9574306e1d609e379cd17fc87a", + "0x14a", + "0x753132385f737562204f766572666c6f77", + "0x753132385f6d756c204f766572666c6f77", + "0x753132385f616464204f766572666c6f77", + "0x553132384d756c47756172616e746565", + "0x153", + "0x424c4f434b5f494e464f5f4d49534d41544348", + "0x54585f494e464f5f4d49534d41544348", + "0x43414c4c45525f4d49534d41544348", + "0x434f4e54524143545f4d49534d41544348", + "0x53454c4543544f525f4d49534d41544348", + "0x15a", + "0x1597b831feeb60c71f259624b79cf66995ea4f7e383403583674ab9c33b9cec", + "0x15b", + "0x15c", + "0x21afb2f280564fc34ddb766bf42f7ca36154bbba994fbc0f0235cd873ace36a", + "0x15d", + "0x1baeba72e79e9db2587cf44fedb2f3700b2075a5e8e39a562584862c4b71f62", + "0x15f", + "0x160", + "0x45b67c75542d42836cef6c02cca4dbff4a80a8621fa521cbfff1b2dd4af35a", + "0x161", + "0x168", + "0x199", + "0x436f6e747261637441646472657373", + "0x800000000000000700000000000000000000000000000006", + "0x7d4d99e9ed8d285b5c61b493cedb63976bc3d9da867933d829f49ce838b5e7", + "0x164", + "0x163", + "0x165", + "0x166", + "0x80000000000000070000000000000000000000000000000e", + "0x348a62b7a38c0673e61e888d83a3ac1bf334ee7361a8514593d3d9532ed8b39", + "0x1ce0be45cbaa9547dfece0f040e22ec60de2d0d5a6c79fa5514066dfdbb7ca6", + "0x3128e9bfd21b6f544f537413d7dd38a8f2e017a3b81c1a4bcf8f51a64d0dc3d", + "0x16c", + "0x33ecdfa3f249457fb2ae8b6a6713b3069fa0c38450e972297821b52ba929029", + "0x16d", + "0x1d49f7a4b277bf7b55a2664ce8cef5d6922b5ffb806b89644b9e0cdbbcac378", + "0x16f", + "0x13fdd7105045794a99550ae1c4ac13faa62610dfab62c16422bfcf5803baa6e", + "0x170", + "0x7536345f616464204f766572666c6f77", + "0x57726f6e675f73746f726167655f76616c75652e", + "0x31448060506164e4d1df7635613bacfbea8af9c3dc85ea9a55935292a4acddc", + "0x73686f756c645f70616e6963", + "0x1e4089d1f1349077b1970f9937c904e27c4582b49a60b6078946dba95bc3c08", + "0x25ff849c52d40a7f29c9849fbe0064575d61c84ddc0ef562bf05bc599abe0ae", + "0x746573745f7265766572745f68656c706572", + "0x45635374617465", + "0xd9", + "0x3c5906a3bc4858a3fc46f5d63a29ff95f31b816586c35b221405f884cb17bc3", + "0xbe96d72eb4f94078192c2e84d5230cde2a70f4b45c8797e2c907acff5060bb", + "0x506f736569646f6e", + "0x22", + "0x45634f70", + "0x7772be8b80a8a33dc6c1f9a6ab820c02e537c73e859de67f288c70f92571bb", + "0x30395f664644a8fcaf5ade2c4222939f92c008e26373687503ba48223c8c394", + "0x187", + "0x506564657273656e", + "0x6661696c", + "0x223b876ce59fbc872ac2e1412727be9abe279bf03bb3002a29d7aeba8b23a9f", + "0x18b", + "0x4609194bf9403d809e38367adb782a43edaf535df565a1b05eea7b577c89af", + "0x18c", + "0x7820213d2079", + "0x73756363657373", + "0x2f23416cc60464d4158423619ba713070eb82b686c9d621a22c67bd37f6e0a9", + "0x537175617368656446656c7432353244696374", + "0x46656c7432353244696374", + "0x5365676d656e744172656e61", + "0x800000000000000f00000000000000000000000000000002", + "0xcc5e86243f861d2d64b08c35db21013e773ac5cf10097946fe0011304886d5", + "0x194", + "0x2271e6a0c1b1931cf78a8bfd030df986f9544c426af3bd6023dc55382237cf7", + "0x196", + "0x1d2ae7ecff8f8db67bf542f1d1f8201ff21e9f36f780ef569bcc7bc74ab634c", + "0x197", + "0x3808c701a5d13e100ab11b6c02f91f752ecae7e420d21b56c90ec0a475cc7e5", + "0x1cbd0cd3f779a7c0d3cdc804f89c39bcf71a85b43d3cf8a042111f0bc2ddf63", + "0x57524f4e475f434c4153535f48415348", + "0x909b0519d7c88c554565d942b48b326c8dcbd2e2915301868fb8159e606aa3", + "0x19d", + "0x657865637574655f616e645f726576657274", + "0xa", + "0x800000000000000f00000000000000000000000000000003", + "0x3153ad87fe24a37e12e7b17b2ed757f4e86be104f506a9fcc51c44f485a3293", + "0x1a2", + "0x436c61737348617368", + "0x4661696c656420746f20646573657269616c697a6520706172616d202334", + "0x4661696c656420746f20646573657269616c697a6520706172616d202335", + "0x4661696c656420746f20646573657269616c697a6520706172616d202336", + "0x74584e9f10ffb1a40aa5a3582e203f6758defc4a497d1a2d5a89f274a320e9", + "0x1a9", + "0x53797374656d", + "0x1ad", + "0x4661696c656420746f20646573657269616c697a6520706172616d202333", + "0x17b6ecc31946835b0d9d92c2dd7a9c14f29af0371571ae74a1b228828b2242", + "0x1b0", + "0x34f9bd7c6cb2dd4263175964ad75f1ff1461ddc332fbfb274e0fb2a5d7ab968", + "0x1b1", + "0x29d7d57c04a880978e7b3689f6218e507f3be17588744b58dc17762447ad0e7", + "0x1b3", + "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x4661696c656420746f20646573657269616c697a6520706172616d202331", + "0x4661696c656420746f20646573657269616c697a6520706172616d202332", + "0x4f7574206f6620676173", + "0x4275696c74696e436f737473", + "0x9931c641b913035ae674b400b61a51476d506bbe8bba2ff8a6272790aba9e6", + "0x1bd", + "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", + "0x53746f7261676541646472657373", + "0x11c6d8087e00642489f92d2821ad6ebd6532ad1a3b6d12833da6d6810391511", + "0x4761734275696c74696e", + "0x36c", + "0x7265766f6b655f61705f747261636b696e67", + "0x77697468647261775f676173", + "0x6272616e63685f616c69676e", + "0x72656465706f7369745f676173", + "0x7374727563745f6465636f6e737472756374", + "0x656e61626c655f61705f747261636b696e67", + "0x73746f72655f74656d70", + "0x1c4", + "0x61727261795f736e617073686f745f706f705f66726f6e74", + "0x756e626f78", + "0x72656e616d65", + "0x656e756d5f696e6974", + "0x1c3", + "0x6a756d70", + "0x7374727563745f636f6e737472756374", + "0x656e756d5f6d61746368", + "0x64697361626c655f61705f747261636b696e67", + "0x1ad5911ecb88aa4a50482c4de3232f196cfcaf7bd4e9c96d22b283733045007", + "0x64726f70", + "0x1c2", + "0x61727261795f6e6577", + "0x636f6e73745f61735f696d6d656469617465", + "0x1c1", + "0x61727261795f617070656e64", + "0x1c0", + "0x6765745f6275696c74696e5f636f737473", + "0x1bf", + "0x77697468647261775f6761735f616c6c", + "0x1be", + "0x647570", + "0x73746f726167655f77726974655f73797363616c6c", + "0x73746f726167655f726561645f73797363616c6c", + "0x736e617073686f745f74616b65", + "0x1bc", + "0x1bb", + "0x1ba", + "0x1b9", + "0x1b8", + "0x1b7", + "0x1b6", + "0x616c6c6f635f6c6f63616c", + "0x66696e616c697a655f6c6f63616c73", + "0x73746f72655f6c6f63616c", + "0x21adb5788e32c84f69a1863d85ef9394b7bf761a0ce1190f826984e5075c371", + "0x1b4", + "0x66756e6374696f6e5f63616c6c", + "0x2f", + "0x1b2", + "0x63616c6c5f636f6e74726163745f73797363616c6c", + "0x1af", + "0x1b5", + "0x1ae", + "0x1ac", + "0x30", + "0x1aa", + "0x61727261795f6c656e", + "0x7533325f746f5f66656c74323532", + "0x1a8", + "0x1a7", + "0x1a6", + "0x1ab", + "0x636c6173735f686173685f7472795f66726f6d5f66656c74323532", + "0x66656c743235325f69735f7a65726f", + "0x1a4", + "0x1a5", + "0x626f6f6c5f6e6f745f696d706c", + "0x1a3", + "0x73746f726167655f626173655f616464726573735f636f6e7374", + "0x1275130f95dda36bcbb6e9d28796c1d7e10b6e9fd5ed083e0ede4b12f613528", + "0x73746f726167655f616464726573735f66726f6d5f62617365", + "0x1a1", + "0x1a0", + "0x7536345f7472795f66726f6d5f66656c74323532", + "0x19f", + "0x19e", + "0x6765745f636c6173735f686173685f61745f73797363616c6c", + "0x636c6173735f686173685f746f5f66656c74323532", + "0x66656c743235325f737562", + "0x19c", + "0x6765745f626c6f636b5f686173685f73797363616c6c", + "0x35", + "0x19a", + "0x36", + "0x198", + "0x37", + "0x195", + "0x19b", + "0x6c6962726172795f63616c6c5f73797363616c6c", + "0x38", + "0x7265706c6163655f636c6173735f73797363616c6c", + "0x73656e645f6d6573736167655f746f5f6c315f73797363616c6c", + "0x193", + "0x66656c743235325f646963745f6e6577", + "0x192", + "0x39", + "0x191", + "0x6465706c6f795f73797363616c6c", + "0x75313238735f66726f6d5f66656c74323532", + "0x3a", + "0x190", + "0x753132385f746f5f66656c74323532", + "0x3b", + "0x3c", + "0x3d", + "0x3e", + "0x18f", + "0x18e", + "0x3f", + "0x18d", + "0x18a", + "0x636f6e74726163745f616464726573735f746f5f66656c74323532", + "0x189", + "0x188", + "0x186", + "0x185", + "0x184", + "0x183", + "0x46", + "0x47", + "0x48", + "0x182", + "0x181", + "0x7533325f62697477697365", + "0x706564657273656e", + "0x180", + "0x66656c743235325f616464", + "0x68616465735f7065726d75746174696f6e", + "0x17f", + "0x17e", + "0x65635f706f696e745f7472795f6e65775f6e7a", + "0x65635f73746174655f696e6974", + "0x17b", + "0x17d", + "0x65635f73746174655f6164645f6d756c", + "0x17c", + "0x656d69745f6576656e745f73797363616c6c", + "0x17a", + "0x179", + "0x178", + "0x626f6f6c5f746f5f66656c74323532", + "0x177", + "0x176", + "0x175", + "0x174", + "0x7536345f6571", + "0x173", + "0x7536345f6f766572666c6f77696e675f616464", + "0x172", + "0x171", + "0x16e", + "0x16b", + "0x7533325f7472795f66726f6d5f66656c74323532", + "0x6765745f657865637574696f6e5f696e666f5f76325f73797363616c6c", + "0x167", + "0x169", + "0x753132385f6571", + "0x7533325f6571", + "0x162", + "0x15e", + "0x159", + "0x158", + "0x157", + "0x156", + "0x155", + "0x16a", + "0x66656c743235325f646963745f737175617368", + "0x753132385f6f766572666c6f77696e675f737562", + "0x151", + "0x753132385f67756172616e7465655f6d756c", + "0x753132385f6d756c5f67756172616e7465655f766572696679", + "0x753132385f6f766572666c6f77696e675f616464", + "0x14f", + "0x14e", + "0x14d", + "0x154", + "0x4d", + "0x14b", + "0x4e", + "0x146", + "0x144", + "0x6b656363616b5f73797363616c6c", + "0x141", + "0x140", + "0x13f", + "0x13e", + "0x13d", + "0x13c", + "0x13b", + "0x13a", + "0x139", + "0x636f6e73745f61735f626f78", + "0x12e", + "0x7368613235365f73746174655f68616e646c655f696e6974", + "0x12d", + "0x7368613235365f73746174655f68616e646c655f646967657374", + "0x12f", + "0x126", + "0x125", + "0x124", + "0x736563703235366b315f6e65775f73797363616c6c", + "0x121", + "0x120", + "0x11f", + "0x11a", + "0x119", + "0x736563703235366b315f6765745f78795f73797363616c6c", + "0x118", + "0x115", + "0x112", + "0x66656c743235325f6d756c", + "0x111", + "0x10c", + "0x10b", + "0x10a", + "0x51", + "0x109", + "0x7365637032353672315f6e65775f73797363616c6c", + "0x106", + "0x102", + "0xfd", + "0xfc", + "0x7365637032353672315f6765745f78795f73797363616c6c", + "0xf7", + "0xf6", + "0xf1", + "0xf0", + "0xeb", + "0xea", + "0xe9", + "0xe6", + "0x7533325f6f766572666c6f77696e675f737562", + "0x61727261795f706f705f66726f6e74", + "0xe5", + "0xe4", + "0xe3", + "0xe2", + "0xe1", + "0xe0", + "0xad292db4ff05a993c318438c1b6c8a8303266af2da151aa28ccece6726f1f1", + "0xdf", + "0xdc", + "0x2679d68052ccd03a53755ca9169677965fbd93e489df62f5f40d4f03c24f7a4", + "0x62697477697365", + "0xdb", + "0xda", + "0x756e777261705f6e6f6e5f7a65726f", + "0xd8", + "0xd7", + "0x65635f706f696e745f69735f7a65726f", + "0xd6", + "0x65635f73746174655f7472795f66696e616c697a655f6e7a", + "0x65635f706f696e745f7a65726f", + "0x65635f73746174655f616464", + "0x65635f706f696e745f756e77726170", + "0x161bc82433cf4a92809836390ccd14921dfc4dc410cf3d2adbfee5e21ecfec8", + "0x61727261795f676574", + "0xce", + "0xcd", + "0xcc", + "0x7472795f696e746f5f636972637569745f6d6f64756c7573", + "0x696e69745f636972637569745f64617461", + "0xc7", + "0x696e746f5f7539365f67756172616e746565", + "0xc6", + "0xc9", + "0x6164645f636972637569745f696e707574", + "0xc4", + "0xd3", + "0xd2", + "0xd5", + "0xd0", + "0xcb", + "0xc3", + "0xc2", + "0x6765745f636972637569745f64657363726970746f72", + "0xbf", + "0xbd", + "0x6576616c5f63697263756974", + "0x6765745f636972637569745f6f7574707574", + "0x3ec1c84a1511eed894537833882a965abdddafab0d627a3ee76e01e6b57f37a", + "0x1d1238f44227bdf67f367571e4dec83368c54054d98ccf71a67381f7c51f1c4", + "0x7539365f67756172616e7465655f766572696679", + "0xb9", + "0xad", + "0xac", + "0xab", + "0xa9", + "0xa8", + "0xa7", + "0xa6", + "0xa5", + "0x7374727563745f736e617073686f745f6465636f6e737472756374", + "0xa3", + "0xbb", + "0xa0", + "0x4ef3b3bc4d34db6611aef96d643937624ebee01d56eae5bde6f3b158e32b15", + "0x9f", + "0x9c", + "0x9a", + "0x995a1546f96051a2b911879c7b314d53d580bd592e7ea51593aaec427e3c9b", + "0x99", + "0x98", + "0x61727261795f736e617073686f745f706f705f6261636b", + "0x97", + "0x96", + "0x95", + "0x94", + "0x93", + "0x92", + "0x91", + "0x90", + "0x8f", + "0x8e", + "0x61727261795f736c696365", + "0x8d", + "0x8c", + "0x8a", + "0x88", + "0x57", + "0x84", + "0x7533325f736166655f6469766d6f64", + "0x7533325f69735f7a65726f", + "0x83", + "0x82", + "0x81", + "0x7f", + "0x7e", + "0x7d", + "0x7c", + "0x7b", + "0x7a", + "0x79", + "0x78", + "0x7536345f69735f7a65726f", + "0x7536345f736166655f6469766d6f64", + "0x74", + "0x73", + "0x72", + "0x70", + "0x6f", + "0x6d", + "0x6c", + "0x6a", + "0x7533325f776964655f6d756c", + "0x646f776e63617374", + "0x7533325f6f766572666c6f77696e675f616464", + "0x69", + "0x68", + "0x67", + "0x66", + "0x65", + "0x64", + "0x61727261795f736e617073686f745f6d756c74695f706f705f66726f6e74", + "0x61", + "0x7368613235365f70726f636573735f626c6f636b5f73797363616c6c", + "0x753132385f69735f7a65726f", + "0x5c", + "0x5b", + "0x753235365f67756172616e7465655f696e765f6d6f645f6e", + "0x753531325f736166655f6469766d6f645f62795f75323536", + "0x7365637032353672315f6d756c5f73797363616c6c", + "0x7365637032353672315f6164645f73797363616c6c", + "0x757063617374", + "0x753132385f736166655f6469766d6f64", + "0x627974657333315f7472795f66726f6d5f66656c74323532", + "0x627974657333315f746f5f66656c74323532", + "0x393d13543d6033e70e218aad8050e8de40a1dfbac0e80459811df56e3716ce6", + "0x2e", + "0x736563703235366b315f6d756c5f73797363616c6c", + "0x736563703235366b315f6164645f73797363616c6c", + "0x2d", + "0x696e746f5f626f78", + "0x7370616e5f66726f6d5f7475706c65", + "0x753132385f627974655f72657665727365", + "0x25", + "0x2c", + "0x23", + "0x626f756e6465645f696e745f616464", + "0x21", + "0x656e756d5f66726f6d5f626f756e6465645f696e74", + "0x1e", + "0x1b", + "0x1a", + "0x17", + "0x16", + "0x13", + "0x12", + "0x45e8", + "0xffffffffffffffff", + "0x26", + "0x242", + "0x22d", + "0x226", + "0x215", + "0x200", + "0x1f6", + "0x1ed", + "0x1dc", + "0x1d1", + "0x209", + "0x77", + "0x236", + "0x49a", + "0x26d", + "0x274", + "0x480", + "0x474", + "0x45e", + "0x290", + "0x297", + "0x444", + "0x435", + "0x427", + "0x2ba", + "0x2c1", + "0x40d", + "0x401", + "0x3eb", + "0x2dd", + "0x2e4", + "0x3d1", + "0x3c2", + "0x3b4", + "0x315", + "0x39e", + "0x38a", + "0x37f", + "0x375", + "0xaf", + "0xb0", + "0xb1", + "0xb3", + "0xba", + "0xbc", + "0xc1", + "0x364", + "0x396", + "0x3df", + "0x41b", + "0x452", + "0x48e", + "0x562", + "0x4c2", + "0x4c9", + "0x54f", + "0x549", + "0x539", + "0x4e4", + "0x4eb", + "0x4ff", + "0x528", + "0x520", + "0x556", + "0x5c3", + "0x589", + "0x5b5", + "0x5aa", + "0x692", + "0x5e4", + "0x5eb", + "0x67f", + "0x679", + "0x600", + "0x607", + "0x665", + "0x65d", + "0x624", + "0x64c", + "0x644", + "0x66d", + "0x686", + "0x79d", + "0x6b6", + "0x6bd", + "0x788", + "0x781", + "0x770", + "0x6d9", + "0x6e0", + "0x75b", + "0x751", + "0x748", + "0x70c", + "0x737", + "0x728", + "0x72e", + "0x764", + "0x791", + "0x8e5", + "0x7c1", + "0x7c8", + "0x8d0", + "0x8c9", + "0x7de", + "0x7e5", + "0x8b4", + "0x8aa", + "0x8a1", + "0x806", + "0x80d", + "0x88c", + "0x882", + "0x879", + "0x839", + "0x868", + "0x860", + "0x895", + "0x8bd", + "0x8d9", + "0x9ce", + "0x908", + "0x90f", + "0x9bb", + "0x9b5", + "0x924", + "0x92b", + "0x9a1", + "0x999", + "0x948", + "0x988", + "0x978", + "0x96d", + "0x97f", + "0x9a9", + "0x9c2", + "0xa62", + "0x9ed", + "0x9f4", + "0xa4f", + "0xa49", + "0xa13", + "0xa3a", + "0xa2f", + "0xa56", + "0xb5b", + "0xb4a", + "0xb41", + "0xb30", + "0xb1f", + "0xb0d", + "0xafa", + "0xab8", + "0xae7", + "0xadf", + "0xc60", + "0xb80", + "0xb87", + "0xc4b", + "0xc44", + "0xc33", + "0xba3", + "0xbaa", + "0xc1e", + "0xc14", + "0xc0b", + "0xbd6", + "0xbfa", + "0xbef", + "0xc27", + "0xc54", + "0xd55", + "0xc83", + "0xc8a", + "0xd42", + "0xd3c", + "0xd2c", + "0xd1b", + "0xd09", + "0xcf6", + "0xcc6", + "0xce3", + "0xd49", + "0xde6", + "0xd76", + "0xd7d", + "0xdd3", + "0xdcd", + "0xd99", + "0xdbe", + "0xdb3", + "0xdda", + "0xeae", + "0xe9e", + "0xe0f", + "0xe16", + "0xe8a", + "0xe81", + "0xe79", + "0xe41", + "0xe69", + "0xe5e", + "0xe92", + "0xf02", + "0xed7", + "0xef3", + "0x103d", + "0xf27", + "0xf2e", + "0x1028", + "0x1021", + "0x1010", + "0xf4a", + "0xf51", + "0xffb", + "0xff1", + "0xfe8", + "0xfd6", + "0xf79", + "0xf80", + "0xf96", + "0xfc3", + "0xfb8", + "0x1004", + "0x1031", + "0x10d4", + "0x105e", + "0x1065", + "0x10c1", + "0x10b9", + "0x1084", + "0x10aa", + "0x10a2", + "0x10c8", + "0x112e", + "0x10fb", + "0x1120", + "0x1118", + "0x1188", + "0x1155", + "0x117a", + "0x1172", + "0x11e7", + "0x11b0", + "0x11d8", + "0x11cf", + "0x1242", + "0x120f", + "0x1234", + "0x122c", + "0x12d7", + "0x12c8", + "0x12b8", + "0x1279", + "0x12a8", + "0x1299", + "0x1380", + "0x12f6", + "0x12fd", + "0x136d", + "0x1365", + "0x135e", + "0x1327", + "0x134f", + "0x1347", + "0x1374", + "0x13ca", + "0x13a7", + "0x13bc", + "0x143d", + "0x142e", + "0x13f9", + "0x141f", + "0x1417", + "0x14b0", + "0x14a1", + "0x146c", + "0x1492", + "0x148a", + "0x1598", + "0x14d1", + "0x14d8", + "0x1585", + "0x157f", + "0x156f", + "0x155e", + "0x1504", + "0x154d", + "0x151b", + "0x1535", + "0x1541", + "0x158c", + "0x164b", + "0x163b", + "0x162a", + "0x1618", + "0x15d8", + "0x1606", + "0x15fd", + "0x173c", + "0x1729", + "0x1673", + "0x167a", + "0x171c", + "0x1712", + "0x168e", + "0x1695", + "0x1706", + "0x16fb", + "0x16b8", + "0x16e7", + "0x16dd", + "0x170f", + "0x1726", + "0x1724", + "0x172e", + "0x1876", + "0x175f", + "0x1766", + "0x1863", + "0x185d", + "0x184b", + "0x1781", + "0x1788", + "0x183d", + "0x1832", + "0x179c", + "0x17a3", + "0x1825", + "0x1819", + "0x17c5", + "0x1806", + "0x17fb", + "0x182f", + "0x1848", + "0x1846", + "0x1851", + "0x186a", + "0x18d5", + "0x189e", + "0x18c6", + "0x18bd", + "0x1950", + "0x1940", + "0x1906", + "0x1930", + "0x1927", + "0x19cf", + "0x19c0", + "0x1980", + "0x19b1", + "0x19a6", + "0x1a37", + "0x19f9", + "0x1a26", + "0x1a1b", + "0x1aaa", + "0x1a62", + "0x1a9b", + "0x1a8e", + "0x1a88", + "0x1a93", + "0x1bb3", + "0x1acf", + "0x1ad6", + "0x1b9e", + "0x1b97", + "0x1b86", + "0x1af2", + "0x1af9", + "0x1b71", + "0x1b67", + "0x1b5e", + "0x1b25", + "0x1b4d", + "0x1b45", + "0x1b7a", + "0x1ba7", + "0x1c18", + "0x1c09", + "0x1be4", + "0x1bfa", + "0x1c61", + "0x1c3f", + "0x1c53", + "0x1cb5", + "0x1c89", + "0x1ca6", + "0x1d08", + "0x1cde", + "0x1cf9", + "0x1d65", + "0x1d31", + "0x1d56", + "0x1dd0", + "0x1d8e", + "0x1dc1", + "0x1db2", + "0x1e4a", + "0x1e3b", + "0x1e2c", + "0x1e07", + "0x1e1d", + "0x1f10", + "0x1f01", + "0x1e72", + "0x1e79", + "0x1eee", + "0x1ee8", + "0x1ed8", + "0x1e9d", + "0x1ec8", + "0x1ebc", + "0x1ef5", + "0x1fa7", + "0x1f98", + "0x1f88", + "0x1f47", + "0x1f78", + "0x1f6c", + "0x1ffa", + "0x1fc8", + "0x1fd8", + "0x1fdf", + "0x1fee", + "0x2029", + "0x201f", + "0x2057", + "0x204d", + "0x20cd", + "0x20c0", + "0x20b4", + "0x20a8", + "0x2099", + "0x2144", + "0x2107", + "0x2139", + "0x212a", + "0x21a4", + "0x2197", + "0x2188", + "0x2176", + "0x21bd", + "0x21c2", + "0x221d", + "0x2219", + "0x21d3", + "0x21d8", + "0x220f", + "0x220a", + "0x21eb", + "0x21f0", + "0x2200", + "0x21fb", + "0x2205", + "0x2214", + "0x2221", + "0x24d3", + "0x2242", + "0x2249", + "0x24bf", + "0x24b3", + "0x225f", + "0x2266", + "0x24a0", + "0x2493", + "0x2484", + "0x2473", + "0x2460", + "0x244d", + "0x243a", + "0x22a0", + "0x22a7", + "0x2422", + "0x2414", + "0x22c6", + "0x22cd", + "0x2405", + "0x22d9", + "0x22e0", + "0x23f1", + "0x23e2", + "0x23d1", + "0x23be", + "0x2301", + "0x2308", + "0x23a7", + "0x2397", + "0x231f", + "0x2326", + "0x2380", + "0x2370", + "0x235c", + "0x2346", + "0x2390", + "0x23b7", + "0x23fe", + "0x2432", + "0x24ac", + "0x24cc", + "0x2925", + "0x251b", + "0x2537", + "0x2539", + "0x2919", + "0x290c", + "0x28df", + "0x28d2", + "0x25c7", + "0x28ec", + "0x2600", + "0x261c", + "0x28bf", + "0x261f", + "0x28ee", + "0x28b1", + "0x28a3", + "0x2895", + "0x150", + "0x26c5", + "0x26e1", + "0x2887", + "0x26e4", + "0x28f6", + "0x2714", + "0x28f8", + "0x1c6", + "0x1c7", + "0x274d", + "0x1c8", + "0x1c9", + "0x1ca", + "0x2769", + "0x1cb", + "0x1cc", + "0x1cd", + "0x1ce", + "0x1cf", + "0x2879", + "0x1d0", + "0x1d2", + "0x1d3", + "0x1d4", + "0x1d5", + "0x276c", + "0x1d6", + "0x1d7", + "0x1d8", + "0x1d9", + "0x28fa", + "0x1da", + "0x1db", + "0x1dd", + "0x1de", + "0x1df", + "0x1e0", + "0x1e1", + "0x1e2", + "0x1e3", + "0x1e4", + "0x1e5", + "0x1e6", + "0x1e7", + "0x1e8", + "0x1e9", + "0x1ea", + "0x1eb", + "0x1ec", + "0x1ee", + "0x1ef", + "0x1f0", + "0x1f1", + "0x1f2", + "0x1f3", + "0x1f4", + "0x1f5", + "0x1f7", + "0x1f8", + "0x279c", + "0x1f9", + "0x1fa", + "0x1fb", + "0x28fc", + "0x1fc", + "0x1fd", + "0x1fe", + "0x1ff", + "0x201", + "0x202", + "0x203", + "0x204", + "0x205", + "0x206", + "0x207", + "0x208", + "0x20a", + "0x20b", + "0x20c", + "0x20d", + "0x20e", + "0x20f", + "0x210", + "0x211", + "0x212", + "0x213", + "0x214", + "0x216", + "0x217", + "0x218", + "0x219", + "0x21a", + "0x27cb", + "0x21b", + "0x21c", + "0x21d", + "0x28fe", + "0x21e", + "0x21f", + "0x220", + "0x221", + "0x222", + "0x223", + "0x224", + "0x225", + "0x227", + "0x228", + "0x229", + "0x22a", + "0x22b", + "0x22c", + "0x22e", + "0x22f", + "0x230", + "0x231", + "0x232", + "0x233", + "0x234", + "0x235", + "0x237", + "0x238", + "0x239", + "0x23a", + "0x23b", + "0x23c", + "0x23d", + "0x23e", + "0x23f", + "0x240", + "0x2800", + "0x241", + "0x243", + "0x2900", + "0x244", + "0x245", + "0x246", + "0x247", + "0x248", + "0x286d", + "0x249", + "0x24a", + "0x24b", + "0x24c", + "0x24d", + "0x24e", + "0x281b", + "0x24f", + "0x250", + "0x251", + "0x252", + "0x253", + "0x285a", + "0x254", + "0x255", + "0x256", + "0x257", + "0x2849", + "0x258", + "0x259", + "0x25a", + "0x283a", + "0x25b", + "0x25c", + "0x25d", + "0x25e", + "0x25f", + "0x260", + "0x261", + "0x262", + "0x263", + "0x264", + "0x265", + "0x266", + "0x267", + "0x268", + "0x269", + "0x26a", + "0x26b", + "0x26c", + "0x26e", + "0x26f", + "0x270", + "0x271", + "0x272", + "0x273", + "0x275", + "0x276", + "0x277", + "0x278", + "0x28cc", + "0x279", + "0x27a", + "0x27b", + "0x27c", + "0x27d", + "0x28f4", + "0x27e", + "0x27f", + "0x280", + "0x28f2", + "0x281", + "0x282", + "0x283", + "0x28f0", + "0x284", + "0x285", + "0x286", + "0x287", + "0x28eb", + "0x288", + "0x289", + "0x28a", + "0x28b", + "0x28c", + "0x28d", + "0x28e", + "0x28f", + "0x291", + "0x292", + "0x293", + "0x294", + "0x295", + "0x296", + "0x298", + "0x299", + "0x2974", + "0x296a", + "0x2a0f", + "0x29ff", + "0x29f6", + "0x29e7", + "0x29df", + "0x29cf", + "0x29c1", + "0x2ae2", + "0x2ad8", + "0x2acf", + "0x2a60", + "0x2a74", + "0x2a91", + "0x2abf", + "0x2aaf", + "0x2aeb", + "0x2b45", + "0x2b3d", + "0x2b33", + "0x2b4c", + "0x2cb5", + "0x2b72", + "0x2b8d", + "0x2ca4", + "0x2c93", + "0x2c84", + "0x2c71", + "0x2c62", + "0x2bd4", + "0x2be4", + "0x2be6", + "0x2c0b", + "0x2bfd", + "0x2c19", + "0x2c51", + "0x2c49", + "0x2c58", + "0x2e26", + "0x2ce0", + "0x2cfa", + "0x2e16", + "0x2e06", + "0x2df8", + "0x2de6", + "0x2dd8", + "0x2d40", + "0x2d50", + "0x2d52", + "0x2d77", + "0x2d69", + "0x2d83", + "0x2dcc", + "0x2dbc", + "0x2db3", + "0x2f41", + "0x2f30", + "0x2f20", + "0x2f0f", + "0x2efd", + "0x2e8b", + "0x2e7a", + "0x2e6e", + "0x2ef8", + "0x2ec4", + "0x2eb3", + "0x2ea7", + "0x2ef5", + "0x2ed7", + "0x2eef", + "0x2f72", + "0x2f68", + "0x2f9d", + "0x2f93", + "0x3026", + "0x301a", + "0x3006", + "0x2ffe", + "0x3011", + "0x3032", + "0x30f3", + "0x30e8", + "0x30d2", + "0x30bc", + "0x30a8", + "0x30a0", + "0x30b2", + "0x30fe", + "0x31be", + "0x31ae", + "0x3124", + "0x313c", + "0x3136", + "0x3144", + "0x3163", + "0x314e", + "0x315e", + "0x3173", + "0x319c", + "0x3194", + "0x31a6", + "0x32b5", + "0x32a1", + "0x3296", + "0x3281", + "0x326d", + "0x3259", + "0x3251", + "0x3264", + "0x32ac", + "0x344e", + "0x32f8", + "0x3437", + "0x33f6", + "0x332f", + "0x332a", + "0x3325", + "0x3333", + "0x33e8", + "0x33dd", + "0x33d2", + "0x33c7", + "0x33bc", + "0x33aa", + "0x33b1", + "0x3427", + "0x3422", + "0x341d", + "0x342b", + "0x3474", + "0x3476", + "0x362a", + "0x361b", + "0x34b1", + "0x3609", + "0x35f6", + "0x35e4", + "0x34f4", + "0x34e3", + "0x352d", + "0x351a", + "0x3509", + "0x352c", + "0x35d2", + "0x35c1", + "0x35b5", + "0x35a8", + "0x3597", + "0x3588", + "0x357d", + "0x356e", + "0x363f", + "0x3644", + "0x3696", + "0x368d", + "0x3680", + "0x3671", + "0x3665", + "0x36d1", + "0x36b2", + "0x36c6", + "0x373f", + "0x36f1", + "0x36f8", + "0x3733", + "0x3722", + "0x3716", + "0x37dc", + "0x375e", + "0x3765", + "0x37d0", + "0x37bf", + "0x37af", + "0x3796", + "0x37b5", + "0x37a6", + "0x37b6", + "0x382c", + "0x37fb", + "0x3802", + "0x3821", + "0x3819", + "0x29a", + "0x3850", + "0x38e3", + "0x29b", + "0x38be", + "0x38b5", + "0x38ac", + "0x29c", + "0x38a3", + "0x29d", + "0x389a", + "0x29e", + "0x3891", + "0x29f", + "0x388b", + "0x2a0", + "0x2a1", + "0x2a2", + "0x2a3", + "0x3897", + "0x2a4", + "0x38a0", + "0x2a5", + "0x38a9", + "0x2a6", + "0x38b2", + "0x2a7", + "0x38bb", + "0x2a8", + "0x38c4", + "0x2a9", + "0x2aa", + "0x38d8", + "0x2ab", + "0x3927", + "0x2ac", + "0x3906", + "0x38f7", + "0x2ad", + "0x2ae", + "0x3918", + "0x2af", + "0x2b0", + "0x2b1", + "0x3945", + "0x2b2", + "0x3973", + "0x3961", + "0x3956", + "0x2b3", + "0x2b4", + "0x2b5", + "0x395d", + "0x2b6", + "0x2b7", + "0x2b8", + "0x2b9", + "0x3968", + "0x2bb", + "0x2bc", + "0x2bd", + "0x2be", + "0x39dd", + "0x2bf", + "0x39ce", + "0x39bf", + "0x2c0", + "0x2c2", + "0x2c3", + "0x39b2", + "0x2c4", + "0x39a5", + "0x3998", + "0x2c5", + "0x2c6", + "0x2c7", + "0x2c8", + "0x2c9", + "0x2ca", + "0x3a2b", + "0x2cb", + "0x2cc", + "0x39fb", + "0x2cd", + "0x2ce", + "0x2cf", + "0x3a03", + "0x2d0", + "0x2d1", + "0x3a20", + "0x2d2", + "0x2d3", + "0x3a14", + "0x2d4", + "0x2d5", + "0x2d6", + "0x2d7", + "0x2d8", + "0x2d9", + "0x2da", + "0x2db", + "0x3a5b", + "0x3a56", + "0x2dc", + "0x3a86", + "0x2de", + "0x3a60", + "0x2df", + "0x3a94", + "0x3a78", + "0x3a8e", + "0x2e0", + "0x2e1", + "0x2e2", + "0x2e3", + "0x3a9d", + "0x3aba", + "0x3ab5", + "0x3ae4", + "0x3abf", + "0x3af2", + "0x3ad7", + "0x3aec", + "0x3afb", + "0x2e5", + "0x2e6", + "0x3b51", + "0x2e7", + "0x3b40", + "0x2e8", + "0x2e9", + "0x2ea", + "0x3b36", + "0x2eb", + "0x2ec", + "0x2ed", + "0x3b29", + "0x2ee", + "0x2ef", + "0x2f0", + "0x3b78", + "0x3b73", + "0x3ba3", + "0x3b7d", + "0x2f1", + "0x3bac", + "0x3b95", + "0x3ba6", + "0x3d11", + "0x3bb5", + "0x3bd1", + "0x3bcc", + "0x3c10", + "0x3bd6", + "0x3c04", + "0x3bed", + "0x3bfb", + "0x3d08", + "0x2f2", + "0x2f3", + "0x2f4", + "0x2f5", + "0x3cf4", + "0x2f6", + "0x2f7", + "0x2f8", + "0x2f9", + "0x2fa", + "0x2fb", + "0x3ce2", + "0x3cd3", + "0x2fc", + "0x3cc5", + "0x3cb8", + "0x2fd", + "0x3cac", + "0x3ca0", + "0x3c82", + "0x3c99", + "0x3c93", + "0x2fe", + "0x2ff", + "0x300", + "0x301", + "0x3cec", + "0x302", + "0x303", + "0x304", + "0x305", + "0x306", + "0x307", + "0x3d72", + "0x3d6d", + "0x3d68", + "0x3d62", + "0x3d76", + "0x3d85", + "0x308", + "0x309", + "0x30a", + "0x30b", + "0x40b3", + "0x4037", + "0x3fd2", + "0x3fc2", + "0x3f30", + "0x3e5e", + "0x3dae", + "0x3db2", + "0x3e4a", + "0x30c", + "0x30d", + "0x3e3e", + "0x30e", + "0x30f", + "0x3e2e", + "0x3dfd", + "0x3dee", + "0x3de2", + "0x310", + "0x3e09", + "0x311", + "0x3e2b", + "0x3e20", + "0x312", + "0x3e14", + "0x313", + "0x3ed4", + "0x3e58", + "0x314", + "0x3e67", + "0x3e6b", + "0x3f1f", + "0x3f0f", + "0x3f02", + "0x3ef1", + "0x3ebe", + "0x3eaf", + "0x3ea3", + "0x3eca", + "0x3eee", + "0x3ee3", + "0x3ed7", + "0x316", + "0x3f8b", + "0x3f2a", + "0x3f38", + "0x3f3c", + "0x3fae", + "0x3f75", + "0x3f66", + "0x3f5a", + "0x3f81", + "0x3fab", + "0x3fa0", + "0x3f94", + "0x3fbc", + "0x4001", + "0x3ff5", + "0x3fec", + "0x400d", + "0x4031", + "0x4029", + "0x401d", + "0x4047", + "0x407a", + "0x406c", + "0x4061", + "0x4087", + "0x40ad", + "0x40a3", + "0x4093", + "0x40e4", + "0x317", + "0x318", + "0x40da", + "0x319", + "0x31a", + "0x31b", + "0x31c", + "0x4149", + "0x4100", + "0x4105", + "0x413f", + "0x413a", + "0x4116", + "0x411b", + "0x4130", + "0x4129", + "0x31d", + "0x31e", + "0x31f", + "0x4135", + "0x320", + "0x4144", + "0x321", + "0x322", + "0x323", + "0x418f", + "0x4184", + "0x4175", + "0x416b", + "0x417e", + "0x4199", + "0x41d6", + "0x41c9", + "0x41ba", + "0x41eb", + "0x41fa", + "0x4209", + "0x324", + "0x4218", + "0x325", + "0x4227", + "0x326", + "0x4236", + "0x327", + "0x4245", + "0x4254", + "0x328", + "0x4263", + "0x329", + "0x4272", + "0x4281", + "0x32a", + "0x4290", + "0x429f", + "0x32b", + "0x42ae", + "0x32c", + "0x42bd", + "0x42ca", + "0x32d", + "0x43ee", + "0x43e1", + "0x32e", + "0x32f", + "0x43cf", + "0x43c0", + "0x330", + "0x43ab", + "0x4319", + "0x4321", + "0x432a", + "0x4336", + "0x4393", + "0x4386", + "0x331", + "0x4379", + "0x436d", + "0x332", + "0x4362", + "0x333", + "0x334", + "0x335", + "0x336", + "0x337", + "0x439f", + "0x338", + "0x43d9", + "0x339", + "0x33a", + "0x446b", + "0x33b", + "0x33c", + "0x33d", + "0x33e", + "0x33f", + "0x340", + "0x341", + "0x342", + "0x445a", + "0x4451", + "0x4449", + "0x343", + "0x344", + "0x345", + "0x346", + "0x347", + "0x4462", + "0x348", + "0x349", + "0x4489", + "0x34a", + "0x34b", + "0x448e", + "0x34c", + "0x4498", + "0x449d", + "0x44a4", + "0x44a9", + "0x44b2", + "0x44b7", + "0x34d", + "0x34e", + "0x44c1", + "0x44c6", + "0x34f", + "0x350", + "0x351", + "0x44d0", + "0x44d3", + "0x352", + "0x353", + "0x354", + "0x4531", + "0x355", + "0x356", + "0x357", + "0x44e2", + "0x44e7", + "0x44ec", + "0x44f1", + "0x44f6", + "0x44fb", + "0x4500", + "0x4505", + "0x450a", + "0x450f", + "0x4514", + "0x4519", + "0x451e", + "0x4523", + "0x4528", + "0x358", + "0x452c", + "0x359", + "0x35a", + "0x35b", + "0x35c", + "0x35d", + "0x35e", + "0x35f", + "0x360", + "0x361", + "0x362", + "0x363", + "0x365", + "0x366", + "0x367", + "0x368", + "0x369", + "0x36a", + "0x4581", + "0x454c", + "0x4553", + "0x4575", + "0x36b", + "0x456c", + "0x45d7", + "0x45cc", + "0x45bc", + "0x45b2", + "0x45c5", + "0x45e1", + "0x4b0", + "0x571", + "0x5d2", + "0x6a1", + "0x7ae", + "0x8f6", + "0x9dd", + "0xa71", + "0xb6b", + "0xc71", + "0xd64", + "0xdf5", + "0xebe", + "0xf12", + "0x104e", + "0x10e3", + "0x113d", + "0x1197", + "0x11f7", + "0x1251", + "0x12e6", + "0x138f", + "0x13d9", + "0x144c", + "0x14bf", + "0x15a7", + "0x165b", + "0x174d", + "0x1885", + "0x18e5", + "0x1960", + "0x19de", + "0x1a49", + "0x1aba", + "0x1bc4", + "0x1c27", + "0x1c70", + "0x1cc5", + "0x1d18", + "0x1d75", + "0x1de0", + "0x1e59", + "0x1f1f", + "0x1fb6", + "0x200a", + "0x2038", + "0x2066", + "0x20db", + "0x2151", + "0x21b6", + "0x2226", + "0x24e5", + "0x293a", + "0x2982", + "0x2989", + "0x2a1e", + "0x2af3", + "0x2b52", + "0x2cc2", + "0x2e32", + "0x2f51", + "0x2f81", + "0x2fac", + "0x303b", + "0x3108", + "0x31cd", + "0x32c3", + "0x3463", + "0x347c", + "0x3638", + "0x36a0", + "0x36e1", + "0x374e", + "0x37eb", + "0x383b", + "0x3938", + "0x39ec", + "0x3a3b", + "0x3b5b", + "0x3d18", + "0x3d7a", + "0x40c4", + "0x40f3", + "0x4151", + "0x419f", + "0x41e5", + "0x42d1", + "0x43fc", + "0x4479", + "0x44d7", + "0x453c", + "0x4591", + "0x23f64", + "0x500900500400300a005009005004003008007006005004003002001000", + "0x300f00500900500400300e00700c00500400300d00700c00500400300b", + "0x500400301200700c00500400301100700c005004003010005009005004", + "0x700c00500400301500700c005004003014005009005004003013005009", + "0x301900700c005004003018005009005004003017005009005004003016", + "0x500400301c00500900500400301b00500900500400301a00700c005004", + "0x500900500400301f00500900500400301e00700c00500400301d00700c", + "0x302300500900500400302200700c00500400302100700c005004003020", + "0x502c02802b02a02902802702602500700c005004003024005009005004", + "0x502d00502d00502d00502d00502d00502d00502d00502d00502d00502d", + "0x702f02e03000702800702f02e02d00502d00502d00502d00502d00502d", + "0x703200500400300500703200500400300700702800702f02e031007028", + "0x500400303600503503403300500900500400300500702800702f02e028", + "0x503c00502902803a02600c00500c00503b02803a02603903803700700c", + "0x304300504200500400304100700600500400304000503f03e00203d03c", + "0x700c00500400304800504700503c00504400304600504500503c005044", + "0x304c00700c00500400304b00700c00500400304a00700c005004003049", + "0x500400304e00700600500400301400700600500400304d007006005004", + "0x700600500400304f00700600500400300f007006005004003010007006", + "0x3405000500900500400303100700600500400300a00700600500400300b", + "0x2600900502902802f02600c00503505305200700c005004003051005035", + "0x505a02805702a059005058005029028057026006005056055054028027", + "0x306000505f00503c00504400305e00505d00503c00504400305c00505b", + "0x500400306300700c00500400306200700c00500400306100700c005004", + "0x504200500400300c00500c00500c00500c00506602806502606400700c", + "0x306a00700600500400306900506800503c00504400303c005035053067", + "0x2600600506e02802f02603906d06c00700c00500400306b00700c005004", + "0x507302803a02a03907205c00507100507002805702a06f00502902802f", + "0x500400305c00507700507602805702a07500502902802f02602d005074", + "0x500400307b00700c00500400307a00507900503c005044003078007006", + "0x2802b02603908002d00507f00507e02803a02a07d00503503407c00700c", + "0x5081005081005081005081005081005081005081005081005081005029", + "0x3082007006005004003081005081005081005081005081005081005081", + "0x500400308400708100500400300f007081005004003083007006005004", + "0x7081005004003087007081005004003086005085005004003017007006", + "0x3022007081005004003089007081005004003088005085005004003021", + "0x500400302500708100500400308b00708100500400308a005085005004", + "0x708100500400308f00708e00500400308d00708100500400308c005085", + "0x302200708e00500400302500708e00500400308e005035053039090017", + "0x500400301e00708e00500400303700708e00500400302100708e005004", + "0x708100500400309100700600500400301a00708e00500400301d00708e", + "0x300a00708100500400300b00708100500400304f007081005004003092", + "0x2a03c005035034018007081005004003081005035053093005085005004", + "0x2602d00509800509702803a02a09600503503402d00509500509402803a", + "0x500400302d00509600509b02803a02a00c00508e00500600509a028099", + "0x700600500400309e00700600500400309d00700600500400309c007006", + "0x30a20070060050040030a10070060050040030a000700600500400309f", + "0x50040030a50070060050040030a40070060050040030a3007006005004", + "0xaa0a90050560a80920070060050040030a70070060050040030a6007006", + "0x50040030b00050290280af0260280070ab0ae0a90050560ad0ac0050ab", + "0x2802f0260b40050350b30510050560550b20070060050040030b1007006", + "0x50040030b90050350b30810050060050b40050b80280b70260b60050b5", + "0x70060050040030bc0070060050040030bb0070060050040030ba007006", + "0x500400305c0050bf0050be02805702a02d0050b90050290280570260bd", + "0xc30070070c40c30050070c40c30390c20c10070060050040030c0007081", + "0xca0c90050c60050af0c800a0070c40c30c70050c60050af0c50310070c4", + "0x260cd00702800702f02e0c90050b00050af0cc0050070ab0ae0cb0050ab", + "0x50350d30d20050560d10020d00cf0050cf0050cf0050cf0050ce028065", + "0x2e0280070d500500400300500700500702f02e0050070d40050040030d2", + "0x700600500400304f0070cf0050040030d20050350d602800702800702f", + "0x30da0050da0050da0050da0050290280d90260020d80d20050560a80d7", + "0xdd0dc0050290280af0260d20050560ad0db0050ab0aa0310070cf005004", + "0x30280070cf0050040030cf0050cf0050cf0050cf005029028065026039", + "0x503f03e0e100503f03e0020e00df00503f03e0020de0920070cf005004", + "0x30e50070060050040030e40070060050040030e300503f03e0020e20b9", + "0x30e90070060050040030e80070060050040030390e70e6007006005004", + "0x50ef02802f0260ee0050ed02802f0260390ec0390eb0050070ea005004", + "0x30f20070060050040030f10070060050040030f0007006005004003006", + "0x2803a02a0310070810050040030f40070060050040030f3007006005004", + "0x305c0050f80050f702805702a0f600502902802f02602d00502d0050f5", + "0x700c0050040030fc0050fb00503c0050440030fa0050f900503c005044", + "0x310000700c0050040030ff00700c0050040030fe00700c0050040030fd", + "0x700c00500400310400510300503c00504400310200510100503c005044", + "0x310800700c00500400310700700c00500400310600700c005004003105", + "0x700c00500400310c00510b00503c00504400310a00510900503c005044", + "0x311000700c00500400310f00700c00500400310e00700c00500400310d", + "0x700c00500400311300502500503c00504400311200511100503c005044", + "0x311700700c00500400311600700c00500400311500700c005004003114", + "0x700c00500400311b00700c00500400303911a11900511800503c005044", + "0x2802f02600600502d00511e02803a02a02d00511d00511c02803a02a0cd", + "0x503c00503c00512202809902605c00512100512002805702a11f005029", + "0x500400312600512500503c00504400312400512300503c0050440030f6", + "0x700c00500400312900700c00500400312800700c00500400312700700c", + "0x700c00500400312d00700600500400312c00512b00503c00504400312a", + "0x700c00500400313100513000503c00504400312f00700c00500400312e", + "0x513500503c00504400313400700600500400313300700c005004003132", + "0x700c00500400313900700c00500400313800513700503c005044003136", + "0x313d00700600500400313c00700c00500400313b00700c00500400313a", + "0x314100700c00500400314000700600500400313f00513e00503c005044", + "0x514300503c00504400314300502400503c00504400314200700c005004", + "0x5081005081005081005081005029028145026144007081005004003143", + "0x514702802f0261460050350b3081005056055081005081005081005081", + "0x514d00514c02805702a02d00514b00514a005029028099026039149148", + "0x515600515500515400515300515200515100515000514f00514e00305c", + "0x500400315900708100500400315800708100500400314f005035034157", + "0x708100500400315c00708100500400315b00708100500400315a007081", + "0x514600502902805702615f00708100500400315e00708100500400315d", + "0x700600500400316200708100500400305c00516100516002805702a02d", + "0x3166007006005004003165007006005004003164007006005004003163", + "0x505605516900700c00500400316800700600500400316700700c005004", + "0x2a02d00516a00502902805702616c00516b02802f02616a0050350b308e", + "0x517002802f02616f0050350b303c00505605505c00516e00516d028057", + "0x305c00517400517302805702a02d00516a0051720050290280b7026171", + "0x500400317600700600500400317500700600500400302800700c005004", + "0x2802f02600500700c00500400300700700c005004003002178177007006", + "0x317b00700600500400317a00700600500400317900503f03e00c005029", + "0x505605517e00700600500400317d00700600500400317c007006005004", + "0x518200518200502902809902618100518002802f02617f0050350b3096", + "0x2618600518502802f0260590050350b305c00518400518302805702a0f6", + "0x503503405c00518900518802805702a0f6005187005187005029028099", + "0x519100519100519000518f00518e02818d02603918c18b00503503418a", + "0x500600518700500c005191005006005194028193026192005035034006", + "0x3e18a00503f03e18700508100508100518700500c005182005006005006", + "0x2602d00517f00519602805702a02d00518200519502803a02a19100503f", + "0x519a02803a02a05c00519900519802805702a197005187005029028057", + "0x305c00519d00519c02805702a19b00518700502902803a02602d005187", + "0x2802f02619f00700600500400300500708e00500400319e007006005004", + "0x70060050040031a20070060050040031a10070060050040030ee0051a0", + "0x1a50070070060050040030180070060050040031a40070060050040031a3", + "0x30021a91a80070060050040031a70070060050040031a6005035053039", + "0x50040031aa007006005004003005007081005004003007007081005004", + "0x2600c00500c00502902803a0261ac0070060050040030021ab013007006", + "0x261b10280270261b00070060050040030021af1ae0050060051ad02803a", + "0x700600500400305c0051b40051b302805702a0060051b200502902803a", + "0x1b90060050561b805c0051790051b702805702a1b60070060050040031b5", + "0x2a05c0051bd0051bc02805702a02d0050290281bb0260021ba0060050c4", + "0x51c002805702a1bf00518700502902803a02602d00518a0051be02803a", + "0x518b0051c302803a02a19100508e00508e0051c202809902605c0051c1", + "0x2a02d00508e00502902803a0261c400700600500400318b00503f03e02d", + "0x31c700700600500400302800708e00500400305c0051c60051c5028057", + "0x51cb0051ca02805702a02d0051b20050290281c90261c8007006005004", + "0x31ce0070060050040031cd0070060050040030391cc00600503505305c", + "0x51d10051d002805702a02d0050590050290280570261cf007006005004", + "0x70060050040031d300503f03e0021d218700503f03e05900503f03e05c", + "0x2805702a1d600518700502902805702602d0050590051d502805702a1d4", + "0x503f03e02d0051da0051d902803a02a00600503503405c0051d80051d7", + "0x30280070060050040030050070060050040031db007006005004003006", + "0x50040031dd0070060050040031dc007006005004003030007006005004", + "0x2805702a0391df02800708100500400318700502902802f0261de007006", + "0x50060051e402803a02a0391e31e200700600500400305c0051e10051e0", + "0x51ed0281ec1870050051eb0281ea0281e90281e80281e71e60021e502d", + "0x71f20060050051f10060050051f00060050051ef1ee0050051ed028005", + "0x71f202d0050051f50281f41f30050051ed1860050051ed0280071f3005", + "0x1860050051f90060050051ed0281f80281f71f30050051f60050071f3005", + "0x1fd0050051fc0060050051fb0060050051f91fa0050051f91da0050051f9", + "0x51ed0050071ff0050071f205c0050051f50580050051f50060050051fe", + "0x52042030050051fc0282022010050051ed0282001ff0050051ed1d3005", + "0x51f90590050052070282060282050810050051ed1fa005005204081005", + "0x590050051ed0280071ff0050071f21e10050051f51870050051f5059005", + "0x20a0050051fc02d0050051f92090050051fc2080050051fc0810050051f9", + "0x20e0050051fc20d0050051fc20c0050051fc20b0050051fc1870050051f9", + "0x51ed0280072130050071f202821200600500521102821000600500520f", + "0x2150310052141870050051ed2130050051f60050072130050071f2213005", + "0x51fc0282171910050051f91d60050051f61d80050051eb2160050051f6", + "0x521105900500520f18700500520f1d300500520f2190050051f9218005", + "0x52141870050052111d300500521121b0050051f921a0050051f9059005", + "0x2821f00600500521e1860050052041d10050051eb21d0050051f621c031", + "0x2210050051fc2200050051fc0580050051f905c0050051eb046031005214", + "0x51ed0050070f60050071f20282250282242230050051f92220050051fc", + "0x2270050051f90f60050051f90280070f60050071f22260050051f90f6005", + "0x51f92290050051f60480310052142270050051ed1b20050051f5028228", + "0x1910050051ed1fa0050051ed22d0050051fc02822c22b00700522a1cb005", + "0x52072300050051fc08e0050051f902822f22e0050051fc047031005214", + "0x282321c60050051f92310050051f604503100521408e0050051ed08e005", + "0x51f623703100521418b00500520f0282362350050051fc028234028233", + "0x51f61c10050051eb23a0050051f623903100521418b005005211238005", + "0x51ed1b20050051f91b200500520718b0050051f918a0050051f91bf005", + "0x51f91bd0050051f923c0050051f623b03100521418a0050051ed18b005", + "0x60050052432420050051ed02824102824023f03100521402823e23d005", + "0xc0050051f90282480282472460050051f92450310052142440050051ed", + "0x521402824b1790050051eb24a0050051f624903100521400c0050051ed", + "0x51fc24f03100521424e0310052140400050051ed24d03100521424c031", + "0x51fc1b40050051eb2530050051f62520310052142510050051fc250005", + "0x28255191005005204006005005204009031005214050031005214254005", + "0x2570050051ed2570050051f51ae0050051f505b0310052142560050051ed", + "0x2570050051f92570050052071ee0050051f10280050051f1058031005214", + "0xc0050051f11ae0050051eb1ae0050051f92570050051eb257005005204", + "0x25a0050051fc05c0310052140590310052142590050051ed2580050051fc", + "0x25c0310052140df0050051ed0e30050051ed0e10050051ed25b0050051fc", + "0x2600050051fc25f0050051fc25e03100521405c0050051ed25d031005214", + "0x2670050051fc2660050051fc0282650282642630050051ed028262028261", + "0x71f226d0050051f902826c26b0050051ed26a0050051fc028269028268", + "0x71f22160050051ed0280072160050071f21d80050051f50280071d6005", + "0x2800721d0050071f21d10050051f50050072160050071f20050071d6005", + "0x26f0050051fc02826e18700500520400500721d0050071f221d0050051ed", + "0x51fc2290050051ed0280072290050071f21cb0050051f50f60050051f6", + "0x51fc2730050051fc0282722710050051fc0050072290050071f2270005", + "0x51f12750050051eb2750050051f92750050052072750050051f5274005", + "0x2780050051fc02827708e0050051f108e0050052042760050051fc0ee005", + "0x1c60050051f52310050051ed0050072310050071f227a0050051fc028279", + "0x2380050051ed0280072380050071f218b0050051f50280072310050071f2", + "0x51f619d0050051eb27b0050051f605e0310052140050072380050071f2", + "0x51eb27c0050051f606003100521417f0050051ed0960050051fb19b005", + "0x71f21820050051f517f0050051f917f0050052071970050051f6199005", + "0x2827e27d0050051f600500727d0050071f227d0050051ed02800727d005", + "0x2800723a0050071f21c10050051f50280071bf0050071f218a0050051f5", + "0x500723a0050071f20050071bf0050071f21820050051f923a0050051ed", + "0x51f02800050051ed02827f18a00500520f19100500520f02d0050051f1", + "0x520418b00500520718b0050051f018f0050051ed1920050051eb192005", + "0x51f91900050051f91910050052111900050051ed18b0050051eb18b005", + "0x520418a00500520718a00500521118a0050051f01910050051f1281005", + "0x51f605f0310052140282831870050051f102828218a0050051eb18a005", + "0x521e1820050051eb1820050052041820050051f11890050051eb284005", + "0x51f11840050051eb2850050051f605d0310052141820050051ed096005", + "0x2860050051fc23c0050051ed02800723c0050071f21bd0050051f5081005", + "0x51fc2890050051fc2880050051fc2870050051fc00500723c0050071f2", + "0x520f2460050051ed00600500528c22700500520428b0050051f928a005", + "0x17900500521128e0050051fc02828d00c0050052040240050051fc179005", + "0x24a0050051ed02800724a0050071f21790050051f502829102829002828f", + "0x51fc2930050051fc1790050051f900500724a0050071f22920050051fc", + "0x51ed03c0050051f51430050051fc03c0050051fb2950050051f9294005", + "0x51f516f0050051f916f00500520708e0050051fb03c0050051fe03c005", + "0x51eb2970050051f629603100521416a0050051ed1720050051ed172005", + "0x520716e0050051eb2990050051f62980310052141720050051f9174005", + "0x29c0050051fc03c0050051eb02829b29a0050051f516a0050051f916a005", + "0x3c0050051f929a0050051ed08e0050051fe29e0050051fc29d0050051fc", + "0x810050051fb2a20050051fc2a10050051fc2a00050051fc29f0050051fc", + "0x2a40050051f60420310052141460050051ed0810050051fe2a30050051fc", + "0x1460050051f91460050052071610050051eb0282a70280072a60050072a5", + "0x2a80050051f606703100521414b0050051ed14a0050051ed14a0050051f5", + "0x51eb14f0050051f02aa0050051ed0282a914a0050051f914d0050051eb", + "0x750050052070282ae2ad0050051fc2ac0050051fc2ab0050051fc14f005", + "0x2af0050051fc0740050051f90750050051f60750050051ed0750050051f9", + "0x3c0050052042b30050051fc2b20050051fc2b10050051fc2b00050051fc", + "0x51fc2b60050051fc1310050051fc2b50050051fc03c0050052070282b4", + "0x2bc0050051f52bb0050051fc2ba0050051fc2b90050051fc0282b82b7005", + "0x2be0050051f62bd03100521406f0050051ed2bc0050051ed06f0050051f5", + "0x51ed2c00050051f92c00050052070282bf11f0050051f61210050051eb", + "0x51fc2c20050051fc2c10050051fc11d0050051f92c00050051f62c0005", + "0x2c70050051fc2c60050051fc2c50050051fc10c0050051fc0282c42c3005", + "0x6903100521411d0050051ed2ca0050051fc2c90050051fc2c80050051fc", + "0x71f20060050052ce0282cd2cc0050051fc0f80050051f92cb0050051f6", + "0x1d30050051f12d00050051fc2cf0050051fc2530050051ed005007253005", + "0x51fc2d20050051fc2d10050051fc0280072530050071f21b40050051f5", + "0x282d52d40050051eb2d40050051f92d40050052072d40050051f52d3005", + "0xee0050052042d60050051eb2d60050051f92d60050052072d60050051f5", + "0x2db0050051fc2da0050051fc0282d90ee0050051f90282d82d70050051fc", + "0x51ed0282df1a60050052042de0050051fc2dd0050051fc1a60050052dc", + "0x51f90282e20282e126d0050051ed2e00050051fc1a60050051f91a6005", + "0x52e618f0050051f90ee0050051ed2e500700522a0282e40282e326b005", + "0x520f0e100500520f0b900500520f0e300500520f1da0050051ed006005", + "0x282ea2e90050051ed2e90050051f52e80050051fc2e70050051fc0df005", + "0x2ef0050051ed2ee0050051f50cf0050052ed2ec0050051fc0d20050052eb", + "0x2f30050051f92f20050051f92f10050051f90d20050052f02ee0050051ed", + "0x2f80050051fc2f70050051fc2f60050051f92f50050051f92f40050051f9", + "0xd40050051ed0d50050051ed2fb0050051fc2fa0050051fc0d20050052f9", + "0x52fe0df0050052110e30050052110dc0050d20050072fd0d20050052fc", + "0x52070283000da0050051ed0282ff0070070052fe0310070052fe00a007", + "0x52110680310052143010050051ed3010050051f53010050051f9301005", + "0x51ed0b90050051f53030050051fc3020050051fc0510050051fb0e1005", + "0x51fc3050050051fc0bf0050051eb3040050051f60060310052140b9005", + "0x51f90b90050052070b90050052113080050051fc3070050051fc306005", + "0x51f505100500521e0b60050052040b900500530a3090050052040b9005", + "0x51f93090050051f90b60050051f906f03100521430b0050051ed30b005", + "0xa90050052eb30f0050051fc2ef0050051f902830e30d0050051fc30c005", + "0x31200700522a3100050051f93110050051f90a90050052f03100050051ed", + "0x3170050051fc3160050051fc0060050053153140050051fc3130050051fc", + "0x31c0050051fc31b0050051fc31a0050051fc3190050051fc3180050051fc", + "0x19b0050071f200600500532031f0050051fc31e0050051fc31d0050051fc", + "0x27b0050071f227b0050051ed02800727b0050071f219d0050051f5028007", + "0x51f50280071970050071f200500719b0050071f23210050051fc005007", + "0x3220050051f607103100521427c0050051ed02800727c0050071f2199005", + "0x1890050051f500500727c0050071f20050071970050071f20960050051fe", + "0x960050051ef0050072840050071f22840050051ed0280072840050071f2", + "0x50073230050071f23230050051ed1810050051ed0280073230050071f2", + "0x960050051eb0960050052040960050051ed0960050051f03230050051f6", + "0x51f92850050051ed0280072850050071f21840050051f50960050051f9", + "0x3240050071f203c0050051ef1720050051eb0050072850050071f2181005", + "0x3240050051f60050073240050071f23240050051ed1710050051ed028007", + "0x51ed0050072970050071f232503100521403c0050051f103c0050051f0", + "0x3260050051fc08e00500521e0280072970050071f21740050051f5297005", + "0x32a0050051fc3290050051fc0850050051f90283280283270850050051ed", + "0x51ed0050072990050071f232c0050051fc08b0050051fc32b0050051fc", + "0x51fc3300050051fc32f0050051fc32e0050051fc32d0050051fc299005", + "0x52140860050051fc0283350283343330050051fc3320050051fc331005", + "0x8100500521e0280072990050071f216e0050051f53360050051fc074031", + "0x33a0050051fc3390050051fc0880050051fc3380050051fc3370050051fc", + "0x8c0050051fc33c0050051fc0850050051f133b0050051fc08a0050051fc", + "0x51fc3410050051fc02834008100508e00500733f02833e33d0050051fc", + "0x71f21610050051f53440050051fc3430050051fc075031005214342005", + "0x51fc0050072a40050071f23450050051fc2a40050051ed0280072a4005", + "0x1480050051ed0280073480050071f207d00500534714a0050051eb346005", + "0x2834907f0050051f13480050051f60050073480050071f23480050051ed", + "0x280072a80050071f214d0050051f52a80050051ed0050072a80050071f2", + "0x51f906f0050051f902834a2bc0050051eb2bc00500520414b0050051f9", + "0x500711f0050071f234b0050051fc0430050051fc0090050051f92bc005", + "0x51f60770310052142be0050051ed0280072be0050071f21210050051f5", + "0x51eb3250050051f634c0310052140740050051ed0770050051eb34c005", + "0x2bd0050051fc02800711f0050071f206f0050051eb06f005005207071005", + "0x51ed0420050052042980050051fc0670050051fc0050072be0050071f2", + "0x51fc2960050051f902834e34b03100521403c0050052dc02834d042005", + "0x280072cb0050071f20f80050051f502835002834f25d0050051fc25e005", + "0x51eb3010050052040420050051f90050072cb0050071f22cb0050051ed", + "0xbf0050051f50060050cf0050073510cf0050051f10cf0050051f9301005", + "0x51f60430310052140b90050051eb3040050051ed0280073040050071f2", + "0x51fe0283530b40050051f900c0050052dc02835205b0050051eb25c005", + "0x30b0050051eb0b90050051f10050073040050071f20590050051f1051005", + "0x51f530b0050051f90283540510050051f10510050051f00510050051ef", + "0x51fc0050073220050071f23220050051ed0280073220050071f2096005", + "0x24d0050051fc24e0050051fc08e00500c00500733f0090050051ed24f005", + "0x23b0050051fc23f0050051fc2450050051fc2490050051fc24c0050051fc", + "0x51fc2150050051fc21c0050051fc0283552370050051fc2390050051fc", + "0x34c0050071f20770050051f50280070750050071f2028358028357356005", + "0x750050071f23590050051fc00500734c0050071f234c0050051ed028007", + "0x51ed0360050051f90360050052070360050051f504000500520f005007", + "0x2835c04000500521107a03100521403600500535b03600500535a036005", + "0x71f23250050051ed0280073250050071f20710050051f535d0050051fc", + "0x1aa0050051fc0320050051ed35f0050051fc35e0050051f9005007325005", + "0x3610050073603610050051ed00c005361005007351032005032005007360", + "0x8100500733f2960050051ed2960050051f500c005084005007351032005", + "0x51fc3640050051fc3630050051f63630050051ed3630050053620c0005", + "0x51fc3690050051fc3680050051fc3670050051fc3660050051fc365005", + "0x51fc0920050051fc1c80050051fc04e0050051fc04d0050051fc030005", + "0x2800725c0050071f205b0050051f50070050051fc0310050051fc04f005", + "0x2836a07903100521400500725c0050071f20050050051fc25c0050051ed", + "0x2809204f0070cb00b00a00736b00700502800700502802836b005028028", + "0x536b00503100500a02800f00536b00500b00503102802836b005028007", + "0x500f00509202800a00536b00500a00504f02802836b00502800b028010", + "0x36b00502800702801300536904e1c800736b00701000500f02800f00536b", + "0x51c802804d00536b00504e00501002801400536b00500f005031028028", + "0x536b00501400509202801700536b00503000504e02803000536b00504d", + "0x2804d02836800536b00501700501402836900536b0051c8005013028018", + "0x2803002801b00536b00500f00503102802836b005028007028028020005", + "0x1800536b00501b00509202836700536b00501c00501702801c00536b005", + "0x36800501802836800536b00536700501402836900536b005013005013028", + "0x2802836b00502836902802836b00502800702801f0050b936600536b007", + "0x36600a00736802802000536b00502000509202802000536b005018005031", + "0x36b00502000503102802836b0050280070280230050ac36436500736b007", + "0xf02802d00536b00502d00509202836500536b00536500504f02802d005", + "0x2d00503102802836b00502800702808400531f0c036300736b007369005", + "0x36300536b0053630050130281aa00536b0050c000501002836100536b005", + "0x36300500f0281aa00536b0051aa00501b02836100536b005361005092028", + "0x36b00535f00501c02802836b00502800702835d00524e03235f00736b007", + "0x51aa00501f02802836b00536400536602802836b005032005367028028", + "0x2836502803300536b00502802002836c00536b00536100503102802836b", + "0x536b00500c03300736402800c00536b00500c00501b02800c00536b005", + "0x536302804000536b00503c03600702d02803600536b00502802302803c", + "0x536b00536c00509202836500536b00536500504f02835e00536b005040", + "0x36500a00535e00536b00535e00508402800700536b0050070050c002836c", + "0x36100503102802836b00535d00501c02802836b00502800702835e00736c", + "0x2835900536b00535900509202835600536b00502836102835900536b005", + "0x732d21c21500736b00735635936503135f02835600536b0053560051aa", + "0x1aa0051c802804700536b00521c00503102802836b005028007028048046", + "0x535d02802836b00502800b02823700536b00502803202804500536b005", + "0x504700509202823b36400736b00536400536c02823923700736b005237", + "0x2821500536b00521500504f02823900536b00523900503302804700536b", + "0x2800702824d24c24903133b24523f00736b00704523b23900704700b00c", + "0x2824e00536b00523f00503102823f00536b00523f00509202802836b005", + "0x24524e00a03c02823700536b00523700503302824e00536b00524e005092", + "0x2802836b00502800702805805b00903134405025224f03136b007364237", + "0x536b00524f00503102824f00536b00524f00509202802836b005028369", + "0x5c00736402805000536b00505000501b02805c00536b005028020028059", + "0x36b00525d00504002825e25d00736b00525c00503602825c00536b005050", + "0x535602806000536b00505e00535902805e00536b00525e00535e028028", + "0x536b00505900509202821500536b00521500504f02805f00536b005060", + "0x21500a00505f00536b00505f00508402825200536b0052520050c0028059", + "0x503102800900536b00500900509202802836b00502800702805f252059", + "0x536b00505b0050c002829600536b00505d00509202805d00536b005009", + "0x36b00502800702802808600502804d02804200536b005058005215028298", + "0x524900509202802836b00523700521c02802836b005364005366028028", + "0x2829600536b00506700509202806700536b00524900503102824900536b", + "0x36b00502836902804200536b00524d00521502829800536b00524c0050c0", + "0x536302806900536b0050422bd00702d0282bd00536b005028023028028", + "0x536b00529600509202821500536b00521500504f02806800536b005069", + "0x21500a00506800536b00506800508402829800536b0052980050c0028296", + "0x1aa00501f02802836b00536400536602802836b005028007028068298296", + "0x4602806f00536b00502802002800600536b00504800503102802836b005", + "0x36b00507106f00736402807100536b00507100501b02807100536b005028", + "0x36302807500536b00532507400702d02807400536b005028023028325005", + "0x36b00500600509202804600536b00504600504f02807700536b005075005", + "0xa00507700536b00507700508402800700536b0050070050c0028006005", + "0x536602802836b00508400501c02802836b005028007028077007006046", + "0x2834b00536b00502802002834c00536b00502d00503102802836b005364", + "0x504334b00736402804300536b00504300501b02804300536b005028048", + "0x2807f00536b00507a07900702d02807900536b00502802302807a00536b", + "0x534c00509202836500536b00536500504f02834800536b00507f005363", + "0x534800536b00534800508402800700536b0050070050c002834c00536b", + "0x3102802836b00536900501c02802836b00502800702834800734c36500a", + "0x36b00508100509202807d00536b00502300504f02808100536b005020005", + "0x2836b00502836902802836b00502800702802830400502804d028346005", + "0x36b00501800503102802836b00536900501c02802836b00501f005047028", + "0x2002834600536b00534500509202807d00536b00500a00504f028345005", + "0x34300536b00534300501b02834300536b00502804502834400536b005028", + "0x34100702d02834100536b00502802302834200536b005343344007364028", + "0x536b00507d00504f02808c00536b00533d00536302833d00536b005342", + "0x508402800700536b0050070050c002834600536b00534600509202807d", + "0x523702802836b00502800702808c00734607d00a00508c00536b00508c", + "0x2833b00536b00502802002833c00536b00509200503102802836b005031", + "0x508a33b00736402808a00536b00508a00501b02808a00536b005028046", + "0x2808800536b00533a33900702d02833900536b00502802302833a00536b", + "0x533c00509202804f00536b00504f00504f02833800536b005088005363", + "0x533800536b00533800508402800700536b0050070050c002833c00536b", + "0xa00736b00700502800700502802836b00502802802833800733c04f00a", + "0x2800f00536b00500b00503102802836b00502800702809204f00729f00b", + "0x500f00509202800a00536b00500a00504f02801000536b00503100500a", + "0x36b0050280070280130050ee04e1c800736b00701000500f02800f00536b", + "0x500f00503102802836b00504e00536702802836b0051c800501c028028", + "0x501b02803000536b00502836502804d00536b00502802002801400536b", + "0x536b00502802302801700536b00503004d00736402803000536b005030", + "0x4f02836800536b00536900536302836900536b00501701800702d028018", + "0x36b0050070050c002801400536b00501400509202800a00536b00500a005", + "0x502800702836800701400a00a00536800536b005368005084028007005", + "0x2836102801b00536b00500f00503102802836b00501300501c02802836b", + "0x1c00536b00501c0051aa02801b00536b00501b00509202801c00536b005", + "0x36b00502800702802001f00715736636700736b00701c01b00a03135f028", + "0x36400501b02836400536b00502823902836500536b005366005031028028", + "0x736b00736436700736802836500536b00536500509202836400536b005", + "0x280c000536b00536500503102802836b00502800702836300513502d023", + "0x736b00508400535d02836100536b00502823b02808400536b005028032", + "0x280c000536b0050c000509202835f02d00736b00502d00536c0281aa084", + "0x502300504f02836100536b00536100501b0281aa00536b0051aa005033", + "0x3336c03112b35d03200736b00736135f1aa0070c000b00c02802300536b", + "0x503200503102803200536b00503200509202802836b00502800702800c", + "0x3302803c00536b00503c00509202803600536b00502823f02803c00536b", + "0x8435d03c00b00c02803600536b00503600501b02808400536b005084005", + "0x9202802836b0050280070282153563590312ba35e04000736b00703602d", + "0x536b00502802002821c00536b00504000503102804000536b005040005", + "0x535e02802836b00504800504002804704800736b005046005036028046", + "0x536b00523700535602823700536b00504500535902804500536b005047", + "0x50c002821c00536b00521c00509202802300536b00502300504f028239", + "0x2823935e21c02300a00523900536b00523900508402835e00536b00535e", + "0x536b00535900503102835900536b00535900509202802836b005028007", + "0x50c002824500536b00523b00509202823f00536b00502300504f02823b", + "0x2802814600502804d02824c00536b00521500521502824900536b005356", + "0x2802836b00502d00536602802836b00508400521c02802836b005028007", + "0x502300504f02824d00536b00536c00503102836c00536b00536c005092", + "0x2824900536b0050330050c002824500536b00524d00509202823f00536b", + "0x2802836b00502800702802814600502804d02824c00536b00500c005215", + "0x536b00502824502824f00536b00502802002824e00536b005365005031", + "0x4f02805000536b00525224f00736402825200536b00525200501b028252", + "0x36b0050070050c002824500536b00524e00509202823f00536b005363005", + "0x702d02800900536b00502802302824c00536b005050005215028249005", + "0x36b00523f00504f02805800536b00505b00536302805b00536b00524c009", + "0x8402824900536b0052490050c002824500536b00524500509202823f005", + "0x3102802836b00502800702805824924523f00a00505800536b005058005", + "0x25c00536b00502804602805c00536b00502802002805900536b005020005", + "0x2802302825d00536b00525c05c00736402825c00536b00525c00501b028", + "0x536b00505e00536302805e00536b00525d25e00702d02825e00536b005", + "0x50c002805900536b00505900509202801f00536b00501f00504f028060", + "0x2806000705901f00a00506000536b00506000508402800700536b005007", + "0x5f00536b00509200503102802836b00503100523702802836b005028007", + "0x36b00529600501b02829600536b00502804602805d00536b005028020028", + "0x2d02804200536b00502802302829800536b00529605d007364028296005", + "0x504f00504f0282bd00536b00506700536302806700536b005298042007", + "0x2800700536b0050070050c002805f00536b00505f00509202804f00536b", + "0xb00536b0050282490282bd00705f04f00a0052bd00536b0052bd005084", + "0x2802836b00502802802802836b00502824c02809200536b005028249028", + "0x2802836b00502800702804e1c800736d01000f00736b007005028007005", + "0x36b00502800b02801400536b00503100500a02801300536b005010005031", + "0x500f02801300536b00501300509202800f00536b00500f00504f028028", + "0x501300503102802836b00502800702801700528403004d00736b007014", + "0x2836800536b0053690051c802836900536b00503000501002801800536b", + "0x504d00501302801c00536b00501800509202801b00536b00536800504e", + "0x2800702802828100502804d02836600536b00501b00501402836700536b", + "0x1702802000536b00502803002801f00536b00501300503102802836b005", + "0x36b00501700501302801c00536b00501f00509202836500536b005020005", + "0x536e04f00536b00736600501802836600536b005365005014028367005", + "0x536b00501c00503102802836b00502836902802836b005028007028364", + "0x24e02802300536b00502300509202804f00536b00504f09200724d028023", + "0x503102802836b0050280070280c000536f36302d00736b00704f00f007", + "0x536b00508400509202802d00536b00502d00504f02808400536b005023", + "0x2802836b00502800702835f0053701aa36100736b00736700500f028084", + "0xa00b00724d02800a00536b0051aa00501002803200536b005084005031", + "0x1302802836b00502800b02835d00536b00500a0051c802800a00536b005", + "0x36b00736100500f02803200536b00503200509202836100536b005361005", + "0x3c00536b00503200503102802836b00502800702800c00525903336c007", + "0x36c00501302804000536b00503c00509202803600536b00503300524f028", + "0x70280281b400502804d02835900536b00503600525202835e00536b005", + "0x2821500536b00502803002835600536b00503200503102802836b005028", + "0x500c00501302804000536b00535600509202821c00536b005215005050", + "0x37104600536b00735900500902835900536b00521c00525202835e00536b", + "0x36b00504000503102802836b00502836902802836b005028007028048005", + "0x535e02823700536b00502802002804500536b005046005010028047005", + "0x536b00502d00504f02823b00536b0050450051c802823900536b00535e", + "0x521502823900536b00523900505b02804700536b00504700509202802d", + "0x23723904702d00b05802823b00536b00523b00501b02823700536b005237", + "0x702824d00537224c00536b00724900505902824924523f03136b00523b", + "0x24f00736b00524c00505c02824e00536b00524500503102802836b005028", + "0x900537305000536b00725200525c02824e00536b00524e005092028252", + "0x36b00524f00500a02805b00536b00524e00503102802836b005028007028", + "0x20c05c05900736b00705800500f02805b00536b00505b005092028058005", + "0x505c00536702802836b00505900501c02802836b00502800702825c005", + "0x36300525d02802836b00535d00501f02802836b00505000504002802836b", + "0x36502825e00536b00502802002825d00536b00505b00503102802836b005", + "0x36b00505e25e00736402805e00536b00505e00501b02805e00536b005028", + "0x36302805d00536b00506005f00702d02805f00536b005028023028060005", + "0x36b00525d00509202823f00536b00523f00504f02829600536b00505d005", + "0xa00529600536b00529600508402800700536b0050070050c002825d005", + "0x503102802836b00525c00501c02802836b00502800702829600725d23f", + "0x29800536b00529800509202804200536b00502836102829800536b00505b", + "0x3742bd06700736b00704229823f03135f02804200536b0050420051aa028", + "0x503602800600536b0052bd00503102802836b005028007028068069007", + "0x536b00507100535e02802836b00506f00504002807106f00736b005050", + "0xb25e02806700536b00506700504f02800600536b005006005092028325", + "0x502800702804334b34c03137507707507403136b00732535d363007006", + "0x35902807a00536b00507400503102807400536b00507400509202802836b", + "0x36b00506700504f02807f00536b00507900535602807900536b005077005", + "0x8402807500536b0050750050c002807a00536b00507a005092028067005", + "0x9202802836b00502800702807f07507a06700a00507f00536b00507f005", + "0x536b00502802302834800536b00534c00503102834c00536b00534c005", + "0x4f02834600536b00507d00536302807d00536b00504308100702d028081", + "0x36b00534b0050c002834800536b00534800509202806700536b005067005", + "0x502800702834634b34806700a00534600536b00534600508402834b005", + "0x36300525d02802836b00535d00501f02802836b00505000504002802836b", + "0x4602834400536b00502802002834500536b00506800503102802836b005", + "0x36b00534334400736402834300536b00534300501b02834300536b005028", + "0x36302833d00536b00534234100702d02834100536b005028023028342005", + "0x36b00534500509202806900536b00506900504f02808c00536b00533d005", + "0xa00508c00536b00508c00508402800700536b0050070050c0028345005", + "0x523702802836b00500900504702802836b00502800702808c007345069", + "0x3102802836b00536300525d02802836b00535d00501f02802836b00524f", + "0x36b00533c00509202833b00536b00523f00504f02833c00536b00524e005", + "0x36b00536300525d02802836b00502800702802837600502804d02808a005", + "0x24d00536302833a00536b00524500503102802836b00535d00501f028028", + "0x33a00536b00533a00509202823f00536b00523f00504f02833900536b005", + "0x33a23f00a00533900536b00533900508402800700536b0050070050c0028", + "0x36b00504800504702802836b00502836902802836b005028007028339007", + "0x535e00501c02802836b00536300525d02802836b00535d00501f028028", + "0x9202833b00536b00502d00504f02808800536b00504000503102802836b", + "0x33700536b00502805e02833800536b00502802002808a00536b005088005", + "0x2802302833600536b00533733800736402833700536b00533700501b028", + "0x536b00508e00536302808e00536b00533608600702d02808600536b005", + "0x50c002808a00536b00508a00509202833b00536b00533b00504f028377", + "0x2837700708a33b00a00537700536b00537700508402800700536b005007", + "0x2802836b00536300525d02802836b00535f00501c02802836b005028007", + "0x536b00502802002833300536b00508400503102802836b00500b005060", + "0x33200736402833100536b00533100501b02833100536b005028048028332", + "0x536b00533032f00702d02832f00536b00502802302833000536b005331", + "0x509202802d00536b00502d00504f02832d00536b00532e00536302832e", + "0x536b00532d00508402800700536b0050070050c002833300536b005333", + "0x2836b00536700501c02802836b00502800702832d00733302d00a00532d", + "0x50c000504f02832c00536b00502300503102802836b00500b005060028", + "0x2800702802837800502804d02832b00536b00532c00509202808b00536b", + "0x36700501c02802836b00536400504702802836b00502836902802836b005", + "0x503102802836b00509200506002802836b00500b00506002802836b005", + "0x536b00532a00509202808b00536b00500f00504f02832a00536b00501c", + "0x532600501b02832600536b00502804502832900536b00502802002832b", + "0x2809300536b00502802302808500536b00532632900736402832600536b", + "0x8b00504f02832400536b00509500536302809500536b00508509300702d", + "0x700536b0050070050c002832b00536b00532b00509202808b00536b005", + "0x2836b00502800702832400732b08b00a00532400536b005324005084028", + "0x36b00503100523702802836b00500b00506002802836b005092005060028", + "0x502804602832300536b00502802002809800536b00504e005031028028", + "0x32200536b00509632300736402809600536b00509600501b02809600536b", + "0x31f00536302831f00536b00532232100702d02832100536b005028023028", + "0x9800536b0050980050920281c800536b0051c800504f02831e00536b005", + "0x981c800a00531e00536b00531e00508402800700536b0050070050c0028", + "0x502829602809200536b00502805d02800b00536b00502805f02831e007", + "0x2824902801400536b00502824902804e00536b00502824902801000536b", + "0x2802802802836b00502824c02801800536b00502824902803000536b005", + "0x2800702801c01b00737936836900736b00700502800700502802836b005", + "0x2836600536b00503100500a02836700536b00536800503102802836b005", + "0x536b00536700509202836900536b00536900504f02802836b00502800b", + "0x2802836b00502800702836500537a02001f00736b00736600500f028367", + "0x50230051c802802300536b00502000501002836400536b005367005031", + "0x280c000536b00536400509202836300536b00502d00504e02802d00536b", + "0x37b00502804d02836100536b00536300501402808400536b00501f005013", + "0x36b0050280300281aa00536b00536700503102802836b005028007028028", + "0x130280c000536b0051aa00509202803200536b00535f00501702835f005", + "0x36b00736100501802836100536b00503200501402808400536b005365005", + "0x503102802836b00502836902802836b00502800702835d00537c1c8005", + "0x36b00536c0050920281c800536b0051c804e00724d02836c00536b0050c0", + "0x36b00502800702803c00537d00c03300736b0071c836900724e02836c005", + "0x509202803300536b00503300504f02803600536b00536c005031028028", + "0x2800702835900537e35e04000736b00708400500f02803600536b005036", + "0x2804d00536b00535e00501002835600536b00503600503102802836b005", + "0x502800b02821500536b00504d0051c802804d00536b00504d03000724d", + "0xf02835600536b00535600509202804000536b00504000501302802836b", + "0x35600503102802836b00502800702804800537f04621c00736b007040005", + "0x23700536b00504700509202804500536b00504600524f02804700536b005", + "0x502804d02823b00536b00504500525202823900536b00521c005013028", + "0x502803002823f00536b00535600503102802836b005028007028028380", + "0x2823700536b00523f00509202824900536b00524500505002824500536b", + "0x723b00500902823b00536b00524900525202823900536b005048005013", + "0x24e00536b00523700503102802836b00502800702824d00538124c00536b", + "0x523900535e02825200536b00502802002824f00536b00524c005010028", + "0x2803300536b00503300504f02800900536b00524f0051c802805000536b", + "0x525200521502805000536b00505000505b02824e00536b00524e005092", + "0x500925205024e03300b05802800900536b00500900501b02825200536b", + "0x502800702825c00538205c00536b00705900505902805905805b03136b", + "0x2805e25e00736b00505c00505c02825d00536b00505800503102802836b", + "0x702806000538300f00536b00705e00525c02825d00536b00525d005092", + "0x5d00536b00525e00500a02805f00536b00525d00503102802836b005028", + "0x505f00509202800f00536b00500f01000729802802836b00502800b028", + "0x36b00502800702804200538429829600736b00705d00500f02805f00536b", + "0x51c80282bd00536b00529800501002806700536b00505f005031028028", + "0x536b00506700509202806800536b00506900504e02806900536b0052bd", + "0x2804d02807100536b00506800501402806f00536b005296005013028006", + "0x2803002832500536b00505f00503102802836b005028007028028385005", + "0x600536b00532500509202807500536b00507400501702807400536b005", + "0x7100501802807100536b00507500501402806f00536b005042005013028", + "0x2802836b00502836902802836b00502800702807700538601300536b007", + "0x34c00509202801300536b00501301400724d02834c00536b005006005031", + "0x2800702807a00538704334b00736b00701305b00724e02834c00536b005", + "0x2834b00536b00534b00504f02807900536b00534c00503102802836b005", + "0x2808100538834807f00736b00706f00500f02807900536b005079005092", + "0x536b00534800501002807d00536b00507900503102802836b005028007", + "0xb02834600536b0050170051c802801700536b00501701800724d028017", + "0x7d00536b00507d00509202807f00536b00507f00501302802836b005028", + "0x3102802836b00502800702834300538934434500736b00707f00500f028", + "0x36b00534200509202834100536b00534400524f02834200536b00507d005", + "0x4d02833c00536b00534100525202808c00536b00534500501302833d005", + "0x3002833b00536b00507d00503102802836b00502800702802838a005028", + "0x536b00533b00509202833a00536b00508a00505002808a00536b005028", + "0x500902833c00536b00533a00525202808c00536b00534300501302833d", + "0x2836b00502836902802836b00502800702808800538b33900536b00733c", + "0x502802002833700536b00533900501002833800536b00533d005031028", + "0x2808e00536b0053370051c802808600536b00508c00535e02833600536b", + "0x508600505b02833800536b00533800509202834b00536b00534b00504f", + "0x2808e00536b00508e00501b02833600536b00533600521502808600536b", + "0x536b00733200505902833233337703136b00508e33608633834b00b058", + "0x5c02832f00536b00533300503102802836b00502800702833000538c331", + "0x732d00525c02832f00536b00532f00509202832d32e00736b005331005", + "0x32b00536b00532f00503102802836b00502800702808b00538d32c00536b", + "0x32a00500f02832b00536b00532b00509202832a00536b00532e00500a028", + "0x36b00532900501c02802836b00502800702808500538e32632900736b007", + "0x500b00504202802836b00504300525d02802836b005326005367028028", + "0x34600501f02802836b00532c00504002802836b00509200506702802836b", + "0x525d02802836b00521500501f02802836b00500f00504002802836b005", + "0x2809500536b00502802002809300536b00532b00503102802836b00500c", + "0x532409500736402832400536b00532400501b02832400536b005028365", + "0x2809600536b00509832300702d02832300536b00502802302809800536b", + "0x509300509202837700536b00537700504f02832200536b005096005363", + "0x532200536b00532200508402800700536b0050070050c002809300536b", + "0x3102802836b00508500501c02802836b00502800702832200709337700a", + "0x536b00532100509202831f00536b00502836102832100536b00532b005", + "0x31d31e00736b00731f32137703135f02831f00536b00531f0051aa028321", + "0x3602831a00536b00531d00503102802836b00502800702831b31c00738f", + "0x36b00531800535e02802836b00531900504002831831900736b00500f005", + "0x25e02831e00536b00531e00504f02831a00536b00531a005092028317005", + "0x280070283100a931103139031331431603136b00731721500c00731a00b", + "0x280b000536b00531600503102831600536b00531600509202802836b005", + "0x530f00535e02802836b0050ac00504002830f0ac00736b00532c005036", + "0x2831300536b00531300505b0280b000536b0050b000509202830d00536b", + "0x70280b930b0b603139104f00a0b403136b00730d3460433140b000b25e", + "0x30900536b0050b40050310280b400536b0050b400509202802836b005028", + "0x530900509202831e00536b00531e00504f02830800536b005028020028", + "0x2831300536b00531300505b02830800536b00530800521502830900536b", + "0xa06802804f00536b00504f09200706902800a00536b00500a00b0072bd", + "0x53920bf00536b00730500500602830530630703136b00531330830931e", + "0x50bf00506f02830300536b00530600503102802836b005028007028304", + "0x2830700536b00530700504f02802836b00505100504702805130200736b", + "0x504f00505b02830200536b00530200521502830300536b005303005092", + "0x39500500602839539439303136b00504f30230330700a06802804f00536b", + "0x536b00539400503102802836b0050280070283960051e60dc00536b007", + "0x50470280cb0c900736b0050dc00506f0280c600536b0050280200280c7", + "0x2836b0050cf0050400283010cf00736b0050c900503602802836b0050cb", + "0x507402830c00536b00539700532502839730100736b005301005071028", + "0x36b0053980c600736402839800536b00539800501b02839800536b00530c", + "0x9202839300536b00539300504f0280d400536b00530100535e0282fb005", + "0x36b0052fb0052150280d400536b0050d400505b0280c700536b0050c7005", + "0x73990050060283990d52fa03136b0052fb0d40c739300a0750282fb005", + "0x2f100536b0050d500503102802836b0050280070282f700539a2f800536b", + "0xda00503602802836b0052ee0050470282ee0da00736b0052f800506f028", + "0x2ef00536b0050d200535e02802836b0052ec0050400280d22ec00736b005", + "0x2fa00504f0282f600536b0050db0053560280db00536b0052ef005359028", + "0xa00536b00500a0050c00282f100536b0052f10050920282fa00536b005", + "0x2836b0050280070282f600a2f12fa00a0052f600536b0052f6005084028", + "0x2fa00504f0282e800536b0052f70053630282e900536b0050d5005031028", + "0xa00536b00500a0050c00282e900536b0052e90050920282fa00536b005", + "0x2836b0050280070282e800a2e92fa00a0052e800536b0052e8005084028", + "0x534c0282f50df00736b0053960050770282e700536b005394005031028", + "0x2f300536b0052e70050920280e100536b00539300504f02802836b0050df", + "0x502804d0280e300536b0052f50052150282f200536b00500a0050c0028", + "0x530600503102802836b00504f00523702802836b00502800702802839b", + "0x2802836b0052e000534c0282de2e000736b0053040050770282f400536b", + "0x500a0050c00282f300536b0052f40050920280e100536b00530700504f", + "0x2800702802839b00502804d0280e300536b0052de0052150282f200536b", + "0x506702802836b00500b00504202802836b00531300523702802836b005", + "0x2dd00536b0050b60050310280b600536b0050b600509202802836b005092", + "0x30b0050c00282f300536b0052dd0050920280e100536b00531e00504f028", + "0x702802839b00502804d0280e300536b0050b90052150282f200536b005", + "0x6702802836b00500b00504202802836b00504300525d02802836b005028", + "0x2802836b00534600501f02802836b00532c00504002802836b005092005", + "0x531e00504f0281a600536b00531100503102831100536b005311005092", + "0x282f200536b0050a90050c00282f300536b0051a60050920280e100536b", + "0x50e32db00702d0282db00536b0050280230280e300536b005310005215", + "0x280e100536b0050e100504f0282d700536b0052da0053630282da00536b", + "0x52d70050840282f200536b0052f20050c00282f300536b0052f3005092", + "0x504300525d02802836b0050280070282d72f22f30e100a0052d700536b", + "0x32c00504002802836b00509200506702802836b00500b00504202802836b", + "0x501f02802836b00500f00504002802836b00534600501f02802836b005", + "0x280ea00536b00531b00503102802836b00500c00525d02802836b005215", + "0x536b0052d600501b0282d600536b0050280460280ee00536b005028020", + "0x702d0282d300536b0050280230282d400536b0052d60ee0073640282d6", + "0x36b00531c00504f0282d100536b0052d20053630282d200536b0052d42d3", + "0x8402800700536b0050070050c00280ea00536b0050ea00509202831c005", + "0x4702802836b0050280070282d10070ea31c00a0052d100536b0052d1005", + "0x2802836b00504300525d02802836b00532e00523702802836b00508b005", + "0x2836b00534600501f02802836b00509200506702802836b00500b005042", + "0x36b00500c00525d02802836b00521500501f02802836b00500f005040028", + "0x50920282cf00536b00537700504f0282d000536b00532f005031028028", + "0x525d02802836b00502800702802839c00502804d0282cc00536b0052d0", + "0x6702802836b00500b00504202802836b00504300525d02802836b00500c", + "0x2802836b00500f00504002802836b00534600501f02802836b005092005", + "0x36b0053300053630280f600536b00533300503102802836b00521500501f", + "0xc00280f600536b0050f600509202837700536b00537700504f0280f8005", + "0xf80070f637700a0050f800536b0050f800508402800700536b005007005", + "0x2802836b00508800504702802836b00502836902802836b005028007028", + "0x2836b00504300525d02802836b00500c00525d02802836b00500f005040", + "0x36b00521500501f02802836b00509200506702802836b00500b005042028", + "0x533d00503102802836b00508c00501c02802836b00534600501f028028", + "0x282cc00536b0052cb0050920282cf00536b00534b00504f0282cb00536b", + "0x536b0052c900501b0282c900536b00502834b0282ca00536b005028020", + "0x702d0280fc00536b0050280230280fa00536b0052c92ca0073640282c9", + "0x36b0052cf00504f0280f900536b0050fb0053630280fb00536b0050fa0fc", + "0x8402800700536b0050070050c00282cc00536b0052cc0050920282cf005", + "0x1c02802836b0050280070280f90072cc2cf00a0050f900536b0050f9005", + "0x2802836b00500c00525d02802836b00500f00504002802836b005081005", + "0x2836b00509200506702802836b00500b00504202802836b00504300525d", + "0x36b00507900503102802836b00501800506002802836b00521500501f028", + "0x10200501b02810200536b0050280430282c700536b0050280200282c8005", + "0x10300536b00502802302810400536b0051022c700736402810200536b005", + "0x504f0282c600536b00510100536302810100536b00510410300702d028", + "0x536b0050070050c00282c800536b0052c800509202834b00536b00534b", + "0x36b0050280070282c60072c834b00a0052c600536b0052c6005084028007", + "0x501800506002802836b00500c00525d02802836b00500f005040028028", + "0x21500501f02802836b00509200506702802836b00500b00504202802836b", + "0x4f0282c500536b00534c00503102802836b00506f00501c02802836b005", + "0x2839d00502804d02810b00536b0052c500509202810a00536b00507a005", + "0x2802836b00507700504702802836b00502836902802836b005028007028", + "0x2836b00501800506002802836b00500c00525d02802836b00500f005040", + "0x36b00521500501f02802836b00509200506702802836b00500b005042028", + "0x500600503102802836b00501400506002802836b00506f00501c028028", + "0x2810b00536b00510900509202810a00536b00505b00504f02810900536b", + "0x536b0052c300501b0282c300536b00502807a02810c00536b005028020", + "0x702d02811200536b0050280230282c200536b0052c310c0073640282c3", + "0x36b00510a00504f02802500536b00511300536302811300536b0052c2112", + "0x8402800700536b0050070050c002810b00536b00510b00509202810a005", + "0x4702802836b00502800702802500710b10a00a00502500536b005025005", + "0x2802836b00501800506002802836b00500c00525d02802836b005060005", + "0x2836b00521500501f02802836b00509200506702802836b00500b005042", + "0x36b00501000507902802836b00525e00523702802836b005014005060028", + "0x50920282c100536b00505b00504f02811100536b00525d005031028028", + "0x525d02802836b00502800702802839e00502804d02811d00536b005111", + "0x6702802836b00500b00504202802836b00501800506002802836b00500c", + "0x2802836b00501400506002802836b00521500501f02802836b005092005", + "0x36b00525c00536302811900536b00505800503102802836b005010005079", + "0xc002811900536b00511900509202805b00536b00505b00504f028118005", + "0x11800711905b00a00511800536b00511800508402800700536b005007005", + "0x2802836b00524d00504702802836b00502836902802836b005028007028", + "0x2836b00501800506002802836b00500c00525d02802836b005010005079", + "0x36b00521500501f02802836b00509200506702802836b00500b005042028", + "0x523700503102802836b00523900501c02802836b005014005060028028", + "0x2811d00536b0052c00050920282c100536b00503300504f0282c000536b", + "0x536b00512100501b02812100536b00502805e02811f00536b005028020", + "0x702d0282bc00536b0050280230282be00536b00512111f007364028121", + "0x36b0052c100504f0282ba00536b0052bb0053630282bb00536b0052be2bc", + "0x8402800700536b0050070050c002811d00536b00511d0050920282c1005", + "0x1c02802836b0050280070282ba00711d2c100a0052ba00536b0052ba005", + "0x2802836b00500c00525d02802836b00501000507902802836b005359005", + "0x2836b00509200506702802836b00500b00504202802836b005018005060", + "0x36b00503600503102802836b00503000506002802836b005014005060028", + "0x12500501b02812500536b00502804802812600536b005028020028124005", + "0x2b900536b00502802302812300536b00512512600736402812500536b005", + "0x504f02812c00536b0052b70053630282b700536b0051232b900702d028", + "0x536b0050070050c002812400536b00512400509202803300536b005033", + "0x36b00502800702812c00712403300a00512c00536b00512c005084028007", + "0x501800506002802836b00503000506002802836b005010005079028028", + "0x8400501c02802836b00509200506702802836b00500b00504202802836b", + "0x4f02812b00536b00536c00503102802836b00501400506002802836b005", + "0x2839f00502804d02813100536b00512b0050920282b600536b00503c005", + "0x2802836b00535d00504702802836b00502836902802836b005028007028", + "0x2836b00501800506002802836b00503000506002802836b005010005079", + "0x36b00508400501c02802836b00509200506702802836b00500b005042028", + "0x50c000503102802836b00504e00506002802836b005014005060028028", + "0x2813100536b0051300050920282b600536b00536900504f02813000536b", + "0x536b0052b300501b0282b300536b0050280450282b500536b005028020", + "0x702d02813600536b0050280230282b200536b0052b32b50073640282b3", + "0x36b0052b600504f02813700536b00513800536302813800536b0052b2136", + "0x8402800700536b0050070050c002813100536b0051310050920282b6005", + "0x7902802836b0050280070281370071312b600a00513700536b005137005", + "0x2802836b00501800506002802836b00503000506002802836b005010005", + "0x2836b00504e00506002802836b00509200506702802836b00500b005042", + "0x36b00501c00503102802836b00503100523702802836b005014005060028", + "0x2b000501b0282b000536b0050280460282b100536b005028020028135005", + "0x13f00536b0050280230282af00536b0052b02b10073640282b000536b005", + "0x504f0282ad00536b00513e00536302813e00536b0052af13f00702d028", + "0x536b0050070050c002813500536b00513500509202801b00536b00501b", + "0x36b0050280280282ad00713501b00a0052ad00536b0052ad005084028007", + "0x36b00502800702809204f0073a000b00a00736b007005028007005028028", + "0x2800b02801000536b00503100500a02800f00536b00500b005031028028", + "0x2800f00536b00500f00509202800a00536b00500a00504f02802836b005", + "0x503102802836b0050280070280130053a104e1c800736b00701000500f", + "0x536b00504d0051c802804d00536b00504e00501002801400536b00500f", + "0x501302801800536b00501400509202801700536b00503000504e028030", + "0x280283a200502804d02836800536b00501700501402836900536b0051c8", + "0x1c00536b00502803002801b00536b00500f00503102802836b005028007", + "0x1300501302801800536b00501b00509202836700536b00501c005017028", + "0x36600536b00736800501802836800536b00536700501402836900536b005", + "0x501800503102802836b00502836902802836b00502800702801f0053a3", + "0x36500736b00736600a00707f02802000536b00502000509202802000536b", + "0x4f02802d00536b00502000503102802836b0050280070280230053a4364", + "0x36b00736900500f02802d00536b00502d00509202836500536b005365005", + "0x36100536b00502d00503102802836b0050280070280840053a50c0363007", + "0x502800b02835f00536b0051aa0051c80281aa00536b0050c0005010028", + "0x9202836300536b00536300501302835f00536b00535f00501b02802836b", + "0x50280070280320053a602836b00735f00534802836100536b005361005", + "0x508102836c00536b00502803002835d00536b00536100503102802836b", + "0x536b00503300507d02800c00536b00535d00509202803300536b00536c", + "0x2836b00503200534602802836b0050280070280283a700502804d02803c", + "0x504000534502804000536b00502803002803600536b005361005031028", + "0x2803c00536b00535e00507d02800c00536b00503600509202835e00536b", + "0x2836902802836b0050280070282150053a835635900736b00736300500f", + "0x534402802836b00535600536702802836b00535900501c02802836b005", + "0x2821c00536b00500c00503102802836b00536400534302802836b00503c", + "0x536b00504800501b02804800536b00502836502804600536b005028020", + "0x702d02804500536b00502802302804700536b005048046007364028048", + "0x36b00536500504f02823900536b00523700536302823700536b005047045", + "0x8402800700536b0050070050c002821c00536b00521c005092028365005", + "0x1c02802836b00502800702823900721c36500a00523900536b005239005", + "0x23f00536b00502836102823b00536b00500c00503102802836b005215005", + "0x36503135f02823f00536b00523f0051aa02823b00536b00523b005092028", + "0x2836902802836b00502800702824d24c0073a924924500736b00723f23b", + "0x2824f00536b00503c00534202824e00536b00524900503102802836b005", + "0x36b0050070050c002824e00536b00524e00509202825200536b005028341", + "0x8c02824f00536b00524f00507d02836400536b00536400533d028007005", + "0x24500536b00524500504f02805b00905003136b00524f36425200724e00b", + "0x533b02802836b0050280070280590053aa05800536b00705b00533c028", + "0x2825c00536b00502802002805c00536b00505000503102802836b005058", + "0x525e00535e02802836b00525d00504002825e25d00736b00525c005036", + "0x2805f00536b00506000535602806000536b00505e00535902805e00536b", + "0x50090050c002805c00536b00505c00509202824500536b00524500504f", + "0x2800702805f00905c24500a00505f00536b00505f00508402800900536b", + "0x2829600536b00505900536302805d00536b00505000503102802836b005", + "0x50090050c002805d00536b00505d00509202824500536b00524500504f", + "0x2800702829600905d24500a00529600536b00529600508402800900536b", + "0x36400534302802836b00503c00534402802836b00502836902802836b005", + "0x4602804200536b00502802002829800536b00524d00503102802836b005", + "0x36b00506704200736402806700536b00506700501b02806700536b005028", + "0x36302806800536b0052bd06900702d02806900536b0050280230282bd005", + "0x36b00529800509202824c00536b00524c00504f02800600536b005068005", + "0xa00500600536b00500600508402800700536b0050070050c0028298005", + "0x534302802836b00508400501c02802836b00502800702800600729824c", + "0x2807100536b00502802002806f00536b00502d00503102802836b005364", + "0x532507100736402832500536b00532500501b02832500536b005028048", + "0x2807700536b00507407500702d02807500536b00502802302807400536b", + "0x506f00509202836500536b00536500504f02834c00536b005077005363", + "0x534c00536b00534c00508402800700536b0050070050c002806f00536b", + "0x3102802836b00536900501c02802836b00502800702834c00706f36500a", + "0x36b00534b00509202804300536b00502300504f02834b00536b005020005", + "0x2836b00502836902802836b0050280070280283ab00502804d02807a005", + "0x36b00501800503102802836b00536900501c02802836b00501f005047028", + "0x2002807a00536b00507900509202804300536b00500a00504f028079005", + "0x34800536b00534800501b02834800536b00502804502807f00536b005028", + "0x7d00702d02807d00536b00502802302808100536b00534807f007364028", + "0x536b00504300504f02834500536b00534600536302834600536b005081", + "0x508402800700536b0050070050c002807a00536b00507a005092028043", + "0x523702802836b00502800702834500707a04300a00534500536b005345", + "0x2834300536b00502802002834400536b00509200503102802836b005031", + "0x534234300736402834200536b00534200501b02834200536b005028046", + "0x2808c00536b00534133d00702d02833d00536b00502802302834100536b", + "0x534400509202804f00536b00504f00504f02833c00536b00508c005363", + "0x533c00536b00533c00508402800700536b0050070050c002834400536b", + "0xa00736b00700502800700502802836b00502802802833c00734404f00a", + "0x2800f00536b00500b00503102802836b00502800702809204f0073ac00b", + "0x500f00509202800a00536b00500a00504f02801000536b00503100500a", + "0x36b0050280070280130053ad04e1c800736b00701000500f02800f00536b", + "0x500f00503102802836b00504e00536702802836b0051c800501c028028", + "0x501b02803000536b00502836502804d00536b00502802002801400536b", + "0x536b00502802302801700536b00503004d00736402803000536b005030", + "0x4f02836800536b00536900536302836900536b00501701800702d028018", + "0x36b0050070050c002801400536b00501400509202800a00536b00500a005", + "0x502800702836800701400a00a00536800536b005368005084028007005", + "0x2836102801b00536b00500f00503102802836b00501300501c02802836b", + "0x1c00536b00501c0051aa02801b00536b00501b00509202801c00536b005", + "0x36b00502800702802001f0073ae36636700736b00701c01b00a03135f028", + "0x36400533a02836400536b00502808a02836500536b005366005031028028", + "0x9202836300536b00502803202802d00536b00502833902802300536b005", + "0x36b00502300508802836300536b00536300503302836500536b005365005", + "0xc02836700536b00536700504f02802d00536b00502d00501b028023005", + "0x502800702835f1aa3610313af0840c000736b00702d02336300736500b", + "0x2002803200536b0050c00050310280c000536b0050c000509202802836b", + "0x36b00536c00504002803336c00736b00535d00503602835d00536b005028", + "0x535602803c00536b00500c00535902800c00536b00503300535e028028", + "0x536b00503200509202836700536b00536700504f02803600536b00503c", + "0x36700a00503600536b00503600508402808400536b0050840050c0028032", + "0x503102836100536b00536100509202802836b005028007028036084032", + "0x536b00535f35e00702d02835e00536b00502802302804000536b005361", + "0x509202836700536b00536700504f02835600536b005359005363028359", + "0x536b0053560050840281aa00536b0051aa0050c002804000536b005040", + "0x536b00502000503102802836b0050280070283561aa04036700a005356", + "0x504600501b02804600536b00502804602821c00536b005028020028215", + "0x2804700536b00502802302804800536b00504621c00736402804600536b", + "0x1f00504f02823700536b00504500536302804500536b00504804700702d", + "0x700536b0050070050c002821500536b00521500509202801f00536b005", + "0x2836b00502800702823700721501f00a00523700536b005237005084028", + "0x36b00502802002823900536b00509200503102802836b005031005237028", + "0x736402823f00536b00523f00501b02823f00536b00502804602823b005", + "0x36b00524524900702d02824900536b00502802302824500536b00523f23b", + "0x9202804f00536b00504f00504f02824d00536b00524c00536302824c005", + "0x36b00524d00508402800700536b0050070050c002823900536b005239005", + "0x700502800700502802836b00502802802824d00723904f00a00524d005", + "0x36b00500b00503102802836b00502800702809204f0073b000b00a00736b", + "0xa00504f02802836b00502800b02801000536b00503100500a02800f005", + "0x1c800736b00701000500f02800f00536b00500f00509202800a00536b005", + "0x1002801400536b00500f00503102802836b0050280070280130053b104e", + "0x36b00503000504e02803000536b00504d0051c802804d00536b00504e005", + "0x1402836900536b0051c800501302801800536b005014005092028017005", + "0x3102802836b0050280070280283b200502804d02836800536b005017005", + "0x536b00501c00501702801c00536b00502803002801b00536b00500f005", + "0x501402836900536b00501300501302801800536b00501b005092028367", + "0x502800702801f0053b336600536b00736800501802836800536b005367", + "0x2000509202802000536b00501800503102802836b00502836902802836b", + "0x280070280230053b436436500736b00736600a00724e02802000536b005", + "0x504f02802836b00502800b02802d00536b00502000503102802836b005", + "0x736b00736900500f02802d00536b00502d00509202836500536b005365", + "0x2836100536b00502d00503102802836b0050280070280840053b50c0363", + "0x535f00504e02835f00536b0051aa0051c80281aa00536b0050c0005010", + "0x2836c00536b00536300501302835d00536b00536100509202803200536b", + "0x2802836b0050280070280283b600502804d02803300536b005032005014", + "0x36b00503c00501702803c00536b00502803002800c00536b00502d005031", + "0x1402836c00536b00508400501302835d00536b00500c005092028036005", + "0x2800702835e0053b704000536b00703300501802803300536b005036005", + "0x2835900536b00535900509202835900536b00535d00503102802836b005", + "0x3102802836b00502800702821c0053b821535600736b00704036500707f", + "0x36b00504600509202835600536b00535600504f02804600536b005359005", + "0x2836b0050280070280450053b904704800736b00736c00500f028046005", + "0x2836b00504700536702802836b00504800501c02802836b005028369028", + "0x36b00504600503102802836b00536400525d02802836b005215005343028", + "0x23b00501b02823b00536b00502836502823900536b005028020028237005", + "0x24500536b00502802302823f00536b00523b23900736402823b00536b005", + "0x504f02824c00536b00524900536302824900536b00523f24500702d028", + "0x536b0050070050c002823700536b00523700509202835600536b005356", + "0x36b00502800702824c00723735600a00524c00536b00524c005084028007", + "0x502836102824d00536b00504600503102802836b00504500501c028028", + "0x2824e00536b00524e0051aa02824d00536b00524d00509202824e00536b", + "0x2836b0050280070280090500073ba25224f00736b00724e24d35603135f", + "0x536b00502834102805b00536b00525200503102802836b005028369028", + "0x533802800700536b0050070050c002805b00536b00505b005092028058", + "0x36405800705b00b33702821500536b00521500533d02836400536b005364", + "0x725c00533c02824f00536b00524f00504f02825c05c05903136b005215", + "0x2802836b00525d00533b02802836b00502800702825e0053bb25d00536b", + "0x36b00506000503602806000536b00502802002805e00536b005059005031", + "0x35902829600536b00505d00535e02802836b00505f00504002805d05f007", + "0x36b00524f00504f02804200536b00529800535602829800536b005296005", + "0x8402805c00536b00505c0050c002805e00536b00505e00509202824f005", + "0x3102802836b00502800702804205c05e24f00a00504200536b005042005", + "0x36b00524f00504f0282bd00536b00525e00536302806700536b005059005", + "0x8402805c00536b00505c0050c002806700536b00506700509202824f005", + "0x36902802836b0050280070282bd05c06724f00a0052bd00536b0052bd005", + "0x3102802836b00536400525d02802836b00521500534302802836b005028", + "0x600536b00502804602806800536b00502802002806900536b005009005", + "0x2802302806f00536b00500606800736402800600536b00500600501b028", + "0x536b00532500536302832500536b00506f07100702d02807100536b005", + "0x50c002806900536b00506900509202805000536b00505000504f028074", + "0x2807400706905000a00507400536b00507400508402800700536b005007", + "0x25d02802836b00536c00501c02802836b00502836902802836b005028007", + "0x536b00521c00504f02807500536b00535900503102802836b005364005", + "0x36b0050280070280283bc00502804d02834c00536b005075005092028077", + "0x36b00536c00501c02802836b00535e00504702802836b005028369028028", + "0x36500504f02834b00536b00535d00503102802836b00536400525d028028", + "0x2804300536b00502802002834c00536b00534b00509202807700536b005", + "0x507a04300736402807a00536b00507a00501b02807a00536b005028048", + "0x2834800536b00507907f00702d02807f00536b00502802302807900536b", + "0x534c00509202807700536b00507700504f02808100536b005348005363", + "0x508100536b00508100508402800700536b0050070050c002834c00536b", + "0x3102802836b00536900501c02802836b00502800702808100734c07700a", + "0x36b00507d00509202834600536b00502300504f02807d00536b005020005", + "0x2836b00502836902802836b0050280070280283bd00502804d028345005", + "0x36b00501800503102802836b00536900501c02802836b00501f005047028", + "0x2002834500536b00534400509202834600536b00500a00504f028344005", + "0x34200536b00534200501b02834200536b00502804502834300536b005028", + "0x33d00702d02833d00536b00502802302834100536b005342343007364028", + "0x536b00534600504f02833c00536b00508c00536302808c00536b005341", + "0x508402800700536b0050070050c002834500536b005345005092028346", + "0x523702802836b00502800702833c00734534600a00533c00536b00533c", + "0x2808a00536b00502802002833b00536b00509200503102802836b005031", + "0x533a08a00736402833a00536b00533a00501b02833a00536b005028046", + "0x2833800536b00533908800702d02808800536b00502802302833900536b", + "0x533b00509202804f00536b00504f00504f02833700536b005338005363", + "0x533700536b00533700508402800700536b0050070050c002833b00536b", + "0x2809200536b00502824902800b00536b00502824902833700733b04f00a", + "0xf00736b00700502800700502802836b00502802802802836b00502824c", + "0x2801300536b00501000503102802836b00502800702804e1c80073be010", + "0x536b00500f00504f02802836b00502800b02801400536b00503100500a", + "0x53bf03004d00736b00701400500f02801300536b00501300509202800f", + "0x503000501002801800536b00501300503102802836b005028007028017", + "0x2801b00536b00536800504e02836800536b0053690051c802836900536b", + "0x501b00501402836700536b00504d00501302801c00536b005018005092", + "0x501300503102802836b0050280070280283c000502804d02836600536b", + "0x9202836500536b00502000501702802000536b00502803002801f00536b", + "0x36b00536500501402836700536b00501700501302801c00536b00501f005", + "0x2802836b0050280070283640053c104f00536b007366005018028366005", + "0x36b00504f09200724d02802300536b00501c00503102802836b005028369", + "0x36302d00736b00704f00f00724e02802300536b00502300509202804f005", + "0x504f02808400536b00502300503102802836b0050280070280c00053c2", + "0x736b00736700500f02808400536b00508400509202802d00536b00502d", + "0x2803200536b00508400503102802836b00502800702835f0053c31aa361", + "0xa0051c802800a00536b00500a00b00724d02800a00536b0051aa005010", + "0x9202836100536b00536100501302802836b00502800b02835d00536b005", + "0x702800c0053c403336c00736b00736100500f02803200536b005032005", + "0x3600536b00503300524f02803c00536b00503200503102802836b005028", + "0x3600525202835e00536b00536c00501302804000536b00503c005092028", + "0x3200503102802836b0050280070280283c500502804d02835900536b005", + "0x2821c00536b00521500505002821500536b00502803002835600536b005", + "0x521c00525202835e00536b00500c00501302804000536b005356005092", + "0x2836b0050280070280480053c604600536b00735900500902835900536b", + "0x36b00504600501002804700536b00504000503102802836b005028369028", + "0x51c802823900536b00535e00535e02823700536b005028020028045005", + "0x536b00504700509202802d00536b00502d00504f02823b00536b005045", + "0x501b02823700536b00523700521502823900536b00523900505b028047", + "0x2824924523f03136b00523b23723904702d00b05802823b00536b00523b", + "0x24500503102802836b00502800702824d0053c724c00536b007249005059", + "0x536b00524e00509202825224f00736b00524c00505c02824e00536b005", + "0x3102802836b0050280070280090053c805000536b00725200525c02824e", + "0x36b00505b00509202805800536b00524f00500a02805b00536b00524e005", + "0x2836b00502800702825c0053c905c05900736b00705800500f02805b005", + "0x36b00505000504002802836b00505c00536702802836b00505900501c028", + "0x505b00503102802836b00536300525d02802836b00535d00501f028028", + "0x501b02805e00536b00502836502825e00536b00502802002825d00536b", + "0x536b00502802302806000536b00505e25e00736402805e00536b00505e", + "0x4f02829600536b00505d00536302805d00536b00506005f00702d02805f", + "0x36b0050070050c002825d00536b00525d00509202823f00536b00523f005", + "0x502800702829600725d23f00a00529600536b005296005084028007005", + "0x2836102829800536b00505b00503102802836b00525c00501c02802836b", + "0x4200536b0050420051aa02829800536b00529800509202804200536b005", + "0x36b0050280070280680690073ca2bd06700736b00704229823f03135f028", + "0x4002807106f00736b00505000503602800600536b0052bd005031028028", + "0x2802836b00502800b02832500536b00507100535e02802836b00506f005", + "0x700600b25e02806700536b00506700504f02800600536b005006005092", + "0x2836b00502800702804334b34c0313cb07707507403136b00732535d363", + "0x507400503102807400536b00507400509202802836b005077005237028", + "0x501b02807f00536b00502833602807900536b00502802002807a00536b", + "0x36b00507a00509202834800536b00507f07900736402807f00536b00507f", + "0x4d02834600536b00534800521502807d00536b0050750050c0028081005", + "0x3102834c00536b00534c00509202802836b0050280070280283cc005028", + "0x36b00534b0050c002808100536b00534500509202834500536b00534c005", + "0x502802302802836b00502836902834600536b00504300521502807d005", + "0x34200536b00534300536302834300536b00534634400702d02834400536b", + "0x7d0050c002808100536b00508100509202806700536b00506700504f028", + "0x702834207d08106700a00534200536b00534200508402807d00536b005", + "0x25d02802836b00535d00501f02802836b00505000504002802836b005028", + "0x33d00536b00502802002834100536b00506800503102802836b005363005", + "0x8c33d00736402808c00536b00508c00501b02808c00536b005028046028", + "0x8a00536b00533c33b00702d02833b00536b00502802302833c00536b005", + "0x34100509202806900536b00506900504f02833a00536b00508a005363028", + "0x33a00536b00533a00508402800700536b0050070050c002834100536b005", + "0x2802836b00500900504702802836b00502800702833a00734106900a005", + "0x2836b00536300525d02802836b00535d00501f02802836b00524f005237", + "0x33900509202808800536b00523f00504f02833900536b00524e005031028", + "0x36300525d02802836b0050280070280283cd00502804d02833800536b005", + "0x36302833700536b00524500503102802836b00535d00501f02802836b005", + "0x36b00533700509202823f00536b00523f00504f02833600536b00524d005", + "0xa00533600536b00533600508402800700536b0050070050c0028337005", + "0x4800504702802836b00502836902802836b00502800702833600733723f", + "0x501c02802836b00536300525d02802836b00535d00501f02802836b005", + "0x8800536b00502d00504f02808600536b00504000503102802836b00535e", + "0x36b00502805e02808e00536b00502802002833800536b005086005092028", + "0x2833300536b00537708e00736402837700536b00537700501b028377005", + "0x533100536302833100536b00533333200702d02833200536b005028023", + "0x2833800536b00533800509202808800536b00508800504f02833000536b", + "0x733808800a00533000536b00533000508402800700536b0050070050c0", + "0x36b00536300525d02802836b00535f00501c02802836b005028007028330", + "0x502802002832f00536b00508400503102802836b00500b005060028028", + "0x36402832d00536b00532d00501b02832d00536b00502804802832e00536b", + "0x532c08b00702d02808b00536b00502802302832c00536b00532d32e007", + "0x2802d00536b00502d00504f02832a00536b00532b00536302832b00536b", + "0x532a00508402800700536b0050070050c002832f00536b00532f005092", + "0x536700501c02802836b00502800702832a00732f02d00a00532a00536b", + "0x504f02832900536b00502300503102802836b00500b00506002802836b", + "0x280283ce00502804d02808500536b00532900509202832600536b0050c0", + "0x1c02802836b00536400504702802836b00502836902802836b005028007", + "0x2802836b00509200506002802836b00500b00506002802836b005367005", + "0x509300509202832600536b00500f00504f02809300536b00501c005031", + "0x501b02832400536b00502804502809500536b00502802002808500536b", + "0x536b00502802302809800536b00532409500736402832400536b005324", + "0x4f02832200536b00509600536302809600536b00509832300702d028323", + "0x36b0050070050c002808500536b00508500509202832600536b005326005", + "0x502800702832200708532600a00532200536b005322005084028007005", + "0x3100523702802836b00500b00506002802836b00509200506002802836b", + "0x4602831f00536b00502802002832100536b00504e00503102802836b005", + "0x36b00531e31f00736402831e00536b00531e00501b02831e00536b005028", + "0x36302831b00536b00531d31c00702d02831c00536b00502802302831d005", + "0x36b0053210050920281c800536b0051c800504f02831a00536b00531b005", + "0xa00531a00536b00531a00508402800700536b0050070050c0028321005", + "0x24c02809200536b00502824902800b00536b00502829602831a0073211c8", + "0x1000f00736b00700502800700502802836b00502802802802836b005028", + "0xa02801300536b00501000503102802836b00502800702804e1c80073cf", + "0xf00536b00500f00504f02802836b00502800b02801400536b005031005", + "0x170053d003004d00736b00701400500f02801300536b005013005092028", + "0x36b00503000524f02801800536b00501300503102802836b005028007028", + "0x25202801b00536b00504d00501302836800536b005018005092028369005", + "0x3102802836b0050280070280283d100502804d02801c00536b005369005", + "0x536b00536600505002836600536b00502803002836700536b005013005", + "0x525202801b00536b00501700501302836800536b00536700509202801f", + "0x50280070283650053d202000536b00701c00500902801c00536b00501f", + "0x2000501002836400536b00536800503102802836b00502836902802836b", + "0x536b00504f0051c802804f00536b00504f09200724d02804f00536b005", + "0x3d336302d00736b00702300f00708602836400536b005364005092028023", + "0x502800b02808400536b00536400503102802836b0050280070280c0005", + "0xf02808400536b00508400509202802d00536b00502d00504f02802836b", + "0x8400503102802836b00502800702835f0053d41aa36100736b00701b005", + "0x36c00536b00503200509202835d00536b0051aa00524f02803200536b005", + "0x502804d02800c00536b00535d00525202803300536b005361005013028", + "0x502803002803c00536b00508400503102802836b0050280070280283d5", + "0x2836c00536b00503c00509202804000536b00503600505002803600536b", + "0x700c00500902800c00536b00504000525202803300536b00535f005013", + "0x35600536b00536c00503102802836b0050280070283590053d635e00536b", + "0x503300535e02821c00536b00502802002821500536b00535e005010028", + "0x2802d00536b00502d00504f02804800536b0052150051c802804600536b", + "0x521c00521502804600536b00504600505b02835600536b005356005092", + "0x504821c04635602d00b05802804800536b00504800501b02821c00536b", + "0x502800702823b0053d723900536b00723700505902823704504703136b", + "0x2824924500736b00523900505c02823f00536b00504500503102802836b", + "0x702824c0053d800a00536b00724900525c02823f00536b00523f005092", + "0x24e00536b00524500500a02824d00536b00523f00503102802836b005028", + "0x524d00509202800a00536b00500a00b00729802802836b00502800b028", + "0x36b0050280070280500053d925224f00736b00724e00500f02824d00536b", + "0x509202805b00536b00525200524f02800900536b00524d005031028028", + "0x536b00505b00525202805900536b00524f00501302805800536b005009", + "0x536b00524d00503102802836b0050280070280283da00502804d02805c", + "0x25c00509202825e00536b00525d00505002825d00536b00502803002825c", + "0x5c00536b00525e00525202805900536b00505000501302805800536b005", + "0x2836902802836b0050280070280600053db05e00536b00705c005009028", + "0x2805d00536b00505e00501002805f00536b00505800503102802836b005", + "0x36b00505d0051c802829800536b00505900535e02829600536b005028020", + "0x5b02805f00536b00505f00509202804700536b00504700504f028042005", + "0x36b00504200501b02829600536b00529600521502829800536b005298005", + "0x690050590280692bd06703136b00504229629805f04700b058028042005", + "0x536b0052bd00503102802836b0050280070280060053dc06800536b007", + "0x25c02806f00536b00506f00509202832507100736b00506800505c02806f", + "0x506f00503102802836b0050280070280750053dd07400536b007325005", + "0x2807700536b00507700509202834c00536b00507100500a02807700536b", + "0x501c02802836b00502800702807a0053de04334b00736b00734c00500f", + "0x8e02802836b00500a00504002802836b00504300536702802836b00534b", + "0x7900536b00507700503102802836b00507400504002802836b005363005", + "0x36b00534800501b02834800536b00502836502807f00536b005028020028", + "0x2d02807d00536b00502802302808100536b00534807f007364028348005", + "0x506700504f02834500536b00534600536302834600536b00508107d007", + "0x2800700536b0050070050c002807900536b00507900509202806700536b", + "0x2802836b00502800702834500707906700a00534500536b005345005084", + "0x536b00502836102834400536b00507700503102802836b00507a00501c", + "0x3135f02834300536b0053430051aa02834400536b005344005092028343", + "0x3102802836b00502800702808c33d0073df34134200736b007343344067", + "0x736b00507400503602833b00536b00502837702833c00536b005341005", + "0x8e02808833900736b00536300533302802836b00508a00504002833a08a", + "0x36b00533800504002833733800736b00500a00503602802836b005339005", + "0x50c002833c00536b00533c00509202834200536b00534200504f028028", + "0x536b00533a00501302833b00536b00533b00533202800700536b005007", + "0x9233102833700536b00533700501302808800536b00508800533202833a", + "0x36b00737700533002837708e08633600a36b00533708833a33b00733c342", + "0x3102802836b00533300532f02802836b0050280070283320053e0333005", + "0x736b00533000503602833000536b00502802002833100536b005086005", + "0x535902832d00536b00532e00535e02802836b00532f00504002832e32f", + "0x536b00533600504f02808b00536b00532c00535602832c00536b00532d", + "0x508402808e00536b00508e0050c002833100536b005331005092028336", + "0x503102802836b00502800702808b08e33133600a00508b00536b00508b", + "0x536b00533600504f02832a00536b00533200536302832b00536b005086", + "0x508402808e00536b00508e0050c002832b00536b00532b005092028336", + "0x504002802836b00502800702832a08e32b33600a00532a00536b00532a", + "0x3102802836b00507400504002802836b00536300508e02802836b00500a", + "0x8500536b00502804602832600536b00502802002832900536b00508c005", + "0x2802302809300536b00508532600736402808500536b00508500501b028", + "0x536b00532400536302832400536b00509309500702d02809500536b005", + "0x50c002832900536b00532900509202833d00536b00533d00504f028098", + "0x2809800732933d00a00509800536b00509800508402800700536b005007", + "0x2802836b00507100523702802836b00507500504702802836b005028007", + "0x536b00506f00503102802836b00536300508e02802836b00500a005040", + "0x2804d02832200536b00532300509202809600536b00506700504f028323", + "0x36300508e02802836b00500a00504002802836b0050280070280283e1005", + "0x2831f00536b00500600536302832100536b0052bd00503102802836b005", + "0x50070050c002832100536b00532100509202806700536b00506700504f", + "0x2800702831f00732106700a00531f00536b00531f00508402800700536b", + "0xa00504002802836b00506000504702802836b00502836902802836b005", + "0x503102802836b00505900501c02802836b00536300508e02802836b005", + "0x536b00531e00509202809600536b00504700504f02831e00536b005058", + "0x531c00501b02831c00536b00502805e02831d00536b005028020028322", + "0x2831a00536b00502802302831b00536b00531c31d00736402831c00536b", + "0x9600504f02831800536b00531900536302831900536b00531b31a00702d", + "0x700536b0050070050c002832200536b00532200509202809600536b005", + "0x2836b00502800702831800732209600a00531800536b005318005084028", + "0x36b00524500523702802836b00536300508e02802836b00524c005047028", + "0x4700504f02831700536b00523f00503102802836b00500b005079028028", + "0x70280283e200502804d02831400536b00531700509202831600536b005", + "0x3102802836b00500b00507902802836b00536300508e02802836b005028", + "0x36b00504700504f02831100536b00523b00536302831300536b005045005", + "0x8402800700536b0050070050c002831300536b005313005092028047005", + "0x36902802836b00502800702831100731304700a00531100536b005311005", + "0x8e02802836b00500b00507902802836b00535900504702802836b005028", + "0xa900536b00536c00503102802836b00503300501c02802836b005363005", + "0x502802002831400536b0050a900509202831600536b00502d00504f028", + "0x3640280b000536b0050b000501b0280b000536b00502804802831000536b", + "0x50ac30f00702d02830f00536b0050280230280ac00536b0050b0310007", + "0x2831600536b00531600504f0280b400536b00530d00536302830d00536b", + "0x50b400508402800700536b0050070050c002831400536b005314005092", + "0x500b00507902802836b0050280070280b400731431600a0050b400536b", + "0x504f0280b600536b00536400503102802836b00501b00501c02802836b", + "0x280283e300502804d0280b900536b0050b600509202830b00536b0050c0", + "0x7902802836b00536500504702802836b00502836902802836b005028007", + "0x2802836b00509200506002802836b00501b00501c02802836b00500b005", + "0x530900509202830b00536b00500f00504f02830900536b005368005031", + "0x501b02830700536b00502804502830800536b0050280200280b900536b", + "0x536b00502802302830600536b00530730800736402830700536b005307", + "0x4f02830400536b0050bf0053630280bf00536b00530630500702d028305", + "0x36b0050070050c00280b900536b0050b900509202830b00536b00530b005", + "0x50280070283040070b930b00a00530400536b005304005084028007005", + "0x3100523702802836b00509200506002802836b00500b00507902802836b", + "0x4602830200536b00502802002830300536b00504e00503102802836b005", + "0x36b00505130200736402805100536b00505100501b02805100536b005028", + "0x36302839500536b00539339400702d02839400536b005028023028393005", + "0x36b0053030050920281c800536b0051c800504f0280dc00536b005395005", + "0xa0050dc00536b0050dc00508402800700536b0050070050c0028303005", + "0xb00a00736b00700502800700502802836b0050280280280dc0073031c8", + "0xa02800f00536b00500b00503102802836b00502800702809204f0073e4", + "0xa00536b00500a00504f02802836b00502800b02801000536b005031005", + "0x130053e504e1c800736b00701000500f02800f00536b00500f005092028", + "0x36b00504e00501002801400536b00500f00503102802836b005028007028", + "0x9202801700536b00503000504e02803000536b00504d0051c802804d005", + "0x36b00501700501402836900536b0051c800501302801800536b005014005", + "0x36b00500f00503102802836b0050280070280283e600502804d028368005", + "0x509202836700536b00501c00501702801c00536b00502803002801b005", + "0x536b00536700501402836900536b00501300501302801800536b00501b", + "0x36902802836b00502800702801f0053e736600536b007368005018028368", + "0x2000536b00502000509202802000536b00501800503102802836b005028", + "0x2802836b0050280070280230053e836436500736b00736600a00724e028", + "0x536b00536500504f02802836b00502800b02802d00536b005020005031", + "0x53e90c036300736b00736900500f02802d00536b00502d005092028365", + "0x50c000501002836100536b00502d00503102802836b005028007028084", + "0x2803200536b00535f00504e02835f00536b0051aa0051c80281aa00536b", + "0x503200501402836c00536b00536300501302835d00536b005361005092", + "0x502d00503102802836b0050280070280283ea00502804d02803300536b", + "0x9202803600536b00503c00501702803c00536b00502803002800c00536b", + "0x36b00503600501402836c00536b00508400501302835d00536b00500c005", + "0x2802836b00502800702835e0053eb04000536b007033005018028033005", + "0x4036500707f02835900536b00535900509202835900536b00535d005031", + "0x36b00535900503102802836b00502800702821c0053ec21535600736b007", + "0xf02804600536b00504600509202835600536b00535600504f028046005", + "0x502836902802836b0050280070280450053ed04704800736b00736c005", + "0x21500534302802836b00504700536702802836b00504800501c02802836b", + "0x2002823700536b00504600503102802836b00536400525d02802836b005", + "0x23b00536b00523b00501b02823b00536b00502836502823900536b005028", + "0x24500702d02824500536b00502802302823f00536b00523b239007364028", + "0x536b00535600504f02824c00536b00524900536302824900536b00523f", + "0x508402800700536b0050070050c002823700536b005237005092028356", + "0x501c02802836b00502800702824c00723735600a00524c00536b00524c", + "0x2824e00536b00502836102824d00536b00504600503102802836b005045", + "0x24d35603135f02824e00536b00524e0051aa02824d00536b00524d005092", + "0x25200503102802836b0050280070280090500073ee25224f00736b00724e", + "0x24f00536b00524f00504f02805b00536b00505b00509202805b00536b005", + "0x2800702825e25d25c0313ef05c05905803136b00736400705b03132e028", + "0x2805e00536b00505800503102805800536b00505800509202802836b005", + "0x506000501b02805f00536b00521500532d02806000536b00505c00532d", + "0x5d00536b00505d00501b02805d00536b00505f06000732c02806000536b", + "0x5d00534802805e00536b00505e00509202805900536b0050590050c0028", + "0x3102802836b00502836902802836b0050280070282960053f002836b007", + "0x736b00504200503602804200536b00502802002829800536b00505e005", + "0x535902806900536b0052bd00535e02802836b0050670050400282bd067", + "0x536b00524f00504f02800600536b00506800535602806800536b005069", + "0x508402805900536b0050590050c002829800536b00529800509202824f", + "0x534602802836b00502800702800605929824f00a00500600536b005006", + "0x2807100536b00502802002806f00536b00505e00503102802836b005296", + "0x532507100736402832500536b00532500501b02832500536b00502808b", + "0x2807700536b0050590050c002807500536b00506f00509202807400536b", + "0x2802836b0050280070280283f100502804d02834c00536b005074005215", + "0x36b00525c00503102825c00536b00525c00509202802836b005215005343", + "0x21502807700536b00525d0050c002807500536b00534b00509202834b005", + "0x2804300536b00502802302802836b00502836902834c00536b00525e005", + "0x24f00504f02807900536b00507a00536302807a00536b00534c04300702d", + "0x7700536b0050770050c002807500536b00507500509202824f00536b005", + "0x2836b00502800702807907707524f00a00507900536b005079005084028", + "0x2836b00536400525d02802836b00521500534302802836b005028369028", + "0x36b00502804602834800536b00502802002807f00536b005009005031028", + "0x2807d00536b00508134800736402808100536b00508100501b028081005", + "0x534500536302834500536b00507d34600702d02834600536b005028023", + "0x2807f00536b00507f00509202805000536b00505000504f02834400536b", + "0x707f05000a00534400536b00534400508402800700536b0050070050c0", + "0x2836b00536c00501c02802836b00502836902802836b005028007028344", + "0x521c00504f02834300536b00535900503102802836b00536400525d028", + "0x280070280283f200502804d02834100536b00534300509202834200536b", + "0x36c00501c02802836b00535e00504702802836b00502836902802836b005", + "0x4f02833d00536b00535d00503102802836b00536400525d02802836b005", + "0x536b00502802002834100536b00533d00509202834200536b005365005", + "0x8c00736402833c00536b00533c00501b02833c00536b00502804802808c", + "0x536b00533b08a00702d02808a00536b00502802302833b00536b00533c", + "0x509202834200536b00534200504f02833900536b00533a00536302833a", + "0x536b00533900508402800700536b0050070050c002834100536b005341", + "0x2836b00536900501c02802836b00502800702833900734134200a005339", + "0x8800509202833800536b00502300504f02808800536b005020005031028", + "0x502836902802836b0050280070280283f300502804d02833700536b005", + "0x1800503102802836b00536900501c02802836b00501f00504702802836b", + "0x33700536b00533600509202833800536b00500a00504f02833600536b005", + "0x36b00508e00501b02808e00536b00502804502808600536b005028020028", + "0x2d02833300536b00502802302837700536b00508e08600736402808e005", + "0x533800504f02833100536b00533200536302833200536b005377333007", + "0x2800700536b0050070050c002833700536b00533700509202833800536b", + "0x2802836b00502800702833100733733800a00533100536b005331005084", + "0x536b00502802002833000536b00509200503102802836b005031005237", + "0x32f00736402832e00536b00532e00501b02832e00536b00502804602832f", + "0x536b00532d32c00702d02832c00536b00502802302832d00536b00532e", + "0x509202804f00536b00504f00504f02832b00536b00508b00536302808b", + "0x536b00532b00508402800700536b0050070050c002833000536b005330", + "0x36b00700502800700502802836b00502802802832b00733004f00a00532b", + "0x536b00500b00503102802836b00502800702809204f0073f400b00a007", + "0x500a00504f02802836b00502800b02801000536b00503100500a02800f", + "0x4e1c800736b00701000500f02800f00536b00500f00509202800a00536b", + "0x524f02801400536b00500f00503102802836b0050280070280130053f5", + "0x536b0051c800501302803000536b00501400509202804d00536b00504e", + "0x36b0050280070280283f600502804d02801800536b00504d005252028017", + "0x36800505002836800536b00502803002836900536b00500f005031028028", + "0x1700536b00501300501302803000536b00536900509202801b00536b005", + "0x283670053f701c00536b00701800500902801800536b00501b005252028", + "0x2836600536b00503000503102802836b00502836902802836b005028007", + "0x502000501b02802000536b00501f0051c802801f00536b00501c005010", + "0x36500736b00702000a00708602836600536b00536600509202802000536b", + "0x4f02802d00536b00536600503102802836b0050280070280230053f8364", + "0x36b00701700500f02802d00536b00502d00509202836500536b005365005", + "0x2802836b00536300501c02802836b0050280070280840053f90c0363007", + "0x536b00502d00503102802836b00536400508e02802836b0050c0005367", + "0x535f00501b02835f00536b0050283650281aa00536b005028020028361", + "0x2835d00536b00502802302803200536b00535f1aa00736402835f00536b", + "0x36500504f02803300536b00536c00536302836c00536b00503235d00702d", + "0x700536b0050070050c002836100536b00536100509202836500536b005", + "0x2836b00502800702803300736136500a00503300536b005033005084028", + "0x36b00502836102800c00536b00502d00503102802836b00508400501c028", + "0x35f02803c00536b00503c0051aa02800c00536b00500c00509202803c005", + "0x2802836b00502800702835935e0073fa04003600736b00703c00c365031", + "0x503600504f02835600536b00535600509202835600536b005040005031", + "0x450470480313fb04621c21503136b00736400735603132b02803600536b", + "0x36b00521500503102821500536b00521500509202802836b005028007028", + "0x736402804600536b00504600501b02823900536b005028020028237005", + "0x523f00504002824523f00736b00523b00503602823b00536b005046239", + "0x35602824c00536b00524900535902824900536b00524500535e02802836b", + "0x36b00523700509202803600536b00503600504f02824d00536b00524c005", + "0xa00524d00536b00524d00508402821c00536b00521c0050c0028237005", + "0x3102804800536b00504800509202802836b00502800702824d21c237036", + "0x36b00504524f00702d02824f00536b00502802302824e00536b005048005", + "0x9202803600536b00503600504f02805000536b005252005363028252005", + "0x36b00505000508402804700536b0050470050c002824e00536b00524e005", + "0x36b00536400508e02802836b00502800702805004724e03600a005050005", + "0x502804602805b00536b00502802002800900536b005359005031028028", + "0x5900536b00505805b00736402805800536b00505800501b02805800536b", + "0x25c00536302825c00536b00505905c00702d02805c00536b005028023028", + "0x900536b00500900509202835e00536b00535e00504f02825d00536b005", + "0x935e00a00525d00536b00525d00508402800700536b0050070050c0028", + "0x536600503102802836b00501700501c02802836b00502800702825d007", + "0x2806000536b00525e00509202805e00536b00502300504f02825e00536b", + "0x504702802836b00502836902802836b0050280070280283fc00502804d", + "0x2805f00536b00503000503102802836b00501700501c02802836b005367", + "0x36b00502802002806000536b00505f00509202805e00536b00500a00504f", + "0x736402829600536b00529600501b02829600536b00502804502805d005", + "0x36b00529804200702d02804200536b00502802302829800536b00529605d", + "0x9202805e00536b00505e00504f0282bd00536b005067005363028067005", + "0x36b0052bd00508402800700536b0050070050c002806000536b005060005", + "0x36b00503100523702802836b0050280070282bd00706005e00a0052bd005", + "0x502804602806800536b00502802002806900536b005092005031028028", + "0x6f00536b00500606800736402800600536b00500600501b02800600536b", + "0x32500536302832500536b00506f07100702d02807100536b005028023028", + "0x6900536b00506900509202804f00536b00504f00504f02807400536b005", + "0x6904f00a00507400536b00507400508402800700536b0050070050c0028", + "0x36b00502802802802836b00502824c02800b00536b00502832a028074007", + "0x36b00502800702801000f0073fd09204f00736b007005028007005028028", + "0x505b02804f00536b00504f00504f0281c800536b005092005031028028", + "0x1c800509202801401304e03136b00503104f00732902803100536b005031", + "0x36b00502800702804d0053fe00a00536b0070140053260281c800536b005", + "0x509202804e00536b00504e00504f02803000536b0051c8005031028028", + "0x36b00500a00b00708502801300536b00501300505b02803000536b005030", + "0x36b00736900509502836901801703136b00501303004e03109302800a005", + "0x2801c00536b00501800503102802836b00502800702801b0053ff368005", + "0x36600509802801c00536b00501c00509202836636700736b005368005324", + "0x536b00501c00503102802836b00502800702802000540001f00536b007", + "0x500f02836500536b00536500509202836400536b00536700500a028365", + "0x536500503102802836b00502800702836300540102d02300736b007364", + "0x2802300536b00502300501302808400536b00502d0050100280c000536b", + "0x702300500f02808400536b00508400501b0280c000536b0050c0005092", + "0x536b0050c000503102802836b00502800702835f0054021aa36100736b", + "0x509202836100536b00536100501302835d00536b0051aa005010028032", + "0x736b00736100500f02835d00536b00535d00501b02803200536b005032", + "0x2803c00536b00503200503102802836b00502800702800c00540303336c", + "0x503c00509202836c00536b00536c00501302803600536b005033005010", + "0x35e04000736b00736c00500f02803600536b00503600501b02803c00536b", + "0x35e00536702802836b00504000501c02802836b005028007028359005404", + "0x501f02802836b00503600501f02802836b00508400501f02802836b005", + "0x3102802836b00500a00509602802836b00501f00532302802836b00535d", + "0x21c00536b00502836502821500536b00502802002835600536b00503c005", + "0x2802302804600536b00521c21500736402821c00536b00521c00501b028", + "0x536b00504700536302804700536b00504604800702d02804800536b005", + "0x50c002835600536b00535600509202801700536b00501700504f028045", + "0x2804500735601700a00504500536b00504500508402800700536b005007", + "0x23700536b00503c00503102802836b00535900501c02802836b005028007", + "0x52390051aa02823700536b00523700509202823900536b005028361028", + "0x702824924500740523f23b00736b00723923701703135f02823900536b", + "0x24d00536b0050840051c802824c00536b00523f00503102802836b005028", + "0x502834102824f00536b0050360051c802824e00536b00535d0051c8028", + "0x2802836b00505000532102800905000736b00525200532202825200536b", + "0x50070050c002824c00536b00524c00509202823b00536b00523b00504f", + "0x2801f00536b00501f00531e02800a00536b00500a00531f02800700536b", + "0x524f00501b02824e00536b00524e00501b02824d00536b00524d00501b", + "0x5805b00a36b00524f24e24d01f00a00900724c23b01031d02824f00536b", + "0x2802836b00502800702825d00540625c00536b00705c00531c02805c059", + "0x536b00502802002825e00536b00505800503102802836b00525c00531b", + "0x535e02802836b00506000504002805f06000736b00505e00503602805e", + "0x536b00529600535602829600536b00505d00535902805d00536b00505f", + "0x50c002825e00536b00525e00509202805b00536b00505b00504f028298", + "0x2829805925e05b00a00529800536b00529800508402805900536b005059", + "0x536b00525d00536302804200536b00505800503102802836b005028007", + "0x50c002804200536b00504200509202805b00536b00505b00504f028067", + "0x2806705904205b00a00506700536b00506700508402805900536b005059", + "0x2802836b00503600501f02802836b00508400501f02802836b005028007", + "0x2836b00500a00509602802836b00501f00532302802836b00535d00501f", + "0x36b00502804602806900536b0050280200282bd00536b005249005031028", + "0x2800600536b00506806900736402806800536b00506800501b028068005", + "0x507100536302807100536b00500606f00702d02806f00536b005028023", + "0x282bd00536b0052bd00509202824500536b00524500504f02832500536b", + "0x72bd24500a00532500536b00532500508402800700536b0050070050c0", + "0x36b00500a00509602802836b00500c00501c02802836b005028007028325", + "0x501f00532302802836b00535d00501f02802836b00508400501f028028", + "0x2804302807500536b00502802002807400536b00503200503102802836b", + "0x536b00507707500736402807700536b00507700501b02807700536b005", + "0x536302804300536b00534c34b00702d02834b00536b00502802302834c", + "0x536b00507400509202801700536b00501700504f02807a00536b005043", + "0x1700a00507a00536b00507a00508402800700536b0050070050c0028074", + "0xa00509602802836b00535f00501c02802836b00502800702807a007074", + "0x503102802836b00501f00532302802836b00508400501f02802836b005", + "0x2834800536b00502807a02807f00536b00502802002807900536b0050c0", + "0x502802302808100536b00534807f00736402834800536b00534800501b", + "0x34500536b00534600536302834600536b00508107d00702d02807d00536b", + "0x70050c002807900536b00507900509202801700536b00501700504f028", + "0x702834500707901700a00534500536b00534500508402800700536b005", + "0x32302802836b00500a00509602802836b00536300501c02802836b005028", + "0x34300536b00502802002834400536b00536500503102802836b00501f005", + "0x34234300736402834200536b00534200501b02834200536b00502805e028", + "0x8c00536b00534133d00702d02833d00536b00502802302834100536b005", + "0x34400509202801700536b00501700504f02833c00536b00508c005363028", + "0x33c00536b00533c00508402800700536b0050070050c002834400536b005", + "0x2802836b00502000504702802836b00502800702833c00734401700a005", + "0x536b00501c00503102802836b00536700523702802836b00500a005096", + "0x533a00501b02833a00536b00502804802808a00536b00502802002833b", + "0x2808800536b00502802302833900536b00533a08a00736402833a00536b", + "0x1700504f02833700536b00533800536302833800536b00533908800702d", + "0x700536b0050070050c002833b00536b00533b00509202801700536b005", + "0x2836b00502800702833700733b01700a00533700536b005337005084028", + "0x501b00536302833600536b00501800503102802836b00500a005096028", + "0x2833600536b00533600509202801700536b00501700504f02808600536b", + "0x733601700a00508600536b00508600508402800700536b0050070050c0", + "0x36b00501300523702802836b00504d00504702802836b005028007028086", + "0x502802002808e00536b0051c800503102802836b00500b00531a028028", + "0x36402833300536b00533300501b02833300536b00502804502837700536b", + "0x533233100702d02833100536b00502802302833200536b005333377007", + "0x2804e00536b00504e00504f02832f00536b00533000536302833000536b", + "0x532f00508402800700536b0050070050c002808e00536b00508e005092", + "0x503100523702802836b00502800702832f00708e04e00a00532f00536b", + "0x2802002832e00536b00501000503102802836b00500b00531a02802836b", + "0x2832c00536b00532c00501b02832c00536b00502804602832d00536b005", + "0x8b32b00702d02832b00536b00502802302808b00536b00532c32d007364", + "0xf00536b00500f00504f02832900536b00532a00536302832a00536b005", + "0x32900508402800700536b0050070050c002832e00536b00532e005092028", + "0x2824902800b00536b00502824902832900732e00f00a00532900536b005", + "0x2800700502802836b00502802802802836b00502824c02809200536b005", + "0x1000503102802836b00502800702804e1c800740701000f00736b007005", + "0x4f02802836b00502800b02801400536b00503100500a02801300536b005", + "0x36b00701400500f02801300536b00501300509202800f00536b00500f005", + "0x1800536b00501300503102802836b00502800702801700540803004d007", + "0x36800504e02836800536b0053690051c802836900536b005030005010028", + "0x36700536b00504d00501302801c00536b00501800509202801b00536b005", + "0x2836b00502800702802840900502804d02836600536b00501b005014028", + "0x502000501702802000536b00502803002801f00536b005013005031028", + "0x2836700536b00501700501302801c00536b00501f00509202836500536b", + "0x702836400540a04f00536b00736600501802836600536b005365005014", + "0x24d02802300536b00501c00503102802836b00502836902802836b005028", + "0x4f00f00707f02802300536b00502300509202804f00536b00504f092007", + "0x36b00502300503102802836b0050280070280c000540b36302d00736b007", + "0xf02808400536b00508400509202802d00536b00502d00504f028084005", + "0x8400503102802836b00502800702835f00540c1aa36100736b007367005", + "0x536b00500a00b00724d02800a00536b0051aa00501002803200536b005", + "0x536100501302802836b00502800b02835d00536b00500a0051c802800a", + "0x3336c00736b00736100500f02803200536b00503200509202836100536b", + "0x524f02803c00536b00503200503102802836b00502800702800c00540d", + "0x536b00536c00501302804000536b00503c00509202803600536b005033", + "0x36b00502800702802840e00502804d02835900536b00503600525202835e", + "0x21500505002821500536b00502803002835600536b005032005031028028", + "0x35e00536b00500c00501302804000536b00535600509202821c00536b005", + "0x2804800540f04600536b00735900500902835900536b00521c005252028", + "0x2804700536b00504000503102802836b00502836902802836b005028007", + "0x36b00535e00535e02823700536b00502802002804500536b005046005010", + "0x9202802d00536b00502d00504f02823b00536b0050450051c8028239005", + "0x36b00523700521502823900536b00523900505b02804700536b005047005", + "0x36b00523b23723904702d00b05802823b00536b00523b00501b028237005", + "0x36b00502800702824d00541024c00536b00724900505902824924523f031", + "0x9202825224f00736b00524c00505c02824e00536b005245005031028028", + "0x2800702800900541105000536b00725200525c02824e00536b00524e005", + "0x2805800536b00524f00500a02805b00536b00524e00503102802836b005", + "0x2825c00541205c05900736b00705800500f02805b00536b00505b005092", + "0x2802836b00505c00536702802836b00505900501c02802836b005028007", + "0x2836b00536300534302802836b00535d00501f02802836b005050005040", + "0x36b00502836502825e00536b00502802002825d00536b00505b005031028", + "0x2806000536b00505e25e00736402805e00536b00505e00501b02805e005", + "0x505d00536302805d00536b00506005f00702d02805f00536b005028023", + "0x2825d00536b00525d00509202823f00536b00523f00504f02829600536b", + "0x725d23f00a00529600536b00529600508402800700536b0050070050c0", + "0x36b00505b00503102802836b00525c00501c02802836b005028007028296", + "0x51aa02829800536b00529800509202804200536b005028361028298005", + "0x680690074132bd06700736b00704229823f03135f02804200536b005042", + "0x36b00505000503602800600536b0052bd00503102802836b005028007028", + "0x9202832500536b00507100535e02802836b00506f00504002807106f007", + "0x36300700600b31902806700536b00506700504f02800600536b005006005", + "0x2802836b00502800702804334b34c03141407707507403136b00732535d", + "0x507700535902807a00536b00507400503102807400536b005074005092", + "0x2806700536b00506700504f02807f00536b00507900535602807900536b", + "0x507f00508402807500536b0050750050c002807a00536b00507a005092", + "0x534c00509202802836b00502800702807f07507a06700a00507f00536b", + "0x2d02808100536b00502802302834800536b00534c00503102834c00536b", + "0x506700504f02834600536b00507d00536302807d00536b005043081007", + "0x2834b00536b00534b0050c002834800536b00534800509202806700536b", + "0x2802836b00502800702834634b34806700a00534600536b005346005084", + "0x2836b00536300534302802836b00535d00501f02802836b005050005040", + "0x36b00502804602834400536b00502802002834500536b005068005031028", + "0x2834200536b00534334400736402834300536b00534300501b028343005", + "0x533d00536302833d00536b00534234100702d02834100536b005028023", + "0x2834500536b00534500509202806900536b00506900504f02808c00536b", + "0x734506900a00508c00536b00508c00508402800700536b0050070050c0", + "0x36b00524f00523702802836b00500900504702802836b00502800702808c", + "0x524e00503102802836b00536300534302802836b00535d00501f028028", + "0x2808a00536b00533c00509202833b00536b00523f00504f02833c00536b", + "0x1f02802836b00536300534302802836b00502800702802841500502804d", + "0x536b00524d00536302833a00536b00524500503102802836b00535d005", + "0x50c002833a00536b00533a00509202823f00536b00523f00504f028339", + "0x2833900733a23f00a00533900536b00533900508402800700536b005007", + "0x1f02802836b00504800504702802836b00502836902802836b005028007", + "0x2802836b00535e00501c02802836b00536300534302802836b00535d005", + "0x508800509202833b00536b00502d00504f02808800536b005040005031", + "0x501b02833700536b00502805e02833800536b00502802002808a00536b", + "0x536b00502802302833600536b00533733800736402833700536b005337", + "0x4f02837700536b00508e00536302808e00536b00533608600702d028086", + "0x36b0050070050c002808a00536b00508a00509202833b00536b00533b005", + "0x502800702837700708a33b00a00537700536b005377005084028007005", + "0xb00506002802836b00536300534302802836b00535f00501c02802836b", + "0x4802833200536b00502802002833300536b00508400503102802836b005", + "0x36b00533133200736402833100536b00533100501b02833100536b005028", + "0x36302832e00536b00533032f00702d02832f00536b005028023028330005", + "0x36b00533300509202802d00536b00502d00504f02832d00536b00532e005", + "0xa00532d00536b00532d00508402800700536b0050070050c0028333005", + "0x506002802836b00536700501c02802836b00502800702832d00733302d", + "0x8b00536b0050c000504f02832c00536b00502300503102802836b00500b", + "0x2836b00502800702802841600502804d02832b00536b00532c005092028", + "0x2836b00536700501c02802836b00536400504702802836b005028369028", + "0x36b00501c00503102802836b00509200506002802836b00500b005060028", + "0x2002832b00536b00532a00509202808b00536b00500f00504f02832a005", + "0x32600536b00532600501b02832600536b00502804502832900536b005028", + "0x9300702d02809300536b00502802302808500536b005326329007364028", + "0x536b00508b00504f02832400536b00509500536302809500536b005085", + "0x508402800700536b0050070050c002832b00536b00532b00509202808b", + "0x506002802836b00502800702832400732b08b00a00532400536b005324", + "0x3102802836b00503100523702802836b00500b00506002802836b005092", + "0x9600536b00502804602832300536b00502802002809800536b00504e005", + "0x2802302832200536b00509632300736402809600536b00509600501b028", + "0x536b00531f00536302831f00536b00532232100702d02832100536b005", + "0x50c002809800536b0050980050920281c800536b0051c800504f02831e", + "0x2831e0070981c800a00531e00536b00531e00508402800700536b005007", + "0x2809204f00741700b00a00736b00700502800700502802836b005028028", + "0x536b00503100500a02800f00536b00500b00503102802836b005028007", + "0x500f00509202800a00536b00500a00504f02802836b00502800b028010", + "0x36b00502800702801300541804e1c800736b00701000500f02800f00536b", + "0x51c802804d00536b00504e00501002801400536b00500f005031028028", + "0x536b00501400509202801700536b00503000504e02803000536b00504d", + "0x2804d02836800536b00501700501402836900536b0051c8005013028018", + "0x2803002801b00536b00500f00503102802836b005028007028028419005", + "0x1800536b00501b00509202836700536b00501c00501702801c00536b005", + "0x36800501802836800536b00536700501402836900536b005013005013028", + "0x2802836b00502836902802836b00502800702801f00541a36600536b007", + "0x36600a00707f02802000536b00502000509202802000536b005018005031", + "0x36b00502000503102802836b00502800702802300541b36436500736b007", + "0xf02802d00536b00502d00509202836500536b00536500504f02802d005", + "0x2d00503102802836b00502800702808400541c0c036300736b007369005", + "0x36300536b0053630050130281aa00536b0050c000501002836100536b005", + "0x36300500f0281aa00536b0051aa00501b02836100536b005361005092028", + "0x36b00536100503102802836b00502800702835d00541d03235f00736b007", + "0x9202835f00536b00535f00501302803300536b00503200501002836c005", + "0x36b00735f00500f02803300536b00503300501b02836c00536b00536c005", + "0x4000536b00536c00503102802836b00502800702803600541e03c00c007", + "0x4000509202800c00536b00500c00501302835e00536b00503c005010028", + "0x35900736b00700c00500f02835e00536b00535e00501b02804000536b005", + "0x1002821c00536b00504000503102802836b00502800702821500541f356", + "0x36b00521c00509202835900536b00535900501302804600536b005356005", + "0x42004704800736b00735900500f02804600536b00504600501b02821c005", + "0x504700536702802836b00504800501c02802836b005028007028045005", + "0x35e00501f02802836b00504600501f02802836b0051aa00501f02802836b", + "0x503102802836b00536400534302802836b00503300501f02802836b005", + "0x2823b00536b00502836502823900536b00502802002823700536b00521c", + "0x502802302823f00536b00523b23900736402823b00536b00523b00501b", + "0x24c00536b00524900536302824900536b00523f24500702d02824500536b", + "0x70050c002823700536b00523700509202836500536b00536500504f028", + "0x702824c00723736500a00524c00536b00524c00508402800700536b005", + "0x2824d00536b00521c00503102802836b00504500501c02802836b005028", + "0x36b00524e0051aa02824d00536b00524d00509202824e00536b005028361", + "0x2800702800905000742125224f00736b00724e24d36503135f02824e005", + "0x2805800536b0051aa0051c802805b00536b00525200503102802836b005", + "0x50460051c802805c00536b00535e0051c802805900536b0050330051c8", + "0x2805e25e00736b00525d00532202825d00536b00502834102825c00536b", + "0x36b0050070050c002805b00536b00505b00509202802836b00525e005321", + "0x1b02805800536b00505800501b02836400536b00536400533d028007005", + "0x36b00525c00501b02805c00536b00505c00501b02805900536b005059005", + "0x2805d05f06003136b00525c05c05905836405e00705b00f31802825c005", + "0x505f0050c002806000536b00506000509202824f00536b00524f00504f", + "0x2800702805d05f06024f00a00505d00536b00505d00508402805f00536b", + "0x501f02802836b00504600501f02802836b0051aa00501f02802836b005", + "0x3102802836b00536400534302802836b00503300501f02802836b00535e", + "0x4200536b00502804602829800536b00502802002829600536b005009005", + "0x2802302806700536b00504229800736402804200536b00504200501b028", + "0x536b00506900536302806900536b0050672bd00702d0282bd00536b005", + "0x50c002829600536b00529600509202805000536b00505000504f028068", + "0x2806800729605000a00506800536b00506800508402800700536b005007", + "0x2802836b00536400534302802836b00521500501c02802836b005028007", + "0x2836b00503300501f02802836b00535e00501f02802836b0051aa00501f", + "0x36b00502804302806f00536b00502802002800600536b005040005031028", + "0x2832500536b00507106f00736402807100536b00507100501b028071005", + "0x507500536302807500536b00532507400702d02807400536b005028023", + "0x2800600536b00500600509202836500536b00536500504f02807700536b", + "0x700636500a00507700536b00507700508402800700536b0050070050c0", + "0x36b00536400534302802836b00503600501c02802836b005028007028077", + "0x536c00503102802836b00503300501f02802836b0051aa00501f028028", + "0x501b02804300536b00502807a02834b00536b00502802002834c00536b", + "0x536b00502802302807a00536b00504334b00736402804300536b005043", + "0x4f02834800536b00507f00536302807f00536b00507a07900702d028079", + "0x36b0050070050c002834c00536b00534c00509202836500536b005365005", + "0x502800702834800734c36500a00534800536b005348005084028007005", + "0x1aa00501f02802836b00536400534302802836b00535d00501c02802836b", + "0x5e02807d00536b00502802002808100536b00536100503102802836b005", + "0x36b00534607d00736402834600536b00534600501b02834600536b005028", + "0x36302834300536b00534534400702d02834400536b005028023028345005", + "0x36b00508100509202836500536b00536500504f02834200536b005343005", + "0xa00534200536b00534200508402800700536b0050070050c0028081005", + "0x534302802836b00508400501c02802836b005028007028342007081365", + "0x2833d00536b00502802002834100536b00502d00503102802836b005364", + "0x508c33d00736402808c00536b00508c00501b02808c00536b005028048", + "0x2808a00536b00533c33b00702d02833b00536b00502802302833c00536b", + "0x534100509202836500536b00536500504f02833a00536b00508a005363", + "0x533a00536b00533a00508402800700536b0050070050c002834100536b", + "0x3102802836b00536900501c02802836b00502800702833a00734136500a", + "0x36b00533900509202808800536b00502300504f02833900536b005020005", + "0x2836b00502836902802836b00502800702802842200502804d028338005", + "0x36b00501800503102802836b00536900501c02802836b00501f005047028", + "0x2002833800536b00533700509202808800536b00500a00504f028337005", + "0x8600536b00508600501b02808600536b00502804502833600536b005028", + "0x37700702d02837700536b00502802302808e00536b005086336007364028", + "0x536b00508800504f02833200536b00533300536302833300536b00508e", + "0x508402800700536b0050070050c002833800536b005338005092028088", + "0x523702802836b00502800702833200733808800a00533200536b005332", + "0x2833000536b00502802002833100536b00509200503102802836b005031", + "0x532f33000736402832f00536b00532f00501b02832f00536b005028046", + "0x2832c00536b00532e32d00702d02832d00536b00502802302832e00536b", + "0x533100509202804f00536b00504f00504f02808b00536b00532c005363", + "0x508b00536b00508b00508402800700536b0050070050c002833100536b", + "0xa00736b00700502800700502802836b00502802802808b00733104f00a", + "0x2800f00536b00500b00503102802836b00502800702809204f00742300b", + "0x536b00500a00504f02802836b00502800b02801000536b00503100500a", + "0x542404e1c800736b00701000500f02800f00536b00500f00509202800a", + "0x504e00501002801400536b00500f00503102802836b005028007028013", + "0x2801700536b00503000504e02803000536b00504d0051c802804d00536b", + "0x501700501402836900536b0051c800501302801800536b005014005092", + "0x500f00503102802836b00502800702802842500502804d02836800536b", + "0x9202836700536b00501c00501702801c00536b00502803002801b00536b", + "0x36b00536700501402836900536b00501300501302801800536b00501b005", + "0x2802836b00502800702801f00542636600536b007368005018028368005", + "0x536b00502000509202802000536b00501800503102802836b005028369", + "0x2836b00502800702802300542736436500736b00736600a00707f028020", + "0x2d00509202836500536b00536500504f02802d00536b005020005031028", + "0x50280070280840054280c036300736b00736900500f02802d00536b005", + "0x36400534302802836b0050c000536702802836b00536300501c02802836b", + "0x3650281aa00536b00502802002836100536b00502d00503102802836b005", + "0x36b00535f1aa00736402835f00536b00535f00501b02835f00536b005028", + "0x36302836c00536b00503235d00702d02835d00536b005028023028032005", + "0x36b00536100509202836500536b00536500504f02803300536b00536c005", + "0xa00503300536b00503300508402800700536b0050070050c0028361005", + "0x503102802836b00508400501c02802836b005028007028033007361365", + "0xc00536b00500c00509202803c00536b00502836102800c00536b00502d", + "0x42904003600736b00703c00c36503135f02803c00536b00503c0051aa028", + "0x509202835600536b00504000503102802836b00502800702835935e007", + "0x736400735603131702803600536b00503600504f02835600536b005356", + "0x521500509202802836b00502800702804704804603142a21c21500736b", + "0x3602823700536b00502802002804500536b00521500503102821500536b", + "0x36b00523b00535e02802836b00523900504002823b23900736b005237005", + "0x4f02824900536b00524500535602824500536b00523f00535902823f005", + "0x36b00521c0050c002804500536b00504500509202803600536b005036005", + "0x502800702824921c04503600a00524900536b00524900508402821c005", + "0x2302824c00536b00504600503102804600536b00504600509202802836b", + "0x36b00524e00536302824e00536b00504724d00702d02824d00536b005028", + "0xc002824c00536b00524c00509202803600536b00503600504f02824f005", + "0x24f04824c03600a00524f00536b00524f00508402804800536b005048005", + "0x536b00535900503102802836b00536400534302802836b005028007028", + "0x500900501b02800900536b00502804602805000536b005028020028252", + "0x2805800536b00502802302805b00536b00500905000736402800900536b", + "0x35e00504f02805c00536b00505900536302805900536b00505b05800702d", + "0x700536b0050070050c002825200536b00525200509202835e00536b005", + "0x2836b00502800702805c00725235e00a00505c00536b00505c005084028", + "0x502300504f02825c00536b00502000503102802836b00536900501c028", + "0x2800702802842b00502804d02825e00536b00525c00509202825d00536b", + "0x36900501c02802836b00501f00504702802836b00502836902802836b005", + "0x2825d00536b00500a00504f02805e00536b00501800503102802836b005", + "0x536b00502804502806000536b00502802002825e00536b00505e005092", + "0x2302805d00536b00505f06000736402805f00536b00505f00501b02805f", + "0x36b00529800536302829800536b00505d29600702d02829600536b005028", + "0xc002825e00536b00525e00509202825d00536b00525d00504f028042005", + "0x4200725e25d00a00504200536b00504200508402800700536b005007005", + "0x536b00509200503102802836b00503100523702802836b005028007028", + "0x506900501b02806900536b0050280460282bd00536b005028020028067", + "0x2800600536b00502802302806800536b0050692bd00736402806900536b", + "0x4f00504f02807100536b00506f00536302806f00536b00506800600702d", + "0x700536b0050070050c002806700536b00506700509202804f00536b005", + "0x536b00502824902807100706704f00a00507100536b005071005084028", + "0x36b00700502800700502802836b00502802802802836b00502824c02800b", + "0x536b00509200503102802836b00502800702801000f00742c09204f007", + "0x509202804f00536b00504f00504f02804e00536b00503100500a0281c8", + "0x2800702804d00542d01401300736b00704e00500f0281c800536b0051c8", + "0x2800a00536b00501400501002803000536b0051c800503102802836b005", + "0x502800b02801700536b00500a0051c802800a00536b00500a00b00724d", + "0xf02803000536b00503000509202801300536b00501300501302802836b", + "0x3000503102802836b00502800702836800542e36901800736b007013005", + "0x36700536b00501b00509202801c00536b00536900524f02801b00536b005", + "0x502804d02801f00536b00501c00525202836600536b005018005013028", + "0x502803002802000536b00503000503102802836b00502800702802842f", + "0x2836700536b00502000509202836400536b00536500505002836500536b", + "0x701f00500902801f00536b00536400525202836600536b005368005013", + "0x3102802836b00502836902802836b00502800702802d00543002300536b", + "0x536b0050280200280c000536b00502300501002836300536b005367005", + "0x504f0281aa00536b0050c00051c802836100536b00536600535e028084", + "0x536b00536100505b02836300536b00536300509202804f00536b00504f", + "0xb0580281aa00536b0051aa00501b02808400536b005084005215028361", + "0x43136c00536b00735d00505902835d03235f03136b0051aa08436136304f", + "0x36c00505c02800c00536b00503200503102802836b005028007028033005", + "0x536b00703600525c02800c00536b00500c00509202803603c00736b005", + "0xa02835900536b00500c00503102802836b00502800702835e005432040", + "0x36b00735600500f02835900536b00535900509202835600536b00503c005", + "0x2802836b00521500501c02802836b00502800702804600543321c215007", + "0x2836b00501700501f02802836b00504000504002802836b00521c005367", + "0x36b00502836502804700536b00502802002804800536b005359005031028", + "0x2823700536b00504504700736402804500536b00504500501b028045005", + "0x523b00536302823b00536b00523723900702d02823900536b005028023", + "0x2804800536b00504800509202835f00536b00535f00504f02823f00536b", + "0x704835f00a00523f00536b00523f00508402800700536b0050070050c0", + "0x36b00535900503102802836b00504600501c02802836b00502800702823f", + "0x51aa02824500536b00524500509202824900536b005028361028245005", + "0x24f24e00743424d24c00736b00724924535f03135f02824900536b005249", + "0x36b00504000503602825200536b00524d00503102802836b005028007028", + "0x9202805b00536b00500900535e02802836b005050005040028009050007", + "0x1700725200a31602824c00536b00524c00504f02825200536b005252005", + "0x509202802836b00502800702825d25c05c03143505905800736b00705b", + "0x5e00536b00502802002825e00536b00505800503102805800536b005058", + "0x5f00535e02802836b00506000504002805f06000736b00505e005036028", + "0x29800536b00529600535602829600536b00505d00535902805d00536b005", + "0x590050c002825e00536b00525e00509202824c00536b00524c00504f028", + "0x702829805925e24c00a00529800536b00529800508402805900536b005", + "0x4200536b00505c00503102805c00536b00505c00509202802836b005028", + "0x2bd0053630282bd00536b00525d06700702d02806700536b005028023028", + "0x4200536b00504200509202824c00536b00524c00504f02806900536b005", + "0x4224c00a00506900536b00506900508402825c00536b00525c0050c0028", + "0x501700501f02802836b00504000504002802836b00502800702806925c", + "0x2804602800600536b00502802002806800536b00524f00503102802836b", + "0x536b00506f00600736402806f00536b00506f00501b02806f00536b005", + "0x536302807400536b00507132500702d02832500536b005028023028071", + "0x536b00506800509202824e00536b00524e00504f02807500536b005074", + "0x24e00a00507500536b00507500508402800700536b0050070050c0028068", + "0x3c00523702802836b00535e00504702802836b005028007028075007068", + "0x4f02807700536b00500c00503102802836b00501700501f02802836b005", + "0x2843600502804d02834b00536b00507700509202834c00536b00535f005", + "0x536b00503200503102802836b00501700501f02802836b005028007028", + "0x509202835f00536b00535f00504f02807a00536b005033005363028043", + "0x536b00507a00508402800700536b0050070050c002804300536b005043", + "0x2802836b00502836902802836b00502800702807a00704335f00a00507a", + "0x2836b00536600501c02802836b00501700501f02802836b00502d005047", + "0x7900509202834c00536b00504f00504f02807900536b005367005031028", + "0x1b02834800536b00502804802807f00536b00502802002834b00536b005", + "0x36b00502802302808100536b00534807f00736402834800536b005348005", + "0x2834500536b00534600536302834600536b00508107d00702d02807d005", + "0x50070050c002834b00536b00534b00509202834c00536b00534c00504f", + "0x2800702834500734b34c00a00534500536b00534500508402800700536b", + "0x503102802836b00500b00506002802836b00504d00501c02802836b005", + "0x2834200536b00502804502834300536b00502802002834400536b0051c8", + "0x502802302834100536b00534234300736402834200536b00534200501b", + "0x33c00536b00508c00536302808c00536b00534133d00702d02833d00536b", + "0x70050c002834400536b00534400509202804f00536b00504f00504f028", + "0x702833c00734404f00a00533c00536b00533c00508402800700536b005", + "0x3102802836b00500b00506002802836b00503100523702802836b005028", + "0x33a00536b00502804602808a00536b00502802002833b00536b005010005", + "0x2802302833900536b00533a08a00736402833a00536b00533a00501b028", + "0x536b00533800536302833800536b00533908800702d02808800536b005", + "0x50c002833b00536b00533b00509202800f00536b00500f00504f028337", + "0x2833700733b00f00a00533700536b00533700508402800700536b005007", + "0x2800f09200743704f00b00736b00700702800700502802836b005028028", + "0x536b00500a00500a02801000536b00504f00503102802836b005028007", + "0x500f02801000536b00501000509202800b00536b00500b00504f0281c8", + "0x504e00501c02802836b00502800702801400543801304e00736b0071c8", + "0x2802002804d00536b00501000503102802836b00501300536702802836b", + "0x2801700536b00501700501b02801700536b00502836502803000536b005", + "0x1836900702d02836900536b00502802302801800536b005017030007364", + "0xb00536b00500b00504f02801b00536b00536800536302836800536b005", + "0x310050c002804d00536b00504d00509202800500536b005005005314028", + "0x2801b03104d00500b00b00501b00536b00501b00508402803100536b005", + "0x1c00536b00501000503102802836b00501400501c02802836b005028007", + "0x53670051aa02801c00536b00501c00509202836700536b005028361028", + "0x702836502000743901f36600736b00736701c00b03135f02836700536b", + "0x2300736b00500500531302836400536b00501f00503102802836b005028", + "0x509202802300536b00502300531402836600536b00536600504f02802d", + "0x2d36402336600a0a902802d00536b00502d00531102836400536b005364", + "0x536b00502802002802836b0053610053100283610840c036300a36b005", + "0x535e02802836b00535f00504002803235f00736b0051aa0050360281aa", + "0x536b00536c00535602836c00536b00535d00535902835d00536b005032", + "0x50920280c000536b0050c000531402836300536b00536300504f028033", + "0x536b00503300508402803100536b0050310050c002808400536b005084", + "0x36b00536500503102802836b0050280070280330310840c036300b005033", + "0x3600501b02803600536b00502804602803c00536b00502802002800c005", + "0x35e00536b00502802302804000536b00503603c00736402803600536b005", + "0x504f02835600536b00535900536302835900536b00504035e00702d028", + "0x536b00500c00509202800500536b00500500531402802000536b005020", + "0x2000b00535600536b00535600508402803100536b0050310050c002800c", + "0x503102802836b00500a00523702802836b00502800702835603100c005", + "0x2804600536b00502804602821c00536b00502802002821500536b00500f", + "0x502802302804800536b00504621c00736402804600536b00504600501b", + "0x23700536b00504500536302804500536b00504804700702d02804700536b", + "0x21500509202800500536b00500500531402809200536b00509200504f028", + "0x23700536b00523700508402803100536b0050310050c002821500536b005", + "0x536b00502824902800b00536b00502824902823703121500509200b005", + "0x36b00700502800700502802836b00502802802802836b00502824c028092", + "0x536b00501000503102802836b00502800702804e1c800743a01000f007", + "0x500f00504f02802836b00502800b02801400536b00503100500a028013", + "0x3004d00736b00701400500f02801300536b00501300509202800f00536b", + "0x501002801800536b00501300503102802836b00502800702801700543b", + "0x536b00536800504e02836800536b0053690051c802836900536b005030", + "0x501402836700536b00504d00501302801c00536b00501800509202801b", + "0x503102802836b00502800702802843c00502804d02836600536b00501b", + "0x36500536b00502000501702802000536b00502803002801f00536b005013", + "0x36500501402836700536b00501700501302801c00536b00501f005092028", + "0x36b00502800702836400543d04f00536b00736600501802836600536b005", + "0x4f09200724d02802300536b00501c00503102802836b005028369028028", + "0x736b00704f00f00707f02802300536b00502300509202804f00536b005", + "0x2808400536b00502300503102802836b0050280070280c000543e36302d", + "0x736700500f02808400536b00508400509202802d00536b00502d00504f", + "0x536b00508400503102802836b00502800702835f00543f1aa36100736b", + "0x1c802800a00536b00500a00b00724d02800a00536b0051aa005010028032", + "0x36100536b00536100501302802836b00502800b02835d00536b00500a005", + "0xc00544003336c00736b00736100500f02803200536b005032005092028", + "0x36b00503300524f02803c00536b00503200503102802836b005028007028", + "0x25202835e00536b00536c00501302804000536b00503c005092028036005", + "0x3102802836b00502800702802844100502804d02835900536b005036005", + "0x536b00521500505002821500536b00502803002835600536b005032005", + "0x525202835e00536b00500c00501302804000536b00535600509202821c", + "0x502800702804800544204600536b00735900500902835900536b00521c", + "0x2002804500536b00504600501002804700536b00504000503102802836b", + "0x536b0050450051c802823900536b00535e00535e02823700536b005028", + "0x505b02804700536b00504700509202802d00536b00502d00504f02823b", + "0x536b00523b00501b02823700536b00523700521502823900536b005239", + "0x724900505902824924523f03136b00523b23723904702d00b05802823b", + "0x24e00536b00524500503102802836b00502800702824d00544324c00536b", + "0x525c02824e00536b00524e00509202825224f00736b00524c00505c028", + "0x36b00524e00503102802836b00502800702800900544405000536b007252", + "0xf02805b00536b00505b00509202805800536b00524f00500a02805b005", + "0x5b00503102802836b00502800702825c00544505c05900736b007058005", + "0x5e00536b00525e0051c802825e00536b00505c00501002825d00536b005", + "0x36b00505900501302805e00536b00505e00501b02802836b00502800b028", + "0x6000544602836b00705e00534802825d00536b00525d005092028059005", + "0x536b00502803002805f00536b00525d00503102802836b005028007028", + "0x507d02829800536b00505f00509202829600536b00505d00508102805d", + "0x534602802836b00502800702802844700502804d02804200536b005296", + "0x282bd00536b00502803002806700536b00525d00503102802836b005060", + "0x506900507d02829800536b00506700509202806900536b0052bd005345", + "0x36b00502800702806f00544800606800736b00705900500f02804200536b", + "0x36b00500600536702802836b00506800501c02802836b005028369028028", + "0x535d00501f02802836b00504200534402802836b005050005040028028", + "0x2802002807100536b00529800503102802836b00536300534302802836b", + "0x2807400536b00507400501b02807400536b00502836502832500536b005", + "0x7507700702d02807700536b00502802302807500536b005074325007364", + "0x23f00536b00523f00504f02834b00536b00534c00536302834c00536b005", + "0x34b00508402800700536b0050070050c002807100536b005071005092028", + "0x6f00501c02802836b00502800702834b00707123f00a00534b00536b005", + "0x9202807a00536b00502836102804300536b00529800503102802836b005", + "0x7a04323f03135f02807a00536b00507a0051aa02804300536b005043005", + "0x36b00502836902802836b00502800702808134800744907f07900736b007", + "0x503602834600536b00504200534202807d00536b00507f005031028028", + "0x536b00534400535e02802836b00534500504002834434500736b005050", + "0x504f02834600536b00534600507d02807d00536b00507d005092028343", + "0x33d34134200a36b00734634335d36300707d04f0b002807900536b005079", + "0x2802836b00533d00525d02802836b00502800702808a33b33c03144a08c", + "0x36b00534200503102834200536b00534200509202802836b00508c005237", + "0x4002833808800736b00533900503602833900536b00502802002833a005", + "0x536b00533700535902833700536b00533800535e02802836b005088005", + "0x509202807900536b00507900504f02808600536b005336005356028336", + "0x536b00508600508402834100536b0053410050c002833a00536b00533a", + "0x536b00533c00509202802836b00502800702808634133a07900a005086", + "0x37700702d02837700536b00502802302808e00536b00533c00503102833c", + "0x536b00507900504f02833200536b00533300536302833300536b00508a", + "0x508402833b00536b00533b0050c002808e00536b00508e005092028079", + "0x2836902802836b00502800702833233b08e07900a00533200536b005332", + "0x501f02802836b00504200534402802836b00505000504002802836b005", + "0x2833100536b00508100503102802836b00536300534302802836b00535d", + "0x536b00532f00501b02832f00536b00502804602833000536b005028020", + "0x702d02832d00536b00502802302832e00536b00532f33000736402832f", + "0x36b00534800504f02808b00536b00532c00536302832c00536b00532e32d", + "0x8402800700536b0050070050c002833100536b005331005092028348005", + "0x1c02802836b00502800702808b00733134800a00508b00536b00508b005", + "0x2802836b00505000504002802836b00536300534302802836b00525c005", + "0x536b00502802002832b00536b00505b00503102802836b00535d00501f", + "0x32a00736402832900536b00532900501b02832900536b00502807a02832a", + "0x536b00532608500702d02808500536b00502802302832600536b005329", + "0x509202823f00536b00523f00504f02809500536b005093005363028093", + "0x536b00509500508402800700536b0050070050c002832b00536b00532b", + "0x2836b00500900504702802836b00502800702809500732b23f00a005095", + "0x36b00535d00501f02802836b00524f00523702802836b005363005343028", + "0x509202809800536b00523f00504f02832400536b00524e005031028028", + "0x534302802836b00502800702802844b00502804d02832300536b005324", + "0x2809600536b00524500503102802836b00535d00501f02802836b005363", + "0x509600509202823f00536b00523f00504f02832200536b00524d005363", + "0x532200536b00532200508402800700536b0050070050c002809600536b", + "0x504702802836b00502836902802836b00502800702832200709623f00a", + "0x1c02802836b00536300534302802836b00535d00501f02802836b005048", + "0x536b00502d00504f02832100536b00504000503102802836b00535e005", + "0x502805e02831f00536b00502802002832300536b005321005092028098", + "0x31d00536b00531e31f00736402831e00536b00531e00501b02831e00536b", + "0x31b00536302831b00536b00531d31c00702d02831c00536b005028023028", + "0x32300536b00532300509202809800536b00509800504f02831a00536b005", + "0x32309800a00531a00536b00531a00508402800700536b0050070050c0028", + "0x536300534302802836b00535f00501c02802836b00502800702831a007", + "0x2802002831900536b00508400503102802836b00500b00506002802836b", + "0x2831700536b00531700501b02831700536b00502804802831800536b005", + "0x31631400702d02831400536b00502802302831600536b005317318007364", + "0x2d00536b00502d00504f02831100536b00531300536302831300536b005", + "0x31100508402800700536b0050070050c002831900536b005319005092028", + "0x36700501c02802836b00502800702831100731902d00a00531100536b005", + "0x4f0280a900536b00502300503102802836b00500b00506002802836b005", + "0x2844c00502804d0280b000536b0050a900509202831000536b0050c0005", + "0x2802836b00536400504702802836b00502836902802836b005028007028", + "0x2836b00509200506002802836b00500b00506002802836b00536700501c", + "0xac00509202831000536b00500f00504f0280ac00536b00501c005031028", + "0x1b02830d00536b00502804502830f00536b0050280200280b000536b005", + "0x36b0050280230280b400536b00530d30f00736402830d00536b00530d005", + "0x280b900536b00530b00536302830b00536b0050b40b600702d0280b6005", + "0x50070050c00280b000536b0050b000509202831000536b00531000504f", + "0x280070280b90070b031000a0050b900536b0050b900508402800700536b", + "0x523702802836b00500b00506002802836b00509200506002802836b005", + "0x2830800536b00502802002830900536b00504e00503102802836b005031", + "0x530730800736402830700536b00530700501b02830700536b005028046", + "0x280bf00536b00530630500702d02830500536b00502802302830600536b", + "0x53090050920281c800536b0051c800504f02830400536b0050bf005363", + "0x530400536b00530400508402800700536b0050070050c002830900536b", + "0xa00736b00700502800700502802836b0050280280283040073091c800a", + "0x2800f00536b00500b00503102802836b00502800702809204f00744d00b", + "0x536b00500a00504f02802836b00502800b02801000536b00503100500a", + "0x544e04e1c800736b00701000500f02800f00536b00500f00509202800a", + "0x504e00524f02801400536b00500f00503102802836b005028007028013", + "0x2801700536b0051c800501302803000536b00501400509202804d00536b", + "0x2802836b00502800702802844f00502804d02801800536b00504d005252", + "0x36b00536800505002836800536b00502803002836900536b00500f005031", + "0x25202801700536b00501300501302803000536b00536900509202801b005", + "0x2800702836700545001c00536b00701800500902801800536b00501b005", + "0x501002836600536b00503000503102802836b00502836902802836b005", + "0x536b00502000501b02802000536b00501f0051c802801f00536b00501c", + "0x45136436500736b00702000a0070ac02836600536b005366005092028020", + "0x4f0280c000536b00536600503102802836b00502800702836302d023031", + "0x36b00701700500f0280c000536b0050c000509202836500536b005365005", + "0x2802836b00508400501c02802836b0050280070281aa005452361084007", + "0x536b0050c000503102802836b00536400530f02802836b005361005367", + "0x535d00501b02835d00536b00502836502803200536b00502802002835f", + "0x2803300536b00502802302836c00536b00535d03200736402835d00536b", + "0x36500504f02803c00536b00500c00536302800c00536b00536c03300702d", + "0x700536b0050070050c002835f00536b00535f00509202836500536b005", + "0x2836b00502800702803c00735f36500a00503c00536b00503c005084028", + "0x36b00502836102803600536b0050c000503102802836b0051aa00501c028", + "0x35f02804000536b0050400051aa02803600536b005036005092028040005", + "0x2802836b00502800702821535600745335935e00736b007040036365031", + "0x521c00509202835e00536b00535e00504f02821c00536b005359005031", + "0x3136b00536421c35e0310b402836400536b00536400530d02821c00536b", + "0x2836b00502800702823700545404500536b0070470050b6028047048046", + "0x504500530b02823b00536b00502802002823900536b005048005031028", + "0x24900536b00524523b00736402824500536b00523f0050b902823f00536b", + "0x24d00535e02802836b00524c00504002824d24c00736b005249005036028", + "0x25200536b00524f00535602824f00536b00524e00535902824e00536b005", + "0x70050c002823900536b00523900509202804600536b00504600504f028", + "0x702825200723904600a00525200536b00525200508402800700536b005", + "0x900536b00523700536302805000536b00504800503102802836b005028", + "0x70050c002805000536b00505000509202804600536b00504600504f028", + "0x702800900705004600a00500900536b00500900508402800700536b005", + "0x2805b00536b00521500503102802836b00536400530f02802836b005028", + "0x536b00505900501b02805900536b00502804602805800536b005028020", + "0x702d02825c00536b00502802302805c00536b005059058007364028059", + "0x36b00535600504f02825e00536b00525d00536302825d00536b00505c25c", + "0x8402800700536b0050070050c002805b00536b00505b005092028356005", + "0x30f02802836b00502800702825e00705b35600a00525e00536b00525e005", + "0x2802836b00501700501c02802836b00536300530f02802836b00502d005", + "0x505e00509202806000536b00502300504f02805e00536b005366005031", + "0x36b00502836902802836b00502800702802845500502804d02805f00536b", + "0x503000503102802836b00501700501c02802836b005367005047028028", + "0x2805f00536b00505d00509202806000536b00500a00504f02805d00536b", + "0x536b00529800501b02829800536b00502804502829600536b005028020", + "0x702d02806700536b00502802302804200536b005298296007364028298", + "0x36b00506000504f02806900536b0052bd0053630282bd00536b005042067", + "0x8402800700536b0050070050c002805f00536b00505f005092028060005", + "0x23702802836b00502800702806900705f06000a00506900536b005069005", + "0x600536b00502802002806800536b00509200503102802836b005031005", + "0x6f00600736402806f00536b00506f00501b02806f00536b005028046028", + "0x7400536b00507132500702d02832500536b00502802302807100536b005", + "0x6800509202804f00536b00504f00504f02807500536b005074005363028", + "0x7500536b00507500508402800700536b0050070050c002806800536b005", + "0x736b00700502800700502802836b00502802802807500706804f00a005", + "0xf00536b00500b00503102802836b00502800702809204f00745600b00a", + "0xf00509202800a00536b00500a00504f02801000536b00503100500a028", + "0x502800702801300545704e1c800736b00701000500f02800f00536b005", + "0xf00503102802836b00504e00536702802836b0051c800501c02802836b", + "0x1b02803000536b00502836502804d00536b00502802002801400536b005", + "0x36b00502802302801700536b00503004d00736402803000536b005030005", + "0x2836800536b00536900536302836900536b00501701800702d028018005", + "0x50070050c002801400536b00501400509202800a00536b00500a00504f", + "0x2800702836800701400a00a00536800536b00536800508402800700536b", + "0x36102801b00536b00500f00503102802836b00501300501c02802836b005", + "0x536b00501c0051aa02801b00536b00501b00509202801c00536b005028", + "0x502800702802001f00745836636700736b00701c01b00a03135f02801c", + "0x504f02836400536b00502834102836500536b00536600503102802836b", + "0x536b0050070050c002836500536b00536500509202836700536b005367", + "0x70c000533c0280c036302d02300a36b00536400736536700a309028007", + "0x2802836b00508400533b02802836b00502800702836100545908400536b", + "0x36b00535f00503602835f00536b0050280200281aa00536b00502d005031", + "0x35902836c00536b00535d00535e02802836b00503200504002835d032007", + "0x36b00502300504f02800c00536b00503300535602803300536b00536c005", + "0x8402836300536b0053630050c00281aa00536b0051aa005092028023005", + "0x3102802836b00502800702800c3631aa02300a00500c00536b00500c005", + "0x36b00502300504f02803600536b00536100536302803c00536b00502d005", + "0x8402836300536b0053630050c002803c00536b00503c005092028023005", + "0x3102802836b00502800702803636303c02300a00503600536b005036005", + "0x35900536b00502804602835e00536b00502802002804000536b005020005", + "0x2802302835600536b00535935e00736402835900536b00535900501b028", + "0x536b00521c00536302821c00536b00535621500702d02821500536b005", + "0x50c002804000536b00504000509202801f00536b00501f00504f028046", + "0x2804600704001f00a00504600536b00504600508402800700536b005007", + "0x4800536b00509200503102802836b00503100523702802836b005028007", + "0x36b00504500501b02804500536b00502804602804700536b005028020028", + "0x2d02823900536b00502802302823700536b005045047007364028045005", + "0x504f00504f02823f00536b00523b00536302823b00536b005237239007", + "0x2800700536b0050070050c002804800536b00504800509202804f00536b", + "0x2802836b00502802802823f00704804f00a00523f00536b00523f005084", + "0x2802836b00502800702809204f00745a00b00a00736b007005028007005", + "0x500a00504f02801000536b00503100500a02800f00536b00500b005031", + "0x4e1c800736b00701000500f02800f00536b00500f00509202800a00536b", + "0x4e00536702802836b0051c800501c02802836b00502800702801300545b", + "0x36502804d00536b00502802002801400536b00500f00503102802836b005", + "0x36b00503004d00736402803000536b00503000501b02803000536b005028", + "0x36302836900536b00501701800702d02801800536b005028023028017005", + "0x36b00501400509202800a00536b00500a00504f02836800536b005369005", + "0xa00536800536b00536800508402800700536b0050070050c0028014005", + "0x503102802836b00501300501c02802836b00502800702836800701400a", + "0x1b00536b00501b00509202801c00536b00502836102801b00536b00500f", + "0x45c36636700736b00701c01b00a03135f02801c00536b00501c0051aa028", + "0x2834102836500536b00536600503102802836b00502800702802001f007", + "0x36500536b00536500509202836700536b00536700504f02836400536b005", + "0x2d02300a36b00536400736536700a30802800700536b0050070050c0028", + "0x2802836b00502800702836100545d08400536b0070c000533c0280c0363", + "0x536b0050280200281aa00536b00502d00503102802836b00508400533b", + "0x535e02802836b00503200504002835d03200736b00535f00503602835f", + "0x536b00503300535602803300536b00536c00535902836c00536b00535d", + "0x50c00281aa00536b0051aa00509202802300536b00502300504f02800c", + "0x2800c3631aa02300a00500c00536b00500c00508402836300536b005363", + "0x536b00536100536302803c00536b00502d00503102802836b005028007", + "0x50c002803c00536b00503c00509202802300536b00502300504f028036", + "0x2803636303c02300a00503600536b00503600508402836300536b005363", + "0x35e00536b00502802002804000536b00502000503102802836b005028007", + "0x35935e00736402835900536b00535900501b02835900536b005028046028", + "0x21c00536b00535621500702d02821500536b00502802302835600536b005", + "0x4000509202801f00536b00501f00504f02804600536b00521c005363028", + "0x4600536b00504600508402800700536b0050070050c002804000536b005", + "0x2802836b00503100523702802836b00502800702804600704001f00a005", + "0x536b00502804602804700536b00502802002804800536b005092005031", + "0x2302823700536b00504504700736402804500536b00504500501b028045", + "0x36b00523b00536302823b00536b00523723900702d02823900536b005028", + "0xc002804800536b00504800509202804f00536b00504f00504f02823f005", + "0x23f00704804f00a00523f00536b00523f00508402800700536b005007005", + "0xf09200745e04f00b00736b00700702800700502802836b005028028028", + "0x36b00500a00500a02801000536b00504f00503102802836b005028007028", + "0xf02801000536b00501000509202800b00536b00500b00504f0281c8005", + "0x4e00501c02802836b00502800702801400545f01304e00736b0071c8005", + "0x2002804d00536b00501000503102802836b00501300536702802836b005", + "0x1700536b00501700501b02801700536b00502836502803000536b005028", + "0x36900702d02836900536b00502802302801800536b005017030007364028", + "0x536b00500b00504f02801b00536b00536800536302836800536b005018", + "0x50c002804d00536b00504d00509202800500536b00500500530702800b", + "0x1b03104d00500b00b00501b00536b00501b00508402803100536b005031", + "0x536b00501000503102802836b00501400501c02802836b005028007028", + "0x3670051aa02801c00536b00501c00509202836700536b00502836102801c", + "0x2836502000746001f36600736b00736701c00b03135f02836700536b005", + "0x2300536b00502834102836400536b00501f00503102802836b005028007", + "0x500530702836400536b00536400509202836600536b00536600504f028", + "0x2303100536436600b30602803100536b0050310050c002800500536b005", + "0x2835f0054611aa00536b00736100533c0283610840c036302d00b36b005", + "0x3200536b00536300503102802836b0051aa00533b02802836b005028007", + "0x36c00504002803336c00736b00535d00503602835d00536b005028020028", + "0x2803c00536b00500c00535902800c00536b00503300535e02802836b005", + "0x50c000530702802d00536b00502d00504f02803600536b00503c005356", + "0x2808400536b0050840050c002803200536b0050320050920280c000536b", + "0x2836b0050280070280360840320c002d00b00503600536b005036005084", + "0x2d00504f02835e00536b00535f00536302804000536b005363005031028", + "0x4000536b0050400050920280c000536b0050c000530702802d00536b005", + "0xc002d00b00535e00536b00535e00508402808400536b0050840050c0028", + "0x2802002835900536b00536500503102802836b00502800702835e084040", + "0x2821500536b00521500501b02821500536b00502804602835600536b005", + "0x21c04600702d02804600536b00502802302821c00536b005215356007364", + "0x2000536b00502000504f02804700536b00504800536302804800536b005", + "0x310050c002835900536b00535900509202800500536b005005005307028", + "0x2804703135900502000b00504700536b00504700508402803100536b005", + "0x4500536b00500f00503102802836b00500a00523702802836b005028007", + "0x36b00523900501b02823900536b00502804602823700536b005028020028", + "0x2d02823f00536b00502802302823b00536b005239237007364028239005", + "0x509200504f02824900536b00524500536302824500536b00523b23f007", + "0x2804500536b00504500509202800500536b00500500530702809200536b", + "0x4500509200b00524900536b00524900508402803100536b0050310050c0", + "0x746200b00a00736b00700502800700502802836b005028028028249031", + "0x3100500a02800f00536b00500b00503102802836b00502800702809204f", + "0xf00536b00500f00509202800a00536b00500a00504f02801000536b005", + "0x1c02802836b00502800702801300546304e1c800736b00701000500f028", + "0x1400536b00500f00503102802836b00504e00536702802836b0051c8005", + "0x36b00503000501b02803000536b00502836502804d00536b005028020028", + "0x2d02801800536b00502802302801700536b00503004d007364028030005", + "0x500a00504f02836800536b00536900536302836900536b005017018007", + "0x2800700536b0050070050c002801400536b00501400509202800a00536b", + "0x2802836b00502800702836800701400a00a00536800536b005368005084", + "0x536b00502836102801b00536b00500f00503102802836b00501300501c", + "0x3135f02801c00536b00501c0051aa02801b00536b00501b00509202801c", + "0x3102802836b00502800702802001f00746436636700736b00701c01b00a", + "0x536b00536700504f02836400536b00502834102836500536b005366005", + "0xa30502800700536b0050070050c002836500536b005365005092028367", + "0x46508400536b0070c000533c0280c036302d02300a36b005364007365367", + "0x502d00503102802836b00508400533b02802836b005028007028361005", + "0x2835d03200736b00535f00503602835f00536b0050280200281aa00536b", + "0x36b00536c00535902836c00536b00535d00535e02802836b005032005040", + "0x9202802300536b00502300504f02800c00536b005033005356028033005", + "0x36b00500c00508402836300536b0053630050c00281aa00536b0051aa005", + "0x36b00502d00503102802836b00502800702800c3631aa02300a00500c005", + "0x9202802300536b00502300504f02803600536b00536100536302803c005", + "0x36b00503600508402836300536b0053630050c002803c00536b00503c005", + "0x36b00502000503102802836b00502800702803636303c02300a005036005", + "0x35900501b02835900536b00502804602835e00536b005028020028040005", + "0x21500536b00502802302835600536b00535935e00736402835900536b005", + "0x504f02804600536b00521c00536302821c00536b00535621500702d028", + "0x536b0050070050c002804000536b00504000509202801f00536b00501f", + "0x36b00502800702804600704001f00a00504600536b005046005084028007", + "0x502802002804800536b00509200503102802836b005031005237028028", + "0x36402804500536b00504500501b02804500536b00502804602804700536b", + "0x523723900702d02823900536b00502802302823700536b005045047007", + "0x2804f00536b00504f00504f02823f00536b00523b00536302823b00536b", + "0x523f00508402800700536b0050070050c002804800536b005048005092", + "0x502800700502802836b00502802802823f00704804f00a00523f00536b", + "0x500b00503102802836b00502800702809204f00746600b00a00736b007", + "0x2800a00536b00500a00504f02801000536b00503100500a02800f00536b", + "0x2801300546704e1c800736b00701000500f02800f00536b00500f005092", + "0x536b00504e00501002801400536b00500f00503102802836b005028007", + "0x501b02801400536b0050140050920281c800536b0051c800501302804d", + "0x2800702801800546801703000736b0071c800500f02804d00536b00504d", + "0x2836800536b00501700501002836900536b00501400503102802836b005", + "0x536800501b02836900536b00536900509202803000536b005030005013", + "0x36b00502800702836700546901c01b00736b00703000500f02836800536b", + "0x536800501f02802836b00501c00536702802836b00501b00501c028028", + "0x2802002836600536b00536900503102802836b00504d00501f02802836b", + "0x2802000536b00502000501b02802000536b00502836502801f00536b005", + "0x36536400702d02836400536b00502802302836500536b00502001f007364", + "0xa00536b00500a00504f02802d00536b00502300536302802300536b005", + "0x2d00508402800700536b0050070050c002836600536b005366005092028", + "0x36700501c02802836b00502800702802d00736600a00a00502d00536b005", + "0x920280c000536b00502836102836300536b00536900503102802836b005", + "0xc036300a03135f0280c000536b0050c00051aa02836300536b005363005", + "0x536100503102802836b00502800702835f1aa00746a36108400736b007", + "0x2836c00536b0053680051c802835d00536b00504d0051c802803200536b", + "0x8400504f02803300536b00503300501b02803300536b00536c35d00732c", + "0x46b02836b00703300534802803200536b00503200509202808400536b005", + "0x502802002803c00536b00503200503102802836b00502800702800c005", + "0x36402804000536b00504000501b02804000536b0050280bf02803600536b", + "0x35900504002835635900736b00535e00503602835e00536b005040036007", + "0x2821c00536b00521500535902821500536b00535600535e02802836b005", + "0x503c00509202808400536b00508400504f02804600536b00521c005356", + "0x504600536b00504600508402800700536b0050070050c002803c00536b", + "0x3102802836b00500c00534602802836b00502800702804600703c08400a", + "0x4500536b00502830402804700536b00502802002804800536b005032005", + "0x2802302823700536b00504504700736402804500536b00504500501b028", + "0x536b00523b00536302823b00536b00523723900702d02823900536b005", + "0x50c002804800536b00504800509202808400536b00508400504f02823f", + "0x2823f00704808400a00523f00536b00523f00508402800700536b005007", + "0x2802836b00504d00501f02802836b00536800501f02802836b005028007", + "0x536b00502804602824900536b00502802002824500536b00535f005031", + "0x2302824d00536b00524c24900736402824c00536b00524c00501b02824c", + "0x36b00524f00536302824f00536b00524d24e00702d02824e00536b005028", + "0xc002824500536b0052450050920281aa00536b0051aa00504f028252005", + "0x2520072451aa00a00525200536b00525200508402800700536b005007005", + "0x2836b00504d00501f02802836b00501800501c02802836b005028007028", + "0x36b00502804802800900536b00502802002805000536b005014005031028", + "0x2805800536b00505b00900736402805b00536b00505b00501b02805b005", + "0x505c00536302805c00536b00505805900702d02805900536b005028023", + "0x2805000536b00505000509202800a00536b00500a00504f02825c00536b", + "0x705000a00a00525c00536b00525c00508402800700536b0050070050c0", + "0x36b00500f00503102802836b00501300501c02802836b00502800702825c", + "0x5e00501b02805e00536b00502804502825e00536b00502802002825d005", + "0x5f00536b00502802302806000536b00505e25e00736402805e00536b005", + "0x504f02829600536b00505d00536302805d00536b00506005f00702d028", + "0x536b0050070050c002825d00536b00525d00509202800a00536b00500a", + "0x36b00502800702829600725d00a00a00529600536b005296005084028007", + "0x502802002829800536b00509200503102802836b005031005237028028", + "0x36402806700536b00506700501b02806700536b00502804602804200536b", + "0x52bd06900702d02806900536b0050280230282bd00536b005067042007", + "0x2804f00536b00504f00504f02800600536b00506800536302806800536b", + "0x500600508402800700536b0050070050c002829800536b005298005092", + "0x502800700502802836b00502802802800600729804f00a00500600536b", + "0x500b00503102802836b00502800702809204f00746c00b00a00736b007", + "0x504f02802836b00502800b02801000536b00503100500a02800f00536b", + "0x736b00701000500f02800f00536b00500f00509202800a00536b00500a", + "0x2801400536b00500f00503102802836b00502800702801300546d04e1c8", + "0x51c800501302803000536b00501400509202804d00536b00504e00524f", + "0x2800702802846e00502804d02801800536b00504d00525202801700536b", + "0x5002836800536b00502803002836900536b00500f00503102802836b005", + "0x36b00501300501302803000536b00536900509202801b00536b005368005", + "0x546f01c00536b00701800500902801800536b00501b005252028017005", + "0x536b00503000503102802836b00502836902802836b005028007028367", + "0x1700535e02802000536b00502802002801f00536b00501c005010028366", + "0xa00536b00500a00504f02836400536b00501f0051c802836500536b005", + "0x2000521502836500536b00536500505b02836600536b005366005092028", + "0x36402036536600a00b05802836400536b00536400501b02802000536b005", + "0x280070280840054700c000536b00736300505902836302d02303136b005", + "0x35f1aa00736b0050c000505c02836100536b00502d00503102802836b005", + "0x2835d00547103200536b00735f00525c02836100536b005361005092028", + "0x536b0051aa00500a02836c00536b00536100503102802836b005028007", + "0x547203c00c00736b00703300500f02836c00536b00536c005092028033", + "0x36b00503c00536702802836b00500c00501c02802836b005028007028036", + "0x502802002804000536b00536c00503102802836b005032005040028028", + "0x36402835900536b00535900501b02835900536b00502836502835e00536b", + "0x535621500702d02821500536b00502802302835600536b00535935e007", + "0x2802300536b00502300504f02804600536b00521c00536302821c00536b", + "0x504600508402800700536b0050070050c002804000536b005040005092", + "0x503600501c02802836b00502800702804600704002300a00504600536b", + "0x509202804700536b00502836102804800536b00536c00503102802836b", + "0x704704802303135f02804700536b0050470051aa02804800536b005048", + "0x36b00523700503102802836b00502800702823b23900747323704500736b", + "0x509202804500536b00504500504f02824500536b00502834102823f005", + "0x536b00503200521502800700536b0050070050c002823f00536b00523f", + "0x24e00530202824e24d24c24900a36b00503224500723f04500b303028032", + "0x536b00524c00503102802836b00502800702825200547424f00536b007", + "0x532102805805b00736b00524f00505102800900536b005028020028050", + "0x736b00505900503602805900536b00505800900736402802836b00505b", + "0x535902825d00536b00525c00535e02802836b00505c00504002825c05c", + "0x536b00524900504f02805e00536b00525e00535602825e00536b00525d", + "0x508402824d00536b00524d0050c002805000536b005050005092028249", + "0x503102802836b00502800702805e24d05024900a00505e00536b00505e", + "0x536b00524900504f02805f00536b00525200536302806000536b00524c", + "0x508402824d00536b00524d0050c002806000536b005060005092028249", + "0x504002802836b00502800702805f24d06024900a00505f00536b00505f", + "0x2829600536b00502802002805d00536b00523b00503102802836b005032", + "0x529829600736402829800536b00529800501b02829800536b005028046", + "0x282bd00536b00504206700702d02806700536b00502802302804200536b", + "0x505d00509202823900536b00523900504f02806900536b0052bd005363", + "0x506900536b00506900508402800700536b0050070050c002805d00536b", + "0x23702802836b00535d00504702802836b00502800702806900705d23900a", + "0x536b00502300504f02806800536b00536100503102802836b0051aa005", + "0x36b00502800702802847500502804d02806f00536b005068005092028006", + "0x504f02832500536b00508400536302807100536b00502d005031028028", + "0x536b0050070050c002807100536b00507100509202802300536b005023", + "0x36b00502800702832500707102300a00532500536b005325005084028007", + "0x36b00501700501c02802836b00536700504702802836b005028369028028", + "0x509202800600536b00500a00504f02807400536b005030005031028028", + "0x2807700536b00502804502807500536b00502802002806f00536b005074", + "0x502802302834c00536b00507707500736402807700536b00507700501b", + "0x7a00536b00504300536302804300536b00534c34b00702d02834b00536b", + "0x70050c002806f00536b00506f00509202800600536b00500600504f028", + "0x702807a00706f00600a00507a00536b00507a00508402800700536b005", + "0x2807900536b00509200503102802836b00503100523702802836b005028", + "0x536b00534800501b02834800536b00502804602807f00536b005028020", + "0x702d02807d00536b00502802302808100536b00534807f007364028348", + "0x36b00504f00504f02834500536b00534600536302834600536b00508107d", + "0x8402800700536b0050070050c002807900536b00507900509202804f005", + "0x502802836b00502802802834500707904f00a00534500536b005345005", + "0x3102802836b00502800702809204f00747600b00a00736b007005028007", + "0x36b00500a00504f02801000536b00503100500a02800f00536b00500b005", + "0x47704e1c800736b00701000500f02800f00536b00500f00509202800a005", + "0x504e00536702802836b0051c800501c02802836b005028007028013005", + "0x2836502804d00536b00502802002801400536b00500f00503102802836b", + "0x536b00503004d00736402803000536b00503000501b02803000536b005", + "0x536302836900536b00501701800702d02801800536b005028023028017", + "0x536b00501400509202800a00536b00500a00504f02836800536b005369", + "0xa00a00536800536b00536800508402800700536b0050070050c0028014", + "0xf00503102802836b00501300501c02802836b005028007028368007014", + "0x2801b00536b00501b00509202801c00536b00502836102801b00536b005", + "0x747836636700736b00701c01b00a03135f02801c00536b00501c0051aa", + "0x502802002836500536b00536600503102802836b00502800702802001f", + "0x36402802300536b00502300501b02802300536b00502839302836400536b", + "0x502d36300702d02836300536b00502802302802d00536b005023364007", + "0x2836700536b00536700504f02808400536b0050c00053630280c000536b", + "0x508400508402800700536b0050070050c002836500536b005365005092", + "0x502000503102802836b00502800702808400736536700a00508400536b", + "0x501b02835f00536b0050280460281aa00536b00502802002836100536b", + "0x536b00502802302803200536b00535f1aa00736402835f00536b00535f", + "0x4f02803300536b00536c00536302836c00536b00503235d00702d02835d", + "0x36b0050070050c002836100536b00536100509202801f00536b00501f005", + "0x502800702803300736101f00a00503300536b005033005084028007005", + "0x2802002800c00536b00509200503102802836b00503100523702802836b", + "0x2803600536b00503600501b02803600536b00502804602803c00536b005", + "0x4035e00702d02835e00536b00502802302804000536b00503603c007364", + "0x4f00536b00504f00504f02835600536b00535900536302835900536b005", + "0x35600508402800700536b0050070050c002800c00536b00500c005092028", + "0x2800700502802836b00502802802835600700c04f00a00535600536b005", + "0xb00503102802836b00502800702809204f00747900b00a00736b007005", + "0xa00536b00500a00504f02801000536b00503100500a02800f00536b005", + "0x1300547a04e1c800736b00701000500f02800f00536b00500f005092028", + "0x36b00504e00501002801400536b00500f00503102802836b005028007028", + "0x1b02801400536b0050140050920281c800536b0051c800501302804d005", + "0x702801800547b01703000736b0071c800500f02804d00536b00504d005", + "0x1f02802836b00501700536702802836b00503000501c02802836b005028", + "0x36800536b00502802002836900536b00501400503102802836b00504d005", + "0x1b36800736402801b00536b00501b00501b02801b00536b005028365028", + "0x36600536b00501c36700702d02836700536b00502802302801c00536b005", + "0x36900509202800a00536b00500a00504f02801f00536b005366005363028", + "0x1f00536b00501f00508402800700536b0050070050c002836900536b005", + "0x2802836b00501800501c02802836b00502800702801f00736900a00a005", + "0x36b00502000509202836500536b00502836102802000536b005014005031", + "0x36400736b00736502000a03135f02836500536b0053650051aa028020005", + "0x280c000536b00502300503102802836b00502800702836302d00747c023", + "0x36b00536400504f02836100536b00502834102808400536b00504d0051c8", + "0x39402808400536b00508400501b0280c000536b0050c0005092028364005", + "0x47d35d00536b00703200533c02803235f1aa03136b0050843610c036400a", + "0x535f00503102802836b00535d00533b02802836b00502800702836c005", + "0x2803603c00736b00500c00503602800c00536b00502802002803300536b", + "0x36b00504000535902804000536b00503600535e02802836b00503c005040", + "0x920281aa00536b0051aa00504f02835900536b00535e00535602835e005", + "0x36b00535900508402800700536b0050070050c002803300536b005033005", + "0x36b00535f00503102802836b0050280070283590070331aa00a005359005", + "0x920281aa00536b0051aa00504f02821500536b00536c005363028356005", + "0x36b00521500508402800700536b0050070050c002835600536b005356005", + "0x36b00504d00501f02802836b0050280070282150073561aa00a005215005", + "0x502804602804600536b00502802002821c00536b005363005031028028", + "0x4700536b00504804600736402804800536b00504800501b02804800536b", + "0x23700536302823700536b00504704500702d02804500536b005028023028", + "0x21c00536b00521c00509202802d00536b00502d00504f02823900536b005", + "0x21c02d00a00523900536b00523900508402800700536b0050070050c0028", + "0x500f00503102802836b00501300501c02802836b005028007028239007", + "0x501b02824500536b00502804502823f00536b00502802002823b00536b", + "0x536b00502802302824900536b00524523f00736402824500536b005245", + "0x4f02824e00536b00524d00536302824d00536b00524924c00702d02824c", + "0x36b0050070050c002823b00536b00523b00509202800a00536b00500a005", + "0x502800702824e00723b00a00a00524e00536b00524e005084028007005", + "0x2802002824f00536b00509200503102802836b00503100523702802836b", + "0x2805000536b00505000501b02805000536b00502804602825200536b005", + "0x905b00702d02805b00536b00502802302800900536b005050252007364", + "0x4f00536b00504f00504f02805900536b00505800536302805800536b005", + "0x5900508402800700536b0050070050c002824f00536b00524f005092028", + "0x2800700502802836b00502802802805900724f04f00a00505900536b005", + "0xb00503102802836b00502800702809204f00747e00b00a00736b007005", + "0xa00536b00500a00504f02801000536b00503100500a02800f00536b005", + "0x1300547f04e1c800736b00701000500f02800f00536b00500f005092028", + "0x36b00504e00501002801400536b00500f00503102802836b005028007028", + "0x1b02801400536b0050140050920281c800536b0051c800501302804d005", + "0x702801800548001703000736b0071c800500f02804d00536b00504d005", + "0x1f02802836b00501700536702802836b00503000501c02802836b005028", + "0x36800536b00502802002836900536b00501400503102802836b00504d005", + "0x1b36800736402801b00536b00501b00501b02801b00536b005028365028", + "0x36600536b00501c36700702d02836700536b00502802302801c00536b005", + "0x36900509202800a00536b00500a00504f02801f00536b005366005363028", + "0x1f00536b00501f00508402800700536b0050070050c002836900536b005", + "0x2802836b00501800501c02802836b00502800702801f00736900a00a005", + "0x36b00502000509202836500536b00502836102802000536b005014005031", + "0x36400736b00736502000a03135f02836500536b0053650051aa028020005", + "0x280c000536b00502300503102802836b00502800702836302d007481023", + "0x36b00536400504f02836100536b00502834102808400536b00504d0051c8", + "0x39502808400536b00508400501b0280c000536b0050c0005092028364005", + "0x48235d00536b00703200533c02803235f1aa03136b0050843610c036400a", + "0x535f00503102802836b00535d00533b02802836b00502800702836c005", + "0x2803603c00736b00500c00503602800c00536b00502802002803300536b", + "0x36b00504000535902804000536b00503600535e02802836b00503c005040", + "0x920281aa00536b0051aa00504f02835900536b00535e00535602835e005", + "0x36b00535900508402800700536b0050070050c002803300536b005033005", + "0x36b00535f00503102802836b0050280070283590070331aa00a005359005", + "0x920281aa00536b0051aa00504f02821500536b00536c005363028356005", + "0x36b00521500508402800700536b0050070050c002835600536b005356005", + "0x36b00504d00501f02802836b0050280070282150073561aa00a005215005", + "0x502804602804600536b00502802002821c00536b005363005031028028", + "0x4700536b00504804600736402804800536b00504800501b02804800536b", + "0x23700536302823700536b00504704500702d02804500536b005028023028", + "0x21c00536b00521c00509202802d00536b00502d00504f02823900536b005", + "0x21c02d00a00523900536b00523900508402800700536b0050070050c0028", + "0x500f00503102802836b00501300501c02802836b005028007028239007", + "0x501b02824500536b00502804502823f00536b00502802002823b00536b", + "0x536b00502802302824900536b00524523f00736402824500536b005245", + "0x4f02824e00536b00524d00536302824d00536b00524924c00702d02824c", + "0x36b0050070050c002823b00536b00523b00509202800a00536b00500a005", + "0x502800702824e00723b00a00a00524e00536b00524e005084028007005", + "0x2802002824f00536b00509200503102802836b00503100523702802836b", + "0x2805000536b00505000501b02805000536b00502804602825200536b005", + "0x905b00702d02805b00536b00502802302800900536b005050252007364", + "0x4f00536b00504f00504f02805900536b00505800536302805800536b005", + "0x5900508402800700536b0050070050c002824f00536b00524f005092028", + "0x2800700502802836b00502802802805900724f04f00a00505900536b005", + "0xb00503102802836b00502800702809204f00748300b00a00736b007005", + "0x4f02802836b00502800b02801000536b00503100500a02800f00536b005", + "0x36b00701000500f02800f00536b00500f00509202800a00536b00500a005", + "0x1400536b00500f00503102802836b00502800702801300548404e1c8007", + "0x3000504e02803000536b00504d0051c802804d00536b00504e005010028", + "0x36900536b0051c800501302801800536b00501400509202801700536b005", + "0x2836b00502800702802848500502804d02836800536b005017005014028", + "0x501c00501702801c00536b00502803002801b00536b00500f005031028", + "0x2836900536b00501300501302801800536b00501b00509202836700536b", + "0x702801f00548636600536b00736800501802836800536b005367005014", + "0x9202802000536b00501800503102802836b00502836902802836b005028", + "0x2802300548736436500736b00736600a00724e02802000536b005020005", + "0x536b00536500504f02802d00536b00502000503102802836b005028007", + "0x54880c036300736b00736900500f02802d00536b00502d005092028365", + "0x50c000501002836100536b00502d00503102802836b005028007028084", + "0x2836100536b00536100509202836300536b0053630050130281aa00536b", + "0x2835d00548903235f00736b00736300500f0281aa00536b0051aa00501b", + "0x536b00503200501002836c00536b00536100503102802836b005028007", + "0x501b02836c00536b00536c00509202835f00536b00535f005013028033", + "0x2800702803600548a03c00c00736b00735f00500f02803300536b005033", + "0x501f02802836b00503c00536702802836b00500c00501c02802836b005", + "0x3102802836b00536400525d02802836b00503300501f02802836b0051aa", + "0x35900536b00502836502835e00536b00502802002804000536b00536c005", + "0x2802302835600536b00535935e00736402835900536b00535900501b028", + "0x536b00521c00536302821c00536b00535621500702d02821500536b005", + "0x50c002804000536b00504000509202836500536b00536500504f028046", + "0x2804600704036500a00504600536b00504600508402800700536b005007", + "0x4800536b00536c00503102802836b00503600501c02802836b005028007", + "0x50470051aa02804800536b00504800509202804700536b005028361028", + "0x702823b23900748b23704500736b00704704836503135f02804700536b", + "0x24500536b0050330051c802823f00536b00523700503102802836b005028", + "0x504500504f02824924500736b0052450050dc02802836b00502800b028", + "0x548c02836b00724900534802823f00536b00523f00509202804500536b", + "0x36b0051aa00501f02802836b00524500501f02802836b00502800702824c", + "0x24d00509202824d00536b00523f00503102802836b00536400525d028028", + "0x702802848d00502804d02824f00536b0050070050c002824e00536b005", + "0x2825200536b00523f00503102802836b00524c00534602802836b005028", + "0x50090050c702800936400736b00536400539602805000536b005028020", + "0x5900536b0051aa0051c802805800536b00505b05000736402805b00536b", + "0x23f02825c00536b00505c05800736402805c05900736b0050590050dc028", + "0x36b00525e00501b02825e00536b00525d24500732c02825d00536b005028", + "0x5f06000736b00505e00503602805e00536b00525e25c00736402825e005", + "0x525200509202805d00536b00505f00535e02802836b005060005040028", + "0x705d05936400725200b25e02805d00536b00505d00505b02825200536b", + "0x4200523702802836b0050280070280692bd06703148e04229829603136b", + "0x2806800536b00529600503102829600536b00529600509202802836b005", + "0x36b00502836902824f00536b0052980050c002824e00536b005068005092", + "0x504002807106f00736b00500600503602800600536b005028020028028", + "0x7400536b00532500535902832500536b00507100535e02802836b00506f", + "0x24e00509202804500536b00504500504f02807500536b005074005356028", + "0x7500536b00507500508402824f00536b00524f0050c002824e00536b005", + "0x9202802836b00502836902802836b00502800702807524f24e04500a005", + "0x536b00502802302807700536b00506700503102806700536b005067005", + "0x4f02804300536b00534b00536302834b00536b00506934c00702d02834c", + "0x36b0052bd0050c002807700536b00507700509202804500536b005045005", + "0x50280070280432bd07704500a00504300536b0050430050840282bd005", + "0x36400525d02802836b00503300501f02802836b0051aa00501f02802836b", + "0x4602807900536b00502802002807a00536b00523b00503102802836b005", + "0x36b00507f07900736402807f00536b00507f00501b02807f00536b005028", + "0x36302807d00536b00534808100702d02808100536b005028023028348005", + "0x36b00507a00509202823900536b00523900504f02834600536b00507d005", + "0xa00534600536b00534600508402800700536b0050070050c002807a005", + "0x525d02802836b00535d00501c02802836b00502800702834600707a239", + "0x2834500536b00536100503102802836b0051aa00501f02802836b005364", + "0x536b00534300501b02834300536b00502805e02834400536b005028020", + "0x702d02834100536b00502802302834200536b005343344007364028343", + "0x36b00536500504f02808c00536b00533d00536302833d00536b005342341", + "0x8402800700536b0050070050c002834500536b005345005092028365005", + "0x1c02802836b00502800702808c00734536500a00508c00536b00508c005", + "0x33c00536b00502d00503102802836b00536400525d02802836b005084005", + "0x36b00508a00501b02808a00536b00502804802833b00536b005028020028", + "0x2d02833900536b00502802302833a00536b00508a33b00736402808a005", + "0x536500504f02833800536b00508800536302808800536b00533a339007", + "0x2800700536b0050070050c002833c00536b00533c00509202836500536b", + "0x2802836b00502800702833800733c36500a00533800536b005338005084", + "0x36b00502300504f02833700536b00502000503102802836b00536900501c", + "0x502800702802848f00502804d02808600536b005337005092028336005", + "0x536900501c02802836b00501f00504702802836b00502836902802836b", + "0x9202833600536b00500a00504f02808e00536b00501800503102802836b", + "0x33300536b00502804502837700536b00502802002808600536b00508e005", + "0x2802302833200536b00533337700736402833300536b00533300501b028", + "0x536b00533000536302833000536b00533233100702d02833100536b005", + "0x50c002808600536b00508600509202833600536b00533600504f02832f", + "0x2832f00708633600a00532f00536b00532f00508402800700536b005007", + "0x32e00536b00509200503102802836b00503100523702802836b005028007", + "0x36b00532c00501b02832c00536b00502804602832d00536b005028020028", + "0x2d02832b00536b00502802302808b00536b00532c32d00736402832c005", + "0x504f00504f02832900536b00532a00536302832a00536b00508b32b007", + "0x2800700536b0050070050c002832e00536b00532e00509202804f00536b", + "0x2802836b00502802802832900732e04f00a00532900536b005329005084", + "0x2802836b00502800702800f09200749004f00b00736b007007005007005", + "0x500b00504f0281c800536b00500a00500a02801000536b00504f005031", + "0x1304e00736b0071c800500f02801000536b00501000509202800b00536b", + "0x501002804d00536b00501000503102802836b005028007028014005491", + "0x536b00504d00509202804e00536b00504e00501302803000536b005013", + "0x549201801700736b00704e00500f02803000536b00503000501b02804d", + "0x501800501002836800536b00504d00503102802836b005028007028369", + "0x2836800536b00536800509202801700536b00501700501302801b00536b", + "0x2836600549336701c00736b00701700500f02801b00536b00501b00501b", + "0x536b00536700501002801f00536b00536800503102802836b005028007", + "0x501b02801f00536b00501f00509202801c00536b00501c005013028020", + "0x2800702802300549436436500736b00701c00500f02802000536b005020", + "0x501f02802836b00536400536702802836b00536500501c02802836b005", + "0x3102802836b00501b00501f02802836b00502000501f02802836b005030", + "0xc000536b00502836502836300536b00502802002802d00536b00501f005", + "0x2802302808400536b0050c03630073640280c000536b0050c000501b028", + "0x536b0051aa0053630281aa00536b00508436100702d02836100536b005", + "0x509202800b00536b00500b00504f02802800536b0050280050c602835f", + "0x536b00535f00508402803100536b0050310050c002802d00536b00502d", + "0x36b00502300501c02802836b00502800702835f03102d00b02800b00535f", + "0x3200509202835d00536b00502836102803200536b00501f005031028028", + "0x36b00735d03200b03135f02835d00536b00535d0051aa02803200536b005", + "0x536b00503300503102802836b00502800702803c00c00749503336c007", + "0x51c802835e00536b00501b0051c802804000536b0050300051c8028036", + "0x36c00536b00536c00504f02835600536b00502834102835900536b005020", + "0x310050c002802800536b0050280050c602803600536b005036005092028", + "0x35e00536b00535e00501b02804000536b00504000501b02803100536b005", + "0x535935e04035603102803636c00f0c902835900536b00535900501b028", + "0x702823700549604500536b00704700533c02804704804621c21500b36b", + "0x2823900536b00521c00503102802836b00504500533b02802836b005028", + "0x523f00504002824523f00736b00523b00503602823b00536b005028020", + "0x35602824c00536b00524900535902824900536b00524500535e02802836b", + "0x36b00521500504f02804600536b0050460050c602824d00536b00524c005", + "0x8402804800536b0050480050c002823900536b005239005092028215005", + "0x2802836b00502800702824d04823921504600b00524d00536b00524d005", + "0x50460050c602824f00536b00523700536302824e00536b00521c005031", + "0x2824e00536b00524e00509202821500536b00521500504f02804600536b", + "0x24e21504600b00524f00536b00524f00508402804800536b0050480050c0", + "0x502000501f02802836b00503000501f02802836b00502800702824f048", + "0x2802002825200536b00503c00503102802836b00501b00501f02802836b", + "0x2800900536b00500900501b02800900536b00502804602805000536b005", + "0x5b05800702d02805800536b00502802302805b00536b005009050007364", + "0x2800536b0050280050c602805c00536b00505900536302805900536b005", + "0x310050c002825200536b00525200509202800c00536b00500c00504f028", + "0x2805c03125200c02800b00505c00536b00505c00508402803100536b005", + "0x2802836b00501b00501f02802836b00536600501c02802836b005028007", + "0x536b00502802002825c00536b00536800503102802836b00503000501f", + "0x25d00736402825e00536b00525e00501b02825e00536b00502805e02825d", + "0x536b00505e06000702d02806000536b00502802302805e00536b00525e", + "0x504f02802800536b0050280050c602805d00536b00505f00536302805f", + "0x536b0050310050c002825c00536b00525c00509202800b00536b00500b", + "0x502800702805d03125c00b02800b00505d00536b00505d005084028031", + "0x4d00503102802836b00503000501f02802836b00536900501c02802836b", + "0x1b02804200536b00502804802829800536b00502802002829600536b005", + "0x36b00502802302806700536b00504229800736402804200536b005042005", + "0x2806800536b00506900536302806900536b0050672bd00702d0282bd005", + "0x529600509202800b00536b00500b00504f02802800536b0050280050c6", + "0x506800536b00506800508402803100536b0050310050c002829600536b", + "0x2802836b00501400501c02802836b00502800702806803129600b02800b", + "0x536b00502804502806f00536b00502802002800600536b005010005031", + "0x2302832500536b00507106f00736402807100536b00507100501b028071", + "0x36b00507500536302807500536b00532507400702d02807400536b005028", + "0x9202800b00536b00500b00504f02802800536b0050280050c6028077005", + "0x36b00507700508402803100536b0050310050c002800600536b005006005", + "0x500a00523702802836b00502800702807703100600b02800b005077005", + "0x2804602834b00536b00502802002834c00536b00500f00503102802836b", + "0x536b00504334b00736402804300536b00504300501b02804300536b005", + "0x536302807f00536b00507a07900702d02807900536b00502802302807a", + "0x536b00509200504f02802800536b0050280050c602834800536b00507f", + "0x508402803100536b0050310050c002834c00536b00534c005092028092", + "0x502802836b00502802802834803134c09202800b00534800536b005348", + "0x3102802836b00502800702801000f00749709204f00736b007031005007", + "0x36b00504f00504f02804e00536b00500b00500a0281c800536b005092005", + "0x49801401300736b00704e00500f0281c800536b0051c800509202804f005", + "0x1400501002803000536b0051c800503102802836b00502800702804d005", + "0x1302802836b00502800b02801800536b0050170051c802801700536b005", + "0x36b00501800501b02803000536b00503000509202801300536b005013005", + "0x2836b00502800702801b00549936836900736b00701300500f028018005", + "0x1c00509202836700536b00536800524f02801c00536b005030005031028", + "0x2000536b00536700525202801f00536b00536900501302836600536b005", + "0x36500536b00503000503102802836b00502800702802849a00502804d028", + "0x536500509202802300536b00536400505002836400536b005028030028", + "0x2802000536b00502300525202801f00536b00501b00501302836600536b", + "0x36600503102802836b00502800702836300549b02d00536b007020005009", + "0x36100536b0050840051c802808400536b00502d0050100280c000536b005", + "0x4f0070ac0280c000536b0050c000509202836100536b00536100501b028", + "0x503102802836b00502800702836c35d03203149c35f1aa00736b007361", + "0x536b0050330050920281aa00536b0051aa00504f02803300536b0050c0", + "0x2802836b00502800702803600549d03c00c00736b00701f00500f028033", + "0x504000509202835e00536b00503c00524f02804000536b005033005031", + "0x2821500536b00535e00525202835600536b00500c00501302835900536b", + "0x2821c00536b00503300503102802836b00502800702802849e00502804d", + "0x36b00521c00509202804800536b00504600505002804600536b005028030", + "0x902821500536b00504800525202835600536b005036005013028359005", + "0x535900503102802836b00502800702804500549f04700536b007215005", + "0x2823b00536b0052390051c802823900536b00504700501002823700536b", + "0x23b1aa0070ac02823700536b00523700509202823b00536b00523b00501b", + "0x23700503102802836b00502800702824d24c2490314a024523f00736b007", + "0x24e00536b00524e00509202823f00536b00523f00504f02824e00536b005", + "0x36902802836b0050280070280500054a125224f00736b00735600500f028", + "0x30f02802836b00525200536702802836b00524f00501c02802836b005028", + "0x2802836b00501800501f02802836b00524500530f02802836b00535f005", + "0x536b00502836502805b00536b00502802002800900536b00524e005031", + "0x2302805900536b00505805b00736402805800536b00505800501b028058", + "0x36b00525c00536302825c00536b00505905c00702d02805c00536b005028", + "0x30702823f00536b00523f00504f02802800536b0050280050c602825d005", + "0x36b00500a0050c002800900536b00500900509202800700536b005007005", + "0x702825d00a00900723f02804f00525d00536b00525d00508402800a005", + "0x2825e00536b00524e00503102802836b00505000501c02802836b005028", + "0x36b00505e0051aa02825e00536b00525e00509202805e00536b005028361", + "0x2800702829605d0074a205f06000736b00705e25e23f03135f02805e005", + "0x70cb02829800536b00505f00503102802836b00502836902802836b005", + "0x36b00502834102806700536b0050420180070cf02804200536b00524535f", + "0x30702829800536b00529800509202806000536b00506000504f0282bd005", + "0x36b00500a0050c002802800536b0050280050c602800700536b005007005", + "0x672bd00a02800729806009239702806700536b00506700530102800a005", + "0x750054a307400536b00732500533c02832507106f00606806904f36b005", + "0x536b00506800503102802836b00507400533b02802836b005028007028", + "0x504002804334b00736b00534c00503602834c00536b005028020028077", + "0x7900536b00507a00535902807a00536b00504300535e02802836b00534b", + "0x6900504f02806f00536b00506f0050c602807f00536b005079005356028", + "0x7700536b00507700509202800600536b00500600530702806900536b005", + "0x6906f04f00507f00536b00507f00508402807100536b0050710050c0028", + "0x36302834800536b00506800503102802836b00502800702807f071077006", + "0x36b00506900504f02806f00536b00506f0050c602808100536b005075005", + "0xc002834800536b00534800509202800600536b005006005307028069005", + "0x34800606906f04f00508100536b00508100508402807100536b005071005", + "0x36b00535f00530f02802836b00502836902802836b005028007028081071", + "0x529600503102802836b00501800501f02802836b00524500530f028028", + "0x501b02834500536b00502804602834600536b00502802002807d00536b", + "0x536b00502802302834400536b00534534600736402834500536b005345", + "0xc602834100536b00534200536302834200536b00534434300702d028343", + "0x36b00500700530702805d00536b00505d00504f02802800536b005028005", + "0x8402800a00536b00500a0050c002807d00536b00507d005092028007005", + "0x2836b00502800702834100a07d00705d02804f00534100536b005341005", + "0x2836b00524d00530f02802836b00524c00530f02802836b005028369028", + "0x36b00501800501f02802836b00535f00530f02802836b00535600501c028", + "0x509202808c00536b00524900504f02833d00536b005237005031028028", + "0x2836902802836b0050280070280284a400502804d02833c00536b00533d", + "0x530f02802836b00535600501c02802836b00504500504702802836b005", + "0x2833b00536b00535900503102802836b00501800501f02802836b00535f", + "0x508c00530c02833c00536b00533b00509202808c00536b0051aa00504f", + "0x280070280284a500502804d02833a00536b00533c00539802808a00536b", + "0x36c00530f02802836b00535d00530f02802836b00502836902802836b005", + "0x503102802836b00501800501f02802836b00501f00501c02802836b005", + "0x536b00533900509202808800536b00503200504f02833900536b0050c0", + "0x2802836b00502836902802836b0050280070280284a600502804d028338", + "0x2836b00501800501f02802836b00501f00501c02802836b005363005047", + "0x33700509202808800536b00504f00504f02833700536b005366005031028", + "0x33a00536b00533800539802808a00536b00508800530c02833800536b005", + "0x502804d02808600536b00533a00539802833600536b00508a00530c028", + "0x51c800503102802836b00504d00501c02802836b0050280070280284a7", + "0x2808600536b00508e00509202833600536b00504f00504f02808e00536b", + "0x536b00533300501b02833300536b00502804502837700536b005028020", + "0x702d02833100536b00502802302833200536b005333377007364028333", + "0x36b0050280050c602832f00536b00533000536302833000536b005332331", + "0x9202800700536b00500700530702833600536b00533600504f028028005", + "0x36b00532f00508402800a00536b00500a0050c002808600536b005086005", + "0xb00523702802836b00502800702832f00a08600733602804f00532f005", + "0x4602832d00536b00502802002832e00536b00501000503102802836b005", + "0x36b00532c32d00736402832c00536b00532c00501b02832c00536b005028", + "0x36302832a00536b00508b32b00702d02832b00536b00502802302808b005", + "0x36b00500f00504f02802800536b0050280050c602832900536b00532a005", + "0xc002832e00536b00532e00509202800700536b00500700530702800f005", + "0x32e00700f02804f00532900536b00532900508402800a00536b00500a005", + "0x74a800b00a00736b00700502800700502802836b00502802802832900a", + "0x3100500a02800f00536b00500b00503102802836b00502800702809204f", + "0x9202800a00536b00500a00504f02802836b00502800b02801000536b005", + "0x70280130054a904e1c800736b00701000500f02800f00536b00500f005", + "0x4d00536b00504e00501002801400536b00500f00503102802836b005028", + "0x1400509202801700536b00503000504e02803000536b00504d0051c8028", + "0x36800536b00501700501402836900536b0051c800501302801800536b005", + "0x1b00536b00500f00503102802836b0050280070280284aa00502804d028", + "0x501b00509202836700536b00501c00501702801c00536b005028030028", + "0x2836800536b00536700501402836900536b00501300501302801800536b", + "0x502836902802836b00502800702801f0054ab36600536b007368005018", + "0x24e02802000536b00502000509202802000536b00501800503102802836b", + "0x503102802836b0050280070280230054ac36436500736b00736600a007", + "0x536b00502d00509202836500536b00536500504f02802d00536b005020", + "0x2802836b0050280070280840054ad0c036300736b00736900500f02802d", + "0x51aa0051c80281aa00536b0050c000501002836100536b00502d005031", + "0x509202836300536b00536300501302802836b00502800b02835f00536b", + "0x736b00736300500f02835f00536b00535f00501b02836100536b005361", + "0x2803300536b00536100503102802836b00502800702836c0054ae35d032", + "0x503200501302803c00536b00503300509202800c00536b00535d00524f", + "0x280070280284af00502804d02804000536b00500c00525202803600536b", + "0x5002835900536b00502803002835e00536b00536100503102802836b005", + "0x36b00536c00501302803c00536b00535e00509202835600536b005359005", + "0x54b021500536b00704000500902804000536b005356005252028036005", + "0x521500501002804600536b00503c00503102802836b00502800702821c", + "0x2804700536b00504700501b02804700536b0050480051c802804800536b", + "0x2390314b123704500736b0070473650070ac02804600536b005046005092", + "0x4500504f02824500536b00504600503102802836b00502800702823f23b", + "0x24900736b00703600500f02824500536b00524500509202804500536b005", + "0x24f02824e00536b00524500503102802836b00502800702824d0054b224c", + "0x36b00524900501302825200536b00524e00509202824f00536b00524c005", + "0x50280070280284b300502804d02800900536b00524f005252028050005", + "0x505002805800536b00502803002805b00536b00524500503102802836b", + "0x536b00524d00501302825200536b00505b00509202805900536b005058", + "0x25c0054b405c00536b00700900500902800900536b005059005252028050", + "0x36b00505c00501002825d00536b00525200503102802836b005028007028", + "0x9202805e00536b00505e00501b02805e00536b00525e0051c802825e005", + "0x29605d0314b505f06000736b00705e0450070ac02825d00536b00525d005", + "0x506000504f02804200536b00525d00503102802836b005028007028298", + "0x2bd06700736b00705000500f02804200536b00504200509202806000536b", + "0x506700501c02802836b00502836902802836b0050280070280690054b6", + "0x5f00530f02802836b00535f00501f02802836b0052bd00536702802836b", + "0x503102802836b00523700530f02802836b00536400525d02802836b005", + "0x2806f00536b00502836502800600536b00502802002806800536b005042", + "0x502802302807100536b00506f00600736402806f00536b00506f00501b", + "0x7500536b00507400536302807400536b00507132500702d02832500536b", + "0x70050c002806800536b00506800509202806000536b00506000504f028", + "0x702807500706806000a00507500536b00507500508402800700536b005", + "0x2807700536b00504200503102802836b00506900501c02802836b005028", + "0x36b00534c0051aa02807700536b00507700509202834c00536b005028361", + "0x2800702807907a0074b704334b00736b00734c07706003135f02834c005", + "0x2802002807f00536b00504300503102802836b00502836902802836b005", + "0x36b00508135f0070cf02808100536b00505f2370070cb02834800536b005", + "0x30102802836b0053460050d402834534600736b00507d0052fb02807d005", + "0x53440050d502834434500736b0053450052fa02834500536b005345005", + "0x2834100536b0053430051c802802836b00534200539902834234300736b", + "0x501f02833c08c00736b0053450050d502833d00536b005341348007364", + "0x536b00533b0052f702808a33b00736b00533c0052f802802836b00508c", + "0x2f702808800536b00533933d00736402833900536b00533a0050b902833a", + "0x533708800736402833700536b0053380050b902833800536b00508a005", + "0x2837708e00736b00533600503602808600536b0050282f102833600536b", + "0x36b00507f00509202833300536b00537700535e02802836b00508e005040", + "0x4f02833300536b00533300505b02808600536b00508600501b02807f005", + "0x33033133203136b00733308636400707f00b25e02834b00536b00534b005", + "0x9202802836b00533000523702802836b00502800702832d32e32f0314b8", + "0x536b00502802002832c00536b00533200503102833200536b005332005", + "0x535e02802836b00532b00504002832a32b00736b00508b00503602808b", + "0x536b00532600535602832600536b00532900535902832900536b00532a", + "0x50c002832c00536b00532c00509202834b00536b00534b00504f028085", + "0x2808533132c34b00a00508500536b00508500508402833100536b005331", + "0x536b00532f00503102832f00536b00532f00509202802836b005028007", + "0x536302832400536b00532d09500702d02809500536b005028023028093", + "0x536b00509300509202834b00536b00534b00504f02809800536b005324", + "0x34b00a00509800536b00509800508402832e00536b00532e0050c0028093", + "0x535f00501f02802836b00502836902802836b00502800702809832e093", + "0x23700530f02802836b00536400525d02802836b00505f00530f02802836b", + "0x4602809600536b00502802002832300536b00507900503102802836b005", + "0x36b00532209600736402832200536b00532200501b02832200536b005028", + "0x36302831e00536b00532131f00702d02831f00536b005028023028321005", + "0x36b00532300509202807a00536b00507a00504f02831d00536b00531e005", + "0xa00531d00536b00531d00508402800700536b0050070050c0028323005", + "0x29600530f02802836b00502836902802836b00502800702831d00732307a", + "0x501f02802836b00505000501c02802836b00529800530f02802836b005", + "0x3102802836b00536400525d02802836b00523700530f02802836b00535f", + "0x36b00531c00509202831b00536b00505d00504f02831c00536b00525d005", + "0x2836b00502836902802836b0050280070280284b900502804d02831a005", + "0x36b00535f00501f02802836b00505000501c02802836b00525c005047028", + "0x525200503102802836b00536400525d02802836b00523700530f028028", + "0x2831a00536b00531900509202831b00536b00504500504f02831900536b", + "0x4ba00502804d02831700536b00531a00539802831800536b00531b00530c", + "0x2836b00523b00530f02802836b00502836902802836b005028007028028", + "0x36b00535f00501f02802836b00503600501c02802836b00523f00530f028", + "0x23900504f02831600536b00504600503102802836b00536400525d028028", + "0x70280284bb00502804d02831300536b00531600509202831400536b005", + "0x501c02802836b00521c00504702802836b00502836902802836b005028", + "0x3102802836b00536400525d02802836b00535f00501f02802836b005036", + "0x36b00531100509202831400536b00536500504f02831100536b00503c005", + "0x30c02831700536b00531300539802831800536b00531400530c028313005", + "0x284bc00502804d02831000536b0053170053980280a900536b005318005", + "0x2836b00536400525d02802836b00508400501c02802836b005028007028", + "0xb00050920280a900536b00536500504f0280b000536b00502d005031028", + "0x1b02830f00536b0050280480280ac00536b00502802002831000536b005", + "0x36b00502802302830d00536b00530f0ac00736402830f00536b00530f005", + "0x2830b00536b0050b60053630280b600536b00530d0b400702d0280b4005", + "0x50070050c002831000536b0053100050920280a900536b0050a900504f", + "0x2800702830b0073100a900a00530b00536b00530b00508402800700536b", + "0x4f0280b900536b00502000503102802836b00536900501c02802836b005", + "0x284bd00502804d02830800536b0050b900509202830900536b005023005", + "0x2802836b00501f00504702802836b00502836902802836b005028007028", + "0x36b00500a00504f02830700536b00501800503102802836b00536900501c", + "0x2804502830600536b00502802002830800536b005307005092028309005", + "0x536b00530530600736402830500536b00530500501b02830500536b005", + "0x536302830300536b0050bf30400702d02830400536b0050280230280bf", + "0x536b00530800509202830900536b00530900504f02830200536b005303", + "0x30900a00530200536b00530200508402800700536b0050070050c0028308", + "0x9200503102802836b00503100523702802836b005028007028302007308", + "0x1b02839400536b00502804602839300536b00502802002805100536b005", + "0x36b00502802302839500536b00539439300736402839400536b005394005", + "0x280c700536b00539600536302839600536b0053950dc00702d0280dc005", + "0x50070050c002805100536b00505100509202804f00536b00504f00504f", + "0x280280280c700705104f00a0050c700536b0050c700508402800700536b", + "0x2800702800f0920074be04f00b00736b00700702800700502802836b005", + "0x281c800536b00500a00500a02801000536b00504f00503102802836b005", + "0x71c800500f02801000536b00501000509202800b00536b00500b00504f", + "0x2836b00504e00501c02802836b0050280070280140054bf01304e00736b", + "0x36b00502802002804d00536b00501000503102802836b005013005367028", + "0x736402801700536b00501700501b02801700536b005028365028030005", + "0x36b00501836900702d02836900536b00502802302801800536b005017030", + "0xda02800b00536b00500b00504f02801b00536b005368005363028368005", + "0x36b0050310050c002804d00536b00504d00509202800500536b005005005", + "0x2800702801b03104d00500b00b00501b00536b00501b005084028031005", + "0x36102801c00536b00501000503102802836b00501400501c02802836b005", + "0x536b0053670051aa02801c00536b00501c00509202836700536b005028", + "0x50280070283650200074c001f36600736b00736701c00b03135f028367", + "0x50da02802300536b00502834102836400536b00501f00503102802836b", + "0x536b0050310050c002836400536b00536400509202800500536b005005", + "0x536600504f0280840c036302d00a36b00502303136400500a2ee028031", + "0x2836b0050280070281aa0054c136100536b00708400533c02836600536b", + "0x36b00502802002835f00536b00536300503102802836b00536100533b028", + "0x35e02802836b00535d00504002836c35d00736b005032005036028032005", + "0x36b00500c00535602800c00536b00503300535902803300536b00536c005", + "0x9202802d00536b00502d0050da02836600536b00536600504f02803c005", + "0x36b00503c0050840280c000536b0050c00050c002835f00536b00535f005", + "0x536300503102802836b00502800702803c0c035f02d36600b00503c005", + "0x2836600536b00536600504f02804000536b0051aa00536302803600536b", + "0x50c00050c002803600536b00503600509202802d00536b00502d0050da", + "0x70280400c003602d36600b00504000536b0050400050840280c000536b", + "0x2835900536b00502802002835e00536b00536500503102802836b005028", + "0x535635900736402835600536b00535600501b02835600536b005028046", + "0x2804600536b00521521c00702d02821c00536b00502802302821500536b", + "0x50050050da02802000536b00502000504f02804800536b005046005363", + "0x2803100536b0050310050c002835e00536b00535e00509202800500536b", + "0x2836b00502800702804803135e00502000b00504800536b005048005084", + "0x36b00502802002804700536b00500f00503102802836b00500a005237028", + "0x736402823700536b00523700501b02823700536b005028046028045005", + "0x36b00523923b00702d02823b00536b00502802302823900536b005237045", + "0xda02809200536b00509200504f02824500536b00523f00536302823f005", + "0x36b0050310050c002804700536b00504700509202800500536b005005005", + "0x2802802824503104700509200b00524500536b005245005084028031005", + "0x2800702800f0920074c204f00b00736b00700700500700502802836b005", + "0x281c800536b00500a00500a02801000536b00504f00503102802836b005", + "0x71c800500f02801000536b00501000509202800b00536b00500b00504f", + "0x536b00501000503102802836b0050280070280140054c301304e00736b", + "0x509202804e00536b00504e00501302803000536b00501300501002804d", + "0x736b00704e00500f02803000536b00503000501b02804d00536b00504d", + "0x36702802836b00501700501c02802836b0050280070283690054c4018017", + "0x36800536b00504d00503102802836b00503000501f02802836b005018005", + "0x36b00501c00501b02801c00536b00502836502801b00536b005028020028", + "0x2d02836600536b00502802302836700536b00501c01b00736402801c005", + "0x50280050c602802000536b00501f00536302801f00536b005367366007", + "0x2836800536b00536800509202800b00536b00500b00504f02802800536b", + "0x36800b02800b00502000536b00502000508402803100536b0050310050c0", + "0x504d00503102802836b00536900501c02802836b005028007028020031", + "0x1aa02836500536b00536500509202836400536b00502836102836500536b", + "0x3630074c502d02300736b00736436500b03135f02836400536b005364005", + "0x50300051c802808400536b00502d00503102802836b0050280070280c0", + "0x9202802300536b00502300504f0281aa00536b00502834102836100536b", + "0x36b0050310050c002802800536b0050280050c602808400536b005084005", + "0x53611aa03102808402304f2ec02836100536b00536100501b028031005", + "0x702803c0054c600c00536b00703300533c02803336c35d03235f00b36b", + "0x2803600536b00503200503102802836b00500c00533b02802836b005028", + "0x535e00504002835935e00736b00504000503602804000536b005028020", + "0x35602821500536b00535600535902835600536b00535900535e02802836b", + "0x36b00535f00504f02835d00536b00535d0050c602821c00536b005215005", + "0x8402836c00536b00536c0050c002803600536b00503600509202835f005", + "0x2802836b00502800702821c36c03635f35d00b00521c00536b00521c005", + "0x535d0050c602804800536b00503c00536302804600536b005032005031", + "0x2804600536b00504600509202835f00536b00535f00504f02835d00536b", + "0x4635f35d00b00504800536b00504800508402836c00536b00536c0050c0", + "0x50c000503102802836b00503000501f02802836b00502800702804836c", + "0x501b02823700536b00502804602804500536b00502802002804700536b", + "0x536b00502802302823900536b00523704500736402823700536b005237", + "0xc602824500536b00523f00536302823f00536b00523923b00702d02823b", + "0x36b00504700509202836300536b00536300504f02802800536b005028005", + "0xb00524500536b00524500508402803100536b0050310050c0028047005", + "0x3102802836b00501400501c02802836b005028007028245031047363028", + "0x24d00536b00502804502824c00536b00502802002824900536b005010005", + "0x2802302824e00536b00524d24c00736402824d00536b00524d00501b028", + "0x536b00525200536302825200536b00524e24f00702d02824f00536b005", + "0x509202800b00536b00500b00504f02802800536b0050280050c6028050", + "0x536b00505000508402803100536b0050310050c002824900536b005249", + "0x36b00500a00523702802836b00502800702805003124900b02800b005050", + "0x502804602805b00536b00502802002800900536b00500f005031028028", + "0x5900536b00505805b00736402805800536b00505800501b02805800536b", + "0x25c00536302825c00536b00505905c00702d02805c00536b005028023028", + "0x9200536b00509200504f02802800536b0050280050c602825d00536b005", + "0x25d00508402803100536b0050310050c002800900536b005009005092028", + "0x700502802836b00502802802825d03100909202800b00525d00536b005", + "0x503102802836b00502800702809204f0074c700b00a00736b007005028", + "0x536b00500a00504f02801000536b00503100500a02800f00536b00500b", + "0x54c804e1c800736b00701000500f02800f00536b00500f00509202800a", + "0x504e00501002801400536b00500f00503102802836b005028007028013", + "0x2801400536b0050140050920281c800536b0051c800501302804d00536b", + "0x280180054c901703000736b0071c800500f02804d00536b00504d00501b", + "0x2802836b00501700536702802836b00503000501c02802836b005028007", + "0x536b00502802002836900536b00501400503102802836b00504d00501f", + "0x36800736402801b00536b00501b00501b02801b00536b005028365028368", + "0x536b00501c36700702d02836700536b00502802302801c00536b00501b", + "0x509202800a00536b00500a00504f02801f00536b005366005363028366", + "0x536b00501f00508402800700536b0050070050c002836900536b005369", + "0x2836b00501800501c02802836b00502800702801f00736900a00a00501f", + "0x502000509202836500536b00502836102802000536b005014005031028", + "0x736b00736502000a03135f02836500536b0053650051aa02802000536b", + "0xc000536b00502300503102802836b00502800702836302d0074ca023364", + "0x36b00536100501b02836100536b0050280d202808400536b005028020028", + "0x1b02835f00536b0050282ef0281aa00536b005361084007364028361005", + "0x504d0051c802803200536b00535f1aa00736402835f00536b00535f005", + "0x2802836b00536c00504002803336c00736b00503200503602835d00536b", + "0x500c00505b0280c000536b0050c000509202800c00536b00503300535e", + "0x36b00700c35d0070c000a31602836400536b00536400504f02800c00536b", + "0x36b00503c00509202802836b00502800702835935e0400314cb03603c007", + "0x503602821500536b00502802002835600536b00503c00503102803c005", + "0x536b00504600535e02802836b00521c00504002804621c00736b005215", + "0x504f02804500536b00504700535602804700536b005048005359028048", + "0x536b0050360050c002835600536b00535600509202836400536b005364", + "0x36b00502800702804503635636400a00504500536b005045005084028036", + "0x2802302823700536b00504000503102804000536b005040005092028028", + "0x536b00523b00536302823b00536b00535923900702d02823900536b005", + "0x50c002823700536b00523700509202836400536b00536400504f02823f", + "0x2823f35e23736400a00523f00536b00523f00508402835e00536b00535e", + "0x24500536b00536300503102802836b00504d00501f02802836b005028007", + "0x36b00524c00501b02824c00536b00502804602824900536b005028020028", + "0x2d02824e00536b00502802302824d00536b00524c24900736402824c005", + "0x502d00504f02825200536b00524f00536302824f00536b00524d24e007", + "0x2800700536b0050070050c002824500536b00524500509202802d00536b", + "0x2802836b00502800702825200724502d00a00525200536b005252005084", + "0x536b00502802002805000536b00500f00503102802836b00501300501c", + "0x900736402805b00536b00505b00501b02805b00536b005028045028009", + "0x536b00505805900702d02805900536b00502802302805800536b00505b", + "0x509202800a00536b00500a00504f02825c00536b00505c00536302805c", + "0x536b00525c00508402800700536b0050070050c002805000536b005050", + "0x2836b00503100523702802836b00502800702825c00705000a00a00525c", + "0x36b00502804602825e00536b00502802002825d00536b005092005031028", + "0x2806000536b00505e25e00736402805e00536b00505e00501b02805e005", + "0x505d00536302805d00536b00506005f00702d02805f00536b005028023", + "0x2825d00536b00525d00509202804f00536b00504f00504f02829600536b", + "0x725d04f00a00529600536b00529600508402800700536b0050070050c0", + "0x100074cc00f09200736b00700a02800700502802836b005028028028296", + "0x504f00500a02804e00536b00500f00503102802836b0050280070281c8", + "0x2804e00536b00504e00509202809200536b00509200504f02801300536b", + "0x501c02802836b0050280070280300054cd04d01400736b00701300500f", + "0x2801700536b00504e00503102802836b00504d00536702802836b005014", + "0x536b00536900501b02836900536b00502836502801800536b005028020", + "0x702d02801b00536b00502802302836800536b005369018007364028369", + "0x36b00509200504f02836700536b00501c00536302801c00536b00536801b", + "0x2e902800700536b0050070052f602800500536b0050050050db028092005", + "0x36b00500b0050c002801700536b00501700509202803100536b005031005", + "0x2836700b01703100700509209200536700536b00536700508402800b005", + "0x36600536b00504e00503102802836b00503000501c02802836b005028007", + "0x501f0051aa02836600536b00536600509202801f00536b005028361028", + "0x70280233640074ce36502000736b00701f36609203135f02801f00536b", + "0x2836300536b00502834102802d00536b00536500503102802836b005028", + "0x50310052e902800700536b0050070052f602802000536b00502000504f", + "0x2802d00536b00502d00509202800500536b0050050050db02803100536b", + "0x533c02803235f1aa3610840c004f36b00536302d00503100702004f2e8", + "0x36b00535d00533b02802836b00502800702836c0054cf35d00536b007032", + "0xc00503602800c00536b00502802002803300536b00535f005031028028", + "0x4000536b00503600535e02802836b00503c00504002803603c00736b005", + "0xc000504f02835900536b00535e00535602835e00536b005040005359028", + "0x8400536b0050840052f60281aa00536b0051aa0050db0280c000536b005", + "0xb0050c002803300536b00503300509202836100536b0053610052e9028", + "0xb0333610841aa0c009200535900536b00535900508402800b00536b005", + "0x536c00536302835600536b00535f00503102802836b005028007028359", + "0x281aa00536b0051aa0050db0280c000536b0050c000504f02821500536b", + "0x535600509202836100536b0053610052e902808400536b0050840052f6", + "0x521500536b00521500508402800b00536b00500b0050c002835600536b", + "0x36b00502300503102802836b00502800702821500b3563610841aa0c0092", + "0x4800501b02804800536b00502804602804600536b00502802002821c005", + "0x4500536b00502802302804700536b00504804600736402804800536b005", + "0x504f02823900536b00523700536302823700536b00504704500702d028", + "0x536b0050070052f602800500536b0050050050db02836400536b005364", + "0x50c002821c00536b00521c00509202803100536b0050310052e9028007", + "0x21c03100700536409200523900536b00523900508402800b00536b00500b", + "0x51c800503102802836b00504f00523702802836b00502800702823900b", + "0x501b02824500536b00502804602823f00536b00502802002823b00536b", + "0x536b00502802302824900536b00524523f00736402824500536b005245", + "0x4f02824e00536b00524d00536302824d00536b00524924c00702d02824c", + "0x36b0050070052f602800500536b0050050050db02801000536b005010005", + "0xc002823b00536b00523b00509202803100536b0050310052e9028007005", + "0x3100700501009200524e00536b00524e00508402800b00536b00500b005", + "0x4d004f00b00736b00700702800700502802836b00502802802824e00b23b", + "0x500a02801000536b00504f00503102802836b00502800702800f092007", + "0x536b00501000509202800b00536b00500b00504f0281c800536b00500a", + "0x2802836b0050280070280140054d101304e00736b0071c800500f028010", + "0x536b00501000503102802836b00501300536702802836b00504e00501c", + "0x501700501b02801700536b00502836502803000536b00502802002804d", + "0x2836900536b00502802302801800536b00501703000736402801700536b", + "0xb00504f02801b00536b00536800536302836800536b00501836900702d", + "0x4d00536b00504d00509202800500536b0050050050db02800b00536b005", + "0x500b00b00501b00536b00501b00508402803100536b0050310050c0028", + "0x1000503102802836b00501400501c02802836b00502800702801b03104d", + "0x2801c00536b00501c00509202836700536b00502836102801c00536b005", + "0x74d201f36600736b00736701c00b03135f02836700536b0053670051aa", + "0x50050db02836400536b00501f00503102802836b005028007028365020", + "0x2802836b00502800b02802d02300736b0050050052e702800500536b005", + "0x702d00531c02836400536b00536400509202836600536b00536600504f", + "0x2802836b00536300531b02802836b0050280070280c00054d336300536b", + "0x50230052e702802300536b0050230050db02808400536b005364005031", + "0x35f00536b0071aa00531c02808400536b0050840050920281aa36100736b", + "0x535f00531b02802836b00502836902802836b0050280070280320054d4", + "0x503602836c00536b00502802002835d00536b00508400503102802836b", + "0x536b00500c00535e02802836b00503300504002800c03300736b00536c", + "0x504f02804000536b00503600535602803600536b00503c00535902803c", + "0x536b00535d00509202836100536b0053610050db02836600536b005366", + "0x36600b00504000536b00504000508402803100536b0050310050c002835d", + "0xdb02835e00536b00508400503102802836b00502800702804003135d361", + "0x36b0050320050df02835600536b00535e00509202835900536b005361005", + "0x36b00536400503102802836b0050280070280284d500502804d028215005", + "0xdf02835600536b00521c00509202835900536b0050230050db02821c005", + "0x4600536b00521500536302802836b00502836902821500536b0050c0005", + "0x35600509202835900536b0053590050db02836600536b00536600504f028", + "0x4600536b00504600508402803100536b0050310050c002835600536b005", + "0x536b00536500503102802836b00502800702804603135635936600b005", + "0x504500501b02804500536b00502804602804700536b005028020028048", + "0x2823900536b00502802302823700536b00504504700736402804500536b", + "0x2000504f02823f00536b00523b00536302823b00536b00523723900702d", + "0x4800536b00504800509202800500536b0050050050db02802000536b005", + "0x502000b00523f00536b00523f00508402803100536b0050310050c0028", + "0xf00503102802836b00500a00523702802836b00502800702823f031048", + "0x1b02824c00536b00502804602824900536b00502802002824500536b005", + "0x36b00502802302824d00536b00524c24900736402824c00536b00524c005", + "0x2825200536b00524f00536302824f00536b00524d24e00702d02824e005", + "0x524500509202800500536b0050050050db02809200536b00509200504f", + "0x525200536b00525200508402803100536b0050310050c002824500536b", + "0x9200536b00502824902800b00536b00502824902825203124500509200b", + "0x736b00700502800700502802836b00502802802802836b00502824c028", + "0x1300536b00501000503102802836b00502800702804e1c80074d601000f", + "0x36b00500f00504f02802836b00502800b02801400536b00503100500a028", + "0x4d703004d00736b00701400500f02801300536b00501300509202800f005", + "0x3000501002801800536b00501300503102802836b005028007028017005", + "0x1b00536b00536800504e02836800536b0053690051c802836900536b005", + "0x1b00501402836700536b00504d00501302801c00536b005018005092028", + "0x1300503102802836b0050280070280284d800502804d02836600536b005", + "0x2836500536b00502000501702802000536b00502803002801f00536b005", + "0x536500501402836700536b00501700501302801c00536b00501f005092", + "0x2836b0050280070283640054d904f00536b00736600501802836600536b", + "0x504f09200724d02802300536b00501c00503102802836b005028369028", + "0x2d00736b00704f00f00724e02802300536b00502300509202804f00536b", + "0x4f02808400536b00502300503102802836b0050280070280c00054da363", + "0x36b00736700500f02808400536b00508400509202802d00536b00502d005", + "0x3200536b00508400503102802836b00502800702835f0054db1aa361007", + "0x51c802800a00536b00500a00b00724d02800a00536b0051aa005010028", + "0x2836100536b00536100501302802836b00502800b02835d00536b00500a", + "0x2800c0054dc03336c00736b00736100500f02803200536b005032005092", + "0x536b00503300524f02803c00536b00503200503102802836b005028007", + "0x525202835e00536b00536c00501302804000536b00503c005092028036", + "0x503102802836b0050280070280284dd00502804d02835900536b005036", + "0x21c00536b00521500505002821500536b00502803002835600536b005032", + "0x21c00525202835e00536b00500c00501302804000536b005356005092028", + "0x36b0050280070280480054de04600536b00735900500902835900536b005", + "0x504600501002804700536b00504000503102802836b005028369028028", + "0x1c802823900536b00535e00535e02823700536b00502802002804500536b", + "0x36b00504700509202802d00536b00502d00504f02823b00536b005045005", + "0x1b02823700536b00523700521502823900536b00523900505b028047005", + "0x24924523f03136b00523b23723904702d00b05802823b00536b00523b005", + "0x503102802836b00502800702824d0054df24c00536b007249005059028", + "0x36b00524e00509202825224f00736b00524c00505c02824e00536b005245", + "0x2802836b0050280070280090054e005000536b00725200525c02824e005", + "0x505b00509202805800536b00524f00500a02805b00536b00524e005031", + "0x36b00502800702825c0054e105c05900736b00705800500f02805b00536b", + "0x505000504002802836b00505c00536702802836b00505900501c028028", + "0x5b00503102802836b00536300525d02802836b00535d00501f02802836b", + "0x1b02805e00536b00502836502825e00536b00502802002825d00536b005", + "0x36b00502802302806000536b00505e25e00736402805e00536b00505e005", + "0x2829600536b00505d00536302805d00536b00506005f00702d02805f005", + "0x50070050c002825d00536b00525d00509202823f00536b00523f00504f", + "0x2800702829600725d23f00a00529600536b00529600508402800700536b", + "0x36102829800536b00505b00503102802836b00525c00501c02802836b005", + "0x536b0050420051aa02829800536b00529800509202804200536b005028", + "0x50280070280680690074e22bd06700736b00704229823f03135f028042", + "0x509202806f00536b00502834102800600536b0052bd00503102802836b", + "0x536b00536300533802800700536b0050070050c002800600536b005006", + "0x4f2f502805000536b00505000521502835d00536b00535d00501b028363", + "0x6700536b00506700504f02807432507103136b00505035d36306f007006", + "0x533b02802836b0050280070280770054e307500536b00707400533c028", + "0x2834b00536b00502802002834c00536b00507100503102802836b005075", + "0x507a00535e02802836b00504300504002807a04300736b00534b005036", + "0x2834800536b00507f00535602807f00536b00507900535902807900536b", + "0x53250050c002834c00536b00534c00509202806700536b00506700504f", + "0x2800702834832534c06700a00534800536b00534800508402832500536b", + "0x2807d00536b00507700536302808100536b00507100503102802836b005", + "0x53250050c002808100536b00508100509202806700536b00506700504f", + "0x2800702807d32508106700a00507d00536b00507d00508402832500536b", + "0x525d02802836b00535d00501f02802836b00505000504002802836b005", + "0x2834500536b00502802002834600536b00506800503102802836b005363", + "0x534434500736402834400536b00534400501b02834400536b005028046", + "0x2834100536b00534334200702d02834200536b00502802302834300536b", + "0x534600509202806900536b00506900504f02833d00536b005341005363", + "0x533d00536b00533d00508402800700536b0050070050c002834600536b", + "0x23702802836b00500900504702802836b00502800702833d00734606900a", + "0x2802836b00536300525d02802836b00535d00501f02802836b00524f005", + "0x508c00509202833c00536b00523f00504f02808c00536b00524e005031", + "0x536300525d02802836b0050280070280284e400502804d02833b00536b", + "0x536302808a00536b00524500503102802836b00535d00501f02802836b", + "0x536b00508a00509202823f00536b00523f00504f02833a00536b00524d", + "0x23f00a00533a00536b00533a00508402800700536b0050070050c002808a", + "0x504800504702802836b00502836902802836b00502800702833a00708a", + "0x35e00501c02802836b00536300525d02802836b00535d00501f02802836b", + "0x2833c00536b00502d00504f02833900536b00504000503102802836b005", + "0x536b00502805e02808800536b00502802002833b00536b005339005092", + "0x2302833700536b00533808800736402833800536b00533800501b028338", + "0x36b00508600536302808600536b00533733600702d02833600536b005028", + "0xc002833b00536b00533b00509202833c00536b00533c00504f02808e005", + "0x8e00733b33c00a00508e00536b00508e00508402800700536b005007005", + "0x2836b00536300525d02802836b00535f00501c02802836b005028007028", + "0x36b00502802002837700536b00508400503102802836b00500b005060028", + "0x736402833200536b00533200501b02833200536b005028048028333005", + "0x36b00533133000702d02833000536b00502802302833100536b005332333", + "0x9202802d00536b00502d00504f02832e00536b00532f00536302832f005", + "0x36b00532e00508402800700536b0050070050c002837700536b005377005", + "0x36b00536700501c02802836b00502800702832e00737702d00a00532e005", + "0xc000504f02832d00536b00502300503102802836b00500b005060028028", + "0x70280284e500502804d02808b00536b00532d00509202832c00536b005", + "0x501c02802836b00536400504702802836b00502836902802836b005028", + "0x3102802836b00509200506002802836b00500b00506002802836b005367", + "0x36b00532b00509202832c00536b00500f00504f02832b00536b00501c005", + "0x32900501b02832900536b00502804502832a00536b00502802002808b005", + "0x8500536b00502802302832600536b00532932a00736402832900536b005", + "0x504f02809500536b00509300536302809300536b00532608500702d028", + "0x536b0050070050c002808b00536b00508b00509202832c00536b00532c", + "0x36b00502800702809500708b32c00a00509500536b005095005084028007", + "0x503100523702802836b00500b00506002802836b005092005060028028", + "0x2804602809800536b00502802002832400536b00504e00503102802836b", + "0x536b00532309800736402832300536b00532300501b02832300536b005", + "0x536302832100536b00509632200702d02832200536b005028023028096", + "0x536b0053240050920281c800536b0051c800504f02831f00536b005321", + "0x1c800a00531f00536b00531f00508402800700536b0050070050c0028324", + "0x4e600b00a00736b00700502800700502802836b00502802802831f007324", + "0x500a02800f00536b00500b00503102802836b00502800702809204f007", + "0x536b00500f00509202800a00536b00500a00504f02801000536b005031", + "0x2802836b0050280070280130054e704e1c800736b00701000500f02800f", + "0x51c800501302804d00536b00504e00501002801400536b00500f005031", + "0x2804d00536b00504d00501b02801400536b0050140050920281c800536b", + "0x501c02802836b0050280070280180054e801703000736b0071c800500f", + "0x3102802836b00504d00501f02802836b00501700536702802836b005030", + "0x1b00536b00502836502836800536b00502802002836900536b005014005", + "0x2802302801c00536b00501b36800736402801b00536b00501b00501b028", + "0x536b00536600536302836600536b00501c36700702d02836700536b005", + "0x50c002836900536b00536900509202800a00536b00500a00504f02801f", + "0x2801f00736900a00a00501f00536b00501f00508402800700536b005007", + "0x2000536b00501400503102802836b00501800501c02802836b005028007", + "0x53650051aa02802000536b00502000509202836500536b005028361028", + "0x702836302d0074e902336400736b00736502000a03135f02836500536b", + "0x2808400536b0050280200280c000536b00502300503102802836b005028", + "0x1aa0050360281aa00536b00536108400736402836100536b00504d0051c8", + "0x35d00536b00503200535e02802836b00535f00504002803235f00736b005", + "0x36400504f02803300536b00536c00535602836c00536b00535d005359028", + "0x700536b0050070050c00280c000536b0050c000509202836400536b005", + "0x2836b0050280070280330070c036400a00503300536b005033005084028", + "0x36b00502802002800c00536b00536300503102802836b00504d00501f028", + "0x736402803600536b00503600501b02803600536b00502804602803c005", + "0x36b00504035e00702d02835e00536b00502802302804000536b00503603c", + "0x9202802d00536b00502d00504f02835600536b005359005363028359005", + "0x36b00535600508402800700536b0050070050c002800c00536b00500c005", + "0x36b00501300501c02802836b00502800702835600700c02d00a005356005", + "0x502804502821c00536b00502802002821500536b00500f005031028028", + "0x4800536b00504621c00736402804600536b00504600501b02804600536b", + "0x4500536302804500536b00504804700702d02804700536b005028023028", + "0x21500536b00521500509202800a00536b00500a00504f02823700536b005", + "0x21500a00a00523700536b00523700508402800700536b0050070050c0028", + "0x509200503102802836b00503100523702802836b005028007028237007", + "0x501b02823f00536b00502804602823b00536b00502802002823900536b", + "0x536b00502802302824500536b00523f23b00736402823f00536b00523f", + "0x4f02824d00536b00524c00536302824c00536b00524524900702d028249", + "0x36b0050070050c002823900536b00523900509202804f00536b00504f005", + "0x502802802824d00723904f00a00524d00536b00524d005084028007005", + "0x502800702809204f0074ea00b00a00736b00700502800700502802836b", + "0x4f02801000536b00503100500a02800f00536b00500b00503102802836b", + "0x36b00701000500f02800f00536b00500f00509202800a00536b00500a005", + "0x2802836b0051c800501c02802836b0050280070280130054eb04e1c8007", + "0x536b00502802002801400536b00500f00503102802836b00504e005367", + "0x4d00736402803000536b00503000501b02803000536b00502836502804d", + "0x536b00501701800702d02801800536b00502802302801700536b005030", + "0x509202800a00536b00500a00504f02836800536b005369005363028369", + "0x536b00536800508402800700536b0050070050c002801400536b005014", + "0x2836b00501300501c02802836b00502800702836800701400a00a005368", + "0x501b00509202801c00536b00502836102801b00536b00500f005031028", + "0x736b00701c01b00a03135f02801c00536b00501c0051aa02801b00536b", + "0x36500536b00536600503102802836b00502800702802001f0074ec366367", + "0x2300504002802d02300736b00536400503602836400536b005028020028", + "0x280c000536b00536300535902836300536b00502d00535e02802836b005", + "0x536500509202836700536b00536700504f02808400536b0050c0005356", + "0x508400536b00508400508402800700536b0050070050c002836500536b", + "0x2836100536b00502000503102802836b00502800702808400736536700a", + "0x536b00535f00501b02835f00536b0050280460281aa00536b005028020", + "0x702d02835d00536b00502802302803200536b00535f1aa00736402835f", + "0x36b00501f00504f02803300536b00536c00536302836c00536b00503235d", + "0x8402800700536b0050070050c002836100536b00536100509202801f005", + "0x23702802836b00502800702803300736101f00a00503300536b005033005", + "0x3c00536b00502802002800c00536b00509200503102802836b005031005", + "0x3603c00736402803600536b00503600501b02803600536b005028046028", + "0x35900536b00504035e00702d02835e00536b00502802302804000536b005", + "0xc00509202804f00536b00504f00504f02835600536b005359005363028", + "0x35600536b00535600508402800700536b0050070050c002800c00536b005", + "0x736b00700702800700502802836b00502802802835600700c04f00a005", + "0x1000536b00504f00503102802836b00502800702800f0920074ed04f00b", + "0x1000509202800b00536b00500b00504f0281c800536b00500a00500a028", + "0x50280070280140054ee01304e00736b0071c800500f02801000536b005", + "0x1000503102802836b00501300536702802836b00504e00501c02802836b", + "0x1b02801700536b00502836502803000536b00502802002804d00536b005", + "0x36b00502802302801800536b00501703000736402801700536b005017005", + "0x2801b00536b00536800536302836800536b00501836900702d028369005", + "0x504d00509202800500536b00500500530702800b00536b00500b00504f", + "0x501b00536b00501b00508402803100536b0050310050c002804d00536b", + "0x2802836b00501400501c02802836b00502800702801b03104d00500b00b", + "0x36b00501c00509202836700536b00502836102801c00536b005010005031", + "0x36600736b00736701c00b03135f02836700536b0053670051aa02801c005", + "0x2836400536b00501f00503102802836b0050280070283650200074ef01f", + "0x536b00502300503302802d00536b0050282f302802300536b0050280e1", + "0xc036300a36b00502d0230050312f202802d00536b00502d005033028023", + "0x36100521c02802836b00508400521c02802836b0050c000521c028361084", + "0x2803235f00736b0051aa0050360281aa00536b00502802002802836b005", + "0x36b00535d00535902835d00536b00503200535e02802836b00535f005040", + "0x30702836600536b00536600504f02803300536b00536c00535602836c005", + "0x36b0050310050c002836400536b00536400509202836300536b005363005", + "0x2800702803303136436336600b00503300536b005033005084028031005", + "0x4602803c00536b00502802002800c00536b00536500503102802836b005", + "0x36b00503603c00736402803600536b00503600501b02803600536b005028", + "0x36302835900536b00504035e00702d02835e00536b005028023028040005", + "0x36b00500500530702802000536b00502000504f02835600536b005359005", + "0x8402803100536b0050310050c002800c00536b00500c005092028005005", + "0x2802836b00502800702835603100c00502000b00535600536b005356005", + "0x536b00502802002821500536b00500f00503102802836b00500a005237", + "0x21c00736402804600536b00504600501b02804600536b00502804602821c", + "0x536b00504804700702d02804700536b00502802302804800536b005046", + "0x530702809200536b00509200504f02823700536b005045005363028045", + "0x536b0050310050c002821500536b00521500509202800500536b005005", + "0x502802802823703121500509200b00523700536b005237005084028031", + "0x502800702800f0920074f004f00b00736b00700700500700502802836b", + "0x4f0281c800536b00500a00500a02801000536b00504f00503102802836b", + "0x36b0071c800500f02801000536b00501000509202800b00536b00500b005", + "0x2802836b00504e00501c02802836b0050280070280140054f101304e007", + "0x536b00502802002804d00536b00501000503102802836b005013005367", + "0x3000736402801700536b00501700501b02801700536b005028365028030", + "0x536b00501836900702d02836900536b00502802302801800536b005017", + "0x504f02802800536b0050280050c602801b00536b005368005363028368", + "0x536b0050310050c002804d00536b00504d00509202800b00536b00500b", + "0x502800702801b03104d00b02800b00501b00536b00501b005084028031", + "0x2836102801c00536b00501000503102802836b00501400501c02802836b", + "0x36700536b0053670051aa02801c00536b00501c00509202836700536b005", + "0x36b0050280070283650200074f201f36600736b00736701c00b03135f028", + "0x502823f02802300536b00502823b02836400536b00501f005031028028", + "0x2802d00536b00502d00501b02802300536b00502300501b02802d00536b", + "0x2802002802836b0050c000501f0280c036300736b00502d0230280310e3", + "0x2836b0053610050400281aa36100736b00508400503602808400536b005", + "0x3200535602803200536b00535f00535902835f00536b0051aa00535e028", + "0x36600536b00536600504f02836300536b0053630050c602835d00536b005", + "0x35d00508402803100536b0050310050c002836400536b005364005092028", + "0x503102802836b00502800702835d03136436636300b00535d00536b005", + "0x2800c00536b00502804602803300536b00502802002836c00536b005365", + "0x502802302803c00536b00500c03300736402800c00536b00500c00501b", + "0x35e00536b00504000536302804000536b00503c03600702d02803600536b", + "0x36c00509202802000536b00502000504f02802800536b0050280050c6028", + "0x35e00536b00535e00508402803100536b0050310050c002836c00536b005", + "0x2836b00500a00523702802836b00502800702835e03136c02002800b005", + "0x36b00502804602835600536b00502802002835900536b00500f005031028", + "0x2821c00536b00521535600736402821500536b00521500501b028215005", + "0x504800536302804800536b00521c04600702d02804600536b005028023", + "0x2809200536b00509200504f02802800536b0050280050c602804700536b", + "0x504700508402803100536b0050310050c002835900536b005359005092", + "0x2800700502802836b00502802802804703135909202800b00504700536b", + "0x4f00503102802836b00502800702800f0920074f304f00b00736b007007", + "0xb00536b00500b00504f0281c800536b00500a00500a02801000536b005", + "0x140054f401304e00736b0071c800500f02801000536b005010005092028", + "0x2836b00501300536702802836b00504e00501c02802836b005028007028", + "0x36b00502836502803000536b00502802002804d00536b005010005031028", + "0x2801800536b00501703000736402801700536b00501700501b028017005", + "0x536800536302836800536b00501836900702d02836900536b005028023", + "0x2800500536b0050050052f402800b00536b00500b00504f02801b00536b", + "0x501b00508402803100536b0050310050c002804d00536b00504d005092", + "0x1400501c02802836b00502800702801b03104d00500b00b00501b00536b", + "0x9202836700536b00502836102801c00536b00501000503102802836b005", + "0x36701c00b03135f02836700536b0053670051aa02801c00536b00501c005", + "0x501f00503102802836b0050280070283650200074f501f36600736b007", + "0x2823b02802d00536b00502823b02802300536b00502823b02836400536b", + "0x2802300536b00502300501b0280c000536b00502823f02836300536b005", + "0x502d00501b02836100536b00502823f02808400536b0050c00230072e0", + "0x8400536b00508400501b0281aa00536b00536102d0072e002802d00536b", + "0x500a2de02836300536b00536300501b0281aa00536b0051aa00501b028", + "0x501f02802836b00503200501f02836c35d03235f00a36b0053631aa084", + "0x3602803300536b00502802002802836b00536c00501f02802836b00535d", + "0x36b00503c00535e02802836b00500c00504002803c00c00736b005033005", + "0x4f02835e00536b00504000535602804000536b005036005359028036005", + "0x36b00536400509202835f00536b00535f0052f402836600536b005366005", + "0xb00535e00536b00535e00508402803100536b0050310050c0028364005", + "0x2835900536b00536500503102802836b00502800702835e03136435f366", + "0x536b00521500501b02821500536b00502804602835600536b005028020", + "0x702d02804600536b00502802302821c00536b005215356007364028215", + "0x36b00502000504f02804700536b00504800536302804800536b00521c046", + "0xc002835900536b00535900509202800500536b0050050052f4028020005", + "0x3135900502000b00504700536b00504700508402803100536b005031005", + "0x36b00500f00503102802836b00500a00523702802836b005028007028047", + "0x23900501b02823900536b00502804602823700536b005028020028045005", + "0x23f00536b00502802302823b00536b00523923700736402823900536b005", + "0x504f02824900536b00524500536302824500536b00523b23f00702d028", + "0x536b00504500509202800500536b0050050052f402809200536b005092", + "0x9200b00524900536b00524900508402803100536b0050310050c0028045", + "0x4f00b00736b00700702800700502802836b005028028028249031045005", + "0xa02801000536b00504f00503102802836b00502800702800f0920074f6", + "0x36b00501000509202800b00536b00500b00504f0281c800536b00500a005", + "0x2836b0050280070280140054f701304e00736b0071c800500f028010005", + "0x36b00501000503102802836b00501300536702802836b00504e00501c028", + "0x1700501b02801700536b00502836502803000536b00502802002804d005", + "0x36900536b00502802302801800536b00501703000736402801700536b005", + "0x504f02801b00536b00536800536302836800536b00501836900702d028", + "0x536b00504d00509202800500536b0050050050da02800b00536b00500b", + "0xb00b00501b00536b00501b00508402803100536b0050310050c002804d", + "0x503102802836b00501400501c02802836b00502800702801b03104d005", + "0x1c00536b00501c00509202836700536b00502836102801c00536b005010", + "0x4f801f36600736b00736701c00b03135f02836700536b0053670051aa028", + "0x282dd02836400536b00501f00503102802836b005028007028365020007", + "0x2802300536b00502300501b02802d00536b0050281a602802300536b005", + "0x536400509202836600536b00536600504f02802d00536b00502d00501b", + "0x2836b0050280070280284f936300536b00702d0230072db02836400536b", + "0x36b0050282d702808400536b0050282da0280c000536b005364005031028", + "0xee02836300536b0053630050ea02836100536b00536100501b028361005", + "0x2802002802836b00535f0052d602835f1aa00736b00536336108400500a", + "0x2836b00535d00504002836c35d00736b00503200503602803200536b005", + "0xc00535602800c00536b00503300535902803300536b00536c00535e028", + "0x1aa00536b0051aa0050da02836600536b00536600504f02803c00536b005", + "0x3c00508402803100536b0050310050c00280c000536b0050c0005092028", + "0x503102802836b00502800702803c0310c01aa36600b00503c00536b005", + "0x2835e00536b00502824502804000536b00502802002803600536b005364", + "0x502802302835900536b00535e04000736402835e00536b00535e00501b", + "0x21c00536b00521500536302821500536b00535935600702d02835600536b", + "0x3600509202800500536b0050050050da02836600536b00536600504f028", + "0x21c00536b00521c00508402803100536b0050310050c002803600536b005", + "0x536b00536500503102802836b00502800702821c03103600536600b005", + "0x504700501b02804700536b00502804602804800536b005028020028046", + "0x2823700536b00502802302804500536b00504704800736402804700536b", + "0x2000504f02823b00536b00523900536302823900536b00504523700702d", + "0x4600536b00504600509202800500536b0050050050da02802000536b005", + "0x502000b00523b00536b00523b00508402803100536b0050310050c0028", + "0xf00503102802836b00500a00523702802836b00502800702823b031046", + "0x1b02824900536b00502804602824500536b00502802002823f00536b005", + "0x36b00502802302824c00536b00524924500736402824900536b005249005", + "0x2824f00536b00524e00536302824e00536b00524c24d00702d02824d005", + "0x523f00509202800500536b0050050050da02809200536b00509200504f", + "0x524f00536b00524f00508402803100536b0050310050c002823f00536b", + "0x736b00700502800700502802836b00502802802824f03123f00509200b", + "0xf00536b00500b00503102802836b00502800702809204f0074fa00b00a", + "0xf00509202800a00536b00500a00504f02801000536b00503100500a028", + "0x50280070280130054fb04e1c800736b00701000500f02800f00536b005", + "0x1f02804d00536b00504e00501002801400536b00500f00503102802836b", + "0x536b0050140050920281c800536b0051c800501302802836b00504d005", + "0x2802836b0050280070280180054fc01703000736b0071c800500f028014", + "0x503000501302836800536b00501700501002836900536b005014005031", + "0x2836800536b00536800501b02836900536b00536900509202803000536b", + "0x501c02802836b0050280070283670054fd01c01b00736b00703000500f", + "0x3102802836b00536800501f02802836b00501c00536702802836b00501b", + "0x2000536b00502836502801f00536b00502802002836600536b005369005", + "0x2802302836500536b00502001f00736402802000536b00502000501b028", + "0x536b00502300536302802300536b00536536400702d02836400536b005", + "0x50c002836600536b00536600509202800a00536b00500a00504f02802d", + "0x2802d00736600a00a00502d00536b00502d00508402800700536b005007", + "0x36300536b00536900503102802836b00536700501c02802836b005028007", + "0x50c00051aa02836300536b0053630050920280c000536b005028361028", + "0x702835f1aa0074fe36108400736b0070c036300a03135f0280c000536b", + "0x2835d00536b00502802002803200536b00536100503102802836b005028", + "0x3300503602803300536b00536c35d00736402836c00536b0053680051c8", + "0x3600536b00503c00535e02802836b00500c00504002803c00c00736b005", + "0x8400504f02835e00536b00504000535602804000536b005036005359028", + "0x700536b0050070050c002803200536b00503200509202808400536b005", + "0x2836b00502800702835e00703208400a00535e00536b00535e005084028", + "0x36b00502802002835900536b00535f00503102802836b00536800501f028", + "0x736402821500536b00521500501b02821500536b005028046028356005", + "0x36b00521c04600702d02804600536b00502802302821c00536b005215356", + "0x920281aa00536b0051aa00504f02804700536b005048005363028048005", + "0x36b00504700508402800700536b0050070050c002835900536b005359005", + "0x36b00501800501c02802836b0050280070280470073591aa00a005047005", + "0x502804802823700536b00502802002804500536b005014005031028028", + "0x23b00536b00523923700736402823900536b00523900501b02823900536b", + "0x24500536302824500536b00523b23f00702d02823f00536b005028023028", + "0x4500536b00504500509202800a00536b00500a00504f02824900536b005", + "0x4500a00a00524900536b00524900508402800700536b0050070050c0028", + "0x500f00503102802836b00501300501c02802836b005028007028249007", + "0x501b02824e00536b00502804502824d00536b00502802002824c00536b", + "0x536b00502802302824f00536b00524e24d00736402824e00536b00524e", + "0x4f02800900536b00505000536302805000536b00524f25200702d028252", + "0x36b0050070050c002824c00536b00524c00509202800a00536b00500a005", + "0x502800702800900724c00a00a00500900536b005009005084028007005", + "0x2802002805b00536b00509200503102802836b00503100523702802836b", + "0x2805900536b00505900501b02805900536b00502804602805800536b005", + "0x5c25c00702d02825c00536b00502802302805c00536b005059058007364", + "0x4f00536b00504f00504f02825e00536b00525d00536302825d00536b005", + "0x25e00508402800700536b0050070050c002805b00536b00505b005092028", + "0x2800700502802836b00502802802825e00705b04f00a00525e00536b005", + "0xb00503102802836b00502800702809204f0074ff00b00a00736b007005", + "0xa00536b00500a00504f02801000536b00503100500a02800f00536b005", + "0x1300550004e1c800736b00701000500f02800f00536b00500f005092028", + "0x36b00504e00501002801400536b00500f00503102802836b005028007028", + "0x51c800501302802836b00502800b02802836b00504d00501f02804d005", + "0x1703000736b0071c800500f02801400536b0050140050920281c800536b", + "0x501002836900536b00501400503102802836b005028007028018005501", + "0x536b00501b00504e02801b00536b0053680051c802836800536b005017", + "0x501402836600536b00503000501302836700536b00536900509202801c", + "0x503102802836b00502800702802850200502804d02801f00536b00501c", + "0x36400536b00536500501702836500536b00502803002802000536b005014", + "0x36400501402836600536b00501800501302836700536b005020005092028", + "0x36b00502800702802d00550302300536b00701f00501802801f00536b005", + "0x536300509202836300536b00536700503102802836b005028369028028", + "0x50280070283610055040840c000736b00702300a00736802836300536b", + "0x920280c000536b0050c000504f0281aa00536b00536300503102802836b", + "0x702835d00550503235f00736b00736600500f0281aa00536b0051aa005", + "0x3300536b00503200501002836c00536b0051aa00503102802836b005028", + "0x3300501b02836c00536b00536c00509202835f00536b00535f005013028", + "0x502800702803600550603c00c00736b00735f00500f02803300536b005", + "0x3300501f02802836b00503c00536702802836b00500c00501c02802836b", + "0x2002804000536b00536c00503102802836b00508400536602802836b005", + "0x35900536b00535900501b02835900536b00502836502835e00536b005028", + "0x21500702d02821500536b00502802302835600536b00535935e007364028", + "0x536b0050c000504f02804600536b00521c00536302821c00536b005356", + "0x508402800700536b0050070050c002804000536b0050400050920280c0", + "0x501c02802836b0050280070280460070400c000a00504600536b005046", + "0x2804700536b00502836102804800536b00536c00503102802836b005036", + "0x480c003135f02804700536b0050470051aa02804800536b005048005092", + "0x23700503102802836b00502800702823b23900750723704500736b007047", + "0x2824900536b00502803202824500536b0050330051c802823f00536b005", + "0x24900503302823f00536b00523f00509202824c24500736b0052450050dc", + "0x24c08424900723f00b00c02804500536b00504500504f02824900536b005", + "0x24d00509202802836b00502800702805025224f03150824e24d00736b007", + "0x2805b00536b00502802002800900536b00524d00503102824d00536b005", + "0x504002805c05900736b00505800503602805800536b00524505b007364", + "0x25d00536b00525c00535902825c00536b00505c00535e02802836b005059", + "0x900509202804500536b00504500504f02825e00536b00525d005356028", + "0x25e00536b00525e00508402824e00536b00524e0050c002800900536b005", + "0x2802836b00524500501f02802836b00502800702825e24e00904500a005", + "0x36b00502802302805e00536b00524f00503102824f00536b00524f005092", + "0x2805d00536b00505f00536302805f00536b00505006000702d028060005", + "0x52520050c002805e00536b00505e00509202804500536b00504500504f", + "0x2800702805d25205e04500a00505d00536b00505d00508402825200536b", + "0x503102802836b00508400536602802836b00503300501f02802836b005", + "0x2804200536b00502804602829800536b00502802002829600536b00523b", + "0x502802302806700536b00504229800736402804200536b00504200501b", + "0x6800536b00506900536302806900536b0050672bd00702d0282bd00536b", + "0x70050c002829600536b00529600509202823900536b00523900504f028", + "0x702806800729623900a00506800536b00506800508402800700536b005", + "0x3102802836b00508400536602802836b00535d00501c02802836b005028", + "0x7100536b00502805e02806f00536b00502802002800600536b0051aa005", + "0x2802302832500536b00507106f00736402807100536b00507100501b028", + "0x536b00507500536302807500536b00532507400702d02807400536b005", + "0x50c002800600536b0050060050920280c000536b0050c000504f028077", + "0x280770070060c000a00507700536b00507700508402800700536b005007", + "0x34c00536b00536300503102802836b00536600501c02802836b005028007", + "0x502804d02804300536b00534c00509202834b00536b00536100504f028", + "0x36b00502d00504702802836b00502836902802836b005028007028028509", + "0xa00504f02807a00536b00536700503102802836b00536600501c028028", + "0x2807900536b00502802002804300536b00507a00509202834b00536b005", + "0x507f07900736402807f00536b00507f00501b02807f00536b005028048", + "0x2807d00536b00534808100702d02808100536b00502802302834800536b", + "0x504300509202834b00536b00534b00504f02834600536b00507d005363", + "0x534600536b00534600508402800700536b0050070050c002804300536b", + "0x3102802836b00501300501c02802836b00502800702834600704334b00a", + "0x34300536b00502804502834400536b00502802002834500536b00500f005", + "0x2802302834200536b00534334400736402834300536b00534300501b028", + "0x536b00533d00536302833d00536b00534234100702d02834100536b005", + "0x50c002834500536b00534500509202800a00536b00500a00504f02808c", + "0x2808c00734500a00a00508c00536b00508c00508402800700536b005007", + "0x33c00536b00509200503102802836b00503100523702802836b005028007", + "0x36b00508a00501b02808a00536b00502804602833b00536b005028020028", + "0x2d02833900536b00502802302833a00536b00508a33b00736402808a005", + "0x504f00504f02833800536b00508800536302808800536b00533a339007", + "0x2800700536b0050070050c002833c00536b00533c00509202804f00536b", + "0x2802836b00502802802833800733c04f00a00533800536b005338005084", + "0x2802836b00502800702809204f00750a00b00a00736b007005028007005", + "0x500a00504f02801000536b00503100500a02800f00536b00500b005031", + "0x4e1c800736b00701000500f02800f00536b00500f00509202800a00536b", + "0x501002801400536b00500f00503102802836b00502800702801300550b", + "0x536b0050140050920281c800536b0051c800501302804d00536b00504e", + "0x550c01703000736b0071c800500f02804d00536b00504d00501b028014", + "0x501700501002836900536b00501400503102802836b005028007028018", + "0x2836900536b00536900509202803000536b00503000501302836800536b", + "0x2836700550d01c01b00736b00703000500f02836800536b00536800501b", + "0x2802836b00501c00536702802836b00501b00501c02802836b005028007", + "0x536b00536900503102802836b00536800501f02802836b00504d00501f", + "0x502000501b02802000536b00502836502801f00536b005028020028366", + "0x2836400536b00502802302836500536b00502001f00736402802000536b", + "0xa00504f02802d00536b00502300536302802300536b00536536400702d", + "0x700536b0050070050c002836600536b00536600509202800a00536b005", + "0x2836b00502800702802d00736600a00a00502d00536b00502d005084028", + "0x36b00502836102836300536b00536900503102802836b00536700501c028", + "0x35f0280c000536b0050c00051aa02836300536b0053630050920280c0005", + "0x2802836b00502800702835f1aa00750e36108400736b0070c036300a031", + "0x36b00535d00533a02835d00536b00502808a02803200536b005361005031", + "0xdc02800c00536b0053680051c802803300536b00504d0051c802836c005", + "0x502803202803600536b00500c03c0072e002803c03300736b005033005", + "0x2804000536b00504000503302803200536b00503200509202804000536b", + "0x508400504f02803600536b00503600501b02836c00536b00536c005088", + "0x21535603150f35935e00736b00703636c04000703200b00c02808400536b", + "0x535e00503102835e00536b00535e00509202802836b00502800702821c", + "0x2804700536b00503304800736402804800536b00502802002804600536b", + "0x523700535e02802836b00504500504002823704500736b005047005036", + "0x2823f00536b00523b00535602823b00536b00523900535902823900536b", + "0x53590050c002804600536b00504600509202808400536b00508400504f", + "0x2800702823f35904608400a00523f00536b00523f00508402835900536b", + "0x3102835600536b00535600509202802836b00503300501f02802836b005", + "0x36b00521c24900702d02824900536b00502802302824500536b005356005", + "0x9202808400536b00508400504f02824d00536b00524c00536302824c005", + "0x36b00524d00508402821500536b0052150050c002824500536b005245005", + "0x36b00504d00501f02802836b00502800702824d21524508400a00524d005", + "0x502802002824e00536b00535f00503102802836b00536800501f028028", + "0x36402825200536b00525200501b02825200536b00502804602824f00536b", + "0x505000900702d02800900536b00502802302805000536b00525224f007", + "0x281aa00536b0051aa00504f02805800536b00505b00536302805b00536b", + "0x505800508402800700536b0050070050c002824e00536b00524e005092", + "0x501800501c02802836b00502800702805800724e1aa00a00505800536b", + "0x2802002805900536b00501400503102802836b00504d00501f02802836b", + "0x2825c00536b00525c00501b02825c00536b00502804802805c00536b005", + "0x25d25e00702d02825e00536b00502802302825d00536b00525c05c007364", + "0xa00536b00500a00504f02806000536b00505e00536302805e00536b005", + "0x6000508402800700536b0050070050c002805900536b005059005092028", + "0x1300501c02802836b00502800702806000705900a00a00506000536b005", + "0x4502805d00536b00502802002805f00536b00500f00503102802836b005", + "0x36b00529605d00736402829600536b00529600501b02829600536b005028", + "0x36302806700536b00529804200702d02804200536b005028023028298005", + "0x36b00505f00509202800a00536b00500a00504f0282bd00536b005067005", + "0xa0052bd00536b0052bd00508402800700536b0050070050c002805f005", + "0x503102802836b00503100523702802836b0050280070282bd00705f00a", + "0x2800600536b00502804602806800536b00502802002806900536b005092", + "0x502802302806f00536b00500606800736402800600536b00500600501b", + "0x7400536b00532500536302832500536b00506f07100702d02807100536b", + "0x70050c002806900536b00506900509202804f00536b00504f00504f028", + "0x36902807400706904f00a00507400536b00507400508402800700536b005", + "0x702800f09200751004f00b00736b00700502800700502802836b005028", + "0xa00736b00500a0050dc02801000536b00504f00503102802836b005028", + "0x534802801000536b00501000509202800b00536b00500b00504f0281c8", + "0x2836b00500a00501f02802836b00502800702804e00551102836b0071c8", + "0x70072d302801400536b0050310052d402801300536b005010005031028", + "0x536b00500b00504f02803000536b00504d0052d202804d00536b005014", + "0xb03100503000536b0050300052d102801300536b00501300509202800b", + "0x501000503102802836b00504e00534602802836b005028007028030013", + "0x509202802836b00502800b02801800536b00500700500a02801700536b", + "0x2800702801b00551236836900736b00701800500f02801700536b005017", + "0x2836700536b00536800501002801c00536b00501700503102802836b005", + "0x501c00509202801f00536b00536600504e02836600536b0053670051c8", + "0x2836400536b00501f00501402836500536b00536900501302802000536b", + "0x2802300536b00501700503102802836b00502800702802851300502804d", + "0x36b00502300509202836300536b00502d00501702802d00536b005028030", + "0x35e02836400536b00536300501402836500536b00501b005013028020005", + "0x2800702836100551408400536b0073640050180280c000536b005365005", + "0x73640281aa00536b00502000503102802836b00502836902802836b005", + "0x36b00503200a00732c02803200536b00502823f02835f00536b005084031", + "0x5b0281aa00536b0051aa00509202800b00536b00500b00504f02835d005", + "0x36b00535d00501b02835f00536b00535f0052150280c000536b0050c0005", + "0x3336c03100500c03336c03136b00535d35f0c01aa00b00b05802835d005", + "0x2836b00500a00501f02802836b00502836902802836b00502800702800c", + "0x53610052d002803c00536b00502000503102802836b005031005040028", + "0x35e00536b0050400052d202804000536b0050360c00072d302803600536b", + "0x35e0052d102803c00536b00503c00509202800b00536b00500b00504f028", + "0x500a00501f02802836b00502800702835e03c00b03100535e00536b005", + "0xf00503102802836b00500700523702802836b00503100504002802836b", + "0x1b02821500536b00502804602835600536b00502802002835900536b005", + "0x36b00502802302821c00536b00521535600736402821500536b005215005", + "0x2804700536b0050480052cf02804800536b00521c04600702d028046005", + "0x50470052d102835900536b00535900509202809200536b00509200504f", + "0x700502800700502802836b00502836902804735909203100504700536b", + "0x36b00500b00503102802836b00502800702809204f00751500b00a00736b", + "0x9202800a00536b00500a00504f02801000536b00503100500a02800f005", + "0x702801300551604e1c800736b00701000500f02800f00536b00500f005", + "0x4d00536b00504e00501002801400536b00500f00503102802836b005028", + "0x700736402803000536b00503000501b02803000536b00504d0051c8028", + "0x536b00500a00504f02801800536b0051c800535e02801700536b005030", + "0x505b02801700536b00501700521502801400536b00501400509202800a", + "0x3100501b36836903136b00501801701400a00a06802801800536b005018", + "0xf00503102802836b00501300501c02802836b00502800702801b368369", + "0x36600536b0053670070072cc02836700536b00502803002801c00536b005", + "0x1c00509202800a00536b00500a00504f02801f00536b0053660050f6028", + "0x2800702801f01c00a03100501f00536b00501f0050f802801c00536b005", + "0x503102802836b00503100523702802836b00500700504002802836b005", + "0x2836400536b00502804602836500536b00502802002802000536b005092", + "0x502802302802300536b00536436500736402836400536b00536400501b", + "0xc000536b0053630052cb02836300536b00502302d00702d02802d00536b", + "0xc00050f802802000536b00502000509202804f00536b00504f00504f028", + "0x502800700502802836b0050283690280c002004f0310050c000536b005", + "0x500b00503102802836b00502800702809204f00751700b00a00736b007", + "0x2800a00536b00500a00504f02801000536b00500700500a02800f00536b", + "0x2801300551804e1c800736b00701000500f02800f00536b00500f005092", + "0x536b00504e00501002801400536b00500f00503102802836b005028007", + "0x736402803000536b00503000501b02803000536b00504d0051c802804d", + "0x36b00500a00504f02801800536b0051c800535e02801700536b005030031", + "0x21502801800536b00501800505b02801400536b00501400509202800a005", + "0x501b36836903136b00501701801400a00a07502801700536b005017005", + "0x503102802836b00501300501c02802836b00502800702801b368369031", + "0x536b0053670310072cc02836700536b00502803002801c00536b00500f", + "0x509202800a00536b00500a00504f02801f00536b0053660050f6028366", + "0x702801f01c00a03100501f00536b00501f0050f802801c00536b00501c", + "0x3102802836b00503100504002802836b00500700523702802836b005028", + "0x36400536b00502804602836500536b00502802002802000536b005092005", + "0x2802302802300536b00536436500736402836400536b00536400501b028", + "0x536b0053630052cb02836300536b00502302d00702d02802d00536b005", + "0x50f802802000536b00502000509202804f00536b00504f00504f0280c0", + "0x2823b02800b00536b0050280200280c002004f0310050c000536b0050c0", + "0x536b00504f00b00736402804f00536b00504f00501b02804f00536b005", + "0x535e02802836b00500f00504002801000f00736b005092005036028092", + "0x736b0051c80052ca0281c800536b0051c800505b0281c800536b005010", + "0x36b00701304e00502800a2c90280131c800736b0051c80052ca02804e1c8", + "0x36b00501400509202802836b00502800702801801703003151904d014007", + "0x31702836900536b00536900509202836900536b005014005031028014005", + "0x2836b00502800702836636701c03151a01b36800736b00703104d369031", + "0x50280fa02801f00536b00536800503102836800536b005368005092028", + "0x2802000536b00502000501b02801f00536b00501f00509202802000536b", + "0x502800702836302d02303151b36436500736b0071c802001b01f00a316", + "0x8a0280c000536b00536500503102836500536b00536500509202802836b", + "0x1aa00536b0050280fa02836100536b00508400533a02808400536b005028", + "0x535f0050330280c000536b0050c000509202835f00536b005028032028", + "0x281aa00536b0051aa00501b02836100536b00536100508802835f00536b", + "0x2800702800c03336c03151c35d03200736b0071aa36135f3640c000b00c", + "0x2803c00536b00503200503102803200536b00503200509202802836b005", + "0x700a0050fc02803c00536b00503c00509202835d00536b00535d0050c0", + "0x2802836b00503600504702802836b00502800702804000551d03600536b", + "0x53590070070fb02835900536b00502803002835e00536b00503c005031", + "0x2835e00536b00535e00509202821500536b0053560050f902835600536b", + "0x21535d35e03100521500536b0052150052c802835d00536b00535d0050c0", + "0x2836b00500700532102802836b00504000504702802836b005028007028", + "0x36b0050282c702804600536b00502802002821c00536b00503c005031028", + "0x2804700536b00504804600736402804800536b00504800501b028048005", + "0x523700510202823700536b00504704500702d02804500536b005028023", + "0x2835d00536b00535d0050c002821c00536b00521c00509202823900536b", + "0x32102802836b00502800702823935d21c03100523900536b0052390052c8", + "0x36c00536b00536c00509202802836b00500a00534402802836b005007005", + "0xc23f00702d02823f00536b00502802302823b00536b00536c005031028", + "0x23b00536b00523b00509202824900536b00524500510202824500536b005", + "0x3323b03100524900536b0052490052c802803300536b0050330050c0028", + "0x36b00500a00534402802836b00500700532102802836b005028007028249", + "0x2802302824c00536b00502300503102802300536b005023005092028028", + "0x536b00524e00510202824e00536b00536324d00702d02824d00536b005", + "0x52c802802d00536b00502d0050c002824c00536b00524c00509202824f", + "0x700532102802836b00502800702824f02d24c03100524f00536b00524f", + "0x509202802836b0051c800523702802836b00500a00534402802836b005", + "0x5000536b00502802302825200536b00501c00503102801c00536b00501c", + "0x509202805b00536b00500900510202800900536b00536605000702d028", + "0x536b00505b0052c802836700536b0053670050c002825200536b005252", + "0x2802836b00500700532102802836b00502800702805b36725203100505b", + "0x2836b00503100534302802836b0051c800523702802836b00500a005344", + "0x502802302805800536b00503000503102803000536b005030005092028", + "0x25c00536b00505c00510202805c00536b00501805900702d02805900536b", + "0x25c0052c802801700536b0050170050c002805800536b005058005092028", + "0x502810402800b00536b00502802002825c01705803100525c00536b005", + "0x2802836b00509200504002800f09200736b00500b00503602804f00536b", + "0x4f00501b0281c803100736b00503100539602801000536b00500f00535e", + "0x3151e01401304e03136b00701004f1c800502800b25e02804f00536b005", + "0x4e00509202802836b00501400523702802836b00502800702801703004d", + "0x2836900536b00502802002801800536b00504e00503102804e00536b005", + "0x502803002801b00536b00536836900736402836800536b00500a00532d", + "0x2836600536b00536700510302836700536b00501c00508102801c00536b", + "0x502810102801f00536b00536601b00736402836600536b00536600501b", + "0x2802836b00536500504002836436500736b00501f00503602802000536b", + "0x502000501b02801800536b00501800509202802300536b00536400535e", + "0x702302003101301800b25e02802300536b00502300505b02802000536b", + "0xc000523702802836b0050280070281aa36108403151f0c036302d03136b", + "0x3102802d00536b00502d00509202802836b00500700532102802836b005", + "0x35d00536b0050282c602803200536b00502802002835f00536b00502d005", + "0x2802302836c00536b00535d03200736402835d00536b00535d00501b028", + "0x536b00500c00510202800c00536b00536c03300702d02803300536b005", + "0x52c802836300536b0053630050c002835f00536b00535f00509202803c", + "0x1aa00504002802836b00502800702803c36335f03100503c00536b00503c", + "0x2803600536b00508400503102808400536b00508400509202802836b005", + "0x36b00535e00510a02835e00536b0050400052c502804000536b00502808a", + "0x10c02821500536b00535600510902802836b00535900510b028356359007", + "0x536b00502803202804600536b00521c00533a02821c00536b005215005", + "0x508802804800536b00504800503302803600536b005036005092028048", + "0x3152023704504703136b00704604836103600a03c02804600536b005046", + "0x503102804700536b00504700509202802836b00502800702823f23b239", + "0x23700536b00523700501b02824900536b00502833902824500536b005047", + "0x50c002824c00536b00524c00501b02824c00536b00524923700732c028", + "0x2836b00724c00534802824500536b00524500509202804500536b005045", + "0x2803002824e00536b00524500503102802836b00502800702824d005521", + "0x536b0052520050f902825200536b00524f0070070fb02824f00536b005", + "0x52c802804500536b0050450050c002824e00536b00524e005092028050", + "0x24d00534602802836b00502800702805004524e03100505000536b005050", + "0x2002800900536b00524500503102802836b00500700532102802836b005", + "0x5800536b00505800501b02805800536b0050282c302805b00536b005028", + "0x5c00702d02805c00536b00502802302805900536b00505805b007364028", + "0x536b00500900509202825d00536b00525c00510202825c00536b005059", + "0x903100525d00536b00525d0052c802804500536b0050450050c0028009", + "0x523900509202802836b00500700532102802836b00502800702825d045", + "0x2d02805e00536b00502802302825e00536b00523900503102823900536b", + "0x525e00509202805f00536b00506000510202806000536b00523f05e007", + "0x505f00536b00505f0052c802823b00536b00523b0050c002825e00536b", + "0x534302802836b00500700532102802836b00502800702805f23b25e031", + "0x2804d00536b00504d00509202802836b00503100525d02802836b00500a", + "0x501729600702d02829600536b00502802302805d00536b00504d005031", + "0x2805d00536b00505d00509202804200536b00529800510202829800536b", + "0x4203005d03100504200536b0050420052c802803000536b0050300050c0", + "0x1c801000752200f09200736b00700502800700502802836b005028369028", + "0x36b00500b0052c202804e00536b00500f00503102802836b005028007028", + "0x4d03100736b0050310052c202801400536b00501300511202801300b007", + "0x4d00711302804e00536b00504e00509202809200536b00509200504f028", + "0x3000536b00504e00503102802836b00502800702802852302836b007014", + "0x507102801800536b00501700535e02801704f00736b00504f005071028", + "0x36b00503000509202836800536b00536900535e02836900a00736b00500a", + "0x2801f36636703152401c01b00736b00736801800703000a2c9028030005", + "0x536b00501b00503102801b00536b00501b00509202802836b005028007", + "0x1c0050c002836500536b00536500533202836500536b005028025028020", + "0x36b00736503109203111102802000536b00502000509202801c00536b005", + "0x536b00502000503102802836b00502800702836302d007525023364007", + "0x50c00280c000536b0050c000509202836400536b00536400504f0280c0", + "0x536b00500a00501302802300536b00502300533202801c00536b00501c", + "0x9233102804f00536b00504f00501302800b00536b00500b00533202800a", + "0x35f1aa36108400a00535f1aa36108400a36b00504f00b00a02301c0c0364", + "0x2836b00504f00501c02802836b00536300508e02802836b005028007028", + "0x36b00502000503102802836b00500a00501c02802836b00500b00508e028", + "0x36c00501b02836c00536b0050282c102835d00536b005028020028032005", + "0xc00536b00502802302803300536b00536c35d00736402836c00536b005", + "0x504f02803600536b00503c00511d02803c00536b00503300c00702d028", + "0x536b00501c0050c002803200536b00503200509202802d00536b00502d", + "0x36b00502800702803601c03202d00a00503600536b00503600511902801c", + "0x500a00501c02802836b00500b00508e02802836b00504f00501c028028", + "0x503102836700536b00536700509202802836b00503100508e02802836b", + "0x536b00501f35e00702d02835e00536b00502802302804000536b005367", + "0x509202809200536b00509200504f02835600536b00535900511d028359", + "0x536b00535600511902836600536b0053660050c002804000536b005040", + "0x2836b00504f00501c02802836b00502800702835636604009200a005356", + "0x36b00504e00503102802836b00500a00501c02802836b00500b00508e028", + "0x2c002804600536b00521c03100711802821c00536b005028030028215005", + "0x36b00521500509202809200536b00509200504f02804800536b005046005", + "0xa00504800536b00504800511902800700536b0050070050c0028215005", + "0x508e02802836b00504f00501c02802836b005028007028048007215092", + "0x3102802836b00503100508e02802836b00500a00501c02802836b00500b", + "0x23700536b00502804602804500536b00502802002804700536b0051c8005", + "0x2802302823900536b00523704500736402823700536b00523700501b028", + "0x536b00523f00511d02823f00536b00523923b00702d02823b00536b005", + "0x50c002804700536b00504700509202801000536b00501000504f028245", + "0x2824500704701000a00524500536b00524500511902800700536b005007", + "0x2800b00552600a03100736b00700700500f02800700536b00500500500a", + "0x536b00503100501302804f00536b00500a00524f02802836b005028007", + "0x36b00502800702802852700502804d02800f00536b00504f005252028092", + "0xb0050130281c800536b00501000505002801000536b005028030028028", + "0x9200736b00509200507102800f00536b0051c800525202809200536b005", + "0x4d00552801400536b00700f00500902801300536b00504e00535e02804e", + "0x36b0050300051c802803000536b00501400501002802836b005028007028", + "0x36901800736b00701702800708602801700536b00501700501b028017005", + "0x1800504f02802836b00501300523702802836b005028007028368005529", + "0x502800702836700552a01c01b00736b00709200500f02801800536b005", + "0x25202801f00536b00501b00501302836600536b00501c00524f02802836b", + "0x3002802836b00502800702802852b00502804d02802000536b005366005", + "0x536b00536700501302836400536b00536500505002836500536b005028", + "0x35e02802301f00736b00501f00507102802000536b00536400525202801f", + "0x280070280c000552c36300536b00702000500902802d00536b005023005", + "0x2836100536b0050840051c802808400536b00536300501002802836b005", + "0x3200552d35f1aa00736b00736101800708602836100536b00536100501b", + "0x536b0051aa00504f02802836b00502d00523702802836b005028007028", + "0x2802836b00502800702803300552e36c35d00736b00701f00500f0281aa", + "0x503c00504e02803c00536b00500c0051c802800c00536b00536c005010", + "0x2835e00536b00503600501402804000536b00535d00501302803600536b", + "0x1702835900536b00502803002802836b00502800702802852f00502804d", + "0x36b00535600501402804000536b00503300501302835600536b005359005", + "0x553021c00536b00735e00501802821500536b00504000535e02835e005", + "0x4500553104704800736b00721c1aa00724e02802836b005028007028046", + "0x23700512102823700536b00504735f36903111f02802836b005028007028", + "0x21500536b00521500505b02804800536b00504800504f02823900536b005", + "0x2802836b00502800702823921504803100523900536b0052390052be028", + "0x536b00504500504f02802836b00535f00508e02802836b00536900508e", + "0x2836b00504600504702802836b00502800702802853200502804d02823b", + "0x36b0051aa00504f02802836b00535f00508e02802836b00536900508e028", + "0x505b02824500536b00523f0052bc02823f00536b00502803002823b005", + "0x702824521523b03100524500536b0052450052be02821500536b005215", + "0x4f02802836b00501f00501c02802836b00536900508e02802836b005028", + "0x4702802836b00502800702802853300502804d02824900536b005032005", + "0x2802836b00501f00501c02802836b00536900508e02802836b0050c0005", + "0x36b00524c0052bc02824c00536b00502803002824900536b00501800504f", + "0x3100524d00536b00524d0052be02802d00536b00502d00505b02824d005", + "0x36800504f02802836b00509200501c02802836b00502800702824d02d249", + "0x4d00504702802836b00502800702802853400502804d02824e00536b005", + "0x3002824e00536b00502800504f02802836b00509200501c02802836b005", + "0x536b00501300505b02825200536b00524f0052bc02824f00536b005028", + "0x536b00502824902825201324e03100525200536b0052520052be028013", + "0x36b00502824902800f00536b00502824902804f00536b00502824902800a", + "0x502824902804d00536b00502805d02801300536b0050282490281c8005", + "0x500700500a02802836b00502836902802836b00502824c02801700536b", + "0x36b00502800702801b00553536836900736b00701800500f02801800536b", + "0x724d02800b00536b00536800501002801c00536b005005005031028028", + "0x36b00536900501302836700536b00500b0051c802800b00536b00500b04f", + "0x53601f36600736b00736900500f02801c00536b00501c005092028369005", + "0x1f00501002836500536b00501c00503102802836b005028007028020005", + "0x2d00536b00502300504e02802300536b0053640051c802836400536b005", + "0x2d0050140280c000536b00536600501302836300536b005365005092028", + "0x1c00503102802836b00502800702802853700502804d02808400536b005", + "0x2835f00536b0051aa0050170281aa00536b00502803002836100536b005", + "0x535f0050140280c000536b00502000501302836300536b005361005092", + "0x35d00536b00503200535e0280320c000736b0050c000507102808400536b", + "0x2800702836c00553809200536b00708400501802802836b00502800b028", + "0x9200536b00509200f00724d02803300536b00536300503102802836b005", + "0x553903c00c00736b00709202800724e02803300536b005033005092028", + "0x36b00503300503102802836b00535d00523702802836b005028007028036", + "0xf02804000536b00504000509202800c00536b00500c00504f028040005", + "0x4000503102802836b00502800702835600553a35935e00736b0070c0005", + "0x4600536b00521500509202821c00536b00535900524f02821500536b005", + "0x502804d02804700536b00521c00525202804800536b00535e005013028", + "0x502803002804500536b00504000503102802836b00502800702802853b", + "0x2804600536b00504500509202823900536b00523700505002823700536b", + "0x504800535e02804700536b00523900525202804800536b005356005013", + "0x2836b00502800702824500553c23f00536b00704700500902823b00536b", + "0xa00724d02803100536b00523f00501002824900536b005046005031028", + "0x536b00524900509202824c00536b0050310051c802803100536b005031", + "0x502800702805025224f03153d24e24d00736b00724c00c0070ac028249", + "0x5b02824d00536b00524d00504f02800900536b00524900503102802836b", + "0x900509202805805b00736b00523b24d0072bb02823b00536b00523b005", + "0x36b00502800702805c00553e05900536b0070580052ba02800900536b005", + "0x9202825e25d00736b00505900512402825c00536b005009005031028028", + "0x2800702805e00553f01400536b00725e00512602825c00536b00525c005", + "0x2805f00536b00525d00500a02806000536b00525c00503102802836b005", + "0x5f00500f02806000536b00506000509202801400536b00501404d007069", + "0x36b00506000503102802836b00502800702829800554029605d00736b007", + "0x9202805d00536b00505d00501302804e00536b005296005010028042005", + "0x705d00500f02804e00536b00504e01300724d02804200536b005042005", + "0x536b00504200503102802836b0050280070280690055412bd06700736b", + "0x509202806700536b00506700501302801000536b0052bd005010028068", + "0x36b00706700500f02801000536b0050101c800724d02806800536b005068", + "0x32500536b00506800503102802836b00502800702807100554206f006007", + "0x100051c802807400536b00504e0051c802803000536b00506f005010028", + "0x536b0050300051c802803000536b00503001700724d02807500536b005", + "0x500f02832500536b00532500509202800600536b005006005013028077", + "0x532500503102802836b00502800702804300554334b34c00736b007006", + "0x2807f00536b00507a00509202807900536b00534b00524f02807a00536b", + "0x54400502804d02808100536b00507900525202834800536b00534c005013", + "0x36b00502803002807d00536b00532500503102802836b005028007028028", + "0x1302807f00536b00507d00509202834500536b005346005050028346005", + "0x36b00708100500902808100536b00534500525202834800536b005043005", + "0x2834200536b00507f00503102802836b005028007028343005545344005", + "0x36b00534800535e02833d00536b00502812502834100536b005344005010", + "0x9202805b00536b00505b00504f02833c00536b0053410051c802808c005", + "0x36b00533d00512302808c00536b00508c00505b02834200536b005342005", + "0x36b00533c33d08c34205b00b2b902833c00536b00533c00501b02833d005", + "0x36b00502800702808800554633900536b00733a0052b702833a08a33b031", + "0xb02833633700736b00533900512c02833800536b00508a005031028028", + "0x8600536b00733600512b02833800536b00533800509202802836b005028", + "0x52b602837700536b00533800503102802836b00502800702808e005547", + "0x536b00533200513002802836b00533300513102833233300736b005086", + "0x509202832f00536b00533700500a02833000536b0053310052b5028331", + "0x536b0053300052b302832d00536b00532f00501302832e00536b005377", + "0x536b00533800503102802836b00502800702802854800502804d02832c", + "0x509202832a00536b00533700500a02832b00536b00508e0052b202808b", + "0x536b00532b0052b302832d00536b00532a00501302832e00536b00508b", + "0x3102802836b00502800702832600554932900536b00732c00513602832c", + "0x36b00732d00500f02808500536b00508500509202808500536b00532e005", + "0x9800536b00508500503102802836b00502800702832400554a095093007", + "0x9300501302809600536b00509800509202832300536b00509500524f028", + "0x702802854b00502804d02832100536b00532300525202832200536b005", + "0x2831e00536b00502803002831f00536b00508500503102802836b005028", + "0x532400501302809600536b00531f00509202831d00536b00531e005050", + "0x2831c00536b00532200535e02832100536b00531d00525202832200536b", + "0x9600503102802836b00502800702831a00554c31b00536b007321005009", + "0x31700536b0053180051c802831800536b00531b00501002831900536b005", + "0x33b0070ac02831900536b00531900509202831700536b00531700501b028", + "0x503102802836b0050280070280a931131303154d31431600736b007317", + "0x536b00531c00505b02831600536b00531600504f02831000536b005319", + "0x2831000536b0053100050920280ac0b000736b00531c3160072bb02831c", + "0x31000503102802836b00502800702830d00554e30f00536b0070ac0052ba", + "0x536b0050b400509202830b0b600736b00530f0051240280b400536b005", + "0x3102802836b00502800702830900554f0b900536b00730b0051260280b4", + "0x36b00530800509202830700536b0050b600500a02830800536b0050b4005", + "0x2836b0050280070280bf00555030530600736b00730700500f028308005", + "0x30400509202830300536b00530500524f02830400536b005308005031028", + "0x39300536b00530300525202805100536b00530600501302830200536b005", + "0x39400536b00530800503102802836b00502800702802855100502804d028", + "0x53940050920280dc00536b00539500505002839500536b005028030028", + "0x2839300536b0050dc00525202805100536b0050bf00501302830200536b", + "0x3930050090280c700536b00539600535e02839605100736b005051005071", + "0x536b00530200503102802836b0050280070280c90055520c600536b007", + "0x501b02830100536b0050cf0051c80280cf00536b0050c60050100280cb", + "0x36b0073010b00071380280cb00536b0050cb00509202830100536b005301", + "0x2802836b0050c700523702802836b00502800702839800555330c397007", + "0x52fb00509202839700536b00539700504f0282fb00536b0050cb005031", + "0x36b0050280070280d50055542fa0d400736b00705100500f0282fb00536b", + "0x50920282f800536b0052fa00524f02839900536b0052fb005031028028", + "0x536b0052f80052520282f100536b0050d40050130282f700536b005399", + "0x536b0052fb00503102802836b00502800702802855500502804d0280da", + "0x2ee0050920280d200536b0052ec0050500282ec00536b0050280300282ee", + "0xda00536b0050d20052520282f100536b0050d50050130282f700536b005", + "0x282f60055560db00536b0070da0050090282ef00536b0052f100535e028", + "0x536b0050db0050100282e900536b0052f700503102802836b005028007", + "0x50920282e700536b0052e700501b0282e700536b0052e80051c80282e8", + "0x70280e10055572f50df00736b0072e73970071380282e900536b0052e9", + "0xdf00536b0050df00504f0282f300536b0052e900503102802836b005028", + "0x920280e32f200736b0052ef0df0072bb0282ef00536b0052ef00505b028", + "0x280070282e00055582f400536b0070e30052ba0282f300536b0052f3005", + "0x1a62dd00736b0052f40051240282de00536b0052f300503102802836b005", + "0x282da0055592db00536b0071a60051260282de00536b0052de005092028", + "0x282d700536b0052de00503102802836b00502836902802836b005028007", + "0x280ea00536b0052db2f530c0b931432907707507401424e03c367014137", + "0x2d60052b00282d600536b0050ee2dd0072b10280ee00536b0050ea005135", + "0x2d700536b0052d70050920282f200536b0052f200504f0282d400536b005", + "0x2802836b0050280070282d42d72f20310052d400536b0052d40052af028", + "0x2802836b0052f500521c02802836b00536700501f02802836b005028369", + "0x2836b00531400530f02802836b0050b900523702802836b00530c00521c", + "0x36b00507500501f02802836b00507700501f02802836b00532900513f028", + "0x524e00530f02802836b00501400523702802836b00507400501f028028", + "0x513e0282d300536b0052de00503102802836b00503c00525d02802836b", + "0x36b0052d10052b00282d100536b0052d22dd0072b10282d200536b0052da", + "0x2af0282d300536b0052d30050920282f200536b0052f200504f0282d0005", + "0x2836902802836b0050280070282d02d32f20310052d000536b0052d0005", + "0x521c02802836b00503c00525d02802836b00536700501f02802836b005", + "0x30f02802836b0050b900523702802836b00530c00521c02802836b0052f5", + "0x2802836b00507700501f02802836b00532900513f02802836b005314005", + "0x2836b00501400523702802836b00507400501f02802836b00507500501f", + "0x52e00052ad0282cf00536b0052f300503102802836b00524e00530f028", + "0x282cf00536b0052cf0050920282f200536b0052f200504f0282cc00536b", + "0x30f02802836b0050280070282cc2cf2f20310052cc00536b0052cc0052af", + "0x2802836b00503c00525d02802836b00536700501f02802836b00524e005", + "0x2836b00531400530f02802836b0050b900523702802836b00530c00521c", + "0x36b00507500501f02802836b00507700501f02802836b00532900513f028", + "0x52e900503102802836b00501400523702802836b00507400501f028028", + "0x282cb00536b0050f60050920280f800536b0050e100504f0280f600536b", + "0x30f02802836b0052f600504702802836b00502800702802855a00502804d", + "0x2802836b00503c00525d02802836b00536700501f02802836b00524e005", + "0x2836b00531400530f02802836b0050b900523702802836b00530c00521c", + "0x36b00507500501f02802836b00507700501f02802836b00532900513f028", + "0x52f700503102802836b00501400523702802836b00507400501f028028", + "0x282cb00536b0052ca0050920280f800536b00539700504f0282ca00536b", + "0xfa00536b0052c900513e0282c900536b00502803002802836b005028369", + "0x52af0280fb00536b0050fc0052b00280fc00536b0050fa2ef0072b1028", + "0x24e00530f02802836b0050280070280fb2cb0f80310050fb00536b0050fb", + "0x501c02802836b00503c00525d02802836b00536700501f02802836b005", + "0x30f02802836b0050b900523702802836b00501400523702802836b005051", + "0x2802836b00507700501f02802836b00532900513f02802836b005314005", + "0x536b0050cb00503102802836b00507400501f02802836b00507500501f", + "0x2804d0282c700536b0050f90050920282c800536b00539800504f0280f9", + "0x24e00530f02802836b0050c900504702802836b00502800702802855b005", + "0x501c02802836b00503c00525d02802836b00536700501f02802836b005", + "0x30f02802836b0050b900523702802836b00501400523702802836b005051", + "0x2802836b00507700501f02802836b00532900513f02802836b005314005", + "0x536b00530200503102802836b00507400501f02802836b00507500501f", + "0x283690282c700536b0051020050920282c800536b0050b000504f028102", + "0x2b102810300536b00510400513e02810400536b00502803002802836b005", + "0x52c60052af0282c600536b0051010052b002810100536b0051030c7007", + "0x2836b00502836902802836b0050280070282c62c72c80310052c600536b", + "0x36b00503c00525d02802836b00536700501f02802836b00524e00530f028", + "0x532900513f02802836b00531400530f02802836b005014005237028028", + "0x7400501f02802836b00507500501f02802836b00507700501f02802836b", + "0x2810a00536b00530900513e0282c500536b0050b400503102802836b005", + "0xb000504f02810900536b00510b0052b002810b00536b00510a0b60072b1", + "0x10900536b0051090052af0282c500536b0052c50050920280b000536b005", + "0x530f02802836b00502836902802836b0050280070281092c50b0031005", + "0x1f02802836b00503c00525d02802836b00536700501f02802836b00524e", + "0x2802836b00531400530f02802836b00501400523702802836b005074005", + "0x2836b00507500501f02802836b00507700501f02802836b00532900513f", + "0xb000504f0282c300536b00530d0052ad02810c00536b005310005031028", + "0x2c300536b0052c30052af02810c00536b00510c0050920280b000536b005", + "0x30f02802836b00531100530f02802836b0050280070282c310c0b0031005", + "0x2802836b00536700501f02802836b00524e00530f02802836b0050a9005", + "0x2836b00507400501f02802836b00507500501f02802836b00503c00525d", + "0x36b00507700501f02802836b00532900513f02802836b005014005237028", + "0x509202811200536b00531300504f0282c200536b005319005031028028", + "0x504702802836b00502800702802855c00502804d02811300536b0052c2", + "0x25d02802836b00536700501f02802836b00524e00530f02802836b00531a", + "0x2802836b00507400501f02802836b00507500501f02802836b00503c005", + "0x2836b00507700501f02802836b00532900513f02802836b005014005237", + "0x2500509202811200536b00533b00504f02802500536b005096005031028", + "0x513e02811100536b00502803002802836b00502836902811300536b005", + "0x36b00511d0052b002811d00536b0052c131c0072b10282c100536b005111", + "0x36b00502800702811911311203100511900536b0051190052af028119005", + "0x36b00536700501f02802836b00524e00530f02802836b005028369028028", + "0x507400501f02802836b00507500501f02802836b00503c00525d028028", + "0x32e00503102802836b00507700501f02802836b00501400523702802836b", + "0x11f00536b0051180050920282c000536b00533b00504f02811800536b005", + "0x502804d0282be00536b00532d00501302812100536b0053260052ac028", + "0x536700501f02802836b00524e00530f02802836b00502800702802855d", + "0x7400501f02802836b00507500501f02802836b00503c00525d02802836b", + "0x503102802836b00507700501f02802836b00501400523702802836b005", + "0x536b00533b00504f0282bb00536b0050880052ad0282bc00536b00508a", + "0x33b0310052bb00536b0052bb0052af0282bc00536b0052bc00509202833b", + "0x36b00534300504702802836b00502836902802836b0050280070282bb2bc", + "0x503c00525d02802836b00536700501f02802836b00524e00530f028028", + "0x1400523702802836b00507400501f02802836b00507500501f02802836b", + "0x300282ba00536b00507f00503102802836b00507700501f02802836b005", + "0x536b0052ba0050920282c000536b00505b00504f02812400536b005028", + "0x535e0282be00536b00534800501302812100536b0051240052ac02811f", + "0x36b0051251260072b102812500536b00512100513e02812600536b0052be", + "0x920282c000536b0052c000504f0282b900536b0051230052b0028123005", + "0x282b911f2c00310052b900536b0052b90052af02811f00536b00511f005", + "0x1f02802836b00524e00530f02802836b00502836902802836b005028007", + "0x2802836b00504e00501f02802836b00503c00525d02802836b005367005", + "0x2836b00501700506002802836b00501400523702802836b00501000501f", + "0x507100535e02812c00536b0050280300282b700536b005068005031028", + "0x13100536b0052b612b0072b10282b600536b00512c00513e02812b00536b", + "0x2b700509202805b00536b00505b00504f02813000536b0051310052b0028", + "0x280070281302b705b03100513000536b0051300052af0282b700536b005", + "0x36700501f02802836b00524e00530f02802836b00502836902802836b005", + "0x523702802836b00504e00501f02802836b00503c00525d02802836b005", + "0x3102802836b00501700506002802836b0051c800506002802836b005014", + "0x536b00506900535e0282b300536b0050280300282b500536b005042005", + "0x2b002813800536b0051362b20072b102813600536b0052b300513e0282b2", + "0x36b0052b500509202805b00536b00505b00504f02813700536b005138005", + "0x36b0050280070281372b505b03100513700536b0051370052af0282b5005", + "0x36b00536700501f02802836b00524e00530f02802836b005028369028028", + "0x501400523702802836b00501300506002802836b00503c00525d028028", + "0x6000503102802836b00501700506002802836b0051c800506002802836b", + "0x282b000536b00529800535e0282b100536b00502803002813500536b005", + "0x13f0052b002813f00536b0052af2b00072b10282af00536b0052b100513e", + "0x13500536b00513500509202805b00536b00505b00504f02813e00536b005", + "0x2802836b00502800702813e13505b03100513e00536b00513e0052af028", + "0x2802836b00536700501f02802836b00524e00530f02802836b005028369", + "0x2836b0051c800506002802836b00501300506002802836b00503c00525d", + "0x36b00525c00503102802836b00504d00506702802836b005017005060028", + "0x282ab00536b0052ac25d0072b10282ac00536b00505e00513e0282ad005", + "0x52ad00509202805b00536b00505b00504f02814f00536b0052ab0052b0", + "0x502800702814f2ad05b03100514f00536b00514f0052af0282ad00536b", + "0x536700501f02802836b00524e00530f02802836b00502836902802836b", + "0x1300506002802836b00504d00506702802836b00503c00525d02802836b", + "0x503102802836b00501700506002802836b0051c800506002802836b005", + "0x536b00505b00504f02814800536b00505c0052ad02814600536b005009", + "0x5b03100514800536b0051480052af02814600536b00514600509202805b", + "0x505000530f02802836b00525200530f02802836b005028007028148146", + "0x4d00506702802836b00503c00525d02802836b00536700501f02802836b", + "0x506002802836b0051c800506002802836b00501300506002802836b005", + "0x14b00536b00524f00504f02814a00536b00524900503102802836b005017", + "0x2836b00502800702802855e00502804d02814d00536b00514a005092028", + "0x36b00503c00525d02802836b00536700501f02802836b005245005047028", + "0x51c800506002802836b00501300506002802836b00504d005067028028", + "0x4600503102802836b00500a00506002802836b00501700506002802836b", + "0x14d00536b0052a800509202814b00536b00500c00504f0282a800536b005", + "0x536b0052a600513e0282a600536b00502803002802836b005028369028", + "0x2af02815600536b0051570052b002815700536b0052aa23b0072b10282aa", + "0x506002802836b00502800702815614d14b03100515600536b005156005", + "0x6002802836b00504d00506702802836b00536700501f02802836b00500a", + "0x2802836b0051c800506002802836b0050c000501c02802836b005013005", + "0x36b00503600504f02815500536b00503300503102802836b005017005060", + "0x502800702802855f00502804d02815300536b005155005092028154005", + "0x36700501f02802836b00500a00506002802836b00536c00504702802836b", + "0x501c02802836b00501300506002802836b00504d00506702802836b005", + "0x6002802836b00501700506002802836b0051c800506002802836b0050c0", + "0x536b00502800504f02815200536b00536300503102802836b00500f005", + "0x36b00502803002802836b00502836902815300536b005152005092028154", + "0x2816100536b00515035d0072b102815000536b00515100513e028151005", + "0x2a41531540310052a400536b0052a40052af0282a400536b0051610052b0", + "0x2836b00504d00506702802836b00500a00506002802836b005028007028", + "0x36b0051c800506002802836b00504f00506002802836b005013005060028", + "0x500500503102802836b00500f00506002802836b005017005060028028", + "0x13e0282a100536b00501b00535e0282a200536b0050280300282a300536b", + "0x529f0052b002829f00536b0052a02a10072b10282a000536b0052a2005", + "0x282a300536b0052a300509202802800536b00502800504f02829e00536b", + "0x281c800536b0050282ab02829e2a302803100529e00536b00529e0052af", + "0x1700536b0050282ab02804d00536b00502824902801300536b00502805f", + "0x2802836b00502836902802836b00502824c02836900536b00502814f028", + "0x1c03156001b04e36803136b00700700500714602802836b005031005321", + "0x36800503102836800536b00536800509202802836b005028007028366367", + "0x2000536b00501b00514a02801b00536b00501b00514802801f00536b005", + "0x36500536b00536500514d02801403001036436500b36b00502000514b028", + "0x509602836302d00736b0050230052a602802300536b0053650052a8028", + "0x2836b0050c00050960280840c000736b00500a0052a602802836b00502d", + "0x515702836136300736b0053630052aa02836300536b00536300531f028", + "0x36b00503200525d02802836b00535f00508e02803235f1aa03136b005361", + "0x15702836c08400736b0050840052aa02835d00536b0051aa005112028028", + "0x503c00525d02802836b00500c00508e02803c00c03303136b00536c005", + "0x2804e00536b00504e0130072bd02803600536b00503300511202802836b", + "0x101c800715502836400536b00536400515602801f00536b00501f005092", + "0x36b00501404d00724d02803000536b00503001700715502801000536b005", + "0x9602802836b00502800702802856102836b00703635d007113028014005", + "0x2802836b00500f00501f02802836b00501400501f02802836b005084005", + "0x2836b00536400515402802836b00509200501f02802836b00503000525d", + "0x36b00504f00501f02802836b00501000525d02802836b00500b005323028", + "0x501f00503102802836b00536300509602802836b005369005153028028", + "0x2800702802856200502804d02835e00536b00504000509202804000536b", + "0x35636300736b0053630052aa02835900536b00501f00503102802836b005", + "0x525d02802836b00521500508e02804621c21503136b005356005157028", + "0x8400736b0050840052aa02804800536b00521c00511202802836b005046", + "0x25d02802836b00504500508e02823923704503136b005047005157028047", + "0x536b00535900509202823b00536b00523700511202802836b005239005", + "0x501f02802836b00502800702802856302836b00723b048007113028359", + "0x1f02802836b00503000525d02802836b00500f00501f02802836b005014", + "0x2802836b00500b00532302802836b00536400515402802836b005092005", + "0x2836b00536900515302802836b00504f00501f02802836b00501000525d", + "0x36b00535900503102802836b00508400509602802836b005363005096028", + "0x4d02824500536b00535e00539802835e00536b00523f00509202823f005", + "0x15702824900536b00535900503102802836b005028007028028564005028", + "0x524d00508e02802836b00524c00508e02824e24d24c03136b005363005", + "0x15702825200536b00524f0050c702824f00536b00524e00515202802836b", + "0x500900508e02802836b00505000508e02805b00905003136b005084005", + "0x32c02805900536b0050580050c702805800536b00505b00515202802836b", + "0x524900509202805c00536b00505c00501b02805c00536b005059252007", + "0x2802836b00502800702825c00556502836b00705c00534802824900536b", + "0x1836900715002801800536b00536400515102825d00536b005249005031", + "0x2836b00525e00532302805e25e00736b00501800516102801800536b005", + "0x5e0052a402802836b00506000532302805f06000736b00500b005161028", + "0x60680692bd06704229829601436b00505d0052a302805d05e00736b005", + "0x2802836b00504200530f02802836b00529800525d02807507432507106f", + "0x2836b00506900501f02802836b0052bd00501f02802836b005067005237", + "0x36b00506f00530f02802836b00500600513f02802836b00506800501f028", + "0x507400521c02802836b00532500521c02802836b005071005237028028", + "0x52a402807700536b0052960051c802802836b00507500523702802836b", + "0x8134807f07907a04334b01436b00534c0052a302834c05f00736b00505f", + "0x2836b00507a00530f02802836b00504300525d02834234334434534607d", + "0x36b00534800501f02802836b00507f00501f02802836b005079005237028", + "0x534600530f02802836b00507d00513f02802836b00508100501f028028", + "0x34300521c02802836b00534400521c02802836b00534500523702802836b", + "0x32c02834100536b00534b0051c802802836b00534200523702802836b005", + "0x525d00509202833d00536b00533d00501b02833d00536b005341077007", + "0x2802836b00502800702808c00556602836b00733d00534802825d00536b", + "0x33b0052a302833b05e00736b00505e0052a402833c00536b00525d005031", + "0x8a00501f02833133233337708e08633633733808833933a08a01436b005", + "0x501f02802836b00508800523702802836b00533900530f02802836b005", + "0x13f02802836b00533600501f02802836b00533700501f02802836b005338", + "0x2802836b00537700523702802836b00508e00530f02802836b005086005", + "0x2836b00533100523702802836b00533200521c02802836b00533300521c", + "0x5f0052a402832f00536b0053300050c702833000536b00533a005152028", + "0x8532632932a32b08b32c32d01436b00532e0052a302832e05f00736b005", + "0x2802836b00508b00530f02802836b00532d00501f028323098324095093", + "0x2836b00532900501f02802836b00532a00501f02802836b00532b005237", + "0x36b00509300530f02802836b00508500513f02802836b00532600501f028", + "0x509800521c02802836b00532400521c02802836b005095005237028028", + "0x50c702809600536b00532c00515202802836b00532300523702802836b", + "0x36b00532100501b02832100536b00532232f00732c02832200536b005096", + "0x31f00556702836b00732100534802833c00536b00533c005092028321005", + "0x36b00505e0052a402831e00536b00533c00503102802836b005028007028", + "0x31131331431631731831931a31b31c01436b00531d0052a302831d05e007", + "0x523702802836b00531b00525d02802836b00531c00501f0280b03100a9", + "0x1f02802836b00531700501f02802836b00531800501f02802836b005319", + "0x2802836b00531300530f02802836b00531400513f02802836b005316005", + "0x2836b00531000521c02802836b0050a900521c02802836b005311005237", + "0x505f0052a40280ac00536b00531a0052f702802836b0050b0005237028", + "0x3063073083090b930b0b60b430d01436b00530f0052a302830f05f00736b", + "0x23702802836b0050b400525d02802836b00530d00501f0283033040bf305", + "0x2802836b00530900501f02802836b0050b900501f02802836b00530b005", + "0x2836b00530600530f02802836b00530700513f02802836b00530800501f", + "0x36b00530400521c02802836b0050bf00521c02802836b005305005237028", + "0x31e00509202830200536b0050b60052f702802836b005303005237028028", + "0x2836b00502800702802856802836b0073020ac0072a202831e00536b005", + "0x36b00509200501f02802836b00503000525d02802836b00500f00501f028", + "0x501000525d02802836b00505e00532302802836b00505f005323028028", + "0x31e00503102802836b00501400501f02802836b00504f00501f02802836b", + "0x702802856900502804d02839300536b00505100509202805100536b005", + "0x5e00736b00505e0052a402839400536b00531e00503102802836b005028", + "0x2fb39830c3973010cf0cb0c90c60c73960dc01436b0053950052a3028395", + "0x50c700530f02802836b00539600525d02802836b0050dc00501f0280d4", + "0xcf00501f02802836b0050cb00501f02802836b0050c900501f02802836b", + "0x523702802836b00539700530f02802836b00530100513f02802836b005", + "0x23702802836b0052fb00521c02802836b00539800521c02802836b00530c", + "0x736b0052fa0052ca0282fa00536b0050c60052a102802836b0050d4005", + "0x2a40282f800536b00539900532502839900536b0050d500500a0280d52fa", + "0x2ef0d22ec2ee0da2f101436b0052f70052a30282f705f00736b00505f005", + "0x36b0050da00525d02802836b0052f100501f0282f50df2e72e82e92f60db", + "0x52ef00501f02802836b0050d200501f02802836b0052ee00530f028028", + "0x2e900530f02802836b0052f600513f02802836b0050db00501f02802836b", + "0x521c02802836b0052e700521c02802836b0052e800523702802836b005", + "0x280e100536b0052ec0052a102802836b0052f500523702802836b0050df", + "0x2f20053250282f200536b0052f300500a0282f30e100736b0050e10052ca", + "0xe300536b0050e30050330282f800536b0052f80050330280e300536b005", + "0x702802856a02836b0070e32f80072a002839400536b005394005092028", + "0x32302802836b00509200501f02802836b00503000525d02802836b005028", + "0x2802836b00501000525d02802836b00505e00532302802836b00505f005", + "0x2836b00500f00501f02802836b00501400501f02802836b00504f00501f", + "0x36b00539400503102802836b0052fa00523702802836b0050e1005237028", + "0x4d0282de00536b0052f40050920282e000536b00502800504f0282f4005", + "0x4f0282dd00536b00539400503102802836b00502800702802856b005028", + "0x36b0052fa00505b0282dd00536b0052dd00509202802800536b005028005", + "0x3136b0050e12fa2dd02800a29f0280e100536b0050e100505b0282fa005", + "0x2836b0050280070280ea00556c2d700536b0072da00529e0282da2db1a6", + "0x2370282d32d42d603136b0052d700529d0280ee00536b0052db005031028", + "0xee00536b0050ee00509202802836b0052d400523702802836b0052d6005", + "0x504702802836b0050280070282d100556d2d200536b0072d30050fc028", + "0x25d02802836b00505e00532302802836b00505f00532302802836b0052d2", + "0x2802836b00501400501f02802836b00504f00501f02802836b005010005", + "0x2836b00509200501f02802836b00503000525d02802836b00500f00501f", + "0x2d00050920282e000536b0051a600504f0282d000536b0050ee005031028", + "0x2cc00536b0052de0053980282cf00536b0052e000530c0282de00536b005", + "0x2802836b0052d100504702802836b00502800702802856e00502804d028", + "0xf80052a30280f805e00736b00505e0052a40280f600536b0050ee005031", + "0x2cb00501f0281011031041022c72c80f90fb0fc0fa2c92ca2cb01436b005", + "0x523702802836b0052c900530f02802836b0052ca00525d02802836b005", + "0x13f02802836b0050f900501f02802836b0050fb00501f02802836b0050fa", + "0x2802836b00510200523702802836b0052c700530f02802836b0052c8005", + "0x2836b00510100523702802836b00510300521c02802836b00510400521c", + "0x52a30282c505f00736b00505f0052a40282c600536b0050fc0051c8028", + "0x501f02811911d2c11110251131122c22c310c10910b10a01436b0052c5", + "0x23702802836b00510900530f02802836b00510b00525d02802836b00510a", + "0x2802836b00511200501f02802836b0052c200501f02802836b00510c005", + "0x2836b00511100523702802836b00502500530f02802836b00511300513f", + "0x36b00511900523702802836b00511d00521c02802836b0052c100521c028", + "0x1b0282c000536b0051182c600732c02811800536b0052c30051c8028028", + "0x36b0072c00053480280f600536b0050f60050920282c000536b0052c0005", + "0x2a402812100536b0050f600503102802836b00502800702811f00556f028", + "0x1251261242ba2bb2bc01436b0052be0052a30282be05e00736b00505e005", + "0x36b0052bb00525d02802836b0052bc00501f0281312b612b12c2b72b9123", + "0x512600501f02802836b00512400523702802836b0052ba00530f028028", + "0x2b700530f02802836b0052b900513f02802836b00512300501f02802836b", + "0x521c02802836b00512b00521c02802836b00512c00523702802836b005", + "0x2813000536b0051250051c802802836b00513100523702802836b0052b6", + "0x1371381362b22b301436b0052b50052a30282b505f00736b00505f0052a4", + "0x52b200525d02802836b0052b300501f0282ac2ad13e13f2af2b02b1135", + "0x13700501f02802836b00513800523702802836b00513600530f02802836b", + "0x530f02802836b0052b000513f02802836b0052b100501f02802836b005", + "0x21c02802836b00513e00521c02802836b00513f00523702802836b0052af", + "0x2ab00536b0051350051c802802836b0052ac00523702802836b0052ad005", + "0x509202814f00536b00514f00501b02814f00536b0052ab13000732c028", + "0x36b00502800702814600557002836b00714f00534802812100536b005121", + "0x2a302814a05e00736b00505e0052a402814800536b005121005031028028", + "0x1f0281501511521531541551561572aa2a62a814d14b01436b00514a005", + "0x2802836b0052a800530f02802836b00514d00525d02802836b00514b005", + "0x2836b00515700501f02802836b0052aa00501f02802836b0052a6005237", + "0x36b00515300523702802836b00515400530f02802836b00515500513f028", + "0x515000523702802836b00515100521c02802836b00515200521c028028", + "0x282a405f00736b00505f0052a402816100536b0051560051c802802836b", + "0x2829916e29a16c16a29c29d29e29f2a02a12a22a301436b0052a40052a3", + "0x2836b0052a100530f02802836b0052a200525d02802836b0052a300501f", + "0x36b00529e00501f02802836b00529f00501f02802836b0052a0005237028", + "0x516c00523702802836b00516a00530f02802836b00529c00513f028028", + "0x29900523702802836b00516e00521c02802836b00529a00521c02802836b", + "0x17100536b00516f16100732c02816f00536b00529d0051c802802836b005", + "0x17100534802814800536b00514800509202817100536b00517100501b028", + "0x17400536b00514800503102802836b00502800702817200557102836b007", + "0x29229329414301436b0052970052a302829705e00736b00505e0052a4028", + "0x29400525d02802836b00514300501f02828728828928a29517902428e572", + "0x501f02802836b00529200523702802836b00529300530f02802836b005", + "0x30f02802836b00502400501f02802836b00528e00501f02802836b005572", + "0x2802836b00528900521c02802836b00528a00523702802836b005295005", + "0x536b00517900529c02802836b00528700523702802836b00528800521c", + "0x29a02818100536b00517f00516c02817f28600736b00528600516a028286", + "0x51840052a302818405f00736b00505f0052a402818200536b005181005", + "0x528500501f02828b28118a28019219118f19028418918718628501436b", + "0x18900523702802836b00518700530f02802836b00518600525d02802836b", + "0x501f02802836b00519000501f02802836b00528400501f02802836b005", + "0x21c02802836b00528000523702802836b00519200530f02802836b00518f", + "0x2802836b00528b00523702802836b00528100521c02802836b00518a005", + "0x19700516c02819727d00736b00527d00516a02827d00536b00519100529c", + "0x18200536b00518200503302827c00536b00519900529a02819900536b005", + "0x1820072a002817400536b00517400509202827c00536b00527c005033028", + "0x2802836b00505e00532302802836b00502800702802857302836b00727c", + "0x2836b00501400501f02802836b00504f00501f02802836b00501000525d", + "0x36b00509200501f02802836b00503000525d02802836b00500f00501f028", + "0x528600513f02802836b00527d00513f02802836b00505f005323028028", + "0x9202819d00536b0051a600504f02819b00536b00517400503102802836b", + "0x3102802836b00502800702802857400502804d02827b00536b00519b005", + "0x36b00527a0050920281a600536b0051a600504f02827a00536b005174005", + "0x29902827d00536b00527d00516e02828600536b00528600516e02827a005", + "0x57527400536b00727500516f02827527627803136b00527d28627a1a600a", + "0x27400517102827100536b00527600503102802836b005028007028273005", + "0x2836b00526f00513f02802836b00527000513f02826a26f27003136b005", + "0x2826b00557626d00536b00726a0050fc02827100536b005271005092028", + "0x2802836b00504f00501f02802836b00526d00504702802836b005028007", + "0x2836b00503000525d02802836b00500f00501f02802836b00501400501f", + "0x36b00505e00532302802836b00505f00532302802836b00509200501f028", + "0x27800504f02826700536b00527100503102802836b00501000525d028028", + "0x26600536b00519d00530c02827b00536b00526700509202819d00536b005", + "0x2836b00502800702802857700502804d02826300536b00527b005398028", + "0x505e0052a402826000536b00527100503102802836b00526b005047028", + "0x1b22542562571ae25825925a25b01436b00525f0052a302825f05e00736b", + "0x30f02802836b00525a00525d02802836b00525b00501f0282502512531b4", + "0x2802836b0051ae00501f02802836b00525800523702802836b005259005", + "0x2836b00525400513f02802836b00525600501f02802836b00525700501f", + "0x36b00525100521c02802836b00525300521c02802836b0051b4005237028", + "0x5f0052a402824a00536b0051b20052f702802836b005250005237028028", + "0x18b23a1c11bf23c1bd24224401436b0052460052a302824605f00736b005", + "0x2802836b00524200525d02802836b00524400501f0282311c623523d238", + "0x2836b0051bf00501f02802836b00523c00523702802836b0051bd00530f", + "0x36b00518b00513f02802836b00523a00501f02802836b0051c100501f028", + "0x51c600521c02802836b00523500521c02802836b00523d005237028028", + "0x509202823000536b0052380052f702802836b00523100523702802836b", + "0x36b00502800702802857802836b00723024a0072a202826000536b005260", + "0x503000525d02802836b00500f00501f02802836b00501400501f028028", + "0x5e00532302802836b00505f00532302802836b00509200501f02802836b", + "0x503102802836b00504f00501f02802836b00501000525d02802836b005", + "0x536b00522e00509202822d00536b00527800504f02822e00536b005260", + "0x536b00526000503102802836b00502800702802857900502804d0281cb", + "0x22122222701436b0052260052a302822605e00736b00505e0052a4028229", + "0x525d02802836b00522700501f0281d81d621821a1d321b22321d1d1220", + "0x1f02802836b00522000523702802836b00522100530f02802836b005222", + "0x2802836b00522300501f02802836b00521d00501f02802836b0051d1005", + "0x2836b00521800521c02802836b0051d300530f02802836b00521b00513f", + "0x36b00521a0052a102802836b0051d800523702802836b0051d600521c028", + "0x2821300536b0051da00500a0281da21600736b0052160052ca028216005", + "0x20e0052a302820e05f00736b00505f0052a402821900536b005213005325", + "0x20d00501f0281f31fa1fd1ff2012031e120820920a20b20c20d01436b005", + "0x523702802836b00520b00530f02802836b00520c00525d02802836b005", + "0x1f02802836b00520800501f02802836b00520900501f02802836b00520a", + "0x2802836b00520100530f02802836b00520300513f02802836b0051e1005", + "0x2836b0051f300523702802836b0051fa00521c02802836b0051fd00521c", + "0x500a0280001ee00736b0051ee0052ca0281ee00536b0051ff0052a1028", + "0x536b00521900503302857b00536b00557a00532502857a00536b005000", + "0x72a002822900536b00522900509202857b00536b00557b005033028219", + "0x2836b00500f00501f02802836b00502800702802857c02836b00757b219", + "0x36b00505f00532302802836b00509200501f02802836b00503000525d028", + "0x504f00501f02802836b00501000525d02802836b00505e005323028028", + "0x21600523702802836b0051ee00523702802836b00501400501f02802836b", + "0x2857e00536b00527800504f02857d00536b00522900503102802836b005", + "0x2802836b00502800702802858000502804d02857f00536b00557d005092", + "0x558100509202827800536b00527800504f02858100536b005229005031", + "0x281ee00536b0051ee00505b02821600536b00521600505b02858100536b", + "0x58500536b00758400529e02858458358203136b0051ee21658127800a29f", + "0x529d02837500536b00558300503102802836b005028007028587005586", + "0x36b00558900523702802836b00558800523702858a58958803136b005585", + "0x58d00558c58b00536b00758a0050fc02837500536b005375005092028028", + "0x2836b00509200501f02802836b00558b00504702802836b005028007028", + "0x36b00501000525d02802836b00505e00532302802836b00505f005323028", + "0x500f00501f02802836b00501400501f02802836b00504f00501f028028", + "0x504f02858e00536b00537500503102802836b00503000525d02802836b", + "0x536b00557e00530c02857f00536b00558e00509202857e00536b005582", + "0x36b00502800702802859100502804d02859000536b00557f00539802858f", + "0x5e0052a402859200536b00537500503102802836b00558d005047028028", + "0x59a59959859759659559437401436b0055930052a302859305e00736b005", + "0x2802836b00559400525d02802836b00537400501f02859f59e59d59c59b", + "0x2836b00559700501f02802836b00559600523702802836b00559500530f", + "0x36b00559a00513f02802836b00559900501f02802836b00559800501f028", + "0x559e00521c02802836b00559c00523702802836b00559b00530f028028", + "0x52a40285a000536b00559d00517202802836b00559f00523702802836b", + "0x5a75a65a55a43735a35a201436b0055a10052a30285a105f00736b00505f", + "0x2836b0055a300525d02802836b0055a200501f0285ac3725ab5aa5a95a8", + "0x36b0055a500501f02802836b0055a400523702802836b00537300530f028", + "0x55a800513f02802836b0055a700501f02802836b0055a600501f028028", + "0x37200521c02802836b0055aa00523702802836b0055a900530f02802836b", + "0x920285ad00536b0055ab00517202802836b0055ac00523702802836b005", + "0x50280070280285ae02836b0075ad5a00072a002859200536b005592005", + "0x1000525d02802836b00505e00532302802836b00505f00532302802836b", + "0x501f02802836b00501400501f02802836b00504f00501f02802836b005", + "0x3102802836b00509200501f02802836b00503000525d02802836b00500f", + "0x36b0055af0050920285b000536b00558200504f0285af00536b005592005", + "0x36b00559200503102802836b0050280070280285b200502804d0285b1005", + "0x5b65b501436b0055b40052a30285b405e00736b00505e0052a40285b3005", + "0x25d02802836b0055b500501f0285bf3765be5bd5bc5bb5ba5b95b85b7371", + "0x2802836b0055b700523702802836b00537100530f02802836b0055b6005", + "0x2836b0055ba00501f02802836b0055b900501f02802836b0055b800501f", + "0x36b0055bd00523702802836b0055bc00530f02802836b0055bb00513f028", + "0x537600517202802836b0055bf00523702802836b0055be00521c028028", + "0x5c201436b0055c10052a30285c105f00736b00505f0052a40285c000536b", + "0x2802836b0055c200501f0285cd5cc5cb5ca3705c95c85c75c65c55c45c3", + "0x2836b0055c500523702802836b0055c400530f02802836b0055c300525d", + "0x36b0055c800501f02802836b0055c700501f02802836b0055c600501f028", + "0x55ca00523702802836b00537000530f02802836b0055c900513f028028", + "0x5cc00517202802836b0055cd00523702802836b0055cb00521c02802836b", + "0x2836b0075ce5c00072a00285b300536b0055b30050920285ce00536b005", + "0x501000525d02802836b00505e00532302802836b0050280070280285cf", + "0xf00501f02802836b00501400501f02802836b00504f00501f02802836b", + "0x532302802836b00509200501f02802836b00503000525d02802836b005", + "0x5d100536b00558200504f0285d000536b0055b300503102802836b00505f", + "0x2836b0050280070280285d300502804d0285d200536b0055d0005092028", + "0x5d95d85d75d65d501436b00505e0052a30285d400536b0055b3005031028", + "0x55d600525d02802836b0055d500501f0285e05df5de5dd5dc36f5db5da", + "0x5d900501f02802836b0055d800523702802836b0055d700530f02802836b", + "0x513f02802836b0055db00501f02802836b0055da00501f02802836b005", + "0x21c02802836b0055dd00523702802836b0055dc00530f02802836b00536f", + "0x5e100536b0055e00052a102802836b0055df00521c02802836b0055de005", + "0x53250285e200536b00536e00500a02836e5e100736b0055e10052ca028", + "0x5ea3785e95e85e75e65e55e401436b00505f0052a30285e300536b0055e2", + "0x2802836b0055e500525d02802836b0055e400501f0285ef5ee5ed5ec5eb", + "0x2836b0055e800501f02802836b0055e700523702802836b0055e600530f", + "0x36b0055ea00513f02802836b00537800501f02802836b0055e900501f028", + "0x55ed00521c02802836b0055ec00523702802836b0055eb00530f028028", + "0x52ca0285f000536b0055ef0052a102802836b0055ee00521c02802836b", + "0x36b0055f20053250285f200536b0055f100500a0285f15f000736b0055f0", + "0x920285f300536b0055f30050330285e300536b0055e30050330285f3005", + "0x50280070280285f402836b0075f35e30072a00285d400536b0055d4005", + "0x1400501f02802836b00504f00501f02802836b00501000525d02802836b", + "0x501f02802836b00503000525d02802836b00500f00501f02802836b005", + "0x3102802836b0055e100523702802836b0055f000523702802836b005092", + "0x36b0055f500509202836d00536b00558200504f0285f500536b0055d4005", + "0x36b0055d400503102802836b0050280070280285f700502804d0285f6005", + "0x5b0285f800536b0055f800509202858200536b00558200504f0285f8005", + "0x5e15f858200a29f0285f000536b0055f000505b0285e100536b0055e1005", + "0x70285fe0055fd5fc00536b0075fb00529e0285fb5fa5f903136b0055f0", + "0x60003136b0055fc00529d0285ff00536b0055fa00503102802836b005028", + "0x5ff00509202802836b00560100523702802836b005600005237028602601", + "0x36b00502800702860500560460300536b0076020050fc0285ff00536b005", + "0x500f00501f02802836b00501400501f02802836b005603005047028028", + "0x1000525d02802836b00509200501f02802836b00503000525d02802836b", + "0x4f02860600536b0055ff00503102802836b00504f00501f02802836b005", + "0x285f700502804d0285f600536b00560600509202836d00536b0055f9005", + "0x536b0055ff00503102802836b00560500504702802836b005028007028", + "0x1b02860900536b00504f60800732c02860800536b0050100050c7028607", + "0x36b00760900534802860700536b00560700509202860900536b005609005", + "0xc702860c00536b00560700503102802836b00502800702860b00560a028", + "0x560e00501b02860e00536b00509260d00732c02860d00536b005030005", + "0x560f02836b00760e00534802860c00536b00560c00509202860e00536b", + "0xf01400732c02861100536b00560c00503102802836b005028007028610", + "0x61100536b00561100509202861200536b00561200501b02861200536b005", + "0x61100503102802836b00502800702861400561302836b007612005348028", + "0x2861700536b00561600517402861600536b00502803002861500536b005", + "0x56150050920285f900536b0055f900504f02861800536b005617005297", + "0x561800536b00561800514302804e00536b00504e0050c002861500536b", + "0x3102802836b00561400534602802836b00502800702861804e6155f900a", + "0x61b00536b00502829402861a00536b00502802002861900536b005611005", + "0x2802302861c00536b00561b61a00736402861b00536b00561b00501b028", + "0x536b00561e00529302861e00536b00561c61d00702d02861d00536b005", + "0x50c002861900536b0056190050920285f900536b0055f900504f02861f", + "0x2861f04e6195f900a00561f00536b00561f00514302804e00536b00504e", + "0x2802836b00501400501f02802836b00561000534602802836b005028007", + "0x536b00502802002862000536b00560c00503102802836b00500f00501f", + "0x62100736402862200536b00562200501b02862200536b005028292028621", + "0x536b00562362400702d02862400536b00502802302862300536b005622", + "0x50920285f900536b0055f900504f02837a00536b005625005293028625", + "0x536b00537a00514302804e00536b00504e0050c002862000536b005620", + "0x2836b00560b00534602802836b00502800702837a04e6205f900a00537a", + "0x36b00503000525d02802836b00500f00501f02802836b00501400501f028", + "0x502802002862600536b00560700503102802836b00509200501f028028", + "0x36402862800536b00562800501b02862800536b00502857202862700536b", + "0x562962a00702d02862a00536b00502802302862900536b005628627007", + "0x285f900536b0055f900504f02837b00536b00562b00529302862b00536b", + "0x537b00514302804e00536b00504e0050c002862600536b005626005092", + "0x501400501f02802836b00502800702837b04e6265f900a00537b00536b", + "0x9200501f02802836b00503000525d02802836b00500f00501f02802836b", + "0x503102802836b00504f00501f02802836b00501000525d02802836b005", + "0x536b00562c00509202862d00536b0055f900504f02862c00536b0055fa", + "0x36b00502800702802863000502804d02862f00536b0055fe0050df02862e", + "0x505e00532302802836b00505f00532302802836b00509200501f028028", + "0x1400501f02802836b00504f00501f02802836b00501000525d02802836b", + "0x503102802836b00503000525d02802836b00500f00501f02802836b005", + "0x536b00563100509202862d00536b00558200504f02863100536b005583", + "0x36b00502800702802863000502804d02862f00536b0055870050df02862e", + "0x500f00501f02802836b00501400501f02802836b00504f00501f028028", + "0x5f00532302802836b00509200501f02802836b00503000525d02802836b", + "0x503102802836b00501000525d02802836b00505e00532302802836b005", + "0x536b00563200509202862d00536b00527800504f02863200536b005276", + "0x36b00502800702802863000502804d02862f00536b0052730050df02862e", + "0x505e00532302802836b00505f00532302802836b005172005346028028", + "0x1400501f02802836b00504f00501f02802836b00501000525d02802836b", + "0x501f02802836b00503000525d02802836b00500f00501f02802836b005", + "0x63400536b0051a600504f02863300536b00514800503102802836b005092", + "0x2836b00502800702802863600502804d02863500536b005633005092028", + "0x36b00505e00532302802836b00505f00532302802836b005146005346028", + "0x501400501f02802836b00504f00501f02802836b00501000525d028028", + "0x9200501f02802836b00503000525d02802836b00500f00501f02802836b", + "0x2863800536b0051a600504f02863700536b00512100503102802836b005", + "0x2802836b00502800702802863a00502804d02863900536b005637005092", + "0x2836b00505e00532302802836b00505f00532302802836b00511f005346", + "0x36b00501400501f02802836b00504f00501f02802836b00501000525d028", + "0x509200501f02802836b00503000525d02802836b00500f00501f028028", + "0x9202863c00536b0051a600504f02863b00536b0050f600503102802836b", + "0x32302802836b00502800702802863e00502804d02863d00536b00563b005", + "0x2802836b00501000525d02802836b00505e00532302802836b00505f005", + "0x2836b00500f00501f02802836b00501400501f02802836b00504f00501f", + "0x36b0052db00503102802836b00509200501f02802836b00503000525d028", + "0xdf02862e00536b00563f00509202862d00536b0051a600504f02863f005", + "0x36b00562d00504f02864000536b00562f00529302862f00536b0050ea005", + "0x14302804e00536b00504e0050c002862e00536b00562e00509202862d005", + "0x34602802836b00502800702864004e62e62d00a00564000536b005640005", + "0x2802836b00500f00501f02802836b00501400501f02802836b00531f005", + "0x2836b00505f00532302802836b00509200501f02802836b00503000525d", + "0x36b00504f00501f02802836b00501000525d02802836b00505e005323028", + "0x2804d02864200536b00564100509202864100536b00533c005031028028", + "0x1400501f02802836b00508c00534602802836b005028007028028643005", + "0x501f02802836b00503000525d02802836b00500f00501f02802836b005", + "0x25d02802836b00505e00532302802836b00505f00532302802836b005092", + "0x64400536b00525d00503102802836b00504f00501f02802836b005010005", + "0x2800504f02839300536b00564200539802864200536b005644005092028", + "0x63c00536b0052cf00530c0282cc00536b0053930050920282cf00536b005", + "0x63d00539802863800536b00563c00530c02863d00536b0052cc005398028", + "0x63500536b00563900539802863400536b00563800530c02863900536b005", + "0x26600530c02826300536b00563500539802826600536b00563400530c028", + "0x58f00536b00522d00530c0281cb00536b00526300539802822d00536b005", + "0x5900053980285b000536b00558f00530c02859000536b0051cb005398028", + "0x5d200536b0055b10053980285d100536b0055b000530c0285b100536b005", + "0x50280200285f600536b0055d200539802836d00536b0055d100530c028", + "0x36402864600536b00564600501b02864600536b00502828e02864500536b", + "0x564764800702d02864800536b00502802302864700536b005646645007", + "0x2836d00536b00536d00504f02864a00536b00564900529302864900536b", + "0x564a00514302804e00536b00504e0050c00285f600536b0055f6005092", + "0x525c00534602802836b00502800702864a04e5f636d00a00564a00536b", + "0x3000525d02802836b00500f00501f02802836b00501400501f02802836b", + "0x532302802836b00536400515402802836b00509200501f02802836b005", + "0x15302802836b00504f00501f02802836b00501000525d02802836b00500b", + "0x536b00564b00509202864b00536b00524900503102802836b005369005", + "0x564c00501b02864c00536b00502802402837f00536b005028020028245", + "0x2864e00536b00502802302864d00536b00564c37f00736402864c00536b", + "0x2800504f02865000536b00564f00529302864f00536b00564d64e00702d", + "0x4e00536b00504e0050c002824500536b00524500509202802800536b005", + "0x2836b00502800702865004e24502800a00565000536b005650005143028", + "0x36b00500a00509602802836b00501700517902802836b00504d005060028", + "0x504f00501f02802836b00500f00501f02802836b00500b005323028028", + "0x1c800517902802836b00536900515302802836b00509200501f02802836b", + "0x3102801c00536b00501c00509202802836b00501300504202802836b005", + "0x36b00536638000702d02838000536b00502802302865100536b00501c005", + "0x9202802800536b00502800504f02865300536b005652005293028652005", + "0x36b00565300514302836700536b0053670050c002865100536b005651005", + "0x36b00502802002802836b00500700532102865336765102800a005653005", + "0x281c800536b00501000532d02801003100736b00503100529502800f005", + "0x736402801300b00736b00500b0050dc02804e00536b0051c800f007364", + "0x536b00504d00501b02804d00536b0050282d702801400536b00501304e", + "0x50dc02801700536b00502823f02803000536b00504d01400736402804d", + "0x536900501b02836900536b0050170180072e002801804f00736b00504f", + "0x2801b00536b00502823f02836800536b00536903000736402836900536b", + "0x501b02836700536b00501b01c0072e002801c09200736b0050920050dc", + "0x36b00536600503602836600536b00536736800736402836700536b005367", + "0x29502836500536b00502000535e02802836b00501f00504002802001f007", + "0x502800b31902836500536b00536500505b02836403100736b005031005", + "0x2836b0050280070283610840c003165436302d02303136b00736500a364", + "0x502300503102802300536b00502300509202802836b005363005237028", + "0x2803200536b00504f35f00736402835f00536b0050280200281aa00536b", + "0x504002803336c00736b00535d00503602835d00536b005092032007364", + "0x1aa00536b0051aa00509202800c00536b00503300535e02802836b00536c", + "0x3c03136b00700c00b03102d1aa00b31902800c00536b00500c00505b028", + "0x536b00503c00509202802836b00502800702835635935e031655040036", + "0x535602821c00536b00504000535902821500536b00503c00503102803c", + "0x536b0050360050c002821500536b00521500509202804600536b00521c", + "0x2836b00502800702804603621503100504600536b005046005084028036", + "0x502802302804800536b00535e00503102835e00536b00535e005092028", + "0x23700536b00504500536302804500536b00535604700702d02804700536b", + "0x23700508402835900536b0053590050c002804800536b005048005092028", + "0x504f00501f02802836b00502800702823735904803100523700536b005", + "0x9200501f02802836b00503100534302802836b00500b00501f02802836b", + "0x2823900536b0050c00050310280c000536b0050c000509202802836b005", + "0x523f00536302823f00536b00536123b00702d02823b00536b005028023", + "0x2808400536b0050840050c002823900536b00523900509202824500536b", + "0x28a02802836b00502836902824508423903100524500536b005245005084", + "0xa00536b00500a00504f02809204f00b00a00a36b00503100500702800a", + "0x9200528902800b00536b00500b00509202804f00536b00504f005314028", + "0x2824c02800a00536b00502828802809200b04f00a00a00509200536b005", + "0x65604f00b00736b00700502800700502802836b00502836902802836b005", + "0x2828702801000536b00504f00503102802836b00502800702800f092007", + "0x536b0051c800530d02804e00700736b0050070052860281c800536b005", + "0x1401300736b0071c804e00b03117f02801000536b0050100050920281c8", + "0x4f02801700536b00501000503102802836b00502800702803004d007657", + "0x36b00501400530d02801700536b00501700509202801300536b005013005", + "0x36b0073680050b602836836901803136b0050140170130310b4028014005", + "0x2801c00536b00536900503102802836b00502800702801b005658031005", + "0x503100a00718202836700536b00536700530d02836700536b005028181", + "0x736b00736700701803117f02801c00536b00501c00509202803100536b", + "0x36400536b00501c00503102802836b00502800702836502000765901f366", + "0x1f00530d02836400536b00536400509202836600536b00536600504f028", + "0x3630050b602836302d02303136b00501f3643660310b402801f00536b005", + "0x536b00502d00503102802836b00502800702808400565a0c000536b007", + "0x1aa00530d02835f00536b0050c000530b0281aa00536b005028181028361", + "0x36c02300728502836c35d03203136b00535f1aa0071840281aa00536b005", + "0x36100536b00536100509202800c00536b0050320050b902803300536b005", + "0x702803c00565b02836b00700c00534802803300536b00503300504f028", + "0x4000536b00503100530b02803600536b00536100503102802836b005028", + "0x65c35935e00736b00735d04003303118602803600536b005036005092028", + "0x518702821c00536b00503600503102802836b005028007028215356007", + "0x536b00535e00504f02804800536b00504600518902804600536b005359", + "0x35e03100504800536b00504800528402821c00536b00521c00509202835e", + "0x503600503102802836b00521500530f02802836b00502800702804821c", + "0x501b02823700536b00502819002804500536b00502802002804700536b", + "0x536b00502802302823900536b00523704500736402823700536b005237", + "0x4f02824500536b00523f00518f02823f00536b00523923b00702d02823b", + "0x36b00524500528402804700536b00504700509202835600536b005356005", + "0x2836b00503c00534602802836b005028007028245047356031005245005", + "0x36b00536100503102802836b00535d00530f02802836b005031005191028", + "0x24d00501b02824d00536b00502819202824c00536b005028020028249005", + "0x24f00536b00502802302824e00536b00524d24c00736402824d00536b005", + "0x504f02805000536b00525200518f02825200536b00524e24f00702d028", + "0x536b00505000528402824900536b00524900509202803300536b005033", + "0x2802836b00503100519102802836b005028007028050249033031005050", + "0x502300504f02805b00536b00508400518f02800900536b00502d005031", + "0x505b00536b00505b00528402800900536b00500900509202802300536b", + "0x519102802836b00536500530f02802836b00502800702805b009023031", + "0x2805900536b00502802002805800536b00501c00503102802836b005031", + "0x505c05900736402805c00536b00505c00501b02805c00536b005028280", + "0x2825e00536b00525c25d00702d02825d00536b00502802302825c00536b", + "0x505800509202802000536b00502000504f02805e00536b00525e00518f", + "0x502800702805e05802003100505e00536b00505e00528402805800536b", + "0x36900503102802836b00500a00518a02802836b00500700530f02802836b", + "0x1800536b00501800504f02805f00536b00501b00518f02806000536b005", + "0x6001803100505f00536b00505f00528402806000536b005060005092028", + "0x36b00500a00518a02802836b00503000530f02802836b00502800702805f", + "0x502802002805d00536b00501000503102802836b00500700530f028028", + "0x36402829800536b00529800501b02829800536b00502828002829600536b", + "0x504206700702d02806700536b00502802302804200536b005298296007", + "0x2804d00536b00504d00504f02806900536b0052bd00518f0282bd00536b", + "0x6905d04d03100506900536b00506900528402805d00536b00505d005092", + "0x2836b00500700530f02802836b00500a00518a02802836b005028007028", + "0x36b00502804602800600536b00502802002806800536b00500f005031028", + "0x2807100536b00506f00600736402806f00536b00506f00501b02806f005", + "0x507400518f02807400536b00507132500702d02832500536b005028023", + "0x2806800536b00506800509202809200536b00509200504f02807500536b", + "0x28102802836b00502836902807506809203100507500536b005075005284", + "0x2804f00536b00502828b02800b00536b00502828702800a00536b005028", + "0xa00719902809200536b00509200519702809200536b00504f00b00727d", + "0x1c800736b00500f00519b02801000536b00502827c02800f00536b005092", + "0x2800504f02801300536b00504e00527b02802836b0051c800519d02804e", + "0x1300536b00501300527a02800500536b00500500509202802800536b005", + "0x4d01403136b00501001300502800a27602801000536b005010005278028", + "0x3102802836b00502800702801800565d01700536b007030005275028030", + "0x36800527302801c01b36803136b00501700527402836900536b00504d005", + "0x2803202836700536b00502837702802836b00501c00504702802836b005", + "0x36900536b00536900509202801400536b00501400504f02836600536b005", + "0x36600503302836700536b00536700533202801b00536b00501b005278028", + "0x27002836502001f03136b00536636701b36901400b27102836600536b005", + "0x502000503102802836b00502800702802300565e36400536b007365005", + "0x2802836b0050c00050470280c036300736b00536400526f02802d00536b", + "0x536100526b02802836b00508400526d02836108400736b00536300526a", + "0x3136b0071aa00702d03126702802d00536b00502d0050920281aa00536b", + "0x36b00535f00509202802836b00502800702800c03336c03165f35d03235f", + "0x2804003600736b00535d00526602803c00536b00535f00503102835f005", + "0x36b0050320050c002803600536b00503600530d02835e00536b005028263", + "0x2a202804000536b00504000530d02803c00536b00503c005092028032005", + "0x36b00504000530f02802836b00502800702802866002836b00735e036007", + "0x502802002835900536b00503c00503102802836b005031005321028028", + "0x36402821500536b00521500501b02821500536b00502826002835600536b", + "0x521c04600702d02804600536b00502802302821c00536b005215356007", + "0x2801f00536b00501f00504f02804700536b00504800510202804800536b", + "0x50470052c802803200536b0050320050c002835900536b005359005092", + "0x503c00503102802836b00502800702804703235901f00a00504700536b", + "0x2a202804500536b00504500509202823700536b00502825f02804500536b", + "0x36b00503100532102802836b00502800702802866102836b007237040007", + "0x502826002823b00536b00502802002823900536b005045005031028028", + "0x24500536b00523f23b00736402823f00536b00523f00501b02823f00536b", + "0x24c00510202824c00536b00524524900702d02824900536b005028023028", + "0x23900536b00523900509202801f00536b00501f00504f02824d00536b005", + "0x23901f00a00524d00536b00524d0052c802803200536b0050320050c0028", + "0x502827c02824e00536b00504500503102802836b00502800702824d032", + "0x25b02825200536b00525200533202825200536b00502802502824f00536b", + "0x900526d02805b00900736b00505000526a02805000536b00525224f007", + "0x2824e00536b00524e00509202805800536b00505b00526b02802836b005", + "0x66225c05c05903136b00705803224e03126702805800536b00505800525a", + "0x532102802836b00525c00525902802836b00502800702805e25e25d031", + "0x6000536b00505900503102805900536b00505900509202802836b005031", + "0x36b00505d00501b02805d00536b00502825802805f00536b005028020028", + "0x2d02829800536b00502802302829600536b00505d05f00736402805d005", + "0x501f00504f02806700536b00504200510202804200536b005296298007", + "0x2805c00536b00505c0050c002806000536b00506000509202801f00536b", + "0x2802836b00502800702806705c06001f00a00506700536b0050670052c8", + "0x505e0050360282bd00536b00525d00503102825d00536b00525d005092", + "0x2806800536b00506800501302802836b00506900504002806806900736b", + "0x706800500f0282bd00536b0052bd00509202825e00536b00525e0050c0", + "0x2836b00500600501c02802836b00502800702807100566306f00600736b", + "0x740051c802807400536b00506f00501002832500536b0052bd005031028", + "0x2807500536b00507500501b02807700536b0050281ae02807500536b005", + "0x32500509202834c00536b00534c00501b02834c00536b00507707500732c", + "0x2836b00502800702834b00566402836b00734c00534802832500536b005", + "0x7a0310070fb02807a00536b00502803002804300536b005325005031028", + "0x1f00536b00501f00504f02807f00536b0050790050f902807900536b005", + "0x7f0052c802825e00536b00525e0050c002804300536b005043005092028", + "0x34b00534602802836b00502800702807f25e04301f00a00507f00536b005", + "0x2002834800536b00532500503102802836b00503100532102802836b005", + "0x7d00536b00507d00501b02807d00536b00502825702808100536b005028", + "0x34500702d02834500536b00502802302834600536b00507d081007364028", + "0x536b00501f00504f02834300536b00534400510202834400536b005346", + "0x52c802825e00536b00525e0050c002834800536b00534800509202801f", + "0x501c02802836b00502800702834325e34801f00a00534300536b005343", + "0x2834200536b0052bd00503102802836b00503100532102802836b005071", + "0x536b00533d00501b02833d00536b00502825602834100536b005028020", + "0x702d02833c00536b00502802302808c00536b00533d34100736402833d", + "0x36b00501f00504f02808a00536b00533b00510202833b00536b00508c33c", + "0x2c802825e00536b00525e0050c002834200536b00534200509202801f005", + "0x32102802836b00502800702808a25e34201f00a00508a00536b00508a005", + "0x536b00536c00503102836c00536b00536c00509202802836b005031005", + "0x50c002808800536b00533a00509202833900536b00501f00504f02833a", + "0x2802866500502804d02833700536b00500c00521502833800536b005033", + "0x33600536b00502000503102802836b00503100532102802836b005028007", + "0x1f00504f02802836b00508600534c02808e08600736b005023005077028", + "0x33800536b0050070050c002808800536b00533600509202833900536b005", + "0x2836b00502800702802866500502804d02833700536b00508e005215028", + "0x501800507702837700536b00504d00503102802836b005031005321028", + "0x2833900536b00501400504f02802836b00533300534c02833233300736b", + "0x533200521502833800536b0050070050c002808800536b005377005092", + "0x2833000536b00533733100702d02833100536b00502802302833700536b", + "0x508800509202833900536b00533900504f02832f00536b005330005102", + "0x532f00536b00532f0052c802833800536b0053380050c002808800536b", + "0x1b202800a00536b00502825402802836b00502836902832f33808833900a", + "0x36b00500b00a0071b402800b00536b00500b00503302800b00536b005028", + "0x2800504f02800f00536b00502803202809200536b00502803202804f005", + "0x9200536b00509200503302804f00536b00504f00525302802800536b005", + "0x1c801000736b00500f09204f02800a25102800f00536b00500f005033028", + "0x503102802836b00502800702801300566604e00536b0071c8005250028", + "0x3000536b00504d00524602804d00536b00502824a02801400536b005005", + "0x1700524202802836b00501800504702801801700736b00504e005244028", + "0x1b00536b00536800523c02802836b0053690051bd02836836900736b005", + "0x70050c002801400536b00501400509202801000536b00501000504f028", + "0x3000536b0050300051c102801b00536b00501b0051bf02800700536b005", + "0x701f00518b02801f36636701c00a36b00503001b00701401000b23a028", + "0x36400536b00536700503102802836b00502800702836500566702000536b", + "0x504702802836b00502300523d02836302d02303136b005020005238028", + "0xc000536b0050c00051c60280c000536b00502d00523502802836b005363", + "0x35d03235f1aa36100f36b00508400523002808400536b0050c0005231028", + "0x521c02802836b00535f00521c02802836b0051aa00521c02800c03336c", + "0x21c02802836b00536c00521c02802836b00535d00521c02802836b005032", + "0x2803c00536b00502822e02802836b00500c00521c02802836b005033005", + "0x3c3610072a002836400536b00536400509202836100536b005361005033", + "0x3102802836b00503100532102802836b00502800702802866802836b007", + "0x35e00536b00502826002804000536b00502802002803600536b005364005", + "0x2802302835900536b00535e04000736402835e00536b00535e00501b028", + "0x536b00521500510202821500536b00535935600702d02835600536b005", + "0x50c002803600536b00503600509202801c00536b00501c00504f02821c", + "0x2821c36603601c00a00521c00536b00521c0052c802836600536b005366", + "0x4800536b00502803002804600536b00536400503102802836b005028007", + "0x504f02804500536b0050470050f902804700536b0050480310070fb028", + "0x536b0053660050c002804600536b00504600509202801c00536b00501c", + "0x36b00502800702804536604601c00a00504500536b0050450052c8028366", + "0x1c00504f02823700536b00536700503102802836b005031005321028028", + "0x23f00536b0053660050c002823b00536b00523700509202823900536b005", + "0x2836b00502800702802866900502804d02824500536b0053650050df028", + "0x501000504f02824900536b00500500503102802836b005031005321028", + "0x2823f00536b0050070050c002823b00536b00524900509202823900536b", + "0x523900504f02824c00536b00524500510202824500536b0050130050df", + "0x2823f00536b00523f0050c002823b00536b00523b00509202823900536b", + "0x2802836b00502836902824c23f23b23900a00524c00536b00524c0052c8", + "0x536b00500b00519702804f00536b0050281cb02800b00536b00502822d", + "0x9203136b00704f00b03100500a22902804f00536b00504f00519702800b", + "0x536b00509200509202802836b00502800702801304e1c803166a01000f", + "0x22702803004d00736b00501000522602801400536b005092005031028092", + "0x536b00500f0050c002803000536b00503000522202802836b00504d005", + "0x1800566b01700536b00703000522102801400536b00501400509202800f", + "0x2836b00500a00532102802836b00501700522002802836b005028007028", + "0x36b0050281d102836800536b00502802002836900536b005014005031028", + "0x2801c00536b00501b36800736402801b00536b00501b00501b02801b005", + "0x536600510202836600536b00501c36700702d02836700536b005028023", + "0x2836900536b00536900509202802800536b00502800504f02801f00536b", + "0x501f0052c802800f00536b00500f0050c002800700536b005007005307", + "0x1800504702802836b00502800702801f00f00736902800b00501f00536b", + "0x1cb02836500536b00502821d02802000536b00501400503102802836b005", + "0x536b00536500519702802000536b00502000509202836400536b005028", + "0x2303136b00736436500f02000a22902836400536b005364005197028365", + "0x2836b00536300522702802836b0050280070283610840c003166c36302d", + "0x502300503102802300536b00502300509202802836b00500a005321028", + "0x501b02803200536b00502825802835f00536b0050280200281aa00536b", + "0x536b00502802302835d00536b00503235f00736402803200536b005032", + "0x4f02800c00536b00503300510202803300536b00535d36c00702d02836c", + "0x36b0050070053070281aa00536b0051aa00509202802800536b005028005", + "0xb00500c00536b00500c0052c802802d00536b00502d0050c0028007005", + "0x280c000536b0050c000509202802836b00502800702800c02d0071aa028", + "0x3600504002804003600736b00536100503602803c00536b0050c0005031", + "0x2808400536b0050840050c002804000536b00504000501302802836b005", + "0x2835600566d35935e00736b00704000500f02803c00536b00503c005092", + "0x21500536b00503c00503102802836b00535e00501c02802836b005028007", + "0x502822302804600536b00521c0051c802821c00536b005359005010028", + "0x4700536b00504804600732c02804600536b00504600501b02804800536b", + "0x4700534802821500536b00521500509202804700536b00504700501b028", + "0x23700536b00521500503102802836b00502800702804500566e02836b007", + "0x36b00523900521a02823b00536b0050281d302823900536b00502821b028", + "0x23700536b00523700509202824523b00736b00523b00521a02823f239007", + "0x23700a22902824500536b00524500519702823f00536b00523f005197028", + "0x2836b00502800702825224f24e03166f24d24c24903136b00724523f084", + "0x24d00522202805000536b00524900503102824900536b005249005092028", + "0x5000536b00505000509202824c00536b00524c0050c002824d00536b005", + "0x503102802836b00502800702805b00567000900536b00724d005221028", + "0x700924c05803121802805800536b00505800509202805800536b005050", + "0x509202802836b00502800702806005e25e03167125d25c05c05900a36b", + "0x736b00525c0051d602805f00536b00505900503102805900536b005059", + "0x25902804229800736b0052390051d602802836b00505d00525902829605d", + "0x736b00529600521a02829600536b00529600519702802836b005298005", + "0x21a02802836b00506900530f0280692bd00736b005067005266028067296", + "0x6f00530f02806f00600736b00506800526602806804200736b005042005", + "0x2832500536b0050060052f702807100536b0052bd0052f702802836b005", + "0x536b00525d00519702805c00536b00505c0050c002802836b00502800b", + "0x2802867202836b0073250710072a202805f00536b00505f00509202825d", + "0x2802836b00525d00525902802836b00529600525902802836b005028007", + "0x2836b00504200525902802836b00500a00532102802836b00523b005259", + "0x502804d02807500536b00507400509202807400536b00505f005031028", + "0x29600526602807700536b00505f00503102802836b005028007028028673", + "0x4300736b00504200526602802836b00534c00530f02834b34c00736b005", + "0x7a0052f702807900536b00534b0052f702802836b00504300530f02807a", + "0x2836b00707f0790072a202807700536b00507700509202807f00536b005", + "0x523b00525902802836b00525d00525902802836b005028007028028674", + "0x509202834800536b00507700503102802836b00500a00532102802836b", + "0x2802867500502804d02808100536b00507500539802807500536b005348", + "0x736b00525d0051d602807d00536b00507700503102802836b005028007", + "0x25902834334400736b00523b0051d602802836b005346005259028345346", + "0x36b00534200526602834234500736b00534500521a02802836b005344005", + "0x2808c34300736b00534300521a02802836b00533d00530f02833d341007", + "0x53410052f702802836b00533b00530f02833b33c00736b00508c005266", + "0x2807d00536b00507d00509202833a00536b00533c0052f702808a00536b", + "0x534500525902802836b00502800702802867602836b00733a08a0072a2", + "0x7d00503102802836b00534300525902802836b00500a00532102802836b", + "0x702802867500502804d02808100536b00533900509202833900536b005", + "0x33800736b00534500526602808800536b00507d00503102802836b005028", + "0x530f02808633600736b00534300526602802836b00533800530f028337", + "0x37700536b0050860052f702808e00536b0053370052f702802836b005336", + "0x702802867702836b00737708e0072a202808800536b005088005092028", + "0x2833300536b00508800503102802836b00500a00532102802836b005028", + "0x33200536b00502802002802836b00502836902808100536b005333005092", + "0x33133200736402833100536b00533100501b02833100536b0050281d8028", + "0x32e00536b00533032f00702d02832f00536b00502802302833000536b005", + "0x8100509202802800536b00502800504f02832d00536b00532e005102028", + "0x5c00536b00505c0050c002800700536b00500700530702808100536b005", + "0x36b00502800702832d05c00708102800b00532d00536b00532d0052c8028", + "0x8b0050b902808b00536b00502821602832c00536b005088005031028028", + "0x32632900736b00532a00526602832a00536b0050281da02832b00536b005", + "0x36b00502821302808500536b0053290050b902802836b00532600530f028", + "0x2809500536b00509332b00721902832b00536b00532b00501b028093005", + "0x502820e02832400536b0050850950072e002809500536b00509500501b", + "0x2803002809600536b00502820c02832300536b00502820d02809800536b", + "0x36b00532109632303120b02832100536b00532200508102832200536b005", + "0x9202802800536b00502800504f02831e00536b00532400520a02831f005", + "0x36b00505c0050c002800700536b00500700530702832c00536b00532c005", + "0x20802831f00536b00531f00520902809800536b00509800519702805c005", + "0x31d00b36b00531e31f09805c00732c0280921e102831e00536b00531e005", + "0x567831800536b00731900520302802836b00502800b02831931a31b31c", + "0x531800520102831600536b00531c00503102802836b005028007028317", + "0x67931300536b0073140051ff02831600536b00531600509202831400536b", + "0x36b00531300504702802836b00502836902802836b005028007028311005", + "0xa0070fb02831000536b0050280300280a900536b005316005031028028", + "0x536b00531d00504f0280ac00536b0050b00050f90280b000536b005310", + "0x50c002831b00536b00531b0053070280a900536b0050a900509202831d", + "0xac31a31b0a931d00b0050ac00536b0050ac0052c802831a00536b00531a", + "0x536b00531600503102802836b00500a00532102802836b005028007028", + "0x50920280b400536b00531130d00736402830d00536b00502802002830f", + "0x2802867a00502804d02830b00536b0050b40052150280b600536b00530f", + "0xb900536b00531c00503102802836b00500a00532102802836b005028007", + "0xb900509202802836b00530900534c02830830900736b005317005077028", + "0x2302802836b00502836902830b00536b0053080052150280b600536b005", + "0x36b00530600510202830600536b00530b30700702d02830700536b005028", + "0x3070280b600536b0050b600509202831d00536b00531d00504f028305005", + "0x36b0053050052c802831a00536b00531a0050c002831b00536b00531b005", + "0x500a00532102802836b00502800702830531a31b0b631d00b005305005", + "0x25e00509202802836b00523900525902802836b00523b00525902802836b", + "0x2830400536b0050280230280bf00536b00525e00503102825e00536b005", + "0x2800504f02830200536b00530300510202830300536b00506030400702d", + "0x700536b0050070053070280bf00536b0050bf00509202802800536b005", + "0xbf02800b00530200536b0053020052c802805e00536b00505e0050c0028", + "0xa00532102802836b00505b00504702802836b00502800702830205e007", + "0x503102802836b00523900525902802836b00523b00525902802836b005", + "0x2839400536b00502824502839300536b00502802002805100536b005050", + "0x502802302839500536b00539439300736402839400536b00539400501b", + "0xc700536b00539600510202839600536b0053950dc00702d0280dc00536b", + "0x700530702805100536b00505100509202802800536b00502800504f028", + "0xc700536b0050c70052c802824c00536b00524c0050c002800700536b005", + "0x2836b00500a00532102802836b0050280070280c724c00705102800b005", + "0x36b00524e00509202802836b00523900525902802836b00523b005259028", + "0x702d0280c900536b0050280230280c600536b00524e00503102824e005", + "0x36b00502800504f0280cf00536b0050cb0051020280cb00536b0052520c9", + "0xc002800700536b0050070053070280c600536b0050c6005092028028005", + "0x24f0070c602800b0050cf00536b0050cf0052c802824f00536b00524f005", + "0x36b00500a00532102802836b00504500534602802836b0050280070280cf", + "0x502825702839700536b00502802002830100536b005215005031028028", + "0x39800536b00530c39700736402830c00536b00530c00501b02830c00536b", + "0xd40051020280d400536b0053982fb00702d0282fb00536b005028023028", + "0x30100536b00530100509202802800536b00502800504f0282fa00536b005", + "0x2fa0052c802808400536b0050840050c002800700536b005007005307028", + "0x501c02802836b0050280070282fa08400730102800b0052fa00536b005", + "0x280d500536b00503c00503102802836b00500a00532102802836b005356", + "0x536b0052f800501b0282f800536b00502825602839900536b005028020", + "0x702d0282f100536b0050280230282f700536b0052f83990073640282f8", + "0x36b00502800504f0282ee00536b0050da0051020280da00536b0052f72f1", + "0xc002800700536b0050070053070280d500536b0050d5005092028028005", + "0x840070d502800b0052ee00536b0052ee0052c802808400536b005084005", + "0x36b0051c800509202802836b00500a00532102802836b0050280070282ee", + "0x702d0280d200536b0050280230282ec00536b0051c80050310281c8005", + "0x36b00502800504f0280db00536b0052ef0051020282ef00536b0050130d2", + "0xc002800700536b0050070053070282ec00536b0052ec005092028028005", + "0x4e0072ec02800b0050db00536b0050db0052c802804e00536b00504e005", + "0x500a00519702800b00536b0050281cb02800a00536b00502822d0280db", + "0x36b00700b00a00700500a1fd02800b00536b00500b00519702800a00536b", + "0x504f00509202802836b00502800702804e1c801003167b00f09204f031", + "0x4d01400736b00500f0051fa02801300536b00504f00503102804f00536b", + "0x50920050c002804d00536b00504d0051ee02802836b0050140051f3028", + "0x67c03000536b00704d00500002801300536b00501300509202809200536b", + "0x503100532102802836b00503000557a02802836b005028007028017005", + "0x281d102836900536b00502802002801800536b00501300503102802836b", + "0x536b00536836900736402836800536b00536800501b02836800536b005", + "0x510202836700536b00501b01c00702d02801c00536b00502802302801b", + "0x536b00501800509202802800536b00502800504f02836600536b005367", + "0x2800a00536600536b0053660052c802809200536b0050920050c0028018", + "0x1300503102802836b00501700504702802836b005028007028366092018", + "0x9202836500536b0050281cb02802000536b00502857b02801f00536b005", + "0x36b00536500519702802000536b00502000519702801f00536b00501f005", + "0x840c036303167d02d02336403136b00736502009201f00a1fd028365005", + "0x2836b00503100532102802836b00502d0051f302802836b005028007028", + "0x502802002836100536b00536400503102836400536b005364005092028", + "0x36402835f00536b00535f00501b02835f00536b0050282580281aa00536b", + "0x503235d00702d02835d00536b00502802302803200536b00535f1aa007", + "0x2802800536b00502800504f02803300536b00536c00510202836c00536b", + "0x50330052c802802300536b0050230050c002836100536b005361005092", + "0x536300509202802836b00502800702803302336102800a00503300536b", + "0x3603c00736b00508400503602800c00536b00536300503102836300536b", + "0x50c00050c002803600536b00503600501302802836b00503c005040028", + "0x35e04000736b00703600500f02800c00536b00500c0050920280c000536b", + "0xc00503102802836b00504000501c02802836b00502800702835900567e", + "0x21c00536b0052150051c802821500536b00535e00501002835600536b005", + "0x4621c00732c02821c00536b00521c00501b02804600536b005028223028", + "0x35600536b00535600509202804800536b00504800501b02804800536b005", + "0x35600503102802836b00502800702804700567f02836b007048005348028", + "0x21a02823900536b00502857e02823700536b00502857d02804500536b005", + "0x4500509202823f23900736b00523900521a02823b23700736b005237005", + "0x23f00536b00523f00519702823b00536b00523b00519702804500536b005", + "0x702824f24e24d03168024c24924503136b00723f23b0c004500a1fd028", + "0x25200536b00524500503102824500536b00524500509202802836b005028", + "0x25200509202824900536b0052490050c002824c00536b00524c0051ee028", + "0x36b00502800702800900568105000536b00724c00500002825200536b005", + "0x3157f02805b00536b00505b00509202805b00536b005252005031028028", + "0x36b00502800702805e25e25d03168225c05c05905800a36b00705024905b", + "0x51d602806000536b00505800503102805800536b005058005092028028", + "0x736b0052370051d602802836b00505f00525902805d05f00736b00505c", + "0x521a02805d00536b00505d00519702802836b005296005259028298296", + "0x52bd00530f0282bd06700736b00504200526602804205d00736b00505d", + "0x606800736b00506900526602806929800736b00529800521a02802836b", + "0x50680052f702806f00536b0050670052f702802836b00500600530f028", + "0x2825c00536b00525c00519702805900536b0050590050c002807100536b", + "0x2800702802868302836b00707106f0072a202806000536b005060005092", + "0x525902802836b00525c00525902802836b00505d00525902802836b005", + "0x3102802836b00529800525902802836b00503100532102802836b005239", + "0x2868400502804d02807400536b00532500509202832500536b005060005", + "0x36b00505d00526602807500536b00506000503102802836b005028007028", + "0x2804334b00736b00529800526602802836b00507700530f02834c077007", + "0x36b0050430052f702807a00536b00534c0052f702802836b00534b00530f", + "0x2868502836b00707907a0072a202807500536b005075005092028079005", + "0x2836b00523900525902802836b00525c00525902802836b005028007028", + "0x507f00509202807f00536b00507500503102802836b005031005321028", + "0x2800702802868600502804d02834800536b00507400539802807400536b", + "0x34607d00736b00525c0051d602808100536b00507500503102802836b005", + "0x34500525902834434500736b0052390051d602802836b00507d005259028", + "0x34200736b00534300526602834334600736b00534600521a02802836b005", + "0x526602833d34400736b00534400521a02802836b00534100530f028341", + "0x536b0053420052f702802836b00533c00530f02833c08c00736b00533d", + "0x72a202808100536b00508100509202808a00536b00508c0052f702833b", + "0x2836b00534600525902802836b00502800702802868702836b00708a33b", + "0x36b00508100503102802836b00534400525902802836b005031005321028", + "0x502800702802868600502804d02834800536b00533a00509202833a005", + "0x2833808800736b00534600526602833900536b00508100503102802836b", + "0x533700530f02833633700736b00534400526602802836b00508800530f", + "0x9202808e00536b0053360052f702808600536b0053380052f702802836b", + "0x502800702802868802836b00708e0860072a202833900536b005339005", + "0x509202837700536b00533900503102802836b00503100532102802836b", + "0x2833200536b0050281d802833300536b00502802002834800536b005377", + "0x502802302833100536b00533233300736402833200536b00533200501b", + "0x32e00536b00532f00510202832f00536b00533133000702d02833000536b", + "0x590050c002834800536b00534800509202802800536b00502800504f028", + "0x702832e05934802800a00532e00536b00532e0052c802805900536b005", + "0x2832c00536b00502858102832d00536b00533900503102802836b005028", + "0x536b00502858202802836b00508b00501f02808b00536b00532c0050b9", + "0x50b902802836b00532900530f02832932a00736b00532b00526602832b", + "0x2808500536b00502858302802836b00532600501f02832600536b00532a", + "0x36b00508500519702832d00536b00532d00509202809300536b005028584", + "0x3136b00709308505932d00a1fd02809300536b005093005197028085005", + "0x36b00509500509202802836b005028007028322096323031689098324095", + "0xc002809800536b0050980051ee02832100536b005095005031028095005", + "0x36b00709800500002832100536b00532100509202832400536b005324005", + "0x2831d00536b00532100503102802836b00502800702831e00568a31f005", + "0x31a00536b00502837502831b00536b00502858702831c00536b005028585", + "0x3240050c002831d00536b00531d00509202802800536b00502800504f028", + "0x31b00536b00531b00519702831c00536b00531c00519702832400536b005", + "0x2809258902831f00536b00531f00558802831a00536b00531a005197028", + "0x536b00731600558a02831631731831900a36b00531f31a31b31c32431d", + "0x503102802836b00531400558b02802836b00502800702831300568b314", + "0x536b0050a90310070fb0280a900536b00502803002831100536b005318", + "0x509202831900536b00531900504f0280b000536b0053100050f9028310", + "0x536b0050b00052c802831700536b0053170050c002831100536b005311", + "0x2836b00503100532102802836b0050280070280b031731131900a0050b0", + "0x31900504f02830f00536b0053130051020280ac00536b005318005031028", + "0x31700536b0053170050c00280ac00536b0050ac00509202831900536b005", + "0x2836b00502800702830f3170ac31900a00530f00536b00530f0052c8028", + "0x36b00532100503102802836b00503100532102802836b00531e005047028", + "0xb600501b0280b600536b0050282450280b400536b00502802002830d005", + "0xb900536b00502802302830b00536b0050b60b40073640280b600536b005", + "0x504f02830800536b00530900510202830900536b00530b0b900702d028", + "0x536b0053240050c002830d00536b00530d00509202802800536b005028", + "0x36b00502800702830832430d02800a00530800536b0053080052c8028324", + "0x32300503102832300536b00532300509202802836b005031005321028028", + "0x30500536b00532230600702d02830600536b00502802302830700536b005", + "0x30700509202802800536b00502800504f0280bf00536b005305005102028", + "0xbf00536b0050bf0052c802809600536b0050960050c002830700536b005", + "0x2802836b00503100532102802836b0050280070280bf09630702800a005", + "0x536b00525d00509202802836b00523700525902802836b005239005259", + "0x30300702d02830300536b00502802302830400536b00525d00503102825d", + "0x536b00502800504f02805100536b00530200510202830200536b00505e", + "0x52c802825e00536b00525e0050c002830400536b005304005092028028", + "0x504702802836b00502800702805125e30402800a00505100536b005051", + "0x25902802836b00523900525902802836b00503100532102802836b005009", + "0x39400536b00502802002839300536b00525200503102802836b005237005", + "0x39539400736402839500536b00539500501b02839500536b005028245028", + "0xc700536b0050dc39600702d02839600536b0050280230280dc00536b005", + "0x39300509202802800536b00502800504f0280c600536b0050c7005102028", + "0xc600536b0050c60052c802824900536b0052490050c002839300536b005", + "0x2802836b00503100532102802836b0050280070280c624939302800a005", + "0x536b00524d00509202802836b00523700525902802836b005239005259", + "0xcb00702d0280cb00536b0050280230280c900536b00524d00503102824d", + "0x536b00502800504f02830100536b0050cf0051020280cf00536b00524f", + "0x52c802824e00536b00524e0050c00280c900536b0050c9005092028028", + "0x534602802836b00502800702830124e0c902800a00530100536b005301", + "0x2839700536b00535600503102802836b00503100532102802836b005047", + "0x536b00539800501b02839800536b00502825702830c00536b005028020", + "0x702d0280d400536b0050280230282fb00536b00539830c007364028398", + "0x36b00502800504f0280d500536b0052fa0051020282fa00536b0052fb0d4", + "0x2c80280c000536b0050c00050c002839700536b005397005092028028005", + "0x1c02802836b0050280070280d50c039702800a0050d500536b0050d5005", + "0x39900536b00500c00503102802836b00503100532102802836b005359005", + "0x36b0052f700501b0282f700536b0050282560282f800536b005028020028", + "0x2d0280da00536b0050280230282f100536b0052f72f80073640282f7005", + "0x502800504f0282ec00536b0052ee0051020282ee00536b0052f10da007", + "0x280c000536b0050c00050c002839900536b00539900509202802800536b", + "0x2802836b0050280070282ec0c039902800a0052ec00536b0052ec0052c8", + "0x36b00501000503102801000536b00501000509202802836b005031005321", + "0x1020280db00536b00504e2ef00702d0282ef00536b0050280230280d2005", + "0x36b0050d200509202802800536b00502800504f0282f600536b0050db005", + "0xa0052f600536b0052f60052c80281c800536b0051c80050c00280d2005", + "0x4f00b00736b00700502800700502802836b0050283690282f61c80d2028", + "0x3602801000536b00504f00503102802836b00502800702800f09200768c", + "0x36b00502858d02801300536b00504e00532502804e1c800736b00500a005", + "0x9202801400536b00501400503302801300536b005013005033028014005", + "0x1700768d03004d00736b00701401300b03158e02801000536b005010005", + "0x36b00501000503102802836b00503000521c02802836b005028007028018", + "0x58f02836900536b00536900509202804d00536b00504d00504f028369005", + "0x36900503102802836b00502800702801c00568e01b36800736b0071c8005", + "0x36800536b00536800521502836600536b00501b00501002836700536b005", + "0x36800558f02836600536b00536600501b02836700536b005367005092028", + "0x36b00536700503102802836b00502800702836500568f02001f00736b007", + "0x9202801f00536b00501f00521502802300536b005020005010028364005", + "0x36b00701f00558f02802300536b00502300501b02836400536b005364005", + "0x8400536b00536400503102802836b0050280070280c000569036302d007", + "0x3610050dc02836100536b00536100501b02836100536b005363005010028", + "0x536b00508400509202802d00536b00502d0052150281aa36100736b005", + "0x501f02802836b00502800702835f00569102836b0071aa005348028084", + "0x3200536b00503200509202803200536b00508400503102802836b005361", + "0x2802836b00502800702803300569236c35d00736b00736604d00724e028", + "0x3c00504002803603c00736b00502d00503602800c00536b005032005031", + "0x2800c00536b00500c00509202804000536b00503600535e02802836b005", + "0x35935e03136b00704002336c00700c00b25e02835d00536b00535d00504f", + "0x2802836b00535600523702802836b00502800702804621c215031693356", + "0x535d00504f02804800536b00535e00503102835e00536b00535e005092", + "0x2823700536b0053590050c002804500536b00504800509202804700536b", + "0x9202802836b00503100532102802836b00502800702802869400502804d", + "0x536b00502802302823900536b00521500503102821500536b005215005", + "0x4f02824500536b00523f00559002823f00536b00504623b00702d02823b", + "0x36b00521c0050c002823900536b00523900509202835d00536b00535d005", + "0x502800702824521c23935d00a00524500536b00524500559202821c005", + "0x2300501f02802836b00502d00504002802836b00503100532102802836b", + "0x24502824c00536b00502802002824900536b00503200503102802836b005", + "0x36b00524d24c00736402824d00536b00524d00501b02824d00536b005028", + "0x59002825200536b00524e24f00702d02824f00536b00502802302824e005", + "0x36b00524900509202803300536b00503300504f02805000536b005252005", + "0xa00505000536b00505000559202800700536b0050070050c0028249005", + "0x503102802836b00535f00534602802836b005028007028050007249033", + "0x536b00505b36100732c02805b00536b00502823f02800900536b005084", + "0x534802800900536b00500900509202805800536b00505800501b028058", + "0x536b00500900503102802836b00502800702805900569502836b007058", + "0x69625d25c00736b00736604d00707f02805c00536b00505c00509202805c", + "0x2d00503602805e00536b00505c00503102802836b00502800702825e005", + "0x5d00536b00505f00535e02802836b00506000504002805f06000736b005", + "0x5e00b31902825c00536b00525c00504f02805e00536b00505e005092028", + "0x36b0050280070280692bd06703169704229829603136b00705d02325d007", + "0x29600503102829600536b00529600509202802836b005042005237028028", + "0x6f00536b00506800509202800600536b00525c00504f02806800536b005", + "0x2836b00502800702802869800502804d02807100536b0052980050c0028", + "0x506700503102806700536b00506700509202802836b005031005321028", + "0x2807500536b00506907400702d02807400536b00502802302832500536b", + "0x532500509202825c00536b00525c00504f02807700536b005075005590", + "0x507700536b0050770055920282bd00536b0052bd0050c002832500536b", + "0x4002802836b00503100532102802836b0050280070280772bd32525c00a", + "0x34c00536b00505c00503102802836b00502300501f02802836b00502d005", + "0x36b00504300501b02804300536b00502824502834b00536b005028020028", + "0x2d02807900536b00502802302807a00536b00504334b007364028043005", + "0x525e00504f02834800536b00507f00559002807f00536b00507a079007", + "0x2800700536b0050070050c002834c00536b00534c00509202825e00536b", + "0x2802836b00502800702834800734c25e00a00534800536b005348005592", + "0x536b00500900503102802836b00536600501f02802836b005059005346", + "0x732c02834602300736b0050230050dc02807d00536b005028593028081", + "0x36b00508100509202834500536b00534500501b02834500536b00507d346", + "0x1f02802836b00502800702834400569902836b007345005348028081005", + "0x536b00504d00504f02834300536b00508100503102802836b005023005", + "0x521502800700536b0050070050c002834300536b00534300509202804d", + "0x8c33d34134200a36b00502d03100734304d00b30302802d00536b00502d", + "0x2802836b00534400534602802836b00502800702808c33d34134200a005", + "0x536b00502837402833c00536b00508100503102802836b00502d005040", + "0x9202808a00536b00508a00501b02808a00536b00533b02300732c02833b", + "0x502800702833a00569a02836b00708a00534802833c00536b00533c005", + "0x2802002833900536b00533c00503102802836b00503100532102802836b", + "0x2833800536b00533800501b02833800536b00502839302808800536b005", + "0x33733600702d02833600536b00502802302833700536b005338088007364", + "0x4d00536b00504d00504f02808e00536b00508600559002808600536b005", + "0x8e00559202800700536b0050070050c002833900536b005339005092028", + "0x33a00534602802836b00502800702808e00733904d00a00508e00536b005", + "0x2800600536b00504d00504f02837700536b00533c00503102802836b005", + "0x500600530c02807100536b0050070050c002806f00536b005377005092", + "0x2823700536b00507100559402804500536b00506f00539802804700536b", + "0x533200559602833200536b00533303100759502833300536b00502823b", + "0x2800702833123704504700a00533100536b00533100559202833100536b", + "0x501f02802836b00503100532102802836b0050c000504002802836b005", + "0x2833000536b00536400503102802836b00536600501f02802836b005023", + "0x536b00532e00501b02832e00536b00502824502832f00536b005028020", + "0x702d02832c00536b00502802302832d00536b00532e32f00736402832e", + "0x36b00504d00504f02832b00536b00508b00559002808b00536b00532d32c", + "0x59202800700536b0050070050c002833000536b00533000509202804d005", + "0x4002802836b00502800702832b00733004d00a00532b00536b00532b005", + "0x2802836b00536600501f02802836b00503100532102802836b005365005", + "0x536b00502824502832900536b00502802002832a00536b005367005031", + "0x2302808500536b00532632900736402832600536b00532600501b028326", + "0x36b00509500559002809500536b00508509300702d02809300536b005028", + "0xc002832a00536b00532a00509202804d00536b00504d00504f028324005", + "0x32400732a04d00a00532400536b00532400559202800700536b005007005", + "0x2836b00503100532102802836b00501c00504002802836b005028007028", + "0x36b00502824502832300536b00502802002809800536b005369005031028", + "0x2832200536b00509632300736402809600536b00509600501b028096005", + "0x531f00559002831f00536b00532232100702d02832100536b005028023", + "0x2809800536b00509800509202804d00536b00504d00504f02831e00536b", + "0x709804d00a00531e00536b00531e00559202800700536b0050070050c0", + "0x36b00503100532102802836b00501800521c02802836b00502800702831e", + "0x502802002831d00536b00501000503102802836b0051c8005040028028", + "0x36402831b00536b00531b00501b02831b00536b00502859702831c00536b", + "0x531a31900702d02831900536b00502802302831a00536b00531b31c007", + "0x2801700536b00501700504f02831700536b00531800559002831800536b", + "0x531700559202800700536b0050070050c002831d00536b00531d005092", + "0x500a00504002802836b00502800702831700731d01700a00531700536b", + "0x2802002831600536b00500f00503102802836b00503100532102802836b", + "0x2831300536b00531300501b02831300536b00502804602831400536b005", + "0x3110a900702d0280a900536b00502802302831100536b005313314007364", + "0x9200536b00509200504f0280b000536b00531000559002831000536b005", + "0xb000559202800700536b0050070050c002831600536b005316005092028", + "0x2800700502802836b0050283690280b000731609200a0050b000536b005", + "0xb00503102802836b00502800702809204f00769b00b00a00736b007005", + "0x536b00500a00504f02801003100736b0050310050dc02800f00536b005", + "0x281c800569c02836b00701000534802800f00536b00500f00509202800a", + "0x2802836b00503100501f02802836b00500700532102802836b005028007", + "0x536b00502859802801300536b00502802002804e00536b00500f005031", + "0x2302804d00536b00501401300736402801400536b00501400501b028014", + "0x36b00501700510202801700536b00504d03000702d02803000536b005028", + "0x2c802804e00536b00504e00509202800a00536b00500a00504f028018005", + "0x534602802836b00502800702801804e00a03100501800536b005018005", + "0x2836800536b00502823f02836900536b00500f00503102802836b0051c8", + "0x36900509202800a00536b00500a00504f02801b00536b00536803100732c", + "0x501b00736900a00a39402801b00536b00501b00501b02836900536b005", + "0x700532102802836b00502800702836636701c03100536636701c03136b", + "0x2002801f00536b00509200503102802836b00503100501f02802836b005", + "0x36500536b00536500501b02836500536b00502804602802000536b005028", + "0x2300702d02802300536b00502802302836400536b005365020007364028", + "0x536b00504f00504f02836300536b00502d00510202802d00536b005364", + "0x4f03100536300536b0053630052c802801f00536b00501f00509202804f", + "0x769d00b00a00736b00700502800700502802836b00502836902836301f", + "0x310050dc02800f00536b00500b00503102802836b00502800702809204f", + "0x536b00500f00509202800a00536b00500a00504f02801003100736b005", + "0x501f02802836b0050280070281c800569e02836b00701000534802800f", + "0x2801300536b00502803002804e00536b00500f00503102802836b005031", + "0xa00504f02804d00536b0050140050f902801400536b0050130070070fb", + "0x4d00536b00504d0052c802804e00536b00504e00509202800a00536b005", + "0x3102802836b0051c800534602802836b00502800702804d04e00a031005", + "0x36b00501703100732c02801700536b00502823f02803000536b00500f005", + "0x1b02803000536b00503000509202800a00536b00500a00504f028018005", + "0x501b36836903136b00501800703000a00a39502801800536b005018005", + "0x532102802836b00503100501f02802836b00502800702801b368369031", + "0x2836700536b00502802002801c00536b00509200503102802836b005007", + "0x536636700736402836600536b00536600501b02836600536b005028046", + "0x2836500536b00501f02000702d02802000536b00502802302801f00536b", + "0x501c00509202804f00536b00504f00504f02836400536b005365005102", + "0x502859902836401c04f03100536400536b0053640052c802801c00536b", + "0x4e1c800736b00501000559b02801000536b00500f00559a02800f00536b", + "0x50130051c802801300536b00504e00559d02802836b0051c800559c028", + "0x1400536b00501400501b02804d00b00736b00500b0050dc02801400536b", + "0x2801700536b00501700501b02801703000736b00504d0140070310e3028", + "0x55a002836800536b00536900559f02836901800736b00501702800759e", + "0x536b00501c0055a202802836b00501b0055a102801c01b00736b005368", + "0x33a02801f36600736b0053660055a302836600536b00536700510c028367", + "0x736b00536500535d02836500536b00502803202802000536b00501f005", + "0x4f02803000536b0050300050c602836400536b005364005033028364365", + "0x69f36302d02303136b00702036403100500a03c02801800536b005018005", + "0x3102802300536b00502300509202802836b0050280070283610840c0031", + "0x36b00535f3660075a402835f00536b0050283730281aa00536b005023005", + "0x8802836500536b0053650050330281aa00536b0051aa005092028032005", + "0x36502d1aa00a03c02836300536b00536300501b02803200536b005032005", + "0x9202802836b00502800702803603c00c0316a003336c35d03136b007032", + "0x536b00502859902804000536b00535d00503102835d00536b00535d005", + "0x59c02821535600736b00535900559b02835900536b00535e00559a02835e", + "0x536b00521c0051c802821c00536b00521500559d02802836b005356005", + "0x4704800736b00500b0460300310e302804600536b00504600501b028046", + "0x5a302823704500736b00504701800759e02804700536b00504700501b028", + "0x4f3630072e002823b00536b00523900533a02823923700736b005237005", + "0x24924500736b00524500535d02824500536b00502803202823f00536b005", + "0x23f00501b02824900536b00524900503302804000536b005040005092028", + "0x4800536b0050480050c602803300536b00503300501b02823f00536b005", + "0x24c00736b00723f23b24936c04000b00c02804500536b00504500504f028", + "0x24c00536b00524c00509202802836b00502800702825224f24e0316a124d", + "0x92370075a402800900536b00502837302805000536b00524c005031028", + "0x536b00505000509202805800536b0050920330072e002805b00536b005", + "0x501b02805b00536b00505b00508802824500536b005245005033028050", + "0x316a205c05900736b00705805b24524d05000b00c02805800536b005058", + "0x503102805900536b00505900509202802836b00502800702825e25d25c", + "0x536b00506000a0070fb02806000536b00502803002805e00536b005059", + "0x509202804500536b00504500504f02805d00536b00505f0050f902805f", + "0x536b00505c0050c002804800536b0050480050c602805e00536b00505e", + "0x502800702805d05c04805e04500b00505d00536b00505d0052c802805c", + "0x503102825c00536b00525c00509202802836b00500a00532102802836b", + "0x536b00525d0050c002829800536b00529600509202829600536b00525c", + "0x36b0050280070280286a300502804d02806700536b00525e005215028042", + "0x503300501f02802836b0052370055a502802836b00500a005321028028", + "0x24e00509202802836b00509200501f02802836b00524500521c02802836b", + "0x29800536b0052bd0050920282bd00536b00524e00503102824e00536b005", + "0x502802302806700536b00525200521502804200536b00524f0050c0028", + "0x600536b00506800510202806800536b00506706900702d02806900536b", + "0x480050c602829800536b00529800509202804500536b00504500504f028", + "0x600536b0050060052c802804200536b0050420050c002804800536b005", + "0x2836b00504f00501f02802836b00502800702800604204829804500b005", + "0x36b00500b00501f02802836b00536300501f02802836b00500a005321028", + "0xc00503102800c00536b00500c00509202802836b00509200501f028028", + "0x32500536b00503c0050c002807100536b00506f00509202806f00536b005", + "0x2836b0050280070280286a400502804d02807400536b005036005215028", + "0x36b00536500521c02802836b00500a00532102802836b00504f00501f028", + "0x53660055a502802836b00509200501f02802836b00500b00501f028028", + "0x9202807500536b0050c00050310280c000536b0050c000509202802836b", + "0x36b00536100521502832500536b0050840050c002807100536b005075005", + "0x10202834c00536b00507407700702d02807700536b005028023028074005", + "0x36b00507100509202801800536b00501800504f02834b00536b00534c005", + "0x2c802832500536b0053250050c002803000536b0050300050c6028071005", + "0x736b00504f0050d502834b32503007101800b00534b00536b00534b005", + "0x559b0281c800536b00501000559a02801000536b00502859902800f092", + "0x536b00501300559d02802836b00504e00559c02801304e00736b0051c8", + "0x1b02803009200736b0050920050dc02804d00536b0050140051c8028014", + "0x501b02801801700736b00503004d0310310e302804d00536b00504d005", + "0x536800559f02836836900736b00501802800759e02801800536b005018", + "0x2802836b00501c0055a102836701c00736b00501b0055a002801b00536b", + "0x501f0055a302801f00536b00536600510c02836600536b0053670055a2", + "0x2836400536b00502803202836500536b00502000533a02802001f00736b", + "0x170050c602802300536b00502300503302802336400736b00536400535d", + "0x736502300a00500a03c02836900536b00536900504f02801700536b005", + "0x2d00509202802836b0050280070281aa3610840316a50c036302d03136b", + "0x2803200536b00502837302835f00536b00502d00503102802d00536b005", + "0x36400503302835f00536b00535f00509202835d00536b00503201f0075a4", + "0xc000536b0050c000501b02835d00536b00535d00508802836400536b005", + "0x702804003603c0316a600c03336c03136b00735d36436335f00a03c028", + "0x35e00536b00536c00503102836c00536b00536c00509202802836b005028", + "0x35e00509202800c00536b00500c00501b02803300536b0050330050c0028", + "0x2804621c2150316a735635900736b0070c03690070ac02835e00536b005", + "0x536b00504800509202804800536b00535e00503102802836b005028007", + "0x502800702823b2392370316a804504700736b00700c3590070ac028048", + "0x2824924500736b00500f0052f802823f00536b00504800503102802836b", + "0x2802836b00524d00530f02824f24e24d24c00a36b0052453560070315a6", + "0x24904524c0315a602825200536b00524e0050b902802836b00524f00530f", + "0x36b00505800530f02802836b00500900530f02805805b00905000a36b005", + "0x5c00559a02805c00536b00502859902805900536b00505b0050b9028028", + "0x2836b00525d00559c02825e25d00736b00525c00559b02825c00536b005", + "0x6000501b02806000536b00505e0051c802805e00536b00525e00559d028", + "0x505d00501b02805d05f00736b0050920600170310e302806000536b005", + "0x736b0052980055a302829829600736b00505d04700759e02805d00536b", + "0x535d0282bd00536b00502803202806700536b00504200533a028042298", + "0x36b00506900503302823f00536b00523f0050920280692bd00736b0052bd", + "0x1b02805000536b00505000530702825200536b00525200501b028069005", + "0x36b00529600504f02805f00536b00505f0050c602805900536b005059005", + "0x32507106f0316a900606800736b00725206706903323f00b00c028296005", + "0x36b00506800503102806800536b00506800509202802836b005028007028", + "0x9202807700536b0050752980075a402807500536b005028373028074005", + "0x36b0050770050880282bd00536b0052bd00503302807400536b005074005", + "0x7907a0430316aa34b34c00736b0070590772bd00607400b00c028077005", + "0x36b00534c00503102834c00536b00534c00509202802836b005028007028", + "0xf902808100536b00534800b0070fb02834800536b00502803002807f005", + "0x36b00507f00509202829600536b00529600504f02807d00536b005081005", + "0xc002805f00536b00505f0050c602805000536b00505000530702807f005", + "0x5f05007f29604f00507d00536b00507d0052c802834b00536b00534b005", + "0x504300509202802836b00500b00532102802836b00502800702807d34b", + "0x2834500536b00534600509202834600536b00504300503102804300536b", + "0x6ab00502804d02834300536b00507900521502834400536b00507a0050c0", + "0x36b00505900501f02802836b00500b00532102802836b005028007028028", + "0x506f00509202802836b0052bd00521c02802836b0052980055a5028028", + "0x2834500536b00534200509202834200536b00506f00503102806f00536b", + "0x36b00502802302834300536b00532500521502834400536b0050710050c0", + "0x2808c00536b00533d00510202833d00536b00534334100702d028341005", + "0x505000530702834500536b00534500509202829600536b00529600504f", + "0x2834400536b0053440050c002805f00536b00505f0050c602805000536b", + "0x36b00502800702808c34405f05034529604f00508c00536b00508c0052c8", + "0x500b00532102802836b00523b00530f02802836b00523900530f028028", + "0x35600530f02802836b00500f00539902802836b00509200501f02802836b", + "0x24502833b00536b00502802002833c00536b00504800503102802836b005", + "0x36b00508a33b00736402808a00536b00508a00501b02808a00536b005028", + "0x10202808800536b00533a33900702d02833900536b00502802302833a005", + "0x36b00533c00509202823700536b00523700504f02833800536b005088005", + "0xc002801700536b0050170050c602800700536b00500700530702833c005", + "0x1700733c23704f00533800536b0053380052c802803300536b005033005", + "0x504600530f02802836b00521c00530f02802836b005028007028338033", + "0xf00539902802836b00509200501f02802836b00500b00532102802836b", + "0x2002833700536b00535e00503102802836b00500c00501f02802836b005", + "0x8600536b00508600501b02808600536b00502824502833600536b005028", + "0x37700702d02837700536b00502802302808e00536b005086336007364028", + "0x536b00521500504f02833200536b00533300510202833300536b00508e", + "0x50c602800700536b00500700530702833700536b005337005092028215", + "0x536b0053320052c802803300536b0050330050c002801700536b005017", + "0x50c000501f02802836b00502800702833203301700733721504f005332", + "0xf00539902802836b00509200501f02802836b00500b00532102802836b", + "0x2833100536b00503c00503102803c00536b00503c00509202802836b005", + "0x504000521502832f00536b0050360050c002833000536b005331005092", + "0x536400521c02802836b0050280070280286ac00502804d02832e00536b", + "0xf00539902802836b00509200501f02802836b00500b00532102802836b", + "0x3102808400536b00508400509202802836b00501f0055a502802836b005", + "0x36b0053610050c002833000536b00532d00509202832d00536b005084005", + "0x702d02832c00536b00502802302832e00536b0051aa00521502832f005", + "0x36b00536900504f02832b00536b00508b00510202808b00536b00532e32c", + "0xc602800700536b00500700530702833000536b005330005092028369005", + "0x36b00532b0052c802832f00536b00532f0050c002801700536b005017005", + "0x285a802800a00536b0050285a702832b32f01700733036904f00532b005", + "0xb00536b00500b00501b02800a00536b00500a00501b02800b00536b005", + "0x503102802836b0050280070280286ad04f00536b00700b00a0072db028", + "0x536b00504f0055a902804f00536b00504f0050ea02809200536b005005", + "0x501000501b0281c800536b0050285ab02801000536b0050285aa02800f", + "0x2809200536b0050920050920281c800536b0051c800501b02801000536b", + "0x9200503102802836b0050280070280286ae04e00536b0071c80100072db", + "0x1400536b00504e0055a902804e00536b00504e0050ea02801300536b005", + "0x55ac02801300536b00501300509202804d01400736b005014005372028", + "0x536b00501300503102802836b0050280070280300056af02836b00704d", + "0x55ad02836900536b00501700509202801800536b0050280050da028017", + "0x55af02802836b0050280070280286b000502804d02836800536b005014", + "0x2801c00536b0050282da02801b00536b00501300503102802836b005014", + "0x36701c02800a0ee02836700536b00536700501b02836700536b0050285b0", + "0x36b00501b00509202801f00536b00501f0055b102801f36600736b005030", + "0x286b102000536b00701f0055b302836600536b0053660050da02801b005", + "0x36b0050200055a902836500536b00501b00503102802836b005028007028", + "0x5ad02836900536b00536500509202801800536b0053660050da028364005", + "0x3102802836b0050280070280286b000502804d02836800536b005364005", + "0x536b0053660050da02802d00536b0050285b402802300536b00501b005", + "0x537202836800536b00502d0055ad02836900536b005023005092028018", + "0x50280070280c00056b202836b0073630055ac02836336800736b005368", + "0x509202808400536b00536900503102802836b0053680055af02802836b", + "0x280286b300502804d0281aa00536b00500f0055ad02836100536b005084", + "0x536b00535f00509202835f00536b00536900503102802836b005028007", + "0x55b502802836b0050280070280320056b402836b00700f0055ac02835f", + "0x36100536b00535d00509202835d00536b00535f00503102802836b0050c0", + "0x2836b0050280070280286b300502804d0281aa00536b0053680055ad028", + "0x36b0050282da02836c00536b00535f00503102802836b0053680055af028", + "0x2800c00536b00500c0055b102800c00536b0050c00330075b6028033005", + "0x36c00509202803c00536b00503c0055b102803c00536b00503200c0075b6", + "0x2836b0050280070280286b503600536b00703c0055b302836c00536b005", + "0x4000509202835e00536b0050360055a902804000536b00536c005031028", + "0x70280286b300502804d0281aa00536b00535e0055ad02836100536b005", + "0x2835600536b0050285b402835900536b00536c00503102802836b005028", + "0x71aa0055ac0281aa00536b0053560055ad02836100536b005359005092", + "0x3102802836b00503100532102802836b0050280070282150056b602836b", + "0x4800536b00502824502804600536b00502802002821c00536b005361005", + "0x2802302804700536b00504804600736402804800536b00504800501b028", + "0x536b00523700510202823700536b00504704500702d02804500536b005", + "0x50c002821c00536b00521c00509202801800536b0050180050da028239", + "0x2823900721c01800a00523900536b0052390052c802800700536b005007", + "0x736b00521500537102823b00536b00536100503102802836b005028007", + "0x33a02824c24900736b0052490055a302824900536b0050285b702824523f", + "0x736b00524e00535d02824e00536b00502803202824d00536b00524c005", + "0x8802824f00536b00524f00503302823b00536b00523b00509202824f24e", + "0x6b705025200736b00723f24d24f00723b00b00c02824d00536b00524d005", + "0x3102825200536b00525200509202802836b00502800702805805b009031", + "0x536b0052490055b802805c00536b00502837302805900536b005252005", + "0x3302805900536b00505900509202825c00536b00505c2490075a4028249", + "0x24e05005900b00c02825c00536b00525c00508802824e00536b00524e005", + "0x9202802836b00502800702805f06005e0316b825e25d00736b00724525c", + "0x536b00502803002805d00536b00525d00503102825d00536b00525d005", + "0xda02804200536b0052980050f902829800536b0052960310070fb028296", + "0x36b00525e0050c002805d00536b00505d00509202801800536b005018005", + "0x502800702804225e05d01800a00504200536b0050420052c802825e005", + "0x503102805e00536b00505e00509202802836b00503100532102802836b", + "0x536b0050600050c00282bd00536b00506700509202806700536b00505e", + "0x36b0050280070280286b900502804d02806800536b00505f005215028069", + "0x52490055a502802836b00524500501f02802836b005031005321028028", + "0x503102800900536b00500900509202802836b00524e00521c02802836b", + "0x536b00505b0050c00282bd00536b00500600509202800600536b005009", + "0x6f00702d02806f00536b00502802302806800536b005058005215028069", + "0x536b0050180050da02832500536b00507100510202807100536b005068", + "0x52c802806900536b0050690050c00282bd00536b0052bd005092028018", + "0x55af02802836b0050280070283250692bd01800a00532500536b005325", + "0x2807400536b00509200503102802836b00503100532102802836b00500f", + "0x536b00507700501b02807700536b00502824502807500536b005028020", + "0x702d02834b00536b00502802302834c00536b005077075007364028077", + "0x36b0050280050da02807a00536b00504300510202804300536b00534c34b", + "0x2c802800700536b0050070050c002807400536b005074005092028028005", + "0x32102802836b00502800702807a00707402800a00507a00536b00507a005", + "0x7f00536b00502802002807900536b00500500503102802836b005031005", + "0x34807f00736402834800536b00534800501b02834800536b005028245028", + "0x34600536b00508107d00702d02807d00536b00502802302808100536b005", + "0x7900509202802800536b0050280050da02834500536b005346005102028", + "0x34500536b0053450052c802800700536b0050070050c002807900536b005", + "0x100316ba00f09204f03136b00703100500714602834500707902800a005", + "0x4f00503102804f00536b00504f00509202802836b00502800702804e1c8", + "0x1400536b00500f00514a02800f00536b00500f00514802801300536b005", + "0x2802836b00504d0055b902836901801703004d00b36b00501400514b028", + "0x2836b00536900501f02802836b00501800525d02802836b00501700525d", + "0x502859902836800536b00503000515102803000536b005030005156028", + "0x36636700736b00501c00559b02801c00536b00501b00559a02801b00536b", + "0x501f0051c802801f00536b00536600559d02802836b00536700559c028", + "0x2000536b00502000501b02836500b00736b00500b0050dc02802000536b", + "0x2802300536b00502300501b02802336400736b0053650200070310e3028", + "0x55a00280c000536b00536300559f02836302d00736b00502302800759e", + "0x536b0053610055a202802836b0050840055a102836108400736b0050c0", + "0x33a02803235f00736b00535f0055a302835f00536b0051aa00510c0281aa", + "0x736b00536c00535d02836c00536b00502803202835d00536b005032005", + "0x31e02803300536b00503300503302801300536b00501300509202803336c", + "0x36b00502d00504f02836400536b0053640050c602836800536b005368005", + "0x35935e0400316bb03603c00c03136b00735d03309201300a03c02802d005", + "0x36b00500c00503102800c00536b00500c00509202802836b005028007028", + "0x9202821c00536b00521535f0075a402821500536b005028373028356005", + "0x36b00521c00508802836c00536b00536c00503302835600536b005356005", + "0x3136b00721c36c03c35600a03c02803600536b00503600501b02821c005", + "0x36b00504600509202802836b0050280070282392370450316bc047048046", + "0x24924523f01436b0053680052a302823b00536b005046005031028046005", + "0x525d02802836b00523f00501f02805905805b00905025224f24e24d24c", + "0x1f02802836b00524d00501f02802836b00524900530f02802836b005245", + "0x2802836b00525200513f02802836b00524f00501f02802836b00524e005", + "0x2836b00505b00521c02802836b00500900523702802836b00505000530f", + "0x36b00524c0052ca02802836b00505900523702802836b00505800521c028", + "0x2804800536b0050480050c002825c00536b00505c00500a02805c24c007", + "0x725c00500f02823b00536b00523b00509202804700536b00504700501b", + "0x2836b00525d00501c02802836b00502800702805e0056bd25e25d00736b", + "0x50280e102805f00536b00525e00501002806000536b00523b005031028", + "0x2805d00536b00505d00503302829600536b00524c00500a02805d00536b", + "0x29602d0315ba02805f00536b00505f00501b02806000536b005060005092", + "0x506000503102802836b0050280070280670056be04229800736b00705d", + "0x2806900536b00504200501002804200536b0050420055bb0282bd00536b", + "0x36b00500600559b02800600536b00506800559a02806800536b005028599", + "0x1c802832500536b00507100559d02802836b00506f00559c02807106f007", + "0xb0743640310e302807400536b00507400501b02807400536b005325005", + "0x36b00507729800759e02807700536b00507700501b02807707500736b005", + "0x7a00536b00504300533a02804334b00736b00534b0055a302834b34c007", + "0x2803202807f00536b0050790360072e002807900536b00505f0051c8028", + "0x536b0052bd00509202808134800736b00534800535d02834800536b005", + "0x501b02807f00536b00507f00501b02808100536b0050810050330282bd", + "0x536b00534c00504f02807500536b0050750050c602806900536b005069", + "0x283433443450316bf34607d00736b00707f07a0810482bd00b00c02834c", + "0x536b00507d00503102807d00536b00507d00509202802836b005028007", + "0x51c802833d00536b00534134b0075a402834100536b005028373028342", + "0x36b00534200509202833c00536b00508c0470072e002808c00536b005069", + "0x1b02833d00536b00533d00508802834800536b005348005033028342005", + "0x6c008a33b00736b00733c33d34834634200b00c02833c00536b00533c005", + "0x3102833b00536b00533b00509202802836b00502800702808833933a031", + "0x36b00533700a0070fb02833700536b00502803002833800536b00533b005", + "0x9202834c00536b00534c00504f02808600536b0053360050f9028336005", + "0x36b00508a0050c002807500536b0050750050c602833800536b005338005", + "0x2800702808608a07533834c00b00508600536b0050860052c802808a005", + "0x3102833a00536b00533a00509202802836b00500a00532102802836b005", + "0x36b0053390050c002837700536b00508e00509202808e00536b00533a005", + "0x50280070280286c100502804d02833200536b005088005215028333005", + "0x6900501f02802836b00534b0055a502802836b00500a00532102802836b", + "0x509202802836b00504700501f02802836b00534800521c02802836b005", + "0x536b00533100509202833100536b00534500503102834500536b005345", + "0x2802302833200536b00534300521502833300536b0053440050c0028377", + "0x536b00532f00510202832f00536b00533233000702d02833000536b005", + "0x50c602837700536b00537700509202834c00536b00534c00504f02832e", + "0x536b00532e0052c802833300536b0053330050c002807500536b005075", + "0x36b00503600501f02802836b00502800702832e33307537734c00b00532e", + "0x500b00501f02802836b00505f00501f02802836b00500a005321028028", + "0x2802002832d00536b00506000503102802836b00504700501f02802836b", + "0x2808b00536b00508b00501b02808b00536b00502825602832c00536b005", + "0x32b32a00702d02832a00536b00502802302832b00536b00508b32c007364", + "0x6700536b00506700504f02832600536b00532900510202832900536b005", + "0x480050c002836400536b0053640050c602832d00536b00532d005092028", + "0x2832604836432d06700b00532600536b0053260052c802804800536b005", + "0x2802836b00503600501f02802836b00505e00501c02802836b005028007", + "0x2836b00504700501f02802836b00500b00501f02802836b00500a005321", + "0x36b00502802002808500536b00523b00503102802836b00524c005237028", + "0x736402809500536b00509500501b02809500536b005028256028093005", + "0x36b00532409800702d02809800536b00502802302832400536b005095093", + "0x9202802d00536b00502d00504f02809600536b005323005102028323005", + "0x36b0050480050c002836400536b0053640050c602808500536b005085005", + "0x2800702809604836408502d00b00509600536b0050960052c8028048005", + "0x532302802836b00500a00532102802836b00503600501f02802836b005", + "0x2804500536b00504500509202802836b00500b00501f02802836b005368", + "0x52370050c002832100536b00532200509202832200536b005045005031", + "0x280070280286c200502804d02831e00536b00523900521502831f00536b", + "0x532302802836b00500a00532102802836b00536c00521c02802836b005", + "0x9202802836b00535f0055a502802836b00500b00501f02802836b005368", + "0x36b00531d00509202831d00536b00504000503102804000536b005040005", + "0x2302831e00536b00535900521502831f00536b00535e0050c0028321005", + "0x36b00531b00510202831b00536b00531e31c00702d02831c00536b005028", + "0xc602832100536b00532100509202802d00536b00502d00504f02831a005", + "0x36b00531a0052c802831f00536b00531f0050c002836400536b005364005", + "0x500a00532102802836b00502800702831a31f36432102d00b00531a005", + "0x503102801000536b00501000509202802836b00500b00501f02802836b", + "0x536b00504e31800702d02831800536b00502802302831900536b005010", + "0x509202802800536b00502800504f02831600536b005317005102028317", + "0x536b0051c80050c002800700536b0050070050c602831900536b005319", + "0x50285bc0283161c800731902800b00531600536b0053160052c80281c8", + "0x2837602804e00536b0050285be02801000536b0050285bd02809200536b", + "0x50285bf02802836b00502836902802836b00502824c02801400536b005", + "0x285c002801700536b0050285c002803000536b0050285c002804d00536b", + "0x53690055c202836900536b00501801703004d00a5c102801800536b005", + "0x2802836b0050280070280286c336800536b0073690055c302836900536b", + "0x50285c502836701c00736b0050310055c402801b00536b00500a005031", + "0x5c602802000536b0050285c002801f00536b0053660055c602836600536b", + "0x536b0053640055c602836400536b0050285c002836500536b005020005", + "0x1f00a5c702836300536b00502d0055c602802d00536b0050285c0028023", + "0x50c00055c902836700536b0053670055c80280c000536b005363023365", + "0x2801c00536b00501c0050db02801b00536b00501b0050920280c000536b", + "0x55ca02802836b0050280070283610056c408400536b0070c0367007370", + "0x32102802836b00504e0055cc02802836b0050100055cb02802836b005084", + "0x2802836b0050140055ce02802836b0050920055cd02802836b00500b005", + "0x536b0050280200281aa00536b00501b00503102802836b0053680055d0", + "0x35f00736402803200536b00503200501b02803200536b0050285d102835f", + "0x536b00535d36c00702d02836c00536b00502802302835d00536b005032", + "0x52f602802800536b00502800504f02800c00536b005033005102028033", + "0x536b00501c0050db02800700536b0050070052e902800500536b005005", + "0x2804f00500c00536b00500c0052c80281aa00536b0051aa00509202801c", + "0x2803c00536b00501b00503102802836b00502800702800c1aa01c007005", + "0x536b0050285c002804000536b0050360055c602803600536b0050285d2", + "0x3560055c602835600536b0050285c002835900536b00535e0055c602835e", + "0x2804600536b00521c0055c602821c00536b0050285c002821500536b005", + "0x9202804800536b0050480055c902804800536b00504621535904000a5c7", + "0x70280450056c504700536b00704836100737002803c00536b00503c005", + "0x2823900536b0050285d402823700536b00503c00503102802836b005028", + "0x536b00523b0055d702823f00536b0050285d602823b00536b0050285d5", + "0x925d902823700536b00523700509202823f00536b00523f0055d802823b", + "0x2824e24d24c24900a6c624501304f03136b00723f23b368047239007005", + "0x736b0052450055da02824f00536b00523700503102802836b005028007", + "0x736f02804f00536b00504f0920075db02802836b00502800b028050252", + "0x36b0070500055dc02824f00536b00524f00509202801300536b005013014", + "0x2805800536b00524f00503102802836b00502800702805b0056c7009005", + "0x702805c0056c805900536b0070090055dd02805800536b005058005092", + "0x25c00536b00525c00509202825c00536b00505800503102802836b005028", + "0x503102802836b00502800702825e0056c925d00536b0070590055de028", + "0x536b00505e00509202806000536b00525d0055df02805e00536b00525c", + "0x36b0050280070280286ca00502804d02805d00536b0050600055e002805f", + "0x55e002805f00536b00529600509202829600536b00525c005031028028", + "0x503102802836b0050280070280286ca00502804d02805d00536b00525e", + "0x536b00505c0055e002805f00536b00529800509202829800536b005058", + "0x536b00524f00503102802836b0050280070280286ca00502804d02805d", + "0x2836902805d00536b00505b0055e002805f00536b005042005092028042", + "0x6700736b00525200536e0281c800536b00505d01c0075e102802836b005", + "0x36b0050285c002806900536b0050285d202802836b0050670055e20282bd", + "0x6900a5e302806f00536b0050285c002800600536b0050285c0028068005", + "0x3250055e202807432500736b00507100536e02807100536b00506f006068", + "0x2807400536b0050740055e40282bd00536b0052bd0055e402802836b005", + "0x50fc0281c800536b0051c804e0075e602807500536b0050742bd0075e5", + "0x36b00507700504702802836b00502800702834c0056cb07700536b007075", + "0x50285e702834b00536b00505f00503102802836b00500b005321028028", + "0x285e802807900536b00502803202807a00536b00502823b02804300536b", + "0x536b00507907a04303137802834800536b0050285e902807f00536b005", + "0x501b02808100536b0050810055ea02802800536b00502800504f028081", + "0x34807f08102800a5eb02834800536b00534800503302807f00536b00507f", + "0x536b0073460055ec02834b00536b00534b00509202834607d00736b005", + "0x5ed02834300536b00534b00503102802836b0050280070283440056cc345", + "0x536b0050285ee02802836b00534100504702834134200736b005345005", + "0x3420055ea02807d00536b00507d00504f02808c00536b0050285e902833d", + "0x8c00536b00508c00503302833d00536b00533d00501b02834200536b005", + "0x34300536b00534300509202833b33c00736b00508c33d34207d00a5eb028", + "0x503102802836b00502800702833a0056cd08a00536b00733b0055ec028", + "0x36b00533800504702833808800736b00508a0055ed02833900536b005343", + "0x533c00504f02833600536b0050285e902833700536b0050285ef028028", + "0x2833700536b00533700501b02808800536b0050880055ea02833c00536b", + "0x2808e08600736b00533633708833c00a5eb02833600536b005336005033", + "0x70283330056ce37700536b00708e0055ec02833900536b005339005092", + "0x33100736b0053770055ed02833200536b00533900503102802836b005028", + "0x36b0050282f302832f00536b0050285f002802836b005330005047028330", + "0x1b02833100536b0053310055ea02808600536b00508600504f02832e005", + "0x32f33108600a5eb02832e00536b00532e00503302832f00536b00532f005", + "0x36b00732c0055ec02833200536b00533200509202832c32d00736b00532e", + "0x2832a00536b00533200503102802836b00502800702832b0056cf08b005", + "0x536b00532600501b02832600536b0050285f102832900536b005028020", + "0x2809300f00736b00508b0055ed02808500536b005326329007364028326", + "0x500f0055f302800f00536b00500f0100075f202802836b005093005047", + "0x9832400736b00532400536d02802836b0050950055f502832409500736b", + "0x521c02802836b00509600501f02832209632303136b0050980055f6028", + "0x536b0053210055f902832132300736b0053230055f802802836b005322", + "0x736402831e00536b00531e00501b02831e00536b00531f00507402831f", + "0x36b00532d00504f02831c00536b0053230055fa02831d00536b00531e085", + "0x21502831c00536b00531c0055fb02832a00536b00532a00509202832d005", + "0x2831931a31b03136b00531d31c32a32d00a5fc02831d00536b00531d005", + "0x50280070283170056d031800536b00731900500602802836b00502800b", + "0x2831331400736b00531800506f02831600536b00531a00503102802836b", + "0x53110055f602831132400736b00532400536d02802836b005313005047", + "0x2802836b0050b000521c02802836b0050a90055fe0280b03100a903136b", + "0x3240055f602830f00536b0050ac3140073640280ac00536b0053100051c8", + "0x2836b0050b400501f02802836b00530d0055fe0280b60b430d03136b005", + "0x30f0073640280b900536b00530b00507402830b00536b0050b6005172028", + "0x536b00530900521502830800536b00531600509202830900536b0050b9", + "0x2836b0053240055ff02802836b0050280070280286d100502804d028307", + "0x534c0280bf30500736b00531700507702830600536b00531a005031028", + "0x30700536b0050bf00521502830800536b00530600509202802836b005305", + "0x36b00530730400702d02830400536b00502802302802836b005028369028", + "0x2f602831b00536b00531b00504f02830200536b005303005102028303005", + "0x36b0051c80050db02801300536b0050130052e902804f00536b00504f005", + "0x4f00530200536b0053020052c802830800536b0053080050920281c8005", + "0x2802836b0050100055cb02802836b0050280070283023081c801304f31b", + "0x532d00504f02839300536b00532b00510202805100536b005332005031", + "0x2801300536b0050130052e902804f00536b00504f0052f602832d00536b", + "0x53930052c802805100536b0050510050920281c800536b0051c80050db", + "0x55cb02802836b0050280070283930511c801304f32d04f00539300536b", + "0x39500536b00533300510202839400536b00533900503102802836b005010", + "0x130052e902804f00536b00504f0052f602808600536b00508600504f028", + "0x39400536b0053940050920281c800536b0051c80050db02801300536b005", + "0x50280070283953941c801304f08604f00539500536b0053950052c8028", + "0x51020280dc00536b00534300503102802836b0050100055cb02802836b", + "0x536b00504f0052f602833c00536b00533c00504f02839600536b00533a", + "0x50920281c800536b0051c80050db02801300536b0050130052e902804f", + "0xdc1c801304f33c04f00539600536b0053960052c80280dc00536b0050dc", + "0x36b00534b00503102802836b0050100055cb02802836b005028007028396", + "0x2f602807d00536b00507d00504f0280c600536b0053440051020280c7005", + "0x36b0051c80050db02801300536b0050130052e902804f00536b00504f005", + "0x4f0050c600536b0050c60052c80280c700536b0050c70050920281c8005", + "0x2802836b00534c00504702802836b0050280070280c60c71c801304f07d", + "0x536b0050280300280c900536b00505f00503102802836b0050100055cb", + "0x4f02830100536b0050cf0050f90280cf00536b0050cb00b0070fb0280cb", + "0x36b0050130052e902804f00536b00504f0052f602802800536b005028005", + "0x2c80280c900536b0050c90050920281c800536b0051c80050db028013005", + "0x2836b0050280070283010c91c801304f02804f00530100536b005301005", + "0x36b00504e0055cc02802836b0050100055cb02802836b00524d005600028", + "0x50140055ce02802836b0050920055cd02802836b00500b005321028028", + "0x2860102830c00536b00502802002839700536b00523700503102802836b", + "0x536b00539830c00736402839800536b00539800501b02839800536b005", + "0x524c0052e90282fa00536b0050285d60280d400536b0050285d50282fb", + "0x282fa00536b0052fa0055d80280d400536b0050d40055d702824c00536b", + "0x2802836b00502800b0282f83990d503136b0052fa0d424e24c01c00b602", + "0x52fb00521502839700536b00539700509202824900536b0052490052f6", + "0x2839900536b0053990052e90280d500536b0050d50050db0282fb00536b", + "0x39700503102802836b0050280070282f10056d22f700536b0072f80055dc", + "0x2ee00536b0072f70055dd0280da00536b0050da0050920280da00536b005", + "0x50920280d200536b0050da00503102802836b0050280070282ec0056d3", + "0x50280070280db0056d42ef00536b0072ee0055de0280d200536b0050d2", + "0x920282e900536b0052ef0055df0282f600536b0050d200503102802836b", + "0x286d500502804d0282e700536b0052e90055e00282e800536b0052f6005", + "0x36b0050df0050920280df00536b0050d200503102802836b005028007028", + "0x50280070280286d500502804d0282e700536b0050db0055e00282e8005", + "0x5e00282e800536b0052f50050920282f500536b0050da00503102802836b", + "0x3102802836b0050280070280286d500502804d0282e700536b0052ec005", + "0x36b0052f10055e00282e800536b0050e10050920280e100536b005397005", + "0x280230282f300536b0052e70d50075e102802836b0050283690282e7005", + "0x536b0050e30051020280e300536b0052fb2f200702d0282f200536b005", + "0x52e902824900536b0052490052f602802800536b00502800504f0282f4", + "0x536b0052e80050920282f300536b0052f30050db02839900536b005399", + "0x280070282f42e82f339924902804f0052f400536b0052f40052c80282e8", + "0x55cc02802836b0050100055cb02802836b00504500560302802836b005", + "0x5ce02802836b0050920055cd02802836b00500b00532102802836b00504e", + "0x2e000536b00503c00503102802836b0053680055d002802836b005014005", + "0x36b0052dd00501b0282dd00536b0050286050282de00536b005028020028", + "0x2d0282db00536b0050280230281a600536b0052dd2de0073640282dd005", + "0x502800504f0282d700536b0052da0051020282da00536b0051a62db007", + "0x2800700536b0050070052e902800500536b0050050052f602802800536b", + "0x52d70052c80282e000536b0052e000509202801c00536b00501c0050db", + "0x55cb02802836b0050280070282d72e001c00700502804f0052d700536b", + "0x5cd02802836b00500b00532102802836b00504e0055cc02802836b005010", + "0xea00536b00500a00503102802836b0050140055ce02802836b005092005", + "0x36b0052d600501b0282d600536b0050282450280ee00536b005028020028", + "0x2d0282d300536b0050280230282d400536b0052d60ee0073640282d6005", + "0x502800504f0282d100536b0052d20051020282d200536b0052d42d3007", + "0x2800700536b0050070052e902800500536b0050050052f602802800536b", + "0x52d10052c80280ea00536b0050ea00509202803100536b0050310050db", + "0x700500736b0050280056060282d10ea03100700502804f0052d100536b", + "0x36b0050285c002800a00536b0050310055c602803100536b0050285c5028", + "0x55c602809200536b0050285c002804f00536b00500b0055c602800b005", + "0x1c800536b0050100055c602801000536b0050285c002800f00536b005092", + "0x2800700536b00500700560702804e00536b0051c800f04f00a00a5c7028", + "0x4e00700760802800500536b0050050050db02804e00536b00504e0055c9", + "0x2836b00501300560902802836b0050280070280140056d601300536b007", + "0x2802836b00501400560b02802836b0050280070280286d700502804d028", + "0x36b00503000529702803000536b00504d00517402804d00536b005028030", + "0x700501700536b00501700514302800500536b0050050050db028017005", + "0x3136b00704f00502803132e02804f03100736b005031005396028017005", + "0x36b00509200509202802836b00502800702801304e1c80316d801000f092", + "0x533a02804d00536b00502860c02801400536b005092005031028092005", + "0x2801800536b00502803202801700536b00502860d02803000536b00504d", + "0x503000508802801800536b00501800503302801400536b005014005092", + "0x2801000536b00501000533d02801700536b00501700501b02803000536b", + "0x2800702836701c01b0316d936836900736b00701703001800f01400b00c", + "0x2836600536b00536900503102836900536b00536900509202802836b005", + "0x502000535e02802836b00501f00504002802001f00736b00500b005036", + "0xa00736b00500a0050dc02836403100736b00503100539602836500536b", + "0x3136b00736502336436836600b25e02836600536b005366005092028023", + "0x36b0050c000523702802836b0050280070281aa3610840316da0c036302d", + "0x503100525d02802836b00501000534302802836b005007005321028028", + "0x503102802d00536b00502d00509202802836b00500a00501f02802836b", + "0x2835d00536b0050285f102803200536b00502802002835f00536b00502d", + "0x502823b02836c00536b00535d03200736402835d00536b00535d00501b", + "0xc00536b00503336c00736402803300536b00503300501b02803300536b", + "0x3c00c00736402803c00536b00503c00501b02803c00536b00502860e028", + "0x2804000536b00504000501b02804000536b00502823902803600536b005", + "0x35e35900702d02835900536b00502802302835e00536b005040036007364", + "0x35f00536b00535f00509202821500536b00535600510202835600536b005", + "0x36335f03100521500536b0052150052c802836300536b0053630050c0028", + "0x508400503102808400536b00508400509202802836b005028007028215", + "0x2802836b00504600504002804804600736b0051aa00503602821c00536b", + "0x521c00509202836100536b0053610050c002804800536b005048005013", + "0x36b0050280070282370056db04504700736b00704800561002821c00536b", + "0x501002804500536b0050450055bb02823900536b00521c005031028028", + "0x24500536b00502861102823f00536b00523b0051c802823b00536b005045", + "0x501b02824900536b00524523f00732c02823f00536b00523f00501b028", + "0x536b00523900509202804700536b00504700501302824900536b005249", + "0x503102802836b00502800702824c0056dc02836b007249005348028239", + "0x736b00704700561002824d00536b00524d00509202824d00536b005239", + "0x3102802836b00524e00501c02802836b0050280070282520056dd24f24e", + "0x36b00524f00501002824f00536b00524f0055bb02805000536b00524d005", + "0x50dc02805800536b00502861202805b00536b0050090051c8028009005", + "0x505c00501b02805c00536b00505805900732c02805900a00736b00500a", + "0x2805b00536b00505b00501b02805000536b00505000509202805c00536b", + "0x500a00501f02802836b00502800702825c0056de02836b00705c005348", + "0x732c02825e00536b00502861402825d00536b00505000503102802836b", + "0x36b00525d00509202805e00536b00505e00501b02805e00536b00525e05b", + "0x3102802836b0050280070280600056df02836b00705e00534802825d005", + "0x286e000502804d02805d00536b00505f00509202805f00536b00525d005", + "0x2836b00500700532102802836b00506000534602802836b005028007028", + "0x36b00525d00503102802836b00503100525d02802836b005010005343028", + "0x4200501b02804200536b00502861502829800536b005028020028296005", + "0x2bd00536b00502802302806700536b00504229800736402804200536b005", + "0x509202806800536b00506900510202806900536b0050672bd00702d028", + "0x536b0050680052c802836100536b0053610050c002829600536b005296", + "0x2802836b00525c00534602802836b005028007028068361296031005068", + "0x36b00500a0050dc02806f00536b00502810102800600536b005050005031", + "0x32500536b00532500501b02832500536b00506f07100732c02807100a007", + "0x70280740056e102836b00732500534802800600536b005006005092028", + "0x2807500536b00500600503102802836b00500a00501f02802836b005028", + "0x534c00501b02834c00536b00507705b00732c02807700536b0050282c7", + "0x56e202836b00734c00534802807500536b00507500509202834c00536b", + "0x504300509202804300536b00507500503102802836b00502800702834b", + "0x534b00534602802836b0050280070280286e300502804d02807a00536b", + "0x3100525d02802836b00501000534302802836b00500700532102802836b", + "0x61502807f00536b00502802002807900536b00507500503102802836b005", + "0x36b00534807f00736402834800536b00534800501b02834800536b005028", + "0x10202834600536b00508107d00702d02807d00536b005028023028081005", + "0x36b0053610050c002807900536b00507900509202834500536b005346005", + "0x36b00502800702834536107903100534500536b0053450052c8028361005", + "0x502861602834400536b00500600503102802836b005074005346028028", + "0x34200536b00534200501b02834200536b00534300a00732c02834300536b", + "0x70283410056e402836b00734200534802834400536b005344005092028", + "0x2808c00536b00502833602833d00536b00534400503102802836b005028", + "0x33d00509202833c00536b00533c00501b02833c00536b00508c05b00732c", + "0x2836b00502800702833b0056e502836b00733c00534802833d00536b005", + "0x7a00539802807a00536b00508a00509202808a00536b00533d005031028", + "0x3373380316e608833933a03136b00703136105d03132e02805d00536b005", + "0x533a00503102833a00536b00533a00509202802836b005028007028336", + "0x10a02837700536b00508e0052c502808e00536b00502808a02808600536b", + "0x36b00533200510902802836b00533300510b02833233300736b005377005", + "0x3202832f00536b00533000533a02833000536b00533100510c028331005", + "0x536b00532e00503302808600536b00508600509202832e00536b005028", + "0xa03c02808800536b00508800533d02832f00536b00532f00508802832e", + "0x36b00502800702832932a32b0316e708b32c32d03136b00732f32e339086", + "0x501b02832600536b00532d00503102832d00536b00532d005092028028", + "0x536b00532600509202832c00536b00532c0050c002808b00536b00508b", + "0x503102802836b0050280070280850056e802836b00708b005348028326", + "0x536b00508800532d02809500536b00501000532d02809300536b005326", + "0x9202809800536b00509800501b02809800536b00532409500732c028324", + "0x50280070283230056e902836b00709800534802809300536b005093005", + "0x52c502832200536b00502860c02809600536b00509300503102802836b", + "0x36b00531f00510b02831e31f00736b00532100510a02832100536b005322", + "0x533a02831c00536b00531d00510c02831d00536b00531e005109028028", + "0x9600536b00509600509202831a00536b00502803202831b00536b00531c", + "0x9600a03c02831b00536b00531b00508802831a00536b00531a005033028", + "0x2836b0050280070283133143160316ea31731831903136b00731b31a32c", + "0x502860d02831100536b00531900503102831900536b005319005092028", + "0x31000536b0050a931700732c02831700536b00531700501b0280a900536b", + "0x31100509202831800536b0053180050c002831000536b00531000501b028", + "0x2836b0050280070280b00056eb02836b00731000534802831100536b005", + "0x30f0070070fb02830f00536b0050280300280ac00536b005311005031028", + "0xac00536b0050ac0050920280b400536b00530d0050f902830d00536b005", + "0x3180ac0310050b400536b0050b40052c802831800536b0053180050c0028", + "0x36b00500700532102802836b0050b000534602802836b0050280070280b4", + "0x502861702830b00536b0050280200280b600536b005311005031028028", + "0x30900536b0050b930b0073640280b900536b0050b900501b0280b900536b", + "0x30700510202830700536b00530930800702d02830800536b005028023028", + "0x31800536b0053180050c00280b600536b0050b600509202830600536b005", + "0x2802836b0050280070283063180b603100530600536b0053060052c8028", + "0x36b00531600503102831600536b00531600509202802836b005007005321", + "0x10202830400536b0053130bf00702d0280bf00536b005028023028305005", + "0x36b0053140050c002830500536b00530500509202830300536b005304005", + "0x36b00502800702830331430503100530300536b0053030052c8028314005", + "0x509300503102802836b00500700532102802836b005323005346028028", + "0x501b02839300536b00502861802805100536b00502802002830200536b", + "0x536b00502802302839400536b00539305100736402839300536b005393", + "0x9202839600536b0050dc0051020280dc00536b00539439500702d028395", + "0x36b0053960052c802832c00536b00532c0050c002830200536b005302005", + "0x2836b00508500534602802836b00502800702839632c302031005396005", + "0x36b00508800534302802836b00501000534302802836b005007005321028", + "0x50286190280c600536b0050280200280c700536b005326005031028028", + "0xcb00536b0050c90c60073640280c900536b0050c900501b0280c900536b", + "0x30100510202830100536b0050cb0cf00702d0280cf00536b005028023028", + "0x32c00536b00532c0050c00280c700536b0050c700509202839700536b005", + "0x2802836b00502800702839732c0c703100539700536b0053970052c8028", + "0x2836b00501000534302802836b00508800534302802836b005007005321", + "0x502802302830c00536b00532b00503102832b00536b00532b005092028", + "0xd400536b0052fb0051020282fb00536b00532939800702d02839800536b", + "0xd40052c802832a00536b00532a0050c002830c00536b00530c005092028", + "0x500700532102802836b0050280070280d432a30c0310050d400536b005", + "0x503102833800536b00533800509202802836b00501000534302802836b", + "0x536b0053360d500702d0280d500536b0050280230282fa00536b005338", + "0x50c00282fa00536b0052fa0050920282f800536b005399005102028399", + "0x70282f83372fa0310052f800536b0052f80052c802833700536b005337", + "0x34302802836b00500700532102802836b00533b00534602802836b005028", + "0x2f700536b00533d00503102802836b00503100525d02802836b005010005", + "0x36b0050da00501b0280da00536b00502861a0282f100536b005028020028", + "0x2d0282ec00536b0050280230282ee00536b0050da2f10073640280da005", + "0x52f70050920282ef00536b0050d20051020280d200536b0052ee2ec007", + "0x52ef00536b0052ef0052c802836100536b0053610050c00282f700536b", + "0x532102802836b00534100534602802836b0050280070282ef3612f7031", + "0x1f02802836b00503100525d02802836b00501000534302802836b005007", + "0x2f600536b0050280200280db00536b00534400503102802836b00505b005", + "0x2e92f60073640282e900536b0052e900501b0282e900536b00502861b028", + "0xdf00536b0052e82e700702d0282e700536b0050280230282e800536b005", + "0x3610050c00280db00536b0050db0050920282f500536b0050df005102028", + "0x280070282f53610db0310052f500536b0052f50052c802836100536b005", + "0x534302802836b00500700532102802836b00525200501c02802836b005", + "0x3102802836b00500a00501f02802836b00503100525d02802836b005010", + "0x2f200536b0050282450282f300536b0050280200280e100536b00524d005", + "0x280230280e300536b0052f22f30073640282f200536b0052f200501b028", + "0x536b0052e00051020282e000536b0050e32f400702d0282f400536b005", + "0x52c802836100536b0053610050c00280e100536b0050e10050920282de", + "0x24c00534602802836b0050280070282de3610e10310052de00536b0052de", + "0x525d02802836b00501000534302802836b00500700532102802836b005", + "0x3102802836b00504700501c02802836b00500a00501f02802836b005031", + "0x2db00536b0050286150281a600536b0050280200282dd00536b005239005", + "0x280230282da00536b0052db1a60073640282db00536b0052db00501b028", + "0x536b0050ea0051020280ea00536b0052da2d700702d0282d700536b005", + "0x52c802836100536b0053610050c00282dd00536b0052dd0050920280ee", + "0x23700501c02802836b0050280070280ee3612dd0310050ee00536b0050ee", + "0x525d02802836b00501000534302802836b00500700532102802836b005", + "0x282d600536b00521c00503102802836b00500a00501f02802836b005031", + "0x536b0052d300501b0282d300536b0050282450282d400536b005028020", + "0x702d0282d100536b0050280230282d200536b0052d32d40073640282d3", + "0x36b0052d60050920282cf00536b0052d00051020282d000536b0052d22d1", + "0x310052cf00536b0052cf0052c802836100536b0053610050c00282d6005", + "0x1000534302802836b00500700532102802836b0050280070282cf3612d6", + "0x504002802836b00500a00501f02802836b00503100525d02802836b005", + "0x2cc00536b00501b00503102801b00536b00501b00509202802836b00500b", + "0xf80051020280f800536b0053670f600702d0280f600536b005028023028", + "0x1c00536b00501c0050c00282cc00536b0052cc0050920282cb00536b005", + "0x2802836b0050280070282cb01c2cc0310052cb00536b0052cb0052c8028", + "0x2836b00503100525d02802836b00500b00504002802836b005007005321", + "0x51c80050310281c800536b0051c800509202802836b00500a00501f028", + "0x280fa00536b0050132c900702d0282c900536b0050280230282ca00536b", + "0x504e0050c00282ca00536b0052ca0050920280fc00536b0050fa005102", + "0x500500a0280fc04e2ca0310050fc00536b0050fc0052c802804e00536b", + "0x502800702800b0056ec00a03100736b00700700500f02800700536b005", + "0x25202809200536b00503100501302804f00536b00500a00524f02802836b", + "0x3002802836b0050280070280286ed00502804d02800f00536b00504f005", + "0x536b00500b0050130281c800536b00501000505002801000536b005028", + "0x35e02804e09200736b00509200507102800f00536b0051c8005252028092", + "0x2800702804d0056ee01400536b00700f00500902801300536b00504e005", + "0x2801700536b0050300051c802803000536b00501400501002802836b005", + "0x3680056ef36901800736b00701702800713802801700536b00501700501b", + "0x1b00536b00502803202802836b00501300523702802836b005028007028", + "0x3302836736900736b00536900535d02801c09200736b005092005071028", + "0x56f001f36600736b00736701b01c01800a61c02801b00536b00501b005", + "0x36500532502836509200736b00509200507102802836b005028007028020", + "0x536b00536400503302802336900736b00536900535d02836400536b005", + "0x36302d00736b00702336436603158e02801f00536b00501f005013028364", + "0x736b00736336909202d00a61c02802836b0050280070280840c00076f1", + "0x2803200536b00501f00535e02802836b00502800702835f0056f21aa361", + "0x35d36c00761e02836c00536b0051aa00535e02835d00536b00503200561d", + "0x36100536b00536100504f02800c00536b00503300561f02803300536b005", + "0x1c02802836b00502800702800c36100700500c00536b00500c005620028", + "0x2803600536b00502825602803c00536b00502802002802836b00501f005", + "0x502802302804000536b00503603c00736402803600536b00503600501b", + "0x35600536b00535900562102835900536b00504035e00702d02835e00536b", + "0x35635f00700535600536b00535600562002835f00536b00535f00504f028", + "0x2836b00501f00501c02802836b00508400521c02802836b005028007028", + "0x536b00502802002802836b00536900521c02802836b00509200501c028", + "0x21500736402821c00536b00521c00501b02821c00536b005028622028215", + "0x536b00504604800702d02804800536b00502802302804600536b00521c", + "0x56200280c000536b0050c000504f02804500536b005047005621028047", + "0x536900521c02802836b0050280070280450c000700504500536b005045", + "0x502825602823700536b00502802002802836b00509200501c02802836b", + "0x23b00536b00523923700736402823900536b00523900501b02823900536b", + "0x24500562102824500536b00523b23f00702d02823f00536b005028023028", + "0x24900536b00524900562002802000536b00502000504f02824900536b005", + "0x2803002802836b00509200501c02802836b005028007028249020007005", + "0x536b00524d01300761e02824d00536b00524c00562302824c00536b005", + "0x562002836800536b00536800504f02824f00536b00524e00561f02824e", + "0x504d00504702802836b00502800702824f36800700524f00536b00524f", + "0x25200562302825200536b00502803002802836b00509200501c02802836b", + "0x536b00500900561f02800900536b00505001300761e02805000536b005", + "0x2800700505b00536b00505b00562002802800536b00502800504f02805b", + "0x920076f304f00b00736b00700502800700502802836b00502836902805b", + "0x500a0050dc02801000536b00504f00503102802836b00502800702800f", + "0x1000536b00501000509202800b00536b00500b00504f0281c800a00736b", + "0xa00501f02802836b00502800702804e0056f402836b0071c8005348028", + "0x2801400536b00503100562402801300536b00501000503102802836b005", + "0xb00504f02803000536b00504d00537a02804d00536b005014007007625", + "0x3000536b00503000562602801300536b00501300509202800b00536b005", + "0x3102802836b00504e00534602802836b00502800702803001300b031005", + "0x36b00500700505b02800b00536b00500b00504f02801700536b005010005", + "0x536b00501700509202836836901803136b00500700b007627028007005", + "0x3102802836b00502800702801c0056f501b00536b007368005628028017", + "0x36b00502823f02836600536b00501b03100762902836700536b005017005", + "0x2801800536b00501800504f02802000536b00501f00a00732c02801f005", + "0x536600512302836900536b00536900505b02836700536b005367005092", + "0x502036636936701800b2b902802000536b00502000501b02836600536b", + "0xa00501f02802836b00502800702802336436503100502336436503136b", + "0x62a02802d00536b00501700503102802836b00503100513102802836b005", + "0x50c000537a0280c000536b00536336900762502836300536b00501c005", + "0x2802d00536b00502d00509202801800536b00501800504f02808400536b", + "0x1f02802836b00502800702808402d01803100508400536b005084005626", + "0x2802836b00500700523702802836b00503100513102802836b00500a005", + "0x536b0050280460281aa00536b00502802002836100536b00500f005031", + "0x2302803200536b00535f1aa00736402835f00536b00535f00501b02835f", + "0x36b00536c00562b02836c00536b00503235d00702d02835d00536b005028", + "0x62602836100536b00536100509202809200536b00509200504f028033005", + "0x700502802836b00502836902803336109203100503300536b005033005", + "0x503102802836b00502800702809204f0076f600b00a00736b007005028", + "0x2802836b00502800b02801000536b00500700500a02800f00536b00500b", + "0x701000500f02800f00536b00500f00509202800a00536b00500a00504f", + "0x536b00500f00503102802836b0050280070280130056f704e1c800736b", + "0x501302803000536b00501400509202804d00536b00504e00524f028014", + "0x280286f800502804d02801800536b00504d00525202801700536b0051c8", + "0x36800536b00502803002836900536b00500f00503102802836b005028007", + "0x1300501302803000536b00536900509202801b00536b005368005050028", + "0x1c00536b00501700535e02801800536b00501b00525202801700536b005", + "0x503102802836b0050280070283660056f936700536b007018005009028", + "0x536b00503100500a02802000536b00536700501002801f00536b005030", + "0x500f02802000536b00502000501b02801f00536b00501f005092028365", + "0x501f00503102802836b00502800702802d0056fa02336400736b007365", + "0x2808400536b00536400535e0280c000536b00502300501002836300536b", + "0x51aa00501b0281aa00536b0050c00051c802836100536b0050200051c8", + "0x35f00536b00535f00501b02835f00536b0051aa36100732c0281aa00536b", + "0x35f00534802808400536b00508400505b02836300536b005363005092028", + "0x3102802836b00502836902802836b0050280070280320056fb02836b007", + "0x36b00535d00509202800a00536b00500a00504f02835d00536b005363005", + "0x29f02808400536b00508400505b02801c00536b00501c00505b02835d005", + "0x502800702800c03336c03100500c03336c03136b00508401c35d00a00a", + "0x536300503102802836b00503200534602802836b00502836902802836b", + "0x37b02804000536b00503600534502803600536b00502803002803c00536b", + "0xa00504f02835900536b00535e00562c02835e00536b00504008401c031", + "0x35900536b00535900562d02803c00536b00503c00509202800a00536b005", + "0x501c02802836b00502836902802836b00502800702835903c00a031005", + "0x3102802836b00501c00523702802836b00502000501f02802836b00502d", + "0x21c00536b00502824502821500536b00502802002835600536b00501f005", + "0x2802302804600536b00521c21500736402821c00536b00521c00501b028", + "0x536b00504700562e02804700536b00504604800702d02804800536b005", + "0x562d02835600536b00535600509202800a00536b00500a00504f028045", + "0x502836902802836b00502800702804535600a03100504500536b005045", + "0x2803002823700536b00503000503102802836b00536600504702802836b", + "0x36b00523b03101c03137b02823b00536b00523900508102823900536b005", + "0x9202800a00536b00500a00504f02824500536b00523f00562c02823f005", + "0x2824523700a03100524500536b00524500562d02823700536b005237005", + "0x2802836b00500700523702802836b00503100523702802836b005028007", + "0x536b00502804602824c00536b00502802002824900536b005092005031", + "0x2302824e00536b00524d24c00736402824d00536b00524d00501b02824d", + "0x36b00525200562e02825200536b00524e24f00702d02824f00536b005028", + "0x62d02824900536b00524900509202804f00536b00504f00504f028050005", + "0x700502802836b00502836902805024904f03100505000536b005050005", + "0x503102802836b00502800702809204f0076fc00b00a00736b007005028", + "0x2802836b00502800b02801000536b00500700516c02800f00536b00500b", + "0x701000562f02800f00536b00500f00509202800a00536b00500a00504f", + "0x536b00500f00503102802836b0050280070280130056fd04e1c800736b", + "0x563202803000536b00501400509202804d00536b00504e005631028014", + "0x280286fe00502804d02801800536b00504d00563302801700536b0051c8", + "0x36800536b00502803002836900536b00500f00503102802836b005028007", + "0x1300563202803000536b00536900509202801b00536b005368005634028", + "0x1c00536b00501700513002801800536b00501b00563302801700536b005", + "0x503102802836b0050280070283660056ff36700536b007018005635028", + "0x536b00503100516c02802000536b00536700563702801f00536b005030", + "0x562f02802000536b00502000563802801f00536b00501f005092028365", + "0x501f00503102802836b00502800702802d00570002336400736b007365", + "0x2808400536b0053640051300280c000536b00502300563702836300536b", + "0x8e02803235f1aa03136b00536100563b02836102000736b005020005639", + "0x35d00536b0051aa0051c802802836b00503200530f02802836b00535f005", + "0x563b02836c0c000736b0050c00056390280c000536b0050c0005638028", + "0x36b00503c00530f02802836b00500c00508e02803c00c03303136b00536c", + "0x1b02804000536b00503635d00732c02803600536b0050330051c8028028", + "0x36b00508400516e02836300536b00536300509202804000536b005040005", + "0x3102802836b00502800702835e00570102836b007040005348028084005", + "0x535600563b02835602000736b00502000563902835900536b005363005", + "0x2802836b00504600530f02802836b00521500501f02804621c21503136b", + "0x4700563b0280470c000736b0050c000563902804800536b00521c005112", + "0x2836b00523900530f02802836b00504500501f02823923704503136b005", + "0x4800711302835900536b00535900509202823b00536b005237005112028", + "0x2802836b00502000563c02802836b00502800702802870202836b00723b", + "0x36b00523f00509202823f00536b00535900503102802836b0050c000563c", + "0x36b00535900503102802836b00502800702802870300502804d028245005", + "0x2802836b00524c00501f02824e24d24c03136b00502000563b028249005", + "0x36b0050c000563b02824f00536b00524e0052f702802836b00524d00508e", + "0x2f702802836b00505000508e02802836b00525200501f028009050252031", + "0x705b24f0072a202824900536b00524900509202805b00536b005009005", + "0x9202805800536b00524900503102802836b00502800702802870402836b", + "0x36902802836b00502800702802870500502804d02805900536b005058005", + "0xa00536b00500a00504f02805c00536b00524900503102802836b005028", + "0x8400516e02801c00536b00501c00516e02805c00536b00505c005092028", + "0x25c03100525e25d25c03136b00508401c05c00a00a29902808400536b005", + "0x50c000563c02802836b00535e00534602802836b00502800702825e25d", + "0x509202805e00536b00536300503102802836b00502000563c02802836b", + "0x2802836b00502836902805900536b00524500539802824500536b00505e", + "0x5f08401c03163d02805f00536b00506000534502806000536b005028030", + "0xa00536b00500a00504f02829600536b00505d00563f02805d00536b005", + "0x5900a03100529600536b00529600564002805900536b005059005092028", + "0x2836b00502d00564102802836b00502836902802836b005028007028296", + "0x36b00501f00503102802836b00501c00513f02802836b00502000563c028", + "0x6700501b02806700536b00502824502804200536b005028020028298005", + "0x6900536b0050280230282bd00536b00506704200736402806700536b005", + "0x504f02800600536b00506800564202806800536b0052bd06900702d028", + "0x536b00500600564002829800536b00529800509202800a00536b00500a", + "0x4702802836b00502836902802836b00502800702800629800a031005006", + "0x7100536b00502803002806f00536b00503000503102802836b005366005", + "0x63f02807400536b00532503101c03163d02832500536b005071005081028", + "0x36b00506f00509202800a00536b00500a00504f02807500536b005074005", + "0x36b00502800702807506f00a03100507500536b00507500564002806f005", + "0x509200503102802836b00503100513f02802836b00500700513f028028", + "0x501b02834b00536b00502804602834c00536b00502802002807700536b", + "0x536b00502802302804300536b00534b34c00736402834b00536b00534b", + "0x4f02807f00536b00507900564202807900536b00504307a00702d02807a", + "0x36b00507f00564002807700536b00507700509202804f00536b00504f005", + "0x36b00700502800700502802836b00502836902807f07704f03100507f005", + "0x536b00500b00503102802836b00502800702809204f00770600b00a007", + "0x500a00504f02802836b00502800b02801000536b00500700564402800f", + "0x4e1c800736b00701000564502800f00536b00500f00509202800a00536b", + "0x564602801400536b00500f00503102802836b005028007028013005707", + "0x536b0051c800564702803000536b00501400509202804d00536b00504e", + "0x36b00502800702802870800502804d02801800536b00504d005648028017", + "0x36800564902836800536b00502803002836900536b00500f005031028028", + "0x1700536b00501300564702803000536b00536900509202801b00536b005", + "0x1800564a02801c00536b00501700527b02801800536b00501b005648028", + "0x2802836b00502836902802836b00502800702836600570936700536b007", + "0x502000537f02802000536b00536700564b02801f00536b005030005031", + "0x2803100536b00503100527802800a00536b00500a00504f02836500536b", + "0x9202802336400736b00536503100a03164c02836500536b005365005197", + "0x2800702836300570a02d00536b00702300527002801f00536b00501f005", + "0x36108400736b00502d00526f0280c000536b00501f00503102802836b005", + "0x50c000509202836400536b00536400504f02802836b005361005047028", + "0x2808400536b00508400527802801c00536b00501c00527a0280c000536b", + "0x2800702803235f1aa03100503235f1aa03136b00508401c0c036400a276", + "0x64d02835d00536b00501f00503102802836b00501c00527302802836b005", + "0x36b00535d00509202836400536b00536400504f02836c00536b005363005", + "0x36b00502800702836c35d36403100536c00536b00536c00564e02835d005", + "0x36b00503000503102802836b00536600504702802836b005028369028028", + "0x2803c00536b00500c03101c03164f02800c00536b005028030028033005", + "0x503300509202800a00536b00500a00504f02803600536b00503c005650", + "0x502800702803603300a03100503600536b00503600564e02803300536b", + "0x9200503102802836b00503100526d02802836b00500700527302802836b", + "0x1b02835900536b00502804602835e00536b00502802002804000536b005", + "0x36b00502802302835600536b00535935e00736402835900536b005359005", + "0x2804600536b00521c00564d02821c00536b00535621500702d028215005", + "0x504600564e02804000536b00504000509202804f00536b00504f00504f", + "0x36b00500700526a02802836b00502836902804604004f03100504600536b", + "0x3302800f00536b00502838002809200536b00504f00565102804f00b007", + "0xf09202803165302800f00536b00500f00565202809200536b005092005", + "0x2802836b00502800b02802836b0051c800521c02804e1c801003136b005", + "0x1300570b02801000536b00501000504f02801300a00736b00500a00535d", + "0x2802836b00500a00521c02802836b00502800702801400570c02836b007", + "0x536b00502802502804d00536b00500500503102802836b00503100508e", + "0x533202801800536b00504d00509202801700536b00501000504f028030", + "0x570e02802836b00502800702802870d00502804d02836900536b005030", + "0x2801b00536b0050280e102836800536b00500500503102802836b005014", + "0x1c0072a002836800536b00536800509202801c00a00736b00500a00535d", + "0x36700536b00536800503102802836b00502800702802870f02836b00701b", + "0x36700509202801f00a00736b00500a00535d02836600536b0050282f3028", + "0x2836b00502800702802871002836b00736601f0072a002836700536b005", + "0x500a00535d02836500536b00502858d02802000536b005367005031028", + "0x2836b0073653640072a002802000536b00502000509202836400a00736b", + "0x502871202802300536b00502000503102802836b005028007028028711", + "0x2300536b00502300509202836300a00736b00500a00535d02802d00536b", + "0x2300503102802836b00502800702802871302836b00702d3630072a0028", + "0x36100a00736b00500a00535d02808400536b0050287140280c000536b005", + "0x702802871502836b0070843610072a00280c000536b0050c0005092028", + "0x2835f00536b0050287160281aa00536b0050c000503102802836b005028", + "0x320072a00281aa00536b0051aa00509202803200a00736b00500a00535d", + "0x35d00536b0051aa00503102802836b00502800702802871702836b00735f", + "0x36c00a0072a002835d00536b00535d00509202836c00536b005028718028", + "0x508e02802836b00502836902802836b00502800702802871902836b007", + "0x3102802836b00504e00521c02802836b00500b00526d02802836b005031", + "0x3c00536b00502871a02800c00536b00502802002803300536b00535d005", + "0x2802302803600536b00503c00c00736402803c00536b00503c00501b028", + "0x536b00535e00571b02835e00536b00503604000702d02804000536b005", + "0x571c02803300536b00503300509202801000536b00501000504f028359", + "0x35d00503102802836b00502800702835903301003100535900536b005359", + "0x2821c00536b00535600509202821500536b00502871d02835600536b005", + "0x2802836b00502800702802871e00502804d02804600536b005215005332", + "0x536b00502871f02804800536b0051aa00503102802836b00500a00521c", + "0x539802804600536b00504700533202821c00536b005048005092028047", + "0x2802872000502804d02823700536b00504600511202804500536b00521c", + "0x23900536b0050c000503102802836b00500a00521c02802836b005028007", + "0x523b00533202804500536b00523900509202823b00536b005028721028", + "0x2824500536b00523700511202823f00536b00504500539802823700536b", + "0x3102802836b00500a00521c02802836b00502800702802872200502804d", + "0x536b00524900509202824c00536b00502872302824900536b005023005", + "0x511202824d00536b00523f00539802824500536b00524c00533202823f", + "0x521c02802836b00502800702802872400502804d02824e00536b005245", + "0x2825200536b00502872502824f00536b00502000503102802836b00500a", + "0x524d00539802824e00536b00525200533202824d00536b00524f005092", + "0x2800702802872600502804d02800900536b00524e00511202805000536b", + "0x72702805b00536b00536700503102802836b00500a00521c02802836b005", + "0x536b00505800533202805000536b00505b00509202805800536b005028", + "0x2804d02805c00536b00500900511202805900536b005050005398028009", + "0x36800503102802836b00500a00521c02802836b005028007028028728005", + "0x2805900536b00525c00509202825d00536b00502872902825c00536b005", + "0x25e00572a02825e05c00736b00505c0052c202805c00536b00525d005332", + "0x26d02802836b00502836902802836b00502800702805e00572b02836b007", + "0x2802836b00505c00508e02802836b00504e00521c02802836b00500b005", + "0x536b00502802002806000536b00505900503102802836b00503100508e", + "0x5f00736402805d00536b00505d00501b02805d00536b00502824502805f", + "0x536b00529629800702d02829800536b00502802302829600536b00505d", + "0x509202801000536b00501000504f02806700536b00504200571b028042", + "0x702806706001003100506700536b00506700571c02806000536b005060", + "0x36b00505e03101003172c0282bd00536b00505900503102802836b005028", + "0x282bd00536b0052bd00509202802836b00506800508e028006068069031", + "0x2836b00502800702807432500772d07106f00736b00700605c069031111", + "0x7500509202801700536b00506f00504f02807500536b0052bd005031028", + "0x2807700536b00502872e02836900536b00507100533202801800536b005", + "0x702802872f02836b00707734c0072a002834c04e00736b00504e00535d", + "0x25b02834b00536b00501800503102802836b00502836902802836b005028", + "0x36b00507a00503302807a00536b00502872e02804300536b00536900b007", + "0x58e02804300536b00504300527802834b00536b00534b00509202807a005", + "0x2802836b00502800702808134800773007f07900736b00704e07a017031", + "0x507d00509202807900536b00507900504f02807d00536b00534b005031", + "0x2807f00536b00507f00503302804300536b00504300527802807d00536b", + "0x2800702834434534603100534434534603136b00507f04307d07900a731", + "0x503102802836b00504300526d02802836b00508100521c02802836b005", + "0x2834100536b00502862202834200536b00502802002834300536b00534b", + "0x502802302833d00536b00534134200736402834100536b00534100501b", + "0x33b00536b00533c00571b02833c00536b00533d08c00702d02808c00536b", + "0x33b00571c02834300536b00534300509202834800536b00534800504f028", + "0x36b00502836902802836b00502800702833b34334803100533b00536b005", + "0x502873202808a00536b00501800503102802836b00504e00521c028028", + "0x2808a00536b00508a00509202833a00536b00533a00533202833a00536b", + "0x2836b00502800702833733800773308833900736b00736933a017031111", + "0x2803002808600536b00508800b00725b02833600536b00508a005031028", + "0x536b00537700573502837700536b00508e08600773402808e00536b005", + "0x571c02833600536b00533600509202833900536b00533900504f028333", + "0x33700508e02802836b00502800702833333633903100533300536b005333", + "0x2002833200536b00508a00503102802836b00500b00526d02802836b005", + "0x33000536b00533000501b02833000536b0050282c102833100536b005028", + "0x32e00702d02832e00536b00502802302832f00536b005330331007364028", + "0x536b00533800504f02832c00536b00532d00571b02832d00536b00532f", + "0x33803100532c00536b00532c00571c02833200536b005332005092028338", + "0x36b00507400508e02802836b00502836902802836b00502800702832c332", + "0x52bd00503102802836b00504e00521c02802836b00500b00526d028028", + "0x501b02832a00536b0050282c102832b00536b00502802002808b00536b", + "0x536b00502802302832900536b00532a32b00736402832a00536b00532a", + "0x4f02809300536b00508500571b02808500536b00532932600702d028326", + "0x36b00509300571c02808b00536b00508b00509202832500536b005325005", + "0xb00573602800b00a00736b00500500524202809308b325031005093005", + "0x536b00504f00503302809203100736b00503100535d02804f00536b005", + "0x521c02802836b00502800702800f00573702836b00709200570b02804f", + "0x2801000536b00501000503302801000536b00502873802802836b005007", + "0x1c800525302804e00536b00502800504f0281c800536b00501000a0071b4", + "0xf00570e02802836b00502800702802873900502804d02801300536b005", + "0x2804d03100736b00503100535d02801400536b0050280e102802836b005", + "0x36b0050282f302802836b00502800702802873a02836b00701404d0072a0", + "0x73b02836b0070300170072a002801703100736b00503100535d028030005", + "0x536b00502873d02801800536b00502873c02802836b005028007028028", + "0x36900503302801b00536b00501800565202836800536b00502873e028369", + "0x702802873f00502804d02836700536b00536800503302801c00536b005", + "0x74202801f00536b00502874102836600536b00502874002802836b005028", + "0x536b00501f00503302801b00536b00536600565202802000536b005028", + "0x517202836500536b00501b00574302836700536b00502000503302801c", + "0x2802874400502804d02802300536b00536700517202836400536b00501c", + "0x2836300536b00502874502802d00536b00502838402802836b005028007", + "0x36b00536300503302836500536b00502d0056520280c000536b005028746", + "0x8403136b00536500702803165302802300536b0050c0005033028364005", + "0x33202835f00536b0053641aa00774702802836b00536100521c0281aa361", + "0x2836c00574935d03200736b00735f08400774802835f00536b00535f005", + "0x3603c00774b00c03300736b00702335d03203174a02802836b005028007", + "0x503300504f02804000536b00500c00a0071b402802836b005028007028", + "0x35935e00736b00501300524202801300536b00504000525302804e00536b", + "0x535600503302821500536b0050280e102835600536b005359005736028", + "0x736b00721535604e03174a02821500536b00521500503302835600536b", + "0x2804500536b00502874d02802836b00502800702804704800774c04621c", + "0x2823b23923703136b00504504621c03165302804500536b005045005652", + "0x536b00502838502823f00536b00523b00507402802836b00523900521c", + "0x25302824900536b00523f24500732c02824500536b00524500501b028245", + "0x524935e00774e02824900536b00524900501b02835e00536b00535e005", + "0x2824e00536b00524d04f00774702824d00536b00502874f02824c00536b", + "0x5000575025224f00736b00724e23700774802824e00536b00524e005332", + "0x36b00500903100774702800900536b00502875102802836b005028007028", + "0x5905800736b00705b24f00774802805b00536b00505b00533202805b005", + "0x25d25c00736b00705925205803174a02802836b00502800702805c005752", + "0x2806000536b00525d24c0071b402802836b00502800702805e25e007753", + "0x505d00575502805d00536b00505f06000775402805f00536b005028030", + "0x529600536b00529600575602825c00536b00525c00504f02829600536b", + "0x24c0051bd02802836b00505e00521c02802836b00502800702829625c007", + "0x501b02804200536b00502875702829800536b00502802002802836b005", + "0x536b00502802302806700536b00504229800736402804200536b005042", + "0x4f02806800536b00506900575802806900536b0050672bd00702d0282bd", + "0x702806825e00700506800536b00506800575602825e00536b00525e005", + "0x2002802836b00525200521c02802836b00524c0051bd02802836b005028", + "0x6f00536b00506f00501b02806f00536b00502875902800600536b005028", + "0x32500702d02832500536b00502802302807100536b00506f006007364028", + "0x536b00505c00504f02807500536b00507400575802807400536b005071", + "0x2802836b00502800702807505c00700507500536b00507500575602805c", + "0x7700536b00502802002802836b00503100521c02802836b00524c0051bd", + "0x34c07700736402834c00536b00534c00501b02834c00536b005028759028", + "0x7a00536b00534b04300702d02804300536b00502802302834b00536b005", + "0x7900575602805000536b00505000504f02807900536b00507a005758028", + "0x36b00504700521c02802836b00502800702807905000700507900536b005", + "0x535e0051bd02802836b00503100521c02802836b00504f00521c028028", + "0x34800501b02834800536b00502875702807f00536b00502802002802836b", + "0x7d00536b00502802302808100536b00534807f00736402834800536b005", + "0x504f02834500536b00534600575802834600536b00508107d00702d028", + "0x2800702834504800700534500536b00534500575602804800536b005048", + "0x521c02802836b00504f00521c02802836b00503600521c02802836b005", + "0x75702834400536b00502802002802836b00500a0051bd02802836b005031", + "0x36b00534334400736402834300536b00534300501b02834300536b005028", + "0x75802833d00536b00534234100702d02834100536b005028023028342005", + "0x36b00508c00575602803c00536b00503c00504f02808c00536b00533d005", + "0x2802836b00504f00521c02802836b00502800702808c03c00700508c005", + "0x2836b00502300521c02802836b00500a0051bd02802836b00503100521c", + "0x36b00533b00501b02833b00536b00502875902833c00536b005028020028", + "0x2d02833a00536b00502802302808a00536b00533b33c00736402833b005", + "0x536c00504f02808800536b00533900575802833900536b00508a33a007", + "0x36b00502836902808836c00700508800536b00508800575602836c00536b", + "0x36b00502800702800f09200775a04f00b00736b007005028007005028028", + "0x50920281c800536b00503100575b02801000536b00504f005031028028", + "0x3004d00775d01401304e03136b0071c800b00775c02801000536b005010", + "0x36b00501400575e02801700536b00501000503102802836b005028007028", + "0x75f02836800536b00501700509202836900536b00504e00504f028018005", + "0x2876100502804d02801c00536b00501800576002801b00536b005013005", + "0x536b00502803002836700536b00501000503102802836b005028007028", + "0x509202836900536b00504d00504f02801f00536b005366005762028366", + "0x536b00501f00576002801b00536b00503000575f02836800536b005367", + "0x36400576436500536b00701c00576302802000536b00501b00523c02801c", + "0x36b00536500576502802300536b00536800503102802836b005028007028", + "0x3136b00702d00a00702300a76602802300536b00502300509202802d005", + "0x36b00536300509202802836b00502800702835f1aa3610317670840c0363", + "0x9202836900536b00536900504f02803200536b005363005031028363005", + "0x36b0050200051bf0280c000536b0050c00050c002803200536b005032005", + "0x36b0050840200c003236900b23a02808400536b0050840051c1028020005", + "0x523d02802836b00502800702800c03336c35d00a00500c03336c35d00a", + "0x3c00536b00536100503102836100536b00536100509202802836b005020", + "0x4000576802804000536b00535f03600702d02803600536b005028023028", + "0x3c00536b00503c00509202836900536b00536900504f02835e00536b005", + "0x3c36900a00535e00536b00535e0057690281aa00536b0051aa0050c0028", + "0x536800503102802836b00536400504702802836b00502800702835e1aa", + "0x21500536b00535600a02003176a02835600536b00502803002835900536b", + "0x35900509202836900536b00536900504f02821c00536b00521500576b028", + "0x21c00536b00521c00576902800700536b0050070050c002835900536b005", + "0x2802836b00500a00576c02802836b00502800702821c00735936900a005", + "0x536b00502802002804600536b00500f00503102802836b00503100523d", + "0x4800736402804700536b00504700501b02804700536b005028046028048", + "0x536b00504523700702d02823700536b00502802302804500536b005047", + "0x509202809200536b00509200504f02823b00536b005239005768028239", + "0x536b00523b00576902800700536b0050070050c002804600536b005046", + "0x736b00500b00576d02802836b00502836902823b00704609200a00523b", + "0x2802836b0051c80053440281c801000f03136b00509200576e02809200b", + "0x526602801401300736b00501300521a02801304e00736b00500f0051d6", + "0x536b00504d0052f702802836b00503000530f02803004d00736b005014", + "0x503102802836b00502800702801800577002836b00701700576f028017", + "0x36b00536800530f02801b36800736b00501300526602836900536b005005", + "0x576f02836900536b00536900509202801c00536b00501b0052f7028028", + "0x2836b00504e00525902802836b00502800702836700577102836b00701c", + "0x36b00504f00577202802836b00501000525902802836b00500a005259028", + "0x2800504f02836600536b00536900503102802836b00500b005389028028", + "0x702802877300502804d02802000536b00536600509202801f00536b005", + "0x2836500536b00536900503102802836b00536700577402802836b005028", + "0x2802836b00502800702802877500502804d02836400536b005365005092", + "0x536b00500500503102802836b00501300525902802836b005018005774", + "0x77602836302d00736b00504e00526602836400536b005023005092028023", + "0x36b00536300528602836108400736b0050c00052660280c000536b005028", + "0x35f00536b00535f00530d02835f36100736b0053610052860281aa363007", + "0x36b00502800702803336c00777735d03200736b00735f1aa02803117f028", + "0x3200504f02800c00536b00536400503102802836b00535d00530f028028", + "0x2836b0073613630072a202800c00536b00500c00509202803200536b005", + "0x501000525902802836b00500a00525902802836b005028007028028778", + "0x8400530f02802836b00500b00538902802836b00504f00577202802836b", + "0x4f02803c00536b00500c00503102802836b00502d00530f02802836b005", + "0x2877300502804d02802000536b00503c00509202801f00536b005032005", + "0x36b00508400530d02803600536b00500c00503102802836b005028007028", + "0x4000736b00708402d03203117f02803600536b005036005092028084005", + "0x25902802836b00535e00530f02802836b00502800702835635900777935e", + "0x2802836b00504f00577202802836b00501000525902802836b00500a005", + "0x36b00504000504f02821500536b00503600503102802836b00500b005389", + "0x577b02821c00536b00502877a02802000536b00521500509202801f005", + "0x536b00504800577d02804800536b00504600577c02804600536b00521c", + "0x538a02803100536b0050310050c002800700536b005007005307028047", + "0x30f02802836b00502800702804703100702001f00b00504700536b005047", + "0x536b00535900504f02804500536b00503600503102802836b005356005", + "0x36b00502800702802877e00502804d02823900536b005045005092028237", + "0x508400530f02802836b00536300530f02802836b00503300530f028028", + "0x36400503102802836b00536100530f02802836b00502d00530f02802836b", + "0x23900536b00523b00509202823700536b00536c00504f02823b00536b005", + "0x26602824924500736b00524500521a02824523f00736b0050100051d6028", + "0x36b00524c0052f702802836b00524d00530f02824d24c00736b005249005", + "0x702824f00577f02836b00724e00576f02802836b00502800b02824e005", + "0x5000736b00524500526602825200536b00523900503102802836b005028", + "0x25200509202805b00536b0050090052f702802836b00505000530f028009", + "0x2836b00502800702805800578002836b00705b00576f02825200536b005", + "0x2836b00504f00577202802836b00523f00525902802836b005028369028", + "0x36b00525200503102802836b00500a00525902802836b00500b005389028", + "0x4d02825c00536b00505900509202805c00536b00523700504f028059005", + "0x503102802836b00505800577402802836b005028007028028781005028", + "0x2802878200502804d02825e00536b00525d00509202825d00536b005252", + "0x2802836b00524500525902802836b00524f00577402802836b005028007", + "0x36b00502836902825e00536b00505e00509202805e00536b005239005031", + "0x526602805d00536b00502877602805f06000736b00523f005266028028", + "0x529800528602804205f00736b00505f00528602829829600736b00505d", + "0x36b00706704223703117f02806700536b00506700530d02806729800736b", + "0x2836b00506900530f02802836b0050280070280060680077830692bd007", + "0x6f0050920282bd00536b0052bd00504f02806f00536b00525e005031028", + "0x2836b00502800702802878402836b00729805f0072a202806f00536b005", + "0x36b00500a00525902802836b00500b00538902802836b00504f005772028", + "0x506f00503102802836b00506000530f02802836b00529600530f028028", + "0x2825c00536b00507100509202805c00536b0052bd00504f02807100536b", + "0x2832500536b00506f00503102802836b00502800702802878100502804d", + "0x602bd03117f02832500536b00532500509202829600536b00529600530d", + "0x7500530f02802836b00502800702834c07700778507507400736b007296", + "0x525902802836b00500b00538902802836b00504f00577202802836b005", + "0x5c00536b00507400504f02834b00536b00532500503102802836b00500a", + "0x504300577b02804300536b00502877a02825c00536b00534b005092028", + "0x2807f00536b00507900577d02807900536b00507a00577c02807a00536b", + "0x507f00538a02803100536b0050310050c002800700536b005007005307", + "0x34c00530f02802836b00502800702807f03100725c05c00b00507f00536b", + "0x2808100536b00507700504f02834800536b00532500503102802836b005", + "0x2802836b00502800702802878600502804d02807d00536b005348005092", + "0x2836b00529600530f02802836b00505f00530f02802836b00500600530f", + "0x36b00525e00503102802836b00529800530f02802836b00506000530f028", + "0xc002807d00536b00534600509202808100536b00506800504f028346005", + "0x36b00500b00520902800a00536b00500a00519702803100536b005031005", + "0x578802834234334434500a36b00500b00a03107d08100b78702800b005", + "0x36b00534400503102802836b00502800702833d00578934100536b007342", + "0x22102808c00536b00508c00509202833c00536b00534100578a02808c005", + "0x508c00503102802836b00502800702808a00578b33b00536b00733c005", + "0x2833a00536b00533a00509202834500536b00534500504f02833a00536b", + "0x533b00578c02834300536b0053430050c002800700536b005007005307", + "0x2833633733808833900b36b00533b34300733a34500b78d02833b00536b", + "0x8800503102802836b00502800702808e00578f08600536b00733600578e", + "0x33200736b00504f00579102833300536b00508600579002837700536b005", + "0x577202832f33000736b00533300579102802836b005332005772028331", + "0x32d00536b00532f00579202832e00536b00533100579202802836b005330", + "0x32c00732c02808b00536b00532d0051c802832c00536b00532e0051c8028", + "0x536b00537700509202832b00536b00532b00501b02832b00536b00508b", + "0x503102802836b00502800702832a00579302836b00732b005348028377", + "0x8500536b00532600579402832600536b00502803002832900536b005377", + "0x33900504f02809500536b00509300577d02809300536b00508500577c028", + "0x33800536b00533800530702832900536b00532900509202833900536b005", + "0x32933900b00509500536b00509500538a02833700536b0053370050c0028", + "0x37700503102802836b00532a00534602802836b005028007028095337338", + "0x2832300536b00509800577b02809800536b00502879502832400536b005", + "0x533900504f02832200536b00509600577d02809600536b00532300577c", + "0x2833800536b00533800530702832400536b00532400509202833900536b", + "0x33832433900b00532200536b00532200538a02833700536b0053370050c0", + "0x508800503102802836b00504f00577202802836b005028007028322337", + "0x2833900536b00533900504f02831f00536b00508e00579602832100536b", + "0x53370050c002833800536b00533800530702832100536b005321005092", + "0x702831f33733832133900b00531f00536b00531f00538a02833700536b", + "0x3102802836b00504f00577202802836b00508a00504702802836b005028", + "0x31c00536b00502824502831d00536b00502802002831e00536b00508c005", + "0x2802302831b00536b00531c31d00736402831c00536b00531c00501b028", + "0x536b00531900579602831900536b00531b31a00702d02831a00536b005", + "0x530702831e00536b00531e00509202834500536b00534500504f028318", + "0x536b00531800538a02834300536b0053430050c002800700536b005007", + "0x36b00504f00577202802836b00502800702831834300731e34500b005318", + "0x504f02831600536b00533d00579602831700536b005344005031028028", + "0x536b00500700530702831700536b00531700509202834500536b005345", + "0x34500b00531600536b00531600538a02834300536b0053430050c0028007", + "0x736b0050920051d602809200a00736b00500a00521a028316343007317", + "0x1304e00736b0051c80052660281c801000736b00501000521a02801000f", + "0x701400576f02801400536b00504e0052f702802836b00501300530f028", + "0x2803000536b00500500503102802836b00502800702804d00579702836b", + "0x50180052f702802836b00501700530f02801801700736b005010005266", + "0x579802836b00736900576f02803000536b00503000509202836900536b", + "0x36b00500a00525902802836b00500f00525902802836b005028007028368", + "0x503100525902802836b00500b00525902802836b00504f00557a028028", + "0x9202801c00536b00502800504f02801b00536b00503000503102802836b", + "0x77402802836b00502800702802879900502804d02836700536b00501b005", + "0x536b00536600509202836600536b00503000503102802836b005368005", + "0x2836b00504d00577402802836b00502800702802879a00502804d02801f", + "0x502000509202802000536b00500500503102802836b005010005259028", + "0x2802300536b00502879b02836436500736b00500f00526602801f00536b", + "0x52860280c036400736b00536400528602836302d00736b005023005266", + "0x840c002803117f02808400536b00508400530d02808436300736b005363", + "0x51aa00530f02802836b00502800702803235f00779c1aa36100736b007", + "0x9202836100536b00536100504f02835d00536b00501f00503102802836b", + "0x502800702802879d02836b0073633640072a202835d00536b00535d005", + "0xb00525902802836b00504f00557a02802836b00500a00525902802836b", + "0x530f02802836b00502d00530f02802836b00503100525902802836b005", + "0x1c00536b00536100504f02836c00536b00535d00503102802836b005365", + "0x2836b00502800702802879900502804d02836700536b00536c005092028", + "0x3300509202802d00536b00502d00530d02803300536b00535d005031028", + "0x2804003600779e03c00c00736b00702d36536103117f02803300536b005", + "0x2802836b00500a00525902802836b00503c00530f02802836b005028007", + "0x2836b00503100525902802836b00500b00525902802836b00504f00557a", + "0x35e00509202801c00536b00500c00504f02835e00536b005033005031028", + "0x35600536b00536700539802835900536b00501c00530c02836700536b005", + "0x2802836b00504000530f02802836b00502800702802879f00502804d028", + "0x521500509202821c00536b00503600504f02821500536b005033005031", + "0x503200530f02802836b0050280070280287a000502804d02804600536b", + "0x36500530f02802836b00502d00530f02802836b00536400530f02802836b", + "0x4f02804800536b00501f00503102802836b00536300530f02802836b005", + "0x36b00500b00521a02804600536b00504800509202821c00536b00535f005", + "0x23700736b00523700521a02823704500736b0050470051d602804700b007", + "0x52f702802836b00523f00530f02823f23b00736b005239005266028239", + "0x36b0050280070282490057a102836b00724500576f02824500536b00523b", + "0x30f02824e24d00736b00523700526602824c00536b005046005031028028", + "0x536b00524c00509202824f00536b00524e0052f702802836b00524d005", + "0x525902802836b0050280070282520057a202836b00724f00576f02824c", + "0x2800900536b00502803002805000536b00524c00503102802836b005045", + "0x505000509202805800536b00521c00504f02805b00536b005009005345", + "0x280070280287a300502804d02805c00536b00505b00507d02805900536b", + "0x9202825c00536b00524c00503102802836b00525200577402802836b005", + "0x77402802836b0050280070280287a400502804d02825d00536b00525c005", + "0x25e00536b00504600503102802836b00523700525902802836b005249005", + "0x2879b02806005e00736b00504500526602825d00536b00525e005092028", + "0x736b00506000528602829605d00736b00505f00526602805f00536b005", + "0x2804200536b00504200530d02804229600736b005296005286028298060", + "0x2836b0050280070280680690077a52bd06700736b00704229821c03117f", + "0x506700504f02800600536b00525d00503102802836b0052bd00530f028", + "0x7a602836b0072960600072a202800600536b00500600509202806700536b", + "0x36b00505e00530f02802836b00505d00530f02802836b005028007028028", + "0x7100534502807100536b00502803002806f00536b005006005031028028", + "0x5900536b00506f00509202805800536b00506700504f02832500536b005", + "0x2836b0050280070280287a300502804d02805c00536b00532500507d028", + "0x7400509202805d00536b00505d00530d02807400536b005006005031028", + "0x2834b34c0077a707707500736b00705d05e06703117f02807400536b005", + "0x4300536b00507400503102802836b00507700530f02802836b005028007", + "0x507500504f02807900536b00507a00534502807a00536b005028030028", + "0x2805c00536b00507900507d02805900536b00504300509202805800536b", + "0x3102802836b00534b00530f02802836b0050280070280287a300502804d", + "0x536b00534800508102834800536b00502803002807f00536b005074005", + "0x507d02805900536b00507f00509202805800536b00534c00504f028081", + "0x530f02802836b0050280070280287a300502804d02805c00536b005081", + "0x30f02802836b00505d00530f02802836b00506000530f02802836b005068", + "0x7d00536b00525d00503102802836b00529600530f02802836b00505e005", + "0x506900504f02834500536b00534600508102834600536b005028030028", + "0x2805c00536b00534500507d02805900536b00507d00509202805800536b", + "0x73440050fc02834400536b00534400507d02834400536b00505c005342", + "0x2802836b00534300504702802836b0050280070283420057a834300536b", + "0x36b00533d0057aa02833d00536b0050287a902834100536b005059005031", + "0x2834100536b00534100509202808c00536b00508c0057ab02808c33d007", + "0x317ad08633633733808833933a08a33b33c1c836b00708c00b0580317ac", + "0x728502833200536b00534100503102802836b00502800702833337708e", + "0x33733000728502833000536b00533633100728502833100536b00508633c", + "0x36b00508832e00728502832e00536b00533832f00728502832f00536b005", + "0x8b00536b00533a32c00728502832c00536b00533932d00728502832d005", + "0x504f02832a00536b00533b0057ae02832b00536b00508a08b007285028", + "0x736b00532a00521a02803100536b00503100519702832b00536b00532b", + "0x32600736b00532903132b0317af02832900536b00532900519702832932a", + "0x7b002809300536b0050930057ab02809333d00736b00533d0057aa028085", + "0x53240057b102831f32132209632309832409500f36b005093085326031", + "0x31d00536b00532131e00728502831e00536b00531f09500728502802836b", + "0x28502831b00536b00509631c00728502831c00536b00532231d007285028", + "0x500a00521a02831a00536b00531a00504f02831a00536b00532331b007", + "0x32a00536b00532a00519702831900536b00531900519702831900a00736b", + "0x2833d00536b00533d0057ab02831731800736b00532a31931a0317af028", + "0x3140057b10280ac0b03100a931131331431600f36b00533d3173180317b0", + "0x536b0050b030f00728502830f00536b0050ac31600728502802836b005", + "0x280b600536b0050a90b40072850280b400536b00531030d00728502830d", + "0x36b0050287b30280b900536b0050287b202830b00536b0053110b6007285", + "0x1970280b900536b0050b900519702833200536b005332005092028309005", + "0xb900733200a1fd02830b00536b00530b00504f02830900536b005309005", + "0x9202802836b0050280070283040bf3050317b430630730803136b007309", + "0x36b0053060051ee02830300536b00530800503102830800536b005308005", + "0x2830300536b00530300509202830700536b0053070050c0028306005", + "0x530300503102802836b0050280070280510057b530200536b007306005", + "0x36b00709830230739300a7b602839300536b00539300509202839300536b", + "0x539400509202802836b0050280070280c60c73960317b70dc395394031", + "0x280c900536b0050c90050920280c900536b00539400503102839400536b", + "0x3010cf0cb03136b00731304f3950c900a7b60280dc00536b0050dc005588", + "0x280cb00536b0050cb00509202802836b00502800702839830c3970317b8", + "0x53010055880282fb00536b0052fb0050920282fb00536b0050cb005031", + "0x2f83990317ba0d52fa0d403136b0073010dc0cf2fb00a7b902830100536b", + "0x50d40050310280d400536b0050d400509202802836b0050280070282f7", + "0x280d500536b0050d50055880282f100536b0052f10050920282f100536b", + "0x280070282f60db2ef0317bb0d22ec2ee0da00a36b0070d52fa2f103157f", + "0x310280da00536b0050da00509202802836b0050d200525902802836b005", + "0x52e80052590282e72e800736b0052ec0051d60282e900536b0050da005", + "0x19702802836b0050df0052590282f50df00736b00500a0051d602802836b", + "0x50e10052660280e12e700736b0052e700521a0282e700536b0052e7005", + "0xe32f500736b0052f500521a02802836b0052f200530f0282f22f300736b", + "0x2f30052f702802836b0052e000530f0282e02f400736b0050e3005266028", + "0x2ee00536b0052ee0050c00282dd00536b0052f40052f70282de00536b005", + "0x70280287bc02836b0072dd2de0072a20282e900536b0052e9005092028", + "0x3102802836b0052f500525902802836b0052e700525902802836b005028", + "0x536b0052db0053450282db00536b0050280300281a600536b0052e9005", + "0x2804d0280ea00536b0052da00507d0282d700536b0051a60050920282da", + "0x52660280ee00536b0052e900503102802836b0050280070280287bd005", + "0x736b0052f500526602802836b0052d600530f0282d42d600736b0052e7", + "0x52f70282d100536b0052d40052f702802836b0052d300530f0282d22d3", + "0x36b0072d02d10072a20280ee00536b0050ee0050920282d000536b0052d2", + "0x280300282cf00536b0050ee00503102802836b0050280070280287be028", + "0x2d700536b0052cf0050920280f600536b0052cc0053450282cc00536b005", + "0x2836b0050280070280287bd00502804d0280ea00536b0050f600507d028", + "0x52cb0050810282cb00536b0050280300280f800536b0050ee005031028", + "0x280ea00536b0052ca00507d0282d700536b0050f80050920282ca00536b", + "0x530b00504f0280fa00536b0052c90057c00282c900536b0050ea0057bf", + "0x282ee00536b0052ee0050c00282d700536b0052d700509202830b00536b", + "0x2802836b0050280070280fa2ee2d730b00a0050fa00536b0050fa0057c1", + "0x36b0052ef0050310282ef00536b0052ef00509202802836b00500a005259", + "0x7c20280f900536b0052f60fb00702d0280fb00536b0050280230280fc005", + "0x36b0050fc00509202830b00536b00530b00504f0282c800536b0050f9005", + "0xa0052c800536b0052c80057c10280db00536b0050db0050c00280fc005", + "0x509202802836b00500a00525902802836b0050280070282c80db0fc30b", + "0x10200536b0050280230282c700536b00539900503102839900536b005399", + "0x504f02810300536b0051040057c202810400536b0052f710200702d028", + "0x536b0052f80050c00282c700536b0052c700509202830b00536b00530b", + "0x36b0050280070281032f82c730b00a00510300536b0051030057c10282f8", + "0x539700509202802836b0050dc00557a02802836b00500a005259028028", + "0x2d0282c600536b00502802302810100536b00539700503102839700536b", + "0x530b00504f02810a00536b0052c50057c20282c500536b0053982c6007", + "0x2830c00536b00530c0050c002810100536b00510100509202830b00536b", + "0x2802836b00502800702810a30c10130b00a00510a00536b00510a0057c1", + "0x2836b00531300525902802836b00504f00557a02802836b00500a005259", + "0x502802302810b00536b00539600503102839600536b005396005092028", + "0x2c300536b00510c0057c202810c00536b0050c610900702d02810900536b", + "0xc70050c002810b00536b00510b00509202830b00536b00530b00504f028", + "0x70282c30c710b30b00a0052c300536b0052c30057c10280c700536b005", + "0x57a02802836b00500a00525902802836b00505100504702802836b005028", + "0x2802836b00509800525902802836b00531300525902802836b00504f005", + "0x536b00502824502811200536b0050280200282c200536b005303005031", + "0x9202802500536b00511311200736402811300536b00511300501b028113", + "0x36b0050250052150282c100536b0053070050c002811100536b0052c2005", + "0x36b00500a00525902802836b0050280070280287c300502804d02811d005", + "0x509800525902802836b00531300525902802836b00504f00557a028028", + "0x9202811900536b00530500503102830500536b00530500509202802836b", + "0x36b0053040052150282c100536b0050bf0050c002811100536b005119005", + "0x7c20282c000536b00511d11800702d02811800536b00502802302811d005", + "0x36b00511100509202830b00536b00530b00504f02811f00536b0052c0005", + "0xa00511f00536b00511f0057c10282c100536b0052c10050c0028111005", + "0x557a02802836b00500a00525902802836b00502800702811f2c111130b", + "0x3102802836b00533d0057c402802836b00503100525902802836b00504f", + "0x3772be0072850282be00536b00533308e00728502812100536b005341005", + "0x1b0282ba00536b0050282450282bb00536b0050280200282bc00536b005", + "0x36b00502802302812400536b0052ba2bb0073640282ba00536b0052ba005", + "0x2812300536b0051250057c202812500536b00512412600702d028126005", + "0x50070050c002812100536b0051210050920282bc00536b0052bc00504f", + "0x280070281230071212bc00a00512300536b0051230057c102800700536b", + "0x557a02802836b00500a00525902802836b00534200504702802836b005", + "0x3102802836b00503100525902802836b00500b00525902802836b00504f", + "0x36b0052b900509202835900536b00505800504f0282b900536b005059005", + "0x57bf02812c00536b0052b70053450282b700536b005028030028356005", + "0x536b0050070050c00282b600536b00512b0057c002812b00536b00512c", + "0x50280057c50282b600735635900a0052b600536b0052b60057c1028007", + "0x500a0057c702804f00b00a03100a36b0050070057c602800702800736b", + "0x310057c802802836b00504f0057c702802836b00500b0057c702802836b", + "0x500736b0050050057c502800f00536b0050920057c902809200536b005", + "0x2802836b00504e0057c702801401304e1c800a36b0050100057c6028010", + "0x536b0051c80057c802802836b0050140057c702802836b0050130057c7", + "0x1b02801700536b00503000f00732c02803000536b00504d0057c902804d", + "0x50280070280180057ca02836b00701700534802801700536b005017005", + "0x1b36800a36b0053690057c602836902800736b0050280057c502802836b", + "0x3670057c702802836b00501c0057c702802836b0053680057c702836701c", + "0x2801f00536b0053660057c902836600536b00501b0057c802802836b005", + "0x2802d02336436500a36b0050200057c602802000500736b0050050057c5", + "0x2836b00502d0057c702802836b0050230057c702802836b0053650057c7", + "0x1f00732c0280c000536b0053630057c902836300536b0053640057c8028", + "0x2836b00708400534802808400536b00508400501b02808400536b0050c0", + "0x7c60281aa02800736b0050280057c502802836b0050280070283610057cb", + "0x320057c702802836b00535f0057c702836c35d03235f00a36b0051aa005", + "0x7c902803300536b00535d0057c802802836b00536c0057c702802836b005", + "0x503c0057c602803c00500736b0050050057c502800c00536b005033005", + "0x2836b0050400057c702802836b0050360057c702835935e04003600a36b", + "0x53560057c902835600536b00535e0057c802802836b0053590057c7028", + "0x21c00536b00521c00501b02821c00536b00521500c00732c02821500536b", + "0x280057c602802836b0050280070280460057cc02836b00721c005348028", + "0x36b0050470057c702802836b0050480057c702823704504704800a36b005", + "0x2390057c902823900536b0052370057c802802836b0050450057c7028028", + "0x523f0057c702824c24924523f00a36b0050050057c602823b00536b005", + "0x24c0057c802802836b0052490057c702802836b0052450057c702802836b", + "0x536b00524e23b00732c02824e00536b00524d0057c902824d00536b005", + "0x282520057cd02836b00724f00534802824f00536b00524f00501b02824f", + "0x900536b00505000508102805000536b00502803002802836b005028007", + "0x534602802836b00502800702800900500500900536b00500900507d028", + "0x2805800536b00505b00534502805b00536b00502803002802836b005252", + "0x4600534602802836b00502800702805800500505800536b00505800507d", + "0x2804d02802836b0050280055e202802836b0050050055e202802836b005", + "0x50055e202802836b00536100534602802836b0050280070280287ce005", + "0x50280070280287ce00502804d02802836b0050280055e202802836b005", + "0x280055e202802836b0050050055e202802836b00501800534602802836b", + "0x7d02805c00536b00505900534502805900536b00502803002802836b005", + "0x70b02800a03100736b00503100535d02805c00500505c00536b00505c005", + "0x36b00500700501f02802836b00502800702800b0057cf02836b00700a005", + "0x4f0050077d002804f00536b00502803002802836b00503100521c028028", + "0x2800536b00502800504f02800f00536b0050920057d102809200536b005", + "0x70e02802836b00502800702800f02800700500f00536b00500f0057d2028", + "0x504e00535d02804e1c801003136b0050050057d302802836b00500b005", + "0x701401302803174a02801403100736b00503100535d02801304e00736b", + "0x536b0050285e902802836b0050280070280180170077d403004d00736b", + "0x58e02836900536b00536900503302836803000736b00503000535d028369", + "0x2802836b0050280070283663670077d501c01b00736b00736936804d031", + "0x736b00503000535d02801f00536b0050285e902802836b00501c00521c", + "0x287d602836b00701f0200072a002801b00536b00501b00504f028020030", + "0x36500536b0050285e902802836b00503100521c02802836b005028007028", + "0x7d702336400736b00736503001b03158e02836500536b005365005033028", + "0x2300535d0280c000536b00502872e02802836b00502800702836302d007", + "0x36b0070c00840072a002836400536b00536400504f02808402300736b005", + "0x2300535d02836100536b00502872e02802836b0050280070280287d8028", + "0x73611aa36403158e02836100536b0053610050330281aa02300736b005", + "0x36b00503200521c02802836b00502800702836c35d0077d903235f00736b", + "0x502800702804003603c0317da00c03300736b00700735f0070ac028028", + "0x530d02835900536b00503300504f02835e00536b00502828b02802836b", + "0x280287db00502804d02821500536b00535e00530d02835600536b00500c", + "0x536b00504000530d02835900536b00503c00504f02802836b005028007", + "0x2300535d02821c00536b00502872e02821500536b00503600530d028356", + "0x721c04635903158e02821c00536b00521c00503302804602300736b005", + "0x36b00504800504f02802836b0050280070282370450077dc04704800736b", + "0x23b23900736b0050470480077dd02804700536b005047005033028048005", + "0x57e002802836b0050280070282450057df23f00536b00723b0057de028", + "0x50b902824e24d24c03136b0052492152390317e102824900536b00523f", + "0x536b00524d0050b902825200536b0053560050b902824f00536b00524e", + "0x503302805b04e00736b00504e00535d02800900536b0050285e9028050", + "0x25c05c0077e205905800736b00705b00924c03158e02800900536b005009", + "0x36b00525d24f00721902825d00536b00502821302802836b005028007028", + "0x2805e00536b00525225e0072e002825e00536b00525e00501b02825e005", + "0x506000503302805f05900736b00505900535d02806000536b00502872e", + "0x736b00706005f05803158e02805e00536b00505e00501b02806000536b", + "0x2802836b00529600521c02802836b0050280070280422980077e329605d", + "0x6705905d03158e02806700536b00506700503302806700536b00502872e", + "0x52bd00504f02802836b0050280070280060680077e40692bd00736b007", + "0x6f00736b0050692bd0077dd02806900536b0050690050330282bd00536b", + "0x7e002802836b0050280070280740057e532500536b0070710057de028071", + "0x36b0050770050b902807700536b0050750057e602807500536b005325005", + "0x4f02804300536b00534b34c00721902834b00536b00502821302834c005", + "0x287e700502804d02807900536b00504300501b02807a00536b00506f005", + "0x2836b00502300521c02802836b0050100057e802802836b005028007028", + "0x36b00505000501f02802836b00505e00501f02802836b00504e00521c028", + "0x534c02834807f00736b00507400507702802836b0051c800501f028028", + "0x7d00536b00534800521502808100536b00506f00504f02802836b00507f", + "0x2802836b00500600521c02802836b0050280070280287e900502804d028", + "0x2836b00504e00521c02802836b00502300521c02802836b0050100057e8", + "0x36b00505000501f02802836b0051c800501f02802836b00505e00501f028", + "0x534500501b02834500536b00502862202834600536b005028020028028", + "0x8100536b00506800504f02834400536b00534534600736402834500536b", + "0x2836b0050280070280287e900502804d02807d00536b005344005215028", + "0x505900503302829800536b00529800504f02802836b00504200521c028", + "0x536b0073420057de02834234300736b0050592980077dd02805900536b", + "0x7e602808c00536b0053410057e002802836b00502800702833d0057ea341", + "0x36b00534300504f02833b00536b00533c0050b902833c00536b00508c005", + "0x2808a00536b0050791c800721902807900536b00533b00501b02807a005", + "0x33a00501b02833a00536b00508a0500072e002808a00536b00508a00501b", + "0x280070283380057ec08833900736b00733a07a0077eb02833a00536b005", + "0x36b00504e05e33703137802833700536b0050880100077ed02802836b005", + "0x4d02808e00536b0053360055ea02808600536b00533900504f028336005", + "0x521c02802836b0050100057e802802836b0050280070280287ee005028", + "0x2002802836b00505e00501f02802836b00504e00521c02802836b005023", + "0x33300536b00533300501b02833300536b00502824502837700536b005028", + "0x521502833100536b00533800504f02833200536b005333377007364028", + "0x57e802802836b0050280070280287ef00502804d02833000536b005332", + "0x1f02802836b00504e00521c02802836b00502300521c02802836b005010", + "0x2802836b0051c800501f02802836b00505000501f02802836b00505e005", + "0x534300504f02802836b00532f00534c02832e32f00736b00533d005077", + "0x2833100536b00508100530c02807d00536b00532e00521502808100536b", + "0x2802836b0050280070280287ef00502804d02833000536b00507d0057f0", + "0x2836b00502300521c02802836b0050100057e802802836b00525c00521c", + "0x36b0051c800501f02802836b00524f00501f02802836b00504e00521c028", + "0x36b00502802002802836b00525200501f02802836b00505000501f028028", + "0x736402832c00536b00532c00501b02832c00536b00502862202832d005", + "0x36b00508b00521502833100536b00505c00504f02808b00536b00532c32d", + "0x36b0050100057e802802836b0050280070280287ef00502804d028330005", + "0x535600530f02802836b00504e00521c02802836b00502300521c028028", + "0x24500507702802836b00521500530f02802836b0051c800501f02802836b", + "0x33100536b00523900504f02802836b00532b00534c02832a32b00736b005", + "0x2836b0050280070280287ef00502804d02833000536b00532a005215028", + "0x36b00502300521c02802836b0050100057e802802836b00523700521c028", + "0x51c800501f02802836b00535600530f02802836b00504e00521c028028", + "0x502862202832900536b00502802002802836b00521500530f02802836b", + "0x8500536b00532632900736402832600536b00532600501b02832600536b", + "0x502802302833000536b00508500521502833100536b00504500504f028", + "0x32400536b00509500538e02809500536b00533009300702d02809300536b", + "0x32433100700532400536b0053240057d202833100536b00533100504f028", + "0x36b00700735d0070ac02802836b00536c00521c02802836b005028007028", + "0x536b00502828b02802836b0050280070283213220960317f1323098007", + "0x530d02831d00536b00532300530d02831e00536b00509800504f02831f", + "0x504f02802836b0050280070280287f200502804d02831c00536b00531f", + "0x536b00532200530d02831d00536b00532100530d02831e00536b005096", + "0x3302831b02300736b00502300535d02831e00536b00531e00504f02831c", + "0x3190057de02831931a00736b00531b31e0077dd02831b00536b00531b005", + "0x536b0053180057e002802836b0050280070283170057f331800536b007", + "0x536b00531c0050b902831131331403136b00531631d31a0317e1028316", + "0x50330280b002300736b00502300535d02831000536b00502872e0280a9", + "0xb430d0077f430f0ac00736b0070b031031403158e02831000536b005310", + "0x36b00530f0050330280ac00536b0050ac00504f02802836b005028007028", + "0xb900536b00730b0057de02830b0b600736b00530f0ac0077dd02830f005", + "0x57e602830800536b0050b90057e002802836b0050280070283090057f5", + "0x536b0053130050b902830600536b0053070050b902830700536b005308", + "0x4e00535d02830400536b0050285e90280bf00536b0053110050b9028305", + "0x73033040b603158e02830400536b00530400503302830304e00736b005", + "0x53060a900721902802836b0050280070283943930077f605130200736b", + "0xdc00536b0053053950072e002839500536b00539500501b02839500536b", + "0x3960050330280c705100736b00505100535d02839600536b00502872e028", + "0x36b0073960c730203158e0280dc00536b0050dc00501b02839600536b005", + "0x2836b0050c900521c02802836b0050280070280cf0cb0077f70c90c6007", + "0x510c603158e02830100536b00530100503302830100536b00502872e028", + "0x39700504f02802836b0050280070282fb3980077f830c39700736b007301", + "0x736b00530c3970077dd02830c00536b00530c00503302839700536b005", + "0x2802836b0050280070283990057f90d500536b0072fa0057de0282fa0d4", + "0x52f70050b90282f700536b0052f80057e60282f800536b0050d50057e0", + "0x282ee00536b0050da2f10072190280da00536b0050282130282f100536b", + "0x7fa00502804d0280d200536b0052ee00501b0282ec00536b0050d400504f", + "0x36b00502300521c02802836b0050100057e802802836b005028007028028", + "0x50dc00501f02802836b0050bf00501f02802836b00504e00521c028028", + "0x34c0280db2ef00736b00539900507702802836b0051c800501f02802836b", + "0x536b0050db0052150282f600536b0050d400504f02802836b0052ef005", + "0x2836b0052fb00521c02802836b0050280070280287fb00502804d0282e9", + "0x36b00504e00521c02802836b00502300521c02802836b0050100057e8028", + "0x50dc00501f02802836b0051c800501f02802836b0050bf00501f028028", + "0x2e700501b0282e700536b0050286220282e800536b00502802002802836b", + "0x536b00539800504f0280df00536b0052e72e80073640282e700536b005", + "0x36b0050280070280287fb00502804d0282e900536b0050df0052150282f6", + "0x510050330280cb00536b0050cb00504f02802836b0050cf00521c028028", + "0x36b0070e10057de0280e12f500736b0050510cb0077dd02805100536b005", + "0x280e300536b0052f30057e002802836b0050280070282f20057fc2f3005", + "0x52f500504f0282e000536b0052f40050b90282f400536b0050e30057e6", + "0x2de00536b0050d21c80072190280d200536b0052e000501b0282ec00536b", + "0x501b0282dd00536b0052de0dc0072e00282de00536b0052de00501b028", + "0x70282da0057fd2db1a600736b0072dd2ec0077eb0282dd00536b0052dd", + "0x504e0bf2d70313780282d700536b0052db0100077ed02802836b005028", + "0x2808e00536b0050ea0055ea02808600536b0051a600504f0280ea00536b", + "0x7ff00502804d0282d600536b00508e0057fe0280ee00536b00508600530c", + "0x36b00502300521c02802836b0050100057e802802836b005028007028028", + "0x36b00502802002802836b0050bf00501f02802836b00504e00521c028028", + "0x73640282d300536b0052d300501b0282d300536b0050282450282d4005", + "0x36b0052d20052150282d100536b0052da00504f0282d200536b0052d32d4", + "0x36b0050100057e802802836b00502800702802880000502804d0282d0005", + "0x50bf00501f02802836b00504e00521c02802836b00502300521c028028", + "0x2f200507702802836b0051c800501f02802836b0050dc00501f02802836b", + "0x2f600536b0052f500504f02802836b0052cf00534c0282cc2cf00736b005", + "0x2e90057f00282d100536b0052f600530c0282e900536b0052cc005215028", + "0x39400521c02802836b00502800702802880000502804d0282d000536b005", + "0x521c02802836b00502300521c02802836b0050100057e802802836b005", + "0x1f02802836b0051c800501f02802836b0050bf00501f02802836b00504e", + "0x2802836b00530500501f02802836b00530600501f02802836b0050a9005", + "0x536b0050f800501b0280f800536b0050286220280f600536b005028020", + "0x2150282d100536b00539300504f0282cb00536b0050f80f60073640280f8", + "0x7e802802836b00502800702802880000502804d0282d000536b0052cb005", + "0x2802836b00504e00521c02802836b00502300521c02802836b005010005", + "0x2836b00531300530f02802836b0050a900501f02802836b0051c800501f", + "0x2ca00534c0282c92ca00736b00530900507702802836b00531100530f028", + "0x282d000536b0052c90052150282d100536b0050b600504f02802836b005", + "0x7e802802836b0050b400521c02802836b00502800702802880000502804d", + "0x2802836b00504e00521c02802836b00502300521c02802836b005010005", + "0x2836b0050a900501f02802836b0051c800501f02802836b00531100530f", + "0x536b0050286220280fa00536b00502802002802836b00531300530f028", + "0x4f0280fb00536b0050fc0fa0073640280fc00536b0050fc00501b0280fc", + "0x2880000502804d0282d000536b0050fb0052150282d100536b00530d005", + "0x2836b00502300521c02802836b0050100057e802802836b005028007028", + "0x36b0051c800501f02802836b00531c00530f02802836b00504e00521c028", + "0x534c0282c80f900736b00531700507702802836b00531d00530f028028", + "0x2d000536b0052c80052150282d100536b00531a00504f02802836b0050f9", + "0x10200538e02810200536b0052d02c700702d0282c700536b005028023028", + "0x10400536b0051040057d20282d100536b0052d100504f02810400536b005", + "0x10110300736b0070073640070ac02802836b0050280070281042d1007005", + "0x4f02810b00536b00502828b02802836b00502800702810a2c52c6031801", + "0x36b00510b00530d02810c00536b00510100530d02810900536b005103005", + "0x36b0052c600504f02802836b00502800702802880200502804d0282c3005", + "0xb90282c300536b0052c500530d02810c00536b00510a00530d028109005", + "0x536b0050285e902811200536b00510c0050b90282c200536b0052c3005", + "0x58e02811300536b00511300503302802504e00736b00504e00535d028113", + "0x2802836b00502800702811911d0078032c111100736b007025113109031", + "0x51180050330282c02c100736b0052c100535d02811800536b00502872e", + "0x70282bc2be00780412111f00736b0071182c011103158e02811800536b", + "0x330282bb00536b00502872e02802836b00512100521c02802836b005028", + "0x1260078051242ba00736b0072bb2c111f03158e0282bb00536b0052bb005", + "0x51240050330282ba00536b0052ba00504f02802836b005028007028125", + "0x536b0072b90057de0282b912300736b0051242ba0077dd02812400536b", + "0x7e602812b00536b0052b70057e002802836b00502800702812c0058062b7", + "0x536b00502821302813100536b0052b60050b90282b600536b00512b005", + "0x1b0282b300536b00512300504f0282b500536b005130131007219028130", + "0x7e802802836b00502800702802880700502804d0282b200536b0052b5005", + "0x2802836b00504e00521c02802836b00502300521c02802836b005010005", + "0x2836b0051c800501f02802836b0052c200501f02802836b00511200501f", + "0x12300504f02802836b00513600534c02813813600736b00512c005077028", + "0x702802880800502804d02813500536b00513800521502813700536b005", + "0x21c02802836b0050100057e802802836b00512500521c02802836b005028", + "0x2802836b00511200501f02802836b00504e00521c02802836b005023005", + "0x2b100536b00502802002802836b0052c200501f02802836b0051c800501f", + "0x2b02b10073640282b000536b0052b000501b0282b000536b005028622028", + "0x13500536b0052af00521502813700536b00512600504f0282af00536b005", + "0x2802836b0052bc00521c02802836b00502800702802880800502804d028", + "0x2c12be0077dd0282c100536b0052c10050330282be00536b0052be00504f", + "0x50280070282ac0058092ad00536b00713e0057de02813e13f00736b005", + "0xb902814f00536b0052ab0057e60282ab00536b0052ad0057e002802836b", + "0x36b00514600501b0282b300536b00513f00504f02814600536b00514f005", + "0x2814800536b00514800501b02814800536b0052b21c80072190282b2005", + "0x2b30077eb02814a00536b00514a00501b02814a00536b0051482c20072e0", + "0x14d0100077ed02802836b0050280070282a800580a14d14b00736b00714a", + "0x36b00514b00504f0282aa00536b00504e1122a60313780282a600536b005", + "0x15515615703136b0052d60057d30282d600536b0052aa0055ea0280ee005", + "0x2803002815400536b00502315615703137802802836b00515500521c028", + "0x536b0051520057d102815200536b0051531540077d002815300536b005", + "0xee00700515100536b0051510057d20280ee00536b0050ee00504f028151", + "0x36b00502300521c02802836b0050100057e802802836b005028007028151", + "0x36b00502802002802836b00511200501f02802836b00504e00521c028028", + "0x736402816100536b00516100501b02816100536b005028245028150005", + "0x36b0052a40052150282a300536b0052a800504f0282a400536b005161150", + "0x36b0050100057e802802836b00502800702802880b00502804d0282a2005", + "0x511200501f02802836b00504e00521c02802836b00502300521c028028", + "0x2ac00507702802836b0051c800501f02802836b0052c200501f02802836b", + "0x13700536b00513f00504f02802836b0052a100534c0282a02a100736b005", + "0x1350057f00282a300536b00513700530c02813500536b0052a0005215028", + "0x11900521c02802836b00502800702802880b00502804d0282a200536b005", + "0x521c02802836b00502300521c02802836b0050100057e802802836b005", + "0x1f02802836b0051c800501f02802836b00511200501f02802836b00504e", + "0x2829e00536b00502862202829f00536b00502802002802836b0052c2005", + "0x11d00504f02829d00536b00529e29f00736402829e00536b00529e00501b", + "0x2829c00536b0050280230282a200536b00529d0052150282a300536b005", + "0x2a300504f02816c00536b00516a00538e02816a00536b0052a229c00702d", + "0x502800702816c2a300700516c00536b00516c0057d20282a300536b005", + "0x700501f02802836b0050100057e802802836b00536300521c02802836b", + "0x2802002802836b0051c800501f02802836b00504e00521c02802836b005", + "0x2816e00536b00516e00501b02816e00536b00502862202829a00536b005", + "0x29916f00702d02816f00536b00502802302829900536b00516e29a007364", + "0x2d00536b00502d00504f02817200536b00517100538e02817100536b005", + "0x21c02802836b00502800702817202d00700517200536b0051720057d2028", + "0x2817400536b00502872e02802836b00503000521c02802836b00504e005", + "0x1b03158e02817400536b00517400503302829703100736b00503100535d", + "0x521c02802836b00502800702829229300780c29414300736b007174297", + "0x2857200536b00557200503302857200536b00502872e02802836b005294", + "0x2836b00502800702829517900780d02428e00736b00757203114303158e", + "0x28e0077dd02802400536b00502400503302828e00536b00528e00504f028", + "0x2800702828700580e28800536b0072890057de02828928a00736b005024", + "0x2817f00536b0052860057e602828600536b0052880057e002802836b005", + "0x518218100721902818200536b00502821302818100536b00517f0050b9", + "0x2818600536b00518400501b02828500536b00528a00504f02818400536b", + "0x1f02802836b0050100057e802802836b00502800702802880f00502804d", + "0x18700736b00528700507702802836b0051c800501f02802836b005007005", + "0x18900521502828400536b00528a00504f02802836b00518700534c028189", + "0x29500521c02802836b00502800702802881000502804d02819000536b005", + "0x501f02802836b0051c800501f02802836b0050100057e802802836b005", + "0x1b02819100536b00502862202818f00536b00502802002802836b005007", + "0x517900504f02819200536b00519118f00736402819100536b005191005", + "0x2800702802881000502804d02819000536b00519200521502828400536b", + "0x3302829300536b00529300504f02802836b00529200521c02802836b005", + "0x18a0057de02818a28000736b0050312930077dd02803100536b005031005", + "0x536b0052810057e002802836b00502800702828b00581128100536b007", + "0x504f02819900536b0051970050b902819700536b00527d0057e602827d", + "0x36b0051861c800721902818600536b00519900501b02828500536b005280", + "0x2819b00536b00527c0070072e002827c00536b00527c00501b02827c005", + "0x27a00581227b19d00736b00719b2850077eb02819b00536b00519b00501b", + "0x36b00502823b02827800536b00527b0100077ed02802836b005028007028", + "0x2827400536b00527527627803137802827500536b005028032028276005", + "0x52710057d102827100536b0052732740077d002827300536b005028030", + "0x527000536b0052700057d202819d00536b00519d00504f02827000536b", + "0x502802002802836b0050100057e802802836b00502800702827019d007", + "0x36402826a00536b00526a00501b02826a00536b00502824502826f00536b", + "0x526d26b00702d02826b00536b00502802302826d00536b00526a26f007", + "0x2827a00536b00527a00504f02826600536b00526700538e02826700536b", + "0x57e802802836b00502800702826627a00700526600536b0052660057d2", + "0x7702802836b0051c800501f02802836b00500700501f02802836b005010", + "0x36b00528000504f02802836b00526300534c02826026300736b00528b005", + "0x702d02825f00536b00502802302819000536b005260005215028284005", + "0x36b00528400504f02825a00536b00525b00538e02825b00536b00519025f", + "0x2836b00502800702825a28400700525a00536b00525a0057d2028284005", + "0x36b00504e00535d02802836b00503000521c02802836b00536600521c028", + "0x581302836b00725900570b02836700536b00536700504f02825904e007", + "0x36b00504e00521c02802836b0051c800501f02802836b005028007028258", + "0x7d002825700536b0050280300281ae00536b005031007010031378028028", + "0x536700504f02825400536b0052560057d102825600536b0052571ae007", + "0x36b00502800702825436700700525400536b0052540057d202836700536b", + "0x503100535d0281b200536b00502872e02802836b00525800570e028028", + "0x36b0071b21b436703158e0281b200536b0051b20050330281b403100736b", + "0x2836b00525100521c02802836b00502800702824a250007814251253007", + "0x24600503302824403100736b00503100535d02824600536b00502872e028", + "0x281bf23c0078151bd24200736b00724624425303158e02824600536b005", + "0x536b0051bd00503302824200536b00524200504f02802836b005028007", + "0x81618b00536b00723a0057de02823a1c100736b0051bd2420077dd0281bd", + "0x23d0057e602823d00536b00518b0057e002802836b005028007028238005", + "0x2823100536b0050282130281c600536b0052350050b902823500536b005", + "0x23000501b02822e00536b0051c100504f02823000536b0052311c6007219", + "0x1c800501f02802836b00502800702802881700502804d02822d00536b005", + "0x521c02802836b00500700501f02802836b0050100057e802802836b005", + "0x2291cb00736b00523800507702802836b00504e00521c02802836b005031", + "0x522900521502822600536b0051c100504f02802836b0051cb00534c028", + "0x51bf00521c02802836b00502800702802881800502804d02822700536b", + "0x100057e802802836b00504e00521c02802836b0051c800501f02802836b", + "0x2802002802836b00503100521c02802836b00500700501f02802836b005", + "0x2822100536b00522100501b02822100536b00502862202822200536b005", + "0x22000521502822600536b00523c00504f02822000536b005221222007364", + "0x24a00521c02802836b00502800702802881800502804d02822700536b005", + "0x1d103100736b00503100535d02825000536b00525000504f02802836b005", + "0x7de02822321d00736b0051d12500077dd0281d100536b0051d1005033028", + "0x521b0057e002802836b0050280070281d300581921b00536b007223005", + "0x281d600536b0052180050b902821800536b00521a0057e602821a00536b", + "0x4e22e03174a02822d00536b0051d600501b02822e00536b00521d00504f", + "0x1c800721902802836b0050280070282131da00781a2161d800736b007031", + "0x36b0052190070072e002821900536b00521900501b02821900536b00522d", + "0x2820c00536b00502803002820d00536b00521620e01003137802820e005", + "0x1d800504f02820a00536b00520b0057d102820b00536b00520c20d0077d0", + "0x502800702820a1d800700520a00536b00520a0057d20281d800536b005", + "0x22d00501f02802836b0051c800501f02802836b00521300521c02802836b", + "0x2802002802836b00500700501f02802836b0050100057e802802836b005", + "0x2820800536b00520800501b02820800536b00502875702820900536b005", + "0x1e120300702d02820300536b0050280230281e100536b005208209007364", + "0x1da00536b0051da00504f0281ff00536b00520100538e02820100536b005", + "0x1f02802836b0050280070281ff1da0070051ff00536b0051ff0057d2028", + "0x2802836b00500700501f02802836b0050100057e802802836b0051c8005", + "0x736b0051d300507702802836b00504e00521c02802836b00503100521c", + "0x521502822600536b00521d00504f02802836b0051fd00534c0281fa1fd", + "0x536b0052271f300702d0281f300536b00502802302822700536b0051fa", + "0x57d202822600536b00522600504f02800000536b0051ee00538e0281ee", + "0x501800521c02802836b00502800702800022600700500000536b005000", + "0x4e00521c02802836b00500700501f02802836b0050100057e802802836b", + "0x2802002802836b00503100521c02802836b0051c800501f02802836b005", + "0x2857b00536b00557b00501b02857b00536b00502875702857a00536b005", + "0x57d57e00702d02857e00536b00502802302857d00536b00557b57a007364", + "0x1700536b00501700504f02858100536b00557f00538e02857f00536b005", + "0x502802836b00502836902858101700700558100536b0055810057d2028", + "0x3102802836b00502800702809204f00781b00b00a00736b007005028007", + "0x36b00500a00504f02801000536b00500700581c02800f00536b00500b005", + "0x81e04e1c800736b00701000581d02800f00536b00500f00509202800a005", + "0x4e00581f02801400536b00500f00503102802836b005028007028013005", + "0x1700536b00503000582102803000536b00504d00582002804d00536b005", + "0x55fa02801800536b00501703100736402801700536b00501700501b028", + "0x536b00501400509202800a00536b00500a00504f02836900536b0051c8", + "0xa5fc02801800536b00501800521502836900536b0053690055fb028014", + "0x36b00502800702801c01b36803100501c01b36803136b00501836901400a", + "0x502803002836700536b00500f00503102802836b0050130055fe028028", + "0x2000536b00501f0050f602801f00536b0053660310072cc02836600536b", + "0x200050f802836700536b00536700509202800a00536b00500a00504f028", + "0x500700582202802836b00502800702802036700a03100502000536b005", + "0x2802002836500536b00509200503102802836b00503100504002802836b", + "0x2802300536b00502300501b02802300536b00502804602836400536b005", + "0x2d36300702d02836300536b00502802302802d00536b005023364007364", + "0x4f00536b00504f00504f02808400536b0050c00052cb0280c000536b005", + "0x36504f03100508400536b0050840050f802836500536b005365005092028", + "0x582300a03100736b00700700500f02800700536b00500500500a028084", + "0x504f0051c802804f00536b00500a00501002802836b00502800702800b", + "0x2809200536b00509200501b02803100536b00503100501302809200536b", + "0x524f02802836b0050280070281c800582401000f00736b00703100500f", + "0x536b00504e00525202801300536b00500f00501302804e00536b005010", + "0x4d00536b00502803002802836b00502800702802882500502804d028014", + "0x3000525202801300536b0051c800501302803000536b00504d005050028", + "0x536b00501700535e02801701300736b00501300507102801400536b005", + "0x1002802836b00502800702836800582636900536b007014005009028018", + "0x36b00501c00501b02801c00536b00501b0051c802801b00536b005369005", + "0x36b00502800702801f00582736636700736b00701c02800708602801c005", + "0x1300500f02836700536b00536700504f02802836b005018005237028028", + "0x36b00536500524f02802836b00502800702836400582836502000736b007", + "0x4d02836300536b00502300525202802d00536b005020005013028023005", + "0x50500280c000536b00502803002802836b005028007028028829005028", + "0x536b00508400525202802d00536b00536400501302808400536b0050c0", + "0x35f00582a1aa00536b00736300500902836100536b00502d00535e028363", + "0x36b0050320051c802803200536b0051aa00501002802836b005028007028", + "0x3336c00736b00735d3670070ac02835d00536b00535d00501b02835d005", + "0x536b00503336609203182c02802836b00502800702803603c00c03182b", + "0x505b02836c00536b00536c00504f02835e00536b00504000582d028040", + "0x702835e36136c03100535e00536b00535e00582e02836100536b005361", + "0x1f02802836b00503600530f02802836b00503c00530f02802836b005028", + "0x35900536b00500c00504f02802836b00536600508e02802836b005092005", + "0x2802836b00535f00504702802836b00502800702802882f00502804d028", + "0x536b00536700504f02802836b00536600508e02802836b00509200501f", + "0x36100505b02821500536b00535600583002835600536b005028030028359", + "0x2800702821536135903100521500536b00521500582e02836100536b005", + "0x504f02802836b00501300501c02802836b00509200501f02802836b005", + "0x504702802836b00502800702802883100502804d02821c00536b00501f", + "0x4f02802836b00501300501c02802836b00509200501f02802836b005368", + "0x536b00504600583002804600536b00502803002821c00536b005028005", + "0x21c03100504800536b00504800582e02801800536b00501800505b028048", + "0x500b00535e02804700536b00502803002802836b005028007028048018", + "0x2802800536b00502800504f02823700536b00504700583002804500536b", + "0x23704502803100523700536b00523700582e02804500536b00504500505b", + "0xb00583302800b00536b00502883202800a03100736b005007005266028", + "0x4f00783402800f09204f03136b00500b0310280317e102800b00536b005", + "0xf01000783402802836b00502800702804e0058351c801000736b007092", + "0x501400500725b02802836b00502800702804d00583601401300736b007", + "0x2801800536b00502883202801700536b0051c803000725b02803000536b", + "0x2801b36836903136b00501800a0130317e102801800536b005018005833", + "0x36600583736701c00736b00736836900783402801700536b005017005278", + "0x2836500583802001f00736b00701b01c00783402802836b005028007028", + "0x536736400725b02836400536b00502001700725b02802836b005028007", + "0x2836300536b00502d02300773402802d00536b00502803002802300536b", + "0x50c000571c02801f00536b00501f00504f0280c000536b005363005735", + "0x2836b00501700526d02802836b0050280070280c001f0070050c000536b", + "0x536b00502824502808400536b00502802002802836b00536700508e028", + "0x4f0281aa00536b00536108400736402836100536b00536100501b028361", + "0x2883900502804d02803200536b0051aa00521502835f00536b005365005", + "0x2836b00501b00530f02802836b00501700526d02802836b005028007028", + "0x36b00536c00501b02836c00536b00502824502835d00536b005028020028", + "0x2835f00536b00536600504f02803300536b00536c35d00736402836c005", + "0x503200c00702d02800c00536b00502802302803200536b005033005215", + "0x2835f00536b00535f00504f02803600536b00503c00571b02803c00536b", + "0x530f02802836b00502800702803635f00700503600536b00503600571c", + "0x2002802836b0051c800508e02802836b00500500526d02802836b00500a", + "0x35e00536b00535e00501b02835e00536b00502824502804000536b005028", + "0x521502835600536b00504d00504f02835900536b00535e040007364028", + "0x530f02802836b00502800702802883a00502804d02821500536b005359", + "0x2002802836b00500f00530f02802836b00500500526d02802836b00500a", + "0x4600536b00504600501b02804600536b00502824502821c00536b005028", + "0x521502835600536b00504e00504f02804800536b00504621c007364028", + "0x536b00521504700702d02804700536b00502802302821500536b005048", + "0x571c02835600536b00535600504f02823700536b00504500571b028045", + "0x502800700502802836b00502836902823735600700523700536b005237", + "0x500b00503102802836b00502800702809204f00783b00b00a00736b007", + "0x281c803100736b00503100535d02801000536b0050280e102800f00536b", + "0x101c80072a002800f00536b00500f00509202800a00536b00500a00504f", + "0x2804e00536b00500f00503102802836b00502800702802883c02836b007", + "0x501300700725b02801300536b00501300533202801300536b005028377", + "0x9202804d00536b00504d00503302804d00536b0050280e102801400536b", + "0x4d03100a03158e02801400536b00501400527802804e00536b00504e005", + "0x504e00503102802836b00502800702836901800783d01703000736b007", + "0x2836800536b00536800509202803000536b00503000504f02836800536b", + "0x36803000a73102801700536b00501700503302801400536b005014005278", + "0x2802836b00502800702836701c01b03100536701c01b03136b005017014", + "0x536b00504e00503102802836b00501400526d02802836b00536900521c", + "0x502000501b02802000536b00502862202801f00536b005028020028366", + "0x2836400536b00502802302836500536b00502001f00736402802000536b", + "0x1800504f02802d00536b00502300571b02802300536b00536536400702d", + "0x2d00536b00502d00571c02836600536b00536600509202801800536b005", + "0x3102802836b00503100521c02802836b00502800702802d366018031005", + "0x536b0050c00053320280c000536b00502873202836300536b00500f005", + "0x773402836100536b00502803002808400536b0050c000700725b0280c0", + "0x36b00500a00504f02835f00536b0051aa0057350281aa00536b005361084", + "0x3100535f00536b00535f00571c02836300536b00536300509202800a005", + "0x3100521c02802836b00500700526d02802836b00502800702835f36300a", + "0x4602835d00536b00502802002803200536b00509200503102802836b005", + "0x36b00536c35d00736402836c00536b00536c00501b02836c00536b005028", + "0x71b02803c00536b00503300c00702d02800c00536b005028023028033005", + "0x36b00503200509202804f00536b00504f00504f02803600536b00503c005", + "0x50050050dc02803603204f03100503600536b00503600571c028032005", + "0x2836b00502800702803100583e02836b00700700534802800700500736b", + "0x702802800500502800536b00502800525302802836b00500500501f028", + "0x3302800a00536b00502803202802836b00503100534602802836b005028", + "0x36b00502823f02800b00536b00500a0280071b402800a00536b00500a005", + "0xf00536b00504f09200732c02809200500736b0050050050dc02804f005", + "0xf00534802800b00536b00500b00525302800f00536b00500f00501b028", + "0x2802836b00500500501f02802836b00502800702801000583f02836b007", + "0x1000534602802836b00502800702800b00500500b00536b00500b005253", + "0x1b40281c800536b0051c80050330281c800536b00502803202802836b005", + "0x36b0050050050dc02801300536b0050282d702804e00536b0051c800b007", + "0x4d00536b00504d00501b02804d00536b00501301400732c028014005007", + "0x702803000584002836b00704d00534802804e00536b00504e005253028", + "0x504e00536b00504e00525302802836b00500500501f02802836b005028", + "0x36b00502803202802836b00503000534602802836b00502800702804e005", + "0x2801800536b00501704e0071b402801700536b005017005033028017005", + "0x36936800732c02836800500736b0050050050dc02836900536b005028841", + "0x1800536b00501800525302801b00536b00501b00501b02801b00536b005", + "0x500501f02802836b00502800702801c00584202836b00701b005348028", + "0x2836b00502800702801800500501800536b00501800525302802836b005", + "0x36b00536700503302836700536b00502803202802836b00501c005346028", + "0xdc02801f00536b00502884302836600536b0053670180071b4028367005", + "0x36500501b02836500536b00501f02000732c02802000500736b005005005", + "0x84402836b00736500534802836600536b00536600525302836500536b005", + "0x536600525302802836b00500500501f02802836b005028007028364005", + "0x2802836b00536400534602802836b00502800702836600500536600536b", + "0x50233660071b402802300536b00502300503302802300536b005028032", + "0x280c000500736b0050050050dc02836300536b00502884502802d00536b", + "0x2d00525302808400536b00508400501b02808400536b0053630c000732c", + "0x2836b00502800702836100584602836b00708400534802802d00536b005", + "0x702802d00500502d00536b00502d00525302802836b00500500501f028", + "0x330281aa00536b00502803202802836b00536100534602802836b005028", + "0x36b00502884702835f00536b0051aa02d0071b40281aa00536b0051aa005", + "0x36c00536b00503235d00732c02835d00500736b0050050050dc028032005", + "0x36c00534802835f00536b00535f00525302836c00536b00536c00501b028", + "0x2802836b00500500501f02802836b00502800702803300584802836b007", + "0x3300534602802836b00502800702835f00500535f00536b00535f005253", + "0x1b402800c00536b00500c00503302800c00536b00502803202802836b005", + "0x36b0050050050dc02803600536b00502860d02803c00536b00500c35f007", + "0x35e00536b00535e00501b02835e00536b00503604000732c028040005007", + "0x702835900584902836b00735e00534802803c00536b00503c005253028", + "0x503c00536b00503c00525302802836b00500500501f02802836b005028", + "0x36b00502803202802836b00535900534602802836b00502800702803c005", + "0x2821500536b00535603c0071b402835600536b005356005033028356005", + "0x21c04600732c02804600500736b0050050050dc02821c00536b00502884a", + "0x21500536b00521500525302804800536b00504800501b02804800536b005", + "0x500501f02802836b00502800702804700584b02836b007048005348028", + "0x2836b00502800702821500500521500536b00521500525302802836b005", + "0x36b00504500503302804500536b00502803202802836b005047005346028", + "0xdc02823900536b00502884c02823700536b0050452150071b4028045005", + "0x23f00501b02823f00536b00523923b00732c02823b00500736b005005005", + "0x84d02836b00723f00534802823700536b00523700525302823f00536b005", + "0x523700525302802836b00500500501f02802836b005028007028245005", + "0x2802836b00524500534602802836b00502800702823700500523700536b", + "0x52492370071b402824900536b00524900503302824900536b005028032", + "0x2824e00500736b0050050050dc02824d00536b00502833902824c00536b", + "0x24c00525302824f00536b00524f00501b02824f00536b00524d24e00732c", + "0x2836b00502800702825200584e02836b00724f00534802824c00536b005", + "0x702824c00500524c00536b00524c00525302802836b00500500501f028", + "0x3302805000536b00502803202802836b00525200534602802836b005028", + "0x36b00502884f02800900536b00505024c0071b402805000536b005050005", + "0x5900536b00505b05800732c02805800500736b0050050050dc02805b005", + "0x5900534802800900536b00500900525302805900536b00505900501b028", + "0x2802836b00500500501f02802836b00502800702805c00585002836b007", + "0x5c00534602802836b00502800702800900500500900536b005009005253", + "0x1b402825c00536b00525c00503302825c00536b00502803202802836b005", + "0x36b0050050050dc02825e00536b0050280d202825d00536b00525c009007", + "0x6000536b00506000501b02806000536b00525e05e00732c02805e005007", + "0x702805f00585102836b00706000534802825d00536b00525d005253028", + "0x525d00536b00525d00525302802836b00500500501f02802836b005028", + "0x36b00502803202802836b00505f00534602802836b00502800702825d005", + "0x2829600536b00505d25d0071b402805d00536b00505d00503302805d005", + "0x29804200732c02804200500736b0050050050dc02829800536b005028852", + "0x29600536b00529600525302806700536b00506700501b02806700536b005", + "0x500501f02802836b0050280070282bd00585302836b007067005348028", + "0x2836b00502800702829600500529600536b00529600525302802836b005", + "0x36b00506900503302806900536b00502803202802836b0052bd005346028", + "0xdc02800600536b00502885402806800536b0050692960071b4028069005", + "0x7100501b02807100536b00500606f00732c02806f00500736b005005005", + "0x85502836b00707100534802806800536b00506800525302807100536b005", + "0x506800525302802836b00500500501f02802836b005028007028325005", + "0x2802836b00532500534602802836b00502800702806800500506800536b", + "0x50740680071b402807400536b00507400503302807400536b005028032", + "0x2834c00536b00507700500732c02807700536b00502823902807500536b", + "0x734c00534802807500536b00507500525302834c00536b00534c00501b", + "0x507500536b00507500525302802836b00502800702834b00585602836b", + "0x36b00502803202802836b00534b00534602802836b005028007028075005", + "0x2807a00536b0050430750071b402804300536b005043005033028043005", + "0x9204f00b03136b00500a00576e02807a00500507a00536b00507a005253", + "0x1003136b00709200f00700500a85702800f00b00736b00500b00521a028", + "0x536b00501000509202802836b00502800702804d01401303185804e1c8", + "0x50c002804e00536b00504e00522202803000536b005010005031028010", + "0x536b00704e00522102803000536b0050300050920281c800536b0051c8", + "0x85a02836900536b00503000503102802836b005028007028018005859017", + "0x36900536b00536900509202801b00536b00502885b02836800536b005028", + "0x36900a22902801b00536b00501b00519702836800536b005368005197028", + "0x2836b00502800702836502001f03185c36636701c03136b00701b3681c8", + "0x36600522202836400536b00501c00503102801c00536b00501c005092028", + "0x36400536b00536400509202836700536b0053670050c002836600536b005", + "0x503102802836b00502800702802d00585d02300536b007366005221028", + "0xc000736b0050c00057aa0280c000536b00502885e02836300536b005364", + "0x317ac02836300536b00536300509202808400536b0050840057ab028084", + "0x35e04003185f03603c00c03336c35d03235f1aa3611c836b00708400b028", + "0x3636100728502835600536b00536300503102802836b005028007028359", + "0x36b00500c21c00728502821c00536b00503c21500728502821500536b005", + "0x4700536b00536c04800728502804800536b005033046007285028046005", + "0x28502823700536b00503204500728502804500536b00535d047007285028", + "0x523900504f02823b00536b0051aa0057ae02823900536b00535f237007", + "0x23f23b00736b00523b00521a02803100536b00503100519702823900536b", + "0x2824924500736b00523f0312390317af02823f00536b00523f005197028", + "0x2450317b002824c00536b00524c0057ab02824c0c000736b0050c00057aa", + "0x2836b00524e0057b102805805b00905025224f24e24d00f36b00524c249", + "0x28502805c00536b00505b05900728502805900536b00505824d007285028", + "0x25d00728502825d00536b00505025c00728502825c00536b00500905c007", + "0x6000736b00505e00526602805e00536b00502877602825e00536b005252", + "0x9202805f00536b00505f00530d02829605d00736b00524f00526602805f", + "0x6700786004229800736b00729605f25e03117f02835600536b005356005", + "0x36b00502803002806900536b00535600503102802836b0050280070282bd", + "0x9202806f00536b00529800504f02800600536b005068005345028068005", + "0x36b00500600507d02832500536b00504200530d02807100536b005069005", + "0x36b00535600503102802836b00502800702802886100502804d028074005", + "0x504f02834c00536b00507700508102807700536b005028030028075005", + "0x536b0052bd00530d02807100536b00507500509202806f00536b005067", + "0x3117f02806000536b00506000530d02807400536b00534c00507d028325", + "0x3102802836b00502800702807907a00786204334b00736b00705d06006f", + "0x36b00507f00509202834800536b00534b00504f02807f00536b005071005", + "0x4d02834600536b00532500530d02807d00536b00504300530d028081005", + "0x28702834500536b00507100503102802836b005028007028028863005028", + "0x536b00534500509202834400536b00534400530d02834400536b005028", + "0x502800702833d34100786434234300736b00734432507a03117f028345", + "0x9202834800536b00534300504f02808c00536b00534500503102802836b", + "0x36b00534200530d02807d00536b00507900530d02808100536b00508c005", + "0x2802836b00502800702833b00586533c00536b0070740050fc028346005", + "0x36b00534800504f02808a00536b00508100503102802836b00533c005047", + "0x7af02823b00536b00523b00519702804f00536b00504f005197028348005", + "0x317b00280c000536b0050c00057ab02833933a00736b00523b04f348031", + "0x36b0053380057b102833337708e08633633733808800f36b0050c033933a", + "0x2833100536b00537733200728502833200536b005333088007285028028", + "0x728502832f00536b00508633000728502833000536b00508e331007285", + "0x508a00509202832d00536b00534607d00727d02832e00536b00533632f", + "0x2832e00536b00532e00504f02832d00536b00532d00519702808a00536b", + "0x2800702832632932a03186732b08b32c03136b00732d02336708a00a866", + "0x2808500536b00532c00503102832c00536b00532c00509202802836b005", + "0x8b08500a86602832b00536b00532b00578c02808500536b005085005092", + "0x2802836b00502800702809632309803186832409509303136b007337017", + "0x532200509202832200536b00509300503102809300536b005093005092", + "0x36b00732432b09532200a86902832400536b00532400578c02832200536b", + "0x532100509202802836b00502800702831b31c31d03186a31e31f321031", + "0x2831900536b00531e00586b02831a00536b00532100503102832100536b", + "0x532e00504f02831700536b00531800586d02831800536b00531900586c", + "0x2831f00536b00531f0050c002831a00536b00531a00509202832e00536b", + "0x2802836b00502800702831731f31a32e00a00531700536b00531700586e", + "0x36b00502802302831600536b00531d00503102831d00536b00531d005092", + "0x2831100536b00531300586f02831300536b00531b31400702d028314005", + "0x531c0050c002831600536b00531600509202832e00536b00532e00504f", + "0x2800702831131c31632e00a00531100536b00531100586e02831c00536b", + "0x3102809800536b00509800509202802836b00532b00522002802836b005", + "0x36b00509631000702d02831000536b0050280230280a900536b005098005", + "0x9202832e00536b00532e00504f0280ac00536b0050b000586f0280b0005", + "0x36b0050ac00586e02832300536b0053230050c00280a900536b0050a9005", + "0x36b00501700522002802836b0050280070280ac3230a932e00a0050ac005", + "0x32a00503102832a00536b00532a00509202802836b005337005259028028", + "0xb400536b00532630d00702d02830d00536b00502802302830f00536b005", + "0x30f00509202832e00536b00532e00504f0280b600536b0050b400586f028", + "0xb600536b0050b600586e02832900536b0053290050c002830f00536b005", + "0x2802836b00533b00504702802836b0050280070280b632930f32e00a005", + "0x2836b00534600530f02802836b00501700522002802836b00507d00530f", + "0x36b00523b00525902802836b0050c00057c402802836b005023005220028", + "0x34800504f02830b00536b00508100503102802836b00504f005259028028", + "0x702802887000502804d02830900536b00530b0050920280b900536b005", + "0x22002802836b00507900530f02802836b00533d00530f02802836b005028", + "0x2802836b00502300522002802836b00507400534402802836b005017005", + "0x2836b00504f00525902802836b00523b00525902802836b0050c00057c4", + "0x3080050920280b900536b00534100504f02830800536b005345005031028", + "0x1b02830600536b00502887102830700536b00502802002830900536b005", + "0x36b00502802302830500536b00530630700736402830600536b005306005", + "0x2830300536b00530400586f02830400536b0053050bf00702d0280bf005", + "0x53670050c002830900536b0053090050920280b900536b0050b900504f", + "0x280070283033673090b900a00530300536b00530300586e02836700536b", + "0x525902802836b00503100525902802836b00501700522002802836b005", + "0x3102802836b0050c00057c402802836b00502300522002802836b00504f", + "0x35e05100728502805100536b00535904000728502830200536b005363005", + "0x1b02839500536b00502824502839400536b00502802002839300536b005", + "0x36b0050280230280dc00536b00539539400736402839500536b005395005", + "0x280c600536b0050c700586f0280c700536b0050dc39600702d028396005", + "0x53670050c002830200536b00530200509202839300536b00539300504f", + "0x280070280c636730239300a0050c600536b0050c600586e02836700536b", + "0x522002802836b00500b00525902802836b00502d00504702802836b005", + "0x3102802836b00504f00525902802836b00503100525902802836b005017", + "0xcf00536b0050282450280cb00536b0050280200280c900536b005364005", + "0x509202830100536b0050cf0cb0073640280cf00536b0050cf00501b028", + "0x536b00530100521502830c00536b0053670050c002839700536b0050c9", + "0x2836b00500b00525902802836b00502800702802887200502804d028398", + "0x36b00504f00525902802836b00503100525902802836b005017005220028", + "0x50920282fb00536b00501f00503102801f00536b00501f005092028028", + "0x536b00536500521502830c00536b0050200050c002839700536b0052fb", + "0x586f0282fa00536b0053980d400702d0280d400536b005028023028398", + "0x536b00539700509202802800536b00502800504f0280d500536b0052fa", + "0x2800a0050d500536b0050d500586e02830c00536b00530c0050c0028397", + "0x3100525902802836b00500b00525902802836b0050280070280d530c397", + "0x87302839900536b00503000503102802836b00504f00525902802836b005", + "0x36b0052f700586d0282f700536b0052f800586c0282f800536b005018005", + "0xc002839900536b00539900509202802800536b00502800504f0282f1005", + "0x2f11c839902800a0052f100536b0052f100586e0281c800536b0051c8005", + "0x2836b00503100525902802836b00500b00525902802836b005028007028", + "0x501300503102801300536b00501300509202802836b00504f005259028", + "0x282ec00536b00504d2ee00702d0282ee00536b0050280230280da00536b", + "0x50da00509202802800536b00502800504f0280d200536b0052ec00586f", + "0x50d200536b0050d200586e02801400536b0050140050c00280da00536b", + "0x2800f00536b00502805f02804f00536b0050288740280d20140da02800a", + "0xa36b00700a03100503121802802836b00502836902802836b00502824c", + "0x501000509202802836b00502800702804d01401303187504e1c8092010", + "0x1700536b00504e1c800787602803000536b00501000503102801000536b", + "0x36900587902802836b00501800587802836901800736b005017005877028", + "0x1b00536b00536800587b02836800536b00536900587a02836900536b005", + "0x502800504f02836700536b00501b00527b02801c00536b00502827c028", + "0x2800700536b00500700530702803000536b00503000509202802800536b", + "0x9200f0072bd02801c00536b00501c00527802836700536b00536700527a", + "0x2802000b01f36600a36b00501c36700703002800b87c02809200536b005", + "0x2836400587e36500536b00702000527502800b00536b00500b04f00787d", + "0x3136b00536500527402802300536b00501f00503102802836b005028007", + "0x2837702802836b0050c000504702802836b00502d0052730280c036302d", + "0x2836600536b00536600504f02836100536b00502803202808400536b005", + "0x508400533202836300536b00536300527802802300536b005023005092", + "0x536108436302336600b27102836100536b00536100503302808400536b", + "0x502800702836c00587f35d00536b00703200527002803235f1aa03136b", + "0x2803c00c00736b00535d00526f02803300536b00535f00503102802836b", + "0x503600526d02804003600736b00500c00526a02802836b00503c005047", + "0x26702803300536b00503300509202835e00536b00504000526b02802836b", + "0x36b00502800702804804621c03188021535635903136b00735e092033031", + "0x526602804700536b00535900503102835900536b005359005092028028", + "0x523700b00788102823700536b00523700530d02823704500736b005215", + "0x736b00504523900788102804500536b00504500530d02823b23900736b", + "0x583302824500536b00524500530d02824900536b00502888202824523f", + "0x530f02824e24d24c03136b0052492451aa0317e102824900536b005249", + "0x25200536b00523b0050b902824f00536b00524e0050b902802836b00524d", + "0x900501b02800900536b00505024f00721902805000536b005028213028", + "0x536b0052520090072e002825200536b00525200501b02800900536b005", + "0x588402805900536b00505800588302805800536b00505b00520a02805b", + "0x536b00504700509202824c00536b00524c00504f02805c00536b005059", + "0x588502835600536b0053560050c002823f00536b00523f005307028047", + "0x9202802836b00502800702805c35623f04724c00b00505c00536b00505c", + "0x36b0051aa00504f02825c00536b00521c00503102821c00536b00521c005", + "0x21502805e00536b0050460050c002825e00536b00525c00509202825d005", + "0x3102802836b00502800702802888600502804d02806000536b005048005", + "0x505d00534c02829605d00736b00536c00507702805f00536b00535f005", + "0xc002825e00536b00505f00509202825d00536b0051aa00504f02802836b", + "0x2888600502804d02806000536b00529600521502805e00536b005092005", + "0x36b00536400507702829800536b00501f00503102802836b005028007028", + "0x9202825d00536b00536600504f02802836b00504200534c028067042007", + "0x36b00506700521502805e00536b0050920050c002825e00536b005298005", + "0x88702806900536b0050602bd00702d0282bd00536b005028023028060005", + "0x36b00525e00509202825d00536b00525d00504f02806800536b005069005", + "0x88502805e00536b00505e0050c002800b00536b00500b00530702825e005", + "0x2802836b00502800702806805e00b25e25d00b00506800536b005068005", + "0x536b00501300509202802836b00500f00504202802836b00504f005888", + "0x6f00702d02806f00536b00502802302800600536b005013005031028013", + "0x536b00502800504f02832500536b00507100588702807100536b00504d", + "0x50c002800700536b00500700530702800600536b005006005092028028", + "0x32501400700602800b00532500536b00532500588502801400536b005014", + "0x28602804f00b00736b00500700526602800a03100736b005005005266028", + "0x9200718402800f00b00736b00500b00528602809203100736b005031005", + "0x4f00528602801300536b00504e02800728502804e1c801003136b00500f", + "0x1300728502801703004d03136b00501403100718402801404f00736b005", + "0x1c01b00788936836900736b00703001001803118602801800536b005017", + "0x536b00536900504f02836700536b00502888a02802836b005028007028", + "0x2804d02802000536b00536700588b02801f00536b00536800530d028366", + "0x1b00504f02836500536b00502888d02802836b00502800702802888c005", + "0x2000536b00536500588b02801f00536b00501c00530d02836600536b005", + "0x36302d02303136b00500b36400718402836400a00736b00500a005286028", + "0x36108400736b00702d01f0c00311860280c000536b005363366007285028", + "0x504f02803200536b00502888a02802836b00502800702835f1aa00788e", + "0x536b00503200588b02836c00536b00536100530d02835d00536b005084", + "0xc00536b00502888d02802836b00502800702802888f00502804d028033", + "0xc00588b02836c00536b00535f00530d02835d00536b0051aa00504f028", + "0x2835e04000789003603c00736b00702304d35d03118602803300536b005", + "0x35600536b00503c00504f02835900536b00502888a02802836b005028007", + "0x502804d02821c00536b00535900588b02821500536b00503600530d028", + "0x504000504f02804600536b00502888d02802836b005028007028028891", + "0x2821c00536b00504600588b02821500536b00535e00530d02835600536b", + "0x2823700536b00504535600728502804504704803136b00504f00a007184", + "0x2836b00502800702824523f00789223b23900736b007047215237031186", + "0x523b00530d02824c00536b00523900504f02824900536b00502888a028", + "0x2800702802889300502804d02824e00536b00524900588b02824d00536b", + "0x30d02824c00536b00523f00504f02824f00536b00502888d02802836b005", + "0x503302000789402824e00536b00524f00588b02824d00536b005245005", + "0x2805000536b00505000530d02805000536b00525200589502825200536b", + "0x2836b00502800702805905800789605b00900736b00705024d24c031186", + "0x505b00530d02825c00536b00500900504f02805c00536b00502888a028", + "0x2800702802889700502804d02825e00536b00505c00588b02825d00536b", + "0x30d02825c00536b00505800504f02805e00536b00502888d02802836b005", + "0x524e21c00789402825e00536b00505e00588b02825d00536b005059005", + "0x5f00536b00525e06000789902806000536b00506000589802806000536b", + "0x25c03118602805d00536b00505d00530d02805d00536b00505f00589a028", + "0x504f02802836b00502800702806704200789b29829600736b00705d048", + "0x2802889c00502804d02806900536b00529800530d0282bd00536b005296", + "0x536b00506700530d0282bd00536b00504200504f02802836b005028007", + "0x2bd00536b0052bd00504f02806800536b00506925d36c1c800a89d028069", + "0x736b00700502800789f0280682bd00700506800536b00506800589e028", + "0x2800b00536b0050310058a102802836b00502800702800a0058a0031007", + "0x1700b0058a302800700536b00500700504f02800b00536b00500b0058a2", + "0x58a904e0058a81c80058a70100058a600f0058a50920058a404f00536b", + "0x8b03690058af0180058ae0170058ad0300058ac04d0058ab0140058aa013", + "0x36b00504f00504702802836b00502800702801c0058b201b0058b1368005", + "0x502804d02836600536b00536700583302836700536b0050288b3028028", + "0x36b0050288b502802836b00509200504702802836b0050280070280288b4", + "0x50280070280288b400502804d02836600536b00501f00583302801f005", + "0x2000583302802000536b0050288b602802836b00500f00504702802836b", + "0x1000504702802836b0050280070280288b400502804d02836600536b005", + "0x4d02836600536b00536500583302836500536b0050288b702802836b005", + "0x2888202802836b0051c800504702802836b0050280070280288b4005028", + "0x70280288b400502804d02836600536b00536400583302836400536b005", + "0x83302802300536b0050288b802802836b00504e00504702802836b005028", + "0x4702802836b0050280070280288b400502804d02836600536b005023005", + "0x36600536b00502d00583302802d00536b0050288b902802836b005013005", + "0x2802836b00501400504702802836b0050280070280288b400502804d028", + "0x288b400502804d02836600536b00536300583302836300536b0050288ba", + "0xc000536b00502883202802836b00504d00504702802836b005028007028", + "0x2836b0050280070280288b400502804d02836600536b0050c0005833028", + "0x36b00508400583302808400536b0050288bb02802836b005030005047028", + "0x36b00501700504702802836b0050280070280288b400502804d028366005", + "0x502804d02836600536b00536100583302836100536b0050288bc028028", + "0x36b0050288bd02802836b00501800504702802836b0050280070280288b4", + "0x50280070280288b400502804d02836600536b0051aa0058330281aa005", + "0x35f00583302835f00536b0050288be02802836b00536900504702802836b", + "0x36800504702802836b0050280070280288b400502804d02836600536b005", + "0x4d02836600536b00503200583302803200536b0050288bf02802836b005", + "0x2839a02802836b00501b00504702802836b0050280070280288b4005028", + "0x70280288b400502804d02836600536b00535d00583302835d00536b005", + "0x83302836c00536b0050288c002802836b00501c00504702802836b005028", + "0x36b0050330058c202803300536b0053660058c102836600536b00536c005", + "0x700500c00536b00500c0058c302800700536b00500700504f02800c005", + "0x36b0050288c402803c00536b00502802002802836b00502800702800c007", + "0x2804000536b00503603c00736402803600536b00503600501b028036005", + "0x53590058c502835900536b00504035e00702d02835e00536b005028023", + "0x535600536b0053560058c302800a00536b00500a00504f02835600536b", + "0x8c604f00b00736b00700502800700502802836b00502836902835600a007", + "0x564402801000536b00504f00503102802836b00502800702800f092007", + "0x2800b00536b00500b00504f02802836b00502800b0281c800536b005031", + "0x280140058c701304e00736b0071c800564502801000536b005010005092", + "0x536b00501300564602804d00536b00501000503102802836b005028007", + "0x564802801800536b00504e00564702801700536b00504d005092028030", + "0x503102802836b0050280070280288c800502804d02836900536b005030", + "0x1c00536b00501b00564902801b00536b00502803002836800536b005010", + "0x1c00564802801800536b00501400564702801700536b005368005092028", + "0x36600536b00736900564a02836700536b00501800527b02836900536b005", + "0x501700503102802836b00502836902802836b00502800702801f0058c9", + "0x2836400536b00536500537f02836500536b00536600564b02802000536b", + "0x500a00527802800700536b00500700530702800b00536b00500b00504f", + "0x36b00536400a00700b00a8ca02836400536b00536400519702800a00536b", + "0xc000536b00736300527002802000536b00502000509202836302d023031", + "0x526f02836100536b00502000503102802836b0050280070280840058cb", + "0x536b00502300504f02802836b00535f00504702835f1aa00736b0050c0", + "0x527a02802d00536b00502d00530702836100536b005361005092028023", + "0x36702d36102300b87c0281aa00536b0051aa00527802836700536b005367", + "0x2836b00502800702803336c35d03200a00503336c35d03200a36b0051aa", + "0x508400564d02800c00536b00502000503102802836b005367005273028", + "0x2800c00536b00500c00509202802300536b00502300504f02803c00536b", + "0x2d00c02300a00503c00536b00503c00564e02802d00536b00502d005307", + "0x2836b00501f00504702802836b00502836902802836b00502800702803c", + "0xa36703164f02804000536b00502803002803600536b005017005031028", + "0x536b00500b00504f02835900536b00535e00565002835e00536b005040", + "0x564e02800700536b00500700530702803600536b00503600509202800b", + "0x527302802836b00502800702835900703600b00a00535900536b005359", + "0x2835600536b00500f00503102802836b00500a00526d02802836b005031", + "0x536b00521c00501b02821c00536b00502804602821500536b005028020", + "0x702d02804800536b00502802302804600536b00521c21500736402821c", + "0x36b00509200504f02804500536b00504700564d02804700536b005046048", + "0x64e02800700536b00500700530702835600536b005356005092028092005", + "0xa00736b00503100526602804500735609200a00504500536b005045005", + "0x30d02800f00536b00502883202809204f00736b00500b00500788102800b", + "0xf0920280317e102800f00536b00500f00583302809200536b005092005", + "0x71c801000783402804f00536b00504f00530702804e1c801003136b005", + "0x36b00704e01300783402802836b00502800702804d0058cc01401300736b", + "0x536b00501700700725b02802836b0050280070280180058cd017030007", + "0x1c01b00736b00500a04f00788102836800536b00501436900725b028369", + "0x536700583302801c00536b00501c00530d02836700536b005028832028", + "0x536800527802802001f36603136b00536701c0300317e102836700536b", + "0x36500736b00701f36600783402801b00536b00501b00530702836800536b", + "0x36302d00736b00702036500783402802836b0050280070280230058ce364", + "0x25b02808400536b00536336800725b02802836b0050280070280c00058cf", + "0x51aa3610077340281aa00536b00502803002836100536b005364084007", + "0x2802d00536b00502d00504f02803200536b00535f00573502835f00536b", + "0x3201b02d03100503200536b00503200571c02801b00536b00501b005307", + "0x2836b00536400508e02802836b00536800526d02802836b005028007028", + "0x36b00536c00501b02836c00536b00502824502835d00536b005028020028", + "0x2800c00536b0050c000504f02803300536b00536c35d00736402836c005", + "0x2802836b0050280070280288d000502804d02803c00536b005033005215", + "0x3600536b00502802002802836b00502000530f02802836b00536800526d", + "0x4003600736402804000536b00504000501b02804000536b005028245028", + "0x3c00536b00535e00521502800c00536b00502300504f02835e00536b005", + "0x35600571b02835600536b00503c35900702d02835900536b005028023028", + "0x1b00536b00501b00530702800c00536b00500c00504f02821500536b005", + "0x2802836b00502800702821501b00c03100521500536b00521500571c028", + "0x2836b00501400508e02802836b00500a00530f02802836b00500700526d", + "0x36b00504600501b02804600536b00502824502821c00536b005028020028", + "0x2804700536b00501800504f02804800536b00504621c007364028046005", + "0x2802836b0050280070280288d100502804d02804500536b005048005215", + "0x2836b00504e00530f02802836b00500a00530f02802836b00500700526d", + "0x36b00523900501b02823900536b00502824502823700536b005028020028", + "0x2804700536b00504d00504f02823b00536b005239237007364028239005", + "0x504523f00702d02823f00536b00502802302804500536b00523b005215", + "0x2804700536b00504700504f02824900536b00524500571b02824500536b", + "0x24904f04703100524900536b00524900571c02804f00536b00504f005307", + "0x1d31ee02800a0280310070050281ff1d31ee02800a1871d31ee02800a07f", + "0x1d31ee02800a1871d31ee02800a2ee0310070050281ff1d31ee02800a187", + "0x310070050281ff1d31ee02800a1871d31ee02800a2940310070050281ff", + "0x1d31ee02800a8d20310070050281ff1d31ee02800a1871d31ee02800a609", + "0x1d31ee02800a1871d31ee02800a8d30310070050281ff1d31ee02800a187", + "0x310070050281ff1d31ee02800a1871d31ee02800a8d40310070050281ff", + "0x1d31ee02800a8d60310070050281ff1d31ee02800a1871d31ee02800a8d5", + "0x1d31ee02800a1871d31ee02800a8d70310070050281ff1d31ee02800a187", + "0x310070050281ff1d31ee02800a1871d31ee02800a8d80310070050281ff", + "0x1d31ee02800a8da0310070050281ff1d31ee02800a1871d31ee02800a8d9", + "0x1d31ee02800a1871d31ee02800a8db0310070050281ff1d31ee02800a187", + "0x310070050281ff1d31ee02800a1871d31ee02800a8dc0310070050281ff", + "0xa8de00a0310070050281ff1d31ee24202800b1871d31ee24202800b8dd", + "0xa1871d31ee02800a8df0310070050281ff1d31ee02800a1871d31ee028", + "0x281ff1d31ee02800a1871d31ee02800a8e00310070050281ff1d31ee028", + "0xb8e20310070050281ff1d31ee02800a1871d31ee02800a8e1031007005", + "0x1ee02800a8e300a0310070050281ff1d31ee04002800b1871d31ee040028", + "0x1ee02800a1871d31ee02800a8e40310070050281ff1d31ee02800a1871d3", + "0x70050281ff1d31ee02800a1871d31ee02800a8e50310070050281ff1d3", + "0x1ee02800a8e70310070050281ff1d31ee02800a1871d31ee02800a8e6031", + "0x1ee02800a1871d31ee02800a8e80310070050281ff1d31ee02800a1871d3", + "0x70050281ff1d31ee02800a1871d31ee02800a8e90310070050281ff1d3", + "0x8eb00a0310070050281ff1d31ee02825600b1871d31ee02825600b8ea031", + "0xb00a0310070050281ff1d31ee04002825604f1871d31ee04002825604f", + "0x1ee25902800b8ed0310070050281ff1d31ee02800a1871d31ee02800a8ec", + "0x1871d31ee02825600b8ee00a0310070050281ff1d31ee25902800b1871d3", + "0x1ee02800a1871d31ee02800a8ef00a0310070050281ff1d31ee02825600b", + "0xdf0e30e10280921871d31ee0df0e30e10280928f00310070050281ff1d3", + "0xe102800b1871d31ee0e102800b8f104f00b00a0310070050281ff1d31ee", + "0x281ff1d31ee02800a1871d31ee02800a8f200a0310070050281ff1d31ee", + "0xa8f40310070050281ff1d31ee02800a1871d31ee02800a8f3031007005", + "0x1871d31ee04002800b8f50310070050281ff1d31ee02800a1871d31ee028", + "0x25600b1871d31ee02825600b8f600a0310070050281ff1d31ee04002800b", + "0x1ee26302800b1871d31ee26302800b8f700a0310070050281ff1d31ee028", + "0x1ff1d31ee25902800b1871d31ee25902800b8f800a0310070050281ff1d3", + "0x310070050281ff1d31ee02800a1871d31ee02800a8f900a031007005028", + "0x1d31ee02800a8fb0310070050281ff1d31ee02800a1871d31ee02800a8fa", + "0x1ee0280310060591871ee02800b8fc0310070050281ff1d31ee02800a187", + "0x3100700502821d1ee0280311870591ee02800a8fd00a031007005028216", + "0x2271b21d31ee00b8ff03100700502821d1ee0280310591871ee02800a8fe", + "0x1d31ee0312271911b21d31ee00b90000a0310070050282291d31ee0310f6", + "0x2311d31ee02800a18608e18608e1d31ee02809290100a031007005028229", + "0x2803190300502823818702803118702800790204f00b00a031007005028", + "0x600600618a18b1b21d31ee02801090400700502823a1ee0280311871ee", + "0x2271b21d31ee00f90500f09204f00b00a03100700502823c1d31ee02800a", + "0x24202800a90609204f00b00a0310070050281ff1d31ee031006006006006", + "0x24a1ee02803100c1ee0280319070310070050282461ee24202800a2441ee", + "0xa9090310070050282291d31ee02800a1b21d31ee02800a908007005028", + "0x1b21d30401ee02800b90a0310070050282291d31ee02800a1b21d31ee028", + "0x1ee02800a1b21d31ee02800a90b00a0310070050282291d30401ee02800b", + "0x50282531d31ee02800a0591b21d31ee02800b90c0310070050282291d3", + "0x2800a90e0310070050282291ee0280310061b21ee02800a90d00a031007", + "0x60061b21d32561ee02800f90f0310070050282291ee0280310061b21ee", + "0x401ee02809291009204f00b00a0310070050282291d32561ee02800b006", + "0xa91104f00b00a0310070050282291d32560401ee02804f2571b21d3256", + "0x1b21d32561ee02804f9120310070050282291d31ee25900a1b21d31ee259", + "0x1ee0e10df0e302804f91300b00a0310070050282291d32561ee02800b006", + "0x23c0e10070e100591400b00a0310070050282291ee0e10df0e302804f1b2", + "0x91600b00a0310070050282291d31ee0310590061911b21d31ee04f915028", + "0x2827c1ee02803100617f1871ee02800b91700502827b028007187028007", + "0xa9190310070050282841ee0280311871871ee02800a91800a031007005", + "0x2803116a1721ee02800a91a0310070050282851ee0280311821821ee028", + "0x70050282991ee02803108108e16a1ee02800b91b0310070050282971ee", + "0x1d31ee02800b91d0310070050282a402800708108114602800a91c00a031", + "0x2bc03c1d30401ee02809291e00a0310070050282a81d31ee02800a14b14a", + "0x3c1d31ee02809291f04f00b00a0310070050282be1d30401ee02800b06f", + "0x530130100792004f00b00a0310070050282cb1d31ee02800a11d03c03c", + "0x1ee02800a9220310070050283040280070810060b902800a9210050280f6", + "0x502832218702803118702800792303100700502821d1ee02803105930b", + "0x1ee02803108116a1ee02800a92500700502829902800703c16a028031924", + "0x2bc03c1d31ee02800b927005028146005006146007926031007005028299", + "0x1ee02800b0741d30401ee02800b92800a03100700502834c1d31ee02800a", + "0x92a00700502829602800703c03c02803192900a0310070050283251d3040", + "0x2970401ee02800a16a1720401ee02800b92b00502825c028007081028007", + "0x92d03100700502829904002803103c16a04002800a92c00a031007005028" + ], + "sierra_program_debug_info": { + "type_names": [], + "libfunc_names": [], + "user_func_names": [] + }, + "contract_class_version": "0.1.0", + "entry_points_by_type": { + "EXTERNAL": [ + { + "selector": "0x1143aa89c8e3ebf8ed14df2a3606c1cd2dd513fac8040b0f8ab441f5c52fe4", + "function_idx": 27 + }, + { + "selector": "0x3541591104188daef4379e06e92ecce09094a3b381da2e654eb041d00566d8", + "function_idx": 36 + }, + { + "selector": "0x3c118a68e16e12e97ed25cb4901c12f4d3162818669cc44c391d8049924c14", + "function_idx": 11 + }, + { + "selector": "0x5562b3e932b4d139366854d5a2e578382e6a3b6572ac9943d55e7efbe43d00", + "function_idx": 23 + }, + { + "selector": "0x600c98a299d72ef1e09a2e1503206fbc76081233172c65f7e2438ef0069d8d", + "function_idx": 28 + }, + { + "selector": "0x62c83572d28cb834a3de3c1e94977a4191469a4a8c26d1d7bc55305e640ed5", + "function_idx": 24 + }, + { + "selector": "0x679c22735055a10db4f275395763a3752a1e3a3043c192299ab6b574fba8d6", + "function_idx": 32 + }, + { + "selector": "0x7772be8b80a8a33dc6c1f9a6ab820c02e537c73e859de67f288c70f92571bb", + "function_idx": 30 + }, + { + "selector": "0xca779dd628d0206eda15b718936109101fcdee458be409b230a64462c4bf23", + "function_idx": 43 + }, + { + "selector": "0xd47144c49bce05b6de6bce9d5ff0cc8da9420f8945453e20ef779cbea13ad4", + "function_idx": 1 + }, + { + "selector": "0xe7510edcf6e9f1b70f7bd1f488767b50f0363422f3c563160ab77adf62467b", + "function_idx": 14 + }, + { + "selector": "0xf818e4530ec36b83dfe702489b4df537308c3b798b0cc120e32c2056d68b7d", + "function_idx": 19 + }, + { + "selector": "0x10d2fede95e3ec06a875a67219425c27c5bd734d57f1b221d729a2337b6b556", + "function_idx": 16 + }, + { + "selector": "0x12ead94ae9d3f9d2bdb6b847cf255f1f398193a1f88884a0ae8e18f24a037b6", + "function_idx": 34 + }, + { + "selector": "0x1469798554697a4c50c64f933147bd163500204d4ae206eee1a9b9bf6c228de", + "function_idx": 18 + }, + { + "selector": "0x14dae1999ae9ab799bc72def6dc6e90890cf8ac0d64525021b7e71d05cb13e8", + "function_idx": 8 + }, + { + "selector": "0x169f135eddda5ab51886052d777a57f2ea9c162d713691b5e04a6d4ed71d47f", + "function_idx": 17 + }, + { + "selector": "0x1995689b6aedab51ad67bc2ae0b0ee3fe1ffc433f96179953e6a6b7210b9e13", + "function_idx": 9 + }, + { + "selector": "0x1ae1a515cf2d214b29bdf63a79ee2d490efd4dd1acc99d383a8e549c3cecb5d", + "function_idx": 33 + }, + { + "selector": "0x1e4089d1f1349077b1970f9937c904e27c4582b49a60b6078946dba95bc3c08", + "function_idx": 4 + }, + { + "selector": "0x227ac0f3ce8083231605cb10be915be2004456b618e44b56067e27fc6f8c84f", + "function_idx": 39 + }, + { + "selector": "0x23039bef544cff56442d9f61ae9b13cf9e36fcce009102c5b678aac93f37b36", + "function_idx": 10 + }, + { + "selector": "0x25ff849c52d40a7f29c9849fbe0064575d61c84ddc0ef562bf05bc599abe0ae", + "function_idx": 5 + }, + { + "selector": "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", + "function_idx": 2 + }, + { + "selector": "0x298e03955860424b6a946506da72353a645f653dc1879f6b55fd756f3d20a59", + "function_idx": 3 + }, + { + "selector": "0x2d7cf5d5a324a320f9f37804b1615a533fde487400b41af80f13f7ac5581325", + "function_idx": 15 + }, + { + "selector": "0x2f8b66957adc4564548f3832947bf264a065874e087c21b9e7cf969e2874c0c", + "function_idx": 6 + }, + { + "selector": "0x30f842021fbf02caf80d09a113997c1e00a32870eee0c6136bed27acb348bea", + "function_idx": 31 + }, + { + "selector": "0x311fb2a7f01403971aca6ae0a12b8ad0602e7a5ec48ad48951969942e99d788", + "function_idx": 7 + }, + { + "selector": "0x31401f504973a5e8e1bb41e9c592519e3aa0b8cf6bbfb9c91b532aab8db54b0", + "function_idx": 37 + }, + { + "selector": "0x317eb442b72a9fae758d4fb26830ed0d9f31c8e7da4dbff4e8c59ea6a158e7f", + "function_idx": 29 + }, + { + "selector": "0x32564d7e0fe091d49b4c20f4632191e4ed6986bf993849879abfef9465def25", + "function_idx": 25 + }, + { + "selector": "0x3502249e98d12b6c72951d280360de19ac166d0f18c620addb78491a669c826", + "function_idx": 42 + }, + { + "selector": "0x3555d7ef6849c9f3e3c3b07e7b36395a40bba49ef095d4a8c41467b76a03501", + "function_idx": 41 + }, + { + "selector": "0x3604cea1cdb094a73a31144f14a3e5861613c008e1e879939ebc4827d10cd50", + "function_idx": 12 + }, + { + "selector": "0x382be990ca34815134e64a9ac28f41a907c62e5ad10547f97174362ab94dc89", + "function_idx": 20 + }, + { + "selector": "0x38be5d5f7bf135b52888ba3e440a457d11107aca3f6542e574b016bf3f074d8", + "function_idx": 21 + }, + { + "selector": "0x39a1491f76903a16feed0a6433bec78de4c73194944e1118e226820ad479701", + "function_idx": 38 + }, + { + "selector": "0x3a6a8bae4c51d5959683ae246347ffdd96aa5b2bfa68cc8c3a6a7c2ed0be331", + "function_idx": 13 + }, + { + "selector": "0x3b097c62d3e4b85742aadd0dfb823f96134b886ec13bda57b68faf86f294d97", + "function_idx": 0 + }, + { + "selector": "0x3b756ccfc32a375b48e673ccd8447bcb3fc271415d0b92a7fb837747606c1f8", + "function_idx": 40 + }, + { + "selector": "0x3d3da80997f8be5d16e9ae7ee6a4b5f7191d60765a1a6c219ab74269c85cf97", + "function_idx": 35 + }, + { + "selector": "0x3d95049b565ec2d4197a55108ef03996381d31c84acf392a0a42b28163d69d1", + "function_idx": 22 + }, + { + "selector": "0x3eb640b15f75fcc06d43182cdb94ed38c8e71755d5fb57c16dd673b466db1d4", + "function_idx": 26 + } + ], + "L1_HANDLER": [ + { + "selector": "0x205500a208d0d49d79197fea83cc3f5fde99ac2e1909ae0a5d9f394c0c52ed0", + "function_idx": 45 + }, + { + "selector": "0x39edbbb129ad752107a94d40c3873cae369a46fd2fc578d075679aa67e85d12", + "function_idx": 44 + } + ], + "CONSTRUCTOR": [ + { + "selector": "0x28ffe4ff0f226a9107253e17a904099aa4f63a02a5621de0576e5aa71bc5194", + "function_idx": 46 + } + ] + }, + "abi": [ + { + "type": "constructor", + "name": "constructor", + "inputs": [ + { + "name": "arg1", + "type": "core::felt252" + }, + { + "name": "arg2", + "type": "core::felt252" + } + ] + }, + { + "type": "function", + "name": "test_storage_read_write", + "inputs": [ + { + "name": "address", + "type": "core::starknet::storage_access::StorageAddress" + }, + { + "name": "value", + "type": "core::felt252" + } + ], + "outputs": [ + { + "type": "core::felt252" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "test_count_actual_storage_changes", + "inputs": [], + "outputs": [], + "state_mutability": "view" + }, + { + "type": "struct", + "name": "core::array::Span::", + "members": [ + { + "name": "snapshot", + "type": "@core::array::Array::" + } + ] + }, + { + "type": "function", + "name": "test_call_contract", + "inputs": [ + { + "name": "contract_address", + "type": "core::starknet::contract_address::ContractAddress" + }, + { + "name": "entry_point_selector", + "type": "core::felt252" + }, + { + "name": "calldata", + "type": "core::array::Array::" + } + ], + "outputs": [ + { + "type": "core::array::Span::" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "test_call_two_contracts", + "inputs": [ + { + "name": "contract_address_0", + "type": "core::starknet::contract_address::ContractAddress" + }, + { + "name": "entry_point_selector_0", + "type": "core::felt252" + }, + { + "name": "calldata_0", + "type": "core::array::Array::" + }, + { + "name": "contract_address_1", + "type": "core::starknet::contract_address::ContractAddress" + }, + { + "name": "entry_point_selector_1", + "type": "core::felt252" + }, + { + "name": "calldata_1", + "type": "core::array::Array::" + } + ], + "outputs": [ + { + "type": "core::array::Span::" + } + ], + "state_mutability": "view" + }, + { + "type": "enum", + "name": "core::bool", + "variants": [ + { + "name": "False", + "type": "()" + }, + { + "name": "True", + "type": "()" + } + ] + }, + { + "type": "function", + "name": "test_revert_helper", + "inputs": [ + { + "name": "replacement_class_hash", + "type": "core::starknet::class_hash::ClassHash" + }, + { + "name": "to_panic", + "type": "core::bool" + } + ], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "write_10_to_my_storage_var", + "inputs": [], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "test_revert_with_inner_call_and_reverted_storage", + "inputs": [ + { + "name": "contract_address", + "type": "core::starknet::contract_address::ContractAddress" + }, + { + "name": "replacement_class_hash", + "type": "core::starknet::class_hash::ClassHash" + } + ], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "middle_revert_contract", + "inputs": [ + { + "name": "contract_address", + "type": "core::starknet::contract_address::ContractAddress" + }, + { + "name": "entry_point_selector", + "type": "core::felt252" + }, + { + "name": "calldata", + "type": "core::array::Array::" + } + ], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "test_emit_events", + "inputs": [ + { + "name": "events_number", + "type": "core::integer::u64" + }, + { + "name": "keys", + "type": "core::array::Array::" + }, + { + "name": "data", + "type": "core::array::Array::" + } + ], + "outputs": [], + "state_mutability": "view" + }, + { + "type": "function", + "name": "test_get_class_hash_at", + "inputs": [ + { + "name": "address", + "type": "core::starknet::contract_address::ContractAddress" + }, + { + "name": "expected_class_hash", + "type": "core::starknet::class_hash::ClassHash" + } + ], + "outputs": [], + "state_mutability": "view" + }, + { + "type": "function", + "name": "test_get_block_hash", + "inputs": [ + { + "name": "block_number", + "type": "core::integer::u64" + } + ], + "outputs": [ + { + "type": "core::felt252" + } + ], + "state_mutability": "view" + }, + { + "type": "struct", + "name": "core::starknet::info::BlockInfo", + "members": [ + { + "name": "block_number", + "type": "core::integer::u64" + }, + { + "name": "block_timestamp", + "type": "core::integer::u64" + }, + { + "name": "sequencer_address", + "type": "core::starknet::contract_address::ContractAddress" + } + ] + }, + { + "type": "struct", + "name": "core::starknet::info::v2::ResourceBounds", + "members": [ + { + "name": "resource", + "type": "core::felt252" + }, + { + "name": "max_amount", + "type": "core::integer::u64" + }, + { + "name": "max_price_per_unit", + "type": "core::integer::u128" + } + ] + }, + { + "type": "struct", + "name": "core::array::Span::", + "members": [ + { + "name": "snapshot", + "type": "@core::array::Array::" + } + ] + }, + { + "type": "struct", + "name": "core::starknet::info::v2::TxInfo", + "members": [ + { + "name": "version", + "type": "core::felt252" + }, + { + "name": "account_contract_address", + "type": "core::starknet::contract_address::ContractAddress" + }, + { + "name": "max_fee", + "type": "core::integer::u128" + }, + { + "name": "signature", + "type": "core::array::Span::" + }, + { + "name": "transaction_hash", + "type": "core::felt252" + }, + { + "name": "chain_id", + "type": "core::felt252" + }, + { + "name": "nonce", + "type": "core::felt252" + }, + { + "name": "resource_bounds", + "type": "core::array::Span::" + }, + { + "name": "tip", + "type": "core::integer::u128" + }, + { + "name": "paymaster_data", + "type": "core::array::Span::" + }, + { + "name": "nonce_data_availability_mode", + "type": "core::integer::u32" + }, + { + "name": "fee_data_availability_mode", + "type": "core::integer::u32" + }, + { + "name": "account_deployment_data", + "type": "core::array::Span::" + } + ] + }, + { + "type": "function", + "name": "test_get_execution_info", + "inputs": [ + { + "name": "expected_block_info", + "type": "core::starknet::info::BlockInfo" + }, + { + "name": "expected_tx_info", + "type": "core::starknet::info::v2::TxInfo" + }, + { + "name": "expected_caller_address", + "type": "core::felt252" + }, + { + "name": "expected_contract_address", + "type": "core::felt252" + }, + { + "name": "expected_entry_point_selector", + "type": "core::felt252" + } + ], + "outputs": [], + "state_mutability": "view" + }, + { + "type": "function", + "name": "test_library_call", + "inputs": [ + { + "name": "class_hash", + "type": "core::starknet::class_hash::ClassHash" + }, + { + "name": "function_selector", + "type": "core::felt252" + }, + { + "name": "calldata", + "type": "core::array::Array::" + } + ], + "outputs": [ + { + "type": "core::array::Span::" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "test_nested_library_call", + "inputs": [ + { + "name": "class_hash", + "type": "core::starknet::class_hash::ClassHash" + }, + { + "name": "lib_selector", + "type": "core::felt252" + }, + { + "name": "nested_selector", + "type": "core::felt252" + }, + { + "name": "a", + "type": "core::felt252" + }, + { + "name": "b", + "type": "core::felt252" + } + ], + "outputs": [ + { + "type": "core::array::Span::" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "test_replace_class", + "inputs": [ + { + "name": "class_hash", + "type": "core::starknet::class_hash::ClassHash" + } + ], + "outputs": [], + "state_mutability": "view" + }, + { + "type": "function", + "name": "test_send_message_to_l1", + "inputs": [ + { + "name": "to_address", + "type": "core::felt252" + }, + { + "name": "payload", + "type": "core::array::Array::" + } + ], + "outputs": [], + "state_mutability": "view" + }, + { + "type": "function", + "name": "segment_arena_builtin", + "inputs": [], + "outputs": [], + "state_mutability": "view" + }, + { + "type": "l1_handler", + "name": "l1_handle", + "inputs": [ + { + "name": "from_address", + "type": "core::felt252" + }, + { + "name": "arg", + "type": "core::felt252" + } + ], + "outputs": [ + { + "type": "core::felt252" + } + ], + "state_mutability": "view" + }, + { + "type": "l1_handler", + "name": "l1_handler_set_value", + "inputs": [ + { + "name": "from_address", + "type": "core::felt252" + }, + { + "name": "key", + "type": "core::starknet::storage_access::StorageAddress" + }, + { + "name": "value", + "type": "core::felt252" + } + ], + "outputs": [ + { + "type": "core::felt252" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "test_deploy", + "inputs": [ + { + "name": "class_hash", + "type": "core::starknet::class_hash::ClassHash" + }, + { + "name": "contract_address_salt", + "type": "core::felt252" + }, + { + "name": "calldata", + "type": "core::array::Array::" + }, + { + "name": "deploy_from_zero", + "type": "core::bool" + } + ], + "outputs": [], + "state_mutability": "view" + }, + { + "type": "function", + "name": "test_stack_overflow", + "inputs": [ + { + "name": "depth", + "type": "core::integer::u128" + } + ], + "outputs": [ + { + "type": "core::integer::u128" + } + ], + "state_mutability": "external" + }, + { + "type": "function", + "name": "test_keccak", + "inputs": [], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "test_sha256", + "inputs": [], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "test_secp256k1", + "inputs": [], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "test_secp256r1", + "inputs": [], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "assert_eq", + "inputs": [ + { + "name": "x", + "type": "core::felt252" + }, + { + "name": "y", + "type": "core::felt252" + } + ], + "outputs": [ + { + "type": "core::felt252" + } + ], + "state_mutability": "external" + }, + { + "type": "function", + "name": "invoke_call_chain", + "inputs": [ + { + "name": "call_chain", + "type": "core::array::Array::" + } + ], + "outputs": [ + { + "type": "core::felt252" + } + ], + "state_mutability": "external" + }, + { + "type": "function", + "name": "fail", + "inputs": [], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "recursive_fail", + "inputs": [ + { + "name": "depth", + "type": "core::felt252" + } + ], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "recurse", + "inputs": [ + { + "name": "depth", + "type": "core::felt252" + } + ], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "recursive_syscall", + "inputs": [ + { + "name": "contract_address", + "type": "core::starknet::contract_address::ContractAddress" + }, + { + "name": "function_selector", + "type": "core::felt252" + }, + { + "name": "depth", + "type": "core::felt252" + } + ], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "advance_counter", + "inputs": [ + { + "name": "index", + "type": "core::felt252" + }, + { + "name": "diff_0", + "type": "core::felt252" + }, + { + "name": "diff_1", + "type": "core::felt252" + } + ], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "struct", + "name": "test_contract::test_contract::TestContract::IndexAndValues", + "members": [ + { + "name": "index", + "type": "core::felt252" + }, + { + "name": "values", + "type": "(core::integer::u128, core::integer::u128)" + } + ] + }, + { + "type": "function", + "name": "xor_counters", + "inputs": [ + { + "name": "index_and_x", + "type": "test_contract::test_contract::TestContract::IndexAndValues" + } + ], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "call_xor_counters", + "inputs": [ + { + "name": "address", + "type": "core::starknet::contract_address::ContractAddress" + }, + { + "name": "index_and_x", + "type": "test_contract::test_contract::TestContract::IndexAndValues" + } + ], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "test_ec_op", + "inputs": [], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "add_signature_to_counters", + "inputs": [ + { + "name": "index", + "type": "core::felt252" + } + ], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "send_message", + "inputs": [ + { + "name": "to_address", + "type": "core::felt252" + } + ], + "outputs": [], + "state_mutability": "view" + }, + { + "type": "function", + "name": "test_circuit", + "inputs": [], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "test_rc96_holes", + "inputs": [], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "test_call_contract_revert", + "inputs": [ + { + "name": "contract_address", + "type": "core::starknet::contract_address::ContractAddress" + }, + { + "name": "entry_point_selector", + "type": "core::felt252" + }, + { + "name": "calldata", + "type": "core::array::Array::" + } + ], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "return_result", + "inputs": [ + { + "name": "num", + "type": "core::felt252" + } + ], + "outputs": [ + { + "type": "core::felt252" + } + ], + "state_mutability": "external" + }, + { + "type": "function", + "name": "empty_function", + "inputs": [], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "test_bitwise", + "inputs": [], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "test_pedersen", + "inputs": [], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "test_poseidon", + "inputs": [], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "function", + "name": "test_ecop", + "inputs": [], + "outputs": [], + "state_mutability": "external" + }, + { + "type": "event", + "name": "test_contract::test_contract::TestContract::Event", + "kind": "enum", + "variants": [] + } + ] +} diff --git a/crates/blockifier_test_utils/resources/feature_contracts/cairo1/sierra/test_contract_execution_info_v1.sierra.json b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/sierra/test_contract_execution_info_v1.sierra.json new file mode 100644 index 00000000000..456f62a38a0 --- /dev/null +++ b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/sierra/test_contract_execution_info_v1.sierra.json @@ -0,0 +1,934 @@ +{ + "sierra_program": [ + "0x1", + "0x7", + "0x0", + "0x2", + "0xb", + "0x0", + "0x188", + "0x78", + "0x44", + "0x52616e6765436865636b", + "0x800000000000000100000000000000000000000000000000", + "0x436f6e7374", + "0x800000000000000000000000000000000000000000000002", + "0x1", + "0x1a", + "0x2", + "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x7533325f737562204f766572666c6f77", + "0x496e646578206f7574206f6620626f756e6473", + "0x18", + "0x0", + "0x53455155454e4345525f4d49534d41544348", + "0x54585f494e464f5f56455253494f4e5f4d49534d41544348", + "0x4143434f554e545f435f414444524553535f4d49534d41544348", + "0x54585f494e464f5f484153485f4d49534d41544348", + "0x54585f494e464f5f434841494e5f49445f4d49534d41544348", + "0x54585f494e464f5f4e4f4e43455f4d49534d41544348", + "0x43414c4c45525f4d49534d41544348", + "0x434f4e54524143545f4d49534d41544348", + "0x53454c4543544f525f4d49534d41544348", + "0x54585f494e464f5f5349474e41545552455f4d49534d41544348", + "0x537472756374", + "0x800000000000000f00000000000000000000000000000001", + "0x2ee1e2b1b89f8c495f200e4956278a4d47395fe262f27b52e5865c9524c08c3", + "0x456e756d", + "0x800000000000000700000000000000000000000000000003", + "0x3288d594b9a45d15bb2fcb7903f06cdb06b27f0ba88186ec4cfaa98307cb972", + "0xf", + "0x4172726179", + "0x800000000000000300000000000000000000000000000001", + "0x536e617073686f74", + "0x800000000000000700000000000000000000000000000001", + "0x11", + "0x800000000000000700000000000000000000000000000002", + "0x1baeba72e79e9db2587cf44fedb2f3700b2075a5e8e39a562584862c4b71f62", + "0x12", + "0x800000000000000700000000000000000000000000000004", + "0x13", + "0x10", + "0x16a4c8d7c05909052238a862d8cc3e7975bf05a07b3a69c6b28951083a6d672", + "0x800000000000000300000000000000000000000000000003", + "0x15", + "0x45b67c75542d42836cef6c02cca4dbff4a80a8621fa521cbfff1b2dd4af35a", + "0x14", + "0x16", + "0x753332", + "0x800000000000000700000000000000000000000000000000", + "0x54585f494e464f5f4d41585f4645455f4d49534d41544348", + "0x66656c74323532", + "0x4e6f6e5a65726f", + "0x424c4f434b5f54494d455354414d505f4d49534d41544348", + "0x424c4f434b5f4e554d4245525f4d49534d41544348", + "0x753634", + "0x436f6e747261637441646472657373", + "0x3808c701a5d13e100ab11b6c02f91f752ecae7e420d21b56c90ec0a475cc7e5", + "0x1e", + "0x1f", + "0x426f78", + "0x3c", + "0x20", + "0x800000000000000700000000000000000000000000000006", + "0x19367431bdedfe09ea99eed9ade3de00f195dd97087ed511b8942ebb45dbc5a", + "0x22", + "0x21", + "0x23", + "0x556e696e697469616c697a6564", + "0x800000000000000200000000000000000000000000000001", + "0x53797374656d", + "0x26", + "0x1d49f7a4b277bf7b55a2664ce8cef5d6922b5ffb806b89644b9e0cdbbcac378", + "0x29", + "0x13fdd7105045794a99550ae1c4ac13faa62610dfab62c16422bfcf5803baa6e", + "0x2a", + "0x75313238", + "0x4661696c656420746f20646573657269616c697a6520706172616d202331", + "0x4661696c656420746f20646573657269616c697a6520706172616d202332", + "0x4661696c656420746f20646573657269616c697a6520706172616d202333", + "0x4661696c656420746f20646573657269616c697a6520706172616d202334", + "0x4661696c656420746f20646573657269616c697a6520706172616d202335", + "0x4661696c656420746f20646573657269616c697a6520706172616d202336", + "0x4661696c656420746f20646573657269616c697a6520706172616d202337", + "0x4f7574206f6620676173", + "0x800000000000000f00000000000000000000000000000002", + "0xcc5e86243f861d2d64b08c35db21013e773ac5cf10097946fe0011304886d5", + "0x36", + "0x371a38276a14d2475f9072073e9ab9b154a40bb41edce5be7d1ade8ccbeb2e4", + "0x4275696c74696e436f737473", + "0x9931c641b913035ae674b400b61a51476d506bbe8bba2ff8a6272790aba9e6", + "0x35", + "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473", + "0x800000000000000700000000000000000000000000000008", + "0x2e655a7513158873ca2e5e659a9e175d23bf69a2325cdd0397ca3b8d864b967", + "0x2c", + "0x109c59bf70ce1d096631b005c20ec90d752446fc0fd825dac0e61dd34c3af50", + "0x3d", + "0x12635a64ec5093a14e1239a44eef43a4a94ce4403a075c9e94b6ef456572cda", + "0x3e", + "0x11c6d8087e00642489f92d2821ad6ebd6532ad1a3b6d12833da6d6810391511", + "0x29d7d57c04a880978e7b3689f6218e507f3be17588744b58dc17762447ad0e7", + "0x41", + "0x4761734275696c74696e", + "0xa0", + "0x7265766f6b655f61705f747261636b696e67", + "0x77697468647261775f676173", + "0x6272616e63685f616c69676e", + "0x72656465706f7369745f676173", + "0x7374727563745f6465636f6e737472756374", + "0x656e61626c655f61705f747261636b696e67", + "0x73746f72655f74656d70", + "0x43", + "0x61727261795f736e617073686f745f706f705f66726f6e74", + "0x656e756d5f696e6974", + "0x42", + "0x6a756d70", + "0x7374727563745f636f6e737472756374", + "0x656e756d5f6d61746368", + "0x64697361626c655f61705f747261636b696e67", + "0x756e626f78", + "0x72656e616d65", + "0x7536345f7472795f66726f6d5f66656c74323532", + "0x40", + "0x21adb5788e32c84f69a1863d85ef9394b7bf761a0ce1190f826984e5075c371", + "0x66756e6374696f6e5f63616c6c", + "0x3", + "0x3f", + "0x64726f70", + "0x61727261795f6e6577", + "0x636f6e73745f61735f696d6d656469617465", + "0x3b", + "0x61727261795f617070656e64", + "0x3a", + "0x6765745f6275696c74696e5f636f737473", + "0x39", + "0x77697468647261775f6761735f616c6c", + "0x38", + "0x736e617073686f745f74616b65", + "0x37", + "0x34", + "0x33", + "0x32", + "0x31", + "0x30", + "0x2f", + "0x2e", + "0x2d", + "0x647570", + "0x75313238735f66726f6d5f66656c74323532", + "0x2b", + "0x616c6c6f635f6c6f63616c", + "0x66696e616c697a655f6c6f63616c73", + "0x6765745f657865637574696f6e5f696e666f5f73797363616c6c", + "0x24", + "0x73746f72655f6c6f63616c", + "0x7536345f6571", + "0x28", + "0x1d", + "0x1c", + "0x636f6e74726163745f616464726573735f746f5f66656c74323532", + "0x66656c743235325f737562", + "0x66656c743235325f69735f7a65726f", + "0x753132385f6571", + "0x19", + "0x61727261795f6c656e", + "0x7533325f6571", + "0x4", + "0x17", + "0xe", + "0x1b", + "0xd", + "0xc", + "0xb", + "0xa", + "0x9", + "0x8", + "0x7", + "0x6", + "0x5", + "0x25", + "0x27", + "0x7533325f7472795f66726f6d5f66656c74323532", + "0x61727261795f736c696365", + "0x7533325f6f766572666c6f77696e675f737562", + "0x548", + "0xffffffffffffffff", + "0x18f", + "0x17c", + "0x176", + "0x162", + "0x15a", + "0x4a", + "0x51", + "0x145", + "0x13c", + "0x45", + "0x46", + "0x47", + "0x48", + "0x49", + "0x130", + "0x4b", + "0x4c", + "0x4d", + "0x4e", + "0x11c", + "0x4f", + "0x50", + "0x52", + "0x53", + "0x108", + "0x54", + "0x55", + "0x56", + "0x57", + "0x58", + "0xf3", + "0x59", + "0x5a", + "0x5b", + "0x5c", + "0x5d", + "0xdd", + "0x5e", + "0x5f", + "0x60", + "0x61", + "0x62", + "0x95", + "0x63", + "0x64", + "0x65", + "0x66", + "0x67", + "0x68", + "0x69", + "0x6a", + "0x6b", + "0x6c", + "0x6d", + "0x6e", + "0xc7", + "0x6f", + "0x70", + "0x71", + "0x72", + "0x73", + "0x74", + "0x75", + "0x76", + "0x77", + "0x78", + "0x79", + "0x7a", + "0x7b", + "0x7c", + "0xbf", + "0x7d", + "0x7e", + "0x7f", + "0x80", + "0x81", + "0x82", + "0x83", + "0x84", + "0x85", + "0x86", + "0x87", + "0x88", + "0x89", + "0x8a", + "0x8b", + "0x8c", + "0x8d", + "0x8e", + "0x8f", + "0x90", + "0x91", + "0x92", + "0x93", + "0x94", + "0x96", + "0x97", + "0x98", + "0x99", + "0x9a", + "0x9b", + "0x9c", + "0x9d", + "0x9e", + "0x9f", + "0xa1", + "0xa2", + "0xa3", + "0xa4", + "0xa5", + "0xa6", + "0xa7", + "0xa8", + "0xa9", + "0xaa", + "0xab", + "0xac", + "0xad", + "0xae", + "0x14e", + "0xaf", + "0xb0", + "0xb1", + "0xb2", + "0xb3", + "0xb4", + "0xb5", + "0xb6", + "0xb7", + "0xb8", + "0x16a", + "0xb9", + "0xba", + "0xbb", + "0xbc", + "0xbd", + "0xbe", + "0xc0", + "0xc1", + "0xc2", + "0x183", + "0xc3", + "0xc4", + "0xc5", + "0xc6", + "0xc8", + "0xc9", + "0xca", + "0xcb", + "0xcc", + "0xcd", + "0xce", + "0xcf", + "0xd0", + "0x255", + "0x1ad", + "0x1b2", + "0x24a", + "0x245", + "0x1c0", + "0x1c5", + "0x23a", + "0x233", + "0x22b", + "0x221", + "0x214", + "0x206", + "0x1ea", + "0x1ef", + "0x1f9", + "0x23f", + "0x24f", + "0x45a", + "0x299", + "0x2b8", + "0x440", + "0x41f", + "0x400", + "0x2f8", + "0x317", + "0x337", + "0x3ec", + "0x343", + "0x3d3", + "0x3bc", + "0x3a7", + "0x394", + "0x383", + "0x374", + "0x47a", + "0x47f", + "0x4d1", + "0x4c8", + "0x4bb", + "0x4ac", + "0x4a0", + "0x539", + "0x4eb", + "0x4f2", + "0x52d", + "0x51c", + "0x510", + "0x19e", + "0x25e", + "0x473", + "0x4db", + "0x2cb9", + "0x300e0b02810060a038180a04018240e06028100608038180a04018080200", + "0x1408030801c0c050200c1e070301408030701c0c050200c1a07030140803", + "0x540e06028100614038180a040184c0e06028100612038180a04018440e06", + "0x5c4405108800c050f8783a050e814380c0d868320c0c05c2c07030140803", + "0x880a2b02864182a0b8a418180b8a00a270289c0a19060982e25028901823", + "0x1c0c050200c0c05108cc60321881c0c050200c602f170145a0516030541a", + "0x84763c02884763a028e40a39028e018260b8c06e301b0d40e06028100634", + "0x10c04451d014884321014423b0301474051d0148205200147e0c1f05c7a05", + "0x124182a0d1200a2702864181b0b8740a270291c181b0d0180a44219180a44", + "0x1408032701c0c050200c9a070301408032601c0c050200c604b170149405", + "0x14c0e06028100652038180a04019440e06028100650038180a040193c0e06", + "0x6860582b830301717014ac052a830541a0e814320c2a05c4e050c8304617", + "0x180a27029780a3a028180a5d061702e5b038180a04018b80a5a02964182a", + "0x14c40530830541a300144e050c83036170e81478052f830361a030140c05", + "0x1a4186833808cc1d029940a640606c340602884761d028180a630606c342e", + "0x1c80a07388180a05381bc0a05370300a0537030da2702814d80c35830d40c", + "0x1d8e405029d40a07390140e710e8140a74061cce405029b84a05029b81807", + "0x1ce27a02814dc0c039e80a0738830f20602814dc0602814f00602814ee0c", + "0x1b0fc05029d40a7d029f04e05029b84e05029d0187b3d0140a750281cf405", + "0xe80a053f8f00a053f8180a053f9940a053f8940a053f9800a053a9880a05", + "0x140e71170140a74158140a74030140a83410140a81030140a801c8140a7f", + "0x2200a0544a200a053a0310e8602814dc0c42a100a05371180a05370140e84", + "0x140a7f450140a75039f40a7c1e0140a6e1d0140a6e1c8140a6e440140a7f", + "0x2300a0540a2c0a05408300e840281ce25a02814e82202814fe22028151256", + "0x140a81480140a81478140a81138140a7f0e8140a7f470140a81468140a81", + "0x1200a053a9280a05362540a053a9f4fa053e0312825028152692028150291", + "0x140a7f3f0140a6e0601cfc05039c4c405029d01807300140e711e0140a74", + "0x312e3a028152c46028152c06028152c05039f80a07388140e600281ce25e", + "0x2687a05029b07a05029dc8005029b88405029b08405029dd3205029b81898", + "0x15029c02814fe4102814fe0c4d8180a054d0e80a054d1040a05371180a05", + "0x1b07805029dc18a106280189f4f0140a81450140a6e0281d1405039c53a05", + "0x314a0b02814dc060281548270281526a302815020c511780a05370f00a05", + "0x140e712b0140a74540140a81140140a75168140a6c538140a75531f40a7c", + "0x2b80a0540ab40a0540ab00a0540aac0a0540aa80a0540aa40a053f8300e8a", + "0x20418b55a0140a7f598140a7f590140a81588140a81580140a81578140a81", + "0x2540a07389280a053a0300e480281ce20c5b8180a055b02c0a0549a980a05", + "0x140e71038140a81058140a7f0281d2a05039c4fa0502a052a05029b81807", + "0x140a0540a9c0a05370300ea70281ce22d02814e80c038a00a07388140e48", + "0x1d7207028300e050603172050603018b80281c5005039c40a07538140e71", + "0x1572053e8154c0c57815720559014fa0c062e40a0c0383160b103ae964a6", + "0x2b80aaf062bc0ab902abc0ab0062980ab902a980ab1060317205062c818ae", + "0x1558055703154055c8155e053e83018b9028300e0c5581450ac5681d7207", + "0x880ab902aa00aac060a00ab902ab40aad060740ab902aa80ab0062a00ab9", + "0x9c0ab902831540c12815720557814fa0c062e40a0c0383018a702831560c", + "0x15580c140157205558155a0c0e815720512815600c16815720513815500c", + "0x2e40a0c1403018b9028300e0c17015762b02ae40e2202874182202ae40a2d", + "0x9c18a302ae40a0b02894180b02ae40a2b0288818a702ae40a1d029f4180c", + "0x2780abc548180eb903a8d4c07168314e055c8154e055803146055c8154605", + "0x15720503015620c062e40a0c590313a055c8154e053e83018b9028300e0c", + "0x3172050601c183d02a48743903ae40e2802abc189d02ae40a9d02ac01806", + "0x155a0c21015720520815600c2001572051d0155c0c2081572054e814fa0c", + "0x1f4180c5c8141807060311605062ac18b302ae40a4002ab0189902ae40a39", + "0x2e40a4602ac0189c02ae40ab402aa018b402ae40a0c550308c055c8153a05", + "0x2f490055c81d66050e83166055c81538055603132055c8147a05568308405", + "0x144a0c2f015720524014440c4a815720521014fa0c062e40a0c038309405", + "0x1d2406038b4189502ae40a9502ac0189202ae40a920289c189202ae40a5e", + "0x2e40a9102ac4188e02ae40a95029f4180c5c81418070623c0abe482440eb9", + "0x2e40a0c0383116055fa311a075c81d3205578311c055c8151c05580312205", + "0xac188a02ae40a5602894185602ae40a8c02888185a02ae40a8e029f4180c", + "0x1510051703108055c8151a05568310c055c814b4055803110055c8151405", + "0x1418aa060f00ab902a380a7d0603172050601c180c6001418ab062080ab9", + "0x2100ab902a2c0aad062180ab9028f00ab0061880ab9029800aa7061800ab9", + "0x1f4180c5c8141807061e80ac13f015720741014160c410157205310145c0c", + "0xac2379c80eb9039f9220751830ca055c814ca0558030ca055c8150c05", + "0x14e4055883188055c81508050303186055c814ca053e83018b9028300e0c", + "0x2e40ac302ac018c66281d7205621c80e9e063100ab902b100aa9061c80ab9", + "0x3240ab902b0c0a7d0603172050601c18bf02b218e055c81d8c054e8318605", + "0x159acc02ae40ecb028e818c902ae40ac902ac018cb6501d720563814720c", + "0x33c0ab0063000ab902b280aa60633c0ab902b240a7d0603172050601c18ce", + "0x159e053e83018b9028300e0c69815a4d16801d7207600155e0c678157205", + "0x3500ab902b500ab0063400ab902b400aad063540ab902b440a22063500ab9", + "0x3018b9028300e0c6c815b0d76b01d7207680155e0c6a81572056a8144e0c", + "0x3680ab0063580ab902b580aad0636c0ab902b5c0a22063680ab902b500a7d", + "0x300e0c6f815bcdd6e01d72076b0155e0c6d81572056d8144e0c6d0157205", + "0x3700ab902b700aad063840ab902b740a22063800ab902b680a7d060317205", + "0x15c8e37101d72076e0155e0c708157205708144e0c70015720570015600c", + "0x31720571814820c062e40ae2028f4180c5c81418280603172050601c18e5", + "0x2e40acc02908180c5c815b6052003018b902b840a400603172056a814800c", + "0x15c0053e83018b902aa40ab306031720548015660c062e40a6f02a64180c", + "0x27018e802ae40ae80289c18e802ae40a0c5a031ce055c8141846063980ab9", + "0x3ac0a95063ac0ab902ba5d40725031d4055c8141848063a40ab902ba1ce07", + "0x15720503814bc0c73015720573015600c62815720562815620c760157205", + "0x2e40ae5028f4180c5c8141807063b00ee662a980aec02ae40aec02a481807", + "0x15200c76815720576815600c7701572050624418ed02ae40ae0029f4180c", + "0x3018b9028300e0c79bc80ef1783bc0eb903bb9dac53ea3c18ee02ae40aee", + "0x2e40adb0289418f502ae40ad50289418f402ae40af0029f4180c5c8141828", + "0x31f4f903ae40af802a3418f802ae40a0c47031ee055c815c20512831ec05", + "0x140e052f031e8055c815e80558031de055c815de055883018b902be40a8c", + "0x1bc0ab9029bc0a5a062400ab902a400a8b062a40ab902aa40a8b0601c0ab9", + "0x144e0c7b01572057b0144e0c7a81572057a8144e0c66015720566014ac0c", + "0x31fcfd7e3ed4cb902bddecf5661bd20a97d01de8ef5622818f702ae40af7", + "0x3f00a7d0603172057f8150c0c062e40a0c038320205803fc0ab903bf80a88", + "0x31720582015040c82c100eb902c0c0a840640c0ab9028308c0c810157205", + "0x15620c84015720583814c00c83815720583014780c830157205828140c0c", + "0x2e40b0802a4818fd02ae40afd02978190202ae40b0202ac018fb02ae40afb", + "0x1602054a83212055c815f8053e83018b9028300e0c843f604fb530161005", + "0x3f40ab902bf40a5e064240ab902c240ab0063ec0ab902bec0ab1064280ab9", + "0x3018b902830500c062e40a0c0383214fd84bed4c0585015720585015240c", + "0x31720566014840c062e40adb02900180c5c815c2052003018b902b540a40", + "0x2e40af3029f4180c5c81552055983018b902a400ab306031720537815320c", + "0x1d380c868157205868144e0c86815720506188190c02ae40a0c230321605", + "0x1620054a83220055c8161d0f03928190f02ae40a0c240321c055c8161b0c", + "0x1c0ab90281c0a5e0642c0ab902c2c0ab0063c80ab902bc80ab1064440ab9", + "0x3018b902830500c062e40a0c03832220785bc94c0588815720588815240c", + "0x3172056d814800c062e40ad502900180c5c81552055983018b902b7c0a3d", + "0x2e40ada029f4180c5c81520055983018b9029bc0a9906031720566014840c", + "0x1d380c8a01572058a0144e0c8a0157205061f8191302ae40a0c230322405", + "0x162e054a8322e055c8162b1603928191602ae40a0c240322a055c8162913", + "0x1c0ab90281c0a5e064480ab902c480ab0063140ab902b140ab1064600ab9", + "0x3018b902830500c062e40a0c038323007893154c058c01572058c015240c", + "0x31720548015660c062e40ad502900180c5c81552055983018b902b640a3d", + "0x2e40a0c23031c8055c815a8053e83018b9029bc0a9906031720566014840c", + "0x3236055c816351903a70191a02ae40b1a0289c191a02ae40a0c3d0323205", + "0x3140ab1064780ab902c740a95064740ab902c6e38072503238055c8141848", + "0x1572058f015240c03815720503814bc0c72015720572015600c628157205", + "0x3018b902b4c0a3d060317205060a0180c5c8141807064780ee462a980b1e", + "0x31720566014840c062e40a6f02a64180c5c81520055983018b902aa40ab3", + "0x1642051383242055c8141865064800ab9028308c0c8f815720567814fa0c", + "0x1572059119c0e4a0619c0ab902830900c91015720590c800e9c064840ab9", + "0x178191f02ae40b1f02ac018c502ae40ac502ac4192402ae40b2302a541923", + "0x3018b9028300e0c9201e3ec55301648055c8164805490300e055c8140e05", + "0x3018b902b280a6f06031720554815660c062e40ace029c8180c5c8141828", + "0x15720506118192502ae40ac9029f4180c5c814de054c83018b902a400ab3", + "0x120192802ae40b279301d380c938157205938144e0c938157205060001926", + "0x158a055883256055c81654054a83254055c816512903928192902ae40a0c", + "0x4ac0ab902cac0a920601c0ab90281c0a5e064940ab902c940ab0063140ab9", + "0x2cc180c5c81552055983018b902830500c062e40a0c03832560792b154c05", + "0x1572055f8152a0c96015720561814fa0c062e40a6f02a64180c5c8152005", + "0x248180702ae40a0702978192c02ae40b2c02ac018c502ae40ac502ac4192d", + "0x15660c062e40a0c1403018b9028300e0c9681e58c5530165a055c8165a05", + "0x325c055c814ca053e83018b902a400ab3060317205420147a0c062e40aa9", + "0x3172050601c180c9881418ab064c00ab902cb80ab0064bc0ab9028000ab1", + "0x317205420147a0c062e40aa902acc180c5c814f4053903018b902830500c", + "0x4c80ab0064bc0ab902a440ab1064c80ab902a180a7d06031720548015660c", + "0x3268055c81668051383268055c81418c3064cc0ab9028308c0c980157205", + "0x152a0c9b81572059acd80e4a064d80ab902830900c9a81572059a4cc0e9c", + "0x2e40a0702978193002ae40b3002ac0192f02ae40b2f02ac4193802ae40b37", + "0x2e40a0c1403018b9028300e0c9c01e612f5301670055c8167005490300e05", + "0x23c0ab1064e40ab902a540a7d0603172054c8147a0c062e40aa902acc180c", + "0x30500c062e40a0c03830193c02831560c9d81572059c815600c9d0157205", + "0x14fa0c062e40a99028f4180c5c81552055983018b9029280a72060317205", + "0x15720506118193b02ae40b3d02ac0193a02ae40a0602ac4193d02ae40a42", + "0x120194002ae40b3f9f01d380c9f81572059f8144e0c9f815720506310193e", + "0x1674055883200055c81684054a83284055c816814103928194102ae40a0c", + "0x4000ab902c000a920601c0ab90281c0a5e064ec0ab902cec0ab0064e80ab9", + "0x50c0ab902a9c0a7d060317205140147a0c062e40a0c0383200079dce94c05", + "0x2e40a0c03830194602831560ca28157205a1815600ca201572054f015620c", + "0x2e40a1d029f4180c5c81450051e83018b9028b80a72060317205060a0180c", + "0x314194802ae40a0c230328a055c8168e055803288055c8154c05588328e05", + "0x2e40a0c2403294055c816934803a70194902ae40b490289c194902ae40a0c", + "0x5100ab902d100ab1065300ab902d2c0a950652c0ab902d29e20725031e205", + "0x5114c05a60157205a6015240c03815720503814bc0ca28157205a2815600c", + "0x308c0ca6815720558014fa0c062e40a7d029bc180c5c8141807065300f45", + "0x157205a7d380e9c0653c0ab902d3c0a270653c0ab902830c40ca70157205", + "0x2c4195302ae40b5202a54195202ae40b50a881c940ca88157205061201950", + "0x16a605490300e055c8140e052f0329a055c8169a055803162055c8156205", + "0x5514c7d03ae40e0702abc180702ae40a0502a98195303d3562a602d4c0ab9", + "0x155a0c580157205588144a0c58815720553014440c062e40a0c038316405", + "0x1c18ad02d555caf03ae40e7d02abc18b002ae40ab00289c187d02ae40a7d", + "0x15720555814560c558157205560144a0c56015720557014440c062e40a0c", + "0x14180706032ac05062ac181d02ae40aaa028b818a802ae40aaf02ab418aa", + "0xb818a802ae40aad02ab4182202ae40a2802a9c182802ae40a0c5503018b9", + "0x740a0b0609c0ab9028940a060609550075c8155005630303a055c8144405", + "0x301605ac29c5c075c81c5a0c03a8c180c5c8141807060ac0b57168157207", + "0x1d7207540155e0c17015720517015620c062e40a27029bc180c5c8141807", + "0x2740ab902a8c0aad062780ab9028180aae0603172050601c18a902d640ca3", + "0xe80ab902831540c062e40a0c03830195a02831560c1c81572054f015580c", + "0x140c0c1c81572051e815580c4e8157205548155a0c1e81572051d015500c", + "0x1480051103018b9028300e0c21016b64002ae40e3902874184102ae40a9d", + "0x1d7207598b80ec7062cc0ab902acc0a27062cc0ab902a640a25062640ab9", + "0x2e40a4102aa4184602ae40a4602ac4180c5c814180706128909c3ed716846", + "0x141807062440b5d4901572072f015920c2f2540eb9029048c075f8308205", + "0x2e40a0c038311a05af2380ab903a3c0acb0623d20075c81524056503018b9", + "0x3172050601c185602d7cb48b03ae40e8c02abc188c02ae40a9002a98180c", + "0x155e0c450157205450144e0c458157205458155a0c4501572052d014440c", + "0x2280a25062080ab902a180a220603172050601c188402d810c8803ae40e8b", + "0x157205300144e0c440157205440155a0c300157205410144a0c1e0157205", + "0x1940ab9029f80a220603172050601c187a02d84fc6203ae40e8802abc1860", + "0x145c0c000157205310155a0c37815720539014560c390157205328144a0c", + "0x154e0c620157205062a8180c5c814180706032c405062ac18c302ae40a6f", + "0x2e40a000281818c302ae40ac5028b8180002ae40a7a02ab418c502ae40ac4", + "0xf11cb453ac160cc0603172050601c18bf02d8d8e055c81d8605058318c05", + "0x32c0ac00632c0ab902b298c076783194055c81592056703192055c8158e60", + "0x300e0c662540e0566015720566015a00c4a81572054a815620c660157205", + "0x14de0c062e40a3c02900180c5c814c0052003018b902ac00a40060317205", + "0x319c055c8157e056983018b902a9c0a990603172055a015a20c062e40a8e", + "0x15a00c4a81572054a815620c60015720567815800c678157205673180ecf", + "0x1560052003018b902a9c0a990603172050601c18c04a81c0ac002ae40ac0", + "0x1418aa06031720547014de0c062e40a8a02900180c5c81568056883018b9", + "0x15720569b440ecf0634c0ab902b400ad3063440ab902a100a06063400ab9", + "0x1c0ad502ae40ad502b40189502ae40a9502ac418d502ae40ad402b0018d4", + "0x1568056883018b902ac00a4006031720553815320c062e40a0c03831aa95", + "0x15a60c6b81572052b0140c0c6b0157205062a8180c5c8151c053783018b9", + "0x152a0558831b6055c815b40560031b4055c815b2d703b3c18d902ae40ad6", + "0x2e40aa702a64180c5c81418070636d2a0702b6c0ab902b6c0ad0062540ab9", + "0x2400ecf063700ab902a340ad30603172055a015a20c062e40ab002900180c", + "0x2e40adf02b40189502ae40a9502ac418df02ae40add02b0018dd02ae40adc", + "0x3018b902ac00a4006031720553815320c062e40a0c03831be9503815be05", + "0x15c005680312a055c8152a0558831c0055c81522056a03018b902ad00ad1", + "0x31720525015a20c062e40a4802b44180c5c8141807063812a0702b800ab9", + "0x5900a0c55831c2055c81538055883018b902ac00a4006031720553815320c", + "0x2e40ab002900180c5c8154e054c83018b9029080a720603172050601c180c", + "0x1d9e0c71815720571015a60c710157205062a818e102ae40a2e02ac4180c", + "0x31cce103815cc055c815cc0568031cc055c815ca0560031ca055c815c641", + "0x39c0ab90282c0ab106031720558014800c062e40aa8028f4180c5c8141807", + "0x3018b902aa00a3d06031720515814e40c062e40a0c03830196502831560c", + "0x2e40ae802b4c18e802ae40a0c55031ce055c81418055883018b902ac00a40", + "0x3ac0ab902bac0ad0063ac0ab902ba80ac0063a80ab902ba44e0767831d205", + "0x34c18ed02ae40ab20281818ec02ae40a0c5503018b9028300e0c75b9c0e05", + "0x300ab1063c00ab902bbc0ac0063bc0ab902bb9da0767831dc055c815d805", + "0x1418d6062ac0ab902831aa0c780300e0578015720578015a00c060157205", + "0x31aa0c1681572050635c182502ae40a0c6b83050055c81418d5062a00ab9", + "0x1f40a8c060317205060a0180c5c81418d90602c0ab902831aa0c170157205", + "0x2c0180c5c8141807062753ca93ed980caa519f57207038140eda060317205", + "0x140c056e0300c055c8140c056d83072055c81546053e83146055c8154605", + "0xf40ae0060f40ab9028f40adf060744427208f564b9028e80add060e80ab9", + "0x2a950077103084055c8148405458316699211f5720520015c20c200157205", + "0x2e40a271681dca0c20815720520815c60c1c81572051c815600c550157205", + "0x1572054c815160c0e81572050e8a00ee6060880ab9028884a07728304e05", + "0x2cc180c5c814180706032ce0c5c81d4c4203b9c18b302ae40ab3029681899", + "0x3018b90289c0a9906031720558014840c062e40aaf02900180c5c8153205", + "0x31720511015320c062e40aad02900180c5c8143a052003018b9029040ae8", + "0x2e40a2e02ba4180c5c81416057483018b902aac0ae906031720557014800c", + "0x1472053e83018b902ac80ab306031720558815320c062e40ab302a64180c", + "0x270189c02ae40a9c0289c189c02ae40a0c7503168055c8141846061180ab9", + "0x2540aeb062540ab90292094072503094055c8141848061200ab902a716807", + "0x15720555014bc0c23015720523015600c06015720506015620c2f0157205", + "0x2e40a39029f4180c5c8141807061795446062980a5e02ae40a5e02bb018aa", + "0x3018b9028300e0c065a018b903ac932077383124055c8152405580312405", + "0x31720520815d00c062e40a2702a64180c5c81560052103018b902abc0a40", + "0x2e40aae02900180c5c81444054c83018b902ab40a400603172050e814800c", + "0x1566054c83018b9028b80ae906031720505815d20c062e40aab02ba4180c", + "0x31da0c48015720506118189102ae40a92029f4180c5c81562054c83018b9", + "0x15720506120188e02ae40a8f4801d380c478157205478144e0c478157205", + "0x3018055c81418055883116055c81518057583118055c8151c8d03928188d", + "0x24418a602a2c0ab902a2c0aec062a80ab902aa80a5e062440ab902a440ab0", + "0x15dc0c2b015720559815dc0c2d015720549014fa0c062e40a0c0383116aa", + "0x14b4055803110055c81510051383110055c815145603bbc188a02ae40ab1", + "0x2100ab9029680a7d0603172050601c188602da418b903a200af0061680ab9", + "0x1560057983056a7561f8c4601e2c1720541015e60c41015720520815e40c", + "0x318a055c814f43c03bbc183c02ae40a3c0289c18c461800de72329e960b9", + "0x1880af4061800ab9029800a5a062100ab902a100ab0063140ab902b140a27", + "0x154e0b03b9818ac02ae40aac5581dcc0c3f01572053f015520c310157205", + "0x2e40a0c038318c05b5031720762815e00c158157205158b80ee60629c0ab9", + "0x3bc18c902ae40a6502bb818bf02ae40a6002bb818c702ae40a84029f4180c", + "0x3280af00631c0ab902b1c0ab0063280ab902b280a27063280ab902b257e07", + "0x15720566015600c66015720563814fa0c062e40a0c038319605b58317207", + "0x14800c062e40a7e029bc180c5c814180706032d80c5c81ce46203bd418cc", + "0x264180c5c8155a052003018b9028740a4006031720500014800c062e40aac", + "0x3018b902abc0a4006031720513815320c062e40aae02900180c5c8144405", + "0x31720561814800c062e40aa702900180c5c81588052003018b9028ac0a40", + "0x2e40a0c7b0319e055c8141846063380ab902b300a7d06031720537814de0c", + "0x31a2055c8141848063400ab902b019e074e03180055c8158005138318005", + "0x15600c06015720506015620c6a015720569815d60c698157205683440e4a", + "0x35154ce062980ad402ae40ad402bb018aa02ae40aaa0297818ce02ae40ace", + "0x3580aa606358fc075c814fc057b831aa055c81598053e83018b9028300e0c", + "0x2e40ada02a9818da3781d720537815ee0c6c81572056b815f00c6b8157205", + "0x31b8055c815b8057c831b2055c815b2057c831b8055c815b6057c031b605", + "0x2b00a400603172050601c180cb683172076e3640efa063540ab902b540ab0", + "0x15320c062e40aad02900180c5c8143a052003018b9028000a40060317205", + "0x100180c5c8155e052003018b90289c0a9906031720557014800c062e40a22", + "0x3018b902b0c0a4006031720553814800c062e40ac402900180c5c8145605", + "0x2e40a0c02ac418dd02ae40ad5029f4180c5c814fc053783018b9029bc0a6f", + "0x15aa053e83018b9028300e0c065b80a0c55831c0055c815ba0558031be05", + "0x1f80ab9029f80aa9063840ab902b840ab0060300ab9028300ab1063840ab9", + "0x2e40ee502bf018e571b88fab9029bcfce106299f60c37815720537815520c", + "0x3a4fab902b980afd063a00ab902b8c0a7d0603172050601c18e702dbdcc05", + "0x15fc0c74015720574015600c062e40aea029bc180c5c815d20537831d6ea", + "0x2e40a1d02900180c5c815d8053903018b9028300e0c76816e0ec02ae40eeb", + "0x144e054c83018b902ab80a4006031720511015320c062e40aad02900180c", + "0x29c0a4006031720562014800c062e40a2b02900180c5c8155e052003018b9", + "0x14fa0c062e40a0002900180c5c81558052003018b902b0c0a40060317205", + "0x1572050611818e002ae40aee02ac018df02ae40ae202ac418ee02ae40ae8", + "0x12018f202ae40af07781d380c780157205780144e0c780157205063fc18ef", + "0x15be0558831ea055c815e80575831e8055c815e4f30392818f302ae40a0c", + "0x3d40ab902bd40aec062a80ab902aa80a5e063800ab902b800ab00637c0ab9", + "0x3d80ab902ba00a7d06031720576814e40c062e40a0c03831eaaa7037d4c05", + "0x3c018f602ae40af602ac018f702ae40af70289c18f702ae40a005601dde0c", + "0x30d4e0777831f2055c815ec053e83018b9028300e0c7c016e20c5c81dee05", + "0x3172077d015e00c7c81572057c815600c7d01572057d0144e0c7d0157205", + "0x31fa055c815882b03bbc18fc02ae40af9029f4180c5c8141807063ec0b72", + "0x1c18fe02dcc18b903bf40af0063f00ab902bf00ab0063f40ab902bf40a27", + "0x2e40aaf8081dde0c80815720513815dc0c7f81572057e014fa0c062e40a0c", + "0x16e80c5c81e040578031fe055c815fe055803204055c8160405138320405", + "0x4140eef064140ab9028880aee064100ab902bfc0a7d0603172050601c1903", + "0x2e40f0602bc0190402ae40b0402ac0190602ae40b060289c190602ae40aae", + "0x4240ab902ab43a077783210055c81608053e83018b9028300e0c83816ea0c", + "0x321405bb031720784815e00c84015720584015600c848157205848144e0c", + "0x15720586016020c860157205062a8190b02ae40b08029f4180c5c8141807", + "0x178190b02ae40b0b02ac018e202ae40ae202ac4190e02ae40b0d02c08190d", + "0x3018b9028300e0c872aa16e2530161c055c8161c057603154055c8155405", + "0x15720506410191002ae40a0c230321e055c81610053e83018b902c280b03", + "0x128191302ae40a0c2403224055c816231003a70191102ae40b110289c1911", + "0x43c0ab0063880ab902b880ab1064540ab902c500aeb064500ab902c4a2607", + "0x322aaa87b894c058a81572058a815d80c55015720555014bc0c878157205", + "0x3018b902ab40a400603172050e814800c062e40b0702c0c180c5c8141807", + "0x2e40b180289c191802ae40a0c828322e055c8141846064580ab902c100a7d", + "0x4680ab902b9232072503232055c8141848063900ab902c622e074e0323005", + "0x14bc0c8b01572058b015600c71015720571015620c8d81572058d015d60c", + "0x40c180c5c81418070646d5516712980b1b02ae40b1b02bb018aa02ae40aaa", + "0x3018b9028880a9906031720556814800c062e40a1d02900180c5c8160605", + "0x15720506418191d02ae40a0c2303238055c815fe053e83018b902ab80a40", + "0x128192002ae40a0c240323e055c8163d1d03a70191e02ae40b1e0289c191e", + "0x4700ab0063880ab902b880ab1064880ab902c840aeb064840ab902c7e4007", + "0x3244aa8e3894c0591015720591015d80c55015720555014bc0c8e0157205", + "0x3018b902ab40a400603172050e814800c062e40afe02c0c180c5c8141807", + "0x31720557814800c062e40a2702a64180c5c8155c052003018b9028880a99", + "0x1648051383248055c81419070648c0ab9028308c0c3381572057e014fa0c", + "0x15720592c980e4a064980ab902830900c9281572059248c0e9c064900ab9", + "0x178186702ae40a6702ac018e202ae40ae202ac4192802ae40b2702bac1927", + "0x3018b9028300e0c942a8cee25301650055c81650057603154055c8155405", + "0x31720511015320c062e40aad02900180c5c8143a052003018b902bec0b03", + "0x2e40a2b02900180c5c8155e052003018b90289c0a9906031720557014800c", + "0x141908064a80ab9028308c0c9481572057c814fa0c062e40ac402900180c", + "0x4b40ab902830900c96015720595ca80e9c064ac0ab902cac0a27064ac0ab9", + "0x2c018e202ae40ae202ac4192f02ae40b2e02bac192e02ae40b2c9681c940c", + "0x2aa52e2530165e055c8165e057603154055c81554052f03252055c8165205", + "0x2e40aad02900180c5c8143a052003018b902be00b030603172050601c192f", + "0x155e052003018b90289c0a9906031720557014800c062e40a2202a64180c", + "0x30c0a4006031720553814800c062e40ac402900180c5c81456052003018b9", + "0x9c193302ae40a0c8483264055c8141846064c00ab902bd80a7d060317205", + "0x4d26a07250326a055c8141848064d00ab902cce64074e03266055c8166605", + "0x15720598015600c71015720571015620c9b81572059b015d60c9b0157205", + "0x141807064dd5530712980b3702ae40b3702bb018aa02ae40aaa029781930", + "0x2b80a4006031720511015320c062e40aad02900180c5c8143a052003018b9", + "0x14800c062e40a2b02900180c5c8155e052003018b90289c0a99060317205", + "0x100180c5c81558052003018b902b0c0a4006031720553814800c062e40ac4", + "0x2e40ae202ac4193902ae40ae702bac193802ae40ae3029f4180c5c8140005", + "0x1672055c81672057603154055c81554052f03270055c816700558031c405", + "0x1bc180c5c814c4056883018b902b2c0b030603172050601c1939554e1c4a6", + "0x3018b9028740a4006031720500014800c062e40aac02900180c5c814fc05", + "0x31720513815320c062e40aae02900180c5c81444054c83018b902ab40a40", + "0x2e40aa702900180c5c81588052003018b9028ac0a4006031720557814800c", + "0x158e053e83018b9029c80ad106031720537814de0c062e40ac302900180c", + "0x270193d02ae40b3d0289c193d02ae40a0c8503276055c8141846064e80ab9", + "0x5000aeb065000ab902cfa7e07250327e055c8141848064f80ab902cf67607", + "0x15720555014bc0c9d01572059d015600c06015720506015620ca08157205", + "0x2e40ac602c0c180c5c814180706505553a062980b4102ae40b4102bb018aa", + "0x1400052003018b902ab00a400603172053f014de0c062e40a6202b44180c", + "0x2b80a4006031720511015320c062e40aad02900180c5c8143a052003018b9", + "0x14800c062e40a2b02900180c5c8155e052003018b90289c0a99060317205", + "0x344180c5c814de053783018b902b0c0a4006031720553814800c062e40ac4", + "0x5080ab902a100a7d06031720532815320c062e40a6002a64180c5c814e405", + "0x50e00074e03286055c81686051383286055c814190b064000ab9028308c0c", + "0x157205a3815d60ca38157205a25140e4a065140ab902830900ca20157205", + "0x3b018aa02ae40aaa02978194202ae40b4202ac0180c02ae40a0c02ac41948", + "0x100180c5c8150c058183018b9028300e0ca42aa840c5301690055c8169005", + "0x3018b9029040ae806031720513815320c062e40ab002908180c5c8155e05", + "0x31720557014800c062e40a2202a64180c5c8155a052003018b9028740a40", + "0x2e40a5a029f4180c5c8145c057483018b90282c0ae906031720555815d20c", + "0x1d380c788157205788144e0c78815720506430194a02ae40a0c230329205", + "0x169a05758329a055c816974c03928194c02ae40a0c2403296055c815e34a", + "0x2a80ab902aa80a5e065240ab902d240ab0060300ab9028300ab1065380ab9", + "0x31720514015d20c062e40a0c038329caaa48314c05a70157205a7015d80c", + "0x2e40ab002908180c5c8155e052003018b902a980ab3060317205128161a0c", + "0x155a052003018b90282c0ae906031720558815320c062e40ab202acc180c", + "0xb40b0d06031720555815d20c062e40aae02900180c5c8145c057483018b9", + "0x329e055c81552053e83152055c81552055803018b902aa00b0e060317205", + "0x300ab1065480ab902d440aeb065440ab902a76a00725032a0055c8141848", + "0x157205a9015d80c4f01572054f014bc0ca78157205a7815600c060157205", + "0x2c80b77531f40eb90381c0aaf0601c0ab9028140aa6065493d4f062980b52", + "0x1562055603160055c814fa055683162055c8154c055703018b9028300e0c", + "0x155c05540315c055c81418aa0603172050601c180cbc01418ab062bc0ab9", + "0x2c00eb902ac00ac6062bc0ab902ab40aac062c00ab902ac80aad062b40ab9", + "0x3018b9028300e0c54016f2aa02ae40eaf0287418ab02ae40aac0281818ac", + "0x300f0f060a00ab9028a00a27060a00ab9028740a25060740ab902aa80a22", + "0x2e40a0c8803018b902aac0a6f0603172050601c182702de84a2203ae40e28", + "0x15720516815f20c170940eb9028940b11060ad60075c8156005630305a05", + "0x1560056303018b9028300e0c51816f60b5381d7207170b4562253448182d", + "0x2e40aa902be4189e1281d720512816220c54815720503015f00c032c00eb9", + "0x1c183d1d01ef8394e81d72074f2a54e7d8983016055c8141605568315205", + "0x18180c5c8141807061080b7d201040eb9038e44ab04ea9a240c062e40a0c", + "0x2cc8c078a8308c055c81480050303166055c81532058a03132055c8141605", + "0x1572054e0162e0c20815720520815620c4e01572055a0162c0c5a0157205", + "0x460184802ae40a0c2303018b90282c0a3d0603172050601c189c2081c0a9c", + "0x2e40a0c240312a055c814944803a70184a02ae40a4a0289c184a02ae40a0c", + "0x1080ab9029080ab1062440ab902a480ae4062480ab902a54bc0725030bc05", + "0xf4180c5c8147a058c83018b9028300e0c489080e05488157205488162e0c", + "0x3120055c814184606031720512816320c062e40ab0028f4180c5c8141605", + "0x141848062380ab902a3d20074e0311e055c8151e05138311e055c814191a", + "0x1572051d015620c45815720546015c80c460157205472340e4a062340ab9", + "0x3018b9028940b190603172050601c188b1d01c0a8b02ae40a8b02c5c183a", + "0x1572052b0144e0c2b015720506460185a02ae40a0c2303018b902ac00a3d", + "0x310c055c815148803928188802ae40a0c2403114055c814ac5a03a701856", + "0x211460702a100ab902a100b170628c0ab902a8c0ab1062100ab902a180ae4", + "0x15720541016360c410157205062a8180c5c81560051e83018b9028300e0c", + "0x304e055c8144e0558830c4055c814c0058b030c0055c81478ab03c54183c", + "0x147a0c062e40aa8029c8180c5c8141807061884e07029880ab9029880b17", + "0x1572053d2ac0f15061e80ab9029f80b1b061f80ab902831540c062e40ab0", + "0x1c0a7202ae40a7202c5c180c02ae40a0c02ac4187202ae40a6502c581865", + "0x2e40a0c0383160b103df964a603ae40e050601c0a0c062e40a0c14030e40c", + "0x2980ab1060317205062c818ae02ae40a0702a9818af02ae40ab2029f4180c", + "0x300e0c55816feac5681d7207570155e0c57815720557815600c530157205", + "0x740ab902aa80ab0062a00ab902ab00aae062a80ab902abc0a7d060317205", + "0x2e40a0c03830198002831560c11015720554015580c140157205568155a0c", + "0x15600c16815720513815500c138157205062a8182502ae40aaf029f4180c", + "0x2e40a2802818182202ae40a2d02ab0182802ae40aab02ab4181d02ae40a25", + "0x2c0ab9028740a7d0603172050601c18a702e045c055c81c44050e8305605", + "0x144e0c05815720505815600c0301572053e8154c0c51815720517014440c", + "0x2c0a7d0603172050601c189d02e093ca903ae40e0602abc18a302ae40aa3", + "0x157205518144a0c1e8157205548140c0c1d01572054f014440c1c8157205", + "0x3084055c814804103bbc184002ae40a400289c184002ae40a3a028941841", + "0x1080af0060f40ab9028f40aa9060e40ab9028e40ab0061080ab9029080a27", + "0x3166055c81472053e83018b902830500c062e40a0c038313205c18317207", + "0xf40aa9060ac0ab9028ac0aa9062cc0ab902acc0ab0062980ab902a980ab1", + "0x2e40a0c0383138b4231f40a9c5a118fab9028f456b353299f60c1e8157205", + "0x2e40a0c5503090055c81472053e83018b902a640b03060317205060a0180c", + "0x1572052f0163c0c2f01572054a8f4567d8e8312a055c81494058e0309405", + "0x1f40a9202ae40a9202c7c184802ae40a4802ac018a602ae40aa602ac41892", + "0x1546052003018b902a740a3d060317205060a0180c5c81418070624890a6", + "0x32400c48015720506118189102ae40a0b029f4180c5c81456053783018b9", + "0x15720506120188e02ae40a8f4801d380c478157205478144e0c478157205", + "0x314c055c8154c055883116055c81518059083118055c8151c8d03928188d", + "0x3018b9028300e0c45a454c7d02a2c0ab902a2c0b1f062440ab902a440ab0", + "0x1580ab902831540c2d01572050e814fa0c062e40aa7029c8180c5c8141828", + "0x310c055c81510058f03110055c815147d159f63a0c4501572052b016440c", + "0x1694c7d02a180ab902a180b1f061680ab9029680ab0062980ab902a980ab1", + "0x2e40ab0029f4180c5c8140e053783018b9029f40a6f0603172050601c1886", + "0x1d380c1e01572051e0144e0c1e015720506188188202ae40a0c230310805", + "0x14fc0590830fc055c814c06203928186202ae40a0c24030c0055c8147882", + "0x1e80ab9029e80b1f062100ab902a100ab0062c40ab902ac40ab1061e80ab9", + "0x1f81807138300e0c3e81c0a0c42118de0c5309c8c6f06299647a422c4fa05", + "0x2c564a63e81c0a0c45118de0c530180c061e0e8723944118de0c566100a0c", + "0x1f40e050629cde0c3e89c4e6f0629b0c05062541807138300f8556ab95eb0", + "0x187" + ], + "sierra_program_debug_info": { + "type_names": [], + "libfunc_names": [], + "user_func_names": [] + }, + "contract_class_version": "0.1.0", + "entry_points_by_type": { + "EXTERNAL": [ + { + "selector": "0x3c118a68e16e12e97ed25cb4901c12f4d3162818669cc44c391d8049924c14", + "function_idx": 0 + } + ], + "L1_HANDLER": [], + "CONSTRUCTOR": [] + }, + "abi": [ + { + "type": "struct", + "name": "core::array::Span::", + "members": [ + { + "name": "snapshot", + "type": "@core::array::Array::" + } + ] + }, + { + "type": "struct", + "name": "core::starknet::info::TxInfo", + "members": [ + { + "name": "version", + "type": "core::felt252" + }, + { + "name": "account_contract_address", + "type": "core::starknet::contract_address::ContractAddress" + }, + { + "name": "max_fee", + "type": "core::integer::u128" + }, + { + "name": "signature", + "type": "core::array::Span::" + }, + { + "name": "transaction_hash", + "type": "core::felt252" + }, + { + "name": "chain_id", + "type": "core::felt252" + }, + { + "name": "nonce", + "type": "core::felt252" + } + ] + }, + { + "type": "function", + "name": "test_get_execution_info", + "inputs": [ + { + "name": "expected_block_number", + "type": "core::integer::u64" + }, + { + "name": "expected_block_timestamp", + "type": "core::integer::u64" + }, + { + "name": "expected_sequencer_address", + "type": "core::starknet::contract_address::ContractAddress" + }, + { + "name": "expected_tx_info", + "type": "core::starknet::info::TxInfo" + }, + { + "name": "expected_caller_address", + "type": "core::felt252" + }, + { + "name": "expected_contract_address", + "type": "core::felt252" + }, + { + "name": "expected_entry_point_selector", + "type": "core::felt252" + } + ], + "outputs": [], + "state_mutability": "view" + }, + { + "type": "event", + "name": "test_contract_execution_info_v1::test_contract_execution_info_v1::TestContract::Event", + "kind": "enum", + "variants": [] + } + ] +} diff --git a/crates/blockifier/feature_contracts/cairo1/test_contract.cairo b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/test_contract.cairo similarity index 82% rename from crates/blockifier/feature_contracts/cairo1/test_contract.cairo rename to crates/blockifier_test_utils/resources/feature_contracts/cairo1/test_contract.cairo index 67ca9db4373..9e29deee85b 100644 --- a/crates/blockifier/feature_contracts/cairo1/test_contract.cairo +++ b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/test_contract.cairo @@ -23,13 +23,17 @@ mod TestContract { }; use core::circuit::{ CircuitElement, CircuitInput, circuit_add, circuit_sub, circuit_mul, circuit_inverse, - EvalCircuitResult, EvalCircuitTrait, u384, CircuitOutputsTrait, - CircuitModulus, CircuitInputs, AddInputResultTrait + EvalCircuitResult, EvalCircuitTrait, u384, CircuitOutputsTrait, CircuitModulus, + CircuitInputs, AddInputResultTrait }; + use core::hash::HashStateTrait; + use core::pedersen::PedersenTrait; + use core::poseidon::PoseidonTrait; #[storage] struct Storage { my_storage_var: felt252, + revert_test_storage_var: felt252, two_counters: starknet::storage::Map, ec_point: (felt252, felt252), } @@ -82,15 +86,11 @@ mod TestContract { calldata_1: Array::, ) -> Span:: { let res_0 = syscalls::call_contract_syscall( - contract_address_0, - entry_point_selector_0, - calldata_0.span(), + contract_address_0, entry_point_selector_0, calldata_0.span(), ) .unwrap_syscall(); let res_1 = syscalls::call_contract_syscall( - contract_address_1, - entry_point_selector_1, - calldata_1.span(), + contract_address_1, entry_point_selector_1, calldata_1.span(), ) .unwrap_syscall(); let mut res: Array:: = Default::default(); @@ -100,15 +100,78 @@ mod TestContract { } #[external(v0)] - fn test_revert_helper(ref self: ContractState, class_hash: ClassHash) { + fn test_revert_helper(ref self: ContractState, replacement_class_hash: ClassHash, to_panic: bool) { let dummy_span = array![0].span(); syscalls::emit_event_syscall(dummy_span, dummy_span).unwrap_syscall(); - syscalls::replace_class_syscall(class_hash).unwrap_syscall(); + syscalls::replace_class_syscall(replacement_class_hash).unwrap_syscall(); syscalls::send_message_to_l1_syscall(17.try_into().unwrap(), dummy_span).unwrap_syscall(); self.my_storage_var.write(17); - panic(array!['test_revert_helper']); + if to_panic { + panic(array!['test_revert_helper']); + } } + #[external(v0)] + fn write_10_to_my_storage_var(ref self: ContractState) { + self.my_storage_var.write(10); + } + + /// Tests the behavior of a revert scenario with an inner contract call. + /// The function performs the following: + /// 1. Calls `write_10_to_my_storage_var` to set the storage variable to 10. + /// 2. Calls `test_revert_helper` with `to_panic=true`. + /// - `test_revert_helper` is expected to change the storage variable to 17 and then panic. + /// 3. Verifies that the `test_revert_helper` changes are reverted, + /// ensuring the storage variable remains 10. + #[external(v0)] + fn test_revert_with_inner_call_and_reverted_storage( + ref self: ContractState, + contract_address: ContractAddress, + replacement_class_hash: ClassHash, + ) { + // Step 1: Call the contract to set the storage variable to 10. + syscalls::call_contract_syscall( + contract_address, + selector!("write_10_to_my_storage_var"), + array![].span(), + ) + .unwrap_syscall(); + + // Step 2: Prepare the call to `test_revert_helper` with `to_panic = true`. + let to_panic = true; + let call_data = array![replacement_class_hash.into(), to_panic.into()]; + + // Step 3: Call `test_revert_helper` and handle the expected panic. + match syscalls::call_contract_syscall( + contract_address, + selector!("test_revert_helper"), + call_data.span(), + ) { + Result::Ok(_) => panic(array!['should_panic']), + Result::Err(_revert_reason) => { + // Verify that the changes made by the second call are reverted. + assert( + self.my_storage_var.read() == 10, + 'Wrong_storage_value.', + ); + } + } + } + + #[external(v0)] + fn middle_revert_contract( + ref self: ContractState, + contract_address: ContractAddress, + entry_point_selector: felt252, + calldata: Array::, + ) { + syscalls::call_contract_syscall( + contract_address, entry_point_selector, calldata.span() + ).unwrap_syscall(); + panic(array!['execute_and_revert']); + } + + #[external(v0)] fn test_emit_events( self: @ContractState, events_number: u64, keys: Array::, data: Array:: @@ -252,6 +315,14 @@ mod TestContract { .unwrap_syscall(); } + #[external(v0)] + fn test_stack_overflow(ref self: ContractState, depth: u128) -> u128 { + non_trivial_recursion(depth) + } + + fn non_trivial_recursion(depth: u128) -> u128 { + non_trivial_recursion(depth - 1) + 2 * non_trivial_recursion(depth - 2) + } #[external(v0)] fn test_keccak(ref self: ContractState) { @@ -594,8 +665,13 @@ mod TestContract { let mul = circuit_mul(inv, sub); let modulus = TryInto::<_, CircuitModulus>::try_into([7, 0, 0, 0]).unwrap(); - let outputs = - (mul,).new_inputs().next([3, 0, 0, 0]).next([6, 0, 0, 0]).done().eval(modulus).unwrap(); + let outputs = (mul,) + .new_inputs() + .next([3, 0, 0, 0]) + .next([6, 0, 0, 0]) + .done() + .eval(modulus) + .unwrap(); assert!(outputs.get_output(mul) == u384 { limb0: 6, limb1: 0, limb2: 0, limb3: 0 }); } @@ -624,27 +700,75 @@ mod TestContract { entry_point_selector: felt252, calldata: Array:: ) { - let class_hash_before_call = syscalls::get_class_hash_at_syscall(contract_address).unwrap_syscall(); - match syscalls::call_contract_syscall( - contract_address, entry_point_selector, calldata.span()) - { + let class_hash_before_call = syscalls::get_class_hash_at_syscall(contract_address) + .unwrap_syscall(); + self.revert_test_storage_var.write(7); + match syscalls::call_contract_syscall( + contract_address, entry_point_selector, calldata.span() + ) { Result::Ok(_) => panic!("Expected revert"), Result::Err(errors) => { let mut error_span = errors.span(); - assert( - *error_span.pop_back().unwrap() == 'ENTRYPOINT_FAILED', - 'Unexpected error', - ); + assert(*error_span.pop_back().unwrap() == 'ENTRYPOINT_FAILED', 'Unexpected error',); let inner_error = *error_span.pop_back().unwrap(); if entry_point_selector == selector!("bad_selector") { assert(inner_error == 'ENTRYPOINT_NOT_FOUND', 'Unexpected error'); - } else { + } else if entry_point_selector == selector!("test_revert_helper") { assert(inner_error == 'test_revert_helper', 'Unexpected error'); } + else { + assert(entry_point_selector == selector!("middle_revert_contract"), 'Wrong Entry Point'); + assert(inner_error == 'execute_and_revert', 'Wrong_error'); + } }, }; - let class_hash_after_call = syscalls::get_class_hash_at_syscall(contract_address).unwrap_syscall(); + let class_hash_after_call = syscalls::get_class_hash_at_syscall(contract_address) + .unwrap_syscall(); assert(self.my_storage_var.read() == 0, 'values should not change.'); assert(class_hash_before_call == class_hash_after_call, 'class hash should not change.'); + assert(self.revert_test_storage_var.read() == 7, 'test_storage_var_changed.'); + } + + #[external(v0)] + fn return_result(ref self: ContractState, num: felt252) -> felt252 { + let result = num; + result + } + + #[external(v0)] + fn empty_function(ref self: ContractState) { + } + + #[external(v0)] + fn test_bitwise(ref self: ContractState) { + let x: u32 = 0x1; + let y: u32 = 0x2; + let _z = x & y; + } + + #[external(v0)] + fn test_pedersen (ref self: ContractState) { + let mut state = PedersenTrait::new(0); + state = state.update(1); + let _hash = state.finalize(); + } + + #[external(v0)] + fn test_poseidon (ref self: ContractState) { + let mut state = PoseidonTrait::new(); + state = state.update(1); + let _hash = state.finalize(); + } + + #[external(v0)] + fn test_ecop (ref self: ContractState) { + let m: felt252 = 2; + let a: felt252 = 336742005567258698661916498343089167447076063081786685068305785816009957563; + let b: felt252 = 1706004133033694959518200210163451614294041810778629639790706933324248611779; + let p : ec::NonZeroEcPoint = (ec::ec_point_try_new_nz(a, b)).unwrap(); + let mut s: ec::EcState = ec::ec_state_init(); + ec::ec_state_add_mul(ref s, m, p); } } + + diff --git a/crates/blockifier/feature_contracts/cairo_native/test_contract_execution_info_v1.cairo b/crates/blockifier_test_utils/resources/feature_contracts/cairo1/test_contract_execution_info_v1.cairo similarity index 100% rename from crates/blockifier/feature_contracts/cairo_native/test_contract_execution_info_v1.cairo rename to crates/blockifier_test_utils/resources/feature_contracts/cairo1/test_contract_execution_info_v1.cairo diff --git a/crates/blockifier/src/test_utils/cairo_compile.rs b/crates/blockifier_test_utils/src/cairo_compile.rs similarity index 74% rename from crates/blockifier/src/test_utils/cairo_compile.rs rename to crates/blockifier_test_utils/src/cairo_compile.rs index a0c5f77a8d9..ae4ea5acac2 100644 --- a/crates/blockifier/src/test_utils/cairo_compile.rs +++ b/crates/blockifier_test_utils/src/cairo_compile.rs @@ -3,65 +3,29 @@ use std::path::{Path, PathBuf}; use std::process::{Command, Output}; use std::{env, fs}; -use cached::proc_macro::cached; -use serde::{Deserialize, Serialize}; +use starknet_infra_utils::cairo_compiler_version::cairo1_compiler_version; +use starknet_infra_utils::compile_time_cargo_manifest_dir; use tempfile::NamedTempFile; +use crate::contracts::TagAndToolchain; + const CAIRO0_PIP_REQUIREMENTS_FILE: &str = "tests/requirements.txt"; const CAIRO1_REPO_RELATIVE_PATH_OVERRIDE_ENV_VAR: &str = "CAIRO1_REPO_RELATIVE_PATH"; const DEFAULT_CAIRO1_REPO_RELATIVE_PATH: &str = "../../../cairo"; -/// Objects for simple deserialization of Cargo.toml to fetch the Cairo1 compiler version. -/// The compiler itself isn't actually a dependency, so we compile by using the version of the -/// cairo-lang-casm crate. -/// The choice of cairo-lang-casm is arbitrary, as all compiler crate dependencies should have the -/// same version. -/// Deserializes: -/// """ -/// ... -/// [workspace.dependencies] -/// ... -/// cairo-lang-casm = VERSION -/// ... -/// """ -/// where `VERSION` can be a simple "x.y.z" version string or an object with a "version" field. -#[derive(Debug, Serialize, Deserialize)] -#[serde(untagged)] -enum DependencyValue { - // cairo-lang-casm = "x.y.z". - String(String), - // cairo-lang-casm = { version = "x.y.z", .. }. - Object { version: String }, -} - -#[derive(Debug, Serialize, Deserialize)] -struct CairoLangCasmDependency { - #[serde(rename = "cairo-lang-casm")] - cairo_lang_casm: DependencyValue, -} - -#[derive(Debug, Serialize, Deserialize)] -struct WorkspaceFields { - dependencies: CairoLangCasmDependency, -} - -#[derive(Debug, Serialize, Deserialize)] -struct CargoToml { - workspace: WorkspaceFields, -} - -#[cached] -/// Returns the version of the Cairo1 compiler defined in the root Cargo.toml (by checking the -/// package version of one of the crates from the compiler in the dependencies). -pub fn cairo1_compiler_version() -> String { - let cargo_toml: CargoToml = toml::from_str(include_str!("../../../../Cargo.toml")).unwrap(); - match cargo_toml.workspace.dependencies.cairo_lang_casm { - DependencyValue::String(version) | DependencyValue::Object { version } => version.clone(), - } +pub enum CompilationArtifacts { + Cairo0 { casm: Vec }, + Cairo1 { casm: Vec, sierra: Vec }, } pub fn cairo1_compiler_tag() -> String { - format!("v{}", cairo1_compiler_version()) + // TODO(lior): Uncomment the following line it and remove the rest of the code, once the + // Cairo compiler version is updated to 2.11.0 in the toml file. + // If the compiler version is updated in the toml to a version < 2.11.0, + // only update the version in the assert below. + // format!("v{}", cairo1_compiler_version()) + assert_eq!(cairo1_compiler_version(), "2.10.0", "Unsupported compiler version."); + "v2.11.0-dev.2".into() } /// Returns the path to the local Cairo1 compiler repository. @@ -69,7 +33,7 @@ pub fn cairo1_compiler_tag() -> String { /// overridden by the environment variable (otherwise, the default is used). fn local_cairo1_compiler_repo_path() -> PathBuf { // Location of blockifier's Cargo.toml. - let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); + let manifest_dir = compile_time_cargo_manifest_dir!(); Path::new(&manifest_dir).join( env::var(CAIRO1_REPO_RELATIVE_PATH_OVERRIDE_ENV_VAR) @@ -89,7 +53,11 @@ fn run_and_verify_output(command: &mut Command) -> Output { } /// Compiles a Cairo0 program using the deprecated compiler. -pub fn cairo0_compile(path: String, extra_arg: Option, debug_info: bool) -> Vec { +pub fn cairo0_compile( + path: String, + extra_arg: Option, + debug_info: bool, +) -> CompilationArtifacts { verify_cairo0_compiler_deps(); let mut command = Command::new("starknet-compile-deprecated"); command.arg(&path); @@ -102,7 +70,7 @@ pub fn cairo0_compile(path: String, extra_arg: Option, debug_info: bool) let compile_output = command.output().unwrap(); let stderr_output = String::from_utf8(compile_output.stderr).unwrap(); assert!(compile_output.status.success(), "{stderr_output}"); - compile_output.stdout + CompilationArtifacts::Cairo0 { casm: compile_output.stdout } } /// Compiles a Cairo1 program using the compiler version set in the Cargo.toml. @@ -110,7 +78,7 @@ pub fn cairo1_compile( path: String, git_tag_override: Option, cargo_nightly_arg: Option, -) -> Vec { +) -> CompilationArtifacts { let mut base_compile_args = vec![]; let sierra_output = @@ -131,7 +99,7 @@ pub fn cairo1_compile( ]); let casm_output = run_and_verify_output(&mut sierra_compile_command); - casm_output.stdout + CompilationArtifacts::Cairo1 { casm: casm_output.stdout, sierra: sierra_output } } /// Compile Cairo1 Contract into their Sierra version using the compiler version set in the @@ -142,7 +110,7 @@ pub fn starknet_compile( cargo_nightly_arg: Option, base_compile_args: &mut Vec, ) -> Vec { - prepare_cairo1_compiler_deps(git_tag_override); + verify_cairo1_compiler_deps(git_tag_override); let cairo1_compiler_path = local_cairo1_compiler_repo_path(); @@ -199,15 +167,14 @@ fn verify_cairo0_compiler_deps() { } else { format!("installed version: {cairo_lang_version}") }, - env::var("CARGO_MANIFEST_DIR").unwrap(), + compile_time_cargo_manifest_dir!(), CAIRO0_PIP_REQUIREMENTS_FILE ); } -fn prepare_cairo1_compiler_deps(git_tag_override: Option) { - let cairo_repo_path = local_cairo1_compiler_repo_path(); +fn get_tag_and_repo_file_path(git_tag_override: Option) -> (String, PathBuf) { let tag = git_tag_override.unwrap_or(cairo1_compiler_tag()); - + let cairo_repo_path = local_cairo1_compiler_repo_path(); // Check if the path is a directory. assert!( cairo_repo_path.is_dir(), @@ -216,7 +183,14 @@ fn prepare_cairo1_compiler_deps(git_tag_override: Option) { cairo_repo_path.to_string_lossy(), ); + (tag, cairo_repo_path) +} + +pub fn prepare_group_tag_compiler_deps(tag_and_toolchain: &TagAndToolchain) { + let (optional_tag, optional_toolchain) = tag_and_toolchain; + // Checkout the required version in the compiler repo. + let (tag, cairo_repo_path) = get_tag_and_repo_file_path(optional_tag.clone()); run_and_verify_output(Command::new("git").args([ "-C", cairo_repo_path.to_str().unwrap(), @@ -224,6 +198,17 @@ fn prepare_cairo1_compiler_deps(git_tag_override: Option) { &tag, ])); + // Install the toolchain, if specified. + if let Some(toolchain) = optional_toolchain { + run_and_verify_output( + Command::new("rustup").args(["install", &format!("nightly-{toolchain}")]), + ); + } +} + +fn verify_cairo1_compiler_deps(git_tag_override: Option) { + let (tag, cairo_repo_path) = get_tag_and_repo_file_path(git_tag_override); + // Verify that the checked out tag is as expected. run_and_verify_output(Command::new("git").args([ "-C", diff --git a/crates/blockifier_test_utils/src/cairo_versions.rs b/crates/blockifier_test_utils/src/cairo_versions.rs new file mode 100644 index 00000000000..e275a138ff4 --- /dev/null +++ b/crates/blockifier_test_utils/src/cairo_versions.rs @@ -0,0 +1,50 @@ +use starknet_api::transaction::TransactionVersion; + +#[derive(Clone, Hash, PartialEq, Eq, Copy, Debug)] +pub enum RunnableCairo1 { + Casm, + #[cfg(feature = "cairo_native")] + Native, +} + +impl Default for RunnableCairo1 { + fn default() -> Self { + Self::Casm + } +} + +// TODO(Aviv, 14/7/2024): Move from test utils module, and use it in ContractClassVersionMismatch +// error. +#[derive(Clone, Hash, PartialEq, Eq, Copy, Debug)] +pub enum CairoVersion { + Cairo0, + Cairo1(RunnableCairo1), +} + +impl Default for CairoVersion { + fn default() -> Self { + Self::Cairo0 + } +} + +impl CairoVersion { + // A declare transaction of the given version, can be used to declare contracts of the returned + // cairo version. + // TODO(Dori): Make TransactionVersion an enum and use match here. + pub fn from_declare_tx_version(tx_version: TransactionVersion) -> Self { + if tx_version == TransactionVersion::ZERO || tx_version == TransactionVersion::ONE { + CairoVersion::Cairo0 + } else if tx_version == TransactionVersion::TWO || tx_version == TransactionVersion::THREE { + CairoVersion::Cairo1(RunnableCairo1::Casm) + } else { + panic!("Transaction version {:?} is not supported.", tx_version) + } + } + + pub fn is_cairo0(&self) -> bool { + match self { + Self::Cairo0 => true, + Self::Cairo1(_) => false, + } + } +} diff --git a/crates/blockifier_test_utils/src/calldata.rs b/crates/blockifier_test_utils/src/calldata.rs new file mode 100644 index 00000000000..7c69894c915 --- /dev/null +++ b/crates/blockifier_test_utils/src/calldata.rs @@ -0,0 +1,51 @@ +use starknet_api::abi::abi_utils::selector_from_name; +use starknet_api::core::ContractAddress; +use starknet_api::felt; +use starknet_api::transaction::fields::Calldata; +use starknet_types_core::felt::Felt; + +use crate::types::u64_from_usize; + +/// Creates the calldata for the "__execute__" entry point in the featured contracts +/// ([`crate::contracts::FeatureContract`]) AccountWithLongValidate and AccountWithoutValidations. +/// The format of the returned calldata is: +/// [ +/// contract_address, +/// entry_point_name, +/// calldata_length, +/// *calldata, +/// ] +/// The contract_address is the address of the called contract, the entry_point_name is the +/// name of the called entry point in said contract, and the calldata is the calldata for the +/// called entry point. +pub fn create_calldata( + contract_address: ContractAddress, + entry_point_name: &str, + entry_point_args: &[Felt], +) -> Calldata { + Calldata( + [ + vec![ + *contract_address.0.key(), // Contract address. + selector_from_name(entry_point_name).0, // EP selector name. + felt!(u64_from_usize(entry_point_args.len())), + ], + entry_point_args.into(), + ] + .concat() + .into(), + ) +} + +/// Calldata for a trivial entry point in the [`crate::contracts::FeatureContract`] TestContract. +/// The calldata is formatted for using the featured contracts AccountWithLongValidate or +/// AccountWithoutValidations as account contract. +/// The contract_address is the address of the called contract, an instance address of +/// TestContract. +pub fn create_trivial_calldata(test_contract_address: ContractAddress) -> Calldata { + create_calldata( + test_contract_address, + "return_result", + &[felt!(2_u8)], // Calldata: num. + ) +} diff --git a/crates/blockifier_test_utils/src/contracts.rs b/crates/blockifier_test_utils/src/contracts.rs new file mode 100644 index 00000000000..df82fb3277c --- /dev/null +++ b/crates/blockifier_test_utils/src/contracts.rs @@ -0,0 +1,419 @@ +use std::collections::HashMap; +use std::fs; +use std::path::PathBuf; + +use cairo_lang_starknet_classes::contract_class::ContractClass as CairoLangContractClass; +use itertools::Itertools; +use starknet_api::contract_class::SierraVersion; +use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress}; +use starknet_api::state::SierraContractClass; +use starknet_api::{class_hash, contract_address, felt}; +use starknet_infra_utils::compile_time_cargo_manifest_dir; +use starknet_types_core::felt::Felt; +use strum::IntoEnumIterator; +use strum_macros::EnumIter; + +use crate::cairo_compile::{cairo0_compile, cairo1_compile, CompilationArtifacts}; +use crate::cairo_versions::{CairoVersion, RunnableCairo1}; + +pub const CAIRO1_FEATURE_CONTRACTS_DIR: &str = "resources/feature_contracts/cairo1"; +pub const SIERRA_CONTRACTS_SUBDIR: &str = "sierra"; + +// This file contains featured contracts, used for tests. Use the function 'test_state' in +// initial_test_state.rs to initialize a state with these contracts. +// +// Use the mock class hashes and addresses to interact with the contracts in tests. +// The structure of such mock address / class hash is as follows: +// +-+-+-----------+---------------+---------------+---------------+ +// |v|a| reserved | 8 bits: class | 16 bits : address | +// +-+-+-----------+---------------+---------------+---------------+ +// v: 1 bit. 0 for Cairo0, 1 for Cairo1. bit 31. +// a: 1 bit. 0 for class hash, 1 for address. bit 30. +// reserved: Must be 0. bit 29-24. +// class: 8 bits. The class hash of the contract. bit 23-16. allows up to 256 unique contracts. +// address: 16 bits. The instance ID of the contract. bit 15-0. allows up to 65536 instances of each +// contract. + +// Bit to set on class hashes and addresses of feature contracts to indicate the Cairo1 variant. +const CAIRO1_BIT: u32 = 1 << 31; + +// Bit to set on a class hash to convert it to the respective address. +const ADDRESS_BIT: u32 = 1 << 30; + +// Mock class hashes of the feature contract. Keep the bottom 16 bits of each class hash unset, to +// allow up to 65536 deployed instances of each contract. +const CLASS_HASH_BASE: u32 = 1 << 16; +const ACCOUNT_LONG_VALIDATE_BASE: u32 = CLASS_HASH_BASE; +const ACCOUNT_WITHOUT_VALIDATIONS_BASE: u32 = 2 * CLASS_HASH_BASE; +const EMPTY_CONTRACT_BASE: u32 = 3 * CLASS_HASH_BASE; +const FAULTY_ACCOUNT_BASE: u32 = 4 * CLASS_HASH_BASE; +const LEGACY_CONTRACT_BASE: u32 = 5 * CLASS_HASH_BASE; +const SECURITY_TEST_CONTRACT_BASE: u32 = 6 * CLASS_HASH_BASE; +const TEST_CONTRACT_BASE: u32 = 7 * CLASS_HASH_BASE; +const ERC20_CONTRACT_BASE: u32 = 8 * CLASS_HASH_BASE; +const CAIRO_STEPS_TEST_CONTRACT_BASE: u32 = 9 * CLASS_HASH_BASE; +const SIERRA_EXECUTION_INFO_V1_CONTRACT_BASE: u32 = 10 * CLASS_HASH_BASE; +const META_TX_CONTRACT_BASE: u32 = 11 * CLASS_HASH_BASE; + +// Contract names. +const ACCOUNT_LONG_VALIDATE_NAME: &str = "account_with_long_validate"; +const ACCOUNT_WITHOUT_VALIDATIONS_NAME: &str = "account_with_dummy_validate"; +const EMPTY_CONTRACT_NAME: &str = "empty_contract"; +const FAULTY_ACCOUNT_NAME: &str = "account_faulty"; +const LEGACY_CONTRACT_NAME: &str = "legacy_test_contract"; +const SECURITY_TEST_CONTRACT_NAME: &str = "security_tests_contract"; +const TEST_CONTRACT_NAME: &str = "test_contract"; +const CAIRO_STEPS_TEST_CONTRACT_NAME: &str = "cairo_steps_test_contract"; +const EXECUTION_INFO_V1_CONTRACT_NAME: &str = "test_contract_execution_info_v1"; +const META_TX_CONTRACT_NAME: &str = "meta_tx_test_contract"; + +// ERC20 contract is in a unique location. +const ERC20_CAIRO0_CONTRACT_SOURCE_PATH: &str = + "./resources/ERC20/ERC20_Cairo0/ERC20_without_some_syscalls/ERC20/ERC20.cairo"; +const ERC20_CAIRO0_CONTRACT_PATH: &str = "./resources/ERC20/ERC20_Cairo0/\ + ERC20_without_some_syscalls/ERC20/\ + erc20_contract_without_some_syscalls_compiled.json"; +const ERC20_CAIRO1_CONTRACT_SOURCE_PATH: &str = "./resources/ERC20/ERC20_Cairo1/ERC20.cairo"; +const ERC20_SIERRA_CONTRACT_PATH: &str = "./resources/ERC20/ERC20_Cairo1/erc20.sierra.json"; +const ERC20_CAIRO1_CONTRACT_PATH: &str = "./resources/ERC20/ERC20_Cairo1/erc20.casm.json"; + +// The following contracts are compiled with a fixed version of the compiler. This compiler version +// no longer compiles with stable rust, so the toolchain is also fixed. +const LEGACY_CONTRACT_COMPILER_TAG: &str = "v2.1.0"; +const LEGACY_CONTRACT_RUST_TOOLCHAIN: &str = "2023-07-05"; + +const CAIRO_STEPS_TEST_CONTRACT_COMPILER_TAG: &str = "v2.7.0"; +const CAIRO_STEPS_TEST_CONTRACT_RUST_TOOLCHAIN: &str = "2024-04-29"; + +pub type TagAndToolchain = (Option, Option); +pub type TagToContractsMapping = HashMap>; + +/// Enum representing all feature contracts. +/// The contracts that are implemented in both Cairo versions include a version field. +#[derive(Clone, Copy, Debug, EnumIter, Hash, PartialEq, Eq)] +pub enum FeatureContract { + AccountWithLongValidate(CairoVersion), + AccountWithoutValidations(CairoVersion), + ERC20(CairoVersion), + Empty(CairoVersion), + FaultyAccount(CairoVersion), + LegacyTestContract, + SecurityTests, + TestContract(CairoVersion), + CairoStepsTestContract, + SierraExecutionInfoV1Contract(RunnableCairo1), + MetaTx(RunnableCairo1), +} + +impl FeatureContract { + pub fn cairo_version(&self) -> CairoVersion { + match self { + Self::AccountWithLongValidate(version) + | Self::AccountWithoutValidations(version) + | Self::Empty(version) + | Self::FaultyAccount(version) + | Self::TestContract(version) + | Self::ERC20(version) => *version, + Self::SecurityTests => CairoVersion::Cairo0, + Self::LegacyTestContract | Self::CairoStepsTestContract => { + CairoVersion::Cairo1(RunnableCairo1::Casm) + } + Self::SierraExecutionInfoV1Contract(runnable_version) + | Self::MetaTx(runnable_version) => CairoVersion::Cairo1(*runnable_version), + } + } + + pub fn set_cairo_version(&mut self, version: CairoVersion) { + match self { + Self::AccountWithLongValidate(v) + | Self::AccountWithoutValidations(v) + | Self::Empty(v) + | Self::FaultyAccount(v) + | Self::TestContract(v) + | Self::ERC20(v) => *v = version, + Self::SierraExecutionInfoV1Contract(rv) | Self::MetaTx(rv) => match version { + CairoVersion::Cairo0 => panic!("{self:?} must be Cairo1"), + CairoVersion::Cairo1(runnable) => *rv = runnable, + }, + Self::SecurityTests | Self::CairoStepsTestContract | Self::LegacyTestContract => { + panic!("{self:?} contract has no configurable version.") + } + } + } + + pub fn get_class_hash(&self) -> ClassHash { + class_hash!(self.get_integer_base()) + } + + pub fn get_compiled_class_hash(&self) -> CompiledClassHash { + match self.cairo_version() { + CairoVersion::Cairo0 => CompiledClassHash(Felt::ZERO), + CairoVersion::Cairo1(_) => CompiledClassHash(felt!(self.get_integer_base())), + } + } + + /// Returns the address of the instance with the given instance ID. + pub fn instance_address(integer_base: u32, instance_id: u32) -> ContractAddress { + contract_address!(integer_base + instance_id + ADDRESS_BIT) + } + + /// Returns the address of the instance with the given instance ID. + pub fn get_instance_address(&self, instance_id: u16) -> ContractAddress { + Self::instance_address(self.get_integer_base(), instance_id.into()) + } + + pub fn get_raw_sierra(&self) -> String { + if self.cairo_version() == CairoVersion::Cairo0 { + panic!("The sierra contract is only available for Cairo1."); + } + + get_raw_contract_class(&self.get_sierra_path()) + } + + pub fn get_sierra(&self) -> SierraContractClass { + let raw_sierra = self.get_raw_sierra(); + let cairo_contract_class: CairoLangContractClass = + serde_json::from_str(&raw_sierra).unwrap(); + SierraContractClass::from(cairo_contract_class) + } + + pub fn get_sierra_version(&self) -> SierraVersion { + SierraVersion::extract_from_program(&self.get_sierra().sierra_program).unwrap() + } + + pub fn get_raw_class(&self) -> String { + get_raw_contract_class(&self.get_compiled_path()) + } + + fn get_cairo_version_bit(&self) -> u32 { + match self.cairo_version() { + CairoVersion::Cairo0 => 0, + CairoVersion::Cairo1(_) => CAIRO1_BIT, + } + } + + /// Some contracts are designed to test behavior of code compiled with a + /// specific (old) compiler tag. To run the (old) compiler, older rust + /// version is required. + pub fn fixed_tag_and_rust_toolchain(&self) -> TagAndToolchain { + match self { + Self::LegacyTestContract => ( + Some(LEGACY_CONTRACT_COMPILER_TAG.into()), + Some(LEGACY_CONTRACT_RUST_TOOLCHAIN.into()), + ), + Self::CairoStepsTestContract => ( + Some(CAIRO_STEPS_TEST_CONTRACT_COMPILER_TAG.into()), + Some(CAIRO_STEPS_TEST_CONTRACT_RUST_TOOLCHAIN.into()), + ), + _ => (None, None), + } + } + + /// Unique integer representing each unique contract. Used to derive "class hash" and "address". + pub fn get_integer_base(self) -> u32 { + self.get_cairo_version_bit() + + match self { + Self::AccountWithLongValidate(_) => ACCOUNT_LONG_VALIDATE_BASE, + Self::AccountWithoutValidations(_) => ACCOUNT_WITHOUT_VALIDATIONS_BASE, + Self::Empty(_) => EMPTY_CONTRACT_BASE, + Self::ERC20(_) => ERC20_CONTRACT_BASE, + Self::FaultyAccount(_) => FAULTY_ACCOUNT_BASE, + Self::LegacyTestContract => LEGACY_CONTRACT_BASE, + Self::SecurityTests => SECURITY_TEST_CONTRACT_BASE, + Self::TestContract(_) => TEST_CONTRACT_BASE, + Self::CairoStepsTestContract => CAIRO_STEPS_TEST_CONTRACT_BASE, + Self::SierraExecutionInfoV1Contract(_) => SIERRA_EXECUTION_INFO_V1_CONTRACT_BASE, + Self::MetaTx(_) => META_TX_CONTRACT_BASE, + } + } + + fn get_non_erc20_base_name(&self) -> &str { + match self { + Self::AccountWithLongValidate(_) => ACCOUNT_LONG_VALIDATE_NAME, + Self::AccountWithoutValidations(_) => ACCOUNT_WITHOUT_VALIDATIONS_NAME, + Self::Empty(_) => EMPTY_CONTRACT_NAME, + Self::FaultyAccount(_) => FAULTY_ACCOUNT_NAME, + Self::LegacyTestContract => LEGACY_CONTRACT_NAME, + Self::SecurityTests => SECURITY_TEST_CONTRACT_NAME, + Self::TestContract(_) => TEST_CONTRACT_NAME, + Self::CairoStepsTestContract => CAIRO_STEPS_TEST_CONTRACT_NAME, + Self::SierraExecutionInfoV1Contract(_) => EXECUTION_INFO_V1_CONTRACT_NAME, + Self::MetaTx(_) => META_TX_CONTRACT_NAME, + Self::ERC20(_) => unreachable!(), + } + } + + pub fn get_source_path(&self) -> String { + // Special case: ERC20 contract in a different location. + if let Self::ERC20(cairo_version) = self { + match cairo_version { + CairoVersion::Cairo0 => ERC20_CAIRO0_CONTRACT_SOURCE_PATH, + CairoVersion::Cairo1(RunnableCairo1::Casm) => ERC20_CAIRO1_CONTRACT_SOURCE_PATH, + #[cfg(feature = "cairo_native")] + CairoVersion::Cairo1(RunnableCairo1::Native) => { + todo!("ERC20 contract is not supported by Native yet") + } + } + .into() + } else { + format!( + "resources/feature_contracts/cairo{}/{}.cairo", + match self.cairo_version() { + CairoVersion::Cairo0 => "0", + CairoVersion::Cairo1(_) => "1", + }, + self.get_non_erc20_base_name() + ) + } + } + + pub fn get_sierra_path(&self) -> String { + assert_ne!(self.cairo_version(), CairoVersion::Cairo0); + // This is not the compiled Sierra file of the existing ERC20 contract, + // but a file that was taken from the compiler repo of another ERC20 contract. + if matches!(self, &Self::ERC20(CairoVersion::Cairo1(_))) { + return ERC20_SIERRA_CONTRACT_PATH.to_string(); + } + + format!( + "{CAIRO1_FEATURE_CONTRACTS_DIR}/{SIERRA_CONTRACTS_SUBDIR}/{}.sierra.json", + self.get_non_erc20_base_name() + ) + } + + pub fn get_compiled_path(&self) -> String { + // ERC20 is a special case - not in the feature_contracts directory. + if let Self::ERC20(cairo_version) = self { + match cairo_version { + CairoVersion::Cairo0 => ERC20_CAIRO0_CONTRACT_PATH, + CairoVersion::Cairo1(RunnableCairo1::Casm) => ERC20_CAIRO1_CONTRACT_PATH, + #[cfg(feature = "cairo_native")] + CairoVersion::Cairo1(RunnableCairo1::Native) => { + todo!("ERC20 cannot be tested with Native") + } + } + .into() + } else { + let cairo_version = self.cairo_version(); + format!( + "resources/feature_contracts/cairo{}/{}{}.json", + match cairo_version { + CairoVersion::Cairo0 => "0/compiled", + CairoVersion::Cairo1(RunnableCairo1::Casm) => "1/compiled", + #[cfg(feature = "cairo_native")] + CairoVersion::Cairo1(RunnableCairo1::Native) => "1/sierra", + }, + self.get_non_erc20_base_name(), + match cairo_version { + CairoVersion::Cairo0 => "_compiled", + CairoVersion::Cairo1(RunnableCairo1::Casm) => ".casm", + #[cfg(feature = "cairo_native")] + CairoVersion::Cairo1(RunnableCairo1::Native) => ".sierra", + } + ) + } + } + + /// Compiles the feature contract and returns the compiled contract as a byte vector. + /// Panics if the contract is ERC20, as ERC20 contract recompilation is not supported. + pub fn compile(&self) -> CompilationArtifacts { + if matches!(self, Self::ERC20(_)) { + panic!("ERC20 contract recompilation not supported."); + } + match self.cairo_version() { + CairoVersion::Cairo0 => { + let extra_arg: Option = match self { + // Account contracts require the account_contract flag. + FeatureContract::AccountWithLongValidate(_) + | FeatureContract::AccountWithoutValidations(_) + | FeatureContract::FaultyAccount(_) => Some("--account_contract".into()), + FeatureContract::SecurityTests => Some("--disable_hint_validation".into()), + FeatureContract::Empty(_) + | FeatureContract::TestContract(_) + | FeatureContract::LegacyTestContract + | FeatureContract::CairoStepsTestContract + | FeatureContract::SierraExecutionInfoV1Contract(_) + | FeatureContract::MetaTx(_) => None, + FeatureContract::ERC20(_) => unreachable!(), + }; + cairo0_compile(self.get_source_path(), extra_arg, false) + } + CairoVersion::Cairo1(_) => { + let (tag_override, cargo_nightly_arg) = self.fixed_tag_and_rust_toolchain(); + cairo1_compile(self.get_source_path(), tag_override, cargo_nightly_arg) + } + } + } + + fn iter_versions(&self, versions: &[CairoVersion]) -> Vec { + versions + .iter() + .map(|&v| { + let mut versioned_contract = *self; + versioned_contract.set_cairo_version(v); + versioned_contract + }) + .collect() + } + + fn all_contract_versions(&self) -> Vec { + match self { + Self::AccountWithLongValidate(_) + | Self::AccountWithoutValidations(_) + | Self::Empty(_) + | Self::FaultyAccount(_) + | Self::TestContract(_) + | Self::ERC20(_) => { + #[cfg(not(feature = "cairo_native"))] + let versions = [CairoVersion::Cairo0, CairoVersion::Cairo1(RunnableCairo1::Casm)]; + #[cfg(feature = "cairo_native")] + let versions = [ + CairoVersion::Cairo0, + CairoVersion::Cairo1(RunnableCairo1::Casm), + CairoVersion::Cairo1(RunnableCairo1::Native), + ]; + self.iter_versions(&versions) + } + + Self::SierraExecutionInfoV1Contract(_) | Self::MetaTx(_) => { + #[cfg(not(feature = "cairo_native"))] + { + vec![*self] + } + #[cfg(feature = "cairo_native")] + { + let versions = [ + CairoVersion::Cairo1(RunnableCairo1::Casm), + CairoVersion::Cairo1(RunnableCairo1::Native), + ]; + self.iter_versions(&versions) + } + } + + Self::LegacyTestContract | Self::CairoStepsTestContract | Self::SecurityTests => { + vec![*self] + } + } + } + + pub fn all_contracts() -> impl Iterator { + Self::iter().flat_map(|contract| contract.all_contract_versions()) + } + + pub fn all_feature_contracts() -> impl Iterator { + // ERC20 is a special case - not in the feature_contracts directory. + Self::all_contracts().filter(|contract| !matches!(contract, Self::ERC20(_))) + } + + pub fn cairo1_feature_contracts_by_tag() -> TagToContractsMapping { + Self::all_feature_contracts() + .filter(|contract| contract.cairo_version() != CairoVersion::Cairo0) + .map(|contract| (contract.fixed_tag_and_rust_toolchain(), contract)) + .into_group_map() + } +} + +pub fn get_raw_contract_class(contract_path: &str) -> String { + let path: PathBuf = [compile_time_cargo_manifest_dir!(), contract_path].iter().collect(); + fs::read_to_string(path).unwrap() +} diff --git a/crates/blockifier_test_utils/src/lib.rs b/crates/blockifier_test_utils/src/lib.rs new file mode 100644 index 00000000000..8c73f2b168c --- /dev/null +++ b/crates/blockifier_test_utils/src/lib.rs @@ -0,0 +1,5 @@ +pub mod cairo_compile; +pub mod cairo_versions; +pub mod calldata; +pub mod contracts; +pub mod types; diff --git a/crates/blockifier_test_utils/src/types.rs b/crates/blockifier_test_utils/src/types.rs new file mode 100644 index 00000000000..8edfca91486 --- /dev/null +++ b/crates/blockifier_test_utils/src/types.rs @@ -0,0 +1,5 @@ +/// Conversion from usize to u64. May fail on architectures with over 64 bits +/// of address space. +pub fn u64_from_usize(val: usize) -> u64 { + val.try_into().expect("Conversion from usize to u64 should not fail.") +} diff --git a/crates/blockifier_test_utils/tests/feature_contracts_compatibility_test.rs b/crates/blockifier_test_utils/tests/feature_contracts_compatibility_test.rs new file mode 100644 index 00000000000..2e456e71416 --- /dev/null +++ b/crates/blockifier_test_utils/tests/feature_contracts_compatibility_test.rs @@ -0,0 +1,332 @@ +use std::fs; + +use blockifier_test_utils::cairo_compile::{prepare_group_tag_compiler_deps, CompilationArtifacts}; +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; +use blockifier_test_utils::contracts::{ + FeatureContract, + CAIRO1_FEATURE_CONTRACTS_DIR, + SIERRA_CONTRACTS_SUBDIR, +}; +use pretty_assertions::assert_eq; +use rstest::rstest; +use tracing::info; +use tracing_test::traced_test; + +const CAIRO0_FEATURE_CONTRACTS_DIR: &str = "resources/feature_contracts/cairo0"; +const COMPILED_CONTRACTS_SUBDIR: &str = "compiled"; +const FIX_COMMAND: &str = "FIX_FEATURE_TEST=1 cargo test -p blockifier_test_utils --test \ + feature_contracts_compatibility_test -- --include-ignored"; + +pub enum FeatureContractMetadata { + Cairo0(Cairo0FeatureContractMetadata), + Cairo1(Cairo1FeatureContractMetadata), +} + +impl FeatureContractMetadata { + pub fn compiled_path(&self) -> String { + match self { + FeatureContractMetadata::Cairo0(data) => data.compiled_path.clone(), + FeatureContractMetadata::Cairo1(data) => data.compiled_path.clone(), + } + } + + pub fn sierra_path(&self) -> String { + match self { + FeatureContractMetadata::Cairo0(_) => panic!("No sierra path for Cairo0 contracts."), + FeatureContractMetadata::Cairo1(data) => data.sierra_path.clone(), + } + } +} + +pub struct Cairo0FeatureContractMetadata { + pub source_path: String, + pub base_filename: String, + pub compiled_path: String, +} + +pub struct Cairo1FeatureContractMetadata { + pub source_path: String, + pub base_filename: String, + pub compiled_path: String, + pub sierra_path: String, +} + +// To fix Cairo0 feature contracts, first enter a python venv and install the requirements: +// ``` +// python -m venv tmp_venv +// . tmp_venv/bin/activate +// pip install -r crates/blockifier_test_utils/tests/requirements.txt +// ``` +// Then, run the FIX_COMMAND above. + +// To fix Cairo1 feature contracts, first clone the Cairo repo and checkout the required tag. +// The repo should be located next to the sequencer repo: +// / +// - sequencer/ +// - cairo/ +// Then, run the FIX_COMMAND above. + +// Checks that: +// 1. `TEST_CONTRACTS` dir exists and contains only `.cairo` files and the subdirectory +// `COMPILED_CONTRACTS_SUBDIR`. +// 2. for each `X.cairo` file in `TEST_CONTRACTS` there exists an `X_compiled.json` file in +// `COMPILED_CONTRACTS_SUBDIR` which equals `starknet-compile-deprecated X.cairo --no_debug_info`. +async fn verify_feature_contracts_compatibility(fix: bool, cairo_version: CairoVersion) { + // TODO(Dori, 1/10/2024): Parallelize this test. + match cairo_version { + CairoVersion::Cairo0 => { + for contract in FeatureContract::all_feature_contracts() + .filter(|contract| contract.cairo_version() == cairo_version) + { + verify_feature_contracts_compatibility_logic(&contract, fix); + } + } + CairoVersion::Cairo1(RunnableCairo1::Casm) => { + for (tag_and_tool_chain, feature_contracts) in + FeatureContract::cairo1_feature_contracts_by_tag() + { + prepare_group_tag_compiler_deps(&tag_and_tool_chain); + + let mut task_set = tokio::task::JoinSet::new(); + + for contract in feature_contracts + .into_iter() + .filter(|contract| contract.cairo_version() == cairo_version) + { + info!("Spawning task for {contract:?}."); + task_set + .spawn(verify_feature_contracts_compatibility_logic_async(contract, fix)); + } + info!("Done spawning tasks for {tag_and_tool_chain:?}. Awaiting them..."); + task_set.join_all().await; + info!("Done awaiting tasks for {tag_and_tool_chain:?}."); + } + } + #[cfg(feature = "cairo_native")] + CairoVersion::Cairo1(RunnableCairo1::Native) => { + panic!("This test does not support native CairoVersion.") + } + } +} + +async fn verify_feature_contracts_compatibility_logic_async(contract: FeatureContract, fix: bool) { + verify_feature_contracts_compatibility_logic(&contract, fix); +} + +fn check_compilation( + actual_content: Vec, + existing_contents: &str, + path: &str, + source_path: String, +) { + if String::from_utf8(actual_content).unwrap() != existing_contents { + panic!( + "{} does not compile to {}.\nRun `{FIX_COMMAND}` to fix the existing file according \ + to locally installed `starknet-compile-deprecated`.\n", + source_path, path + ); + } +} + +fn compare_compilation_data(contract: &FeatureContract) { + let expected_compiled_raw_output = contract.compile(); + let existing_compiled_path = contract.get_compiled_path(); + let existing_compiled_contents = fs::read_to_string(&existing_compiled_path) + .unwrap_or_else(|_| panic!("Cannot read {existing_compiled_path}.")); + + match expected_compiled_raw_output { + CompilationArtifacts::Cairo0 { casm } => { + check_compilation( + casm, + &existing_compiled_contents, + &existing_compiled_path, + contract.get_source_path(), + ); + } + CompilationArtifacts::Cairo1 { casm, sierra } => { + // TODO(Aviv): Remove this if after fixing sierra file of cairo steps contract. + if !matches!(contract, FeatureContract::CairoStepsTestContract) { + check_compilation( + casm, + &existing_compiled_contents, + &existing_compiled_path, + contract.get_source_path(), + ); + + let sierra_compiled_path = contract.get_sierra_path(); + let existing_sierra_contents = fs::read_to_string(&sierra_compiled_path) + .unwrap_or_else(|_| panic!("Cannot read {sierra_compiled_path}.")); + check_compilation( + sierra, + &existing_sierra_contents, + &sierra_compiled_path, + contract.get_source_path(), + ); + } + } + } +} + +fn verify_feature_contracts_compatibility_logic(contract: &FeatureContract, fix: bool) { + // Compare output of cairo-file on file with existing compiled file. + info!("Compiling {contract:?}..."); + let expected_compiled_raw_output = contract.compile(); + info!("Done compiling {contract:?}."); + let existing_compiled_path = contract.get_compiled_path(); + if fix { + match expected_compiled_raw_output { + CompilationArtifacts::Cairo0 { ref casm } => { + fs::write(&existing_compiled_path, casm).unwrap(); + } + CompilationArtifacts::Cairo1 { ref casm, ref sierra } => { + fs::write(&existing_compiled_path, casm).unwrap(); + fs::write(contract.get_sierra_path(), sierra).unwrap(); + } + } + } + + compare_compilation_data(contract); +} + +/// Verifies that the feature contracts directory contains the expected contents, and returns +/// the feature contracts metadata. +fn verify_and_get_files(cairo_version: CairoVersion) -> Vec { + let mut paths = vec![]; + let directory = match cairo_version { + CairoVersion::Cairo0 => CAIRO0_FEATURE_CONTRACTS_DIR, + CairoVersion::Cairo1(RunnableCairo1::Casm) => CAIRO1_FEATURE_CONTRACTS_DIR, + #[cfg(feature = "cairo_native")] + CairoVersion::Cairo1(RunnableCairo1::Native) => { + panic!("This test does not support native CairoVersion.") + } + }; + let compiled_extension = match cairo_version { + CairoVersion::Cairo0 => "_compiled.json", + CairoVersion::Cairo1(RunnableCairo1::Casm) => ".casm.json", + #[cfg(feature = "cairo_native")] + CairoVersion::Cairo1(RunnableCairo1::Native) => { + panic!("This test does not support native CairoVersion.") + } + }; + for file in fs::read_dir(directory).unwrap() { + let path = file.unwrap().path(); + + // Verify `TEST_CONTRACTS` file and directory structure. + if !path.is_file() { + if let Some(dir_name) = path.file_name() { + assert!( + dir_name == COMPILED_CONTRACTS_SUBDIR || dir_name == SIERRA_CONTRACTS_SUBDIR, + "Found directory '{}' in `{directory}`, which should contain only the \ + `{COMPILED_CONTRACTS_SUBDIR}` or `{SIERRA_CONTRACTS_SUBDIR}` directory.", + dir_name.to_string_lossy() + ); + continue; + } + } + let path_str = path.to_string_lossy(); + assert_eq!( + path.extension().unwrap(), + "cairo", + "Found a non-Cairo file '{path_str}' in `{directory}`" + ); + + let file_name = path.file_stem().unwrap().to_string_lossy(); + let existing_compiled_path = + format!("{directory}/{COMPILED_CONTRACTS_SUBDIR}/{file_name}{compiled_extension}"); + + match cairo_version { + CairoVersion::Cairo0 => { + paths.push(FeatureContractMetadata::Cairo0(Cairo0FeatureContractMetadata { + source_path: path_str.to_string(), + base_filename: file_name.to_string(), + compiled_path: existing_compiled_path, + })) + } + + CairoVersion::Cairo1(RunnableCairo1::Casm) => { + let existing_sierra_path = + format!("{directory}/{SIERRA_CONTRACTS_SUBDIR}/{file_name}.sierra.json"); + paths.push(FeatureContractMetadata::Cairo1(Cairo1FeatureContractMetadata { + source_path: path_str.to_string(), + base_filename: file_name.to_string(), + compiled_path: existing_compiled_path, + sierra_path: existing_sierra_path, + })); + } + #[cfg(feature = "cairo_native")] + CairoVersion::Cairo1(RunnableCairo1::Native) => { + panic!("This test does not support native CairoVersion.") + } + } + } + + paths +} + +// Native and Casm have the same contracts, therefore should have the same enum, so we exclude +// Native CairoVersion from this test. +#[rstest] +fn verify_feature_contracts_match_enum( + #[values(CairoVersion::Cairo0, CairoVersion::Cairo1(RunnableCairo1::Casm))] + cairo_version: CairoVersion, +) { + let mut compiled_paths_from_enum: Vec = FeatureContract::all_feature_contracts() + .filter(|contract| contract.cairo_version() == cairo_version) + .map(|contract| contract.get_compiled_path()) + .collect(); + + let mut compiled_paths_on_filesystem = match cairo_version { + CairoVersion::Cairo0 => verify_and_get_files(cairo_version) + .into_iter() + .map(|metadata| metadata.compiled_path().to_string()) + .collect(), + CairoVersion::Cairo1(RunnableCairo1::Casm) => { + let (compiled_paths_on_filesystem, mut sierra_paths_on_filesystem): ( + Vec, + Vec, + ) = verify_and_get_files(cairo_version) + .into_iter() + .map(|metadata| (metadata.compiled_path(), metadata.sierra_path())) + .collect(); + + let mut sierra_paths_from_enum: Vec = FeatureContract::all_feature_contracts() + .filter(|contract| contract.cairo_version() == cairo_version) + .map(|contract| contract.get_sierra_path()) + .collect(); + + sierra_paths_from_enum.sort(); + sierra_paths_on_filesystem.sort(); + assert_eq!(sierra_paths_from_enum, sierra_paths_on_filesystem); + compiled_paths_on_filesystem + } + + #[cfg(feature = "cairo_native")] + CairoVersion::Cairo1(RunnableCairo1::Native) => { + panic!("This test does not support native CairoVersion.") + } + }; + compiled_paths_from_enum.sort(); + compiled_paths_on_filesystem.sort(); + assert_eq!(compiled_paths_from_enum, compiled_paths_on_filesystem); +} + +async fn verify_feature_contracts_test_body(cairo_version: CairoVersion) { + let fix_features = std::env::var("FIX_FEATURE_TEST").is_ok(); + verify_feature_contracts_compatibility(fix_features, cairo_version).await; +} + +// Native and Casm have the same contracts and compiled files, as we only save the sierra for +// Native, so we exclude Native CairoVersion from these tests. +#[ignore] +#[traced_test] +#[tokio::test(flavor = "multi_thread")] +async fn verify_feature_contracts_cairo0() { + verify_feature_contracts_test_body(CairoVersion::Cairo0).await; +} + +#[ignore] +#[traced_test] +#[tokio::test(flavor = "multi_thread")] +async fn verify_feature_contracts_cairo1() { + verify_feature_contracts_test_body(CairoVersion::Cairo1(RunnableCairo1::Casm)).await; +} diff --git a/crates/blockifier/tests/requirements.txt b/crates/blockifier_test_utils/tests/requirements.txt similarity index 100% rename from crates/blockifier/tests/requirements.txt rename to crates/blockifier_test_utils/tests/requirements.txt diff --git a/crates/committer_cli/src/main.rs b/crates/committer_cli/src/main.rs deleted file mode 100644 index 4cb7116bfb4..00000000000 --- a/crates/committer_cli/src/main.rs +++ /dev/null @@ -1,113 +0,0 @@ -use clap::{Args, Parser, Subcommand}; -use committer_cli::block_hash::{BlockCommitmentsInput, BlockHashInput}; -use committer_cli::commands::parse_and_commit; -use committer_cli::parse_input::read::{load_from_stdin, read_from_stdin, write_to_file}; -use committer_cli::tests::python_tests::PythonTest; -use committer_cli::tracing_utils::configure_tracing; -use starknet_api::block_hash::block_hash_calculator::{ - calculate_block_commitments, - calculate_block_hash, -}; -use tracing::info; - -/// Committer CLI. -#[derive(Debug, Parser)] -#[clap(name = "committer-cli", version)] -pub struct CommitterCliArgs { - #[clap(flatten)] - global_options: GlobalOptions, - - #[clap(subcommand)] - command: Command, -} - -#[derive(Debug, Subcommand)] -enum Command { - /// Calculates the block hash. - BlockHash { - /// File path to output. - #[clap(long, short = 'o', default_value = "stdout")] - output_path: String, - }, - /// Calculates commitments needed for the block hash. - BlockHashCommitments { - /// File path to output. - #[clap(long, short = 'o', default_value = "stdout")] - output_path: String, - }, - /// Given previous state tree skeleton and a state diff, computes the new commitment. - Commit { - /// File path to output. - #[clap(long, short = 'o', default_value = "stdout")] - output_path: String, - }, - PythonTest { - /// File path to output. - #[clap(long, short = 'o', default_value = "stdout")] - output_path: String, - - /// Test name. - #[clap(long)] - test_name: String, - }, -} - -#[derive(Debug, Args)] -struct GlobalOptions {} - -#[tokio::main] -/// Main entry point of the committer CLI. -async fn main() { - // Initialize the logger. The log_filter_handle is used to change the log level. The - // default log level is INFO. - let log_filter_handle = configure_tracing(); - - let args = CommitterCliArgs::parse(); - info!("Starting committer-cli with args: \n{:?}", args); - - match args.command { - Command::Commit { output_path } => { - // TODO(Aner, 15/7/24): try moving read_from_stdin into function. - parse_and_commit(&read_from_stdin(), output_path, log_filter_handle).await; - } - - Command::PythonTest { output_path, test_name } => { - // Create PythonTest from test_name. - let test = PythonTest::try_from(test_name) - .unwrap_or_else(|error| panic!("Failed to create PythonTest: {}", error)); - let stdin_input = read_from_stdin(); - - // Run relevant test. - let output = test - .run(Some(&stdin_input)) - .await - .unwrap_or_else(|error| panic!("Failed to run test: {}", error)); - - // Write test's output. - write_to_file(&output_path, &output); - } - - Command::BlockHash { output_path } => { - let block_hash_input: BlockHashInput = load_from_stdin(); - info!("Successfully loaded block hash input."); - let block_hash = - calculate_block_hash(block_hash_input.header, block_hash_input.block_commitments) - .unwrap_or_else(|error| panic!("Failed to calculate block hash: {}", error)); - write_to_file(&output_path, &block_hash); - info!("Successfully computed block hash {:?}.", block_hash); - } - - Command::BlockHashCommitments { output_path } => { - let commitments_input: BlockCommitmentsInput = load_from_stdin(); - info!("Successfully loaded block hash commitment input."); - let commitments = calculate_block_commitments( - &commitments_input.transactions_data, - &commitments_input.state_diff, - commitments_input.l1_da_mode, - &commitments_input.starknet_version, - ); - write_to_file(&output_path, &commitments); - info!("Successfully computed block hash commitment: \n{:?}", commitments); - } - } -} diff --git a/crates/committer_cli/src/parse_input/read.rs b/crates/committer_cli/src/parse_input/read.rs deleted file mode 100644 index dba859ba243..00000000000 --- a/crates/committer_cli/src/parse_input/read.rs +++ /dev/null @@ -1,32 +0,0 @@ -use std::fs::File; -use std::io::{self, BufWriter}; - -use serde::{Deserialize, Serialize}; -use starknet_patricia::storage::errors::DeserializationError; - -use crate::parse_input::cast::InputImpl; -use crate::parse_input::raw_input::RawInput; - -#[cfg(test)] -#[path = "read_test.rs"] -pub mod read_test; - -type DeserializationResult = Result; - -pub fn parse_input(input: &str) -> DeserializationResult { - serde_json::from_str::(input)?.try_into() -} - -pub fn read_from_stdin() -> String { - io::read_to_string(io::stdin()).expect("Failed to read from stdin.") -} - -pub fn load_from_stdin Deserialize<'a>>() -> T { - let stdin = read_from_stdin(); - serde_json::from_str(&stdin).expect("Failed to load from stdin") -} - -pub fn write_to_file(file_path: &str, object: &T) { - let file_buffer = BufWriter::new(File::create(file_path).expect("Failed to create file")); - serde_json::to_writer(file_buffer, object).expect("Failed to serialize"); -} diff --git a/crates/infra_utils/Cargo.toml b/crates/infra_utils/Cargo.toml deleted file mode 100644 index 6b42af283d4..00000000000 --- a/crates/infra_utils/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "infra_utils" -version.workspace = true -edition.workspace = true -repository.workspace = true -license-file.workspace = true -description = "Infrastructure utility." - -[lints] -workspace = true - -[dependencies] -tokio = { workspace = true, features = ["process"] } - -[dev-dependencies] -rstest.workspace = true diff --git a/crates/infra_utils/src/lib.rs b/crates/infra_utils/src/lib.rs deleted file mode 100644 index f744151bf9a..00000000000 --- a/crates/infra_utils/src/lib.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod command; -pub mod path; diff --git a/crates/infra_utils/src/path.rs b/crates/infra_utils/src/path.rs deleted file mode 100644 index d8080216fe1..00000000000 --- a/crates/infra_utils/src/path.rs +++ /dev/null @@ -1,49 +0,0 @@ -use std::path::{Path, PathBuf}; -use std::sync::LazyLock; -use std::{env, fs}; - -#[cfg(test)] -#[path = "path_test.rs"] -mod path_test; - -// TODO(tsabary): wrap path-related env::* invocations in the repo as utility functions -static PATH_TO_CARGO_MANIFEST_DIR: LazyLock> = - LazyLock::new(|| env::var("CARGO_MANIFEST_DIR").ok().map(|dir| Path::new(&dir).into())); - -// TODO(Tsabary): should not be public. Use a getter instead. -pub fn cargo_manifest_dir() -> Option { - PATH_TO_CARGO_MANIFEST_DIR.clone() -} - -// TODO(Tsabary/ Arni): consolidate with other get_absolute_path functions. -/// Resolves a relative path from the project root directory and returns its absolute path. -/// -/// # Arguments -/// * `relative_path` - A string slice representing the relative path from the project root. -/// -/// # Returns -/// * A `PathBuf` representing the resolved path starting from the project root. -pub fn resolve_project_relative_path(relative_path: &str) -> Result { - let base_dir = path_of_project_root(); - let path = base_dir.join(relative_path); - let absolute_path = fs::canonicalize(path)?; - - Ok(absolute_path) -} - -/// Returns the absolute path of the project root directory. -/// -/// # Returns -/// * A `PathBuf` representing the path of the project root. -pub fn project_path() -> Result { - resolve_project_relative_path(".") -} - -fn path_of_project_root() -> PathBuf { - cargo_manifest_dir() - // Attempt to get the `CARGO_MANIFEST_DIR` environment variable and convert it to `PathBuf`. - // Ascend two directories ("../..") to get to the project root. - .map(|dir| dir.join("../..")) - // If `CARGO_MANIFEST_DIR` isn't set, fall back to the current working directory - .unwrap_or(env::current_dir().expect("Failed to get current directory")) -} diff --git a/crates/mempool_test_utils/Cargo.toml b/crates/mempool_test_utils/Cargo.toml index ef49716460b..2458a6dbfcf 100644 --- a/crates/mempool_test_utils/Cargo.toml +++ b/crates/mempool_test_utils/Cargo.toml @@ -10,9 +10,8 @@ workspace = true [dependencies] assert_matches.workspace = true -blockifier = { workspace = true, features = ["testing"] } -infra_utils.workspace = true -pretty_assertions.workspace = true +blockifier_test_utils.workspace = true serde_json.workspace = true starknet-types-core.workspace = true starknet_api.workspace = true +starknet_infra_utils.workspace = true diff --git a/crates/mempool_test_utils/src/lib.rs b/crates/mempool_test_utils/src/lib.rs index 6500101322c..893ddc9a891 100644 --- a/crates/mempool_test_utils/src/lib.rs +++ b/crates/mempool_test_utils/src/lib.rs @@ -5,3 +5,9 @@ pub const CONTRACT_CLASS_FILE: &str = "contract_class.json"; pub const COMPILED_CLASS_HASH_OF_CONTRACT_CLASS: &str = "0x01e4f1248860f32c336f93f2595099aaa4959be515e40b75472709ef5243ae17"; pub const FAULTY_ACCOUNT_CLASS_FILE: &str = "faulty_account.sierra.json"; + +// TODO(Gilad): Use everywhere instead of relying on the confusing `#[ignore]` api to mark slow +// tests. +pub fn in_ci() -> bool { + std::env::var("CI").is_ok() +} diff --git a/crates/mempool_test_utils/src/starknet_api_test_utils.rs b/crates/mempool_test_utils/src/starknet_api_test_utils.rs index c9e685fbd7b..19491cb4b90 100644 --- a/crates/mempool_test_utils/src/starknet_api_test_utils.rs +++ b/crates/mempool_test_utils/src/starknet_api_test_utils.rs @@ -6,39 +6,60 @@ use std::rc::Rc; use std::sync::LazyLock; use assert_matches::assert_matches; -use blockifier::test_utils::contracts::FeatureContract; -use blockifier::test_utils::{create_trivial_calldata, CairoVersion}; -use infra_utils::path::resolve_project_relative_path; -use pretty_assertions::assert_ne; -use serde_json::to_string_pretty; +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; +use blockifier_test_utils::calldata::create_trivial_calldata; +use blockifier_test_utils::contracts::FeatureContract; +use starknet_api::abi::abi_utils::selector_from_name; use starknet_api::block::GasPrice; use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; use starknet_api::executable_transaction::AccountTransaction; use starknet_api::execution_resources::GasAmount; -use starknet_api::rpc_transaction::{ContractClass, RpcTransaction}; +use starknet_api::hash::StarkHash; +use starknet_api::rpc_transaction::RpcTransaction; +use starknet_api::state::SierraContractClass; use starknet_api::test_utils::declare::rpc_declare_tx; use starknet_api::test_utils::deploy_account::rpc_deploy_account_tx; use starknet_api::test_utils::invoke::{rpc_invoke_tx, InvokeTxArgs}; -use starknet_api::test_utils::NonceManager; +use starknet_api::test_utils::{NonceManager, TEST_ERC20_CONTRACT_ADDRESS2}; +use starknet_api::transaction::constants::TRANSFER_ENTRY_POINT_NAME; use starknet_api::transaction::fields::{ AllResourceBounds, ContractAddressSalt, + Fee, ResourceBounds, Tip, TransactionSignature, ValidResourceBounds, }; -use starknet_api::{declare_tx_args, deploy_account_tx_args, felt, invoke_tx_args, nonce}; +use starknet_api::transaction::L1HandlerTransaction; +use starknet_api::{ + calldata, + declare_tx_args, + deploy_account_tx_args, + felt, + invoke_tx_args, + nonce, +}; +use starknet_infra_utils::path::resolve_project_relative_path; use starknet_types_core::felt::Felt; use crate::{COMPILED_CLASS_HASH_OF_CONTRACT_CLASS, CONTRACT_CLASS_FILE, TEST_FILES_FOLDER}; pub const VALID_L1_GAS_MAX_AMOUNT: u64 = 203484; pub const VALID_L1_GAS_MAX_PRICE_PER_UNIT: u128 = 100000000000; -pub const VALID_L2_GAS_MAX_AMOUNT: u64 = 500000; +pub const VALID_L2_GAS_MAX_AMOUNT: u64 = 500000 * 200000; // Enough to declare the test class. pub const VALID_L2_GAS_MAX_PRICE_PER_UNIT: u128 = 100000000000; pub const VALID_L1_DATA_GAS_MAX_AMOUNT: u64 = 203484; pub const VALID_L1_DATA_GAS_MAX_PRICE_PER_UNIT: u128 = 100000000000; +#[allow(clippy::as_conversions)] +pub const VALID_ACCOUNT_BALANCE: Fee = + Fee(VALID_L2_GAS_MAX_AMOUNT as u128 * VALID_L2_GAS_MAX_PRICE_PER_UNIT * 1000); + +// Default funded account, there are more fixed funded accounts, +// see https://github.com/foundry-rs/foundry/tree/master/crates/anvil. +// This address is the sender address of messages sent to L2 by Anvil. +pub const DEFAULT_ANVIL_L1_ACCOUNT_ADDRESS: StarkHash = + StarkHash::from_hex_unchecked("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"); // Utils. @@ -65,7 +86,7 @@ pub fn test_valid_resource_bounds() -> ValidResourceBounds { } /// Get the contract class used for testing. -pub fn contract_class() -> ContractClass { +pub fn contract_class() -> SierraContractClass { env::set_current_dir(resolve_project_relative_path(TEST_FILES_FOLDER).unwrap()) .expect("Couldn't set working dir."); let json_file_path = Path::new(CONTRACT_CLASS_FILE); @@ -79,7 +100,8 @@ pub fn declare_tx() -> RpcTransaction { let contract_class = contract_class(); let compiled_class_hash = *COMPILED_CLASS_HASH; - let account_contract = FeatureContract::AccountWithoutValidations(CairoVersion::Cairo1); + let account_contract = + FeatureContract::AccountWithoutValidations(CairoVersion::Cairo1(RunnableCairo1::Casm)); let account_address = account_contract.get_instance_address(0); let mut nonce_manager = NonceManager::default(); let nonce = nonce_manager.next(account_address); @@ -117,8 +139,8 @@ pub fn executable_invoke_tx(cairo_version: CairoVersion) -> AccountTransaction { let default_account = FeatureContract::AccountWithoutValidations(cairo_version); let mut tx_generator = MultiAccountTransactionGenerator::new(); - tx_generator.register_account(default_account); - tx_generator.account_with_id(0).generate_executable_invoke() + tx_generator.register_deployed_account(default_account); + tx_generator.account_with_id_mut(0).generate_executable_invoke() } pub fn generate_deploy_account_with_salt( @@ -134,12 +156,49 @@ pub fn generate_deploy_account_with_salt( rpc_deploy_account_tx(deploy_account_args) } -// TODO: when moving this to Starknet API crate, move this const into a module alongside +// TODO(Gilad): when moving this to Starknet API crate, move this const into a module alongside // MultiAcconutTransactionGenerator. pub type AccountId = usize; type SharedNonceManager = Rc>; +#[derive(Default)] +struct L1HandlerTransactionGenerator { + tx_number: usize, +} + +impl L1HandlerTransactionGenerator { + /// Creates an L1 handler transaction calling the "l1_handler_set_value" entry point in + /// [TestContract](FeatureContract::TestContract). + fn create_l1_handler_tx(&mut self) -> L1HandlerTransaction { + self.tx_number += 1; + // TODO(Arni): Get test contract from test setup. + let test_contract = + FeatureContract::TestContract(CairoVersion::Cairo1(RunnableCairo1::Casm)); + + L1HandlerTransaction { + contract_address: test_contract.get_instance_address(0), + // TODO(Arni): Consider saving this value as a lazy constant. + entry_point_selector: selector_from_name("l1_handler_set_value"), + calldata: calldata![ + DEFAULT_ANVIL_L1_ACCOUNT_ADDRESS, + // Arbitrary key and value. + felt!("0x876"), // key + felt!("0x44") // value + ], + ..Default::default() + } + } +} + +// TODO(Yair): Separate MultiAccountTransactionGenerator to phases: +// 1. Setup phase - register erc20 contract and initially deployed account with some balance +// (produce the state diff that represents the initial state so it can be used in the test). +// 2. Execution phase - generate transactions. + +// TODO(Yair): Add optional StateReader and assert that the state supports each operation (e.g. +// nonce). + /// Manages transaction generation for multiple pre-funded accounts, internally bumping nonces /// as needed. /// @@ -150,19 +209,30 @@ type SharedNonceManager = Rc>; /// # Example /// /// ``` -/// use blockifier::test_utils::contracts::FeatureContract; -/// use blockifier::test_utils::CairoVersion; +/// use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; +/// use blockifier_test_utils::contracts::FeatureContract; /// use mempool_test_utils::starknet_api_test_utils::MultiAccountTransactionGenerator; +/// use starknet_api::transaction::fields::ContractAddressSalt; /// /// let mut tx_generator = MultiAccountTransactionGenerator::new(); -/// let some_account_type = FeatureContract::AccountWithoutValidations(CairoVersion::Cairo1); +/// let some_account_type = +/// FeatureContract::AccountWithoutValidations(CairoVersion::Cairo1(RunnableCairo1::Casm)); /// // Initialize multiple accounts, these can be any account type in `FeatureContract`. -/// tx_generator.register_account_for_flow_test(some_account_type.clone()); -/// tx_generator.register_account_for_flow_test(some_account_type); +/// tx_generator.register_deployed_account(some_account_type.clone()); +/// tx_generator.register_deployed_account(some_account_type.clone()); +/// +/// let account_0_tx_with_nonce_0 = tx_generator.account_with_id_mut(0).generate_invoke_with_tip(1); +/// let account_1_tx_with_nonce_0 = tx_generator.account_with_id_mut(1).generate_invoke_with_tip(3); +/// let account_0_tx_with_nonce_1 = tx_generator.account_with_id_mut(0).generate_invoke_with_tip(1); /// -/// let account_0_tx_with_nonce_0 = tx_generator.account_with_id(0).generate_invoke_with_tip(1); -/// let account_1_tx_with_nonce_0 = tx_generator.account_with_id(1).generate_invoke_with_tip(3); -/// let account_0_tx_with_nonce_1 = tx_generator.account_with_id(0).generate_invoke_with_tip(1); +/// // Initialize an undeployed account. +/// let salt = ContractAddressSalt(123_u64.into()); +/// tx_generator.register_undeployed_account(some_account_type, salt); +/// let undeployed_account = tx_generator.account_with_id(2).account; +/// // Generate a transfer to fund the undeployed account. +/// let transfer_tx = tx_generator.account_with_id_mut(0).generate_transfer(&undeployed_account); +/// // Generate a deploy account transaction for the undeployed account. +/// let deploy_account_tx = tx_generator.account_with_id_mut(2).generate_deploy_account(); /// ``` // Note: when moving this to starknet api crate, see if blockifier's // [blockifier::transaction::test_utils::FaultyAccountTxCreatorArgs] can be made to use this. @@ -170,9 +240,10 @@ type SharedNonceManager = Rc>; pub struct MultiAccountTransactionGenerator { // Invariant: coupled with the nonce manager. account_tx_generators: Vec, - // Invariant: nonces managed internally thorugh `generate` API of the account transaction + // Invariant: nonces managed internally through `generate` API of the account transaction // generator. nonce_manager: SharedNonceManager, + l1_handler_tx_generator: L1HandlerTransactionGenerator, } impl MultiAccountTransactionGenerator { @@ -180,19 +251,59 @@ impl MultiAccountTransactionGenerator { Self::default() } - pub fn register_account(&mut self, account_contract: FeatureContract) -> RpcTransaction { + pub fn snapshot(&self) -> Self { + let nonce_manager = Rc::new(RefCell::new((*self.nonce_manager.borrow()).clone())); + let account_tx_generators = self + .account_tx_generators + .iter() + .map(|tx_gen| AccountTransactionGenerator { + account: tx_gen.account, + nonce_manager: nonce_manager.clone(), + contract_address_salt: tx_gen.contract_address_salt, + }) + .collect(); + let l1_handler_tx_generator = + L1HandlerTransactionGenerator { tx_number: self.l1_handler_tx_generator.tx_number }; + + Self { account_tx_generators, nonce_manager, l1_handler_tx_generator } + } + + /// Registers a new account with the given contract, assuming it is already deployed. + /// Note: the state should reflect that the account is already deployed. + pub fn register_deployed_account(&mut self, account_contract: FeatureContract) -> AccountId { let new_account_id = self.account_tx_generators.len(); - let (account_tx_generator, default_deploy_account_tx) = AccountTransactionGenerator::new( - new_account_id, + let salt = ContractAddressSalt(new_account_id.into()); + let (account_tx_generator, _default_deploy_account_tx) = AccountTransactionGenerator::new( account_contract, self.nonce_manager.clone(), + salt, + true, ); self.account_tx_generators.push(account_tx_generator); + new_account_id + } - default_deploy_account_tx + /// Registers a new undeployed account with the given contract. + pub fn register_undeployed_account( + &mut self, + account_contract: FeatureContract, + contract_address_salt: ContractAddressSalt, + ) -> AccountId { + let new_account_id = self.account_tx_generators.len(); + let (account_tx_generator, _default_deploy_account_tx) = AccountTransactionGenerator::new( + account_contract, + self.nonce_manager.clone(), + contract_address_salt, + false, + ); + self.account_tx_generators.push(account_tx_generator); + new_account_id } - pub fn account_with_id(&mut self, account_id: AccountId) -> &mut AccountTransactionGenerator { + pub fn account_with_id_mut( + &mut self, + account_id: AccountId, + ) -> &mut AccountTransactionGenerator { self.account_tx_generators.get_mut(account_id).unwrap_or_else(|| { panic!( "{account_id:?} not found! This number should be an index of an account in the \ @@ -201,15 +312,45 @@ impl MultiAccountTransactionGenerator { }) } - // TODO(deploy_account_support): once we support deploy account in tests, remove this method and - // only use new_account_default in tests. In particular, deploy account txs must be then sent to - // the GW via the add tx endpoint just like other txs. - pub fn register_account_for_flow_test(&mut self, account_contract: FeatureContract) { - self.register_account(account_contract); + pub fn account_with_id(&self, account_id: AccountId) -> &AccountTransactionGenerator { + self.account_tx_generators.get(account_id).unwrap_or_else(|| { + panic!( + "{account_id:?} not found! This number should be an index of an account in the \ + initialization array. " + ) + }) + } + + pub fn accounts(&self) -> &[AccountTransactionGenerator] { + self.account_tx_generators.as_slice() + } + + pub fn account_tx_generators(&mut self) -> &mut Vec { + &mut self.account_tx_generators + } + + pub fn deployed_accounts(&self) -> Vec { + self.account_tx_generators + .iter() + .filter_map(|tx_gen| if tx_gen.is_deployed() { Some(&tx_gen.account) } else { None }) + .copied() + .collect() + } + + pub fn undeployed_accounts(&self) -> Vec { + self.account_tx_generators + .iter() + .filter_map(|tx_gen| if !tx_gen.is_deployed() { Some(&tx_gen.account) } else { None }) + .copied() + .collect() + } + + pub fn create_l1_handler_tx(&mut self) -> L1HandlerTransaction { + self.l1_handler_tx_generator.create_l1_handler_tx() } - pub fn accounts(&self) -> Vec { - self.account_tx_generators.iter().map(|tx_gen| &tx_gen.account).copied().collect() + pub fn n_l1_txs(&self) -> usize { + self.l1_handler_tx_generator.tx_number } } @@ -219,23 +360,27 @@ impl MultiAccountTransactionGenerator { /// This struct provides methods to generate both default and fully customized transactions, /// with room for future extensions. /// -/// TODO: add more transaction generation methods as needed. -#[derive(Debug)] +/// TODO(Gilad): add more transaction generation methods as needed. +#[derive(Clone, Debug)] pub struct AccountTransactionGenerator { - account: Contract, + pub account: Contract, nonce_manager: SharedNonceManager, + contract_address_salt: ContractAddressSalt, } impl AccountTransactionGenerator { + pub fn is_deployed(&self) -> bool { + self.nonce_manager.borrow().get(self.sender_address()) != nonce!(0) + } + /// Generate a valid `RpcTransaction` with default parameters. pub fn generate_invoke_with_tip(&mut self, tip: u64) -> RpcTransaction { - let nonce = self.next_nonce(); - assert_ne!( - nonce, - nonce!(0), + assert!( + self.is_deployed(), "Cannot invoke on behalf of an undeployed account: the first transaction of every \ account must be a deploy account transaction." ); + let nonce = self.next_nonce(); let invoke_args = invoke_tx_args!( nonce, tip : Tip(tip), @@ -247,13 +392,12 @@ impl AccountTransactionGenerator { } pub fn generate_executable_invoke(&mut self) -> AccountTransaction { - let nonce = self.next_nonce(); - assert_ne!( - nonce, - nonce!(0), + assert!( + self.is_deployed(), "Cannot invoke on behalf of an undeployed account: the first transaction of every \ account must be a deploy account transaction." ); + let nonce = self.next_nonce(); let invoke_args = invoke_tx_args!( sender_address: self.sender_address(), @@ -262,9 +406,7 @@ impl AccountTransactionGenerator { calldata: create_trivial_calldata(self.sender_address()), ); - AccountTransaction::Invoke(starknet_api::test_utils::invoke::executable_invoke_tx( - invoke_args, - )) + starknet_api::test_utils::invoke::executable_invoke_tx(invoke_args) } /// Generates an `RpcTransaction` with fully custom parameters. @@ -280,7 +422,60 @@ impl AccountTransactionGenerator { rpc_invoke_tx(invoke_tx_args) } - pub fn sender_address(&mut self) -> ContractAddress { + pub fn generate_transfer(&mut self, recipient: &Contract) -> RpcTransaction { + let nonce = self.next_nonce(); + let entry_point_selector = selector_from_name(TRANSFER_ENTRY_POINT_NAME); + let erc20_address = felt!(TEST_ERC20_CONTRACT_ADDRESS2); + + let calldata = calldata![ + erc20_address, // Contract address. + entry_point_selector.0, // EP selector. + felt!(3_u8), // Calldata length. + *recipient.sender_address.key(), // Calldata: recipient. + felt!(1_u8), // Calldata: lsb amount. + felt!(0_u8) // Calldata: msb amount. + ]; + + let invoke_args = invoke_tx_args!( + sender_address: self.sender_address(), + resource_bounds: test_valid_resource_bounds(), + nonce, + calldata + ); + + rpc_invoke_tx(invoke_args) + } + + pub fn generate_deploy_account(&mut self) -> RpcTransaction { + assert!( + !self.is_deployed(), + "Cannot deploy an already deployed account: the first transaction of every account \ + must be a deploy account transaction." + ); + let nonce = self.next_nonce(); + assert_eq!(nonce, nonce!(0), "The deploy account tx should have nonce 0."); + let deploy_account_args = deploy_account_tx_args!( + class_hash: self.account.class_hash(), + resource_bounds: test_valid_resource_bounds(), + contract_address_salt: ContractAddressSalt(self.contract_address_salt.0) + ); + rpc_deploy_account_tx(deploy_account_args) + } + + pub fn generate_declare(&mut self) -> RpcTransaction { + let nonce = self.next_nonce(); + let declare_args = declare_tx_args!( + signature: TransactionSignature(vec![Felt::ZERO]), + sender_address: self.sender_address(), + resource_bounds: test_valid_resource_bounds(), + nonce, + compiled_class_hash: *COMPILED_CLASS_HASH, + ); + let contract_class = contract_class(); + rpc_declare_tx(declare_args, contract_class) + } + + pub fn sender_address(&self) -> ContractAddress { self.account.sender_address } @@ -290,16 +485,22 @@ impl AccountTransactionGenerator { self.nonce_manager.borrow_mut().next(sender_address) } + /// Retrieves the nonce for the current account. + pub fn get_nonce(&self) -> Nonce { + let sender_address = self.sender_address(); + self.nonce_manager.borrow().get(sender_address) + } + /// Private constructor, since only the multi-account transaction generator should create this /// struct. - // TODO: add a version that doesn't rely on the default deploy account constructor, but takes - // deploy account args. + // TODO(Gilad): add a version that doesn't rely on the default deploy account constructor, but + // takes deploy account args. fn new( - account_id: usize, account: FeatureContract, nonce_manager: SharedNonceManager, + contract_address_salt: ContractAddressSalt, + is_deployed: bool, ) -> (Self, RpcTransaction) { - let contract_address_salt = ContractAddressSalt(account_id.into()); // A deploy account transaction must be created now in order to affix an address to it. // If this doesn't happen now it'll be difficult to fund the account during test setup. let default_deploy_account_tx = @@ -308,9 +509,12 @@ impl AccountTransactionGenerator { let mut account_tx_generator = Self { account: Contract::new_for_account(account, &default_deploy_account_tx), nonce_manager, + contract_address_salt, }; - // Bump the account nonce after transaction creation. - account_tx_generator.next_nonce(); + if is_deployed { + // Bump the account nonce after transaction creation. + account_tx_generator.next_nonce(); + } (account_tx_generator, default_deploy_account_tx) } @@ -321,7 +525,7 @@ impl AccountTransactionGenerator { // Note: feature contracts have their own address generating method, but it a mocked address and is // not related to an actual deploy account transaction, which is the way real account addresses are // calculated. -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, PartialEq)] pub struct Contract { pub contract: FeatureContract, pub sender_address: ContractAddress, @@ -336,6 +540,10 @@ impl Contract { self.contract.cairo_version() } + pub fn sierra(&self) -> SierraContractClass { + self.contract.get_sierra() + } + pub fn raw_class(&self) -> String { self.contract.get_raw_class() } @@ -360,23 +568,3 @@ impl Contract { } } } - -pub fn rpc_tx_to_json(tx: &RpcTransaction) -> String { - let mut tx_json = serde_json::to_value(tx) - .unwrap_or_else(|tx| panic!("Failed to serialize transaction: {tx:?}")); - - // Add type and version manually - let type_string = match tx { - RpcTransaction::Declare(_) => "DECLARE", - RpcTransaction::DeployAccount(_) => "DEPLOY_ACCOUNT", - RpcTransaction::Invoke(_) => "INVOKE", - }; - - tx_json - .as_object_mut() - .unwrap() - .extend([("type".to_string(), type_string.into()), ("version".to_string(), "0x3".into())]); - - // Serialize back to pretty JSON string - to_string_pretty(&tx_json).expect("Failed to serialize transaction") -} diff --git a/crates/native_blockifier/Cargo.toml b/crates/native_blockifier/Cargo.toml index 4c0ba4ec5d9..c3ff61fbd3f 100644 --- a/crates/native_blockifier/Cargo.toml +++ b/crates/native_blockifier/Cargo.toml @@ -7,11 +7,16 @@ license-file.workspace = true description = "A Bridge between the Rust blockifier crate and Python." [features] +cairo_native = [ + "blockifier/cairo_native", + "papyrus_state_reader/cairo_native", + "starknet_sierra_multicompile/cairo_native", +] # Required for `cargo test` to work with Pyo3. # On Python, make sure to compile this with the extension-module feature enabled. # https://pyo3.rs/v0.19.1/faq#i-cant-run-cargo-test-or-i-cant-build-in-a-cargo-workspace-im-having-linker-issues-like-symbol-not-found-or-undefined-reference-to-_pyexc_systemerror extension-module = ["pyo3/extension-module"] -testing = [] +testing = ["blockifier/testing", "papyrus_storage/testing", "starknet_api/testing"] [lints] workspace = true @@ -26,24 +31,27 @@ name = "native_blockifier" crate-type = ["cdylib"] [dependencies] -# TODO(Dori, 1/1/2025): Add the "jemalloc" feature to the blockifier crate when possible. -blockifier = { workspace = true, features = ["testing"] } +blockifier = { workspace = true, features = ["native_blockifier"] } cairo-lang-starknet-classes.workspace = true cairo-vm.workspace = true indexmap.workspace = true log.workspace = true num-bigint.workspace = true papyrus_state_reader.workspace = true -papyrus_storage = { workspace = true, features = ["testing"] } +papyrus_storage.workspace = true pyo3 = { workspace = true, features = ["hashbrown", "num-bigint"] } pyo3-log.workspace = true -serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true, features = ["arbitrary_precision"] } +shared_execution_objects.workspace = true starknet-types-core.workspace = true -starknet_api = { workspace = true, features = ["testing"] } +starknet_api.workspace = true +starknet_sierra_multicompile.workspace = true thiserror.workspace = true [dev-dependencies] +blockifier = { workspace = true, features = ["native_blockifier", "testing"] } cached.workspace = true +papyrus_storage = { workspace = true, features = ["testing"] } pretty_assertions.workspace = true +starknet_api = { workspace = true, features = ["testing"] } tempfile.workspace = true diff --git a/crates/native_blockifier/src/errors.rs b/crates/native_blockifier/src/errors.rs index 2128f417484..07794fc49fc 100644 --- a/crates/native_blockifier/src/errors.rs +++ b/crates/native_blockifier/src/errors.rs @@ -1,6 +1,6 @@ use blockifier::blockifier::stateful_validator::StatefulValidatorError; use blockifier::blockifier::transaction_executor::TransactionExecutorError; -use blockifier::bouncer::BuiltinCount; +use blockifier::bouncer::BuiltinCounterMap; use blockifier::state::errors::StateError; use blockifier::transaction::errors::{ ParseError, @@ -89,6 +89,8 @@ pub enum NativeBlockifierInputError { ProgramError(#[from] ProgramError), #[error(transparent)] PyFeltParseError(#[from] FromStrError), + #[error("Sierra version is missing.")] + MissingSierraVersion, #[error(transparent)] StarknetApiError(#[from] StarknetApiError), #[error("Unknown builtin: {0}.")] @@ -102,7 +104,7 @@ pub enum NativeBlockifierInputError { #[derive(Debug, Error)] pub enum InvalidNativeBlockifierInputError { #[error("Invalid builtin count: {0:?}.")] - InvalidBuiltinCounts(BuiltinCount), + InvalidBuiltinCounts(BuiltinCounterMap), #[error("Invalid Wei gas price: {0}.")] InvalidL1GasPriceWei(u128), #[error("Invalid Fri gas price: {0}.")] diff --git a/crates/native_blockifier/src/lib.rs b/crates/native_blockifier/src/lib.rs index 5b94780628f..5d18e3dafb4 100644 --- a/crates/native_blockifier/src/lib.rs +++ b/crates/native_blockifier/src/lib.rs @@ -20,6 +20,11 @@ pub mod state_readers; pub mod storage; pub mod test_utils; +use blockifier::state::stateful_compression::{ + ALIAS_COUNTER_STORAGE_KEY, + MAX_NON_COMPRESSED_CONTRACT_ADDRESS, + MIN_VALUE_FOR_ALIAS_ALLOC, +}; use errors::{add_py_exceptions, UndeclaredClassHashError}; use py_block_executor::PyBlockExecutor; use py_objects::PyExecutionResources; @@ -51,7 +56,6 @@ fn native_blockifier(py: Python<'_>, py_module: &PyModule) -> PyResult<()> { py_module.add("UndeclaredClassHashError", py.get_type::())?; add_py_exceptions(py, py_module)?; - py_module.add_function(wrap_pyfunction!(blockifier_version, py)?)?; py_module.add_function(wrap_pyfunction!(starknet_version, py)?)?; // TODO(Dori, 1/4/2023): If and when supported in the Python build environment, gate this code @@ -65,18 +69,16 @@ fn native_blockifier(py: Python<'_>, py_module: &PyModule) -> PyResult<()> { estimate_casm_hash_computation_resources_for_testing_single, py )?)?; + py_module.add("ALIAS_COUNTER_STORAGE_KEY", ALIAS_COUNTER_STORAGE_KEY.to_string())?; + py_module.add( + "MAX_NON_COMPRESSED_CONTRACT_ADDRESS", + MAX_NON_COMPRESSED_CONTRACT_ADDRESS.to_string(), + )?; + py_module.add("INITIAL_AVAILABLE_ALIAS", MIN_VALUE_FOR_ALIAS_ALLOC.to_string())?; Ok(()) } -/// Returns the version that the `blockifier` and `native_blockifier` crates were built with. -// Assumption: both `blockifier` and `native_blockifier` use `version.workspace` in the package -// section of their `Cargo.toml`. -#[pyfunction] -pub fn blockifier_version() -> PyResult { - Ok(env!("CARGO_PKG_VERSION").to_string()) -} - /// Returns the latest Starknet version for versioned constants. #[pyfunction] pub fn starknet_version() -> PyResult { diff --git a/crates/native_blockifier/src/py_block_executor.rs b/crates/native_blockifier/src/py_block_executor.rs index 17f8604bb16..ea4a69f8db7 100644 --- a/crates/native_blockifier/src/py_block_executor.rs +++ b/crates/native_blockifier/src/py_block_executor.rs @@ -1,31 +1,36 @@ -use std::collections::HashMap; +#![allow(non_local_definitions)] -use blockifier::abi::constants as abi_constants; -use blockifier::blockifier::config::TransactionExecutorConfig; -use blockifier::blockifier::transaction_executor::{TransactionExecutor, TransactionExecutorError}; +use std::str::FromStr; + +use blockifier::blockifier::config::{ContractClassManagerConfig, TransactionExecutorConfig}; +use blockifier::blockifier::transaction_executor::{ + BlockExecutionSummary, + TransactionExecutor, + TransactionExecutorError, +}; +use blockifier::blockifier_versioned_constants::VersionedConstants; use blockifier::bouncer::BouncerConfig; use blockifier::context::{BlockContext, ChainInfo, FeeTokenAddresses}; -use blockifier::execution::call_info::CallInfo; -use blockifier::execution::contract_class::RunnableContractClass; -use blockifier::fee::receipt::TransactionReceipt; -use blockifier::state::global_cache::GlobalContractCache; -use blockifier::transaction::objects::{ExecutionResourcesTraits, TransactionExecutionInfo}; +use blockifier::state::contract_class_manager::ContractClassManager; +use blockifier::transaction::objects::TransactionExecutionInfo; use blockifier::transaction::transaction_execution::Transaction; -use blockifier::utils::usize_from_u64; -use blockifier::versioned_constants::VersionedConstants; use papyrus_state_reader::papyrus_state::PapyrusReader; use pyo3::prelude::*; use pyo3::types::{PyBytes, PyList}; use pyo3::{FromPyObject, PyAny, Python}; -use serde::Serialize; +use shared_execution_objects::central_objects::CentralTransactionExecutionInfo; use starknet_api::block::BlockNumber; +use starknet_api::contract_class::SierraVersion; use starknet_api::core::{ChainId, ContractAddress}; -use starknet_api::execution_resources::GasVector; -use starknet_api::transaction::fields::Fee; use starknet_types_core::felt::Felt; use crate::errors::{NativeBlockifierError, NativeBlockifierResult}; -use crate::py_objects::{PyBouncerConfig, PyConcurrencyConfig, PyVersionedConstantsOverrides}; +use crate::py_objects::{ + PyBouncerConfig, + PyConcurrencyConfig, + PyContractClassManagerConfig, + PyVersionedConstantsOverrides, +}; use crate::py_state_diff::{PyBlockInfo, PyStateDiff}; use crate::py_transaction::{py_tx, PyClassInfo, PY_TX_PARSING_ERR}; use crate::py_utils::{int_to_chain_id, into_block_number_hash_pair, PyFelt}; @@ -38,87 +43,17 @@ use crate::storage::{ }; pub(crate) type RawTransactionExecutionResult = Vec; -pub(crate) type PyVisitedSegmentsMapping = Vec<(PyFelt, Vec)>; +const RESULT_SERIALIZE_ERR: &str = "Failed serializing execution info."; #[cfg(test)] #[path = "py_block_executor_test.rs"] mod py_block_executor_test; -const RESULT_SERIALIZE_ERR: &str = "Failed serializing execution info."; - -/// A mapping from a transaction execution resource to its actual usage. -#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize)] -pub struct ResourcesMapping(pub HashMap); - -/// Stripped down `TransactionExecutionInfo` for Python serialization, containing only the required -/// fields. -#[derive(Debug, Serialize)] -pub(crate) struct ThinTransactionExecutionInfo { - pub validate_call_info: Option, - pub execute_call_info: Option, - pub fee_transfer_call_info: Option, - pub actual_fee: Fee, - pub da_gas: GasVector, - pub actual_resources: ResourcesMapping, - pub revert_error: Option, - pub total_gas: GasVector, -} - -impl ThinTransactionExecutionInfo { - pub fn from_tx_execution_info(tx_execution_info: TransactionExecutionInfo) -> Self { - Self { - validate_call_info: tx_execution_info.validate_call_info, - execute_call_info: tx_execution_info.execute_call_info, - fee_transfer_call_info: tx_execution_info.fee_transfer_call_info, - actual_fee: tx_execution_info.receipt.fee, - da_gas: tx_execution_info.receipt.da_gas, - actual_resources: ThinTransactionExecutionInfo::receipt_to_resources_mapping( - &tx_execution_info.receipt, - ), - revert_error: tx_execution_info.revert_error.map(|error| error.to_string()), - total_gas: tx_execution_info.receipt.gas, - } - } - pub fn serialize(self) -> RawTransactionExecutionResult { - serde_json::to_vec(&self).expect(RESULT_SERIALIZE_ERR) - } - - pub fn receipt_to_resources_mapping(receipt: &TransactionReceipt) -> ResourcesMapping { - let GasVector { l1_gas, l1_data_gas, l2_gas } = receipt.gas; - let vm_resources = &receipt.resources.computation.vm_resources; - let mut resources = HashMap::from([( - abi_constants::N_STEPS_RESOURCE.to_string(), - vm_resources.total_n_steps(), - )]); - resources.extend( - vm_resources - .prover_builtins() - .iter() - .map(|(builtin, value)| (builtin.to_str_with_suffix().to_string(), *value)), - ); - // TODO(Yoni) remove these since we pass the gas vector in separate. - resources.extend(HashMap::from([ - ( - abi_constants::L1_GAS_USAGE.to_string(), - usize_from_u64(l1_gas.0) - .expect("This conversion should not fail as the value is a converted usize."), - ), - ( - abi_constants::BLOB_GAS_USAGE.to_string(), - usize_from_u64(l1_data_gas.0) - .expect("This conversion should not fail as the value is a converted usize."), - ), - ( - abi_constants::L2_GAS_USAGE.to_string(), - usize_from_u64(l2_gas.0) - .expect("This conversion should not fail as the value is a converted usize."), - ), - ])); - *resources.get_mut(abi_constants::N_STEPS_RESOURCE).unwrap_or(&mut 0) += - receipt.resources.computation.n_reverted_steps; - - ResourcesMapping(resources) - } +fn serialize_tx_execution_info( + tx_execution_info: TransactionExecutionInfo, +) -> RawTransactionExecutionResult { + let central_tx_execution_info = CentralTransactionExecutionInfo::from(tx_execution_info); + serde_json::to_vec(¢ral_tx_execution_info).expect(RESULT_SERIALIZE_ERR) } #[pyclass] @@ -130,20 +65,21 @@ pub struct PyBlockExecutor { pub tx_executor: Option>, /// `Send` trait is required for `pyclass` compatibility as Python objects must be threadsafe. pub storage: Box, - pub global_contract_cache: GlobalContractCache, + pub contract_class_manager: ContractClassManager, } #[pymethods] impl PyBlockExecutor { #[new] - #[pyo3(signature = (bouncer_config, concurrency_config, os_config, global_contract_cache_size, target_storage_config, py_versioned_constants_overrides))] + #[pyo3(signature = (bouncer_config, concurrency_config, contract_class_manager_config, os_config, target_storage_config, py_versioned_constants_overrides, stack_size))] pub fn create( bouncer_config: PyBouncerConfig, concurrency_config: PyConcurrencyConfig, + contract_class_manager_config: PyContractClassManagerConfig, os_config: PyOsConfig, - global_contract_cache_size: usize, target_storage_config: StorageConfig, py_versioned_constants_overrides: PyVersionedConstantsOverrides, + stack_size: usize, ) -> Self { log::debug!("Initializing Block Executor..."); let storage = @@ -156,12 +92,15 @@ impl PyBlockExecutor { bouncer_config: bouncer_config.try_into().expect("Failed to parse bouncer config."), tx_executor_config: TransactionExecutorConfig { concurrency_config: concurrency_config.into(), + stack_size, }, chain_info: os_config.into_chain_info(), versioned_constants, tx_executor: None, storage: Box::new(storage), - global_contract_cache: GlobalContractCache::new(global_contract_cache_size), + contract_class_manager: ContractClassManager::start( + contract_class_manager_config.into(), + ), } } @@ -206,12 +145,10 @@ impl PyBlockExecutor { optional_py_class_info: Option, ) -> NativeBlockifierResult> { let tx: Transaction = py_tx(tx, optional_py_class_info).expect(PY_TX_PARSING_ERR); - let tx_execution_info = self.tx_executor().execute(&tx)?; - let thin_tx_execution_info = - ThinTransactionExecutionInfo::from_tx_execution_info(tx_execution_info); + let (tx_execution_info, _state_diff) = self.tx_executor().execute(&tx)?; // Serialize and convert to PyBytes. - let serialized_tx_execution_info = thin_tx_execution_info.serialize(); + let serialized_tx_execution_info = serialize_tx_execution_info(tx_execution_info); Ok(Python::with_gil(|py| PyBytes::new(py, &serialized_tx_execution_info).into())) } @@ -241,12 +178,11 @@ impl PyBlockExecutor { .into_iter() // Note: there might be less results than txs (if there is no room for all of them). .map(|result| match result { - Ok(tx_execution_info) => ( + Ok((tx_execution_info, _state_diff)) => ( true, - ThinTransactionExecutionInfo::from_tx_execution_info( + serialize_tx_execution_info( tx_execution_info, - ) - .serialize(), + ), ), Err(error) => (false, serialize_failure_reason(error)), }) @@ -268,29 +204,24 @@ impl PyBlockExecutor { }) } - /// Returns the state diff, a list of contract class hash with the corresponding list of - /// visited segment values and the block weights. + /// Returns the state diff, the stateful-compressed state diff and the block weights. pub fn finalize( &mut self, - ) -> NativeBlockifierResult<(PyStateDiff, PyVisitedSegmentsMapping, Py)> { + ) -> NativeBlockifierResult<(PyStateDiff, Option, Py)> { log::debug!("Finalizing execution..."); - let (commitment_state_diff, visited_pcs, block_weights) = self.tx_executor().finalize()?; - let visited_pcs = visited_pcs - .into_iter() - .map(|(class_hash, class_visited_pcs_vec)| { - (PyFelt::from(class_hash), class_visited_pcs_vec) - }) - .collect(); - let py_state_diff = PyStateDiff::from(commitment_state_diff); + let BlockExecutionSummary { state_diff, compressed_state_diff, bouncer_weights } = + self.tx_executor().finalize()?; + let py_state_diff = PyStateDiff::from(state_diff); + let py_compressed_state_diff = compressed_state_diff.map(PyStateDiff::from); let serialized_block_weights = - serde_json::to_vec(&block_weights).expect("Failed serializing bouncer weights."); + serde_json::to_vec(&bouncer_weights).expect("Failed serializing bouncer weights."); let raw_block_weights = Python::with_gil(|py| PyBytes::new(py, &serialized_block_weights).into()); log::debug!("Finalized execution."); - Ok((py_state_diff, visited_pcs, raw_block_weights)) + Ok((py_state_diff, py_compressed_state_diff, raw_block_weights)) } // Storage Alignment API. @@ -354,8 +285,8 @@ impl PyBlockExecutor { /// (this is true for every partial existence of information at tables). #[pyo3(signature = (block_number))] pub fn revert_block(&mut self, block_number: u64) -> NativeBlockifierResult<()> { - // Clear global class cache, to peroperly revert classes declared in the reverted block. - self.global_contract_cache.clear(); + // Clear global class cache, to properly revert classes declared in the reverted block. + self.contract_class_manager.clear(); self.storage.revert_block(block_number) } @@ -368,21 +299,29 @@ impl PyBlockExecutor { self.storage.close(); } - #[cfg(any(feature = "testing", test))] - #[pyo3(signature = (concurrency_config, os_config, path, max_state_diff_size))] + #[pyo3(signature = (concurrency_config, contract_class_manager_config, os_config, path, max_state_diff_size, stack_size, min_sierra_version))] #[staticmethod] fn create_for_testing( concurrency_config: PyConcurrencyConfig, + contract_class_manager_config: PyContractClassManagerConfig, os_config: PyOsConfig, path: std::path::PathBuf, max_state_diff_size: usize, + stack_size: usize, + min_sierra_version: Option, ) -> Self { use blockifier::bouncer::BouncerWeights; - use blockifier::state::global_cache::GLOBAL_CONTRACT_CACHE_SIZE_FOR_TEST; // TODO(Meshi, 01/01/2025): Remove this once we fix all python tests that re-declare cairo0 // contracts. let mut versioned_constants = VersionedConstants::latest_constants().clone(); versioned_constants.disable_cairo0_redeclaration = false; + + if let Some(min_sierra_version) = min_sierra_version { + versioned_constants.min_sierra_version_for_sierra_gas = + SierraVersion::from_str(&min_sierra_version) + .expect("failed to parse sierra version."); + } + Self { bouncer_config: BouncerConfig { block_max_capacity: BouncerWeights { @@ -392,12 +331,15 @@ impl PyBlockExecutor { }, tx_executor_config: TransactionExecutorConfig { concurrency_config: concurrency_config.into(), + stack_size, }, storage: Box::new(PapyrusStorage::new_for_testing(path, &os_config.chain_id)), chain_info: os_config.into_chain_info(), versioned_constants, tx_executor: None, - global_contract_cache: GlobalContractCache::new(GLOBAL_CONTRACT_CACHE_SIZE_FOR_TEST), + contract_class_manager: ContractClassManager::start( + contract_class_manager_config.into(), + ), } } } @@ -413,13 +355,11 @@ impl PyBlockExecutor { PapyrusReader::new( self.storage.reader().clone(), next_block_number, - self.global_contract_cache.clone(), + self.contract_class_manager.clone(), ) } - #[cfg(any(feature = "testing", test))] pub fn create_for_testing_with_storage(storage: impl Storage + Send + 'static) -> Self { - use blockifier::state::global_cache::GLOBAL_CONTRACT_CACHE_SIZE_FOR_TEST; Self { bouncer_config: BouncerConfig::max(), tx_executor_config: TransactionExecutorConfig::create_for_testing(true), @@ -427,18 +367,30 @@ impl PyBlockExecutor { chain_info: ChainInfo::default(), versioned_constants: VersionedConstants::latest_constants().clone(), tx_executor: None, - global_contract_cache: GlobalContractCache::new(GLOBAL_CONTRACT_CACHE_SIZE_FOR_TEST), + contract_class_manager: ContractClassManager::start( + ContractClassManagerConfig::default(), + ), } } #[cfg(test)] pub(crate) fn native_create_for_testing( concurrency_config: PyConcurrencyConfig, + contract_class_manager_config: PyContractClassManagerConfig, os_config: PyOsConfig, path: std::path::PathBuf, max_state_diff_size: usize, + stack_size: usize, ) -> Self { - Self::create_for_testing(concurrency_config, os_config, path, max_state_diff_size) + Self::create_for_testing( + concurrency_config, + contract_class_manager_config, + os_config, + path, + max_state_diff_size, + stack_size, + None, + ) } } diff --git a/crates/native_blockifier/src/py_block_executor_test.rs b/crates/native_blockifier/src/py_block_executor_test.rs index 47a39d3409c..3708046ffa4 100644 --- a/crates/native_blockifier/src/py_block_executor_test.rs +++ b/crates/native_blockifier/src/py_block_executor_test.rs @@ -1,18 +1,18 @@ use std::collections::HashMap; -use blockifier::blockifier::transaction_executor::BLOCK_STATE_ACCESS_ERR; -use blockifier::execution::contract_class::{ContractClassV1, RunnableContractClass}; +use blockifier::blockifier::transaction_executor::{BLOCK_STATE_ACCESS_ERR, DEFAULT_STACK_SIZE}; +use blockifier::execution::contract_class::{CompiledClassV1, RunnableCompiledClass}; use blockifier::state::state_api::StateReader; -use cached::Cached; use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass; use pretty_assertions::assert_eq; use starknet_api::class_hash; +use starknet_api::contract_class::SierraVersion; use starknet_api::deprecated_contract_class::ContractClass as DeprecatedContractClass; use starknet_api::state::SierraContractClass; use starknet_types_core::felt::Felt; use crate::py_block_executor::{PyBlockExecutor, PyOsConfig}; -use crate::py_objects::PyConcurrencyConfig; +use crate::py_objects::{PyConcurrencyConfig, PyContractClassManagerConfig}; use crate::py_state_diff::{PyBlockInfo, PyStateDiff}; use crate::py_utils::PyFelt; use crate::test_utils::MockStorage; @@ -32,16 +32,24 @@ fn global_contract_cache_update() { entry_points_by_type: Default::default(), }; let sierra = SierraContractClass::default(); - let contract_class = - RunnableContractClass::V1(ContractClassV1::try_from(casm.clone()).unwrap()); + let contract_class = RunnableCompiledClass::V1( + CompiledClassV1::try_from(( + casm.clone(), + SierraVersion::extract_from_program(&sierra.sierra_program).unwrap(), + )) + .unwrap(), + ); let class_hash = class_hash!("0x1"); let temp_storage_path = tempfile::tempdir().unwrap().into_path(); let mut block_executor = PyBlockExecutor::create_for_testing( PyConcurrencyConfig::default(), + PyContractClassManagerConfig::default(), PyOsConfig::default(), temp_storage_path, 4000, + DEFAULT_STACK_SIZE, + None, ); block_executor .append_block( @@ -68,18 +76,18 @@ fn global_contract_cache_update() { ) .unwrap(); - assert_eq!(block_executor.global_contract_cache.lock().cache_size(), 0); + assert_eq!(block_executor.contract_class_manager.get_cache_size(), 0); let queried_contract_class = block_executor .tx_executor() .block_state .as_ref() .expect(BLOCK_STATE_ACCESS_ERR) - .get_compiled_contract_class(class_hash) + .get_compiled_class(class_hash) .unwrap(); assert_eq!(queried_contract_class, contract_class); - assert_eq!(block_executor.global_contract_cache.lock().cache_size(), 1); + assert_eq!(block_executor.contract_class_manager.get_cache_size(), 1); } #[test] @@ -119,9 +127,11 @@ fn global_contract_cache_update_large_contract() { let temp_storage_path = tempfile::tempdir().unwrap().into_path(); let mut block_executor = PyBlockExecutor::native_create_for_testing( Default::default(), + PyContractClassManagerConfig::default(), Default::default(), temp_storage_path, 4000, + DEFAULT_STACK_SIZE, ); block_executor .append_block( diff --git a/crates/native_blockifier/src/py_declare.rs b/crates/native_blockifier/src/py_declare.rs index 55cf53c4bef..868572e4284 100644 --- a/crates/native_blockifier/src/py_declare.rs +++ b/crates/native_blockifier/src/py_declare.rs @@ -113,7 +113,7 @@ pub fn py_declare( py_class_info: PyClassInfo, ) -> NativeBlockifierResult { let version = py_attr::(py_tx, "version")?.0; - // TODO: Make TransactionVersion an enum and use match here. + // TODO(Dori): Make TransactionVersion an enum and use match here. let tx = if version == Felt::ZERO { let py_declare_tx: PyDeclareTransactionV0V1 = py_tx.extract()?; let declare_tx = DeclareTransactionV0V1::try_from(py_declare_tx)?; diff --git a/crates/native_blockifier/src/py_deploy_account.rs b/crates/native_blockifier/src/py_deploy_account.rs index 9d4dbdb9301..48ce9ebd2e7 100644 --- a/crates/native_blockifier/src/py_deploy_account.rs +++ b/crates/native_blockifier/src/py_deploy_account.rs @@ -83,7 +83,7 @@ impl TryFrom for DeployAccountTransactionV3 { pub fn py_deploy_account(py_tx: &PyAny) -> NativeBlockifierResult { let version = py_attr::(py_tx, "version")?.0; - // TODO: Make TransactionVersion an enum and use match here. + // TODO(Dori): Make TransactionVersion an enum and use match here. let tx = if version == Felt::ONE { let py_deploy_account_tx: PyDeployAccountTransactionV1 = py_tx.extract()?; let deploy_account_tx = DeployAccountTransactionV1::from(py_deploy_account_tx); diff --git a/crates/native_blockifier/src/py_invoke_function.rs b/crates/native_blockifier/src/py_invoke_function.rs index bad90021caa..7f366391ac2 100644 --- a/crates/native_blockifier/src/py_invoke_function.rs +++ b/crates/native_blockifier/src/py_invoke_function.rs @@ -108,7 +108,7 @@ impl TryFrom for InvokeTransactionV3 { pub fn py_invoke_function(py_tx: &PyAny) -> NativeBlockifierResult { let version = py_attr::(py_tx, "version")?.0; - // TODO: Make TransactionVersion an enum and use match here. + // TODO(Dori): Make TransactionVersion an enum and use match here. let tx = if version == Felt::ZERO { let py_invoke_tx: PyInvokeTransactionV0 = py_tx.extract()?; let invoke_tx = InvokeTransactionV0::try_from(py_invoke_tx)?; diff --git a/crates/native_blockifier/src/py_l1_handler.rs b/crates/native_blockifier/src/py_l1_handler.rs index df90b9642ed..1816e42a7ce 100644 --- a/crates/native_blockifier/src/py_l1_handler.rs +++ b/crates/native_blockifier/src/py_l1_handler.rs @@ -1,6 +1,5 @@ use std::sync::Arc; -use blockifier::abi::constants; use pyo3::prelude::*; use starknet_api::core::{ContractAddress, EntryPointSelector, Nonce}; use starknet_api::executable_transaction::L1HandlerTransaction; @@ -22,7 +21,7 @@ impl TryFrom for starknet_api::transaction::L1HandlerTra type Error = NativeBlockifierInputError; fn try_from(tx: PyL1HandlerTransaction) -> Result { Ok(Self { - version: constants::L1_HANDLER_VERSION, + version: starknet_api::transaction::L1HandlerTransaction::VERSION, nonce: Nonce(tx.nonce.0), contract_address: ContractAddress::try_from(tx.contract_address.0)?, entry_point_selector: EntryPointSelector(tx.entry_point_selector.0), diff --git a/crates/native_blockifier/src/py_objects.rs b/crates/native_blockifier/src/py_objects.rs index 8212a3fd3a3..698b690d76b 100644 --- a/crates/native_blockifier/src/py_objects.rs +++ b/crates/native_blockifier/src/py_objects.rs @@ -1,19 +1,27 @@ +#![allow(non_local_definitions)] + use std::collections::HashMap; +use std::path::PathBuf; use blockifier::abi::constants; -use blockifier::blockifier::config::ConcurrencyConfig; -use blockifier::bouncer::{BouncerConfig, BouncerWeights, BuiltinCount, HashMapWrapper}; -use blockifier::versioned_constants::VersionedConstantsOverrides; -use cairo_vm::types::builtin_name::BuiltinName; +use blockifier::blockifier::config::{ + CairoNativeRunConfig, + ConcurrencyConfig, + ContractClassManagerConfig, + NativeClassesWhitelist, +}; +use blockifier::blockifier_versioned_constants::VersionedConstantsOverrides; +use blockifier::bouncer::{BouncerConfig, BouncerWeights}; +use blockifier::state::contract_class_manager::DEFAULT_COMPILATION_REQUEST_CHANNEL_SIZE; +use blockifier::state::global_cache::GLOBAL_CONTRACT_CACHE_SIZE_FOR_TEST; use cairo_vm::vm::runners::cairo_runner::ExecutionResources; use pyo3::prelude::*; +use starknet_api::core::ClassHash; +use starknet_api::execution_resources::GasAmount; +use starknet_sierra_multicompile::config::SierraCompilationConfig; -use crate::errors::{ - InvalidNativeBlockifierInputError, - NativeBlockifierError, - NativeBlockifierInputError, - NativeBlockifierResult, -}; +use crate::errors::{NativeBlockifierError, NativeBlockifierResult}; +use crate::py_utils::PyFelt; // From Rust to Python. @@ -50,18 +58,20 @@ pub struct PyVersionedConstantsOverrides { pub validate_max_n_steps: u32, pub max_recursion_depth: usize, pub invoke_tx_max_n_steps: u32, + pub max_n_events: usize, } #[pymethods] impl PyVersionedConstantsOverrides { #[new] - #[pyo3(signature = (validate_max_n_steps, max_recursion_depth, invoke_tx_max_n_steps))] + #[pyo3(signature = (validate_max_n_steps, max_recursion_depth, invoke_tx_max_n_steps, max_n_events))] pub fn create( validate_max_n_steps: u32, max_recursion_depth: usize, invoke_tx_max_n_steps: u32, + max_n_events: usize, ) -> Self { - Self { validate_max_n_steps, max_recursion_depth, invoke_tx_max_n_steps } + Self { validate_max_n_steps, max_recursion_depth, invoke_tx_max_n_steps, max_n_events } } } @@ -71,8 +81,9 @@ impl From for VersionedConstantsOverrides { validate_max_n_steps, max_recursion_depth, invoke_tx_max_n_steps, + max_n_events, } = py_versioned_constants_overrides; - Self { validate_max_n_steps, max_recursion_depth, invoke_tx_max_n_steps } + Self { validate_max_n_steps, max_recursion_depth, invoke_tx_max_n_steps, max_n_events } } } @@ -92,44 +103,24 @@ impl TryFrom for BouncerConfig { } } -fn hash_map_into_builtin_count( - builtins: HashMap, -) -> Result { - let mut wrapper = HashMapWrapper::new(); - for (builtin_name, count) in builtins.iter() { - let builtin = BuiltinName::from_str_with_suffix(builtin_name) - .ok_or(NativeBlockifierInputError::UnknownBuiltin(builtin_name.clone()))?; - wrapper.insert(builtin, *count); - } - let builtin_count: BuiltinCount = wrapper.into(); - if builtin_count.all_non_zero() { - Ok(builtin_count) - } else { - Err(NativeBlockifierInputError::InvalidNativeBlockifierInputError( - InvalidNativeBlockifierInputError::InvalidBuiltinCounts(builtin_count), - )) - } -} - fn hash_map_into_bouncer_weights( mut data: HashMap, ) -> NativeBlockifierResult { - let gas = data.remove(constants::L1_GAS_USAGE).expect("gas_weight must be present"); - let n_steps = data.remove(constants::N_STEPS_RESOURCE).expect("n_steps must be present"); + let l1_gas = data.remove(constants::L1_GAS_USAGE).expect("gas_weight must be present"); let message_segment_length = data .remove(constants::MESSAGE_SEGMENT_LENGTH) .expect("message_segment_length must be present"); let state_diff_size = data.remove(constants::STATE_DIFF_SIZE).expect("state_diff_size must be present"); let n_events = data.remove(constants::N_EVENTS).expect("n_events must be present"); - Ok(BouncerWeights { - gas, - n_steps, - message_segment_length, - state_diff_size, - n_events, - builtin_count: hash_map_into_builtin_count(data)?, - }) + let sierra_gas = GasAmount( + data.remove(constants::SIERRA_GAS) + .expect("sierra_gas must be present") + .try_into() + .unwrap_or_else(|err| panic!("Failed to convert 'sierra_gas' into GasAmount: {err}.")), + ); + + Ok(BouncerWeights { l1_gas, message_segment_length, state_diff_size, n_events, sierra_gas }) } #[derive(Debug, Default, FromPyObject)] @@ -148,3 +139,100 @@ impl From for ConcurrencyConfig { } } } +#[derive(Clone, Debug, Default, FromPyObject)] +pub struct PySierraCompilationConfig { + pub sierra_to_native_compiler_path: String, + pub max_native_bytecode_size: u64, + pub max_cpu_time: u64, + pub max_memory_usage: u64, + pub optimization_level: u8, + pub panic_on_compilation_failure: bool, +} + +impl From for SierraCompilationConfig { + fn from(py_sierra_compilation_config: PySierraCompilationConfig) -> Self { + SierraCompilationConfig { + sierra_to_native_compiler_path: if py_sierra_compilation_config + .sierra_to_native_compiler_path + .is_empty() + { + None + } else { + Some(PathBuf::from(py_sierra_compilation_config.sierra_to_native_compiler_path)) + }, + max_native_bytecode_size: py_sierra_compilation_config.max_native_bytecode_size, + max_cpu_time: py_sierra_compilation_config.max_cpu_time, + max_memory_usage: py_sierra_compilation_config.max_memory_usage, + panic_on_compilation_failure: py_sierra_compilation_config.panic_on_compilation_failure, + optimization_level: py_sierra_compilation_config.optimization_level, + ..Default::default() + } + } +} + +#[derive(Clone, Debug, FromPyObject)] +pub struct PyCairoNativeRunConfig { + pub run_cairo_native: bool, + pub wait_on_native_compilation: bool, + pub channel_size: usize, + // Determines which contracts are allowd to run Cairo Native. `None` → All. + pub native_classes_whitelist: Option>, +} + +impl Default for PyCairoNativeRunConfig { + fn default() -> Self { + Self { + run_cairo_native: false, + wait_on_native_compilation: false, + channel_size: DEFAULT_COMPILATION_REQUEST_CHANNEL_SIZE, + native_classes_whitelist: None, + } + } +} + +impl From for CairoNativeRunConfig { + fn from(py_cairo_native_run_config: PyCairoNativeRunConfig) -> Self { + let native_classes_whitelist = match py_cairo_native_run_config.native_classes_whitelist { + Some(felts) => NativeClassesWhitelist::Limited( + felts.into_iter().map(|felt| ClassHash(felt.0)).collect(), + ), + None => NativeClassesWhitelist::All, + }; + + CairoNativeRunConfig { + run_cairo_native: py_cairo_native_run_config.run_cairo_native, + wait_on_native_compilation: py_cairo_native_run_config.wait_on_native_compilation, + channel_size: py_cairo_native_run_config.channel_size, + native_classes_whitelist, + } + } +} + +#[derive(Debug, Clone, FromPyObject)] +pub struct PyContractClassManagerConfig { + pub contract_cache_size: usize, + pub cairo_native_run_config: PyCairoNativeRunConfig, + pub native_compiler_config: PySierraCompilationConfig, +} + +impl Default for PyContractClassManagerConfig { + fn default() -> Self { + Self { + contract_cache_size: GLOBAL_CONTRACT_CACHE_SIZE_FOR_TEST, + cairo_native_run_config: PyCairoNativeRunConfig::default(), + native_compiler_config: PySierraCompilationConfig::default(), + } + } +} + +impl From for ContractClassManagerConfig { + fn from(py_contract_class_manager_config: PyContractClassManagerConfig) -> Self { + ContractClassManagerConfig { + contract_cache_size: py_contract_class_manager_config.contract_cache_size, + cairo_native_run_config: py_contract_class_manager_config + .cairo_native_run_config + .into(), + native_compiler_config: py_contract_class_manager_config.native_compiler_config.into(), + } + } +} diff --git a/crates/native_blockifier/src/py_state_diff.rs b/crates/native_blockifier/src/py_state_diff.rs index 70f15e98e39..63f1606840e 100644 --- a/crates/native_blockifier/src/py_state_diff.rs +++ b/crates/native_blockifier/src/py_state_diff.rs @@ -1,19 +1,13 @@ use std::collections::HashMap; use std::convert::TryFrom; -use blockifier::blockifier::block::{BlockInfo, GasPrices}; +use blockifier::blockifier::block::validated_gas_prices; +use blockifier::blockifier_versioned_constants::VersionedConstants; use blockifier::state::cached_state::CommitmentStateDiff; -use blockifier::test_utils::{ - DEFAULT_ETH_L1_DATA_GAS_PRICE, - DEFAULT_ETH_L1_GAS_PRICE, - DEFAULT_STRK_L1_DATA_GAS_PRICE, - DEFAULT_STRK_L1_GAS_PRICE, -}; -use blockifier::versioned_constants::VersionedConstants; use indexmap::IndexMap; use pyo3::prelude::*; use pyo3::FromPyObject; -use starknet_api::block::{BlockNumber, BlockTimestamp, NonzeroGasPrice}; +use starknet_api::block::{BlockInfo, BlockNumber, BlockTimestamp, GasPrice, NonzeroGasPrice}; use starknet_api::core::{ClassHash, ContractAddress, Nonce}; use starknet_api::state::{StateDiff, StorageKey}; @@ -25,9 +19,15 @@ use crate::errors::{ }; use crate::py_utils::PyFelt; +// TODO(Arni): consider moving to starknet api. +const DEFAULT_ETH_L1_GAS_PRICE: GasPrice = GasPrice(100 * u128::pow(10, 9)); +const DEFAULT_STRK_L1_GAS_PRICE: GasPrice = GasPrice(100 * u128::pow(10, 9)); +const DEFAULT_ETH_L1_DATA_GAS_PRICE: GasPrice = GasPrice(u128::pow(10, 6)); +const DEFAULT_STRK_L1_DATA_GAS_PRICE: GasPrice = GasPrice(u128::pow(10, 9)); + #[pyclass] #[derive(Default, FromPyObject)] -// TODO: Add support for returning the `declared_classes` to python. +// TODO(Dori): Add support for returning the `declared_classes` to python. pub struct PyStateDiff { #[pyo3(get)] pub address_to_class_hash: HashMap, @@ -77,7 +77,6 @@ impl TryFrom for StateDiff { declared_classes: IndexMap::new(), deprecated_declared_classes: IndexMap::new(), nonces, - replaced_classes: IndexMap::new(), }) } } @@ -153,19 +152,19 @@ impl Default for PyBlockInfo { block_number: u64::default(), block_timestamp: u64::default(), l1_gas_price: PyResourcePrice { - price_in_wei: DEFAULT_ETH_L1_GAS_PRICE.get().0, - price_in_fri: DEFAULT_STRK_L1_GAS_PRICE.get().0, + price_in_wei: DEFAULT_ETH_L1_GAS_PRICE.0, + price_in_fri: DEFAULT_STRK_L1_GAS_PRICE.0, }, l1_data_gas_price: PyResourcePrice { - price_in_wei: DEFAULT_ETH_L1_DATA_GAS_PRICE.get().0, - price_in_fri: DEFAULT_STRK_L1_DATA_GAS_PRICE.get().0, + price_in_wei: DEFAULT_ETH_L1_DATA_GAS_PRICE.0, + price_in_fri: DEFAULT_STRK_L1_DATA_GAS_PRICE.0, }, l2_gas_price: PyResourcePrice { price_in_wei: VersionedConstants::latest_constants() - .convert_l1_to_l2_gas_price_round_up(DEFAULT_ETH_L1_GAS_PRICE.into()) + .convert_l1_to_l2_gas_price_round_up(DEFAULT_ETH_L1_GAS_PRICE) .0, price_in_fri: VersionedConstants::latest_constants() - .convert_l1_to_l2_gas_price_round_up(DEFAULT_STRK_L1_GAS_PRICE.into()) + .convert_l1_to_l2_gas_price_round_up(DEFAULT_STRK_L1_GAS_PRICE) .0, }, sequencer_address: PyFelt::default(), @@ -182,7 +181,7 @@ impl TryFrom for BlockInfo { block_number: BlockNumber(block_info.block_number), block_timestamp: BlockTimestamp(block_info.block_timestamp), sequencer_address: ContractAddress::try_from(block_info.sequencer_address.0)?, - gas_prices: GasPrices::new( + gas_prices: validated_gas_prices( NonzeroGasPrice::try_from(block_info.l1_gas_price.price_in_wei).map_err(|_| { NativeBlockifierInputError::InvalidNativeBlockifierInputError( InvalidNativeBlockifierInputError::InvalidL1GasPriceWei( diff --git a/crates/native_blockifier/src/py_test_utils.rs b/crates/native_blockifier/src/py_test_utils.rs index 6cae66fa3fa..2ba5ac4d485 100644 --- a/crates/native_blockifier/src/py_test_utils.rs +++ b/crates/native_blockifier/src/py_test_utils.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use blockifier::execution::contract_class::ContractClassV0; +use blockifier::execution::contract_class::CompiledClassV0; use blockifier::state::cached_state::CachedState; use blockifier::test_utils::dict_state_reader::DictStateReader; use blockifier::test_utils::struct_impls::LoadContractFromFile; @@ -14,7 +14,7 @@ pub const TOKEN_FOR_TESTING_CONTRACT_PATH: &str = starknet/core/test_contract/token_for_testing.json"; pub fn create_py_test_state() -> CachedState { - let contract_class: ContractClassV0 = + let contract_class: CompiledClassV0 = ContractClass::from_file(TOKEN_FOR_TESTING_CONTRACT_PATH).try_into().unwrap(); let class_hash_to_class = HashMap::from([(class_hash!(TOKEN_FOR_TESTING_CLASS_HASH), contract_class.into())]); diff --git a/crates/native_blockifier/src/py_transaction.rs b/crates/native_blockifier/src/py_transaction.rs index bdf28426b08..6d7bf55ce75 100644 --- a/crates/native_blockifier/src/py_transaction.rs +++ b/crates/native_blockifier/src/py_transaction.rs @@ -6,7 +6,7 @@ use blockifier::transaction::transaction_types::TransactionType; use pyo3::exceptions::PyValueError; use pyo3::prelude::*; use starknet_api::block::GasPrice; -use starknet_api::contract_class::{ClassInfo, ContractClass}; +use starknet_api::contract_class::{ClassInfo, ContractClass, SierraVersion}; use starknet_api::executable_transaction::AccountTransaction as ExecutableTransaction; use starknet_api::execution_resources::GasAmount; use starknet_api::transaction::fields::{ @@ -30,6 +30,7 @@ pub(crate) const PY_TX_PARSING_ERR: &str = "Failed parsing Py transaction."; #[derive(Clone, Eq, Ord, PartialEq, PartialOrd)] pub enum PyResource { L1Gas, + L1DataGas, L2Gas, } @@ -37,6 +38,7 @@ impl From for Resource { fn from(py_resource: PyResource) -> Self { match py_resource { PyResource::L1Gas => Resource::L1Gas, + PyResource::L1DataGas => Resource::L1DataGas, PyResource::L2Gas => Resource::L2Gas, } } @@ -47,6 +49,7 @@ impl FromPyObject<'_> for PyResource { let resource_name: &str = resource.getattr("name")?.extract()?; match resource_name { "L1_GAS" => Ok(PyResource::L1Gas), + "L1_DATA_GAS" => Ok(PyResource::L1DataGas), "L2_GAS" => Ok(PyResource::L2Gas), _ => Err(PyValueError::new_err(format!("Invalid resource: {resource_name}"))), } @@ -138,18 +141,16 @@ pub fn py_tx( TransactionType::Declare => { let non_optional_py_class_info: PyClassInfo = optional_py_class_info .expect("A class info must be passed in a Declare transaction."); - AccountTransaction::new(ExecutableTransaction::Declare(py_declare( - tx, - non_optional_py_class_info, - )?)) - .into() + let tx = ExecutableTransaction::Declare(py_declare(tx, non_optional_py_class_info)?); + AccountTransaction::new_for_sequencing(tx).into() } TransactionType::DeployAccount => { - AccountTransaction::new(ExecutableTransaction::DeployAccount(py_deploy_account(tx)?)) - .into() + let tx = ExecutableTransaction::DeployAccount(py_deploy_account(tx)?); + AccountTransaction::new_for_sequencing(tx).into() } TransactionType::InvokeFunction => { - AccountTransaction::new(ExecutableTransaction::Invoke(py_invoke_function(tx)?)).into() + let tx = ExecutableTransaction::Invoke(py_invoke_function(tx)?); + AccountTransaction::new_for_sequencing(tx).into() } TransactionType::L1Handler => py_l1_handler(tx)?.into(), }) @@ -164,6 +165,7 @@ pub struct PyClassInfo { raw_contract_class: String, sierra_program_length: usize, abi_length: usize, + sierra_version: (u64, u64, u64), } impl PyClassInfo { @@ -177,14 +179,18 @@ impl PyClassInfo { ContractClass::V0(serde_json::from_str(&py_class_info.raw_contract_class)?) } starknet_api::transaction::DeclareTransaction::V2(_) - | starknet_api::transaction::DeclareTransaction::V3(_) => { - ContractClass::V1(serde_json::from_str(&py_class_info.raw_contract_class)?) - } + | starknet_api::transaction::DeclareTransaction::V3(_) => ContractClass::V1(( + serde_json::from_str(&py_class_info.raw_contract_class)?, + SierraVersion::from(py_class_info.sierra_version), + )), }; + let (major, minor, patch) = py_class_info.sierra_version; + let class_info = ClassInfo::new( &contract_class, py_class_info.sierra_program_length, py_class_info.abi_length, + SierraVersion::new(major, minor, patch), )?; Ok(class_info) } diff --git a/crates/native_blockifier/src/py_utils.rs b/crates/native_blockifier/src/py_utils.rs index 5b5f1b22f96..744e6be350a 100644 --- a/crates/native_blockifier/src/py_utils.rs +++ b/crates/native_blockifier/src/py_utils.rs @@ -68,7 +68,7 @@ fn int_to_stark_felt(int: &PyAny) -> PyResult { biguint_to_felt(biguint).map_err(|e| PyValueError::new_err(e.to_string())) } -// TODO: Convert to a `TryFrom` cast and put in starknet-api (In Felt). +// TODO(Dori): Convert to a `TryFrom` cast and put in starknet-api (In Felt). pub fn biguint_to_felt(biguint: BigUint) -> NativeBlockifierResult { let biguint_hex = format!("{biguint:#x}"); Ok(Felt::from_hex(&biguint_hex).map_err(NativeBlockifierInputError::from)?) diff --git a/crates/native_blockifier/src/py_validator.rs b/crates/native_blockifier/src/py_validator.rs index e035f0c4ef6..cd39147fa16 100644 --- a/crates/native_blockifier/src/py_validator.rs +++ b/crates/native_blockifier/src/py_validator.rs @@ -1,11 +1,13 @@ +#![allow(non_local_definitions)] + use blockifier::blockifier::stateful_validator::{StatefulValidator, StatefulValidatorResult}; +use blockifier::blockifier_versioned_constants::VersionedConstants; use blockifier::bouncer::BouncerConfig; use blockifier::context::BlockContext; use blockifier::state::cached_state::CachedState; use blockifier::transaction::account_transaction::AccountTransaction; use blockifier::transaction::objects::TransactionInfoCreator; use blockifier::transaction::transaction_types::TransactionType; -use blockifier::versioned_constants::VersionedConstants; use pyo3::{pyclass, pymethods, PyAny}; use starknet_api::core::Nonce; use starknet_api::transaction::TransactionHash; @@ -66,30 +68,33 @@ impl PyValidator { optional_py_class_info: Option, deploy_account_tx_hash: Option, ) -> NativeBlockifierResult<()> { - let account_tx = py_account_tx(tx, optional_py_class_info).expect(PY_TX_PARSING_ERR); + let mut account_tx = py_account_tx(tx, optional_py_class_info).expect(PY_TX_PARSING_ERR); let deploy_account_tx_hash = deploy_account_tx_hash.map(|hash| TransactionHash(hash.0)); // We check if the transaction should be skipped due to the deploy account not being // processed. - let skip_validate = self - .skip_validate_due_to_unprocessed_deploy_account(&account_tx, deploy_account_tx_hash)?; - self.stateful_validator.perform_validations(account_tx, skip_validate)?; + let validate = self.should_run_stateful_validations(&account_tx, deploy_account_tx_hash)?; + + account_tx.execution_flags.validate = validate; + account_tx.execution_flags.strict_nonce_check = false; + self.stateful_validator.perform_validations(account_tx)?; Ok(()) } } impl PyValidator { - // Check if deploy account was submitted but not processed yet. If so, then skip - // `__validate__` method for subsequent transactions for a better user experience. - // (they will otherwise fail solely because the deploy account hasn't been processed yet). - pub fn skip_validate_due_to_unprocessed_deploy_account( + // Returns whether the transaction should be statefully validated. + // If the DeployAccount transaction of the account was submitted but not processed yet, it + // should be skipped for subsequent transactions for a better user experience. (they will + // otherwise fail solely because the deploy account hasn't been processed yet). + pub fn should_run_stateful_validations( &mut self, account_tx: &AccountTransaction, deploy_account_tx_hash: Option, ) -> StatefulValidatorResult { if account_tx.tx_type() != TransactionType::InvokeFunction { - return Ok(false); + return Ok(true); } let tx_info = account_tx.create_tx_info(); let nonce = self.stateful_validator.get_nonce(tx_info.sender_address())?; @@ -105,6 +110,6 @@ impl PyValidator { && is_post_deploy_nonce && nonce_small_enough_to_qualify_for_validation_skip; - Ok(skip_validate) + Ok(!skip_validate) } } diff --git a/crates/native_blockifier/src/state_readers/py_state_reader.rs b/crates/native_blockifier/src/state_readers/py_state_reader.rs index f379dcb05bf..778fcc6a716 100644 --- a/crates/native_blockifier/src/state_readers/py_state_reader.rs +++ b/crates/native_blockifier/src/state_readers/py_state_reader.rs @@ -1,11 +1,13 @@ use blockifier::execution::contract_class::{ - ContractClassV0, - ContractClassV1, - RunnableContractClass, + CompiledClassV0, + CompiledClassV1, + RunnableCompiledClass, }; use blockifier::state::errors::StateError; use blockifier::state::state_api::{StateReader, StateResult}; +use pyo3::types::PyTuple; use pyo3::{FromPyObject, PyAny, PyErr, PyObject, PyResult, Python}; +use starknet_api::contract_class::SierraVersion; use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; use starknet_api::state::StorageKey; use starknet_types_core::felt::Felt; @@ -68,19 +70,33 @@ impl StateReader for PyStateReader { .map_err(|err| StateError::StateReadError(err.to_string())) } - fn get_compiled_contract_class( - &self, - class_hash: ClassHash, - ) -> StateResult { - Python::with_gil(|py| -> Result { + fn get_compiled_class(&self, class_hash: ClassHash) -> StateResult { + Python::with_gil(|py| -> Result { let args = (PyFelt::from(class_hash),); - let py_raw_compiled_class: PyRawCompiledClass = self + let py_versioned_raw_compiled_class: &PyTuple = self .state_reader_proxy .as_ref(py) - .call_method1("get_raw_compiled_class", args)? - .extract()?; + .call_method1("get_versioned_raw_compiled_class", args)? + .downcast()?; + + // Extract the raw compiled class + let py_raw_compiled_class: PyRawCompiledClass = + py_versioned_raw_compiled_class.get_item(0)?.extract()?; + + // Extract and process the Sierra version + let (major, minor, patch): (u64, u64, u64) = + py_versioned_raw_compiled_class.get_item(1)?.extract()?; + + let sierra_version = SierraVersion::new(major, minor, patch); + + let versioned_py_raw_compiled_class = VersionedPyRawClass { + raw_compiled_class: py_raw_compiled_class, + optional_sierra_version: Some(sierra_version), + }; - Ok(RunnableContractClass::try_from(py_raw_compiled_class)?) + let runnable_compiled_class = + RunnableCompiledClass::try_from(versioned_py_raw_compiled_class)?; + Ok(runnable_compiled_class) }) .map_err(|err| { if Python::with_gil(|py| err.is_instance_of::(py)) { @@ -110,15 +126,30 @@ pub struct PyRawCompiledClass { pub version: usize, } -impl TryFrom for RunnableContractClass { +pub struct VersionedPyRawClass { + raw_compiled_class: PyRawCompiledClass, + optional_sierra_version: Option, +} + +impl TryFrom for RunnableCompiledClass { type Error = NativeBlockifierError; - fn try_from(raw_compiled_class: PyRawCompiledClass) -> NativeBlockifierResult { + fn try_from(versioned_raw_compiled_class: VersionedPyRawClass) -> NativeBlockifierResult { + let raw_compiled_class = versioned_raw_compiled_class.raw_compiled_class; + match raw_compiled_class.version { - 0 => Ok(ContractClassV0::try_from_json_string(&raw_compiled_class.raw_compiled_class)? - .into()), - 1 => Ok(ContractClassV1::try_from_json_string(&raw_compiled_class.raw_compiled_class)? + 0 => Ok(CompiledClassV0::try_from_json_string(&raw_compiled_class.raw_compiled_class)? .into()), + 1 => { + let sierra_version = versioned_raw_compiled_class + .optional_sierra_version + .ok_or(NativeBlockifierInputError::MissingSierraVersion)?; + Ok(CompiledClassV1::try_from_json_string( + &raw_compiled_class.raw_compiled_class, + sierra_version, + )? + .into()) + } _ => Err(NativeBlockifierInputError::UnsupportedContractClassVersion { version: raw_compiled_class.version, })?, diff --git a/crates/native_blockifier/src/storage.rs b/crates/native_blockifier/src/storage.rs index 8f6dc054715..5b5b09dfee0 100644 --- a/crates/native_blockifier/src/storage.rs +++ b/crates/native_blockifier/src/storage.rs @@ -1,3 +1,5 @@ +#![allow(non_local_definitions)] + use std::collections::HashMap; use std::convert::TryFrom; use std::path::PathBuf; @@ -10,7 +12,7 @@ use papyrus_storage::header::{HeaderStorageReader, HeaderStorageWriter}; use papyrus_storage::state::{StateStorageReader, StateStorageWriter}; use pyo3::prelude::*; use starknet_api::block::{BlockHash, BlockHeader, BlockHeaderWithoutHash, BlockNumber}; -use starknet_api::core::{ChainId, ClassHash, CompiledClassHash, ContractAddress}; +use starknet_api::core::{ChainId, ClassHash, CompiledClassHash}; use starknet_api::deprecated_contract_class::ContractClass as DeprecatedContractClass; use starknet_api::hash::StarkHash; use starknet_api::state::{SierraContractClass, StateDiff, StateNumber, ThinStateDiff}; @@ -29,7 +31,8 @@ pub type RawDeprecatedDeclaredClassMapping = HashMap; // Invariant: Only one instance of this struct should exist. // Reader and writer fields must be cleared before the struct goes out of scope in Python; -// to prevent possible memory leaks (TODO: see if this is indeed necessary). +// to prevent possible memory leaks +// TODO(Dori): see if this is indeed necessary. pub struct PapyrusStorage { reader: Option, writer: Option, @@ -149,27 +152,6 @@ impl Storage for PapyrusStorage { } } - // Collect replaced classes (changed class hash of an already allocated address; - // i.e.: pointing to a non-zeroed class hash). Rest would be (newly) deployed classes. - let mut replaced_classes = IndexMap::::new(); - for (address, class_hash) in &py_state_diff.address_to_class_hash { - let address = ContractAddress::try_from(address.0)?; - let address_assigned: bool = self - .reader() - .begin_ro_txn()? - .get_state_reader()? - .get_class_hash_at(state_number, &address)? - .is_some(); - - if address_assigned { - replaced_classes.insert(address, ClassHash(class_hash.0)); - } - } - let mut py_state_diff = py_state_diff; - replaced_classes.keys().for_each(|&address| { - py_state_diff.address_to_class_hash.remove(&address.into()); - }); - let mut declared_classes = IndexMap::::new(); let mut undeclared_casm_contracts = Vec::<(ClassHash, CasmContractClass)>::new(); @@ -204,7 +186,6 @@ impl Storage for PapyrusStorage { let mut state_diff = StateDiff::try_from(py_state_diff)?; state_diff.deprecated_declared_classes = deprecated_declared_classes; state_diff.declared_classes = declared_classes; - state_diff.replaced_classes = replaced_classes; let (thin_state_diff, declared_classes, deprecated_declared_classes) = ThinStateDiff::from_state_diff(state_diff); diff --git a/crates/papyrus_base_layer/Cargo.toml b/crates/papyrus_base_layer/Cargo.toml index 91092fa7d10..f81d1c108f2 100644 --- a/crates/papyrus_base_layer/Cargo.toml +++ b/crates/papyrus_base_layer/Cargo.toml @@ -9,22 +9,16 @@ license-file.workspace = true workspace = true [features] -testing = ["tar", "tempfile"] +testing = ["alloy/node-bindings", "colored", "tar", "tempfile"] [dependencies] -alloy-contract.workspace = true -alloy-dyn-abi.workspace = true -alloy-json-rpc.workspace = true -alloy-primitives.workspace = true -alloy-provider.workspace = true -alloy-sol-types.workspace = true -alloy-transport.workspace = true -alloy-transport-http.workspace = true +alloy = { workspace = true, features = ["contract", "json-rpc", "rpc-types"] } async-trait.workspace = true +colored = { workspace = true, optional = true } ethers.workspace = true +mockall.workspace = true papyrus_config.workspace = true serde.workspace = true -serde_json.workspace = true starknet-types-core.workspace = true starknet_api.workspace = true tar = { workspace = true, optional = true } @@ -32,10 +26,15 @@ tempfile = { workspace = true, optional = true } thiserror.workspace = true tokio = { workspace = true, features = ["full", "sync"] } url = { workspace = true, features = ["serde"] } +validator.workspace = true [dev-dependencies] +alloy = { workspace = true, features = ["node-bindings"] } +colored.workspace = true ethers-core.workspace = true -papyrus_base_layer = { workspace = true, features = ["testing"] } +mempool_test_utils.workspace = true pretty_assertions.workspace = true starknet-types-core.workspace = true starknet_api = { workspace = true, features = ["testing"] } +tar.workspace = true +tempfile.workspace = true diff --git a/crates/papyrus_base_layer/resources/Starknet-0.10.3.4.json b/crates/papyrus_base_layer/resources/Starknet-0.10.3.4.json new file mode 100644 index 00000000000..b54eadd25ba --- /dev/null +++ b/crates/papyrus_base_layer/resources/Starknet-0.10.3.4.json @@ -0,0 +1,831 @@ +{ + "contractName": "Starknet", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "fromAddress", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "toAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "payload", + "type": "uint256[]" + } + ], + "name": "ConsumedMessageToL1", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "fromAddress", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "toAddress", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "selector", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "payload", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + } + ], + "name": "ConsumedMessageToL2", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "Finalized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "fromAddress", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "toAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "payload", + "type": "uint256[]" + } + ], + "name": "LogMessageToL1", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "fromAddress", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "toAddress", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "selector", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "payload", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "fee", + "type": "uint256" + } + ], + "name": "LogMessageToL2", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "acceptedGovernor", + "type": "address" + } + ], + "name": "LogNewGovernorAccepted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "nominatedGovernor", + "type": "address" + } + ], + "name": "LogNominatedGovernor", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "LogNominationCancelled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "LogOperatorAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "LogOperatorRemoved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "removedGovernor", + "type": "address" + } + ], + "name": "LogRemovedGovernor", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes32", + "name": "stateTransitionFact", + "type": "bytes32" + } + ], + "name": "LogStateTransitionFact", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "globalRoot", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "int256", + "name": "blockNumber", + "type": "int256" + } + ], + "name": "LogStateUpdate", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "fromAddress", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "toAddress", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "selector", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "payload", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + } + ], + "name": "MessageToL2Canceled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "fromAddress", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "toAddress", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "selector", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "payload", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + } + ], + "name": "MessageToL2CancellationStarted", + "type": "event" + }, + { + "inputs": [], + "name": "MAX_L1_MSG_FEE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "toAddress", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "selector", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "payload", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + } + ], + "name": "cancelL1ToL2Message", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "configHash", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "fromAddress", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "payload", + "type": "uint256[]" + } + ], + "name": "consumeMessageFromL2", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "identify", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "isFinalized", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isFrozen", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "user", + "type": "address" + } + ], + "name": "isOperator", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "msgHash", + "type": "bytes32" + } + ], + "name": "l1ToL2MessageCancellations", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "l1ToL2MessageNonce", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "msgHash", + "type": "bytes32" + } + ], + "name": "l1ToL2Messages", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "msgHash", + "type": "bytes32" + } + ], + "name": "l2ToL1Messages", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "messageCancellationDelay", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "programHash", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOperator", + "type": "address" + } + ], + "name": "registerOperator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "toAddress", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "selector", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "payload", + "type": "uint256[]" + } + ], + "name": "sendMessageToL2", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newConfigHash", + "type": "uint256" + } + ], + "name": "setConfigHash", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "delayInSeconds", + "type": "uint256" + } + ], + "name": "setMessageCancellationDelay", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newProgramHash", + "type": "uint256" + } + ], + "name": "setProgramHash", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "starknetAcceptGovernance", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "starknetCancelNomination", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "user", + "type": "address" + } + ], + "name": "starknetIsGovernor", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newGovernor", + "type": "address" + } + ], + "name": "starknetNominateNewGovernor", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "governorForRemoval", + "type": "address" + } + ], + "name": "starknetRemoveGovernor", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "toAddress", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "selector", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "payload", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + } + ], + "name": "startL1ToL2MessageCancellation", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "stateBlockNumber", + "outputs": [ + { + "internalType": "int256", + "name": "", + "type": "int256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "stateBlockHash", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "stateRoot", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "removedOperator", + "type": "address" + } + ], + "name": "unregisterOperator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "programOutput", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "onchainDataHash", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "onchainDataSize", + "type": "uint256" + } + ], + "name": "updateState", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x60a060405234801561001057600080fd5b5030606081901b608052612d73610031600039806108a35250612d736000f3fe6080604052600436106101d85760003560e01c80637cbe06d11161010257806396115bc211610095578063e1f1176d11610064578063e1f1176d146104f5578063e37fec251461050a578063e87e73321461051f578063eeb728661461053f576101d8565b806396115bc2146104755780639be446bf14610495578063a46efaf3146104b5578063c99d397f146104d5576101d8565b80638d4e4083116100d15780638d4e40831461041657806391a66a261461042b578063946be3ed1461044b5780639588eca214610460576101d8565b80637cbe06d1146103b75780638303bd8a146103cc57806384f921cd146103e15780638a9bf09014610401576101d8565b80633e3aa6c51161017a5780636d70f7ae116101495780636d70f7ae14610337578063775526411461035757806377c7d7a9146103775780637a98660b14610397576101d8565b80633e3aa6c5146102c1578063439fab91146102e25780634bb278f3146103025780636170ff1b14610317576101d8565b806333eeb147116101b657806333eeb1471461025557806335befa5d1461026a5780633682a4501461027f5780633d07b336146102a1576101d8565b8063018cccdf146101dd57806301a01590146102085780632c9dd5c014610235575b600080fd5b3480156101e957600080fd5b506101f2610561565b6040516101ff9190612439565b60405180910390f35b34801561021457600080fd5b50610228610223366004611fd7565b6105a6565b6040516101ff919061242e565b34801561024157600080fd5b506101f261025036600461216f565b6105b7565b34801561026157600080fd5b5061022861069a565b34801561027657600080fd5b506101f261069f565b34801561028b57600080fd5b5061029f61029a366004611fd7565b6106b2565b005b3480156102ad57600080fd5b5061029f6102bc366004612069565b610753565b6102d46102cf3660046121b9565b6107a6565b6040516101ff929190612442565b3480156102ee57600080fd5b5061029f6102fd366004612081565b6108a1565b34801561030e57600080fd5b5061029f6109e9565b34801561032357600080fd5b506101f261033236600461220a565b610a81565b34801561034357600080fd5b50610228610352366004611fd7565b610bc3565b34801561036357600080fd5b5061029f610372366004611ffa565b610bf0565b34801561038357600080fd5b506101f2610392366004612069565b610e4a565b3480156103a357600080fd5b506101f26103b236600461220a565b610e65565b3480156103c357600080fd5b506101f2610f1c565b3480156103d857600080fd5b506101f2610f28565b3480156103ed57600080fd5b5061029f6103fc366004611fd7565b610f4b565b34801561040d57600080fd5b506101f2610f54565b34801561042257600080fd5b50610228610f77565b34801561043757600080fd5b5061029f610446366004611fd7565b610f9a565b34801561045757600080fd5b5061029f610fa3565b34801561046c57600080fd5b506101f2610fad565b34801561048157600080fd5b5061029f610490366004611fd7565b610fbd565b3480156104a157600080fd5b506101f26104b0366004612069565b611053565b3480156104c157600080fd5b506101f26104d0366004612069565b61105d565b3480156104e157600080fd5b5061029f6104f0366004612069565b611067565b34801561050157600080fd5b506101f26110ba565b34801561051657600080fd5b5061029f6110dd565b34801561052b57600080fd5b5061029f61053a366004612069565b6110e5565b34801561054b57600080fd5b50610554611138565b6040516101ff919061247f565b60006105a16040518060400160405280602081526020017f535441524b4e45545f312e305f4d5347494e475f4c31544f4c325f4e4f4e434581525061116f565b905090565b60006105b1826111a3565b92915050565b60405160009081906105d59086903390869088908290602001612311565b60405160208183030381529060405280519060200120905060006105f76111d2565b600083815260209190915260409020541161062d5760405162461bcd60e51b8152600401610624906129ca565b60405180910390fd5b336001600160a01b0316857f7a06c571aa77f34d9706c51e5d8122b5595aebeaa34233bfe866f22befb973b18686604051610669929190612387565b60405180910390a3600161067b6111d2565b6000838152602091909152604090208054919091039055949350505050565b600090565b60006106a96111f5565b60010154905090565b6106bb336111a3565b6106d75760405162461bcd60e51b8152600401610624906128e1565b6106e081610bc3565b6107505760016106ee61123f565b6001600160a01b0383166000908152602091909152604090819020805460ff191692151592909217909155517f50a18c352ee1c02ffe058e15c2eb6e58be387c81e73cc1e17035286e54c19a5790610747908390612373565b60405180910390a15b50565b61075b610f77565b156107785760405162461bcd60e51b8152600401610624906128be565b610781336111a3565b61079d5760405162461bcd60e51b8152600401610624906128e1565b61075081611262565b600080670de0b6b3a76400003411156107d15760405162461bcd60e51b81526004016106249061268c565b60006107db610561565b905061081f6040518060400160405280602081526020017f535441524b4e45545f312e305f4d5347494e475f4c31544f4c325f4e4f4e434581525082600101611280565b8587336001600160a01b03167fdb80dd488acf86d17c747445b0eabb5d57c541d3bd7b6b87af987858e5066b2b8888863460405161086094939291906123bf565b60405180910390a4600061087788888888866112b3565b9050346001016108856112f4565b6000838152602091909152604090205597909650945050505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163014156108ea5760405162461bcd60e51b815260040161062490612721565b60006108f461069a565b6020908102915081018083101561091d5760405162461bcd60e51b815260040161062490612966565b600061092b82848688612b44565b8101906109389190611fd7565b90503660006109498582888a612b44565b9150915061095782826109e5565b3660006109668887818c612b44565b90925090506001600160a01b0385161561099157610985858383611317565b505050505050506109e5565b61099961143c565b156109c15780156109bc5760405162461bcd60e51b8152600401610624906126c3565b6109dd565b6109cb828261144d565b6109d582826114ad565b6109dd611507565b505050505050505b5050565b6109f2336111a3565b610a0e5760405162461bcd60e51b8152600401610624906128e1565b610a16610f77565b15610a335760405162461bcd60e51b8152600401610624906128be565b610a56604051806060016040528060318152602001612d0d603191396001611280565b6040517f6823b073d48d6e3a7d385eeb601452d680e74bb46afe3255a7d778f3a9b1768190600090a1565b60008486336001600160a01b03167f8abd2ec2e0a10c82f5b60ea00455fa96c41fd144f225fcc52b8d83d94f803ed8878787604051610ac29392919061239b565b60405180910390a46000610ad987878787876112b3565b90506000610ae56112f4565b60008381526020919091526040902054905080610b145760405162461bcd60e51b815260040161062490612822565b6000610b1e61155e565b60008481526020919091526040902054905080610b4d5760405162461bcd60e51b815260040161062490612ad7565b6000610b57610f28565b8201905081811015610b7b5760405162461bcd60e51b8152600401610624906125ec565b80421015610b9b5760405162461bcd60e51b815260040161062490612623565b6000610ba56112f4565b60008681526020919091526040902055509198975050505050505050565b6000610bcd61123f565b6001600160a01b0392909216600090815260209290925250604090205460ff1690565b610bf933610bc3565b610c155760405162461bcd60e51b815260040161062490612a2e565b610c1f8484611581565b83836003818110610c2c57fe5b90506020020135610c3b6110ba565b14610c585760405162461bcd60e51b815260040161062490612592565b6000610c7985856040518060400160405280878152602001868152506115a1565b90506000610c85610f54565b82604051602001610c97929190612442565b604051602081830303815290604052805190602001209050610cb761161c565b6001600160a01b0316636a938567826040518263ffffffff1660e01b8152600401610ce29190612439565b60206040518083038186803b158015610cfa57600080fd5b505afa158015610d0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d329190612049565b610d4e5760405162461bcd60e51b81526004016106249061290a565b7f9866f8ddfe70bb512b2f2b28b49d4017c43f7ba775f1a20c61c13eea8cdac11182604051610d7d9190612439565b60405180910390a16004610da56001610d988884818c612b19565b610da06111d2565b61163f565b01610dbf6000610db78884818c612b19565b610da06112f4565b01858114610ddf5760405162461bcd60e51b8152600401610624906127eb565b610df38787610dec6111f5565b9190611a34565b6000610dfd6111f5565b90507fe8012213bb931d3efa0a954cfb0d7b75f2a5e2358ba5f7d3edfb0154f6e7a56881600001548260010154604051610e38929190612442565b60405180910390a15050505050505050565b6000610e546112f4565b600092835260205250604090205490565b60008486336001600160a01b03167f2e00dccd686fd6823ec7dc3e125582aa82881b6ff5f6b5a73856e1ea8338a3be878787604051610ea69392919061239b565b60405180910390a46000610ebd87878787876112b3565b90506000610ec96112f4565b60008381526020919091526040902054905080610ef85760405162461bcd60e51b815260040161062490612822565b42610f0161155e565b60008481526020919091526040902055509695505050505050565b670de0b6b3a764000081565b60006105a16040518060600160405280602d8152602001612c76602d913961116f565b61075081611ac3565b60006105a1604051806060016040528060238152602001612c536023913961116f565b60006105a1604051806060016040528060318152602001612d0d6031913961116f565b61075081611b9e565b610fab611c93565b565b6000610fb76111f5565b54905090565b610fc6336111a3565b610fe25760405162461bcd60e51b8152600401610624906128e1565b610feb81610bc3565b15610750576000610ffa61123f565b6001600160a01b0383166000908152602091909152604090819020805460ff191692151592909217909155517fec5f6c3a91a1efb1f9a308bb33c6e9e66bf9090fad0732f127dfdbf516d0625d90610747908390612373565b6000610e5461155e565b6000610e546111d2565b61106f610f77565b1561108c5760405162461bcd60e51b8152600401610624906128be565b611095336111a3565b6110b15760405162461bcd60e51b8152600401610624906128e1565b61075081611cf6565b60006105a1604051806060016040528060218152602001612ca36021913961116f565b610fab611d18565b6110ed610f77565b1561110a5760405162461bcd60e51b8152600401610624906128be565b611113336111a3565b61112f5760405162461bcd60e51b8152600401610624906128e1565b61075081611d9b565b60408051808201909152601981527f537461726b576172655f537461726b6e65745f323032325f3400000000000000602082015290565b6000808260405160200161118391906122f2565b60408051601f198184030181529190528051602090910120549392505050565b6000806111ae611dbd565b6001600160a01b039390931660009081526020939093525050604090205460ff1690565b60006105a1604051806060016040528060238152602001612cc460239139611e06565b600080604051806060016040528060278152602001612c2c6027913960405160200161122191906122f2565b60408051601f19818403018152919052805160209091012092915050565b60006105a1604051806060016040528060288152602001612bd460289139611e06565b610750604051806060016040528060218152602001612ca360219139825b60008260405160200161129391906122f2565b604051602081830303815290604052805190602001209050818155505050565b6040516000906112d390339088908590899088908a90829060200161233b565b60405160208183030381529060405280519060200120905095945050505050565b60006105a1604051806060016040528060268152602001612ce760269139611e06565b611329836001600160a01b0316611e39565b6113455760405162461bcd60e51b8152600401610624906124b2565b60006060846001600160a01b031663439fab9160e01b858560405160240161136e929190612450565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516113ac91906122f2565b600060405180830381855af49150503d80600081146113e7576040519150601f19603f3d011682016040523d82523d6000602084013e6113ec565b606091505b50915091508181906114115760405162461bcd60e51b8152600401610624919061247f565b5080518190156114345760405162461bcd60e51b8152600401610624919061247f565b505050505050565b6000611446610f54565b1515905090565b60a0811461146d5760405162461bcd60e51b815260040161062490612509565b600061147c6020828486612b44565b8101906114899190612069565b9050806114a85760405162461bcd60e51b815260040161062490612788565b505050565b60008060006114ba611f7b565b6114c6858701876120ee565b93509350935093506114d784611d9b565b6114e083611e3f565b6114f2816114ec6111f5565b90611e61565b6114fb82611262565b61143462069780611cf6565b6000611511611dbd565b6001810154909150600160a01b900460ff16156115405760405162461bcd60e51b8152600401610624906125bf565b60018101805460ff60a01b1916600160a01b17905561075033611e71565b60006105a1604051806060016040528060308152602001612bfc60309139611e06565b600481116109e55760405162461bcd60e51b815260040161062490612850565b604051600090839082906115bb90879084906020016122c2565b604051602081830303815290604052805190602001209050600081838660000151876020015186016040516020016115f694939291906122d7565b60408051808303601f190181529190528051602090910120600101979650505050505050565b60006105a1604051806060016040528060228152602001612bb26022913961116f565b6000808484600081811061164f57fe5b9050602002013590506340000000811061167b5760405162461bcd60e51b8152600401610624906127b4565b600181810160008861168e576004611691565b60025b905060005b82841015611983578382018881106116c05760405162461bcd60e51b8152600401610624906124de565b60008a8a838181106116ce57fe5b905060200201359050634000000081106116fa5760405162461bcd60e51b8152600401610624906126f1565b8181016001018a8111156117205760405162461bcd60e51b815260040161062490612887565b8c156117fe5760008c8c8990849261173a93929190612b19565b60405160200161174b9291906122c2565b6040516020818303038152906040528051906020012090508c8c60018a0181811061177257fe5b905060200201356001600160a01b03168d8d60008b0181811061179157fe5b905060200201357f4264ac208b5fde633ccdd42e0f12c3d6d443a4f3779bbf886925b94665b63a228f8f60038d019087926117ce93929190612b19565b6040516117dc929190612387565b60405180910390a3600090815260208b90526040902080546001019055611979565b60008c8c8990849261181293929190612b19565b6040516020016118239291906122c2565b60408051601f1981840301815291815281516020928301206000818152928e9052912054909150806118675760405162461bcd60e51b8152600401610624906129ca565b600091825260208c9052604082208290559490940160001901938c8c60028a0181811061189057fe5b90506020020135905060608d8d60058b019085926118b093929190612b19565b80806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f8201169050808301925050505050505090508d8d60038b0181811061190157fe5b905060200201358e8e60018c0181811061191757fe5b905060200201358f8f60008d0181811061192d57fe5b905060200201356001600160a01b03167f9592d37825c744e33fa80c469683bbd04d336241bb600b574758efd182abe26a848660405161196e9291906123e6565b60405180910390a450505b9550611696915050565b8284146119a25760405162461bcd60e51b8152600401610624906127b4565b8015611a26576000336001600160a01b0316826040516119c19061230e565b60006040518083038185875af1925050503d80600081146119fe576040519150601f19603f3d011682016040523d82523d6000602084013e611a03565b606091505b5050905080611a245760405162461bcd60e51b815260040161062490612a01565b505b509198975050505050505050565b60018381018054909101905581816002818110611a4d57fe5b90506020020135836001015414611a765760405162461bcd60e51b815260040161062490612a55565b366000611a838484611ef7565b91509150611a918282611f13565b855414611ab05760405162461bcd60e51b815260040161062490612563565b611aba8282611f31565b90945550505050565b611acc336111a3565b611ae85760405162461bcd60e51b8152600401610624906128e1565b336001600160a01b0382161415611b115760405162461bcd60e51b815260040161062490612a83565b6000611b1b611dbd565b9050611b26826111a3565b611b425760405162461bcd60e51b815260040161062490612ab1565b6001600160a01b03821660009081526020829052604090819020805460ff19169055517fd75f94825e770b8b512be8e74759e252ad00e102e38f50cce2f7c6f868a2959990611b92908490612373565b60405180910390a15050565b611ba7336111a3565b611bc35760405162461bcd60e51b8152600401610624906128e1565b6000611bcd611dbd565b90506001600160a01b038216611bf55760405162461bcd60e51b815260040161062490612941565b611bfe826111a3565b15611c1b5760405162461bcd60e51b815260040161062490612539565b60018101546001600160a01b031615611c465760405162461bcd60e51b815260040161062490612993565b6001810180546001600160a01b0319166001600160a01b0384161790556040517f6166272c8d3f5f579082f2827532732f97195007983bb5b83ac12c56700b01a690611b92908490612373565b6000611c9d611dbd565b60018101549091506001600160a01b03163314611ccc5760405162461bcd60e51b815260040161062490612751565b6001810154611ce3906001600160a01b0316611e71565b60010180546001600160a01b0319169055565b6107506040518060600160405280602d8152602001612c76602d913982611280565b611d21336111a3565b611d3d5760405162461bcd60e51b8152600401610624906128e1565b6000611d47611dbd565b60018101549091506001600160a01b031615610750576001810180546001600160a01b03191690556040517f7a8dc7dd7fffb43c4807438fa62729225156941e641fd877938f4edade3429f590600090a150565b610750604051806060016040528060238152602001612c536023913982611280565b6000806040518060400160405280601c81526020017f535441524b4e45545f312e305f474f5645524e414e43455f494e464f0000000081525060405160200161122191906122f2565b60008082604051602001611e1a91906122f2565b60408051601f1981840301815291905280516020909101209392505050565b3b151590565b610750604051806060016040528060228152602001612bb26022913982611f40565b8051825560200151600190910155565b611e7a816111a3565b15611e975760405162461bcd60e51b815260040161062490612539565b6000611ea1611dbd565b6001600160a01b03831660009081526020829052604090819020805460ff19166001179055519091507fcfb473e6c03f9a29ddaf990e736fa3de5188a0bd85d684f5b6e164ebfbfff5d290611b92908490612373565b366000611f076002828587612b19565b915091505b9250929050565b600082826000818110611f2257fe5b90506020020135905092915050565b600082826001818110611f2257fe5b6000611f4b8361116f565b6001600160a01b031614611f715760405162461bcd60e51b815260040161062490612667565b6109e58282611280565b604051806040016040528060008152602001600081525090565b60008083601f840112611fa6578182fd5b50813567ffffffffffffffff811115611fbd578182fd5b6020830191508360208083028501011115611f0c57600080fd5b600060208284031215611fe8578081fd5b8135611ff381612b9c565b9392505050565b6000806000806060858703121561200f578283fd5b843567ffffffffffffffff811115612025578384fd5b61203187828801611f95565b90989097506020870135966040013595509350505050565b60006020828403121561205a578081fd5b81518015158114611ff3578182fd5b60006020828403121561207a578081fd5b5035919050565b60008060208385031215612093578182fd5b823567ffffffffffffffff808211156120aa578384fd5b818501915085601f8301126120bd578384fd5b8135818111156120cb578485fd5b8660208285010111156120dc578485fd5b60209290920196919550909350505050565b60008060008084860360a0811215612104578485fd5b85359450602086013561211681612b9c565b93506040868101359350605f198201121561212f578182fd5b506040516040810181811067ffffffffffffffff8211171561214f578283fd5b604052606086013581526080909501356020860152509194909350909190565b600080600060408486031215612183578283fd5b83359250602084013567ffffffffffffffff8111156121a0578283fd5b6121ac86828701611f95565b9497909650939450505050565b600080600080606085870312156121ce578384fd5b8435935060208501359250604085013567ffffffffffffffff8111156121f2578283fd5b6121fe87828801611f95565b95989497509550505050565b600080600080600060808688031215612221578081fd5b8535945060208601359350604086013567ffffffffffffffff811115612245578182fd5b61225188828901611f95565b96999598509660600135949350505050565b81835260006001600160fb1b0383111561227b578081fd5b6020830280836020870137939093016020019283525090919050565b60006001600160fb1b038311156122ac578081fd5b6020830280838637939093019283525090919050565b60006122cf828486612297565b949350505050565b93845260208401929092526040830152606082015260800190565b60008251612304818460208701612b6c565b9190910192915050565b90565b6000868252856020830152846040830152612330606083018486612297565b979650505050505050565b600088825287602083015286604083015285606083015284608083015261236660a083018486612297565b9998505050505050505050565b6001600160a01b0391909116815260200190565b6000602082526122cf602083018486612263565b6000604082526123af604083018587612263565b9050826020830152949350505050565b6000606082526123d3606083018688612263565b6020830194909452506040015292915050565b604080825283519082018190526000906020906060840190828701845b8281101561241f57815184529284019290840190600101612403565b50505092019290925292915050565b901515815260200190565b90815260200190565b918252602082015260400190565b60006020825282602083015282846040840137818301604090810191909152601f909201601f19160101919050565b600060208252825180602084015261249e816040850160208701612b6c565b601f01601f19169190910160400192915050565b602080825260129082015271115250d7d393d517d057d0d3d395149050d560721b604082015260600190565b602080825260119082015270135154d4d051d157d513d3d7d4d213d495607a1b604082015260600190565b602080825260169082015275494c4c4547414c5f494e49545f444154415f53495a4560501b604082015260600190565b60208082526010908201526f20a62922a0a22cafa3a7ab22a92727a960811b604082015260600190565b6020808252601590820152741253959053125117d41491559253d554d7d493d3d5605a1b604082015260600190565b6020808252601390820152720929cac82989288be869e9c8c928ebe9082a69606b1b604082015260600190565b6020808252601390820152721053149150511657d253925512505312569151606a1b604082015260600190565b6020808252601c908201527f43414e43454c5f414c4c4f5745445f54494d455f4f564552464c4f5700000000604082015260600190565b60208082526024908201527f4d4553534147455f43414e43454c4c4154494f4e5f4e4f545f414c4c4f57454460408201526317d6515560e21b606082015260800190565b6020808252600b908201526a1053149150511657d4d15560aa1b604082015260600190565b60208082526017908201527f4d41585f4c315f4d53475f4645455f4558434545444544000000000000000000604082015260600190565b602080825260149082015273554e45585045435445445f494e49545f4441544160601b604082015260600190565b6020808252601690820152750929cac82989288bea082b2989e8288be988a9c8ea8960531b604082015260600190565b6020808252601690820152751112549150d517d0d0531317d11254d0531313d5d15160521b604082015260600190565b60208082526017908201527f4f4e4c595f43414e4449444154455f474f5645524e4f52000000000000000000604082015260600190565b6020808252601290820152712120a22fa4a724aa24a0a624ad20aa24a7a760711b604082015260600190565b6020808252601c908201527f494e56414c49445f4d4553534147455f5345474d454e545f53495a4500000000604082015260600190565b60208082526018908201527f535441524b4e45545f4f55545055545f544f4f5f4c4f4e470000000000000000604082015260600190565b6020808252601490820152731393d7d35154d4d051d157d513d7d0d05390d15360621b604082015260600190565b60208082526019908201527f535441524b4e45545f4f55545055545f544f4f5f53484f525400000000000000604082015260600190565b60208082526019908201527f5452554e43415445445f4d4553534147455f5041594c4f414400000000000000604082015260600190565b60208082526009908201526811925390531256915160ba1b604082015260600190565b6020808252600f908201526e4f4e4c595f474f5645524e414e434560881b604082015260600190565b60208082526019908201527f4e4f5f53544154455f5452414e534954494f4e5f50524f4f4600000000000000604082015260600190565b6020808252600b908201526a4241445f4144445245535360a81b604082015260600190565b6020808252601390820152721253925517d110551057d513d3d7d4d3505313606a1b604082015260600190565b60208082526017908201527f4f544845525f43414e4449444154455f50454e44494e47000000000000000000604082015260600190565b6020808252601a908201527f494e56414c49445f4d4553534147455f544f5f434f4e53554d45000000000000604082015260600190565b60208082526013908201527211551217d514905394d1915497d19052531151606a1b604082015260600190565b6020808252600d908201526c27a7262cafa7a822a920aa27a960991b604082015260600190565b60208082526014908201527324a72b20a624a22fa12627a1a5afa72aa6a122a960611b604082015260600190565b602080825260149082015273474f5645524e4f525f53454c465f52454d4f564560601b604082015260600190565b6020808252600c908201526b2727aa2fa3a7ab22a92727a960a11b604082015260600190565b60208082526022908201527f4d4553534147455f43414e43454c4c4154494f4e5f4e4f545f52455155455354604082015261115160f21b606082015260800190565b60008085851115612b28578182fd5b83861115612b34578182fd5b5050602083020193919092039150565b60008085851115612b53578081fd5b83861115612b5f578081fd5b5050820193919092039150565b60005b83811015612b87578181015183820152602001612b6f565b83811115612b96576000848401525b50505050565b6001600160a01b038116811461075057600080fdfe535441524b4e45545f312e305f494e49545f56455249464945525f41444452455353535441524b4e45545f312e305f524f4c45535f4f50455241544f52535f4d415050494e475f544147535441524b4e45545f312e305f4d5347494e475f4c31544f4c325f43414e43454c4c4154494f4e5f4d41505050494e47535441524b4e45545f312e305f494e49545f535441524b4e45545f53544154455f535452554354535441524b4e45545f312e305f494e49545f50524f4752414d5f484153485f55494e54535441524b4e45545f312e305f4d5347494e475f4c31544f4c325f43414e43454c4c4154494f4e5f44454c4159535441524b4e45545f312e305f535441524b4e45545f434f4e4649475f48415348535441524b4e45545f312e305f4d5347494e475f4c32544f4c315f4d41505050494e47535441524b4e45545f312e305f4d5347494e475f4c31544f4c325f4d41505050494e475f5632535441524b574152455f434f4e5452414354535f474f564552454e45445f46494e414c495a41424c455f312e305f544147a26469706673582212206cf2519eeb6d67aa7134a4ec1c369a3dbef46e84d03bd45309766773ff074d1964736f6c634300060c0033" +} diff --git a/crates/papyrus_base_layer/src/base_layer_test.rs b/crates/papyrus_base_layer/src/base_layer_test.rs index b52d0538979..4ec957485ac 100644 --- a/crates/papyrus_base_layer/src/base_layer_test.rs +++ b/crates/papyrus_base_layer/src/base_layer_test.rs @@ -1,17 +1,16 @@ +use mempool_test_utils::in_ci; use pretty_assertions::assert_eq; -use starknet_api::block::{BlockHash, BlockNumber}; +use starknet_api::block::{BlockHash, BlockHashAndNumber, BlockNumber}; use starknet_api::felt; use crate::ethereum_base_layer_contract::{EthereumBaseLayerConfig, EthereumBaseLayerContract}; -use crate::test_utils::get_test_ethereum_node; +use crate::test_utils::{ + anvil_instance_from_config, + ethereum_base_layer_config_for_anvil, + get_test_ethereum_node, +}; use crate::BaseLayerContract; -// TODO: move to global test_utils crate and use everywhere instead of relying on the -// confusing `#[ignore]` api to mark slow tests. -fn in_ci() -> bool { - std::env::var("CI").is_ok() -} - #[tokio::test] // Note: the test requires ganache-cli installed, otherwise it is ignored. async fn latest_proved_block_ethereum() { @@ -20,17 +19,19 @@ async fn latest_proved_block_ethereum() { } let (node_handle, starknet_contract_address) = get_test_ethereum_node(); - let config = EthereumBaseLayerConfig { + let contract = EthereumBaseLayerContract::new(EthereumBaseLayerConfig { node_url: node_handle.0.endpoint().parse().unwrap(), starknet_contract_address, - }; - let contract = EthereumBaseLayerContract::new(config).unwrap(); + }); - let first_sn_state_update = (BlockNumber(100), BlockHash(felt!("0x100"))); - let second_sn_state_update = (BlockNumber(200), BlockHash(felt!("0x200"))); - let third_sn_state_update = (BlockNumber(300), BlockHash(felt!("0x300"))); + let first_sn_state_update = + BlockHashAndNumber { number: BlockNumber(100), hash: BlockHash(felt!("0x100")) }; + let second_sn_state_update = + BlockHashAndNumber { number: BlockNumber(200), hash: BlockHash(felt!("0x200")) }; + let third_sn_state_update = + BlockHashAndNumber { number: BlockNumber(300), hash: BlockHash(felt!("0x300")) }; - type Scenario = (u64, Option<(BlockNumber, BlockHash)>); + type Scenario = (u64, Option); let scenarios: Vec = vec![ (0, Some(third_sn_state_update)), (5, Some(third_sn_state_update)), @@ -43,3 +44,46 @@ async fn latest_proved_block_ethereum() { assert_eq!(latest_block, expected); } } + +#[tokio::test] +async fn get_proved_block_at_unknown_block_number() { + if !in_ci() { + return; + } + + let config = ethereum_base_layer_config_for_anvil(None); + let _anvil = anvil_instance_from_config(&config); + let contract = EthereumBaseLayerContract::new(config); + + assert!( + contract + .get_proved_block_at(123) + .await + .unwrap_err() + // This error is nested way too deep inside `alloy`. + .to_string() + .contains("BlockOutOfRangeError") + ); +} + +#[tokio::test] +async fn get_gas_price_and_timestamps() { + if !in_ci() { + return; + } + + let (node_handle, starknet_contract_address) = get_test_ethereum_node(); + let contract = EthereumBaseLayerContract::new(EthereumBaseLayerConfig { + node_url: node_handle.0.endpoint().parse().unwrap(), + starknet_contract_address, + }); + + let block_number = 30; + let price_sample = contract.get_price_sample(block_number).await.unwrap().unwrap(); + + // TODO(guyn): Figure out how these numbers are calculated, instead of just printing and testing + // against what we got. + assert_eq!(price_sample.timestamp, 1676992456); + assert_eq!(price_sample.base_fee_per_gas, 20168195); + assert_eq!(price_sample.blob_fee, 0); +} diff --git a/crates/papyrus_base_layer/src/constants.rs b/crates/papyrus_base_layer/src/constants.rs new file mode 100644 index 00000000000..f3551406bbe --- /dev/null +++ b/crates/papyrus_base_layer/src/constants.rs @@ -0,0 +1,11 @@ +use alloy::sol_types::SolEvent; + +use crate::ethereum_base_layer_contract::Starknet; + +pub type EventIdentifier = &'static str; + +pub const LOG_MESSAGE_TO_L2_EVENT_IDENTIFIER: &str = Starknet::LogMessageToL2::SIGNATURE; +pub const CONSUMED_MESSAGE_TO_L1_EVENT_IDENTIFIER: &str = Starknet::ConsumedMessageToL1::SIGNATURE; +pub const MESSAGE_TO_L2_CANCELLATION_STARTED_EVENT_IDENTIFIER: &str = + Starknet::MessageToL2CancellationStarted::SIGNATURE; +pub const MESSAGE_TO_L2_CANCELED_EVENT_IDENTIFIER: &str = Starknet::MessageToL2Canceled::SIGNATURE; diff --git a/crates/papyrus_base_layer/src/core_contract_latest_block.abi b/crates/papyrus_base_layer/src/core_contract_latest_block.abi deleted file mode 100644 index e8c65974990..00000000000 --- a/crates/papyrus_base_layer/src/core_contract_latest_block.abi +++ /dev/null @@ -1,28 +0,0 @@ -[ - { - "inputs": [], - "name": "stateBlockNumber", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "stateBlockHash", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/crates/papyrus_base_layer/src/eth_events.rs b/crates/papyrus_base_layer/src/eth_events.rs new file mode 100644 index 00000000000..916b574732f --- /dev/null +++ b/crates/papyrus_base_layer/src/eth_events.rs @@ -0,0 +1,138 @@ +use std::sync::Arc; + +use alloy::primitives::{Address as EthereumContractAddress, U256}; +use alloy::rpc::types::Log; +use alloy::sol_types::SolEventInterface; +use starknet_api::core::{EntryPointSelector, Nonce}; +use starknet_api::transaction::fields::{Calldata, Fee}; +use starknet_api::transaction::L1HandlerTransaction; +use starknet_types_core::felt::Felt; + +use crate::ethereum_base_layer_contract::{ + EthereumBaseLayerError, + EthereumBaseLayerResult, + Starknet, +}; +use crate::{EventData, L1Event}; + +impl TryFrom for L1Event { + type Error = EthereumBaseLayerError; + + fn try_from(log: Log) -> EthereumBaseLayerResult { + let validate = true; + let log = log.inner; + + let event = Starknet::StarknetEvents::decode_log(&log, validate)?.data; + match event { + Starknet::StarknetEvents::LogMessageToL2(event) => { + let fee = + Fee(event.fee.try_into().map_err(EthereumBaseLayerError::FeeOutOfRange)?); + let mut event_data = EventData::try_from(event)?; + let payload_inner = Arc::get_mut(&mut event_data.payload.0).expect( + "The event data is the only owner and was initialized in the previous line", + ); + // Prepend the L1 sender address to the calldata. + payload_inner.insert(0, event_data.from_address.into()); + + let tx = L1HandlerTransaction { + version: L1HandlerTransaction::VERSION, + contract_address: event_data.to_address, + entry_point_selector: event_data.entry_point_selector, + nonce: event_data.nonce, + calldata: event_data.payload, + }; + Ok(L1Event::LogMessageToL2 { tx, fee }) + } + Starknet::StarknetEvents::ConsumedMessageToL2(event) => { + Ok(L1Event::ConsumedMessageToL2(event.try_into()?)) + } + Starknet::StarknetEvents::MessageToL2Canceled(event) => { + Ok(L1Event::MessageToL2Canceled(event.try_into()?)) + } + Starknet::StarknetEvents::MessageToL2CancellationStarted(event) => { + Ok(L1Event::MessageToL2CancellationStarted(event.try_into()?)) + } + _ => Err(EthereumBaseLayerError::UnhandledL1Event(log)), + } + } +} + +impl TryFrom for EventData { + type Error = EthereumBaseLayerError; + + fn try_from(event: Starknet::MessageToL2Canceled) -> EthereumBaseLayerResult { + create_l1_event_data( + event.fromAddress, + event.toAddress, + event.selector, + &event.payload, + event.nonce, + ) + } +} + +impl TryFrom for EventData { + type Error = EthereumBaseLayerError; + + fn try_from(event: Starknet::MessageToL2CancellationStarted) -> EthereumBaseLayerResult { + create_l1_event_data( + event.fromAddress, + event.toAddress, + event.selector, + &event.payload, + event.nonce, + ) + } +} + +impl TryFrom for EventData { + type Error = EthereumBaseLayerError; + + fn try_from(decoded: Starknet::LogMessageToL2) -> EthereumBaseLayerResult { + create_l1_event_data( + decoded.fromAddress, + decoded.toAddress, + decoded.selector, + &decoded.payload, + decoded.nonce, + ) + } +} + +impl TryFrom for EventData { + type Error = EthereumBaseLayerError; + + fn try_from(event: Starknet::ConsumedMessageToL2) -> EthereumBaseLayerResult { + create_l1_event_data( + event.fromAddress, + event.toAddress, + event.selector, + &event.payload, + event.nonce, + ) + } +} + +pub fn create_l1_event_data( + from_address: EthereumContractAddress, + to_address: U256, + selector: U256, + payload: &[U256], + nonce: U256, +) -> EthereumBaseLayerResult { + Ok(EventData { + from_address: Felt::from_bytes_be_slice(from_address.0.as_slice()) + .try_into() + .map_err(EthereumBaseLayerError::StarknetApiParsingError)?, + to_address: felt_from_u256(to_address) + .try_into() + .map_err(EthereumBaseLayerError::StarknetApiParsingError)?, + entry_point_selector: EntryPointSelector(felt_from_u256(selector)), + payload: Calldata(Arc::new(payload.iter().map(|&x| felt_from_u256(x)).collect())), + nonce: Nonce(felt_from_u256(nonce)), + }) +} + +pub fn felt_from_u256(num: U256) -> Felt { + Felt::from_bytes_be(&num.to_be_bytes()) +} diff --git a/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs b/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs index 3f9366065ec..81cabb55535 100644 --- a/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs +++ b/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs @@ -1,41 +1,187 @@ use std::collections::BTreeMap; use std::future::IntoFuture; +use std::ops::RangeInclusive; -use alloy_contract::{ContractInstance, Interface}; -use alloy_dyn_abi::SolType; -use alloy_json_rpc::RpcError; -pub(crate) use alloy_primitives::Address as EthereumContractAddress; -use alloy_provider::network::Ethereum; -use alloy_provider::{Provider, ProviderBuilder, RootProvider}; -use alloy_sol_types::sol_data; -use alloy_transport::TransportErrorKind; -use alloy_transport_http::{Client, Http}; +use alloy::dyn_abi::SolType; +use alloy::primitives::Address as EthereumContractAddress; +use alloy::providers::network::Ethereum; +use alloy::providers::{Provider, ProviderBuilder, RootProvider}; +use alloy::rpc::json_rpc::RpcError; +use alloy::rpc::types::eth::{ + BlockId, + BlockNumberOrTag, + BlockTransactionsKind, + Filter as EthEventFilter, +}; +use alloy::sol; +use alloy::sol_types::sol_data; +use alloy::transports::http::{Client, Http}; +use alloy::transports::TransportErrorKind; use async_trait::async_trait; -use papyrus_config::dumping::{ser_param, ser_required_param, SerializeConfig}; -use papyrus_config::{ParamPath, ParamPrivacyInput, SerializationType, SerializedParam}; +use papyrus_config::dumping::{ser_param, SerializeConfig}; +use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; use serde::{Deserialize, Serialize}; -use starknet_api::block::{BlockHash, BlockNumber}; +use starknet_api::block::{BlockHash, BlockHashAndNumber, BlockNumber}; use starknet_api::hash::StarkHash; -use starknet_types_core::felt; +use starknet_api::StarknetApiError; use url::Url; +use validator::Validate; -use crate::BaseLayerContract; +use crate::{BaseLayerContract, L1BlockNumber, L1BlockReference, L1Event, PriceSample}; + +pub type EthereumBaseLayerResult = Result; + +// Wraps the Starknet contract with a type that implements its interface, and is aware of its +// events. +sol!( + #[sol(rpc)] + Starknet, + "resources/Starknet-0.10.3.4.json" +); + +#[derive(Clone, Debug)] +pub struct EthereumBaseLayerContract { + pub config: EthereumBaseLayerConfig, + pub contract: Starknet::StarknetInstance, RootProvider>, Ethereum>, +} + +impl EthereumBaseLayerContract { + pub fn new(config: EthereumBaseLayerConfig) -> Self { + let l1_client = ProviderBuilder::new().on_http(config.node_url.clone()); + // This type is generated from `sol!` macro, and the `new` method assumes it is already + // deployed at L1, and wraps it with a type. + let contract = Starknet::new(config.starknet_contract_address, l1_client); + Self { contract, config } + } +} + +#[async_trait] +impl BaseLayerContract for EthereumBaseLayerContract { + type Error = EthereumBaseLayerError; + async fn get_proved_block_at( + &self, + l1_block: L1BlockNumber, + ) -> EthereumBaseLayerResult { + let block_id = l1_block.into(); + let call_state_block_number = self.contract.stateBlockNumber().block(block_id); + let call_state_block_hash = self.contract.stateBlockHash().block(block_id); + + let (state_block_number, state_block_hash) = tokio::try_join!( + call_state_block_number.call_raw().into_future(), + call_state_block_hash.call_raw().into_future() + )?; + + let validate = true; + let block_number = sol_data::Uint::<64>::abi_decode(&state_block_number, validate)?; + let block_hash = sol_data::FixedBytes::<32>::abi_decode(&state_block_hash, validate)?; + Ok(BlockHashAndNumber { + number: BlockNumber(block_number), + hash: BlockHash(StarkHash::from_bytes_be(&block_hash)), + }) + } + + /// Returns the latest proved block on Ethereum, where finality determines how many + /// blocks back (0 = latest). + async fn latest_proved_block( + &self, + finality: u64, + ) -> EthereumBaseLayerResult> { + let Some(ethereum_block_number) = self.latest_l1_block_number(finality).await? else { + return Ok(None); + }; + self.get_proved_block_at(ethereum_block_number).await.map(Some) + } + + async fn events<'a>( + &'a self, + block_range: RangeInclusive, + events: &'a [&'a str], + ) -> EthereumBaseLayerResult> { + let filter = EthEventFilter::new().select(block_range).events(events); + + let matching_logs = self.contract.provider().get_logs(&filter).await?; + matching_logs.into_iter().map(TryInto::try_into).collect() + } + + async fn latest_l1_block_number( + &self, + finality: u64, + ) -> EthereumBaseLayerResult> { + Ok(self.contract.provider().get_block_number().await?.checked_sub(finality)) + } + + async fn latest_l1_block( + &self, + finality: u64, + ) -> EthereumBaseLayerResult> { + let Some(block_number) = self.latest_l1_block_number(finality).await? else { + return Ok(None); + }; + + self.l1_block_at(block_number).await + } + + async fn l1_block_at( + &self, + block_number: L1BlockNumber, + ) -> EthereumBaseLayerResult> { + let only_block_header: BlockTransactionsKind = BlockTransactionsKind::default(); + let block = self + .contract + .provider() + .get_block(BlockId::Number(block_number.into()), only_block_header) + .await?; + + Ok(block.map(|block| L1BlockReference { + number: block.header.number, + hash: block.header.hash.0, + })) + } + + // Query the Ethereum base layer for the timestamp, gas price, and data gas price of a block. + async fn get_price_sample( + &self, + block_number: L1BlockNumber, + ) -> EthereumBaseLayerResult> { + let block = self + .contract + .provider() + .get_block( + BlockId::Number(BlockNumberOrTag::Number(block_number)), + BlockTransactionsKind::Hashes, + ) + .await?; + let Some(block) = block else { + return Ok(None); + }; + match (block.header.timestamp, block.header.base_fee_per_gas) { + (timestamp, Some(base_fee_per_gas)) => Ok(Some(PriceSample { + timestamp, + base_fee_per_gas: base_fee_per_gas.into(), + blob_fee: block.header.blob_fee().unwrap_or(0), + })), + _ => Ok(None), + } + } +} #[derive(thiserror::Error, Debug)] pub enum EthereumBaseLayerError { #[error(transparent)] - Contract(#[from] alloy_contract::Error), - #[error(transparent)] - FeltParseError(#[from] felt::FromStrError), + Contract(#[from] alloy::contract::Error), + #[error("{0}")] + FeeOutOfRange(alloy::primitives::ruint::FromUintError), #[error(transparent)] RpcError(#[from] RpcError), + #[error("{0}")] + StarknetApiParsingError(StarknetApiError), #[error(transparent)] - Serde(#[from] serde_json::Error), - #[error(transparent)] - TypeError(#[from] alloy_sol_types::Error), + TypeError(#[from] alloy::sol_types::Error), + #[error("{0:?}")] + UnhandledL1Event(alloy::primitives::Log), } -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] +#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, Validate)] pub struct EthereumBaseLayerConfig { pub node_url: Url, pub starknet_contract_address: EthereumContractAddress, @@ -44,9 +190,9 @@ pub struct EthereumBaseLayerConfig { impl SerializeConfig for EthereumBaseLayerConfig { fn dump(&self) -> BTreeMap { BTreeMap::from_iter([ - ser_required_param( + ser_param( "node_url", - SerializationType::String, + &self.node_url.to_string(), "Ethereum node URL. A schema to match to Infura node: https://mainnet.infura.io/v3/, but any other node can be used.", ParamPrivacyInput::Private, ), @@ -71,57 +217,3 @@ impl Default for EthereumBaseLayerConfig { } } } - -#[derive(Debug)] -pub struct EthereumBaseLayerContract { - contract: ContractInstance, RootProvider>, Ethereum>, -} - -impl EthereumBaseLayerContract { - pub fn new(config: EthereumBaseLayerConfig) -> Result { - let client = ProviderBuilder::new().on_http(config.node_url); - - // The solidity contract was pre-compiled, and only the relevant functions were kept. - let abi = serde_json::from_str(include_str!("core_contract_latest_block.abi"))?; - Ok(Self { - contract: ContractInstance::new( - config.starknet_contract_address, - client, - Interface::new(abi), - ), - }) - } -} - -#[async_trait] -impl BaseLayerContract for EthereumBaseLayerContract { - type Error = EthereumBaseLayerError; - - /// Returns the latest proved block on Ethereum, where finality determines how many - /// blocks back (0 = latest). - async fn latest_proved_block( - &self, - finality: u64, - ) -> Result, Self::Error> { - let ethereum_block_number = - self.contract.provider().get_block_number().await?.checked_sub(finality); - let Some(ethereum_block_number) = ethereum_block_number else { - return Ok(None); - }; - - let call_state_block_number = - self.contract.function("stateBlockNumber", &[])?.block(ethereum_block_number.into()); - let call_state_block_hash = - self.contract.function("stateBlockHash", &[])?.block(ethereum_block_number.into()); - - let (state_block_number, state_block_hash) = tokio::try_join!( - call_state_block_number.call_raw().into_future(), - call_state_block_hash.call_raw().into_future() - )?; - - Ok(Some(( - BlockNumber(sol_data::Uint::<64>::abi_decode(&state_block_number, true)?), - BlockHash(StarkHash::from_hex(&state_block_hash.to_string())?), - ))) - } -} diff --git a/crates/papyrus_base_layer/src/lib.rs b/crates/papyrus_base_layer/src/lib.rs index a3bc340cce7..f4052ac1f32 100644 --- a/crates/papyrus_base_layer/src/lib.rs +++ b/crates/papyrus_base_layer/src/lib.rs @@ -1,23 +1,110 @@ +use std::error::Error; +use std::fmt::{Debug, Display}; +use std::ops::RangeInclusive; + use async_trait::async_trait; -use starknet_api::block::{BlockHash, BlockNumber}; +#[cfg(any(feature = "testing", test))] +use mockall::automock; +use serde::{Deserialize, Serialize}; +use starknet_api::block::BlockHashAndNumber; +use starknet_api::core::{ContractAddress, EntryPointSelector, EthAddress, Nonce}; +use starknet_api::transaction::fields::{Calldata, Fee}; +use starknet_api::transaction::L1HandlerTransaction; +use thiserror::Error; +pub mod constants; pub mod ethereum_base_layer_contract; +pub(crate) mod eth_events; + #[cfg(any(feature = "testing", test))] pub mod test_utils; #[cfg(test)] mod base_layer_test; +pub type L1BlockNumber = u64; + +#[derive(Debug, Error)] +pub enum MockError {} + /// Interface for getting data from the Starknet base contract. +#[cfg_attr(any(feature = "testing", test), automock(type Error = MockError;))] #[async_trait] pub trait BaseLayerContract { - type Error; + type Error: Error + Display + Debug; + + /// Get the latest Starknet block that is proved on the base layer at a specific L1 block + /// number. If the number is too low, return an error. + async fn get_proved_block_at( + &self, + l1_block: L1BlockNumber, + ) -> Result; - /// Get the latest Starknet block that is proved on the base layer. - /// Optionally, require minimum confirmations. + /// Get the latest Starknet block that is proved on the base layer with minimum number of + /// confirmations (for no confirmations, pass `0`). async fn latest_proved_block( &self, finality: u64, - ) -> Result, Self::Error>; + ) -> Result, Self::Error>; + + async fn latest_l1_block_number( + &self, + finality: u64, + ) -> Result, Self::Error>; + + async fn latest_l1_block(&self, finality: u64) + -> Result, Self::Error>; + + async fn l1_block_at( + &self, + block_number: L1BlockNumber, + ) -> Result, Self::Error>; + + /// Get specific events from the Starknet base contract between two L1 block numbers. + async fn events<'a>( + &'a self, + block_range: RangeInclusive, + event_identifiers: &'a [&'a str], + ) -> Result, Self::Error>; + + async fn get_price_sample( + &self, + block_number: L1BlockNumber, + ) -> Result, Self::Error>; +} + +/// A struct that holds together the data on the base layer's gas prices, for a given timestamp. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct PriceSample { + pub timestamp: u64, + // Fee is stored as u128 for compatibility with any base layer. + pub base_fee_per_gas: u128, + pub blob_fee: u128, +} + +/// Reference to an L1 block, extend as needed. +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] +pub struct L1BlockReference { + pub number: L1BlockNumber, + pub hash: [u8; 32], +} + +/// Wraps Starknet L1 events with Starknet API types. +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub enum L1Event { + ConsumedMessageToL2(EventData), + LogMessageToL2 { tx: L1HandlerTransaction, fee: Fee }, + MessageToL2CancellationStarted(EventData), + MessageToL2Canceled(EventData), +} + +/// Shared fields in Starknet messaging. +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Default)] +pub struct EventData { + pub from_address: EthAddress, + pub to_address: ContractAddress, + pub entry_point_selector: EntryPointSelector, + pub payload: Calldata, + pub nonce: Nonce, } diff --git a/crates/papyrus_base_layer/src/test_utils.rs b/crates/papyrus_base_layer/src/test_utils.rs index 230578e1316..8264ecc9edb 100644 --- a/crates/papyrus_base_layer/src/test_utils.rs +++ b/crates/papyrus_base_layer/src/test_utils.rs @@ -1,15 +1,36 @@ use std::fs::File; use std::process::Command; -pub(crate) use alloy_primitives::Address as EthereumContractAddress; +use alloy::node_bindings::{Anvil, AnvilInstance, NodeError as AnvilError}; +pub(crate) use alloy::primitives::Address as EthereumContractAddress; +use alloy::providers::RootProvider; +use alloy::transports::http::{Client, Http}; +use colored::*; use ethers::utils::{Ganache, GanacheInstance}; use tar::Archive; use tempfile::{tempdir, TempDir}; +use url::Url; + +use crate::ethereum_base_layer_contract::{ + EthereumBaseLayerConfig, + EthereumBaseLayerContract, + Starknet, +}; type TestEthereumNodeHandle = (GanacheInstance, TempDir); const MINIMAL_GANACHE_VERSION: u8 = 7; +// See Anvil documentation: +// https://docs.rs/ethers-core/latest/ethers_core/utils/struct.Anvil.html#method.new. +const DEFAULT_ANVIL_PORT: u16 = 8545; +// This address is commonly used as the L1 address of the Starknet core contract. +pub const DEFAULT_ANVIL_L1_DEPLOYED_ADDRESS: &str = "0x5fbdb2315678afecb367f032d93f642f64180aa3"; + +/// An interface that plays the role of the starknet L1 contract. It is able to create messages to +/// L2 from this contract, which appear on the corresponding base layer. +pub type StarknetL1Contract = Starknet::StarknetInstance, RootProvider>>; + // Returns a Ganache instance, preset with a Starknet core contract and some state updates: // Starknet contract address: 0xe2aF2c1AE11fE13aFDb7598D0836398108a4db0A // Ethereum block number starknet block number starknet block hash @@ -18,9 +39,9 @@ const MINIMAL_GANACHE_VERSION: u8 = 7; // 30 300 0x300 // The blockchain is at Ethereum block number 31. // Note: Requires Ganache@7.4.3 installed. -// TODO: `Ganache` and `ethers` have both been deprecated. Also, `ethers`s' replacement, `alloy`, -// no longer supports `Ganache`. Once we decide on a Ganache replacement, fix this test and fully -// remove `ethers`. +// TODO(Gilad): `Ganache` and `ethers` have both been deprecated. Also, `ethers`s' replacement, +// `alloy`, no longer supports `Ganache`. Once we decide on a Ganache replacement, fix this test and +// fully remove `ethers`. pub fn get_test_ethereum_node() -> (TestEthereumNodeHandle, EthereumContractAddress) { const SN_CONTRACT_ADDR: &str = "0xe2aF2c1AE11fE13aFDb7598D0836398108a4db0A"; // Verify correct Ganache version. @@ -61,3 +82,57 @@ pub fn get_test_ethereum_node() -> (TestEthereumNodeHandle, EthereumContractAddr ((ganache, ganache_db), SN_CONTRACT_ADDR.to_string().parse().unwrap()) } + +// TODO(Arni): Make port non-optional. +// Spin up Anvil instance, a local Ethereum node, dies when dropped. +fn anvil(port: Option) -> AnvilInstance { + let mut anvil = Anvil::new(); + // If the port is not set explicitly, a random value will be used. + if let Some(port) = port { + anvil = anvil.port(port); + } + + anvil.try_spawn().unwrap_or_else(|error| match error { + AnvilError::SpawnError(e) if e.to_string().contains("No such file or directory") => { + panic!( + "\n{}\n{}\n", + "Anvil binary not found!".bold().red(), + "Install instructions (for local development):\n + cargo install --git \ + https://github.com/foundry-rs/foundry anvil --locked --tag=v0.3.0" + .yellow() + ) + } + _ => panic!("Failed to spawn Anvil: {}", error.to_string().red()), + }) +} + +pub fn ethereum_base_layer_config_for_anvil(port: Option) -> EthereumBaseLayerConfig { + // Use the specified port if provided; otherwise, default to Anvil's default port. + let non_optional_port = port.unwrap_or(DEFAULT_ANVIL_PORT); + let endpoint = format!("http://localhost:{}", non_optional_port); + EthereumBaseLayerConfig { + node_url: Url::parse(&endpoint).unwrap(), + starknet_contract_address: DEFAULT_ANVIL_L1_DEPLOYED_ADDRESS.parse().unwrap(), + } +} + +pub fn anvil_instance_from_config(config: &EthereumBaseLayerConfig) -> AnvilInstance { + let port = config.node_url.port(); + let anvil = anvil(port); + assert_eq!(config.node_url, anvil.endpoint_url(), "Unexpected config for Anvil instance."); + anvil +} + +pub async fn spawn_anvil_and_deploy_starknet_l1_contract( + config: &EthereumBaseLayerConfig, +) -> (AnvilInstance, StarknetL1Contract) { + let anvil = anvil_instance_from_config(config); + let starknet_l1_contract = deploy_starknet_l1_contract(config.clone()).await; + (anvil, starknet_l1_contract) +} + +pub async fn deploy_starknet_l1_contract(config: EthereumBaseLayerConfig) -> StarknetL1Contract { + let ethereum_base_layer_contract = EthereumBaseLayerContract::new(config); + Starknet::deploy(ethereum_base_layer_contract.contract.provider().clone()).await.unwrap() +} diff --git a/crates/papyrus_common/Cargo.toml b/crates/papyrus_common/Cargo.toml index f5105adc1b2..dc7ddbebe14 100644 --- a/crates/papyrus_common/Cargo.toml +++ b/crates/papyrus_common/Cargo.toml @@ -11,11 +11,9 @@ base64.workspace = true cairo-lang-starknet-classes.workspace = true flate2.workspace = true indexmap.workspace = true -lazy_static.workspace = true rand.workspace = true serde.workspace = true serde_json.workspace = true -sha3.workspace = true starknet-types-core = { workspace = true, features = ["hash"] } starknet_api.workspace = true thiserror.workspace = true diff --git a/crates/papyrus_common/src/class_hash.rs b/crates/papyrus_common/src/class_hash.rs deleted file mode 100644 index f464c2fc43a..00000000000 --- a/crates/papyrus_common/src/class_hash.rs +++ /dev/null @@ -1,63 +0,0 @@ -#[cfg(test)] -#[path = "class_hash_test.rs"] -mod class_hash_test; -use lazy_static::lazy_static; -use sha3::Digest; -use starknet_api::contract_class::EntryPointType; -use starknet_api::core::ClassHash; -use starknet_api::hash::PoseidonHash; -use starknet_api::state::SierraContractClass; -use starknet_types_core::felt::Felt; -use starknet_types_core::hash::{Poseidon, StarkHash}; - -use crate::usize_into_felt; - -lazy_static! { - static ref API_VERSION: Felt = Felt::from_bytes_be_slice(b"CONTRACT_CLASS_V0.1.0"); -} - -/// Calculates the hash of a contract class. -// Based on Pathfinder code (the starknet.io doc is incorrect). -pub fn calculate_class_hash(class: &SierraContractClass) -> ClassHash { - let external_entry_points_hash = entry_points_hash(class, &EntryPointType::External); - let l1_handler_entry_points_hash = entry_points_hash(class, &EntryPointType::L1Handler); - let constructor_entry_points_hash = entry_points_hash(class, &EntryPointType::Constructor); - let abi_keccak = sha3::Keccak256::default().chain_update(class.abi.as_bytes()).finalize(); - let abi_hash = truncated_keccak(abi_keccak.into()); - let program_hash = Poseidon::hash_array(class.sierra_program.as_slice()); - - let class_hash = Poseidon::hash_array(&[ - *API_VERSION, - external_entry_points_hash.0, - l1_handler_entry_points_hash.0, - constructor_entry_points_hash.0, - abi_hash, - program_hash, - ]); - // TODO: Modify ClassHash Be be PoseidonHash instead of StarkFelt. - ClassHash(class_hash) -} - -fn entry_points_hash( - class: &SierraContractClass, - entry_point_type: &EntryPointType, -) -> PoseidonHash { - PoseidonHash(Poseidon::hash_array( - class - .entry_points_by_type - .to_hash_map() - .get(entry_point_type) - .unwrap_or(&vec![]) - .iter() - .flat_map(|ep| [ep.selector.0, usize_into_felt(ep.function_idx.0)]) - .collect::>() - .as_slice(), - )) -} - -// Python code masks with (2**250 - 1) which starts 0x03 and is followed by 31 0xff in be. -// Truncation is needed not to overflow the field element. -fn truncated_keccak(mut plain: [u8; 32]) -> Felt { - plain[0] &= 0x03; - Felt::from_bytes_be(&plain) -} diff --git a/crates/papyrus_common/src/class_hash_test.rs b/crates/papyrus_common/src/class_hash_test.rs deleted file mode 100644 index 29617bf22ea..00000000000 --- a/crates/papyrus_common/src/class_hash_test.rs +++ /dev/null @@ -1,14 +0,0 @@ -use starknet_api::class_hash; -use starknet_api::state::SierraContractClass; -use starknet_api::test_utils::read_json_file; - -use crate::class_hash::calculate_class_hash; - -#[test] -fn class_hash() { - let class: SierraContractClass = serde_json::from_value(read_json_file("class.json")).unwrap(); - let expected_class_hash = - class_hash!("0x29927c8af6bccf3f6fda035981e765a7bdbf18a2dc0d630494f8758aa908e2b"); - let calculated_class_hash = calculate_class_hash(&class); - assert_eq!(calculated_class_hash, expected_class_hash); -} diff --git a/crates/papyrus_common/src/deprecated_class_abi.rs b/crates/papyrus_common/src/deprecated_class_abi.rs index 33f95cd9c87..58aeb839893 100644 --- a/crates/papyrus_common/src/deprecated_class_abi.rs +++ b/crates/papyrus_common/src/deprecated_class_abi.rs @@ -2,7 +2,7 @@ use serde::Serialize; use crate::python_json::PythonJsonFormatter; -// TODO: Consider moving to SN API as a method of deprecated_contract_class::ContractClass. +// TODO(Shahak): Consider moving to SN API as a method of deprecated_contract_class::ContractClass. pub fn calculate_deprecated_class_abi_length( deprecated_class: &starknet_api::deprecated_contract_class::ContractClass, ) -> Result { diff --git a/crates/papyrus_common/src/lib.rs b/crates/papyrus_common/src/lib.rs index 3fc0c90beac..edfa2ac2ca5 100644 --- a/crates/papyrus_common/src/lib.rs +++ b/crates/papyrus_common/src/lib.rs @@ -1,6 +1,3 @@ -use starknet_types_core::felt::Felt; - -pub mod class_hash; pub mod compression_utils; pub mod deprecated_class_abi; pub mod metrics; @@ -8,8 +5,3 @@ pub mod pending_classes; pub mod python_json; pub mod state; pub mod storage_query; -pub mod tcp; - -pub(crate) fn usize_into_felt(u: usize) -> Felt { - u128::try_from(u).expect("Expect at most 128 bits").into() -} diff --git a/crates/papyrus_common/src/metrics.rs b/crates/papyrus_common/src/metrics.rs index cdb6e24a665..f1982150965 100644 --- a/crates/papyrus_common/src/metrics.rs +++ b/crates/papyrus_common/src/metrics.rs @@ -1,39 +1,6 @@ use std::sync::OnceLock; -/// The central marker is the first block number that doesn't exist yet. -pub const PAPYRUS_CENTRAL_BLOCK_MARKER: &str = "papyrus_central_block_marker"; - -/// The header marker is the first block number for which the node does not have a header. -pub const PAPYRUS_HEADER_MARKER: &str = "papyrus_header_marker"; - -/// The body marker is the first block number for which the node does not have a body. -pub const PAPYRUS_BODY_MARKER: &str = "papyrus_body_marker"; - -/// The state marker is the first block number for which the node does not have a state body. -pub const PAPYRUS_STATE_MARKER: &str = "papyrus_state_marker"; - -/// The compiled class marker is the first block number for which the node does not have all of the -/// corresponding compiled classes. -pub const PAPYRUS_COMPILED_CLASS_MARKER: &str = "papyrus_compiled_class_marker"; - -/// The base layer marker is the first block number for which the node does not guarantee L1 -/// finality. -pub const PAPYRUS_BASE_LAYER_MARKER: &str = "papyrus_base_layer_marker"; - -/// The latency, in seconds, between a block timestamp (as state in its header) and the time the -/// node stores the header. -pub const PAPYRUS_HEADER_LATENCY_SEC: &str = "papyrus_header_latency"; - -/// The number of peers this node is connected to. -pub const PAPYRUS_NUM_CONNECTED_PEERS: &str = "papyrus_num_connected_peers"; - -/// The number of active sessions this peer has in which it sends data. -pub const PAPYRUS_NUM_ACTIVE_INBOUND_SESSIONS: &str = "papyrus_num_active_inbound_sessions"; - -/// The number of active sessions this peer has in which it requests data. -pub const PAPYRUS_NUM_ACTIVE_OUTBOUND_SESSIONS: &str = "papyrus_num_active_outbound_sessions"; - -// TODO: consider making this value non static and add a way to change this while the app is +// TODO(Shahak): consider making this value non static and add a way to change this while the app is // running. e.g via a monitoring endpoint. /// Global variable set by the main config to enable collecting profiling metrics. pub static COLLECT_PROFILING_METRICS: OnceLock = OnceLock::new(); diff --git a/crates/papyrus_common/src/pending_classes.rs b/crates/papyrus_common/src/pending_classes.rs index 79de3849e84..f2d3a5ae34a 100644 --- a/crates/papyrus_common/src/pending_classes.rs +++ b/crates/papyrus_common/src/pending_classes.rs @@ -7,13 +7,13 @@ use starknet_api::deprecated_contract_class::ContractClass as DeprecatedContract use starknet_api::state::SierraContractClass; pub trait PendingClassesTrait { - // TODO(shahak) Return an Arc to avoid cloning the class. This requires to re-implement + // TODO(shahak): Return an Arc to avoid cloning the class. This requires to re-implement // From/TryFrom for various structs in a way that the input is passed by reference. fn get_class(&self, class_hash: ClassHash) -> Option; fn add_class(&mut self, class_hash: ClassHash, class: ApiContractClass); - // TODO(shahak) Return an Arc to avoid cloning the class. This requires to re-implement + // TODO(shahak): Return an Arc to avoid cloning the class. This requires to re-implement // From/TryFrom for various structs in a way that the input is passed by reference. fn get_compiled_class(&self, class_hash: ClassHash) -> Option; diff --git a/crates/papyrus_common/src/state.rs b/crates/papyrus_common/src/state.rs index badf6d7ba0b..d1a130bbe23 100644 --- a/crates/papyrus_common/src/state.rs +++ b/crates/papyrus_common/src/state.rs @@ -32,7 +32,7 @@ pub struct ReplacedClass { pub class_hash: ClassHash, } -// TODO: move to used crate +// TODO(Shahak): move to used crate pub fn create_random_state_diff(rng: &mut impl RngCore) -> ThinStateDiff { let contract0 = ContractAddress::from(rng.next_u64()); let contract1 = ContractAddress::from(rng.next_u64()); @@ -57,6 +57,5 @@ pub fn create_random_state_diff(rng: &mut impl RngCore) -> ThinStateDiff { nonces: indexmap! { contract0 => Nonce(Felt::ONE), contract2 => Nonce(Felt::TWO) }, - replaced_classes: Default::default(), } } diff --git a/crates/papyrus_common/src/tcp.rs b/crates/papyrus_common/src/tcp.rs deleted file mode 100644 index 87199415ce1..00000000000 --- a/crates/papyrus_common/src/tcp.rs +++ /dev/null @@ -1,18 +0,0 @@ -use std::net::TcpListener; - -pub fn find_free_port() -> u16 { - // The socket is automatically closed when the function exits. - // The port may still be available when accessed, but this is not guaranteed. - // TODO(Asmaa): find a reliable way to ensure the port stays free. - let listener = TcpListener::bind("0.0.0.0:0").expect("Failed to bind"); - listener.local_addr().expect("Failed to get local address").port() -} - -pub fn find_n_free_ports() -> [u16; N] { - // The socket is automatically closed when the function exits. - // The port may still be available when accessed, but this is not guaranteed. - // TODO(Asmaa): find a reliable way to ensure the port stays free. - let listeners: [TcpListener; N] = - core::array::from_fn(|_i| TcpListener::bind("0.0.0.0:0").expect("Failed to bind")); - core::array::from_fn(|i| listeners[i].local_addr().expect("Failed to get local address").port()) -} diff --git a/crates/papyrus_config/Cargo.toml b/crates/papyrus_config/Cargo.toml index a8e385ec25c..6234c7fd768 100644 --- a/crates/papyrus_config/Cargo.toml +++ b/crates/papyrus_config/Cargo.toml @@ -6,26 +6,24 @@ repository.workspace = true license-file.workspace = true description = "A library for handling node configuration." -[package.metadata.cargo-udeps.ignore] -development = ["tempfile"] # Dependency of a doc-test - [dependencies] clap = { workspace = true, features = ["env", "string"] } -infra_utils.workspace = true itertools.workspace = true serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true, features = ["arbitrary_precision"] } +starknet_infra_utils.workspace = true strum_macros.workspace = true thiserror.workspace = true +tracing.workspace = true validator = { workspace = true, features = ["derive"] } [dev-dependencies] assert_matches.workspace = true -infra_utils.workspace = true itertools.workspace = true lazy_static.workspace = true papyrus_test_utils.workspace = true starknet_api.workspace = true +starknet_infra_utils.workspace = true tempfile.workspace = true [lints] diff --git a/crates/papyrus_config/src/command.rs b/crates/papyrus_config/src/command.rs index f21d1e9bee8..41fcf7d81f3 100644 --- a/crates/papyrus_config/src/command.rs +++ b/crates/papyrus_config/src/command.rs @@ -41,7 +41,9 @@ fn build_args_parser(config_map: &BTreeMap) -> Vec) -> CustomConfig { File::open(file_path).unwrap(), Command::new("Program"), args.into_iter().map(|s| s.to_owned()).collect(), + false, ) .unwrap() } @@ -698,6 +699,7 @@ fn load_required_param_path(args: Vec<&str>) -> String { File::open(file_path).unwrap(), Command::new("Program"), args.into_iter().map(|s| s.to_owned()).collect(), + false, ) .unwrap(); loaded_config.param_path @@ -792,6 +794,7 @@ fn deeply_nested_optionals() { File::open(file_path.clone()).unwrap(), Command::new("Testing"), Vec::new(), + false, ) .unwrap(); assert_eq!(l0, Level0 { level0_value: 1, level1: None }); @@ -800,6 +803,7 @@ fn deeply_nested_optionals() { File::open(file_path.clone()).unwrap(), Command::new("Testing"), vec!["Testing".to_owned(), "--level1.#is_none".to_owned(), "false".to_owned()], + false, ) .unwrap(); assert_eq!( @@ -817,6 +821,7 @@ fn deeply_nested_optionals() { "--level1.level2.#is_none".to_owned(), "false".to_owned(), ], + false, ) .unwrap(); assert_eq!( @@ -839,6 +844,7 @@ fn deeply_nested_optionals() { "--level1.level2.level2_value.#is_none".to_owned(), "false".to_owned(), ], + false, ) .unwrap(); assert_eq!( diff --git a/crates/papyrus_config/src/dumping.rs b/crates/papyrus_config/src/dumping.rs index 1acddda1123..7b13b046414 100644 --- a/crates/papyrus_config/src/dumping.rs +++ b/crates/papyrus_config/src/dumping.rs @@ -363,7 +363,7 @@ pub fn ser_pointer_target_required_param( /// Updates entries in the map to point to these targets, replacing values of entries that match /// the target parameter paths to contain only the name of the target they point to. /// Fails if a param is not pointing to a same-named pointer target nor whitelisted. -pub(crate) fn combine_config_map_and_pointers( +pub fn combine_config_map_and_pointers( mut config_map: BTreeMap, pointers: &ConfigPointers, non_pointer_params: &Pointers, diff --git a/crates/papyrus_config/src/lib.rs b/crates/papyrus_config/src/lib.rs index 7a383cef548..b9c6334c806 100644 --- a/crates/papyrus_config/src/lib.rs +++ b/crates/papyrus_config/src/lib.rs @@ -42,6 +42,7 @@ //! file, //! Command::new("Program"), //! vec!["Program".to_owned(), "--key".to_owned(), "770".to_owned()], +//! false, //! ) //! .unwrap(); //! assert_eq!(loaded_config.key, 770); @@ -180,8 +181,7 @@ pub enum ConfigError { CommandMatches(#[from] MatchesError), #[error(transparent)] IOError(#[from] std::io::Error), - // TODO(Eitan): Improve error message - #[error("Insert a new param is not allowed: {param_path}.")] + #[error("Param does not exist: {param_path}.")] ParamNotFound { param_path: String }, #[error("{target_param} is not found.")] PointerTargetNotFound { target_param: String }, diff --git a/crates/papyrus_config/src/loading.rs b/crates/papyrus_config/src/loading.rs index 50df585217f..51c08028ef6 100644 --- a/crates/papyrus_config/src/loading.rs +++ b/crates/papyrus_config/src/loading.rs @@ -15,6 +15,7 @@ use command::{get_command_matches, update_config_map_by_command_args}; use itertools::any; use serde::Deserialize; use serde_json::{json, Map, Value}; +use tracing::{info, instrument}; use crate::validators::validate_path_exists; use crate::{ @@ -30,6 +31,7 @@ use crate::{ /// Deserializes config from flatten JSON. /// For an explanation of `for<'a> Deserialize<'a>` see /// ``. +#[instrument(skip(config_map))] pub fn load Deserialize<'a>>( config_map: &BTreeMap, ) -> Result { @@ -50,16 +52,21 @@ pub fn load_and_process_config Deserialize<'a>>( default_config_file: File, command: Command, args: Vec, + ignore_default_values: bool, ) -> Result { - let deserialized_default_config: Map = + let deserialized_default_config: Map = serde_json::from_reader(default_config_file)?; - // Store the pointers separately from the default values. The pointers will receive a value // only at the end of the process. let (default_config_map, pointers_map) = split_pointers_map(deserialized_default_config); // Take param paths with corresponding descriptions, and get the matching arguments. let mut arg_matches = get_command_matches(&default_config_map, command, args)?; + // Retaining values from the default config map for backward compatibility. let (mut values_map, types_map) = split_values_and_types(default_config_map); + if ignore_default_values { + info!("Ignoring default values by overriding with an empty map."); + values_map = BTreeMap::new(); + } // If the config_file arg is given, updates the values map according to this files. if let Some(custom_config_paths) = arg_matches.remove_many::("config_file") { update_config_map_by_custom_configs(&mut values_map, &types_map, custom_config_paths)?; @@ -124,6 +131,7 @@ pub(crate) fn update_config_map_by_custom_configs( custom_config_paths: Values, ) -> Result<(), ConfigError> { for config_path in custom_config_paths { + info!("Loading custom config file: {:?}", config_path); validate_path_exists(&config_path)?; let file = std::fs::File::open(config_path)?; let custom_config: Map = serde_json::from_reader(file)?; diff --git a/crates/papyrus_config/src/presentation.rs b/crates/papyrus_config/src/presentation.rs index ea8f3702470..19c8fb9eefd 100644 --- a/crates/papyrus_config/src/presentation.rs +++ b/crates/papyrus_config/src/presentation.rs @@ -56,7 +56,7 @@ fn remove_path_from_json( // be "v1". let mut path_to_entry = param_path.split('.').collect_vec(); let Some(entry_to_remove) = path_to_entry.pop() else { - // TODO: Can we expect this to never happen? + // TODO(Yair): Can we expect this to never happen? return Ok(()); // Empty param path. }; let mut inner_json = json; diff --git a/crates/papyrus_config/src/validators.rs b/crates/papyrus_config/src/validators.rs index ec2fc27ea12..93b2fcab6b3 100644 --- a/crates/papyrus_config/src/validators.rs +++ b/crates/papyrus_config/src/validators.rs @@ -15,7 +15,7 @@ pub fn validate_ascii(name: &impl ToString) -> Result<(), ValidationError> { } /// Custom validation for file or directory path existence. -pub fn validate_path_exists(file_path: &Path) -> Result<(), ValidationError> { +pub(crate) fn validate_path_exists(file_path: &Path) -> Result<(), ValidationError> { if !file_path.exists() { let mut error = ValidationError::new("file or directory not found"); error.message = Some( diff --git a/crates/papyrus_execution/src/execution_test.rs b/crates/papyrus_execution/src/execution_test.rs index f100c7d1faf..3454f455a88 100644 --- a/crates/papyrus_execution/src/execution_test.rs +++ b/crates/papyrus_execution/src/execution_test.rs @@ -3,11 +3,11 @@ use std::sync::Arc; use assert_matches::assert_matches; +use blockifier::blockifier_versioned_constants::VersionedConstants; use blockifier::execution::call_info::Retdata; use blockifier::execution::errors::ConstructorEntryPointExecutionError; use blockifier::execution::stack_trace::gen_tx_execution_error_trace; use blockifier::transaction::errors::TransactionExecutionError as BlockifierTransactionExecutionError; -use blockifier::versioned_constants::VersionedConstants; use indexmap::indexmap; use papyrus_storage::test_utils::get_test_storage; use pretty_assertions::assert_eq; @@ -645,7 +645,7 @@ fn simulate_invoke_from_new_account_validate_and_charge() { } #[test] -// TODO: Fix this test. +// TODO(DanB): Fix this test. #[ignore] fn induced_state_diff() { let ((storage_reader, storage_writer), _temp_dir) = get_test_storage(); @@ -682,7 +682,6 @@ fn induced_state_diff() { }, declared_classes: indexmap! {}, deprecated_declared_classes: vec![], - replaced_classes: indexmap! {}, }; assert_eq!(simulation_results[0].induced_state_diff, expected_invoke_deprecated); @@ -699,7 +698,6 @@ fn induced_state_diff() { }, deployed_contracts: indexmap! {}, deprecated_declared_classes: vec![], - replaced_classes: indexmap! {}, }; assert_eq!(simulation_results[1].induced_state_diff, expected_declare_class); next_declared_class_hash += 1; @@ -717,7 +715,6 @@ fn induced_state_diff() { }, declared_classes: indexmap! {}, deployed_contracts: indexmap! {}, - replaced_classes: indexmap! {}, }; assert_eq!(simulation_results[2].induced_state_diff, expected_declare_deprecated_class); @@ -738,7 +735,6 @@ fn induced_state_diff() { }, declared_classes: indexmap! {}, deployed_contracts: indexmap! {*NEW_ACCOUNT_ADDRESS => *ACCOUNT_CLASS_HASH}, - replaced_classes: indexmap! {}, }; assert_eq!(simulation_results[3].induced_state_diff, expected_deploy_account); } diff --git a/crates/papyrus_execution/src/execution_utils.rs b/crates/papyrus_execution/src/execution_utils.rs index 45e45d16b8d..5bd3b829315 100644 --- a/crates/papyrus_execution/src/execution_utils.rs +++ b/crates/papyrus_execution/src/execution_utils.rs @@ -3,12 +3,11 @@ use std::fs::File; use std::path::PathBuf; use blockifier::execution::contract_class::{ - ContractClassV0, - ContractClassV1, - RunnableContractClass, + CompiledClassV0, + CompiledClassV1, + RunnableCompiledClass, }; use blockifier::state::cached_state::{CachedState, CommitmentStateDiff, MutRefState}; -use blockifier::state::state_api::StateReader; use blockifier::transaction::objects::TransactionExecutionInfo; use cairo_vm::types::errors::program_errors::ProgramError; use indexmap::IndexMap; @@ -19,6 +18,7 @@ use papyrus_storage::state::StateStorageReader; use papyrus_storage::{StorageError, StorageResult, StorageTxn}; // Expose the tool for creating entry point selectors from function names. pub use starknet_api::abi::abi_utils::selector_from_name; +use starknet_api::contract_class::SierraVersion; use starknet_api::core::{ClassHash, ContractAddress, Nonce}; use starknet_api::state::{StateNumber, StorageKey, ThinStateDiff}; use starknet_types_core::felt::Felt; @@ -26,13 +26,7 @@ use thiserror::Error; use crate::objects::TransactionTrace; use crate::state_reader::ExecutionStateReader; -use crate::{ - BlockifierError, - ExecutableTransactionInput, - ExecutionConfig, - ExecutionError, - ExecutionResult, -}; +use crate::{ExecutableTransactionInput, ExecutionConfig, ExecutionError, ExecutionResult}; // An error that can occur during the use of the execution utils. #[derive(Debug, Error)] @@ -43,6 +37,8 @@ pub(crate) enum ExecutionUtilsError { StorageError(#[from] StorageError), #[error("Casm table not fully synced")] CasmTableNotSynced, + #[error(transparent)] + SierraValidationError(starknet_api::StarknetApiError), } /// Returns the execution config from the config file. @@ -59,16 +55,19 @@ pub(crate) fn get_contract_class( txn: &StorageTxn<'_, RO>, class_hash: &ClassHash, state_number: StateNumber, -) -> Result, ExecutionUtilsError> { +) -> Result, ExecutionUtilsError> { match txn.get_state_reader()?.get_class_definition_block_number(class_hash)? { Some(block_number) if state_number.is_before(block_number) => return Ok(None), Some(_block_number) => { - let Some(casm) = txn.get_casm(class_hash)? else { + let (Some(casm), Some(sierra)) = txn.get_casm_and_sierra(class_hash)? else { return Err(ExecutionUtilsError::CasmTableNotSynced); }; - return Ok(Some(RunnableContractClass::V1( - ContractClassV1::try_from(casm).map_err(ExecutionUtilsError::ProgramError)?, - ))); + let sierra_version = SierraVersion::extract_from_program(&sierra.sierra_program) + .map_err(ExecutionUtilsError::SierraValidationError)?; + return Ok(Some(RunnableCompiledClass::V1(CompiledClassV1::try_from(( + casm, + sierra_version, + ))?))); } None => {} }; @@ -78,8 +77,8 @@ pub(crate) fn get_contract_class( else { return Ok(None); }; - Ok(Some(RunnableContractClass::V0( - ContractClassV0::try_from(deprecated_class).map_err(ExecutionUtilsError::ProgramError)?, + Ok(Some(RunnableCompiledClass::V0( + CompiledClassV0::try_from(deprecated_class).map_err(ExecutionUtilsError::ProgramError)?, ))) } @@ -125,34 +124,20 @@ pub fn induced_state_diff( ) -> ExecutionResult { let blockifier_state_diff = CommitmentStateDiff::from(transactional_state.to_state_diff()?.state_maps); - // Determine which contracts were deployed and which were replaced by comparing their - // previous class hash (default value suggests it didn't exist before). - let mut deployed_contracts = IndexMap::new(); - let mut replaced_classes = IndexMap::new(); - let default_class_hash = ClassHash::default(); - for (address, class_hash) in blockifier_state_diff.address_to_class_hash.iter() { - let prev_class_hash = - transactional_state.state.get_class_hash_at(*address).map_err(BlockifierError::new)?; - if prev_class_hash == default_class_hash { - deployed_contracts.insert(*address, *class_hash); - } else { - replaced_classes.insert(*address, *class_hash); - } - } + Ok(ThinStateDiff { - deployed_contracts, + deployed_contracts: blockifier_state_diff.address_to_class_hash, storage_diffs: blockifier_state_diff.storage_updates, declared_classes: blockifier_state_diff.class_hash_to_compiled_class_hash, deprecated_declared_classes: deprecated_declared_class_hash .map_or_else(Vec::new, |class_hash| vec![class_hash]), nonces: blockifier_state_diff.address_to_nonce, - replaced_classes, }) } /// Get the storage at the given contract and key in the given state. If there's a given pending /// storage diffs, apply them on top of the given state. -// TODO(shahak) If the structure of storage diffs changes, remove this function and move its code +// TODO(shahak): If the structure of storage diffs changes, remove this function and move its code // into papyrus_rpc. pub fn get_storage_at( txn: &StorageTxn<'_, Mode>, diff --git a/crates/papyrus_execution/src/lib.rs b/crates/papyrus_execution/src/lib.rs index 4e7fada6bdf..b1e6dbbcc43 100644 --- a/crates/papyrus_execution/src/lib.rs +++ b/crates/papyrus_execution/src/lib.rs @@ -12,7 +12,6 @@ mod execution_test; pub mod execution_utils; mod state_reader; - #[cfg(test)] mod test_utils; #[cfg(any(feature = "testing", test))] @@ -23,7 +22,8 @@ use std::cell::Cell; use std::collections::BTreeMap; use std::sync::{Arc, LazyLock}; -use blockifier::blockifier::block::{pre_process_block, BlockInfo, GasPrices}; +use blockifier::blockifier::block::{pre_process_block, validated_gas_prices}; +use blockifier::blockifier_versioned_constants::{VersionedConstants, VersionedConstantsError}; use blockifier::bouncer::BouncerConfig; use blockifier::context::{BlockContext, ChainInfo, FeeTokenAddresses, TransactionContext}; use blockifier::execution::call_info::CallExecution; @@ -31,8 +31,10 @@ use blockifier::execution::entry_point::{ CallEntryPoint, CallType as BlockifierCallType, EntryPointExecutionContext, + SierraGasRevertTracker, }; use blockifier::state::cached_state::CachedState; +use blockifier::transaction::account_transaction::ExecutionFlags; use blockifier::transaction::errors::TransactionExecutionError as BlockifierTransactionExecutionError; use blockifier::transaction::objects::{ DeprecatedTransactionInfo, @@ -41,7 +43,6 @@ use blockifier::transaction::objects::{ }; use blockifier::transaction::transaction_execution::Transaction as BlockifierTransaction; use blockifier::transaction::transactions::ExecutableTransaction; -use blockifier::versioned_constants::{VersionedConstants, VersionedConstantsError}; use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass; use cairo_vm::types::builtin_name::BuiltinName; use execution_utils::{get_trace_constructor, induced_state_diff}; @@ -51,11 +52,18 @@ use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; use papyrus_storage::header::HeaderStorageReader; use papyrus_storage::{StorageError, StorageReader}; use serde::{Deserialize, Serialize}; -use starknet_api::block::{BlockHashAndNumber, BlockNumber, NonzeroGasPrice, StarknetVersion}; -use starknet_api::contract_class::{ClassInfo, EntryPointType}; +use starknet_api::block::{ + BlockHashAndNumber, + BlockInfo, + BlockNumber, + NonzeroGasPrice, + StarknetVersion, +}; +use starknet_api::contract_class::{ClassInfo, EntryPointType, SierraVersion}; use starknet_api::core::{ChainId, ClassHash, ContractAddress, EntryPointSelector}; use starknet_api::data_availability::L1DataAvailabilityMode; use starknet_api::deprecated_contract_class::ContractClass as DeprecatedContractClass; +use starknet_api::execution_resources::GasAmount; use starknet_api::state::{StateNumber, ThinStateDiff}; use starknet_api::transaction::fields::{Calldata, Fee}; use starknet_api::transaction::{ @@ -266,8 +274,9 @@ pub fn execute_call( let limit_steps_by_resources = false; // Default resource bounds. let mut context = EntryPointExecutionContext::new_invoke( - Arc::new(TransactionContext { block_context, tx_info }), + Arc::new(TransactionContext { block_context: Arc::new(block_context), tx_info }), limit_steps_by_resources, + SierraGasRevertTracker::new(GasAmount(remaining_gas)), ); let res = call_entry_point @@ -369,7 +378,7 @@ fn create_block_context( use_kzg_da, block_number, // TODO(yair): What to do about blocks pre 0.13.1 where the data gas price were 0? - gas_prices: GasPrices::new( + gas_prices: validated_gas_prices( NonzeroGasPrice::new(l1_gas_price.price_in_wei).unwrap_or(NonzeroGasPrice::MIN), NonzeroGasPrice::new(l1_gas_price.price_in_fri).unwrap_or(NonzeroGasPrice::MIN), NonzeroGasPrice::new(l1_data_gas_price.price_in_wei).unwrap_or(NonzeroGasPrice::MIN), @@ -399,7 +408,12 @@ fn create_block_context( ); let next_block_number = block_context.block_info().block_number; - pre_process_block(cached_state, ten_blocks_ago, next_block_number)?; + pre_process_block( + cached_state, + ten_blocks_ago, + next_block_number, + &versioned_constants.os_constants, + )?; Ok(block_context) } @@ -422,8 +436,22 @@ pub enum ExecutableTransactionInput { // todo(yair): Do we need to support V0? DeclareV0(DeclareTransactionV0V1, DeprecatedContractClass, AbiSize, OnlyQuery), DeclareV1(DeclareTransactionV0V1, DeprecatedContractClass, AbiSize, OnlyQuery), - DeclareV2(DeclareTransactionV2, CasmContractClass, SierraSize, AbiSize, OnlyQuery), - DeclareV3(DeclareTransactionV3, CasmContractClass, SierraSize, AbiSize, OnlyQuery), + DeclareV2( + DeclareTransactionV2, + CasmContractClass, + SierraSize, + AbiSize, + OnlyQuery, + SierraVersion, + ), + DeclareV3( + DeclareTransactionV3, + CasmContractClass, + SierraSize, + AbiSize, + OnlyQuery, + SierraVersion, + ), DeployAccount(DeployAccountTransaction, OnlyQuery), L1Handler(L1HandlerTransaction, Fee, OnlyQuery), } @@ -479,13 +507,24 @@ impl ExecutableTransactionInput { sierra_program_length, abi_length, only_query, + sierra_version, ) => { let as_transaction = Transaction::Declare(DeclareTransaction::V2(tx)); let res = func(&as_transaction, only_query); let Transaction::Declare(DeclareTransaction::V2(tx)) = as_transaction else { unreachable!("Should be declare v2 transaction.") }; - (Self::DeclareV2(tx, class, sierra_program_length, abi_length, only_query), res) + ( + Self::DeclareV2( + tx, + class, + sierra_program_length, + abi_length, + only_query, + sierra_version, + ), + res, + ) } ExecutableTransactionInput::DeclareV3( tx, @@ -493,13 +532,24 @@ impl ExecutableTransactionInput { sierra_program_length, abi_length, only_query, + sierra_version, ) => { let as_transaction = Transaction::Declare(DeclareTransaction::V3(tx)); let res = func(&as_transaction, only_query); let Transaction::Declare(DeclareTransaction::V3(tx)) = as_transaction else { unreachable!("Should be declare v3 transaction.") }; - (Self::DeclareV3(tx, class, sierra_program_length, abi_length, only_query), res) + ( + Self::DeclareV3( + tx, + class, + sierra_program_length, + abi_length, + only_query, + sierra_version, + ), + res, + ) } ExecutableTransactionInput::DeployAccount(tx, only_query) => { let as_transaction = Transaction::DeployAccount(tx); @@ -664,7 +714,7 @@ fn execute_transactions( for (transaction_index, (tx, tx_hash)) in txs.into_iter().zip(tx_hashes.into_iter()).enumerate() { let transaction_version = tx.transaction_version(); - // TODO: consider supporting match instead. + // TODO(DanB): consider supporting match instead. let price_unit = if transaction_version == TransactionVersion::ZERO || transaction_version == TransactionVersion::ONE || transaction_version == TransactionVersion::TWO @@ -689,10 +739,10 @@ fn execute_transactions( ) => Some(*class_hash), _ => None, }; - let blockifier_tx = to_blockifier_tx(tx, tx_hash, transaction_index)?; + let blockifier_tx = to_blockifier_tx(tx, tx_hash, transaction_index, charge_fee, validate)?; // TODO(Yoni): use the TransactionExecutor instead. let tx_execution_info_result = - blockifier_tx.execute(&mut transactional_state, &block_context, charge_fee, validate); + blockifier_tx.execute(&mut transactional_state, &block_context); let state_diff = induced_state_diff(&mut transactional_state, deprecated_declared_class_hash)?; transactional_state.commit(); @@ -751,30 +801,37 @@ fn to_blockifier_tx( tx: ExecutableTransactionInput, tx_hash: TransactionHash, transaction_index: usize, + charge_fee: bool, + validate: bool, ) -> ExecutionResult { // TODO(yair): support only_query version bit (enable in the RPC v0.6 and use the correct // value). + let strict_nonce_check = true; match tx { ExecutableTransactionInput::Invoke(invoke_tx, only_query) => { + let execution_flags = + ExecutionFlags { only_query, charge_fee, validate, strict_nonce_check }; BlockifierTransaction::from_api( Transaction::Invoke(invoke_tx), tx_hash, None, None, None, - only_query, + execution_flags, ) .map_err(|err| ExecutionError::from((transaction_index, err))) } ExecutableTransactionInput::DeployAccount(deploy_acc_tx, only_query) => { + let execution_flags = + ExecutionFlags { only_query, charge_fee, validate, strict_nonce_check }; BlockifierTransaction::from_api( Transaction::DeployAccount(deploy_acc_tx), tx_hash, None, None, None, - only_query, + execution_flags, ) .map_err(|err| ExecutionError::from((transaction_index, err))) } @@ -789,19 +846,22 @@ fn to_blockifier_tx( &deprecated_class.into(), DEPRECATED_CONTRACT_SIERRA_SIZE, abi_length, + SierraVersion::DEPRECATED, ) .map_err(|err| ExecutionError::BadDeclareTransaction { tx: DeclareTransaction::V0(declare_tx.clone()), err, })?; + let execution_flags = + ExecutionFlags { only_query, charge_fee, validate, strict_nonce_check }; BlockifierTransaction::from_api( Transaction::Declare(DeclareTransaction::V0(declare_tx)), tx_hash, Some(class_info), None, None, - only_query, + execution_flags, ) .map_err(|err| ExecutionError::from((transaction_index, err))) } @@ -815,18 +875,21 @@ fn to_blockifier_tx( &deprecated_class.into(), DEPRECATED_CONTRACT_SIERRA_SIZE, abi_length, + SierraVersion::DEPRECATED, ) .map_err(|err| ExecutionError::BadDeclareTransaction { tx: DeclareTransaction::V1(declare_tx.clone()), err, })?; + let execution_flags = + ExecutionFlags { only_query, charge_fee, validate, strict_nonce_check }; BlockifierTransaction::from_api( Transaction::Declare(DeclareTransaction::V1(declare_tx)), tx_hash, Some(class_info), None, None, - only_query, + execution_flags, ) .map_err(|err| ExecutionError::from((transaction_index, err))) } @@ -836,21 +899,27 @@ fn to_blockifier_tx( sierra_program_length, abi_length, only_query, + sierra_version, ) => { - let class_info = - ClassInfo::new(&compiled_class.into(), sierra_program_length, abi_length).map_err( - |err| ExecutionError::BadDeclareTransaction { - tx: DeclareTransaction::V2(declare_tx.clone()), - err, - }, - )?; + let class_info = ClassInfo::new( + &(compiled_class, sierra_version.clone()).into(), + sierra_program_length, + abi_length, + sierra_version, + ) + .map_err(|err| ExecutionError::BadDeclareTransaction { + tx: DeclareTransaction::V2(declare_tx.clone()), + err, + })?; + let execution_flags = + ExecutionFlags { only_query, charge_fee, validate, strict_nonce_check }; BlockifierTransaction::from_api( Transaction::Declare(DeclareTransaction::V2(declare_tx)), tx_hash, Some(class_info), None, None, - only_query, + execution_flags, ) .map_err(|err| ExecutionError::from((transaction_index, err))) } @@ -860,32 +929,40 @@ fn to_blockifier_tx( sierra_program_length, abi_length, only_query, + sierra_version, ) => { - let class_info = - ClassInfo::new(&compiled_class.into(), sierra_program_length, abi_length).map_err( - |err| ExecutionError::BadDeclareTransaction { - tx: DeclareTransaction::V3(declare_tx.clone()), - err, - }, - )?; + let class_info = ClassInfo::new( + &(compiled_class, sierra_version.clone()).into(), + sierra_program_length, + abi_length, + sierra_version, + ) + .map_err(|err| ExecutionError::BadDeclareTransaction { + tx: DeclareTransaction::V3(declare_tx.clone()), + err, + })?; + let execution_flags = + ExecutionFlags { only_query, charge_fee, validate, strict_nonce_check }; BlockifierTransaction::from_api( Transaction::Declare(DeclareTransaction::V3(declare_tx)), tx_hash, Some(class_info), None, None, - only_query, + execution_flags, ) .map_err(|err| ExecutionError::from((transaction_index, err))) } ExecutableTransactionInput::L1Handler(l1_handler_tx, paid_fee, only_query) => { + let execution_flags = + ExecutionFlags { only_query, charge_fee, validate, strict_nonce_check }; BlockifierTransaction::from_api( Transaction::L1Handler(l1_handler_tx), tx_hash, None, Some(paid_fee), None, - only_query, + execution_flags, ) .map_err(|err| ExecutionError::from((transaction_index, err))) } diff --git a/crates/papyrus_execution/src/objects.rs b/crates/papyrus_execution/src/objects.rs index f80ab9e6c29..ed734049ffe 100644 --- a/crates/papyrus_execution/src/objects.rs +++ b/crates/papyrus_execution/src/objects.rs @@ -9,7 +9,7 @@ use blockifier::execution::call_info::{ Retdata as BlockifierRetdata, }; use blockifier::execution::entry_point::CallType as BlockifierCallType; -use blockifier::transaction::objects::{FeeType, TransactionExecutionInfo}; +use blockifier::transaction::objects::TransactionExecutionInfo; use blockifier::utils::u64_from_usize; use cairo_vm::types::builtin_name::BuiltinName; use cairo_vm::vm::runners::cairo_runner::ExecutionResources as VmExecutionResources; @@ -23,7 +23,7 @@ use papyrus_common::state::{ StorageEntry, }; use serde::{Deserialize, Serialize}; -use starknet_api::block::{BlockTimestamp, GasPrice, GasPricePerToken}; +use starknet_api::block::{BlockTimestamp, FeeType, GasPrice, GasPricePerToken}; use starknet_api::contract_class::EntryPointType; use starknet_api::core::{ ClassHash, @@ -164,9 +164,9 @@ pub(crate) fn tx_execution_output_to_fee_estimation( ) -> ExecutionResult { let gas_prices = &block_context.block_info().gas_prices; let (l1_gas_price, l1_data_gas_price, l2_gas_price) = ( - gas_prices.get_l1_gas_price_by_fee_type(&tx_execution_output.price_unit.into()).get(), - gas_prices.get_l1_data_gas_price_by_fee_type(&tx_execution_output.price_unit.into()).get(), - gas_prices.get_l2_gas_price_by_fee_type(&tx_execution_output.price_unit.into()).get(), + gas_prices.l1_gas_price(&tx_execution_output.price_unit.into()).get(), + gas_prices.l1_data_gas_price(&tx_execution_output.price_unit.into()).get(), + gas_prices.l2_gas_price(&tx_execution_output.price_unit.into()).get(), ); let gas_vector = tx_execution_output.execution_info.receipt.gas; @@ -322,7 +322,7 @@ impl TryFrom<(CallInfo, GasVector)> for FunctionInvocation { calldata: call_info.call.calldata, }, caller_address: call_info.call.caller_address, - class_hash: call_info.call.class_hash.ok_or(ExecutionError::MissingClassHash)?, /* TODO: fix this. */ + class_hash: call_info.call.class_hash.ok_or(ExecutionError::MissingClassHash)?, /* TODO(DanB): fix this. */ entry_point_type: call_info.call.entry_point_type, call_type: call_info.call.call_type.into(), result: call_info.execution.retdata.into(), @@ -350,7 +350,7 @@ impl TryFrom<(CallInfo, GasVector)> for FunctionInvocation { }) .collect(), execution_resources: vm_resources_to_execution_resources( - call_info.charged_resources.vm_resources, + call_info.resources, gas_vector, )?, }) @@ -383,7 +383,7 @@ fn vm_resources_to_execution_resources( BuiltinName::segment_arena => { builtin_instance_counter.insert(Builtin::SegmentArena, count) } - // TODO: what about the following? + // TODO(DanB): what about the following? // BuiltinName::range_check96 => todo!(), // BuiltinName::add_mod => todo!(), // BuiltinName::mul_mod => todo!(), diff --git a/crates/papyrus_execution/src/state_reader.rs b/crates/papyrus_execution/src/state_reader.rs index a963241f613..e53530167b9 100644 --- a/crates/papyrus_execution/src/state_reader.rs +++ b/crates/papyrus_execution/src/state_reader.rs @@ -5,9 +5,9 @@ mod state_reader_test; use std::cell::Cell; use blockifier::execution::contract_class::{ - ContractClassV0, - ContractClassV1, - RunnableContractClass, + CompiledClassV0, + CompiledClassV1, + RunnableCompiledClass, }; use blockifier::state::errors::StateError; use blockifier::state::state_api::{StateReader as BlockifierStateReader, StateResult}; @@ -15,6 +15,7 @@ use papyrus_common::pending_classes::{ApiContractClass, PendingClassesTrait}; use papyrus_common::state::DeclaredClassHashEntry; use papyrus_storage::state::StateStorageReader; use papyrus_storage::{StorageError, StorageReader}; +use starknet_api::contract_class::SierraVersion; use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; use starknet_api::state::{StateNumber, StorageKey}; use starknet_types_core::felt::Felt; @@ -75,28 +76,31 @@ impl BlockifierStateReader for ExecutionStateReader { .unwrap_or_default()) } - fn get_compiled_contract_class( - &self, - class_hash: ClassHash, - ) -> StateResult { - if let Some(pending_casm) = self - .maybe_pending_data - .as_ref() - .and_then(|pending_data| pending_data.classes.get_compiled_class(class_hash)) - { - return Ok(RunnableContractClass::V1( - ContractClassV1::try_from(pending_casm).map_err(StateError::ProgramError)?, - )); - } - if let Some(ApiContractClass::DeprecatedContractClass(pending_deprecated_class)) = self - .maybe_pending_data - .as_ref() - .and_then(|pending_data| pending_data.classes.get_class(class_hash)) + fn get_compiled_class(&self, class_hash: ClassHash) -> StateResult { + if let Some(pending_classes) = + self.maybe_pending_data.as_ref().map(|pending_data| &pending_data.classes) { - return Ok(RunnableContractClass::V0( - ContractClassV0::try_from(pending_deprecated_class) - .map_err(StateError::ProgramError)?, - )); + if let Some(api_contract_class) = pending_classes.get_class(class_hash) { + match api_contract_class { + ApiContractClass::ContractClass(sierra) => { + if let Some(pending_casm) = pending_classes.get_compiled_class(class_hash) { + let sierra_version = + SierraVersion::extract_from_program(&sierra.sierra_program)?; + let runnable_compiled_class = RunnableCompiledClass::V1( + CompiledClassV1::try_from((pending_casm, sierra_version)) + .map_err(StateError::ProgramError)?, + ); + return Ok(runnable_compiled_class); + } + } + ApiContractClass::DeprecatedContractClass(pending_deprecated_class) => { + return Ok(RunnableCompiledClass::V0( + CompiledClassV0::try_from(pending_deprecated_class) + .map_err(StateError::ProgramError)?, + )); + } + } + } } match get_contract_class( &self.storage_reader.begin_ro_txn().map_err(storage_err_to_state_err)?, @@ -111,6 +115,9 @@ impl BlockifierStateReader for ExecutionStateReader { } Err(ExecutionUtilsError::ProgramError(err)) => Err(StateError::ProgramError(err)), Err(ExecutionUtilsError::StorageError(err)) => Err(storage_err_to_state_err(err)), + Err(ExecutionUtilsError::SierraValidationError(err)) => { + Err(StateError::StarknetApiError(err)) + } } } diff --git a/crates/papyrus_execution/src/state_reader_test.rs b/crates/papyrus_execution/src/state_reader_test.rs index ac16c98afa6..87cd8c50773 100644 --- a/crates/papyrus_execution/src/state_reader_test.rs +++ b/crates/papyrus_execution/src/state_reader_test.rs @@ -2,9 +2,9 @@ use std::cell::Cell; use assert_matches::assert_matches; use blockifier::execution::contract_class::{ - ContractClassV0, - ContractClassV1, - RunnableContractClass, + CompiledClassV0, + CompiledClassV1, + RunnableCompiledClass, }; use blockifier::state::errors::StateError; use blockifier::state::state_api::StateReader; @@ -24,6 +24,7 @@ use papyrus_storage::header::HeaderStorageWriter; use papyrus_storage::state::StateStorageWriter; use papyrus_storage::test_utils::get_test_storage; use starknet_api::block::{BlockBody, BlockHash, BlockHeader, BlockHeaderWithoutHash, BlockNumber}; +use starknet_api::contract_class::SierraVersion; use starknet_api::core::{ClassHash, CompiledClassHash, Nonce}; use starknet_api::hash::StarkHash; use starknet_api::state::{SierraContractClass, StateNumber, ThinStateDiff}; @@ -48,9 +49,11 @@ fn read_state() { let storage_value1 = felt!(888_u128); // The class is not used in the execution, so it can be default. let class0 = SierraContractClass::default(); + let sierra_version0 = SierraVersion::extract_from_program(&class0.sierra_program).unwrap(); let casm0 = get_test_casm(); - let blockifier_casm0 = - RunnableContractClass::V1(ContractClassV1::try_from(casm0.clone()).unwrap()); + let blockifier_casm0 = RunnableCompiledClass::V1( + CompiledClassV1::try_from((casm0.clone(), sierra_version0)).unwrap(), + ); let compiled_class_hash0 = CompiledClassHash(StarkHash::default()); let class_hash1 = ClassHash(1u128.into()); @@ -62,10 +65,13 @@ fn read_state() { let storage_value2 = felt!(999_u128); let class_hash2 = ClassHash(1234u128.into()); let compiled_class_hash2 = CompiledClassHash(StarkHash::TWO); - let mut casm1 = get_test_casm(); - casm1.bytecode[0] = BigUintAsHex { value: 12345u32.into() }; - let blockifier_casm1 = - RunnableContractClass::V1(ContractClassV1::try_from(casm1.clone()).unwrap()); + let mut casm2 = get_test_casm(); + casm2.bytecode[0] = BigUintAsHex { value: 12345u32.into() }; + let class2 = SierraContractClass::default(); + let sierra_version2 = SierraVersion::extract_from_program(&class2.sierra_program).unwrap(); + let blockifier_casm2 = RunnableCompiledClass::V1( + CompiledClassV1::try_from((casm2.clone(), sierra_version2)).unwrap(), + ); let nonce1 = Nonce(felt!(2_u128)); let class_hash3 = ClassHash(567_u128.into()); let class_hash4 = ClassHash(89_u128.into()); @@ -117,7 +123,6 @@ fn read_state() { address0 => nonce0, address1 => Nonce::default(), ), - replaced_classes: indexmap!(), }, ) .unwrap() @@ -163,8 +168,7 @@ fn read_state() { assert_eq!(nonce_after_block_0, Nonce::default()); let class_hash_after_block_0 = state_reader0.get_class_hash_at(address0).unwrap(); assert_eq!(class_hash_after_block_0, ClassHash::default()); - let compiled_contract_class_after_block_0 = - state_reader0.get_compiled_contract_class(class_hash0); + let compiled_contract_class_after_block_0 = state_reader0.get_compiled_class(class_hash0); assert_matches!( compiled_contract_class_after_block_0, Err(StateError::UndeclaredClassHash(class_hash)) if class_hash == class_hash0 @@ -185,12 +189,12 @@ fn read_state() { let class_hash_after_block_1 = state_reader1.get_class_hash_at(address0).unwrap(); assert_eq!(class_hash_after_block_1, class_hash0); let compiled_contract_class_after_block_1 = - state_reader1.get_compiled_contract_class(class_hash0).unwrap(); + state_reader1.get_compiled_class(class_hash0).unwrap(); assert_eq!(compiled_contract_class_after_block_1, blockifier_casm0); - // Test that if we try to get a casm and it's missing, that an error is returned and the field - // `missing_compiled_class` is set to its hash - state_reader1.get_compiled_contract_class(class_hash5).unwrap_err(); + // Test that an error is returned if we try to get a missing casm, and the field + // `missing_compiled_class` is set to the missing casm's hash. + state_reader1.get_compiled_class(class_hash5).unwrap_err(); assert_eq!(state_reader1.missing_compiled_class.get().unwrap(), class_hash5); let state_number2 = StateNumber::unchecked_right_after_block(BlockNumber(2)); @@ -205,7 +209,8 @@ fn read_state() { // Test pending state diff let mut pending_classes = PendingClasses::default(); - pending_classes.add_compiled_class(class_hash2, casm1); + pending_classes.add_compiled_class(class_hash2, casm2); + pending_classes.add_class(class_hash2, ApiContractClass::ContractClass(class2)); pending_classes.add_class(class_hash3, ApiContractClass::ContractClass(class0)); pending_classes .add_class(class_hash4, ApiContractClass::DeprecatedContractClass(class1.clone())); @@ -234,14 +239,14 @@ fn read_state() { assert_eq!(state_reader2.get_compiled_class_hash(class_hash2).unwrap(), compiled_class_hash2); assert_eq!(state_reader2.get_nonce_at(address0).unwrap(), nonce0); assert_eq!(state_reader2.get_nonce_at(address2).unwrap(), nonce1); - assert_eq!(state_reader2.get_compiled_contract_class(class_hash0).unwrap(), blockifier_casm0); - assert_eq!(state_reader2.get_compiled_contract_class(class_hash2).unwrap(), blockifier_casm1); - // Test that if we only got the class without the casm then an error is returned. - state_reader2.get_compiled_contract_class(class_hash3).unwrap_err(); + assert_eq!(state_reader2.get_compiled_class(class_hash0).unwrap(), blockifier_casm0); + assert_eq!(state_reader2.get_compiled_class(class_hash2).unwrap(), blockifier_casm2); + // Test that an error is returned if we only got the class without the casm. + state_reader2.get_compiled_class(class_hash3).unwrap_err(); // Test that if the class is deprecated it is returned. assert_eq!( - state_reader2.get_compiled_contract_class(class_hash4).unwrap(), - RunnableContractClass::V0(ContractClassV0::try_from(class1).unwrap()) + state_reader2.get_compiled_class(class_hash4).unwrap(), + RunnableCompiledClass::V0(CompiledClassV0::try_from(class1).unwrap()) ); // Test get_class_hash_at when the class is replaced. diff --git a/crates/papyrus_execution/src/test_utils.rs b/crates/papyrus_execution/src/test_utils.rs index 861fc4b2316..12550c25cef 100644 --- a/crates/papyrus_execution/src/test_utils.rs +++ b/crates/papyrus_execution/src/test_utils.rs @@ -21,6 +21,7 @@ use starknet_api::block::{ GasPrice, GasPricePerToken, }; +use starknet_api::contract_class::SierraVersion; use starknet_api::core::{ ChainId, ClassHash, @@ -157,7 +158,6 @@ pub fn prepare_storage(mut storage_writer: StorageWriter) { *DEPRECATED_CONTRACT_ADDRESS => Nonce::default(), *ACCOUNT_ADDRESS => Nonce::default(), ), - replaced_classes: indexmap!(), }, ) .unwrap() @@ -219,7 +219,7 @@ pub fn execute_simulate_transactions( &get_test_execution_config(), charge_fee, validate, - // TODO: Consider testing without overriding DA (It's already tested in the RPC) + // TODO(DanB): Consider testing without overriding DA (It's already tested in the RPC) true, ) .unwrap() @@ -312,6 +312,7 @@ impl TxsScenarioBuilder { DUMMY_SIERRA_SIZE, 0, false, + SierraVersion::LATEST, ); self.txs.push(tx); self diff --git a/crates/papyrus_load_test/Cargo.toml b/crates/papyrus_load_test/Cargo.toml index b321a4481cc..ce1ffdaf6ae 100644 --- a/crates/papyrus_load_test/Cargo.toml +++ b/crates/papyrus_load_test/Cargo.toml @@ -17,7 +17,7 @@ rand.workspace = true reqwest.workspace = true serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true, features = ["arbitrary_precision"] } -starknet_api.workspace = true +starknet_api = { workspace = true, features = ["testing"] } tokio.workspace = true [dev-dependencies] diff --git a/crates/papyrus_monitoring_gateway/src/gateway_test.rs b/crates/papyrus_monitoring_gateway/src/gateway_test.rs index a075bca6405..4cd356c6abe 100644 --- a/crates/papyrus_monitoring_gateway/src/gateway_test.rs +++ b/crates/papyrus_monitoring_gateway/src/gateway_test.rs @@ -5,7 +5,7 @@ use axum::body::Body; use axum::http::{Request, StatusCode}; use axum::response::Response; use axum::Router; -use metrics::{absolute_counter, describe_counter, register_counter}; +use metrics::{counter, describe_counter}; use metrics_exporter_prometheus::PrometheusBuilder; use papyrus_storage::{table_names, test_utils}; use pretty_assertions::assert_eq; @@ -182,9 +182,8 @@ async fn with_metrics() { let metric_name = "metric_name"; let metric_help = "metric_help"; let metric_value = 8224; - register_counter!(metric_name); + counter!(metric_name).absolute(metric_value); describe_counter!(metric_name, metric_help); - absolute_counter!(metric_name, metric_value); let response = request_app(app, "metrics").await; diff --git a/crates/papyrus_network/Cargo.toml b/crates/papyrus_network/Cargo.toml index 04a22212a76..82e2a399e89 100644 --- a/crates/papyrus_network/Cargo.toml +++ b/crates/papyrus_network/Cargo.toml @@ -29,12 +29,12 @@ libp2p = { workspace = true, features = [ "yamux", ] } metrics.workspace = true -papyrus_common.workspace = true papyrus_config.workspace = true papyrus_network_types.workspace = true replace_with.workspace = true serde = { workspace = true, features = ["derive"] } starknet_api.workspace = true +starknet_sequencer_metrics.workspace = true thiserror.workspace = true tokio = { workspace = true, features = ["full", "sync"] } tokio-retry.workspace = true diff --git a/crates/papyrus_network/src/bin/network_stress_test/README.md b/crates/papyrus_network/src/bin/network_stress_test/README.md new file mode 100644 index 00000000000..4d3f322539a --- /dev/null +++ b/crates/papyrus_network/src/bin/network_stress_test/README.md @@ -0,0 +1,41 @@ +# Network Stress Test + +## Setup and Run Stress Test + +1. **Create Remote Engines** + + Create 5 gcloud VM instances. Make sure to have the necessary RAM and disk space. Each instance should be named in the following pattern: + + ``` + -0, ... ,-4 + ``` + +2. **Set Bootstrap Node** + + Find the internal IP of your bootstrap node in the VM instances chart on google cloud console. Paste it into the test_config.json file into the bootstrap_peer_multaddr value instead of its placeholder. + +3. **Install Rust and clone repository** + + For all 5 instances run: + + ``` + gcloud compute ssh -0 --project -- 'cd && sudo apt install -y git unzip clang && curl https://sh.rustup.rs -sSf | sh -s -- -y && source "$HOME/.cargo/env" && git clone https://github.com/starkware-libs/sequencer.git; cd sequencer && sudo scripts/dependencies.sh cargo build --release -p papyrus_network --bin network_stress_test' + ``` + +4. **Run test** + + ``` + PROJECT_ID= BASE_INSTANCE_NAME= ZONE= ./run_broadcast_stress_test.sh + ``` + +5. **Results** + + Results are retrieved from VM instances and saved to /output.csv. You can change the default path by adjusting the config file. + +## Pull repo updates to virtual machines + +1. **Run** + + ``` + PROJECT_ID= BASE_INSTANCE_NAME= ZONE= ./pull_stress_test.sh + ``` diff --git a/crates/papyrus_network/src/bin/network_stress_test/converters.rs b/crates/papyrus_network/src/bin/network_stress_test/converters.rs index d3b8ae628bd..b0eca852118 100644 --- a/crates/papyrus_network/src/bin/network_stress_test/converters.rs +++ b/crates/papyrus_network/src/bin/network_stress_test/converters.rs @@ -1,21 +1,37 @@ +use std::mem::size_of; +use std::str::FromStr; use std::time::{Duration, SystemTime}; -struct StressTestMessage { - id: u32, - payload: Vec, - time: SystemTime, +use libp2p::PeerId; + +pub const METADATA_SIZE: usize = size_of::() + size_of::() + size_of::() + 38; + +#[derive(Debug, Clone)] +pub struct StressTestMessage { + pub id: u32, + pub payload: Vec, + pub time: SystemTime, + pub peer_id: String, +} + +impl StressTestMessage { + pub fn new(id: u32, payload: Vec, peer_id: String) -> Self { + StressTestMessage { id, payload, time: SystemTime::now(), peer_id } + } } impl From for Vec { fn from(value: StressTestMessage) -> Self { - let StressTestMessage { id, mut payload, time } = value; + let StressTestMessage { id, mut payload, time, peer_id } = value; let id = id.to_be_bytes().to_vec(); let time = time.duration_since(SystemTime::UNIX_EPOCH).unwrap(); let seconds = time.as_secs().to_be_bytes().to_vec(); let nanos = time.subsec_nanos().to_be_bytes().to_vec(); + let peer_id = PeerId::from_str(&peer_id).unwrap().to_bytes(); payload.extend(id); payload.extend(seconds); payload.extend(nanos); + payload.extend(peer_id); payload } } @@ -24,12 +40,13 @@ impl From> for StressTestMessage { // This auto implements TryFrom> for StressTestMessage fn from(mut value: Vec) -> Self { let vec_size = value.len(); - let payload_size = vec_size - 12; + let payload_size = vec_size - METADATA_SIZE; let id_and_time = value.split_off(payload_size); let id = u32::from_be_bytes(id_and_time[0..4].try_into().unwrap()); let seconds = u64::from_be_bytes(id_and_time[4..12].try_into().unwrap()); let nanos = u32::from_be_bytes(id_and_time[12..16].try_into().unwrap()); let time = SystemTime::UNIX_EPOCH + Duration::new(seconds, nanos); - StressTestMessage { id, payload: value, time } + let peer_id = PeerId::from_bytes(&id_and_time[16..]).unwrap().to_string(); + StressTestMessage { id, payload: value, time, peer_id } } } diff --git a/crates/papyrus_network/src/bin/network_stress_test/main.rs b/crates/papyrus_network/src/bin/network_stress_test/main.rs index 1591c86df99..726e8cfcc24 100644 --- a/crates/papyrus_network/src/bin/network_stress_test/main.rs +++ b/crates/papyrus_network/src/bin/network_stress_test/main.rs @@ -1,3 +1,4 @@ mod converters; +mod utils; fn main() {} diff --git a/crates/papyrus_network/src/bin/network_stress_test/pull_stress_test.sh b/crates/papyrus_network/src/bin/network_stress_test/pull_stress_test.sh new file mode 100755 index 00000000000..4de24cc3747 --- /dev/null +++ b/crates/papyrus_network/src/bin/network_stress_test/pull_stress_test.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +# TODO(eitan): support generic amount of instances +if [[ -z "$BASE_INSTANCE_NAME" || -z "$PROJECT_ID" || -z "$ZONE" ]]; then + echo "Error: BASE_INSTANCE_NAME, PROJECT_ID, and ZONE must be set." + echo "Each instance name should be of the form -, where instance number is between 0 and 4. ie 'papyrus-network-0'" + exit 1 +fi + +PATH_TO_REPO="~/sequencer" + +# Loop over instances from 0 to 4 +for i in {0..4}; do +( + INSTANCE_NAME="${BASE_INSTANCE_NAME}-${i}" + echo "Connecting to $INSTANCE_NAME..." + gcloud compute ssh "$INSTANCE_NAME" --project "$PROJECT_ID" --zone "$ZONE" --tunnel-through-iap -- "cd $PATH_TO_REPO && git pull" + echo "Finished with $INSTANCE_NAME." +) & +done +echo "All VMs have pulled." diff --git a/crates/papyrus_network/src/bin/network_stress_test/run_broadcast_stress_test.sh b/crates/papyrus_network/src/bin/network_stress_test/run_broadcast_stress_test.sh new file mode 100755 index 00000000000..9eb4eb9015f --- /dev/null +++ b/crates/papyrus_network/src/bin/network_stress_test/run_broadcast_stress_test.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +if [[ -z "$BASE_INSTANCE_NAME" || -z "$PROJECT_ID" || -z "$ZONE" ]]; then + echo "Error: BASE_INSTANCE_NAME, PROJECT_ID, and ZONE must be set." + echo "Instance name must be set in the format 'BASE_INSTANCE_NAME-0' -> 'BASE_INSTANCE_NAME-4'." + exit 1 +fi + +# Project ID and base instance name +PATH_TO_REPO="~/sequencer" +PATH_TO_ENV="~/.cargo/env" + +# Commands to execute on each instance +COMMAND_PATH_BOOT="cd ${PATH_TO_REPO} && source ${PATH_TO_ENV} && cargo run --release -p papyrus_network --bin network_stress_test" +COMMAND_PATH="cd ${PATH_TO_REPO} && source ${PATH_TO_ENV} && cargo run --release -p papyrus_network --bin network_stress_test -- crates/papyrus_network/src/bin/network_stress_test/test_config.json" + + +# Store the process IDs of all opened processes +declare -a process_pids + +# Start the boot command on the first instance (instance 0) +( + echo "Starting boot command on ${BASE_INSTANCE_NAME}-0..." + gcloud compute ssh "${BASE_INSTANCE_NAME}-0" --project "${PROJECT_ID}" --zone "${ZONE}" --tunnel-through-iap -- "${COMMAND_PATH_BOOT}" + echo "Boot command finished on ${BASE_INSTANCE_NAME}-0." +) & +process_pids+=($!) # Store the PID of the background process + +# Run the command on instances 1 to 4 +for i in {1..4}; do + ( + echo "Starting command on ${BASE_INSTANCE_NAME}-${i}..." + gcloud compute ssh "${BASE_INSTANCE_NAME}-${i}" --project "${PROJECT_ID}" --zone "${ZONE}" --tunnel-through-iap -- "${COMMAND_PATH}" + echo "Command finished on ${BASE_INSTANCE_NAME}-${i}." + ) & + process_pids+=($!) # Store the PID of the background process +done + +# Wait for all commands to complete +for pid in "${process_pids[@]}"; do + wait "$pid" +done +echo "All commands completed." + +# Retrieve output.csv files from each instance with an incremented filename +for i in {0..4}; do + ( + echo "Retrieving output.csv from ${BASE_INSTANCE_NAME}-${i}..." + gcloud compute ssh "${BASE_INSTANCE_NAME}-${i}" --project "${PROJECT_ID}" --zone "${ZONE}" --tunnel-through-iap -- "cat ${PATH_TO_REPO}/crates/papyrus_network/src/bin/network_stress_test/output.csv" > output${i}.csv + echo "Retrieved output.csv from ${BASE_INSTANCE_NAME}-${i} and saved as output${i}.csv." + ) & +done + +# Wait for file retrieval processes to complete +wait +echo "All output files retrieved." diff --git a/crates/papyrus_network/src/bin/network_stress_test/utils.rs b/crates/papyrus_network/src/bin/network_stress_test/utils.rs new file mode 100644 index 00000000000..a905aad18d8 --- /dev/null +++ b/crates/papyrus_network/src/bin/network_stress_test/utils.rs @@ -0,0 +1,130 @@ +use std::collections::{BTreeMap, HashSet}; +use std::str::FromStr; +use std::time::{SystemTime, UNIX_EPOCH}; +use std::vec; + +use libp2p::identity::Keypair; +use libp2p::Multiaddr; +use papyrus_config::dumping::{append_sub_config_name, ser_param, SerializeConfig}; +use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; +use papyrus_network::NetworkConfig; +use serde::{Deserialize, Serialize, Serializer}; + +pub const BOOTSTRAP_CONFIG_FILE_PATH: &str = + "crates/papyrus_network/src/bin/network_stress_test/bootstrap_test_config.json"; +pub const BOOTSTRAP_OUTPUT_FILE_PATH: &str = + "crates/papyrus_network/src/bin/network_stress_test/bootstrap_output.csv"; +pub const DEFAULT_CONFIG_FILE_PATH: &str = + "crates/papyrus_network/src/bin/network_stress_test/test_config.json"; +pub const DEFAULT_OUTPUT_FILE_PATH: &str = + "crates/papyrus_network/src/bin/network_stress_test/output.csv"; + +#[derive(Debug, Deserialize, Serialize)] +pub struct TestConfig { + pub network_config: NetworkConfig, + pub buffer_size: usize, + pub message_size: usize, + pub num_messages: u32, + pub output_path: String, +} + +impl SerializeConfig for TestConfig { + fn dump(&self) -> BTreeMap { + let mut config = BTreeMap::from_iter([ + ser_param( + "buffer_size", + &self.buffer_size, + "The buffer size for the network receiver.", + ParamPrivacyInput::Public, + ), + ser_param( + "message_size", + &self.message_size, + "The size of the payload for the test messages.", + ParamPrivacyInput::Public, + ), + ser_param( + "num_messages", + &self.num_messages, + "The amount of messages to send and receive.", + ParamPrivacyInput::Public, + ), + ser_param( + "output_path", + &self.output_path, + "The path of the output file.", + ParamPrivacyInput::Public, + ), + ]); + config.extend(append_sub_config_name(self.network_config.dump(), "network_config")); + config + } +} + +impl Default for TestConfig { + fn default() -> Self { + Self { + network_config: NetworkConfig::default(), + buffer_size: 1000, + message_size: 1000, + num_messages: 10000, + output_path: BOOTSTRAP_OUTPUT_FILE_PATH.to_string(), + } + } +} + +impl TestConfig { + #[allow(dead_code)] + pub fn create_config_files() { + let secret_key = vec![0; 32]; + let keypair = Keypair::ed25519_from_bytes(secret_key.clone()).unwrap(); + let peer_id = keypair.public().to_peer_id(); + + let _ = TestConfig { + network_config: NetworkConfig { + port: 10000, + secret_key: Some(secret_key), + ..Default::default() + }, + ..Default::default() + } + .dump_to_file(&vec![], &HashSet::new(), BOOTSTRAP_CONFIG_FILE_PATH); + let _ = TestConfig { + network_config: NetworkConfig { + port: 10002, + bootstrap_peer_multiaddr: Some( + Multiaddr::from_str(&format!("/ip4/127.0.0.1/tcp/10000/p2p/{}", peer_id)) + .unwrap(), + ), + ..Default::default() + }, + output_path: DEFAULT_OUTPUT_FILE_PATH.to_string(), + ..Default::default() + } + .dump_to_file(&vec![], &HashSet::new(), DEFAULT_CONFIG_FILE_PATH); + } +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct Record { + pub peer_id: String, + pub id: u32, + #[serde(serialize_with = "serialize_system_time_as_u128_millis")] + pub start_time: SystemTime, + #[serde(serialize_with = "serialize_system_time_as_u128_millis")] + pub end_time: SystemTime, + pub duration: i128, +} + +pub fn serialize_system_time_as_u128_millis( + time: &SystemTime, + serializer: S, +) -> Result +where + S: Serializer, +{ + let duration_since_epoch = + time.duration_since(UNIX_EPOCH).map_err(serde::ser::Error::custom)?; + let millis = duration_since_epoch.as_millis(); + serializer.serialize_u128(millis) +} diff --git a/crates/papyrus_network/src/bin_utils/mod.rs b/crates/papyrus_network/src/bin_utils/mod.rs deleted file mode 100644 index 53cd97449c5..00000000000 --- a/crates/papyrus_network/src/bin_utils/mod.rs +++ /dev/null @@ -1,47 +0,0 @@ -use std::str::FromStr; -use std::time::Duration; - -use libp2p::identity::Keypair; -use libp2p::swarm::NetworkBehaviour; -use libp2p::{noise, yamux, Multiaddr, Swarm, SwarmBuilder}; -use tracing::debug; - -pub fn build_swarm( - listen_addresses: Vec, - idle_connection_timeout: Duration, - secret_key: Option>, - behaviour: impl FnOnce(Keypair) -> Behaviour, -) -> Swarm -where -{ - let listen_addresses = listen_addresses.iter().map(|listen_address| { - Multiaddr::from_str(listen_address) - .unwrap_or_else(|_| panic!("Unable to parse address {}", listen_address)) - }); - debug!("Creating swarm with listen addresses: {:?}", listen_addresses); - - let key_pair = match secret_key { - Some(secret_key) => { - Keypair::ed25519_from_bytes(secret_key).expect("Error while parsing secret key") - } - None => Keypair::generate_ed25519(), - }; - let mut swarm = SwarmBuilder::with_existing_identity(key_pair) - .with_tokio() - .with_tcp(Default::default(), noise::Config::new, yamux::Config::default) - .expect("Error building TCP transport") - .with_dns() - .expect("Error building DNS transport") - // TODO: quic transpot does not work (failure appears in the command line when running in debug mode) - // .with_quic() - .with_behaviour(|key| behaviour(key.clone())) - .expect("Error while building the swarm") - .with_swarm_config(|cfg| cfg.with_idle_connection_timeout(idle_connection_timeout)) - .build(); - for listen_address in listen_addresses { - swarm - .listen_on(listen_address.clone()) - .unwrap_or_else(|_| panic!("Error while binding to {}", listen_address)); - } - swarm -} diff --git a/crates/papyrus_network/src/discovery/discovery_test.rs b/crates/papyrus_network/src/discovery/discovery_test.rs index 2526a36be3d..fbdc94fd88e 100644 --- a/crates/papyrus_network/src/discovery/discovery_test.rs +++ b/crates/papyrus_network/src/discovery/discovery_test.rs @@ -5,7 +5,6 @@ use std::task::{Context, Poll}; use std::time::Duration; use assert_matches::assert_matches; -use futures::future::pending; use futures::{FutureExt, Stream, StreamExt}; use libp2p::core::{ConnectedPoint, Endpoint}; use libp2p::swarm::behaviour::ConnectionEstablished; @@ -19,16 +18,10 @@ use libp2p::swarm::{ ToSwarm, }; use libp2p::{Multiaddr, PeerId}; -use tokio::select; -use tokio::sync::Mutex; use tokio::time::timeout; use void::Void; -use super::kad_impl::KadToOtherBehaviourEvent; use super::{Behaviour, DiscoveryConfig, RetryConfig, ToOtherBehaviourEvent}; -use crate::mixed_behaviour; -use crate::mixed_behaviour::BridgedBehaviour; -use crate::test_utils::next_on_mutex_stream; const TIMEOUT: Duration = Duration::from_secs(1); const BOOTSTRAP_DIAL_SLEEP_MILLIS: u64 = 1000; // 1 second @@ -56,6 +49,8 @@ impl Stream for Behaviour { } } +// TODO(shahak): Make the tests resilient to the order of events. + // In case we have a bug when we return pending and then return an event. const TIMES_TO_CHECK_FOR_PENDING_EVENT: usize = 5; @@ -66,7 +61,7 @@ fn assert_no_event(behaviour: &mut Behaviour) { } #[tokio::test] -async fn discovery_outputs_dial_request_on_start_without_query() { +async fn discovery_outputs_dial_request_and_query_on_start() { let bootstrap_peer_id = PeerId::random(); let bootstrap_peer_address = Multiaddr::empty(); @@ -78,6 +73,12 @@ async fn discovery_outputs_dial_request_on_start_without_query() { ToSwarm::Dial{opts} if opts.get_peer_id() == Some(bootstrap_peer_id) ); + let event = timeout(TIMEOUT, behaviour.next()).await.unwrap().unwrap(); + assert_matches!( + event, + ToSwarm::GenerateEvent(ToOtherBehaviourEvent::RequestKadQuery(_peer_id)) + ); + assert_no_event(&mut behaviour); } @@ -103,7 +104,9 @@ async fn discovery_redials_on_dial_failure() { let bootstrap_peer_id = PeerId::random(); let bootstrap_peer_address = Multiaddr::empty(); - let mut behaviour = Behaviour::new(CONFIG, bootstrap_peer_id, bootstrap_peer_address); + let mut config = CONFIG.clone(); + config.heartbeat_interval = BOOTSTRAP_DIAL_SLEEP * 2; + let mut behaviour = Behaviour::new(config, bootstrap_peer_id, bootstrap_peer_address); let event = timeout(TIMEOUT, behaviour.next()).await.unwrap().unwrap(); assert_matches!( @@ -111,6 +114,9 @@ async fn discovery_redials_on_dial_failure() { ToSwarm::Dial{opts} if opts.get_peer_id() == Some(bootstrap_peer_id) ); + // Consume the first query event. + behaviour.next().await.unwrap(); + behaviour.on_swarm_event(FromSwarm::DialFailure(DialFailure { peer_id: Some(bootstrap_peer_id), error: &DialError::Aborted, @@ -229,16 +235,17 @@ async fn discovery_outputs_single_query_after_connecting() { } #[tokio::test] -async fn discovery_outputs_single_query_on_query_finished() { - let mut behaviour = create_behaviour_and_connect_to_bootstrap_node(CONFIG).await; +async fn discovery_sleeps_between_queries() { + let mut config = CONFIG; + const HEARTBEAT_INTERVAL: Duration = Duration::from_secs(1); + config.heartbeat_interval = HEARTBEAT_INTERVAL; + + let mut behaviour = create_behaviour_and_connect_to_bootstrap_node(config).await; // Consume the initial query event. timeout(TIMEOUT, behaviour.next()).await.unwrap(); - behaviour.on_other_behaviour_event(&mixed_behaviour::ToOtherBehaviourEvent::Kad( - KadToOtherBehaviourEvent::KadQueryFinished, - )); - let event = timeout(TIMEOUT, behaviour.next()).await.unwrap().unwrap(); + let event = check_event_happens_after_given_duration(&mut behaviour, HEARTBEAT_INTERVAL).await; assert_matches!( event, ToSwarm::GenerateEvent(ToOtherBehaviourEvent::RequestKadQuery(_peer_id)) @@ -246,49 +253,35 @@ async fn discovery_outputs_single_query_on_query_finished() { } #[tokio::test] -async fn discovery_sleeps_between_queries() { +async fn discovery_performs_queries_even_if_not_connected_to_bootstrap_peer() { let mut config = CONFIG; const HEARTBEAT_INTERVAL: Duration = Duration::from_secs(1); + const BOOTSTRAP_DIAL_SLEEP: Duration = Duration::from_secs(5); config.heartbeat_interval = HEARTBEAT_INTERVAL; + config.bootstrap_dial_retry_config.base_delay_millis = + BOOTSTRAP_DIAL_SLEEP.as_millis().try_into().unwrap(); + config.bootstrap_dial_retry_config.max_delay_seconds = BOOTSTRAP_DIAL_SLEEP; - let mut behaviour = create_behaviour_and_connect_to_bootstrap_node(config).await; + let bootstrap_peer_id = PeerId::random(); + let bootstrap_peer_address = Multiaddr::empty(); - // Consume the initial query event. + let mut behaviour = Behaviour::new(config, bootstrap_peer_id, bootstrap_peer_address.clone()); + + // Consume the initial dial and query events. + timeout(TIMEOUT, behaviour.next()).await.unwrap(); timeout(TIMEOUT, behaviour.next()).await.unwrap(); - // Report that the query has finished - behaviour.on_other_behaviour_event(&mixed_behaviour::ToOtherBehaviourEvent::Kad( - KadToOtherBehaviourEvent::KadQueryFinished, - )); + // Simulate dial failure. + behaviour.on_swarm_event(FromSwarm::DialFailure(DialFailure { + peer_id: Some(bootstrap_peer_id), + error: &DialError::Aborted, + connection_id: ConnectionId::new_unchecked(0), + })); + // Check that we get a new Kad query after HEARTBEAT_INTERVAL. let event = check_event_happens_after_given_duration(&mut behaviour, HEARTBEAT_INTERVAL).await; assert_matches!( event, ToSwarm::GenerateEvent(ToOtherBehaviourEvent::RequestKadQuery(_peer_id)) ); } - -#[tokio::test] -async fn discovery_awakes_on_query_finished() { - let mut behaviour = create_behaviour_and_connect_to_bootstrap_node(CONFIG).await; - - // Consume the initial query event. - timeout(TIMEOUT, behaviour.next()).await.unwrap(); - - let mutex = Mutex::new(behaviour); - - select! { - _ = async { - mutex.lock().await.on_other_behaviour_event( - &mixed_behaviour::ToOtherBehaviourEvent::Kad( - KadToOtherBehaviourEvent::KadQueryFinished, - ) - ); - timeout(TIMEOUT, pending::<()>()).await.unwrap(); - } => {}, - maybe_event = next_on_mutex_stream(&mutex) => assert_matches!( - maybe_event.unwrap(), - ToSwarm::GenerateEvent(ToOtherBehaviourEvent::RequestKadQuery(_peer_id)) - ), - } -} diff --git a/crates/papyrus_network/src/discovery/flow_test.rs b/crates/papyrus_network/src/discovery/flow_test.rs index 7bc33d73391..97ce014fd53 100644 --- a/crates/papyrus_network/src/discovery/flow_test.rs +++ b/crates/papyrus_network/src/discovery/flow_test.rs @@ -15,7 +15,7 @@ use super::{Behaviour, DiscoveryConfig}; use crate::mixed_behaviour; use crate::mixed_behaviour::{BridgedBehaviour, MixedBehaviour}; use crate::peer_manager::PeerManagerConfig; -use crate::utils::StreamHashMap; +use crate::utils::StreamMap; #[derive(NetworkBehaviour)] struct DiscoveryMixedBehaviour { @@ -65,7 +65,7 @@ async fn all_nodes_have_same_bootstrap_peer() { DiscoveryMixedBehaviour::new(keypair, Some(bootstrap_peer_multiaddr.clone())) }) }); - let mut swarms_stream = StreamHashMap::new( + let mut swarms_stream = StreamMap::new( iter::once(bootstrap_swarm) .chain(swarms) .map(|swarm| (*swarm.local_peer_id(), swarm)) diff --git a/crates/papyrus_network/src/discovery/kad_impl.rs b/crates/papyrus_network/src/discovery/kad_impl.rs index 17b72d30639..7bed62af142 100644 --- a/crates/papyrus_network/src/discovery/kad_impl.rs +++ b/crates/papyrus_network/src/discovery/kad_impl.rs @@ -1,36 +1,16 @@ use libp2p::kad; -use tracing::{error, info}; +use tracing::info; use super::identify_impl::IdentifyToOtherBehaviourEvent; use crate::mixed_behaviour::BridgedBehaviour; use crate::{mixed_behaviour, peer_manager}; #[derive(Debug)] -pub enum KadToOtherBehaviourEvent { - KadQueryFinished, -} +pub enum KadToOtherBehaviourEvent {} impl From for mixed_behaviour::Event { - fn from(event: kad::Event) -> Self { - match event { - kad::Event::OutboundQueryProgressed { - id: _, - result: kad::QueryResult::GetClosestPeers(result), - .. - } => { - if let Err(err) = result { - error!("Kademlia query failed on {err:?}"); - } - mixed_behaviour::Event::ToOtherBehaviourEvent( - mixed_behaviour::ToOtherBehaviourEvent::Kad( - KadToOtherBehaviourEvent::KadQueryFinished, - ), - ) - } - _ => mixed_behaviour::Event::ToOtherBehaviourEvent( - mixed_behaviour::ToOtherBehaviourEvent::NoOp, - ), - } + fn from(_event: kad::Event) -> Self { + mixed_behaviour::Event::ToOtherBehaviourEvent(mixed_behaviour::ToOtherBehaviourEvent::NoOp) } } diff --git a/crates/papyrus_network/src/discovery/mod.rs b/crates/papyrus_network/src/discovery/mod.rs index fb37d2e57c7..bcd51feeb47 100644 --- a/crates/papyrus_network/src/discovery/mod.rs +++ b/crates/papyrus_network/src/discovery/mod.rs @@ -6,12 +6,11 @@ pub mod identify_impl; pub mod kad_impl; use std::collections::BTreeMap; -use std::task::{ready, Context, Poll, Waker}; +use std::task::{ready, Context, Poll}; use std::time::Duration; -use futures::future::BoxFuture; +use futures::future::{pending, select, BoxFuture, Either}; use futures::{pin_mut, Future, FutureExt}; -use kad_impl::KadToOtherBehaviourEvent; use libp2p::core::Endpoint; use libp2p::swarm::behaviour::ConnectionEstablished; use libp2p::swarm::dial_opts::{DialOpts, PeerCondition}; @@ -42,8 +41,6 @@ use crate::mixed_behaviour::BridgedBehaviour; pub struct Behaviour { config: DiscoveryConfig, - // TODO(shahak): Consider running several queries in parallel - is_query_running: bool, bootstrap_peer_address: Multiaddr, bootstrap_peer_id: PeerId, is_dialing_to_bootstrap_peer: bool, @@ -51,7 +48,6 @@ pub struct Behaviour { sleep_future_for_dialing_bootstrap_peer: Option>, is_connected_to_bootstrap_peer: bool, is_bootstrap_in_kad_routing_table: bool, - wakers_waiting_for_query_to_finish: Vec, bootstrap_dial_retry_strategy: ExponentialBackoff, query_sleep_future: Option>, } @@ -94,8 +90,6 @@ impl NetworkBehaviour for Behaviour { self.is_dialing_to_bootstrap_peer = false; // For the case that the reason for failure is consistent (e.g the bootstrap peer // is down), we sleep before redialing - // TODO(shahak): Consider increasing the time after each failure, the same way we - // do in starknet client. self.sleep_future_for_dialing_bootstrap_peer = Some( tokio::time::sleep(self.bootstrap_dial_retry_strategy.next().expect( "Dial sleep strategy ended even though it's an infinite iterator.", @@ -118,6 +112,7 @@ impl NetworkBehaviour for Behaviour { }) if peer_id == self.bootstrap_peer_id && remaining_established == 0 => { self.is_connected_to_bootstrap_peer = false; self.is_dialing_to_bootstrap_peer = false; + self.is_bootstrap_in_kad_routing_table = false; } FromSwarm::AddressChange(AddressChange { peer_id, .. }) if peer_id == self.bootstrap_peer_id => @@ -141,29 +136,7 @@ impl NetworkBehaviour for Behaviour { cx: &mut Context<'_>, ) -> Poll::FromBehaviour>> { - if !self.is_dialing_to_bootstrap_peer && !self.is_connected_to_bootstrap_peer { - if let Some(sleep_future) = &mut self.sleep_future_for_dialing_bootstrap_peer { - pin_mut!(sleep_future); - ready!(sleep_future.poll(cx)); - } - self.is_dialing_to_bootstrap_peer = true; - self.sleep_future_for_dialing_bootstrap_peer = None; - return Poll::Ready(ToSwarm::Dial { - opts: DialOpts::peer_id(self.bootstrap_peer_id) - .addresses(vec![self.bootstrap_peer_address.clone()]) - // The peer manager might also be dialing to the bootstrap node. - .condition(PeerCondition::DisconnectedAndNotDialing) - .build(), - }); - } - - // If we're not connected to any node, then each Kademlia query we make will automatically - // return without any peers. Running queries in that mode will add unnecessary overload to - // the swarm. - if !self.is_connected_to_bootstrap_peer { - return Poll::Pending; - } - if !self.is_bootstrap_in_kad_routing_table { + if self.is_connected_to_bootstrap_peer && !self.is_bootstrap_in_kad_routing_table { self.is_bootstrap_in_kad_routing_table = true; return Poll::Ready(ToSwarm::GenerateEvent( ToOtherBehaviourEvent::FoundListenAddresses { @@ -173,19 +146,55 @@ impl NetworkBehaviour for Behaviour { )); } - if self.is_query_running { - self.wakers_waiting_for_query_to_finish.push(cx.waker().clone()); - return Poll::Pending; - } - if let Some(sleep_future) = &mut self.query_sleep_future { - pin_mut!(sleep_future); - ready!(sleep_future.poll(cx)); - } - self.is_query_running = true; - self.query_sleep_future = None; - Poll::Ready(ToSwarm::GenerateEvent(ToOtherBehaviourEvent::RequestKadQuery( - libp2p::identity::PeerId::random(), - ))) + // Unpacking self so that we can create 2 futures that use different members of self + let Self { + is_dialing_to_bootstrap_peer, + is_connected_to_bootstrap_peer, + sleep_future_for_dialing_bootstrap_peer, + bootstrap_peer_id, + bootstrap_peer_address, + query_sleep_future, + config, + .. + } = self; + + let bootstrap_dial_future = async move { + if !(*is_dialing_to_bootstrap_peer) && !(*is_connected_to_bootstrap_peer) { + if let Some(sleep_future) = sleep_future_for_dialing_bootstrap_peer { + sleep_future.await; + } + *is_dialing_to_bootstrap_peer = true; + *sleep_future_for_dialing_bootstrap_peer = None; + return ToSwarm::Dial { + opts: DialOpts::peer_id(*bootstrap_peer_id) + .addresses(vec![bootstrap_peer_address.clone()]) + // The peer manager might also be dialing to the bootstrap node. + .condition(PeerCondition::DisconnectedAndNotDialing) + .build(), + }; + } + // We're already connected to the bootstrap peer. Nothing to do + // TODO(Shahak): register a waker here and wake it when we receive an event that we've + // disconnected from the bootstrap peer. + pending().await + }; + pin_mut!(bootstrap_dial_future); + let kad_future = async move { + if let Some(sleep_future) = query_sleep_future { + sleep_future.await; + } + *query_sleep_future = Some(tokio::time::sleep(config.heartbeat_interval).boxed()); + ToSwarm::GenerateEvent(ToOtherBehaviourEvent::RequestKadQuery( + libp2p::identity::PeerId::random(), + )) + }; + pin_mut!(kad_future); + + // polling both futures together since each of them contains sleep. + let select_future = select(bootstrap_dial_future, kad_future); + pin_mut!(select_future); + let (Either::Left((event, _)) | Either::Right((event, _))) = ready!(select_future.poll(cx)); + Poll::Ready(event) } } @@ -279,14 +288,12 @@ impl Behaviour { let bootstrap_dial_retry_strategy = config.bootstrap_dial_retry_config.strategy(); Self { config, - is_query_running: false, bootstrap_peer_id, bootstrap_peer_address, is_dialing_to_bootstrap_peer: false, sleep_future_for_dialing_bootstrap_peer: None, is_connected_to_bootstrap_peer: false, is_bootstrap_in_kad_routing_table: false, - wakers_waiting_for_query_to_finish: Vec::new(), bootstrap_dial_retry_strategy, query_sleep_future: None, } @@ -312,16 +319,5 @@ impl From for mixed_behaviour::Event { } impl BridgedBehaviour for Behaviour { - fn on_other_behaviour_event(&mut self, event: &mixed_behaviour::ToOtherBehaviourEvent) { - let mixed_behaviour::ToOtherBehaviourEvent::Kad(KadToOtherBehaviourEvent::KadQueryFinished) = - event - else { - return; - }; - for waker in self.wakers_waiting_for_query_to_finish.drain(..) { - waker.wake(); - } - self.query_sleep_future = Some(tokio::time::sleep(self.config.heartbeat_interval).boxed()); - self.is_query_running = false; - } + fn on_other_behaviour_event(&mut self, _event: &mixed_behaviour::ToOtherBehaviourEvent) {} } diff --git a/crates/papyrus_network/src/e2e_broadcast_test.rs b/crates/papyrus_network/src/e2e_broadcast_test.rs index 5fca0a93651..cfdae3be7a0 100644 --- a/crates/papyrus_network/src/e2e_broadcast_test.rs +++ b/crates/papyrus_network/src/e2e_broadcast_test.rs @@ -49,7 +49,7 @@ async fn create_swarm(bootstrap_peer_multiaddr: Option) -> Swarm, ) -> GenericNetworkManager> { - GenericNetworkManager::generic_new(swarm, None) + GenericNetworkManager::generic_new(swarm, None, None) } const BUFFER_SIZE: usize = 100; diff --git a/crates/papyrus_network/src/lib.rs b/crates/papyrus_network/src/lib.rs index 136010f92e8..f03316e49a0 100644 --- a/crates/papyrus_network/src/lib.rs +++ b/crates/papyrus_network/src/lib.rs @@ -2,7 +2,6 @@ /// to the [`Starknet p2p specs`] /// /// [`Starknet p2p specs`]: https://github.com/starknet-io/starknet-p2p-specs/ -mod bin_utils; mod discovery; #[cfg(test)] mod e2e_broadcast_test; @@ -38,11 +37,10 @@ use serde::{Deserialize, Serialize}; use starknet_api::core::ChainId; use validator::Validate; -// TODO: add peer manager config to the network config +// TODO(Shahak): add peer manager config to the network config #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Validate)] pub struct NetworkConfig { - pub tcp_port: u16, - pub quic_port: u16, + pub port: u16, #[serde(deserialize_with = "deserialize_seconds_to_duration")] pub session_timeout: Duration, #[serde(deserialize_with = "deserialize_seconds_to_duration")] @@ -61,17 +59,11 @@ impl SerializeConfig for NetworkConfig { fn dump(&self) -> BTreeMap { let mut config = BTreeMap::from_iter([ ser_param( - "tcp_port", - &self.tcp_port, + "port", + &self.port, "The port that the node listens on for incoming tcp connections.", ParamPrivacyInput::Public, ), - ser_param( - "quic_port", - &self.quic_port, - "The port that the node listens on for incoming quic connections.", - ParamPrivacyInput::Public, - ), ser_param( "session_timeout", &self.session_timeout.as_secs(), @@ -125,8 +117,7 @@ impl SerializeConfig for NetworkConfig { impl Default for NetworkConfig { fn default() -> Self { Self { - tcp_port: 10000, - quic_port: 10001, + port: 10000, session_timeout: Duration::from_secs(120), idle_connection_timeout: Duration::from_secs(120), bootstrap_peer_multiaddr: None, diff --git a/crates/papyrus_network/src/mixed_behaviour.rs b/crates/papyrus_network/src/mixed_behaviour.rs index a67576103a1..196f3c4abd0 100644 --- a/crates/papyrus_network/src/mixed_behaviour.rs +++ b/crates/papyrus_network/src/mixed_behaviour.rs @@ -16,7 +16,7 @@ use crate::{discovery, gossipsub_impl, peer_manager, sqmr}; const ONE_MEGA: usize = 1 << 20; -// TODO: consider reducing the pulicity of all behaviour to pub(crate) +// TODO(Shahak): consider reducing the pulicity of all behaviour to pub(crate) #[derive(NetworkBehaviour)] #[behaviour(out_event = "Event")] pub struct MixedBehaviour { @@ -56,7 +56,7 @@ pub trait BridgedBehaviour { } impl MixedBehaviour { - // TODO: get config details from network manager config + // TODO(Shahak): get config details from network manager config /// Panics if bootstrap_peer_multiaddr doesn't have a peer id. pub fn new( keypair: Keypair, @@ -97,7 +97,7 @@ impl MixedBehaviour { public_key, )), }, - // TODO: change kademlia protocol name + // TODO(Shahak): change kademlia protocol name kademlia: kad::Behaviour::with_config( local_peer_id, MemoryStore::new(local_peer_id), diff --git a/crates/papyrus_network/src/network_manager/metrics.rs b/crates/papyrus_network/src/network_manager/metrics.rs new file mode 100644 index 00000000000..7ba6ed671d0 --- /dev/null +++ b/crates/papyrus_network/src/network_manager/metrics.rs @@ -0,0 +1,56 @@ +use std::collections::HashMap; + +use libp2p::gossipsub::TopicHash; +use starknet_sequencer_metrics::metrics::{MetricCounter, MetricGauge}; + +pub struct BroadcastNetworkMetrics { + pub num_sent_broadcast_messages: MetricCounter, + pub num_received_broadcast_messages: MetricCounter, +} + +impl BroadcastNetworkMetrics { + pub fn register(&self) { + self.num_sent_broadcast_messages.register(); + self.num_received_broadcast_messages.register(); + } +} + +pub struct SqmrNetworkMetrics { + pub num_active_inbound_sessions: MetricGauge, + pub num_active_outbound_sessions: MetricGauge, +} + +impl SqmrNetworkMetrics { + pub fn register(&self) { + self.num_active_inbound_sessions.register(); + self.num_active_inbound_sessions.set(0f64); + self.num_active_outbound_sessions.register(); + self.num_active_outbound_sessions.set(0f64); + } +} + +// TODO(alonl, shahak): Consider making these fields private and receive Topics instead of +// TopicHashes in the constructor +pub struct NetworkMetrics { + pub num_connected_peers: MetricGauge, + pub num_blacklisted_peers: MetricGauge, + pub broadcast_metrics_by_topic: Option>, + pub sqmr_metrics: Option, +} + +impl NetworkMetrics { + pub fn register(&self) { + self.num_connected_peers.register(); + self.num_connected_peers.set(0f64); + self.num_blacklisted_peers.register(); + self.num_blacklisted_peers.set(0f64); + if let Some(broadcast_metrics_by_topic) = self.broadcast_metrics_by_topic.as_ref() { + for broadcast_metrics in broadcast_metrics_by_topic.values() { + broadcast_metrics.register(); + } + } + if let Some(sqmr_metrics) = self.sqmr_metrics.as_ref() { + sqmr_metrics.register(); + } + } +} diff --git a/crates/papyrus_network/src/network_manager/mod.rs b/crates/papyrus_network/src/network_manager/mod.rs index 8fa54349617..ded2d0a323a 100644 --- a/crates/papyrus_network/src/network_manager/mod.rs +++ b/crates/papyrus_network/src/network_manager/mod.rs @@ -1,12 +1,13 @@ +pub mod metrics; mod swarm_trait; - #[cfg(test)] mod test; #[cfg(any(test, feature = "testing"))] pub mod test_utils; -use std::collections::HashMap; +use std::collections::{BTreeMap, HashMap}; use std::pin::Pin; +use std::str::FromStr; use std::task::{Context, Poll}; use async_trait::async_trait; @@ -17,44 +18,45 @@ use futures::sink::With; use futures::stream::{FuturesUnordered, Map, Stream}; use futures::{pin_mut, FutureExt, Sink, SinkExt, StreamExt}; use libp2p::gossipsub::{SubscriptionError, TopicHash}; +use libp2p::identity::Keypair; use libp2p::swarm::SwarmEvent; -use libp2p::{Multiaddr, PeerId, StreamProtocol, Swarm}; -use metrics::gauge; -use papyrus_common::metrics as papyrus_metrics; +use libp2p::{noise, yamux, Multiaddr, PeerId, StreamProtocol, Swarm, SwarmBuilder}; +use metrics::NetworkMetrics; use papyrus_network_types::network_types::{BroadcastedMessageMetadata, OpaquePeerId}; use sqmr::Bytes; -use tracing::{debug, error, info, trace, warn}; +use tracing::{debug, error, trace, warn}; use self::swarm_trait::SwarmTrait; -use crate::bin_utils::build_swarm; use crate::gossipsub_impl::Topic; use crate::mixed_behaviour::{self, BridgedBehaviour}; use crate::sqmr::behaviour::SessionError; use crate::sqmr::{self, InboundSessionId, OutboundSessionId, SessionId}; -use crate::utils::{is_localhost, StreamHashMap}; +use crate::utils::{is_localhost, StreamMap}; use crate::{gossipsub_impl, NetworkConfig}; #[derive(thiserror::Error, Debug)] pub enum NetworkError { #[error(transparent)] DialError(#[from] libp2p::swarm::DialError), + #[error("Channels for broadcast topic with hash {topic_hash:?} were dropped.")] + BroadcastChannelsDropped { topic_hash: TopicHash }, } -// TODO: Understand whats the correct thing to do here. +// TODO(Shahak): Understand whats the correct thing to do here. const MESSAGE_METADATA_BUFFER_SIZE: usize = 100000; pub struct GenericNetworkManager { swarm: SwarmT, inbound_protocol_to_buffer_size: HashMap, - sqmr_inbound_response_receivers: StreamHashMap, + sqmr_inbound_response_receivers: StreamMap, sqmr_inbound_payload_senders: HashMap, - sqmr_outbound_payload_receivers: StreamHashMap, + sqmr_outbound_payload_receivers: StreamMap, sqmr_outbound_response_senders: HashMap, sqmr_outbound_report_receivers_awaiting_assignment: HashMap, // Splitting the broadcast receivers from the broadcasted senders in order to poll all // receivers simultaneously. // Each receiver has a matching sender and vice versa (i.e the maps have the same keys). - messages_to_broadcast_receivers: StreamHashMap>, + messages_to_broadcast_receivers: StreamMap>, broadcasted_messages_senders: HashMap>, reported_peer_receivers: FuturesUnordered>>, advertised_multiaddr: Option, @@ -62,22 +64,26 @@ pub struct GenericNetworkManager { reported_peers_sender: Sender, continue_propagation_sender: Sender, continue_propagation_receiver: Receiver, - // Fields for metrics - num_active_inbound_sessions: usize, - num_active_outbound_sessions: usize, + metrics: Option, } impl GenericNetworkManager { pub async fn run(mut self) -> Result<(), NetworkError> { loop { tokio::select! { - Some(event) = self.swarm.next() => self.handle_swarm_event(event), + Some(event) = self.swarm.next() => self.handle_swarm_event(event)?, Some(res) = self.sqmr_inbound_response_receivers.next() => self.handle_response_for_inbound_query(res), Some((protocol, client_payload)) = self.sqmr_outbound_payload_receivers.next() => { + let protocol = StreamProtocol::try_from_owned(protocol).expect("Invalid protocol should not appear"); self.handle_local_sqmr_payload(protocol, client_payload.expect("An SQMR client channel should not be terminated.")) } Some((topic_hash, message)) = self.messages_to_broadcast_receivers.next() => { - self.broadcast_message(message.expect("A broadcast channel should not be terminated."), topic_hash); + self.broadcast_message( + message.ok_or(NetworkError::BroadcastChannelsDropped { + topic_hash: topic_hash.clone() + })?, + topic_hash, + ); } Some(Some(peer_id)) = self.reported_peer_receivers.next() => self.swarm.report_peer_as_malicious(peer_id), Some(peer_id) = self.reported_peers_receiver.next() => self.swarm.report_peer_as_malicious(peer_id), @@ -90,8 +96,14 @@ impl GenericNetworkManager { // TODO(shahak): remove the advertised_multiaddr arg once we manage external addresses // in a behaviour. - pub(crate) fn generic_new(mut swarm: SwarmT, advertised_multiaddr: Option) -> Self { - gauge!(papyrus_metrics::PAPYRUS_NUM_CONNECTED_PEERS, 0f64); + pub(crate) fn generic_new( + mut swarm: SwarmT, + advertised_multiaddr: Option, + metrics: Option, + ) -> Self { + if let Some(metrics) = metrics.as_ref() { + metrics.register(); + } let reported_peer_receivers = FuturesUnordered::new(); reported_peer_receivers.push(futures::future::pending().boxed()); if let Some(address) = advertised_multiaddr.clone() { @@ -104,12 +116,12 @@ impl GenericNetworkManager { Self { swarm, inbound_protocol_to_buffer_size: HashMap::new(), - sqmr_inbound_response_receivers: StreamHashMap::new(HashMap::new()), + sqmr_inbound_response_receivers: StreamMap::new(BTreeMap::new()), sqmr_inbound_payload_senders: HashMap::new(), - sqmr_outbound_payload_receivers: StreamHashMap::new(HashMap::new()), + sqmr_outbound_payload_receivers: StreamMap::new(BTreeMap::new()), sqmr_outbound_response_senders: HashMap::new(), sqmr_outbound_report_receivers_awaiting_assignment: HashMap::new(), - messages_to_broadcast_receivers: StreamHashMap::new(HashMap::new()), + messages_to_broadcast_receivers: StreamMap::new(BTreeMap::new()), broadcasted_messages_senders: HashMap::new(), reported_peer_receivers, advertised_multiaddr, @@ -117,12 +129,12 @@ impl GenericNetworkManager { reported_peers_sender, continue_propagation_sender, continue_propagation_receiver, - num_active_inbound_sessions: 0, - num_active_outbound_sessions: 0, + metrics, } } - // TODO: Support multiple protocols where they're all different versions of the same protocol + // TODO(Shahak): Support multiple protocols where they're all different versions of the same + // protocol pub fn register_sqmr_protocol_server( &mut self, protocol: String, @@ -158,8 +170,9 @@ impl GenericNetworkManager { /// Register a new subscriber for sending a single query and receiving multiple responses. /// Panics if the given protocol is already subscribed. - // TODO: Support multiple protocols where they're all different versions of the same protocol - // TODO: Seperate query and response buffer sizes. + // TODO(Shahak): Support multiple protocols where they're all different versions of the same + // protocol. + // TODO(Shahak): Seperate query and response buffer sizes. pub fn register_sqmr_protocol_client( &mut self, protocol: String, @@ -178,7 +191,7 @@ impl GenericNetworkManager { let insert_result = self .sqmr_outbound_payload_receivers - .insert(protocol.clone(), Box::new(payload_receiver)); + .insert(protocol.clone().as_ref().to_string(), Box::new(payload_receiver)); if insert_result.is_some() { panic!("Protocol '{}' has already been registered as a client.", protocol); }; @@ -188,7 +201,7 @@ impl GenericNetworkManager { /// Register a new subscriber for broadcasting and receiving broadcasts for a given topic. /// Panics if this topic is already subscribed. - // TODO: consider splitting into register_broadcast_topic_client and + // TODO(Shahak): consider splitting into register_broadcast_topic_client and // register_broadcast_topic_server pub fn register_broadcast_topic( &mut self, @@ -252,15 +265,16 @@ impl GenericNetworkManager { }) } - fn handle_swarm_event(&mut self, event: SwarmEvent) { - #[allow(clippy::as_conversions)] // FIXME: use int metrics so `as f64` may be removed. + fn handle_swarm_event( + &mut self, + event: SwarmEvent, + ) -> Result<(), NetworkError> { match event { SwarmEvent::ConnectionEstablished { peer_id, .. } => { debug!("Connected to peer id: {peer_id:?}"); - gauge!( - papyrus_metrics::PAPYRUS_NUM_CONNECTED_PEERS, - self.swarm.num_connected_peers() as f64 - ); + if let Some(metrics) = self.metrics.as_ref() { + metrics.num_connected_peers.increment(1); + } } SwarmEvent::ConnectionClosed { peer_id, cause, .. } => { match cause { @@ -269,13 +283,12 @@ impl GenericNetworkManager { } None => debug!("Connection to {peer_id:?} closed."), } - gauge!( - papyrus_metrics::PAPYRUS_NUM_CONNECTED_PEERS, - self.swarm.num_connected_peers() as f64 - ); + if let Some(metrics) = self.metrics.as_ref() { + metrics.num_connected_peers.decrement(1); + } } SwarmEvent::Behaviour(event) => { - self.handle_behaviour_event(event); + self.handle_behaviour_event(event)?; } SwarmEvent::OutgoingConnectionError { connection_id, peer_id, error } => { warn!( @@ -310,28 +323,37 @@ impl GenericNetworkManager { error!("Unexpected event {event:?}"); } } + Ok(()) } - fn handle_behaviour_event(&mut self, event: mixed_behaviour::Event) { + fn handle_behaviour_event( + &mut self, + event: mixed_behaviour::Event, + ) -> Result<(), NetworkError> { match event { mixed_behaviour::Event::ExternalEvent(external_event) => { - self.handle_behaviour_external_event(external_event); + self.handle_behaviour_external_event(external_event)?; } mixed_behaviour::Event::ToOtherBehaviourEvent(internal_event) => { self.handle_to_other_behaviour_event(internal_event); } } + Ok(()) } - fn handle_behaviour_external_event(&mut self, event: mixed_behaviour::ExternalEvent) { + fn handle_behaviour_external_event( + &mut self, + event: mixed_behaviour::ExternalEvent, + ) -> Result<(), NetworkError> { match event { mixed_behaviour::ExternalEvent::Sqmr(event) => { self.handle_sqmr_event(event); } mixed_behaviour::ExternalEvent::GossipSub(event) => { - self.handle_gossipsub_behaviour_event(event); + self.handle_gossipsub_behaviour_event(event)?; } } + Ok(()) } // TODO(shahak): Move this logic to mixed_behaviour. @@ -376,7 +398,6 @@ impl GenericNetworkManager { } } - #[allow(clippy::as_conversions)] // FIXME: use int metrics so `as f64` may be removed. fn handle_sqmr_event_new_inbound_session( &mut self, peer_id: PeerId, @@ -384,17 +405,24 @@ impl GenericNetworkManager { inbound_session_id: InboundSessionId, query: Vec, ) { - self.num_active_inbound_sessions += 1; - gauge!( - papyrus_metrics::PAPYRUS_NUM_ACTIVE_INBOUND_SESSIONS, - self.num_active_inbound_sessions as f64 + debug!( + "Network received new inbound query from peer {peer_id:?}. Sending query to server. \ + {inbound_session_id:?}" ); let (report_sender, report_receiver) = oneshot::channel::<()>(); self.handle_new_report_receiver(peer_id, report_receiver); - // TODO: consider returning error instead of panic. let Some(query_sender) = self.sqmr_inbound_payload_senders.get_mut(&protocol_name) else { + error!( + "Received an inbound query for an unregistered protocol. Dropping query for \ + session {inbound_session_id:?}" + ); return; }; + if let Some(sqmr_metrics) = + self.metrics.as_ref().and_then(|metrics| metrics.sqmr_metrics.as_ref()) + { + sqmr_metrics.num_active_inbound_sessions.increment(1); + } let (responses_sender, responses_receiver) = futures::channel::mpsc::channel( *self .inbound_protocol_to_buffer_size @@ -417,6 +445,7 @@ impl GenericNetworkManager { "Received an inbound query while the buffer is full. Dropping query for session \ {inbound_session_id:?}" ), + true, ); } @@ -427,7 +456,7 @@ impl GenericNetworkManager { response: Vec, ) { trace!( - "Received response from peer for session id: {outbound_session_id:?}. sending to sync \ + "Received response from peer {peer_id:?} for {outbound_session_id:?}. Sending to sync \ subscriber." ); if let Some(report_receiver) = @@ -439,13 +468,15 @@ impl GenericNetworkManager { self.sqmr_outbound_response_senders.get_mut(&outbound_session_id) { // TODO(shahak): Close the channel if the buffer is full. + // TODO(Eitan): Close the channel if query was dropped by user. send_now( response_sender, response, format!( "Received response for an outbound query while the buffer is full. Dropping \ - it. Session: {outbound_session_id:?}" + it. {outbound_session_id:?}" ), + false, ); } } @@ -453,7 +484,7 @@ impl GenericNetworkManager { fn handle_sqmr_event_session_failed(&mut self, session_id: SessionId, error: SessionError) { error!("Session {session_id:?} failed on {error:?}"); self.report_session_removed_to_metrics(session_id); - // TODO: Handle reputation and retry. + // TODO(Shahak): Handle reputation and retry. if let SessionId::OutboundSessionId(outbound_session_id) = session_id { self.sqmr_outbound_response_senders.remove(&outbound_session_id); if let Some(_report_receiver) = @@ -468,7 +499,7 @@ impl GenericNetworkManager { } fn handle_sqmr_event_session_finished_successfully(&mut self, session_id: SessionId) { - debug!("Session completed successfully. session_id: {session_id:?}"); + debug!("Session completed successfully. {session_id:?}"); self.report_session_removed_to_metrics(session_id); if let SessionId::OutboundSessionId(outbound_session_id) = session_id { self.sqmr_outbound_response_senders.remove(&outbound_session_id); @@ -483,22 +514,37 @@ impl GenericNetworkManager { } } - fn handle_gossipsub_behaviour_event(&mut self, event: gossipsub_impl::ExternalEvent) { + fn handle_gossipsub_behaviour_event( + &mut self, + event: gossipsub_impl::ExternalEvent, + ) -> Result<(), NetworkError> { + if let Some(broadcast_metrics_by_topic) = + self.metrics.as_ref().and_then(|metrics| metrics.broadcast_metrics_by_topic.as_ref()) + { + let gossipsub_impl::ExternalEvent::Received { ref topic_hash, .. } = event; + match broadcast_metrics_by_topic.get(topic_hash) { + Some(broadcast_metrics) => { + broadcast_metrics.num_received_broadcast_messages.increment(1) + } + None => error!("Attempted to update topic metric with unregistered topic_hash"), + } + } let gossipsub_impl::ExternalEvent::Received { originated_peer_id, message, topic_hash } = event; + trace!("Received broadcast message with topic hash: {topic_hash:?}"); let broadcasted_message_metadata = BroadcastedMessageMetadata { originator_id: OpaquePeerId::private_new(originated_peer_id), + encoded_message_length: message.len(), }; let Some(sender) = self.broadcasted_messages_senders.get_mut(&topic_hash) else { - error!( + panic!( "Received a message from a topic we're not subscribed to with hash {topic_hash:?}" ); - return; }; let send_result = sender.try_send((message, broadcasted_message_metadata)); if let Err(e) = send_result { if e.is_disconnected() { - panic!("Receiver was dropped. This should never happen.") + return Err(NetworkError::BroadcastChannelsDropped { topic_hash }); } else if e.is_full() { warn!( "Receiver buffer is full. Dropping broadcasted message for topic with hash: \ @@ -506,25 +552,33 @@ impl GenericNetworkManager { ); } } + Ok(()) } fn handle_response_for_inbound_query(&mut self, res: (InboundSessionId, Option)) { let (inbound_session_id, maybe_response) = res; match maybe_response { Some(response) => { + trace!( + "Received response from server. Sending response to peer. \ + {inbound_session_id:?}" + ); self.swarm.send_response(response, inbound_session_id).unwrap_or_else(|e| { error!( - "Failed to send response to peer. Session id: {inbound_session_id:?} not \ - found error: {e:?}" + "Failed to send response to peer. {inbound_session_id:?} not found error: \ + {e:?}" ); }); } // The None is inserted by the network manager after the receiver end terminated so // that we'll know here when it terminated. None => { + trace!( + "Server finished sending responses. Closing session. {inbound_session_id:?}" + ); self.swarm.close_inbound_session(inbound_session_id).unwrap_or_else(|e| { error!( - "Failed to close session after sending all response. Session id: \ + "Failed to close session after sending all response. \ {inbound_session_id:?} not found error: {e:?}" ) }); @@ -538,51 +592,47 @@ impl GenericNetworkManager { client_payload: SqmrClientPayload, ) { let SqmrClientPayload { query, report_receiver, responses_sender } = client_payload; - match self.swarm.send_query(query, PeerId::random(), protocol.clone()) { - #[allow(clippy::as_conversions)] // FIXME: use int metrics so `as f64` may be removed. - Ok(outbound_session_id) => { - debug!( - "Network received new query. waiting for peer assignment. \ - outbound_session_id: {outbound_session_id:?}" - ); - self.num_active_outbound_sessions += 1; - gauge!( - papyrus_metrics::PAPYRUS_NUM_ACTIVE_OUTBOUND_SESSIONS, - self.num_active_outbound_sessions as f64 - ); - self.sqmr_outbound_response_senders.insert(outbound_session_id, responses_sender); - self.sqmr_outbound_report_receivers_awaiting_assignment - .insert(outbound_session_id, report_receiver); - } - Err(e) => { - info!( - "Failed to send query to peer. Peer not connected error: {e:?} Returning \ - empty response to sync subscriber." - ); - } + let outbound_session_id = self.swarm.send_query(query, protocol.clone()); + if let Some(sqmr_metrics) = + self.metrics.as_ref().and_then(|metrics| metrics.sqmr_metrics.as_ref()) + { + sqmr_metrics.num_active_outbound_sessions.increment(1); } + self.sqmr_outbound_response_senders.insert(outbound_session_id, responses_sender); + self.sqmr_outbound_report_receivers_awaiting_assignment + .insert(outbound_session_id, report_receiver); } fn broadcast_message(&mut self, message: Bytes, topic_hash: TopicHash) { + if let Some(broadcast_metrics_by_topic) = + self.metrics.as_ref().and_then(|metrics| metrics.broadcast_metrics_by_topic.as_ref()) + { + match broadcast_metrics_by_topic.get(&topic_hash) { + Some(broadcast_metrics) => { + broadcast_metrics.num_sent_broadcast_messages.increment(1) + } + None => error!("Attempted to update topic metric with unregistered topic_hash"), + } + } + trace!("Sending broadcast message with topic hash: {topic_hash:?}"); self.swarm.broadcast_message(message, topic_hash); } fn report_session_removed_to_metrics(&mut self, session_id: SessionId) { - #[allow(clippy::as_conversions)] // FIXME: use int metrics so `as f64` may be removed. match session_id { SessionId::InboundSessionId(_) => { - self.num_active_inbound_sessions -= 1; - gauge!( - papyrus_metrics::PAPYRUS_NUM_ACTIVE_INBOUND_SESSIONS, - self.num_active_inbound_sessions as f64 - ); + if let Some(sqmr_metrics) = + self.metrics.as_ref().and_then(|metrics| metrics.sqmr_metrics.as_ref()) + { + sqmr_metrics.num_active_inbound_sessions.decrement(1); + } } SessionId::OutboundSessionId(_) => { - self.num_active_outbound_sessions += 1; - gauge!( - papyrus_metrics::PAPYRUS_NUM_ACTIVE_OUTBOUND_SESSIONS, - self.num_active_outbound_sessions as f64 - ); + if let Some(sqmr_metrics) = + self.metrics.as_ref().and_then(|metrics| metrics.sqmr_metrics.as_ref()) + { + sqmr_metrics.num_active_outbound_sessions.decrement(1); + } } } } @@ -598,12 +648,19 @@ impl GenericNetworkManager { } } -fn send_now(sender: &mut GenericSender, item: Item, buffer_full_message: String) { +fn send_now( + sender: &mut GenericSender, + item: Item, + buffer_full_message: String, + should_panic_upon_disconnect: bool, +) { pin_mut!(sender); match sender.as_mut().send(item).now_or_never() { Some(Ok(())) => {} Some(Err(error)) => { - error!("Received error while sending message: {:?}", error); + if should_panic_upon_disconnect || !error.is_disconnected() { + panic!("Received error while sending message: {:?}", error); + } } None => { warn!(buffer_full_message); @@ -614,10 +671,13 @@ fn send_now(sender: &mut GenericSender, item: Item, buffer_full_mess pub type NetworkManager = GenericNetworkManager>; impl NetworkManager { - pub fn new(config: NetworkConfig, node_version: Option) -> Self { + pub fn new( + config: NetworkConfig, + node_version: Option, + metrics: Option, + ) -> Self { let NetworkConfig { - tcp_port, - quic_port: _, + port, session_timeout, idle_connection_timeout, bootstrap_peer_multiaddr, @@ -628,29 +688,49 @@ impl NetworkManager { peer_manager_config, } = config; - let listen_addresses = vec![ - // TODO: uncomment once quic transpot works. - // format!("/ip4/0.0.0.0/udp/{quic_port}/quic-v1"), - format!("/ip4/0.0.0.0/tcp/{tcp_port}"), - ]; + // TODO(shahak): Add quic transport. + let listen_address_str = format!("/ip4/0.0.0.0/tcp/{port}"); + let listen_address = Multiaddr::from_str(&listen_address_str) + .unwrap_or_else(|_| panic!("Unable to parse address {}", listen_address_str)); + debug!("Creating swarm with listen address: {:?}", listen_address); - let swarm = build_swarm(listen_addresses, idle_connection_timeout, secret_key, |key| { - mixed_behaviour::MixedBehaviour::new( - key, + let key_pair = match secret_key { + Some(secret_key) => { + Keypair::ed25519_from_bytes(secret_key).expect("Error while parsing secret key") + } + None => Keypair::generate_ed25519(), + }; + let mut swarm = SwarmBuilder::with_existing_identity(key_pair) + .with_tokio() + .with_tcp(Default::default(), noise::Config::new, yamux::Config::default) + .expect("Error building TCP transport") + .with_dns() + .expect("Error building DNS transport") + // TODO(Shahak): quic transpot does not work (failure appears in the command line when running in debug mode) + // .with_quic() + .with_behaviour(|key| mixed_behaviour::MixedBehaviour::new( + key.clone(), bootstrap_peer_multiaddr.clone(), sqmr::Config { session_timeout }, chain_id, node_version, discovery_config, peer_manager_config, - ) - }); + )) + .expect("Error while building the swarm") + .with_swarm_config(|cfg| cfg.with_idle_connection_timeout(idle_connection_timeout)) + .build(); + + swarm + .listen_on(listen_address.clone()) + .unwrap_or_else(|_| panic!("Error while binding to {}", listen_address)); + let advertised_multiaddr = advertised_multiaddr.map(|address| { address .with_p2p(*swarm.local_peer_id()) .expect("advertised_multiaddr has a peer id different than the local peer id") }); - Self::generic_new(swarm, advertised_multiaddr) + Self::generic_new(swarm, advertised_multiaddr, metrics) } pub fn get_local_peer_id(&self) -> String { @@ -811,7 +891,6 @@ where } pub async fn send_response(&mut self, response: Response) -> Result<(), SendError> { - debug!("Sending response from server to network"); match self.responses_sender.feed(response).await { Ok(()) => Ok(()), Err(e) => { @@ -914,13 +993,13 @@ pub type BroadcastTopicSender = With< pub type BroadcastTopicServer = Map, BroadcastReceivedMessagesConverterFn>; -type ReceivedBroadcastedMessage = +pub type ReceivedBroadcastedMessage = (Result>::Error>, BroadcastedMessageMetadata); -type BroadcastReceivedMessagesConverterFn = - fn((Bytes, BroadcastedMessageMetadata)) -> ReceivedBroadcastedMessage; - pub struct BroadcastTopicChannels> { pub broadcasted_messages_receiver: BroadcastTopicServer, pub broadcast_topic_client: BroadcastTopicClient, } + +type BroadcastReceivedMessagesConverterFn = + fn((Bytes, BroadcastedMessageMetadata)) -> ReceivedBroadcastedMessage; diff --git a/crates/papyrus_network/src/network_manager/swarm_trait.rs b/crates/papyrus_network/src/network_manager/swarm_trait.rs index d91cfc7f9b2..2f4f3e4c4c2 100644 --- a/crates/papyrus_network/src/network_manager/swarm_trait.rs +++ b/crates/papyrus_network/src/network_manager/swarm_trait.rs @@ -9,7 +9,7 @@ use super::BroadcastedMessageMetadata; use crate::gossipsub_impl::Topic; use crate::mixed_behaviour; use crate::peer_manager::{ReputationModifier, MALICIOUS}; -use crate::sqmr::behaviour::{PeerNotConnected, SessionIdNotFoundError}; +use crate::sqmr::behaviour::SessionIdNotFoundError; use crate::sqmr::{Bytes, InboundSessionId, OutboundSessionId, SessionId}; pub type Event = SwarmEvent<::ToSwarm>; @@ -21,17 +21,10 @@ pub trait SwarmTrait: Stream + Unpin { inbound_session_id: InboundSessionId, ) -> Result<(), SessionIdNotFoundError>; - fn send_query( - &mut self, - query: Vec, - peer_id: PeerId, - protocol: StreamProtocol, - ) -> Result; + fn send_query(&mut self, query: Vec, protocol: StreamProtocol) -> OutboundSessionId; fn dial(&mut self, peer_multiaddr: Multiaddr) -> Result<(), DialError>; - fn num_connected_peers(&self) -> usize; - fn close_inbound_session( &mut self, session_id: InboundSessionId, @@ -50,7 +43,7 @@ pub trait SwarmTrait: Stream + Unpin { fn broadcast_message(&mut self, message: Bytes, topic_hash: TopicHash); - // TODO: change this to report_peer and add an argument for the score. + // TODO(Shahak): change this to report_peer and add an argument for the score. fn report_peer_as_malicious(&mut self, peer_id: PeerId); fn add_new_supported_inbound_protocol(&mut self, protocol_name: StreamProtocol); @@ -67,23 +60,14 @@ impl SwarmTrait for Swarm { self.behaviour_mut().sqmr.send_response(response, inbound_session_id) } - // TODO: change this function signature - fn send_query( - &mut self, - query: Vec, - _peer_id: PeerId, - protocol: StreamProtocol, - ) -> Result { - Ok(self.behaviour_mut().sqmr.start_query(query, protocol)) + fn send_query(&mut self, query: Vec, protocol: StreamProtocol) -> OutboundSessionId { + self.behaviour_mut().sqmr.start_query(query, protocol) } fn dial(&mut self, peer_multiaddr: Multiaddr) -> Result<(), DialError> { self.dial(DialOpts::from(peer_multiaddr)) } - fn num_connected_peers(&self) -> usize { - self.network_info().num_peers() - } fn close_inbound_session( &mut self, session_id: InboundSessionId, diff --git a/crates/papyrus_network/src/network_manager/test.rs b/crates/papyrus_network/src/network_manager/test.rs index 18598363054..da0ffb114bd 100644 --- a/crates/papyrus_network/src/network_manager/test.rs +++ b/crates/papyrus_network/src/network_manager/test.rs @@ -25,7 +25,7 @@ use super::{BroadcastTopicChannels, GenericNetworkManager}; use crate::gossipsub_impl::{self, Topic}; use crate::mixed_behaviour; use crate::network_manager::{BroadcastTopicClientTrait, ServerQueryManager}; -use crate::sqmr::behaviour::{PeerNotConnected, SessionIdNotFoundError}; +use crate::sqmr::behaviour::SessionIdNotFoundError; use crate::sqmr::{Bytes, GenericEvent, InboundSessionId, OutboundSessionId}; const TIMEOUT: Duration = Duration::from_secs(1); @@ -133,28 +133,21 @@ impl SwarmTrait for MockSwarm { Ok(()) } - fn send_query( - &mut self, - query: Vec, - peer_id: PeerId, - _protocol: StreamProtocol, - ) -> Result { + fn send_query(&mut self, query: Vec, _protocol: StreamProtocol) -> OutboundSessionId { let outbound_session_id = OutboundSessionId { value: self.next_outbound_session_id }; self.create_response_events_for_query_each_num_becomes_response( query, outbound_session_id, - peer_id, + PeerId::random(), ); self.next_outbound_session_id += 1; - Ok(outbound_session_id) + outbound_session_id } fn dial(&mut self, _peer: Multiaddr) -> Result<(), libp2p::swarm::DialError> { Ok(()) } - fn num_connected_peers(&self) -> usize { - 0 - } + fn close_inbound_session( &mut self, inbound_session_id: InboundSessionId, @@ -203,7 +196,7 @@ impl SwarmTrait for MockSwarm { Ok(PeerId::random()) } - // TODO (shahak): Add test for continue propagation. + // TODO(shahak): Add test for continue propagation. fn continue_propagation(&mut self, _message_metadata: super::BroadcastedMessageMetadata) { unimplemented!() } @@ -222,7 +215,7 @@ async fn register_sqmr_protocol_client_and_use_channels() { mock_swarm.first_polled_event_notifier = Some(event_notifier); // network manager to register subscriber - let mut network_manager = GenericNetworkManager::generic_new(mock_swarm, None); + let mut network_manager = GenericNetworkManager::generic_new(mock_swarm, None, None); // register subscriber and send payload let mut payload_sender = network_manager.register_sqmr_protocol_client::, Vec>( @@ -284,7 +277,7 @@ async fn process_incoming_query() { let get_responses_fut = mock_swarm.get_responses_sent_to_inbound_session(inbound_session_id); let mut get_supported_inbound_protocol_fut = mock_swarm.get_supported_inbound_protocol(); - let mut network_manager = GenericNetworkManager::generic_new(mock_swarm, None); + let mut network_manager = GenericNetworkManager::generic_new(mock_swarm, None, None); let mut inbound_payload_receiver = network_manager .register_sqmr_protocol_server::, Vec>(protocol.to_string(), BUFFER_SIZE); @@ -320,7 +313,7 @@ async fn broadcast_message() { let mut mock_swarm = MockSwarm::default(); let mut messages_we_broadcasted_stream = mock_swarm.stream_messages_we_broadcasted(); - let mut network_manager = GenericNetworkManager::generic_new(mock_swarm, None); + let mut network_manager = GenericNetworkManager::generic_new(mock_swarm, None, None); let mut broadcast_topic_client = network_manager .register_broadcast_topic(topic.clone(), BUFFER_SIZE) @@ -356,7 +349,7 @@ async fn receive_broadcasted_message_and_report_it() { ))); let mut reported_peer_receiver = mock_swarm.get_reported_peers_stream(); - let mut network_manager = GenericNetworkManager::generic_new(mock_swarm, None); + let mut network_manager = GenericNetworkManager::generic_new(mock_swarm, None, None); let BroadcastTopicChannels { mut broadcast_topic_client, diff --git a/crates/papyrus_network/src/network_manager/test_utils.rs b/crates/papyrus_network/src/network_manager/test_utils.rs index 855cdc19042..21680208df5 100644 --- a/crates/papyrus_network/src/network_manager/test_utils.rs +++ b/crates/papyrus_network/src/network_manager/test_utils.rs @@ -11,12 +11,14 @@ use libp2p::core::multiaddr::Protocol; use libp2p::gossipsub::SubscriptionError; use libp2p::identity::Keypair; use libp2p::{Multiaddr, PeerId}; -use papyrus_common::tcp::find_n_free_ports; use super::{ + BroadcastReceivedMessagesConverterFn, + BroadcastTopicChannels, BroadcastTopicClient, BroadcastedMessageMetadata, GenericReceiver, + NetworkError, NetworkManager, ReportReceiver, ServerQueryManager, @@ -26,7 +28,6 @@ use super::{ SqmrServerReceiver, Topic, }; -use crate::network_manager::{BroadcastReceivedMessagesConverterFn, BroadcastTopicChannels}; use crate::sqmr::Bytes; use crate::NetworkConfig; @@ -67,7 +68,7 @@ where pub fn create_test_server_query_manager( query: Query, - // TODO: wrap the second and third types with a struct to make them more readable + // TODO(Shahak): wrap the second and third types with a struct to make them more readable ) -> (ServerQueryManager, ReportReceiver, GenericReceiver) where Query: TryFrom, @@ -84,8 +85,10 @@ where ) } -const CHANNEL_BUFFER_SIZE: usize = 10000; +const CHANNEL_BUFFER_SIZE: usize = 1000; +/// Mock register subscriber for a given topic. BroadcastNetworkMock is used to send and catch +/// messages broadcasted by and to the subscriber respectively. pub fn mock_register_broadcast_topic() -> Result, SubscriptionError> where T: TryFrom + 'static, @@ -148,49 +151,59 @@ where Ok(TestSubscriberChannels { subscriber_channels, mock_network }) } -// TODO(shahak): Change to n instead of 2. -pub fn create_two_connected_network_configs() -> (NetworkConfig, NetworkConfig) { - let [port0, port1] = find_n_free_ports::<2>(); +pub fn create_connected_network_configs(mut ports: Vec) -> Vec { + let number_of_configs = ports.len(); + let port0 = ports.remove(0); let secret_key0 = [1u8; 32]; let public_key0 = Keypair::ed25519_from_bytes(secret_key0).unwrap().public(); - let config0 = NetworkConfig { - tcp_port: port0, - secret_key: Some(secret_key0.to_vec()), - ..Default::default() - }; - let config1 = NetworkConfig { - tcp_port: port1, - bootstrap_peer_multiaddr: Some( - Multiaddr::empty() - .with(Protocol::Ip4(Ipv4Addr::LOCALHOST)) - .with(Protocol::Tcp(port0)) - .with(Protocol::P2p(PeerId::from_public_key(&public_key0))), - ), - ..Default::default() - }; - (config0, config1) + let config0 = + NetworkConfig { port: port0, secret_key: Some(secret_key0.to_vec()), ..Default::default() }; + let mut configs = Vec::with_capacity(number_of_configs); + configs.push(config0); + for port in ports.iter() { + configs.push(NetworkConfig { + port: *port, + bootstrap_peer_multiaddr: Some( + Multiaddr::empty() + .with(Protocol::Ip4(Ipv4Addr::LOCALHOST)) + .with(Protocol::Tcp(port0)) + .with(Protocol::P2p(PeerId::from_public_key(&public_key0))), + ), + ..Default::default() + }); + } + configs } -pub fn create_network_config_connected_to_broadcast_channels( +pub fn network_config_into_broadcast_channels( + network_config: NetworkConfig, topic: Topic, -) -> (NetworkConfig, BroadcastTopicChannels) +) -> BroadcastTopicChannels where T: TryFrom + 'static, Bytes: From, { const BUFFER_SIZE: usize = 1000; - let (channels_config, result_config) = create_two_connected_network_configs(); - - let mut channels_network_manager = NetworkManager::new(channels_config, None); + let mut network_manager = NetworkManager::new(network_config, None, None); let broadcast_channels = - channels_network_manager.register_broadcast_topic(topic, BUFFER_SIZE).unwrap(); - - tokio::task::spawn(channels_network_manager.run()); + network_manager.register_broadcast_topic(topic.clone(), BUFFER_SIZE).unwrap(); + + tokio::task::spawn(async move { + let result = network_manager.run().await; + match result { + Ok(()) => panic!("Network manager terminated."), + // The user of this function can drop the broadcast channels if they want to. In that + // case we should just terminate NetworkManager's run quietly. + Err(NetworkError::BroadcastChannelsDropped { topic_hash }) + if topic_hash == topic.into() => {} + Err(err) => panic!("Network manager failed on {err:?}"), + } + }); - (result_config, broadcast_channels) + broadcast_channels } pub struct MockClientResponsesManager, Response: TryFrom> { @@ -248,6 +261,9 @@ pub(crate) type MockBroadcastedMessagesFn = pub type MockMessagesToBroadcastReceiver = Map, fn(Bytes) -> T>; +/// Mock network for testing broadcast topics. It allows to send and catch messages broadcasted to +/// and by a subscriber (respectively). The naming convension is to mimick BroadcastTopicChannels +/// and replace sender and receiver. pub struct BroadcastNetworkMock> { pub broadcasted_messages_sender: MockBroadcastedMessagesSender, pub messages_to_broadcast_receiver: MockMessagesToBroadcastReceiver, diff --git a/crates/papyrus_network/src/peer_manager/behaviour_impl.rs b/crates/papyrus_network/src/peer_manager/behaviour_impl.rs index efdcbf59e63..cac67a9478a 100644 --- a/crates/papyrus_network/src/peer_manager/behaviour_impl.rs +++ b/crates/papyrus_network/src/peer_manager/behaviour_impl.rs @@ -13,7 +13,6 @@ use libp2p::swarm::{ use libp2p::{Multiaddr, PeerId}; use tracing::{debug, error, warn}; -use super::peer::PeerTrait; use super::{PeerManager, PeerManagerError}; use crate::sqmr::OutboundSessionId; @@ -40,8 +39,8 @@ impl NetworkBehaviour for PeerManager { _local_addr: &libp2p::Multiaddr, _remote_addr: &libp2p::Multiaddr, ) -> Result, libp2p::swarm::ConnectionDenied> { - // TODO: consider implementing a better lookup mechanism in case there's a lot of peers this - // will be slow + // TODO(Shahak): consider implementing a better lookup mechanism in case there's a lot of + // peers this will be slow match self .peers .iter() @@ -54,7 +53,7 @@ impl NetworkBehaviour for PeerManager { } } - // TODO: in case we want to deny a connection based on the remote address + // TODO(Shahak): in case we want to deny a connection based on the remote address // we probably need to keep a separate list of banned addresses since extracting it from the // peers multiaddrs will be slow fn handle_pending_inbound_connection( @@ -86,7 +85,7 @@ impl NetworkBehaviour for PeerManager { } fn on_swarm_event(&mut self, event: libp2p::swarm::FromSwarm<'_>) { - // TODO: consider if we should handle other events + // TODO(Shahak): consider if we should handle other events #[allow(clippy::single_match)] match event { libp2p::swarm::FromSwarm::DialFailure(DialFailure { @@ -107,7 +106,7 @@ impl NetworkBehaviour for PeerManager { warn!("Dial failure of an unknown peer. peer id: {}", peer_id) } // Re-assign a peer to the session so that a SessionAssgined Event will be emitted. - // TODO: test this case + // TODO(Shahak): test this case let queries_to_assign = self.session_to_peer_map .iter() @@ -140,13 +139,16 @@ impl NetworkBehaviour for PeerManager { ) .add_connection_id(connection_id); } else { - let Some(peer) = self.peers.get_mut(&peer_id) else { - // TODO(shahak): Consider tracking connection ids for peers we don't know - // yet because once a connection is established we'll shortly receive an - // identify message and add this peer. + if let Some(peer) = self.peers.get_mut(&peer_id) { + peer.add_connection_id(connection_id); return; }; - peer.add_connection_id(connection_id); + match self.connections_for_unknown_peers.get_mut(&peer_id) { + Some(connection_ids) => connection_ids.push(connection_id), + None => { + self.connections_for_unknown_peers.insert(peer_id, vec![connection_id]); + } + } } } libp2p::swarm::FromSwarm::ConnectionClosed(ConnectionClosed { @@ -154,17 +156,22 @@ impl NetworkBehaviour for PeerManager { connection_id, .. }) => { - if let Some(peer) = self.peers.get_mut(&peer_id) { - let known_connection_ids = peer.connection_ids(); - if known_connection_ids.contains(&connection_id) { - peer.remove_connection_id(connection_id); - } else { - error!( - "Connection closed event for a peer with a different connection id. \ - known connection ids: {:?}, emitted connection id: {}", - known_connection_ids, connection_id - ); - } + let mut empty_connection_ids = vec![]; + let known_connection_ids = match self.peers.get_mut(&peer_id) { + Some(peer) => peer.connection_ids_mut(), + None => self + .connections_for_unknown_peers + .get_mut(&peer_id) + .unwrap_or(&mut empty_connection_ids), + }; + if known_connection_ids.contains(&connection_id) { + known_connection_ids.retain(|&id| id != connection_id); + } else { + error!( + "Connection id {:?} was closed and it should appear in the known \ + connection ids, but it doesn't. known connection ids: {:?}.", + connection_id, known_connection_ids + ); } } _ => {} diff --git a/crates/papyrus_network/src/peer_manager/mod.rs b/crates/papyrus_network/src/peer_manager/mod.rs index 7c5818643db..8ed8e39d419 100644 --- a/crates/papyrus_network/src/peer_manager/mod.rs +++ b/crates/papyrus_network/src/peer_manager/mod.rs @@ -4,7 +4,7 @@ use std::time::Duration; use futures::future::BoxFuture; use futures::FutureExt; use libp2p::swarm::dial_opts::DialOpts; -use libp2p::swarm::ToSwarm; +use libp2p::swarm::{ConnectionId, ToSwarm}; use libp2p::PeerId; use papyrus_config::converters::{ deserialize_milliseconds_to_duration, @@ -17,7 +17,6 @@ use serde::{Deserialize, Serialize}; use tracing::info; pub use self::behaviour_impl::ToOtherBehaviourEvent; -use self::peer::PeerTrait; use crate::discovery::identify_impl::IdentifyToOtherBehaviourEvent; use crate::mixed_behaviour::BridgedBehaviour; use crate::sqmr::OutboundSessionId; @@ -43,7 +42,7 @@ pub enum ReputationModifier { pub struct PeerManager { peers: HashMap, - // TODO: consider implementing a cleanup mechanism to not store all queries forever + // TODO(Shahak): consider implementing a cleanup mechanism to not store all queries forever session_to_peer_map: HashMap, config: PeerManagerConfig, last_peer_index: usize, @@ -52,6 +51,8 @@ pub struct PeerManager { peers_pending_dial_with_sessions: HashMap>, sessions_received_when_no_peers: Vec, sleep_waiting_for_unblocked_peer: Option>, + // A peer is known only after we get the identify message. + connections_for_unknown_peers: HashMap>, } #[derive(Debug, Clone, Deserialize, Serialize, PartialEq)] @@ -75,8 +76,8 @@ pub(crate) enum PeerManagerError { impl Default for PeerManagerConfig { fn default() -> Self { Self { - // 1 year. - malicious_timeout_seconds: Duration::from_secs(3600 * 24 * 365), + // TODO(shahak): Increase this once we're in a non-trusted setup. + malicious_timeout_seconds: Duration::from_secs(1), unstable_timeout_millis: Duration::from_millis(1000), } } @@ -114,6 +115,7 @@ impl PeerManager { peers_pending_dial_with_sessions: HashMap::new(), sessions_received_when_no_peers: Vec::new(), sleep_waiting_for_unblocked_peer: None, + connections_for_unknown_peers: HashMap::default(), } } @@ -135,7 +137,7 @@ impl PeerManager { // TODO(shahak): Remove return value and use events in tests. // TODO(shahak): Split this function for readability. fn assign_peer_to_session(&mut self, outbound_session_id: OutboundSessionId) -> Option { - // TODO: consider moving this logic to be async (on a different tokio task) + // TODO(Shahak): consider moving this logic to be async (on a different tokio task) // until then we can return the assignment even if we use events for the notification. if self.peers.is_empty() { info!("No peers. Waiting for a new peer to be connected for {outbound_session_id:?}"); @@ -169,15 +171,11 @@ impl PeerManager { return None; } peer.map(|(peer_id, peer)| { - // TODO: consider not allowing reassignment of the same session + // TODO(Shahak): consider not allowing reassignment of the same session self.session_to_peer_map.insert(outbound_session_id, *peer_id); let peer_connection_ids = peer.connection_ids(); if !peer_connection_ids.is_empty() { let connection_id = peer_connection_ids[0]; - info!( - "Session {:?} assigned to peer {:?} with connection id: {:?}", - outbound_session_id, peer_id, connection_id - ); self.pending_events.push(ToSwarm::GenerateEvent( ToOtherBehaviourEvent::SessionAssigned { outbound_session_id, @@ -215,18 +213,22 @@ impl PeerManager { peer_id: PeerId, reason: ReputationModifier, ) -> Result<(), PeerManagerError> { - self.pending_events - .push(ToSwarm::GenerateEvent(ToOtherBehaviourEvent::PeerBlacklisted { peer_id })); if let Some(peer) = self.peers.get_mut(&peer_id) { match reason { ReputationModifier::Misconduct { misconduct_score } => { peer.report(misconduct_score); if peer.is_malicious() { + self.pending_events.push(ToSwarm::GenerateEvent( + ToOtherBehaviourEvent::PeerBlacklisted { peer_id }, + )); peer.blacklist_peer(self.config.malicious_timeout_seconds); peer.reset_misconduct_score(); } } ReputationModifier::Unstable => { + self.pending_events.push(ToSwarm::GenerateEvent( + ToOtherBehaviourEvent::PeerBlacklisted { peer_id }, + )); peer.blacklist_peer(self.config.unstable_timeout_millis); } } @@ -281,7 +283,10 @@ impl BridgedBehaviour for PeerManager { return; }; - let peer = Peer::new(*peer_id, address.clone()); + let mut peer = Peer::new(*peer_id, address.clone()); + if let Some(connection_ids) = self.connections_for_unknown_peers.remove(peer_id) { + *peer.connection_ids_mut() = connection_ids; + } self.add_peer(peer); } _ => {} diff --git a/crates/papyrus_network/src/peer_manager/peer.rs b/crates/papyrus_network/src/peer_manager/peer.rs index 3ade97da2a8..478fa00c158 100644 --- a/crates/papyrus_network/src/peer_manager/peer.rs +++ b/crates/papyrus_network/src/peer_manager/peer.rs @@ -4,33 +4,6 @@ use libp2p::swarm::ConnectionId; use libp2p::{Multiaddr, PeerId}; use tracing::info; -pub trait PeerTrait { - fn new(peer_id: PeerId, multiaddr: Multiaddr) -> Self; - - fn blacklist_peer(&mut self, timeout_duration: Duration); - - fn peer_id(&self) -> PeerId; - - fn multiaddr(&self) -> Multiaddr; - - fn is_blocked(&self) -> bool; - - /// Returns Instant::now if not blocked. - fn blocked_until(&self) -> Instant; - - fn connection_ids(&self) -> &Vec; - - fn add_connection_id(&mut self, connection_id: ConnectionId); - - fn remove_connection_id(&mut self, connection_id: ConnectionId); - - fn reset_misconduct_score(&mut self); - - fn report(&mut self, misconduct_score: f64); - - fn is_malicious(&self) -> bool; -} - #[derive(Clone)] pub struct Peer { peer_id: PeerId, @@ -40,8 +13,8 @@ pub struct Peer { misconduct_score: f64, } -impl PeerTrait for Peer { - fn new(peer_id: PeerId, multiaddr: Multiaddr) -> Self { +impl Peer { + pub fn new(peer_id: PeerId, multiaddr: Multiaddr) -> Self { Self { peer_id, multiaddr, @@ -51,7 +24,7 @@ impl PeerTrait for Peer { } } - fn blacklist_peer(&mut self, timeout_duration: Duration) { + pub fn blacklist_peer(&mut self, timeout_duration: Duration) { self.timed_out_until = get_instant_now() + timeout_duration; info!( "Peer {:?} misbehaved. Blacklisting it for {:.3} seconds.", @@ -60,19 +33,19 @@ impl PeerTrait for Peer { ); } - fn peer_id(&self) -> PeerId { + pub fn peer_id(&self) -> PeerId { self.peer_id } - fn multiaddr(&self) -> Multiaddr { + pub fn multiaddr(&self) -> Multiaddr { self.multiaddr.clone() } - fn is_blocked(&self) -> bool { + pub fn is_blocked(&self) -> bool { self.timed_out_until > get_instant_now() } - fn blocked_until(&self) -> Instant { + pub fn blocked_until(&self) -> Instant { if self.timed_out_until > get_instant_now() { self.timed_out_until } else { @@ -80,27 +53,27 @@ impl PeerTrait for Peer { } } - fn connection_ids(&self) -> &Vec { + pub fn connection_ids(&self) -> &Vec { &self.connection_ids } - fn add_connection_id(&mut self, connection_id: ConnectionId) { - self.connection_ids.push(connection_id); + pub fn connection_ids_mut(&mut self) -> &mut Vec { + &mut self.connection_ids } - fn remove_connection_id(&mut self, connection_id: ConnectionId) { - self.connection_ids.retain(|&id| id != connection_id); + pub fn add_connection_id(&mut self, connection_id: ConnectionId) { + self.connection_ids.push(connection_id); } - fn reset_misconduct_score(&mut self) { + pub fn reset_misconduct_score(&mut self) { self.misconduct_score = 0f64; } - fn report(&mut self, misconduct_score: f64) { + pub fn report(&mut self, misconduct_score: f64) { self.misconduct_score += misconduct_score; } - fn is_malicious(&self) -> bool { + pub fn is_malicious(&self) -> bool { 1.0f64 <= self.misconduct_score } } diff --git a/crates/papyrus_network/src/peer_manager/test.rs b/crates/papyrus_network/src/peer_manager/test.rs index 56f69e34c43..992569f25cc 100644 --- a/crates/papyrus_network/src/peer_manager/test.rs +++ b/crates/papyrus_network/src/peer_manager/test.rs @@ -18,7 +18,7 @@ use super::behaviour_impl::ToOtherBehaviourEvent; use crate::discovery::identify_impl::IdentifyToOtherBehaviourEvent; use crate::mixed_behaviour; use crate::mixed_behaviour::BridgedBehaviour; -use crate::peer_manager::peer::{Peer, PeerTrait}; +use crate::peer_manager::peer::Peer; use crate::peer_manager::{PeerManager, PeerManagerConfig, ReputationModifier, MALICIOUS}; use crate::sqmr::OutboundSessionId; diff --git a/crates/papyrus_network/src/sqmr/behaviour.rs b/crates/papyrus_network/src/sqmr/behaviour.rs index 88787ceeb09..d4e51982ff1 100644 --- a/crates/papyrus_network/src/sqmr/behaviour.rs +++ b/crates/papyrus_network/src/sqmr/behaviour.rs @@ -21,7 +21,7 @@ use libp2p::swarm::{ ToSwarm, }; use libp2p::{Multiaddr, PeerId, StreamProtocol}; -use tracing::{error, info}; +use tracing::{debug, error}; use super::handler::{ Handler, @@ -143,7 +143,10 @@ impl Behaviour { self.outbound_sessions_pending_peer_assignment .insert(outbound_session_id, (query, protocol_name)); - info!("Requesting peer assignment for outbound session: {:?}.", outbound_session_id); + debug!( + "Network received new outbound query. Requesting peer assignment for {:?}.", + outbound_session_id + ); self.add_event_to_queue(ToSwarm::GenerateEvent(Event::ToOtherBehaviourEvent( ToOtherBehaviourEvent::RequestPeerAssignment { outbound_session_id }, ))); @@ -344,7 +347,10 @@ impl BridgedBehaviour for Behaviour { else { return; }; - info!("Assigned {outbound_session_id:?} to {peer_id:?}"); + debug!( + "Assigned peer {:?} to session {:?} with connection id: {:?}", + peer_id, outbound_session_id, connection_id + ); self.session_id_to_peer_id_and_connection_id .insert((*outbound_session_id).into(), (*peer_id, *connection_id)); diff --git a/crates/papyrus_network/src/sqmr/flow_test.rs b/crates/papyrus_network/src/sqmr/flow_test.rs index 99fced94396..a34900aad38 100644 --- a/crates/papyrus_network/src/sqmr/flow_test.rs +++ b/crates/papyrus_network/src/sqmr/flow_test.rs @@ -12,7 +12,7 @@ use super::behaviour::{Behaviour, Event, ExternalEvent, ToOtherBehaviourEvent}; use super::{Bytes, Config, InboundSessionId, OutboundSessionId, SessionId}; use crate::mixed_behaviour::BridgedBehaviour; use crate::test_utils::create_fully_connected_swarms_stream; -use crate::utils::StreamHashMap; +use crate::utils::StreamMap; use crate::{mixed_behaviour, peer_manager}; const NUM_PEERS: usize = 3; @@ -24,7 +24,7 @@ pub const OTHER_PROTOCOL_NAME: StreamProtocol = StreamProtocol::new("/other"); type SwarmEventAlias = SwarmEvent<::ToSwarm>; async fn collect_events_from_swarms( - swarms_stream: &mut StreamHashMap>, + swarms_stream: &mut StreamMap>, mut map_and_filter_event: impl FnMut(PeerId, SwarmEventAlias) -> Option<(PeerId, T)>, assert_unique: bool, ) -> HashMap<(PeerId, PeerId), T> { @@ -46,7 +46,7 @@ async fn collect_events_from_swarms( } fn perform_action_on_swarms( - swarms_stream: &mut StreamHashMap>, + swarms_stream: &mut StreamMap>, peer_ids: &[PeerId], action: &mut dyn FnMut(&mut Swarm, PeerId), ) { diff --git a/crates/papyrus_network/src/sqmr/handler.rs b/crates/papyrus_network/src/sqmr/handler.rs index 5a6dc3bee0a..d5588ac253e 100644 --- a/crates/papyrus_network/src/sqmr/handler.rs +++ b/crates/papyrus_network/src/sqmr/handler.rs @@ -91,7 +91,7 @@ pub struct Handler { } impl Handler { - // TODO(shahak) If we'll add more parameters, consider creating a HandlerConfig struct. + // TODO(shahak): If we'll add more parameters, consider creating a HandlerConfig struct. pub fn new( config: Config, next_inbound_session_id: Arc, @@ -251,7 +251,7 @@ impl ConnectionHandler for Handler { outbound_session_id, protocol_name, } => { - // TODO(shahak) Consider extracting to a utility function to prevent forgetfulness + // TODO(shahak): Consider extracting to a utility function to prevent forgetfulness // of the timeout. // No need to wake because the swarm guarantees that `poll` will be called after diff --git a/crates/papyrus_network/src/sqmr/mod.rs b/crates/papyrus_network/src/sqmr/mod.rs index 7225e7a530a..64a7859ebc2 100644 --- a/crates/papyrus_network/src/sqmr/mod.rs +++ b/crates/papyrus_network/src/sqmr/mod.rs @@ -18,7 +18,9 @@ pub struct OutboundSessionId { pub value: usize, } -#[derive(Clone, Copy, Debug, Default, derive_more::Display, Eq, Hash, PartialEq)] +#[derive( + Clone, Copy, Debug, Default, derive_more::Display, Eq, Hash, PartialEq, PartialOrd, Ord, +)] pub struct InboundSessionId { pub value: usize, } diff --git a/crates/papyrus_network/src/test_utils/mod.rs b/crates/papyrus_network/src/test_utils/mod.rs index 9afbb353472..113b14751ee 100644 --- a/crates/papyrus_network/src/test_utils/mod.rs +++ b/crates/papyrus_network/src/test_utils/mod.rs @@ -2,23 +2,18 @@ mod get_stream; use std::collections::{HashMap, HashSet}; use std::fmt::Debug; -use std::pin::Pin; -use std::task::{ready, Context, Poll}; use std::time::Duration; -use futures::future::{Either, Future}; -use futures::pin_mut; -use futures::stream::Stream as StreamTrait; +use futures::future::Either; use libp2p::swarm::dial_opts::{DialOpts, PeerCondition}; use libp2p::swarm::{ConnectionId, NetworkBehaviour, Swarm, SwarmEvent}; use libp2p::{PeerId, Stream, StreamProtocol}; use libp2p_swarm_test::SwarmExt; -use tokio::sync::Mutex; use tokio::task::JoinHandle; use tokio_stream::StreamExt; use crate::sqmr::Bytes; -use crate::utils::StreamHashMap; +use crate::utils::StreamMap; /// Create two streams that are connected to each other. Return them and a join handle for a thread /// that will perform the sends between the streams (this thread will run forever so it shouldn't @@ -65,7 +60,7 @@ impl crate::sqmr::handler::Handler { pub(crate) async fn create_fully_connected_swarms_stream( num_swarms: usize, behaviour_gen: impl Fn() -> TBehaviour, -) -> (StreamHashMap>, HashMap<(PeerId, PeerId), ConnectionId>) +) -> (StreamMap>, HashMap<(PeerId, PeerId), ConnectionId>) where ::ToSwarm: Debug, { @@ -91,9 +86,7 @@ where } ( - StreamHashMap::new( - swarms.into_iter().map(|swarm| (*swarm.local_peer_id(), swarm)).collect(), - ), + StreamMap::new(swarms.into_iter().map(|swarm| (*swarm.local_peer_id(), swarm)).collect()), connection_ids, ) } @@ -148,29 +141,3 @@ where } } } - -// I tried making this generic on the async function we run, but it caused a lot of lifetime -// issues. -/// Run `next` on a mutex of a stream, unlocking it while the function is pending. -pub(crate) fn next_on_mutex_stream( - mutex: &Mutex, -) -> NextOnMutexStream<'_, T> { - NextOnMutexStream { mutex } -} - -pub(crate) struct NextOnMutexStream<'a, T: StreamTrait + Unpin> { - mutex: &'a Mutex, -} - -impl<'a, T: StreamTrait + Unpin> Future for NextOnMutexStream<'a, T> { - type Output = Option; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let lock_fut = self.mutex.lock(); - pin_mut!(lock_fut); - let mut locked_value = ready!(lock_fut.poll(cx)); - let fut = StreamExt::next(&mut *locked_value); - pin_mut!(fut); - fut.poll(cx) - } -} diff --git a/crates/papyrus_network/src/utils.rs b/crates/papyrus_network/src/utils.rs index 72c862b61c5..a27be4a92e5 100644 --- a/crates/papyrus_network/src/utils.rs +++ b/crates/papyrus_network/src/utils.rs @@ -1,7 +1,6 @@ use core::net::Ipv4Addr; -use std::collections::hash_map::{Keys, ValuesMut}; -use std::collections::HashMap; -use std::hash::Hash; +use std::collections::btree_map::{Keys, ValuesMut}; +use std::collections::BTreeMap; use std::pin::Pin; use std::task::{Context, Poll, Waker}; @@ -12,15 +11,16 @@ use libp2p::Multiaddr; // This is an implementation of `StreamMap` from tokio_stream. The reason we're implementing it // ourselves is that the implementation in tokio_stream requires that the values implement the // Stream trait from tokio_stream and not from futures. -pub struct StreamHashMap { - map: HashMap, +pub struct StreamMap { + map: BTreeMap, wakers_waiting_for_new_stream: Vec, + next_index_to_poll: Option, } -impl StreamHashMap { +impl StreamMap { #[allow(dead_code)] - pub fn new(map: HashMap) -> Self { - Self { map, wakers_waiting_for_new_stream: Default::default() } + pub fn new(map: BTreeMap) -> Self { + Self { map, wakers_waiting_for_new_stream: Default::default(), next_index_to_poll: None } } #[allow(dead_code)] @@ -47,18 +47,35 @@ impl StreamHashMap { } } -impl Stream for StreamHashMap { +impl Stream for StreamMap { type Item = (K, Option<::Item>); fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { let unpinned_self = Pin::into_inner(self); let mut finished_stream_key: Option = None; - for (key, stream) in &mut unpinned_self.map { + let next_index_to_poll = unpinned_self.next_index_to_poll.take().unwrap_or_default(); + let size_of_map = unpinned_self.map.len(); + let keys = unpinned_self + .map + .keys() + .cloned() + .enumerate() + .cycle() + .skip(next_index_to_poll) + .take(size_of_map) + .collect::>() + .into_iter(); + for (index, key) in keys { + let stream = unpinned_self.map.get_mut(&key).unwrap(); + // poll the stream match stream.poll_next_unpin(cx) { Poll::Ready(Some(value)) => { + unpinned_self.next_index_to_poll = + Some(index.checked_add(1).unwrap_or_default()); return Poll::Ready(Some((key.clone(), Some(value)))); } Poll::Ready(None) => { + unpinned_self.next_index_to_poll = Some(index); finished_stream_key = Some(key.clone()); // breaking and removing the finished stream from the map outside of the loop // because we can't have two mutable references to the map. @@ -67,6 +84,7 @@ impl Stream for StreamHashMap {} } } + if let Some(finished_stream_key) = finished_stream_key { unpinned_self.map.remove(&finished_stream_key); return Poll::Ready(Some((finished_stream_key, None))); diff --git a/crates/papyrus_network_types/src/network_types.rs b/crates/papyrus_network_types/src/network_types.rs index 0748209dd47..1b43136b01a 100644 --- a/crates/papyrus_network_types/src/network_types.rs +++ b/crates/papyrus_network_types/src/network_types.rs @@ -5,6 +5,7 @@ use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)] pub struct BroadcastedMessageMetadata { pub originator_id: OpaquePeerId, + pub encoded_message_length: usize, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)] diff --git a/crates/papyrus_network_types/src/test_utils.rs b/crates/papyrus_network_types/src/test_utils.rs index e7c20c5daba..dc06b468104 100644 --- a/crates/papyrus_network_types/src/test_utils.rs +++ b/crates/papyrus_network_types/src/test_utils.rs @@ -5,7 +5,7 @@ use rand_chacha::ChaCha8Rng; use crate::network_types::{BroadcastedMessageMetadata, OpaquePeerId}; impl GetTestInstance for OpaquePeerId { - // TODO: use the given rng by copying the libp2p implementation. + // TODO(Shahak): use the given rng by copying the libp2p implementation. fn get_test_instance(_rng: &mut ChaCha8Rng) -> Self { Self::private_new(PeerId::random()) } @@ -14,5 +14,6 @@ impl GetTestInstance for OpaquePeerId { auto_impl_get_test_instance! { pub struct BroadcastedMessageMetadata { pub originator_id: OpaquePeerId, + pub encoded_message_length: usize, } } diff --git a/crates/papyrus_node/Cargo.toml b/crates/papyrus_node/Cargo.toml index 8f25b053551..fc712630827 100644 --- a/crates/papyrus_node/Cargo.toml +++ b/crates/papyrus_node/Cargo.toml @@ -5,9 +5,6 @@ edition.workspace = true repository.workspace = true license-file.workspace = true -[package.metadata.cargo-udeps.ignore] -normal = ["clap", "papyrus_base_layer", "reqwest", "tokio"] - [features] default = ["rpc"] rpc = ["papyrus_rpc"] @@ -18,11 +15,6 @@ name = "central_source_integration_test" path = "src/bin/central_source_integration_test.rs" required-features = ["futures-util", "tokio-stream"] -[[bin]] -name = "run_consensus" -path = "src/bin/run_consensus.rs" -required-features = ["testing"] - [dependencies] anyhow.workspace = true clap = { workspace = true } @@ -34,8 +26,6 @@ once_cell.workspace = true papyrus_base_layer.workspace = true papyrus_common.workspace = true papyrus_config.workspace = true -papyrus_consensus.workspace = true -papyrus_consensus_orchestrator.workspace = true papyrus_monitoring_gateway.workspace = true papyrus_network.workspace = true papyrus_p2p_sync.workspace = true @@ -45,8 +35,11 @@ papyrus_sync.workspace = true reqwest = { workspace = true, features = ["blocking", "json"] } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true, features = ["arbitrary_precision"] } -starknet_api = { workspace = true, features = ["testing"] } +starknet_api.workspace = true +starknet_class_manager_types.workspace = true starknet_client.workspace = true +starknet_consensus.workspace = true +starknet_consensus_orchestrator.workspace = true strum.workspace = true tokio = { workspace = true, features = ["full", "sync"] } tracing.workspace = true @@ -57,16 +50,15 @@ validator = { workspace = true, features = ["derive"] } futures-util = { workspace = true, optional = true } tokio-stream = { workspace = true, optional = true } - [dev-dependencies] -assert-json-diff.workspace = true colored.workspace = true -infra_utils.workspace = true insta = { workspace = true, features = ["json"] } metrics-exporter-prometheus.workspace = true papyrus_test_utils.workspace = true pretty_assertions.workspace = true +starknet_infra_utils = { workspace = true, features = ["testing"] } tempfile.workspace = true + [lints] workspace = true diff --git a/crates/papyrus_node/src/bin/central_source_integration_test.rs b/crates/papyrus_node/src/bin/central_source_integration_test.rs index 10da36ce31a..7649a8ab411 100644 --- a/crates/papyrus_node/src/bin/central_source_integration_test.rs +++ b/crates/papyrus_node/src/bin/central_source_integration_test.rs @@ -17,6 +17,7 @@ async fn main() { let _ = fs::remove_dir_all(path.clone()); fs::create_dir_all(path.clone()).expect("Should make a temporary `data` directory"); let config = NodeConfig::load_and_process(vec![ + "Placeholder-binary-name".to_owned(), "--chain_id=SN_SEPOLIA".to_owned(), "--starknet_url=https://alpha-sepolia.starknet.io/".to_owned(), "--base_layer.node_url=https://mainnet.infura.io/v3/1234".to_owned(), diff --git a/crates/papyrus_node/src/bin/run_consensus.rs b/crates/papyrus_node/src/bin/run_consensus.rs deleted file mode 100644 index ec62abc1d95..00000000000 --- a/crates/papyrus_node/src/bin/run_consensus.rs +++ /dev/null @@ -1,117 +0,0 @@ -//! Run a papyrus node with consensus enabled and the ability to simulate network issues for -//! consensus. -//! -//! Expects to receive 2 groupings of arguments: -//! 1. TestConfig - these are prefixed with `--test.` in the command. -//! 2. NodeConfig - any argument lacking the above prefix is assumed to be in NodeConfig. - -use clap::Parser; -use futures::stream::StreamExt; -use papyrus_consensus::config::ConsensusConfig; -use papyrus_consensus::simulation_network_receiver::NetworkReceiver; -use papyrus_consensus::types::BroadcastConsensusMessageChannel; -use papyrus_consensus_orchestrator::papyrus_consensus_context::PapyrusConsensusContext; -use papyrus_network::gossipsub_impl::Topic; -use papyrus_network::network_manager::NetworkManager; -use papyrus_node::bin_utils::build_configs; -use papyrus_node::run::{run, PapyrusResources, PapyrusTaskHandles}; -use papyrus_p2p_sync::BUFFER_SIZE; -use papyrus_storage::StorageReader; -use starknet_api::block::BlockNumber; -use tokio::task::JoinHandle; - -/// Test configuration for consensus. -#[derive(Parser, Debug, Clone, PartialEq)] -pub struct TestConfig { - #[arg(long = "cache_size", help = "The cache size for the test network receiver.")] - pub cache_size: usize, - #[arg( - long = "random_seed", - help = "The random seed for the test simulation to ensure repeatable test results." - )] - pub random_seed: u64, - #[arg(long = "drop_probability", help = "The probability of dropping a message.")] - pub drop_probability: f64, - #[arg(long = "invalid_probability", help = "The probability of sending an invalid message.")] - pub invalid_probability: f64, - #[arg(long = "sync_topic", help = "The network topic for sync messages.")] - pub sync_topic: String, -} - -impl Default for TestConfig { - fn default() -> Self { - Self { - cache_size: 1000, - random_seed: 0, - drop_probability: 0.0, - invalid_probability: 0.0, - sync_topic: "consensus_test_sync".to_string(), - } - } -} - -fn build_consensus( - consensus_config: ConsensusConfig, - test_config: TestConfig, - storage_reader: StorageReader, - network_manager: &mut NetworkManager, -) -> anyhow::Result>>> { - let network_channels = network_manager.register_broadcast_topic( - Topic::new(consensus_config.network_topic.clone()), - BUFFER_SIZE, - )?; - // TODO(matan): connect this to an actual channel. - let sync_channels = network_manager - .register_broadcast_topic(Topic::new(test_config.sync_topic.clone()), BUFFER_SIZE)?; - let context = PapyrusConsensusContext::new( - storage_reader.clone(), - network_channels.broadcast_topic_client.clone(), - consensus_config.num_validators, - Some(sync_channels.broadcast_topic_client), - ); - let sync_receiver = - sync_channels.broadcasted_messages_receiver.map(|(vote, _report_sender)| { - BlockNumber(vote.expect("Sync channel should never have errors").height) - }); - let network_receiver = NetworkReceiver::new( - network_channels.broadcasted_messages_receiver, - test_config.cache_size, - test_config.random_seed, - test_config.drop_probability, - test_config.invalid_probability, - ); - let broadcast_channels = BroadcastConsensusMessageChannel { - broadcasted_messages_receiver: Box::new(network_receiver), - broadcast_topic_client: network_channels.broadcast_topic_client, - }; - - Ok(Some(tokio::spawn(async move { - Ok(papyrus_consensus::run_consensus( - context, - consensus_config.start_height, - consensus_config.validator_id, - consensus_config.consensus_delay, - consensus_config.timeouts.clone(), - broadcast_channels, - sync_receiver, - ) - .await?) - }))) -} - -#[tokio::main] -async fn main() -> anyhow::Result<()> { - let (test_config, node_config) = build_configs::("--test.")?; - - let mut resources = PapyrusResources::new(&node_config)?; - - let consensus_handle = build_consensus( - node_config.consensus.clone().unwrap(), - test_config, - resources.storage_reader.clone(), - resources.maybe_network_manager.as_mut().unwrap(), - )?; - let tasks = PapyrusTaskHandles { consensus_handle, ..Default::default() }; - - run(node_config, resources, tasks).await -} diff --git a/crates/papyrus_node/src/config/config_test.rs b/crates/papyrus_node/src/config/config_test.rs index fe7a025a5a3..5a2f1403456 100644 --- a/crates/papyrus_node/src/config/config_test.rs +++ b/crates/papyrus_node/src/config/config_test.rs @@ -7,9 +7,7 @@ use std::ops::IndexMut; use std::path::{Path, PathBuf}; use std::str::FromStr; -use assert_json_diff::assert_json_eq; use colored::Colorize; -use infra_utils::path::resolve_project_relative_path; use itertools::Itertools; use papyrus_base_layer::ethereum_base_layer_contract::EthereumBaseLayerConfig; use papyrus_config::dumping::SerializeConfig; @@ -19,6 +17,8 @@ use papyrus_monitoring_gateway::MonitoringGatewayConfig; use pretty_assertions::assert_eq; use serde_json::{json, Map, Value}; use starknet_api::core::ChainId; +use starknet_infra_utils::path::resolve_project_relative_path; +use starknet_infra_utils::test_utils::assert_json_eq; use tempfile::NamedTempFile; use validator::Validate; @@ -64,10 +64,10 @@ fn required_args() -> Vec { args } -fn get_args(additional_args: Vec<&str>) -> Vec { +fn get_args(additional_args: impl IntoIterator) -> Vec { let mut args = vec!["Papyrus".to_owned()]; - args.append(&mut required_args()); - args.append(&mut additional_args.into_iter().map(|s| s.to_owned()).collect()); + args.extend(required_args()); + args.extend(additional_args.into_iter().map(|s| s.to_string())); args } @@ -75,12 +75,18 @@ fn get_args(additional_args: Vec<&str>) -> Vec { fn load_default_config() { env::set_current_dir(resolve_project_relative_path("").unwrap()) .expect("Couldn't set working dir."); - NodeConfig::load_and_process(get_args(vec![])).expect("Failed to load the config."); + NodeConfig::load_and_process(get_args(["--chain_id", "SN_MAIN"])) + .expect("Failed to load the config."); } #[test] fn load_http_headers() { - let args = get_args(vec!["--central.http_headers", "NAME_1:VALUE_1 NAME_2:VALUE_2"]); + let args = get_args([ + "--central.http_headers", + "NAME_1:VALUE_1 NAME_2:VALUE_2", + "--chain_id", + "SN_MAIN", + ]); env::set_current_dir(resolve_project_relative_path("").unwrap()) .expect("Couldn't set working dir."); let config = NodeConfig::load_and_process(args).unwrap(); @@ -113,12 +119,17 @@ fn test_dump_default_config() { fn test_default_config_process() { env::set_current_dir(resolve_project_relative_path("").unwrap()) .expect("Couldn't set working dir."); - assert_eq!(NodeConfig::load_and_process(get_args(vec![])).unwrap(), NodeConfig::default()); + assert_eq!( + NodeConfig::load_and_process(get_args(["--chain_id", "SN_MAIN"])).unwrap(), + NodeConfig::default() + ); } #[test] fn test_update_dumped_config_by_command() { - let args = get_args(vec![ + let args = get_args([ + "--chain_id", + "SN_MAIN", "--central.retry_config.retry_max_delay_millis", "1234", "--storage.db_config.path_prefix", @@ -132,6 +143,8 @@ fn test_update_dumped_config_by_command() { assert_eq!(config.storage.db_config.path_prefix.to_str(), Some("/abc")); } +// TODO(Arni): share code with +// `starknet_sequencer_node::config::config_test::test_default_config_file_is_up_to_date`. #[cfg(feature = "rpc")] #[test] fn default_config_file_is_up_to_date() { @@ -155,13 +168,13 @@ fn default_config_file_is_up_to_date() { let from_code: serde_json::Value = serde_json::from_reader(File::open(tmp_file_path).unwrap()).unwrap(); - println!( - "{}", + let error_message = format!( + "{}\n{}", "Default config file doesn't match the default NodeConfig implementation. Please update \ it using the papyrus_dump_config binary." .purple() - .bold() + .bold(), + "Diffs shown below (default config file <<>> dump of NodeConfig::default())." ); - println!("Diffs shown below."); - assert_json_eq!(from_default_config_file, from_code) + assert_json_eq(&from_default_config_file, &from_code, error_message); } diff --git a/crates/papyrus_node/src/config/mod.rs b/crates/papyrus_node/src/config/mod.rs index e185710e53a..188d673f286 100644 --- a/crates/papyrus_node/src/config/mod.rs +++ b/crates/papyrus_node/src/config/mod.rs @@ -25,10 +25,9 @@ use papyrus_config::dumping::{ }; use papyrus_config::loading::load_and_process_config; use papyrus_config::{ConfigError, ParamPath, ParamPrivacyInput, SerializedParam}; -use papyrus_consensus::config::ConsensusConfig; use papyrus_monitoring_gateway::MonitoringGatewayConfig; use papyrus_network::NetworkConfig; -use papyrus_p2p_sync::client::{P2PSyncClient, P2PSyncClientConfig}; +use papyrus_p2p_sync::client::{P2pSyncClient, P2pSyncClientConfig}; #[cfg(feature = "rpc")] use papyrus_rpc::RpcConfig; use papyrus_storage::db::DbConfig; @@ -39,6 +38,8 @@ use serde::{Deserialize, Serialize}; use serde_json::{Map, Value}; use starknet_api::core::ChainId; use starknet_client::RetryConfig; +use starknet_consensus::config::ConsensusConfig; +use starknet_consensus_orchestrator::config::ContextConfig; use validator::Validate; use crate::version::VERSION_FULL; @@ -60,10 +61,11 @@ pub struct NodeConfig { /// None if the syncing should be disabled. pub sync: Option, /// One of p2p_sync or sync must be None. - /// If P2P sync is active, then network must be active too. - // TODO(yair): Change NodeConfig to have an option of enum of SyncConfig or P2PSyncConfig. - pub p2p_sync: Option, + /// If p2p sync is active, then network must be active too. + // TODO(yair): Change NodeConfig to have an option of enum of SyncConfig or P2pSyncConfig. + pub p2p_sync: Option, pub consensus: Option, + pub context: Option, // TODO(shahak): Make network non-optional once it's developed enough. pub network: Option, pub collect_profiling_metrics: bool, @@ -79,9 +81,10 @@ impl Default for NodeConfig { rpc: RpcConfig::default(), monitoring_gateway: MonitoringGatewayConfig::default(), storage: StorageConfig::default(), - sync: Some(SyncConfig::default()), + sync: Some(SyncConfig { store_sierras_and_casms: true, ..Default::default() }), p2p_sync: None, consensus: None, + context: None, network: None, collect_profiling_metrics: false, } @@ -99,6 +102,7 @@ impl SerializeConfig for NodeConfig { ser_optional_sub_config(&self.sync, "sync"), ser_optional_sub_config(&self.p2p_sync, "p2p_sync"), ser_optional_sub_config(&self.consensus, "consensus"), + ser_optional_sub_config(&self.context, "context"), ser_optional_sub_config(&self.network, "network"), BTreeMap::from_iter([ser_param( "collect_profiling_metrics", @@ -119,7 +123,7 @@ impl NodeConfig { /// higher priority. pub fn load_and_process(args: Vec) -> Result { let default_config_file = std::fs::File::open(Path::new(DEFAULT_CONFIG_PATH))?; - load_and_process_config(default_config_file, node_command(), args) + load_and_process_config(default_config_file, node_command(), args, false) } } diff --git a/crates/papyrus_node/src/config/pointers.rs b/crates/papyrus_node/src/config/pointers.rs index 850b35cc2c8..50721625f03 100644 --- a/crates/papyrus_node/src/config/pointers.rs +++ b/crates/papyrus_node/src/config/pointers.rs @@ -18,6 +18,7 @@ use papyrus_config::dumping::{ append_sub_config_name, ser_optional_sub_config, ser_pointer_target_param, + ser_pointer_target_required_param, set_pointing_param_paths, ConfigPointers, Pointers, @@ -26,10 +27,10 @@ use papyrus_config::dumping::{ use papyrus_config::loading::load_and_process_config; #[cfg(not(feature = "rpc"))] use papyrus_config::ParamPrivacyInput; -use papyrus_config::{ConfigError, ParamPath, SerializedParam}; +use papyrus_config::{ConfigError, ParamPath, SerializationType, SerializedParam}; use papyrus_monitoring_gateway::MonitoringGatewayConfig; use papyrus_network::NetworkConfig; -use papyrus_p2p_sync::client::{P2PSyncClient, P2PSyncClientConfig}; +use papyrus_p2p_sync::client::{P2pSyncClient, P2pSyncClientConfig}; #[cfg(feature = "rpc")] use papyrus_rpc::RpcConfig; use papyrus_storage::db::DbConfig; @@ -51,13 +52,13 @@ use crate::version::VERSION_FULL; pub static CONFIG_POINTERS: LazyLock = LazyLock::new(|| { vec![ ( - ser_pointer_target_param( + ser_pointer_target_required_param( "chain_id", - &ChainId::Mainnet, + SerializationType::String, "The chain to follow. For more details see https://docs.starknet.io/documentation/architecture_and_concepts/Blocks/transactions/#chain-id.", ), set_pointing_param_paths(&[ - "consensus.network_config.chain_id", + "context.chain_id", "network.chain_id", "rpc.chain_id", "storage.db_config.chain_id", diff --git a/crates/papyrus_node/src/config/snapshots/papyrus_node__config__config_test__dump_default_config.snap b/crates/papyrus_node/src/config/snapshots/papyrus_node__config__config_test__dump_default_config.snap index bc2248761a1..951a9d68bbf 100644 --- a/crates/papyrus_node/src/config/snapshots/papyrus_node__config__config_test__dump_default_config.snap +++ b/crates/papyrus_node/src/config/snapshots/papyrus_node__config__config_test__dump_default_config.snap @@ -4,8 +4,8 @@ expression: dumped_default_config --- { "base_layer.node_url": { - "description": "A required param! Ethereum node URL. A schema to match to Infura node: https://mainnet.infura.io/v3/, but any other node can be used.", - "param_type": "String", + "description": "Ethereum node URL. A schema to match to Infura node: https://mainnet.infura.io/v3/, but any other node can be used.", + "value": "https://mainnet.infura.io/v3/%3Cyour_api_key%3E", "privacy": "Private" }, "base_layer.starknet_contract_address": { @@ -89,158 +89,122 @@ expression: dumped_default_config "value": true, "privacy": "TemporaryValue" }, - "consensus.consensus_delay": { - "description": "Delay (seconds) before starting consensus to give time for network peering.", + "consensus.future_height_limit": { + "description": "How many heights in the future should we cache.", "value": { - "$serde_json::private::Number": "5" + "$serde_json::private::Number": "10" }, "privacy": "Public" }, - "consensus.network_config.advertised_multiaddr": { - "description": "The external address other peers see this node. If this is set, the node will not try to find out which addresses it has and will write this address as external instead", - "value": "", - "privacy": "Public" - }, - "consensus.network_config.advertised_multiaddr.#is_none": { - "description": "Flag for an optional field.", - "value": true, - "privacy": "TemporaryValue" - }, - "consensus.network_config.bootstrap_peer_multiaddr": { - "description": "The multiaddress of the peer node. It should include the peer's id. For more info: https://docs.libp2p.io/concepts/fundamentals/peers/", - "value": "", - "privacy": "Public" - }, - "consensus.network_config.bootstrap_peer_multiaddr.#is_none": { - "description": "Flag for an optional field.", - "value": true, - "privacy": "TemporaryValue" - }, - "consensus.network_config.chain_id": { - "description": "The chain to follow. For more details see https://docs.starknet.io/documentation/architecture_and_concepts/Blocks/transactions/#chain-id.", - "value": "SN_MAIN", - "privacy": "Public" - }, - "consensus.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": { - "description": "The base delay in milliseconds for the exponential backoff strategy.", + "consensus.future_height_round_limit": { + "description": "How many rounds should we cache for future heights.", "value": { - "$serde_json::private::Number": "2" + "$serde_json::private::Number": "1" }, "privacy": "Public" }, - "consensus.network_config.discovery_config.bootstrap_dial_retry_config.factor": { - "description": "The factor for the exponential backoff strategy.", + "consensus.future_round_limit": { + "description": "How many rounds in the future (for current height) should we cache.", "value": { - "$serde_json::private::Number": "5" + "$serde_json::private::Number": "10" }, "privacy": "Public" }, - "consensus.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": { - "description": "The maximum delay in seconds for the exponential backoff strategy.", + "consensus.startup_delay": { + "description": "Delay (seconds) before starting consensus to give time for network peering.", "value": { "$serde_json::private::Number": "5" }, "privacy": "Public" }, - "consensus.network_config.discovery_config.heartbeat_interval": { - "description": "The interval between each discovery (Kademlia) query in milliseconds.", + "consensus.sync_retry_interval": { + "description": "The duration (seconds) between sync attempts.", "value": { - "$serde_json::private::Number": "100" + "$serde_json::private::Number": "1.0" }, "privacy": "Public" }, - "consensus.network_config.idle_connection_timeout": { - "description": "Amount of time in seconds that a connection with no active sessions will stay alive.", + "consensus.timeouts.precommit_timeout": { + "description": "The timeout (seconds) for a precommit.", "value": { - "$serde_json::private::Number": "120" + "$serde_json::private::Number": "1.0" }, "privacy": "Public" }, - "consensus.network_config.peer_manager_config.malicious_timeout_seconds": { - "description": "The duration in seconds a peer is blacklisted after being marked as malicious.", + "consensus.timeouts.prevote_timeout": { + "description": "The timeout (seconds) for a prevote.", "value": { - "$serde_json::private::Number": "31536000" + "$serde_json::private::Number": "1.0" }, "privacy": "Public" }, - "consensus.network_config.peer_manager_config.unstable_timeout_millis": { - "description": "The duration in milliseconds a peer blacklisted after being reported as unstable.", + "consensus.timeouts.proposal_timeout": { + "description": "The timeout (seconds) for a proposal.", "value": { - "$serde_json::private::Number": "1000" + "$serde_json::private::Number": "3.0" }, "privacy": "Public" }, - "consensus.network_config.quic_port": { - "description": "The port that the node listens on for incoming quic connections.", - "value": { - "$serde_json::private::Number": "10101" - }, + "consensus.validator_id": { + "description": "The validator id of the node.", + "value": "0x64", "privacy": "Public" }, - "consensus.network_config.secret_key": { - "description": "The secret key used for building the peer id. If it's an empty string a random one will be used.", - "value": "", - "privacy": "Private" + "context.#is_none": { + "description": "Flag for an optional field.", + "value": true, + "privacy": "TemporaryValue" }, - "consensus.network_config.session_timeout": { - "description": "Maximal time in seconds that each session can take before failing on timeout.", + "context.block_timestamp_window": { + "description": "Maximum allowed deviation (seconds) of a proposed block's timestamp from the current time.", "value": { - "$serde_json::private::Number": "120" + "$serde_json::private::Number": "1" }, "privacy": "Public" }, - "consensus.network_config.tcp_port": { - "description": "The port that the node listens on for incoming tcp connections.", + "context.build_proposal_margin": { + "description": "Safety margin (in ms) to make sure that the batcher completes building the proposal with enough time for the Fin to be checked by validators.", "value": { - "$serde_json::private::Number": "10100" + "$serde_json::private::Number": "1000" }, "privacy": "Public" }, - "consensus.network_topic": { - "description": "The network topic of the consensus.", - "value": "consensus", + "context.builder_address": { + "description": "The address of the contract that builds the block.", + "value": "0x0", "privacy": "Public" }, - "consensus.num_validators": { - "description": "The number of validators in the consensus.", - "value": { - "$serde_json::private::Number": "1" - }, + "context.chain_id": { + "description": "The chain id of the Starknet chain.", + "value": "SN_MAIN", "privacy": "Public" }, - "consensus.start_height": { - "description": "The height to start the consensus from.", - "value": { - "$serde_json::private::Number": "0" - }, + "context.l1_da_mode": { + "description": "The data availability mode, true: Blob, false: Calldata.", + "value": true, "privacy": "Public" }, - "consensus.timeouts.precommit_timeout": { - "description": "The timeout (seconds) for a precommit.", + "context.num_validators": { + "description": "The number of validators.", "value": { - "$serde_json::private::Number": "1.0" + "$serde_json::private::Number": "1" }, "privacy": "Public" }, - "consensus.timeouts.prevote_timeout": { - "description": "The timeout (seconds) for a prevote.", + "context.proposal_buffer_size": { + "description": "The buffer size for streaming outbound proposals.", "value": { - "$serde_json::private::Number": "1.0" + "$serde_json::private::Number": "100" }, "privacy": "Public" }, - "consensus.timeouts.proposal_timeout": { - "description": "The timeout (seconds) for a proposal.", + "context.validate_proposal_margin": { + "description": "Safety margin (in ms) to make sure that consensus determines when to timeout validating a proposal.", "value": { - "$serde_json::private::Number": "3.0" + "$serde_json::private::Number": "10000" }, "privacy": "Public" }, - "consensus.validator_id": { - "description": "The validator id of the node.", - "value": "0x0", - "privacy": "Public" - }, "monitoring_gateway.collect_metrics": { "description": "If true, collect and return metrics in the monitoring gateway.", "value": false, @@ -334,7 +298,7 @@ expression: dumped_default_config "network.peer_manager_config.malicious_timeout_seconds": { "description": "The duration in seconds a peer is blacklisted after being marked as malicious.", "value": { - "$serde_json::private::Number": "31536000" + "$serde_json::private::Number": "1" }, "privacy": "Public" }, @@ -345,10 +309,10 @@ expression: dumped_default_config }, "privacy": "Public" }, - "network.quic_port": { - "description": "The port that the node listens on for incoming quic connections.", + "network.port": { + "description": "The port that the node listens on for incoming tcp connections.", "value": { - "$serde_json::private::Number": "10001" + "$serde_json::private::Number": "10000" }, "privacy": "Public" }, @@ -364,13 +328,6 @@ expression: dumped_default_config }, "privacy": "Public" }, - "network.tcp_port": { - "description": "The port that the node listens on for incoming tcp connections.", - "value": { - "$serde_json::private::Number": "10000" - }, - "privacy": "Public" - }, "p2p_sync.#is_none": { "description": "Flag for an optional field.", "value": true, @@ -411,22 +368,17 @@ expression: dumped_default_config }, "privacy": "Public" }, - "p2p_sync.stop_sync_at_block_number": { - "description": "Stops the sync at given block number and closes the node cleanly. Used to run profiling on the node.", + "p2p_sync.wait_period_for_new_data": { + "description": "Time in millisseconds to wait when a query returned with partial data before sending a new query", "value": { - "$serde_json::private::Number": "1000" + "$serde_json::private::Number": "50" }, "privacy": "Public" }, - "p2p_sync.stop_sync_at_block_number.#is_none": { - "description": "Flag for an optional field.", - "value": true, - "privacy": "TemporaryValue" - }, - "p2p_sync.wait_period_for_new_data": { - "description": "Time in seconds to wait when a query returned with partial data before sending a new query", + "p2p_sync.wait_period_for_other_protocol": { + "description": "Time in millisseconds to wait for a dependency protocol to advance (e.g.state diff sync depends on header sync)", "value": { - "$serde_json::private::Number": "5" + "$serde_json::private::Number": "50" }, "privacy": "Public" }, @@ -609,6 +561,11 @@ expression: dumped_default_config }, "privacy": "Public" }, + "sync.store_sierras_and_casms": { + "description": "Whether to store sierras and casms to the storage. This allows maintaining backward-compatibility with native-blockifier", + "value": true, + "privacy": "Public" + }, "sync.verify_blocks": { "description": "Whether to verify incoming blocks.", "value": true, diff --git a/crates/papyrus_node/src/run.rs b/crates/papyrus_node/src/run.rs index 2ddd3297990..dc22c9764d1 100644 --- a/crates/papyrus_node/src/run.rs +++ b/crates/papyrus_node/src/run.rs @@ -7,35 +7,35 @@ use std::process::exit; use std::sync::Arc; use std::time::Duration; +use futures::StreamExt; use papyrus_base_layer::ethereum_base_layer_contract::EthereumBaseLayerConfig; use papyrus_common::metrics::COLLECT_PROFILING_METRICS; use papyrus_common::pending_classes::PendingClasses; use papyrus_config::presentation::get_config_presentation; use papyrus_config::validators::config_validate; -use papyrus_consensus::config::ConsensusConfig; -use papyrus_consensus_orchestrator::papyrus_consensus_context::PapyrusConsensusContext; use papyrus_monitoring_gateway::MonitoringServer; -use papyrus_network::gossipsub_impl::Topic; use papyrus_network::network_manager::NetworkManager; use papyrus_network::{network_manager, NetworkConfig}; -use papyrus_p2p_sync::client::{P2PSyncClient, P2PSyncClientChannels}; -use papyrus_p2p_sync::server::{P2PSyncServer, P2PSyncServerChannels}; +use papyrus_p2p_sync::client::{P2pSyncClient, P2pSyncClientChannels}; +use papyrus_p2p_sync::server::{P2pSyncServer, P2pSyncServerChannels}; use papyrus_p2p_sync::{Protocol, BUFFER_SIZE}; #[cfg(feature = "rpc")] use papyrus_rpc::run_server; -use papyrus_storage::{open_storage, update_storage_metrics, StorageReader, StorageWriter}; -use papyrus_sync::sources::base_layer::{BaseLayerSourceError, EthereumBaseLayerSource}; +use papyrus_storage::storage_metrics::update_storage_metrics; +use papyrus_storage::{open_storage, StorageReader, StorageWriter}; +use papyrus_sync::sources::base_layer::EthereumBaseLayerSource; use papyrus_sync::sources::central::{CentralError, CentralSource, CentralSourceConfig}; use papyrus_sync::sources::pending::PendingSource; -use papyrus_sync::{StateSync, SyncConfig}; +use papyrus_sync::{StateSync as CentralStateSync, SyncConfig as CentralSyncConfig}; use starknet_api::block::{BlockHash, BlockHashAndNumber}; use starknet_api::felt; +use starknet_class_manager_types::{EmptyClassManagerClient, SharedClassManagerClient}; use starknet_client::reader::objects::pending_data::{PendingBlock, PendingBlockOrDeprecated}; use starknet_client::reader::PendingData; use tokio::sync::RwLock; use tokio::task::JoinHandle; use tracing::metadata::LevelFilter; -use tracing::{debug, debug_span, error, info, warn, Instrument}; +use tracing::{debug_span, error, info, warn, Instrument}; use tracing_subscriber::prelude::*; use tracing_subscriber::{fmt, EnvFilter}; @@ -45,9 +45,9 @@ use crate::version::VERSION_FULL; // TODO(yair): Add to config. const DEFAULT_LEVEL: LevelFilter = LevelFilter::INFO; -// TODO(shahak): Consider adding genesis hash to the config to support chains that have +// TODO(Shahak): Consider adding genesis hash to the config to support chains that have // different genesis hash. -// TODO: Consider moving to a more general place. +// TODO(Shahak): Consider moving to a more general place. const GENESIS_HASH: &str = "0x0"; // TODO(dvir): add this to config. @@ -62,6 +62,7 @@ pub struct PapyrusResources { pub shared_highest_block: Arc>>, pub pending_data: Arc>, pub pending_classes: Arc>, + pub class_manager_client: SharedClassManagerClient, } /// Struct which allows configuring how the node will run. @@ -75,7 +76,6 @@ pub struct PapyrusTaskHandles { pub sync_client_handle: Option>>, pub monitoring_server_handle: Option>>, pub p2p_sync_server_handle: Option>>, - pub consensus_handle: Option>>, pub network_handle: Option>>, } @@ -94,6 +94,8 @@ impl PapyrusResources { ..Default::default() })); let pending_classes = Arc::new(RwLock::new(PendingClasses::default())); + // TODO(noamsp): Remove this and use the real client instead once implemented. + let class_manager_client = Arc::new(EmptyClassManagerClient); Ok(Self { storage_reader, storage_writer, @@ -102,6 +104,7 @@ impl PapyrusResources { shared_highest_block, pending_data, pending_classes, + class_manager_client, }) } } @@ -115,6 +118,7 @@ fn build_network_manager( let network_manager = network_manager::NetworkManager::new( network_config.clone(), Some(VERSION_FULL.to_string()), + None, ); let local_peer_id = network_manager.get_local_peer_id(); @@ -171,42 +175,8 @@ fn spawn_monitoring_server( Ok(tokio::spawn(async move { Ok(monitoring_server.run_server().await?) })) } -fn spawn_consensus( - config: Option<&ConsensusConfig>, - storage_reader: StorageReader, - network_manager: Option<&mut NetworkManager>, -) -> anyhow::Result>> { - let (Some(config), Some(network_manager)) = (config, network_manager) else { - info!("Consensus is disabled."); - return Ok(tokio::spawn(future::pending())); - }; - let config = config.clone(); - debug!("Consensus configuration: {config:?}"); - - let network_channels = network_manager - .register_broadcast_topic(Topic::new(config.network_topic.clone()), BUFFER_SIZE)?; - let context = PapyrusConsensusContext::new( - storage_reader.clone(), - network_channels.broadcast_topic_client.clone(), - config.num_validators, - None, - ); - Ok(tokio::spawn(async move { - Ok(papyrus_consensus::run_consensus( - context, - config.start_height, - config.validator_id, - config.consensus_delay, - config.timeouts.clone(), - network_channels.into(), - futures::stream::pending(), - ) - .await?) - })) -} - async fn run_sync( - configs: (SyncConfig, CentralSourceConfig, EthereumBaseLayerConfig), + configs: (CentralSyncConfig, CentralSourceConfig, EthereumBaseLayerConfig), shared_highest_block: Arc>>, pending_data: Arc>, pending_classes: Arc>, @@ -219,9 +189,9 @@ async fn run_sync( .map_err(CentralError::ClientCreation)?; let pending_source = PendingSource::new(central_config, VERSION_FULL).map_err(CentralError::ClientCreation)?; - let base_layer_source = EthereumBaseLayerSource::new(base_layer_config) - .map_err(|e| BaseLayerSourceError::BaseLayerSourceCreationError(e.to_string()))?; - let sync = StateSync::new( + let base_layer_source = Some(EthereumBaseLayerSource::new(base_layer_config)); + let class_manager_client = None; + let sync = CentralStateSync::new( sync_config, shared_highest_block, pending_data, @@ -231,10 +201,12 @@ async fn run_sync( base_layer_source, storage_reader.clone(), storage_writer, + class_manager_client, ); Ok(sync.run().await?) } +#[allow(clippy::too_many_arguments)] async fn spawn_sync_client( maybe_network_manager: Option<&mut NetworkManager>, storage_reader: StorageReader, @@ -243,6 +215,7 @@ async fn spawn_sync_client( shared_highest_block: Arc>>, pending_data: Arc>, pending_classes: Arc>, + class_manager_client: SharedClassManagerClient, ) -> JoinHandle> { match (config.sync, config.p2p_sync) { (Some(_), Some(_)) => { @@ -271,19 +244,21 @@ async fn spawn_sync_client( .register_sqmr_protocol_client(Protocol::Transaction.into(), BUFFER_SIZE); let class_client_sender = network_manager.register_sqmr_protocol_client(Protocol::Class.into(), BUFFER_SIZE); - let p2p_sync_client_channels = P2PSyncClientChannels::new( + let p2p_sync_client_channels = P2pSyncClientChannels::new( header_client_sender, state_diff_client_sender, transaction_client_sender, class_client_sender, ); - let p2p_sync = P2PSyncClient::new( + let p2p_sync = P2pSyncClient::new( p2p_sync_client_config, storage_reader, storage_writer, p2p_sync_client_channels, + futures::stream::pending().boxed(), + class_manager_client, ); - tokio::spawn(async move { Ok(p2p_sync.run().await?) }) + tokio::spawn(async move { Ok(p2p_sync.run().await.map(|_never| ())?) }) } } } @@ -291,9 +266,10 @@ async fn spawn_sync_client( fn spawn_p2p_sync_server( network_manager: Option<&mut NetworkManager>, storage_reader: StorageReader, + class_manager_client: SharedClassManagerClient, ) -> JoinHandle> { let Some(network_manager) = network_manager else { - info!("P2P Sync is disabled."); + info!("P2p Sync is disabled."); return tokio::spawn(future::pending()); }; @@ -308,7 +284,7 @@ fn spawn_p2p_sync_server( let event_server_receiver = network_manager.register_sqmr_protocol_server(Protocol::Event.into(), BUFFER_SIZE); - let p2p_sync_server_channels = P2PSyncServerChannels::new( + let p2p_sync_server_channels = P2pSyncServerChannels::new( header_server_receiver, state_diff_server_receiver, transaction_server_receiver, @@ -316,10 +292,11 @@ fn spawn_p2p_sync_server( event_server_receiver, ); - let p2p_sync_server = P2PSyncServer::new(storage_reader.clone(), p2p_sync_server_channels); + let p2p_sync_server = + P2pSyncServer::new(storage_reader.clone(), p2p_sync_server_channels, class_manager_client); tokio::spawn(async move { - p2p_sync_server.run().await; - Ok(()) + let _never = p2p_sync_server.run().await; + unreachable!("Return type Never should never be constructed."); }) } @@ -328,16 +305,6 @@ async fn run_threads( mut resources: PapyrusResources, tasks: PapyrusTaskHandles, ) -> anyhow::Result<()> { - let consensus_handle = if let Some(handle) = tasks.consensus_handle { - handle - } else { - spawn_consensus( - config.consensus.as_ref(), - resources.storage_reader.clone(), - resources.maybe_network_manager.as_mut(), - )? - }; - let storage_metrics_handle = if let Some(handle) = tasks.storage_metrics_handle { handle } else { @@ -372,13 +339,14 @@ async fn run_threads( .await? }; - // P2P Sync Server task. + // P2p Sync Server task. let p2p_sync_server_handle = if let Some(handle) = tasks.p2p_sync_server_handle { handle } else { spawn_p2p_sync_server( resources.maybe_network_manager.as_mut(), resources.storage_reader.clone(), + resources.class_manager_client.clone(), ) }; @@ -394,6 +362,7 @@ async fn run_threads( resources.shared_highest_block, resources.pending_data, resources.pending_classes, + resources.class_manager_client.clone(), ) .await }; @@ -425,17 +394,13 @@ async fn run_threads( res?? } res = p2p_sync_server_handle => { - error!("P2P Sync server stopped"); + error!("P2p Sync server stopped"); res?? } res = network_handle => { error!("Network stopped."); res?? } - res = consensus_handle => { - error!("Consensus stopped."); - res?? - } }; error!("Task ended with unexpected Ok."); Ok(()) diff --git a/crates/papyrus_p2p_sync/Cargo.toml b/crates/papyrus_p2p_sync/Cargo.toml index 653fbd259b4..5224d63f6e1 100644 --- a/crates/papyrus_p2p_sync/Cargo.toml +++ b/crates/papyrus_p2p_sync/Cargo.toml @@ -19,23 +19,30 @@ papyrus_network.workspace = true papyrus_proc_macros.workspace = true papyrus_protobuf.workspace = true papyrus_storage.workspace = true +papyrus_sync.workspace = true +papyrus_test_utils.workspace = true rand.workspace = true +rand_chacha.workspace = true serde.workspace = true starknet_api.workspace = true +starknet_state_sync_types.workspace = true starknet-types-core.workspace = true thiserror.workspace = true +starknet_class_manager_types.workspace = true +async-trait.workspace = true tokio.workspace = true tokio-stream.workspace = true tracing.workspace = true +validator.workspace = true [dev-dependencies] assert_matches.workspace = true lazy_static.workspace = true +mockall.workspace = true papyrus_network = { workspace = true, features = ["testing"] } papyrus_protobuf = { workspace = true, features = ["testing"] } papyrus_storage = { workspace = true, features = ["testing"] } -papyrus_test_utils.workspace = true -rand_chacha.workspace = true +starknet_class_manager_types = { workspace = true, features = ["testing"] } static_assertions.workspace = true tokio = { workspace = true, features = ["test-util"] } diff --git a/crates/papyrus_p2p_sync/src/client/block_data_stream_builder.rs b/crates/papyrus_p2p_sync/src/client/block_data_stream_builder.rs new file mode 100644 index 00000000000..c6ce2afefa7 --- /dev/null +++ b/crates/papyrus_p2p_sync/src/client/block_data_stream_builder.rs @@ -0,0 +1,294 @@ +use std::cmp::min; +use std::collections::HashMap; +use std::time::Duration; + +use async_stream::stream; +use futures::channel::mpsc::Receiver; +use futures::future::BoxFuture; +use futures::stream::BoxStream; +use futures::{FutureExt, StreamExt}; +use papyrus_network::network_manager::{ClientResponsesManager, SqmrClientSender}; +use papyrus_protobuf::converters::ProtobufConversionError; +use papyrus_protobuf::sync::{BlockHashOrNumber, DataOrFin, Direction, Query}; +use papyrus_storage::header::HeaderStorageReader; +use papyrus_storage::state::StateStorageReader; +use papyrus_storage::{StorageError, StorageReader, StorageWriter}; +use starknet_api::block::{BlockNumber, BlockSignature}; +use starknet_api::core::ClassHash; +use starknet_class_manager_types::SharedClassManagerClient; +use starknet_state_sync_types::state_sync_types::SyncBlock; +use tracing::{debug, info, trace, warn}; + +use super::{P2pSyncClientError, STEP}; + +pub type BlockDataResult = Result, P2pSyncClientError>; + +pub(crate) trait BlockData: Send { + /// Write the block data to the storage. + // Async functions in trait don't work well with argument references + fn write_to_storage<'a>( + // This is Box in order to allow using it with `Box`. + self: Box, + storage_writer: &'a mut StorageWriter, + class_manager_client: &'a mut SharedClassManagerClient, + ) -> BoxFuture<'a, Result<(), P2pSyncClientError>>; +} + +pub(crate) enum BlockNumberLimit { + Unlimited, + HeaderMarker, + StateDiffMarker, +} + +pub(crate) trait BlockDataStreamBuilder +where + InputFromNetwork: Send + 'static, + DataOrFin: TryFrom, Error = ProtobufConversionError>, +{ + type Output: BlockData + 'static; + + const TYPE_DESCRIPTION: &'static str; + const BLOCK_NUMBER_LIMIT: BlockNumberLimit; + + // Async functions in trait don't work well with argument references + /// Parse data for a specific block received from the network and return a future resolving to + /// an optional block data output or a parse error. + fn parse_data_for_block<'a>( + client_response_manager: &'a mut ClientResponsesManager>, + block_number: BlockNumber, + storage_reader: &'a StorageReader, + ) -> BoxFuture<'a, Result, ParseDataError>>; + + /// Get the starting block number for this stream. + fn get_start_block_number(storage_reader: &StorageReader) -> Result; + + /// Convert a sync block into block data. + fn convert_sync_block_to_block_data( + block_number: BlockNumber, + sync_block: SyncBlock, + ) -> Self::Output; + + // Async functions in trait don't work well with argument references + /// Retrieve the internal block for a specific block number. + fn get_internal_block_at<'a>( + internal_blocks_received: &'a mut HashMap, + internal_block_receiver: &'a mut Option>, + current_block_number: BlockNumber, + ) -> BoxFuture<'a, Self::Output> { + async move { + if let Some(block) = internal_blocks_received.remove(¤t_block_number) { + return block; + } + let internal_block_receiver = + internal_block_receiver.as_mut().expect("Internal block receiver not set"); + while let Some(sync_block) = internal_block_receiver.next().await { + let block_number = sync_block.block_header_without_hash.block_number; + if block_number >= current_block_number { + let block_data = + Self::convert_sync_block_to_block_data(block_number, sync_block); + if block_number == current_block_number { + return block_data; + } + internal_blocks_received.insert(block_number, block_data); + } + } + panic!("Internal block receiver terminated"); + } + .boxed() + } + + /// Create a stream for fetching and processing block data. + fn create_stream( + mut sqmr_sender: SqmrClientSender>, + storage_reader: StorageReader, + mut internal_block_receiver: Option>, + wait_period_for_new_data: Duration, + wait_period_for_other_protocol: Duration, + num_blocks_per_query: u64, + ) -> BoxStream<'static, BlockDataResult> + where + TQuery: From + Send + 'static, + Vec: From, + { + stream! { + let mut current_block_number = Self::get_start_block_number(&storage_reader)?; + let mut internal_blocks_received = HashMap::new(); + 'send_query_and_parse_responses: loop { + let limit = match Self::BLOCK_NUMBER_LIMIT { + BlockNumberLimit::Unlimited => num_blocks_per_query, + BlockNumberLimit::HeaderMarker | BlockNumberLimit::StateDiffMarker => { + let (last_block_number, description) = match Self::BLOCK_NUMBER_LIMIT { + BlockNumberLimit::HeaderMarker => (storage_reader.begin_ro_txn()?.get_header_marker()?, "header"), + BlockNumberLimit::StateDiffMarker => (storage_reader.begin_ro_txn()?.get_state_marker()?, "state diff"), + _ => unreachable!(), + }; + let limit = min(last_block_number.0 - current_block_number.0, num_blocks_per_query); + if limit == 0 { + trace!("{:?} sync is waiting for a new {}", Self::TYPE_DESCRIPTION, description); + tokio::time::sleep(wait_period_for_other_protocol).await; + continue; + } + limit + }, + }; + if let Some(block) = Self::get_internal_block_at(&mut internal_blocks_received, &mut internal_block_receiver, current_block_number) + .now_or_never() + { + info!("Added internally {:?} for block {}.", Self::TYPE_DESCRIPTION, current_block_number); + yield Ok(Box::::from(Box::new(block))); + current_block_number = current_block_number.unchecked_next(); + continue 'send_query_and_parse_responses; + } + + let end_block_number = current_block_number.0 + limit; + debug!( + "Sync sent query for {:?} for blocks [{}, {}) from network.", + Self::TYPE_DESCRIPTION, + current_block_number.0, + end_block_number, + ); + + // TODO(shahak): Use the report callback. + let mut client_response_manager = sqmr_sender + .send_new_query( + TQuery::from(Query { + start_block: BlockHashOrNumber::Number(current_block_number), + direction: Direction::Forward, + limit, + step: STEP, + }) + ).await?; + while current_block_number.0 < end_block_number { + tokio::select! { + res = Self::parse_data_for_block( + &mut client_response_manager, current_block_number, &storage_reader + ) => { + match res { + Ok(Some(output)) => { + info!("Added {:?} for block {}.", Self::TYPE_DESCRIPTION, current_block_number); + current_block_number = current_block_number.unchecked_next(); + yield Ok(Box::::from(Box::new(output))); + } + Ok(None) => { + debug!( + "Query for {:?} on {:?} returned with partial data. Waiting {:?} before \ + sending another query.", + Self::TYPE_DESCRIPTION, current_block_number, wait_period_for_new_data + ); + tokio::time::sleep(wait_period_for_new_data).await; + continue 'send_query_and_parse_responses; + }, + Err(ParseDataError::BadPeer(err)) => { + warn!( + "Query for {:?} on {:?} returned with bad peer error: {:?}. reporting \ + peer and retrying query.", + Self::TYPE_DESCRIPTION, current_block_number, err + ); + client_response_manager.report_peer(); + continue 'send_query_and_parse_responses; + }, + Err(ParseDataError::Fatal(err)) => { + yield Err(err); + return; + }, + } + } + block = Self::get_internal_block_at(&mut internal_blocks_received, &mut internal_block_receiver, current_block_number) => { + info!("Added internally {:?} for block {}.", Self::TYPE_DESCRIPTION, current_block_number); + current_block_number = current_block_number.unchecked_next(); + yield Ok(Box::::from(Box::new(block))); + debug!("Network query ending at block {} for {:?} being ignored due to internal block", end_block_number, Self::TYPE_DESCRIPTION); + continue 'send_query_and_parse_responses; + } + } + } + + // Consume the None message signaling the end of the query. + match client_response_manager.next().await { + Some(Ok(DataOrFin(None))) => { + debug!("Network query ending at block {} for {:?} finished", end_block_number, Self::TYPE_DESCRIPTION); + }, + Some(_) => { + warn!( + "Query for {:?} returned more messages after {:?} even though it \ + should have returned Fin. reporting peer and retrying query.", + Self::TYPE_DESCRIPTION, current_block_number + ); + client_response_manager.report_peer(); + continue 'send_query_and_parse_responses; + } + + None => { + warn!( + "Query for {:?} didn't send Fin after block {:?}. \ + Reporting peer and retrying query.", + Self::TYPE_DESCRIPTION, current_block_number + ); + client_response_manager.report_peer(); + continue 'send_query_and_parse_responses; + } + } + } + }.boxed() + } +} + +#[derive(thiserror::Error, Debug)] +pub(crate) enum BadPeerError { + #[error("The sender end of the response receivers for {type_description:?} was closed.")] + SessionEndedWithoutFin { type_description: &'static str }, + #[error( + "Blocks returned unordered from the network. Expected header with \ + {expected_block_number}, got {actual_block_number}." + )] + HeadersUnordered { expected_block_number: BlockNumber, actual_block_number: BlockNumber }, + #[error( + "Expected to receive {expected} transactions for {block_number} from the network. Got \ + {actual} instead." + )] + NotEnoughTransactions { expected: usize, actual: usize, block_number: u64 }, + #[error("Expected to receive one signature from the network. got {signatures:?} instead.")] + WrongSignaturesLength { signatures: Vec }, + #[error( + "The header says that the block's state diff should be of length {expected_length}. Can \ + only divide the state diff parts into the following lengths: {possible_lengths:?}." + )] + WrongStateDiffLength { expected_length: usize, possible_lengths: Vec }, + #[error("Two state diff parts for the same state diff are conflicting.")] + ConflictingStateDiffParts, + #[error( + "Received an empty state diff part from the network (this is a potential DDoS vector)." + )] + EmptyStateDiffPart, + #[error(transparent)] + ProtobufConversionError(#[from] ProtobufConversionError), + #[error( + "Expected to receive {expected} classes for {block_number} from the network. Got {actual} \ + classes instead" + )] + NotEnoughClasses { expected: usize, actual: usize, block_number: u64 }, + #[error("The class with hash {class_hash} was not found in the state diff.")] + ClassNotInStateDiff { class_hash: ClassHash }, + #[error("Received two classes with the same hash: {class_hash}.")] + DuplicateClass { class_hash: ClassHash }, +} + +#[derive(thiserror::Error, Debug)] +pub(crate) enum ParseDataError { + #[error(transparent)] + Fatal(#[from] P2pSyncClientError), + #[error(transparent)] + BadPeer(#[from] BadPeerError), +} + +impl From for ParseDataError { + fn from(err: StorageError) -> Self { + ParseDataError::Fatal(P2pSyncClientError::StorageError(err)) + } +} + +impl From for ParseDataError { + fn from(err: ProtobufConversionError) -> Self { + ParseDataError::BadPeer(BadPeerError::ProtobufConversionError(err)) + } +} diff --git a/crates/papyrus_p2p_sync/src/client/class.rs b/crates/papyrus_p2p_sync/src/client/class.rs index 9cb5dfaa390..5cb34d60563 100644 --- a/crates/papyrus_p2p_sync/src/client/class.rs +++ b/crates/papyrus_p2p_sync/src/client/class.rs @@ -5,45 +5,80 @@ use futures::{FutureExt, StreamExt}; use papyrus_common::pending_classes::ApiContractClass; use papyrus_network::network_manager::ClientResponsesManager; use papyrus_protobuf::sync::DataOrFin; -use papyrus_storage::class::{ClassStorageReader, ClassStorageWriter}; +use papyrus_storage::class_manager::{ClassManagerStorageReader, ClassManagerStorageWriter}; use papyrus_storage::state::StateStorageReader; use papyrus_storage::{StorageError, StorageReader, StorageWriter}; +use papyrus_sync::metrics::SYNC_CLASS_MANAGER_MARKER; use starknet_api::block::BlockNumber; use starknet_api::core::ClassHash; use starknet_api::state::{DeclaredClasses, DeprecatedDeclaredClasses}; +use starknet_class_manager_types::SharedClassManagerClient; +use starknet_state_sync_types::state_sync_types::SyncBlock; +use tracing::{trace, warn}; -use super::stream_builder::{ +use super::block_data_stream_builder::{ BadPeerError, BlockData, + BlockDataStreamBuilder, BlockNumberLimit, - DataStreamBuilder, ParseDataError, }; -use super::{P2PSyncClientError, NETWORK_DATA_TIMEOUT}; +use super::P2pSyncClientError; impl BlockData for (DeclaredClasses, DeprecatedDeclaredClasses, BlockNumber) { - fn write_to_storage( + fn write_to_storage<'a>( self: Box, - storage_writer: &mut StorageWriter, - ) -> Result<(), StorageError> { - storage_writer - .begin_rw_txn()? - .append_classes( - self.2, - &self.0.iter().map(|(class_hash, class)| (*class_hash, class)).collect::>(), - &self - .1 - .iter() - .map(|(class_hash, deprecated_class)| (*class_hash, deprecated_class)) - .collect::>(), - )? - .commit() + storage_writer: &'a mut StorageWriter, + class_manager_client: &'a mut SharedClassManagerClient, + ) -> BoxFuture<'a, Result<(), P2pSyncClientError>> { + async move { + for (class_hash, class) in self.0 { + // We can't continue without writing to the class manager, so we'll keep retrying + // until it succeeds. + // TODO(shahak): Test this flow. + // TODO(shahak): Verify class hash matches class manager response. report if not. + // TODO(shahak): Try to avoid cloning. See if ClientError can contain the request. + while let Err(err) = class_manager_client.add_class(class.clone()).await { + warn!( + "Failed writing class with hash {class_hash:?} to class manager. Trying \ + again. Error: {err:?}" + ); + trace!("Class: {class:?}"); + // TODO(shahak): Consider sleeping here. + } + } + + for (class_hash, deprecated_class) in self.1 { + // TODO(shahak): Test this flow. + // TODO(shahak): Try to avoid cloning. See if ClientError can contain the request. + while let Err(err) = class_manager_client + .add_deprecated_class(class_hash, deprecated_class.clone()) + .await + { + warn!( + "Failed writing deprecated class with hash {class_hash:?} to class \ + manager. Trying again. Error: {err:?}" + ); + trace!("Class: {deprecated_class:?}"); + // TODO(shahak): Consider sleeping here. + } + } + + storage_writer + .begin_rw_txn()? + .update_class_manager_block_marker(&self.2.unchecked_next())? + .commit()?; + SYNC_CLASS_MANAGER_MARKER.set_lossy(self.2.unchecked_next().0); + + Ok(()) + } + .boxed() } } pub(crate) struct ClassStreamBuilder; -impl DataStreamBuilder<(ApiContractClass, ClassHash)> for ClassStreamBuilder { +impl BlockDataStreamBuilder<(ApiContractClass, ClassHash)> for ClassStreamBuilder { type Output = (DeclaredClasses, DeprecatedDeclaredClasses, BlockNumber); const TYPE_DESCRIPTION: &'static str = "classes"; @@ -76,12 +111,11 @@ impl DataStreamBuilder<(ApiContractClass, ClassHash)> for ClassStreamBuilder { ) = (0, DeclaredClasses::new(), DeprecatedDeclaredClasses::new()); while current_class_len < target_class_len { - let maybe_contract_class = - tokio::time::timeout(NETWORK_DATA_TIMEOUT, classes_response_manager.next()) - .await? - .ok_or(P2PSyncClientError::ReceiverChannelTerminated { - type_description: Self::TYPE_DESCRIPTION, - })?; + let maybe_contract_class = classes_response_manager.next().await.ok_or( + ParseDataError::BadPeer(BadPeerError::SessionEndedWithoutFin { + type_description: Self::TYPE_DESCRIPTION, + }), + )?; let Some((api_contract_class, class_hash)) = maybe_contract_class?.0 else { if current_class_len == 0 { return Ok(None); @@ -127,6 +161,15 @@ impl DataStreamBuilder<(ApiContractClass, ClassHash)> for ClassStreamBuilder { } fn get_start_block_number(storage_reader: &StorageReader) -> Result { - storage_reader.begin_ro_txn()?.get_class_marker() + storage_reader.begin_ro_txn()?.get_class_manager_block_marker() + } + + // Returning empty set because we assume that internal block's classes are already added to the + // class manager by the caller. + fn convert_sync_block_to_block_data( + block_number: BlockNumber, + _sync_block: SyncBlock, + ) -> (DeclaredClasses, DeprecatedDeclaredClasses, BlockNumber) { + (DeclaredClasses::new(), DeprecatedDeclaredClasses::new(), block_number) } } diff --git a/crates/papyrus_p2p_sync/src/client/class_test.rs b/crates/papyrus_p2p_sync/src/client/class_test.rs index 8916dd5d3d4..49f729a87fc 100644 --- a/crates/papyrus_p2p_sync/src/client/class_test.rs +++ b/crates/papyrus_p2p_sync/src/client/class_test.rs @@ -1,10 +1,10 @@ -use std::cmp::min; +use std::collections::HashMap; -use futures::{FutureExt, StreamExt}; +use futures::FutureExt; +use mockall::predicate::eq; use papyrus_common::pending_classes::ApiContractClass; use papyrus_protobuf::sync::{ BlockHashOrNumber, - ClassQuery, DataOrFin, DeclaredClass, DeprecatedDeclaredClass, @@ -12,145 +12,187 @@ use papyrus_protobuf::sync::{ Query, StateDiffChunk, }; -use papyrus_storage::class::ClassStorageReader; +use papyrus_storage::class_manager::ClassManagerStorageReader; use papyrus_test_utils::{get_rng, GetTestInstance}; use rand::{Rng, RngCore}; use rand_chacha::ChaCha8Rng; use starknet_api::block::BlockNumber; -use starknet_api::core::{ClassHash, CompiledClassHash}; -use starknet_api::deprecated_contract_class::ContractClass as DeprecatedContractClass; +use starknet_api::core::{ClassHash, CompiledClassHash, EntryPointSelector}; +use starknet_api::deprecated_contract_class::{ + ContractClass as DeprecatedContractClass, + EntryPointOffset, + EntryPointV0, +}; use starknet_api::state::SierraContractClass; +use starknet_class_manager_types::{ClassHashes, MockClassManagerClient}; use super::test_utils::{ - setup, + random_header, + run_test, wait_for_marker, - MarkerKind, - TestArgs, - CLASS_DIFF_QUERY_LENGTH, - HEADER_QUERY_LENGTH, + Action, + DataType, SLEEP_DURATION_TO_LET_SYNC_ADVANCE, TIMEOUT_FOR_TEST, }; -use crate::client::state_diff_test::run_state_diff_sync; #[tokio::test] async fn class_basic_flow() { - let TestArgs { - p2p_sync, - storage_reader, - mut mock_state_diff_response_manager, - mut mock_header_response_manager, - mut mock_class_response_manager, - // The test will fail if we drop this - mock_transaction_response_manager: _mock_transaction_responses_manager, - .. - } = setup(); - let mut rng = get_rng(); - // TODO(noamsp): Add multiple state diffs per header - let (class_state_diffs, api_contract_classes): (Vec<_>, Vec<_>) = (0..HEADER_QUERY_LENGTH) - .map(|_| create_random_state_diff_chunk_with_class(&mut rng)) - .unzip(); - let header_state_diff_lengths = - class_state_diffs.iter().map(|class_state_diff| class_state_diff.len()).collect::>(); - - // Create a future that will receive queries, send responses and validate the results - let parse_queries_future = async move { - // Check that before we send state diffs there is no class query. - assert!(mock_class_response_manager.next().now_or_never().is_none()); - - run_state_diff_sync( - p2p_sync.config, - &mut mock_header_response_manager, - &mut mock_state_diff_response_manager, - header_state_diff_lengths.clone(), - class_state_diffs.clone().into_iter().map(Some).collect(), - ) - .await; - - let num_declare_class_state_diff_headers = - u64::try_from(header_state_diff_lengths.len()).unwrap(); - let num_class_queries = - num_declare_class_state_diff_headers.div_ceil(CLASS_DIFF_QUERY_LENGTH); - for i in 0..num_class_queries { - let start_block_number = i * CLASS_DIFF_QUERY_LENGTH; - let limit = min( - num_declare_class_state_diff_headers - start_block_number, - CLASS_DIFF_QUERY_LENGTH, - ); - - // Get a class query and validate it - let mut mock_class_responses_manager = - mock_class_response_manager.next().await.unwrap(); - assert_eq!( - *mock_class_responses_manager.query(), - Ok(ClassQuery(Query { - start_block: BlockHashOrNumber::Number(BlockNumber(start_block_number)), - direction: Direction::Forward, - limit, - step: 1, - })), - "If the limit of the query is too low, try to increase \ - SLEEP_DURATION_TO_LET_SYNC_ADVANCE", - ); - for block_number in start_block_number..(start_block_number + limit) { - let class_hash = - class_state_diffs[usize::try_from(block_number).unwrap()].get_class_hash(); - let expected_class = - api_contract_classes[usize::try_from(block_number).unwrap()].clone(); + let mut class_manager_client = MockClassManagerClient::new(); + + let state_diffs_and_classes_of_blocks = [ + vec![ + create_random_state_diff_chunk_with_class(&mut rng), + create_random_state_diff_chunk_with_class(&mut rng), + ], + vec![ + create_random_state_diff_chunk_with_class(&mut rng), + create_random_state_diff_chunk_with_class(&mut rng), + create_random_state_diff_chunk_with_class(&mut rng), + ], + ]; - let block_number = BlockNumber(block_number); + // Fill class manager client with expectations. + for state_diffs_and_classes in &state_diffs_and_classes_of_blocks { + for (state_diff, class) in state_diffs_and_classes { + let class_hash = state_diff.get_class_hash(); + match class { + ApiContractClass::ContractClass(class) => { + let executable_class_hash = state_diff.get_compiled_class_hash(); + class_manager_client + .expect_add_class() + .times(1) + .with(eq(class.clone())) + .return_once(move |_| { + Ok(ClassHashes { class_hash, executable_class_hash }) + }); + } + ApiContractClass::DeprecatedContractClass(class) => { + class_manager_client + .expect_add_deprecated_class() + .times(1) + .with(eq(class_hash), eq(class.clone())) + .return_once(|_, _| Ok(())); + } + } + } + } + + let mut actions = vec![ + Action::RunP2pSync, + // We already validate the header query content in other tests. + Action::ReceiveQuery(Box::new(|_query| ()), DataType::Header), + ]; + + // Send headers with corresponding state diff length. + for (i, state_diffs_and_classes) in state_diffs_and_classes_of_blocks.iter().enumerate() { + actions.push(Action::SendHeader(DataOrFin(Some(random_header( + &mut rng, + BlockNumber(i.try_into().unwrap()), + Some(state_diffs_and_classes.len()), + None, + ))))); + } + actions.push(Action::SendHeader(DataOrFin(None))); + + // Send state diffs. + actions.push( + // We already validate the state diff query content in other tests. + Action::ReceiveQuery(Box::new(|_query| ()), DataType::StateDiff), + ); + + // Sleep so class sync will reach the sleep waiting for state diff protocol to receive new data. + actions.push(Action::SleepToLetSyncAdvance); + for state_diffs_and_classes in &state_diffs_and_classes_of_blocks { + for (state_diff, _) in state_diffs_and_classes { + actions.push(Action::SendStateDiff(DataOrFin(Some(state_diff.clone())))); + } + } - // Check that before we've sent all parts the contract class wasn't written yet - let txn = storage_reader.begin_ro_txn().unwrap(); - assert_eq!(block_number, txn.get_class_marker().unwrap()); + let len = state_diffs_and_classes_of_blocks.len(); + // Wait for state diff sync to finish before continuing class sync. + actions.push(Action::CheckStorage(Box::new(move |reader| { + async move { + let block_number = BlockNumber(len.try_into().unwrap()); + wait_for_marker( + DataType::StateDiff, + &reader, + block_number, + SLEEP_DURATION_TO_LET_SYNC_ADVANCE, + TIMEOUT_FOR_TEST, + ) + .await; + } + .boxed() + }))); + actions.push(Action::SimulateWaitPeriodForOtherProtocol); - mock_class_responses_manager - .send_response(DataOrFin(Some((expected_class.clone(), class_hash)))) - .await - .unwrap(); + actions.push(Action::ReceiveQuery( + Box::new(move |query| { + assert_eq!( + query, + Query { + start_block: BlockHashOrNumber::Number(BlockNumber(0)), + direction: Direction::Forward, + limit: len.try_into().unwrap(), + step: 1, + } + ) + }), + DataType::Class, + )); + for (i, state_diffs_and_classes) in state_diffs_and_classes_of_blocks.into_iter().enumerate() { + for (state_diff, class) in &state_diffs_and_classes { + let class_hash = state_diff.get_class_hash(); + // Check that before the last class was sent, the classes aren't written. + actions.push(Action::CheckStorage(Box::new(move |reader| { + async move { + assert_eq!( + u64::try_from(i).unwrap(), + reader.begin_ro_txn().unwrap().get_class_manager_block_marker().unwrap().0 + ); + } + .boxed() + }))); + actions.push(Action::SendClass(DataOrFin(Some((class.clone(), class_hash))))); + } + // Check that a block's classes are written before the entire query finished. + actions.push(Action::CheckStorage(Box::new(move |reader| { + async move { + let block_number = BlockNumber(i.try_into().unwrap()); wait_for_marker( - MarkerKind::Class, - &storage_reader, + DataType::Class, + &reader, block_number.unchecked_next(), SLEEP_DURATION_TO_LET_SYNC_ADVANCE, TIMEOUT_FOR_TEST, ) .await; - - let txn = storage_reader.begin_ro_txn().unwrap(); - let actual_class = match expected_class { - ApiContractClass::ContractClass(_) => ApiContractClass::ContractClass( - txn.get_class(&class_hash).unwrap().unwrap(), - ), - ApiContractClass::DeprecatedContractClass(_) => { - ApiContractClass::DeprecatedContractClass( - txn.get_deprecated_class(&class_hash).unwrap().unwrap(), - ) - } - }; - assert_eq!(expected_class, actual_class); } - - mock_class_responses_manager.send_response(DataOrFin(None)).await.unwrap(); - } - }; - - tokio::select! { - sync_result = p2p_sync.run() => { - sync_result.unwrap(); - panic!("P2P sync aborted with no failure."); - } - _ = parse_queries_future => {} + .boxed() + }))); } + + run_test( + HashMap::from([ + (DataType::Header, len.try_into().unwrap()), + (DataType::StateDiff, len.try_into().unwrap()), + (DataType::Class, len.try_into().unwrap()), + ]), + Some(class_manager_client), + actions, + ) + .await; } // We define this new trait here so we can use the get_class_hash function in the test. // we need to define this trait because StateDiffChunk is defined in an other crate. trait GetClassHash { fn get_class_hash(&self) -> ClassHash; + fn get_compiled_class_hash(&self) -> CompiledClassHash; } impl GetClassHash for StateDiffChunk { @@ -163,6 +205,13 @@ impl GetClassHash for StateDiffChunk { _ => unreachable!(), } } + + fn get_compiled_class_hash(&self) -> CompiledClassHash { + match self { + StateDiffChunk::DeclaredClass(declared_class) => declared_class.compiled_class_hash, + _ => unreachable!(), + } + } } fn create_random_state_diff_chunk_with_class( @@ -174,17 +223,152 @@ fn create_random_state_diff_chunk_with_class( class_hash, compiled_class_hash: CompiledClassHash(rng.next_u64().into()), }; + + // SierraContractClass::get_test_instance(rng) currently returns the same value every time, + // so we change the program to be random. + let mut sierra_contract_class = SierraContractClass::get_test_instance(rng); + + sierra_contract_class.sierra_program = vec![rng.next_u64().into()]; ( StateDiffChunk::DeclaredClass(declared_class), - ApiContractClass::ContractClass(SierraContractClass::get_test_instance(rng)), + ApiContractClass::ContractClass(sierra_contract_class), ) } else { let deprecated_declared_class = DeprecatedDeclaredClass { class_hash }; + + // DeprecatedContractClass::get_test_instance(rng) currently returns the same value every + // time, so we change the entry points to be random. + let mut deprecated_contract_class = DeprecatedContractClass::get_test_instance(rng); + deprecated_contract_class.entry_points_by_type.insert( + Default::default(), + vec![EntryPointV0 { + selector: EntryPointSelector::default(), + offset: EntryPointOffset(rng.next_u64().try_into().unwrap()), + }], + ); + ( StateDiffChunk::DeprecatedDeclaredClass(deprecated_declared_class), - ApiContractClass::DeprecatedContractClass(DeprecatedContractClass::get_test_instance( - rng, - )), + ApiContractClass::DeprecatedContractClass(deprecated_contract_class), ) } } + +// TODO(noamsp): Consider verifying that ParseDataError::BadPeerError(NotEnoughClasses) +// was returned from parse_data_for_block. We currently dont have a way to check this. +#[tokio::test] +async fn not_enough_classes() { + let mut rng = get_rng(); + let (state_diff_chunk, class) = create_random_state_diff_chunk_with_class(&mut rng); + + validate_class_sync_fails( + vec![2], + vec![ + Some(state_diff_chunk.clone()), + Some(create_random_state_diff_chunk_with_class(&mut rng).0), + ], + vec![Some((class, state_diff_chunk.get_class_hash())), None], + ) + .await; +} + +// TODO(noamsp): Consider verifying that ParseDataError::BadPeerError(ClassNotInStateDiff) +// was returned from parse_data_for_block. We currently dont have a way to check this. +#[tokio::test] +async fn class_not_in_state_diff() { + let mut rng = get_rng(); + let (state_diff_chunk, class) = create_random_state_diff_chunk_with_class(&mut rng); + + validate_class_sync_fails( + vec![1], + vec![Some(create_random_state_diff_chunk_with_class(&mut rng).0)], + vec![Some((class, state_diff_chunk.get_class_hash()))], + ) + .await; +} + +// TODO(noamsp): Consider verifying that ParseDataError::BadPeerError(DuplicateClass) +// was returned from parse_data_for_block. We currently dont have a way to check this. +#[tokio::test] +async fn duplicate_classes() { + let mut rng = get_rng(); + let (state_diff_chunk, class) = create_random_state_diff_chunk_with_class(&mut rng); + + // We provide a state diff with 3 classes to verify that we return the error once we encounter + // duplicate classes and not wait for the whole state diff classes to be sent. + validate_class_sync_fails( + vec![3], + vec![ + Some(state_diff_chunk.clone()), + Some(create_random_state_diff_chunk_with_class(&mut rng).0), + Some(create_random_state_diff_chunk_with_class(&mut rng).0), + ], + vec![ + Some((class.clone(), state_diff_chunk.get_class_hash())), + Some((class, state_diff_chunk.get_class_hash())), + ], + ) + .await; +} + +async fn validate_class_sync_fails( + header_state_diff_lengths: Vec, + state_diff_chunks: Vec>, + classes: Vec>, +) { + let mut rng = get_rng(); + + // TODO(noamsp): remove code duplication with state diff test. + let mut actions = vec![ + Action::RunP2pSync, + // We already validate the header query content in other tests. + Action::ReceiveQuery(Box::new(|_query| ()), DataType::Header), + ]; + + // Send headers with corresponding state diff length + for (i, state_diff_length) in header_state_diff_lengths.iter().copied().enumerate() { + actions.push(Action::SendHeader(DataOrFin(Some(random_header( + &mut rng, + BlockNumber(i.try_into().unwrap()), + Some(state_diff_length), + None, + ))))); + } + actions.push(Action::SendHeader(DataOrFin(None))); + + actions.push( + // We already validate the state diff query content in other tests. + Action::ReceiveQuery(Box::new(|_query| ()), DataType::StateDiff), + ); + + // Send state diff chunks. + for state_diff_chunk in state_diff_chunks { + actions.push(Action::SendStateDiff(DataOrFin(state_diff_chunk))); + } + + actions.push(Action::SendStateDiff(DataOrFin(None))); + + actions.push( + // We already validate the class query content in other tests. + Action::ReceiveQuery(Box::new(|_query| ()), DataType::Class), + ); + + // Send classes. + for class in classes { + actions.push(Action::SendClass(DataOrFin(class))); + } + + // We validate the report is sent before we send fin. + actions.push(Action::ValidateReportSent(DataType::Class)); + + run_test( + HashMap::from([ + (DataType::Header, header_state_diff_lengths.len().try_into().unwrap()), + (DataType::StateDiff, header_state_diff_lengths.len().try_into().unwrap()), + (DataType::Class, header_state_diff_lengths.len().try_into().unwrap()), + ]), + None, + actions, + ) + .await; +} diff --git a/crates/papyrus_p2p_sync/src/client/header.rs b/crates/papyrus_p2p_sync/src/client/header.rs index 947f8ede25e..fb491fbc6e4 100644 --- a/crates/papyrus_p2p_sync/src/client/header.rs +++ b/crates/papyrus_p2p_sync/src/client/header.rs @@ -1,69 +1,77 @@ use chrono::{TimeZone, Utc}; use futures::future::BoxFuture; use futures::{FutureExt, StreamExt}; -use metrics::gauge; -use papyrus_common::metrics as papyrus_metrics; use papyrus_network::network_manager::ClientResponsesManager; use papyrus_protobuf::sync::{DataOrFin, SignedBlockHeader}; use papyrus_storage::header::{HeaderStorageReader, HeaderStorageWriter}; use papyrus_storage::{StorageError, StorageReader, StorageWriter}; -use starknet_api::block::BlockNumber; +use papyrus_sync::metrics::{SYNC_HEADER_LATENCY_SEC, SYNC_HEADER_MARKER}; +use starknet_api::block::{BlockHash, BlockHeader, BlockNumber, BlockSignature}; +use starknet_api::hash::StarkHash; +use starknet_class_manager_types::SharedClassManagerClient; +use starknet_state_sync_types::state_sync_types::SyncBlock; use tracing::debug; -use super::stream_builder::{ +use super::block_data_stream_builder::{ BadPeerError, BlockData, + BlockDataStreamBuilder, BlockNumberLimit, - DataStreamBuilder, ParseDataError, }; -use super::{P2PSyncClientError, ALLOWED_SIGNATURES_LENGTH, NETWORK_DATA_TIMEOUT}; +use super::{P2pSyncClientError, ALLOWED_SIGNATURES_LENGTH}; impl BlockData for SignedBlockHeader { #[allow(clippy::as_conversions)] // FIXME: use int metrics so `as f64` may be removed. - fn write_to_storage( + fn write_to_storage<'a>( self: Box, - storage_writer: &mut StorageWriter, - ) -> Result<(), StorageError> { - storage_writer - .begin_rw_txn()? - .append_header( - self.block_header.block_header_without_hash.block_number, - &self.block_header, - )? - .append_block_signature( - self.block_header.block_header_without_hash.block_number, - self + storage_writer: &'a mut StorageWriter, + _class_manager_client: &'a mut SharedClassManagerClient, + ) -> BoxFuture<'a, Result<(), P2pSyncClientError>> { + async move { + storage_writer + .begin_rw_txn()? + .append_header( + self.block_header.block_header_without_hash.block_number, + &self.block_header, + )? + .append_block_signature( + self.block_header.block_header_without_hash.block_number, + self .signatures // In the future we will support multiple signatures. .first() // The verification that the size of the vector is 1 is done in the data // verification. .expect("Vec::first should return a value on a vector of size 1"), - )? - .commit()?; - gauge!( - papyrus_metrics::PAPYRUS_HEADER_MARKER, - self.block_header.block_header_without_hash.block_number.unchecked_next().0 as f64 - ); - // TODO(shahak): Fix code dup with central sync - let time_delta = Utc::now() - - Utc - .timestamp_opt(self.block_header.block_header_without_hash.timestamp.0 as i64, 0) - .single() - .expect("block timestamp should be valid"); - let header_latency = time_delta.num_seconds(); - debug!("Header latency: {}.", header_latency); - if header_latency >= 0 { - gauge!(papyrus_metrics::PAPYRUS_HEADER_LATENCY_SEC, header_latency as f64); + )? + .commit()?; + SYNC_HEADER_MARKER.set_lossy( + self.block_header.block_header_without_hash.block_number.unchecked_next().0, + ); + // TODO(shahak): Fix code dup with central sync + let time_delta = Utc::now() + - Utc + .timestamp_opt( + self.block_header.block_header_without_hash.timestamp.0 as i64, + 0, + ) + .single() + .expect("block timestamp should be valid"); + let header_latency = time_delta.num_seconds(); + debug!("Header latency: {}.", header_latency); + if header_latency >= 0 { + SYNC_HEADER_LATENCY_SEC.set_lossy(header_latency); + } + Ok(()) } - Ok(()) + .boxed() } } pub(crate) struct HeaderStreamBuilder; -impl DataStreamBuilder for HeaderStreamBuilder { +impl BlockDataStreamBuilder for HeaderStreamBuilder { type Output = SignedBlockHeader; const TYPE_DESCRIPTION: &'static str = "headers"; @@ -77,12 +85,11 @@ impl DataStreamBuilder for HeaderStreamBuilder { _storage_reader: &'a StorageReader, ) -> BoxFuture<'a, Result, ParseDataError>> { async move { - let maybe_signed_header = - tokio::time::timeout(NETWORK_DATA_TIMEOUT, signed_headers_response_manager.next()) - .await? - .ok_or(P2PSyncClientError::ReceiverChannelTerminated { - type_description: Self::TYPE_DESCRIPTION, - })?; + let maybe_signed_header = signed_headers_response_manager.next().await.ok_or( + ParseDataError::BadPeer(BadPeerError::SessionEndedWithoutFin { + type_description: Self::TYPE_DESCRIPTION, + }), + )?; let Some(signed_block_header) = maybe_signed_header?.0 else { return Ok(None); }; @@ -112,4 +119,21 @@ impl DataStreamBuilder for HeaderStreamBuilder { fn get_start_block_number(storage_reader: &StorageReader) -> Result { storage_reader.begin_ro_txn()?.get_header_marker() } + + // TODO(Eitan): Use real header once SyncBlock contains data required by full nodes + fn convert_sync_block_to_block_data( + block_number: BlockNumber, + sync_block: SyncBlock, + ) -> SignedBlockHeader { + SignedBlockHeader { + block_header: BlockHeader { + block_hash: BlockHash(StarkHash::from(block_number.0)), + block_header_without_hash: sync_block.block_header_without_hash, + state_diff_length: Some(sync_block.state_diff.len()), + n_transactions: sync_block.transaction_hashes.len(), + ..Default::default() + }, + signatures: vec![BlockSignature::default()], + } + } } diff --git a/crates/papyrus_p2p_sync/src/client/header_test.rs b/crates/papyrus_p2p_sync/src/client/header_test.rs index 7a4b6961ce7..a2efe8b5496 100644 --- a/crates/papyrus_p2p_sync/src/client/header_test.rs +++ b/crates/papyrus_p2p_sync/src/client/header_test.rs @@ -1,4 +1,6 @@ -use futures::StreamExt; +use std::collections::HashMap; + +use futures::{FutureExt, StreamExt}; use papyrus_protobuf::sync::{ BlockHashOrNumber, DataOrFin, @@ -8,14 +10,18 @@ use papyrus_protobuf::sync::{ SignedBlockHeader, }; use papyrus_storage::header::HeaderStorageReader; +use papyrus_test_utils::get_rng; use starknet_api::block::{BlockHeader, BlockHeaderWithoutHash, BlockNumber}; use tokio::time::timeout; use super::test_utils::{ create_block_hashes_and_signatures, + random_header, + run_test, setup, wait_for_marker, - MarkerKind, + Action, + DataType, TestArgs, HEADER_QUERY_LENGTH, SLEEP_DURATION_TO_LET_SYNC_ADVANCE, @@ -88,7 +94,7 @@ async fn signed_headers_basic_flow() { // sent. let block_number = BlockNumber(i.try_into().unwrap()); wait_for_marker( - MarkerKind::Header, + DataType::Header, &storage_reader, block_number.unchecked_next(), SLEEP_DURATION_TO_LET_SYNC_ADVANCE, @@ -111,7 +117,7 @@ async fn signed_headers_basic_flow() { tokio::select! { sync_result = p2p_sync.run() => { sync_result.unwrap(); - panic!("P2P sync aborted with no failure."); + unreachable!("Return type Never should never be constructed."); } _ = parse_queries_future => {} } @@ -186,10 +192,37 @@ async fn sync_sends_new_header_query_if_it_got_partial_responses() { tokio::select! { sync_result = p2p_sync.run() => { sync_result.unwrap(); - panic!("P2P sync aborted with no failure."); + unreachable!("Return type Never should never be constructed."); } _ = parse_queries_future => {} } } -// TODO(shahak): Add negative tests. +#[tokio::test] +async fn wrong_block_number() { + run_test( + HashMap::from([(DataType::Header, 1)]), + None, + vec![ + Action::RunP2pSync, + // We already validate the query content in other tests. + Action::ReceiveQuery(Box::new(|_query| ()), DataType::Header), + Action::SendHeader(DataOrFin(Some(random_header( + &mut get_rng(), + BlockNumber(1), + None, + None, + )))), + Action::ValidateReportSent(DataType::Header), + Action::CheckStorage(Box::new(|reader| { + async move { + assert_eq!(0, reader.begin_ro_txn().unwrap().get_header_marker().unwrap().0); + } + .boxed() + })), + ], + ) + .await; +} + +// TODO(shahak): Add more negative tests. diff --git a/crates/papyrus_p2p_sync/src/client/mod.rs b/crates/papyrus_p2p_sync/src/client/mod.rs index 9248d85f02f..3842f49bf07 100644 --- a/crates/papyrus_p2p_sync/src/client/mod.rs +++ b/crates/papyrus_p2p_sync/src/client/mod.rs @@ -1,3 +1,4 @@ +mod block_data_stream_builder; mod class; #[cfg(test)] mod class_test; @@ -7,7 +8,8 @@ mod header_test; mod state_diff; #[cfg(test)] mod state_diff_test; -mod stream_builder; +#[cfg(test)] +mod test; #[cfg(test)] mod test_utils; mod transaction; @@ -17,13 +19,16 @@ mod transaction_test; use std::collections::BTreeMap; use std::time::Duration; +use block_data_stream_builder::{BlockDataResult, BlockDataStreamBuilder}; use class::ClassStreamBuilder; -use futures::channel::mpsc::SendError; -use futures::Stream; +use futures::channel::mpsc::{Receiver, SendError, Sender}; +use futures::never::Never; +use futures::stream::BoxStream; +use futures::{SinkExt as _, Stream}; use header::HeaderStreamBuilder; use papyrus_common::pending_classes::ApiContractClass; -use papyrus_config::converters::deserialize_seconds_to_duration; -use papyrus_config::dumping::{ser_optional_param, ser_param, SerializeConfig}; +use papyrus_config::converters::deserialize_milliseconds_to_duration; +use papyrus_config::dumping::{ser_param, SerializeConfig}; use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; use papyrus_network::network_manager::SqmrClientSender; use papyrus_protobuf::sync::{ @@ -40,31 +45,33 @@ use serde::{Deserialize, Serialize}; use starknet_api::block::BlockNumber; use starknet_api::core::ClassHash; use starknet_api::transaction::FullTransaction; +use starknet_class_manager_types::SharedClassManagerClient; +use starknet_state_sync_types::state_sync_types::SyncBlock; use state_diff::StateDiffStreamBuilder; -use stream_builder::{DataStreamBuilder, DataStreamResult}; use tokio_stream::StreamExt; -use tracing::instrument; +use tracing::{info, instrument}; use transaction::TransactionStreamFactory; +use validator::Validate; + const STEP: u64 = 1; const ALLOWED_SIGNATURES_LENGTH: usize = 1; -const NETWORK_DATA_TIMEOUT: Duration = Duration::from_secs(300); - -#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq)] -pub struct P2PSyncClientConfig { +#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Validate)] +pub struct P2pSyncClientConfig { pub num_headers_per_query: u64, pub num_block_state_diffs_per_query: u64, pub num_block_transactions_per_query: u64, pub num_block_classes_per_query: u64, - #[serde(deserialize_with = "deserialize_seconds_to_duration")] + #[serde(deserialize_with = "deserialize_milliseconds_to_duration")] pub wait_period_for_new_data: Duration, + #[serde(deserialize_with = "deserialize_milliseconds_to_duration")] + pub wait_period_for_other_protocol: Duration, pub buffer_size: usize, - pub stop_sync_at_block_number: Option, } -impl SerializeConfig for P2PSyncClientConfig { +impl SerializeConfig for P2pSyncClientConfig { fn dump(&self) -> BTreeMap { - let mut config = BTreeMap::from_iter([ + BTreeMap::from_iter([ ser_param( "num_headers_per_query", &self.num_headers_per_query, @@ -92,9 +99,16 @@ impl SerializeConfig for P2PSyncClientConfig { ), ser_param( "wait_period_for_new_data", - &self.wait_period_for_new_data.as_secs(), - "Time in seconds to wait when a query returned with partial data before sending a \ - new query", + &self.wait_period_for_new_data.as_millis(), + "Time in millisseconds to wait when a query returned with partial data before \ + sending a new query", + ParamPrivacyInput::Public, + ), + ser_param( + "wait_period_for_other_protocol", + &self.wait_period_for_other_protocol.as_millis(), + "Time in millisseconds to wait for a dependency protocol to advance (e.g.state \ + diff sync depends on header sync)", ParamPrivacyInput::Public, ), ser_param( @@ -103,38 +117,29 @@ impl SerializeConfig for P2PSyncClientConfig { "Size of the buffer for read from the storage and for incoming responses.", ParamPrivacyInput::Public, ), - ]); - config.extend(ser_optional_param( - &self.stop_sync_at_block_number, - BlockNumber(1000), - "stop_sync_at_block_number", - "Stops the sync at given block number and closes the node cleanly. Used to run \ - profiling on the node.", - ParamPrivacyInput::Public, - )); - config + ]) } } -impl Default for P2PSyncClientConfig { +impl Default for P2pSyncClientConfig { fn default() -> Self { - P2PSyncClientConfig { + P2pSyncClientConfig { num_headers_per_query: 10000, // State diffs are split into multiple messages, so big queries can lead to a lot of // messages in the network buffers. num_block_state_diffs_per_query: 100, num_block_transactions_per_query: 100, num_block_classes_per_query: 100, - wait_period_for_new_data: Duration::from_secs(5), + wait_period_for_new_data: Duration::from_millis(50), + wait_period_for_other_protocol: Duration::from_millis(50), // TODO(eitan): split this by protocol buffer_size: 100000, - stop_sync_at_block_number: None, } } } #[derive(thiserror::Error, Debug)] -pub enum P2PSyncClientError { +pub enum P2pSyncClientError { // TODO(shahak): Remove this and report to network on invalid data once that's possible. #[error("Network returned more responses than expected for a query.")] TooManyResponses, @@ -144,10 +149,6 @@ pub enum P2PSyncClientError { field." )] OldHeaderInStorage { block_number: BlockNumber, missing_field: &'static str }, - #[error("The sender end of the response receivers for {type_description:?} was closed.")] - ReceiverChannelTerminated { type_description: &'static str }, - #[error(transparent)] - NetworkTimeout(#[from] tokio::time::error::Elapsed), #[error(transparent)] StorageError(#[from] StorageError), #[error(transparent)] @@ -159,15 +160,14 @@ type StateSqmrDiffSender = SqmrClientSender>; type ClassSqmrSender = SqmrClientSender>; -pub struct P2PSyncClientChannels { +pub struct P2pSyncClientChannels { header_sender: HeaderSqmrSender, state_diff_sender: StateSqmrDiffSender, transaction_sender: TransactionSqmrSender, - #[allow(dead_code)] class_sender: ClassSqmrSender, } -impl P2PSyncClientChannels { +impl P2pSyncClientChannels { pub fn new( header_sender: HeaderSqmrSender, state_diff_sender: StateSqmrDiffSender, @@ -179,69 +179,169 @@ impl P2PSyncClientChannels { pub(crate) fn create_stream( self, storage_reader: StorageReader, - config: P2PSyncClientConfig, - ) -> impl Stream + Send + 'static { + config: P2pSyncClientConfig, + internal_blocks_receivers: InternalBlocksReceivers, + ) -> impl Stream + Send + 'static { let header_stream = HeaderStreamBuilder::create_stream( self.header_sender, storage_reader.clone(), + Some(internal_blocks_receivers.header_receiver), config.wait_period_for_new_data, + config.wait_period_for_other_protocol, config.num_headers_per_query, - config.stop_sync_at_block_number, ); let state_diff_stream = StateDiffStreamBuilder::create_stream( self.state_diff_sender, storage_reader.clone(), + Some(internal_blocks_receivers.state_diff_receiver), config.wait_period_for_new_data, + config.wait_period_for_other_protocol, config.num_block_state_diffs_per_query, - config.stop_sync_at_block_number, ); let transaction_stream = TransactionStreamFactory::create_stream( self.transaction_sender, storage_reader.clone(), + Some(internal_blocks_receivers.transaction_receiver), config.wait_period_for_new_data, + config.wait_period_for_other_protocol, config.num_block_transactions_per_query, - config.stop_sync_at_block_number, ); let class_stream = ClassStreamBuilder::create_stream( self.class_sender, storage_reader.clone(), + Some(internal_blocks_receivers.class_receiver), config.wait_period_for_new_data, + config.wait_period_for_other_protocol, config.num_block_classes_per_query, - config.stop_sync_at_block_number, ); header_stream.merge(state_diff_stream).merge(transaction_stream).merge(class_stream) } } -pub struct P2PSyncClient { - config: P2PSyncClientConfig, +pub struct P2pSyncClient { + config: P2pSyncClientConfig, storage_reader: StorageReader, storage_writer: StorageWriter, - p2p_sync_channels: P2PSyncClientChannels, + p2p_sync_channels: P2pSyncClientChannels, + internal_blocks_receiver: BoxStream<'static, SyncBlock>, + class_manager_client: SharedClassManagerClient, } -impl P2PSyncClient { +impl P2pSyncClient { pub fn new( - config: P2PSyncClientConfig, + config: P2pSyncClientConfig, storage_reader: StorageReader, storage_writer: StorageWriter, - p2p_sync_channels: P2PSyncClientChannels, + p2p_sync_channels: P2pSyncClientChannels, + internal_blocks_receiver: BoxStream<'static, SyncBlock>, + class_manager_client: SharedClassManagerClient, ) -> Self { - Self { config, storage_reader, storage_writer, p2p_sync_channels } + Self { + config, + storage_reader, + storage_writer, + p2p_sync_channels, + internal_blocks_receiver, + class_manager_client, + } } #[instrument(skip(self), level = "debug", err)] - pub async fn run(mut self) -> Result<(), P2PSyncClientError> { + pub async fn run(self) -> Result { + info!("Starting p2p sync client"); + + let InternalBlocksChannels { + receivers: internal_blocks_receivers, + senders: mut internal_blocks_senders, + } = InternalBlocksChannels::new(); + let P2pSyncClient { + config, + storage_reader, + mut storage_writer, + p2p_sync_channels, + mut internal_blocks_receiver, + mut class_manager_client, + } = self; let mut data_stream = - self.p2p_sync_channels.create_stream(self.storage_reader.clone(), self.config); + p2p_sync_channels.create_stream(storage_reader, config, internal_blocks_receivers); loop { - let data = data_stream.next().await.expect("Sync data stream should never end")?; - data.write_to_storage(&mut self.storage_writer)?; + tokio::select! { + maybe_internal_block = internal_blocks_receiver.next() => { + let sync_block = maybe_internal_block.expect("Internal blocks stream should never end"); + internal_blocks_senders.send(sync_block).await?; + } + data = data_stream.next() => { + let data = data.expect("Sync data stream should never end")?; + data.write_to_storage(&mut storage_writer, &mut class_manager_client).await?; + } + } + } + } +} + +pub(crate) struct InternalBlocksReceivers { + header_receiver: Receiver, + state_diff_receiver: Receiver, + transaction_receiver: Receiver, + class_receiver: Receiver, +} + +pub struct InternalBlocksSenders { + header_sender: Sender, + state_diff_sender: Sender, + transaction_sender: Sender, + class_sender: Sender, +} + +impl InternalBlocksSenders { + pub async fn send(&mut self, sync_block: SyncBlock) -> Result<(), SendError> { + let header_send = self.header_sender.send(sync_block.clone()); + let state_diff_send = self.state_diff_sender.send(sync_block.clone()); + let transaction_send = self.transaction_sender.send(sync_block.clone()); + let class_send = self.class_sender.send(sync_block); + let res = + futures::future::join4(header_send, state_diff_send, transaction_send, class_send) + .await; + match res { + (Ok(()), Ok(()), Ok(()), Ok(())) => Ok(()), + (Err(e), _, _, _) => Err(e), + (_, Err(e), _, _) => Err(e), + (_, _, Err(e), _) => Err(e), + (_, _, _, Err(e)) => Err(e), + } + } +} + +struct InternalBlocksChannels { + receivers: InternalBlocksReceivers, + senders: InternalBlocksSenders, +} + +impl InternalBlocksChannels { + pub fn new() -> Self { + let (header_sender, header_receiver) = futures::channel::mpsc::channel(100); + let (state_diff_sender, state_diff_receiver) = futures::channel::mpsc::channel(100); + let (transaction_sender, transaction_receiver) = futures::channel::mpsc::channel(100); + let (class_sender, class_receiver) = futures::channel::mpsc::channel(100); + + Self { + receivers: InternalBlocksReceivers { + header_receiver, + state_diff_receiver, + transaction_receiver, + class_receiver, + }, + senders: InternalBlocksSenders { + header_sender, + state_diff_sender, + transaction_sender, + class_sender, + }, } } } diff --git a/crates/papyrus_p2p_sync/src/client/p2p_sync_test.rs b/crates/papyrus_p2p_sync/src/client/p2p_sync_test.rs deleted file mode 100644 index 8b137891791..00000000000 --- a/crates/papyrus_p2p_sync/src/client/p2p_sync_test.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/crates/papyrus_p2p_sync/src/client/state_diff.rs b/crates/papyrus_p2p_sync/src/client/state_diff.rs index 4eeebd36c41..6b7606d8b53 100644 --- a/crates/papyrus_p2p_sync/src/client/state_diff.rs +++ b/crates/papyrus_p2p_sync/src/client/state_diff.rs @@ -2,42 +2,46 @@ use std::collections::HashSet; use futures::future::BoxFuture; use futures::{FutureExt, StreamExt}; -use metrics::gauge; -use papyrus_common::metrics as papyrus_metrics; use papyrus_network::network_manager::ClientResponsesManager; use papyrus_proc_macros::latency_histogram; use papyrus_protobuf::sync::{DataOrFin, StateDiffChunk}; use papyrus_storage::header::HeaderStorageReader; use papyrus_storage::state::{StateStorageReader, StateStorageWriter}; use papyrus_storage::{StorageError, StorageReader, StorageWriter}; +use papyrus_sync::metrics::SYNC_STATE_MARKER; use starknet_api::block::BlockNumber; use starknet_api::state::ThinStateDiff; +use starknet_class_manager_types::SharedClassManagerClient; +use starknet_state_sync_types::state_sync_types::SyncBlock; -use super::stream_builder::BadPeerError; -use crate::client::stream_builder::{ +use super::block_data_stream_builder::BadPeerError; +use crate::client::block_data_stream_builder::{ BlockData, + BlockDataStreamBuilder, BlockNumberLimit, - DataStreamBuilder, ParseDataError, }; -use crate::client::{P2PSyncClientError, NETWORK_DATA_TIMEOUT}; +use crate::client::P2pSyncClientError; impl BlockData for (ThinStateDiff, BlockNumber) { #[latency_histogram("p2p_sync_state_diff_write_to_storage_latency_seconds", true)] - #[allow(clippy::as_conversions)] // FIXME: use int metrics so `as f64` may be removed. - fn write_to_storage( + fn write_to_storage<'a>( self: Box, - storage_writer: &mut StorageWriter, - ) -> Result<(), StorageError> { - storage_writer.begin_rw_txn()?.append_state_diff(self.1, self.0)?.commit()?; - gauge!(papyrus_metrics::PAPYRUS_STATE_MARKER, self.1.unchecked_next().0 as f64); - Ok(()) + storage_writer: &'a mut StorageWriter, + _class_manager_client: &'a mut SharedClassManagerClient, + ) -> BoxFuture<'a, Result<(), P2pSyncClientError>> { + async move { + storage_writer.begin_rw_txn()?.append_state_diff(self.1, self.0)?.commit()?; + SYNC_STATE_MARKER.set_lossy(self.1.unchecked_next().0); + Ok(()) + } + .boxed() } } pub(crate) struct StateDiffStreamBuilder; -impl DataStreamBuilder for StateDiffStreamBuilder { +impl BlockDataStreamBuilder for StateDiffStreamBuilder { type Output = (ThinStateDiff, BlockNumber); const TYPE_DESCRIPTION: &'static str = "state diffs"; @@ -60,20 +64,18 @@ impl DataStreamBuilder for StateDiffStreamBuilder { .get_block_header(block_number)? .expect("A header with number lower than the header marker is missing") .state_diff_length - .ok_or(P2PSyncClientError::OldHeaderInStorage { + .ok_or(P2pSyncClientError::OldHeaderInStorage { block_number, missing_field: "state_diff_length", })?; while current_state_diff_len < target_state_diff_len { - let maybe_state_diff_chunk = tokio::time::timeout( - NETWORK_DATA_TIMEOUT, - state_diff_chunks_response_manager.next(), - ) - .await? - .ok_or(P2PSyncClientError::ReceiverChannelTerminated { - type_description: Self::TYPE_DESCRIPTION, - })?; + let maybe_state_diff_chunk = state_diff_chunks_response_manager + .next() + .await + .ok_or(ParseDataError::BadPeer(BadPeerError::SessionEndedWithoutFin { + type_description: Self::TYPE_DESCRIPTION, + }))?; let Some(state_diff_chunk) = maybe_state_diff_chunk?.0 else { if current_state_diff_len == 0 { return Ok(None); @@ -110,6 +112,13 @@ impl DataStreamBuilder for StateDiffStreamBuilder { fn get_start_block_number(storage_reader: &StorageReader) -> Result { storage_reader.begin_ro_txn()?.get_state_marker() } + + fn convert_sync_block_to_block_data( + block_number: BlockNumber, + sync_block: SyncBlock, + ) -> (ThinStateDiff, BlockNumber) { + (sync_block.state_diff, block_number) + } } // For performance reasons, this function does not check if a deprecated class was declared twice. diff --git a/crates/papyrus_p2p_sync/src/client/state_diff_test.rs b/crates/papyrus_p2p_sync/src/client/state_diff_test.rs index 9e3061c5358..113407a6b5e 100644 --- a/crates/papyrus_p2p_sync/src/client/state_diff_test.rs +++ b/crates/papyrus_p2p_sync/src/client/state_diff_test.rs @@ -1,9 +1,7 @@ -use std::cmp::min; +use std::collections::HashMap; -use futures::future::join; -use futures::{FutureExt, StreamExt}; +use futures::FutureExt; use indexmap::indexmap; -use papyrus_network::network_manager::GenericReceiver; use papyrus_protobuf::sync::{ BlockHashOrNumber, ContractDiff, @@ -12,156 +10,195 @@ use papyrus_protobuf::sync::{ DeprecatedDeclaredClass, Direction, Query, - SignedBlockHeader, StateDiffChunk, }; use papyrus_storage::state::StateStorageReader; -use papyrus_test_utils::{get_rng, GetTestInstance}; -use rand::RngCore; -use rand_chacha::ChaCha8Rng; -use starknet_api::block::{BlockHeader, BlockHeaderWithoutHash, BlockNumber}; -use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; +use papyrus_test_utils::get_rng; +use starknet_api::block::BlockNumber; +use starknet_api::core::{ascii_as_felt, ClassHash, CompiledClassHash, ContractAddress, Nonce}; use starknet_api::state::{StorageKey, ThinStateDiff}; use starknet_types_core::felt::Felt; -use static_assertions::const_assert; -use tokio::sync::mpsc::{channel, Receiver}; use super::test_utils::{ - create_block_hashes_and_signatures, - setup, + random_header, + run_test, wait_for_marker, - HeaderTestPayload, - MarkerKind, - StateDiffTestPayload, - TestArgs, - HEADER_QUERY_LENGTH, + Action, + DataType, SLEEP_DURATION_TO_LET_SYNC_ADVANCE, - STATE_DIFF_QUERY_LENGTH, TIMEOUT_FOR_TEST, - WAIT_PERIOD_FOR_NEW_DATA, }; -use super::{P2PSyncClientConfig, StateDiffQuery}; #[tokio::test] async fn state_diff_basic_flow() { - // Asserting the constants so the test can assume there will be 2 state diff queries for a - // single header query and the second will be smaller than the first. - const_assert!(STATE_DIFF_QUERY_LENGTH < HEADER_QUERY_LENGTH); - const_assert!(HEADER_QUERY_LENGTH < 2 * STATE_DIFF_QUERY_LENGTH); - - let TestArgs { - p2p_sync, - storage_reader, - mut mock_state_diff_response_manager, - mut mock_header_response_manager, - // The test will fail if we drop these - mock_transaction_response_manager: _mock_transaction_responses_manager, - mock_class_response_manager: _mock_class_responses_manager, - .. - } = setup(); - let mut rng = get_rng(); - // TODO(eitan): Add a 3rd constant for NUM_CHUNKS_PER_BLOCK so that ThinStateDiff is made from - // multiple StateDiffChunks - let (state_diffs, header_state_diff_lengths): (Vec<_>, Vec<_>) = (0..HEADER_QUERY_LENGTH) - .map(|_| { - let diff = create_random_state_diff_chunk(&mut rng); - let length = diff.len(); - (diff, length) - }) - .unzip(); - - let (state_diff_sender, mut state_diff_receiver) = channel(p2p_sync.config.buffer_size); - - // Create a future that will receive send responses and validate the results. - let test_future = async move { - for (start_block_number, num_blocks) in [ - (0u64, STATE_DIFF_QUERY_LENGTH), - (STATE_DIFF_QUERY_LENGTH, HEADER_QUERY_LENGTH - STATE_DIFF_QUERY_LENGTH), - ] { - for block_number in start_block_number..(start_block_number + num_blocks) { - let state_diff_chunk = state_diffs[usize::try_from(block_number).unwrap()].clone(); - - let block_number = BlockNumber(block_number); - // Check that before we've sent all parts the state diff wasn't written yet. - let txn = storage_reader.begin_ro_txn().unwrap(); - assert_eq!(block_number, txn.get_state_marker().unwrap()); - - state_diff_sender.send(Some(state_diff_chunk.clone())).await.unwrap(); - - // Check state diff was written to the storage. This way we make sure that the sync - // writes to the storage each block's state diff before receiving all query - // responses. + let class_hash0 = ClassHash(ascii_as_felt("class_hash0").unwrap()); + let class_hash1 = ClassHash(ascii_as_felt("class_hash1").unwrap()); + let casm_hash0 = CompiledClassHash(ascii_as_felt("casm_hash0").unwrap()); + let address0 = ContractAddress(ascii_as_felt("address0").unwrap().try_into().unwrap()); + let address1 = ContractAddress(ascii_as_felt("address1").unwrap().try_into().unwrap()); + let address2 = ContractAddress(ascii_as_felt("address2").unwrap().try_into().unwrap()); + let key0 = StorageKey(ascii_as_felt("key0").unwrap().try_into().unwrap()); + let key1 = StorageKey(ascii_as_felt("key1").unwrap().try_into().unwrap()); + let value0 = ascii_as_felt("value0").unwrap(); + let value1 = ascii_as_felt("value1").unwrap(); + let nonce0 = Nonce(ascii_as_felt("nonce0").unwrap()); + + let state_diffs_and_chunks = vec![ + ( + ThinStateDiff { + deployed_contracts: indexmap!(address0 => class_hash0), + storage_diffs: indexmap!(address0 => indexmap!(key0 => value0, key1 => value1)), + declared_classes: indexmap!(class_hash0 => casm_hash0), + deprecated_declared_classes: vec![class_hash1], + nonces: indexmap!(address0 => nonce0), + }, + vec![ + StateDiffChunk::DeclaredClass(DeclaredClass { + class_hash: class_hash0, + compiled_class_hash: casm_hash0, + }), + StateDiffChunk::ContractDiff(ContractDiff { + contract_address: address0, + class_hash: Some(class_hash0), + nonce: Some(nonce0), + storage_diffs: indexmap!(key0 => value0, key1 => value1), + }), + StateDiffChunk::DeprecatedDeclaredClass(DeprecatedDeclaredClass { + class_hash: class_hash1, + }), + ], + ), + ( + ThinStateDiff { + deployed_contracts: indexmap!(address1 => class_hash1), + storage_diffs: indexmap!( + address1 => indexmap!(key0 => value0), + address2 => indexmap!(key1 => value1) + ), + nonces: indexmap!(address2 => nonce0), + ..Default::default() + }, + vec![ + StateDiffChunk::ContractDiff(ContractDiff { + contract_address: address1, + class_hash: Some(class_hash1), + nonce: None, + storage_diffs: indexmap!(key0 => value0), + }), + StateDiffChunk::ContractDiff(ContractDiff { + contract_address: address2, + class_hash: None, + nonce: Some(nonce0), + storage_diffs: indexmap!(key1 => value1), + }), + ], + ), + ]; + + let mut actions = vec![ + Action::RunP2pSync, + // We already validate the header query content in other tests. + Action::ReceiveQuery(Box::new(|_query| ()), DataType::Header), + ]; + + // Sleep so state diff sync will reach the sleep waiting for header protocol to receive new + // data. + actions.push(Action::SleepToLetSyncAdvance); + // Send headers with corresponding state diff length + for (i, (state_diff, _)) in state_diffs_and_chunks.iter().enumerate() { + actions.push(Action::SendHeader(DataOrFin(Some(random_header( + &mut rng, + BlockNumber(i.try_into().unwrap()), + Some(state_diff.len()), + None, + ))))); + } + actions.push(Action::SendHeader(DataOrFin(None))); + + let len = state_diffs_and_chunks.len(); + // Wait for header sync to finish before continuing state diff sync. + actions.push(Action::CheckStorage(Box::new(move |reader| { + async move { + let block_number = BlockNumber(len.try_into().unwrap()); + wait_for_marker( + DataType::Header, + &reader, + block_number, + SLEEP_DURATION_TO_LET_SYNC_ADVANCE, + TIMEOUT_FOR_TEST, + ) + .await; + } + .boxed() + }))); + actions.push(Action::SimulateWaitPeriodForOtherProtocol); + + let len = state_diffs_and_chunks.len(); + actions.push(Action::ReceiveQuery( + Box::new(move |query| { + assert_eq!( + query, + Query { + start_block: BlockHashOrNumber::Number(BlockNumber(0)), + direction: Direction::Forward, + limit: len.try_into().unwrap(), + step: 1, + } + ) + }), + DataType::StateDiff, + )); + // Send state diff chunks and check storage + for (i, (expected_state_diff, state_diff_chunks)) in + state_diffs_and_chunks.iter().cloned().enumerate() + { + for state_diff_chunk in state_diff_chunks { + // Check that before the last chunk was sent, the state diff isn't written. + actions.push(Action::CheckStorage(Box::new(move |reader| { + async move { + assert_eq!( + u64::try_from(i).unwrap(), + reader.begin_ro_txn().unwrap().get_state_marker().unwrap().0 + ); + } + .boxed() + }))); + actions.push(Action::SendStateDiff(DataOrFin(Some(state_diff_chunk)))); + } + // Check that a block's state diff is written before the entire query finished. + actions.push(Action::CheckStorage(Box::new(move |reader| { + async move { + let block_number = BlockNumber(i.try_into().unwrap()); wait_for_marker( - MarkerKind::State, - &storage_reader, + DataType::StateDiff, + &reader, block_number.unchecked_next(), SLEEP_DURATION_TO_LET_SYNC_ADVANCE, TIMEOUT_FOR_TEST, ) .await; - let txn = storage_reader.begin_ro_txn().unwrap(); - let state_diff = txn.get_state_diff(block_number).unwrap().unwrap(); - // TODO(noamsp): refactor test so that we treat multiple state diff chunks as a - // single state diff - let expected_state_diff = match state_diff_chunk { - StateDiffChunk::ContractDiff(contract_diff) => { - let mut deployed_contracts = indexmap! {}; - if let Some(class_hash) = contract_diff.class_hash { - deployed_contracts.insert(contract_diff.contract_address, class_hash); - }; - let mut nonces = indexmap! {}; - if let Some(nonce) = contract_diff.nonce { - nonces.insert(contract_diff.contract_address, nonce); - } - ThinStateDiff { - deployed_contracts, - nonces, - storage_diffs: indexmap! { - contract_diff.contract_address => contract_diff.storage_diffs - }, - ..Default::default() - } - } - StateDiffChunk::DeclaredClass(declared_class) => ThinStateDiff { - declared_classes: indexmap! { - declared_class.class_hash => declared_class.compiled_class_hash - }, - ..Default::default() - }, - StateDiffChunk::DeprecatedDeclaredClass(deprecated_declared_class) => { - ThinStateDiff { - deprecated_declared_classes: vec![deprecated_declared_class.class_hash], - ..Default::default() - } - } - }; - assert_eq!(state_diff, expected_state_diff); + let txn = reader.begin_ro_txn().unwrap(); + let actual_state_diff = txn.get_state_diff(block_number).unwrap().unwrap(); + assert_eq!(actual_state_diff, expected_state_diff); } - - state_diff_sender.send(None).await.unwrap(); - } - }; - - tokio::select! { - sync_result = p2p_sync.run() => { - sync_result.unwrap(); - panic!("P2P sync aborted with no failure."); - } - _ = join( - run_state_diff_sync_through_channel( - &mut mock_header_response_manager, - &mut mock_state_diff_response_manager, - header_state_diff_lengths, - &mut state_diff_receiver, - false, - ), - test_future, - ) => {} + .boxed() + }))); } + actions.push(Action::SendStateDiff(DataOrFin(None))); + + run_test( + HashMap::from([ + (DataType::Header, state_diffs_and_chunks.len().try_into().unwrap()), + (DataType::StateDiff, state_diffs_and_chunks.len().try_into().unwrap()), + ]), + None, + actions, + ) + .await; } // TODO(noamsp): Consider verifying that ParseDataError::BadPeerError(EmptyStateDiffPart) was @@ -288,219 +325,44 @@ async fn validate_state_diff_fails( header_state_diff_lengths: Vec, state_diff_chunks: Vec>, ) { - let TestArgs { - storage_reader, - p2p_sync, - mut mock_state_diff_response_manager, - mut mock_header_response_manager, - // The test will fail if we drop these - mock_transaction_response_manager: _mock_transaction_responses_manager, - mock_class_response_manager: _mock_class_responses_manager, - .. - } = setup(); - - let (state_diff_sender, mut state_diff_receiver) = channel(p2p_sync.config.buffer_size); - - // Create a future that will send responses and validate the results. - let test_future = async move { - for state_diff_chunk in state_diff_chunks { - // Check that before we've sent all parts the state diff wasn't written yet. - let txn = storage_reader.begin_ro_txn().unwrap(); - assert_eq!(0, txn.get_state_marker().unwrap().0); - - state_diff_sender.send(state_diff_chunk).await.unwrap(); - } - }; - - tokio::select! { - sync_result = p2p_sync.run() => { - sync_result.unwrap(); - panic!("P2P sync aborted with no failure."); - } - _ = join( - run_state_diff_sync_through_channel( - &mut mock_header_response_manager, - &mut mock_state_diff_response_manager, - header_state_diff_lengths, - &mut state_diff_receiver, - true, - ), - test_future - ) => {} - } -} - -// Advances the header sync with associated header state diffs. -// The receiver waits for external sender to provide the state diff chunks. -async fn run_state_diff_sync_through_channel( - mock_header_response_manager: &mut GenericReceiver, - mock_state_diff_response_manager: &mut GenericReceiver, - header_state_diff_lengths: Vec, - state_diff_chunk_receiver: &mut Receiver>, - should_assert_reported: bool, -) { - // We wait for the state diff sync to see that there are no headers and start sleeping - tokio::time::sleep(SLEEP_DURATION_TO_LET_SYNC_ADVANCE).await; - - // Check that before we send headers there is no state diff query. - assert!(mock_state_diff_response_manager.next().now_or_never().is_none()); - - let num_headers = header_state_diff_lengths.len(); - let block_hashes_and_signatures = - create_block_hashes_and_signatures(num_headers.try_into().unwrap()); - - // split the headers into queries of size HEADER_QUERY_LENGTH and send headers for each query - for headers_for_current_query in block_hashes_and_signatures - .into_iter() - .zip(header_state_diff_lengths.clone().into_iter()) - .enumerate() - .collect::>() - .chunks(HEADER_QUERY_LENGTH.try_into().unwrap()) - .map(Vec::from) - { - // Receive the next query from header sync - let mut mock_header_responses_manager = mock_header_response_manager.next().await.unwrap(); - - for (i, ((block_hash, block_signature), header_state_diff_length)) in - headers_for_current_query - { - // Send header responses - mock_header_responses_manager - .send_response(DataOrFin(Some(SignedBlockHeader { - block_header: BlockHeader { - block_hash, - block_header_without_hash: BlockHeaderWithoutHash { - block_number: BlockNumber(u64::try_from(i).unwrap()), - ..Default::default() - }, - state_diff_length: Some(header_state_diff_length), - ..Default::default() - }, - signatures: vec![block_signature], - }))) - .await - .unwrap(); - } + let mut rng = get_rng(); - mock_header_responses_manager.send_response(DataOrFin(None)).await.unwrap(); + let mut actions = vec![ + Action::RunP2pSync, + // We already validate the header query content in other tests. + Action::ReceiveQuery(Box::new(|_query| ()), DataType::Header), + ]; + + // Send headers with corresponding state diff length + for (i, state_diff_length) in header_state_diff_lengths.iter().copied().enumerate() { + actions.push(Action::SendHeader(DataOrFin(Some(random_header( + &mut rng, + BlockNumber(i.try_into().unwrap()), + Some(state_diff_length), + None, + ))))); } + actions.push(Action::SendHeader(DataOrFin(None))); - // TODO(noamsp): remove sleep and wait until header marker writes the new headers. remove the - // comment from the StateDiffQuery about the limit being too low. We wait for the header - // sync to write the new headers. - tokio::time::sleep(SLEEP_DURATION_TO_LET_SYNC_ADVANCE).await; - - // Simulate time has passed so that state diff sync will resend query after it waited for - // new header - tokio::time::pause(); - tokio::time::advance(WAIT_PERIOD_FOR_NEW_DATA).await; - tokio::time::resume(); - - let num_state_diff_headers = u64::try_from(num_headers).unwrap(); - let num_state_diff_queries = num_state_diff_headers.div_ceil(STATE_DIFF_QUERY_LENGTH); - - for i in 0..num_state_diff_queries { - let start_block_number = i * STATE_DIFF_QUERY_LENGTH; - let limit = min(num_state_diff_headers - start_block_number, STATE_DIFF_QUERY_LENGTH); - - // Get a state diff query and validate it - let mut mock_state_diff_responses_manager = - mock_state_diff_response_manager.next().await.unwrap(); - assert_eq!( - *mock_state_diff_responses_manager.query(), - Ok(StateDiffQuery(Query { - start_block: BlockHashOrNumber::Number(BlockNumber(start_block_number)), - direction: Direction::Forward, - limit, - step: 1, - })), - "If the limit of the query is too low, try to increase \ - SLEEP_DURATION_TO_LET_SYNC_ADVANCE", - ); - - let mut current_state_diff_length = 0; - let destination_state_diff_length = - header_state_diff_lengths[start_block_number.try_into().unwrap() - ..(start_block_number + limit).try_into().unwrap()] - .iter() - .sum(); - - while current_state_diff_length < destination_state_diff_length { - let state_diff_chunk = state_diff_chunk_receiver.recv().await.unwrap(); - - mock_state_diff_responses_manager - .send_response(DataOrFin(state_diff_chunk.clone())) - .await - .unwrap(); - - if let Some(state_diff_chunk) = state_diff_chunk { - if !state_diff_chunk.is_empty() { - current_state_diff_length += state_diff_chunk.len(); - continue; - } - } - - break; - } - - if should_assert_reported { - mock_state_diff_responses_manager.assert_reported(TIMEOUT_FOR_TEST).await; - continue; - } + actions.push( + // We already validate the state diff query content in other tests. + Action::ReceiveQuery(Box::new(|_query| ()), DataType::StateDiff), + ); - assert_eq!(current_state_diff_length, destination_state_diff_length); - let state_diff_chunk = state_diff_chunk_receiver.recv().await.unwrap(); - mock_state_diff_responses_manager - .send_response(DataOrFin(state_diff_chunk.clone())) - .await - .unwrap(); + // Send state diff chunks. + for state_diff_chunk in state_diff_chunks { + actions.push(Action::SendStateDiff(DataOrFin(state_diff_chunk))); } -} -pub(crate) async fn run_state_diff_sync( - config: P2PSyncClientConfig, - mock_header_response_manager: &mut GenericReceiver, - mock_state_diff_response_manager: &mut GenericReceiver, - header_state_diff_lengths: Vec, - state_diff_chunks: Vec>, -) { - let (state_diff_sender, mut state_diff_receiver) = channel(config.buffer_size); - tokio::join! { - run_state_diff_sync_through_channel( - mock_header_response_manager, - mock_state_diff_response_manager, - header_state_diff_lengths, - &mut state_diff_receiver, - false, - ), - async { - for state_diff in state_diff_chunks.chunks(STATE_DIFF_QUERY_LENGTH.try_into().unwrap()) { - for state_diff_chunk in state_diff { - state_diff_sender.send(state_diff_chunk.clone()).await.unwrap(); - } + actions.push(Action::ValidateReportSent(DataType::StateDiff)); - state_diff_sender.send(None).await.unwrap(); - } - } - }; -} - -fn create_random_state_diff_chunk(rng: &mut ChaCha8Rng) -> StateDiffChunk { - let mut state_diff_chunk = StateDiffChunk::get_test_instance(rng); - let contract_address = ContractAddress::from(rng.next_u64()); - let class_hash = ClassHash(rng.next_u64().into()); - match &mut state_diff_chunk { - StateDiffChunk::ContractDiff(contract_diff) => { - contract_diff.contract_address = contract_address; - contract_diff.class_hash = Some(class_hash); - } - StateDiffChunk::DeclaredClass(declared_class) => { - declared_class.class_hash = class_hash; - declared_class.compiled_class_hash = CompiledClassHash(rng.next_u64().into()); - } - StateDiffChunk::DeprecatedDeclaredClass(deprecated_declared_class) => { - deprecated_declared_class.class_hash = class_hash; - } - } - state_diff_chunk + run_test( + HashMap::from([ + (DataType::Header, header_state_diff_lengths.len().try_into().unwrap()), + (DataType::StateDiff, header_state_diff_lengths.len().try_into().unwrap()), + ]), + None, + actions, + ) + .await; } diff --git a/crates/papyrus_p2p_sync/src/client/stream_builder.rs b/crates/papyrus_p2p_sync/src/client/stream_builder.rs deleted file mode 100644 index f566d50ecbe..00000000000 --- a/crates/papyrus_p2p_sync/src/client/stream_builder.rs +++ /dev/null @@ -1,221 +0,0 @@ -use std::cmp::min; -use std::time::Duration; - -use async_stream::stream; -use futures::future::BoxFuture; -use futures::stream::BoxStream; -use futures::StreamExt; -use papyrus_network::network_manager::{ClientResponsesManager, SqmrClientSender}; -use papyrus_protobuf::converters::ProtobufConversionError; -use papyrus_protobuf::sync::{BlockHashOrNumber, DataOrFin, Direction, Query}; -use papyrus_storage::header::HeaderStorageReader; -use papyrus_storage::state::StateStorageReader; -use papyrus_storage::{StorageError, StorageReader, StorageWriter}; -use starknet_api::block::{BlockNumber, BlockSignature}; -use starknet_api::core::ClassHash; -use tracing::{debug, info, warn}; - -use super::{P2PSyncClientError, STEP}; - -pub type DataStreamResult = Result, P2PSyncClientError>; - -pub(crate) trait BlockData: Send { - fn write_to_storage( - // This is Box in order to allow using it with `Box`. - self: Box, - storage_writer: &mut StorageWriter, - ) -> Result<(), StorageError>; -} - -pub(crate) enum BlockNumberLimit { - Unlimited, - HeaderMarker, - StateDiffMarker, -} - -pub(crate) trait DataStreamBuilder -where - InputFromNetwork: Send + 'static, - DataOrFin: TryFrom, Error = ProtobufConversionError>, -{ - type Output: BlockData + 'static; - - const TYPE_DESCRIPTION: &'static str; - const BLOCK_NUMBER_LIMIT: BlockNumberLimit; - - // Async functions in trait don't work well with argument references - fn parse_data_for_block<'a>( - client_response_manager: &'a mut ClientResponsesManager>, - block_number: BlockNumber, - storage_reader: &'a StorageReader, - ) -> BoxFuture<'a, Result, ParseDataError>>; - - fn get_start_block_number(storage_reader: &StorageReader) -> Result; - - fn create_stream( - mut sqmr_sender: SqmrClientSender>, - storage_reader: StorageReader, - wait_period_for_new_data: Duration, - num_blocks_per_query: u64, - stop_sync_at_block_number: Option, - ) -> BoxStream<'static, DataStreamResult> - where - TQuery: From + Send + 'static, - Vec: From, - { - stream! { - let mut current_block_number = Self::get_start_block_number(&storage_reader)?; - 'send_query_and_parse_responses: loop { - let limit = match Self::BLOCK_NUMBER_LIMIT { - BlockNumberLimit::Unlimited => num_blocks_per_query, - BlockNumberLimit::HeaderMarker | BlockNumberLimit::StateDiffMarker => { - let (last_block_number, description) = match Self::BLOCK_NUMBER_LIMIT { - BlockNumberLimit::HeaderMarker => (storage_reader.begin_ro_txn()?.get_header_marker()?, "header"), - BlockNumberLimit::StateDiffMarker => (storage_reader.begin_ro_txn()?.get_state_marker()?, "state diff"), - _ => unreachable!(), - }; - let limit = min(last_block_number.0 - current_block_number.0, num_blocks_per_query); - if limit == 0 { - debug!("{:?} sync is waiting for a new {}", Self::TYPE_DESCRIPTION, description); - tokio::time::sleep(wait_period_for_new_data).await; - continue; - } - limit - }, - }; - let end_block_number = current_block_number.0 + limit; - debug!( - "Downloading {:?} for blocks [{}, {})", - Self::TYPE_DESCRIPTION, - current_block_number.0, - end_block_number, - ); - // TODO(shahak): Use the report callback. - let mut client_response_manager = sqmr_sender - .send_new_query( - TQuery::from(Query { - start_block: BlockHashOrNumber::Number(current_block_number), - direction: Direction::Forward, - limit, - step: STEP, - }) - ) - .await?; - - while current_block_number.0 < end_block_number { - match Self::parse_data_for_block( - &mut client_response_manager, current_block_number, &storage_reader - ).await { - Ok(Some(output)) => yield Ok(Box::::from(Box::new(output))), - Ok(None) => { - debug!( - "Query for {:?} on {:?} returned with partial data. Waiting {:?} before \ - sending another query.", - Self::TYPE_DESCRIPTION, current_block_number, wait_period_for_new_data - ); - tokio::time::sleep(wait_period_for_new_data).await; - continue 'send_query_and_parse_responses; - }, - Err(ParseDataError::BadPeer(err)) => { - warn!( - "Query for {:?} on {:?} returned with bad peer error: {:?}. reporting \ - peer and retrying query.", - Self::TYPE_DESCRIPTION, current_block_number, err - ); - client_response_manager.report_peer(); - continue 'send_query_and_parse_responses; - }, - Err(ParseDataError::Fatal(err)) => { - yield Err(err); - return; - }, - } - info!("Added {:?} for block {}.", Self::TYPE_DESCRIPTION, current_block_number); - current_block_number = current_block_number.unchecked_next(); - if stop_sync_at_block_number.is_some_and(|stop_sync_at_block_number| { - current_block_number >= stop_sync_at_block_number - }) { - info!("{:?} hit the stop sync block number.", Self::TYPE_DESCRIPTION); - return; - } - } - - // Consume the None message signaling the end of the query. - match client_response_manager.next().await { - Some(Ok(DataOrFin(None))) => { - debug!("Query sent to network for {:?} finished", Self::TYPE_DESCRIPTION); - }, - Some(_) => Err(P2PSyncClientError::TooManyResponses)?, - None => Err(P2PSyncClientError::ReceiverChannelTerminated { - type_description: Self::TYPE_DESCRIPTION - })?, - } - } - } - .boxed() - } -} - -#[derive(thiserror::Error, Debug)] -pub(crate) enum BadPeerError { - #[error( - "Blocks returned unordered from the network. Expected header with \ - {expected_block_number}, got {actual_block_number}." - )] - HeadersUnordered { expected_block_number: BlockNumber, actual_block_number: BlockNumber }, - #[error( - "Expected to receive {expected} transactions for {block_number} from the network. Got \ - {actual} instead." - )] - NotEnoughTransactions { expected: usize, actual: usize, block_number: u64 }, - #[error("Expected to receive one signature from the network. got {signatures:?} instead.")] - WrongSignaturesLength { signatures: Vec }, - #[error( - "The header says that the block's state diff should be of length {expected_length}. Can \ - only divide the state diff parts into the following lengths: {possible_lengths:?}." - )] - WrongStateDiffLength { expected_length: usize, possible_lengths: Vec }, - #[error("Two state diff parts for the same state diff are conflicting.")] - ConflictingStateDiffParts, - #[error( - "Received an empty state diff part from the network (this is a potential DDoS vector)." - )] - EmptyStateDiffPart, - #[error(transparent)] - ProtobufConversionError(#[from] ProtobufConversionError), - #[error( - "Expected to receive {expected} classes for {block_number} from the network. Got {actual} \ - classes instead" - )] - NotEnoughClasses { expected: usize, actual: usize, block_number: u64 }, - #[error("The class with hash {class_hash} was not found in the state diff.")] - ClassNotInStateDiff { class_hash: ClassHash }, - #[error("Received two classes with the same hash: {class_hash}.")] - DuplicateClass { class_hash: ClassHash }, -} - -#[derive(thiserror::Error, Debug)] -pub(crate) enum ParseDataError { - #[error(transparent)] - Fatal(#[from] P2PSyncClientError), - #[error(transparent)] - BadPeer(#[from] BadPeerError), -} - -impl From for ParseDataError { - fn from(err: StorageError) -> Self { - ParseDataError::Fatal(P2PSyncClientError::StorageError(err)) - } -} - -impl From for ParseDataError { - fn from(err: tokio::time::error::Elapsed) -> Self { - ParseDataError::Fatal(P2PSyncClientError::NetworkTimeout(err)) - } -} - -impl From for ParseDataError { - fn from(err: ProtobufConversionError) -> Self { - ParseDataError::BadPeer(BadPeerError::ProtobufConversionError(err)) - } -} diff --git a/crates/papyrus_p2p_sync/src/client/test.rs b/crates/papyrus_p2p_sync/src/client/test.rs new file mode 100644 index 00000000000..c9e61921ce4 --- /dev/null +++ b/crates/papyrus_p2p_sync/src/client/test.rs @@ -0,0 +1,289 @@ +use std::collections::HashMap; + +use futures::FutureExt; +use indexmap::IndexMap; +use papyrus_protobuf::sync::DataOrFin; +use papyrus_storage::body::BodyStorageReader; +use papyrus_storage::header::HeaderStorageReader; +use papyrus_storage::state::StateStorageReader; +use papyrus_test_utils::{get_rng, GetTestInstance}; +use rand::Rng; +use rand_chacha::ChaCha8Rng; +use starknet_api::block::{BlockHeaderWithoutHash, BlockNumber}; +use starknet_api::core::{ClassHash, ContractAddress}; +use starknet_api::state::ThinStateDiff; +use starknet_api::transaction::TransactionHash; +use starknet_state_sync_types::state_sync_types::SyncBlock; + +use crate::client::test_utils::{ + random_header, + run_test, + wait_for_marker, + Action, + DataType, + SLEEP_DURATION_TO_LET_SYNC_ADVANCE, + TIMEOUT_FOR_TEST, +}; + +#[tokio::test] +async fn receive_block_internally() { + let transaction_hashes_len = 2; + let sync_block = create_random_sync_block(BlockNumber(0), transaction_hashes_len, get_rng()); + let block_header_without_hash = sync_block.block_header_without_hash.clone(); + let transaction_hashes = sync_block.transaction_hashes.clone(); + let state_diff = sync_block.state_diff.clone(); + + run_test( + HashMap::new(), + None, + vec![ + Action::SendInternalBlock(sync_block), + Action::RunP2pSync, + Action::CheckStorage(Box::new(move |reader| { + async move { + wait_for_marker( + DataType::StateDiff, + &reader, + BlockNumber(1), + SLEEP_DURATION_TO_LET_SYNC_ADVANCE, + TIMEOUT_FOR_TEST, + ) + .await; + wait_for_marker( + DataType::Transaction, + &reader, + BlockNumber(1), + SLEEP_DURATION_TO_LET_SYNC_ADVANCE, + TIMEOUT_FOR_TEST, + ) + .await; + + assert_eq!( + reader.begin_ro_txn().unwrap().get_header_marker().unwrap(), + BlockNumber(1) + ); + let txn = reader.begin_ro_txn().unwrap(); + let block_header = txn.get_block_header(BlockNumber(0)).unwrap(); + assert!(block_header.clone().is_some()); + assert!( + block_header.clone().unwrap().n_transactions + == Into::::into(transaction_hashes_len) + ); + assert!(block_header.unwrap().state_diff_length.unwrap() == 1); + assert_eq!( + txn.get_block_header(BlockNumber(0)) + .unwrap() + .unwrap() + .block_header_without_hash, + block_header_without_hash + ); + assert_eq!(txn.get_state_diff(BlockNumber(0)).unwrap().unwrap(), state_diff); + assert_eq!( + txn.get_block_transaction_hashes(BlockNumber(0)) + .unwrap() + .unwrap() + .as_slice(), + transaction_hashes.as_slice() + ); + } + .boxed() + })), + ], + ) + .await; +} + +#[tokio::test] +async fn receive_blocks_out_of_order() { + let mut rng = get_rng(); + let sync_block_0 = create_random_sync_block(BlockNumber(0), 1, rng.clone()); + let block_header_without_hash_0 = sync_block_0.block_header_without_hash.clone(); + let transaction_hashes_0 = sync_block_0.transaction_hashes.clone(); + let state_diff_0 = sync_block_0.state_diff.clone(); + + // We need to forward the rng to the next generated num to make sure the blocks are different. + rng.gen::(); + let sync_block_1 = create_random_sync_block(BlockNumber(1), 1, rng); + let block_header_without_hash_1 = sync_block_1.block_header_without_hash.clone(); + let transaction_hashes_1 = sync_block_1.transaction_hashes.clone(); + let state_diff_1 = sync_block_1.state_diff.clone(); + + run_test( + HashMap::new(), + None, + vec![ + Action::SendInternalBlock(sync_block_1), + Action::SendInternalBlock(sync_block_0), + Action::RunP2pSync, + Action::CheckStorage(Box::new(move |reader| { + async move { + wait_for_marker( + DataType::StateDiff, + &reader, + BlockNumber(2), + SLEEP_DURATION_TO_LET_SYNC_ADVANCE, + TIMEOUT_FOR_TEST, + ) + .await; + wait_for_marker( + DataType::Transaction, + &reader, + BlockNumber(2), + SLEEP_DURATION_TO_LET_SYNC_ADVANCE, + TIMEOUT_FOR_TEST, + ) + .await; + + assert_eq!( + reader.begin_ro_txn().unwrap().get_header_marker().unwrap(), + BlockNumber(2) + ); + let txn = reader.begin_ro_txn().unwrap(); + // TODO(Eitan): test rest of data types + assert_eq!( + txn.get_block_header(BlockNumber(0)) + .unwrap() + .unwrap() + .block_header_without_hash, + block_header_without_hash_0 + ); + assert_eq!(txn.get_state_diff(BlockNumber(0)).unwrap().unwrap(), state_diff_0); + assert_eq!( + txn.get_block_transaction_hashes(BlockNumber(0)) + .unwrap() + .unwrap() + .as_slice(), + transaction_hashes_0.as_slice() + ); + assert_eq!( + txn.get_block_header(BlockNumber(1)) + .unwrap() + .unwrap() + .block_header_without_hash, + block_header_without_hash_1 + ); + assert_eq!(txn.get_state_diff(BlockNumber(1)).unwrap().unwrap(), state_diff_1); + assert_eq!( + txn.get_block_transaction_hashes(BlockNumber(1)) + .unwrap() + .unwrap() + .as_slice(), + transaction_hashes_1.as_slice() + ); + } + .boxed() + })), + ], + ) + .await; +} + +#[tokio::test] +async fn receive_blocks_first_externally_and_then_internally() { + let rng = get_rng(); + let sync_block_0 = create_random_sync_block(BlockNumber(0), 1, rng.clone()); + let sync_block_1 = create_random_sync_block(BlockNumber(1), 1, rng); + run_test( + HashMap::from([(DataType::Header, 2)]), + None, + vec![ + Action::RunP2pSync, + // We already validate the query content in other tests. + Action::ReceiveQuery(Box::new(|_query| ()), DataType::Header), + Action::SendHeader(DataOrFin(Some(random_header( + &mut get_rng(), + BlockNumber(0), + None, + None, + )))), + Action::CheckStorage(Box::new(|reader| { + async move { + wait_for_marker( + DataType::Header, + &reader, + BlockNumber(1), + SLEEP_DURATION_TO_LET_SYNC_ADVANCE, + TIMEOUT_FOR_TEST, + ) + .await; + assert_eq!( + BlockNumber(1), + reader.begin_ro_txn().unwrap().get_header_marker().unwrap() + ); + } + .boxed() + })), + Action::SendInternalBlock(sync_block_0), + Action::SendInternalBlock(sync_block_1), + Action::CheckStorage(Box::new(|reader| { + async move { + wait_for_marker( + DataType::Header, + &reader, + BlockNumber(2), + SLEEP_DURATION_TO_LET_SYNC_ADVANCE, + TIMEOUT_FOR_TEST, + ) + .await; + assert_eq!( + BlockNumber(2), + reader.begin_ro_txn().unwrap().get_header_marker().unwrap() + ); + } + .boxed() + })), + ], + ) + .await; +} + +fn create_random_sync_block( + block_number: BlockNumber, + transaction_hashes_len: u8, + mut rng: ChaCha8Rng, +) -> SyncBlock { + let contract_address = ContractAddress::from(1_u128); + let state_diff = ThinStateDiff { + deployed_contracts: vec![(contract_address, ClassHash::get_test_instance(&mut rng))] + .into_iter() + .collect(), + storage_diffs: IndexMap::new(), + declared_classes: IndexMap::new(), + deprecated_declared_classes: vec![], + nonces: IndexMap::new(), + }; + + let mut transaction_hashes = vec![]; + for _ in 0..transaction_hashes_len { + transaction_hashes.push(TransactionHash::random(&mut rng)); + } + let BlockHeaderWithoutHash { + block_number: _, + parent_hash, + timestamp, + state_root, + l1_gas_price, + l1_data_gas_price, + l2_gas_price, + l2_gas_consumed, + next_l2_gas_price, + sequencer, + l1_da_mode, + starknet_version, + } = BlockHeaderWithoutHash::get_test_instance(&mut rng); + let block_header_without_hash = BlockHeaderWithoutHash { + block_number, + parent_hash, + timestamp, + state_root, + l1_gas_price, + l1_data_gas_price, + l2_gas_price, + l2_gas_consumed, + next_l2_gas_price, + sequencer, + l1_da_mode, + starknet_version, + }; + SyncBlock { state_diff, transaction_hashes, block_header_without_hash } +} diff --git a/crates/papyrus_p2p_sync/src/client/test_utils.rs b/crates/papyrus_p2p_sync/src/client/test_utils.rs index d9423d1f9bf..c48c3bdb86a 100644 --- a/crates/papyrus_p2p_sync/src/client/test_utils.rs +++ b/crates/papyrus_p2p_sync/src/client/test_utils.rs @@ -1,5 +1,12 @@ +use core::panic; +use std::collections::HashMap; +use std::fmt::Debug; +use std::sync::Arc; use std::time::{Duration, Instant}; +use futures::channel::mpsc; +use futures::future::BoxFuture; +use futures::{FutureExt, SinkExt, StreamExt}; use lazy_static::lazy_static; use papyrus_common::pending_classes::ApiContractClass; use papyrus_network::network_manager::test_utils::{ @@ -11,25 +18,38 @@ use papyrus_protobuf::sync::{ ClassQuery, DataOrFin, HeaderQuery, + Query, SignedBlockHeader, StateDiffChunk, StateDiffQuery, TransactionQuery, }; use papyrus_storage::body::BodyStorageReader; -use papyrus_storage::class::ClassStorageReader; +use papyrus_storage::class_manager::ClassManagerStorageReader; use papyrus_storage::header::HeaderStorageReader; use papyrus_storage::state::StateStorageReader; use papyrus_storage::test_utils::get_test_storage; use papyrus_storage::StorageReader; -use starknet_api::block::{BlockHash, BlockNumber, BlockSignature}; +use papyrus_test_utils::GetTestInstance; +use rand::{Rng, RngCore}; +use rand_chacha::ChaCha8Rng; +use starknet_api::block::{ + BlockHash, + BlockHeader, + BlockHeaderWithoutHash, + BlockNumber, + BlockSignature, +}; use starknet_api::core::ClassHash; use starknet_api::crypto::utils::Signature; use starknet_api::hash::StarkHash; use starknet_api::transaction::FullTransaction; +use starknet_class_manager_types::MockClassManagerClient; +use starknet_state_sync_types::state_sync_types::SyncBlock; use starknet_types_core::felt::Felt; +use tokio::sync::oneshot; -use super::{P2PSyncClient, P2PSyncClientChannels, P2PSyncClientConfig}; +use super::{P2pSyncClient, P2pSyncClientChannels, P2pSyncClientConfig}; pub(crate) const TIMEOUT_FOR_TEST: Duration = Duration::from_secs(5); pub const BUFFER_SIZE: usize = 1000; @@ -39,18 +59,19 @@ pub const CLASS_DIFF_QUERY_LENGTH: u64 = 3; pub const TRANSACTION_QUERY_LENGTH: u64 = 3; pub const SLEEP_DURATION_TO_LET_SYNC_ADVANCE: Duration = Duration::from_millis(10); pub const WAIT_PERIOD_FOR_NEW_DATA: Duration = Duration::from_secs(1); +pub const WAIT_PERIOD_FOR_OTHER_PROTOCOL: Duration = Duration::from_secs(1); pub const TIMEOUT_FOR_NEW_QUERY_AFTER_PARTIAL_RESPONSE: Duration = WAIT_PERIOD_FOR_NEW_DATA.saturating_add(Duration::from_secs(1)); lazy_static! { - static ref TEST_CONFIG: P2PSyncClientConfig = P2PSyncClientConfig { + static ref TEST_CONFIG: P2pSyncClientConfig = P2pSyncClientConfig { num_headers_per_query: HEADER_QUERY_LENGTH, num_block_state_diffs_per_query: STATE_DIFF_QUERY_LENGTH, num_block_transactions_per_query: TRANSACTION_QUERY_LENGTH, num_block_classes_per_query: CLASS_DIFF_QUERY_LENGTH, wait_period_for_new_data: WAIT_PERIOD_FOR_NEW_DATA, + wait_period_for_other_protocol: WAIT_PERIOD_FOR_OTHER_PROTOCOL, buffer_size: BUFFER_SIZE, - stop_sync_at_block_number: None, }; } pub(crate) type HeaderTestPayload = @@ -65,7 +86,7 @@ pub(crate) type ClassTestPayload = // TODO(Eitan): Use SqmrSubscriberChannels once there is a utility function for testing pub struct TestArgs { #[allow(clippy::type_complexity)] - pub p2p_sync: P2PSyncClient, + pub p2p_sync: P2pSyncClient, pub storage_reader: StorageReader, pub mock_header_response_manager: GenericReceiver, pub mock_state_diff_response_manager: GenericReceiver, @@ -87,17 +108,20 @@ pub fn setup() -> TestArgs { mock_register_sqmr_protocol_client(buffer_size); let (class_sender, mock_class_response_manager) = mock_register_sqmr_protocol_client(buffer_size); - let p2p_sync_channels = P2PSyncClientChannels { + let p2p_sync_channels = P2pSyncClientChannels { header_sender, state_diff_sender, transaction_sender, class_sender, }; - let p2p_sync = P2PSyncClient::new( + let class_manager_client = Arc::new(MockClassManagerClient::new()); + let p2p_sync = P2pSyncClient::new( p2p_sync_config, storage_reader.clone(), storage_writer, p2p_sync_channels, + futures::stream::pending().boxed(), + class_manager_client, ); TestArgs { p2p_sync, @@ -109,6 +133,243 @@ pub fn setup() -> TestArgs { } } +#[derive(Eq, PartialEq, Hash)] +pub enum DataType { + Header, + #[allow(dead_code)] + Transaction, + StateDiff, + #[allow(dead_code)] + Class, +} + +pub enum Action { + /// Run the p2p sync client. + RunP2pSync, + /// Get a header query from the sync and run custom validations on it. + ReceiveQuery(Box, DataType), + /// Send a header as a response to a query we got from ReceiveQuery. Will panic if didn't call + /// ReceiveQuery with DataType::Header before. + SendHeader(DataOrFin), + /// Send a state diff as a response to a query we got from ReceiveQuery. Will panic if didn't + /// call ReceiveQuery with DataType::StateDiff before. + SendStateDiff(DataOrFin), + /// Send a transaction as a response to a query we got from ReceiveQuery. Will panic if didn't + /// call ReceiveQuery with DataType::Transaction before. + SendTransaction(DataOrFin), + /// Send a class as a response to a query we got from ReceiveQuery. Will panic if didn't + /// call ReceiveQuery with DataType::Class before. + SendClass(DataOrFin<(ApiContractClass, ClassHash)>), + /// Perform custom validations on the storage. Returns back the storage reader it received as + /// input + CheckStorage(Box BoxFuture<'static, ()>>), + /// Check that a report was sent on the current header query. + ValidateReportSent(DataType), + /// Sends an internal block to the sync. + #[allow(dead_code)] + SendInternalBlock(SyncBlock), + /// Sleep for SLEEP_DURATION_TO_LET_SYNC_ADVANCE duration. + SleepToLetSyncAdvance, + /// Simulate WAIT_PERIOD_FOR_OTHER_PROTOCOL duration has passed. + SimulateWaitPeriodForOtherProtocol, +} + +// TODO(shahak): add support for state diffs, transactions and classes. +pub async fn run_test( + max_query_lengths: HashMap, + class_manager_client: Option, + actions: Vec, +) { + let p2p_sync_config = P2pSyncClientConfig { + num_headers_per_query: max_query_lengths.get(&DataType::Header).cloned().unwrap_or(1), + num_block_state_diffs_per_query: max_query_lengths + .get(&DataType::StateDiff) + .cloned() + .unwrap_or(1), + num_block_transactions_per_query: max_query_lengths + .get(&DataType::Transaction) + .cloned() + .unwrap_or(1), + num_block_classes_per_query: max_query_lengths.get(&DataType::Class).cloned().unwrap_or(1), + wait_period_for_new_data: WAIT_PERIOD_FOR_NEW_DATA, + wait_period_for_other_protocol: WAIT_PERIOD_FOR_OTHER_PROTOCOL, + buffer_size: BUFFER_SIZE, + }; + let class_manager_client = class_manager_client.unwrap_or_default(); + let class_manager_client = Arc::new(class_manager_client); + let buffer_size = p2p_sync_config.buffer_size; + let ((storage_reader, storage_writer), _temp_dir) = get_test_storage(); + let (header_sender, mut mock_header_network) = mock_register_sqmr_protocol_client(buffer_size); + let (state_diff_sender, mut mock_state_diff_network) = + mock_register_sqmr_protocol_client(buffer_size); + let (transaction_sender, mut mock_transaction_network) = + mock_register_sqmr_protocol_client(buffer_size); + let (class_sender, mut mock_class_network) = mock_register_sqmr_protocol_client(buffer_size); + let p2p_sync_channels = P2pSyncClientChannels { + header_sender, + state_diff_sender, + transaction_sender, + class_sender, + }; + let (mut internal_block_sender, internal_block_receiver) = mpsc::channel(buffer_size); + let p2p_sync = P2pSyncClient::new( + p2p_sync_config, + storage_reader.clone(), + storage_writer, + p2p_sync_channels, + internal_block_receiver.boxed(), + class_manager_client, + ); + + let mut headers_current_query_responses_manager = None; + let mut state_diff_current_query_responses_manager = None; + let mut transaction_current_query_responses_manager = None; + let mut class_current_query_responses_manager = None; + + let (sync_future_sender, sync_future_receiver) = oneshot::channel(); + let mut sync_future_sender = Some(sync_future_sender); + + tokio::select! { + _ = async { + for action in actions { + match action { + Action::ReceiveQuery(validate_query_fn, data_type) => { + let query = match data_type { + DataType::Header => { + get_next_query_and_update_responses_manager( + &mut mock_header_network, + &mut headers_current_query_responses_manager, + ).await.0 + } + DataType::StateDiff => { + get_next_query_and_update_responses_manager( + &mut mock_state_diff_network, + &mut state_diff_current_query_responses_manager, + ).await.0 + } + DataType::Transaction => { + get_next_query_and_update_responses_manager( + &mut mock_transaction_network, + &mut transaction_current_query_responses_manager, + ).await.0 + } + DataType::Class => { + get_next_query_and_update_responses_manager( + &mut mock_class_network, + &mut class_current_query_responses_manager, + ).await.0 + } + }; + validate_query_fn(query); + } + Action::SendHeader(header_or_fin) => { + let responses_manager = headers_current_query_responses_manager.as_mut() + .expect("Called SendHeader without calling ReceiveQuery"); + responses_manager.send_response(header_or_fin).await.unwrap(); + } + Action::SendStateDiff(state_diff_or_fin) => { + let responses_manager = state_diff_current_query_responses_manager.as_mut() + .expect("Called SendStateDiff without calling ReceiveQuery"); + responses_manager.send_response(state_diff_or_fin).await.unwrap(); + } + Action::SendTransaction(transaction_or_fin) => { + let responses_manager = transaction_current_query_responses_manager.as_mut() + .expect("Called SendTransaction without calling ReceiveQuery"); + responses_manager.send_response(transaction_or_fin).await.unwrap(); + } + Action::SendClass(class_or_fin) => { + let responses_manager = class_current_query_responses_manager.as_mut() + .expect("Called SendClass without calling ReceiveQuery"); + responses_manager.send_response(class_or_fin).await.unwrap(); + } + Action::CheckStorage(check_storage_fn) => { + // We tried avoiding the clone here but it causes lifetime issues. + check_storage_fn(storage_reader.clone()).await; + } + Action::ValidateReportSent(DataType::Header) => { + let responses_manager = headers_current_query_responses_manager.take() + .expect( + "Called ValidateReportSent without calling ReceiveQuery on the same + data type"); + responses_manager.assert_reported(TIMEOUT_FOR_TEST).await; + } + Action::ValidateReportSent(DataType::StateDiff) => { + let responses_manager = state_diff_current_query_responses_manager.take() + .expect( + "Called ValidateReportSent without calling ReceiveQuery on the same + data type"); + responses_manager.assert_reported(TIMEOUT_FOR_TEST).await; + } + Action::ValidateReportSent(DataType::Transaction) => { + let responses_manager = transaction_current_query_responses_manager.take() + .expect( + "Called ValidateReportSent without calling ReceiveQuery on the same + data type"); + responses_manager.assert_reported(TIMEOUT_FOR_TEST).await; + } + Action::ValidateReportSent(DataType::Class) => { + let responses_manager = class_current_query_responses_manager.take() + .expect( + "Called ValidateReportSent without calling ReceiveQuery on the same + data type"); + responses_manager.assert_reported(TIMEOUT_FOR_TEST).await; + } + Action::SendInternalBlock(sync_block) => { + internal_block_sender.send(sync_block).await.unwrap(); + } + Action::RunP2pSync => { + sync_future_sender.take().expect("Called RunP2pSync twice").send(()).expect("Failed to send message to run p2p sync"); + } + Action::SleepToLetSyncAdvance => { + tokio::time::sleep(SLEEP_DURATION_TO_LET_SYNC_ADVANCE).await; + } + Action::SimulateWaitPeriodForOtherProtocol => { + tokio::time::pause(); + tokio::time::advance(WAIT_PERIOD_FOR_OTHER_PROTOCOL).await; + tokio::time::resume(); + } + } + } + } => {}, + res = sync_future_receiver.then(|res| async { + res.expect("Failed to run p2p sync"); + p2p_sync.run().await + }) => { + res.unwrap(); + unreachable!("Return type Never should never be constructed."); + } + _ = tokio::time::sleep(TIMEOUT_FOR_TEST) => { + panic!("Test timed out."); + } + } +} + +pub fn random_header( + rng: &mut ChaCha8Rng, + block_number: BlockNumber, + state_diff_length: Option, + num_transactions: Option, +) -> SignedBlockHeader { + SignedBlockHeader { + block_header: BlockHeader { + // TODO(shahak): Remove this once get_test_instance puts random values. + block_hash: BlockHash(rng.next_u64().into()), + block_header_without_hash: BlockHeaderWithoutHash { + block_number, + ..GetTestInstance::get_test_instance(rng) + }, + state_diff_length: Some(state_diff_length.unwrap_or_else(|| rng.gen())), + n_transactions: num_transactions.unwrap_or_else(|| rng.gen()), + ..GetTestInstance::get_test_instance(rng) + }, + // TODO(shahak): Remove this once get_test_instance puts random values. + signatures: vec![BlockSignature(Signature { + r: rng.next_u64().into(), + s: rng.next_u64().into(), + })], + } +} + pub fn create_block_hashes_and_signatures(n_blocks: u8) -> Vec<(BlockHash, BlockSignature)> { let mut bytes = [0u8; 32]; (0u8..n_blocks) @@ -125,18 +386,9 @@ pub fn create_block_hashes_and_signatures(n_blocks: u8) -> Vec<(BlockHash, Block .collect() } -pub(crate) enum MarkerKind { - Header, - #[allow(dead_code)] - Body, - State, - #[allow(dead_code)] - Class, -} - -// TODO: Consider moving this to storage and to use poll wakeup instead of sleep +// TODO(Shahak): Consider moving this to storage and to use poll wakeup instead of sleep pub(crate) async fn wait_for_marker( - marker_kind: MarkerKind, + data_type: DataType, storage_reader: &StorageReader, expected_marker: BlockNumber, sleep_duration: Duration, @@ -148,11 +400,11 @@ pub(crate) async fn wait_for_marker( assert!(start_time.elapsed() < timeout, "Timeout waiting for marker"); let txn = storage_reader.begin_ro_txn().unwrap(); - let storage_marker = match marker_kind { - MarkerKind::Header => txn.get_header_marker().unwrap(), - MarkerKind::Body => txn.get_body_marker().unwrap(), - MarkerKind::State => txn.get_state_marker().unwrap(), - MarkerKind::Class => txn.get_class_marker().unwrap(), + let storage_marker = match data_type { + DataType::Header => txn.get_header_marker().unwrap(), + DataType::Transaction => txn.get_body_marker().unwrap(), + DataType::StateDiff => txn.get_state_marker().unwrap(), + DataType::Class => txn.get_class_manager_block_marker().unwrap(), }; if storage_marker >= expected_marker { @@ -162,3 +414,19 @@ pub(crate) async fn wait_for_marker( tokio::time::sleep(sleep_duration).await; } } + +async fn get_next_query_and_update_responses_manager< + Query: TryFrom> + Clone, + Response: TryFrom>, +>( + mock_network: &mut GenericReceiver>, + current_query_responses_manager: &mut Option>, +) -> Query +where + >>::Error: Debug, +{ + let responses_manager = mock_network.next().await.unwrap(); + let query = responses_manager.query().as_ref().unwrap().clone(); + *current_query_responses_manager = Some(responses_manager); + query +} diff --git a/crates/papyrus_p2p_sync/src/client/transaction.rs b/crates/papyrus_p2p_sync/src/client/transaction.rs index e3c11a8df87..eb2d6c0cce1 100644 --- a/crates/papyrus_p2p_sync/src/client/transaction.rs +++ b/crates/papyrus_p2p_sync/src/client/transaction.rs @@ -5,30 +5,43 @@ use papyrus_protobuf::sync::DataOrFin; use papyrus_storage::body::{BodyStorageReader, BodyStorageWriter}; use papyrus_storage::header::HeaderStorageReader; use papyrus_storage::{StorageError, StorageReader, StorageWriter}; +use papyrus_sync::metrics::{SYNC_BODY_MARKER, SYNC_PROCESSED_TRANSACTIONS}; use starknet_api::block::{BlockBody, BlockNumber}; -use starknet_api::transaction::FullTransaction; +use starknet_api::test_utils::invoke::{invoke_tx, InvokeTxArgs}; +use starknet_api::transaction::{FullTransaction, Transaction, TransactionOutput}; +use starknet_class_manager_types::SharedClassManagerClient; +use starknet_state_sync_types::state_sync_types::SyncBlock; -use super::stream_builder::{ +use super::block_data_stream_builder::{ BadPeerError, BlockData, + BlockDataStreamBuilder, BlockNumberLimit, - DataStreamBuilder, ParseDataError, }; -use super::{P2PSyncClientError, NETWORK_DATA_TIMEOUT}; +use super::P2pSyncClientError; impl BlockData for (BlockBody, BlockNumber) { - fn write_to_storage( + fn write_to_storage<'a>( self: Box, - storage_writer: &mut StorageWriter, - ) -> Result<(), StorageError> { - storage_writer.begin_rw_txn()?.append_body(self.1, self.0)?.commit() + storage_writer: &'a mut StorageWriter, + _class_manager_client: &'a mut SharedClassManagerClient, + ) -> BoxFuture<'a, Result<(), P2pSyncClientError>> { + async move { + let num_txs = + self.0.transactions.len().try_into().expect("Failed to convert usize to u64"); + storage_writer.begin_rw_txn()?.append_body(self.1, self.0)?.commit()?; + SYNC_BODY_MARKER.set_lossy(self.1.unchecked_next().0); + SYNC_PROCESSED_TRANSACTIONS.increment(num_txs); + Ok(()) + } + .boxed() } } pub(crate) struct TransactionStreamFactory; -impl DataStreamBuilder for TransactionStreamFactory { +impl BlockDataStreamBuilder for TransactionStreamFactory { // TODO(Eitan): Add events protocol to BlockBody or split their write to storage type Output = (BlockBody, BlockNumber); @@ -49,14 +62,11 @@ impl DataStreamBuilder for TransactionStreamFactory { .expect("A header with number lower than the header marker is missing") .n_transactions; while current_transaction_len < target_transaction_len { - let maybe_transaction = tokio::time::timeout( - NETWORK_DATA_TIMEOUT, - transactions_response_manager.next(), - ) - .await? - .ok_or(P2PSyncClientError::ReceiverChannelTerminated { - type_description: Self::TYPE_DESCRIPTION, - })?; + let maybe_transaction = transactions_response_manager.next().await.ok_or( + ParseDataError::BadPeer(BadPeerError::SessionEndedWithoutFin { + type_description: Self::TYPE_DESCRIPTION, + }), + )?; let Some(FullTransaction { transaction, transaction_output, transaction_hash }) = maybe_transaction?.0 else { @@ -84,4 +94,26 @@ impl DataStreamBuilder for TransactionStreamFactory { fn get_start_block_number(storage_reader: &StorageReader) -> Result { storage_reader.begin_ro_txn()?.get_body_marker() } + + // TODO(Eitan): Use real transactions once SyncBlock contains data required by full nodes + fn convert_sync_block_to_block_data( + block_number: BlockNumber, + sync_block: SyncBlock, + ) -> (BlockBody, BlockNumber) { + let num_transactions = sync_block.transaction_hashes.len(); + let block_body = BlockBody { + transaction_hashes: sync_block.transaction_hashes, + transaction_outputs: std::iter::repeat_with(|| { + TransactionOutput::Invoke(Default::default()) + }) + .take(num_transactions) + .collect::>(), + transactions: std::iter::repeat_with(|| { + Transaction::Invoke(invoke_tx(InvokeTxArgs::default())) + }) + .take(num_transactions) + .collect::>(), + }; + (block_body, block_number) + } } diff --git a/crates/papyrus_p2p_sync/src/client/transaction_test.rs b/crates/papyrus_p2p_sync/src/client/transaction_test.rs index 591703d1640..65a3ecf0399 100644 --- a/crates/papyrus_p2p_sync/src/client/transaction_test.rs +++ b/crates/papyrus_p2p_sync/src/client/transaction_test.rs @@ -1,181 +1,168 @@ use std::cmp::min; +use std::collections::HashMap; -use futures::{FutureExt, StreamExt}; -use papyrus_protobuf::sync::{ - BlockHashOrNumber, - DataOrFin, - Direction, - Query, - SignedBlockHeader, - TransactionQuery, -}; +use futures::FutureExt; +use papyrus_protobuf::sync::{BlockHashOrNumber, DataOrFin, Direction, Query}; use papyrus_storage::body::BodyStorageReader; -use papyrus_test_utils::get_test_body; -use starknet_api::block::{BlockBody, BlockHeader, BlockHeaderWithoutHash, BlockNumber}; -use starknet_api::transaction::FullTransaction; +use papyrus_test_utils::{get_rng, get_test_body}; +use starknet_api::block::{BlockBody, BlockNumber}; +use starknet_api::transaction::{FullTransaction, TransactionHash}; use super::test_utils::{ - create_block_hashes_and_signatures, - setup, - TestArgs, - HEADER_QUERY_LENGTH, + random_header, + run_test, + wait_for_marker, + Action, + DataType, SLEEP_DURATION_TO_LET_SYNC_ADVANCE, - TRANSACTION_QUERY_LENGTH, - WAIT_PERIOD_FOR_NEW_DATA, + TIMEOUT_FOR_TEST, }; -use crate::client::test_utils::{wait_for_marker, MarkerKind, TIMEOUT_FOR_TEST}; #[tokio::test] async fn transaction_basic_flow() { - let TestArgs { - p2p_sync, - storage_reader, - mut mock_header_response_manager, - mut mock_transaction_response_manager, - // The test will fail if we drop these - mock_state_diff_response_manager: _mock_state_diff_response_manager, - mock_class_response_manager: _mock_class_responses_manager, - .. - } = setup(); - - const NUM_TRANSACTIONS_PER_BLOCK: u64 = 6; - let block_hashes_and_signatures = - create_block_hashes_and_signatures(HEADER_QUERY_LENGTH.try_into().unwrap()); - let BlockBody { transactions, transaction_outputs, transaction_hashes } = get_test_body( - (NUM_TRANSACTIONS_PER_BLOCK * HEADER_QUERY_LENGTH).try_into().unwrap(), - None, - None, - None, - ); - - // Create a future that will receive queries, send responses and validate the results. - let parse_queries_future = async move { - // We wait for the state diff sync to see that there are no headers and start sleeping - tokio::time::sleep(SLEEP_DURATION_TO_LET_SYNC_ADVANCE).await; - - // Check that before we send headers there is no transaction query. - assert!(mock_transaction_response_manager.next().now_or_never().is_none()); - let mut mock_header_responses_manager = mock_header_response_manager.next().await.unwrap(); - - // Send headers for entire query. - for (i, (block_hash, block_signature)) in block_hashes_and_signatures.iter().enumerate() { - // Send responses - mock_header_responses_manager - .send_response(DataOrFin(Some(SignedBlockHeader { - block_header: BlockHeader { - block_hash: *block_hash, - block_header_without_hash: BlockHeaderWithoutHash { - block_number: BlockNumber(i.try_into().unwrap()), - ..Default::default() - }, - n_transactions: NUM_TRANSACTIONS_PER_BLOCK.try_into().unwrap(), - state_diff_length: Some(0), - ..Default::default() - }, - signatures: vec![*block_signature], - }))) - .await - .unwrap(); + const NUM_BLOCKS: u64 = 5; + const TRANSACTION_QUERY_LENGTH: u64 = 2; + + let mut rng = get_rng(); + + let block_bodies = (0..NUM_BLOCKS) + // TODO(shahak): remove Some(0) once we separate events from transactions correctly. + .map(|i| { + let mut body = get_test_body(i.try_into().unwrap(), Some(0), None, None); + // get_test_body returns transaction hash in the range 0..num_transactions. We want to + // avoid collisions in transaction hash. + for transaction_hash in &mut body.transaction_hashes { + *transaction_hash = TransactionHash(transaction_hash.0 + NUM_BLOCKS * i); + } + body + }) + .collect::>(); + + let mut actions = vec![ + Action::RunP2pSync, + // We already validate the header query content in other tests. + Action::ReceiveQuery(Box::new(|_query| ()), DataType::Header), + ]; + + // Sleep so transaction sync will reach the sleep waiting for header protocol to receive new + // data. + actions.push(Action::SleepToLetSyncAdvance); + // Send headers with corresponding transaction length + for (i, block_body) in block_bodies.iter().enumerate() { + actions.push(Action::SendHeader(DataOrFin(Some(random_header( + &mut rng, + BlockNumber(i.try_into().unwrap()), + None, + Some(block_body.transactions.len()), + ))))); + } + actions.push(Action::SendHeader(DataOrFin(None))); + + let len = block_bodies.len(); + // Wait for header sync to finish before continuing transaction sync. + actions.push(Action::CheckStorage(Box::new(move |reader| { + async move { + let block_number = BlockNumber(len.try_into().unwrap()); + wait_for_marker( + DataType::Header, + &reader, + block_number, + SLEEP_DURATION_TO_LET_SYNC_ADVANCE, + TIMEOUT_FOR_TEST, + ) + .await; + } + .boxed() + }))); + actions.push(Action::SimulateWaitPeriodForOtherProtocol); + + // Send transactions for each block and then validate they were written + for (i, BlockBody { transactions, transaction_outputs, transaction_hashes }) in + block_bodies.into_iter().enumerate() + { + let i = u64::try_from(i).unwrap(); + // If this block starts a new transaction query, receive the new query. + if i % TRANSACTION_QUERY_LENGTH == 0 { + let limit = min(TRANSACTION_QUERY_LENGTH, NUM_BLOCKS - i); + actions.push(Action::ReceiveQuery( + Box::new(move |query| { + assert_eq!( + query, + Query { + start_block: BlockHashOrNumber::Number(BlockNumber(i)), + direction: Direction::Forward, + limit, + step: 1, + } + ) + }), + DataType::Transaction, + )); } - wait_for_marker( - MarkerKind::Header, - &storage_reader, - BlockNumber(HEADER_QUERY_LENGTH), - SLEEP_DURATION_TO_LET_SYNC_ADVANCE, - TIMEOUT_FOR_TEST, - ) - .await; - - // Simulate time has passed so that transaction sync will resend query after it waited for - // new header - tokio::time::pause(); - tokio::time::advance(WAIT_PERIOD_FOR_NEW_DATA).await; - tokio::time::resume(); - - for start_block_number in - (0..HEADER_QUERY_LENGTH).step_by(TRANSACTION_QUERY_LENGTH.try_into().unwrap()) + for (transaction, (transaction_output, transaction_hash)) in transactions + .iter() + .cloned() + .zip(transaction_outputs.iter().cloned().zip(transaction_hashes.iter().cloned())) { - let num_blocks_in_query = - min(TRANSACTION_QUERY_LENGTH, HEADER_QUERY_LENGTH - start_block_number); - - // Receive query and validate it. - let mut mock_transaction_responses_manager = - mock_transaction_response_manager.next().await.unwrap(); - assert_eq!( - *mock_transaction_responses_manager.query(), - Ok(TransactionQuery(Query { - start_block: BlockHashOrNumber::Number(BlockNumber(start_block_number)), - direction: Direction::Forward, - limit: num_blocks_in_query, - step: 1, - })), - "If the limit of the query is too low, try to increase \ - SLEEP_DURATION_TO_LET_SYNC_ADVANCE", - ); - - for block_number in start_block_number..(start_block_number + num_blocks_in_query) { - let start_transaction_number = block_number * NUM_TRANSACTIONS_PER_BLOCK; - for transaction_number in start_transaction_number - ..(start_transaction_number + NUM_TRANSACTIONS_PER_BLOCK) - { - let transaction_idx = usize::try_from(transaction_number).unwrap(); - let transaction = transactions[transaction_idx].clone(); - let transaction_output = transaction_outputs[transaction_idx].clone(); - let transaction_hash = transaction_hashes[transaction_idx]; - - mock_transaction_responses_manager - .send_response(DataOrFin(Some(FullTransaction { - transaction, - transaction_output, - transaction_hash, - }))) - .await - .unwrap(); + // Check that before the last transaction was sent, the transactions aren't written. + actions.push(Action::CheckStorage(Box::new(move |reader| { + async move { + assert_eq!(i, reader.begin_ro_txn().unwrap().get_body_marker().unwrap().0); } + .boxed() + }))); + + actions.push(Action::SendTransaction(DataOrFin(Some(FullTransaction { + transaction, + transaction_output, + transaction_hash, + })))); + } - // Check responses were written to the storage. This way we make sure that the sync - // writes to the storage each response it receives before all query responses were - // sent. - let block_number = BlockNumber(block_number); + // Check that a block's transactions are written before the entire query finished. + actions.push(Action::CheckStorage(Box::new(move |reader| { + async move { + let block_number = BlockNumber(i); wait_for_marker( - MarkerKind::Body, - &storage_reader, + DataType::Transaction, + &reader, block_number.unchecked_next(), SLEEP_DURATION_TO_LET_SYNC_ADVANCE, TIMEOUT_FOR_TEST, ) .await; - let txn = storage_reader.begin_ro_txn().unwrap(); - - // TODO: Verify that the transaction outputs are equal aswell. currently is buggy. - let storage_transactions = + let txn = reader.begin_ro_txn().unwrap(); + let actual_transactions = txn.get_block_transactions(block_number).unwrap().unwrap(); - let storage_transaction_hashes = + // TODO(alonl): Uncomment this once we fix protobuf conversion for receipt + // builtins. + // let actual_transaction_outputs = + // txn.get_block_transaction_outputs(block_number).unwrap().unwrap(); + let actual_transaction_hashes = txn.get_block_transaction_hashes(block_number).unwrap().unwrap(); - for i in 0..NUM_TRANSACTIONS_PER_BLOCK { - let idx: usize = usize::try_from(i + start_transaction_number).unwrap(); - assert_eq!( - storage_transactions[usize::try_from(i).unwrap()], - transactions[idx] - ); - assert_eq!( - storage_transaction_hashes[usize::try_from(i).unwrap()], - transaction_hashes[idx] - ); - } + assert_eq!(actual_transactions, transactions); + // TODO(alonl): Uncomment this once we fix protobuf conversion for receipt + // builtins. + // assert_eq!(actual_transaction_outputs, transaction_outputs); + assert_eq!(actual_transaction_hashes, transaction_hashes); } + .boxed() + }))); - mock_transaction_responses_manager.send_response(DataOrFin(None)).await.unwrap(); - } - }; - - tokio::select! { - sync_result = p2p_sync.run() => { - sync_result.unwrap(); - panic!("P2P sync aborted with no failure."); + if (i + 1) % TRANSACTION_QUERY_LENGTH == 0 || i + 1 == NUM_BLOCKS { + actions.push(Action::SendTransaction(DataOrFin(None))); } - _ = parse_queries_future => {} } + + run_test( + HashMap::from([ + (DataType::Header, NUM_BLOCKS), + (DataType::Transaction, TRANSACTION_QUERY_LENGTH), + ]), + None, + actions, + ) + .await; } diff --git a/crates/papyrus_p2p_sync/src/server/mod.rs b/crates/papyrus_p2p_sync/src/server/mod.rs index 205a10239a4..0f4c6089ba8 100644 --- a/crates/papyrus_p2p_sync/src/server/mod.rs +++ b/crates/papyrus_p2p_sync/src/server/mod.rs @@ -1,5 +1,7 @@ use std::fmt::Debug; +use async_trait::async_trait; +use futures::never::Never; use futures::StreamExt; use papyrus_common::pending_classes::ApiContractClass; use papyrus_network::network_manager::{ServerQueryManager, SqmrServerReceiver}; @@ -20,15 +22,17 @@ use papyrus_protobuf::sync::{ TransactionQuery, }; use papyrus_storage::body::BodyStorageReader; -use papyrus_storage::class::ClassStorageReader; +use papyrus_storage::class_manager::ClassManagerStorageReader; use papyrus_storage::header::HeaderStorageReader; use papyrus_storage::state::StateStorageReader; use papyrus_storage::{db, StorageReader, StorageTxn}; use starknet_api::block::BlockNumber; +use starknet_api::contract_class::ContractClass; use starknet_api::core::ClassHash; use starknet_api::state::ThinStateDiff; use starknet_api::transaction::{Event, FullTransaction, TransactionHash}; -use tracing::{error, info}; +use starknet_class_manager_types::{ClassManagerClientError, SharedClassManagerClient}; +use tracing::{debug, error, info}; #[cfg(test)] mod test; @@ -36,12 +40,12 @@ mod test; mod utils; #[derive(thiserror::Error, Debug)] -pub enum P2PSyncServerError { +pub enum P2pSyncServerError { #[error(transparent)] DBInternalError(#[from] papyrus_storage::StorageError), #[error("Block number is out of range. Query: {query:?}, counter: {counter}")] BlockNumberOutOfRange { query: Query, counter: u64 }, - // TODO: add data type to the error message. + // TODO(Shahak): add data type to the error message. #[error("Block not found. Block: {block_hash_or_number:?}")] BlockNotFound { block_hash_or_number: BlockHashOrNumber }, #[error("Class not found. Class hash: {class_hash}")] @@ -49,18 +53,20 @@ pub enum P2PSyncServerError { // This error should be non recoverable. #[error(transparent)] JoinError(#[from] tokio::task::JoinError), - // TODO: remove this error, use BlockNotFound instead. + // TODO(Shahak): remove this error, use BlockNotFound instead. // This error should be non recoverable. #[error("Block {block_number:?} is in the storage but its signature isn't.")] SignatureNotFound { block_number: BlockNumber }, #[error(transparent)] SendError(#[from] futures::channel::mpsc::SendError), + #[error(transparent)] + ClassManagerClientError(#[from] ClassManagerClientError), } -impl P2PSyncServerError { +impl P2pSyncServerError { pub fn should_log_in_error_level(&self) -> bool { match self { - Self::JoinError(_) | Self::SignatureNotFound { .. } | Self::SendError { .. } + Self::JoinError(_) | Self::SignatureNotFound { .. } | Self::SendError { .. } | Self::ClassManagerClientError { .. } // TODO(shahak): Consider returning false for some of the StorageError variants. | Self::DBInternalError { .. } => true, Self::BlockNumberOutOfRange { .. } | Self::BlockNotFound { .. } | Self::ClassNotFound { .. } => false, @@ -74,7 +80,7 @@ type TransactionReceiver = SqmrServerReceiver>; type EventReceiver = SqmrServerReceiver>; -pub struct P2PSyncServerChannels { +pub struct P2pSyncServerChannels { header_receiver: HeaderReceiver, state_diff_receiver: StateDiffReceiver, transaction_receiver: TransactionReceiver, @@ -82,7 +88,7 @@ pub struct P2PSyncServerChannels { event_receiver: EventReceiver, } -impl P2PSyncServerChannels { +impl P2pSyncServerChannels { pub fn new( header_receiver: HeaderReceiver, state_diff_receiver: StateDiffReceiver, @@ -100,15 +106,16 @@ impl P2PSyncServerChannels { } } -/// A P2PSyncServer receives inbound queries and returns their corresponding data. -pub struct P2PSyncServer { +/// A P2pSyncServer receives inbound queries and returns their corresponding data. +pub struct P2pSyncServer { storage_reader: StorageReader, - p2p_sync_channels: P2PSyncServerChannels, + p2p_sync_channels: P2pSyncServerChannels, + class_manager_client: SharedClassManagerClient, } -impl P2PSyncServer { - pub async fn run(self) { - let P2PSyncServerChannels { +impl P2pSyncServer { + pub async fn run(self) -> Never { + let P2pSyncServerChannels { mut header_receiver, mut state_diff_receiver, mut transaction_receiver, @@ -121,54 +128,67 @@ impl P2PSyncServer { let server_query_manager = maybe_server_query_manager.expect( "Header queries sender was unexpectedly dropped." ); - register_query(self.storage_reader.clone(), server_query_manager); + register_query(self.storage_reader.clone(), server_query_manager, self.class_manager_client.clone(), "header"); } maybe_server_query_manager = state_diff_receiver.next() => { let server_query_manager = maybe_server_query_manager.expect( "State diff queries sender was unexpectedly dropped." ); - register_query(self.storage_reader.clone(), server_query_manager); + register_query(self.storage_reader.clone(), server_query_manager, self.class_manager_client.clone(), "state diff"); } maybe_server_query_manager = transaction_receiver.next() => { let server_query_manager = maybe_server_query_manager.expect( "Transaction queries sender was unexpectedly dropped." ); - register_query(self.storage_reader.clone(), server_query_manager); + register_query(self.storage_reader.clone(), server_query_manager, self.class_manager_client.clone(), "transaction"); } - mayber_server_query_manager = class_receiver.next() => { - let server_query_manager = mayber_server_query_manager.expect( + maybe_server_query_manager = class_receiver.next() => { + let server_query_manager = maybe_server_query_manager.expect( "Class queries sender was unexpectedly dropped." ); - register_query(self.storage_reader.clone(), server_query_manager); + register_query(self.storage_reader.clone(), server_query_manager, self.class_manager_client.clone(), "class"); } - mayber_server_query_manager = event_receiver.next() => { - let server_query_manager = mayber_server_query_manager.expect( + maybe_server_query_manager = event_receiver.next() => { + let server_query_manager = maybe_server_query_manager.expect( "Event queries sender was unexpectedly dropped." ); - register_query(self.storage_reader.clone(), server_query_manager); + register_query(self.storage_reader.clone(), server_query_manager, self.class_manager_client.clone(), "event"); } }; } } - pub fn new(storage_reader: StorageReader, p2p_sync_channels: P2PSyncServerChannels) -> Self { - Self { storage_reader, p2p_sync_channels } + pub fn new( + storage_reader: StorageReader, + p2p_sync_channels: P2pSyncServerChannels, + class_manager_client: SharedClassManagerClient, + ) -> Self { + Self { storage_reader, p2p_sync_channels, class_manager_client } } } fn register_query( storage_reader: StorageReader, server_query_manager: ServerQueryManager>, + class_manager_client: SharedClassManagerClient, + protocol_decription: &str, ) where - Data: FetchBlockDataFromDb + Send + 'static, + Data: FetchBlockData + Send + 'static, TQuery: TryFrom, Error = ProtobufConversionError> + Send + Clone + Debug + 'static, Query: From, { + let protocol_decription = protocol_decription.to_owned(); let query = server_query_manager.query().clone(); match query { Ok(query) => { - info!("Sync server received a new inbound query {query:?}"); + debug!("Sync server received a new inbound query {query:?}"); tokio::task::spawn(async move { - let result = send_data_for_query(storage_reader, server_query_manager).await; + let result = send_data_for_query( + storage_reader, + server_query_manager, + class_manager_client, + protocol_decription.as_str(), + ) + .await; if let Err(error) = result { if error.should_log_in_error_level() { error!("Running inbound query {query:?} failed on {error:?}"); @@ -186,27 +206,31 @@ fn register_query( } } -pub trait FetchBlockDataFromDb: Sized { - fn fetch_block_data_from_db( +#[async_trait] +pub trait FetchBlockData: Sized { + async fn fetch_block_data( block_number: BlockNumber, txn: &StorageTxn<'_, db::RO>, - ) -> Result, P2PSyncServerError>; + class_manager_client: &mut SharedClassManagerClient, + ) -> Result, P2pSyncServerError>; } -impl FetchBlockDataFromDb for SignedBlockHeader { - fn fetch_block_data_from_db( +#[async_trait] +impl FetchBlockData for SignedBlockHeader { + async fn fetch_block_data( block_number: BlockNumber, txn: &StorageTxn<'_, db::RO>, - ) -> Result, P2PSyncServerError> { + _class_manager_client: &mut SharedClassManagerClient, + ) -> Result, P2pSyncServerError> { let mut header = - txn.get_block_header(block_number)?.ok_or(P2PSyncServerError::BlockNotFound { + txn.get_block_header(block_number)?.ok_or(P2pSyncServerError::BlockNotFound { block_hash_or_number: BlockHashOrNumber::Number(block_number), })?; - // TODO(shahak) Remove this once central sync fills the state_diff_length field. + // TODO(shahak): Remove this once central sync fills the state_diff_length field. if header.state_diff_length.is_none() { header.state_diff_length = Some( txn.get_state_diff(block_number)? - .ok_or(P2PSyncServerError::BlockNotFound { + .ok_or(P2pSyncServerError::BlockNotFound { block_hash_or_number: BlockHashOrNumber::Number(block_number), })? .len(), @@ -214,40 +238,44 @@ impl FetchBlockDataFromDb for SignedBlockHeader { } let signature = txn .get_block_signature(block_number)? - .ok_or(P2PSyncServerError::SignatureNotFound { block_number })?; + .ok_or(P2pSyncServerError::SignatureNotFound { block_number })?; Ok(vec![SignedBlockHeader { block_header: header, signatures: vec![signature] }]) } } -impl FetchBlockDataFromDb for StateDiffChunk { - fn fetch_block_data_from_db( +#[async_trait] +impl FetchBlockData for StateDiffChunk { + async fn fetch_block_data( block_number: BlockNumber, txn: &StorageTxn<'_, db::RO>, - ) -> Result, P2PSyncServerError> { + _class_manager_client: &mut SharedClassManagerClient, + ) -> Result, P2pSyncServerError> { let thin_state_diff = - txn.get_state_diff(block_number)?.ok_or(P2PSyncServerError::BlockNotFound { + txn.get_state_diff(block_number)?.ok_or(P2pSyncServerError::BlockNotFound { block_hash_or_number: BlockHashOrNumber::Number(block_number), })?; Ok(split_thin_state_diff(thin_state_diff)) } } -impl FetchBlockDataFromDb for FullTransaction { - fn fetch_block_data_from_db( +#[async_trait] +impl FetchBlockData for FullTransaction { + async fn fetch_block_data( block_number: BlockNumber, txn: &StorageTxn<'_, db::RO>, - ) -> Result, P2PSyncServerError> { + _class_manager_client: &mut SharedClassManagerClient, + ) -> Result, P2pSyncServerError> { let transactions = - txn.get_block_transactions(block_number)?.ok_or(P2PSyncServerError::BlockNotFound { + txn.get_block_transactions(block_number)?.ok_or(P2pSyncServerError::BlockNotFound { block_hash_or_number: BlockHashOrNumber::Number(block_number), })?; let transaction_outputs = txn.get_block_transaction_outputs(block_number)?.ok_or( - P2PSyncServerError::BlockNotFound { + P2pSyncServerError::BlockNotFound { block_hash_or_number: BlockHashOrNumber::Number(block_number), }, )?; let transaction_hashes = txn.get_block_transaction_hashes(block_number)?.ok_or( - P2PSyncServerError::BlockNotFound { + P2pSyncServerError::BlockNotFound { block_hash_or_number: BlockHashOrNumber::Number(block_number), }, )?; @@ -264,52 +292,67 @@ impl FetchBlockDataFromDb for FullTransaction { } } -impl FetchBlockDataFromDb for (ApiContractClass, ClassHash) { - fn fetch_block_data_from_db( +#[async_trait] +impl FetchBlockData for (ApiContractClass, ClassHash) { + async fn fetch_block_data( block_number: BlockNumber, txn: &StorageTxn<'_, db::RO>, - ) -> Result, P2PSyncServerError> { + class_manager_client: &mut SharedClassManagerClient, + ) -> Result, P2pSyncServerError> { let thin_state_diff = - txn.get_state_diff(block_number)?.ok_or(P2PSyncServerError::BlockNotFound { + txn.get_state_diff(block_number)?.ok_or(P2pSyncServerError::BlockNotFound { block_hash_or_number: BlockHashOrNumber::Number(block_number), })?; + + if block_number >= txn.get_class_manager_block_marker()? { + return Err(P2pSyncServerError::BlockNotFound { + block_hash_or_number: BlockHashOrNumber::Number(block_number), + }); + } + let declared_classes = thin_state_diff.declared_classes; let deprecated_declared_classes = thin_state_diff.deprecated_declared_classes; let mut result = Vec::new(); - for class_hash in &deprecated_declared_classes { + for class_hash in deprecated_declared_classes { + let ContractClass::V0(deprecated_contract_class) = class_manager_client + .get_executable(class_hash) + .await? + .ok_or(P2pSyncServerError::ClassNotFound { class_hash })? + else { + panic!("Received a cairo1 contract, expected cairo0"); + }; result.push(( - ApiContractClass::DeprecatedContractClass( - txn.get_deprecated_class(class_hash)? - .ok_or(P2PSyncServerError::ClassNotFound { class_hash: *class_hash })?, - ), - *class_hash, + ApiContractClass::DeprecatedContractClass(deprecated_contract_class), + class_hash, )); } - for (class_hash, _) in &declared_classes { - result.push(( - ApiContractClass::ContractClass( - txn.get_class(class_hash)? - .ok_or(P2PSyncServerError::ClassNotFound { class_hash: *class_hash })?, - ), - *class_hash, - )); + + for (class_hash, _) in declared_classes { + let sierra = class_manager_client + .get_sierra(class_hash) + .await? + .ok_or(P2pSyncServerError::ClassNotFound { class_hash })?; + result.push((ApiContractClass::ContractClass(sierra), class_hash)); } + Ok(result) } } -impl FetchBlockDataFromDb for (Event, TransactionHash) { - fn fetch_block_data_from_db( +#[async_trait] +impl FetchBlockData for (Event, TransactionHash) { + async fn fetch_block_data( block_number: BlockNumber, txn: &StorageTxn<'_, db::RO>, - ) -> Result, P2PSyncServerError> { + _class_manager_client: &mut SharedClassManagerClient, + ) -> Result, P2pSyncServerError> { let transaction_outputs = txn.get_block_transaction_outputs(block_number)?.ok_or( - P2PSyncServerError::BlockNotFound { + P2pSyncServerError::BlockNotFound { block_hash_or_number: BlockHashOrNumber::Number(block_number), }, )?; let transaction_hashes = txn.get_block_transaction_hashes(block_number)?.ok_or( - P2PSyncServerError::BlockNotFound { + P2pSyncServerError::BlockNotFound { block_hash_or_number: BlockHashOrNumber::Number(block_number), }, )?; @@ -337,16 +380,11 @@ pub fn split_thin_state_diff(thin_state_diff: ThinStateDiff) -> Vec Vec( storage_reader: StorageReader, mut server_query_manager: ServerQueryManager>, -) -> Result<(), P2PSyncServerError> + mut class_manager_client: SharedClassManagerClient, + protocol_decription: &str, +) -> Result<(), P2pSyncServerError> where - Data: FetchBlockDataFromDb + Send + 'static, + Data: FetchBlockData + Send + 'static, TQuery: TryFrom, Error = ProtobufConversionError> + Clone, Query: From, { // If this function fails, we still want to send fin before failing. - let result = send_data_without_fin_for_query(&storage_reader, &mut server_query_manager).await; - info!("Sending fin message for inbound sync query"); + let result = send_data_without_fin_for_query( + &storage_reader, + &mut server_query_manager, + &mut class_manager_client, + protocol_decription, + ) + .await; + debug!("Sending fin message for inbound sync query"); server_query_manager.send_response(DataOrFin(None)).await?; result } @@ -389,9 +435,11 @@ where async fn send_data_without_fin_for_query( storage_reader: &StorageReader, server_query_manager: &mut ServerQueryManager>, -) -> Result<(), P2PSyncServerError> + class_manager_client: &mut SharedClassManagerClient, + protocol_decription: &str, +) -> Result<(), P2pSyncServerError> where - Data: FetchBlockDataFromDb + Send + 'static, + Data: FetchBlockData + Send + 'static, TQuery: TryFrom, Error = ProtobufConversionError> + Clone, Query: From, { @@ -404,7 +452,7 @@ where BlockHashOrNumber::Number(BlockNumber(num)) => num, BlockHashOrNumber::Hash(block_hash) => { txn.get_block_number_by_hash(&block_hash)? - .ok_or(P2PSyncServerError::BlockNotFound { + .ok_or(P2pSyncServerError::BlockNotFound { block_hash_or_number: BlockHashOrNumber::Hash(block_hash), })? .0 @@ -413,10 +461,13 @@ where for block_counter in 0..query.limit { let block_number = BlockNumber(utils::calculate_block_number(&query, start_block_number, block_counter)?); - let data_vec = Data::fetch_block_data_from_db(block_number, &txn)?; + let data_vec = Data::fetch_block_data(block_number, &txn, class_manager_client).await?; for data in data_vec { - // TODO: consider implement retry mechanism. - info!("Sending response for inbound sync query"); + // TODO(Shahak): consider implement retry mechanism. + info!( + "Sending response for inbound {protocol_decription} query for block \ + {block_number:?}" + ); server_query_manager.send_response(DataOrFin(Some(data))).await?; } } diff --git a/crates/papyrus_p2p_sync/src/server/test.rs b/crates/papyrus_p2p_sync/src/server/test.rs index 29f74535cf8..57a32e00d88 100644 --- a/crates/papyrus_p2p_sync/src/server/test.rs +++ b/crates/papyrus_p2p_sync/src/server/test.rs @@ -1,8 +1,10 @@ use std::fmt::Debug; +use std::sync::Arc; use futures::channel::mpsc::Sender; use futures::StreamExt; use lazy_static::lazy_static; +use mockall::predicate::eq; use papyrus_common::pending_classes::ApiContractClass; use papyrus_common::state::create_random_state_diff; use papyrus_network::network_manager::test_utils::{ @@ -25,7 +27,7 @@ use papyrus_protobuf::sync::{ TransactionQuery, }; use papyrus_storage::body::BodyStorageWriter; -use papyrus_storage::class::ClassStorageWriter; +use papyrus_storage::class_manager::ClassManagerStorageWriter; use papyrus_storage::header::{HeaderStorageReader, HeaderStorageWriter}; use papyrus_storage::state::StateStorageWriter; use papyrus_storage::test_utils::get_test_storage; @@ -40,6 +42,7 @@ use starknet_api::block::{ BlockNumber, BlockSignature, }; +use starknet_api::contract_class::ContractClass; use starknet_api::deprecated_contract_class::ContractClass as DeprecatedContractClass; use starknet_api::state::SierraContractClass; use starknet_api::transaction::{ @@ -49,8 +52,9 @@ use starknet_api::transaction::{ TransactionHash, TransactionOutput, }; +use starknet_class_manager_types::{MockClassManagerClient, SharedClassManagerClient}; -use super::{split_thin_state_diff, FetchBlockDataFromDb, P2PSyncServer, P2PSyncServerChannels}; +use super::{split_thin_state_diff, FetchBlockData, P2pSyncServer, P2pSyncServerChannels}; use crate::server::register_query; const BUFFER_SIZE: usize = 10; const NUM_OF_BLOCKS: usize = 10; @@ -312,7 +316,7 @@ async fn run_test( start_block_number: usize, start_block_type: StartBlockType, ) where - T: FetchBlockDataFromDb + std::fmt::Debug + PartialEq + Send + Sync + 'static, + T: FetchBlockData + std::fmt::Debug + PartialEq + Send + Sync + 'static, F: FnOnce(Vec), TQuery: From + TryFrom, Error = ProtobufConversionError> @@ -326,16 +330,12 @@ async fn run_test( let TestArgs { p2p_sync_server, storage_reader, - mut storage_writer, header_sender: _header_sender, state_diff_sender: _state_diff_sender, transaction_sender: _transaction_sender, class_sender: _class_sender, event_sender: _event_sender, - } = setup(); - - // put some data in the storage. - insert_to_storage_test_blocks_up_to(&mut storage_writer); + } = setup_sync_server_and_storage(); let block_number = BlockNumber(start_block_number.try_into().unwrap()); let start_block = match start_block_type { @@ -361,17 +361,23 @@ async fn run_test( let query = TQuery::from(query); let (server_query_manager, _report_sender, response_reciever) = create_test_server_query_manager(query); - register_query::(storage_reader, server_query_manager); + + register_query::( + storage_reader, + server_query_manager, + p2p_sync_server.class_manager_client.clone(), + "test", + ); // run p2p_sync_server and collect query results. tokio::select! { - _ = p2p_sync_server.run() => { - panic!("p2p_sync_server should never finish its run."); + _never = p2p_sync_server.run() => { + unreachable!("Return type Never should never be constructed"); }, mut res = response_reciever.collect::>() => { assert_eq!(DataOrFin(None), res.pop().unwrap()); let filtered_res: Vec = res.into_iter() - .map(|data| data.0.expect("P2PSyncServer returned Fin and then returned another response")) + .map(|data| data.0.expect("P2pSyncServer returned Fin and then returned another response")) .collect(); assert_fn(filtered_res); } @@ -380,9 +386,8 @@ async fn run_test( pub struct TestArgs { #[allow(clippy::type_complexity)] - pub p2p_sync_server: P2PSyncServer, + pub p2p_sync_server: P2pSyncServer, pub storage_reader: StorageReader, - pub storage_writer: StorageWriter, pub header_sender: Sender>>, pub state_diff_sender: Sender>>, pub transaction_sender: @@ -393,15 +398,22 @@ pub struct TestArgs { } #[allow(clippy::type_complexity)] -fn setup() -> TestArgs { - let ((storage_reader, storage_writer), _temp_dir) = get_test_storage(); +fn setup_sync_server_and_storage() -> TestArgs { + let ((storage_reader, mut storage_writer), _temp_dir) = get_test_storage(); + + // put some data in the storage. + insert_to_storage_test_blocks_up_to(&mut storage_writer); + + // put classes into class manager and update marker in storage + let class_manager_client = create_mock_class_manager_with_blocks_up_to(&mut storage_writer); + let (header_receiver, header_sender) = mock_register_sqmr_protocol_server(BUFFER_SIZE); let (state_diff_receiver, state_diff_sender) = mock_register_sqmr_protocol_server(BUFFER_SIZE); let (transaction_receiver, transaction_sender) = mock_register_sqmr_protocol_server(BUFFER_SIZE); let (class_receiver, class_sender) = mock_register_sqmr_protocol_server(BUFFER_SIZE); let (event_receiver, event_sender) = mock_register_sqmr_protocol_server(BUFFER_SIZE); - let p2p_sync_server_channels = P2PSyncServerChannels { + let p2p_sync_server_channels = P2pSyncServerChannels { header_receiver, state_diff_receiver, transaction_receiver, @@ -409,12 +421,14 @@ fn setup() -> TestArgs { event_receiver, }; - let p2p_sync_server = - super::P2PSyncServer::new(storage_reader.clone(), p2p_sync_server_channels); + let p2p_sync_server = super::P2pSyncServer::new( + storage_reader.clone(), + p2p_sync_server_channels, + class_manager_client, + ); TestArgs { p2p_sync_server, storage_reader, - storage_writer, header_sender, state_diff_sender, transaction_sender, @@ -422,6 +436,7 @@ fn setup() -> TestArgs { event_sender, } } + use starknet_api::core::ClassHash; fn insert_to_storage_test_blocks_up_to(storage_writer: &mut StorageWriter) { for i in 0..NUM_OF_BLOCKS { @@ -434,14 +449,6 @@ fn insert_to_storage_test_blocks_up_to(storage_writer: &mut StorageWriter) { }, ..Default::default() }; - let classes_with_hashes = CLASSES_WITH_HASHES[i] - .iter() - .map(|(class_hash, contract_class)| (*class_hash, contract_class)) - .collect::>(); - let deprecated_classes_with_hashes = DEPRECATED_CLASSES_WITH_HASHES[i] - .iter() - .map(|(class_hash, contract_class)| (*class_hash, contract_class)) - .collect::>(); storage_writer .begin_rw_txn() .unwrap() @@ -456,11 +463,52 @@ fn insert_to_storage_test_blocks_up_to(storage_writer: &mut StorageWriter) { .append_body(block_number, BlockBody{transactions: TXS[i].clone(), transaction_outputs: TX_OUTPUTS[i].clone(), transaction_hashes: TX_HASHES[i].clone(),}).unwrap() - .append_classes(block_number, &classes_with_hashes, &deprecated_classes_with_hashes) + .commit() + .unwrap(); + } +} + +// TODO(shahak): test undeclared class flow (when class manager client returns None). +fn create_mock_class_manager_with_blocks_up_to( + storage_writer: &mut StorageWriter, +) -> SharedClassManagerClient { + let mut class_manager_client = MockClassManagerClient::new(); + for i in 0..NUM_OF_BLOCKS { + let block_number = BlockNumber(i.try_into().unwrap()); + let classes_with_hashes = CLASSES_WITH_HASHES[i] + .iter() + .map(|(class_hash, contract_class)| (*class_hash, contract_class)) + .collect::>(); + + for (class_hash, contract_class) in classes_with_hashes { + class_manager_client + .expect_get_sierra() + .with(eq(class_hash)) + .returning(|_| Ok(Some(contract_class.clone()))); + } + + let deprecated_classes_with_hashes = DEPRECATED_CLASSES_WITH_HASHES[i] + .iter() + .map(|(class_hash, contract_class)| (*class_hash, contract_class)) + .collect::>(); + + for (class_hash, contract_class) in deprecated_classes_with_hashes { + // TODO(shahak): test the case where class manager client returned error. + class_manager_client + .expect_get_executable() + .with(eq(class_hash)) + .returning(|_| Ok(Some(ContractClass::V0(contract_class.clone())))); + } + + storage_writer + .begin_rw_txn() + .unwrap() + .update_class_manager_block_marker(&block_number.unchecked_next()) .unwrap() .commit() .unwrap(); } + Arc::new(class_manager_client) } lazy_static! { diff --git a/crates/papyrus_p2p_sync/src/server/utils.rs b/crates/papyrus_p2p_sync/src/server/utils.rs index 528fec6238a..8320be62e70 100644 --- a/crates/papyrus_p2p_sync/src/server/utils.rs +++ b/crates/papyrus_p2p_sync/src/server/utils.rs @@ -1,12 +1,12 @@ use papyrus_protobuf::sync::{Direction, Query}; -use super::P2PSyncServerError; +use super::P2pSyncServerError; pub(crate) fn calculate_block_number( query: &Query, start_block: u64, read_blocks_counter: u64, -) -> Result { +) -> Result { let direction_factor: i128 = match query.direction { Direction::Forward => 1, Direction::Backward => -1, @@ -15,7 +15,7 @@ pub(crate) fn calculate_block_number( let blocks_delta: i128 = direction_factor * i128::from(query.step * read_blocks_counter); let block_number: i128 = i128::from(start_block) + blocks_delta; - u64::try_from(block_number).map_err(|_| P2PSyncServerError::BlockNumberOutOfRange { + u64::try_from(block_number).map_err(|_| P2pSyncServerError::BlockNumberOutOfRange { query: query.clone(), counter: read_blocks_counter, }) diff --git a/crates/papyrus_proc_macros/Cargo.toml b/crates/papyrus_proc_macros/Cargo.toml index e2471eb39d1..b082bc2e1d8 100644 --- a/crates/papyrus_proc_macros/Cargo.toml +++ b/crates/papyrus_proc_macros/Cargo.toml @@ -17,6 +17,9 @@ metrics-exporter-prometheus.workspace = true papyrus_common.workspace = true papyrus_test_utils.workspace = true prometheus-parse.workspace = true +rstest.workspace = true +starknet_monitoring_endpoint.workspace = true +starknet_sequencer_metrics.workspace = true [lib] proc-macro = true diff --git a/crates/papyrus_proc_macros/src/lib.rs b/crates/papyrus_proc_macros/src/lib.rs index 91a1c0a4e03..1ff196e32c9 100644 --- a/crates/papyrus_proc_macros/src/lib.rs +++ b/crates/papyrus_proc_macros/src/lib.rs @@ -1,11 +1,11 @@ -use std::str::FromStr; - use proc_macro::TokenStream; use quote::{quote, ToTokens}; -use syn::parse::{Parse, ParseStream, Result}; +use syn::parse::{Parse, ParseStream}; use syn::{ + parse, + parse2, parse_macro_input, - DeriveInput, + parse_str, ExprLit, Ident, ItemFn, @@ -133,42 +133,134 @@ pub fn versioned_rpc(attr: TokenStream, input: TokenStream) -> TokenStream { /// since the config value is false. #[proc_macro_attribute] pub fn latency_histogram(attr: TokenStream, input: TokenStream) -> TokenStream { - let mut input_fn = parse_macro_input!(input as ItemFn); - let parts = attr - .to_string() - .split(',') - .map(|s| { - TokenStream::from_str(s) - .expect("Expecting metric name and bool (is for profiling only)") - }) - .collect::>(); - let metric_name_as_tokenstream = parts + let (metric_name, control_with_config, input_fn) = parse_latency_histogram_attributes::( + attr, + input, + "Expecting a string literal for metric name", + ); + + // TODO(DanB): consider naming the input value instead of providing a bool + // TODO(DanB): consider adding support for metrics levels (e.g. debug, info, warn, error) + // instead of boolean + + let metric_recording_logic = quote! { + ::metrics::histogram!(#metric_name).record(exec_time); + }; + + let collect_metric_flag = quote! { + papyrus_common::metrics::COLLECT_PROFILING_METRICS + }; + + create_modified_function( + metric_name, + control_with_config, + input_fn, + metric_recording_logic, + collect_metric_flag, + ) +} + +/// This macro will emit a histogram metric with the given name and the latency of the function. +/// In addition, also a debug log with the metric name and the execution time will be emitted. +/// The macro also receives a boolean for whether it will be emitted only when +/// profiling is activated or at all times. +/// +/// # Example +/// Given this code: +/// +/// ```rust,ignore +/// use starknet_sequencer_metrics::metrics::{MetricHistogram, MetricScope}; +/// +/// const FOO_HISTOGRAM_METRIC: MetricHistogram = MetricHistogram::new( +/// MetricScope::Infra, +/// "foo_histogram_metric", +/// "foo function latency histogram metrics", +/// ); +/// +/// #[sequencer_latency_histogram(FOO_HISTOGRAM_METRIC, false)] +/// fn foo() { +/// // Some code ... +/// } +/// ``` +/// Every call to foo will update the histogram metric FOO_HISTOGRAM_METRIC with the time it +/// took to execute foo. In addition, a debug log with the following format will be emitted: +/// “: ” +/// The metric will be emitted regardless of the value of the profiling configuration, +/// since the config value is false. +#[proc_macro_attribute] +pub fn sequencer_latency_histogram(attr: TokenStream, input: TokenStream) -> TokenStream { + let (metric_name, control_with_config, input_fn) = parse_latency_histogram_attributes::( + attr, + input, + "Expecting an identifier for metric name", + ); + + let metric_recording_logic = quote! { + #metric_name.record(exec_time); + }; + + let collect_metric_flag = quote! { + starknet_sequencer_metrics::metrics::COLLECT_SEQUENCER_PROFILING_METRICS + }; + + create_modified_function( + metric_name, + control_with_config, + input_fn, + metric_recording_logic, + collect_metric_flag, + ) +} + +/// Helper function to parse the attributes and input for the latency histogram macros. +fn parse_latency_histogram_attributes( + attr: TokenStream, + input: TokenStream, + err_msg: &str, +) -> (T, LitBool, ItemFn) { + let binding = attr.to_string(); + let parts: Vec<&str> = binding.split(',').collect(); + let metric_name_string = parts .first() - .expect("attribute should include metric name and controll with config boolean") - .clone(); - // TODO: consider naming the input value instead of providing a bool - // TODO: consider adding support for metrics levels (e.g. debug, info, warn, error) instead of - // boolean - let controll_with_config_as_tokenstream = parts + .expect("attribute should include metric name and control with config boolean") + .trim() + .to_string(); + let control_with_config_string = parts .get(1) - .expect("attribute should include metric name and controll with config boolean") - .clone(); - let metric_name = parse_macro_input!(metric_name_as_tokenstream as ExprLit); - let controll_with_config = parse_macro_input!(controll_with_config_as_tokenstream as LitBool); - let origin_block = &mut input_fn.block; + .expect("attribute should include metric name and control with config boolean") + .trim() + .to_string(); + let control_with_config = parse_str::(&control_with_config_string) + .expect("Expecting a boolean value for control with config"); + let metric_name = parse_str::(&metric_name_string).expect(err_msg); + + let input_fn = parse::(input).expect("Failed to parse input as ItemFn"); + + (metric_name, control_with_config, input_fn) +} + +/// Helper function to create the expanded block and modified function. +fn create_modified_function( + metric_name: impl ToTokens, + control_with_config: LitBool, + input_fn: ItemFn, + metric_recording_logic: impl ToTokens, + collect_metric_flag: impl ToTokens, +) -> TokenStream { // Create a new block with the metric update. + let origin_block = &input_fn.block; let expanded_block = quote! { { let mut start_function_time = None; - if !#controll_with_config || (#controll_with_config && *(papyrus_common::metrics::COLLECT_PROFILING_METRICS.get().unwrap_or(&false))) { - start_function_time=Some(std::time::Instant::now()); + if !#control_with_config || (#control_with_config && *(#collect_metric_flag.get().unwrap_or(&false))) { + start_function_time = Some(std::time::Instant::now()); } - let return_value=#origin_block; + let return_value = #origin_block; if let Some(start_time) = start_function_time { let exec_time = start_time.elapsed().as_secs_f64(); - metrics::histogram!(#metric_name, exec_time); - tracing::debug!("{}: {}", #metric_name, exec_time); + #metric_recording_logic + tracing::debug!("{}: {}", stringify!(#metric_name), exec_time); } return_value } @@ -176,57 +268,86 @@ pub fn latency_histogram(attr: TokenStream, input: TokenStream) -> TokenStream { // Create a new function with the modified block. let modified_function = ItemFn { - block: syn::parse2(expanded_block).expect("Parse tokens in latency_histogram attribute."), + block: parse2(expanded_block).expect("Parse tokens in latency_histogram attribute."), ..input_fn }; modified_function.to_token_stream().into() } -struct HandleResponseVariantsMacroInput { +struct HandleAllResponseVariantsMacroInput { response_enum: Ident, request_response_enum_var: Ident, component_client_error: Ident, component_error: Ident, + response_type: Ident, } -impl Parse for HandleResponseVariantsMacroInput { - fn parse(input: ParseStream<'_>) -> Result { - let response_enum = input.parse()?; +impl Parse for HandleAllResponseVariantsMacroInput { + fn parse(input: ParseStream<'_>) -> syn::Result { + let response_enum: Ident = input.parse()?; + input.parse::()?; + let request_response_enum_var: Ident = input.parse()?; input.parse::()?; - let request_response_enum_var = input.parse()?; + let component_client_error: Ident = input.parse()?; input.parse::()?; - let component_client_error = input.parse()?; + let component_error: Ident = input.parse()?; input.parse::()?; - let component_error = input.parse()?; - Ok(HandleResponseVariantsMacroInput { + let response_type: Ident = input.parse()?; + + Ok(HandleAllResponseVariantsMacroInput { response_enum, request_response_enum_var, component_client_error, component_error, + response_type, }) } } -/// A macro for generating code that handles the received communication response. +/// A macro for generating code that sends the request and handles the received response. /// Takes the following arguments: /// * response_enum -- the response enum type /// * request_response_enum_var -- the request/response enum variant corresponding to the invoked /// function /// * component_client_error -- the component client error type /// * component_error -- the component error type +/// * response_type -- Boxed or Direct, a string literal indicating if the response content is boxed +/// or not /// -/// For example, the following code: +/// For example, use of the Direct response_type: /// ```rust,ignore -/// handle_response_variants!(MempoolResponse, GetTransactions, MempoolClientError, MempoolError) -/// `````` +/// handle_all_response_variants!(MempoolResponse, GetTransactions, MempoolClientError, MempoolError, Direct) +/// ``` /// /// Results in: /// ```rust,ignore -/// match response { -/// MempoolResponse::GetTransactions(Ok(response)) => Ok(response), -/// MempoolResponse::GetTransactions(Err(response)) => { -/// Err(MempoolClientError::MempoolError(response)) +/// let response = self.send(request).await; +/// match response? { +/// MempoolResponse::GetTransactions(Ok(resp)) => Ok(resp), +/// MempoolResponse::GetTransactions(Err(resp)) => { +/// Err(MempoolClientError::MempoolError(resp)) +/// } +/// unexpected_response => Err(MempoolClientError::ClientError( +/// ClientError::UnexpectedResponse(format!("{unexpected_response:?}")), +/// )), +/// } +/// ``` +/// Use of the Boxed response_type: +/// ```rust,ignore +/// handle_all_response_variants!(MempoolResponse, GetTransactions, MempoolClientError, MempoolError, Boxed) +/// ``` +/// +/// Results in: +/// ```rust,ignore +/// let response = self.send(request).await; +/// match response? { +/// MempoolResponse::GetTransactions(Ok(boxed_resp)) => { +/// let resp = *boxed_resp; +/// Ok(resp) +/// } +/// MempoolResponse::GetTransactions(Err(resp)) => { +/// Err(MempoolClientError::MempoolError(resp)) /// } /// unexpected_response => Err(MempoolClientError::ClientError( /// ClientError::UnexpectedResponse(format!("{unexpected_response:?}")), @@ -234,74 +355,42 @@ impl Parse for HandleResponseVariantsMacroInput { /// } /// ``` #[proc_macro] -pub fn handle_response_variants(input: TokenStream) -> TokenStream { - let HandleResponseVariantsMacroInput { +pub fn handle_all_response_variants(input: TokenStream) -> TokenStream { + let HandleAllResponseVariantsMacroInput { response_enum, request_response_enum_var, component_client_error, component_error, - } = parse_macro_input!(input as HandleResponseVariantsMacroInput); + response_type, + } = parse_macro_input!(input as HandleAllResponseVariantsMacroInput); - let expanded = quote! { - match response? { - #response_enum::#request_response_enum_var(Ok(response)) => Ok(response), - #response_enum::#request_response_enum_var(Err(response)) => { - Err(#component_client_error::#component_error(response)) + let mut expanded = match response_type.to_string().as_str() { + "Boxed" => quote! { + { + // Dereference the Box to get the response value + let resp = *resp; + Ok(resp) } - unexpected_response => Err(#component_client_error::ClientError(ClientError::UnexpectedResponse(format!("{unexpected_response:?}")))), - } - }; - - TokenStream::from(expanded) -} - -/// This macro generates a `pub fn field_names() -> Vec`, a method that returns a vector of -/// the struct field element names. -/// -/// # Example -/// ```rust -/// use papyrus_proc_macros::gen_field_names_fn; -/// -/// #[gen_field_names_fn] -/// pub struct Example { -/// pub field_a: u8, -/// field_b: u32, -/// pub field_c: String, -/// } -/// -/// assert_eq!(Example::field_names(), vec!["field_a", "field_b", "field_c"]); -/// ``` -#[proc_macro_attribute] -pub fn gen_field_names_fn(_attr: TokenStream, item: TokenStream) -> TokenStream { - // Parse the input tokens as a Rust struct - let input = parse_macro_input!(item as DeriveInput); - - // Get the struct name - let struct_name = &input.ident; - - // Collect the names of the struct's fields as string literals - let field_names = if let syn::Data::Struct(data) = &input.data { - data.fields - .iter() - .filter_map(|field| field.ident.as_ref()) - .map(|ident| ident.to_string()) - .collect::>() - } else { - panic!("#[gen_field_names_fn] can only be used on structs"); + }, + "Direct" => quote! { + Ok(resp), + }, + _ => panic!("Expected 'Boxed' or 'Direct'"), }; - // Generate the field_names method - let gen = quote! { - #input - - impl #struct_name { - pub fn field_names() -> Vec { - vec![ - #(#field_names.to_string()),* - ] + expanded = quote! { + { + let response = self.send(request).await; + match response? { + #response_enum::#request_response_enum_var(Ok(resp)) => + #expanded + #response_enum::#request_response_enum_var(Err(resp)) => { + Err(#component_client_error::#component_error(resp)) + } + unexpected_response => Err(#component_client_error::ClientError(ClientError::UnexpectedResponse(format!("{unexpected_response:?}")))), } } }; - gen.into() + TokenStream::from(expanded) } diff --git a/crates/papyrus_proc_macros/tests/latency_histogram.rs b/crates/papyrus_proc_macros/tests/latency_histogram.rs index f4415c2b59f..fdd384c0c3e 100644 --- a/crates/papyrus_proc_macros/tests/latency_histogram.rs +++ b/crates/papyrus_proc_macros/tests/latency_histogram.rs @@ -1,40 +1,94 @@ +use std::sync::OnceLock; + +use metrics::set_default_local_recorder; use metrics_exporter_prometheus::PrometheusBuilder; use papyrus_common::metrics::COLLECT_PROFILING_METRICS; -use papyrus_proc_macros::latency_histogram; +use papyrus_proc_macros::{latency_histogram, sequencer_latency_histogram}; use papyrus_test_utils::prometheus_is_contained; use prometheus_parse::Value::Untyped; +use rstest::rstest; +use starknet_sequencer_metrics::metrics::{ + MetricHistogram, + MetricScope, + COLLECT_SEQUENCER_PROFILING_METRICS, +}; + +const FOO_HISTOGRAM_TEST_METRIC: MetricHistogram = MetricHistogram::new( + MetricScope::Infra, + "foo_histogram_test_metric", + "foo function latency histogram test metrics", +); + +const BAR_HISTOGRAM_TEST_METRIC: MetricHistogram = MetricHistogram::new( + MetricScope::Infra, + "bar_histogram_test_metric", + "bar function latency histogram test metrics", +); -#[test] -fn latency_histogram_test() { - COLLECT_PROFILING_METRICS.set(false).unwrap(); +type TestFn = fn() -> usize; - #[latency_histogram("foo_histogram", false)] - fn foo() -> usize { - #[allow(clippy::let_and_return)] - let start_function_time = 1000; - start_function_time - } +#[latency_histogram("foo_histogram", false)] +fn foo_for_papyrus_macro() -> usize { + #[allow(clippy::let_and_return)] + let start_function_time = 1000; + start_function_time +} - #[latency_histogram("bar_histogram", true)] - fn bar() -> usize { - #[allow(clippy::let_and_return)] - let start_function_time = 1000; - start_function_time - } +#[latency_histogram("bar_histogram", true)] +fn bar_for_papyrus_macro() -> usize { + #[allow(clippy::let_and_return)] + let start_function_time = 1000; + start_function_time +} - let handle = PrometheusBuilder::new().install_recorder().unwrap(); +#[sequencer_latency_histogram(FOO_HISTOGRAM_TEST_METRIC, false)] +fn foo_for_sequencer_macro() -> usize { + #[allow(clippy::let_and_return)] + let start_function_time = 1000; + start_function_time +} + +#[sequencer_latency_histogram(BAR_HISTOGRAM_TEST_METRIC, true)] +fn bar_for_sequencer_macro() -> usize { + #[allow(clippy::let_and_return)] + let start_function_time = 1000; + start_function_time +} + +#[rstest] +#[case::latency_histogram( + &COLLECT_PROFILING_METRICS, + foo_for_papyrus_macro, + bar_for_papyrus_macro, + "foo_histogram_count", + "foo_histogram_sum" +)] +#[case::sequencer_latency_histogram( + &COLLECT_SEQUENCER_PROFILING_METRICS, + foo_for_sequencer_macro, + bar_for_sequencer_macro, + FOO_HISTOGRAM_TEST_METRIC.get_name().to_string() + "_count", + FOO_HISTOGRAM_TEST_METRIC.get_name().to_string() + "_sum" +)] +fn latency_histogram_test( + #[case] global_flag: &OnceLock, + #[case] foo: TestFn, + #[case] bar: TestFn, + #[case] count_metric: String, + #[case] sum_metric: String, +) { + global_flag.set(false).unwrap(); + + let recorder = PrometheusBuilder::new().build_recorder(); + let _recorder_guard = set_default_local_recorder(&recorder); + let handle = recorder.handle(); assert!(handle.render().is_empty()); assert_eq!(bar(), 1000); assert!(handle.render().is_empty()); assert_eq!(foo(), 1000); - assert_eq!( - prometheus_is_contained(handle.render(), "foo_histogram_count", &[]), - Some(Untyped(1f64)) - ); + + assert_eq!(prometheus_is_contained(handle.render(), &count_metric, &[]), Some(Untyped(1f64))); // Test that the "start_function_time" variable from the macro is not shadowed. - assert_ne!( - prometheus_is_contained(handle.render(), "foo_histogram_sum", &[]), - Some(Untyped(1000f64)) - ); + assert_ne!(prometheus_is_contained(handle.render(), &sum_metric, &[]), Some(Untyped(1000f64))); } diff --git a/crates/papyrus_protobuf/Cargo.toml b/crates/papyrus_protobuf/Cargo.toml index 071928db6f1..c3df82e251b 100644 --- a/crates/papyrus_protobuf/Cargo.toml +++ b/crates/papyrus_protobuf/Cargo.toml @@ -7,10 +7,15 @@ license-file.workspace = true [features] testing = ["papyrus_test_utils", "rand", "rand_chacha"] +bin-deps = ["prost-build", "protoc-prebuilt"] + +[[bin]] +name = "generate_protoc_output" +path = "src/bin/generate_protoc_output.rs" +required-features = ["bin-deps"] [dependencies] -# TODO(Guy): Remove after implementing broadcast streams. -futures.workspace = true +bytes.workspace = true indexmap.workspace = true lazy_static.workspace = true primitive-types.workspace = true @@ -23,14 +28,18 @@ starknet_api.workspace = true starknet-types-core.workspace = true papyrus_test_utils = { workspace = true, optional = true } thiserror.workspace = true +tracing.workspace = true papyrus_common.workspace = true +# Binaries dependencies +prost-build = { workspace = true, optional = true } +protoc-prebuilt = { workspace = true, optional = true } + [dev-dependencies] rand.workspace = true rand_chacha.workspace = true papyrus_test_utils.workspace = true - -[build-dependencies] +tempfile.workspace = true prost-build.workspace = true protoc-prebuilt.workspace = true diff --git a/crates/papyrus_protobuf/src/bin/generate_protoc_output.rs b/crates/papyrus_protobuf/src/bin/generate_protoc_output.rs new file mode 100644 index 00000000000..58c056b0126 --- /dev/null +++ b/crates/papyrus_protobuf/src/bin/generate_protoc_output.rs @@ -0,0 +1,31 @@ +use std::fs; +use std::path::Path; + +use papyrus_protobuf::regression_test_utils::{ + generate_protos, + PROTOC_OUTPUT, + PROTO_DIR, + PROTO_FILES, +}; + +fn main() { + let out_dir = String::from("crates/papyrus_protobuf/") + PROTO_DIR; + + generate_protos(out_dir.clone().into(), PROTO_FILES).unwrap(); + + // TODO(alonl): Consider using tonic_build to allow naming the file directly instead of renaming + // here + fs::rename(Path::new(&out_dir).join("_.rs"), Path::new(&out_dir).join(PROTOC_OUTPUT)).unwrap(); + + for file in fs::read_dir(out_dir).unwrap() { + let file = file.unwrap(); + let file_name = file.file_name().into_string().unwrap(); + if file_name != PROTOC_OUTPUT { + if file.path().is_file() { + fs::remove_file(file.path()).unwrap(); + } else { + fs::remove_dir_all(file.path()).unwrap(); + } + } + } +} diff --git a/crates/papyrus_protobuf/src/consensus.rs b/crates/papyrus_protobuf/src/consensus.rs index 894b035b5ea..743b6fc58a3 100644 --- a/crates/papyrus_protobuf/src/consensus.rs +++ b/crates/papyrus_protobuf/src/consensus.rs @@ -1,19 +1,18 @@ -use futures::channel::{mpsc, oneshot}; +use std::fmt::Display; + +use bytes::{Buf, BufMut}; +use prost::DecodeError; use starknet_api::block::{BlockHash, BlockNumber}; +use starknet_api::consensus_transaction::ConsensusTransaction; use starknet_api::core::ContractAddress; -use starknet_api::executable_transaction::Transaction as ExecutableTransaction; -use starknet_api::transaction::{Transaction, TransactionHash}; +use starknet_api::data_availability::L1DataAvailabilityMode; use crate::converters::ProtobufConversionError; -#[derive(Debug, Default, Hash, Clone, Eq, PartialEq)] -pub struct Proposal { - pub height: u64, - pub round: u32, - pub proposer: ContractAddress, - pub transactions: Vec, - pub block_hash: BlockHash, - pub valid_round: Option, +pub trait IntoFromProto: Into> + TryFrom, Error = ProtobufConversionError> {} +impl IntoFromProto for T where + T: Into> + TryFrom, Error = ProtobufConversionError> +{ } #[derive(Debug, Default, Hash, Clone, Eq, PartialEq)] @@ -32,21 +31,6 @@ pub struct Vote { pub voter: ContractAddress, } -#[derive(Debug, Clone, Hash, Eq, PartialEq)] -pub enum ConsensusMessage { - Proposal(Proposal), - Vote(Vote), -} - -impl ConsensusMessage { - pub fn height(&self) -> u64 { - match self { - ConsensusMessage::Proposal(proposal) => proposal.height, - ConsensusMessage::Vote(vote) => vote.height, - } - } -} - #[derive(Debug, Clone, Hash, Eq, PartialEq)] pub enum StreamMessageBody { Content(T), @@ -54,14 +38,14 @@ pub enum StreamMessageBody { } #[derive(Debug, Clone, Hash, Eq, PartialEq)] -pub struct StreamMessage> + TryFrom, Error = ProtobufConversionError>> { +pub struct StreamMessage { pub message: StreamMessageBody, - pub stream_id: u64, + pub stream_id: StreamId, pub message_id: u64, } /// This message must be sent first when proposing a new block. -#[derive(Default, Debug, Clone, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq)] pub struct ProposalInit { /// The height of the consensus (block number). pub height: BlockNumber, @@ -73,22 +57,50 @@ pub struct ProposalInit { pub proposer: ContractAddress, } +/// This struct differs from `BlockInfo` in `starknet_api` because we send L1 gas prices in ETH and +/// include the ETH to STRK conversion rate. This allows for more informative validations, as we can +/// distinguish whether an issue comes from the L1 price reading or the conversion rate instead of +/// comparing after multiplication. +#[derive(Clone, Debug, PartialEq)] +pub struct ConsensusBlockInfo { + pub height: BlockNumber, + pub timestamp: u64, + pub builder: ContractAddress, + pub l1_da_mode: L1DataAvailabilityMode, + pub l2_gas_price_fri: u128, + pub l1_gas_price_wei: u128, + pub l1_data_gas_price_wei: u128, + pub eth_to_fri_rate: u128, +} + +/// A temporary constant to use as a validator ID. Zero is not a valid contract address. +// TODO(Matan): Remove this once we have a proper validator set. +pub const DEFAULT_VALIDATOR_ID: u64 = 100; + +impl Default for ProposalInit { + fn default() -> Self { + ProposalInit { + height: Default::default(), + round: Default::default(), + valid_round: Default::default(), + proposer: ContractAddress::from(DEFAULT_VALIDATOR_ID), + } + } +} + /// There is one or more batches of transactions in a proposed block. #[derive(Debug, Clone, PartialEq)] pub struct TransactionBatch { /// The transactions in the batch. - pub transactions: Vec, - // TODO(guyn): remove this once we settle how to convert transactions to ExecutableTransactions - /// The hashes of each transaction. - pub tx_hashes: Vec, + pub transactions: Vec, } -/// The propsal is done when receiving this fin message, which contains the block hash. +/// The proposal is done when receiving this fin message, which contains the block hash. #[derive(Debug, Clone, PartialEq)] pub struct ProposalFin { /// The block hash of the proposed block. - /// TODO(guyn): Consider changing the content ID - pub proposal_content_id: BlockHash, + /// TODO(Matan): Consider changing the content ID to a signature. + pub proposal_commitment: BlockHash, } /// A part of the proposal. @@ -96,18 +108,41 @@ pub struct ProposalFin { pub enum ProposalPart { /// The initialization part of the proposal. Init(ProposalInit), + /// Identifies the content of the proposal; contains `id(v)` in Tendermint terms. + Fin(ProposalFin), + /// The block info part of the proposal. + BlockInfo(ConsensusBlockInfo), /// A part of the proposal that contains one or more transactions. Transactions(TransactionBatch), - /// The final part of the proposal, including the block hash. - Fin(ProposalFin), } -impl std::fmt::Display for StreamMessage +impl TryInto for ProposalPart { + type Error = ProtobufConversionError; + + fn try_into(self: ProposalPart) -> Result { + match self { + ProposalPart::Init(init) => Ok(init), + _ => Err(ProtobufConversionError::WrongEnumVariant { + type_description: "ProposalPart", + expected: "Init", + value_as_str: format!("{:?}", self), + }), + } + } +} + +impl From for ProposalPart { + fn from(value: ProposalInit) -> Self { + ProposalPart::Init(value) + } +} + +impl std::fmt::Display for StreamMessage where - T: Clone + Into> + TryFrom, Error = ProtobufConversionError>, + T: Clone + IntoFromProto, + StreamId: IntoFromProto + Clone + Display, { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - // TODO(guyn): add option to display when message is Fin and doesn't have content (PR #1048) if let StreamMessageBody::Content(message) = &self.message { let message: Vec = message.clone().into(); write!( @@ -127,52 +162,35 @@ where } } -// TODO(Guy): Remove after implementing broadcast streams. -#[allow(missing_docs)] -pub struct ProposalWrapper(pub Proposal); +/// HeighAndRound is a tuple struct used as the StreamId for consensus and context. +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct HeightAndRound(pub u64, pub u32); -impl From - for (ProposalInit, mpsc::Receiver, oneshot::Receiver) -{ - fn from(val: ProposalWrapper) -> Self { - let transactions: Vec = val.0.transactions.into_iter().collect(); - let proposal_init = ProposalInit { - height: BlockNumber(val.0.height), - round: val.0.round, - proposer: val.0.proposer, - valid_round: val.0.valid_round, - }; - let (mut content_sender, content_receiver) = mpsc::channel(transactions.len()); - for tx in transactions { - content_sender.try_send(tx).expect("Send should succeed"); - } - content_sender.close_channel(); +impl TryFrom> for HeightAndRound { + type Error = ProtobufConversionError; - let (fin_sender, fin_receiver) = oneshot::channel(); - fin_sender.send(val.0.block_hash).expect("Send should succeed"); + fn try_from(value: Vec) -> Result { + if value.len() != 12 { + return Err(ProtobufConversionError::DecodeError(DecodeError::new("Invalid length"))); + } + let mut bytes = value.as_slice(); + let height = bytes.get_u64(); + let round = bytes.get_u32(); + Ok(HeightAndRound(height, round)) + } +} - (proposal_init, content_receiver, fin_receiver) +impl From for Vec { + fn from(value: HeightAndRound) -> Vec { + let mut bytes = Vec::with_capacity(12); + bytes.put_u64(value.0); + bytes.put_u32(value.1); + bytes } } -impl From - for (ProposalInit, mpsc::Receiver>, oneshot::Receiver) -{ - fn from(val: ProposalWrapper) -> Self { - let proposal_init = ProposalInit { - height: BlockNumber(val.0.height), - round: val.0.round, - proposer: val.0.proposer, - valid_round: val.0.valid_round, - }; - - let (_, content_receiver) = mpsc::channel(0); - // This should only be used for Milestone 1, and then removed once streaming is supported. - println!("Cannot build ExecutableTransaction from Transaction."); - - let (fin_sender, fin_receiver) = oneshot::channel(); - fin_sender.send(val.0.block_hash).expect("Send should succeed"); - - (proposal_init, content_receiver, fin_receiver) +impl std::fmt::Display for HeightAndRound { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "(height: {}, round: {})", self.0, self.1) } } diff --git a/crates/papyrus_protobuf/src/converters/class.rs b/crates/papyrus_protobuf/src/converters/class.rs index 2a34a5d219e..ee58f829225 100644 --- a/crates/papyrus_protobuf/src/converters/class.rs +++ b/crates/papyrus_protobuf/src/converters/class.rs @@ -17,7 +17,7 @@ use starknet_api::rpc_transaction::EntryPointByType; use starknet_api::{deprecated_contract_class, state}; use starknet_types_core::felt::Felt; -use super::common::volition_domain_to_enum_int; +use super::common::{missing, volition_domain_to_enum_int}; use super::ProtobufConversionError; use crate::sync::{ClassQuery, DataOrFin, Query}; use crate::{auto_impl_into_and_try_from_vec_u8, protobuf}; @@ -32,9 +32,7 @@ impl TryFrom for DataOrFin<(ApiContractClass, ClassHa Ok(Self(Some(class.try_into()?))) } Some(protobuf::classes_response::ClassMessage::Fin(_)) => Ok(Self(None)), - None => Err(ProtobufConversionError::MissingField { - field_description: "ClassesResponse::class_message", - }), + None => Err(missing("ClassesResponse::class_message")), } } } @@ -71,18 +69,11 @@ impl TryFrom for (ApiContractClass, ClassHash) { ApiContractClass::ContractClass(state::SierraContractClass::try_from(class)?) } None => { - return Err(ProtobufConversionError::MissingField { - field_description: "Class::class", - }); + return Err(missing("Class::class")); } }; - let class_hash = value - .class_hash - .ok_or(ProtobufConversionError::MissingField { - field_description: "Class::class_hash", - })? - .try_into() - .map(ClassHash)?; + let class_hash = + value.class_hash.ok_or(missing("Class::class_hash"))?.try_into().map(ClassHash)?; Ok((class, class_hash)) } } @@ -146,15 +137,15 @@ impl TryFrom for deprecated_contract_class::ContractClass impl From for protobuf::Cairo0Class { fn from(value: deprecated_contract_class::ContractClass) -> Self { - // TODO: remove expects and handle results properly + // TODO(Shahak): remove expects and handle results properly let serialized_program = serde_json::to_value(&value.program) .expect("Failed to serialize Cairo 0 program to serde_json::Value"); - // TODO: consider storing the encoded program + // TODO(Shahak): consider storing the encoded program let encoded_program = compress_and_encode(serialized_program) .expect("Failed to compress and encode serialized Cairo 0 program"); - // TODO: remove expects and handle results properly + // TODO(Shahak): remove expects and handle results properly let encoded_abi = match value.abi { Some(abi_entries) => { let mut abi_bytes = vec![]; @@ -212,9 +203,7 @@ impl TryFrom for state::SierraContractClass { let mut entry_points_by_type = HashMap::new(); let entry_points = - value.entry_points.clone().ok_or(ProtobufConversionError::MissingField { - field_description: "Cairo1Class::entry_points", - })?; + value.entry_points.clone().ok_or(missing("Cairo1Class::entry_points"))?; if !entry_points.constructors.is_empty() { entry_points_by_type.insert( EntryPointType::Constructor, @@ -304,10 +293,7 @@ impl From for protobuf::Cairo1Class { impl TryFrom for deprecated_contract_class::EntryPointV0 { type Error = ProtobufConversionError; fn try_from(value: protobuf::EntryPoint) -> Result { - let selector_felt = - Felt::try_from(value.selector.ok_or(ProtobufConversionError::MissingField { - field_description: "EntryPoint::selector", - })?)?; + let selector_felt = Felt::try_from(value.selector.ok_or(missing("EntryPoint::selector"))?)?; let selector = EntryPointSelector(selector_felt); let offset = deprecated_contract_class::EntryPointOffset( @@ -331,9 +317,7 @@ impl TryFrom for state::EntryPoint { type Error = ProtobufConversionError; fn try_from(value: protobuf::SierraEntryPoint) -> Result { let selector_felt = - Felt::try_from(value.selector.ok_or(ProtobufConversionError::MissingField { - field_description: "SierraEntryPoint::selector", - })?)?; + Felt::try_from(value.selector.ok_or(missing("SierraEntryPoint::selector"))?)?; let selector = EntryPointSelector(selector_felt); let function_idx = @@ -362,14 +346,7 @@ impl TryFrom for Query { impl TryFrom for ClassQuery { type Error = ProtobufConversionError; fn try_from(value: protobuf::ClassesRequest) -> Result { - Ok(ClassQuery( - value - .iteration - .ok_or(ProtobufConversionError::MissingField { - field_description: "ClassesRequest::iteration", - })? - .try_into()?, - )) + Ok(ClassQuery(value.iteration.ok_or(missing("ClassesRequest::iteration"))?.try_into()?)) } } diff --git a/crates/papyrus_protobuf/src/converters/class_test.rs b/crates/papyrus_protobuf/src/converters/class_test.rs index 1768f929fd2..4c876414896 100644 --- a/crates/papyrus_protobuf/src/converters/class_test.rs +++ b/crates/papyrus_protobuf/src/converters/class_test.rs @@ -10,4 +10,4 @@ fn convert_cairo_0_class_to_protobuf_and_back() { assert_eq!(cairo_0_class, expected_cairo_0_class); } -// TODO: Add test for cairo 1 class conversion. +// TODO(Shahak): Add test for cairo 1 class conversion. diff --git a/crates/papyrus_protobuf/src/converters/common.rs b/crates/papyrus_protobuf/src/converters/common.rs index 30ee7a81b7f..f1664c19ae8 100644 --- a/crates/papyrus_protobuf/src/converters/common.rs +++ b/crates/papyrus_protobuf/src/converters/common.rs @@ -14,7 +14,7 @@ impl TryFrom for starknet_types_core::felt::Felt { fn try_from(value: protobuf::Felt252) -> Result { let mut felt = [0; 32]; felt.copy_from_slice(&value.elements); - // TODO: use from_bytes_checked once it's available. + // TODO(Shahak): use from_bytes_checked once it's available. Ok(Self::from_bytes_be(&felt)) // if let Ok(stark_felt) = Self::from_bytes_be(&felt) { // Ok(stark_felt) @@ -79,7 +79,7 @@ impl TryFrom for starknet_api::hash::StarkHash { }); } felt.copy_from_slice(&value.elements); - // TODO: use from_bytes_checked once it's available. + // TODO(Shahak): use from_bytes_checked once it's available. Ok(Self::from_bytes_be(&felt)) // if let Ok(stark_hash) = Self::new(felt) { // Ok(stark_hash) @@ -104,7 +104,7 @@ impl TryFrom for starknet_api::core::ContractAddress { }); } felt.copy_from_slice(&value.elements); - // TODO: use from_bytes_checked once it's available. + // TODO(Shahak): use from_bytes_checked once it's available. let hash = starknet_types_core::felt::Felt::from_bytes_be(&felt); // if let Ok(hash) = starknet_api::hash::StarkHash::new(felt) { if let Ok(stark_felt) = starknet_api::core::PatriciaKey::try_from(hash) { @@ -189,7 +189,7 @@ impl TestInstance for protobuf::ConsensusSignature { } #[allow(dead_code)] -pub(super) fn enum_int_to_volition_domain( +pub(crate) fn enum_int_to_volition_domain( value: i32, ) -> Result { match value { @@ -214,9 +214,7 @@ impl TryFrom for Query { type Error = ProtobufConversionError; fn try_from(value: protobuf::Iteration) -> Result { - let start = value.start.ok_or(ProtobufConversionError::MissingField { - field_description: "Iteration::start", - })?; + let start = value.start.ok_or(missing("Iteration::start"))?; let start_block = match start { protobuf::iteration::Start::BlockNumber(block_number) => { BlockHashOrNumber::Number(BlockNumber(block_number)) @@ -263,7 +261,7 @@ impl From for protobuf::Iteration { } } -// TODO: Consider add this functionality to the Felt itself. +// TODO(Shahak): Consider add this functionality to the Felt itself. pub(super) fn try_from_starkfelt_to_u128( felt: starknet_types_core::felt::Felt, ) -> Result { @@ -282,7 +280,7 @@ pub(super) fn try_from_starkfelt_to_u128( Ok(u128::from_be_bytes(bytes)) } -// TODO: Consider add this functionality to the Felt itself. +// TODO(Shahak): Consider add this functionality to the Felt itself. pub(super) fn try_from_starkfelt_to_u32( felt: starknet_types_core::felt::Felt, ) -> Result { @@ -300,3 +298,7 @@ pub(super) fn try_from_starkfelt_to_u32( Ok(u32::from_be_bytes(bytes)) } + +pub fn missing(field_description: &'static str) -> ProtobufConversionError { + ProtobufConversionError::MissingField { field_description } +} diff --git a/crates/papyrus_protobuf/src/converters/consensus.rs b/crates/papyrus_protobuf/src/converters/consensus.rs index 178c7c95892..836d233786a 100644 --- a/crates/papyrus_protobuf/src/converters/consensus.rs +++ b/crates/papyrus_protobuf/src/converters/consensus.rs @@ -1,17 +1,22 @@ #[cfg(test)] #[path = "consensus_test.rs"] mod consensus_test; + use std::convert::{TryFrom, TryInto}; use prost::Message; use starknet_api::block::{BlockHash, BlockNumber}; +use starknet_api::consensus_transaction::ConsensusTransaction; use starknet_api::hash::StarkHash; -use starknet_api::transaction::{Transaction, TransactionHash}; -use starknet_types_core::felt::Felt; +use super::common::{ + enum_int_to_l1_data_availability_mode, + l1_data_availability_mode_to_enum_int, + missing, +}; use crate::consensus::{ - ConsensusMessage, - Proposal, + ConsensusBlockInfo, + IntoFromProto, ProposalFin, ProposalInit, ProposalPart, @@ -24,50 +29,6 @@ use crate::consensus::{ use crate::converters::ProtobufConversionError; use crate::{auto_impl_into_and_try_from_vec_u8, protobuf}; -impl TryFrom for Proposal { - type Error = ProtobufConversionError; - - fn try_from(value: protobuf::Proposal) -> Result { - let transactions = value - .transactions - .into_iter() - .map(|tx| tx.try_into()) - .collect::, ProtobufConversionError>>()?; - - let height = value.height; - let round = value.round; - let proposer = value - .proposer - .ok_or(ProtobufConversionError::MissingField { field_description: "proposer" })? - .try_into()?; - let block_hash: StarkHash = value - .block_hash - .ok_or(ProtobufConversionError::MissingField { field_description: "block_hash" })? - .try_into()?; - let block_hash = BlockHash(block_hash); - let valid_round = value.valid_round; - - Ok(Proposal { height, round, proposer, transactions, block_hash, valid_round }) - } -} - -impl From for protobuf::Proposal { - fn from(value: Proposal) -> Self { - let transactions = value.transactions.into_iter().map(Into::into).collect(); - - protobuf::Proposal { - height: value.height, - round: value.round, - proposer: Some(value.proposer.into()), - transactions, - block_hash: Some(value.block_hash.0.into()), - valid_round: value.valid_round, - } - } -} - -auto_impl_into_and_try_from_vec_u8!(Proposal, protobuf::Proposal); - impl TryFrom for VoteType { type Error = ProtobufConversionError; @@ -98,10 +59,7 @@ impl TryFrom for Vote { let round = value.round; let block_hash: Option = value.block_hash.map(|block_hash| block_hash.try_into()).transpose()?.map(BlockHash); - let voter = value - .voter - .ok_or(ProtobufConversionError::MissingField { field_description: "voter" })? - .try_into()?; + let voter = value.voter.ok_or(missing("voter"))?.try_into()?; Ok(Vote { vote_type, height, round, block_hash, voter }) } @@ -126,8 +84,10 @@ impl From for protobuf::Vote { auto_impl_into_and_try_from_vec_u8!(Vote, protobuf::Vote); -impl> + TryFrom, Error = ProtobufConversionError>> - TryFrom for StreamMessage +impl TryFrom for StreamMessage +where + T: IntoFromProto, + StreamId: IntoFromProto + Clone, { type Error = ProtobufConversionError; @@ -148,16 +108,18 @@ impl> + TryFrom, Error = ProtobufConversionError>> StreamMessageBody::Fin } }, - stream_id: value.stream_id, + stream_id: value.stream_id.try_into()?, message_id: value.message_id, }) } } -impl> + TryFrom, Error = ProtobufConversionError>> From> - for protobuf::StreamMessage +impl From> for protobuf::StreamMessage +where + T: IntoFromProto, + StreamId: IntoFromProto + Clone, { - fn from(value: StreamMessage) -> Self { + fn from(value: StreamMessage) -> Self { Self { message: match value { StreamMessage { @@ -169,7 +131,7 @@ impl> + TryFrom, Error = ProtobufConversionError>> From< Some(protobuf::stream_message::Message::Fin(protobuf::Fin {})) } }, - stream_id: value.stream_id, + stream_id: value.stream_id.into(), message_id: value.message_id, } } @@ -178,17 +140,21 @@ impl> + TryFrom, Error = ProtobufConversionError>> From< // Can't use auto_impl_into_and_try_from_vec_u8!(StreamMessage, protobuf::StreamMessage); // because it doesn't seem to work with generics. // TODO(guyn): consider expanding the macro to support generics -impl> + TryFrom, Error = ProtobufConversionError>> From> - for Vec +impl From> for Vec +where + T: IntoFromProto, + StreamId: IntoFromProto + Clone, { - fn from(value: StreamMessage) -> Self { + fn from(value: StreamMessage) -> Self { let protobuf_value = ::from(value); protobuf_value.encode_to_vec() } } -impl> + TryFrom, Error = ProtobufConversionError>> TryFrom> - for StreamMessage +impl TryFrom> for StreamMessage +where + T: IntoFromProto, + StreamId: IntoFromProto + Clone, { type Error = ProtobufConversionError; fn try_from(value: Vec) -> Result { @@ -206,10 +172,7 @@ impl TryFrom for ProposalInit { let height = value.height; let round = value.round; let valid_round = value.valid_round; - let proposer = value - .proposer - .ok_or(ProtobufConversionError::MissingField { field_description: "proposer" })? - .try_into()?; + let proposer = value.proposer.ok_or(missing("proposer"))?.try_into()?; Ok(ProposalInit { height: BlockNumber(height), round, valid_round, proposer }) } } @@ -227,6 +190,48 @@ impl From for protobuf::ProposalInit { auto_impl_into_and_try_from_vec_u8!(ProposalInit, protobuf::ProposalInit); +impl TryFrom for ConsensusBlockInfo { + type Error = ProtobufConversionError; + fn try_from(value: protobuf::BlockInfo) -> Result { + let height = value.height; + let timestamp = value.timestamp; + let builder = value.builder.ok_or(missing("builder"))?.try_into()?; + let l1_da_mode = enum_int_to_l1_data_availability_mode(value.l1_da_mode)?; + let l2_gas_price_fri = value.l2_gas_price_fri.ok_or(missing("l2_gas_price_fri"))?.into(); + let l1_gas_price_wei = value.l1_gas_price_wei.ok_or(missing("l1_gas_price_wei"))?.into(); + let l1_data_gas_price_wei = + value.l1_data_gas_price_wei.ok_or(missing("l1_data_gas_price_wei"))?.into(); + let eth_to_fri_rate = value.eth_to_fri_rate.ok_or(missing("eth_to_fri_rate"))?.into(); + Ok(ConsensusBlockInfo { + height: BlockNumber(height), + timestamp, + builder, + l1_da_mode, + l2_gas_price_fri, + l1_gas_price_wei, + l1_data_gas_price_wei, + eth_to_fri_rate, + }) + } +} + +impl From for protobuf::BlockInfo { + fn from(value: ConsensusBlockInfo) -> Self { + protobuf::BlockInfo { + height: value.height.0, + timestamp: value.timestamp, + builder: Some(value.builder.into()), + l1_da_mode: l1_data_availability_mode_to_enum_int(value.l1_da_mode), + l1_gas_price_wei: Some(value.l1_gas_price_wei.into()), + l1_data_gas_price_wei: Some(value.l1_data_gas_price_wei.into()), + l2_gas_price_fri: Some(value.l2_gas_price_fri.into()), + eth_to_fri_rate: Some(value.eth_to_fri_rate.into()), + } + } +} + +auto_impl_into_and_try_from_vec_u8!(ConsensusBlockInfo, protobuf::BlockInfo); + impl TryFrom for TransactionBatch { type Error = ProtobufConversionError; fn try_from(value: protobuf::TransactionBatch) -> Result { @@ -234,21 +239,15 @@ impl TryFrom for TransactionBatch { .transactions .into_iter() .map(|tx| tx.try_into()) - .collect::, ProtobufConversionError>>()?; - let tx_hashes = value - .tx_hashes - .into_iter() - .map(|x| Felt::try_from(x).map(TransactionHash)) - .collect::>()?; - Ok(TransactionBatch { transactions, tx_hashes }) + .collect::, ProtobufConversionError>>()?; + Ok(TransactionBatch { transactions }) } } impl From for protobuf::TransactionBatch { fn from(value: TransactionBatch) -> Self { let transactions = value.transactions.into_iter().map(Into::into).collect(); - let tx_hashes = value.tx_hashes.into_iter().map(|hash| hash.0.into()).collect(); - protobuf::TransactionBatch { transactions, tx_hashes } + protobuf::TransactionBatch { transactions } } } @@ -257,20 +256,16 @@ auto_impl_into_and_try_from_vec_u8!(TransactionBatch, protobuf::TransactionBatch impl TryFrom for ProposalFin { type Error = ProtobufConversionError; fn try_from(value: protobuf::ProposalFin) -> Result { - let proposal_content_id: StarkHash = value - .proposal_content_id - .ok_or(ProtobufConversionError::MissingField { - field_description: "proposal_content_id", - })? - .try_into()?; - let proposal_content_id = BlockHash(proposal_content_id); - Ok(ProposalFin { proposal_content_id }) + let proposal_commitment: StarkHash = + value.proposal_commitment.ok_or(missing("proposal_commitment"))?.try_into()?; + let proposal_commitment = BlockHash(proposal_commitment); + Ok(ProposalFin { proposal_commitment }) } } impl From for protobuf::ProposalFin { fn from(value: ProposalFin) -> Self { - protobuf::ProposalFin { proposal_content_id: Some(value.proposal_content_id.0.into()) } + protobuf::ProposalFin { proposal_commitment: Some(value.proposal_commitment.0.into()) } } } @@ -282,13 +277,14 @@ impl TryFrom for ProposalPart { use protobuf::proposal_part::Message; let Some(part) = value.message else { - return Err(ProtobufConversionError::MissingField { field_description: "part" }); + return Err(missing("part")); }; match part { Message::Init(init) => Ok(ProposalPart::Init(init.try_into()?)), - Message::Transactions(content) => Ok(ProposalPart::Transactions(content.try_into()?)), Message::Fin(fin) => Ok(ProposalPart::Fin(fin.try_into()?)), + Message::BlockInfo(block_info) => Ok(ProposalPart::BlockInfo(block_info.try_into()?)), + Message::Transactions(content) => Ok(ProposalPart::Transactions(content.try_into()?)), } } } @@ -299,46 +295,17 @@ impl From for protobuf::ProposalPart { ProposalPart::Init(init) => protobuf::ProposalPart { message: Some(protobuf::proposal_part::Message::Init(init.into())), }, - ProposalPart::Transactions(content) => protobuf::ProposalPart { - message: Some(protobuf::proposal_part::Message::Transactions(content.into())), - }, ProposalPart::Fin(fin) => protobuf::ProposalPart { message: Some(protobuf::proposal_part::Message::Fin(fin.into())), }, - } - } -} - -auto_impl_into_and_try_from_vec_u8!(ProposalPart, protobuf::ProposalPart); - -impl TryFrom for ConsensusMessage { - type Error = ProtobufConversionError; - - fn try_from(value: protobuf::ConsensusMessage) -> Result { - use protobuf::consensus_message::Message; - - let Some(message) = value.message else { - return Err(ProtobufConversionError::MissingField { field_description: "message" }); - }; - - match message { - Message::Proposal(proposal) => Ok(ConsensusMessage::Proposal(proposal.try_into()?)), - Message::Vote(vote) => Ok(ConsensusMessage::Vote(vote.try_into()?)), - } - } -} - -impl From for protobuf::ConsensusMessage { - fn from(value: ConsensusMessage) -> Self { - match value { - ConsensusMessage::Proposal(proposal) => protobuf::ConsensusMessage { - message: Some(protobuf::consensus_message::Message::Proposal(proposal.into())), + ProposalPart::BlockInfo(block_info) => protobuf::ProposalPart { + message: Some(protobuf::proposal_part::Message::BlockInfo(block_info.into())), }, - ConsensusMessage::Vote(vote) => protobuf::ConsensusMessage { - message: Some(protobuf::consensus_message::Message::Vote(vote.into())), + ProposalPart::Transactions(content) => protobuf::ProposalPart { + message: Some(protobuf::proposal_part::Message::Transactions(content.into())), }, } } } -auto_impl_into_and_try_from_vec_u8!(ConsensusMessage, protobuf::ConsensusMessage); +auto_impl_into_and_try_from_vec_u8!(ProposalPart, protobuf::ProposalPart); diff --git a/crates/papyrus_protobuf/src/converters/consensus_test.rs b/crates/papyrus_protobuf/src/converters/consensus_test.rs index 57e328a7fac..ec9454aa260 100644 --- a/crates/papyrus_protobuf/src/converters/consensus_test.rs +++ b/crates/papyrus_protobuf/src/converters/consensus_test.rs @@ -1,19 +1,18 @@ use papyrus_test_utils::{get_rng, GetTestInstance}; +use starknet_api::consensus_transaction::ConsensusTransaction; use starknet_api::execution_resources::GasAmount; -use starknet_api::transaction::fields::ValidResourceBounds; -use starknet_api::transaction::{ - DeclareTransaction, - DeclareTransactionV3, - DeployAccountTransaction, - DeployAccountTransactionV3, - InvokeTransaction, - InvokeTransactionV3, - Transaction, +use starknet_api::rpc_transaction::{ + RpcDeclareTransaction, + RpcDeclareTransactionV3, + RpcDeployAccountTransaction, + RpcDeployAccountTransactionV3, + RpcInvokeTransaction, + RpcInvokeTransactionV3, + RpcTransaction, }; use crate::consensus::{ - ConsensusMessage, - Proposal, + ConsensusBlockInfo, ProposalFin, ProposalInit, ProposalPart, @@ -22,28 +21,29 @@ use crate::consensus::{ TransactionBatch, Vote, }; +use crate::converters::test_instances::TestStreamId; // If all the fields of `AllResources` are 0 upon serialization, // then the deserialized value will be interpreted as the `L1Gas` variant. -fn add_gas_values_to_transaction(transactions: &mut [Transaction]) { +fn add_gas_values_to_transaction(transactions: &mut [ConsensusTransaction]) { let transaction = &mut transactions[0]; match transaction { - Transaction::Declare(DeclareTransaction::V3(DeclareTransactionV3 { - resource_bounds, - .. - })) - | Transaction::Invoke(InvokeTransaction::V3(InvokeTransactionV3 { - resource_bounds, .. - })) - | Transaction::DeployAccount(DeployAccountTransaction::V3(DeployAccountTransactionV3 { - resource_bounds, - .. - })) => { - if let ValidResourceBounds::AllResources(ref mut bounds) = resource_bounds { - bounds.l2_gas.max_amount = GasAmount(1); + ConsensusTransaction::RpcTransaction(rpc_transaction) => match rpc_transaction { + RpcTransaction::Declare(RpcDeclareTransaction::V3(RpcDeclareTransactionV3 { + resource_bounds, + .. + })) + | RpcTransaction::Invoke(RpcInvokeTransaction::V3(RpcInvokeTransactionV3 { + resource_bounds, + .. + })) + | RpcTransaction::DeployAccount(RpcDeployAccountTransaction::V3( + RpcDeployAccountTransactionV3 { resource_bounds, .. }, + )) => { + resource_bounds.l2_gas.max_amount = GasAmount(1); } - } - _ => {} + }, + ConsensusTransaction::L1Handler(_) => {} } } @@ -51,11 +51,11 @@ fn add_gas_values_to_transaction(transactions: &mut [Transaction]) { fn convert_stream_message_to_vec_u8_and_back() { let mut rng = get_rng(); - // Test that we can convert a StreamMessage with a ConsensusMessage message to bytes and back. - let mut stream_message: StreamMessage = + // Test that we can convert a StreamMessage with a ProposalPart message to bytes and back. + let mut stream_message: StreamMessage = StreamMessage::get_test_instance(&mut rng); - if let StreamMessageBody::Content(ConsensusMessage::Proposal(proposal)) = + if let StreamMessageBody::Content(ProposalPart::Transactions(proposal)) = &mut stream_message.message { add_gas_values_to_transaction(&mut proposal.transactions); @@ -66,22 +66,6 @@ fn convert_stream_message_to_vec_u8_and_back() { assert_eq!(stream_message, res_data); } -#[test] -fn convert_consensus_message_to_vec_u8_and_back() { - let mut rng = get_rng(); - - // Test that we can convert a ConsensusMessage to bytes and back. - let mut message = ConsensusMessage::get_test_instance(&mut rng); - - if let ConsensusMessage::Proposal(proposal) = &mut message { - add_gas_values_to_transaction(&mut proposal.transactions); - } - - let bytes_data: Vec = message.clone().into(); - let res_data = ConsensusMessage::try_from(bytes_data).unwrap(); - assert_eq!(message, res_data); -} - #[test] fn convert_vote_to_vec_u8_and_back() { let mut rng = get_rng(); @@ -94,27 +78,25 @@ fn convert_vote_to_vec_u8_and_back() { } #[test] -fn convert_proposal_to_vec_u8_and_back() { +fn convert_proposal_init_to_vec_u8_and_back() { let mut rng = get_rng(); - let mut proposal = Proposal::get_test_instance(&mut rng); - - add_gas_values_to_transaction(&mut proposal.transactions); + let proposal_init = ProposalInit::get_test_instance(&mut rng); - let bytes_data: Vec = proposal.clone().into(); - let res_data = Proposal::try_from(bytes_data).unwrap(); - assert_eq!(proposal, res_data); + let bytes_data: Vec = proposal_init.into(); + let res_data = ProposalInit::try_from(bytes_data).unwrap(); + assert_eq!(proposal_init, res_data); } #[test] -fn convert_proposal_init_to_vec_u8_and_back() { +fn convert_block_info_to_vec_u8_and_back() { let mut rng = get_rng(); - let proposal_init = ProposalInit::get_test_instance(&mut rng); + let block_info = ConsensusBlockInfo::get_test_instance(&mut rng); - let bytes_data: Vec = proposal_init.clone().into(); - let res_data = ProposalInit::try_from(bytes_data).unwrap(); - assert_eq!(proposal_init, res_data); + let bytes_data: Vec = block_info.clone().into(); + let res_data = ConsensusBlockInfo::try_from(bytes_data).unwrap(); + assert_eq!(block_info, res_data); } #[test] @@ -159,9 +141,9 @@ fn convert_proposal_part_to_vec_u8_and_back() { #[test] fn stream_message_display() { let mut rng = get_rng(); - let stream_id = 42; + let stream_id = TestStreamId(42); let message_id = 127; - let proposal = Proposal::get_test_instance(&mut rng); + let proposal = ProposalPart::get_test_instance(&mut rng); let proposal_bytes: Vec = proposal.clone().into(); let proposal_length = proposal_bytes.len(); let content = StreamMessageBody::Content(proposal); @@ -176,7 +158,7 @@ fn stream_message_display() { ) ); - let content: StreamMessageBody = StreamMessageBody::Fin; + let content: StreamMessageBody = StreamMessageBody::Fin; let message = StreamMessage { message: content, stream_id, message_id }; let txt = message.to_string(); assert_eq!( diff --git a/crates/papyrus_protobuf/src/converters/event.rs b/crates/papyrus_protobuf/src/converters/event.rs index 41d9f8c5dfe..962bef612d4 100644 --- a/crates/papyrus_protobuf/src/converters/event.rs +++ b/crates/papyrus_protobuf/src/converters/event.rs @@ -6,6 +6,7 @@ use starknet_api::core::{ContractAddress, PatriciaKey}; use starknet_api::transaction::{Event, EventContent, EventData, EventKey, TransactionHash}; use starknet_types_core::felt::Felt; +use super::common::missing; use super::ProtobufConversionError; use crate::sync::{DataOrFin, EventQuery, Query}; use crate::{auto_impl_into_and_try_from_vec_u8, protobuf}; @@ -18,9 +19,7 @@ impl TryFrom for DataOrFin<(Event, TransactionHash)> { Ok(Self(Some(event.try_into()?))) } Some(protobuf::events_response::EventMessage::Fin(_)) => Ok(Self(None)), - None => Err(ProtobufConversionError::MissingField { - field_description: "EventsResponse::event_message", - }), + None => Err(missing("EventsResponse::event_message")), } } } @@ -45,18 +44,11 @@ impl TryFrom for (Event, TransactionHash) { type Error = ProtobufConversionError; fn try_from(value: protobuf::Event) -> Result { let transaction_hash = TransactionHash( - value - .transaction_hash - .ok_or(ProtobufConversionError::MissingField { - field_description: "Event::transaction_hash", - })? - .try_into()?, + value.transaction_hash.ok_or(missing("Event::transaction_hash"))?.try_into()?, ); let from_address_felt = - Felt::try_from(value.from_address.ok_or(ProtobufConversionError::MissingField { - field_description: "Event::from_address", - })?)?; + Felt::try_from(value.from_address.ok_or(missing("Event::from_address"))?)?; let from_address = ContractAddress(PatriciaKey::try_from(from_address_felt).map_err(|_| { ProtobufConversionError::OutOfRangeValue { @@ -103,14 +95,7 @@ impl TryFrom for Query { impl TryFrom for EventQuery { type Error = ProtobufConversionError; fn try_from(value: protobuf::EventsRequest) -> Result { - Ok(EventQuery( - value - .iteration - .ok_or(ProtobufConversionError::MissingField { - field_description: "EventsRequest::iteration", - })? - .try_into()?, - )) + Ok(EventQuery(value.iteration.ok_or(missing("EventsRequest::iteration"))?.try_into()?)) } } diff --git a/crates/papyrus_protobuf/src/converters/header.rs b/crates/papyrus_protobuf/src/converters/header.rs index cd01db6ad9d..3fbe250e2dc 100644 --- a/crates/papyrus_protobuf/src/converters/header.rs +++ b/crates/papyrus_protobuf/src/converters/header.rs @@ -23,7 +23,11 @@ use starknet_api::core::{ use starknet_api::crypto::utils::Signature; use starknet_api::hash::PoseidonHash; -use super::common::{enum_int_to_l1_data_availability_mode, l1_data_availability_mode_to_enum_int}; +use super::common::{ + enum_int_to_l1_data_availability_mode, + l1_data_availability_mode_to_enum_int, + missing, +}; use super::ProtobufConversionError; use crate::sync::{DataOrFin, HeaderQuery, Query, SignedBlockHeader}; use crate::{auto_impl_into_and_try_from_vec_u8, protobuf}; @@ -43,9 +47,7 @@ impl TryFrom for Option { Ok(Some(header.try_into()?)) } Some(protobuf::block_headers_response::HeaderMessage::Fin(_)) => Ok(None), - None => Err(ProtobufConversionError::MissingField { - field_description: "BlockHeadersResponse::header_message", - }), + None => Err(missing("BlockHeadersResponse::header_message")), } } } @@ -55,17 +57,13 @@ impl TryFrom for SignedBlockHeader { fn try_from(value: protobuf::SignedBlockHeader) -> Result { let block_hash = value .block_hash - .ok_or(ProtobufConversionError::MissingField { - field_description: "SignedBlockHeader::block_hash", - })? + .ok_or(missing("SignedBlockHeader::block_hash"))? .try_into() .map(BlockHash)?; let parent_hash = value .parent_hash - .ok_or(ProtobufConversionError::MissingField { - field_description: "SignedBlockHeader::parent_hash", - })? + .ok_or(missing("SignedBlockHeader::parent_hash"))? .try_into() .map(BlockHash)?; @@ -73,35 +71,27 @@ impl TryFrom for SignedBlockHeader { let sequencer = value .sequencer_address - .ok_or(ProtobufConversionError::MissingField { - field_description: "SignedBlockHeader::sequencer_address", - })? + .ok_or(missing("SignedBlockHeader::sequencer_address"))? .try_into() .map(SequencerContractAddress)?; let state_root = value .state_root - .ok_or(ProtobufConversionError::MissingField { - field_description: "SignedBlockHeader::state_root", - })? + .ok_or(missing("SignedBlockHeader::state_root"))? .try_into() .map(GlobalRoot)?; let n_transactions = value .transactions .as_ref() - .ok_or(ProtobufConversionError::MissingField { - field_description: "SignedBlockHeader::transactions", - })? + .ok_or(missing("SignedBlockHeader::transactions"))? .n_leaves .try_into() .expect("Failed converting u64 to usize"); let transaction_commitment = value .transactions - .ok_or(ProtobufConversionError::MissingField { - field_description: "SignedBlockHeader::transactions", - })? + .ok_or(missing("SignedBlockHeader::transactions"))? .root .map(|root| root.try_into()) .transpose()? @@ -110,18 +100,14 @@ impl TryFrom for SignedBlockHeader { let n_events = value .events .as_ref() - .ok_or(ProtobufConversionError::MissingField { - field_description: "SignedBlockHeader::events", - })? + .ok_or(missing("SignedBlockHeader::events"))? .n_leaves .try_into() .expect("Failed converting u64 to usize"); let event_commitment = value .events - .ok_or(ProtobufConversionError::MissingField { - field_description: "SignedBlockHeader::events", - })? + .ok_or(missing("SignedBlockHeader::events"))? .root .map(|root| root.try_into()) .transpose()? @@ -147,51 +133,46 @@ impl TryFrom for SignedBlockHeader { }; let l1_gas_price = GasPricePerToken { - price_in_fri: u128::from(value.gas_price_fri.ok_or( - ProtobufConversionError::MissingField { - field_description: "SignedBlockHeader::gas_price_fri", - }, - )?) + price_in_fri: u128::from( + value.l1_gas_price_fri.ok_or(missing("SignedBlockHeader::gas_price_fri"))?, + ) .into(), - price_in_wei: u128::from(value.gas_price_wei.ok_or( - ProtobufConversionError::MissingField { - field_description: "SignedBlockHeader::gas_price_wei", - }, - )?) + price_in_wei: u128::from( + value.l1_gas_price_wei.ok_or(missing("SignedBlockHeader::gas_price_wei"))?, + ) .into(), }; let l1_data_gas_price = GasPricePerToken { - price_in_fri: u128::from(value.data_gas_price_fri.ok_or( - ProtobufConversionError::MissingField { - field_description: "SignedBlockHeader::data_gas_price_fri", - }, - )?) + price_in_fri: u128::from( + value + .l1_data_gas_price_fri + .ok_or(missing("SignedBlockHeader::data_gas_price_fri"))?, + ) .into(), - price_in_wei: u128::from(value.data_gas_price_wei.ok_or( - ProtobufConversionError::MissingField { - field_description: "SignedBlockHeader::data_gas_price_wei", - }, - )?) + price_in_wei: u128::from( + value + .l1_data_gas_price_wei + .ok_or(missing("SignedBlockHeader::data_gas_price_wei"))?, + ) .into(), }; let l2_gas_price = GasPricePerToken { - price_in_fri: u128::from(value.l2_gas_price_fri.ok_or( - ProtobufConversionError::MissingField { - field_description: "SignedBlockHeader::l2_gas_price_fri", - }, - )?) + price_in_fri: u128::from( + value.l2_gas_price_fri.ok_or(missing("SignedBlockHeader::l2_gas_price_fri"))?, + ) .into(), - price_in_wei: u128::from(value.l2_gas_price_wei.ok_or( - ProtobufConversionError::MissingField { - field_description: "SignedBlockHeader::l2_gas_price_wei", - }, - )?) + price_in_wei: u128::from( + value.l2_gas_price_wei.ok_or(missing("SignedBlockHeader::l2_gas_price_wei"))?, + ) .into(), }; + let l2_gas_consumed = value.l2_gas_consumed; + let next_l2_gas_price = value.next_l2_gas_price; + let receipt_commitment = value .receipts .map(|receipts| receipts.try_into().map(ReceiptCommitment)) @@ -199,9 +180,7 @@ impl TryFrom for SignedBlockHeader { let state_diff_commitment = value .state_diff_commitment - .ok_or(ProtobufConversionError::MissingField { - field_description: "SignedBlockHeader::state_diff_commitment", - })? + .ok_or(missing("SignedBlockHeader::state_diff_commitment"))? .root .map(|root| root.try_into()) .transpose()? @@ -216,6 +195,8 @@ impl TryFrom for SignedBlockHeader { l1_gas_price, l1_data_gas_price, l2_gas_price, + l2_gas_consumed, + next_l2_gas_price, state_root, sequencer, timestamp, @@ -279,16 +260,16 @@ impl From<(BlockHeader, Vec)> for protobuf::SignedBlockHeader { .receipt_commitment .map(|receipt_commitment| receipt_commitment.0.into()), protocol_version: header.block_header_without_hash.starknet_version.to_string(), - gas_price_wei: Some( + l1_gas_price_wei: Some( header.block_header_without_hash.l1_gas_price.price_in_wei.0.into(), ), - gas_price_fri: Some( + l1_gas_price_fri: Some( header.block_header_without_hash.l1_gas_price.price_in_fri.0.into(), ), - data_gas_price_wei: Some( + l1_data_gas_price_wei: Some( header.block_header_without_hash.l1_data_gas_price.price_in_wei.0.into(), ), - data_gas_price_fri: Some( + l1_data_gas_price_fri: Some( header.block_header_without_hash.l1_data_gas_price.price_in_fri.0.into(), ), l2_gas_price_wei: Some( @@ -300,6 +281,8 @@ impl From<(BlockHeader, Vec)> for protobuf::SignedBlockHeader { l1_data_availability_mode: l1_data_availability_mode_to_enum_int( header.block_header_without_hash.l1_da_mode, ), + l2_gas_consumed: header.block_header_without_hash.l2_gas_consumed, + next_l2_gas_price: header.block_header_without_hash.next_l2_gas_price, signatures: signatures.iter().map(|signature| (*signature).into()).collect(), } } @@ -309,18 +292,8 @@ impl TryFrom for starknet_api::block::BlockSignatu type Error = ProtobufConversionError; fn try_from(value: protobuf::ConsensusSignature) -> Result { Ok(Self(Signature { - r: value - .r - .ok_or(ProtobufConversionError::MissingField { - field_description: "SignedBlockHeader::r", - })? - .try_into()?, - s: value - .s - .ok_or(ProtobufConversionError::MissingField { - field_description: "SignedBlockHeader::s", - })? - .try_into()?, + r: value.r.ok_or(missing("SignedBlockHeader::r"))?.try_into()?, + s: value.s.ok_or(missing("SignedBlockHeader::s"))?.try_into()?, })) } } @@ -364,12 +337,7 @@ impl TryFrom for HeaderQuery { type Error = ProtobufConversionError; fn try_from(value: protobuf::BlockHeadersRequest) -> Result { Ok(HeaderQuery( - value - .iteration - .ok_or(ProtobufConversionError::MissingField { - field_description: "BlockHeadersRequest::iteration", - })? - .try_into()?, + value.iteration.ok_or(missing("BlockHeadersRequest::iteration"))?.try_into()?, )) } } diff --git a/crates/papyrus_protobuf/src/converters/mod.rs b/crates/papyrus_protobuf/src/converters/mod.rs index a72d774d25d..fb5f3a96098 100644 --- a/crates/papyrus_protobuf/src/converters/mod.rs +++ b/crates/papyrus_protobuf/src/converters/mod.rs @@ -1,5 +1,5 @@ mod class; -mod common; +pub(crate) mod common; // TODO(matan): Internalize once we remove the dependency on the protobuf crate. pub mod consensus; mod event; @@ -22,6 +22,12 @@ pub enum ProtobufConversionError { MissingField { field_description: &'static str }, #[error("Type `{type_description}` should be {num_expected} bytes but it got {value:?}.")] BytesDataLengthMismatch { type_description: &'static str, num_expected: usize, value: Vec }, + #[error("Type `{type_description}` got unexpected enum variant {value_as_str}")] + WrongEnumVariant { + type_description: &'static str, + value_as_str: String, + expected: &'static str, + }, #[error(transparent)] DecodeError(#[from] DecodeError), /// For CompressionError and serde_json::Error we put the string of the error instead of the diff --git a/crates/papyrus_protobuf/src/converters/receipt.rs b/crates/papyrus_protobuf/src/converters/receipt.rs index 1caac6cc1cb..cbfec8573b4 100644 --- a/crates/papyrus_protobuf/src/converters/receipt.rs +++ b/crates/papyrus_protobuf/src/converters/receipt.rs @@ -17,16 +17,14 @@ use starknet_api::transaction::{ }; use starknet_types_core::felt::Felt; -use super::common::try_from_starkfelt_to_u128; +use super::common::{missing, try_from_starkfelt_to_u128}; use super::ProtobufConversionError; use crate::protobuf; impl TryFrom for TransactionOutput { type Error = ProtobufConversionError; fn try_from(value: protobuf::Receipt) -> Result { - let receipt = value - .r#type - .ok_or(ProtobufConversionError::MissingField { field_description: "Receipt::type" })?; + let receipt = value.r#type.ok_or(missing("Receipt::type"))?; match receipt { protobuf::receipt::Type::Invoke(invoke) => { Ok(TransactionOutput::Invoke(InvokeTransactionOutput::try_from(invoke)?)) @@ -81,9 +79,7 @@ impl TryFrom for DeployAccountTransactionOutpu let events = vec![]; let contract_address = - value.contract_address.ok_or(ProtobufConversionError::MissingField { - field_description: "DeployAccount::contract_address", - })?; + value.contract_address.ok_or(missing("DeployAccount::contract_address"))?; let felt = Felt::try_from(contract_address)?; let contract_address = ContractAddress(PatriciaKey::try_from(felt).map_err(|_| { ProtobufConversionError::OutOfRangeValue { @@ -130,10 +126,7 @@ impl TryFrom for DeployTransactionOutput { let events = vec![]; - let contract_address = - value.contract_address.ok_or(ProtobufConversionError::MissingField { - field_description: "Deploy::contract_address", - })?; + let contract_address = value.contract_address.ok_or(missing("Deploy::contract_address"))?; let felt = Felt::try_from(contract_address)?; let contract_address = ContractAddress(PatriciaKey::try_from(felt).map_err(|_| { ProtobufConversionError::OutOfRangeValue { @@ -277,7 +270,7 @@ impl From> for ProtobufBuiltinCounter { fn from(value: HashMap) -> Self { let builtin_counter = ProtobufBuiltinCounter { range_check: u32::try_from(*value.get(&Builtin::RangeCheck).unwrap_or(&0)) - // TODO: should not panic + // TODO(Shahak): should not panic .expect("Failed to convert u64 to u32"), pedersen: u32::try_from(*value.get(&Builtin::Pedersen).unwrap_or(&0)) .expect("Failed to convert u64 to u32"), @@ -300,24 +293,14 @@ impl From> for ProtobufBuiltinCounter { impl TryFrom for ExecutionResources { type Error = ProtobufConversionError; fn try_from(value: protobuf::receipt::ExecutionResources) -> Result { - let builtin_instance_counter = value - .builtins - .ok_or(ProtobufConversionError::MissingField { field_description: "builtins" })?; + let builtin_instance_counter = value.builtins.ok_or(missing("builtins"))?; let builtin_instance_counter = HashMap::::try_from(builtin_instance_counter)?; - // TODO: remove all non-da gas consumed - let gas_consumed = value - .gas_consumed - .ok_or(ProtobufConversionError::MissingField { - field_description: "ExecutionResources::gas_consumed", - })? - .into(); - let da_gas_consumed = value - .da_gas_consumed - .ok_or(ProtobufConversionError::MissingField { - field_description: "ExecutionResources::da_gas_consumed", - })? - .into(); + // TODO(Shahak): remove all non-da gas consumed + let gas_consumed = + value.gas_consumed.ok_or(missing("ExecutionResources::gas_consumed"))?.into(); + let da_gas_consumed = + value.da_gas_consumed.ok_or(missing("ExecutionResources::da_gas_consumed"))?.into(); let execution_resources = ExecutionResources { steps: u64::from(value.steps), @@ -343,10 +326,10 @@ impl From for GasVector { impl From for protobuf::receipt::ExecutionResources { fn from(value: ExecutionResources) -> Self { let builtin_instance_counter = ProtobufBuiltinCounter::from(value.builtin_instance_counter); - // TODO: add all l1 gas consumed, not just da + // TODO(Shahak): add all l1 gas consumed, not just da let gas_consumed = value.gas_consumed.into(); let da_gas_consumed = value.da_gas_consumed.into(); - // TODO: should not panic + // TODO(Shahak): should not panic let steps = u32::try_from(value.steps).expect("Failed to convert u64 to u32"); let memory_holes = u32::try_from(value.memory_holes).expect("Failed to convert u64 to u32"); @@ -396,15 +379,12 @@ impl TryFrom for MessageToL1 { type Error = ProtobufConversionError; fn try_from(value: protobuf::MessageToL1) -> Result { let from_address_felt = - Felt::try_from(value.from_address.ok_or(ProtobufConversionError::MissingField { - field_description: "MessageToL1::from_address", - })?)?; + Felt::try_from(value.from_address.ok_or(missing("MessageToL1::from_address"))?)?; let from_address = ContractAddress::try_from(from_address_felt) .expect("Converting ContractAddress from Felt failed"); - let to_address = EthAddress::try_from(value.to_address.ok_or( - ProtobufConversionError::MissingField { field_description: "MessageToL1::to_address" }, - )?)?; + let to_address = + EthAddress::try_from(value.to_address.ok_or(missing("MessageToL1::to_address"))?)?; let payload = L2ToL1Payload( value.payload.into_iter().map(Felt::try_from).collect::, _>>()?, @@ -433,12 +413,8 @@ fn parse_common_receipt_fields( (Fee, Vec, TransactionExecutionStatus, ExecutionResources), ProtobufConversionError, > { - let common = - common.ok_or(ProtobufConversionError::MissingField { field_description: "Common" })?; - let actual_fee_felt = - Felt::try_from(common.actual_fee.ok_or(ProtobufConversionError::MissingField { - field_description: "Common::actual_fee", - })?)?; + let common = common.ok_or(missing("Common"))?; + let actual_fee_felt = Felt::try_from(common.actual_fee.ok_or(missing("Common::actual_fee"))?)?; let actual_fee = Fee(try_from_starkfelt_to_u128(actual_fee_felt).map_err(|_| { ProtobufConversionError::OutOfRangeValue { type_description: "u128", @@ -456,9 +432,9 @@ fn parse_common_receipt_fields( revert_reason, }) }); - let execution_resources = ExecutionResources::try_from(common.execution_resources.ok_or( - ProtobufConversionError::MissingField { field_description: "Common::execution_resources" }, - )?)?; + let execution_resources = ExecutionResources::try_from( + common.execution_resources.ok_or(missing("Common::execution_resources"))?, + )?; Ok((actual_fee, messages_sent, execution_status, execution_resources)) } diff --git a/crates/papyrus_protobuf/src/converters/rpc_transaction.rs b/crates/papyrus_protobuf/src/converters/rpc_transaction.rs index 234a31e3ffc..d65d65e4b61 100644 --- a/crates/papyrus_protobuf/src/converters/rpc_transaction.rs +++ b/crates/papyrus_protobuf/src/converters/rpc_transaction.rs @@ -4,8 +4,6 @@ mod rpc_transaction_test; use prost::Message; use starknet_api::rpc_transaction::{ - ContractClass, - EntryPointByType, RpcDeclareTransaction, RpcDeclareTransactionV3, RpcDeployAccountTransaction, @@ -14,288 +12,183 @@ use starknet_api::rpc_transaction::{ RpcInvokeTransactionV3, RpcTransaction, }; -use starknet_api::state::EntryPoint; +use starknet_api::state::SierraContractClass; use starknet_api::transaction::fields::{AllResourceBounds, ValidResourceBounds}; -use starknet_api::transaction::{ - DeclareTransactionV3, - DeployAccountTransactionV3, - InvokeTransactionV3, -}; -use starknet_types_core::felt::Felt; +use starknet_api::transaction::{DeployAccountTransactionV3, InvokeTransactionV3}; +use super::common::missing; use super::ProtobufConversionError; use crate::auto_impl_into_and_try_from_vec_u8; -use crate::mempool::RpcTransactionWrapper; -use crate::protobuf::{self, Felt252}; - -auto_impl_into_and_try_from_vec_u8!(RpcTransactionWrapper, protobuf::RpcTransaction); +use crate::mempool::RpcTransactionBatch; +use crate::protobuf::{self}; +use crate::transaction::DeclareTransactionV3Common; +auto_impl_into_and_try_from_vec_u8!(RpcTransactionBatch, protobuf::MempoolTransactionBatch); -impl TryFrom for RpcTransactionWrapper { - type Error = ProtobufConversionError; - fn try_from(value: protobuf::RpcTransaction) -> Result { - Ok(RpcTransactionWrapper(RpcTransaction::try_from(value)?)) - } -} -impl From for protobuf::RpcTransaction { - fn from(value: RpcTransactionWrapper) -> Self { - protobuf::RpcTransaction::from(value.0) - } -} +const DEPRECATED_RESOURCE_BOUNDS_ERROR: ProtobufConversionError = + ProtobufConversionError::MissingField { field_description: "ResourceBounds::l1_data_gas" }; -impl TryFrom for RpcTransaction { +impl TryFrom for RpcTransaction { type Error = ProtobufConversionError; - fn try_from(value: protobuf::RpcTransaction) -> Result { - let txn = value.txn.ok_or(ProtobufConversionError::MissingField { - field_description: "RpcTransaction::txn", - })?; + fn try_from(value: protobuf::MempoolTransaction) -> Result { + let txn = value.txn.ok_or(missing("RpcTransaction::txn"))?; Ok(match txn { - protobuf::rpc_transaction::Txn::DeclareV3(txn) => { + protobuf::mempool_transaction::Txn::DeclareV3(txn) => { RpcTransaction::Declare(RpcDeclareTransaction::V3(txn.try_into()?)) } - protobuf::rpc_transaction::Txn::DeployAccountV3(txn) => { + protobuf::mempool_transaction::Txn::DeployAccountV3(txn) => { RpcTransaction::DeployAccount(RpcDeployAccountTransaction::V3(txn.try_into()?)) } - protobuf::rpc_transaction::Txn::InvokeV3(txn) => { + protobuf::mempool_transaction::Txn::InvokeV3(txn) => { RpcTransaction::Invoke(RpcInvokeTransaction::V3(txn.try_into()?)) } }) } } -impl From for protobuf::RpcTransaction { +impl From for protobuf::MempoolTransaction { fn from(value: RpcTransaction) -> Self { match value { - RpcTransaction::Declare(RpcDeclareTransaction::V3(txn)) => protobuf::RpcTransaction { - txn: Some(protobuf::rpc_transaction::Txn::DeclareV3(txn.into())), - }, + RpcTransaction::Declare(RpcDeclareTransaction::V3(txn)) => { + protobuf::MempoolTransaction { + txn: Some(protobuf::mempool_transaction::Txn::DeclareV3(txn.into())), + // TODO(alonl): Consider removing transaction hash from protobuf + transaction_hash: None, + } + } RpcTransaction::DeployAccount(RpcDeployAccountTransaction::V3(txn)) => { - protobuf::RpcTransaction { - txn: Some(protobuf::rpc_transaction::Txn::DeployAccountV3(txn.into())), + protobuf::MempoolTransaction { + txn: Some(protobuf::mempool_transaction::Txn::DeployAccountV3(txn.into())), + // TODO(alonl): Consider removing transaction hash from protobuf + transaction_hash: None, + } + } + RpcTransaction::Invoke(RpcInvokeTransaction::V3(txn)) => { + protobuf::MempoolTransaction { + txn: Some(protobuf::mempool_transaction::Txn::InvokeV3(txn.into())), + // TODO(alonl): Consider removing transaction hash from protobuf + transaction_hash: None, } } - RpcTransaction::Invoke(RpcInvokeTransaction::V3(txn)) => protobuf::RpcTransaction { - txn: Some(protobuf::rpc_transaction::Txn::InvokeV3(txn.into())), - }, } } } -impl TryFrom for RpcDeclareTransactionV3 { +impl TryFrom for RpcTransactionBatch { type Error = ProtobufConversionError; - fn try_from(value: protobuf::rpc_transaction::DeclareV3) -> Result { - let declare_v3 = value.declare_v3.ok_or(ProtobufConversionError::MissingField { - field_description: "DeclareV3::declare_v3", - })?; - let contract_class = value - .contract_class - .ok_or(ProtobufConversionError::MissingField { - field_description: "DeclareV3::contract_class", - })? - .try_into()?; - let DeclareTransactionV3 { - sender_address, - compiled_class_hash, - signature, - nonce, - resource_bounds, - class_hash: _, - tip, - paymaster_data, - account_deployment_data, - nonce_data_availability_mode, - fee_data_availability_mode, - } = declare_v3.try_into()?; + fn try_from(value: protobuf::MempoolTransactionBatch) -> Result { + Ok(RpcTransactionBatch( + value + .transactions + .into_iter() + .map(RpcTransaction::try_from) + .collect::>()?, + )) + } +} - let resource_bounds = match resource_bounds { - ValidResourceBounds::AllResources(resource_bounds) => resource_bounds, - ValidResourceBounds::L1Gas(resource_bounds) => AllResourceBounds { - l1_gas: resource_bounds, - l2_gas: Default::default(), - l1_data_gas: Default::default(), - }, - }; +impl From for protobuf::MempoolTransactionBatch { + fn from(value: RpcTransactionBatch) -> Self { + protobuf::MempoolTransactionBatch { + transactions: value.0.into_iter().map(protobuf::MempoolTransaction::from).collect(), + } + } +} - Ok(Self { - sender_address, - compiled_class_hash, - signature, - nonce, - contract_class, - resource_bounds, - tip, - paymaster_data, - account_deployment_data, - nonce_data_availability_mode, - fee_data_availability_mode, - }) +impl TryFrom for RpcDeployAccountTransactionV3 { + type Error = ProtobufConversionError; + fn try_from(value: protobuf::DeployAccountV3) -> Result { + let snapi_deploy_account: DeployAccountTransactionV3 = value.try_into()?; + // This conversion can fail only if the resource_bounds are not AllResources. + snapi_deploy_account.try_into().map_err(|_| DEPRECATED_RESOURCE_BOUNDS_ERROR) } } -impl From for protobuf::rpc_transaction::DeclareV3 { - fn from(value: RpcDeclareTransactionV3) -> Self { - let RpcDeclareTransactionV3 { - sender_address, - compiled_class_hash, - signature, - nonce, - contract_class, - resource_bounds, - tip, - paymaster_data, - account_deployment_data, - nonce_data_availability_mode, - fee_data_availability_mode, - } = value; - let declare_v3 = DeclareTransactionV3 { - resource_bounds: ValidResourceBounds::AllResources(resource_bounds), - tip, - signature, - nonce, - // TODO(Eitan): refactor the protobuf transaction to not have class_hash - class_hash: Default::default(), - compiled_class_hash, - sender_address, - nonce_data_availability_mode, - fee_data_availability_mode, - paymaster_data, - account_deployment_data, - }; - Self { contract_class: Some(contract_class.into()), declare_v3: Some(declare_v3.into()) } +impl From for protobuf::DeployAccountV3 { + fn from(value: RpcDeployAccountTransactionV3) -> Self { + let snapi_deploy_account: DeployAccountTransactionV3 = value.into(); + snapi_deploy_account.into() } } -impl TryFrom for RpcDeployAccountTransactionV3 { +impl TryFrom for RpcInvokeTransactionV3 { type Error = ProtobufConversionError; - fn try_from(value: protobuf::transaction::DeployAccountV3) -> Result { - let resource_bounds = value - .resource_bounds - .clone() - .ok_or(ProtobufConversionError::MissingField { - field_description: "DeployAccountV3::resource_bounds", - })? - .try_into()?; - let DeployAccountTransactionV3 { - resource_bounds: _, - tip, - signature, - nonce, - class_hash, - contract_address_salt, - constructor_calldata, - nonce_data_availability_mode, - fee_data_availability_mode, - paymaster_data, - } = value.try_into()?; + fn try_from(value: protobuf::InvokeV3) -> Result { + let snapi_invoke: InvokeTransactionV3 = value.try_into()?; + // This conversion can fail only if the resource_bounds are not AllResources. + snapi_invoke.try_into().map_err(|_| DEPRECATED_RESOURCE_BOUNDS_ERROR) + } +} - Ok(Self { - resource_bounds, - tip, - signature, - nonce, - class_hash, - contract_address_salt, - constructor_calldata, - nonce_data_availability_mode, - fee_data_availability_mode, - paymaster_data, - }) +impl From for protobuf::InvokeV3 { + fn from(value: RpcInvokeTransactionV3) -> Self { + let snapi_invoke: InvokeTransactionV3 = value.into(); + snapi_invoke.into() } } -impl From for protobuf::transaction::DeployAccountV3 { - fn from(value: RpcDeployAccountTransactionV3) -> Self { - let RpcDeployAccountTransactionV3 { - resource_bounds, - tip, - signature, - nonce, - class_hash, - contract_address_salt, - constructor_calldata, - nonce_data_availability_mode, - fee_data_availability_mode, - paymaster_data, - } = value; - DeployAccountTransactionV3 { - resource_bounds: ValidResourceBounds::AllResources(resource_bounds), - tip, - signature, - nonce, - class_hash, - contract_address_salt, - constructor_calldata, - nonce_data_availability_mode, - fee_data_availability_mode, - paymaster_data, - } - .into() +impl TryFrom for (DeclareTransactionV3Common, SierraContractClass) { + type Error = ProtobufConversionError; + fn try_from(value: protobuf::DeclareV3WithClass) -> Result { + let common = DeclareTransactionV3Common::try_from(value.common.ok_or( + ProtobufConversionError::MissingField { + field_description: "DeclareV3WithClass::common", + }, + )?)?; + let class: SierraContractClass = SierraContractClass::try_from(value.class.ok_or( + ProtobufConversionError::MissingField { + field_description: "DeclareV3WithClass::class", + }, + )?)?; + Ok((common, class)) + } +} + +impl From<(DeclareTransactionV3Common, SierraContractClass)> for protobuf::DeclareV3WithClass { + fn from(value: (DeclareTransactionV3Common, SierraContractClass)) -> Self { + Self { common: Some(value.0.into()), class: Some(value.1.into()) } } } -impl TryFrom for RpcInvokeTransactionV3 { +impl TryFrom for RpcDeclareTransactionV3 { type Error = ProtobufConversionError; - fn try_from(value: protobuf::transaction::InvokeV3) -> Result { - let resource_bounds = value - .resource_bounds - .clone() - .ok_or(ProtobufConversionError::MissingField { - field_description: "InvokeV3::resource_bounds", - })? - .try_into()?; - let InvokeTransactionV3 { - resource_bounds: _, - tip, - signature, - nonce, - sender_address, - calldata, - nonce_data_availability_mode, - fee_data_availability_mode, - paymaster_data, - account_deployment_data, - } = value.try_into()?; + fn try_from(value: protobuf::DeclareV3WithClass) -> Result { + let (common, class) = value.try_into()?; Ok(Self { - resource_bounds, - tip, - signature, - nonce, - sender_address, - calldata, - nonce_data_availability_mode, - fee_data_availability_mode, - paymaster_data, - account_deployment_data, + resource_bounds: match common.resource_bounds { + ValidResourceBounds::AllResources(resource_bounds) => resource_bounds, + _ => { + return Err(DEPRECATED_RESOURCE_BOUNDS_ERROR); + } + }, + sender_address: common.sender_address, + signature: common.signature, + nonce: common.nonce, + compiled_class_hash: common.compiled_class_hash, + contract_class: class, + tip: common.tip, + paymaster_data: common.paymaster_data, + account_deployment_data: common.account_deployment_data, + nonce_data_availability_mode: common.nonce_data_availability_mode, + fee_data_availability_mode: common.fee_data_availability_mode, }) } } -impl From for protobuf::transaction::InvokeV3 { - fn from(value: RpcInvokeTransactionV3) -> Self { - let RpcInvokeTransactionV3 { - resource_bounds, - tip, - signature, - nonce, - sender_address, - calldata, - nonce_data_availability_mode, - fee_data_availability_mode, - paymaster_data, - account_deployment_data, - } = value; - InvokeTransactionV3 { - resource_bounds: ValidResourceBounds::AllResources(resource_bounds), - tip, - signature, - nonce, - sender_address, - calldata, - nonce_data_availability_mode, - fee_data_availability_mode, - paymaster_data, - account_deployment_data, - } - .into() +impl From for protobuf::DeclareV3WithClass { + fn from(value: RpcDeclareTransactionV3) -> Self { + let snapi_declare = DeclareTransactionV3Common { + resource_bounds: ValidResourceBounds::AllResources(value.resource_bounds), + sender_address: value.sender_address, + signature: value.signature, + nonce: value.nonce, + compiled_class_hash: value.compiled_class_hash, + tip: value.tip, + paymaster_data: value.paymaster_data, + account_deployment_data: value.account_deployment_data, + nonce_data_availability_mode: value.nonce_data_availability_mode, + fee_data_availability_mode: value.fee_data_availability_mode, + }; + (snapi_declare, value.contract_class).into() } } @@ -303,23 +196,11 @@ impl TryFrom for AllResourceBounds { type Error = ProtobufConversionError; fn try_from(value: protobuf::ResourceBounds) -> Result { Ok(Self { - l1_gas: value - .l1_gas - .ok_or(ProtobufConversionError::MissingField { - field_description: "ResourceBounds::l1_gas", - })? - .try_into()?, - l2_gas: value - .l2_gas - .ok_or(ProtobufConversionError::MissingField { - field_description: "ResourceBounds::l2_gas", - })? - .try_into()?, + l1_gas: value.l1_gas.ok_or(missing("ResourceBounds::l1_gas"))?.try_into()?, + l2_gas: value.l2_gas.ok_or(missing("ResourceBounds::l2_gas"))?.try_into()?, l1_data_gas: value .l1_data_gas - .ok_or(ProtobufConversionError::MissingField { - field_description: "ResourceBounds::l1_data_gas", - })? + .ok_or(missing("ResourceBounds::l1_data_gas"))? .try_into()?, }) } @@ -330,63 +211,3 @@ impl From for protobuf::ResourceBounds { ValidResourceBounds::AllResources(value).into() } } - -impl TryFrom for ContractClass { - type Error = ProtobufConversionError; - fn try_from(value: protobuf::Cairo1Class) -> Result { - let sierra_program = - value.program.into_iter().map(Felt::try_from).collect::, _>>()?; - let contract_class_version = value.contract_class_version; - let entry_points = value.entry_points.ok_or(ProtobufConversionError::MissingField { - field_description: "Cairo1Class::entry_points_by_type", - })?; - let entry_points_by_type = EntryPointByType { - constructor: entry_points - .constructors - .into_iter() - .map(EntryPoint::try_from) - .collect::, _>>()?, - external: entry_points - .externals - .into_iter() - .map(EntryPoint::try_from) - .collect::, _>>()?, - l1handler: entry_points - .l1_handlers - .into_iter() - .map(EntryPoint::try_from) - .collect::, _>>()?, - }; - let abi = value.abi; - Ok(Self { sierra_program, contract_class_version, entry_points_by_type, abi }) - } -} - -impl From for protobuf::Cairo1Class { - fn from(value: ContractClass) -> Self { - let program = value.sierra_program.into_iter().map(Felt252::from).collect(); - let contract_class_version = value.contract_class_version; - let entry_points = protobuf::Cairo1EntryPoints { - constructors: value - .entry_points_by_type - .constructor - .into_iter() - .map(protobuf::SierraEntryPoint::from) - .collect(), - externals: value - .entry_points_by_type - .external - .into_iter() - .map(protobuf::SierraEntryPoint::from) - .collect(), - l1_handlers: value - .entry_points_by_type - .l1handler - .into_iter() - .map(protobuf::SierraEntryPoint::from) - .collect(), - }; - let abi = value.abi; - Self { program, contract_class_version, entry_points: Some(entry_points), abi } - } -} diff --git a/crates/papyrus_protobuf/src/converters/rpc_transaction_test.rs b/crates/papyrus_protobuf/src/converters/rpc_transaction_test.rs index 081cbf19105..b4d55364afc 100644 --- a/crates/papyrus_protobuf/src/converters/rpc_transaction_test.rs +++ b/crates/papyrus_protobuf/src/converters/rpc_transaction_test.rs @@ -13,7 +13,7 @@ use starknet_api::rpc_transaction::{ }; use starknet_api::transaction::fields::{AllResourceBounds, ResourceBounds}; -use crate::mempool::RpcTransactionWrapper; +use crate::mempool::RpcTransactionBatch; #[test] fn convert_declare_transaction_v3_to_vec_u8_and_back() { @@ -48,10 +48,10 @@ fn convert_deploy_account_transaction_v3_to_vec_u8_and_back() { } fn assert_transaction_to_vec_u8_and_back(transaction: RpcTransaction) { - let data = RpcTransactionWrapper(transaction.clone()); + let data = RpcTransactionBatch(vec![transaction.clone()]); let bytes_data = Vec::::from(data); - let res_data = RpcTransactionWrapper::try_from(bytes_data).unwrap(); - assert_eq!(RpcTransactionWrapper(transaction), res_data); + let res_data = RpcTransactionBatch::try_from(bytes_data).unwrap(); + assert_eq!(RpcTransactionBatch(vec![transaction]), res_data); } lazy_static! { diff --git a/crates/papyrus_protobuf/src/converters/state_diff.rs b/crates/papyrus_protobuf/src/converters/state_diff.rs index 070d85cc82d..3c120ec6a36 100644 --- a/crates/papyrus_protobuf/src/converters/state_diff.rs +++ b/crates/papyrus_protobuf/src/converters/state_diff.rs @@ -8,7 +8,7 @@ use starknet_api::data_availability::DataAvailabilityMode; use starknet_api::state::{StorageKey, ThinStateDiff}; use starknet_types_core::felt::Felt; -use super::common::volition_domain_to_enum_int; +use super::common::{missing, volition_domain_to_enum_int}; use super::ProtobufConversionError; use crate::sync::{ ContractDiff, @@ -35,9 +35,7 @@ impl TryFrom for DataOrFin { declared_class, )) => Ok(DataOrFin(Some(declared_class.try_into()?))), Some(protobuf::state_diffs_response::StateDiffMessage::Fin(_)) => Ok(DataOrFin(None)), - None => Err(ProtobufConversionError::MissingField { - field_description: "StateDiffsResponse::state_diff_message", - }), + None => Err(missing("StateDiffsResponse::state_diff_message")), } } } @@ -61,9 +59,7 @@ impl TryFrom for DataOrFin { )))), }, Some(protobuf::state_diffs_response::StateDiffMessage::Fin(_)) => Ok(DataOrFin(None)), - None => Err(ProtobufConversionError::MissingField { - field_description: "StateDiffsResponse::state_diff_message", - }), + None => Err(missing("StateDiffsResponse::state_diff_message")), } } } @@ -95,12 +91,7 @@ auto_impl_into_and_try_from_vec_u8!(DataOrFin, protobuf::StateDi impl TryFrom for ThinStateDiff { type Error = ProtobufConversionError; fn try_from(value: protobuf::ContractDiff) -> Result { - let contract_address = value - .address - .ok_or(ProtobufConversionError::MissingField { - field_description: "ContractDiff::address", - })? - .try_into()?; + let contract_address = value.address.ok_or(missing("ContractDiff::address"))?.try_into()?; let deployed_contracts = value .class_hash @@ -144,10 +135,6 @@ impl TryFrom for ThinStateDiff { // These two fields come from DeclaredClass messages. declared_classes: Default::default(), deprecated_declared_classes: Default::default(), - // The p2p specs doesn't separate replaced classes from deployed contracts. In RPC v0.8 - // the node will stop separating them as well. Until then nodes syncing from - // P2P won't be able to separate replaced classes from deployed contracts correctly - replaced_classes: Default::default(), }) } } @@ -155,16 +142,10 @@ impl TryFrom for ThinStateDiff { impl TryFrom for ThinStateDiff { type Error = ProtobufConversionError; fn try_from(value: protobuf::DeclaredClass) -> Result { - let class_hash = ClassHash( - value - .class_hash - .ok_or(ProtobufConversionError::MissingField { - field_description: "DeclaredClass::class_hash", - })? - .try_into()?, - ); + let class_hash = + ClassHash(value.class_hash.ok_or(missing("DeclaredClass::class_hash"))?.try_into()?); - // According to the P2P specs, if compiled_class_hash is missing, the declared class is a + // According to the p2p specs, if compiled_class_hash is missing, the declared class is a // cairo-0 class. match value.compiled_class_hash { Some(compiled_class_hash) => Ok(ThinStateDiff { @@ -185,9 +166,7 @@ impl TryFrom for ThinStateDiff { impl TryFrom for (StorageKey, Felt) { type Error = ProtobufConversionError; fn try_from(entry: protobuf::ContractStoredValue) -> Result { - let key_felt = Felt::try_from(entry.key.ok_or(ProtobufConversionError::MissingField { - field_description: "ContractStoredValue::key", - })?)?; + let key_felt = Felt::try_from(entry.key.ok_or(missing("ContractStoredValue::key"))?)?; let key = StorageKey(key_felt.try_into().map_err(|_| { ProtobufConversionError::OutOfRangeValue { // TODO(shahak): Check if the type in the protobuf of the field @@ -197,9 +176,7 @@ impl TryFrom for (StorageKey, Felt) { value_as_str: format!("{key_felt:?}"), } })?); - let value = Felt::try_from(entry.value.ok_or(ProtobufConversionError::MissingField { - field_description: "ContractStoredValue::value", - })?)?; + let value = Felt::try_from(entry.value.ok_or(missing("ContractStoredValue::value"))?)?; Ok((key, value)) } } @@ -216,12 +193,7 @@ impl TryFrom for StateDiffQuery { type Error = ProtobufConversionError; fn try_from(value: protobuf::StateDiffsRequest) -> Result { Ok(StateDiffQuery( - value - .iteration - .ok_or(ProtobufConversionError::MissingField { - field_description: "StateDiffsRequest::iteration", - })? - .try_into()?, + value.iteration.ok_or(missing("StateDiffsRequest::iteration"))?.try_into()?, )) } } @@ -244,12 +216,7 @@ auto_impl_into_and_try_from_vec_u8!(StateDiffQuery, protobuf::StateDiffsRequest) impl TryFrom for ContractDiff { type Error = ProtobufConversionError; fn try_from(value: protobuf::ContractDiff) -> Result { - let contract_address = value - .address - .ok_or(ProtobufConversionError::MissingField { - field_description: "ContractDiff::address", - })? - .try_into()?; + let contract_address = value.address.ok_or(missing("ContractDiff::address"))?.try_into()?; // class_hash can be None if the contract wasn't deployed in this block let class_hash = value @@ -293,20 +260,12 @@ impl From for protobuf::ContractDiff { impl TryFrom for DeclaredClass { type Error = ProtobufConversionError; fn try_from(value: protobuf::DeclaredClass) -> Result { - let class_hash = ClassHash( - value - .class_hash - .ok_or(ProtobufConversionError::MissingField { - field_description: "DeclaredClass::class_hash", - })? - .try_into()?, - ); + let class_hash = + ClassHash(value.class_hash.ok_or(missing("DeclaredClass::class_hash"))?.try_into()?); let compiled_class_hash = CompiledClassHash( value .compiled_class_hash - .ok_or(ProtobufConversionError::MissingField { - field_description: "DeclaredClass::compiled_class_hash", - })? + .ok_or(missing("DeclaredClass::compiled_class_hash"))? .try_into()?, ); Ok(DeclaredClass { class_hash, compiled_class_hash }) @@ -327,12 +286,7 @@ impl TryFrom for DeprecatedDeclaredClass { fn try_from(value: protobuf::DeclaredClass) -> Result { Ok(DeprecatedDeclaredClass { class_hash: ClassHash( - value - .class_hash - .ok_or(ProtobufConversionError::MissingField { - field_description: "DeclaredClass::class_hash", - })? - .try_into()?, + value.class_hash.ok_or(missing("DeclaredClass::class_hash"))?.try_into()?, ), }) } diff --git a/crates/papyrus_protobuf/src/converters/test_instances.rs b/crates/papyrus_protobuf/src/converters/test_instances.rs index 01c9c1903aa..58b15fa0fbc 100644 --- a/crates/papyrus_protobuf/src/converters/test_instances.rs +++ b/crates/papyrus_protobuf/src/converters/test_instances.rs @@ -1,12 +1,16 @@ +use std::fmt::Display; + use papyrus_test_utils::{auto_impl_get_test_instance, get_number_of_variants, GetTestInstance}; +use prost::DecodeError; use rand::Rng; use starknet_api::block::{BlockHash, BlockNumber}; +use starknet_api::consensus_transaction::ConsensusTransaction; use starknet_api::core::ContractAddress; -use starknet_api::transaction::{Transaction, TransactionHash}; +use starknet_api::data_availability::L1DataAvailabilityMode; +use super::ProtobufConversionError; use crate::consensus::{ - ConsensusMessage, - Proposal, + ConsensusBlockInfo, ProposalFin, ProposalInit, ProposalPart, @@ -18,18 +22,6 @@ use crate::consensus::{ }; auto_impl_get_test_instance! { - pub enum ConsensusMessage { - Proposal(Proposal) = 0, - Vote(Vote) = 1, - } - pub struct Proposal { - pub height: u64, - pub round: u32, - pub proposer: ContractAddress, - pub transactions: Vec, - pub block_hash: BlockHash, - pub valid_round: Option, - } pub struct Vote { pub vote_type: VoteType, pub height: u64, @@ -48,29 +40,81 @@ auto_impl_get_test_instance! { pub proposer: ContractAddress, } pub struct ProposalFin { - pub proposal_content_id: BlockHash, + pub proposal_commitment: BlockHash, } pub struct TransactionBatch { - pub transactions: Vec, - pub tx_hashes: Vec, + pub transactions: Vec, + } + pub struct ConsensusBlockInfo { + pub height: BlockNumber, + pub timestamp: u64, + pub builder: ContractAddress, + pub l1_da_mode: L1DataAvailabilityMode, + pub l2_gas_price_fri: u128, + pub l1_gas_price_wei: u128, + pub l1_data_gas_price_wei: u128, + pub eth_to_fri_rate: u128, } pub enum ProposalPart { Init(ProposalInit) = 0, Fin(ProposalFin) = 1, - Transactions(TransactionBatch) = 2, + BlockInfo(ConsensusBlockInfo) = 2, + Transactions(TransactionBatch) = 3, + } + +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct TestStreamId(pub u64); + +impl From for Vec { + fn from(value: TestStreamId) -> Self { + value.0.to_be_bytes().to_vec() } +} +impl TryFrom> for TestStreamId { + type Error = ProtobufConversionError; + fn try_from(bytes: Vec) -> Result { + if bytes.len() != 8 { + return Err(ProtobufConversionError::DecodeError(DecodeError::new("Invalid length"))); + }; + let mut array = [0; 8]; + array.copy_from_slice(&bytes); + Ok(TestStreamId(u64::from_be_bytes(array))) + } +} + +impl PartialOrd for TestStreamId { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for TestStreamId { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.0.cmp(&other.0) + } +} + +impl Display for TestStreamId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "TestStreamId({})", self.0) + } } // The auto_impl_get_test_instance macro does not work for StreamMessage because it has -// a generic type. TODO(guyn): try to make the macro work with generic types. -impl GetTestInstance for StreamMessage { +// a generic type. +// TODO(guyn): try to make the macro work with generic types. +impl GetTestInstance for StreamMessage { fn get_test_instance(rng: &mut rand_chacha::ChaCha8Rng) -> Self { let message = if rng.gen_bool(0.5) { - StreamMessageBody::Content(ConsensusMessage::Proposal(Proposal::get_test_instance(rng))) + StreamMessageBody::Content(ProposalPart::Transactions(TransactionBatch { + transactions: vec![ConsensusTransaction::get_test_instance(rng)], + })) } else { StreamMessageBody::Fin }; - Self { message, stream_id: 12, message_id: 47 } + Self { message, stream_id: TestStreamId(12), message_id: 47 } } } diff --git a/crates/papyrus_protobuf/src/converters/transaction.rs b/crates/papyrus_protobuf/src/converters/transaction.rs index 2e43b8ccf60..0119339ee7c 100644 --- a/crates/papyrus_protobuf/src/converters/transaction.rs +++ b/crates/papyrus_protobuf/src/converters/transaction.rs @@ -5,8 +5,15 @@ use std::convert::{TryFrom, TryInto}; use prost::Message; use starknet_api::block::GasPrice; +use starknet_api::consensus_transaction::ConsensusTransaction; use starknet_api::core::{ClassHash, CompiledClassHash, EntryPointSelector, Nonce}; use starknet_api::execution_resources::GasAmount; +use starknet_api::rpc_transaction::{ + RpcDeclareTransaction, + RpcDeployAccountTransaction, + RpcInvokeTransaction, + RpcTransaction, +}; use starknet_api::transaction::fields::{ AccountDeploymentData, AllResourceBounds, @@ -43,21 +50,21 @@ use starknet_types_core::felt::Felt; use super::common::{ enum_int_to_volition_domain, + missing, try_from_starkfelt_to_u128, try_from_starkfelt_to_u32, volition_domain_to_enum_int, }; use super::ProtobufConversionError; use crate::sync::{DataOrFin, Query, TransactionQuery}; +use crate::transaction::DeclareTransactionV3Common; use crate::{auto_impl_into_and_try_from_vec_u8, protobuf}; impl TryFrom for DataOrFin { type Error = ProtobufConversionError; fn try_from(value: protobuf::TransactionsResponse) -> Result { let Some(transaction_message) = value.transaction_message else { - return Err(ProtobufConversionError::MissingField { - field_description: "TransactionsResponse::transaction_message", - }); + return Err(missing("TransactionsResponse::transaction_message")); }; match transaction_message { @@ -102,16 +109,12 @@ impl TryFrom for FullTransaction { type Error = ProtobufConversionError; fn try_from(value: protobuf::TransactionWithReceipt) -> Result { let (transaction, transaction_hash) = <(Transaction, TransactionHash)>::try_from( - value.transaction.ok_or(ProtobufConversionError::MissingField { - field_description: "TransactionWithReceipt::transaction", - })?, + value.transaction.ok_or(missing("TransactionWithReceipt::transaction"))?, )?; - let transaction_output = TransactionOutput::try_from(value.receipt.ok_or( - ProtobufConversionError::MissingField { - field_description: "TransactionWithReceipt::output", - }, - )?)?; + let transaction_output = TransactionOutput::try_from( + value.receipt.ok_or(missing("TransactionWithReceipt::output"))?, + )?; Ok(FullTransaction { transaction, transaction_output, transaction_hash }) } } @@ -126,239 +129,135 @@ impl From for protobuf::TransactionWithReceipt { } } -impl TryFrom for (Transaction, TransactionHash) { +// Used when converting a protobuf::TransactionWithReceipt to a FullTransaction. +impl TryFrom for (Transaction, TransactionHash) { type Error = ProtobufConversionError; - fn try_from(value: protobuf::Transaction) -> Result { - let txn = value.txn.ok_or(ProtobufConversionError::MissingField { - field_description: "Transaction::txn", - })?; + fn try_from(value: protobuf::TransactionInBlock) -> Result { let tx_hash = value .transaction_hash - .ok_or(ProtobufConversionError::MissingField { - field_description: "Transaction::transaction_hash", - })? + .clone() + .ok_or(missing("Transaction::transaction_hash"))? .try_into() .map(TransactionHash)?; - - let txn = match txn { - protobuf::transaction::Txn::DeclareV0(declare_v0) => Transaction::Declare( + let txn = value.txn.ok_or(missing("Transaction::txn"))?; + let transaction: Transaction = match txn { + protobuf::transaction_in_block::Txn::DeclareV0(declare_v0) => Transaction::Declare( DeclareTransaction::V0(DeclareTransactionV0V1::try_from(declare_v0)?), ), - protobuf::transaction::Txn::DeclareV1(declare_v1) => Transaction::Declare( + protobuf::transaction_in_block::Txn::DeclareV1(declare_v1) => Transaction::Declare( DeclareTransaction::V1(DeclareTransactionV0V1::try_from(declare_v1)?), ), - protobuf::transaction::Txn::DeclareV2(declare_v2) => Transaction::Declare( + protobuf::transaction_in_block::Txn::DeclareV2(declare_v2) => Transaction::Declare( DeclareTransaction::V2(DeclareTransactionV2::try_from(declare_v2)?), ), - protobuf::transaction::Txn::DeclareV3(declare_v3) => Transaction::Declare( + protobuf::transaction_in_block::Txn::DeclareV3(declare_v3) => Transaction::Declare( DeclareTransaction::V3(DeclareTransactionV3::try_from(declare_v3)?), ), - protobuf::transaction::Txn::Deploy(deploy) => { + protobuf::transaction_in_block::Txn::Deploy(deploy) => { Transaction::Deploy(DeployTransaction::try_from(deploy)?) } - protobuf::transaction::Txn::DeployAccountV1(deploy_account_v1) => { + protobuf::transaction_in_block::Txn::DeployAccountV1(deploy_account_v1) => { Transaction::DeployAccount(DeployAccountTransaction::V1( DeployAccountTransactionV1::try_from(deploy_account_v1)?, )) } - protobuf::transaction::Txn::DeployAccountV3(deploy_account_v3) => { + protobuf::transaction_in_block::Txn::DeployAccountV3(deploy_account_v3) => { Transaction::DeployAccount(DeployAccountTransaction::V3( DeployAccountTransactionV3::try_from(deploy_account_v3)?, )) } - protobuf::transaction::Txn::InvokeV0(invoke_v0) => Transaction::Invoke( + protobuf::transaction_in_block::Txn::InvokeV0(invoke_v0) => Transaction::Invoke( InvokeTransaction::V0(InvokeTransactionV0::try_from(invoke_v0)?), ), - protobuf::transaction::Txn::InvokeV1(invoke_v1) => Transaction::Invoke( + protobuf::transaction_in_block::Txn::InvokeV1(invoke_v1) => Transaction::Invoke( InvokeTransaction::V1(InvokeTransactionV1::try_from(invoke_v1)?), ), - protobuf::transaction::Txn::InvokeV3(invoke_v3) => Transaction::Invoke( + protobuf::transaction_in_block::Txn::InvokeV3(invoke_v3) => Transaction::Invoke( InvokeTransaction::V3(InvokeTransactionV3::try_from(invoke_v3)?), ), - protobuf::transaction::Txn::L1Handler(l1_handler) => { + protobuf::transaction_in_block::Txn::L1Handler(l1_handler) => { Transaction::L1Handler(L1HandlerTransaction::try_from(l1_handler)?) } }; - Ok((txn, tx_hash)) + Ok((transaction, tx_hash)) } } -// TODO(eitan): remove when consensus uses BroadcastedTransaction -impl TryFrom for Transaction { - type Error = ProtobufConversionError; - fn try_from(value: protobuf::Transaction) -> Result { - let txn = value.txn.ok_or(ProtobufConversionError::MissingField { - field_description: "Transaction::txn", - })?; - Ok(match txn { - protobuf::transaction::Txn::DeclareV0(declare_v0) => Transaction::Declare( - DeclareTransaction::V0(DeclareTransactionV0V1::try_from(declare_v0)?), - ), - protobuf::transaction::Txn::DeclareV1(declare_v1) => Transaction::Declare( - DeclareTransaction::V1(DeclareTransactionV0V1::try_from(declare_v1)?), - ), - protobuf::transaction::Txn::DeclareV2(declare_v2) => Transaction::Declare( - DeclareTransaction::V2(DeclareTransactionV2::try_from(declare_v2)?), - ), - protobuf::transaction::Txn::DeclareV3(declare_v3) => Transaction::Declare( - DeclareTransaction::V3(DeclareTransactionV3::try_from(declare_v3)?), - ), - protobuf::transaction::Txn::Deploy(deploy) => { - Transaction::Deploy(DeployTransaction::try_from(deploy)?) +impl From<(Transaction, TransactionHash)> for protobuf::TransactionInBlock { + fn from(value: (Transaction, TransactionHash)) -> Self { + let tx_hash = Some(value.1.0.into()); + match value.0 { + Transaction::Declare(DeclareTransaction::V0(declare_v0)) => { + protobuf::TransactionInBlock { + txn: Some(protobuf::transaction_in_block::Txn::DeclareV0(declare_v0.into())), + transaction_hash: tx_hash, + } } - protobuf::transaction::Txn::DeployAccountV1(deploy_account_v1) => { - Transaction::DeployAccount(DeployAccountTransaction::V1( - DeployAccountTransactionV1::try_from(deploy_account_v1)?, - )) + Transaction::Declare(DeclareTransaction::V1(declare_v1)) => { + protobuf::TransactionInBlock { + txn: Some(protobuf::transaction_in_block::Txn::DeclareV1(declare_v1.into())), + transaction_hash: tx_hash, + } } - protobuf::transaction::Txn::DeployAccountV3(deploy_account_v3) => { - Transaction::DeployAccount(DeployAccountTransaction::V3( - DeployAccountTransactionV3::try_from(deploy_account_v3)?, - )) + Transaction::Declare(DeclareTransaction::V2(declare_v2)) => { + protobuf::TransactionInBlock { + txn: Some(protobuf::transaction_in_block::Txn::DeclareV2(declare_v2.into())), + transaction_hash: tx_hash, + } } - protobuf::transaction::Txn::InvokeV0(invoke_v0) => Transaction::Invoke( - InvokeTransaction::V0(InvokeTransactionV0::try_from(invoke_v0)?), - ), - protobuf::transaction::Txn::InvokeV1(invoke_v1) => Transaction::Invoke( - InvokeTransaction::V1(InvokeTransactionV1::try_from(invoke_v1)?), - ), - protobuf::transaction::Txn::InvokeV3(invoke_v3) => Transaction::Invoke( - InvokeTransaction::V3(InvokeTransactionV3::try_from(invoke_v3)?), - ), - protobuf::transaction::Txn::L1Handler(l1_handler) => { - Transaction::L1Handler(L1HandlerTransaction::try_from(l1_handler)?) + Transaction::Declare(DeclareTransaction::V3(declare_v3)) => { + protobuf::TransactionInBlock { + txn: Some(protobuf::transaction_in_block::Txn::DeclareV3(declare_v3.into())), + transaction_hash: tx_hash, + } } - }) - } -} -impl From<(Transaction, TransactionHash)> for protobuf::Transaction { - fn from(value: (Transaction, TransactionHash)) -> Self { - let txn = value.0; - let txn_hash = value.1; - match txn { - Transaction::Declare(DeclareTransaction::V0(declare_v0)) => protobuf::Transaction { - txn: Some(protobuf::transaction::Txn::DeclareV0(declare_v0.into())), - transaction_hash: Some(txn_hash.0.into()), - }, - Transaction::Declare(DeclareTransaction::V1(declare_v1)) => protobuf::Transaction { - txn: Some(protobuf::transaction::Txn::DeclareV1(declare_v1.into())), - transaction_hash: Some(txn_hash.0.into()), - }, - Transaction::Declare(DeclareTransaction::V2(declare_v2)) => protobuf::Transaction { - txn: Some(protobuf::transaction::Txn::DeclareV2(declare_v2.into())), - transaction_hash: Some(txn_hash.0.into()), - }, - Transaction::Declare(DeclareTransaction::V3(declare_v3)) => protobuf::Transaction { - txn: Some(protobuf::transaction::Txn::DeclareV3(declare_v3.into())), - transaction_hash: Some(txn_hash.0.into()), - }, - Transaction::Deploy(deploy) => protobuf::Transaction { - txn: Some(protobuf::transaction::Txn::Deploy(deploy.into())), - transaction_hash: Some(txn_hash.0.into()), + Transaction::Deploy(deploy) => protobuf::TransactionInBlock { + txn: Some(protobuf::transaction_in_block::Txn::Deploy(deploy.into())), + transaction_hash: tx_hash, }, Transaction::DeployAccount(deploy_account) => match deploy_account { - DeployAccountTransaction::V1(deploy_account_v1) => protobuf::Transaction { - txn: Some(protobuf::transaction::Txn::DeployAccountV1( + DeployAccountTransaction::V1(deploy_account_v1) => protobuf::TransactionInBlock { + txn: Some(protobuf::transaction_in_block::Txn::DeployAccountV1( deploy_account_v1.into(), )), - transaction_hash: Some(txn_hash.0.into()), + transaction_hash: tx_hash, }, - DeployAccountTransaction::V3(deploy_account_v3) => protobuf::Transaction { - txn: Some(protobuf::transaction::Txn::DeployAccountV3( + DeployAccountTransaction::V3(deploy_account_v3) => protobuf::TransactionInBlock { + txn: Some(protobuf::transaction_in_block::Txn::DeployAccountV3( deploy_account_v3.into(), )), - transaction_hash: Some(txn_hash.0.into()), + transaction_hash: tx_hash, }, }, Transaction::Invoke(invoke) => match invoke { - InvokeTransaction::V0(invoke_v0) => protobuf::Transaction { - txn: Some(protobuf::transaction::Txn::InvokeV0(invoke_v0.into())), - transaction_hash: Some(txn_hash.0.into()), + InvokeTransaction::V0(invoke_v0) => protobuf::TransactionInBlock { + txn: Some(protobuf::transaction_in_block::Txn::InvokeV0(invoke_v0.into())), + transaction_hash: tx_hash, }, - InvokeTransaction::V1(invoke_v1) => protobuf::Transaction { - txn: Some(protobuf::transaction::Txn::InvokeV1(invoke_v1.into())), - transaction_hash: Some(txn_hash.0.into()), + InvokeTransaction::V1(invoke_v1) => protobuf::TransactionInBlock { + txn: Some(protobuf::transaction_in_block::Txn::InvokeV1(invoke_v1.into())), + transaction_hash: tx_hash, }, - InvokeTransaction::V3(invoke_v3) => protobuf::Transaction { - txn: Some(protobuf::transaction::Txn::InvokeV3(invoke_v3.into())), - transaction_hash: Some(txn_hash.0.into()), + InvokeTransaction::V3(invoke_v3) => protobuf::TransactionInBlock { + txn: Some(protobuf::transaction_in_block::Txn::InvokeV3(invoke_v3.into())), + transaction_hash: tx_hash, }, }, - Transaction::L1Handler(l1_handler) => protobuf::Transaction { - txn: Some(protobuf::transaction::Txn::L1Handler(l1_handler.into())), - transaction_hash: Some(txn_hash.0.into()), + Transaction::L1Handler(l1_handler) => protobuf::TransactionInBlock { + txn: Some(protobuf::transaction_in_block::Txn::L1Handler(l1_handler.into())), + transaction_hash: tx_hash, }, } } } -// TODO(eitan): remove when consensus uses BroadcastedTransaction -impl From for protobuf::Transaction { - fn from(value: Transaction) -> Self { - match value { - Transaction::Declare(DeclareTransaction::V0(declare_v0)) => protobuf::Transaction { - txn: Some(protobuf::transaction::Txn::DeclareV0(declare_v0.into())), - transaction_hash: None, - }, - Transaction::Declare(DeclareTransaction::V1(declare_v1)) => protobuf::Transaction { - txn: Some(protobuf::transaction::Txn::DeclareV1(declare_v1.into())), - transaction_hash: None, - }, - Transaction::Declare(DeclareTransaction::V2(declare_v2)) => protobuf::Transaction { - txn: Some(protobuf::transaction::Txn::DeclareV2(declare_v2.into())), - transaction_hash: None, - }, - Transaction::Declare(DeclareTransaction::V3(declare_v3)) => protobuf::Transaction { - txn: Some(protobuf::transaction::Txn::DeclareV3(declare_v3.into())), - transaction_hash: None, - }, - Transaction::Deploy(deploy) => protobuf::Transaction { - txn: Some(protobuf::transaction::Txn::Deploy(deploy.into())), - transaction_hash: None, - }, - Transaction::DeployAccount(deploy_account) => match deploy_account { - DeployAccountTransaction::V1(deploy_account_v1) => protobuf::Transaction { - txn: Some(protobuf::transaction::Txn::DeployAccountV1( - deploy_account_v1.into(), - )), - transaction_hash: None, - }, - DeployAccountTransaction::V3(deploy_account_v3) => protobuf::Transaction { - txn: Some(protobuf::transaction::Txn::DeployAccountV3( - deploy_account_v3.into(), - )), - transaction_hash: None, - }, - }, - Transaction::Invoke(invoke) => match invoke { - InvokeTransaction::V0(invoke_v0) => protobuf::Transaction { - txn: Some(protobuf::transaction::Txn::InvokeV0(invoke_v0.into())), - transaction_hash: None, - }, - InvokeTransaction::V1(invoke_v1) => protobuf::Transaction { - txn: Some(protobuf::transaction::Txn::InvokeV1(invoke_v1.into())), - transaction_hash: None, - }, - InvokeTransaction::V3(invoke_v3) => protobuf::Transaction { - txn: Some(protobuf::transaction::Txn::InvokeV3(invoke_v3.into())), - transaction_hash: None, - }, - }, - Transaction::L1Handler(l1_handler) => protobuf::Transaction { - txn: Some(protobuf::transaction::Txn::L1Handler(l1_handler.into())), - transaction_hash: None, - }, - } - } -} - -impl TryFrom for DeployAccountTransactionV1 { +impl TryFrom for DeployAccountTransactionV1 { type Error = ProtobufConversionError; - fn try_from(value: protobuf::transaction::DeployAccountV1) -> Result { + fn try_from( + value: protobuf::transaction_in_block::DeployAccountV1, + ) -> Result { let max_fee_felt = - Felt::try_from(value.max_fee.ok_or(ProtobufConversionError::MissingField { - field_description: "DeployAccountV1::max_fee", - })?)?; + Felt::try_from(value.max_fee.ok_or(missing("DeployAccountV1::max_fee"))?)?; let max_fee = Fee(try_from_starkfelt_to_u128(max_fee_felt).map_err(|_| { ProtobufConversionError::OutOfRangeValue { type_description: "u128", @@ -369,40 +268,20 @@ impl TryFrom for DeployAccountTransactio let signature = TransactionSignature( value .signature - .ok_or(ProtobufConversionError::MissingField { - field_description: "DeployAccountV1::signature", - })? + .ok_or(missing("DeployAccountV1::signature"))? .parts .into_iter() .map(Felt::try_from) .collect::, _>>()?, ); - let nonce = Nonce( - value - .nonce - .ok_or(ProtobufConversionError::MissingField { - field_description: "DeployAccountV1::nonce", - })? - .try_into()?, - ); + let nonce = Nonce(value.nonce.ok_or(missing("DeployAccountV1::nonce"))?.try_into()?); - let class_hash = ClassHash( - value - .class_hash - .ok_or(ProtobufConversionError::MissingField { - field_description: "DeployAccountV1::class_hash", - })? - .try_into()?, - ); + let class_hash = + ClassHash(value.class_hash.ok_or(missing("DeployAccountV1::class_hash"))?.try_into()?); let contract_address_salt = ContractAddressSalt( - value - .address_salt - .ok_or(ProtobufConversionError::MissingField { - field_description: "DeployAccountV1::address_salt", - })? - .try_into()?, + value.address_salt.ok_or(missing("DeployAccountV1::address_salt"))?.try_into()?, ); let constructor_calldata = @@ -421,7 +300,7 @@ impl TryFrom for DeployAccountTransactio } } -impl From for protobuf::transaction::DeployAccountV1 { +impl From for protobuf::transaction_in_block::DeployAccountV1 { fn from(value: DeployAccountTransactionV1) -> Self { Self { max_fee: Some(Felt::from(value.max_fee.0).into()), @@ -441,54 +320,32 @@ impl From for protobuf::transaction::DeployAccountV1 } } -impl TryFrom for DeployAccountTransactionV3 { +impl TryFrom for DeployAccountTransactionV3 { type Error = ProtobufConversionError; - fn try_from(value: protobuf::transaction::DeployAccountV3) -> Result { - let resource_bounds = ValidResourceBounds::try_from(value.resource_bounds.ok_or( - ProtobufConversionError::MissingField { - field_description: "DeployAccountV3::resource_bounds", - }, - )?)?; + fn try_from(value: protobuf::DeployAccountV3) -> Result { + let resource_bounds = ValidResourceBounds::try_from( + value.resource_bounds.ok_or(missing("DeployAccountV3::resource_bounds"))?, + )?; let tip = Tip(value.tip); let signature = TransactionSignature( value .signature - .ok_or(ProtobufConversionError::MissingField { - field_description: "DeployAccountV3::signature", - })? + .ok_or(missing("DeployAccountV3::signature"))? .parts .into_iter() .map(Felt::try_from) .collect::, _>>()?, ); - let nonce = Nonce( - value - .nonce - .ok_or(ProtobufConversionError::MissingField { - field_description: "DeployAccountV3::nonce", - })? - .try_into()?, - ); + let nonce = Nonce(value.nonce.ok_or(missing("DeployAccountV3::nonce"))?.try_into()?); - let class_hash = ClassHash( - value - .class_hash - .ok_or(ProtobufConversionError::MissingField { - field_description: "DeployAccountV3::class_hash", - })? - .try_into()?, - ); + let class_hash = + ClassHash(value.class_hash.ok_or(missing("DeployAccountV3::class_hash"))?.try_into()?); let contract_address_salt = ContractAddressSalt( - value - .address_salt - .ok_or(ProtobufConversionError::MissingField { - field_description: "DeployAccountV3::address_salt", - })? - .try_into()?, + value.address_salt.ok_or(missing("DeployAccountV3::address_salt"))?.try_into()?, ); let constructor_calldata = @@ -521,7 +378,7 @@ impl TryFrom for DeployAccountTransactio } } -impl From for protobuf::transaction::DeployAccountV3 { +impl From for protobuf::DeployAccountV3 { fn from(value: DeployAccountTransactionV3) -> Self { Self { resource_bounds: Some(protobuf::ResourceBounds::from(value.resource_bounds)), @@ -558,14 +415,10 @@ impl TryFrom for ValidResourceBounds { type Error = ProtobufConversionError; fn try_from(value: protobuf::ResourceBounds) -> Result { let Some(l1_gas) = value.l1_gas else { - return Err(ProtobufConversionError::MissingField { - field_description: "ResourceBounds::l1_gas", - }); + return Err(missing("ResourceBounds::l1_gas")); }; let Some(l2_gas) = value.l2_gas else { - return Err(ProtobufConversionError::MissingField { - field_description: "ResourceBounds::l2_gas", - }); + return Err(missing("ResourceBounds::l2_gas")); }; // TODO(Shahak): Assert data gas is not none once we remove support for 0.13.2. let l1_data_gas = value.l1_data_gas.unwrap_or_default(); @@ -584,11 +437,11 @@ impl TryFrom for ResourceBounds { type Error = ProtobufConversionError; fn try_from(value: protobuf::ResourceLimits) -> Result { let max_amount = value.max_amount; - let max_price_per_unit_felt = Felt::try_from(value.max_price_per_unit.ok_or( - ProtobufConversionError::MissingField { - field_description: "ResourceBounds::ResourceLimits::max_price_per_unit", - }, - )?)?; + let max_price_per_unit_felt = Felt::try_from( + value + .max_price_per_unit + .ok_or(missing("ResourceBounds::ResourceLimits::max_price_per_unit"))?, + )?; let max_price_per_unit = try_from_starkfelt_to_u128(max_price_per_unit_felt).map_err(|_| { ProtobufConversionError::OutOfRangeValue { @@ -633,13 +486,10 @@ impl From for protobuf::ResourceBounds { } } -impl TryFrom for InvokeTransactionV0 { +impl TryFrom for InvokeTransactionV0 { type Error = ProtobufConversionError; - fn try_from(value: protobuf::transaction::InvokeV0) -> Result { - let max_fee_felt = - Felt::try_from(value.max_fee.ok_or(ProtobufConversionError::MissingField { - field_description: "InvokeV0::max_fee", - })?)?; + fn try_from(value: protobuf::transaction_in_block::InvokeV0) -> Result { + let max_fee_felt = Felt::try_from(value.max_fee.ok_or(missing("InvokeV0::max_fee"))?)?; let max_fee = Fee(try_from_starkfelt_to_u128(max_fee_felt).map_err(|_| { ProtobufConversionError::OutOfRangeValue { type_description: "u128", @@ -650,27 +500,18 @@ impl TryFrom for InvokeTransactionV0 { let signature = TransactionSignature( value .signature - .ok_or(ProtobufConversionError::MissingField { - field_description: "InvokeV0::signature", - })? + .ok_or(missing("InvokeV0::signature"))? .parts .into_iter() .map(Felt::try_from) .collect::, _>>()?, ); - let contract_address = value - .address - .ok_or(ProtobufConversionError::MissingField { - field_description: "InvokeV0::address", - })? - .try_into()?; + let contract_address = value.address.ok_or(missing("InvokeV0::address"))?.try_into()?; - let entry_point_selector_felt = Felt::try_from(value.entry_point_selector.ok_or( - ProtobufConversionError::MissingField { - field_description: "InvokeV0::entry_point_selector", - }, - )?)?; + let entry_point_selector_felt = Felt::try_from( + value.entry_point_selector.ok_or(missing("InvokeV0::entry_point_selector"))?, + )?; let entry_point_selector = EntryPointSelector(entry_point_selector_felt); let calldata = @@ -682,7 +523,7 @@ impl TryFrom for InvokeTransactionV0 { } } -impl From for protobuf::transaction::InvokeV0 { +impl From for protobuf::transaction_in_block::InvokeV0 { fn from(value: InvokeTransactionV0) -> Self { Self { max_fee: Some(Felt::from(value.max_fee.0).into()), @@ -696,13 +537,10 @@ impl From for protobuf::transaction::InvokeV0 { } } -impl TryFrom for InvokeTransactionV1 { +impl TryFrom for InvokeTransactionV1 { type Error = ProtobufConversionError; - fn try_from(value: protobuf::transaction::InvokeV1) -> Result { - let max_fee_felt = - Felt::try_from(value.max_fee.ok_or(ProtobufConversionError::MissingField { - field_description: "InvokeV1::max_fee", - })?)?; + fn try_from(value: protobuf::transaction_in_block::InvokeV1) -> Result { + let max_fee_felt = Felt::try_from(value.max_fee.ok_or(missing("InvokeV1::max_fee"))?)?; let max_fee = Fee(try_from_starkfelt_to_u128(max_fee_felt).map_err(|_| { ProtobufConversionError::OutOfRangeValue { type_description: "u128", @@ -713,28 +551,16 @@ impl TryFrom for InvokeTransactionV1 { let signature = TransactionSignature( value .signature - .ok_or(ProtobufConversionError::MissingField { - field_description: "InvokeV1::signature", - })? + .ok_or(missing("InvokeV1::signature"))? .parts .into_iter() .map(Felt::try_from) .collect::, _>>()?, ); - let sender_address = value - .sender - .ok_or(ProtobufConversionError::MissingField { field_description: "InvokeV1::sender" })? - .try_into()?; + let sender_address = value.sender.ok_or(missing("InvokeV1::sender"))?.try_into()?; - let nonce = Nonce( - value - .nonce - .ok_or(ProtobufConversionError::MissingField { - field_description: "InvokeV1::nonce", - })? - .try_into()?, - ); + let nonce = Nonce(value.nonce.ok_or(missing("InvokeV1::nonce"))?.try_into()?); let calldata = value.calldata.into_iter().map(Felt::try_from).collect::, _>>()?; @@ -745,7 +571,7 @@ impl TryFrom for InvokeTransactionV1 { } } -impl From for protobuf::transaction::InvokeV1 { +impl From for protobuf::transaction_in_block::InvokeV1 { fn from(value: InvokeTransactionV1) -> Self { Self { max_fee: Some(Felt::from(value.max_fee.0).into()), @@ -759,42 +585,28 @@ impl From for protobuf::transaction::InvokeV1 { } } -impl TryFrom for InvokeTransactionV3 { +impl TryFrom for InvokeTransactionV3 { type Error = ProtobufConversionError; - fn try_from(value: protobuf::transaction::InvokeV3) -> Result { - let resource_bounds = ValidResourceBounds::try_from(value.resource_bounds.ok_or( - ProtobufConversionError::MissingField { - field_description: "InvokeV3::resource_bounds", - }, - )?)?; + fn try_from(value: protobuf::InvokeV3) -> Result { + let resource_bounds = ValidResourceBounds::try_from( + value.resource_bounds.ok_or(missing("InvokeV3::resource_bounds"))?, + )?; let tip = Tip(value.tip); let signature = TransactionSignature( value .signature - .ok_or(ProtobufConversionError::MissingField { - field_description: "InvokeV3::signature", - })? + .ok_or(missing("InvokeV3::signature"))? .parts .into_iter() .map(Felt::try_from) .collect::, _>>()?, ); - let nonce = Nonce( - value - .nonce - .ok_or(ProtobufConversionError::MissingField { - field_description: "InvokeV3::nonce", - })? - .try_into()?, - ); + let nonce = Nonce(value.nonce.ok_or(missing("InvokeV3::nonce"))?.try_into()?); - let sender_address = value - .sender - .ok_or(ProtobufConversionError::MissingField { field_description: "InvokeV3::sender" })? - .try_into()?; + let sender_address = value.sender.ok_or(missing("InvokeV3::sender"))?.try_into()?; let calldata = value.calldata.into_iter().map(Felt::try_from).collect::, _>>()?; @@ -834,7 +646,7 @@ impl TryFrom for InvokeTransactionV3 { } } -impl From for protobuf::transaction::InvokeV3 { +impl From for protobuf::InvokeV3 { fn from(value: InvokeTransactionV3) -> Self { Self { resource_bounds: Some(protobuf::ResourceBounds::from(value.resource_bounds)), @@ -867,13 +679,12 @@ impl From for protobuf::transaction::InvokeV3 { } } -impl TryFrom for DeclareTransactionV0V1 { +impl TryFrom for DeclareTransactionV0V1 { type Error = ProtobufConversionError; - fn try_from(value: protobuf::transaction::DeclareV0) -> Result { - let max_fee_felt = - Felt::try_from(value.max_fee.ok_or(ProtobufConversionError::MissingField { - field_description: "DeclareV0::max_fee", - })?)?; + fn try_from( + value: protobuf::transaction_in_block::DeclareV0WithoutClass, + ) -> Result { + let max_fee_felt = Felt::try_from(value.max_fee.ok_or(missing("DeclareV0::max_fee"))?)?; let max_fee = Fee(try_from_starkfelt_to_u128(max_fee_felt).map_err(|_| { ProtobufConversionError::OutOfRangeValue { type_description: "u128", @@ -884,9 +695,7 @@ impl TryFrom for DeclareTransactionV0V1 { let signature = TransactionSignature( value .signature - .ok_or(ProtobufConversionError::MissingField { - field_description: "DeclareV0::signature", - })? + .ok_or(missing("DeclareV0::signature"))? .parts .into_iter() .map(Felt::try_from) @@ -896,27 +705,16 @@ impl TryFrom for DeclareTransactionV0V1 { // V0 transactions don't have a nonce, but the StarkNet API adds one to them let nonce = Nonce::default(); - let class_hash = ClassHash( - value - .class_hash - .ok_or(ProtobufConversionError::MissingField { - field_description: "DeclareV0::class_hash", - })? - .try_into()?, - ); + let class_hash = + ClassHash(value.class_hash.ok_or(missing("DeclareV0::class_hash"))?.try_into()?); - let sender_address = value - .sender - .ok_or(ProtobufConversionError::MissingField { - field_description: "DeclareV0::sender", - })? - .try_into()?; + let sender_address = value.sender.ok_or(missing("DeclareV0::sender"))?.try_into()?; Ok(Self { max_fee, signature, nonce, class_hash, sender_address }) } } -impl From for protobuf::transaction::DeclareV0 { +impl From for protobuf::transaction_in_block::DeclareV0WithoutClass { fn from(value: DeclareTransactionV0V1) -> Self { Self { max_fee: Some(Felt::from(value.max_fee.0).into()), @@ -929,13 +727,12 @@ impl From for protobuf::transaction::DeclareV0 { } } -impl TryFrom for DeclareTransactionV0V1 { +impl TryFrom for DeclareTransactionV0V1 { type Error = ProtobufConversionError; - fn try_from(value: protobuf::transaction::DeclareV1) -> Result { - let max_fee_felt = - Felt::try_from(value.max_fee.ok_or(ProtobufConversionError::MissingField { - field_description: "DeclareV1::max_fee", - })?)?; + fn try_from( + value: protobuf::transaction_in_block::DeclareV1WithoutClass, + ) -> Result { + let max_fee_felt = Felt::try_from(value.max_fee.ok_or(missing("DeclareV1::max_fee"))?)?; let max_fee = Fee(try_from_starkfelt_to_u128(max_fee_felt).map_err(|_| { ProtobufConversionError::OutOfRangeValue { type_description: "u128", @@ -946,45 +743,25 @@ impl TryFrom for DeclareTransactionV0V1 { let signature = TransactionSignature( value .signature - .ok_or(ProtobufConversionError::MissingField { - field_description: "DeclareV1::signature", - })? + .ok_or(missing("DeclareV1::signature"))? .parts .into_iter() .map(Felt::try_from) .collect::, _>>()?, ); - let nonce = Nonce( - value - .nonce - .ok_or(ProtobufConversionError::MissingField { - field_description: "DeclareV1::nonce", - })? - .try_into()?, - ); + let nonce = Nonce(value.nonce.ok_or(missing("DeclareV1::nonce"))?.try_into()?); - let class_hash = ClassHash( - value - .class_hash - .ok_or(ProtobufConversionError::MissingField { - field_description: "DeclareV1::class_hash", - })? - .try_into()?, - ); + let class_hash = + ClassHash(value.class_hash.ok_or(missing("DeclareV1::class_hash"))?.try_into()?); - let sender_address = value - .sender - .ok_or(ProtobufConversionError::MissingField { - field_description: "DeclareV1::sender", - })? - .try_into()?; + let sender_address = value.sender.ok_or(missing("DeclareV1::sender"))?.try_into()?; Ok(Self { max_fee, signature, nonce, class_hash, sender_address }) } } -impl From for protobuf::transaction::DeclareV1 { +impl From for protobuf::transaction_in_block::DeclareV1WithoutClass { fn from(value: DeclareTransactionV0V1) -> Self { Self { max_fee: Some(Felt::from(value.max_fee.0).into()), @@ -998,13 +775,12 @@ impl From for protobuf::transaction::DeclareV1 { } } -impl TryFrom for DeclareTransactionV2 { +impl TryFrom for DeclareTransactionV2 { type Error = ProtobufConversionError; - fn try_from(value: protobuf::transaction::DeclareV2) -> Result { - let max_fee_felt = - Felt::try_from(value.max_fee.ok_or(ProtobufConversionError::MissingField { - field_description: "DeclareV2::max_fee", - })?)?; + fn try_from( + value: protobuf::transaction_in_block::DeclareV2WithoutClass, + ) -> Result { + let max_fee_felt = Felt::try_from(value.max_fee.ok_or(missing("DeclareV2::max_fee"))?)?; let max_fee = Fee(try_from_starkfelt_to_u128(max_fee_felt).map_err(|_| { ProtobufConversionError::OutOfRangeValue { type_description: "u128", @@ -1015,54 +791,32 @@ impl TryFrom for DeclareTransactionV2 { let signature = TransactionSignature( value .signature - .ok_or(ProtobufConversionError::MissingField { - field_description: "DeclareV2::signature", - })? + .ok_or(missing("DeclareV2::signature"))? .parts .into_iter() .map(Felt::try_from) .collect::, _>>()?, ); - let nonce = Nonce( - value - .nonce - .ok_or(ProtobufConversionError::MissingField { - field_description: "DeclareV2::nonce", - })? - .try_into()?, - ); + let nonce = Nonce(value.nonce.ok_or(missing("DeclareV2::nonce"))?.try_into()?); - let class_hash = ClassHash( - value - .class_hash - .ok_or(ProtobufConversionError::MissingField { - field_description: "DeclareV2::class_hash", - })? - .try_into()?, - ); + let class_hash = + ClassHash(value.class_hash.ok_or(missing("DeclareV2::class_hash"))?.try_into()?); let compiled_class_hash = CompiledClassHash( value .compiled_class_hash - .ok_or(ProtobufConversionError::MissingField { - field_description: "DeclareV2::compiled_class_hash", - })? + .ok_or(missing("DeclareV2::compiled_class_hash"))? .try_into()?, ); - let sender_address = value - .sender - .ok_or(ProtobufConversionError::MissingField { - field_description: "DeclareV2::sender", - })? - .try_into()?; + let sender_address = value.sender.ok_or(missing("DeclareV2::sender"))?.try_into()?; Ok(Self { max_fee, signature, nonce, class_hash, compiled_class_hash, sender_address }) } } -impl From for protobuf::transaction::DeclareV2 { +impl From for protobuf::transaction_in_block::DeclareV2WithoutClass { fn from(value: DeclareTransactionV2) -> Self { Self { max_fee: Some(Felt::from(value.max_fee.0).into()), @@ -1077,152 +831,83 @@ impl From for protobuf::transaction::DeclareV2 { } } -impl TryFrom for DeclareTransactionV3 { +impl TryFrom + for (DeclareTransactionV3Common, ClassHash) +{ type Error = ProtobufConversionError; - fn try_from(value: protobuf::transaction::DeclareV3) -> Result { - let resource_bounds = ValidResourceBounds::try_from(value.resource_bounds.ok_or( - ProtobufConversionError::MissingField { - field_description: "DeclareV3::resource_bounds", - }, - )?)?; - - let tip = Tip(value.tip); - - let signature = TransactionSignature( - value - .signature - .ok_or(ProtobufConversionError::MissingField { - field_description: "DeclareV3::signature", - })? - .parts - .into_iter() - .map(Felt::try_from) - .collect::, _>>()?, - ); - - let nonce = Nonce( - value - .nonce - .ok_or(ProtobufConversionError::MissingField { - field_description: "DeclareV3::nonce", - })? - .try_into()?, - ); - + fn try_from( + value: protobuf::transaction_in_block::DeclareV3WithoutClass, + ) -> Result { + let common = DeclareTransactionV3Common::try_from( + value.common.ok_or(missing("DeclareV3WithoutClass::common"))?, + )?; let class_hash = ClassHash( - value - .class_hash - .ok_or(ProtobufConversionError::MissingField { - field_description: "DeclareV3::class_hash", - })? - .try_into()?, - ); - - let compiled_class_hash = CompiledClassHash( - value - .compiled_class_hash - .ok_or(ProtobufConversionError::MissingField { - field_description: "DeclareV3::compiled_class_hash", - })? - .try_into()?, + value.class_hash.ok_or(missing("DeclareV3WithoutClass::class_hash"))?.try_into()?, ); + Ok((common, class_hash)) + } +} - let sender_address = value - .sender - .ok_or(ProtobufConversionError::MissingField { - field_description: "DeclareV3::sender", - })? - .try_into()?; - - let nonce_data_availability_mode = - enum_int_to_volition_domain(value.nonce_data_availability_mode)?; - - let fee_data_availability_mode = - enum_int_to_volition_domain(value.fee_data_availability_mode)?; - - let paymaster_data = PaymasterData( - value.paymaster_data.into_iter().map(Felt::try_from).collect::, _>>()?, - ); +impl From<(DeclareTransactionV3Common, ClassHash)> + for protobuf::transaction_in_block::DeclareV3WithoutClass +{ + fn from(value: (DeclareTransactionV3Common, ClassHash)) -> Self { + Self { common: Some(value.0.into()), class_hash: Some(value.1.0.into()) } + } +} - let account_deployment_data = AccountDeploymentData( - value - .account_deployment_data - .into_iter() - .map(Felt::try_from) - .collect::, _>>()?, - ); +impl TryFrom for DeclareTransactionV3 { + type Error = ProtobufConversionError; + fn try_from( + value: protobuf::transaction_in_block::DeclareV3WithoutClass, + ) -> Result { + let (common, class_hash) = value.try_into()?; Ok(Self { - resource_bounds, - tip, - signature, - nonce, + resource_bounds: common.resource_bounds, + tip: common.tip, + signature: common.signature, + nonce: common.nonce, class_hash, - compiled_class_hash, - sender_address, - nonce_data_availability_mode, - fee_data_availability_mode, - paymaster_data, - account_deployment_data, + compiled_class_hash: common.compiled_class_hash, + sender_address: common.sender_address, + nonce_data_availability_mode: common.nonce_data_availability_mode, + fee_data_availability_mode: common.fee_data_availability_mode, + paymaster_data: common.paymaster_data, + account_deployment_data: common.account_deployment_data, }) } } -impl From for protobuf::transaction::DeclareV3 { +impl From for protobuf::transaction_in_block::DeclareV3WithoutClass { fn from(value: DeclareTransactionV3) -> Self { - Self { - resource_bounds: Some(protobuf::ResourceBounds::from(value.resource_bounds)), - tip: value.tip.0, - signature: Some(protobuf::AccountSignature { - parts: value.signature.0.into_iter().map(|signature| signature.into()).collect(), - }), - nonce: Some(value.nonce.0.into()), - class_hash: Some(value.class_hash.0.into()), - compiled_class_hash: Some(value.compiled_class_hash.0.into()), - sender: Some(value.sender_address.into()), - nonce_data_availability_mode: volition_domain_to_enum_int( - value.nonce_data_availability_mode, - ), - fee_data_availability_mode: volition_domain_to_enum_int( - value.fee_data_availability_mode, - ), - paymaster_data: value - .paymaster_data - .0 - .iter() - .map(|paymaster_data| (*paymaster_data).into()) - .collect(), - account_deployment_data: value - .account_deployment_data - .0 - .iter() - .map(|account_deployment_data| (*account_deployment_data).into()) - .collect(), - } + let common = DeclareTransactionV3Common { + resource_bounds: value.resource_bounds, + tip: value.tip, + signature: value.signature, + nonce: value.nonce, + compiled_class_hash: value.compiled_class_hash, + sender_address: value.sender_address, + nonce_data_availability_mode: value.nonce_data_availability_mode, + fee_data_availability_mode: value.fee_data_availability_mode, + paymaster_data: value.paymaster_data, + account_deployment_data: value.account_deployment_data, + }; + let class_hash = value.class_hash; + Self { common: Some(common.into()), class_hash: Some(class_hash.0.into()) } } } -impl TryFrom for DeployTransaction { +impl TryFrom for DeployTransaction { type Error = ProtobufConversionError; - fn try_from(value: protobuf::transaction::Deploy) -> Result { + fn try_from(value: protobuf::transaction_in_block::Deploy) -> Result { let version = TransactionVersion(Felt::from(value.version)); - let class_hash = ClassHash( - value - .class_hash - .ok_or(ProtobufConversionError::MissingField { - field_description: "Deploy::class_hash", - })? - .try_into()?, - ); + let class_hash = + ClassHash(value.class_hash.ok_or(missing("Deploy::class_hash"))?.try_into()?); let contract_address_salt = ContractAddressSalt( - value - .address_salt - .ok_or(ProtobufConversionError::MissingField { - field_description: "Deploy::address_salt", - })? - .try_into()?, + value.address_salt.ok_or(missing("Deploy::address_salt"))?.try_into()?, ); let constructor_calldata = @@ -1234,7 +919,7 @@ impl TryFrom for DeployTransaction { } } -impl From for protobuf::transaction::Deploy { +impl From for protobuf::transaction_in_block::Deploy { fn from(value: DeployTransaction) -> Self { Self { version: try_from_starkfelt_to_u32(value.version.0).unwrap_or_default(), @@ -1250,32 +935,18 @@ impl From for protobuf::transaction::Deploy { } } -impl TryFrom for L1HandlerTransaction { +impl TryFrom for L1HandlerTransaction { type Error = ProtobufConversionError; - fn try_from(value: protobuf::transaction::L1HandlerV0) -> Result { - let version = TransactionVersion(Felt::ZERO); + fn try_from(value: protobuf::L1HandlerV0) -> Result { + let version = L1HandlerTransaction::VERSION; - let nonce = Nonce( - value - .nonce - .ok_or(ProtobufConversionError::MissingField { - field_description: "L1HandlerV0::nonce", - })? - .try_into()?, - ); + let nonce = Nonce(value.nonce.ok_or(missing("L1HandlerV0::nonce"))?.try_into()?); - let contract_address = value - .address - .ok_or(ProtobufConversionError::MissingField { - field_description: "L1HandlerV0::address", - })? - .try_into()?; + let contract_address = value.address.ok_or(missing("L1HandlerV0::address"))?.try_into()?; - let entry_point_selector_felt = Felt::try_from(value.entry_point_selector.ok_or( - ProtobufConversionError::MissingField { - field_description: "L1HandlerV0::entry_point_selector", - }, - )?)?; + let entry_point_selector_felt = Felt::try_from( + value.entry_point_selector.ok_or(missing("L1HandlerV0::entry_point_selector"))?, + )?; let entry_point_selector = EntryPointSelector(entry_point_selector_felt); let calldata = @@ -1287,7 +958,7 @@ impl TryFrom for L1HandlerTransaction { } } -impl From for protobuf::transaction::L1HandlerV0 { +impl From for protobuf::L1HandlerV0 { fn from(value: L1HandlerTransaction) -> Self { Self { nonce: Some(value.nonce.0.into()), @@ -1298,6 +969,63 @@ impl From for protobuf::transaction::L1HandlerV0 { } } +impl From for protobuf::ConsensusTransaction { + fn from(value: ConsensusTransaction) -> Self { + match value { + ConsensusTransaction::RpcTransaction(RpcTransaction::Declare( + RpcDeclareTransaction::V3(txn), + )) => protobuf::ConsensusTransaction { + txn: Some(protobuf::consensus_transaction::Txn::DeclareV3(txn.into())), + transaction_hash: None, + }, + ConsensusTransaction::RpcTransaction(RpcTransaction::DeployAccount( + RpcDeployAccountTransaction::V3(txn), + )) => protobuf::ConsensusTransaction { + txn: Some(protobuf::consensus_transaction::Txn::DeployAccountV3(txn.into())), + transaction_hash: None, + }, + ConsensusTransaction::RpcTransaction(RpcTransaction::Invoke( + RpcInvokeTransaction::V3(txn), + )) => protobuf::ConsensusTransaction { + txn: Some(protobuf::consensus_transaction::Txn::InvokeV3(txn.into())), + transaction_hash: None, + }, + ConsensusTransaction::L1Handler(txn) => protobuf::ConsensusTransaction { + txn: Some(protobuf::consensus_transaction::Txn::L1Handler(txn.into())), + transaction_hash: None, + }, + } + } +} + +impl TryFrom for ConsensusTransaction { + type Error = ProtobufConversionError; + fn try_from(value: protobuf::ConsensusTransaction) -> Result { + let txn = value.txn.ok_or(missing("ConsensusTransaction::txn"))?; + let txn = match txn { + protobuf::consensus_transaction::Txn::DeclareV3(txn) => { + ConsensusTransaction::RpcTransaction(RpcTransaction::Declare( + RpcDeclareTransaction::V3(txn.try_into()?), + )) + } + protobuf::consensus_transaction::Txn::DeployAccountV3(txn) => { + ConsensusTransaction::RpcTransaction(RpcTransaction::DeployAccount( + RpcDeployAccountTransaction::V3(txn.try_into()?), + )) + } + protobuf::consensus_transaction::Txn::InvokeV3(txn) => { + ConsensusTransaction::RpcTransaction(RpcTransaction::Invoke( + RpcInvokeTransaction::V3(txn.try_into()?), + )) + } + protobuf::consensus_transaction::Txn::L1Handler(txn) => { + ConsensusTransaction::L1Handler(txn.try_into()?) + } + }; + Ok(txn) + } +} + impl TryFrom for Query { type Error = ProtobufConversionError; fn try_from(value: protobuf::TransactionsRequest) -> Result { @@ -1309,12 +1037,7 @@ impl TryFrom for TransactionQuery { type Error = ProtobufConversionError; fn try_from(value: protobuf::TransactionsRequest) -> Result { Ok(TransactionQuery( - value - .iteration - .ok_or(ProtobufConversionError::MissingField { - field_description: "TransactionsRequest::iteration", - })? - .try_into()?, + value.iteration.ok_or(missing("TransactionsRequest::iteration"))?.try_into()?, )) } } @@ -1335,18 +1058,18 @@ auto_impl_into_and_try_from_vec_u8!(TransactionQuery, protobuf::TransactionsRequ pub fn set_price_unit_based_on_transaction( receipt: &mut protobuf::Receipt, - transaction: &protobuf::Transaction, + transaction: &protobuf::TransactionInBlock, ) { let price_unit = match &transaction.txn { - Some(protobuf::transaction::Txn::DeclareV1(_)) => protobuf::PriceUnit::Wei, - Some(protobuf::transaction::Txn::DeclareV2(_)) => protobuf::PriceUnit::Wei, - Some(protobuf::transaction::Txn::DeclareV3(_)) => protobuf::PriceUnit::Fri, - Some(protobuf::transaction::Txn::Deploy(_)) => protobuf::PriceUnit::Wei, - Some(protobuf::transaction::Txn::DeployAccountV1(_)) => protobuf::PriceUnit::Wei, - Some(protobuf::transaction::Txn::DeployAccountV3(_)) => protobuf::PriceUnit::Fri, - Some(protobuf::transaction::Txn::InvokeV1(_)) => protobuf::PriceUnit::Wei, - Some(protobuf::transaction::Txn::InvokeV3(_)) => protobuf::PriceUnit::Fri, - Some(protobuf::transaction::Txn::L1Handler(_)) => protobuf::PriceUnit::Wei, + Some(protobuf::transaction_in_block::Txn::DeclareV1(_)) => protobuf::PriceUnit::Wei, + Some(protobuf::transaction_in_block::Txn::DeclareV2(_)) => protobuf::PriceUnit::Wei, + Some(protobuf::transaction_in_block::Txn::DeclareV3(_)) => protobuf::PriceUnit::Fri, + Some(protobuf::transaction_in_block::Txn::Deploy(_)) => protobuf::PriceUnit::Wei, + Some(protobuf::transaction_in_block::Txn::DeployAccountV1(_)) => protobuf::PriceUnit::Wei, + Some(protobuf::transaction_in_block::Txn::DeployAccountV3(_)) => protobuf::PriceUnit::Fri, + Some(protobuf::transaction_in_block::Txn::InvokeV1(_)) => protobuf::PriceUnit::Wei, + Some(protobuf::transaction_in_block::Txn::InvokeV3(_)) => protobuf::PriceUnit::Fri, + Some(protobuf::transaction_in_block::Txn::L1Handler(_)) => protobuf::PriceUnit::Wei, _ => return, }; let Some(ref mut receipt_type) = receipt.r#type else { diff --git a/crates/papyrus_protobuf/src/converters/transaction_test.rs b/crates/papyrus_protobuf/src/converters/transaction_test.rs index ce5d02eabeb..6f03abf2908 100644 --- a/crates/papyrus_protobuf/src/converters/transaction_test.rs +++ b/crates/papyrus_protobuf/src/converters/transaction_test.rs @@ -15,10 +15,9 @@ use starknet_api::transaction::{ InvokeTransactionOutput, L1HandlerTransactionOutput, Transaction as StarknetApiTransaction, - TransactionHash, TransactionOutput, }; -use starknet_types_core::felt::Felt; +use starknet_api::tx_hash; use crate::sync::DataOrFin; @@ -167,7 +166,7 @@ fn assert_transaction_to_vec_u8_and_back( transaction: StarknetApiTransaction, transaction_output: TransactionOutput, ) { - let random_transaction_hash = TransactionHash(Felt::from(random::())); + let random_transaction_hash = tx_hash!(random::()); let data = DataOrFin(Some(FullTransaction { transaction, transaction_output, diff --git a/crates/papyrus_protobuf/src/lib.rs b/crates/papyrus_protobuf/src/lib.rs index 1ead9a2a16f..a4a317fa7ca 100644 --- a/crates/papyrus_protobuf/src/lib.rs +++ b/crates/papyrus_protobuf/src/lib.rs @@ -4,4 +4,10 @@ pub mod converters; pub mod consensus; pub mod mempool; pub mod protobuf; +#[cfg(any(test, feature = "bin-deps"))] +pub mod regression_test_utils; pub mod sync; +mod transaction; + +#[cfg(test)] +mod protoc_regression_test; diff --git a/crates/papyrus_protobuf/src/mempool.rs b/crates/papyrus_protobuf/src/mempool.rs index aec5c8ba375..aed302b46b0 100644 --- a/crates/papyrus_protobuf/src/mempool.rs +++ b/crates/papyrus_protobuf/src/mempool.rs @@ -1,4 +1,4 @@ use starknet_api::rpc_transaction::RpcTransaction; #[derive(Debug, Clone, PartialEq, Eq)] -pub struct RpcTransactionWrapper(pub RpcTransaction); +pub struct RpcTransactionBatch(pub Vec); diff --git a/crates/papyrus_protobuf/src/proto/p2p/proto/class.proto b/crates/papyrus_protobuf/src/proto/p2p/proto/class.proto index 755f70e8503..4fc1be53290 100644 --- a/crates/papyrus_protobuf/src/proto/p2p/proto/class.proto +++ b/crates/papyrus_protobuf/src/proto/p2p/proto/class.proto @@ -1,6 +1,7 @@ syntax = "proto3"; import "p2p/proto/common.proto"; +option go_package = "github.com/starknet-io/starknet-p2pspecs/p2p/proto/class"; message EntryPoint { Felt252 selector = 1; @@ -42,15 +43,3 @@ message Class { uint32 domain = 3; Hash class_hash = 4; } - -message ClassesRequest { - Iteration iteration = 1; -} - -// Responses are sent ordered by the order given in the request. -message ClassesResponse { - oneof class_message { - Class class = 1; - Fin fin = 2; // Fin is sent after the peer sent all the data or when it encountered a block that it doesn't have its classes. - } -} \ No newline at end of file diff --git a/crates/papyrus_protobuf/src/proto/p2p/proto/common.proto b/crates/papyrus_protobuf/src/proto/p2p/proto/common.proto index 0964096d8ba..c223d411e16 100644 --- a/crates/papyrus_protobuf/src/proto/p2p/proto/common.proto +++ b/crates/papyrus_protobuf/src/proto/p2p/proto/common.proto @@ -1,13 +1,22 @@ syntax = "proto3"; +option go_package = "github.com/starknet-io/starknet-p2pspecs/p2p/proto/common"; + message Felt252 { bytes elements = 1; } +// A hash value representable as a Felt252 message Hash { bytes elements = 1; } +// A 256 bit hash value (like Keccak256) +message Hash256 { + // Required to be 32 bytes long + bytes elements = 1; +} + message Hashes { repeated Hash items = 1; } @@ -29,17 +38,13 @@ message ConsensusSignature { Felt252 r = 1; Felt252 s = 2; } + message Patricia { uint64 n_leaves = 1; // needed to know the height, so as to how many nodes to expect in a proof. // and also when receiving all leaves, how many to expect Hash root = 2; } -message StateDiffCommitment { - uint64 state_diff_length = 1; - Hash root = 2; -} - message BlockID { uint64 number = 1; Hash header = 2; @@ -55,19 +60,9 @@ enum VolitionDomain { L2 = 1; } -message Iteration { - enum Direction { - Forward = 0; - Backward = 1; - } - oneof start { - uint64 block_number = 1; - Hash header = 2; - } - Direction direction = 3; - uint64 limit = 4; - uint64 step = 5; // to allow interleaving from several nodes - // bool interleave = 6; // return results in any order of blocks, per block the messages should still be in the order specified +message BlockProof { + repeated bytes proof = 1; } +// mark the end of a stream of messages message Fin {} diff --git a/crates/papyrus_protobuf/src/proto/p2p/proto/consensus.proto b/crates/papyrus_protobuf/src/proto/p2p/proto/consensus/consensus.proto similarity index 54% rename from crates/papyrus_protobuf/src/proto/p2p/proto/consensus.proto rename to crates/papyrus_protobuf/src/proto/p2p/proto/consensus/consensus.proto index 81e5af8d2c6..e92b2966cc5 100644 --- a/crates/papyrus_protobuf/src/proto/p2p/proto/consensus.proto +++ b/crates/papyrus_protobuf/src/proto/p2p/proto/consensus/consensus.proto @@ -1,15 +1,19 @@ syntax = "proto3"; -import "p2p/proto/transaction.proto"; import "p2p/proto/common.proto"; +import "p2p/proto/transaction.proto"; + +option go_package = "github.com/starknet-io/starknet-p2pspecs/p2p/proto/consensus/consensus"; -// To be deprecated -message Proposal { - uint64 height = 1; - uint32 round = 2; - Address proposer = 3; - repeated Transaction transactions = 4; - Hash block_hash = 5; - optional uint32 valid_round = 6; +// Contains all variants of mempool and an L1Handler variant to cover all transactions that can be +// in a new block. +message ConsensusTransaction { + oneof txn { + DeclareV3WithClass declare_v3 = 1; + DeployAccountV3 deploy_account_v3 = 2; + InvokeV3 invoke_v3 = 3; + L1HandlerV0 l1_handler = 4; + } + Hash transaction_hash = 5; } message Vote { @@ -29,20 +33,12 @@ message Vote { Address voter = 6; } -// TODO(guyn): remove this after we have integrated streams for the proposal -message ConsensusMessage { - oneof message { - Proposal proposal = 1; - Vote vote = 2; - } -} - message StreamMessage { oneof message { bytes content = 1; Fin fin = 2; } - uint64 stream_id = 3; + bytes stream_id = 3; uint64 message_id = 4; } @@ -53,15 +49,24 @@ message ProposalInit { Address proposer = 4; } +message BlockInfo { + uint64 height = 1; + uint64 timestamp = 2; + Address builder = 3; + L1DataAvailabilityMode l1_da_mode = 4; + Uint128 l2_gas_price_fri = 5; + Uint128 l1_gas_price_wei = 6; + Uint128 l1_data_gas_price_wei = 7; + Uint128 eth_to_fri_rate = 8; +} + message TransactionBatch { - repeated Transaction transactions = 1; - // TODO(guyn): remove this once we know how to calculate hashes - repeated Felt252 tx_hashes = 2; + repeated ConsensusTransaction transactions = 1; } message ProposalFin { - // Identifies all of the content streamed in the proposal. - Hash proposal_content_id = 1; + // Identifies a Starknet block based on the content streamed in the proposal. + Hash proposal_commitment = 1; } // Network format: @@ -72,6 +77,7 @@ message ProposalPart { oneof message { ProposalInit init = 1; ProposalFin fin = 2; - TransactionBatch transactions = 3; + BlockInfo block_info = 3; + TransactionBatch transactions = 4; } } diff --git a/crates/papyrus_protobuf/src/proto/p2p/proto/mempool/mempool.md b/crates/papyrus_protobuf/src/proto/p2p/proto/mempool/mempool.md new file mode 100644 index 00000000000..71d1c60b1cb --- /dev/null +++ b/crates/papyrus_protobuf/src/proto/p2p/proto/mempool/mempool.md @@ -0,0 +1,36 @@ +# Starknet Mempool Protocol + +## Overview +The goal of the mempool p2p protocol is to allow mempools to share transactions they receive through RPC. +This will make it so that once a user submits a transaction to one mempool it will appear across all mempools. + +## Gossipsub +The protocol is based on the [Gossipsub](https://docs.libp2p.io/concepts/pubsub/overview/) protocol, V1.1 + +The topic for this protocol is: `"/starknet/mempool_transaction_propagation/0.1.0"`. + +We use Gossipsub to publish transactions once they reach the node through RPC. + +Once a node receives a transaction, it should verify it against the current state by running +`validate` before continuing its propagation to other nodes. +This is to prevent giving scale for a DDoS attack. + +Our choice of using Gossipsub might change in the future if we encounter performance issues with it. + +## Transaction +The object that we're passing is a [MempoolTransaction](./transaction.proto). A few notes about it: +* It contains support only for V3 transactions. Transaction prior to V3 can't be a part of a mempool +because they don't have the required fields to enter the fee market +* It doesn't contain a variant for L1Handler transactions. The reason is that mempools can learn +about existing L1Handler transactions by simply looking at L1 +* In Declare, it contains the SIERRA of the class being declared. The reason it doesn't contain the +CASM of the class is that the mempool should validate that the CASM came from the compilation of a +SIERRA class and not from an unsafe class. + +## No sync +We've decided to not implement a protocol for syncing on existing transactions in the mempool. + +The reason for that is that we're aiming for a very low block time (1-2 seconds) and a very high TPS (1000+). +The combination of these means that most transactions will be either included in a block or evicted within a few seconds after their arrival. + +This means that a new mempool will have most of the transactions that an older mempool would have within a few seconds after it starts listening for new transactions. diff --git a/crates/papyrus_protobuf/src/proto/p2p/proto/mempool/transaction.proto b/crates/papyrus_protobuf/src/proto/p2p/proto/mempool/transaction.proto new file mode 100644 index 00000000000..7eeabd7dc60 --- /dev/null +++ b/crates/papyrus_protobuf/src/proto/p2p/proto/mempool/transaction.proto @@ -0,0 +1,23 @@ +syntax = "proto3"; + +import "p2p/proto/class.proto"; +import "p2p/proto/common.proto"; +import "p2p/proto/transaction.proto"; +import "p2p/proto/sync/transaction.proto"; + + +option go_package = "github.com/starknet-io/starknet-p2pspecs/p2p/proto/mempool/transaction"; + +// Doesn't contain L1Handler, as those don't need to be propagated and can be downloaded from L1. +message MempoolTransaction { + oneof txn { + DeclareV3WithClass declare_v3 = 1; + DeployAccountV3 deploy_account_v3 = 2; + InvokeV3 invoke_v3 = 3; + } + Hash transaction_hash = 4; +} + +message MempoolTransactionBatch { + repeated MempoolTransaction transactions = 1; +} diff --git a/crates/papyrus_protobuf/src/proto/p2p/proto/rpc_transaction.proto b/crates/papyrus_protobuf/src/proto/p2p/proto/rpc_transaction.proto deleted file mode 100644 index 672ad3dc08a..00000000000 --- a/crates/papyrus_protobuf/src/proto/p2p/proto/rpc_transaction.proto +++ /dev/null @@ -1,18 +0,0 @@ -syntax = "proto3"; -import "p2p/proto/class.proto"; -import "p2p/proto/common.proto"; -import "p2p/proto/transaction.proto"; - -message RpcTransaction -{ - message DeclareV3 { - Transaction.DeclareV3 declare_v3 = 1; - Cairo1Class contract_class = 2; - } - - oneof txn { - DeclareV3 declare_v3 = 1; - Transaction.DeployAccountV3 deploy_account_v3 = 2; - Transaction.InvokeV3 invoke_v3 = 3; - } -} diff --git a/crates/papyrus_protobuf/src/proto/p2p/proto/sync/class.proto b/crates/papyrus_protobuf/src/proto/p2p/proto/sync/class.proto new file mode 100644 index 00000000000..dbbdc430582 --- /dev/null +++ b/crates/papyrus_protobuf/src/proto/p2p/proto/sync/class.proto @@ -0,0 +1,18 @@ +syntax = "proto3"; +import "p2p/proto/class.proto"; +import "p2p/proto/common.proto"; +import "p2p/proto/sync/common.proto"; + +option go_package = "github.com/starknet-io/starknet-p2pspecs/p2p/proto/sync/class"; + +message ClassesRequest { + Iteration iteration = 1; +} + +// Responses are sent ordered by the order given in the request. +message ClassesResponse { + oneof class_message { + Class class = 1; + Fin fin = 2; // Fin is sent after the peer sent all the data or when it encountered a block that it doesn't have its classes. + } +} diff --git a/crates/papyrus_protobuf/src/proto/p2p/proto/sync/common.proto b/crates/papyrus_protobuf/src/proto/p2p/proto/sync/common.proto new file mode 100644 index 00000000000..2155e302e9a --- /dev/null +++ b/crates/papyrus_protobuf/src/proto/p2p/proto/sync/common.proto @@ -0,0 +1,24 @@ +syntax = "proto3"; +import "p2p/proto/common.proto"; + +option go_package = "github.com/starknet-io/starknet-p2pspecs/p2p/proto/sync/common"; + +message StateDiffCommitment { + uint64 state_diff_length = 1; + Hash root = 2; +} + +message Iteration { + enum Direction { + Forward = 0; + Backward = 1; + } + oneof start { + uint64 block_number = 1; + Hash header = 2; + } + Direction direction = 3; + uint64 limit = 4; + uint64 step = 5; // to allow interleaving from several nodes + // bool interleave = 6; // return results in any order of blocks, per block the messages should still be in the order specified +} diff --git a/crates/papyrus_protobuf/src/proto/p2p/proto/event.proto b/crates/papyrus_protobuf/src/proto/p2p/proto/sync/event.proto similarity index 81% rename from crates/papyrus_protobuf/src/proto/p2p/proto/event.proto rename to crates/papyrus_protobuf/src/proto/p2p/proto/sync/event.proto index 89e02391736..fb938118dde 100644 --- a/crates/papyrus_protobuf/src/proto/p2p/proto/event.proto +++ b/crates/papyrus_protobuf/src/proto/p2p/proto/sync/event.proto @@ -1,5 +1,8 @@ syntax = "proto3"; import "p2p/proto/common.proto"; +import "p2p/proto/sync/common.proto"; + +option go_package = "github.com/starknet-io/starknet-p2pspecs/p2p/proto/sync/event"; message Event { Hash transaction_hash = 1; diff --git a/crates/papyrus_protobuf/src/proto/p2p/proto/header.proto b/crates/papyrus_protobuf/src/proto/p2p/proto/sync/header.proto similarity index 75% rename from crates/papyrus_protobuf/src/proto/p2p/proto/header.proto rename to crates/papyrus_protobuf/src/proto/p2p/proto/sync/header.proto index 67963acb57e..d78505ffc09 100644 --- a/crates/papyrus_protobuf/src/proto/p2p/proto/header.proto +++ b/crates/papyrus_protobuf/src/proto/p2p/proto/sync/header.proto @@ -1,5 +1,8 @@ syntax = "proto3"; import "p2p/proto/common.proto"; +import "p2p/proto/sync/common.proto"; + +option go_package = "github.com/starknet-io/starknet-p2pspecs/p2p/proto/sync/header"; // Note: commitments may change to be for the previous blocks like comet/tendermint // hash of block header sent to L1 @@ -17,17 +20,17 @@ message SignedBlockHeader { Patricia events = 9; // By order of issuance. TBD: in receipts? Hash receipts = 10; // By order of issuance. This is a patricia root. No need for length because it's the same length as transactions. string protocol_version = 11; // Starknet version - Uint128 gas_price_fri = 12; - Uint128 gas_price_wei = 13; - Uint128 data_gas_price_fri = 14; - Uint128 data_gas_price_wei = 15; - L1DataAvailabilityMode l1_data_availability_mode = 16; + Uint128 l1_gas_price_fri = 12; + Uint128 l1_gas_price_wei = 13; + Uint128 l1_data_gas_price_fri = 14; + Uint128 l1_data_gas_price_wei = 15; + Uint128 l2_gas_price_fri = 16; + Uint128 l2_gas_price_wei = 17; + uint64 l2_gas_consumed = 18; + uint64 next_l2_gas_price = 19; + L1DataAvailabilityMode l1_data_availability_mode = 20; // for now, we assume a small consensus, so this fits in 1M. Else, these will be repeated and extracted from this message. - repeated ConsensusSignature signatures = 17; - // TODO(Shahak): Move l2_gas_price up next to the gas price context and renumber, - // once we insert l2 gas fields to the p2p specs. - optional Uint128 l2_gas_price_fri = 18; // Added on v0.13.3. - optional Uint128 l2_gas_price_wei = 19; // Added on v0.13.3. + repeated ConsensusSignature signatures = 21; // can be more explicit here about the signature structure as this is not part of account abstraction } @@ -35,7 +38,7 @@ message SignedBlockHeader { // for a fraction of peers, also send the GetBlockHeaders response (as if they asked for it for this block) message NewBlock { oneof maybe_full { - BlockID id = 1; + BlockID id = 1; BlockHeadersResponse header = 2; } } @@ -49,6 +52,6 @@ message BlockHeadersRequest { message BlockHeadersResponse { oneof header_message { SignedBlockHeader header = 1; - Fin fin = 2; // Fin is sent after the peer sent all the data or when it encountered a block that it doesn't have its header. + Fin fin = 2; // Fin is sent after the peer sent all the data or when it encountered a block that it doesn't have its header. } } diff --git a/crates/papyrus_protobuf/src/proto/p2p/proto/receipt.proto b/crates/papyrus_protobuf/src/proto/p2p/proto/sync/receipt.proto similarity index 90% rename from crates/papyrus_protobuf/src/proto/p2p/proto/receipt.proto rename to crates/papyrus_protobuf/src/proto/p2p/proto/sync/receipt.proto index fd38c237aad..ebbc0c17797 100644 --- a/crates/papyrus_protobuf/src/proto/p2p/proto/receipt.proto +++ b/crates/papyrus_protobuf/src/proto/p2p/proto/sync/receipt.proto @@ -27,8 +27,10 @@ message Receipt { uint32 poseidon = 6; uint32 keccak = 7; uint32 output = 8; + // TODO(alonl): add the missing builtins } + //TODO(alonl): remove GasVector and unsplit gas_consumed and da_gas_consumed message GasVector { uint64 l1_gas = 1; uint64 l1_data_gas = 2; @@ -57,7 +59,7 @@ message Receipt { message L1Handler { Common common = 1; - Hash msg_hash = 2; + Hash256 msg_hash = 2; } message Declare { diff --git a/crates/papyrus_protobuf/src/proto/p2p/proto/state.proto b/crates/papyrus_protobuf/src/proto/p2p/proto/sync/state.proto similarity index 74% rename from crates/papyrus_protobuf/src/proto/p2p/proto/state.proto rename to crates/papyrus_protobuf/src/proto/p2p/proto/sync/state.proto index 132a4a87128..9eb14e2b9b7 100644 --- a/crates/papyrus_protobuf/src/proto/p2p/proto/state.proto +++ b/crates/papyrus_protobuf/src/proto/p2p/proto/sync/state.proto @@ -1,5 +1,8 @@ syntax = "proto3"; import "p2p/proto/common.proto"; +import "p2p/proto/sync/common.proto"; + +option go_package = "github.com/starknet-io/starknet-p2pspecs/p2p/proto/sync/state"; // optimized for flat storage, not through a trie (not sharing key prefixes) @@ -9,11 +12,11 @@ message ContractStoredValue { } message ContractDiff { - Address address = 1; - optional Felt252 nonce = 2; // Present only if the nonce was updated - optional Hash class_hash = 3; // Present only if the contract was deployed or replaced in this block. + Address address = 1; + optional Felt252 nonce = 2; // Present only if the nonce was updated + optional Hash class_hash = 3; // Present only if the contract was deployed or replaced in this block. repeated ContractStoredValue values = 4; - VolitionDomain domain = 5; + VolitionDomain domain = 5; } message DeclaredClass { diff --git a/crates/papyrus_protobuf/src/proto/p2p/proto/sync/transaction.proto b/crates/papyrus_protobuf/src/proto/p2p/proto/sync/transaction.proto new file mode 100644 index 00000000000..b798dfb109d --- /dev/null +++ b/crates/papyrus_protobuf/src/proto/p2p/proto/sync/transaction.proto @@ -0,0 +1,108 @@ +syntax = "proto3"; +import "p2p/proto/common.proto"; +import "p2p/proto/sync/common.proto"; +import "p2p/proto/sync/receipt.proto"; +import "p2p/proto/transaction.proto"; +//TODO(alonl): remove this once we change transaction type to TransactionInBlock in TransactionWithReceipt +import "p2p/proto/consensus/consensus.proto"; + +option go_package = "github.com/starknet-io/starknet-p2pspecs/p2p/proto/sync/transaction"; + +// TBD: can support a flag to return tx hashes only, good for standalone mempool to remove them, +// or any node that keeps track of transaction streaming in the consensus. +message TransactionsRequest { + Iteration iteration = 1; +} + +// Responses are sent ordered by the order given in the request. The order inside each block is +// according to the execution order. +message TransactionsResponse { + oneof transaction_message { + TransactionWithReceipt transaction_with_receipt = 1; + Fin fin = 2; // Fin is sent after the peer sent all the data or when it encountered a block that it doesn't have its transactions. + } +} + +message TransactionWithReceipt { + TransactionInBlock transaction = 1; + Receipt receipt = 2; +} + +message TransactionInBlock { + message DeclareV0WithoutClass { + Address sender = 1; + Felt252 max_fee = 2; + AccountSignature signature = 3; + Hash class_hash = 4; + } + + message DeclareV1WithoutClass { + Address sender = 1; + Felt252 max_fee = 2; + AccountSignature signature = 3; + Hash class_hash = 4; + Felt252 nonce = 5; + } + + message DeclareV2WithoutClass { + Address sender = 1; + Felt252 max_fee = 2; + AccountSignature signature = 3; + Hash class_hash = 4; + Felt252 nonce = 5; + Hash compiled_class_hash = 6; + } + + // see https://external.integration.starknet.io/feeder_gateway/get_transaction?transactionHash=0x41d1f5206ef58a443e7d3d1ca073171ec25fa75313394318fc83a074a6631c3 + message DeclareV3WithoutClass { + DeclareV3Common common = 1; + Hash class_hash = 2; + } + + message Deploy { + Hash class_hash = 1; + Felt252 address_salt = 2; + repeated Felt252 calldata = 3; + uint32 version = 4; + } + + message DeployAccountV1 { + Felt252 max_fee = 1; + AccountSignature signature = 2; + Hash class_hash = 3; + Felt252 nonce = 4; + Felt252 address_salt = 5; + repeated Felt252 calldata = 6; + } + + message InvokeV0 { + Felt252 max_fee = 1; + AccountSignature signature = 2; + Address address = 3; + Felt252 entry_point_selector = 4; + repeated Felt252 calldata = 5; + } + + message InvokeV1 { + Address sender = 1; + Felt252 max_fee = 2; + AccountSignature signature = 3; + repeated Felt252 calldata = 4; + Felt252 nonce = 5; + } + + oneof txn { + DeclareV0WithoutClass declare_v0 = 1; + DeclareV1WithoutClass declare_v1 = 2; + DeclareV2WithoutClass declare_v2 = 3; + DeclareV3WithoutClass declare_v3 = 4; + Deploy deploy = 5; + DeployAccountV1 deploy_account_v1 = 6; + DeployAccountV3 deploy_account_v3 = 7; + InvokeV0 invoke_v0 = 8; + InvokeV1 invoke_v1 = 9; + InvokeV3 invoke_v3 = 10; + L1HandlerV0 l1_handler = 11; + } + Hash transaction_hash = 12; +} diff --git a/crates/papyrus_protobuf/src/proto/p2p/proto/transaction.proto b/crates/papyrus_protobuf/src/proto/p2p/proto/transaction.proto index 33065edd512..9dfef05526c 100644 --- a/crates/papyrus_protobuf/src/proto/p2p/proto/transaction.proto +++ b/crates/papyrus_protobuf/src/proto/p2p/proto/transaction.proto @@ -1,164 +1,77 @@ syntax = "proto3"; import "p2p/proto/common.proto"; -import "p2p/proto/receipt.proto"; +import "p2p/proto/class.proto"; + +option go_package = "github.com/starknet-io/starknet-p2pspecs/p2p/proto/transaction"; message ResourceLimits { + // TODO(shahak, alonl): figure out if max_amount should be uint64 or Felt252 uint64 max_amount = 1; Felt252 max_price_per_unit = 2; } message ResourceBounds { ResourceLimits l1_gas = 1; - ResourceLimits l2_gas = 2; - ResourceLimits l1_data_gas = 3; + // This can be None only in transactions that don't support l2 gas. + // Starting from 0.14.0, MempoolTransaction and ConsensusTransaction shouldn't have None here. + optional ResourceLimits l1_data_gas = 2; + ResourceLimits l2_gas = 3; } message AccountSignature { repeated Felt252 parts = 1; } -// This is a transaction that is already accepted in a block. Once we have a mempool, we will define -// a separate message for BroadcastedTransaction. -message Transaction -{ - message DeclareV0 { - Address sender = 1; - Felt252 max_fee = 2; - AccountSignature signature = 3; - Hash class_hash = 4; - } - - message DeclareV1 { - Address sender = 1; - Felt252 max_fee = 2; - AccountSignature signature = 3; - Hash class_hash = 4; - Felt252 nonce = 5; - } - - message DeclareV2 { - Address sender = 1; - Felt252 max_fee = 2; - AccountSignature signature = 3; - Hash class_hash = 4; - Felt252 nonce = 5; - Hash compiled_class_hash = 6; - } - - // see https://external.integration.starknet.io/feeder_gateway/get_transaction?transactionHash=0x41d1f5206ef58a443e7d3d1ca073171ec25fa75313394318fc83a074a6631c3 - message DeclareV3 { - Address sender = 1; - AccountSignature signature = 2; - Hash class_hash = 3; - Felt252 nonce = 4; - Hash compiled_class_hash = 5; - ResourceBounds resource_bounds = 6; - uint64 tip = 7; - repeated Felt252 paymaster_data = 8; - repeated Felt252 account_deployment_data = 9; - VolitionDomain nonce_data_availability_mode = 10; - VolitionDomain fee_data_availability_mode = 11; - } - - message Deploy { - Hash class_hash = 1; - Felt252 address_salt = 2; - repeated Felt252 calldata = 3; - uint32 version = 4; - } - - message DeployAccountV1 { - Felt252 max_fee = 1; - AccountSignature signature = 2; - Hash class_hash = 3; - Felt252 nonce = 4; - Felt252 address_salt = 5; - repeated Felt252 calldata = 6; - } - - // see https://external.integration.starknet.io/feeder_gateway/get_transaction?transactionHash=0x29fd7881f14380842414cdfdd8d6c0b1f2174f8916edcfeb1ede1eb26ac3ef0 - message DeployAccountV3 { - AccountSignature signature = 1; - Hash class_hash = 2; - Felt252 nonce = 3; - Felt252 address_salt = 4; - repeated Felt252 calldata = 5; - ResourceBounds resource_bounds = 6; - uint64 tip = 7; - repeated Felt252 paymaster_data = 8; - VolitionDomain nonce_data_availability_mode = 9; - VolitionDomain fee_data_availability_mode = 10; - } - - message InvokeV0 { - Felt252 max_fee = 1; - AccountSignature signature = 2; - Address address = 3; - Felt252 entry_point_selector = 4; - repeated Felt252 calldata = 5; - } - - message InvokeV1 { - Address sender = 1; - Felt252 max_fee = 2; - AccountSignature signature = 3; - repeated Felt252 calldata = 4; - Felt252 nonce = 5; - } - - // see https://external.integration.starknet.io/feeder_gateway/get_transaction?transactionHash=0x41906f1c314cca5f43170ea75d3b1904196a10101190d2b12a41cc61cfd17c - message InvokeV3 { - Address sender = 1; - AccountSignature signature = 2; - repeated Felt252 calldata = 3; - ResourceBounds resource_bounds = 4; - uint64 tip = 5; - repeated Felt252 paymaster_data = 6; - repeated Felt252 account_deployment_data = 7; - VolitionDomain nonce_data_availability_mode = 8; - VolitionDomain fee_data_availability_mode = 9; - Felt252 nonce = 10; - } - - message L1HandlerV0 { - Felt252 nonce = 1; - Address address = 2; - Felt252 entry_point_selector = 3; - repeated Felt252 calldata = 4; - } +message L1HandlerV0 { + Felt252 nonce = 1; + Address address = 2; + Felt252 entry_point_selector = 3; + repeated Felt252 calldata = 4; +} - oneof txn { - DeclareV0 declare_v0 = 1; - DeclareV1 declare_v1 = 2; - DeclareV2 declare_v2 = 3; - DeclareV3 declare_v3 = 4; - Deploy deploy = 5; - DeployAccountV1 deploy_account_v1 = 6; - DeployAccountV3 deploy_account_v3 = 7; - InvokeV0 invoke_v0 = 8; - InvokeV1 invoke_v1 = 9; - InvokeV3 invoke_v3 = 10; - L1HandlerV0 l1_handler = 11; - } - Hash transaction_hash = 12; +message DeclareV3Common { + Address sender = 1; + AccountSignature signature = 2; + Felt252 nonce = 4; + Hash compiled_class_hash = 5; + ResourceBounds resource_bounds = 6; + uint64 tip = 7; + repeated Felt252 paymaster_data = 8; + repeated Felt252 account_deployment_data = 9; + VolitionDomain nonce_data_availability_mode = 10; + VolitionDomain fee_data_availability_mode = 11; } -message TransactionWithReceipt { - Transaction transaction = 1; - Receipt receipt = 2; +message DeclareV3WithClass { + DeclareV3Common common = 1; + Cairo1Class class = 2; } -// TBD: can support a flag to return tx hashes only, good for standalone mempool to remove them, -// or any node that keeps track of transaction streaming in the consensus. -message TransactionsRequest { - Iteration iteration = 1; + +// see https://external.integration.starknet.io/feeder_gateway/get_transaction?transactionHash=0x41906f1c314cca5f43170ea75d3b1904196a10101190d2b12a41cc61cfd17c +message InvokeV3 { + Address sender = 1; + AccountSignature signature = 2; + repeated Felt252 calldata = 3; + ResourceBounds resource_bounds = 4; + uint64 tip = 5; + repeated Felt252 paymaster_data = 6; + repeated Felt252 account_deployment_data = 7; + VolitionDomain nonce_data_availability_mode = 8; + VolitionDomain fee_data_availability_mode = 9; + Felt252 nonce = 10; } -// Responses are sent ordered by the order given in the request. The order inside each block is -// according to the execution order. -message TransactionsResponse { - oneof transaction_message { - TransactionWithReceipt transaction_with_receipt = 1; - Fin fin = 2; // Fin is sent after the peer sent all the data or when it encountered a block that it doesn't have its transactions. - } +// see https://external.integration.starknet.io/feeder_gateway/get_transaction?transactionHash=0x29fd7881f14380842414cdfdd8d6c0b1f2174f8916edcfeb1ede1eb26ac3ef0 +message DeployAccountV3 { + AccountSignature signature = 1; + Hash class_hash = 2; + Felt252 nonce = 3; + Felt252 address_salt = 4; + repeated Felt252 calldata = 5; + ResourceBounds resource_bounds = 6; + uint64 tip = 7; + repeated Felt252 paymaster_data = 8; + VolitionDomain nonce_data_availability_mode = 9; + VolitionDomain fee_data_availability_mode = 10; } diff --git a/crates/papyrus_protobuf/src/protobuf.rs b/crates/papyrus_protobuf/src/protobuf.rs index cf3f29b13a9..a3208dae8cb 100644 --- a/crates/papyrus_protobuf/src/protobuf.rs +++ b/crates/papyrus_protobuf/src/protobuf.rs @@ -1,3 +1,5 @@ // TODO(Dan, Shahak): consider whether to enable clippy::large_enum_variant #![allow(clippy::large_enum_variant)] -include!(concat!(env!("OUT_DIR"), "/_.rs")); +pub mod protoc_output; + +pub use protoc_output::*; diff --git a/crates/papyrus_protobuf/src/protobuf/protoc_output.rs b/crates/papyrus_protobuf/src/protobuf/protoc_output.rs new file mode 100644 index 00000000000..3c6744ef19e --- /dev/null +++ b/crates/papyrus_protobuf/src/protobuf/protoc_output.rs @@ -0,0 +1,1184 @@ +// This file is @generated by prost-build. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Felt252 { + #[prost(bytes = "vec", tag = "1")] + pub elements: ::prost::alloc::vec::Vec, +} +/// A hash value representable as a Felt252 +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Hash { + #[prost(bytes = "vec", tag = "1")] + pub elements: ::prost::alloc::vec::Vec, +} +/// A 256 bit hash value (like Keccak256) +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Hash256 { + /// Required to be 32 bytes long + #[prost(bytes = "vec", tag = "1")] + pub elements: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Hashes { + #[prost(message, repeated, tag = "1")] + pub items: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Address { + #[prost(bytes = "vec", tag = "1")] + pub elements: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PeerId { + #[prost(bytes = "vec", tag = "1")] + pub id: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Uint128 { + #[prost(uint64, tag = "1")] + pub low: u64, + #[prost(uint64, tag = "2")] + pub high: u64, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ConsensusSignature { + #[prost(message, optional, tag = "1")] + pub r: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub s: ::core::option::Option, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Patricia { + /// needed to know the height, so as to how many nodes to expect in a proof. + #[prost(uint64, tag = "1")] + pub n_leaves: u64, + /// and also when receiving all leaves, how many to expect + #[prost(message, optional, tag = "2")] + pub root: ::core::option::Option, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BlockId { + #[prost(uint64, tag = "1")] + pub number: u64, + #[prost(message, optional, tag = "2")] + pub header: ::core::option::Option, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BlockProof { + #[prost(bytes = "vec", repeated, tag = "1")] + pub proof: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, +} +/// mark the end of a stream of messages +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Fin {} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum L1DataAvailabilityMode { + Calldata = 0, + Blob = 1, +} +impl L1DataAvailabilityMode { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + L1DataAvailabilityMode::Calldata => "Calldata", + L1DataAvailabilityMode::Blob => "Blob", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "Calldata" => Some(Self::Calldata), + "Blob" => Some(Self::Blob), + _ => None, + } + } +} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum VolitionDomain { + L1 = 0, + L2 = 1, +} +impl VolitionDomain { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + VolitionDomain::L1 => "L1", + VolitionDomain::L2 => "L2", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "L1" => Some(Self::L1), + "L2" => Some(Self::L2), + _ => None, + } + } +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct EntryPoint { + #[prost(message, optional, tag = "1")] + pub selector: ::core::option::Option, + #[prost(uint64, tag = "2")] + pub offset: u64, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Cairo0Class { + #[prost(string, tag = "1")] + pub abi: ::prost::alloc::string::String, + #[prost(message, repeated, tag = "2")] + pub externals: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "3")] + pub l1_handlers: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "4")] + pub constructors: ::prost::alloc::vec::Vec, + /// Compressed in base64 representation. + #[prost(string, tag = "5")] + pub program: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SierraEntryPoint { + #[prost(uint64, tag = "1")] + pub index: u64, + #[prost(message, optional, tag = "2")] + pub selector: ::core::option::Option, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Cairo1EntryPoints { + #[prost(message, repeated, tag = "1")] + pub externals: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "2")] + pub l1_handlers: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "3")] + pub constructors: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Cairo1Class { + #[prost(string, tag = "1")] + pub abi: ::prost::alloc::string::String, + #[prost(message, optional, tag = "2")] + pub entry_points: ::core::option::Option, + #[prost(message, repeated, tag = "3")] + pub program: ::prost::alloc::vec::Vec, + #[prost(string, tag = "4")] + pub contract_class_version: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Class { + #[prost(uint32, tag = "3")] + pub domain: u32, + #[prost(message, optional, tag = "4")] + pub class_hash: ::core::option::Option, + #[prost(oneof = "class::Class", tags = "1, 2")] + pub class: ::core::option::Option, +} +/// Nested message and enum types in `Class`. +pub mod class { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Class { + #[prost(message, tag = "1")] + Cairo0(super::Cairo0Class), + #[prost(message, tag = "2")] + Cairo1(super::Cairo1Class), + } +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ResourceLimits { + /// TODO(shahak, alonl): figure out if max_amount should be uint64 or Felt252 + #[prost(uint64, tag = "1")] + pub max_amount: u64, + #[prost(message, optional, tag = "2")] + pub max_price_per_unit: ::core::option::Option, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ResourceBounds { + #[prost(message, optional, tag = "1")] + pub l1_gas: ::core::option::Option, + /// This can be None only in transactions that don't support l2 gas. + /// Starting from 0.14.0, MempoolTransaction and ConsensusTransaction shouldn't have None here. + #[prost(message, optional, tag = "2")] + pub l1_data_gas: ::core::option::Option, + #[prost(message, optional, tag = "3")] + pub l2_gas: ::core::option::Option, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AccountSignature { + #[prost(message, repeated, tag = "1")] + pub parts: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct L1HandlerV0 { + #[prost(message, optional, tag = "1")] + pub nonce: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub address: ::core::option::Option
, + #[prost(message, optional, tag = "3")] + pub entry_point_selector: ::core::option::Option, + #[prost(message, repeated, tag = "4")] + pub calldata: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DeclareV3Common { + #[prost(message, optional, tag = "1")] + pub sender: ::core::option::Option
, + #[prost(message, optional, tag = "2")] + pub signature: ::core::option::Option, + #[prost(message, optional, tag = "4")] + pub nonce: ::core::option::Option, + #[prost(message, optional, tag = "5")] + pub compiled_class_hash: ::core::option::Option, + #[prost(message, optional, tag = "6")] + pub resource_bounds: ::core::option::Option, + #[prost(uint64, tag = "7")] + pub tip: u64, + #[prost(message, repeated, tag = "8")] + pub paymaster_data: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "9")] + pub account_deployment_data: ::prost::alloc::vec::Vec, + #[prost(enumeration = "VolitionDomain", tag = "10")] + pub nonce_data_availability_mode: i32, + #[prost(enumeration = "VolitionDomain", tag = "11")] + pub fee_data_availability_mode: i32, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DeclareV3WithClass { + #[prost(message, optional, tag = "1")] + pub common: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub class: ::core::option::Option, +} +/// see +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct InvokeV3 { + #[prost(message, optional, tag = "1")] + pub sender: ::core::option::Option
, + #[prost(message, optional, tag = "2")] + pub signature: ::core::option::Option, + #[prost(message, repeated, tag = "3")] + pub calldata: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "4")] + pub resource_bounds: ::core::option::Option, + #[prost(uint64, tag = "5")] + pub tip: u64, + #[prost(message, repeated, tag = "6")] + pub paymaster_data: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "7")] + pub account_deployment_data: ::prost::alloc::vec::Vec, + #[prost(enumeration = "VolitionDomain", tag = "8")] + pub nonce_data_availability_mode: i32, + #[prost(enumeration = "VolitionDomain", tag = "9")] + pub fee_data_availability_mode: i32, + #[prost(message, optional, tag = "10")] + pub nonce: ::core::option::Option, +} +/// see +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DeployAccountV3 { + #[prost(message, optional, tag = "1")] + pub signature: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub class_hash: ::core::option::Option, + #[prost(message, optional, tag = "3")] + pub nonce: ::core::option::Option, + #[prost(message, optional, tag = "4")] + pub address_salt: ::core::option::Option, + #[prost(message, repeated, tag = "5")] + pub calldata: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "6")] + pub resource_bounds: ::core::option::Option, + #[prost(uint64, tag = "7")] + pub tip: u64, + #[prost(message, repeated, tag = "8")] + pub paymaster_data: ::prost::alloc::vec::Vec, + #[prost(enumeration = "VolitionDomain", tag = "9")] + pub nonce_data_availability_mode: i32, + #[prost(enumeration = "VolitionDomain", tag = "10")] + pub fee_data_availability_mode: i32, +} +/// Contains all variants of mempool and an L1Handler variant to cover all transactions that can be +/// in a new block. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ConsensusTransaction { + #[prost(message, optional, tag = "5")] + pub transaction_hash: ::core::option::Option, + #[prost(oneof = "consensus_transaction::Txn", tags = "1, 2, 3, 4")] + pub txn: ::core::option::Option, +} +/// Nested message and enum types in `ConsensusTransaction`. +pub mod consensus_transaction { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Txn { + #[prost(message, tag = "1")] + DeclareV3(super::DeclareV3WithClass), + #[prost(message, tag = "2")] + DeployAccountV3(super::DeployAccountV3), + #[prost(message, tag = "3")] + InvokeV3(super::InvokeV3), + #[prost(message, tag = "4")] + L1Handler(super::L1HandlerV0), + } +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Vote { + /// We use a type field to distinguish between prevotes and precommits instead of different + /// messages, to make sure the data, and therefore the signatures, are unambiguous between + /// Prevote and Precommit. + #[prost(enumeration = "vote::VoteType", tag = "2")] + pub vote_type: i32, + #[prost(uint64, tag = "3")] + pub height: u64, + #[prost(uint32, tag = "4")] + pub round: u32, + /// This is optional since a vote can be NIL. + #[prost(message, optional, tag = "5")] + pub block_hash: ::core::option::Option, + #[prost(message, optional, tag = "6")] + pub voter: ::core::option::Option
, +} +/// Nested message and enum types in `Vote`. +pub mod vote { + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum VoteType { + Prevote = 0, + Precommit = 1, + } + impl VoteType { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + VoteType::Prevote => "Prevote", + VoteType::Precommit => "Precommit", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "Prevote" => Some(Self::Prevote), + "Precommit" => Some(Self::Precommit), + _ => None, + } + } + } +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct StreamMessage { + #[prost(bytes = "vec", tag = "3")] + pub stream_id: ::prost::alloc::vec::Vec, + #[prost(uint64, tag = "4")] + pub message_id: u64, + #[prost(oneof = "stream_message::Message", tags = "1, 2")] + pub message: ::core::option::Option, +} +/// Nested message and enum types in `StreamMessage`. +pub mod stream_message { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Message { + #[prost(bytes, tag = "1")] + Content(::prost::alloc::vec::Vec), + #[prost(message, tag = "2")] + Fin(super::Fin), + } +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ProposalInit { + #[prost(uint64, tag = "1")] + pub height: u64, + #[prost(uint32, tag = "2")] + pub round: u32, + #[prost(uint32, optional, tag = "3")] + pub valid_round: ::core::option::Option, + #[prost(message, optional, tag = "4")] + pub proposer: ::core::option::Option
, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BlockInfo { + #[prost(uint64, tag = "1")] + pub height: u64, + #[prost(uint64, tag = "2")] + pub timestamp: u64, + #[prost(message, optional, tag = "3")] + pub builder: ::core::option::Option
, + #[prost(enumeration = "L1DataAvailabilityMode", tag = "4")] + pub l1_da_mode: i32, + #[prost(message, optional, tag = "5")] + pub l2_gas_price_fri: ::core::option::Option, + #[prost(message, optional, tag = "6")] + pub l1_gas_price_wei: ::core::option::Option, + #[prost(message, optional, tag = "7")] + pub l1_data_gas_price_wei: ::core::option::Option, + #[prost(message, optional, tag = "8")] + pub eth_to_fri_rate: ::core::option::Option, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TransactionBatch { + #[prost(message, repeated, tag = "1")] + pub transactions: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ProposalFin { + /// Identifies a Starknet block based on the content streamed in the proposal. + #[prost(message, optional, tag = "1")] + pub proposal_commitment: ::core::option::Option, +} +/// Network format: +/// 1. First message is ProposalInit +/// 2. Last message is ProposalFin +/// 3. In between can be any number of other messages. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ProposalPart { + #[prost(oneof = "proposal_part::Message", tags = "1, 2, 3, 4")] + pub message: ::core::option::Option, +} +/// Nested message and enum types in `ProposalPart`. +pub mod proposal_part { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Message { + #[prost(message, tag = "1")] + Init(super::ProposalInit), + #[prost(message, tag = "2")] + Fin(super::ProposalFin), + #[prost(message, tag = "3")] + BlockInfo(super::BlockInfo), + #[prost(message, tag = "4")] + Transactions(super::TransactionBatch), + } +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct StateDiffCommitment { + #[prost(uint64, tag = "1")] + pub state_diff_length: u64, + #[prost(message, optional, tag = "2")] + pub root: ::core::option::Option, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Iteration { + #[prost(enumeration = "iteration::Direction", tag = "3")] + pub direction: i32, + #[prost(uint64, tag = "4")] + pub limit: u64, + /// to allow interleaving from several nodes + #[prost(uint64, tag = "5")] + pub step: u64, + #[prost(oneof = "iteration::Start", tags = "1, 2")] + pub start: ::core::option::Option, +} +/// Nested message and enum types in `Iteration`. +pub mod iteration { + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum Direction { + Forward = 0, + Backward = 1, + } + impl Direction { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Direction::Forward => "Forward", + Direction::Backward => "Backward", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "Forward" => Some(Self::Forward), + "Backward" => Some(Self::Backward), + _ => None, + } + } + } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Start { + #[prost(uint64, tag = "1")] + BlockNumber(u64), + #[prost(message, tag = "2")] + Header(super::Hash), + } +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MessageToL1 { + #[prost(message, optional, tag = "2")] + pub from_address: ::core::option::Option, + #[prost(message, repeated, tag = "3")] + pub payload: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "4")] + pub to_address: ::core::option::Option, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct EthereumAddress { + #[prost(bytes = "vec", tag = "1")] + pub elements: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Receipt { + #[prost(oneof = "receipt::Type", tags = "1, 2, 3, 4, 5")] + pub r#type: ::core::option::Option, +} +/// Nested message and enum types in `Receipt`. +pub mod receipt { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct ExecutionResources { + #[prost(message, optional, tag = "1")] + pub builtins: ::core::option::Option, + #[prost(uint32, tag = "2")] + pub steps: u32, + #[prost(uint32, tag = "3")] + pub memory_holes: u32, + #[prost(message, optional, tag = "4")] + pub da_gas_consumed: ::core::option::Option, + #[prost(message, optional, tag = "5")] + pub gas_consumed: ::core::option::Option, + } + /// Nested message and enum types in `ExecutionResources`. + pub mod execution_resources { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct BuiltinCounter { + #[prost(uint32, tag = "1")] + pub bitwise: u32, + #[prost(uint32, tag = "2")] + pub ecdsa: u32, + #[prost(uint32, tag = "3")] + pub ec_op: u32, + #[prost(uint32, tag = "4")] + pub pedersen: u32, + #[prost(uint32, tag = "5")] + pub range_check: u32, + #[prost(uint32, tag = "6")] + pub poseidon: u32, + #[prost(uint32, tag = "7")] + pub keccak: u32, + /// TODO(alonl): add the missing builtins + #[prost(uint32, tag = "8")] + pub output: u32, + } + /// TODO(alonl): remove GasVector and unsplit gas_consumed and da_gas_consumed + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct GasVector { + #[prost(uint64, tag = "1")] + pub l1_gas: u64, + #[prost(uint64, tag = "2")] + pub l1_data_gas: u64, + #[prost(uint64, tag = "3")] + pub l2_gas: u64, + } + } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct Common { + #[prost(message, optional, tag = "2")] + pub actual_fee: ::core::option::Option, + #[prost(enumeration = "super::PriceUnit", tag = "3")] + pub price_unit: i32, + #[prost(message, repeated, tag = "4")] + pub messages_sent: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "5")] + pub execution_resources: ::core::option::Option, + #[prost(string, optional, tag = "6")] + pub revert_reason: ::core::option::Option<::prost::alloc::string::String>, + } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct Invoke { + #[prost(message, optional, tag = "1")] + pub common: ::core::option::Option, + } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct L1Handler { + #[prost(message, optional, tag = "1")] + pub common: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub msg_hash: ::core::option::Option, + } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct Declare { + #[prost(message, optional, tag = "1")] + pub common: ::core::option::Option, + } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct Deploy { + #[prost(message, optional, tag = "1")] + pub common: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub contract_address: ::core::option::Option, + } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct DeployAccount { + #[prost(message, optional, tag = "1")] + pub common: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub contract_address: ::core::option::Option, + } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Type { + #[prost(message, tag = "1")] + Invoke(Invoke), + #[prost(message, tag = "2")] + L1Handler(L1Handler), + #[prost(message, tag = "3")] + Declare(Declare), + #[prost(message, tag = "4")] + DeprecatedDeploy(Deploy), + #[prost(message, tag = "5")] + DeployAccount(DeployAccount), + } +} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum PriceUnit { + Wei = 0, + Fri = 1, +} +impl PriceUnit { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + PriceUnit::Wei => "Wei", + PriceUnit::Fri => "Fri", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "Wei" => Some(Self::Wei), + "Fri" => Some(Self::Fri), + _ => None, + } + } +} +/// TBD: can support a flag to return tx hashes only, good for standalone mempool to remove them, +/// or any node that keeps track of transaction streaming in the consensus. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TransactionsRequest { + #[prost(message, optional, tag = "1")] + pub iteration: ::core::option::Option, +} +/// Responses are sent ordered by the order given in the request. The order inside each block is +/// according to the execution order. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TransactionsResponse { + #[prost(oneof = "transactions_response::TransactionMessage", tags = "1, 2")] + pub transaction_message: ::core::option::Option< + transactions_response::TransactionMessage, + >, +} +/// Nested message and enum types in `TransactionsResponse`. +pub mod transactions_response { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum TransactionMessage { + #[prost(message, tag = "1")] + TransactionWithReceipt(super::TransactionWithReceipt), + /// Fin is sent after the peer sent all the data or when it encountered a block that it doesn't have its transactions. + #[prost(message, tag = "2")] + Fin(super::Fin), + } +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TransactionWithReceipt { + #[prost(message, optional, tag = "1")] + pub transaction: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub receipt: ::core::option::Option, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TransactionInBlock { + #[prost(message, optional, tag = "12")] + pub transaction_hash: ::core::option::Option, + #[prost( + oneof = "transaction_in_block::Txn", + tags = "1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11" + )] + pub txn: ::core::option::Option, +} +/// Nested message and enum types in `TransactionInBlock`. +pub mod transaction_in_block { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct DeclareV0WithoutClass { + #[prost(message, optional, tag = "1")] + pub sender: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub max_fee: ::core::option::Option, + #[prost(message, optional, tag = "3")] + pub signature: ::core::option::Option, + #[prost(message, optional, tag = "4")] + pub class_hash: ::core::option::Option, + } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct DeclareV1WithoutClass { + #[prost(message, optional, tag = "1")] + pub sender: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub max_fee: ::core::option::Option, + #[prost(message, optional, tag = "3")] + pub signature: ::core::option::Option, + #[prost(message, optional, tag = "4")] + pub class_hash: ::core::option::Option, + #[prost(message, optional, tag = "5")] + pub nonce: ::core::option::Option, + } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct DeclareV2WithoutClass { + #[prost(message, optional, tag = "1")] + pub sender: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub max_fee: ::core::option::Option, + #[prost(message, optional, tag = "3")] + pub signature: ::core::option::Option, + #[prost(message, optional, tag = "4")] + pub class_hash: ::core::option::Option, + #[prost(message, optional, tag = "5")] + pub nonce: ::core::option::Option, + #[prost(message, optional, tag = "6")] + pub compiled_class_hash: ::core::option::Option, + } + /// see + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct DeclareV3WithoutClass { + #[prost(message, optional, tag = "1")] + pub common: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub class_hash: ::core::option::Option, + } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct Deploy { + #[prost(message, optional, tag = "1")] + pub class_hash: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub address_salt: ::core::option::Option, + #[prost(message, repeated, tag = "3")] + pub calldata: ::prost::alloc::vec::Vec, + #[prost(uint32, tag = "4")] + pub version: u32, + } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct DeployAccountV1 { + #[prost(message, optional, tag = "1")] + pub max_fee: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub signature: ::core::option::Option, + #[prost(message, optional, tag = "3")] + pub class_hash: ::core::option::Option, + #[prost(message, optional, tag = "4")] + pub nonce: ::core::option::Option, + #[prost(message, optional, tag = "5")] + pub address_salt: ::core::option::Option, + #[prost(message, repeated, tag = "6")] + pub calldata: ::prost::alloc::vec::Vec, + } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct InvokeV0 { + #[prost(message, optional, tag = "1")] + pub max_fee: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub signature: ::core::option::Option, + #[prost(message, optional, tag = "3")] + pub address: ::core::option::Option, + #[prost(message, optional, tag = "4")] + pub entry_point_selector: ::core::option::Option, + #[prost(message, repeated, tag = "5")] + pub calldata: ::prost::alloc::vec::Vec, + } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct InvokeV1 { + #[prost(message, optional, tag = "1")] + pub sender: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub max_fee: ::core::option::Option, + #[prost(message, optional, tag = "3")] + pub signature: ::core::option::Option, + #[prost(message, repeated, tag = "4")] + pub calldata: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "5")] + pub nonce: ::core::option::Option, + } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Txn { + #[prost(message, tag = "1")] + DeclareV0(DeclareV0WithoutClass), + #[prost(message, tag = "2")] + DeclareV1(DeclareV1WithoutClass), + #[prost(message, tag = "3")] + DeclareV2(DeclareV2WithoutClass), + #[prost(message, tag = "4")] + DeclareV3(DeclareV3WithoutClass), + #[prost(message, tag = "5")] + Deploy(Deploy), + #[prost(message, tag = "6")] + DeployAccountV1(DeployAccountV1), + #[prost(message, tag = "7")] + DeployAccountV3(super::DeployAccountV3), + #[prost(message, tag = "8")] + InvokeV0(InvokeV0), + #[prost(message, tag = "9")] + InvokeV1(InvokeV1), + #[prost(message, tag = "10")] + InvokeV3(super::InvokeV3), + #[prost(message, tag = "11")] + L1Handler(super::L1HandlerV0), + } +} +/// Doesn't contain L1Handler, as those don't need to be propagated and can be downloaded from L1. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MempoolTransaction { + #[prost(message, optional, tag = "4")] + pub transaction_hash: ::core::option::Option, + #[prost(oneof = "mempool_transaction::Txn", tags = "1, 2, 3")] + pub txn: ::core::option::Option, +} +/// Nested message and enum types in `MempoolTransaction`. +pub mod mempool_transaction { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Txn { + #[prost(message, tag = "1")] + DeclareV3(super::DeclareV3WithClass), + #[prost(message, tag = "2")] + DeployAccountV3(super::DeployAccountV3), + #[prost(message, tag = "3")] + InvokeV3(super::InvokeV3), + } +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MempoolTransactionBatch { + #[prost(message, repeated, tag = "1")] + pub transactions: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ClassesRequest { + #[prost(message, optional, tag = "1")] + pub iteration: ::core::option::Option, +} +/// Responses are sent ordered by the order given in the request. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ClassesResponse { + #[prost(oneof = "classes_response::ClassMessage", tags = "1, 2")] + pub class_message: ::core::option::Option, +} +/// Nested message and enum types in `ClassesResponse`. +pub mod classes_response { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum ClassMessage { + #[prost(message, tag = "1")] + Class(super::Class), + /// Fin is sent after the peer sent all the data or when it encountered a block that it doesn't have its classes. + #[prost(message, tag = "2")] + Fin(super::Fin), + } +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Event { + #[prost(message, optional, tag = "1")] + pub transaction_hash: ::core::option::Option, + #[prost(message, optional, tag = "3")] + pub from_address: ::core::option::Option, + #[prost(message, repeated, tag = "4")] + pub keys: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "5")] + pub data: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct EventsRequest { + #[prost(message, optional, tag = "1")] + pub iteration: ::core::option::Option, +} +/// Responses are sent ordered by the order given in the request. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct EventsResponse { + #[prost(oneof = "events_response::EventMessage", tags = "1, 2")] + pub event_message: ::core::option::Option, +} +/// Nested message and enum types in `EventsResponse`. +pub mod events_response { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum EventMessage { + #[prost(message, tag = "1")] + Event(super::Event), + /// Fin is sent after the peer sent all the data or when it encountered a block that it doesn't have its events. + #[prost(message, tag = "2")] + Fin(super::Fin), + } +} +/// Note: commitments may change to be for the previous blocks like comet/tendermint +/// hash of block header sent to L1 +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SignedBlockHeader { + /// For the structure of the block hash, see + #[prost(message, optional, tag = "1")] + pub block_hash: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub parent_hash: ::core::option::Option, + /// This can be deduced from context. We can consider removing this field. + #[prost(uint64, tag = "3")] + pub number: u64, + /// Encoded in Unix time. + #[prost(uint64, tag = "4")] + pub time: u64, + #[prost(message, optional, tag = "5")] + pub sequencer_address: ::core::option::Option
, + /// Patricia root of contract and class patricia tries. Each of those tries are of height 251. Same as in L1. Later more trees will be included + #[prost(message, optional, tag = "6")] + pub state_root: ::core::option::Option, + /// The state diff commitment returned by the Starknet Feeder Gateway + #[prost(message, optional, tag = "7")] + pub state_diff_commitment: ::core::option::Option, + /// For more info, see + /// The leaves contain a hash of the transaction hash and transaction signature. + /// + /// By order of execution. TBD: required? the client can execute (powerful machine) and match state diff + #[prost(message, optional, tag = "8")] + pub transactions: ::core::option::Option, + /// By order of issuance. TBD: in receipts? + #[prost(message, optional, tag = "9")] + pub events: ::core::option::Option, + /// By order of issuance. This is a patricia root. No need for length because it's the same length as transactions. + #[prost(message, optional, tag = "10")] + pub receipts: ::core::option::Option, + /// Starknet version + #[prost(string, tag = "11")] + pub protocol_version: ::prost::alloc::string::String, + #[prost(message, optional, tag = "12")] + pub l1_gas_price_fri: ::core::option::Option, + #[prost(message, optional, tag = "13")] + pub l1_gas_price_wei: ::core::option::Option, + #[prost(message, optional, tag = "14")] + pub l1_data_gas_price_fri: ::core::option::Option, + #[prost(message, optional, tag = "15")] + pub l1_data_gas_price_wei: ::core::option::Option, + #[prost(message, optional, tag = "16")] + pub l2_gas_price_fri: ::core::option::Option, + #[prost(message, optional, tag = "17")] + pub l2_gas_price_wei: ::core::option::Option, + #[prost(uint64, tag = "18")] + pub l2_gas_consumed: u64, + #[prost(uint64, tag = "19")] + pub next_l2_gas_price: u64, + #[prost(enumeration = "L1DataAvailabilityMode", tag = "20")] + pub l1_data_availability_mode: i32, + /// for now, we assume a small consensus, so this fits in 1M. Else, these will be repeated and extracted from this message. + /// + /// can be more explicit here about the signature structure as this is not part of account abstraction + #[prost(message, repeated, tag = "21")] + pub signatures: ::prost::alloc::vec::Vec, +} +/// sent to all peers (except the ones this was received from, if any). +/// for a fraction of peers, also send the GetBlockHeaders response (as if they asked for it for this block) +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct NewBlock { + #[prost(oneof = "new_block::MaybeFull", tags = "1, 2")] + pub maybe_full: ::core::option::Option, +} +/// Nested message and enum types in `NewBlock`. +pub mod new_block { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum MaybeFull { + #[prost(message, tag = "1")] + Id(super::BlockId), + #[prost(message, tag = "2")] + Header(super::BlockHeadersResponse), + } +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BlockHeadersRequest { + #[prost(message, optional, tag = "1")] + pub iteration: ::core::option::Option, +} +/// Responses are sent ordered by the order given in the request. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BlockHeadersResponse { + #[prost(oneof = "block_headers_response::HeaderMessage", tags = "1, 2")] + pub header_message: ::core::option::Option, +} +/// Nested message and enum types in `BlockHeadersResponse`. +pub mod block_headers_response { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum HeaderMessage { + #[prost(message, tag = "1")] + Header(super::SignedBlockHeader), + /// Fin is sent after the peer sent all the data or when it encountered a block that it doesn't have its header. + #[prost(message, tag = "2")] + Fin(super::Fin), + } +} +/// optimized for flat storage, not through a trie (not sharing key prefixes) +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ContractStoredValue { + #[prost(message, optional, tag = "1")] + pub key: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub value: ::core::option::Option, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ContractDiff { + #[prost(message, optional, tag = "1")] + pub address: ::core::option::Option
, + /// Present only if the nonce was updated + #[prost(message, optional, tag = "2")] + pub nonce: ::core::option::Option, + /// Present only if the contract was deployed or replaced in this block. + #[prost(message, optional, tag = "3")] + pub class_hash: ::core::option::Option, + #[prost(message, repeated, tag = "4")] + pub values: ::prost::alloc::vec::Vec, + #[prost(enumeration = "VolitionDomain", tag = "5")] + pub domain: i32, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DeclaredClass { + #[prost(message, optional, tag = "1")] + pub class_hash: ::core::option::Option, + /// Present only if the class is Cairo1 + #[prost(message, optional, tag = "2")] + pub compiled_class_hash: ::core::option::Option, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct StateDiffsRequest { + #[prost(message, optional, tag = "1")] + pub iteration: ::core::option::Option, +} +/// Responses are sent ordered by the order given in the request. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct StateDiffsResponse { + /// All of the messages related to a block need to be sent before a message from the next block is sent. + #[prost(oneof = "state_diffs_response::StateDiffMessage", tags = "1, 2, 3")] + pub state_diff_message: ::core::option::Option< + state_diffs_response::StateDiffMessage, + >, +} +/// Nested message and enum types in `StateDiffsResponse`. +pub mod state_diffs_response { + /// All of the messages related to a block need to be sent before a message from the next block is sent. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum StateDiffMessage { + /// Multiple contract diffs for the same contract may appear continuously if the diff is too large or if it's more convenient. + #[prost(message, tag = "1")] + ContractDiff(super::ContractDiff), + #[prost(message, tag = "2")] + DeclaredClass(super::DeclaredClass), + /// Fin is sent after the peer sent all the data or when it encountered a block that it doesn't have its state diff. + #[prost(message, tag = "3")] + Fin(super::Fin), + } +} diff --git a/crates/papyrus_protobuf/src/protoc_regression_test.rs b/crates/papyrus_protobuf/src/protoc_regression_test.rs new file mode 100644 index 00000000000..29df2b3510b --- /dev/null +++ b/crates/papyrus_protobuf/src/protoc_regression_test.rs @@ -0,0 +1,30 @@ +use std::fs; +use std::path::PathBuf; + +use tempfile::tempdir; + +use crate::regression_test_utils::{generate_protos, PROTOC_OUTPUT, PROTO_DIR, PROTO_FILES}; + +#[test] +fn protoc_output_matches_result_of_running_protoc() { + let out_dir = tempdir().unwrap(); + + generate_protos(out_dir.path().to_path_buf(), PROTO_FILES).unwrap(); + + let generated_name = PathBuf::from(out_dir.path()).join("_.rs"); + let expected_name = PathBuf::from(PROTO_DIR).join(PROTOC_OUTPUT); + + let expected_file = fs::read_to_string(&expected_name) + .unwrap_or_else(|_| panic!("Failed to read expected file at {:?}", expected_name)); + let generated_file = fs::read_to_string(&generated_name) + .unwrap_or_else(|_| panic!("Failed to read generated file at {:?}", generated_name)); + + // Using assert instead of assert_eq to avoid showing the entire content of the files on + // assertion fail + assert!( + expected_file == generated_file, + "Generated protos are different from precompiled protos. Run 'cargo run --bin \ + generate_protoc_output -q --features bin-deps' to override precompiled protos with newly \ + generated." + ); +} diff --git a/crates/papyrus_protobuf/build.rs b/crates/papyrus_protobuf/src/regression_test_utils.rs similarity index 56% rename from crates/papyrus_protobuf/build.rs rename to crates/papyrus_protobuf/src/regression_test_utils.rs index f6da55625dd..abf831c0940 100644 --- a/crates/papyrus_protobuf/build.rs +++ b/crates/papyrus_protobuf/src/regression_test_utils.rs @@ -1,6 +1,63 @@ +use std::path::PathBuf; use std::process::Command; use std::{env, io}; +use tracing::info; + +pub const PROTO_DIR: &str = "src/protobuf"; +pub const PROTO_FILES: &[&str] = &[ + "src/proto/p2p/proto/class.proto", + "src/proto/p2p/proto/consensus/consensus.proto", + "src/proto/p2p/proto/mempool/transaction.proto", + "src/proto/p2p/proto/sync/class.proto", + "src/proto/p2p/proto/sync/event.proto", + "src/proto/p2p/proto/sync/header.proto", + "src/proto/p2p/proto/sync/state.proto", + "src/proto/p2p/proto/sync/receipt.proto", + "src/proto/p2p/proto/sync/transaction.proto", + "src/proto/p2p/proto/transaction.proto", +]; +pub const PROTOC_OUTPUT: &str = "protoc_output.rs"; + +pub fn generate_protos(out_dir: PathBuf, proto_files: &[&str]) -> Result<(), io::Error> { + info!("Building protos"); + + // OUT_DIR env variable is required by protoc_prebuilt + env::set_var("OUT_DIR", &out_dir); + + if get_valid_preinstalled_protoc_version().is_none() { + info!( + "Protoc is not installed. Adding a prebuilt protoc binary via gh actions before \ + building." + ); + let (protoc_bin, _) = protoc_prebuilt::init("27.0").expect( + "Build failed due to Github's rate limit. Please run `gh auth login` to lift the rate limit and allow protoc compilation to proceed. \ + If this issue persists please download Protoc following the instructions at https://github.com/starkware-libs/sequencer/blob/main/docs/papyrus/README.adoc#prerequisites", + ); + info!("Prebuilt protoc added to the project."); + env::set_var("PROTOC", protoc_bin); + } + + // Using absolute paths for consistency between test and bin + let project_root = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + + prost_build::Config::new() + .protoc_arg(format!("--proto_path={}", project_root.display())) + .out_dir(&out_dir) + .compile_protos( + &proto_files + .iter() + .map(|p| project_root.join(p)) + .collect::>() + .iter() + .map(|p| p.to_str().unwrap()) + .collect::>(), + &[project_root.join("src/proto").to_str().unwrap()], + )?; + + Ok(()) +} + /// Returns the version of the preinstalled protoc if it is valid (version 3.15.x or greater). /// Otherwise, returns None. fn get_valid_preinstalled_protoc_version() -> Option<(u32, u32)> { @@ -12,10 +69,7 @@ fn get_valid_preinstalled_protoc_version() -> Option<(u32, u32)> { let parts: Vec<&str> = protoc_version_output.split_whitespace().collect(); // The returned string is in the format "libprotoc 25.1". We need to extract the version - let protoc_version_str = match parts.get(1) { - Some(version) => version, - None => return None, - }; + let protoc_version_str = parts.get(1)?; let (major, minor) = parse_protoc_version(protoc_version_str)?; // Protoc versions before 3.15 are not supported. if (major < 3) || (major == 3 && minor < 15) { None } else { Some((major, minor)) } @@ -35,33 +89,3 @@ fn parse_protoc_version(protoc_version_str: &str) -> Option<(u32, u32)> { }; Some((major, minor)) } - -fn main() -> io::Result<()> { - // If Protoc is installed use it, if not compile using prebuilt protoc. - println!("Building"); - if get_valid_preinstalled_protoc_version().is_none() { - println!( - "Protoc is not installed. Adding a prebuilt protoc binary via gh actions before \ - building." - ); - let (protoc_bin, _) = protoc_prebuilt::init("27.0").expect( - "Build failed due to Github's rate limit. Please run `gh auth login` to lift the rate limit and allow protoc compilation to proceed. \ - If this issue persists please download Protoc following the instructions at https://github.com/starkware-libs/sequencer/blob/main/docs/papyrus/README.adoc#prerequisites", - ); - println!("Prebuilt protoc added to the project."); - env::set_var("PROTOC", protoc_bin); - } - prost_build::compile_protos( - &[ - "src/proto/p2p/proto/rpc_transaction.proto", - "src/proto/p2p/proto/class.proto", - "src/proto/p2p/proto/event.proto", - "src/proto/p2p/proto/header.proto", - "src/proto/p2p/proto/state.proto", - "src/proto/p2p/proto/transaction.proto", - "src/proto/p2p/proto/consensus.proto", - ], - &["src/proto/"], - )?; - Ok(()) -} diff --git a/crates/papyrus_protobuf/src/transaction.rs b/crates/papyrus_protobuf/src/transaction.rs new file mode 100644 index 00000000000..11834c64ad1 --- /dev/null +++ b/crates/papyrus_protobuf/src/transaction.rs @@ -0,0 +1,129 @@ +use serde::{Deserialize, Serialize}; +use starknet_api::core::{CompiledClassHash, ContractAddress, Nonce}; +use starknet_api::data_availability::DataAvailabilityMode; +use starknet_api::transaction::fields::{ + AccountDeploymentData, + PaymasterData, + Tip, + TransactionSignature, + ValidResourceBounds, +}; +use starknet_types_core::felt::Felt; + +use crate::converters::common::{ + enum_int_to_volition_domain, + missing, + volition_domain_to_enum_int, +}; +use crate::converters::ProtobufConversionError; +use crate::protobuf; + +#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)] +pub(crate) struct DeclareTransactionV3Common { + pub resource_bounds: ValidResourceBounds, + pub tip: Tip, + pub signature: TransactionSignature, + pub nonce: Nonce, + pub compiled_class_hash: CompiledClassHash, + pub sender_address: ContractAddress, + pub nonce_data_availability_mode: DataAvailabilityMode, + pub fee_data_availability_mode: DataAvailabilityMode, + pub paymaster_data: PaymasterData, + pub account_deployment_data: AccountDeploymentData, +} + +impl TryFrom for DeclareTransactionV3Common { + type Error = ProtobufConversionError; + fn try_from(value: protobuf::DeclareV3Common) -> Result { + let resource_bounds = ValidResourceBounds::try_from( + value.resource_bounds.ok_or(missing("DeclareV3Common::resource_bounds"))?, + )?; + + let tip = Tip(value.tip); + + let signature = TransactionSignature( + value + .signature + .ok_or(missing("DeclareV3Common::signature"))? + .parts + .into_iter() + .map(Felt::try_from) + .collect::, _>>()?, + ); + + let nonce = Nonce(value.nonce.ok_or(missing("DeclareV3Common::nonce"))?.try_into()?); + + let compiled_class_hash = CompiledClassHash( + value + .compiled_class_hash + .ok_or(missing("DeclareV3Common::compiled_class_hash"))? + .try_into()?, + ); + + let sender_address = value.sender.ok_or(missing("DeclareV3Common::sender"))?.try_into()?; + + let nonce_data_availability_mode = + enum_int_to_volition_domain(value.nonce_data_availability_mode)?; + + let fee_data_availability_mode = + enum_int_to_volition_domain(value.fee_data_availability_mode)?; + + let paymaster_data = PaymasterData( + value.paymaster_data.into_iter().map(Felt::try_from).collect::, _>>()?, + ); + + let account_deployment_data = AccountDeploymentData( + value + .account_deployment_data + .into_iter() + .map(Felt::try_from) + .collect::, _>>()?, + ); + + Ok(Self { + resource_bounds, + tip, + signature, + nonce, + compiled_class_hash, + sender_address, + nonce_data_availability_mode, + fee_data_availability_mode, + paymaster_data, + account_deployment_data, + }) + } +} + +impl From for protobuf::DeclareV3Common { + fn from(value: DeclareTransactionV3Common) -> Self { + Self { + resource_bounds: Some(protobuf::ResourceBounds::from(value.resource_bounds)), + tip: value.tip.0, + signature: Some(protobuf::AccountSignature { + parts: value.signature.0.into_iter().map(|signature| signature.into()).collect(), + }), + nonce: Some(value.nonce.0.into()), + compiled_class_hash: Some(value.compiled_class_hash.0.into()), + sender: Some(value.sender_address.into()), + nonce_data_availability_mode: volition_domain_to_enum_int( + value.nonce_data_availability_mode, + ), + fee_data_availability_mode: volition_domain_to_enum_int( + value.fee_data_availability_mode, + ), + paymaster_data: value + .paymaster_data + .0 + .iter() + .map(|paymaster_data| (*paymaster_data).into()) + .collect(), + account_deployment_data: value + .account_deployment_data + .0 + .iter() + .map(|account_deployment_data| (*account_deployment_data).into()) + .collect(), + } + } +} diff --git a/crates/papyrus_rpc/src/lib.rs b/crates/papyrus_rpc/src/lib.rs index d38dae8b616..1ec26895094 100644 --- a/crates/papyrus_rpc/src/lib.rs +++ b/crates/papyrus_rpc/src/lib.rs @@ -58,9 +58,9 @@ pub use crate::v0_8::transaction::{ }; pub use crate::v0_8::write_api_result::AddInvokeOkResult as AddInvokeOkResultRPC0_8; -// TODO(shahak): Consider adding genesis hash to the config to support chains that have +// TODO(Shahak): Consider adding genesis hash to the config to support chains that have // different genesis hash. -// TODO: Consider moving to a more general place. +// TODO(DanB): Consider moving to a more general place. const GENESIS_HASH: &str = "0x0"; /// Maximum size of a supported transaction body - 10MB. diff --git a/crates/papyrus_rpc/src/rpc_metrics/mod.rs b/crates/papyrus_rpc/src/rpc_metrics/mod.rs index a5098f80e91..6e565670d1f 100644 --- a/crates/papyrus_rpc/src/rpc_metrics/mod.rs +++ b/crates/papyrus_rpc/src/rpc_metrics/mod.rs @@ -8,7 +8,7 @@ use std::time::Instant; use jsonrpsee::server::logger::{HttpRequest, Logger, MethodKind, TransportProtocol}; use jsonrpsee::types::Params; use jsonrpsee::Methods; -use metrics::{histogram, increment_counter, register_counter, register_histogram}; +use metrics::{counter, histogram}; // Name of the metrics. const INCOMING_REQUEST: &str = "rpc_incoming_requests"; @@ -23,14 +23,15 @@ const ILLEGAL_METHOD: &str = "illegal_method"; // Register the metrics and returns a set of the method names. fn init_metrics(methods: &Methods) -> HashSet { let mut methods_set: HashSet = HashSet::new(); - register_counter!(INCOMING_REQUEST, METHOD_LABEL => ILLEGAL_METHOD); - register_counter!(FAILED_REQUESTS, METHOD_LABEL => ILLEGAL_METHOD); + counter!(INCOMING_REQUEST, METHOD_LABEL => ILLEGAL_METHOD).absolute(0); + counter!(FAILED_REQUESTS, METHOD_LABEL => ILLEGAL_METHOD).absolute(0); for method in methods.method_names() { methods_set.insert(method.to_string()); let (method_name, version) = get_method_and_version(method); - register_counter!(FAILED_REQUESTS, METHOD_LABEL => method_name.clone(), VERSION_LABEL => version.clone()); - register_counter!(INCOMING_REQUEST, METHOD_LABEL => method_name.clone(), VERSION_LABEL => version.clone()); - register_histogram!(REQUEST_LATENCY, METHOD_LABEL => method_name, VERSION_LABEL => version); + counter!(FAILED_REQUESTS, METHOD_LABEL => method_name.clone(), VERSION_LABEL => version.clone()).absolute(0); + counter!(INCOMING_REQUEST, METHOD_LABEL => method_name.clone(), VERSION_LABEL => version.clone()).absolute(0); + histogram!(REQUEST_LATENCY, METHOD_LABEL => method_name, VERSION_LABEL => version) + .record(0); } methods_set } @@ -61,14 +62,15 @@ impl Logger for MetricLogger { if self.methods_set.contains(method_name) { let (method, version) = get_method_and_version(method_name); if let jsonrpsee::helpers::MethodResponseResult::Failed(_) = success_or_error { - increment_counter!(FAILED_REQUESTS, METHOD_LABEL=> method.clone(), VERSION_LABEL=> version.clone()); + counter!(FAILED_REQUESTS, METHOD_LABEL=> method.clone(), VERSION_LABEL=> version.clone()).increment(1); } - increment_counter!(INCOMING_REQUEST, METHOD_LABEL=> method.clone(), VERSION_LABEL=> version.clone()); + counter!(INCOMING_REQUEST, METHOD_LABEL=> method.clone(), VERSION_LABEL=> version.clone()).increment(1); let latency = started_at.elapsed().as_secs_f64(); - histogram!(REQUEST_LATENCY, latency,METHOD_LABEL=> method, VERSION_LABEL=> version); + histogram!(REQUEST_LATENCY, METHOD_LABEL=> method, VERSION_LABEL=> version) + .record(latency); } else { - increment_counter!(INCOMING_REQUEST, METHOD_LABEL => ILLEGAL_METHOD); - increment_counter!(FAILED_REQUESTS, METHOD_LABEL => ILLEGAL_METHOD); + counter!(INCOMING_REQUEST, METHOD_LABEL => ILLEGAL_METHOD).increment(1); + counter!(FAILED_REQUESTS, METHOD_LABEL => ILLEGAL_METHOD).increment(1); } } diff --git a/crates/papyrus_rpc/src/rpc_test.rs b/crates/papyrus_rpc/src/rpc_test.rs index b0a72935f27..86853226c2a 100644 --- a/crates/papyrus_rpc/src/rpc_test.rs +++ b/crates/papyrus_rpc/src/rpc_test.rs @@ -142,7 +142,7 @@ fn get_request_body( } } -// TODO: nevo - add middleware negative cases tests +// TODO(DanB): nevo - add middleware negative cases tests #[tokio::test] async fn test_version_middleware() { diff --git a/crates/papyrus_rpc/src/v0_8/api/api_impl.rs b/crates/papyrus_rpc/src/v0_8/api/api_impl.rs index b05437de3d3..b65edb79db2 100644 --- a/crates/papyrus_rpc/src/v0_8/api/api_impl.rs +++ b/crates/papyrus_rpc/src/v0_8/api/api_impl.rs @@ -20,7 +20,14 @@ use papyrus_storage::compiled_class::CasmStorageReader; use papyrus_storage::db::{TransactionKind, RO}; use papyrus_storage::state::StateStorageReader; use papyrus_storage::{StorageError, StorageReader, StorageTxn}; -use starknet_api::block::{BlockHash, BlockHeaderWithoutHash, BlockNumber, BlockStatus}; +use starknet_api::block::{ + BlockHash, + BlockHeaderWithoutHash, + BlockNumber, + BlockStatus, + GasPricePerToken, +}; +use starknet_api::contract_class::SierraVersion; use starknet_api::core::{ ChainId, ClassHash, @@ -31,7 +38,7 @@ use starknet_api::core::{ }; use starknet_api::execution_utils::format_panic_data; use starknet_api::hash::StarkHash; -use starknet_api::state::{StateNumber, StorageKey}; +use starknet_api::state::{StateNumber, StorageKey, ThinStateDiff as StarknetApiThinStateDiff}; use starknet_api::transaction::fields::Fee; use starknet_api::transaction::{ EventContent, @@ -65,7 +72,6 @@ use super::super::block::{ BlockNotRevertedValidator, GeneralBlockHeader, PendingBlockHeader, - ResourcePrice, }; use super::super::broadcasted_transaction::{ BroadcastedDeclareTransaction, @@ -137,11 +143,13 @@ use super::{ use crate::api::{BlockHashOrNumber, JsonRpcServerTrait, Tag}; use crate::pending::client_pending_data_to_execution_pending_data; use crate::syncing_state::{get_last_synced_block, SyncStatus, SyncingState}; +use crate::v0_8::state::ThinStateDiff; use crate::version_config::VERSION_0_8 as VERSION; use crate::{ get_block_status, get_latest_block_number, internal_server_error, + internal_server_error_with_msg, verify_storage_scope, ContinuationTokenAsStruct, GENESIS_HASH, @@ -499,11 +507,13 @@ impl JsonRpcServer for JsonRpcServerImpl { // the computation of state diff commitment. thin_state_diff.storage_diffs.retain(|_k, v| !v.is_empty()); + let state_diff = + self.convert_thin_state_diff(thin_state_diff, block_id, block_number).await?; Ok(StateUpdate::AcceptedStateUpdate(AcceptedStateUpdate { block_hash: header.block_hash, new_root: header.new_root, old_root, - state_diff: thin_state_diff.into(), + state_diff, })) } @@ -531,7 +541,7 @@ impl JsonRpcServer for JsonRpcServerImpl { .map_err(internal_server_error)? .unwrap_or_else(|| panic!("Should have tx {}", transaction_hash)); - // TODO: Add version function to transaction in SN_API. + // TODO(Shahak): Add version function to transaction in SN_API. let tx_version = match &tx { StarknetApiTransaction::Declare(tx) => tx.version(), StarknetApiTransaction::Deploy(tx) => tx.version, @@ -629,28 +639,9 @@ impl JsonRpcServer for JsonRpcServerImpl { block_id: BlockId, contract_address: ContractAddress, ) -> RpcResult { - let txn = self.storage_reader.begin_ro_txn().map_err(internal_server_error)?; - - let maybe_pending_deployed_contracts_and_replaced_classes = - if let BlockId::Tag(Tag::Pending) = block_id { - let pending_state_diff = - read_pending_data(&self.pending_data, &txn).await?.state_update.state_diff; - Some((pending_state_diff.deployed_contracts, pending_state_diff.replaced_classes)) - } else { - None - }; - - let block_number = get_accepted_block_number(&txn, block_id)?; - let state_number = StateNumber::unchecked_right_after_block(block_number); - execution_utils::get_class_hash_at( - &txn, - state_number, - // This map converts &(T, S) to (&T, &S). - maybe_pending_deployed_contracts_and_replaced_classes.as_ref().map(|t| (&t.0, &t.1)), - contract_address, - ) - .map_err(internal_server_error)? - .ok_or_else(|| ErrorObjectOwned::from(CONTRACT_NOT_FOUND)) + self.maybe_get_class_hash_at(block_id, contract_address) + .await? + .ok_or_else(|| ErrorObjectOwned::from(CONTRACT_NOT_FOUND)) } #[instrument(skip(self), level = "debug", err, ret)] @@ -763,7 +754,7 @@ impl JsonRpcServer for JsonRpcServerImpl { break; } } - // TODO: Consider changing empty sets in the filer keys to None. + // TODO(Shahak): Consider changing empty sets in the filer keys to None. if do_event_keys_match_filter(&content, &filter) { if filtered_events.len() == filter.chunk_size { return Ok(EventsChunk { @@ -1089,17 +1080,21 @@ impl JsonRpcServer for JsonRpcServerImpl { block_not_reverted_validator.validate(&self.storage_reader)?; - Ok(simulation_results - .into_iter() - .map(|simulation_output| SimulatedTransaction { - transaction_trace: ( - simulation_output.transaction_trace, + let mut res = vec![]; + for simulation_output in simulation_results { + let state_diff = self + .convert_thin_state_diff( simulation_output.induced_state_diff, + block_id, + block_number, ) - .into(), + .await?; + res.push(SimulatedTransaction { + transaction_trace: (simulation_output.transaction_trace, state_diff).into(), fee_estimation: simulation_output.fee_estimation, - }) - .collect()) + }); + } + Ok(res) } #[instrument(skip(self), level = "debug", err)] @@ -1217,6 +1212,7 @@ impl JsonRpcServer for JsonRpcServerImpl { let chain_id = self.chain_id.clone(); let reader = self.storage_reader.clone(); + let is_pending = maybe_pending_data.is_some(); let mut simulation_results = tokio::task::spawn_blocking(move || { exec_simulate_transactions( executable_transactions, @@ -1240,7 +1236,16 @@ impl JsonRpcServer for JsonRpcServerImpl { let simulation_result = simulation_results.pop().expect("Should have transaction exeuction result"); - Ok((simulation_result.transaction_trace, simulation_result.induced_state_diff).into()) + + let block_id = if is_pending { + BlockId::Tag(Tag::Pending) + } else { + BlockId::HashOrNumber(BlockHashOrNumber::Number(block_number)) + }; + let state_diff = self + .convert_thin_state_diff(simulation_result.induced_state_diff, block_id, block_number) + .await?; + Ok((simulation_result.transaction_trace, state_diff).into()) } #[instrument(skip(self), level = "debug", err)] @@ -1354,18 +1359,23 @@ impl JsonRpcServer for JsonRpcServerImpl { block_not_reverted_validator.validate(&self.storage_reader)?; - Ok(simulation_results - .into_iter() - .zip(transaction_hashes) - .map(|(simulation_output, transaction_hash)| TransactionTraceWithHash { - transaction_hash, - trace_root: ( - simulation_output.transaction_trace, + let mut res = vec![]; + for (simulation_output, transaction_hash) in + simulation_results.into_iter().zip(transaction_hashes) + { + let state_diff = self + .convert_thin_state_diff( simulation_output.induced_state_diff, + block_id, + block_number, ) - .into(), - }) - .collect()) + .await?; + res.push(TransactionTraceWithHash { + transaction_hash, + trace_root: (simulation_output.transaction_trace, state_diff).into(), + }); + } + Ok(res) } #[instrument(skip(self, message), level = "debug", err)] @@ -1445,11 +1455,11 @@ impl JsonRpcServer for JsonRpcServerImpl { } #[instrument(skip(self), level = "debug", err)] - fn get_compiled_contract_class( + fn get_compiled_class( &self, block_id: BlockId, class_hash: ClassHash, - ) -> RpcResult { + ) -> RpcResult<(CompiledContractClass, SierraVersion)> { let storage_txn = self.storage_reader.begin_ro_txn().map_err(internal_server_error)?; let state_reader = storage_txn.get_state_reader().map_err(internal_server_error)?; let block_number = get_accepted_block_number(&storage_txn, block_id)?; @@ -1462,11 +1472,17 @@ impl JsonRpcServer for JsonRpcServerImpl { if class_definition_block_number > block_number { return Err(ErrorObjectOwned::from(CLASS_HASH_NOT_FOUND)); } - let casm = storage_txn - .get_casm(&class_hash) - .map_err(internal_server_error)? + let (option_casm, option_sierra) = storage_txn + .get_casm_and_sierra(&class_hash) + .map_err(internal_server_error_with_msg)?; + + // Check if both options are `Some`. + let (casm, sierra) = option_casm + .zip(option_sierra) .ok_or_else(|| ErrorObjectOwned::from(CLASS_HASH_NOT_FOUND))?; - return Ok(CompiledContractClass::V1(casm)); + let sierra_version = SierraVersion::extract_from_program(&sierra.sierra_program) + .map_err(internal_server_error_with_msg)?; + return Ok((CompiledContractClass::V1(casm), sierra_version)); } // Check if this class exists in the Cairo0 classes table. @@ -1476,7 +1492,10 @@ impl JsonRpcServer for JsonRpcServerImpl { .get_deprecated_class_definition_at(state_number, &class_hash) .map_err(internal_server_error)? .ok_or_else(|| ErrorObjectOwned::from(CLASS_HASH_NOT_FOUND))?; - Ok(CompiledContractClass::V0(deprecated_compiled_contract_class)) + Ok(( + CompiledContractClass::V0(deprecated_compiled_contract_class), + SierraVersion::DEPRECATED, + )) } } @@ -1539,15 +1558,15 @@ impl JsonRpcServerImpl { parent_hash: block.parent_block_hash(), sequencer_address: block.sequencer_address(), timestamp: block.timestamp(), - l1_gas_price: ResourcePrice { + l1_gas_price: GasPricePerToken { price_in_wei: block.l1_gas_price().price_in_wei, price_in_fri: block.l1_gas_price().price_in_fri, }, - l1_data_gas_price: ResourcePrice { + l1_data_gas_price: GasPricePerToken { price_in_wei: block.l1_data_gas_price().price_in_wei, price_in_fri: block.l1_data_gas_price().price_in_fri, }, - l2_gas_price: ResourcePrice { + l2_gas_price: GasPricePerToken { price_in_wei: block.l2_gas_price().price_in_wei, price_in_fri: block.l2_gas_price().price_in_fri, }, @@ -1573,6 +1592,69 @@ impl JsonRpcServerImpl { transactions: get_transactions(&txn, block_number)?, }) } + + async fn maybe_get_class_hash_at( + &self, + block_id: BlockId, + contract_address: ContractAddress, + ) -> RpcResult> { + let txn = self.storage_reader.begin_ro_txn().map_err(internal_server_error)?; + + let maybe_pending_deployed_contracts_and_replaced_classes = + if let BlockId::Tag(Tag::Pending) = block_id { + let pending_state_diff = + read_pending_data(&self.pending_data, &txn).await?.state_update.state_diff; + Some((pending_state_diff.deployed_contracts, pending_state_diff.replaced_classes)) + } else { + None + }; + + let block_number = get_accepted_block_number(&txn, block_id)?; + let state_number = StateNumber::unchecked_right_after_block(block_number); + execution_utils::get_class_hash_at( + &txn, + state_number, + // This map converts &(T, S) to (&T, &S). + maybe_pending_deployed_contracts_and_replaced_classes.as_ref().map(|t| (&t.0, &t.1)), + contract_address, + ) + .map_err(internal_server_error) + } + + async fn is_deployed( + &self, + block_number: BlockNumber, + contract_address: ContractAddress, + ) -> RpcResult { + let block_id = BlockId::HashOrNumber(BlockHashOrNumber::Number(block_number)); + Ok(self.maybe_get_class_hash_at(block_id, contract_address).await?.is_some()) + } + + async fn convert_thin_state_diff( + &self, + mut thin_state_diff: StarknetApiThinStateDiff, + // TODO(AlonH): Remove the `block_id` parameter once we don't have pending blocks. + block_id: BlockId, + block_number: BlockNumber, + ) -> RpcResult { + let prev_block_number = match block_id { + BlockId::Tag(Tag::Pending) => Some(block_number), + _ => block_number.prev(), + }; + let mut replaced_classes = vec![]; + for (&address, &class_hash) in thin_state_diff.deployed_contracts.iter() { + // Check if the class was replaced. + if let Some(prev_block_number) = prev_block_number { + if self.is_deployed(prev_block_number, address).await? { + replaced_classes.push((address, class_hash)); + } + } + } + replaced_classes.iter().for_each(|(address, _)| { + thin_state_diff.deployed_contracts.swap_remove(address); + }); + Ok(ThinStateDiff::from(thin_state_diff, replaced_classes)) + } } fn get_non_pending_receipt( diff --git a/crates/papyrus_rpc/src/v0_8/api/mod.rs b/crates/papyrus_rpc/src/v0_8/api/mod.rs index 0c272fc3792..64430523a2b 100644 --- a/crates/papyrus_rpc/src/v0_8/api/mod.rs +++ b/crates/papyrus_rpc/src/v0_8/api/mod.rs @@ -18,6 +18,7 @@ use papyrus_storage::state::StateStorageReader; use papyrus_storage::StorageTxn; use serde::{Deserialize, Serialize}; use starknet_api::block::{BlockHashAndNumber, BlockNumber}; +use starknet_api::contract_class::SierraVersion; use starknet_api::core::{ClassHash, ContractAddress, Nonce}; use starknet_api::deprecated_contract_class::{ ContractClass as StarknetApiDeprecatedContractClass, @@ -257,13 +258,13 @@ pub trait JsonRpc { block_id: BlockId, ) -> RpcResult>; - /// Returns the compiled contract class associated with the given class hash. + /// Returns the compiled class associated with the given class hash. #[method(name = "getCompiledContractClass")] - fn get_compiled_contract_class( + fn get_compiled_class( &self, block_id: BlockId, class_hash: ClassHash, - ) -> RpcResult; + ) -> RpcResult<(CompiledContractClass, SierraVersion)>; } #[derive(Debug, Clone, Deserialize, Serialize)] @@ -331,10 +332,8 @@ impl TryFrom for ExecutableTransactionInput { // TODO(yair): pass the right value for only_query field. match value { BroadcastedTransaction::Declare(tx) => Ok(tx.try_into()?), - BroadcastedTransaction::DeployAccount(tx) => { - Ok(Self::DeployAccount(tx.try_into()?, false)) - } - BroadcastedTransaction::Invoke(tx) => Ok(Self::Invoke(tx.try_into()?, false)), + BroadcastedTransaction::DeployAccount(tx) => Ok(Self::DeployAccount(tx.into(), false)), + BroadcastedTransaction::Invoke(tx) => Ok(Self::Invoke(tx.into(), false)), } } } @@ -379,7 +378,7 @@ pub(crate) fn stored_txn_to_executable_txn( value.class_hash )) })?; - let (sierra_program_length, abi_length) = + let (sierra_program_length, abi_length, sierra_version) = get_class_lengths(storage_txn, state_number, value.class_hash)?; Ok(ExecutableTransactionInput::DeclareV2( value, @@ -387,6 +386,7 @@ pub(crate) fn stored_txn_to_executable_txn( sierra_program_length, abi_length, false, + sierra_version, )) } starknet_api::transaction::Transaction::Declare( @@ -401,7 +401,7 @@ pub(crate) fn stored_txn_to_executable_txn( value.class_hash )) })?; - let (sierra_program_length, abi_length) = + let (sierra_program_length, abi_length, sierra_version) = get_class_lengths(storage_txn, state_number, value.class_hash)?; Ok(ExecutableTransactionInput::DeclareV3( value, @@ -409,6 +409,7 @@ pub(crate) fn stored_txn_to_executable_txn( sierra_program_length, abi_length, false, + sierra_version, )) } starknet_api::transaction::Transaction::Deploy(_) => { @@ -453,9 +454,10 @@ fn get_class_lengths( storage_txn: &StorageTxn<'_, RO>, state_number: StateNumber, class_hash: ClassHash, -) -> Result<(SierraSize, AbiSize), ErrorObjectOwned> { +) -> Result<(SierraSize, AbiSize, SierraVersion), ErrorObjectOwned> { let state_number_after_block = StateNumber::unchecked_right_after_block(state_number.block_after()); + storage_txn .get_state_reader() .map_err(internal_server_error)? @@ -464,7 +466,14 @@ fn get_class_lengths( .ok_or_else(|| { internal_server_error(format!("Missing deprecated class definition of {class_hash}.")) }) - .map(|contract_class| (contract_class.sierra_program.len(), contract_class.abi.len())) + .and_then(|contract_class| { + let sierra_program_len = contract_class.sierra_program.len(); + let abi_len = contract_class.abi.len(); + let sierra_program = + SierraVersion::extract_from_program(&contract_class.sierra_program) + .map_err(internal_server_error)?; + Ok((sierra_program_len, abi_len, sierra_program)) + }) } impl TryFrom for ExecutableTransactionInput { @@ -521,10 +530,9 @@ fn user_deprecated_contract_class_to_sn_api( }) } -impl TryFrom for starknet_api::transaction::DeployAccountTransaction { - type Error = ErrorObjectOwned; - fn try_from(tx: DeployAccountTransaction) -> Result { - Ok(match tx { +impl From for starknet_api::transaction::DeployAccountTransaction { + fn from(tx: DeployAccountTransaction) -> Self { + match tx { DeployAccountTransaction::Version1(DeployAccountTransactionV1 { max_fee, signature, @@ -554,7 +562,7 @@ impl TryFrom for starknet_api::transaction::DeployAcco nonce_data_availability_mode, fee_data_availability_mode, }) => Self::V3(starknet_api::transaction::DeployAccountTransactionV3 { - resource_bounds: resource_bounds.try_into()?, + resource_bounds: resource_bounds.into(), tip, signature, nonce, @@ -565,14 +573,13 @@ impl TryFrom for starknet_api::transaction::DeployAcco fee_data_availability_mode, paymaster_data, }), - }) + } } } -impl TryFrom for starknet_api::transaction::InvokeTransaction { - type Error = ErrorObjectOwned; - fn try_from(value: InvokeTransaction) -> Result { - Ok(match value { +impl From for starknet_api::transaction::InvokeTransaction { + fn from(value: InvokeTransaction) -> Self { + match value { InvokeTransaction::Version0(InvokeTransactionV0 { max_fee, version: _, @@ -614,7 +621,7 @@ impl TryFrom for starknet_api::transaction::InvokeTransaction nonce_data_availability_mode, fee_data_availability_mode, }) => Self::V3(starknet_api::transaction::InvokeTransactionV3 { - resource_bounds: resource_bounds.try_into()?, + resource_bounds: resource_bounds.into(), tip, signature, nonce, @@ -625,7 +632,7 @@ impl TryFrom for starknet_api::transaction::InvokeTransaction paymaster_data, account_deployment_data, }), - }) + } } } diff --git a/crates/papyrus_rpc/src/v0_8/api/test.rs b/crates/papyrus_rpc/src/v0_8/api/test.rs index 54819a917f4..52c0731b133 100644 --- a/crates/papyrus_rpc/src/v0_8/api/test.rs +++ b/crates/papyrus_rpc/src/v0_8/api/test.rs @@ -48,10 +48,10 @@ use starknet_api::block::{ BlockNumber, BlockStatus, BlockTimestamp, - GasPrice, GasPricePerToken, StarknetVersion, }; +use starknet_api::contract_class::SierraVersion; use starknet_api::core::{ ClassHash, CompiledClassHash, @@ -68,7 +68,6 @@ use starknet_api::deprecated_contract_class::{ FunctionAbiEntry, FunctionStateMutability, }; -use starknet_api::hash::StarkHash; use starknet_api::state::{SierraContractClass as StarknetApiContractClass, StateDiff}; use starknet_api::transaction::{ Event as StarknetApiEvent, @@ -81,7 +80,7 @@ use starknet_api::transaction::{ TransactionOffsetInBlock, TransactionOutput as StarknetApiTransactionOutput, }; -use starknet_api::{class_hash, contract_address, felt, storage_key}; +use starknet_api::{class_hash, contract_address, felt, storage_key, tx_hash}; use starknet_client::reader::objects::pending_data::{ DeprecatedPendingBlock, PendingBlockOrDeprecated, @@ -114,7 +113,7 @@ use starknet_client::ClientError; use starknet_types_core::felt::Felt; use super::super::api::EventsChunk; -use super::super::block::{Block, GeneralBlockHeader, PendingBlockHeader, ResourcePrice}; +use super::super::block::{Block, GeneralBlockHeader, PendingBlockHeader}; use super::super::broadcasted_transaction::BroadcastedDeclareTransaction; use super::super::deprecated_contract_class::ContractClass as DeprecatedContractClass; use super::super::error::{ @@ -139,7 +138,7 @@ use super::super::state::{ ContractNonce, DeployedContract, PendingStateUpdate, - ReplacedClasses, + ReplacedClass, StateUpdate, StorageDiff, StorageEntry, @@ -613,12 +612,12 @@ async fn get_block_w_full_transactions() { parent_hash: block_hash, sequencer_address: pending_sequencer_address, timestamp: pending_timestamp, - l1_gas_price: ResourcePrice { + l1_gas_price: GasPricePerToken { price_in_wei: pending_l1_gas_price.price_in_wei, price_in_fri: pending_l1_gas_price.price_in_fri, }, - l1_data_gas_price: ResourcePrice::default(), - l2_gas_price: ResourcePrice { + l1_data_gas_price: GasPricePerToken::default(), + l2_gas_price: GasPricePerToken { price_in_wei: pending_l2_gas_price.price_in_wei, price_in_fri: pending_l2_gas_price.price_in_fri, }, @@ -805,12 +804,12 @@ async fn get_block_w_full_transactions_and_receipts() { parent_hash: block_hash, sequencer_address: pending_sequencer_address, timestamp: pending_timestamp, - l1_gas_price: ResourcePrice { + l1_gas_price: GasPricePerToken { price_in_wei: pending_l1_gas_price.price_in_wei, price_in_fri: pending_l1_gas_price.price_in_fri, }, - l1_data_gas_price: ResourcePrice::default(), - l2_gas_price: ResourcePrice { + l1_data_gas_price: GasPricePerToken::default(), + l2_gas_price: GasPricePerToken { price_in_wei: pending_l2_gas_price.price_in_wei, price_in_fri: pending_l2_gas_price.price_in_fri, }, @@ -997,15 +996,15 @@ async fn get_block_w_transaction_hashes() { parent_hash: block_hash, sequencer_address: pending_sequencer_address, timestamp: pending_timestamp, - l1_gas_price: ResourcePrice { + l1_gas_price: GasPricePerToken { price_in_wei: pending_l1_gas_price.price_in_wei, price_in_fri: pending_l1_gas_price.price_in_fri, }, - l2_gas_price: ResourcePrice { + l2_gas_price: GasPricePerToken { price_in_wei: pending_l2_gas_price.price_in_wei, price_in_fri: pending_l2_gas_price.price_in_fri, }, - l1_data_gas_price: ResourcePrice::default(), + l1_data_gas_price: GasPricePerToken::default(), l1_da_mode: L1DataAvailabilityMode::Calldata, starknet_version: starknet_version.to_string(), }), @@ -1350,7 +1349,7 @@ async fn get_transaction_status() { call_api_then_assert_and_validate_schema_for_err::<_, TransactionStatus>( &module, method_name, - vec![Box::new(TransactionHash(StarkHash::from(1_u8)))], + vec![Box::new(tx_hash!(1))], &VERSION, SpecFile::StarknetApiOpenrpc, &TRANSACTION_HASH_NOT_FOUND.into(), @@ -1474,7 +1473,7 @@ async fn get_transaction_receipt() { call_api_then_assert_and_validate_schema_for_err::<_, TransactionReceipt>( &module, method_name, - vec![Box::new(TransactionHash(StarkHash::from(1_u8)))], + vec![Box::new(tx_hash!(1))], &VERSION, SpecFile::StarknetApiOpenrpc, &TRANSACTION_HASH_NOT_FOUND.into(), @@ -2202,7 +2201,7 @@ async fn get_storage_at() { fn generate_client_transaction_client_receipt_rpc_transaction_and_rpc_receipt( rng: &mut ChaCha8Rng, ) -> (ClientTransaction, ClientTransactionReceipt, Transaction, PendingTransactionReceipt) { - let pending_transaction_hash = TransactionHash(StarkHash::from(rng.next_u64())); + let pending_transaction_hash = tx_hash!(rng.next_u64()); let mut client_transaction_receipt = ClientTransactionReceipt::get_test_instance(rng); client_transaction_receipt.transaction_hash = pending_transaction_hash; client_transaction_receipt.execution_resources.n_memory_holes = 1; @@ -2279,7 +2278,7 @@ async fn get_transaction_by_hash() { let mut block = get_test_block(1, None, None, None); // Change the transaction hash from 0 to a random value, so that later on we can add a // transaction with 0 hash to the pending block. - block.body.transaction_hashes[0] = TransactionHash(StarkHash::from(random::())); + block.body.transaction_hashes[0] = tx_hash!(random::()); storage_writer .begin_rw_txn() .unwrap() @@ -2333,7 +2332,7 @@ async fn get_transaction_by_hash() { call_api_then_assert_and_validate_schema_for_err::<_, TransactionWithHash>( &module, method_name, - vec![Box::new(TransactionHash(StarkHash::from(1_u8)))], + vec![Box::new(tx_hash!(1))], &VERSION, SpecFile::StarknetApiOpenrpc, &TRANSACTION_HASH_NOT_FOUND.into(), @@ -2344,7 +2343,7 @@ async fn get_transaction_by_hash() { #[tokio::test] async fn get_transaction_by_hash_state_only() { let method_name = "starknet_V0_8_getTransactionByHash"; - let params = [TransactionHash(StarkHash::from(1_u8))]; + let params = [tx_hash!(1)]; let (module, _) = get_test_rpc_server_and_storage_writer_from_params::( None, None, @@ -2532,7 +2531,7 @@ async fn get_state_update() { .unwrap(); let expected_old_root = parent_header.block_header_without_hash.state_root; - let expected_state_diff = ThinStateDiff::from(diff); + let expected_state_diff = ThinStateDiff::from(diff, vec![]); let expected_update = StateUpdate::AcceptedStateUpdate(AcceptedStateUpdate { block_hash: header.block_hash, new_root: header.block_header_without_hash.state_root, @@ -2605,7 +2604,7 @@ async fn get_state_update() { .map(|ContractNonce { contract_address, nonce }| (contract_address, nonce)), ), replaced_classes: Vec::from_iter(expected_state_diff.replaced_classes.into_iter().map( - |ReplacedClasses { contract_address, class_hash }| ClientReplacedClass { + |ReplacedClass { contract_address, class_hash }| ClientReplacedClass { address: contract_address, class_hash, }, @@ -2658,6 +2657,90 @@ async fn get_state_update() { assert_matches!(err, Error::Call(err) if err == BLOCK_NOT_FOUND.into()); } +#[tokio::test] +async fn get_state_update_with_replaced_class() { + let method_name = "starknet_V0_8_getStateUpdate"; + let pending_data = get_test_pending_data(); + let (module, mut storage_writer) = get_test_rpc_server_and_storage_writer_from_params::< + JsonRpcServerImpl, + >(None, None, Some(pending_data.clone()), None, None); + let parent_header = BlockHeader::default(); + let expected_pending_old_root = GlobalRoot(felt!("0x1234")); + let header = BlockHeader { + block_hash: BlockHash(felt!("0x1")), + block_header_without_hash: BlockHeaderWithoutHash { + block_number: BlockNumber(1), + parent_hash: parent_header.block_hash, + state_root: expected_pending_old_root, + ..Default::default() + }, + ..Default::default() + }; + let contract_address_0 = contract_address!("0x1234"); + let contract_address_1 = contract_address!("0x5678"); + let class_hash_0 = class_hash!("0x12"); + let class_hash_1 = class_hash!("0x34"); + let class_hash_2 = class_hash!("0x56"); + let diff_0 = starknet_api::state::ThinStateDiff { + deployed_contracts: indexmap! { + contract_address_0 => class_hash_0, + }, + ..Default::default() + }; + let diff_1 = starknet_api::state::ThinStateDiff { + deployed_contracts: indexmap! { + contract_address_0 => class_hash_2, + contract_address_1 => class_hash_1, + }, + ..Default::default() + }; + storage_writer + .begin_rw_txn() + .unwrap() + .append_header(parent_header.block_header_without_hash.block_number, &parent_header) + .unwrap() + .append_state_diff( + parent_header.block_header_without_hash.block_number, + diff_0, + ) + .unwrap() + .append_header(header.block_header_without_hash.block_number, &header) + .unwrap() + .append_state_diff(header.block_header_without_hash.block_number, diff_1.clone()) + .unwrap() + // No need to write the class definitions + .commit() + .unwrap(); + + let expected_old_root = parent_header.block_header_without_hash.state_root; + let expected_state_diff = ThinStateDiff::from( + starknet_api::state::ThinStateDiff { + deployed_contracts: indexmap! { + contract_address_1 => class_hash_1, + }, + ..Default::default() + }, + vec![(contract_address_0, class_hash_2)], + ); + let expected_update = StateUpdate::AcceptedStateUpdate(AcceptedStateUpdate { + block_hash: header.block_hash, + new_root: header.block_header_without_hash.state_root, + old_root: expected_old_root, + state_diff: expected_state_diff.clone(), + }); + + let res = module + .call::<_, StateUpdate>( + method_name, + [BlockId::HashOrNumber(BlockHashOrNumber::Number( + header.block_header_without_hash.block_number, + ))], + ) + .await + .unwrap(); + assert_eq!(res, expected_update); +} + #[tokio::test] async fn get_state_update_with_empty_storage_diff() { let method_name = "starknet_V0_8_getStateUpdate"; @@ -2681,7 +2764,7 @@ async fn get_state_update_with_empty_storage_diff() { // The empty storage diff should be removed in the result. let expected_state_diff = - ThinStateDiff::from(starknet_api::state::ThinStateDiff::from(StateDiff::default())); + ThinStateDiff::from(starknet_api::state::ThinStateDiff::from(StateDiff::default()), vec![]); let expected_update = StateUpdate::AcceptedStateUpdate(AcceptedStateUpdate { state_diff: expected_state_diff.clone(), ..Default::default() @@ -2736,7 +2819,7 @@ impl BlockMetadata { block.header.block_hash = BlockHash(rng.next_u64().into()); // Randomize the transaction hashes because get_test_block returns constant hashes for transaction_hash in &mut block.body.transaction_hashes { - *transaction_hash = TransactionHash(rng.next_u64().into()); + *transaction_hash = tx_hash!(rng.next_u64()); } for (output, event_metadatas_of_tx) in @@ -2761,9 +2844,8 @@ impl BlockMetadata { rng: &mut ChaCha8Rng, parent_hash: BlockHash, ) -> PendingBlockOrDeprecated { - let transaction_hashes = iter::repeat_with(|| TransactionHash(rng.next_u64().into())) - .take(self.0.len()) - .collect::>(); + let transaction_hashes = + iter::repeat_with(|| tx_hash!(rng.next_u64())).take(self.0.len()).collect::>(); PendingBlockOrDeprecated::Deprecated(DeprecatedPendingBlock { parent_block_hash: parent_hash, transactions: transaction_hashes @@ -3430,8 +3512,6 @@ async fn serialize_returns_valid_json() { )]); // For checking the schema also for deprecated contract classes. state_diff.deployed_contracts.insert(contract_address!("0x2"), class_hash!("0x2")); - // TODO(yair): handle replaced classes. - state_diff.replaced_classes.clear(); let (thin_state_diff, classes, deprecated_classes) = starknet_api::state::ThinStateDiff::from_state_diff(state_diff.clone()); @@ -3678,9 +3758,9 @@ async fn get_deprecated_class_state_mutability() { assert_eq!(entry.get("stateMutability").unwrap().as_str().unwrap(), "view"); } -// TODO (Yael 16/06/2024): Add a test case for block_number which is not the latest. +// TODO(Yael): Add a test case for block_number which is not the latest. #[tokio::test] -async fn get_compiled_contract_class() { +async fn get_compiled_class() { let cairo1_class_hash = ClassHash(Felt::ONE); let cairo0_class_hash = ClassHash(Felt::TWO); let invalid_class_hash = ClassHash(Felt::THREE); @@ -3690,6 +3770,9 @@ async fn get_compiled_contract_class() { JsonRpcServerImpl, >(None, None, None, None, None); let cairo1_contract_class = CasmContractClass::get_test_instance(&mut get_rng()); + // We need to save the Sierra component of the Cairo 1 contract in storage to maintain + // consistency. + let sierra_contract_class = StarknetApiContractClass::default(); let cairo0_contract_class = StarknetApiDeprecatedContractClass::get_test_instance(&mut get_rng()); storage_writer @@ -3711,28 +3794,34 @@ async fn get_compiled_contract_class() { .unwrap() // Note: there is no need to write the cairo1 contract class here because the // declared_classes_table is not used in the rpc method. - .append_classes(BlockNumber(0), &[], &[(cairo0_class_hash, &cairo0_contract_class)]) + .append_classes(BlockNumber(0), &[(cairo1_class_hash, &sierra_contract_class)], &[(cairo0_class_hash, &cairo0_contract_class)]) .unwrap() .commit() .unwrap(); let res = module - .call::<_, CompiledContractClass>( + .call::<_, (CompiledContractClass, SierraVersion)>( method_name, (BlockId::Tag(Tag::Latest), cairo1_class_hash), ) .await .unwrap(); - assert_eq!(res, CompiledContractClass::V1(cairo1_contract_class)); + assert_eq!( + res, + ( + CompiledContractClass::V1(cairo1_contract_class), + SierraVersion::extract_from_program(&sierra_contract_class.sierra_program).unwrap() + ) + ); let res = module - .call::<_, CompiledContractClass>( + .call::<_, (CompiledContractClass, SierraVersion)>( method_name, (BlockId::Tag(Tag::Latest), cairo0_class_hash), ) .await .unwrap(); - assert_eq!(res, CompiledContractClass::V0(cairo0_contract_class)); + assert_eq!(res, (CompiledContractClass::V0(cairo0_contract_class), SierraVersion::DEPRECATED)); // Ask for an invalid class hash, which does no exist in the table. let err = module @@ -4088,16 +4177,12 @@ auto_impl_get_test_instance! { pub parent_hash: BlockHash, pub sequencer_address: SequencerContractAddress, pub timestamp: BlockTimestamp, - pub l1_gas_price: ResourcePrice, - pub l1_data_gas_price: ResourcePrice, - pub l2_gas_price: ResourcePrice, + pub l1_gas_price: GasPricePerToken, + pub l1_data_gas_price: GasPricePerToken, + pub l2_gas_price: GasPricePerToken, pub l1_da_mode: L1DataAvailabilityMode, pub starknet_version: String, } - pub struct ResourcePrice { - pub price_in_wei: GasPrice, - pub price_in_fri: GasPrice, - } pub enum TypedInvokeTransaction { Invoke(InvokeTransaction) = 0, } diff --git a/crates/papyrus_rpc/src/v0_8/block.rs b/crates/papyrus_rpc/src/v0_8/block.rs index 2659535a3bf..1da2545ca34 100644 --- a/crates/papyrus_rpc/src/v0_8/block.rs +++ b/crates/papyrus_rpc/src/v0_8/block.rs @@ -3,7 +3,7 @@ use papyrus_storage::db::TransactionKind; use papyrus_storage::header::HeaderStorageReader; use papyrus_storage::{StorageError, StorageReader, StorageTxn}; use serde::{Deserialize, Serialize}; -use starknet_api::block::{BlockHash, BlockNumber, BlockStatus, BlockTimestamp, GasPrice}; +use starknet_api::block::{BlockHash, BlockNumber, BlockStatus, BlockTimestamp, GasPricePerToken}; use starknet_api::core::{GlobalRoot, SequencerContractAddress}; use starknet_api::data_availability::L1DataAvailabilityMode; @@ -20,9 +20,9 @@ pub struct BlockHeader { pub sequencer_address: SequencerContractAddress, pub new_root: GlobalRoot, pub timestamp: BlockTimestamp, - pub l1_gas_price: ResourcePrice, - pub l1_data_gas_price: ResourcePrice, - pub l2_gas_price: ResourcePrice, + pub l1_gas_price: GasPricePerToken, + pub l1_data_gas_price: GasPricePerToken, + pub l2_gas_price: GasPricePerToken, pub l1_da_mode: L1DataAvailabilityMode, pub starknet_version: String, } @@ -33,9 +33,9 @@ pub struct PendingBlockHeader { pub parent_hash: BlockHash, pub sequencer_address: SequencerContractAddress, pub timestamp: BlockTimestamp, - pub l1_gas_price: ResourcePrice, - pub l1_data_gas_price: ResourcePrice, - pub l2_gas_price: ResourcePrice, + pub l1_gas_price: GasPricePerToken, + pub l1_data_gas_price: GasPricePerToken, + pub l2_gas_price: GasPricePerToken, pub l1_da_mode: L1DataAvailabilityMode, pub starknet_version: String, } @@ -56,15 +56,15 @@ impl From for BlockHeader { sequencer_address: header.block_header_without_hash.sequencer, new_root: header.block_header_without_hash.state_root, timestamp: header.block_header_without_hash.timestamp, - l1_gas_price: ResourcePrice { + l1_gas_price: GasPricePerToken { price_in_wei: header.block_header_without_hash.l1_gas_price.price_in_wei, price_in_fri: header.block_header_without_hash.l1_gas_price.price_in_fri, }, - l1_data_gas_price: ResourcePrice { + l1_data_gas_price: GasPricePerToken { price_in_wei: header.block_header_without_hash.l1_data_gas_price.price_in_wei, price_in_fri: header.block_header_without_hash.l1_data_gas_price.price_in_fri, }, - l2_gas_price: ResourcePrice { + l2_gas_price: GasPricePerToken { price_in_wei: header.block_header_without_hash.l2_gas_price.price_in_wei, price_in_fri: header.block_header_without_hash.l2_gas_price.price_in_fri, }, @@ -74,12 +74,6 @@ impl From for BlockHeader { } } -#[derive(Debug, Default, Clone, Eq, PartialEq, Hash, Deserialize, Serialize, PartialOrd, Ord)] -pub struct ResourcePrice { - pub price_in_wei: GasPrice, - pub price_in_fri: GasPrice, -} - #[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize, PartialOrd, Ord)] pub struct Block { #[serde(skip_serializing_if = "Option::is_none")] diff --git a/crates/papyrus_rpc/src/v0_8/broadcasted_transaction_test.rs b/crates/papyrus_rpc/src/v0_8/broadcasted_transaction_test.rs index 806581ba01f..232b87cf298 100644 --- a/crates/papyrus_rpc/src/v0_8/broadcasted_transaction_test.rs +++ b/crates/papyrus_rpc/src/v0_8/broadcasted_transaction_test.rs @@ -108,6 +108,7 @@ auto_impl_get_test_instance! { pub struct ResourceBoundsMapping { pub l1_gas: ResourceBounds, + pub l1_data_gas: ResourceBounds, pub l2_gas: ResourceBounds, } } diff --git a/crates/papyrus_rpc/src/v0_8/execution.rs b/crates/papyrus_rpc/src/v0_8/execution.rs index 1e8c03700eb..32f15d24adc 100644 --- a/crates/papyrus_rpc/src/v0_8/execution.rs +++ b/crates/papyrus_rpc/src/v0_8/execution.rs @@ -12,7 +12,6 @@ use papyrus_execution::objects::{ use serde::{Deserialize, Serialize}; use starknet_api::contract_class::EntryPointType; use starknet_api::core::{ClassHash, ContractAddress}; -use starknet_api::state::ThinStateDiff as StarknetApiThinStateDiff; use super::state::ThinStateDiff; use super::transaction::{ComputationResources, ExecutionResources}; @@ -130,10 +129,9 @@ pub struct FunctionInvocation { pub execution_resources: ComputationResources, } -impl From<(ExecutionTransactionTrace, StarknetApiThinStateDiff)> for TransactionTrace { - fn from((trace, state_diff): (ExecutionTransactionTrace, StarknetApiThinStateDiff)) -> Self { - let mut state_diff = ThinStateDiff::from(state_diff); - // TODO: Investigate why blockifier sometimes returns unsorted state diff +impl From<(ExecutionTransactionTrace, ThinStateDiff)> for TransactionTrace { + fn from((trace, mut state_diff): (ExecutionTransactionTrace, ThinStateDiff)) -> Self { + // TODO(Shahak): Investigate why blockifier sometimes returns unsorted state diff state_diff.sort(); match trace { ExecutionTransactionTrace::L1Handler(trace) => { diff --git a/crates/papyrus_rpc/src/v0_8/execution_test.rs b/crates/papyrus_rpc/src/v0_8/execution_test.rs index 6566ba0ad37..5abaef986aa 100644 --- a/crates/papyrus_rpc/src/v0_8/execution_test.rs +++ b/crates/papyrus_rpc/src/v0_8/execution_test.rs @@ -71,7 +71,7 @@ use starknet_api::transaction::{ TransactionOffsetInBlock, TransactionVersion, }; -use starknet_api::{calldata, class_hash, contract_address, felt, nonce}; +use starknet_api::{calldata, class_hash, contract_address, felt, nonce, tx_hash}; use starknet_client::reader::objects::pending_data::{ PendingBlock, PendingBlockOrDeprecated, @@ -113,7 +113,7 @@ use super::state::{ ClassHashes, ContractNonce, DeployedContract, - ReplacedClasses, + ReplacedClass, StorageDiff, StorageEntry, ThinStateDiff, @@ -148,7 +148,7 @@ lazy_static! { price_in_wei: (100 * u128::pow(10, 9)).into(), price_in_fri: 0_u8.into(), }; - //TODO: Tests for data_gas_price and l2_gas_price. + //TODO(Shahak): Tests for data_gas_price and l2_gas_price. pub static ref DATA_GAS_PRICE: GasPricePerToken = GasPricePerToken{ price_in_wei: 1_u8.into(), price_in_fri: 0_u8.into(), @@ -171,22 +171,22 @@ lazy_static! { // TODO(yair): verify this is the correct fee, got this value by printing the result of the // call. pub static ref EXPECTED_FEE_ESTIMATE: FeeEstimation = FeeEstimation { - gas_consumed: felt!("0x681"), + gas_consumed: felt!("0x682"), l1_gas_price: GAS_PRICE.price_in_wei, data_gas_consumed: Felt::ZERO, l1_data_gas_price: DATA_GAS_PRICE.price_in_wei, l2_gas_price: L2_GAS_PRICE.price_in_wei, - overall_fee: Fee(166500000000000,), + overall_fee: Fee(166600000000000,), unit: PriceUnit::Wei, }; pub static ref EXPECTED_FEE_ESTIMATE_SKIP_VALIDATE: FeeEstimation = FeeEstimation { - gas_consumed: felt!("0x681"), + gas_consumed: felt!("0x682"), l1_gas_price: GAS_PRICE.price_in_wei, data_gas_consumed: Felt::ZERO, l1_data_gas_price: DATA_GAS_PRICE.price_in_wei, l2_gas_price: L2_GAS_PRICE.price_in_wei, - overall_fee: Fee(166500000000000,), + overall_fee: Fee(166600000000000,), unit: PriceUnit::Wei, }; @@ -302,7 +302,7 @@ async fn execution_call() { *BLOCK_TIMESTAMP, *SEQUENCER_ADDRESS, &InvokeTransactionV1::default(), - TransactionHash(StarkHash::ZERO), + tx_hash!(0), Some(Felt::ZERO), ); // Calling the contract directly and not through the account contract. @@ -363,7 +363,7 @@ async fn pending_execution_call() { *BLOCK_TIMESTAMP, *SEQUENCER_ADDRESS, &InvokeTransactionV1::default(), - TransactionHash(StarkHash::ZERO), + tx_hash!(0), Some(Felt::ZERO), ); // Calling the contract directly and not through the account contract. @@ -630,7 +630,7 @@ async fn test_call_simulate( // Because the transaction hash depends on the calldata and the calldata needs to contain // the transaction hash, there's no way to put the correct hash here. Instead, we'll check // that the function `test_get_execution_info` fails on the transaction hash validation. - TransactionHash(StarkHash::ZERO), + tx_hash!(0), None, ); invoke_v1.calldata = calldata; @@ -763,8 +763,8 @@ async fn trace_block_transactions_regular_and_pending() { let mut writer = prepare_storage_for_execution(storage_writer); - let tx_hash1 = TransactionHash(felt!("0x1234")); - let tx_hash2 = TransactionHash(felt!("0x5678")); + let tx_hash1 = tx_hash!(0x1234); + let tx_hash2 = tx_hash!(0x5678); let client_tx1 = ClientTransaction::Invoke(ClientInvokeTransaction { max_fee: Some(*MAX_FEE), @@ -945,8 +945,8 @@ async fn trace_block_transactions_regular_and_pending() { #[tokio::test] async fn trace_block_transactions_and_trace_transaction_execution_context() { - let tx_hash1 = TransactionHash(felt!("0x1234")); - let tx_hash2 = TransactionHash(felt!("0x5678")); + let tx_hash1 = tx_hash!(0x1234); + let tx_hash2 = tx_hash!(0x5678); let mut invoke_tx1 = starknet_api::transaction::InvokeTransactionV1 { max_fee: *MAX_FEE, @@ -1084,8 +1084,8 @@ async fn trace_block_transactions_and_trace_transaction_execution_context() { #[tokio::test] async fn pending_trace_block_transactions_and_trace_transaction_execution_context() { - let tx_hash1 = TransactionHash(felt!("0x1234")); - let tx_hash2 = TransactionHash(felt!("0x5678")); + let tx_hash1 = tx_hash!(0x1234); + let tx_hash2 = tx_hash!(0x5678); let mut client_invoke_tx1 = ClientInvokeTransaction { max_fee: Some(*MAX_FEE), @@ -1204,7 +1204,7 @@ async fn pending_trace_block_transactions_and_trace_transaction_execution_contex #[test] fn message_from_l1_to_l1_handler_tx() { let l1_handler_tx = L1HandlerTransaction::from(MESSAGE_FROM_L1.clone()); - assert_eq!(l1_handler_tx.version, TransactionVersion::ONE); + assert_eq!(l1_handler_tx.version, L1HandlerTransaction::VERSION); assert_eq!(l1_handler_tx.contract_address, *CONTRACT_ADDRESS); assert_eq!(l1_handler_tx.entry_point_selector, selector_from_name("l1_handle")); // The first item of calldata is the from_address. @@ -1222,7 +1222,7 @@ async fn call_estimate_message_fee() { // TODO(yair): get a l1_handler entry point that actually does something and check that the fee // is correct. let expected_fee_estimate = FeeEstimation { - gas_consumed: felt!("0x3937"), + gas_consumed: felt!("0x3933"), l1_gas_price: GAS_PRICE.price_in_wei, data_gas_consumed: Felt::ZERO, l1_data_gas_price: DATA_GAS_PRICE.price_in_wei, @@ -1326,10 +1326,10 @@ fn broadcasted_to_executable_deploy_account() { #[test] fn broadcasted_to_executable_invoke() { let mut rng = get_rng(); - let broadcasted_deploy_account = + let broadcasted_invoke = BroadcastedTransaction::Invoke(InvokeTransaction::get_test_instance(&mut rng)); assert_matches!( - broadcasted_deploy_account.try_into(), + broadcasted_invoke.try_into(), Ok(ExecutableTransactionInput::Invoke(_tx, _only_query)) ); } @@ -1405,7 +1405,7 @@ auto_impl_get_test_instance! { pub declared_classes: Vec, pub deprecated_declared_classes: Vec, pub nonces: Vec, - pub replaced_classes: Vec, + pub replaced_classes: Vec, } pub struct DeployedContract { @@ -1433,7 +1433,7 @@ auto_impl_get_test_instance! { pub value: Felt, } - pub struct ReplacedClasses { + pub struct ReplacedClass { pub contract_address: ContractAddress, pub class_hash: ClassHash, } @@ -1721,7 +1721,6 @@ fn prepare_storage_for_execution(mut storage_writer: StorageWriter) -> StorageWr *DEPRECATED_CONTRACT_ADDRESS => Nonce::default(), *ACCOUNT_ADDRESS => Nonce::default(), ), - replaced_classes: indexmap!(), }, ) .unwrap() diff --git a/crates/papyrus_rpc/src/v0_8/state.rs b/crates/papyrus_rpc/src/v0_8/state.rs index 7e0cd096e2e..ce7ea8c435a 100644 --- a/crates/papyrus_rpc/src/v0_8/state.rs +++ b/crates/papyrus_rpc/src/v0_8/state.rs @@ -46,44 +46,7 @@ pub struct ThinStateDiff { pub declared_classes: Vec, pub deprecated_declared_classes: Vec, pub nonces: Vec, - pub replaced_classes: Vec, -} - -impl From for ThinStateDiff { - fn from(diff: starknet_api_ThinStateDiff) -> Self { - Self { - deployed_contracts: Vec::from_iter( - diff.deployed_contracts - .into_iter() - .map(|(address, class_hash)| DeployedContract { address, class_hash }), - ), - storage_diffs: Vec::from_iter(diff.storage_diffs.into_iter().map( - |(address, entries)| { - let storage_entries = Vec::from_iter( - entries.into_iter().map(|(key, value)| StorageEntry { key, value }), - ); - StorageDiff { address, storage_entries } - }, - )), - declared_classes: diff - .declared_classes - .into_iter() - .map(|(class_hash, compiled_class_hash)| ClassHashes { - class_hash, - compiled_class_hash, - }) - .collect(), - deprecated_declared_classes: diff.deprecated_declared_classes, - nonces: Vec::from_iter( - diff.nonces - .into_iter() - .map(|(contract_address, nonce)| ContractNonce { contract_address, nonce }), - ), - replaced_classes: Vec::from_iter(diff.replaced_classes.into_iter().map( - |(contract_address, class_hash)| ReplacedClasses { contract_address, class_hash }, - )), - } - } + pub replaced_classes: Vec, } impl From for ThinStateDiff { @@ -119,7 +82,7 @@ impl From for ThinStateDiff { .map(|(contract_address, nonce)| ContractNonce { contract_address, nonce }), ), replaced_classes: Vec::from_iter(diff.replaced_classes.into_iter().map( - |ClientReplacedClass { address: contract_address, class_hash }| ReplacedClasses { + |ClientReplacedClass { address: contract_address, class_hash }| ReplacedClass { contract_address, class_hash, }, @@ -144,6 +107,44 @@ impl ThinStateDiff { .sort_unstable_by_key(|storage_entry| storage_entry.key); } } + + pub fn from( + diff: starknet_api_ThinStateDiff, + replaced_classes: Vec<(ContractAddress, ClassHash)>, + ) -> Self { + Self { + deployed_contracts: Vec::from_iter( + diff.deployed_contracts + .into_iter() + .map(|(address, class_hash)| DeployedContract { address, class_hash }), + ), + storage_diffs: Vec::from_iter(diff.storage_diffs.into_iter().map( + |(address, entries)| { + let storage_entries = Vec::from_iter( + entries.into_iter().map(|(key, value)| StorageEntry { key, value }), + ); + StorageDiff { address, storage_entries } + }, + )), + declared_classes: diff + .declared_classes + .into_iter() + .map(|(class_hash, compiled_class_hash)| ClassHashes { + class_hash, + compiled_class_hash, + }) + .collect(), + deprecated_declared_classes: diff.deprecated_declared_classes, + nonces: Vec::from_iter( + diff.nonces + .into_iter() + .map(|(contract_address, nonce)| ContractNonce { contract_address, nonce }), + ), + replaced_classes: Vec::from_iter(replaced_classes.into_iter().map( + |(contract_address, class_hash)| ReplacedClass { contract_address, class_hash }, + )), + } + } } /// The nonce of a StarkNet contract. @@ -212,9 +213,9 @@ impl EntryPointByType { impl From for EntryPointByType { fn from(entry_points: starknet_api_EntryPointByType) -> Self { Self { - constructor: entry_points.constructor.into_iter().map(EntryPoint::from).collect(), - external: entry_points.external.into_iter().map(EntryPoint::from).collect(), - l1handler: entry_points.l1handler.into_iter().map(EntryPoint::from).collect(), + constructor: entry_points.constructor, + external: entry_points.external, + l1handler: entry_points.l1handler, } } } @@ -245,7 +246,7 @@ pub struct ClassHashes { } #[derive(Debug, Clone, Default, Eq, PartialEq, Deserialize, Serialize)] -pub struct ReplacedClasses { +pub struct ReplacedClass { pub contract_address: ContractAddress, pub class_hash: ClassHash, } diff --git a/crates/papyrus_rpc/src/v0_8/transaction.rs b/crates/papyrus_rpc/src/v0_8/transaction.rs index 16375420410..4e5f1ce6b9b 100644 --- a/crates/papyrus_rpc/src/v0_8/transaction.rs +++ b/crates/papyrus_rpc/src/v0_8/transaction.rs @@ -38,6 +38,7 @@ use starknet_api::transaction::fields::{ ResourceBounds, Tip, TransactionSignature, + ValidResourceBounds, }; use starknet_api::transaction::{ DeployTransaction, @@ -154,6 +155,7 @@ impl From for DeclareTransactio #[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize, PartialOrd, Ord)] pub struct ResourceBoundsMapping { pub l1_gas: ResourceBounds, + pub l1_data_gas: ResourceBounds, pub l2_gas: ResourceBounds, } @@ -161,7 +163,14 @@ impl From for starknet_api::transaction::fields::DeprecatedResourceBoundsMapping { fn from(value: ResourceBoundsMapping) -> Self { - Self([(Resource::L1Gas, value.l1_gas), (Resource::L2Gas, value.l2_gas)].into()) + Self( + [ + (Resource::L1Gas, value.l1_gas), + (Resource::L1DataGas, value.l1_data_gas), + (Resource::L2Gas, value.l2_gas), + ] + .into(), + ) } } @@ -171,31 +180,39 @@ impl From fn from(value: starknet_api::transaction::fields::DeprecatedResourceBoundsMapping) -> Self { Self { l1_gas: value.0.get(&Resource::L1Gas).cloned().unwrap_or_default(), + l1_data_gas: value.0.get(&Resource::L1DataGas).cloned().unwrap_or_default(), l2_gas: value.0.get(&Resource::L2Gas).cloned().unwrap_or_default(), } } } -impl TryFrom for starknet_api::transaction::fields::ValidResourceBounds { - type Error = ErrorObjectOwned; - fn try_from(value: ResourceBoundsMapping) -> Result { - if !value.l2_gas.is_zero() { - Err(internal_server_error("Got a transaction with non zero l2 gas.")) +impl From for ValidResourceBounds { + fn from(value: ResourceBoundsMapping) -> Self { + if value.l1_data_gas.is_zero() && value.l2_gas.is_zero() { + Self::L1Gas(value.l1_gas) } else { - Ok(Self::L1Gas(value.l1_gas)) + Self::AllResources(AllResourceBounds { + l1_gas: value.l1_gas, + l1_data_gas: value.l1_data_gas, + l2_gas: value.l2_gas, + }) } } } -impl From for ResourceBoundsMapping { - fn from(value: starknet_api::transaction::fields::ValidResourceBounds) -> Self { +impl From for ResourceBoundsMapping { + fn from(value: ValidResourceBounds) -> Self { match value { - starknet_api::transaction::fields::ValidResourceBounds::L1Gas(l1_gas) => { - Self { l1_gas, l2_gas: ResourceBounds::default() } - } - starknet_api::transaction::fields::ValidResourceBounds::AllResources( - AllResourceBounds { l1_gas, l2_gas, .. }, - ) => Self { l1_gas, l2_gas }, + ValidResourceBounds::L1Gas(l1_gas) => Self { + l1_gas, + l1_data_gas: ResourceBounds::default(), + l2_gas: ResourceBounds::default(), + }, + ValidResourceBounds::AllResources(AllResourceBounds { + l1_gas, + l1_data_gas, + l2_gas, + }) => Self { l1_gas, l1_data_gas, l2_gas }, } } } @@ -845,7 +862,8 @@ pub struct L1HandlerTransactionOutput { } // Note: This is not the same as the Builtins in starknet_api, the serialization of SegmentArena is -// different. TODO(yair): remove this once a newer version of the API is published. +// different. +// TODO(yair): remove this once a newer version of the API is published. #[derive(Debug, Clone, Eq, Hash, PartialEq, Deserialize, Serialize, PartialOrd, Ord)] pub enum Builtin { #[serde(rename = "range_check_builtin_applications")] @@ -949,9 +967,16 @@ impl Add for ExecutionResources { memory_holes, }, data_availability: DataAvailabilityResources { - l1_gas: self.data_availability.l1_gas + other.data_availability.l1_gas, - l1_data_gas: self.data_availability.l1_data_gas - + other.data_availability.l1_data_gas, + l1_gas: self + .data_availability + .l1_gas + .checked_add(other.data_availability.l1_gas) + .expect("L1 Gas overflow"), + l1_data_gas: self + .data_availability + .l1_data_gas + .checked_add(other.data_availability.l1_data_gas) + .expect("L1_Data Gas overflow"), }, } } @@ -1036,7 +1061,7 @@ impl From<(starknet_api::transaction::TransactionOutput, TransactionVersion, Opt ), ) -> Self { let (tx_output, tx_version, maybe_msg_hash) = tx_output_msg_hash; - // TODO: consider supporting match instead. + // TODO(DanB): consider supporting match instead. let actual_fee = if tx_version == TransactionVersion::ZERO || tx_version == TransactionVersion::ONE || tx_version == TransactionVersion::TWO @@ -1256,7 +1281,7 @@ fn l1_handler_message_hash( #[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize, Serialize)] pub struct MessageFromL1 { - // TODO: fix serialization of EthAddress in SN_API to fit the spec. + // TODO(Shahak): fix serialization of EthAddress in SN_API to fit the spec. #[serde(serialize_with = "serialize_eth_address")] pub from_address: EthAddress, pub to_address: ContractAddress, @@ -1281,7 +1306,7 @@ impl From for L1HandlerTransaction { calldata.extend_from_slice(&message.payload.0); let calldata = Calldata(Arc::new(calldata)); Self { - version: TransactionVersion::ONE, + version: L1HandlerTransaction::VERSION, contract_address: message.to_address, entry_point_selector: message.entry_point_selector, calldata, diff --git a/crates/papyrus_rpc/src/v0_8/transaction_test.rs b/crates/papyrus_rpc/src/v0_8/transaction_test.rs index 965656b6f87..e9c06471e7d 100644 --- a/crates/papyrus_rpc/src/v0_8/transaction_test.rs +++ b/crates/papyrus_rpc/src/v0_8/transaction_test.rs @@ -16,7 +16,7 @@ use starknet_api::transaction::fields::{ Tip, TransactionSignature, }; -use starknet_api::transaction::{L1HandlerTransaction, Transaction, TransactionVersion}; +use starknet_api::transaction::{L1HandlerTransaction, Transaction}; use starknet_api::{calldata, contract_address, felt, nonce}; use starknet_client::writer::objects::transaction as client_transaction; @@ -38,7 +38,7 @@ use super::{ lazy_static::lazy_static! { // A transaction from MAINNET with tx hash 0x439e12f67962c353182d72b4af12c3f11eaba4b36e552aebcdcd6db66971bdb. static ref L1_HANDLER_TX: L1HandlerTransaction = L1HandlerTransaction { - version: TransactionVersion::ZERO, + version: L1HandlerTransaction::VERSION, nonce: nonce!(0x18e94d), contract_address: contract_address!( "0x73314940630fd6dcda0d772d4c972c4e0a9946bef9dabf4ef84eda8ef542b82" @@ -132,7 +132,7 @@ auto_impl_get_test_instance! { } } -// TODO: check the conversion against the expected GW transaction. +// TODO(Yair): check the conversion against the expected GW transaction. #[test] fn test_gateway_trascation_from_starknet_api_transaction() { let mut rng = get_rng(); diff --git a/crates/papyrus_rpc/src/v0_8/write_api_result_test.rs b/crates/papyrus_rpc/src/v0_8/write_api_result_test.rs index d4d0bbfeb01..7be59678c2a 100644 --- a/crates/papyrus_rpc/src/v0_8/write_api_result_test.rs +++ b/crates/papyrus_rpc/src/v0_8/write_api_result_test.rs @@ -2,7 +2,7 @@ use papyrus_test_utils::{auto_impl_get_test_instance, get_rng, GetTestInstance}; use serde::Serialize; use starknet_api::core::{ClassHash, ContractAddress, PatriciaKey}; use starknet_api::transaction::TransactionHash; -use starknet_api::{class_hash, felt}; +use starknet_api::{class_hash, felt, tx_hash}; use starknet_client::writer::objects::response::{ DeclareResponse, DeployAccountResponse, @@ -54,7 +54,7 @@ fn add_deploy_account_ok_result_fits_rpc() { #[test] fn add_invoke_ok_result_from_response() { - let transaction_hash = TransactionHash(felt!("0x12345")); + let transaction_hash = tx_hash!(0x12345); let ok_result = AddInvokeOkResult::from(InvokeResponse { code: SuccessfulStarknetErrorCode::default(), transaction_hash, @@ -65,7 +65,7 @@ fn add_invoke_ok_result_from_response() { #[test] fn add_declare_ok_result_from_response() { - let transaction_hash = TransactionHash(felt!("0x12345")); + let transaction_hash = tx_hash!(0x12345); let class_hash = class_hash!("0xabcde"); let ok_result = AddDeclareOkResult::from(DeclareResponse { code: SuccessfulStarknetErrorCode::default(), @@ -78,7 +78,7 @@ fn add_declare_ok_result_from_response() { #[test] fn add_deploy_account_ok_result_from_response() { - let transaction_hash = TransactionHash(felt!("0x12345")); + let transaction_hash = tx_hash!(0x12345); let contract_address = ContractAddress(PatriciaKey::try_from(felt!("0xabcde")).unwrap()); let ok_result = AddDeployAccountOkResult::from(DeployAccountResponse { code: SuccessfulStarknetErrorCode::default(), diff --git a/crates/papyrus_rpc/tests/gateway_integration_test.rs b/crates/papyrus_rpc/tests/gateway_integration_test.rs index a4e24cb698d..bb9107b25b6 100644 --- a/crates/papyrus_rpc/tests/gateway_integration_test.rs +++ b/crates/papyrus_rpc/tests/gateway_integration_test.rs @@ -16,7 +16,6 @@ use starknet_api::transaction_hash::get_transaction_hash; use starknet_api::{calldata, contract_address, felt}; use starknet_client::writer::objects::transaction::InvokeTransaction as SNClientInvokeTransaction; use starknet_core::crypto::ecdsa_sign; -use starknet_core::types::FieldElement; use starknet_types_core::felt::Felt; const ETH_TO_WEI: u128 = u128::pow(10, 18); @@ -102,19 +101,17 @@ async fn test_gw_integration_testnet() { // Update the signature. let hash = get_transaction_hash( - &Transaction::Invoke( - InvokeTransactionRPC0_8::Version1(invoke_tx.clone()).try_into().unwrap(), - ), + &Transaction::Invoke(InvokeTransactionRPC0_8::Version1(invoke_tx.clone()).into()), &ChainId::Sepolia, &TransactionOptions::default(), ) .unwrap(); let signature = ecdsa_sign( - &FieldElement::from_hex_be(&env::var("SENDER_PRIVATE_KEY").expect( + &Felt::from_hex(&env::var("SENDER_PRIVATE_KEY").expect( "Sender private key must be given in SENDER_PRIVATE_KEY environment variable.", )) .unwrap(), - &FieldElement::from_bytes_be(&hash.0.to_bytes_be()).unwrap(), + &hash.0, ) .unwrap(); invoke_tx.signature = TransactionSignature(vec![ diff --git a/crates/papyrus_state_reader/Cargo.toml b/crates/papyrus_state_reader/Cargo.toml index 80d5d7cabb6..0521fe55b00 100644 --- a/crates/papyrus_state_reader/Cargo.toml +++ b/crates/papyrus_state_reader/Cargo.toml @@ -5,17 +5,26 @@ edition.workspace = true repository.workspace = true license.workspace = true +[features] +cairo_native = ["blockifier/cairo_native"] + [lints] workspace = true [dependencies] blockifier.workspace = true +cairo-lang-starknet-classes.workspace = true +log.workspace = true papyrus_storage.workspace = true starknet-types-core.workspace = true starknet_api.workspace = true +starknet_class_manager_types.workspace = true +tokio.workspace = true [dev-dependencies] assert_matches.workspace = true blockifier = { workspace = true, features = ["testing"] } +blockifier_test_utils.workspace = true indexmap.workspace = true papyrus_storage = { workspace = true, features = ["testing"] } +rstest.workspace = true diff --git a/crates/papyrus_state_reader/src/papyrus_state.rs b/crates/papyrus_state_reader/src/papyrus_state.rs index 3ff2cdc46e3..bb28f485564 100644 --- a/crates/papyrus_state_reader/src/papyrus_state.rs +++ b/crates/papyrus_state_reader/src/papyrus_state.rs @@ -1,18 +1,26 @@ +use std::sync::Arc; + use blockifier::execution::contract_class::{ - ContractClassV0, - ContractClassV1, - RunnableContractClass, + CompiledClassV0, + CompiledClassV1, + RunnableCompiledClass, }; -use blockifier::state::errors::StateError; -use blockifier::state::global_cache::GlobalContractCache; +use blockifier::state::contract_class_manager::ContractClassManager; +use blockifier::state::errors::{couple_casm_and_sierra, StateError}; +use blockifier::state::global_cache::CachedClass; use blockifier::state::state_api::{StateReader, StateResult}; +use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass; +use log; use papyrus_storage::compiled_class::CasmStorageReader; use papyrus_storage::db::RO; use papyrus_storage::state::StateStorageReader; use papyrus_storage::StorageReader; use starknet_api::block::BlockNumber; +use starknet_api::contract_class::{ContractClass, SierraVersion}; use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; -use starknet_api::state::{StateNumber, StorageKey}; +use starknet_api::deprecated_contract_class::ContractClass as DeprecatedClass; +use starknet_api::state::{SierraContractClass, StateNumber, StorageKey}; +use starknet_class_manager_types::SharedClassManagerClient; use starknet_types_core::felt::Felt; #[cfg(test)] @@ -20,19 +28,78 @@ use starknet_types_core::felt::Felt; mod test; type RawPapyrusReader<'env> = papyrus_storage::StorageTxn<'env, RO>; + +pub struct ClassReader { + pub reader: SharedClassManagerClient, + // Used to invoke async functions from sync reader code. + pub runtime: tokio::runtime::Handle, +} + +impl ClassReader { + fn read_executable(&self, class_hash: ClassHash) -> StateResult { + let casm = self + .runtime + .block_on(self.reader.get_executable(class_hash)) + .map_err(|err| StateError::StateReadError(err.to_string()))? + .ok_or(StateError::UndeclaredClassHash(class_hash))?; + + Ok(casm) + } + + fn read_casm(&self, class_hash: ClassHash) -> StateResult { + let casm = self.read_executable(class_hash)?; + let ContractClass::V1((casm, _sierra_version)) = casm else { + panic!("Class hash {class_hash} originated from a Cairo 1 contract."); + }; + + Ok(casm) + } + + fn read_sierra(&self, class_hash: ClassHash) -> StateResult { + let sierra = self + .runtime + .block_on(self.reader.get_sierra(class_hash)) + .map_err(|err| StateError::StateReadError(err.to_string()))? + .ok_or(StateError::UndeclaredClassHash(class_hash))?; + + Ok(sierra) + } + + // TODO(Elin): make `read[_optional_deprecated]_casm` symmetrical and independent of invocation + // order. + fn read_optional_deprecated_casm( + &self, + class_hash: ClassHash, + ) -> StateResult> { + let casm = self.read_executable(class_hash)?; + if let ContractClass::V0(casm) = casm { Ok(Some(casm)) } else { Ok(None) } + } +} + pub struct PapyrusReader { storage_reader: StorageReader, latest_block: BlockNumber, - global_class_hash_to_class: GlobalContractCache, + contract_class_manager: ContractClassManager, + // Reader is `None` for reader invoked through `native_blockifier`. + class_reader: Option, } impl PapyrusReader { + pub fn new_with_class_manager( + storage_reader: StorageReader, + latest_block: BlockNumber, + contract_class_manager: ContractClassManager, + class_reader: Option, + ) -> Self { + Self { storage_reader, latest_block, contract_class_manager, class_reader } + } + pub fn new( storage_reader: StorageReader, latest_block: BlockNumber, - global_class_hash_to_class: GlobalContractCache, + contract_class_manager: ContractClassManager, ) -> Self { - Self { storage_reader, latest_block, global_class_hash_to_class } + Self { storage_reader, latest_block, contract_class_manager, class_reader: None } } fn reader(&self) -> StateResult> { @@ -41,12 +108,9 @@ impl PapyrusReader { .map_err(|error| StateError::StateReadError(error.to_string())) } - /// Returns a V1 contract if found, or a V0 contract if a V1 contract is not - /// found, or an `Error` otherwise. - fn get_compiled_contract_class_inner( - &self, - class_hash: ClassHash, - ) -> StateResult { + /// Returns a V1 contract with Sierra if V1 contract is found, or a V0 contract without Sierra + /// if a V1 contract is not found, or an `Error` otherwise. + fn get_compiled_class_from_db(&self, class_hash: ClassHash) -> StateResult { let state_number = StateNumber(self.latest_block); let class_declaration_block_number = self .reader()? @@ -57,31 +121,61 @@ impl PapyrusReader { Some(block_number) if block_number <= state_number.0); if class_is_declared { - let casm_contract_class = self - .reader()? - .get_casm(&class_hash) - .map_err(|err| StateError::StateReadError(err.to_string()))? - .expect( - "Should be able to fetch a Casm class if its definition exists, database is \ - inconsistent.", - ); - - return Ok(RunnableContractClass::V1(ContractClassV1::try_from(casm_contract_class)?)); + // Cairo 1. + let (casm_compiled_class, sierra) = self.read_casm_and_sierra(class_hash)?; + let sierra_version = SierraVersion::extract_from_program(&sierra.sierra_program)?; + return Ok(CachedClass::V1( + CompiledClassV1::try_from((casm_compiled_class, sierra_version))?, + Arc::new(sierra), + )); } - let v0_contract_class = self - .reader()? - .get_state_reader() - .and_then(|sr| sr.get_deprecated_class_definition_at(state_number, &class_hash)) - .map_err(|err| StateError::StateReadError(err.to_string()))?; - - match v0_contract_class { + // Possibly Cairo 0. + let v0_compiled_class = self.read_deprecated_casm(class_hash)?; + match v0_compiled_class { Some(starknet_api_contract_class) => { - Ok(ContractClassV0::try_from(starknet_api_contract_class)?.into()) + Ok(CachedClass::V0(CompiledClassV0::try_from(starknet_api_contract_class)?)) } None => Err(StateError::UndeclaredClassHash(class_hash)), } } + + fn read_casm_and_sierra( + &self, + class_hash: ClassHash, + ) -> StateResult<(CasmContractClass, SierraContractClass)> { + let Some(class_reader) = &self.class_reader else { + let (option_casm, option_sierra) = self + .reader()? + .get_casm_and_sierra(&class_hash) + .map_err(|err| StateError::StateReadError(err.to_string()))?; + let (casm, sierra) = couple_casm_and_sierra(class_hash, option_casm, option_sierra)? + .expect( + "Should be able to fetch a Casm and Sierra class if its definition exists, + database is inconsistent.", + ); + + return Ok((casm, sierra)); + }; + + // TODO(Elin): consider not reading Sierra if compilation is disabled. + Ok((class_reader.read_casm(class_hash)?, class_reader.read_sierra(class_hash)?)) + } + + fn read_deprecated_casm(&self, class_hash: ClassHash) -> StateResult> { + let Some(class_reader) = &self.class_reader else { + let state_number = StateNumber(self.latest_block); + let option_casm = self + .reader()? + .get_state_reader() + .and_then(|sr| sr.get_deprecated_class_definition_at(state_number, &class_hash)) + .map_err(|err| StateError::StateReadError(err.to_string()))?; + + return Ok(option_casm); + }; + + class_reader.read_optional_deprecated_casm(class_hash) + } } // Currently unused - will soon replace the same `impl` for `PapyrusStateReader`. @@ -124,22 +218,23 @@ impl StateReader for PapyrusReader { } } - fn get_compiled_contract_class( - &self, - class_hash: ClassHash, - ) -> StateResult { + fn get_compiled_class(&self, class_hash: ClassHash) -> StateResult { // Assumption: the global cache is cleared upon reverted blocks. - let contract_class = self.global_class_hash_to_class.get(&class_hash); - - match contract_class { - Some(contract_class) => Ok(contract_class), - None => { - let contract_class_from_db = self.get_compiled_contract_class_inner(class_hash)?; - // The class was declared in a previous (finalized) state; update the global cache. - self.global_class_hash_to_class.set(class_hash, contract_class_from_db.clone()); - Ok(contract_class_from_db) - } + + // TODO(Yoni): move this logic to a separate reader. Move tests from papyrus_state. + if let Some(runnable_class) = self.contract_class_manager.get_runnable(&class_hash) { + return Ok(runnable_class); } + + let cached_class = self.get_compiled_class_from_db(class_hash)?; + self.contract_class_manager.set_and_compile(class_hash, cached_class.clone()); + // Access the cache again in case the class was compiled. + Ok(self.contract_class_manager.get_runnable(&class_hash).unwrap_or_else(|| { + // Edge case that should not be happen if the cache size is big enough. + // TODO(Yoni): consider having an atomic set-and-get. + log::error!("Class is missing immediately after being cached."); + cached_class.to_runnable() + })) } fn get_compiled_class_hash(&self, _class_hash: ClassHash) -> StateResult { diff --git a/crates/papyrus_state_reader/src/papyrus_state_test.rs b/crates/papyrus_state_reader/src/papyrus_state_test.rs index 0f398f00afc..c254c9e0d55 100644 --- a/crates/papyrus_state_reader/src/papyrus_state_test.rs +++ b/crates/papyrus_state_reader/src/papyrus_state_test.rs @@ -1,19 +1,29 @@ +use core::panic; + use assert_matches::assert_matches; +use blockifier::blockifier::config::ContractClassManagerConfig; use blockifier::execution::call_info::CallExecution; +use blockifier::execution::contract_class::RunnableCompiledClass; use blockifier::execution::entry_point::CallEntryPoint; use blockifier::retdata; use blockifier::state::cached_state::CachedState; -use blockifier::state::global_cache::{GlobalContractCache, GLOBAL_CONTRACT_CACHE_SIZE_FOR_TEST}; +use blockifier::state::contract_class_manager::ContractClassManager; +#[cfg(feature = "cairo_native")] +use blockifier::state::global_cache::{CachedCairoNative, CachedClass}; use blockifier::state::state_api::StateReader; -use blockifier::test_utils::contracts::FeatureContract; -use blockifier::test_utils::{trivial_external_entry_point_new, CairoVersion}; +use blockifier::test_utils::contracts::FeatureContractTrait; +use blockifier::test_utils::trivial_external_entry_point_new; +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; +use blockifier_test_utils::contracts::FeatureContract; use indexmap::IndexMap; use papyrus_storage::class::ClassStorageWriter; +use papyrus_storage::compiled_class::CasmStorageWriter; use papyrus_storage::state::StateStorageWriter; +use rstest::rstest; use starknet_api::abi::abi_utils::selector_from_name; use starknet_api::block::BlockNumber; use starknet_api::contract_class::ContractClass; -use starknet_api::state::{StateDiff, StorageKey}; +use starknet_api::state::{StateDiff, StorageKey, ThinStateDiff}; use starknet_api::{calldata, felt}; use crate::papyrus_state::PapyrusReader; @@ -49,7 +59,7 @@ fn test_entry_point_with_papyrus_state() -> papyrus_storage::StorageResult<()> { let papyrus_reader = PapyrusReader::new( storage_reader, block_number, - GlobalContractCache::new(GLOBAL_CONTRACT_CACHE_SIZE_FOR_TEST), + ContractClassManager::start(ContractClassManagerConfig::default()), ); let mut state = CachedState::from(papyrus_reader); @@ -75,3 +85,141 @@ fn test_entry_point_with_papyrus_state() -> papyrus_storage::StorageResult<()> { Ok(()) } + +fn build_papyrus_state_reader_and_declare_contract( + contract: FeatureContract, + contract_manager_config: ContractClassManagerConfig, +) -> PapyrusReader { + let class_hash = contract.get_class_hash(); + let ((storage_reader, mut storage_writer), _) = papyrus_storage::test_utils::get_test_storage(); + let test_compiled_class_hash = contract.get_compiled_class_hash(); + let block_number = BlockNumber::default(); + + // Hack to declare the contract in the storage. + match contract.get_class() { + ContractClass::V1((casm_class, _)) => { + let thin_state_diff = ThinStateDiff { + declared_classes: IndexMap::from([(class_hash, test_compiled_class_hash)]), + ..Default::default() + }; + storage_writer + .begin_rw_txn() + .unwrap() + .append_state_diff(block_number, thin_state_diff) + .unwrap() + .append_classes(block_number, &[(class_hash, &contract.get_sierra())], &[]) + .unwrap() + .append_casm(&class_hash, &casm_class) + .unwrap() + .commit() + .unwrap(); + } + + ContractClass::V0(deprecated_contract_class) => { + let thin_state_diff = ThinStateDiff { + deprecated_declared_classes: vec![class_hash], + ..Default::default() + }; + storage_writer + .begin_rw_txn() + .unwrap() + .append_state_diff(block_number, thin_state_diff) + .unwrap() + .append_classes(block_number, &[], &[(class_hash, &deprecated_contract_class)]) + .unwrap() + .commit() + .unwrap(); + } + } + + PapyrusReader::new( + storage_reader, + BlockNumber(1), + ContractClassManager::start(contract_manager_config), + ) +} + +#[rstest] +#[case::dont_run_cairo_native(false, false)] +#[cfg_attr(feature = "cairo_native", case::run_cairo_native_without_waiting(true, false))] +#[cfg_attr(feature = "cairo_native", case::run_cairo_native_and_wait(true, true))] +fn test_get_compiled_class_without_native_in_cache( + #[values(CairoVersion::Cairo0, CairoVersion::Cairo1(RunnableCairo1::Casm))] + cairo_version: CairoVersion, + #[case] run_cairo_native: bool, + #[case] wait_on_native_compilation: bool, +) { + // Sanity checks. + if !run_cairo_native { + assert!(!wait_on_native_compilation); + } + #[cfg(not(feature = "cairo_native"))] + assert!(!run_cairo_native); + + let test_contract = FeatureContract::TestContract(cairo_version); + let test_class_hash = test_contract.get_class_hash(); + let contract_manager_config = ContractClassManagerConfig::create_for_testing( + run_cairo_native, + wait_on_native_compilation, + ); + + let papyrus_reader = + build_papyrus_state_reader_and_declare_contract(test_contract, contract_manager_config); + // Sanity check - the cache is empty. + assert!(papyrus_reader.contract_class_manager.get_runnable(&test_class_hash).is_none()); + + let compiled_class = papyrus_reader.get_compiled_class(test_class_hash).unwrap(); + + match cairo_version { + CairoVersion::Cairo1(_) => { + // TODO(Meshi): Test that a compilation request was sent. + if wait_on_native_compilation { + #[cfg(feature = "cairo_native")] + assert_matches!( + compiled_class, + RunnableCompiledClass::V1Native(_), + "We should have waited to the native class." + ); + } else { + assert_matches!( + compiled_class, + RunnableCompiledClass::V1(_), + "We do not wait for native, return the cairo1 casm." + ); + } + } + CairoVersion::Cairo0 => { + assert_eq!( + compiled_class, + test_contract.get_runnable_class(), + "`get_compiled_class` should return the casm." + ); + } + } +} + +#[cfg(feature = "cairo_native")] +#[test] +fn test_get_compiled_class_when_native_is_cached() { + let ((storage_reader, _), _) = papyrus_storage::test_utils::get_test_storage(); + let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1(RunnableCairo1::Native)); + let test_class_hash = test_contract.get_class_hash(); + let contract_manager_config = ContractClassManagerConfig::create_for_testing(true, true); + let papyrus_reader = PapyrusReader::new( + storage_reader, + BlockNumber::default(), + ContractClassManager::start(contract_manager_config), + ); + if let RunnableCompiledClass::V1Native(native_compiled_class) = + test_contract.get_runnable_class() + { + papyrus_reader.contract_class_manager.set_and_compile( + test_class_hash, + CachedClass::V1Native(CachedCairoNative::Compiled(native_compiled_class)), + ); + } else { + panic!("Expected NativeCompiledClassV1"); + } + let compiled_class = papyrus_reader.get_compiled_class(test_class_hash).unwrap(); + assert_matches!(compiled_class, RunnableCompiledClass::V1Native(_)); +} diff --git a/crates/papyrus_storage/Cargo.toml b/crates/papyrus_storage/Cargo.toml index 21ee7564623..fb841327751 100644 --- a/crates/papyrus_storage/Cargo.toml +++ b/crates/papyrus_storage/Cargo.toml @@ -8,12 +8,7 @@ description = "A storage implementation for a Starknet node." [features] document_calls = ["lazy_static"] -testing = ["tempfile"] - -[[bin]] -name = "dump_declared_classes" -path = "src/bin/dump_declared_classes.rs" -required-features = ["clap"] +testing = ["starknet_api/testing", "tempfile"] [[bin]] name = "storage_benchmark" @@ -67,8 +62,10 @@ pretty_assertions.workspace = true prometheus-parse.workspace = true rand.workspace = true rand_chacha.workspace = true +rstest.workspace = true schemars = { workspace = true, features = ["preserve_order"] } simple_logger.workspace = true +starknet_api = { workspace = true, features = ["testing"] } tempfile = { workspace = true } test-case.workspace = true test-log.workspace = true diff --git a/crates/papyrus_storage/src/base_layer.rs b/crates/papyrus_storage/src/base_layer.rs index ea5e844e71a..90ca7ea8a0a 100644 --- a/crates/papyrus_storage/src/base_layer.rs +++ b/crates/papyrus_storage/src/base_layer.rs @@ -68,14 +68,14 @@ where ) -> StorageResult; } -impl<'env, Mode: TransactionKind> BaseLayerStorageReader for StorageTxn<'env, Mode> { +impl BaseLayerStorageReader for StorageTxn<'_, Mode> { fn get_base_layer_block_marker(&self) -> StorageResult { let markers_table = self.open_table(&self.tables.markers)?; Ok(markers_table.get(&self.txn, &MarkerKind::BaseLayerBlock)?.unwrap_or_default()) } } -impl<'env> BaseLayerStorageWriter for StorageTxn<'env, RW> { +impl BaseLayerStorageWriter for StorageTxn<'_, RW> { fn update_base_layer_block_marker(self, block_number: &BlockNumber) -> StorageResult { let markers_table = self.open_table(&self.tables.markers)?; markers_table.upsert(&self.txn, &MarkerKind::BaseLayerBlock, block_number)?; diff --git a/crates/papyrus_storage/src/bin/README.md b/crates/papyrus_storage/src/bin/README.md deleted file mode 100644 index 72496f4d19b..00000000000 --- a/crates/papyrus_storage/src/bin/README.md +++ /dev/null @@ -1,41 +0,0 @@ -# Dump Declared Classes Tool - -This tool allows you to dump the entire `declared_classes` table from Papyrus storage into a file. - -## Instructions - -1. **Run a Docker** - Please refer to the main [README](../../../../README.adoc#running-papyrus-with-docker) for instructions. - - Note: use a released Docker image - -3. **View Running Docker Containers** - - ```bash - docker ps - ``` - You can also view the logs produced by the full node with: - - ```bash - docker logs - ``` - -4. **Sync the Full Node** - - The full node sync could take a few hours/days. Once it's partially or fully synced, you can run the tool to dump the declared classes into a file. - -5. **Access the Docker Container** - - ```bash - docker exec -ti sh - ``` - -6. **Run the Tool** - - ```bash - target/release/dump_declared_classes --start_block --end_block --chain_id [--file_path file_path] - ``` - - The default value for file_path is `dump_declared_classes.json`. - - diff --git a/crates/papyrus_storage/src/bin/dump_declared_classes.rs b/crates/papyrus_storage/src/bin/dump_declared_classes.rs deleted file mode 100644 index 80c43999cee..00000000000 --- a/crates/papyrus_storage/src/bin/dump_declared_classes.rs +++ /dev/null @@ -1,79 +0,0 @@ -use clap::{Arg, Command}; -use papyrus_storage::utils::dump_declared_classes_table_by_block_range; -use starknet_api::core::ChainId; - -/// This executable dumps the declared_classes table from the storage to a file. -fn main() { - let cli_params = get_cli_params(); - match dump_declared_classes_table_by_block_range( - cli_params.start_block, - cli_params.end_block, - &cli_params.file_path, - &cli_params.chain_id, - ) { - Ok(_) => println!("Dumped declared_classes table to file: {} .", cli_params.file_path), - Err(e) => println!("Failed dumping declared_classes table with error: {}", e), - } -} - -struct CliParams { - start_block: u64, - end_block: u64, - file_path: String, - chain_id: ChainId, -} - -/// The start_block and end_block arguments are mandatory and define the block range to dump, -/// start_block is inclusive and end_block is exclusive. The file_path is an optional parameter, -/// otherwise the data will be dumped to "dump_declared_classes.json". -fn get_cli_params() -> CliParams { - let matches = Command::new("Dump declared classes") - .arg( - Arg::new("file_path") - .short('f') - .long("file_path") - .default_value("dump_declared_classes.json") - .help("The file path to dump the declared classes table to."), - ) - .arg( - Arg::new("start_block") - .short('s') - .long("start_block") - .required(true) - .help("The block number to start dumping from."), - ) - .arg( - Arg::new("end_block") - .short('e') - .long("end_block") - .required(true) - .help("The block number to end dumping at."), - ) - .arg( - Arg::new("chain_id") - .short('c') - .long("chain_id") - .required(true) - .help("The chain id SN_MAIN/SN_SEPOLIA, default value is SN_MAIN."), - ) - .get_matches(); - - let file_path = - matches.get_one::("file_path").expect("Failed parsing file_path").to_string(); - let start_block = matches - .get_one::("start_block") - .expect("Failed parsing start_block") - .parse::() - .expect("Failed parsing start_block"); - let end_block = matches - .get_one::("end_block") - .expect("Failed parsing end_block") - .parse::() - .expect("Failed parsing end_block"); - if start_block >= end_block { - panic!("start_block must be smaller than end_block"); - } - let chain_id = - matches.get_one::("chain_id").expect("Failed parsing chain_id").to_string(); - CliParams { start_block, end_block, file_path, chain_id: ChainId::Other(chain_id) } -} diff --git a/crates/papyrus_storage/src/body/events.rs b/crates/papyrus_storage/src/body/events.rs index ca45f35de73..4f961843b7a 100644 --- a/crates/papyrus_storage/src/body/events.rs +++ b/crates/papyrus_storage/src/body/events.rs @@ -93,7 +93,7 @@ pub trait EventsReader<'txn, 'env> { ) -> StorageResult>; } -// TODO: support all read transactions (including RW). +// TODO(DanB): support all read transactions (including RW). impl<'txn, 'env> EventsReader<'txn, 'env> for StorageTxn<'env, RO> { fn iter_events( &'env self, @@ -152,7 +152,7 @@ pub struct EventIterByContractAddress<'env, 'txn> { transaction_metadata_table: TransactionMetadataTable<'env>, } -impl<'env, 'txn> EventIterByContractAddress<'env, 'txn> { +impl EventIterByContractAddress<'_, '_> { /// Returns the next event. If there are no more events, returns None. /// /// # Errors diff --git a/crates/papyrus_storage/src/body/mod.rs b/crates/papyrus_storage/src/body/mod.rs index 066be012aa1..4a560715f1f 100644 --- a/crates/papyrus_storage/src/body/mod.rs +++ b/crates/papyrus_storage/src/body/mod.rs @@ -162,7 +162,7 @@ where ) -> StorageResult<(Self, Option)>; } -impl<'env, Mode: TransactionKind> BodyStorageReader for StorageTxn<'env, Mode> { +impl BodyStorageReader for StorageTxn<'_, Mode> { fn get_body_marker(&self) -> StorageResult { let markers_table = self.open_table(&self.tables.markers)?; Ok(markers_table.get(&self.txn, &MarkerKind::Body)?.unwrap_or_default()) @@ -341,7 +341,7 @@ impl<'env, Mode: TransactionKind> StorageTxn<'env, Mode> { } } -impl<'env> BodyStorageWriter for StorageTxn<'env, RW> { +impl BodyStorageWriter for StorageTxn<'_, RW> { #[latency_histogram("storage_append_body_latency_seconds", false)] fn append_body(self, block_number: BlockNumber, block_body: BlockBody) -> StorageResult { let markers_table = self.open_table(&self.tables.markers)?; diff --git a/crates/papyrus_storage/src/class.rs b/crates/papyrus_storage/src/class.rs index 08e38d4d60c..193529d7c97 100644 --- a/crates/papyrus_storage/src/class.rs +++ b/crates/papyrus_storage/src/class.rs @@ -124,7 +124,7 @@ where ) -> StorageResult; } -impl<'env, Mode: TransactionKind> ClassStorageReader for StorageTxn<'env, Mode> { +impl ClassStorageReader for StorageTxn<'_, Mode> { fn get_class(&self, class_hash: &ClassHash) -> StorageResult> { let declared_classes_table = self.open_table(&self.tables.declared_classes)?; let contract_class_location = declared_classes_table.get(&self.txn, class_hash)?; @@ -154,7 +154,7 @@ impl<'env, Mode: TransactionKind> ClassStorageReader for StorageTxn<'env, Mode> } } -impl<'env> ClassStorageWriter for StorageTxn<'env, RW> { +impl ClassStorageWriter for StorageTxn<'_, RW> { #[latency_histogram("storage_append_classes_latency_seconds", false)] fn append_classes( self, diff --git a/crates/papyrus_storage/src/class_hash.rs b/crates/papyrus_storage/src/class_hash.rs new file mode 100644 index 00000000000..bab7abc84da --- /dev/null +++ b/crates/papyrus_storage/src/class_hash.rs @@ -0,0 +1,64 @@ +//! Interface for handling hashes of Starknet [classes (Cairo 1)](https://docs.rs/starknet_api/latest/starknet_api/state/struct.ContractClass.html). +//! This is a table separate from Papyrus storage; scope and version do not apply on it. +//! Use carefully, only within class manager code, which is responsible for maintaining this table. +//! +//! Import [`ClassHashStorageReader`] and [`ClassHashStorageWriter`] to read and write data related +//! to classes using a [`StorageTxn`]. + +use starknet_api::core::{ClassHash, CompiledClassHash}; + +use crate::db::table_types::Table; +use crate::db::{TransactionKind, RW}; +use crate::{StorageResult, StorageTxn}; + +#[cfg(test)] +#[path = "class_hash_test.rs"] +mod class_hash_test; + +// TODO(Elin): consider implementing directly over `libmdbx`. + +/// Interface for reading executable class hashes. +pub trait ClassHashStorageReader { + /// Returns the executable class hash corresponding to the given class hash. + /// Returns `None` if the class hash is not found. + fn get_executable_class_hash( + &self, + class_hash: &ClassHash, + ) -> StorageResult>; +} + +/// Interface for writing executable class hashes. +pub trait ClassHashStorageWriter +where + Self: Sized, +{ + /// Inserts the executable class hash corresponding to the given class hash. + /// An error is returned if the class hash already exists. + fn set_executable_class_hash( + self, + class_hash: &ClassHash, + executable_class_hash: CompiledClassHash, + ) -> StorageResult; +} + +impl ClassHashStorageReader for StorageTxn<'_, Mode> { + fn get_executable_class_hash( + &self, + class_hash: &ClassHash, + ) -> StorageResult> { + let table = self.open_table(&self.tables.class_hash_to_executable_class_hash)?; + Ok(table.get(&self.txn, class_hash)?) + } +} + +impl ClassHashStorageWriter for StorageTxn<'_, RW> { + fn set_executable_class_hash( + self, + class_hash: &ClassHash, + executable_class_hash: CompiledClassHash, + ) -> StorageResult { + let table = self.open_table(&self.tables.class_hash_to_executable_class_hash)?; + table.insert(&self.txn, class_hash, &executable_class_hash)?; + Ok(self) + } +} diff --git a/crates/papyrus_storage/src/class_hash_test.rs b/crates/papyrus_storage/src/class_hash_test.rs new file mode 100644 index 00000000000..d73310c82b1 --- /dev/null +++ b/crates/papyrus_storage/src/class_hash_test.rs @@ -0,0 +1,31 @@ +use starknet_api::core::{ClassHash, CompiledClassHash}; +use starknet_api::felt; + +use crate::class_hash::{ClassHashStorageReader, ClassHashStorageWriter}; +use crate::test_utils::get_test_storage; + +#[test] +fn class_hash_storage() { + let ((reader, mut writer), _temp_dir) = get_test_storage(); + + // Non-existent entry. + let class_hash = ClassHash(felt!("0x1234")); + let executable_class_hash = + reader.begin_ro_txn().unwrap().get_executable_class_hash(&class_hash).unwrap(); + assert_eq!(executable_class_hash, None); + + // Insert an entry. + let expected_executable_class_hash = CompiledClassHash(felt!("0x5678")); + writer + .begin_rw_txn() + .unwrap() + .set_executable_class_hash(&class_hash, expected_executable_class_hash) + .unwrap() + .commit() + .unwrap(); + + // Read the inserted entry. + let executable_class_hash = + reader.begin_ro_txn().unwrap().get_executable_class_hash(&class_hash).unwrap(); + assert_eq!(executable_class_hash, Some(expected_executable_class_hash)); +} diff --git a/crates/papyrus_storage/src/class_manager.rs b/crates/papyrus_storage/src/class_manager.rs new file mode 100644 index 00000000000..fb0de553bbf --- /dev/null +++ b/crates/papyrus_storage/src/class_manager.rs @@ -0,0 +1,94 @@ +//! Interface for handling data related to the class manager. +// TODO(noamsp): Add Documentation +#[cfg(test)] +#[path = "class_manager_test.rs"] +mod class_manager_test; + +use starknet_api::block::BlockNumber; + +use crate::db::table_types::Table; +use crate::db::{TransactionKind, RW}; +use crate::{MarkerKind, StorageResult, StorageTxn}; + +/// Interface for reading data related to the class manager. +pub trait ClassManagerStorageReader { + /// The block number marker is the first block number that doesn't exist yet in the class + /// manager. + fn get_class_manager_block_marker(&self) -> StorageResult; + + /// The block number marker is the first block number that the class manager supports + /// compilation from. + fn get_compiler_backward_compatibility_marker(&self) -> StorageResult; +} + +/// Interface for writing data related to the class manager. +pub trait ClassManagerStorageWriter +where + Self: Sized, +{ + /// Updates the block marker of the class manager. + // To enforce that no commit happen after a failure, we consume and return Self on success. + fn update_class_manager_block_marker(self, block_number: &BlockNumber) -> StorageResult; + + /// Reverts the class manager marker by one block if the current marker in storage is + /// `target_block_number + 1`. This means it can only revert one height at a time. + fn try_revert_class_manager_marker( + self, + target_block_number: BlockNumber, + ) -> StorageResult; + + /// Updates the block marker of compiler backward compatibility, marking the blocks behind the + /// given number as non-backward-compatible. + // To enforce that no commit happen after a failure, we consume and return Self on success. + fn update_compiler_backward_compatibility_marker( + self, + block_number: &BlockNumber, + ) -> StorageResult; +} + +impl ClassManagerStorageReader for StorageTxn<'_, Mode> { + fn get_class_manager_block_marker(&self) -> StorageResult { + let markers_table = self.open_table(&self.tables.markers)?; + Ok(markers_table.get(&self.txn, &MarkerKind::ClassManagerBlock)?.unwrap_or_default()) + } + + fn get_compiler_backward_compatibility_marker(&self) -> StorageResult { + let markers_table = self.open_table(&self.tables.markers)?; + Ok(markers_table + .get(&self.txn, &MarkerKind::CompilerBackwardCompatibility)? + .unwrap_or_default()) + } +} + +impl ClassManagerStorageWriter for StorageTxn<'_, RW> { + fn update_class_manager_block_marker(self, block_number: &BlockNumber) -> StorageResult { + let markers_table = self.open_table(&self.tables.markers)?; + markers_table.upsert(&self.txn, &MarkerKind::ClassManagerBlock, block_number)?; + Ok(self) + } + + fn try_revert_class_manager_marker( + self, + target_block_number: BlockNumber, + ) -> StorageResult { + let cur_marker = self.get_class_manager_block_marker()?; + if cur_marker == target_block_number.unchecked_next() { + Ok(self.update_class_manager_block_marker(&target_block_number)?) + } else { + Ok(self) + } + } + + fn update_compiler_backward_compatibility_marker( + self, + block_number: &BlockNumber, + ) -> StorageResult { + let markers_table = self.open_table(&self.tables.markers)?; + markers_table.upsert( + &self.txn, + &MarkerKind::CompilerBackwardCompatibility, + block_number, + )?; + Ok(self) + } +} diff --git a/crates/papyrus_storage/src/class_manager_test.rs b/crates/papyrus_storage/src/class_manager_test.rs new file mode 100644 index 00000000000..e6f40af2fbb --- /dev/null +++ b/crates/papyrus_storage/src/class_manager_test.rs @@ -0,0 +1,54 @@ +use rstest::rstest; +use starknet_api::block::BlockNumber; + +use crate::class_manager::{ClassManagerStorageReader, ClassManagerStorageWriter}; +use crate::test_utils::get_test_storage; + +#[test] +fn get_class_manager_marker_initial_state() { + let (reader, _) = get_test_storage().0; + + let marker = reader.begin_ro_txn().unwrap().get_class_manager_block_marker().unwrap(); + assert_eq!(marker, BlockNumber(0)); +} + +#[test] +fn update_class_manager_marker() { + let (reader, mut writer) = get_test_storage().0; + + writer + .begin_rw_txn() + .unwrap() + .update_class_manager_block_marker(&BlockNumber(2)) + .unwrap() + .commit() + .unwrap(); + let updated_marker = reader.begin_ro_txn().unwrap().get_class_manager_block_marker().unwrap(); + assert_eq!(updated_marker, BlockNumber(2)); +} + +#[rstest] +#[case::equal_to_current_minus_one(BlockNumber(2), BlockNumber(1), BlockNumber(1))] +#[case::smaller_than_current_minus_one(BlockNumber(2), BlockNumber(0), BlockNumber(2))] +#[case::equal_to_current(BlockNumber(2), BlockNumber(2), BlockNumber(2))] +#[case::larger_than_current(BlockNumber(2), BlockNumber(3), BlockNumber(2))] +fn try_revert_class_manager_marker( + #[case] initial_block_marker: BlockNumber, + #[case] target_block_marker: BlockNumber, + #[case] expected_block_marker: BlockNumber, +) { + let (reader, mut writer) = get_test_storage().0; + + writer + .begin_rw_txn() + .unwrap() + .update_class_manager_block_marker(&initial_block_marker) + .unwrap() + .try_revert_class_manager_marker(target_block_marker) + .unwrap() + .commit() + .unwrap(); + + let cur_marker = reader.begin_ro_txn().unwrap().get_class_manager_block_marker().unwrap(); + assert_eq!(cur_marker, expected_block_marker); +} diff --git a/crates/papyrus_storage/src/compiled_class.rs b/crates/papyrus_storage/src/compiled_class.rs index 2f3488cf7e6..1ee8c2d5830 100644 --- a/crates/papyrus_storage/src/compiled_class.rs +++ b/crates/papyrus_storage/src/compiled_class.rs @@ -50,7 +50,9 @@ use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass; use papyrus_proc_macros::latency_histogram; use starknet_api::block::BlockNumber; use starknet_api::core::ClassHash; +use starknet_api::state::SierraContractClass; +use crate::class::ClassStorageReader; use crate::db::serialization::VersionZeroWrapper; use crate::db::table_types::{SimpleTable, Table}; use crate::db::{DbTransaction, TableHandle, TransactionKind, RW}; @@ -61,6 +63,15 @@ use crate::{FileHandlers, MarkerKind, MarkersTable, OffsetKind, StorageResult, S pub trait CasmStorageReader { /// Returns the Cairo assembly of a class given its Sierra class hash. fn get_casm(&self, class_hash: &ClassHash) -> StorageResult>; + + /// Returns the CASM and Sierra contract classes for the given hash. + /// If both exist, returns `(Some(casm), Some(sierra))`. + /// If neither, returns `(None, None)`. + /// If only one exists, returns `(Some, None)` or `(None, Some)`. + fn get_casm_and_sierra( + &self, + class_hash: &ClassHash, + ) -> StorageResult<(Option, Option)>; /// The block marker is the first block number that doesn't exist yet. /// /// Note: If the last blocks don't contain any declared classes, the marker will point at the @@ -78,20 +89,27 @@ where fn append_casm(self, class_hash: &ClassHash, casm: &CasmContractClass) -> StorageResult; } -impl<'env, Mode: TransactionKind> CasmStorageReader for StorageTxn<'env, Mode> { +impl CasmStorageReader for StorageTxn<'_, Mode> { fn get_casm(&self, class_hash: &ClassHash) -> StorageResult> { let casm_table = self.open_table(&self.tables.casms)?; let casm_location = casm_table.get(&self.txn, class_hash)?; casm_location.map(|location| self.file_handlers.get_casm_unchecked(location)).transpose() } + fn get_casm_and_sierra( + &self, + class_hash: &ClassHash, + ) -> StorageResult<(Option, Option)> { + Ok((self.get_casm(class_hash)?, self.get_class(class_hash)?)) + } + fn get_compiled_class_marker(&self) -> StorageResult { let markers_table = self.open_table(&self.tables.markers)?; Ok(markers_table.get(&self.txn, &MarkerKind::CompiledClass)?.unwrap_or_default()) } } -impl<'env> CasmStorageWriter for StorageTxn<'env, RW> { +impl CasmStorageWriter for StorageTxn<'_, RW> { #[latency_histogram("storage_append_casm_latency_seconds", false)] fn append_casm(self, class_hash: &ClassHash, casm: &CasmContractClass) -> StorageResult { let casm_table = self.open_table(&self.tables.casms)?; diff --git a/crates/papyrus_storage/src/compiled_class_test.rs b/crates/papyrus_storage/src/compiled_class_test.rs index 204cada5745..2e2aec5c014 100644 --- a/crates/papyrus_storage/src/compiled_class_test.rs +++ b/crates/papyrus_storage/src/compiled_class_test.rs @@ -1,9 +1,14 @@ use assert_matches::assert_matches; use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass; +use papyrus_test_utils::{get_rng, GetTestInstance}; use pretty_assertions::assert_eq; +use rstest::rstest; +use starknet_api::block::BlockNumber; use starknet_api::core::ClassHash; +use starknet_api::state::SierraContractClass; use starknet_api::test_utils::read_json_file; +use crate::class::ClassStorageWriter; use crate::compiled_class::{CasmStorageReader, CasmStorageWriter}; use crate::db::{DbError, KeyAlreadyExistsError}; use crate::test_utils::get_test_storage; @@ -27,6 +32,46 @@ fn append_casm() { assert_eq!(casm, expected_casm); } +#[rstest] +fn test_casm_and_sierra( + #[values(true, false)] has_casm: bool, + #[values(true, false)] has_sierra: bool, +) { + let test_class_hash = ClassHash::default(); + let mut rng = get_rng(); + + // Setup storage. + let ((reader, mut writer), _temp_dir) = get_test_storage(); + let expected_casm = CasmContractClass::get_test_instance(&mut rng); + let expected_sierra = ::get_test_instance(&mut rng); + + if has_casm { + writer + .begin_rw_txn() + .unwrap() + .append_casm(&test_class_hash, &expected_casm) + .unwrap() + .commit() + .unwrap(); + } + if has_sierra { + writer + .begin_rw_txn() + .unwrap() + .append_classes(BlockNumber::default(), &[(test_class_hash, &expected_sierra)], &[]) + .unwrap() + .commit() + .unwrap(); + } + + let result = reader.begin_ro_txn().unwrap().get_casm_and_sierra(&test_class_hash); + + assert_eq!( + result.unwrap(), + (has_casm.then_some(expected_casm), has_sierra.then_some(expected_sierra)) + ); +} + #[test] fn casm_rewrite() { let ((_, mut writer), _temp_dir) = get_test_storage(); diff --git a/crates/papyrus_storage/src/compression_utils.rs b/crates/papyrus_storage/src/compression_utils.rs index fd9c0de4b36..c6c637df3b7 100644 --- a/crates/papyrus_storage/src/compression_utils.rs +++ b/crates/papyrus_storage/src/compression_utils.rs @@ -6,7 +6,8 @@ use crate::db::serialization::{StorageSerde, StorageSerdeError}; // TODO(dvir): create one compressor/decompressor only once (maybe only once per thread) to prevent // buffer reallocation. -// TODO: fine tune the compression hyperparameters (and maybe even the compression algorithm). +// TODO(Dvir): fine tune the compression hyperparameters (and maybe even the compression +// algorithm). // The maximum size of the decompressed data. // TODO(Dvir): consider defining this for each type separately and pass it as an argument to the @@ -43,7 +44,7 @@ pub fn serialize_and_compress(object: &impl StorageSerde) -> Result, Sto /// /// # Arguments /// * data - bytes to decompress. - +/// /// # Errors /// Returns [`std::io::Error`] if any read error is encountered. pub fn decompress(data: &[u8]) -> Result, std::io::Error> { diff --git a/crates/papyrus_storage/src/db/db_test.rs b/crates/papyrus_storage/src/db/db_test.rs index 747d88f4581..879e91ae61a 100644 --- a/crates/papyrus_storage/src/db/db_test.rs +++ b/crates/papyrus_storage/src/db/db_test.rs @@ -227,7 +227,7 @@ fn with_version_zero_serialization() { let iter = DbIter::new(&mut cursor); assert_eq!(items, iter.collect::>>().unwrap()); - // TODO: move to serialization tests. + // TODO(DanB): move to serialization tests. const A_RANDOM_U8: u8 = 123; let with_zero_version_serialization = VersionZeroWrapper::::serialize(&A_RANDOM_U8).unwrap(); diff --git a/crates/papyrus_storage/src/db/mod.rs b/crates/papyrus_storage/src/db/mod.rs index 2573ebb7b0d..193f4b147b5 100644 --- a/crates/papyrus_storage/src/db/mod.rs +++ b/crates/papyrus_storage/src/db/mod.rs @@ -31,7 +31,7 @@ use std::sync::Arc; use libmdbx::{DatabaseFlags, Geometry, PageSize, WriteMap}; use papyrus_config::dumping::{ser_param, SerializeConfig}; -use papyrus_config::validators::{validate_ascii, validate_path_exists}; +use papyrus_config::validators::validate_ascii; use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; use papyrus_proc_macros::latency_histogram; use serde::{Deserialize, Serialize}; @@ -43,7 +43,7 @@ use self::table_types::{DbCursor, DbCursorTrait}; use crate::db::table_types::TableType; // Maximum number of Sub-Databases. -const MAX_DBS: usize = 18; +const MAX_DBS: usize = 19; // Note that NO_TLS mode is used by default. type EnvironmentKind = WriteMap; @@ -57,7 +57,6 @@ type DbValueType<'env> = Cow<'env, [u8]>; pub struct DbConfig { /// The path prefix of the database files. The final path is the path prefix followed by the /// chain id. - #[validate(custom = "validate_path_exists")] pub path_prefix: PathBuf, /// The [chain id](https://docs.rs/starknet_api/latest/starknet_api/core/struct.ChainId.html) of the Starknet network. #[validate(custom = "validate_ascii")] @@ -77,6 +76,7 @@ impl Default for DbConfig { fn default() -> Self { DbConfig { path_prefix: PathBuf::from("./data"), + // TODO(guyn): should we remove the default for chain_id? chain_id: ChainId::Mainnet, enforce_file_exists: false, min_size: 1 << 20, // 1MB @@ -261,7 +261,7 @@ impl DbWriter { type DbWriteTransaction<'env> = DbTransaction<'env, RW>; -impl<'a> DbWriteTransaction<'a> { +impl DbWriteTransaction<'_> { #[latency_histogram("storage_commit_inner_db_latency_seconds", false)] pub(crate) fn commit(self) -> DbResult<()> { self.txn.commit()?; @@ -279,7 +279,7 @@ pub(crate) struct DbTransaction<'env, Mode: TransactionKind> { txn: libmdbx::Transaction<'env, Mode::Internal, EnvironmentKind>, } -impl<'a, Mode: TransactionKind> DbTransaction<'a, Mode> { +impl DbTransaction<'_, Mode> { pub fn open_table<'env, K: Key + Debug, V: ValueSerde + Debug, T: TableType>( &'env self, table_id: &TableIdentifier, @@ -326,8 +326,8 @@ impl<'cursor, 'txn, Mode: TransactionKind, K: Key, V: ValueSerde, T: TableType> } } -impl<'cursor, 'txn, Mode: TransactionKind, K: Key, V: ValueSerde, T: TableType> Iterator - for DbIter<'cursor, 'txn, Mode, K, V, T> +impl<'txn, Mode: TransactionKind, K: Key, V: ValueSerde, T: TableType> Iterator + for DbIter<'_, 'txn, Mode, K, V, T> where DbCursor<'txn, Mode, K, V, T>: DbCursorTrait, { diff --git a/crates/papyrus_storage/src/db/serialization.rs b/crates/papyrus_storage/src/db/serialization.rs index 0ff9f28ae3c..936daabe834 100644 --- a/crates/papyrus_storage/src/db/serialization.rs +++ b/crates/papyrus_storage/src/db/serialization.rs @@ -174,6 +174,6 @@ pub enum StorageSerdeError { // Make sure we are at EOF. fn is_all_bytes_read(bytes: &mut impl std::io::Read) -> bool { let mut buf = [0u8, 1]; - // TODO: return an error instead of false. + // TODO(DvirYo): return an error instead of false. bytes.read(&mut buf[..]).ok() == Some(0) } diff --git a/crates/papyrus_storage/src/db/table_types/dup_sort_tables.rs b/crates/papyrus_storage/src/db/table_types/dup_sort_tables.rs index 7c607b6b9d3..7596a39553c 100644 --- a/crates/papyrus_storage/src/db/table_types/dup_sort_tables.rs +++ b/crates/papyrus_storage/src/db/table_types/dup_sort_tables.rs @@ -409,12 +409,11 @@ impl<'env, K: KeyTrait + Debug, V: ValueSerde + Debug, T: DupSortTableType + Dup } impl< - 'txn, Mode: TransactionKind, K: KeyTrait + Debug, V: ValueSerde + Debug, T: DupSortTableType + DupSortUtils, -> DbCursorTrait for DbCursor<'txn, Mode, K, V, T> +> DbCursorTrait for DbCursor<'_, Mode, K, V, T> { type Key = K; type Value = V; diff --git a/crates/papyrus_storage/src/db/table_types/simple_table.rs b/crates/papyrus_storage/src/db/table_types/simple_table.rs index 37208145444..d583c930a4c 100644 --- a/crates/papyrus_storage/src/db/table_types/simple_table.rs +++ b/crates/papyrus_storage/src/db/table_types/simple_table.rs @@ -137,8 +137,8 @@ impl<'env, K: KeyTrait + Debug, V: ValueSerde + Debug> Table<'env> } } -impl<'txn, Mode: TransactionKind, K: KeyTrait + Debug, V: ValueSerde + Debug> DbCursorTrait - for DbCursor<'txn, Mode, K, V, SimpleTable> +impl DbCursorTrait + for DbCursor<'_, Mode, K, V, SimpleTable> { type Key = K; type Value = V; diff --git a/crates/papyrus_storage/src/header.rs b/crates/papyrus_storage/src/header.rs index c33c98f37fe..5d73ef6a440 100644 --- a/crates/papyrus_storage/src/header.rs +++ b/crates/papyrus_storage/src/header.rs @@ -73,6 +73,8 @@ pub(crate) struct StorageBlockHeader { pub l1_gas_price: GasPricePerToken, pub l1_data_gas_price: GasPricePerToken, pub l2_gas_price: GasPricePerToken, + pub l2_gas_consumed: u64, + pub next_l2_gas_price: u64, pub state_root: GlobalRoot, pub sequencer: SequencerContractAddress, pub timestamp: BlockTimestamp, @@ -151,7 +153,7 @@ where ) -> StorageResult; } -impl<'env, Mode: TransactionKind> HeaderStorageReader for StorageTxn<'env, Mode> { +impl HeaderStorageReader for StorageTxn<'_, Mode> { fn get_header_marker(&self) -> StorageResult { let markers_table = self.open_table(&self.tables.markers)?; Ok(markers_table.get(&self.txn, &MarkerKind::Header)?.unwrap_or_default()) @@ -173,6 +175,8 @@ impl<'env, Mode: TransactionKind> HeaderStorageReader for StorageTxn<'env, Mode> l1_gas_price: block_header.l1_gas_price, l1_data_gas_price: block_header.l1_data_gas_price, l2_gas_price: block_header.l2_gas_price, + l2_gas_consumed: block_header.l2_gas_consumed, + next_l2_gas_price: block_header.next_l2_gas_price, state_root: block_header.state_root, sequencer: block_header.sequencer, timestamp: block_header.timestamp, @@ -234,7 +238,7 @@ impl<'env, Mode: TransactionKind> HeaderStorageReader for StorageTxn<'env, Mode> } } -impl<'env> HeaderStorageWriter for StorageTxn<'env, RW> { +impl HeaderStorageWriter for StorageTxn<'_, RW> { fn append_header( self, block_number: BlockNumber, @@ -253,6 +257,8 @@ impl<'env> HeaderStorageWriter for StorageTxn<'env, RW> { l1_gas_price: block_header.block_header_without_hash.l1_gas_price, l1_data_gas_price: block_header.block_header_without_hash.l1_data_gas_price, l2_gas_price: block_header.block_header_without_hash.l2_gas_price, + l2_gas_consumed: block_header.block_header_without_hash.l2_gas_consumed, + next_l2_gas_price: block_header.block_header_without_hash.next_l2_gas_price, state_root: block_header.block_header_without_hash.state_root, sequencer: block_header.block_header_without_hash.sequencer, timestamp: block_header.block_header_without_hash.timestamp, @@ -364,6 +370,8 @@ impl<'env> HeaderStorageWriter for StorageTxn<'env, RW> { l1_gas_price: reverted_header.l1_gas_price, l1_data_gas_price: reverted_header.l1_data_gas_price, l2_gas_price: reverted_header.l2_gas_price, + l2_gas_consumed: reverted_header.l2_gas_consumed, + next_l2_gas_price: reverted_header.next_l2_gas_price, state_root: reverted_header.state_root, sequencer: reverted_header.sequencer, timestamp: reverted_header.timestamp, diff --git a/crates/papyrus_storage/src/lib.rs b/crates/papyrus_storage/src/lib.rs index 2cc0101272e..e01a523a3b1 100644 --- a/crates/papyrus_storage/src/lib.rs +++ b/crates/papyrus_storage/src/lib.rs @@ -78,10 +78,12 @@ pub mod base_layer; pub mod body; pub mod class; +pub mod class_hash; +pub mod class_manager; pub mod compiled_class; #[cfg(feature = "document_calls")] pub mod document_calls; -pub mod utils; +pub mod storage_metrics; // TODO(yair): Make the compression_utils module pub(crate) or extract it from the crate. #[doc(hidden)] pub mod compression_utils; @@ -102,6 +104,7 @@ pub mod test_utils; use std::collections::{BTreeMap, HashMap}; use std::fmt::Debug; +use std::fs; use std::sync::Arc; use body::events::EventIndex; @@ -123,12 +126,12 @@ use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; use papyrus_proc_macros::latency_histogram; use serde::{Deserialize, Serialize}; use starknet_api::block::{BlockHash, BlockNumber, BlockSignature, StarknetVersion}; -use starknet_api::core::{ClassHash, ContractAddress, Nonce}; +use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; use starknet_api::deprecated_contract_class::ContractClass as DeprecatedContractClass; use starknet_api::state::{SierraContractClass, StateNumber, StorageKey, ThinStateDiff}; use starknet_api::transaction::{Transaction, TransactionHash, TransactionOutput}; use starknet_types_core::felt::Felt; -use tracing::{debug, warn}; +use tracing::{debug, info, warn}; use validator::Validate; use version::{StorageVersionError, Version}; @@ -150,19 +153,26 @@ use crate::db::{ use crate::header::StorageBlockHeader; use crate::mmap_file::MMapFileStats; use crate::state::data::IndexedDeprecatedContractClass; -pub use crate::utils::update_storage_metrics; use crate::version::{VersionStorageReader, VersionStorageWriter}; // For more details on the storage version, see the module documentation. /// The current version of the storage state code. -pub const STORAGE_VERSION_STATE: Version = Version { major: 3, minor: 0 }; +pub const STORAGE_VERSION_STATE: Version = Version { major: 5, minor: 0 }; /// The current version of the storage blocks code. -pub const STORAGE_VERSION_BLOCKS: Version = Version { major: 3, minor: 0 }; +pub const STORAGE_VERSION_BLOCKS: Version = Version { major: 5, minor: 0 }; /// Opens a storage and returns a [`StorageReader`] and a [`StorageWriter`]. pub fn open_storage( storage_config: StorageConfig, ) -> StorageResult<(StorageReader, StorageWriter)> { + info!("Opening storage: {}", storage_config.db_config.path_prefix.display()); + if !storage_config.db_config.path_prefix.exists() + && !storage_config.db_config.enforce_file_exists + { + fs::create_dir_all(storage_config.db_config.path_prefix.clone())?; + info!("Created storage directory: {}", storage_config.db_config.path_prefix.display()); + } + let (db_reader, mut db_writer) = open_env(&storage_config.db_config)?; let tables = Arc::new(Tables { block_hash_to_number: db_writer.create_simple_table("block_hash_to_number")?, @@ -183,9 +193,13 @@ pub fn open_storage( transaction_hash_to_idx: db_writer.create_simple_table("transaction_hash_to_idx")?, transaction_metadata: db_writer.create_simple_table("transaction_metadata")?, - // Version tables + // Version tables. starknet_version: db_writer.create_simple_table("starknet_version")?, storage_version: db_writer.create_simple_table("storage_version")?, + + // Class hashes. + class_hash_to_executable_class_hash: db_writer + .create_simple_table("class_hash_to_executable_class_hash")?, }); let (file_writers, file_readers) = open_storage_files( &storage_config.db_config, @@ -472,7 +486,7 @@ pub struct StorageTxn<'env, Mode: TransactionKind> { scope: StorageScope, } -impl<'env> StorageTxn<'env, RW> { +impl StorageTxn<'_, RW> { /// Commits the changes made in the transaction to the storage. #[latency_histogram("storage_commit_latency_seconds", false)] pub fn commit(self) -> StorageResult<()> { @@ -481,7 +495,7 @@ impl<'env> StorageTxn<'env, RW> { } } -impl<'env, Mode: TransactionKind> StorageTxn<'env, Mode> { +impl StorageTxn<'_, Mode> { pub(crate) fn open_table( &self, table_id: &TableIdentifier, @@ -533,7 +547,10 @@ struct_field_names! { // Version tables starknet_version: TableIdentifier, SimpleTable>, - storage_version: TableIdentifier, SimpleTable> + storage_version: TableIdentifier, SimpleTable>, + + // Class hashes. + class_hash_to_executable_class_hash: TableIdentifier, SimpleTable> } } @@ -560,7 +577,7 @@ pub(crate) struct TransactionMetadata { tx_output_location: LocationInFile, } -// TODO: sort the variants alphabetically. +// TODO(Yair): sort the variants alphabetically. /// Error type for the storage crate. #[allow(missing_docs)] #[derive(thiserror::Error, Debug)] @@ -658,6 +675,10 @@ pub(crate) enum MarkerKind { Class, CompiledClass, BaseLayerBlock, + ClassManagerBlock, + /// Marks the block beyond the last block that its classes can't be compiled with the current + /// compiler version used in the class manager. Determined by starknet version. + CompilerBackwardCompatibility, } pub(crate) type MarkersTable<'env> = @@ -723,7 +744,7 @@ impl FileHandlers { impl FileHandlers { pub fn stats(&self) -> HashMap { - // TODO: use consts for the file names. + // TODO(Yair): use consts for the file names. HashMap::from_iter([ ("thin_state_diff".to_string(), self.thin_state_diff.stats()), ("contract_class".to_string(), self.contract_class.stats()), diff --git a/crates/papyrus_storage/src/serialization/serializers.rs b/crates/papyrus_storage/src/serialization/serializers.rs index 8daf2510c2b..bcadf530575 100644 --- a/crates/papyrus_storage/src/serialization/serializers.rs +++ b/crates/papyrus_storage/src/serialization/serializers.rs @@ -163,6 +163,8 @@ auto_storage_serde! { pub l1_gas_price: GasPricePerToken, pub l1_data_gas_price: GasPricePerToken, pub l2_gas_price: GasPricePerToken, + pub l2_gas_consumed: u64, + pub next_l2_gas_price: u64, pub state_root: GlobalRoot, pub sequencer: SequencerContractAddress, pub timestamp: BlockTimestamp, @@ -325,6 +327,8 @@ auto_storage_serde! { Class = 4, CompiledClass = 5, BaseLayerBlock = 6, + ClassManagerBlock = 7, + CompilerBackwardCompatibility = 8, } pub struct MessageToL1 { pub to_address: EthAddress, @@ -412,6 +416,8 @@ auto_storage_serde! { V0_13_2_1 = 17, V0_13_3 = 18, V0_13_4 = 19, + V0_13_5 = 20, + V0_14_0 = 21, } pub struct StateDiffCommitment(pub PoseidonHash); pub struct Tip(pub u64); @@ -1101,7 +1107,6 @@ impl StorageSerde for ThinStateDiff { self.declared_classes.serialize_into(&mut to_compress)?; self.deprecated_declared_classes.serialize_into(&mut to_compress)?; self.nonces.serialize_into(&mut to_compress)?; - self.replaced_classes.serialize_into(&mut to_compress)?; if to_compress.len() > crate::compression_utils::MAX_DECOMPRESSED_SIZE { warn!( "ThinStateDiff serialization size is too large and will lead to deserialization \ @@ -1125,7 +1130,6 @@ impl StorageSerde for ThinStateDiff { declared_classes: IndexMap::deserialize_from(data)?, deprecated_declared_classes: Vec::deserialize_from(data)?, nonces: IndexMap::deserialize_from(data)?, - replaced_classes: IndexMap::deserialize_from(data)?, }) } } diff --git a/crates/papyrus_storage/src/state/mod.rs b/crates/papyrus_storage/src/state/mod.rs index 023df4fe5b3..41896f68c21 100644 --- a/crates/papyrus_storage/src/state/mod.rs +++ b/crates/papyrus_storage/src/state/mod.rs @@ -123,7 +123,6 @@ pub(crate) type NoncesTable<'env> = // block_num. // * nonces_table: (contract_address, block_num) -> (nonce). Specifies that at `block_num`, the // nonce of `contract_address` was changed to `nonce`. - pub trait StateStorageReader { /// The state marker is the first block number that doesn't exist yet. fn get_state_marker(&self) -> StorageResult; @@ -159,7 +158,7 @@ where ) -> StorageResult<(Self, Option)>; } -impl<'env, Mode: TransactionKind> StateStorageReader for StorageTxn<'env, Mode> { +impl StateStorageReader for StorageTxn<'_, Mode> { // The block number marker is the first block number that doesn't exist yet. fn get_state_marker(&self) -> StorageResult { let markers_table = self.open_table(&self.tables.markers)?; @@ -278,25 +277,8 @@ impl<'env, Mode: TransactionKind> StateReader<'env, Mode> { add_query(StorageQuery::GetNonceAt(state_number, *address)); // State diff updates are indexed by the block_number at which they occurred. - let first_irrelevant_block: BlockNumber = state_number.block_after(); - // The relevant update is the last update strictly before `first_irrelevant_block`. - let db_key = (*address, first_irrelevant_block); - // Find the previous db item. - let mut cursor = self.nonces_table.cursor(self.txn)?; - cursor.lower_bound(&db_key)?; - let res = cursor.prev()?; - match res { - None => Ok(None), - Some(((got_address, _got_block_number), value)) => { - if got_address != *address { - // The previous item belongs to different address, which means there is no - // previous state diff for this item. - return Ok(None); - }; - // The previous db item indeed belongs to this address and key. - Ok(Some(value)) - } - } + let block_number: BlockNumber = state_number.block_after(); + get_nonce_at(block_number, address, self.txn, &self.nonces_table) } /// Returns the storage value at a given state number for a given contract and key. @@ -425,7 +407,7 @@ impl<'env, Mode: TransactionKind> StateReader<'env, Mode> { } } -impl<'env> StateStorageWriter for StorageTxn<'env, RW> { +impl StateStorageWriter for StorageTxn<'_, RW> { #[latency_histogram("storage_append_thin_state_diff_latency_seconds", false)] fn append_state_diff( self, @@ -447,7 +429,6 @@ impl<'env> StateStorageWriter for StorageTxn<'env, RW> { block_number, &deployed_contracts_table, &nonces_table, - &thin_state_diff.nonces, )?; write_storage_diffs( &thin_state_diff.storage_diffs, @@ -455,13 +436,8 @@ impl<'env> StateStorageWriter for StorageTxn<'env, RW> { block_number, &storage_table, )?; + // Must be called after write_deployed_contracts since the nonces are updated there. write_nonces(&thin_state_diff.nonces, &self.txn, block_number, &nonces_table)?; - write_replaced_classes( - &thin_state_diff.replaced_classes, - &self.txn, - block_number, - &deployed_contracts_table, - )?; // We don't store the deprecated declared classes' block number. for (class_hash, _) in &thin_state_diff.declared_classes { @@ -560,12 +536,6 @@ impl<'env> StateStorageWriter for StorageTxn<'env, RW> { delete_storage_diffs(&self.txn, block_number, &thin_state_diff, &storage_table)?; delete_nonces(&self.txn, block_number, &thin_state_diff, &nonces_table)?; state_diffs_table.delete(&self.txn, &block_number)?; - delete_replaced_classes( - &self.txn, - block_number, - &thin_state_diff, - &deployed_contracts_table, - )?; Ok(( self, @@ -639,16 +609,14 @@ fn write_deployed_contracts<'env>( block_number: BlockNumber, deployed_contracts_table: &'env DeployedContractsTable<'env>, nonces_table: &'env NoncesTable<'env>, - nonces_diffs: &IndexMap, ) -> StorageResult<()> { for (address, class_hash) in deployed_contracts { deployed_contracts_table.insert(txn, &(*address, block_number), class_hash)?; - // In old blocks, there is no nonce diff, so we must add the default value if the diff is - // not specified. - // TODO: check what happens in case of a contract that was deployed and its nonce is still - // zero (does it in the nonce diff?). - if !nonces_diffs.contains_key(address) { + // In old blocks, there is no nonce diff, so we must add the default value for newly + // deployed contracts. Replaced classes will already have a nonce and thus won't enter this + // condition. + if get_nonce_at(block_number, address, txn, nonces_table)?.is_none() { nonces_table.append_greater_sub_key( txn, &(*address, block_number), @@ -672,19 +640,6 @@ fn write_nonces<'env>( Ok(()) } -#[latency_histogram("storage_write_replaced_classes_latency_seconds", true)] -fn write_replaced_classes<'env>( - replaced_classes: &IndexMap, - txn: &DbTransaction<'env, RW>, - block_number: BlockNumber, - deployed_contracts_table: &'env DeployedContractsTable<'env>, -) -> StorageResult<()> { - for (contract_address, class_hash) in replaced_classes { - deployed_contracts_table.insert(txn, &(*contract_address, block_number), class_hash)?; - } - Ok(()) -} - #[latency_histogram("storage_write_storage_diffs_latency_seconds", false)] fn write_storage_diffs<'env>( storage_diffs: &IndexMap>, @@ -795,7 +750,11 @@ fn delete_deployed_contracts<'env>( ) -> StorageResult<()> { for contract_address in thin_state_diff.deployed_contracts.keys() { deployed_contracts_table.delete(txn, &(*contract_address, block_number))?; - nonces_table.delete(txn, &(*contract_address, block_number))?; + // Delete the nonce if the contract was deployed in this block (i.e didn't have a nonce in + // the previous block). + if get_nonce_at(block_number, contract_address, txn, nonces_table)?.is_none() { + nonces_table.delete(txn, &(*contract_address, block_number))?; + } } Ok(()) } @@ -828,14 +787,28 @@ fn delete_nonces<'env>( Ok(()) } -fn delete_replaced_classes<'env>( - txn: &'env DbTransaction<'env, RW>, - block_number: BlockNumber, - thin_state_diff: &ThinStateDiff, - deployed_contracts_table: &'env DeployedContractsTable<'env>, -) -> StorageResult<()> { - for contract_address in thin_state_diff.replaced_classes.keys() { - deployed_contracts_table.delete(txn, &(*contract_address, block_number))?; +fn get_nonce_at<'env, Mode: TransactionKind>( + first_irrelevant_block: BlockNumber, + address: &ContractAddress, + txn: &'env DbTransaction<'env, Mode>, + nonces_table: &'env NoncesTable<'env>, +) -> StorageResult> { + // The relevant update is the last update strictly before `first_irrelevant_block`. + let db_key = (*address, first_irrelevant_block); + // Find the previous db item. + let mut cursor = nonces_table.cursor(txn)?; + cursor.lower_bound(&db_key)?; + let res = cursor.prev()?; + match res { + None => Ok(None), + Some(((got_address, _got_block_number), value)) => { + if got_address != *address { + // The previous item belongs to different address, which means there is no + // previous state diff for this item. + return Ok(None); + }; + // The previous db item indeed belongs to this address and key. + Ok(Some(value)) + } } - Ok(()) } diff --git a/crates/papyrus_storage/src/state/state_test.rs b/crates/papyrus_storage/src/state/state_test.rs index 3f82f82f0ff..c1ae6e23975 100644 --- a/crates/papyrus_storage/src/state/state_test.rs +++ b/crates/papyrus_storage/src/state/state_test.rs @@ -106,14 +106,14 @@ fn append_state_diff_replaced_classes() { }; // Replacements between different class types (cairo0 and cairo1). let diff1 = ThinStateDiff { - replaced_classes: IndexMap::from([(contract_0, hash_1), (contract_1, hash_0)]), + deployed_contracts: IndexMap::from([(contract_0, hash_1), (contract_1, hash_0)]), ..Default::default() }; // Replace to class that was declared in the same block. let hash_2 = class_hash!("0x12"); let diff2 = ThinStateDiff { declared_classes: IndexMap::from([(hash_2, compiled_class_hash)]), - replaced_classes: IndexMap::from([(contract_1, hash_2)]), + deployed_contracts: IndexMap::from([(contract_1, hash_2)]), ..Default::default() }; @@ -166,10 +166,9 @@ fn append_state_diff() { deprecated_declared_classes: vec![cl0], declared_classes: IndexMap::from([(cl1, c_cls)]), nonces: IndexMap::from([(c0, Nonce(StarkHash::from(1_u8)))]), - replaced_classes: indexmap! {}, }; let diff1 = ThinStateDiff { - deployed_contracts: IndexMap::from([(c2, cl0)]), + deployed_contracts: IndexMap::from([(c2, cl0), (c0, cl1)]), storage_diffs: IndexMap::from([ (c0, IndexMap::from([(key0, felt!("0x300")), (key1, felt!("0x0"))])), (c1, IndexMap::from([(key0, felt!("0x0"))])), @@ -181,7 +180,6 @@ fn append_state_diff() { (c1, Nonce(StarkHash::from(1_u8))), (c2, Nonce(StarkHash::from(1_u8))), ]), - replaced_classes: IndexMap::from([(c0, cl1)]), }; let ((_, mut writer), _temp_dir) = get_test_storage(); @@ -383,7 +381,6 @@ fn revert_doesnt_delete_previously_declared_classes() { deprecated_declared_classes: vec![cl0], declared_classes: indexmap! {}, nonces: IndexMap::from([(c0, Nonce(StarkHash::from(1_u8)))]), - replaced_classes: indexmap! {}, }; let c1 = contract_address!("0x12"); @@ -393,7 +390,6 @@ fn revert_doesnt_delete_previously_declared_classes() { deprecated_declared_classes: vec![cl0], declared_classes: indexmap! {}, nonces: IndexMap::from([(c1, Nonce(StarkHash::from(2_u8)))]), - replaced_classes: indexmap! {}, }; let ((reader, mut writer), _temp_dir) = get_test_storage(); @@ -444,10 +440,12 @@ fn revert_doesnt_delete_previously_declared_classes() { #[test] fn revert_state() { - let (state_diff0, classes0, deprecated_classes0) = + let (mut state_diff0, classes0, deprecated_classes0) = ThinStateDiff::from_state_diff(get_test_state_diff()); let (contract0, class0) = state_diff0.deployed_contracts.first().unwrap(); - let (_contract0, nonce0) = state_diff0.nonces.first().unwrap(); + // Change nonce to non-zero value to make sure it isn't overwritten when replacing the class. + let nonce0 = Nonce(Felt::from(7_u8)); + state_diff0.nonces = IndexMap::from([(*contract0, nonce0)]); // Create another state diff, deploying new contracts and changing the state and the class hash // of the contract deployed in state0. @@ -469,12 +467,15 @@ fn revert_state() { let updated_storage = IndexMap::from([(updated_storage_key, new_data)]); let nonce1 = Nonce(Felt::from(111_u8)); let state_diff1 = ThinStateDiff { - deployed_contracts: IndexMap::from([(contract1, class1), (contract2, class2)]), + deployed_contracts: IndexMap::from([ + (contract1, class1), + (contract2, class2), + (*contract0, class1), + ]), storage_diffs: IndexMap::from([(*contract0, updated_storage)]), deprecated_declared_classes: vec![class1], declared_classes: IndexMap::from([(class2, CompiledClassHash::default())]), nonces: IndexMap::from([(contract1, nonce1)]), - replaced_classes: IndexMap::from([(*contract0, class1)]), }; let ((reader, mut writer), _temp_dir) = get_test_storage(); @@ -514,7 +515,7 @@ fn revert_state() { assert_eq!(state_reader.get_class_hash_at(state_number, contract0).unwrap().unwrap(), class1); assert_eq!(state_reader.get_class_hash_at(state_number, &contract1).unwrap().unwrap(), class1); assert_eq!(state_reader.get_class_hash_at(state_number, &contract2).unwrap().unwrap(), class2); - assert_eq!(state_reader.get_nonce_at(state_number, contract0).unwrap().unwrap(), *nonce0); + assert_eq!(state_reader.get_nonce_at(state_number, contract0).unwrap().unwrap(), nonce0); assert_eq!(state_reader.get_nonce_at(state_number, &contract1).unwrap().unwrap(), nonce1); assert_eq!( state_reader.get_storage_at(state_number, contract0, &updated_storage_key).unwrap(), @@ -559,8 +560,9 @@ fn revert_state() { assert_eq!(state_reader.get_class_hash_at(state_number, contract0).unwrap().unwrap(), *class0); assert!(state_reader.get_class_hash_at(state_number, &contract1).unwrap().is_none()); assert!(state_reader.get_class_hash_at(state_number, &contract2).unwrap().is_none()); - assert_eq!(state_reader.get_nonce_at(state_number, contract0).unwrap().unwrap(), *nonce0); + assert_eq!(state_reader.get_nonce_at(state_number, contract0).unwrap().unwrap(), nonce0); assert!(state_reader.get_nonce_at(state_number, &contract1).unwrap().is_none()); + assert!(state_reader.get_nonce_at(state_number, &contract2).unwrap().is_none()); assert_eq!( state_reader.get_storage_at(state_number, contract0, &updated_storage_key).unwrap(), Felt::ZERO @@ -583,7 +585,6 @@ fn get_nonce_key_serialization() { contract_address, Nonce(StarkHash::from(u128::from(block_number) + 1)), )]), - replaced_classes: IndexMap::new(), }; writer @@ -634,7 +635,6 @@ fn replace_class() { declared_classes: IndexMap::new(), deprecated_declared_classes: vec![class_hash0], nonces: IndexMap::new(), - replaced_classes: IndexMap::new(), }; writer .begin_rw_txn() @@ -658,16 +658,15 @@ fn replace_class() { let class_hash1 = class_hash!("0x1"); let state_diff2 = ThinStateDiff { - deployed_contracts: IndexMap::new(), + deployed_contracts: indexmap! { + contract_address => class_hash1, + }, storage_diffs: IndexMap::new(), declared_classes: indexmap! { class_hash1 => CompiledClassHash::default(), }, deprecated_declared_classes: Vec::new(), nonces: IndexMap::new(), - replaced_classes: indexmap! { - contract_address => class_hash1, - }, }; writer .begin_rw_txn() @@ -719,7 +718,6 @@ fn declare_revert_declare_scenario() { deprecated_declared_classes: vec![deprecated_class_hash], declared_classes: IndexMap::from([(class_hash, compiled_class_hash)]), nonces: IndexMap::from([(contract_address, Nonce(StarkHash::from(1_u8)))]), - replaced_classes: indexmap! {}, }; let ((reader, mut writer), _temp_dir) = get_test_storage(); diff --git a/crates/papyrus_storage/src/storage_metrics.rs b/crates/papyrus_storage/src/storage_metrics.rs new file mode 100644 index 00000000000..82b0ab02104 --- /dev/null +++ b/crates/papyrus_storage/src/storage_metrics.rs @@ -0,0 +1,27 @@ +//! module for metrics utilities. +#[cfg(test)] +#[path = "storage_metrics_test.rs"] +mod storage_metrics_test; + +use metrics::{counter, gauge}; +use tracing::debug; + +use crate::{StorageReader, StorageResult}; + +// TODO(dvir): add storage metrics names to this module. + +// TODO(dvir): consider adding storage size metrics. +// TODO(dvir): relocate all the storage metrics in one module and export them (also in other +// crates). +/// Updates storage metrics about the state of the storage. +#[allow(clippy::as_conversions)] +pub fn update_storage_metrics(reader: &StorageReader) -> StorageResult<()> { + debug!("updating storage metrics"); + gauge!("storage_free_pages_number").set(reader.db_reader.get_free_pages()? as f64); + let info = reader.db_reader.get_db_info()?; + counter!("storage_last_page_number") + .absolute(u64::try_from(info.last_pgno()).expect("usize should fit in u64")); + counter!("storage_last_transaction_index") + .absolute(u64::try_from(info.last_txnid()).expect("usize should fit in u64")); + Ok(()) +} diff --git a/crates/papyrus_storage/src/storage_metrics_test.rs b/crates/papyrus_storage/src/storage_metrics_test.rs new file mode 100644 index 00000000000..323d1947467 --- /dev/null +++ b/crates/papyrus_storage/src/storage_metrics_test.rs @@ -0,0 +1,44 @@ +use metrics_exporter_prometheus::PrometheusBuilder; +use papyrus_test_utils::prometheus_is_contained; +use prometheus_parse::Value::{Counter, Gauge}; + +use super::update_storage_metrics; +use crate::test_utils::get_test_storage; + +#[test] +fn update_storage_metrics_test() { + let ((reader, _writer), _temp_dir) = get_test_storage(); + let handle = PrometheusBuilder::new().install_recorder().unwrap(); + + assert!(prometheus_is_contained(handle.render(), "storage_free_pages_number", &[]).is_none()); + assert!(prometheus_is_contained(handle.render(), "storage_last_page_number", &[]).is_none()); + assert!( + prometheus_is_contained(handle.render(), "storage_last_transaction_index", &[]).is_none() + ); + + update_storage_metrics(&reader).unwrap(); + + let Gauge(free_pages) = + prometheus_is_contained(handle.render(), "storage_free_pages_number", &[]).unwrap() + else { + panic!("storage_free_pages_number is not a Gauge") + }; + // TODO(dvir): add an upper limit when the bug in the binding freelist function will be fixed. + assert!(0f64 < free_pages); + + let Counter(last_page) = + prometheus_is_contained(handle.render(), "storage_last_page_number", &[]).unwrap() + else { + panic!("storage_last_page_number is not a Counter") + }; + assert!(0f64 < last_page); + assert!(last_page < 1000f64); + + let Counter(last_transaction) = + prometheus_is_contained(handle.render(), "storage_last_transaction_index", &[]).unwrap() + else { + panic!("storage_last_transaction_index is not a Counter") + }; + assert!(0f64 < last_transaction); + assert!(last_transaction < 100f64); +} diff --git a/crates/papyrus_storage/src/test_instances.rs b/crates/papyrus_storage/src/test_instances.rs index 583ce74f92d..389fff1fef3 100644 --- a/crates/papyrus_storage/src/test_instances.rs +++ b/crates/papyrus_storage/src/test_instances.rs @@ -31,6 +31,8 @@ auto_impl_get_test_instance! { pub l1_gas_price: GasPricePerToken, pub l1_data_gas_price: GasPricePerToken, pub l2_gas_price: GasPricePerToken, + pub l2_gas_consumed: u64, + pub next_l2_gas_price: u64, pub state_root: GlobalRoot, pub sequencer: SequencerContractAddress, pub timestamp: BlockTimestamp, @@ -61,6 +63,8 @@ auto_impl_get_test_instance! { Class = 4, CompiledClass = 5, BaseLayerBlock = 6, + ClassManagerBlock = 7, + CompilerBackwardCompatibility = 8, } pub enum OffsetKind { ThinStateDiff = 0, diff --git a/crates/papyrus_storage/src/test_utils.rs b/crates/papyrus_storage/src/test_utils.rs index 1ea60bed928..27c0f54953f 100644 --- a/crates/papyrus_storage/src/test_utils.rs +++ b/crates/papyrus_storage/src/test_utils.rs @@ -1,18 +1,31 @@ #![allow(clippy::unwrap_used)] //! Test utilities for the storage crate users. -use std::sync::LazyLock; +use std::fs::create_dir_all; +use std::path::PathBuf; use starknet_api::core::ChainId; +use starknet_api::test_utils::CHAIN_ID_FOR_TESTS; use tempfile::{tempdir, TempDir}; use crate::db::DbConfig; use crate::mmap_file::MmapFileConfig; use crate::{open_storage, StorageConfig, StorageReader, StorageScope, StorageWriter}; -/// A chain id for tests. -pub static CHAIN_ID_FOR_TESTS: LazyLock = - LazyLock::new(|| ChainId::Other("CHAIN_ID_SUBDIR".to_owned())); +fn build_storage_config(storage_scope: StorageScope, path_prefix: PathBuf) -> StorageConfig { + StorageConfig { + db_config: DbConfig { + path_prefix, + chain_id: CHAIN_ID_FOR_TESTS.clone(), + enforce_file_exists: false, + min_size: 1 << 20, // 1MB + max_size: 1 << 35, // 32GB + growth_step: 1 << 26, // 64MB + }, + scope: storage_scope, + mmap_file_config: get_mmap_file_test_config(), + } +} /// Returns a db config and the temporary directory that holds this db. /// The TempDir object is returned as a handler for the lifetime of this object (the temp @@ -21,23 +34,23 @@ pub static CHAIN_ID_FOR_TESTS: LazyLock = /// is deleted. pub(crate) fn get_test_config(storage_scope: Option) -> (StorageConfig, TempDir) { let storage_scope = storage_scope.unwrap_or_default(); - let dir = tempdir().unwrap(); - println!("{dir:?}"); - ( - StorageConfig { - db_config: DbConfig { - path_prefix: dir.path().to_path_buf(), - chain_id: CHAIN_ID_FOR_TESTS.clone(), - enforce_file_exists: false, - min_size: 1 << 20, // 1MB - max_size: 1 << 35, // 32GB - growth_step: 1 << 26, // 64MB - }, - scope: storage_scope, - mmap_file_config: get_mmap_file_test_config(), - }, - dir, - ) + let temp_dir = tempdir().expect("Failed to create temp directory"); + + (build_storage_config(storage_scope, temp_dir.path().to_path_buf()), temp_dir) +} + +/// Returns a db config for a given path. +/// This function ensures that the specified directory exists by creating it if necessary. +/// Unlike get_test_config, this function does not return a TempDir object, so the caller is +/// responsible for managing the directory's lifecycle and cleanup. +pub(crate) fn get_test_config_with_path( + storage_scope: Option, + path: PathBuf, +) -> StorageConfig { + let storage_scope = storage_scope.unwrap_or_default(); + create_dir_all(&path).expect("Failed to create directory"); + + build_storage_config(storage_scope, path) } /// Returns [`StorageReader`], [`StorageWriter`] and the temporary directory that holds a db for @@ -84,7 +97,7 @@ pub fn get_test_storage_with_config_by_scope( /// A tool for creating a test storage. pub struct TestStorageBuilder { config: StorageConfig, - handle: TempDir, + handle: Option, } impl TestStorageBuilder { @@ -104,15 +117,22 @@ impl TestStorageBuilder { /// that were built, and the temporary directory that holds a db for testing purposes. The /// returned [`StorageConfig`] can be used to open the exact same storage again (same DB /// file). - pub fn build(self) -> ((StorageReader, StorageWriter), StorageConfig, TempDir) { + pub fn build(self) -> ((StorageReader, StorageWriter), StorageConfig, Option) { let (reader, writer) = open_storage(self.config.clone()).unwrap(); ((reader, writer), self.config, self.handle) } -} -impl Default for TestStorageBuilder { - fn default() -> Self { - let (config, handle) = get_test_config(None); - Self { config, handle } + /// Creates a TestStorageBuilder with a path to the directory that holds a db for testing. + pub fn new(path: Option) -> Self { + match path { + Some(path) => { + let config = get_test_config_with_path(None, path); + Self { config, handle: None } + } + None => { + let (config, handle) = get_test_config(None); + Self { config, handle: Some(handle) } + } + } } } diff --git a/crates/papyrus_storage/src/utils.rs b/crates/papyrus_storage/src/utils.rs deleted file mode 100644 index 157c7cbb7b1..00000000000 --- a/crates/papyrus_storage/src/utils.rs +++ /dev/null @@ -1,110 +0,0 @@ -//! module for external utils, such as dumping a storage table to a file -#[cfg(test)] -#[path = "utils_test.rs"] -mod utils_test; - -use std::fs::File; -use std::io::{BufWriter, Write}; - -use metrics::{absolute_counter, gauge}; -use serde::Serialize; -use starknet_api::block::BlockNumber; -use starknet_api::core::{ChainId, ClassHash, CompiledClassHash}; -use starknet_api::rpc_transaction::EntryPointByType; -use starknet_types_core::felt::Felt; -use tracing::debug; - -use crate::compiled_class::CasmStorageReader; -use crate::db::table_types::Table; -use crate::db::RO; -use crate::state::StateStorageReader; -use crate::{open_storage, StorageConfig, StorageError, StorageReader, StorageResult, StorageTxn}; - -#[derive(Serialize)] -struct DumpDeclaredClass { - class_hash: ClassHash, - compiled_class_hash: CompiledClassHash, - sierra_program: Vec, - contract_class_version: String, - entry_points_by_type: EntryPointByType, -} - -/// Dumps the declared_classes at a given block range from the storage to a file. -pub fn dump_declared_classes_table_by_block_range( - start_block: u64, - end_block: u64, - file_path: &str, - chain_id: &ChainId, -) -> StorageResult<()> { - let mut storage_config = StorageConfig::default(); - storage_config.db_config.chain_id = chain_id.clone(); - let (storage_reader, _) = open_storage(storage_config)?; - let txn = storage_reader.begin_ro_txn()?; - let compiled_class_marker = txn.get_compiled_class_marker()?; - if end_block > compiled_class_marker.0 { - return Err(StorageError::InvalidBlockNumber { - block: BlockNumber(end_block), - compiled_class_marker, - }); - } - dump_declared_classes_table_by_block_range_internal(&txn, file_path, start_block, end_block) -} - -fn dump_declared_classes_table_by_block_range_internal( - txn: &StorageTxn<'_, RO>, - file_path: &str, - start_block: u64, - end_block: u64, -) -> StorageResult<()> { - let table_handle = txn.txn.open_table(&txn.tables.declared_classes)?; - let file = File::create(file_path)?; - let mut writer = BufWriter::new(file); - writer.write_all(b"[")?; - let mut first = true; - for block_number in start_block..end_block { - if let Some(thin_state_diff) = txn.get_state_diff(BlockNumber(block_number))? { - for (class_hash, compiled_class_hash) in thin_state_diff.declared_classes.iter() { - if let Some(contract_class_location) = table_handle.get(&txn.txn, class_hash)? { - let contract_class = - txn.file_handlers.get_contract_class_unchecked(contract_class_location)?; - if !first { - writer.write_all(b",")?; - } - serde_json::to_writer( - &mut writer, - &DumpDeclaredClass { - class_hash: *class_hash, - compiled_class_hash: *compiled_class_hash, - sierra_program: contract_class.sierra_program.clone(), - contract_class_version: contract_class.contract_class_version.clone(), - entry_points_by_type: contract_class.entry_points_by_type.clone(), - }, - )?; - first = false; - } - } - }; - } - writer.write_all(b"]")?; - Ok(()) -} - -// TODO(dvir): consider adding storage size metrics. -// TODO(dvir): relocate all the storage metrics in one module and export them (also in other -// crates). -/// Updates storage metrics about the state of the storage. -#[allow(clippy::as_conversions)] -pub fn update_storage_metrics(reader: &StorageReader) -> StorageResult<()> { - debug!("updating storage metrics"); - gauge!("storage_free_pages_number", reader.db_reader.get_free_pages()? as f64); - let info = reader.db_reader.get_db_info()?; - absolute_counter!( - "storage_last_page_number", - u64::try_from(info.last_pgno()).expect("usize should fit in u64") - ); - absolute_counter!( - "storage_last_transaction_index", - u64::try_from(info.last_txnid()).expect("usize should fit in u64") - ); - Ok(()) -} diff --git a/crates/papyrus_storage/src/utils_test.rs b/crates/papyrus_storage/src/utils_test.rs deleted file mode 100644 index 8f69a6570bb..00000000000 --- a/crates/papyrus_storage/src/utils_test.rs +++ /dev/null @@ -1,120 +0,0 @@ -use std::fs; - -use indexmap::indexmap; -use metrics_exporter_prometheus::PrometheusBuilder; -use papyrus_test_utils::prometheus_is_contained; -use pretty_assertions::assert_eq; -use prometheus_parse::Value::{Counter, Gauge}; -use starknet_api::block::BlockNumber; -use starknet_api::core::{ClassHash, CompiledClassHash}; -use starknet_api::hash::StarkHash; -use starknet_api::rpc_transaction::EntryPointByType; -use starknet_api::state::{SierraContractClass, ThinStateDiff}; -use starknet_types_core::felt::Felt; - -use super::update_storage_metrics; -use crate::class::ClassStorageWriter; -use crate::state::StateStorageWriter; -use crate::test_utils::get_test_storage; -use crate::utils::{dump_declared_classes_table_by_block_range_internal, DumpDeclaredClass}; - -// TODO(yael): fix dump_table_to_file. -#[test] -fn test_dump_declared_classes() { - let file_path = "tmp_test_dump_declared_classes_table.json"; - let compiled_class_hash = CompiledClassHash(StarkHash::default()); - let mut declared_classes = vec![]; - let mut state_diffs = vec![]; - let ((reader, mut writer), _temp_dir) = get_test_storage(); - for i in 0..5 { - let i_felt = Felt::from(u128::try_from(i).expect("usize should fit in u128")); - declared_classes.push(( - ClassHash(i_felt), - SierraContractClass { - sierra_program: vec![i_felt, i_felt], - contract_class_version: "0.1.0".to_string(), - entry_points_by_type: EntryPointByType::default(), - abi: "".to_string(), - }, - )); - state_diffs.push(ThinStateDiff { - deployed_contracts: indexmap!(), - storage_diffs: indexmap!(), - declared_classes: indexmap!( - declared_classes[i].0 => compiled_class_hash - ), - deprecated_declared_classes: vec![], - nonces: indexmap!(), - replaced_classes: indexmap!(), - }); - let block_number = BlockNumber(u64::try_from(i).expect("usize should fit in u64")); - let txn = writer.begin_rw_txn().unwrap(); - txn.append_state_diff(block_number, state_diffs[i].clone()) - .unwrap() - .append_classes(block_number, &[(declared_classes[i].0, &declared_classes[i].1)], &[]) - .unwrap() - .commit() - .unwrap(); - } - let txn = reader.begin_ro_txn().unwrap(); - - // Test dump_declared_classes_table_by_block_range - dump_declared_classes_table_by_block_range_internal(&txn, file_path, 2, 4).unwrap(); - let file_content = fs::read_to_string(file_path).unwrap(); - let _ = fs::remove_file(file_path); - let expected_declared_classes = vec![ - DumpDeclaredClass { - class_hash: declared_classes[2].0, - compiled_class_hash, - sierra_program: declared_classes[2].1.sierra_program.clone(), - contract_class_version: declared_classes[2].1.contract_class_version.clone(), - entry_points_by_type: declared_classes[2].1.entry_points_by_type.clone(), - }, - DumpDeclaredClass { - class_hash: declared_classes[3].0, - compiled_class_hash, - sierra_program: declared_classes[3].1.sierra_program.clone(), - contract_class_version: declared_classes[3].1.contract_class_version.clone(), - entry_points_by_type: declared_classes[3].1.entry_points_by_type.clone(), - }, - ]; - assert_eq!(file_content, serde_json::to_string(&expected_declared_classes).unwrap()); -} - -#[test] -fn update_storage_metrics_test() { - let ((reader, _writer), _temp_dir) = get_test_storage(); - let handle = PrometheusBuilder::new().install_recorder().unwrap(); - - assert!(prometheus_is_contained(handle.render(), "storage_free_pages_number", &[]).is_none()); - assert!(prometheus_is_contained(handle.render(), "storage_last_page_number", &[]).is_none()); - assert!( - prometheus_is_contained(handle.render(), "storage_last_transaction_index", &[]).is_none() - ); - - update_storage_metrics(&reader).unwrap(); - - let Gauge(free_pages) = - prometheus_is_contained(handle.render(), "storage_free_pages_number", &[]).unwrap() - else { - panic!("storage_free_pages_number is not a Gauge") - }; - // TODO(dvir): add an upper limit when the bug in the binding freelist function will be fixed. - assert!(0f64 < free_pages); - - let Counter(last_page) = - prometheus_is_contained(handle.render(), "storage_last_page_number", &[]).unwrap() - else { - panic!("storage_last_page_number is not a Counter") - }; - assert!(0f64 < last_page); - assert!(last_page < 1000f64); - - let Counter(last_transaction) = - prometheus_is_contained(handle.render(), "storage_last_transaction_index", &[]).unwrap() - else { - panic!("storage_last_transaction_index is not a Counter") - }; - assert!(0f64 < last_transaction); - assert!(last_transaction < 100f64); -} diff --git a/crates/papyrus_storage/src/version.rs b/crates/papyrus_storage/src/version.rs index 8b3fafb2bd7..d70a45741ad 100644 --- a/crates/papyrus_storage/src/version.rs +++ b/crates/papyrus_storage/src/version.rs @@ -56,7 +56,7 @@ where fn delete_blocks_version(self) -> StorageResult; } -impl<'env, Mode: TransactionKind> VersionStorageReader for StorageTxn<'env, Mode> { +impl VersionStorageReader for StorageTxn<'_, Mode> { fn get_state_version(&self) -> StorageResult> { let version_table = self.open_table(&self.tables.storage_version)?; Ok(version_table.get(&self.txn, &VERSION_STATE_KEY.to_string())?) @@ -68,7 +68,7 @@ impl<'env, Mode: TransactionKind> VersionStorageReader for StorageTxn<'env, Mode } } -impl<'env> VersionStorageWriter for StorageTxn<'env, RW> { +impl VersionStorageWriter for StorageTxn<'_, RW> { fn set_state_version(self, version: &Version) -> StorageResult { let version_table = self.open_table(&self.tables.storage_version)?; if let Some(current_storage_version) = self.get_state_version()? { diff --git a/crates/papyrus_storage/src/version_test.rs b/crates/papyrus_storage/src/version_test.rs index 8a0b64d1ae5..164a8ac8bda 100644 --- a/crates/papyrus_storage/src/version_test.rs +++ b/crates/papyrus_storage/src/version_test.rs @@ -27,7 +27,7 @@ use crate::{ STORAGE_VERSION_STATE, }; -// TODO: Add this test for set_blocks_version or combine the logic. +// TODO(Dvir): Add this test for set_blocks_version or combine the logic. #[test] fn set_state_version_test() { let ((reader, mut writer), _temp_dir) = get_test_storage(); diff --git a/crates/papyrus_sync/Cargo.toml b/crates/papyrus_sync/Cargo.toml index 50ee6603f54..bea965e4131 100644 --- a/crates/papyrus_sync/Cargo.toml +++ b/crates/papyrus_sync/Cargo.toml @@ -5,6 +5,9 @@ edition.workspace = true repository.workspace = true license-file.workspace = true +[features] +testing = [] + [dependencies] async-stream.workspace = true async-trait.workspace = true @@ -25,7 +28,9 @@ reqwest = { workspace = true, features = ["blocking", "json"] } serde = { workspace = true, features = ["derive"] } starknet-types-core.workspace = true starknet_api.workspace = true +starknet_class_manager_types.workspace = true starknet_client.workspace = true +starknet_sequencer_metrics.workspace = true thiserror.workspace = true tokio = { workspace = true, features = ["full", "sync"] } tracing.workspace = true @@ -38,8 +43,13 @@ papyrus_test_utils.workspace = true pretty_assertions.workspace = true simple_logger.workspace = true starknet_api = { workspace = true, features = ["testing"] } +starknet_class_manager_types = { workspace = true, features = ["testing"] } starknet_client = { workspace = true, features = ["testing"] } tokio-stream.workspace = true +[package.metadata.cargo-machete] +# `metrics` is used in `latency_histogram` but is falsely detected as unused. +ignored = ["metrics"] + [lints] workspace = true diff --git a/crates/papyrus_sync/src/lib.rs b/crates/papyrus_sync/src/lib.rs index b1e1f4165c5..33294862776 100644 --- a/crates/papyrus_sync/src/lib.rs +++ b/crates/papyrus_sync/src/lib.rs @@ -2,11 +2,11 @@ // within this crate #![cfg_attr(coverage_nightly, feature(coverage_attribute))] -#[cfg(test)] -mod sync_test; - +pub mod metrics; mod pending_sync; pub mod sources; +#[cfg(test)] +mod sync_test; use std::cmp::min; use std::collections::BTreeMap; @@ -16,9 +16,10 @@ use std::time::Duration; use async_stream::try_stream; use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass; use chrono::{TimeZone, Utc}; +use futures::future::pending; +use futures::stream; use futures_util::{pin_mut, select, Stream, StreamExt}; use indexmap::IndexMap; -use papyrus_common::metrics as papyrus_metrics; use papyrus_common::pending_classes::PendingClasses; use papyrus_config::converters::deserialize_seconds_to_duration; use papyrus_config::dumping::{ser_param, SerializeConfig}; @@ -26,7 +27,8 @@ use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; use papyrus_proc_macros::latency_histogram; use papyrus_storage::base_layer::{BaseLayerStorageReader, BaseLayerStorageWriter}; use papyrus_storage::body::BodyStorageWriter; -use papyrus_storage::class::ClassStorageWriter; +use papyrus_storage::class::{ClassStorageReader, ClassStorageWriter}; +use papyrus_storage::class_manager::{ClassManagerStorageReader, ClassManagerStorageWriter}; use papyrus_storage::compiled_class::{CasmStorageReader, CasmStorageWriter}; use papyrus_storage::db::DbError; use papyrus_storage::header::{HeaderStorageReader, HeaderStorageWriter}; @@ -34,14 +36,34 @@ use papyrus_storage::state::{StateStorageReader, StateStorageWriter}; use papyrus_storage::{StorageError, StorageReader, StorageWriter}; use serde::{Deserialize, Serialize}; use sources::base_layer::BaseLayerSourceError; -use starknet_api::block::{Block, BlockHash, BlockHashAndNumber, BlockNumber, BlockSignature}; +use starknet_api::block::{ + Block, + BlockHash, + BlockHashAndNumber, + BlockNumber, + BlockSignature, + StarknetVersion, +}; +use starknet_api::contract_class::{ContractClass, SierraVersion}; use starknet_api::core::{ClassHash, CompiledClassHash, SequencerPublicKey}; use starknet_api::deprecated_contract_class::ContractClass as DeprecatedContractClass; use starknet_api::state::{StateDiff, ThinStateDiff}; +use starknet_class_manager_types::{ClassManagerClientError, SharedClassManagerClient}; use starknet_client::reader::PendingData; -use tokio::sync::RwLock; +use tokio::sync::{Mutex, RwLock}; +use tokio::task::{spawn_blocking, JoinError}; use tracing::{debug, error, info, instrument, trace, warn}; +use crate::metrics::{ + SYNC_BASE_LAYER_MARKER, + SYNC_BODY_MARKER, + SYNC_CENTRAL_BLOCK_MARKER, + SYNC_COMPILED_CLASS_MARKER, + SYNC_HEADER_LATENCY_SEC, + SYNC_HEADER_MARKER, + SYNC_PROCESSED_TRANSACTIONS, + SYNC_STATE_MARKER, +}; use crate::pending_sync::sync_pending_data; use crate::sources::base_layer::{BaseLayerSourceTrait, EthereumBaseLayerSource}; use crate::sources::central::{CentralError, CentralSource, CentralSourceTrait}; @@ -49,7 +71,7 @@ use crate::sources::pending::{PendingError, PendingSource, PendingSourceTrait}; // TODO(shahak): Consider adding genesis hash to the config to support chains that have // different genesis hash. -// TODO: Consider moving to a more general place. +// TODO(Shahak): Consider moving to a more general place. pub const GENESIS_HASH: &str = "0x0"; // TODO(dvir): add to config. @@ -59,6 +81,10 @@ const PENDING_SLEEP_DURATION: Duration = Duration::from_millis(500); // Sleep duration, in seconds, between sync progress checks. const SLEEP_TIME_SYNC_PROGRESS: Duration = Duration::from_secs(300); +// The first starknet version where we can send sierras to the class manager without casms and it +// will compile them, in a backward-compatible manner. +const STARKNET_VERSION_TO_COMPILE_FROM: StarknetVersion = StarknetVersion::V0_12_0; + #[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq)] pub struct SyncConfig { #[serde(deserialize_with = "deserialize_seconds_to_duration")] @@ -71,6 +97,7 @@ pub struct SyncConfig { pub state_updates_max_stream_size: u32, pub verify_blocks: bool, pub collect_pending_data: bool, + pub store_sierras_and_casms: bool, } impl SerializeConfig for SyncConfig { @@ -119,6 +146,13 @@ impl SerializeConfig for SyncConfig { "Whether to collect data on pending blocks.", ParamPrivacyInput::Public, ), + ser_param( + "store_sierras_and_casms", + &self.store_sierras_and_casms, + "Whether to store sierras and casms to the storage. This allows maintaining \ + backward-compatibility with native-blockifier", + ParamPrivacyInput::Public, + ), ]) } } @@ -133,6 +167,7 @@ impl Default for SyncConfig { state_updates_max_stream_size: 1000, verify_blocks: true, collect_pending_data: false, + store_sierras_and_casms: false, } } } @@ -150,16 +185,17 @@ pub struct GenericStateSync< central_source: Arc, pending_source: Arc, pending_classes: Arc>, - base_layer_source: Arc, + base_layer_source: Option>, reader: StorageReader, - writer: StorageWriter, + writer: Arc>, sequencer_pub_key: Option, + class_manager_client: Option, } pub type StateSyncResult = Result<(), StateSyncError>; -// TODO: Sort alphabetically. -// TODO: Change this to CentralStateSyncError +// TODO(DanB): Sort alphabetically. +// TODO(DanB): Change this to CentralStateSyncError #[derive(thiserror::Error, Debug)] pub enum StateSyncError { #[error("Sync stopped progress.")] @@ -194,6 +230,10 @@ pub enum StateSyncError { }, #[error("Sequencer public key changed from {old:?} to {new:?}.")] SequencerPubKeyChanged { old: SequencerPublicKey, new: SequencerPublicKey }, + #[error(transparent)] + ClassManagerClientError(#[from] ClassManagerClientError), + #[error(transparent)] + JoinError(#[from] JoinError), } #[allow(clippy::large_enum_variant)] @@ -219,6 +259,7 @@ pub enum SyncEvent { class_hash: ClassHash, compiled_class_hash: CompiledClassHash, compiled_class: CasmContractClass, + is_compiler_backward_compatible: bool, }, NewBaseLayerBlock { block_number: BlockNumber, @@ -267,7 +308,9 @@ impl< | StateSyncError::BaseLayerSourceError(_) | StateSyncError::ParentBlockHashMismatch { .. } | StateSyncError::BaseLayerHashMismatch { .. } - | StateSyncError::BaseLayerBlockWithoutMatchingHeader { .. } => true, + | StateSyncError::ClassManagerClientError(_) + | StateSyncError::BaseLayerBlockWithoutMatchingHeader { .. } + | StateSyncError::JoinError(_) => true, StateSyncError::SequencerPubKeyChanged { .. } => false, } } @@ -286,7 +329,7 @@ impl< warn!( "Sequencer public key changed from {cur_key:?} to {sequencer_pub_key:?}." ); - // TODO: Add alert. + // TODO(Yair): Add alert. self.sequencer_pub_key = Some(sequencer_pub_key); return Err(StateSyncError::SequencerPubKeyChanged { old: cur_key, @@ -333,17 +376,23 @@ impl< self.config.block_propagation_sleep_duration, // TODO(yair): separate config param. self.config.state_updates_max_stream_size, + self.config.store_sierras_and_casms, ) .fuse(); - let base_layer_block_stream = stream_new_base_layer_block( - self.reader.clone(), - self.base_layer_source.clone(), - self.config.base_layer_propagation_sleep_duration, - ) - .fuse(); + let base_layer_block_stream = match &self.base_layer_source { + Some(base_layer_source) => stream_new_base_layer_block( + self.reader.clone(), + base_layer_source.clone(), + self.config.base_layer_propagation_sleep_duration, + ) + .boxed() + .fuse(), + None => stream::pending().boxed().fuse(), + }; // TODO(dvir): try use interval instead of stream. - // TODO: fix the bug and remove this check. - let check_sync_progress = check_sync_progress(self.reader.clone()).fuse(); + // TODO(DvirYo): fix the bug and remove this check. + let check_sync_progress = + check_sync_progress(self.reader.clone(), self.config.store_sierras_and_casms).fuse(); pin_mut!( block_stream, state_diff_stream, @@ -373,26 +422,38 @@ impl< async fn process_sync_event(&mut self, sync_event: SyncEvent) -> StateSyncResult { match sync_event { SyncEvent::BlockAvailable { block_number, block, signature } => { - self.store_block(block_number, block, &signature) + self.store_block(block_number, block, signature).await } SyncEvent::StateDiffAvailable { block_number, block_hash, state_diff, deployed_contract_class_definitions, - } => self.store_state_diff( - block_number, - block_hash, - state_diff, - deployed_contract_class_definitions, - ), + } => { + self.store_state_diff( + block_number, + block_hash, + state_diff, + deployed_contract_class_definitions, + ) + .await + } SyncEvent::CompiledClassAvailable { class_hash, compiled_class_hash, compiled_class, - } => self.store_compiled_class(class_hash, compiled_class_hash, compiled_class), + is_compiler_backward_compatible, + } => { + self.store_compiled_class( + class_hash, + compiled_class_hash, + compiled_class, + is_compiler_backward_compatible, + ) + .await + } SyncEvent::NewBaseLayerBlock { block_number, block_hash } => { - self.store_base_layer_block(block_number, block_hash) + self.store_base_layer_block(block_number, block_hash).await } SyncEvent::NoProgress => Err(StateSyncError::NoProgress), } @@ -406,11 +467,11 @@ impl< err )] #[allow(clippy::as_conversions)] // FIXME: use int metrics so `as f64` may be removed. - fn store_block( + async fn store_block( &mut self, block_number: BlockNumber, block: Block, - signature: &BlockSignature, + signature: BlockSignature, ) -> StateSyncResult { // Assuming the central source is trusted, detect reverts by comparing the incoming block's // parent hash to the current hash. @@ -418,37 +479,46 @@ impl< debug!("Storing block."); trace!("Block data: {block:#?}, signature: {signature:?}"); - self.writer - .begin_rw_txn()? - .append_header(block_number, &block.header)? - .append_block_signature(block_number, signature)? - .append_body(block_number, block.body)? - .commit()?; - metrics::gauge!( - papyrus_metrics::PAPYRUS_HEADER_MARKER, - block_number.unchecked_next().0 as f64 - ); - metrics::gauge!( - papyrus_metrics::PAPYRUS_BODY_MARKER, - block_number.unchecked_next().0 as f64 - ); + let num_txs = + block.body.transactions.len().try_into().expect("Failed to convert usize to u64"); + let timestamp = block.header.block_header_without_hash.timestamp; + self.perform_storage_writes(move |writer| { + let mut txn = writer + .begin_rw_txn()? + .append_header(block_number, &block.header)? + .append_block_signature(block_number, &signature)? + .append_body(block_number, block.body)?; + if block.header.block_header_without_hash.starknet_version + < STARKNET_VERSION_TO_COMPILE_FROM + { + txn = txn.update_compiler_backward_compatibility_marker( + &block_number.unchecked_next(), + )?; + } + txn.commit()?; + Ok(()) + }) + .await?; + SYNC_HEADER_MARKER.set_lossy(block_number.unchecked_next().0); + SYNC_BODY_MARKER.set_lossy(block_number.unchecked_next().0); + SYNC_PROCESSED_TRANSACTIONS.increment(num_txs); let time_delta = Utc::now() - Utc - .timestamp_opt(block.header.block_header_without_hash.timestamp.0 as i64, 0) + .timestamp_opt(timestamp.0 as i64, 0) .single() .expect("block timestamp should be valid"); let header_latency = time_delta.num_seconds(); debug!("Header latency: {}.", header_latency); if header_latency >= 0 { - metrics::gauge!(papyrus_metrics::PAPYRUS_HEADER_LATENCY_SEC, header_latency as f64); + SYNC_HEADER_LATENCY_SEC.set_lossy(header_latency); } + Ok(()) } #[latency_histogram("sync_store_state_diff_latency_seconds", false)] #[instrument(skip(self, state_diff, deployed_contract_class_definitions), level = "debug", err)] - #[allow(clippy::as_conversions)] // FIXME: use int metrics so `as f64` may be removed. - fn store_state_diff( + async fn store_state_diff( &mut self, block_number: BlockNumber, block_hash: BlockHash, @@ -463,29 +533,76 @@ impl< // classes. let (thin_state_diff, classes, deprecated_classes) = ThinStateDiff::from_state_diff(state_diff); - self.writer - .begin_rw_txn()? - .append_state_diff(block_number, thin_state_diff)? - .append_classes( - block_number, - &classes.iter().map(|(class_hash, class)| (*class_hash, class)).collect::>(), - &deprecated_classes - .iter() - .chain(deployed_contract_class_definitions.iter()) - .map(|(class_hash, deprecated_class)| (*class_hash, deprecated_class)) - .collect::>(), - )? - .commit()?; - - metrics::gauge!( - papyrus_metrics::PAPYRUS_STATE_MARKER, - block_number.unchecked_next().0 as f64 - ); + + // Sending to class manager before updating the storage so that if the class manager send + // fails we retry the same block. + if let Some(class_manager_client) = &self.class_manager_client { + // Blocks smaller than compiler_backward_compatibility marker are added to class + // manager via the compiled classes stream. + // We're sure that if the current block is above the compiler_backward_compatibility + // marker then the compiler_backward_compatibility will not advance anymore, because + // the compiler_backward_compatibility marker advances in the header stream and this + // stream is behind the header stream + // The compiled classes stream is always behind the compiler_backward_compatibility + // marker + // TODO(shahak): Consider storing a boolean and updating it to true once + // compiler_backward_compatibility_marker <= block_number and avoiding the check if the + // boolean is true. + let compiler_backward_compatibility_marker = + self.reader.begin_ro_txn()?.get_compiler_backward_compatibility_marker()?; + + if compiler_backward_compatibility_marker <= block_number { + for (expected_class_hash, class) in &classes { + let class_hash = + class_manager_client.add_class(class.clone()).await?.class_hash; + if class_hash != *expected_class_hash { + panic!( + "Class hash mismatch. Expected: {expected_class_hash}, got: \ + {class_hash}." + ); + } + } + } + + for (class_hash, deprecated_class) in &deprecated_classes { + class_manager_client + .add_deprecated_class(*class_hash, deprecated_class.clone()) + .await?; + } + } + let has_class_manager = self.class_manager_client.is_some(); + let store_sierras_and_casms = self.config.store_sierras_and_casms; + self.perform_storage_writes(move |writer| { + if has_class_manager { + writer + .begin_rw_txn()? + .update_class_manager_block_marker(&block_number.unchecked_next())? + .commit()?; + } + let mut txn = writer.begin_rw_txn()?; + txn = txn.append_state_diff(block_number, thin_state_diff)?; + if store_sierras_and_casms { + txn = txn.append_classes( + block_number, + &classes + .iter() + .map(|(class_hash, class)| (*class_hash, class)) + .collect::>(), + &deprecated_classes + .iter() + .chain(deployed_contract_class_definitions.iter()) + .map(|(class_hash, deprecated_class)| (*class_hash, deprecated_class)) + .collect::>(), + )?; + } + txn.commit()?; + Ok(()) + }) + .await?; + let compiled_class_marker = self.reader.begin_ro_txn()?.get_compiled_class_marker()?; - metrics::gauge!( - papyrus_metrics::PAPYRUS_COMPILED_CLASS_MARKER, - compiled_class_marker.0 as f64 - ); + SYNC_STATE_MARKER.set_lossy(block_number.unchecked_next().0); + SYNC_COMPILED_CLASS_MARKER.set_lossy(compiled_class_marker.0); // Info the user on syncing the block once all the data is stored. info!("Added block {} with hash {:#064x}.", block_number, block_hash.0); @@ -495,35 +612,61 @@ impl< #[latency_histogram("sync_store_compiled_class_latency_seconds", false)] #[instrument(skip(self, compiled_class), level = "debug", err)] - fn store_compiled_class( + async fn store_compiled_class( &mut self, class_hash: ClassHash, compiled_class_hash: CompiledClassHash, compiled_class: CasmContractClass, + is_compiler_backward_compatible: bool, ) -> StateSyncResult { - let txn = self.writer.begin_rw_txn()?; - // TODO: verifications - verify casm corresponds to a class on storage. - match txn.append_casm(&class_hash, &compiled_class) { - #[allow(clippy::as_conversions)] // FIXME: use int metrics so `as f64` may be removed. - Ok(txn) => { - txn.commit()?; + if !is_compiler_backward_compatible { + if let Some(class_manager_client) = &self.class_manager_client { + let class = self.reader.begin_ro_txn()?.get_class(&class_hash)?.expect( + "Compiled classes stream gave class hash that doesn't appear in storage.", + ); + let sierra_version = SierraVersion::extract_from_program(&class.sierra_program) + .expect("Failed reading sierra version from program."); + let contract_class = ContractClass::V1((compiled_class.clone(), sierra_version)); + class_manager_client + .add_class_and_executable_unsafe( + class_hash, + class, + compiled_class_hash, + contract_class, + ) + .await + .expect("Failed adding class and compiled class to class manager."); + } + } + if !self.config.store_sierras_and_casms { + return Ok(()); + } + let result = self + .perform_storage_writes(move |writer| { + writer.begin_rw_txn()?.append_casm(&class_hash, &compiled_class)?.commit()?; + Ok(()) + }) + .await; + // TODO(Yair): verifications - verify casm corresponds to a class on storage. + match result { + Ok(()) => { let compiled_class_marker = self.reader.begin_ro_txn()?.get_compiled_class_marker()?; - metrics::gauge!( - papyrus_metrics::PAPYRUS_COMPILED_CLASS_MARKER, - compiled_class_marker.0 as f64 - ); + // Write class and casm to class manager. + SYNC_COMPILED_CLASS_MARKER.set_lossy(compiled_class_marker.0); debug!("Added compiled class."); Ok(()) } // TODO(yair): Modify the stream so it skips already stored classes. - // Compiled classes rewrite is valid because the stream downloads from the beginning of - // the block instead of the last downloaded class. - Err(StorageError::InnerError(DbError::KeyAlreadyExists(..))) => { + // Compiled classes rewrite is valid because the stream downloads from the beginning + // of the block instead of the last downloaded class. + Err(StateSyncError::StorageError(StorageError::InnerError( + DbError::KeyAlreadyExists(..), + ))) => { debug!("Compiled class of {class_hash} already stored."); Ok(()) } - Err(err) => Err(StateSyncError::StorageError(err)), + Err(err) => Err(err), } } @@ -531,35 +674,35 @@ impl< // In case of a mismatch between the base layer and l2, an error will be returned, then the // sync will revert blocks if needed based on the l2 central source. This approach works as long // as l2 is trusted so all the reverts can be detect by using it. - fn store_base_layer_block( + async fn store_base_layer_block( &mut self, block_number: BlockNumber, block_hash: BlockHash, ) -> StateSyncResult { - let txn = self.writer.begin_rw_txn()?; - // Missing header can be because of a base layer reorg, the matching header may be reverted. - let expected_hash = txn - .get_block_header(block_number)? - .ok_or(StateSyncError::BaseLayerBlockWithoutMatchingHeader { block_number })? - .block_hash; - // Can be caused because base layer reorg or l2 reverts. - if expected_hash != block_hash { - return Err(StateSyncError::BaseLayerHashMismatch { - block_number, - base_layer_hash: block_hash, - l2_hash: expected_hash, - }); - } - #[allow(clippy::as_conversions)] // FIXME: use int metrics so `as f64` may be removed. - if txn.get_base_layer_block_marker()? != block_number.unchecked_next() { - info!("Verified block {block_number} hash against base layer."); - txn.update_base_layer_block_marker(&block_number.unchecked_next())?.commit()?; - metrics::gauge!( - papyrus_metrics::PAPYRUS_BASE_LAYER_MARKER, - block_number.unchecked_next().0 as f64 - ); - } - Ok(()) + self.perform_storage_writes(move |writer| { + let txn = writer.begin_rw_txn()?; + // Missing header can be because of a base layer reorg, the matching header may be + // reverted. + let expected_hash = txn + .get_block_header(block_number)? + .ok_or(StateSyncError::BaseLayerBlockWithoutMatchingHeader { block_number })? + .block_hash; + // Can be caused because base layer reorg or l2 reverts. + if expected_hash != block_hash { + return Err(StateSyncError::BaseLayerHashMismatch { + block_number, + base_layer_hash: block_hash, + l2_hash: expected_hash, + }); + } + if txn.get_base_layer_block_marker()? != block_number.unchecked_next() { + info!("Verified block {block_number} hash against base layer."); + txn.update_base_layer_block_marker(&block_number.unchecked_next())?.commit()?; + SYNC_BASE_LAYER_MARKER.set_lossy(block_number.unchecked_next().0); + } + Ok(()) + }) + .await } // Compares the block's parent hash to the stored block. @@ -610,7 +753,7 @@ impl< let mut last_block_in_storage = header_marker.prev(); while let Some(block_number) = last_block_in_storage { if self.should_revert_block(block_number).await? { - self.revert_block(block_number)?; + self.revert_block(block_number).await?; last_block_in_storage = block_number.prev(); } else { break; @@ -623,29 +766,32 @@ impl< // Deletes the block data from the storage. #[allow(clippy::expect_fun_call)] #[instrument(skip(self), level = "debug", err)] - fn revert_block(&mut self, block_number: BlockNumber) -> StateSyncResult { + async fn revert_block(&mut self, block_number: BlockNumber) -> StateSyncResult { debug!("Reverting block."); - let mut txn = self.writer.begin_rw_txn()?; - txn = txn.try_revert_base_layer_marker(block_number)?; - let res = txn.revert_header(block_number)?; - txn = res.0; - let mut reverted_block_hash: Option = None; - if let Some(header) = res.1 { - reverted_block_hash = Some(header.block_hash); - - let res = txn.revert_body(block_number)?; + self.perform_storage_writes(move |writer| { + let mut txn = writer.begin_rw_txn()?; + txn = txn.try_revert_base_layer_marker(block_number)?; + let res = txn.revert_header(block_number)?; txn = res.0; + let mut reverted_block_hash: Option = None; + if let Some(header) = res.1 { + reverted_block_hash = Some(header.block_hash); - let res = txn.revert_state_diff(block_number)?; - txn = res.0; - } + let res = txn.revert_body(block_number)?; + txn = res.0; - txn.commit()?; - if let Some(hash) = reverted_block_hash { - info!(%hash, "Reverted block."); - } - Ok(()) + let res = txn.revert_state_diff(block_number)?; + txn = res.0; + } + + txn.commit()?; + if let Some(hash) = reverted_block_hash { + info!(%hash, %block_number, "Reverted block."); + } + Ok(()) + }) + .await } /// Checks if centrals block hash at the block number is different from ours (or doesn't exist). @@ -664,6 +810,16 @@ impl< Ok(true) } } + + async fn perform_storage_writes< + F: FnOnce(&mut StorageWriter) -> Result<(), StateSyncError> + Send + 'static, + >( + &mut self, + f: F, + ) -> Result<(), StateSyncError> { + let writer = self.writer.clone(); + spawn_blocking(move || f(&mut (writer.blocking_lock()))).await? + } } // TODO(dvir): consider gathering in a single pending argument instead. #[allow(clippy::too_many_arguments)] @@ -683,17 +839,14 @@ fn stream_new_blocks< max_stream_size: u32, ) -> impl Stream> { try_stream! { - #[allow(clippy::as_conversions)] // FIXME: use int metrics so `as f64` may be removed. - loop { + loop { let header_marker = reader.begin_ro_txn()?.get_header_marker()?; let latest_central_block = central_source.get_latest_block().await?; *shared_highest_block.write().await = latest_central_block; let central_block_marker = latest_central_block.map_or( BlockNumber::default(), |block_hash_and_number| block_hash_and_number.number.unchecked_next() ); - metrics::gauge!( - papyrus_metrics::PAPYRUS_CENTRAL_BLOCK_MARKER, central_block_marker.0 as f64 - ); + SYNC_CENTRAL_BLOCK_MARKER.set_lossy(central_block_marker.0); if header_marker == central_block_marker { // Only if the node have the last block and state (without casms), sync pending data. if collect_pending_data && reader.begin_ro_txn()?.get_state_marker()? == header_marker{ @@ -714,7 +867,7 @@ fn stream_new_blocks< }; continue; } - let up_to = min(central_block_marker, BlockNumber(header_marker.0 + max_stream_size as u64)); + let up_to = min(central_block_marker, BlockNumber(header_marker.0 + u64::from(max_stream_size))); debug!("Downloading blocks [{} - {}).", header_marker, up_to); let block_stream = central_source.stream_new_blocks(header_marker, up_to).fuse(); @@ -774,7 +927,6 @@ pub fn sort_state_diff(diff: &mut StateDiff) { diff.deprecated_declared_classes.sort_unstable_keys(); diff.deployed_contracts.sort_unstable_keys(); diff.nonces.sort_unstable_keys(); - diff.replaced_classes.sort_unstable_keys(); diff.storage_diffs.sort_unstable_keys(); for storage_entries in diff.storage_diffs.values_mut() { storage_entries.sort_unstable_keys(); @@ -792,10 +944,12 @@ impl StateSync { pending_classes: Arc>, central_source: CentralSource, pending_source: PendingSource, - base_layer_source: EthereumBaseLayerSource, + base_layer_source: Option, reader: StorageReader, writer: StorageWriter, + class_manager_client: Option, ) -> Self { + let base_layer_source = base_layer_source.map(Arc::new); Self { config, shared_highest_block, @@ -803,10 +957,11 @@ impl StateSync { pending_classes, central_source: Arc::new(central_source), pending_source: Arc::new(pending_source), - base_layer_source: Arc::new(base_layer_source), + base_layer_source, reader, - writer, + writer: Arc::new(Mutex::new(writer)), sequencer_pub_key: None, + class_manager_client, } } } @@ -816,12 +971,14 @@ fn stream_new_compiled_classes central_source: Arc, block_propagation_sleep_duration: Duration, max_stream_size: u32, + store_sierras_and_casms: bool, ) -> impl Stream> { try_stream! { loop { let txn = reader.begin_ro_txn()?; let mut from = txn.get_compiled_class_marker()?; let state_marker = txn.get_state_marker()?; + let compiler_backward_compatibility_marker = txn.get_compiler_backward_compatibility_marker()?; // Avoid starting streams from blocks without declared classes. while from < state_marker { let state_diff = txn.get_state_diff(from)?.expect("Expecting to have state diff up to the marker."); @@ -841,7 +998,24 @@ fn stream_new_compiled_classes tokio::time::sleep(block_propagation_sleep_duration).await; continue; } - let up_to = min(state_marker, BlockNumber(from.0 + u64::from(max_stream_size))); + let mut up_to = min(state_marker, BlockNumber(from.0 + u64::from(max_stream_size))); + let are_casms_backward_compatible = from >= compiler_backward_compatibility_marker; + // We want that the stream will either have all compiled classes as backward compatible + // or all as not backward compatible. If needed we'll decrease up_to + if from < compiler_backward_compatibility_marker && up_to > compiler_backward_compatibility_marker { + up_to = compiler_backward_compatibility_marker; + } + + // No point in downloading casms if we don't store them and don't send them to the + // class manager + if are_casms_backward_compatible && !store_sierras_and_casms { + info!("Compiled classes stream reached a block that has backward compatibility for \ + the compiler, and store_sierras_and_casms is set to false. \ + Finishing the compiled class stream"); + pending::<()>().await; + continue; + } + debug!("Downloading compiled classes of blocks [{} - {}).", from, up_to); let compiled_classes_stream = central_source.stream_compiled_classes(from, up_to).fuse(); @@ -853,6 +1027,7 @@ fn stream_new_compiled_classes class_hash, compiled_class_hash, compiled_class, + is_compiler_backward_compatible: are_casms_backward_compatible, }; } } @@ -893,10 +1068,11 @@ fn stream_new_base_layer_block( } // This function is used to check if the sync is stuck. -// TODO: fix the bug and remove this function. +// TODO(DvirYo): fix the bug and remove this function. // TODO(dvir): add a test for this scenario. fn check_sync_progress( reader: StorageReader, + store_sierras_and_casms: bool, ) -> impl Stream> { try_stream! { let mut txn=reader.begin_ro_txn()?; @@ -910,7 +1086,9 @@ fn check_sync_progress( let new_header_marker=txn.get_header_marker()?; let new_state_marker=txn.get_state_marker()?; let new_casm_marker=txn.get_compiled_class_marker()?; - if header_marker==new_header_marker || state_marker==new_state_marker || casm_marker==new_casm_marker{ + let compiler_backward_compatibility_marker = txn.get_compiler_backward_compatibility_marker()?; + let is_casm_stuck = casm_marker == new_casm_marker && (new_casm_marker < compiler_backward_compatibility_marker || store_sierras_and_casms); + if header_marker==new_header_marker || state_marker==new_state_marker || is_casm_stuck { debug!("No progress in the sync. Return NoProgress event."); yield SyncEvent::NoProgress; } diff --git a/crates/papyrus_sync/src/metrics.rs b/crates/papyrus_sync/src/metrics.rs new file mode 100644 index 00000000000..a79481939c1 --- /dev/null +++ b/crates/papyrus_sync/src/metrics.rs @@ -0,0 +1,23 @@ +// Can't call this module metrics.rs because it will conflict with `latency_histogram` macro in +// libs.rs + +use starknet_sequencer_metrics::define_metrics; +use starknet_sequencer_metrics::metrics::{MetricCounter, MetricGauge}; + +define_metrics!( + PapyrusSync => { + // Gauges + MetricGauge { SYNC_HEADER_MARKER, "apollo_sync_header_marker", "The first block number for which sync does not have a header" }, + MetricGauge { SYNC_BODY_MARKER, "apollo_sync_body_marker", "The first block number for which sync does not have a body" }, + MetricGauge { SYNC_STATE_MARKER, "apollo_sync_state_marker", "The first block number for which sync does not have a state body" }, + MetricGauge { SYNC_COMPILED_CLASS_MARKER, "apollo_sync_compiled_class_marker", "The first block number for which sync does not have all of the corresponding compiled classes" }, + MetricGauge { SYNC_CLASS_MANAGER_MARKER, "apollo_sync_class_manager_marker", "The first block number for which sync does not guarantee all of the corresponding classes are stored in the class manager component" }, + MetricGauge { SYNC_BASE_LAYER_MARKER, "apollo_sync_base_layer_marker", "The first block number for which sync does not guarantee L1 finality" }, + MetricGauge { SYNC_CENTRAL_BLOCK_MARKER, "apollo_sync_central_block_marker", "The first block number that doesn't exist yet" }, + MetricGauge { SYNC_HEADER_LATENCY_SEC, "apollo_sync_header_latency", "The latency, in seconds, between a block timestamp (as state in its header) and the time sync stores the header" }, + // Counters + // TODO(shahak): add to metric's dashboard + MetricCounter { SYNC_PROCESSED_TRANSACTIONS, "apollo_sync_processed_transactions", "The number of transactions processed by the sync component", init = 0 }, + MetricCounter { SYNC_REVERTED_TRANSACTIONS, "apollo_sync_reverted_transactions", "The number of transactions reverted by the sync component", init = 0 }, + }, +); diff --git a/crates/papyrus_sync/src/pending_sync.rs b/crates/papyrus_sync/src/pending_sync.rs index 0a6afbce3d1..c9983463605 100644 --- a/crates/papyrus_sync/src/pending_sync.rs +++ b/crates/papyrus_sync/src/pending_sync.rs @@ -32,7 +32,7 @@ pub(crate) async fn sync_pending_data< ) -> Result<(), StateSyncError> { let txn = reader.begin_ro_txn()?; let header_marker = txn.get_header_marker()?; - // TODO: Consider extracting this functionality to different а function. + // TODO(Shahak): Consider extracting this functionality to different а function. let latest_block_hash = match header_marker { BlockNumber(0) => BlockHash(Felt::from_hex_unchecked(crate::GENESIS_HASH)), _ => { @@ -63,7 +63,7 @@ pub(crate) async fn sync_pending_data< PendingSyncTaskResult::PendingSyncFinished => return Ok(()), PendingSyncTaskResult::DownloadedNewPendingData => { let (declared_classes, old_declared_contracts) = { - // TODO (shahak): Consider getting the pending data from the task result instead + // TODO(shahak): Consider getting the pending data from the task result instead // of reading from the lock. let pending_state_diff = &pending_data.read().await.state_update.state_diff; ( diff --git a/crates/papyrus_sync/src/sources/base_layer.rs b/crates/papyrus_sync/src/sources/base_layer.rs index 2ecac3b8c45..9478c29b215 100644 --- a/crates/papyrus_sync/src/sources/base_layer.rs +++ b/crates/papyrus_sync/src/sources/base_layer.rs @@ -39,6 +39,7 @@ impl< let finality = 0; self.latest_proved_block(finality) .await + .map(|block| block.map(|block| (block.number, block.hash))) .map_err(|e| BaseLayerSourceError::BaseLayerContractError(Box::new(e))) } } diff --git a/crates/papyrus_sync/src/sources/central/state_update_stream.rs b/crates/papyrus_sync/src/sources/central/state_update_stream.rs index db811567c69..0faa5899e4e 100644 --- a/crates/papyrus_sync/src/sources/central/state_update_stream.rs +++ b/crates/papyrus_sync/src/sources/central/state_update_stream.rs @@ -268,10 +268,14 @@ fn client_to_central_state_update( let deployed_contract_class_definitions = deprecated_classes.split_off(n_deprecated_declared_classes); + let mut deployed_contracts = IndexMap::from_iter( + deployed_contracts.into_iter().map(|dc| (dc.address, dc.class_hash)), + ); + replaced_classes.into_iter().for_each(|rc| { + deployed_contracts.insert(rc.address, rc.class_hash); + }); let state_diff = StateDiff { - deployed_contracts: IndexMap::from_iter( - deployed_contracts.iter().map(|dc| (dc.address, dc.class_hash)), - ), + deployed_contracts, storage_diffs: IndexMap::from_iter(storage_diffs.into_iter().map( |(address, entries)| { (address, entries.into_iter().map(|se| (se.key, se.value)).collect()) @@ -298,10 +302,6 @@ fn client_to_central_state_update( }) .collect(), nonces, - replaced_classes: replaced_classes - .into_iter() - .map(|replaced_class| (replaced_class.address, replaced_class.class_hash)) - .collect(), }; // Filter out deployed contracts of new classes because since 0.11 new classes can not // be implicitly declared by deployment. diff --git a/crates/papyrus_sync/src/sources/central_sync_test.rs b/crates/papyrus_sync/src/sources/central_sync_test.rs index 581de1263e5..6ad251eee34 100644 --- a/crates/papyrus_sync/src/sources/central_sync_test.rs +++ b/crates/papyrus_sync/src/sources/central_sync_test.rs @@ -1,3 +1,4 @@ +use core::panic; use std::sync::Arc; use std::time::Duration; @@ -27,8 +28,10 @@ use starknet_api::core::{ClassHash, SequencerPublicKey}; use starknet_api::crypto::utils::PublicKey; use starknet_api::felt; use starknet_api::state::StateDiff; +use starknet_class_manager_types::ClassManagerClient; use starknet_client::reader::PendingData; use tokio::sync::{Mutex, RwLock}; +use tokio::time::sleep; use tracing::{debug, error}; use super::pending::MockPendingSourceTrait; @@ -51,7 +54,7 @@ use crate::{ const SYNC_SLEEP_DURATION: Duration = Duration::from_millis(100); // 100ms const BASE_LAYER_SLEEP_DURATION: Duration = Duration::from_millis(10); // 10ms const DURATION_BEFORE_CHECKING_STORAGE: Duration = SYNC_SLEEP_DURATION.saturating_mul(2); // 200ms twice the sleep duration of the sync loop. -const MAX_CHECK_STORAGE_ITERATIONS: u8 = 3; +const MAX_CHECK_STORAGE_ITERATIONS: u8 = 5; const STREAM_SIZE: u32 = 1000; // TODO(dvir): separate this file to flow tests and unit tests. @@ -103,6 +106,8 @@ fn get_test_sync_config(verify_blocks: bool) -> SyncConfig { state_updates_max_stream_size: STREAM_SIZE, verify_blocks, collect_pending_data: false, + // TODO(Shahak): Add test where store_sierras_and_casms is set to false. + store_sierras_and_casms: true, } } @@ -113,6 +118,7 @@ async fn run_sync( central: impl CentralSourceTrait + Send + Sync + 'static, base_layer: impl BaseLayerSourceTrait + Send + Sync, config: SyncConfig, + class_manager_client: Option>, ) -> StateSyncResult { // Mock to the pending source that always returns the default pending data. let mut pending_source = MockPendingSourceTrait::new(); @@ -125,10 +131,15 @@ async fn run_sync( central_source: Arc::new(central), pending_source: Arc::new(pending_source), pending_classes: Arc::new(RwLock::new(PendingClasses::default())), - base_layer_source: Arc::new(base_layer), + base_layer_source: Some(Arc::new(base_layer)), reader, - writer, + writer: Arc::new(Mutex::new(writer)), sequencer_pub_key: None, + // TODO(shahak): Add test with mock class manager client. + // TODO(shahak): Add test with post 0.14.0 block and mock class manager client and see that + // up until that block we call add_class_and_executable_unsafe and from that block we call + // add_class. + class_manager_client, }; state_sync.run().await?; @@ -148,12 +159,14 @@ async fn sync_empty_chain() { base_layer_mock.expect_latest_proved_block().returning(|| Ok(None)); let ((reader, writer), _temp_dir) = get_test_storage(); + let class_manager_client = None; let sync_future = run_sync( reader.clone(), writer, central_mock, base_layer_mock, get_test_sync_config(false), + class_manager_client, ); // Check that the header marker is 0. @@ -215,6 +228,7 @@ async fn sync_happy_flow() { central_mock.expect_stream_state_updates().returning(move |initial, up_to| { let state_stream: StateUpdatesStream<'_> = stream! { for block_number in initial.iter_up_to(up_to) { + // TODO(Eitan): test classes were added to class manager by including declared classes and deprecated declared classes if block_number.0 >= N_BLOCKS { yield Err(CentralError::BlockNotFound { block_number }) } @@ -256,6 +270,7 @@ async fn sync_happy_flow() { central_mock, base_layer_mock, get_test_sync_config(false), + None, ); // Check that the storage reached N_BLOCKS within MAX_TIME_TO_SYNC_MS. @@ -293,6 +308,7 @@ async fn sync_happy_flow() { }); tokio::select! { + _ = sleep(Duration::from_secs(1)) => panic!("Test timed out."), sync_result = sync_future => sync_result.unwrap(), storage_check_result = check_storage_future => assert!(storage_check_result), } @@ -313,13 +329,21 @@ async fn sync_with_revert() { let mock = MockedCentralWithRevert { reverted: reverted_mutex.clone() }; let mut base_layer_mock = MockBaseLayerSourceTrait::new(); base_layer_mock.expect_latest_proved_block().returning(|| Ok(None)); - let sync_future = - run_sync(reader.clone(), writer, mock, base_layer_mock, get_test_sync_config(false)); + let class_manager_client = None; + let sync_future = run_sync( + reader.clone(), + writer, + mock, + base_layer_mock, + get_test_sync_config(false), + class_manager_client, + ); // Prepare functions that check that the sync worked up to N_BLOCKS_BEFORE_REVERT and then // reacted correctly to the revert. const N_BLOCKS_BEFORE_REVERT: u64 = 8; - const MAX_TIME_TO_SYNC_BEFORE_REVERT_MS: u64 = 100; + // FIXME: (Shahak) analyze and set a lower value. + const MAX_TIME_TO_SYNC_BEFORE_REVERT_MS: u64 = 900; const CHAIN_FORK_BLOCK_NUMBER: u64 = 5; const N_BLOCKS_AFTER_REVERT: u64 = 10; // FIXME: (Omri) analyze and set a lower value. @@ -403,7 +427,7 @@ async fn sync_with_revert() { return CheckStoragePredicateResult::Error; } - // TODO: add checks to the state diff. + // TODO(Yair): add checks to the state diff. } CheckStoragePredicateResult::Passed @@ -652,12 +676,14 @@ async fn test_unrecoverable_sync_error_flow() { .returning(|_| Ok(Some(create_block_hash(WRONG_BLOCK_NUMBER, false)))); let ((reader, writer), _temp_dir) = get_test_storage(); + let class_manager_client = None; let sync_future = run_sync( reader.clone(), writer, mock, MockBaseLayerSourceTrait::new(), get_test_sync_config(false), + class_manager_client, ); let sync_res = tokio::join! {sync_future}; assert!(sync_res.0.is_err()); @@ -692,7 +718,15 @@ async fn sequencer_pub_key_management() { let ((reader, writer), _temp_dir) = get_test_storage(); let config = get_test_sync_config(true); - let sync_future = run_sync(reader.clone(), writer, central_mock, base_layer_mock, config); + let class_manager_client = None; + let sync_future = run_sync( + reader.clone(), + writer, + central_mock, + base_layer_mock, + config, + class_manager_client, + ); let sync_result = tokio::time::timeout(config.block_propagation_sleep_duration * 4, sync_future) diff --git a/crates/papyrus_sync/src/sources/central_test.rs b/crates/papyrus_sync/src/sources/central_test.rs index c8c593ee10d..37b427a9c76 100644 --- a/crates/papyrus_sync/src/sources/central_test.rs +++ b/crates/papyrus_sync/src/sources/central_test.rs @@ -406,7 +406,11 @@ async fn stream_state_updates() { ); assert_eq!( - IndexMap::from([(contract_address1, class_hash2), (contract_address2, class_hash3)]), + IndexMap::from([ + (contract_address1, class_hash2), + (contract_address2, class_hash3), + (contract_address3, class_hash4) + ]), state_diff.deployed_contracts ); assert_eq!( @@ -440,7 +444,6 @@ async fn stream_state_updates() { state_diff.declared_classes, ); assert_eq!(IndexMap::from([(contract_address1, nonce1)]), state_diff.nonces); - assert_eq!(IndexMap::from([(contract_address3, class_hash4)]), state_diff.replaced_classes); let Some(Ok(state_diff_tuple)) = stream.next().await else { panic!("Match of streamed state_update failed!"); @@ -471,7 +474,6 @@ async fn stream_compiled_classes() { }, deprecated_declared_classes: vec![], nonces: indexmap! {}, - replaced_classes: indexmap! {}, }, ) .unwrap() @@ -486,7 +488,6 @@ async fn stream_compiled_classes() { }, deprecated_declared_classes: vec![], nonces: indexmap! {}, - replaced_classes: indexmap! {}, }, ) .unwrap() diff --git a/crates/papyrus_sync/src/sync_test.rs b/crates/papyrus_sync/src/sync_test.rs index 7a2796d2f0d..ded39472291 100644 --- a/crates/papyrus_sync/src/sync_test.rs +++ b/crates/papyrus_sync/src/sync_test.rs @@ -27,7 +27,7 @@ use starknet_client::reader::objects::pending_data::{ use starknet_client::reader::objects::state::StateDiff as ClientStateDiff; use starknet_client::reader::objects::transaction::Transaction as ClientTransaction; use starknet_client::reader::{DeclaredClassHashEntry, PendingData}; -use tokio::sync::RwLock; +use tokio::sync::{Mutex, RwLock}; use crate::sources::base_layer::MockBaseLayerSourceTrait; use crate::sources::central::MockCentralSourceTrait; @@ -64,8 +64,6 @@ fn state_sorted() { let deprecated_declared_1 = (ClassHash(hash1), DeprecatedContractClass::default()); let nonce_0 = (contract_address_0, Nonce(hash0)); let nonce_1 = (contract_address_1, Nonce(hash1)); - let replaced_class_0 = (contract_address_0, ClassHash(hash0)); - let replaced_class_1 = (contract_address_1, ClassHash(hash1)); let unsorted_deployed_contracts = IndexMap::from([dep_contract_1, dep_contract_0]); let unsorted_declared_classes = @@ -78,7 +76,6 @@ fn state_sorted() { (contract_address_1, unsorted_storage_entries.clone()), (contract_address_0, unsorted_storage_entries), ]); - let unsorted_replaced_classes = IndexMap::from([replaced_class_1, replaced_class_0]); let mut state_diff = StateDiff { deployed_contracts: unsorted_deployed_contracts, @@ -86,7 +83,6 @@ fn state_sorted() { deprecated_declared_classes: unsorted_deprecated_declared, declared_classes: unsorted_declared_classes, nonces: unsorted_nonces, - replaced_classes: unsorted_replaced_classes, }; let sorted_deployed_contracts = IndexMap::from([dep_contract_0, dep_contract_1]); @@ -98,7 +94,6 @@ fn state_sorted() { (contract_address_0, sorted_storage_entries.clone()), (contract_address_1, sorted_storage_entries.clone()), ]); - let sorted_replaced_classes = IndexMap::from([replaced_class_0, replaced_class_1]); sort_state_diff(&mut state_diff); assert_eq!( @@ -122,10 +117,6 @@ fn state_sorted() { sorted_storage_entries.get_index(0).unwrap(), ); assert_eq!(state_diff.nonces.get_index(0).unwrap(), sorted_nonces.get_index(0).unwrap()); - assert_eq!( - state_diff.replaced_classes.get_index(0).unwrap(), - sorted_replaced_classes.get_index(0).unwrap(), - ); } #[tokio::test] @@ -171,8 +162,8 @@ async fn stream_new_base_layer_block_no_blocks_on_base_layer() { assert_matches!(event, SyncEvent::NewBaseLayerBlock { block_number: BlockNumber(1), .. }); } -#[test] -fn store_base_layer_block_test() { +#[tokio::test] +async fn store_base_layer_block_test() { let (reader, mut writer) = get_test_storage().0; let header_hash = BlockHash(felt!("0x0")); @@ -199,22 +190,24 @@ fn store_base_layer_block_test() { central_source: Arc::new(MockCentralSourceTrait::new()), pending_source: Arc::new(MockPendingSourceTrait::new()), pending_classes: Arc::new(RwLock::new(PendingClasses::default())), - base_layer_source: Arc::new(MockBaseLayerSourceTrait::new()), + base_layer_source: Some(Arc::new(MockBaseLayerSourceTrait::new())), reader, - writer, + writer: Arc::new(Mutex::new(writer)), sequencer_pub_key: None, + class_manager_client: None, }; // Trying to store a block without a header in the storage. - let res = gen_state_sync.store_base_layer_block(BlockNumber(1), BlockHash::default()); + let res = gen_state_sync.store_base_layer_block(BlockNumber(1), BlockHash::default()).await; assert_matches!(res, Err(StateSyncError::BaseLayerBlockWithoutMatchingHeader { .. })); // Trying to store a block with mismatching header. - let res = gen_state_sync.store_base_layer_block(BlockNumber(0), BlockHash(felt!("0x666"))); + let res = + gen_state_sync.store_base_layer_block(BlockNumber(0), BlockHash(felt!("0x666"))).await; assert_matches!(res, Err(StateSyncError::BaseLayerHashMismatch { .. })); // Happy flow. - let res = gen_state_sync.store_base_layer_block(BlockNumber(0), header_hash); + let res = gen_state_sync.store_base_layer_block(BlockNumber(0), header_hash).await; assert!(res.is_ok()); let base_layer_marker = gen_state_sync.reader.begin_ro_txn().unwrap().get_base_layer_block_marker().unwrap(); diff --git a/crates/papyrus_test_utils/src/lib.rs b/crates/papyrus_test_utils/src/lib.rs index e930cf6e60e..24560568e61 100644 --- a/crates/papyrus_test_utils/src/lib.rs +++ b/crates/papyrus_test_utils/src/lib.rs @@ -49,7 +49,7 @@ use starknet_api::block::{ GasPricePerToken, StarknetVersion, }; -use starknet_api::class_hash; +use starknet_api::consensus_transaction::ConsensusTransaction; use starknet_api::contract_class::EntryPointType; use starknet_api::core::{ ClassHash, @@ -88,9 +88,12 @@ use starknet_api::deprecated_contract_class::{ use starknet_api::execution_resources::{Builtin, ExecutionResources, GasAmount, GasVector}; use starknet_api::hash::{PoseidonHash, StarkHash}; use starknet_api::rpc_transaction::{ - ContractClass as RpcContractClass, EntryPointByType as RpcEntryPointByType, EntryPointByType, + InternalRpcDeclareTransactionV3, + InternalRpcDeployAccountTransaction, + InternalRpcTransaction, + InternalRpcTransactionWithoutTxHash, RpcDeclareTransaction, RpcDeclareTransactionV3, RpcDeployAccountTransaction, @@ -157,6 +160,7 @@ use starknet_api::transaction::{ TransactionOutput, TransactionVersion, }; +use starknet_api::{class_hash, tx_hash}; use starknet_types_core::felt::Felt; ////////////////////////////////////////////////////////////////////////// @@ -281,7 +285,7 @@ fn get_rand_test_body_with_events( while is_v3_transaction(&transaction) { transaction = Transaction::get_test_instance(rng); } - transaction_hashes.push(TransactionHash(StarkHash::from(u128::try_from(i).unwrap()))); + transaction_hashes.push(tx_hash!(i)); let transaction_output = get_test_transaction_output(&transaction); transactions.push(transaction); transaction_outputs.push(transaction_output); @@ -362,7 +366,7 @@ fn set_events(tx: &mut TransactionOutput, events: Vec) { } ////////////////////////////////////////////////////////////////////////// -/// EXTERNAL FUNCTIONS - REMOVE DUPLICATIONS +// EXTERNAL FUNCTIONS - REMOVE DUPLICATIONS ////////////////////////////////////////////////////////////////////////// // Returns a test block with a variable number of transactions and events. @@ -405,8 +409,6 @@ pub fn get_test_state_diff() -> StateDiff { // hashes than the deprecated_contract_classes. let (_, data) = res.declared_classes.pop().unwrap(); res.declared_classes.insert(class_hash!("0x001"), data); - // TODO(yair): Find a way to create replaced classes in a test instance of StateDiff. - res.replaced_classes.clear(); res } @@ -443,6 +445,8 @@ auto_impl_get_test_instance! { pub l1_gas_price: GasPricePerToken, pub l1_data_gas_price: GasPricePerToken, pub l2_gas_price: GasPricePerToken, + pub l2_gas_consumed: u64, + pub next_l2_gas_price: u64, pub state_root: GlobalRoot, pub sequencer: SequencerContractAddress, pub timestamp: BlockTimestamp, @@ -492,12 +496,18 @@ auto_impl_get_test_instance! { V0_13_2_1 = 17, V0_13_3 = 18, V0_13_4 = 19, + V0_13_5 = 20, + V0_14_0 = 21, } pub struct Calldata(pub Arc>); pub struct ClassHash(pub StarkHash); pub struct CompiledClassHash(pub StarkHash); pub struct ContractAddressSalt(pub StarkHash); + pub enum ConsensusTransaction { + RpcTransaction(RpcTransaction) = 0, + L1Handler(L1HandlerTransaction) = 1, + } pub struct SierraContractClass { pub sierra_program: Vec, pub contract_class_version: String, @@ -746,15 +756,31 @@ auto_impl_get_test_instance! { L1Gas = 0, L2Gas = 1, } - pub struct ResourceBounds { - pub max_amount: GasAmount, - pub max_price_per_unit: GasPrice, + pub struct InternalRpcTransaction { + pub tx: InternalRpcTransactionWithoutTxHash, + pub tx_hash: TransactionHash, } - pub struct RpcContractClass { - pub sierra_program: Vec, - pub contract_class_version: String, - pub entry_points_by_type: RpcEntryPointByType, - pub abi: String, + pub enum InternalRpcTransactionWithoutTxHash { + Declare(InternalRpcDeclareTransactionV3) = 0, + DeployAccount(InternalRpcDeployAccountTransaction) = 1, + Invoke(RpcInvokeTransaction) = 2, + } + pub struct InternalRpcDeclareTransactionV3 { + pub sender_address: ContractAddress, + pub compiled_class_hash: CompiledClassHash, + pub signature: TransactionSignature, + pub nonce: Nonce, + pub class_hash: ClassHash, + pub resource_bounds: AllResourceBounds, + pub tip: Tip, + pub paymaster_data: PaymasterData, + pub account_deployment_data: AccountDeploymentData, + pub nonce_data_availability_mode: DataAvailabilityMode, + pub fee_data_availability_mode: DataAvailabilityMode, + } + pub struct InternalRpcDeployAccountTransaction { + pub tx: RpcDeployAccountTransaction, + pub contract_address: ContractAddress, } pub enum RpcTransaction { Declare(RpcDeclareTransaction) = 0, @@ -769,7 +795,7 @@ auto_impl_get_test_instance! { pub tip: Tip, pub signature: TransactionSignature, pub nonce: Nonce, - pub contract_class: RpcContractClass, + pub contract_class: SierraContractClass, pub compiled_class_hash: CompiledClassHash, pub sender_address: ContractAddress, pub nonce_data_availability_mode: DataAvailabilityMode, @@ -823,7 +849,6 @@ auto_impl_get_test_instance! { pub declared_classes: IndexMap, pub deprecated_declared_classes: IndexMap, pub nonces: IndexMap, - pub replaced_classes: IndexMap, } pub struct StateDiffCommitment(pub PoseidonHash); pub struct StructMember { @@ -840,7 +865,6 @@ auto_impl_get_test_instance! { pub declared_classes: IndexMap, pub deprecated_declared_classes: Vec, pub nonces: IndexMap, - pub replaced_classes: IndexMap, } pub struct Tip(pub u64); pub enum Transaction { @@ -1130,7 +1154,7 @@ impl GetTestInstance for Hint { } } -// TODO: fix mismatch of member types between ExecutionResources and +// TODO(NoamS): fix mismatch of member types between ExecutionResources and // protobuf::receipt::ExecutionResources. impl GetTestInstance for ExecutionResources { fn get_test_instance(rng: &mut ChaCha8Rng) -> Self { @@ -1170,3 +1194,14 @@ impl GetTestInstance for NonZeroU64 { max(1, rng.next_u64()).try_into().expect("Failed to convert a non-zero u64 to NonZeroU64") } } + +impl GetTestInstance for ResourceBounds { + // The default value is invalid in some cases, so we need to override it. + fn get_test_instance(rng: &mut ChaCha8Rng) -> Self { + Self { + max_amount: GasAmount(rng.next_u64()), + // TODO(alonl): change GasPrice generation to use u128 directly + max_price_per_unit: GasPrice(rng.next_u64().into()), + } + } +} diff --git a/crates/sequencing/papyrus_consensus/src/lib.rs b/crates/sequencing/papyrus_consensus/src/lib.rs deleted file mode 100644 index 6c1fa967524..00000000000 --- a/crates/sequencing/papyrus_consensus/src/lib.rs +++ /dev/null @@ -1,20 +0,0 @@ -#![warn(missing_docs)] -// TODO(Matan): Add a description of the crate. -// TODO(Matan): fix #[allow(missing_docs)]. -//! A consensus implementation for a [`Starknet`](https://www.starknet.io/) node. - -pub mod config; -pub mod manager; -#[allow(missing_docs)] -pub mod simulation_network_receiver; -#[allow(missing_docs)] -pub mod single_height_consensus; -#[allow(missing_docs)] -pub mod state_machine; -pub mod stream_handler; -#[cfg(test)] -pub(crate) mod test_utils; -#[allow(missing_docs)] -pub mod types; - -pub use manager::run_consensus; diff --git a/crates/sequencing/papyrus_consensus/src/manager.rs b/crates/sequencing/papyrus_consensus/src/manager.rs deleted file mode 100644 index 5dfa5c7ad52..00000000000 --- a/crates/sequencing/papyrus_consensus/src/manager.rs +++ /dev/null @@ -1,279 +0,0 @@ -//! Consensus manager, see Manager struct. - -#[cfg(test)] -#[path = "manager_test.rs"] -mod manager_test; - -use std::collections::BTreeMap; -use std::time::Duration; - -use futures::channel::{mpsc, oneshot}; -use futures::stream::FuturesUnordered; -use futures::{Stream, StreamExt}; -use papyrus_common::metrics::{PAPYRUS_CONSENSUS_HEIGHT, PAPYRUS_CONSENSUS_SYNC_COUNT}; -use papyrus_network::network_manager::BroadcastTopicClientTrait; -use papyrus_protobuf::consensus::{ConsensusMessage, ProposalInit, ProposalWrapper}; -use starknet_api::block::{BlockHash, BlockNumber}; -use tracing::{debug, info, instrument}; - -use crate::config::TimeoutsConfig; -use crate::single_height_consensus::{ShcReturn, SingleHeightConsensus}; -use crate::types::{ - BroadcastConsensusMessageChannel, - ConsensusContext, - ConsensusError, - Decision, - ValidatorId, -}; - -// TODO(dvir): add test for this. -#[instrument(skip_all, level = "info")] -#[allow(missing_docs)] -#[allow(clippy::too_many_arguments)] -pub async fn run_consensus( - mut context: ContextT, - start_height: BlockNumber, - validator_id: ValidatorId, - consensus_delay: Duration, - timeouts: TimeoutsConfig, - mut broadcast_channels: BroadcastConsensusMessageChannel, - mut sync_receiver: SyncReceiverT, -) -> Result<(), ConsensusError> -where - ContextT: ConsensusContext, - SyncReceiverT: Stream + Unpin, - ProposalWrapper: - Into<(ProposalInit, mpsc::Receiver, oneshot::Receiver)>, -{ - info!( - "Running consensus, start_height={}, validator_id={}, consensus_delay={}, timeouts={:?}", - start_height, - validator_id, - consensus_delay.as_secs(), - timeouts - ); - - // Add a short delay to allow peers to connect and avoid "InsufficientPeers" error - tokio::time::sleep(consensus_delay).await; - let mut current_height = start_height; - let mut manager = MultiHeightManager::new(validator_id, timeouts); - #[allow(clippy::as_conversions)] // FIXME: use int metrics so `as f64` may be removed. - loop { - metrics::gauge!(PAPYRUS_CONSENSUS_HEIGHT, current_height.0 as f64); - - let run_height = manager.run_height(&mut context, current_height, &mut broadcast_channels); - - // `run_height` is not cancel safe. Our implementation doesn't enable us to start and stop - // it. We also cannot restart the height; when we dropped the future we dropped the state it - // built and risk equivocating. Therefore, we must only enter the other select branches if - // we are certain to leave this height. - tokio::select! { - decision = run_height => { - let decision = decision?; - context.decision_reached(decision.block, decision.precommits).await?; - current_height = current_height.unchecked_next(); - }, - sync_height = sync_height(current_height, &mut sync_receiver) => { - metrics::increment_counter!(PAPYRUS_CONSENSUS_SYNC_COUNT); - current_height = sync_height?.unchecked_next(); - } - } - } -} - -/// Runs Tendermint repeatedly across different heights. Handles issues which are not explicitly -/// part of the single height consensus algorithm (e.g. messages from future heights). -#[derive(Debug, Default)] -struct MultiHeightManager { - validator_id: ValidatorId, - cached_messages: BTreeMap>, - timeouts: TimeoutsConfig, -} - -impl MultiHeightManager { - /// Create a new consensus manager. - pub fn new(validator_id: ValidatorId, timeouts: TimeoutsConfig) -> Self { - Self { validator_id, cached_messages: BTreeMap::new(), timeouts } - } - - /// Run the consensus algorithm for a single height. - /// - /// Assumes that `height` is monotonically increasing across calls for the sake of filtering - /// `cached_messaged`. - #[instrument(skip(self, context, broadcast_channels), level = "info")] - pub async fn run_height( - &mut self, - context: &mut ContextT, - height: BlockNumber, - broadcast_channels: &mut BroadcastConsensusMessageChannel, - ) -> Result - where - ContextT: ConsensusContext, - ProposalWrapper: Into<( - ProposalInit, - mpsc::Receiver, - oneshot::Receiver, - )>, - { - let validators = context.validators(height).await; - info!("running consensus for height {height:?} with validator set {validators:?}"); - let mut shc = SingleHeightConsensus::new( - height, - self.validator_id, - validators, - self.timeouts.clone(), - ); - let mut shc_events = FuturesUnordered::new(); - - match shc.start(context).await? { - ShcReturn::Decision(decision) => return Ok(decision), - ShcReturn::Tasks(tasks) => { - for task in tasks { - shc_events.push(task.run()); - } - } - } - - let mut current_height_messages = self.get_current_height_messages(height); - loop { - let shc_return = tokio::select! { - message = next_message(&mut current_height_messages, broadcast_channels) => { - self.handle_message(context, height, &mut shc, message?).await? - }, - Some(shc_event) = shc_events.next() => { - shc.handle_event(context, shc_event).await? - }, - }; - - match shc_return { - ShcReturn::Decision(decision) => return Ok(decision), - ShcReturn::Tasks(tasks) => { - for task in tasks { - shc_events.push(task.run()); - } - } - } - } - } - - // Handle a single consensus message. - async fn handle_message( - &mut self, - context: &mut ContextT, - height: BlockNumber, - shc: &mut SingleHeightConsensus, - message: ConsensusMessage, - ) -> Result - where - ContextT: ConsensusContext, - ProposalWrapper: Into<( - ProposalInit, - mpsc::Receiver, - oneshot::Receiver, - )>, - { - // TODO(matan): We need to figure out an actual cacheing strategy under 2 constraints: - // 1. Malicious - must be capped so a malicious peer can't DoS us. - // 2. Parallel proposals - we may send/receive a proposal for (H+1, 0). - // In general I think we will want to only cache (H+1, 0) messages. - if message.height() != height.0 { - debug!("Received a message for a different height. {:?}", message); - if message.height() > height.0 { - self.cached_messages.entry(message.height()).or_default().push(message); - } - return Ok(ShcReturn::Tasks(Vec::new())); - } - match message { - ConsensusMessage::Proposal(proposal) => { - // Special case due to fake streaming. - let (proposal_init, content_receiver, fin_receiver) = - ProposalWrapper(proposal).into(); - let res = shc - .handle_proposal(context, proposal_init, content_receiver, fin_receiver) - .await?; - Ok(res) - } - _ => { - let res = shc.handle_message(context, message).await?; - Ok(res) - } - } - } - - // Filters the cached messages: - // - returns all of the current height messages. - // - drops messages from earlier heights. - // - retains future messages in the cache. - fn get_current_height_messages(&mut self, height: BlockNumber) -> Vec { - // Depends on `cached_messages` being sorted by height. - loop { - let Some(entry) = self.cached_messages.first_entry() else { - return Vec::new(); - }; - match entry.key().cmp(&height.0) { - std::cmp::Ordering::Greater => return Vec::new(), - std::cmp::Ordering::Equal => return entry.remove(), - std::cmp::Ordering::Less => { - entry.remove(); - } - } - } - } -} - -async fn next_message( - cached_messages: &mut Vec, - broadcast_channels: &mut BroadcastConsensusMessageChannel, -) -> Result -where -{ - let BroadcastConsensusMessageChannel { broadcasted_messages_receiver, broadcast_topic_client } = - broadcast_channels; - if let Some(msg) = cached_messages.pop() { - return Ok(msg); - } - - let (msg, broadcasted_message_metadata) = - broadcasted_messages_receiver.next().await.ok_or_else(|| { - ConsensusError::InternalNetworkError( - "NetworkReceiver should never be closed".to_string(), - ) - })?; - match msg { - // TODO(matan): Return report_sender for use in later errors by SHC. - Ok(msg) => { - let _ = - broadcast_topic_client.continue_propagation(&broadcasted_message_metadata).await; - Ok(msg) - } - Err(e) => { - // Failed to parse consensus message - let _ = broadcast_topic_client.report_peer(broadcasted_message_metadata).await; - Err(e.into()) - } - } -} - -// Return only when a height is reached that is greater than or equal to the current height. -async fn sync_height( - height: BlockNumber, - mut sync_receiver: SyncReceiverT, -) -> Result -where - SyncReceiverT: Stream + Unpin, -{ - loop { - match sync_receiver.next().await { - Some(sync_height) if sync_height >= height => { - info!("Sync to height: {}. current_height={}", sync_height, height); - return Ok(sync_height); - } - Some(sync_height) => { - debug!("Ignoring sync to height: {}. current_height={}", sync_height, height); - } - None => { - return Err(ConsensusError::SyncError("Sync receiver closed".to_string())); - } - } - } -} diff --git a/crates/sequencing/papyrus_consensus/src/manager_test.rs b/crates/sequencing/papyrus_consensus/src/manager_test.rs deleted file mode 100644 index 3f94d78fb42..00000000000 --- a/crates/sequencing/papyrus_consensus/src/manager_test.rs +++ /dev/null @@ -1,306 +0,0 @@ -use std::time::Duration; -use std::vec; - -use async_trait::async_trait; -use futures::channel::{mpsc, oneshot}; -use futures::SinkExt; -use lazy_static::lazy_static; -use mockall::mock; -use mockall::predicate::eq; -use papyrus_network::network_manager::test_utils::{ - mock_register_broadcast_topic, - MockBroadcastedMessagesSender, - TestSubscriberChannels, -}; -use papyrus_network_types::network_types::BroadcastedMessageMetadata; -use papyrus_protobuf::consensus::{ConsensusMessage, ProposalInit, Vote}; -use papyrus_test_utils::{get_rng, GetTestInstance}; -use starknet_api::block::{BlockHash, BlockNumber}; -use starknet_api::transaction::Transaction; -use starknet_types_core::felt::Felt; - -use super::{run_consensus, MultiHeightManager}; -use crate::config::TimeoutsConfig; -use crate::test_utils::{precommit, prevote, proposal}; -use crate::types::{ConsensusContext, ConsensusError, ProposalContentId, Round, ValidatorId}; - -lazy_static! { - static ref PROPOSER_ID: ValidatorId = 0_u32.into(); - static ref VALIDATOR_ID: ValidatorId = 1_u32.into(); - static ref VALIDATOR_ID_2: ValidatorId = 2_u32.into(); - static ref VALIDATOR_ID_3: ValidatorId = 3_u32.into(); - static ref TIMEOUTS: TimeoutsConfig = TimeoutsConfig::default(); -} - -mock! { - pub TestContext {} - - #[async_trait] - impl ConsensusContext for TestContext { - type ProposalChunk = Transaction; - - async fn build_proposal( - &mut self, - init: ProposalInit, - timeout: Duration - ) -> oneshot::Receiver; - - async fn validate_proposal( - &mut self, - height: BlockNumber, - timeout: Duration, - content: mpsc::Receiver - ) -> oneshot::Receiver; - - async fn repropose( - &mut self, - id: ProposalContentId, - init: ProposalInit, - ); - - async fn validators(&self, height: BlockNumber) -> Vec; - - fn proposer(&self, height: BlockNumber, round: Round) -> ValidatorId; - - async fn broadcast(&mut self, message: ConsensusMessage) -> Result<(), ConsensusError>; - - async fn decision_reached( - &mut self, - block: ProposalContentId, - precommits: Vec, - ) -> Result<(), ConsensusError>; - } -} - -async fn send(sender: &mut MockBroadcastedMessagesSender, msg: ConsensusMessage) { - let broadcasted_message_metadata = - BroadcastedMessageMetadata::get_test_instance(&mut get_rng()); - sender.send((msg, broadcasted_message_metadata)).await.unwrap(); -} - -#[tokio::test] -async fn manager_multiple_heights_unordered() { - let TestSubscriberChannels { mock_network, subscriber_channels } = - mock_register_broadcast_topic().unwrap(); - let mut sender = mock_network.broadcasted_messages_sender; - // Send messages for height 2 followed by those for height 1. - send(&mut sender, proposal(Felt::TWO, 2, 0, *PROPOSER_ID)).await; - send(&mut sender, prevote(Some(Felt::TWO), 2, 0, *PROPOSER_ID)).await; - send(&mut sender, precommit(Some(Felt::TWO), 2, 0, *PROPOSER_ID)).await; - send(&mut sender, proposal(Felt::ONE, 1, 0, *PROPOSER_ID)).await; - send(&mut sender, prevote(Some(Felt::ONE), 1, 0, *PROPOSER_ID)).await; - send(&mut sender, precommit(Some(Felt::ONE), 1, 0, *PROPOSER_ID)).await; - - let mut context = MockTestContext::new(); - // Run the manager for height 1. - context - .expect_validate_proposal() - .return_once(move |_, _, _| { - let (block_sender, block_receiver) = oneshot::channel(); - block_sender.send(BlockHash(Felt::ONE)).unwrap(); - block_receiver - }) - .times(1); - context.expect_validators().returning(move |_| vec![*PROPOSER_ID, *VALIDATOR_ID]); - context.expect_proposer().returning(move |_, _| *PROPOSER_ID); - context.expect_broadcast().returning(move |_| Ok(())); - - let mut manager = MultiHeightManager::new(*VALIDATOR_ID, TIMEOUTS.clone()); - let mut subscriber_channels = subscriber_channels.into(); - let decision = - manager.run_height(&mut context, BlockNumber(1), &mut subscriber_channels).await.unwrap(); - assert_eq!(decision.block, BlockHash(Felt::ONE)); - - // Run the manager for height 2. - context - .expect_validate_proposal() - .return_once(move |_, _, _| { - let (block_sender, block_receiver) = oneshot::channel(); - block_sender.send(BlockHash(Felt::TWO)).unwrap(); - block_receiver - }) - .times(1); - let decision = - manager.run_height(&mut context, BlockNumber(2), &mut subscriber_channels).await.unwrap(); - assert_eq!(decision.block, BlockHash(Felt::TWO)); -} - -#[tokio::test] -async fn run_consensus_sync() { - // Set expectations. - let mut context = MockTestContext::new(); - let (decision_tx, decision_rx) = oneshot::channel(); - - context.expect_validate_proposal().return_once(move |_, _, _| { - let (block_sender, block_receiver) = oneshot::channel(); - block_sender.send(BlockHash(Felt::TWO)).unwrap(); - block_receiver - }); - context.expect_validators().returning(move |_| vec![*PROPOSER_ID, *VALIDATOR_ID]); - context.expect_proposer().returning(move |_, _| *PROPOSER_ID); - context.expect_broadcast().returning(move |_| Ok(())); - context.expect_decision_reached().return_once(move |block, votes| { - assert_eq!(block, BlockHash(Felt::TWO)); - assert_eq!(votes[0].height, 2); - decision_tx.send(()).unwrap(); - Ok(()) - }); - - // Send messages for height 2. - let TestSubscriberChannels { mock_network, subscriber_channels } = - mock_register_broadcast_topic().unwrap(); - let mut network_sender = mock_network.broadcasted_messages_sender; - send(&mut network_sender, proposal(Felt::TWO, 2, 0, *PROPOSER_ID)).await; - send(&mut network_sender, prevote(Some(Felt::TWO), 2, 0, *PROPOSER_ID)).await; - send(&mut network_sender, precommit(Some(Felt::TWO), 2, 0, *PROPOSER_ID)).await; - - // Start at height 1. - let (mut sync_sender, mut sync_receiver) = mpsc::unbounded(); - let consensus_handle = tokio::spawn(async move { - run_consensus( - context, - BlockNumber(1), - *VALIDATOR_ID, - Duration::ZERO, - TIMEOUTS.clone(), - subscriber_channels.into(), - &mut sync_receiver, - ) - .await - }); - - // Send sync for height 1. - sync_sender.send(BlockNumber(1)).await.unwrap(); - // Make sure the sync is processed before the upcoming messages. - tokio::time::sleep(Duration::from_millis(100)).await; - - // Decision for height 2. - decision_rx.await.unwrap(); - - // Drop the sender to close consensus and gracefully shut down. - drop(sync_sender); - assert!(matches!(consensus_handle.await.unwrap(), Err(ConsensusError::SyncError(_)))); -} - -// Check for cancellation safety when ignoring old heights. If the current height check was done -// within the select branch this test would hang. -#[tokio::test] -async fn run_consensus_sync_cancellation_safety() { - let mut context = MockTestContext::new(); - let (proposal_handled_tx, proposal_handled_rx) = oneshot::channel(); - let (decision_tx, decision_rx) = oneshot::channel(); - - context.expect_validate_proposal().return_once(move |_, _, _| { - let (block_sender, block_receiver) = oneshot::channel(); - block_sender.send(BlockHash(Felt::ONE)).unwrap(); - block_receiver - }); - context.expect_validators().returning(move |_| vec![*PROPOSER_ID, *VALIDATOR_ID]); - context.expect_proposer().returning(move |_, _| *PROPOSER_ID); - context.expect_broadcast().with(eq(prevote(Some(Felt::ONE), 1, 0, *VALIDATOR_ID))).return_once( - move |_| { - proposal_handled_tx.send(()).unwrap(); - Ok(()) - }, - ); - context.expect_broadcast().returning(move |_| Ok(())); - context.expect_decision_reached().return_once(|block, votes| { - assert_eq!(block, BlockHash(Felt::ONE)); - assert_eq!(votes[0].height, 1); - decision_tx.send(()).unwrap(); - Ok(()) - }); - - let TestSubscriberChannels { mock_network, subscriber_channels } = - mock_register_broadcast_topic().unwrap(); - let (mut sync_sender, mut sync_receiver) = mpsc::unbounded(); - - let consensus_handle = tokio::spawn(async move { - run_consensus( - context, - BlockNumber(1), - *VALIDATOR_ID, - Duration::ZERO, - TIMEOUTS.clone(), - subscriber_channels.into(), - &mut sync_receiver, - ) - .await - }); - let mut network_sender = mock_network.broadcasted_messages_sender; - - // Send a proposal for height 1. - send(&mut network_sender, proposal(Felt::ONE, 1, 0, *PROPOSER_ID)).await; - proposal_handled_rx.await.unwrap(); - - // Send an old sync. This should not cancel the current height. - sync_sender.send(BlockNumber(0)).await.unwrap(); - // Make sure the sync is processed before the upcoming messages. - tokio::time::sleep(Duration::from_millis(100)).await; - - // Finished messages for 1 - send(&mut network_sender, prevote(Some(Felt::ONE), 1, 0, *PROPOSER_ID)).await; - send(&mut network_sender, precommit(Some(Felt::ONE), 1, 0, *PROPOSER_ID)).await; - decision_rx.await.unwrap(); - - // Drop the sender to close consensus and gracefully shut down. - drop(sync_sender); - assert!(matches!(consensus_handle.await.unwrap(), Err(ConsensusError::SyncError(_)))); -} - -#[tokio::test] -async fn test_timeouts() { - let TestSubscriberChannels { mock_network, subscriber_channels } = - mock_register_broadcast_topic().unwrap(); - let mut sender = mock_network.broadcasted_messages_sender; - send(&mut sender, proposal(Felt::ONE, 1, 0, *PROPOSER_ID)).await; - send(&mut sender, prevote(None, 1, 0, *VALIDATOR_ID_2)).await; - send(&mut sender, prevote(None, 1, 0, *VALIDATOR_ID_3)).await; - send(&mut sender, precommit(None, 1, 0, *VALIDATOR_ID_2)).await; - send(&mut sender, precommit(None, 1, 0, *VALIDATOR_ID_3)).await; - - let mut context = MockTestContext::new(); - context.expect_validate_proposal().returning(move |_, _, _| { - let (block_sender, block_receiver) = oneshot::channel(); - block_sender.send(BlockHash(Felt::ONE)).unwrap(); - block_receiver - }); - context - .expect_validators() - .returning(move |_| vec![*PROPOSER_ID, *VALIDATOR_ID, *VALIDATOR_ID_2, *VALIDATOR_ID_3]); - context.expect_proposer().returning(move |_, _| *PROPOSER_ID); - - let (timeout_send, timeout_receive) = oneshot::channel(); - // Node handled Timeout events and responded with NIL vote. - context - .expect_broadcast() - .times(1) - .withf(move |msg: &ConsensusMessage| msg == &prevote(None, 1, 1, *VALIDATOR_ID)) - .return_once(move |_| { - timeout_send.send(()).unwrap(); - Ok(()) - }); - context.expect_broadcast().returning(move |_| Ok(())); - - let mut manager = MultiHeightManager::new(*VALIDATOR_ID, TIMEOUTS.clone()); - let manager_handle = tokio::spawn(async move { - let decision = manager - .run_height(&mut context, BlockNumber(1), &mut subscriber_channels.into()) - .await - .unwrap(); - assert_eq!(decision.block, BlockHash(Felt::ONE)); - }); - - // Wait for the timeout to be triggered. - timeout_receive.await.unwrap(); - // Show that after the timeout is triggered we can still precommit in favor of the block and - // reach a decision. - send(&mut sender, proposal(Felt::ONE, 1, 1, *PROPOSER_ID)).await; - send(&mut sender, prevote(Some(Felt::ONE), 1, 1, *PROPOSER_ID)).await; - send(&mut sender, prevote(Some(Felt::ONE), 1, 1, *VALIDATOR_ID_2)).await; - send(&mut sender, prevote(Some(Felt::ONE), 1, 1, *VALIDATOR_ID_3)).await; - send(&mut sender, precommit(Some(Felt::ONE), 1, 1, *VALIDATOR_ID_2)).await; - send(&mut sender, precommit(Some(Felt::ONE), 1, 1, *VALIDATOR_ID_3)).await; - - manager_handle.await.unwrap(); -} diff --git a/crates/sequencing/papyrus_consensus/src/stream_handler.rs b/crates/sequencing/papyrus_consensus/src/stream_handler.rs deleted file mode 100644 index aef64421c75..00000000000 --- a/crates/sequencing/papyrus_consensus/src/stream_handler.rs +++ /dev/null @@ -1,332 +0,0 @@ -//! Stream handler, see StreamManager struct. - -use std::cmp::Ordering; -use std::collections::btree_map::Entry as BTreeEntry; -use std::collections::hash_map::Entry as HashMapEntry; -use std::collections::{BTreeMap, HashMap}; - -use futures::channel::mpsc; -use futures::StreamExt; -use papyrus_network::network_manager::{ - BroadcastTopicClient, - BroadcastTopicClientTrait, - BroadcastTopicServer, -}; -use papyrus_network::utils::StreamHashMap; -use papyrus_network_types::network_types::{BroadcastedMessageMetadata, OpaquePeerId}; -use papyrus_protobuf::consensus::{StreamMessage, StreamMessageBody}; -use papyrus_protobuf::converters::ProtobufConversionError; -use tracing::{instrument, warn}; - -#[cfg(test)] -#[path = "stream_handler_test.rs"] -mod stream_handler_test; - -type PeerId = OpaquePeerId; -type StreamId = u64; -type MessageId = u64; -type StreamKey = (PeerId, StreamId); - -const CHANNEL_BUFFER_LENGTH: usize = 100; - -#[derive(Debug, Clone)] -struct StreamData< - T: Clone + Into> + TryFrom, Error = ProtobufConversionError> + 'static, -> { - next_message_id: MessageId, - // Last message ID. If None, it means we have not yet gotten to it. - fin_message_id: Option, - max_message_id_received: MessageId, - sender: mpsc::Sender, - // A buffer for messages that were received out of order. - message_buffer: BTreeMap>, -} - -impl> + TryFrom, Error = ProtobufConversionError>> StreamData { - fn new(sender: mpsc::Sender) -> Self { - StreamData { - next_message_id: 0, - fin_message_id: None, - max_message_id_received: 0, - sender, - message_buffer: BTreeMap::new(), - } - } -} - -/// A StreamHandler is responsible for: -/// - Buffering inbound messages and reporting them to the application in order. -/// - Sending outbound messages to the network, wrapped in StreamMessage. -pub struct StreamHandler< - T: Clone + Into> + TryFrom, Error = ProtobufConversionError> + 'static, -> { - // For each stream ID from the network, send the application a Receiver - // that will receive the messages in order. This allows sending such Receivers. - inbound_channel_sender: mpsc::Sender>, - // This receives messages from the network. - inbound_receiver: BroadcastTopicServer>, - // A map from (peer_id, stream_id) to a struct that contains all the information - // about the stream. This includes both the message buffer and some metadata - // (like the latest message ID). - inbound_stream_data: HashMap>, - // Whenever application wants to start a new stream, it must send out a - // (stream_id, Receiver) pair. Each receiver gets messages that should - // be sent out to the network. - outbound_channel_receiver: mpsc::Receiver<(StreamId, mpsc::Receiver)>, - // A map where the abovementioned Receivers are stored. - outbound_stream_receivers: StreamHashMap>, - // A network sender that allows sending StreamMessages to peers. - outbound_sender: BroadcastTopicClient>, - // For each stream, keep track of the message_id of the last message sent. - outbound_stream_number: HashMap, -} - -impl> + TryFrom, Error = ProtobufConversionError>> - StreamHandler -{ - /// Create a new StreamHandler. - pub fn new( - inbound_channel_sender: mpsc::Sender>, - inbound_receiver: BroadcastTopicServer>, - outbound_channel_receiver: mpsc::Receiver<(StreamId, mpsc::Receiver)>, - outbound_sender: BroadcastTopicClient>, - ) -> Self { - Self { - inbound_channel_sender, - inbound_receiver, - inbound_stream_data: HashMap::new(), - outbound_channel_receiver, - outbound_sender, - outbound_stream_receivers: StreamHashMap::new(HashMap::new()), - outbound_stream_number: HashMap::new(), - } - } - - /// Create a new StreamHandler and start it running in a new task. - /// Gets network input/output channels and returns application input/output channels. - #[allow(clippy::type_complexity)] - pub fn get_channels( - inbound_network_receiver: BroadcastTopicServer>, - outbound_network_sender: BroadcastTopicClient>, - ) -> ( - mpsc::Sender<(StreamId, mpsc::Receiver)>, - mpsc::Receiver>, - tokio::task::JoinHandle<()>, - ) { - // The inbound messages come into StreamHandler via inbound_network_receiver. - // The application gets the messages from inbound_internal_receiver - // (the StreamHandler keeps the inbound_internal_sender to pass the messages). - let (inbound_internal_sender, inbound_internal_receiver): ( - mpsc::Sender>, - mpsc::Receiver>, - ) = mpsc::channel(CHANNEL_BUFFER_LENGTH); - // The outbound messages that an application would like to send are: - // 1. Sent into outbound_internal_sender as tuples of (StreamId, Receiver) - // 2. Ingested by StreamHandler by its outbound_internal_receiver. - // 3. Broadcast by the StreamHandler using its outbound_network_sender. - let (outbound_internal_sender, outbound_internal_receiver): ( - mpsc::Sender<(StreamId, mpsc::Receiver)>, - mpsc::Receiver<(StreamId, mpsc::Receiver)>, - ) = mpsc::channel(CHANNEL_BUFFER_LENGTH); - - let mut stream_handler = StreamHandler::::new( - inbound_internal_sender, // Sender>, - inbound_network_receiver, // BroadcastTopicServer>, - outbound_internal_receiver, // Receiver<(StreamId, Receiver)>, - outbound_network_sender, // BroadcastTopicClient> - ); - let handle = tokio::spawn(async move { - stream_handler.run().await; - }); - - (outbound_internal_sender, inbound_internal_receiver, handle) - } - - /// Listen for messages coming from the network and from the application. - /// - Outbound messages are wrapped as StreamMessage and sent to the network directly. - /// - Inbound messages are stripped of StreamMessage and buffered until they can be sent in the - /// correct order to the application. - #[instrument(skip_all)] - pub async fn run(&mut self) { - loop { - tokio::select!( - // Go over the channel receiver to see if there is a new channel. - Some((stream_id, receiver)) = self.outbound_channel_receiver.next() => { - self.outbound_stream_receivers.insert(stream_id, receiver); - } - // Go over all existing outbound receivers to see if there are any messages. - output = self.outbound_stream_receivers.next() => { - match output { - Some((key, Some(message))) => { - self.broadcast(key, message).await; - } - Some((key, None)) => { - self.broadcast_fin(key).await; - } - None => { - warn!( - "StreamHashMap should not be closed! \ - Usually only the individual channels are closed. " - ) - } - } - } - // Check if there is an inbound message from the network. - Some(message) = self.inbound_receiver.next() => { - self.handle_message(message); - } - ); - } - } - - fn inbound_send(data: &mut StreamData, message: StreamMessage) { - // TODO(guyn): reconsider the "expect" here. - let sender = &mut data.sender; - if let StreamMessageBody::Content(content) = message.message { - sender.try_send(content).expect("Send should succeed"); - data.next_message_id += 1; - } - } - - // Send the message to the network. - async fn broadcast(&mut self, stream_id: StreamId, message: T) { - let message = StreamMessage { - message: StreamMessageBody::Content(message), - stream_id, - message_id: *self.outbound_stream_number.get(&stream_id).unwrap_or(&0), - }; - // TODO(guyn): reconsider the "expect" here. - self.outbound_sender.broadcast_message(message).await.expect("Send should succeed"); - self.outbound_stream_number - .insert(stream_id, self.outbound_stream_number.get(&stream_id).unwrap_or(&0) + 1); - } - - // Send a fin message to the network. - async fn broadcast_fin(&mut self, stream_id: StreamId) { - let message = StreamMessage { - message: StreamMessageBody::Fin, - stream_id, - message_id: *self.outbound_stream_number.get(&stream_id).unwrap_or(&0), - }; - self.outbound_sender.broadcast_message(message).await.expect("Send should succeed"); - self.outbound_stream_number.remove(&stream_id); - } - - // Handle a message that was received from the network. - #[instrument(skip_all, level = "warn")] - fn handle_message( - &mut self, - message: (Result, ProtobufConversionError>, BroadcastedMessageMetadata), - ) { - let (message, metadata) = message; - let message = match message { - Ok(message) => message, - Err(e) => { - warn!("Error converting message: {:?}", e); - return; - } - }; - let peer_id = metadata.originator_id; - let stream_id = message.stream_id; - let key = (peer_id, stream_id); - let message_id = message.message_id; - - let data = match self.inbound_stream_data.entry(key.clone()) { - HashMapEntry::Occupied(entry) => entry.into_mut(), - HashMapEntry::Vacant(e) => { - // If we received a message for a stream that we have not seen before, - // we need to create a new receiver for it. - let (sender, receiver) = mpsc::channel(CHANNEL_BUFFER_LENGTH); - // TODO(guyn): reconsider the "expect" here. - self.inbound_channel_sender.try_send(receiver).expect("Send should succeed"); - - let data = StreamData::new(sender); - e.insert(data) - } - }; - - if data.max_message_id_received < message_id { - data.max_message_id_received = message_id; - } - - // Check for Fin type message. - match message.message { - StreamMessageBody::Content(_) => {} - StreamMessageBody::Fin => { - data.fin_message_id = Some(message_id); - if data.max_message_id_received > message_id { - // TODO(guyn): replace warnings with more graceful error handling - warn!( - "Received fin message with id that is smaller than a previous message! \ - key: {:?}, fin_message_id: {}, max_message_id_received: {}", - key, message_id, data.max_message_id_received - ); - return; - } - } - } - - if message_id > data.fin_message_id.unwrap_or(u64::MAX) { - // TODO(guyn): replace warnings with more graceful error handling - warn!( - "Received message with id that is bigger than the id of the fin message! key: \ - {:?}, message_id: {}, fin_message_id: {}", - key, - message_id, - data.fin_message_id.unwrap_or(u64::MAX) - ); - return; - } - - // This means we can just send the message without buffering it. - match message_id.cmp(&data.next_message_id) { - Ordering::Equal => { - Self::inbound_send(data, message); - Self::process_buffer(data); - - if data.message_buffer.is_empty() && data.fin_message_id.is_some() { - data.sender.close_channel(); - self.inbound_stream_data.remove(&key); - } - } - Ordering::Greater => { - Self::store(data, key, message); - } - Ordering::Less => { - // TODO(guyn): replace warnings with more graceful error handling - warn!( - "Received message with id that is smaller than the next message expected! \ - key: {:?}, message_id: {}, next_message_id: {}", - key, message_id, data.next_message_id - ); - return; - } - } - } - - // Store an inbound message in the buffer. - fn store(data: &mut StreamData, key: StreamKey, message: StreamMessage) { - let message_id = message.message_id; - - match data.message_buffer.entry(message_id) { - BTreeEntry::Vacant(e) => { - e.insert(message); - } - BTreeEntry::Occupied(_) => { - // TODO(guyn): replace warnings with more graceful error handling - warn!( - "Two messages with the same message_id in buffer! key: {:?}, message_id: {}", - key, message_id - ); - } - } - } - - // Tries to drain as many messages as possible from the buffer (in order), - // DOES NOT guarantee that the buffer will be empty after calling this function. - fn process_buffer(data: &mut StreamData) { - while let Some(message) = data.message_buffer.remove(&data.next_message_id) { - Self::inbound_send(data, message); - } - } -} diff --git a/crates/sequencing/papyrus_consensus/src/stream_handler_test.rs b/crates/sequencing/papyrus_consensus/src/stream_handler_test.rs deleted file mode 100644 index 0bd7250f122..00000000000 --- a/crates/sequencing/papyrus_consensus/src/stream_handler_test.rs +++ /dev/null @@ -1,513 +0,0 @@ -use std::time::Duration; - -use futures::channel::mpsc; -use futures::stream::StreamExt; -use futures::SinkExt; -use papyrus_network::network_manager::test_utils::{ - mock_register_broadcast_topic, - MockBroadcastedMessagesSender, - TestSubscriberChannels, -}; -use papyrus_network::network_manager::BroadcastTopicChannels; -use papyrus_network_types::network_types::BroadcastedMessageMetadata; -use papyrus_protobuf::consensus::{ConsensusMessage, Proposal, StreamMessage, StreamMessageBody}; -use papyrus_test_utils::{get_rng, GetTestInstance}; - -use super::{MessageId, StreamHandler, StreamId}; - -const TIMEOUT: Duration = Duration::from_millis(100); -const CHANNEL_SIZE: usize = 100; - -#[cfg(test)] -mod tests { - use super::*; - - fn make_test_message( - stream_id: StreamId, - message_id: MessageId, - fin: bool, - ) -> StreamMessage { - let content = match fin { - true => StreamMessageBody::Fin, - false => StreamMessageBody::Content(ConsensusMessage::Proposal(Proposal::default())), - }; - StreamMessage { message: content, stream_id, message_id } - } - - // Check if two vectors are the same: - fn do_vecs_match(a: &[T], b: &[T]) -> bool { - let matching = a.iter().zip(b.iter()).filter(|&(a, b)| a == b).count(); - matching == a.len() && matching == b.len() - } - - async fn send( - sender: &mut MockBroadcastedMessagesSender>, - metadata: &BroadcastedMessageMetadata, - msg: StreamMessage, - ) { - sender.send((msg, metadata.clone())).await.unwrap(); - } - - #[allow(clippy::type_complexity)] - fn setup_test() -> ( - StreamHandler, - MockBroadcastedMessagesSender>, - mpsc::Receiver>, - BroadcastedMessageMetadata, - mpsc::Sender<(StreamId, mpsc::Receiver)>, - futures::stream::Map< - mpsc::Receiver>, - fn(Vec) -> StreamMessage, - >, - ) { - // The outbound_sender is the network connector for broadcasting messages. - // The network_broadcast_receiver is used to catch those messages in the test. - let TestSubscriberChannels { mock_network: mock_broadcast_network, subscriber_channels } = - mock_register_broadcast_topic().unwrap(); - let BroadcastTopicChannels { - broadcasted_messages_receiver: _, - broadcast_topic_client: outbound_sender, - } = subscriber_channels; - - let network_broadcast_receiver = mock_broadcast_network.messages_to_broadcast_receiver; - - // This is used to feed receivers of messages to StreamHandler for broadcasting. - // The receiver goes into StreamHandler, sender is used by the test (as mock Consensus). - // Note that each new channel comes in a tuple with (stream_id, receiver). - let (outbound_channel_sender, outbound_channel_receiver) = - mpsc::channel::<(StreamId, mpsc::Receiver)>(CHANNEL_SIZE); - - // The network_sender_to_inbound is the sender of the mock network, that is used by the - // test to send messages into the StreamHandler (from the mock network). - let TestSubscriberChannels { mock_network, subscriber_channels } = - mock_register_broadcast_topic().unwrap(); - let network_sender_to_inbound = mock_network.broadcasted_messages_sender; - - // The inbound_receiver is given to StreamHandler to inbound to mock network messages. - let BroadcastTopicChannels { - broadcasted_messages_receiver: inbound_receiver, - broadcast_topic_client: _, - } = subscriber_channels; - - // The inbound_channel_sender is given to StreamHandler so it can output new channels for - // each stream. The inbound_channel_receiver is given to the "mock consensus" that - // gets new channels and inbounds to them. - let (inbound_channel_sender, inbound_channel_receiver) = - mpsc::channel::>(CHANNEL_SIZE); - - // TODO(guyn): We should also give the broadcast_topic_client to the StreamHandler - // This will allow reporting to the network things like bad peers. - let handler = StreamHandler::new( - inbound_channel_sender, - inbound_receiver, - outbound_channel_receiver, - outbound_sender, - ); - - let inbound_metadata = BroadcastedMessageMetadata::get_test_instance(&mut get_rng()); - - ( - handler, - network_sender_to_inbound, - inbound_channel_receiver, - inbound_metadata, - outbound_channel_sender, - network_broadcast_receiver, - ) - } - - #[tokio::test] - async fn inbound_in_order() { - let (mut stream_handler, mut network_sender, mut inbound_channel_receiver, metadata, _, _) = - setup_test(); - - let stream_id = 127; - for i in 0..10 { - let message = make_test_message(stream_id, i, i == 9); - send(&mut network_sender, &metadata, message).await; - } - - let join_handle = tokio::spawn(async move { - let _ = tokio::time::timeout(TIMEOUT, stream_handler.run()).await; - }); - - join_handle.await.expect("Task should succeed"); - - let mut receiver = inbound_channel_receiver.next().await.unwrap(); - for _ in 0..9 { - // message number 9 is Fin, so it will not be sent! - let _ = receiver.next().await.unwrap(); - } - // Check that the receiver was closed: - assert!(matches!(receiver.try_next(), Ok(None))); - } - - #[tokio::test] - async fn inbound_in_reverse() { - let ( - mut stream_handler, - mut network_sender, - mut inbound_channel_receiver, - inbound_metadata, - _, - _, - ) = setup_test(); - let peer_id = inbound_metadata.originator_id.clone(); - let stream_id = 127; - - for i in 0..5 { - let message = make_test_message(stream_id, 5 - i, i == 0); - send(&mut network_sender, &inbound_metadata, message).await; - } - - // Run the loop for a short duration to process the message. - let join_handle = tokio::spawn(async move { - let _ = tokio::time::timeout(TIMEOUT, stream_handler.run()).await; - stream_handler - }); - let mut stream_handler = join_handle.await.expect("Task should succeed"); - - // Get the receiver for the stream. - let mut receiver = inbound_channel_receiver.next().await.unwrap(); - // Check that the channel is empty (no messages were sent yet). - assert!(receiver.try_next().is_err()); - - assert_eq!(stream_handler.inbound_stream_data.len(), 1); - assert_eq!( - stream_handler.inbound_stream_data[&(peer_id.clone(), stream_id)].message_buffer.len(), - 5 - ); - let range: Vec = (1..6).collect(); - let keys: Vec = stream_handler.inbound_stream_data[&(peer_id, stream_id)] - .clone() - .message_buffer - .into_keys() - .collect(); - assert!(do_vecs_match(&keys, &range)); - - // Now send the last message: - send(&mut network_sender, &inbound_metadata, make_test_message(stream_id, 0, false)).await; - - // Run the loop for a short duration to process the message. - let join_handle = tokio::spawn(async move { - let _ = tokio::time::timeout(TIMEOUT, stream_handler.run()).await; - stream_handler - }); - - let stream_handler = join_handle.await.expect("Task should succeed"); - assert!(stream_handler.inbound_stream_data.is_empty()); - - for _ in 0..5 { - // message number 5 is Fin, so it will not be sent! - let _ = receiver.next().await.unwrap(); - } - // Check that the receiver was closed: - assert!(matches!(receiver.try_next(), Ok(None))); - } - - #[tokio::test] - async fn inbound_multiple_streams() { - let ( - mut stream_handler, - mut network_sender, - mut inbound_channel_receiver, - inbound_metadata, - _, - _, - ) = setup_test(); - let peer_id = inbound_metadata.originator_id.clone(); - - let stream_id1 = 127; // Send all messages in order (except the first one). - let stream_id2 = 10; // Send in reverse order (except the first one). - let stream_id3 = 1; // Send in two batches, without the first one, don't send fin. - - for i in 1..10 { - let message = make_test_message(stream_id1, i, i == 9); - send(&mut network_sender, &inbound_metadata, message).await; - } - - for i in 0..5 { - let message = make_test_message(stream_id2, 5 - i, i == 0); - send(&mut network_sender, &inbound_metadata, message).await; - } - - for i in 5..10 { - let message = make_test_message(stream_id3, i, false); - send(&mut network_sender, &inbound_metadata, message).await; - } - - for i in 1..5 { - let message = make_test_message(stream_id3, i, false); - send(&mut network_sender, &inbound_metadata, message).await; - } - - // Run the loop for a short duration to process the message. - let join_handle = tokio::spawn(async move { - let _ = tokio::time::timeout(TIMEOUT, stream_handler.run()).await; - stream_handler - }); - let mut stream_handler = join_handle.await.expect("Task should succeed"); - - let values = [(peer_id.clone(), 1), (peer_id.clone(), 10), (peer_id.clone(), 127)]; - assert!( - stream_handler - .inbound_stream_data - .clone() - .into_keys() - .all(|item| values.contains(&item)) - ); - - // We have all message from 1 to 9 buffered. - assert!(do_vecs_match( - &stream_handler.inbound_stream_data[&(peer_id.clone(), stream_id1)] - .message_buffer - .clone() - .into_keys() - .collect::>(), - &(1..10).collect::>() - )); - - // We have all message from 1 to 5 buffered. - assert!(do_vecs_match( - &stream_handler.inbound_stream_data[&(peer_id.clone(), stream_id2)] - .message_buffer - .clone() - .into_keys() - .collect::>(), - &(1..6).collect::>() - )); - - // We have all message from 1 to 5 buffered. - assert!(do_vecs_match( - &stream_handler.inbound_stream_data[&(peer_id.clone(), stream_id3)] - .message_buffer - .clone() - .into_keys() - .collect::>(), - &(1..10).collect::>() - )); - - // Get the receiver for the first stream. - let mut receiver1 = inbound_channel_receiver.next().await.unwrap(); - - // Check that the channel is empty (no messages were sent yet). - assert!(receiver1.try_next().is_err()); - - // Get the receiver for the second stream. - let mut receiver2 = inbound_channel_receiver.next().await.unwrap(); - - // Check that the channel is empty (no messages were sent yet). - assert!(receiver2.try_next().is_err()); - - // Get the receiver for the third stream. - let mut receiver3 = inbound_channel_receiver.next().await.unwrap(); - - // Check that the channel is empty (no messages were sent yet). - assert!(receiver3.try_next().is_err()); - - // Send the last message on stream_id1: - send(&mut network_sender, &inbound_metadata, make_test_message(stream_id1, 0, false)).await; - - // Run the loop for a short duration to process the message. - let join_handle = tokio::spawn(async move { - let _ = tokio::time::timeout(TIMEOUT, stream_handler.run()).await; - stream_handler - }); - - // Should be able to read all the messages for stream_id1. - for _ in 0..9 { - // message number 9 is Fin, so it will not be sent! - let _ = receiver1.next().await.unwrap(); - } - let mut stream_handler = join_handle.await.expect("Task should succeed"); - - // stream_id1 should be gone - let values = [(peer_id.clone(), 1), (peer_id.clone(), 10)]; - assert!( - stream_handler - .inbound_stream_data - .clone() - .into_keys() - .all(|item| values.contains(&item)) - ); - - // Send the last message on stream_id2: - send(&mut network_sender, &inbound_metadata, make_test_message(stream_id2, 0, false)).await; - - // Run the loop for a short duration to process the message. - let join_handle = tokio::spawn(async move { - let _ = tokio::time::timeout(TIMEOUT, stream_handler.run()).await; - stream_handler - }); - - // Should be able to read all the messages for stream_id2. - for _ in 0..5 { - // message number 5 is Fin, so it will not be sent! - let _ = receiver2.next().await.unwrap(); - } - - let mut stream_handler = join_handle.await.expect("Task should succeed"); - - // Stream_id2 should also be gone. - let values = [(peer_id.clone(), 1)]; - assert!( - stream_handler - .inbound_stream_data - .clone() - .into_keys() - .all(|item| values.contains(&item)) - ); - - // Send the last message on stream_id3: - send(&mut network_sender, &inbound_metadata, make_test_message(stream_id3, 0, false)).await; - - // Run the loop for a short duration to process the message. - let join_handle = tokio::spawn(async move { - let _ = tokio::time::timeout(TIMEOUT, stream_handler.run()).await; - stream_handler - }); - - let stream_handler = join_handle.await.expect("Task should succeed"); - for _ in 0..10 { - // All messages are received, including number 9 which is not Fin - let _ = receiver3.next().await.unwrap(); - } - - // Stream_id3 should still be there, because we didn't send a fin. - let values = [(peer_id.clone(), 1)]; - assert!( - stream_handler - .inbound_stream_data - .clone() - .into_keys() - .all(|item| values.contains(&item)) - ); - - // But the buffer should be empty, as we've successfully drained it all. - assert!( - stream_handler.inbound_stream_data[&(peer_id, stream_id3)].message_buffer.is_empty() - ); - } - - // This test does two things: - // 1. Opens two outbound channels and checks that messages get correctly sent on both. - // 2. Closes the first channel and checks that Fin is sent and that the relevant structures - // inside the stream handler are cleaned up. - #[tokio::test] - async fn outbound_multiple_streams() { - let ( - mut stream_handler, - _, - _, - _, - mut broadcast_channel_sender, - mut broadcasted_messages_receiver, - ) = setup_test(); - - let stream_id1: StreamId = 42; - let stream_id2: StreamId = 127; - - // Start a new stream by sending the (stream_id, receiver). - let (mut sender1, receiver1) = mpsc::channel(CHANNEL_SIZE); - broadcast_channel_sender.send((stream_id1, receiver1)).await.unwrap(); - - // Send a message on the stream. - let message1 = ConsensusMessage::Proposal(Proposal::default()); - sender1.send(message1.clone()).await.unwrap(); - - // Run the loop for a short duration to process the message. - let join_handle = tokio::spawn(async move { - let _ = tokio::time::timeout(TIMEOUT, stream_handler.run()).await; - stream_handler - }); - - // Wait for an incoming message. - let broadcasted_message = broadcasted_messages_receiver.next().await.unwrap(); - let mut stream_handler = join_handle.await.expect("Task should succeed"); - - // Check that message was broadcasted. - assert_eq!(broadcasted_message.message, StreamMessageBody::Content(message1)); - assert_eq!(broadcasted_message.stream_id, stream_id1); - assert_eq!(broadcasted_message.message_id, 0); - - // Check that internally, stream_handler holds this receiver. - assert_eq!( - stream_handler.outbound_stream_receivers.keys().collect::>(), - vec![&stream_id1] - ); - // Check that the number of messages sent on this stream is 1. - assert_eq!(stream_handler.outbound_stream_number[&stream_id1], 1); - - // Send another message on the same stream. - let message2 = ConsensusMessage::Proposal(Proposal::default()); - sender1.send(message2.clone()).await.unwrap(); - - // Run the loop for a short duration to process the message. - let join_handle = tokio::spawn(async move { - let _ = tokio::time::timeout(TIMEOUT, stream_handler.run()).await; - stream_handler - }); - - // Wait for an incoming message. - let broadcasted_message = broadcasted_messages_receiver.next().await.unwrap(); - - let mut stream_handler = join_handle.await.expect("Task should succeed"); - - // Check that message was broadcasted. - assert_eq!(broadcasted_message.message, StreamMessageBody::Content(message2)); - assert_eq!(broadcasted_message.stream_id, stream_id1); - assert_eq!(broadcasted_message.message_id, 1); - assert_eq!(stream_handler.outbound_stream_number[&stream_id1], 2); - - // Start a new stream by sending the (stream_id, receiver). - let (mut sender2, receiver2) = mpsc::channel(CHANNEL_SIZE); - broadcast_channel_sender.send((stream_id2, receiver2)).await.unwrap(); - - // Send a message on the stream. - let message3 = ConsensusMessage::Proposal(Proposal::default()); - sender2.send(message3.clone()).await.unwrap(); - - // Run the loop for a short duration to process the message. - let join_handle = tokio::spawn(async move { - let _ = tokio::time::timeout(TIMEOUT, stream_handler.run()).await; - stream_handler - }); - - // Wait for an incoming message. - let broadcasted_message = broadcasted_messages_receiver.next().await.unwrap(); - - let mut stream_handler = join_handle.await.expect("Task should succeed"); - - // Check that message was broadcasted. - assert_eq!(broadcasted_message.message, StreamMessageBody::Content(message3)); - assert_eq!(broadcasted_message.stream_id, stream_id2); - assert_eq!(broadcasted_message.message_id, 0); - let mut vec1 = stream_handler.outbound_stream_receivers.keys().collect::>(); - vec1.sort(); - let mut vec2 = vec![&stream_id1, &stream_id2]; - vec2.sort(); - do_vecs_match(&vec1, &vec2); - assert_eq!(stream_handler.outbound_stream_number[&stream_id2], 1); - - // Close the first channel. - sender1.close_channel(); - - // Run the loop for a short duration to process that the channel was closed. - let join_handle = tokio::spawn(async move { - let _ = tokio::time::timeout(TIMEOUT, stream_handler.run()).await; - stream_handler - }); - - // Check that we got a fin message. - let broadcasted_message = broadcasted_messages_receiver.next().await.unwrap(); - assert_eq!(broadcasted_message.message, StreamMessageBody::Fin); - - let stream_handler = join_handle.await.expect("Task should succeed"); - - // Check that the information about this stream is gone. - assert_eq!( - stream_handler.outbound_stream_receivers.keys().collect::>(), - vec![&stream_id2] - ); - } -} diff --git a/crates/sequencing/papyrus_consensus/src/test_utils.rs b/crates/sequencing/papyrus_consensus/src/test_utils.rs deleted file mode 100644 index 303e30a049a..00000000000 --- a/crates/sequencing/papyrus_consensus/src/test_utils.rs +++ /dev/null @@ -1,101 +0,0 @@ -use std::time::Duration; - -use async_trait::async_trait; -use futures::channel::{mpsc, oneshot}; -use mockall::mock; -use papyrus_protobuf::consensus::{ConsensusMessage, Proposal, ProposalInit, Vote, VoteType}; -use starknet_api::block::{BlockHash, BlockNumber}; -use starknet_types_core::felt::Felt; - -use crate::types::{ConsensusContext, ConsensusError, ProposalContentId, Round, ValidatorId}; - -/// Define a consensus block which can be used to enable auto mocking Context. -#[derive(Debug, PartialEq, Clone)] -pub struct TestBlock { - pub content: Vec, - pub id: BlockHash, -} - -// TODO(matan): When QSelf is supported, switch to automocking `ConsensusContext`. -mock! { - pub TestContext {} - - #[async_trait] - impl ConsensusContext for TestContext { - type ProposalChunk = u32; - - async fn build_proposal( - &mut self, - init: ProposalInit, - timeout: Duration, - ) -> oneshot::Receiver; - - async fn validate_proposal( - &mut self, - height: BlockNumber, - timeout: Duration, - content: mpsc::Receiver - ) -> oneshot::Receiver; - - async fn repropose( - &mut self, - id: ProposalContentId, - init: ProposalInit, - ); - - async fn validators(&self, height: BlockNumber) -> Vec; - - fn proposer(&self, height: BlockNumber, round: Round) -> ValidatorId; - - async fn broadcast(&mut self, message: ConsensusMessage) -> Result<(), ConsensusError>; - - async fn decision_reached( - &mut self, - block: ProposalContentId, - precommits: Vec, - ) -> Result<(), ConsensusError>; - } -} - -pub fn prevote( - block_felt: Option, - height: u64, - round: u32, - voter: ValidatorId, -) -> ConsensusMessage { - let block_hash = block_felt.map(BlockHash); - ConsensusMessage::Vote(Vote { vote_type: VoteType::Prevote, height, round, block_hash, voter }) -} - -pub fn precommit( - block_felt: Option, - height: u64, - round: u32, - voter: ValidatorId, -) -> ConsensusMessage { - let block_hash = block_felt.map(BlockHash); - ConsensusMessage::Vote(Vote { - vote_type: VoteType::Precommit, - height, - round, - block_hash, - voter, - }) -} - -pub fn proposal( - block_felt: Felt, - height: u64, - round: u32, - proposer: ValidatorId, -) -> ConsensusMessage { - let block_hash = BlockHash(block_felt); - ConsensusMessage::Proposal(Proposal { - height, - block_hash, - round, - proposer, - transactions: Vec::new(), - valid_round: None, - }) -} diff --git a/crates/sequencing/papyrus_consensus_orchestrator/Cargo.toml b/crates/sequencing/papyrus_consensus_orchestrator/Cargo.toml deleted file mode 100644 index 7b91ad6ab37..00000000000 --- a/crates/sequencing/papyrus_consensus_orchestrator/Cargo.toml +++ /dev/null @@ -1,33 +0,0 @@ -[package] -name = "papyrus_consensus_orchestrator" -version.workspace = true -edition.workspace = true -repository.workspace = true -license-file.workspace = true -description = "Implements the consensus context and orchestrates the node's components accordingly" - -[dependencies] -async-trait.workspace = true -chrono.workspace = true -futures.workspace = true -papyrus_consensus.workspace = true -papyrus_network.workspace = true -papyrus_protobuf.workspace = true -papyrus_storage.workspace = true -starknet-types-core.workspace = true -starknet_api.workspace = true -starknet_batcher_types.workspace = true -tokio = { workspace = true, features = ["full"] } -tracing.workspace = true - -[dev-dependencies] -lazy_static.workspace = true -mockall.workspace = true -papyrus_network = { workspace = true, features = ["testing"] } -papyrus_storage = { workspace = true, features = ["testing"] } -papyrus_test_utils.workspace = true -starknet_batcher_types = { workspace = true, features = ["testing"] } -test-case.workspace = true - -[lints] -workspace = true diff --git a/crates/sequencing/papyrus_consensus_orchestrator/src/lib.rs b/crates/sequencing/papyrus_consensus_orchestrator/src/lib.rs deleted file mode 100644 index ff7de38c704..00000000000 --- a/crates/sequencing/papyrus_consensus_orchestrator/src/lib.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![warn(missing_docs)] -//! An orchestrator for a StarkNet node. -//! Implements the consensus context - the interface for consensus to call out to the node. - -#[allow(missing_docs)] -// TODO: this is test code, rename accordingly. -pub mod papyrus_consensus_context; -#[allow(missing_docs)] -pub mod sequencer_consensus_context; diff --git a/crates/sequencing/papyrus_consensus_orchestrator/src/papyrus_consensus_context.rs b/crates/sequencing/papyrus_consensus_orchestrator/src/papyrus_consensus_context.rs deleted file mode 100644 index 5779d8a1560..00000000000 --- a/crates/sequencing/papyrus_consensus_orchestrator/src/papyrus_consensus_context.rs +++ /dev/null @@ -1,275 +0,0 @@ -//! Implementation of the ConsensusContext interface for Papyrus. -//! -//! It connects to papyrus storage and runs consensus on actual blocks that already exist on the -//! network. Useful for testing the consensus algorithm without the need to actually build new -//! blocks. -#[cfg(test)] -#[path = "papyrus_consensus_context_test.rs"] -mod papyrus_consensus_context_test; - -use core::panic; -use std::collections::{BTreeMap, HashMap}; -use std::sync::{Arc, Mutex}; -use std::time::Duration; - -use async_trait::async_trait; -use futures::channel::{mpsc, oneshot}; -use futures::StreamExt; -use papyrus_consensus::types::{ - ConsensusContext, - ConsensusError, - ProposalContentId, - Round, - ValidatorId, -}; -use papyrus_network::network_manager::{BroadcastTopicClient, BroadcastTopicClientTrait}; -use papyrus_protobuf::consensus::{ConsensusMessage, Proposal, ProposalInit, Vote}; -use papyrus_storage::body::BodyStorageReader; -use papyrus_storage::header::HeaderStorageReader; -use papyrus_storage::{StorageError, StorageReader}; -use starknet_api::block::BlockNumber; -use starknet_api::core::ContractAddress; -use starknet_api::transaction::Transaction; -use tracing::{debug, debug_span, info, warn, Instrument}; - -// TODO: add debug messages and span to the tasks. - -type HeightToIdToContent = BTreeMap>>; - -pub struct PapyrusConsensusContext { - storage_reader: StorageReader, - network_broadcast_client: BroadcastTopicClient, - validators: Vec, - sync_broadcast_sender: Option>, - // Proposal building/validating returns immediately, leaving the actual processing to a spawned - // task. The spawned task processes the proposal asynchronously and updates the - // valid_proposals map upon completion, ensuring consistency across tasks. - valid_proposals: Arc>, -} - -impl PapyrusConsensusContext { - pub fn new( - storage_reader: StorageReader, - network_broadcast_client: BroadcastTopicClient, - num_validators: u64, - sync_broadcast_sender: Option>, - ) -> Self { - Self { - storage_reader, - network_broadcast_client, - validators: (0..num_validators).map(ContractAddress::from).collect(), - sync_broadcast_sender, - valid_proposals: Arc::new(Mutex::new(BTreeMap::new())), - } - } -} - -#[async_trait] -impl ConsensusContext for PapyrusConsensusContext { - type ProposalChunk = Transaction; - - async fn build_proposal( - &mut self, - init: ProposalInit, - _timeout: Duration, - ) -> oneshot::Receiver { - let mut network_broadcast_sender = self.network_broadcast_client.clone(); - let (fin_sender, fin_receiver) = oneshot::channel(); - - let storage_reader = self.storage_reader.clone(); - let valid_proposals = Arc::clone(&self.valid_proposals); - tokio::spawn( - async move { - // TODO(dvir): consider fix this for the case of reverts. If between the check that - // the block in storage and to getting the transaction was a revert - // this flow will fail. - wait_for_block(&storage_reader, init.height) - .await - .expect("Failed to wait to block"); - - let txn = storage_reader.begin_ro_txn().expect("Failed to begin ro txn"); - let transactions = txn - .get_block_transactions(init.height) - .expect("Get transactions from storage failed") - .unwrap_or_else(|| { - panic!( - "Block in {} was not found in storage despite waiting for it", - init.height - ) - }); - - let block_hash = txn - .get_block_header(init.height) - .expect("Get header from storage failed") - .unwrap_or_else(|| { - panic!( - "Block in {} was not found in storage despite waiting for it", - init.height - ) - }) - .block_hash; - - let proposal = Proposal { - height: init.height.0, - round: init.round, - proposer: init.proposer, - transactions: transactions.clone(), - block_hash, - valid_round: init.valid_round, - }; - network_broadcast_sender - .broadcast_message(ConsensusMessage::Proposal(proposal)) - .await - .expect("Failed to send proposal"); - { - let mut proposals = valid_proposals - .lock() - .expect("Lock on active proposals was poisoned due to a previous panic"); - proposals.entry(init.height).or_default().insert(block_hash, transactions); - } - // Done after inserting the proposal into the map to avoid race conditions between - // insertion and calls to `repropose`. - fin_sender.send(block_hash).expect("Send should succeed"); - } - .instrument(debug_span!("consensus_build_proposal")), - ); - - fin_receiver - } - - async fn validate_proposal( - &mut self, - height: BlockNumber, - _timeout: Duration, - mut content: mpsc::Receiver, - ) -> oneshot::Receiver { - let (fin_sender, fin_receiver) = oneshot::channel(); - - let storage_reader = self.storage_reader.clone(); - let valid_proposals = Arc::clone(&self.valid_proposals); - tokio::spawn( - async move { - // TODO(dvir): consider fix this for the case of reverts. If between the check that - // the block in storage and to getting the transaction was a revert - // this flow will fail. - wait_for_block(&storage_reader, height).await.expect("Failed to wait to block"); - - let txn = storage_reader.begin_ro_txn().expect("Failed to begin ro txn"); - let transactions = txn - .get_block_transactions(height) - .expect("Get transactions from storage failed") - .unwrap_or_else(|| { - panic!("Block in {height} was not found in storage despite waiting for it") - }); - - for tx in transactions.iter() { - let received_tx = content - .next() - .await - .unwrap_or_else(|| panic!("Not received transaction equals to {tx:?}")); - if tx != &received_tx { - panic!("Transactions are not equal. In storage: {tx:?}, : {received_tx:?}"); - } - } - - if content.next().await.is_some() { - panic!("Received more transactions than expected"); - } - - let block_hash = txn - .get_block_header(height) - .expect("Get header from storage failed") - .unwrap_or_else(|| { - panic!("Block in {height} was not found in storage despite waiting for it") - }) - .block_hash; - - let mut proposals = valid_proposals - .lock() - .expect("Lock on active proposals was poisoned due to a previous panic"); - - proposals.entry(height).or_default().insert(block_hash, transactions); - // Done after inserting the proposal into the map to avoid race conditions between - // insertion and calls to `repropose`. - // This can happen as a result of sync interrupting `run_height`. - fin_sender.send(block_hash).unwrap_or_else(|_| { - warn!("Failed to send block to consensus. height={height}"); - }) - } - .instrument(debug_span!("consensus_validate_proposal")), - ); - - fin_receiver - } - - async fn repropose(&mut self, id: ProposalContentId, init: ProposalInit) { - let transactions = self - .valid_proposals - .lock() - .expect("valid_proposals lock was poisoned") - .get(&init.height) - .unwrap_or_else(|| panic!("No proposals found for height {}", init.height)) - .get(&id) - .unwrap_or_else(|| panic!("No proposal found for height {} and id {}", init.height, id)) - .clone(); - - let proposal = Proposal { - height: init.height.0, - round: init.round, - proposer: init.proposer, - transactions, - block_hash: id, - valid_round: init.valid_round, - }; - self.network_broadcast_client - .broadcast_message(ConsensusMessage::Proposal(proposal)) - .await - .expect("Failed to send proposal"); - } - - async fn validators(&self, _height: BlockNumber) -> Vec { - self.validators.clone() - } - - fn proposer(&self, _height: BlockNumber, _round: Round) -> ValidatorId { - *self.validators.first().expect("there should be at least one validator") - } - - async fn broadcast(&mut self, message: ConsensusMessage) -> Result<(), ConsensusError> { - debug!("Broadcasting message: {message:?}"); - self.network_broadcast_client.broadcast_message(message).await?; - Ok(()) - } - - async fn decision_reached( - &mut self, - block: ProposalContentId, - precommits: Vec, - ) -> Result<(), ConsensusError> { - let height = precommits[0].height; - info!("Finished consensus for height: {height}. Agreed on block: {:#064x}", block.0); - if let Some(sender) = &mut self.sync_broadcast_sender { - sender.broadcast_message(precommits[0].clone()).await?; - } - - let mut proposals = self - .valid_proposals - .lock() - .expect("Lock on active proposals was poisoned due to a previous panic"); - proposals.retain(|&h, _| h > BlockNumber(height)); - Ok(()) - } -} - -const SLEEP_BETWEEN_CHECK_FOR_BLOCK: Duration = Duration::from_secs(10); - -async fn wait_for_block( - storage_reader: &StorageReader, - height: BlockNumber, -) -> Result<(), StorageError> { - while storage_reader.begin_ro_txn()?.get_body_marker()? <= height { - debug!("Waiting for block {height:?} to continue consensus"); - tokio::time::sleep(SLEEP_BETWEEN_CHECK_FOR_BLOCK).await; - } - Ok(()) -} diff --git a/crates/sequencing/papyrus_consensus_orchestrator/src/papyrus_consensus_context_test.rs b/crates/sequencing/papyrus_consensus_orchestrator/src/papyrus_consensus_context_test.rs deleted file mode 100644 index 9c7e5b9f966..00000000000 --- a/crates/sequencing/papyrus_consensus_orchestrator/src/papyrus_consensus_context_test.rs +++ /dev/null @@ -1,118 +0,0 @@ -use std::time::Duration; - -use futures::channel::{mpsc, oneshot}; -use futures::StreamExt; -use papyrus_consensus::types::ConsensusContext; -use papyrus_network::network_manager::test_utils::{ - mock_register_broadcast_topic, - BroadcastNetworkMock, -}; -use papyrus_protobuf::consensus::{ConsensusMessage, ProposalInit, Vote}; -use papyrus_storage::body::BodyStorageWriter; -use papyrus_storage::header::HeaderStorageWriter; -use papyrus_storage::test_utils::get_test_storage; -use papyrus_test_utils::get_test_block; -use starknet_api::block::{Block, BlockHash}; -use starknet_api::core::ContractAddress; - -use crate::papyrus_consensus_context::PapyrusConsensusContext; - -// TODO(dvir): consider adding tests for times, i.e, the calls are returned immediately and nothing -// happen until it should (for example, not creating a block before we have it in storage). - -const TEST_CHANNEL_SIZE: usize = 10; - -#[tokio::test] -async fn build_proposal() { - let (block, mut papyrus_context, _mock_network, _) = test_setup(); - let block_number = block.header.block_header_without_hash.block_number; - let proposal_init = ProposalInit { - height: block_number, - round: 0, - proposer: ContractAddress::default(), - valid_round: None, - }; - // TODO(Asmaa): Test proposal content. - let fin_receiver = papyrus_context.build_proposal(proposal_init, Duration::MAX).await; - - let fin = fin_receiver.await.unwrap(); - assert_eq!(fin, block.header.block_hash); -} - -#[tokio::test] -async fn validate_proposal_success() { - let (block, mut papyrus_context, _mock_network, _) = test_setup(); - let block_number = block.header.block_header_without_hash.block_number; - - let (mut validate_sender, validate_receiver) = mpsc::channel(TEST_CHANNEL_SIZE); - for tx in block.body.transactions.clone() { - validate_sender.try_send(tx).unwrap(); - } - validate_sender.close_channel(); - - let fin = papyrus_context - .validate_proposal(block_number, Duration::MAX, validate_receiver) - .await - .await - .unwrap(); - - assert_eq!(fin, block.header.block_hash); -} - -#[tokio::test] -async fn validate_proposal_fail() { - let (block, mut papyrus_context, _mock_network, _) = test_setup(); - let block_number = block.header.block_header_without_hash.block_number; - - let different_block = get_test_block(4, None, None, None); - let (mut validate_sender, validate_receiver) = mpsc::channel(5000); - for tx in different_block.body.transactions.clone() { - validate_sender.try_send(tx).unwrap(); - } - validate_sender.close_channel(); - - let fin = papyrus_context - .validate_proposal(block_number, Duration::MAX, validate_receiver) - .await - .await; - assert_eq!(fin, Err(oneshot::Canceled)); -} - -#[tokio::test] -async fn decision() { - let (_, mut papyrus_context, _, mut sync_network) = test_setup(); - let block = BlockHash::default(); - let precommit = Vote::default(); - papyrus_context.decision_reached(block, vec![precommit.clone()]).await.unwrap(); - assert_eq!(sync_network.messages_to_broadcast_receiver.next().await.unwrap(), precommit); -} - -fn test_setup() -> ( - Block, - PapyrusConsensusContext, - BroadcastNetworkMock, - BroadcastNetworkMock, -) { - let ((storage_reader, mut storage_writer), _temp_dir) = get_test_storage(); - let block = get_test_block(5, None, None, None); - let block_number = block.header.block_header_without_hash.block_number; - storage_writer - .begin_rw_txn() - .unwrap() - .append_header(block_number, &block.header) - .unwrap() - .append_body(block_number, block.body.clone()) - .unwrap() - .commit() - .unwrap(); - - let network_channels = mock_register_broadcast_topic().unwrap(); - let sync_channels = mock_register_broadcast_topic().unwrap(); - let papyrus_context = PapyrusConsensusContext::new( - storage_reader.clone(), - network_channels.subscriber_channels.broadcast_topic_client, - 4, - Some(sync_channels.subscriber_channels.broadcast_topic_client), - ); - (block, papyrus_context, network_channels.mock_network, sync_channels.mock_network) -} diff --git a/crates/sequencing/papyrus_consensus_orchestrator/src/sequencer_consensus_context.rs b/crates/sequencing/papyrus_consensus_orchestrator/src/sequencer_consensus_context.rs deleted file mode 100644 index 8ee354a4f91..00000000000 --- a/crates/sequencing/papyrus_consensus_orchestrator/src/sequencer_consensus_context.rs +++ /dev/null @@ -1,417 +0,0 @@ -//! Implementation of the ConsensusContext interface for running the sequencer. -//! -//! It connects to the Batcher who is responsible for building/validating blocks. -#[cfg(test)] -#[path = "sequencer_consensus_context_test.rs"] -mod sequencer_consensus_context_test; - -use std::collections::{BTreeMap, HashMap}; -use std::sync::{Arc, Mutex}; -use std::time::Duration; - -use async_trait::async_trait; -use futures::channel::{mpsc, oneshot}; -use futures::StreamExt; -use papyrus_consensus::types::{ - ConsensusContext, - ConsensusError, - ProposalContentId, - Round, - ValidatorId, -}; -use papyrus_network::network_manager::{BroadcastTopicClient, BroadcastTopicClientTrait}; -use papyrus_protobuf::consensus::{ - ConsensusMessage, - ProposalFin, - ProposalInit, - ProposalPart, - TransactionBatch, - Vote, -}; -use starknet_api::block::{BlockHash, BlockHashAndNumber, BlockNumber}; -use starknet_api::executable_transaction::Transaction; -use starknet_batcher_types::batcher_types::{ - DecisionReachedInput, - GetProposalContent, - GetProposalContentInput, - ProposalId, - ProposalStatus, - ProposeBlockInput, - SendProposalContent, - SendProposalContentInput, - StartHeightInput, - ValidateBlockInput, -}; -use starknet_batcher_types::communication::BatcherClient; -use tracing::{debug, debug_span, error, info, trace, warn, Instrument}; - -// {height: {proposal_id: (content, [proposal_ids])}} -// Note that multiple proposals IDs can be associated with the same content, but we only need to -// store one of them. -type HeightToIdToContent = - BTreeMap, ProposalId)>>; - -pub struct SequencerConsensusContext { - batcher: Arc, - validators: Vec, - // Proposal building/validating returns immediately, leaving the actual processing to a spawned - // task. The spawned task processes the proposal asynchronously and updates the - // valid_proposals map upon completion, ensuring consistency across tasks. - valid_proposals: Arc>, - // Used to generate unique proposal IDs across the lifetime of the context. - // TODO(matan): Consider robustness in case consensus can restart without the Batcher - // restarting. - proposal_id: u64, - current_height: Option, - network_broadcast_client: BroadcastTopicClient, -} - -impl SequencerConsensusContext { - pub fn new( - batcher: Arc, - network_broadcast_client: BroadcastTopicClient, - num_validators: u64, - ) -> Self { - Self { - batcher, - network_broadcast_client, - validators: (0..num_validators).map(ValidatorId::from).collect(), - valid_proposals: Arc::new(Mutex::new(HeightToIdToContent::new())), - proposal_id: 0, - current_height: None, - } - } -} - -#[async_trait] -impl ConsensusContext for SequencerConsensusContext { - // TODO: Switch to ProposalPart when Guy merges the PR. - type ProposalChunk = Vec; - - async fn build_proposal( - &mut self, - proposal_init: ProposalInit, - timeout: Duration, - ) -> oneshot::Receiver { - debug!( - "Building proposal for height: {} with timeout: {:?}", - proposal_init.height, timeout - ); - let (fin_sender, fin_receiver) = oneshot::channel(); - - let batcher = Arc::clone(&self.batcher); - let valid_proposals = Arc::clone(&self.valid_proposals); - - let proposal_id = ProposalId(self.proposal_id); - self.proposal_id += 1; - let timeout = - chrono::Duration::from_std(timeout).expect("Can't convert timeout to chrono::Duration"); - let build_proposal_input = ProposeBlockInput { - proposal_id, - // TODO: Discuss with batcher team passing std Duration instead. - deadline: chrono::Utc::now() + timeout, - // TODO: This is not part of Milestone 1. - retrospective_block_hash: Some(BlockHashAndNumber { - number: BlockNumber::default(), - hash: BlockHash::default(), - }), - }; - self.maybe_start_height(proposal_init.height).await; - // TODO: Should we be returning an error? - // I think this implies defining an error type in this crate and moving the trait definition - // here also. - debug!("Initiating proposal build: {build_proposal_input:?}"); - batcher - .propose_block(build_proposal_input) - .await - .expect("Failed to initiate proposal build"); - debug!("Broadcasting proposal init: {proposal_init:?}"); - self.network_broadcast_client - .broadcast_message(ProposalPart::Init(proposal_init.clone())) - .await - .expect("Failed to broadcast proposal init"); - let broadcast_client = self.network_broadcast_client.clone(); - tokio::spawn( - async move { - stream_build_proposal( - proposal_init.height, - proposal_id, - batcher, - valid_proposals, - broadcast_client, - fin_sender, - ) - .await; - } - .instrument(debug_span!("consensus_build_proposal")), - ); - - fin_receiver - } - - async fn validate_proposal( - &mut self, - height: BlockNumber, - timeout: Duration, - content: mpsc::Receiver, - ) -> oneshot::Receiver { - debug!("Validating proposal for height: {height} with timeout: {timeout:?}"); - let (fin_sender, fin_receiver) = oneshot::channel(); - let batcher = Arc::clone(&self.batcher); - let valid_proposals = Arc::clone(&self.valid_proposals); - let proposal_id = ProposalId(self.proposal_id); - self.proposal_id += 1; - - let chrono_timeout = - chrono::Duration::from_std(timeout).expect("Can't convert timeout to chrono::Duration"); - let input = ValidateBlockInput { - proposal_id, - deadline: chrono::Utc::now() + chrono_timeout, - // TODO(Matan 3/11/2024): Add the real value of the retrospective block hash. - retrospective_block_hash: Some(BlockHashAndNumber { - number: BlockNumber::default(), - hash: BlockHash::default(), - }), - }; - self.maybe_start_height(height).await; - batcher.validate_block(input).await.expect("Failed to initiate proposal validation"); - tokio::spawn( - async move { - let validate_fut = stream_validate_proposal( - height, - proposal_id, - batcher, - valid_proposals, - content, - fin_sender, - ); - if let Err(e) = tokio::time::timeout(timeout, validate_fut).await { - error!("Validation timed out. {e:?}"); - } - } - .instrument(debug_span!("consensus_validate_proposal")), - ); - - fin_receiver - } - - async fn repropose(&mut self, id: ProposalContentId, init: ProposalInit) { - let height = init.height; - debug!("Getting proposal for height: {height} and id: {id}"); - let (_transactions, _) = self - .valid_proposals - .lock() - .expect("Lock on active proposals was poisoned due to a previous panic") - .get(&height) - .unwrap_or_else(|| panic!("No proposals found for height {height}")) - .get(&id) - .unwrap_or_else(|| panic!("No proposal found for height {height} and id {id}")); - // TODO: Stream the TXs to the network. - } - - async fn validators(&self, _height: BlockNumber) -> Vec { - self.validators.clone() - } - - fn proposer(&self, _height: BlockNumber, _round: Round) -> ValidatorId { - *self.validators.first().expect("there should be at least one validator") - } - - async fn broadcast(&mut self, message: ConsensusMessage) -> Result<(), ConsensusError> { - debug!("No-op broadcasting message: {message:?}"); - Ok(()) - } - - async fn decision_reached( - &mut self, - block: ProposalContentId, - precommits: Vec, - ) -> Result<(), ConsensusError> { - let height = precommits[0].height; - info!("Finished consensus for height: {height}. Agreed on block: {:#064x}", block.0); - - // TODO(matan): Broadcast the decision to the network. - - let proposal_id; - { - let mut proposals = self - .valid_proposals - .lock() - .expect("Lock on active proposals was poisoned due to a previous panic"); - proposal_id = proposals.get(&BlockNumber(height)).unwrap().get(&block).unwrap().1; - proposals.retain(|&h, _| h > BlockNumber(height)); - } - self.batcher.decision_reached(DecisionReachedInput { proposal_id }).await.unwrap(); - - Ok(()) - } -} - -impl SequencerConsensusContext { - // The Batcher must be told when we begin to work on a new height. The implicit model is that - // consensus works on a given height until it is done (either a decision is reached or sync - // causes us to move on) and then moves on to a different height, never to return to the old - // height. - async fn maybe_start_height(&mut self, height: BlockNumber) { - if self.current_height == Some(height) { - return; - } - self.batcher - .start_height(StartHeightInput { height }) - .await - .expect("Batcher should be ready to start the next height"); - self.current_height = Some(height); - } -} - -// Handles building a new proposal without blocking consensus: -// 1. Receive chunks of content from the batcher. -// 2. Forward these to consensus to be streamed out to the network. -// 3. Once finished, receive the commitment from the batcher. -// 4. Store the proposal for re-proposal. -// 5. Send the commitment to consensus. -async fn stream_build_proposal( - height: BlockNumber, - proposal_id: ProposalId, - batcher: Arc, - valid_proposals: Arc>, - mut broadcast_client: BroadcastTopicClient, - fin_sender: oneshot::Sender, -) { - let mut content = Vec::new(); - loop { - let response = - match batcher.get_proposal_content(GetProposalContentInput { proposal_id }).await { - Ok(response) => response, - Err(e) => { - warn!("Failed to get proposal content: {e:?}"); - return; - } - }; - match response.content { - GetProposalContent::Txs(txs) => { - content.extend_from_slice(&txs[..]); - // TODO: Broadcast the transactions to the network. - // TODO(matan): Convert to protobuf and make sure this isn't too large for a single - // proto message (could this be a With adapter added to the channel in `new`?). - let mut transaction_hashes = Vec::with_capacity(txs.len()); - let mut transactions = Vec::with_capacity(txs.len()); - for tx in txs.into_iter() { - transaction_hashes.push(tx.tx_hash()); - transactions.push(tx.into()); - } - debug!("Broadcasting proposal content: {transaction_hashes:?}"); - trace!("Broadcasting proposal content: {transactions:?}"); - broadcast_client - .broadcast_message(ProposalPart::Transactions(TransactionBatch { - transactions, - tx_hashes: transaction_hashes, - })) - .await - .expect("Failed to broadcast proposal content"); - } - GetProposalContent::Finished(id) => { - let proposal_content_id = BlockHash(id.state_diff_commitment.0.0); - info!( - "Finished building proposal {:?}: content_id = {:?}, num_txs = {:?}, height = \ - {:?}", - proposal_id, - proposal_content_id, - content.len(), - height - ); - debug!("Broadcasting proposal fin: {proposal_content_id:?}"); - broadcast_client - .broadcast_message(ProposalPart::Fin(ProposalFin { proposal_content_id })) - .await - .expect("Failed to broadcast proposal fin"); - // Update valid_proposals before sending fin to avoid a race condition - // with `repropose` being called before `valid_proposals` is updated. - let mut valid_proposals = valid_proposals.lock().expect("Lock was poisoned"); - valid_proposals - .entry(height) - .or_default() - .insert(proposal_content_id, (content, proposal_id)); - if fin_sender.send(proposal_content_id).is_err() { - // Consensus may exit early (e.g. sync). - warn!("Failed to send proposal content id"); - } - return; - } - } - } -} - -// Handles receiving a proposal from another node without blocking consensus: -// 1. Receives the proposal content from the network. -// 2. Pass this to the batcher. -// 3. Once finished, receive the commitment from the batcher. -// 4. Store the proposal for re-proposal. -// 5. Send the commitment to consensus. -async fn stream_validate_proposal( - height: BlockNumber, - proposal_id: ProposalId, - batcher: Arc, - valid_proposals: Arc>, - mut content_receiver: mpsc::Receiver>, - fin_sender: oneshot::Sender, -) { - let mut content = Vec::new(); - while let Some(txs) = content_receiver.next().await { - content.extend_from_slice(&txs[..]); - let input = - SendProposalContentInput { proposal_id, content: SendProposalContent::Txs(txs) }; - let response = batcher.send_proposal_content(input).await.unwrap_or_else(|e| { - panic!("Failed to send proposal content to batcher: {proposal_id:?}. {e:?}") - }); - match response.response { - ProposalStatus::Processing => {} - ProposalStatus::Finished(fin) => { - panic!("Batcher returned Fin before all content was sent: {proposal_id:?} {fin:?}"); - } - ProposalStatus::Aborted => { - panic!("Unexpected abort response for proposal: {:?}", proposal_id); - } - ProposalStatus::InvalidProposal => { - warn!("Proposal was invalid: {:?}", proposal_id); - return; - } - } - } - // TODO: In the future we will receive a Fin from the network instead of the channel closing. - // We will just send the network Fin out along with what the batcher calculates. - let input = SendProposalContentInput { proposal_id, content: SendProposalContent::Finish }; - let response = batcher - .send_proposal_content(input) - .await - .unwrap_or_else(|e| panic!("Failed to send Fin to batcher: {proposal_id:?}. {e:?}")); - let id = match response.response { - ProposalStatus::Finished(id) => id, - ProposalStatus::Processing => { - panic!("Batcher failed to return Fin after all content was sent: {:?}", proposal_id); - } - ProposalStatus::Aborted => { - panic!("Unexpected abort response for proposal: {:?}", proposal_id); - } - ProposalStatus::InvalidProposal => { - warn!("Proposal was invalid: {:?}", proposal_id); - return; - } - }; - let proposal_content_id = BlockHash(id.state_diff_commitment.0.0); - info!( - "Finished validating proposal {:?}: content_id = {:?}, num_txs = {:?}, height = {:?}", - proposal_id, - proposal_content_id, - content.len(), - height - ); - // Update valid_proposals before sending fin to avoid a race condition - // with `get_proposal` being called before `valid_proposals` is updated. - let mut valid_proposals = valid_proposals.lock().unwrap(); - valid_proposals.entry(height).or_default().insert(proposal_content_id, (content, proposal_id)); - if fin_sender.send(proposal_content_id).is_err() { - // Consensus may exit early (e.g. sync). - warn!("Failed to send proposal content id"); - } -} diff --git a/crates/sequencing/papyrus_consensus_orchestrator/src/sequencer_consensus_context_test.rs b/crates/sequencing/papyrus_consensus_orchestrator/src/sequencer_consensus_context_test.rs deleted file mode 100644 index c5b1c127c50..00000000000 --- a/crates/sequencing/papyrus_consensus_orchestrator/src/sequencer_consensus_context_test.rs +++ /dev/null @@ -1,195 +0,0 @@ -use std::sync::{Arc, OnceLock}; -use std::time::Duration; -use std::vec; - -use futures::channel::mpsc; -use futures::SinkExt; -use lazy_static::lazy_static; -use papyrus_consensus::types::ConsensusContext; -use papyrus_network::network_manager::test_utils::{ - mock_register_broadcast_topic, - TestSubscriberChannels, -}; -use papyrus_network::network_manager::BroadcastTopicChannels; -use papyrus_protobuf::consensus::ProposalInit; -use starknet_api::block::{BlockHash, BlockNumber}; -use starknet_api::core::{ContractAddress, StateDiffCommitment}; -use starknet_api::executable_transaction::{AccountTransaction, Transaction}; -use starknet_api::hash::PoseidonHash; -use starknet_api::test_utils::invoke::{executable_invoke_tx, InvokeTxArgs}; -use starknet_api::transaction::TransactionHash; -use starknet_batcher_types::batcher_types::{ - GetProposalContent, - GetProposalContentResponse, - ProposalCommitment, - ProposalId, - ProposalStatus, - ProposeBlockInput, - SendProposalContent, - SendProposalContentInput, - SendProposalContentResponse, - StartHeightInput, - ValidateBlockInput, -}; -use starknet_batcher_types::communication::MockBatcherClient; -use starknet_types_core::felt::Felt; - -use crate::sequencer_consensus_context::SequencerConsensusContext; - -const TIMEOUT: Duration = Duration::from_millis(100); -const CHANNEL_SIZE: usize = 5000; -const NUM_VALIDATORS: u64 = 4; -const STATE_DIFF_COMMITMENT: StateDiffCommitment = StateDiffCommitment(PoseidonHash(Felt::ZERO)); - -lazy_static! { - static ref TX_BATCH: Vec = vec![generate_invoke_tx(Felt::THREE)]; -} - -fn generate_invoke_tx(tx_hash: Felt) -> Transaction { - Transaction::Account(AccountTransaction::Invoke(executable_invoke_tx(InvokeTxArgs { - tx_hash: TransactionHash(tx_hash), - ..Default::default() - }))) -} - -#[tokio::test] -async fn build_proposal() { - let mut batcher = MockBatcherClient::new(); - let proposal_id = Arc::new(OnceLock::new()); - let proposal_id_clone = Arc::clone(&proposal_id); - batcher.expect_propose_block().returning(move |input: ProposeBlockInput| { - proposal_id_clone.set(input.proposal_id).unwrap(); - Ok(()) - }); - batcher.expect_start_height().return_once(|input: StartHeightInput| { - assert_eq!(input.height, BlockNumber(0)); - Ok(()) - }); - let proposal_id_clone = Arc::clone(&proposal_id); - batcher.expect_get_proposal_content().times(1).returning(move |input| { - assert_eq!(input.proposal_id, *proposal_id_clone.get().unwrap()); - Ok(GetProposalContentResponse { content: GetProposalContent::Txs(TX_BATCH.clone()) }) - }); - let proposal_id_clone = Arc::clone(&proposal_id); - batcher.expect_get_proposal_content().times(1).returning(move |input| { - assert_eq!(input.proposal_id, *proposal_id_clone.get().unwrap()); - Ok(GetProposalContentResponse { - content: GetProposalContent::Finished(ProposalCommitment { - state_diff_commitment: STATE_DIFF_COMMITMENT, - }), - }) - }); - let TestSubscriberChannels { mock_network: _mock_network, subscriber_channels } = - mock_register_broadcast_topic().expect("Failed to create mock network"); - let BroadcastTopicChannels { broadcasted_messages_receiver: _, broadcast_topic_client } = - subscriber_channels; - let mut context = - SequencerConsensusContext::new(Arc::new(batcher), broadcast_topic_client, NUM_VALIDATORS); - let init = ProposalInit { - height: BlockNumber(0), - round: 0, - proposer: ContractAddress::default(), - valid_round: None, - }; - // TODO(Asmaa): Test proposal content. - let fin_receiver = context.build_proposal(init, TIMEOUT).await; - assert_eq!(fin_receiver.await.unwrap().0, STATE_DIFF_COMMITMENT.0.0); -} - -#[tokio::test] -async fn validate_proposal_success() { - let mut batcher = MockBatcherClient::new(); - let proposal_id: Arc> = Arc::new(OnceLock::new()); - let proposal_id_clone = Arc::clone(&proposal_id); - batcher.expect_validate_block().returning(move |input: ValidateBlockInput| { - proposal_id_clone.set(input.proposal_id).unwrap(); - Ok(()) - }); - batcher.expect_start_height().return_once(|input: StartHeightInput| { - assert_eq!(input.height, BlockNumber(0)); - Ok(()) - }); - let proposal_id_clone = Arc::clone(&proposal_id); - batcher.expect_send_proposal_content().times(1).returning( - move |input: SendProposalContentInput| { - assert_eq!(input.proposal_id, *proposal_id_clone.get().unwrap()); - let SendProposalContent::Txs(txs) = input.content else { - panic!("Expected SendProposalContent::Txs, got {:?}", input.content); - }; - assert_eq!(txs, TX_BATCH.clone()); - Ok(SendProposalContentResponse { response: ProposalStatus::Processing }) - }, - ); - let proposal_id_clone = Arc::clone(&proposal_id); - batcher.expect_send_proposal_content().times(1).returning( - move |input: SendProposalContentInput| { - assert_eq!(input.proposal_id, *proposal_id_clone.get().unwrap()); - assert!(matches!(input.content, SendProposalContent::Finish)); - Ok(SendProposalContentResponse { - response: ProposalStatus::Finished(ProposalCommitment { - state_diff_commitment: STATE_DIFF_COMMITMENT, - }), - }) - }, - ); - let TestSubscriberChannels { mock_network: _, subscriber_channels } = - mock_register_broadcast_topic().expect("Failed to create mock network"); - let BroadcastTopicChannels { broadcasted_messages_receiver: _, broadcast_topic_client } = - subscriber_channels; - let mut context = - SequencerConsensusContext::new(Arc::new(batcher), broadcast_topic_client, NUM_VALIDATORS); - let (mut content_sender, content_receiver) = mpsc::channel(CHANNEL_SIZE); - content_sender.send(TX_BATCH.clone()).await.unwrap(); - let fin_receiver = context.validate_proposal(BlockNumber(0), TIMEOUT, content_receiver).await; - content_sender.close_channel(); - assert_eq!(fin_receiver.await.unwrap().0, STATE_DIFF_COMMITMENT.0.0); -} - -#[tokio::test] -async fn repropose() { - // Receive a proposal. Then re-retrieve it. - let mut batcher = MockBatcherClient::new(); - batcher.expect_validate_block().returning(move |_| Ok(())); - batcher.expect_start_height().return_once(|input: StartHeightInput| { - assert_eq!(input.height, BlockNumber(0)); - Ok(()) - }); - batcher.expect_send_proposal_content().times(1).returning( - move |input: SendProposalContentInput| { - assert!(matches!(input.content, SendProposalContent::Txs(_))); - Ok(SendProposalContentResponse { response: ProposalStatus::Processing }) - }, - ); - batcher.expect_send_proposal_content().times(1).returning( - move |input: SendProposalContentInput| { - assert!(matches!(input.content, SendProposalContent::Finish)); - Ok(SendProposalContentResponse { - response: ProposalStatus::Finished(ProposalCommitment { - state_diff_commitment: STATE_DIFF_COMMITMENT, - }), - }) - }, - ); - let TestSubscriberChannels { mock_network: _, subscriber_channels } = - mock_register_broadcast_topic().expect("Failed to create mock network"); - let BroadcastTopicChannels { broadcasted_messages_receiver: _, broadcast_topic_client } = - subscriber_channels; - let mut context = - SequencerConsensusContext::new(Arc::new(batcher), broadcast_topic_client, NUM_VALIDATORS); - - // Receive a valid proposal. - let (mut content_sender, content_receiver) = mpsc::channel(CHANNEL_SIZE); - let txs = vec![generate_invoke_tx(Felt::TWO)]; - content_sender.send(txs.clone()).await.unwrap(); - let fin_receiver = context.validate_proposal(BlockNumber(0), TIMEOUT, content_receiver).await; - content_sender.close_channel(); - assert_eq!(fin_receiver.await.unwrap().0, STATE_DIFF_COMMITMENT.0.0); - - // Re-proposal: Just asserts this is a known valid proposal. - context - .repropose( - BlockHash(STATE_DIFF_COMMITMENT.0.0), - ProposalInit { height: BlockNumber(0), ..Default::default() }, - ) - .await; -} diff --git a/crates/shared_execution_objects/Cargo.toml b/crates/shared_execution_objects/Cargo.toml new file mode 100644 index 00000000000..8dd9be4589f --- /dev/null +++ b/crates/shared_execution_objects/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "shared_execution_objects" +version.workspace = true +edition.workspace = true +repository.workspace = true +license-file.workspace = true + +[features] +deserialize = ["blockifier/transaction_serde"] + +[dependencies] +blockifier.workspace = true +serde.workspace = true +starknet_api.workspace = true + +[lints] +workspace = true diff --git a/crates/shared_execution_objects/src/central_objects.rs b/crates/shared_execution_objects/src/central_objects.rs new file mode 100644 index 00000000000..1d6160bc95a --- /dev/null +++ b/crates/shared_execution_objects/src/central_objects.rs @@ -0,0 +1,61 @@ +use std::collections::HashMap; + +use blockifier::abi::constants as abi_constants; +use blockifier::execution::call_info::CallInfo; +use blockifier::fee::receipt::TransactionReceipt; +use blockifier::transaction::objects::{ExecutionResourcesTraits, TransactionExecutionInfo}; +use serde::Serialize; +use starknet_api::execution_resources::GasVector; +use starknet_api::transaction::fields::Fee; + +/// A mapping from a transaction execution resource to its actual usage. +#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))] +#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize)] +pub struct ResourcesMapping(pub HashMap); + +impl From for ResourcesMapping { + fn from(receipt: TransactionReceipt) -> ResourcesMapping { + let vm_resources = &receipt.resources.computation.vm_resources; + let mut resources = HashMap::from([( + abi_constants::N_STEPS_RESOURCE.to_string(), + vm_resources.total_n_steps() + receipt.resources.computation.n_reverted_steps, + )]); + resources.extend( + vm_resources + .prover_builtins() + .iter() + .map(|(builtin, value)| (builtin.to_str_with_suffix().to_string(), *value)), + ); + + ResourcesMapping(resources) + } +} + +/// The TransactionExecutionInfo object as used by the Python code. +#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))] +#[derive(Debug, Serialize)] +pub struct CentralTransactionExecutionInfo { + pub validate_call_info: Option, + pub execute_call_info: Option, + pub fee_transfer_call_info: Option, + pub actual_fee: Fee, + pub da_gas: GasVector, + pub actual_resources: ResourcesMapping, + pub revert_error: Option, + pub total_gas: GasVector, +} + +impl From for CentralTransactionExecutionInfo { + fn from(tx_execution_info: TransactionExecutionInfo) -> CentralTransactionExecutionInfo { + CentralTransactionExecutionInfo { + validate_call_info: tx_execution_info.validate_call_info, + execute_call_info: tx_execution_info.execute_call_info, + fee_transfer_call_info: tx_execution_info.fee_transfer_call_info, + actual_fee: tx_execution_info.receipt.fee, + da_gas: tx_execution_info.receipt.da_gas, + revert_error: tx_execution_info.revert_error.map(|error| error.to_string()), + total_gas: tx_execution_info.receipt.gas, + actual_resources: tx_execution_info.receipt.into(), + } + } +} diff --git a/crates/shared_execution_objects/src/lib.rs b/crates/shared_execution_objects/src/lib.rs new file mode 100644 index 00000000000..625ea25fa5c --- /dev/null +++ b/crates/shared_execution_objects/src/lib.rs @@ -0,0 +1,7 @@ +//! The `shared_execution_objects` crate contains execution objects shared between different crates. + +/// Contains a rust version of objects on the centralized Python side. These objects are used when +/// interacting with the centralized Python. +pub mod central_objects; +// TODO(Yael): add the execution objects from the blockifier: execution_info, bouncer_weights, +// commitment_state_diff. diff --git a/crates/starknet_api/Cargo.toml b/crates/starknet_api/Cargo.toml index 5fac49f236f..c893600e4da 100644 --- a/crates/starknet_api/Cargo.toml +++ b/crates/starknet_api/Cargo.toml @@ -11,22 +11,26 @@ testing = [] [dependencies] bitvec.workspace = true -cairo-lang-starknet-classes.workspace = true +cached.workspace = true cairo-lang-runner.workspace = true +cairo-lang-starknet-classes.workspace = true derive_more.workspace = true hex.workspace = true indexmap = { workspace = true, features = ["serde"] } -infra_utils.workspace = true itertools.workspace = true num-bigint.workspace = true +num-traits.workspace = true pretty_assertions.workspace = true primitive-types = { workspace = true, features = ["serde"] } +rand.workspace = true +semver.workspace = true serde = { workspace = true, features = ["derive", "rc"] } serde_json.workspace = true sha3.workspace = true starknet-crypto.workspace = true starknet-types-core = { workspace = true, features = ["hash"] } -strum.workspace = true +starknet_infra_utils.workspace = true +strum = { workspace = true, features = ["derive"] } strum_macros.workspace = true thiserror.workspace = true @@ -34,8 +38,5 @@ thiserror.workspace = true assert_matches.workspace = true rstest.workspace = true -[package.metadata.cargo-machete] -ignored = ["strum"] - [lints] workspace = true diff --git a/crates/papyrus_common/resources/class.json b/crates/starknet_api/resources/class.json similarity index 100% rename from crates/papyrus_common/resources/class.json rename to crates/starknet_api/resources/class.json diff --git a/crates/starknet_api/src/block.rs b/crates/starknet_api/src/block.rs index 32dde80eac8..960cdc76c17 100644 --- a/crates/starknet_api/src/block.rs +++ b/crates/starknet_api/src/block.rs @@ -6,8 +6,10 @@ use itertools::Itertools; use serde::{Deserialize, Serialize}; use starknet_types_core::felt::Felt; use starknet_types_core::hash::{Poseidon, StarkHash as CoreStarkHash}; +use strum_macros::EnumIter; use crate::core::{ + ContractAddress, EventCommitment, GlobalRoot, ReceiptCommitment, @@ -28,8 +30,9 @@ use crate::StarknetApiError; /// A block. #[derive(Debug, Default, Clone, Eq, PartialEq, Deserialize, Serialize)] pub struct Block { - // TODO: Consider renaming to BlockWithCommitments, for the header use BlockHeaderWithoutHash - // instead of BlockHeader, and add BlockHeaderCommitments and BlockHash fields. + // TODO(YoavGr): Consider renaming to BlockWithCommitments, for the header use + // BlockHeaderWithoutHash instead of BlockHeader, and add BlockHeaderCommitments and + // BlockHash fields. pub header: BlockHeader, pub body: BlockBody, } @@ -96,7 +99,9 @@ starknet_version_enum! { (V0_13_2_1, 0, 13, 2, 1), (V0_13_3, 0, 13, 3), (V0_13_4, 0, 13, 4), - V0_13_4 + (V0_13_5, 0, 13, 5), + (V0_14_0, 0, 14, 0), + V0_14_0 } impl Default for StarknetVersion { @@ -166,13 +171,13 @@ impl<'de> Deserialize<'de> for StarknetVersion { /// The header of a [Block](`crate::block::Block`). #[derive(Debug, Default, Clone, Eq, PartialEq, Hash, Deserialize, Serialize, PartialOrd, Ord)] pub struct BlockHeader { - // TODO: Consider removing the block hash from the header (note it can be computed from + // TODO(Gilad): Consider removing the block hash from the header (note it can be computed from // the rest of the fields. pub block_hash: BlockHash, pub block_header_without_hash: BlockHeaderWithoutHash, // The optional fields below are not included in older versions of the block. // Currently they are not included in any RPC spec, so we skip their serialization. - // TODO: Once all environments support these fields, remove the Option (make sure to + // TODO(Yair): Once all environments support these fields, remove the Option (make sure to // update/resync any storage is missing the data). #[serde(skip_serializing)] pub state_diff_commitment: Option, @@ -198,6 +203,10 @@ pub struct BlockHeaderWithoutHash { pub l1_gas_price: GasPricePerToken, pub l1_data_gas_price: GasPricePerToken, pub l2_gas_price: GasPricePerToken, + // TODO(Ayelet): Change to GasAmount. + pub l2_gas_consumed: u64, + // TODO(Ayelet): Change to GasPrice. + pub next_l2_gas_price: u64, pub state_root: GlobalRoot, pub sequencer: SequencerContractAddress, pub timestamp: BlockTimestamp, @@ -374,7 +383,9 @@ impl GasPrice { /// Utility struct representing a non-zero gas price. Useful when a gas amount must be computed by /// taking a fee amount and dividing by the gas price. -#[derive(Copy, Clone, Debug, Deserialize, Serialize, derive_more::Display)] +#[derive( + Copy, Clone, Debug, Deserialize, Eq, PartialEq, Serialize, PartialOrd, Ord, derive_more::Display, +)] pub struct NonzeroGasPrice(GasPrice); impl NonzeroGasPrice { @@ -437,19 +448,65 @@ macro_rules! impl_try_from_uint_for_nonzero_gas_price { impl_try_from_uint_for_nonzero_gas_price!(u8, u16, u32, u64, u128); -#[derive(Clone, Debug, Deserialize, Serialize)] +// TODO(Arni): Remove derive of Default. Gas prices should always be set. +#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] pub struct GasPriceVector { pub l1_gas_price: NonzeroGasPrice, pub l1_data_gas_price: NonzeroGasPrice, pub l2_gas_price: NonzeroGasPrice, } +#[derive(Clone, Copy, Hash, EnumIter, Eq, PartialEq)] +pub enum FeeType { + Strk, + Eth, +} + +// TODO(Arni): Remove derive of Default. Gas prices should always be set. +#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] +pub struct GasPrices { + pub eth_gas_prices: GasPriceVector, // In wei. + pub strk_gas_prices: GasPriceVector, // In fri. +} + +impl GasPrices { + pub fn l1_gas_price(&self, fee_type: &FeeType) -> NonzeroGasPrice { + self.gas_price_vector(fee_type).l1_gas_price + } + + pub fn l1_data_gas_price(&self, fee_type: &FeeType) -> NonzeroGasPrice { + self.gas_price_vector(fee_type).l1_data_gas_price + } + + pub fn l2_gas_price(&self, fee_type: &FeeType) -> NonzeroGasPrice { + self.gas_price_vector(fee_type).l2_gas_price + } + + pub fn gas_price_vector(&self, fee_type: &FeeType) -> &GasPriceVector { + match fee_type { + FeeType::Strk => &self.strk_gas_prices, + FeeType::Eth => &self.eth_gas_prices, + } + } +} + /// The timestamp of a [Block](`crate::block::Block`). #[derive( Debug, Default, Copy, Clone, Eq, PartialEq, Hash, Deserialize, Serialize, PartialOrd, Ord, )] pub struct BlockTimestamp(pub u64); +#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] +pub struct BlockInfo { + pub block_number: BlockNumber, + pub block_timestamp: BlockTimestamp, + + // Fee-related. + pub sequencer_address: ContractAddress, + pub gas_prices: GasPrices, + pub use_kzg_da: bool, +} + /// The signature of a [Block](`crate::block::Block`), signed by the sequencer. The signed message /// is defined as poseidon_hash(block_hash, state_diff_commitment). #[derive( diff --git a/crates/starknet_api/src/block_hash/block_hash_calculator.rs b/crates/starknet_api/src/block_hash/block_hash_calculator.rs index e948bd4b39f..4c00d2784df 100644 --- a/crates/starknet_api/src/block_hash/block_hash_calculator.rs +++ b/crates/starknet_api/src/block_hash/block_hash_calculator.rs @@ -237,6 +237,7 @@ fn to_64_bits(num: usize) -> [u8; 8] { // )]. // Otherwise, returns: // [gas_price_wei, gas_price_fri, data_gas_price_wei, data_gas_price_fri]. +// TODO(Ayelet): add l2_gas_consumed, next_l2_gas_price after 0.14.0. fn gas_prices_to_hash( l1_gas_price: &GasPricePerToken, l1_data_gas_price: &GasPricePerToken, diff --git a/crates/starknet_api/src/block_hash/block_hash_calculator_test.rs b/crates/starknet_api/src/block_hash/block_hash_calculator_test.rs index 7adb1ad0942..ed2cd5e4cc9 100644 --- a/crates/starknet_api/src/block_hash/block_hash_calculator_test.rs +++ b/crates/starknet_api/src/block_hash/block_hash_calculator_test.rs @@ -28,21 +28,24 @@ use crate::core::{ TransactionCommitment, }; use crate::data_availability::L1DataAvailabilityMode; -use crate::felt; use crate::hash::PoseidonHash; use crate::transaction::fields::TransactionSignature; -use crate::transaction::TransactionHash; +use crate::{felt, tx_hash}; /// Macro to test if changing any field in the header or commitments /// results a change in the block hash. /// The macro clones the original header and commitments, modifies each specified field, /// and asserts that the block hash changes as a result. +/// Allows excluding specific fields that aren't part of the hash. macro_rules! test_hash_changes { ( - BlockHeaderWithoutHash { $($header_field:ident: $header_value:expr),* }, - BlockHeaderCommitments { $($commitments_field:ident: $commitments_value:expr),* } + BlockHeaderWithoutHash { $($header_field:ident: $header_value:expr),* $(,)? }, + BlockHeaderCommitments { $($commitments_field:ident: $commitments_value:expr),* $(,)? }, + exclude_header_fields = [ $( $excluded_field:ident ),* $(,)? ] ) => { { + let excluded_fields = vec![$(stringify!($excluded_field)),*]; + let header = BlockHeaderWithoutHash { l1_da_mode: L1DataAvailabilityMode::Blob, starknet_version: BlockHashVersion::V0_13_4.into(), @@ -54,11 +57,17 @@ macro_rules! test_hash_changes { let original_hash = calculate_block_hash(header.clone(), commitments.clone()).unwrap(); $( - // Test changing the field in the header. let mut modified_header = header.clone(); modified_header.$header_field = Default::default(); let new_hash = calculate_block_hash(modified_header, commitments.clone()).unwrap(); - assert_ne!(original_hash, new_hash, concat!("Hash should change when ", stringify!($header_field), " is modified")); + if excluded_fields.contains(&stringify!($header_field)) { + // Hash should not change. + assert_eq!(original_hash, new_hash, concat!("Hash should NOT change when ", stringify!($header_field), " is modified")); + } + else{ + // Hash should change. + assert_ne!(original_hash, new_hash, concat!("Hash should change when ", stringify!($header_field), " is modified")); + } )* $( @@ -89,13 +98,15 @@ fn test_block_hash_regression( price_in_wei: 9_u8.into(), }, l2_gas_price: GasPricePerToken { price_in_fri: 11_u8.into(), price_in_wei: 12_u8.into() }, + l2_gas_consumed: 13, + next_l2_gas_price: 14, starknet_version: block_hash_version.clone().into(), parent_hash: BlockHash(Felt::from(11_u8)), }; let transactions_data = vec![TransactionHashingData { transaction_signature: TransactionSignature(vec![Felt::TWO, Felt::THREE]), transaction_output: get_transaction_output(), - transaction_hash: TransactionHash(Felt::ONE), + transaction_hash: tx_hash!(1), }]; let state_diff = get_state_diff(); @@ -162,6 +173,8 @@ fn change_field_of_hash_input() { price_in_wei: 1_u8.into(), }, l2_gas_price: GasPricePerToken { price_in_fri: 1_u8.into(), price_in_wei: 1_u8.into() }, + l2_gas_consumed: 1, + next_l2_gas_price: 1, state_root: GlobalRoot(Felt::ONE), sequencer: SequencerContractAddress(ContractAddress::from(1_u128)), timestamp: BlockTimestamp(1) @@ -172,7 +185,11 @@ fn change_field_of_hash_input() { receipt_commitment: ReceiptCommitment(Felt::ONE), state_diff_commitment: StateDiffCommitment(PoseidonHash(Felt::ONE)), concatenated_counts: Felt::ONE - } + }, + // Excluding l2_gas_consumed, l2_gas_consumed as they're not currently included in the + // block hash. + // TODO(Ayelet): Remove these fields after 0.14.0, once they are included in the hash. + exclude_header_fields = [l2_gas_consumed, next_l2_gas_price] ); // TODO(Aviv, 10/06/2024): add tests that changes the first hash input, and the const zero. } diff --git a/crates/starknet_api/src/block_hash/event_commitment_test.rs b/crates/starknet_api/src/block_hash/event_commitment_test.rs index 5c483842686..7fc0752bfb3 100644 --- a/crates/starknet_api/src/block_hash/event_commitment_test.rs +++ b/crates/starknet_api/src/block_hash/event_commitment_test.rs @@ -3,8 +3,8 @@ use starknet_types_core::hash::Poseidon; use super::{calculate_event_commitment, calculate_event_hash, EventLeafElement}; use crate::core::EventCommitment; -use crate::transaction::{Event, EventContent, EventData, EventKey, TransactionHash}; -use crate::{contract_address, felt}; +use crate::transaction::{Event, EventContent, EventData, EventKey}; +use crate::{contract_address, felt, tx_hash}; #[test] fn test_event_commitment_regression() { @@ -39,6 +39,6 @@ fn get_event_leaf_element(seed: u8) -> EventLeafElement { ), }, }, - transaction_hash: TransactionHash(felt!("0x1234")), + transaction_hash: tx_hash!(0x1234), } } diff --git a/crates/starknet_api/src/block_hash/receipt_commitment_test.rs b/crates/starknet_api/src/block_hash/receipt_commitment_test.rs index 53dc119f785..3d9c5c57208 100644 --- a/crates/starknet_api/src/block_hash/receipt_commitment_test.rs +++ b/crates/starknet_api/src/block_hash/receipt_commitment_test.rs @@ -10,17 +10,13 @@ use crate::block_hash::receipt_commitment::{ }; use crate::block_hash::test_utils::{generate_message_to_l1, get_transaction_output}; use crate::core::ReceiptCommitment; -use crate::felt; -use crate::transaction::{ - RevertedTransactionExecutionStatus, - TransactionExecutionStatus, - TransactionHash, -}; +use crate::transaction::{RevertedTransactionExecutionStatus, TransactionExecutionStatus}; +use crate::{felt, tx_hash}; #[test] fn test_receipt_hash_regression() { let transaction_receipt = ReceiptElement { - transaction_hash: TransactionHash(Felt::from(1234_u16)), + transaction_hash: tx_hash!(1234), transaction_output: get_transaction_output(), }; diff --git a/crates/starknet_api/src/block_hash/state_diff_hash.rs b/crates/starknet_api/src/block_hash/state_diff_hash.rs index 147f56a2862..c04e95f7cef 100644 --- a/crates/starknet_api/src/block_hash/state_diff_hash.rs +++ b/crates/starknet_api/src/block_hash/state_diff_hash.rs @@ -30,11 +30,7 @@ static STARKNET_STATE_DIFF0: LazyLock = LazyLock::new(|| { pub fn calculate_state_diff_hash(state_diff: &ThinStateDiff) -> StateDiffCommitment { let mut hash_chain = HashChain::new(); hash_chain = hash_chain.chain(&STARKNET_STATE_DIFF0); - hash_chain = chain_updated_contracts( - &state_diff.deployed_contracts, - &state_diff.replaced_classes, - hash_chain, - ); + hash_chain = chain_deployed_contracts(&state_diff.deployed_contracts, hash_chain); hash_chain = chain_declared_classes(&state_diff.declared_classes, hash_chain); hash_chain = chain_deprecated_declared_classes(&state_diff.deprecated_declared_classes, hash_chain); @@ -47,14 +43,12 @@ pub fn calculate_state_diff_hash(state_diff: &ThinStateDiff) -> StateDiffCommitm // Chains: [number_of_updated_contracts, address_0, class_hash_0, address_1, class_hash_1, ...]. // The updated contracts includes deployed contracts and replaced classes. -fn chain_updated_contracts( +fn chain_deployed_contracts( deployed_contracts: &IndexMap, - replaced_classes: &IndexMap, mut hash_chain: HashChain, ) -> HashChain { - let updated_contracts = deployed_contracts.iter().chain(replaced_classes.iter()); - hash_chain = hash_chain.chain(&(deployed_contracts.len() + replaced_classes.len()).into()); - for (address, class_hash) in sorted_index_map(&updated_contracts.collect()) { + hash_chain = hash_chain.chain(&deployed_contracts.len().into()); + for (address, class_hash) in sorted_index_map(&deployed_contracts.iter().collect()) { hash_chain = hash_chain.chain(&address.0).chain(class_hash); } hash_chain diff --git a/crates/starknet_api/src/block_hash/state_diff_hash_test.rs b/crates/starknet_api/src/block_hash/state_diff_hash_test.rs index c0cadf2ef23..ee767452a27 100644 --- a/crates/starknet_api/src/block_hash/state_diff_hash_test.rs +++ b/crates/starknet_api/src/block_hash/state_diff_hash_test.rs @@ -3,10 +3,10 @@ use indexmap::indexmap; use crate::block_hash::state_diff_hash::{ calculate_state_diff_hash, chain_declared_classes, + chain_deployed_contracts, chain_deprecated_declared_classes, chain_nonces, chain_storage_diffs, - chain_updated_contracts, }; use crate::block_hash::test_utils::get_state_diff; use crate::core::{ClassHash, CompiledClassHash, Nonce, StateDiffCommitment}; @@ -30,22 +30,16 @@ fn test_sorting_deployed_contracts() { let deployed_contracts_0 = indexmap! { 0u64.into() => ClassHash(3u64.into()), 1u64.into() => ClassHash(2u64.into()), - }; - let replaced_classes_0 = indexmap! { 2u64.into() => ClassHash(1u64.into()), }; let deployed_contracts_1 = indexmap! { 2u64.into() => ClassHash(1u64.into()), 0u64.into() => ClassHash(3u64.into()), - }; - let replaced_classes_1 = indexmap! { 1u64.into() => ClassHash(2u64.into()), }; assert_eq!( - chain_updated_contracts(&deployed_contracts_0, &replaced_classes_0, HashChain::new()) - .get_poseidon_hash(), - chain_updated_contracts(&deployed_contracts_1, &replaced_classes_1, HashChain::new()) - .get_poseidon_hash(), + chain_deployed_contracts(&deployed_contracts_0, HashChain::new()).get_poseidon_hash(), + chain_deployed_contracts(&deployed_contracts_1, HashChain::new()).get_poseidon_hash(), ); } diff --git a/crates/starknet_api/src/block_hash/test_utils.rs b/crates/starknet_api/src/block_hash/test_utils.rs index 620a8e52102..008b6f737cb 100644 --- a/crates/starknet_api/src/block_hash/test_utils.rs +++ b/crates/starknet_api/src/block_hash/test_utils.rs @@ -45,6 +45,7 @@ pub(crate) fn get_state_diff() -> ThinStateDiff { deployed_contracts: indexmap! { 0u64.into() => ClassHash(1u64.into()), 2u64.into() => ClassHash(3u64.into()), + 19u64.into() => ClassHash(20u64.into()), }, storage_diffs: indexmap! { 4u64.into() => indexmap! { @@ -63,8 +64,5 @@ pub(crate) fn get_state_diff() -> ThinStateDiff { nonces: indexmap! { 17u64.into() => Nonce(18u64.into()), }, - replaced_classes: indexmap! { - 19u64.into() => ClassHash(20u64.into()), - }, } } diff --git a/crates/starknet_api/src/block_hash/transaction_commitment_test.rs b/crates/starknet_api/src/block_hash/transaction_commitment_test.rs index a8287d28c14..df48e360132 100644 --- a/crates/starknet_api/src/block_hash/transaction_commitment_test.rs +++ b/crates/starknet_api/src/block_hash/transaction_commitment_test.rs @@ -7,9 +7,8 @@ use crate::block_hash::transaction_commitment::{ calculate_transaction_leaf, }; use crate::core::TransactionCommitment; -use crate::felt; use crate::transaction::fields::TransactionSignature; -use crate::transaction::TransactionHash; +use crate::{felt, tx_hash}; #[test] fn test_transaction_leaf_regression() { @@ -22,7 +21,7 @@ fn test_transaction_leaf_regression() { #[test] fn test_transaction_leaf_without_signature_regression() { let transaction_leaf_elements = TransactionLeafElement { - transaction_hash: TransactionHash(Felt::ONE), + transaction_hash: tx_hash!(1), transaction_signature: TransactionSignature(vec![]), }; let expected_leaf = felt!("0x579e8877c7755365d5ec1ec7d3a94a457eff5d1f40482bbe9729c064cdead2"); @@ -45,7 +44,7 @@ fn test_transaction_commitment_regression() { } fn get_transaction_leaf_element() -> TransactionLeafElement { - let transaction_hash = TransactionHash(Felt::ONE); + let transaction_hash = tx_hash!(1); let transaction_signature = TransactionSignature(vec![Felt::TWO, Felt::THREE]); TransactionLeafElement { transaction_hash, transaction_signature } } diff --git a/crates/starknet_api/src/class_cache.rs b/crates/starknet_api/src/class_cache.rs new file mode 100644 index 00000000000..fe3d91b4b09 --- /dev/null +++ b/crates/starknet_api/src/class_cache.rs @@ -0,0 +1,38 @@ +use std::sync::{Arc, Mutex, MutexGuard}; + +use cached::{Cached, SizedCache}; + +use crate::core::ClassHash; + +type ContractLRUCache = SizedCache; +type LockedClassCache<'a, T> = MutexGuard<'a, ContractLRUCache>; + +// TODO(Yoni, 1/2/2025): consider defining CachedStateReader. +/// Thread-safe LRU cache for contract classes (Sierra or compiled Casm/Native), optimized for +/// inter-language sharing when `blockifier` compiles as a shared library. +#[derive(Clone, Debug)] +pub struct GlobalContractCache(pub Arc>>); + +impl GlobalContractCache { + /// Locks the cache for atomic access. Although conceptually shared, writing to this cache is + /// only possible for one writer at a time. + pub fn lock(&self) -> LockedClassCache<'_, T> { + self.0.lock().expect("Global contract cache is poisoned.") + } + + pub fn get(&self, class_hash: &ClassHash) -> Option { + self.lock().cache_get(class_hash).cloned() + } + + pub fn set(&self, class_hash: ClassHash, contract_class: T) { + self.lock().cache_set(class_hash, contract_class); + } + + pub fn clear(&mut self) { + self.lock().cache_clear(); + } + + pub fn new(cache_size: usize) -> Self { + Self(Arc::new(Mutex::new(ContractLRUCache::::with_size(cache_size)))) + } +} diff --git a/crates/starknet_api/src/consensus_transaction.rs b/crates/starknet_api/src/consensus_transaction.rs new file mode 100644 index 00000000000..d5e87214524 --- /dev/null +++ b/crates/starknet_api/src/consensus_transaction.rs @@ -0,0 +1,26 @@ +use serde::{Deserialize, Serialize}; + +use crate::rpc_transaction::{InternalRpcTransaction, RpcTransaction}; +use crate::transaction::TransactionHash; +use crate::{executable_transaction, transaction}; + +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize, Hash)] +pub enum ConsensusTransaction { + RpcTransaction(RpcTransaction), + L1Handler(transaction::L1HandlerTransaction), +} + +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize, Hash)] +pub enum InternalConsensusTransaction { + RpcTransaction(InternalRpcTransaction), + L1Handler(executable_transaction::L1HandlerTransaction), +} + +impl InternalConsensusTransaction { + pub fn tx_hash(&self) -> TransactionHash { + match self { + Self::RpcTransaction(tx) => tx.tx_hash, + Self::L1Handler(tx) => tx.tx_hash, + } + } +} diff --git a/crates/starknet_api/src/contract_class.rs b/crates/starknet_api/src/contract_class.rs index f103a13eaed..55611d2b3e9 100644 --- a/crates/starknet_api/src/contract_class.rs +++ b/crates/starknet_api/src/contract_class.rs @@ -1,4 +1,10 @@ +use std::fmt::Display; +use std::str::FromStr; + use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass; +use cairo_lang_starknet_classes::compiler_version::VersionId; +use derive_more::Deref; +use semver::Version; use serde::{Deserialize, Serialize}; use crate::core::CompiledClassHash; @@ -25,23 +31,114 @@ pub enum EntryPointType { L1Handler, } +fn u64_to_usize(val: u64) -> usize { + val.try_into().expect("Failed to convert u64 version tag to usize.") +} + +pub type VersionedCasm = (CasmContractClass, SierraVersion); + /// Represents a raw Starknet contract class. #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize, derive_more::From)] pub enum ContractClass { V0(DeprecatedContractClass), - V1(CasmContractClass), + V1(VersionedCasm), } impl ContractClass { pub fn compiled_class_hash(&self) -> CompiledClassHash { match self { ContractClass::V0(_) => panic!("Cairo 0 doesn't have compiled class hash."), - ContractClass::V1(casm_contract_class) => { + ContractClass::V1((casm_contract_class, _sierra_version)) => { CompiledClassHash(casm_contract_class.compiled_class_hash()) } } } } + +#[derive(Deref, Serialize, Deserialize, Clone, Debug, Eq, PartialEq, PartialOrd)] +pub struct SierraVersion(Version); + +impl From for VersionId { + fn from(val: SierraVersion) -> Self { + VersionId { + major: u64_to_usize(val.0.major), + minor: u64_to_usize(val.0.minor), + patch: u64_to_usize(val.0.patch), + } + } +} + +impl SierraVersion { + /// Version of deprecated contract class (Cairo 0). + pub const DEPRECATED: Self = Self(Version::new(0, 0, 0)); + + // TODO(Aviv): Implement logic to fetch the latest version dynamically from Cargo.toml and write + // tests to ensure that it matches the value returned by this function. + pub const LATEST: Self = Self(Version::new(2, 8, 4)); + + pub fn new(major: u64, minor: u64, patch: u64) -> Self { + Self(Version::new(major, minor, patch)) + } + + /// Converts a sierra program to a SierraVersion. + /// The sierra program is a list of felts. + /// The first 3 felts are the major, minor and patch version. + /// The rest of the felts are ignored. + pub fn extract_from_program(sierra_program: &[F]) -> Result + // TODO(Aviv): Refactor the implementation to remove generic handling once we standardize to a + // single type of Felt. + where + F: TryInto + Display + Clone, + >::Error: std::fmt::Display, + { + if sierra_program.len() < 3 { + return Err(StarknetApiError::ParseSierraVersionError( + "Sierra program length must be at least 3 Felts.".to_string(), + )); + } + + let version_components: Vec = sierra_program + .iter() + .take(3) + .enumerate() + .map(|(index, felt)| { + felt.clone().try_into().map_err(|err| { + StarknetApiError::ParseSierraVersionError(format!( + "Failed to parse Sierra program to Sierra version. Index: {}, Felt: {}, \ + Error: {}", + index, felt, err + )) + }) + }) + .collect::>()?; + + Ok(Self::new(version_components[0], version_components[1], version_components[2])) + } +} + +impl Default for SierraVersion { + fn default() -> Self { + Self::LATEST + } +} + +impl FromStr for SierraVersion { + type Err = StarknetApiError; + + fn from_str(s: &str) -> Result { + Ok(Self( + Version::parse(s) + .map_err(|_| StarknetApiError::ParseSierraVersionError(s.to_string()))?, + )) + } +} + +impl From<(u64, u64, u64)> for SierraVersion { + fn from((major, minor, patch): (u64, u64, u64)) -> Self { + Self::new(major, minor, patch) + } +} + /// All relevant information about a declared contract class, including the compiled contract class /// and other parameters derived from the original declare transaction required for billing. #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] @@ -51,13 +148,14 @@ pub struct ClassInfo { pub contract_class: ContractClass, pub sierra_program_length: usize, pub abi_length: usize, + pub sierra_version: SierraVersion, } impl ClassInfo { pub fn bytecode_length(&self) -> usize { match &self.contract_class { ContractClass::V0(contract_class) => contract_class.bytecode_length(), - ContractClass::V1(contract_class) => contract_class.bytecode.len(), + ContractClass::V1((contract_class, _sierra_version)) => contract_class.bytecode.len(), } } @@ -84,6 +182,7 @@ impl ClassInfo { contract_class: &ContractClass, sierra_program_length: usize, abi_length: usize, + sierra_version: SierraVersion, ) -> Result { let (contract_class_version, condition) = match contract_class { ContractClass::V0(_) => (0, sierra_program_length == 0), @@ -91,7 +190,12 @@ impl ClassInfo { }; if condition { - Ok(Self { contract_class: contract_class.clone(), sierra_program_length, abi_length }) + Ok(Self { + contract_class: contract_class.clone(), + sierra_program_length, + abi_length, + sierra_version, + }) } else { Err(StarknetApiError::ContractClassVersionSierraProgramLengthMismatch { contract_class_version, diff --git a/crates/starknet_api/src/core.rs b/crates/starknet_api/src/core.rs index 4841e01a911..8accc8caf3b 100644 --- a/crates/starknet_api/src/core.rs +++ b/crates/starknet_api/src/core.rs @@ -5,6 +5,7 @@ mod core_test; use std::fmt::Debug; use std::sync::LazyLock; +use num_traits::ToPrimitive; use primitive_types::H160; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use starknet_types_core::felt::{Felt, NonZeroFelt}; @@ -23,6 +24,12 @@ pub fn ascii_as_felt(ascii_str: &str) -> Result { }) } +pub fn felt_to_u128(felt: &Felt) -> Result { + felt.to_u128().ok_or(StarknetApiError::OutOfRange { + string: format!("Felt {} is too big to convert to 'u128'", *felt,), + }) +} + /// A chain id. #[derive(Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)] pub enum ChainId { @@ -75,19 +82,11 @@ impl ChainId { pub fn as_hex(&self) -> String { format!("0x{}", hex::encode(self.to_string())) } - - #[cfg(any(feature = "testing", test))] - pub fn create_for_testing() -> Self { - const CHAIN_ID_NAME: &str = "SN_GOERLI"; - - ChainId::Other(CHAIN_ID_NAME.to_string()) - } } /// The address of a contract, used for example in [StateDiff](`crate::state::StateDiff`), /// [DeclareTransaction](`crate::transaction::DeclareTransaction`), and /// [BlockHeader](`crate::block::BlockHeader`). - // The block hash table is stored in address 0x1, // this is a special address that is not used for contracts. pub const BLOCK_HASH_TABLE_ADDRESS: ContractAddress = ContractAddress(PatriciaKey(StarkHash::ONE)); @@ -156,7 +155,7 @@ impl TryFrom for ContractAddress { } } -// TODO: Add a hash_function as a parameter +// TODO(Noa): Add a hash_function as a parameter pub fn calculate_contract_address( salt: ContractAddressSalt, class_hash: ClassHash, @@ -355,9 +354,17 @@ pub const PATRICIA_KEY_UPPER_BOUND: &str = "0x800000000000000000000000000000000000000000000000000000000000000"; impl PatriciaKey { + pub const ZERO: Self = Self(StarkHash::ZERO); + pub const ONE: Self = Self(StarkHash::ONE); + pub const TWO: Self = Self(StarkHash::TWO); + pub fn key(&self) -> &StarkHash { &self.0 } + + pub const fn from_hex_unchecked(val: &str) -> Self { + Self(StarkHash::from_hex_unchecked(val)) + } } impl From for PatriciaKey { diff --git a/crates/starknet_api/src/core_test.rs b/crates/starknet_api/src/core_test.rs index 81221cce446..0443f9ffb48 100644 --- a/crates/starknet_api/src/core_test.rs +++ b/crates/starknet_api/src/core_test.rs @@ -1,10 +1,12 @@ use assert_matches::assert_matches; +use num_bigint::BigUint; use starknet_types_core::felt::Felt; use starknet_types_core::hash::{Pedersen, StarkHash as CoreStarkHash}; use crate::core::{ ascii_as_felt, calculate_contract_address, + felt_to_u128, ChainId, ContractAddress, EthAddress, @@ -111,3 +113,21 @@ fn test_ascii_as_felt() { let expected_sn_main = Felt::from(23448594291968334_u128); assert_eq!(sn_main_felt, expected_sn_main); } + +#[test] +fn test_value_too_large_for_type() { + // Happy flow. + let n = 1991_u128; + let n_as_felt = Felt::from(n); + felt_to_u128(&n_as_felt).unwrap(); + + // Value too large for type. + let overflowed_u128: BigUint = BigUint::from(1_u8) << 128; + let overflowed_u128_as_felt = Felt::from(overflowed_u128); + let error = felt_to_u128(&overflowed_u128_as_felt).unwrap_err(); + assert_eq!( + format!("{error}"), + "Out of range Felt 340282366920938463463374607431768211456 is too big to convert to \ + 'u128'." + ); +} diff --git a/crates/starknet_api/src/deprecated_contract_class.rs b/crates/starknet_api/src/deprecated_contract_class.rs index 233ceb64ea1..df03fc4fcf6 100644 --- a/crates/starknet_api/src/deprecated_contract_class.rs +++ b/crates/starknet_api/src/deprecated_contract_class.rs @@ -21,7 +21,7 @@ pub struct ContractClass { pub abi: Option>, pub program: Program, /// The selector of each entry point is a unique identifier in the program. - // TODO: Consider changing to IndexMap, since this is used for computing the + // TODO(Yair): Consider changing to IndexMap, since this is used for computing the // class hash. pub entry_points_by_type: HashMap>, } diff --git a/crates/starknet_api/src/executable_transaction.rs b/crates/starknet_api/src/executable_transaction.rs index fe3e20f9f49..d139239ade7 100644 --- a/crates/starknet_api/src/executable_transaction.rs +++ b/crates/starknet_api/src/executable_transaction.rs @@ -1,17 +1,11 @@ +use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass; use serde::{Deserialize, Serialize}; use crate::contract_class::{ClassInfo, ContractClass}; -use crate::core::{calculate_contract_address, ChainId, ClassHash, ContractAddress, Nonce}; +use crate::core::{ChainId, ClassHash, CompiledClassHash, ContractAddress, Nonce}; use crate::data_availability::DataAvailabilityMode; -use crate::rpc_transaction::{ - RpcDeployAccountTransaction, - RpcDeployAccountTransactionV3, - RpcInvokeTransaction, - RpcInvokeTransactionV3, -}; use crate::transaction::fields::{ AccountDeploymentData, - AllResourceBounds, Calldata, ContractAddressSalt, Fee, @@ -20,7 +14,12 @@ use crate::transaction::fields::{ TransactionSignature, ValidResourceBounds, }; -use crate::transaction::{TransactionHash, TransactionHasher, TransactionVersion}; +use crate::transaction::{ + CalculateContractAddress, + TransactionHash, + TransactionHasher, + TransactionVersion, +}; use crate::StarknetApiError; macro_rules! implement_inner_tx_getter_calls { @@ -90,50 +89,12 @@ impl AccountTransaction { AccountTransaction::Invoke(tx_data) => tx_data.tx_hash, } } -} -// TODO: add a converter for Declare transactions as well. - -impl From for RpcInvokeTransactionV3 { - fn from(tx: InvokeTransaction) -> Self { - Self { - sender_address: tx.sender_address(), - tip: tx.tip(), - nonce: tx.nonce(), - resource_bounds: match tx.resource_bounds() { - ValidResourceBounds::AllResources(all_resource_bounds) => all_resource_bounds, - ValidResourceBounds::L1Gas(l1_gas) => { - AllResourceBounds { l1_gas, ..Default::default() } - } - }, - signature: tx.signature(), - calldata: tx.calldata(), - nonce_data_availability_mode: tx.nonce_data_availability_mode(), - fee_data_availability_mode: tx.fee_data_availability_mode(), - paymaster_data: tx.paymaster_data(), - account_deployment_data: tx.account_deployment_data(), - } - } -} - -impl From for RpcDeployAccountTransactionV3 { - fn from(tx: DeployAccountTransaction) -> Self { - Self { - class_hash: tx.class_hash(), - constructor_calldata: tx.constructor_calldata(), - contract_address_salt: tx.contract_address_salt(), - nonce: tx.nonce(), - signature: tx.signature(), - resource_bounds: match tx.resource_bounds() { - ValidResourceBounds::AllResources(all_resource_bounds) => all_resource_bounds, - ValidResourceBounds::L1Gas(l1_gas) => { - AllResourceBounds { l1_gas, ..Default::default() } - } - }, - tip: tx.tip(), - nonce_data_availability_mode: tx.nonce_data_availability_mode(), - fee_data_availability_mode: tx.fee_data_availability_mode(), - paymaster_data: tx.paymaster_data(), + pub fn account_tx_type_name(&self) -> &'static str { + match self { + AccountTransaction::Declare(_) => "DECLARE", + AccountTransaction::DeployAccount(_) => "DEPLOY_ACCOUNT", + AccountTransaction::Invoke(_) => "INVOKE_FUNCTION", } } } @@ -152,7 +113,16 @@ impl DeclareTransaction { (nonce, Nonce), (sender_address, ContractAddress), (signature, TransactionSignature), - (version, TransactionVersion) + (version, TransactionVersion), + // compiled_class_hash is only supported in V2 and V3, otherwise the getter panics. + (compiled_class_hash, CompiledClassHash), + // The following fields are only supported in V3, otherwise the getter panics. + (tip, Tip), + (nonce_data_availability_mode, DataAvailabilityMode), + (fee_data_availability_mode, DataAvailabilityMode), + (paymaster_data, PaymasterData), + (account_deployment_data, AccountDeploymentData), + (resource_bounds, ValidResourceBounds) ); pub fn create( @@ -168,7 +138,7 @@ impl DeclareTransaction { Ok(Self { tx: declare_tx, tx_hash, class_info }) } - /// Validates that the compiled class hash of the compiled contract class matches the supplied + /// Validates that the compiled class hash of the compiled class matches the supplied /// compiled class hash. /// Relevant only for version 3 transactions. pub fn validate_compiled_class_hash(&self) -> bool { @@ -188,6 +158,14 @@ impl DeclareTransaction { pub fn contract_class(&self) -> ContractClass { self.class_info.contract_class.clone() } + + /// Casm contract class exists only for contract class V1, for version V0 the getter panics. + pub fn casm_contract_class(&self) -> &CasmContractClass { + let ContractClass::V1(versioned_casm) = &self.class_info.contract_class else { + panic!("Contract class version must be V1.") + }; + &versioned_casm.0 + } } /// Validates that the Declare transaction version is compatible with the Cairo contract version. @@ -239,24 +217,11 @@ impl DeployAccountTransaction { deploy_account_tx: crate::transaction::DeployAccountTransaction, chain_id: &ChainId, ) -> Result { - let contract_address = calculate_contract_address( - deploy_account_tx.contract_address_salt(), - deploy_account_tx.class_hash(), - &deploy_account_tx.constructor_calldata(), - ContractAddress::default(), - )?; + let contract_address = deploy_account_tx.calculate_contract_address()?; let tx_hash = deploy_account_tx.calculate_transaction_hash(chain_id, &deploy_account_tx.version())?; Ok(Self { tx: deploy_account_tx, tx_hash, contract_address }) } - - pub fn from_rpc_tx( - rpc_tx: RpcDeployAccountTransaction, - chain_id: &ChainId, - ) -> Result { - let deploy_account_tx: crate::transaction::DeployAccountTransaction = rpc_tx.into(); - Self::create(deploy_account_tx, chain_id) - } } #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] @@ -292,17 +257,9 @@ impl InvokeTransaction { let tx_hash = invoke_tx.calculate_transaction_hash(chain_id, &invoke_tx.version())?; Ok(Self { tx: invoke_tx, tx_hash }) } - - pub fn from_rpc_tx( - rpc_tx: RpcInvokeTransaction, - chain_id: &ChainId, - ) -> Result { - let invoke_tx: crate::transaction::InvokeTransaction = rpc_tx.into(); - Self::create(invoke_tx, chain_id) - } } -#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] +#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize, Hash)] pub struct L1HandlerTransaction { pub tx: crate::transaction::L1HandlerTransaction, pub tx_hash: TransactionHash, @@ -310,6 +267,17 @@ pub struct L1HandlerTransaction { } impl L1HandlerTransaction { + pub const L1_HANDLER_TYPE_NAME: &str = "L1_HANDLER"; + + pub fn create( + raw_tx: crate::transaction::L1HandlerTransaction, + chain_id: &ChainId, + paid_fee_on_l1: Fee, + ) -> Result { + let tx_hash = raw_tx.calculate_transaction_hash(chain_id, &raw_tx.version)?; + Ok(Self { tx: raw_tx, tx_hash, paid_fee_on_l1 }) + } + pub fn payload_size(&self) -> usize { // The calldata includes the "from" field, which is not a part of the payload. self.tx.calldata.0.len() - 1 @@ -329,4 +297,11 @@ impl Transaction { Transaction::L1Handler(tx) => tx.tx_hash, } } + + pub fn tx_type_name(&self) -> &'static str { + match self { + Transaction::Account(tx) => tx.account_tx_type_name(), + Transaction::L1Handler(_) => L1HandlerTransaction::L1_HANDLER_TYPE_NAME, + } + } } diff --git a/crates/starknet_api/src/execution_resources.rs b/crates/starknet_api/src/execution_resources.rs index 9c564434643..21a573f2743 100644 --- a/crates/starknet_api/src/execution_resources.rs +++ b/crates/starknet_api/src/execution_resources.rs @@ -9,7 +9,14 @@ use crate::transaction::fields::{Fee, Resource}; #[cfg_attr( any(test, feature = "testing"), - derive(derive_more::Add, derive_more::Sum, derive_more::AddAssign, derive_more::Div) + derive( + derive_more::Sum, + derive_more::Div, + derive_more::SubAssign, + derive_more::Sub, + derive_more::Add, + derive_more::AddAssign, + ) )] #[derive( derive_more::Display, @@ -55,6 +62,10 @@ impl GasAmount { self.0.checked_add(rhs.0).map(Self) } + pub fn checked_sub(self, rhs: Self) -> Option { + self.0.checked_sub(rhs.0).map(Self) + } + pub const fn nonzero_saturating_mul(self, rhs: NonzeroGasPrice) -> Fee { rhs.saturating_mul(self) } @@ -66,6 +77,10 @@ impl GasAmount { pub fn checked_mul(self, rhs: GasPrice) -> Option { rhs.checked_mul(self) } + + pub fn checked_factor_mul(self, factor: u64) -> Option { + self.0.checked_mul(factor).map(Self) + } } #[cfg_attr( @@ -109,6 +124,19 @@ impl GasVector { } } + pub fn checked_scalar_mul(self, factor: u64) -> Option { + match ( + self.l1_gas.checked_factor_mul(factor), + self.l1_data_gas.checked_factor_mul(factor), + self.l2_gas.checked_factor_mul(factor), + ) { + (Some(l1_gas), Some(l1_data_gas), Some(l2_gas)) => { + Some(Self { l1_gas, l1_data_gas, l2_gas }) + } + _ => None, + } + } + /// Computes the cost (in fee token units) of the gas vector (panicking on overflow). pub fn cost(&self, gas_prices: &GasPriceVector) -> Fee { let mut sum = Fee(0); @@ -134,44 +162,49 @@ impl GasVector { } sum } +} - /// Compute l1_gas estimation from gas_vector using the following formula: - /// One byte of data costs either 1 data gas (in blob mode) or 16 gas (in calldata - /// mode). For gas price GP and data gas price DGP, the discount for using blobs - /// would be DGP / (16 * GP). - /// X non-data-related gas consumption and Y bytes of data, in non-blob mode, would - /// cost (X + 16*Y) units of gas. Applying the discount ratio to the data-related - /// summand, we get total_gas = (X + Y * DGP / GP). - /// If this function is called with kzg_flag==false, then l1_data_gas==0, and this discount - /// function does nothing. - /// Panics on overflow. - pub fn to_discounted_l1_gas(&self, gas_prices: &GasPriceVector) -> GasAmount { - let l1_data_gas_fee = self - .l1_data_gas - .checked_mul(gas_prices.l1_data_gas_price.into()) - .unwrap_or_else(|| { - panic!( - "Discounted L1 gas cost overflowed: multiplication of L1 data gas ({}) by L1 \ - data gas price ({}) resulted in overflow.", - self.l1_data_gas, gas_prices.l1_data_gas_price - ); - }); - let l1_data_gas_in_l1_gas_units = - l1_data_gas_fee.checked_div_ceil(gas_prices.l1_gas_price).unwrap_or_else(|| { - panic!( - "Discounted L1 gas cost overflowed: division of L1 data fee ({}) by regular \ - L1 gas price ({}) resulted in overflow.", - l1_data_gas_fee, gas_prices.l1_gas_price - ); - }); - self.l1_gas.checked_add(l1_data_gas_in_l1_gas_units).unwrap_or_else(|| { +/// Computes the total L1 gas amount estimation from the different given L1 gas arguments using the +/// following formula: +/// One byte of data costs either 1 data gas (in blob mode) or 16 gas (in calldata +/// mode). For gas price GP and data gas price DGP, the discount for using blobs +/// would be DGP / (16 * GP). +/// X non-data-related gas consumption and Y bytes of data, in non-blob mode, would +/// cost (X + 16*Y) units of gas. Applying the discount ratio to the data-related +/// summand, we get total_gas = (X + Y * DGP / GP). +/// If this function is called with kzg_flag==false, then l1_data_gas==0, and this discount +/// function does nothing. +/// Panics on overflow. +/// Does not take L2 gas into account - more context is required to convert L2 gas units to L1 gas +/// units (context defined outside of the current crate). +pub fn to_discounted_l1_gas( + l1_gas_price: NonzeroGasPrice, + l1_data_gas_price: GasPrice, + l1_gas: GasAmount, + l1_data_gas: GasAmount, +) -> GasAmount { + let l1_data_gas_fee = l1_data_gas.checked_mul(l1_data_gas_price).unwrap_or_else(|| { + panic!( + "Discounted L1 gas cost overflowed: multiplication of L1 data gas ({}) by L1 data gas \ + price ({}) resulted in overflow.", + l1_data_gas, l1_data_gas_price + ); + }); + let l1_data_gas_in_l1_gas_units = + l1_data_gas_fee.checked_div_ceil(l1_gas_price).unwrap_or_else(|| { panic!( - "Overflow while computing discounted L1 gas: L1 gas ({}) + L1 data gas in L1 gas \ - units ({}) resulted in overflow.", - self.l1_gas, l1_data_gas_in_l1_gas_units - ) - }) - } + "Discounted L1 gas cost overflowed: division of L1 data fee ({}) by regular L1 \ + gas price ({}) resulted in overflow.", + l1_data_gas_fee, l1_gas_price + ); + }); + l1_gas.checked_add(l1_data_gas_in_l1_gas_units).unwrap_or_else(|| { + panic!( + "Overflow while computing discounted L1 gas: L1 gas ({}) + L1 data gas in L1 gas \ + units ({}) resulted in overflow.", + l1_gas, l1_data_gas_in_l1_gas_units + ) + }) } /// The execution resources used by a transaction. diff --git a/crates/starknet_api/src/lib.rs b/crates/starknet_api/src/lib.rs index 2531709e670..f3b2fcc8952 100644 --- a/crates/starknet_api/src/lib.rs +++ b/crates/starknet_api/src/lib.rs @@ -5,6 +5,8 @@ pub mod abi; pub mod block; pub mod block_hash; +pub mod class_cache; +pub mod consensus_transaction; pub mod contract_class; pub mod core; pub mod crypto; @@ -22,6 +24,7 @@ pub mod test_utils; pub mod transaction; pub mod transaction_hash; pub mod type_utils; +pub mod versioned_constants_logic; use std::num::ParseIntError; @@ -65,6 +68,8 @@ pub enum StarknetApiError { version {cairo_version:?}.", **declare_version )] ContractClassVersionMismatch { declare_version: TransactionVersion, cairo_version: u64 }, + #[error("Failed to parse Sierra version: {0}")] + ParseSierraVersionError(String), } pub type StarknetApiResult = Result; diff --git a/crates/starknet_api/src/rpc_transaction.rs b/crates/starknet_api/src/rpc_transaction.rs index 4607fdd45d5..998ed2a3f38 100644 --- a/crates/starknet_api/src/rpc_transaction.rs +++ b/crates/starknet_api/src/rpc_transaction.rs @@ -4,19 +4,15 @@ mod rpc_transaction_test; use std::collections::HashMap; +use cairo_lang_starknet_classes::contract_class::ContractEntryPoints as CairoLangContractEntryPoints; use serde::{Deserialize, Serialize}; -use starknet_types_core::felt::Felt; +use strum::EnumVariantNames; +use strum_macros::{EnumDiscriminants, EnumIter, IntoStaticStr}; use crate::contract_class::EntryPointType; -use crate::core::{ - calculate_contract_address, - ClassHash, - CompiledClassHash, - ContractAddress, - Nonce, -}; +use crate::core::{ChainId, ClassHash, CompiledClassHash, ContractAddress, Nonce}; use crate::data_availability::DataAvailabilityMode; -use crate::state::EntryPoint; +use crate::state::{EntryPoint, SierraContractClass}; use crate::transaction::fields::{ AccountDeploymentData, AllResourceBounds, @@ -28,19 +24,37 @@ use crate::transaction::fields::{ ValidResourceBounds, }; use crate::transaction::{ + CalculateContractAddress, DeclareTransaction, DeclareTransactionV3, DeployAccountTransaction, DeployAccountTransactionV3, + DeployTransactionTrait, InvokeTransaction, InvokeTransactionV3, Transaction, + TransactionHash, + TransactionHasher, + TransactionVersion, +}; +use crate::transaction_hash::{ + get_declare_transaction_v3_hash, + get_deploy_account_transaction_v3_hash, + get_invoke_transaction_v3_hash, + DeclareTransactionV3Trait, + DeployAccountTransactionV3Trait, + InvokeTransactionV3Trait, }; -use crate::StarknetApiError; +use crate::{impl_deploy_transaction_trait, StarknetApiError}; /// Transactions that are ready to be broadcasted to the network through RPC and are not included in /// a block. -#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize, Hash)] +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize, Hash, EnumDiscriminants)] +#[strum_discriminants( + name(RpcTransactionLabelValue), + derive(IntoStaticStr, EnumIter, EnumVariantNames), + strum(serialize_all = "snake_case") +)] #[serde(tag = "type")] #[serde(deny_unknown_fields)] pub enum RpcTransaction { @@ -52,6 +66,83 @@ pub enum RpcTransaction { Invoke(RpcInvokeTransaction), } +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize, Hash)] +pub struct InternalRpcDeployAccountTransaction { + pub tx: RpcDeployAccountTransaction, + pub contract_address: ContractAddress, +} + +impl InternalRpcDeployAccountTransaction { + fn version(&self) -> TransactionVersion { + self.tx.version() + } +} + +impl TransactionHasher for InternalRpcDeployAccountTransaction { + fn calculate_transaction_hash( + &self, + chain_id: &ChainId, + transaction_version: &TransactionVersion, + ) -> Result { + match &self.tx { + RpcDeployAccountTransaction::V3(tx) => { + tx.calculate_transaction_hash(chain_id, transaction_version) + } + } + } +} + +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize, Hash, EnumDiscriminants)] +#[strum_discriminants( + name(InternalRpcTransactionLabelValue), + derive(IntoStaticStr, EnumIter, EnumVariantNames), + strum(serialize_all = "snake_case") +)] +#[serde(tag = "type")] +#[serde(deny_unknown_fields)] +pub enum InternalRpcTransactionWithoutTxHash { + #[serde(rename = "DECLARE")] + Declare(InternalRpcDeclareTransactionV3), + #[serde(rename = "DEPLOY_ACCOUNT")] + DeployAccount(InternalRpcDeployAccountTransaction), + #[serde(rename = "INVOKE")] + Invoke(RpcInvokeTransaction), +} + +impl InternalRpcTransactionWithoutTxHash { + pub fn version(&self) -> TransactionVersion { + match self { + InternalRpcTransactionWithoutTxHash::Declare(tx) => tx.version(), + InternalRpcTransactionWithoutTxHash::Invoke(tx) => tx.version(), + InternalRpcTransactionWithoutTxHash::DeployAccount(tx) => tx.version(), + } + } + + pub fn calculate_transaction_hash( + &self, + chain_id: &ChainId, + ) -> Result { + let transaction_version = &self.version(); + match self { + InternalRpcTransactionWithoutTxHash::Declare(tx) => { + tx.calculate_transaction_hash(chain_id, transaction_version) + } + InternalRpcTransactionWithoutTxHash::Invoke(tx) => { + tx.calculate_transaction_hash(chain_id, transaction_version) + } + InternalRpcTransactionWithoutTxHash::DeployAccount(tx) => { + tx.calculate_transaction_hash(chain_id, transaction_version) + } + } + } +} + +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize, Hash)] +pub struct InternalRpcTransaction { + pub tx: InternalRpcTransactionWithoutTxHash, + pub tx_hash: TransactionHash, +} + macro_rules! implement_ref_getters { ($(($member_name:ident, $member_type:ty)), *) => { $(pub fn $member_name(&self) -> &$member_type { @@ -84,18 +175,15 @@ impl RpcTransaction { match self { RpcTransaction::Declare(RpcDeclareTransaction::V3(tx)) => Ok(tx.sender_address), RpcTransaction::DeployAccount(RpcDeployAccountTransaction::V3(tx)) => { - calculate_contract_address( - tx.contract_address_salt, - tx.class_hash, - &tx.constructor_calldata, - ContractAddress::default(), - ) + tx.calculate_contract_address() } RpcTransaction::Invoke(RpcInvokeTransaction::V3(tx)) => Ok(tx.sender_address), } } } +// TODO(Arni): Replace this with RPCTransaction -> InternalRpcTransaction conversion (don't use From +// because it contains hash calculations). impl From for Transaction { fn from(rpc_transaction: RpcTransaction) -> Self { match rpc_transaction { @@ -106,6 +194,44 @@ impl From for Transaction { } } +macro_rules! implement_internal_getters_for_internal_rpc { + ($(($field_name:ident, $field_ty:ty)),* $(,)?) => { + $( + pub fn $field_name(&self) -> $field_ty { + match &self.tx { + InternalRpcTransactionWithoutTxHash::Declare(tx) => tx.$field_name.clone(), + InternalRpcTransactionWithoutTxHash::DeployAccount(tx) => { + let RpcDeployAccountTransaction::V3(tx) = &tx.tx; + tx.$field_name.clone() + }, + InternalRpcTransactionWithoutTxHash::Invoke(RpcInvokeTransaction::V3(tx)) => tx.$field_name.clone(), + } + } + )* + }; +} + +impl InternalRpcTransaction { + implement_internal_getters_for_internal_rpc!( + (nonce, Nonce), + (resource_bounds, AllResourceBounds), + (tip, Tip), + ); + + pub fn contract_address(&self) -> ContractAddress { + match &self.tx { + InternalRpcTransactionWithoutTxHash::Declare(tx) => tx.sender_address, + InternalRpcTransactionWithoutTxHash::DeployAccount(tx) => tx.contract_address, + InternalRpcTransactionWithoutTxHash::Invoke(RpcInvokeTransaction::V3(tx)) => { + tx.sender_address + } + } + } + + pub fn tx_hash(&self) -> TransactionHash { + self.tx_hash + } +} /// A RPC declare transaction. /// /// This transaction is equivalent to the component DECLARE_TXN in the @@ -141,6 +267,14 @@ pub enum RpcDeployAccountTransaction { V3(RpcDeployAccountTransactionV3), } +impl RpcDeployAccountTransaction { + fn version(&self) -> TransactionVersion { + match self { + RpcDeployAccountTransaction::V3(_) => TransactionVersion::THREE, + } + } +} + impl From for DeployAccountTransaction { fn from(rpc_deploy_account_transaction: RpcDeployAccountTransaction) -> Self { match rpc_deploy_account_transaction { @@ -149,6 +283,32 @@ impl From for DeployAccountTransaction { } } +impl TryFrom for RpcDeployAccountTransactionV3 { + type Error = StarknetApiError; + + fn try_from(value: DeployAccountTransactionV3) -> Result { + Ok(Self { + resource_bounds: match value.resource_bounds { + ValidResourceBounds::AllResources(bounds) => bounds, + _ => { + return Err(StarknetApiError::OutOfRange { + string: "resource_bounds".to_string(), + }); + } + }, + signature: value.signature, + nonce: value.nonce, + class_hash: value.class_hash, + contract_address_salt: value.contract_address_salt, + constructor_calldata: value.constructor_calldata, + tip: value.tip, + paymaster_data: value.paymaster_data, + nonce_data_availability_mode: value.nonce_data_availability_mode, + fee_data_availability_mode: value.fee_data_availability_mode, + }) + } +} + /// A RPC invoke transaction. /// /// This transaction is equivalent to the component INVOKE_TXN in the @@ -162,6 +322,28 @@ pub enum RpcInvokeTransaction { V3(RpcInvokeTransactionV3), } +impl RpcInvokeTransaction { + fn version(&self) -> TransactionVersion { + match self { + RpcInvokeTransaction::V3(_) => TransactionVersion::THREE, + } + } +} + +impl TransactionHasher for RpcInvokeTransaction { + fn calculate_transaction_hash( + &self, + chain_id: &ChainId, + transaction_version: &TransactionVersion, + ) -> Result { + match self { + RpcInvokeTransaction::V3(tx) => { + tx.calculate_transaction_hash(chain_id, transaction_version) + } + } + } +} + impl From for InvokeTransaction { fn from(rpc_invoke_tx: RpcInvokeTransaction) -> Self { match rpc_invoke_tx { @@ -174,13 +356,13 @@ impl From for InvokeTransaction { /// RPC. #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize, Hash)] pub struct RpcDeclareTransactionV3 { - // TODO: Check with Shahak why we need to keep the DeclareType. + // TODO(Mohammad): Check with Shahak why we need to keep the DeclareType. // pub r#type: DeclareType, pub sender_address: ContractAddress, pub compiled_class_hash: CompiledClassHash, pub signature: TransactionSignature, pub nonce: Nonce, - pub contract_class: ContractClass, + pub contract_class: SierraContractClass, pub resource_bounds: AllResourceBounds, pub tip: Tip, pub paymaster_data: PaymasterData, @@ -192,8 +374,7 @@ pub struct RpcDeclareTransactionV3 { impl From for DeclareTransactionV3 { fn from(tx: RpcDeclareTransactionV3) -> Self { Self { - class_hash: ClassHash::default(), /* FIXME(yael 15/4/24): call the starknet-api - * function once ready */ + class_hash: tx.contract_class.calculate_class_hash(), resource_bounds: ValidResourceBounds::AllResources(tx.resource_bounds), tip: tx.tip, signature: tx.signature, @@ -208,6 +389,95 @@ impl From for DeclareTransactionV3 { } } +/// An [RpcDeclareTransactionV3] that contains a class hash instead of the full contract class. +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize, Hash)] +pub struct InternalRpcDeclareTransactionV3 { + pub sender_address: ContractAddress, + pub compiled_class_hash: CompiledClassHash, + pub signature: TransactionSignature, + pub nonce: Nonce, + pub class_hash: ClassHash, + pub resource_bounds: AllResourceBounds, + pub tip: Tip, + pub paymaster_data: PaymasterData, + pub account_deployment_data: AccountDeploymentData, + pub nonce_data_availability_mode: DataAvailabilityMode, + pub fee_data_availability_mode: DataAvailabilityMode, +} + +impl InternalRpcDeclareTransactionV3 { + fn version(&self) -> TransactionVersion { + TransactionVersion::THREE + } +} + +impl DeclareTransactionV3Trait for InternalRpcDeclareTransactionV3 { + fn resource_bounds(&self) -> ValidResourceBounds { + ValidResourceBounds::AllResources(self.resource_bounds) + } + fn tip(&self) -> &Tip { + &self.tip + } + fn paymaster_data(&self) -> &PaymasterData { + &self.paymaster_data + } + fn nonce_data_availability_mode(&self) -> &DataAvailabilityMode { + &self.nonce_data_availability_mode + } + fn fee_data_availability_mode(&self) -> &DataAvailabilityMode { + &self.fee_data_availability_mode + } + fn account_deployment_data(&self) -> &AccountDeploymentData { + &self.account_deployment_data + } + fn sender_address(&self) -> &ContractAddress { + &self.sender_address + } + fn nonce(&self) -> &Nonce { + &self.nonce + } + fn class_hash(&self) -> &ClassHash { + &self.class_hash + } + fn compiled_class_hash(&self) -> &CompiledClassHash { + &self.compiled_class_hash + } +} + +impl TransactionHasher for InternalRpcDeclareTransactionV3 { + fn calculate_transaction_hash( + &self, + chain_id: &ChainId, + transaction_version: &TransactionVersion, + ) -> Result { + get_declare_transaction_v3_hash(self, chain_id, transaction_version) + } +} + +impl From for DeclareTransactionV3 { + fn from(tx: InternalRpcDeclareTransactionV3) -> Self { + Self { + class_hash: tx.class_hash, + resource_bounds: ValidResourceBounds::AllResources(tx.resource_bounds), + tip: tx.tip, + signature: tx.signature, + nonce: tx.nonce, + compiled_class_hash: tx.compiled_class_hash, + sender_address: tx.sender_address, + nonce_data_availability_mode: tx.nonce_data_availability_mode, + fee_data_availability_mode: tx.fee_data_availability_mode, + paymaster_data: tx.paymaster_data, + account_deployment_data: tx.account_deployment_data, + } + } +} + +impl From for DeclareTransaction { + fn from(tx: InternalRpcDeclareTransactionV3) -> Self { + Self::V3(tx.into()) + } +} + /// A deploy account transaction that can be added to Starknet through the RPC. #[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)] pub struct RpcDeployAccountTransactionV3 { @@ -223,6 +493,8 @@ pub struct RpcDeployAccountTransactionV3 { pub fee_data_availability_mode: DataAvailabilityMode, } +impl_deploy_transaction_trait!(RpcDeployAccountTransactionV3); + impl From for DeployAccountTransactionV3 { fn from(tx: RpcDeployAccountTransactionV3) -> Self { Self { @@ -240,6 +512,46 @@ impl From for DeployAccountTransactionV3 { } } +impl DeployAccountTransactionV3Trait for RpcDeployAccountTransactionV3 { + fn resource_bounds(&self) -> ValidResourceBounds { + ValidResourceBounds::AllResources(self.resource_bounds) + } + fn tip(&self) -> &Tip { + &self.tip + } + fn paymaster_data(&self) -> &PaymasterData { + &self.paymaster_data + } + fn nonce_data_availability_mode(&self) -> &DataAvailabilityMode { + &self.nonce_data_availability_mode + } + fn fee_data_availability_mode(&self) -> &DataAvailabilityMode { + &self.fee_data_availability_mode + } + fn constructor_calldata(&self) -> &Calldata { + &self.constructor_calldata + } + fn nonce(&self) -> &Nonce { + &self.nonce + } + fn class_hash(&self) -> &ClassHash { + &self.class_hash + } + fn contract_address_salt(&self) -> &ContractAddressSalt { + &self.contract_address_salt + } +} + +impl TransactionHasher for RpcDeployAccountTransactionV3 { + fn calculate_transaction_hash( + &self, + chain_id: &ChainId, + transaction_version: &TransactionVersion, + ) -> Result { + get_deploy_account_transaction_v3_hash(self, chain_id, transaction_version) + } +} + /// An invoke account transaction that can be added to Starknet through the RPC. #[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)] pub struct RpcInvokeTransactionV3 { @@ -255,6 +567,46 @@ pub struct RpcInvokeTransactionV3 { pub fee_data_availability_mode: DataAvailabilityMode, } +impl InvokeTransactionV3Trait for RpcInvokeTransactionV3 { + fn resource_bounds(&self) -> ValidResourceBounds { + ValidResourceBounds::AllResources(self.resource_bounds) + } + fn tip(&self) -> &Tip { + &self.tip + } + fn paymaster_data(&self) -> &PaymasterData { + &self.paymaster_data + } + fn nonce_data_availability_mode(&self) -> &DataAvailabilityMode { + &self.nonce_data_availability_mode + } + fn fee_data_availability_mode(&self) -> &DataAvailabilityMode { + &self.fee_data_availability_mode + } + fn account_deployment_data(&self) -> &AccountDeploymentData { + &self.account_deployment_data + } + fn sender_address(&self) -> &ContractAddress { + &self.sender_address + } + fn nonce(&self) -> &Nonce { + &self.nonce + } + fn calldata(&self) -> &Calldata { + &self.calldata + } +} + +impl TransactionHasher for RpcInvokeTransactionV3 { + fn calculate_transaction_hash( + &self, + chain_id: &ChainId, + transaction_version: &TransactionVersion, + ) -> Result { + get_invoke_transaction_v3_hash(self, chain_id, transaction_version) + } +} + impl From for InvokeTransactionV3 { fn from(tx: RpcInvokeTransactionV3) -> Self { Self { @@ -272,13 +624,30 @@ impl From for InvokeTransactionV3 { } } -// The contract class in SN_API state doesn't have `contract_class_version`, not following the spec. -#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize, Hash)] -pub struct ContractClass { - pub sierra_program: Vec, - pub contract_class_version: String, - pub entry_points_by_type: EntryPointByType, - pub abi: String, +impl TryFrom for RpcInvokeTransactionV3 { + type Error = StarknetApiError; + + fn try_from(value: InvokeTransactionV3) -> Result { + Ok(Self { + resource_bounds: match value.resource_bounds { + ValidResourceBounds::AllResources(bounds) => bounds, + _ => { + return Err(StarknetApiError::OutOfRange { + string: "resource_bounds".to_string(), + }); + } + }, + signature: value.signature, + nonce: value.nonce, + tip: value.tip, + paymaster_data: value.paymaster_data, + nonce_data_availability_mode: value.nonce_data_availability_mode, + fee_data_availability_mode: value.fee_data_availability_mode, + sender_address: value.sender_address, + calldata: value.calldata, + account_deployment_data: value.account_deployment_data, + }) + } } // TODO(Aviv): remove duplication with sequencer/crates/papyrus_rpc/src/v0_8/state.rs @@ -292,6 +661,18 @@ pub struct EntryPointByType { pub l1handler: Vec, } +// TODO(AVIV): Consider removing this conversion and using CairoLangContractEntryPoints instead of +// defining the EntryPointByType struct. +impl From for EntryPointByType { + fn from(value: CairoLangContractEntryPoints) -> Self { + Self { + constructor: value.constructor.into_iter().map(EntryPoint::from).collect(), + external: value.external.into_iter().map(EntryPoint::from).collect(), + l1handler: value.l1_handler.into_iter().map(EntryPoint::from).collect(), + } + } +} + impl EntryPointByType { pub fn from_hash_map(entry_points_by_type: HashMap>) -> Self { macro_rules! get_entrypoint_by_type { diff --git a/crates/starknet_api/src/rpc_transaction_test.rs b/crates/starknet_api/src/rpc_transaction_test.rs index f12acce012e..a609b4b3ed8 100644 --- a/crates/starknet_api/src/rpc_transaction_test.rs +++ b/crates/starknet_api/src/rpc_transaction_test.rs @@ -1,25 +1,17 @@ -use std::sync::Arc; - use rstest::rstest; use starknet_types_core::felt::Felt; use crate::block::GasPrice; use crate::core::CompiledClassHash; use crate::execution_resources::GasAmount; -use crate::rpc_transaction::{ - ContractClass, - DataAvailabilityMode, - RpcDeclareTransaction, - RpcDeclareTransactionV3, - RpcDeployAccountTransaction, - RpcDeployAccountTransactionV3, - RpcTransaction, -}; +use crate::rpc_transaction::{DataAvailabilityMode, RpcTransaction}; +use crate::state::SierraContractClass; +use crate::test_utils::declare::{rpc_declare_tx, DeclareTxArgs}; +use crate::test_utils::deploy_account::{rpc_deploy_account_tx, DeployAccountTxArgs}; use crate::test_utils::invoke::{rpc_invoke_tx, InvokeTxArgs}; use crate::transaction::fields::{ AccountDeploymentData, AllResourceBounds, - Calldata, ContractAddressSalt, PaymasterData, ResourceBounds, @@ -29,7 +21,7 @@ use crate::transaction::fields::{ }; use crate::{calldata, class_hash, contract_address, felt, nonce}; -// TODO: Delete this when starknet_api_test_util is moved to StarkNet API. +// TODO(Nimrod): Delete this when starknet_api_test_util is moved to StarkNet API. fn create_resource_bounds_for_testing() -> AllResourceBounds { AllResourceBounds { l1_gas: ResourceBounds { max_amount: GasAmount(100), max_price_per_unit: GasPrice(12) }, @@ -38,38 +30,41 @@ fn create_resource_bounds_for_testing() -> AllResourceBounds { } } -fn create_declare_v3() -> RpcDeclareTransaction { - RpcDeclareTransaction::V3(RpcDeclareTransactionV3 { - contract_class: ContractClass::default(), - resource_bounds: create_resource_bounds_for_testing(), - tip: Tip(1), - signature: TransactionSignature(vec![Felt::ONE, Felt::TWO]), - nonce: nonce!(1), - compiled_class_hash: CompiledClassHash(Felt::TWO), - sender_address: contract_address!("0x3"), - nonce_data_availability_mode: DataAvailabilityMode::L1, - fee_data_availability_mode: DataAvailabilityMode::L2, - paymaster_data: PaymasterData(vec![Felt::ZERO]), - account_deployment_data: AccountDeploymentData(vec![Felt::THREE]), - }) +fn create_declare_tx() -> RpcTransaction { + rpc_declare_tx( + DeclareTxArgs { + resource_bounds: ValidResourceBounds::AllResources(create_resource_bounds_for_testing()), + tip: Tip(1), + signature: TransactionSignature(vec![felt!("0x1"), felt!("0x2")]), + sender_address: contract_address!("0x3"), + nonce: nonce!(1), + paymaster_data: PaymasterData(vec![felt!("0x0")]), + account_deployment_data: AccountDeploymentData(vec![felt!("0x3")]), + nonce_data_availability_mode: DataAvailabilityMode::L1, + fee_data_availability_mode: DataAvailabilityMode::L2, + compiled_class_hash: CompiledClassHash(felt!("0x2")), + ..Default::default() + }, + SierraContractClass::default(), + ) } -fn create_deploy_account_v3() -> RpcDeployAccountTransaction { - RpcDeployAccountTransaction::V3(RpcDeployAccountTransactionV3 { - resource_bounds: create_resource_bounds_for_testing(), - tip: Tip::default(), - contract_address_salt: ContractAddressSalt(felt!("0x23")), +fn create_deploy_account_tx() -> RpcTransaction { + rpc_deploy_account_tx(DeployAccountTxArgs { + resource_bounds: ValidResourceBounds::AllResources(create_resource_bounds_for_testing()), + contract_address_salt: ContractAddressSalt(felt!("0x1")), class_hash: class_hash!("0x2"), - constructor_calldata: Calldata(Arc::new(vec![Felt::ZERO])), - nonce: nonce!(60), - signature: TransactionSignature(vec![Felt::TWO]), + constructor_calldata: calldata![felt!("0x1")], + nonce: nonce!(1), + signature: TransactionSignature(vec![felt!("0x1")]), nonce_data_availability_mode: DataAvailabilityMode::L2, fee_data_availability_mode: DataAvailabilityMode::L1, - paymaster_data: PaymasterData(vec![Felt::TWO, Felt::ZERO]), + paymaster_data: PaymasterData(vec![felt!("0x2"), felt!("0x0")]), + ..Default::default() }) } -fn create_rpc_invoke_tx() -> RpcTransaction { +fn create_invoke_tx() -> RpcTransaction { rpc_invoke_tx(InvokeTxArgs { resource_bounds: ValidResourceBounds::AllResources(create_resource_bounds_for_testing()), calldata: calldata![felt!("0x1"), felt!("0x2")], @@ -83,9 +78,9 @@ fn create_rpc_invoke_tx() -> RpcTransaction { // Test the custom serde/deserde of RPC transactions. #[rstest] -#[case(RpcTransaction::Declare(create_declare_v3()))] -#[case(RpcTransaction::DeployAccount(create_deploy_account_v3()))] -#[case(create_rpc_invoke_tx())] +#[case(create_declare_tx())] +#[case(create_deploy_account_tx())] +#[case(create_invoke_tx())] fn test_rpc_transactions(#[case] tx: RpcTransaction) { let serialized = serde_json::to_string(&tx).unwrap(); let deserialized: RpcTransaction = serde_json::from_str(&serialized).unwrap(); diff --git a/crates/starknet_api/src/state.rs b/crates/starknet_api/src/state.rs index 8bfb841bef4..67399eb72a1 100644 --- a/crates/starknet_api/src/state.rs +++ b/crates/starknet_api/src/state.rs @@ -3,12 +3,17 @@ mod state_test; use std::fmt::Debug; +use std::sync::LazyLock; +use cairo_lang_starknet_classes::contract_class::ContractEntryPoint as CairoLangContractEntryPoint; use indexmap::IndexMap; use serde::{Deserialize, Serialize}; +use sha3::Digest; use starknet_types_core::felt::Felt; +use starknet_types_core::hash::{Poseidon, StarkHash as SNTypsCoreStarkHash}; use crate::block::{BlockHash, BlockNumber}; +use crate::contract_class::EntryPointType; use crate::core::{ ClassHash, CompiledClassHash, @@ -19,13 +24,16 @@ use crate::core::{ PatriciaKey, }; use crate::deprecated_contract_class::ContractClass as DeprecatedContractClass; -use crate::hash::StarkHash; +use crate::hash::{PoseidonHash, StarkHash}; use crate::rpc_transaction::EntryPointByType; use crate::{impl_from_through_intermediate, StarknetApiError}; pub type DeclaredClasses = IndexMap; pub type DeprecatedDeclaredClasses = IndexMap; +static API_VERSION: LazyLock = + LazyLock::new(|| Felt::from_bytes_be_slice(b"CONTRACT_CLASS_V0.1.0")); + /// The differences between two states before and after a block with hash block_hash /// and their respective roots. #[derive(Debug, Default, Clone, Eq, PartialEq, Deserialize, Serialize)] @@ -47,7 +55,6 @@ pub struct StateDiff { pub declared_classes: IndexMap, pub deprecated_declared_classes: IndexMap, pub nonces: IndexMap, - pub replaced_classes: IndexMap, } // Invariant: Addresses are strictly increasing. @@ -60,7 +67,6 @@ pub struct ThinStateDiff { pub declared_classes: IndexMap, pub deprecated_declared_classes: Vec, pub nonces: IndexMap, - pub replaced_classes: IndexMap, } impl ThinStateDiff { @@ -81,7 +87,6 @@ impl ThinStateDiff { .copied() .collect(), nonces: diff.nonces, - replaced_classes: diff.replaced_classes, }, diff.declared_classes .into_iter() @@ -98,7 +103,6 @@ impl ThinStateDiff { result += self.declared_classes.len(); result += self.deprecated_declared_classes.len(); result += self.nonces.len(); - result += self.replaced_classes.len(); for (_contract_address, storage_diffs) in &self.storage_diffs { result += storage_diffs.len(); @@ -111,7 +115,6 @@ impl ThinStateDiff { && self.declared_classes.is_empty() && self.deprecated_declared_classes.is_empty() && self.nonces.is_empty() - && self.replaced_classes.is_empty() && self .storage_diffs .iter() @@ -209,7 +212,7 @@ impl StorageKey { impl_from_through_intermediate!(u128, StorageKey, u8, u16, u32, u64); /// A contract class. -#[derive(Debug, Clone, Default, Eq, PartialEq, Deserialize, Serialize)] +#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize, Hash)] pub struct SierraContractClass { pub sierra_program: Vec, pub contract_class_version: String, @@ -217,14 +220,101 @@ pub struct SierraContractClass { pub abi: String, } -/// An entry point of a [ContractClass](`crate::state::ContractClass`). +impl Default for SierraContractClass { + fn default() -> Self { + Self { + sierra_program: [Felt::ONE, Felt::TWO, Felt::THREE].to_vec(), + contract_class_version: Default::default(), + entry_points_by_type: Default::default(), + abi: Default::default(), + } + } +} + +impl SierraContractClass { + pub fn calculate_class_hash(&self) -> ClassHash { + let external_entry_points_hash = entry_points_hash(self, &EntryPointType::External); + let l1_handler_entry_points_hash = entry_points_hash(self, &EntryPointType::L1Handler); + let constructor_entry_points_hash = entry_points_hash(self, &EntryPointType::Constructor); + let abi_keccak = sha3::Keccak256::default().chain_update(self.abi.as_bytes()).finalize(); + let abi_hash = truncated_keccak(abi_keccak.into()); + let program_hash = Poseidon::hash_array(self.sierra_program.as_slice()); + + let class_hash = Poseidon::hash_array(&[ + *API_VERSION, + external_entry_points_hash.0, + l1_handler_entry_points_hash.0, + constructor_entry_points_hash.0, + abi_hash, + program_hash, + ]); + ClassHash(class_hash) + } +} + +#[cfg(any(test, feature = "testing"))] +impl From for SierraContractClass { + fn from( + cairo_lang_contract_class: cairo_lang_starknet_classes::contract_class::ContractClass, + ) -> Self { + Self { + sierra_program: cairo_lang_contract_class + .sierra_program + .into_iter() + .map(|big_uint_as_hex| Felt::from(big_uint_as_hex.value)) + .collect(), + contract_class_version: cairo_lang_contract_class.contract_class_version, + entry_points_by_type: cairo_lang_contract_class.entry_points_by_type.into(), + abi: cairo_lang_contract_class.abi.map(|abi| abi.json()).unwrap_or_default(), + } + } +} + +/// An entry point of a [SierraContractClass](`SierraContractClass`). #[derive(Debug, Default, Clone, Eq, PartialEq, Hash, Deserialize, Serialize, PartialOrd, Ord)] pub struct EntryPoint { pub function_idx: FunctionIndex, pub selector: EntryPointSelector, } +impl From for EntryPoint { + fn from(entry_point: CairoLangContractEntryPoint) -> Self { + Self { + function_idx: FunctionIndex(entry_point.function_idx), + selector: EntryPointSelector(entry_point.selector.into()), + } + } +} + #[derive( Debug, Copy, Clone, Default, Eq, PartialEq, Hash, Deserialize, Serialize, PartialOrd, Ord, )] pub struct FunctionIndex(pub usize); + +fn entry_points_hash( + class: &SierraContractClass, + entry_point_type: &EntryPointType, +) -> PoseidonHash { + PoseidonHash(Poseidon::hash_array( + class + .entry_points_by_type + .to_hash_map() + .get(entry_point_type) + .unwrap_or(&vec![]) + .iter() + .flat_map(|ep| [ep.selector.0, usize_into_felt(ep.function_idx.0)]) + .collect::>() + .as_slice(), + )) +} + +// Python code masks with (2**250 - 1) which starts 0x03 and is followed by 31 0xff in be. +// Truncation is needed not to overflow the field element. +pub fn truncated_keccak(mut plain: [u8; 32]) -> Felt { + plain[0] &= 0x03; + Felt::from_bytes_be(&plain) +} + +fn usize_into_felt(u: usize) -> Felt { + u128::try_from(u).expect("Expect at most 128 bits").into() +} diff --git a/crates/starknet_api/src/state_test.rs b/crates/starknet_api/src/state_test.rs index 47b9a56b15e..5730791ed22 100644 --- a/crates/starknet_api/src/state_test.rs +++ b/crates/starknet_api/src/state_test.rs @@ -3,9 +3,11 @@ use std::collections::HashMap; use indexmap::{indexmap, IndexMap}; use serde_json::json; -use super::ThinStateDiff; +use crate::class_hash; use crate::core::{ClassHash, CompiledClassHash, Nonce}; use crate::deprecated_contract_class::EntryPointOffset; +use crate::state::{SierraContractClass, ThinStateDiff}; +use crate::test_utils::read_json_file; #[test] fn entry_point_offset_from_json_str() { @@ -54,12 +56,8 @@ fn thin_state_diff_len() { 0u64.into() => Nonce(1u64.into()), 1u64.into() => Nonce(1u64.into()), }, - replaced_classes: indexmap! { - 2u64.into() => ClassHash(4u64.into()), - 3u64.into() => ClassHash(5u64.into()), - }, }; - assert_eq!(state_diff.len(), 13); + assert_eq!(state_diff.len(), 11); } #[test] @@ -108,11 +106,13 @@ fn thin_state_diff_is_empty() { } .is_empty() ); - assert!( - !ThinStateDiff { - replaced_classes: indexmap! { Default::default() => Default::default() }, - ..Default::default() - } - .is_empty() - ); +} + +#[test] +fn calc_class_hash() { + let class: SierraContractClass = serde_json::from_value(read_json_file("class.json")).unwrap(); + let expected_class_hash = + class_hash!("0x29927c8af6bccf3f6fda035981e765a7bdbf18a2dc0d630494f8758aa908e2b"); + let calculated_class_hash = class.calculate_class_hash(); + assert_eq!(calculated_class_hash, expected_class_hash); } diff --git a/crates/starknet_api/src/test_utils.rs b/crates/starknet_api/src/test_utils.rs index dd27509fef9..3226145a411 100644 --- a/crates/starknet_api/src/test_utils.rs +++ b/crates/starknet_api/src/test_utils.rs @@ -1,13 +1,27 @@ use std::collections::HashMap; use std::fs::read_to_string; use std::path::{Path, PathBuf}; +use std::sync::LazyLock; -use infra_utils::path::cargo_manifest_dir; use serde::{Deserialize, Serialize}; +use serde_json::to_string_pretty; +use starknet_infra_utils::path::current_dir; use starknet_types_core::felt::Felt; -use crate::block::BlockNumber; +use crate::block::{ + BlockInfo, + BlockNumber, + BlockTimestamp, + GasPrice, + GasPriceVector, + GasPrices, + NonzeroGasPrice, +}; +use crate::contract_address; use crate::core::{ChainId, ContractAddress, Nonce}; +use crate::execution_resources::GasAmount; +use crate::rpc_transaction::RpcTransaction; +use crate::transaction::fields::Fee; use crate::transaction::{Transaction, TransactionHash}; pub mod declare; @@ -15,11 +29,29 @@ pub mod deploy_account; pub mod invoke; pub mod l1_handler; +// TODO(Dori, 1/2/2024): Remove these constants once all tests use the `contracts` and +// `initial_test_state` modules for testing. +// Addresses. +pub const TEST_SEQUENCER_ADDRESS: &str = "0x1000"; +pub const TEST_ERC20_CONTRACT_ADDRESS: &str = "0x1001"; +pub const TEST_ERC20_CONTRACT_ADDRESS2: &str = "0x1002"; + +// The block number of the BlockContext being used for testing. +pub const CURRENT_BLOCK_NUMBER: u64 = 2001; +pub const CURRENT_BLOCK_NUMBER_FOR_VALIDATE: u64 = 2000; + +// The block timestamp of the BlockContext being used for testing. +pub const CURRENT_BLOCK_TIMESTAMP: u64 = 1072023; +pub const CURRENT_BLOCK_TIMESTAMP_FOR_VALIDATE: u64 = 1069200; + +pub static CHAIN_ID_FOR_TESTS: LazyLock = + LazyLock::new(|| ChainId::Other("CHAIN_ID_SUBDIR".to_owned())); + /// Returns the path to a file in the resources directory. This assumes the current working /// directory has a `resources` folder. The value for file_path should be the path to the required /// file in the folder "resources". pub fn path_in_resources>(file_path: P) -> PathBuf { - cargo_manifest_dir().unwrap().join("resources").join(file_path) + current_dir().unwrap().join("resources").join(file_path) } /// Reads from the directory containing the manifest at run time, same as current working directory. @@ -43,12 +75,16 @@ pub struct TransactionTestData { pub block_number: BlockNumber, } -#[derive(Debug, Default)] +#[derive(Debug, Default, Clone)] pub struct NonceManager { next_nonce: HashMap, } impl NonceManager { + pub fn get(&self, account_address: ContractAddress) -> Nonce { + Nonce(*self.next_nonce.get(&account_address).unwrap_or(&Felt::default())) + } + pub fn next(&mut self, account_address: ContractAddress) -> Nonce { let next = self.next_nonce.remove(&account_address).unwrap_or_default(); self.next_nonce.insert(account_address, next + 1); @@ -90,3 +126,77 @@ macro_rules! compiled_class_hash { $crate::core::CompiledClassHash(starknet_types_core::felt::Felt::from($s)) }; } + +/// Converts a [`RpcTransaction`] to a JSON string. +pub fn rpc_tx_to_json(tx: &RpcTransaction) -> String { + let mut tx_json = serde_json::to_value(tx) + .unwrap_or_else(|tx| panic!("Failed to serialize transaction: {tx:?}")); + + // Add type and version manually + let type_string = match tx { + RpcTransaction::Declare(_) => "DECLARE", + RpcTransaction::DeployAccount(_) => "DEPLOY_ACCOUNT", + RpcTransaction::Invoke(_) => "INVOKE", + }; + + tx_json + .as_object_mut() + .unwrap() + .extend([("type".to_string(), type_string.into()), ("version".to_string(), "0x3".into())]); + + // Serialize back to pretty JSON string + to_string_pretty(&tx_json).expect("Failed to serialize transaction") +} + +// V3 transactions: +pub const DEFAULT_L1_GAS_AMOUNT: GasAmount = GasAmount(u64::pow(10, 6)); +pub const DEFAULT_L1_DATA_GAS_MAX_AMOUNT: GasAmount = GasAmount(u64::pow(10, 6)); +pub const DEFAULT_L2_GAS_MAX_AMOUNT: GasAmount = GasAmount(u64::pow(10, 9)); +pub const MAX_L1_GAS_PRICE: NonzeroGasPrice = DEFAULT_STRK_L1_GAS_PRICE; +pub const MAX_L2_GAS_PRICE: NonzeroGasPrice = DEFAULT_STRK_L2_GAS_PRICE; +pub const MAX_L1_DATA_GAS_PRICE: NonzeroGasPrice = DEFAULT_STRK_L1_DATA_GAS_PRICE; + +pub const DEFAULT_ETH_L1_GAS_PRICE: NonzeroGasPrice = + NonzeroGasPrice::new_unchecked(GasPrice(100 * u128::pow(10, 9))); // Given in units of Wei. +pub const DEFAULT_STRK_L1_GAS_PRICE: NonzeroGasPrice = + NonzeroGasPrice::new_unchecked(GasPrice(100 * u128::pow(10, 9))); // Given in units of Fri. +pub const DEFAULT_ETH_L1_DATA_GAS_PRICE: NonzeroGasPrice = + NonzeroGasPrice::new_unchecked(GasPrice(u128::pow(10, 6))); // Given in units of Wei. +pub const DEFAULT_STRK_L1_DATA_GAS_PRICE: NonzeroGasPrice = + NonzeroGasPrice::new_unchecked(GasPrice(u128::pow(10, 9))); // Given in units of Fri. +pub const DEFAULT_ETH_L2_GAS_PRICE: NonzeroGasPrice = + NonzeroGasPrice::new_unchecked(GasPrice(u128::pow(10, 6))); +pub const DEFAULT_STRK_L2_GAS_PRICE: NonzeroGasPrice = + NonzeroGasPrice::new_unchecked(GasPrice(u128::pow(10, 9))); + +pub const DEFAULT_GAS_PRICES: GasPrices = GasPrices { + eth_gas_prices: GasPriceVector { + l1_gas_price: DEFAULT_ETH_L1_GAS_PRICE, + l2_gas_price: DEFAULT_ETH_L2_GAS_PRICE, + l1_data_gas_price: DEFAULT_ETH_L1_DATA_GAS_PRICE, + }, + strk_gas_prices: GasPriceVector { + l1_gas_price: DEFAULT_STRK_L1_GAS_PRICE, + l2_gas_price: DEFAULT_STRK_L2_GAS_PRICE, + l1_data_gas_price: DEFAULT_STRK_L1_DATA_GAS_PRICE, + }, +}; + +// Deprecated transactions: +pub const MAX_FEE: Fee = DEFAULT_L1_GAS_AMOUNT.nonzero_saturating_mul(DEFAULT_ETH_L1_GAS_PRICE); + +impl BlockInfo { + pub fn create_for_testing() -> Self { + Self { + block_number: BlockNumber(CURRENT_BLOCK_NUMBER), + block_timestamp: BlockTimestamp(CURRENT_BLOCK_TIMESTAMP), + sequencer_address: contract_address!(TEST_SEQUENCER_ADDRESS), + gas_prices: DEFAULT_GAS_PRICES, + use_kzg_da: false, + } + } + + pub fn create_for_testing_with_kzg(use_kzg_da: bool) -> Self { + Self { use_kzg_da, ..Self::create_for_testing() } + } +} diff --git a/crates/starknet_api/src/test_utils/declare.rs b/crates/starknet_api/src/test_utils/declare.rs index 141cf964b92..5807dc9d46e 100644 --- a/crates/starknet_api/src/test_utils/declare.rs +++ b/crates/starknet_api/src/test_utils/declare.rs @@ -2,13 +2,19 @@ use crate::contract_address; use crate::contract_class::ClassInfo; use crate::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; use crate::data_availability::DataAvailabilityMode; -use crate::executable_transaction::DeclareTransaction as ExecutableDeclareTransaction; +use crate::executable_transaction::{ + AccountTransaction, + DeclareTransaction as ExecutableDeclareTransaction, +}; use crate::rpc_transaction::{ - ContractClass, + InternalRpcDeclareTransactionV3, + InternalRpcTransaction, + InternalRpcTransactionWithoutTxHash, RpcDeclareTransaction, RpcDeclareTransactionV3, RpcTransaction, }; +use crate::state::SierraContractClass; use crate::transaction::fields::{ AccountDeploymentData, Fee, @@ -86,7 +92,7 @@ macro_rules! declare_tx_args { } pub fn declare_tx(declare_tx_args: DeclareTxArgs) -> DeclareTransaction { - // TODO: Make TransactionVersion an enum and use match here. + // TODO(Arni): Make TransactionVersion an enum and use match here. if declare_tx_args.version == TransactionVersion::ZERO { DeclareTransaction::V0(DeclareTransactionV0V1 { max_fee: declare_tx_args.max_fee, @@ -134,15 +140,17 @@ pub fn declare_tx(declare_tx_args: DeclareTxArgs) -> DeclareTransaction { pub fn executable_declare_tx( declare_tx_args: DeclareTxArgs, class_info: ClassInfo, -) -> ExecutableDeclareTransaction { +) -> AccountTransaction { let tx_hash = declare_tx_args.tx_hash; let tx = declare_tx(declare_tx_args); - ExecutableDeclareTransaction { tx, tx_hash, class_info } + let declare_tx = ExecutableDeclareTransaction { tx, tx_hash, class_info }; + + AccountTransaction::Declare(declare_tx) } pub fn rpc_declare_tx( declare_tx_args: DeclareTxArgs, - contract_class: ContractClass, + contract_class: SierraContractClass, ) -> RpcTransaction { if declare_tx_args.version != TransactionVersion::THREE { panic!("Unsupported transaction version: {:?}.", declare_tx_args.version); @@ -166,3 +174,28 @@ pub fn rpc_declare_tx( compiled_class_hash: declare_tx_args.compiled_class_hash, })) } + +pub fn internal_rpc_declare_tx(declare_tx_args: DeclareTxArgs) -> InternalRpcTransaction { + let rpc_declare_tx = rpc_declare_tx(declare_tx_args.clone(), SierraContractClass::default()); + + if let RpcTransaction::Declare(RpcDeclareTransaction::V3(rpc_declare_tx)) = rpc_declare_tx { + InternalRpcTransaction { + tx: InternalRpcTransactionWithoutTxHash::Declare(InternalRpcDeclareTransactionV3 { + signature: rpc_declare_tx.signature, + sender_address: rpc_declare_tx.sender_address, + resource_bounds: rpc_declare_tx.resource_bounds, + tip: rpc_declare_tx.tip, + nonce_data_availability_mode: rpc_declare_tx.nonce_data_availability_mode, + fee_data_availability_mode: rpc_declare_tx.fee_data_availability_mode, + paymaster_data: rpc_declare_tx.paymaster_data, + account_deployment_data: rpc_declare_tx.account_deployment_data, + nonce: rpc_declare_tx.nonce, + compiled_class_hash: rpc_declare_tx.compiled_class_hash, + class_hash: declare_tx_args.class_hash, + }), + tx_hash: declare_tx_args.tx_hash, + } + } else { + panic!("Unexpected RpcTransaction type.") + } +} diff --git a/crates/starknet_api/src/test_utils/deploy_account.rs b/crates/starknet_api/src/test_utils/deploy_account.rs index 8d64aeb6580..dd1b353bdc5 100644 --- a/crates/starknet_api/src/test_utils/deploy_account.rs +++ b/crates/starknet_api/src/test_utils/deploy_account.rs @@ -1,7 +1,12 @@ +use starknet_crypto::Felt; + use super::NonceManager; -use crate::core::{calculate_contract_address, ClassHash, ContractAddress, Nonce}; +use crate::core::{ClassHash, Nonce}; use crate::data_availability::DataAvailabilityMode; -use crate::executable_transaction::DeployAccountTransaction as ExecutableDeployAccountTransaction; +use crate::executable_transaction::{ + AccountTransaction, + DeployAccountTransaction as ExecutableDeployAccountTransaction, +}; use crate::rpc_transaction::{ RpcDeployAccountTransaction, RpcDeployAccountTransactionV3, @@ -17,6 +22,7 @@ use crate::transaction::fields::{ ValidResourceBounds, }; use crate::transaction::{ + CalculateContractAddress, DeployAccountTransaction, DeployAccountTransactionV1, DeployAccountTransactionV3, @@ -28,7 +34,6 @@ use crate::transaction::{ pub struct DeployAccountTxArgs { pub max_fee: Fee, pub signature: TransactionSignature, - pub deployer_address: ContractAddress, pub version: TransactionVersion, pub resource_bounds: ValidResourceBounds, pub tip: Tip, @@ -47,7 +52,6 @@ impl Default for DeployAccountTxArgs { DeployAccountTxArgs { max_fee: Fee::default(), signature: TransactionSignature::default(), - deployer_address: ContractAddress::default(), version: TransactionVersion::THREE, resource_bounds: ValidResourceBounds::create_for_testing_no_fee_enforcement(), tip: Tip::default(), @@ -84,7 +88,7 @@ pub fn deploy_account_tx( deploy_tx_args: DeployAccountTxArgs, nonce: Nonce, ) -> DeployAccountTransaction { - // TODO: Make TransactionVersion an enum and use match here. + // TODO(Arni): Make TransactionVersion an enum and use match here. if deploy_tx_args.version == TransactionVersion::ONE { DeployAccountTransaction::V1(DeployAccountTransactionV1 { max_fee: deploy_tx_args.max_fee, @@ -112,22 +116,30 @@ pub fn deploy_account_tx( } } -pub fn executable_deploy_account_tx( +// TODO(Arni): Consider using [ExecutableDeployAccountTransaction::create] in the body of this +// function. We don't use it now to avoid tx_hash calculation. +pub fn executable_deploy_account_tx(deploy_tx_args: DeployAccountTxArgs) -> AccountTransaction { + let tx_hash = deploy_tx_args.tx_hash; + let tx = deploy_account_tx(deploy_tx_args, Nonce(Felt::ZERO)); + let contract_address = tx.calculate_contract_address().unwrap(); + let deploy_account_tx = ExecutableDeployAccountTransaction { tx, tx_hash, contract_address }; + + AccountTransaction::DeployAccount(deploy_account_tx) +} + +pub fn create_executable_deploy_account_tx_and_update_nonce( deploy_tx_args: DeployAccountTxArgs, nonce_manager: &mut NonceManager, -) -> ExecutableDeployAccountTransaction { - let tx_hash = deploy_tx_args.tx_hash; - let contract_address = calculate_contract_address( - deploy_tx_args.contract_address_salt, - deploy_tx_args.class_hash, - &deploy_tx_args.constructor_calldata, - deploy_tx_args.deployer_address, - ) - .unwrap(); +) -> AccountTransaction { + let tx = executable_deploy_account_tx(deploy_tx_args); + let contract_address = tx.contract_address(); let nonce = nonce_manager.next(contract_address); - let tx = deploy_account_tx(deploy_tx_args, nonce); - - ExecutableDeployAccountTransaction { tx, tx_hash, contract_address } + assert_eq!( + nonce, + Nonce(Felt::ZERO), + "Account already deployed at this address: {contract_address}." + ); + tx } pub fn rpc_deploy_account_tx(deploy_tx_args: DeployAccountTxArgs) -> RpcTransaction { diff --git a/crates/starknet_api/src/test_utils/invoke.rs b/crates/starknet_api/src/test_utils/invoke.rs index 5f0764b4f8e..29d49885293 100644 --- a/crates/starknet_api/src/test_utils/invoke.rs +++ b/crates/starknet_api/src/test_utils/invoke.rs @@ -2,8 +2,17 @@ use crate::abi::abi_utils::selector_from_name; use crate::calldata; use crate::core::{ContractAddress, Nonce}; use crate::data_availability::DataAvailabilityMode; -use crate::executable_transaction::InvokeTransaction as ExecutableInvokeTransaction; -use crate::rpc_transaction::{RpcInvokeTransaction, RpcInvokeTransactionV3, RpcTransaction}; +use crate::executable_transaction::{ + AccountTransaction, + InvokeTransaction as ExecutableInvokeTransaction, +}; +use crate::rpc_transaction::{ + InternalRpcTransaction, + InternalRpcTransactionWithoutTxHash, + RpcInvokeTransaction, + RpcInvokeTransactionV3, + RpcTransaction, +}; use crate::transaction::constants::EXECUTE_ENTRY_POINT_NAME; use crate::transaction::fields::{ AccountDeploymentData, @@ -80,7 +89,7 @@ macro_rules! invoke_tx_args { } pub fn invoke_tx(invoke_args: InvokeTxArgs) -> InvokeTransaction { - // TODO: Make TransactionVersion an enum and use match here. + // TODO(Arni): Make TransactionVersion an enum and use match here. if invoke_args.version == TransactionVersion::ZERO { InvokeTransaction::V0(InvokeTransactionV0 { max_fee: invoke_args.max_fee, @@ -116,11 +125,12 @@ pub fn invoke_tx(invoke_args: InvokeTxArgs) -> InvokeTransaction { } } -pub fn executable_invoke_tx(invoke_args: InvokeTxArgs) -> ExecutableInvokeTransaction { +pub fn executable_invoke_tx(invoke_args: InvokeTxArgs) -> AccountTransaction { let tx_hash = invoke_args.tx_hash; let tx = invoke_tx(invoke_args); + let invoke_tx = ExecutableInvokeTransaction { tx, tx_hash }; - ExecutableInvokeTransaction { tx, tx_hash } + AccountTransaction::Invoke(invoke_tx) } pub fn rpc_invoke_tx(invoke_args: InvokeTxArgs) -> RpcTransaction { @@ -145,3 +155,17 @@ pub fn rpc_invoke_tx(invoke_args: InvokeTxArgs) -> RpcTransaction { account_deployment_data: invoke_args.account_deployment_data, })) } + +pub fn internal_invoke_tx(invoke_args: InvokeTxArgs) -> InternalRpcTransaction { + if invoke_args.version != TransactionVersion::THREE { + panic!("Unsupported transaction version: {:?}.", invoke_args.version); + } + let tx_hash = invoke_args.tx_hash; + let RpcTransaction::Invoke(tx) = rpc_invoke_tx(invoke_args) else { + panic!("Expected RpcTransaction::Invoke"); + }; + + let invoke_tx = InternalRpcTransactionWithoutTxHash::Invoke(tx); + + InternalRpcTransaction { tx: invoke_tx, tx_hash } +} diff --git a/crates/starknet_api/src/test_utils/l1_handler.rs b/crates/starknet_api/src/test_utils/l1_handler.rs index 0610ac8711a..9177d19784d 100644 --- a/crates/starknet_api/src/test_utils/l1_handler.rs +++ b/crates/starknet_api/src/test_utils/l1_handler.rs @@ -1,11 +1,10 @@ use crate::core::{ContractAddress, EntryPointSelector, Nonce}; use crate::executable_transaction::L1HandlerTransaction as ExecutableL1HandlerTransaction; use crate::transaction::fields::{Calldata, Fee}; -use crate::transaction::{L1HandlerTransaction, TransactionHash, TransactionVersion}; +use crate::transaction::{L1HandlerTransaction, TransactionHash}; -#[derive(Clone)] +#[derive(Clone, Default)] pub struct L1HandlerTxArgs { - pub version: TransactionVersion, pub nonce: Nonce, pub contract_address: ContractAddress, pub entry_point_selector: EntryPointSelector, @@ -14,20 +13,6 @@ pub struct L1HandlerTxArgs { pub paid_fee_on_l1: Fee, } -impl Default for L1HandlerTxArgs { - fn default() -> Self { - L1HandlerTxArgs { - version: TransactionVersion::THREE, - nonce: Nonce::default(), - contract_address: ContractAddress::default(), - entry_point_selector: EntryPointSelector::default(), - calldata: Calldata::default(), - tx_hash: TransactionHash::default(), - paid_fee_on_l1: Fee::default(), - } - } -} - /// Utility macro for creating `L1HandlerTransaction` to reduce boilerplate. #[macro_export] macro_rules! l1_handler_tx_args { @@ -50,7 +35,7 @@ pub fn executable_l1_handler_tx( ) -> ExecutableL1HandlerTransaction { ExecutableL1HandlerTransaction { tx: L1HandlerTransaction { - version: l1_handler_tx_args.version, + version: L1HandlerTransaction::VERSION, nonce: l1_handler_tx_args.nonce, contract_address: l1_handler_tx_args.contract_address, entry_point_selector: l1_handler_tx_args.entry_point_selector, diff --git a/crates/starknet_api/src/transaction.rs b/crates/starknet_api/src/transaction.rs index 77eb7da72b1..6ffc77e3ee8 100644 --- a/crates/starknet_api/src/transaction.rs +++ b/crates/starknet_api/src/transaction.rs @@ -6,6 +6,7 @@ use starknet_types_core::felt::Felt; use crate::block::{BlockHash, BlockNumber}; use crate::core::{ + calculate_contract_address, ChainId, ClassHash, CompiledClassHash, @@ -13,6 +14,7 @@ use crate::core::{ EntryPointSelector, EthAddress, Nonce, + PatriciaKey, }; use crate::data_availability::DataAvailabilityMode; use crate::execution_resources::ExecutionResources; @@ -40,7 +42,7 @@ use crate::transaction_hash::{ get_invoke_transaction_v3_hash, get_l1_handler_transaction_hash, }; -use crate::StarknetApiError; +use crate::{executable_transaction, StarknetApiError, StarknetApiResult}; #[cfg(test)] #[path = "transaction_test.rs"] @@ -116,20 +118,18 @@ impl Transaction { } } -impl From for Transaction { - fn from(tx: crate::executable_transaction::Transaction) -> Self { +impl From for Transaction { + fn from(tx: executable_transaction::Transaction) -> Self { match tx { - crate::executable_transaction::Transaction::L1Handler(_) => { - unimplemented!("L1Handler transactions are not supported yet.") - } - crate::executable_transaction::Transaction::Account(account_tx) => match account_tx { - crate::executable_transaction::AccountTransaction::Declare(tx) => { + executable_transaction::Transaction::L1Handler(tx) => Transaction::L1Handler(tx.tx), + executable_transaction::Transaction::Account(account_tx) => match account_tx { + executable_transaction::AccountTransaction::Declare(tx) => { Transaction::Declare(tx.tx) } - crate::executable_transaction::AccountTransaction::DeployAccount(tx) => { + executable_transaction::AccountTransaction::DeployAccount(tx) => { Transaction::DeployAccount(tx.tx) } - crate::executable_transaction::AccountTransaction::Invoke(tx) => { + executable_transaction::AccountTransaction::Invoke(tx) => { Transaction::Invoke(tx.tx) } }, @@ -137,16 +137,43 @@ impl From for Transaction { } } -impl From<(Transaction, TransactionHash)> for crate::executable_transaction::Transaction { - fn from((tx, tx_hash): (Transaction, TransactionHash)) -> Self { +impl TryFrom<(Transaction, &ChainId)> for executable_transaction::Transaction { + type Error = StarknetApiError; + + fn try_from((tx, chain_id): (Transaction, &ChainId)) -> Result { + let tx_hash = tx.calculate_transaction_hash(chain_id)?; match tx { - Transaction::Invoke(tx) => crate::executable_transaction::Transaction::Account( - crate::executable_transaction::AccountTransaction::Invoke( - crate::executable_transaction::InvokeTransaction { tx, tx_hash }, + Transaction::DeployAccount(tx) => { + let contract_address = tx.calculate_contract_address()?; + Ok(executable_transaction::Transaction::Account( + executable_transaction::AccountTransaction::DeployAccount( + executable_transaction::DeployAccountTransaction { + tx, + tx_hash, + contract_address, + }, + ), + )) + } + Transaction::Invoke(tx) => Ok(executable_transaction::Transaction::Account( + executable_transaction::AccountTransaction::Invoke( + executable_transaction::InvokeTransaction { tx, tx_hash }, ), - ), + )), + Transaction::L1Handler(tx) => Ok(executable_transaction::Transaction::L1Handler( + executable_transaction::L1HandlerTransaction { + tx, + tx_hash, + // TODO(yael): The paid fee should be an input from the l1_handler. + paid_fee_on_l1: Fee(1), + }, + )), _ => { - unimplemented!("Unsupported transaction type. Only Invoke is currently supported.") + unimplemented!( + "Unsupported transaction type. Only DeployAccount, Invoke and L1Handler are \ + currently supported. tx: {:?}", + tx + ) } } } @@ -155,12 +182,10 @@ impl From<(Transaction, TransactionHash)> for crate::executable_transaction::Tra #[derive(Copy, Clone, Debug, Eq, PartialEq, Default)] pub struct TransactionOptions { /// Transaction that shouldn't be broadcasted to StarkNet. For example, users that want to - /// test the execution result of a transaction without the risk of it being rebroadcasted (the /// signature will be different while the execution remain the same). Using this flag will /// modify the transaction version by setting the 128-th bit to 1. pub only_query: bool, } - macro_rules! implement_v3_tx_getters { ($(($field:ident, $field_type:ty)),*) => { $(pub fn $field(&self) -> $field_type { @@ -393,6 +418,54 @@ impl TransactionHasher for DeclareTransaction { } } +pub trait CalculateContractAddress { + fn calculate_contract_address(&self) -> StarknetApiResult; +} + +/// A trait intended for deploy account transactions. Structs implementing this trait derive the +/// implementation of [CalculateContractAddress]. +pub trait DeployTransactionTrait { + fn contract_address_salt(&self) -> ContractAddressSalt; + fn class_hash(&self) -> ClassHash; + fn constructor_calldata(&self) -> &Calldata; +} + +#[macro_export] +macro_rules! impl_deploy_transaction_trait { + ($type:ty) => { + impl DeployTransactionTrait for $type { + fn contract_address_salt(&self) -> ContractAddressSalt { + self.contract_address_salt + } + + fn class_hash(&self) -> ClassHash { + self.class_hash + } + + fn constructor_calldata(&self) -> &Calldata { + &self.constructor_calldata + } + } + }; +} + +impl CalculateContractAddress for T { + /// Calculates the contract address for the contract deployed by a deploy account transaction. + /// For more details see: + /// + fn calculate_contract_address(&self) -> StarknetApiResult { + // When the contract is deployed via a deploy-account transaction, the deployer address is + // zero. + const DEPLOYER_ADDRESS: ContractAddress = ContractAddress(PatriciaKey::ZERO); + calculate_contract_address( + self.contract_address_salt(), + self.class_hash(), + self.constructor_calldata(), + DEPLOYER_ADDRESS, + ) + } +} + /// A deploy account V1 transaction. #[derive(Debug, Clone, Default, Eq, PartialEq, Hash, Deserialize, Serialize, PartialOrd, Ord)] pub struct DeployAccountTransactionV1 { @@ -404,6 +477,8 @@ pub struct DeployAccountTransactionV1 { pub constructor_calldata: Calldata, } +impl_deploy_transaction_trait!(DeployAccountTransactionV1); + impl TransactionHasher for DeployAccountTransactionV1 { fn calculate_transaction_hash( &self, @@ -439,6 +514,8 @@ impl TransactionHasher for DeployAccountTransactionV3 { } } +impl_deploy_transaction_trait!(DeployAccountTransactionV3); + #[derive( Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize, PartialOrd, Ord, derive_more::From, )] @@ -447,6 +524,15 @@ pub enum DeployAccountTransaction { V3(DeployAccountTransactionV3), } +impl CalculateContractAddress for DeployAccountTransaction { + fn calculate_contract_address(&self) -> StarknetApiResult { + match self { + DeployAccountTransaction::V1(tx) => tx.calculate_contract_address(), + DeployAccountTransaction::V3(tx) => tx.calculate_contract_address(), + } + } +} + macro_rules! implement_deploy_account_tx_getters { ($(($field:ident, $field_type:ty)),*) => { $( @@ -461,6 +547,7 @@ macro_rules! implement_deploy_account_tx_getters { } impl DeployAccountTransaction { + // TODO(Arni): Consider using a direct reference to the getters from [DeployTrait]. implement_deploy_account_tx_getters!( (class_hash, ClassHash), (constructor_calldata, Calldata), @@ -521,6 +608,11 @@ impl TransactionHasher for DeployTransaction { } } +// The trait [`DeployTransactionTrait`] is intended for [`DeployAccountTransaction`]. +// The calculation of the contract address of the contract deployed by the deprecated +// [`DeployTransaction`] is consistent with that calculation. +impl_deploy_transaction_trait!(DeployTransaction); + /// An invoke V0 transaction. #[derive(Debug, Clone, Default, Eq, PartialEq, Hash, Deserialize, Serialize, PartialOrd, Ord)] pub struct InvokeTransactionV0 { @@ -674,6 +766,12 @@ pub struct L1HandlerTransaction { pub calldata: Calldata, } +impl L1HandlerTransaction { + /// The transaction version is considered 0 for L1-Handler transaction for hash calculation + /// purposes. + pub const VERSION: TransactionVersion = TransactionVersion::ZERO; +} + impl TransactionHasher for L1HandlerTransaction { fn calculate_transaction_hash( &self, @@ -767,7 +865,7 @@ pub enum TransactionExecutionStatus { /// A reverted transaction execution status. #[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize, PartialOrd, Ord)] pub struct RevertedTransactionExecutionStatus { - // TODO: Validate it's an ASCII string. + // TODO(YoavGr): Validate it's an ASCII string. pub revert_reason: String, } /// The hash of a [Transaction](`crate::transaction::Transaction`). @@ -789,22 +887,31 @@ pub struct TransactionHash(pub StarkHash); impl std::fmt::Display for TransactionHash { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0) + write!(f, "{}", self.0.to_hex_string()) } } -// TODO(guyn): this is only used for conversion of transactions->executable transactions -// It should be removed once we integrate a proper way to calculate executable transaction hashes -impl From for Vec { - fn from(tx_hash: TransactionHash) -> Vec { - tx_hash.0.to_bytes_be().to_vec() +// Use this in tests to get a randomly generate transaction hash. +// Note that get_test_instance uses StarkHash::default, not a random value. +#[cfg(any(feature = "testing", test))] +impl TransactionHash { + pub fn random(rng: &mut impl rand::Rng) -> Self { + let mut byte_vec = vec![]; + for _ in 0..32 { + byte_vec.push(rng.gen::()); + } + let byte_array = byte_vec.try_into().expect("Expected a Vec of length 32"); + TransactionHash(StarkHash::from_bytes_be(&byte_array)) } } -impl From> for TransactionHash { - fn from(bytes: Vec) -> TransactionHash { - let array: [u8; 32] = bytes.try_into().expect("Expected a Vec of length 32"); - TransactionHash(StarkHash::from_bytes_be(&array)) - } + +/// A utility macro to create a [`TransactionHash`] from an unsigned integer representation. +#[cfg(any(feature = "testing", test))] +#[macro_export] +macro_rules! tx_hash { + ($tx_hash:expr) => { + $crate::transaction::TransactionHash($crate::hash::StarkHash::from($tx_hash)) + }; } /// A transaction version. @@ -838,7 +945,7 @@ impl TransactionVersion { pub const THREE: Self = { Self(Felt::THREE) }; } -// TODO: TransactionVersion and SignedTransactionVersion should probably be separate types. +// TODO(Dori): TransactionVersion and SignedTransactionVersion should probably be separate types. // Returns the transaction version taking into account the transaction options. pub fn signed_tx_version_from_tx( tx: &Transaction, @@ -891,7 +998,8 @@ pub struct L2ToL1Payload(pub Vec); /// An event. #[derive(Debug, Clone, Default, Eq, PartialEq, Hash, Deserialize, Serialize, PartialOrd, Ord)] pub struct Event { - // TODO: Add a TransactionHash element to this struct, and then remove EventLeafElements. + // TODO(Gilad): Add a TransactionHash element to this struct, and then remove + // EventLeafElements. pub from_address: ContractAddress, #[serde(flatten)] pub content: EventContent, diff --git a/crates/starknet_api/src/transaction/fields.rs b/crates/starknet_api/src/transaction/fields.rs index 5e1df8e112f..de2b6392641 100644 --- a/crates/starknet_api/src/transaction/fields.rs +++ b/crates/starknet_api/src/transaction/fields.rs @@ -6,7 +6,7 @@ use starknet_types_core::felt::Felt; use strum_macros::EnumIter; use crate::block::{GasPrice, NonzeroGasPrice}; -use crate::execution_resources::GasAmount; +use crate::execution_resources::{GasAmount, GasVector}; use crate::hash::StarkHash; use crate::serde_utils::PrefixedBytesAsHex; use crate::StarknetApiError; @@ -162,6 +162,7 @@ pub enum Resource { #[serde(rename = "L2_GAS")] L2Gas, #[serde(rename = "L1_DATA")] + #[serde(alias = "L1_DATA_GAS")] L1DataGas, } @@ -369,6 +370,14 @@ impl AllResourceBounds { Resource::L1DataGas => self.l1_data_gas, } } + + pub fn to_max_amounts(&self) -> GasVector { + GasVector { + l1_gas: self.l1_gas.max_amount, + l1_data_gas: self.l1_data_gas.max_amount, + l2_gas: self.l2_gas.max_amount, + } + } } /// Deserializes raw resource bounds, given as map, into valid resource bounds. diff --git a/crates/starknet_api/src/transaction_hash.rs b/crates/starknet_api/src/transaction_hash.rs index e612e68f7a6..51ad2201eba 100644 --- a/crates/starknet_api/src/transaction_hash.rs +++ b/crates/starknet_api/src/transaction_hash.rs @@ -3,12 +3,21 @@ use std::sync::LazyLock; use starknet_types_core::felt::Felt; use crate::block::BlockNumber; -use crate::core::{ascii_as_felt, calculate_contract_address, ChainId, ContractAddress}; +use crate::core::{ascii_as_felt, ChainId, ClassHash, CompiledClassHash, ContractAddress, Nonce}; use crate::crypto::utils::HashChain; use crate::data_availability::DataAvailabilityMode; -use crate::transaction::fields::{ResourceBounds, Tip, ValidResourceBounds}; +use crate::transaction::fields::{ + AccountDeploymentData, + Calldata, + ContractAddressSalt, + PaymasterData, + ResourceBounds, + Tip, + ValidResourceBounds, +}; use crate::transaction::{ signed_tx_version_from_tx, + CalculateContractAddress, DeclareTransaction, DeclareTransactionV0V1, DeclareTransactionV2, @@ -256,12 +265,7 @@ fn get_common_deploy_transaction_hash( is_deprecated: bool, transaction_version: &TransactionVersion, ) -> Result { - let contract_address = calculate_contract_address( - transaction.contract_address_salt, - transaction.class_hash, - &transaction.constructor_calldata, - ContractAddress::from(0_u8), - )?; + let contract_address = transaction.calculate_contract_address()?; Ok(TransactionHash( HashChain::new() @@ -347,34 +351,48 @@ pub(crate) fn get_invoke_transaction_v1_hash( )) } -pub(crate) fn get_invoke_transaction_v3_hash( - transaction: &InvokeTransactionV3, +/// A trait intended for version 3 invoke transactions. Structs implementing this trait can use the +/// function [get_invoke_transaction_v3_hash]. +pub(crate) trait InvokeTransactionV3Trait { + fn resource_bounds(&self) -> ValidResourceBounds; + fn tip(&self) -> &Tip; + fn paymaster_data(&self) -> &PaymasterData; + fn nonce_data_availability_mode(&self) -> &DataAvailabilityMode; + fn fee_data_availability_mode(&self) -> &DataAvailabilityMode; + fn account_deployment_data(&self) -> &AccountDeploymentData; + fn calldata(&self) -> &Calldata; + fn sender_address(&self) -> &ContractAddress; + fn nonce(&self) -> &Nonce; +} + +pub(crate) fn get_invoke_transaction_v3_hash( + transaction: &T, chain_id: &ChainId, transaction_version: &TransactionVersion, ) -> Result { let tip_resource_bounds_hash = - get_tip_resource_bounds_hash(&transaction.resource_bounds, &transaction.tip)?; + get_tip_resource_bounds_hash(&transaction.resource_bounds(), transaction.tip())?; let paymaster_data_hash = - HashChain::new().chain_iter(transaction.paymaster_data.0.iter()).get_poseidon_hash(); + HashChain::new().chain_iter(transaction.paymaster_data().0.iter()).get_poseidon_hash(); let data_availability_mode = concat_data_availability_mode( - &transaction.nonce_data_availability_mode, - &transaction.fee_data_availability_mode, + transaction.nonce_data_availability_mode(), + transaction.fee_data_availability_mode(), ); let account_deployment_data_hash = HashChain::new() - .chain_iter(transaction.account_deployment_data.0.iter()) + .chain_iter(transaction.account_deployment_data().0.iter()) .get_poseidon_hash(); let calldata_hash = - HashChain::new().chain_iter(transaction.calldata.0.iter()).get_poseidon_hash(); + HashChain::new().chain_iter(transaction.calldata().0.iter()).get_poseidon_hash(); Ok(TransactionHash( HashChain::new() .chain(&INVOKE) .chain(&transaction_version.0) - .chain(transaction.sender_address.0.key()) + .chain(transaction.sender_address().0.key()) .chain(&tip_resource_bounds_hash) .chain(&paymaster_data_hash) .chain(&ascii_as_felt(chain_id.to_string().as_str())?) - .chain(&transaction.nonce.0) + .chain(&transaction.nonce().0) .chain(&data_availability_mode) .chain(&account_deployment_data_hash) .chain(&calldata_hash) @@ -382,6 +400,36 @@ pub(crate) fn get_invoke_transaction_v3_hash( )) } +impl InvokeTransactionV3Trait for InvokeTransactionV3 { + fn resource_bounds(&self) -> ValidResourceBounds { + self.resource_bounds + } + fn tip(&self) -> &Tip { + &self.tip + } + fn paymaster_data(&self) -> &PaymasterData { + &self.paymaster_data + } + fn nonce_data_availability_mode(&self) -> &DataAvailabilityMode { + &self.nonce_data_availability_mode + } + fn fee_data_availability_mode(&self) -> &DataAvailabilityMode { + &self.fee_data_availability_mode + } + fn account_deployment_data(&self) -> &AccountDeploymentData { + &self.account_deployment_data + } + fn sender_address(&self) -> &ContractAddress { + &self.sender_address + } + fn nonce(&self) -> &Nonce { + &self.nonce + } + fn calldata(&self) -> &Calldata { + &self.calldata + } +} + #[derive(PartialEq, PartialOrd)] enum L1HandlerVersions { AsInvoke, @@ -526,40 +574,88 @@ pub(crate) fn get_declare_transaction_v2_hash( )) } -pub(crate) fn get_declare_transaction_v3_hash( - transaction: &DeclareTransactionV3, +/// A trait intended for version 3 declare transactions. Structs implementing this trait can use the +/// function [get_declare_transaction_v3_hash]. +pub(crate) trait DeclareTransactionV3Trait { + fn resource_bounds(&self) -> ValidResourceBounds; + fn tip(&self) -> &Tip; + fn paymaster_data(&self) -> &PaymasterData; + fn nonce_data_availability_mode(&self) -> &DataAvailabilityMode; + fn fee_data_availability_mode(&self) -> &DataAvailabilityMode; + fn account_deployment_data(&self) -> &AccountDeploymentData; + fn sender_address(&self) -> &ContractAddress; + fn nonce(&self) -> &Nonce; + fn class_hash(&self) -> &ClassHash; + fn compiled_class_hash(&self) -> &CompiledClassHash; +} + +pub(crate) fn get_declare_transaction_v3_hash( + transaction: &T, chain_id: &ChainId, transaction_version: &TransactionVersion, ) -> Result { let tip_resource_bounds_hash = - get_tip_resource_bounds_hash(&transaction.resource_bounds, &transaction.tip)?; + get_tip_resource_bounds_hash(&transaction.resource_bounds(), transaction.tip())?; let paymaster_data_hash = - HashChain::new().chain_iter(transaction.paymaster_data.0.iter()).get_poseidon_hash(); + HashChain::new().chain_iter(transaction.paymaster_data().0.iter()).get_poseidon_hash(); let data_availability_mode = concat_data_availability_mode( - &transaction.nonce_data_availability_mode, - &transaction.fee_data_availability_mode, + transaction.nonce_data_availability_mode(), + transaction.fee_data_availability_mode(), ); let account_deployment_data_hash = HashChain::new() - .chain_iter(transaction.account_deployment_data.0.iter()) + .chain_iter(transaction.account_deployment_data().0.iter()) .get_poseidon_hash(); Ok(TransactionHash( HashChain::new() .chain(&DECLARE) .chain(&transaction_version.0) - .chain(transaction.sender_address.0.key()) + .chain(transaction.sender_address().0.key()) .chain(&tip_resource_bounds_hash) .chain(&paymaster_data_hash) .chain(&ascii_as_felt(chain_id.to_string().as_str())?) - .chain(&transaction.nonce.0) + .chain(&transaction.nonce().0) .chain(&data_availability_mode) .chain(&account_deployment_data_hash) - .chain(&transaction.class_hash.0) - .chain(&transaction.compiled_class_hash.0) + .chain(&transaction.class_hash().0) + .chain(&transaction.compiled_class_hash().0) .get_poseidon_hash(), )) } +impl DeclareTransactionV3Trait for DeclareTransactionV3 { + fn resource_bounds(&self) -> ValidResourceBounds { + self.resource_bounds + } + fn tip(&self) -> &Tip { + &self.tip + } + fn paymaster_data(&self) -> &PaymasterData { + &self.paymaster_data + } + fn nonce_data_availability_mode(&self) -> &DataAvailabilityMode { + &self.nonce_data_availability_mode + } + fn fee_data_availability_mode(&self) -> &DataAvailabilityMode { + &self.fee_data_availability_mode + } + fn account_deployment_data(&self) -> &AccountDeploymentData { + &self.account_deployment_data + } + fn sender_address(&self) -> &ContractAddress { + &self.sender_address + } + fn nonce(&self) -> &Nonce { + &self.nonce + } + fn class_hash(&self) -> &ClassHash { + &self.class_hash + } + fn compiled_class_hash(&self) -> &CompiledClassHash { + &self.compiled_class_hash + } +} + pub(crate) fn get_deploy_account_transaction_v1_hash( transaction: &DeployAccountTransactionV1, chain_id: &ChainId, @@ -571,12 +667,7 @@ pub(crate) fn get_deploy_account_transaction_v1_hash( .chain_iter(transaction.constructor_calldata.0.iter()) .get_pedersen_hash(); - let contract_address = calculate_contract_address( - transaction.contract_address_salt, - transaction.class_hash, - &transaction.constructor_calldata, - ContractAddress::from(0_u8), - )?; + let contract_address = transaction.calculate_contract_address()?; Ok(TransactionHash( HashChain::new() @@ -592,27 +683,41 @@ pub(crate) fn get_deploy_account_transaction_v1_hash( )) } -pub(crate) fn get_deploy_account_transaction_v3_hash( - transaction: &DeployAccountTransactionV3, +// TODO(Arni): Share properties with [crate::transaction::DeployTransactionTrait] - which allows the +// computation of contract address. +/// A trait intended for version 3 deploy account transactions. Structs implementing this trait +/// can use the function [get_deploy_account_transaction_v3_hash]. +pub(crate) trait DeployAccountTransactionV3Trait { + fn resource_bounds(&self) -> ValidResourceBounds; + fn tip(&self) -> &Tip; + fn paymaster_data(&self) -> &PaymasterData; + fn nonce_data_availability_mode(&self) -> &DataAvailabilityMode; + fn fee_data_availability_mode(&self) -> &DataAvailabilityMode; + fn constructor_calldata(&self) -> &Calldata; + fn nonce(&self) -> &Nonce; + fn class_hash(&self) -> &ClassHash; + fn contract_address_salt(&self) -> &ContractAddressSalt; +} + +pub(crate) fn get_deploy_account_transaction_v3_hash< + T: DeployAccountTransactionV3Trait + CalculateContractAddress, +>( + transaction: &T, chain_id: &ChainId, transaction_version: &TransactionVersion, ) -> Result { - let contract_address = calculate_contract_address( - transaction.contract_address_salt, - transaction.class_hash, - &transaction.constructor_calldata, - ContractAddress::from(0_u8), - )?; + let contract_address = transaction.calculate_contract_address()?; let tip_resource_bounds_hash = - get_tip_resource_bounds_hash(&transaction.resource_bounds, &transaction.tip)?; + get_tip_resource_bounds_hash(&transaction.resource_bounds(), transaction.tip())?; let paymaster_data_hash = - HashChain::new().chain_iter(transaction.paymaster_data.0.iter()).get_poseidon_hash(); + HashChain::new().chain_iter(transaction.paymaster_data().0.iter()).get_poseidon_hash(); let data_availability_mode = concat_data_availability_mode( - &transaction.nonce_data_availability_mode, - &transaction.fee_data_availability_mode, + transaction.nonce_data_availability_mode(), + transaction.fee_data_availability_mode(), ); - let constructor_calldata_hash = - HashChain::new().chain_iter(transaction.constructor_calldata.0.iter()).get_poseidon_hash(); + let constructor_calldata_hash = HashChain::new() + .chain_iter(transaction.constructor_calldata().0.iter()) + .get_poseidon_hash(); Ok(TransactionHash( HashChain::new() @@ -623,10 +728,40 @@ pub(crate) fn get_deploy_account_transaction_v3_hash( .chain(&paymaster_data_hash) .chain(&ascii_as_felt(chain_id.to_string().as_str())?) .chain(&data_availability_mode) - .chain(&transaction.nonce.0) + .chain(&transaction.nonce().0) .chain(&constructor_calldata_hash) - .chain(&transaction.class_hash.0) - .chain(&transaction.contract_address_salt.0) + .chain(&transaction.class_hash().0) + .chain(&transaction.contract_address_salt().0) .get_poseidon_hash(), )) } + +impl DeployAccountTransactionV3Trait for DeployAccountTransactionV3 { + fn resource_bounds(&self) -> ValidResourceBounds { + self.resource_bounds + } + fn tip(&self) -> &Tip { + &self.tip + } + fn paymaster_data(&self) -> &PaymasterData { + &self.paymaster_data + } + fn nonce_data_availability_mode(&self) -> &DataAvailabilityMode { + &self.nonce_data_availability_mode + } + fn fee_data_availability_mode(&self) -> &DataAvailabilityMode { + &self.fee_data_availability_mode + } + fn constructor_calldata(&self) -> &Calldata { + &self.constructor_calldata + } + fn nonce(&self) -> &Nonce { + &self.nonce + } + fn class_hash(&self) -> &ClassHash { + &self.class_hash + } + fn contract_address_salt(&self) -> &ContractAddressSalt { + &self.contract_address_salt + } +} diff --git a/crates/starknet_api/src/transaction_hash_test.rs b/crates/starknet_api/src/transaction_hash_test.rs index 32877f5be3c..71baae451f9 100644 --- a/crates/starknet_api/src/transaction_hash_test.rs +++ b/crates/starknet_api/src/transaction_hash_test.rs @@ -84,7 +84,6 @@ fn test_only_query_transaction_hash() { continue; } - dbg!(transaction_test_data.transaction_hash); let actual_transaction_hash = get_transaction_hash( &transaction_test_data.transaction, &transaction_test_data.chain_id, diff --git a/crates/starknet_api/src/transaction_test.rs b/crates/starknet_api/src/transaction_test.rs index 3c029603b5e..9ff28c58582 100644 --- a/crates/starknet_api/src/transaction_test.rs +++ b/crates/starknet_api/src/transaction_test.rs @@ -1,10 +1,36 @@ +use rstest::{fixture, rstest}; + use super::Transaction; use crate::block::NonzeroGasPrice; -use crate::executable_transaction::Transaction as ExecutableTransaction; +use crate::core::ChainId; +use crate::executable_transaction::{ + AccountTransaction, + InvokeTransaction, + L1HandlerTransaction, + Transaction as ExecutableTransaction, +}; use crate::execution_resources::GasAmount; use crate::test_utils::{read_json_file, TransactionTestData}; use crate::transaction::Fee; +const CHAIN_ID: ChainId = ChainId::Mainnet; + +#[fixture] +fn transactions_data() -> Vec { + // The details were taken from Starknet Mainnet. You can find the transactions by hash in: + // https://alpha-mainnet.starknet.io/feeder_gateway/get_transaction?transactionHash= + serde_json::from_value(read_json_file("transaction_hash.json")).unwrap() +} + +fn verify_transaction_conversion(tx: &Transaction, expected_executable_tx: ExecutableTransaction) { + let converted_executable_tx: ExecutableTransaction = + (tx.clone(), &CHAIN_ID).try_into().unwrap(); + let reconverted_tx = Transaction::from(converted_executable_tx.clone()); + + assert_eq!(converted_executable_tx, expected_executable_tx); + assert_eq!(tx, &reconverted_tx); +} + #[test] fn test_fee_div_ceil() { assert_eq!( @@ -29,27 +55,38 @@ fn test_fee_div_ceil() { ); } -#[test] -fn convert_executable_transaction_and_back() { - // The details were taken from Starknet Mainnet. You can find the transactions by hash in: - // https://alpha-mainnet.starknet.io/feeder_gateway/get_transaction?transactionHash= - let mut transactions_test_data_vec: Vec = - serde_json::from_value(read_json_file("transaction_hash.json")).unwrap(); - - let (tx, tx_hash) = loop { - match transactions_test_data_vec.pop() { - Some(data) => { - if let Transaction::Invoke(tx) = data.transaction { - // Do something with the data - break (Transaction::Invoke(tx), data.transaction_hash); - } - } - None => { - panic!("Could not find a single Invoke transaction in the test data"); - } - } +#[rstest] +fn test_invoke_executable_transaction_conversion(mut transactions_data: Vec) { + // Extract Invoke transaction data. + let transaction_data = transactions_data.remove(0); + let Transaction::Invoke(invoke_tx) = transaction_data.transaction.clone() else { + panic!("Transaction_hash.json is expected to have Invoke as the first transaction.") }; - let executable_tx: ExecutableTransaction = (tx.clone(), tx_hash.clone()).into(); - let tx_back = Transaction::from(executable_tx); - assert_eq!(tx, tx_back); + + let expected_executable_tx = + ExecutableTransaction::Account(AccountTransaction::Invoke(InvokeTransaction { + tx: invoke_tx, + tx_hash: transaction_data.transaction_hash, + })); + + verify_transaction_conversion(&transaction_data.transaction, expected_executable_tx); +} + +#[rstest] +fn test_l1_handler_executable_transaction_conversion( + mut transactions_data: Vec, +) { + // Extract L1 Handler transaction data. + let transaction_data = transactions_data.remove(10); + let Transaction::L1Handler(l1_handler_tx) = transaction_data.transaction.clone() else { + panic!("Transaction_hash.json is expected to have L1 Handler as the 11th transaction.") + }; + + let expected_executable_tx = ExecutableTransaction::L1Handler(L1HandlerTransaction { + tx: l1_handler_tx, + tx_hash: transaction_data.transaction_hash, + paid_fee_on_l1: Fee(1), + }); + + verify_transaction_conversion(&transaction_data.transaction, expected_executable_tx); } diff --git a/crates/starknet_api/src/versioned_constants_logic.rs b/crates/starknet_api/src/versioned_constants_logic.rs new file mode 100644 index 00000000000..ec946f5cabf --- /dev/null +++ b/crates/starknet_api/src/versioned_constants_logic.rs @@ -0,0 +1,62 @@ +/// Auto-generate getters for listed versioned constants versions. +#[macro_export] +macro_rules! define_versioned_constants { + ($struct_name:ident, $error_type:ident, $(($variant:ident, $path_to_json:expr)),* $(,)?) => { + // Static (lazy) instances of the versioned constants. + // For internal use only; for access to a static instance use the `StarknetVersion` enum. + paste::paste! { + $( + pub(crate) const []: &str = + include_str!($path_to_json); + /// Static instance of the versioned constants for the Starknet version. + pub static []: std::sync::LazyLock<$struct_name> = + std::sync::LazyLock::new(|| { + serde_json::from_str([]) + .expect(&format!("Versioned constants {} is malformed.", $path_to_json)) + }); + )* + } + + impl $struct_name { + /// Gets the path to the JSON file for the specified Starknet version. + pub fn path_to_json(version: &starknet_api::block::StarknetVersion) -> Result<&'static str, $error_type> { + match version { + $(starknet_api::block::StarknetVersion::$variant => Ok($path_to_json),)* + _ => Err($error_type::InvalidStarknetVersion(*version)), + } + } + + /// Gets the constants that shipped with the current version of the Starknet. + /// To use custom constants, initialize the struct from a file using `from_path`. + pub fn latest_constants() -> &'static Self { + Self::get(&starknet_api::block::StarknetVersion::LATEST) + .expect("Latest version should support VC.") + } + + /// Gets the constants for the specified Starknet version. + pub fn get(version: &starknet_api::block::StarknetVersion) -> Result<&'static Self, $error_type> { + match version { + $( + starknet_api::block::StarknetVersion::$variant => Ok( + & paste::paste! { [] } + ), + )* + _ => Err($error_type::InvalidStarknetVersion(*version)), + } + } + } + + /// Gets a string of the constants of the latest version of Starknet. + pub static VERSIONED_CONSTANTS_LATEST_JSON: std::sync::LazyLock = std::sync::LazyLock::new(|| { + let latest_variant = StarknetVersion::LATEST; + let path_to_json: std::path::PathBuf = [ + starknet_infra_utils::compile_time_cargo_manifest_dir!(), + "src".into(), + $struct_name::path_to_json(&latest_variant) + .expect("Latest variant should have a path to json.").into() + ].iter().collect(); + std::fs::read_to_string(path_to_json.clone()) + .expect(&format!("Failed to read file {}.", path_to_json.display())) + }); + }; +} diff --git a/crates/starknet_batcher/Cargo.toml b/crates/starknet_batcher/Cargo.toml index 7f14eb059da..5a70cc51fd1 100644 --- a/crates/starknet_batcher/Cargo.toml +++ b/crates/starknet_batcher/Cargo.toml @@ -5,13 +5,18 @@ edition.workspace = true license.workspace = true repository.workspace = true +[features] +testing = [] + [lints] workspace = true [dependencies] +apollo_reverts.workspace = true async-trait.workspace = true blockifier.workspace = true chrono.workspace = true +futures.workspace = true indexmap.workspace = true papyrus_config.workspace = true papyrus_state_reader.workspace = true @@ -19,8 +24,12 @@ papyrus_storage.workspace = true serde.workspace = true starknet_api.workspace = true starknet_batcher_types.workspace = true +starknet_class_manager_types.workspace = true +starknet_l1_provider_types.workspace = true starknet_mempool_types.workspace = true starknet_sequencer_infra.workspace = true +starknet_sequencer_metrics.workspace = true +starknet_state_sync_types.workspace = true thiserror.workspace = true tokio.workspace = true tracing.workspace = true @@ -28,11 +37,20 @@ validator.workspace = true [dev-dependencies] assert_matches.workspace = true +blockifier = { workspace = true, features = ["testing"] } +cairo-lang-starknet-classes.workspace = true chrono = { workspace = true } -futures.workspace = true mempool_test_utils.workspace = true +metrics.workspace = true +metrics-exporter-prometheus.workspace = true mockall.workspace = true +papyrus_storage = { workspace = true, features = ["testing"] } +pretty_assertions.workspace = true rstest.workspace = true starknet-types-core.workspace = true starknet_api = { workspace = true, features = ["testing"] } +starknet_class_manager_types = { workspace = true, features = ["testing"] } +starknet_infra_utils.workspace = true +starknet_l1_provider_types = { workspace = true, features = ["testing"] } starknet_mempool_types = { workspace = true, features = ["testing"] } +starknet_sequencer_metrics.workspace = true diff --git a/crates/starknet_batcher/src/batcher.rs b/crates/starknet_batcher/src/batcher.rs index 8a123996023..4ac036a8ac4 100644 --- a/crates/starknet_batcher/src/batcher.rs +++ b/crates/starknet_batcher/src/batcher.rs @@ -1,24 +1,32 @@ -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::sync::Arc; -use blockifier::abi::constants; -use blockifier::state::global_cache::GlobalContractCache; -use chrono::Utc; +use apollo_reverts::revert_block; +use async_trait::async_trait; +use blockifier::state::contract_class_manager::ContractClassManager; +use indexmap::IndexSet; #[cfg(test)] use mockall::automock; use papyrus_storage::state::{StateStorageReader, StateStorageWriter}; -use starknet_api::block::{BlockHashAndNumber, BlockNumber}; -use starknet_api::executable_transaction::Transaction; +use starknet_api::block::{BlockHeaderWithoutHash, BlockNumber}; +use starknet_api::consensus_transaction::InternalConsensusTransaction; +use starknet_api::core::{ContractAddress, Nonce}; use starknet_api::state::ThinStateDiff; +use starknet_api::transaction::TransactionHash; use starknet_batcher_types::batcher_types::{ BatcherResult, + CentralObjects, DecisionReachedInput, + DecisionReachedResponse, + GetHeightResponse, GetProposalContent, GetProposalContentInput, GetProposalContentResponse, + ProposalCommitment, ProposalId, ProposalStatus, ProposeBlockInput, + RevertBlockInput, SendProposalContent, SendProposalContentInput, SendProposalContentResponse, @@ -26,39 +34,86 @@ use starknet_batcher_types::batcher_types::{ ValidateBlockInput, }; use starknet_batcher_types::errors::BatcherError; +use starknet_class_manager_types::transaction_converter::TransactionConverter; +use starknet_class_manager_types::SharedClassManagerClient; +use starknet_l1_provider_types::errors::{L1ProviderClientError, L1ProviderError}; +use starknet_l1_provider_types::{SessionState, SharedL1ProviderClient}; use starknet_mempool_types::communication::SharedMempoolClient; use starknet_mempool_types::mempool_types::CommitBlockArgs; -use starknet_sequencer_infra::component_definitions::ComponentStarter; -use tracing::{debug, error, info, instrument, trace}; - -use crate::block_builder::{BlockBuilderError, BlockBuilderFactory}; +use starknet_sequencer_infra::component_definitions::{ + default_component_start_fn, + ComponentStarter, +}; +use starknet_state_sync_types::state_sync_types::SyncBlock; +use tokio::sync::Mutex; +use tracing::{debug, error, info, instrument, trace, Instrument}; + +use crate::block_builder::{ + BlockBuilderError, + BlockBuilderExecutionParams, + BlockBuilderFactory, + BlockBuilderFactoryTrait, + BlockBuilderTrait, + BlockExecutionArtifacts, + BlockMetadata, +}; use crate::config::BatcherConfig; -use crate::proposal_manager::{ - GenerateProposalError, - GetProposalResultError, - InternalProposalStatus, - ProposalManager, - ProposalManagerTrait, - ProposalOutput, +use crate::metrics::{ + register_metrics, + ProposalMetricsHandle, + BATCHED_TRANSACTIONS, + CLASS_CACHE_HITS, + CLASS_CACHE_MISSES, + REJECTED_TRANSACTIONS, + REVERTED_BLOCKS, + STORAGE_HEIGHT, + SYNCED_BLOCKS, + SYNCED_TRANSACTIONS, }; -use crate::transaction_provider::{ - DummyL1ProviderClient, - ProposeTransactionProvider, - ValidateTransactionProvider, +use crate::transaction_provider::{ProposeTransactionProvider, ValidateTransactionProvider}; +use crate::utils::{ + deadline_as_instant, + proposal_status_from, + verify_block_input, + ProposalResult, + ProposalTask, }; -type OutputStreamReceiver = tokio::sync::mpsc::UnboundedReceiver; -type InputStreamSender = tokio::sync::mpsc::Sender; +type OutputStreamReceiver = tokio::sync::mpsc::UnboundedReceiver; +type InputStreamSender = tokio::sync::mpsc::Sender; pub struct Batcher { pub config: BatcherConfig, pub storage_reader: Arc, pub storage_writer: Box, + pub l1_provider_client: SharedL1ProviderClient, pub mempool_client: SharedMempoolClient, + pub transaction_converter: TransactionConverter, + // Used to create block builders. + // Using the factory pattern to allow for easier testing. + block_builder_factory: Box, + + // The height that the batcher is currently working on. + // All proposals are considered to be at this height. active_height: Option, - proposal_manager: Box, + + // The block proposal that is currently being built, if any. + // At any given time, there can be only one proposal being actively executed (either proposed + // or validated). + active_proposal: Arc>>, + active_proposal_task: Option, + + // Holds all the proposals that completed execution in the current height. + executed_proposals: Arc>>>, + + // The propose blocks transaction streams, used to stream out the proposal transactions. + // Each stream is kept until all the transactions are streamed out, or a new height is started. propose_tx_streams: HashMap, + + // The validate blocks transaction streams, used to stream in the transactions to validate. + // Each stream is kept until SendProposalContent::Finish/Abort is received, or a new height is + // started. validate_tx_streams: HashMap, } @@ -67,16 +122,23 @@ impl Batcher { config: BatcherConfig, storage_reader: Arc, storage_writer: Box, + l1_provider_client: SharedL1ProviderClient, mempool_client: SharedMempoolClient, - proposal_manager: Box, + transaction_converter: TransactionConverter, + block_builder_factory: Box, ) -> Self { Self { config: config.clone(), storage_reader, storage_writer, + l1_provider_client, mempool_client, + transaction_converter, + block_builder_factory, active_height: None, - proposal_manager, + active_proposal: Arc::new(Mutex::new(None)), + active_proposal_task: None, + executed_proposals: Arc::new(Mutex::new(HashMap::new())), propose_tx_streams: HashMap::new(), validate_tx_streams: HashMap::new(), } @@ -88,25 +150,15 @@ impl Batcher { return Err(BatcherError::HeightInProgress); } - let storage_height = - self.storage_reader.height().map_err(|_| BatcherError::InternalError)?; - if storage_height < input.height { - return Err(BatcherError::StorageNotSynced { - storage_height, - requested_height: input.height, - }); - } - if storage_height > input.height { - return Err(BatcherError::HeightAlreadyPassed { - storage_height, + let storage_height = self.get_height_from_storage()?; + if storage_height != input.height { + return Err(BatcherError::StorageHeightMarkerMismatch { + marker_height: storage_height, requested_height: input.height, }); } - // Clear all the proposals from the previous height. - self.proposal_manager.reset().await; - self.propose_tx_streams.clear(); - self.validate_tx_streams.clear(); + self.abort_active_height().await; info!("Starting to work on height {}.", input.height); self.active_height = Some(input.height); @@ -119,32 +171,81 @@ impl Batcher { &mut self, propose_block_input: ProposeBlockInput, ) -> BatcherResult<()> { + let proposal_metrics_handle = ProposalMetricsHandle::new(); let active_height = self.active_height.ok_or(BatcherError::NoActiveHeight)?; - verify_block_input(active_height, propose_block_input.retrospective_block_hash)?; - - let proposal_id = propose_block_input.proposal_id; - let deadline = deadline_as_instant(propose_block_input.deadline)?; + verify_block_input( + active_height, + propose_block_input.block_info.block_number, + propose_block_input.retrospective_block_hash, + )?; + + // TODO(yair): extract function for the following calls, use join_all. + self.mempool_client.commit_block(CommitBlockArgs::default()).await.map_err(|err| { + error!( + "Mempool is not ready to start proposal {}: {}.", + propose_block_input.proposal_id, err + ); + BatcherError::NotReady + })?; + self.mempool_client + .update_gas_price( + propose_block_input.block_info.gas_prices.strk_gas_prices.l2_gas_price, + ) + .await + .map_err(|err| { + error!("Failed to update gas price in mempool: {}", err); + BatcherError::InternalError + })?; + self.l1_provider_client + .start_block(SessionState::Propose, propose_block_input.block_info.block_number) + .await + .map_err(|err| { + error!( + "L1 provider is not ready to start proposing block {}: {}. ", + propose_block_input.block_info.block_number, err + ); + BatcherError::NotReady + })?; - let (output_tx_sender, output_tx_receiver) = tokio::sync::mpsc::unbounded_channel(); let tx_provider = ProposeTransactionProvider::new( self.mempool_client.clone(), - // TODO: use a real L1 provider client. - Arc::new(DummyL1ProviderClient), + self.l1_provider_client.clone(), self.config.max_l1_handler_txs_per_block_proposal, + propose_block_input.block_info.block_number, ); - self.proposal_manager - .propose_block( - active_height, - proposal_id, - propose_block_input.retrospective_block_hash, - deadline, - output_tx_sender, - tx_provider, - ) - .await?; + // A channel to receive the transactions included in the proposed block. + let (output_tx_sender, output_tx_receiver) = tokio::sync::mpsc::unbounded_channel(); - self.propose_tx_streams.insert(proposal_id, output_tx_receiver); + let (block_builder, abort_signal_sender) = self + .block_builder_factory + .create_block_builder( + BlockMetadata { + block_info: propose_block_input.block_info, + retrospective_block_hash: propose_block_input.retrospective_block_hash, + }, + BlockBuilderExecutionParams { + deadline: deadline_as_instant(propose_block_input.deadline)?, + fail_on_err: false, + }, + Box::new(tx_provider), + Some(output_tx_sender), + tokio::runtime::Handle::current(), + ) + .map_err(|err| { + error!("Failed to get block builder: {}", err); + BatcherError::InternalError + })?; + + self.spawn_proposal( + propose_block_input.proposal_id, + block_builder, + abort_signal_sender, + proposal_metrics_handle, + ) + .await?; + + self.propose_tx_streams.insert(propose_block_input.proposal_id, output_tx_receiver); Ok(()) } @@ -153,31 +254,64 @@ impl Batcher { &mut self, validate_block_input: ValidateBlockInput, ) -> BatcherResult<()> { + let proposal_metrics_handle = ProposalMetricsHandle::new(); let active_height = self.active_height.ok_or(BatcherError::NoActiveHeight)?; - verify_block_input(active_height, validate_block_input.retrospective_block_hash)?; - - let proposal_id = validate_block_input.proposal_id; - let deadline = deadline_as_instant(validate_block_input.deadline)?; - + verify_block_input( + active_height, + validate_block_input.block_info.block_number, + validate_block_input.retrospective_block_hash, + )?; + + self.l1_provider_client + .start_block(SessionState::Validate, validate_block_input.block_info.block_number) + .await + .map_err(|err| { + error!( + "L1 provider is not ready to start validating block {}: {}. ", + validate_block_input.block_info.block_number, err + ); + BatcherError::NotReady + })?; + + // A channel to send the transactions to include in the block being validated. let (input_tx_sender, input_tx_receiver) = tokio::sync::mpsc::channel(self.config.input_stream_content_buffer_size); + let tx_provider = ValidateTransactionProvider { tx_receiver: input_tx_receiver, - // TODO: use a real L1 provider client. - l1_provider_client: Arc::new(DummyL1ProviderClient), + l1_provider_client: self.l1_provider_client.clone(), + height: validate_block_input.block_info.block_number, }; - self.proposal_manager - .validate_block( - active_height, - proposal_id, - validate_block_input.retrospective_block_hash, - deadline, - tx_provider, + let (block_builder, abort_signal_sender) = self + .block_builder_factory + .create_block_builder( + BlockMetadata { + block_info: validate_block_input.block_info, + retrospective_block_hash: validate_block_input.retrospective_block_hash, + }, + BlockBuilderExecutionParams { + deadline: deadline_as_instant(validate_block_input.deadline)?, + fail_on_err: true, + }, + Box::new(tx_provider), + None, + tokio::runtime::Handle::current(), ) - .await?; - - self.validate_tx_streams.insert(proposal_id, input_tx_sender); + .map_err(|err| { + error!("Failed to get block builder: {}", err); + BatcherError::InternalError + })?; + + self.spawn_proposal( + validate_block_input.proposal_id, + block_builder, + abort_signal_sender, + proposal_metrics_handle, + ) + .await?; + + self.validate_tx_streams.insert(validate_block_input.proposal_id, input_tx_sender); Ok(()) } @@ -189,77 +323,101 @@ impl Batcher { send_proposal_content_input: SendProposalContentInput, ) -> BatcherResult { let proposal_id = send_proposal_content_input.proposal_id; + if !self.validate_tx_streams.contains_key(&proposal_id) { + return Err(BatcherError::ProposalNotFound { proposal_id }); + } match send_proposal_content_input.content { - SendProposalContent::Txs(txs) => self.send_txs_and_get_status(proposal_id, txs).await, - SendProposalContent::Finish => { - self.close_tx_channel_and_get_commitment(proposal_id).await - } - SendProposalContent::Abort => { - self.proposal_manager.abort_proposal(proposal_id).await; - Ok(SendProposalContentResponse { response: ProposalStatus::Aborted }) - } + SendProposalContent::Txs(txs) => self.handle_send_txs_request(proposal_id, txs).await, + SendProposalContent::Finish => self.handle_finish_proposal_request(proposal_id).await, + SendProposalContent::Abort => self.handle_abort_proposal_request(proposal_id).await, } } - async fn send_txs_and_get_status( + /// Clear all the proposals from the previous height. + async fn abort_active_height(&mut self) { + self.abort_active_proposal().await; + self.executed_proposals.lock().await.clear(); + self.propose_tx_streams.clear(); + self.validate_tx_streams.clear(); + self.active_height = None; + } + + async fn handle_send_txs_request( &mut self, proposal_id: ProposalId, - txs: Vec, + txs: Vec, ) -> BatcherResult { - match self.proposal_manager.get_proposal_status(proposal_id).await { - InternalProposalStatus::Processing => { - let tx_provider_sender = &self - .validate_tx_streams - .get(&proposal_id) - .expect("Expecting tx_provider_sender to exist during batching."); - for tx in txs { - tx_provider_sender.send(tx).await.map_err(|err| { - error!("Failed to send transaction to the tx provider: {}", err); - BatcherError::InternalError - })?; - } - Ok(SendProposalContentResponse { response: ProposalStatus::Processing }) - } - // Proposal Got an Error while processing transactions. - InternalProposalStatus::Failed => { - Ok(SendProposalContentResponse { response: ProposalStatus::InvalidProposal }) + if self.is_active(proposal_id).await { + // The proposal is active. Send the transactions through the tx provider. + let tx_provider_sender = &self + .validate_tx_streams + .get(&proposal_id) + .expect("Expecting tx_provider_sender to exist during batching."); + for tx in txs { + tx_provider_sender.send(tx).await.map_err(|err| { + error!("Failed to send transaction to the tx provider: {}", err); + BatcherError::InternalError + })?; } - InternalProposalStatus::Finished => { - Err(BatcherError::ProposalAlreadyFinished { proposal_id }) - } - InternalProposalStatus::NotFound => Err(BatcherError::ProposalNotFound { proposal_id }), + return Ok(SendProposalContentResponse { response: ProposalStatus::Processing }); + } + + // The proposal is no longer active, can't send the transactions. + let proposal_result = + self.get_completed_proposal_result(proposal_id).await.expect("Proposal should exist."); + match proposal_result { + Ok(_) => panic!("Proposal finished validation before all transactions were sent."), + Err(err) => Ok(SendProposalContentResponse { response: proposal_status_from(err)? }), } } - async fn close_tx_channel_and_get_commitment( + async fn handle_finish_proposal_request( &mut self, proposal_id: ProposalId, ) -> BatcherResult { debug!("Send proposal content done for {}", proposal_id); - self.close_input_transaction_stream(proposal_id)?; + self.validate_tx_streams.remove(&proposal_id).expect("validate tx stream should exist."); + if self.is_active(proposal_id).await { + self.await_active_proposal().await; + } - let response = match self.proposal_manager.await_proposal_commitment(proposal_id).await { - Ok(proposal_commitment) => ProposalStatus::Finished(proposal_commitment), - Err(GetProposalResultError::BlockBuilderError(err)) => match err.as_ref() { - BlockBuilderError::FailOnError(_) => ProposalStatus::InvalidProposal, - _ => return Err(BatcherError::InternalError), - }, - Err(GetProposalResultError::ProposalDoesNotExist { proposal_id: _ }) - | Err(GetProposalResultError::Aborted) => { - panic!("Proposal {} should exist in the proposal manager.", proposal_id) - } + let proposal_result = + self.get_completed_proposal_result(proposal_id).await.expect("Proposal should exist."); + let proposal_status = match proposal_result { + Ok(commitment) => ProposalStatus::Finished(commitment), + Err(err) => proposal_status_from(err)?, }; + Ok(SendProposalContentResponse { response: proposal_status }) + } - Ok(SendProposalContentResponse { response }) + async fn handle_abort_proposal_request( + &mut self, + proposal_id: ProposalId, + ) -> BatcherResult { + if self.is_active(proposal_id).await { + self.abort_active_proposal().await; + self.executed_proposals + .lock() + .await + .insert(proposal_id, Err(Arc::new(BlockBuilderError::Aborted))); + } + self.validate_tx_streams.remove(&proposal_id); + Ok(SendProposalContentResponse { response: ProposalStatus::Aborted }) } - fn close_input_transaction_stream(&mut self, proposal_id: ProposalId) -> BatcherResult<()> { - self.validate_tx_streams - .remove(&proposal_id) - .ok_or(BatcherError::ProposalNotFound { proposal_id })?; - Ok(()) + fn get_height_from_storage(&self) -> BatcherResult { + self.storage_reader.height().map_err(|err| { + error!("Failed to get height from storage: {}", err); + BatcherError::InternalError + }) + } + + #[instrument(skip(self), err)] + pub async fn get_height(&self) -> BatcherResult { + let height = self.get_height_from_storage()?; + Ok(GetHeightResponse { height }) } #[instrument(skip(self), err)] @@ -285,59 +443,325 @@ impl Batcher { } // Finished streaming all the transactions. - // TODO: Consider removing the proposal from the proposal manager and keep it in the batcher - // for decision reached. + // TODO(AlonH): Consider removing the proposal from the proposal manager and keep it in the + // batcher for decision reached. self.propose_tx_streams.remove(&proposal_id); - let proposal_commitment = - self.proposal_manager.await_proposal_commitment(proposal_id).await?; - Ok(GetProposalContentResponse { - content: GetProposalContent::Finished(proposal_commitment), - }) + let commitment = self + .get_completed_proposal_result(proposal_id) + .await + .expect("Proposal should exist.") + .map_err(|err| { + error!("Failed to get commitment: {}", err); + BatcherError::InternalError + })?; + + Ok(GetProposalContentResponse { content: GetProposalContent::Finished(commitment) }) + } + + #[instrument(skip(self, sync_block), err)] + pub async fn add_sync_block(&mut self, sync_block: SyncBlock) -> BatcherResult<()> { + trace!("Received sync block: {:?}", sync_block); + // TODO(AlonH): Use additional data from the sync block. + let SyncBlock { + state_diff, + transaction_hashes, + block_header_without_hash: BlockHeaderWithoutHash { block_number, .. }, + } = sync_block; + + let height = self.get_height_from_storage()?; + if height != block_number { + return Err(BatcherError::StorageHeightMarkerMismatch { + marker_height: height, + requested_height: block_number, + }); + } + + if let Some(height) = self.active_height { + info!("Aborting all work on height {} due to state sync.", height); + self.abort_active_height().await; + } + + let address_to_nonce = state_diff.nonces.iter().map(|(k, v)| (*k, *v)).collect(); + self.commit_proposal_and_block( + height, + state_diff, + address_to_nonce, + Default::default(), + Default::default(), + ) + .await?; + SYNCED_BLOCKS.increment(1); + SYNCED_TRANSACTIONS.increment(transaction_hashes.len().try_into().unwrap()); + Ok(()) } #[instrument(skip(self), err)] - pub async fn decision_reached(&mut self, input: DecisionReachedInput) -> BatcherResult<()> { + pub async fn decision_reached( + &mut self, + input: DecisionReachedInput, + ) -> BatcherResult { + let height = self.active_height.ok_or(BatcherError::NoActiveHeight)?; + let proposal_id = input.proposal_id; - let proposal_output = self.proposal_manager.take_proposal_result(proposal_id).await?; - let ProposalOutput { state_diff, nonces: address_to_nonce, tx_hashes, .. } = - proposal_output; - // TODO: Keep the height from start_height or get it from the input. - let height = self.storage_reader.height().map_err(|err| { - error!("Failed to get height from storage: {}", err); - BatcherError::InternalError - })?; + let proposal_result = self.executed_proposals.lock().await.remove(&proposal_id); + let block_execution_artifacts = proposal_result + .ok_or(BatcherError::ExecutedProposalNotFound { proposal_id })? + .map_err(|err| { + error!("Failed to get block execution artifacts: {}", err); + BatcherError::InternalError + })?; + let state_diff = block_execution_artifacts.thin_state_diff(); + let n_txs = u64::try_from(block_execution_artifacts.tx_hashes().len()) + .expect("Number of transactions should fit in u64"); + let n_rejected_txs = + u64::try_from(block_execution_artifacts.execution_data.rejected_tx_hashes.len()) + .expect("Number of rejected transactions should fit in u64"); + self.commit_proposal_and_block( + height, + state_diff.clone(), + block_execution_artifacts.address_to_nonce(), + block_execution_artifacts.execution_data.accepted_l1_handler_tx_hashes, + block_execution_artifacts.execution_data.rejected_tx_hashes, + ) + .await?; + let execution_infos: Vec<_> = block_execution_artifacts + .execution_data + .execution_infos + .into_iter() + .map(|(_, info)| info) + .collect(); + + CLASS_CACHE_MISSES.increment(self.block_builder_factory.take_class_cache_miss_counter()); + CLASS_CACHE_HITS.increment(self.block_builder_factory.take_class_cache_hit_counter()); + BATCHED_TRANSACTIONS.increment(n_txs); + REJECTED_TRANSACTIONS.increment(n_rejected_txs); + + Ok(DecisionReachedResponse { + state_diff, + l2_gas_used: block_execution_artifacts.l2_gas_used, + central_objects: CentralObjects { + execution_infos, + bouncer_weights: block_execution_artifacts.bouncer_weights, + compressed_state_diff: block_execution_artifacts.compressed_state_diff, + }, + }) + } + + async fn commit_proposal_and_block( + &mut self, + height: BlockNumber, + state_diff: ThinStateDiff, + address_to_nonce: HashMap, + accepted_l1_handler_tx_hashes: IndexSet, + rejected_tx_hashes: HashSet, + ) -> BatcherResult<()> { info!( - "Committing proposal {} at height {} and notifying mempool of the block.", - proposal_id, height + "Committing block at height {} and notifying mempool & L1 event provider of the block.", + height ); - trace!("Transactions: {:#?}, State diff: {:#?}.", tx_hashes, state_diff); + trace!("Rejected transactions: {:#?}, State diff: {:#?}.", rejected_tx_hashes, state_diff); + + // Commit the proposal to the storage and notify the mempool. self.storage_writer.commit_proposal(height, state_diff).map_err(|err| { error!("Failed to commit proposal to storage: {}", err); BatcherError::InternalError })?; - if let Err(mempool_err) = - self.mempool_client.commit_block(CommitBlockArgs { address_to_nonce, tx_hashes }).await - { + STORAGE_HEIGHT.increment(1); + let mempool_result = self + .mempool_client + .commit_block(CommitBlockArgs { address_to_nonce, rejected_tx_hashes }) + .await; + + if let Err(mempool_err) = mempool_result { error!("Failed to commit block to mempool: {}", mempool_err); - // TODO: Should we rollback the state diff and return an error? + // TODO(AlonH): Should we rollback the state diff and return an error? + }; + + let l1_provider_result = self + .l1_provider_client + .commit_block(accepted_l1_handler_tx_hashes.iter().copied().collect(), height) + .await; + l1_provider_result.unwrap_or_else(|err| match err { + L1ProviderClientError::L1ProviderError(L1ProviderError::UnexpectedHeight { + expected_height, + got, + }) => { + error!( + "Unexpected height while committing block in L1 provider: expected={:?}, \ + got={:?}", + expected_height, got + ); + } + other_err => { + panic!("Unexpected error while committing block in L1 provider: {:?}", other_err) + } + }); + + Ok(()) + } + + async fn is_active(&self, proposal_id: ProposalId) -> bool { + *self.active_proposal.lock().await == Some(proposal_id) + } + + // Sets a new active proposal task. + // Fails if there is another proposal being currently generated, or a proposal with the same ID + // already exists. + async fn set_active_proposal(&mut self, proposal_id: ProposalId) -> BatcherResult<()> { + if self.executed_proposals.lock().await.contains_key(&proposal_id) { + return Err(BatcherError::ProposalAlreadyExists { proposal_id }); + } + + let mut active_proposal = self.active_proposal.lock().await; + if let Some(active_proposal_id) = *active_proposal { + return Err(BatcherError::AnotherProposalInProgress { + active_proposal_id, + new_proposal_id: proposal_id, + }); + } + + debug!("Set proposal {} as the one being generated.", proposal_id); + *active_proposal = Some(proposal_id); + Ok(()) + } + + // Starts a new block proposal generation task for the given proposal_id. + // Uses the given block_builder to generate the proposal. + async fn spawn_proposal( + &mut self, + proposal_id: ProposalId, + mut block_builder: Box, + abort_signal_sender: tokio::sync::oneshot::Sender<()>, + mut proposal_metrics_handle: ProposalMetricsHandle, + ) -> BatcherResult<()> { + self.set_active_proposal(proposal_id).await?; + info!("Starting generation of a new proposal with id {}.", proposal_id); + + let active_proposal = self.active_proposal.clone(); + let executed_proposals = self.executed_proposals.clone(); + + let join_handle = tokio::spawn( + async move { + let result = match block_builder.build_block().await { + Ok(artifacts) => { + proposal_metrics_handle.set_succeeded(); + Ok(artifacts) + } + Err(BlockBuilderError::Aborted) => { + proposal_metrics_handle.set_aborted(); + Err(BlockBuilderError::Aborted) + } + Err(e) => Err(e), + } + .map_err(Arc::new); + + // The proposal is done, clear the active proposal. + // Keep the proposal result only if it is the same as the active proposal. + // The active proposal might have changed if this proposal was aborted. + let mut active_proposal = active_proposal.lock().await; + if *active_proposal == Some(proposal_id) { + active_proposal.take(); + executed_proposals.lock().await.insert(proposal_id, result); + } + } + .in_current_span(), + ); + + self.active_proposal_task = Some(ProposalTask { abort_signal_sender, join_handle }); + Ok(()) + } + + // Returns a completed proposal result, either its commitment or an error if the proposal + // failed. If the proposal doesn't exist, or it's still active, returns None. + async fn get_completed_proposal_result( + &self, + proposal_id: ProposalId, + ) -> Option> { + let guard = self.executed_proposals.lock().await; + let proposal_result = guard.get(&proposal_id); + match proposal_result { + Some(Ok(artifacts)) => Some(Ok(artifacts.commitment())), + Some(Err(e)) => Some(Err(e.clone())), + None => None, + } + } + + // Ends the current active proposal. + // This call is non-blocking. + async fn abort_active_proposal(&mut self) { + self.active_proposal.lock().await.take(); + if let Some(proposal_task) = self.active_proposal_task.take() { + proposal_task.abort_signal_sender.send(()).ok(); + } + } + + pub async fn await_active_proposal(&mut self) { + if let Some(proposal_task) = self.active_proposal_task.take() { + proposal_task.join_handle.await.ok(); + } + } + + #[instrument(skip(self), err)] + // This function will panic if there is a storage failure to revert the block. + pub async fn revert_block(&mut self, input: RevertBlockInput) -> BatcherResult<()> { + info!("Reverting block at height {}.", input.height); + let height = self.get_height_from_storage()?.prev().ok_or( + BatcherError::StorageHeightMarkerMismatch { + marker_height: BlockNumber(0), + requested_height: input.height, + }, + )?; + + if height != input.height { + return Err(BatcherError::StorageHeightMarkerMismatch { + marker_height: height.unchecked_next(), + requested_height: input.height, + }); + } + + if let Some(height) = self.active_height { + info!("Aborting all work on height {} due to a revert request.", height); + self.abort_active_height().await; } + + self.storage_writer.revert_block(height); + STORAGE_HEIGHT.decrement(1); + REVERTED_BLOCKS.increment(1); Ok(()) } } -pub fn create_batcher(config: BatcherConfig, mempool_client: SharedMempoolClient) -> Batcher { +pub fn create_batcher( + config: BatcherConfig, + mempool_client: SharedMempoolClient, + l1_provider_client: SharedL1ProviderClient, + class_manager_client: SharedClassManagerClient, +) -> Batcher { let (storage_reader, storage_writer) = papyrus_storage::open_storage(config.storage.clone()) .expect("Failed to open batcher's storage"); - let block_builder_factory = Arc::new(BlockBuilderFactory { + let block_builder_factory = Box::new(BlockBuilderFactory { block_builder_config: config.block_builder_config.clone(), storage_reader: storage_reader.clone(), - global_class_hash_to_class: GlobalContractCache::new(config.global_contract_cache_size), + contract_class_manager: ContractClassManager::start( + config.contract_class_manager_config.clone(), + ), + class_manager_client: class_manager_client.clone(), }); let storage_reader = Arc::new(storage_reader); let storage_writer = Box::new(storage_writer); - let proposal_manager = Box::new(ProposalManager::new(block_builder_factory)); - Batcher::new(config, storage_reader, storage_writer, mempool_client, proposal_manager) + let transaction_converter = + TransactionConverter::new(class_manager_client, config.storage.db_config.chain_id.clone()); + + Batcher::new( + config, + storage_reader, + storage_writer, + l1_provider_client, + mempool_client, + transaction_converter, + block_builder_factory, + ) } #[cfg_attr(test, automock)] @@ -359,6 +783,8 @@ pub trait BatcherStorageWriterTrait: Send + Sync { height: BlockNumber, state_diff: ThinStateDiff, ) -> papyrus_storage::StorageResult<()>; + + fn revert_block(&mut self, height: BlockNumber); } impl BatcherStorageWriterTrait for papyrus_storage::StorageWriter { @@ -367,59 +793,24 @@ impl BatcherStorageWriterTrait for papyrus_storage::StorageWriter { height: BlockNumber, state_diff: ThinStateDiff, ) -> papyrus_storage::StorageResult<()> { - // TODO: write casms. + // TODO(AlonH): write casms. self.begin_rw_txn()?.append_state_diff(height, state_diff)?.commit() } -} -impl From for BatcherError { - fn from(err: GenerateProposalError) -> Self { - match err { - GenerateProposalError::AlreadyGeneratingProposal { - current_generating_proposal_id, - new_proposal_id, - } => BatcherError::ServerBusy { - active_proposal_id: current_generating_proposal_id, - new_proposal_id, - }, - GenerateProposalError::BlockBuilderError(..) => BatcherError::InternalError, - GenerateProposalError::NoActiveHeight => BatcherError::NoActiveHeight, - GenerateProposalError::ProposalAlreadyExists { proposal_id } => { - BatcherError::ProposalAlreadyExists { proposal_id } - } - } + // This function will panic if there is a storage failure to revert the block. + fn revert_block(&mut self, height: BlockNumber) { + revert_block(self, height); } } -impl From for BatcherError { - fn from(err: GetProposalResultError) -> Self { - match err { - GetProposalResultError::BlockBuilderError(..) => BatcherError::InternalError, - GetProposalResultError::ProposalDoesNotExist { proposal_id } => { - BatcherError::ExecutedProposalNotFound { proposal_id } - } - GetProposalResultError::Aborted => BatcherError::ProposalAborted, - } - } -} - -impl ComponentStarter for Batcher {} - -pub fn deadline_as_instant(deadline: chrono::DateTime) -> BatcherResult { - let time_to_deadline = deadline - chrono::Utc::now(); - let as_duration = - time_to_deadline.to_std().map_err(|_| BatcherError::TimeToDeadlineError { deadline })?; - Ok((std::time::Instant::now() + as_duration).into()) -} - -fn verify_block_input( - height: BlockNumber, - retrospective_block_hash: Option, -) -> BatcherResult<()> { - if height >= BlockNumber(constants::STORED_BLOCK_HASH_BUFFER) - && retrospective_block_hash.is_none() - { - return Err(BatcherError::MissingRetrospectiveBlockHash); +#[async_trait] +impl ComponentStarter for Batcher { + async fn start(&mut self) { + default_component_start_fn::().await; + let storage_height = self + .storage_reader + .height() + .expect("Failed to get height from storage during batcher creation."); + register_metrics(storage_height); } - Ok(()) } diff --git a/crates/starknet_batcher/src/batcher_test.rs b/crates/starknet_batcher/src/batcher_test.rs index 3f6e2feb81d..c8765233112 100644 --- a/crates/starknet_batcher/src/batcher_test.rs +++ b/crates/starknet_batcher/src/batcher_test.rs @@ -2,23 +2,23 @@ use std::collections::{HashMap, HashSet}; use std::sync::Arc; use assert_matches::assert_matches; -use async_trait::async_trait; use blockifier::abi::constants; -use chrono::Utc; -use futures::future::BoxFuture; -use futures::FutureExt; -use mockall::automock; -use mockall::predicate::{always, eq}; -use rstest::{fixture, rstest}; -use starknet_api::block::{BlockHashAndNumber, BlockNumber}; -use starknet_api::core::{ContractAddress, Nonce, StateDiffCommitment}; -use starknet_api::executable_transaction::Transaction; -use starknet_api::hash::PoseidonHash; +use blockifier::transaction::objects::TransactionExecutionInfo; +use indexmap::indexmap; +use metrics_exporter_prometheus::PrometheusBuilder; +use mockall::predicate::eq; +use rstest::rstest; +use starknet_api::block::{BlockHeaderWithoutHash, BlockInfo, BlockNumber}; +use starknet_api::consensus_transaction::InternalConsensusTransaction; +use starknet_api::core::{ContractAddress, Nonce}; use starknet_api::state::ThinStateDiff; +use starknet_api::test_utils::CHAIN_ID_FOR_TESTS; use starknet_api::transaction::TransactionHash; -use starknet_api::{contract_address, felt, nonce}; +use starknet_api::{contract_address, nonce, tx_hash}; use starknet_batcher_types::batcher_types::{ DecisionReachedInput, + DecisionReachedResponse, + GetHeightResponse, GetProposalContent, GetProposalContentInput, GetProposalContentResponse, @@ -26,6 +26,7 @@ use starknet_batcher_types::batcher_types::{ ProposalId, ProposalStatus, ProposeBlockInput, + RevertBlockInput, SendProposalContent, SendProposalContentInput, SendProposalContentResponse, @@ -33,154 +34,344 @@ use starknet_batcher_types::batcher_types::{ ValidateBlockInput, }; use starknet_batcher_types::errors::BatcherError; -use starknet_mempool_types::communication::MockMempoolClient; +use starknet_class_manager_types::transaction_converter::TransactionConverter; +use starknet_class_manager_types::{EmptyClassManagerClient, SharedClassManagerClient}; +use starknet_l1_provider_types::errors::{L1ProviderClientError, L1ProviderError}; +use starknet_l1_provider_types::{MockL1ProviderClient, SessionState}; +use starknet_mempool_types::communication::{MempoolClientError, MockMempoolClient}; use starknet_mempool_types::mempool_types::CommitBlockArgs; +use starknet_sequencer_infra::component_client::ClientError; +use starknet_sequencer_infra::component_definitions::ComponentStarter; +use starknet_state_sync_types::state_sync_types::SyncBlock; +use validator::Validate; use crate::batcher::{Batcher, MockBatcherStorageReaderTrait, MockBatcherStorageWriterTrait}; -use crate::block_builder::{BlockBuilderError, FailOnErrorCause}; +use crate::block_builder::{ + AbortSignalSender, + BlockBuilderConfig, + BlockBuilderError, + BlockBuilderResult, + BlockExecutionArtifacts, + FailOnErrorCause, + MockBlockBuilderFactoryTrait, +}; use crate::config::BatcherConfig; -use crate::proposal_manager::{ - GenerateProposalError, - GetProposalResultError, - InternalProposalStatus, - ProposalManagerTrait, - ProposalOutput, - ProposalResult, +use crate::metrics::{ + BATCHED_TRANSACTIONS, + PROPOSAL_ABORTED, + PROPOSAL_FAILED, + PROPOSAL_STARTED, + PROPOSAL_SUCCEEDED, + REJECTED_TRANSACTIONS, + REVERTED_BLOCKS, + STORAGE_HEIGHT, + SYNCED_BLOCKS, + SYNCED_TRANSACTIONS, +}; +use crate::test_utils::{ + test_txs, + verify_indexed_execution_infos, + FakeProposeBlockBuilder, + FakeValidateBlockBuilder, }; -use crate::test_utils::test_txs; -use crate::transaction_provider::{ProposeTransactionProvider, ValidateTransactionProvider}; const INITIAL_HEIGHT: BlockNumber = BlockNumber(3); +const LATEST_BLOCK_IN_STORAGE: BlockNumber = BlockNumber(INITIAL_HEIGHT.0 - 1); const STREAMING_CHUNK_SIZE: usize = 3; const BLOCK_GENERATION_TIMEOUT: tokio::time::Duration = tokio::time::Duration::from_secs(1); const PROPOSAL_ID: ProposalId = ProposalId(0); +const BUILD_BLOCK_FAIL_ON_ERROR: BlockBuilderError = + BlockBuilderError::FailOnError(FailOnErrorCause::BlockFull); fn proposal_commitment() -> ProposalCommitment { - ProposalCommitment { - state_diff_commitment: StateDiffCommitment(PoseidonHash(felt!(u128::try_from(7).unwrap()))), + BlockExecutionArtifacts::create_for_testing().commitment() +} + +fn propose_block_input(proposal_id: ProposalId) -> ProposeBlockInput { + ProposeBlockInput { + proposal_id, + retrospective_block_hash: None, + deadline: chrono::Utc::now() + BLOCK_GENERATION_TIMEOUT, + block_info: BlockInfo { block_number: INITIAL_HEIGHT, ..BlockInfo::create_for_testing() }, } } -fn deadline() -> chrono::DateTime { - chrono::Utc::now() + BLOCK_GENERATION_TIMEOUT +fn validate_block_input(proposal_id: ProposalId) -> ValidateBlockInput { + ValidateBlockInput { + proposal_id, + retrospective_block_hash: None, + deadline: chrono::Utc::now() + BLOCK_GENERATION_TIMEOUT, + block_info: BlockInfo { block_number: INITIAL_HEIGHT, ..BlockInfo::create_for_testing() }, + } } -#[fixture] -fn storage_reader() -> MockBatcherStorageReaderTrait { - let mut storage = MockBatcherStorageReaderTrait::new(); - storage.expect_height().returning(|| Ok(INITIAL_HEIGHT)); - storage +struct MockDependencies { + storage_reader: MockBatcherStorageReaderTrait, + storage_writer: MockBatcherStorageWriterTrait, + mempool_client: MockMempoolClient, + l1_provider_client: MockL1ProviderClient, + block_builder_factory: MockBlockBuilderFactoryTrait, + class_manager_client: SharedClassManagerClient, } -#[fixture] -fn storage_writer() -> MockBatcherStorageWriterTrait { - MockBatcherStorageWriterTrait::new() +impl Default for MockDependencies { + fn default() -> Self { + let mut storage_reader = MockBatcherStorageReaderTrait::new(); + storage_reader.expect_height().returning(|| Ok(INITIAL_HEIGHT)); + let mut mempool_client = MockMempoolClient::new(); + let expected_gas_price = + propose_block_input(PROPOSAL_ID).block_info.gas_prices.strk_gas_prices.l2_gas_price; + mempool_client.expect_update_gas_price().with(eq(expected_gas_price)).returning(|_| Ok(())); + mempool_client + .expect_commit_block() + .with(eq(CommitBlockArgs::default())) + .returning(|_| Ok(())); + let mut block_builder_factory = MockBlockBuilderFactoryTrait::new(); + block_builder_factory.expect_take_class_cache_miss_counter().return_const(0_u64); + block_builder_factory.expect_take_class_cache_hit_counter().return_const(0_u64); + + Self { + storage_reader, + storage_writer: MockBatcherStorageWriterTrait::new(), + l1_provider_client: MockL1ProviderClient::new(), + mempool_client, + block_builder_factory, + // TODO(noamsp): use MockClassManagerClient + class_manager_client: Arc::new(EmptyClassManagerClient), + } + } } -#[fixture] -fn batcher_config() -> BatcherConfig { - BatcherConfig { outstream_content_buffer_size: STREAMING_CHUNK_SIZE, ..Default::default() } +async fn create_batcher(mock_dependencies: MockDependencies) -> Batcher { + let mut batcher = Batcher::new( + BatcherConfig { outstream_content_buffer_size: STREAMING_CHUNK_SIZE, ..Default::default() }, + Arc::new(mock_dependencies.storage_reader), + Box::new(mock_dependencies.storage_writer), + Arc::new(mock_dependencies.l1_provider_client), + Arc::new(mock_dependencies.mempool_client), + TransactionConverter::new( + mock_dependencies.class_manager_client, + CHAIN_ID_FOR_TESTS.clone(), + ), + Box::new(mock_dependencies.block_builder_factory), + ); + // Call post-creation functionality (e.g., metrics registration). + batcher.start().await; + batcher } -#[fixture] -fn mempool_client() -> MockMempoolClient { - MockMempoolClient::new() +fn abort_signal_sender() -> AbortSignalSender { + tokio::sync::oneshot::channel().0 } -fn batcher(proposal_manager: MockProposalManagerTraitWrapper) -> Batcher { - Batcher::new( - batcher_config(), - Arc::new(storage_reader()), - Box::new(storage_writer()), - Arc::new(mempool_client()), - Box::new(proposal_manager), - ) +async fn batcher_propose_and_commit_block( + mock_dependencies: MockDependencies, +) -> DecisionReachedResponse { + let mut batcher = create_batcher(mock_dependencies).await; + batcher.start_height(StartHeightInput { height: INITIAL_HEIGHT }).await.unwrap(); + batcher.propose_block(propose_block_input(PROPOSAL_ID)).await.unwrap(); + batcher.await_active_proposal().await; + batcher.decision_reached(DecisionReachedInput { proposal_id: PROPOSAL_ID }).await.unwrap() } -fn mock_proposal_manager_common_expectations( - proposal_manager: &mut MockProposalManagerTraitWrapper, +fn mock_create_builder_for_validate_block( + block_builder_factory: &mut MockBlockBuilderFactoryTrait, + build_block_result: BlockBuilderResult, ) { - proposal_manager.expect_wrap_reset().times(1).return_once(|| async {}.boxed()); - proposal_manager - .expect_wrap_await_proposal_commitment() - .times(1) - .with(eq(PROPOSAL_ID)) - .return_once(move |_| { async move { Ok(proposal_commitment()) } }.boxed()); + block_builder_factory.expect_create_block_builder().times(1).return_once( + |_, _, tx_provider, _, _| { + let block_builder = FakeValidateBlockBuilder { + tx_provider, + build_block_result: Some(build_block_result), + }; + Ok((Box::new(block_builder), abort_signal_sender())) + }, + ); } -fn mock_proposal_manager_validate_flow() -> MockProposalManagerTraitWrapper { - let mut proposal_manager = MockProposalManagerTraitWrapper::new(); - mock_proposal_manager_common_expectations(&mut proposal_manager); - proposal_manager - .expect_wrap_validate_block() - .times(1) - .with(eq(INITIAL_HEIGHT), eq(PROPOSAL_ID), eq(None), always(), always()) - .return_once(|_, _, _, _, tx_provider| { - { - async move { - // Spawn a task to keep tx_provider alive until the transactions sender is - // dropped. Without this, the provider would be dropped, - // causing the batcher to fail when sending transactions to - // it during the test. - tokio::spawn(async move { - while !tx_provider.tx_receiver.is_closed() { - tokio::task::yield_now().await; - } - }); - Ok(()) - } - } - .boxed() - }); - proposal_manager - .expect_wrap_get_proposal_status() - .times(1) - .with(eq(PROPOSAL_ID)) - .returning(move |_| async move { InternalProposalStatus::Processing }.boxed()); - proposal_manager +fn mock_create_builder_for_propose_block( + block_builder_factory: &mut MockBlockBuilderFactoryTrait, + output_txs: Vec, + build_block_result: BlockBuilderResult, +) { + block_builder_factory.expect_create_block_builder().times(1).return_once( + move |_, _, _, output_content_sender, _| { + let block_builder = FakeProposeBlockBuilder { + output_content_sender: output_content_sender.unwrap(), + output_txs, + build_block_result: Some(build_block_result), + }; + Ok((Box::new(block_builder), abort_signal_sender())) + }, + ); +} + +async fn create_batcher_with_active_validate_block( + build_block_result: BlockBuilderResult, +) -> Batcher { + let mut block_builder_factory = MockBlockBuilderFactoryTrait::new(); + mock_create_builder_for_validate_block(&mut block_builder_factory, build_block_result); + start_batcher_with_active_validate(block_builder_factory).await +} + +async fn start_batcher_with_active_validate( + block_builder_factory: MockBlockBuilderFactoryTrait, +) -> Batcher { + let mut l1_provider_client = MockL1ProviderClient::new(); + l1_provider_client.expect_start_block().returning(|_, _| Ok(())); + + let mut batcher = create_batcher(MockDependencies { + block_builder_factory, + l1_provider_client, + ..Default::default() + }) + .await; + + batcher.start_height(StartHeightInput { height: INITIAL_HEIGHT }).await.unwrap(); + + batcher.validate_block(validate_block_input(PROPOSAL_ID)).await.unwrap(); + + batcher +} + +fn test_tx_hashes() -> HashSet { + (0..5u8).map(|i| tx_hash!(i + 12)).collect() +} + +fn test_contract_nonces() -> HashMap { + HashMap::from_iter((0..3u8).map(|i| (contract_address!(i + 33), nonce!(i + 9)))) +} + +pub fn test_state_diff() -> ThinStateDiff { + ThinStateDiff { + storage_diffs: indexmap! { + 4u64.into() => indexmap! { + 5u64.into() => 6u64.into(), + 7u64.into() => 8u64.into(), + }, + 9u64.into() => indexmap! { + 10u64.into() => 11u64.into(), + }, + }, + nonces: test_contract_nonces().into_iter().collect(), + ..Default::default() + } +} + +fn verify_decision_reached_response( + response: &DecisionReachedResponse, + expected_artifacts: &BlockExecutionArtifacts, +) { + assert_eq!( + response.state_diff.nonces, + expected_artifacts.commitment_state_diff.address_to_nonce + ); + assert_eq!( + response.state_diff.storage_diffs, + expected_artifacts.commitment_state_diff.storage_updates + ); + assert_eq!( + response.state_diff.declared_classes, + expected_artifacts.commitment_state_diff.class_hash_to_compiled_class_hash + ); + assert_eq!( + response.state_diff.deployed_contracts, + expected_artifacts.commitment_state_diff.address_to_class_hash + ); + assert_eq!(response.l2_gas_used, expected_artifacts.l2_gas_used); + assert_eq!(response.central_objects.bouncer_weights, expected_artifacts.bouncer_weights); + assert_eq!( + response.central_objects.execution_infos, + expected_artifacts.execution_data.execution_infos.values().cloned().collect::>() + ); +} + +fn assert_proposal_metrics( + metrics: &str, + expected_started: u64, + expected_succeeded: u64, + expected_failed: u64, + expected_aborted: u64, +) { + let n_expected_active_proposals = + expected_started - (expected_succeeded + expected_failed + expected_aborted); + assert!(n_expected_active_proposals <= 1); + let started = PROPOSAL_STARTED.parse_numeric_metric::(metrics); + let succeeded = PROPOSAL_SUCCEEDED.parse_numeric_metric::(metrics); + let failed = PROPOSAL_FAILED.parse_numeric_metric::(metrics); + let aborted = PROPOSAL_ABORTED.parse_numeric_metric::(metrics); + + assert_eq!( + started, + Some(expected_started), + "unexpected value proposal_started, expected {} got {:?}", + expected_started, + started, + ); + assert_eq!( + succeeded, + Some(expected_succeeded), + "unexpected value proposal_succeeded, expected {} got {:?}", + expected_succeeded, + succeeded, + ); + assert_eq!( + failed, + Some(expected_failed), + "unexpected value proposal_failed, expected {} got {:?}", + expected_failed, + failed, + ); + assert_eq!( + aborted, + Some(expected_aborted), + "unexpected value proposal_aborted, expected {} got {:?}", + expected_aborted, + aborted, + ); +} + +#[tokio::test] +async fn metrics_registered() { + let recorder = PrometheusBuilder::new().build_recorder(); + let _recorder_guard = metrics::set_default_local_recorder(&recorder); + let _batcher = create_batcher(MockDependencies::default()).await; + let metrics = recorder.handle().render(); + assert_eq!(STORAGE_HEIGHT.parse_numeric_metric::(&metrics), Some(INITIAL_HEIGHT.0)); } #[rstest] #[tokio::test] async fn start_height_success() { - let mut proposal_manager = MockProposalManagerTraitWrapper::new(); - proposal_manager.expect_wrap_reset().times(1).return_once(|| async {}.boxed()); - - let mut batcher = batcher(proposal_manager); + let mut batcher = create_batcher(MockDependencies::default()).await; assert_eq!(batcher.start_height(StartHeightInput { height: INITIAL_HEIGHT }).await, Ok(())); } #[rstest] #[case::height_already_passed( INITIAL_HEIGHT.prev().unwrap(), - BatcherError::HeightAlreadyPassed { - storage_height: INITIAL_HEIGHT, + BatcherError::StorageHeightMarkerMismatch { + marker_height: INITIAL_HEIGHT, requested_height: INITIAL_HEIGHT.prev().unwrap() } )] #[case::storage_not_synced( INITIAL_HEIGHT.unchecked_next(), - BatcherError::StorageNotSynced { - storage_height: INITIAL_HEIGHT, + BatcherError::StorageHeightMarkerMismatch { + marker_height: INITIAL_HEIGHT, requested_height: INITIAL_HEIGHT.unchecked_next() } )] #[tokio::test] async fn start_height_fail(#[case] height: BlockNumber, #[case] expected_error: BatcherError) { - let mut proposal_manager = MockProposalManagerTraitWrapper::new(); - proposal_manager.expect_wrap_reset().never(); - - let mut batcher = batcher(proposal_manager); + let mut batcher = create_batcher(MockDependencies::default()).await; assert_eq!(batcher.start_height(StartHeightInput { height }).await, Err(expected_error)); } #[rstest] #[tokio::test] async fn duplicate_start_height() { - let mut proposal_manager = MockProposalManagerTraitWrapper::new(); - proposal_manager.expect_wrap_reset().times(1).return_once(|| async {}.boxed()); - - let mut batcher = batcher(proposal_manager); + let mut batcher = create_batcher(MockDependencies::default()).await; let initial_height = StartHeightInput { height: INITIAL_HEIGHT }; assert_eq!(batcher.start_height(initial_height.clone()).await, Ok(())); @@ -190,198 +381,238 @@ async fn duplicate_start_height() { #[rstest] #[tokio::test] async fn no_active_height() { - let proposal_manager = MockProposalManagerTraitWrapper::new(); - let mut batcher = batcher(proposal_manager); + let mut batcher = create_batcher(MockDependencies::default()).await; // Calling `propose_block` and `validate_block` without starting a height should fail. - let result = batcher - .propose_block(ProposeBlockInput { - proposal_id: ProposalId(0), - retrospective_block_hash: None, - deadline: chrono::Utc::now() + chrono::Duration::seconds(1), - }) - .await; + let result = batcher.propose_block(propose_block_input(PROPOSAL_ID)).await; assert_eq!(result, Err(BatcherError::NoActiveHeight)); - let result = batcher - .validate_block(ValidateBlockInput { - proposal_id: ProposalId(0), - retrospective_block_hash: None, - deadline: chrono::Utc::now() + chrono::Duration::seconds(1), - }) - .await; + let result = batcher.validate_block(validate_block_input(PROPOSAL_ID)).await; assert_eq!(result, Err(BatcherError::NoActiveHeight)); } #[rstest] +#[case::proposer(true)] +#[case::validator(false)] #[tokio::test] -async fn validate_block_full_flow() { - let proposal_manager = mock_proposal_manager_validate_flow(); - let mut batcher = batcher(proposal_manager); +async fn l1_handler_provider_not_ready(#[case] proposer: bool) { + let mut deps = MockDependencies::default(); + deps.l1_provider_client.expect_start_block().returning(|_, _| { + // The heights are not important for the test. + let err = L1ProviderError::UnexpectedHeight { + expected_height: INITIAL_HEIGHT, + got: INITIAL_HEIGHT, + }; + Err(err.into()) + }); + let mut batcher = create_batcher(deps).await; + assert_eq!(batcher.start_height(StartHeightInput { height: INITIAL_HEIGHT }).await, Ok(())); + + if proposer { + assert_eq!( + batcher.propose_block(propose_block_input(PROPOSAL_ID)).await, + Err(BatcherError::NotReady) + ); + } else { + assert_eq!( + batcher.validate_block(validate_block_input(PROPOSAL_ID)).await, + Err(BatcherError::NotReady) + ); + } +} - // TODO(Yael 14/11/2024): The test will pass without calling start height (if we delete the mock - // expectation). Leaving this here for future compatibility with the upcoming - // batcher-proposal_manager unification. +#[rstest] +#[tokio::test] +async fn consecutive_heights_success() { + let mut storage_reader = MockBatcherStorageReaderTrait::new(); + storage_reader.expect_height().times(1).returning(|| Ok(INITIAL_HEIGHT)); // metrics registration + storage_reader.expect_height().times(1).returning(|| Ok(INITIAL_HEIGHT)); // first start_height + storage_reader.expect_height().times(1).returning(|| Ok(INITIAL_HEIGHT.unchecked_next())); // second start_height + + let mut block_builder_factory = MockBlockBuilderFactoryTrait::new(); + for _ in 0..2 { + mock_create_builder_for_propose_block( + &mut block_builder_factory, + vec![], + Ok(BlockExecutionArtifacts::create_for_testing()), + ); + } + + let mut l1_provider_client = MockL1ProviderClient::new(); + l1_provider_client.expect_start_block().times(2).returning(|_, _| Ok(())); + let mut batcher = create_batcher(MockDependencies { + block_builder_factory, + storage_reader, + l1_provider_client, + ..Default::default() + }) + .await; + + // Prepare the propose_block requests for the first and the second heights. + let first_propose_block_input = propose_block_input(PROPOSAL_ID); + let mut second_propose_block_input = first_propose_block_input.clone(); + second_propose_block_input.block_info.block_number = INITIAL_HEIGHT.unchecked_next(); + + // Start the first height and propose block. batcher.start_height(StartHeightInput { height: INITIAL_HEIGHT }).await.unwrap(); + batcher.propose_block(first_propose_block_input).await.unwrap(); - let validate_block_input = ValidateBlockInput { - proposal_id: PROPOSAL_ID, - deadline: deadline(), - retrospective_block_hash: None, - }; - batcher.validate_block(validate_block_input).await.unwrap(); + // Start the second height, and make sure the previous height proposal is cleared, by trying to + // create a proposal with the same ID. + batcher + .start_height(StartHeightInput { height: INITIAL_HEIGHT.unchecked_next() }) + .await + .unwrap(); + batcher.propose_block(second_propose_block_input).await.unwrap(); +} + +#[rstest] +#[tokio::test] +async fn validate_block_full_flow() { + let recorder = PrometheusBuilder::new().build_recorder(); + let _recorder_guard = metrics::set_default_local_recorder(&recorder); + let mut batcher = create_batcher_with_active_validate_block(Ok( + BlockExecutionArtifacts::create_for_testing(), + )) + .await; + let metrics = recorder.handle().render(); + assert_proposal_metrics(&metrics, 1, 0, 0, 0); let send_proposal_input_txs = SendProposalContentInput { proposal_id: PROPOSAL_ID, content: SendProposalContent::Txs(test_txs(0..1)), }; - let send_txs_result = batcher.send_proposal_content(send_proposal_input_txs).await.unwrap(); assert_eq!( - send_txs_result, + batcher.send_proposal_content(send_proposal_input_txs).await.unwrap(), SendProposalContentResponse { response: ProposalStatus::Processing } ); - let send_proposal_input_finish = + let finish_proposal = SendProposalContentInput { proposal_id: PROPOSAL_ID, content: SendProposalContent::Finish }; - let send_finish_result = - batcher.send_proposal_content(send_proposal_input_finish).await.unwrap(); assert_eq!( - send_finish_result, + batcher.send_proposal_content(finish_proposal).await.unwrap(), SendProposalContentResponse { response: ProposalStatus::Finished(proposal_commitment()) } ); + let metrics = recorder.handle().render(); + assert_proposal_metrics(&metrics, 1, 1, 0, 0); } #[rstest] +#[case::send_txs(SendProposalContent::Txs(test_txs(0..1)))] +#[case::send_finish(SendProposalContent::Finish)] +#[case::send_abort(SendProposalContent::Abort)] #[tokio::test] -async fn send_content_after_proposal_already_finished() { - let mut proposal_manager = MockProposalManagerTraitWrapper::new(); - proposal_manager - .expect_wrap_get_proposal_status() - .with(eq(PROPOSAL_ID)) - .times(1) - .returning(|_| async move { InternalProposalStatus::Finished }.boxed()); - - let mut batcher = batcher(proposal_manager); +async fn send_content_to_unknown_proposal(#[case] content: SendProposalContent) { + let mut batcher = create_batcher(MockDependencies::default()).await; - // Send transactions after the proposal has finished. - let send_proposal_input_txs = SendProposalContentInput { - proposal_id: PROPOSAL_ID, - content: SendProposalContent::Txs(test_txs(0..1)), - }; - let result = batcher.send_proposal_content(send_proposal_input_txs).await; - assert_eq!(result, Err(BatcherError::ProposalAlreadyFinished { proposal_id: PROPOSAL_ID })); + let send_proposal_content_input = + SendProposalContentInput { proposal_id: PROPOSAL_ID, content }; + let result = batcher.send_proposal_content(send_proposal_content_input).await; + assert_eq!(result, Err(BatcherError::ProposalNotFound { proposal_id: PROPOSAL_ID })); } #[rstest] +#[case::send_txs(SendProposalContent::Txs(test_txs(0..1)), ProposalStatus::InvalidProposal)] +#[case::send_finish(SendProposalContent::Finish, ProposalStatus::InvalidProposal)] +#[case::send_abort(SendProposalContent::Abort, ProposalStatus::Aborted)] #[tokio::test] -async fn send_content_to_unknown_proposal() { - let mut proposal_manager = MockProposalManagerTraitWrapper::new(); - proposal_manager - .expect_wrap_get_proposal_status() - .times(1) - .with(eq(PROPOSAL_ID)) - .return_once(move |_| async move { InternalProposalStatus::NotFound }.boxed()); - - let mut batcher = batcher(proposal_manager); - - // Send transactions to an unknown proposal. - let send_proposal_input_txs = SendProposalContentInput { - proposal_id: PROPOSAL_ID, - content: SendProposalContent::Txs(test_txs(0..1)), - }; - let result = batcher.send_proposal_content(send_proposal_input_txs).await; - assert_eq!(result, Err(BatcherError::ProposalNotFound { proposal_id: PROPOSAL_ID })); - - // Send finish to an unknown proposal. - let send_proposal_input_txs = - SendProposalContentInput { proposal_id: PROPOSAL_ID, content: SendProposalContent::Finish }; - let result = batcher.send_proposal_content(send_proposal_input_txs).await; - assert_eq!(result, Err(BatcherError::ProposalNotFound { proposal_id: PROPOSAL_ID })); +async fn send_content_to_an_invalid_proposal( + #[case] content: SendProposalContent, + #[case] response: ProposalStatus, +) { + let mut batcher = + create_batcher_with_active_validate_block(Err(BUILD_BLOCK_FAIL_ON_ERROR)).await; + batcher.await_active_proposal().await; + + let send_proposal_content_input = + SendProposalContentInput { proposal_id: PROPOSAL_ID, content }; + let result = batcher.send_proposal_content(send_proposal_content_input).await.unwrap(); + assert_eq!(result, SendProposalContentResponse { response }); } #[rstest] +#[case::send_txs_after_finish(SendProposalContent::Finish, SendProposalContent::Txs(test_txs(0..1)))] +#[case::send_finish_after_finish(SendProposalContent::Finish, SendProposalContent::Finish)] +#[case::send_abort_after_finish(SendProposalContent::Finish, SendProposalContent::Abort)] +#[case::send_txs_after_abort(SendProposalContent::Abort, SendProposalContent::Txs(test_txs(0..1)))] +#[case::send_finish_after_abort(SendProposalContent::Abort, SendProposalContent::Finish)] +#[case::send_abort_after_abort(SendProposalContent::Abort, SendProposalContent::Abort)] #[tokio::test] -async fn send_txs_to_an_invalid_proposal() { - let mut proposal_manager = MockProposalManagerTraitWrapper::new(); - proposal_manager - .expect_wrap_get_proposal_status() - .times(1) - .with(eq(PROPOSAL_ID)) - .return_once(move |_| async move { InternalProposalStatus::Failed }.boxed()); - - let mut batcher = batcher(proposal_manager); - - let send_proposal_input_txs = SendProposalContentInput { - proposal_id: PROPOSAL_ID, - content: SendProposalContent::Txs(test_txs(0..1)), - }; - let result = batcher.send_proposal_content(send_proposal_input_txs).await.unwrap(); - assert_eq!(result, SendProposalContentResponse { response: ProposalStatus::InvalidProposal }); +async fn send_proposal_content_after_finish_or_abort( + #[case] end_proposal_content: SendProposalContent, + #[case] content: SendProposalContent, +) { + let mut batcher = create_batcher_with_active_validate_block(Ok( + BlockExecutionArtifacts::create_for_testing(), + )) + .await; + + // End the proposal. + let end_proposal = + SendProposalContentInput { proposal_id: PROPOSAL_ID, content: end_proposal_content }; + batcher.send_proposal_content(end_proposal).await.unwrap(); + + // Send another request. + let send_proposal_content_input = + SendProposalContentInput { proposal_id: PROPOSAL_ID, content }; + let result = batcher.send_proposal_content(send_proposal_content_input).await; + assert_eq!(result, Err(BatcherError::ProposalNotFound { proposal_id: PROPOSAL_ID })); } #[rstest] #[tokio::test] -async fn send_finish_to_an_invalid_proposal() { - let mut proposal_manager = MockProposalManagerTraitWrapper::new(); - proposal_manager.expect_wrap_reset().times(1).return_once(|| async {}.boxed()); - proposal_manager - .expect_wrap_validate_block() - .times(1) - .with(eq(INITIAL_HEIGHT), eq(PROPOSAL_ID), eq(None), always(), always()) - .return_once(|_, _, _, _, _| { async move { Ok(()) } }.boxed()); - - let proposal_error = GetProposalResultError::BlockBuilderError(Arc::new( - BlockBuilderError::FailOnError(FailOnErrorCause::BlockFull), - )); - proposal_manager - .expect_wrap_await_proposal_commitment() - .times(1) - .with(eq(PROPOSAL_ID)) - .return_once(move |_| { async move { Err(proposal_error) } }.boxed()); - - let mut batcher = batcher(proposal_manager); - batcher.start_height(StartHeightInput { height: INITIAL_HEIGHT }).await.unwrap(); - - let validate_block_input = ValidateBlockInput { - proposal_id: PROPOSAL_ID, - deadline: deadline(), - retrospective_block_hash: None, - }; - batcher.validate_block(validate_block_input).await.unwrap(); +async fn send_proposal_content_abort() { + let recorder = PrometheusBuilder::new().build_recorder(); + let _recorder_guard = metrics::set_default_local_recorder(&recorder); + let mut batcher = + create_batcher_with_active_validate_block(Err(BlockBuilderError::Aborted)).await; + let metrics = recorder.handle().render(); + assert_proposal_metrics(&metrics, 1, 0, 0, 0); + + let send_abort_proposal = + SendProposalContentInput { proposal_id: PROPOSAL_ID, content: SendProposalContent::Abort }; + assert_eq!( + batcher.send_proposal_content(send_abort_proposal).await.unwrap(), + SendProposalContentResponse { response: ProposalStatus::Aborted } + ); - let send_proposal_input_txs = - SendProposalContentInput { proposal_id: PROPOSAL_ID, content: SendProposalContent::Finish }; - let result = batcher.send_proposal_content(send_proposal_input_txs).await.unwrap(); - assert_eq!(result, SendProposalContentResponse { response: ProposalStatus::InvalidProposal }); + // The block builder is running in a separate task, and the proposal metrics are emitted from + // that task, so we need to wait for them (we don't have a way to wait for the completion of the + // abort). + // TODO(AlonH): Find a way to wait for the metrics to be emitted. + tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; + let metrics = recorder.handle().render(); + assert_proposal_metrics(&metrics, 1, 0, 0, 1); } #[rstest] #[tokio::test] async fn propose_block_full_flow() { + let recorder = PrometheusBuilder::new().build_recorder(); + let _recorder_guard = metrics::set_default_local_recorder(&recorder); // Expecting 3 chunks of streamed txs. let expected_streamed_txs = test_txs(0..STREAMING_CHUNK_SIZE * 2 + 1); - let txs_to_stream = expected_streamed_txs.clone(); - let mut proposal_manager = MockProposalManagerTraitWrapper::new(); - mock_proposal_manager_common_expectations(&mut proposal_manager); - proposal_manager.expect_wrap_propose_block().times(1).return_once( - move |_height, _proposal_id, _block_hash, _deadline, tx_sender, _tx_provider| { - simulate_build_block_proposal(tx_sender, txs_to_stream).boxed() - }, + let mut block_builder_factory = MockBlockBuilderFactoryTrait::new(); + mock_create_builder_for_propose_block( + &mut block_builder_factory, + expected_streamed_txs.clone(), + Ok(BlockExecutionArtifacts::create_for_testing()), ); - let mut batcher = batcher(proposal_manager); + let mut l1_provider_client = MockL1ProviderClient::new(); + l1_provider_client.expect_start_block().times(1).returning(|_, _| Ok(())); + + let mut batcher = create_batcher(MockDependencies { + block_builder_factory, + l1_provider_client, + ..Default::default() + }) + .await; batcher.start_height(StartHeightInput { height: INITIAL_HEIGHT }).await.unwrap(); - batcher - .propose_block(ProposeBlockInput { - proposal_id: PROPOSAL_ID, - retrospective_block_hash: None, - deadline: chrono::Utc::now() + chrono::Duration::seconds(1), - }) - .await - .unwrap(); + batcher.propose_block(propose_block_input(PROPOSAL_ID)).await.unwrap(); let expected_n_chunks = expected_streamed_txs.len().div_ceil(STREAMING_CHUNK_SIZE); let mut aggregated_streamed_txs = Vec::new(); @@ -409,37 +640,39 @@ async fn propose_block_full_flow() { let exhausted = batcher.get_proposal_content(GetProposalContentInput { proposal_id: PROPOSAL_ID }).await; assert_matches!(exhausted, Err(BatcherError::ProposalNotFound { .. })); + + let metrics = recorder.handle().render(); + assert_proposal_metrics(&metrics, 1, 1, 0, 0); } +#[rstest] #[tokio::test] -async fn propose_block_without_retrospective_block_hash() { - let mut proposal_manager = MockProposalManagerTraitWrapper::new(); - proposal_manager.expect_wrap_reset().times(1).return_once(|| async {}.boxed()); +async fn get_height() { + let mut storage_reader = MockBatcherStorageReaderTrait::new(); + storage_reader.expect_height().returning(|| Ok(INITIAL_HEIGHT)); + + let batcher = create_batcher(MockDependencies { storage_reader, ..Default::default() }).await; + let result = batcher.get_height().await.unwrap(); + assert_eq!(result, GetHeightResponse { height: INITIAL_HEIGHT }); +} + +#[rstest] +#[tokio::test] +async fn propose_block_without_retrospective_block_hash() { let mut storage_reader = MockBatcherStorageReaderTrait::new(); storage_reader .expect_height() .returning(|| Ok(BlockNumber(constants::STORED_BLOCK_HASH_BUFFER))); - let mut batcher = Batcher::new( - batcher_config(), - Arc::new(storage_reader), - Box::new(storage_writer()), - Arc::new(mempool_client()), - Box::new(proposal_manager), - ); + let mut batcher = + create_batcher(MockDependencies { storage_reader, ..Default::default() }).await; batcher .start_height(StartHeightInput { height: BlockNumber(constants::STORED_BLOCK_HASH_BUFFER) }) .await .unwrap(); - let result = batcher - .propose_block(ProposeBlockInput { - proposal_id: PROPOSAL_ID, - retrospective_block_hash: None, - deadline: deadline(), - }) - .await; + let result = batcher.propose_block(propose_block_input(PROPOSAL_ID)).await; assert_matches!(result, Err(BatcherError::MissingRetrospectiveBlockHash)); } @@ -447,10 +680,7 @@ async fn propose_block_without_retrospective_block_hash() { #[rstest] #[tokio::test] async fn get_content_from_unknown_proposal() { - let mut proposal_manager = MockProposalManagerTraitWrapper::new(); - proposal_manager.expect_wrap_await_proposal_commitment().times(0); - - let mut batcher = batcher(proposal_manager); + let mut batcher = create_batcher(MockDependencies::default()).await; let get_proposal_content_input = GetProposalContentInput { proposal_id: PROPOSAL_ID }; let result = batcher.get_proposal_content(get_proposal_content_input).await; @@ -459,52 +689,331 @@ async fn get_content_from_unknown_proposal() { #[rstest] #[tokio::test] -async fn decision_reached( - batcher_config: BatcherConfig, - storage_reader: MockBatcherStorageReaderTrait, - mut storage_writer: MockBatcherStorageWriterTrait, - mut mempool_client: MockMempoolClient, -) { - let expected_state_diff = ThinStateDiff::default(); - let state_diff_clone = expected_state_diff.clone(); - let expected_proposal_commitment = ProposalCommitment::default(); - let tx_hashes = test_tx_hashes(0..5); - let tx_hashes_clone = tx_hashes.clone(); - let address_to_nonce = test_contract_nonces(0..3); - let nonces_clone = address_to_nonce.clone(); - - let mut proposal_manager = MockProposalManagerTraitWrapper::new(); - proposal_manager.expect_wrap_take_proposal_result().times(1).with(eq(PROPOSAL_ID)).return_once( - move |_| { - async move { - Ok(ProposalOutput { - state_diff: state_diff_clone, - commitment: expected_proposal_commitment, - tx_hashes: tx_hashes_clone, - nonces: nonces_clone, - }) - } - .boxed() +async fn consecutive_proposal_generation_success() { + let recorder = PrometheusBuilder::new().build_recorder(); + let _recorder_guard = metrics::set_default_local_recorder(&recorder); + let mut block_builder_factory = MockBlockBuilderFactoryTrait::new(); + for _ in 0..2 { + mock_create_builder_for_propose_block( + &mut block_builder_factory, + vec![], + Ok(BlockExecutionArtifacts::create_for_testing()), + ); + mock_create_builder_for_validate_block( + &mut block_builder_factory, + Ok(BlockExecutionArtifacts::create_for_testing()), + ); + } + let mut l1_provider_client = MockL1ProviderClient::new(); + l1_provider_client.expect_start_block().times(4).returning(|_, _| Ok(())); + let mut batcher = create_batcher(MockDependencies { + block_builder_factory, + l1_provider_client, + ..Default::default() + }) + .await; + + batcher.start_height(StartHeightInput { height: INITIAL_HEIGHT }).await.unwrap(); + + // Make sure we can generate 4 consecutive proposals. + for i in 0..2 { + batcher.propose_block(propose_block_input(ProposalId(2 * i))).await.unwrap(); + batcher.await_active_proposal().await; + + batcher.validate_block(validate_block_input(ProposalId(2 * i + 1))).await.unwrap(); + let finish_proposal = SendProposalContentInput { + proposal_id: ProposalId(2 * i + 1), + content: SendProposalContent::Finish, + }; + batcher.send_proposal_content(finish_proposal).await.unwrap(); + batcher.await_active_proposal().await; + } + + let metrics = recorder.handle().render(); + assert_proposal_metrics(&metrics, 4, 4, 0, 0); +} + +#[rstest] +#[tokio::test] +async fn concurrent_proposals_generation_fail() { + let recorder = PrometheusBuilder::new().build_recorder(); + let _recorder_guard = metrics::set_default_local_recorder(&recorder); + let mut block_builder_factory = MockBlockBuilderFactoryTrait::new(); + // Expecting the block builder factory to be called twice. + for _ in 0..2 { + mock_create_builder_for_validate_block( + &mut block_builder_factory, + Ok(BlockExecutionArtifacts::create_for_testing()), + ); + } + let mut batcher = start_batcher_with_active_validate(block_builder_factory).await; + + // Make sure another proposal can't be generated while the first one is still active. + let result = batcher.propose_block(propose_block_input(ProposalId(1))).await; + + assert_matches!(result, Err(BatcherError::AnotherProposalInProgress { .. })); + + // Finish the first proposal. + batcher + .send_proposal_content(SendProposalContentInput { + proposal_id: ProposalId(0), + content: SendProposalContent::Finish, + }) + .await + .unwrap(); + batcher.await_active_proposal().await; + + let metrics = recorder.handle().render(); + assert_proposal_metrics(&metrics, 2, 1, 1, 0); +} + +#[rstest] +#[tokio::test] +async fn proposal_startup_failure_allows_new_proposals() { + let recorder = PrometheusBuilder::new().build_recorder(); + let _recorder_guard = metrics::set_default_local_recorder(&recorder); + let mut block_builder_factory = MockBlockBuilderFactoryTrait::new(); + mock_create_builder_for_validate_block( + &mut block_builder_factory, + Ok(BlockExecutionArtifacts::create_for_testing()), + ); + let mut l1_provider_client = MockL1ProviderClient::new(); + let error = L1ProviderClientError::L1ProviderError(L1ProviderError::UnexpectedHeight { + expected_height: BlockNumber(1), + got: BlockNumber(0), + }); + l1_provider_client.expect_start_block().once().return_once(|_, _| Err(error)); + l1_provider_client.expect_start_block().once().return_once(|_, _| Ok(())); + let mut batcher = create_batcher(MockDependencies { + block_builder_factory, + l1_provider_client, + ..Default::default() + }) + .await; + + batcher.start_height(StartHeightInput { height: INITIAL_HEIGHT }).await.unwrap(); + + batcher + .propose_block(propose_block_input(ProposalId(0))) + .await + .expect_err("Expected to fail because of the first L1ProviderClient error"); + + batcher.validate_block(validate_block_input(ProposalId(1))).await.expect("Expected to succeed"); + batcher + .send_proposal_content(SendProposalContentInput { + proposal_id: ProposalId(1), + content: SendProposalContent::Finish, + }) + .await + .unwrap(); + batcher.await_active_proposal().await; + + let metrics = recorder.handle().render(); + assert_proposal_metrics(&metrics, 2, 1, 1, 0); +} + +#[rstest] +#[tokio::test] +async fn add_sync_block() { + let recorder = PrometheusBuilder::new().build_recorder(); + let _recorder_guard = metrics::set_default_local_recorder(&recorder); + let mut mock_dependencies = MockDependencies::default(); + + mock_dependencies + .storage_writer + .expect_commit_proposal() + .times(1) + .with(eq(INITIAL_HEIGHT), eq(test_state_diff())) + .returning(|_, _| Ok(())); + + mock_dependencies + .mempool_client + .expect_commit_block() + .times(1) + .with(eq(CommitBlockArgs { + address_to_nonce: test_contract_nonces(), + rejected_tx_hashes: [].into(), + })) + .returning(|_| Ok(())); + + mock_dependencies + .l1_provider_client + .expect_commit_block() + .times(1) + .with(eq(vec![]), eq(INITIAL_HEIGHT)) + .returning(|_, _| Ok(())); + + let mut batcher = create_batcher(mock_dependencies).await; + + let transaction_hashes: Vec<_> = test_tx_hashes().into_iter().collect(); + let n_synced_transactions = transaction_hashes.len(); + + let sync_block = SyncBlock { + block_header_without_hash: BlockHeaderWithoutHash { + block_number: INITIAL_HEIGHT, + ..Default::default() }, + state_diff: test_state_diff(), + transaction_hashes, + }; + batcher.add_sync_block(sync_block).await.unwrap(); + let metrics = recorder.handle().render(); + assert_eq!( + STORAGE_HEIGHT.parse_numeric_metric::(&metrics), + Some(INITIAL_HEIGHT.unchecked_next().0) + ); + let metrics = recorder.handle().render(); + assert_eq!(SYNCED_BLOCKS.parse_numeric_metric::(&metrics), Some(1)); + assert_eq!( + SYNCED_TRANSACTIONS.parse_numeric_metric::(&metrics), + Some(n_synced_transactions) ); - mempool_client +} + +#[rstest] +#[tokio::test] +async fn add_sync_block_mismatch_block_number() { + let mut batcher = create_batcher(MockDependencies::default()).await; + + let sync_block = SyncBlock { + block_header_without_hash: BlockHeaderWithoutHash { + block_number: INITIAL_HEIGHT.unchecked_next(), + ..Default::default() + }, + ..Default::default() + }; + let result = batcher.add_sync_block(sync_block).await; + assert_eq!( + result, + Err(BatcherError::StorageHeightMarkerMismatch { + marker_height: BlockNumber(3), + requested_height: BlockNumber(4) + }) + ) +} + +#[tokio::test] +async fn revert_block() { + let recorder = PrometheusBuilder::new().build_recorder(); + let _recorder_guard = metrics::set_default_local_recorder(&recorder); + let mut mock_dependencies = MockDependencies::default(); + + mock_dependencies + .storage_writer + .expect_revert_block() + .times(1) + .with(eq(LATEST_BLOCK_IN_STORAGE)) + .returning(|_| ()); + + let mut batcher = create_batcher(mock_dependencies).await; + + let metrics = recorder.handle().render(); + assert_eq!(STORAGE_HEIGHT.parse_numeric_metric::(&metrics), Some(INITIAL_HEIGHT.0)); + + let revert_input = RevertBlockInput { height: LATEST_BLOCK_IN_STORAGE }; + batcher.revert_block(revert_input).await.unwrap(); + + let metrics = recorder.handle().render(); + assert_eq!(STORAGE_HEIGHT.parse_numeric_metric::(&metrics), Some(INITIAL_HEIGHT.0 - 1)); + assert_eq!(REVERTED_BLOCKS.parse_numeric_metric::(&metrics), Some(1)); +} + +#[tokio::test] +async fn revert_block_mismatch_block_number() { + let mut batcher = create_batcher(MockDependencies::default()).await; + + let revert_input = RevertBlockInput { height: INITIAL_HEIGHT }; + let result = batcher.revert_block(revert_input).await; + assert_eq!( + result, + Err(BatcherError::StorageHeightMarkerMismatch { + marker_height: BlockNumber(3), + requested_height: BlockNumber(3) + }) + ) +} + +#[tokio::test] +async fn revert_block_empty_storage() { + let mut storage_reader = MockBatcherStorageReaderTrait::new(); + storage_reader.expect_height().returning(|| Ok(BlockNumber(0))); + + let mock_dependencies = MockDependencies { storage_reader, ..Default::default() }; + let mut batcher = create_batcher(mock_dependencies).await; + + let revert_input = RevertBlockInput { height: BlockNumber(0) }; + let result = batcher.revert_block(revert_input).await; + assert_eq!( + result, + Err(BatcherError::StorageHeightMarkerMismatch { + marker_height: BlockNumber(0), + requested_height: BlockNumber(0) + }) + ); +} + +#[rstest] +#[tokio::test] +async fn decision_reached() { + let recorder = PrometheusBuilder::new().build_recorder(); + let _recorder_guard = metrics::set_default_local_recorder(&recorder); + let mut mock_dependencies = MockDependencies::default(); + let expected_artifacts = BlockExecutionArtifacts::create_for_testing(); + + mock_dependencies + .mempool_client .expect_commit_block() - .with(eq(CommitBlockArgs { address_to_nonce, tx_hashes })) + .times(1) + .with(eq(CommitBlockArgs { + address_to_nonce: expected_artifacts.address_to_nonce(), + rejected_tx_hashes: expected_artifacts.execution_data.rejected_tx_hashes.clone(), + })) .returning(|_| Ok(())); - storage_writer + mock_dependencies + .l1_provider_client + .expect_start_block() + .times(1) + .with(eq(SessionState::Propose), eq(INITIAL_HEIGHT)) + .returning(|_, _| Ok(())); + + mock_dependencies + .l1_provider_client + .expect_commit_block() + .times(1) + .with(eq(vec![]), eq(INITIAL_HEIGHT)) + .returning(|_, _| Ok(())); + + mock_dependencies + .storage_writer .expect_commit_proposal() - .with(eq(INITIAL_HEIGHT), eq(expected_state_diff)) + .times(1) + .with(eq(INITIAL_HEIGHT), eq(expected_artifacts.thin_state_diff())) .returning(|_, _| Ok(())); - let mut batcher = Batcher::new( - batcher_config, - Arc::new(storage_reader), - Box::new(storage_writer), - Arc::new(mempool_client), - Box::new(proposal_manager), + mock_create_builder_for_propose_block( + &mut mock_dependencies.block_builder_factory, + vec![], + Ok(BlockExecutionArtifacts::create_for_testing()), + ); + + let decision_reached_response = batcher_propose_and_commit_block(mock_dependencies).await; + + verify_decision_reached_response(&decision_reached_response, &expected_artifacts); + + let metrics = recorder.handle().render(); + assert_eq!( + STORAGE_HEIGHT.parse_numeric_metric::(&metrics), + Some(INITIAL_HEIGHT.unchecked_next().0) + ); + assert_eq!( + BATCHED_TRANSACTIONS.parse_numeric_metric::(&metrics), + Some(expected_artifacts.execution_data.execution_infos.len()) + ); + assert_eq!( + REJECTED_TRANSACTIONS.parse_numeric_metric::(&metrics), + Some(expected_artifacts.execution_data.rejected_tx_hashes.len()) ); - batcher.decision_reached(DecisionReachedInput { proposal_id: PROPOSAL_ID }).await.unwrap(); } #[rstest] @@ -512,144 +1021,76 @@ async fn decision_reached( async fn decision_reached_no_executed_proposal() { let expected_error = BatcherError::ExecutedProposalNotFound { proposal_id: PROPOSAL_ID }; - let mut proposal_manager = MockProposalManagerTraitWrapper::new(); - proposal_manager.expect_wrap_take_proposal_result().times(1).with(eq(PROPOSAL_ID)).return_once( - |proposal_id| { - async move { Err(GetProposalResultError::ProposalDoesNotExist { proposal_id }) }.boxed() - }, - ); + let mut batcher = create_batcher(MockDependencies::default()).await; + batcher.start_height(StartHeightInput { height: INITIAL_HEIGHT }).await.unwrap(); - let mut batcher = batcher(proposal_manager); let decision_reached_result = batcher.decision_reached(DecisionReachedInput { proposal_id: PROPOSAL_ID }).await; assert_eq!(decision_reached_result, Err(expected_error)); } -async fn simulate_build_block_proposal( - tx_sender: tokio::sync::mpsc::UnboundedSender, - txs: Vec, -) -> Result<(), GenerateProposalError> { - tokio::spawn(async move { - for tx in txs { - tx_sender.send(tx).unwrap(); - } - }); - Ok(()) -} - -// A wrapper trait to allow mocking the ProposalManagerTrait in tests. -#[automock] -trait ProposalManagerTraitWrapper: Send + Sync { - fn wrap_propose_block( - &mut self, - height: BlockNumber, - proposal_id: ProposalId, - retrospective_block_hash: Option, - deadline: tokio::time::Instant, - output_content_sender: tokio::sync::mpsc::UnboundedSender, - tx_provider: ProposeTransactionProvider, - ) -> BoxFuture<'_, Result<(), GenerateProposalError>>; - - fn wrap_validate_block( - &mut self, - height: BlockNumber, - proposal_id: ProposalId, - retrospective_block_hash: Option, - deadline: tokio::time::Instant, - tx_provider: ValidateTransactionProvider, - ) -> BoxFuture<'_, Result<(), GenerateProposalError>>; - - fn wrap_take_proposal_result( - &mut self, - proposal_id: ProposalId, - ) -> BoxFuture<'_, ProposalResult>; - - fn wrap_get_proposal_status( - &self, - proposal_id: ProposalId, - ) -> BoxFuture<'_, InternalProposalStatus>; - - fn wrap_await_proposal_commitment( - &self, - proposal_id: ProposalId, - ) -> BoxFuture<'_, ProposalResult>; - - fn wrap_abort_proposal(&mut self, proposal_id: ProposalId) -> BoxFuture<'_, ()>; - - fn wrap_reset(&mut self) -> BoxFuture<'_, ()>; -} - -#[async_trait] -impl ProposalManagerTrait for T { - async fn propose_block( - &mut self, - height: BlockNumber, - proposal_id: ProposalId, - retrospective_block_hash: Option, - deadline: tokio::time::Instant, - output_content_sender: tokio::sync::mpsc::UnboundedSender, - tx_provider: ProposeTransactionProvider, - ) -> Result<(), GenerateProposalError> { - self.wrap_propose_block( - height, - proposal_id, - retrospective_block_hash, - deadline, - output_content_sender, - tx_provider, - ) - .await - } - - async fn validate_block( - &mut self, - height: BlockNumber, - proposal_id: ProposalId, - retrospective_block_hash: Option, - deadline: tokio::time::Instant, - tx_provider: ValidateTransactionProvider, - ) -> Result<(), GenerateProposalError> { - self.wrap_validate_block( - height, - proposal_id, - retrospective_block_hash, - deadline, - tx_provider, - ) - .await - } +// Test that the batcher returns the execution_infos in the same order as returned from the +// block_builder. It is crucial that the execution_infos will be ordered in the same order as +// the transactions in the block for the correct execution of starknet. +// This test together with [block_builder_test::test_execution_info_order] covers this requirement. +#[tokio::test] +async fn test_execution_info_order_is_kept() { + let mut mock_dependencies = MockDependencies::default(); + mock_dependencies.l1_provider_client.expect_start_block().returning(|_, _| Ok(())); + mock_dependencies.mempool_client.expect_commit_block().returning(|_| Ok(())); + mock_dependencies.l1_provider_client.expect_commit_block().returning(|_, _| Ok(())); + mock_dependencies.storage_writer.expect_commit_proposal().returning(|_, _| Ok(())); + + let block_builder_result = BlockExecutionArtifacts::create_for_testing(); + // Check that the execution_infos were initiated properly for this test. + verify_indexed_execution_infos(&block_builder_result.execution_data.execution_infos); + + mock_create_builder_for_propose_block( + &mut mock_dependencies.block_builder_factory, + vec![], + Ok(block_builder_result.clone()), + ); - async fn take_proposal_result( - &mut self, - proposal_id: ProposalId, - ) -> ProposalResult { - self.wrap_take_proposal_result(proposal_id).await - } + let decision_reached_response = batcher_propose_and_commit_block(mock_dependencies).await; - async fn get_proposal_status(&self, proposal_id: ProposalId) -> InternalProposalStatus { - self.wrap_get_proposal_status(proposal_id).await - } - - async fn await_proposal_commitment( - &mut self, - proposal_id: ProposalId, - ) -> ProposalResult { - self.wrap_await_proposal_commitment(proposal_id).await - } + // Verify that the execution_infos are in the same order as returned from the block_builder. + let expected_execution_infos: Vec = + block_builder_result.execution_data.execution_infos.into_values().collect(); + assert_eq!(decision_reached_response.central_objects.execution_infos, expected_execution_infos); +} - async fn abort_proposal(&mut self, proposal_id: ProposalId) { - self.wrap_abort_proposal(proposal_id).await - } +#[tokio::test] +async fn mempool_not_ready() { + let mut mock_dependencies = MockDependencies::default(); + mock_dependencies.mempool_client.checkpoint(); + mock_dependencies.mempool_client.expect_update_gas_price().returning(|_| { + Err(MempoolClientError::ClientError(ClientError::CommunicationFailure("".to_string()))) + }); + mock_dependencies + .mempool_client + .expect_commit_block() + .with(eq(CommitBlockArgs::default())) + .returning(|_| Ok(())); + mock_dependencies.l1_provider_client.expect_start_block().returning(|_, _| Ok(())); - async fn reset(&mut self) { - self.wrap_reset().await - } + let mut batcher = create_batcher(mock_dependencies).await; + batcher.start_height(StartHeightInput { height: INITIAL_HEIGHT }).await.unwrap(); + let result = batcher.propose_block(propose_block_input(PROPOSAL_ID)).await; + assert_eq!(result, Err(BatcherError::InternalError)); } -fn test_tx_hashes(range: std::ops::Range) -> HashSet { - range.map(|i| TransactionHash(felt!(i))).collect() -} +#[test] +fn validate_batcher_config_failure() { + let config = BatcherConfig { + input_stream_content_buffer_size: 99, + block_builder_config: BlockBuilderConfig { tx_chunk_size: 100, ..Default::default() }, + ..Default::default() + }; -fn test_contract_nonces(range: std::ops::Range) -> HashMap { - HashMap::from_iter(range.map(|i| (contract_address!(i), nonce!(i)))) + let error = config.validate().unwrap_err(); + assert!( + error + .to_string() + .contains("input_stream_content_buffer_size must be at least tx_chunk_size") + ); } diff --git a/crates/starknet_batcher/src/block_builder.rs b/crates/starknet_batcher/src/block_builder.rs index 4eab564c0fc..9a5363c1ec0 100644 --- a/crates/starknet_batcher/src/block_builder.rs +++ b/crates/starknet_batcher/src/block_builder.rs @@ -1,35 +1,45 @@ -use std::collections::BTreeMap; +use std::collections::{BTreeMap, HashMap, HashSet}; +use std::sync::Arc; use async_trait::async_trait; -use blockifier::blockifier::block::{BlockInfo, GasPrices}; use blockifier::blockifier::config::TransactionExecutorConfig; use blockifier::blockifier::transaction_executor::{ + BlockExecutionSummary, TransactionExecutor, TransactionExecutorError as BlockifierTransactionExecutorError, TransactionExecutorResult, - VisitedSegmentsMapping, }; +use blockifier::blockifier_versioned_constants::{VersionedConstants, VersionedConstantsOverrides}; use blockifier::bouncer::{BouncerConfig, BouncerWeights}; use blockifier::context::{BlockContext, ChainInfo}; -use blockifier::execution::contract_class::RunnableContractClass; use blockifier::state::cached_state::CommitmentStateDiff; +use blockifier::state::contract_class_manager::ContractClassManager; use blockifier::state::errors::StateError; -use blockifier::state::global_cache::GlobalContractCache; use blockifier::transaction::objects::TransactionExecutionInfo; use blockifier::transaction::transaction_execution::Transaction as BlockifierTransaction; -use blockifier::versioned_constants::{VersionedConstants, VersionedConstantsOverrides}; -use indexmap::IndexMap; +use indexmap::{IndexMap, IndexSet}; #[cfg(test)] use mockall::automock; use papyrus_config::dumping::{append_sub_config_name, ser_param, SerializeConfig}; use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; -use papyrus_state_reader::papyrus_state::PapyrusReader; +use papyrus_state_reader::papyrus_state::{ClassReader, PapyrusReader}; use papyrus_storage::StorageReader; use serde::{Deserialize, Serialize}; -use starknet_api::block::{BlockHashAndNumber, BlockNumber, BlockTimestamp, NonzeroGasPrice}; -use starknet_api::core::ContractAddress; -use starknet_api::executable_transaction::Transaction; +use starknet_api::block::{BlockHashAndNumber, BlockInfo}; +use starknet_api::block_hash::state_diff_hash::calculate_state_diff_hash; +use starknet_api::consensus_transaction::InternalConsensusTransaction; +use starknet_api::core::{ContractAddress, Nonce}; +use starknet_api::execution_resources::GasAmount; +use starknet_api::state::ThinStateDiff; use starknet_api::transaction::TransactionHash; +use starknet_batcher_types::batcher_types::ProposalCommitment; +use starknet_class_manager_types::transaction_converter::{ + TransactionConverter, + TransactionConverterError, + TransactionConverterResult, + TransactionConverterTrait, +}; +use starknet_class_manager_types::SharedClassManagerClient; use thiserror::Error; use tokio::sync::Mutex; use tracing::{debug, error, info, trace}; @@ -39,8 +49,6 @@ use crate::transaction_provider::{NextTxs, TransactionProvider, TransactionProvi #[derive(Debug, Error)] pub enum BlockBuilderError { - #[error(transparent)] - BadTimestamp(#[from] std::num::TryFromIntError), #[error(transparent)] BlockifierStateError(#[from] StateError), #[error(transparent)] @@ -48,11 +56,15 @@ pub enum BlockBuilderError { #[error(transparent)] GetTransactionError(#[from] TransactionProviderError), #[error(transparent)] - StreamTransactionsError(#[from] tokio::sync::mpsc::error::SendError), + StreamTransactionsError( + #[from] tokio::sync::mpsc::error::SendError, + ), #[error(transparent)] FailOnError(FailOnErrorCause), #[error("The block builder was aborted.")] Aborted, + #[error(transparent)] + TransactionConverterError(#[from] TransactionConverterError), } pub type BlockBuilderResult = Result; @@ -70,10 +82,47 @@ pub enum FailOnErrorCause { #[cfg_attr(test, derive(Clone))] #[derive(Debug, PartialEq)] pub struct BlockExecutionArtifacts { - pub execution_infos: IndexMap, + // Note: The execution_infos must be ordered to match the order of the transactions in the + // block. + pub execution_data: BlockTransactionExecutionData, pub commitment_state_diff: CommitmentStateDiff, - pub visited_segments_mapping: VisitedSegmentsMapping, + pub compressed_state_diff: Option, pub bouncer_weights: BouncerWeights, + pub l2_gas_used: GasAmount, +} + +impl BlockExecutionArtifacts { + pub fn address_to_nonce(&self) -> HashMap { + HashMap::from_iter( + self.commitment_state_diff + .address_to_nonce + .iter() + .map(|(address, nonce)| (*address, *nonce)), + ) + } + + pub fn tx_hashes(&self) -> HashSet { + HashSet::from_iter(self.execution_data.execution_infos.keys().copied()) + } + + pub fn thin_state_diff(&self) -> ThinStateDiff { + // TODO(Ayelet): Remove the clones. + let commitment_state_diff = self.commitment_state_diff.clone(); + ThinStateDiff { + deployed_contracts: commitment_state_diff.address_to_class_hash, + storage_diffs: commitment_state_diff.storage_updates, + declared_classes: commitment_state_diff.class_hash_to_compiled_class_hash, + nonces: commitment_state_diff.address_to_nonce, + // TODO(AlonH): Remove this when the structure of storage diffs changes. + deprecated_declared_classes: Vec::new(), + } + } + + pub fn commitment(&self) -> ProposalCommitment { + ProposalCommitment { + state_diff_commitment: calculate_state_diff_hash(&self.thin_state_diff()), + } + } } /// The BlockBuilderTrait is responsible for building a new block from transactions provided by the @@ -92,10 +141,11 @@ pub struct BlockBuilderExecutionParams { pub struct BlockBuilder { // TODO(Yael 14/10/2024): make the executor thread safe and delete this mutex. - executor: Mutex>, + executor: Arc>, tx_provider: Box, - output_content_sender: Option>, + output_content_sender: Option>, abort_signal_receiver: tokio::sync::oneshot::Receiver<()>, + transaction_converter: TransactionConverter, // Parameters to configure the block builder behavior. tx_chunk_size: usize, @@ -104,18 +154,23 @@ pub struct BlockBuilder { impl BlockBuilder { pub fn new( - executor: Box, + executor: impl TransactionExecutorTrait + 'static, tx_provider: Box, - output_content_sender: Option>, + output_content_sender: Option< + tokio::sync::mpsc::UnboundedSender, + >, abort_signal_receiver: tokio::sync::oneshot::Receiver<()>, + transaction_converter: TransactionConverter, tx_chunk_size: usize, execution_params: BlockBuilderExecutionParams, ) -> Self { + let executor = Arc::new(Mutex::new(executor)); Self { - executor: Mutex::new(executor), + executor, tx_provider, output_content_sender, abort_signal_receiver, + transaction_converter, tx_chunk_size, execution_params, } @@ -126,7 +181,8 @@ impl BlockBuilder { impl BlockBuilderTrait for BlockBuilder { async fn build_block(&mut self) -> BlockBuilderResult { let mut block_is_full = false; - let mut execution_infos = IndexMap::new(); + let mut l2_gas_used = GasAmount::ZERO; + let mut execution_data = BlockTransactionExecutionData::default(); // TODO(yael 6/10/2024): delete the timeout condition once the executor has a timeout while !block_is_full { if tokio::time::Instant::now() >= self.execution_params.deadline { @@ -140,109 +196,163 @@ impl BlockBuilderTrait for BlockBuilder { info!("Received abort signal. Aborting block builder."); return Err(BlockBuilderError::Aborted); } - let next_txs = self.tx_provider.get_txs(self.tx_chunk_size).await?; + let next_txs = + self.tx_provider.get_txs(self.tx_chunk_size).await.inspect_err(|err| { + error!("Failed to get transactions from the transaction provider: {}", err); + })?; let next_tx_chunk = match next_txs { NextTxs::Txs(txs) => txs, NextTxs::End => break, }; debug!("Got {} transactions from the transaction provider.", next_tx_chunk.len()); if next_tx_chunk.is_empty() { - // TODO: Consider what is the best sleep duration. + // TODO(AlonH): Consider what is the best sleep duration. tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; continue; } - let mut executor_input_chunk = vec![]; - for tx in &next_tx_chunk { - // TODO(yair): Avoid this clone. - executor_input_chunk.push(BlockifierTransaction::from(tx.clone())); - } - let results = self.executor.lock().await.add_txs_to_block(&executor_input_chunk); + let tx_convert_futures = next_tx_chunk.iter().map(|tx| async { + convert_to_executable_blockifier_tx(&self.transaction_converter, tx.clone()).await + }); + let executor_input_chunk = futures::future::try_join_all(tx_convert_futures).await?; + + // Execute the transactions on a separate thread pool to avoid blocking the executor + // while waiting on `block_on` calls. + let executor = self.executor.clone(); + let results = tokio::task::spawn_blocking(move || { + executor + .try_lock() // Acquire the lock in a sync manner. + .expect("Only a single task should use the executor.") + .add_txs_to_block(executor_input_chunk.as_slice()) + }) + .await + .expect("Failed to spawn blocking executor task."); trace!("Transaction execution results: {:?}", results); block_is_full = collect_execution_results_and_stream_txs( next_tx_chunk, results, - &mut execution_infos, + &mut l2_gas_used, + &mut execution_data, &self.output_content_sender, self.execution_params.fail_on_err, ) .await?; } - let (commitment_state_diff, visited_segments_mapping, bouncer_weights) = + let BlockExecutionSummary { state_diff, compressed_state_diff, bouncer_weights } = self.executor.lock().await.close_block()?; Ok(BlockExecutionArtifacts { - execution_infos, - commitment_state_diff, - visited_segments_mapping, + execution_data, + commitment_state_diff: state_diff, + compressed_state_diff, bouncer_weights, + l2_gas_used, }) } } +async fn convert_to_executable_blockifier_tx( + transaction_converter: &TransactionConverter, + tx: InternalConsensusTransaction, +) -> TransactionConverterResult { + let executable_tx = + transaction_converter.convert_internal_consensus_tx_to_executable_tx(tx).await?; + Ok(BlockifierTransaction::new_for_sequencing(executable_tx)) +} + /// Returns true if the block is full and should be closed, false otherwise. async fn collect_execution_results_and_stream_txs( - tx_chunk: Vec, + tx_chunk: Vec, results: Vec>, - execution_infos: &mut IndexMap, - output_content_sender: &Option>, + l2_gas_used: &mut GasAmount, + execution_data: &mut BlockTransactionExecutionData, + output_content_sender: &Option< + tokio::sync::mpsc::UnboundedSender, + >, fail_on_err: bool, ) -> BlockBuilderResult { + assert!( + results.len() <= tx_chunk.len(), + "The number of results should be less than or equal to the number of transactions." + ); + let mut block_is_full = false; + // If the block is full, we won't get an error from the executor. We will just get only the + // results of the transactions that were executed before the block was full. + // see [TransactionExecutor::execute_txs]. + if results.len() < tx_chunk.len() { + info!("Block is full."); + if fail_on_err { + return Err(BlockBuilderError::FailOnError(FailOnErrorCause::BlockFull)); + } else { + block_is_full = true; + } + } for (input_tx, result) in tx_chunk.into_iter().zip(results.into_iter()) { match result { Ok(tx_execution_info) => { - execution_infos.insert(input_tx.tx_hash(), tx_execution_info); + *l2_gas_used = l2_gas_used + .checked_add(tx_execution_info.receipt.gas.l2_gas) + .expect("Total L2 gas overflow."); + + let tx_hash = input_tx.tx_hash(); + execution_data.execution_infos.insert(tx_hash, tx_execution_info); + if let InternalConsensusTransaction::L1Handler(_) = input_tx { + execution_data.accepted_l1_handler_tx_hashes.insert(tx_hash); + } + if let Some(output_content_sender) = output_content_sender { output_content_sender.send(input_tx)?; } } // TODO(yael 18/9/2024): add timeout error handling here once this // feature is added. - Err(BlockifierTransactionExecutorError::BlockFull) => { - info!("Block is full"); - if fail_on_err { - return Err(BlockBuilderError::FailOnError(FailOnErrorCause::BlockFull)); - } - return Ok(true); - } Err(err) => { - debug!("Transaction {:?} failed with error: {}.", input_tx, err); + debug!("Transaction {} failed with error: {}.", input_tx.tx_hash(), err); if fail_on_err { return Err(BlockBuilderError::FailOnError( FailOnErrorCause::TransactionFailed(err), )); } + execution_data.rejected_tx_hashes.insert(input_tx.tx_hash()); } } } - Ok(false) + Ok(block_is_full) } pub struct BlockMetadata { - pub height: BlockNumber, + pub block_info: BlockInfo, pub retrospective_block_hash: Option, } +// Type definitions for the abort channel required to abort the block builder. +pub type AbortSignalSender = tokio::sync::oneshot::Sender<()>; + /// The BlockBuilderFactoryTrait is responsible for creating a new block builder. #[cfg_attr(test, automock)] -pub trait BlockBuilderFactoryTrait { +pub trait BlockBuilderFactoryTrait: Send + Sync { + // TODO(noamsp): Investigate and remove this clippy warning. + #[allow(clippy::result_large_err)] fn create_block_builder( &self, block_metadata: BlockMetadata, execution_params: BlockBuilderExecutionParams, tx_provider: Box, - output_content_sender: Option>, - abort_signal_receiver: tokio::sync::oneshot::Receiver<()>, - ) -> BlockBuilderResult>; + output_content_sender: Option< + tokio::sync::mpsc::UnboundedSender, + >, + runtime: tokio::runtime::Handle, + ) -> BlockBuilderResult<(Box, AbortSignalSender)>; + + fn take_class_cache_miss_counter(&self) -> u64; + + fn take_class_cache_hit_counter(&self) -> u64; } #[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] pub struct BlockBuilderConfig { - // TODO(Yael 1/10/2024): add to config pointers pub chain_info: ChainInfo, pub execute_config: TransactionExecutorConfig, pub bouncer_config: BouncerConfig, - pub sequencer_address: ContractAddress, - pub use_kzg_da: bool, pub tx_chunk_size: usize, pub versioned_constants_overrides: VersionedConstantsOverrides, } @@ -250,12 +360,10 @@ pub struct BlockBuilderConfig { impl Default for BlockBuilderConfig { fn default() -> Self { Self { - // TODO: update the default values once the actual values are known. + // TODO(AlonH): update the default values once the actual values are known. chain_info: ChainInfo::default(), execute_config: TransactionExecutorConfig::default(), bouncer_config: BouncerConfig::default(), - sequencer_address: ContractAddress::default(), - use_kzg_da: true, tx_chunk_size: 100, versioned_constants_overrides: VersionedConstantsOverrides::default(), } @@ -267,22 +375,10 @@ impl SerializeConfig for BlockBuilderConfig { let mut dump = append_sub_config_name(self.chain_info.dump(), "chain_info"); dump.append(&mut append_sub_config_name(self.execute_config.dump(), "execute_config")); dump.append(&mut append_sub_config_name(self.bouncer_config.dump(), "bouncer_config")); - dump.append(&mut BTreeMap::from([ser_param( - "sequencer_address", - &self.sequencer_address, - "The address of the sequencer.", - ParamPrivacyInput::Public, - )])); - dump.append(&mut BTreeMap::from([ser_param( - "use_kzg_da", - &self.use_kzg_da, - "Indicates whether the kzg mechanism is used for data availability.", - ParamPrivacyInput::Public, - )])); dump.append(&mut BTreeMap::from([ser_param( "tx_chunk_size", &self.tx_chunk_size, - "The size of the transaction chunk.", + "Number of transactions in each request from the tx_provider.", ParamPrivacyInput::Public, )])); dump.append(&mut append_sub_config_name( @@ -296,40 +392,36 @@ impl SerializeConfig for BlockBuilderConfig { pub struct BlockBuilderFactory { pub block_builder_config: BlockBuilderConfig, pub storage_reader: StorageReader, - pub global_class_hash_to_class: GlobalContractCache, + pub contract_class_manager: ContractClassManager, + pub class_manager_client: SharedClassManagerClient, } impl BlockBuilderFactory { + // TODO(noamsp): Investigate and remove this clippy warning. + #[allow(clippy::result_large_err)] fn preprocess_and_create_transaction_executor( &self, - block_metadata: &BlockMetadata, + block_metadata: BlockMetadata, + runtime: tokio::runtime::Handle, ) -> BlockBuilderResult> { + let height = block_metadata.block_info.block_number; let block_builder_config = self.block_builder_config.clone(); - let next_block_info = BlockInfo { - block_number: block_metadata.height, - block_timestamp: BlockTimestamp(chrono::Utc::now().timestamp().try_into()?), - sequencer_address: block_builder_config.sequencer_address, - // TODO (yael 7/10/2024): add logic to compute gas prices - gas_prices: { - let tmp_val = NonzeroGasPrice::MIN; - GasPrices::new(tmp_val, tmp_val, tmp_val, tmp_val, tmp_val, tmp_val) - }, - use_kzg_da: block_builder_config.use_kzg_da, - }; let versioned_constants = VersionedConstants::get_versioned_constants( block_builder_config.versioned_constants_overrides, ); let block_context = BlockContext::new( - next_block_info, + block_metadata.block_info, block_builder_config.chain_info, versioned_constants, block_builder_config.bouncer_config, ); - let state_reader = PapyrusReader::new( + let class_reader = Some(ClassReader { reader: self.class_manager_client.clone(), runtime }); + let state_reader = PapyrusReader::new_with_class_manager( self.storage_reader.clone(), - block_metadata.height, - self.global_class_hash_to_class.clone(), + height, + self.contract_class_manager.clone(), + class_reader, ); let executor = TransactionExecutor::pre_process_and_create( @@ -349,17 +441,43 @@ impl BlockBuilderFactoryTrait for BlockBuilderFactory { block_metadata: BlockMetadata, execution_params: BlockBuilderExecutionParams, tx_provider: Box, - output_content_sender: Option>, - abort_signal_receiver: tokio::sync::oneshot::Receiver<()>, - ) -> BlockBuilderResult> { - let executor = self.preprocess_and_create_transaction_executor(&block_metadata)?; - Ok(Box::new(BlockBuilder::new( - Box::new(executor), + output_content_sender: Option< + tokio::sync::mpsc::UnboundedSender, + >, + runtime: tokio::runtime::Handle, + ) -> BlockBuilderResult<(Box, AbortSignalSender)> { + let executor = self.preprocess_and_create_transaction_executor(block_metadata, runtime)?; + let (abort_signal_sender, abort_signal_receiver) = tokio::sync::oneshot::channel(); + let transaction_converter = TransactionConverter::new( + self.class_manager_client.clone(), + self.block_builder_config.chain_info.chain_id.clone(), + ); + let block_builder = Box::new(BlockBuilder::new( + executor, tx_provider, output_content_sender, abort_signal_receiver, + transaction_converter, self.block_builder_config.tx_chunk_size, execution_params, - ))) + )); + Ok((block_builder, abort_signal_sender)) + } + + fn take_class_cache_hit_counter(&self) -> u64 { + self.contract_class_manager.take_cache_hit_counter() } + + fn take_class_cache_miss_counter(&self) -> u64 { + self.contract_class_manager.take_cache_miss_counter() + } +} + +/// Supplementary information for use by downstream services. +#[cfg_attr(test, derive(Clone))] +#[derive(Debug, Default, PartialEq)] +pub struct BlockTransactionExecutionData { + pub execution_infos: IndexMap, + pub rejected_tx_hashes: HashSet, + pub accepted_l1_handler_tx_hashes: IndexSet, } diff --git a/crates/starknet_batcher/src/block_builder_test.rs b/crates/starknet_batcher/src/block_builder_test.rs index ea73200169a..a8d6ddc252f 100644 --- a/crates/starknet_batcher/src/block_builder_test.rs +++ b/crates/starknet_batcher/src/block_builder_test.rs @@ -1,18 +1,30 @@ +use std::collections::HashSet; +use std::sync::Arc; + use assert_matches::assert_matches; -use blockifier::blockifier::transaction_executor::TransactionExecutorError; +use blockifier::blockifier::transaction_executor::{ + BlockExecutionSummary, + TransactionExecutorError, +}; use blockifier::bouncer::BouncerWeights; use blockifier::fee::fee_checks::FeeCheckError; +use blockifier::fee::receipt::TransactionReceipt; use blockifier::state::errors::StateError; use blockifier::transaction::objects::{RevertError, TransactionExecutionInfo}; use blockifier::transaction::transaction_execution::Transaction as BlockifierTransaction; -use indexmap::{indexmap, IndexMap}; +use indexmap::{IndexMap, IndexSet}; use mockall::predicate::eq; use mockall::Sequence; +use pretty_assertions::assert_eq; use rstest::rstest; -use starknet_api::executable_transaction::Transaction; -use starknet_api::felt; +use starknet_api::consensus_transaction::InternalConsensusTransaction; +use starknet_api::execution_resources::{GasAmount, GasVector}; +use starknet_api::test_utils::CHAIN_ID_FOR_TESTS; use starknet_api::transaction::fields::Fee; use starknet_api::transaction::TransactionHash; +use starknet_api::tx_hash; +use starknet_class_manager_types::transaction_converter::TransactionConverter; +use starknet_class_manager_types::MockClassManagerClient; use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender}; use crate::block_builder::{ @@ -22,9 +34,10 @@ use crate::block_builder::{ BlockBuilderResult, BlockBuilderTrait, BlockExecutionArtifacts, + BlockTransactionExecutionData, FailOnErrorCause, }; -use crate::test_utils::test_txs; +use crate::test_utils::{test_l1_handler_txs, test_txs}; use crate::transaction_executor::MockTransactionExecutorTrait; use crate::transaction_provider::{MockTransactionProvider, NextTxs}; @@ -37,21 +50,32 @@ struct TestExpectations { mock_transaction_executor: MockTransactionExecutorTrait, mock_tx_provider: MockTransactionProvider, expected_block_artifacts: BlockExecutionArtifacts, - expected_txs_output: Vec, + expected_txs_output: Vec, } -fn output_channel() -> (UnboundedSender, UnboundedReceiver) { +fn output_channel() +-> (UnboundedSender, UnboundedReceiver) +{ tokio::sync::mpsc::unbounded_channel() } fn block_execution_artifacts( execution_infos: IndexMap, + rejected_tx_hashes: HashSet, + accepted_l1_handler_tx_hashes: IndexSet, ) -> BlockExecutionArtifacts { + let l2_gas_used = GasAmount(execution_infos.len().try_into().unwrap()); BlockExecutionArtifacts { - execution_infos, + execution_data: BlockTransactionExecutionData { + execution_infos, + rejected_tx_hashes, + accepted_l1_handler_tx_hashes, + }, commitment_state_diff: Default::default(), - visited_segments_mapping: Default::default(), - bouncer_weights: BouncerWeights { gas: 100, ..BouncerWeights::empty() }, + compressed_state_diff: Default::default(), + bouncer_weights: BouncerWeights { l1_gas: 100, ..BouncerWeights::empty() }, + // Each mock transaction uses 1 L2 gas so the total amount should be the number of txs. + l2_gas_used, } } @@ -62,6 +86,10 @@ fn execution_info() -> TransactionExecutionInfo { max_fee: Fee(100), actual_fee: Fee(101), })), + receipt: TransactionReceipt { + gas: GasVector { l2_gas: GasAmount(1), ..Default::default() }, + ..Default::default() + }, ..Default::default() } } @@ -83,7 +111,7 @@ fn one_chunk_test_expectations() -> TestExpectations { } fn one_chunk_mock_executor( - input_txs: &[Transaction], + input_txs: &[InternalConsensusTransaction], block_size: usize, ) -> (MockTransactionExecutorTrait, BlockExecutionArtifacts) { let input_txs_cloned = input_txs.to_vec(); @@ -107,7 +135,8 @@ fn two_chunks_test_expectations() -> TestExpectations { let block_size = input_txs.len(); let mut mock_transaction_executor = MockTransactionExecutorTrait::new(); - let mut mock_add_txs_to_block = |tx_chunk: Vec, seq: &mut Sequence| { + let mut mock_add_txs_to_block = |tx_chunk: Vec, + seq: &mut Sequence| { mock_transaction_executor .expect_add_txs_to_block() .times(1) @@ -149,14 +178,19 @@ fn empty_block_test_expectations() -> TestExpectations { } } -fn mock_transaction_executor_block_full(input_txs: &[Transaction]) -> MockTransactionExecutorTrait { +fn mock_transaction_executor_block_full( + input_txs: &[InternalConsensusTransaction], +) -> MockTransactionExecutorTrait { let input_txs_cloned = input_txs.to_vec(); let mut mock_transaction_executor = MockTransactionExecutorTrait::new(); + let execution_results = vec![Ok(execution_info())]; + // When the block is full, the executor will return less results than the number of input txs. + assert!(input_txs.len() > execution_results.len()); mock_transaction_executor .expect_add_txs_to_block() .times(1) .withf(move |blockifier_input| compare_tx_hashes(&input_txs_cloned, blockifier_input)) - .return_once(move |_| vec![Ok(execution_info()), Err(TransactionExecutorError::BlockFull)]); + .return_once(move |_| execution_results); mock_transaction_executor } @@ -176,7 +210,9 @@ fn block_full_test_expectations() -> TestExpectations { } } -fn mock_transaction_executor_with_delay(input_txs: &[Transaction]) -> MockTransactionExecutorTrait { +fn mock_transaction_executor_with_delay( + input_txs: &[InternalConsensusTransaction], +) -> MockTransactionExecutorTrait { let input_txs_cloned = input_txs.to_vec(); let mut mock_transaction_executor = MockTransactionExecutorTrait::new(); mock_transaction_executor @@ -234,33 +270,55 @@ fn stream_done_test_expectations() -> TestExpectations { } fn transaction_failed_test_expectations() -> TestExpectations { - let input_txs = test_txs(0..3); - - let mut expected_txs_output = input_txs.clone(); - expected_txs_output.remove(1); + let input_invoke_txs = test_txs(0..3); + let input_l1_handler_txs = test_l1_handler_txs(3..6); + let failed_tx_hashes = HashSet::from([tx_hash!(1), tx_hash!(4)]); + let accepted_l1_handler_tx_hashes: IndexSet<_> = input_l1_handler_txs + .iter() + .map(|tx| tx.tx_hash()) + .filter(|tx_hash| !failed_tx_hashes.contains(tx_hash)) + .collect(); + let input_txs = input_invoke_txs.into_iter().chain(input_l1_handler_txs); + + let expected_txs_output: Vec<_> = + input_txs.clone().filter(|tx| !failed_tx_hashes.contains(&tx.tx_hash())).collect(); let mut mock_transaction_executor = MockTransactionExecutorTrait::new(); - let execution_error = - TransactionExecutorError::StateError(StateError::OutOfRangeContractAddress); - mock_transaction_executor.expect_add_txs_to_block().times(1).return_once(move |_| { - vec![Ok(execution_info()), Err(execution_error), Ok(execution_info())] - }); + let failed_tx_hashes_ref = failed_tx_hashes.clone(); + let mocked_add_txs_response = move |txs: &[BlockifierTransaction]| { + txs.iter() + .map(|tx| { + if (failed_tx_hashes_ref).contains(&BlockifierTransaction::tx_hash(tx)) { + Err(TransactionExecutorError::StateError(StateError::OutOfRangeContractAddress)) + } else { + Ok(execution_info()) + } + }) + .collect() + }; + mock_transaction_executor + .expect_add_txs_to_block() + .times(1) + .return_once(mocked_add_txs_response); + + let execution_infos_mapping = + expected_txs_output.iter().map(|tx| (tx.tx_hash(), execution_info())).collect(); - let execution_infos_mapping = indexmap![ - TransactionHash(felt!(u8::try_from(0).unwrap()))=> execution_info(), - TransactionHash(felt!(u8::try_from(2).unwrap()))=> execution_info(), - ]; - let expected_block_artifacts = block_execution_artifacts(execution_infos_mapping); + let expected_block_artifacts = block_execution_artifacts( + execution_infos_mapping, + failed_tx_hashes, + accepted_l1_handler_tx_hashes, + ); let expected_block_artifacts_copy = expected_block_artifacts.clone(); mock_transaction_executor.expect_close_block().times(1).return_once(move || { - Ok(( - expected_block_artifacts_copy.commitment_state_diff, - expected_block_artifacts_copy.visited_segments_mapping, - expected_block_artifacts_copy.bouncer_weights, - )) + Ok(BlockExecutionSummary { + state_diff: expected_block_artifacts_copy.commitment_state_diff, + compressed_state_diff: None, + bouncer_weights: expected_block_artifacts_copy.bouncer_weights, + }) }); - let mock_tx_provider = mock_tx_provider_limitless_calls(1, vec![input_txs]); + let mock_tx_provider = mock_tx_provider_limitless_calls(1, vec![input_txs.collect()]); TestExpectations { mock_transaction_executor, @@ -275,8 +333,8 @@ fn transaction_failed_test_expectations() -> TestExpectations { fn block_builder_expected_output(execution_info_len: usize) -> BlockExecutionArtifacts { let execution_info_len_u8 = u8::try_from(execution_info_len).unwrap(); let execution_infos_mapping = - (0..execution_info_len_u8).map(|i| (TransactionHash(felt!(i)), execution_info())).collect(); - block_execution_artifacts(execution_infos_mapping) + (0..execution_info_len_u8).map(|i| (tx_hash!(i), execution_info())).collect(); + block_execution_artifacts(execution_infos_mapping, Default::default(), Default::default()) } fn set_close_block_expectations( @@ -286,11 +344,11 @@ fn set_close_block_expectations( let output_block_artifacts = block_builder_expected_output(block_size); let output_block_artifacts_copy = output_block_artifacts.clone(); mock_transaction_executor.expect_close_block().times(1).return_once(move || { - Ok(( - output_block_artifacts.commitment_state_diff, - output_block_artifacts.visited_segments_mapping, - output_block_artifacts.bouncer_weights, - )) + Ok(BlockExecutionSummary { + state_diff: output_block_artifacts.commitment_state_diff, + compressed_state_diff: None, + bouncer_weights: output_block_artifacts.bouncer_weights, + }) }); output_block_artifacts_copy } @@ -299,7 +357,7 @@ fn set_close_block_expectations( /// This function assumes constant chunk size of TX_CHUNK_SIZE. fn mock_tx_provider_limited_calls( n_calls: usize, - mut input_chunks: Vec>, + mut input_chunks: Vec>, ) -> MockTransactionProvider { let mut mock_tx_provider = MockTransactionProvider::new(); mock_tx_provider @@ -310,7 +368,9 @@ fn mock_tx_provider_limited_calls( mock_tx_provider } -fn mock_tx_provider_stream_done(input_chunk: Vec) -> MockTransactionProvider { +fn mock_tx_provider_stream_done( + input_chunk: Vec, +) -> MockTransactionProvider { let mut mock_tx_provider = MockTransactionProvider::new(); let mut seq = Sequence::new(); mock_tx_provider @@ -331,7 +391,7 @@ fn mock_tx_provider_stream_done(input_chunk: Vec) -> MockTransactio /// This function assumes constant chunk size of TX_CHUNK_SIZE. fn mock_tx_provider_limitless_calls( n_calls: usize, - input_chunks: Vec>, + input_chunks: Vec>, ) -> MockTransactionProvider { let mut mock_tx_provider = mock_tx_provider_limited_calls(n_calls, input_chunks); @@ -347,7 +407,10 @@ fn add_limitless_empty_calls(mock_tx_provider: &mut MockTransactionProvider) { .returning(|_n_txs| Ok(NextTxs::Txs(Vec::new()))); } -fn compare_tx_hashes(input: &[Transaction], blockifier_input: &[BlockifierTransaction]) -> bool { +fn compare_tx_hashes( + input: &[InternalConsensusTransaction], + blockifier_input: &[BlockifierTransaction], +) -> bool { let expected_tx_hashes: Vec = input.iter().map(|tx| tx.tx_hash()).collect(); let input_tx_hashes: Vec = blockifier_input.iter().map(BlockifierTransaction::tx_hash).collect(); @@ -355,19 +418,15 @@ fn compare_tx_hashes(input: &[Transaction], blockifier_input: &[BlockifierTransa } async fn verify_build_block_output( - expected_output_txs: Vec, + expected_output_txs: Vec, expected_block_artifacts: BlockExecutionArtifacts, result_block_artifacts: BlockExecutionArtifacts, - mut output_stream_receiver: UnboundedReceiver, + mut output_stream_receiver: UnboundedReceiver, ) { // Verify the transactions in the output channel. let mut output_txs = vec![]; output_stream_receiver.recv_many(&mut output_txs, TX_CHANNEL_SIZE).await; - - assert_eq!(output_txs.len(), expected_output_txs.len()); - for tx in expected_output_txs.iter() { - assert!(output_txs.contains(tx)); - } + assert_eq!(output_txs, expected_output_txs); // Verify the block artifacts. assert_eq!(result_block_artifacts, expected_block_artifacts); @@ -376,17 +435,22 @@ async fn verify_build_block_output( async fn run_build_block( mock_transaction_executor: MockTransactionExecutorTrait, tx_provider: MockTransactionProvider, - output_sender: Option>, + output_sender: Option>, fail_on_err: bool, abort_receiver: tokio::sync::oneshot::Receiver<()>, deadline_secs: u64, ) -> BlockBuilderResult { let deadline = tokio::time::Instant::now() + tokio::time::Duration::from_secs(deadline_secs); + let transaction_converter = TransactionConverter::new( + Arc::new(MockClassManagerClient::new()), + CHAIN_ID_FOR_TESTS.clone(), + ); let mut block_builder = BlockBuilder::new( - Box::new(mock_transaction_executor), + mock_transaction_executor, Box::new(tx_provider), output_sender, abort_receiver, + transaction_converter, TX_CHUNK_SIZE, BlockBuilderExecutionParams { deadline, fail_on_err }, ); @@ -454,7 +518,7 @@ async fn test_validate_block() { #[case::deadline_reached(test_txs(0..3), mock_transaction_executor_with_delay(&input_txs), FailOnErrorCause::DeadlineReached)] #[tokio::test] async fn test_validate_block_with_error( - #[case] input_txs: Vec, + #[case] input_txs: Vec, #[case] mut mock_transaction_executor: MockTransactionExecutorTrait, #[case] expected_error: FailOnErrorCause, ) { @@ -544,3 +608,56 @@ async fn test_build_block_abort_immediately() { Err(BlockBuilderError::Aborted) ); } + +#[rstest] +#[tokio::test] +async fn test_l2_gas_used() { + let n_txs = 3; + let input_txs = test_txs(0..n_txs); + let (mock_transaction_executor, _) = one_chunk_mock_executor(&input_txs, input_txs.len()); + let mock_tx_provider = mock_tx_provider_stream_done(input_txs); + + let (_abort_sender, abort_receiver) = tokio::sync::oneshot::channel(); + let result_block_artifacts = run_build_block( + mock_transaction_executor, + mock_tx_provider, + None, + true, + abort_receiver, + BLOCK_GENERATION_DEADLINE_SECS, + ) + .await + .unwrap(); + + // Each mock transaction uses 1 L2 gas so the total amount should be the number of txs. + assert_eq!(result_block_artifacts.l2_gas_used, GasAmount(n_txs.try_into().unwrap())); +} + +// Test that the BlocBuilder returns the execution_infos ordered in the same order as +// the transactions are included in the block. This is crucial for the correct execution of +// starknet. +#[tokio::test] +async fn test_execution_info_order() { + let input_txs = test_txs(0..6); + let (mock_transaction_executor, _) = one_chunk_mock_executor(&input_txs, input_txs.len()); + let mock_tx_provider = mock_tx_provider_stream_done(input_txs.clone()); + let (_abort_sender, abort_receiver) = tokio::sync::oneshot::channel(); + + let result_block_artifacts = run_build_block( + mock_transaction_executor, + mock_tx_provider, + None, + false, + abort_receiver, + BLOCK_GENERATION_DEADLINE_SECS, + ) + .await + .unwrap(); + + // Verify that the execution_infos are ordered in the same order as the input_txs. + result_block_artifacts.execution_data.execution_infos.iter().zip(&input_txs).for_each( + |((tx_hash, _execution_info), tx)| { + assert_eq!(tx_hash, &tx.tx_hash()); + }, + ); +} diff --git a/crates/starknet_batcher/src/communication.rs b/crates/starknet_batcher/src/communication.rs index d5b7ae5c7a4..e91859c0d01 100644 --- a/crates/starknet_batcher/src/communication.rs +++ b/crates/starknet_batcher/src/communication.rs @@ -15,6 +15,9 @@ impl ComponentRequestHandler for Batcher { BatcherRequest::ProposeBlock(input) => { BatcherResponse::ProposeBlock(self.propose_block(input).await) } + BatcherRequest::GetCurrentHeight => { + BatcherResponse::GetCurrentHeight(self.get_height().await) + } BatcherRequest::GetProposalContent(input) => { BatcherResponse::GetProposalContent(self.get_proposal_content(input).await) } @@ -22,7 +25,7 @@ impl ComponentRequestHandler for Batcher { BatcherResponse::StartHeight(self.start_height(input).await) } BatcherRequest::DecisionReached(input) => { - BatcherResponse::DecisionReached(self.decision_reached(input).await) + BatcherResponse::DecisionReached(self.decision_reached(input).await.map(Box::new)) } BatcherRequest::ValidateBlock(input) => { BatcherResponse::ValidateBlock(self.validate_block(input).await) @@ -30,6 +33,12 @@ impl ComponentRequestHandler for Batcher { BatcherRequest::SendProposalContent(input) => { BatcherResponse::SendProposalContent(self.send_proposal_content(input).await) } + BatcherRequest::AddSyncBlock(sync_block) => { + BatcherResponse::AddSyncBlock(self.add_sync_block(sync_block).await) + } + BatcherRequest::RevertBlock(input) => { + BatcherResponse::RevertBlock(self.revert_block(input).await) + } } } } diff --git a/crates/starknet_batcher/src/config.rs b/crates/starknet_batcher/src/config.rs index d36329e733a..e27162c42c2 100644 --- a/crates/starknet_batcher/src/config.rs +++ b/crates/starknet_batcher/src/config.rs @@ -1,20 +1,22 @@ use std::collections::BTreeMap; +use blockifier::blockifier::config::ContractClassManagerConfig; use papyrus_config::dumping::{append_sub_config_name, ser_param, SerializeConfig}; use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; use serde::{Deserialize, Serialize}; -use validator::Validate; +use validator::{Validate, ValidationError}; use crate::block_builder::BlockBuilderConfig; /// The batcher related configuration. #[derive(Clone, Debug, Serialize, Deserialize, Validate, PartialEq)] +#[validate(schema(function = "validate_batcher_config"))] pub struct BatcherConfig { pub storage: papyrus_storage::StorageConfig, pub outstream_content_buffer_size: usize, pub input_stream_content_buffer_size: usize, pub block_builder_config: BlockBuilderConfig, - pub global_contract_cache_size: usize, + pub contract_class_manager_config: ContractClassManagerConfig, pub max_l1_handler_txs_per_block_proposal: usize, } @@ -35,13 +37,6 @@ impl SerializeConfig for BatcherConfig { beyond this limit will block until space is available.", ParamPrivacyInput::Public, ), - ser_param( - "global_contract_cache_size", - &self.global_contract_cache_size, - "Cache size for the global_class_hash_to_class. Initialized with this size on \ - creation.", - ParamPrivacyInput::Public, - ), ser_param( "max_l1_handler_txs_per_block_proposal", &self.max_l1_handler_txs_per_block_proposal, @@ -54,6 +49,10 @@ impl SerializeConfig for BatcherConfig { self.block_builder_config.dump(), "block_builder_config", )); + dump.append(&mut append_sub_config_name( + self.contract_class_manager_config.dump(), + "contract_class_manager_config", + )); dump } } @@ -63,20 +62,30 @@ impl Default for BatcherConfig { Self { storage: papyrus_storage::StorageConfig { db_config: papyrus_storage::db::DbConfig { - path_prefix: ".".into(), - // By default we don't want to create the DB if it doesn't exist. - enforce_file_exists: true, + path_prefix: "/data/batcher".into(), + enforce_file_exists: false, ..Default::default() }, scope: papyrus_storage::StorageScope::StateOnly, ..Default::default() }, - // TODO: set a more reasonable default value. + // TODO(AlonH): set a more reasonable default value. outstream_content_buffer_size: 100, input_stream_content_buffer_size: 400, block_builder_config: BlockBuilderConfig::default(), - global_contract_cache_size: 400, + contract_class_manager_config: ContractClassManagerConfig::default(), max_l1_handler_txs_per_block_proposal: 3, } } } + +fn validate_batcher_config(batcher_config: &BatcherConfig) -> Result<(), ValidationError> { + if batcher_config.input_stream_content_buffer_size + < batcher_config.block_builder_config.tx_chunk_size + { + return Err(ValidationError::new( + "input_stream_content_buffer_size must be at least tx_chunk_size", + )); + } + Ok(()) +} diff --git a/crates/starknet_batcher/src/fee_market_test.rs b/crates/starknet_batcher/src/fee_market_test.rs deleted file mode 100644 index 88e4ecebe91..00000000000 --- a/crates/starknet_batcher/src/fee_market_test.rs +++ /dev/null @@ -1,62 +0,0 @@ -use crate::fee_market::{ - calculate_next_base_gas_price, - GAS_PRICE_MAX_CHANGE_DENOMINATOR, - MAX_BLOCK_SIZE, - MIN_GAS_PRICE, -}; - -#[test] -fn test_price_calculation_snapshot() { - // Setup: using realistic arbitrary values. - const INIT_PRICE: u64 = 1_000_000; - const GAS_TARGET: u64 = MAX_BLOCK_SIZE / 2; - const HIGH_CONGESTION_GAS_USED: u64 = MAX_BLOCK_SIZE * 3 / 4; - const LOW_CONGESTION_GAS_USED: u64 = MAX_BLOCK_SIZE / 4; - const STABLE_CONGESTION_GAS_USED: u64 = GAS_TARGET; - - // Fixed expected output values. - let increased_price = 1000000 + 10416; // 1000000 + (1000000 * 1 / 4 * MAX_BLOCK_SIZE) / (0.5 * MAX_BLOCK_SIZE * 48); - let decreased_price = 1000000 - 10416; // 1000000 - (1000000 * 1 / 4 * MAX_BLOCK_SIZE) / (0.5 * MAX_BLOCK_SIZE * 48); - - // Assert. - assert_eq!( - calculate_next_base_gas_price(INIT_PRICE, HIGH_CONGESTION_GAS_USED, GAS_TARGET), - increased_price - ); - assert_eq!( - calculate_next_base_gas_price(INIT_PRICE, LOW_CONGESTION_GAS_USED, GAS_TARGET), - decreased_price - ); - assert_eq!( - calculate_next_base_gas_price(INIT_PRICE, STABLE_CONGESTION_GAS_USED, GAS_TARGET), - INIT_PRICE - ); -} - -#[test] -// This test ensures that the gas price calculation does not overflow with extreme values, -fn test_gas_price_with_extreme_values() { - let price = MIN_GAS_PRICE; - let gas_target = MAX_BLOCK_SIZE / 2; - let gas_used = 0; - assert_eq!(calculate_next_base_gas_price(price, gas_used, gas_target), MIN_GAS_PRICE); - - let price = MIN_GAS_PRICE; - let gas_target = MAX_BLOCK_SIZE / 2; - let gas_used = MAX_BLOCK_SIZE; - assert!(calculate_next_base_gas_price(price, gas_used, gas_target) > MIN_GAS_PRICE); - - let price = u64::MAX; - let gas_target = MAX_BLOCK_SIZE / 2; - let gas_used = 0; - calculate_next_base_gas_price(price, gas_used, gas_target); // Should not panic. - - // To avoid overflow when updating the price, the value is set below a certain threshold so that - // the new price does not exceed u64::MAX. - let max_u128 = u128::from(u64::MAX); - let price_u128 = - max_u128 * GAS_PRICE_MAX_CHANGE_DENOMINATOR / (GAS_PRICE_MAX_CHANGE_DENOMINATOR + 1); - let gas_target = MAX_BLOCK_SIZE / 2; - let gas_used = MAX_BLOCK_SIZE; - calculate_next_base_gas_price(u64::try_from(price_u128).unwrap(), gas_used, gas_target); // Should not panic. -} diff --git a/crates/starknet_batcher/src/lib.rs b/crates/starknet_batcher/src/lib.rs index f25938de6eb..2308fbc73e6 100644 --- a/crates/starknet_batcher/src/lib.rs +++ b/crates/starknet_batcher/src/lib.rs @@ -6,17 +6,15 @@ pub mod block_builder; mod block_builder_test; pub mod communication; pub mod config; -pub mod fee_market; -mod proposal_manager; -#[cfg(test)] -mod proposal_manager_test; +pub mod metrics; #[cfg(test)] mod test_utils; mod transaction_executor; mod transaction_provider; #[cfg(test)] mod transaction_provider_test; +mod utils; // Re-export so it can be used in the general config of the sequencer node without depending on // blockifier. -pub use blockifier::versioned_constants::VersionedConstantsOverrides; +pub use blockifier::blockifier_versioned_constants::VersionedConstantsOverrides; diff --git a/crates/starknet_batcher/src/metrics.rs b/crates/starknet_batcher/src/metrics.rs new file mode 100644 index 00000000000..6ecb5f93a93 --- /dev/null +++ b/crates/starknet_batcher/src/metrics.rs @@ -0,0 +1,76 @@ +use starknet_api::block::BlockNumber; +use starknet_sequencer_metrics::define_metrics; +use starknet_sequencer_metrics::metrics::{MetricCounter, MetricGauge}; + +define_metrics!( + Batcher => { + // Gauges + MetricGauge { STORAGE_HEIGHT, "batcher_storage_height", "The height of the batcher's storage" }, + // Counters + MetricCounter { PROPOSAL_STARTED, "batcher_proposal_started", "Counter of proposals started", init = 0 }, + MetricCounter { CLASS_CACHE_MISSES, "class_cache_misses", "Counter of global class cache misses", init=0 }, + MetricCounter { CLASS_CACHE_HITS, "class_cache_hits", "Counter of global class cache hits", init=0 }, + MetricCounter { PROPOSAL_SUCCEEDED, "batcher_proposal_succeeded", "Counter of successful proposals", init = 0 }, + MetricCounter { PROPOSAL_FAILED, "batcher_proposal_failed", "Counter of failed proposals", init = 0 }, + MetricCounter { PROPOSAL_ABORTED, "batcher_proposal_aborted", "Counter of aborted proposals", init = 0 }, + MetricCounter { BATCHED_TRANSACTIONS, "batcher_batched_transactions", "Counter of batched transactions across all forks", init = 0 }, + MetricCounter { REJECTED_TRANSACTIONS, "batcher_rejected_transactions", "Counter of rejected transactions", init = 0 }, + MetricCounter { SYNCED_BLOCKS, "batcher_synced_blocks", "Counter of synced blocks", init = 0 }, + MetricCounter { SYNCED_TRANSACTIONS, "batcher_synced_transactions", "Counter of synced transactions", init = 0 }, + MetricCounter { REVERTED_BLOCKS, "batcher_reverted_blocks", "Counter of reverted blocks", init = 0 } + }, +); + +pub fn register_metrics(storage_height: BlockNumber) { + STORAGE_HEIGHT.register(); + STORAGE_HEIGHT.set_lossy(storage_height.0); + CLASS_CACHE_MISSES.register(); + CLASS_CACHE_HITS.register(); + + PROPOSAL_STARTED.register(); + PROPOSAL_SUCCEEDED.register(); + PROPOSAL_FAILED.register(); + PROPOSAL_ABORTED.register(); + + // In case of revert, consider calling `absolute`. + BATCHED_TRANSACTIONS.register(); + REJECTED_TRANSACTIONS.register(); +} + +/// A handle to update the proposal metrics when the proposal is created and dropped. +#[derive(Debug)] +pub(crate) struct ProposalMetricsHandle { + finish_status: ProposalFinishStatus, +} + +impl ProposalMetricsHandle { + pub fn new() -> Self { + PROPOSAL_STARTED.increment(1); + Self { finish_status: ProposalFinishStatus::Failed } + } + + pub fn set_succeeded(&mut self) { + self.finish_status = ProposalFinishStatus::Succeeded; + } + + pub fn set_aborted(&mut self) { + self.finish_status = ProposalFinishStatus::Aborted; + } +} + +#[derive(Debug)] +enum ProposalFinishStatus { + Succeeded, + Aborted, + Failed, +} + +impl Drop for ProposalMetricsHandle { + fn drop(&mut self) { + match self.finish_status { + ProposalFinishStatus::Succeeded => PROPOSAL_SUCCEEDED.increment(1), + ProposalFinishStatus::Aborted => PROPOSAL_ABORTED.increment(1), + ProposalFinishStatus::Failed => PROPOSAL_FAILED.increment(1), + } + } +} diff --git a/crates/starknet_batcher/src/proposal_manager.rs b/crates/starknet_batcher/src/proposal_manager.rs deleted file mode 100644 index 5f1fc2407c9..00000000000 --- a/crates/starknet_batcher/src/proposal_manager.rs +++ /dev/null @@ -1,376 +0,0 @@ -use std::collections::{HashMap, HashSet}; -use std::sync::Arc; - -use async_trait::async_trait; -use indexmap::IndexMap; -use starknet_api::block::{BlockHashAndNumber, BlockNumber}; -use starknet_api::block_hash::state_diff_hash::calculate_state_diff_hash; -use starknet_api::core::{ContractAddress, Nonce}; -use starknet_api::executable_transaction::Transaction; -use starknet_api::state::ThinStateDiff; -use starknet_api::transaction::TransactionHash; -use starknet_batcher_types::batcher_types::{ProposalCommitment, ProposalId}; -use thiserror::Error; -use tokio::sync::Mutex; -use tracing::{debug, error, info, instrument, Instrument}; - -use crate::block_builder::{ - BlockBuilderError, - BlockBuilderExecutionParams, - BlockBuilderFactoryTrait, - BlockBuilderTrait, - BlockExecutionArtifacts, - BlockMetadata, -}; -use crate::transaction_provider::{ProposeTransactionProvider, ValidateTransactionProvider}; - -#[derive(Debug, Error)] -pub enum GenerateProposalError { - #[error( - "Received proposal generation request with id {new_proposal_id} while already generating \ - proposal with id {current_generating_proposal_id}." - )] - AlreadyGeneratingProposal { - current_generating_proposal_id: ProposalId, - new_proposal_id: ProposalId, - }, - #[error(transparent)] - BlockBuilderError(#[from] BlockBuilderError), - #[error("No active height to work on.")] - NoActiveHeight, - #[error("Proposal with id {proposal_id} already exists.")] - ProposalAlreadyExists { proposal_id: ProposalId }, -} - -#[derive(Clone, Debug, Error)] -pub enum GetProposalResultError { - #[error(transparent)] - BlockBuilderError(Arc), - #[error("Proposal with id {proposal_id} does not exist.")] - ProposalDoesNotExist { proposal_id: ProposalId }, - #[error("Proposal was aborted")] - Aborted, -} - -pub(crate) enum InternalProposalStatus { - Processing, - Finished, - Failed, - NotFound, -} - -#[async_trait] -pub trait ProposalManagerTrait: Send + Sync { - async fn propose_block( - &mut self, - height: BlockNumber, - proposal_id: ProposalId, - retrospective_block_hash: Option, - deadline: tokio::time::Instant, - tx_sender: tokio::sync::mpsc::UnboundedSender, - tx_provider: ProposeTransactionProvider, - ) -> Result<(), GenerateProposalError>; - - async fn validate_block( - &mut self, - height: BlockNumber, - proposal_id: ProposalId, - retrospective_block_hash: Option, - deadline: tokio::time::Instant, - tx_provider: ValidateTransactionProvider, - ) -> Result<(), GenerateProposalError>; - - async fn take_proposal_result( - &mut self, - proposal_id: ProposalId, - ) -> ProposalResult; - - async fn get_proposal_status(&self, proposal_id: ProposalId) -> InternalProposalStatus; - - async fn await_proposal_commitment( - &mut self, - proposal_id: ProposalId, - ) -> ProposalResult; - - async fn abort_proposal(&mut self, proposal_id: ProposalId); - - // Resets the proposal manager, aborting any active proposal. - async fn reset(&mut self); -} - -// Represents a spawned task of building new block proposal. -struct ProposalTask { - abort_signal_sender: tokio::sync::oneshot::Sender<()>, - join_handle: tokio::task::JoinHandle<()>, -} - -/// Main struct for handling block proposals. -/// Taking care of: -/// - Proposing new blocks. -/// - Validating incoming proposals. -/// - Commiting accepted proposals to the storage. -/// -/// Triggered by the consensus. -pub(crate) struct ProposalManager { - /// The block proposal that is currently being built, if any. - /// At any given time, there can be only one proposal being actively executed (either proposed - /// or validated). - active_proposal: Arc>>, - active_proposal_task: Option, - - // Use a factory object, to be able to mock BlockBuilder in tests. - block_builder_factory: Arc, - executed_proposals: Arc>>>, -} - -pub type ProposalResult = Result; - -#[derive(Debug, PartialEq)] -pub struct ProposalOutput { - pub state_diff: ThinStateDiff, - pub commitment: ProposalCommitment, - pub tx_hashes: HashSet, - pub nonces: HashMap, -} - -#[async_trait] -impl ProposalManagerTrait for ProposalManager { - /// Starts a new block proposal generation task for the given proposal_id and height with - /// transactions from the mempool. - /// Requires tx_sender for sending the generated transactions to the caller. - #[instrument(skip(self, tx_sender, tx_provider), err, fields(self.active_height))] - async fn propose_block( - &mut self, - height: BlockNumber, - proposal_id: ProposalId, - retrospective_block_hash: Option, - deadline: tokio::time::Instant, - tx_sender: tokio::sync::mpsc::UnboundedSender, - tx_provider: ProposeTransactionProvider, - ) -> Result<(), GenerateProposalError> { - self.set_active_proposal(proposal_id).await?; - - info!("Starting generation of a new proposal with id {}.", proposal_id); - - // Create the block builder, and a channel to allow aborting the block building task. - let (abort_signal_sender, abort_signal_receiver) = tokio::sync::oneshot::channel(); - - let block_builder = self.block_builder_factory.create_block_builder( - BlockMetadata { height, retrospective_block_hash }, - BlockBuilderExecutionParams { deadline, fail_on_err: false }, - Box::new(tx_provider), - Some(tx_sender.clone()), - abort_signal_receiver, - )?; - - let join_handle = self.spawn_build_block_task(proposal_id, block_builder).await; - self.active_proposal_task = Some(ProposalTask { abort_signal_sender, join_handle }); - - Ok(()) - } - - /// Starts validation of a block proposal for the given proposal_id and height with - /// transactions from tx_receiver channel. - #[instrument(skip(self, tx_provider), err, fields(self.active_height))] - async fn validate_block( - &mut self, - height: BlockNumber, - proposal_id: ProposalId, - retrospective_block_hash: Option, - deadline: tokio::time::Instant, - tx_provider: ValidateTransactionProvider, - ) -> Result<(), GenerateProposalError> { - self.set_active_proposal(proposal_id).await?; - - info!("Starting validation of proposal with id {}.", proposal_id); - - // Create the block builder, and a channel to allow aborting the block building task. - let (abort_signal_sender, abort_signal_receiver) = tokio::sync::oneshot::channel(); - - let block_builder = self.block_builder_factory.create_block_builder( - BlockMetadata { height, retrospective_block_hash }, - BlockBuilderExecutionParams { deadline, fail_on_err: true }, - Box::new(tx_provider), - None, - abort_signal_receiver, - )?; - - let join_handle = self.spawn_build_block_task(proposal_id, block_builder).await; - self.active_proposal_task = Some(ProposalTask { abort_signal_sender, join_handle }); - - Ok(()) - } - - async fn take_proposal_result( - &mut self, - proposal_id: ProposalId, - ) -> ProposalResult { - self.executed_proposals - .lock() - .await - .remove(&proposal_id) - .ok_or(GetProposalResultError::ProposalDoesNotExist { proposal_id })? - } - - // Returns None if the proposal does not exist, otherwise, returns the status of the proposal. - async fn get_proposal_status(&self, proposal_id: ProposalId) -> InternalProposalStatus { - match self.executed_proposals.lock().await.get(&proposal_id) { - Some(Ok(_)) => InternalProposalStatus::Finished, - Some(Err(_)) => InternalProposalStatus::Failed, - None => { - if self.active_proposal.lock().await.as_ref() == Some(&proposal_id) { - InternalProposalStatus::Processing - } else { - InternalProposalStatus::NotFound - } - } - } - } - - async fn await_proposal_commitment( - &mut self, - proposal_id: ProposalId, - ) -> ProposalResult { - if *self.active_proposal.lock().await == Some(proposal_id) { - self.await_active_proposal().await; - } - let proposals = self.executed_proposals.lock().await; - let output = proposals - .get(&proposal_id) - .ok_or(GetProposalResultError::ProposalDoesNotExist { proposal_id })?; - match output { - Ok(output) => Ok(output.commitment), - Err(e) => Err(e.clone()), - } - } - - // Aborts the proposal with the given ID, if active. - // Should be used in validate flow, if the consensus decides to abort the proposal. - async fn abort_proposal(&mut self, proposal_id: ProposalId) { - if *self.active_proposal.lock().await == Some(proposal_id) { - self.abort_active_proposal().await; - self.executed_proposals - .lock() - .await - .insert(proposal_id, Err(GetProposalResultError::Aborted)); - } - } - - async fn reset(&mut self) { - self.abort_active_proposal().await; - self.executed_proposals.lock().await.clear(); - } -} - -impl ProposalManager { - pub fn new(block_builder_factory: Arc) -> Self { - Self { - active_proposal: Arc::new(Mutex::new(None)), - block_builder_factory, - active_proposal_task: None, - executed_proposals: Arc::new(Mutex::new(HashMap::new())), - } - } - - async fn spawn_build_block_task( - &mut self, - proposal_id: ProposalId, - mut block_builder: Box, - ) -> tokio::task::JoinHandle<()> { - let active_proposal = self.active_proposal.clone(); - let executed_proposals = self.executed_proposals.clone(); - - tokio::spawn( - async move { - let result = block_builder - .build_block() - .await - .map(ProposalOutput::from) - .map_err(|e| GetProposalResultError::BlockBuilderError(Arc::new(e))); - - // The proposal is done, clear the active proposal. - // Keep the proposal result only if it is the same as the active proposal. - // The active proposal might have changed if this proposal was aborted. - let mut active_proposal = active_proposal.lock().await; - if *active_proposal == Some(proposal_id) { - active_proposal.take(); - executed_proposals.lock().await.insert(proposal_id, result); - } - } - .in_current_span(), - ) - } - - // Sets a new active proposal task. - // Fails if either there is no active height, there is another proposal being generated, or a - // proposal with the same ID already exists. - async fn set_active_proposal( - &mut self, - proposal_id: ProposalId, - ) -> Result<(), GenerateProposalError> { - if self.executed_proposals.lock().await.contains_key(&proposal_id) { - return Err(GenerateProposalError::ProposalAlreadyExists { proposal_id }); - } - - let mut active_proposal = self.active_proposal.lock().await; - if let Some(current_generating_proposal_id) = *active_proposal { - return Err(GenerateProposalError::AlreadyGeneratingProposal { - current_generating_proposal_id, - new_proposal_id: proposal_id, - }); - } - - debug!("Set proposal {} as the one being generated.", proposal_id); - *active_proposal = Some(proposal_id); - Ok(()) - } - - // Awaits the active proposal. - // Returns true if there was an active proposal, and false otherwise. - pub async fn await_active_proposal(&mut self) -> bool { - if let Some(proposal_task) = self.active_proposal_task.take() { - proposal_task.join_handle.await.ok(); - return true; - } - false - } - - // Ends the current active proposal. - // This call is non-blocking. - async fn abort_active_proposal(&mut self) { - self.active_proposal.lock().await.take(); - if let Some(proposal_task) = self.active_proposal_task.take() { - proposal_task.abort_signal_sender.send(()).ok(); - } - } -} - -impl From for ProposalOutput { - fn from(artifacts: BlockExecutionArtifacts) -> Self { - let commitment_state_diff = artifacts.commitment_state_diff; - let nonces = HashMap::from_iter( - commitment_state_diff - .address_to_nonce - .iter() - .map(|(address, nonce)| (*address, *nonce)), - ); - - // TODO: Get these from the transactions. - let deployed_contracts = IndexMap::new(); - let declared_classes = IndexMap::new(); - let state_diff = ThinStateDiff { - deployed_contracts, - storage_diffs: commitment_state_diff.storage_updates, - declared_classes, - nonces: commitment_state_diff.address_to_nonce, - // TODO: Remove this when the structure of storage diffs changes. - deprecated_declared_classes: Vec::new(), - replaced_classes: IndexMap::new(), - }; - let commitment = - ProposalCommitment { state_diff_commitment: calculate_state_diff_hash(&state_diff) }; - let tx_hashes = HashSet::from_iter(artifacts.execution_infos.keys().copied()); - - Self { state_diff, commitment, tx_hashes, nonces } - } -} diff --git a/crates/starknet_batcher/src/proposal_manager_test.rs b/crates/starknet_batcher/src/proposal_manager_test.rs deleted file mode 100644 index b3e52da2e33..00000000000 --- a/crates/starknet_batcher/src/proposal_manager_test.rs +++ /dev/null @@ -1,315 +0,0 @@ -use std::sync::Arc; - -use assert_matches::assert_matches; -use rstest::{fixture, rstest}; -use starknet_api::block::BlockNumber; -use starknet_api::executable_transaction::Transaction; -use starknet_batcher_types::batcher_types::ProposalId; -use starknet_mempool_types::communication::MockMempoolClient; - -use crate::block_builder::{ - BlockBuilderResult, - BlockBuilderTrait, - BlockExecutionArtifacts, - MockBlockBuilderFactoryTrait, - MockBlockBuilderTrait, -}; -use crate::proposal_manager::{ - GenerateProposalError, - GetProposalResultError, - ProposalManager, - ProposalManagerTrait, - ProposalOutput, -}; -use crate::transaction_provider::{ - MockL1ProviderClient, - ProposeTransactionProvider, - ValidateTransactionProvider, -}; - -const INITIAL_HEIGHT: BlockNumber = BlockNumber(3); -const BLOCK_GENERATION_TIMEOUT: tokio::time::Duration = tokio::time::Duration::from_secs(1); -const MAX_L1_HANDLER_TXS_PER_BLOCK_PROPOSAL: usize = 3; -const INPUT_CHANNEL_SIZE: usize = 30; - -#[fixture] -fn output_streaming() -> ( - tokio::sync::mpsc::UnboundedSender, - tokio::sync::mpsc::UnboundedReceiver, -) { - tokio::sync::mpsc::unbounded_channel() -} - -struct MockDependencies { - block_builder_factory: MockBlockBuilderFactoryTrait, -} - -impl MockDependencies { - fn expect_build_block(&mut self, times: usize) { - let simulate_build_block = || -> BlockBuilderResult> { - let mut mock_block_builder = MockBlockBuilderTrait::new(); - mock_block_builder - .expect_build_block() - .times(1) - .return_once(move || Ok(BlockExecutionArtifacts::create_for_testing())); - Ok(Box::new(mock_block_builder)) - }; - - self.block_builder_factory - .expect_create_block_builder() - .times(times) - .returning(move |_, _, _, _, _| simulate_build_block()); - } - - // This function simulates a long build block operation. This is required for a test that - // tries to run other operations while a block is being built. - fn expect_long_build_block(&mut self, times: usize) { - let simulate_long_build_block = || -> BlockBuilderResult> { - let mut mock_block_builder = MockBlockBuilderTrait::new(); - mock_block_builder.expect_build_block().times(1).return_once(move || { - std::thread::sleep(BLOCK_GENERATION_TIMEOUT * 10); - Ok(BlockExecutionArtifacts::create_for_testing()) - }); - Ok(Box::new(mock_block_builder)) - }; - - self.block_builder_factory - .expect_create_block_builder() - .times(times) - .returning(move |_, _, _, _, _| simulate_long_build_block()); - } -} - -#[fixture] -fn mock_dependencies() -> MockDependencies { - MockDependencies { block_builder_factory: MockBlockBuilderFactoryTrait::new() } -} - -#[fixture] -fn propose_tx_provider() -> ProposeTransactionProvider { - ProposeTransactionProvider::new( - Arc::new(MockMempoolClient::new()), - Arc::new(MockL1ProviderClient::new()), - MAX_L1_HANDLER_TXS_PER_BLOCK_PROPOSAL, - ) -} - -#[fixture] -fn validate_tx_provider() -> ValidateTransactionProvider { - ValidateTransactionProvider { - tx_receiver: tokio::sync::mpsc::channel(INPUT_CHANNEL_SIZE).1, - l1_provider_client: Arc::new(MockL1ProviderClient::new()), - } -} - -fn proposal_manager(mock_dependencies: MockDependencies) -> ProposalManager { - ProposalManager::new(Arc::new(mock_dependencies.block_builder_factory)) -} - -fn proposal_deadline() -> tokio::time::Instant { - tokio::time::Instant::now() + BLOCK_GENERATION_TIMEOUT -} - -async fn propose_block_non_blocking( - proposal_manager: &mut ProposalManager, - tx_provider: ProposeTransactionProvider, - proposal_id: ProposalId, -) { - let (output_sender, _receiver) = output_streaming(); - proposal_manager - .propose_block( - INITIAL_HEIGHT, - proposal_id, - None, - proposal_deadline(), - output_sender, - tx_provider, - ) - .await - .unwrap(); -} - -async fn propose_block( - proposal_manager: &mut ProposalManager, - tx_provider: ProposeTransactionProvider, - proposal_id: ProposalId, -) { - propose_block_non_blocking(proposal_manager, tx_provider, proposal_id).await; - assert!(proposal_manager.await_active_proposal().await); -} - -async fn validate_block( - proposal_manager: &mut ProposalManager, - tx_provider: ValidateTransactionProvider, - proposal_id: ProposalId, -) { - proposal_manager - .validate_block(INITIAL_HEIGHT, proposal_id, None, proposal_deadline(), tx_provider) - .await - .unwrap(); - - assert!(proposal_manager.await_active_proposal().await); -} - -#[rstest] -#[tokio::test] -async fn propose_block_success( - mut mock_dependencies: MockDependencies, - propose_tx_provider: ProposeTransactionProvider, -) { - mock_dependencies.expect_build_block(1); - let mut proposal_manager = proposal_manager(mock_dependencies); - - propose_block(&mut proposal_manager, propose_tx_provider, ProposalId(0)).await; - proposal_manager.take_proposal_result(ProposalId(0)).await.unwrap(); -} - -#[rstest] -#[tokio::test] -async fn validate_block_success( - mut mock_dependencies: MockDependencies, - validate_tx_provider: ValidateTransactionProvider, -) { - mock_dependencies.expect_build_block(1); - let mut proposal_manager = proposal_manager(mock_dependencies); - - validate_block(&mut proposal_manager, validate_tx_provider, ProposalId(0)).await; - proposal_manager.take_proposal_result(ProposalId(0)).await.unwrap(); -} - -#[rstest] -#[tokio::test] -async fn consecutive_proposal_generations_success( - mut mock_dependencies: MockDependencies, - propose_tx_provider: ProposeTransactionProvider, -) { - mock_dependencies.expect_build_block(4); - let mut proposal_manager = proposal_manager(mock_dependencies); - - // Build and validate multiple proposals consecutively (awaiting on them to - // make sure they finished successfully). - propose_block(&mut proposal_manager, propose_tx_provider.clone(), ProposalId(0)).await; - validate_block(&mut proposal_manager, validate_tx_provider(), ProposalId(1)).await; - propose_block(&mut proposal_manager, propose_tx_provider, ProposalId(2)).await; - validate_block(&mut proposal_manager, validate_tx_provider(), ProposalId(3)).await; -} - -// This test checks that trying to generate a proposal while another one is being generated will -// fail. First the test will generate a new proposal that takes a very long time, and during -// that time it will send another build proposal request. -#[rstest] -#[tokio::test] -async fn multiple_proposals_generation_fail( - mut mock_dependencies: MockDependencies, - propose_tx_provider: ProposeTransactionProvider, -) { - // Generate a block builder with a very long build block operation. - mock_dependencies.expect_long_build_block(1); - let mut proposal_manager = proposal_manager(mock_dependencies); - - // Build a proposal that will take a very long time to finish. - let (output_sender_0, _rec_0) = output_streaming(); - proposal_manager - .propose_block( - INITIAL_HEIGHT, - ProposalId(0), - None, - proposal_deadline(), - output_sender_0, - propose_tx_provider.clone(), - ) - .await - .unwrap(); - - // Try to generate another proposal while the first one is still being generated. - let (output_sender_1, _rec_1) = output_streaming(); - let another_generate_request = proposal_manager - .propose_block( - INITIAL_HEIGHT, - ProposalId(1), - None, - proposal_deadline(), - output_sender_1, - propose_tx_provider, - ) - .await; - assert_matches!( - another_generate_request, - Err(GenerateProposalError::AlreadyGeneratingProposal { - current_generating_proposal_id, - new_proposal_id - }) if current_generating_proposal_id == ProposalId(0) && new_proposal_id == ProposalId(1) - ); -} - -#[rstest] -#[tokio::test] -async fn take_proposal_result_no_active_proposal( - mut mock_dependencies: MockDependencies, - propose_tx_provider: ProposeTransactionProvider, -) { - mock_dependencies.expect_build_block(1); - let mut proposal_manager = proposal_manager(mock_dependencies); - - propose_block(&mut proposal_manager, propose_tx_provider, ProposalId(0)).await; - - let expected_proposal_output = - ProposalOutput::from(BlockExecutionArtifacts::create_for_testing()); - assert_eq!( - proposal_manager.take_proposal_result(ProposalId(0)).await.unwrap(), - expected_proposal_output - ); - assert_matches!( - proposal_manager.take_proposal_result(ProposalId(0)).await, - Err(GetProposalResultError::ProposalDoesNotExist { .. }) - ); -} - -#[rstest] -#[tokio::test] -async fn abort_active_proposal( - mut mock_dependencies: MockDependencies, - propose_tx_provider: ProposeTransactionProvider, -) { - mock_dependencies.expect_long_build_block(1); - let mut proposal_manager = proposal_manager(mock_dependencies); - - propose_block_non_blocking(&mut proposal_manager, propose_tx_provider, ProposalId(0)).await; - - proposal_manager.abort_proposal(ProposalId(0)).await; - - assert_matches!( - proposal_manager.take_proposal_result(ProposalId(0)).await, - Err(GetProposalResultError::Aborted) - ); - - // Make sure there is no active proposal. - assert!(!proposal_manager.await_active_proposal().await); -} - -#[rstest] -#[tokio::test] -async fn reset( - mut mock_dependencies: MockDependencies, - propose_tx_provider: ProposeTransactionProvider, -) { - mock_dependencies.expect_build_block(1); - mock_dependencies.expect_long_build_block(1); - let mut proposal_manager = proposal_manager(mock_dependencies); - - // Create 2 proposals, one will remain active. - propose_block(&mut proposal_manager, propose_tx_provider.clone(), ProposalId(0)).await; - propose_block_non_blocking(&mut proposal_manager, propose_tx_provider.clone(), ProposalId(1)) - .await; - - proposal_manager.reset().await; - - // Make sure executed proposals are deleted. - assert_matches!( - proposal_manager.take_proposal_result(ProposalId(0)).await, - Err(GetProposalResultError::ProposalDoesNotExist { .. }) - ); - - // Make sure there is no active proposal. - assert!(!proposal_manager.await_active_proposal().await); -} diff --git a/crates/starknet_batcher/src/test_utils.rs b/crates/starknet_batcher/src/test_utils.rs index e6b8183638f..221871a9677 100644 --- a/crates/starknet_batcher/src/test_utils.rs +++ b/crates/starknet_batcher/src/test_utils.rs @@ -1,34 +1,147 @@ use std::ops::Range; -use blockifier::blockifier::transaction_executor::VisitedSegmentsMapping; +use async_trait::async_trait; use blockifier::bouncer::BouncerWeights; +use blockifier::fee::receipt::TransactionReceipt; use blockifier::state::cached_state::CommitmentStateDiff; +use blockifier::transaction::objects::TransactionExecutionInfo; use indexmap::IndexMap; -use starknet_api::executable_transaction::{AccountTransaction, Transaction}; -use starknet_api::felt; -use starknet_api::test_utils::invoke::{executable_invoke_tx, InvokeTxArgs}; +use starknet_api::consensus_transaction::InternalConsensusTransaction; +use starknet_api::execution_resources::GasAmount; +use starknet_api::test_utils::invoke::{internal_invoke_tx, InvokeTxArgs}; +use starknet_api::test_utils::l1_handler::{executable_l1_handler_tx, L1HandlerTxArgs}; +use starknet_api::transaction::fields::Fee; use starknet_api::transaction::TransactionHash; +use starknet_api::{class_hash, contract_address, nonce, tx_hash}; +use tokio::sync::mpsc::UnboundedSender; -use crate::block_builder::BlockExecutionArtifacts; +use crate::block_builder::{ + BlockBuilderResult, + BlockBuilderTrait, + BlockExecutionArtifacts, + BlockTransactionExecutionData, +}; +use crate::transaction_provider::{NextTxs, TransactionProvider}; -pub fn test_txs(tx_hash_range: Range) -> Vec { +pub const EXECUTION_INFO_LEN: usize = 10; + +// A fake block builder for validate flow, that fetches transactions from the transaction provider +// until it is exhausted. +// This ensures the block builder (and specifically the tx_provider) is not dropped before all +// transactions are processed. Otherwise, the batcher would fail during tests when attempting to +// send transactions to it. +pub(crate) struct FakeValidateBlockBuilder { + pub tx_provider: Box, + pub build_block_result: Option>, +} + +#[async_trait] +impl BlockBuilderTrait for FakeValidateBlockBuilder { + async fn build_block(&mut self) -> BlockBuilderResult { + // build_block should be called only once, so we can safely take the result. + let build_block_result = self.build_block_result.take().unwrap(); + + if build_block_result.is_ok() { + while self.tx_provider.get_txs(1).await.is_ok_and(|v| v != NextTxs::End) { + tokio::task::yield_now().await; + } + } + build_block_result + } +} + +// A fake block builder for propose flow, that sends the given transactions to the output content +// sender. +pub(crate) struct FakeProposeBlockBuilder { + pub output_content_sender: UnboundedSender, + pub output_txs: Vec, + pub build_block_result: Option>, +} + +#[async_trait] +impl BlockBuilderTrait for FakeProposeBlockBuilder { + async fn build_block(&mut self) -> BlockBuilderResult { + for tx in &self.output_txs { + self.output_content_sender.send(tx.clone()).unwrap(); + } + + // build_block should be called only once, so we can safely take the result. + self.build_block_result.take().unwrap() + } +} + +pub fn test_txs(tx_hash_range: Range) -> Vec { tx_hash_range .map(|i| { - Transaction::Account(AccountTransaction::Invoke(executable_invoke_tx(InvokeTxArgs { - tx_hash: TransactionHash(felt!(u128::try_from(i).unwrap())), + InternalConsensusTransaction::RpcTransaction(internal_invoke_tx(InvokeTxArgs { + tx_hash: tx_hash!(i), ..Default::default() - }))) + })) }) .collect() } +pub fn test_l1_handler_txs(tx_hash_range: Range) -> Vec { + tx_hash_range + .map(|i| { + InternalConsensusTransaction::L1Handler(executable_l1_handler_tx(L1HandlerTxArgs { + tx_hash: tx_hash!(i), + ..Default::default() + })) + }) + .collect() +} + +// Create `execution_infos` with an indexed field to enable verification of the order. +fn indexed_execution_infos() -> IndexMap { + test_txs(0..EXECUTION_INFO_LEN) + .iter() + .enumerate() + .map(|(i, tx)| { + ( + tx.tx_hash(), + TransactionExecutionInfo { + receipt: TransactionReceipt { + fee: Fee(i.try_into().unwrap()), + ..Default::default() + }, + ..Default::default() + }, + ) + }) + .collect() +} + +// Verify that `execution_infos` was initiated with an indexed fields. +pub fn verify_indexed_execution_infos( + execution_infos: &IndexMap, +) { + for (i, execution_info) in execution_infos.iter().enumerate() { + assert_eq!(execution_info.1.receipt.fee, Fee(i.try_into().unwrap())); + } +} + impl BlockExecutionArtifacts { pub fn create_for_testing() -> Self { + // Use a non-empty commitment_state_diff to get a valuable test verification of the result. Self { - execution_infos: IndexMap::default(), - commitment_state_diff: CommitmentStateDiff::default(), - visited_segments_mapping: VisitedSegmentsMapping::default(), + execution_data: BlockTransactionExecutionData { + execution_infos: indexed_execution_infos(), + rejected_tx_hashes: test_txs(10..15).iter().map(|tx| tx.tx_hash()).collect(), + accepted_l1_handler_tx_hashes: Default::default(), + }, + commitment_state_diff: CommitmentStateDiff { + address_to_class_hash: IndexMap::from_iter([( + contract_address!("0x7"), + class_hash!("0x11111111"), + )]), + storage_updates: IndexMap::new(), + class_hash_to_compiled_class_hash: IndexMap::new(), + address_to_nonce: IndexMap::from_iter([(contract_address!("0x7"), nonce!(1_u64))]), + }, + compressed_state_diff: Default::default(), bouncer_weights: BouncerWeights::empty(), + l2_gas_used: GasAmount::default(), } } } diff --git a/crates/starknet_batcher/src/transaction_executor.rs b/crates/starknet_batcher/src/transaction_executor.rs index a781f81bd1c..870e67682de 100644 --- a/crates/starknet_batcher/src/transaction_executor.rs +++ b/crates/starknet_batcher/src/transaction_executor.rs @@ -1,10 +1,8 @@ use blockifier::blockifier::transaction_executor::{ + BlockExecutionSummary, TransactionExecutor, TransactionExecutorResult, - VisitedSegmentsMapping, }; -use blockifier::bouncer::BouncerWeights; -use blockifier::state::cached_state::CommitmentStateDiff; use blockifier::state::state_api::StateReader; use blockifier::transaction::objects::TransactionExecutionInfo; use blockifier::transaction::transaction_execution::Transaction as BlockifierTransaction; @@ -17,9 +15,7 @@ pub trait TransactionExecutorTrait: Send { &mut self, txs: &[BlockifierTransaction], ) -> Vec>; - fn close_block( - &mut self, - ) -> TransactionExecutorResult<(CommitmentStateDiff, VisitedSegmentsMapping, BouncerWeights)>; + fn close_block(&mut self) -> TransactionExecutorResult; } impl TransactionExecutorTrait for TransactionExecutor { @@ -29,13 +25,13 @@ impl TransactionExecutorTrait for TransactionExecu txs: &[BlockifierTransaction], ) -> Vec> { self.execute_txs(txs) + .into_iter() + .map(|res| res.map(|(tx_execution_info, _state_diff)| tx_execution_info)) + .collect() } /// Finalizes the block creation and returns the commitment state diff, visited /// segments mapping and bouncer. - fn close_block( - &mut self, - ) -> TransactionExecutorResult<(CommitmentStateDiff, VisitedSegmentsMapping, BouncerWeights)> - { + fn close_block(&mut self) -> TransactionExecutorResult { self.finalize() } } diff --git a/crates/starknet_batcher/src/transaction_provider.rs b/crates/starknet_batcher/src/transaction_provider.rs index 50324a890b1..da35ef10169 100644 --- a/crates/starknet_batcher/src/transaction_provider.rs +++ b/crates/starknet_batcher/src/transaction_provider.rs @@ -1,34 +1,50 @@ use std::cmp::min; -use std::sync::Arc; use std::vec; use async_trait::async_trait; #[cfg(test)] use mockall::automock; -use starknet_api::executable_transaction::{L1HandlerTransaction, Transaction}; +use starknet_api::block::BlockNumber; +use starknet_api::consensus_transaction::InternalConsensusTransaction; use starknet_api::transaction::TransactionHash; +use starknet_l1_provider_types::errors::L1ProviderClientError; +use starknet_l1_provider_types::{ + InvalidValidationStatus as L1InvalidValidationStatus, + SharedL1ProviderClient, + ValidationStatus as L1ValidationStatus, +}; use starknet_mempool_types::communication::{MempoolClientError, SharedMempoolClient}; use thiserror::Error; -use tracing::warn; + +type TransactionProviderResult = Result; #[derive(Clone, Debug, Error)] pub enum TransactionProviderError { #[error(transparent)] MempoolError(#[from] MempoolClientError), - #[error("L1Handler transaction validation failed for tx with hash {0}.")] - L1HandlerTransactionValidationFailed(TransactionHash), + #[error( + "L1Handler transaction validation failed for tx with hash {} status {:?}.", + tx_hash.0.to_hex_string(), + validation_status + )] + L1HandlerTransactionValidationFailed { + tx_hash: TransactionHash, + validation_status: L1InvalidValidationStatus, + }, + #[error(transparent)] + L1ProviderError(#[from] L1ProviderClientError), } #[derive(Debug, PartialEq)] pub enum NextTxs { - Txs(Vec), + Txs(Vec), End, } #[cfg_attr(test, automock)] #[async_trait] -pub trait TransactionProvider: Send + Sync { - async fn get_txs(&mut self, n_txs: usize) -> Result; +pub trait TransactionProvider: Send { + async fn get_txs(&mut self, n_txs: usize) -> TransactionProviderResult; } #[derive(Clone)] @@ -36,6 +52,7 @@ pub struct ProposeTransactionProvider { pub mempool_client: SharedMempoolClient, pub l1_provider_client: SharedL1ProviderClient, pub max_l1_handler_txs_per_block: usize, + pub height: BlockNumber, phase: TxProviderPhase, n_l1handler_txs_so_far: usize, } @@ -52,42 +69,54 @@ impl ProposeTransactionProvider { mempool_client: SharedMempoolClient, l1_provider_client: SharedL1ProviderClient, max_l1_handler_txs_per_block: usize, + height: BlockNumber, ) -> Self { Self { mempool_client, l1_provider_client, max_l1_handler_txs_per_block, + height, phase: TxProviderPhase::L1, n_l1handler_txs_so_far: 0, } } - fn get_l1_handler_txs(&mut self, n_txs: usize) -> Vec { - self.l1_provider_client.get_txs(n_txs).into_iter().map(Transaction::L1Handler).collect() + async fn get_l1_handler_txs( + &mut self, + n_txs: usize, + ) -> TransactionProviderResult> { + Ok(self + .l1_provider_client + .get_txs(n_txs, self.height) + .await? + .into_iter() + .map(InternalConsensusTransaction::L1Handler) + .collect()) } async fn get_mempool_txs( &mut self, n_txs: usize, - ) -> Result, TransactionProviderError> { + ) -> TransactionProviderResult> { Ok(self .mempool_client .get_txs(n_txs) .await? .into_iter() - .map(Transaction::Account) + .map(InternalConsensusTransaction::RpcTransaction) .collect()) } } #[async_trait] impl TransactionProvider for ProposeTransactionProvider { - async fn get_txs(&mut self, n_txs: usize) -> Result { + async fn get_txs(&mut self, n_txs: usize) -> TransactionProviderResult { + assert!(n_txs > 0, "The number of transactions requested must be greater than zero."); let mut txs = vec![]; if self.phase == TxProviderPhase::L1 { let n_l1handler_txs_to_get = min(self.max_l1_handler_txs_per_block - self.n_l1handler_txs_so_far, n_txs); - let mut l1handler_txs = self.get_l1_handler_txs(n_l1handler_txs_to_get); + let mut l1handler_txs = self.get_l1_handler_txs(n_l1handler_txs_to_get).await?; self.n_l1handler_txs_so_far += l1handler_txs.len(); // Determine whether we need to switch to mempool phase. @@ -111,13 +140,15 @@ impl TransactionProvider for ProposeTransactionProvider { } pub struct ValidateTransactionProvider { - pub tx_receiver: tokio::sync::mpsc::Receiver, + pub tx_receiver: tokio::sync::mpsc::Receiver, pub l1_provider_client: SharedL1ProviderClient, + pub height: BlockNumber, } #[async_trait] impl TransactionProvider for ValidateTransactionProvider { - async fn get_txs(&mut self, n_txs: usize) -> Result { + async fn get_txs(&mut self, n_txs: usize) -> TransactionProviderResult { + assert!(n_txs > 0, "The number of transactions requested must be greater than zero."); let mut buffer = Vec::with_capacity(n_txs); self.tx_receiver.recv_many(&mut buffer, n_txs).await; // If the buffer is empty, it means that the stream was dropped, otherwise it would have @@ -126,39 +157,17 @@ impl TransactionProvider for ValidateTransactionProvider { return Ok(NextTxs::End); } for tx in &buffer { - if let Transaction::L1Handler(tx) = tx { - if !self.l1_provider_client.validate(tx) { - return Err(TransactionProviderError::L1HandlerTransactionValidationFailed( - tx.tx_hash, - )); + if let InternalConsensusTransaction::L1Handler(tx) = tx { + let l1_validation_status = + self.l1_provider_client.validate(tx.tx_hash, self.height).await?; + if let L1ValidationStatus::Invalid(validation_status) = l1_validation_status { + return Err(TransactionProviderError::L1HandlerTransactionValidationFailed { + tx_hash: tx.tx_hash, + validation_status, + }); } } } Ok(NextTxs::Txs(buffer)) } } - -// TODO: Remove L1Provider code when the communication module of l1_provider is added. -#[cfg_attr(test, automock)] -#[async_trait] -pub trait L1ProviderClient: Send + Sync { - fn get_txs(&self, n_txs: usize) -> Vec; - fn validate(&self, tx: &L1HandlerTransaction) -> bool; -} - -pub type SharedL1ProviderClient = Arc; - -pub struct DummyL1ProviderClient; - -#[async_trait] -impl L1ProviderClient for DummyL1ProviderClient { - fn get_txs(&self, _n_txs: usize) -> Vec { - warn!("Dummy L1 provider client is used, no L1 transactions are provided."); - vec![] - } - - fn validate(&self, _tx: &L1HandlerTransaction) -> bool { - warn!("Dummy L1 provider client is used, tx is not really validated."); - true - } -} diff --git a/crates/starknet_batcher/src/transaction_provider_test.rs b/crates/starknet_batcher/src/transaction_provider_test.rs index 0e806a72484..146d7495168 100644 --- a/crates/starknet_batcher/src/transaction_provider_test.rs +++ b/crates/starknet_batcher/src/transaction_provider_test.rs @@ -3,14 +3,19 @@ use std::sync::Arc; use assert_matches::assert_matches; use mockall::predicate::eq; use rstest::{fixture, rstest}; -use starknet_api::executable_transaction::{AccountTransaction, L1HandlerTransaction, Transaction}; -use starknet_api::test_utils::invoke::{executable_invoke_tx, InvokeTxArgs}; -use starknet_api::transaction::TransactionHash; +use starknet_api::block::BlockNumber; +use starknet_api::consensus_transaction::InternalConsensusTransaction; +use starknet_api::executable_transaction::L1HandlerTransaction; +use starknet_api::test_utils::invoke::{internal_invoke_tx, InvokeTxArgs}; +use starknet_api::tx_hash; +use starknet_l1_provider_types::{ + InvalidValidationStatus, + MockL1ProviderClient, + ValidationStatus as L1ValidationStatus, +}; use starknet_mempool_types::communication::MockMempoolClient; -use starknet_types_core::felt::Felt; use crate::transaction_provider::{ - MockL1ProviderClient, NextTxs, ProposeTransactionProvider, TransactionProvider, @@ -19,41 +24,39 @@ use crate::transaction_provider::{ }; const MAX_L1_HANDLER_TXS_PER_BLOCK: usize = 15; +const HEIGHT: BlockNumber = BlockNumber(1); const MAX_TXS_PER_FETCH: usize = 10; const VALIDATE_BUFFER_SIZE: usize = 30; struct MockDependencies { mempool_client: MockMempoolClient, l1_provider_client: MockL1ProviderClient, - tx_sender: tokio::sync::mpsc::Sender, - tx_receiver: tokio::sync::mpsc::Receiver, + tx_sender: tokio::sync::mpsc::Sender, + tx_receiver: tokio::sync::mpsc::Receiver, } impl MockDependencies { fn expect_get_l1_handler_txs(&mut self, n_to_request: usize, n_to_return: usize) { self.l1_provider_client .expect_get_txs() - .with(eq(n_to_request)) - .returning(move |_| vec![L1HandlerTransaction::default(); n_to_return]); + .with(eq(n_to_request), eq(HEIGHT)) + .returning(move |_, _| Ok(vec![L1HandlerTransaction::default(); n_to_return])); } fn expect_get_mempool_txs(&mut self, n_to_request: usize) { self.mempool_client.expect_get_txs().with(eq(n_to_request)).returning(move |n_requested| { - Ok(vec![ - AccountTransaction::Invoke(executable_invoke_tx(InvokeTxArgs::default())); - n_requested - ]) + Ok(vec![internal_invoke_tx(InvokeTxArgs::default()); n_requested]) }); } - fn expect_validate_l1handler(&mut self, tx: L1HandlerTransaction, result: bool) { + fn expect_validate_l1handler(&mut self, tx: L1HandlerTransaction, result: L1ValidationStatus) { self.l1_provider_client .expect_validate() - .withf(move |tx_arg| tx_arg == &tx) - .returning(move |_| result); + .withf(move |tx_arg, height| tx_arg == &tx.tx_hash && *height == HEIGHT) + .returning(move |_, _| Ok(result)); } - async fn simulate_input_txs(&mut self, txs: Vec) { + async fn simulate_input_txs(&mut self, txs: Vec) { for tx in txs { self.tx_sender.send(tx).await.unwrap(); } @@ -64,6 +67,7 @@ impl MockDependencies { Arc::new(self.mempool_client), Arc::new(self.l1_provider_client), MAX_L1_HANDLER_TXS_PER_BLOCK, + HEIGHT, ) } @@ -71,13 +75,17 @@ impl MockDependencies { ValidateTransactionProvider { tx_receiver: self.tx_receiver, l1_provider_client: Arc::new(self.l1_provider_client), + height: HEIGHT, } } } #[fixture] fn mock_dependencies( - tx_channel: (tokio::sync::mpsc::Sender, tokio::sync::mpsc::Receiver), + tx_channel: ( + tokio::sync::mpsc::Sender, + tokio::sync::mpsc::Receiver, + ), ) -> MockDependencies { let (tx_sender, tx_receiver) = tx_channel; MockDependencies { @@ -89,13 +97,15 @@ fn mock_dependencies( } #[fixture] -fn tx_channel() -> (tokio::sync::mpsc::Sender, tokio::sync::mpsc::Receiver) -{ +fn tx_channel() -> ( + tokio::sync::mpsc::Sender, + tokio::sync::mpsc::Receiver, +) { tokio::sync::mpsc::channel(VALIDATE_BUFFER_SIZE) } fn test_l1handler_tx() -> L1HandlerTransaction { - L1HandlerTransaction { tx_hash: TransactionHash(Felt::ONE), ..Default::default() } + L1HandlerTransaction { tx_hash: tx_hash!(1), ..Default::default() } } #[rstest] @@ -116,16 +126,24 @@ async fn fill_max_l1_handler(mut mock_dependencies: MockDependencies) { let txs = tx_provider.get_txs(MAX_TXS_PER_FETCH).await.unwrap(); let data = assert_matches!(txs, NextTxs::Txs(txs) if txs.len() == MAX_TXS_PER_FETCH => txs); - assert!(data.iter().all(|tx| matches!(tx, Transaction::L1Handler(_)))); + assert!(data.iter().all(|tx| matches!(tx, InternalConsensusTransaction::L1Handler(_)))); let txs = tx_provider.get_txs(MAX_TXS_PER_FETCH).await.unwrap(); let data = assert_matches!(txs, NextTxs::Txs(txs) if txs.len() == MAX_TXS_PER_FETCH => txs); - assert!(data[..n_l1handler_left].iter().all(|tx| matches!(tx, Transaction::L1Handler(_)))); - assert!(data[n_l1handler_left..].iter().all(|tx| matches!(tx, Transaction::Account(_)))); + assert!( + data[..n_l1handler_left] + .iter() + .all(|tx| matches!(tx, InternalConsensusTransaction::L1Handler(_))) + ); + assert!( + data[n_l1handler_left..] + .iter() + .all(|tx| matches!(tx, InternalConsensusTransaction::RpcTransaction(_))) + ); let txs = tx_provider.get_txs(MAX_TXS_PER_FETCH).await.unwrap(); let data = assert_matches!(txs, NextTxs::Txs(txs) if txs.len() == MAX_TXS_PER_FETCH => txs); - assert!(data.iter().all(|tx| matches!(tx, Transaction::Account(_)))); + assert!(data.iter().all(|tx| matches!(tx, InternalConsensusTransaction::RpcTransaction(_)))); } #[rstest] @@ -150,30 +168,30 @@ async fn no_more_l1_handler(mut mock_dependencies: MockDependencies) { assert!( data[..NUM_L1_HANDLER_TXS_IN_PROVIDER] .iter() - .all(|tx| matches!(tx, Transaction::L1Handler(_))) + .all(|tx| matches!(tx, InternalConsensusTransaction::L1Handler(_))) ); assert!( data[NUM_L1_HANDLER_TXS_IN_PROVIDER..] .iter() - .all(|tx| { matches!(tx, Transaction::Account(_)) }) + .all(|tx| { matches!(tx, InternalConsensusTransaction::RpcTransaction(_)) }) ); let txs = tx_provider.get_txs(MAX_TXS_PER_FETCH).await.unwrap(); let data = assert_matches!(txs, NextTxs::Txs(txs) if txs.len() == MAX_TXS_PER_FETCH => txs); - assert!(data.iter().all(|tx| matches!(tx, Transaction::Account(_)))); + assert!(data.iter().all(|tx| matches!(tx, InternalConsensusTransaction::RpcTransaction(_)))); } #[rstest] #[tokio::test] async fn validate_flow(mut mock_dependencies: MockDependencies) { let test_tx = test_l1handler_tx(); - mock_dependencies.expect_validate_l1handler(test_tx.clone(), true); + mock_dependencies.expect_validate_l1handler(test_tx.clone(), L1ValidationStatus::Validated); mock_dependencies .simulate_input_txs(vec![ - Transaction::L1Handler(test_tx), - Transaction::Account(AccountTransaction::Invoke(executable_invoke_tx( + InternalConsensusTransaction::L1Handler(test_tx), + InternalConsensusTransaction::RpcTransaction(internal_invoke_tx( InvokeTxArgs::default(), - ))), + )), ]) .await; let mut validate_tx_provider = mock_dependencies.validate_tx_provider(); @@ -181,21 +199,32 @@ async fn validate_flow(mut mock_dependencies: MockDependencies) { let txs = validate_tx_provider.get_txs(MAX_TXS_PER_FETCH).await.unwrap(); let data = assert_matches!(txs, NextTxs::Txs(txs) => txs); assert_eq!(data.len(), 2); - assert!(matches!(data[0], Transaction::L1Handler(_))); - assert!(matches!(data[1], Transaction::Account(_))); + assert!(matches!(data[0], InternalConsensusTransaction::L1Handler(_))); + assert!(matches!(data[1], InternalConsensusTransaction::RpcTransaction(_))); } #[rstest] #[tokio::test] -async fn validate_fails(mut mock_dependencies: MockDependencies) { +async fn validate_fails( + mut mock_dependencies: MockDependencies, + #[values( + InvalidValidationStatus::AlreadyIncludedInProposedBlock, + InvalidValidationStatus::AlreadyIncludedOnL2, + InvalidValidationStatus::ConsumedOnL1OrUnknown + )] + expected_validation_status: InvalidValidationStatus, +) { let test_tx = test_l1handler_tx(); - mock_dependencies.expect_validate_l1handler(test_tx.clone(), false); + mock_dependencies.expect_validate_l1handler( + test_tx.clone(), + L1ValidationStatus::Invalid(expected_validation_status), + ); mock_dependencies .simulate_input_txs(vec![ - Transaction::L1Handler(test_tx), - Transaction::Account(AccountTransaction::Invoke(executable_invoke_tx( + InternalConsensusTransaction::L1Handler(test_tx), + InternalConsensusTransaction::RpcTransaction(internal_invoke_tx( InvokeTxArgs::default(), - ))), + )), ]) .await; let mut validate_tx_provider = mock_dependencies.validate_tx_provider(); @@ -203,6 +232,7 @@ async fn validate_fails(mut mock_dependencies: MockDependencies) { let result = validate_tx_provider.get_txs(MAX_TXS_PER_FETCH).await; assert_matches!( result, - Err(TransactionProviderError::L1HandlerTransactionValidationFailed(_tx_hash)) + Err(TransactionProviderError::L1HandlerTransactionValidationFailed { validation_status, .. }) + if validation_status == expected_validation_status ); } diff --git a/crates/starknet_batcher/src/utils.rs b/crates/starknet_batcher/src/utils.rs new file mode 100644 index 00000000000..9b9ad1c37e1 --- /dev/null +++ b/crates/starknet_batcher/src/utils.rs @@ -0,0 +1,75 @@ +use std::sync::Arc; + +use blockifier::abi::constants; +use chrono::Utc; +use starknet_api::block::{BlockHashAndNumber, BlockNumber}; +use starknet_batcher_types::batcher_types::{BatcherResult, ProposalStatus}; +use starknet_batcher_types::errors::BatcherError; + +use crate::block_builder::BlockBuilderError; + +// BlockBuilderError is wrapped in an Arc since it doesn't implement Clone. +pub(crate) type ProposalResult = Result>; + +// Represents a spawned task of building new block proposal. +pub(crate) struct ProposalTask { + pub abort_signal_sender: tokio::sync::oneshot::Sender<()>, + pub join_handle: tokio::task::JoinHandle<()>, +} + +pub(crate) fn deadline_as_instant( + deadline: chrono::DateTime, +) -> BatcherResult { + let time_to_deadline = deadline - chrono::Utc::now(); + let as_duration = + time_to_deadline.to_std().map_err(|_| BatcherError::TimeToDeadlineError { deadline })?; + Ok((std::time::Instant::now() + as_duration).into()) +} + +pub(crate) fn verify_block_input( + height: BlockNumber, + block_number: BlockNumber, + retrospective_block_hash: Option, +) -> BatcherResult<()> { + verify_non_empty_retrospective_block_hash(height, retrospective_block_hash)?; + verify_block_number(height, block_number)?; + Ok(()) +} + +pub(crate) fn verify_non_empty_retrospective_block_hash( + height: BlockNumber, + retrospective_block_hash: Option, +) -> BatcherResult<()> { + if height >= BlockNumber(constants::STORED_BLOCK_HASH_BUFFER) + && retrospective_block_hash.is_none() + { + return Err(BatcherError::MissingRetrospectiveBlockHash); + } + Ok(()) +} + +pub(crate) fn verify_block_number( + height: BlockNumber, + block_number: BlockNumber, +) -> BatcherResult<()> { + if block_number != height { + return Err(BatcherError::InvalidBlockNumber { active_height: height, block_number }); + } + Ok(()) +} + +// Return the appropriate ProposalStatus for a given ProposalError. +pub(crate) fn proposal_status_from( + block_builder_error: Arc, +) -> BatcherResult { + match *block_builder_error { + // FailOnError means the proposal either failed due to bad input (e.g. invalid + // transactions), or couldn't finish in time. + BlockBuilderError::FailOnError(_) => Ok(ProposalStatus::InvalidProposal), + BlockBuilderError::Aborted => Err(BatcherError::ProposalAborted), + _ => { + tracing::error!("Unexpected error: {}", block_builder_error); + Err(BatcherError::InternalError) + } + } +} diff --git a/crates/starknet_batcher_types/Cargo.toml b/crates/starknet_batcher_types/Cargo.toml index 021f2e933be..8eef417770e 100644 --- a/crates/starknet_batcher_types/Cargo.toml +++ b/crates/starknet_batcher_types/Cargo.toml @@ -13,6 +13,7 @@ workspace = true [dependencies] async-trait.workspace = true +blockifier = { workspace = true, features = ["transaction_serde"] } chrono = { workspace = true, features = ["serde"] } derive_more.workspace = true mockall = { workspace = true, optional = true } @@ -20,9 +21,10 @@ papyrus_proc_macros.workspace = true serde = { workspace = true, features = ["derive"] } starknet_api.workspace = true starknet_sequencer_infra.workspace = true +starknet_state_sync_types.workspace = true +strum_macros.workspace = true thiserror.workspace = true [dev-dependencies] -# Enable self with "testing" feature in tests. -starknet_batcher_types = { workspace = true, features = ["testing"] } +mockall.workspace = true diff --git a/crates/starknet_batcher_types/src/batcher_types.rs b/crates/starknet_batcher_types/src/batcher_types.rs index f12bb25513f..59901f9c58a 100644 --- a/crates/starknet_batcher_types/src/batcher_types.rs +++ b/crates/starknet_batcher_types/src/batcher_types.rs @@ -1,14 +1,19 @@ use std::fmt::Debug; +use blockifier::bouncer::BouncerWeights; +use blockifier::state::cached_state::CommitmentStateDiff; +use blockifier::transaction::objects::TransactionExecutionInfo; use chrono::prelude::*; use serde::{Deserialize, Serialize}; -use starknet_api::block::{BlockHashAndNumber, BlockNumber}; +use starknet_api::block::{BlockHashAndNumber, BlockInfo, BlockNumber}; +use starknet_api::consensus_transaction::InternalConsensusTransaction; use starknet_api::core::StateDiffCommitment; -use starknet_api::executable_transaction::Transaction; +use starknet_api::execution_resources::GasAmount; +use starknet_api::state::ThinStateDiff; use crate::errors::BatcherError; -// TODO (Matan) decide on the id structure +// TODO(Matan): decide on the id structure #[derive( Copy, Clone, @@ -35,9 +40,7 @@ pub struct ProposeBlockInput { pub proposal_id: ProposalId, pub deadline: chrono::DateTime, pub retrospective_block_hash: Option, - // TODO: Should we get the gas price here? - // TODO: add proposer address. - // TODO: add whether the kzg mechanism is used for DA. + pub block_info: BlockInfo, } #[derive(Clone, Debug, Serialize, Deserialize)] @@ -46,6 +49,11 @@ pub struct GetProposalContentInput { pub proposal_id: ProposalId, } +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct GetHeightResponse { + pub height: BlockNumber, +} + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct GetProposalContentResponse { pub content: GetProposalContent, @@ -53,7 +61,7 @@ pub struct GetProposalContentResponse { #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum GetProposalContent { - Txs(Vec), + Txs(Vec), Finished(ProposalCommitment), } @@ -63,6 +71,7 @@ pub struct ValidateBlockInput { pub proposal_id: ProposalId, pub deadline: chrono::DateTime, pub retrospective_block_hash: Option, + pub block_info: BlockInfo, } #[derive(Clone, Debug, Serialize, Deserialize)] @@ -74,7 +83,7 @@ pub struct SendProposalContentInput { /// The content of the stream that the consensus sends to the batcher. #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum SendProposalContent { - Txs(Vec), + Txs(Vec), Finish, Abort, } @@ -84,6 +93,22 @@ pub struct SendProposalContentResponse { pub response: ProposalStatus, } +#[derive(Debug, Serialize, Deserialize, PartialEq)] +pub struct CentralObjects { + pub execution_infos: Vec, + pub bouncer_weights: BouncerWeights, + pub compressed_state_diff: Option, +} + +#[derive(Debug, Serialize, Deserialize, PartialEq)] +pub struct DecisionReachedResponse { + // TODO(Yael): Consider passing the state_diff as CommitmentStateDiff inside CentralObjects. + // Today the ThinStateDiff is used for the state sync but it may not be needed in the future. + pub state_diff: ThinStateDiff, + pub l2_gas_used: GasAmount, + pub central_objects: CentralObjects, +} + #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub enum ProposalStatus { Processing, @@ -92,7 +117,7 @@ pub enum ProposalStatus { // Only sent in response to `Abort`. Aborted, // May be caused due to handling of a previous item of the new proposal. - // In this case, the propsal is aborted and no additional content will be processed. + // In this case, the proposal is aborted and no additional content will be processed. InvalidProposal, } @@ -106,4 +131,9 @@ pub struct DecisionReachedInput { pub proposal_id: ProposalId, } +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +pub struct RevertBlockInput { + pub height: BlockNumber, +} + pub type BatcherResult = Result; diff --git a/crates/starknet_batcher_types/src/communication.rs b/crates/starknet_batcher_types/src/communication.rs index 01643eb27a5..216c15b0ebd 100644 --- a/crates/starknet_batcher_types/src/communication.rs +++ b/crates/starknet_batcher_types/src/communication.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use async_trait::async_trait; #[cfg(any(feature = "testing", test))] use mockall::automock; -use papyrus_proc_macros::handle_response_variants; +use papyrus_proc_macros::handle_all_response_variants; use serde::{Deserialize, Serialize}; use starknet_sequencer_infra::component_client::{ ClientError, @@ -14,14 +14,20 @@ use starknet_sequencer_infra::component_definitions::{ ComponentClient, ComponentRequestAndResponseSender, }; +use starknet_sequencer_infra::impl_debug_for_infra_requests_and_responses; +use starknet_state_sync_types::state_sync_types::SyncBlock; +use strum_macros::AsRefStr; use thiserror::Error; use crate::batcher_types::{ BatcherResult, DecisionReachedInput, + DecisionReachedResponse, + GetHeightResponse, GetProposalContentInput, GetProposalContentResponse, ProposeBlockInput, + RevertBlockInput, SendProposalContentInput, SendProposalContentResponse, StartHeightInput, @@ -43,6 +49,8 @@ pub type SharedBatcherClient = Arc; pub trait BatcherClient: Send + Sync { /// Starts the process of building a proposal. async fn propose_block(&self, input: ProposeBlockInput) -> BatcherClientResult<()>; + /// Gets the first height that is not written in the storage yet. + async fn get_height(&self) -> BatcherClientResult; /// Gets the next available content from the proposal stream (only relevant when building a /// proposal). async fn get_proposal_content( @@ -65,30 +73,46 @@ pub trait BatcherClient: Send + Sync { /// From this point onwards, the batcher will accept requests only for proposals associated /// with this height. async fn start_height(&self, input: StartHeightInput) -> BatcherClientResult<()>; + /// Adds a block from the state sync. Updates the batcher's state and commits the + /// transactions to the mempool. + async fn add_sync_block(&self, sync_block: SyncBlock) -> BatcherClientResult<()>; /// Notifies the batcher that a decision has been reached. /// This closes the process of the given height, and the accepted proposal is committed. - async fn decision_reached(&self, input: DecisionReachedInput) -> BatcherClientResult<()>; + async fn decision_reached( + &self, + input: DecisionReachedInput, + ) -> BatcherClientResult; + /// Reverts the block with the given block number, only if it is the last in the storage. + async fn revert_block(&self, input: RevertBlockInput) -> BatcherClientResult<()>; } -#[derive(Debug, Serialize, Deserialize, Clone)] +#[derive(Serialize, Deserialize, Clone, AsRefStr)] pub enum BatcherRequest { ProposeBlock(ProposeBlockInput), GetProposalContent(GetProposalContentInput), ValidateBlock(ValidateBlockInput), SendProposalContent(SendProposalContentInput), StartHeight(StartHeightInput), + GetCurrentHeight, DecisionReached(DecisionReachedInput), + AddSyncBlock(SyncBlock), + RevertBlock(RevertBlockInput), } +impl_debug_for_infra_requests_and_responses!(BatcherRequest); -#[derive(Debug, Serialize, Deserialize, Clone)] +#[derive(Serialize, Deserialize, AsRefStr)] pub enum BatcherResponse { ProposeBlock(BatcherResult<()>), + GetCurrentHeight(BatcherResult), GetProposalContent(BatcherResult), ValidateBlock(BatcherResult<()>), SendProposalContent(BatcherResult), StartHeight(BatcherResult<()>), - DecisionReached(BatcherResult<()>), + DecisionReached(BatcherResult>), + AddSyncBlock(BatcherResult<()>), + RevertBlock(BatcherResult<()>), } +impl_debug_for_infra_requests_and_responses!(BatcherResponse); #[derive(Clone, Debug, Error)] pub enum BatcherClientError { @@ -105,8 +129,13 @@ where { async fn propose_block(&self, input: ProposeBlockInput) -> BatcherClientResult<()> { let request = BatcherRequest::ProposeBlock(input); - let response = self.send(request).await; - handle_response_variants!(BatcherResponse, ProposeBlock, BatcherClientError, BatcherError) + handle_all_response_variants!( + BatcherResponse, + ProposeBlock, + BatcherClientError, + BatcherError, + Direct + ) } async fn get_proposal_content( @@ -114,19 +143,24 @@ where input: GetProposalContentInput, ) -> BatcherClientResult { let request = BatcherRequest::GetProposalContent(input); - let response = self.send(request).await; - handle_response_variants!( + handle_all_response_variants!( BatcherResponse, GetProposalContent, BatcherClientError, - BatcherError + BatcherError, + Direct ) } async fn validate_block(&self, input: ValidateBlockInput) -> BatcherClientResult<()> { let request = BatcherRequest::ValidateBlock(input); - let response = self.send(request).await; - handle_response_variants!(BatcherResponse, ValidateBlock, BatcherClientError, BatcherError) + handle_all_response_variants!( + BatcherResponse, + ValidateBlock, + BatcherClientError, + BatcherError, + Direct + ) } async fn send_proposal_content( @@ -134,29 +168,70 @@ where input: SendProposalContentInput, ) -> BatcherClientResult { let request = BatcherRequest::SendProposalContent(input); - let response = self.send(request).await; - handle_response_variants!( + handle_all_response_variants!( BatcherResponse, SendProposalContent, BatcherClientError, - BatcherError + BatcherError, + Direct ) } async fn start_height(&self, input: StartHeightInput) -> BatcherClientResult<()> { let request = BatcherRequest::StartHeight(input); - let response = self.send(request).await; - handle_response_variants!(BatcherResponse, StartHeight, BatcherClientError, BatcherError) + handle_all_response_variants!( + BatcherResponse, + StartHeight, + BatcherClientError, + BatcherError, + Direct + ) + } + + async fn get_height(&self) -> BatcherClientResult { + let request = BatcherRequest::GetCurrentHeight; + handle_all_response_variants!( + BatcherResponse, + GetCurrentHeight, + BatcherClientError, + BatcherError, + Direct + ) } - async fn decision_reached(&self, input: DecisionReachedInput) -> BatcherClientResult<()> { + async fn decision_reached( + &self, + input: DecisionReachedInput, + ) -> BatcherClientResult { let request = BatcherRequest::DecisionReached(input); - let response = self.send(request).await; - handle_response_variants!( + handle_all_response_variants!( BatcherResponse, DecisionReached, BatcherClientError, - BatcherError + BatcherError, + Boxed + ) + } + + async fn add_sync_block(&self, sync_block: SyncBlock) -> BatcherClientResult<()> { + let request = BatcherRequest::AddSyncBlock(sync_block); + handle_all_response_variants!( + BatcherResponse, + AddSyncBlock, + BatcherClientError, + BatcherError, + Direct + ) + } + + async fn revert_block(&self, input: RevertBlockInput) -> BatcherClientResult<()> { + let request = BatcherRequest::RevertBlock(input); + handle_all_response_variants!( + BatcherResponse, + RevertBlock, + BatcherClientError, + BatcherError, + Direct ) } } diff --git a/crates/starknet_batcher_types/src/errors.rs b/crates/starknet_batcher_types/src/errors.rs index a3a028a815e..59b39bbc9ec 100644 --- a/crates/starknet_batcher_types/src/errors.rs +++ b/crates/starknet_batcher_types/src/errors.rs @@ -7,29 +7,31 @@ use crate::batcher_types::ProposalId; #[derive(Clone, Debug, Error, PartialEq, Eq, Serialize, Deserialize)] pub enum BatcherError { + #[error( + "There is already an active proposal {}, can't start proposal {}.", + active_proposal_id, + new_proposal_id + )] + AnotherProposalInProgress { active_proposal_id: ProposalId, new_proposal_id: ProposalId }, #[error( "Decision reached for proposal with ID {proposal_id} that does not exist (might still \ being executed)." )] ExecutedProposalNotFound { proposal_id: ProposalId }, - #[error( - "Height {storage_height} already passed, can't start working on height {requested_height}." - )] - HeightAlreadyPassed { storage_height: BlockNumber, requested_height: BlockNumber }, #[error("Height is in progress.")] HeightInProgress, #[error("Internal server error.")] InternalError, + #[error("Invalid block number. The active height is {active_height}, got {block_number}.")] + InvalidBlockNumber { active_height: BlockNumber, block_number: BlockNumber }, #[error("Missing retrospective block hash.")] MissingRetrospectiveBlockHash, #[error("Attempt to start proposal with no active height.")] NoActiveHeight, - #[error( - "There is already an active proposal {}, can't start proposal {}.", - active_proposal_id, - new_proposal_id - )] - ServerBusy { active_proposal_id: ProposalId, new_proposal_id: ProposalId }, + #[error("Not ready to begin work on proposal.")] + NotReady, + #[error("Proposal aborted.")] + ProposalAborted, #[error("Proposal with ID {proposal_id} already exists.")] ProposalAlreadyExists { proposal_id: ProposalId }, #[error( @@ -39,15 +41,13 @@ pub enum BatcherError { ProposalAlreadyFinished { proposal_id: ProposalId }, #[error("Proposal failed.")] ProposalFailed, - #[error("Proposal aborted.")] - ProposalAborted, #[error("Proposal with ID {proposal_id} not found.")] ProposalNotFound { proposal_id: ProposalId }, #[error( - "Storage is not synced. Storage height: {storage_height}, requested height: \ - {requested_height}." + "Storage height marker mismatch. Storage marker (first unwritten height): \ + {marker_height}, requested height: {requested_height}." )] - StorageNotSynced { storage_height: BlockNumber, requested_height: BlockNumber }, + StorageHeightMarkerMismatch { marker_height: BlockNumber, requested_height: BlockNumber }, #[error("Time to deadline is out of range. Got {deadline}.")] TimeToDeadlineError { deadline: chrono::DateTime }, } diff --git a/crates/starknet_class_manager/Cargo.toml b/crates/starknet_class_manager/Cargo.toml new file mode 100644 index 00000000000..bb0e8b044fc --- /dev/null +++ b/crates/starknet_class_manager/Cargo.toml @@ -0,0 +1,36 @@ +[package] +name = "starknet_class_manager" +edition.workspace = true +license.workspace = true +repository.workspace = true +version.workspace = true + +[features] +testing = [] + +[lints] +workspace = true + +[dependencies] +async-trait.workspace = true +hex.workspace = true +papyrus_config.workspace = true +papyrus_storage.workspace = true +serde.workspace = true +starknet_api.workspace = true +starknet_class_manager_types.workspace = true +starknet_sequencer_infra.workspace = true +starknet_sequencer_metrics.workspace = true +starknet_sierra_multicompile_types.workspace = true +strum.workspace = true +strum_macros.workspace = true +tempfile.workspace = true +thiserror.workspace = true +tracing.workspace = true +validator.workspace = true + +[dev-dependencies] +mockall.workspace = true +starknet_api = { workspace = true, features = ["testing"] } +starknet_sierra_multicompile_types = { workspace = true, features = ["testing"] } +tokio.workspace = true diff --git a/crates/starknet_class_manager/src/class_manager.rs b/crates/starknet_class_manager/src/class_manager.rs new file mode 100644 index 00000000000..1c865c6c4db --- /dev/null +++ b/crates/starknet_class_manager/src/class_manager.rs @@ -0,0 +1,132 @@ +use async_trait::async_trait; +use starknet_api::state::SierraContractClass; +use starknet_class_manager_types::{ + ClassHashes, + ClassId, + ClassManagerError, + ClassManagerResult, + ExecutableClassHash, +}; +use starknet_sequencer_infra::component_definitions::{ + default_component_start_fn, + ComponentStarter, +}; +use starknet_sierra_multicompile_types::{ + RawClass, + RawExecutableClass, + SharedSierraCompilerClient, + SierraCompilerClientError, +}; +use tracing::instrument; + +use crate::class_storage::{CachedClassStorage, ClassStorage, FsClassStorage}; +use crate::config::{ClassManagerConfig, FsClassManagerConfig}; +use crate::metrics::register_metrics; +use crate::FsClassManager; + +#[cfg(test)] +#[path = "class_manager_test.rs"] +pub mod class_manager_test; + +pub struct ClassManager { + pub config: ClassManagerConfig, + pub compiler: SharedSierraCompilerClient, + pub classes: CachedClassStorage, +} + +impl ClassManager { + pub fn new( + config: ClassManagerConfig, + compiler: SharedSierraCompilerClient, + storage: S, + ) -> Self { + let cached_class_storage_config = config.cached_class_storage_config.clone(); + Self { + config, + compiler, + classes: CachedClassStorage::new(cached_class_storage_config, storage), + } + } + + #[instrument(skip(self, class), ret, err)] + pub async fn add_class(&mut self, class: RawClass) -> ClassManagerResult { + // TODO(Elin): think how to not clone the class to deserialize. + let sierra_class = + SierraContractClass::try_from(class.clone()).map_err(ClassManagerError::from)?; + let class_hash = sierra_class.calculate_class_hash(); + if let Ok(Some(executable_class_hash)) = self.classes.get_executable_class_hash(class_hash) + { + // Class already exists. + return Ok(ClassHashes { class_hash, executable_class_hash }); + } + + let (raw_executable_class, executable_class_hash) = + self.compiler.compile(class.clone()).await.map_err(|err| match err { + SierraCompilerClientError::SierraCompilerError(error) => { + ClassManagerError::SierraCompiler { class_hash, error } + } + SierraCompilerClientError::ClientError(error) => { + ClassManagerError::Client(error.to_string()) + } + })?; + + self.classes.set_class(class_hash, class, executable_class_hash, raw_executable_class)?; + + let class_hashes = ClassHashes { class_hash, executable_class_hash }; + Ok(class_hashes) + } + + #[instrument(skip(self), err)] + pub fn get_executable( + &self, + class_id: ClassId, + ) -> ClassManagerResult> { + Ok(self.classes.get_executable(class_id)?) + } + + #[instrument(skip(self), err)] + pub fn get_sierra(&self, class_id: ClassId) -> ClassManagerResult> { + Ok(self.classes.get_sierra(class_id)?) + } + + #[instrument(skip(self, class), ret, err)] + pub fn add_deprecated_class( + &mut self, + class_id: ClassId, + class: RawExecutableClass, + ) -> ClassManagerResult<()> { + self.classes.set_deprecated_class(class_id, class)?; + Ok(()) + } + + #[instrument(skip(self, class, executable_class), ret, err)] + pub fn add_class_and_executable_unsafe( + &mut self, + class_id: ClassId, + class: RawClass, + executable_class_id: ExecutableClassHash, + executable_class: RawExecutableClass, + ) -> ClassManagerResult<()> { + Ok(self.classes.set_class(class_id, class, executable_class_id, executable_class)?) + } +} + +pub fn create_class_manager( + config: FsClassManagerConfig, + compiler_client: SharedSierraCompilerClient, +) -> FsClassManager { + let FsClassManagerConfig { class_manager_config, class_storage_config } = config; + let fs_class_storage = + FsClassStorage::new(class_storage_config).expect("Failed to create class storage."); + let class_manager = ClassManager::new(class_manager_config, compiler_client, fs_class_storage); + + FsClassManager(class_manager) +} + +#[async_trait] +impl ComponentStarter for FsClassManager { + async fn start(&mut self) { + default_component_start_fn::().await; + register_metrics(); + } +} diff --git a/crates/starknet_class_manager/src/class_manager_test.rs b/crates/starknet_class_manager/src/class_manager_test.rs new file mode 100644 index 00000000000..f2456e52a77 --- /dev/null +++ b/crates/starknet_class_manager/src/class_manager_test.rs @@ -0,0 +1,119 @@ +use std::sync::Arc; + +use mockall::predicate::eq; +use starknet_api::core::{ClassHash, CompiledClassHash}; +use starknet_api::felt; +use starknet_api::state::SierraContractClass; +use starknet_class_manager_types::ClassHashes; +use starknet_sierra_multicompile_types::{MockSierraCompilerClient, RawClass, RawExecutableClass}; + +use crate::class_manager::ClassManager; +use crate::class_storage::{create_tmp_dir, CachedClassStorageConfig, FsClassStorage}; +use crate::config::ClassManagerConfig; + +impl ClassManager { + fn new_for_testing( + compiler: MockSierraCompilerClient, + persistent_root: &tempfile::TempDir, + class_hash_storage_path_prefix: &tempfile::TempDir, + ) -> Self { + let cached_class_storage_config = + CachedClassStorageConfig { class_cache_size: 10, deprecated_class_cache_size: 10 }; + let config = ClassManagerConfig { cached_class_storage_config }; + let storage = + FsClassStorage::new_for_testing(persistent_root, class_hash_storage_path_prefix); + + ClassManager::new(config, Arc::new(compiler), storage) + } +} + +// TODO(Elin): consider sharing setup code, keeping it clear for the test reader how the compiler is +// mocked per test. + +#[tokio::test] +async fn class_manager() { + // Setup. + + // Prepare mock compiler. + let mut compiler = MockSierraCompilerClient::new(); + let class = RawClass::try_from(SierraContractClass::default()).unwrap(); + let expected_executable_class = RawExecutableClass::new_unchecked(vec![4, 5, 6].into()); + let expected_executable_class_for_closure = expected_executable_class.clone(); + let expected_executable_class_hash = CompiledClassHash(felt!("0x5678")); + compiler.expect_compile().with(eq(class.clone())).times(1).return_once(move |_| { + Ok((expected_executable_class_for_closure, expected_executable_class_hash)) + }); + + // Prepare class manager. + let persistent_root = create_tmp_dir().unwrap(); + let class_hash_storage_path_prefix = create_tmp_dir().unwrap(); + let mut class_manager = + ClassManager::new_for_testing(compiler, &persistent_root, &class_hash_storage_path_prefix); + + // Test. + + // Non-existent class. + let class_id = SierraContractClass::try_from(class.clone()).unwrap().calculate_class_hash(); + assert_eq!(class_manager.get_sierra(class_id), Ok(None)); + assert_eq!(class_manager.get_executable(class_id), Ok(None)); + + // Add new class. + let class_hashes = class_manager.add_class(class.clone()).await.unwrap(); + let expected_class_hashes = + ClassHashes { class_hash: class_id, executable_class_hash: expected_executable_class_hash }; + assert_eq!(class_hashes, expected_class_hashes); + + // Get class. + assert_eq!(class_manager.get_sierra(class_id).unwrap(), Some(class.clone())); + assert_eq!(class_manager.get_executable(class_id).unwrap(), Some(expected_executable_class)); + + // Add existing class; response returned immediately, without invoking compilation. + let class_hashes = class_manager.add_class(class).await.unwrap(); + assert_eq!(class_hashes, expected_class_hashes); +} + +#[tokio::test] +#[ignore = "Test deprecated class API"] +async fn class_manager_deprecated_class_api() { + todo!("Test deprecated class API"); +} + +#[tokio::test] +async fn class_manager_get_executable() { + // Setup. + + // Prepare mock compiler. + let mut compiler = MockSierraCompilerClient::new(); + let class = RawClass::try_from(SierraContractClass::default()).unwrap(); + let expected_executable_class = RawExecutableClass::new_unchecked(vec![4, 5, 6].into()); + let expected_executable_class_for_closure = expected_executable_class.clone(); + let expected_executable_class_hash = CompiledClassHash(felt!("0x5678")); + compiler.expect_compile().with(eq(class.clone())).times(1).return_once(move |_| { + Ok((expected_executable_class_for_closure, expected_executable_class_hash)) + }); + + // Prepare class manager. + let persistent_root = create_tmp_dir().unwrap(); + let class_hash_storage_path_prefix = create_tmp_dir().unwrap(); + let mut class_manager = + ClassManager::new_for_testing(compiler, &persistent_root, &class_hash_storage_path_prefix); + + // Test. + + // Add classes: deprecated and non-deprecated, under different hashes. + let ClassHashes { class_hash, executable_class_hash: _ } = + class_manager.add_class(class.clone()).await.unwrap(); + + let deprecated_class_hash = ClassHash(felt!("0x1806")); + let deprecated_executable_class = RawExecutableClass::new_unchecked(vec![1, 2, 3].into()); + class_manager + .add_deprecated_class(deprecated_class_hash, deprecated_executable_class.clone()) + .unwrap(); + + // Get both executable classes. + assert_eq!(class_manager.get_executable(class_hash).unwrap(), Some(expected_executable_class)); + assert_eq!( + class_manager.get_executable(deprecated_class_hash).unwrap(), + Some(deprecated_executable_class) + ); +} diff --git a/crates/starknet_class_manager/src/class_storage.rs b/crates/starknet_class_manager/src/class_storage.rs new file mode 100644 index 00000000000..c8c764fd464 --- /dev/null +++ b/crates/starknet_class_manager/src/class_storage.rs @@ -0,0 +1,594 @@ +use std::collections::BTreeMap; +use std::error::Error; +use std::mem; +use std::path::{Path, PathBuf}; +use std::sync::{Arc, Mutex, MutexGuard}; + +use papyrus_config::dumping::{ser_param, SerializeConfig}; +use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; +use papyrus_storage::class_hash::{ClassHashStorageReader, ClassHashStorageWriter}; +use serde::{Deserialize, Serialize}; +use starknet_api::class_cache::GlobalContractCache; +use starknet_api::contract_class::ContractClass; +use starknet_api::core::ChainId; +use starknet_class_manager_types::{CachedClassStorageError, ClassId, ExecutableClassHash}; +use starknet_sierra_multicompile_types::{RawClass, RawClassError, RawExecutableClass}; +use thiserror::Error; +use tracing::instrument; + +use crate::config::{ClassHashStorageConfig, FsClassStorageConfig}; +use crate::metrics::{increment_n_classes, record_class_size, CairoClassType, ClassObjectType}; + +#[cfg(test)] +#[path = "class_storage_test.rs"] +mod class_storage_test; + +// TODO(Elin): restrict visibility once this code is used. + +pub trait ClassStorage: Send + Sync { + type Error: Error; + + fn set_class( + &mut self, + class_id: ClassId, + class: RawClass, + executable_class_hash: ExecutableClassHash, + executable_class: RawExecutableClass, + ) -> Result<(), Self::Error>; + + fn get_sierra(&self, class_id: ClassId) -> Result, Self::Error>; + + fn get_executable(&self, class_id: ClassId) -> Result, Self::Error>; + + fn get_executable_class_hash( + &self, + class_id: ClassId, + ) -> Result, Self::Error>; + + fn set_deprecated_class( + &mut self, + class_id: ClassId, + class: RawExecutableClass, + ) -> Result<(), Self::Error>; + + fn get_deprecated_class( + &self, + class_id: ClassId, + ) -> Result, Self::Error>; +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +pub struct CachedClassStorageConfig { + pub class_cache_size: usize, + pub deprecated_class_cache_size: usize, +} + +// TODO(Elin): provide default values for the fields. +impl Default for CachedClassStorageConfig { + fn default() -> Self { + Self { class_cache_size: 10, deprecated_class_cache_size: 10 } + } +} + +impl SerializeConfig for CachedClassStorageConfig { + fn dump(&self) -> BTreeMap { + BTreeMap::from([ + ser_param( + "class_cache_size", + &self.class_cache_size, + "Contract classes cache size.", + ParamPrivacyInput::Public, + ), + ser_param( + "deprecated_class_cache_size", + &self.deprecated_class_cache_size, + "Deprecated contract classes cache size.", + ParamPrivacyInput::Public, + ), + ]) + } +} + +pub struct CachedClassStorage { + storage: S, + + // Cache. + classes: GlobalContractCache, + executable_classes: GlobalContractCache, + executable_class_hashes: GlobalContractCache, + deprecated_classes: GlobalContractCache, +} + +impl CachedClassStorage { + pub fn new(config: CachedClassStorageConfig, storage: S) -> Self { + Self { + storage, + classes: GlobalContractCache::new(config.class_cache_size), + executable_classes: GlobalContractCache::new(config.class_cache_size), + executable_class_hashes: GlobalContractCache::new(config.class_cache_size), + deprecated_classes: GlobalContractCache::new(config.deprecated_class_cache_size), + } + } + + pub fn class_cached(&self, class_id: ClassId) -> bool { + self.executable_class_hashes.get(&class_id).is_some() + } + + pub fn deprecated_class_cached(&self, class_id: ClassId) -> bool { + self.deprecated_classes.get(&class_id).is_some() + } +} + +impl ClassStorage for CachedClassStorage { + type Error = CachedClassStorageError; + + #[instrument(skip(self, class, executable_class), level = "debug", ret, err)] + fn set_class( + &mut self, + class_id: ClassId, + class: RawClass, + executable_class_hash: ExecutableClassHash, + executable_class: RawExecutableClass, + ) -> Result<(), Self::Error> { + if self.class_cached(class_id) { + return Ok(()); + } + + self.storage.set_class( + class_id, + class.clone(), + executable_class_hash, + executable_class.clone(), + )?; + + increment_n_classes(CairoClassType::Regular); + record_class_size(ClassObjectType::Sierra, &class); + record_class_size(ClassObjectType::Casm, &executable_class); + + // Cache the class. + // Done after successfully writing to storage as an optimization; + // does not require atomicity. + self.classes.set(class_id, class); + self.executable_classes.set(class_id, executable_class); + // Cache the executable class hash last; acts as an existence marker. + self.executable_class_hashes.set(class_id, executable_class_hash); + + Ok(()) + } + + #[instrument(skip(self), level = "debug", err)] + fn get_sierra(&self, class_id: ClassId) -> Result, Self::Error> { + if let Some(class) = self.classes.get(&class_id) { + return Ok(Some(class)); + } + + let Some(class) = self.storage.get_sierra(class_id)? else { + return Ok(None); + }; + + self.classes.set(class_id, class.clone()); + Ok(Some(class)) + } + + #[instrument(skip(self), level = "debug", err)] + fn get_executable(&self, class_id: ClassId) -> Result, Self::Error> { + if let Some(class) = self + .executable_classes + .get(&class_id) + .or_else(|| self.deprecated_classes.get(&class_id)) + { + return Ok(Some(class)); + } + + let Some(class) = self.storage.get_executable(class_id)? else { + return Ok(None); + }; + + // TODO(Elin): separate Cairo0<>1 getters to avoid deserializing here. + match ContractClass::try_from(class.clone()).unwrap() { + ContractClass::V0(_) => { + self.deprecated_classes.set(class_id, class.clone()); + } + ContractClass::V1(_) => { + self.executable_classes.set(class_id, class.clone()); + } + } + + Ok(Some(class)) + } + + #[instrument(skip(self), level = "debug", ret, err)] + fn get_executable_class_hash( + &self, + class_id: ClassId, + ) -> Result, Self::Error> { + if let Some(class_hash) = self.executable_class_hashes.get(&class_id) { + return Ok(Some(class_hash)); + } + + let Some(class_hash) = self.storage.get_executable_class_hash(class_id)? else { + return Ok(None); + }; + + self.executable_class_hashes.set(class_id, class_hash); + Ok(Some(class_hash)) + } + + #[instrument(skip(self, class), level = "debug", ret, err)] + fn set_deprecated_class( + &mut self, + class_id: ClassId, + class: RawExecutableClass, + ) -> Result<(), Self::Error> { + if self.deprecated_class_cached(class_id) { + return Ok(()); + } + + self.storage.set_deprecated_class(class_id, class.clone())?; + + increment_n_classes(CairoClassType::Deprecated); + record_class_size(ClassObjectType::DeprecatedCasm, &class); + + self.deprecated_classes.set(class_id, class); + + Ok(()) + } + + #[instrument(skip(self), level = "debug", err)] + fn get_deprecated_class( + &self, + class_id: ClassId, + ) -> Result, Self::Error> { + if let Some(class) = self.deprecated_classes.get(&class_id) { + return Ok(Some(class)); + } + + let Some(class) = self.storage.get_deprecated_class(class_id)? else { + return Ok(None); + }; + + self.deprecated_classes.set(class_id, class.clone()); + Ok(Some(class)) + } +} + +impl Clone for CachedClassStorage { + fn clone(&self) -> Self { + Self { + storage: self.storage.clone(), + classes: self.classes.clone(), + executable_classes: self.executable_classes.clone(), + executable_class_hashes: self.executable_class_hashes.clone(), + deprecated_classes: self.deprecated_classes.clone(), + } + } +} + +#[derive(Debug, Error)] +pub enum ClassHashStorageError { + #[error(transparent)] + Storage(#[from] papyrus_storage::StorageError), +} + +type ClassHashStorageResult = Result; +type LockedWriter<'a> = MutexGuard<'a, papyrus_storage::StorageWriter>; + +#[derive(Clone)] +pub struct ClassHashStorage { + reader: papyrus_storage::StorageReader, + writer: Arc>, +} + +impl ClassHashStorage { + pub fn new(config: ClassHashStorageConfig) -> ClassHashStorageResult { + let storage_config = papyrus_storage::StorageConfig { + db_config: papyrus_storage::db::DbConfig { + path_prefix: config.path_prefix, + chain_id: ChainId::Other("UnusedChainID".to_string()), + enforce_file_exists: config.enforce_file_exists, + max_size: config.max_size, + growth_step: 1 << 20, // 1MB. + ..Default::default() + }, + scope: papyrus_storage::StorageScope::StateOnly, + mmap_file_config: papyrus_storage::mmap_file::MmapFileConfig { + max_size: 1 << 30, // 1GB. + growth_step: 1 << 20, // 1MB. + max_object_size: 1 << 10, // 1KB; a class hash is 32B. + }, + }; + let (reader, writer) = papyrus_storage::open_storage(storage_config)?; + + Ok(Self { reader, writer: Arc::new(Mutex::new(writer)) }) + } + + fn writer(&self) -> ClassHashStorageResult> { + Ok(self.writer.lock().expect("Writer is poisoned.")) + } + + #[instrument(skip(self), level = "debug", ret, err)] + fn get_executable_class_hash( + &self, + class_id: ClassId, + ) -> ClassHashStorageResult> { + Ok(self.reader.begin_ro_txn()?.get_executable_class_hash(&class_id)?) + } + + #[instrument(skip(self), level = "debug", ret, err)] + fn set_executable_class_hash( + &mut self, + class_id: ClassId, + executable_class_hash: ExecutableClassHash, + ) -> ClassHashStorageResult<()> { + let mut writer = self.writer()?; + let txn = + writer.begin_rw_txn()?.set_executable_class_hash(&class_id, executable_class_hash)?; + txn.commit()?; + + Ok(()) + } +} + +type FsClassStorageResult = Result; + +#[derive(Clone)] +pub struct FsClassStorage { + pub persistent_root: PathBuf, + pub class_hash_storage: ClassHashStorage, +} + +#[derive(Debug, Error)] +pub enum FsClassStorageError { + #[error(transparent)] + ClassHashStorage(#[from] ClassHashStorageError), + #[error("Class of hash {class_id} not found.")] + ClassNotFound { class_id: ClassId }, + #[error(transparent)] + IoError(#[from] std::io::Error), + #[error(transparent)] + RawClass(#[from] RawClassError), +} + +impl FsClassStorage { + pub fn new(config: FsClassStorageConfig) -> FsClassStorageResult { + let class_hash_storage = ClassHashStorage::new(config.class_hash_storage_config)?; + Ok(Self { persistent_root: config.persistent_root, class_hash_storage }) + } + + fn contains_class(&self, class_id: ClassId) -> FsClassStorageResult { + Ok(self.get_executable_class_hash(class_id)?.is_some()) + } + + // TODO(Elin): make this more robust; checking file existence is not enough, since by reading + // it can be deleted. + fn contains_deprecated_class(&self, class_id: ClassId) -> bool { + self.get_deprecated_executable_path(class_id).exists() + } + + /// Returns the directory that will hold classes related to the given class ID. + /// For a class ID: 0xa1b2c3d4... (rest of hash), the structure is: + /// a1/ + /// └── b2/ + /// └── a1b2c3d4.../ + fn get_class_dir(&self, class_id: ClassId) -> PathBuf { + let class_id = hex::encode(class_id.to_bytes_be()); + let (first_msb_byte, second_msb_byte, _rest_of_bytes) = + (&class_id[..2], &class_id[2..4], &class_id[4..]); + + PathBuf::from(first_msb_byte).join(second_msb_byte).join(class_id) + } + + fn get_persistent_dir(&self, class_id: ClassId) -> PathBuf { + self.persistent_root.join(self.get_class_dir(class_id)) + } + + fn get_persistent_dir_with_create(&self, class_id: ClassId) -> FsClassStorageResult { + let path = self.get_persistent_dir(class_id); + if let Some(parent) = path.parent() { + std::fs::create_dir_all(parent)?; + } + + Ok(path) + } + + fn get_sierra_path(&self, class_id: ClassId) -> PathBuf { + concat_sierra_filename(&self.get_persistent_dir(class_id)) + } + + fn get_executable_path(&self, class_id: ClassId) -> PathBuf { + concat_executable_filename(&self.get_persistent_dir(class_id)) + } + + fn get_deprecated_executable_path(&self, class_id: ClassId) -> PathBuf { + concat_deprecated_executable_filename(&self.get_persistent_dir(class_id)) + } + + fn mark_class_id_as_existent( + &mut self, + class_id: ClassId, + executable_class_hash: ExecutableClassHash, + ) -> FsClassStorageResult<()> { + Ok(self.class_hash_storage.set_executable_class_hash(class_id, executable_class_hash)?) + } + + fn write_class( + &self, + class_id: ClassId, + class: RawClass, + executable_class: RawExecutableClass, + ) -> FsClassStorageResult<()> { + let persistent_dir = self.get_persistent_dir_with_create(class_id)?; + class.write_to_file(concat_sierra_filename(&persistent_dir))?; + executable_class.write_to_file(concat_executable_filename(&persistent_dir))?; + + Ok(()) + } + + fn write_deprecated_class( + &self, + class_id: ClassId, + class: RawExecutableClass, + ) -> FsClassStorageResult<()> { + let persistent_dir = self.get_persistent_dir_with_create(class_id)?; + class.write_to_file(concat_deprecated_executable_filename(&persistent_dir))?; + + Ok(()) + } + + // TODO(Elin): restore use of `write_[deprecated_]class_atomically`, but tmpdir + // should be located inside the PVC to prevent linking errors. + #[allow(dead_code)] + fn write_class_atomically( + &self, + class_id: ClassId, + class: RawClass, + executable_class: RawExecutableClass, + ) -> FsClassStorageResult<()> { + // Write classes to a temporary directory. + let tmp_dir = create_tmp_dir()?; + let tmp_dir = tmp_dir.path().join(self.get_class_dir(class_id)); + class.write_to_file(concat_sierra_filename(&tmp_dir))?; + executable_class.write_to_file(concat_executable_filename(&tmp_dir))?; + + // Atomically rename directory to persistent one. + let persistent_dir = self.get_persistent_dir_with_create(class_id)?; + std::fs::rename(tmp_dir, persistent_dir)?; + + Ok(()) + } + + #[allow(dead_code)] + fn write_deprecated_class_atomically( + &self, + class_id: ClassId, + class: RawExecutableClass, + ) -> FsClassStorageResult<()> { + // Write class to a temporary directory. + let tmp_dir = create_tmp_dir()?; + let tmp_dir = tmp_dir.path().join(self.get_class_dir(class_id)); + class.write_to_file(concat_deprecated_executable_filename(&tmp_dir))?; + + // Atomically rename directory to persistent one. + let persistent_dir = self.get_persistent_dir_with_create(class_id)?; + std::fs::rename(tmp_dir, persistent_dir)?; + + Ok(()) + } +} + +impl ClassStorage for FsClassStorage { + type Error = FsClassStorageError; + + #[instrument(skip(self, class, executable_class), level = "debug", ret, err)] + fn set_class( + &mut self, + class_id: ClassId, + class: RawClass, + executable_class_hash: ExecutableClassHash, + executable_class: RawExecutableClass, + ) -> Result<(), Self::Error> { + if self.contains_class(class_id)? { + return Ok(()); + } + + self.write_class(class_id, class, executable_class)?; + self.mark_class_id_as_existent(class_id, executable_class_hash)?; + + Ok(()) + } + + #[instrument(skip(self), level = "debug", err)] + fn get_sierra(&self, class_id: ClassId) -> Result, Self::Error> { + if !self.contains_class(class_id)? { + return Ok(None); + } + + let path = self.get_sierra_path(class_id); + let class = + RawClass::from_file(path)?.ok_or(FsClassStorageError::ClassNotFound { class_id })?; + + Ok(Some(class)) + } + + #[instrument(skip(self), level = "debug", err)] + fn get_executable(&self, class_id: ClassId) -> Result, Self::Error> { + let path = if self.contains_class(class_id)? { + self.get_executable_path(class_id) + } else if self.contains_deprecated_class(class_id) { + self.get_deprecated_executable_path(class_id) + } else { + // Class does not exist in storage. + return Ok(None); + }; + + let class = RawExecutableClass::from_file(path)? + .ok_or(FsClassStorageError::ClassNotFound { class_id })?; + Ok(Some(class)) + } + + #[instrument(skip(self), level = "debug", err)] + fn get_executable_class_hash( + &self, + class_id: ClassId, + ) -> Result, Self::Error> { + Ok(self.class_hash_storage.get_executable_class_hash(class_id)?) + } + + #[instrument(skip(self, class), level = "debug", ret, err)] + fn set_deprecated_class( + &mut self, + class_id: ClassId, + class: RawExecutableClass, + ) -> Result<(), Self::Error> { + if self.contains_deprecated_class(class_id) { + return Ok(()); + } + + self.write_deprecated_class(class_id, class)?; + + Ok(()) + } + + #[instrument(skip(self), level = "debug", err)] + fn get_deprecated_class( + &self, + class_id: ClassId, + ) -> Result, Self::Error> { + if !self.contains_deprecated_class(class_id) { + return Ok(None); + } + + let path = self.get_deprecated_executable_path(class_id); + let class = RawExecutableClass::from_file(path)? + .ok_or(FsClassStorageError::ClassNotFound { class_id })?; + + Ok(Some(class)) + } +} + +impl PartialEq for FsClassStorageError { + fn eq(&self, other: &Self) -> bool { + // Only compare enum variants; no need to compare the error values. + mem::discriminant(self) == mem::discriminant(other) + } +} + +// Utils. + +fn concat_sierra_filename(path: &Path) -> PathBuf { + path.join("sierra") +} + +fn concat_executable_filename(path: &Path) -> PathBuf { + path.join("casm") +} + +fn concat_deprecated_executable_filename(path: &Path) -> PathBuf { + path.join("deprecated_casm") +} + +// Creates a tmp directory and returns a owned representation of it. +// As long as the returned directory object is lived, the directory is not deleted. +pub(crate) fn create_tmp_dir() -> FsClassStorageResult { + Ok(tempfile::tempdir()?) +} diff --git a/crates/starknet_class_manager/src/class_storage_test.rs b/crates/starknet_class_manager/src/class_storage_test.rs new file mode 100644 index 00000000000..6a63b380e15 --- /dev/null +++ b/crates/starknet_class_manager/src/class_storage_test.rs @@ -0,0 +1,134 @@ +use starknet_api::core::{ClassHash, CompiledClassHash}; +use starknet_api::felt; +use starknet_api::state::SierraContractClass; +use starknet_sierra_multicompile_types::{RawClass, RawExecutableClass}; + +use crate::class_storage::{ + create_tmp_dir, + ClassHashStorage, + ClassHashStorageConfig, + ClassStorage, + FsClassStorage, + FsClassStorageError, +}; + +// TODO(Elin): consider creating an empty Casm instead of vec (doesn't implement default). + +#[cfg(test)] +impl ClassHashStorage { + pub fn new_for_testing(path_prefix: &tempfile::TempDir) -> Self { + let config = ClassHashStorageConfig { + path_prefix: path_prefix.path().to_path_buf(), + enforce_file_exists: false, + max_size: 1 << 20, // 1MB. + }; + Self::new(config).unwrap() + } +} + +#[cfg(test)] +impl FsClassStorage { + pub fn new_for_testing( + persistent_root: &tempfile::TempDir, + class_hash_storage_path_prefix: &tempfile::TempDir, + ) -> Self { + let class_hash_storage = ClassHashStorage::new_for_testing(class_hash_storage_path_prefix); + Self { persistent_root: persistent_root.path().to_path_buf(), class_hash_storage } + } +} + +#[test] +fn fs_storage() { + let persistent_root = create_tmp_dir().unwrap(); + let class_hash_storage_path_prefix = create_tmp_dir().unwrap(); + let mut storage = + FsClassStorage::new_for_testing(&persistent_root, &class_hash_storage_path_prefix); + + // Non-existent class. + let class_id = ClassHash(felt!("0x1234")); + assert_eq!(storage.get_sierra(class_id), Ok(None)); + assert_eq!(storage.get_executable(class_id), Ok(None)); + assert_eq!(storage.get_executable_class_hash(class_id), Ok(None)); + + // Add new class. + let class = RawClass::try_from(SierraContractClass::default()).unwrap(); + let executable_class = RawExecutableClass::new_unchecked(vec![4, 5, 6].into()); + let executable_class_hash = CompiledClassHash(felt!("0x5678")); + storage + .set_class(class_id, class.clone(), executable_class_hash, executable_class.clone()) + .unwrap(); + + // Get class. + assert_eq!(storage.get_sierra(class_id).unwrap(), Some(class.clone())); + assert_eq!(storage.get_executable(class_id).unwrap(), Some(executable_class.clone())); + assert_eq!(storage.get_executable_class_hash(class_id).unwrap(), Some(executable_class_hash)); + + // Add existing class. + storage + .set_class(class_id, class.clone(), executable_class_hash, executable_class.clone()) + .unwrap(); +} + +#[test] +fn fs_storage_deprecated_class_api() { + let persistent_root = create_tmp_dir().unwrap(); + let class_hash_storage_path_prefix = create_tmp_dir().unwrap(); + let mut storage = + FsClassStorage::new_for_testing(&persistent_root, &class_hash_storage_path_prefix); + + // Non-existent class. + let class_id = ClassHash(felt!("0x1234")); + assert_eq!(storage.get_deprecated_class(class_id), Ok(None)); + + // Add new class. + let executable_class = RawExecutableClass::new_unchecked(vec![4, 5, 6].into()); + storage.set_deprecated_class(class_id, executable_class.clone()).unwrap(); + + // Get class. + assert_eq!(storage.get_deprecated_class(class_id).unwrap(), Some(executable_class.clone())); + + // Add existing class. + storage.set_deprecated_class(class_id, executable_class).unwrap(); +} + +// TODO(Elin): check a nonexistent persistent root (should be created). +// TODO(Elin): add unimplemented skeletons for test above and rest of missing tests. + +/// This scenario simulates a (manual) DB corruption; e.g., files were deleted. +// TODO(Elin): should this flow return an error? +#[test] +fn fs_storage_partial_write_only_atomic_marker() { + let persistent_root = create_tmp_dir().unwrap(); + let class_hash_storage_path_prefix = create_tmp_dir().unwrap(); + let mut storage = + FsClassStorage::new_for_testing(&persistent_root, &class_hash_storage_path_prefix); + + // Write only atomic marker, no class files. + let class_id = ClassHash(felt!("0x1234")); + let executable_class_hash = CompiledClassHash(felt!("0x5678")); + storage.mark_class_id_as_existent(class_id, executable_class_hash).unwrap(); + + // Query class, should be considered an erroneous flow. + let class_not_found_error = FsClassStorageError::ClassNotFound { class_id }; + assert_eq!(storage.get_sierra(class_id).unwrap_err(), class_not_found_error); + assert_eq!(storage.get_executable(class_id).unwrap_err(), class_not_found_error); +} + +#[test] +fn fs_storage_partial_write_no_atomic_marker() { + let persistent_root = create_tmp_dir().unwrap(); + let class_hash_storage_path_prefix = create_tmp_dir().unwrap(); + let storage = + FsClassStorage::new_for_testing(&persistent_root, &class_hash_storage_path_prefix); + + // Fully write class files, without atomic marker. + let class_id = ClassHash(felt!("0x1234")); + let class = RawClass::try_from(SierraContractClass::default()).unwrap(); + let executable_class = RawExecutableClass::new_unchecked(vec![4, 5, 6].into()); + storage.write_class_atomically(class_id, class, executable_class).unwrap(); + assert_eq!(storage.get_executable_class_hash(class_id), Ok(None)); + + // Query class, should be considered non-existent. + assert_eq!(storage.get_sierra(class_id), Ok(None)); + assert_eq!(storage.get_executable(class_id), Ok(None)); +} diff --git a/crates/starknet_class_manager/src/communication.rs b/crates/starknet_class_manager/src/communication.rs new file mode 100644 index 00000000000..bd26caf4536 --- /dev/null +++ b/crates/starknet_class_manager/src/communication.rs @@ -0,0 +1,58 @@ +use async_trait::async_trait; +use starknet_api::contract_class::ContractClass; +use starknet_class_manager_types::{ClassManagerRequest, ClassManagerResponse}; +use starknet_sequencer_infra::component_definitions::ComponentRequestHandler; +use starknet_sequencer_infra::component_server::{LocalComponentServer, RemoteComponentServer}; + +use crate::ClassManager; + +pub type LocalClassManagerServer = + LocalComponentServer; +pub type RemoteClassManagerServer = + RemoteComponentServer; + +// TODO(Elin): change the request and response the server sees to raw types; remove conversions and +// unwraps. +#[async_trait] +impl ComponentRequestHandler for ClassManager { + async fn handle_request(&mut self, request: ClassManagerRequest) -> ClassManagerResponse { + match request { + ClassManagerRequest::AddClass(class) => { + ClassManagerResponse::AddClass(self.0.add_class(class.try_into().unwrap()).await) + } + ClassManagerRequest::AddClassAndExecutableUnsafe( + class_id, + class, + executable_class_id, + executable_class, + ) => ClassManagerResponse::AddClassAndExecutableUnsafe( + self.0.add_class_and_executable_unsafe( + class_id, + class.try_into().unwrap(), + executable_class_id, + executable_class.try_into().unwrap(), + ), + ), + ClassManagerRequest::AddDeprecatedClass(class_id, class) => { + let class = ContractClass::V0(class).try_into().unwrap(); + ClassManagerResponse::AddDeprecatedClass( + self.0.add_deprecated_class(class_id, class), + ) + } + ClassManagerRequest::GetExecutable(class_id) => { + let result = self + .0 + .get_executable(class_id) + .map(|optional_class| optional_class.map(|class| class.try_into().unwrap())); + ClassManagerResponse::GetExecutable(result) + } + ClassManagerRequest::GetSierra(class_id) => { + let result = self + .0 + .get_sierra(class_id) + .map(|optional_class| optional_class.map(|class| class.try_into().unwrap())); + ClassManagerResponse::GetSierra(result) + } + } + } +} diff --git a/crates/starknet_class_manager/src/config.rs b/crates/starknet_class_manager/src/config.rs new file mode 100644 index 00000000000..52b45d191c3 --- /dev/null +++ b/crates/starknet_class_manager/src/config.rs @@ -0,0 +1,119 @@ +use std::collections::BTreeMap; +use std::path::PathBuf; + +use papyrus_config::dumping::{append_sub_config_name, ser_param, SerializeConfig}; +use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; +use serde::{Deserialize, Serialize}; +use validator::Validate; + +use crate::class_storage::CachedClassStorageConfig; + +#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +pub struct ClassHashStorageConfig { + pub path_prefix: PathBuf, + pub enforce_file_exists: bool, + pub max_size: usize, +} + +impl Default for ClassHashStorageConfig { + fn default() -> Self { + Self { + path_prefix: "/data/class_hash_storage".into(), + enforce_file_exists: false, + max_size: 1 << 20, // 1MB. + } + } +} + +impl SerializeConfig for ClassHashStorageConfig { + fn dump(&self) -> BTreeMap { + BTreeMap::from([ + ser_param( + "path_prefix", + &self.path_prefix, + "Prefix of the path of class hash storage directory.", + ParamPrivacyInput::Public, + ), + ser_param( + "enforce_file_exists", + &self.enforce_file_exists, + "Whether to enforce that the above path exists.", + ParamPrivacyInput::Public, + ), + ser_param( + "max_size", + &self.max_size, + "The maximum size of the class hash storage in bytes.", + ParamPrivacyInput::Public, + ), + ]) + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +pub struct FsClassStorageConfig { + pub persistent_root: PathBuf, + pub class_hash_storage_config: ClassHashStorageConfig, +} + +impl Default for FsClassStorageConfig { + fn default() -> Self { + Self { + persistent_root: "/data/classes".into(), + class_hash_storage_config: Default::default(), + } + } +} + +impl SerializeConfig for FsClassStorageConfig { + fn dump(&self) -> BTreeMap { + let mut dump = BTreeMap::from([ser_param( + "persistent_root", + &self.persistent_root, + "Path to the node's class storage directory.", + ParamPrivacyInput::Public, + )]); + dump.append(&mut append_sub_config_name( + self.class_hash_storage_config.dump(), + "class_hash_storage_config", + )); + dump + } +} + +#[derive(Clone, Debug, Default, Serialize, Deserialize, Validate, PartialEq)] +pub struct ClassManagerConfig { + pub cached_class_storage_config: CachedClassStorageConfig, +} + +impl SerializeConfig for ClassManagerConfig { + fn dump(&self) -> BTreeMap { + let mut dump = BTreeMap::new(); + dump.append(&mut append_sub_config_name( + self.cached_class_storage_config.dump(), + "cached_class_storage_config", + )); + dump + } +} + +#[derive(Clone, Debug, Default, Serialize, Deserialize, Validate, PartialEq)] +pub struct FsClassManagerConfig { + pub class_manager_config: ClassManagerConfig, + pub class_storage_config: FsClassStorageConfig, +} + +impl SerializeConfig for FsClassManagerConfig { + fn dump(&self) -> BTreeMap { + let mut dump = BTreeMap::new(); + dump.append(&mut append_sub_config_name( + self.class_manager_config.dump(), + "class_manager_config", + )); + dump.append(&mut append_sub_config_name( + self.class_storage_config.dump(), + "class_storage_config", + )); + dump + } +} diff --git a/crates/starknet_class_manager/src/lib.rs b/crates/starknet_class_manager/src/lib.rs new file mode 100644 index 00000000000..c9a6e6a3c3d --- /dev/null +++ b/crates/starknet_class_manager/src/lib.rs @@ -0,0 +1,27 @@ +pub mod class_manager; +pub mod class_storage; +pub mod communication; +pub mod config; +pub mod metrics; + +use crate::class_manager::ClassManager as GenericClassManager; +use crate::class_storage::FsClassStorage; + +pub struct FsClassManager(pub GenericClassManager); + +impl Clone for FsClassManager { + fn clone(&self) -> Self { + let GenericClassManager { config, compiler, classes } = &self.0; + + FsClassManager(GenericClassManager { + config: config.clone(), + compiler: compiler.clone(), + classes: classes.clone(), + }) + } +} + +pub use FsClassManager as ClassManager; + +#[cfg(any(feature = "testing", test))] +pub mod test_utils; diff --git a/crates/starknet_class_manager/src/metrics.rs b/crates/starknet_class_manager/src/metrics.rs new file mode 100644 index 00000000000..8c7400d37c9 --- /dev/null +++ b/crates/starknet_class_manager/src/metrics.rs @@ -0,0 +1,76 @@ +use starknet_sequencer_metrics::metrics::{LabeledMetricCounter, LabeledMetricHistogram}; +use starknet_sequencer_metrics::{define_metrics, generate_permutation_labels}; +use starknet_sierra_multicompile_types::SerializedClass; +use strum::VariantNames; + +const CAIRO_CLASS_TYPE_LABEL: &str = "class_type"; + +#[derive(strum_macros::EnumVariantNames, strum_macros::IntoStaticStr)] +#[strum(serialize_all = "snake_case")] +pub(crate) enum CairoClassType { + Regular, + Deprecated, +} + +generate_permutation_labels! { + CAIRO_CLASS_TYPE_LABELS, + (CAIRO_CLASS_TYPE_LABEL, CairoClassType), +} + +const CLASS_OBJECT_TYPE_LABEL: &str = "class_object_type"; + +#[derive( + Debug, strum_macros::Display, strum_macros::EnumVariantNames, strum_macros::IntoStaticStr, +)] +#[strum(serialize_all = "snake_case")] +pub(crate) enum ClassObjectType { + Sierra, + Casm, + DeprecatedCasm, +} + +generate_permutation_labels! { + CLASS_OBJECT_TYPE_LABELS, + (CLASS_OBJECT_TYPE_LABEL, ClassObjectType), +} + +define_metrics!( + ClassManager => { + LabeledMetricCounter { + N_CLASSES, + "class_manager_n_classes", "Number of classes, by label (regular, deprecated)", + init = 0 , + labels = CAIRO_CLASS_TYPE_LABELS + }, + LabeledMetricHistogram { + CLASS_SIZES, + "class_manager_class_sizes", + "Size of the classes in bytes, labeled by type (sierra, casm, deprecated casm)", + labels = CLASS_OBJECT_TYPE_LABELS + }, + }, +); + +pub(crate) fn increment_n_classes(cls_type: CairoClassType) { + N_CLASSES.increment(1, &[(CAIRO_CLASS_TYPE_LABEL, cls_type.into())]); +} + +pub(crate) fn record_class_size(class_type: ClassObjectType, class: &SerializedClass) { + let class_size = class.size().unwrap_or_else(|_| { + panic!("Illegally formatted {} class, should not have gotten into the system.", class_type) + }); + let class_size = u32::try_from(class_size).unwrap_or_else(|_| { + panic!( + "{} class size {} is bigger than what is allowed, + should not have gotten into the system.", + class_type, class_size + ) + }); + + CLASS_SIZES.record(class_size, &[(CLASS_OBJECT_TYPE_LABEL, class_type.into())]); +} + +pub(crate) fn register_metrics() { + N_CLASSES.register(); + CLASS_SIZES.register(); +} diff --git a/crates/starknet_class_manager/src/test_utils.rs b/crates/starknet_class_manager/src/test_utils.rs new file mode 100644 index 00000000000..c34bb3de982 --- /dev/null +++ b/crates/starknet_class_manager/src/test_utils.rs @@ -0,0 +1,52 @@ +use std::path::PathBuf; + +use tempfile::TempDir; + +use crate::class_storage::{ClassHashStorage, FsClassStorage}; +use crate::config::{ClassHashStorageConfig, FsClassStorageConfig}; + +pub type FileHandles = (TempDir, TempDir); + +pub struct FsClassStorageBuilderForTesting { + config: FsClassStorageConfig, + handles: Option, +} + +impl Default for FsClassStorageBuilderForTesting { + fn default() -> Self { + let class_hash_storage_handle = tempfile::tempdir().unwrap(); + let persistent_root_handle = tempfile::tempdir().unwrap(); + let persistent_root = persistent_root_handle.path().to_path_buf(); + let config = FsClassStorageConfig { + persistent_root, + class_hash_storage_config: ClassHashStorageConfig { + path_prefix: class_hash_storage_handle.path().to_path_buf(), + enforce_file_exists: false, + max_size: 1 << 20, // 1MB. + }, + }; + Self { config, handles: Some((class_hash_storage_handle, persistent_root_handle)) } + } +} + +impl FsClassStorageBuilderForTesting { + pub fn with_existing_paths( + mut self, + class_hash_storage_path_prefix: PathBuf, + persistent_path: PathBuf, + ) -> Self { + self.config.class_hash_storage_config.path_prefix = class_hash_storage_path_prefix; + self.config.persistent_root = persistent_path; + self.handles = None; + self + } + + pub fn build(self) -> (FsClassStorage, FsClassStorageConfig, Option) { + let Self { config, handles } = self; + let class_hash_storage = + ClassHashStorage::new(config.class_hash_storage_config.clone()).unwrap(); + let fs_class_storage = + FsClassStorage { persistent_root: config.persistent_root.clone(), class_hash_storage }; + (fs_class_storage, config, handles) + } +} diff --git a/crates/starknet_class_manager_types/Cargo.toml b/crates/starknet_class_manager_types/Cargo.toml new file mode 100644 index 00000000000..9dae821fcc4 --- /dev/null +++ b/crates/starknet_class_manager_types/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "starknet_class_manager_types" +edition.workspace = true +license.workspace = true +repository.workspace = true +version.workspace = true + +[features] +testing = ["mockall"] + +[lints] +workspace = true + +[dependencies] +async-trait.workspace = true +mockall = { workspace = true, optional = true } +papyrus_proc_macros.workspace = true +serde = { workspace = true, features = ["derive"] } +serde_json.workspace = true +starknet_api.workspace = true +starknet_sequencer_infra.workspace = true +starknet_sierra_multicompile_types.workspace = true +strum_macros.workspace = true +thiserror.workspace = true + +[dev-dependencies] +mockall.workspace = true +starknet_api = { workspace = true, features = ["testing"] } diff --git a/crates/starknet_class_manager_types/src/lib.rs b/crates/starknet_class_manager_types/src/lib.rs new file mode 100644 index 00000000000..ca76fdb2743 --- /dev/null +++ b/crates/starknet_class_manager_types/src/lib.rs @@ -0,0 +1,263 @@ +pub mod transaction_converter; + +use std::error::Error; +use std::sync::Arc; + +use async_trait::async_trait; +#[cfg(feature = "testing")] +use mockall::automock; +use papyrus_proc_macros::handle_all_response_variants; +use serde::{Deserialize, Serialize}; +use starknet_api::contract_class::ContractClass; +use starknet_api::core::{ClassHash, CompiledClassHash}; +use starknet_api::deprecated_contract_class::ContractClass as DeprecatedClass; +use starknet_api::state::SierraContractClass; +use starknet_sequencer_infra::component_client::{ + ClientError, + LocalComponentClient, + RemoteComponentClient, +}; +use starknet_sequencer_infra::component_definitions::{ + ComponentClient, + ComponentRequestAndResponseSender, +}; +use starknet_sequencer_infra::impl_debug_for_infra_requests_and_responses; +use starknet_sierra_multicompile_types::SierraCompilerError; +use strum_macros::AsRefStr; +use thiserror::Error; + +pub type ClassManagerResult = Result; +pub type ClassManagerClientResult = Result; + +pub type LocalClassManagerClient = LocalComponentClient; +pub type RemoteClassManagerClient = + RemoteComponentClient; + +pub type SharedClassManagerClient = Arc; +pub type ClassManagerRequestAndResponseSender = + ComponentRequestAndResponseSender; + +// TODO(Elin): export. +pub type ClassId = ClassHash; +pub type Class = SierraContractClass; +pub type ExecutableClass = ContractClass; +pub type ExecutableClassHash = CompiledClassHash; + +#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] +pub struct ClassHashes { + pub class_hash: ClassHash, + pub executable_class_hash: ExecutableClassHash, +} + +/// Serves as the class manager's shared interface. +/// Requires `Send + Sync` to allow transferring and sharing resources (inputs, futures) across +/// threads. +#[cfg_attr(feature = "testing", automock)] +#[async_trait] +pub trait ClassManagerClient: Send + Sync { + async fn add_class(&self, class: Class) -> ClassManagerClientResult; + + // TODO(Elin): separate V0 and V1 APIs; remove Sierra version. + async fn get_executable( + &self, + class_id: ClassId, + ) -> ClassManagerClientResult>; + + async fn get_sierra(&self, class_id: ClassId) -> ClassManagerClientResult>; + + async fn add_deprecated_class( + &self, + class_id: ClassId, + class: DeprecatedClass, + ) -> ClassManagerClientResult<()>; + + // This method should only be used through state sync. + // It acts as a writer to the class storage, and bypasses compilation - thus unsafe. + async fn add_class_and_executable_unsafe( + &self, + class_id: ClassId, + class: Class, + executable_class_id: ExecutableClassHash, + executable_class: ExecutableClass, + ) -> ClassManagerClientResult<()>; +} + +#[derive(Clone, Debug, Error, Eq, PartialEq, Serialize, Deserialize)] +pub enum CachedClassStorageError { + // TODO(Elin): remove from, it's too permissive. + #[error(transparent)] + Storage(#[from] E), +} + +#[derive(Clone, Debug, Error, Eq, PartialEq, Serialize, Deserialize)] +pub enum ClassManagerError { + #[error("Internal client error: {0}")] + Client(String), + #[error("Failed to deserialize Sierra class: {0}")] + ClassSerde(String), + #[error("Class storage error: {0}")] + ClassStorage(String), + #[error("Sierra compiler error for class hash {class_hash}: {error}")] + SierraCompiler { + class_hash: ClassHash, + #[source] + error: SierraCompilerError, + }, +} + +impl From> for ClassManagerError { + fn from(error: CachedClassStorageError) -> Self { + ClassManagerError::ClassStorage(error.to_string()) + } +} + +impl From for ClassManagerError { + fn from(error: serde_json::Error) -> Self { + ClassManagerError::ClassSerde(error.to_string()) + } +} + +#[derive(Clone, Debug, Error)] +pub enum ClassManagerClientError { + #[error(transparent)] + ClientError(#[from] ClientError), + #[error(transparent)] + ClassManagerError(#[from] ClassManagerError), +} + +#[derive(Clone, Serialize, Deserialize, AsRefStr)] +pub enum ClassManagerRequest { + AddClass(Class), + AddClassAndExecutableUnsafe(ClassId, Class, ExecutableClassHash, ExecutableClass), + AddDeprecatedClass(ClassId, DeprecatedClass), + GetExecutable(ClassId), + GetSierra(ClassId), +} +impl_debug_for_infra_requests_and_responses!(ClassManagerRequest); + +#[derive(Clone, Serialize, Deserialize, AsRefStr)] +pub enum ClassManagerResponse { + AddClass(ClassManagerResult), + AddClassAndExecutableUnsafe(ClassManagerResult<()>), + AddDeprecatedClass(ClassManagerResult<()>), + GetExecutable(ClassManagerResult>), + GetSierra(ClassManagerResult>), +} +impl_debug_for_infra_requests_and_responses!(ClassManagerResponse); + +#[async_trait] +impl ClassManagerClient for ComponentClientType +where + ComponentClientType: Send + Sync + ComponentClient, +{ + async fn add_class(&self, class: Class) -> ClassManagerClientResult { + let request = ClassManagerRequest::AddClass(class); + handle_all_response_variants!( + ClassManagerResponse, + AddClass, + ClassManagerClientError, + ClassManagerError, + Direct + ) + } + + async fn add_deprecated_class( + &self, + class_id: ClassId, + class: DeprecatedClass, + ) -> ClassManagerClientResult<()> { + let request = ClassManagerRequest::AddDeprecatedClass(class_id, class); + handle_all_response_variants!( + ClassManagerResponse, + AddDeprecatedClass, + ClassManagerClientError, + ClassManagerError, + Direct + ) + } + + async fn get_executable( + &self, + class_id: ClassId, + ) -> ClassManagerClientResult> { + let request = ClassManagerRequest::GetExecutable(class_id); + handle_all_response_variants!( + ClassManagerResponse, + GetExecutable, + ClassManagerClientError, + ClassManagerError, + Direct + ) + } + + async fn get_sierra(&self, class_id: ClassId) -> ClassManagerClientResult> { + let request = ClassManagerRequest::GetSierra(class_id); + handle_all_response_variants!( + ClassManagerResponse, + GetSierra, + ClassManagerClientError, + ClassManagerError, + Direct + ) + } + + async fn add_class_and_executable_unsafe( + &self, + class_id: ClassId, + class: Class, + executable_class_id: ExecutableClassHash, + executable_class: ExecutableClass, + ) -> ClassManagerClientResult<()> { + let request = ClassManagerRequest::AddClassAndExecutableUnsafe( + class_id, + class, + executable_class_id, + executable_class, + ); + handle_all_response_variants!( + ClassManagerResponse, + AddClassAndExecutableUnsafe, + ClassManagerClientError, + ClassManagerError, + Direct + ) + } +} + +pub struct EmptyClassManagerClient; + +#[async_trait] +impl ClassManagerClient for EmptyClassManagerClient { + async fn add_class(&self, _class: Class) -> ClassManagerClientResult { + Ok(Default::default()) + } + + async fn add_deprecated_class( + &self, + _class_id: ClassId, + _class: DeprecatedClass, + ) -> ClassManagerClientResult<()> { + Ok(()) + } + + async fn get_executable( + &self, + _class_id: ClassId, + ) -> ClassManagerClientResult> { + Ok(Some(ExecutableClass::V0(Default::default()))) + } + + async fn get_sierra(&self, _class_id: ClassId) -> ClassManagerClientResult> { + Ok(Some(Default::default())) + } + + async fn add_class_and_executable_unsafe( + &self, + _class_id: ClassId, + _class: Class, + _executable_class_id: ExecutableClassHash, + _executable_class: ExecutableClass, + ) -> ClassManagerClientResult<()> { + Ok(()) + } +} diff --git a/crates/starknet_class_manager_types/src/transaction_converter.rs b/crates/starknet_class_manager_types/src/transaction_converter.rs new file mode 100644 index 00000000000..a4c312f1c7b --- /dev/null +++ b/crates/starknet_class_manager_types/src/transaction_converter.rs @@ -0,0 +1,270 @@ +use std::str::FromStr; + +use async_trait::async_trait; +#[cfg(any(feature = "testing", test))] +use mockall::automock; +use starknet_api::consensus_transaction::{ConsensusTransaction, InternalConsensusTransaction}; +use starknet_api::contract_class::{ClassInfo, ContractClass, SierraVersion}; +use starknet_api::core::{ChainId, ClassHash}; +use starknet_api::executable_transaction::{ + AccountTransaction, + Transaction as ExecutableTransaction, +}; +use starknet_api::rpc_transaction::{ + InternalRpcDeclareTransactionV3, + InternalRpcDeployAccountTransaction, + InternalRpcTransaction, + InternalRpcTransactionWithoutTxHash, + RpcDeclareTransaction, + RpcDeclareTransactionV3, + RpcDeployAccountTransaction, + RpcTransaction, +}; +use starknet_api::state::SierraContractClass; +use starknet_api::transaction::fields::Fee; +use starknet_api::transaction::{CalculateContractAddress, TransactionHasher, TransactionVersion}; +use starknet_api::{executable_transaction, transaction, StarknetApiError}; +use thiserror::Error; + +use crate::{ClassHashes, ClassManagerClientError, SharedClassManagerClient}; + +#[derive(Error, Debug, Clone)] +pub enum TransactionConverterError { + #[error(transparent)] + ClassManagerClientError(#[from] ClassManagerClientError), + #[error("Class of hash: {class_hash} not found")] + ClassNotFound { class_hash: ClassHash }, + #[error(transparent)] + StarknetApiError(#[from] StarknetApiError), +} + +pub type TransactionConverterResult = Result; + +#[cfg_attr(any(test, feature = "testing"), automock)] +#[async_trait] +pub trait TransactionConverterTrait { + async fn convert_internal_consensus_tx_to_consensus_tx( + &self, + tx: InternalConsensusTransaction, + ) -> TransactionConverterResult; + + async fn convert_consensus_tx_to_internal_consensus_tx( + &self, + tx: ConsensusTransaction, + ) -> TransactionConverterResult; + + async fn convert_internal_rpc_tx_to_rpc_tx( + &self, + tx: InternalRpcTransaction, + ) -> TransactionConverterResult; + + async fn convert_rpc_tx_to_internal_rpc_tx( + &self, + tx: RpcTransaction, + ) -> TransactionConverterResult; + + async fn convert_internal_rpc_tx_to_executable_tx( + &self, + tx: InternalRpcTransaction, + ) -> TransactionConverterResult; + + async fn convert_internal_consensus_tx_to_executable_tx( + &self, + tx: InternalConsensusTransaction, + ) -> TransactionConverterResult; +} + +#[derive(Clone)] +pub struct TransactionConverter { + class_manager_client: SharedClassManagerClient, + chain_id: ChainId, +} + +impl TransactionConverter { + pub fn new(class_manager_client: SharedClassManagerClient, chain_id: ChainId) -> Self { + Self { class_manager_client, chain_id } + } + + async fn get_sierra( + &self, + class_hash: ClassHash, + ) -> TransactionConverterResult { + self.class_manager_client + .get_sierra(class_hash) + .await? + .ok_or(TransactionConverterError::ClassNotFound { class_hash }) + } + + async fn get_executable( + &self, + class_hash: ClassHash, + ) -> TransactionConverterResult { + self.class_manager_client + .get_executable(class_hash) + .await? + .ok_or(TransactionConverterError::ClassNotFound { class_hash }) + } +} + +#[async_trait] +impl TransactionConverterTrait for TransactionConverter { + async fn convert_internal_consensus_tx_to_consensus_tx( + &self, + tx: InternalConsensusTransaction, + ) -> TransactionConverterResult { + match tx { + InternalConsensusTransaction::RpcTransaction(tx) => self + .convert_internal_rpc_tx_to_rpc_tx(tx) + .await + .map(ConsensusTransaction::RpcTransaction), + InternalConsensusTransaction::L1Handler(tx) => { + Ok(ConsensusTransaction::L1Handler(tx.tx)) + } + } + } + + async fn convert_consensus_tx_to_internal_consensus_tx( + &self, + tx: ConsensusTransaction, + ) -> TransactionConverterResult { + match tx { + ConsensusTransaction::RpcTransaction(tx) => self + .convert_rpc_tx_to_internal_rpc_tx(tx) + .await + .map(InternalConsensusTransaction::RpcTransaction), + ConsensusTransaction::L1Handler(tx) => self + .convert_consensus_l1_handler_to_internal_l1_handler(tx) + .map(InternalConsensusTransaction::L1Handler), + } + } + + async fn convert_internal_rpc_tx_to_rpc_tx( + &self, + tx: InternalRpcTransaction, + ) -> TransactionConverterResult { + match tx.tx { + InternalRpcTransactionWithoutTxHash::Invoke(tx) => Ok(RpcTransaction::Invoke(tx)), + InternalRpcTransactionWithoutTxHash::Declare(tx) => { + Ok(RpcTransaction::Declare(RpcDeclareTransaction::V3(RpcDeclareTransactionV3 { + sender_address: tx.sender_address, + compiled_class_hash: tx.compiled_class_hash, + signature: tx.signature, + nonce: tx.nonce, + contract_class: self.get_sierra(tx.class_hash).await?, + resource_bounds: tx.resource_bounds, + tip: tx.tip, + paymaster_data: tx.paymaster_data, + account_deployment_data: tx.account_deployment_data, + nonce_data_availability_mode: tx.nonce_data_availability_mode, + fee_data_availability_mode: tx.fee_data_availability_mode, + }))) + } + InternalRpcTransactionWithoutTxHash::DeployAccount( + InternalRpcDeployAccountTransaction { tx, .. }, + ) => Ok(RpcTransaction::DeployAccount(tx)), + } + } + + async fn convert_rpc_tx_to_internal_rpc_tx( + &self, + tx: RpcTransaction, + ) -> TransactionConverterResult { + let tx_without_hash = match tx { + RpcTransaction::Invoke(tx) => InternalRpcTransactionWithoutTxHash::Invoke(tx), + RpcTransaction::Declare(RpcDeclareTransaction::V3(tx)) => { + let ClassHashes { class_hash, .. } = + self.class_manager_client.add_class(tx.contract_class).await?; + InternalRpcTransactionWithoutTxHash::Declare(InternalRpcDeclareTransactionV3 { + sender_address: tx.sender_address, + compiled_class_hash: tx.compiled_class_hash, + signature: tx.signature, + nonce: tx.nonce, + class_hash, + resource_bounds: tx.resource_bounds, + tip: tx.tip, + paymaster_data: tx.paymaster_data, + account_deployment_data: tx.account_deployment_data, + nonce_data_availability_mode: tx.nonce_data_availability_mode, + fee_data_availability_mode: tx.fee_data_availability_mode, + }) + } + RpcTransaction::DeployAccount(RpcDeployAccountTransaction::V3(tx)) => { + let contract_address = tx.calculate_contract_address()?; + InternalRpcTransactionWithoutTxHash::DeployAccount( + InternalRpcDeployAccountTransaction { + tx: RpcDeployAccountTransaction::V3(tx), + contract_address, + }, + ) + } + }; + let tx_hash = tx_without_hash.calculate_transaction_hash(&self.chain_id)?; + + Ok(InternalRpcTransaction { tx: tx_without_hash, tx_hash }) + } + + async fn convert_internal_rpc_tx_to_executable_tx( + &self, + InternalRpcTransaction { tx, tx_hash }: InternalRpcTransaction, + ) -> TransactionConverterResult { + match tx { + InternalRpcTransactionWithoutTxHash::Invoke(tx) => { + Ok(AccountTransaction::Invoke(executable_transaction::InvokeTransaction { + tx: tx.into(), + tx_hash, + })) + } + InternalRpcTransactionWithoutTxHash::Declare(tx) => { + let sierra = self.get_sierra(tx.class_hash).await?; + let class_info = ClassInfo { + contract_class: self.get_executable(tx.class_hash).await?, + sierra_program_length: sierra.sierra_program.len(), + abi_length: sierra.abi.len(), + sierra_version: SierraVersion::from_str(&sierra.contract_class_version)?, + }; + + Ok(AccountTransaction::Declare(executable_transaction::DeclareTransaction { + tx: tx.into(), + tx_hash, + class_info, + })) + } + InternalRpcTransactionWithoutTxHash::DeployAccount( + InternalRpcDeployAccountTransaction { tx, contract_address }, + ) => Ok(AccountTransaction::DeployAccount( + executable_transaction::DeployAccountTransaction { + tx: tx.into(), + contract_address, + tx_hash, + }, + )), + } + } + + async fn convert_internal_consensus_tx_to_executable_tx( + &self, + tx: InternalConsensusTransaction, + ) -> TransactionConverterResult { + match tx { + InternalConsensusTransaction::RpcTransaction(tx) => Ok(ExecutableTransaction::Account( + self.convert_internal_rpc_tx_to_executable_tx(tx).await?, + )), + InternalConsensusTransaction::L1Handler(tx) => Ok(ExecutableTransaction::L1Handler(tx)), + } + } +} + +impl TransactionConverter { + fn convert_consensus_l1_handler_to_internal_l1_handler( + &self, + tx: transaction::L1HandlerTransaction, + ) -> TransactionConverterResult { + let tx_hash = tx.calculate_transaction_hash(&self.chain_id, &TransactionVersion::ZERO)?; + Ok(executable_transaction::L1HandlerTransaction { + tx, + tx_hash, + // TODO(Gilad): Change this once we put real value in paid_fee_on_l1. + paid_fee_on_l1: Fee(1), + }) + } +} diff --git a/crates/starknet_client/Cargo.toml b/crates/starknet_client/Cargo.toml index e326d8545f1..0541d57b060 100644 --- a/crates/starknet_client/Cargo.toml +++ b/crates/starknet_client/Cargo.toml @@ -40,7 +40,7 @@ url.workspace = true assert_matches.workspace = true enum-iterator.workspace = true mockall.workspace = true -# TODO: Upgrade to workspace-defined version. +# TODO(Dori): Upgrade to workspace-defined version. mockito = "0.31.0" rand.workspace = true rand_chacha.workspace = true diff --git a/crates/starknet_client/resources/reader/block_post_0_13_2.json b/crates/starknet_client/resources/reader/block_post_0_13_2.json index cfe34fe17a1..02aceb4c271 100644 --- a/crates/starknet_client/resources/reader/block_post_0_13_2.json +++ b/crates/starknet_client/resources/reader/block_post_0_13_2.json @@ -1 +1,6058 @@ -{"block_hash": "0x3dbd0429c01b03d63e34ecc0ab4be6aca8273b31b3158620d05934505d18f4b", "parent_block_hash": "0x402b35df0b7fb31bb310325bf85dd6bc12b588055022d3a9d4ac3fbf8b42b41", "block_number": 36668, "state_root": "0x484fc02b288a87fdcdb3f02fe4eda8dda4c555337d6a61979c07704a3f6164b", "transaction_commitment": "0x35f006aa7326d9e864c2db098659e7d35a07a7c1b3db1de55207d3d11f1c735", "event_commitment": "0x3092f43797271ca31c806e0697ec177d5da5f99ab5098b09b5037c753385662", "receipt_commitment": "0x88edeaeb2de4fbb2ba1c04517f9c6b50becfa818daec1b71fcb99f9183f096", "state_diff_commitment": "0xa256c205a4e07f054c438de3bfa7bb5961b43019dbf9533a9582a320920dec", "state_diff_length": 66, "status": "ACCEPTED_ON_L2", "l1_da_mode": "BLOB", "l1_gas_price": {"price_in_wei": "0x361f0fd75", "price_in_fri": "0x47612b5790fa"}, "l1_data_gas_price": {"price_in_wei": "0x186a0", "price_in_fri": "0x8a7b81"}, "transactions": [{"transaction_hash": "0x195e0414c0c8dea28fde9944a71bd97abea493826d302e2030d9c0249985237", "version": "0x3", "signature": ["0x3ce127060dc268a191c07780afa0807ae246a0b14cc6fa16edbe32cbe87bb34", "0x7b80f068920dd9b95feecf5d5932c94dc1c89216fc581fb26624b475c80a138"], "nonce": "0x2ae1", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x6", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", "0x2", "0x6d6a4e9fe18b132978fdd5e46bc2e5de", "0x7521e0f1bf2330ab3788f08afaf8e7c2", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", "0x2", "0x60c3d56dd59b7edd528ef2e9eeb2961e8a2d6807d922de1e0067e82f6bdfca1", "0x4a28aa6a713c7dd557e71ac860d5406df0a791a49b8ac9e81d1e775a445d888", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", "0x6", "0x54ac7e24b2048fc11c6acd60e4ed10c43867d240968fcb8feee8456ce1834a", "0x3", "0x1effc638ac1dab44be3251b9481fa6ae5e793a5d863f930254153a071238556", "0x60842344c544cebb67f822fce41f409047aad7e83499960b970dba7874a7992", "0x513f6b8d4f96f5e5c02df23e7b78a775188d2754cfa27aab1aae350be8ec776", "0x408b63c6262dc25ff65e7cb99a58fa49ae28d666fc9a478ac455266e17327ba", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", "0x0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0xf818e4530ec36b83dfe702489b4df537308c3b798b0cc120e32c2056d68b7d", "0x0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", "0x1", "0x37f2bff5f371f9d1654185f60489c943c3887b1436f474ffff8b2d7c82c42b9"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x4000d1e50af1fff8150bb5fd8558a5146952171804ba967358a5fe0e6b0e354", "version": "0x1", "max_fee": "0x354a6ba7a18000", "signature": ["0x723e94abacdd257f4e1ad09babc2d3b63f4e6df2a835f5dd7c7cf17a7d73358", "0x4b49195c54998a7858cf8b3843f1e1761103de90cd4ec141cd02be90c1bd9a9"], "nonce": "0x2ae2", "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x5", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0xfddf1b880b5e97ebd26e578922b072ff", "0x32f4a2bac28b127febd90114a9648429", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x1", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x1", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0xf818e4530ec36b83dfe702489b4df537308c3b798b0cc120e32c2056d68b7d", "0x0"], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x1d5adbb883c7a0bca0f77ae2dfdce4ad0e1a74098c19042c8e4e62fa85fffdb", "version": "0x3", "signature": ["0x3bcaf664e502ba8489d1ad3bd3eee56045e7a26f361106c852990e9297554d3", "0x3ede44d898ea01d0664efb95689687aaced6031c5535cfa610968aeff59712f"], "nonce": "0x2ae3", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x6", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", "0x6", "0x2efe3ae7f7d837b89fdecbf7b7945ce3b25aaf05af34e1efb05e0547f1ee386", "0x3", "0x1f079c6646bc296715cd4dd16aa925ce5b0d3b4451f8a9bbc4cbc640f597028", "0x33010c7c261820fde09299468cdf37a9eb00a24996974d064e99dfa773be529", "0x1e03394ec22f3057f33e71f64aea7bee380e434c102e428e7b371453cba01a6", "0x72d8c487fd248ed4566cb000092832ffc6ac4ed03ac754279590f8f6de869dd", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x241f3ff573208515225eb136d2132bb89bd593e4c844225ead202a1657cfe64", "0x0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", "0x2", "0x20450dc34392f80c21d9a73bfdc53dae968838c5621e9bed6860000a0bce67c", "0x619629bfe0e29c1d2377a2bf1fe7708ec5b9f33584eb86d5b76c584226d8731", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x169f135eddda5ab51886052d777a57f2ea9c162d713691b5e04a6d4ed71d47f", "0x4", "0x19de7881922dbc95846b1bb9464dba34046c46470cfb5e18b4cb2892fd4111f", "0x4afe15fffeb973192d6336002beb80b85d9fc06df693eb8c756c9832767010d", "0x0", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", "0x6", "0x503e8a1838da4c1f6cc8f5034720744ea17fb42cea8fff5325cac8af867a31e", "0x3", "0x5a42ab0819e4fb5af67cfbc5c7cee60add07d61dba6c4872f9bdfa8b8db7e0f", "0x2935ea46f5da5df3e0ac6c41882cfdbae828fbcc3dff634a94c2db075d94765", "0x2aa78c08c048e674553c8db20bb4dddd80a8c3dbfd25b9168adb5b8e6627eb4", "0x1676fbcd5e5f371999d54004766635c1b309e9ad6a5be0ae407a24abe3e5375"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x2a2e7175a982ddb0d1636d453692a6de9c8542b40f2230d684070aff102b31a", "version": "0x3", "signature": ["0x67c21bbcd137ee91f25893f16db3ea76626336037932bca932e1a328f19ca38", "0x38ba552743adc38f28db91d88f7c6ae9aeed91734847291c099467ddcb034cc"], "nonce": "0x2ae4", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x5", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x241f3ff573208515225eb136d2132bb89bd593e4c844225ead202a1657cfe64", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", "0x6", "0x3e24d7e4732ddf3f933bf601ee207f42004159f8a1474ab3448ecf6cca36cff", "0x3", "0x7749874b2259b32547758256b902d9b46ed2b1e066867b967ed02ba3a8fd267", "0x5bce1cd81751fa197b1583eae513f3948cf3299ad3428f76724e2af9558a7d4", "0x4f8cf745cf31a95ff415b79eb94eba142a798d1aa812fc49e108b8ee5efd260", "0x30c386c19149d593600c25b8e4f4bb25ff5e3937956a4b4d0da79fbae2ed08d", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x451a26cbcd55d2281c1b2c24445a5469d2fc16da4159c44d3b04a76579b5443", "version": "0x3", "signature": ["0x45971c6d3d85f2ad23e080793967349eecc0cb67590827566b279429b08fdb5", "0x3c590f1c44d8c2eb0fec385a7e0551ca63f1222bf6962cbba4075d2a12e9274"], "nonce": "0x2ae5", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x6", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0x6baf7f785f554a74201a8204d20dd168", "0xed9747f7b83300810b7d8bf14c10e5ea", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", "0x6", "0x5be0ead6150d49c16a6277e7290e2d949a9e99b6c4aa0a3c3abf06ced66ad19", "0x3", "0x29224b3670651d8012b718c5054731e012817da20d50f7b54c6f8092ac130cd", "0x3b644a3062bc3a55da8cc0d5bb9420d3b37124840c18423e7886c020bd85460", "0x372a463e2aca39366b207734cec5b4612ed71582f97904e31a65b16dca90b69", "0x7036f905a2b4f976fbd4f498fca008e00f650ce23677816a2778b5ce9925d2", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", "0x0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", "0x2", "0x34d66d97d435936ee2e15d9cff5081ce", "0x6efe9c17c3a7961c24596137590cc149", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x67ffd6807ec99456360431e3411ff24d94bbb7db058c5a427540720d3f23bc7", "version": "0x3", "signature": ["0x1e9fdb4ef232dbcd3a625e39057687920cd338c5783d0ffbfd053264b5c8879", "0x162e5fe6f3635e97923dc90251d33eb87b11abb9dc872ea6c82ac45feaae46a"], "nonce": "0x2ae6", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x6", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", "0x2", "0x3e8f97e2afc891afba924ca1de776225073f9acbedf3ff46d318ec902ad3653", "0x6a27839e256ca61fa43d6f348a640a7e6b21e873cf4d171070f61d61814c8db", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", "0x5", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0x27b86393c20b270fd6b92a6d10a14366", "0xc43e998da0e2e75b82c3c8bbbb7900d", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", "0x2", "0xc688868dc6e9c05aa925264946b620d5", "0x905f08f13a2d956348a95748f77a9949", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", "0x2", "0xe7a49ef55592fa6ecceff818acf7252e", "0x8f6698d47e25af7d0dc4212af51c223f", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x1", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x651b1acfa1652c7eb678979a8cd26df183dd3fe3e16ad26bf1b5c150547893", "version": "0x3", "signature": ["0x2a04435512c22dfb31d26d2d80bb1981c379380b6c5ba2d1523ccdd4adef625", "0x552b2cb8b91b3265f190e92823d0a5ee6f281c559e8fdea2840af5c8e426acc"], "nonce": "0x2ae7", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x6", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", "0x5", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", "0x2", "0x6d6e91265cf1e0bf15ff9b695e5089032c4ab616ba25c0b507d9e9f39c9ddfc", "0x5d344e352238cd5a1082aaa37b01fc392f55fa7768d779fa6cdc78ac3d50af", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", "0x3", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", "0x5", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", "0x2", "0xce2305e2a02a8fe3691c0b73a12e274e", "0x80dd5826db992b2e92710ed0bf4a9cff", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", "0x2", "0x6acbed37acf15328d3afde3f2db41c4", "0x6f119050d266f2d77ac62d0845d9fa8e"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x30b2d48fd3c80877d7c05dcdd9535ba500570f22c5c8ff2354707d78b89b511", "version": "0x3", "signature": ["0x4f64846a64b6bdc564ce3449a3d485b00640e3f59ac67af508527251512e666", "0x1d2b3c6255d8e6289009955d4add0de7dc141df953b74deffa495f9dffa5ed2"], "nonce": "0x2ae8", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x6", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", "0x6", "0x4619138d933b114b7942c93762827303aab9ff0a8b876765802ef7cb60ba658", "0x3", "0x32d345a97bc0db35ae9578aff71192bd142595afe1720056892f00c245fddf1", "0x3748f3eefc81fd923a83f9ab2d9ea2ee41378fde4de92257a067538138faba3", "0x1265c400681e1fdea145d3857b045a792a882334bf858335716c2934e189838", "0x52641747cc939c3254a8a4a226e2ab74309396b6261eb434b2e949bcab370c5", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0x9ce0c16cf9083b40dc0e72e500e99118", "0x868470928c1b10fbf5f6b398727c4a3a", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", "0x1", "0x2e6095aa6b4dfbc9127bad9819638d2ac31e6a7b7e51856915e22de5215e9c9", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", "0x1", "0x166ecda541ff4b6f1d56c431b0c9bc893740234b3d4396cf19239e871bea3d", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x24c7fb9c2336b7a3db94970c71d095b464ff25f47e4c62f505d8bd3c86a784c", "version": "0x1", "max_fee": "0x354a6ba7a18000", "signature": ["0x51635ba56525926d25a2532c894421ec0de7487381b7967cf05500f067e001f", "0x1d9e04a4b6e4d17197f3a60b3d3ae28e85e88ebdd4b23ec80405e8e6354863d"], "nonce": "0x2ae9", "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x6", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x169f135eddda5ab51886052d777a57f2ea9c162d713691b5e04a6d4ed71d47f", "0x4", "0x19de7881922dbc95846b1bb9464dba34046c46470cfb5e18b4cb2892fd4111f", "0x56a0a743d6adcf58d137f4aedba1c47c64e3b729cc8914a0568cb571ddcf82e", "0x0", "0x0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0x52608f33b0e282806213607d6fd1a5ee", "0x4cd43497a5400a9903c56faff64541ee", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", "0x2", "0x2b29a48b0e4c7e1154a2ff489bcf221d", "0xb8ad79046e47ab1412efe081278b0c68", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0x5029136950e9315e229a799b0c283edf", "0x8a5fd093d52d0defbb05aa6509d2bb97", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0xf818e4530ec36b83dfe702489b4df537308c3b798b0cc120e32c2056d68b7d", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x1", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea"], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x2f32394596d4bd1ddc5c7599ae53db8309893e1dbeadebaebb282763abcad27", "version": "0x3", "signature": ["0x381f039e10c089c82555de82f911606817fe804d87bc53b6f160a46ecd5423b", "0x35e84047d52a712493decba735e96ef0f9edeb74e37989f2c2dcb5c35ce3316"], "nonce": "0x2aea", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x6", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", "0x2", "0xc92c84ed60f70168ab73aff5fc334b3a", "0x2b83d1f0eca0d6237c171b0c105a7772", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", "0x1", "0x1b323a52436a873a171d8693d9819beb2fbb1b8120c76caa24f2917ca3dc734", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", "0x2", "0xa7c33b02d680105d8d090fb246d30398", "0xb6cf7678b04299e84d2a9bb17d067ed0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", "0x2", "0x6d95d7cddf881e0220e73cb72347595d7580a199f9ad01f3d05e82a94ac6274", "0x28b5958d742e5315361cf5a9a18b8c77af43b061b625e843e5eb30815fbbd25", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", "0x3", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0xf818e4530ec36b83dfe702489b4df537308c3b798b0cc120e32c2056d68b7d", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0xa62ee89e1402d61683d961a18e5820f42d061c9615022ada8b13c24202c688", "version": "0x3", "signature": ["0x310eae957c6b7294e1fefb4bfb5c2375ee0c22913db830f786e14ec78eb4d4e", "0x71a3fc6f5d9a56e3dcf019ac9dbf112de458f447b0ecb0eddca5c5406f83fbd"], "nonce": "0x2aeb", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x6", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", "0x0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x169f135eddda5ab51886052d777a57f2ea9c162d713691b5e04a6d4ed71d47f", "0x4", "0x19de7881922dbc95846b1bb9464dba34046c46470cfb5e18b4cb2892fd4111f", "0x6840b41c5acfa5b869fec37a14feda64b608968a1a082280d032ae772f0c1c9", "0x0", "0x0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", "0x2", "0x501be05622164d8f800fdb528bb8cc75", "0x126b3f82374b4e79ba1d340c8c8aa87b", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", "0x2", "0xf6bfbb0555b4084817d3ada8e81ad00d", "0x488f7cef15e7bb68a9e048ad3bbee2a6", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0x8ff690eee1967fc06db0ac7ef87a9725", "0xa39901da587330beb6e9f76cc316fcaf", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", "0x2", "0xab2e5c9e3c11a99ef23d8af80ef7af8", "0x62df1f09c714c713df4df8b62303a96d"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x5cc90d16fc214b41f79fb7e6eaa9d54c86c480bd575a2af7f4ad9dedba6276f", "version": "0x1", "max_fee": "0x354a6ba7a18000", "signature": ["0x4b193fb9b0c0c98bfaee15dd9d35e1f7445f5a261c31e508eab4813bd8e2bef", "0x3c6408f4aa551e2602514ccd6f061bdbb6a246ac3476f88f2216ae0f3dc97b9"], "nonce": "0x2aec", "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x5", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", "0x2", "0xac54f96fda8febb5f2f488afbfb6e79f", "0x1fde96168ea03365684f689e17d8231e", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", "0x0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0x415e95e3d4f2e68c530312ba9b31eba8", "0xd5789d771e36e8fe580461a44fd81d06", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0xae8d72177359e389bb35e3733d07b30c", "0x473dd8b3e9d9b101fa139d530e9b5ad6", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", "0x2", "0xc912174ca7fa00fb922e27436c7da7b7", "0x23f0f3ccea34390f6322981607b59f97"], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x6753e208f73a868d74312420692d12e69751e40bcf89c021119c24490ece9ad", "version": "0x3", "signature": ["0x4f5e4da4016066a6f2e92eabd256223585ffa0bef7dc60008ab7231c39ebbea", "0x455663ed4be94e9acb5281094443b253b44f0d2f24a1d613588370b38d8efec"], "nonce": "0x2aed", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x5", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0x73eaa8be337ffc377c02d3d4f45fff4e", "0x9e9021a653b662249f9d3672ffcb5525", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0xf73a434a015c2e85f5966f09428172ec", "0x508e12c93cf4f77d3db64f258f09b393", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x41bdd5c64656ccc96115120b5b05215cc995f78b1587dca49feaf4aedca2631", "version": "0x1", "max_fee": "0x354a6ba7a18000", "signature": ["0x40385e00234310f566a829c8b1e8c0df708ebb234522c6be9c34798f4a7580b", "0x4722fe54f3cb65731b3b760d80a9788b9ed7ad9935507078f050a766b292e0a"], "nonce": "0x2aee", "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x6", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", "0x1", "0x63c5c04c7765495986cd53d1a04b3ad24c3419fc68b428263dd23cadea8f778", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x1", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", "0x2", "0x668d6f7a82728a2d1571be2e7ab11e85653fad96d466954b7131b96f1ecda9b", "0x5bf3fc21b55cad5f4d84baecfc717ed9c66662e3f83bbe56b9f7f4ddd6b79d8", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", "0x2", "0xcb63e5b172188aa95829a042660f8984", "0x5b506421a5704846cbe614269e31f30a"], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x3d0d388f2810a550b11dc9f1ed6b747b3bcdbc5ba1f6c4e19a37e5360dea0f8", "version": "0x3", "signature": ["0x6f35d1dd41e804faf22711037fac4ce136f2a5543b667a6c33d716c8abc13ed", "0x2558a7b2f58c529c91786c4284b29a420134191378d6ecc44a34d446312a7ac"], "nonce": "0x2aef", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x6", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0x9d5c49cb5e2993b6bf31973fec801a9d", "0xae4ef1fad32095da2291acc7847e0a66", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x1", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", "0x2", "0x9df97bdaf3a64e6b480166eb9b8452a7", "0xd092d021fe62f52bb659963572b0fcea", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0x327eb1227f9e88e4021578d4f0c38150", "0x381066d9cd0f5516f13dcdddb93258c8", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", "0x6", "0x4b69423be6879cf6d118721dfecfab9d1afbab93c5706e6930c4bf3be81d791", "0x3", "0x49c8205ced269d1ced335d5c501e63ab4e44d98a0650fa927d280d3f7c36230", "0x54948a4b82b56b98f1cb2043401028a428c78f3f6df737d3d3a2678e733dc3d", "0x2293a32380507e57f9ef6bf716af36086f17cdfae9a369a52b2a17b1c2678d1", "0x1a94d4bbd06b900e82e700a7e4e735ebc1480d1d1ec6cbe7f7c74256481bdc"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x71789cc9d5ea16b746d857265754d21fc0686d327f46d06ddee21fdd3ca88bb", "version": "0x1", "max_fee": "0x354a6ba7a18000", "signature": ["0x43d675602666b58f44cc438542c62bdf15ae5637f85aa63e0c44b9f528c7f3", "0x25454989bc19d55d8119af8fb48781e941329f373e3886dacfb0e13de8e0a4f"], "nonce": "0x2af0", "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x6", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x3604cea1cdb094a73a31144f14a3e5861613c008e1e879939ebc4827d10cd50", "0x9", "0x19de7881922dbc95846b1bb9464dba34046c46470cfb5e18b4cb2892fd4111f", "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", "0x6", "0x212ff21302b29f74fcf5847ca85efb7ce2cc579fe69aa3ce1b234737faf2d66", "0x3", "0x6f01640f0164f58cc7dbcf8a97ed7a3eca7bf9014809d47aad40bff3390234a", "0x246c45ebaed09c37ab7268e28f8d60cc8d5dffa102ba3823b1fcf285b6b4588", "0x356d4583e6d8a026858ae2c2f7ee62a857f8373d8b8fd384220a17242af6b1a", "0x6e4ccc58a74edba65036bf4f23f2be53536fcc02c2504ca55ff794603e7c230", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x1", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0xf818e4530ec36b83dfe702489b4df537308c3b798b0cc120e32c2056d68b7d", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", "0x5", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", "0x2", "0x77585bd4bdf342d582c703ae5df0eef431ee39991ad5806dd070deab8db9b0f", "0x2e6a13f0f4d2bdfacce8e048646d90672cf7b735e753b2f2b2ff2e773da72eb", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x1", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea"], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x397df33c7aca7521db3df0052454e9d673e2f9e855c922c3e1d4cd4d12fb2bc", "version": "0x3", "signature": ["0x468bc551a3d75f078c0fd0c353f11d2807bc6cab4825185781ac116c70bebe7", "0x201e10716b45bc23596d5c99b1bf9d0a5138803927d95eb490d77f4c269eea2"], "nonce": "0x2af1", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x6", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x1", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", "0x9", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", "0x6", "0x3debf9d54b0e563b8fe4b64eedf699a24bd4bcf8b9071aa27e99f25c88ba961", "0x3", "0x87ed1ff492fe3875dd94b50e2a32f370fe02cf0e60b453b69d5fcf393d9c01", "0x11ba08688015c45ad4415d1659dea6159a8df2935983bdc41b9b5613c55f886", "0x7000994f2467389db1e940804a166053d3929fca4f14d04ed51330ee6a1f4ce", "0x534d92f74b4af9013304ee2d5610bb741d798333efc8353645846ed1ce55923", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", "0x2", "0x4eaa912c17dfc566e8f7cf853948824217556ba27c1726a43526cb3678e93b2", "0x68a2b20ce8c751bd668ceaedb9210a08e44d1e4b393568e129aa6f3b8bc2385", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x1", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0xaa3cc28d51dea8ea6658d7147ba81450", "0xa4f9ce0aec45febcae1d8e11713cb2b7"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x75e605c318963ca63a9355587cf82865227115327199a96e762c6dd7f032eed", "version": "0x3", "signature": ["0x699ce5f688a2826b036991d3f7b14fac21781092091c1fbf044c16b694bb557", "0x64cbbc0bc0e92c6bcfaee80cec70d1d38f192a3a6993007c108ec52cf9d554e"], "nonce": "0x2af2", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x5", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0x8f8e304b4b88e7158cfa3ea5ce96243e", "0xc8f3fe8a67a2ce24a461d082b85bfa5e", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", "0x2", "0x57bfdb31e2e369367448c9fb541930df20d632f53cdb89a254ff381f41a08ca", "0xeadaa29a2017bc360aed6b8df5198cc25dec6bf9c2e97b998ae552213a2450", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0xfc4416e02ca173660c83cdf571b2e963", "0x2971b0d7d000709955b00de23fd8fd26", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", "0x6", "0x5a84ba14f489e71466dbd10fbd54cb05450a0e2f38e2d99e3e587bc7cb63890", "0x3", "0x12dfd2e3413b429f95268d0d163b0fbef734358314ac2e77f6255c291c146dc", "0x144934c01839b32d64d21da2c53bcba79bf55c170700b07090d86eaa1a3650e", "0x7f1c2e64a60109d6681038d3994fea871d6507effc607342e7fef0c2d8e821d", "0x2d4c5d4309a24f6af9b956e69789d0622e01abb3fc1754d4acaee139e1f8b73", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", "0x2", "0xcc4c697513d102c2829098490331edd9e9e49255be3fca7f857477342585fb", "0x7d88d09ca676c668444c3b4277c9845fb4bd30b64b580f52e5cf3a34d91e818"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x3b2c54a4a0fb53dcb1d139fd66b0d33ef292599d5779d6fbc9869a3443b16d7", "version": "0x1", "max_fee": "0x354a6ba7a18000", "signature": ["0x5001a97a86439561183c474e136e55ddafe916fd9129b08cbf2a4414782091", "0x1467a4c87a87f09e124ebf25b1e149739f0def1fd664661d4d238e3452f1d1f"], "nonce": "0x2af3", "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x6", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", "0x3", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x1", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x1", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", "0x5", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", "0x2", "0x50fc87d9d3fede421ef5db0de74e0edca47c9a725c0a8a80477e11e6f7be4e4", "0x5d80e71e49199f68b1a97b6c87087a47fe06af9ac42b7b025f97c71834e2b3f", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", "0x6", "0x36a003b9f26f41a345836abb901c1a71fcaa586d174dea5fc1dce6b1cc5a145", "0x3", "0x344abe714959a0289fff2c0d988cda83ba46965603e7839225726fc9c34f4cb", "0x3e4c1cb040c585a1b599031d44895054534683e9f03c41f14ef4ae3eeedf9ec", "0x8d434813d65c2e95a9840421588b6888383f09a6dcfce99b1f2057c3625024", "0x7638012489a5d8385977e90846462277be161f078c1fc2cef28df749f2c30a3", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", "0x6", "0x41c145fd2ed46fc644e408743a12081e8809cd16a5f0de242f33da1aadd3436", "0x3", "0x30edb7c0d02cb69d2dc750909c6290fa6b562bace746368bbf994338fd84724", "0x43d7fee256e3c65ec0b3e30f0237933c357a0731b74303939fac965e568cb78", "0x3091b52f28583e2a23ca109b9c372e9eb0d5d976c8f17c9ebfd42f0dccdb669", "0x3d2b99dced2ebfc231a4490bdac9fca9687aa7a69ab122b18e11cf480991ba4"], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x7765195b77c0eea821a8f807f8fa022d2484d3bc848d519ea689d97c4015bff", "version": "0x3", "signature": ["0x232a9eb615f255179df3833b40ea315a6f1a65dfde8bd01108240bd4a3ba86e", "0x75578d63a7944c5a424893fa137b06e311d67773b30d339880ff19e24b88c61"], "nonce": "0x2af4", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x6", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", "0x1", "0x39c8e54cc0cd11e61804bd114b283a57a9f73ceafc2b796415383a17c50dcd9", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", "0x6", "0x6ec2cddbfdacf4cbd0108e87bb889213d139ff2e9eadf68c81157a3f0c7e769", "0x3", "0x7057660cdbeb602d9094eb34650d362c0b0d89057bc9f49163501da7c552e1f", "0x798891c19b8abaf6ee00f6a989eeea8cdfa76f3a4ad390fba68ecf9353fd687", "0x5deebf68d35fe0b2fc0f89b6c96e6e8ad88883993f9ab8ad56570f8f02d6d2a", "0x1b600bfa5682950284690b28749b0501610d87e7ae6e88fc2decd7c21765352", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", "0x2", "0x4b1646a5e3e3d1f9aac80c90c6bcd71d", "0xe41f8f46e121db5ef5497574d6310737", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", "0x3", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", "0x0"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x2d667c69935407d1482d8b0182ec02e5ec2cf71bbf6619f739dc8a0ae1e8b92", "version": "0x3", "signature": ["0x48e4f4b79b9f41f0c36c734fbe6699f3dfe1a528cb052ba8df135c25d2d18be", "0x33fce2fc02d766232b168b81b433e238205fa0eccf6d2c3afd9a0f967c371d3"], "nonce": "0x2af5", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x5", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", "0x3", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", "0x2", "0x133f4a7fd773d4f33738fc0597e3fafd1f043a69fcac6bc7cd2d829b8f1b960", "0x1d363fcd342dd5bb809ec8a8493f53fceb418e62912f1afecf5b0e38b520ae8", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x17da35ce4ed77e22e3b9149fd965dba57351a6c29f588a7d245e208d073e4c1", "0x0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", "0x2", "0x3134280efb90933614eae4713107dc7d", "0x8992e86e759f95a8d1bbb86365166269", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x4c93adbd1aa8f107be890556eba8a4071515d5510b6a93fd35ecda87fc6df80", "version": "0x3", "signature": ["0x4df3a153adf467cfcf61e57cd48d824161dd25bfbb99cd99902e07c687e9fdc", "0x701ed8f54d1b1bfaee8e267b10f001a7f8cf4b1d12b1f24cb7a1409bef3702"], "nonce": "0x2af6", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x5", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", "0x9", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", "0x6", "0x720213ac76a0f3f2565f04f51c8d13f00878dadb125a59c9a3d3c846e0ee72d", "0x3", "0x65dcd1a3b2933e6f20f019a97de3272d0549bf793e41a0144a7d21bbdb2fcf0", "0x8f260cdd6d8d7a9668d1bfa93136d12c15246e80975b8571e7d09c76207fbb", "0x430cf4d69439b8d69afb49f3c44286d78ce666e924c3b99e3aecae688a30bc3", "0x600ec4076b035b493816d5d1ce1b46c5024f893844db88e9f02b3eb57423e3a", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0xf818e4530ec36b83dfe702489b4df537308c3b798b0cc120e32c2056d68b7d", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", "0x6", "0x11ebde260ce04bcbafc74879bd67c1aa39a50a2d3af027f407147e18a5ee20f", "0x3", "0x158db84882f02aab220d39d821e92dafb4db61c3fa65acc8b80c6b11f4afd30", "0xd192afb935fdaf0a61c2ba39be015356ba32a25c839fdb6be44e771b43f1e", "0x4336b1b67cd7bd5ac601308c72b02e27659a932373facd00ca73dcc7d45e880", "0x2a5b364fbf2ba9d5c3e8e4fd65507dbf9ab3694f0196ec593d9704d77eb9dfc", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", "0x2", "0x3cb3d73d7ce98bd3baad49800844e6a2", "0x6e4c545735e6f49896af4cd236352ce", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", "0x6", "0x82e6948d4df169db1d3d53f528a78224467d356457dc61b1c19145fb7a60d2", "0x3", "0x1ae7558984ac06156913dc6992b2a5c1122598f49e6965c5f8a71210c6721ae", "0x46707418ecb32d37b3c817a9c92884dcf4ded2bf98c756c255d7b8da05fd961", "0x55316930897583852f858e6a8311efdfac9b026bcac1312a52dfe524ce4c3b5", "0x12b36b9a3081929c3518d078151ff6f505fd6a4a37efae48d6939576c6cf3df"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x68a4d9bcff51d99fd3f5dc6df6e4902073cdf8d43575e3922f904d800517e8d", "version": "0x3", "signature": ["0x1f74b6c109b09be172c7e0326be84b44838e762651d7500c9a12b7678823f98", "0x351cce04cfcaf5744920b91de9509e0813084247a5a816a2ada7de40d82e690"], "nonce": "0x2af7", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x6", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", "0x2", "0x4a8543716dde9fd5051e1899a30be66442b8f2aad98dc7fab46702aef973208", "0x362e2ab6cf7eb90f5dd702f006a8e480b8a04e827efcdc8330c8be3bd80d5f9", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0xd82c8c5b0c6c6ddd426ec86c8aaec4e7", "0x7062d60d085f7d0b3246dfb9babb0b57", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x17da35ce4ed77e22e3b9149fd965dba57351a6c29f588a7d245e208d073e4c1", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x169f135eddda5ab51886052d777a57f2ea9c162d713691b5e04a6d4ed71d47f", "0x4", "0x19de7881922dbc95846b1bb9464dba34046c46470cfb5e18b4cb2892fd4111f", "0x6f666bc1231e8fd5fc2076699d6efbe354188833175dc0f5def712b74dba207", "0x0", "0x0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", "0x5", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", "0x2", "0x4d6dfeeb0f84e439b9dfa1bb4ff5eeaa5d7fe1fe17214bf2b7efe0b42916fa0", "0x4a539db0e55ebd6d9d7835451d2a0c80d7d07289fc5f8d4fbeae0a8845019df"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0xe0f970f4ce407adef51a760559ee6ee74a4769758768b808097b520216230b", "version": "0x3", "signature": ["0x1229a7d742142e70b11145e106082b507dc302ff49a48883d1865a001548af4", "0x1d83ea6bb1e4ad7618b0903c1984c3a15718cee02c7e8dc431f5de9c71d5ebf"], "nonce": "0x2af8", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x5", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", "0x2", "0x43c60fc938e19d99ccff0bbfa18b4261", "0x237fc09f3c158be2d2bc99a6d9ebbc4d", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0x35b4e984575e9dec65833fd5485aa1d", "0xafd2863cd029b8777771cd7e105a91f9", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", "0x6", "0x66e6852463ea25790fb91b17d81f3d94c2d29690ce5283a19d54503c93c03d4", "0x3", "0x47a7420476d121e7481da71e59fe5eac3e6e058175191aac84315ced6f5d101", "0x203c2d2e3335474d659e032766de8c06a746175afabcbf6b21e49a2bc8d9565", "0x2490dd8f87566f3ba033a272c9eebfc0f3feae6bf5149b71b4d14c4dc26dfd2", "0x2be568ae8f7d9133491e5a8b04f7044b5fe032f8bad3d1925d238133865c8db", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x3d95cdb95afd14cbdb4c4669525e879dcb683baf81484a3e1f8d907153e53ed", "version": "0x3", "signature": ["0x6cf60d9124edf2ce57dee16d0634392b78a6c2b6c286295b6b2b53aaf3df2df", "0x1cc0b0eb3bf5580301e65bac42a843a8dd47ff58f0f2483b298b4f950f4e904"], "nonce": "0x2af9", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x6", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x1", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", "0x1", "0x39e7dfaafad6ac2cee097515c0a06063543d2145177a8e6bc480d051cbe5e06", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", "0x2", "0x734230d8463ccfa78e011ac24bbcf3c1078ab86739b7812a7fbd56887e2a3c7", "0x7ced184701e413325e711e93f726a8506b37f8dd47c45ddaca5add22a4516ea", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", "0x1", "0x1776ef94f6fb07e1fc41e8eb36fe7e5534daaea0abe9a3bd483fee3ec769557", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0x441dfc5dcb717276b126f4937a6d082b", "0xfc338ca78ce4cf6dbd3fa4c357d6eaa3"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x4f0afadd2870468cf005f56bebded204bae8515a4e70a0a2ef4a55367cfc205", "version": "0x3", "signature": ["0x177e583304955e9013e676b24d14fd1926e7f3978b9d72bc4b3224e4a3f1b07", "0x2f55d29a9db1885aa934cae7e0fa35879336931cf66c9475984da937dd19d0a"], "nonce": "0x2afa", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x5", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x3604cea1cdb094a73a31144f14a3e5861613c008e1e879939ebc4827d10cd50", "0x4", "0x19de7881922dbc95846b1bb9464dba34046c46470cfb5e18b4cb2892fd4111f", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x1", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", "0x1", "0x1cb7cfae5bb1e05c4ab2df9131740ae6aca46ba7ff8935a2118b7227970929d", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", "0x2", "0x23d9068f531552f6c74bf446c8dc6f883a77dc3e925a9958eb74d986e061982", "0x54d2f37f02cf7d87896ba3152123a7805d73ad47310993b815599c260059b3a", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x169f135eddda5ab51886052d777a57f2ea9c162d713691b5e04a6d4ed71d47f", "0x4", "0x19de7881922dbc95846b1bb9464dba34046c46470cfb5e18b4cb2892fd4111f", "0x4ab8a35cb117e071c569da65787c81a04f51bdf039b2dc7ac571da6df3a6e04", "0x0", "0x0"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x727effea1ae4e021bfa5435651f2ec0ddfc8d6c471f0e1948d89f00879ea099", "version": "0x1", "max_fee": "0x354a6ba7a18000", "signature": ["0x430ea24ed76eea6c6949d1cd2b3cfe2f67ba2e46aca605f4dbb0f671af3a3f9", "0x3c7ee925f025780a189e243dadd6a03c7d1277b627ed852576181c7cb43d41a"], "nonce": "0x2afb", "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x6", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0x7f701511f499ec21792da5c5982c6401", "0x4cb0a181cdbcce5fff35dca0d398c64a", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x2d7cf5d5a324a320f9f37804b1615a533fde487400b41af80f13f7ac5581325", "0x4", "0xa0adce6dbaff6bce9f7a620a9ed209aa748a0b24", "0x2", "0x9b971fe02819281443860767515bcfbd4a87795e973ae4c5f0da3f38b3fc78", "0x138d2ff63ebe4cff9b97f36d9842f5784d1c14c77d552a9f202f700df99eb80", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0x18af48e8845ea1c7c34a314b3c3b2375", "0x2292a149b646abdb89c35b3429bb483", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x169f135eddda5ab51886052d777a57f2ea9c162d713691b5e04a6d4ed71d47f", "0x4", "0x19de7881922dbc95846b1bb9464dba34046c46470cfb5e18b4cb2892fd4111f", "0x57739cfa38624abb7526147eb5883b962e1b8e081823ef983800842a7cd2246", "0x0", "0x0"], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x5a6591fddd64df4f57b64543c00a1bc788485b2f558056ea853548d3d1e9637", "version": "0x3", "signature": ["0x37fc84d260663393d65ac62ec776ed3126f6dc57cd1417ec192dc768ccd9c66", "0x674dc62d137a8d61fc2caed4172f6f05b123d8b614242a1bc04a1f9a31d8543"], "nonce": "0x2afc", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x5", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", "0x5", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", "0x2", "0xa704d52ec1184a435b796982a2961b5b", "0x68d91e3b8baf380a1a103b0ef8189f89", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x1", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", "0x1", "0x3fa28db865f00851e0e084410ec80157474473680a1cb8d12f9a980b40ed159", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0x925270ea40150f1017d9030a37c8d225", "0x33a4e8e13c41ca50580aced266d0d10b", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", "0x9", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", "0x6", "0x367d67d017a167d525cb8d18acd2b7aa354b96db81d60949ec7fb66c4f1f674", "0x3", "0x755c24b1b54061ed134fd9d6f0d910f166b1d134cafb9a1fbd62300b1eefa02", "0x5daa8bcd0707512e3d7c6230d40198e0a7190009ae097f9b2e2963441560f3f", "0x3acc6203b842ebd20e31109d66d8bc8ca2e55495bb4e3ceb90ab6b268fa8843", "0x2d11b69ea163cc20b08ca557146861dabb4b2e3e0b8a3d7ca0f8dc57c200fcd"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x667247e8ae4537222be926e7d29001431251f70024836752c4cbe68a5377beb", "version": "0x3", "signature": ["0x18e2effa99f9bc7d8cb171abc5a1f8d6c564d4daec6b30cf59d4450b0ea9dbd", "0x48021ac765e54bf0c21b8c2a6dbe0f7d9adfb9f19757496a8bf1152ecf2b7a"], "nonce": "0x2afd", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x6", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x1", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x241f3ff573208515225eb136d2132bb89bd593e4c844225ead202a1657cfe64", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x1", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", "0x2", "0x4e111b1ad23e286630769990a3783720", "0xf29b6b58b3fd9bb0500cfcbc1015c848", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0xa3ac12ff5c51f47e7f7328470d92e3d0", "0x204447d717a322685318579c14836064", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", "0x5", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", "0x2", "0x1d964948cfff2c14888675fd7f76fab2b88c37aa22115b50b46afc024874f0a", "0x32b67000b87808ef73ad7eb1e404e30eb4c76524ac01ad06279e1975729deff"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0xafdac29914cf6054190cf08c1a83acbbdc86a413690f40326b9aae545253e8", "version": "0x3", "signature": ["0x23ac3bec5495f55a5219469a269065790e35239b289345047d5b967cf6e1e89", "0x23112efcee6522622cef06abea54b82759040a3293d6903d6b0a8afe93a6b80"], "nonce": "0x2afe", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x5", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", "0x2", "0xc7c917230cd008e1265ad1ee22ace88c5be770523389845ff00f49d7338118", "0x3ee28cde6fd7a13b007d272ba6d9d2aa60c368b1953c49266abb5575a964c08", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", "0x5", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0xd7dbcbd2f4a683b6a2d38ecdce699a83", "0xc3fc17d04bdb882e05bb43671720765f", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", "0x1", "0x5308f3d9b6084569f82820b1eb085c72ac5a612971c9680b18c21ec735aaa4b", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", "0x2", "0x539fdc41a334940ccc171054ad1ac3eaeb610e49e67672a016667b3be772832", "0xd98f2531dec263f3c96154482bdfb72e5b31d503c993080d7bf2433c737d47", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", "0x5", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", "0x2", "0xe2b78726249ffd02947b885c8187140e", "0x1537d57a9b032a151c71c3bfb6051e84"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x14786356d92d3359426657aba526e8e6bc3c6913beb2a06fd5a1af3254c8ca6", "version": "0x3", "signature": ["0x134db6c6026797efbb39fef321dd78a38f6d06328bd995fcf204ba9c9de62f0", "0x3ba78d2dbe1d0e2943f6f325389bb2f7044d5d99d7b45823f73173569afbb6c"], "nonce": "0x2aff", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x5", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", "0x2", "0x429823daf44e2561c59cac59bbee902e", "0x2587a5c079fdb6f5c33ea7a894f5f9a0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", "0x2", "0x4f762c3d7a166bfbb9ffbb6c41ce6d095b419805282f953bcf9d9c5d9f5d7f4", "0x7c569075876129c2c52f6d07d73a0fd573bc08fafae48daa8a029649ecb1599", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0xda7231f5fe13374aeffb6f4d62136fd", "0x6e2842fba79a18e891fe49b0504aba46", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0xf818e4530ec36b83dfe702489b4df537308c3b798b0cc120e32c2056d68b7d", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", "0x0"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x644839d53b3e8e9d4690a19ab35f0564b249c58443774ffaa8e4db4a8890ee7", "version": "0x3", "signature": ["0x56fe160ed17b4cb561e1bc8b4af560a5fad95a6210da52341715c9d81922e27", "0x52d991fe388f88b776cdf7cb1683623bbc3a036ee3be20ef6d9c46bb0c5d973"], "nonce": "0x2b00", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x6", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", "0x6", "0x48ba4a09e3cfc54a0fb13826f9d9066f019db290b3ac4ca202f9e284013e38c", "0x3", "0x582a7beb60027e27dabc1a9e9b4746528535aae1c47ea1a2224fcfed00ea52c", "0x51eadf84f9e6df0d7079bb184cb44e34bb311edcc62d1e94d5b1ac2f1d6b8a3", "0x2c08e60b9a4f7106c503b13b490fbff384b07726e0e156ac27563ff05114b20", "0x664e2b539726f17b24f345f28acf490ed92cec85538bc366bb5c8edd2b82e69", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", "0x6", "0x47b42da4835595cf4cfd06826eb76ed95ea8dc2f777b0c4acd2e0809e6680fe", "0x3", "0x4333048345c017b97d18648e47c5fc51e8ab6127ed22f6eb1cc810c6163f6db", "0x203aed1de52fb8f7f43524752d45bea702df6f2ace6e5dac195de918fce2133", "0x316385dc04628c6b11a08b31006343bc98580278ced84ddf620e9738d69b055", "0x43129d981b339482732bdc3ca8e420d203862569ddcc0d6d201418c05f4d9d", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", "0x3", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0x8bf09672958b0e6aeec96a79277e97b4", "0xb6f7ef9c28e2e6bdbaf690685b74630d", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", "0x3", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", "0x0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", "0x2", "0x33f793f20ca2b13f3e00bc06024aea61b2b48d37eb5d88851d550c52a43802c", "0x6a897e9229c37a46716b1077c7da5032dbaac03c525cef9440426399af639bc"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x7f32793534b160cdc40e4ce20a8709adfa9bdd0b5860013698fc754b4103542", "version": "0x3", "signature": ["0x5599359dae473f4cf42aa8a5a336f49001316447967c9dcf5d5db7832065e4b", "0x14dda87b9cc41148b36150a85fa888301428eda36e203a39a5592a0a0a5ff54"], "nonce": "0x2b01", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x5", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0x7a57003c2a8877940911d3447218298e", "0xeb74fdacf6b44de6b0263947a674941a", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", "0x1", "0xda58559b7807dd5ec046d36a061c641b71c7ea84ec73884ce07008b52b6056", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", "0x6", "0xba435eb69d3226f365880885b2ce8596ba44ae0821dc9f8dc7907d14a282b", "0x3", "0x40a013b398bee56959eefd6c4edcc4675872dcf412ca5065a6f7c413b717732", "0x371a8adc1170613db866c390fb96e780d1a5c36cfa7f970724ff5e1b0a5675a", "0x287a7a8fba7421005c45b0f98e0d9605ae017e9bfb4b837c23bda6df6549787", "0x6432918f928ded128bf19240e81e97c8f2719ee6d361208e5bb6b78c61a9e59", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x17da35ce4ed77e22e3b9149fd965dba57351a6c29f588a7d245e208d073e4c1", "0x0"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x642146ccbb341535e2f4f7aa82ad34ab2d0dd6bcc5d98f6e9485638b67a6d", "version": "0x1", "max_fee": "0x354a6ba7a18000", "signature": ["0x11364510890c78e524e9c6aae1c8f433515924a544206d2e25fbf855c2e1525", "0x6c483c512935270915f601b8f6e6be8117e572b19a43576493f05508224f045"], "nonce": "0x2b02", "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x6", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", "0x9", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", "0x6", "0x51814831a2493c60497a96034f00d3e72c1ca7b071631c1cd873c0e7b46f42", "0x3", "0x79f3c4cf6a5ecf86c3b4ffedbde7b884f61b408085a07f7e3f8a1c73dcd6792", "0x1f282d7be25fe585523745afba8f5ef4bcd9e8eade41b3fe25d8786b6b5fe98", "0x415081db9ad19aa0e2173ba93d99d0d6ed9a48385fbedb24c7c81dd18eed394", "0x3dd2cb4cb6238ae01cdc5f9a266487605ced4215f9a8a0e7b010a12be0cfe80", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x1", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", "0x5", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0xe0057bc20ea2e65355b9babde022c12b", "0xdc7ed21d9136c6db539a5ebd3064cba8", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", "0x0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0x5f7e4cd36574fbc7bf721ab551930eaa", "0x43bbc843a0d677c58f0de8f473d9f5fe"], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x72d70c0f1ab91afa262e842a6f3f8a98dd658da565c7279364999314ccbed5c", "version": "0x1", "max_fee": "0x354a6ba7a18000", "signature": ["0x4a1653d0eee3fe5cf52a71e2d3789018f657770ea4d1520704355e5a5a250c3", "0x7fda50a8767eaf42de251ff184a337e9a01c957335bbde0dd430526d073fc67"], "nonce": "0x2b03", "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x6", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", "0x1", "0x17b670dae24500d3c79b915c046eadcc85d0800a392600cc5621291bc4aa461", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", "0x4", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", "0x1", "0x55752e2c74b4fe577f7814e2bbc12c200f88b2cde23f711b7d50292b803853c", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x1", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", "0x5", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", "0x2", "0x1be2067e9e9147c11a15d1d87f43ba0b8302fe4ffc050b0ec46386ae76ec9f", "0x7d82c7b2c959aee34df1cb5c17153ffe7d41e46c7f5df636251015af171dd81"], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x214d0a540e7b03414772c2c2de426eb5d4e4ad63668b6b81c35c0b2b2d6bcb4", "version": "0x1", "max_fee": "0x354a6ba7a18000", "signature": ["0x69a2bfc21ebfaa4939244762ba0e2dcab4a73b0981072eeb2920c3a65d683b4", "0x105dbe471bcd8c10ee14b57dc74086812339de9355d0dcd0752d586bfd23be1"], "nonce": "0x2b04", "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x5", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", "0x1", "0x3951bc2d237738dbc3f8e599de009304d873151c89cb4eeb383a8dee19a0ddb", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x3604cea1cdb094a73a31144f14a3e5861613c008e1e879939ebc4827d10cd50", "0x7", "0x19de7881922dbc95846b1bb9464dba34046c46470cfb5e18b4cb2892fd4111f", "0x2d7cf5d5a324a320f9f37804b1615a533fde487400b41af80f13f7ac5581325", "0x4", "0xf40fbaa08bfabcd6fb1a0ec3ea1fd8d0cdbaf82a", "0x2", "0x48c560eca37e048d7cb12b7ef2ea65d5e34a9b79a0379a1644939f7b9bf3f7c", "0x1d65cca89665e33658632b26a178c617b6e6d6b34c687244a94e89202b407f5", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", "0x5", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", "0x2", "0xb27423ef1c65d01b5166cc338bf943b3", "0x9f43dfdcd16838d5be75643708dfb610", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0x73de4df6e20652d17f10334c16301c11", "0xb9a1fceba481bd69490f5010e4a3b65"], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x3aeb0a48ba255a5aae097ebdcead737a46ee6a768ada5dea2956aa2446107eb", "version": "0x1", "max_fee": "0x354a6ba7a18000", "signature": ["0x4c6b20d49be38735a26bf5945e1f3c6e2fce1a4f9e0738ecd52f4795c525e12", "0x2cc70c6a78df1f37ddb471f8e1eb2d6842aa6a66931bd3c5b6bcce1586cf8e7"], "nonce": "0x2b05", "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x5", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0xbf96ed271423c439e2db76e2746573b5", "0xf07190dfcf287d653caedf8dda552ae", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", "0x2", "0x67447bbbcb454bead44c902e17bdcc80d0056f533abebe082e6d71ab00f28c5", "0x1175210ad43009ec56bde0abff3b2a2309aa5538ff5a9778ac97294df5af80c", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0x807a2ad9869abb8389c2cb931d1ed9d6", "0x89a1b9d05e6f300d613d62295046fd0c"], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x4b6c706b4a3038b41519a3dd6d0f5e8bc18d8425a1df493fb5de747558636c8", "version": "0x3", "signature": ["0x17fe6eabf9de8ce62907b7e6a4d65a8fa59dd8c354306d715abb65f86a3e6eb", "0x4a12e41d278a51d563dd43acc57c420cee55a7bad617d4bcf9d74605fd03e88"], "nonce": "0x2b06", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x5", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0x1dcbc489e0f6ba07feedb2b612a6f7c9", "0x1ec0d38b41f52802919811295f71e6e5", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", "0x6", "0x45697840297d58b4a4d5a5409c5ff698e080a7202bac696cac7997ab35909e4", "0x3", "0xb1cbd90586a7512eb49e81f604bc9cc37387dfa9be668cdbea1117690ae3a7", "0x46cd6cfafefae479a5c3c9f5f1ab86edab3f252d6d0e13442cd648c541408de", "0x588192bee153ea941a778fa2f6be1212d995437e93954b86d7b2e7995611994", "0x22d3a9c729f9c3ab1b2ba97c59144c0d8aeb26bf3e8cc17c4d52a7bceaf853b", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", "0x0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", "0x2", "0x8cc2b8aaa2cd756ca982a77725696f3d", "0xee51cc63766130e7467331fae41f3bde", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", "0x2", "0x69466ef6c2babaab5d69b9a241992e66befe2fa37d3c84b6ebe012200733788", "0x44d73e39fbbef9b97005eb505bf24b30826966666a4173f4a4126bdd02feb73"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x1f6fa1f89da0df7a186bacfd78e91b95d88f057a513e1214f8ff0a732de30f4", "version": "0x3", "signature": ["0x6450b8a132de926d76dd5bdb8c86c33aefe32229a5a781cdcb79dfc24490e02", "0x14c74a65f5101af1061f10576806d81f49fd2734856eb1eba734f578626650c"], "nonce": "0x2b07", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x6", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", "0x2", "0x23775eab251666c2828f90635955e4549ed21ba07bb40894c16338f408b55bd", "0x41365c6c3603fc12bc2bebb360cb228cf67c0df428f72872a96fa10b81397", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", "0x2", "0x713289e14d0c229fc28d77d3d8349253a75b8413bd5aa4a4adf790832e5b39b", "0x215724bdf36e7a678366890bab97c1659a0190ca282f1638973bf2423011ce5", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", "0x1", "0x73cd87bafbef1a62813f780ce7f28e5f3b8a14201f839a34786841dbaf81080", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", "0x1", "0x413e1e751538e41027e223c64087c6ced93f87eb22edf87cca530bf5bcdad96", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", "0x0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", "0x6", "0x2d11bb5170a1f928b6ecd7b97e025a491a5cb5fc4855eb496e07835dff04487", "0x3", "0x692e616a28746075cb8a6e660f951cc842f43fc5a2030fa13a27bf7a41b179b", "0x2ef606af2baf35a9e60c618328075b4d309765e55c336ce29d79d3a3c5566ce", "0x12159a449f1a0c82c83906dd424f34f8b3e00073a67668a814cd9c1940167ce", "0x7ea13f682c7d3a64f766dc6774b4d6306cddc564c66bee45c2194d47d80936b"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x5d7941297f3232c0a98bd8e0b51d5d2464e97057147d06a0c41a07203c639ac", "version": "0x3", "signature": ["0x235112872a32e6ad2a0ad40f6dcf5ef5ab07a374a301c560e969c3ea9d8a3ea", "0x599c44ff9ce4742e7d9ce3d84e7941d35001b7cca3139b77cc1b1d2c532ecec"], "nonce": "0x2b08", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x5", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x17da35ce4ed77e22e3b9149fd965dba57351a6c29f588a7d245e208d073e4c1", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", "0x2", "0x30180bf5092a5ff4b3cc0869fd41908be37fcfaec0037142227d3c916e86473", "0x6764d400af34621182e8a6959dc7c716c66428210d3495d5b443df0103370e0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", "0x2", "0x6f4bbcac9ccd3f40270d33077a220a2b7be4b027195fbecebcdfb99bc98280b", "0x719b92cfad6796e15ffddf636885f2fb5255427091db6d4fae9b23546a0f6a6", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", "0x2", "0x7e5c2f4b0dbef33d51a707e8a5f2b0855dd7e15142d8f49811cec6c1976427b", "0x48512d692d3429b05b4417a80c12328df0c40656561c2e0d72bffd187ab606a", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", "0x6", "0x55cca0b45c9c4cee79718132afc5c4d2d1f4d029a29efc66b464e9209199af3", "0x3", "0x693aff98f855195256320c1744b36988e5efb7544af094f0234f5102b6fedc", "0x68f7ccc05e42591293a68372d8cce749527e66804a036b22a0b14098b862218", "0x282e2b68eb812129b5b2305aa4e1a45348ea41ba2bf9ab46d541b91d8ddafb4", "0x100b081355846a5cb46d10a84e181b09d1c8f85b33b1e818aeb7fe8759caf7"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x323977511f652a2c494d4b7ef52b713d20ba702c7edf1fd1495a5b7fcb9b44b", "version": "0x3", "signature": ["0x4f4cea7dd16350ca4fbd98934063a41026007d4ec6d89a6b7e89c2aa5c972a7", "0x28ec61ef4503111fa4d6e1f5c2b08b2059cdea9991e48e5c1eb6f0a63215991"], "nonce": "0x2b09", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x6", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", "0x0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", "0x4", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", "0x1", "0x1c95c56dcdc5774e37988893ba5edf52b07ef4ca3730a969144643f551bbbc5", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", "0x6", "0x666c83f59b7389bac9789070aee65ace9e99ed5f4ffcb86a4d8aba7d338c98b", "0x3", "0x7b5b27757a05f6bb78487984f7a96e15a18c6053b4657886f5e4e6f91178f0f", "0x33695f320ce6d43202b522fa2d92c6e34118f960a0d9edb25ed15910682f596", "0x1e21d486fabbba4261dd3f6ac5148571bd250983730dee61ab8631afed8d89", "0x65e8f77d55085d2561c8000a4f2ead80ed266695b4501d6946bb1281f6be540"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x2c0957019f8956130340acd8c96bc5c93a03a3045cf90dd50b70d580377b61d", "version": "0x1", "max_fee": "0x354a6ba7a18000", "signature": ["0x198b44af8fb4a8af161f8da184d14edafc52f7e4c66d62841f9a6a757a16dbe", "0x5a93ba3b72d470f90df29e3e1b3d7a2a132cd92c0ec77292309b950a8bb8bdf"], "nonce": "0x2b0a", "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x5", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x1", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", "0x1", "0x6034a91070e61d796132b34792bc1915bf795ed829032e3d32aae0ea992352", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x241f3ff573208515225eb136d2132bb89bd593e4c844225ead202a1657cfe64", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0x223964780f6f8de6a748ba2ac3b73e15", "0xab3d17df7864a109cd68e9e884a0c554", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", "0x2", "0x19b9637dbca5e7dba97ef0cb26c80a6ee2c402d47e1d259b4e07e96c38d5f71", "0x124c127fc636898043a083d0515c47759b61e2556b2e0f90041816eaabe9697"], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x570a47e2a3aab957dd3d09f8fe778ccb54163bc4207585d3f1e7ad471197f1c", "version": "0x3", "signature": ["0x3ef16b0d32b4b68a3a627b304e6328428b36d83f9aca38baf050d9fc059efb5", "0x5e118208e04a46d748aba9b90f1adf51bbb1982ba4226e928f499af3d932d57"], "nonce": "0x2b0b", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x6", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", "0x6", "0x49d389ff8457b29a69c3d57c0450dc56b1406b9e822f08f88b6ff7fa11627e9", "0x3", "0x52afc8740c79463d83b7628c35dddd807f6d2858d860752f980000e87d8d854", "0x6f6a828242385c55eb76bb6c4f896492a91980e2551ccee675f7c6dfe79956a", "0x575b2db2490f75d6877f64f23cc14589958b4cf31da2c65d9663c6dcb656a23", "0x1413e46e460ee879a99aa5c350a2b38ddfbd59fd740c4ac3ffdf3e4ecef3204", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", "0x5", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", "0x2", "0x83a3f525814262fc83e4e79e8e898222", "0xe48645edef42b2b0e6e029f5c11c536b", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x1", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", "0x0"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x2cd6a8aea2b82b7e37d30451074c298e03c377feb90999c4fcdacf99ed46f97", "version": "0x3", "signature": ["0x6208631264e1fea9cc4bb62eef7008f23ad70a2d8c5f3ce5e0e0065c0c69639", "0x6405dd3e44e48d7d2d6b81fc511affea0b249faf65473eab07eeda4398a8174"], "nonce": "0x2b0c", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x6", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0xbbbf5056ca48a6099b038ac93ca1d41", "0x2c45e9d21b843a7209a3578c62b7f863", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", "0x6", "0x3ef516eb44f7a25907ebee82d2eed55a2b26882cb684da9a0b1358fe0672e12", "0x3", "0x1bfa88a6d84994c4cff5dec7d8e3aaa205b28b7bcfb7e5583f33508ee92b17b", "0x50a25225519d91ba161f48cad22cb84d48d5108c43665c0cd5d3a3ece0946b2", "0x23e92483a133a6aef2ec70e9faf85ae1afb61138bf385a28cf0281610bc4e86", "0x493f503c206a325fa868ee3c0f46c6ded2fb7d8794c2fb51aae324e8f8ad68b", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x1", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0xaf6c5141ccae2abad79d68be3c06cd47", "0xdef061addc512a1a79c80b148a32f0dc", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", "0x2", "0x87f8bb5b0d1992436c27e387ed8a1919", "0x49c668a847de5cf6bae037d937fbde28", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x2d7cf5d5a324a320f9f37804b1615a533fde487400b41af80f13f7ac5581325", "0x4", "0x2eae5b0fe2112b79ecef02b30243ee9a7cce0ebe", "0x2", "0x11f17e586559af18b7e5beeb3fe68587e7e69f0b336079f9e3d03fa0343c783", "0x82a221fd714f879773458cfc0df8b8c2d5798ed9e57fb2afc3cc1c485e6f1c"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x5e3470f9a6a059d2190685fb82ca05eeea79bcba70b591130aff661cd5fb828", "version": "0x1", "max_fee": "0x354a6ba7a18000", "signature": ["0x639ecbf576244c33094172a07acfb70857c8bb01d09457a859845abae52ea06", "0x3ce2a80ad5a0d4a663713dae7a0df79c7601c09043d8d516f55b13bc4192193"], "nonce": "0x2b0d", "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x6", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x3604cea1cdb094a73a31144f14a3e5861613c008e1e879939ebc4827d10cd50", "0x4", "0x19de7881922dbc95846b1bb9464dba34046c46470cfb5e18b4cb2892fd4111f", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x1", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x1", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", "0x2", "0xbf1ef784b19f0afeb1bf8a8e05a45f35", "0xefc35253c76135d8b8769f25e4f66662", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", "0x3", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", "0x6", "0x5b6036498212930c0160795ee17255fb94291ff053251b855b6da5d97b74531", "0x3", "0x40a8bcf47285adcb19628e0480e1057968b655ae8ecde24ffd7086070b5b9a2", "0x3e1e8cf3b705f1039bee876a6a72988c59ebace9186ab399dae1c3f8b76b6fd", "0x383afa7ce58c752b62f44f4f86446226b2246731ecb15296971731882c10f3", "0x734e0292602f96d307cefe554cd1c5d32d1e115f3b8a5097f307bdeff24a320", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", "0x4", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", "0x1", "0x7ac2fe2ab9751c67f517ef4850a4b025a812695f1b63d8d7a6e0beb9c3f6536"], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x3c78d2cab2fc776e2dcccf55ecbbd480b9484953a8be01b8c0306f88b2ee774", "version": "0x1", "max_fee": "0x354a6ba7a18000", "signature": ["0x73619bcc36c7e3e78afa8b4352758b93b2e67b96e9e825ebe8794aacb90e03a", "0x3df74700add4e5fd6b69f6a8fea70e90ed38d470a3e41cdd537518cd639fc48"], "nonce": "0x2b0e", "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x5", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", "0x0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", "0x5", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", "0x2", "0x4aa8efea3b222661d24122eea76d3d5ced765e259e52661bcc755a0714fd48", "0x142f1e5d40c680f935bd44f83421d9cf28119727d06b56d2e9b4c3b370bf107", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", "0x2", "0x25524703ebf4fc398a37c573d6cf02798ad6faaa2a3dfa4df32c4bc65e08362", "0xe554fe3ae68d105750635ad0f7f284f9d2ae8f3a517a400418864b8e2cf4ad", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", "0x2", "0x9d26b9dff3413d16f4d1ee8ed037b762", "0x89fcc59f11a31406f8290a6e42a31387", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x3604cea1cdb094a73a31144f14a3e5861613c008e1e879939ebc4827d10cd50", "0x3", "0x19de7881922dbc95846b1bb9464dba34046c46470cfb5e18b4cb2892fd4111f", "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", "0x0"], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x2f8a9ceebe94631c2a75b078731515cee0e5ca12d2729575dc7d932f66593b6", "version": "0x3", "signature": ["0x534a93c18cf11040cc387c9c406b9a0625e1fffb68ee6abc8636e72ee6df394", "0x1121a1f70cc733a088e9e9320d5684ba1938170685377af8d96e9a78db3cba2"], "nonce": "0x2b0f", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x5", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", "0x2", "0x2022ad39ad6c5f8cfb021797c62ffe33a0be2e8b974fcb26b0c1dbf56aa12aa", "0x2210e910f662f494eec608337a71b287f6a2f346456cc34ba35e2f01412012e", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", "0x1", "0xc54ba698bd75e3638f6855d6cd17c6ddb0a364fbf03868a930433a27436a5", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x1", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", "0x6", "0x37b72967ee34e9b00c45a6c1319ba8d28def41e60c8e0bbf91d440dedbf3a44", "0x3", "0x2e0afc0b8bdbc766d2d58ec64f78a0fc82c4f73abaff128c10005bb6a625475", "0x7a945a82f362f478cda98c5c2952dbd9d8d805f5f02b211bba7e3299f261979", "0x46aef08ffafe9b3e7644623e58f73dcf148fcf483a3fc9779836260bf576377", "0x748a9cf9c9dc4ecb387ec19e8c56150240c73b42d84d1d196a84c125234773c", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x1", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x65949106a60aa0465ccc50dfa41676fbef444c94b051b08248653e443f9532f", "version": "0x3", "signature": ["0x17d95036e269896b48ce1f7af77a379ab8fc77eda72c20aaeb494cf9297c92c", "0x3ede07f71f1228be351f9a5ce2ef854027ad6918890957a5ac76f194b85ac94"], "nonce": "0x2b10", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x6", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x169f135eddda5ab51886052d777a57f2ea9c162d713691b5e04a6d4ed71d47f", "0x4", "0x19de7881922dbc95846b1bb9464dba34046c46470cfb5e18b4cb2892fd4111f", "0x3fe5120e78196b665bb1bb5299fe4f94cc23ac6d71e39cec67014a2ac834053", "0x0", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x169f135eddda5ab51886052d777a57f2ea9c162d713691b5e04a6d4ed71d47f", "0x4", "0x19de7881922dbc95846b1bb9464dba34046c46470cfb5e18b4cb2892fd4111f", "0x724a2319c76a573ba125cb1a720fecf39712a9f36b14cfc89e186fb15a31f54", "0x0", "0x0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", "0x6", "0x49083c6dbeada5ca48496d10c5b5fc879a66cfe2106edb7ad133c47089a461d", "0x3", "0x4e39b2f0a8f28116d4bcb252009dc6f9f99582801bb9a0d9338e69e572675c4", "0x33fc55ab493b435eddc00987bc0587689ded268a82ffc6d41e32d32f4e18ea5", "0x6f2747503b85199bef9ab777e17ee34bf358726cc1b9440d1a1c439ffeadaf8", "0x214ad9ac97a938e7849567b63fdc4db5cb199a1be029d9b6139423d51b12ac2", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", "0x2", "0x3e333e6d57a0f05cf0872a7b6747fee", "0x4e752f68ef85ea22f5af42e8d2d95a94", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", "0x1", "0x85b24a956875ecc291451fbcbcf89f36a9a996e11cc6e9d4def54a5c317456"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x7c31171221dce0134eaed898eedef9a9283c46007d5a7205cbefb60bfdfdeae", "version": "0x1", "max_fee": "0x354a6ba7a18000", "signature": ["0x29c8843a2629da960d18889ed9533d239230771de74bf6714bc80200d1b662c", "0x79ad670c5227cd9226783be58a1ec635fd94cb3215000be65c219e1a8df87bd"], "nonce": "0x2b11", "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x5", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", "0x2", "0x704ca12a4f2fce52c563008447e73b881260209e89f2dcdb0e1d1684cbf0d38", "0xb3560faf72558bb834f120a8c97cc11155a71b154a6c976a394c41335ed3ff", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x3604cea1cdb094a73a31144f14a3e5861613c008e1e879939ebc4827d10cd50", "0x3", "0x19de7881922dbc95846b1bb9464dba34046c46470cfb5e18b4cb2892fd4111f", "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", "0x2", "0x7456d9d187b28bd4c47dce05c0a08091", "0xa3b6447a65be4e98195a851de398370f", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", "0x3", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", "0x0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", "0x0"], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x57dc37799d80e5a4325b44b272177af28259afe4a08d9e035fcaa7463c78d1", "version": "0x3", "signature": ["0x608f978f1f43ba410ba375b98423dccb750e55efb1068fae60705371d87bba4", "0x7fc94d1307875ab647b111f116400a56c2e723ec24238ccb3ed38dab3e087a7"], "nonce": "0x2b12", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x5", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", "0x5", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0x5895a6d426fe9f31dfa92b92f129f03a", "0xe13483fb7e371972acdd7a988b7c3dda", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", "0x2", "0x42a9f637a51b03361e1479cf7aa4a6c0", "0xbb655695f7a40bea741ea60e36c6eff1", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x17da35ce4ed77e22e3b9149fd965dba57351a6c29f588a7d245e208d073e4c1", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", "0x2", "0x5bd399d1e7c918c4d53fda5eb32a4f2d", "0x3fed1afa0c2ac0ed7cfc0da8944d92f8"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x5b112706c56d0e776f2074dac9622796190c46c460f6d3f7e21848a0f823564", "version": "0x3", "signature": ["0x719d8f8c8ef0e3840614c64831f006cbea2747dc951707bcc193a7dae3ce9", "0x2fedc0a0ae6653c2e35c7b5178fe55a8fd4e6bc417e51538254035c64748dd0"], "nonce": "0x2b13", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x5", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", "0x2", "0x1fca2bd4a99a332e61049ef871281c512f8602b65df29e571391089095146f6", "0x7202a8c18893f7950847d13dcb66dc6216f5705bfb1e5508ddeafaa145302ce", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", "0x2", "0x2746a3cf38463dbbcfc2e34d90c0d1ca", "0xab587d97d68a9ba2febde33143882331", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", "0x1", "0x5395b30901d24f20dac387095a663db9a7c07f2452c699e7bb104bd73a3951b", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", "0x0"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x2805277fab3bf13cabea921219a291b59f5c976c576b17880bbc6420df1d948", "version": "0x1", "max_fee": "0x354a6ba7a18000", "signature": ["0x25cde97bc5548445309df5fe7d80639adec0332c374f4ab8cc2df933d5ec48", "0x34a4b80e0c550e1edf2416cad0cb7a2dab42e105e883cd69e9e881232eeb044"], "nonce": "0x2b14", "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x5", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", "0x2", "0x5b80a44014d71e4c3cc56392d7167dfb", "0xf5c47ad72cb7729e6deed83c07edf677", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0xdc794c7435a242d1e2970bc2d4943639", "0x242104b5f506f8952fbd4a630bf17672", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", "0x1", "0x7ba9f7d0828ce4dcc85501ce6b13f331b9536bf5a2e7faf23b0db3319511935", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", "0x2", "0xfe63880340f114c15c74a0f679663a8b", "0x870a0be881377a89a98cf92790b80d4c", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", "0x1", "0x1a2a61024dca097e3b4a81ee898d83d0348afb7746a850bed6e0160f754ec2a"], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x8b6c4271730d086c0c63000fa2cc756f6915ce9d4c949aa03a3675f265d4c8", "version": "0x3", "signature": ["0x4bebd487277fef385bf103f30a3222a5e054835ec2d845af7a8beb6fcbbdcf0", "0x17e1947a2c14908659e6ce211aabe688d2cbc1506d5bd1a5c954c01d31c23db"], "nonce": "0x2b15", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x6", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", "0x2", "0x12704101a5e04604b8ba9fa1001108d96c6ff7ca584506ac76e71e56cd61b33", "0x44a69811281bedbdff09284b8ac54658a4a535fd04cdeeb5de08ab00c55ac91", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", "0x5", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", "0x2", "0xbda8ead4de04074dca870401158c646", "0x24536f648a5b39d277dfca3f416118f8", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", "0x3", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", "0x0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", "0x2", "0x571265dee208a842bd24b00d9ef03cab9d75cde3fd940fdebdc98b930cf635a", "0x6756c71d08ff148f5d623765cbf6969bf88390eeae0968b29185c76619e5d51"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0xbdac2ee80cd888998e3233d2ad3d8760f58582d82fce9b6272d3177d9d7dea", "version": "0x1", "max_fee": "0x354a6ba7a18000", "signature": ["0x7b75a1c526feff49f43ea098f6423cc463ef603e847ac5a2c5e419f97931693", "0x1e6deeff6fc9239de2d2356452dd047b8055ffb43fbb82f5a53228eaded43b5"], "nonce": "0x2b16", "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x5", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x3604cea1cdb094a73a31144f14a3e5861613c008e1e879939ebc4827d10cd50", "0x7", "0x19de7881922dbc95846b1bb9464dba34046c46470cfb5e18b4cb2892fd4111f", "0x2d7cf5d5a324a320f9f37804b1615a533fde487400b41af80f13f7ac5581325", "0x4", "0xa1b72fcd5be6af767d745199f73dbfb425b34a60", "0x2", "0x295e81336118da80d9deef4f5c67272f2195f7bfaf175a387ea1dbd50d9f5c6", "0x94a852b9c75eed97c3458c1b4a3916fbe40eebfbe6f36f494881b89e98e0f7", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", "0x6", "0x1acb1a91d60fdc1fc1c8403949e8f97c6066de26be3cd4ee7b0b0d44f5e8441", "0x3", "0x7f98353f5a29ef95702930c304c98b14ccca62c82dbc49e2dc14c3c6c6191d7", "0xe6d48809cc6e0cf670c0f05aae20747c3e5a4ea0c619d465f296dd05946ccf", "0x400c16a3b7f0a2fd2575962c75beb90376defce72ed3d206d17327884e21b6e", "0x45e8abe8d79936f9c9acaaa30eb7facba0cd1bb08b7f15855a4d74364977f2f", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", "0x2", "0x5ea4648fff8c7f3ef9ede48f7f534e5d2703106394dab5ba265db271b4e1c8", "0x4a08b85df0047321aff3eb785a6b76e1d99e601b6aa2db2a08d35424a146a9c", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x3604cea1cdb094a73a31144f14a3e5861613c008e1e879939ebc4827d10cd50", "0x4", "0x19de7881922dbc95846b1bb9464dba34046c46470cfb5e18b4cb2892fd4111f", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x1", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", "0x1", "0x47b2d2189c76735f4ade97b9585c85c805a8807bc3c22141c3131459256c0e8"], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x715b99aec587534547d4e33e0816e40129342404dcdb7b2f6cb5d75976f6595", "version": "0x3", "signature": ["0x758987c1e6d0ed57acb29d2bab5b3d1d1cdc3cd621d51a387eb7aa8dae12fd6", "0x25105a79b0f1022d9e32b1a288060c3f8927ff506f30e333dc7c8fd0e77951e"], "nonce": "0x2b17", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x6", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x1", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x169f135eddda5ab51886052d777a57f2ea9c162d713691b5e04a6d4ed71d47f", "0x4", "0x19de7881922dbc95846b1bb9464dba34046c46470cfb5e18b4cb2892fd4111f", "0x174f7a59ed3cafd016a00d1f2662d0340b237634c62e6c8cb41fcd28c40facd", "0x0", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", "0x1", "0x233117f6b96e6c38532500d51fa8e88aa2d291231e531db24a9915a15d3a919", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x1", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0xb4b791ff3b1855355f8ed7e0eec3b5cf", "0xb120d90d71d8efbf8eb5d2e225ac38da", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", "0x1", "0x1cb6b26d1e1bb70447ff3197aa68d82e6870f04325fe9df09d2d54b58c23583"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x4364ff805b7cab23338929dc8927ae982f74b8b5970dda00f36ca97eb1deb28", "version": "0x3", "signature": ["0x7c0fbee6a598a351360d5eac79082bf2da01a789b49ac56a8e9a4fbfccfd87", "0x451b04c37763f88aed43d9d4f147b4c28e53ddea531a55d9b57f9f72513fe05"], "nonce": "0x2b18", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x6", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", "0x6", "0x7ce989b0419ef8fe25e6840faa1c773d72ba3348c55180662748e63a105a786", "0x3", "0xc7f6f73697f21eac88b7d95deeaf48acc8aec543a90b64b00bb1902660b57b", "0x146b1e6617de03414d6b766339c823f4f0b090b8a383d4c3bc8371e1e9b2729", "0x5b72ae12e06513fcd37083cca27aa83898b8a1064fb7c936d1bf93517fa1e22", "0xb1b17c4a60ffd0a634e1d713ae5bd3ca2ead781cd35ae5674fd855a5795158", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", "0x1", "0x478da66587824115dc0f98ad7be0e9a103cf27d200cc2dff31b5932c46e10c3", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0x2e085134a16ebfafa44a16d146026a24", "0x3e705c878d7b37b5bfc2478c598ef1b0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", "0x2", "0x13bc8ce5125f1186f2dbd5bd06044f0755373d9707ee78e748b8bfc9d984439", "0x4151c442d9d919b55e628d871277089ef237b04b25311961af0b21daa46aca6", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", "0x6", "0x77005947a2dad7aa2389374892cc3d719571b33229bbe1bd16aac13b22fa1b0", "0x3", "0x2b73e559128d2c78c1e9d8c5a54f4cf7ed878f19af1bf70909d1f87124da7ba", "0x3dd38cbf00e2d583d5bbce77623c3ac3cd5461710a2b2e78045c12078e9976f", "0x5aef01d048765fd2b399b15a0fa4414254f1dfb22caf535b489beea48ed9079", "0x1c453eacc7c47a6535d43c88374958b4955d02393919e9161ea94e73ae11a2a", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x17da35ce4ed77e22e3b9149fd965dba57351a6c29f588a7d245e208d073e4c1", "0x0"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x77a8d43ca8fd40069f884b7773577d63fa954065c3b1a1daa421dfa87ec6afa", "version": "0x3", "signature": ["0x41e2addd6e2ec96d02d177abb71371755b8a3af0a9ba1726b69e6ae9aa88481", "0x4a99ddc92a8f2d3b6664efb90ada05bbf7e16b0ec8408f46110f1b9d34a7c09"], "nonce": "0x2b19", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x6", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", "0x4", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x1", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", "0x6", "0x3fe2ae4b30012d46c1f883db48c2d54cea76abf6b5870adbf4a3f8de97fe84c", "0x3", "0x48cbfaaa29757c20f9bd898aa285b66b049876d67b47424176e945ffb6cbb73", "0x188896a20fbe98a0fe8e35cdac9d3ac809260de7288331c1901b8a0241eb050", "0x4edb416bd209c871e52843ae78bacdb9347ba0bb25449f125bb78af1d34ce7f", "0x1a00d61f010f9e891c33c45d1baa1d8fbb78b825ff31d85f67ba0e0ec2e9b6a", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", "0x2", "0xc623389a9d41fec3dfc9dc7b414a727e", "0x78274dae4861a5839ce9063b83d8daf3", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", "0x0", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", "0x1", "0x73f787fa47d46e38dd6d6630eb5adfc12f1f3448be1a5bfcb1ee4ff4c673c41", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x169f135eddda5ab51886052d777a57f2ea9c162d713691b5e04a6d4ed71d47f", "0x4", "0x19de7881922dbc95846b1bb9464dba34046c46470cfb5e18b4cb2892fd4111f", "0x4e50a2b09771dd09d10717e9f231b0df3851085280e38e666c448b1fd896489", "0x0", "0x0"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x58177e246ff04b9b229a68910a374605766a298254e357b30aaeb8edaf9d66d", "version": "0x3", "signature": ["0x73a3aba1ea0123702575fa1d662428f7d330e528b99324b43d77106675d178d", "0x6bb624d7fc32ffc0500991614a55e9531c03bfdb3448ea32123a1e88faeb6f4"], "nonce": "0x2b1a", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x5", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", "0x6", "0x699baf12807140f31ae31552b26bcdfa9d5abd2cdfe25a6505452f0bbdd31c1", "0x3", "0x429ca58b9b7d74ffdf0f2834eb13881bc3133027694c42076b31dad26f5583b", "0x4c055756c36807649f3c6b403313cc82db56c8f303ede8ecb2b8861c67f255e", "0x31da6141fcf54cc7595791dfa3cd1aeedb2062955de755c370c26ef111e1791", "0x5dde871eeba96b8fbbf84ee6d78fc2e9431a6c1f5c5f942601a70abe5860902", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x1", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x1", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x1", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", "0x6", "0x557e86f7dbca848da70ca314e09d4c2d3aa0ffce4c595172b2d41e78632f837", "0x3", "0x7cc095ee2c4c6cb238c19bd2267a7cded49f8ac8ce6f8de22acdf9c1d736e1f", "0x69f642da1980792daf9890e7f76966f9addeaebfe0150f2a264f4fe4e17ed10", "0x37301f8848d498baa6088a9da64b9a58bb557d4035367bcb1e69a24b67df765", "0x6ad0a6e5af2ec53793262ead372a2524f7bccda1db09cd545bfdc3951e79447"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}, {"transaction_hash": "0x1f55ed06d78117d417899bd94eda790bea602379e1c43f8b86d859d92eff38", "version": "0x3", "signature": ["0x758887ba77a567096ab1aa88e3f60e3c1828f1da0a76a246b31ce2913414817", "0x1f0964dd2b090be6f800982c2a0d2e05fe2b213c81ae3e14cc929b2dec3acc6"], "nonce": "0x2b1b", "nonce_data_availability_mode": 0, "fee_data_availability_mode": 0, "resource_bounds": {"L1_GAS": {"max_amount": "0xc3500", "max_price_per_unit": "0x5543df729c000"}, "L2_GAS": {"max_amount": "0x0", "max_price_per_unit": "0x0"}}, "tip": "0x0", "paymaster_data": [], "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "calldata": ["0x6", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", "0x2", "0x168c74c6c2d6911cc5e223a0680d754b3b4934022fc9463cace69d4a2b9dbce", "0x2c57ea26ec79a71efeb4d3601883d7d71d555986ecdb7c3fd9e1bd7e0c19da8", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", "0x0", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", "0x2", "0x35c857f538814c8f47ffd6d6decc1173", "0x6a25775a51476c4d2ba3a0a8dfdfae1d", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x2d7cf5d5a324a320f9f37804b1615a533fde487400b41af80f13f7ac5581325", "0x4", "0x9cdf07d5726bc54bf908bee8caed3d3ecc5263ff", "0x2", "0x4066ebb426311bfe53ab1580e14fb2379a5d7d610695c9b05d11beb2c444376", "0x8d380443209a3ec5875d5e25d361936b3b75cd45d39f1ad5dc7f4e601b179e", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", "0x2", "0xa4100e4985a8fe24f4c8d2b9e963dcc9", "0xd22d5d37d75f2f426378a78e2f09714a", "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", "0x4", "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", "0x1", "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea"], "account_deployment_data": [], "type": "INVOKE_FUNCTION"}], "timestamp": 1721022890, "sequencer_address": "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "transaction_receipts": [{"execution_status": "SUCCEEDED", "transaction_index": 0, "transaction_hash": "0x195e0414c0c8dea28fde9944a71bd97abea493826d302e2030d9c0249985237", "l2_to_l1_messages": [], "events": [{"from_address": "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "keys": ["0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4"], "data": ["0x54ac7e24b2048fc11c6acd60e4ed10c43867d240968fcb8feee8456ce1834a", "0x3", "0x1effc638ac1dab44be3251b9481fa6ae5e793a5d863f930254153a071238556", "0x60842344c544cebb67f822fce41f409047aad7e83499960b970dba7874a7992", "0x513f6b8d4f96f5e5c02df23e7b78a775188d2754cfa27aab1aae350be8ec776"]}, {"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0xda999d63e40da", "0x0"]}], "execution_resources": {"n_steps": 17931, "builtin_instance_counter": {"poseidon_builtin": 5, "bitwise_builtin": 6, "pedersen_builtin": 44, "ec_op_builtin": 3, "keccak_builtin": 1, "range_check_builtin": 874}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 256}, "total_gas_consumed": {"l1_gas": 49, "l1_data_gas": 256}}, "actual_fee": "0xda999d63e40da"}, {"execution_status": "SUCCEEDED", "transaction_index": 1, "transaction_hash": "0x4000d1e50af1fff8150bb5fd8558a5146952171804ba967358a5fe0e6b0e354", "l2_to_l1_messages": [], "events": [{"from_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0x8ab05be7bd", "0x0"]}], "execution_resources": {"n_steps": 15214, "builtin_instance_counter": {"bitwise_builtin": 6, "ec_op_builtin": 3, "poseidon_builtin": 4, "range_check_builtin": 683, "keccak_builtin": 1, "pedersen_builtin": 34}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 128}, "total_gas_consumed": {"l1_gas": 41, "l1_data_gas": 128}}, "actual_fee": "0x8ab05be7bd"}, {"execution_status": "SUCCEEDED", "transaction_index": 2, "transaction_hash": "0x1d5adbb883c7a0bca0f77ae2dfdce4ad0e1a74098c19042c8e4e62fa85fffdb", "l2_to_l1_messages": [], "events": [{"from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "keys": ["0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4"], "data": ["0x2efe3ae7f7d837b89fdecbf7b7945ce3b25aaf05af34e1efb05e0547f1ee386", "0x3", "0x1f079c6646bc296715cd4dd16aa925ce5b0d3b4451f8a9bbc4cbc640f597028", "0x33010c7c261820fde09299468cdf37a9eb00a24996974d064e99dfa773be529", "0x1e03394ec22f3057f33e71f64aea7bee380e434c102e428e7b371453cba01a6"]}, {"from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "keys": ["0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4"], "data": ["0x503e8a1838da4c1f6cc8f5034720744ea17fb42cea8fff5325cac8af867a31e", "0x3", "0x5a42ab0819e4fb5af67cfbc5c7cee60add07d61dba6c4872f9bdfa8b8db7e0f", "0x2935ea46f5da5df3e0ac6c41882cfdbae828fbcc3dff634a94c2db075d94765", "0x2aa78c08c048e674553c8db20bb4dddd80a8c3dbfd25b9168adb5b8e6627eb4"]}, {"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0x1448dd1f32fe258", "0x0"]}], "execution_resources": {"n_steps": 269125, "builtin_instance_counter": {"poseidon_builtin": 8, "range_check_builtin": 28964, "ec_op_builtin": 3, "pedersen_builtin": 58}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 416}, "total_gas_consumed": {"l1_gas": 1164, "l1_data_gas": 416}}, "actual_fee": "0x1448dd1f32fe258"}, {"execution_status": "SUCCEEDED", "transaction_index": 3, "transaction_hash": "0x2a2e7175a982ddb0d1636d453692a6de9c8542b40f2230d684070aff102b31a", "l2_to_l1_messages": [], "events": [{"from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "keys": ["0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4"], "data": ["0x3e24d7e4732ddf3f933bf601ee207f42004159f8a1474ab3448ecf6cca36cff", "0x3", "0x7749874b2259b32547758256b902d9b46ed2b1e066867b967ed02ba3a8fd267", "0x5bce1cd81751fa197b1583eae513f3948cf3299ad3428f76724e2af9558a7d4", "0x4f8cf745cf31a95ff415b79eb94eba142a798d1aa812fc49e108b8ee5efd260"]}, {"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0x1417ca47aa1b67a", "0x0"]}], "execution_resources": {"n_steps": 265383, "builtin_instance_counter": {"range_check_builtin": 28750, "pedersen_builtin": 36, "ec_op_builtin": 3, "poseidon_builtin": 5}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 128}, "total_gas_consumed": {"l1_gas": 1153, "l1_data_gas": 128}}, "actual_fee": "0x1417ca47aa1b67a"}, {"execution_status": "SUCCEEDED", "transaction_index": 4, "transaction_hash": "0x451a26cbcd55d2281c1b2c24445a5469d2fc16da4159c44d3b04a76579b5443", "l2_to_l1_messages": [], "events": [{"from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "keys": ["0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4"], "data": ["0x5be0ead6150d49c16a6277e7290e2d949a9e99b6c4aa0a3c3abf06ced66ad19", "0x3", "0x29224b3670651d8012b718c5054731e012817da20d50f7b54c6f8092ac130cd", "0x3b644a3062bc3a55da8cc0d5bb9420d3b37124840c18423e7886c020bd85460", "0x372a463e2aca39366b207734cec5b4612ed71582f97904e31a65b16dca90b69"]}, {"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0xec71e3e5ec442", "0x0"]}], "execution_resources": {"n_steps": 19872, "builtin_instance_counter": {"pedersen_builtin": 43, "range_check_builtin": 946, "poseidon_builtin": 4, "ec_op_builtin": 3}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 128}, "total_gas_consumed": {"l1_gas": 53, "l1_data_gas": 128}}, "actual_fee": "0xec71e3e5ec442"}, {"execution_status": "SUCCEEDED", "transaction_index": 5, "transaction_hash": "0x67ffd6807ec99456360431e3411ff24d94bbb7db058c5a427540720d3f23bc7", "l2_to_l1_messages": [], "events": [{"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0x121fac8bb7507a", "0x0"]}], "execution_resources": {"n_steps": 24141, "builtin_instance_counter": {"poseidon_builtin": 6, "pedersen_builtin": 45, "ec_op_builtin": 3, "range_check_builtin": 1291}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 256}, "total_gas_consumed": {"l1_gas": 65, "l1_data_gas": 256}}, "actual_fee": "0x121fac8bb7507a"}, {"execution_status": "SUCCEEDED", "transaction_index": 6, "transaction_hash": "0x651b1acfa1652c7eb678979a8cd26df183dd3fe3e16ad26bf1b5c150547893", "l2_to_l1_messages": [], "events": [{"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0x11498909b09d8c", "0x0"]}], "execution_resources": {"n_steps": 23110, "builtin_instance_counter": {"poseidon_builtin": 7, "pedersen_builtin": 48, "range_check_builtin": 1115, "ec_op_builtin": 3}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 256}, "total_gas_consumed": {"l1_gas": 62, "l1_data_gas": 256}}, "actual_fee": "0x11498909b09d8c"}, {"execution_status": "SUCCEEDED", "transaction_index": 7, "transaction_hash": "0x30b2d48fd3c80877d7c05dcdd9535ba500570f22c5c8ff2354707d78b89b511", "l2_to_l1_messages": [], "events": [{"from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "keys": ["0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4"], "data": ["0x4619138d933b114b7942c93762827303aab9ff0a8b876765802ef7cb60ba658", "0x3", "0x32d345a97bc0db35ae9578aff71192bd142595afe1720056892f00c245fddf1", "0x3748f3eefc81fd923a83f9ab2d9ea2ee41378fde4de92257a067538138faba3", "0x1265c400681e1fdea145d3857b045a792a882334bf858335716c2934e189838"]}, {"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0xc44b3b84aab78", "0x0"]}], "execution_resources": {"n_steps": 16033, "builtin_instance_counter": {"poseidon_builtin": 5, "range_check_builtin": 638, "ec_op_builtin": 3, "pedersen_builtin": 43}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 128}, "total_gas_consumed": {"l1_gas": 44, "l1_data_gas": 128}}, "actual_fee": "0xc44b3b84aab78"}, {"execution_status": "SUCCEEDED", "transaction_index": 8, "transaction_hash": "0x24c7fb9c2336b7a3db94970c71d095b464ff25f47e4c62f505d8bd3c86a784c", "l2_to_l1_messages": [], "events": [{"from_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0xe2a3c9c99f", "0x0"]}], "execution_resources": {"n_steps": 24991, "builtin_instance_counter": {"range_check_builtin": 1352, "bitwise_builtin": 6, "ec_op_builtin": 3, "keccak_builtin": 1, "poseidon_builtin": 5, "pedersen_builtin": 51}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 288}, "total_gas_consumed": {"l1_gas": 67, "l1_data_gas": 288}}, "actual_fee": "0xe2a3c9c99f"}, {"execution_status": "SUCCEEDED", "transaction_index": 9, "transaction_hash": "0x2f32394596d4bd1ddc5c7599ae53db8309893e1dbeadebaebb282763abcad27", "l2_to_l1_messages": [], "events": [{"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0x102c045c5259a4", "0x0"]}], "execution_resources": {"n_steps": 21776, "builtin_instance_counter": {"bitwise_builtin": 6, "keccak_builtin": 1, "range_check_builtin": 1159, "pedersen_builtin": 43, "ec_op_builtin": 3, "poseidon_builtin": 6}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 256}, "total_gas_consumed": {"l1_gas": 58, "l1_data_gas": 256}}, "actual_fee": "0x102c045c5259a4"}, {"execution_status": "SUCCEEDED", "transaction_index": 10, "transaction_hash": "0xa62ee89e1402d61683d961a18e5820f42d061c9615022ada8b13c24202c688", "l2_to_l1_messages": [], "events": [{"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0x14e9784e726a5e", "0x0"]}], "execution_resources": {"n_steps": 28192, "builtin_instance_counter": {"poseidon_builtin": 5, "pedersen_builtin": 52, "ec_op_builtin": 3, "range_check_builtin": 1608}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 288}, "total_gas_consumed": {"l1_gas": 75, "l1_data_gas": 288}}, "actual_fee": "0x14e9784e726a5e"}, {"execution_status": "SUCCEEDED", "transaction_index": 11, "transaction_hash": "0x5cc90d16fc214b41f79fb7e6eaa9d54c86c480bd575a2af7f4ad9dedba6276f", "l2_to_l1_messages": [], "events": [{"from_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0xdbdef3aab5", "0x0"]}], "execution_resources": {"n_steps": 24762, "builtin_instance_counter": {"ec_op_builtin": 3, "pedersen_builtin": 38, "poseidon_builtin": 3, "range_check_builtin": 1406}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 128}, "total_gas_consumed": {"l1_gas": 65, "l1_data_gas": 128}}, "actual_fee": "0xdbdef3aab5"}, {"execution_status": "SUCCEEDED", "transaction_index": 12, "transaction_hash": "0x6753e208f73a868d74312420692d12e69751e40bcf89c021119c24490ece9ad", "l2_to_l1_messages": [], "events": [{"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0xcd3760ef9cd6c", "0x0"]}], "execution_resources": {"n_steps": 17466, "builtin_instance_counter": {"pedersen_builtin": 34, "range_check_builtin": 815, "poseidon_builtin": 6, "ec_op_builtin": 3}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 128}, "total_gas_consumed": {"l1_gas": 46, "l1_data_gas": 128}}, "actual_fee": "0xcd3760ef9cd6c"}, {"execution_status": "SUCCEEDED", "transaction_index": 13, "transaction_hash": "0x41bdd5c64656ccc96115120b5b05215cc995f78b1587dca49feaf4aedca2631", "l2_to_l1_messages": [], "events": [{"from_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0x9838e32d91", "0x0"]}], "execution_resources": {"n_steps": 16547, "builtin_instance_counter": {"range_check_builtin": 751, "ec_op_builtin": 3, "pedersen_builtin": 39, "poseidon_builtin": 7}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 256}, "total_gas_consumed": {"l1_gas": 45, "l1_data_gas": 256}}, "actual_fee": "0x9838e32d91"}, {"execution_status": "SUCCEEDED", "transaction_index": 14, "transaction_hash": "0x3d0d388f2810a550b11dc9f1ed6b747b3bcdbc5ba1f6c4e19a37e5360dea0f8", "l2_to_l1_messages": [], "events": [{"from_address": "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "keys": ["0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4"], "data": ["0x4b69423be6879cf6d118721dfecfab9d1afbab93c5706e6930c4bf3be81d791", "0x3", "0x49c8205ced269d1ced335d5c501e63ab4e44d98a0650fa927d280d3f7c36230", "0x54948a4b82b56b98f1cb2043401028a428c78f3f6df737d3d3a2678e733dc3d", "0x2293a32380507e57f9ef6bf716af36086f17cdfae9a369a52b2a17b1c2678d1"]}, {"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0x110227991b4c12", "0x0"]}], "execution_resources": {"n_steps": 22573, "builtin_instance_counter": {"range_check_builtin": 1151, "ec_op_builtin": 3, "poseidon_builtin": 4, "pedersen_builtin": 46}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 128}, "total_gas_consumed": {"l1_gas": 61, "l1_data_gas": 128}}, "actual_fee": "0x110227991b4c12"}, {"execution_status": "SUCCEEDED", "transaction_index": 15, "transaction_hash": "0x71789cc9d5ea16b746d857265754d21fc0686d327f46d06ddee21fdd3ca88bb", "l2_to_l1_messages": [], "events": [{"from_address": "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "keys": ["0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4"], "data": ["0x212ff21302b29f74fcf5847ca85efb7ce2cc579fe69aa3ce1b234737faf2d66", "0x3", "0x6f01640f0164f58cc7dbcf8a97ed7a3eca7bf9014809d47aad40bff3390234a", "0x246c45ebaed09c37ab7268e28f8d60cc8d5dffa102ba3823b1fcf285b6b4588", "0x356d4583e6d8a026858ae2c2f7ee62a857f8373d8b8fd384220a17242af6b1a"]}, {"from_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0x9838e32d91", "0x0"]}], "execution_resources": {"n_steps": 16229, "builtin_instance_counter": {"ec_op_builtin": 3, "poseidon_builtin": 6, "pedersen_builtin": 49, "range_check_builtin": 618, "bitwise_builtin": 6, "keccak_builtin": 1}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 256}, "total_gas_consumed": {"l1_gas": 45, "l1_data_gas": 256}}, "actual_fee": "0x9838e32d91"}, {"execution_status": "SUCCEEDED", "transaction_index": 16, "transaction_hash": "0x397df33c7aca7521db3df0052454e9d673e2f9e855c922c3e1d4cd4d12fb2bc", "l2_to_l1_messages": [], "events": [{"from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "keys": ["0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4"], "data": ["0x3debf9d54b0e563b8fe4b64eedf699a24bd4bcf8b9071aa27e99f25c88ba961", "0x3", "0x87ed1ff492fe3875dd94b50e2a32f370fe02cf0e60b453b69d5fcf393d9c01", "0x11ba08688015c45ad4415d1659dea6159a8df2935983bdc41b9b5613c55f886", "0x7000994f2467389db1e940804a166053d3929fca4f14d04ed51330ee6a1f4ce"]}, {"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0xda999d63e40da", "0x0"]}], "execution_resources": {"n_steps": 17613, "builtin_instance_counter": {"ec_op_builtin": 3, "pedersen_builtin": 48, "poseidon_builtin": 6, "range_check_builtin": 729}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 256}, "total_gas_consumed": {"l1_gas": 49, "l1_data_gas": 256}}, "actual_fee": "0xda999d63e40da"}, {"execution_status": "SUCCEEDED", "transaction_index": 17, "transaction_hash": "0x75e605c318963ca63a9355587cf82865227115327199a96e762c6dd7f032eed", "l2_to_l1_messages": [], "events": [{"from_address": "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "keys": ["0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4"], "data": ["0x5a84ba14f489e71466dbd10fbd54cb05450a0e2f38e2d99e3e587bc7cb63890", "0x3", "0x12dfd2e3413b429f95268d0d163b0fbef734358314ac2e77f6255c291c146dc", "0x144934c01839b32d64d21da2c53bcba79bf55c170700b07090d86eaa1a3650e", "0x7f1c2e64a60109d6681038d3994fea871d6507effc607342e7fef0c2d8e821d"]}, {"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0xe7fbd9d82b448", "0x0"]}], "execution_resources": {"n_steps": 18962, "builtin_instance_counter": {"ec_op_builtin": 3, "poseidon_builtin": 7, "range_check_builtin": 968, "pedersen_builtin": 44}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 384}, "total_gas_consumed": {"l1_gas": 52, "l1_data_gas": 384}}, "actual_fee": "0xe7fbd9d82b448"}, {"execution_status": "SUCCEEDED", "transaction_index": 18, "transaction_hash": "0x3b2c54a4a0fb53dcb1d139fd66b0d33ef292599d5779d6fbc9869a3443b16d7", "l2_to_l1_messages": [], "events": [{"from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "keys": ["0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4"], "data": ["0x36a003b9f26f41a345836abb901c1a71fcaa586d174dea5fc1dce6b1cc5a145", "0x3", "0x344abe714959a0289fff2c0d988cda83ba46965603e7839225726fc9c34f4cb", "0x3e4c1cb040c585a1b599031d44895054534683e9f03c41f14ef4ae3eeedf9ec", "0x8d434813d65c2e95a9840421588b6888383f09a6dcfce99b1f2057c3625024"]}, {"from_address": "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "keys": ["0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4"], "data": ["0x41c145fd2ed46fc644e408743a12081e8809cd16a5f0de242f33da1aadd3436", "0x3", "0x30edb7c0d02cb69d2dc750909c6290fa6b562bace746368bbf994338fd84724", "0x43d7fee256e3c65ec0b3e30f0237933c357a0731b74303939fac965e568cb78", "0x3091b52f28583e2a23ca109b9c372e9eb0d5d976c8f17c9ebfd42f0dccdb669"]}, {"from_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0x9b9ad42b06", "0x0"]}], "execution_resources": {"n_steps": 15603, "builtin_instance_counter": {"pedersen_builtin": 55, "range_check_builtin": 521, "poseidon_builtin": 6, "ec_op_builtin": 3}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 256}, "total_gas_consumed": {"l1_gas": 46, "l1_data_gas": 256}}, "actual_fee": "0x9b9ad42b06"}, {"execution_status": "SUCCEEDED", "transaction_index": 19, "transaction_hash": "0x7765195b77c0eea821a8f807f8fa022d2484d3bc848d519ea689d97c4015bff", "l2_to_l1_messages": [], "events": [{"from_address": "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "keys": ["0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4"], "data": ["0x6ec2cddbfdacf4cbd0108e87bb889213d139ff2e9eadf68c81157a3f0c7e769", "0x3", "0x7057660cdbeb602d9094eb34650d362c0b0d89057bc9f49163501da7c552e1f", "0x798891c19b8abaf6ee00f6a989eeea8cdfa76f3a4ad390fba68ecf9353fd687", "0x5deebf68d35fe0b2fc0f89b6c96e6e8ad88883993f9ab8ad56570f8f02d6d2a"]}, {"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0xd623865a8ef60", "0x0"]}], "execution_resources": {"n_steps": 17455, "builtin_instance_counter": {"pedersen_builtin": 45, "ec_op_builtin": 3, "poseidon_builtin": 5, "range_check_builtin": 723}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 128}, "total_gas_consumed": {"l1_gas": 48, "l1_data_gas": 128}}, "actual_fee": "0xd623865a8ef60"}, {"execution_status": "SUCCEEDED", "transaction_index": 20, "transaction_hash": "0x2d667c69935407d1482d8b0182ec02e5ec2cf71bbf6619f739dc8a0ae1e8b92", "l2_to_l1_messages": [], "events": [{"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0xabc1d0d5305a90", "0x0"]}], "execution_resources": {"n_steps": 172752, "builtin_instance_counter": {"keccak_builtin": 1, "poseidon_builtin": 7, "bitwise_builtin": 30, "range_check_builtin": 15325, "ec_op_builtin": 3, "pedersen_builtin": 37}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 256}, "total_gas_consumed": {"l1_gas": 616, "l1_data_gas": 256}}, "actual_fee": "0xabc1d0d5305a90"}, {"execution_status": "SUCCEEDED", "transaction_index": 21, "transaction_hash": "0x4c93adbd1aa8f107be890556eba8a4071515d5510b6a93fd35ecda87fc6df80", "l2_to_l1_messages": [], "events": [{"from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "keys": ["0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4"], "data": ["0x720213ac76a0f3f2565f04f51c8d13f00878dadb125a59c9a3d3c846e0ee72d", "0x3", "0x65dcd1a3b2933e6f20f019a97de3272d0549bf793e41a0144a7d21bbdb2fcf0", "0x8f260cdd6d8d7a9668d1bfa93136d12c15246e80975b8571e7d09c76207fbb", "0x430cf4d69439b8d69afb49f3c44286d78ce666e924c3b99e3aecae688a30bc3"]}, {"from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "keys": ["0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4"], "data": ["0x11ebde260ce04bcbafc74879bd67c1aa39a50a2d3af027f407147e18a5ee20f", "0x3", "0x158db84882f02aab220d39d821e92dafb4db61c3fa65acc8b80c6b11f4afd30", "0xd192afb935fdaf0a61c2ba39be015356ba32a25c839fdb6be44e771b43f1e", "0x4336b1b67cd7bd5ac601308c72b02e27659a932373facd00ca73dcc7d45e880"]}, {"from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "keys": ["0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4"], "data": ["0x82e6948d4df169db1d3d53f528a78224467d356457dc61b1c19145fb7a60d2", "0x3", "0x1ae7558984ac06156913dc6992b2a5c1122598f49e6965c5f8a71210c6721ae", "0x46707418ecb32d37b3c817a9c92884dcf4ded2bf98c756c255d7b8da05fd961", "0x55316930897583852f858e6a8311efdfac9b026bcac1312a52dfe524ce4c3b5"]}, {"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0xe385be7afa24e", "0x0"]}], "execution_resources": {"n_steps": 17485, "builtin_instance_counter": {"range_check_builtin": 789, "bitwise_builtin": 6, "keccak_builtin": 1, "ec_op_builtin": 3, "pedersen_builtin": 53, "poseidon_builtin": 3}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 128}, "total_gas_consumed": {"l1_gas": 51, "l1_data_gas": 128}}, "actual_fee": "0xe385be7afa24e"}, {"execution_status": "SUCCEEDED", "transaction_index": 22, "transaction_hash": "0x68a4d9bcff51d99fd3f5dc6df6e4902073cdf8d43575e3922f904d800517e8d", "l2_to_l1_messages": [], "events": [{"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0xadb5797dc16246", "0x0"]}], "execution_resources": {"n_steps": 175942, "builtin_instance_counter": {"range_check_builtin": 15459, "pedersen_builtin": 53, "keccak_builtin": 1, "poseidon_builtin": 9, "bitwise_builtin": 30, "ec_op_builtin": 3}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 480}, "total_gas_consumed": {"l1_gas": 623, "l1_data_gas": 480}}, "actual_fee": "0xadb5797dc16246"}, {"execution_status": "SUCCEEDED", "transaction_index": 23, "transaction_hash": "0xe0f970f4ce407adef51a760559ee6ee74a4769758768b808097b520216230b", "l2_to_l1_messages": [], "events": [{"from_address": "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "keys": ["0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4"], "data": ["0x66e6852463ea25790fb91b17d81f3d94c2d29690ce5283a19d54503c93c03d4", "0x3", "0x47a7420476d121e7481da71e59fe5eac3e6e058175191aac84315ced6f5d101", "0x203c2d2e3335474d659e032766de8c06a746175afabcbf6b21e49a2bc8d9565", "0x2490dd8f87566f3ba033a272c9eebfc0f3feae6bf5149b71b4d14c4dc26dfd2"]}, {"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0xda9999100805a", "0x0"]}], "execution_resources": {"n_steps": 18102, "builtin_instance_counter": {"range_check_builtin": 878, "ec_op_builtin": 3, "poseidon_builtin": 5, "pedersen_builtin": 40}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 128}, "total_gas_consumed": {"l1_gas": 49, "l1_data_gas": 128}}, "actual_fee": "0xda9999100805a"}, {"execution_status": "SUCCEEDED", "transaction_index": 24, "transaction_hash": "0x3d95cdb95afd14cbdb4c4669525e879dcb683baf81484a3e1f8d907153e53ed", "l2_to_l1_messages": [], "events": [{"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0xc44b3fd886bf8", "0x0"]}], "execution_resources": {"n_steps": 16360, "builtin_instance_counter": {"range_check_builtin": 702, "pedersen_builtin": 40, "poseidon_builtin": 6, "ec_op_builtin": 3}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 256}, "total_gas_consumed": {"l1_gas": 44, "l1_data_gas": 256}}, "actual_fee": "0xc44b3fd886bf8"}, {"execution_status": "SUCCEEDED", "transaction_index": 25, "transaction_hash": "0x4f0afadd2870468cf005f56bebded204bae8515a4e70a0a2ef4a55367cfc205", "l2_to_l1_messages": [], "events": [{"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0xb272fa6b758b0", "0x0"]}], "execution_resources": {"n_steps": 14687, "builtin_instance_counter": {"pedersen_builtin": 48, "range_check_builtin": 557, "ec_op_builtin": 3, "poseidon_builtin": 8}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 416}, "total_gas_consumed": {"l1_gas": 40, "l1_data_gas": 416}}, "actual_fee": "0xb272fa6b758b0"}, {"execution_status": "SUCCEEDED", "transaction_index": 26, "transaction_hash": "0x727effea1ae4e021bfa5435651f2ec0ddfc8d6c471f0e1948d89f00879ea099", "l2_to_l1_messages": [{"from_address": "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "to_address": "0xA0AdcE6dBaFf6bCE9f7a620A9ED209AA748A0b24", "payload": ["0x9b971fe02819281443860767515bcfbd4a87795e973ae4c5f0da3f38b3fc78", "0x138d2ff63ebe4cff9b97f36d9842f5784d1c14c77d552a9f202f700df99eb80"]}], "events": [{"from_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0x174a03e3851bd", "0x0"]}], "execution_resources": {"n_steps": 21123, "builtin_instance_counter": {"poseidon_builtin": 6, "ec_op_builtin": 3, "range_check_builtin": 982, "pedersen_builtin": 52}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 288}, "total_gas_consumed": {"l1_gas": 28201, "l1_data_gas": 288}}, "actual_fee": "0x174a03e3851bd"}, {"execution_status": "SUCCEEDED", "transaction_index": 27, "transaction_hash": "0x5a6591fddd64df4f57b64543c00a1bc788485b2f558056ea853548d3d1e9637", "l2_to_l1_messages": [], "events": [{"from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "keys": ["0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4"], "data": ["0x367d67d017a167d525cb8d18acd2b7aa354b96db81d60949ec7fb66c4f1f674", "0x3", "0x755c24b1b54061ed134fd9d6f0d910f166b1d134cafb9a1fbd62300b1eefa02", "0x5daa8bcd0707512e3d7c6230d40198e0a7190009ae097f9b2e2963441560f3f", "0x3acc6203b842ebd20e31109d66d8bc8ca2e55495bb4e3ceb90ab6b268fa8843"]}, {"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0xf55e0950de636", "0x0"]}], "execution_resources": {"n_steps": 20369, "builtin_instance_counter": {"pedersen_builtin": 48, "poseidon_builtin": 3, "ec_op_builtin": 3, "range_check_builtin": 934}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 128}, "total_gas_consumed": {"l1_gas": 55, "l1_data_gas": 128}}, "actual_fee": "0xf55e0950de636"}, {"execution_status": "SUCCEEDED", "transaction_index": 28, "transaction_hash": "0x667247e8ae4537222be926e7d29001431251f70024836752c4cbe68a5377beb", "l2_to_l1_messages": [], "events": [{"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0x14903e4521bc158", "0x0"]}], "execution_resources": {"n_steps": 274405, "builtin_instance_counter": {"ec_op_builtin": 3, "pedersen_builtin": 44, "range_check_builtin": 29383, "poseidon_builtin": 5}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 256}, "total_gas_consumed": {"l1_gas": 1180, "l1_data_gas": 256}}, "actual_fee": "0x14903e4521bc158"}, {"execution_status": "SUCCEEDED", "transaction_index": 29, "transaction_hash": "0xafdac29914cf6054190cf08c1a83acbbdc86a413690f40326b9aae545253e8", "l2_to_l1_messages": [], "events": [{"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0xfe4a35399a8ea", "0x0"]}], "execution_resources": {"n_steps": 20802, "builtin_instance_counter": {"ec_op_builtin": 3, "poseidon_builtin": 6, "pedersen_builtin": 45, "range_check_builtin": 1030}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 320}, "total_gas_consumed": {"l1_gas": 57, "l1_data_gas": 320}}, "actual_fee": "0xfe4a35399a8ea"}, {"execution_status": "SUCCEEDED", "transaction_index": 30, "transaction_hash": "0x14786356d92d3359426657aba526e8e6bc3c6913beb2a06fd5a1af3254c8ca6", "l2_to_l1_messages": [], "events": [{"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0xe7fbd5844f3c8", "0x0"]}], "execution_resources": {"n_steps": 19480, "builtin_instance_counter": {"bitwise_builtin": 6, "range_check_builtin": 1056, "poseidon_builtin": 5, "ec_op_builtin": 3, "keccak_builtin": 1, "pedersen_builtin": 36}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 256}, "total_gas_consumed": {"l1_gas": 52, "l1_data_gas": 256}}, "actual_fee": "0xe7fbd5844f3c8"}, {"execution_status": "SUCCEEDED", "transaction_index": 31, "transaction_hash": "0x644839d53b3e8e9d4690a19ab35f0564b249c58443774ffaa8e4db4a8890ee7", "l2_to_l1_messages": [], "events": [{"from_address": "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "keys": ["0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4"], "data": ["0x48ba4a09e3cfc54a0fb13826f9d9066f019db290b3ac4ca202f9e284013e38c", "0x3", "0x582a7beb60027e27dabc1a9e9b4746528535aae1c47ea1a2224fcfed00ea52c", "0x51eadf84f9e6df0d7079bb184cb44e34bb311edcc62d1e94d5b1ac2f1d6b8a3", "0x2c08e60b9a4f7106c503b13b490fbff384b07726e0e156ac27563ff05114b20"]}, {"from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "keys": ["0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4"], "data": ["0x47b42da4835595cf4cfd06826eb76ed95ea8dc2f777b0c4acd2e0809e6680fe", "0x3", "0x4333048345c017b97d18648e47c5fc51e8ab6127ed22f6eb1cc810c6163f6db", "0x203aed1de52fb8f7f43524752d45bea702df6f2ace6e5dac195de918fce2133", "0x316385dc04628c6b11a08b31006343bc98580278ced84ddf620e9738d69b055"]}, {"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0xf0e7faef415bc", "0x0"]}], "execution_resources": {"n_steps": 18899, "builtin_instance_counter": {"pedersen_builtin": 55, "poseidon_builtin": 6, "range_check_builtin": 765, "ec_op_builtin": 3}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 256}, "total_gas_consumed": {"l1_gas": 54, "l1_data_gas": 256}}, "actual_fee": "0xf0e7faef415bc"}, {"execution_status": "SUCCEEDED", "transaction_index": 32, "transaction_hash": "0x7f32793534b160cdc40e4ce20a8709adfa9bdd0b5860013698fc754b4103542", "l2_to_l1_messages": [], "events": [{"from_address": "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "keys": ["0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4"], "data": ["0xba435eb69d3226f365880885b2ce8596ba44ae0821dc9f8dc7907d14a282b", "0x3", "0x40a013b398bee56959eefd6c4edcc4675872dcf412ca5065a6f7c413b717732", "0x371a8adc1170613db866c390fb96e780d1a5c36cfa7f970724ff5e1b0a5675a", "0x287a7a8fba7421005c45b0f98e0d9605ae017e9bfb4b837c23bda6df6549787"]}, {"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0xaaa44be2945628", "0x0"]}], "execution_resources": {"n_steps": 171628, "builtin_instance_counter": {"bitwise_builtin": 30, "pedersen_builtin": 39, "ec_op_builtin": 3, "range_check_builtin": 15207, "poseidon_builtin": 3, "keccak_builtin": 1}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 128}, "total_gas_consumed": {"l1_gas": 612, "l1_data_gas": 128}}, "actual_fee": "0xaaa44be2945628"}, {"execution_status": "SUCCEEDED", "transaction_index": 33, "transaction_hash": "0x642146ccbb341535e2f4f7aa82ad34ab2d0dd6bcc5d98f6e9485638b67a6d", "l2_to_l1_messages": [], "events": [{"from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "keys": ["0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4"], "data": ["0x51814831a2493c60497a96034f00d3e72c1ca7b071631c1cd873c0e7b46f42", "0x3", "0x79f3c4cf6a5ecf86c3b4ffedbde7b884f61b408085a07f7e3f8a1c73dcd6792", "0x1f282d7be25fe585523745afba8f5ef4bcd9e8eade41b3fe25d8786b6b5fe98", "0x415081db9ad19aa0e2173ba93d99d0d6ed9a48385fbedb24c7c81dd18eed394"]}, {"from_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0xc4315cbc82", "0x0"]}], "execution_resources": {"n_steps": 21438, "builtin_instance_counter": {"ec_op_builtin": 3, "range_check_builtin": 928, "poseidon_builtin": 4, "pedersen_builtin": 50}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 128}, "total_gas_consumed": {"l1_gas": 58, "l1_data_gas": 128}}, "actual_fee": "0xc4315cbc82"}, {"execution_status": "SUCCEEDED", "transaction_index": 34, "transaction_hash": "0x72d70c0f1ab91afa262e842a6f3f8a98dd658da565c7279364999314ccbed5c", "l2_to_l1_messages": [], "events": [{"from_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0x91750132a7", "0x0"]}], "execution_resources": {"n_steps": 15391, "builtin_instance_counter": {"poseidon_builtin": 6, "pedersen_builtin": 44, "ec_op_builtin": 3, "range_check_builtin": 527}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 256}, "total_gas_consumed": {"l1_gas": 43, "l1_data_gas": 256}}, "actual_fee": "0x91750132a7"}, {"execution_status": "SUCCEEDED", "transaction_index": 35, "transaction_hash": "0x214d0a540e7b03414772c2c2de426eb5d4e4ad63668b6b81c35c0b2b2d6bcb4", "l2_to_l1_messages": [{"from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "to_address": "0xf40fBAA08BfABcd6fB1A0Ec3ea1fD8D0CdbAf82a", "payload": ["0x48c560eca37e048d7cb12b7ef2ea65d5e34a9b79a0379a1644939f7b9bf3f7c", "0x1d65cca89665e33658632b26a178c617b6e6d6b34c687244a94e89202b407f5"]}], "events": [{"from_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0x17499796232d3", "0x0"]}], "execution_resources": {"n_steps": 20168, "builtin_instance_counter": {"poseidon_builtin": 4, "pedersen_builtin": 45, "ec_op_builtin": 3, "range_check_builtin": 926}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 128}, "total_gas_consumed": {"l1_gas": 28199, "l1_data_gas": 128}}, "actual_fee": "0x17499796232d3"}, {"execution_status": "SUCCEEDED", "transaction_index": 36, "transaction_hash": "0x3aeb0a48ba255a5aae097ebdcead737a46ee6a768ada5dea2956aa2446107eb", "l2_to_l1_messages": [], "events": [{"from_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0xa5c0a72365", "0x0"]}], "execution_resources": {"n_steps": 18347, "builtin_instance_counter": {"pedersen_builtin": 36, "poseidon_builtin": 6, "ec_op_builtin": 3, "range_check_builtin": 902}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 256}, "total_gas_consumed": {"l1_gas": 49, "l1_data_gas": 256}}, "actual_fee": "0xa5c0a72365"}, {"execution_status": "SUCCEEDED", "transaction_index": 37, "transaction_hash": "0x4b6c706b4a3038b41519a3dd6d0f5e8bc18d8425a1df493fb5de747558636c8", "l2_to_l1_messages": [], "events": [{"from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "keys": ["0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4"], "data": ["0x45697840297d58b4a4d5a5409c5ff698e080a7202bac696cac7997ab35909e4", "0x3", "0xb1cbd90586a7512eb49e81f604bc9cc37387dfa9be668cdbea1117690ae3a7", "0x46cd6cfafefae479a5c3c9f5f1ab86edab3f252d6d0e13442cd648c541408de", "0x588192bee153ea941a778fa2f6be1212d995437e93954b86d7b2e7995611994"]}, {"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0xe385c2ced62ce", "0x0"]}], "execution_resources": {"n_steps": 18983, "builtin_instance_counter": {"poseidon_builtin": 5, "range_check_builtin": 965, "pedersen_builtin": 42, "ec_op_builtin": 3}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 256}, "total_gas_consumed": {"l1_gas": 51, "l1_data_gas": 256}}, "actual_fee": "0xe385c2ced62ce"}, {"execution_status": "SUCCEEDED", "transaction_index": 38, "transaction_hash": "0x1f6fa1f89da0df7a186bacfd78e91b95d88f057a513e1214f8ff0a732de30f4", "l2_to_l1_messages": [], "events": [{"from_address": "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "keys": ["0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4"], "data": ["0x2d11bb5170a1f928b6ecd7b97e025a491a5cb5fc4855eb496e07835dff04487", "0x3", "0x692e616a28746075cb8a6e660f951cc842f43fc5a2030fa13a27bf7a41b179b", "0x2ef606af2baf35a9e60c618328075b4d309765e55c336ce29d79d3a3c5566ce", "0x12159a449f1a0c82c83906dd424f34f8b3e00073a67668a814cd9c1940167ce"]}, {"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0xb272f9567e890", "0x0"]}], "execution_resources": {"n_steps": 14274, "builtin_instance_counter": {"range_check_builtin": 563, "poseidon_builtin": 7, "ec_op_builtin": 3, "pedersen_builtin": 45}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 384}, "total_gas_consumed": {"l1_gas": 40, "l1_data_gas": 384}}, "actual_fee": "0xb272f9567e890"}, {"execution_status": "SUCCEEDED", "transaction_index": 39, "transaction_hash": "0x5d7941297f3232c0a98bd8e0b51d5d2464e97057147d06a0c41a07203c639ac", "l2_to_l1_messages": [], "events": [{"from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "keys": ["0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4"], "data": ["0x55cca0b45c9c4cee79718132afc5c4d2d1f4d029a29efc66b464e9209199af3", "0x3", "0x693aff98f855195256320c1744b36988e5efb7544af094f0234f5102b6fedc", "0x68f7ccc05e42591293a68372d8cce749527e66804a036b22a0b14098b862218", "0x282e2b68eb812129b5b2305aa4e1a45348ea41ba2bf9ab46d541b91d8ddafb4"]}, {"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0xa9ce290da8047a", "0x0"]}], "execution_resources": {"n_steps": 169544, "builtin_instance_counter": {"ec_op_builtin": 3, "poseidon_builtin": 8, "range_check_builtin": 15135, "keccak_builtin": 1, "pedersen_builtin": 42, "bitwise_builtin": 30}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 448}, "total_gas_consumed": {"l1_gas": 609, "l1_data_gas": 448}}, "actual_fee": "0xa9ce290da8047a"}, {"execution_status": "SUCCEEDED", "transaction_index": 40, "transaction_hash": "0x323977511f652a2c494d4b7ef52b713d20ba702c7edf1fd1495a5b7fcb9b44b", "l2_to_l1_messages": [], "events": [{"from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "keys": ["0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4"], "data": ["0x666c83f59b7389bac9789070aee65ace9e99ed5f4ffcb86a4d8aba7d338c98b", "0x3", "0x7b5b27757a05f6bb78487984f7a96e15a18c6053b4657886f5e4e6f91178f0f", "0x33695f320ce6d43202b522fa2d92c6e34118f960a0d9edb25ed15910682f596", "0x1e21d486fabbba4261dd3f6ac5148571bd250983730dee61ab8631afed8d89"]}, {"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0xb272f0aec6790", "0x0"]}], "execution_resources": {"n_steps": 14795, "builtin_instance_counter": {"range_check_builtin": 480, "pedersen_builtin": 43, "ec_op_builtin": 3, "poseidon_builtin": 3}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 128}, "total_gas_consumed": {"l1_gas": 40, "l1_data_gas": 128}}, "actual_fee": "0xb272f0aec6790"}, {"execution_status": "SUCCEEDED", "transaction_index": 41, "transaction_hash": "0x2c0957019f8956130340acd8c96bc5c93a03a3045cf90dd50b70d580377b61d", "l2_to_l1_messages": [], "events": [{"from_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0xf64b7380d71", "0x0"]}], "execution_resources": {"n_steps": 268748, "builtin_instance_counter": {"poseidon_builtin": 5, "ec_op_builtin": 3, "pedersen_builtin": 36, "range_check_builtin": 29038}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 256}, "total_gas_consumed": {"l1_gas": 1165, "l1_data_gas": 256}}, "actual_fee": "0xf64b7380d71"}, {"execution_status": "SUCCEEDED", "transaction_index": 42, "transaction_hash": "0x570a47e2a3aab957dd3d09f8fe778ccb54163bc4207585d3f1e7ad471197f1c", "l2_to_l1_messages": [], "events": [{"from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "keys": ["0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4"], "data": ["0x49d389ff8457b29a69c3d57c0450dc56b1406b9e822f08f88b6ff7fa11627e9", "0x3", "0x52afc8740c79463d83b7628c35dddd807f6d2858d860752f980000e87d8d854", "0x6f6a828242385c55eb76bb6c4f896492a91980e2551ccee675f7c6dfe79956a", "0x575b2db2490f75d6877f64f23cc14589958b4cf31da2c65d9663c6dcb656a23"]}, {"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0xd623865a8ef60", "0x0"]}], "execution_resources": {"n_steps": 17446, "builtin_instance_counter": {"ec_op_builtin": 3, "range_check_builtin": 721, "pedersen_builtin": 45, "poseidon_builtin": 5}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 128}, "total_gas_consumed": {"l1_gas": 48, "l1_data_gas": 128}}, "actual_fee": "0xd623865a8ef60"}, {"execution_status": "SUCCEEDED", "transaction_index": 43, "transaction_hash": "0x2cd6a8aea2b82b7e37d30451074c298e03c377feb90999c4fcdacf99ed46f97", "l2_to_l1_messages": [{"from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "to_address": "0x2EAe5B0fE2112b79ECef02b30243eE9a7CCE0eBE", "payload": ["0x11f17e586559af18b7e5beeb3fe68587e7e69f0b336079f9e3d03fa0343c783", "0x82a221fd714f879773458cfc0df8b8c2d5798ed9e57fb2afc3cc1c485e6f1c"]}], "events": [{"from_address": "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "keys": ["0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4"], "data": ["0x3ef516eb44f7a25907ebee82d2eed55a2b26882cb684da9a0b1358fe0672e12", "0x3", "0x1bfa88a6d84994c4cff5dec7d8e3aaa205b28b7bcfb7e5583f33508ee92b17b", "0x50a25225519d91ba161f48cad22cb84d48d5108c43665c0cd5d3a3ece0946b2", "0x23e92483a133a6aef2ec70e9faf85ae1afb61138bf385a28cf0281610bc4e86"]}, {"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0x1eb89415af45396c", "0x0"]}], "execution_resources": {"n_steps": 22821, "builtin_instance_counter": {"range_check_builtin": 1155, "ec_op_builtin": 3, "pedersen_builtin": 50, "poseidon_builtin": 3}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 128}, "total_gas_consumed": {"l1_gas": 28206, "l1_data_gas": 128}}, "actual_fee": "0x1eb89415af45396c"}, {"execution_status": "SUCCEEDED", "transaction_index": 44, "transaction_hash": "0x5e3470f9a6a059d2190685fb82ca05eeea79bcba70b591130aff661cd5fb828", "l2_to_l1_messages": [], "events": [{"from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "keys": ["0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4"], "data": ["0x5b6036498212930c0160795ee17255fb94291ff053251b855b6da5d97b74531", "0x3", "0x40a8bcf47285adcb19628e0480e1057968b655ae8ecde24ffd7086070b5b9a2", "0x3e1e8cf3b705f1039bee876a6a72988c59ebace9186ab399dae1c3f8b76b6fd", "0x383afa7ce58c752b62f44f4f86446226b2246731ecb15296971731882c10f3"]}, {"from_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0xb6a998c6ae", "0x0"]}], "execution_resources": {"n_steps": 19476, "builtin_instance_counter": {"range_check_builtin": 767, "poseidon_builtin": 3, "ec_op_builtin": 3, "pedersen_builtin": 53}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 128}, "total_gas_consumed": {"l1_gas": 54, "l1_data_gas": 128}}, "actual_fee": "0xb6a998c6ae"}, {"execution_status": "SUCCEEDED", "transaction_index": 45, "transaction_hash": "0x3c78d2cab2fc776e2dcccf55ecbbd480b9484953a8be01b8c0306f88b2ee774", "l2_to_l1_messages": [], "events": [{"from_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0xa5c16a7365", "0x0"]}], "execution_resources": {"n_steps": 18213, "builtin_instance_counter": {"pedersen_builtin": 42, "ec_op_builtin": 3, "poseidon_builtin": 7, "range_check_builtin": 852}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 384}, "total_gas_consumed": {"l1_gas": 49, "l1_data_gas": 384}}, "actual_fee": "0xa5c16a7365"}, {"execution_status": "SUCCEEDED", "transaction_index": 46, "transaction_hash": "0x2f8a9ceebe94631c2a75b078731515cee0e5ca12d2729575dc7d932f66593b6", "l2_to_l1_messages": [], "events": [{"from_address": "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "keys": ["0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4"], "data": ["0x37b72967ee34e9b00c45a6c1319ba8d28def41e60c8e0bbf91d440dedbf3a44", "0x3", "0x2e0afc0b8bdbc766d2d58ec64f78a0fc82c4f73abaff128c10005bb6a625475", "0x7a945a82f362f478cda98c5c2952dbd9d8d805f5f02b211bba7e3299f261979", "0x46aef08ffafe9b3e7644623e58f73dcf148fcf483a3fc9779836260bf576377"]}, {"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0x97ae84c1cc234", "0x0"]}], "execution_resources": {"n_steps": 12228, "builtin_instance_counter": {"poseidon_builtin": 5, "pedersen_builtin": 41, "range_check_builtin": 435, "ec_op_builtin": 3}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 256}, "total_gas_consumed": {"l1_gas": 34, "l1_data_gas": 256}}, "actual_fee": "0x97ae84c1cc234"}, {"execution_status": "SUCCEEDED", "transaction_index": 47, "transaction_hash": "0x65949106a60aa0465ccc50dfa41676fbef444c94b051b08248653e443f9532f", "l2_to_l1_messages": [], "events": [{"from_address": "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "keys": ["0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4"], "data": ["0x49083c6dbeada5ca48496d10c5b5fc879a66cfe2106edb7ad133c47089a461d", "0x3", "0x4e39b2f0a8f28116d4bcb252009dc6f9f99582801bb9a0d9338e69e572675c4", "0x33fc55ab493b435eddc00987bc0587689ded268a82ffc6d41e32d32f4e18ea5", "0x6f2747503b85199bef9ab777e17ee34bf358726cc1b9440d1a1c439ffeadaf8"]}, {"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0xf55e142284776", "0x0"]}], "execution_resources": {"n_steps": 20039, "builtin_instance_counter": {"range_check_builtin": 907, "ec_op_builtin": 3, "pedersen_builtin": 64, "poseidon_builtin": 9}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 448}, "total_gas_consumed": {"l1_gas": 55, "l1_data_gas": 448}}, "actual_fee": "0xf55e142284776"}, {"execution_status": "SUCCEEDED", "transaction_index": 48, "transaction_hash": "0x7c31171221dce0134eaed898eedef9a9283c46007d5a7205cbefb60bfdfdeae", "l2_to_l1_messages": [], "events": [{"from_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0xa25eb625f0", "0x0"]}], "execution_resources": {"n_steps": 17863, "builtin_instance_counter": {"poseidon_builtin": 5, "ec_op_builtin": 3, "range_check_builtin": 792, "pedersen_builtin": 40}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 256}, "total_gas_consumed": {"l1_gas": 48, "l1_data_gas": 256}}, "actual_fee": "0xa25eb625f0"}, {"execution_status": "SUCCEEDED", "transaction_index": 49, "transaction_hash": "0x57dc37799d80e5a4325b44b272177af28259afe4a08d9e035fcaa7463c78d1", "l2_to_l1_messages": [], "events": [{"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0xb10e06c7725c9e", "0x0"]}], "execution_resources": {"n_steps": 178910, "builtin_instance_counter": {"poseidon_builtin": 4, "range_check_builtin": 15777, "pedersen_builtin": 39, "ec_op_builtin": 3, "bitwise_builtin": 30, "keccak_builtin": 1}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 128}, "total_gas_consumed": {"l1_gas": 635, "l1_data_gas": 128}}, "actual_fee": "0xb10e06c7725c9e"}, {"execution_status": "SUCCEEDED", "transaction_index": 50, "transaction_hash": "0x5b112706c56d0e776f2074dac9622796190c46c460f6d3f7e21848a0f823564", "l2_to_l1_messages": [], "events": [{"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0xb6e907b81b90a", "0x0"]}], "execution_resources": {"n_steps": 15562, "builtin_instance_counter": {"range_check_builtin": 727, "ec_op_builtin": 3, "pedersen_builtin": 35, "poseidon_builtin": 6}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 256}, "total_gas_consumed": {"l1_gas": 41, "l1_data_gas": 256}}, "actual_fee": "0xb6e907b81b90a"}, {"execution_status": "SUCCEEDED", "transaction_index": 51, "transaction_hash": "0x2805277fab3bf13cabea921219a291b59f5c976c576b17880bbc6420df1d948", "l2_to_l1_messages": [], "events": [{"from_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0xc0cf6bbf0d", "0x0"]}], "execution_resources": {"n_steps": 21508, "builtin_instance_counter": {"ec_op_builtin": 3, "poseidon_builtin": 3, "pedersen_builtin": 38, "range_check_builtin": 1167}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 128}, "total_gas_consumed": {"l1_gas": 57, "l1_data_gas": 128}}, "actual_fee": "0xc0cf6bbf0d"}, {"execution_status": "SUCCEEDED", "transaction_index": 52, "transaction_hash": "0x8b6c4271730d086c0c63000fa2cc756f6915ce9d4c949aa03a3675f265d4c8", "l2_to_l1_messages": [], "events": [{"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0xec71ec8da4542", "0x0"]}], "execution_resources": {"n_steps": 19428, "builtin_instance_counter": {"ec_op_builtin": 3, "range_check_builtin": 890, "pedersen_builtin": 45, "poseidon_builtin": 8}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 384}, "total_gas_consumed": {"l1_gas": 53, "l1_data_gas": 384}}, "actual_fee": "0xec71ec8da4542"}, {"execution_status": "SUCCEEDED", "transaction_index": 53, "transaction_hash": "0xbdac2ee80cd888998e3233d2ad3d8760f58582d82fce9b6272d3177d9d7dea", "l2_to_l1_messages": [{"from_address": "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "to_address": "0xa1b72fcd5be6af767d745199F73Dbfb425B34A60", "payload": ["0x295e81336118da80d9deef4f5c67272f2195f7bfaf175a387ea1dbd50d9f5c6", "0x94a852b9c75eed97c3458c1b4a3916fbe40eebfbe6f36f494881b89e98e0f7"]}], "events": [{"from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "keys": ["0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4"], "data": ["0x1acb1a91d60fdc1fc1c8403949e8f97c6066de26be3cd4ee7b0b0d44f5e8441", "0x3", "0x7f98353f5a29ef95702930c304c98b14ccca62c82dbc49e2dc14c3c6c6191d7", "0xe6d48809cc6e0cf670c0f05aae20747c3e5a4ea0c619d465f296dd05946ccf", "0x400c16a3b7f0a2fd2575962c75beb90376defce72ed3d206d17327884e21b6e"]}, {"from_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0x1746a1ef7a66d", "0x0"]}], "execution_resources": {"n_steps": 14418, "builtin_instance_counter": {"range_check_builtin": 485, "ec_op_builtin": 3, "poseidon_builtin": 5, "pedersen_builtin": 50}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 256}, "total_gas_consumed": {"l1_gas": 28185, "l1_data_gas": 256}}, "actual_fee": "0x1746a1ef7a66d"}, {"execution_status": "SUCCEEDED", "transaction_index": 54, "transaction_hash": "0x715b99aec587534547d4e33e0816e40129342404dcdb7b2f6cb5d75976f6595", "l2_to_l1_messages": [], "events": [{"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0xd6238bc362000", "0x0"]}], "execution_resources": {"n_steps": 17743, "builtin_instance_counter": {"ec_op_builtin": 3, "range_check_builtin": 741, "pedersen_builtin": 50, "poseidon_builtin": 5}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 288}, "total_gas_consumed": {"l1_gas": 48, "l1_data_gas": 288}}, "actual_fee": "0xd6238bc362000"}, {"execution_status": "SUCCEEDED", "transaction_index": 55, "transaction_hash": "0x4364ff805b7cab23338929dc8927ae982f74b8b5970dda00f36ca97eb1deb28", "l2_to_l1_messages": [], "events": [{"from_address": "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "keys": ["0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4"], "data": ["0x7ce989b0419ef8fe25e6840faa1c773d72ba3348c55180662748e63a105a786", "0x3", "0xc7f6f73697f21eac88b7d95deeaf48acc8aec543a90b64b00bb1902660b57b", "0x146b1e6617de03414d6b766339c823f4f0b090b8a383d4c3bc8371e1e9b2729", "0x5b72ae12e06513fcd37083cca27aa83898b8a1064fb7c936d1bf93517fa1e22"]}, {"from_address": "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "keys": ["0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4"], "data": ["0x77005947a2dad7aa2389374892cc3d719571b33229bbe1bd16aac13b22fa1b0", "0x3", "0x2b73e559128d2c78c1e9d8c5a54f4cf7ed878f19af1bf70909d1f87124da7ba", "0x3dd38cbf00e2d583d5bbce77623c3ac3cd5461710a2b2e78045c12078e9976f", "0x5aef01d048765fd2b399b15a0fa4414254f1dfb22caf535b489beea48ed9079"]}, {"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0xac50932bdf7c84", "0x0"]}], "execution_resources": {"n_steps": 173484, "builtin_instance_counter": {"range_check_builtin": 15311, "poseidon_builtin": 5, "pedersen_builtin": 50, "bitwise_builtin": 30, "ec_op_builtin": 3, "keccak_builtin": 1}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 256}, "total_gas_consumed": {"l1_gas": 618, "l1_data_gas": 256}}, "actual_fee": "0xac50932bdf7c84"}, {"execution_status": "SUCCEEDED", "transaction_index": 56, "transaction_hash": "0x77a8d43ca8fd40069f884b7773577d63fa954065c3b1a1daa421dfa87ec6afa", "l2_to_l1_messages": [], "events": [{"from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", "keys": ["0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4"], "data": ["0x3fe2ae4b30012d46c1f883db48c2d54cea76abf6b5870adbf4a3f8de97fe84c", "0x3", "0x48cbfaaa29757c20f9bd898aa285b66b049876d67b47424176e945ffb6cbb73", "0x188896a20fbe98a0fe8e35cdac9d3ac809260de7288331c1901b8a0241eb050", "0x4edb416bd209c871e52843ae78bacdb9347ba0bb25449f125bb78af1d34ce7f"]}, {"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0xe7fbd699463e8", "0x0"]}], "execution_resources": {"n_steps": 19157, "builtin_instance_counter": {"ec_op_builtin": 3, "range_check_builtin": 781, "pedersen_builtin": 57, "poseidon_builtin": 5}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 288}, "total_gas_consumed": {"l1_gas": 52, "l1_data_gas": 288}}, "actual_fee": "0xe7fbd699463e8"}, {"execution_status": "SUCCEEDED", "transaction_index": 57, "transaction_hash": "0x58177e246ff04b9b229a68910a374605766a298254e357b30aaeb8edaf9d66d", "l2_to_l1_messages": [], "events": [{"from_address": "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "keys": ["0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4"], "data": ["0x699baf12807140f31ae31552b26bcdfa9d5abd2cdfe25a6505452f0bbdd31c1", "0x3", "0x429ca58b9b7d74ffdf0f2834eb13881bc3133027694c42076b31dad26f5583b", "0x4c055756c36807649f3c6b403313cc82db56c8f303ede8ecb2b8861c67f255e", "0x31da6141fcf54cc7595791dfa3cd1aeedb2062955de755c370c26ef111e1791"]}, {"from_address": "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "keys": ["0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4"], "data": ["0x557e86f7dbca848da70ca314e09d4c2d3aa0ffce4c595172b2d41e78632f837", "0x3", "0x7cc095ee2c4c6cb238c19bd2267a7cded49f8ac8ce6f8de22acdf9c1d736e1f", "0x69f642da1980792daf9890e7f76966f9addeaebfe0150f2a264f4fe4e17ed10", "0x37301f8848d498baa6088a9da64b9a58bb557d4035367bcb1e69a24b67df765"]}, {"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0x9c249323692ae", "0x0"]}], "execution_resources": {"n_steps": 11907, "builtin_instance_counter": {"pedersen_builtin": 45, "poseidon_builtin": 3, "ec_op_builtin": 3, "range_check_builtin": 368}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 128}, "total_gas_consumed": {"l1_gas": 35, "l1_data_gas": 128}}, "actual_fee": "0x9c249323692ae"}, {"execution_status": "SUCCEEDED", "transaction_index": 58, "transaction_hash": "0x1f55ed06d78117d417899bd94eda790bea602379e1c43f8b86d859d92eff38", "l2_to_l1_messages": [{"from_address": "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", "to_address": "0x9CdF07d5726BC54bf908beE8CAED3D3ECc5263fF", "payload": ["0x4066ebb426311bfe53ab1580e14fb2379a5d7d610695c9b05d11beb2c444376", "0x8d380443209a3ec5875d5e25d361936b3b75cd45d39f1ad5dc7f4e601b179e"]}], "events": [{"from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", "keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0x1eb72f301bcd250a", "0x0"]}], "execution_resources": {"n_steps": 21162, "builtin_instance_counter": {"poseidon_builtin": 6, "pedersen_builtin": 47, "ec_op_builtin": 3, "range_check_builtin": 1060}, "n_memory_holes": 0, "data_availability": {"l1_gas": 0, "l1_data_gas": 256}, "total_gas_consumed": {"l1_gas": 28201, "l1_data_gas": 256}}, "actual_fee": "0x1eb72f301bcd250a"}], "starknet_version": "0.13.2"} +{ + "block_hash": "0x3dbd0429c01b03d63e34ecc0ab4be6aca8273b31b3158620d05934505d18f4b", + "parent_block_hash": "0x402b35df0b7fb31bb310325bf85dd6bc12b588055022d3a9d4ac3fbf8b42b41", + "block_number": 36668, + "state_root": "0x484fc02b288a87fdcdb3f02fe4eda8dda4c555337d6a61979c07704a3f6164b", + "transaction_commitment": "0x35f006aa7326d9e864c2db098659e7d35a07a7c1b3db1de55207d3d11f1c735", + "event_commitment": "0x3092f43797271ca31c806e0697ec177d5da5f99ab5098b09b5037c753385662", + "receipt_commitment": "0x88edeaeb2de4fbb2ba1c04517f9c6b50becfa818daec1b71fcb99f9183f096", + "state_diff_commitment": "0xa256c205a4e07f054c438de3bfa7bb5961b43019dbf9533a9582a320920dec", + "state_diff_length": 66, + "status": "ACCEPTED_ON_L2", + "l1_da_mode": "BLOB", + "l1_gas_price": { + "price_in_wei": "0x361f0fd75", + "price_in_fri": "0x47612b5790fa" + }, + "l1_data_gas_price": { + "price_in_wei": "0x186a0", + "price_in_fri": "0x8a7b81" + }, + "transactions": [ + { + "transaction_hash": "0x195e0414c0c8dea28fde9944a71bd97abea493826d302e2030d9c0249985237", + "version": "0x3", + "signature": [ + "0x3ce127060dc268a191c07780afa0807ae246a0b14cc6fa16edbe32cbe87bb34", + "0x7b80f068920dd9b95feecf5d5932c94dc1c89216fc581fb26624b475c80a138" + ], + "nonce": "0x2ae1", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x6", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", + "0x2", + "0x6d6a4e9fe18b132978fdd5e46bc2e5de", + "0x7521e0f1bf2330ab3788f08afaf8e7c2", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0x60c3d56dd59b7edd528ef2e9eeb2961e8a2d6807d922de1e0067e82f6bdfca1", + "0x4a28aa6a713c7dd557e71ac860d5406df0a791a49b8ac9e81d1e775a445d888", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", + "0x6", + "0x54ac7e24b2048fc11c6acd60e4ed10c43867d240968fcb8feee8456ce1834a", + "0x3", + "0x1effc638ac1dab44be3251b9481fa6ae5e793a5d863f930254153a071238556", + "0x60842344c544cebb67f822fce41f409047aad7e83499960b970dba7874a7992", + "0x513f6b8d4f96f5e5c02df23e7b78a775188d2754cfa27aab1aae350be8ec776", + "0x408b63c6262dc25ff65e7cb99a58fa49ae28d666fc9a478ac455266e17327ba", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", + "0x0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0xf818e4530ec36b83dfe702489b4df537308c3b798b0cc120e32c2056d68b7d", + "0x0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", + "0x1", + "0x37f2bff5f371f9d1654185f60489c943c3887b1436f474ffff8b2d7c82c42b9" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x4000d1e50af1fff8150bb5fd8558a5146952171804ba967358a5fe0e6b0e354", + "version": "0x1", + "max_fee": "0x354a6ba7a18000", + "signature": [ + "0x723e94abacdd257f4e1ad09babc2d3b63f4e6df2a835f5dd7c7cf17a7d73358", + "0x4b49195c54998a7858cf8b3843f1e1761103de90cd4ec141cd02be90c1bd9a9" + ], + "nonce": "0x2ae2", + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x5", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0xfddf1b880b5e97ebd26e578922b072ff", + "0x32f4a2bac28b127febd90114a9648429", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x1", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x1", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0xf818e4530ec36b83dfe702489b4df537308c3b798b0cc120e32c2056d68b7d", + "0x0" + ], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x1d5adbb883c7a0bca0f77ae2dfdce4ad0e1a74098c19042c8e4e62fa85fffdb", + "version": "0x3", + "signature": [ + "0x3bcaf664e502ba8489d1ad3bd3eee56045e7a26f361106c852990e9297554d3", + "0x3ede44d898ea01d0664efb95689687aaced6031c5535cfa610968aeff59712f" + ], + "nonce": "0x2ae3", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x6", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", + "0x6", + "0x2efe3ae7f7d837b89fdecbf7b7945ce3b25aaf05af34e1efb05e0547f1ee386", + "0x3", + "0x1f079c6646bc296715cd4dd16aa925ce5b0d3b4451f8a9bbc4cbc640f597028", + "0x33010c7c261820fde09299468cdf37a9eb00a24996974d064e99dfa773be529", + "0x1e03394ec22f3057f33e71f64aea7bee380e434c102e428e7b371453cba01a6", + "0x72d8c487fd248ed4566cb000092832ffc6ac4ed03ac754279590f8f6de869dd", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x241f3ff573208515225eb136d2132bb89bd593e4c844225ead202a1657cfe64", + "0x0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0x20450dc34392f80c21d9a73bfdc53dae968838c5621e9bed6860000a0bce67c", + "0x619629bfe0e29c1d2377a2bf1fe7708ec5b9f33584eb86d5b76c584226d8731", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x169f135eddda5ab51886052d777a57f2ea9c162d713691b5e04a6d4ed71d47f", + "0x4", + "0x19de7881922dbc95846b1bb9464dba34046c46470cfb5e18b4cb2892fd4111f", + "0x4afe15fffeb973192d6336002beb80b85d9fc06df693eb8c756c9832767010d", + "0x0", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", + "0x6", + "0x503e8a1838da4c1f6cc8f5034720744ea17fb42cea8fff5325cac8af867a31e", + "0x3", + "0x5a42ab0819e4fb5af67cfbc5c7cee60add07d61dba6c4872f9bdfa8b8db7e0f", + "0x2935ea46f5da5df3e0ac6c41882cfdbae828fbcc3dff634a94c2db075d94765", + "0x2aa78c08c048e674553c8db20bb4dddd80a8c3dbfd25b9168adb5b8e6627eb4", + "0x1676fbcd5e5f371999d54004766635c1b309e9ad6a5be0ae407a24abe3e5375" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x2a2e7175a982ddb0d1636d453692a6de9c8542b40f2230d684070aff102b31a", + "version": "0x3", + "signature": [ + "0x67c21bbcd137ee91f25893f16db3ea76626336037932bca932e1a328f19ca38", + "0x38ba552743adc38f28db91d88f7c6ae9aeed91734847291c099467ddcb034cc" + ], + "nonce": "0x2ae4", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x5", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x241f3ff573208515225eb136d2132bb89bd593e4c844225ead202a1657cfe64", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", + "0x6", + "0x3e24d7e4732ddf3f933bf601ee207f42004159f8a1474ab3448ecf6cca36cff", + "0x3", + "0x7749874b2259b32547758256b902d9b46ed2b1e066867b967ed02ba3a8fd267", + "0x5bce1cd81751fa197b1583eae513f3948cf3299ad3428f76724e2af9558a7d4", + "0x4f8cf745cf31a95ff415b79eb94eba142a798d1aa812fc49e108b8ee5efd260", + "0x30c386c19149d593600c25b8e4f4bb25ff5e3937956a4b4d0da79fbae2ed08d", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x451a26cbcd55d2281c1b2c24445a5469d2fc16da4159c44d3b04a76579b5443", + "version": "0x3", + "signature": [ + "0x45971c6d3d85f2ad23e080793967349eecc0cb67590827566b279429b08fdb5", + "0x3c590f1c44d8c2eb0fec385a7e0551ca63f1222bf6962cbba4075d2a12e9274" + ], + "nonce": "0x2ae5", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x6", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0x6baf7f785f554a74201a8204d20dd168", + "0xed9747f7b83300810b7d8bf14c10e5ea", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", + "0x6", + "0x5be0ead6150d49c16a6277e7290e2d949a9e99b6c4aa0a3c3abf06ced66ad19", + "0x3", + "0x29224b3670651d8012b718c5054731e012817da20d50f7b54c6f8092ac130cd", + "0x3b644a3062bc3a55da8cc0d5bb9420d3b37124840c18423e7886c020bd85460", + "0x372a463e2aca39366b207734cec5b4612ed71582f97904e31a65b16dca90b69", + "0x7036f905a2b4f976fbd4f498fca008e00f650ce23677816a2778b5ce9925d2", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", + "0x0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", + "0x2", + "0x34d66d97d435936ee2e15d9cff5081ce", + "0x6efe9c17c3a7961c24596137590cc149", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x67ffd6807ec99456360431e3411ff24d94bbb7db058c5a427540720d3f23bc7", + "version": "0x3", + "signature": [ + "0x1e9fdb4ef232dbcd3a625e39057687920cd338c5783d0ffbfd053264b5c8879", + "0x162e5fe6f3635e97923dc90251d33eb87b11abb9dc872ea6c82ac45feaae46a" + ], + "nonce": "0x2ae6", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x6", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0x3e8f97e2afc891afba924ca1de776225073f9acbedf3ff46d318ec902ad3653", + "0x6a27839e256ca61fa43d6f348a640a7e6b21e873cf4d171070f61d61814c8db", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", + "0x5", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0x27b86393c20b270fd6b92a6d10a14366", + "0xc43e998da0e2e75b82c3c8bbbb7900d", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", + "0x2", + "0xc688868dc6e9c05aa925264946b620d5", + "0x905f08f13a2d956348a95748f77a9949", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", + "0x2", + "0xe7a49ef55592fa6ecceff818acf7252e", + "0x8f6698d47e25af7d0dc4212af51c223f", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x1", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x651b1acfa1652c7eb678979a8cd26df183dd3fe3e16ad26bf1b5c150547893", + "version": "0x3", + "signature": [ + "0x2a04435512c22dfb31d26d2d80bb1981c379380b6c5ba2d1523ccdd4adef625", + "0x552b2cb8b91b3265f190e92823d0a5ee6f281c559e8fdea2840af5c8e426acc" + ], + "nonce": "0x2ae7", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x6", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", + "0x5", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0x6d6e91265cf1e0bf15ff9b695e5089032c4ab616ba25c0b507d9e9f39c9ddfc", + "0x5d344e352238cd5a1082aaa37b01fc392f55fa7768d779fa6cdc78ac3d50af", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", + "0x3", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", + "0x5", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", + "0x2", + "0xce2305e2a02a8fe3691c0b73a12e274e", + "0x80dd5826db992b2e92710ed0bf4a9cff", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", + "0x2", + "0x6acbed37acf15328d3afde3f2db41c4", + "0x6f119050d266f2d77ac62d0845d9fa8e" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x30b2d48fd3c80877d7c05dcdd9535ba500570f22c5c8ff2354707d78b89b511", + "version": "0x3", + "signature": [ + "0x4f64846a64b6bdc564ce3449a3d485b00640e3f59ac67af508527251512e666", + "0x1d2b3c6255d8e6289009955d4add0de7dc141df953b74deffa495f9dffa5ed2" + ], + "nonce": "0x2ae8", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x6", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", + "0x6", + "0x4619138d933b114b7942c93762827303aab9ff0a8b876765802ef7cb60ba658", + "0x3", + "0x32d345a97bc0db35ae9578aff71192bd142595afe1720056892f00c245fddf1", + "0x3748f3eefc81fd923a83f9ab2d9ea2ee41378fde4de92257a067538138faba3", + "0x1265c400681e1fdea145d3857b045a792a882334bf858335716c2934e189838", + "0x52641747cc939c3254a8a4a226e2ab74309396b6261eb434b2e949bcab370c5", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0x9ce0c16cf9083b40dc0e72e500e99118", + "0x868470928c1b10fbf5f6b398727c4a3a", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", + "0x1", + "0x2e6095aa6b4dfbc9127bad9819638d2ac31e6a7b7e51856915e22de5215e9c9", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", + "0x1", + "0x166ecda541ff4b6f1d56c431b0c9bc893740234b3d4396cf19239e871bea3d", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x24c7fb9c2336b7a3db94970c71d095b464ff25f47e4c62f505d8bd3c86a784c", + "version": "0x1", + "max_fee": "0x354a6ba7a18000", + "signature": [ + "0x51635ba56525926d25a2532c894421ec0de7487381b7967cf05500f067e001f", + "0x1d9e04a4b6e4d17197f3a60b3d3ae28e85e88ebdd4b23ec80405e8e6354863d" + ], + "nonce": "0x2ae9", + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x6", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x169f135eddda5ab51886052d777a57f2ea9c162d713691b5e04a6d4ed71d47f", + "0x4", + "0x19de7881922dbc95846b1bb9464dba34046c46470cfb5e18b4cb2892fd4111f", + "0x56a0a743d6adcf58d137f4aedba1c47c64e3b729cc8914a0568cb571ddcf82e", + "0x0", + "0x0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0x52608f33b0e282806213607d6fd1a5ee", + "0x4cd43497a5400a9903c56faff64541ee", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", + "0x2", + "0x2b29a48b0e4c7e1154a2ff489bcf221d", + "0xb8ad79046e47ab1412efe081278b0c68", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0x5029136950e9315e229a799b0c283edf", + "0x8a5fd093d52d0defbb05aa6509d2bb97", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0xf818e4530ec36b83dfe702489b4df537308c3b798b0cc120e32c2056d68b7d", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x1", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea" + ], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x2f32394596d4bd1ddc5c7599ae53db8309893e1dbeadebaebb282763abcad27", + "version": "0x3", + "signature": [ + "0x381f039e10c089c82555de82f911606817fe804d87bc53b6f160a46ecd5423b", + "0x35e84047d52a712493decba735e96ef0f9edeb74e37989f2c2dcb5c35ce3316" + ], + "nonce": "0x2aea", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x6", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", + "0x2", + "0xc92c84ed60f70168ab73aff5fc334b3a", + "0x2b83d1f0eca0d6237c171b0c105a7772", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", + "0x1", + "0x1b323a52436a873a171d8693d9819beb2fbb1b8120c76caa24f2917ca3dc734", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", + "0x2", + "0xa7c33b02d680105d8d090fb246d30398", + "0xb6cf7678b04299e84d2a9bb17d067ed0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0x6d95d7cddf881e0220e73cb72347595d7580a199f9ad01f3d05e82a94ac6274", + "0x28b5958d742e5315361cf5a9a18b8c77af43b061b625e843e5eb30815fbbd25", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", + "0x3", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0xf818e4530ec36b83dfe702489b4df537308c3b798b0cc120e32c2056d68b7d", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0xa62ee89e1402d61683d961a18e5820f42d061c9615022ada8b13c24202c688", + "version": "0x3", + "signature": [ + "0x310eae957c6b7294e1fefb4bfb5c2375ee0c22913db830f786e14ec78eb4d4e", + "0x71a3fc6f5d9a56e3dcf019ac9dbf112de458f447b0ecb0eddca5c5406f83fbd" + ], + "nonce": "0x2aeb", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x6", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", + "0x0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x169f135eddda5ab51886052d777a57f2ea9c162d713691b5e04a6d4ed71d47f", + "0x4", + "0x19de7881922dbc95846b1bb9464dba34046c46470cfb5e18b4cb2892fd4111f", + "0x6840b41c5acfa5b869fec37a14feda64b608968a1a082280d032ae772f0c1c9", + "0x0", + "0x0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", + "0x2", + "0x501be05622164d8f800fdb528bb8cc75", + "0x126b3f82374b4e79ba1d340c8c8aa87b", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", + "0x2", + "0xf6bfbb0555b4084817d3ada8e81ad00d", + "0x488f7cef15e7bb68a9e048ad3bbee2a6", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0x8ff690eee1967fc06db0ac7ef87a9725", + "0xa39901da587330beb6e9f76cc316fcaf", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", + "0x2", + "0xab2e5c9e3c11a99ef23d8af80ef7af8", + "0x62df1f09c714c713df4df8b62303a96d" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x5cc90d16fc214b41f79fb7e6eaa9d54c86c480bd575a2af7f4ad9dedba6276f", + "version": "0x1", + "max_fee": "0x354a6ba7a18000", + "signature": [ + "0x4b193fb9b0c0c98bfaee15dd9d35e1f7445f5a261c31e508eab4813bd8e2bef", + "0x3c6408f4aa551e2602514ccd6f061bdbb6a246ac3476f88f2216ae0f3dc97b9" + ], + "nonce": "0x2aec", + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x5", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", + "0x2", + "0xac54f96fda8febb5f2f488afbfb6e79f", + "0x1fde96168ea03365684f689e17d8231e", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", + "0x0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0x415e95e3d4f2e68c530312ba9b31eba8", + "0xd5789d771e36e8fe580461a44fd81d06", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0xae8d72177359e389bb35e3733d07b30c", + "0x473dd8b3e9d9b101fa139d530e9b5ad6", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", + "0x2", + "0xc912174ca7fa00fb922e27436c7da7b7", + "0x23f0f3ccea34390f6322981607b59f97" + ], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x6753e208f73a868d74312420692d12e69751e40bcf89c021119c24490ece9ad", + "version": "0x3", + "signature": [ + "0x4f5e4da4016066a6f2e92eabd256223585ffa0bef7dc60008ab7231c39ebbea", + "0x455663ed4be94e9acb5281094443b253b44f0d2f24a1d613588370b38d8efec" + ], + "nonce": "0x2aed", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x5", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0x73eaa8be337ffc377c02d3d4f45fff4e", + "0x9e9021a653b662249f9d3672ffcb5525", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0xf73a434a015c2e85f5966f09428172ec", + "0x508e12c93cf4f77d3db64f258f09b393", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x41bdd5c64656ccc96115120b5b05215cc995f78b1587dca49feaf4aedca2631", + "version": "0x1", + "max_fee": "0x354a6ba7a18000", + "signature": [ + "0x40385e00234310f566a829c8b1e8c0df708ebb234522c6be9c34798f4a7580b", + "0x4722fe54f3cb65731b3b760d80a9788b9ed7ad9935507078f050a766b292e0a" + ], + "nonce": "0x2aee", + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x6", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", + "0x1", + "0x63c5c04c7765495986cd53d1a04b3ad24c3419fc68b428263dd23cadea8f778", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x1", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0x668d6f7a82728a2d1571be2e7ab11e85653fad96d466954b7131b96f1ecda9b", + "0x5bf3fc21b55cad5f4d84baecfc717ed9c66662e3f83bbe56b9f7f4ddd6b79d8", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", + "0x2", + "0xcb63e5b172188aa95829a042660f8984", + "0x5b506421a5704846cbe614269e31f30a" + ], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x3d0d388f2810a550b11dc9f1ed6b747b3bcdbc5ba1f6c4e19a37e5360dea0f8", + "version": "0x3", + "signature": [ + "0x6f35d1dd41e804faf22711037fac4ce136f2a5543b667a6c33d716c8abc13ed", + "0x2558a7b2f58c529c91786c4284b29a420134191378d6ecc44a34d446312a7ac" + ], + "nonce": "0x2aef", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x6", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0x9d5c49cb5e2993b6bf31973fec801a9d", + "0xae4ef1fad32095da2291acc7847e0a66", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x1", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", + "0x2", + "0x9df97bdaf3a64e6b480166eb9b8452a7", + "0xd092d021fe62f52bb659963572b0fcea", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0x327eb1227f9e88e4021578d4f0c38150", + "0x381066d9cd0f5516f13dcdddb93258c8", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", + "0x6", + "0x4b69423be6879cf6d118721dfecfab9d1afbab93c5706e6930c4bf3be81d791", + "0x3", + "0x49c8205ced269d1ced335d5c501e63ab4e44d98a0650fa927d280d3f7c36230", + "0x54948a4b82b56b98f1cb2043401028a428c78f3f6df737d3d3a2678e733dc3d", + "0x2293a32380507e57f9ef6bf716af36086f17cdfae9a369a52b2a17b1c2678d1", + "0x1a94d4bbd06b900e82e700a7e4e735ebc1480d1d1ec6cbe7f7c74256481bdc" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x71789cc9d5ea16b746d857265754d21fc0686d327f46d06ddee21fdd3ca88bb", + "version": "0x1", + "max_fee": "0x354a6ba7a18000", + "signature": [ + "0x43d675602666b58f44cc438542c62bdf15ae5637f85aa63e0c44b9f528c7f3", + "0x25454989bc19d55d8119af8fb48781e941329f373e3886dacfb0e13de8e0a4f" + ], + "nonce": "0x2af0", + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x6", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x3604cea1cdb094a73a31144f14a3e5861613c008e1e879939ebc4827d10cd50", + "0x9", + "0x19de7881922dbc95846b1bb9464dba34046c46470cfb5e18b4cb2892fd4111f", + "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", + "0x6", + "0x212ff21302b29f74fcf5847ca85efb7ce2cc579fe69aa3ce1b234737faf2d66", + "0x3", + "0x6f01640f0164f58cc7dbcf8a97ed7a3eca7bf9014809d47aad40bff3390234a", + "0x246c45ebaed09c37ab7268e28f8d60cc8d5dffa102ba3823b1fcf285b6b4588", + "0x356d4583e6d8a026858ae2c2f7ee62a857f8373d8b8fd384220a17242af6b1a", + "0x6e4ccc58a74edba65036bf4f23f2be53536fcc02c2504ca55ff794603e7c230", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x1", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0xf818e4530ec36b83dfe702489b4df537308c3b798b0cc120e32c2056d68b7d", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", + "0x5", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0x77585bd4bdf342d582c703ae5df0eef431ee39991ad5806dd070deab8db9b0f", + "0x2e6a13f0f4d2bdfacce8e048646d90672cf7b735e753b2f2b2ff2e773da72eb", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x1", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea" + ], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x397df33c7aca7521db3df0052454e9d673e2f9e855c922c3e1d4cd4d12fb2bc", + "version": "0x3", + "signature": [ + "0x468bc551a3d75f078c0fd0c353f11d2807bc6cab4825185781ac116c70bebe7", + "0x201e10716b45bc23596d5c99b1bf9d0a5138803927d95eb490d77f4c269eea2" + ], + "nonce": "0x2af1", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x6", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x1", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", + "0x9", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", + "0x6", + "0x3debf9d54b0e563b8fe4b64eedf699a24bd4bcf8b9071aa27e99f25c88ba961", + "0x3", + "0x87ed1ff492fe3875dd94b50e2a32f370fe02cf0e60b453b69d5fcf393d9c01", + "0x11ba08688015c45ad4415d1659dea6159a8df2935983bdc41b9b5613c55f886", + "0x7000994f2467389db1e940804a166053d3929fca4f14d04ed51330ee6a1f4ce", + "0x534d92f74b4af9013304ee2d5610bb741d798333efc8353645846ed1ce55923", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0x4eaa912c17dfc566e8f7cf853948824217556ba27c1726a43526cb3678e93b2", + "0x68a2b20ce8c751bd668ceaedb9210a08e44d1e4b393568e129aa6f3b8bc2385", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x1", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0xaa3cc28d51dea8ea6658d7147ba81450", + "0xa4f9ce0aec45febcae1d8e11713cb2b7" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x75e605c318963ca63a9355587cf82865227115327199a96e762c6dd7f032eed", + "version": "0x3", + "signature": [ + "0x699ce5f688a2826b036991d3f7b14fac21781092091c1fbf044c16b694bb557", + "0x64cbbc0bc0e92c6bcfaee80cec70d1d38f192a3a6993007c108ec52cf9d554e" + ], + "nonce": "0x2af2", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x5", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0x8f8e304b4b88e7158cfa3ea5ce96243e", + "0xc8f3fe8a67a2ce24a461d082b85bfa5e", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0x57bfdb31e2e369367448c9fb541930df20d632f53cdb89a254ff381f41a08ca", + "0xeadaa29a2017bc360aed6b8df5198cc25dec6bf9c2e97b998ae552213a2450", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0xfc4416e02ca173660c83cdf571b2e963", + "0x2971b0d7d000709955b00de23fd8fd26", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", + "0x6", + "0x5a84ba14f489e71466dbd10fbd54cb05450a0e2f38e2d99e3e587bc7cb63890", + "0x3", + "0x12dfd2e3413b429f95268d0d163b0fbef734358314ac2e77f6255c291c146dc", + "0x144934c01839b32d64d21da2c53bcba79bf55c170700b07090d86eaa1a3650e", + "0x7f1c2e64a60109d6681038d3994fea871d6507effc607342e7fef0c2d8e821d", + "0x2d4c5d4309a24f6af9b956e69789d0622e01abb3fc1754d4acaee139e1f8b73", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0xcc4c697513d102c2829098490331edd9e9e49255be3fca7f857477342585fb", + "0x7d88d09ca676c668444c3b4277c9845fb4bd30b64b580f52e5cf3a34d91e818" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x3b2c54a4a0fb53dcb1d139fd66b0d33ef292599d5779d6fbc9869a3443b16d7", + "version": "0x1", + "max_fee": "0x354a6ba7a18000", + "signature": [ + "0x5001a97a86439561183c474e136e55ddafe916fd9129b08cbf2a4414782091", + "0x1467a4c87a87f09e124ebf25b1e149739f0def1fd664661d4d238e3452f1d1f" + ], + "nonce": "0x2af3", + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x6", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", + "0x3", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x1", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x1", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", + "0x5", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0x50fc87d9d3fede421ef5db0de74e0edca47c9a725c0a8a80477e11e6f7be4e4", + "0x5d80e71e49199f68b1a97b6c87087a47fe06af9ac42b7b025f97c71834e2b3f", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", + "0x6", + "0x36a003b9f26f41a345836abb901c1a71fcaa586d174dea5fc1dce6b1cc5a145", + "0x3", + "0x344abe714959a0289fff2c0d988cda83ba46965603e7839225726fc9c34f4cb", + "0x3e4c1cb040c585a1b599031d44895054534683e9f03c41f14ef4ae3eeedf9ec", + "0x8d434813d65c2e95a9840421588b6888383f09a6dcfce99b1f2057c3625024", + "0x7638012489a5d8385977e90846462277be161f078c1fc2cef28df749f2c30a3", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", + "0x6", + "0x41c145fd2ed46fc644e408743a12081e8809cd16a5f0de242f33da1aadd3436", + "0x3", + "0x30edb7c0d02cb69d2dc750909c6290fa6b562bace746368bbf994338fd84724", + "0x43d7fee256e3c65ec0b3e30f0237933c357a0731b74303939fac965e568cb78", + "0x3091b52f28583e2a23ca109b9c372e9eb0d5d976c8f17c9ebfd42f0dccdb669", + "0x3d2b99dced2ebfc231a4490bdac9fca9687aa7a69ab122b18e11cf480991ba4" + ], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x7765195b77c0eea821a8f807f8fa022d2484d3bc848d519ea689d97c4015bff", + "version": "0x3", + "signature": [ + "0x232a9eb615f255179df3833b40ea315a6f1a65dfde8bd01108240bd4a3ba86e", + "0x75578d63a7944c5a424893fa137b06e311d67773b30d339880ff19e24b88c61" + ], + "nonce": "0x2af4", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x6", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", + "0x1", + "0x39c8e54cc0cd11e61804bd114b283a57a9f73ceafc2b796415383a17c50dcd9", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", + "0x6", + "0x6ec2cddbfdacf4cbd0108e87bb889213d139ff2e9eadf68c81157a3f0c7e769", + "0x3", + "0x7057660cdbeb602d9094eb34650d362c0b0d89057bc9f49163501da7c552e1f", + "0x798891c19b8abaf6ee00f6a989eeea8cdfa76f3a4ad390fba68ecf9353fd687", + "0x5deebf68d35fe0b2fc0f89b6c96e6e8ad88883993f9ab8ad56570f8f02d6d2a", + "0x1b600bfa5682950284690b28749b0501610d87e7ae6e88fc2decd7c21765352", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", + "0x2", + "0x4b1646a5e3e3d1f9aac80c90c6bcd71d", + "0xe41f8f46e121db5ef5497574d6310737", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", + "0x3", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", + "0x0" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x2d667c69935407d1482d8b0182ec02e5ec2cf71bbf6619f739dc8a0ae1e8b92", + "version": "0x3", + "signature": [ + "0x48e4f4b79b9f41f0c36c734fbe6699f3dfe1a528cb052ba8df135c25d2d18be", + "0x33fce2fc02d766232b168b81b433e238205fa0eccf6d2c3afd9a0f967c371d3" + ], + "nonce": "0x2af5", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x5", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", + "0x3", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0x133f4a7fd773d4f33738fc0597e3fafd1f043a69fcac6bc7cd2d829b8f1b960", + "0x1d363fcd342dd5bb809ec8a8493f53fceb418e62912f1afecf5b0e38b520ae8", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x17da35ce4ed77e22e3b9149fd965dba57351a6c29f588a7d245e208d073e4c1", + "0x0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", + "0x2", + "0x3134280efb90933614eae4713107dc7d", + "0x8992e86e759f95a8d1bbb86365166269", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x4c93adbd1aa8f107be890556eba8a4071515d5510b6a93fd35ecda87fc6df80", + "version": "0x3", + "signature": [ + "0x4df3a153adf467cfcf61e57cd48d824161dd25bfbb99cd99902e07c687e9fdc", + "0x701ed8f54d1b1bfaee8e267b10f001a7f8cf4b1d12b1f24cb7a1409bef3702" + ], + "nonce": "0x2af6", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x5", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", + "0x9", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", + "0x6", + "0x720213ac76a0f3f2565f04f51c8d13f00878dadb125a59c9a3d3c846e0ee72d", + "0x3", + "0x65dcd1a3b2933e6f20f019a97de3272d0549bf793e41a0144a7d21bbdb2fcf0", + "0x8f260cdd6d8d7a9668d1bfa93136d12c15246e80975b8571e7d09c76207fbb", + "0x430cf4d69439b8d69afb49f3c44286d78ce666e924c3b99e3aecae688a30bc3", + "0x600ec4076b035b493816d5d1ce1b46c5024f893844db88e9f02b3eb57423e3a", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0xf818e4530ec36b83dfe702489b4df537308c3b798b0cc120e32c2056d68b7d", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", + "0x6", + "0x11ebde260ce04bcbafc74879bd67c1aa39a50a2d3af027f407147e18a5ee20f", + "0x3", + "0x158db84882f02aab220d39d821e92dafb4db61c3fa65acc8b80c6b11f4afd30", + "0xd192afb935fdaf0a61c2ba39be015356ba32a25c839fdb6be44e771b43f1e", + "0x4336b1b67cd7bd5ac601308c72b02e27659a932373facd00ca73dcc7d45e880", + "0x2a5b364fbf2ba9d5c3e8e4fd65507dbf9ab3694f0196ec593d9704d77eb9dfc", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", + "0x2", + "0x3cb3d73d7ce98bd3baad49800844e6a2", + "0x6e4c545735e6f49896af4cd236352ce", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", + "0x6", + "0x82e6948d4df169db1d3d53f528a78224467d356457dc61b1c19145fb7a60d2", + "0x3", + "0x1ae7558984ac06156913dc6992b2a5c1122598f49e6965c5f8a71210c6721ae", + "0x46707418ecb32d37b3c817a9c92884dcf4ded2bf98c756c255d7b8da05fd961", + "0x55316930897583852f858e6a8311efdfac9b026bcac1312a52dfe524ce4c3b5", + "0x12b36b9a3081929c3518d078151ff6f505fd6a4a37efae48d6939576c6cf3df" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x68a4d9bcff51d99fd3f5dc6df6e4902073cdf8d43575e3922f904d800517e8d", + "version": "0x3", + "signature": [ + "0x1f74b6c109b09be172c7e0326be84b44838e762651d7500c9a12b7678823f98", + "0x351cce04cfcaf5744920b91de9509e0813084247a5a816a2ada7de40d82e690" + ], + "nonce": "0x2af7", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x6", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0x4a8543716dde9fd5051e1899a30be66442b8f2aad98dc7fab46702aef973208", + "0x362e2ab6cf7eb90f5dd702f006a8e480b8a04e827efcdc8330c8be3bd80d5f9", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0xd82c8c5b0c6c6ddd426ec86c8aaec4e7", + "0x7062d60d085f7d0b3246dfb9babb0b57", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x17da35ce4ed77e22e3b9149fd965dba57351a6c29f588a7d245e208d073e4c1", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x169f135eddda5ab51886052d777a57f2ea9c162d713691b5e04a6d4ed71d47f", + "0x4", + "0x19de7881922dbc95846b1bb9464dba34046c46470cfb5e18b4cb2892fd4111f", + "0x6f666bc1231e8fd5fc2076699d6efbe354188833175dc0f5def712b74dba207", + "0x0", + "0x0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", + "0x5", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0x4d6dfeeb0f84e439b9dfa1bb4ff5eeaa5d7fe1fe17214bf2b7efe0b42916fa0", + "0x4a539db0e55ebd6d9d7835451d2a0c80d7d07289fc5f8d4fbeae0a8845019df" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0xe0f970f4ce407adef51a760559ee6ee74a4769758768b808097b520216230b", + "version": "0x3", + "signature": [ + "0x1229a7d742142e70b11145e106082b507dc302ff49a48883d1865a001548af4", + "0x1d83ea6bb1e4ad7618b0903c1984c3a15718cee02c7e8dc431f5de9c71d5ebf" + ], + "nonce": "0x2af8", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x5", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", + "0x2", + "0x43c60fc938e19d99ccff0bbfa18b4261", + "0x237fc09f3c158be2d2bc99a6d9ebbc4d", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0x35b4e984575e9dec65833fd5485aa1d", + "0xafd2863cd029b8777771cd7e105a91f9", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", + "0x6", + "0x66e6852463ea25790fb91b17d81f3d94c2d29690ce5283a19d54503c93c03d4", + "0x3", + "0x47a7420476d121e7481da71e59fe5eac3e6e058175191aac84315ced6f5d101", + "0x203c2d2e3335474d659e032766de8c06a746175afabcbf6b21e49a2bc8d9565", + "0x2490dd8f87566f3ba033a272c9eebfc0f3feae6bf5149b71b4d14c4dc26dfd2", + "0x2be568ae8f7d9133491e5a8b04f7044b5fe032f8bad3d1925d238133865c8db", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x3d95cdb95afd14cbdb4c4669525e879dcb683baf81484a3e1f8d907153e53ed", + "version": "0x3", + "signature": [ + "0x6cf60d9124edf2ce57dee16d0634392b78a6c2b6c286295b6b2b53aaf3df2df", + "0x1cc0b0eb3bf5580301e65bac42a843a8dd47ff58f0f2483b298b4f950f4e904" + ], + "nonce": "0x2af9", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x6", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x1", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", + "0x1", + "0x39e7dfaafad6ac2cee097515c0a06063543d2145177a8e6bc480d051cbe5e06", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0x734230d8463ccfa78e011ac24bbcf3c1078ab86739b7812a7fbd56887e2a3c7", + "0x7ced184701e413325e711e93f726a8506b37f8dd47c45ddaca5add22a4516ea", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", + "0x1", + "0x1776ef94f6fb07e1fc41e8eb36fe7e5534daaea0abe9a3bd483fee3ec769557", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0x441dfc5dcb717276b126f4937a6d082b", + "0xfc338ca78ce4cf6dbd3fa4c357d6eaa3" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x4f0afadd2870468cf005f56bebded204bae8515a4e70a0a2ef4a55367cfc205", + "version": "0x3", + "signature": [ + "0x177e583304955e9013e676b24d14fd1926e7f3978b9d72bc4b3224e4a3f1b07", + "0x2f55d29a9db1885aa934cae7e0fa35879336931cf66c9475984da937dd19d0a" + ], + "nonce": "0x2afa", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x5", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x3604cea1cdb094a73a31144f14a3e5861613c008e1e879939ebc4827d10cd50", + "0x4", + "0x19de7881922dbc95846b1bb9464dba34046c46470cfb5e18b4cb2892fd4111f", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x1", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", + "0x1", + "0x1cb7cfae5bb1e05c4ab2df9131740ae6aca46ba7ff8935a2118b7227970929d", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0x23d9068f531552f6c74bf446c8dc6f883a77dc3e925a9958eb74d986e061982", + "0x54d2f37f02cf7d87896ba3152123a7805d73ad47310993b815599c260059b3a", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x169f135eddda5ab51886052d777a57f2ea9c162d713691b5e04a6d4ed71d47f", + "0x4", + "0x19de7881922dbc95846b1bb9464dba34046c46470cfb5e18b4cb2892fd4111f", + "0x4ab8a35cb117e071c569da65787c81a04f51bdf039b2dc7ac571da6df3a6e04", + "0x0", + "0x0" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x727effea1ae4e021bfa5435651f2ec0ddfc8d6c471f0e1948d89f00879ea099", + "version": "0x1", + "max_fee": "0x354a6ba7a18000", + "signature": [ + "0x430ea24ed76eea6c6949d1cd2b3cfe2f67ba2e46aca605f4dbb0f671af3a3f9", + "0x3c7ee925f025780a189e243dadd6a03c7d1277b627ed852576181c7cb43d41a" + ], + "nonce": "0x2afb", + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x6", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0x7f701511f499ec21792da5c5982c6401", + "0x4cb0a181cdbcce5fff35dca0d398c64a", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x2d7cf5d5a324a320f9f37804b1615a533fde487400b41af80f13f7ac5581325", + "0x4", + "0xa0adce6dbaff6bce9f7a620a9ed209aa748a0b24", + "0x2", + "0x9b971fe02819281443860767515bcfbd4a87795e973ae4c5f0da3f38b3fc78", + "0x138d2ff63ebe4cff9b97f36d9842f5784d1c14c77d552a9f202f700df99eb80", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0x18af48e8845ea1c7c34a314b3c3b2375", + "0x2292a149b646abdb89c35b3429bb483", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x169f135eddda5ab51886052d777a57f2ea9c162d713691b5e04a6d4ed71d47f", + "0x4", + "0x19de7881922dbc95846b1bb9464dba34046c46470cfb5e18b4cb2892fd4111f", + "0x57739cfa38624abb7526147eb5883b962e1b8e081823ef983800842a7cd2246", + "0x0", + "0x0" + ], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x5a6591fddd64df4f57b64543c00a1bc788485b2f558056ea853548d3d1e9637", + "version": "0x3", + "signature": [ + "0x37fc84d260663393d65ac62ec776ed3126f6dc57cd1417ec192dc768ccd9c66", + "0x674dc62d137a8d61fc2caed4172f6f05b123d8b614242a1bc04a1f9a31d8543" + ], + "nonce": "0x2afc", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x5", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", + "0x5", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", + "0x2", + "0xa704d52ec1184a435b796982a2961b5b", + "0x68d91e3b8baf380a1a103b0ef8189f89", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x1", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", + "0x1", + "0x3fa28db865f00851e0e084410ec80157474473680a1cb8d12f9a980b40ed159", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0x925270ea40150f1017d9030a37c8d225", + "0x33a4e8e13c41ca50580aced266d0d10b", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", + "0x9", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", + "0x6", + "0x367d67d017a167d525cb8d18acd2b7aa354b96db81d60949ec7fb66c4f1f674", + "0x3", + "0x755c24b1b54061ed134fd9d6f0d910f166b1d134cafb9a1fbd62300b1eefa02", + "0x5daa8bcd0707512e3d7c6230d40198e0a7190009ae097f9b2e2963441560f3f", + "0x3acc6203b842ebd20e31109d66d8bc8ca2e55495bb4e3ceb90ab6b268fa8843", + "0x2d11b69ea163cc20b08ca557146861dabb4b2e3e0b8a3d7ca0f8dc57c200fcd" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x667247e8ae4537222be926e7d29001431251f70024836752c4cbe68a5377beb", + "version": "0x3", + "signature": [ + "0x18e2effa99f9bc7d8cb171abc5a1f8d6c564d4daec6b30cf59d4450b0ea9dbd", + "0x48021ac765e54bf0c21b8c2a6dbe0f7d9adfb9f19757496a8bf1152ecf2b7a" + ], + "nonce": "0x2afd", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x6", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x1", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x241f3ff573208515225eb136d2132bb89bd593e4c844225ead202a1657cfe64", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x1", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", + "0x2", + "0x4e111b1ad23e286630769990a3783720", + "0xf29b6b58b3fd9bb0500cfcbc1015c848", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0xa3ac12ff5c51f47e7f7328470d92e3d0", + "0x204447d717a322685318579c14836064", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", + "0x5", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0x1d964948cfff2c14888675fd7f76fab2b88c37aa22115b50b46afc024874f0a", + "0x32b67000b87808ef73ad7eb1e404e30eb4c76524ac01ad06279e1975729deff" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0xafdac29914cf6054190cf08c1a83acbbdc86a413690f40326b9aae545253e8", + "version": "0x3", + "signature": [ + "0x23ac3bec5495f55a5219469a269065790e35239b289345047d5b967cf6e1e89", + "0x23112efcee6522622cef06abea54b82759040a3293d6903d6b0a8afe93a6b80" + ], + "nonce": "0x2afe", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x5", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0xc7c917230cd008e1265ad1ee22ace88c5be770523389845ff00f49d7338118", + "0x3ee28cde6fd7a13b007d272ba6d9d2aa60c368b1953c49266abb5575a964c08", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", + "0x5", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0xd7dbcbd2f4a683b6a2d38ecdce699a83", + "0xc3fc17d04bdb882e05bb43671720765f", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", + "0x1", + "0x5308f3d9b6084569f82820b1eb085c72ac5a612971c9680b18c21ec735aaa4b", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0x539fdc41a334940ccc171054ad1ac3eaeb610e49e67672a016667b3be772832", + "0xd98f2531dec263f3c96154482bdfb72e5b31d503c993080d7bf2433c737d47", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", + "0x5", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", + "0x2", + "0xe2b78726249ffd02947b885c8187140e", + "0x1537d57a9b032a151c71c3bfb6051e84" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x14786356d92d3359426657aba526e8e6bc3c6913beb2a06fd5a1af3254c8ca6", + "version": "0x3", + "signature": [ + "0x134db6c6026797efbb39fef321dd78a38f6d06328bd995fcf204ba9c9de62f0", + "0x3ba78d2dbe1d0e2943f6f325389bb2f7044d5d99d7b45823f73173569afbb6c" + ], + "nonce": "0x2aff", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x5", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", + "0x2", + "0x429823daf44e2561c59cac59bbee902e", + "0x2587a5c079fdb6f5c33ea7a894f5f9a0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0x4f762c3d7a166bfbb9ffbb6c41ce6d095b419805282f953bcf9d9c5d9f5d7f4", + "0x7c569075876129c2c52f6d07d73a0fd573bc08fafae48daa8a029649ecb1599", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0xda7231f5fe13374aeffb6f4d62136fd", + "0x6e2842fba79a18e891fe49b0504aba46", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0xf818e4530ec36b83dfe702489b4df537308c3b798b0cc120e32c2056d68b7d", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", + "0x0" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x644839d53b3e8e9d4690a19ab35f0564b249c58443774ffaa8e4db4a8890ee7", + "version": "0x3", + "signature": [ + "0x56fe160ed17b4cb561e1bc8b4af560a5fad95a6210da52341715c9d81922e27", + "0x52d991fe388f88b776cdf7cb1683623bbc3a036ee3be20ef6d9c46bb0c5d973" + ], + "nonce": "0x2b00", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x6", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", + "0x6", + "0x48ba4a09e3cfc54a0fb13826f9d9066f019db290b3ac4ca202f9e284013e38c", + "0x3", + "0x582a7beb60027e27dabc1a9e9b4746528535aae1c47ea1a2224fcfed00ea52c", + "0x51eadf84f9e6df0d7079bb184cb44e34bb311edcc62d1e94d5b1ac2f1d6b8a3", + "0x2c08e60b9a4f7106c503b13b490fbff384b07726e0e156ac27563ff05114b20", + "0x664e2b539726f17b24f345f28acf490ed92cec85538bc366bb5c8edd2b82e69", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", + "0x6", + "0x47b42da4835595cf4cfd06826eb76ed95ea8dc2f777b0c4acd2e0809e6680fe", + "0x3", + "0x4333048345c017b97d18648e47c5fc51e8ab6127ed22f6eb1cc810c6163f6db", + "0x203aed1de52fb8f7f43524752d45bea702df6f2ace6e5dac195de918fce2133", + "0x316385dc04628c6b11a08b31006343bc98580278ced84ddf620e9738d69b055", + "0x43129d981b339482732bdc3ca8e420d203862569ddcc0d6d201418c05f4d9d", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", + "0x3", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0x8bf09672958b0e6aeec96a79277e97b4", + "0xb6f7ef9c28e2e6bdbaf690685b74630d", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", + "0x3", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", + "0x0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0x33f793f20ca2b13f3e00bc06024aea61b2b48d37eb5d88851d550c52a43802c", + "0x6a897e9229c37a46716b1077c7da5032dbaac03c525cef9440426399af639bc" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x7f32793534b160cdc40e4ce20a8709adfa9bdd0b5860013698fc754b4103542", + "version": "0x3", + "signature": [ + "0x5599359dae473f4cf42aa8a5a336f49001316447967c9dcf5d5db7832065e4b", + "0x14dda87b9cc41148b36150a85fa888301428eda36e203a39a5592a0a0a5ff54" + ], + "nonce": "0x2b01", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x5", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0x7a57003c2a8877940911d3447218298e", + "0xeb74fdacf6b44de6b0263947a674941a", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", + "0x1", + "0xda58559b7807dd5ec046d36a061c641b71c7ea84ec73884ce07008b52b6056", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", + "0x6", + "0xba435eb69d3226f365880885b2ce8596ba44ae0821dc9f8dc7907d14a282b", + "0x3", + "0x40a013b398bee56959eefd6c4edcc4675872dcf412ca5065a6f7c413b717732", + "0x371a8adc1170613db866c390fb96e780d1a5c36cfa7f970724ff5e1b0a5675a", + "0x287a7a8fba7421005c45b0f98e0d9605ae017e9bfb4b837c23bda6df6549787", + "0x6432918f928ded128bf19240e81e97c8f2719ee6d361208e5bb6b78c61a9e59", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x17da35ce4ed77e22e3b9149fd965dba57351a6c29f588a7d245e208d073e4c1", + "0x0" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x642146ccbb341535e2f4f7aa82ad34ab2d0dd6bcc5d98f6e9485638b67a6d", + "version": "0x1", + "max_fee": "0x354a6ba7a18000", + "signature": [ + "0x11364510890c78e524e9c6aae1c8f433515924a544206d2e25fbf855c2e1525", + "0x6c483c512935270915f601b8f6e6be8117e572b19a43576493f05508224f045" + ], + "nonce": "0x2b02", + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x6", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", + "0x9", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", + "0x6", + "0x51814831a2493c60497a96034f00d3e72c1ca7b071631c1cd873c0e7b46f42", + "0x3", + "0x79f3c4cf6a5ecf86c3b4ffedbde7b884f61b408085a07f7e3f8a1c73dcd6792", + "0x1f282d7be25fe585523745afba8f5ef4bcd9e8eade41b3fe25d8786b6b5fe98", + "0x415081db9ad19aa0e2173ba93d99d0d6ed9a48385fbedb24c7c81dd18eed394", + "0x3dd2cb4cb6238ae01cdc5f9a266487605ced4215f9a8a0e7b010a12be0cfe80", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x1", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", + "0x5", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0xe0057bc20ea2e65355b9babde022c12b", + "0xdc7ed21d9136c6db539a5ebd3064cba8", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", + "0x0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0x5f7e4cd36574fbc7bf721ab551930eaa", + "0x43bbc843a0d677c58f0de8f473d9f5fe" + ], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x72d70c0f1ab91afa262e842a6f3f8a98dd658da565c7279364999314ccbed5c", + "version": "0x1", + "max_fee": "0x354a6ba7a18000", + "signature": [ + "0x4a1653d0eee3fe5cf52a71e2d3789018f657770ea4d1520704355e5a5a250c3", + "0x7fda50a8767eaf42de251ff184a337e9a01c957335bbde0dd430526d073fc67" + ], + "nonce": "0x2b03", + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x6", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", + "0x1", + "0x17b670dae24500d3c79b915c046eadcc85d0800a392600cc5621291bc4aa461", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", + "0x4", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", + "0x1", + "0x55752e2c74b4fe577f7814e2bbc12c200f88b2cde23f711b7d50292b803853c", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x1", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", + "0x5", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0x1be2067e9e9147c11a15d1d87f43ba0b8302fe4ffc050b0ec46386ae76ec9f", + "0x7d82c7b2c959aee34df1cb5c17153ffe7d41e46c7f5df636251015af171dd81" + ], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x214d0a540e7b03414772c2c2de426eb5d4e4ad63668b6b81c35c0b2b2d6bcb4", + "version": "0x1", + "max_fee": "0x354a6ba7a18000", + "signature": [ + "0x69a2bfc21ebfaa4939244762ba0e2dcab4a73b0981072eeb2920c3a65d683b4", + "0x105dbe471bcd8c10ee14b57dc74086812339de9355d0dcd0752d586bfd23be1" + ], + "nonce": "0x2b04", + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x5", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", + "0x1", + "0x3951bc2d237738dbc3f8e599de009304d873151c89cb4eeb383a8dee19a0ddb", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x3604cea1cdb094a73a31144f14a3e5861613c008e1e879939ebc4827d10cd50", + "0x7", + "0x19de7881922dbc95846b1bb9464dba34046c46470cfb5e18b4cb2892fd4111f", + "0x2d7cf5d5a324a320f9f37804b1615a533fde487400b41af80f13f7ac5581325", + "0x4", + "0xf40fbaa08bfabcd6fb1a0ec3ea1fd8d0cdbaf82a", + "0x2", + "0x48c560eca37e048d7cb12b7ef2ea65d5e34a9b79a0379a1644939f7b9bf3f7c", + "0x1d65cca89665e33658632b26a178c617b6e6d6b34c687244a94e89202b407f5", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", + "0x5", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", + "0x2", + "0xb27423ef1c65d01b5166cc338bf943b3", + "0x9f43dfdcd16838d5be75643708dfb610", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0x73de4df6e20652d17f10334c16301c11", + "0xb9a1fceba481bd69490f5010e4a3b65" + ], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x3aeb0a48ba255a5aae097ebdcead737a46ee6a768ada5dea2956aa2446107eb", + "version": "0x1", + "max_fee": "0x354a6ba7a18000", + "signature": [ + "0x4c6b20d49be38735a26bf5945e1f3c6e2fce1a4f9e0738ecd52f4795c525e12", + "0x2cc70c6a78df1f37ddb471f8e1eb2d6842aa6a66931bd3c5b6bcce1586cf8e7" + ], + "nonce": "0x2b05", + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x5", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0xbf96ed271423c439e2db76e2746573b5", + "0xf07190dfcf287d653caedf8dda552ae", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0x67447bbbcb454bead44c902e17bdcc80d0056f533abebe082e6d71ab00f28c5", + "0x1175210ad43009ec56bde0abff3b2a2309aa5538ff5a9778ac97294df5af80c", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0x807a2ad9869abb8389c2cb931d1ed9d6", + "0x89a1b9d05e6f300d613d62295046fd0c" + ], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x4b6c706b4a3038b41519a3dd6d0f5e8bc18d8425a1df493fb5de747558636c8", + "version": "0x3", + "signature": [ + "0x17fe6eabf9de8ce62907b7e6a4d65a8fa59dd8c354306d715abb65f86a3e6eb", + "0x4a12e41d278a51d563dd43acc57c420cee55a7bad617d4bcf9d74605fd03e88" + ], + "nonce": "0x2b06", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x5", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0x1dcbc489e0f6ba07feedb2b612a6f7c9", + "0x1ec0d38b41f52802919811295f71e6e5", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", + "0x6", + "0x45697840297d58b4a4d5a5409c5ff698e080a7202bac696cac7997ab35909e4", + "0x3", + "0xb1cbd90586a7512eb49e81f604bc9cc37387dfa9be668cdbea1117690ae3a7", + "0x46cd6cfafefae479a5c3c9f5f1ab86edab3f252d6d0e13442cd648c541408de", + "0x588192bee153ea941a778fa2f6be1212d995437e93954b86d7b2e7995611994", + "0x22d3a9c729f9c3ab1b2ba97c59144c0d8aeb26bf3e8cc17c4d52a7bceaf853b", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", + "0x0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", + "0x2", + "0x8cc2b8aaa2cd756ca982a77725696f3d", + "0xee51cc63766130e7467331fae41f3bde", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0x69466ef6c2babaab5d69b9a241992e66befe2fa37d3c84b6ebe012200733788", + "0x44d73e39fbbef9b97005eb505bf24b30826966666a4173f4a4126bdd02feb73" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x1f6fa1f89da0df7a186bacfd78e91b95d88f057a513e1214f8ff0a732de30f4", + "version": "0x3", + "signature": [ + "0x6450b8a132de926d76dd5bdb8c86c33aefe32229a5a781cdcb79dfc24490e02", + "0x14c74a65f5101af1061f10576806d81f49fd2734856eb1eba734f578626650c" + ], + "nonce": "0x2b07", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x6", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0x23775eab251666c2828f90635955e4549ed21ba07bb40894c16338f408b55bd", + "0x41365c6c3603fc12bc2bebb360cb228cf67c0df428f72872a96fa10b81397", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0x713289e14d0c229fc28d77d3d8349253a75b8413bd5aa4a4adf790832e5b39b", + "0x215724bdf36e7a678366890bab97c1659a0190ca282f1638973bf2423011ce5", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", + "0x1", + "0x73cd87bafbef1a62813f780ce7f28e5f3b8a14201f839a34786841dbaf81080", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", + "0x1", + "0x413e1e751538e41027e223c64087c6ced93f87eb22edf87cca530bf5bcdad96", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", + "0x0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", + "0x6", + "0x2d11bb5170a1f928b6ecd7b97e025a491a5cb5fc4855eb496e07835dff04487", + "0x3", + "0x692e616a28746075cb8a6e660f951cc842f43fc5a2030fa13a27bf7a41b179b", + "0x2ef606af2baf35a9e60c618328075b4d309765e55c336ce29d79d3a3c5566ce", + "0x12159a449f1a0c82c83906dd424f34f8b3e00073a67668a814cd9c1940167ce", + "0x7ea13f682c7d3a64f766dc6774b4d6306cddc564c66bee45c2194d47d80936b" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x5d7941297f3232c0a98bd8e0b51d5d2464e97057147d06a0c41a07203c639ac", + "version": "0x3", + "signature": [ + "0x235112872a32e6ad2a0ad40f6dcf5ef5ab07a374a301c560e969c3ea9d8a3ea", + "0x599c44ff9ce4742e7d9ce3d84e7941d35001b7cca3139b77cc1b1d2c532ecec" + ], + "nonce": "0x2b08", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x5", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x17da35ce4ed77e22e3b9149fd965dba57351a6c29f588a7d245e208d073e4c1", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0x30180bf5092a5ff4b3cc0869fd41908be37fcfaec0037142227d3c916e86473", + "0x6764d400af34621182e8a6959dc7c716c66428210d3495d5b443df0103370e0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0x6f4bbcac9ccd3f40270d33077a220a2b7be4b027195fbecebcdfb99bc98280b", + "0x719b92cfad6796e15ffddf636885f2fb5255427091db6d4fae9b23546a0f6a6", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0x7e5c2f4b0dbef33d51a707e8a5f2b0855dd7e15142d8f49811cec6c1976427b", + "0x48512d692d3429b05b4417a80c12328df0c40656561c2e0d72bffd187ab606a", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", + "0x6", + "0x55cca0b45c9c4cee79718132afc5c4d2d1f4d029a29efc66b464e9209199af3", + "0x3", + "0x693aff98f855195256320c1744b36988e5efb7544af094f0234f5102b6fedc", + "0x68f7ccc05e42591293a68372d8cce749527e66804a036b22a0b14098b862218", + "0x282e2b68eb812129b5b2305aa4e1a45348ea41ba2bf9ab46d541b91d8ddafb4", + "0x100b081355846a5cb46d10a84e181b09d1c8f85b33b1e818aeb7fe8759caf7" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x323977511f652a2c494d4b7ef52b713d20ba702c7edf1fd1495a5b7fcb9b44b", + "version": "0x3", + "signature": [ + "0x4f4cea7dd16350ca4fbd98934063a41026007d4ec6d89a6b7e89c2aa5c972a7", + "0x28ec61ef4503111fa4d6e1f5c2b08b2059cdea9991e48e5c1eb6f0a63215991" + ], + "nonce": "0x2b09", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x6", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", + "0x0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", + "0x4", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", + "0x1", + "0x1c95c56dcdc5774e37988893ba5edf52b07ef4ca3730a969144643f551bbbc5", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", + "0x6", + "0x666c83f59b7389bac9789070aee65ace9e99ed5f4ffcb86a4d8aba7d338c98b", + "0x3", + "0x7b5b27757a05f6bb78487984f7a96e15a18c6053b4657886f5e4e6f91178f0f", + "0x33695f320ce6d43202b522fa2d92c6e34118f960a0d9edb25ed15910682f596", + "0x1e21d486fabbba4261dd3f6ac5148571bd250983730dee61ab8631afed8d89", + "0x65e8f77d55085d2561c8000a4f2ead80ed266695b4501d6946bb1281f6be540" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x2c0957019f8956130340acd8c96bc5c93a03a3045cf90dd50b70d580377b61d", + "version": "0x1", + "max_fee": "0x354a6ba7a18000", + "signature": [ + "0x198b44af8fb4a8af161f8da184d14edafc52f7e4c66d62841f9a6a757a16dbe", + "0x5a93ba3b72d470f90df29e3e1b3d7a2a132cd92c0ec77292309b950a8bb8bdf" + ], + "nonce": "0x2b0a", + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x5", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x1", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", + "0x1", + "0x6034a91070e61d796132b34792bc1915bf795ed829032e3d32aae0ea992352", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x241f3ff573208515225eb136d2132bb89bd593e4c844225ead202a1657cfe64", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0x223964780f6f8de6a748ba2ac3b73e15", + "0xab3d17df7864a109cd68e9e884a0c554", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0x19b9637dbca5e7dba97ef0cb26c80a6ee2c402d47e1d259b4e07e96c38d5f71", + "0x124c127fc636898043a083d0515c47759b61e2556b2e0f90041816eaabe9697" + ], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x570a47e2a3aab957dd3d09f8fe778ccb54163bc4207585d3f1e7ad471197f1c", + "version": "0x3", + "signature": [ + "0x3ef16b0d32b4b68a3a627b304e6328428b36d83f9aca38baf050d9fc059efb5", + "0x5e118208e04a46d748aba9b90f1adf51bbb1982ba4226e928f499af3d932d57" + ], + "nonce": "0x2b0b", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x6", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", + "0x6", + "0x49d389ff8457b29a69c3d57c0450dc56b1406b9e822f08f88b6ff7fa11627e9", + "0x3", + "0x52afc8740c79463d83b7628c35dddd807f6d2858d860752f980000e87d8d854", + "0x6f6a828242385c55eb76bb6c4f896492a91980e2551ccee675f7c6dfe79956a", + "0x575b2db2490f75d6877f64f23cc14589958b4cf31da2c65d9663c6dcb656a23", + "0x1413e46e460ee879a99aa5c350a2b38ddfbd59fd740c4ac3ffdf3e4ecef3204", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", + "0x5", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", + "0x2", + "0x83a3f525814262fc83e4e79e8e898222", + "0xe48645edef42b2b0e6e029f5c11c536b", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x1", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", + "0x0" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x2cd6a8aea2b82b7e37d30451074c298e03c377feb90999c4fcdacf99ed46f97", + "version": "0x3", + "signature": [ + "0x6208631264e1fea9cc4bb62eef7008f23ad70a2d8c5f3ce5e0e0065c0c69639", + "0x6405dd3e44e48d7d2d6b81fc511affea0b249faf65473eab07eeda4398a8174" + ], + "nonce": "0x2b0c", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x6", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0xbbbf5056ca48a6099b038ac93ca1d41", + "0x2c45e9d21b843a7209a3578c62b7f863", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", + "0x6", + "0x3ef516eb44f7a25907ebee82d2eed55a2b26882cb684da9a0b1358fe0672e12", + "0x3", + "0x1bfa88a6d84994c4cff5dec7d8e3aaa205b28b7bcfb7e5583f33508ee92b17b", + "0x50a25225519d91ba161f48cad22cb84d48d5108c43665c0cd5d3a3ece0946b2", + "0x23e92483a133a6aef2ec70e9faf85ae1afb61138bf385a28cf0281610bc4e86", + "0x493f503c206a325fa868ee3c0f46c6ded2fb7d8794c2fb51aae324e8f8ad68b", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x1", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0xaf6c5141ccae2abad79d68be3c06cd47", + "0xdef061addc512a1a79c80b148a32f0dc", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", + "0x2", + "0x87f8bb5b0d1992436c27e387ed8a1919", + "0x49c668a847de5cf6bae037d937fbde28", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x2d7cf5d5a324a320f9f37804b1615a533fde487400b41af80f13f7ac5581325", + "0x4", + "0x2eae5b0fe2112b79ecef02b30243ee9a7cce0ebe", + "0x2", + "0x11f17e586559af18b7e5beeb3fe68587e7e69f0b336079f9e3d03fa0343c783", + "0x82a221fd714f879773458cfc0df8b8c2d5798ed9e57fb2afc3cc1c485e6f1c" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x5e3470f9a6a059d2190685fb82ca05eeea79bcba70b591130aff661cd5fb828", + "version": "0x1", + "max_fee": "0x354a6ba7a18000", + "signature": [ + "0x639ecbf576244c33094172a07acfb70857c8bb01d09457a859845abae52ea06", + "0x3ce2a80ad5a0d4a663713dae7a0df79c7601c09043d8d516f55b13bc4192193" + ], + "nonce": "0x2b0d", + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x6", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x3604cea1cdb094a73a31144f14a3e5861613c008e1e879939ebc4827d10cd50", + "0x4", + "0x19de7881922dbc95846b1bb9464dba34046c46470cfb5e18b4cb2892fd4111f", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x1", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x1", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", + "0x2", + "0xbf1ef784b19f0afeb1bf8a8e05a45f35", + "0xefc35253c76135d8b8769f25e4f66662", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", + "0x3", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", + "0x6", + "0x5b6036498212930c0160795ee17255fb94291ff053251b855b6da5d97b74531", + "0x3", + "0x40a8bcf47285adcb19628e0480e1057968b655ae8ecde24ffd7086070b5b9a2", + "0x3e1e8cf3b705f1039bee876a6a72988c59ebace9186ab399dae1c3f8b76b6fd", + "0x383afa7ce58c752b62f44f4f86446226b2246731ecb15296971731882c10f3", + "0x734e0292602f96d307cefe554cd1c5d32d1e115f3b8a5097f307bdeff24a320", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", + "0x4", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", + "0x1", + "0x7ac2fe2ab9751c67f517ef4850a4b025a812695f1b63d8d7a6e0beb9c3f6536" + ], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x3c78d2cab2fc776e2dcccf55ecbbd480b9484953a8be01b8c0306f88b2ee774", + "version": "0x1", + "max_fee": "0x354a6ba7a18000", + "signature": [ + "0x73619bcc36c7e3e78afa8b4352758b93b2e67b96e9e825ebe8794aacb90e03a", + "0x3df74700add4e5fd6b69f6a8fea70e90ed38d470a3e41cdd537518cd639fc48" + ], + "nonce": "0x2b0e", + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x5", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", + "0x0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", + "0x5", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0x4aa8efea3b222661d24122eea76d3d5ced765e259e52661bcc755a0714fd48", + "0x142f1e5d40c680f935bd44f83421d9cf28119727d06b56d2e9b4c3b370bf107", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0x25524703ebf4fc398a37c573d6cf02798ad6faaa2a3dfa4df32c4bc65e08362", + "0xe554fe3ae68d105750635ad0f7f284f9d2ae8f3a517a400418864b8e2cf4ad", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", + "0x2", + "0x9d26b9dff3413d16f4d1ee8ed037b762", + "0x89fcc59f11a31406f8290a6e42a31387", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x3604cea1cdb094a73a31144f14a3e5861613c008e1e879939ebc4827d10cd50", + "0x3", + "0x19de7881922dbc95846b1bb9464dba34046c46470cfb5e18b4cb2892fd4111f", + "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", + "0x0" + ], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x2f8a9ceebe94631c2a75b078731515cee0e5ca12d2729575dc7d932f66593b6", + "version": "0x3", + "signature": [ + "0x534a93c18cf11040cc387c9c406b9a0625e1fffb68ee6abc8636e72ee6df394", + "0x1121a1f70cc733a088e9e9320d5684ba1938170685377af8d96e9a78db3cba2" + ], + "nonce": "0x2b0f", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x5", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0x2022ad39ad6c5f8cfb021797c62ffe33a0be2e8b974fcb26b0c1dbf56aa12aa", + "0x2210e910f662f494eec608337a71b287f6a2f346456cc34ba35e2f01412012e", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", + "0x1", + "0xc54ba698bd75e3638f6855d6cd17c6ddb0a364fbf03868a930433a27436a5", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x1", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", + "0x6", + "0x37b72967ee34e9b00c45a6c1319ba8d28def41e60c8e0bbf91d440dedbf3a44", + "0x3", + "0x2e0afc0b8bdbc766d2d58ec64f78a0fc82c4f73abaff128c10005bb6a625475", + "0x7a945a82f362f478cda98c5c2952dbd9d8d805f5f02b211bba7e3299f261979", + "0x46aef08ffafe9b3e7644623e58f73dcf148fcf483a3fc9779836260bf576377", + "0x748a9cf9c9dc4ecb387ec19e8c56150240c73b42d84d1d196a84c125234773c", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x1", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x65949106a60aa0465ccc50dfa41676fbef444c94b051b08248653e443f9532f", + "version": "0x3", + "signature": [ + "0x17d95036e269896b48ce1f7af77a379ab8fc77eda72c20aaeb494cf9297c92c", + "0x3ede07f71f1228be351f9a5ce2ef854027ad6918890957a5ac76f194b85ac94" + ], + "nonce": "0x2b10", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x6", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x169f135eddda5ab51886052d777a57f2ea9c162d713691b5e04a6d4ed71d47f", + "0x4", + "0x19de7881922dbc95846b1bb9464dba34046c46470cfb5e18b4cb2892fd4111f", + "0x3fe5120e78196b665bb1bb5299fe4f94cc23ac6d71e39cec67014a2ac834053", + "0x0", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x169f135eddda5ab51886052d777a57f2ea9c162d713691b5e04a6d4ed71d47f", + "0x4", + "0x19de7881922dbc95846b1bb9464dba34046c46470cfb5e18b4cb2892fd4111f", + "0x724a2319c76a573ba125cb1a720fecf39712a9f36b14cfc89e186fb15a31f54", + "0x0", + "0x0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", + "0x6", + "0x49083c6dbeada5ca48496d10c5b5fc879a66cfe2106edb7ad133c47089a461d", + "0x3", + "0x4e39b2f0a8f28116d4bcb252009dc6f9f99582801bb9a0d9338e69e572675c4", + "0x33fc55ab493b435eddc00987bc0587689ded268a82ffc6d41e32d32f4e18ea5", + "0x6f2747503b85199bef9ab777e17ee34bf358726cc1b9440d1a1c439ffeadaf8", + "0x214ad9ac97a938e7849567b63fdc4db5cb199a1be029d9b6139423d51b12ac2", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", + "0x2", + "0x3e333e6d57a0f05cf0872a7b6747fee", + "0x4e752f68ef85ea22f5af42e8d2d95a94", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", + "0x1", + "0x85b24a956875ecc291451fbcbcf89f36a9a996e11cc6e9d4def54a5c317456" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x7c31171221dce0134eaed898eedef9a9283c46007d5a7205cbefb60bfdfdeae", + "version": "0x1", + "max_fee": "0x354a6ba7a18000", + "signature": [ + "0x29c8843a2629da960d18889ed9533d239230771de74bf6714bc80200d1b662c", + "0x79ad670c5227cd9226783be58a1ec635fd94cb3215000be65c219e1a8df87bd" + ], + "nonce": "0x2b11", + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x5", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0x704ca12a4f2fce52c563008447e73b881260209e89f2dcdb0e1d1684cbf0d38", + "0xb3560faf72558bb834f120a8c97cc11155a71b154a6c976a394c41335ed3ff", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x3604cea1cdb094a73a31144f14a3e5861613c008e1e879939ebc4827d10cd50", + "0x3", + "0x19de7881922dbc95846b1bb9464dba34046c46470cfb5e18b4cb2892fd4111f", + "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", + "0x2", + "0x7456d9d187b28bd4c47dce05c0a08091", + "0xa3b6447a65be4e98195a851de398370f", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", + "0x3", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", + "0x0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", + "0x0" + ], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x57dc37799d80e5a4325b44b272177af28259afe4a08d9e035fcaa7463c78d1", + "version": "0x3", + "signature": [ + "0x608f978f1f43ba410ba375b98423dccb750e55efb1068fae60705371d87bba4", + "0x7fc94d1307875ab647b111f116400a56c2e723ec24238ccb3ed38dab3e087a7" + ], + "nonce": "0x2b12", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x5", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", + "0x5", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0x5895a6d426fe9f31dfa92b92f129f03a", + "0xe13483fb7e371972acdd7a988b7c3dda", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", + "0x2", + "0x42a9f637a51b03361e1479cf7aa4a6c0", + "0xbb655695f7a40bea741ea60e36c6eff1", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x17da35ce4ed77e22e3b9149fd965dba57351a6c29f588a7d245e208d073e4c1", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", + "0x2", + "0x5bd399d1e7c918c4d53fda5eb32a4f2d", + "0x3fed1afa0c2ac0ed7cfc0da8944d92f8" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x5b112706c56d0e776f2074dac9622796190c46c460f6d3f7e21848a0f823564", + "version": "0x3", + "signature": [ + "0x719d8f8c8ef0e3840614c64831f006cbea2747dc951707bcc193a7dae3ce9", + "0x2fedc0a0ae6653c2e35c7b5178fe55a8fd4e6bc417e51538254035c64748dd0" + ], + "nonce": "0x2b13", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x5", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0x1fca2bd4a99a332e61049ef871281c512f8602b65df29e571391089095146f6", + "0x7202a8c18893f7950847d13dcb66dc6216f5705bfb1e5508ddeafaa145302ce", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", + "0x2", + "0x2746a3cf38463dbbcfc2e34d90c0d1ca", + "0xab587d97d68a9ba2febde33143882331", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", + "0x1", + "0x5395b30901d24f20dac387095a663db9a7c07f2452c699e7bb104bd73a3951b", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", + "0x0" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x2805277fab3bf13cabea921219a291b59f5c976c576b17880bbc6420df1d948", + "version": "0x1", + "max_fee": "0x354a6ba7a18000", + "signature": [ + "0x25cde97bc5548445309df5fe7d80639adec0332c374f4ab8cc2df933d5ec48", + "0x34a4b80e0c550e1edf2416cad0cb7a2dab42e105e883cd69e9e881232eeb044" + ], + "nonce": "0x2b14", + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x5", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", + "0x2", + "0x5b80a44014d71e4c3cc56392d7167dfb", + "0xf5c47ad72cb7729e6deed83c07edf677", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0xdc794c7435a242d1e2970bc2d4943639", + "0x242104b5f506f8952fbd4a630bf17672", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", + "0x1", + "0x7ba9f7d0828ce4dcc85501ce6b13f331b9536bf5a2e7faf23b0db3319511935", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", + "0x2", + "0xfe63880340f114c15c74a0f679663a8b", + "0x870a0be881377a89a98cf92790b80d4c", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", + "0x1", + "0x1a2a61024dca097e3b4a81ee898d83d0348afb7746a850bed6e0160f754ec2a" + ], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x8b6c4271730d086c0c63000fa2cc756f6915ce9d4c949aa03a3675f265d4c8", + "version": "0x3", + "signature": [ + "0x4bebd487277fef385bf103f30a3222a5e054835ec2d845af7a8beb6fcbbdcf0", + "0x17e1947a2c14908659e6ce211aabe688d2cbc1506d5bd1a5c954c01d31c23db" + ], + "nonce": "0x2b15", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x6", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0x12704101a5e04604b8ba9fa1001108d96c6ff7ca584506ac76e71e56cd61b33", + "0x44a69811281bedbdff09284b8ac54658a4a535fd04cdeeb5de08ab00c55ac91", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", + "0x5", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", + "0x2", + "0xbda8ead4de04074dca870401158c646", + "0x24536f648a5b39d277dfca3f416118f8", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", + "0x3", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", + "0x0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0x571265dee208a842bd24b00d9ef03cab9d75cde3fd940fdebdc98b930cf635a", + "0x6756c71d08ff148f5d623765cbf6969bf88390eeae0968b29185c76619e5d51" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0xbdac2ee80cd888998e3233d2ad3d8760f58582d82fce9b6272d3177d9d7dea", + "version": "0x1", + "max_fee": "0x354a6ba7a18000", + "signature": [ + "0x7b75a1c526feff49f43ea098f6423cc463ef603e847ac5a2c5e419f97931693", + "0x1e6deeff6fc9239de2d2356452dd047b8055ffb43fbb82f5a53228eaded43b5" + ], + "nonce": "0x2b16", + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x5", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x3604cea1cdb094a73a31144f14a3e5861613c008e1e879939ebc4827d10cd50", + "0x7", + "0x19de7881922dbc95846b1bb9464dba34046c46470cfb5e18b4cb2892fd4111f", + "0x2d7cf5d5a324a320f9f37804b1615a533fde487400b41af80f13f7ac5581325", + "0x4", + "0xa1b72fcd5be6af767d745199f73dbfb425b34a60", + "0x2", + "0x295e81336118da80d9deef4f5c67272f2195f7bfaf175a387ea1dbd50d9f5c6", + "0x94a852b9c75eed97c3458c1b4a3916fbe40eebfbe6f36f494881b89e98e0f7", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", + "0x6", + "0x1acb1a91d60fdc1fc1c8403949e8f97c6066de26be3cd4ee7b0b0d44f5e8441", + "0x3", + "0x7f98353f5a29ef95702930c304c98b14ccca62c82dbc49e2dc14c3c6c6191d7", + "0xe6d48809cc6e0cf670c0f05aae20747c3e5a4ea0c619d465f296dd05946ccf", + "0x400c16a3b7f0a2fd2575962c75beb90376defce72ed3d206d17327884e21b6e", + "0x45e8abe8d79936f9c9acaaa30eb7facba0cd1bb08b7f15855a4d74364977f2f", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0x5ea4648fff8c7f3ef9ede48f7f534e5d2703106394dab5ba265db271b4e1c8", + "0x4a08b85df0047321aff3eb785a6b76e1d99e601b6aa2db2a08d35424a146a9c", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x3604cea1cdb094a73a31144f14a3e5861613c008e1e879939ebc4827d10cd50", + "0x4", + "0x19de7881922dbc95846b1bb9464dba34046c46470cfb5e18b4cb2892fd4111f", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x1", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", + "0x1", + "0x47b2d2189c76735f4ade97b9585c85c805a8807bc3c22141c3131459256c0e8" + ], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x715b99aec587534547d4e33e0816e40129342404dcdb7b2f6cb5d75976f6595", + "version": "0x3", + "signature": [ + "0x758987c1e6d0ed57acb29d2bab5b3d1d1cdc3cd621d51a387eb7aa8dae12fd6", + "0x25105a79b0f1022d9e32b1a288060c3f8927ff506f30e333dc7c8fd0e77951e" + ], + "nonce": "0x2b17", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x6", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x1", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x169f135eddda5ab51886052d777a57f2ea9c162d713691b5e04a6d4ed71d47f", + "0x4", + "0x19de7881922dbc95846b1bb9464dba34046c46470cfb5e18b4cb2892fd4111f", + "0x174f7a59ed3cafd016a00d1f2662d0340b237634c62e6c8cb41fcd28c40facd", + "0x0", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", + "0x1", + "0x233117f6b96e6c38532500d51fa8e88aa2d291231e531db24a9915a15d3a919", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x1", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0xb4b791ff3b1855355f8ed7e0eec3b5cf", + "0xb120d90d71d8efbf8eb5d2e225ac38da", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", + "0x1", + "0x1cb6b26d1e1bb70447ff3197aa68d82e6870f04325fe9df09d2d54b58c23583" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x4364ff805b7cab23338929dc8927ae982f74b8b5970dda00f36ca97eb1deb28", + "version": "0x3", + "signature": [ + "0x7c0fbee6a598a351360d5eac79082bf2da01a789b49ac56a8e9a4fbfccfd87", + "0x451b04c37763f88aed43d9d4f147b4c28e53ddea531a55d9b57f9f72513fe05" + ], + "nonce": "0x2b18", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x6", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", + "0x6", + "0x7ce989b0419ef8fe25e6840faa1c773d72ba3348c55180662748e63a105a786", + "0x3", + "0xc7f6f73697f21eac88b7d95deeaf48acc8aec543a90b64b00bb1902660b57b", + "0x146b1e6617de03414d6b766339c823f4f0b090b8a383d4c3bc8371e1e9b2729", + "0x5b72ae12e06513fcd37083cca27aa83898b8a1064fb7c936d1bf93517fa1e22", + "0xb1b17c4a60ffd0a634e1d713ae5bd3ca2ead781cd35ae5674fd855a5795158", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", + "0x1", + "0x478da66587824115dc0f98ad7be0e9a103cf27d200cc2dff31b5932c46e10c3", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0x2e085134a16ebfafa44a16d146026a24", + "0x3e705c878d7b37b5bfc2478c598ef1b0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0x13bc8ce5125f1186f2dbd5bd06044f0755373d9707ee78e748b8bfc9d984439", + "0x4151c442d9d919b55e628d871277089ef237b04b25311961af0b21daa46aca6", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", + "0x6", + "0x77005947a2dad7aa2389374892cc3d719571b33229bbe1bd16aac13b22fa1b0", + "0x3", + "0x2b73e559128d2c78c1e9d8c5a54f4cf7ed878f19af1bf70909d1f87124da7ba", + "0x3dd38cbf00e2d583d5bbce77623c3ac3cd5461710a2b2e78045c12078e9976f", + "0x5aef01d048765fd2b399b15a0fa4414254f1dfb22caf535b489beea48ed9079", + "0x1c453eacc7c47a6535d43c88374958b4955d02393919e9161ea94e73ae11a2a", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x17da35ce4ed77e22e3b9149fd965dba57351a6c29f588a7d245e208d073e4c1", + "0x0" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x77a8d43ca8fd40069f884b7773577d63fa954065c3b1a1daa421dfa87ec6afa", + "version": "0x3", + "signature": [ + "0x41e2addd6e2ec96d02d177abb71371755b8a3af0a9ba1726b69e6ae9aa88481", + "0x4a99ddc92a8f2d3b6664efb90ada05bbf7e16b0ec8408f46110f1b9d34a7c09" + ], + "nonce": "0x2b19", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x6", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", + "0x4", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x1", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", + "0x6", + "0x3fe2ae4b30012d46c1f883db48c2d54cea76abf6b5870adbf4a3f8de97fe84c", + "0x3", + "0x48cbfaaa29757c20f9bd898aa285b66b049876d67b47424176e945ffb6cbb73", + "0x188896a20fbe98a0fe8e35cdac9d3ac809260de7288331c1901b8a0241eb050", + "0x4edb416bd209c871e52843ae78bacdb9347ba0bb25449f125bb78af1d34ce7f", + "0x1a00d61f010f9e891c33c45d1baa1d8fbb78b825ff31d85f67ba0e0ec2e9b6a", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0xc623389a9d41fec3dfc9dc7b414a727e", + "0x78274dae4861a5839ce9063b83d8daf3", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8", + "0x0", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", + "0x1", + "0x73f787fa47d46e38dd6d6630eb5adfc12f1f3448be1a5bfcb1ee4ff4c673c41", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x169f135eddda5ab51886052d777a57f2ea9c162d713691b5e04a6d4ed71d47f", + "0x4", + "0x19de7881922dbc95846b1bb9464dba34046c46470cfb5e18b4cb2892fd4111f", + "0x4e50a2b09771dd09d10717e9f231b0df3851085280e38e666c448b1fd896489", + "0x0", + "0x0" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x58177e246ff04b9b229a68910a374605766a298254e357b30aaeb8edaf9d66d", + "version": "0x3", + "signature": [ + "0x73a3aba1ea0123702575fa1d662428f7d330e528b99324b43d77106675d178d", + "0x6bb624d7fc32ffc0500991614a55e9531c03bfdb3448ea32123a1e88faeb6f4" + ], + "nonce": "0x2b1a", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x5", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", + "0x6", + "0x699baf12807140f31ae31552b26bcdfa9d5abd2cdfe25a6505452f0bbdd31c1", + "0x3", + "0x429ca58b9b7d74ffdf0f2834eb13881bc3133027694c42076b31dad26f5583b", + "0x4c055756c36807649f3c6b403313cc82db56c8f303ede8ecb2b8861c67f255e", + "0x31da6141fcf54cc7595791dfa3cd1aeedb2062955de755c370c26ef111e1791", + "0x5dde871eeba96b8fbbf84ee6d78fc2e9431a6c1f5c5f942601a70abe5860902", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x1", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x1", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x1", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92", + "0x6", + "0x557e86f7dbca848da70ca314e09d4c2d3aa0ffce4c595172b2d41e78632f837", + "0x3", + "0x7cc095ee2c4c6cb238c19bd2267a7cded49f8ac8ce6f8de22acdf9c1d736e1f", + "0x69f642da1980792daf9890e7f76966f9addeaebfe0150f2a264f4fe4e17ed10", + "0x37301f8848d498baa6088a9da64b9a58bb557d4035367bcb1e69a24b67df765", + "0x6ad0a6e5af2ec53793262ead372a2524f7bccda1db09cd545bfdc3951e79447" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x1f55ed06d78117d417899bd94eda790bea602379e1c43f8b86d859d92eff38", + "version": "0x3", + "signature": [ + "0x758887ba77a567096ab1aa88e3f60e3c1828f1da0a76a246b31ce2913414817", + "0x1f0964dd2b090be6f800982c2a0d2e05fe2b213c81ae3e14cc929b2dec3acc6" + ], + "nonce": "0x2b1b", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0xc3500", + "max_price_per_unit": "0x5543df729c000" + }, + "L2_GAS": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "calldata": [ + "0x6", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0x168c74c6c2d6911cc5e223a0680d754b3b4934022fc9463cace69d4a2b9dbce", + "0x2c57ea26ec79a71efeb4d3601883d7d71d555986ecdb7c3fd9e1bd7e0c19da8", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", + "0x2", + "0x35c857f538814c8f47ffd6d6decc1173", + "0x6a25775a51476c4d2ba3a0a8dfdfae1d", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x2d7cf5d5a324a320f9f37804b1615a533fde487400b41af80f13f7ac5581325", + "0x4", + "0x9cdf07d5726bc54bf908bee8caed3d3ecc5263ff", + "0x2", + "0x4066ebb426311bfe53ab1580e14fb2379a5d7d610695c9b05d11beb2c444376", + "0x8d380443209a3ec5875d5e25d361936b3b75cd45d39f1ad5dc7f4e601b179e", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x1136789e1c76159d9b9eca06fcef05bdcf77f5d51bd4d9e09f2bc8d7520d8e6", + "0x2", + "0xa4100e4985a8fe24f4c8d2b9e963dcc9", + "0xd22d5d37d75f2f426378a78e2f09714a", + "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", + "0x4", + "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea", + "0x1", + "0x2fd9126ee011f3a837cea02e32ae4ee73342d827e216998e5616bab88d8b7ea" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + } + ], + "timestamp": 1721022890, + "sequencer_address": "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "transaction_receipts": [ + { + "execution_status": "SUCCEEDED", + "transaction_index": 0, + "transaction_hash": "0x195e0414c0c8dea28fde9944a71bd97abea493826d302e2030d9c0249985237", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "keys": [ + "0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4" + ], + "data": [ + "0x54ac7e24b2048fc11c6acd60e4ed10c43867d240968fcb8feee8456ce1834a", + "0x3", + "0x1effc638ac1dab44be3251b9481fa6ae5e793a5d863f930254153a071238556", + "0x60842344c544cebb67f822fce41f409047aad7e83499960b970dba7874a7992", + "0x513f6b8d4f96f5e5c02df23e7b78a775188d2754cfa27aab1aae350be8ec776" + ] + }, + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0xda999d63e40da", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 17931, + "builtin_instance_counter": { + "poseidon_builtin": 5, + "bitwise_builtin": 6, + "pedersen_builtin": 44, + "ec_op_builtin": 3, + "keccak_builtin": 1, + "range_check_builtin": 874 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 256 + }, + "total_gas_consumed": { + "l1_gas": 49, + "l1_data_gas": 256 + } + }, + "actual_fee": "0xda999d63e40da" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 1, + "transaction_hash": "0x4000d1e50af1fff8150bb5fd8558a5146952171804ba967358a5fe0e6b0e354", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0x8ab05be7bd", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 15214, + "builtin_instance_counter": { + "bitwise_builtin": 6, + "ec_op_builtin": 3, + "poseidon_builtin": 4, + "range_check_builtin": 683, + "keccak_builtin": 1, + "pedersen_builtin": 34 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 128 + }, + "total_gas_consumed": { + "l1_gas": 41, + "l1_data_gas": 128 + } + }, + "actual_fee": "0x8ab05be7bd" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 2, + "transaction_hash": "0x1d5adbb883c7a0bca0f77ae2dfdce4ad0e1a74098c19042c8e4e62fa85fffdb", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "keys": [ + "0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4" + ], + "data": [ + "0x2efe3ae7f7d837b89fdecbf7b7945ce3b25aaf05af34e1efb05e0547f1ee386", + "0x3", + "0x1f079c6646bc296715cd4dd16aa925ce5b0d3b4451f8a9bbc4cbc640f597028", + "0x33010c7c261820fde09299468cdf37a9eb00a24996974d064e99dfa773be529", + "0x1e03394ec22f3057f33e71f64aea7bee380e434c102e428e7b371453cba01a6" + ] + }, + { + "from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "keys": [ + "0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4" + ], + "data": [ + "0x503e8a1838da4c1f6cc8f5034720744ea17fb42cea8fff5325cac8af867a31e", + "0x3", + "0x5a42ab0819e4fb5af67cfbc5c7cee60add07d61dba6c4872f9bdfa8b8db7e0f", + "0x2935ea46f5da5df3e0ac6c41882cfdbae828fbcc3dff634a94c2db075d94765", + "0x2aa78c08c048e674553c8db20bb4dddd80a8c3dbfd25b9168adb5b8e6627eb4" + ] + }, + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0x1448dd1f32fe258", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 269125, + "builtin_instance_counter": { + "poseidon_builtin": 8, + "range_check_builtin": 28964, + "ec_op_builtin": 3, + "pedersen_builtin": 58 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 416 + }, + "total_gas_consumed": { + "l1_gas": 1164, + "l1_data_gas": 416 + } + }, + "actual_fee": "0x1448dd1f32fe258" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 3, + "transaction_hash": "0x2a2e7175a982ddb0d1636d453692a6de9c8542b40f2230d684070aff102b31a", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "keys": [ + "0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4" + ], + "data": [ + "0x3e24d7e4732ddf3f933bf601ee207f42004159f8a1474ab3448ecf6cca36cff", + "0x3", + "0x7749874b2259b32547758256b902d9b46ed2b1e066867b967ed02ba3a8fd267", + "0x5bce1cd81751fa197b1583eae513f3948cf3299ad3428f76724e2af9558a7d4", + "0x4f8cf745cf31a95ff415b79eb94eba142a798d1aa812fc49e108b8ee5efd260" + ] + }, + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0x1417ca47aa1b67a", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 265383, + "builtin_instance_counter": { + "range_check_builtin": 28750, + "pedersen_builtin": 36, + "ec_op_builtin": 3, + "poseidon_builtin": 5 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 128 + }, + "total_gas_consumed": { + "l1_gas": 1153, + "l1_data_gas": 128 + } + }, + "actual_fee": "0x1417ca47aa1b67a" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 4, + "transaction_hash": "0x451a26cbcd55d2281c1b2c24445a5469d2fc16da4159c44d3b04a76579b5443", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "keys": [ + "0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4" + ], + "data": [ + "0x5be0ead6150d49c16a6277e7290e2d949a9e99b6c4aa0a3c3abf06ced66ad19", + "0x3", + "0x29224b3670651d8012b718c5054731e012817da20d50f7b54c6f8092ac130cd", + "0x3b644a3062bc3a55da8cc0d5bb9420d3b37124840c18423e7886c020bd85460", + "0x372a463e2aca39366b207734cec5b4612ed71582f97904e31a65b16dca90b69" + ] + }, + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0xec71e3e5ec442", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 19872, + "builtin_instance_counter": { + "pedersen_builtin": 43, + "range_check_builtin": 946, + "poseidon_builtin": 4, + "ec_op_builtin": 3 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 128 + }, + "total_gas_consumed": { + "l1_gas": 53, + "l1_data_gas": 128 + } + }, + "actual_fee": "0xec71e3e5ec442" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 5, + "transaction_hash": "0x67ffd6807ec99456360431e3411ff24d94bbb7db058c5a427540720d3f23bc7", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0x121fac8bb7507a", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 24141, + "builtin_instance_counter": { + "poseidon_builtin": 6, + "pedersen_builtin": 45, + "ec_op_builtin": 3, + "range_check_builtin": 1291 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 256 + }, + "total_gas_consumed": { + "l1_gas": 65, + "l1_data_gas": 256 + } + }, + "actual_fee": "0x121fac8bb7507a" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 6, + "transaction_hash": "0x651b1acfa1652c7eb678979a8cd26df183dd3fe3e16ad26bf1b5c150547893", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0x11498909b09d8c", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 23110, + "builtin_instance_counter": { + "poseidon_builtin": 7, + "pedersen_builtin": 48, + "range_check_builtin": 1115, + "ec_op_builtin": 3 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 256 + }, + "total_gas_consumed": { + "l1_gas": 62, + "l1_data_gas": 256 + } + }, + "actual_fee": "0x11498909b09d8c" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 7, + "transaction_hash": "0x30b2d48fd3c80877d7c05dcdd9535ba500570f22c5c8ff2354707d78b89b511", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "keys": [ + "0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4" + ], + "data": [ + "0x4619138d933b114b7942c93762827303aab9ff0a8b876765802ef7cb60ba658", + "0x3", + "0x32d345a97bc0db35ae9578aff71192bd142595afe1720056892f00c245fddf1", + "0x3748f3eefc81fd923a83f9ab2d9ea2ee41378fde4de92257a067538138faba3", + "0x1265c400681e1fdea145d3857b045a792a882334bf858335716c2934e189838" + ] + }, + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0xc44b3b84aab78", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 16033, + "builtin_instance_counter": { + "poseidon_builtin": 5, + "range_check_builtin": 638, + "ec_op_builtin": 3, + "pedersen_builtin": 43 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 128 + }, + "total_gas_consumed": { + "l1_gas": 44, + "l1_data_gas": 128 + } + }, + "actual_fee": "0xc44b3b84aab78" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 8, + "transaction_hash": "0x24c7fb9c2336b7a3db94970c71d095b464ff25f47e4c62f505d8bd3c86a784c", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0xe2a3c9c99f", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 24991, + "builtin_instance_counter": { + "range_check_builtin": 1352, + "bitwise_builtin": 6, + "ec_op_builtin": 3, + "keccak_builtin": 1, + "poseidon_builtin": 5, + "pedersen_builtin": 51 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 288 + }, + "total_gas_consumed": { + "l1_gas": 67, + "l1_data_gas": 288 + } + }, + "actual_fee": "0xe2a3c9c99f" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 9, + "transaction_hash": "0x2f32394596d4bd1ddc5c7599ae53db8309893e1dbeadebaebb282763abcad27", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0x102c045c5259a4", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 21776, + "builtin_instance_counter": { + "bitwise_builtin": 6, + "keccak_builtin": 1, + "range_check_builtin": 1159, + "pedersen_builtin": 43, + "ec_op_builtin": 3, + "poseidon_builtin": 6 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 256 + }, + "total_gas_consumed": { + "l1_gas": 58, + "l1_data_gas": 256 + } + }, + "actual_fee": "0x102c045c5259a4" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 10, + "transaction_hash": "0xa62ee89e1402d61683d961a18e5820f42d061c9615022ada8b13c24202c688", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0x14e9784e726a5e", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 28192, + "builtin_instance_counter": { + "poseidon_builtin": 5, + "pedersen_builtin": 52, + "ec_op_builtin": 3, + "range_check_builtin": 1608 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 288 + }, + "total_gas_consumed": { + "l1_gas": 75, + "l1_data_gas": 288 + } + }, + "actual_fee": "0x14e9784e726a5e" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 11, + "transaction_hash": "0x5cc90d16fc214b41f79fb7e6eaa9d54c86c480bd575a2af7f4ad9dedba6276f", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0xdbdef3aab5", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 24762, + "builtin_instance_counter": { + "ec_op_builtin": 3, + "pedersen_builtin": 38, + "poseidon_builtin": 3, + "range_check_builtin": 1406 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 128 + }, + "total_gas_consumed": { + "l1_gas": 65, + "l1_data_gas": 128 + } + }, + "actual_fee": "0xdbdef3aab5" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 12, + "transaction_hash": "0x6753e208f73a868d74312420692d12e69751e40bcf89c021119c24490ece9ad", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0xcd3760ef9cd6c", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 17466, + "builtin_instance_counter": { + "pedersen_builtin": 34, + "range_check_builtin": 815, + "poseidon_builtin": 6, + "ec_op_builtin": 3 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 128 + }, + "total_gas_consumed": { + "l1_gas": 46, + "l1_data_gas": 128 + } + }, + "actual_fee": "0xcd3760ef9cd6c" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 13, + "transaction_hash": "0x41bdd5c64656ccc96115120b5b05215cc995f78b1587dca49feaf4aedca2631", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0x9838e32d91", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 16547, + "builtin_instance_counter": { + "range_check_builtin": 751, + "ec_op_builtin": 3, + "pedersen_builtin": 39, + "poseidon_builtin": 7 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 256 + }, + "total_gas_consumed": { + "l1_gas": 45, + "l1_data_gas": 256 + } + }, + "actual_fee": "0x9838e32d91" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 14, + "transaction_hash": "0x3d0d388f2810a550b11dc9f1ed6b747b3bcdbc5ba1f6c4e19a37e5360dea0f8", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "keys": [ + "0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4" + ], + "data": [ + "0x4b69423be6879cf6d118721dfecfab9d1afbab93c5706e6930c4bf3be81d791", + "0x3", + "0x49c8205ced269d1ced335d5c501e63ab4e44d98a0650fa927d280d3f7c36230", + "0x54948a4b82b56b98f1cb2043401028a428c78f3f6df737d3d3a2678e733dc3d", + "0x2293a32380507e57f9ef6bf716af36086f17cdfae9a369a52b2a17b1c2678d1" + ] + }, + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0x110227991b4c12", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 22573, + "builtin_instance_counter": { + "range_check_builtin": 1151, + "ec_op_builtin": 3, + "poseidon_builtin": 4, + "pedersen_builtin": 46 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 128 + }, + "total_gas_consumed": { + "l1_gas": 61, + "l1_data_gas": 128 + } + }, + "actual_fee": "0x110227991b4c12" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 15, + "transaction_hash": "0x71789cc9d5ea16b746d857265754d21fc0686d327f46d06ddee21fdd3ca88bb", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "keys": [ + "0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4" + ], + "data": [ + "0x212ff21302b29f74fcf5847ca85efb7ce2cc579fe69aa3ce1b234737faf2d66", + "0x3", + "0x6f01640f0164f58cc7dbcf8a97ed7a3eca7bf9014809d47aad40bff3390234a", + "0x246c45ebaed09c37ab7268e28f8d60cc8d5dffa102ba3823b1fcf285b6b4588", + "0x356d4583e6d8a026858ae2c2f7ee62a857f8373d8b8fd384220a17242af6b1a" + ] + }, + { + "from_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0x9838e32d91", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 16229, + "builtin_instance_counter": { + "ec_op_builtin": 3, + "poseidon_builtin": 6, + "pedersen_builtin": 49, + "range_check_builtin": 618, + "bitwise_builtin": 6, + "keccak_builtin": 1 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 256 + }, + "total_gas_consumed": { + "l1_gas": 45, + "l1_data_gas": 256 + } + }, + "actual_fee": "0x9838e32d91" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 16, + "transaction_hash": "0x397df33c7aca7521db3df0052454e9d673e2f9e855c922c3e1d4cd4d12fb2bc", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "keys": [ + "0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4" + ], + "data": [ + "0x3debf9d54b0e563b8fe4b64eedf699a24bd4bcf8b9071aa27e99f25c88ba961", + "0x3", + "0x87ed1ff492fe3875dd94b50e2a32f370fe02cf0e60b453b69d5fcf393d9c01", + "0x11ba08688015c45ad4415d1659dea6159a8df2935983bdc41b9b5613c55f886", + "0x7000994f2467389db1e940804a166053d3929fca4f14d04ed51330ee6a1f4ce" + ] + }, + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0xda999d63e40da", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 17613, + "builtin_instance_counter": { + "ec_op_builtin": 3, + "pedersen_builtin": 48, + "poseidon_builtin": 6, + "range_check_builtin": 729 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 256 + }, + "total_gas_consumed": { + "l1_gas": 49, + "l1_data_gas": 256 + } + }, + "actual_fee": "0xda999d63e40da" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 17, + "transaction_hash": "0x75e605c318963ca63a9355587cf82865227115327199a96e762c6dd7f032eed", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "keys": [ + "0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4" + ], + "data": [ + "0x5a84ba14f489e71466dbd10fbd54cb05450a0e2f38e2d99e3e587bc7cb63890", + "0x3", + "0x12dfd2e3413b429f95268d0d163b0fbef734358314ac2e77f6255c291c146dc", + "0x144934c01839b32d64d21da2c53bcba79bf55c170700b07090d86eaa1a3650e", + "0x7f1c2e64a60109d6681038d3994fea871d6507effc607342e7fef0c2d8e821d" + ] + }, + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0xe7fbd9d82b448", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 18962, + "builtin_instance_counter": { + "ec_op_builtin": 3, + "poseidon_builtin": 7, + "range_check_builtin": 968, + "pedersen_builtin": 44 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 384 + }, + "total_gas_consumed": { + "l1_gas": 52, + "l1_data_gas": 384 + } + }, + "actual_fee": "0xe7fbd9d82b448" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 18, + "transaction_hash": "0x3b2c54a4a0fb53dcb1d139fd66b0d33ef292599d5779d6fbc9869a3443b16d7", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "keys": [ + "0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4" + ], + "data": [ + "0x36a003b9f26f41a345836abb901c1a71fcaa586d174dea5fc1dce6b1cc5a145", + "0x3", + "0x344abe714959a0289fff2c0d988cda83ba46965603e7839225726fc9c34f4cb", + "0x3e4c1cb040c585a1b599031d44895054534683e9f03c41f14ef4ae3eeedf9ec", + "0x8d434813d65c2e95a9840421588b6888383f09a6dcfce99b1f2057c3625024" + ] + }, + { + "from_address": "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "keys": [ + "0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4" + ], + "data": [ + "0x41c145fd2ed46fc644e408743a12081e8809cd16a5f0de242f33da1aadd3436", + "0x3", + "0x30edb7c0d02cb69d2dc750909c6290fa6b562bace746368bbf994338fd84724", + "0x43d7fee256e3c65ec0b3e30f0237933c357a0731b74303939fac965e568cb78", + "0x3091b52f28583e2a23ca109b9c372e9eb0d5d976c8f17c9ebfd42f0dccdb669" + ] + }, + { + "from_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0x9b9ad42b06", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 15603, + "builtin_instance_counter": { + "pedersen_builtin": 55, + "range_check_builtin": 521, + "poseidon_builtin": 6, + "ec_op_builtin": 3 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 256 + }, + "total_gas_consumed": { + "l1_gas": 46, + "l1_data_gas": 256 + } + }, + "actual_fee": "0x9b9ad42b06" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 19, + "transaction_hash": "0x7765195b77c0eea821a8f807f8fa022d2484d3bc848d519ea689d97c4015bff", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "keys": [ + "0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4" + ], + "data": [ + "0x6ec2cddbfdacf4cbd0108e87bb889213d139ff2e9eadf68c81157a3f0c7e769", + "0x3", + "0x7057660cdbeb602d9094eb34650d362c0b0d89057bc9f49163501da7c552e1f", + "0x798891c19b8abaf6ee00f6a989eeea8cdfa76f3a4ad390fba68ecf9353fd687", + "0x5deebf68d35fe0b2fc0f89b6c96e6e8ad88883993f9ab8ad56570f8f02d6d2a" + ] + }, + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0xd623865a8ef60", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 17455, + "builtin_instance_counter": { + "pedersen_builtin": 45, + "ec_op_builtin": 3, + "poseidon_builtin": 5, + "range_check_builtin": 723 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 128 + }, + "total_gas_consumed": { + "l1_gas": 48, + "l1_data_gas": 128 + } + }, + "actual_fee": "0xd623865a8ef60" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 20, + "transaction_hash": "0x2d667c69935407d1482d8b0182ec02e5ec2cf71bbf6619f739dc8a0ae1e8b92", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0xabc1d0d5305a90", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 172752, + "builtin_instance_counter": { + "keccak_builtin": 1, + "poseidon_builtin": 7, + "bitwise_builtin": 30, + "range_check_builtin": 15325, + "ec_op_builtin": 3, + "pedersen_builtin": 37 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 256 + }, + "total_gas_consumed": { + "l1_gas": 616, + "l1_data_gas": 256 + } + }, + "actual_fee": "0xabc1d0d5305a90" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 21, + "transaction_hash": "0x4c93adbd1aa8f107be890556eba8a4071515d5510b6a93fd35ecda87fc6df80", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "keys": [ + "0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4" + ], + "data": [ + "0x720213ac76a0f3f2565f04f51c8d13f00878dadb125a59c9a3d3c846e0ee72d", + "0x3", + "0x65dcd1a3b2933e6f20f019a97de3272d0549bf793e41a0144a7d21bbdb2fcf0", + "0x8f260cdd6d8d7a9668d1bfa93136d12c15246e80975b8571e7d09c76207fbb", + "0x430cf4d69439b8d69afb49f3c44286d78ce666e924c3b99e3aecae688a30bc3" + ] + }, + { + "from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "keys": [ + "0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4" + ], + "data": [ + "0x11ebde260ce04bcbafc74879bd67c1aa39a50a2d3af027f407147e18a5ee20f", + "0x3", + "0x158db84882f02aab220d39d821e92dafb4db61c3fa65acc8b80c6b11f4afd30", + "0xd192afb935fdaf0a61c2ba39be015356ba32a25c839fdb6be44e771b43f1e", + "0x4336b1b67cd7bd5ac601308c72b02e27659a932373facd00ca73dcc7d45e880" + ] + }, + { + "from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "keys": [ + "0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4" + ], + "data": [ + "0x82e6948d4df169db1d3d53f528a78224467d356457dc61b1c19145fb7a60d2", + "0x3", + "0x1ae7558984ac06156913dc6992b2a5c1122598f49e6965c5f8a71210c6721ae", + "0x46707418ecb32d37b3c817a9c92884dcf4ded2bf98c756c255d7b8da05fd961", + "0x55316930897583852f858e6a8311efdfac9b026bcac1312a52dfe524ce4c3b5" + ] + }, + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0xe385be7afa24e", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 17485, + "builtin_instance_counter": { + "range_check_builtin": 789, + "bitwise_builtin": 6, + "keccak_builtin": 1, + "ec_op_builtin": 3, + "pedersen_builtin": 53, + "poseidon_builtin": 3 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 128 + }, + "total_gas_consumed": { + "l1_gas": 51, + "l1_data_gas": 128 + } + }, + "actual_fee": "0xe385be7afa24e" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 22, + "transaction_hash": "0x68a4d9bcff51d99fd3f5dc6df6e4902073cdf8d43575e3922f904d800517e8d", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0xadb5797dc16246", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 175942, + "builtin_instance_counter": { + "range_check_builtin": 15459, + "pedersen_builtin": 53, + "keccak_builtin": 1, + "poseidon_builtin": 9, + "bitwise_builtin": 30, + "ec_op_builtin": 3 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 480 + }, + "total_gas_consumed": { + "l1_gas": 623, + "l1_data_gas": 480 + } + }, + "actual_fee": "0xadb5797dc16246" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 23, + "transaction_hash": "0xe0f970f4ce407adef51a760559ee6ee74a4769758768b808097b520216230b", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "keys": [ + "0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4" + ], + "data": [ + "0x66e6852463ea25790fb91b17d81f3d94c2d29690ce5283a19d54503c93c03d4", + "0x3", + "0x47a7420476d121e7481da71e59fe5eac3e6e058175191aac84315ced6f5d101", + "0x203c2d2e3335474d659e032766de8c06a746175afabcbf6b21e49a2bc8d9565", + "0x2490dd8f87566f3ba033a272c9eebfc0f3feae6bf5149b71b4d14c4dc26dfd2" + ] + }, + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0xda9999100805a", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 18102, + "builtin_instance_counter": { + "range_check_builtin": 878, + "ec_op_builtin": 3, + "poseidon_builtin": 5, + "pedersen_builtin": 40 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 128 + }, + "total_gas_consumed": { + "l1_gas": 49, + "l1_data_gas": 128 + } + }, + "actual_fee": "0xda9999100805a" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 24, + "transaction_hash": "0x3d95cdb95afd14cbdb4c4669525e879dcb683baf81484a3e1f8d907153e53ed", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0xc44b3fd886bf8", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 16360, + "builtin_instance_counter": { + "range_check_builtin": 702, + "pedersen_builtin": 40, + "poseidon_builtin": 6, + "ec_op_builtin": 3 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 256 + }, + "total_gas_consumed": { + "l1_gas": 44, + "l1_data_gas": 256 + } + }, + "actual_fee": "0xc44b3fd886bf8" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 25, + "transaction_hash": "0x4f0afadd2870468cf005f56bebded204bae8515a4e70a0a2ef4a55367cfc205", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0xb272fa6b758b0", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 14687, + "builtin_instance_counter": { + "pedersen_builtin": 48, + "range_check_builtin": 557, + "ec_op_builtin": 3, + "poseidon_builtin": 8 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 416 + }, + "total_gas_consumed": { + "l1_gas": 40, + "l1_data_gas": 416 + } + }, + "actual_fee": "0xb272fa6b758b0" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 26, + "transaction_hash": "0x727effea1ae4e021bfa5435651f2ec0ddfc8d6c471f0e1948d89f00879ea099", + "l2_to_l1_messages": [ + { + "from_address": "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "to_address": "0xA0AdcE6dBaFf6bCE9f7a620A9ED209AA748A0b24", + "payload": [ + "0x9b971fe02819281443860767515bcfbd4a87795e973ae4c5f0da3f38b3fc78", + "0x138d2ff63ebe4cff9b97f36d9842f5784d1c14c77d552a9f202f700df99eb80" + ] + } + ], + "events": [ + { + "from_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0x174a03e3851bd", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 21123, + "builtin_instance_counter": { + "poseidon_builtin": 6, + "ec_op_builtin": 3, + "range_check_builtin": 982, + "pedersen_builtin": 52 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 288 + }, + "total_gas_consumed": { + "l1_gas": 28201, + "l1_data_gas": 288 + } + }, + "actual_fee": "0x174a03e3851bd" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 27, + "transaction_hash": "0x5a6591fddd64df4f57b64543c00a1bc788485b2f558056ea853548d3d1e9637", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "keys": [ + "0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4" + ], + "data": [ + "0x367d67d017a167d525cb8d18acd2b7aa354b96db81d60949ec7fb66c4f1f674", + "0x3", + "0x755c24b1b54061ed134fd9d6f0d910f166b1d134cafb9a1fbd62300b1eefa02", + "0x5daa8bcd0707512e3d7c6230d40198e0a7190009ae097f9b2e2963441560f3f", + "0x3acc6203b842ebd20e31109d66d8bc8ca2e55495bb4e3ceb90ab6b268fa8843" + ] + }, + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0xf55e0950de636", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 20369, + "builtin_instance_counter": { + "pedersen_builtin": 48, + "poseidon_builtin": 3, + "ec_op_builtin": 3, + "range_check_builtin": 934 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 128 + }, + "total_gas_consumed": { + "l1_gas": 55, + "l1_data_gas": 128 + } + }, + "actual_fee": "0xf55e0950de636" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 28, + "transaction_hash": "0x667247e8ae4537222be926e7d29001431251f70024836752c4cbe68a5377beb", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0x14903e4521bc158", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 274405, + "builtin_instance_counter": { + "ec_op_builtin": 3, + "pedersen_builtin": 44, + "range_check_builtin": 29383, + "poseidon_builtin": 5 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 256 + }, + "total_gas_consumed": { + "l1_gas": 1180, + "l1_data_gas": 256 + } + }, + "actual_fee": "0x14903e4521bc158" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 29, + "transaction_hash": "0xafdac29914cf6054190cf08c1a83acbbdc86a413690f40326b9aae545253e8", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0xfe4a35399a8ea", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 20802, + "builtin_instance_counter": { + "ec_op_builtin": 3, + "poseidon_builtin": 6, + "pedersen_builtin": 45, + "range_check_builtin": 1030 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 320 + }, + "total_gas_consumed": { + "l1_gas": 57, + "l1_data_gas": 320 + } + }, + "actual_fee": "0xfe4a35399a8ea" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 30, + "transaction_hash": "0x14786356d92d3359426657aba526e8e6bc3c6913beb2a06fd5a1af3254c8ca6", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0xe7fbd5844f3c8", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 19480, + "builtin_instance_counter": { + "bitwise_builtin": 6, + "range_check_builtin": 1056, + "poseidon_builtin": 5, + "ec_op_builtin": 3, + "keccak_builtin": 1, + "pedersen_builtin": 36 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 256 + }, + "total_gas_consumed": { + "l1_gas": 52, + "l1_data_gas": 256 + } + }, + "actual_fee": "0xe7fbd5844f3c8" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 31, + "transaction_hash": "0x644839d53b3e8e9d4690a19ab35f0564b249c58443774ffaa8e4db4a8890ee7", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "keys": [ + "0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4" + ], + "data": [ + "0x48ba4a09e3cfc54a0fb13826f9d9066f019db290b3ac4ca202f9e284013e38c", + "0x3", + "0x582a7beb60027e27dabc1a9e9b4746528535aae1c47ea1a2224fcfed00ea52c", + "0x51eadf84f9e6df0d7079bb184cb44e34bb311edcc62d1e94d5b1ac2f1d6b8a3", + "0x2c08e60b9a4f7106c503b13b490fbff384b07726e0e156ac27563ff05114b20" + ] + }, + { + "from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "keys": [ + "0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4" + ], + "data": [ + "0x47b42da4835595cf4cfd06826eb76ed95ea8dc2f777b0c4acd2e0809e6680fe", + "0x3", + "0x4333048345c017b97d18648e47c5fc51e8ab6127ed22f6eb1cc810c6163f6db", + "0x203aed1de52fb8f7f43524752d45bea702df6f2ace6e5dac195de918fce2133", + "0x316385dc04628c6b11a08b31006343bc98580278ced84ddf620e9738d69b055" + ] + }, + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0xf0e7faef415bc", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 18899, + "builtin_instance_counter": { + "pedersen_builtin": 55, + "poseidon_builtin": 6, + "range_check_builtin": 765, + "ec_op_builtin": 3 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 256 + }, + "total_gas_consumed": { + "l1_gas": 54, + "l1_data_gas": 256 + } + }, + "actual_fee": "0xf0e7faef415bc" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 32, + "transaction_hash": "0x7f32793534b160cdc40e4ce20a8709adfa9bdd0b5860013698fc754b4103542", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "keys": [ + "0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4" + ], + "data": [ + "0xba435eb69d3226f365880885b2ce8596ba44ae0821dc9f8dc7907d14a282b", + "0x3", + "0x40a013b398bee56959eefd6c4edcc4675872dcf412ca5065a6f7c413b717732", + "0x371a8adc1170613db866c390fb96e780d1a5c36cfa7f970724ff5e1b0a5675a", + "0x287a7a8fba7421005c45b0f98e0d9605ae017e9bfb4b837c23bda6df6549787" + ] + }, + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0xaaa44be2945628", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 171628, + "builtin_instance_counter": { + "bitwise_builtin": 30, + "pedersen_builtin": 39, + "ec_op_builtin": 3, + "range_check_builtin": 15207, + "poseidon_builtin": 3, + "keccak_builtin": 1 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 128 + }, + "total_gas_consumed": { + "l1_gas": 612, + "l1_data_gas": 128 + } + }, + "actual_fee": "0xaaa44be2945628" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 33, + "transaction_hash": "0x642146ccbb341535e2f4f7aa82ad34ab2d0dd6bcc5d98f6e9485638b67a6d", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "keys": [ + "0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4" + ], + "data": [ + "0x51814831a2493c60497a96034f00d3e72c1ca7b071631c1cd873c0e7b46f42", + "0x3", + "0x79f3c4cf6a5ecf86c3b4ffedbde7b884f61b408085a07f7e3f8a1c73dcd6792", + "0x1f282d7be25fe585523745afba8f5ef4bcd9e8eade41b3fe25d8786b6b5fe98", + "0x415081db9ad19aa0e2173ba93d99d0d6ed9a48385fbedb24c7c81dd18eed394" + ] + }, + { + "from_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0xc4315cbc82", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 21438, + "builtin_instance_counter": { + "ec_op_builtin": 3, + "range_check_builtin": 928, + "poseidon_builtin": 4, + "pedersen_builtin": 50 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 128 + }, + "total_gas_consumed": { + "l1_gas": 58, + "l1_data_gas": 128 + } + }, + "actual_fee": "0xc4315cbc82" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 34, + "transaction_hash": "0x72d70c0f1ab91afa262e842a6f3f8a98dd658da565c7279364999314ccbed5c", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0x91750132a7", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 15391, + "builtin_instance_counter": { + "poseidon_builtin": 6, + "pedersen_builtin": 44, + "ec_op_builtin": 3, + "range_check_builtin": 527 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 256 + }, + "total_gas_consumed": { + "l1_gas": 43, + "l1_data_gas": 256 + } + }, + "actual_fee": "0x91750132a7" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 35, + "transaction_hash": "0x214d0a540e7b03414772c2c2de426eb5d4e4ad63668b6b81c35c0b2b2d6bcb4", + "l2_to_l1_messages": [ + { + "from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "to_address": "0xf40fBAA08BfABcd6fB1A0Ec3ea1fD8D0CdbAf82a", + "payload": [ + "0x48c560eca37e048d7cb12b7ef2ea65d5e34a9b79a0379a1644939f7b9bf3f7c", + "0x1d65cca89665e33658632b26a178c617b6e6d6b34c687244a94e89202b407f5" + ] + } + ], + "events": [ + { + "from_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0x17499796232d3", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 20168, + "builtin_instance_counter": { + "poseidon_builtin": 4, + "pedersen_builtin": 45, + "ec_op_builtin": 3, + "range_check_builtin": 926 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 128 + }, + "total_gas_consumed": { + "l1_gas": 28199, + "l1_data_gas": 128 + } + }, + "actual_fee": "0x17499796232d3" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 36, + "transaction_hash": "0x3aeb0a48ba255a5aae097ebdcead737a46ee6a768ada5dea2956aa2446107eb", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0xa5c0a72365", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 18347, + "builtin_instance_counter": { + "pedersen_builtin": 36, + "poseidon_builtin": 6, + "ec_op_builtin": 3, + "range_check_builtin": 902 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 256 + }, + "total_gas_consumed": { + "l1_gas": 49, + "l1_data_gas": 256 + } + }, + "actual_fee": "0xa5c0a72365" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 37, + "transaction_hash": "0x4b6c706b4a3038b41519a3dd6d0f5e8bc18d8425a1df493fb5de747558636c8", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "keys": [ + "0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4" + ], + "data": [ + "0x45697840297d58b4a4d5a5409c5ff698e080a7202bac696cac7997ab35909e4", + "0x3", + "0xb1cbd90586a7512eb49e81f604bc9cc37387dfa9be668cdbea1117690ae3a7", + "0x46cd6cfafefae479a5c3c9f5f1ab86edab3f252d6d0e13442cd648c541408de", + "0x588192bee153ea941a778fa2f6be1212d995437e93954b86d7b2e7995611994" + ] + }, + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0xe385c2ced62ce", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 18983, + "builtin_instance_counter": { + "poseidon_builtin": 5, + "range_check_builtin": 965, + "pedersen_builtin": 42, + "ec_op_builtin": 3 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 256 + }, + "total_gas_consumed": { + "l1_gas": 51, + "l1_data_gas": 256 + } + }, + "actual_fee": "0xe385c2ced62ce" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 38, + "transaction_hash": "0x1f6fa1f89da0df7a186bacfd78e91b95d88f057a513e1214f8ff0a732de30f4", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "keys": [ + "0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4" + ], + "data": [ + "0x2d11bb5170a1f928b6ecd7b97e025a491a5cb5fc4855eb496e07835dff04487", + "0x3", + "0x692e616a28746075cb8a6e660f951cc842f43fc5a2030fa13a27bf7a41b179b", + "0x2ef606af2baf35a9e60c618328075b4d309765e55c336ce29d79d3a3c5566ce", + "0x12159a449f1a0c82c83906dd424f34f8b3e00073a67668a814cd9c1940167ce" + ] + }, + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0xb272f9567e890", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 14274, + "builtin_instance_counter": { + "range_check_builtin": 563, + "poseidon_builtin": 7, + "ec_op_builtin": 3, + "pedersen_builtin": 45 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 384 + }, + "total_gas_consumed": { + "l1_gas": 40, + "l1_data_gas": 384 + } + }, + "actual_fee": "0xb272f9567e890" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 39, + "transaction_hash": "0x5d7941297f3232c0a98bd8e0b51d5d2464e97057147d06a0c41a07203c639ac", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "keys": [ + "0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4" + ], + "data": [ + "0x55cca0b45c9c4cee79718132afc5c4d2d1f4d029a29efc66b464e9209199af3", + "0x3", + "0x693aff98f855195256320c1744b36988e5efb7544af094f0234f5102b6fedc", + "0x68f7ccc05e42591293a68372d8cce749527e66804a036b22a0b14098b862218", + "0x282e2b68eb812129b5b2305aa4e1a45348ea41ba2bf9ab46d541b91d8ddafb4" + ] + }, + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0xa9ce290da8047a", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 169544, + "builtin_instance_counter": { + "ec_op_builtin": 3, + "poseidon_builtin": 8, + "range_check_builtin": 15135, + "keccak_builtin": 1, + "pedersen_builtin": 42, + "bitwise_builtin": 30 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 448 + }, + "total_gas_consumed": { + "l1_gas": 609, + "l1_data_gas": 448 + } + }, + "actual_fee": "0xa9ce290da8047a" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 40, + "transaction_hash": "0x323977511f652a2c494d4b7ef52b713d20ba702c7edf1fd1495a5b7fcb9b44b", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "keys": [ + "0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4" + ], + "data": [ + "0x666c83f59b7389bac9789070aee65ace9e99ed5f4ffcb86a4d8aba7d338c98b", + "0x3", + "0x7b5b27757a05f6bb78487984f7a96e15a18c6053b4657886f5e4e6f91178f0f", + "0x33695f320ce6d43202b522fa2d92c6e34118f960a0d9edb25ed15910682f596", + "0x1e21d486fabbba4261dd3f6ac5148571bd250983730dee61ab8631afed8d89" + ] + }, + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0xb272f0aec6790", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 14795, + "builtin_instance_counter": { + "range_check_builtin": 480, + "pedersen_builtin": 43, + "ec_op_builtin": 3, + "poseidon_builtin": 3 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 128 + }, + "total_gas_consumed": { + "l1_gas": 40, + "l1_data_gas": 128 + } + }, + "actual_fee": "0xb272f0aec6790" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 41, + "transaction_hash": "0x2c0957019f8956130340acd8c96bc5c93a03a3045cf90dd50b70d580377b61d", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0xf64b7380d71", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 268748, + "builtin_instance_counter": { + "poseidon_builtin": 5, + "ec_op_builtin": 3, + "pedersen_builtin": 36, + "range_check_builtin": 29038 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 256 + }, + "total_gas_consumed": { + "l1_gas": 1165, + "l1_data_gas": 256 + } + }, + "actual_fee": "0xf64b7380d71" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 42, + "transaction_hash": "0x570a47e2a3aab957dd3d09f8fe778ccb54163bc4207585d3f1e7ad471197f1c", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "keys": [ + "0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4" + ], + "data": [ + "0x49d389ff8457b29a69c3d57c0450dc56b1406b9e822f08f88b6ff7fa11627e9", + "0x3", + "0x52afc8740c79463d83b7628c35dddd807f6d2858d860752f980000e87d8d854", + "0x6f6a828242385c55eb76bb6c4f896492a91980e2551ccee675f7c6dfe79956a", + "0x575b2db2490f75d6877f64f23cc14589958b4cf31da2c65d9663c6dcb656a23" + ] + }, + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0xd623865a8ef60", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 17446, + "builtin_instance_counter": { + "ec_op_builtin": 3, + "range_check_builtin": 721, + "pedersen_builtin": 45, + "poseidon_builtin": 5 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 128 + }, + "total_gas_consumed": { + "l1_gas": 48, + "l1_data_gas": 128 + } + }, + "actual_fee": "0xd623865a8ef60" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 43, + "transaction_hash": "0x2cd6a8aea2b82b7e37d30451074c298e03c377feb90999c4fcdacf99ed46f97", + "l2_to_l1_messages": [ + { + "from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "to_address": "0x2EAe5B0fE2112b79ECef02b30243eE9a7CCE0eBE", + "payload": [ + "0x11f17e586559af18b7e5beeb3fe68587e7e69f0b336079f9e3d03fa0343c783", + "0x82a221fd714f879773458cfc0df8b8c2d5798ed9e57fb2afc3cc1c485e6f1c" + ] + } + ], + "events": [ + { + "from_address": "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "keys": [ + "0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4" + ], + "data": [ + "0x3ef516eb44f7a25907ebee82d2eed55a2b26882cb684da9a0b1358fe0672e12", + "0x3", + "0x1bfa88a6d84994c4cff5dec7d8e3aaa205b28b7bcfb7e5583f33508ee92b17b", + "0x50a25225519d91ba161f48cad22cb84d48d5108c43665c0cd5d3a3ece0946b2", + "0x23e92483a133a6aef2ec70e9faf85ae1afb61138bf385a28cf0281610bc4e86" + ] + }, + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0x1eb89415af45396c", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 22821, + "builtin_instance_counter": { + "range_check_builtin": 1155, + "ec_op_builtin": 3, + "pedersen_builtin": 50, + "poseidon_builtin": 3 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 128 + }, + "total_gas_consumed": { + "l1_gas": 28206, + "l1_data_gas": 128 + } + }, + "actual_fee": "0x1eb89415af45396c" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 44, + "transaction_hash": "0x5e3470f9a6a059d2190685fb82ca05eeea79bcba70b591130aff661cd5fb828", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "keys": [ + "0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4" + ], + "data": [ + "0x5b6036498212930c0160795ee17255fb94291ff053251b855b6da5d97b74531", + "0x3", + "0x40a8bcf47285adcb19628e0480e1057968b655ae8ecde24ffd7086070b5b9a2", + "0x3e1e8cf3b705f1039bee876a6a72988c59ebace9186ab399dae1c3f8b76b6fd", + "0x383afa7ce58c752b62f44f4f86446226b2246731ecb15296971731882c10f3" + ] + }, + { + "from_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0xb6a998c6ae", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 19476, + "builtin_instance_counter": { + "range_check_builtin": 767, + "poseidon_builtin": 3, + "ec_op_builtin": 3, + "pedersen_builtin": 53 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 128 + }, + "total_gas_consumed": { + "l1_gas": 54, + "l1_data_gas": 128 + } + }, + "actual_fee": "0xb6a998c6ae" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 45, + "transaction_hash": "0x3c78d2cab2fc776e2dcccf55ecbbd480b9484953a8be01b8c0306f88b2ee774", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0xa5c16a7365", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 18213, + "builtin_instance_counter": { + "pedersen_builtin": 42, + "ec_op_builtin": 3, + "poseidon_builtin": 7, + "range_check_builtin": 852 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 384 + }, + "total_gas_consumed": { + "l1_gas": 49, + "l1_data_gas": 384 + } + }, + "actual_fee": "0xa5c16a7365" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 46, + "transaction_hash": "0x2f8a9ceebe94631c2a75b078731515cee0e5ca12d2729575dc7d932f66593b6", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "keys": [ + "0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4" + ], + "data": [ + "0x37b72967ee34e9b00c45a6c1319ba8d28def41e60c8e0bbf91d440dedbf3a44", + "0x3", + "0x2e0afc0b8bdbc766d2d58ec64f78a0fc82c4f73abaff128c10005bb6a625475", + "0x7a945a82f362f478cda98c5c2952dbd9d8d805f5f02b211bba7e3299f261979", + "0x46aef08ffafe9b3e7644623e58f73dcf148fcf483a3fc9779836260bf576377" + ] + }, + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0x97ae84c1cc234", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 12228, + "builtin_instance_counter": { + "poseidon_builtin": 5, + "pedersen_builtin": 41, + "range_check_builtin": 435, + "ec_op_builtin": 3 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 256 + }, + "total_gas_consumed": { + "l1_gas": 34, + "l1_data_gas": 256 + } + }, + "actual_fee": "0x97ae84c1cc234" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 47, + "transaction_hash": "0x65949106a60aa0465ccc50dfa41676fbef444c94b051b08248653e443f9532f", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "keys": [ + "0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4" + ], + "data": [ + "0x49083c6dbeada5ca48496d10c5b5fc879a66cfe2106edb7ad133c47089a461d", + "0x3", + "0x4e39b2f0a8f28116d4bcb252009dc6f9f99582801bb9a0d9338e69e572675c4", + "0x33fc55ab493b435eddc00987bc0587689ded268a82ffc6d41e32d32f4e18ea5", + "0x6f2747503b85199bef9ab777e17ee34bf358726cc1b9440d1a1c439ffeadaf8" + ] + }, + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0xf55e142284776", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 20039, + "builtin_instance_counter": { + "range_check_builtin": 907, + "ec_op_builtin": 3, + "pedersen_builtin": 64, + "poseidon_builtin": 9 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 448 + }, + "total_gas_consumed": { + "l1_gas": 55, + "l1_data_gas": 448 + } + }, + "actual_fee": "0xf55e142284776" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 48, + "transaction_hash": "0x7c31171221dce0134eaed898eedef9a9283c46007d5a7205cbefb60bfdfdeae", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0xa25eb625f0", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 17863, + "builtin_instance_counter": { + "poseidon_builtin": 5, + "ec_op_builtin": 3, + "range_check_builtin": 792, + "pedersen_builtin": 40 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 256 + }, + "total_gas_consumed": { + "l1_gas": 48, + "l1_data_gas": 256 + } + }, + "actual_fee": "0xa25eb625f0" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 49, + "transaction_hash": "0x57dc37799d80e5a4325b44b272177af28259afe4a08d9e035fcaa7463c78d1", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0xb10e06c7725c9e", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 178910, + "builtin_instance_counter": { + "poseidon_builtin": 4, + "range_check_builtin": 15777, + "pedersen_builtin": 39, + "ec_op_builtin": 3, + "bitwise_builtin": 30, + "keccak_builtin": 1 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 128 + }, + "total_gas_consumed": { + "l1_gas": 635, + "l1_data_gas": 128 + } + }, + "actual_fee": "0xb10e06c7725c9e" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 50, + "transaction_hash": "0x5b112706c56d0e776f2074dac9622796190c46c460f6d3f7e21848a0f823564", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0xb6e907b81b90a", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 15562, + "builtin_instance_counter": { + "range_check_builtin": 727, + "ec_op_builtin": 3, + "pedersen_builtin": 35, + "poseidon_builtin": 6 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 256 + }, + "total_gas_consumed": { + "l1_gas": 41, + "l1_data_gas": 256 + } + }, + "actual_fee": "0xb6e907b81b90a" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 51, + "transaction_hash": "0x2805277fab3bf13cabea921219a291b59f5c976c576b17880bbc6420df1d948", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0xc0cf6bbf0d", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 21508, + "builtin_instance_counter": { + "ec_op_builtin": 3, + "poseidon_builtin": 3, + "pedersen_builtin": 38, + "range_check_builtin": 1167 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 128 + }, + "total_gas_consumed": { + "l1_gas": 57, + "l1_data_gas": 128 + } + }, + "actual_fee": "0xc0cf6bbf0d" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 52, + "transaction_hash": "0x8b6c4271730d086c0c63000fa2cc756f6915ce9d4c949aa03a3675f265d4c8", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0xec71ec8da4542", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 19428, + "builtin_instance_counter": { + "ec_op_builtin": 3, + "range_check_builtin": 890, + "pedersen_builtin": 45, + "poseidon_builtin": 8 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 384 + }, + "total_gas_consumed": { + "l1_gas": 53, + "l1_data_gas": 384 + } + }, + "actual_fee": "0xec71ec8da4542" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 53, + "transaction_hash": "0xbdac2ee80cd888998e3233d2ad3d8760f58582d82fce9b6272d3177d9d7dea", + "l2_to_l1_messages": [ + { + "from_address": "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "to_address": "0xa1b72fcd5be6af767d745199F73Dbfb425B34A60", + "payload": [ + "0x295e81336118da80d9deef4f5c67272f2195f7bfaf175a387ea1dbd50d9f5c6", + "0x94a852b9c75eed97c3458c1b4a3916fbe40eebfbe6f36f494881b89e98e0f7" + ] + } + ], + "events": [ + { + "from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "keys": [ + "0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4" + ], + "data": [ + "0x1acb1a91d60fdc1fc1c8403949e8f97c6066de26be3cd4ee7b0b0d44f5e8441", + "0x3", + "0x7f98353f5a29ef95702930c304c98b14ccca62c82dbc49e2dc14c3c6c6191d7", + "0xe6d48809cc6e0cf670c0f05aae20747c3e5a4ea0c619d465f296dd05946ccf", + "0x400c16a3b7f0a2fd2575962c75beb90376defce72ed3d206d17327884e21b6e" + ] + }, + { + "from_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0x1746a1ef7a66d", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 14418, + "builtin_instance_counter": { + "range_check_builtin": 485, + "ec_op_builtin": 3, + "poseidon_builtin": 5, + "pedersen_builtin": 50 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 256 + }, + "total_gas_consumed": { + "l1_gas": 28185, + "l1_data_gas": 256 + } + }, + "actual_fee": "0x1746a1ef7a66d" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 54, + "transaction_hash": "0x715b99aec587534547d4e33e0816e40129342404dcdb7b2f6cb5d75976f6595", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0xd6238bc362000", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 17743, + "builtin_instance_counter": { + "ec_op_builtin": 3, + "range_check_builtin": 741, + "pedersen_builtin": 50, + "poseidon_builtin": 5 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 288 + }, + "total_gas_consumed": { + "l1_gas": 48, + "l1_data_gas": 288 + } + }, + "actual_fee": "0xd6238bc362000" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 55, + "transaction_hash": "0x4364ff805b7cab23338929dc8927ae982f74b8b5970dda00f36ca97eb1deb28", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "keys": [ + "0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4" + ], + "data": [ + "0x7ce989b0419ef8fe25e6840faa1c773d72ba3348c55180662748e63a105a786", + "0x3", + "0xc7f6f73697f21eac88b7d95deeaf48acc8aec543a90b64b00bb1902660b57b", + "0x146b1e6617de03414d6b766339c823f4f0b090b8a383d4c3bc8371e1e9b2729", + "0x5b72ae12e06513fcd37083cca27aa83898b8a1064fb7c936d1bf93517fa1e22" + ] + }, + { + "from_address": "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "keys": [ + "0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4" + ], + "data": [ + "0x77005947a2dad7aa2389374892cc3d719571b33229bbe1bd16aac13b22fa1b0", + "0x3", + "0x2b73e559128d2c78c1e9d8c5a54f4cf7ed878f19af1bf70909d1f87124da7ba", + "0x3dd38cbf00e2d583d5bbce77623c3ac3cd5461710a2b2e78045c12078e9976f", + "0x5aef01d048765fd2b399b15a0fa4414254f1dfb22caf535b489beea48ed9079" + ] + }, + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0xac50932bdf7c84", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 173484, + "builtin_instance_counter": { + "range_check_builtin": 15311, + "poseidon_builtin": 5, + "pedersen_builtin": 50, + "bitwise_builtin": 30, + "ec_op_builtin": 3, + "keccak_builtin": 1 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 256 + }, + "total_gas_consumed": { + "l1_gas": 618, + "l1_data_gas": 256 + } + }, + "actual_fee": "0xac50932bdf7c84" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 56, + "transaction_hash": "0x77a8d43ca8fd40069f884b7773577d63fa954065c3b1a1daa421dfa87ec6afa", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x65cdd7892656f7f89887c2c84bb3cea8f8c1b472a4f61838496c1fc7cc8733b", + "keys": [ + "0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4" + ], + "data": [ + "0x3fe2ae4b30012d46c1f883db48c2d54cea76abf6b5870adbf4a3f8de97fe84c", + "0x3", + "0x48cbfaaa29757c20f9bd898aa285b66b049876d67b47424176e945ffb6cbb73", + "0x188896a20fbe98a0fe8e35cdac9d3ac809260de7288331c1901b8a0241eb050", + "0x4edb416bd209c871e52843ae78bacdb9347ba0bb25449f125bb78af1d34ce7f" + ] + }, + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0xe7fbd699463e8", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 19157, + "builtin_instance_counter": { + "ec_op_builtin": 3, + "range_check_builtin": 781, + "pedersen_builtin": 57, + "poseidon_builtin": 5 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 288 + }, + "total_gas_consumed": { + "l1_gas": 52, + "l1_data_gas": 288 + } + }, + "actual_fee": "0xe7fbd699463e8" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 57, + "transaction_hash": "0x58177e246ff04b9b229a68910a374605766a298254e357b30aaeb8edaf9d66d", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "keys": [ + "0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4" + ], + "data": [ + "0x699baf12807140f31ae31552b26bcdfa9d5abd2cdfe25a6505452f0bbdd31c1", + "0x3", + "0x429ca58b9b7d74ffdf0f2834eb13881bc3133027694c42076b31dad26f5583b", + "0x4c055756c36807649f3c6b403313cc82db56c8f303ede8ecb2b8861c67f255e", + "0x31da6141fcf54cc7595791dfa3cd1aeedb2062955de755c370c26ef111e1791" + ] + }, + { + "from_address": "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "keys": [ + "0x15bd0500dc9d7e69ab9577f73a8d753e8761bed10f25ba0f124254dc4edb8b4" + ], + "data": [ + "0x557e86f7dbca848da70ca314e09d4c2d3aa0ffce4c595172b2d41e78632f837", + "0x3", + "0x7cc095ee2c4c6cb238c19bd2267a7cded49f8ac8ce6f8de22acdf9c1d736e1f", + "0x69f642da1980792daf9890e7f76966f9addeaebfe0150f2a264f4fe4e17ed10", + "0x37301f8848d498baa6088a9da64b9a58bb557d4035367bcb1e69a24b67df765" + ] + }, + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0x9c249323692ae", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 11907, + "builtin_instance_counter": { + "pedersen_builtin": 45, + "poseidon_builtin": 3, + "ec_op_builtin": 3, + "range_check_builtin": 368 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 128 + }, + "total_gas_consumed": { + "l1_gas": 35, + "l1_data_gas": 128 + } + }, + "actual_fee": "0x9c249323692ae" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 58, + "transaction_hash": "0x1f55ed06d78117d417899bd94eda790bea602379e1c43f8b86d859d92eff38", + "l2_to_l1_messages": [ + { + "from_address": "0x5e4cecd764121b8547d6e0ebec94618edc0933f97918af264d4d7064e70dc36", + "to_address": "0x9CdF07d5726BC54bf908beE8CAED3D3ECc5263fF", + "payload": [ + "0x4066ebb426311bfe53ab1580e14fb2379a5d7d610695c9b05d11beb2c444376", + "0x8d380443209a3ec5875d5e25d361936b3b75cd45d39f1ad5dc7f4e601b179e" + ] + } + ], + "events": [ + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4136ff8eb3070b7141dccfd95e248ec747a904433449f3ea9e80664719c0f8a", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0x1eb72f301bcd250a", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 21162, + "builtin_instance_counter": { + "poseidon_builtin": 6, + "pedersen_builtin": 47, + "ec_op_builtin": 3, + "range_check_builtin": 1060 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 256 + }, + "total_gas_consumed": { + "l1_gas": 28201, + "l1_data_gas": 256 + } + }, + "actual_fee": "0x1eb72f301bcd250a" + } + ], + "starknet_version": "0.13.2" +} diff --git a/crates/starknet_client/resources/reader/block_post_0_13_3.json b/crates/starknet_client/resources/reader/block_post_0_13_3.json index dac44f7e4da..049d98e778e 100644 --- a/crates/starknet_client/resources/reader/block_post_0_13_3.json +++ b/crates/starknet_client/resources/reader/block_post_0_13_3.json @@ -6059,4 +6059,4 @@ } ], "starknet_version": "0.13.3" -} \ No newline at end of file +} diff --git a/crates/starknet_client/resources/reader/block_post_0_13_4.json b/crates/starknet_client/resources/reader/block_post_0_13_4.json new file mode 100644 index 00000000000..a0464e3c467 --- /dev/null +++ b/crates/starknet_client/resources/reader/block_post_0_13_4.json @@ -0,0 +1,340 @@ +{ + "block_hash": "0xdaf586a70f9c09289b920fa2914bd3fb8c92d034e382afa834ecf2cce24929", + "parent_block_hash": "0x10a6d52171db8f41abbd27f522beeaa2b1f8406473937a7a8626ac8e6cc9bd1", + "block_number": 64820, + "state_root": "0x7d8e10d62a5945de816b82b626cb2131c008539f324b410244a75c2cc368472", + "transaction_commitment": "0x1b7dbe66c42f8d90e0d12a41500122774b94014a23474ee98dd77626f8c785e", + "event_commitment": "0x7047a5e649af66a6c3d6081e88c80ea9c9a98070fc2e1689f98458c099c978a", + "receipt_commitment": "0x8684350ddac79aedd60b66ff3cd03c96cb92b981b48db9d0436ceeb9873f48", + "state_diff_commitment": "0x254e3f6ed4b8eebc182caa6c994634bf28ba870264e284d7f77f5aa2b394b1b", + "state_diff_length": 14, + "status": "ACCEPTED_ON_L2", + "l1_da_mode": "BLOB", + "l1_gas_price": { + "price_in_wei": "0x58fe7705c", + "price_in_fri": "0xa4277658199c" + }, + "l1_data_gas_price": { + "price_in_wei": "0xf00cef70", + "price_in_fri": "0x1bac93100f36" + }, + "l2_gas_price": { + "price_in_wei": "0x91ced", + "price_in_fri": "0x10cf33d99" + }, + "transactions": [ + { + "transaction_hash": "0x45a51f77d38e6f7eab91d0545e812a3d6b60a806b38907746eeea2c327f5fec", + "version": "0x3", + "signature": [ + "0x2ded30230942a00ae16f9472046e2d7f2779a3ea02c3bf5776f064f799d817e", + "0x563f9aff4f808b0edf5a526b17b34d4e0fa4ae06783c274fc498b2728f66386" + ], + "nonce": "0xe72", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_DATA_GAS": { + "max_amount": "0x186a0", + "max_price_per_unit": "0x2d79883d20000" + }, + "L1_GAS": { + "max_amount": "0x186a0", + "max_price_per_unit": "0x2d79883d20000" + }, + "L2_GAS": { + "max_amount": "0x5f5e100", + "max_price_per_unit": "0xba43b7400" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x745d525a3582e91299d8d7c71730ffc4b1f191f5b219d800334bc0edad0983b", + "calldata": [ + "0x2", + "0x4138fd51f90d171df37e9d4419c8cdb67d525840c58f8a5c347be93a1c5277d", + "0x3604cea1cdb094a73a31144f14a3e5861613c008e1e879939ebc4827d10cd50", + "0x5", + "0x5d4f123c53c7cfe4db2725ff77f52b7cc0293115175c4a6ae26b931bb33c973", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0x15bbb8880e6edfef67f7fbcc2bd28c0e207c1df789c7ace4154257286cf704e", + "0x15824a49f8ce20b648a699c458cabf255363919efe34055c5dcf791ebc19923", + "0x28c62efb55444e72ba017fd975177c3960fc62a1c213713691dff28c0a81424", + "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", + "0x5", + "0x4138fd51f90d171df37e9d4419c8cdb67d525840c58f8a5c347be93a1c5277d", + "0x1a8e87e9d2008fcd3ce423ae5219c21e49be18d05d72825feb7e2bb687ba35c", + "0x2", + "0x71fcc19d63d870b8ac3d826e878cd752", + "0x93bb0859cc1a97cf8e44963d6a80314" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x20a6b5bc2fcd7c4fa68583c5714ac997da6aa512453f2dcd321ac83c402aabf", + "version": "0x3", + "signature": [ + "0x17772d362ff7d8f731cc7bca9622d8447c999695de7f6105dcd86215762eae5", + "0x446d7ede989c747dc10adf07eb6126c9b468f9b6b2685239c9cccefca74abaf" + ], + "nonce": "0xe73", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_DATA_GAS": { + "max_amount": "0x186a0", + "max_price_per_unit": "0x2d79883d20000" + }, + "L1_GAS": { + "max_amount": "0x186a0", + "max_price_per_unit": "0x2d79883d20000" + }, + "L2_GAS": { + "max_amount": "0x5f5e100", + "max_price_per_unit": "0xba43b7400" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x745d525a3582e91299d8d7c71730ffc4b1f191f5b219d800334bc0edad0983b", + "calldata": [ + "0x2", + "0x28c62efb55444e72ba017fd975177c3960fc62a1c213713691dff28c0a81424", + "0x27a4a7332e590dd789019a6d125ff2aacd358e453090978cbf81f0d85e4c045", + "0x2", + "0x3b360f46f5cca30d75a45d67c0a241bd4532412cf2bc75a19894e20e634576a", + "0x1b9b9d909de78c8e87f3460a59aa0a879a5ae5d0b0743295570fa7e47808a3d", + "0x28c62efb55444e72ba017fd975177c3960fc62a1c213713691dff28c0a81424", + "0x169f135eddda5ab51886052d777a57f2ea9c162d713691b5e04a6d4ed71d47f", + "0x4", + "0x5d4f123c53c7cfe4db2725ff77f52b7cc0293115175c4a6ae26b931bb33c973", + "0x7fadf2f7649d8b2e3d436a18aa825fbde7f34ccf07898fd7329ce06f892a4fa", + "0x0", + "0x0" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x3b7869de77438959db61644b709bd771fce950ae22d9cc583153e39183e0efe", + "version": "0x3", + "signature": [ + "0x4ebd6fb71da4338b2d8ec234accd0bd667f3ae5d10982d5a03412e92314dab6", + "0x44bd872c4b475af7c586905221655b9d74926845c4084f6c31a66397efcca0d" + ], + "nonce": "0xe74", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_DATA_GAS": { + "max_amount": "0x186a0", + "max_price_per_unit": "0x2d79883d20000" + }, + "L1_GAS": { + "max_amount": "0x186a0", + "max_price_per_unit": "0x2d79883d20000" + }, + "L2_GAS": { + "max_amount": "0x5f5e100", + "max_price_per_unit": "0xba43b7400" + } + }, + "tip": "0x0", + "paymaster_data": [], + "sender_address": "0x745d525a3582e91299d8d7c71730ffc4b1f191f5b219d800334bc0edad0983b", + "calldata": [ + "0x1", + "0x28c62efb55444e72ba017fd975177c3960fc62a1c213713691dff28c0a81424", + "0x382be990ca34815134e64a9ac28f41a907c62e5ad10547f97174362ab94dc89", + "0x0" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x21d28c5d64ddc242cb6337b07bff970425fc2173245660580b705c0afb4a90d", + "version": "0x1", + "max_fee": "0x11c37937e08000", + "signature": [ + "0x790c36229fac8a6bab2fb2892de6100fcbfe965079d5434354e3ba22191ab20", + "0x6d588d2c9ac82bfe07176b1cd79df19836144d1cb7eba3e3b14b1cd252449cb" + ], + "nonce": "0xe75", + "sender_address": "0x745d525a3582e91299d8d7c71730ffc4b1f191f5b219d800334bc0edad0983b", + "calldata": [ + "0x1", + "0x4138fd51f90d171df37e9d4419c8cdb67d525840c58f8a5c347be93a1c5277d", + "0x2468d193cd15b621b24c2a602b8dbcfa5eaa14f88416c40c09d7fd12592cb4b", + "0x0" + ], + "type": "INVOKE_FUNCTION" + } + ], + "timestamp": 1736860560, + "sequencer_address": "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "transaction_receipts": [ + { + "execution_status": "SUCCEEDED", + "transaction_index": 0, + "transaction_hash": "0x45a51f77d38e6f7eab91d0545e812a3d6b60a806b38907746eeea2c327f5fec", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9", + "0x745d525a3582e91299d8d7c71730ffc4b1f191f5b219d800334bc0edad0983b", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8" + ], + "data": [ + "0x376ba0d9af89e3", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 5051, + "builtin_instance_counter": { + "poseidon_builtin": 5, + "pedersen_builtin": 31, + "range_check_builtin": 205 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 256, + "l2_gas": 0 + }, + "total_gas_consumed": { + "l1_gas": 0, + "l1_data_gas": 288, + "l2_gas": 1515035 + } + }, + "actual_fee": "0x376ba0d9af89e3" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 1, + "transaction_hash": "0x20a6b5bc2fcd7c4fa68583c5714ac997da6aa512453f2dcd321ac83c402aabf", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9", + "0x745d525a3582e91299d8d7c71730ffc4b1f191f5b219d800334bc0edad0983b", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8" + ], + "data": [ + "0x4676bba3b24d89", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 5588, + "builtin_instance_counter": { + "range_check_builtin": 290, + "poseidon_builtin": 7, + "pedersen_builtin": 27 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 416, + "l2_gas": 0 + }, + "total_gas_consumed": { + "l1_gas": 0, + "l1_data_gas": 480, + "l2_gas": 1158705 + } + }, + "actual_fee": "0x4676bba3b24d89" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 2, + "transaction_hash": "0x3b7869de77438959db61644b709bd771fce950ae22d9cc583153e39183e0efe", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9", + "0x745d525a3582e91299d8d7c71730ffc4b1f191f5b219d800334bc0edad0983b", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8" + ], + "data": [ + "0x277bcbedda7560", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 4459, + "builtin_instance_counter": { + "pedersen_builtin": 18, + "poseidon_builtin": 3, + "range_check_builtin": 137 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 128, + "l2_gas": 0 + }, + "total_gas_consumed": { + "l1_gas": 0, + "l1_data_gas": 128, + "l2_gas": 1599840 + } + }, + "actual_fee": "0x277bcbedda7560" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 3, + "transaction_hash": "0x21d28c5d64ddc242cb6337b07bff970425fc2173245660580b705c0afb4a90d", + "l2_to_l1_messages": [], + "events": [ + { + "from_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9", + "0x745d525a3582e91299d8d7c71730ffc4b1f191f5b219d800334bc0edad0983b", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8" + ], + "data": [ + "0xdc24bd9e78", + "0x0" + ] + } + ], + "execution_resources": { + "n_steps": 4459, + "builtin_instance_counter": { + "range_check_builtin": 137, + "poseidon_builtin": 3, + "pedersen_builtin": 18 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 128, + "l2_gas": 0 + }, + "total_gas_consumed": { + "l1_gas": 18, + "l1_data_gas": 128, + "l2_gas": 0 + } + }, + "actual_fee": "0xdc24bd9e78" + } + ], + "starknet_version": "0.13.5" +} diff --git a/crates/starknet_client/resources/reader/block_post_0_14_0.json b/crates/starknet_client/resources/reader/block_post_0_14_0.json new file mode 100644 index 00000000000..21303196299 --- /dev/null +++ b/crates/starknet_client/resources/reader/block_post_0_14_0.json @@ -0,0 +1,399 @@ +{ + "block_hash": "0x1219b7fcf5b8872c5d16ecabe3120eb221bec7d99eb299fa2dd830100f70bfd", + "parent_block_hash": "0x0", + "block_number": 329526, + "state_root": "0x502c54a3efd1d6e679675e3edc3d0b5a978e5de5118e439605985b5a3dc9816", + "transaction_commitment": "0x3669da31ff0c48e7a14c7caf54480defcbfd3d6c506c38ce6a069acf64e8436", + "event_commitment": "0x0", + "status": "ACCEPTED_ON_L2", + "l1_da_mode": "BLOB", + "l1_gas_price": { + "price_in_wei": "0x1", + "price_in_fri": "0x1" + }, + "l1_data_gas_price": { + "price_in_wei": "0x1", + "price_in_fri": "0x1" + }, + "l2_gas_price": { + "price_in_wei": "0x1", + "price_in_fri": "0x1" + }, + "transactions": [ + { + "transaction_hash": "0x7d445a6f17252cf122493cf0b4ecd0b67f9cf5b849f2cc5deabbc1b28901406", + "version": "0x0", + "max_fee": "0x0", + "signature": [], + "nonce": "0x0", + "class_hash": "0x13574877f3e200c5d9f09128637ad5c6321adee3a770165ace5444e6f3208bb", + "sender_address": "0x1", + "type": "DECLARE" + }, + { + "transaction_hash": "0x3c83ee09d08b4fab2bf8ba24460376493d116565393fa328ffe000202380fcf", + "version": "0x1", + "max_fee": "0x0", + "signature": [], + "nonce": "0x0", + "contract_address": "0x2754c4a367ad73980ee5a62d1dc88815c249cbc6eab08b6729dfcd186dc14e8", + "contract_address_salt": "0x0", + "class_hash": "0x13574877f3e200c5d9f09128637ad5c6321adee3a770165ace5444e6f3208bb", + "constructor_calldata": [], + "type": "DEPLOY_ACCOUNT" + }, + { + "transaction_hash": "0x3b704517d03da744765ea00b8d040885dc816e97eae6509347b8a5ac23306da", + "version": "0x1", + "max_fee": "0x0", + "signature": [], + "nonce": "0x1", + "class_hash": "0x6c235ee373f5dd26f54e168ded916e7c329799f1d06965eea63140ec9442cb", + "sender_address": "0x2754c4a367ad73980ee5a62d1dc88815c249cbc6eab08b6729dfcd186dc14e8", + "type": "DECLARE" + }, + { + "transaction_hash": "0x187128812e48b8901671f212ff5ffc224ebb7eb3370c01105ae85ea7675e07f", + "version": "0x1", + "max_fee": "0x0", + "signature": [], + "nonce": "0x2", + "sender_address": "0x2754c4a367ad73980ee5a62d1dc88815c249cbc6eab08b6729dfcd186dc14e8", + "calldata": [ + "0x2754c4a367ad73980ee5a62d1dc88815c249cbc6eab08b6729dfcd186dc14e8", + "0x2730079d734ee55315f4f141eaed376bddd8c2133523d223a344c5604e0f7f8", + "0x5", + "0x6c235ee373f5dd26f54e168ded916e7c329799f1d06965eea63140ec9442cb", + "0x21", + "0x2", + "0x141", + "0x21f" + ], + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x6d4a150b7e39b8d1047582d243e78e816c7baa300a5b3ecce3cfcb3865e6e0f", + "version": "0x2", + "max_fee": "0x0", + "signature": [], + "nonce": "0x3", + "class_hash": "0x5d4f123c53c7cfe4db2725ff77f52b7cc0293115175c4a6ae26b931bb33c973", + "compiled_class_hash": "0xc96e9f97365579383ef8edcae038bc50dfc94df26aead3ce46d269562854bd", + "sender_address": "0x2754c4a367ad73980ee5a62d1dc88815c249cbc6eab08b6729dfcd186dc14e8", + "type": "DECLARE" + }, + { + "transaction_hash": "0x2db77a282c7fae7f10519adcf2a84050b0fce14017bddb37e8121bedda45e8d", + "version": "0x0", + "max_fee": "0x0", + "signature": [], + "entry_point_selector": "0x12ead94ae9d3f9d2bdb6b847cf255f1f398193a1f88884a0ae8e18f24a037b6", + "calldata": [ + "0x55" + ], + "contract_address": "0x4047251081e724d4922a5577ad962da37ec278c2596a8f603f6406eaf40a5c5", + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x3f2c7b7fdc8974e9eaec65e2c093bf8fa46f57aff87bf10ad38fe870eaf4afa", + "version": "0x0", + "max_fee": "0x0", + "signature": [], + "entry_point_selector": "0x3d7905601c217734671143d457f0db37f7f8883112abd34b92c4abfeafde0c3", + "calldata": [ + "0x0", + "0x1" + ], + "contract_address": "0x4047251081e724d4922a5577ad962da37ec278c2596a8f603f6406eaf40a5c5", + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x1a429beceff5a24327b15a58b665990631748a37765e71df213099bb10a2f27", + "version": "0x0", + "max_fee": "0x0", + "signature": [], + "entry_point_selector": "0x3d7905601c217734671143d457f0db37f7f8883112abd34b92c4abfeafde0c3", + "calldata": [ + "0x1", + "0x2" + ], + "contract_address": "0x4047251081e724d4922a5577ad962da37ec278c2596a8f603f6406eaf40a5c5", + "type": "INVOKE_FUNCTION" + }, + { + "transaction_hash": "0x7b85ae3d7d19e5efb31b3cb4fd154bf166388db5711dd3580e665d012f4d96c", + "version": "0x0", + "max_fee": "0x0", + "signature": [], + "entry_point_selector": "0x3d7905601c217734671143d457f0db37f7f8883112abd34b92c4abfeafde0c3", + "calldata": [ + "0x2", + "0x3" + ], + "contract_address": "0x4047251081e724d4922a5577ad962da37ec278c2596a8f603f6406eaf40a5c5", + "type": "INVOKE_FUNCTION" + } + ], + "timestamp": 1, + "sequencer_address": "0x61a342ce11aa3ba7770c592537270fbd64f4bd7e6fa0904498c2b5675da0f48", + "transaction_receipts": [ + { + "execution_status": "SUCCEEDED", + "transaction_index": 0, + "transaction_hash": "0x7d445a6f17252cf122493cf0b4ecd0b67f9cf5b849f2cc5deabbc1b28901406", + "l2_to_l1_messages": [], + "events": [], + "execution_resources": { + "n_steps": 3468, + "builtin_instance_counter": { + "range_check_builtin": 90, + "poseidon_builtin": 6, + "pedersen_builtin": 16 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 64, + "l2_gas": 0 + }, + "total_gas_consumed": { + "l1_gas": 245, + "l1_data_gas": 64, + "l2_gas": 0 + } + }, + "actual_fee": "0x0" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 1, + "transaction_hash": "0x3c83ee09d08b4fab2bf8ba24460376493d116565393fa328ffe000202380fcf", + "l2_to_l1_messages": [], + "events": [], + "execution_resources": { + "n_steps": 4799, + "builtin_instance_counter": { + "pedersen_builtin": 23, + "range_check_builtin": 157, + "poseidon_builtin": 3 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 160, + "l2_gas": 0 + }, + "total_gas_consumed": { + "l1_gas": 12, + "l1_data_gas": 160, + "l2_gas": 0 + } + }, + "actual_fee": "0xac" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 2, + "transaction_hash": "0x3b704517d03da744765ea00b8d040885dc816e97eae6509347b8a5ac23306da", + "l2_to_l1_messages": [], + "events": [], + "execution_resources": { + "n_steps": 3724, + "builtin_instance_counter": { + "range_check_builtin": 124, + "poseidon_builtin": 7, + "pedersen_builtin": 16 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 128, + "l2_gas": 0 + }, + "total_gas_consumed": { + "l1_gas": 2272, + "l1_data_gas": 128, + "l2_gas": 0 + } + }, + "actual_fee": "0x960" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 3, + "transaction_hash": "0x187128812e48b8901671f212ff5ffc224ebb7eb3370c01105ae85ea7675e07f", + "l2_to_l1_messages": [], + "events": [], + "execution_resources": { + "n_steps": 7472, + "builtin_instance_counter": { + "poseidon_builtin": 5, + "range_check_builtin": 261, + "pedersen_builtin": 29 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 288, + "l2_gas": 0 + }, + "total_gas_consumed": { + "l1_gas": 20, + "l1_data_gas": 320, + "l2_gas": 0 + } + }, + "actual_fee": "0x154" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 4, + "transaction_hash": "0x6d4a150b7e39b8d1047582d243e78e816c7baa300a5b3ecce3cfcb3865e6e0f", + "l2_to_l1_messages": [], + "events": [], + "execution_resources": { + "n_steps": 3968, + "builtin_instance_counter": { + "pedersen_builtin": 16, + "poseidon_builtin": 8, + "range_check_builtin": 158 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 192, + "l2_gas": 0 + }, + "total_gas_consumed": { + "l1_gas": 34987, + "l1_data_gas": 192, + "l2_gas": 0 + } + }, + "actual_fee": "0x896b" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 5, + "transaction_hash": "0x2db77a282c7fae7f10519adcf2a84050b0fce14017bddb37e8121bedda45e8d", + "l2_to_l1_messages": [ + { + "from_address": "0x4047251081e724d4922a5577ad962da37ec278c2596a8f603f6406eaf40a5c5", + "to_address": "0x0000000000000000000000000000000000000055", + "payload": [ + "0xc", + "0x22" + ] + } + ], + "events": [], + "execution_resources": { + "n_steps": 4364, + "builtin_instance_counter": { + "pedersen_builtin": 15, + "range_check_builtin": 104, + "poseidon_builtin": 2 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 64, + "l2_gas": 0 + }, + "total_gas_consumed": { + "l1_gas": 28155, + "l1_data_gas": 64, + "l2_gas": 0 + } + }, + "actual_fee": "0x6e3b" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 6, + "transaction_hash": "0x3f2c7b7fdc8974e9eaec65e2c093bf8fa46f57aff87bf10ad38fe870eaf4afa", + "l2_to_l1_messages": [], + "events": [], + "execution_resources": { + "n_steps": 4806, + "builtin_instance_counter": { + "pedersen_builtin": 16, + "range_check_builtin": 172, + "poseidon_builtin": 4 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 192, + "l2_gas": 0 + }, + "total_gas_consumed": { + "l1_gas": 13, + "l1_data_gas": 224, + "l2_gas": 0 + } + }, + "actual_fee": "0xed" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 7, + "transaction_hash": "0x1a429beceff5a24327b15a58b665990631748a37765e71df213099bb10a2f27", + "l2_to_l1_messages": [], + "events": [], + "execution_resources": { + "n_steps": 4806, + "builtin_instance_counter": { + "pedersen_builtin": 16, + "poseidon_builtin": 4, + "range_check_builtin": 172 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 192, + "l2_gas": 0 + }, + "total_gas_consumed": { + "l1_gas": 13, + "l1_data_gas": 224, + "l2_gas": 0 + } + }, + "actual_fee": "0xed" + }, + { + "execution_status": "SUCCEEDED", + "transaction_index": 8, + "transaction_hash": "0x7b85ae3d7d19e5efb31b3cb4fd154bf166388db5711dd3580e665d012f4d96c", + "l2_to_l1_messages": [], + "events": [], + "execution_resources": { + "n_steps": 4806, + "builtin_instance_counter": { + "pedersen_builtin": 16, + "poseidon_builtin": 4, + "range_check_builtin": 172 + }, + "n_memory_holes": 0, + "data_availability": { + "l1_gas": 0, + "l1_data_gas": 192, + "l2_gas": 0 + }, + "total_gas_consumed": { + "l1_gas": 13, + "l1_data_gas": 224, + "l2_gas": 0 + } + }, + "actual_fee": "0xed" + } + ], + "starknet_version": "0.14.0", + "l2_gas_consumed": 0, + "next_l2_gas_price": 1, + "receipt_commitment": "0x0", + "state_diff_commitment": "0x0", + "state_diff_length": 1 +} diff --git a/crates/starknet_client/resources/reader/old_block_post_0_13_1_no_sequencer.json b/crates/starknet_client/resources/reader/old_block_post_0_13_1_no_sequencer.json index f5449be2518..3d1bd2d162f 100644 --- a/crates/starknet_client/resources/reader/old_block_post_0_13_1_no_sequencer.json +++ b/crates/starknet_client/resources/reader/old_block_post_0_13_1_no_sequencer.json @@ -153,5 +153,7 @@ }, "actual_fee": "0x0" } - ] + ], + "l2_gas_consumed": 0, + "next_l2_gas_price": 1 } diff --git a/crates/starknet_client/resources/reader/old_block_post_0_13_1_no_sn_version.json b/crates/starknet_client/resources/reader/old_block_post_0_13_1_no_sn_version.json index 98a4f01e72c..08aefa8d514 100644 --- a/crates/starknet_client/resources/reader/old_block_post_0_13_1_no_sn_version.json +++ b/crates/starknet_client/resources/reader/old_block_post_0_13_1_no_sn_version.json @@ -105,5 +105,7 @@ }, "actual_fee": "0x0" } - ] + ], + "l2_gas_consumed": 0, + "next_l2_gas_price": 1 } diff --git a/crates/starknet_client/src/reader/mod.rs b/crates/starknet_client/src/reader/mod.rs index 7dc4b31ff1b..feba92ab571 100644 --- a/crates/starknet_client/src/reader/mod.rs +++ b/crates/starknet_client/src/reader/mod.rs @@ -141,6 +141,7 @@ const GET_COMPILED_CLASS_BY_CLASS_HASH_URL: &str = "feeder_gateway/get_compiled_class_by_class_hash"; const GET_STATE_UPDATE_URL: &str = "feeder_gateway/get_state_update"; const BLOCK_NUMBER_QUERY: &str = "blockNumber"; +const FEE_MARKET_INFO_QUERY: &str = "withFeeMarketInfo"; const LATEST_BLOCK_NUMBER: &str = "latest"; const CLASS_HASH_QUERY: &str = "classHash"; const PENDING_BLOCK_ID: &str = "pending"; @@ -208,12 +209,26 @@ impl StarknetFeederGatewayClient { &self, block_number: Option, ) -> ReaderClientResult> { - let mut url = self.urls.get_block.clone(); let block_number = block_number.map(|bn| bn.to_string()).unwrap_or(String::from(LATEST_BLOCK_NUMBER)); - url.query_pairs_mut().append_pair(BLOCK_NUMBER_QUERY, block_number.as_str()); - let response = self.request_with_retry_url(url).await; + let mut get_block_url = self.urls.get_block.clone(); + get_block_url.query_pairs_mut().append_pair(BLOCK_NUMBER_QUERY, block_number.as_str()); + let old_get_block_url = get_block_url.clone(); + // For version >= 0.14.0 + get_block_url.query_pairs_mut().append_pair(FEE_MARKET_INFO_QUERY, "true"); + + let mut response = self.request_with_retry_url(get_block_url).await; + // TODO(Ayelet): Temporary fallback for backward compatibility. Remove once the version + // update to 0.14.0 is complete. + if let Err(ReaderClientError::ClientError(ClientError::StarknetError(StarknetError { + code: StarknetErrorCode::KnownErrorCode(KnownStarknetErrorCode::MalformedRequest), + .. + }))) = response + { + response = self.request_with_retry_url(old_get_block_url).await; + } + load_object_from_response( response, Some(KnownStarknetErrorCode::BlockNotFound), @@ -281,7 +296,7 @@ impl StarknetReader for StarknetFeederGatewayClient { // FIXME: Remove the following default CasmContractClass once integration environment gets // regenesissed. // Use default value for CasmConractClass that are malformed in the integration environment. - // TODO: Make this array a const. + // TODO(YoavGr): Make this array a const. if [ ClassHash(Felt::from_hex_unchecked( "0x4e70b19333ae94bd958625f7b61ce9eec631653597e68645e13780061b2136c", diff --git a/crates/starknet_client/src/reader/objects/block.rs b/crates/starknet_client/src/reader/objects/block.rs index da6700e4e54..c1ae9832bd7 100644 --- a/crates/starknet_client/src/reader/objects/block.rs +++ b/crates/starknet_client/src/reader/objects/block.rs @@ -36,6 +36,9 @@ use crate::reader::objects::transaction::{ }; use crate::reader::{ReaderClientError, ReaderClientResult}; +fn default_next_l2_gas_price() -> u64 { + 1 +} /// A block as returned by the starknet gateway since V0.13.1. #[derive(Debug, Default, Deserialize, Serialize, Clone, Eq, PartialEq)] #[serde(deny_unknown_fields)] @@ -74,6 +77,16 @@ pub struct BlockPostV0_13_1 { pub receipt_commitment: Option, #[serde(skip_serializing_if = "Option::is_none")] pub state_diff_length: Option, + // New field in V0.14.0 + // TODO(Ayelet): Remove default Serde after 0.14.0, as the feeder gateway returns defaults when + // values are missing for older blocks. Change to GasAmount. + #[serde(default)] + pub l2_gas_consumed: u64, + // New field in V0.14.0 + // TODO(Ayelet): Remove default Serde after 0.14.0, as the feeder gateway returns defaults when + // values are missing for older blocks. Change to GasPrice. + #[serde(default = "default_next_l2_gas_price")] + pub next_l2_gas_price: u64, } impl BlockPostV0_13_1 { @@ -267,6 +280,18 @@ impl Block { } } + pub fn l2_gas_consumed(&self) -> u64 { + match self { + Block::PostV0_13_1(block) => block.l2_gas_consumed, + } + } + + pub fn next_l2_gas_price(&self) -> u64 { + match self { + Block::PostV0_13_1(block) => block.next_l2_gas_price, + } + } + // TODO(shahak): Rename to to_starknet_api_block. pub fn to_starknet_api_block_and_version(self) -> ReaderClientResult { // Check that the number of receipts is the same as the number of transactions. @@ -305,6 +330,8 @@ impl Block { block_number: self.block_number(), l1_gas_price: self.l1_gas_price(), l2_gas_price: self.l2_gas_price(), + l2_gas_consumed: self.l2_gas_consumed(), + next_l2_gas_price: self.next_l2_gas_price(), state_root: self.state_root(), sequencer: self.sequencer_address(), timestamp: self.timestamp(), diff --git a/crates/starknet_client/src/reader/objects/block_test.rs b/crates/starknet_client/src/reader/objects/block_test.rs index 58325afc420..5398fd7b3e4 100644 --- a/crates/starknet_client/src/reader/objects/block_test.rs +++ b/crates/starknet_client/src/reader/objects/block_test.rs @@ -4,8 +4,8 @@ use pretty_assertions::assert_eq; use starknet_api::block::BlockHash; use starknet_api::core::{CompiledClassHash, Nonce}; use starknet_api::hash::StarkHash; -use starknet_api::transaction::{TransactionHash, TransactionOffsetInBlock}; -use starknet_api::{class_hash, contract_address, felt, storage_key}; +use starknet_api::transaction::TransactionOffsetInBlock; +use starknet_api::{class_hash, contract_address, felt, storage_key, tx_hash}; use super::{Block, GlobalRoot, TransactionReceiptsError}; use crate::reader::objects::block::BlockPostV0_13_1; @@ -26,6 +26,8 @@ fn load_block_succeeds() { // TODO(Tzahi): Replace block_post_0_13_3 (copied from 0_13_2 and added additional fields) with // live data once available. for block_path in [ + "reader/block_post_0_14_0.json", + "reader/block_post_0_13_4.json", "reader/block_post_0_13_3.json", "reader/block_post_0_13_2.json", "reader/block_post_0_13_1.json", @@ -135,7 +137,7 @@ async fn to_starknet_api_block_and_version() { ); let mut err_block: BlockPostV0_13_1 = serde_json::from_str(&raw_block).unwrap(); - err_block.transaction_receipts[0].transaction_hash = TransactionHash(felt!("0x4")); + err_block.transaction_receipts[0].transaction_hash = tx_hash!(0x4); let err = err_block.to_starknet_api_block_and_version().unwrap_err(); assert_matches!( err, diff --git a/crates/starknet_client/src/reader/objects/transaction.rs b/crates/starknet_client/src/reader/objects/transaction.rs index e341c2ea203..783d5d4d1fa 100644 --- a/crates/starknet_client/src/reader/objects/transaction.rs +++ b/crates/starknet_client/src/reader/objects/transaction.rs @@ -207,7 +207,7 @@ pub struct IntermediateDeclareTransaction { impl TryFrom for starknet_api::transaction::DeclareTransaction { type Error = ReaderClientError; - // TODO: Consider using match instead. + // TODO(DanB): Consider using match instead. fn try_from(declare_tx: IntermediateDeclareTransaction) -> Result { if declare_tx.version == TransactionVersion::ZERO { return Ok(Self::V0(declare_tx.try_into()?)); @@ -740,7 +740,7 @@ pub struct TransactionReceipt { #[serde(default)] pub execution_resources: ExecutionResources, pub actual_fee: Fee, - // TODO: Check if we can remove the serde(default). + // TODO(Yair): Check if we can remove the serde(default). #[serde(default)] pub execution_status: TransactionExecutionStatus, // Note that in starknet_api this field is named `revert_reason`. diff --git a/crates/starknet_client/src/reader/starknet_feeder_gateway_client_test.rs b/crates/starknet_client/src/reader/starknet_feeder_gateway_client_test.rs index a2cf5cf2621..d175cc0a07d 100644 --- a/crates/starknet_client/src/reader/starknet_feeder_gateway_client_test.rs +++ b/crates/starknet_client/src/reader/starknet_feeder_gateway_client_test.rs @@ -45,10 +45,78 @@ use crate::reader::objects::block::{BlockSignatureData, BlockSignatureMessage}; use crate::reader::Block; use crate::test_utils::read_resource::read_resource_file; use crate::test_utils::retry::get_test_config; +use crate::{KnownStarknetErrorCode, StarknetError, StarknetErrorCode}; const NODE_VERSION: &str = "NODE VERSION"; const FEEDER_GATEWAY_ALIVE_RESPONSE: &str = "FeederGateway is alive!"; +// TODO(Ayelet): Remove old feeder gateway support once the version update to 0.14.0 is complete. +fn get_block_url( + block_number_or_latest: Option, + use_deprecated_feeder_gateway: bool, +) -> String { + let mut url = match block_number_or_latest { + Some(block_number) => format!("/feeder_gateway/get_block?blockNumber={}", block_number), + _ => "/feeder_gateway/get_block?blockNumber=latest".to_string(), + }; + + if !use_deprecated_feeder_gateway { + url.push_str("&withFeeMarketInfo=true"); + } + + url +} + +fn starknet_client() -> StarknetFeederGatewayClient { + StarknetFeederGatewayClient::new(&mockito::server_url(), None, NODE_VERSION, get_test_config()) + .unwrap() +} + +// TODO(Ayelet): Consider making this function generic for all successful mock responses in this +// file. +fn mock_successful_get_block_response( + response_file: &str, + request_param: Option, + use_deprecated_feeder_gateway: bool, +) -> mockito::Mock { + mock("GET", get_block_url(request_param, use_deprecated_feeder_gateway).as_str()) + .with_status(200) + .with_body(read_resource_file(response_file)) + .create() +} + +// TODO(Ayelet): Consider making this function generic for all error mock responses in this file. +fn mock_error_get_block_response( + error_response_body: String, + request_param: Option, + use_deprecated_feeder_gateway: bool, +) -> mockito::Mock { + mock("GET", get_block_url(request_param, use_deprecated_feeder_gateway).as_str()) + .with_status(400) + .with_body(error_response_body) + .create() +} + +fn mock_current_feeder_gateway_invalid_get_latest_block_response() -> mockito::Mock { + mock_error_get_block_response(malformed_error(), None, false) +} + +fn block_not_found_error(block_number: i64) -> String { + let error = StarknetError { + code: StarknetErrorCode::KnownErrorCode(KnownStarknetErrorCode::BlockNotFound), + message: format!("Block {} was not found.", block_number), + }; + serde_json::to_string(&error).unwrap() +} + +fn malformed_error() -> String { + let error = StarknetError { + code: StarknetErrorCode::KnownErrorCode(KnownStarknetErrorCode::MalformedRequest), + message: "Malformed request.".to_string(), + }; + serde_json::to_string(&error).unwrap() +} + #[test] fn new_urls() { let url_base_str = "https://url"; @@ -66,34 +134,47 @@ fn new_urls() { } #[tokio::test] -async fn get_block_number() { - let starknet_client = StarknetFeederGatewayClient::new( - &mockito::server_url(), - None, - NODE_VERSION, - get_test_config(), - ) - .unwrap(); - // There are blocks in Starknet. - let mock_block = mock("GET", "/feeder_gateway/get_block?blockNumber=latest") - .with_status(200) - .with_body(read_resource_file("reader/block_post_0_13_1.json")) - .create(); +async fn get_latest_block_when_blocks_exists() { + let starknet_client = starknet_client(); + let mock_block = + mock_successful_get_block_response("reader/block_post_0_14_0.json", None, false); let latest_block = starknet_client.latest_block().await.unwrap(); mock_block.assert(); + assert_eq!(latest_block.unwrap().block_number(), BlockNumber(329526)); +} + +#[tokio::test] +async fn fallback_get_latest_block_when_blocks_exists() { + let starknet_client = starknet_client(); + let mock_fallback_error = mock_current_feeder_gateway_invalid_get_latest_block_response(); + let mock_block = + mock_successful_get_block_response("reader/block_post_0_13_1.json", None, true); + let latest_block = starknet_client.latest_block().await.unwrap(); + mock_fallback_error.assert(); + mock_block.assert(); assert_eq!(latest_block.unwrap().block_number(), BlockNumber(329525)); +} - // There are no blocks in Starknet. - let body = r#"{"code": "StarknetErrorCode.BLOCK_NOT_FOUND", "message": "Block number -1 was not found."}"#; - let mock_no_block = mock("GET", "/feeder_gateway/get_block?blockNumber=latest") - .with_status(400) - .with_body(body) - .create(); +#[tokio::test] +async fn get_latest_block_when_no_blocks_exist() { + let starknet_client = starknet_client(); + let mock_no_block = mock_error_get_block_response(block_not_found_error(-1), None, false); let latest_block = starknet_client.latest_block().await.unwrap(); mock_no_block.assert(); assert!(latest_block.is_none()); } +#[tokio::test] +async fn fallback_get_latest_block_when_no_blocks_exist() { + let starknet_client = starknet_client(); + let mock_fallback_error = mock_current_feeder_gateway_invalid_get_latest_block_response(); + let mock_no_block = mock_error_get_block_response(block_not_found_error(-1), None, true); + let latest_block = starknet_client.latest_block().await.unwrap(); + mock_fallback_error.assert(); + mock_no_block.assert(); + assert!(latest_block.is_none()); +} + #[tokio::test] async fn declare_tx_serde() { let declare_tx = IntermediateDeclareTransaction { @@ -122,13 +203,7 @@ async fn declare_tx_serde() { #[tokio::test] async fn state_update() { - let starknet_client = StarknetFeederGatewayClient::new( - &mockito::server_url(), - None, - NODE_VERSION, - get_test_config(), - ) - .unwrap(); + let starknet_client = starknet_client(); let raw_state_update = read_resource_file("reader/block_state_update.json"); let mock_state_update = mock("GET", &format!("/feeder_gateway/get_state_update?{BLOCK_NUMBER_QUERY}=123456")[..]) @@ -140,11 +215,10 @@ async fn state_update() { let expected_state_update: StateUpdate = serde_json::from_str(&raw_state_update).unwrap(); assert_eq!(state_update.unwrap(), expected_state_update); - let body = r#"{"code": "StarknetErrorCode.BLOCK_NOT_FOUND", "message": "Block number -1 was not found."}"#; let mock_no_block = mock("GET", &format!("/feeder_gateway/get_state_update?{BLOCK_NUMBER_QUERY}=999999")[..]) .with_status(400) - .with_body(body) + .with_body(block_not_found_error(-1)) .create(); let state_update = starknet_client.state_update(BlockNumber(999999)).await.unwrap(); assert!(state_update.is_none()); @@ -162,13 +236,7 @@ async fn serialization_precision() { #[tokio::test] async fn contract_class() { - let starknet_client = StarknetFeederGatewayClient::new( - &mockito::server_url(), - None, - NODE_VERSION, - get_test_config(), - ) - .unwrap(); + let starknet_client = starknet_client(); let expected_contract_class = ContractClass { sierra_program: vec![ felt!("0x302e312e30"), @@ -218,13 +286,7 @@ async fn contract_class() { #[tokio::test] async fn deprecated_contract_class() { - let starknet_client = StarknetFeederGatewayClient::new( - &mockito::server_url(), - None, - NODE_VERSION, - get_test_config(), - ) - .unwrap(); + let starknet_client = starknet_client(); let expected_contract_class = DeprecatedContractClass { abi: Some(vec![ContractClassAbiEntry::Constructor(FunctionAbiEntry:: { name: "constructor".to_string(), @@ -316,17 +378,11 @@ async fn deprecated_contract_class() { assert!(class.is_none()); } -// TODO: Add test for pending_data. +// TODO(DanB): Add test for pending_data. #[tokio::test] async fn deprecated_pending_data() { - let starknet_client = StarknetFeederGatewayClient::new( - &mockito::server_url(), - None, - NODE_VERSION, - get_test_config(), - ) - .unwrap(); + let starknet_client = starknet_client(); // Pending let raw_pending_data = read_resource_file("reader/deprecated_pending_data.json"); @@ -355,44 +411,61 @@ async fn deprecated_pending_data() { #[tokio::test] async fn get_block() { - let starknet_client = StarknetFeederGatewayClient::new( - &mockito::server_url(), - None, - NODE_VERSION, - get_test_config(), - ) - .unwrap(); - let raw_block = read_resource_file("reader/block_post_0_13_1.json"); - let mock_block = mock("GET", &format!("/feeder_gateway/get_block?{BLOCK_NUMBER_QUERY}=20")[..]) - .with_status(200) - .with_body(&raw_block) - .create(); + let starknet_client = starknet_client(); + let json_filename = "reader/block_post_0_14_0.json"; + + let mock_block = mock_successful_get_block_response(json_filename, Some(20), false); + let block = starknet_client.block(BlockNumber(20)).await.unwrap().unwrap(); + mock_block.assert(); + + let expected_block: Block = serde_json::from_str(&read_resource_file(json_filename)).unwrap(); + assert_eq!(block, expected_block); +} + +#[tokio::test] +async fn fallback_get_block() { + let starknet_client = starknet_client(); + let json_filename = "reader/block_post_0_13_1.json"; + + let mock_fallback_error = mock_error_get_block_response(malformed_error(), Some(20), false); + let mock_block = mock_successful_get_block_response(json_filename, Some(20), true); let block = starknet_client.block(BlockNumber(20)).await.unwrap().unwrap(); + mock_fallback_error.assert(); mock_block.assert(); - let expected_block: Block = serde_json::from_str(&raw_block).unwrap(); + + let expected_block: Block = serde_json::from_str(&read_resource_file(json_filename)).unwrap(); assert_eq!(block, expected_block); +} - // Non-existing block. - let body = r#"{"code": "StarknetErrorCode.BLOCK_NOT_FOUND", "message": "Block 9999999999 was not found."}"#; +// Requesting a block that does not exist, expecting a "Block Not Found" error. +#[tokio::test] +async fn get_block_not_found() { + let starknet_client = starknet_client(); let mock_no_block = - mock("GET", &format!("/feeder_gateway/get_block?{BLOCK_NUMBER_QUERY}=9999999999")[..]) - .with_status(400) - .with_body(body) - .create(); + mock_error_get_block_response(block_not_found_error(9999999999), Some(9999999999), false); + let block = starknet_client.block(BlockNumber(9999999999)).await.unwrap(); + mock_no_block.assert(); + assert!(block.is_none()); +} + +#[tokio::test] +async fn fallback_get_block_not_found() { + let starknet_client = starknet_client(); + + let mock_fallback_error = + mock_error_get_block_response(malformed_error(), Some(9999999999), false); + let mock_no_block = + mock_error_get_block_response(block_not_found_error(9999999999), Some(9999999999), true); let block = starknet_client.block(BlockNumber(9999999999)).await.unwrap(); + mock_fallback_error.assert(); mock_no_block.assert(); + assert!(block.is_none()); } #[tokio::test] async fn compiled_class_by_hash() { - let starknet_client = StarknetFeederGatewayClient::new( - &mockito::server_url(), - None, - NODE_VERSION, - get_test_config(), - ) - .unwrap(); + let starknet_client = starknet_client(); let raw_casm_contract_class = read_resource_file("reader/casm_contract_class.json"); let mock_casm_contract_class = mock( "GET", @@ -429,13 +502,7 @@ async fn compiled_class_by_hash() { #[tokio::test] async fn is_alive() { - let starknet_client = StarknetFeederGatewayClient::new( - &mockito::server_url(), - None, - NODE_VERSION, - get_test_config(), - ) - .unwrap(); + let starknet_client = starknet_client(); let mock_is_alive = mock("GET", "/feeder_gateway/is_alive") .with_status(200) .with_body(FEEDER_GATEWAY_ALIVE_RESPONSE) @@ -449,13 +516,8 @@ async fn is_alive() { // the state diff commitment). #[tokio::test] async fn state_update_with_empty_storage_diff() { - let starknet_client = StarknetFeederGatewayClient::new( - &mockito::server_url(), - None, - NODE_VERSION, - get_test_config(), - ) - .unwrap(); + let starknet_client = starknet_client(); + let mut state_update = StateUpdate::default(); let empty_storage_diff = indexmap!(ContractAddress::default() => vec![]); state_update.state_diff.storage_diffs.clone_from(&empty_storage_diff); @@ -478,13 +540,7 @@ async fn test_unserializable< url_suffix: &str, call_method: F, ) { - let starknet_client = StarknetFeederGatewayClient::new( - &mockito::server_url(), - None, - NODE_VERSION, - get_test_config(), - ) - .unwrap(); + let starknet_client = starknet_client(); let body = "body"; let mock = mock("GET", url_suffix).with_status(200).with_body(body).create(); let error = call_method(starknet_client).await.unwrap_err(); @@ -492,18 +548,57 @@ async fn test_unserializable< assert_matches!(error, ReaderClientError::SerdeError(_)); } +async fn fallback_test_unserializable< + Output: Send + Debug, + Fut: Future>, + F: FnOnce(StarknetFeederGatewayClient) -> Fut, +>( + block_number: Option, + call_method: F, +) { + let starknet_client = starknet_client(); + + let mock_fallback_error = mock_error_get_block_response(malformed_error(), block_number, false); + let mock_success_response = mock("GET", get_block_url(block_number, true).as_str()) + .with_status(200) + .with_body("body") + .create(); + + let error = call_method(starknet_client).await.unwrap_err(); + + mock_fallback_error.assert(); + mock_success_response.assert(); + + assert_matches!(error, ReaderClientError::SerdeError(_)); +} + #[tokio::test] async fn latest_block_unserializable() { - test_unserializable( - "/feeder_gateway/get_block?blockNumber=latest", - |starknet_client| async move { starknet_client.latest_block().await }, - ) + test_unserializable(&get_block_url(None, false), |starknet_client| async move { + starknet_client.latest_block().await + }) + .await +} + +#[tokio::test] +async fn fallback_latest_block_unserializable() { + fallback_test_unserializable(None, |starknet_client| async move { + starknet_client.latest_block().await + }) .await } #[tokio::test] async fn block_unserializable() { - test_unserializable("/feeder_gateway/get_block?blockNumber=20", |starknet_client| async move { + test_unserializable(&get_block_url(Some(20), false), |starknet_client| async move { + starknet_client.block(BlockNumber(20)).await + }) + .await +} + +#[tokio::test] +async fn fallback_block_unserializable() { + fallback_test_unserializable(Some(20), |starknet_client| async move { starknet_client.block(BlockNumber(20)).await }) .await @@ -545,13 +640,7 @@ async fn compiled_class_by_hash_unserializable() { #[tokio::test] async fn get_block_signature() { - let starknet_client = StarknetFeederGatewayClient::new( - &mockito::server_url(), - None, - NODE_VERSION, - get_test_config(), - ) - .unwrap(); + let starknet_client = starknet_client(); let expected_block_signature = BlockSignatureData::Deprecated { block_number: BlockNumber(20), @@ -575,19 +664,11 @@ async fn get_block_signature() { #[tokio::test] async fn get_block_signature_unknown_block() { - let starknet_client = StarknetFeederGatewayClient::new( - &mockito::server_url(), - None, - NODE_VERSION, - get_test_config(), - ) - .unwrap(); - - let body = r#"{"code": "StarknetErrorCode.BLOCK_NOT_FOUND", "message": "Block number 999999 was not found."}"#; + let starknet_client = starknet_client(); let mock_no_block = mock("GET", &format!("/feeder_gateway/get_signature?{BLOCK_NUMBER_QUERY}=999999")[..]) .with_status(400) - .with_body(body) + .with_body(block_not_found_error(999999)) .create(); let block_signature = starknet_client.block_signature(BlockNumber(999999)).await.unwrap(); mock_no_block.assert(); @@ -596,13 +677,7 @@ async fn get_block_signature_unknown_block() { #[tokio::test] async fn get_sequencer_public_key() { - let starknet_client = StarknetFeederGatewayClient::new( - &mockito::server_url(), - None, - NODE_VERSION, - get_test_config(), - ) - .unwrap(); + let starknet_client = starknet_client(); let expected_sequencer_pub_key = SequencerPublicKey(PublicKey(felt!("0x1"))); diff --git a/crates/starknet_client/src/test_utils/read_resource.rs b/crates/starknet_client/src/test_utils/read_resource.rs index e9ce891b5e1..69676a0058f 100644 --- a/crates/starknet_client/src/test_utils/read_resource.rs +++ b/crates/starknet_client/src/test_utils/read_resource.rs @@ -5,5 +5,5 @@ use starknet_api::test_utils::path_in_resources; pub fn read_resource_file(path_in_resource_dir: &str) -> String { let path = path_in_resources(path_in_resource_dir); - return read_to_string(path.to_str().unwrap()).unwrap(); + read_to_string(path.to_str().unwrap()).unwrap() } diff --git a/crates/starknet_committer/Cargo.toml b/crates/starknet_committer/Cargo.toml index bc354434e19..26f1a4ba69b 100644 --- a/crates/starknet_committer/Cargo.toml +++ b/crates/starknet_committer/Cargo.toml @@ -6,17 +6,22 @@ repository.workspace = true license.workspace = true description = "Computes and manages Starknet state." - [dependencies] hex.workspace = true pretty_assertions.workspace = true rstest.workspace = true serde_json.workspace = true starknet-types-core = { workspace = true, features = ["hash"] } -starknet_patricia = { workspace = true, features = ["testing"] } +starknet_api.workspace = true +starknet_patricia.workspace = true +starknet_patricia_storage.workspace = true thiserror.workspace = true tokio = { workspace = true, features = ["rt"] } tracing.workspace = true +[dev-dependencies] +starknet_api = { workspace = true, features = ["testing"] } +starknet_patricia = { workspace = true, features = ["testing"] } + [lints] workspace = true diff --git a/crates/starknet_committer/src/block_committer/commit.rs b/crates/starknet_committer/src/block_committer/commit.rs index 911dd932888..a20ca4edcbc 100644 --- a/crates/starknet_committer/src/block_committer/commit.rs +++ b/crates/starknet_committer/src/block_committer/commit.rs @@ -1,17 +1,24 @@ use std::collections::HashMap; +use starknet_api::core::{ClassHash, ContractAddress, Nonce}; use starknet_patricia::patricia_merkle_tree::types::{NodeIndex, SortedLeafIndices}; -use starknet_patricia::storage::map_storage::MapStorage; +use starknet_patricia_storage::map_storage::MapStorage; use tracing::{info, warn}; use crate::block_committer::errors::BlockCommitmentError; -use crate::block_committer::input::{Config, ConfigImpl, ContractAddress, Input, StateDiff}; +use crate::block_committer::input::{ + contract_address_into_node_index, + Config, + ConfigImpl, + Input, + StateDiff, +}; use crate::forest::filled_forest::FilledForest; use crate::forest::original_skeleton_forest::{ForestSortedIndices, OriginalSkeletonForest}; use crate::forest::updated_skeleton_forest::UpdatedSkeletonForest; use crate::hash_function::hash::TreeHashFunctionImpl; use crate::patricia_merkle_tree::leaf::leaf_impl::ContractState; -use crate::patricia_merkle_tree::types::{ClassHash, Nonce}; +use crate::patricia_merkle_tree::types::class_hash_into_node_index; type BlockCommitmentResult = Result; @@ -80,7 +87,7 @@ fn check_trivial_nonce_and_class_hash_updates( ) { for (address, nonce) in address_to_nonce.iter() { if original_contracts_trie_leaves - .get(&address.into()) + .get(&contract_address_into_node_index(address)) .is_some_and(|previous_contract_state| previous_contract_state.nonce == *nonce) { warn!("Encountered a trivial nonce update of contract {:?}", address) @@ -88,9 +95,12 @@ fn check_trivial_nonce_and_class_hash_updates( } for (address, class_hash) in address_to_class_hash.iter() { - if original_contracts_trie_leaves.get(&address.into()).is_some_and( - |previous_contract_state| previous_contract_state.class_hash == *class_hash, - ) { + if original_contracts_trie_leaves + .get(&contract_address_into_node_index(address)) + .is_some_and(|previous_contract_state| { + previous_contract_state.class_hash == *class_hash + }) + { warn!("Encountered a trivial class hash update of contract {:?}", address) } } @@ -105,10 +115,15 @@ pub(crate) fn get_all_modified_indices( state_diff: &StateDiff, ) -> (StorageTriesIndices, ContractsTrieIndices, ClassesTrieIndices) { let accessed_addresses = state_diff.accessed_addresses(); - let contracts_trie_indices: Vec = - accessed_addresses.iter().map(|address| NodeIndex::from(*address)).collect(); - let classes_trie_indices: Vec = - state_diff.class_hash_to_compiled_class_hash.keys().map(NodeIndex::from).collect(); + let contracts_trie_indices: Vec = accessed_addresses + .iter() + .map(|address| contract_address_into_node_index(address)) + .collect(); + let classes_trie_indices: Vec = state_diff + .class_hash_to_compiled_class_hash + .keys() + .map(class_hash_into_node_index) + .collect(); let storage_tries_indices: HashMap> = accessed_addresses .iter() .map(|address| { diff --git a/crates/starknet_committer/src/block_committer/input.rs b/crates/starknet_committer/src/block_committer/input.rs index 62590b2465b..39edaba809c 100644 --- a/crates/starknet_committer/src/block_committer/input.rs +++ b/crates/starknet_committer/src/block_committer/input.rs @@ -1,45 +1,38 @@ use std::collections::{HashMap, HashSet}; use std::fmt::Debug; -use starknet_patricia::felt::Felt; +use starknet_api::core::{ClassHash, ContractAddress, Nonce}; use starknet_patricia::hash::hash_trait::HashOutput; use starknet_patricia::patricia_merkle_tree::node_data::leaf::{LeafModifications, SkeletonLeaf}; use starknet_patricia::patricia_merkle_tree::types::NodeIndex; -use starknet_patricia::storage::storage_trait::{StorageKey, StorageValue}; +use starknet_patricia_storage::storage_trait::{DbKey, DbValue}; +use starknet_types_core::felt::Felt; use tracing::level_filters::LevelFilter; -use crate::patricia_merkle_tree::types::{ClassHash, CompiledClassHash, Nonce}; +use crate::patricia_merkle_tree::types::{class_hash_into_node_index, CompiledClassHash}; #[cfg(test)] #[path = "input_test.rs"] pub mod input_test; -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -// TODO(Nimrod, 1/6/2025): Use the ContractAddress defined in starknet-types-core when available. -pub struct ContractAddress(pub Felt); - -impl TryFrom<&NodeIndex> for ContractAddress { - type Error = String; - - fn try_from(node_index: &NodeIndex) -> Result { - if !node_index.is_leaf() { - return Err("NodeIndex is not a leaf.".to_string()); - } - let result = Felt::try_from(*node_index - NodeIndex::FIRST_LEAF); - match result { - Ok(felt) => Ok(ContractAddress(felt)), - Err(error) => Err(format!( - "Tried to convert node index to felt and got the following error: {:?}", - error.to_string() - )), - } +pub fn try_node_index_into_contract_address( + node_index: &NodeIndex, +) -> Result { + if !node_index.is_leaf() { + return Err("NodeIndex is not a leaf.".to_string()); + } + let result = Felt::try_from(*node_index - NodeIndex::FIRST_LEAF); + match result { + Ok(felt) => Ok(ContractAddress::try_from(felt).map_err(|error| error.to_string())?), + Err(error) => Err(format!( + "Tried to convert node index to felt and got the following error: {:?}", + error.to_string() + )), } } -impl From<&ContractAddress> for NodeIndex { - fn from(address: &ContractAddress) -> NodeIndex { - NodeIndex::from_leaf_felt(&address.0) - } +pub fn contract_address_into_node_index(address: &ContractAddress) -> NodeIndex { + NodeIndex::from_leaf_felt(&address.0) } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] @@ -100,7 +93,7 @@ impl ConfigImpl { #[derive(Debug, Eq, PartialEq)] pub struct Input { - pub storage: HashMap, + pub storage: HashMap, /// All relevant information for the state diff commitment. pub state_diff: StateDiff, pub contracts_trie_root_hash: HashOutput, @@ -141,7 +134,7 @@ impl StateDiff { self.class_hash_to_compiled_class_hash .iter() .map(|(class_hash, compiled_class_hash)| { - (class_hash.into(), SkeletonLeaf::from(compiled_class_hash.0)) + (class_hash_into_node_index(class_hash), SkeletonLeaf::from(compiled_class_hash.0)) }) .collect() } @@ -166,7 +159,9 @@ impl StateDiff { pub(crate) fn actual_classes_updates(&self) -> LeafModifications { self.class_hash_to_compiled_class_hash .iter() - .map(|(class_hash, compiled_class_hash)| (class_hash.into(), *compiled_class_hash)) + .map(|(class_hash, compiled_class_hash)| { + (class_hash_into_node_index(class_hash), *compiled_class_hash) + }) .collect() } } diff --git a/crates/starknet_committer/src/block_committer/input_test.rs b/crates/starknet_committer/src/block_committer/input_test.rs index 5838d8b018a..32f04ca1742 100644 --- a/crates/starknet_committer/src/block_committer/input_test.rs +++ b/crates/starknet_committer/src/block_committer/input_test.rs @@ -1,25 +1,32 @@ use rstest::rstest; -use starknet_patricia::felt::Felt; +use starknet_api::core::ContractAddress; use starknet_patricia::patricia_merkle_tree::types::NodeIndex; +use starknet_types_core::felt::Felt; -use crate::block_committer::input::ContractAddress; +use crate::block_committer::input::try_node_index_into_contract_address; #[rstest] fn test_node_index_to_contract_address_conversion() { // Positive flow. - assert_eq!(ContractAddress::try_from(&NodeIndex::FIRST_LEAF), Ok(ContractAddress(Felt::ZERO))); assert_eq!( - ContractAddress::try_from(&(NodeIndex::FIRST_LEAF + NodeIndex(1_u32.into()))), - Ok(ContractAddress(Felt::ONE)) + try_node_index_into_contract_address(&NodeIndex::FIRST_LEAF), + Ok(ContractAddress::try_from(Felt::ZERO).unwrap()) ); assert_eq!( - ContractAddress::try_from(&NodeIndex::MAX), - Ok(ContractAddress(Felt::try_from(NodeIndex::MAX - NodeIndex::FIRST_LEAF).unwrap())) + try_node_index_into_contract_address(&(NodeIndex::FIRST_LEAF + NodeIndex(1_u32.into()))), + Ok(ContractAddress::try_from(Felt::ONE).unwrap()) + ); + assert_eq!( + try_node_index_into_contract_address(&NodeIndex::MAX), + Ok(ContractAddress::try_from( + Felt::try_from(NodeIndex::MAX - NodeIndex::FIRST_LEAF).unwrap() + ) + .unwrap()) ); // Negative flow. assert_eq!( - ContractAddress::try_from(&(NodeIndex::FIRST_LEAF - NodeIndex(1_u32.into()))), + try_node_index_into_contract_address(&(NodeIndex::FIRST_LEAF - NodeIndex(1_u32.into()))), Err("NodeIndex is not a leaf.".to_string()) ); } diff --git a/crates/starknet_committer/src/forest/filled_forest.rs b/crates/starknet_committer/src/forest/filled_forest.rs index e1d0037112f..fedd7227930 100644 --- a/crates/starknet_committer/src/forest/filled_forest.rs +++ b/crates/starknet_committer/src/forest/filled_forest.rs @@ -1,24 +1,27 @@ use std::collections::HashMap; +use starknet_api::core::{ClassHash, ContractAddress, Nonce}; use starknet_patricia::hash::hash_trait::HashOutput; use starknet_patricia::patricia_merkle_tree::filled_tree::tree::FilledTree; use starknet_patricia::patricia_merkle_tree::node_data::leaf::LeafModifications; use starknet_patricia::patricia_merkle_tree::types::NodeIndex; use starknet_patricia::patricia_merkle_tree::updated_skeleton_tree::tree::UpdatedSkeletonTreeImpl; -use starknet_patricia::storage::storage_trait::Storage; +use starknet_patricia_storage::storage_trait::Storage; use tracing::info; -use crate::block_committer::input::{ContractAddress, StarknetStorageValue}; +use crate::block_committer::input::{ + contract_address_into_node_index, + try_node_index_into_contract_address, + StarknetStorageValue, +}; use crate::forest::forest_errors::{ForestError, ForestResult}; use crate::forest::updated_skeleton_forest::UpdatedSkeletonForest; use crate::hash_function::hash::ForestHashFunction; use crate::patricia_merkle_tree::leaf::leaf_impl::{ContractState, ContractStateInput}; use crate::patricia_merkle_tree::types::{ - ClassHash, ClassesTrie, CompiledClassHash, ContractsTrie, - Nonce, StorageTrieMap, }; @@ -94,7 +97,7 @@ impl FilledForest { .into_iter() .map(|(node_index, storage_trie)| { ( - ContractAddress::try_from(&node_index).unwrap_or_else(|error| { + try_node_index_into_contract_address(&node_index).unwrap_or_else(|error| { panic!( "Got the following error when trying to convert node index \ {node_index:?} to a contract address: {error:?}", @@ -132,7 +135,7 @@ impl FilledForest { // `contract_address_to_storage_updates` includes all modified contracts, even those with // unmodified storage, see StateDiff::actual_storage_updates(). for (contract_address, storage_updates) in contract_address_to_storage_updates { - let node_index = NodeIndex::from(&contract_address); + let node_index = contract_address_into_node_index(&contract_address); let original_contract_state = original_contracts_trie_leaves .get(&node_index) .ok_or(ForestError::MissingContractCurrentState(contract_address))?; diff --git a/crates/starknet_committer/src/forest/forest_errors.rs b/crates/starknet_committer/src/forest/forest_errors.rs index 51c866d24eb..c4d52b65ef9 100644 --- a/crates/starknet_committer/src/forest/forest_errors.rs +++ b/crates/starknet_committer/src/forest/forest_errors.rs @@ -1,11 +1,10 @@ +use starknet_api::core::ContractAddress; use starknet_patricia::patricia_merkle_tree::filled_tree::errors::FilledTreeError; use starknet_patricia::patricia_merkle_tree::original_skeleton_tree::errors::OriginalSkeletonTreeError; use starknet_patricia::patricia_merkle_tree::updated_skeleton_tree::errors::UpdatedSkeletonTreeError; use thiserror::Error; use tokio::task::JoinError; -use crate::block_committer::input::ContractAddress; - pub(crate) type ForestResult = Result; #[derive(Debug, Error)] diff --git a/crates/starknet_committer/src/forest/original_skeleton_forest.rs b/crates/starknet_committer/src/forest/original_skeleton_forest.rs index 1ecca036d28..9ec6873ee76 100644 --- a/crates/starknet_committer/src/forest/original_skeleton_forest.rs +++ b/crates/starknet_committer/src/forest/original_skeleton_forest.rs @@ -1,5 +1,6 @@ use std::collections::HashMap; +use starknet_api::core::ContractAddress; use starknet_patricia::hash::hash_trait::HashOutput; use starknet_patricia::patricia_merkle_tree::node_data::leaf::LeafModifications; use starknet_patricia::patricia_merkle_tree::original_skeleton_tree::tree::{ @@ -7,9 +8,13 @@ use starknet_patricia::patricia_merkle_tree::original_skeleton_tree::tree::{ OriginalSkeletonTreeImpl, }; use starknet_patricia::patricia_merkle_tree::types::{NodeIndex, SortedLeafIndices}; -use starknet_patricia::storage::storage_trait::Storage; +use starknet_patricia_storage::storage_trait::Storage; -use crate::block_committer::input::{Config, ContractAddress, StarknetStorageValue}; +use crate::block_committer::input::{ + contract_address_into_node_index, + Config, + StarknetStorageValue, +}; use crate::forest::forest_errors::{ForestError, ForestResult}; use crate::patricia_merkle_tree::leaf::leaf_impl::ContractState; use crate::patricia_merkle_tree::tree::{ @@ -94,7 +99,7 @@ impl<'a> OriginalSkeletonForest<'a> { .get(address) .ok_or(ForestError::MissingSortedLeafIndices(*address))?; let contract_state = original_contracts_trie_leaves - .get(&address.into()) + .get(&contract_address_into_node_index(address)) .ok_or(ForestError::MissingContractCurrentState(*address))?; let config = OriginalSkeletonStorageTrieConfig::new(config.warn_on_trivial_modifications()); diff --git a/crates/starknet_committer/src/forest/skeleton_forest_test.rs b/crates/starknet_committer/src/forest/skeleton_forest_test.rs index e6707f41bd2..2f86419f2ef 100644 --- a/crates/starknet_committer/src/forest/skeleton_forest_test.rs +++ b/crates/starknet_committer/src/forest/skeleton_forest_test.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use pretty_assertions::assert_eq; use rstest::rstest; -use starknet_patricia::felt::Felt; +use starknet_api::core::{ClassHash, ContractAddress, Nonce}; use starknet_patricia::hash::hash_trait::HashOutput; use starknet_patricia::patricia_merkle_tree::external_test_utils::{ create_32_bytes_entry, @@ -16,15 +16,16 @@ use starknet_patricia::patricia_merkle_tree::external_test_utils::{ }; use starknet_patricia::patricia_merkle_tree::original_skeleton_tree::tree::OriginalSkeletonTreeImpl; use starknet_patricia::patricia_merkle_tree::types::{NodeIndex, SortedLeafIndices, SubTreeHeight}; -use starknet_patricia::storage::db_object::DBObject; -use starknet_patricia::storage::map_storage::MapStorage; -use starknet_patricia::storage::storage_trait::{StorageKey, StorageValue}; +use starknet_patricia_storage::db_object::DBObject; +use starknet_patricia_storage::map_storage::MapStorage; +use starknet_patricia_storage::storage_trait::{DbKey, DbValue}; +use starknet_types_core::felt::Felt; use tracing::level_filters::LevelFilter; use crate::block_committer::commit::get_all_modified_indices; use crate::block_committer::input::{ + contract_address_into_node_index, ConfigImpl, - ContractAddress, Input, StarknetStorageKey, StarknetStorageValue, @@ -32,7 +33,7 @@ use crate::block_committer::input::{ }; use crate::forest::original_skeleton_forest::{ForestSortedIndices, OriginalSkeletonForest}; use crate::patricia_merkle_tree::leaf::leaf_impl::ContractState; -use crate::patricia_merkle_tree::types::{ClassHash, CompiledClassHash, Nonce}; +use crate::patricia_merkle_tree::types::CompiledClassHash; macro_rules! compare_skeleton_tree { ($actual_skeleton:expr, $expected_skeleton:expr, $expected_indices:expr) => {{ @@ -44,17 +45,17 @@ macro_rules! compare_skeleton_tree { }}; } -pub(crate) fn create_storage_leaf_entry(val: u128) -> (StorageKey, StorageValue) { +pub(crate) fn create_storage_leaf_entry(val: u128) -> (DbKey, DbValue) { let leaf = StarknetStorageValue(Felt::from(val)); (leaf.get_db_key(&leaf.0.to_bytes_be()), leaf.serialize()) } -pub(crate) fn create_compiled_class_leaf_entry(val: u128) -> (StorageKey, StorageValue) { +pub(crate) fn create_compiled_class_leaf_entry(val: u128) -> (DbKey, DbValue) { let leaf = CompiledClassHash(Felt::from(val)); (leaf.get_db_key(&leaf.0.to_bytes_be()), leaf.serialize()) } -pub(crate) fn create_contract_state_leaf_entry(val: u128) -> (StorageKey, StorageValue) { +pub(crate) fn create_contract_state_leaf_entry(val: u128) -> (DbKey, DbValue) { let felt = Felt::from(val); let leaf = ContractState { nonce: Nonce(felt), @@ -222,7 +223,7 @@ pub(crate) fn create_contract_state_leaf_entry(val: u128) -> (StorageKey, Storag }, storage_tries: HashMap::from([ ( - ContractAddress(Felt::ZERO), + ContractAddress::try_from(Felt::ZERO).unwrap(), OriginalSkeletonTreeImpl { nodes: create_expected_skeleton_nodes( vec![ @@ -241,7 +242,7 @@ pub(crate) fn create_contract_state_leaf_entry(val: u128) -> (StorageKey, Storag } ), ( - ContractAddress(Felt::from(6_u128)), + ContractAddress::try_from(Felt::from(6_u128)).unwrap(), OriginalSkeletonTreeImpl { nodes: create_expected_skeleton_nodes( vec![ @@ -259,7 +260,7 @@ pub(crate) fn create_contract_state_leaf_entry(val: u128) -> (StorageKey, Storag } ), ( - ContractAddress(Felt::from(7_u128)), + ContractAddress::try_from(Felt::from(7_u128)).unwrap(), OriginalSkeletonTreeImpl { nodes: create_expected_skeleton_nodes( vec![ @@ -317,7 +318,7 @@ fn test_create_original_skeleton_forest( .unwrap(); let expected_original_contracts_trie_leaves = expected_original_contracts_trie_leaves .into_iter() - .map(|(address, state)| ((&address).into(), state)) + .map(|(address, state)| (contract_address_into_node_index(&address), state)) .collect(); assert_eq!(original_contracts_trie_leaves, expected_original_contracts_trie_leaves); @@ -334,7 +335,7 @@ fn test_create_original_skeleton_forest( ); for (contract, indices) in expected_storage_tries_sorted_indices { - let contract_address = ContractAddress(Felt::from(contract)); + let contract_address = ContractAddress::try_from(Felt::from(contract)).unwrap(); compare_skeleton_tree!( &actual_forest.storage_tries[&contract_address], &expected_forest.storage_tries[&contract_address], @@ -348,7 +349,8 @@ fn create_contract_leaves(leaves: &[(u128, u128)]) -> HashMap HashOutput { - HashOutput(Felt(Pedersen::hash(&left.0, &right.0))) + HashOutput(Pedersen::hash(left, right)) } } @@ -23,7 +23,7 @@ impl HashFunction for PedersenHashFunction { pub struct PoseidonHashFunction; impl HashFunction for PoseidonHashFunction { fn hash(left: &Felt, right: &Felt) -> HashOutput { - HashOutput(Felt(Poseidon::hash(&left.0, &right.0))) + HashOutput(Poseidon::hash(left, right)) } } @@ -43,19 +43,13 @@ impl TreeHashFunctionImpl { /// impl TreeHashFunction for TreeHashFunctionImpl { fn compute_leaf_hash(contract_state: &ContractState) -> HashOutput { - HashOutput( - Pedersen::hash( - &Pedersen::hash( - &Pedersen::hash( - &contract_state.class_hash.0.into(), - &contract_state.storage_root_hash.0.into(), - ), - &contract_state.nonce.0.into(), - ), - &Self::CONTRACT_STATE_HASH_VERSION.into(), - ) - .into(), - ) + HashOutput(Pedersen::hash( + &Pedersen::hash( + &Pedersen::hash(&contract_state.class_hash.0, &contract_state.storage_root_hash.0), + &contract_state.nonce.0, + ), + &Self::CONTRACT_STATE_HASH_VERSION, + )) } fn compute_node_hash(node_data: &NodeData) -> HashOutput { Self::compute_node_hash_with_inner_hash_function::(node_data) @@ -71,10 +65,7 @@ impl TreeHashFunction for TreeHashFunctionImpl { .expect( "could not parse hex string corresponding to b'CONTRACT_CLASS_LEAF_V0' to Felt", ); - HashOutput( - Poseidon::hash(&contract_class_leaf_version.into(), &compiled_class_hash.0.into()) - .into(), - ) + HashOutput(Poseidon::hash(&contract_class_leaf_version, &compiled_class_hash.0)) } fn compute_node_hash(node_data: &NodeData) -> HashOutput { Self::compute_node_hash_with_inner_hash_function::(node_data) diff --git a/crates/starknet_committer/src/hash_function/hash_test.rs b/crates/starknet_committer/src/hash_function/hash_test.rs index 8e3c7c5b0ab..283d95f5a03 100644 --- a/crates/starknet_committer/src/hash_function/hash_test.rs +++ b/crates/starknet_committer/src/hash_function/hash_test.rs @@ -1,6 +1,6 @@ use hex; use rstest::rstest; -use starknet_patricia::felt::Felt; +use starknet_api::core::{ClassHash, Nonce}; use starknet_patricia::hash::hash_trait::HashOutput; use starknet_patricia::patricia_merkle_tree::node_data::inner_node::{ BinaryData, @@ -10,12 +10,13 @@ use starknet_patricia::patricia_merkle_tree::node_data::inner_node::{ PathToBottom, }; use starknet_patricia::patricia_merkle_tree::updated_skeleton_tree::hash_function::TreeHashFunction; +use starknet_types_core::felt::Felt; use starknet_types_core::hash::Pedersen; use crate::block_committer::input::StarknetStorageValue; use crate::hash_function::hash::TreeHashFunctionImpl; use crate::patricia_merkle_tree::leaf::leaf_impl::ContractState; -use crate::patricia_merkle_tree::types::{ClassHash, CompiledClassHash, Nonce}; +use crate::patricia_merkle_tree::types::CompiledClassHash; #[rstest] // Random StateTreeTuples and the expected hash results were generated and computed elsewhere. @@ -97,10 +98,7 @@ fn test_tree_hash_function_impl_binary_node( TreeHashFunctionImpl::compute_node_hash(&NodeData::::Binary( BinaryData { left_hash: HashOutput(left_hash), right_hash: HashOutput(right_hash) }, )); - assert_eq!( - hash_output, - HashOutput(Pedersen::hash(&left_hash.into(), &right_hash.into()).into()) - ); + assert_eq!(hash_output, HashOutput(Pedersen::hash(&left_hash, &right_hash))); assert_eq!(hash_output, HashOutput(expected_hash)); } @@ -126,9 +124,8 @@ fn test_tree_hash_function_impl_edge_node( .unwrap(), }), ); - let direct_hash_computation = HashOutput( - Felt::from(Pedersen::hash(&bottom_hash.into(), &edge_path.into())) + length.into(), - ); + let direct_hash_computation = + HashOutput(Pedersen::hash(&bottom_hash, &edge_path.into()) + Felt::from(length)); assert_eq!(hash_output, HashOutput(expected_hash)); assert_eq!(hash_output, direct_hash_computation); } diff --git a/crates/starknet_committer/src/patricia_merkle_tree/leaf/leaf_impl.rs b/crates/starknet_committer/src/patricia_merkle_tree/leaf/leaf_impl.rs index 0e7d3df7ce3..2a8c8a2d916 100644 --- a/crates/starknet_committer/src/patricia_merkle_tree/leaf/leaf_impl.rs +++ b/crates/starknet_committer/src/patricia_merkle_tree/leaf/leaf_impl.rs @@ -1,14 +1,18 @@ -use starknet_patricia::felt::Felt; +use starknet_api::core::{ClassHash, Nonce}; use starknet_patricia::hash::hash_trait::HashOutput; use starknet_patricia::patricia_merkle_tree::filled_tree::tree::{FilledTree, FilledTreeImpl}; use starknet_patricia::patricia_merkle_tree::node_data::errors::{LeafError, LeafResult}; use starknet_patricia::patricia_merkle_tree::node_data::leaf::{Leaf, LeafModifications}; use starknet_patricia::patricia_merkle_tree::types::NodeIndex; use starknet_patricia::patricia_merkle_tree::updated_skeleton_tree::tree::UpdatedSkeletonTreeImpl; +use starknet_patricia_storage::db_object::HasStaticPrefix; +use starknet_patricia_storage::storage_trait::DbKeyPrefix; +use starknet_types_core::felt::Felt; +use super::leaf_serde::CommitterLeafPrefix; use crate::block_committer::input::StarknetStorageValue; use crate::hash_function::hash::TreeHashFunctionImpl; -use crate::patricia_merkle_tree::types::{ClassHash, CompiledClassHash, Nonce}; +use crate::patricia_merkle_tree::types::CompiledClassHash; #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct ContractState { @@ -17,6 +21,12 @@ pub struct ContractState { pub class_hash: ClassHash, } +impl HasStaticPrefix for StarknetStorageValue { + fn get_static_prefix() -> DbKeyPrefix { + CommitterLeafPrefix::StorageLeaf.into() + } +} + impl Leaf for StarknetStorageValue { type Input = Self; type Output = (); @@ -30,6 +40,12 @@ impl Leaf for StarknetStorageValue { } } +impl HasStaticPrefix for CompiledClassHash { + fn get_static_prefix() -> DbKeyPrefix { + CommitterLeafPrefix::CompiledClassLeaf.into() + } +} + impl Leaf for CompiledClassHash { type Input = Self; type Output = (); @@ -43,6 +59,12 @@ impl Leaf for CompiledClassHash { } } +impl HasStaticPrefix for ContractState { + fn get_static_prefix() -> DbKeyPrefix { + CommitterLeafPrefix::StateTreeLeaf.into() + } +} + impl Leaf for ContractState { type Input = ContractStateInput; type Output = FilledTreeImpl; diff --git a/crates/starknet_committer/src/patricia_merkle_tree/leaf/leaf_serde.rs b/crates/starknet_committer/src/patricia_merkle_tree/leaf/leaf_serde.rs index 2bebaa28e65..4d6f7888be1 100644 --- a/crates/starknet_committer/src/patricia_merkle_tree/leaf/leaf_serde.rs +++ b/crates/starknet_committer/src/patricia_merkle_tree/leaf/leaf_serde.rs @@ -1,70 +1,72 @@ use std::collections::HashMap; use serde_json::Value; -use starknet_patricia::felt::Felt; +use starknet_api::core::{ClassHash, Nonce}; use starknet_patricia::hash::hash_trait::HashOutput; use starknet_patricia::patricia_merkle_tree::types::SubTreeHeight; -use starknet_patricia::storage::db_object::{DBObject, Deserializable}; -use starknet_patricia::storage::errors::DeserializationError; -use starknet_patricia::storage::storage_trait::{StarknetPrefix, StorageValue}; +use starknet_patricia_storage::db_object::{DBObject, Deserializable}; +use starknet_patricia_storage::errors::DeserializationError; +use starknet_patricia_storage::storage_trait::{DbKeyPrefix, DbValue}; +use starknet_types_core::felt::Felt; use crate::block_committer::input::StarknetStorageValue; use crate::patricia_merkle_tree::leaf::leaf_impl::ContractState; -use crate::patricia_merkle_tree::types::{ClassHash, CompiledClassHash, Nonce}; +use crate::patricia_merkle_tree::types::{fixed_hex_string_no_prefix, CompiledClassHash}; -impl DBObject for StarknetStorageValue { - /// Serializes the value into a 32-byte vector. - fn serialize(&self) -> StorageValue { - StorageValue(self.0.to_bytes_be().to_vec()) +#[derive(Clone, Debug)] +pub enum CommitterLeafPrefix { + StorageLeaf, + StateTreeLeaf, + CompiledClassLeaf, +} + +impl From for DbKeyPrefix { + fn from(value: CommitterLeafPrefix) -> Self { + match value { + CommitterLeafPrefix::StorageLeaf => Self::new(b"starknet_storage_leaf"), + CommitterLeafPrefix::StateTreeLeaf => Self::new(b"contract_state"), + CommitterLeafPrefix::CompiledClassLeaf => Self::new(b"contract_class_leaf"), + } } +} - fn get_prefix(&self) -> Vec { - StarknetPrefix::StorageLeaf.to_storage_prefix() +impl DBObject for StarknetStorageValue { + /// Serializes the value into a 32-byte vector. + fn serialize(&self) -> DbValue { + DbValue(self.0.to_bytes_be().to_vec()) } } impl DBObject for CompiledClassHash { /// Creates a json string describing the leaf and casts it into a byte vector. - fn serialize(&self) -> StorageValue { - let json_string = format!(r#"{{"compiled_class_hash": "{}"}}"#, self.0.to_hex()); - StorageValue(json_string.into_bytes()) - } - - fn get_prefix(&self) -> Vec { - StarknetPrefix::CompiledClassLeaf.to_storage_prefix() + fn serialize(&self) -> DbValue { + let json_string = format!(r#"{{"compiled_class_hash": "{}"}}"#, self.0.to_hex_string()); + DbValue(json_string.into_bytes()) } } impl DBObject for ContractState { /// Creates a json string describing the leaf and casts it into a byte vector. - fn serialize(&self) -> StorageValue { + fn serialize(&self) -> DbValue { let json_string = format!( r#"{{"contract_hash": "{}", "storage_commitment_tree": {{"root": "{}", "height": {}}}, "nonce": "{}"}}"#, - self.class_hash.0.to_fixed_hex_string(), - self.storage_root_hash.0.to_fixed_hex_string(), + fixed_hex_string_no_prefix(&self.class_hash.0), + fixed_hex_string_no_prefix(&self.storage_root_hash.0), SubTreeHeight::ACTUAL_HEIGHT, - self.nonce.0.to_hex(), + self.nonce.0.to_hex_string(), ); - StorageValue(json_string.into_bytes()) - } - - fn get_prefix(&self) -> Vec { - StarknetPrefix::StateTreeLeaf.to_storage_prefix() + DbValue(json_string.into_bytes()) } } impl Deserializable for StarknetStorageValue { - fn deserialize(value: &StorageValue) -> Result { + fn deserialize(value: &DbValue) -> Result { Ok(Self(Felt::from_bytes_be_slice(&value.0))) } - - fn prefix() -> Vec { - StarknetPrefix::StorageLeaf.to_storage_prefix() - } } impl Deserializable for CompiledClassHash { - fn deserialize(value: &StorageValue) -> Result { + fn deserialize(value: &DbValue) -> Result { let json_str = std::str::from_utf8(&value.0)?; let map: HashMap = serde_json::from_str(json_str)?; let hash_as_hex = map @@ -72,14 +74,10 @@ impl Deserializable for CompiledClassHash { .ok_or(DeserializationError::NonExistingKey("compiled_class_hash".to_string()))?; Ok(Self::from_hex(hash_as_hex)?) } - - fn prefix() -> Vec { - StarknetPrefix::CompiledClassLeaf.to_storage_prefix() - } } impl Deserializable for ContractState { - fn deserialize(value: &StorageValue) -> Result { + fn deserialize(value: &DbValue) -> Result { let json_str = std::str::from_utf8(&value.0)?; let deserialized_map: Value = serde_json::from_str(json_str)?; let get_leaf_key = |map: &Value, key: &str| { @@ -97,15 +95,11 @@ impl Deserializable for ContractState { get_leaf_key(get_key_from_map(&deserialized_map, "storage_commitment_tree")?, "root")?; Ok(Self { - nonce: Nonce::from_hex(&nonce_as_hex)?, + nonce: Nonce(Felt::from_hex(&nonce_as_hex)?), storage_root_hash: HashOutput::from_hex(&root_hash_as_hex)?, - class_hash: ClassHash::from_hex(&class_hash_as_hex)?, + class_hash: ClassHash(Felt::from_hex(&class_hash_as_hex)?), }) } - - fn prefix() -> Vec { - StarknetPrefix::StateTreeLeaf.to_storage_prefix() - } } fn get_key_from_map<'a>(map: &'a Value, key: &str) -> Result<&'a Value, DeserializationError> { diff --git a/crates/starknet_committer/src/patricia_merkle_tree/leaf/leaf_serde_test.rs b/crates/starknet_committer/src/patricia_merkle_tree/leaf/leaf_serde_test.rs index f1c6395facd..dff00c5622f 100644 --- a/crates/starknet_committer/src/patricia_merkle_tree/leaf/leaf_serde_test.rs +++ b/crates/starknet_committer/src/patricia_merkle_tree/leaf/leaf_serde_test.rs @@ -1,15 +1,17 @@ use std::fmt::Debug; use rstest::rstest; -use starknet_patricia::felt::Felt; +use starknet_api::core::{ClassHash, Nonce}; +use starknet_api::felt; use starknet_patricia::hash::hash_trait::HashOutput; use starknet_patricia::patricia_merkle_tree::node_data::leaf::Leaf; -use starknet_patricia::storage::db_object::Deserializable; -use starknet_patricia::storage::storage_trait::StorageValue; +use starknet_patricia_storage::db_object::Deserializable; +use starknet_patricia_storage::storage_trait::DbValue; +use starknet_types_core::felt::Felt; use crate::block_committer::input::StarknetStorageValue; use crate::patricia_merkle_tree::leaf::leaf_impl::ContractState; -use crate::patricia_merkle_tree::types::{ClassHash, CompiledClassHash, Nonce}; +use crate::patricia_merkle_tree::types::CompiledClassHash; #[rstest] #[case::zero_storage_leaf(StarknetStorageValue(Felt::ZERO))] @@ -45,7 +47,7 @@ fn test_default_is_empty(#[case] leaf: L) { #[rstest] fn test_deserialize_contract_state_without_nonce() { // Simulate a serialized JSON without the "nonce" field. - let serialized = StorageValue( + let serialized = DbValue( r#" { "contract_hash": "0x1234abcd", @@ -61,7 +63,7 @@ fn test_deserialize_contract_state_without_nonce() { let contract_state = ContractState::deserialize(&serialized).unwrap(); // Validate the fields (nonce should be the default "0") - assert_eq!(contract_state.nonce, Nonce::from_hex("0x0").unwrap()); - assert_eq!(contract_state.class_hash, ClassHash::from_hex("0x1234abcd").unwrap()); + assert_eq!(contract_state.nonce, Nonce(Felt::ZERO)); + assert_eq!(contract_state.class_hash, ClassHash(felt!("0x1234abcd"))); assert_eq!(contract_state.storage_root_hash, HashOutput::from_hex("0x5678").unwrap()); } diff --git a/crates/starknet_committer/src/patricia_merkle_tree/types.rs b/crates/starknet_committer/src/patricia_merkle_tree/types.rs index ec88e7b2566..60ef41e7342 100644 --- a/crates/starknet_committer/src/patricia_merkle_tree/types.rs +++ b/crates/starknet_committer/src/patricia_merkle_tree/types.rs @@ -1,29 +1,21 @@ use std::collections::HashMap; -use starknet_patricia::felt::Felt; +use starknet_api::core::{ClassHash, ContractAddress}; use starknet_patricia::impl_from_hex_for_felt_wrapper; use starknet_patricia::patricia_merkle_tree::filled_tree::tree::FilledTreeImpl; use starknet_patricia::patricia_merkle_tree::types::NodeIndex; -use starknet_types_core::felt::FromStrError; +use starknet_types_core::felt::{Felt, FromStrError}; -use crate::block_committer::input::{ContractAddress, StarknetStorageValue}; +use crate::block_committer::input::StarknetStorageValue; use crate::patricia_merkle_tree::leaf::leaf_impl::ContractState; -// TODO(Nimrod, 1/6/2024): Use the ClassHash defined in starknet-types-core when available. -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)] -pub struct ClassHash(pub Felt); - -impl From<&ClassHash> for NodeIndex { - fn from(val: &ClassHash) -> Self { - NodeIndex::from_leaf_felt(&val.0) - } +pub fn fixed_hex_string_no_prefix(felt: &Felt) -> String { + format!("{:064x}", felt) } -impl_from_hex_for_felt_wrapper!(ClassHash); -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)] -pub struct Nonce(pub Felt); - -impl_from_hex_for_felt_wrapper!(Nonce); +pub fn class_hash_into_node_index(class_hash: &ClassHash) -> NodeIndex { + NodeIndex::from_leaf_felt(&class_hash.0) +} #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] pub struct CompiledClassHash(pub Felt); diff --git a/crates/starknet_committer/src/patricia_merkle_tree/types_test.rs b/crates/starknet_committer/src/patricia_merkle_tree/types_test.rs index ff8db54a47a..2c7969f0cb4 100644 --- a/crates/starknet_committer/src/patricia_merkle_tree/types_test.rs +++ b/crates/starknet_committer/src/patricia_merkle_tree/types_test.rs @@ -1,8 +1,10 @@ use rstest::rstest; -use starknet_patricia::felt::Felt; +use starknet_api::core::ContractAddress; use starknet_patricia::patricia_merkle_tree::types::NodeIndex; +use starknet_types_core::felt::Felt; -use crate::block_committer::input::{ContractAddress, StarknetStorageKey}; +use crate::block_committer::input::{contract_address_into_node_index, StarknetStorageKey}; +use crate::patricia_merkle_tree::types::fixed_hex_string_no_prefix; #[rstest] fn test_cast_to_node_index( @@ -11,9 +13,20 @@ fn test_cast_to_node_index( ) { let expected_node_index = NodeIndex::FIRST_LEAF + leaf_index; let actual: NodeIndex = if bool_from_contract_address { - (&ContractAddress(Felt::from(leaf_index))).into() + contract_address_into_node_index( + &ContractAddress::try_from(Felt::from(leaf_index)).unwrap(), + ) } else { (&StarknetStorageKey(Felt::from(leaf_index))).into() }; assert_eq!(actual, expected_node_index); } + +#[rstest] +fn test_fixed_hex_string_no_prefix( + #[values(Felt::ZERO, Felt::ONE, Felt::MAX, Felt::from(u128::MAX))] value: Felt, +) { + let fixed_hex = fixed_hex_string_no_prefix(&value); + assert_eq!(fixed_hex.len(), 64); + assert_eq!(Felt::from_hex(&fixed_hex).unwrap(), value); +} diff --git a/crates/committer_cli/BUILD b/crates/starknet_committer_and_os_cli/BUILD similarity index 100% rename from crates/committer_cli/BUILD rename to crates/starknet_committer_and_os_cli/BUILD diff --git a/crates/committer_cli/Cargo.toml b/crates/starknet_committer_and_os_cli/Cargo.toml similarity index 69% rename from crates/committer_cli/Cargo.toml rename to crates/starknet_committer_and_os_cli/Cargo.toml index e29ad842b25..4abcb4ce265 100644 --- a/crates/committer_cli/Cargo.toml +++ b/crates/starknet_committer_and_os_cli/Cargo.toml @@ -1,6 +1,5 @@ [package] -# TODO(Dori, 15/8/2024): Rename to starknet_committer_cli. -name = "committer_cli" +name = "starknet_committer_and_os_cli" version.workspace = true edition.workspace = true repository.workspace = true @@ -11,12 +10,16 @@ description = "Cli for the committer package." workspace = true [dev-dependencies] +assert_matches.workspace = true criterion = { workspace = true, features = ["html_reports"] } futures.workspace = true pretty_assertions.workspace = true tempfile.workspace = true +# TODO(Amos): Add `testing` feature and move Python test dependencies under it. [dependencies] +cairo-lang-starknet-classes.workspace = true +cairo-vm.workspace = true # Should be moved under `testing` feature, when it exists. clap = { workspace = true, features = ["cargo", "derive"] } derive_more.workspace = true ethnum.workspace = true @@ -29,7 +32,10 @@ serde_repr.workspace = true starknet-types-core.workspace = true starknet_api.workspace = true starknet_committer.workspace = true +# Should be moved under `testing` feature, when it exists. +starknet_os = { workspace = true, features = ["deserialize", "testing"] } starknet_patricia = { workspace = true, features = ["testing"] } +starknet_patricia_storage.workspace = true strum.workspace = true strum_macros.workspace = true thiserror.workspace = true @@ -39,8 +45,8 @@ tracing.workspace = true [[bench]] harness = false -name = "committer_bench" -path = "benches/committer_bench.rs" +name = "starknet_committer_and_os_cli" +path = "benches/main.rs" # Optional dependencies required for tests and the testing feature. # See [here](https://github.com/bnjbvr/cargo-machete/issues/128). diff --git a/crates/committer_cli/benches/bench_split_and_prepare_post.sh b/crates/starknet_committer_and_os_cli/benches/bench_split_and_prepare_post.sh similarity index 86% rename from crates/committer_cli/benches/bench_split_and_prepare_post.sh rename to crates/starknet_committer_and_os_cli/benches/bench_split_and_prepare_post.sh index 2bc4e33453a..6ff8845ada8 100644 --- a/crates/committer_cli/benches/bench_split_and_prepare_post.sh +++ b/crates/starknet_committer_and_os_cli/benches/bench_split_and_prepare_post.sh @@ -5,10 +5,10 @@ set -e benchmarks_list=${1} benchmark_results=${2} # Benchmark the new code, splitting the benchmarks -# TODO: split the output file instead. +# TODO(Aner): split the output file instead. cat ${benchmarks_list} | while read line; do - cargo bench -p committer_cli $line > ${line}.txt; + cargo bench -p starknet_committer_and_os_cli $line > ${line}.txt; sed -i '/'"${line}"'/,$!d' ${line}.txt; done diff --git a/crates/committer_cli/benches/committer_bench.rs b/crates/starknet_committer_and_os_cli/benches/main.rs similarity index 86% rename from crates/committer_cli/benches/committer_bench.rs rename to crates/starknet_committer_and_os_cli/benches/main.rs index 2d5947466a7..f5b9fa1dce1 100644 --- a/crates/committer_cli/benches/committer_bench.rs +++ b/crates/starknet_committer_and_os_cli/benches/main.rs @@ -2,20 +2,20 @@ // This file is for benchmarking the committer flow. // The input files for the different benchmarks are downloaded from GCS, using the prefix stored in -// committer_cli/src/tests/flow_test_files_prefix. In order to update them, generate a new random -// prefix (the hash of the initial new commit can be used) and update it in the mentioned file. -// Then upload the new files to GCS with this new prefix (run e.g., +// starknet_committer_and_os_cli/src/committer_cli/tests/flow_test_files_prefix. In order to +// update them, generate a new random prefix (the hash of the initial new commit can be used) and +// update it in the mentioned file. Then upload the new files to GCS with this new prefix (run e.g., // gcloud storage cp LOCAL_FILE gs://committer-testing-artifacts/NEW_PREFIX/tree_flow_inputs.json). use std::collections::HashMap; -use committer_cli::commands::commit; -use committer_cli::parse_input::read::parse_input; -use committer_cli::tests::utils::parse_from_python::TreeFlowInput; use criterion::{criterion_group, criterion_main, BatchSize, Criterion}; use starknet_committer::block_committer::input::StarknetStorageValue; use starknet_committer::hash_function::hash::TreeHashFunctionImpl; use starknet_committer::patricia_merkle_tree::tree::OriginalSkeletonStorageTrieConfig; +use starknet_committer_and_os_cli::committer_cli::commands::commit; +use starknet_committer_and_os_cli::committer_cli::parse_input::read::parse_input; +use starknet_committer_and_os_cli::committer_cli::tests::utils::parse_from_python::TreeFlowInput; use starknet_patricia::patricia_merkle_tree::external_test_utils::tree_computation_flow; use starknet_patricia::patricia_merkle_tree::node_data::leaf::LeafModifications; use starknet_patricia::patricia_merkle_tree::types::NodeIndex; diff --git a/crates/starknet_committer_and_os_cli/src/block_hash_cli.rs b/crates/starknet_committer_and_os_cli/src/block_hash_cli.rs new file mode 100644 index 00000000000..ea4948a04a0 --- /dev/null +++ b/crates/starknet_committer_and_os_cli/src/block_hash_cli.rs @@ -0,0 +1,2 @@ +pub mod run_block_hash_cli; +pub mod tests; diff --git a/crates/starknet_committer_and_os_cli/src/block_hash_cli/run_block_hash_cli.rs b/crates/starknet_committer_and_os_cli/src/block_hash_cli/run_block_hash_cli.rs new file mode 100644 index 00000000000..a742c11136c --- /dev/null +++ b/crates/starknet_committer_and_os_cli/src/block_hash_cli/run_block_hash_cli.rs @@ -0,0 +1,63 @@ +use clap::{Parser, Subcommand}; +use starknet_api::block_hash::block_hash_calculator::{ + calculate_block_commitments, + calculate_block_hash, +}; +use tracing::info; + +use crate::block_hash_cli::tests::python_tests::BlockHashPythonTestRunner; +use crate::committer_cli::block_hash::{BlockCommitmentsInput, BlockHashInput}; +use crate::shared_utils::read::{load_input, write_to_file}; +use crate::shared_utils::types::{run_python_test, IoArgs, PythonTestArg}; + +#[derive(Parser, Debug)] +pub struct BlockHashCliCommand { + #[clap(subcommand)] + command: Command, +} + +#[derive(Debug, Subcommand)] +enum Command { + /// Calculates the block hash. + BlockHash { + #[clap(flatten)] + io_args: IoArgs, + }, + /// Calculates commitments needed for the block hash. + BlockHashCommitments { + #[clap(flatten)] + io_args: IoArgs, + }, + PythonTest(PythonTestArg), +} + +pub async fn run_block_hash_cli(block_hash_cli_command: BlockHashCliCommand) { + info!("Starting block-hash-cli with command: \n{:?}", block_hash_cli_command); + match block_hash_cli_command.command { + Command::BlockHash { io_args: IoArgs { input_path, output_path } } => { + let block_hash_input: BlockHashInput = load_input(input_path); + info!("Successfully loaded block hash input."); + let block_hash = + calculate_block_hash(block_hash_input.header, block_hash_input.block_commitments) + .unwrap_or_else(|error| panic!("Failed to calculate block hash: {}", error)); + write_to_file(&output_path, &block_hash); + info!("Successfully computed block hash {:?}.", block_hash); + } + + Command::BlockHashCommitments { io_args: IoArgs { input_path, output_path } } => { + let commitments_input: BlockCommitmentsInput = load_input(input_path); + info!("Successfully loaded block hash commitment input."); + let commitments = calculate_block_commitments( + &commitments_input.transactions_data, + &commitments_input.state_diff, + commitments_input.l1_da_mode, + &commitments_input.starknet_version, + ); + write_to_file(&output_path, &commitments); + info!("Successfully computed block hash commitment: \n{:?}", commitments); + } + Command::PythonTest(python_test_arg) => { + run_python_test::(python_test_arg).await; + } + } +} diff --git a/crates/starknet_committer_and_os_cli/src/block_hash_cli/tests.rs b/crates/starknet_committer_and_os_cli/src/block_hash_cli/tests.rs new file mode 100644 index 00000000000..8147ce14697 --- /dev/null +++ b/crates/starknet_committer_and_os_cli/src/block_hash_cli/tests.rs @@ -0,0 +1,2 @@ +pub mod objects; +pub mod python_tests; diff --git a/crates/committer_cli/src/tests/utils/objects.rs b/crates/starknet_committer_and_os_cli/src/block_hash_cli/tests/objects.rs similarity index 98% rename from crates/committer_cli/src/tests/utils/objects.rs rename to crates/starknet_committer_and_os_cli/src/block_hash_cli/tests/objects.rs index 25bcb4ef6ea..047b3536648 100644 --- a/crates/committer_cli/src/tests/utils/objects.rs +++ b/crates/starknet_committer_and_os_cli/src/block_hash_cli/tests/objects.rs @@ -83,7 +83,6 @@ pub(crate) fn get_thin_state_diff() -> ThinStateDiff { nonces: indexmap! { ContractAddress::from(3_u128) => Nonce(Felt::from_bytes_be_slice(&[4_u8])), }, - replaced_classes: indexmap! {}, } } diff --git a/crates/starknet_committer_and_os_cli/src/block_hash_cli/tests/python_tests.rs b/crates/starknet_committer_and_os_cli/src/block_hash_cli/tests/python_tests.rs new file mode 100644 index 00000000000..3eaa3e45fd1 --- /dev/null +++ b/crates/starknet_committer_and_os_cli/src/block_hash_cli/tests/python_tests.rs @@ -0,0 +1,84 @@ +use starknet_api::block_hash::block_hash_calculator::{ + TransactionHashingData, + TransactionOutputForHash, +}; +use starknet_api::state::ThinStateDiff; +use starknet_api::transaction::TransactionExecutionStatus; + +use crate::block_hash_cli::tests::objects::{ + get_thin_state_diff, + get_transaction_output_for_hash, + get_tx_data, +}; +use crate::shared_utils::types::{PythonTestError, PythonTestResult, PythonTestRunner}; + +pub type BlockHashPythonTestError = PythonTestError<()>; +pub type BlockHashPythonTestResult = PythonTestResult<()>; + +// Enum representing different Python tests. +pub enum BlockHashPythonTestRunner { + ParseTxOutput, + ParseStateDiff, + ParseTxData, +} + +/// Implements conversion from a string to the test runner. +impl TryFrom for BlockHashPythonTestRunner { + type Error = BlockHashPythonTestError; + + fn try_from(value: String) -> Result { + match value.as_str() { + "parse_tx_output_test" => Ok(Self::ParseTxOutput), + "parse_state_diff_test" => Ok(Self::ParseStateDiff), + "parse_tx_data_test" => Ok(Self::ParseTxData), + _ => Err(PythonTestError::UnknownTestName(value)), + } + } +} + +impl PythonTestRunner for BlockHashPythonTestRunner { + type SpecificError = (); + /// Runs the test with the given arguments. + async fn run(&self, input: Option<&str>) -> BlockHashPythonTestResult { + match self { + Self::ParseTxOutput => { + let tx_output: TransactionOutputForHash = + serde_json::from_str(Self::non_optional_input(input)?)?; + Ok(parse_tx_output_test(tx_output)) + } + Self::ParseStateDiff => { + let tx_output: ThinStateDiff = + serde_json::from_str(Self::non_optional_input(input)?)?; + Ok(parse_state_diff_test(tx_output)) + } + Self::ParseTxData => { + let tx_data: TransactionHashingData = + serde_json::from_str(Self::non_optional_input(input)?)?; + Ok(parse_tx_data_test(tx_data)) + } + } + } +} + +pub(crate) fn parse_tx_output_test(tx_execution_info: TransactionOutputForHash) -> String { + let expected_object = get_transaction_output_for_hash(&tx_execution_info.execution_status); + is_success_string(expected_object == tx_execution_info) +} + +pub(crate) fn parse_state_diff_test(state_diff: ThinStateDiff) -> String { + let expected_object = get_thin_state_diff(); + is_success_string(expected_object == state_diff) +} + +pub(crate) fn parse_tx_data_test(tx_data: TransactionHashingData) -> String { + let expected_object = get_tx_data(&TransactionExecutionStatus::Succeeded); + is_success_string(expected_object == tx_data) +} + +fn is_success_string(is_success: bool) -> String { + match is_success { + true => "Success", + false => "Failure", + } + .to_owned() +} diff --git a/crates/committer_cli/src/lib.rs b/crates/starknet_committer_and_os_cli/src/committer_cli.rs similarity index 79% rename from crates/committer_cli/src/lib.rs rename to crates/starknet_committer_and_os_cli/src/committer_cli.rs index 7f8bb26aeea..ea14e207cc5 100644 --- a/crates/committer_cli/src/lib.rs +++ b/crates/starknet_committer_and_os_cli/src/committer_cli.rs @@ -2,5 +2,5 @@ pub mod block_hash; pub mod commands; pub mod filled_tree_output; pub mod parse_input; +pub mod run_committer_cli; pub mod tests; -pub mod tracing_utils; diff --git a/crates/committer_cli/src/block_hash.rs b/crates/starknet_committer_and_os_cli/src/committer_cli/block_hash.rs similarity index 100% rename from crates/committer_cli/src/block_hash.rs rename to crates/starknet_committer_and_os_cli/src/committer_cli/block_hash.rs diff --git a/crates/committer_cli/src/commands.rs b/crates/starknet_committer_and_os_cli/src/committer_cli/commands.rs similarity index 76% rename from crates/committer_cli/src/commands.rs rename to crates/starknet_committer_and_os_cli/src/committer_cli/commands.rs index fad171a4cb3..55054d7a467 100644 --- a/crates/committer_cli/src/commands.rs +++ b/crates/starknet_committer_and_os_cli/src/committer_cli/commands.rs @@ -5,15 +5,19 @@ use tracing::level_filters::LevelFilter; use tracing_subscriber::reload::Handle; use tracing_subscriber::Registry; -use crate::filled_tree_output::filled_forest::SerializedForest; -use crate::parse_input::read::{parse_input, write_to_file}; +use crate::committer_cli::filled_tree_output::filled_forest::SerializedForest; +use crate::committer_cli::parse_input::cast::InputImpl; +use crate::committer_cli::parse_input::raw_input::RawInput; +use crate::shared_utils::read::{load_input, write_to_file}; pub async fn parse_and_commit( - input_string: &str, + input_path: String, output_path: String, log_filter_handle: Handle, ) { - let input = parse_input(input_string).expect("Failed to parse the given input."); + let input: InputImpl = load_input::(input_path) + .try_into() + .expect("Failed to convert RawInput to InputImpl."); info!( "Parsed committer input successfully. Original Contracts Trie Root Hash: {:?}, Original Classes Trie Root Hash: {:?}", diff --git a/crates/committer_cli/src/filled_tree_output.rs b/crates/starknet_committer_and_os_cli/src/committer_cli/filled_tree_output.rs similarity index 100% rename from crates/committer_cli/src/filled_tree_output.rs rename to crates/starknet_committer_and_os_cli/src/committer_cli/filled_tree_output.rs diff --git a/crates/committer_cli/src/filled_tree_output/filled_forest.rs b/crates/starknet_committer_and_os_cli/src/committer_cli/filled_tree_output/filled_forest.rs similarity index 91% rename from crates/committer_cli/src/filled_tree_output/filled_forest.rs rename to crates/starknet_committer_and_os_cli/src/committer_cli/filled_tree_output/filled_forest.rs index 710f5202fc0..a6d900a0864 100644 --- a/crates/committer_cli/src/filled_tree_output/filled_forest.rs +++ b/crates/starknet_committer_and_os_cli/src/committer_cli/filled_tree_output/filled_forest.rs @@ -1,6 +1,6 @@ use serde::Serialize; use starknet_committer::forest::filled_forest::FilledForest; -use starknet_patricia::storage::map_storage::MapStorage; +use starknet_patricia_storage::map_storage::MapStorage; pub struct SerializedForest(pub FilledForest); @@ -24,8 +24,8 @@ impl SerializedForest { let compiled_class_root_hash = self.0.get_compiled_class_root_hash().0; Output { storage, - contract_storage_root_hash: contract_storage_root_hash.to_hex(), - compiled_class_root_hash: compiled_class_root_hash.to_hex(), + contract_storage_root_hash: contract_storage_root_hash.to_hex_string(), + compiled_class_root_hash: compiled_class_root_hash.to_hex_string(), } } } diff --git a/crates/committer_cli/src/parse_input.rs b/crates/starknet_committer_and_os_cli/src/committer_cli/parse_input.rs similarity index 100% rename from crates/committer_cli/src/parse_input.rs rename to crates/starknet_committer_and_os_cli/src/committer_cli/parse_input.rs diff --git a/crates/committer_cli/src/parse_input/cast.rs b/crates/starknet_committer_and_os_cli/src/committer_cli/parse_input/cast.rs similarity index 82% rename from crates/committer_cli/src/parse_input/cast.rs rename to crates/starknet_committer_and_os_cli/src/committer_cli/parse_input/cast.rs index 155cd9db3c7..a784025ca66 100644 --- a/crates/committer_cli/src/parse_input/cast.rs +++ b/crates/starknet_committer_and_os_cli/src/committer_cli/parse_input/cast.rs @@ -1,20 +1,20 @@ use std::collections::HashMap; +use starknet_api::core::{ClassHash, ContractAddress, Nonce}; use starknet_committer::block_committer::input::{ ConfigImpl, - ContractAddress, Input, StarknetStorageKey, StarknetStorageValue, StateDiff, }; -use starknet_committer::patricia_merkle_tree::types::{ClassHash, CompiledClassHash, Nonce}; -use starknet_patricia::felt::Felt; +use starknet_committer::patricia_merkle_tree::types::CompiledClassHash; use starknet_patricia::hash::hash_trait::HashOutput; -use starknet_patricia::storage::errors::DeserializationError; -use starknet_patricia::storage::storage_trait::{StorageKey, StorageValue}; +use starknet_patricia_storage::errors::DeserializationError; +use starknet_patricia_storage::storage_trait::{DbKey, DbValue}; +use starknet_types_core::felt::Felt; -use crate::parse_input::raw_input::RawInput; +use crate::committer_cli::parse_input::raw_input::RawInput; pub type InputImpl = Input; @@ -23,7 +23,7 @@ impl TryFrom for InputImpl { fn try_from(raw_input: RawInput) -> Result { let mut storage = HashMap::new(); for entry in raw_input.storage { - add_unique(&mut storage, "storage", StorageKey(entry.key), StorageValue(entry.value))?; + add_unique(&mut storage, "storage", DbKey(entry.key), DbValue(entry.value))?; } let mut address_to_class_hash = HashMap::new(); @@ -31,7 +31,7 @@ impl TryFrom for InputImpl { add_unique( &mut address_to_class_hash, "address to class hash", - ContractAddress(Felt::from_bytes_be_slice(&entry.key)), + ContractAddress::try_from(Felt::from_bytes_be_slice(&entry.key))?, ClassHash(Felt::from_bytes_be_slice(&entry.value)), )?; } @@ -41,7 +41,7 @@ impl TryFrom for InputImpl { add_unique( &mut address_to_nonce, "address to nonce", - ContractAddress(Felt::from_bytes_be_slice(&entry.key)), + ContractAddress::try_from(Felt::from_bytes_be_slice(&entry.key))?, Nonce(Felt::from_bytes_be_slice(&entry.value)), )?; } @@ -71,7 +71,7 @@ impl TryFrom for InputImpl { add_unique( &mut storage_updates, "starknet storage updates", - ContractAddress(Felt::from_bytes_be_slice(&outer_entry.address)), + ContractAddress::try_from(Felt::from_bytes_be_slice(&outer_entry.address))?, inner_map, )?; } diff --git a/crates/committer_cli/src/parse_input/raw_input.rs b/crates/starknet_committer_and_os_cli/src/committer_cli/parse_input/raw_input.rs similarity index 100% rename from crates/committer_cli/src/parse_input/raw_input.rs rename to crates/starknet_committer_and_os_cli/src/committer_cli/parse_input/raw_input.rs diff --git a/crates/starknet_committer_and_os_cli/src/committer_cli/parse_input/read.rs b/crates/starknet_committer_and_os_cli/src/committer_cli/parse_input/read.rs new file mode 100644 index 00000000000..275afd80768 --- /dev/null +++ b/crates/starknet_committer_and_os_cli/src/committer_cli/parse_input/read.rs @@ -0,0 +1,14 @@ +use starknet_patricia_storage::errors::DeserializationError; + +use crate::committer_cli::parse_input::cast::InputImpl; +use crate::committer_cli::parse_input::raw_input::RawInput; + +#[cfg(test)] +#[path = "read_test.rs"] +pub mod read_test; + +type DeserializationResult = Result; + +pub fn parse_input(input: &str) -> DeserializationResult { + serde_json::from_str::(input)?.try_into() +} diff --git a/crates/committer_cli/src/parse_input/read_test.rs b/crates/starknet_committer_and_os_cli/src/committer_cli/parse_input/read_test.rs similarity index 89% rename from crates/committer_cli/src/parse_input/read_test.rs rename to crates/starknet_committer_and_os_cli/src/committer_cli/parse_input/read_test.rs index 781d17d43fa..d2b148e2b70 100644 --- a/crates/committer_cli/src/parse_input/read_test.rs +++ b/crates/starknet_committer_and_os_cli/src/committer_cli/parse_input/read_test.rs @@ -1,19 +1,20 @@ use std::collections::HashMap; +use assert_matches::assert_matches; use pretty_assertions::assert_eq; +use starknet_api::core::{ClassHash, ContractAddress, Nonce}; use starknet_committer::block_committer::input::{ ConfigImpl, - ContractAddress, Input, StarknetStorageKey, StarknetStorageValue, StateDiff, }; -use starknet_committer::patricia_merkle_tree::types::{ClassHash, CompiledClassHash, Nonce}; -use starknet_patricia::felt::Felt; +use starknet_committer::patricia_merkle_tree::types::CompiledClassHash; use starknet_patricia::hash::hash_trait::HashOutput; -use starknet_patricia::storage::errors::DeserializationError; -use starknet_patricia::storage::storage_trait::{StorageKey, StorageValue}; +use starknet_patricia_storage::errors::DeserializationError; +use starknet_patricia_storage::storage_trait::{DbKey, DbValue}; +use starknet_types_core::felt::Felt; use tracing::level_filters::LevelFilter; use super::parse_input; @@ -88,26 +89,28 @@ fn test_simple_input_parsing() { "#; let expected_storage = HashMap::from([ - (StorageKey([14, 6, 78, 90].to_vec()), StorageValue([245, 90, 0, 0, 1].to_vec())), - (StorageKey([14, 6, 43, 90].to_vec()), StorageValue([9, 0, 0, 0, 1].to_vec())), + (DbKey([14, 6, 78, 90].to_vec()), DbValue([245, 90, 0, 0, 1].to_vec())), + (DbKey([14, 6, 43, 90].to_vec()), DbValue([9, 0, 0, 0, 1].to_vec())), ]); let expected_address_to_class_hash = HashMap::from([ ( - ContractAddress(Felt::from_bytes_be_slice(&[ + ContractAddress::try_from(Felt::from_bytes_be_slice(&[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 1, 0, 89, 0, 0, 0, 0, 0, 0, 0, - ])), + ])) + .unwrap(), ClassHash(Felt::from_bytes_be_slice(&[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ])), ), ( - ContractAddress(Felt::from_bytes_be_slice(&[ + ContractAddress::try_from(Felt::from_bytes_be_slice(&[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 5, 0, 0, 0, 0, 0, 1, 0, 89, 0, 0, 0, 0, 0, 0, 0, - ])), + ])) + .unwrap(), ClassHash(Felt::from_bytes_be_slice(&[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 77, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -117,20 +120,22 @@ fn test_simple_input_parsing() { let expected_address_to_nonce = HashMap::from([ ( - ContractAddress(Felt::from_bytes_be_slice(&[ + ContractAddress::try_from(Felt::from_bytes_be_slice(&[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 1, 0, 89, 0, 0, 0, 0, 0, 0, 0, - ])), + ])) + .unwrap(), Nonce(Felt::from_bytes_be_slice(&[ 0, 0, 0, 0, 0, 14, 0, 0, 0, 45, 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ])), ), ( - ContractAddress(Felt::from_bytes_be_slice(&[ + ContractAddress::try_from(Felt::from_bytes_be_slice(&[ 0, 0, 0, 0, 0, 98, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 5, 0, 0, 0, 0, 0, 1, 0, 89, 0, 0, 0, 0, 0, 0, 0, - ])), + ])) + .unwrap(), Nonce(Felt::from_bytes_be_slice(&[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 77, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -162,10 +167,11 @@ fn test_simple_input_parsing() { ]); let expected_storage_updates = HashMap::from([( - ContractAddress(Felt::from_bytes_be_slice(&[ + ContractAddress::try_from(Felt::from_bytes_be_slice(&[ 0, 0, 0, 0, 0, 98, 0, 0, 0, 156, 0, 0, 0, 0, 0, 11, 5, 0, 0, 0, 0, 0, 1, 0, 89, 0, 0, 0, 0, 0, 0, 0, - ])), + ])) + .unwrap(), HashMap::from([ ( StarknetStorageKey(Felt::from_bytes_be_slice(&[ @@ -233,7 +239,7 @@ fn test_input_parsing_with_storage_key_duplicate() { ] "#; - let expected_error = "storage: StorageKey([14, 6, 78, 90])"; + let expected_error = "storage: DbKey([14, 6, 78, 90])"; assert!(matches!( parse_input(input).unwrap_err(), DeserializationError::KeyDuplicate(key) if key == expected_error @@ -276,9 +282,9 @@ fn test_input_parsing_with_mapping_key_duplicate() { "#; let expected_error = - "address to class hash: ContractAddress(6646139978924584093298644040422522880)"; - assert!(matches!( + "address to class hash: ContractAddress(PatriciaKey(0x5000000000001005900000000000000))"; + assert_matches!( parse_input(input).unwrap_err(), DeserializationError::KeyDuplicate(key) if key == expected_error - )); + ); } diff --git a/crates/starknet_committer_and_os_cli/src/committer_cli/run_committer_cli.rs b/crates/starknet_committer_and_os_cli/src/committer_cli/run_committer_cli.rs new file mode 100644 index 00000000000..391d58f4130 --- /dev/null +++ b/crates/starknet_committer_and_os_cli/src/committer_cli/run_committer_cli.rs @@ -0,0 +1,41 @@ +use clap::{Parser, Subcommand}; +use tracing::info; +use tracing::level_filters::LevelFilter; +use tracing_subscriber::reload::Handle; +use tracing_subscriber::Registry; + +use crate::committer_cli::commands::parse_and_commit; +use crate::committer_cli::tests::python_tests::CommitterPythonTestRunner; +use crate::shared_utils::types::{run_python_test, IoArgs, PythonTestArg}; + +#[derive(Parser, Debug)] +pub struct CommitterCliCommand { + #[clap(subcommand)] + command: Command, +} + +#[derive(Debug, Subcommand)] +enum Command { + /// Given previous state tree skeleton and a state diff, computes the new commitment. + Commit { + #[clap(flatten)] + io_args: IoArgs, + }, + PythonTest(PythonTestArg), +} + +pub async fn run_committer_cli( + committer_command: CommitterCliCommand, + log_filter_handle: Handle, +) { + info!("Starting committer-cli with command: \n{:?}", committer_command); + match committer_command.command { + Command::Commit { io_args: IoArgs { input_path, output_path } } => { + parse_and_commit(input_path, output_path, log_filter_handle).await; + } + + Command::PythonTest(python_test_arg) => { + run_python_test::(python_test_arg).await; + } + } +} diff --git a/crates/committer_cli/src/tests.rs b/crates/starknet_committer_and_os_cli/src/committer_cli/tests.rs similarity index 100% rename from crates/committer_cli/src/tests.rs rename to crates/starknet_committer_and_os_cli/src/committer_cli/tests.rs diff --git a/crates/committer_cli/src/tests/flow_test_files_prefix b/crates/starknet_committer_and_os_cli/src/committer_cli/tests/flow_test_files_prefix similarity index 100% rename from crates/committer_cli/src/tests/flow_test_files_prefix rename to crates/starknet_committer_and_os_cli/src/committer_cli/tests/flow_test_files_prefix diff --git a/crates/committer_cli/src/tests/python_tests.rs b/crates/starknet_committer_and_os_cli/src/committer_cli/tests/python_tests.rs similarity index 83% rename from crates/committer_cli/src/tests/python_tests.rs rename to crates/starknet_committer_and_os_cli/src/committer_cli/tests/python_tests.rs index 87af9f18f1d..1826addad2f 100644 --- a/crates/committer_cli/src/tests/python_tests.rs +++ b/crates/starknet_committer_and_os_cli/src/committer_cli/tests/python_tests.rs @@ -3,14 +3,8 @@ use std::fmt::Debug; use ethnum::U256; use serde_json::json; -use starknet_api::block_hash::block_hash_calculator::{ - TransactionHashingData, - TransactionOutputForHash, -}; -use starknet_api::state::ThinStateDiff; -use starknet_api::transaction::TransactionExecutionStatus; +use starknet_api::core::{ClassHash, ContractAddress, Nonce}; use starknet_committer::block_committer::input::{ - ContractAddress, StarknetStorageKey, StarknetStorageValue, StateDiff, @@ -19,8 +13,7 @@ use starknet_committer::forest::filled_forest::FilledForest; use starknet_committer::hash_function::hash::TreeHashFunctionImpl; use starknet_committer::patricia_merkle_tree::leaf::leaf_impl::ContractState; use starknet_committer::patricia_merkle_tree::tree::OriginalSkeletonStorageTrieConfig; -use starknet_committer::patricia_merkle_tree::types::{ClassHash, CompiledClassHash, Nonce}; -use starknet_patricia::felt::Felt; +use starknet_committer::patricia_merkle_tree::types::CompiledClassHash; use starknet_patricia::hash::hash_trait::HashOutput; use starknet_patricia::patricia_merkle_tree::external_test_utils::single_tree_flow_test; use starknet_patricia::patricia_merkle_tree::filled_tree::node::FilledNode; @@ -32,24 +25,28 @@ use starknet_patricia::patricia_merkle_tree::node_data::inner_node::{ PathToBottom, }; use starknet_patricia::patricia_merkle_tree::types::SubTreeHeight; -use starknet_patricia::storage::db_object::DBObject; -use starknet_patricia::storage::errors::DeserializationError; -use starknet_patricia::storage::map_storage::MapStorage; -use starknet_patricia::storage::storage_trait::{Storage, StorageKey, StorageValue}; +use starknet_patricia_storage::db_object::DBObject; +use starknet_patricia_storage::errors::DeserializationError; +use starknet_patricia_storage::map_storage::MapStorage; +use starknet_patricia_storage::storage_trait::{DbKey, DbValue, Storage}; +use starknet_types_core::felt::Felt; use starknet_types_core::hash::{Pedersen, StarkHash}; use thiserror; use tracing::{debug, error, info, warn}; -use super::utils::objects::{get_thin_state_diff, get_transaction_output_for_hash, get_tx_data}; use super::utils::parse_from_python::TreeFlowInput; -use crate::filled_tree_output::filled_forest::SerializedForest; -use crate::parse_input::cast::InputImpl; -use crate::parse_input::read::parse_input; -use crate::tests::utils::parse_from_python::parse_input_single_storage_tree_flow_test; -use crate::tests::utils::random_structs::DummyRandomValue; +use crate::committer_cli::filled_tree_output::filled_forest::SerializedForest; +use crate::committer_cli::parse_input::cast::InputImpl; +use crate::committer_cli::parse_input::read::parse_input; +use crate::committer_cli::tests::utils::parse_from_python::parse_input_single_storage_tree_flow_test; +use crate::committer_cli::tests::utils::random_structs::DummyRandomValue; +use crate::shared_utils::types::{PythonTestError, PythonTestResult, PythonTestRunner}; + +pub type CommitterPythonTestError = PythonTestError; +pub type CommitterPythonTestResult = PythonTestResult; // Enum representing different Python tests. -pub enum PythonTest { +pub enum CommitterPythonTestRunner { ExampleTest, FeltSerialize, HashFunction, @@ -61,22 +58,15 @@ pub enum PythonTest { StorageNode, FilledForestOutput, TreeHeightComparison, - ParseTxOutput, - ParseStateDiff, - ParseTxData, SerializeForRustCommitterFlowTest, ComputeHashSingleTree, MaybePanic, LogError, } -/// Error type for PythonTest enum. +/// Error type for CommitterPythonTest enum. #[derive(Debug, thiserror::Error)] -pub enum PythonTestError { - #[error("Unknown test name: {0}")] - UnknownTestName(String), - #[error(transparent)] - ParseInputError(#[from] serde_json::Error), +pub enum CommitterSpecificTestError { #[error(transparent)] ParseIntError(#[from] std::num::ParseIntError), #[error("{0}")] @@ -85,13 +75,11 @@ pub enum PythonTestError { InvalidCastError(#[from] std::num::TryFromIntError), #[error(transparent)] DeserializationTestFailure(#[from] DeserializationError), - #[error("None value found in input.")] - NoneInputError, } -/// Implements conversion from a string to a `PythonTest`. -impl TryFrom for PythonTest { - type Error = PythonTestError; +/// Implements conversion from a string to the test runner. +impl TryFrom for CommitterPythonTestRunner { + type Error = CommitterPythonTestError; fn try_from(value: String) -> Result { match value.as_str() { @@ -106,9 +94,6 @@ impl TryFrom for PythonTest { "storage_node_test" => Ok(Self::StorageNode), "filled_forest_output" => Ok(Self::FilledForestOutput), "compare_tree_height" => Ok(Self::TreeHeightComparison), - "parse_tx_output_test" => Ok(Self::ParseTxOutput), - "parse_state_diff_test" => Ok(Self::ParseStateDiff), - "parse_tx_data_test" => Ok(Self::ParseTxData), "serialize_to_rust_committer_flow_test" => Ok(Self::SerializeForRustCommitterFlowTest), "tree_test" => Ok(Self::ComputeHashSingleTree), "maybe_panic" => Ok(Self::MaybePanic), @@ -118,14 +103,11 @@ impl TryFrom for PythonTest { } } -impl PythonTest { - /// Returns the input string if it's `Some`, or an error if it's `None`. - pub fn non_optional_input(input: Option<&str>) -> Result<&str, PythonTestError> { - input.ok_or_else(|| PythonTestError::NoneInputError) - } +impl PythonTestRunner for CommitterPythonTestRunner { + type SpecificError = CommitterSpecificTestError; /// Runs the test with the given arguments. - pub async fn run(&self, input: Option<&str>) -> Result { + async fn run(&self, input: Option<&str>) -> CommitterPythonTestResult { match self { Self::ExampleTest => { let example_input: HashMap = @@ -133,7 +115,9 @@ impl PythonTest { Ok(example_test(example_input)) } Self::FeltSerialize => { - let felt = Self::non_optional_input(input)?.parse::()?; + let felt = Self::non_optional_input(input)?.parse::().map_err(|err| { + PythonTestError::SpecificError(CommitterSpecificTestError::ParseIntError(err)) + })?; Ok(felt_serialize_test(felt)) } Self::HashFunction => { @@ -160,21 +144,6 @@ impl PythonTest { } Self::FilledForestOutput => filled_forest_output_test(), Self::TreeHeightComparison => Ok(get_actual_tree_height()), - Self::ParseTxOutput => { - let tx_output: TransactionOutputForHash = - serde_json::from_str(Self::non_optional_input(input)?)?; - Ok(parse_tx_output_test(tx_output)) - } - Self::ParseStateDiff => { - let tx_output: ThinStateDiff = - serde_json::from_str(Self::non_optional_input(input)?)?; - Ok(parse_state_diff_test(tx_output)) - } - Self::ParseTxData => { - let tx_data: TransactionHashingData = - serde_json::from_str(Self::non_optional_input(input)?)?; - Ok(parse_tx_data_test(tx_data)) - } Self::SerializeForRustCommitterFlowTest => { // TODO(Aner, 8/7/2024): refactor using structs for deserialization. let input: HashMap = @@ -232,12 +201,12 @@ fn serialize_for_rust_committer_flow_test(input: HashMap) -> Str fn get_or_key_not_found<'a, T: Debug>( map: &'a HashMap, key: &'a str, -) -> Result<&'a T, PythonTestError> { +) -> Result<&'a T, CommitterPythonTestError> { map.get(key).ok_or_else(|| { - PythonTestError::KeyNotFound(format!( + PythonTestError::SpecificError(CommitterSpecificTestError::KeyNotFound(format!( "Failed to get value for key '{}' from {:?}.", key, map - )) + ))) }) } @@ -251,29 +220,6 @@ pub(crate) fn example_test(test_args: HashMap) -> String { format!("Calling example test with args: x: {}, y: {}", x, y) } -pub(crate) fn parse_tx_output_test(tx_execution_info: TransactionOutputForHash) -> String { - let expected_object = get_transaction_output_for_hash(&tx_execution_info.execution_status); - is_success_string(expected_object == tx_execution_info) -} - -pub(crate) fn parse_state_diff_test(state_diff: ThinStateDiff) -> String { - let expected_object = get_thin_state_diff(); - is_success_string(expected_object == state_diff) -} - -pub(crate) fn parse_tx_data_test(tx_data: TransactionHashingData) -> String { - let expected_object = get_tx_data(&TransactionExecutionStatus::Succeeded); - is_success_string(expected_object == tx_data) -} - -fn is_success_string(is_success: bool) -> String { - match is_success { - true => "Success", - false => "Failure", - } - .to_owned() -} - /// Serializes a Felt into a string. pub(crate) fn felt_serialize_test(felt: u128) -> String { let bytes = Felt::from(felt).to_bytes_be().to_vec(); @@ -291,7 +237,7 @@ pub(crate) fn test_hash_function(hash_input: HashMap) -> String { let y_felt = Felt::from(*y); // Compute the hash. - let hash_result = Pedersen::hash(&x_felt.into(), &y_felt.into()); + let hash_result = Pedersen::hash(&x_felt, &y_felt); // Serialize the hash result. serde_json::to_string(&hash_result) @@ -334,8 +280,10 @@ pub(crate) fn test_binary_serialize_test(binary_input: HashMap) -> .unwrap_or_else(|error| panic!("Failed to serialize binary fact: {}", error)) } -pub(crate) fn parse_input_test(committer_input: String) -> Result { - Ok(create_output_to_python(parse_input(&committer_input)?)) +pub(crate) fn parse_input_test(committer_input: String) -> CommitterPythonTestResult { + Ok(create_output_to_python(parse_input(&committer_input).map_err(|err| { + PythonTestError::SpecificError(CommitterSpecificTestError::DeserializationTestFailure(err)) + })?)) } fn create_output_to_python(actual_input: InputImpl) -> String { @@ -437,7 +385,7 @@ generate_storage_map_xor_hasher!( generate_storage_map_xor_hasher!(hash_address_to_class_hash, ContractAddress, ClassHash); generate_storage_map_xor_hasher!(hash_address_to_nonce, ContractAddress, Nonce); -fn hash_storage(storage: &HashMap) -> (Vec, Vec) { +fn hash_storage(storage: &HashMap) -> (Vec, Vec) { let mut keys_hash = vec![0; 32]; let mut values_hash = vec![0; 32]; for (key, value) in storage { @@ -509,15 +457,15 @@ pub(crate) fn test_node_db_key() -> String { .unwrap_or_else(|error| panic!("Failed to serialize storage prefix: {}", error)) } -/// This function storage_serialize_test generates a MapStorage containing StorageKey and -/// StorageValue pairs for u128 values in the range 0..=1000, +/// This function storage_serialize_test generates a MapStorage containing DbKey and +/// DbValue pairs for u128 values in the range 0..=1000, /// serializes it to a JSON string using Serde, /// and returns the serialized JSON string or panics with an error message if serialization fails. -pub(crate) fn storage_serialize_test() -> Result { +pub(crate) fn storage_serialize_test() -> CommitterPythonTestResult { let mut storage = MapStorage { storage: HashMap::new() }; for i in 0..=99_u128 { - let key = StorageKey(Felt::from(i).to_bytes_be().to_vec()); - let value = StorageValue(Felt::from(i).to_bytes_be().to_vec()); + let key = DbKey(Felt::from(i).to_bytes_be().to_vec()); + let value = DbValue(Felt::from(i).to_bytes_be().to_vec()); storage.set(key, value); } @@ -547,9 +495,9 @@ fn python_hash_constants_compare() -> String { /// - `"contract_class_leaf"`: Compiled class leaf data. /// /// # Returns -/// A `Result` containing a serialized map of all nodes on success, or an -/// error if keys are missing or parsing fails. -fn test_storage_node(data: HashMap) -> Result { +/// A `Result` containing a serialized map of all nodes on +/// success, or an error if keys are missing or parsing fails. +fn test_storage_node(data: HashMap) -> CommitterPythonTestResult { // Create a storage to store the nodes. let mut rust_fact_storage = MapStorage { storage: HashMap::new() }; @@ -579,8 +527,14 @@ fn test_storage_node(data: HashMap) -> Result) -> Result Result { +pub(crate) fn filled_forest_output_test() -> CommitterPythonTestResult { let dummy_forest = SerializedForest(FilledForest::dummy_random(&mut rand::thread_rng(), None)); let output = dummy_forest.forest_to_output(); let output_string = serde_json::to_string(&output).expect("Failed to serialize"); diff --git a/crates/committer_cli/src/tests/regression_tests.rs b/crates/starknet_committer_and_os_cli/src/committer_cli/tests/regression_tests.rs similarity index 95% rename from crates/committer_cli/src/tests/regression_tests.rs rename to crates/starknet_committer_and_os_cli/src/committer_cli/tests/regression_tests.rs index 56a272cde83..0369bcfd763 100644 --- a/crates/committer_cli/src/tests/regression_tests.rs +++ b/crates/starknet_committer_and_os_cli/src/committer_cli/tests/regression_tests.rs @@ -11,17 +11,17 @@ use starknet_patricia::patricia_merkle_tree::external_test_utils::single_tree_fl use tempfile::NamedTempFile; use super::utils::parse_from_python::parse_input_single_storage_tree_flow_test; -use crate::commands::commit; -use crate::parse_input::read::parse_input; -use crate::tests::utils::parse_from_python::TreeFlowInput; +use crate::committer_cli::commands::commit; +use crate::committer_cli::parse_input::read::parse_input; +use crate::committer_cli::tests::utils::parse_from_python::TreeFlowInput; // TODO(Aner, 20/06/2024): these tests needs to be fixed to be run correctly in the CI: // 1. Fix the test to measure cpu_time and not wall_time. // 2. Fix the max time threshold to be the expected time for the benchmark test. const MAX_TIME_FOR_SINGLE_TREE_BECHMARK_TEST: f64 = 5.0; const MAX_TIME_FOR_COMMITTER_FLOW_BECHMARK_TEST: f64 = 5.0; -const SINGLE_TREE_FLOW_INPUT: &str = include_str!("../../test_inputs/tree_flow_inputs.json"); -const FLOW_TEST_INPUT: &str = include_str!("../../test_inputs/committer_flow_inputs.json"); +const SINGLE_TREE_FLOW_INPUT: &str = include_str!("../../../test_inputs/tree_flow_inputs.json"); +const FLOW_TEST_INPUT: &str = include_str!("../../../test_inputs/committer_flow_inputs.json"); const OUTPUT_PATH: &str = "benchmark_output.txt"; const EXPECTED_NUMBER_OF_FILES: usize = 100; diff --git a/crates/committer_cli/src/tests/utils.rs b/crates/starknet_committer_and_os_cli/src/committer_cli/tests/utils.rs similarity index 75% rename from crates/committer_cli/src/tests/utils.rs rename to crates/starknet_committer_and_os_cli/src/committer_cli/tests/utils.rs index 2b502e0ae2b..dc1e5b73edb 100644 --- a/crates/committer_cli/src/tests/utils.rs +++ b/crates/starknet_committer_and_os_cli/src/committer_cli/tests/utils.rs @@ -1,3 +1,2 @@ -pub mod objects; pub mod parse_from_python; pub mod random_structs; diff --git a/crates/committer_cli/src/tests/utils/parse_from_python.rs b/crates/starknet_committer_and_os_cli/src/committer_cli/tests/utils/parse_from_python.rs similarity index 84% rename from crates/committer_cli/src/tests/utils/parse_from_python.rs rename to crates/starknet_committer_and_os_cli/src/committer_cli/tests/utils/parse_from_python.rs index 833f732ed13..4baa2d3cda6 100644 --- a/crates/committer_cli/src/tests/utils/parse_from_python.rs +++ b/crates/starknet_committer_and_os_cli/src/committer_cli/tests/utils/parse_from_python.rs @@ -3,15 +3,15 @@ use std::collections::HashMap; use ethnum::U256; use serde::{Deserialize, Deserializer}; use starknet_committer::block_committer::input::StarknetStorageValue; -use starknet_patricia::felt::Felt; use starknet_patricia::hash::hash_trait::HashOutput; use starknet_patricia::patricia_merkle_tree::node_data::leaf::LeafModifications; use starknet_patricia::patricia_merkle_tree::types::NodeIndex; -use starknet_patricia::storage::map_storage::MapStorage; -use starknet_patricia::storage::storage_trait::{StorageKey, StorageValue}; +use starknet_patricia_storage::map_storage::MapStorage; +use starknet_patricia_storage::storage_trait::{DbKey, DbValue}; +use starknet_types_core::felt::Felt; -use crate::parse_input::cast::add_unique; -use crate::parse_input::raw_input::RawStorageEntry; +use crate::committer_cli::parse_input::cast::add_unique; +use crate::committer_cli::parse_input::raw_input::RawStorageEntry; pub struct TreeFlowInput { pub leaf_modifications: LeafModifications, @@ -53,8 +53,7 @@ pub fn parse_input_single_storage_tree_flow_test(input: &HashMap let mut storage = HashMap::new(); for entry in raw_storage { - add_unique(&mut storage, "storage", StorageKey(entry.key), StorageValue(entry.value)) - .unwrap(); + add_unique(&mut storage, "storage", DbKey(entry.key), DbValue(entry.value)).unwrap(); } let map_storage = MapStorage { storage }; diff --git a/crates/committer_cli/src/tests/utils/random_structs.rs b/crates/starknet_committer_and_os_cli/src/committer_cli/tests/utils/random_structs.rs similarity index 92% rename from crates/committer_cli/src/tests/utils/random_structs.rs rename to crates/starknet_committer_and_os_cli/src/committer_cli/tests/utils/random_structs.rs index 5f175acb93d..54b3611ca06 100644 --- a/crates/committer_cli/src/tests/utils/random_structs.rs +++ b/crates/starknet_committer_and_os_cli/src/committer_cli/tests/utils/random_structs.rs @@ -6,21 +6,23 @@ use rand::prelude::IteratorRandom; use rand::Rng; use rand_distr::num_traits::ToPrimitive; use rand_distr::{Distribution, Geometric}; -use starknet_committer::block_committer::input::{ContractAddress, StarknetStorageValue}; +use starknet_api::core::{ClassHash, ContractAddress, Nonce, PATRICIA_KEY_UPPER_BOUND}; +use starknet_committer::block_committer::input::StarknetStorageValue; use starknet_committer::forest::filled_forest::FilledForest; use starknet_committer::patricia_merkle_tree::leaf::leaf_impl::ContractState; use starknet_committer::patricia_merkle_tree::types::{ - ClassHash, ClassesTrie, CompiledClassHash, ContractsTrie, - Nonce, StorageTrie, StorageTrieMap, }; -use starknet_patricia::felt::Felt; +use starknet_patricia::felt::u256_from_felt; use starknet_patricia::hash::hash_trait::HashOutput; -use starknet_patricia::patricia_merkle_tree::external_test_utils::get_random_u256; +use starknet_patricia::patricia_merkle_tree::external_test_utils::{ + get_random_u256, + u256_try_into_felt, +}; use starknet_patricia::patricia_merkle_tree::filled_tree::node::FilledNode; use starknet_patricia::patricia_merkle_tree::node_data::inner_node::{ BinaryData, @@ -32,6 +34,7 @@ use starknet_patricia::patricia_merkle_tree::node_data::inner_node::{ PathToBottom, }; use starknet_patricia::patricia_merkle_tree::types::NodeIndex; +use starknet_types_core::felt::Felt; use strum::IntoEnumIterator; pub trait RandomValue { @@ -44,7 +47,7 @@ pub trait DummyRandomValue { impl RandomValue for Felt { fn random(rng: &mut R, _max: Option) -> Self { - Felt::try_from(&get_random_u256(rng, U256::ONE, U256::from(&Felt::MAX) + 1)) + u256_try_into_felt(&get_random_u256(rng, U256::ONE, u256_from_felt(&Felt::MAX) + 1)) .expect("Failed to create a random Felt") } } @@ -179,7 +182,12 @@ random_filled_node!(ContractState); impl RandomValue for ContractAddress { fn random(rng: &mut R, max: Option) -> Self { - ContractAddress(Felt::random(rng, max)) + let address_max = u256_from_felt(&Felt::from_hex_unchecked(PATRICIA_KEY_UPPER_BOUND)); + let max = match max { + None => address_max, + Some(caller_max) => min(address_max, caller_max), + }; + ContractAddress::try_from(Felt::random(rng, Some(max))).unwrap() } } diff --git a/crates/starknet_committer_and_os_cli/src/lib.rs b/crates/starknet_committer_and_os_cli/src/lib.rs new file mode 100644 index 00000000000..b1c73f78349 --- /dev/null +++ b/crates/starknet_committer_and_os_cli/src/lib.rs @@ -0,0 +1,5 @@ +pub mod block_hash_cli; +pub mod committer_cli; +pub mod os_cli; +pub mod shared_utils; +pub mod tracing_utils; diff --git a/crates/starknet_committer_and_os_cli/src/main.rs b/crates/starknet_committer_and_os_cli/src/main.rs new file mode 100644 index 00000000000..d43d6cec7fc --- /dev/null +++ b/crates/starknet_committer_and_os_cli/src/main.rs @@ -0,0 +1,59 @@ +use clap::{Args, Parser, Subcommand}; +use starknet_committer_and_os_cli::block_hash_cli::run_block_hash_cli::{ + run_block_hash_cli, + BlockHashCliCommand, +}; +use starknet_committer_and_os_cli::committer_cli::run_committer_cli::{ + run_committer_cli, + CommitterCliCommand, +}; +use starknet_committer_and_os_cli::os_cli::run_os_cli::{run_os_cli, OsCliCommand}; +use starknet_committer_and_os_cli::tracing_utils::configure_tracing; +use tracing::info; + +/// Committer and OS CLI. +#[derive(Debug, Parser)] +#[clap(name = "committer-and-os-cli", version)] +struct CliArgs { + #[clap(flatten)] + global_options: GlobalOptions, + + #[clap(subcommand)] + command: CommitterOrOsCommand, +} + +#[derive(Debug, Subcommand)] +enum CommitterOrOsCommand { + /// Run Committer CLI. + Committer(CommitterCliCommand), + /// Run BlockHash CLI. + BlockHash(BlockHashCliCommand), + /// Run OS CLI. + OS(OsCliCommand), +} + +#[derive(Debug, Args)] +struct GlobalOptions {} + +#[tokio::main] +/// Main entry point of the committer & OS CLI. +async fn main() { + // Initialize the logger. The log_filter_handle is used to change the log level. The + // default log level is INFO. + let log_filter_handle = configure_tracing(); + + let args = CliArgs::parse(); + info!("Starting committer & OS cli with args: \n{:?}", args); + + match args.command { + CommitterOrOsCommand::Committer(command) => { + run_committer_cli(command, log_filter_handle).await; + } + CommitterOrOsCommand::OS(command) => { + run_os_cli(command, log_filter_handle).await; + } + CommitterOrOsCommand::BlockHash(command) => { + run_block_hash_cli(command).await; + } + } +} diff --git a/crates/starknet_committer_and_os_cli/src/os_cli.rs b/crates/starknet_committer_and_os_cli/src/os_cli.rs new file mode 100644 index 00000000000..8a62b12d661 --- /dev/null +++ b/crates/starknet_committer_and_os_cli/src/os_cli.rs @@ -0,0 +1,3 @@ +pub mod commands; +pub mod run_os_cli; +pub mod tests; diff --git a/crates/starknet_committer_and_os_cli/src/os_cli/commands.rs b/crates/starknet_committer_and_os_cli/src/os_cli/commands.rs new file mode 100644 index 00000000000..3182ccc8abe --- /dev/null +++ b/crates/starknet_committer_and_os_cli/src/os_cli/commands.rs @@ -0,0 +1,69 @@ +use std::fs; +use std::path::Path; + +use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass; +use cairo_vm::types::layout_name::LayoutName; +use rand_distr::num_traits::Zero; +use serde::Deserialize; +use starknet_api::contract_class::ContractClass; +use starknet_api::executable_transaction::{AccountTransaction, Transaction}; +use starknet_os::io::os_input::{CachedStateInput, StarknetOsInput}; +use starknet_os::runner::run_os_stateless; +use tracing::info; + +use crate::shared_utils::read::{load_input, write_to_file}; + +#[derive(Deserialize, Debug)] +/// Input to the os runner. +pub(crate) struct Input { + // A path to a compiled program that its hint set should be a subset of those defined in + // starknet-os. + pub compiled_os_path: String, + pub layout: LayoutName, + pub os_input: StarknetOsInput, + pub cached_state_input: CachedStateInput, +} + +/// Validate the os_input. +pub fn validate_input(os_input: &StarknetOsInput) { + assert!( + os_input.transactions.len() == os_input._tx_execution_infos.len(), + "The number of transactions and execution infos should be equal" + ); + + // The CasmContractClass in Declare transactions should hold invalid data to mark it should not + // be used. + assert!( + os_input + .transactions + .iter() + .filter_map(|tx| { + if let Transaction::Account(AccountTransaction::Declare(declare_tx)) = tx { + Some(&declare_tx.class_info.contract_class) + } else { + None + } + }) + .all(|contract_class| match contract_class { + ContractClass::V0(_) => false, + ContractClass::V1((CasmContractClass { prime, .. }, _)) => prime.is_zero(), + }), + "All declare transactions should be of V1 and should have contract class with prime=0" + ); +} + +pub fn parse_and_run_os(input_path: String, output_path: String) { + let Input { compiled_os_path, layout, os_input, cached_state_input } = load_input(input_path); + validate_input(&os_input); + let block_number = os_input.block_info.block_number; + info!("Parsed OS input successfully for block number: {}", block_number); + + // Load the compiled_os from the compiled_os_path. + let compiled_os = + fs::read(Path::new(&compiled_os_path)).expect("Failed to read compiled_os file"); + + let output = run_os_stateless(&compiled_os, layout, os_input, cached_state_input) + .unwrap_or_else(|_| panic!("OS run failed on block number: {}.", block_number)); + write_to_file(&output_path, &output); + info!("OS program ran successfully on block number: {}", block_number); +} diff --git a/crates/starknet_committer_and_os_cli/src/os_cli/run_os_cli.rs b/crates/starknet_committer_and_os_cli/src/os_cli/run_os_cli.rs new file mode 100644 index 00000000000..9d2e0804a72 --- /dev/null +++ b/crates/starknet_committer_and_os_cli/src/os_cli/run_os_cli.rs @@ -0,0 +1,39 @@ +use clap::{Parser, Subcommand}; +use tracing::info; +use tracing::level_filters::LevelFilter; +use tracing_subscriber::reload::Handle; +use tracing_subscriber::Registry; + +use crate::os_cli::commands::parse_and_run_os; +use crate::os_cli::tests::python_tests::OsPythonTestRunner; +use crate::shared_utils::types::{run_python_test, IoArgs, PythonTestArg}; + +#[derive(Parser, Debug)] +pub struct OsCliCommand { + #[clap(subcommand)] + command: Command, +} + +#[derive(Debug, Subcommand)] +enum Command { + PythonTest(PythonTestArg), + RunOsStateless { + #[clap(flatten)] + io_args: IoArgs, + }, +} + +pub async fn run_os_cli( + os_command: OsCliCommand, + _log_filter_handle: Handle, +) { + info!("Starting starknet-os-cli with command: \n{:?}", os_command); + match os_command.command { + Command::PythonTest(python_test_arg) => { + run_python_test::(python_test_arg).await; + } + Command::RunOsStateless { io_args: IoArgs { input_path, output_path } } => { + parse_and_run_os(input_path, output_path); + } + } +} diff --git a/crates/starknet_committer_and_os_cli/src/os_cli/tests.rs b/crates/starknet_committer_and_os_cli/src/os_cli/tests.rs new file mode 100644 index 00000000000..eacc60df0c6 --- /dev/null +++ b/crates/starknet_committer_and_os_cli/src/os_cli/tests.rs @@ -0,0 +1 @@ +pub mod python_tests; diff --git a/crates/starknet_committer_and_os_cli/src/os_cli/tests/python_tests.rs b/crates/starknet_committer_and_os_cli/src/os_cli/tests/python_tests.rs new file mode 100644 index 00000000000..1b63a7a0d3d --- /dev/null +++ b/crates/starknet_committer_and_os_cli/src/os_cli/tests/python_tests.rs @@ -0,0 +1,656 @@ +use std::collections::HashSet; + +// TODO(Amos): When available in the VM crate, use an existing set, instead of using each hint +// const explicitly. +use cairo_vm::hint_processor::builtin_hint_processor::hint_code::{ + ADD_NO_UINT384_CHECK, + ADD_SEGMENT, + ASSERT_250_BITS, + ASSERT_LE_FELT, + ASSERT_LE_FELT_EXCLUDED_0, + ASSERT_LE_FELT_EXCLUDED_1, + ASSERT_LE_FELT_EXCLUDED_2, + ASSERT_LE_FELT_V_0_6, + ASSERT_LE_FELT_V_0_8, + ASSERT_LT_FELT, + ASSERT_NN, + ASSERT_NOT_EQUAL, + ASSERT_NOT_ZERO, + A_B_BITAND_1, + BIGINT_PACK_DIV_MOD, + BIGINT_SAFE_DIV, + BIGINT_TO_UINT256, + BLAKE2S_ADD_UINT256, + BLAKE2S_ADD_UINT256_BIGEND, + BLAKE2S_COMPUTE, + BLAKE2S_FINALIZE, + BLAKE2S_FINALIZE_V2, + BLAKE2S_FINALIZE_V3, + BLOCK_PERMUTATION, + BLOCK_PERMUTATION_WHITELIST_V1, + BLOCK_PERMUTATION_WHITELIST_V2, + CAIRO_KECCAK_FINALIZE_V1, + CAIRO_KECCAK_FINALIZE_V2, + CAIRO_KECCAK_INPUT_IS_FULL_WORD, + CHAINED_EC_OP_RANDOM_EC_POINT, + COMPARE_BYTES_IN_WORD_NONDET, + COMPARE_KECCAK_FULL_RATE_IN_BYTES_NONDET, + COMPUTE_SLOPE_SECP256R1_V1, + COMPUTE_SLOPE_SECP256R1_V2, + COMPUTE_SLOPE_V1, + COMPUTE_SLOPE_V2, + COMPUTE_SLOPE_WHITELIST, + DEFAULT_DICT_NEW, + DICT_NEW, + DICT_READ, + DICT_SQUASH_COPY_DICT, + DICT_SQUASH_UPDATE_PTR, + DICT_UPDATE, + DICT_WRITE, + DIV_MOD_N_PACKED_DIVMOD_EXTERNAL_N, + DIV_MOD_N_PACKED_DIVMOD_V1, + DIV_MOD_N_SAFE_DIV, + DIV_MOD_N_SAFE_DIV_PLUS_ONE, + DI_BIT, + EC_DOUBLE_ASSIGN_NEW_X_V1, + EC_DOUBLE_ASSIGN_NEW_X_V2, + EC_DOUBLE_ASSIGN_NEW_X_V3, + EC_DOUBLE_ASSIGN_NEW_X_V4, + EC_DOUBLE_ASSIGN_NEW_Y, + EC_DOUBLE_SLOPE_EXTERNAL_CONSTS, + EC_DOUBLE_SLOPE_V1, + EC_DOUBLE_SLOPE_V2, + EC_DOUBLE_SLOPE_V3, + EC_DOUBLE_SLOPE_V4, + EC_MUL_INNER, + EC_NEGATE, + EC_NEGATE_EMBEDDED_SECP, + EC_RECOVER_DIV_MOD_N_PACKED, + EC_RECOVER_PRODUCT_DIV_M, + EC_RECOVER_PRODUCT_MOD, + EC_RECOVER_SUB_A_B, + EXAMPLE_BLAKE2S_COMPRESS, + EXCESS_BALANCE, + FAST_EC_ADD_ASSIGN_NEW_X, + FAST_EC_ADD_ASSIGN_NEW_X_V2, + FAST_EC_ADD_ASSIGN_NEW_X_V3, + FAST_EC_ADD_ASSIGN_NEW_Y, + FIND_ELEMENT, + GET_FELT_BIT_LENGTH, + GET_POINT_FROM_X, + HI_MAX_BITLEN, + IMPORT_SECP256R1_ALPHA, + IMPORT_SECP256R1_N, + IMPORT_SECP256R1_P, + INV_MOD_P_UINT256, + INV_MOD_P_UINT512, + IS_250_BITS, + IS_ADDR_BOUNDED, + IS_LE_FELT, + IS_NN, + IS_NN_OUT_OF_RANGE, + IS_POSITIVE, + IS_QUAD_RESIDUE, + IS_ZERO_ASSIGN_SCOPE_VARS, + IS_ZERO_ASSIGN_SCOPE_VARS_ED25519, + IS_ZERO_ASSIGN_SCOPE_VARS_EXTERNAL_SECP, + IS_ZERO_INT, + IS_ZERO_NONDET, + IS_ZERO_PACK_ED25519, + IS_ZERO_PACK_EXTERNAL_SECP_V1, + IS_ZERO_PACK_EXTERNAL_SECP_V2, + IS_ZERO_PACK_V1, + IS_ZERO_PACK_V2, + KECCAK_WRITE_ARGS, + MEMCPY_CONTINUE_COPYING, + MEMCPY_ENTER_SCOPE, + MEMSET_CONTINUE_LOOP, + MEMSET_ENTER_SCOPE, + NONDET_BIGINT3_V1, + NONDET_BIGINT3_V2, + NONDET_ELEMENTS_OVER_TEN, + NONDET_ELEMENTS_OVER_TWO, + NONDET_N_GREATER_THAN_10, + NONDET_N_GREATER_THAN_2, + PACK_MODN_DIV_MODN, + POW, + QUAD_BIT, + RANDOM_EC_POINT, + RECOVER_Y, + REDUCE_ED25519, + REDUCE_V1, + REDUCE_V2, + RELOCATE_SEGMENT, + RUN_P_CIRCUIT, + RUN_P_CIRCUIT_WITH_LARGE_BATCH_SIZE, + SEARCH_SORTED_LOWER, + SET_ADD, + SHA256_FINALIZE, + SHA256_INPUT, + SHA256_MAIN_ARBITRARY_INPUT_LENGTH, + SHA256_MAIN_CONSTANT_INPUT_LENGTH, + SIGNED_DIV_REM, + SPLIT_64, + SPLIT_FELT, + SPLIT_INPUT_12, + SPLIT_INPUT_15, + SPLIT_INPUT_3, + SPLIT_INPUT_6, + SPLIT_INPUT_9, + SPLIT_INT, + SPLIT_INT_ASSERT_RANGE, + SPLIT_N_BYTES, + SPLIT_OUTPUT_0, + SPLIT_OUTPUT_1, + SPLIT_OUTPUT_MID_LOW_HIGH, + SPLIT_XX, + SQRT, + SQUARE_SLOPE_X_MOD_P, + SQUASH_DICT, + SQUASH_DICT_INNER_ASSERT_LEN_KEYS, + SQUASH_DICT_INNER_CHECK_ACCESS_INDEX, + SQUASH_DICT_INNER_CONTINUE_LOOP, + SQUASH_DICT_INNER_FIRST_ITERATION, + SQUASH_DICT_INNER_LEN_ASSERT, + SQUASH_DICT_INNER_NEXT_KEY, + SQUASH_DICT_INNER_SKIP_LOOP, + SQUASH_DICT_INNER_USED_ACCESSES_ASSERT, + SUB_REDUCED_A_AND_REDUCED_B, + TEMPORARY_ARRAY, + UINT128_ADD, + UINT256_ADD, + UINT256_ADD_LOW, + UINT256_EXPANDED_UNSIGNED_DIV_REM, + UINT256_GET_SQUARE_ROOT, + UINT256_MUL_DIV_MOD, + UINT256_MUL_INV_MOD_P, + UINT256_SIGNED_NN, + UINT256_SQRT, + UINT256_SQRT_FELT, + UINT256_SUB, + UINT256_UNSIGNED_DIV_REM, + UINT384_DIV, + UINT384_GET_SQUARE_ROOT, + UINT384_SIGNED_NN, + UINT384_SPLIT_128, + UINT384_SQRT, + UINT384_UNSIGNED_DIV_REM, + UINT512_UNSIGNED_DIV_REM, + UNSAFE_KECCAK, + UNSAFE_KECCAK_FINALIZE, + UNSIGNED_DIV_REM, + UNSIGNED_DIV_REM_UINT768_BY_UINT384, + UNSIGNED_DIV_REM_UINT768_BY_UINT384_STRIPPED, + USORT_BODY, + USORT_ENTER_SCOPE, + USORT_VERIFY, + USORT_VERIFY_MULTIPLICITY_ASSERT, + USORT_VERIFY_MULTIPLICITY_BODY, + VERIFY_ECDSA_SIGNATURE, + VERIFY_ZERO_EXTERNAL_SECP, + VERIFY_ZERO_V1, + VERIFY_ZERO_V2, + VERIFY_ZERO_V3, + VM_ENTER_SCOPE, + VM_EXIT_SCOPE, + XS_SAFE_DIV, +}; +use starknet_os::hints::enum_definition::{AggregatorHint, HintExtension, OsHint}; +use starknet_os::hints::types::HintEnum; +use starknet_os::test_utils::cairo_runner::{EndpointArg, ImplicitArg}; +use starknet_os::test_utils::errors::Cairo0EntryPointRunnerError; +use starknet_os::test_utils::utils::run_cairo_function_and_check_result; +use strum::IntoEnumIterator; +use strum_macros::Display; +use thiserror; + +use crate::os_cli::commands::{validate_input, Input}; +use crate::shared_utils::types::{PythonTestError, PythonTestResult, PythonTestRunner}; + +pub type OsPythonTestError = PythonTestError; +type OsPythonTestResult = PythonTestResult; + +// Enum representing different Python tests. +pub enum OsPythonTestRunner { + AliasesTest, + CompareOsHints, + InputDeserialization, + RunDummyFunction, +} + +// Implements conversion from a string to the test runner. +impl TryFrom for OsPythonTestRunner { + type Error = OsPythonTestError; + + fn try_from(value: String) -> Result { + match value.as_str() { + "aliases_test" => Ok(Self::AliasesTest), + "compare_os_hints" => Ok(Self::CompareOsHints), + "input_deserialization" => Ok(Self::InputDeserialization), + "run_dummy_function" => Ok(Self::RunDummyFunction), + _ => Err(PythonTestError::UnknownTestName(value)), + } + } +} + +#[derive(Debug, thiserror::Error, Display)] +pub enum OsSpecificTestError { + Cairo0EntryPointRunner(#[from] Cairo0EntryPointRunnerError), +} + +impl PythonTestRunner for OsPythonTestRunner { + type SpecificError = OsSpecificTestError; + async fn run(&self, input: Option<&str>) -> OsPythonTestResult { + match self { + Self::AliasesTest => aliases_test(Self::non_optional_input(input)?), + Self::CompareOsHints => compare_os_hints(Self::non_optional_input(input)?), + Self::InputDeserialization => input_deserialization(Self::non_optional_input(input)?), + Self::RunDummyFunction => run_dummy_cairo_function(Self::non_optional_input(input)?), + } + } +} + +fn compare_os_hints(input: &str) -> OsPythonTestResult { + let unfiltered_python_hints: HashSet = serde_json::from_str(input)?; + + // Remove VM hints. + let vm_hints = vm_hints(); + let python_os_hints: HashSet = unfiltered_python_hints + .into_iter() + .filter(|hint| !vm_hints.contains(hint.as_str())) + .collect(); + + // We ignore `SyscallHint`s here, as they are not part of the compiled OS. + let rust_os_hints: HashSet = OsHint::iter() + .map(|hint| hint.to_str().to_string()) + .chain(HintExtension::iter().map(|hint| hint.to_str().to_string())) + .chain(AggregatorHint::iter().map(|hint| hint.to_str().to_string())) + .collect(); + + let mut only_in_python: Vec = + python_os_hints.difference(&rust_os_hints).cloned().collect(); + only_in_python.sort(); + let mut only_in_rust: Vec = + rust_os_hints.difference(&python_os_hints).cloned().collect(); + only_in_rust.sort(); + Ok(serde_json::to_string(&(only_in_python, only_in_rust))?) +} + +fn test_cairo_function( + program_str: &str, + function_name: &str, + explicit_args: &[EndpointArg], + implicit_args: &[ImplicitArg], + expected_explicit_retdata: &[EndpointArg], + expected_implicit_retdata: &[ImplicitArg], +) -> OsPythonTestResult { + run_cairo_function_and_check_result( + program_str, + function_name, + explicit_args, + implicit_args, + expected_explicit_retdata, + expected_implicit_retdata, + ) + .map_err(|error| { + PythonTestError::SpecificError(OsSpecificTestError::Cairo0EntryPointRunner(error)) + })?; + Ok("".to_string()) +} + +// TODO(Amos): Delete this test, as the cairo runner now has it's own separate test. +fn run_dummy_cairo_function(input: &str) -> OsPythonTestResult { + let param_1 = 123; + let param_2 = 456; + test_cairo_function( + input, + "dummy_function", + &[param_1.into(), param_2.into()], + &[], + &[(789 + param_1).into(), param_1.into(), param_2.into()], + &[], + ) +} + +// TODO(Amos): This test is incomplete. Add the rest of the test cases and remove this todo. +fn aliases_test(input: &str) -> OsPythonTestResult { + test_constants(input)?; + Ok("".to_string()) +} + +fn test_constants(input: &str) -> OsPythonTestResult { + let max_non_compressed_contract_address = 15; + let alias_counter_storage_key = 0; + let initial_available_alias = 128; + let alias_contract_address = 2; + test_cairo_function( + input, + "test_constants", + &[ + max_non_compressed_contract_address.into(), + alias_counter_storage_key.into(), + initial_available_alias.into(), + alias_contract_address.into(), + ], + &[], + &[], + &[], + ) +} + +/// Deserialize the input string into an `Input` struct. +fn input_deserialization(input_str: &str) -> OsPythonTestResult { + let input = serde_json::from_str::(input_str)?; + validate_input(&input.os_input); + Ok("Deserialization successful".to_string()) +} + +fn vm_hints() -> HashSet<&'static str> { + HashSet::from([ + ADD_SEGMENT, + VM_ENTER_SCOPE, + VM_EXIT_SCOPE, + MEMCPY_ENTER_SCOPE, + MEMCPY_CONTINUE_COPYING, + MEMSET_ENTER_SCOPE, + MEMSET_CONTINUE_LOOP, + POW, + IS_NN, + IS_NN_OUT_OF_RANGE, + IS_LE_FELT, + IS_POSITIVE, + ASSERT_NN, + ASSERT_NOT_ZERO, + ASSERT_NOT_EQUAL, + ASSERT_LE_FELT, + ASSERT_LE_FELT_V_0_6, + ASSERT_LE_FELT_V_0_8, + ASSERT_LE_FELT_EXCLUDED_0, + ASSERT_LE_FELT_EXCLUDED_1, + ASSERT_LE_FELT_EXCLUDED_2, + ASSERT_LT_FELT, + SPLIT_INT_ASSERT_RANGE, + ASSERT_250_BITS, + IS_250_BITS, + IS_ADDR_BOUNDED, + SPLIT_INT, + SPLIT_64, + SPLIT_FELT, + SQRT, + UNSIGNED_DIV_REM, + SIGNED_DIV_REM, + IS_QUAD_RESIDUE, + FIND_ELEMENT, + SEARCH_SORTED_LOWER, + SET_ADD, + DEFAULT_DICT_NEW, + DICT_NEW, + DICT_READ, + DICT_WRITE, + DICT_UPDATE, + SQUASH_DICT, + SQUASH_DICT_INNER_SKIP_LOOP, + SQUASH_DICT_INNER_FIRST_ITERATION, + SQUASH_DICT_INNER_CHECK_ACCESS_INDEX, + SQUASH_DICT_INNER_CONTINUE_LOOP, + SQUASH_DICT_INNER_ASSERT_LEN_KEYS, + SQUASH_DICT_INNER_LEN_ASSERT, + SQUASH_DICT_INNER_USED_ACCESSES_ASSERT, + SQUASH_DICT_INNER_NEXT_KEY, + DICT_SQUASH_COPY_DICT, + DICT_SQUASH_UPDATE_PTR, + BIGINT_TO_UINT256, + UINT256_ADD, + UINT256_ADD_LOW, + UINT128_ADD, + UINT256_SUB, + UINT256_SQRT, + UINT256_SQRT_FELT, + UINT256_SIGNED_NN, + UINT256_UNSIGNED_DIV_REM, + UINT256_EXPANDED_UNSIGNED_DIV_REM, + UINT256_MUL_DIV_MOD, + USORT_ENTER_SCOPE, + USORT_BODY, + USORT_VERIFY, + USORT_VERIFY_MULTIPLICITY_ASSERT, + USORT_VERIFY_MULTIPLICITY_BODY, + BLAKE2S_COMPUTE, + BLAKE2S_FINALIZE, + BLAKE2S_FINALIZE_V2, + BLAKE2S_FINALIZE_V3, + BLAKE2S_ADD_UINT256, + BLAKE2S_ADD_UINT256_BIGEND, + EXAMPLE_BLAKE2S_COMPRESS, + NONDET_BIGINT3_V1, + NONDET_BIGINT3_V2, + VERIFY_ZERO_V1, + VERIFY_ZERO_V2, + VERIFY_ZERO_V3, + VERIFY_ZERO_EXTERNAL_SECP, + REDUCE_V1, + REDUCE_V2, + REDUCE_ED25519, + UNSAFE_KECCAK, + UNSAFE_KECCAK_FINALIZE, + IS_ZERO_NONDET, + IS_ZERO_INT, + IS_ZERO_PACK_V1, + IS_ZERO_PACK_V2, + IS_ZERO_PACK_EXTERNAL_SECP_V1, + IS_ZERO_PACK_EXTERNAL_SECP_V2, + IS_ZERO_PACK_ED25519, + IS_ZERO_ASSIGN_SCOPE_VARS, + IS_ZERO_ASSIGN_SCOPE_VARS_EXTERNAL_SECP, + IS_ZERO_ASSIGN_SCOPE_VARS_ED25519, + DIV_MOD_N_PACKED_DIVMOD_V1, + DIV_MOD_N_PACKED_DIVMOD_EXTERNAL_N, + DIV_MOD_N_SAFE_DIV, + GET_FELT_BIT_LENGTH, + BIGINT_PACK_DIV_MOD, + BIGINT_SAFE_DIV, + DIV_MOD_N_SAFE_DIV_PLUS_ONE, + GET_POINT_FROM_X, + EC_NEGATE, + EC_NEGATE_EMBEDDED_SECP, + EC_DOUBLE_SLOPE_V1, + EC_DOUBLE_SLOPE_V2, + EC_DOUBLE_SLOPE_V3, + EC_DOUBLE_SLOPE_V4, + EC_DOUBLE_SLOPE_EXTERNAL_CONSTS, + COMPUTE_SLOPE_V1, + COMPUTE_SLOPE_V2, + COMPUTE_SLOPE_SECP256R1_V1, + COMPUTE_SLOPE_SECP256R1_V2, + IMPORT_SECP256R1_P, + COMPUTE_SLOPE_WHITELIST, + EC_DOUBLE_ASSIGN_NEW_X_V1, + EC_DOUBLE_ASSIGN_NEW_X_V2, + EC_DOUBLE_ASSIGN_NEW_X_V3, + EC_DOUBLE_ASSIGN_NEW_X_V4, + EC_DOUBLE_ASSIGN_NEW_Y, + SHA256_INPUT, + SHA256_MAIN_CONSTANT_INPUT_LENGTH, + SHA256_MAIN_ARBITRARY_INPUT_LENGTH, + SHA256_FINALIZE, + KECCAK_WRITE_ARGS, + COMPARE_BYTES_IN_WORD_NONDET, + COMPARE_KECCAK_FULL_RATE_IN_BYTES_NONDET, + BLOCK_PERMUTATION, + BLOCK_PERMUTATION_WHITELIST_V1, + BLOCK_PERMUTATION_WHITELIST_V2, + CAIRO_KECCAK_INPUT_IS_FULL_WORD, + CAIRO_KECCAK_FINALIZE_V1, + CAIRO_KECCAK_FINALIZE_V2, + FAST_EC_ADD_ASSIGN_NEW_X, + FAST_EC_ADD_ASSIGN_NEW_X_V2, + FAST_EC_ADD_ASSIGN_NEW_X_V3, + FAST_EC_ADD_ASSIGN_NEW_Y, + EC_MUL_INNER, + RELOCATE_SEGMENT, + TEMPORARY_ARRAY, + VERIFY_ECDSA_SIGNATURE, + SPLIT_OUTPUT_0, + SPLIT_OUTPUT_1, + SPLIT_INPUT_3, + SPLIT_INPUT_6, + SPLIT_INPUT_9, + SPLIT_INPUT_12, + SPLIT_INPUT_15, + SPLIT_N_BYTES, + SPLIT_OUTPUT_MID_LOW_HIGH, + NONDET_N_GREATER_THAN_10, + NONDET_N_GREATER_THAN_2, + RANDOM_EC_POINT, + CHAINED_EC_OP_RANDOM_EC_POINT, + RECOVER_Y, + PACK_MODN_DIV_MODN, + XS_SAFE_DIV, + UINT384_UNSIGNED_DIV_REM, + UINT384_SPLIT_128, + ADD_NO_UINT384_CHECK, + UINT384_SQRT, + SUB_REDUCED_A_AND_REDUCED_B, + UNSIGNED_DIV_REM_UINT768_BY_UINT384, + UNSIGNED_DIV_REM_UINT768_BY_UINT384_STRIPPED, + UINT384_SIGNED_NN, + IMPORT_SECP256R1_ALPHA, + IMPORT_SECP256R1_N, + UINT384_GET_SQUARE_ROOT, + UINT256_GET_SQUARE_ROOT, + UINT384_DIV, + INV_MOD_P_UINT256, + HI_MAX_BITLEN, + QUAD_BIT, + INV_MOD_P_UINT512, + DI_BIT, + EC_RECOVER_DIV_MOD_N_PACKED, + UINT512_UNSIGNED_DIV_REM, + EC_RECOVER_SUB_A_B, + A_B_BITAND_1, + EC_RECOVER_PRODUCT_MOD, + UINT256_MUL_INV_MOD_P, + EC_RECOVER_PRODUCT_DIV_M, + SQUARE_SLOPE_X_MOD_P, + SPLIT_XX, + RUN_P_CIRCUIT, + RUN_P_CIRCUIT_WITH_LARGE_BATCH_SIZE, + NONDET_ELEMENTS_OVER_TEN, + NONDET_ELEMENTS_OVER_TWO, + EXCESS_BALANCE, + // TODO(Amos): Load These hints from the cairo VM once the workspace version is upgraded to + // v2.0.0. + r#"from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P +from starkware.cairo.common.cairo_secp.secp_utils import pack + +q, r = divmod(pack(ids.val, PRIME), SECP256R1_P) +assert r == 0, f"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}." +ids.q = q % PRIME"#, + r#"from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P +from starkware.cairo.common.cairo_secp.secp_utils import pack + +slope = pack(ids.slope, SECP256R1_P) +x = pack(ids.point.x, SECP256R1_P) +y = pack(ids.point.y, SECP256R1_P) + +value = new_x = (pow(slope, 2, SECP256R1_P) - 2 * x) % SECP256R1_P"#, + r#"from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P +from starkware.cairo.common.cairo_secp.secp_utils import pack + +x = pack(ids.x, PRIME) % SECP256R1_P"#, + r#"from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P +from starkware.cairo.common.cairo_secp.secp_utils import pack +value = pack(ids.x, PRIME) % SECP256R1_P"#, + r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP256R1, pack +from starkware.python.math_utils import y_squared_from_x + +y_square_int = y_squared_from_x( + x=pack(ids.x, SECP256R1.prime), + alpha=SECP256R1.alpha, + beta=SECP256R1.beta, + field_prime=SECP256R1.prime, +) + +# Note that (y_square_int ** ((SECP256R1.prime + 1) / 4)) ** 2 = +# = y_square_int ** ((SECP256R1.prime + 1) / 2) = +# = y_square_int ** ((SECP256R1.prime - 1) / 2 + 1) = +# = y_square_int * y_square_int ** ((SECP256R1.prime - 1) / 2) = y_square_int * {+/-}1. +y = pow(y_square_int, (SECP256R1.prime + 1) // 4, SECP256R1.prime) + +# We need to decide whether to take y or prime - y. +if ids.v % 2 == y % 2: + value = y +else: + value = (-y) % SECP256R1.prime"#, + r#"from starkware.cairo.common.math_utils import as_int + +# Correctness check. +value = as_int(ids.value, PRIME) % PRIME +assert value < ids.UPPER_BOUND, f'{value} is outside of the range [0, 2**165).' + +# Calculation for the assertion. +ids.high, ids.low = divmod(ids.value, ids.SHIFT)"#, + r#"from starkware.python.math_utils import div_mod + +value = div_mod(1, x, SECP256R1_P)"#, + r#"from starkware.starknet.core.os.data_availability.bls_utils import BLS_PRIME, pack, split + +a = pack(ids.a, PRIME) +b = pack(ids.b, PRIME) + +q, r = divmod(a * b, BLS_PRIME) + +# By the assumption: |a|, |b| < 2**104 * ((2**86) ** 2 + 2**86 + 1) < 2**276.001. +# Therefore |q| <= |ab| / BLS_PRIME < 2**299. +# Hence the absolute value of the high limb of split(q) < 2**127. +segments.write_arg(ids.q.address_, split(q)) +segments.write_arg(ids.res.address_, split(r))"#, + r#"ids.is_on_curve = (y * y) % SECP256R1.prime == y_square_int"#, + r#"memory[fp + 0] = to_felt_or_relocatable(nibbles.pop())"#, + r#"num = (ids.scalar.high << 128) + ids.scalar.low +nibbles = [(num >> i) & 0xf for i in range(0, 256, 4)] +ids.first_nibble = nibbles.pop() +ids.last_nibble = nibbles[0]"#, + r#"value = new_y = (slope * (x - new_x) - y) % SECP256R1_P"#, + // This hint was modified to reflect changes in the Python crate. + r#"from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_ALPHA, SECP256R1_P +from starkware.cairo.common.cairo_secp.secp_utils import pack +from starkware.python.math_utils import ec_double_slope + +# Compute the slope. +x = pack(ids.point.x, PRIME) +y = pack(ids.point.y, PRIME) +value = slope = ec_double_slope(point=(x, y), alpha=SECP256R1_ALPHA, p=SECP256R1_P)"#, + // This hint was modified to reflect changes in the Python crate. + r#"from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P +from starkware.cairo.common.cairo_secp.secp_utils import pack + +slope = pack(ids.slope, PRIME) +x = pack(ids.point.x, PRIME) +y = pack(ids.point.y, PRIME) + +value = new_x = (pow(slope, 2, SECP256R1_P) - 2 * x) % SECP256R1_P"#, + // This hint was modified to reflect changes in the Python crate. + r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP256R1, pack +from starkware.python.math_utils import y_squared_from_x + +y_square_int = y_squared_from_x( + x=pack(ids.x, PRIME), + alpha=SECP256R1.alpha, + beta=SECP256R1.beta, + field_prime=SECP256R1.prime, +) + +# Note that (y_square_int ** ((SECP256R1.prime + 1) / 4)) ** 2 = +# = y_square_int ** ((SECP256R1.prime + 1) / 2) = +# = y_square_int ** ((SECP256R1.prime - 1) / 2 + 1) = +# = y_square_int * y_square_int ** ((SECP256R1.prime - 1) / 2) = y_square_int * {+/-}1. +y = pow(y_square_int, (SECP256R1.prime + 1) // 4, SECP256R1.prime) + +# We need to decide whether to take y or prime - y. +if ids.v % 2 == y % 2: + value = y +else: + value = (-y) % SECP256R1.prime"#, + ]) +} diff --git a/crates/starknet_committer_and_os_cli/src/shared_utils.rs b/crates/starknet_committer_and_os_cli/src/shared_utils.rs new file mode 100644 index 00000000000..cfef6ac46f4 --- /dev/null +++ b/crates/starknet_committer_and_os_cli/src/shared_utils.rs @@ -0,0 +1,2 @@ +pub mod read; +pub mod types; diff --git a/crates/starknet_committer_and_os_cli/src/shared_utils/read.rs b/crates/starknet_committer_and_os_cli/src/shared_utils/read.rs new file mode 100644 index 00000000000..6c99ece97c2 --- /dev/null +++ b/crates/starknet_committer_and_os_cli/src/shared_utils/read.rs @@ -0,0 +1,29 @@ +use std::fs::File; +use std::io::BufWriter; + +use serde::{Deserialize, Serialize}; +use tracing::info; + +pub fn read_input(input_path: String) -> String { + String::from_utf8( + std::fs::read(input_path.clone()) + .unwrap_or_else(|_| panic!("Failed to read from {input_path}")), + ) + .expect("Failed to convert bytes to string.") +} + +pub fn load_input Deserialize<'a>>(input_path: String) -> T { + info!("Reading input from file: {input_path}."); + let input_bytes = std::fs::read(input_path.clone()) + .unwrap_or_else(|_| panic!("Failed to read from {input_path}")); + info!("Done reading {} bytes from {input_path}. Deserializing...", input_bytes.len()); + let result = serde_json::from_slice::(&input_bytes) + .unwrap_or_else(|e| panic!("Failed to deserialize data from {input_path}. Error: {e:?}")); + info!("Successfully deserialized data from {input_path}."); + result +} + +pub fn write_to_file(file_path: &str, object: &T) { + let file_buffer = BufWriter::new(File::create(file_path).expect("Failed to create file")); + serde_json::to_writer(file_buffer, object).expect("Failed to serialize"); +} diff --git a/crates/starknet_committer_and_os_cli/src/shared_utils/types.rs b/crates/starknet_committer_and_os_cli/src/shared_utils/types.rs new file mode 100644 index 00000000000..b844e30aa27 --- /dev/null +++ b/crates/starknet_committer_and_os_cli/src/shared_utils/types.rs @@ -0,0 +1,74 @@ +use std::fmt::Debug; + +use clap::Args; + +use crate::shared_utils::read::{read_input, write_to_file}; + +pub(crate) type PythonTestResult = Result>; + +#[derive(Debug, Args)] +pub(crate) struct IoArgs { + /// File path to input. + #[clap(long, short = 'i')] + pub(crate) input_path: String, + + /// File path to output. + #[clap(long, short = 'o', default_value = "stdout")] + pub(crate) output_path: String, +} + +#[derive(Debug, Args)] +pub(crate) struct PythonTestArg { + // TODO(Amos): Make this optional. + #[clap(flatten)] + pub(crate) io_args: IoArgs, + + /// Test name. + #[clap(long)] + pub(crate) test_name: String, +} + +/// Error type for PythonTest enum. +#[derive(Debug, thiserror::Error)] +pub enum PythonTestError { + #[error("Unknown test name: {0}")] + UnknownTestName(String), + #[error(transparent)] + ParseInputError(#[from] serde_json::Error), + #[error("None value found in input.")] + NoneInputError, + #[error(transparent)] + SpecificError(E), +} + +pub(crate) trait PythonTestRunner: TryFrom { + type SpecificError: Debug; + + /// Returns the input string if it's `Some`, or an error if it's `None`. + fn non_optional_input( + input: Option<&str>, + ) -> Result<&str, PythonTestError> { + input.ok_or(PythonTestError::NoneInputError) + } + + async fn run(&self, input: Option<&str>) -> PythonTestResult; +} + +pub(crate) async fn run_python_test(python_test_arg: PythonTestArg) +where + >::Error: Debug, +{ + // Create PythonTest from test_name. + let test = PT::try_from(python_test_arg.test_name) + .unwrap_or_else(|error| panic!("Failed to create PythonTest: {:?}", error)); + let input = read_input(python_test_arg.io_args.input_path); + + // Run relevant test. + let output = test + .run(Some(&input)) + .await + .unwrap_or_else(|error| panic!("Failed to run test: {:?}", error)); + + // Write test's output. + write_to_file(&python_test_arg.io_args.output_path, &output); +} diff --git a/crates/committer_cli/src/tracing_utils.rs b/crates/starknet_committer_and_os_cli/src/tracing_utils.rs similarity index 86% rename from crates/committer_cli/src/tracing_utils.rs rename to crates/starknet_committer_and_os_cli/src/tracing_utils.rs index 2a859abdd18..1c2f5b4ff45 100644 --- a/crates/committer_cli/src/tracing_utils.rs +++ b/crates/starknet_committer_and_os_cli/src/tracing_utils.rs @@ -3,7 +3,7 @@ use tracing_subscriber::prelude::*; use tracing_subscriber::reload::Handle; use tracing_subscriber::{filter, fmt, reload, Registry}; -// TODO(Amos, 1/8/2024) Move all tracing instantiations in the Sequencer repo to a common location. +// TODO(Amos, 1/8/2024): Move all tracing instantiations in the Sequencer repo to a common location. pub fn configure_tracing() -> Handle { // Create a handle to the global filter to allow setting log level at runtime. let (global_filter, global_filter_handle) = reload::Layer::new(filter::LevelFilter::INFO); diff --git a/crates/committer_cli/test_inputs/committer_flow_inputs.json b/crates/starknet_committer_and_os_cli/test_inputs/committer_flow_inputs.json similarity index 100% rename from crates/committer_cli/test_inputs/committer_flow_inputs.json rename to crates/starknet_committer_and_os_cli/test_inputs/committer_flow_inputs.json diff --git a/crates/committer_cli/test_inputs/tree_flow_inputs.json b/crates/starknet_committer_and_os_cli/test_inputs/tree_flow_inputs.json similarity index 100% rename from crates/committer_cli/test_inputs/tree_flow_inputs.json rename to crates/starknet_committer_and_os_cli/test_inputs/tree_flow_inputs.json diff --git a/crates/sequencing/papyrus_consensus/Cargo.toml b/crates/starknet_consensus/Cargo.toml similarity index 79% rename from crates/sequencing/papyrus_consensus/Cargo.toml rename to crates/starknet_consensus/Cargo.toml index 743557a0da1..6c45f5f8e08 100644 --- a/crates/sequencing/papyrus_consensus/Cargo.toml +++ b/crates/starknet_consensus/Cargo.toml @@ -1,11 +1,14 @@ [package] -name = "papyrus_consensus" +name = "starknet_consensus" version.workspace = true edition.workspace = true repository.workspace = true license-file.workspace = true description = "Reach consensus for Starknet" +[features] +testing = [] + [dependencies] async-trait.workspace = true clap = { workspace = true, features = ["derive"] } @@ -20,15 +23,20 @@ papyrus_config.workspace = true papyrus_network.workspace = true papyrus_network_types.workspace = true papyrus_protobuf.workspace = true +prost.workspace = true serde = { workspace = true, features = ["derive"] } starknet-types-core.workspace = true starknet_api.workspace = true +starknet_sequencer_metrics.workspace = true +strum.workspace = true +strum_macros.workspace = true thiserror.workspace = true -tokio.workspace = true +tokio = { workspace = true, features = ["sync"] } tracing.workspace = true +validator.workspace = true [dev-dependencies] -enum-as-inner = "0.6.1" +enum-as-inner.workspace = true mockall.workspace = true papyrus_network = { workspace = true, features = ["testing"] } papyrus_network_types = { workspace = true, features = ["testing"] } diff --git a/crates/sequencing/papyrus_consensus/README.md b/crates/starknet_consensus/README.md similarity index 84% rename from crates/sequencing/papyrus_consensus/README.md rename to crates/starknet_consensus/README.md index 10c315e30a9..b85bdeb4086 100644 --- a/crates/sequencing/papyrus_consensus/README.md +++ b/crates/starknet_consensus/README.md @@ -29,7 +29,7 @@ cargo run --package papyrus_node --bin papyrus_node -- --base_layer.node_url --network.#is_none false --consensus.#is_none false --consensus.validator_id 0x --network.tcp_port --network.bootstrap_peer_multiaddr.#is_none false --rpc.server_address 127.0.0.1: --monitoring_gateway.server_address 127.0.0.1: --storage.db_config.path_prefix --network.bootstrap_peer_multiaddr /ip4/127.0.0.1/tcp/10000/p2p/ +cargo run --package papyrus_node --bin papyrus_node -- --base_layer.node_url --network.#is_none false --consensus.#is_none false --consensus.validator_id 0x --network.port --network.bootstrap_peer_multiaddr.#is_none false --rpc.server_address 127.0.0.1: --monitoring_gateway.server_address 127.0.0.1: --storage.db_config.path_prefix --network.bootstrap_peer_multiaddr /ip4/127.0.0.1/tcp/10000/p2p/ ``` - Node 0 is the first proposer and should be run last. diff --git a/crates/sequencing/papyrus_consensus/src/bin/run_simulation.rs b/crates/starknet_consensus/src/bin/run_simulation.rs similarity index 89% rename from crates/sequencing/papyrus_consensus/src/bin/run_simulation.rs rename to crates/starknet_consensus/src/bin/run_simulation.rs index 4ebb40c8af8..ece0cca7052 100644 --- a/crates/sequencing/papyrus_consensus/src/bin/run_simulation.rs +++ b/crates/starknet_consensus/src/bin/run_simulation.rs @@ -4,6 +4,7 @@ //! uses the `run_consensus` binary which is able to simulate network issues for consensus messages. use std::collections::HashSet; use std::fs::{self, File}; +use std::net::TcpListener; use std::os::unix::process::CommandExt; use std::process::Command; use std::str::FromStr; @@ -13,7 +14,7 @@ use clap::Parser; use fs2::FileExt; use lazy_static::lazy_static; use nix::unistd::Pid; -use papyrus_common::tcp::find_free_port; +use papyrus_protobuf::consensus::DEFAULT_VALIDATOR_ID; use tokio::process::Command as TokioCommand; lazy_static! { @@ -180,10 +181,23 @@ impl LockDir { impl Drop for LockDir { fn drop(&mut self) { - let _ = self.lockfile.unlock(); + // Due to [#48919](https://github.com/rust-lang/rust/issues/48919) we use fully qualified + // syntax (from rust 1.84), instead of `self.lockfile.unlock()`. + let _ = fs2::FileExt::unlock(&self.lockfile); } } +// WARNING(Tsabary): This is not a reliable way to obtain a free port; most notably it fails when +// multiple concurrent instances try to obtain ports using this function. Do NOT use this in +// production code, nor in tests, as they run concurrently. +fn find_free_port() -> u16 { + // The socket is automatically closed when the function exits. + // The port may still be available when accessed, but this is not guaranteed. + // TODO(Asmaa): find a reliable way to ensure the port stays free. + let listener = TcpListener::bind("0.0.0.0:0").expect("Failed to bind"); + listener.local_addr().expect("Failed to get local address").port() +} + fn parse_duration(s: &str) -> Result { let secs = u64::from_str(s)?; Ok(Duration::from_secs(secs)) @@ -262,21 +276,22 @@ async fn run_simulation( async fn build_node(data_dir: &str, logs_dir: &str, i: usize, papyrus_args: &PapyrusArgs) -> Node { let is_bootstrap = i == 1; - let tcp_port = if is_bootstrap { *BOOTNODE_TCP_PORT } else { find_free_port() }; + let port = if is_bootstrap { *BOOTNODE_TCP_PORT } else { find_free_port() }; let monitoring_gateway_server_port = find_free_port(); let data_dir = format!("{}/data{}", data_dir, i); + let validator_id = i + usize::try_from(DEFAULT_VALIDATOR_ID).expect("Conversion failed"); let mut cmd = format!( - "RUST_LOG=papyrus_consensus=debug,papyrus=info target/release/run_consensus \ + "RUST_LOG=starknet_consensus=debug,papyrus=info target/release/run_consensus \ --network.#is_none false --base_layer.node_url {} --storage.db_config.path_prefix {} \ - --consensus.#is_none false --consensus.validator_id 0x{} --consensus.num_validators {} \ - --network.tcp_port {} --rpc.server_address 127.0.0.1:{} \ - --monitoring_gateway.server_address 127.0.0.1:{} --collect_metrics true ", + --consensus.#is_none false --consensus.validator_id 0x{:x} --consensus.num_validators {} \ + --network.port {} --rpc.server_address 127.0.0.1:{} --monitoring_gateway.server_address \ + 127.0.0.1:{} --collect_metrics true ", papyrus_args.base_layer_node_url, data_dir, - i, + validator_id, papyrus_args.num_validators, - tcp_port, + port, find_free_port(), monitoring_gateway_server_port ); @@ -310,19 +325,20 @@ async fn build_node(data_dir: &str, logs_dir: &str, i: usize, papyrus_args: &Pap if is_bootstrap { cmd.push_str(&format!( - "--network.secret_key {} 2>&1 | sed -r 's/\\x1B\\[[0-9;]*[mK]//g' > {}/validator{}.txt", - SECRET_KEY, logs_dir, i + "--network.secret_key {} 2>&1 | sed -r 's/\\x1B\\[[0-9;]*[mK]//g' > \ + {}/validator0x{:x}.txt", + SECRET_KEY, logs_dir, validator_id )); } else { cmd.push_str(&format!( "--network.bootstrap_peer_multiaddr.#is_none false --network.bootstrap_peer_multiaddr \ /ip4/127.0.0.1/tcp/{}/p2p/{} 2>&1 | sed -r 's/\\x1B\\[[0-9;]*[mK]//g' > \ - {}/validator{}.txt", - *BOOTNODE_TCP_PORT, BOOT_NODE_PEER_ID, logs_dir, i + {}/validator0x{:x}.txt", + *BOOTNODE_TCP_PORT, BOOT_NODE_PEER_ID, logs_dir, validator_id )); } - Node::new(i, monitoring_gateway_server_port, cmd) + Node::new(validator_id, monitoring_gateway_server_port, cmd) } async fn build_all_nodes(data_dir: &str, logs_dir: &str, papyrus_args: &PapyrusArgs) -> Vec { diff --git a/crates/sequencing/papyrus_consensus/src/config.rs b/crates/starknet_consensus/src/config.rs similarity index 67% rename from crates/sequencing/papyrus_consensus/src/config.rs rename to crates/starknet_consensus/src/config.rs index 97ed7f4656e..082ceea62b1 100644 --- a/crates/sequencing/papyrus_consensus/src/config.rs +++ b/crates/starknet_consensus/src/config.rs @@ -11,35 +11,31 @@ use papyrus_config::converters::{ }; use papyrus_config::dumping::{append_sub_config_name, ser_param, SerializeConfig}; use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; -use papyrus_network::NetworkConfig; +use papyrus_protobuf::consensus::DEFAULT_VALIDATOR_ID; use serde::{Deserialize, Serialize}; -use starknet_api::block::BlockNumber; +use validator::Validate; -use super::types::ValidatorId; - -const CONSENSUS_TCP_PORT: u16 = 10100; -const CONSENSUS_QUIC_PORT: u16 = 10101; +use crate::types::ValidatorId; /// Configuration for consensus. -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Validate)] pub struct ConsensusConfig { /// The validator ID of the node. pub validator_id: ValidatorId, - /// The network topic of the consensus. - pub network_topic: String, - /// The height to start the consensus from. - pub start_height: BlockNumber, - /// The number of validators in the consensus. - // Used for testing in an early milestones. - pub num_validators: u64, /// The delay (seconds) before starting consensus to give time for network peering. #[serde(deserialize_with = "deserialize_seconds_to_duration")] - pub consensus_delay: Duration, + pub startup_delay: Duration, /// Timeouts configuration for consensus. pub timeouts: TimeoutsConfig, - // TODO(Dan/Matan): validate configs (#[validate]). - /// The network configuration for the consensus. - pub network_config: NetworkConfig, + /// The duration (seconds) between sync attempts. + #[serde(deserialize_with = "deserialize_float_seconds_to_duration")] + pub sync_retry_interval: Duration, + /// How many heights in the future should we cache. + pub future_height_limit: u32, + /// How many rounds in the future (for current height) should we cache. + pub future_round_limit: u32, + /// How many rounds should we cache for future heights. + pub future_height_round_limit: u32, } impl SerializeConfig for ConsensusConfig { @@ -52,51 +48,51 @@ impl SerializeConfig for ConsensusConfig { ParamPrivacyInput::Public, ), ser_param( - "network_topic", - &self.network_topic, - "The network topic of the consensus.", + "startup_delay", + &self.startup_delay.as_secs(), + "Delay (seconds) before starting consensus to give time for network peering.", + ParamPrivacyInput::Public, + ), + ser_param( + "sync_retry_interval", + &self.sync_retry_interval.as_secs_f64(), + "The duration (seconds) between sync attempts.", ParamPrivacyInput::Public, ), ser_param( - "start_height", - &self.start_height, - "The height to start the consensus from.", + "future_height_limit", + &self.future_height_limit, + "How many heights in the future should we cache.", ParamPrivacyInput::Public, ), ser_param( - "num_validators", - &self.num_validators, - "The number of validators in the consensus.", + "future_round_limit", + &self.future_round_limit, + "How many rounds in the future (for current height) should we cache.", ParamPrivacyInput::Public, ), ser_param( - "consensus_delay", - &self.consensus_delay.as_secs(), - "Delay (seconds) before starting consensus to give time for network peering.", + "future_height_round_limit", + &self.future_height_round_limit, + "How many rounds should we cache for future heights.", ParamPrivacyInput::Public, ), ]); config.extend(append_sub_config_name(self.timeouts.dump(), "timeouts")); - config.extend(append_sub_config_name(self.network_config.dump(), "network_config")); config } } impl Default for ConsensusConfig { fn default() -> Self { - let network_config = NetworkConfig { - tcp_port: CONSENSUS_TCP_PORT, - quic_port: CONSENSUS_QUIC_PORT, - ..Default::default() - }; Self { - validator_id: ValidatorId::default(), - network_topic: "consensus".to_string(), - start_height: BlockNumber::default(), - num_validators: 1, - consensus_delay: Duration::from_secs(5), + validator_id: ValidatorId::from(DEFAULT_VALIDATOR_ID), + startup_delay: Duration::from_secs(5), timeouts: TimeoutsConfig::default(), - network_config, + sync_retry_interval: Duration::from_secs_f64(1.0), + future_height_limit: 10, + future_round_limit: 10, + future_height_round_limit: 1, } } } diff --git a/crates/starknet_consensus/src/lib.rs b/crates/starknet_consensus/src/lib.rs new file mode 100644 index 00000000000..921a6b31b61 --- /dev/null +++ b/crates/starknet_consensus/src/lib.rs @@ -0,0 +1,43 @@ +#![warn(missing_docs)] +// TODO(Matan): Add links to the spec. +// TODO(Matan): fix #[allow(missing_docs)]. +//! A consensus implementation for a [Starknet](https://www.starknet.io/) node. The consensus +//! algorithm is based on [Tendermint](https://arxiv.org/pdf/1807.04938). +//! +//! Consensus communicates with other nodes via a gossip network; sending and receiving votes on one +//! topic and streaming proposals on a separate topic. [details](https://github.com/starknet-io/starknet-p2p-specs/tree/main/p2p/proto/consensus). +//! +//! In addition to the network inputs, consensus reaches out to the rest of the node via the +//! [`Context`](types::ConsensusContext) API. +//! +//! Consensus is generic over the content of the proposals, and merely requires an identifier to be +//! produced by the Context. +//! +//! Consensus operates in two modes: +//! 1. Observer - Receives consensus messages and updates the node when a decision is reached. +//! 2. Active - In addition to receiving messages, the node can also send messages to the network. +//! +//! Observer mode offers lower latency compared to sync, as Proposals and votes are processed in +//! real-time rather than after a decision has been made. +//! +//! Consensus is an active component, it doesn't follow the server/client model: +//! 1. The outbound messages are not sent as responses to the inbound messages. +//! 2. It generates and runs its own events (e.g. timeouts). + +pub mod config; +#[allow(missing_docs)] +pub mod types; +pub use manager::run_consensus; +#[allow(missing_docs)] +pub mod metrics; +#[allow(missing_docs)] +pub mod simulation_network_receiver; +pub mod stream_handler; + +mod manager; +#[allow(missing_docs)] +mod single_height_consensus; +#[allow(missing_docs)] +mod state_machine; +#[cfg(test)] +pub(crate) mod test_utils; diff --git a/crates/starknet_consensus/src/manager.rs b/crates/starknet_consensus/src/manager.rs new file mode 100644 index 00000000000..0dfe1258ee6 --- /dev/null +++ b/crates/starknet_consensus/src/manager.rs @@ -0,0 +1,490 @@ +//! Top level of consensus, used to run multiple heights of consensus. +//! +//! [`run_consensus`] - This is the primary entrypoint for running the consensus component. +//! +//! [`MultiHeightManager`] - Runs consensus repeatedly across different heights using +//! [`run_height`](MultiHeightManager::run_height). + +#[cfg(test)] +#[path = "manager_test.rs"] +mod manager_test; + +use std::collections::BTreeMap; +use std::time::Duration; + +use futures::channel::mpsc; +use futures::stream::FuturesUnordered; +use futures::{FutureExt, StreamExt}; +use metrics::counter; +use papyrus_common::metrics::{PAPYRUS_CONSENSUS_HEIGHT, PAPYRUS_CONSENSUS_SYNC_COUNT}; +use papyrus_network::network_manager::BroadcastTopicClientTrait; +use papyrus_network_types::network_types::BroadcastedMessageMetadata; +use papyrus_protobuf::consensus::{ProposalInit, Vote}; +use papyrus_protobuf::converters::ProtobufConversionError; +use starknet_api::block::BlockNumber; +use tracing::{debug, error, info, instrument, trace, warn}; + +use crate::config::TimeoutsConfig; +use crate::metrics::{ + register_metrics, + CONSENSUS_BLOCK_NUMBER, + CONSENSUS_CACHED_VOTES, + CONSENSUS_DECISIONS_REACHED_BY_CONSENSUS, + CONSENSUS_DECISIONS_REACHED_BY_SYNC, + CONSENSUS_MAX_CACHED_BLOCK_NUMBER, + CONSENSUS_PROPOSALS_RECEIVED, +}; +use crate::single_height_consensus::{ShcReturn, SingleHeightConsensus}; +use crate::types::{BroadcastVoteChannel, ConsensusContext, ConsensusError, Decision, ValidatorId}; + +/// Run consensus indefinitely. +/// +/// If a decision is reached via consensus the context is updated. If a decision is learned via the +/// sync protocol, consensus silently moves on to the next height. +/// +/// Inputs: +/// - `context`: The API for consensus to reach out to the rest of the node. +/// - `start_active_height`: The height at which the node may participate in consensus (if it is a +/// validator). +/// - `start_observe_height`: The height at which the node begins to run consensus. +/// - `validator_id`: The ID of this node. +/// - `consensus_delay`: delay before starting consensus; allowing the network to connect to peers. +/// - `timeouts`: The timeouts for the consensus algorithm. +/// - `sync_retry_interval`: The interval to wait between sync retries. +/// - `vote_receiver`: The channels to receive votes from the network. These are self contained +/// messages. +/// - `proposal_receiver`: The channel to receive proposals from the network. Proposals are +/// represented as streams (ProposalInit, Content.*, ProposalFin). +// TODO(dvir): add test for this. +// TODO(Asmaa): Update documentation when we update for the real sync. +// Always print the validator ID since some tests collate multiple consensus logs in a single file. +#[instrument(skip_all, fields(%validator_id), level = "error")] +#[allow(missing_docs)] +#[allow(clippy::too_many_arguments)] +pub async fn run_consensus( + mut context: ContextT, + start_active_height: BlockNumber, + start_observe_height: BlockNumber, + validator_id: ValidatorId, + consensus_delay: Duration, + timeouts: TimeoutsConfig, + sync_retry_interval: Duration, + mut vote_receiver: BroadcastVoteChannel, + mut proposal_receiver: mpsc::Receiver>, +) -> Result<(), ConsensusError> +where + ContextT: ConsensusContext, +{ + info!( + "Running consensus, start_active_height={start_active_height}, \ + start_observe_height={start_observe_height}, consensus_delay={}, timeouts={timeouts:?}", + consensus_delay.as_secs(), + ); + register_metrics(); + // Add a short delay to allow peers to connect and avoid "InsufficientPeers" error + tokio::time::sleep(consensus_delay).await; + assert!(start_observe_height <= start_active_height); + let mut current_height = start_observe_height; + let mut manager = MultiHeightManager::new(validator_id, timeouts); + #[allow(clippy::as_conversions)] // FIXME: use int metrics so `as f64` may be removed. + loop { + metrics::gauge!(PAPYRUS_CONSENSUS_HEIGHT).set(current_height.0 as f64); + + let must_observer = current_height < start_active_height; + match manager + .run_height( + &mut context, + current_height, + must_observer, + sync_retry_interval, + &mut vote_receiver, + &mut proposal_receiver, + ) + .await? + { + RunHeightRes::Decision(decision) => { + // We expect there to be under 100 validators, so this is a reasonable number of + // precommits to print. + info!("Decision reached. {:?}", decision); + CONSENSUS_DECISIONS_REACHED_BY_CONSENSUS.increment(1); + context.decision_reached(decision.block, decision.precommits).await?; + } + RunHeightRes::Sync => { + info!(height = current_height.0, "Decision learned via sync protocol."); + CONSENSUS_DECISIONS_REACHED_BY_SYNC.increment(1); + counter!(PAPYRUS_CONSENSUS_SYNC_COUNT).increment(1); + } + } + current_height = current_height.unchecked_next(); + } +} + +/// Run height can end either when consensus reaches a decision or when we learn, via sync, of the +/// decision. +#[derive(Debug, PartialEq)] +pub enum RunHeightRes { + /// Decision reached. + Decision(Decision), + /// Decision learned via sync. + Sync, +} + +type ProposalReceiverTuple = (ProposalInit, mpsc::Receiver); + +/// Runs Tendermint repeatedly across different heights. Handles issues which are not explicitly +/// part of the single height consensus algorithm (e.g. messages from future heights). +#[derive(Debug, Default)] +struct MultiHeightManager { + validator_id: ValidatorId, + future_votes: BTreeMap>, + // Mapping: { Height : { Round : (Init, Receiver)}} + cached_proposals: BTreeMap>>, + timeouts: TimeoutsConfig, +} + +impl MultiHeightManager { + /// Create a new consensus manager. + pub(crate) fn new(validator_id: ValidatorId, timeouts: TimeoutsConfig) -> Self { + Self { + validator_id, + future_votes: BTreeMap::new(), + cached_proposals: BTreeMap::new(), + timeouts, + } + } + + /// Run the consensus algorithm for a single height. + /// + /// A height of consensus ends either when the node learns of a decision, either by consensus + /// directly or via the sync protocol. + /// - An error implies that consensus cannot continue, not just that the current height failed. + /// + /// This is the "top level" task of consensus, which is able to multiplex across activities: + /// network messages and self generated events. + /// + /// Assumes that `height` is monotonically increasing across calls. + /// + /// Inputs - see [`run_consensus`]. + /// - `must_observer`: Whether the node must observe or if it is allowed to be active (assuming + /// it is in the validator set). + #[instrument(skip_all, fields(height=%height.0), level = "error")] + pub(crate) async fn run_height( + &mut self, + context: &mut ContextT, + height: BlockNumber, + must_observer: bool, + sync_retry_interval: Duration, + broadcast_channels: &mut BroadcastVoteChannel, + proposal_receiver: &mut mpsc::Receiver>, + ) -> Result { + let res = self + .run_height_inner( + context, + height, + must_observer, + sync_retry_interval, + broadcast_channels, + proposal_receiver, + ) + .await?; + + // Networking layer assumes messages are handled in a timely fashion, otherwise we may build + // up a backlog of useless messages. Similarly we don't want to waste space on old messages. + // This is particularly important when there is a significant lag and we continually finish + // heights immediately due to sync. + self.get_current_height_votes(height); + while let Some(message) = + broadcast_channels.broadcasted_messages_receiver.next().now_or_never() + { + self.handle_vote(context, height, None, message, broadcast_channels).await?; + } + self.get_current_height_proposals(height); + while let Ok(content_receiver) = proposal_receiver.try_next() { + self.handle_proposal(context, height, None, content_receiver).await?; + } + + Ok(res) + } + + async fn run_height_inner( + &mut self, + context: &mut ContextT, + height: BlockNumber, + must_observer: bool, + sync_retry_interval: Duration, + broadcast_channels: &mut BroadcastVoteChannel, + proposal_receiver: &mut mpsc::Receiver>, + ) -> Result { + self.report_max_cached_block_number_metric(height); + if context.try_sync(height).await { + return Ok(RunHeightRes::Sync); + } + + let validators = context.validators(height).await; + let is_observer = must_observer || !validators.contains(&self.validator_id); + info!( + "running consensus for height {height:?}. is_observer: {is_observer}, validators: \ + {validators:?}" + ); + CONSENSUS_BLOCK_NUMBER.set_lossy(height.0); + + let mut shc = SingleHeightConsensus::new( + height, + is_observer, + self.validator_id, + validators, + self.timeouts.clone(), + ); + let mut shc_events = FuturesUnordered::new(); + + match self.start_height(context, height, &mut shc).await? { + ShcReturn::Decision(decision) => { + return Ok(RunHeightRes::Decision(decision)); + } + ShcReturn::Tasks(tasks) => { + for task in tasks { + shc_events.push(task.run()); + } + } + } + + // Loop over incoming proposals, messages, and self generated events. + loop { + self.report_max_cached_block_number_metric(height); + let shc_return = tokio::select! { + message = broadcast_channels.broadcasted_messages_receiver.next() => { + self.handle_vote( + context, height, Some(&mut shc), message, broadcast_channels).await? + }, + content_receiver = proposal_receiver.next() => { + self.handle_proposal(context, height, Some(&mut shc), content_receiver).await? + }, + Some(shc_event) = shc_events.next() => { + shc.handle_event(context, shc_event).await? + }, + _ = tokio::time::sleep(sync_retry_interval) => { + if context.try_sync(height).await { + return Ok(RunHeightRes::Sync); + } + continue; + } + }; + + match shc_return { + ShcReturn::Decision(decision) => return Ok(RunHeightRes::Decision(decision)), + ShcReturn::Tasks(tasks) => { + for task in tasks { + shc_events.push(task.run()); + } + } + } + } + } + + async fn start_height( + &mut self, + context: &mut ContextT, + height: BlockNumber, + shc: &mut SingleHeightConsensus, + ) -> Result { + CONSENSUS_CACHED_VOTES.set_lossy(self.future_votes.entry(height.0).or_default().len()); + let mut tasks = match shc.start(context).await? { + decision @ ShcReturn::Decision(_) => { + // Start should generate either TimeoutProposal (validator) or GetProposal + // (proposer). We do not enforce this since the Manager is + // intentionally not meant to understand consensus in detail. + warn!("Decision reached at start of height. {:?}", decision); + return Ok(decision); + } + ShcReturn::Tasks(tasks) => tasks, + }; + + let cached_proposals = self.get_current_height_proposals(height); + trace!("Cached proposals for height {}: {:?}", height, cached_proposals); + for (init, content_receiver) in cached_proposals { + match shc.handle_proposal(context, init, content_receiver).await? { + decision @ ShcReturn::Decision(_) => return Ok(decision), + ShcReturn::Tasks(new_tasks) => tasks.extend(new_tasks), + } + } + + let cached_votes = self.get_current_height_votes(height); + trace!("Cached votes for height {}: {:?}", height, cached_votes); + for msg in cached_votes { + match shc.handle_vote(context, msg).await? { + decision @ ShcReturn::Decision(_) => return Ok(decision), + ShcReturn::Tasks(new_tasks) => tasks.extend(new_tasks), + } + } + + Ok(ShcReturn::Tasks(tasks)) + } + + // Handle a new proposal receiver from the network. + // shc - None if the height was just completed and we should drop the message. + async fn handle_proposal( + &mut self, + context: &mut ContextT, + height: BlockNumber, + shc: Option<&mut SingleHeightConsensus>, + content_receiver: Option>, + ) -> Result { + CONSENSUS_PROPOSALS_RECEIVED.increment(1); + // Get the first message to verify the init was sent. + let Some(mut content_receiver) = content_receiver else { + return Err(ConsensusError::InternalNetworkError( + "proposal receiver should never be closed".to_string(), + )); + }; + let Some(first_part) = content_receiver.try_next().map_err(|_| { + ConsensusError::InternalNetworkError( + "Stream handler must fill the first message before sending the stream".to_string(), + ) + })? + else { + return Err(ConsensusError::InternalNetworkError( + "Proposal receiver closed".to_string(), + )); + }; + let proposal_init: ProposalInit = first_part.try_into()?; + + match proposal_init.height.cmp(&height) { + std::cmp::Ordering::Greater => { + debug!("Received a proposal for a future height. {:?}", proposal_init); + // Note: new proposals with the same height/round will be ignored. + self.cached_proposals + .entry(proposal_init.height.0) + .or_default() + .entry(proposal_init.round) + .or_insert((proposal_init, content_receiver)); + Ok(ShcReturn::Tasks(Vec::new())) + } + std::cmp::Ordering::Less => { + trace!("Drop proposal from past height. {:?}", proposal_init); + Ok(ShcReturn::Tasks(Vec::new())) + } + std::cmp::Ordering::Equal => match shc { + Some(shc) => shc.handle_proposal(context, proposal_init, content_receiver).await, + None => { + trace!("Drop proposal from just completed height. {:?}", proposal_init); + Ok(ShcReturn::Tasks(Vec::new())) + } + }, + } + } + + // Handle a single consensus message. + // shc - None if the height was just completed and we should drop the message. + async fn handle_vote( + &mut self, + context: &mut ContextT, + height: BlockNumber, + shc: Option<&mut SingleHeightConsensus>, + vote: Option<(Result, BroadcastedMessageMetadata)>, + broadcast_channels: &mut BroadcastVoteChannel, + ) -> Result { + let message = match vote { + None => Err(ConsensusError::InternalNetworkError( + "NetworkReceiver should never be closed".to_string(), + )), + Some((Ok(msg), metadata)) => { + // TODO(matan): Hold onto report_sender for use in later errors by SHC. + if broadcast_channels + .broadcast_topic_client + .continue_propagation(&metadata) + .now_or_never() + .is_none() + { + error!("Unable to send continue_propogation. {:?}", metadata); + } + Ok(msg) + } + Some((Err(e), metadata)) => { + // Failed to parse consensus message + if broadcast_channels + .broadcast_topic_client + .report_peer(metadata.clone()) + .now_or_never() + .is_none() + { + error!("Unable to send report_peer. {:?}", metadata) + } + Err(e.into()) + } + }?; + + // TODO(matan): We need to figure out an actual caching strategy under 2 constraints: + // 1. Malicious - must be capped so a malicious peer can't DoS us. + // 2. Parallel proposals - we may send/receive a proposal for (H+1, 0). + match message.height.cmp(&height.0) { + std::cmp::Ordering::Greater => { + debug!("Cache message for a future height. {:?}", message); + self.future_votes.entry(message.height).or_default().push(message); + Ok(ShcReturn::Tasks(Vec::new())) + } + std::cmp::Ordering::Less => { + trace!("Drop message from past height. {:?}", message); + Ok(ShcReturn::Tasks(Vec::new())) + } + std::cmp::Ordering::Equal => match shc { + Some(shc) => shc.handle_vote(context, message).await, + None => { + trace!("Drop message from just completed height. {:?}", message); + Ok(ShcReturn::Tasks(Vec::new())) + } + }, + } + } + + // Checks if a cached proposal already exists (with correct height) + // - returns the proposal if it exists and removes it from the cache. + // - returns None if no proposal exists. + // - cleans up any proposals from earlier heights. + // - for a given height, returns the proposal with the lowest round (and removes it). + fn get_current_height_proposals( + &mut self, + height: BlockNumber, + ) -> Vec<(ProposalInit, mpsc::Receiver)> { + loop { + let Some(entry) = self.cached_proposals.first_entry() else { + return Vec::new(); + }; + match entry.key().cmp(&height.0) { + std::cmp::Ordering::Greater => return vec![], + std::cmp::Ordering::Equal => { + let submap = entry.remove(); + return submap.into_values().collect(); + } + std::cmp::Ordering::Less => { + entry.remove(); + } + } + } + } + + // Filters the cached messages: + // - returns all of the current height messages. + // - drops messages from earlier heights. + // - retains future messages in the cache. + fn get_current_height_votes(&mut self, height: BlockNumber) -> Vec { + // Depends on `future_votes` being sorted by height. + loop { + let Some(entry) = self.future_votes.first_entry() else { + return Vec::new(); + }; + match entry.key().cmp(&height.0) { + std::cmp::Ordering::Greater => return Vec::new(), + std::cmp::Ordering::Equal => return entry.remove(), + std::cmp::Ordering::Less => { + entry.remove(); + } + } + } + } + + fn report_max_cached_block_number_metric(&self, height: BlockNumber) { + // If nothing is cached use current height as "max". + let max_cached_block_number = self.cached_proposals.keys().max().unwrap_or(&height.0); + CONSENSUS_MAX_CACHED_BLOCK_NUMBER.set_lossy(*max_cached_block_number); + } +} diff --git a/crates/starknet_consensus/src/manager_test.rs b/crates/starknet_consensus/src/manager_test.rs new file mode 100644 index 00000000000..6536dd7ccdd --- /dev/null +++ b/crates/starknet_consensus/src/manager_test.rs @@ -0,0 +1,317 @@ +use std::time::Duration; +use std::vec; + +use futures::channel::{mpsc, oneshot}; +use futures::{FutureExt, SinkExt}; +use lazy_static::lazy_static; +use papyrus_network::network_manager::test_utils::{ + mock_register_broadcast_topic, + MockBroadcastedMessagesSender, + TestSubscriberChannels, +}; +use papyrus_network_types::network_types::BroadcastedMessageMetadata; +use papyrus_protobuf::consensus::{ProposalFin, Vote, DEFAULT_VALIDATOR_ID}; +use papyrus_test_utils::{get_rng, GetTestInstance}; +use starknet_api::block::{BlockHash, BlockNumber}; +use starknet_types_core::felt::Felt; + +use super::{run_consensus, MultiHeightManager, RunHeightRes}; +use crate::config::TimeoutsConfig; +use crate::test_utils::{precommit, prevote, proposal_init, MockTestContext, TestProposalPart}; +use crate::types::ValidatorId; + +lazy_static! { + static ref PROPOSER_ID: ValidatorId = DEFAULT_VALIDATOR_ID.into(); + static ref VALIDATOR_ID: ValidatorId = (DEFAULT_VALIDATOR_ID + 1).into(); + static ref VALIDATOR_ID_2: ValidatorId = (DEFAULT_VALIDATOR_ID + 2).into(); + static ref VALIDATOR_ID_3: ValidatorId = (DEFAULT_VALIDATOR_ID + 3).into(); + static ref TIMEOUTS: TimeoutsConfig = TimeoutsConfig { + prevote_timeout: Duration::from_millis(100), + precommit_timeout: Duration::from_millis(100), + proposal_timeout: Duration::from_millis(100), + }; +} + +const CHANNEL_SIZE: usize = 10; +const SYNC_RETRY_INTERVAL: Duration = Duration::from_millis(100); + +async fn send(sender: &mut MockBroadcastedMessagesSender, msg: Vote) { + let broadcasted_message_metadata = + BroadcastedMessageMetadata::get_test_instance(&mut get_rng()); + sender.send((msg, broadcasted_message_metadata)).await.unwrap(); +} + +async fn send_proposal( + proposal_receiver_sender: &mut mpsc::Sender>, + content: Vec, +) { + let (mut proposal_sender, proposal_receiver) = mpsc::channel(CHANNEL_SIZE); + proposal_receiver_sender.send(proposal_receiver).await.unwrap(); + for item in content { + proposal_sender.send(item).await.unwrap(); + } +} + +fn expect_validate_proposal(context: &mut MockTestContext, block_hash: Felt, times: usize) { + context + .expect_validate_proposal() + .returning(move |_, _, _| { + let (block_sender, block_receiver) = oneshot::channel(); + block_sender + .send(( + BlockHash(block_hash), + ProposalFin { proposal_commitment: BlockHash(block_hash) }, + )) + .unwrap(); + block_receiver + }) + .times(times); +} + +fn assert_decision(res: RunHeightRes, id: Felt) { + match res { + RunHeightRes::Decision(decision) => assert_eq!(decision.block, BlockHash(id)), + _ => panic!("Expected decision"), + } +} + +#[tokio::test] +async fn manager_multiple_heights_unordered() { + let TestSubscriberChannels { mock_network, subscriber_channels } = + mock_register_broadcast_topic().unwrap(); + let mut sender = mock_network.broadcasted_messages_sender; + + let (mut proposal_receiver_sender, mut proposal_receiver_receiver) = + mpsc::channel(CHANNEL_SIZE); + + // Send messages for height 2 followed by those for height 1. + send_proposal( + &mut proposal_receiver_sender, + vec![TestProposalPart::Init(proposal_init(2, 0, *PROPOSER_ID))], + ) + .await; + send(&mut sender, prevote(Some(Felt::TWO), 2, 0, *PROPOSER_ID)).await; + send(&mut sender, precommit(Some(Felt::TWO), 2, 0, *PROPOSER_ID)).await; + + send_proposal( + &mut proposal_receiver_sender, + vec![TestProposalPart::Init(proposal_init(1, 0, *PROPOSER_ID))], + ) + .await; + send(&mut sender, prevote(Some(Felt::ONE), 1, 0, *PROPOSER_ID)).await; + send(&mut sender, precommit(Some(Felt::ONE), 1, 0, *PROPOSER_ID)).await; + + let mut context = MockTestContext::new(); + // Run the manager for height 1. + context.expect_try_sync().returning(|_| false); + expect_validate_proposal(&mut context, Felt::ONE, 1); + context.expect_validators().returning(move |_| vec![*PROPOSER_ID, *VALIDATOR_ID]); + context.expect_proposer().returning(move |_, _| *PROPOSER_ID); + context.expect_set_height_and_round().returning(move |_, _| ()); + context.expect_broadcast().returning(move |_| Ok(())); + + let mut manager = MultiHeightManager::new(*VALIDATOR_ID, TIMEOUTS.clone()); + let mut subscriber_channels = subscriber_channels.into(); + let decision = manager + .run_height( + &mut context, + BlockNumber(1), + false, + SYNC_RETRY_INTERVAL, + &mut subscriber_channels, + &mut proposal_receiver_receiver, + ) + .await + .unwrap(); + assert_decision(decision, Felt::ONE); + + // Run the manager for height 2. + expect_validate_proposal(&mut context, Felt::TWO, 1); + let decision = manager + .run_height( + &mut context, + BlockNumber(2), + false, + SYNC_RETRY_INTERVAL, + &mut subscriber_channels, + &mut proposal_receiver_receiver, + ) + .await + .unwrap(); + assert_decision(decision, Felt::TWO); +} + +#[tokio::test] +async fn run_consensus_sync() { + // Set expectations. + let mut context = MockTestContext::new(); + let (decision_tx, decision_rx) = oneshot::channel(); + + let (mut proposal_receiver_sender, proposal_receiver_receiver) = mpsc::channel(CHANNEL_SIZE); + + expect_validate_proposal(&mut context, Felt::TWO, 1); + context.expect_validators().returning(move |_| vec![*PROPOSER_ID, *VALIDATOR_ID]); + context.expect_proposer().returning(move |_, _| *PROPOSER_ID); + context.expect_set_height_and_round().returning(move |_, _| ()); + context.expect_broadcast().returning(move |_| Ok(())); + context + .expect_decision_reached() + .withf(move |block, votes| *block == BlockHash(Felt::TWO) && votes[0].height == 2) + .return_once(move |_, _| { + decision_tx.send(()).unwrap(); + Ok(()) + }); + context + .expect_try_sync() + .withf(move |height| *height == BlockNumber(1)) + .times(1) + .returning(|_| true); + context.expect_try_sync().returning(|_| false); + + // Send messages for height 2. + send_proposal( + &mut proposal_receiver_sender, + vec![TestProposalPart::Init(proposal_init(2, 0, *PROPOSER_ID))], + ) + .await; + let TestSubscriberChannels { mock_network, subscriber_channels } = + mock_register_broadcast_topic().unwrap(); + let mut network_sender = mock_network.broadcasted_messages_sender; + send(&mut network_sender, prevote(Some(Felt::TWO), 2, 0, *PROPOSER_ID)).await; + send(&mut network_sender, precommit(Some(Felt::TWO), 2, 0, *PROPOSER_ID)).await; + + // Start at height 1. + tokio::spawn(async move { + run_consensus( + context, + BlockNumber(1), + BlockNumber(1), + *VALIDATOR_ID, + Duration::ZERO, + TIMEOUTS.clone(), + SYNC_RETRY_INTERVAL, + subscriber_channels.into(), + proposal_receiver_receiver, + ) + .await + }); + + // Decision for height 2. + decision_rx.await.unwrap(); +} + +#[tokio::test] +async fn test_timeouts() { + let TestSubscriberChannels { mock_network, subscriber_channels } = + mock_register_broadcast_topic().unwrap(); + let mut sender = mock_network.broadcasted_messages_sender; + + let (mut proposal_receiver_sender, mut proposal_receiver_receiver) = + mpsc::channel(CHANNEL_SIZE); + + send_proposal( + &mut proposal_receiver_sender, + vec![TestProposalPart::Init(proposal_init(1, 0, *PROPOSER_ID))], + ) + .await; + send(&mut sender, prevote(None, 1, 0, *VALIDATOR_ID_2)).await; + send(&mut sender, prevote(None, 1, 0, *VALIDATOR_ID_3)).await; + send(&mut sender, precommit(None, 1, 0, *VALIDATOR_ID_2)).await; + send(&mut sender, precommit(None, 1, 0, *VALIDATOR_ID_3)).await; + + let mut context = MockTestContext::new(); + context.expect_set_height_and_round().returning(move |_, _| ()); + expect_validate_proposal(&mut context, Felt::ONE, 2); + context + .expect_validators() + .returning(move |_| vec![*PROPOSER_ID, *VALIDATOR_ID, *VALIDATOR_ID_2, *VALIDATOR_ID_3]); + context.expect_proposer().returning(move |_, _| *PROPOSER_ID); + context.expect_try_sync().returning(|_| false); + + let (timeout_send, timeout_receive) = oneshot::channel(); + // Node handled Timeout events and responded with NIL vote. + context + .expect_broadcast() + .times(1) + .withf(move |msg: &Vote| msg == &prevote(None, 1, 1, *VALIDATOR_ID)) + .return_once(move |_| { + timeout_send.send(()).unwrap(); + Ok(()) + }); + context.expect_broadcast().returning(move |_| Ok(())); + + let mut manager = MultiHeightManager::new(*VALIDATOR_ID, TIMEOUTS.clone()); + let manager_handle = tokio::spawn(async move { + let decision = manager + .run_height( + &mut context, + BlockNumber(1), + false, + SYNC_RETRY_INTERVAL, + &mut subscriber_channels.into(), + &mut proposal_receiver_receiver, + ) + .await + .unwrap(); + assert_decision(decision, Felt::ONE); + }); + + // Wait for the timeout to be triggered. + timeout_receive.await.unwrap(); + // Show that after the timeout is triggered we can still precommit in favor of the block and + // reach a decision. + send_proposal( + &mut proposal_receiver_sender, + vec![TestProposalPart::Init(proposal_init(1, 1, *PROPOSER_ID))], + ) + .await; + send(&mut sender, prevote(Some(Felt::ONE), 1, 1, *PROPOSER_ID)).await; + send(&mut sender, prevote(Some(Felt::ONE), 1, 1, *VALIDATOR_ID_2)).await; + send(&mut sender, prevote(Some(Felt::ONE), 1, 1, *VALIDATOR_ID_3)).await; + send(&mut sender, precommit(Some(Felt::ONE), 1, 1, *VALIDATOR_ID_2)).await; + send(&mut sender, precommit(Some(Felt::ONE), 1, 1, *VALIDATOR_ID_3)).await; + + manager_handle.await.unwrap(); +} + +#[tokio::test] +async fn timely_message_handling() { + // TODO(matan): Make run_height more generic so don't need mock network? + // Check that, even when sync is immediately ready, consensus still handles queued messages. + let mut context = MockTestContext::new(); + context.expect_try_sync().returning(|_| true); + + // Send messages + let (mut proposal_receiver_sender, mut proposal_receiver_receiver) = mpsc::channel(0); + let (mut content_sender, content_receiver) = mpsc::channel(0); + content_sender.try_send(TestProposalPart::Init(proposal_init(1, 0, *PROPOSER_ID))).unwrap(); + proposal_receiver_sender.try_send(content_receiver).unwrap(); + + // Fill up the sender. + let TestSubscriberChannels { mock_network, subscriber_channels } = + mock_register_broadcast_topic().unwrap(); + let mut subscriber_channels = subscriber_channels.into(); + let mut vote_sender = mock_network.broadcasted_messages_sender; + let metadata = BroadcastedMessageMetadata::get_test_instance(&mut get_rng()); + let vote = prevote(Some(Felt::TWO), 1, 0, *PROPOSER_ID); + // Fill up the buffer. + while vote_sender.send((vote.clone(), metadata.clone())).now_or_never().is_some() {} + + let mut manager = MultiHeightManager::new(*VALIDATOR_ID, TIMEOUTS.clone()); + let res = manager + .run_height( + &mut context, + BlockNumber(1), + false, + SYNC_RETRY_INTERVAL, + &mut subscriber_channels, + &mut proposal_receiver_receiver, + ) + .await; + assert_eq!(res, Ok(RunHeightRes::Sync)); + + // Try sending another proposal, to check that, even though sync was known at the beginning of + // the height and so consensus was not actually run, the inbound channels are cleared. + proposal_receiver_sender.try_send(mpsc::channel(1).1).unwrap(); + assert!(vote_sender.send((vote.clone(), metadata.clone())).now_or_never().is_some()); +} diff --git a/crates/starknet_consensus/src/metrics.rs b/crates/starknet_consensus/src/metrics.rs new file mode 100644 index 00000000000..2ce6a249b6f --- /dev/null +++ b/crates/starknet_consensus/src/metrics.rs @@ -0,0 +1,54 @@ +use starknet_sequencer_metrics::metrics::{LabeledMetricCounter, MetricCounter, MetricGauge}; +use starknet_sequencer_metrics::{define_metrics, generate_permutation_labels}; +use strum::{EnumVariantNames, VariantNames}; +use strum_macros::{EnumIter, IntoStaticStr}; + +define_metrics!( + Consensus => { + MetricGauge { CONSENSUS_BLOCK_NUMBER, "consensus_block_number", "The block number consensus is working to decide" }, + MetricGauge { CONSENSUS_ROUND, "consensus_round", "The round of the state machine"}, + MetricGauge { CONSENSUS_MAX_CACHED_BLOCK_NUMBER, "consensus_max_cached_block_number", "How many blocks after current are cached"}, + MetricGauge { CONSENSUS_CACHED_VOTES, "consensus_cached_votes", "How many votes are cached when starting to work on a new block number" }, + MetricCounter { CONSENSUS_DECISIONS_REACHED_BY_CONSENSUS, "consensus_decisions_reached_by_consensus", "The total number of decisions reached by way of consensus", init=0}, + MetricCounter { CONSENSUS_DECISIONS_REACHED_BY_SYNC, "consensus_decisions_reached_by_sync", "The total number of decisions reached by way of sync", init=0}, + MetricCounter { CONSENSUS_PROPOSALS_RECEIVED, "consensus_proposals_received", "The total number of proposals received", init=0}, + MetricCounter { CONSENSUS_PROPOSALS_VALID_INIT, "consensus_proposals_valid_init", "The total number of proposals received with a valid init", init=0}, + MetricCounter { CONSENSUS_PROPOSALS_VALIDATED, "consensus_proposals_validated", "The total number of complete, valid proposals received", init=0}, + MetricCounter { CONSENSUS_PROPOSALS_INVALID, "consensus_proposals_invalid", "The total number of proposals that failed validation", init=0}, + MetricCounter { CONSENSUS_BUILD_PROPOSAL_TOTAL, "consensus_build_proposal_total", "The total number of proposals built", init=0}, + MetricCounter { CONSENSUS_BUILD_PROPOSAL_FAILED, "consensus_build_proposal_failed", "The number of proposals that failed to be built", init=0}, + MetricCounter { CONSENSUS_REPROPOSALS, "consensus_reproposals", "The number of reproposals sent", init=0}, + LabeledMetricCounter { CONSENSUS_TIMEOUTS, "consensus_timeouts", "The number of timeouts for the current block number", init=0, labels = CONSENSUS_TIMEOUT_LABELS }, + }, +); + +pub const LABEL_NAME_TIMEOUT_REASON: &str = "timeout_reason"; + +#[derive(IntoStaticStr, EnumIter, EnumVariantNames)] +#[strum(serialize_all = "snake_case")] +pub(crate) enum TimeoutReason { + Propose, + Prevote, + Precommit, +} + +generate_permutation_labels! { + CONSENSUS_TIMEOUT_LABELS, + (LABEL_NAME_TIMEOUT_REASON, TimeoutReason), +} + +pub(crate) fn register_metrics() { + CONSENSUS_BLOCK_NUMBER.register(); + CONSENSUS_ROUND.register(); + CONSENSUS_MAX_CACHED_BLOCK_NUMBER.register(); + CONSENSUS_CACHED_VOTES.register(); + CONSENSUS_DECISIONS_REACHED_BY_CONSENSUS.register(); + CONSENSUS_DECISIONS_REACHED_BY_SYNC.register(); + CONSENSUS_PROPOSALS_RECEIVED.register(); + CONSENSUS_PROPOSALS_VALID_INIT.register(); + CONSENSUS_PROPOSALS_VALIDATED.register(); + CONSENSUS_PROPOSALS_INVALID.register(); + CONSENSUS_BUILD_PROPOSAL_TOTAL.register(); + CONSENSUS_BUILD_PROPOSAL_FAILED.register(); + CONSENSUS_REPROPOSALS.register(); +} diff --git a/crates/sequencing/papyrus_consensus/src/simulation_network_receiver.rs b/crates/starknet_consensus/src/simulation_network_receiver.rs similarity index 63% rename from crates/sequencing/papyrus_consensus/src/simulation_network_receiver.rs rename to crates/starknet_consensus/src/simulation_network_receiver.rs index 876032bf970..9cecc1b4485 100644 --- a/crates/sequencing/papyrus_consensus/src/simulation_network_receiver.rs +++ b/crates/starknet_consensus/src/simulation_network_receiver.rs @@ -11,30 +11,23 @@ use futures::{Stream, StreamExt}; use lru::LruCache; use papyrus_network::network_manager::BroadcastTopicServer; use papyrus_network_types::network_types::BroadcastedMessageMetadata; -use papyrus_protobuf::consensus::ConsensusMessage; +use papyrus_protobuf::consensus::Vote; use papyrus_protobuf::converters::ProtobufConversionError; -use starknet_api::block::BlockHash; use starknet_api::core::{ContractAddress, PatriciaKey}; use tracing::{debug, instrument}; -/// Receiver used to help run simulations of consensus. It has 2 goals in mind: -/// 1. Simulate network failures. -/// 2. Make tests repeatable - This is challenging because simulations involve a noisy environment; -/// so the actual network issues experienced may differ between 2 test runs. -/// - We expect simulations to use fairly reliable networks. That means messages arriving in -/// different order between runs will make up most of the actual noise between runs, as -/// opposed to actual drops or corruption. -/// - Tendermint is, to a large extent, unaffected by minor network reorderings. For instance it -/// doesn't matter if prevotes arrive before or after the Proposal they are for. -/// - This struct is therefore also designed not to be overly sensistive to message order. If -/// message A was dropped by this struct in one run, it should be dropped in the rerun. This -/// is as opposed to using a stateful RNG where the random number is a function of all the -/// previous calls to the RNG. +/// Receiver which can simulate network issues in a repeatable manner. Simulates drops and network +/// corruption. The errors are meant to be repeatable regardless of the order of messages received. +/// +/// Being indifferent to the order of messages on the network means that we don't have a state which +/// changes across all messages. If we were truly stateless though we would treat resends of +/// messages all the same, meaning that a dropped message would always be dropped. To avoid this we +/// have the cache, which allows us to treat resends of a specific message differently. pub struct NetworkReceiver { - pub broadcasted_messages_receiver: BroadcastTopicServer, + pub broadcasted_messages_receiver: BroadcastTopicServer, // Cache is used so that repeat sends of a message can be processed differently. For example, // if a message is dropped resending it should result in a new decision. - pub cache: LruCache, + pub cache: LruCache, pub seed: u64, // Probability of dropping a message [0, 1]. pub drop_probability: f64, @@ -43,8 +36,16 @@ pub struct NetworkReceiver { } impl NetworkReceiver { + /// Creates a new NetworkReceiver. + /// + /// Inputs: + /// - `broadcasted_messages_receiver`: The receiver to listen to. + /// - `cache_size`: Determines the size of the cache. A small cache risks acting the same across + /// resends of a given message. /// - `seed`: Seed for the random number generator. + /// - `drop_probability`: Probability of dropping a message [0, 1]. + /// - `invalid_probability`: Probability of making a message invalid [0, 1]. pub fn new( - broadcasted_messages_receiver: BroadcastTopicServer, + broadcasted_messages_receiver: BroadcastTopicServer, cache_size: usize, seed: u64, drop_probability: f64, @@ -61,13 +62,13 @@ impl NetworkReceiver { } } - /// Determine how to handle a message. If None then the message is silently droppeds. If some, + /// Determine how to handle a message. If None then the message is silently dropped. If some, /// the returned message is what is sent to the consensus crate. /// /// Applies `drop_probability` followed by `invalid_probability`. So the probability of an /// invalid message is `(1- drop_probability) * invalid_probability`. #[instrument(skip(self), level = "debug")] - pub fn filter_msg(&mut self, msg: ConsensusMessage) -> Option { + pub fn filter_msg(&mut self, msg: Vote) -> Option { let msg_hash = self.calculate_msg_hash(&msg); if self.should_drop_msg(msg_hash) { @@ -78,7 +79,7 @@ impl NetworkReceiver { Some(self.maybe_invalidate_msg(msg, msg_hash)) } - fn calculate_msg_hash(&mut self, msg: &ConsensusMessage) -> u64 { + fn calculate_msg_hash(&mut self, msg: &Vote) -> u64 { let count = if let Some(count) = self.cache.get_mut(msg) { *count += 1; *count @@ -100,31 +101,20 @@ impl NetworkReceiver { prob <= self.drop_probability } - fn maybe_invalidate_msg( - &mut self, - mut msg: ConsensusMessage, - msg_hash: u64, - ) -> ConsensusMessage { + fn maybe_invalidate_msg(&mut self, mut msg: Vote, msg_hash: u64) -> Vote { #[allow(clippy::as_conversions)] if (msg_hash as f64) / (u64::MAX as f64) > self.invalid_probability { return msg; } debug!("Invalidating message"); // TODO(matan): Allow for invalid votes based on signature. - match msg { - ConsensusMessage::Proposal(ref mut proposal) => { - proposal.block_hash = BlockHash(proposal.block_hash.0 + 1); - } - ConsensusMessage::Vote(ref mut vote) => { - vote.voter = ContractAddress(PatriciaKey::from(msg_hash)); - } - } + msg.voter = ContractAddress(PatriciaKey::from(msg_hash)); msg } } impl Stream for NetworkReceiver { - type Item = (Result, BroadcastedMessageMetadata); + type Item = (Result, BroadcastedMessageMetadata); fn poll_next( mut self: std::pin::Pin<&mut Self>, diff --git a/crates/sequencing/papyrus_consensus/src/simulation_network_receiver_test.rs b/crates/starknet_consensus/src/simulation_network_receiver_test.rs similarity index 67% rename from crates/sequencing/papyrus_consensus/src/simulation_network_receiver_test.rs rename to crates/starknet_consensus/src/simulation_network_receiver_test.rs index ff2b49f4670..8334bc88b59 100644 --- a/crates/sequencing/papyrus_consensus/src/simulation_network_receiver_test.rs +++ b/crates/starknet_consensus/src/simulation_network_receiver_test.rs @@ -4,7 +4,7 @@ use papyrus_network::network_manager::test_utils::{ TestSubscriberChannels, }; use papyrus_network_types::network_types::BroadcastedMessageMetadata; -use papyrus_protobuf::consensus::ConsensusMessage; +use papyrus_protobuf::consensus::Vote; use papyrus_test_utils::{get_rng, GetTestInstance}; use test_case::test_case; @@ -15,12 +15,10 @@ const SEED: u64 = 123; const DROP_PROBABILITY: f64 = 0.5; const INVALID_PROBABILITY: f64 = 0.5; -#[test_case(true, true; "distinct_vote")] -#[test_case(false, true; "repeat_vote")] -#[test_case(true, false; "distinct_proposal")] -#[test_case(false, false; "repeat_proposal")] +#[test_case(true; "distinct_vote")] +#[test_case(false; "repeat_vote")] #[tokio::test] -async fn test_invalid(distinct_messages: bool, is_vote: bool) { +async fn test_invalid(distinct_messages: bool) { let TestSubscriberChannels { subscriber_channels, mut mock_network } = mock_register_broadcast_topic().unwrap(); let mut receiver = NetworkReceiver::new( @@ -33,7 +31,7 @@ async fn test_invalid(distinct_messages: bool, is_vote: bool) { let mut invalid_messages = 0; for height in 0..1000 { - let msg = create_consensus_msg(if distinct_messages { height } else { 0 }, is_vote); + let msg = Vote { height: if distinct_messages { height } else { 0 }, ..Default::default() }; let broadcasted_message_metadata = BroadcastedMessageMetadata::get_test_instance(&mut get_rng()); mock_network @@ -48,12 +46,10 @@ async fn test_invalid(distinct_messages: bool, is_vote: bool) { assert!((400..=600).contains(&invalid_messages), "num_invalid={invalid_messages}"); } -#[test_case(true, true; "distinct_vote")] -#[test_case(false, true; "repeat_vote")] -#[test_case(true, false; "distinct_proposal")] -#[test_case(false, false; "repeat_proposal")] +#[test_case(true; "distinct_vote")] +#[test_case(false; "repeat_vote")] #[tokio::test] -async fn test_drops(distinct_messages: bool, is_vote: bool) { +async fn test_drops(distinct_messages: bool) { let TestSubscriberChannels { subscriber_channels, mut mock_network } = mock_register_broadcast_topic().unwrap(); let mut receiver = NetworkReceiver::new( @@ -66,7 +62,7 @@ async fn test_drops(distinct_messages: bool, is_vote: bool) { let mut num_received = 0; for height in 0..1000 { - let msg = create_consensus_msg(if distinct_messages { height } else { 0 }, is_vote); + let msg = Vote { height: if distinct_messages { height } else { 0 }, ..Default::default() }; let broadcasted_message_metadata = BroadcastedMessageMetadata::get_test_instance(&mut get_rng()); mock_network @@ -82,14 +78,3 @@ async fn test_drops(distinct_messages: bool, is_vote: bool) { } assert!((400..=600).contains(&num_received), "num_received={num_received}"); } - -fn create_consensus_msg(height: u64, is_vote: bool) -> ConsensusMessage { - if is_vote { - ConsensusMessage::Vote(papyrus_protobuf::consensus::Vote { height, ..Default::default() }) - } else { - ConsensusMessage::Proposal(papyrus_protobuf::consensus::Proposal { - height, - ..Default::default() - }) - } -} diff --git a/crates/sequencing/papyrus_consensus/src/single_height_consensus.rs b/crates/starknet_consensus/src/single_height_consensus.rs similarity index 58% rename from crates/sequencing/papyrus_consensus/src/single_height_consensus.rs rename to crates/starknet_consensus/src/single_height_consensus.rs index f2ee23c7d34..ea0e0dda019 100644 --- a/crates/sequencing/papyrus_consensus/src/single_height_consensus.rs +++ b/crates/starknet_consensus/src/single_height_consensus.rs @@ -1,3 +1,11 @@ +//! Run a single height of consensus. +//! +//! [`SingleHeightConsensus`] (SHC) - run consensus for a single height. +//! +//! [`ShcTask`] - a task which should be run without blocking consensus. +//! +//! [`ShcEvent`] - an event, generated from an `ShcTask` which should be handled by the SHC. + #[cfg(test)] #[path = "single_height_consensus_test.rs"] mod single_height_consensus_test; @@ -9,21 +17,34 @@ use std::time::Duration; #[cfg(test)] use enum_as_inner::EnumAsInner; use futures::channel::{mpsc, oneshot}; -use papyrus_protobuf::consensus::{ConsensusMessage, ProposalInit, Vote, VoteType}; +use papyrus_protobuf::consensus::{ProposalFin, ProposalInit, Vote, VoteType}; use starknet_api::block::BlockNumber; use tracing::{debug, info, instrument, trace, warn}; use crate::config::TimeoutsConfig; +use crate::metrics::{ + TimeoutReason, + CONSENSUS_BUILD_PROPOSAL_FAILED, + CONSENSUS_BUILD_PROPOSAL_TOTAL, + CONSENSUS_PROPOSALS_INVALID, + CONSENSUS_PROPOSALS_VALIDATED, + CONSENSUS_PROPOSALS_VALID_INIT, + CONSENSUS_REPROPOSALS, + CONSENSUS_TIMEOUTS, + LABEL_NAME_TIMEOUT_REASON, +}; use crate::state_machine::{StateMachine, StateMachineEvent}; use crate::types::{ ConsensusContext, ConsensusError, Decision, - ProposalContentId, + ProposalCommitment, Round, ValidatorId, }; +/// The SHC can either update the manager of a decision or return tasks that should be run without +/// blocking further calls to itself. #[derive(Debug, PartialEq)] #[cfg_attr(test, derive(EnumAsInner))] pub enum ShcReturn { @@ -31,6 +52,7 @@ pub enum ShcReturn { Decision(Decision), } +/// Events produced from tasks for the SHC to handle. #[derive(Debug, Clone)] pub enum ShcEvent { TimeoutPropose(StateMachineEvent), @@ -39,10 +61,11 @@ pub enum ShcEvent { Prevote(StateMachineEvent), Precommit(StateMachineEvent), BuildProposal(StateMachineEvent), - // TODO: Replace ProposalContentId with the unvalidated signature from the proposer. - ValidateProposal(StateMachineEvent, Option), + // TODO(Matan): Replace ProposalCommitment with the unvalidated signature from the proposer. + ValidateProposal(StateMachineEvent, Option), } +/// A task which should be run without blocking calls to SHC. #[derive(Debug)] #[cfg_attr(test, derive(EnumAsInner))] pub enum ShcTask { @@ -59,18 +82,14 @@ pub enum ShcTask { /// which can be sent to the SM. /// * During this process, the SM is frozen; it will accept and buffer other events, only /// processing them once it receives the built proposal. - BuildProposal(Round, oneshot::Receiver), + BuildProposal(Round, oneshot::Receiver), /// Validating a proposal is handled in 3 stages: /// 1. The SHC validates `ProposalInit`, then starts block validation within the context. /// 2. SHC returns, allowing the context to validate the content while the Manager await the /// result without blocking consensus. /// 3. Once validation is complete, the manager returns the built proposal to the SHC as an /// event, which can be sent to the SM. - ValidateProposal( - ProposalInit, - oneshot::Receiver, // Block built from the content. - oneshot::Receiver, // Fin sent by the proposer. - ), + ValidateProposal(ProposalInit, oneshot::Receiver<(ProposalCommitment, ProposalFin)>), } impl PartialEq for ShcTask { @@ -82,9 +101,7 @@ impl PartialEq for ShcTask { | (ShcTask::Prevote(d1, e1), ShcTask::Prevote(d2, e2)) | (ShcTask::Precommit(d1, e1), ShcTask::Precommit(d2, e2)) => d1 == d2 && e1 == e2, (ShcTask::BuildProposal(r1, _), ShcTask::BuildProposal(r2, _)) => r1 == r2, - (ShcTask::ValidateProposal(pi1, _, _), ShcTask::ValidateProposal(pi2, _, _)) => { - pi1 == pi2 - } + (ShcTask::ValidateProposal(pi1, _), ShcTask::ValidateProposal(pi2, _)) => pi1 == pi2, _ => false, } } @@ -92,6 +109,7 @@ impl PartialEq for ShcTask { impl ShcTask { pub async fn run(self) -> ShcEvent { + trace!("Running task: {:?}", self); match self { ShcTask::TimeoutPropose(duration, event) => { tokio::time::sleep(duration).await; @@ -114,45 +132,52 @@ impl ShcTask { ShcEvent::Precommit(event) } ShcTask::BuildProposal(round, receiver) => { - println!("Building proposal for round {}", round); - let proposal_id = receiver.await.expect("Block building failed."); - ShcEvent::BuildProposal(StateMachineEvent::GetProposal(Some(proposal_id), round)) + let proposal_id = receiver.await.ok(); + ShcEvent::BuildProposal(StateMachineEvent::GetProposal(proposal_id, round)) } - ShcTask::ValidateProposal( - init, - id_built_from_content_receiver, - fin_from_proposer_receiver, - ) => { - let proposal_id = match id_built_from_content_receiver.await { - Ok(proposal_id) => Some(proposal_id), + ShcTask::ValidateProposal(init, block_receiver) => { + // Handle the result of the block validation: + // The output is a tuple with the proposal id, calculated and from network. + // - If successful, set it as (Some, Some). + // - If there was an error (e.g., invalid proposal, no proposal received from the + // peer, or the process was interrupted), set it to (None, None). + // TODO(Asmaa): Consider if we want to differentiate between an interrupt and other + // failures. + let (built_content_id, received_proposal_id) = match block_receiver.await { + Ok((built_content_id, received_proposal_id)) => { + (Some(built_content_id), Some(received_proposal_id)) + } // Proposal never received from peer. - Err(_) => None, - }; - let fin = match fin_from_proposer_receiver.await { - Ok(fin) => Some(fin), - // ProposalFin never received from peer. - Err(_) => None, + Err(_) => (None, None), }; ShcEvent::ValidateProposal( - StateMachineEvent::Proposal(proposal_id, init.round, init.valid_round), - fin, + StateMachineEvent::Proposal(built_content_id, init.round, init.valid_round), + received_proposal_id, ) } } } } -/// Struct which represents a single height of consensus. Each height is expected to be begun with a -/// call to `start`, which is relevant if we are the proposer for this height's first round. -/// SingleHeightConsensus receives messages directly as parameters to function calls. It can send -/// out messages "directly" to the network, and returning a decision to the caller. +/// Represents a single height of consensus. It is responsible for mapping between the idealized +/// view of consensus represented in the StateMachine and the real world implementation. +/// +/// Example: +/// - Timeouts: the SM returns an event timeout, but SHC then maps that to a task which can be run +/// by the Manager. The manager though unaware of the specific task as it has minimal consensus +/// logic. +/// +/// Each height is begun with a call to `start`, with no further calls to it. +/// +/// SHC is not a top level task, it is called directly and returns values (doesn't directly run sub +/// tasks). SHC does have side effects, such as sending messages to the network via the context. pub(crate) struct SingleHeightConsensus { height: BlockNumber, validators: Vec, id: ValidatorId, timeouts: TimeoutsConfig, state_machine: StateMachine, - proposals: HashMap>, + proposals: HashMap>, prevotes: HashMap<(Round, ValidatorId), Vote>, precommits: HashMap<(Round, ValidatorId), Vote>, last_prevote: Option, @@ -162,6 +187,7 @@ pub(crate) struct SingleHeightConsensus { impl SingleHeightConsensus { pub(crate) fn new( height: BlockNumber, + is_observer: bool, id: ValidatorId, validators: Vec, timeouts: TimeoutsConfig, @@ -169,7 +195,7 @@ impl SingleHeightConsensus { // TODO(matan): Use actual weights, not just `len`. let n_validators = u32::try_from(validators.len()).expect("Should have way less than u32::MAX validators"); - let state_machine = StateMachine::new(id, n_validators); + let state_machine = StateMachine::new(id, n_validators, is_observer); Self { height, validators, @@ -184,107 +210,80 @@ impl SingleHeightConsensus { } } - #[instrument(skip_all, fields(height=self.height.0), level = "debug")] + #[instrument(skip_all)] pub(crate) async fn start( &mut self, context: &mut ContextT, ) -> Result { - info!("Starting consensus with validators {:?}", self.validators); + context.set_height_and_round(self.height, self.state_machine.round()).await; let leader_fn = |round: Round| -> ValidatorId { context.proposer(self.height, round) }; let events = self.state_machine.start(&leader_fn); - self.handle_state_machine_events(context, events).await + let ret = self.handle_state_machine_events(context, events).await; + context.set_height_and_round(self.height, self.state_machine.round()).await; + ret } /// Process the proposal init and initiate block validation. See [`ShcTask::ValidateProposal`] /// for more details on the full proposal flow. - #[instrument( - skip_all, - fields(height = %self.height), - level = "debug", - )] + #[instrument(skip_all)] pub(crate) async fn handle_proposal( &mut self, context: &mut ContextT, init: ProposalInit, - p2p_messages_receiver: mpsc::Receiver, - fin_receiver: oneshot::Receiver, + p2p_messages_receiver: mpsc::Receiver, ) -> Result { - debug!( - "Received proposal: height={}, round={}, proposer={:?}", - init.height.0, init.round, init.proposer - ); + debug!("Received {init:?}"); let proposer_id = context.proposer(self.height, init.round); if init.height != self.height { - let msg = format!("invalid height: expected {:?}, got {:?}", self.height, init.height); - return Err(ConsensusError::InvalidProposal(proposer_id, self.height, msg)); + warn!("Invalid proposal height: expected {:?}, got {:?}", self.height, init.height); + return Ok(ShcReturn::Tasks(Vec::new())); } if init.proposer != proposer_id { - let msg = - format!("invalid proposer: expected {:?}, got {:?}", proposer_id, init.proposer); - return Err(ConsensusError::InvalidProposal(proposer_id, self.height, msg)); + warn!("Invalid proposer: expected {:?}, got {:?}", proposer_id, init.proposer); + return Ok(ShcReturn::Tasks(Vec::new())); } let Entry::Vacant(proposal_entry) = self.proposals.entry(init.round) else { warn!("Round {} already has a proposal, ignoring", init.round); return Ok(ShcReturn::Tasks(Vec::new())); }; + let timeout = self.timeouts.proposal_timeout; + info!( + "Accepting {init:?}. node_round: {}, timeout: {timeout:?}", + self.state_machine.round() + ); + CONSENSUS_PROPOSALS_VALID_INIT.increment(1); + // Since validating the proposal is non-blocking, we want to avoid validating the same round // twice in parallel. This could be caused by a network repeat or a malicious spam attack. proposal_entry.insert(None); - let block_receiver = context - .validate_proposal(self.height, self.timeouts.proposal_timeout, p2p_messages_receiver) - .await; - Ok(ShcReturn::Tasks(vec![ShcTask::ValidateProposal(init, block_receiver, fin_receiver)])) - } - - async fn process_inbound_proposal( - &mut self, - context: &mut ContextT, - sm_proposal: StateMachineEvent, - ) -> Result { - let leader_fn = |round: Round| -> ValidatorId { context.proposer(self.height, round) }; - let sm_events = self.state_machine.handle_event(sm_proposal, &leader_fn); - self.handle_state_machine_events(context, sm_events).await + let block_receiver = context.validate_proposal(init, timeout, p2p_messages_receiver).await; + context.set_height_and_round(self.height, self.state_machine.round()).await; + Ok(ShcReturn::Tasks(vec![ShcTask::ValidateProposal(init, block_receiver)])) } - /// Handle messages from peer nodes. #[instrument(skip_all)] - pub(crate) async fn handle_message( - &mut self, - context: &mut ContextT, - message: ConsensusMessage, - ) -> Result { - debug!("Received message: {:?}", message); - match message { - ConsensusMessage::Proposal(_) => { - unimplemented!("Proposals should use `handle_proposal` due to fake streaming") - } - ConsensusMessage::Vote(vote) => self.handle_vote(context, vote).await, - } - } - pub async fn handle_event( &mut self, context: &mut ContextT, event: ShcEvent, ) -> Result { debug!("Received ShcEvent: {:?}", event); - match event { + let ret = match event { ShcEvent::TimeoutPropose(event) | ShcEvent::TimeoutPrevote(event) - | ShcEvent::TimeoutPrecommit(event) => { - let leader_fn = - |round: Round| -> ValidatorId { context.proposer(self.height, round) }; - let sm_events = self.state_machine.handle_event(event, &leader_fn); - self.handle_state_machine_events(context, sm_events).await - } + | ShcEvent::TimeoutPrecommit(event) => self.handle_timeout(context, event).await, ShcEvent::Prevote(StateMachineEvent::Prevote(proposal_id, round)) => { let Some(last_vote) = &self.last_prevote else { - return Err(ConsensusError::InvalidEvent("No prevote to send".to_string())); + return Err(ConsensusError::InternalInconsistency( + "No prevote to send".to_string(), + )); }; if last_vote.round > round { + // Only replay the newest prevote. return Ok(ShcReturn::Tasks(Vec::new())); } - context.broadcast(ConsensusMessage::Vote(last_vote.clone())).await?; + debug!("Rebroadcasting {last_vote:?}"); + context.broadcast(last_vote.clone()).await?; Ok(ShcReturn::Tasks(vec![ShcTask::Prevote( self.timeouts.prevote_timeout, StateMachineEvent::Prevote(proposal_id, round), @@ -292,48 +291,70 @@ impl SingleHeightConsensus { } ShcEvent::Precommit(StateMachineEvent::Precommit(proposal_id, round)) => { let Some(last_vote) = &self.last_precommit else { - return Err(ConsensusError::InvalidEvent("No precommit to send".to_string())); + return Err(ConsensusError::InternalInconsistency( + "No precommit to send".to_string(), + )); }; if last_vote.round > round { + // Only replay the newest precommit. return Ok(ShcReturn::Tasks(Vec::new())); } - context.broadcast(ConsensusMessage::Vote(last_vote.clone())).await?; + debug!("Rebroadcasting {last_vote:?}"); + context.broadcast(last_vote.clone()).await?; Ok(ShcReturn::Tasks(vec![ShcTask::Precommit( self.timeouts.precommit_timeout, StateMachineEvent::Precommit(proposal_id, round), )])) } ShcEvent::ValidateProposal( - StateMachineEvent::Proposal(proposal_id, round, valid_round), - fin, + StateMachineEvent::Proposal(built_id, round, valid_round), + received_fin, ) => { + let leader_fn = + |round: Round| -> ValidatorId { context.proposer(self.height, round) }; + debug!( + proposer = %leader_fn(round), + %round, + ?valid_round, + ?built_id, + ?received_fin, + node_round = self.state_machine.round(), + "Validated proposal.", + ); // TODO(matan): Switch to signature validation. - let id = if proposal_id != fin { - warn!( - "proposal_id built from content receiver does not match fin: {:#064x?} != \ - {:#064x?}", - proposal_id, fin - ); - None - } else { - proposal_id - }; + if built_id != received_fin.as_ref().map(|fin| fin.proposal_commitment) { + CONSENSUS_PROPOSALS_INVALID.increment(1); + warn!("proposal_id built from content received does not match fin."); + return Ok(ShcReturn::Tasks(Vec::new())); + } + CONSENSUS_PROPOSALS_VALIDATED.increment(1); + // Retaining the entry for this round prevents us from receiving another proposal on - // this round. If the validations failed, which can be caused by a network issue, we - // may want to re-open ourselves to this round. The downside is that this may open - // us to a spam attack. - // TODO(Asmaa): consider revisiting this decision. Spam attacks may not be a problem - // given that serial proposing anyways forces us to use interrupts. - self.proposals.insert(round, id); - self.process_inbound_proposal( - context, - StateMachineEvent::Proposal(id, round, valid_round), - ) - .await + // this round. While this prevents spam attacks it also prevents re-receiving after + // a network issue. + let old = self.proposals.insert(round, built_id); + let old = old.unwrap_or_else(|| { + panic!("Proposal entry should exist from init. round: {round}") + }); + assert!(old.is_none(), "Proposal already exists for this round: {round}. {old:?}"); + let sm_events = self.state_machine.handle_event( + StateMachineEvent::Proposal(built_id, round, valid_round), + &leader_fn, + ); + self.handle_state_machine_events(context, sm_events).await } ShcEvent::BuildProposal(StateMachineEvent::GetProposal(proposal_id, round)) => { + if proposal_id.is_none() { + CONSENSUS_BUILD_PROPOSAL_FAILED.increment(1); + } let old = self.proposals.insert(round, proposal_id); - assert!(old.is_none(), "There should be no entry for this round."); + assert!(old.is_none(), "There should be no entry for round {round} when proposing"); + assert_eq!( + round, + self.state_machine.round(), + "State machine should not progress while awaiting proposal" + ); + debug!(%round, proposal_commitment = ?proposal_id, "Built proposal."); let leader_fn = |round: Round| -> ValidatorId { context.proposer(self.height, round) }; let sm_events = self @@ -342,17 +363,38 @@ impl SingleHeightConsensus { self.handle_state_machine_events(context, sm_events).await } _ => unimplemented!("Unexpected event: {:?}", event), - } + }; + context.set_height_and_round(self.height, self.state_machine.round()).await; + ret } + async fn handle_timeout( + &mut self, + context: &mut ContextT, + event: StateMachineEvent, + ) -> Result { + let timeout_reason = match event { + StateMachineEvent::TimeoutPropose(_) => TimeoutReason::Propose, + StateMachineEvent::TimeoutPrevote(_) => TimeoutReason::Prevote, + StateMachineEvent::TimeoutPrecommit(_) => TimeoutReason::Precommit, + _ => panic!("Expected a timeout event, got: {:?}", event), + }; + CONSENSUS_TIMEOUTS.increment(1, &[(LABEL_NAME_TIMEOUT_REASON, timeout_reason.into())]); + let leader_fn = |round: Round| -> ValidatorId { context.proposer(self.height, round) }; + let sm_events = self.state_machine.handle_event(event, &leader_fn); + self.handle_state_machine_events(context, sm_events).await + } + + /// Handle vote messages from peer nodes. #[instrument(skip_all)] - async fn handle_vote( + pub(crate) async fn handle_vote( &mut self, context: &mut ContextT, vote: Vote, ) -> Result { + debug!("Received {:?}", vote); if !self.validators.contains(&vote.voter) { - debug!("Ignoring vote from voter not in validators: vote={:?}", vote); + debug!("Ignoring vote from non validator: vote={:?}", vote); return Ok(ShcReturn::Tasks(Vec::new())); } @@ -372,24 +414,23 @@ impl SingleHeightConsensus { Entry::Occupied(entry) => { let old = entry.get(); if old.block_hash != vote.block_hash { - return Err(ConsensusError::Equivocation( - self.height, - ConsensusMessage::Vote(old.clone()), - ConsensusMessage::Vote(vote), - )); + warn!("Conflicting votes: old={:?}, new={:?}", old, vote); + return Ok(ShcReturn::Tasks(Vec::new())); } else { // Replay, ignore. return Ok(ShcReturn::Tasks(Vec::new())); } } } + info!("Accepting {:?}", vote); let leader_fn = |round: Round| -> ValidatorId { context.proposer(self.height, round) }; let sm_events = self.state_machine.handle_event(sm_vote, &leader_fn); - self.handle_state_machine_events(context, sm_events).await + let ret = self.handle_state_machine_events(context, sm_events).await; + context.set_height_and_round(self.height, self.state_machine.round()).await; + ret } // Handle events output by the state machine. - #[instrument(skip_all)] async fn handle_state_machine_events( &mut self, context: &mut ContextT, @@ -397,7 +438,7 @@ impl SingleHeightConsensus { ) -> Result { let mut ret_val = Vec::new(); while let Some(event) = events.pop_front() { - trace!("Handling event: {:?}", event); + trace!("Handling sm event: {:?}", event); match event { StateMachineEvent::GetProposal(proposal_id, round) => { ret_val.extend( @@ -449,63 +490,63 @@ impl SingleHeightConsensus { /// Initiate block building. See [`ShcTask::BuildProposal`] for more details on the full /// proposal flow. - #[instrument(skip(self, context), level = "debug")] async fn handle_state_machine_get_proposal( &mut self, context: &mut ContextT, - proposal_id: Option, + proposal_id: Option, round: Round, ) -> Vec { assert!( proposal_id.is_none(), - "ProposalContentId must be None since the state machine is requesting a \ - ProposalContentId" + "StateMachine is requesting a new proposal, but provided a content id." ); - debug!("Proposer"); - // TODO: Figure out how to handle failed proposal building. I believe this should be handled - // by applying timeoutPropose when we are the leader. + // TODO(Matan): Figure out how to handle failed proposal building. I believe this should be + // handled by applying timeoutPropose when we are the leader. let init = ProposalInit { height: self.height, round, proposer: self.id, valid_round: None }; + CONSENSUS_BUILD_PROPOSAL_TOTAL.increment(1); let fin_receiver = context.build_proposal(init, self.timeouts.proposal_timeout).await; vec![ShcTask::BuildProposal(round, fin_receiver)] } - #[instrument(skip(self, context), level = "debug")] async fn handle_state_machine_proposal( &mut self, context: &mut ContextT, - proposal_id: Option, + proposal_id: Option, round: Round, valid_round: Option, ) { - let proposal_id = proposal_id.expect("StateMachine should not propose a None proposal_id"); let Some(valid_round) = valid_round else { - // newly built so just streamed + // Newly built proposals are handled by the BuildProposal flow. return; }; + let proposal_id = proposal_id.expect("Reproposal must have a valid ID"); + let id = self .proposals .get(&valid_round) - .expect("proposals should have proposal for valid_round") - .expect("proposal should not be None"); - assert_eq!(id, proposal_id, "proposal should match the stored proposal"); + .unwrap_or_else(|| panic!("A proposal should exist for valid_round: {valid_round}")) + .unwrap_or_else(|| { + panic!("A valid proposal should exist for valid_round: {valid_round}") + }); + assert_eq!(id, proposal_id, "reproposal should match the stored proposal"); + let old = self.proposals.insert(round, Some(proposal_id)); + assert!(old.is_none(), "There should be no proposal for round {round}."); let init = ProposalInit { height: self.height, round, proposer: self.id, valid_round: Some(valid_round), }; + CONSENSUS_REPROPOSALS.increment(1); context.repropose(id, init).await; - let old = self.proposals.insert(round, Some(proposal_id)); - assert!(old.is_none(), "There should be no entry for this round."); } - #[instrument(skip_all)] async fn handle_state_machine_vote( &mut self, context: &mut ContextT, - proposal_id: Option, + proposal_id: Option, round: Round, vote_type: VoteType, ) -> Result, ConsensusError> { @@ -535,29 +576,54 @@ impl SingleHeightConsensus { voter: self.id, }; if let Some(old) = votes.insert((round, self.id), vote.clone()) { - // TODO(matan): Consider refactoring not to panic, rather log and return the error. - panic!("State machine should not send repeat votes: old={:?}, new={:?}", old, vote); + return Err(ConsensusError::InternalInconsistency(format!( + "State machine should not send repeat votes: old={:?}, new={:?}", + old, vote + ))); } - context.broadcast(ConsensusMessage::Vote(vote.clone())).await?; - if last_vote.as_ref().map_or(false, |last| round < last.round) { - return Ok(Vec::new()); - } - *last_vote = Some(vote); + *last_vote = match last_vote { + None => Some(vote.clone()), + Some(last_vote) if round > last_vote.round => Some(vote.clone()), + Some(_) => { + // According to the Tendermint paper, the state machine should only vote for its + // current round. It should monotonicly increase its round. It should only vote once + // per step. + return Err(ConsensusError::InternalInconsistency(format!( + "State machine must progress in time: last_vote: {:?} new_vote: {:?}", + last_vote, vote, + ))); + } + }; + + info!("Broadcasting {vote:?}"); + context.broadcast(vote).await?; Ok(vec![task]) } - #[instrument(skip_all)] async fn handle_state_machine_decision( &mut self, - proposal_id: ProposalContentId, + proposal_id: ProposalCommitment, round: Round, ) -> Result { + let invalid_decision = |msg: String| { + ConsensusError::InternalInconsistency(format!( + "Invalid decision: sm_proposal_id: {proposal_id}, round: {round}. {msg}", + )) + }; let block = self .proposals .remove(&round) - .expect("StateMachine arrived at an unknown decision") - .expect("StateMachine should not decide on a missing proposal"); - assert_eq!(block, proposal_id, "StateMachine block hash should match the stored block"); + .ok_or_else(|| invalid_decision("No proposal entry for this round".to_string()))? + .ok_or_else(|| { + invalid_decision( + "Proposal is invalid or validations haven't yet completed".to_string(), + ) + })?; + if block != proposal_id { + return Err(invalid_decision(format!( + "StateMachine block hash should match the stored block. Shc.block_id: {block}" + ))); + } let supporting_precommits: Vec = self .validators .iter() @@ -566,12 +632,17 @@ impl SingleHeightConsensus { if vote.block_hash == Some(proposal_id) { Some(vote.clone()) } else { None } }) .collect(); + let quorum_size = + usize::try_from(self.state_machine.quorum_size()).expect("u32 should fit in usize"); // TODO(matan): Check actual weights. - assert!( - supporting_precommits.len() - >= usize::try_from(self.state_machine.quorum_size()) - .expect("u32 should fit in usize") - ); + if quorum_size > supporting_precommits.len() { + let msg = format!( + "Not enough supporting votes. quorum_size: {quorum_size}, num_supporting_votes: \ + {}. supporting_votes: {supporting_precommits:?}", + supporting_precommits.len(), + ); + return Err(invalid_decision(msg)); + } Ok(ShcReturn::Decision(Decision { precommits: supporting_precommits, block })) } } diff --git a/crates/sequencing/papyrus_consensus/src/single_height_consensus_test.rs b/crates/starknet_consensus/src/single_height_consensus_test.rs similarity index 70% rename from crates/sequencing/papyrus_consensus/src/single_height_consensus_test.rs rename to crates/starknet_consensus/src/single_height_consensus_test.rs index deb0d937f8a..9d1a1838bba 100644 --- a/crates/sequencing/papyrus_consensus/src/single_height_consensus_test.rs +++ b/crates/starknet_consensus/src/single_height_consensus_test.rs @@ -1,39 +1,38 @@ use futures::channel::{mpsc, oneshot}; +use futures::SinkExt; use lazy_static::lazy_static; -use papyrus_protobuf::consensus::{ConsensusMessage, ProposalInit}; +use papyrus_protobuf::consensus::{ProposalFin, ProposalInit, Vote, DEFAULT_VALIDATOR_ID}; use starknet_api::block::{BlockHash, BlockNumber}; use starknet_types_core::felt::Felt; use test_case::test_case; -use tokio; use super::SingleHeightConsensus; use crate::config::TimeoutsConfig; use crate::single_height_consensus::{ShcEvent, ShcReturn, ShcTask}; use crate::state_machine::StateMachineEvent; -use crate::test_utils::{precommit, prevote, MockTestContext, TestBlock}; -use crate::types::{ConsensusError, ValidatorId}; +use crate::test_utils::{precommit, prevote, MockTestContext, TestBlock, TestProposalPart}; +use crate::types::ValidatorId; lazy_static! { - static ref PROPOSER_ID: ValidatorId = 0_u32.into(); - static ref VALIDATOR_ID_1: ValidatorId = 1_u32.into(); - static ref VALIDATOR_ID_2: ValidatorId = 2_u32.into(); - static ref VALIDATOR_ID_3: ValidatorId = 3_u32.into(); + static ref PROPOSER_ID: ValidatorId = DEFAULT_VALIDATOR_ID.into(); + static ref VALIDATOR_ID_1: ValidatorId = (DEFAULT_VALIDATOR_ID + 1).into(); + static ref VALIDATOR_ID_2: ValidatorId = (DEFAULT_VALIDATOR_ID + 2).into(); + static ref VALIDATOR_ID_3: ValidatorId = (DEFAULT_VALIDATOR_ID + 3).into(); static ref VALIDATORS: Vec = vec![*PROPOSER_ID, *VALIDATOR_ID_1, *VALIDATOR_ID_2, *VALIDATOR_ID_3]; static ref BLOCK: TestBlock = TestBlock { content: vec![1, 2, 3], id: BlockHash(Felt::ONE) }; - static ref PROPOSAL_INIT: ProposalInit = ProposalInit { - height: BlockNumber(0), - round: 0, - proposer: *PROPOSER_ID, - valid_round: None - }; + static ref PROPOSAL_INIT: ProposalInit = + ProposalInit { proposer: *PROPOSER_ID, ..Default::default() }; static ref TIMEOUTS: TimeoutsConfig = TimeoutsConfig::default(); static ref VALIDATE_PROPOSAL_EVENT: ShcEvent = ShcEvent::ValidateProposal( StateMachineEvent::Proposal(Some(BLOCK.id), PROPOSAL_INIT.round, PROPOSAL_INIT.valid_round,), - Some(BLOCK.id), + Some(ProposalFin { proposal_commitment: BLOCK.id }), ); + static ref PROPOSAL_FIN: ProposalFin = ProposalFin { proposal_commitment: BLOCK.id }; } +const CHANNEL_SIZE: usize = 1; + fn prevote_task(block_felt: Option, round: u32) -> ShcTask { ShcTask::Prevote( TIMEOUTS.prevote_timeout, @@ -64,17 +63,10 @@ async fn handle_proposal( context: &mut MockTestContext, ) -> ShcReturn { // Send the proposal from the peer. - let (fin_sender, fin_receiver) = oneshot::channel(); - fin_sender.send(BLOCK.id).unwrap(); - - shc.handle_proposal( - context, - PROPOSAL_INIT.clone(), - mpsc::channel(1).1, // content - ignored by SHC. - fin_receiver, - ) - .await - .unwrap() + let (mut content_sender, content_receiver) = mpsc::channel(CHANNEL_SIZE); + content_sender.send(TestProposalPart::Init(ProposalInit::default())).await.unwrap(); + + shc.handle_proposal(context, *PROPOSAL_INIT, content_receiver).await.unwrap() } #[tokio::test] @@ -83,6 +75,7 @@ async fn proposer() { let mut shc = SingleHeightConsensus::new( BlockNumber(0), + false, *PROPOSER_ID, VALIDATORS.to_vec(), TIMEOUTS.clone(), @@ -94,10 +87,11 @@ async fn proposer() { block_sender.send(BLOCK.id).unwrap(); block_receiver }); + context.expect_set_height_and_round().returning(move |_, _| ()); context .expect_broadcast() .times(1) - .withf(move |msg: &ConsensusMessage| msg == &prevote(Some(BLOCK.id.0), 0, 0, *PROPOSER_ID)) + .withf(move |msg: &Vote| msg == &prevote(Some(BLOCK.id.0), 0, 0, *PROPOSER_ID)) .returning(move |_| Ok(())); // Sends proposal and prevote. let shc_ret = shc.start(&mut context).await.unwrap(); @@ -111,20 +105,18 @@ async fn proposer() { Ok(ShcReturn::Tasks(vec![prevote_task(Some(BLOCK.id.0), 0)])) ); assert_eq!( - shc.handle_message(&mut context, prevote(Some(BLOCK.id.0), 0, 0, *VALIDATOR_ID_1)).await, + shc.handle_vote(&mut context, prevote(Some(BLOCK.id.0), 0, 0, *VALIDATOR_ID_1)).await, Ok(ShcReturn::Tasks(Vec::new())) ); // 3 of 4 Prevotes is enough to send a Precommit. context .expect_broadcast() .times(1) - .withf(move |msg: &ConsensusMessage| { - msg == &precommit(Some(BLOCK.id.0), 0, 0, *PROPOSER_ID) - }) + .withf(move |msg: &Vote| msg == &precommit(Some(BLOCK.id.0), 0, 0, *PROPOSER_ID)) .returning(move |_| Ok(())); // The Node got a Prevote quorum. assert_eq!( - shc.handle_message(&mut context, prevote(Some(BLOCK.id.0), 0, 0, *VALIDATOR_ID_2)).await, + shc.handle_vote(&mut context, prevote(Some(BLOCK.id.0), 0, 0, *VALIDATOR_ID_2)).await, Ok(ShcReturn::Tasks(vec![timeout_prevote_task(0), precommit_task(Some(BLOCK.id.0), 0),])) ); @@ -135,27 +127,22 @@ async fn proposer() { precommit(Some(BLOCK.id.0), 0, 0, *PROPOSER_ID), ]; assert_eq!( - shc.handle_message(&mut context, precommits[0].clone()).await, + shc.handle_vote(&mut context, precommits[0].clone()).await, Ok(ShcReturn::Tasks(Vec::new())) ); // The disagreeing vote counts towards the timeout, which uses a heterogeneous quorum, but not // the decision, which uses a homogenous quorum. assert_eq!( - shc.handle_message(&mut context, precommits[1].clone()).await, + shc.handle_vote(&mut context, precommits[1].clone()).await, Ok(ShcReturn::Tasks(vec![timeout_precommit_task(0),])) ); let ShcReturn::Decision(decision) = - shc.handle_message(&mut context, precommits[2].clone()).await.unwrap() + shc.handle_vote(&mut context, precommits[2].clone()).await.unwrap() else { panic!("Expected decision"); }; assert_eq!(decision.block, BLOCK.id); - assert!( - decision - .precommits - .into_iter() - .all(|item| precommits.contains(&ConsensusMessage::Vote(item))) - ); + assert!(decision.precommits.into_iter().all(|item| precommits.contains(&item))); } #[test_case(false; "single_proposal")] @@ -167,6 +154,7 @@ async fn validator(repeat_proposal: bool) { // Creation calls to `context.validators`. let mut shc = SingleHeightConsensus::new( BlockNumber(0), + false, *VALIDATOR_ID_1, VALIDATORS.to_vec(), TIMEOUTS.clone(), @@ -175,15 +163,14 @@ async fn validator(repeat_proposal: bool) { context.expect_proposer().returning(move |_, _| *PROPOSER_ID); context.expect_validate_proposal().times(1).returning(move |_, _, _| { let (block_sender, block_receiver) = oneshot::channel(); - block_sender.send(BLOCK.id).unwrap(); + block_sender.send((BLOCK.id, PROPOSAL_FIN.clone())).unwrap(); block_receiver }); + context.expect_set_height_and_round().returning(move |_, _| ()); context .expect_broadcast() .times(1) - .withf(move |msg: &ConsensusMessage| { - msg == &prevote(Some(BLOCK.id.0), 0, 0, *VALIDATOR_ID_1) - }) + .withf(move |msg: &Vote| msg == &prevote(Some(BLOCK.id.0), 0, 0, *VALIDATOR_ID_1)) .returning(move |_| Ok(())); let shc_ret = handle_proposal(&mut shc, &mut context).await; assert_eq!(shc_ret.as_tasks().unwrap()[0].as_validate_proposal().unwrap().0, &*PROPOSAL_INIT); @@ -197,20 +184,18 @@ async fn validator(repeat_proposal: bool) { assert_eq!(shc_ret, ShcReturn::Tasks(Vec::new())); } assert_eq!( - shc.handle_message(&mut context, prevote(Some(BLOCK.id.0), 0, 0, *PROPOSER_ID)).await, + shc.handle_vote(&mut context, prevote(Some(BLOCK.id.0), 0, 0, *PROPOSER_ID)).await, Ok(ShcReturn::Tasks(Vec::new())) ); // 3 of 4 Prevotes is enough to send a Precommit. context .expect_broadcast() .times(1) - .withf(move |msg: &ConsensusMessage| { - msg == &precommit(Some(BLOCK.id.0), 0, 0, *VALIDATOR_ID_1) - }) + .withf(move |msg: &Vote| msg == &precommit(Some(BLOCK.id.0), 0, 0, *VALIDATOR_ID_1)) .returning(move |_| Ok(())); // The Node got a Prevote quorum. assert_eq!( - shc.handle_message(&mut context, prevote(Some(BLOCK.id.0), 0, 0, *VALIDATOR_ID_2)).await, + shc.handle_vote(&mut context, prevote(Some(BLOCK.id.0), 0, 0, *VALIDATOR_ID_2)).await, Ok(ShcReturn::Tasks(vec![timeout_prevote_task(0), precommit_task(Some(BLOCK.id.0), 0)])) ); @@ -220,21 +205,16 @@ async fn validator(repeat_proposal: bool) { precommit(Some(BLOCK.id.0), 0, 0, *VALIDATOR_ID_1), ]; assert_eq!( - shc.handle_message(&mut context, precommits[0].clone()).await, + shc.handle_vote(&mut context, precommits[0].clone()).await, Ok(ShcReturn::Tasks(Vec::new())) ); let ShcReturn::Decision(decision) = - shc.handle_message(&mut context, precommits[1].clone()).await.unwrap() + shc.handle_vote(&mut context, precommits[1].clone()).await.unwrap() else { panic!("Expected decision"); }; assert_eq!(decision.block, BLOCK.id); - assert!( - decision - .precommits - .into_iter() - .all(|item| precommits.contains(&ConsensusMessage::Vote(item))) - ); + assert!(decision.precommits.into_iter().all(|item| precommits.contains(&item))); } #[test_case(true; "repeat")] @@ -245,6 +225,7 @@ async fn vote_twice(same_vote: bool) { let mut shc = SingleHeightConsensus::new( BlockNumber(0), + false, *VALIDATOR_ID_1, VALIDATORS.to_vec(), TIMEOUTS.clone(), @@ -253,13 +234,14 @@ async fn vote_twice(same_vote: bool) { context.expect_proposer().times(1).returning(move |_, _| *PROPOSER_ID); context.expect_validate_proposal().times(1).returning(move |_, _, _| { let (block_sender, block_receiver) = oneshot::channel(); - block_sender.send(BLOCK.id).unwrap(); + block_sender.send((BLOCK.id, PROPOSAL_FIN.clone())).unwrap(); block_receiver }); + context.expect_set_height_and_round().returning(move |_, _| ()); context .expect_broadcast() .times(1) // Shows the repeat vote is ignored. - .withf(move |msg: &ConsensusMessage| msg == &prevote(Some(BLOCK.id.0), 0, 0, *VALIDATOR_ID_1)) + .withf(move |msg: &Vote| msg == &prevote(Some(BLOCK.id.0), 0, 0, *VALIDATOR_ID_1)) .returning(move |_| Ok(())); let shc_ret = handle_proposal(&mut shc, &mut context).await; assert_eq!(shc_ret.as_tasks().unwrap()[0].as_validate_proposal().unwrap().0, &*PROPOSAL_INIT,); @@ -268,16 +250,15 @@ async fn vote_twice(same_vote: bool) { Ok(ShcReturn::Tasks(vec![prevote_task(Some(BLOCK.id.0), 0)])) ); - let res = shc.handle_message(&mut context, prevote(Some(BLOCK.id.0), 0, 0, *PROPOSER_ID)).await; + let res = shc.handle_vote(&mut context, prevote(Some(BLOCK.id.0), 0, 0, *PROPOSER_ID)).await; assert_eq!(res, Ok(ShcReturn::Tasks(Vec::new()))); context .expect_broadcast() .times(1) // Shows the repeat vote is ignored. - .withf(move |msg: &ConsensusMessage| msg == &precommit(Some(BLOCK.id.0), 0, 0, *VALIDATOR_ID_1)) + .withf(move |msg: &Vote| msg == &precommit(Some(BLOCK.id.0), 0, 0, *VALIDATOR_ID_1)) .returning(move |_| Ok(())); - let res = - shc.handle_message(&mut context, prevote(Some(BLOCK.id.0), 0, 0, *VALIDATOR_ID_2)).await; + let res = shc.handle_vote(&mut context, prevote(Some(BLOCK.id.0), 0, 0, *VALIDATOR_ID_2)).await; // The Node got a Prevote quorum. assert_eq!( res, @@ -285,20 +266,16 @@ async fn vote_twice(same_vote: bool) { ); let first_vote = precommit(Some(BLOCK.id.0), 0, 0, *PROPOSER_ID); - let res = shc.handle_message(&mut context, first_vote.clone()).await; + let res = shc.handle_vote(&mut context, first_vote.clone()).await; assert_eq!(res, Ok(ShcReturn::Tasks(Vec::new()))); let second_vote = if same_vote { first_vote.clone() } else { precommit(Some(Felt::TWO), 0, 0, *PROPOSER_ID) }; - let res = shc.handle_message(&mut context, second_vote.clone()).await; - if same_vote { - assert_eq!(res, Ok(ShcReturn::Tasks(Vec::new()))); - } else { - assert!(matches!(res, Err(ConsensusError::Equivocation(_, _, _)))); - } + let res = shc.handle_vote(&mut context, second_vote.clone()).await; + assert_eq!(res, Ok(ShcReturn::Tasks(Vec::new()))); let ShcReturn::Decision(decision) = shc - .handle_message(&mut context, precommit(Some(BLOCK.id.0), 0, 0, *VALIDATOR_ID_2)) + .handle_vote(&mut context, precommit(Some(BLOCK.id.0), 0, 0, *VALIDATOR_ID_2)) .await .unwrap() else { @@ -313,6 +290,7 @@ async fn rebroadcast_votes() { let mut shc = SingleHeightConsensus::new( BlockNumber(0), + false, *PROPOSER_ID, VALIDATORS.to_vec(), TIMEOUTS.clone(), @@ -324,10 +302,11 @@ async fn rebroadcast_votes() { block_sender.send(BLOCK.id).unwrap(); block_receiver }); + context.expect_set_height_and_round().returning(move |_, _| ()); context .expect_broadcast() .times(1) - .withf(move |msg: &ConsensusMessage| msg == &prevote(Some(BLOCK.id.0), 0, 0, *PROPOSER_ID)) + .withf(move |msg: &Vote| msg == &prevote(Some(BLOCK.id.0), 0, 0, *PROPOSER_ID)) .returning(move |_| Ok(())); // Sends proposal and prevote. let shc_ret = shc.start(&mut context).await.unwrap(); @@ -341,20 +320,20 @@ async fn rebroadcast_votes() { Ok(ShcReturn::Tasks(vec![prevote_task(Some(BLOCK.id.0), 0)])) ); assert_eq!( - shc.handle_message(&mut context, prevote(Some(BLOCK.id.0), 0, 0, *VALIDATOR_ID_1)).await, + shc.handle_vote(&mut context, prevote(Some(BLOCK.id.0), 0, 0, *VALIDATOR_ID_1)).await, Ok(ShcReturn::Tasks(Vec::new())) ); // 3 of 4 Prevotes is enough to send a Precommit. context .expect_broadcast() .times(2) // vote rebroadcast - .withf(move |msg: &ConsensusMessage| { + .withf(move |msg: &Vote| { msg == &precommit(Some(BLOCK.id.0), 0, 0, *PROPOSER_ID) }) .returning(move |_| Ok(())); // The Node got a Prevote quorum. assert_eq!( - shc.handle_message(&mut context, prevote(Some(BLOCK.id.0), 0, 0, *VALIDATOR_ID_2)).await, + shc.handle_vote(&mut context, prevote(Some(BLOCK.id.0), 0, 0, *VALIDATOR_ID_2)).await, Ok(ShcReturn::Tasks(vec![timeout_prevote_task(0), precommit_task(Some(BLOCK.id.0), 0),])) ); // Re-broadcast vote. @@ -374,6 +353,7 @@ async fn repropose() { let mut shc = SingleHeightConsensus::new( BlockNumber(0), + false, *PROPOSER_ID, VALIDATORS.to_vec(), TIMEOUTS.clone(), @@ -385,10 +365,11 @@ async fn repropose() { block_sender.send(BLOCK.id).unwrap(); block_receiver }); + context.expect_set_height_and_round().returning(move |_, _| ()); context .expect_broadcast() .times(1) - .withf(move |msg: &ConsensusMessage| msg == &prevote(Some(BLOCK.id.0), 0, 0, *PROPOSER_ID)) + .withf(move |msg: &Vote| msg == &prevote(Some(BLOCK.id.0), 0, 0, *PROPOSER_ID)) .returning(move |_| Ok(())); // Sends proposal and prevote. shc.start(&mut context).await.unwrap(); @@ -398,19 +379,15 @@ async fn repropose() { ) .await .unwrap(); - shc.handle_message(&mut context, prevote(Some(BLOCK.id.0), 0, 0, *VALIDATOR_ID_1)) - .await - .unwrap(); + shc.handle_vote(&mut context, prevote(Some(BLOCK.id.0), 0, 0, *VALIDATOR_ID_1)).await.unwrap(); context .expect_broadcast() .times(1) - .withf(move |msg: &ConsensusMessage| { - msg == &precommit(Some(BLOCK.id.0), 0, 0, *PROPOSER_ID) - }) + .withf(move |msg: &Vote| msg == &precommit(Some(BLOCK.id.0), 0, 0, *PROPOSER_ID)) .returning(move |_| Ok(())); // The Node got a Prevote quorum, and set valid proposal. assert_eq!( - shc.handle_message(&mut context, prevote(Some(BLOCK.id.0), 0, 0, *VALIDATOR_ID_2)).await, + shc.handle_vote(&mut context, prevote(Some(BLOCK.id.0), 0, 0, *VALIDATOR_ID_2)).await, Ok(ShcReturn::Tasks(vec![timeout_prevote_task(0), precommit_task(Some(BLOCK.id.0), 0),])) ); // Advance to the next round. @@ -419,8 +396,8 @@ async fn repropose() { precommit(None, 0, 0, *VALIDATOR_ID_2), precommit(None, 0, 0, *VALIDATOR_ID_3), ]; - shc.handle_message(&mut context, precommits[0].clone()).await.unwrap(); - shc.handle_message(&mut context, precommits[1].clone()).await.unwrap(); + shc.handle_vote(&mut context, precommits[0].clone()).await.unwrap(); + shc.handle_vote(&mut context, precommits[1].clone()).await.unwrap(); // After NIL precommits, the proposer should re-propose. context.expect_repropose().returning(move |id, init| { assert_eq!(init.height, BlockNumber(0)); @@ -429,9 +406,9 @@ async fn repropose() { context .expect_broadcast() .times(1) - .withf(move |msg: &ConsensusMessage| msg == &prevote(Some(BLOCK.id.0), 0, 1, *PROPOSER_ID)) + .withf(move |msg: &Vote| msg == &prevote(Some(BLOCK.id.0), 0, 1, *PROPOSER_ID)) .returning(move |_| Ok(())); - shc.handle_message(&mut context, precommits[2].clone()).await.unwrap(); + shc.handle_vote(&mut context, precommits[2].clone()).await.unwrap(); shc.handle_event( &mut context, ShcEvent::TimeoutPrecommit(StateMachineEvent::TimeoutPrecommit(0)), @@ -444,18 +421,13 @@ async fn repropose() { precommit(Some(BLOCK.id.0), 0, 1, *VALIDATOR_ID_2), precommit(Some(BLOCK.id.0), 0, 1, *VALIDATOR_ID_3), ]; - shc.handle_message(&mut context, precommits[0].clone()).await.unwrap(); - shc.handle_message(&mut context, precommits[1].clone()).await.unwrap(); + shc.handle_vote(&mut context, precommits[0].clone()).await.unwrap(); + shc.handle_vote(&mut context, precommits[1].clone()).await.unwrap(); let ShcReturn::Decision(decision) = - shc.handle_message(&mut context, precommits[2].clone()).await.unwrap() + shc.handle_vote(&mut context, precommits[2].clone()).await.unwrap() else { panic!("Expected decision"); }; assert_eq!(decision.block, BLOCK.id); - assert!( - decision - .precommits - .into_iter() - .all(|item| precommits.contains(&ConsensusMessage::Vote(item))) - ); + assert!(decision.precommits.into_iter().all(|item| precommits.contains(&item))); } diff --git a/crates/sequencing/papyrus_consensus/src/state_machine.rs b/crates/starknet_consensus/src/state_machine.rs similarity index 88% rename from crates/sequencing/papyrus_consensus/src/state_machine.rs rename to crates/starknet_consensus/src/state_machine.rs index c4b3cd70f8b..ba63ca7ed4f 100644 --- a/crates/sequencing/papyrus_consensus/src/state_machine.rs +++ b/crates/starknet_consensus/src/state_machine.rs @@ -9,29 +9,30 @@ mod state_machine_test; use std::collections::{HashMap, HashSet, VecDeque}; -use tracing::trace; +use tracing::{info, trace}; -use crate::types::{ProposalContentId, Round, ValidatorId}; +use crate::metrics::CONSENSUS_ROUND; +use crate::types::{ProposalCommitment, Round, ValidatorId}; /// Events which the state machine sends/receives. #[derive(Debug, Clone, PartialEq)] pub enum StateMachineEvent { - /// Sent by the state machine when a block is required to propose (ProposalContentId is always + /// Sent by the state machine when a block is required to propose (ProposalCommitment is always /// None). While waiting for the response of GetProposal, the state machine will buffer all - /// other events. The caller must respond with a valid proposal id for this height to the + /// other events. The caller *must* respond with a valid proposal id for this height to the /// state machine, and the same round sent out. - GetProposal(Option, Round), + GetProposal(Option, Round), /// Consensus message, can be both sent from and to the state machine. // (proposal_id, round, valid_round) - Proposal(Option, Round, Option), + Proposal(Option, Round, Option), /// Consensus message, can be both sent from and to the state machine. - Prevote(Option, Round), + Prevote(Option, Round), /// Consensus message, can be both sent from and to the state machine. - Precommit(Option, Round), + Precommit(Option, Round), /// The state machine returns this event to the caller when a decision is reached. Not /// expected as an inbound message. We presume that the caller is able to recover the set of /// precommits which led to this decision from the information returned here. - Decision(ProposalContentId, Round), + Decision(ProposalCommitment, Round), /// Timeout events, can be both sent from and to the state machine. TimeoutPropose(Round), /// Timeout events, can be both sent from and to the state machine. @@ -48,26 +49,28 @@ pub enum Step { } /// State Machine. Major assumptions: -/// 1. SHC handles replays and conflicts. +/// 1. SHC handles: authentication, replays, and conflicts. /// 2. SM must handle "out of order" messages (E.g. vote arrives before proposal). -/// 3. No network failures. +/// +/// Each height is begun with a call to `start`, with no further calls to it. pub struct StateMachine { id: ValidatorId, round: Round, step: Step, quorum: u32, round_skip_threshold: u32, + is_observer: bool, // {round: (proposal_id, valid_round)} - proposals: HashMap, Option)>, + proposals: HashMap, Option)>, // {round: {proposal_id: vote_count} - prevotes: HashMap, u32>>, - precommits: HashMap, u32>>, + prevotes: HashMap, u32>>, + precommits: HashMap, u32>>, // When true, the state machine will wait for a GetProposal event, buffering all other input // events in `events_queue`. awaiting_get_proposal: bool, events_queue: VecDeque, - locked_value_round: Option<(ProposalContentId, Round)>, - valid_value_round: Option<(ProposalContentId, Round)>, + locked_value_round: Option<(ProposalCommitment, Round)>, + valid_value_round: Option<(ProposalCommitment, Round)>, prevote_quorum: HashSet, mixed_prevote_quorum: HashSet, mixed_precommit_quorum: HashSet, @@ -75,13 +78,14 @@ pub struct StateMachine { impl StateMachine { /// total_weight - the total voting weight of all validators for this height. - pub fn new(id: ValidatorId, total_weight: u32) -> Self { + pub fn new(id: ValidatorId, total_weight: u32, is_observer: bool) -> Self { Self { id, round: 0, step: Step::Propose, quorum: (2 * total_weight / 3) + 1, round_skip_threshold: total_weight / 3 + 1, + is_observer, proposals: HashMap::new(), prevotes: HashMap::new(), precommits: HashMap::new(), @@ -95,6 +99,10 @@ impl StateMachine { } } + pub fn round(&self) -> Round { + self.round + } + pub fn quorum_size(&self) -> u32 { self.quorum } @@ -111,8 +119,8 @@ impl StateMachine { /// Process the incoming event. /// - /// If we are waiting for a response to `GetProposal` all other incoming events are buffered - /// until that response arrives. + /// If we are waiting for a response to [`GetProposal`](`StateMachineEvent::GetProposal`) all + /// other incoming events are buffered until that response arrives. /// /// Returns a set of events for the caller to handle. The caller should not mirror the output /// events back to the state machine, as it makes sure to handle them before returning. @@ -126,7 +134,6 @@ impl StateMachine { where LeaderFn: Fn(Round) -> ValidatorId, { - trace!("Handling event: {:?}", event); // Mimic LOC 18 in the paper; the state machine doesn't // handle any events until `getValue` completes. if self.awaiting_get_proposal { @@ -163,6 +170,9 @@ impl StateMachine { StateMachineEvent::Proposal(_, _, _) | StateMachineEvent::Prevote(_, _) | StateMachineEvent::Precommit(_, _) => { + if self.is_observer { + continue; + } self.events_queue.push_back(e.clone()); } StateMachineEvent::Decision(_, _) => { @@ -171,7 +181,8 @@ impl StateMachine { } StateMachineEvent::GetProposal(_, _) => { // LOC 18. - debug_assert!(resultant_events.is_empty()); + assert!(resultant_events.is_empty()); + assert!(!self.is_observer); output_events.push_back(e); return output_events; } @@ -191,8 +202,9 @@ impl StateMachine { where LeaderFn: Fn(Round) -> ValidatorId, { + trace!("Processing event: {:?}", event); if self.awaiting_get_proposal { - debug_assert!(matches!(event, StateMachineEvent::GetProposal(_, _)), "{:?}", event); + assert!(matches!(event, StateMachineEvent::GetProposal(_, _)), "{:?}", event); } match event { @@ -223,21 +235,20 @@ impl StateMachine { fn handle_get_proposal( &mut self, - proposal_id: Option, + proposal_id: Option, round: u32, ) -> VecDeque { // TODO(matan): Will we allow other events (timeoutPropose) to exit this state? assert!(self.awaiting_get_proposal); assert_eq!(round, self.round); self.awaiting_get_proposal = false; - assert!(proposal_id.is_some(), "SHC should pass a valid proposal content id"); VecDeque::from([StateMachineEvent::Proposal(proposal_id, round, None)]) } // A proposal from a peer (or self) node. fn handle_proposal( &mut self, - proposal_id: Option, + proposal_id: Option, round: u32, valid_round: Option, leader_fn: &LeaderFn, @@ -262,7 +273,7 @@ impl StateMachine { // A prevote from a peer (or self) node. fn handle_prevote( &mut self, - proposal_id: Option, + proposal_id: Option, round: u32, leader_fn: &LeaderFn, ) -> VecDeque @@ -287,7 +298,7 @@ impl StateMachine { // A precommit from a peer (or self) node. fn handle_precommit( &mut self, - proposal_id: Option, + proposal_id: Option, round: u32, leader_fn: &LeaderFn, ) -> VecDeque @@ -324,9 +335,11 @@ impl StateMachine { where LeaderFn: Fn(Round) -> ValidatorId, { + CONSENSUS_ROUND.set(round); self.round = round; self.step = Step::Propose; - let mut output = if self.id == leader_fn(self.round) { + let mut output = if !self.is_observer && self.id == leader_fn(self.round) { + info!("Starting round {round} as Proposer"); // Leader. match self.valid_value_round { Some((proposal_id, valid_round)) => VecDeque::from([StateMachineEvent::Proposal( @@ -341,6 +354,7 @@ impl StateMachine { } } } else { + info!("Starting round {round} as Validator"); VecDeque::from([StateMachineEvent::TimeoutPropose(self.round)]) }; output.append(&mut self.current_round_upons()); @@ -400,7 +414,7 @@ impl StateMachine { return VecDeque::new(); } let mut output = if proposal_id.is_some_and(|v| { - self.locked_value_round.map_or(true, |(locked_value, _)| v == locked_value) + self.locked_value_round.is_none_or(|(locked_value, _)| v == locked_value) }) { VecDeque::from([StateMachineEvent::Prevote(*proposal_id, self.round)]) } else { @@ -428,7 +442,7 @@ impl StateMachine { return VecDeque::new(); } let mut output = if proposal_id.is_some_and(|v| { - self.locked_value_round.map_or(true, |(locked_value, locked_round)| { + self.locked_value_round.is_none_or(|(locked_value, locked_round)| { locked_round <= *valid_round || locked_value == v }) }) { @@ -538,7 +552,7 @@ impl StateMachine { } fn round_has_enough_votes( - votes: &HashMap, u32>>, + votes: &HashMap, u32>>, round: u32, threshold: u32, ) -> bool { @@ -546,9 +560,9 @@ fn round_has_enough_votes( } fn value_has_enough_votes( - votes: &HashMap, u32>>, + votes: &HashMap, u32>>, round: u32, - value: &Option, + value: &Option, threshold: u32, ) -> bool { votes.get(&round).map_or(0, |v| *v.get(value).unwrap_or(&0)) >= threshold diff --git a/crates/sequencing/papyrus_consensus/src/state_machine_test.rs b/crates/starknet_consensus/src/state_machine_test.rs similarity index 89% rename from crates/sequencing/papyrus_consensus/src/state_machine_test.rs rename to crates/starknet_consensus/src/state_machine_test.rs index 03d76b17a56..69c46df6294 100644 --- a/crates/sequencing/papyrus_consensus/src/state_machine_test.rs +++ b/crates/starknet_consensus/src/state_machine_test.rs @@ -1,20 +1,21 @@ use std::collections::VecDeque; use lazy_static::lazy_static; +use papyrus_protobuf::consensus::DEFAULT_VALIDATOR_ID; use starknet_api::block::BlockHash; use starknet_types_core::felt::Felt; use test_case::test_case; use super::Round; use crate::state_machine::{StateMachine, StateMachineEvent}; -use crate::types::{ProposalContentId, ValidatorId}; +use crate::types::{ProposalCommitment, ValidatorId}; lazy_static! { - static ref PROPOSER_ID: ValidatorId = 0_u32.into(); - static ref VALIDATOR_ID: ValidatorId = 1_u32.into(); + static ref PROPOSER_ID: ValidatorId = DEFAULT_VALIDATOR_ID.into(); + static ref VALIDATOR_ID: ValidatorId = (DEFAULT_VALIDATOR_ID + 1).into(); } -const PROPOSAL_ID: Option = Some(BlockHash(Felt::ONE)); +const PROPOSAL_ID: Option = Some(BlockHash(Felt::ONE)); const ROUND: Round = 0; struct TestWrapper ValidatorId> { @@ -24,9 +25,9 @@ struct TestWrapper ValidatorId> { } impl ValidatorId> TestWrapper { - pub fn new(id: ValidatorId, total_weight: u32, leader_fn: LeaderFn) -> Self { + pub fn new(id: ValidatorId, total_weight: u32, leader_fn: LeaderFn, is_observer: bool) -> Self { Self { - state_machine: StateMachine::new(id, total_weight), + state_machine: StateMachine::new(id, total_weight, is_observer), leader_fn, events: VecDeque::new(), } @@ -40,19 +41,19 @@ impl ValidatorId> TestWrapper { self.events.append(&mut self.state_machine.start(&self.leader_fn)) } - pub fn send_get_proposal(&mut self, proposal_id: Option, round: Round) { + pub fn send_get_proposal(&mut self, proposal_id: Option, round: Round) { self.send_event(StateMachineEvent::GetProposal(proposal_id, round)) } - pub fn send_proposal(&mut self, proposal_id: Option, round: Round) { + pub fn send_proposal(&mut self, proposal_id: Option, round: Round) { self.send_event(StateMachineEvent::Proposal(proposal_id, round, None)) } - pub fn send_prevote(&mut self, proposal_id: Option, round: Round) { + pub fn send_prevote(&mut self, proposal_id: Option, round: Round) { self.send_event(StateMachineEvent::Prevote(proposal_id, round)) } - pub fn send_precommit(&mut self, proposal_id: Option, round: Round) { + pub fn send_precommit(&mut self, proposal_id: Option, round: Round) { self.send_event(StateMachineEvent::Precommit(proposal_id, round)) } @@ -77,7 +78,7 @@ impl ValidatorId> TestWrapper { #[test_case(false; "validator")] fn events_arrive_in_ideal_order(is_proposer: bool) { let id = if is_proposer { *PROPOSER_ID } else { *VALIDATOR_ID }; - let mut wrapper = TestWrapper::new(id, 4, |_: Round| *PROPOSER_ID); + let mut wrapper = TestWrapper::new(id, 4, |_: Round| *PROPOSER_ID, false); wrapper.start(); if is_proposer { @@ -120,7 +121,7 @@ fn events_arrive_in_ideal_order(is_proposer: bool) { #[test] fn validator_receives_votes_first() { - let mut wrapper = TestWrapper::new(*VALIDATOR_ID, 4, |_: Round| *PROPOSER_ID); + let mut wrapper = TestWrapper::new(*VALIDATOR_ID, 4, |_: Round| *PROPOSER_ID, false); wrapper.start(); // Waiting for the proposal. @@ -153,8 +154,8 @@ fn validator_receives_votes_first() { #[test_case(PROPOSAL_ID ; "valid_proposal")] #[test_case(None ; "invalid_proposal")] -fn buffer_events_during_get_proposal(vote: Option) { - let mut wrapper = TestWrapper::new(*PROPOSER_ID, 4, |_: Round| *PROPOSER_ID); +fn buffer_events_during_get_proposal(vote: Option) { + let mut wrapper = TestWrapper::new(*PROPOSER_ID, 4, |_: Round| *PROPOSER_ID, false); wrapper.start(); assert_eq!(wrapper.next_event().unwrap(), StateMachineEvent::GetProposal(None, 0)); @@ -179,7 +180,7 @@ fn buffer_events_during_get_proposal(vote: Option) { #[test] fn only_send_precommit_with_prevote_quorum_and_proposal() { - let mut wrapper = TestWrapper::new(*VALIDATOR_ID, 4, |_: Round| *PROPOSER_ID); + let mut wrapper = TestWrapper::new(*VALIDATOR_ID, 4, |_: Round| *PROPOSER_ID, false); wrapper.start(); // Waiting for the proposal. @@ -202,7 +203,7 @@ fn only_send_precommit_with_prevote_quorum_and_proposal() { #[test] fn only_decide_with_prcommit_quorum_and_proposal() { - let mut wrapper = TestWrapper::new(*VALIDATOR_ID, 4, |_: Round| *PROPOSER_ID); + let mut wrapper = TestWrapper::new(*VALIDATOR_ID, 4, |_: Round| *PROPOSER_ID, false); wrapper.start(); // Waiting for the proposal. @@ -232,7 +233,7 @@ fn only_decide_with_prcommit_quorum_and_proposal() { #[test] fn advance_to_the_next_round() { - let mut wrapper = TestWrapper::new(*VALIDATOR_ID, 4, |_: Round| *PROPOSER_ID); + let mut wrapper = TestWrapper::new(*VALIDATOR_ID, 4, |_: Round| *PROPOSER_ID, false); wrapper.start(); // Waiting for the proposal. @@ -258,7 +259,7 @@ fn advance_to_the_next_round() { #[test] fn prevote_when_receiving_proposal_in_current_round() { - let mut wrapper = TestWrapper::new(*VALIDATOR_ID, 4, |_: Round| *PROPOSER_ID); + let mut wrapper = TestWrapper::new(*VALIDATOR_ID, 4, |_: Round| *PROPOSER_ID, false); wrapper.start(); assert_eq!(wrapper.next_event().unwrap(), StateMachineEvent::TimeoutPropose(ROUND)); @@ -283,7 +284,7 @@ fn prevote_when_receiving_proposal_in_current_round() { #[test_case(true ; "send_proposal")] #[test_case(false ; "send_timeout_propose")] fn mixed_quorum(send_prposal: bool) { - let mut wrapper = TestWrapper::new(*VALIDATOR_ID, 4, |_: Round| *PROPOSER_ID); + let mut wrapper = TestWrapper::new(*VALIDATOR_ID, 4, |_: Round| *PROPOSER_ID, false); wrapper.start(); // Waiting for the proposal. @@ -313,7 +314,7 @@ fn mixed_quorum(send_prposal: bool) { #[test] fn dont_handle_enqueued_while_awaiting_get_proposal() { - let mut wrapper = TestWrapper::new(*PROPOSER_ID, 4, |_: Round| *PROPOSER_ID); + let mut wrapper = TestWrapper::new(*PROPOSER_ID, 4, |_: Round| *PROPOSER_ID, false); wrapper.start(); assert_eq!(wrapper.next_event().unwrap(), StateMachineEvent::GetProposal(None, ROUND)); @@ -358,7 +359,7 @@ fn dont_handle_enqueued_while_awaiting_get_proposal() { #[test] fn return_proposal_if_locked_value_is_set() { - let mut wrapper = TestWrapper::new(*PROPOSER_ID, 4, |_: Round| *PROPOSER_ID); + let mut wrapper = TestWrapper::new(*PROPOSER_ID, 4, |_: Round| *PROPOSER_ID, false); wrapper.start(); assert_eq!(wrapper.next_event().unwrap(), StateMachineEvent::GetProposal(None, ROUND)); @@ -389,3 +390,29 @@ fn return_proposal_if_locked_value_is_set() { ); assert_eq!(wrapper.next_event().unwrap(), StateMachineEvent::Prevote(PROPOSAL_ID, ROUND + 1)); } + +#[test] +fn observer_node_reaches_decision() { + let id = *VALIDATOR_ID; + let mut wrapper = TestWrapper::new(id, 4, |_: Round| *PROPOSER_ID, true); + + wrapper.start(); + + // Waiting for the proposal. + assert_eq!(wrapper.next_event().unwrap(), StateMachineEvent::TimeoutPropose(ROUND)); + assert!(wrapper.next_event().is_none()); + wrapper.send_proposal(PROPOSAL_ID, ROUND); + // The observer node does not respond to the proposal by sending votes. + assert!(wrapper.next_event().is_none()); + + wrapper.send_precommit(PROPOSAL_ID, ROUND); + wrapper.send_precommit(PROPOSAL_ID, ROUND); + wrapper.send_precommit(PROPOSAL_ID, ROUND); + assert_eq!(wrapper.next_event().unwrap(), StateMachineEvent::TimeoutPrecommit(ROUND)); + // Once a quorum of precommits is observed, the node should generate a decision event. + assert_eq!( + wrapper.next_event().unwrap(), + StateMachineEvent::Decision(PROPOSAL_ID.unwrap(), ROUND) + ); + assert!(wrapper.next_event().is_none()); +} diff --git a/crates/starknet_consensus/src/stream_handler.rs b/crates/starknet_consensus/src/stream_handler.rs new file mode 100644 index 00000000000..3f77ea90f46 --- /dev/null +++ b/crates/starknet_consensus/src/stream_handler.rs @@ -0,0 +1,457 @@ +//! Overlay streaming logic onto individual messages. + +use std::cmp::Ordering; +use std::collections::hash_map::Entry::{Occupied, Vacant}; +use std::collections::{BTreeMap, HashMap}; +use std::fmt::{Debug, Display}; +use std::hash::Hash; + +use futures::channel::mpsc; +use futures::never::Never; +use futures::StreamExt; +use papyrus_network::network_manager::{BroadcastTopicClientTrait, ReceivedBroadcastedMessage}; +use papyrus_network::utils::StreamMap; +use papyrus_network_types::network_types::{BroadcastedMessageMetadata, OpaquePeerId}; +use papyrus_protobuf::consensus::{StreamMessage, StreamMessageBody}; +use papyrus_protobuf::converters::ProtobufConversionError; +use tracing::{instrument, warn}; + +#[cfg(test)] +#[path = "stream_handler_test.rs"] +mod stream_handler_test; + +type PeerId = OpaquePeerId; +type MessageId = u64; + +/// Channel size for stream messages. +// TODO(guy): make this configurable. +pub const CHANNEL_BUFFER_LENGTH: usize = 100; + +/// Errors which cause the stream handler to stop functioning. +#[derive(thiserror::Error, PartialEq, Debug)] +pub enum StreamHandlerError { + /// Client has closed their sender, so no more outbound streams can be sent. + #[error("Client has closed their sender, so no more outbound streams can be sent.")] + OutboundChannelClosed, + /// Network has closed their sender, so no more inbound streams can be sent. + #[error("Network has closed their sender, so no more inbound streams can be sent.")] + InboundChannelClosed, + /// StreamId sent by client for a stream which is in use for an existing stream. + #[error("StreamId sent by client for a stream which is in use for an existing stream. {0}")] + StreamIdReused(String), +} + +/// A combination of trait bounds needed for the content of the stream. +pub trait StreamContentTrait: + Clone + Into> + TryFrom, Error = ProtobufConversionError> + Send +{ +} +impl StreamContentTrait for StreamContent where + StreamContent: Clone + Into> + TryFrom, Error = ProtobufConversionError> + Send +{ +} +/// A combination of trait bounds needed for the stream ID. +pub trait StreamIdTrait: + Into> + + TryFrom, Error = ProtobufConversionError> + + Eq + + Hash + + Clone + + Unpin + + Display + + Debug + + Send + + Ord +{ +} +impl StreamIdTrait for StreamId where + StreamId: Into> + + TryFrom, Error = ProtobufConversionError> + + Eq + + Hash + + Clone + + Unpin + + Display + + Debug + + Send + + Ord +{ +} + +// Use this struct for each inbound stream. +// Drop the struct when: +// (1) receiver on the other end is dropped, +// (2) fin message is received and all messages are sent. +#[derive(Debug)] +struct StreamData { + next_message_id: MessageId, + // Last message ID. If None, it means we have not yet gotten to it. + fin_message_id: Option, + max_message_id_received: MessageId, + // Keep the receiver until it is time to send it to the application. + receiver: Option>, + sender: mpsc::Sender, + // A buffer for messages that were received out of order. + message_buffer: HashMap>, +} + +impl + StreamData +{ + fn new() -> Self { + let (sender, receiver) = mpsc::channel(CHANNEL_BUFFER_LENGTH); + StreamData { + next_message_id: 0, + fin_message_id: None, + max_message_id_received: 0, + sender, + receiver: Some(receiver), + message_buffer: HashMap::new(), + } + } +} + +/// A StreamHandler is responsible for: +/// - Buffering inbound messages and reporting them to the application in order. +/// - Sending outbound messages to the network, wrapped in StreamMessage. +pub struct StreamHandler +where + StreamContent: StreamContentTrait, + StreamId: StreamIdTrait, + InboundReceiverT: Unpin + + StreamExt>>, + OutboundSenderT: BroadcastTopicClientTrait>, +{ + // For each stream ID from the network, send the application a Receiver + // that will receive the messages in order. This allows sending such Receivers. + inbound_channel_sender: mpsc::Sender>, + // This receives messages from the network. + inbound_receiver: InboundReceiverT, + // A map from (peer_id, stream_id) to a struct that contains all the information + // about the stream. This includes both the message buffer and some metadata + // (like the latest message ID). + inbound_stream_data: HashMap<(PeerId, StreamId), StreamData>, + // Whenever application wants to start a new stream, it must send out a + // (stream_id, Receiver) pair. Each receiver gets messages that should + // be sent out to the network. + outbound_channel_receiver: mpsc::Receiver<(StreamId, mpsc::Receiver)>, + // A map where the abovementioned Receivers are stored. + outbound_stream_receivers: StreamMap>, + // A network sender that allows sending StreamMessages to peers. + outbound_sender: OutboundSenderT, + // For each stream, keep track of the message_id of the last message sent. + outbound_stream_number: HashMap, +} + +impl + StreamHandler +where + StreamContent: StreamContentTrait, + StreamId: StreamIdTrait, + InboundReceiverT: Unpin + + StreamExt>>, + OutboundSenderT: BroadcastTopicClientTrait>, +{ + /// Create a new StreamHandler. + pub fn new( + inbound_channel_sender: mpsc::Sender>, + inbound_receiver: InboundReceiverT, + outbound_channel_receiver: mpsc::Receiver<(StreamId, mpsc::Receiver)>, + outbound_sender: OutboundSenderT, + ) -> Self { + Self { + inbound_channel_sender, + inbound_receiver, + inbound_stream_data: HashMap::new(), + outbound_channel_receiver, + outbound_sender, + outbound_stream_receivers: StreamMap::new(BTreeMap::new()), + outbound_stream_number: HashMap::new(), + } + } + + /// Run the stream handler indefinitely. + pub async fn run(mut self) -> Result { + loop { + self.handle_next_msg().await? + } + } + + /// Listen for a single message coming from the network or from an application. + /// - Outbound messages are wrapped as StreamMessage and sent to the network directly. + /// - Inbound messages are stripped of StreamMessage and buffered until they can be sent in the + /// correct order to the application. + /// + /// Expects to live forever, returning an Error if the client or network close their sender. + pub async fn handle_next_msg(&mut self) -> Result<(), StreamHandlerError> { + tokio::select!( + // New outbound stream. + outbound_stream = self.outbound_channel_receiver.next() => { + self.handle_new_stream(outbound_stream).await + } + // New message on an existing outbound stream. + output = self.outbound_stream_receivers.next() => { + self.handle_outbound_message(output).await; + Ok(()) + } + // New inbound message from the network. + message = self.inbound_receiver.next() => { + self.handle_inbound_message(message) + } + ) + } + + async fn handle_new_stream( + &mut self, + outbound_stream: Option<(StreamId, mpsc::Receiver)>, + ) -> Result<(), StreamHandlerError> { + let Some((stream_id, receiver)) = outbound_stream else { + return Err(StreamHandlerError::OutboundChannelClosed); + }; + if self.outbound_stream_receivers.insert(stream_id.clone(), receiver).is_some() { + return Err(StreamHandlerError::StreamIdReused(format!("{stream_id}"))); + } + Ok(()) + } + + async fn handle_outbound_message( + &mut self, + message: Option<(StreamId, Option)>, + ) { + match message { + Some((key, Some(msg))) => self.broadcast(key, msg).await, + Some((key, None)) => self.broadcast_fin(key).await, + None => { + panic!("StreamHashMap should never be closed") + } + } + } + + fn inbound_send( + &mut self, + data: &mut StreamData, + message: StreamMessage, + ) -> bool { + // TODO(guyn): reconsider the "expect" here. + let sender = &mut data.sender; + if let StreamMessageBody::Content(content) = message.message { + match sender.try_send(content) { + Ok(_) => {} + Err(e) => { + if e.is_disconnected() { + warn!( + "Sender is disconnected, dropping the message. StreamId: {}, \ + MessageId: {}", + message.stream_id, message.message_id + ); + return true; + } else if e.is_full() { + // TODO(guyn): replace panic with buffering of the message. + panic!( + "Sender is full, dropping the message. StreamId: {}, MessageId: {}", + message.stream_id, message.message_id + ); + } else { + // TODO(guyn): replace panic with more graceful error handling + panic!("Unexpected error: {:?}", e); + } + } + }; + // Send the receiver only once the first message has been sent. + if message.message_id == 0 { + // TODO(guyn): consider the expect in both cases. + // If this is the first message, send the receiver to the application. + let receiver = data.receiver.take().expect("Receiver should exist"); + // Send the receiver to the application. + self.inbound_channel_sender.try_send(receiver).expect("Send should succeed"); + } + data.next_message_id += 1; + return false; + } + // A Fin message is not sent. This is a no-op, can safely return true. + true + } + + // Send the message to the network. + async fn broadcast(&mut self, stream_id: StreamId, message: StreamContent) { + // TODO(guyn): add a random nonce to the outbound stream ID, + // such that even if the client sends the same stream ID, + // (e.g., after a crash) this will be treated as a new stream. + let message = StreamMessage { + message: StreamMessageBody::Content(message), + stream_id: stream_id.clone(), + message_id: *self.outbound_stream_number.get(&stream_id).unwrap_or(&0), + }; + // TODO(guyn): reconsider the "expect" here. + self.outbound_sender.broadcast_message(message).await.expect("Send should succeed"); + self.outbound_stream_number.insert( + stream_id.clone(), + self.outbound_stream_number.get(&stream_id).unwrap_or(&0) + 1, + ); + } + + // Send a fin message to the network. + async fn broadcast_fin(&mut self, stream_id: StreamId) { + let message = StreamMessage { + message: StreamMessageBody::Fin, + stream_id: stream_id.clone(), + message_id: *self.outbound_stream_number.get(&stream_id).unwrap_or(&0), + }; + self.outbound_sender.broadcast_message(message).await.expect("Send should succeed"); + self.outbound_stream_number.remove(&stream_id); + } + + // Handle a message that was received from the network. + #[instrument(skip_all, level = "warn")] + #[allow(clippy::type_complexity)] + fn handle_inbound_message( + &mut self, + message: Option<( + Result, ProtobufConversionError>, + BroadcastedMessageMetadata, + )>, + ) -> Result<(), StreamHandlerError> { + let (message, metadata) = match message { + None => return Err(StreamHandlerError::InboundChannelClosed), + Some((Ok(message), metadata)) => (message, metadata), + Some((Err(e), _)) => { + // TODO(guy): switch to debug when network is opened to "all". + warn!("Error converting message: {:?}", e); + return Ok(()); + } + }; + + let peer_id = metadata.originator_id.clone(); + let stream_id = message.stream_id.clone(); + let key = (peer_id, stream_id); + + let data = match self.inbound_stream_data.entry(key.clone()) { + // If data exists, remove it (it will be returned to hash map at end of function). + Occupied(entry) => entry.remove_entry().1, + Vacant(_) => { + // If we received a message for a stream that we have not seen before, + // we need to create a new receiver for it. + StreamData::new() + } + }; + if let Some(data) = self.handle_message_inner(message, metadata, data) { + self.inbound_stream_data.insert(key, data); + } + Ok(()) + } + + /// Returns the StreamData struct if it should be put back into the hash map. None if the data + /// should be dropped. + fn handle_message_inner( + &mut self, + message: StreamMessage, + metadata: BroadcastedMessageMetadata, + mut data: StreamData, + ) -> Option> { + let peer_id = metadata.originator_id; + let stream_id = message.stream_id.clone(); + let key = (peer_id, stream_id); + let message_id = message.message_id; + + if data.max_message_id_received < message_id { + data.max_message_id_received = message_id; + } + + // Check for Fin type message. + match message.message { + StreamMessageBody::Content(_) => {} + StreamMessageBody::Fin => { + data.fin_message_id = Some(message_id); + if data.max_message_id_received > message_id { + // TODO(guyn): replace warnings with more graceful error handling + warn!( + "Received fin message with id that is smaller than a previous message! \ + key: {:?}, fin_message_id: {}, max_message_id_received: {}", + key.clone(), + message_id, + data.max_message_id_received + ); + return None; + } + } + } + + if message_id > data.fin_message_id.unwrap_or(u64::MAX) { + // TODO(guyn): replace warnings with more graceful error handling + warn!( + "Received message with id that is bigger than the id of the fin message! key: \ + {:?}, message_id: {}, fin_message_id: {}", + key.clone(), + message_id, + data.fin_message_id.unwrap_or(u64::MAX) + ); + return None; + } + + // This means we can just send the message without buffering it. + match message_id.cmp(&data.next_message_id) { + Ordering::Equal => { + let mut receiver_dropped = self.inbound_send(&mut data, message); + if !receiver_dropped { + receiver_dropped = self.process_buffer(&mut data); + } + + if data.message_buffer.is_empty() && data.fin_message_id.is_some() + || receiver_dropped + { + data.sender.close_channel(); + return None; + } + } + Ordering::Greater => { + Self::store(&mut data, key.clone(), message); + } + Ordering::Less => { + // TODO(guyn): replace warnings with more graceful error handling + warn!( + "Received message with id that is smaller than the next message expected! \ + key: {:?}, message_id: {}, next_message_id: {}", + key.clone(), + message_id, + data.next_message_id + ); + return None; + } + } + Some(data) + } + + // Store an inbound message in the buffer. + fn store( + data: &mut StreamData, + key: (PeerId, StreamId), + message: StreamMessage, + ) { + let message_id = message.message_id; + + match data.message_buffer.entry(message_id) { + Vacant(e) => { + e.insert(message); + } + Occupied(_) => { + // TODO(guyn): replace warnings with more graceful error handling + warn!( + "Two messages with the same message_id in buffer! key: {:?}, message_id: {}", + key, message_id + ); + } + } + } + + // Tries to drain as many messages as possible from the buffer (in order), + // DOES NOT guarantee that the buffer will be empty after calling this function. + // Returns true if the receiver for this stream is dropped. + fn process_buffer(&mut self, data: &mut StreamData) -> bool { + while let Some(message) = data.message_buffer.remove(&data.next_message_id) { + if self.inbound_send(data, message) { + return true; + } + } + false + } +} diff --git a/crates/starknet_consensus/src/stream_handler_test.rs b/crates/starknet_consensus/src/stream_handler_test.rs new file mode 100644 index 00000000000..9f68720432b --- /dev/null +++ b/crates/starknet_consensus/src/stream_handler_test.rs @@ -0,0 +1,404 @@ +use std::collections::BTreeSet; +use std::fmt::Display; + +use futures::channel::mpsc::{self, Receiver, SendError, Sender}; +use futures::{FutureExt, SinkExt, StreamExt}; +use papyrus_network::network_manager::{BroadcastTopicClientTrait, ReceivedBroadcastedMessage}; +use papyrus_network_types::network_types::BroadcastedMessageMetadata; +use papyrus_protobuf::consensus::{ProposalInit, ProposalPart, StreamMessageBody}; +use papyrus_protobuf::converters::ProtobufConversionError; +use papyrus_test_utils::{get_rng, GetTestInstance}; +use prost::DecodeError; + +use crate::stream_handler::StreamHandler; +const CHANNEL_SIZE: usize = 100; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +struct TestStreamId(u64); + +impl From for Vec { + fn from(value: TestStreamId) -> Self { + value.0.to_be_bytes().to_vec() + } +} + +impl TryFrom> for TestStreamId { + type Error = ProtobufConversionError; + fn try_from(bytes: Vec) -> Result { + if bytes.len() != 8 { + return Err(ProtobufConversionError::DecodeError(DecodeError::new("Invalid length"))); + } + let mut array = [0; 8]; + array.copy_from_slice(&bytes); + Ok(TestStreamId(u64::from_be_bytes(array))) + } +} + +impl PartialOrd for TestStreamId { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for TestStreamId { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.0.cmp(&other.0) + } +} + +impl Display for TestStreamId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "TestStreamId({})", self.0) + } +} + +type StreamMessage = papyrus_protobuf::consensus::StreamMessage; + +struct FakeBroadcastClient { + sender: Sender, +} + +#[async_trait::async_trait] +impl BroadcastTopicClientTrait for FakeBroadcastClient { + async fn broadcast_message(&mut self, message: StreamMessage) -> Result<(), SendError> { + self.sender.send(message).await + } + + async fn report_peer(&mut self, _: BroadcastedMessageMetadata) -> Result<(), SendError> { + todo!() + } + + async fn continue_propagation( + &mut self, + _: &BroadcastedMessageMetadata, + ) -> Result<(), SendError> { + todo!() + } +} + +#[allow(clippy::type_complexity)] +fn setup() -> ( + StreamHandler< + ProposalPart, + TestStreamId, + Receiver>, + FakeBroadcastClient, + >, + Sender>, + Receiver>, + Sender<(TestStreamId, Receiver)>, + Receiver, +) { + let (inbound_internal_sender, inbound_internal_receiver) = mpsc::channel(CHANNEL_SIZE); + let (inbound_network_sender, inbound_network_receiver) = mpsc::channel(CHANNEL_SIZE); + let (outbound_internal_sender, outbound_internal_receiver) = mpsc::channel(CHANNEL_SIZE); + let (outbound_network_sender, outbound_network_receiver) = mpsc::channel(CHANNEL_SIZE); + let outbound_network_sender = FakeBroadcastClient { sender: outbound_network_sender }; + let stream_handler = StreamHandler::new( + inbound_internal_sender, + inbound_network_receiver, + outbound_internal_receiver, + outbound_network_sender, + ); + + ( + stream_handler, + inbound_network_sender, + inbound_internal_receiver, + outbound_internal_sender, + outbound_network_receiver, + ) +} + +fn build_init_message(round: u32, stream_id: u64, message_id: u32) -> StreamMessage { + StreamMessage { + message: StreamMessageBody::Content(ProposalPart::Init(ProposalInit { + round, + ..Default::default() + })), + stream_id: TestStreamId(stream_id), + message_id: message_id.into(), + } +} + +fn build_fin_message(stream_id: u64, message_id: u32) -> StreamMessage { + StreamMessage { + message: StreamMessageBody::Fin, + stream_id: TestStreamId(stream_id), + message_id: message_id.into(), + } +} + +fn as_usize>(t: T) -> usize +where + >::Error: std::fmt::Debug, +{ + t.try_into().unwrap() +} + +#[tokio::test] +async fn outbound_single() { + let num_messages = 5; + let stream_id = 1; + let ( + mut stream_handler, + _inbound_network_sender, + _inbound_internal_receiver, + mut client_to_streamhandler_sender, + mut streamhandler_to_network_receiver, + ) = setup(); + + // Create a new stream to send. + let (mut sender, stream_receiver) = mpsc::channel(CHANNEL_SIZE); + client_to_streamhandler_sender.send((TestStreamId(stream_id), stream_receiver)).await.unwrap(); + stream_handler.handle_next_msg().await.unwrap(); + + // Send the content of the stream. + for i in 0..num_messages { + let init = ProposalPart::Init(ProposalInit { round: i, ..Default::default() }); + sender.send(init).await.unwrap(); + } + + // Check the content is sent to the network in order. + for i in 0..num_messages { + stream_handler.handle_next_msg().await.unwrap(); + let actual = streamhandler_to_network_receiver.next().now_or_never().unwrap().unwrap(); + assert_eq!(actual, build_init_message(i, stream_id, i)); + } + + // Close the stream and check that a Fin is sent to the network. + sender.close_channel(); + stream_handler.handle_next_msg().await.unwrap(); + assert_eq!( + streamhandler_to_network_receiver.next().now_or_never().unwrap().unwrap(), + build_fin_message(stream_id, num_messages) + ); +} + +#[tokio::test] +async fn outbound_multiple() { + let num_messages = 5; + let num_streams = 3; + let ( + mut stream_handler, + _inbound_network_sender, + _inbound_internal_receiver, + mut client_to_streamhandler_sender, + mut streamhandler_to_network_receiver, + ) = setup(); + + // Client opens up multiple outbound streams. + let mut stream_senders = Vec::new(); + for stream_id in 0..num_streams { + let (sender, stream_receiver) = mpsc::channel(CHANNEL_SIZE); + stream_senders.push(sender); + client_to_streamhandler_sender + .send((TestStreamId(stream_id), stream_receiver)) + .await + .unwrap(); + stream_handler.handle_next_msg().await.unwrap(); + } + + // Send messages on all of the streams. + for stream_id in 0..num_streams { + let sender = stream_senders.get_mut(as_usize(stream_id)).unwrap(); + for i in 0..num_messages { + let init = ProposalPart::Init(ProposalInit { round: i, ..Default::default() }); + sender.send(init).await.unwrap(); + } + } + + // {StreamId : [Msgs]} - asserts order received matches expected order per stream. + let mut expected_msgs = (0..num_streams).map(|_| Vec::new()).collect::>(); + let mut actual_msgs = expected_msgs.clone(); + for stream_id in 0..num_streams { + for i in 0..num_messages { + // The order the stream handler selects from among multiple streams is undefined. + stream_handler.handle_next_msg().await.unwrap(); + let msg = streamhandler_to_network_receiver.next().now_or_never().unwrap().unwrap(); + actual_msgs[as_usize(msg.stream_id.0)].push(msg); + expected_msgs[as_usize(stream_id)].push(build_init_message(i, stream_id, i)); + } + } + assert_eq!(actual_msgs, expected_msgs); + + // Drop all the senders and check Fins are sent. + stream_senders.clear(); + let mut stream_ids = (0..num_streams).collect::>(); + for _ in 0..num_streams { + stream_handler.handle_next_msg().await.unwrap(); + let fin = streamhandler_to_network_receiver.next().now_or_never().unwrap().unwrap(); + assert_eq!(fin.message, StreamMessageBody::Fin); + assert_eq!(fin.message_id, u64::from(num_messages)); + assert!(stream_ids.remove(&fin.stream_id.0)); + } +} + +#[tokio::test] +async fn inbound_in_order() { + let num_messages = 10; + let stream_id = 127; + let ( + mut stream_handler, + mut inbound_network_sender, + mut inbound_internal_receiver, + _client_to_streamhandler_sender, + _streamhandler_to_network_receiver, + ) = setup(); + let metadata = BroadcastedMessageMetadata::get_test_instance(&mut get_rng()); + + // Send all messages in order. + for i in 0..num_messages { + let message = build_init_message(i, stream_id, i); + inbound_network_sender.send((Ok(message), metadata.clone())).await.unwrap(); + stream_handler.handle_next_msg().await.unwrap(); + } + let message = build_fin_message(stream_id, num_messages); + inbound_network_sender.send((Ok(message), metadata.clone())).await.unwrap(); + stream_handler.handle_next_msg().await.unwrap(); + // Fin is communicated by dropping the sender, hence `..num_message` not `..=num_messages` + let mut receiver = inbound_internal_receiver.next().now_or_never().unwrap().unwrap(); + for i in 0..num_messages { + let message = receiver.next().await.unwrap(); + assert_eq!(message, ProposalPart::Init(ProposalInit { round: i, ..Default::default() })); + } + // Check that the receiver was closed: + assert!(matches!(receiver.try_next(), Ok(None))); +} + +#[tokio::test] +async fn inbound_multiple() { + let num_messages = 5; + let num_streams = 3; + let ( + mut stream_handler, + mut inbound_network_sender, + mut inbound_internal_receiver, + _client_to_streamhandler_sender, + _streamhandler_to_network_receiver, + ) = setup(); + let metadata = BroadcastedMessageMetadata::get_test_instance(&mut get_rng()); + + // Send all messages to all streams, each stream's messages in order. + for sid in 0..num_streams { + for i in 0..num_messages { + let message = build_init_message(i, sid, i); + inbound_network_sender.send((Ok(message), metadata.clone())).await.unwrap(); + stream_handler.handle_next_msg().await.unwrap(); + } + let message = build_fin_message(sid, num_messages); + inbound_network_sender.send((Ok(message), metadata.clone())).await.unwrap(); + stream_handler.handle_next_msg().await.unwrap(); + } + + let mut expected_msgs = (0..num_streams).map(|_| Vec::new()).collect::>(); + let mut actual_msgs = expected_msgs.clone(); + for sid in 0..num_streams { + let mut receiver = inbound_internal_receiver.next().now_or_never().unwrap().unwrap(); + // Fin is communicated by dropping the sender, hence `..num_message` not `..=num_messages` + for i in 0..num_messages { + let message = receiver.next().await.unwrap(); + actual_msgs.get_mut(as_usize(sid)).unwrap().push(message); + expected_msgs + .get_mut(as_usize(sid)) + .unwrap() + .push(ProposalPart::Init(ProposalInit { round: i, ..Default::default() })); + } + // Check that the receiver was closed: + assert!(matches!(receiver.try_next(), Ok(None))); + } + assert_eq!(actual_msgs, expected_msgs); +} + +#[tokio::test] +async fn inbound_delayed_first() { + let num_messages = 10; + let stream_id = 127; + let ( + mut stream_handler, + mut inbound_network_sender, + mut inbound_internal_receiver, + _client_to_streamhandler_sender, + _streamhandler_to_network_receiver, + ) = setup(); + let metadata = BroadcastedMessageMetadata::get_test_instance(&mut get_rng()); + + // Send all messages besides first one. + for i in 1..num_messages { + let message = build_init_message(i, stream_id, i); + inbound_network_sender.send((Ok(message), metadata.clone())).await.unwrap(); + stream_handler.handle_next_msg().await.unwrap(); + } + let message = build_fin_message(stream_id, num_messages); + inbound_network_sender.send((Ok(message), metadata.clone())).await.unwrap(); + stream_handler.handle_next_msg().await.unwrap(); + + // Check that no receiver was created yet. + assert!(inbound_internal_receiver.try_next().is_err()); + + // Send first message now. + let first_message = build_init_message(0, stream_id, 0); + inbound_network_sender.send((Ok(first_message), metadata.clone())).await.unwrap(); + // Activate the stream handler to ingest this message. + stream_handler.handle_next_msg().await.unwrap(); + + // Now first message and all cached messages should be received. + let mut receiver = inbound_internal_receiver.next().now_or_never().unwrap().unwrap(); + // Fin is communicated by dropping the sender, hence `..num_message` not `..=num_messages` + for i in 0..num_messages { + let message = receiver.next().await.unwrap(); + assert_eq!(message, ProposalPart::Init(ProposalInit { round: i, ..Default::default() })); + } + // Check that the receiver was closed: + assert!(matches!(receiver.try_next(), Ok(None))); +} + +#[tokio::test] +async fn inbound_delayed_middle() { + let num_messages = 10; + let missing_message_id = 3; + let stream_id = 127; + let ( + mut stream_handler, + mut inbound_network_sender, + mut inbound_internal_receiver, + _client_to_streamhandler_sender, + _streamhandler_to_network_receiver, + ) = setup(); + let metadata = BroadcastedMessageMetadata::get_test_instance(&mut get_rng()); + + // Send all messages besides one in the middle of the stream. + for i in 0..num_messages { + if i == missing_message_id { + continue; + } + let message = build_init_message(i, stream_id, i); + inbound_network_sender.send((Ok(message), metadata.clone())).await.unwrap(); + stream_handler.handle_next_msg().await.unwrap(); + } + let message = build_fin_message(stream_id, num_messages); + inbound_network_sender.send((Ok(message), metadata.clone())).await.unwrap(); + stream_handler.handle_next_msg().await.unwrap(); + + // Should receive a few messages, until we reach the missing one. + let mut receiver = inbound_internal_receiver.next().now_or_never().unwrap().unwrap(); + for i in 0..missing_message_id { + let message = receiver.next().await.unwrap(); + assert_eq!(message, ProposalPart::Init(ProposalInit { round: i, ..Default::default() })); + } + + // Send the missing message now. + let missing_msg = build_init_message(missing_message_id, stream_id, missing_message_id); + inbound_network_sender.send((Ok(missing_msg), metadata.clone())).await.unwrap(); + // Activate the stream handler to ingest this message. + stream_handler.handle_next_msg().await.unwrap(); + + // Should now get missing message and all the following ones. + // Fin is communicated by dropping the sender, hence `..num_message` not `..=num_messages` + for i in missing_message_id..num_messages { + let message = receiver.next().await.unwrap(); + assert_eq!(message, ProposalPart::Init(ProposalInit { round: i, ..Default::default() })); + } + // Check that the receiver was closed: + assert!(matches!(receiver.try_next(), Ok(None))); +} diff --git a/crates/starknet_consensus/src/test_utils.rs b/crates/starknet_consensus/src/test_utils.rs new file mode 100644 index 00000000000..79cebbffa25 --- /dev/null +++ b/crates/starknet_consensus/src/test_utils.rs @@ -0,0 +1,110 @@ +use std::time::Duration; + +use async_trait::async_trait; +use futures::channel::{mpsc, oneshot}; +use mockall::mock; +use papyrus_protobuf::consensus::{ProposalFin, ProposalInit, Vote, VoteType}; +use papyrus_protobuf::converters::ProtobufConversionError; +use starknet_api::block::{BlockHash, BlockNumber}; +use starknet_types_core::felt::Felt; + +use crate::types::{ConsensusContext, ConsensusError, ProposalCommitment, Round, ValidatorId}; + +/// Define a consensus block which can be used to enable auto mocking Context. +#[derive(Debug, PartialEq, Clone)] +pub struct TestBlock { + pub content: Vec, + pub id: BlockHash, +} + +#[derive(Debug, PartialEq, Clone)] +pub enum TestProposalPart { + Init(ProposalInit), +} + +impl From for TestProposalPart { + fn from(init: ProposalInit) -> Self { + TestProposalPart::Init(init) + } +} + +impl TryFrom for ProposalInit { + type Error = ProtobufConversionError; + fn try_from(part: TestProposalPart) -> Result { + let TestProposalPart::Init(init) = part; + Ok(init) + } +} + +impl From for Vec { + fn from(part: TestProposalPart) -> Vec { + let TestProposalPart::Init(init) = part; + init.into() + } +} + +impl TryFrom> for TestProposalPart { + type Error = ProtobufConversionError; + + fn try_from(value: Vec) -> Result { + Ok(TestProposalPart::Init(value.try_into()?)) + } +} + +// TODO(matan): When QSelf is supported, switch to automocking `ConsensusContext`. +mock! { + pub TestContext {} + + #[async_trait] + impl ConsensusContext for TestContext { + type ProposalPart = TestProposalPart; + + async fn build_proposal( + &mut self, + init: ProposalInit, + timeout: Duration, + ) -> oneshot::Receiver; + + async fn validate_proposal( + &mut self, + init: ProposalInit, + timeout: Duration, + content: mpsc::Receiver + ) -> oneshot::Receiver<(ProposalCommitment, ProposalFin)>; + + async fn repropose( + &mut self, + id: ProposalCommitment, + init: ProposalInit, + ); + + async fn validators(&self, height: BlockNumber) -> Vec; + + fn proposer(&self, height: BlockNumber, round: Round) -> ValidatorId; + + async fn broadcast(&mut self, message: Vote) -> Result<(), ConsensusError>; + + async fn decision_reached( + &mut self, + block: ProposalCommitment, + precommits: Vec, + ) -> Result<(), ConsensusError>; + + async fn try_sync(&mut self, height: BlockNumber) -> bool; + + async fn set_height_and_round(&mut self, height: BlockNumber, round: Round); + } +} + +pub fn prevote(block_felt: Option, height: u64, round: u32, voter: ValidatorId) -> Vote { + let block_hash = block_felt.map(BlockHash); + Vote { vote_type: VoteType::Prevote, height, round, block_hash, voter } +} + +pub fn precommit(block_felt: Option, height: u64, round: u32, voter: ValidatorId) -> Vote { + let block_hash = block_felt.map(BlockHash); + Vote { vote_type: VoteType::Precommit, height, round, block_hash, voter } +} +pub fn proposal_init(height: u64, round: u32, proposer: ValidatorId) -> ProposalInit { + ProposalInit { height: BlockNumber(height), round, proposer, ..Default::default() } +} diff --git a/crates/sequencing/papyrus_consensus/src/types.rs b/crates/starknet_consensus/src/types.rs similarity index 69% rename from crates/sequencing/papyrus_consensus/src/types.rs rename to crates/starknet_consensus/src/types.rs index a4fcd53f314..65cff656158 100644 --- a/crates/sequencing/papyrus_consensus/src/types.rs +++ b/crates/starknet_consensus/src/types.rs @@ -1,3 +1,4 @@ +//! Types for interfacing between consensus and the node. use std::fmt::Debug; use std::time::Duration; @@ -9,7 +10,7 @@ use papyrus_network::network_manager::{ GenericReceiver, }; use papyrus_network_types::network_types::BroadcastedMessageMetadata; -use papyrus_protobuf::consensus::{ConsensusMessage, ProposalInit, Vote}; +use papyrus_protobuf::consensus::{ProposalFin, ProposalInit, Vote}; use papyrus_protobuf::converters::ProtobufConversionError; use starknet_api::block::{BlockHash, BlockNumber}; use starknet_api::core::ContractAddress; @@ -21,15 +22,22 @@ use starknet_api::core::ContractAddress; // TODO(matan): Determine the actual type of NodeId. pub type ValidatorId = ContractAddress; pub type Round = u32; -pub type ProposalContentId = BlockHash; +pub type ProposalCommitment = BlockHash; /// Interface for consensus to call out to the node. +/// +/// Function calls should be assumed to not be cancel safe. #[async_trait] pub trait ConsensusContext { - /// The chunks of content returned when iterating the proposal. - // In practice I expect this to match the type sent to the network - // (papyrus_protobuf::ConsensusMessage), and not to be specific to just the block's content. - type ProposalChunk; + /// The parts of the proposal that are streamed in. + /// Must contain at least the ProposalInit and ProposalFin. + type ProposalPart: TryFrom, Error = ProtobufConversionError> + + Into> + + TryInto + + From + + Clone + + Send + + Debug; // TODO(matan): The oneshot for receiving the build block could be generalized to just be some // future which returns a block. @@ -50,7 +58,7 @@ pub trait ConsensusContext { &mut self, init: ProposalInit, timeout: Duration, - ) -> oneshot::Receiver; + ) -> oneshot::Receiver; /// This function is called by consensus to validate a block. It expects that this call will /// return immediately and that context can then stream in the block's content in parallel to @@ -59,6 +67,7 @@ pub trait ConsensusContext { /// Params: /// - `height`: The height of the block to be built. Specifically this indicates the initial /// state of the block. + /// - `round`: The round of the block to be built. /// - `timeout`: The maximum time to wait for the block to be built. /// - `content`: A receiver for the stream of the block's content. /// @@ -67,18 +76,18 @@ pub trait ConsensusContext { /// by ConsensusContext. async fn validate_proposal( &mut self, - height: BlockNumber, + init: ProposalInit, timeout: Duration, - content: mpsc::Receiver, - ) -> oneshot::Receiver; + content: mpsc::Receiver, + ) -> oneshot::Receiver<(ProposalCommitment, ProposalFin)>; /// This function is called by consensus to retrieve the content of a previously built or /// validated proposal. It broadcasts the proposal to the network. /// /// Params: - /// - `id`: The `ProposalContentId` associated with the block's content. + /// - `id`: The `ProposalCommitment` associated with the block's content. /// - `init`: The `ProposalInit` that is broadcast to the network. - async fn repropose(&mut self, id: ProposalContentId, init: ProposalInit); + async fn repropose(&mut self, id: ProposalCommitment, init: ProposalInit); /// Get the set of validators for a given height. These are the nodes that can propose and vote /// on blocks. @@ -88,9 +97,10 @@ pub trait ConsensusContext { async fn validators(&self, height: BlockNumber) -> Vec; /// Calculates the ID of the Proposer based on the inputs. + // TODO(matan): Consider passing the validator set in order to keep this sync. fn proposer(&self, height: BlockNumber, round: Round) -> ValidatorId; - async fn broadcast(&mut self, message: ConsensusMessage) -> Result<(), ConsensusError>; + async fn broadcast(&mut self, message: Vote) -> Result<(), ConsensusError>; /// Update the context that a decision has been reached for a given height. /// - `block` identifies the decision. @@ -98,15 +108,23 @@ pub trait ConsensusContext { /// quorum (>2/3 of the voting power) for this height. async fn decision_reached( &mut self, - block: ProposalContentId, + block: ProposalCommitment, precommits: Vec, ) -> Result<(), ConsensusError>; + + /// Attempt to learn of a decision from the sync protocol. + /// Returns true if a decision was learned so consensus can proceed. + async fn try_sync(&mut self, height: BlockNumber) -> bool; + + /// Update the context with the current height and round. + /// Must be called at the beginning of each height. + async fn set_height_and_round(&mut self, height: BlockNumber, round: Round); } #[derive(PartialEq)] pub struct Decision { pub precommits: Vec, - pub block: ProposalContentId, + pub block: ProposalCommitment, } impl Debug for Decision { @@ -118,17 +136,15 @@ impl Debug for Decision { } } -pub struct BroadcastConsensusMessageChannel { - pub broadcasted_messages_receiver: GenericReceiver<( - Result, - BroadcastedMessageMetadata, - )>, - pub broadcast_topic_client: BroadcastTopicClient, +pub struct BroadcastVoteChannel { + pub broadcasted_messages_receiver: + GenericReceiver<(Result, BroadcastedMessageMetadata)>, + pub broadcast_topic_client: BroadcastTopicClient, } -impl From> for BroadcastConsensusMessageChannel { - fn from(broadcast_topic_channels: BroadcastTopicChannels) -> Self { - BroadcastConsensusMessageChannel { +impl From> for BroadcastVoteChannel { + fn from(broadcast_topic_channels: BroadcastTopicChannels) -> Self { + BroadcastVoteChannel { broadcasted_messages_receiver: Box::new( broadcast_topic_channels.broadcasted_messages_receiver, ), @@ -143,19 +159,17 @@ pub enum ConsensusError { Canceled(#[from] oneshot::Canceled), #[error(transparent)] ProtobufConversionError(#[from] ProtobufConversionError), - /// This should never occur, since events are internally generated. - #[error("Invalid event: {0}")] - InvalidEvent(String), - #[error("Invalid proposal sent by peer {0:?} at height {1}: {2}")] - InvalidProposal(ValidatorId, BlockNumber, String), #[error(transparent)] SendError(#[from] mpsc::SendError), - #[error("Conflicting messages for block {0}. Old: {1:?}, New: {2:?}")] - Equivocation(BlockNumber, ConsensusMessage, ConsensusMessage), // Indicates an error in communication between consensus and the node's networking component. // As opposed to an error between this node and peer nodes. #[error("{0}")] InternalNetworkError(String), #[error("{0}")] SyncError(String), + // For example the state machine and SHC are out of sync. + #[error("{0}")] + InternalInconsistency(String), + #[error("{0}")] + Other(String), } diff --git a/crates/starknet_consensus_manager/Cargo.toml b/crates/starknet_consensus_manager/Cargo.toml index 88b13d65d1f..2a5481af01f 100644 --- a/crates/starknet_consensus_manager/Cargo.toml +++ b/crates/starknet_consensus_manager/Cargo.toml @@ -5,22 +5,36 @@ edition.workspace = true license.workspace = true repository.workspace = true +[features] +testing = [] + [lints] workspace = true [dependencies] +apollo_reverts.workspace = true async-trait.workspace = true futures.workspace = true -libp2p.workspace = true papyrus_config.workspace = true -papyrus_consensus.workspace = true -papyrus_consensus_orchestrator.workspace = true papyrus_network.workspace = true -papyrus_network_types.workspace = true papyrus_protobuf.workspace = true serde.workspace = true +starknet_api.workspace = true starknet_batcher_types.workspace = true +starknet_class_manager_types.workspace = true +starknet_consensus.workspace = true +starknet_consensus_orchestrator.workspace = true +starknet_infra_utils.workspace = true +starknet_l1_gas_price.workspace = true starknet_sequencer_infra.workspace = true +starknet_sequencer_metrics.workspace = true +starknet_state_sync_types.workspace = true tokio.workspace = true tracing.workspace = true validator.workspace = true + +[dev-dependencies] +mockall.workspace = true +rstest.workspace = true +starknet_batcher_types = { workspace = true, features = ["testing"] } +starknet_state_sync_types = { workspace = true, features = ["testing"] } diff --git a/crates/starknet_consensus_manager/src/config.rs b/crates/starknet_consensus_manager/src/config.rs index 84ca95dfd21..0ecca6499e0 100644 --- a/crates/starknet_consensus_manager/src/config.rs +++ b/crates/starknet_consensus_manager/src/config.rs @@ -1,23 +1,87 @@ use std::collections::BTreeMap; -use papyrus_config::dumping::{append_sub_config_name, SerializeConfig}; -use papyrus_config::{ParamPath, SerializedParam}; -use papyrus_consensus::config::ConsensusConfig; +use apollo_reverts::RevertConfig; +use papyrus_config::dumping::{append_sub_config_name, ser_param, SerializeConfig}; +use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; +use papyrus_network::NetworkConfig; use serde::{Deserialize, Serialize}; +use starknet_api::block::BlockNumber; +use starknet_consensus::config::ConsensusConfig; +use starknet_consensus_orchestrator::cende::CendeConfig; +use starknet_consensus_orchestrator::config::ContextConfig; +use starknet_l1_gas_price::eth_to_strk_oracle::EthToStrkOracleConfig; use validator::Validate; /// The consensus manager related configuration. -/// TODO(Matan): Remove ConsensusManagerConfig if it's only field remains ConsensusConfig. -#[derive(Clone, Default, Debug, Serialize, Deserialize, Validate, PartialEq)] +#[derive(Clone, Debug, Serialize, Deserialize, Validate, PartialEq)] pub struct ConsensusManagerConfig { pub consensus_config: ConsensusConfig, + pub context_config: ContextConfig, + pub eth_to_strk_oracle_config: EthToStrkOracleConfig, + #[validate] + pub network_config: NetworkConfig, + pub cende_config: CendeConfig, + pub revert_config: RevertConfig, + pub votes_topic: String, + pub proposals_topic: String, + pub broadcast_buffer_size: usize, + pub immediate_active_height: BlockNumber, } impl SerializeConfig for ConsensusManagerConfig { fn dump(&self) -> BTreeMap { - let sub_configs = - vec![append_sub_config_name(self.consensus_config.dump(), "consensus_config")]; + let mut config = BTreeMap::from_iter([ + ser_param( + "votes_topic", + &self.votes_topic, + "The topic for consensus votes.", + ParamPrivacyInput::Public, + ), + ser_param( + "proposals_topic", + &self.proposals_topic, + "The topic for consensus proposals.", + ParamPrivacyInput::Public, + ), + ser_param( + "broadcast_buffer_size", + &self.broadcast_buffer_size, + "The buffer size for the broadcast channel.", + ParamPrivacyInput::Public, + ), + ser_param( + "immediate_active_height", + &self.immediate_active_height, + "The height at which the node may actively participate in consensus.", + ParamPrivacyInput::Public, + ), + ]); + config.extend(append_sub_config_name(self.consensus_config.dump(), "consensus_config")); + config.extend(append_sub_config_name(self.context_config.dump(), "context_config")); + config.extend(append_sub_config_name( + self.eth_to_strk_oracle_config.dump(), + "eth_to_strk_oracle_config", + )); + config.extend(append_sub_config_name(self.cende_config.dump(), "cende_config")); + config.extend(append_sub_config_name(self.network_config.dump(), "network_config")); + config.extend(append_sub_config_name(self.revert_config.dump(), "revert_config")); + config + } +} - sub_configs.into_iter().flatten().collect() +impl Default for ConsensusManagerConfig { + fn default() -> Self { + ConsensusManagerConfig { + consensus_config: ConsensusConfig::default(), + context_config: ContextConfig::default(), + eth_to_strk_oracle_config: EthToStrkOracleConfig::default(), + cende_config: CendeConfig::default(), + network_config: NetworkConfig::default(), + revert_config: RevertConfig::default(), + votes_topic: "consensus_votes".to_string(), + proposals_topic: "consensus_proposals".to_string(), + broadcast_buffer_size: 10000, + immediate_active_height: BlockNumber::default(), + } } } diff --git a/crates/starknet_consensus_manager/src/consensus_manager.rs b/crates/starknet_consensus_manager/src/consensus_manager.rs index 1ee091bff29..d2b0f03cbd1 100644 --- a/crates/starknet_consensus_manager/src/consensus_manager.rs +++ b/crates/starknet_consensus_manager/src/consensus_manager.rs @@ -1,115 +1,224 @@ -use std::any::type_name; +#[cfg(test)] +#[path = "consensus_manager_test.rs"] +mod consensus_manager_test; + +use std::collections::HashMap; use std::sync::Arc; +use apollo_reverts::revert_blocks_and_eternal_pending; use async_trait::async_trait; -use futures::channel::mpsc::{self, SendError}; -use futures::future::Ready; -use futures::SinkExt; -use libp2p::PeerId; -use papyrus_consensus::types::{BroadcastConsensusMessageChannel, ConsensusError}; -use papyrus_consensus_orchestrator::sequencer_consensus_context::SequencerConsensusContext; +use futures::channel::mpsc; use papyrus_network::gossipsub_impl::Topic; -use papyrus_network::network_manager::{BroadcastTopicClient, NetworkManager}; -use papyrus_network_types::network_types::BroadcastedMessageMetadata; -use papyrus_protobuf::consensus::{ConsensusMessage, ProposalPart}; +use papyrus_network::network_manager::metrics::{BroadcastNetworkMetrics, NetworkMetrics}; +use papyrus_network::network_manager::{BroadcastTopicChannels, NetworkManager}; +use papyrus_protobuf::consensus::{HeightAndRound, ProposalPart, StreamMessage, Vote}; +use starknet_api::block::BlockNumber; +use starknet_batcher_types::batcher_types::RevertBlockInput; use starknet_batcher_types::communication::SharedBatcherClient; +use starknet_class_manager_types::SharedClassManagerClient; +use starknet_consensus::stream_handler::{StreamHandler, CHANNEL_BUFFER_LENGTH}; +use starknet_consensus::types::ConsensusError; +use starknet_consensus_orchestrator::cende::CendeAmbassador; +use starknet_consensus_orchestrator::sequencer_consensus_context::SequencerConsensusContext; +use starknet_infra_utils::type_name::short_type_name; +use starknet_l1_gas_price::eth_to_strk_oracle::EthToStrkOracleClient; use starknet_sequencer_infra::component_definitions::ComponentStarter; -use starknet_sequencer_infra::errors::ComponentError; -use tracing::{error, info}; +use starknet_state_sync_types::communication::SharedStateSyncClient; +use tracing::info; use crate::config::ConsensusManagerConfig; - -// TODO(Dan, Guy): move to config. -pub const BROADCAST_BUFFER_SIZE: usize = 100; -pub const NETWORK_TOPIC: &str = "consensus_proposals"; +use crate::metrics::{ + CONSENSUS_NUM_BLACKLISTED_PEERS, + CONSENSUS_NUM_CONNECTED_PEERS, + CONSENSUS_PROPOSALS_NUM_RECEIVED_MESSAGES, + CONSENSUS_PROPOSALS_NUM_SENT_MESSAGES, + CONSENSUS_VOTES_NUM_RECEIVED_MESSAGES, + CONSENSUS_VOTES_NUM_SENT_MESSAGES, +}; #[derive(Clone)] pub struct ConsensusManager { pub config: ConsensusManagerConfig, pub batcher_client: SharedBatcherClient, + pub state_sync_client: SharedStateSyncClient, + pub class_manager_client: SharedClassManagerClient, } impl ConsensusManager { - pub fn new(config: ConsensusManagerConfig, batcher_client: SharedBatcherClient) -> Self { - Self { config, batcher_client } + pub fn new( + config: ConsensusManagerConfig, + batcher_client: SharedBatcherClient, + state_sync_client: SharedStateSyncClient, + class_manager_client: SharedClassManagerClient, + ) -> Self { + Self { config, batcher_client, state_sync_client, class_manager_client } } pub async fn run(&self) -> Result<(), ConsensusError> { + if self.config.revert_config.should_revert { + self.revert_batcher_blocks(self.config.revert_config.revert_up_to_and_including).await; + } + + let mut broadcast_metrics_by_topic = HashMap::new(); + broadcast_metrics_by_topic.insert( + Topic::new(self.config.votes_topic.clone()).hash(), + BroadcastNetworkMetrics { + num_sent_broadcast_messages: CONSENSUS_VOTES_NUM_SENT_MESSAGES, + num_received_broadcast_messages: CONSENSUS_VOTES_NUM_RECEIVED_MESSAGES, + }, + ); + broadcast_metrics_by_topic.insert( + Topic::new(self.config.proposals_topic.clone()).hash(), + BroadcastNetworkMetrics { + num_sent_broadcast_messages: CONSENSUS_PROPOSALS_NUM_SENT_MESSAGES, + num_received_broadcast_messages: CONSENSUS_PROPOSALS_NUM_RECEIVED_MESSAGES, + }, + ); + let network_manager_metrics = Some(NetworkMetrics { + num_connected_peers: CONSENSUS_NUM_CONNECTED_PEERS, + num_blacklisted_peers: CONSENSUS_NUM_BLACKLISTED_PEERS, + broadcast_metrics_by_topic: Some(broadcast_metrics_by_topic), + sqmr_metrics: None, + }); let mut network_manager = - NetworkManager::new(self.config.consensus_config.network_config.clone(), None); + NetworkManager::new(self.config.network_config.clone(), None, network_manager_metrics); + let proposals_broadcast_channels = network_manager - .register_broadcast_topic::( - Topic::new(NETWORK_TOPIC), - BROADCAST_BUFFER_SIZE, + .register_broadcast_topic::>( + Topic::new(self.config.proposals_topic.clone()), + self.config.broadcast_buffer_size, ) .expect("Failed to register broadcast topic"); + + let votes_broadcast_channels = network_manager + .register_broadcast_topic::( + Topic::new(self.config.votes_topic.clone()), + self.config.broadcast_buffer_size, + ) + .expect("Failed to register broadcast topic"); + + let BroadcastTopicChannels { + broadcasted_messages_receiver: inbound_network_receiver, + broadcast_topic_client: outbound_network_sender, + } = proposals_broadcast_channels; + + let (inbound_internal_sender, inbound_internal_receiver) = + mpsc::channel(CHANNEL_BUFFER_LENGTH); + let (outbound_internal_sender, outbound_internal_receiver) = + mpsc::channel(CHANNEL_BUFFER_LENGTH); + let stream_handler = StreamHandler::new( + inbound_internal_sender, + inbound_network_receiver, + outbound_internal_receiver, + outbound_network_sender, + ); + + let observer_height = self + .batcher_client + .get_height() + .await + .expect("Failed to get observer_height from batcher") + .height; + let active_height = if self.config.immediate_active_height == observer_height { + // Setting `start_height` is only used to enable consensus starting immediately without + // observing the first height. This means consensus may return to a height + // it has already voted on, risking equivocation. This is only safe to do if we + // restart all nodes at this height. + observer_height + } else { + BlockNumber(observer_height.0 + 1) + }; + let context = SequencerConsensusContext::new( + self.config.context_config.clone(), + Arc::clone(&self.class_manager_client), + Arc::clone(&self.state_sync_client), Arc::clone(&self.batcher_client), - proposals_broadcast_channels.broadcast_topic_client.clone(), - self.config.consensus_config.num_validators, + outbound_internal_sender, + votes_broadcast_channels.broadcast_topic_client.clone(), + Arc::new(CendeAmbassador::new( + self.config.cende_config.clone(), + Arc::clone(&self.class_manager_client), + )), + Some(Arc::new(EthToStrkOracleClient::new( + self.config.eth_to_strk_oracle_config.base_url.clone(), + self.config.eth_to_strk_oracle_config.headers.clone(), + ))), ); - let mut network_handle = tokio::task::spawn(network_manager.run()); - let consensus_task = papyrus_consensus::run_consensus( + let network_task = tokio::spawn(network_manager.run()); + let stream_handler_task = tokio::spawn(stream_handler.run()); + let consensus_fut = starknet_consensus::run_consensus( context, - self.config.consensus_config.start_height, + active_height, + observer_height, self.config.consensus_config.validator_id, - self.config.consensus_config.consensus_delay, + self.config.consensus_config.startup_delay, self.config.consensus_config.timeouts.clone(), - create_fake_network_channels(), - futures::stream::pending(), + self.config.consensus_config.sync_retry_interval, + votes_broadcast_channels.into(), + inbound_internal_receiver, ); tokio::select! { - consensus_result = consensus_task => { + consensus_result = consensus_fut => { match consensus_result { Ok(_) => panic!("Consensus task finished unexpectedly"), Err(e) => Err(e), } }, - network_result = &mut network_handle => { + network_result = network_task => { panic!("Consensus' network task finished unexpectedly: {:?}", network_result); } + stream_handler_result = stream_handler_task => { + panic!("Consensus' stream handler task finished unexpectedly: {:?}", stream_handler_result); + } } } -} -// Milestone 1: -// We want to only run 1 node (e.g. no network), implying the local node can reach a quorum -// alone and is always the proposer. Actually connecting to the network will require an external -// dependency. -fn create_fake_network_channels() -> BroadcastConsensusMessageChannel { - let messages_to_broadcast_fn: fn(ConsensusMessage) -> Ready, SendError>> = - |_| todo!("messages_to_broadcast_sender should not be used"); - let reported_messages_sender_fn: fn( - BroadcastedMessageMetadata, - ) -> Ready> = - |_| todo!("messages_to_broadcast_sender should not be used"); - let broadcast_topic_client = BroadcastTopicClient::new( - mpsc::channel(0).0.with(messages_to_broadcast_fn), - mpsc::channel(0).0.with(reported_messages_sender_fn), - mpsc::channel(0).0, - ); - BroadcastConsensusMessageChannel { - broadcasted_messages_receiver: Box::new(futures::stream::pending()), - broadcast_topic_client, + // Performs reverts to the batcher. + async fn revert_batcher_blocks(&self, revert_up_to_and_including: BlockNumber) { + // If we revert all blocks up to height X (including), the new height marker will be X. + let batcher_height_marker = self + .batcher_client + .get_height() + .await + .expect("Failed to get batcher_height_marker from batcher") + .height; + + // This function will panic if the revert fails. + let revert_blocks_fn = move |height| async move { + self.batcher_client + .revert_block(RevertBlockInput { height }) + .await + .expect("Failed to revert block at height {height} in the batcher"); + }; + + revert_blocks_and_eternal_pending( + batcher_height_marker, + revert_up_to_and_including, + revert_blocks_fn, + "Batcher", + ) + .await; } } pub fn create_consensus_manager( config: ConsensusManagerConfig, batcher_client: SharedBatcherClient, + state_sync_client: SharedStateSyncClient, + class_manager_client: SharedClassManagerClient, ) -> ConsensusManager { - ConsensusManager::new(config, batcher_client) + ConsensusManager::new(config, batcher_client, state_sync_client, class_manager_client) } #[async_trait] impl ComponentStarter for ConsensusManager { - async fn start(&mut self) -> Result<(), ComponentError> { - info!("Starting component {}.", type_name::()); - self.run().await.map_err(|e| { - error!("Error running component ConsensusManager: {:?}", e); - ComponentError::InternalComponentError - }) + async fn start(&mut self) { + info!("Starting component {}.", short_type_name::()); + self.run() + .await + .unwrap_or_else(|e| panic!("Failed to start ConsensusManager component: {:?}", e)) } } diff --git a/crates/starknet_consensus_manager/src/consensus_manager_test.rs b/crates/starknet_consensus_manager/src/consensus_manager_test.rs new file mode 100644 index 00000000000..7008c54cbe2 --- /dev/null +++ b/crates/starknet_consensus_manager/src/consensus_manager_test.rs @@ -0,0 +1,98 @@ +use std::sync::Arc; + +use apollo_reverts::RevertConfig; +use mockall::predicate::eq; +use rstest::rstest; +use starknet_api::block::BlockNumber; +use starknet_batcher_types::batcher_types::{GetHeightResponse, RevertBlockInput}; +use starknet_batcher_types::communication::MockBatcherClient; +use starknet_class_manager_types::EmptyClassManagerClient; +use starknet_state_sync_types::communication::MockStateSyncClient; +use tokio::time::{timeout, Duration}; + +use crate::config::ConsensusManagerConfig; +use crate::consensus_manager::ConsensusManager; + +const BATCHER_HEIGHT: BlockNumber = BlockNumber(10); + +#[tokio::test] +async fn revert_batcher_blocks() { + const REVERT_UP_TO_AND_INCLUDING_HEIGHT: BlockNumber = BlockNumber(7); + + let mut mock_batcher_client = MockBatcherClient::new(); + mock_batcher_client + .expect_get_height() + .returning(|| Ok(GetHeightResponse { height: BATCHER_HEIGHT })); + + let expected_revert_heights = + (REVERT_UP_TO_AND_INCLUDING_HEIGHT.0..BATCHER_HEIGHT.0).rev().map(BlockNumber); + for height in expected_revert_heights { + mock_batcher_client + .expect_revert_block() + .times(1) + .with(eq(RevertBlockInput { height })) + .returning(|_| Ok(())); + } + + let manager_config = ConsensusManagerConfig { + revert_config: RevertConfig { + revert_up_to_and_including: REVERT_UP_TO_AND_INCLUDING_HEIGHT, + should_revert: true, + }, + ..Default::default() + }; + + let consensus_manager = ConsensusManager::new( + manager_config, + Arc::new(mock_batcher_client), + Arc::new(MockStateSyncClient::new()), + Arc::new(EmptyClassManagerClient), + ); + + // TODO(Shahak, dvir): try to solve this better (the test will take 100 milliseconds to run). + timeout(Duration::from_millis(100), consensus_manager.run()).await.unwrap_err(); +} + +#[rstest] +#[should_panic(expected = "Batcher's storage height marker 10 is not larger than the target \ + height marker 10. No reverts are needed.")] +#[case::equal_block(BATCHER_HEIGHT)] +#[should_panic(expected = "Batcher's storage height marker 10 is not larger than the target \ + height marker 11. No reverts are needed.")] +#[case::larger_block(BATCHER_HEIGHT.unchecked_next())] +#[tokio::test] +async fn revert_with_invalid_height_panics(#[case] revert_up_to_and_including: BlockNumber) { + let mut mock_batcher = MockBatcherClient::new(); + mock_batcher.expect_get_height().returning(|| Ok(GetHeightResponse { height: BATCHER_HEIGHT })); + + let consensus_manager_config = ConsensusManagerConfig { + revert_config: RevertConfig { revert_up_to_and_including, should_revert: true }, + ..Default::default() + }; + + let consensus_manager = ConsensusManager::new( + consensus_manager_config, + Arc::new(mock_batcher), + Arc::new(MockStateSyncClient::new()), + Arc::new(EmptyClassManagerClient), + ); + + consensus_manager.run().await.unwrap(); +} + +#[tokio::test] +async fn no_reverts_without_config() { + let mut mock_batcher = MockBatcherClient::new(); + mock_batcher.expect_revert_block().times(0).returning(|_| Ok(())); + mock_batcher.expect_get_height().returning(|| Ok(GetHeightResponse { height: BlockNumber(0) })); + + let consensus_manager = ConsensusManager::new( + ConsensusManagerConfig::default(), + Arc::new(mock_batcher), + Arc::new(MockStateSyncClient::new()), + Arc::new(EmptyClassManagerClient), + ); + + // TODO(Shahak, dvir): try to solve this better (the test will take 100 milliseconds to run). + timeout(Duration::from_millis(100), consensus_manager.run()).await.unwrap_err(); +} diff --git a/crates/starknet_consensus_manager/src/lib.rs b/crates/starknet_consensus_manager/src/lib.rs index eac2096a6e0..97eda850bbd 100644 --- a/crates/starknet_consensus_manager/src/lib.rs +++ b/crates/starknet_consensus_manager/src/lib.rs @@ -1,3 +1,4 @@ pub mod communication; pub mod config; pub mod consensus_manager; +pub mod metrics; diff --git a/crates/starknet_consensus_manager/src/metrics.rs b/crates/starknet_consensus_manager/src/metrics.rs new file mode 100644 index 00000000000..d47b5d5c451 --- /dev/null +++ b/crates/starknet_consensus_manager/src/metrics.rs @@ -0,0 +1,19 @@ +use starknet_sequencer_metrics::define_metrics; +use starknet_sequencer_metrics::metrics::{MetricCounter, MetricGauge}; + +define_metrics!( + Consensus => { + // topic agnostic metrics + MetricGauge { CONSENSUS_NUM_CONNECTED_PEERS, "apollo_consensus_num_connected_peers", "The number of connected peers to the consensus p2p component" }, + MetricGauge { CONSENSUS_NUM_BLACKLISTED_PEERS, "apollo_consensus_num_blacklisted_peers", "The number of currently blacklisted peers by the consensus component" }, + + // Votes topic metrics + MetricCounter { CONSENSUS_VOTES_NUM_SENT_MESSAGES, "apollo_consensus_votes_num_sent_messages", "The number of messages sent by the consensus p2p component over the Votes topic", init = 0 }, + MetricCounter { CONSENSUS_VOTES_NUM_RECEIVED_MESSAGES, "apollo_consensus_votes_num_received_messages", "The number of messages received by the consensus p2p component over the Votes topic", init = 0 }, + + // Proposals topic metrics + MetricCounter { CONSENSUS_PROPOSALS_NUM_SENT_MESSAGES, "apollo_consensus_proposals_num_sent_messages", "The number of messages sent by the consensus p2p component over the Proposals topic", init = 0 }, + MetricCounter { CONSENSUS_PROPOSALS_NUM_RECEIVED_MESSAGES, "apollo_consensus_proposals_num_received_messages", "The number of messages received by the consensus p2p component over the Proposals topic", init = 0 }, + + }, +); diff --git a/crates/starknet_consensus_orchestrator/Cargo.toml b/crates/starknet_consensus_orchestrator/Cargo.toml new file mode 100644 index 00000000000..9336fe12fed --- /dev/null +++ b/crates/starknet_consensus_orchestrator/Cargo.toml @@ -0,0 +1,68 @@ +[package] +name = "starknet_consensus_orchestrator" +version.workspace = true +edition.workspace = true +repository.workspace = true +license-file.workspace = true +description = "Implements the consensus context and orchestrates the node's components accordingly" + +[dependencies] +async-trait.workspace = true +cairo-lang-starknet-classes.workspace = true +blockifier.workspace = true +chrono.workspace = true +futures.workspace = true +indexmap.workspace = true +papyrus_config.workspace = true +papyrus_network.workspace = true +papyrus_protobuf.workspace = true +paste.workspace = true +reqwest = { workspace = true, features = ["json"] } +serde.workspace = true +serde_json = { workspace = true, features = ["arbitrary_precision"] } +shared_execution_objects.workspace = true +starknet-types-core.workspace = true +starknet_api.workspace = true +starknet_batcher_types.workspace = true +starknet_class_manager_types.workspace = true +starknet_consensus.workspace = true +starknet_infra_utils.workspace = true +starknet_l1_gas_price_types.workspace = true +starknet_sequencer_metrics.workspace = true +starknet_state_sync_types.workspace = true +thiserror.workspace = true +tokio = { workspace = true, features = ["full"] } +tokio-util = { workspace = true, features = ["rt"] } +tracing.workspace = true +url = { workspace = true, features = ["serde"] } +validator.workspace = true + +[dev-dependencies] +cairo-lang-casm.workspace = true +cairo-lang-utils.workspace = true +cairo-vm.workspace = true +lazy_static.workspace = true +mockall.workspace = true +mockito.workspace = true +num-bigint.workspace = true +papyrus_network = { workspace = true, features = ["testing"] } +papyrus_storage = { workspace = true, features = ["testing"] } +papyrus_test_utils.workspace = true +rstest.workspace = true +serde_json.workspace = true +starknet_batcher_types = { workspace = true, features = ["testing"] } +starknet_batcher.workspace = true +starknet_class_manager_types = { workspace = true, features = ["testing"] } +starknet_infra_utils = { workspace = true, features = ["testing"] } +starknet_l1_gas_price_types = { workspace = true, features = ["testing"] } +starknet_state_sync_types = { workspace = true, features = ["testing"] } + +[lints] +workspace = true + +[package.metadata.cargo-machete] +# `paste`, `starknet_infra_utils` are used in the `define_versioned_constants!` macro but may be falsely detected as unused. +ignored = ["paste", "starknet_infra_utils"] + +[features] +testing = [] diff --git a/crates/starknet_consensus_orchestrator/resources/central_blob.json b/crates/starknet_consensus_orchestrator/resources/central_blob.json new file mode 100644 index 00000000000..db79dc697e3 --- /dev/null +++ b/crates/starknet_consensus_orchestrator/resources/central_blob.json @@ -0,0 +1,1017 @@ +{ + "block_number": 5, + "state_diff": { + "address_to_class_hash": { + "0x1": "0x1", + "0x5": "0x5" + }, + "nonces": { + "L1": { + "0x2": "0x2" + } + }, + "storage_updates": { + "L1": { + "0x3": { + "0x3": "0x3" + } + } + }, + "declared_classes": { + "0x4": "0x4" + }, + "block_info": { + "block_number": 5, + "block_timestamp": 6, + "sequencer_address": "0x7", + "l1_gas_price": { + "price_in_wei": "0x8", + "price_in_fri": "0x9" + }, + "l1_data_gas_price": { + "price_in_wei": "0xa", + "price_in_fri": "0xb" + }, + "l2_gas_price": { + "price_in_wei": "0xc", + "price_in_fri": "0xd" + }, + "use_kzg_da": true, + "starknet_version": "0.14.0" + } + }, + "compressed_state_diff": { + "address_to_class_hash": { + "0x1": "0x1", + "0x5": "0x5" + }, + "nonces": { + "L1": { + "0x2": "0x2" + } + }, + "storage_updates": { + "L1": { + "0x3": { + "0x3": "0x3" + } + } + }, + "declared_classes": { + "0x4": "0x4" + }, + "block_info": { + "block_number": 5, + "block_timestamp": 6, + "sequencer_address": "0x7", + "l1_gas_price": { + "price_in_wei": "0x8", + "price_in_fri": "0x9" + }, + "l1_data_gas_price": { + "price_in_wei": "0xa", + "price_in_fri": "0xb" + }, + "l2_gas_price": { + "price_in_wei": "0xc", + "price_in_fri": "0xd" + }, + "use_kzg_da": true, + "starknet_version": "0.14.0" + } + }, + "bouncer_weights": { + "l1_gas": 8, + "message_segment_length": 9, + "n_events": 2, + "state_diff_size": 45, + "sierra_gas": 10 + }, + "fee_market_info": { + "l2_gas_consumed": 150000, + "next_l2_gas_price": 100000 + }, + "transactions": [ + { + "tx": { + "type": "DECLARE", + "version": "0x3", + "resource_bounds": { + "L1_GAS": { + "max_amount": "0x1", + "max_price_per_unit": "0x1" + }, + "L2_GAS": { + "max_amount": "0x2", + "max_price_per_unit": "0x2" + }, + "L1_DATA_GAS": { + "max_amount": "0x3", + "max_price_per_unit": "0x3" + } + }, + "tip": "0x1", + "signature": [ + "0x0", + "0x1", + "0x2" + ], + "nonce": "0x1", + "class_hash": "0x3a59046762823dc87385eb5ac8a21f3f5bfe4274151c6eb633737656c209056", + "compiled_class_hash": "0x1", + "sender_address": "0x12fd537", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "paymaster_data": [], + "account_deployment_data": [], + "sierra_program_size": 3, + "abi_size": 9, + "sierra_version": [ + "0x0", + "0x1", + "0x0" + ], + "hash_value": "0x1" + }, + "time_created": 6 + }, + { + "tx": { + "type": "INVOKE_FUNCTION", + "version": "0x3", + "resource_bounds": { + "L1_GAS": { + "max_amount": "0x1", + "max_price_per_unit": "0x1" + }, + "L2_GAS": { + "max_amount": "0x2", + "max_price_per_unit": "0x2" + }, + "L1_DATA_GAS": { + "max_amount": "0x3", + "max_price_per_unit": "0x3" + } + }, + "tip": "0x1", + "signature": [ + "0x0", + "0x1", + "0x2" + ], + "nonce": "0x1", + "sender_address": "0x14abfd58671a1a9b30de2fcd2a42e8bff2ce1096a7c70bc7995904965f277e", + "calldata": [ + "0x0", + "0x1" + ], + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "paymaster_data": [], + "account_deployment_data": [], + "hash_value": "0x2" + }, + "time_created": 6 + }, + { + "tx": { + "type": "DEPLOY_ACCOUNT", + "version": "0x3", + "resource_bounds": { + "L1_GAS": { + "max_amount": "0x1", + "max_price_per_unit": "0x1" + }, + "L2_GAS": { + "max_amount": "0x2", + "max_price_per_unit": "0x2" + }, + "L1_DATA_GAS": { + "max_amount": "0x3", + "max_price_per_unit": "0x3" + } + }, + "tip": "0x1", + "signature": [ + "0x0", + "0x1", + "0x2" + ], + "nonce": "0x1", + "class_hash": "0x1b5a0b09f23b091d5d1fa2f660ddfad6bcfce607deba23806cd7328ccfb8ee9", + "contract_address_salt": "0x2", + "sender_address": "0x4c2e031b0ddaa38e06fd9b1bf32bff739965f9d64833006204c67cbc879a57c", + "constructor_calldata": [ + "0x0", + "0x1", + "0x2" + ], + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "paymaster_data": [], + "hash_value": "0x3" + }, + "time_created": 6 + }, + { + "tx": { + "type": "L1_HANDLER", + "contract_address": "0x14abfd58671a1a9b30de2fcd2a42e8bff2ce1096a7c70bc7995904965f277e", + "entry_point_selector": "0x2a", + "calldata": [ + "0x0", + "0x1" + ], + "nonce": "0x1", + "paid_fee_on_l1": "0x1", + "hash_value": "0xc947753befd252ca08042000cd6d783162ee2f5df87b519ddf3081b9b4b997" + }, + "time_created": 6 + }, + { + "tx": { + "type": "DECLARE", + "version": "0x3", + "resource_bounds": { + "L1_GAS": { + "max_amount": "0x1", + "max_price_per_unit": "0x1" + }, + "L2_GAS": { + "max_amount": "0x2", + "max_price_per_unit": "0x2" + }, + "L1_DATA_GAS": { + "max_amount": "0x3", + "max_price_per_unit": "0x3" + } + }, + "tip": "0x1", + "signature": [ + "0x0", + "0x1", + "0x2" + ], + "nonce": "0x1", + "class_hash": "0x3a59046762823dc87385eb5ac8a21f3f5bfe4274151c6eb633737656c209056", + "compiled_class_hash": "0x1", + "sender_address": "0x12fd537", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "paymaster_data": [], + "account_deployment_data": [], + "sierra_program_size": 3, + "abi_size": 9, + "sierra_version": [ + "0x0", + "0x1", + "0x0" + ], + "hash_value": "0x4" + }, + "time_created": 6 + } + ], + "execution_infos": [ + { + "validate_call_info": { + "call": { + "class_hash": "0x80020000", + "code_address": "0x40070000", + "entry_point_type": "EXTERNAL", + "entry_point_selector": "0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775", + "calldata": [ + "0x40070000", + "0x39a1491f76903a16feed0a6433bec78de4c73194944e1118e226820ad479701", + "0x1", + "0x2" + ], + "storage_address": "0xc0020000", + "caller_address": "0x1", + "call_type": "Call", + "initial_gas": 100000000 + }, + "execution": { + "retdata": [ + "0x56414c4944" + ], + "events": [ + { + "order": 2, + "event": { + "keys": [ + "0x9" + ], + "data": [ + "0x0", + "0x1", + "0x2" + ] + } + } + ], + "l2_to_l1_messages": [ + { + "order": 1, + "message": { + "to_address": "0x1", + "payload": [ + "0x0", + "0x1", + "0x2" + ] + } + } + ], + "failed": false, + "gas_consumed": 11690 + }, + "inner_calls": [ + { + "call": { + "class_hash": "0x80020000", + "code_address": "0x40070000", + "entry_point_type": "EXTERNAL", + "entry_point_selector": "0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775", + "calldata": [ + "0x40070000", + "0x39a1491f76903a16feed0a6433bec78de4c73194944e1118e226820ad479701", + "0x1", + "0x2" + ], + "storage_address": "0xc0020000", + "caller_address": "0x1", + "call_type": "Call", + "initial_gas": 100000000 + }, + "execution": { + "retdata": [ + "0x56414c4944" + ], + "events": [ + { + "order": 2, + "event": { + "keys": [ + "0x9" + ], + "data": [ + "0x0", + "0x1", + "0x2" + ] + } + } + ], + "l2_to_l1_messages": [ + { + "order": 1, + "message": { + "to_address": "0x1", + "payload": [ + "0x0", + "0x1", + "0x2" + ] + } + } + ], + "failed": false, + "gas_consumed": 11690 + }, + "inner_calls": [], + "resources": { + "n_steps": 2, + "n_memory_holes": 3, + "builtin_instance_counter": { + "range_check_builtin": 31, + "pedersen_builtin": 4 + } + }, + "tracked_resource": "SierraGas", + "storage_access_tracker": { + "storage_read_values": [ + "0x0", + "0x1", + "0x2" + ], + "accessed_storage_keys": [ + "0x1" + ], + "read_class_hash_values": [ + "0x80020000" + ], + "accessed_contract_addresses": [ + "0x1" + ], + "read_block_hash_values": [ + "0xdeafbee" + ], + "accessed_blocks": [ + 100 + ] + } + } + ], + "resources": { + "n_steps": 2, + "n_memory_holes": 3, + "builtin_instance_counter": { + "pedersen_builtin": 4, + "range_check_builtin": 31 + } + }, + "tracked_resource": "SierraGas", + "storage_access_tracker": { + "storage_read_values": [ + "0x0", + "0x1", + "0x2" + ], + "accessed_storage_keys": [ + "0x1" + ], + "read_class_hash_values": [ + "0x80020000" + ], + "accessed_contract_addresses": [ + "0x1" + ], + "read_block_hash_values": [ + "0xdeafbee" + ], + "accessed_blocks": [ + 100 + ] + } + }, + "execute_call_info": { + "call": { + "class_hash": "0x80020000", + "code_address": "0x40070000", + "entry_point_type": "EXTERNAL", + "entry_point_selector": "0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775", + "calldata": [ + "0x40070000", + "0x39a1491f76903a16feed0a6433bec78de4c73194944e1118e226820ad479701", + "0x1", + "0x2" + ], + "storage_address": "0xc0020000", + "caller_address": "0x1", + "call_type": "Call", + "initial_gas": 100000000 + }, + "execution": { + "retdata": [ + "0x56414c4944" + ], + "events": [ + { + "order": 2, + "event": { + "keys": [ + "0x9" + ], + "data": [ + "0x0", + "0x1", + "0x2" + ] + } + } + ], + "l2_to_l1_messages": [ + { + "order": 1, + "message": { + "to_address": "0x1", + "payload": [ + "0x0", + "0x1", + "0x2" + ] + } + } + ], + "failed": false, + "gas_consumed": 11690 + }, + "inner_calls": [ + { + "call": { + "class_hash": "0x80020000", + "code_address": "0x40070000", + "entry_point_type": "EXTERNAL", + "entry_point_selector": "0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775", + "calldata": [ + "0x40070000", + "0x39a1491f76903a16feed0a6433bec78de4c73194944e1118e226820ad479701", + "0x1", + "0x2" + ], + "storage_address": "0xc0020000", + "caller_address": "0x1", + "call_type": "Call", + "initial_gas": 100000000 + }, + "execution": { + "retdata": [ + "0x56414c4944" + ], + "events": [ + { + "order": 2, + "event": { + "keys": [ + "0x9" + ], + "data": [ + "0x0", + "0x1", + "0x2" + ] + } + } + ], + "l2_to_l1_messages": [ + { + "order": 1, + "message": { + "to_address": "0x1", + "payload": [ + "0x0", + "0x1", + "0x2" + ] + } + } + ], + "failed": false, + "gas_consumed": 11690 + }, + "inner_calls": [], + "resources": { + "n_steps": 2, + "n_memory_holes": 3, + "builtin_instance_counter": { + "pedersen_builtin": 4, + "range_check_builtin": 31 + } + }, + "tracked_resource": "SierraGas", + "storage_access_tracker": { + "storage_read_values": [ + "0x0", + "0x1", + "0x2" + ], + "accessed_storage_keys": [ + "0x1" + ], + "read_class_hash_values": [ + "0x80020000" + ], + "accessed_contract_addresses": [ + "0x1" + ], + "read_block_hash_values": [ + "0xdeafbee" + ], + "accessed_blocks": [ + 100 + ] + } + } + ], + "resources": { + "n_steps": 2, + "n_memory_holes": 3, + "builtin_instance_counter": { + "range_check_builtin": 31, + "pedersen_builtin": 4 + } + }, + "tracked_resource": "SierraGas", + "storage_access_tracker": { + "storage_read_values": [ + "0x0", + "0x1", + "0x2" + ], + "accessed_storage_keys": [ + "0x1" + ], + "read_class_hash_values": [ + "0x80020000" + ], + "accessed_contract_addresses": [ + "0x1" + ], + "read_block_hash_values": [ + "0xdeafbee" + ], + "accessed_blocks": [ + 100 + ] + } + }, + "fee_transfer_call_info": { + "call": { + "class_hash": "0x80020000", + "code_address": "0x40070000", + "entry_point_type": "EXTERNAL", + "entry_point_selector": "0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775", + "calldata": [ + "0x40070000", + "0x39a1491f76903a16feed0a6433bec78de4c73194944e1118e226820ad479701", + "0x1", + "0x2" + ], + "storage_address": "0xc0020000", + "caller_address": "0x1", + "call_type": "Call", + "initial_gas": 100000000 + }, + "execution": { + "retdata": [ + "0x56414c4944" + ], + "events": [ + { + "order": 2, + "event": { + "keys": [ + "0x9" + ], + "data": [ + "0x0", + "0x1", + "0x2" + ] + } + } + ], + "l2_to_l1_messages": [ + { + "order": 1, + "message": { + "to_address": "0x1", + "payload": [ + "0x0", + "0x1", + "0x2" + ] + } + } + ], + "failed": false, + "gas_consumed": 11690 + }, + "inner_calls": [ + { + "call": { + "class_hash": "0x80020000", + "code_address": "0x40070000", + "entry_point_type": "EXTERNAL", + "entry_point_selector": "0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775", + "calldata": [ + "0x40070000", + "0x39a1491f76903a16feed0a6433bec78de4c73194944e1118e226820ad479701", + "0x1", + "0x2" + ], + "storage_address": "0xc0020000", + "caller_address": "0x1", + "call_type": "Call", + "initial_gas": 100000000 + }, + "execution": { + "retdata": [ + "0x56414c4944" + ], + "events": [ + { + "order": 2, + "event": { + "keys": [ + "0x9" + ], + "data": [ + "0x0", + "0x1", + "0x2" + ] + } + } + ], + "l2_to_l1_messages": [ + { + "order": 1, + "message": { + "to_address": "0x1", + "payload": [ + "0x0", + "0x1", + "0x2" + ] + } + } + ], + "failed": false, + "gas_consumed": 11690 + }, + "inner_calls": [], + "resources": { + "n_steps": 2, + "n_memory_holes": 3, + "builtin_instance_counter": { + "range_check_builtin": 31, + "pedersen_builtin": 4 + } + }, + "tracked_resource": "SierraGas", + "storage_access_tracker": { + "storage_read_values": [ + "0x0", + "0x1", + "0x2" + ], + "accessed_storage_keys": [ + "0x1" + ], + "read_class_hash_values": [ + "0x80020000" + ], + "accessed_contract_addresses": [ + "0x1" + ], + "read_block_hash_values": [ + "0xdeafbee" + ], + "accessed_blocks": [ + 100 + ] + } + } + ], + "resources": { + "n_steps": 2, + "n_memory_holes": 3, + "builtin_instance_counter": { + "range_check_builtin": 31, + "pedersen_builtin": 4 + } + }, + "tracked_resource": "SierraGas", + "storage_access_tracker": { + "storage_read_values": [ + "0x0", + "0x1", + "0x2" + ], + "accessed_storage_keys": [ + "0x1" + ], + "read_class_hash_values": [ + "0x80020000" + ], + "accessed_contract_addresses": [ + "0x1" + ], + "read_block_hash_values": [ + "0xdeafbee" + ], + "accessed_blocks": [ + 100 + ] + } + }, + "actual_fee": "0x26fe9d250e000", + "da_gas": { + "l1_gas": 1652, + "l1_data_gas": 1, + "l2_gas": 1 + }, + "actual_resources": { + "n_steps": 7, + "range_check_builtin": 31, + "pedersen_builtin": 4 + }, + "revert_error": null, + "total_gas": { + "l1_gas": 6860, + "l1_data_gas": 1, + "l2_gas": 1 + } + } + ], + "contract_classes": [ + [ + "0x3a59046762823dc87385eb5ac8a21f3f5bfe4274151c6eb633737656c209056", + { + "contract_class": { + "sierra_program": [ + "0x0", + "0x1", + "0x2" + ], + "contract_class_version": "0.1.0", + "entry_points_by_type": { + "CONSTRUCTOR": [ + { + "function_idx": 1, + "selector": "0x2" + } + ], + "EXTERNAL": [ + { + "function_idx": 3, + "selector": "0x4" + } + ], + "L1_HANDLER": [ + { + "function_idx": 5, + "selector": "0x6" + } + ] + }, + "abi": "dummy abi" + } + } + ], + [ + "0x3a59046762823dc87385eb5ac8a21f3f5bfe4274151c6eb633737656c209056", + { + "contract_class": { + "sierra_program": [ + "0x0", + "0x1", + "0x2" + ], + "contract_class_version": "0.1.0", + "entry_points_by_type": { + "CONSTRUCTOR": [ + { + "function_idx": 1, + "selector": "0x2" + } + ], + "EXTERNAL": [ + { + "function_idx": 3, + "selector": "0x4" + } + ], + "L1_HANDLER": [ + { + "function_idx": 5, + "selector": "0x6" + } + ] + }, + "abi": "dummy abi" + } + } + ] + ], + "compiled_classes": [ + [ + "0x1", + { + "compiled_class": { + "prime": "0x1", + "compiler_version": "dummy version", + "bytecode": [ + "0x1" + ], + "bytecode_segment_lengths": [ + 1, + 2 + ], + "hints": [ + [ + 4, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 1 + } + } + } + ] + ] + ], + "pythonic_hints": [ + [ + 5, + [ + "dummy pythonic hint" + ] + ] + ], + "entry_points_by_type": { + "EXTERNAL": [ + { + "selector": "0x1", + "offset": 1, + "builtins": [ + "dummy builtin" + ] + } + ], + "L1_HANDLER": [ + { + "selector": "0x1", + "offset": 1, + "builtins": [ + "dummy builtin" + ] + } + ], + "CONSTRUCTOR": [ + { + "selector": "0x1", + "offset": 1, + "builtins": [ + "dummy builtin" + ] + } + ] + } + } + } + ], + [ + "0x1", + { + "compiled_class": { + "prime": "0x1", + "compiler_version": "dummy version", + "bytecode": [ + "0x1" + ], + "bytecode_segment_lengths": [ + 1, + 2 + ], + "hints": [ + [ + 4, + [ + { + "AllocSegment": { + "dst": { + "register": "AP", + "offset": 1 + } + } + } + ] + ] + ], + "pythonic_hints": [ + [ + 5, + [ + "dummy pythonic hint" + ] + ] + ], + "entry_points_by_type": { + "EXTERNAL": [ + { + "selector": "0x1", + "offset": 1, + "builtins": [ + "dummy builtin" + ] + } + ], + "L1_HANDLER": [ + { + "selector": "0x1", + "offset": 1, + "builtins": [ + "dummy builtin" + ] + } + ], + "CONSTRUCTOR": [ + { + "selector": "0x1", + "offset": 1, + "builtins": [ + "dummy builtin" + ] + } + ] + } + } + } + ] + ] +} \ No newline at end of file diff --git a/crates/starknet_consensus_orchestrator/resources/central_bouncer_weights.json b/crates/starknet_consensus_orchestrator/resources/central_bouncer_weights.json new file mode 100644 index 00000000000..e34f397f0c0 --- /dev/null +++ b/crates/starknet_consensus_orchestrator/resources/central_bouncer_weights.json @@ -0,0 +1,7 @@ +{ + "l1_gas": 8, + "message_segment_length": 9, + "n_events": 2, + "state_diff_size": 45, + "sierra_gas": 10 +} diff --git a/crates/starknet_consensus_orchestrator/resources/central_contract_class.casm.json b/crates/starknet_consensus_orchestrator/resources/central_contract_class.casm.json new file mode 100644 index 00000000000..d5bae0551b0 --- /dev/null +++ b/crates/starknet_consensus_orchestrator/resources/central_contract_class.casm.json @@ -0,0 +1,65 @@ +{ + "compiled_class":{ + "prime":"0x1", + "compiler_version":"dummy version", + "bytecode":[ + "0x1" + ], + "bytecode_segment_lengths":[ + 1, + 2 + ], + "hints":[ + [ + 4, + [ + { + "AllocSegment":{ + "dst":{ + "offset":1, + "register":"AP" + } + } + } + ] + ] + ], + "pythonic_hints":[ + [ + 5, + [ + "dummy pythonic hint" + ] + ] + ], + "entry_points_by_type":{ + "CONSTRUCTOR":[ + { + "selector":"0x1", + "offset":1, + "builtins":[ + "dummy builtin" + ] + } + ], + "EXTERNAL":[ + { + "selector":"0x1", + "offset":1, + "builtins":[ + "dummy builtin" + ] + } + ], + "L1_HANDLER":[ + { + "selector":"0x1", + "offset":1, + "builtins":[ + "dummy builtin" + ] + } + ] + } + } +} \ No newline at end of file diff --git a/crates/starknet_consensus_orchestrator/resources/central_contract_class.sierra.json b/crates/starknet_consensus_orchestrator/resources/central_contract_class.sierra.json new file mode 100644 index 00000000000..b8da460a2c4 --- /dev/null +++ b/crates/starknet_consensus_orchestrator/resources/central_contract_class.sierra.json @@ -0,0 +1,31 @@ +{ + "contract_class":{ + "sierra_program":[ + "0x0", + "0x1", + "0x2" + ], + "contract_class_version":"0.1.0", + "entry_points_by_type":{ + "CONSTRUCTOR":[ + { + "function_idx":1, + "selector":"0x2" + } + ], + "EXTERNAL":[ + { + "function_idx":3, + "selector":"0x4" + } + ], + "L1_HANDLER":[ + { + "function_idx":5, + "selector":"0x6" + } + ] + }, + "abi":"dummy abi" + } +} \ No newline at end of file diff --git a/crates/starknet_consensus_orchestrator/resources/central_contract_class_default_optionals.casm.json b/crates/starknet_consensus_orchestrator/resources/central_contract_class_default_optionals.casm.json new file mode 100644 index 00000000000..e759aa900f7 --- /dev/null +++ b/crates/starknet_consensus_orchestrator/resources/central_contract_class_default_optionals.casm.json @@ -0,0 +1,56 @@ +{ + "compiled_class":{ + "prime":"0x1", + "compiler_version":"dummy version", + "bytecode":[ + "0x1" + ], + "hints":[ + [ + 4, + [ + { + "AllocSegment":{ + "dst":{ + "offset":1, + "register":"AP" + } + } + } + ] + ] + ], + "pythonic_hints":[ + + ], + "entry_points_by_type":{ + "CONSTRUCTOR":[ + { + "selector":"0x1", + "offset":1, + "builtins":[ + "dummy builtin" + ] + } + ], + "EXTERNAL":[ + { + "selector":"0x1", + "offset":1, + "builtins":[ + "dummy builtin" + ] + } + ], + "L1_HANDLER":[ + { + "selector":"0x1", + "offset":1, + "builtins":[ + "dummy builtin" + ] + } + ] + } + } +} \ No newline at end of file diff --git a/crates/starknet_consensus_orchestrator/resources/central_declare_tx.json b/crates/starknet_consensus_orchestrator/resources/central_declare_tx.json new file mode 100644 index 00000000000..060101ae235 --- /dev/null +++ b/crates/starknet_consensus_orchestrator/resources/central_declare_tx.json @@ -0,0 +1,39 @@ +{ + "tx": { + "hash_value": "0x41e7d973115400a98a7775190c27d4e3b1fcd8cd40b7d27464f6c3f10b8b706", + "version": "0x3", + "signature": ["0x0", "0x1", "0x2"], + "nonce": "0x1", + "sender_address": "0x12fd537", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0x1", + "max_price_per_unit": "0x1" + }, + "L2_GAS": { + "max_amount": "0x2", + "max_price_per_unit": "0x2" + }, + "L1_DATA_GAS": { + "max_amount": "0x3", + "max_price_per_unit": "0x3" + } + }, + "tip": "0x1", + "paymaster_data": [], + "class_hash": "0x3a59046762823dc87385eb5ac8a21f3f5bfe4274151c6eb633737656c209056", + "compiled_class_hash": "0x1", + "sierra_program_size": 3, + "sierra_version": [ + "0x0", + "0x1", + "0x0" + ], + "abi_size": 9, + "account_deployment_data": [], + "type": "DECLARE" + }, + "time_created": 1734601649 +} diff --git a/crates/starknet_consensus_orchestrator/resources/central_deploy_account_tx.json b/crates/starknet_consensus_orchestrator/resources/central_deploy_account_tx.json new file mode 100644 index 00000000000..0e81d6fbf3f --- /dev/null +++ b/crates/starknet_consensus_orchestrator/resources/central_deploy_account_tx.json @@ -0,0 +1,32 @@ +{ + "tx": { + "hash_value": "0x429cb4dc45610a80a96800ab350a11ff50e2d69e25c7723c002934e66b5a282", + "version": "0x3", + "signature": ["0x0", "0x1", "0x2"], + "nonce": "0x1", + "sender_address": "0x4c2e031b0ddaa38e06fd9b1bf32bff739965f9d64833006204c67cbc879a57c", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0x1", + "max_price_per_unit": "0x1" + }, + "L2_GAS": { + "max_amount": "0x2", + "max_price_per_unit": "0x2" + }, + "L1_DATA_GAS": { + "max_amount": "0x3", + "max_price_per_unit": "0x3" + } + }, + "tip": "0x1", + "paymaster_data": [], + "contract_address_salt": "0x2", + "class_hash": "0x1b5a0b09f23b091d5d1fa2f660ddfad6bcfce607deba23806cd7328ccfb8ee9", + "constructor_calldata": ["0x0", "0x1", "0x2"], + "type": "DEPLOY_ACCOUNT" + }, + "time_created": 1734601616 +} diff --git a/crates/starknet_consensus_orchestrator/resources/central_fee_market_info.json b/crates/starknet_consensus_orchestrator/resources/central_fee_market_info.json new file mode 100644 index 00000000000..69fa0a265c0 --- /dev/null +++ b/crates/starknet_consensus_orchestrator/resources/central_fee_market_info.json @@ -0,0 +1,4 @@ +{ + "l2_gas_consumed": 150000, + "next_l2_gas_price": 100000 +} diff --git a/crates/starknet_consensus_orchestrator/resources/central_invoke_tx.json b/crates/starknet_consensus_orchestrator/resources/central_invoke_tx.json new file mode 100644 index 00000000000..0c477a4e7ce --- /dev/null +++ b/crates/starknet_consensus_orchestrator/resources/central_invoke_tx.json @@ -0,0 +1,34 @@ +{ + "tx": { + "hash_value": "0x6efd067c859e6469d0f6d158e9ae408a9552eb8cc11f618ab3aef3e52450666", + "version": "0x3", + "signature": ["0x0", "0x1", "0x2"], + "nonce": "0x1", + "sender_address": "0x14abfd58671a1a9b30de2fcd2a42e8bff2ce1096a7c70bc7995904965f277e", + "nonce_data_availability_mode": 0, + "fee_data_availability_mode": 0, + "resource_bounds": { + "L1_GAS": { + "max_amount": "0x1", + "max_price_per_unit": "0x1" + }, + "L2_GAS": { + "max_amount": "0x2", + "max_price_per_unit": "0x2" + }, + "L1_DATA_GAS": { + "max_amount": "0x3", + "max_price_per_unit": "0x3" + } + }, + "tip": "0x1", + "paymaster_data": [], + "calldata": [ + "0x0", + "0x1" + ], + "account_deployment_data": [], + "type": "INVOKE_FUNCTION" + }, + "time_created": 1734601615 +} diff --git a/crates/starknet_consensus_orchestrator/resources/central_l1_handler_tx.json b/crates/starknet_consensus_orchestrator/resources/central_l1_handler_tx.json new file mode 100644 index 00000000000..308a21ecbf4 --- /dev/null +++ b/crates/starknet_consensus_orchestrator/resources/central_l1_handler_tx.json @@ -0,0 +1,15 @@ +{ + "tx": { + "hash_value": "0xc947753befd252ca08042000cd6d783162ee2f5df87b519ddf3081b9b4b997", + "contract_address": "0x14abfd58671a1a9b30de2fcd2a42e8bff2ce1096a7c70bc7995904965f277e", + "entry_point_selector": "0x2a", + "calldata": [ + "0x0", + "0x1" + ], + "nonce": "0x1", + "paid_fee_on_l1": "0x1", + "type": "L1_HANDLER" + }, + "time_created": 1734601657 +} diff --git a/crates/starknet_consensus_orchestrator/resources/central_state_diff.json b/crates/starknet_consensus_orchestrator/resources/central_state_diff.json new file mode 100644 index 00000000000..65a92abddcd --- /dev/null +++ b/crates/starknet_consensus_orchestrator/resources/central_state_diff.json @@ -0,0 +1,40 @@ +{ + "address_to_class_hash": { + "0x1": "0x1", + "0x5": "0x5" + }, + "nonces": { + "L1": { + "0x2": "0x2" + } + }, + "storage_updates": { + "L1": { + "0x3": { + "0x3": "0x3" + } + } + }, + "declared_classes": { + "0x4": "0x4" + }, + "block_info": { + "block_number": 5, + "block_timestamp": 6, + "l1_gas_price": { + "price_in_wei": "0x8", + "price_in_fri": "0x9" + }, + "l1_data_gas_price": { + "price_in_wei": "0xa", + "price_in_fri": "0xb" + }, + "l2_gas_price": { + "price_in_wei": "0xc", + "price_in_fri": "0xd" + }, + "sequencer_address": "0x7", + "starknet_version": "0.14.0", + "use_kzg_da": true + } +} diff --git a/crates/starknet_consensus_orchestrator/resources/central_transaction_execution_info.json b/crates/starknet_consensus_orchestrator/resources/central_transaction_execution_info.json new file mode 100644 index 00000000000..a8a52ec96a6 --- /dev/null +++ b/crates/starknet_consensus_orchestrator/resources/central_transaction_execution_info.json @@ -0,0 +1,532 @@ +{ + "actual_fee": "0x26fe9d250e000", + "actual_resources": { + "n_steps": 7, + "pedersen_builtin": 4, + "range_check_builtin": 31 + }, + "da_gas": { + "l1_data_gas": 1, + "l1_gas": 1652, + "l2_gas": 1 + }, + "execute_call_info": { + "call": { + "call_type": "Call", + "calldata": [ + "0x40070000", + "0x39a1491f76903a16feed0a6433bec78de4c73194944e1118e226820ad479701", + "0x1", + "0x2" + ], + "caller_address": "0x1", + "class_hash": "0x80020000", + "code_address": "0x40070000", + "entry_point_selector": "0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775", + "entry_point_type": "EXTERNAL", + "initial_gas": 100000000, + "storage_address": "0xc0020000" + }, + "execution": { + "events": [ + { + "event": { + "data": [ + "0x0", + "0x1", + "0x2" + ], + "keys": [ + "0x9" + ] + }, + "order": 2 + } + ], + "failed": false, + "gas_consumed": 11690, + "l2_to_l1_messages": [ + { + "message": { + "payload": [ + "0x0", + "0x1", + "0x2" + ], + "to_address": "0x1" + }, + "order": 1 + } + ], + "retdata": [ + "0x56414c4944" + ] + }, + "inner_calls": [ + { + "call": { + "call_type": "Call", + "calldata": [ + "0x40070000", + "0x39a1491f76903a16feed0a6433bec78de4c73194944e1118e226820ad479701", + "0x1", + "0x2" + ], + "caller_address": "0x1", + "class_hash": "0x80020000", + "code_address": "0x40070000", + "entry_point_selector": "0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775", + "entry_point_type": "EXTERNAL", + "initial_gas": 100000000, + "storage_address": "0xc0020000" + }, + "execution": { + "events": [ + { + "event": { + "data": [ + "0x0", + "0x1", + "0x2" + ], + "keys": [ + "0x9" + ] + }, + "order": 2 + } + ], + "failed": false, + "gas_consumed": 11690, + "l2_to_l1_messages": [ + { + "message": { + "payload": [ + "0x0", + "0x1", + "0x2" + ], + "to_address": "0x1" + }, + "order": 1 + } + ], + "retdata": [ + "0x56414c4944" + ] + }, + "resources": { + "builtin_instance_counter": { + "pedersen_builtin": 4, + "range_check_builtin": 31 + }, + "n_memory_holes": 3, + "n_steps": 2 + }, + "storage_access_tracker": { + "accessed_contract_addresses": [ + "0x1" + ], + "accessed_storage_keys": [ + "0x1" + ], + "read_class_hash_values": [ + "0x80020000" + ], + "storage_read_values": [ + "0x0", + "0x1", + "0x2" + ], + "read_block_hash_values": [ + "0xdeafbee" + ], + "accessed_blocks": [ + 100 + ] + }, + "tracked_resource": "SierraGas", + "inner_calls": [] + } + ], + "resources": { + "builtin_instance_counter": { + "pedersen_builtin": 4, + "range_check_builtin": 31 + }, + "n_memory_holes": 3, + "n_steps": 2 + }, + "storage_access_tracker": { + "accessed_contract_addresses": [ + "0x1" + ], + "accessed_storage_keys": [ + "0x1" + ], + "read_class_hash_values": [ + "0x80020000" + ], + "storage_read_values": [ + "0x0", + "0x1", + "0x2" + ], + "read_block_hash_values": [ + "0xdeafbee" + ], + "accessed_blocks": [ + 100 + ] + }, + "tracked_resource": "SierraGas" + }, + "fee_transfer_call_info": { + "call": { + "call_type": "Call", + "calldata": [ + "0x40070000", + "0x39a1491f76903a16feed0a6433bec78de4c73194944e1118e226820ad479701", + "0x1", + "0x2" + ], + "caller_address": "0x1", + "class_hash": "0x80020000", + "code_address": "0x40070000", + "entry_point_selector": "0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775", + "entry_point_type": "EXTERNAL", + "initial_gas": 100000000, + "storage_address": "0xc0020000" + }, + "execution": { + "events": [ + { + "event": { + "data": [ + "0x0", + "0x1", + "0x2" + ], + "keys": [ + "0x9" + ] + }, + "order": 2 + } + ], + "failed": false, + "gas_consumed": 11690, + "l2_to_l1_messages": [ + { + "message": { + "payload": [ + "0x0", + "0x1", + "0x2" + ], + "to_address": "0x1" + }, + "order": 1 + } + ], + "retdata": [ + "0x56414c4944" + ] + }, + "inner_calls": [ + { + "call": { + "call_type": "Call", + "calldata": [ + "0x40070000", + "0x39a1491f76903a16feed0a6433bec78de4c73194944e1118e226820ad479701", + "0x1", + "0x2" + ], + "caller_address": "0x1", + "class_hash": "0x80020000", + "code_address": "0x40070000", + "entry_point_selector": "0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775", + "entry_point_type": "EXTERNAL", + "initial_gas": 100000000, + "storage_address": "0xc0020000" + }, + "execution": { + "events": [ + { + "event": { + "data": [ + "0x0", + "0x1", + "0x2" + ], + "keys": [ + "0x9" + ] + }, + "order": 2 + } + ], + "failed": false, + "gas_consumed": 11690, + "l2_to_l1_messages": [ + { + "message": { + "payload": [ + "0x0", + "0x1", + "0x2" + ], + "to_address": "0x1" + }, + "order": 1 + } + ], + "retdata": [ + "0x56414c4944" + ] + }, + "resources": { + "builtin_instance_counter": { + "pedersen_builtin": 4, + "range_check_builtin": 31 + }, + "n_memory_holes": 3, + "n_steps": 2 + }, + "storage_access_tracker": { + "accessed_contract_addresses": [ + "0x1" + ], + "accessed_storage_keys": [ + "0x1" + ], + "read_class_hash_values": [ + "0x80020000" + ], + "storage_read_values": [ + "0x0", + "0x1", + "0x2" + ], + "read_block_hash_values": [ + "0xdeafbee" + ], + "accessed_blocks": [ + 100 + ] + }, + "tracked_resource": "SierraGas", + "inner_calls": [] + } + ], + "resources": { + "builtin_instance_counter": { + "pedersen_builtin": 4, + "range_check_builtin": 31 + }, + "n_memory_holes": 3, + "n_steps": 2 + }, + "storage_access_tracker": { + "accessed_contract_addresses": [ + "0x1" + ], + "accessed_storage_keys": [ + "0x1" + ], + "read_class_hash_values": [ + "0x80020000" + ], + "storage_read_values": [ + "0x0", + "0x1", + "0x2" + ], + "read_block_hash_values": [ + "0xdeafbee" + ], + "accessed_blocks": [ + 100 + ] + }, + "tracked_resource": "SierraGas" + }, + "revert_error": null, + "total_gas": { + "l1_data_gas": 1, + "l1_gas": 6860, + "l2_gas": 1 + }, + "validate_call_info": { + "call": { + "call_type": "Call", + "calldata": [ + "0x40070000", + "0x39a1491f76903a16feed0a6433bec78de4c73194944e1118e226820ad479701", + "0x1", + "0x2" + ], + "caller_address": "0x1", + "class_hash": "0x80020000", + "code_address": "0x40070000", + "entry_point_selector": "0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775", + "entry_point_type": "EXTERNAL", + "initial_gas": 100000000, + "storage_address": "0xc0020000" + }, + "execution": { + "events": [ + { + "event": { + "data": [ + "0x0", + "0x1", + "0x2" + ], + "keys": [ + "0x9" + ] + }, + "order": 2 + } + ], + "failed": false, + "gas_consumed": 11690, + "l2_to_l1_messages": [ + { + "message": { + "payload": [ + "0x0", + "0x1", + "0x2" + ], + "to_address": "0x1" + }, + "order": 1 + } + ], + "retdata": [ + "0x56414c4944" + ] + }, + "inner_calls": [ + { + "call": { + "call_type": "Call", + "calldata": [ + "0x40070000", + "0x39a1491f76903a16feed0a6433bec78de4c73194944e1118e226820ad479701", + "0x1", + "0x2" + ], + "caller_address": "0x1", + "class_hash": "0x80020000", + "code_address": "0x40070000", + "entry_point_selector": "0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775", + "entry_point_type": "EXTERNAL", + "initial_gas": 100000000, + "storage_address": "0xc0020000" + }, + "execution": { + "events": [ + { + "event": { + "data": [ + "0x0", + "0x1", + "0x2" + ], + "keys": [ + "0x9" + ] + }, + "order": 2 + } + ], + "failed": false, + "gas_consumed": 11690, + "l2_to_l1_messages": [ + { + "message": { + "payload": [ + "0x0", + "0x1", + "0x2" + ], + "to_address": "0x1" + }, + "order": 1 + } + ], + "retdata": [ + "0x56414c4944" + ] + }, + "resources": { + "builtin_instance_counter": { + "pedersen_builtin": 4, + "range_check_builtin": 31 + }, + "n_memory_holes": 3, + "n_steps": 2 + }, + "storage_access_tracker": { + "accessed_contract_addresses": [ + "0x1" + ], + "accessed_storage_keys": [ + "0x1" + ], + "read_class_hash_values": [ + "0x80020000" + ], + "storage_read_values": [ + "0x0", + "0x1", + "0x2" + ], + "read_block_hash_values": [ + "0xdeafbee" + ], + "accessed_blocks": [ + 100 + ] + }, + "tracked_resource": "SierraGas", + "inner_calls": [] + } + ], + "resources": { + "builtin_instance_counter": { + "pedersen_builtin": 4, + "range_check_builtin": 31 + }, + "n_memory_holes": 3, + "n_steps": 2 + }, + "storage_access_tracker": { + "accessed_contract_addresses": [ + "0x1" + ], + "accessed_storage_keys": [ + "0x1" + ], + "read_class_hash_values": [ + "0x80020000" + ], + "storage_read_values": [ + "0x0", + "0x1", + "0x2" + ], + "read_block_hash_values": [ + "0xdeafbee" + ], + "accessed_blocks": [ + 100 + ] + }, + "tracked_resource": "SierraGas" + } +} diff --git a/crates/starknet_consensus_orchestrator/resources/central_transaction_execution_info_reverted.json b/crates/starknet_consensus_orchestrator/resources/central_transaction_execution_info_reverted.json new file mode 100644 index 00000000000..cb1fa7e30e8 --- /dev/null +++ b/crates/starknet_consensus_orchestrator/resources/central_transaction_execution_info_reverted.json @@ -0,0 +1,362 @@ +{ + "actual_fee": "0x26fe9d250e000", + "actual_resources": { + "n_steps": 7, + "pedersen_builtin": 4, + "range_check_builtin": 31 + }, + "da_gas": { + "l1_data_gas": 1, + "l1_gas": 1652, + "l2_gas": 1 + }, + "execute_call_info": null, + "fee_transfer_call_info": { + "call": { + "call_type": "Call", + "calldata": [ + "0x40070000", + "0x39a1491f76903a16feed0a6433bec78de4c73194944e1118e226820ad479701", + "0x1", + "0x2" + ], + "caller_address": "0x1", + "class_hash": "0x80020000", + "code_address": "0x40070000", + "entry_point_selector": "0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775", + "entry_point_type": "EXTERNAL", + "initial_gas": 100000000, + "storage_address": "0xc0020000" + }, + "execution": { + "events": [ + { + "event": { + "data": [ + "0x0", + "0x1", + "0x2" + ], + "keys": [ + "0x9" + ] + }, + "order": 2 + } + ], + "failed": false, + "gas_consumed": 11690, + "l2_to_l1_messages": [ + { + "message": { + "payload": [ + "0x0", + "0x1", + "0x2" + ], + "to_address": "0x1" + }, + "order": 1 + } + ], + "retdata": [ + "0x56414c4944" + ] + }, + "inner_calls": [ + { + "call": { + "call_type": "Call", + "calldata": [ + "0x40070000", + "0x39a1491f76903a16feed0a6433bec78de4c73194944e1118e226820ad479701", + "0x1", + "0x2" + ], + "caller_address": "0x1", + "class_hash": "0x80020000", + "code_address": "0x40070000", + "entry_point_selector": "0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775", + "entry_point_type": "EXTERNAL", + "initial_gas": 100000000, + "storage_address": "0xc0020000" + }, + "execution": { + "events": [ + { + "event": { + "data": [ + "0x0", + "0x1", + "0x2" + ], + "keys": [ + "0x9" + ] + }, + "order": 2 + } + ], + "failed": false, + "gas_consumed": 11690, + "l2_to_l1_messages": [ + { + "message": { + "payload": [ + "0x0", + "0x1", + "0x2" + ], + "to_address": "0x1" + }, + "order": 1 + } + ], + "retdata": [ + "0x56414c4944" + ] + }, + "resources": { + "builtin_instance_counter": { + "pedersen_builtin": 4, + "range_check_builtin": 31 + }, + "n_memory_holes": 3, + "n_steps": 2 + }, + "storage_access_tracker": { + "accessed_contract_addresses": [ + "0x1" + ], + "accessed_storage_keys": [ + "0x1" + ], + "read_class_hash_values": [ + "0x80020000" + ], + "storage_read_values": [ + "0x0", + "0x1", + "0x2" + ], + "read_block_hash_values": [ + "0xdeafbee" + ], + "accessed_blocks": [ + 100 + ] + }, + "tracked_resource": "SierraGas", + "inner_calls": [] + } + ], + "resources": { + "builtin_instance_counter": { + "pedersen_builtin": 4, + "range_check_builtin": 31 + }, + "n_memory_holes": 3, + "n_steps": 2 + }, + "storage_access_tracker": { + "accessed_contract_addresses": [ + "0x1" + ], + "accessed_storage_keys": [ + "0x1" + ], + "read_class_hash_values": [ + "0x80020000" + ], + "storage_read_values": [ + "0x0", + "0x1", + "0x2" + ], + "read_block_hash_values": [ + "0xdeafbee" + ], + "accessed_blocks": [ + 100 + ] + }, + "tracked_resource": "SierraGas" + }, + "revert_error": "Insufficient fee token balance. Fee: 1, balance: low/high 2/3.", + "total_gas": { + "l1_data_gas": 1, + "l1_gas": 6860, + "l2_gas": 1 + }, + "validate_call_info": { + "call": { + "call_type": "Call", + "calldata": [ + "0x40070000", + "0x39a1491f76903a16feed0a6433bec78de4c73194944e1118e226820ad479701", + "0x1", + "0x2" + ], + "caller_address": "0x1", + "class_hash": "0x80020000", + "code_address": "0x40070000", + "entry_point_selector": "0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775", + "entry_point_type": "EXTERNAL", + "initial_gas": 100000000, + "storage_address": "0xc0020000" + }, + "execution": { + "events": [ + { + "event": { + "data": [ + "0x0", + "0x1", + "0x2" + ], + "keys": [ + "0x9" + ] + }, + "order": 2 + } + ], + "failed": false, + "gas_consumed": 11690, + "l2_to_l1_messages": [ + { + "message": { + "payload": [ + "0x0", + "0x1", + "0x2" + ], + "to_address": "0x1" + }, + "order": 1 + } + ], + "retdata": [ + "0x56414c4944" + ] + }, + "inner_calls": [ + { + "call": { + "call_type": "Call", + "calldata": [ + "0x40070000", + "0x39a1491f76903a16feed0a6433bec78de4c73194944e1118e226820ad479701", + "0x1", + "0x2" + ], + "caller_address": "0x1", + "class_hash": "0x80020000", + "code_address": "0x40070000", + "entry_point_selector": "0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775", + "entry_point_type": "EXTERNAL", + "initial_gas": 100000000, + "storage_address": "0xc0020000" + }, + "execution": { + "events": [ + { + "event": { + "data": [ + "0x0", + "0x1", + "0x2" + ], + "keys": [ + "0x9" + ] + }, + "order": 2 + } + ], + "failed": false, + "gas_consumed": 11690, + "l2_to_l1_messages": [ + { + "message": { + "payload": [ + "0x0", + "0x1", + "0x2" + ], + "to_address": "0x1" + }, + "order": 1 + } + ], + "retdata": [ + "0x56414c4944" + ] + }, + "resources": { + "builtin_instance_counter": { + "pedersen_builtin": 4, + "range_check_builtin": 31 + }, + "n_memory_holes": 3, + "n_steps": 2 + }, + "storage_access_tracker": { + "accessed_contract_addresses": [ + "0x1" + ], + "accessed_storage_keys": [ + "0x1" + ], + "read_class_hash_values": [ + "0x80020000" + ], + "storage_read_values": [ + "0x0", + "0x1", + "0x2" + ], + "read_block_hash_values": [ + "0xdeafbee" + ], + "accessed_blocks": [ + 100 + ] + }, + "tracked_resource": "SierraGas", + "inner_calls": [] + } + ], + "resources": { + "builtin_instance_counter": { + "pedersen_builtin": 4, + "range_check_builtin": 31 + }, + "n_memory_holes": 3, + "n_steps": 2 + }, + "storage_access_tracker": { + "accessed_contract_addresses": [ + "0x1" + ], + "accessed_storage_keys": [ + "0x1" + ], + "read_class_hash_values": [ + "0x80020000" + ], + "storage_read_values": [ + "0x0", + "0x1", + "0x2" + ], + "read_block_hash_values": [ + "0xdeafbee" + ], + "accessed_blocks": [ + 100 + ] + }, + "tracked_resource": "SierraGas" + } +} diff --git a/crates/starknet_consensus_orchestrator/resources/orchestrator_versioned_constants_0_14_0.json b/crates/starknet_consensus_orchestrator/resources/orchestrator_versioned_constants_0_14_0.json new file mode 100644 index 00000000000..e40fe5be714 --- /dev/null +++ b/crates/starknet_consensus_orchestrator/resources/orchestrator_versioned_constants_0_14_0.json @@ -0,0 +1,6 @@ +{ + "gas_price_max_change_denominator": 48, + "gas_target": 2000000000, + "max_block_size": 4000000000, + "min_gas_price": 100000 +} diff --git a/crates/starknet_consensus_orchestrator/src/cende/cende_test.rs b/crates/starknet_consensus_orchestrator/src/cende/cende_test.rs new file mode 100644 index 00000000000..086104a7468 --- /dev/null +++ b/crates/starknet_consensus_orchestrator/src/cende/cende_test.rs @@ -0,0 +1,83 @@ +use std::sync::Arc; + +use rstest::rstest; +use starknet_api::block::{BlockInfo, BlockNumber}; +use starknet_class_manager_types::MockClassManagerClient; + +use super::{CendeAmbassador, RECORDER_WRITE_BLOB_PATH}; +use crate::cende::{BlobParameters, CendeConfig, CendeContext}; + +const HEIGHT_TO_WRITE: BlockNumber = BlockNumber(10); + +impl BlobParameters { + fn with_block_number(block_number: BlockNumber) -> Self { + Self { block_info: BlockInfo { block_number, ..Default::default() }, ..Default::default() } + } +} + +#[rstest] +#[case::success(200, Some(9), 1, true)] +#[case::no_prev_block(200, None, 0, false)] +#[case::prev_block_height_mismatch(200, Some(7), 0, false)] +#[case::recorder_return_error(500, Some(9), 1, false)] +#[tokio::test] +async fn write_prev_height_blob( + #[case] mock_status_code: usize, + #[case] prev_block: Option, + #[case] expected_calls: usize, + #[case] expected_result: bool, +) { + let mut server = mockito::Server::new_async().await; + let url = server.url(); + let mock = server.mock("POST", RECORDER_WRITE_BLOB_PATH).with_status(mock_status_code).create(); + + let cende_ambassador = CendeAmbassador::new( + CendeConfig { recorder_url: url.parse().unwrap(), ..Default::default() }, + Arc::new(MockClassManagerClient::new()), + ); + + if let Some(prev_block) = prev_block { + cende_ambassador + .prepare_blob_for_next_height(BlobParameters::with_block_number(BlockNumber( + prev_block, + ))) + .await + .unwrap(); + } + + let receiver = cende_ambassador.write_prev_height_blob(HEIGHT_TO_WRITE); + + assert_eq!(receiver.await.unwrap(), expected_result); + mock.expect(expected_calls).assert(); +} + +#[tokio::test] +async fn prepare_blob_for_next_height() { + let cende_ambassador = + CendeAmbassador::new(CendeConfig::default(), Arc::new(MockClassManagerClient::new())); + + cende_ambassador + .prepare_blob_for_next_height(BlobParameters::with_block_number(HEIGHT_TO_WRITE)) + .await + .unwrap(); + assert_eq!( + cende_ambassador.prev_height_blob.lock().await.as_ref().unwrap().block_number, + HEIGHT_TO_WRITE + ); +} + +#[tokio::test] +async fn no_write_at_skipped_height() { + const SKIP_WRITE_HEIGHT: BlockNumber = HEIGHT_TO_WRITE; + let cende_ambassador = CendeAmbassador::new( + CendeConfig { skip_write_height: Some(SKIP_WRITE_HEIGHT), ..Default::default() }, + Arc::new(MockClassManagerClient::new()), + ); + + // Returns false since the blob is missing and the height is different than skip_write_height. + assert!( + !cende_ambassador.write_prev_height_blob(HEIGHT_TO_WRITE.unchecked_next()).await.unwrap() + ); + + assert!(cende_ambassador.write_prev_height_blob(HEIGHT_TO_WRITE).await.unwrap()); +} diff --git a/crates/starknet_consensus_orchestrator/src/cende/central_objects.rs b/crates/starknet_consensus_orchestrator/src/cende/central_objects.rs new file mode 100644 index 00000000000..494a7011d00 --- /dev/null +++ b/crates/starknet_consensus_orchestrator/src/cende/central_objects.rs @@ -0,0 +1,507 @@ +use std::str::FromStr; + +use blockifier::bouncer::BouncerWeights; +use blockifier::state::cached_state::CommitmentStateDiff; +use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass; +use indexmap::{indexmap, IndexMap}; +use serde::Serialize; +use starknet_api::block::{ + BlockInfo, + BlockNumber, + BlockTimestamp, + NonzeroGasPrice, + StarknetVersion, +}; +use starknet_api::consensus_transaction::InternalConsensusTransaction; +use starknet_api::contract_class::{ContractClass, SierraVersion}; +use starknet_api::core::{ + ClassHash, + CompiledClassHash, + ContractAddress, + EntryPointSelector, + Nonce, +}; +use starknet_api::data_availability::DataAvailabilityMode; +use starknet_api::executable_transaction::L1HandlerTransaction; +use starknet_api::rpc_transaction::{ + InternalRpcDeclareTransactionV3, + InternalRpcDeployAccountTransaction, + InternalRpcTransaction, + InternalRpcTransactionWithoutTxHash, + RpcDeployAccountTransaction, + RpcInvokeTransaction, +}; +use starknet_api::state::{SierraContractClass, StorageKey, ThinStateDiff}; +use starknet_api::transaction::fields::{ + AccountDeploymentData, + AllResourceBounds, + Calldata, + ContractAddressSalt, + Fee, + PaymasterData, + ResourceBounds, + Tip, + TransactionSignature, +}; +use starknet_api::transaction::TransactionHash; +use starknet_class_manager_types::SharedClassManagerClient; +use starknet_types_core::felt::Felt; + +use super::{CendeAmbassadorError, CendeAmbassadorResult}; +use crate::fee_market::FeeMarketInfo; + +/// Central objects are required in order to continue processing the block by the centralized +/// Python pipline. These objects are written to the Aerospike database and are used by python +/// services. In the future, all services will be decentralized and this module will be removed. +#[cfg(test)] +#[path = "central_objects_test.rs"] +mod central_objects_test; + +pub(crate) type CentralBouncerWeights = BouncerWeights; +pub(crate) type CentralFeeMarketInfo = FeeMarketInfo; +pub(crate) type CentralCompressedStateDiff = CentralStateDiff; +pub(crate) type CentralSierraContractClassEntry = (ClassHash, CentralSierraContractClass); +pub(crate) type CentralCasmContractClassEntry = (CompiledClassHash, CentralCasmContractClass); + +#[derive(Clone, Debug, PartialEq, Serialize)] +struct CentralResourcePrice { + price_in_wei: NonzeroGasPrice, + price_in_fri: NonzeroGasPrice, +} + +#[derive(Clone, Debug, PartialEq, Serialize)] +pub(crate) struct CentralBlockInfo { + block_number: BlockNumber, + block_timestamp: BlockTimestamp, + sequencer_address: ContractAddress, + l1_gas_price: CentralResourcePrice, + l1_data_gas_price: CentralResourcePrice, + l2_gas_price: CentralResourcePrice, + use_kzg_da: bool, + starknet_version: Option, +} + +impl From<(BlockInfo, StarknetVersion)> for CentralBlockInfo { + fn from((block_info, starknet_version): (BlockInfo, StarknetVersion)) -> CentralBlockInfo { + CentralBlockInfo { + block_number: block_info.block_number, + block_timestamp: block_info.block_timestamp, + sequencer_address: block_info.sequencer_address, + l1_gas_price: CentralResourcePrice { + price_in_wei: block_info.gas_prices.eth_gas_prices.l1_gas_price, + price_in_fri: block_info.gas_prices.strk_gas_prices.l1_gas_price, + }, + l1_data_gas_price: CentralResourcePrice { + price_in_wei: block_info.gas_prices.eth_gas_prices.l1_data_gas_price, + price_in_fri: block_info.gas_prices.strk_gas_prices.l1_data_gas_price, + }, + l2_gas_price: CentralResourcePrice { + price_in_wei: block_info.gas_prices.eth_gas_prices.l2_gas_price, + price_in_fri: block_info.gas_prices.strk_gas_prices.l2_gas_price, + }, + use_kzg_da: block_info.use_kzg_da, + starknet_version: Some(starknet_version), + } + } +} + +#[derive(Debug, PartialEq, Serialize)] +pub(crate) struct CentralStateDiff { + address_to_class_hash: IndexMap, + nonces: IndexMap>, + storage_updates: + IndexMap>>, + declared_classes: IndexMap, + block_info: CentralBlockInfo, +} + +// We convert to CentralStateDiff from ThinStateDiff since this object is already sent to consensus +// for the Sync service, otherwise we could have used the CommitmentStateDiff as well. +impl From<(ThinStateDiff, CentralBlockInfo)> for CentralStateDiff { + fn from( + (state_diff, central_block_info): (ThinStateDiff, CentralBlockInfo), + ) -> CentralStateDiff { + assert!( + state_diff.deprecated_declared_classes.is_empty(), + "Deprecated classes are not supported" + ); + + CentralStateDiff { + address_to_class_hash: state_diff.deployed_contracts, + nonces: indexmap!(DataAvailabilityMode::L1=> state_diff.nonces), + storage_updates: indexmap!(DataAvailabilityMode::L1=> state_diff.storage_diffs), + declared_classes: state_diff.declared_classes, + block_info: central_block_info, + } + } +} + +impl From<(CommitmentStateDiff, CentralBlockInfo)> for CentralStateDiff { + fn from( + (state_diff, central_block_info): (CommitmentStateDiff, CentralBlockInfo), + ) -> CentralStateDiff { + CentralStateDiff { + address_to_class_hash: state_diff.address_to_class_hash, + nonces: indexmap!(DataAvailabilityMode::L1=> state_diff.address_to_nonce), + storage_updates: indexmap!(DataAvailabilityMode::L1=> state_diff.storage_updates), + declared_classes: state_diff.class_hash_to_compiled_class_hash, + block_info: central_block_info, + } + } +} + +#[derive(Debug, PartialEq, Serialize)] +struct CentralResourceBounds { + #[serde(rename = "L1_GAS")] + l1_gas: ResourceBounds, + #[serde(rename = "L2_GAS")] + l2_gas: ResourceBounds, + #[serde(rename = "L1_DATA_GAS")] + l1_data_gas: ResourceBounds, +} + +impl From for CentralResourceBounds { + fn from(resource_bounds: AllResourceBounds) -> CentralResourceBounds { + CentralResourceBounds { + l1_gas: resource_bounds.l1_gas, + l2_gas: resource_bounds.l2_gas, + l1_data_gas: resource_bounds.l1_data_gas, + } + } +} + +#[derive(Debug, PartialEq, Serialize)] +struct CentralInvokeTransactionV3 { + resource_bounds: CentralResourceBounds, + tip: Tip, + signature: TransactionSignature, + nonce: Nonce, + sender_address: ContractAddress, + calldata: Calldata, + nonce_data_availability_mode: u32, + fee_data_availability_mode: u32, + paymaster_data: PaymasterData, + account_deployment_data: AccountDeploymentData, + hash_value: TransactionHash, +} + +impl From<(RpcInvokeTransaction, TransactionHash)> for CentralInvokeTransactionV3 { + fn from( + (tx, hash_value): (RpcInvokeTransaction, TransactionHash), + ) -> CentralInvokeTransactionV3 { + let RpcInvokeTransaction::V3(tx) = tx; + CentralInvokeTransactionV3 { + sender_address: tx.sender_address, + calldata: tx.calldata, + signature: tx.signature, + nonce: tx.nonce, + resource_bounds: tx.resource_bounds.into(), + tip: tx.tip, + paymaster_data: tx.paymaster_data, + account_deployment_data: tx.account_deployment_data, + nonce_data_availability_mode: tx.nonce_data_availability_mode.into(), + fee_data_availability_mode: tx.fee_data_availability_mode.into(), + hash_value, + } + } +} + +#[derive(Debug, PartialEq, Serialize)] +#[serde(tag = "version")] +enum CentralInvokeTransaction { + #[serde(rename = "0x3")] + V3(CentralInvokeTransactionV3), +} + +#[derive(Debug, PartialEq, Serialize)] +struct CentralDeployAccountTransactionV3 { + resource_bounds: CentralResourceBounds, + tip: Tip, + signature: TransactionSignature, + nonce: Nonce, + class_hash: ClassHash, + contract_address_salt: ContractAddressSalt, + sender_address: ContractAddress, + constructor_calldata: Calldata, + nonce_data_availability_mode: u32, + fee_data_availability_mode: u32, + paymaster_data: PaymasterData, + hash_value: TransactionHash, +} + +impl From<(InternalRpcDeployAccountTransaction, TransactionHash)> + for CentralDeployAccountTransactionV3 +{ + fn from( + (tx, hash_value): (InternalRpcDeployAccountTransaction, TransactionHash), + ) -> CentralDeployAccountTransactionV3 { + let sender_address = tx.contract_address; + let RpcDeployAccountTransaction::V3(tx) = tx.tx; + + CentralDeployAccountTransactionV3 { + resource_bounds: tx.resource_bounds.into(), + tip: tx.tip, + signature: tx.signature, + nonce: tx.nonce, + class_hash: tx.class_hash, + contract_address_salt: tx.contract_address_salt, + constructor_calldata: tx.constructor_calldata, + nonce_data_availability_mode: tx.nonce_data_availability_mode.into(), + fee_data_availability_mode: tx.fee_data_availability_mode.into(), + paymaster_data: tx.paymaster_data, + hash_value, + sender_address, + } + } +} + +#[derive(Debug, PartialEq, Serialize)] +#[serde(tag = "version")] +enum CentralDeployAccountTransaction { + #[serde(rename = "0x3")] + V3(CentralDeployAccountTransactionV3), +} + +fn into_string_tuple(val: SierraVersion) -> (String, String, String) { + (format!("0x{:x}", val.major), format!("0x{:x}", val.minor), format!("0x{:x}", val.patch)) +} + +#[derive(Debug, PartialEq, Serialize)] +struct CentralDeclareTransactionV3 { + resource_bounds: CentralResourceBounds, + tip: Tip, + signature: TransactionSignature, + nonce: Nonce, + class_hash: ClassHash, + compiled_class_hash: CompiledClassHash, + sender_address: ContractAddress, + nonce_data_availability_mode: u32, + fee_data_availability_mode: u32, + paymaster_data: PaymasterData, + account_deployment_data: AccountDeploymentData, + sierra_program_size: usize, + abi_size: usize, + sierra_version: (String, String, String), + hash_value: TransactionHash, +} + +impl TryFrom<(InternalRpcDeclareTransactionV3, &SierraContractClass, TransactionHash)> + for CentralDeclareTransactionV3 +{ + type Error = CendeAmbassadorError; + + fn try_from( + (tx, sierra, hash_value): ( + InternalRpcDeclareTransactionV3, + &SierraContractClass, + TransactionHash, + ), + ) -> CendeAmbassadorResult { + Ok(CentralDeclareTransactionV3 { + resource_bounds: tx.resource_bounds.into(), + tip: tx.tip, + signature: tx.signature, + nonce: tx.nonce, + class_hash: tx.class_hash, + compiled_class_hash: tx.compiled_class_hash, + sender_address: tx.sender_address, + nonce_data_availability_mode: tx.nonce_data_availability_mode.into(), + fee_data_availability_mode: tx.fee_data_availability_mode.into(), + paymaster_data: tx.paymaster_data, + account_deployment_data: tx.account_deployment_data, + sierra_program_size: sierra.sierra_program.len(), + abi_size: sierra.abi.len(), + sierra_version: into_string_tuple(SierraVersion::from_str( + &sierra.contract_class_version, + )?), + hash_value, + }) + } +} + +#[derive(Debug, PartialEq, Serialize)] +#[serde(tag = "version")] +enum CentralDeclareTransaction { + #[serde(rename = "0x3")] + V3(CentralDeclareTransactionV3), +} + +#[derive(Debug, PartialEq, Serialize)] +struct CentralL1HandlerTransaction { + contract_address: ContractAddress, + entry_point_selector: EntryPointSelector, + calldata: Calldata, + nonce: Nonce, + paid_fee_on_l1: Fee, + hash_value: TransactionHash, +} + +impl From for CentralL1HandlerTransaction { + fn from(tx: L1HandlerTransaction) -> CentralL1HandlerTransaction { + CentralL1HandlerTransaction { + hash_value: tx.tx_hash, + contract_address: tx.tx.contract_address, + entry_point_selector: tx.tx.entry_point_selector, + calldata: tx.tx.calldata, + nonce: tx.tx.nonce, + paid_fee_on_l1: tx.paid_fee_on_l1, + } + } +} + +#[derive(Debug, PartialEq, Serialize)] +#[serde(tag = "type")] +enum CentralTransaction { + #[serde(rename = "INVOKE_FUNCTION")] + Invoke(CentralInvokeTransaction), + #[serde(rename = "DEPLOY_ACCOUNT")] + DeployAccount(CentralDeployAccountTransaction), + #[serde(rename = "DECLARE")] + Declare(CentralDeclareTransaction), + #[serde(rename = "L1_HANDLER")] + L1Handler(CentralL1HandlerTransaction), +} + +impl TryFrom<(InternalConsensusTransaction, Option<&SierraContractClass>)> for CentralTransaction { + type Error = CendeAmbassadorError; + + fn try_from( + (tx, sierra): (InternalConsensusTransaction, Option<&SierraContractClass>), + ) -> CendeAmbassadorResult { + match tx { + InternalConsensusTransaction::RpcTransaction(rpc_transaction) => { + match rpc_transaction.tx { + InternalRpcTransactionWithoutTxHash::Invoke(invoke_tx) => { + Ok(CentralTransaction::Invoke(CentralInvokeTransaction::V3( + (invoke_tx, rpc_transaction.tx_hash).into(), + ))) + } + InternalRpcTransactionWithoutTxHash::DeployAccount(deploy_tx) => { + Ok(CentralTransaction::DeployAccount(CentralDeployAccountTransaction::V3( + (deploy_tx, rpc_transaction.tx_hash).into(), + ))) + } + InternalRpcTransactionWithoutTxHash::Declare(declare_tx) => { + let sierra = sierra + .expect("Sierra contract class is required for declare_tx conversion"); + Ok(CentralTransaction::Declare(CentralDeclareTransaction::V3( + (declare_tx, sierra, rpc_transaction.tx_hash).try_into()?, + ))) + } + } + } + InternalConsensusTransaction::L1Handler(l1_handler_tx) => { + Ok(CentralTransaction::L1Handler(l1_handler_tx.into())) + } + } + } +} + +#[derive(Debug, PartialEq, Serialize)] +pub(crate) struct CentralTransactionWritten { + tx: CentralTransaction, + // The timestamp is required for monitoring data, we use the block timestamp for this. + time_created: u64, +} + +// This function gets SierraContractClass only for declare_tx, otherwise use None. +impl TryFrom<(InternalConsensusTransaction, Option<&SierraContractClass>, u64)> + for CentralTransactionWritten +{ + type Error = CendeAmbassadorError; + + fn try_from( + (tx, sierra, timestamp): (InternalConsensusTransaction, Option<&SierraContractClass>, u64), + ) -> CendeAmbassadorResult { + Ok(CentralTransactionWritten { + tx: CentralTransaction::try_from((tx, sierra))?, + time_created: timestamp, + }) + } +} +#[derive(Clone, Debug, PartialEq, Serialize)] +pub(crate) struct CentralSierraContractClass { + contract_class: SierraContractClass, +} + +#[derive(Clone, Debug, PartialEq, Serialize)] +pub(crate) struct CentralCasmContractClass { + compiled_class: CasmContractClass, +} + +impl From for CentralCasmContractClass { + fn from(compiled_class: CasmContractClass) -> CentralCasmContractClass { + CentralCasmContractClass { + compiled_class: CasmContractClass { + // This field is mandatory in the python object. + pythonic_hints: Some(compiled_class.pythonic_hints.unwrap_or_default()), + ..compiled_class + }, + } + } +} + +async fn get_contract_classes_if_declare( + class_manager: SharedClassManagerClient, + tx: &InternalConsensusTransaction, +) -> CendeAmbassadorResult> +{ + // Check if the tx is declare, otherwise return None. + let InternalConsensusTransaction::RpcTransaction(InternalRpcTransaction { + tx: InternalRpcTransactionWithoutTxHash::Declare(declare_tx), + .. + }) = &tx + else { + return Ok(None); + }; + + let class_hash = declare_tx.class_hash; + + // TODO(yael, dvir): get the classes in parallel from the class manager. + let ContractClass::V1(casm) = class_manager + .get_executable(class_hash) + .await? + .ok_or(CendeAmbassadorError::ClassNotFound { class_hash })? + else { + panic!("Only V1 contract classes are supported"); + }; + + let hashed_casm = (declare_tx.compiled_class_hash, CentralCasmContractClass::from(casm.0)); + let sierra = class_manager + .get_sierra(class_hash) + .await? + .ok_or(CendeAmbassadorError::ClassNotFound { class_hash })?; + let hashed_sierra = (class_hash, CentralSierraContractClass { contract_class: sierra }); + + Ok(Some((hashed_sierra, hashed_casm))) +} + +pub(crate) async fn process_transactions( + class_manager: SharedClassManagerClient, + txs: Vec, + timestamp: u64, +) -> CendeAmbassadorResult<( + Vec, + Vec, + Vec, +)> { + let mut contract_classes = Vec::new(); + let mut compiled_classes = Vec::new(); + let mut central_transactions = Vec::new(); + for tx in txs { + if let Some((contract_class, compiled_class)) = + get_contract_classes_if_declare(class_manager.clone(), &tx).await? + { + central_transactions.push(CentralTransactionWritten::try_from(( + tx, + Some(&contract_class.1.contract_class), + timestamp, + ))?); + contract_classes.push(contract_class); + compiled_classes.push(compiled_class); + } else { + central_transactions.push(CentralTransactionWritten::try_from((tx, None, timestamp))?); + } + } + Ok((central_transactions, contract_classes, compiled_classes)) +} diff --git a/crates/starknet_consensus_orchestrator/src/cende/central_objects_test.rs b/crates/starknet_consensus_orchestrator/src/cende/central_objects_test.rs new file mode 100644 index 00000000000..4cf04c89ba1 --- /dev/null +++ b/crates/starknet_consensus_orchestrator/src/cende/central_objects_test.rs @@ -0,0 +1,657 @@ +use std::collections::{HashMap, HashSet}; +use std::sync::Arc; +use std::vec; + +use blockifier::execution::call_info::{ + CallExecution, + CallInfo, + MessageToL1, + OrderedEvent, + OrderedL2ToL1Message, + Retdata, + StorageAccessTracker, +}; +use blockifier::execution::contract_class::TrackedResource; +use blockifier::execution::entry_point::{CallEntryPoint, CallType}; +use blockifier::fee::fee_checks::FeeCheckError; +use blockifier::fee::receipt::TransactionReceipt; +use blockifier::fee::resources::{ + ArchivalDataResources, + ComputationResources, + MessageResources, + StarknetResources, + StateResources, + TransactionResources, +}; +use blockifier::state::cached_state::{ + CommitmentStateDiff, + StateChangesCount, + StateChangesCountForFee, +}; +use blockifier::transaction::objects::{RevertError, TransactionExecutionInfo}; +use cairo_lang_casm::hints::{CoreHint, CoreHintBase, Hint}; +use cairo_lang_casm::operand::{CellRef, Register}; +use cairo_lang_starknet_classes::casm_contract_class::{ + CasmContractClass, + CasmContractEntryPoint, + CasmContractEntryPoints, +}; +use cairo_lang_starknet_classes::NestedIntList; +use cairo_lang_utils::bigint::BigUintAsHex; +use cairo_vm::types::builtin_name::BuiltinName; +use cairo_vm::vm::runners::cairo_runner::ExecutionResources; +use indexmap::indexmap; +use mockall::predicate::eq; +use num_bigint::BigUint; +use rstest::rstest; +use serde::Serialize; +use shared_execution_objects::central_objects::CentralTransactionExecutionInfo; +use starknet_api::block::{ + BlockHash, + BlockInfo, + BlockNumber, + BlockTimestamp, + GasPrice, + GasPriceVector, + GasPrices, + NonzeroGasPrice, + StarknetVersion, +}; +use starknet_api::consensus_transaction::InternalConsensusTransaction; +use starknet_api::contract_class::{ContractClass, EntryPointType, SierraVersion}; +use starknet_api::core::{ClassHash, CompiledClassHash, EntryPointSelector, EthAddress}; +use starknet_api::data_availability::DataAvailabilityMode; +use starknet_api::executable_transaction::L1HandlerTransaction; +use starknet_api::execution_resources::{GasAmount, GasVector}; +use starknet_api::rpc_transaction::{ + EntryPointByType, + InternalRpcDeclareTransactionV3, + InternalRpcDeployAccountTransaction, + InternalRpcTransaction, + InternalRpcTransactionWithoutTxHash, + RpcDeployAccountTransaction, + RpcDeployAccountTransactionV3, + RpcInvokeTransaction, + RpcInvokeTransactionV3, +}; +use starknet_api::state::{ + EntryPoint, + FunctionIndex, + SierraContractClass, + StorageKey, + ThinStateDiff, +}; +use starknet_api::test_utils::read_json_file; +use starknet_api::transaction::fields::{ + AccountDeploymentData, + AllResourceBounds, + Calldata, + ContractAddressSalt, + Fee, + PaymasterData, + ResourceBounds, + Tip, + TransactionSignature, +}; +use starknet_api::transaction::{ + EventContent, + EventData, + EventKey, + L2ToL1Payload, + TransactionHash, + TransactionVersion, +}; +use starknet_api::{contract_address, felt, nonce, storage_key}; +use starknet_class_manager_types::MockClassManagerClient; +use starknet_infra_utils::test_utils::assert_json_eq; +use starknet_types_core::felt::Felt; + +use super::{ + CentralBouncerWeights, + CentralCompressedStateDiff, + CentralDeclareTransaction, + CentralDeployAccountTransaction, + CentralFeeMarketInfo, + CentralInvokeTransaction, + CentralSierraContractClass, + CentralStateDiff, + CentralTransaction, + CentralTransactionWritten, +}; +use crate::cende::central_objects::CentralCasmContractClass; +use crate::cende::{AerospikeBlob, BlobParameters}; + +// TODO(yael, dvir): add default object serialization tests. + +pub const CENTRAL_STATE_DIFF_JSON_PATH: &str = "central_state_diff.json"; +pub const CENTRAL_INVOKE_TX_JSON_PATH: &str = "central_invoke_tx.json"; +pub const CENTRAL_DEPLOY_ACCOUNT_TX_JSON_PATH: &str = "central_deploy_account_tx.json"; +pub const CENTRAL_DECLARE_TX_JSON_PATH: &str = "central_declare_tx.json"; +pub const CENTRAL_L1_HANDLER_TX_JSON_PATH: &str = "central_l1_handler_tx.json"; +pub const CENTRAL_BOUNCER_WEIGHTS_JSON_PATH: &str = "central_bouncer_weights.json"; +pub const CENTRAL_FEE_MARKET_INFO_JSON_PATH: &str = "central_fee_market_info.json"; +pub const CENTRAL_SIERRA_CONTRACT_CLASS_JSON_PATH: &str = "central_contract_class.sierra.json"; +pub const CENTRAL_CASM_CONTRACT_CLASS_JSON_PATH: &str = "central_contract_class.casm.json"; +pub const CENTRAL_CASM_CONTRACT_CLASS_DEFAULT_OPTIONALS_JSON_PATH: &str = + "central_contract_class_default_optionals.casm.json"; +pub const CENTRAL_TRANSACTION_EXECUTION_INFO_JSON_PATH: &str = + "central_transaction_execution_info.json"; +pub const CENTRAL_TRANSACTION_EXECUTION_INFO_REVERTED_JSON_PATH: &str = + "central_transaction_execution_info_reverted.json"; +pub const CENTRAL_BLOB_JSON_PATH: &str = "central_blob.json"; + +fn resource_bounds() -> AllResourceBounds { + AllResourceBounds { + l1_gas: ResourceBounds { max_amount: GasAmount(1), max_price_per_unit: GasPrice(1) }, + l2_gas: ResourceBounds { max_amount: GasAmount(2), max_price_per_unit: GasPrice(2) }, + l1_data_gas: ResourceBounds { max_amount: GasAmount(3), max_price_per_unit: GasPrice(3) }, + } +} + +fn felt_vector() -> Vec { + vec![felt!(0_u8), felt!(1_u8), felt!(2_u8)] +} + +fn declare_class_hash() -> ClassHash { + ClassHash(felt!("0x3a59046762823dc87385eb5ac8a21f3f5bfe4274151c6eb633737656c209056")) +} + +fn declare_compiled_class_hash() -> CompiledClassHash { + CompiledClassHash(felt!(1_u8)) +} + +fn thin_state_diff() -> ThinStateDiff { + ThinStateDiff { + deployed_contracts: indexmap! { + contract_address!(1_u8) => + ClassHash(felt!(1_u8)), + contract_address!(5_u8)=> ClassHash(felt!(5_u8)), + }, + storage_diffs: indexmap!(contract_address!(3_u8) => indexmap!(storage_key!(3_u8) => felt!(3_u8))), + declared_classes: indexmap!(ClassHash(felt!(4_u8))=> CompiledClassHash(felt!(4_u8))), + nonces: indexmap!(contract_address!(2_u8)=> nonce!(2)), + ..Default::default() + } +} + +fn block_info() -> BlockInfo { + BlockInfo { + block_number: BlockNumber(5), + block_timestamp: BlockTimestamp(6), + sequencer_address: contract_address!(7_u8), + gas_prices: GasPrices { + eth_gas_prices: GasPriceVector { + l1_gas_price: NonzeroGasPrice::new(GasPrice(8)).unwrap(), + l1_data_gas_price: NonzeroGasPrice::new(GasPrice(10)).unwrap(), + l2_gas_price: NonzeroGasPrice::new(GasPrice(12)).unwrap(), + }, + strk_gas_prices: GasPriceVector { + l1_gas_price: NonzeroGasPrice::new(GasPrice(9)).unwrap(), + l1_data_gas_price: NonzeroGasPrice::new(GasPrice(11)).unwrap(), + l2_gas_price: NonzeroGasPrice::new(GasPrice(13)).unwrap(), + }, + }, + use_kzg_da: true, + } +} + +fn central_state_diff() -> CentralStateDiff { + let state_diff = thin_state_diff(); + let block_info = block_info(); + let starknet_version = StarknetVersion::V0_14_0; + + (state_diff, (block_info, starknet_version).into()).into() +} + +fn commitment_state_diff() -> CommitmentStateDiff { + CommitmentStateDiff { + address_to_class_hash: indexmap! { + contract_address!(1_u8) => ClassHash(felt!(1_u8)), + contract_address!(5_u8)=> ClassHash(felt!(5_u8)), + }, + storage_updates: indexmap!(contract_address!(3_u8) => indexmap!(storage_key!(3_u8) => felt!(3_u8))), + class_hash_to_compiled_class_hash: indexmap!(ClassHash(felt!(4_u8))=> CompiledClassHash(felt!(4_u8))), + address_to_nonce: indexmap!(contract_address!(2_u8)=> nonce!(2)), + } +} + +fn central_compressed_state_diff() -> CentralCompressedStateDiff { + let state_diff = commitment_state_diff(); + let block_info = block_info(); + let starknet_version = StarknetVersion::V0_14_0; + + (state_diff, (block_info, starknet_version).into()).into() +} + +fn invoke_transaction() -> RpcInvokeTransaction { + RpcInvokeTransaction::V3(RpcInvokeTransactionV3 { + resource_bounds: resource_bounds(), + tip: Tip(1), + signature: TransactionSignature(felt_vector()), + nonce: nonce!(1), + sender_address: contract_address!( + "0x14abfd58671a1a9b30de2fcd2a42e8bff2ce1096a7c70bc7995904965f277e" + ), + calldata: Calldata(Arc::new(vec![felt!(0_u8), felt!(1_u8)])), + nonce_data_availability_mode: DataAvailabilityMode::L1, + fee_data_availability_mode: DataAvailabilityMode::L1, + paymaster_data: PaymasterData(vec![]), + account_deployment_data: AccountDeploymentData(vec![]), + }) +} + +fn central_invoke_tx() -> CentralTransactionWritten { + let invoke_tx = invoke_transaction(); + let tx_hash = + TransactionHash(felt!("0x6efd067c859e6469d0f6d158e9ae408a9552eb8cc11f618ab3aef3e52450666")); + + CentralTransactionWritten { + tx: CentralTransaction::Invoke(CentralInvokeTransaction::V3((invoke_tx, tx_hash).into())), + time_created: 1734601615, + } +} + +fn deploy_account_tx() -> InternalRpcDeployAccountTransaction { + InternalRpcDeployAccountTransaction { + tx: RpcDeployAccountTransaction::V3(RpcDeployAccountTransactionV3 { + resource_bounds: resource_bounds(), + tip: Tip(1), + signature: TransactionSignature(felt_vector()), + nonce: nonce!(1), + class_hash: ClassHash(felt!( + "0x1b5a0b09f23b091d5d1fa2f660ddfad6bcfce607deba23806cd7328ccfb8ee9" + )), + contract_address_salt: ContractAddressSalt(felt!(2_u8)), + constructor_calldata: Calldata(Arc::new(felt_vector())), + nonce_data_availability_mode: DataAvailabilityMode::L1, + fee_data_availability_mode: DataAvailabilityMode::L1, + paymaster_data: PaymasterData(vec![]), + }), + contract_address: contract_address!( + "0x4c2e031b0ddaa38e06fd9b1bf32bff739965f9d64833006204c67cbc879a57c" + ), + } +} + +fn central_deploy_account_tx() -> CentralTransactionWritten { + let deploy_account_tx = deploy_account_tx(); + + let tx_hash = + TransactionHash(felt!("0x429cb4dc45610a80a96800ab350a11ff50e2d69e25c7723c002934e66b5a282")); + + CentralTransactionWritten { + tx: CentralTransaction::DeployAccount(CentralDeployAccountTransaction::V3( + (deploy_account_tx, tx_hash).into(), + )), + time_created: 1734601616, + } +} + +fn declare_transaction() -> InternalRpcDeclareTransactionV3 { + InternalRpcDeclareTransactionV3 { + resource_bounds: resource_bounds(), + tip: Tip(1), + signature: TransactionSignature(felt_vector()), + nonce: nonce!(1), + class_hash: declare_class_hash(), + compiled_class_hash: declare_compiled_class_hash(), + sender_address: contract_address!("0x12fd537"), + nonce_data_availability_mode: DataAvailabilityMode::L1, + fee_data_availability_mode: DataAvailabilityMode::L1, + paymaster_data: PaymasterData(vec![]), + account_deployment_data: AccountDeploymentData(vec![]), + } +} + +fn central_declare_tx() -> CentralTransactionWritten { + let tx_hash = + TransactionHash(felt!("0x41e7d973115400a98a7775190c27d4e3b1fcd8cd40b7d27464f6c3f10b8b706")); + let declare_tx = declare_transaction(); + + CentralTransactionWritten { + tx: CentralTransaction::Declare(CentralDeclareTransaction::V3( + (declare_tx, &sierra_contract_class(), tx_hash).try_into().unwrap(), + )), + time_created: 1734601649, + } +} + +fn l1_handler_tx() -> L1HandlerTransaction { + L1HandlerTransaction { + tx: starknet_api::transaction::L1HandlerTransaction { + version: TransactionVersion::ZERO, + nonce: nonce!(1), + contract_address: contract_address!( + "0x14abfd58671a1a9b30de2fcd2a42e8bff2ce1096a7c70bc7995904965f277e" + ), + entry_point_selector: EntryPointSelector(felt!("0x2a")), + calldata: Calldata(Arc::new(vec![felt!(0_u8), felt!(1_u8)])), + }, + tx_hash: TransactionHash(felt!( + "0xc947753befd252ca08042000cd6d783162ee2f5df87b519ddf3081b9b4b997" + )), + paid_fee_on_l1: Fee(1), + } +} + +fn central_l1_handler_tx() -> CentralTransactionWritten { + let l1_handler_tx = l1_handler_tx(); + + CentralTransactionWritten { + tx: CentralTransaction::L1Handler(l1_handler_tx.into()), + time_created: 1734601657, + } +} + +fn central_bouncer_weights() -> CentralBouncerWeights { + CentralBouncerWeights { + l1_gas: 8, + message_segment_length: 9, + n_events: 2, + state_diff_size: 45, + sierra_gas: GasAmount(10), + } +} + +fn central_fee_market_info() -> CentralFeeMarketInfo { + CentralFeeMarketInfo { l2_gas_consumed: 150000, next_l2_gas_price: 100000 } +} + +fn entry_point(idx: usize, selector: u8) -> EntryPoint { + EntryPoint { function_idx: FunctionIndex(idx), selector: EntryPointSelector(felt!(selector)) } +} + +fn sierra_contract_class() -> SierraContractClass { + SierraContractClass { + sierra_program: felt_vector(), + contract_class_version: "0.1.0".to_string(), + entry_points_by_type: EntryPointByType { + constructor: vec![entry_point(1, 2)], + external: vec![entry_point(3, 4)], + l1handler: vec![entry_point(5, 6)], + }, + abi: "dummy abi".to_string(), + } +} + +fn central_sierra_contract_class() -> CentralSierraContractClass { + CentralSierraContractClass { contract_class: sierra_contract_class() } +} + +fn casm_contract_entry_points() -> Vec { + vec![CasmContractEntryPoint { + selector: BigUint::from(1_u8), + offset: 1, + builtins: vec!["dummy builtin".to_string()], + }] +} + +fn casm_contract_class() -> CasmContractClass { + CasmContractClass { + prime: BigUint::from(1_u8), + compiler_version: "dummy version".to_string(), + bytecode: vec![BigUintAsHex { value: BigUint::from(1_u8) }], + bytecode_segment_lengths: Some(NestedIntList::Node(vec![ + NestedIntList::Leaf(1), + NestedIntList::Leaf(2), + ])), + hints: vec![( + 4, + vec![Hint::Core(CoreHintBase::Core(CoreHint::AllocSegment { + dst: CellRef { register: Register::AP, offset: 1 }, + }))], + )], + pythonic_hints: Some(vec![(5, vec!["dummy pythonic hint".to_string()])]), + entry_points_by_type: CasmContractEntryPoints { + external: casm_contract_entry_points(), + l1_handler: casm_contract_entry_points(), + constructor: casm_contract_entry_points(), + }, + } +} + +fn central_casm_contract_class() -> CentralCasmContractClass { + CentralCasmContractClass::from(casm_contract_class()) +} + +fn central_casm_contract_class_default_optional_fields() -> CentralCasmContractClass { + let casm_contract_class = CasmContractClass { + bytecode_segment_lengths: None, + pythonic_hints: None, + ..casm_contract_class() + }; + CentralCasmContractClass::from(casm_contract_class) +} + +fn execution_resources() -> ExecutionResources { + ExecutionResources { + n_steps: 2, + n_memory_holes: 3, + builtin_instance_counter: HashMap::from([ + (BuiltinName::range_check, 31), + (BuiltinName::pedersen, 4), + ]), + } +} + +fn call_info() -> CallInfo { + CallInfo { + call: CallEntryPoint { + class_hash: Some(ClassHash(felt!("0x80020000"))), + code_address: Some(contract_address!("0x40070000")), + entry_point_type: EntryPointType::External, + entry_point_selector: EntryPointSelector(felt!( + "0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775" + )), + calldata: Calldata(Arc::new(vec![ + felt!("0x40070000"), + felt!("0x39a1491f76903a16feed0a6433bec78de4c73194944e1118e226820ad479701"), + felt!("0x1"), + felt!("0x2"), + ])), + storage_address: contract_address!("0xc0020000"), + caller_address: contract_address!("0x1"), + call_type: CallType::Call, + initial_gas: 100_000_000, + }, + execution: CallExecution { + retdata: Retdata(vec![felt!("0x56414c4944")]), + events: vec![OrderedEvent { + order: 2, + event: EventContent { + keys: vec![EventKey(felt!("0x9"))], + data: EventData(felt_vector()), + }, + }], + l2_to_l1_messages: vec![OrderedL2ToL1Message { + order: 1, + message: MessageToL1 { + to_address: EthAddress::try_from(felt!(1_u8)).unwrap(), + payload: L2ToL1Payload(felt_vector()), + }, + }], + failed: false, + gas_consumed: 11_690, + }, + inner_calls: Vec::new(), + resources: execution_resources(), + tracked_resource: TrackedResource::SierraGas, + storage_access_tracker: StorageAccessTracker { + storage_read_values: felt_vector(), + accessed_storage_keys: HashSet::from([StorageKey::from(1_u128)]), + read_class_hash_values: vec![ClassHash(felt!("0x80020000"))], + accessed_contract_addresses: HashSet::from([contract_address!("0x1")]), + read_block_hash_values: vec![BlockHash(felt!("0xdeafbee"))], + accessed_blocks: HashSet::from([BlockNumber(100)]), + }, + } +} + +// This object is very long , so in order to test all types of sub-structs and refrain from filling +// the entire object, we fill only one CallInfo with non-default values and the other CallInfos are +// None. +fn transaction_execution_info() -> TransactionExecutionInfo { + TransactionExecutionInfo { + validate_call_info: Some(CallInfo { inner_calls: vec![call_info()], ..call_info() }), + execute_call_info: Some(CallInfo { inner_calls: vec![call_info()], ..call_info() }), + fee_transfer_call_info: Some(CallInfo { inner_calls: vec![call_info()], ..call_info() }), + revert_error: None, + receipt: TransactionReceipt { + fee: Fee(0x26fe9d250e000), + gas: GasVector { + l1_gas: GasAmount(6860), + l1_data_gas: GasAmount(1), + l2_gas: GasAmount(1), + }, + da_gas: GasVector { + l1_gas: GasAmount(1652), + l1_data_gas: GasAmount(1), + l2_gas: GasAmount(1), + }, + resources: TransactionResources { + starknet_resources: StarknetResources { + // The archival_data has private fields so it cannot be assigned, however, it is + // not being used in the central object anyway so it can be default. + archival_data: ArchivalDataResources::default(), + messages: MessageResources { + l2_to_l1_payload_lengths: vec![1, 2], + message_segment_length: 1, + l1_handler_payload_size: Some(1), + }, + state: StateResources { + state_changes_for_fee: StateChangesCountForFee { + state_changes_count: StateChangesCount { + n_storage_updates: 1, + n_class_hash_updates: 2, + n_compiled_class_hash_updates: 3, + n_modified_contracts: 4, + }, + n_allocated_keys: 5, + }, + }, + }, + computation: ComputationResources { + vm_resources: execution_resources(), + n_reverted_steps: 2, + sierra_gas: GasAmount(0x128140), + reverted_sierra_gas: GasAmount(0x2), + }, + }, + }, + } +} + +fn central_transaction_execution_info() -> CentralTransactionExecutionInfo { + transaction_execution_info().into() +} + +fn central_transaction_execution_info_reverted() -> CentralTransactionExecutionInfo { + let mut transaction_execution_info = transaction_execution_info(); + // The python side enforces that if the transaction is reverted, the execute_call_info is None. + // Since we are using the same json files for python tests, we apply these rules here as well. + transaction_execution_info.execute_call_info = None; + + transaction_execution_info.revert_error = + Some(RevertError::PostExecution(FeeCheckError::InsufficientFeeTokenBalance { + fee: Fee(1), + balance_low: felt!(2_u8), + balance_high: felt!(3_u8), + })); + + transaction_execution_info.into() +} + +fn declare_tx_with_hash(tx_hash: u64) -> InternalConsensusTransaction { + InternalConsensusTransaction::RpcTransaction(InternalRpcTransaction { + tx: InternalRpcTransactionWithoutTxHash::Declare(declare_transaction()), + tx_hash: TransactionHash(felt!(tx_hash)), + }) +} + +// Returns a vector of transactions and a mock class manager with the expectation that needed to +// convert the consensus transactions to central transactions. +fn input_txs_and_mock_class_manager() -> (Vec, MockClassManagerClient) +{ + let invoke = InternalConsensusTransaction::RpcTransaction(InternalRpcTransaction { + tx: InternalRpcTransactionWithoutTxHash::Invoke(invoke_transaction()), + tx_hash: TransactionHash(Felt::TWO), + }); + let deploy_account = InternalConsensusTransaction::RpcTransaction(InternalRpcTransaction { + tx: InternalRpcTransactionWithoutTxHash::DeployAccount(deploy_account_tx()), + tx_hash: TransactionHash(Felt::THREE), + }); + let l1_handler = InternalConsensusTransaction::L1Handler(l1_handler_tx()); + + let transactions = + vec![declare_tx_with_hash(1), invoke, deploy_account, l1_handler, declare_tx_with_hash(4)]; + + let mut mock_class_manager = MockClassManagerClient::new(); + mock_class_manager + .expect_get_sierra() + .with(eq(declare_class_hash())) + .times(2) + .returning(|_| Ok(Some(sierra_contract_class()))); + mock_class_manager.expect_get_executable().with(eq(declare_class_hash())).times(2).returning( + |_| Ok(Some(ContractClass::V1((casm_contract_class(), SierraVersion::new(0, 0, 0))))), + ); + + (transactions, mock_class_manager) +} + +// TODO(dvir): use real blob when possible. +fn central_blob() -> AerospikeBlob { + let (input_txs, mock_class_manager) = input_txs_and_mock_class_manager(); + let blob_parameters = BlobParameters { + block_info: block_info(), + state_diff: thin_state_diff(), + compressed_state_diff: Some(commitment_state_diff()), + transactions: input_txs, + bouncer_weights: central_bouncer_weights(), + fee_market_info: central_fee_market_info(), + execution_infos: vec![transaction_execution_info()], + }; + + // This is to make the function sync (not async) so that it can be used as a case in the + // serialize_central_objects test. + let runtime = tokio::runtime::Runtime::new().unwrap(); + runtime + .block_on(AerospikeBlob::from_blob_parameters_and_class_manager( + blob_parameters, + Arc::new(mock_class_manager), + )) + .unwrap() +} + +#[rstest] +#[case::compressed_state_diff(central_compressed_state_diff(), CENTRAL_STATE_DIFF_JSON_PATH)] +#[case::state_diff(central_state_diff(), CENTRAL_STATE_DIFF_JSON_PATH)] +#[case::invoke_tx(central_invoke_tx(), CENTRAL_INVOKE_TX_JSON_PATH)] +#[case::deploy_account_tx(central_deploy_account_tx(), CENTRAL_DEPLOY_ACCOUNT_TX_JSON_PATH)] +#[case::declare_tx(central_declare_tx(), CENTRAL_DECLARE_TX_JSON_PATH)] +#[case::l1_handler_tx(central_l1_handler_tx(), CENTRAL_L1_HANDLER_TX_JSON_PATH)] +#[case::bouncer_weights(central_bouncer_weights(), CENTRAL_BOUNCER_WEIGHTS_JSON_PATH)] +#[case::fee_market_info(central_fee_market_info(), CENTRAL_FEE_MARKET_INFO_JSON_PATH)] +#[case::sierra_contract_class( + central_sierra_contract_class(), + CENTRAL_SIERRA_CONTRACT_CLASS_JSON_PATH +)] +#[case::optionals_are_some(central_casm_contract_class(), CENTRAL_CASM_CONTRACT_CLASS_JSON_PATH)] +#[case::optionals_are_none( + central_casm_contract_class_default_optional_fields(), + CENTRAL_CASM_CONTRACT_CLASS_DEFAULT_OPTIONALS_JSON_PATH +)] +#[case::transaction_execution_info( + central_transaction_execution_info(), + CENTRAL_TRANSACTION_EXECUTION_INFO_JSON_PATH +)] +#[case::transaction_execution_info_reverted( + central_transaction_execution_info_reverted(), + CENTRAL_TRANSACTION_EXECUTION_INFO_REVERTED_JSON_PATH +)] +#[case::central_blob(central_blob(), CENTRAL_BLOB_JSON_PATH)] +fn serialize_central_objects(#[case] rust_obj: impl Serialize, #[case] python_json_path: &str) { + let python_json = read_json_file(python_json_path); + let rust_json = serde_json::to_value(rust_obj).unwrap(); + + assert_json_eq(&rust_json, &python_json, "Json Comparison failed".to_string()); +} diff --git a/crates/starknet_consensus_orchestrator/src/cende/mod.rs b/crates/starknet_consensus_orchestrator/src/cende/mod.rs new file mode 100644 index 00000000000..fa89c4aca51 --- /dev/null +++ b/crates/starknet_consensus_orchestrator/src/cende/mod.rs @@ -0,0 +1,320 @@ +#[cfg(test)] +mod cende_test; +mod central_objects; + +use std::collections::BTreeMap; +use std::future::ready; +use std::sync::Arc; + +use async_trait::async_trait; +use blockifier::bouncer::BouncerWeights; +use blockifier::state::cached_state::CommitmentStateDiff; +use blockifier::transaction::objects::TransactionExecutionInfo; +use central_objects::{ + process_transactions, + CentralBlockInfo, + CentralBouncerWeights, + CentralCasmContractClassEntry, + CentralCompressedStateDiff, + CentralFeeMarketInfo, + CentralSierraContractClassEntry, + CentralStateDiff, + CentralTransactionWritten, +}; +#[cfg(test)] +use mockall::automock; +use papyrus_config::dumping::{ser_optional_param, ser_param, SerializeConfig}; +use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; +use reqwest::{Client, RequestBuilder, Response}; +use serde::{Deserialize, Serialize}; +use shared_execution_objects::central_objects::CentralTransactionExecutionInfo; +use starknet_api::block::{BlockInfo, BlockNumber, StarknetVersion}; +use starknet_api::consensus_transaction::InternalConsensusTransaction; +use starknet_api::core::ClassHash; +use starknet_api::state::ThinStateDiff; +use starknet_class_manager_types::{ClassManagerClientError, SharedClassManagerClient}; +use tokio::sync::Mutex; +use tokio::task::{self, JoinHandle}; +use tracing::{error, info, warn, Instrument}; +use url::Url; + +use crate::fee_market::FeeMarketInfo; + +// TODO(dvir): add metrics when the infra side will be completed. + +#[derive(thiserror::Error, Debug)] +pub enum CendeAmbassadorError { + #[error(transparent)] + ClassManagerError(#[from] ClassManagerClientError), + #[error("Class of hash: {class_hash} not found")] + ClassNotFound { class_hash: ClassHash }, + #[error(transparent)] + StarknetApiError(#[from] starknet_api::StarknetApiError), +} + +pub type CendeAmbassadorResult = Result; + +/// A chunk of all the data to write to Aersopike. +#[derive(Debug, Serialize)] +pub(crate) struct AerospikeBlob { + block_number: BlockNumber, + state_diff: CentralStateDiff, + // The batcher may return a `None` compressed state diff if it is disabled in the + // configuration. + compressed_state_diff: Option, + bouncer_weights: CentralBouncerWeights, + fee_market_info: CentralFeeMarketInfo, + transactions: Vec, + execution_infos: Vec, + contract_classes: Vec, + compiled_classes: Vec, +} + +#[cfg_attr(test, automock)] +#[async_trait] +pub trait CendeContext: Send + Sync { + /// Write the previous height blob to Aerospike. Returns a cell with an inner boolean indicating + /// whether the write was successful. + /// `current_height` is the height of the block that is built when calling this function. + fn write_prev_height_blob(&self, current_height: BlockNumber) -> JoinHandle; + + // Prepares the previous height blob that will be written in the next height. + async fn prepare_blob_for_next_height( + &self, + blob_parameters: BlobParameters, + ) -> CendeAmbassadorResult<()>; +} + +#[derive(Clone)] +pub struct CendeAmbassador { + // TODO(dvir): consider creating enum varaiant instead of the `Option`. + // `None` indicates that there is no blob to write, and therefore, the node can't be the + // proposer. + prev_height_blob: Arc>>, + url: Url, + client: Client, + skip_write_height: Option, + class_manager: SharedClassManagerClient, +} + +/// The path to write blob in the Recorder. +pub const RECORDER_WRITE_BLOB_PATH: &str = "/cende_recorder/write_blob"; + +impl CendeAmbassador { + pub fn new(cende_config: CendeConfig, class_manager: SharedClassManagerClient) -> Self { + CendeAmbassador { + prev_height_blob: Arc::new(Mutex::new(None)), + url: cende_config + .recorder_url + .join(RECORDER_WRITE_BLOB_PATH) + .expect("Failed to join `RECORDER_WRITE_BLOB_PATH` with the Recorder URL"), + client: Client::new(), + skip_write_height: cende_config.skip_write_height, + class_manager, + } + } +} + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +pub struct CendeConfig { + pub recorder_url: Url, + pub skip_write_height: Option, +} + +impl Default for CendeConfig { + fn default() -> Self { + CendeConfig { + recorder_url: "https://recorder_url" + .parse() + .expect("recorder_url must be a valid Recorder URL"), + skip_write_height: None, + } + } +} + +impl SerializeConfig for CendeConfig { + fn dump(&self) -> BTreeMap { + let mut config = BTreeMap::from_iter([ser_param( + "recorder_url", + &self.recorder_url, + "The URL of the Pythonic cende_recorder", + ParamPrivacyInput::Private, + )]); + config.extend(ser_optional_param( + &self.skip_write_height, + BlockNumber(0), + "skip_write_height", + "A height that the consensus can skip writing to Aerospike. Needed for booting up (no \ + previous height blob to write) or to handle extreme cases (all the nodes failed).", + ParamPrivacyInput::Private, + )); + + config + } +} + +#[async_trait] +impl CendeContext for CendeAmbassador { + fn write_prev_height_blob(&self, current_height: BlockNumber) -> JoinHandle { + info!("Start writing to Aerospike previous height blob for height {current_height}."); + + // TODO(dvir): consider returning a future that will be spawned in the context instead. + if self.skip_write_height == Some(current_height) { + info!( + "Height {current_height} is configured as the `skip_write_height`, meaning \ + consensus can send a proposal without writing to Aerospike. The blob that should \ + have been written here in a normal flow, should already be written to Aerospike. \ + Not writing to Aerospike previous height blob!!!.", + ); + return tokio::spawn(ready(true)); + } + + let prev_height_blob = self.prev_height_blob.clone(); + let request_builder = self.client.post(self.url.clone()); + + task::spawn( + async move { + // TODO(dvir): consider extracting the "should write blob" logic to a function. + let Some(ref blob): Option = *prev_height_blob.lock().await else { + // This case happens when restarting the node, `prev_height_blob` initial value + // is `None`. + warn!("No blob to write to Aerospike."); + return false; + }; + + if blob.block_number.0 >= current_height.0 { + panic!( + "Blob block number is greater than or equal to the current height. That \ + means cende has a blob of height that hasn't reached a consensus." + ) + } + + // Can happen in case the consensus got a block from the state sync and due to that + // did not update the cende ambassador in `decision_reached` function. + if blob.block_number.0 + 1 != current_height.0 { + warn!( + "Mismatch blob block number and height, can't write blob to Aerospike. \ + Blob block number {}, height {current_height}", + blob.block_number + ); + + return false; + } + + info!("Writing blob to Aerospike."); + return send_write_blob(request_builder, blob).await; + } + .instrument(tracing::debug_span!("cende write_prev_height_blob height")), + ) + } + + async fn prepare_blob_for_next_height( + &self, + blob_parameters: BlobParameters, + ) -> CendeAmbassadorResult<()> { + // TODO(dvir): as optimization, call the `into` and other preperation when writing to AS. + let block_number = blob_parameters.block_info.block_number; + *self.prev_height_blob.lock().await = Some( + AerospikeBlob::from_blob_parameters_and_class_manager( + blob_parameters, + self.class_manager.clone(), + ) + .await?, + ); + info!("Blob for block number {block_number} is ready."); + Ok(()) + } +} + +async fn send_write_blob(request_builder: RequestBuilder, blob: &AerospikeBlob) -> bool { + // TODO(dvir): use compression to reduce the size of the blob in the network. + match request_builder.json(blob).send().await { + Ok(response) => { + if response.status().is_success() { + info!( + "Blob with block number {} was written to Aerospike successfully.", + blob.block_number + ); + print_write_blob_response(response).await; + + true + } else { + warn!( + "The recorder failed to write blob with block number {}. Status code: {}", + blob.block_number, + response.status(), + ); + print_write_blob_response(response).await; + + false + } + } + Err(err) => { + // TODO(dvir): try to test this case. + warn!("Failed to send a request to the recorder. Error: {err}"); + false + } + } +} + +async fn print_write_blob_response(response: Response) { + info!("write blob response status code: {}", response.status()); + if let Ok(text) = response.text().await { + info!("write blob response text: {text}"); + } else { + info!("Failed to get response text."); + } +} + +#[derive(Debug, Default)] +pub struct BlobParameters { + pub(crate) block_info: BlockInfo, + pub(crate) state_diff: ThinStateDiff, + pub(crate) compressed_state_diff: Option, + pub(crate) bouncer_weights: BouncerWeights, + pub(crate) fee_market_info: FeeMarketInfo, + pub(crate) transactions: Vec, + // TODO(dvir): consider passing the execution_infos from the batcher as a string that + // serialized in the correct format from the batcher. + pub(crate) execution_infos: Vec, +} + +impl AerospikeBlob { + async fn from_blob_parameters_and_class_manager( + blob_parameters: BlobParameters, + class_manager: SharedClassManagerClient, + ) -> CendeAmbassadorResult { + let block_number = blob_parameters.block_info.block_number; + let block_timestamp = blob_parameters.block_info.block_timestamp.0; + + let block_info = + CentralBlockInfo::from((blob_parameters.block_info, StarknetVersion::LATEST)); + let state_diff = CentralStateDiff::from((blob_parameters.state_diff, block_info.clone())); + let compressed_state_diff = + blob_parameters.compressed_state_diff.map(|compressed_state_diff| { + CentralStateDiff::from((compressed_state_diff, block_info)) + }); + + let (central_transactions, contract_classes, compiled_classes) = + process_transactions(class_manager, blob_parameters.transactions, block_timestamp) + .await?; + + let execution_infos = blob_parameters + .execution_infos + .into_iter() + .map(CentralTransactionExecutionInfo::from) + .collect(); + + Ok(AerospikeBlob { + block_number, + state_diff, + compressed_state_diff, + bouncer_weights: blob_parameters.bouncer_weights, + fee_market_info: blob_parameters.fee_market_info, + transactions: central_transactions, + execution_infos, + contract_classes, + compiled_classes, + }) + } +} diff --git a/crates/starknet_consensus_orchestrator/src/config.rs b/crates/starknet_consensus_orchestrator/src/config.rs new file mode 100644 index 00000000000..ad5a212f959 --- /dev/null +++ b/crates/starknet_consensus_orchestrator/src/config.rs @@ -0,0 +1,110 @@ +use std::collections::BTreeMap; +use std::fmt::Debug; +use std::time::Duration; + +use papyrus_config::converters::deserialize_milliseconds_to_duration; +use papyrus_config::dumping::{ser_param, SerializeConfig}; +use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; +use serde::{Deserialize, Serialize}; +use starknet_api::core::{ChainId, ContractAddress}; +use validator::Validate; + +/// Configuration for the Context struct. +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Validate)] +pub struct ContextConfig { + /// Buffer size for streaming outbound proposals. + pub proposal_buffer_size: usize, + /// The number of validators. + pub num_validators: u64, + /// The chain id of the Starknet chain. + pub chain_id: ChainId, + /// Maximum allowed deviation (seconds) of a proposed block's timestamp from the current time. + pub block_timestamp_window: u64, + /// The data availability mode, true: Blob, false: Calldata. + pub l1_da_mode: bool, + /// The address of the contract that builds the block. + pub builder_address: ContractAddress, + /// Safety margin in milliseconds to make sure that the batcher completes building the proposal + /// with enough time for the Fin to be checked by validators. + #[serde(deserialize_with = "deserialize_milliseconds_to_duration")] + pub build_proposal_margin: Duration, + // When validating a proposal the Context is responsible for timeout handling. The Batcher + // though has a timeout as a defensive measure to make sure the proposal doesn't live + // forever if the Context crashes or has a bug. + /// Safety margin in milliseconds to allow the batcher to successfully validate a proposal. + #[serde(deserialize_with = "deserialize_milliseconds_to_duration")] + pub validate_proposal_margin: Duration, +} + +impl SerializeConfig for ContextConfig { + fn dump(&self) -> BTreeMap { + BTreeMap::from_iter([ + ser_param( + "proposal_buffer_size", + &self.proposal_buffer_size, + "The buffer size for streaming outbound proposals.", + ParamPrivacyInput::Public, + ), + ser_param( + "num_validators", + &self.num_validators, + "The number of validators.", + ParamPrivacyInput::Public, + ), + ser_param( + "chain_id", + &self.chain_id, + "The chain id of the Starknet chain.", + ParamPrivacyInput::Public, + ), + ser_param( + "block_timestamp_window", + &self.block_timestamp_window, + "Maximum allowed deviation (seconds) of a proposed block's timestamp from the \ + current time.", + ParamPrivacyInput::Public, + ), + ser_param( + "l1_da_mode", + &self.l1_da_mode, + "The data availability mode, true: Blob, false: Calldata.", + ParamPrivacyInput::Public, + ), + ser_param( + "builder_address", + &self.builder_address, + "The address of the contract that builds the block.", + ParamPrivacyInput::Public, + ), + ser_param( + "build_proposal_margin", + &self.build_proposal_margin.as_millis(), + "Safety margin (in ms) to make sure that the batcher completes building the \ + proposal with enough time for the Fin to be checked by validators.", + ParamPrivacyInput::Public, + ), + ser_param( + "validate_proposal_margin", + &self.validate_proposal_margin.as_millis(), + "Safety margin (in ms) to make sure that consensus determines when to timeout \ + validating a proposal.", + ParamPrivacyInput::Public, + ), + ]) + } +} + +impl Default for ContextConfig { + fn default() -> Self { + Self { + proposal_buffer_size: 100, + num_validators: 1, + chain_id: ChainId::Mainnet, + block_timestamp_window: 1, + l1_da_mode: true, + builder_address: ContractAddress::default(), + build_proposal_margin: Duration::from_millis(1000), + validate_proposal_margin: Duration::from_millis(10_000), + } + } +} diff --git a/crates/starknet_batcher/src/fee_market.rs b/crates/starknet_consensus_orchestrator/src/fee_market/mod.rs similarity index 76% rename from crates/starknet_batcher/src/fee_market.rs rename to crates/starknet_consensus_orchestrator/src/fee_market/mod.rs index 71cba26a494..823dc88be75 100644 --- a/crates/starknet_batcher/src/fee_market.rs +++ b/crates/starknet_consensus_orchestrator/src/fee_market/mod.rs @@ -1,37 +1,43 @@ use std::cmp::max; +use serde::Serialize; + +use crate::orchestrator_versioned_constants; + #[cfg(test)] -#[path = "fee_market_test.rs"] -pub mod fee_market_test; +mod test; -// This constant is used to calculate the base gas price for the next block according to EIP-1559 -// and serves as a sensitivity parameter that limits the maximum rate of change of the gas price -// between consecutive blocks. -const GAS_PRICE_MAX_CHANGE_DENOMINATOR: u128 = 48; -const MIN_GAS_PRICE: u64 = 100000; // In fri. -// TODO(Mohammad): Check the exact value for maximum block size in StarkNet. -const MAX_BLOCK_SIZE: u64 = 4000000000; // In gas units. It's equivalent to 40M gas steps, with 100 gas units per step. +/// Fee market information for the next block. +#[derive(Debug, Default, Serialize)] +pub struct FeeMarketInfo { + /// Total gas consumed in the current block. + pub l2_gas_consumed: u64, + /// Gas price for the next block. + pub next_l2_gas_price: u64, +} /// Calculate the base gas price for the next block according to EIP-1559. /// /// # Parameters -/// - `price`: The base fee of the current block. +/// - `price`: The base gas price per unit (in fri) of the current block. /// - `gas_used`: The total gas used in the current block. -/// - `gas_target`: The target gas usage per block (usually half of the gas limit). +/// - `gas_target`: The target gas usage per block (usually half of a block's gas limit). pub fn calculate_next_base_gas_price(price: u64, gas_used: u64, gas_target: u64) -> u64 { + let versioned_constants = + orchestrator_versioned_constants::VersionedConstants::latest_constants(); // Setting the target at 50% of the max block size balances the rate of gas price changes, // helping to prevent sudden spikes, particularly during increases, for a better user // experience. assert_eq!( gas_target, - MAX_BLOCK_SIZE / 2, + versioned_constants.max_block_size / 2, "Gas target must be 50% of max block size to balance price changes." ); // To prevent precision loss during multiplication and division, we set a minimum gas price. // Additionally, a minimum gas price is established to prevent prolonged periods before the // price reaches a higher value. assert!( - price >= MIN_GAS_PRICE, + price >= versioned_constants.min_gas_price, "The gas price must be at least the minimum to prevent precision loss during \ multiplication and division." ); @@ -53,7 +59,8 @@ pub fn calculate_next_base_gas_price(price: u64, gas_used: u64, gas_target: u64) // Calculate the price change, maintaining precision by dividing after scaling up. // This avoids significant precision loss that would occur if dividing before // multiplication. - let price_change_u128 = gas_delta_cost / gas_target_u128 / GAS_PRICE_MAX_CHANGE_DENOMINATOR; + let price_change_u128 = + gas_delta_cost / (gas_target_u128 * versioned_constants.gas_price_max_change_denominator); // Convert back to u64, as the price change should fit within the u64 range. // Since the target is half the maximum block size (which fits within a u64), the gas delta @@ -70,5 +77,5 @@ pub fn calculate_next_base_gas_price(price: u64, gas_used: u64, gas_target: u64) || gas_used <= gas_target && adjusted_price <= price ); - max(adjusted_price, MIN_GAS_PRICE) + max(adjusted_price, versioned_constants.min_gas_price) } diff --git a/crates/starknet_consensus_orchestrator/src/fee_market/test.rs b/crates/starknet_consensus_orchestrator/src/fee_market/test.rs new file mode 100644 index 00000000000..fd76c36493e --- /dev/null +++ b/crates/starknet_consensus_orchestrator/src/fee_market/test.rs @@ -0,0 +1,68 @@ +use std::sync::LazyLock; + +use crate::fee_market::calculate_next_base_gas_price; +use crate::orchestrator_versioned_constants::VersionedConstants; + +static VERSIONED_CONSTANTS: LazyLock<&VersionedConstants> = + LazyLock::new(VersionedConstants::latest_constants); + +#[test] +fn test_price_calculation_snapshot() { + // Setup: using realistic arbitrary values. + let init_price: u64 = 1_000_000; + let max_block_size = VERSIONED_CONSTANTS.max_block_size; + let gas_target: u64 = max_block_size / 2; + let high_congestion_gas_used: u64 = max_block_size * 3 / 4; + let low_congestion_gas_used: u64 = max_block_size / 4; + let stable_congestion_gas_used: u64 = gas_target; + + // Fixed expected output values. + let increased_price = 1000000 + 10416; // 1000000 + (1000000 * 1 / 4 * max_block_size) / (0.5 * max_block_size * 48); + let decreased_price = 1000000 - 10416; // 1000000 - (1000000 * 1 / 4 * max_block_size) / (0.5 * max_block_size * 48); + + // Assert. + assert_eq!( + calculate_next_base_gas_price(init_price, high_congestion_gas_used, gas_target), + increased_price + ); + assert_eq!( + calculate_next_base_gas_price(init_price, low_congestion_gas_used, gas_target), + decreased_price + ); + assert_eq!( + calculate_next_base_gas_price(init_price, stable_congestion_gas_used, gas_target), + init_price + ); +} + +#[test] +// This test ensures that the gas price calculation does not overflow with extreme values, +fn test_gas_price_with_extreme_values() { + let max_block_size = VERSIONED_CONSTANTS.max_block_size; + let min_gas_price = VERSIONED_CONSTANTS.min_gas_price; + let gas_price_max_change_denominator = VERSIONED_CONSTANTS.gas_price_max_change_denominator; + + let price = min_gas_price; + let gas_target = max_block_size / 2; + let gas_used = 0; + assert_eq!(calculate_next_base_gas_price(price, gas_used, gas_target), min_gas_price); + + let price = min_gas_price; + let gas_target = max_block_size / 2; + let gas_used = max_block_size; + assert!(calculate_next_base_gas_price(price, gas_used, gas_target) > min_gas_price); + + let price = u64::MAX; + let gas_target = max_block_size / 2; + let gas_used = 0; + calculate_next_base_gas_price(price, gas_used, gas_target); // Should not panic. + + // To avoid overflow when updating the price, the value is set below a certain threshold so that + // the new price does not exceed u64::MAX. + let max_u128 = u128::from(u64::MAX); + let price_u128 = + max_u128 * gas_price_max_change_denominator / (gas_price_max_change_denominator + 1); + let gas_target = max_block_size / 2; + let gas_used = max_block_size; + calculate_next_base_gas_price(u64::try_from(price_u128).unwrap(), gas_used, gas_target); // Should not panic. +} diff --git a/crates/starknet_consensus_orchestrator/src/lib.rs b/crates/starknet_consensus_orchestrator/src/lib.rs new file mode 100644 index 00000000000..c95bce0dd03 --- /dev/null +++ b/crates/starknet_consensus_orchestrator/src/lib.rs @@ -0,0 +1,22 @@ +#![warn(missing_docs)] +//! An orchestrator for a StarkNet node. +//! Implements the consensus context - the interface for consensus to call out to the node. + +#[allow(missing_docs)] +pub mod sequencer_consensus_context; + +/// Centralized and decentralized communication types and functionality. +#[allow(missing_docs)] +pub mod cende; + +/// Fee market logic. +pub mod fee_market; + +/// Consensus' versioned constants. +pub mod orchestrator_versioned_constants; + +/// The orchestrator's configuration. +pub mod config; + +#[allow(missing_docs)] +mod metrics; diff --git a/crates/starknet_consensus_orchestrator/src/metrics.rs b/crates/starknet_consensus_orchestrator/src/metrics.rs new file mode 100644 index 00000000000..c41c8b80879 --- /dev/null +++ b/crates/starknet_consensus_orchestrator/src/metrics.rs @@ -0,0 +1,9 @@ +use starknet_sequencer_metrics::define_metrics; +use starknet_sequencer_metrics::metrics::MetricGauge; + +define_metrics!( + Consensus => { + MetricGauge { CONSENSUS_NUM_BATCHES_IN_PROPOSAL, "consensus_num_batches_in_proposal", "The number of transaction batches in a valid proposal received" }, + MetricGauge { CONSENSUS_NUM_TXS_IN_PROPOSAL, "consensus_num_txs_in_proposal", "The total number of individual transactions in a valid proposal received" }, + } +); diff --git a/crates/starknet_consensus_orchestrator/src/orchestrator_versioned_constants.rs b/crates/starknet_consensus_orchestrator/src/orchestrator_versioned_constants.rs new file mode 100644 index 00000000000..218770aa752 --- /dev/null +++ b/crates/starknet_consensus_orchestrator/src/orchestrator_versioned_constants.rs @@ -0,0 +1,33 @@ +use serde::Deserialize; +use starknet_api::block::StarknetVersion; +use starknet_api::define_versioned_constants; +use thiserror::Error; + +/// Versioned constants for the Consensus. +#[derive(Clone, Deserialize)] +pub struct VersionedConstants { + /// This is used to calculate the base gas price for the next block according to EIP-1559 and + /// serves as a sensitivity parameter that limits the maximum rate of change of the gas price + /// between consecutive blocks. + pub gas_price_max_change_denominator: u128, + /// The minimum gas price in fri. + pub min_gas_price: u64, + /// The maximum block size in gas units. + pub max_block_size: u64, + /// The target gas usage per block (usually half of a block's gas limit). + pub gas_target: u64, +} + +define_versioned_constants!( + VersionedConstants, + VersionedConstantsError, + (V0_14_0, "../resources/orchestrator_versioned_constants_0_14_0.json"), +); + +/// Error type for the Consensus' versioned constants. +#[derive(Debug, Error)] +pub enum VersionedConstantsError { + /// Invalid Starknet version. + #[error("Invalid Starknet version: {0}")] + InvalidStarknetVersion(StarknetVersion), +} diff --git a/crates/starknet_consensus_orchestrator/src/sequencer_consensus_context.rs b/crates/starknet_consensus_orchestrator/src/sequencer_consensus_context.rs new file mode 100644 index 00000000000..e1192f4cc93 --- /dev/null +++ b/crates/starknet_consensus_orchestrator/src/sequencer_consensus_context.rs @@ -0,0 +1,1151 @@ +//! Implementation of the ConsensusContext interface for running the sequencer. +//! +//! It connects to the Batcher who is responsible for building/validating blocks. +#[cfg(test)] +#[path = "sequencer_consensus_context_test.rs"] +mod sequencer_consensus_context_test; + +use std::cmp::max; +use std::collections::{BTreeMap, HashMap}; +use std::sync::{Arc, Mutex}; +use std::time::Duration; + +use async_trait::async_trait; +use futures::channel::{mpsc, oneshot}; +use futures::{FutureExt, SinkExt, StreamExt}; +use papyrus_network::network_manager::{BroadcastTopicClient, BroadcastTopicClientTrait}; +use papyrus_protobuf::consensus::{ + ConsensusBlockInfo, + HeightAndRound, + ProposalFin, + ProposalInit, + ProposalPart, + TransactionBatch, + Vote, + DEFAULT_VALIDATOR_ID, +}; +use starknet_api::block::{ + BlockHash, + BlockHashAndNumber, + BlockHeaderWithoutHash, + BlockNumber, + BlockTimestamp, + GasPrice, + GasPricePerToken, + GasPriceVector, + GasPrices, + NonzeroGasPrice, +}; +use starknet_api::consensus_transaction::InternalConsensusTransaction; +use starknet_api::core::{ContractAddress, SequencerContractAddress}; +use starknet_api::data_availability::L1DataAvailabilityMode; +use starknet_api::transaction::TransactionHash; +use starknet_batcher_types::batcher_types::{ + DecisionReachedInput, + DecisionReachedResponse, + GetProposalContent, + GetProposalContentInput, + ProposalId, + ProposalStatus, + ProposeBlockInput, + SendProposalContent, + SendProposalContentInput, + StartHeightInput, + ValidateBlockInput, +}; +use starknet_batcher_types::communication::{ + BatcherClient, + BatcherClientError, + BatcherClientResult, +}; +use starknet_class_manager_types::transaction_converter::{ + TransactionConverter, + TransactionConverterTrait, +}; +use starknet_class_manager_types::SharedClassManagerClient; +use starknet_consensus::types::{ + ConsensusContext, + ConsensusError, + ProposalCommitment, + Round, + ValidatorId, +}; +use starknet_l1_gas_price_types::errors::EthToStrkOracleClientError; +use starknet_l1_gas_price_types::EthToStrkOracleClientTrait; +use starknet_state_sync_types::communication::SharedStateSyncClient; +use starknet_state_sync_types::state_sync_types::SyncBlock; +use starknet_types_core::felt::Felt; +use tokio::task::JoinHandle; +use tokio::time::Instant; +use tokio_util::sync::CancellationToken; +use tokio_util::task::AbortOnDropHandle; +use tracing::{debug, error, error_span, info, instrument, trace, warn, Instrument}; + +use crate::cende::{BlobParameters, CendeContext}; +use crate::config::ContextConfig; +use crate::fee_market::{calculate_next_base_gas_price, FeeMarketInfo}; +use crate::metrics::{CONSENSUS_NUM_BATCHES_IN_PROPOSAL, CONSENSUS_NUM_TXS_IN_PROPOSAL}; +use crate::orchestrator_versioned_constants::VersionedConstants; + +// Contains parameters required for validating block info. +#[derive(Clone, Debug)] +struct BlockInfoValidation { + height: BlockNumber, + block_timestamp_window: u64, + last_block_timestamp: Option, + l1_da_mode: L1DataAvailabilityMode, +} + +const EMPTY_BLOCK_COMMITMENT: BlockHash = BlockHash(Felt::ONE); + +// TODO(Dan, Matan): Remove this once and replace with real gas prices. +const TEMPORARY_GAS_PRICES: GasPrices = GasPrices { + eth_gas_prices: GasPriceVector { + l1_gas_price: NonzeroGasPrice::MIN, + l1_data_gas_price: NonzeroGasPrice::MIN, + l2_gas_price: NonzeroGasPrice::MIN, + }, + strk_gas_prices: GasPriceVector { + l1_gas_price: NonzeroGasPrice::MIN, + l1_data_gas_price: NonzeroGasPrice::MIN, + l2_gas_price: NonzeroGasPrice::MIN, + }, +}; + +// {height: {proposal_commitment: (block_info, content, [proposal_ids])}} +// Note that multiple proposals IDs can be associated with the same content, but we only need to +// store one of them. +type HeightToIdToContent = BTreeMap< + BlockNumber, + HashMap< + ProposalCommitment, + (ConsensusBlockInfo, Vec>, ProposalId), + >, +>; +type ValidationParams = (BlockNumber, ValidatorId, Duration, mpsc::Receiver); +type BuildProposalResult = Result; + +enum HandledProposalPart { + Continue, + Invalid, + Finished(ProposalCommitment, ProposalFin), + Failed(String), +} + +#[derive(Debug, thiserror::Error)] +enum BuildProposalError { + #[error("Batcher error: {0}")] + Batcher(#[from] BatcherClientError), + + #[error("EthToStrkOracle error: {0}")] + EthToStrkOracle(#[from] EthToStrkOracleClientError), +} + +pub struct SequencerConsensusContext { + config: ContextConfig, + // TODO(Shahak): change this into a dynamic TransactionConverterTrait. + transaction_converter: TransactionConverter, + state_sync_client: SharedStateSyncClient, + batcher: Arc, + validators: Vec, + // Proposal building/validating returns immediately, leaving the actual processing to a spawned + // task. The spawned task processes the proposal asynchronously and updates the + // valid_proposals map upon completion, ensuring consistency across tasks. + valid_proposals: Arc>, + // Used to generate unique proposal IDs across the lifetime of the context. + // TODO(matan): Consider robustness in case consensus can restart without the Batcher + // restarting. + proposal_id: u64, + current_height: Option, + current_round: Round, + // The active proposal refers to the proposal being validated at the current height/round. + // Building proposals are not tracked as active, as consensus can't move on to the next + // height/round until building is done. Context only works on proposals for the + // current round. + active_proposal: Option<(CancellationToken, JoinHandle<()>)>, + // Stores proposals for future rounds until the round is reached. + queued_proposals: + BTreeMap)>, + outbound_proposal_sender: mpsc::Sender<(HeightAndRound, mpsc::Receiver)>, + // Used to broadcast votes to other consensus nodes. + vote_broadcast_client: BroadcastTopicClient, + cende_ambassador: Arc, + // TODO(Asmaa): remove the option once e2e integration tests are updated with fake http server. + eth_to_strk_oracle_client: Option>, + // The next block's l2 gas price, calculated based on EIP-1559, used for building and + // validating proposals. + l2_gas_price: u64, + l1_da_mode: L1DataAvailabilityMode, + last_block_timestamp: Option, +} + +impl SequencerConsensusContext { + #[allow(clippy::too_many_arguments)] + pub fn new( + config: ContextConfig, + class_manager_client: SharedClassManagerClient, + state_sync_client: SharedStateSyncClient, + batcher: Arc, + outbound_proposal_sender: mpsc::Sender<(HeightAndRound, mpsc::Receiver)>, + vote_broadcast_client: BroadcastTopicClient, + cende_ambassador: Arc, + eth_to_strk_oracle_client: Option>, + ) -> Self { + let chain_id = config.chain_id.clone(); + let num_validators = config.num_validators; + let l1_da_mode = if config.l1_da_mode { + L1DataAvailabilityMode::Blob + } else { + L1DataAvailabilityMode::Calldata + }; + Self { + config, + transaction_converter: TransactionConverter::new(class_manager_client, chain_id), + state_sync_client, + batcher, + outbound_proposal_sender, + vote_broadcast_client, + // TODO(Matan): Set the actual validator IDs (contract addresses). + validators: (0..num_validators) + .map(|i| ValidatorId::from(DEFAULT_VALIDATOR_ID + i)) + .collect(), + valid_proposals: Arc::new(Mutex::new(HeightToIdToContent::new())), + proposal_id: 0, + current_height: None, + current_round: 0, + active_proposal: None, + queued_proposals: BTreeMap::new(), + cende_ambassador, + eth_to_strk_oracle_client, + l2_gas_price: VersionedConstants::latest_constants().min_gas_price, + l1_da_mode, + last_block_timestamp: None, + } + } + + fn gas_prices(&self) -> GasPrices { + GasPrices { + strk_gas_prices: GasPriceVector { + l2_gas_price: NonzeroGasPrice::new(self.l2_gas_price.into()) + .expect("Failed to convert l2_gas_price to NonzeroGasPrice, should not be 0."), + ..TEMPORARY_GAS_PRICES.strk_gas_prices + }, + ..TEMPORARY_GAS_PRICES + } + } +} + +struct ProposalBuildArguments { + batcher_timeout: Duration, + proposal_init: ProposalInit, + l1_da_mode: L1DataAvailabilityMode, + proposal_sender: mpsc::Sender, + fin_sender: oneshot::Sender, + batcher: Arc, + eth_to_strk_oracle_client: Option>, + valid_proposals: Arc>, + proposal_id: ProposalId, + cende_write_success: AbortOnDropHandle, + gas_prices: GasPrices, + transaction_converter: TransactionConverter, + builder_address: ContractAddress, + cancel_token: CancellationToken, +} + +struct ProposalValidateArguments { + block_info_validation: BlockInfoValidation, + proposal_id: ProposalId, + batcher: Arc, + timeout: Duration, + batcher_timeout_margin: Duration, + valid_proposals: Arc>, + content_receiver: mpsc::Receiver, + fin_sender: oneshot::Sender<(ProposalCommitment, ProposalFin)>, + cancel_token: CancellationToken, + transaction_converter: TransactionConverter, +} + +#[async_trait] +impl ConsensusContext for SequencerConsensusContext { + type ProposalPart = ProposalPart; + + #[instrument(skip_all)] + async fn build_proposal( + &mut self, + proposal_init: ProposalInit, + timeout: Duration, + ) -> oneshot::Receiver { + // TODO(dvir): consider start writing the blob in `decision_reached`, to reduce transactions + // finality time. Use this option only for one special sequencer that is the same cluster as + // the recorder. + let cende_write_success = AbortOnDropHandle::new( + self.cende_ambassador.write_prev_height_blob(proposal_init.height), + ); + // Handles interrupting an active proposal from a previous height/round + self.set_height_and_round(proposal_init.height, proposal_init.round).await; + + let (fin_sender, fin_receiver) = oneshot::channel(); + let batcher = Arc::clone(&self.batcher); + let eth_to_strk_oracle_client = self.eth_to_strk_oracle_client.clone(); + let valid_proposals = Arc::clone(&self.valid_proposals); + let proposal_id = ProposalId(self.proposal_id); + self.proposal_id += 1; + assert!(timeout > self.config.build_proposal_margin); + let (proposal_sender, proposal_receiver) = mpsc::channel(self.config.proposal_buffer_size); + let l1_da_mode = self.l1_da_mode; + let stream_id = HeightAndRound(proposal_init.height.0, proposal_init.round); + self.outbound_proposal_sender + .send((stream_id, proposal_receiver)) + .await + .expect("Failed to send proposal receiver"); + let gas_prices = self.gas_prices(); + let transaction_converter = self.transaction_converter.clone(); + let builder_address = self.config.builder_address; + + info!(?proposal_init, ?timeout, %proposal_id, "Building proposal"); + let batcher_timeout = timeout - self.config.build_proposal_margin; + let cancel_token = CancellationToken::new(); + let cancel_token_clone = cancel_token.clone(); + let handle = tokio::spawn( + async move { + build_proposal(ProposalBuildArguments { + batcher_timeout, + proposal_init, + l1_da_mode, + proposal_sender, + fin_sender, + batcher, + eth_to_strk_oracle_client, + valid_proposals, + proposal_id, + cende_write_success, + gas_prices, + transaction_converter, + builder_address, + cancel_token, + }) + .await; + } + .instrument( + error_span!("consensus_build_proposal", %proposal_id, round=proposal_init.round), + ), + ); + assert!(self.active_proposal.is_none()); + self.active_proposal = Some((cancel_token_clone, handle)); + + fin_receiver + } + + // Note: this function does not receive ProposalInit. + // That part is consumed by the caller, so it can know the height/round. + #[instrument(skip_all)] + async fn validate_proposal( + &mut self, + proposal_init: ProposalInit, + timeout: Duration, + content_receiver: mpsc::Receiver, + ) -> oneshot::Receiver<(ProposalCommitment, ProposalFin)> { + assert_eq!(Some(proposal_init.height), self.current_height); + let (fin_sender, fin_receiver) = oneshot::channel(); + match proposal_init.round.cmp(&self.current_round) { + std::cmp::Ordering::Less => { + trace!("Dropping proposal from past round"); + fin_receiver + } + std::cmp::Ordering::Greater => { + trace!("Queueing proposal for future round."); + self.queued_proposals.insert( + proposal_init.round, + ( + (proposal_init.height, proposal_init.proposer, timeout, content_receiver), + fin_sender, + ), + ); + fin_receiver + } + std::cmp::Ordering::Equal => { + let block_info_validation = BlockInfoValidation { + height: proposal_init.height, + block_timestamp_window: self.config.block_timestamp_window, + last_block_timestamp: self.last_block_timestamp, + l1_da_mode: self.l1_da_mode, + }; + self.validate_current_round_proposal( + block_info_validation, + proposal_init.proposer, + timeout, + self.config.validate_proposal_margin, + content_receiver, + fin_sender, + ) + .await; + fin_receiver + } + } + } + + async fn repropose(&mut self, id: ProposalCommitment, init: ProposalInit) { + info!(?id, ?init, "Reproposing."); + let height = init.height; + let (block_info, txs, _) = self + .valid_proposals + .lock() + .expect("Lock on active proposals was poisoned due to a previous panic") + .get(&height) + .unwrap_or_else(|| panic!("No proposals found for height {height}")) + .get(&id) + .unwrap_or_else(|| panic!("No proposal found for height {height} and id {id}")) + .clone(); + + let transaction_converter = self.transaction_converter.clone(); + let mut outbound_proposal_sender = self.outbound_proposal_sender.clone(); + let channel_size = self.config.proposal_buffer_size; + tokio::spawn( + async move { + let (mut proposal_sender, proposal_receiver) = mpsc::channel(channel_size); + let stream_id = HeightAndRound(height.0, init.round); + outbound_proposal_sender + .send((stream_id, proposal_receiver)) + .await + .expect("Failed to send proposal receiver"); + proposal_sender + .send(ProposalPart::Init(init)) + .await + .expect("Failed to send proposal init"); + proposal_sender + .send(ProposalPart::BlockInfo(block_info.clone())) + .await + .expect("Failed to send block info"); + for batch in txs.iter() { + let transactions = futures::future::join_all(batch.iter().map(|tx| { + transaction_converter + .convert_internal_consensus_tx_to_consensus_tx(tx.clone()) + })) + .await + .into_iter() + .collect::, _>>() + .expect("Failed converting transaction during repropose"); + + proposal_sender + .send(ProposalPart::Transactions(TransactionBatch { transactions })) + .await + .expect("Failed to broadcast proposal content"); + } + proposal_sender + .send(ProposalPart::Fin(ProposalFin { proposal_commitment: id })) + .await + .expect("Failed to broadcast proposal fin"); + } + .instrument(error_span!("consensus_repropose", round = init.round)), + ); + } + + async fn validators(&self, _height: BlockNumber) -> Vec { + self.validators.clone() + } + + fn proposer(&self, height: BlockNumber, round: Round) -> ValidatorId { + let height: usize = height.0.try_into().expect("Cannot convert to usize"); + let round: usize = round.try_into().expect("Cannot convert to usize"); + *self + .validators + .get((height + round) % self.validators.len()) + .expect("There should be at least one validator") + } + + async fn broadcast(&mut self, message: Vote) -> Result<(), ConsensusError> { + trace!("Broadcasting message: {message:?}"); + self.vote_broadcast_client.broadcast_message(message).await?; + Ok(()) + } + + async fn decision_reached( + &mut self, + block: ProposalCommitment, + precommits: Vec, + ) -> Result<(), ConsensusError> { + let height = precommits[0].height; + info!("Finished consensus for height: {height}. Agreed on block: {:#064x}", block.0); + + self.interrupt_active_proposal().await; + let proposal_id; + let transactions; + let block_info; + { + let mut proposals = self + .valid_proposals + .lock() + .expect("Lock on active proposals was poisoned due to a previous panic"); + (block_info, transactions, proposal_id) = + proposals.get(&BlockNumber(height)).unwrap().get(&block).unwrap().clone(); + + proposals.retain(|&h, _| h > BlockNumber(height)); + } + let transactions = transactions.concat(); + // TODO(dvir): return from the batcher's 'decision_reached' function the relevant data to + // build a blob. + let DecisionReachedResponse { state_diff, l2_gas_used, central_objects } = self + .batcher + .decision_reached(DecisionReachedInput { proposal_id }) + .await + .expect("Failed to get state diff."); + + let next_l2_gas_price = calculate_next_base_gas_price( + self.l2_gas_price, + l2_gas_used.0, + VersionedConstants::latest_constants().max_block_size / 2, + ); + + let transaction_hashes = + transactions.iter().map(|tx| tx.tx_hash()).collect::>(); + // TODO(Asmaa/Eitan): update with the correct values. + let l1_gas_price = + GasPricePerToken { price_in_fri: GasPrice(1), price_in_wei: GasPrice(1) }; + let l1_data_gas_price = + GasPricePerToken { price_in_fri: GasPrice(1), price_in_wei: GasPrice(1) }; + let sequencer = SequencerContractAddress(ContractAddress::from(123_u128)); + let block_header_without_hash = BlockHeaderWithoutHash { + block_number: BlockNumber(height), + l1_gas_price, + l1_data_gas_price, + l2_gas_price: GasPricePerToken { + price_in_fri: GasPrice(self.l2_gas_price.into()), + price_in_wei: GasPrice(1), + }, + l2_gas_consumed: l2_gas_used.0, + next_l2_gas_price, + sequencer, + ..Default::default() + }; + let sync_block = SyncBlock { + state_diff: state_diff.clone(), + transaction_hashes, + block_header_without_hash, + }; + let state_sync_client = self.state_sync_client.clone(); + // `add_new_block` returns immediately, it doesn't wait for sync to fully process the block. + state_sync_client.add_new_block(sync_block).await.expect("Failed to add new block."); + + self.l2_gas_price = next_l2_gas_price; + + // TODO(dvir): pass here real `BlobParameters` info. + // TODO(dvir): when passing here the correct `BlobParameters`, also test that + // `prepare_blob_for_next_height` is called with the correct parameters. + self.last_block_timestamp = Some(block_info.timestamp); + let _ = self + .cende_ambassador + .prepare_blob_for_next_height(BlobParameters { + block_info: convert_to_sn_api_block_info(block_info), + state_diff, + compressed_state_diff: central_objects.compressed_state_diff, + transactions, + execution_infos: central_objects.execution_infos, + bouncer_weights: central_objects.bouncer_weights, + fee_market_info: FeeMarketInfo { + l2_gas_consumed: l2_gas_used.0, + next_l2_gas_price: self.l2_gas_price, + }, + }) + .await + .inspect_err(|e| { + error!("Failed to prepare blob for next height: {e:?}"); + }); + + Ok(()) + } + + async fn try_sync(&mut self, height: BlockNumber) -> bool { + let sync_block = match self.state_sync_client.get_block(height).await { + Err(e) => { + error!("Sync returned an error: {e:?}"); + return false; + } + Ok(None) => return false, + Ok(Some(block)) => block, + }; + // May be default for blocks older than 0.14.0, ensure min gas price is met. + self.l2_gas_price = max( + sync_block.block_header_without_hash.next_l2_gas_price, + VersionedConstants::latest_constants().min_gas_price, + ); + // TODO(Asmaa): validate starknet_version and parent_hash when they are stored. + let block_number = sync_block.block_header_without_hash.block_number; + let timestamp = sync_block.block_header_without_hash.timestamp; + let now: u64 = + chrono::Utc::now().timestamp().try_into().expect("Failed to convert timestamp to u64"); + if !(block_number == height + && timestamp.0 >= self.last_block_timestamp.unwrap_or(0) + && timestamp.0 <= now + self.config.block_timestamp_window) + { + warn!( + "Invalid block info: expected block number {}, got {}, expected timestamp range \ + [{}, {}], got {}", + height, + block_number, + self.last_block_timestamp.unwrap_or(0), + now + self.config.block_timestamp_window, + timestamp.0, + ); + return false; + } + self.interrupt_active_proposal().await; + self.batcher.add_sync_block(sync_block).await.unwrap(); + true + } + + async fn set_height_and_round(&mut self, height: BlockNumber, round: Round) { + if self.current_height.map(|h| height > h).unwrap_or(true) { + self.current_height = Some(height); + assert_eq!(round, 0); + self.current_round = round; + self.queued_proposals.clear(); + // The Batcher must be told when we begin to work on a new height. The implicit model is + // that consensus works on a given height until it is done (either a decision is reached + // or sync causes us to move on) and then moves on to a different height, never to + // return to the old height. + self.batcher + .start_height(StartHeightInput { height }) + .await + .expect("Batcher should be ready to start the next height"); + return; + } + assert_eq!(Some(height), self.current_height); + if round == self.current_round { + return; + } + assert!(round > self.current_round); + self.interrupt_active_proposal().await; + self.current_round = round; + let mut to_process = None; + while let Some(entry) = self.queued_proposals.first_entry() { + match self.current_round.cmp(entry.key()) { + std::cmp::Ordering::Less => { + entry.remove(); + } + std::cmp::Ordering::Equal => { + to_process = Some(entry.remove()); + break; + } + std::cmp::Ordering::Greater => return, + } + } + // Validate the proposal for the current round if exists. + let Some(((height, validator, timeout, content), fin_sender)) = to_process else { + return; + }; + let block_info_validation = BlockInfoValidation { + height, + block_timestamp_window: self.config.block_timestamp_window, + last_block_timestamp: self.last_block_timestamp, + l1_da_mode: self.l1_da_mode, + }; + self.validate_current_round_proposal( + block_info_validation, + validator, + timeout, + self.config.validate_proposal_margin, + content, + fin_sender, + ) + .await; + } +} + +impl SequencerConsensusContext { + async fn validate_current_round_proposal( + &mut self, + block_info_validation: BlockInfoValidation, + proposer: ValidatorId, + timeout: Duration, + batcher_timeout_margin: Duration, + content_receiver: mpsc::Receiver, + fin_sender: oneshot::Sender<(ProposalCommitment, ProposalFin)>, + ) { + let cancel_token = CancellationToken::new(); + let cancel_token_clone = cancel_token.clone(); + let batcher = Arc::clone(&self.batcher); + let transaction_converter = self.transaction_converter.clone(); + let valid_proposals = Arc::clone(&self.valid_proposals); + let proposal_id = ProposalId(self.proposal_id); + self.proposal_id += 1; + + info!(?timeout, %proposal_id, %proposer, round=self.current_round, "Validating proposal."); + let handle = tokio::spawn( + async move { + validate_proposal(ProposalValidateArguments { + block_info_validation, + proposal_id, + batcher, + timeout, + batcher_timeout_margin, + valid_proposals, + content_receiver, + fin_sender, + cancel_token: cancel_token_clone, + transaction_converter, + }) + .await + } + .instrument( + error_span!("consensus_validate_proposal", %proposal_id, round=self.current_round), + ), + ); + self.active_proposal = Some((cancel_token, handle)); + } + + async fn interrupt_active_proposal(&mut self) { + if let Some((token, handle)) = self.active_proposal.take() { + token.cancel(); + handle.await.expect("Proposal task failed"); + } + } +} + +// Handles building a new proposal without blocking consensus: +async fn build_proposal(mut args: ProposalBuildArguments) { + let block_info = initiate_build(&args).await; + let block_info = match block_info { + Ok(info) => info, + Err(e) => { + error!("Failed to initiate proposal build. {e:?}"); + return; + } + }; + args.proposal_sender + .send(ProposalPart::Init(args.proposal_init)) + .await + .expect("Failed to send proposal init"); + args.proposal_sender + .send(ProposalPart::BlockInfo(block_info.clone())) + .await + .expect("Failed to send block info"); + + let Some((proposal_commitment, content)) = get_proposal_content( + args.proposal_id, + args.batcher.as_ref(), + args.proposal_sender, + args.cende_write_success, + &args.transaction_converter, + args.cancel_token, + ) + .await + else { + return; + }; + + // Update valid_proposals before sending fin to avoid a race condition + // with `repropose` being called before `valid_proposals` is updated. + let mut valid_proposals = args.valid_proposals.lock().expect("Lock was poisoned"); + valid_proposals + .entry(args.proposal_init.height) + .or_default() + .insert(proposal_commitment, (block_info, content, args.proposal_id)); + if args.fin_sender.send(proposal_commitment).is_err() { + // Consensus may exit early (e.g. sync). + warn!("Failed to send proposal content id"); + } +} + +async fn initiate_build(args: &ProposalBuildArguments) -> BuildProposalResult { + let batcher_timeout = chrono::Duration::from_std(args.batcher_timeout) + .expect("Can't convert timeout to chrono::Duration"); + let now = chrono::Utc::now(); + let timestamp = now.timestamp().try_into().expect("Failed to convert timestamp"); + let eth_to_fri_rate = match &args.eth_to_strk_oracle_client { + Some(eth_to_strk_oracle_client) => { + eth_to_strk_oracle_client.eth_to_fri_rate(timestamp).await? + } + None => 1, + }; + // TODO(Asmaa): change this to the real values. + let block_info = ConsensusBlockInfo { + height: args.proposal_init.height, + timestamp, + builder: args.builder_address, + l1_da_mode: args.l1_da_mode, + l2_gas_price_fri: args.gas_prices.strk_gas_prices.l2_gas_price.get().0, + l1_gas_price_wei: args.gas_prices.eth_gas_prices.l1_gas_price.get().0, + l1_data_gas_price_wei: args.gas_prices.eth_gas_prices.l1_data_gas_price.get().0, + eth_to_fri_rate, + }; + let build_proposal_input = ProposeBlockInput { + proposal_id: args.proposal_id, + deadline: now + batcher_timeout, + // TODO(Matan): This is not part of Milestone 1. + retrospective_block_hash: Some(BlockHashAndNumber { + number: BlockNumber::default(), + hash: BlockHash::default(), + }), + block_info: convert_to_sn_api_block_info(block_info.clone()), + }; + // TODO(Matan): Should we be returning an error? + // I think this implies defining an error type in this crate and moving the trait definition + // here also. + debug!("Initiating build proposal: {build_proposal_input:?}"); + args.batcher.propose_block(build_proposal_input).await?; + Ok(block_info) +} + +// 1. Receive chunks of content from the batcher. +// 2. Forward these to the stream handler to be streamed out to the network. +// 3. Once finished, receive the commitment from the batcher. +async fn get_proposal_content( + proposal_id: ProposalId, + batcher: &dyn BatcherClient, + mut proposal_sender: mpsc::Sender, + cende_write_success: AbortOnDropHandle, + transaction_converter: &TransactionConverter, + cancel_token: CancellationToken, +) -> Option<(ProposalCommitment, Vec>)> { + let mut content = Vec::new(); + loop { + if cancel_token.is_cancelled() { + warn!("Proposal interrupted during building."); + return None; + } + // We currently want one part of the node failing to cause all components to fail. If this + // changes, we can simply return None and consider this as a failed proposal which consensus + // should support. + let response = batcher.get_proposal_content(GetProposalContentInput { proposal_id }).await; + let response = match response { + Ok(resp) => resp, + Err(e) => { + error!("Failed to get proposal content. {e:?}"); + return None; + } + }; + + match response.content { + GetProposalContent::Txs(txs) => { + content.push(txs.clone()); + // TODO(matan): Make sure this isn't too large for a single proto message. + debug!( + hashes = ?txs.iter().map(|tx| tx.tx_hash()).collect::>(), + "Sending transaction batch with {} txs.", + txs.len() + ); + let transactions = futures::future::join_all(txs.into_iter().map(|tx| { + transaction_converter.convert_internal_consensus_tx_to_consensus_tx(tx) + })) + .await + .into_iter() + .collect::, _>>(); + let transactions = match transactions { + Ok(txs) => txs, + Err(e) => { + error!("Failed to convert transactions. {e:?}"); + return None; + } + }; + + trace!(?transactions, "Sending transaction batch with {} txs.", transactions.len()); + proposal_sender + .send(ProposalPart::Transactions(TransactionBatch { transactions })) + .await + .expect("Failed to broadcast proposal content"); + } + GetProposalContent::Finished(id) => { + let proposal_commitment = BlockHash(id.state_diff_commitment.0.0); + let num_txs: usize = content.iter().map(|batch| batch.len()).sum(); + info!(?proposal_commitment, num_txs = num_txs, "Finished building proposal",); + + // If the blob writing operation to Aerospike doesn't return a success status, we + // can't finish the proposal. + match cende_write_success.now_or_never() { + Some(Ok(true)) => { + info!("Writing blob to Aerospike completed successfully."); + } + Some(Ok(false)) => { + warn!("Writing blob to Aerospike failed."); + return None; + } + Some(Err(e)) => { + warn!("Writing blob to Aerospike failed. Error: {e:?}"); + return None; + } + None => { + warn!("Writing blob to Aerospike didn't return in time."); + return None; + } + } + + proposal_sender + .send(ProposalPart::Fin(ProposalFin { proposal_commitment })) + .await + .expect("Failed to broadcast proposal fin"); + return Some((proposal_commitment, content)); + } + } + } +} + +async fn validate_proposal(mut args: ProposalValidateArguments) { + let mut content = Vec::new(); + let deadline = tokio::time::Instant::now() + args.timeout; + let Some((block_info, fin_sender)) = await_second_proposal_part( + &args.cancel_token, + deadline, + &mut args.content_receiver, + args.fin_sender, + ) + .await + else { + return; + }; + if !is_block_info_valid(args.block_info_validation.clone(), block_info.clone()).await { + warn!( + "Invalid BlockInfo. block_info_validation={:?}, block_info={:?}", + args.block_info_validation, block_info + ); + return; + } + if let Err(e) = initiate_validation( + args.batcher.as_ref(), + block_info.clone(), + args.proposal_id, + args.timeout + args.batcher_timeout_margin, + ) + .await + { + error!("Failed to initiate proposal validation. {e:?}"); + return; + } + // Validating the rest of the proposal parts. + let (built_block, received_fin) = loop { + tokio::select! { + _ = args.cancel_token.cancelled() => { + warn!("Proposal interrupted during validation."); + batcher_abort_proposal(args.batcher.as_ref(), args.proposal_id).await; + return; + } + _ = tokio::time::sleep_until(deadline) => { + warn!("Validation timed out."); + batcher_abort_proposal(args.batcher.as_ref(), args.proposal_id).await; + return; + } + proposal_part = args.content_receiver.next() => { + match handle_proposal_part( + args.proposal_id, + args.batcher.as_ref(), + proposal_part, + &mut content, + &args.transaction_converter, + ).await { + HandledProposalPart::Finished(built_block, received_fin) => { + break (built_block, received_fin); + } + HandledProposalPart::Continue => {continue;} + HandledProposalPart::Invalid => { + warn!("Invalid proposal."); + // No need to abort since the Batcher is the source of this info. + return; + } + HandledProposalPart::Failed(fail_reason) => { + warn!("Failed to handle proposal part. {fail_reason}"); + batcher_abort_proposal(args.batcher.as_ref(), args.proposal_id).await; + return; + } + } + } + } + }; + + let num_txs: usize = content.iter().map(|batch| batch.len()).sum(); + CONSENSUS_NUM_BATCHES_IN_PROPOSAL.set_lossy(content.len()); + CONSENSUS_NUM_TXS_IN_PROPOSAL.set_lossy(num_txs); + + // Update valid_proposals before sending fin to avoid a race condition + // with `get_proposal` being called before `valid_proposals` is updated. + // TODO(Matan): Consider validating the ProposalFin signature here. + let mut valid_proposals = args.valid_proposals.lock().unwrap(); + valid_proposals + .entry(args.block_info_validation.height) + .or_default() + .insert(built_block, (block_info, content, args.proposal_id)); + if fin_sender.send((built_block, received_fin)).is_err() { + // Consensus may exit early (e.g. sync). + warn!("Failed to send proposal content ids"); + } +} + +async fn is_block_info_valid( + block_info_validation: BlockInfoValidation, + block_info: ConsensusBlockInfo, +) -> bool { + let now: u64 = + chrono::Utc::now().timestamp().try_into().expect("Failed to convert timestamp to u64"); + // TODO(Asmaa): Validate the rest of the block info. + block_info.height == block_info_validation.height + && block_info.timestamp >= block_info_validation.last_block_timestamp.unwrap_or(0) + && block_info.timestamp <= now + block_info_validation.block_timestamp_window + && block_info.l1_da_mode == block_info_validation.l1_da_mode +} + +// The second proposal part when validating a proposal must be: +// 1. Fin - empty proposal. +// 2. BlockInfo - required to begin executing TX batches. +async fn await_second_proposal_part( + cancel_token: &CancellationToken, + deadline: Instant, + content_receiver: &mut mpsc::Receiver, + fin_sender: oneshot::Sender<(ProposalCommitment, ProposalFin)>, +) -> Option<(ConsensusBlockInfo, oneshot::Sender<(ProposalCommitment, ProposalFin)>)> { + tokio::select! { + _ = cancel_token.cancelled() => { + warn!("Proposal interrupted"); + None + } + _ = tokio::time::sleep_until(deadline) => { + warn!("Validation timed out."); + None + } + proposal_part = content_receiver.next() => { + match proposal_part { + Some(ProposalPart::BlockInfo(block_info)) => { + Some((block_info, fin_sender)) + } + Some(ProposalPart::Fin(ProposalFin { proposal_commitment })) => { + warn!("Received an empty proposal."); + if fin_sender + .send((EMPTY_BLOCK_COMMITMENT, ProposalFin { proposal_commitment })) + .is_err() + { + // Consensus may exit early (e.g. sync). + warn!("Failed to send proposal content ids"); + } + None + } + x => { + warn!("Invalid second proposal part: {x:?}"); + None + } + } + } + } +} + +async fn initiate_validation( + batcher: &dyn BatcherClient, + block_info: ConsensusBlockInfo, + proposal_id: ProposalId, + timeout_plus_margin: Duration, +) -> BatcherClientResult<()> { + let chrono_timeout = chrono::Duration::from_std(timeout_plus_margin) + .expect("Can't convert timeout to chrono::Duration"); + let now = chrono::Utc::now(); + let input = ValidateBlockInput { + proposal_id, + deadline: now + chrono_timeout, + // TODO(Matan 3/11/2024): Add the real value of the retrospective block hash. + retrospective_block_hash: Some(BlockHashAndNumber { + number: BlockNumber::default(), + hash: BlockHash::default(), + }), + block_info: convert_to_sn_api_block_info(block_info), + }; + debug!("Initiating validate proposal: input={input:?}"); + batcher.validate_block(input).await +} + +// Handles receiving a proposal from another node without blocking consensus: +// 1. Receives the proposal part from the network. +// 2. Pass this to the batcher. +// 3. Once finished, receive the commitment from the batcher. +async fn handle_proposal_part( + proposal_id: ProposalId, + batcher: &dyn BatcherClient, + proposal_part: Option, + content: &mut Vec>, + transaction_converter: &TransactionConverter, +) -> HandledProposalPart { + match proposal_part { + None => HandledProposalPart::Failed("Failed to receive proposal content".to_string()), + Some(ProposalPart::Fin(ProposalFin { proposal_commitment: id })) => { + // Output this along with the ID from batcher, to compare them. + let input = + SendProposalContentInput { proposal_id, content: SendProposalContent::Finish }; + let response = batcher.send_proposal_content(input).await.unwrap_or_else(|e| { + panic!("Failed to send Fin to batcher: {proposal_id:?}. {e:?}") + }); + let response_id = match response.response { + ProposalStatus::Finished(id) => id, + ProposalStatus::InvalidProposal => { + return HandledProposalPart::Failed("Invalid proposal".to_string()); + } + status => panic!("Unexpected status: for {proposal_id:?}, {status:?}"), + }; + let batcher_block_id = BlockHash(response_id.state_diff_commitment.0.0); + let num_txs: usize = content.iter().map(|batch| batch.len()).sum(); + info!( + network_block_id = ?id, + ?batcher_block_id, + num_txs, + "Finished validating proposal." + ); + HandledProposalPart::Finished(batcher_block_id, ProposalFin { proposal_commitment: id }) + } + Some(ProposalPart::Transactions(TransactionBatch { transactions: txs })) => { + debug!("Received transaction batch with {} txs", txs.len()); + let txs = + futures::future::join_all(txs.into_iter().map(|tx| { + transaction_converter.convert_consensus_tx_to_internal_consensus_tx(tx) + })) + .await + .into_iter() + .collect::, _>>(); + let txs = match txs { + Ok(txs) => txs, + Err(e) => { + return HandledProposalPart::Failed(format!( + "Failed to convert transactions. Stopping the build of the current \ + proposal. {e:?}" + )); + } + }; + debug!("Converted transactions to internal representation."); + + content.push(txs.clone()); + let input = + SendProposalContentInput { proposal_id, content: SendProposalContent::Txs(txs) }; + let response = batcher.send_proposal_content(input).await.unwrap_or_else(|e| { + panic!("Failed to send proposal content to batcher: {proposal_id:?}. {e:?}") + }); + match response.response { + ProposalStatus::Processing => HandledProposalPart::Continue, + ProposalStatus::InvalidProposal => HandledProposalPart::Invalid, + status => panic!("Unexpected status: for {proposal_id:?}, {status:?}"), + } + } + _ => HandledProposalPart::Failed("Invalid proposal part".to_string()), + } +} + +async fn batcher_abort_proposal(batcher: &dyn BatcherClient, proposal_id: ProposalId) { + let input = SendProposalContentInput { proposal_id, content: SendProposalContent::Abort }; + batcher + .send_proposal_content(input) + .await + .unwrap_or_else(|e| panic!("Failed to send Abort to batcher: {proposal_id:?}. {e:?}")); +} + +fn convert_to_sn_api_block_info(block_info: ConsensusBlockInfo) -> starknet_api::block::BlockInfo { + let l1_gas_price = + NonzeroGasPrice::new(GasPrice(block_info.l1_gas_price_wei * block_info.eth_to_fri_rate)) + .unwrap(); + let l1_data_gas_price = NonzeroGasPrice::new(GasPrice( + block_info.l1_data_gas_price_wei * block_info.eth_to_fri_rate, + )) + .unwrap(); + let l2_gas_price = NonzeroGasPrice::new(GasPrice(block_info.l2_gas_price_fri)).unwrap(); + + starknet_api::block::BlockInfo { + block_number: block_info.height, + block_timestamp: BlockTimestamp(block_info.timestamp), + sequencer_address: block_info.builder, + gas_prices: GasPrices { + strk_gas_prices: GasPriceVector { l1_gas_price, l1_data_gas_price, l2_gas_price }, + ..TEMPORARY_GAS_PRICES + }, + use_kzg_da: block_info.l1_da_mode == L1DataAvailabilityMode::Blob, + } +} diff --git a/crates/starknet_consensus_orchestrator/src/sequencer_consensus_context_test.rs b/crates/starknet_consensus_orchestrator/src/sequencer_consensus_context_test.rs new file mode 100644 index 00000000000..f8f3fdd4739 --- /dev/null +++ b/crates/starknet_consensus_orchestrator/src/sequencer_consensus_context_test.rs @@ -0,0 +1,637 @@ +use std::future::ready; +use std::sync::{Arc, OnceLock}; +use std::time::Duration; +use std::vec; + +use futures::channel::oneshot::Canceled; +use futures::channel::{mpsc, oneshot}; +use futures::executor::block_on; +use futures::future::pending; +use futures::{FutureExt, SinkExt, StreamExt}; +use lazy_static::lazy_static; +use papyrus_network::network_manager::test_utils::{ + mock_register_broadcast_topic, + BroadcastNetworkMock, + TestSubscriberChannels, +}; +use papyrus_network::network_manager::BroadcastTopicChannels; +use papyrus_protobuf::consensus::{ + ConsensusBlockInfo, + HeightAndRound, + ProposalFin, + ProposalInit, + ProposalPart, + TransactionBatch, + Vote, +}; +use rstest::rstest; +use starknet_api::block::{BlockHash, BlockNumber}; +use starknet_api::consensus_transaction::{ConsensusTransaction, InternalConsensusTransaction}; +use starknet_api::core::{ChainId, Nonce, StateDiffCommitment}; +use starknet_api::data_availability::L1DataAvailabilityMode; +use starknet_api::felt; +use starknet_api::hash::PoseidonHash; +use starknet_api::test_utils::invoke::{rpc_invoke_tx, InvokeTxArgs}; +use starknet_batcher_types::batcher_types::{ + GetProposalContent, + GetProposalContentResponse, + ProposalCommitment, + ProposalId, + ProposalStatus, + ProposeBlockInput, + SendProposalContent, + SendProposalContentInput, + SendProposalContentResponse, + ValidateBlockInput, +}; +use starknet_batcher_types::communication::{BatcherClientError, MockBatcherClient}; +use starknet_batcher_types::errors::BatcherError; +use starknet_class_manager_types::transaction_converter::{ + TransactionConverter, + TransactionConverterTrait, +}; +use starknet_class_manager_types::EmptyClassManagerClient; +use starknet_consensus::types::{ConsensusContext, Round}; +use starknet_l1_gas_price_types::MockEthToStrkOracleClientTrait; +use starknet_state_sync_types::communication::MockStateSyncClient; +use starknet_types_core::felt::Felt; + +use crate::cende::MockCendeContext; +use crate::config::ContextConfig; +use crate::sequencer_consensus_context::SequencerConsensusContext; + +const TIMEOUT: Duration = Duration::from_millis(1200); +const CHANNEL_SIZE: usize = 5000; +const NUM_VALIDATORS: u64 = 4; +const STATE_DIFF_COMMITMENT: StateDiffCommitment = StateDiffCommitment(PoseidonHash(Felt::ZERO)); +const CHAIN_ID: ChainId = ChainId::Mainnet; +const ETH_TO_FRI_RATE: u128 = 10000; + +lazy_static! { + static ref TX_BATCH: Vec = + (0..3).map(generate_invoke_tx).collect(); + // TODO(shahak): Use MockTransactionConverter instead. + static ref TRANSACTION_CONVERTER: TransactionConverter = + TransactionConverter::new(Arc::new(EmptyClassManagerClient), CHAIN_ID); + static ref INTERNAL_TX_BATCH: Vec = + TX_BATCH.iter().cloned().map(|tx| { + block_on(TRANSACTION_CONVERTER.convert_consensus_tx_to_internal_consensus_tx(tx)).unwrap() + }).collect(); +} + +fn generate_invoke_tx(nonce: u8) -> ConsensusTransaction { + ConsensusTransaction::RpcTransaction(rpc_invoke_tx(InvokeTxArgs { + nonce: Nonce(felt!(nonce)), + ..Default::default() + })) +} + +fn block_info(height: BlockNumber) -> ConsensusBlockInfo { + ConsensusBlockInfo { + height, + timestamp: chrono::Utc::now().timestamp().try_into().expect("Timestamp conversion failed"), + builder: Default::default(), + l1_da_mode: L1DataAvailabilityMode::Blob, + l2_gas_price_fri: 1, + l1_gas_price_wei: 1, + l1_data_gas_price_wei: 1, + eth_to_fri_rate: 1, + } +} +// Structs which aren't utilized but should not be dropped. +struct NetworkDependencies { + _vote_network: BroadcastNetworkMock, + outbound_proposal_receiver: mpsc::Receiver<(HeightAndRound, mpsc::Receiver)>, +} + +fn setup( + batcher: MockBatcherClient, + cende_ambassador: MockCendeContext, + eth_to_strk_oracle_client: MockEthToStrkOracleClientTrait, +) -> (SequencerConsensusContext, NetworkDependencies) { + let (outbound_proposal_sender, outbound_proposal_receiver) = + mpsc::channel::<(HeightAndRound, mpsc::Receiver)>(CHANNEL_SIZE); + // TODO(Asmaa/Matan): remove this. + let TestSubscriberChannels { mock_network: mock_vote_network, subscriber_channels } = + mock_register_broadcast_topic().expect("Failed to create mock network"); + let BroadcastTopicChannels { broadcast_topic_client: votes_topic_client, .. } = + subscriber_channels; + let state_sync_client = MockStateSyncClient::new(); + + let context = SequencerConsensusContext::new( + ContextConfig { + proposal_buffer_size: CHANNEL_SIZE, + num_validators: NUM_VALIDATORS, + chain_id: CHAIN_ID, + ..Default::default() + }, + // TODO(shahak): Use MockTransactionConverter instead. + Arc::new(EmptyClassManagerClient), + Arc::new(state_sync_client), + Arc::new(batcher), + outbound_proposal_sender, + votes_topic_client, + Arc::new(cende_ambassador), + Some(Arc::new(eth_to_strk_oracle_client)), + ); + + let network_dependencies = + NetworkDependencies { _vote_network: mock_vote_network, outbound_proposal_receiver }; + + (context, network_dependencies) +} + +// Setup for test of the `build_proposal` function. +async fn build_proposal_setup( + mock_cende_context: MockCendeContext, +) -> (oneshot::Receiver, SequencerConsensusContext, NetworkDependencies) { + let mut batcher = MockBatcherClient::new(); + let proposal_id = Arc::new(OnceLock::new()); + let proposal_id_clone = Arc::clone(&proposal_id); + batcher.expect_propose_block().returning(move |input: ProposeBlockInput| { + proposal_id_clone.set(input.proposal_id).unwrap(); + Ok(()) + }); + batcher + .expect_start_height() + .withf(|input| input.height == BlockNumber(0)) + .return_once(|_| Ok(())); + let proposal_id_clone = Arc::clone(&proposal_id); + batcher.expect_get_proposal_content().times(1).returning(move |input| { + assert_eq!(input.proposal_id, *proposal_id_clone.get().unwrap()); + Ok(GetProposalContentResponse { + content: GetProposalContent::Txs(INTERNAL_TX_BATCH.clone()), + }) + }); + let proposal_id_clone = Arc::clone(&proposal_id); + batcher.expect_get_proposal_content().times(1).returning(move |input| { + assert_eq!(input.proposal_id, *proposal_id_clone.get().unwrap()); + Ok(GetProposalContentResponse { + content: GetProposalContent::Finished(ProposalCommitment { + state_diff_commitment: STATE_DIFF_COMMITMENT, + }), + }) + }); + + let mut eth_to_strk_oracle_client = MockEthToStrkOracleClientTrait::new(); + eth_to_strk_oracle_client.expect_eth_to_fri_rate().returning(|_| Ok(ETH_TO_FRI_RATE)); + let (mut context, _network) = setup(batcher, mock_cende_context, eth_to_strk_oracle_client); + let init = ProposalInit::default(); + + (context.build_proposal(init, TIMEOUT).await, context, _network) +} + +// Returns a mock CendeContext that will return a successful write_prev_height_blob. +fn success_cende_ammbassador() -> MockCendeContext { + let mut mock_cende = MockCendeContext::new(); + mock_cende.expect_write_prev_height_blob().return_once(|_height| tokio::spawn(ready(true))); + mock_cende +} + +#[tokio::test] +async fn cancelled_proposal_aborts() { + let mut batcher = MockBatcherClient::new(); + batcher.expect_propose_block().return_once(|_| Ok(())); + + batcher.expect_start_height().return_once(|_| Ok(())); + + batcher.expect_get_proposal_content().returning(move |_| { + Ok(GetProposalContentResponse { content: GetProposalContent::Txs(Vec::new()) }) + }); + + let mut mock_eth_to_strk_oracle = MockEthToStrkOracleClientTrait::new(); + mock_eth_to_strk_oracle.expect_eth_to_fri_rate().returning(|_| Ok(ETH_TO_FRI_RATE)); + + let (mut context, _network) = + setup(batcher, success_cende_ammbassador(), mock_eth_to_strk_oracle); + + let fin_receiver = context.build_proposal(ProposalInit::default(), TIMEOUT).await; + + // Now we intrrupt the proposal and verify that the fin_receiever is dropped. + context.set_height_and_round(BlockNumber(0), 1).await; + + assert_eq!(fin_receiver.await, Err(Canceled)); +} + +#[tokio::test] +async fn validate_proposal_success() { + let mut batcher = MockBatcherClient::new(); + let proposal_id: Arc> = Arc::new(OnceLock::new()); + let proposal_id_clone = Arc::clone(&proposal_id); + batcher.expect_validate_block().returning(move |input: ValidateBlockInput| { + proposal_id_clone.set(input.proposal_id).unwrap(); + Ok(()) + }); + batcher + .expect_start_height() + .withf(|input| input.height == BlockNumber(0)) + .return_once(|_| Ok(())); + let proposal_id_clone = Arc::clone(&proposal_id); + batcher.expect_send_proposal_content().times(1).returning( + move |input: SendProposalContentInput| { + assert_eq!(input.proposal_id, *proposal_id_clone.get().unwrap()); + let SendProposalContent::Txs(txs) = input.content else { + panic!("Expected SendProposalContent::Txs, got {:?}", input.content); + }; + assert_eq!(txs, *INTERNAL_TX_BATCH); + Ok(SendProposalContentResponse { response: ProposalStatus::Processing }) + }, + ); + let proposal_id_clone = Arc::clone(&proposal_id); + batcher.expect_send_proposal_content().times(1).returning( + move |input: SendProposalContentInput| { + assert_eq!(input.proposal_id, *proposal_id_clone.get().unwrap()); + assert!(matches!(input.content, SendProposalContent::Finish)); + Ok(SendProposalContentResponse { + response: ProposalStatus::Finished(ProposalCommitment { + state_diff_commitment: STATE_DIFF_COMMITMENT, + }), + }) + }, + ); + let (mut context, _network) = + setup(batcher, success_cende_ammbassador(), MockEthToStrkOracleClientTrait::new()); + + // Initialize the context for a specific height, starting with round 0. + context.set_height_and_round(BlockNumber(0), 0).await; + + let (mut content_sender, content_receiver) = mpsc::channel(context.config.proposal_buffer_size); + content_sender.send(ProposalPart::BlockInfo(block_info(BlockNumber(0)))).await.unwrap(); + content_sender + .send(ProposalPart::Transactions(TransactionBatch { transactions: TX_BATCH.to_vec() })) + .await + .unwrap(); + content_sender + .send(ProposalPart::Fin(ProposalFin { + proposal_commitment: BlockHash(STATE_DIFF_COMMITMENT.0.0), + })) + .await + .unwrap(); + let fin_receiver = + context.validate_proposal(ProposalInit::default(), TIMEOUT, content_receiver).await; + content_sender.close_channel(); + assert_eq!(fin_receiver.await.unwrap().0.0, STATE_DIFF_COMMITMENT.0.0); +} + +#[tokio::test] +async fn dont_send_block_info() { + let mut batcher = MockBatcherClient::new(); + batcher + .expect_start_height() + .withf(|input| input.height == BlockNumber(0)) + .return_once(|_| Ok(())); + let (mut context, _network) = + setup(batcher, success_cende_ammbassador(), MockEthToStrkOracleClientTrait::new()); + + // Initialize the context for a specific height, starting with round 0. + context.set_height_and_round(BlockNumber(0), 0).await; + + let (mut content_sender, content_receiver) = mpsc::channel(context.config.proposal_buffer_size); + let fin_receiver = + context.validate_proposal(ProposalInit::default(), TIMEOUT, content_receiver).await; + content_sender.close_channel(); + // No block info was sent, the proposal is invalid. + assert!(fin_receiver.await.is_err()); +} + +#[tokio::test] +async fn repropose() { + // Receive a proposal. Then re-retrieve it. + let mut batcher = MockBatcherClient::new(); + batcher.expect_validate_block().returning(move |_| Ok(())); + batcher + .expect_start_height() + .withf(|input| input.height == BlockNumber(0)) + .return_once(|_| Ok(())); + batcher.expect_send_proposal_content().times(1).returning( + move |input: SendProposalContentInput| { + assert!(matches!(input.content, SendProposalContent::Txs(_))); + Ok(SendProposalContentResponse { response: ProposalStatus::Processing }) + }, + ); + batcher.expect_send_proposal_content().times(1).returning( + move |input: SendProposalContentInput| { + assert!(matches!(input.content, SendProposalContent::Finish)); + Ok(SendProposalContentResponse { + response: ProposalStatus::Finished(ProposalCommitment { + state_diff_commitment: STATE_DIFF_COMMITMENT, + }), + }) + }, + ); + let (mut context, mut network) = + setup(batcher, success_cende_ammbassador(), MockEthToStrkOracleClientTrait::new()); + + // Initialize the context for a specific height, starting with round 0. + context.set_height_and_round(BlockNumber(0), 0).await; + + // Receive a valid proposal. + let (mut content_sender, content_receiver) = mpsc::channel(context.config.proposal_buffer_size); + let block_info = ProposalPart::BlockInfo(block_info(BlockNumber(0))); + content_sender.send(block_info.clone()).await.unwrap(); + let transactions = + ProposalPart::Transactions(TransactionBatch { transactions: vec![generate_invoke_tx(2)] }); + content_sender.send(transactions.clone()).await.unwrap(); + let fin = ProposalPart::Fin(ProposalFin { + proposal_commitment: BlockHash(STATE_DIFF_COMMITMENT.0.0), + }); + content_sender.send(fin.clone()).await.unwrap(); + let fin_receiver = + context.validate_proposal(ProposalInit::default(), TIMEOUT, content_receiver).await; + content_sender.close_channel(); + assert_eq!(fin_receiver.await.unwrap().0.0, STATE_DIFF_COMMITMENT.0.0); + + let init = ProposalInit { round: 1, ..Default::default() }; + context.repropose(BlockHash(STATE_DIFF_COMMITMENT.0.0), init).await; + let (_, mut receiver) = network.outbound_proposal_receiver.next().await.unwrap(); + assert_eq!(receiver.next().await.unwrap(), ProposalPart::Init(init)); + assert_eq!(receiver.next().await.unwrap(), block_info); + assert_eq!(receiver.next().await.unwrap(), transactions); + assert_eq!(receiver.next().await.unwrap(), fin); + assert!(receiver.next().await.is_none()); +} + +#[tokio::test] +async fn proposals_from_different_rounds() { + let mut batcher = MockBatcherClient::new(); + let proposal_id: Arc> = Arc::new(OnceLock::new()); + let proposal_id_clone = Arc::clone(&proposal_id); + batcher.expect_validate_block().returning(move |input: ValidateBlockInput| { + proposal_id_clone.set(input.proposal_id).unwrap(); + Ok(()) + }); + batcher + .expect_start_height() + .withf(|input| input.height == BlockNumber(0)) + .return_once(|_| Ok(())); + let proposal_id_clone = Arc::clone(&proposal_id); + batcher.expect_send_proposal_content().times(1).returning( + move |input: SendProposalContentInput| { + assert_eq!(input.proposal_id, *proposal_id_clone.get().unwrap()); + let SendProposalContent::Txs(txs) = input.content else { + panic!("Expected SendProposalContent::Txs, got {:?}", input.content); + }; + assert_eq!(txs, *INTERNAL_TX_BATCH); + Ok(SendProposalContentResponse { response: ProposalStatus::Processing }) + }, + ); + let proposal_id_clone = Arc::clone(&proposal_id); + batcher.expect_send_proposal_content().times(1).returning( + move |input: SendProposalContentInput| { + assert_eq!(input.proposal_id, *proposal_id_clone.get().unwrap()); + assert!(matches!(input.content, SendProposalContent::Finish)); + Ok(SendProposalContentResponse { + response: ProposalStatus::Finished(ProposalCommitment { + state_diff_commitment: STATE_DIFF_COMMITMENT, + }), + }) + }, + ); + let (mut context, _network) = + setup(batcher, success_cende_ammbassador(), MockEthToStrkOracleClientTrait::new()); + // Initialize the context for a specific height, starting with round 0. + context.set_height_and_round(BlockNumber(0), 0).await; + context.set_height_and_round(BlockNumber(0), 1).await; + + // Proposal parts sent in the proposals. + let prop_part_txs = + ProposalPart::Transactions(TransactionBatch { transactions: TX_BATCH.to_vec() }); + let prop_part_fin = ProposalPart::Fin(ProposalFin { + proposal_commitment: BlockHash(STATE_DIFF_COMMITMENT.0.0), + }); + + // The proposal from the past round is ignored. + let (mut content_sender, content_receiver) = mpsc::channel(context.config.proposal_buffer_size); + content_sender.send(ProposalPart::BlockInfo(block_info(BlockNumber(0)))).await.unwrap(); + content_sender.send(prop_part_txs.clone()).await.unwrap(); + + let mut init = ProposalInit { round: 0, ..Default::default() }; + let fin_receiver_past_round = context.validate_proposal(init, TIMEOUT, content_receiver).await; + // No fin was sent, channel remains open. + assert!(fin_receiver_past_round.await.is_err()); + + // The proposal from the current round should be validated. + let (mut content_sender, content_receiver) = mpsc::channel(context.config.proposal_buffer_size); + content_sender.send(ProposalPart::BlockInfo(block_info(BlockNumber(0)))).await.unwrap(); + content_sender.send(prop_part_txs.clone()).await.unwrap(); + content_sender.send(prop_part_fin.clone()).await.unwrap(); + init.round = 1; + let fin_receiver_curr_round = context.validate_proposal(init, TIMEOUT, content_receiver).await; + assert_eq!(fin_receiver_curr_round.await.unwrap().0.0, STATE_DIFF_COMMITMENT.0.0); + + // The proposal from the future round should not be processed. + let (mut content_sender, content_receiver) = mpsc::channel(context.config.proposal_buffer_size); + content_sender.send(ProposalPart::BlockInfo(block_info(BlockNumber(0)))).await.unwrap(); + content_sender.send(prop_part_txs.clone()).await.unwrap(); + content_sender.send(prop_part_fin.clone()).await.unwrap(); + let fin_receiver_future_round = context + .validate_proposal( + ProposalInit { round: 2, ..Default::default() }, + TIMEOUT, + content_receiver, + ) + .await; + content_sender.close_channel(); + // Even with sending fin and closing the channel. + assert!(fin_receiver_future_round.now_or_never().is_none()); +} + +#[tokio::test] +async fn interrupt_active_proposal() { + let mut batcher = MockBatcherClient::new(); + batcher + .expect_start_height() + .withf(|input| input.height == BlockNumber(0)) + .return_once(|_| Ok(())); + batcher + .expect_validate_block() + .times(1) + .withf(|input| input.proposal_id == ProposalId(1)) + .returning(|_| Ok(())); + batcher + .expect_send_proposal_content() + .withf(|input| { + input.proposal_id == ProposalId(1) + && input.content == SendProposalContent::Txs(INTERNAL_TX_BATCH.clone()) + }) + .times(1) + .returning(move |_| { + Ok(SendProposalContentResponse { response: ProposalStatus::Processing }) + }); + batcher + .expect_send_proposal_content() + .withf(|input| { + input.proposal_id == ProposalId(1) + && matches!(input.content, SendProposalContent::Finish) + }) + .times(1) + .returning(move |_| { + Ok(SendProposalContentResponse { + response: ProposalStatus::Finished(ProposalCommitment { + state_diff_commitment: STATE_DIFF_COMMITMENT, + }), + }) + }); + let (mut context, _network) = + setup(batcher, success_cende_ammbassador(), MockEthToStrkOracleClientTrait::new()); + // Initialize the context for a specific height, starting with round 0. + context.set_height_and_round(BlockNumber(0), 0).await; + + // Keep the sender open, as closing it or sending Fin would cause the validate to complete + // without needing interrupt. + let (mut _content_sender_0, content_receiver) = + mpsc::channel(context.config.proposal_buffer_size); + let fin_receiver_0 = + context.validate_proposal(ProposalInit::default(), TIMEOUT, content_receiver).await; + + let (mut content_sender_1, content_receiver) = + mpsc::channel(context.config.proposal_buffer_size); + content_sender_1.send(ProposalPart::BlockInfo(block_info(BlockNumber(0)))).await.unwrap(); + content_sender_1 + .send(ProposalPart::Transactions(TransactionBatch { transactions: TX_BATCH.to_vec() })) + .await + .unwrap(); + content_sender_1 + .send(ProposalPart::Fin(ProposalFin { + proposal_commitment: BlockHash(STATE_DIFF_COMMITMENT.0.0), + })) + .await + .unwrap(); + let fin_receiver_1 = context + .validate_proposal( + ProposalInit { round: 1, ..Default::default() }, + TIMEOUT, + content_receiver, + ) + .await; + // Move the context to the next round. + context.set_height_and_round(BlockNumber(0), 1).await; + + // Interrupt active proposal. + assert!(fin_receiver_0.await.is_err()); + assert_eq!(fin_receiver_1.await.unwrap().0.0, STATE_DIFF_COMMITMENT.0.0); +} + +#[tokio::test] +async fn build_proposal() { + let before: u64 = + chrono::Utc::now().timestamp().try_into().expect("Timestamp conversion failed"); + let (fin_receiver, _, mut network) = build_proposal_setup(success_cende_ammbassador()).await; + // Test proposal parts. + let (_, mut receiver) = network.outbound_proposal_receiver.next().await.unwrap(); + assert_eq!(receiver.next().await.unwrap(), ProposalPart::Init(ProposalInit::default())); + let block_info = receiver.next().await.unwrap(); + let after: u64 = + chrono::Utc::now().timestamp().try_into().expect("Timestamp conversion failed"); + let ProposalPart::BlockInfo(info) = block_info else { + panic!("Expected ProposalPart::BlockInfo"); + }; + assert!(info.timestamp >= before && info.timestamp <= after); + assert_eq!(info.eth_to_fri_rate, ETH_TO_FRI_RATE); + assert_eq!( + receiver.next().await.unwrap(), + ProposalPart::Transactions(TransactionBatch { transactions: TX_BATCH.to_vec() }) + ); + assert_eq!( + receiver.next().await.unwrap(), + ProposalPart::Fin(ProposalFin { + proposal_commitment: BlockHash(STATE_DIFF_COMMITMENT.0.0), + }) + ); + assert!(receiver.next().await.is_none()); + assert_eq!(fin_receiver.await.unwrap().0, STATE_DIFF_COMMITMENT.0.0); +} + +#[tokio::test] +async fn build_proposal_cende_failure() { + let mut mock_cende_context = MockCendeContext::new(); + mock_cende_context + .expect_write_prev_height_blob() + .return_once(|_height| tokio::spawn(ready(false))); + + let (fin_receiver, _, _network) = build_proposal_setup(mock_cende_context).await; + + assert_eq!(fin_receiver.await, Err(Canceled)); +} + +#[tokio::test] +async fn build_proposal_cende_incomplete() { + let mut mock_cende_context = MockCendeContext::new(); + mock_cende_context + .expect_write_prev_height_blob() + .return_once(|_height| tokio::spawn(pending())); + + let (fin_receiver, _, _network) = build_proposal_setup(mock_cende_context).await; + + assert_eq!(fin_receiver.await, Err(Canceled)); +} + +#[rstest] +#[case::proposer(true)] +#[case::validator(false)] +#[tokio::test] +async fn batcher_not_ready(#[case] proposer: bool) { + let mut batcher = MockBatcherClient::new(); + batcher.expect_start_height().return_once(|_| Ok(())); + let mut eth_to_strk_oracle_client = MockEthToStrkOracleClientTrait::new(); + if proposer { + eth_to_strk_oracle_client + .expect_eth_to_fri_rate() + .times(1) + .returning(|_| Ok(ETH_TO_FRI_RATE)); + batcher + .expect_propose_block() + .times(1) + .returning(|_| Err(BatcherClientError::BatcherError(BatcherError::NotReady))); + } else { + batcher + .expect_validate_block() + .times(1) + .returning(move |_| Err(BatcherClientError::BatcherError(BatcherError::NotReady))); + } + let (mut context, _network) = + setup(batcher, success_cende_ammbassador(), eth_to_strk_oracle_client); + context.set_height_and_round(BlockNumber::default(), Round::default()).await; + + if proposer { + let fin_receiver = context.build_proposal(ProposalInit::default(), TIMEOUT).await; + assert_eq!(fin_receiver.await, Err(Canceled)); + } else { + let (mut content_sender, content_receiver) = + mpsc::channel(context.config.proposal_buffer_size); + content_sender.send(ProposalPart::BlockInfo(block_info(BlockNumber(0)))).await.unwrap(); + + let fin_receiver = + context.validate_proposal(ProposalInit::default(), TIMEOUT, content_receiver).await; + assert_eq!(fin_receiver.await, Err(Canceled)); + } +} + +#[tokio::test] +async fn propose_then_repropose() { + // Build proposal. + let (fin_receiver, mut context, mut network) = + build_proposal_setup(success_cende_ammbassador()).await; + let (_, mut receiver) = network.outbound_proposal_receiver.next().await.unwrap(); + // Receive the proposal parts. + let _init = receiver.next().await.unwrap(); + let block_info = receiver.next().await.unwrap(); + let txs = receiver.next().await.unwrap(); + let fin = receiver.next().await.unwrap(); + assert_eq!(fin_receiver.await.unwrap().0, STATE_DIFF_COMMITMENT.0.0); + + // Re-propose. + context + .repropose( + BlockHash(STATE_DIFF_COMMITMENT.0.0), + ProposalInit { round: 1, ..Default::default() }, + ) + .await; + // Re-propose sends the same proposal. + let (_, mut receiver) = network.outbound_proposal_receiver.next().await.unwrap(); + let _init = receiver.next().await.unwrap(); + assert_eq!(receiver.next().await.unwrap(), block_info); + assert_eq!(receiver.next().await.unwrap(), txs); + assert_eq!(receiver.next().await.unwrap(), fin); + assert!(receiver.next().await.is_none()); +} diff --git a/crates/starknet_gateway/Cargo.toml b/crates/starknet_gateway/Cargo.toml index 611f9e9b6cf..709559ea318 100644 --- a/crates/starknet_gateway/Cargo.toml +++ b/crates/starknet_gateway/Cargo.toml @@ -9,26 +9,34 @@ version.workspace = true workspace = true [features] -testing = [] +testing = ["blockifier/testing", "blockifier_test_utils"] [dependencies] async-trait.workspace = true axum.workspace = true -blockifier = { workspace = true, features = ["testing"] } +blockifier.workspace = true +blockifier_test_utils = { workspace = true, optional = true } cairo-lang-starknet-classes.workspace = true +futures.workspace = true mempool_test_utils.workspace = true papyrus_config.workspace = true papyrus_network_types.workspace = true +papyrus_proc_macros.workspace = true papyrus_rpc.workspace = true reqwest.workspace = true serde.workspace = true serde_json.workspace = true starknet-types-core.workspace = true starknet_api.workspace = true +starknet_class_manager_types.workspace = true starknet_gateway_types.workspace = true starknet_mempool_types.workspace = true starknet_sequencer_infra.workspace = true -starknet_sierra_compile.workspace = true +starknet_sequencer_metrics.workspace = true +starknet_sierra_multicompile.workspace = true +starknet_state_sync_types.workspace = true +strum.workspace = true +strum_macros.workspace = true thiserror.workspace = true tokio.workspace = true tracing.workspace = true @@ -36,7 +44,12 @@ validator.workspace = true [dev-dependencies] assert_matches.workspace = true +blockifier = { workspace = true, features = ["testing"] } +blockifier_test_utils.workspace = true cairo-lang-sierra-to-casm.workspace = true +criterion = { workspace = true, features = ["async_tokio"] } +metrics.workspace = true +metrics-exporter-prometheus.workspace = true mockall.workspace = true mockito.workspace = true num-bigint.workspace = true @@ -44,6 +57,14 @@ papyrus_network_types = { workspace = true, features = ["testing"] } papyrus_test_utils.workspace = true pretty_assertions.workspace = true rstest.workspace = true +starknet_class_manager_types = { workspace = true, features = ["testing"] } starknet_mempool.workspace = true starknet_mempool_types = { workspace = true, features = ["testing"] } +starknet_state_sync_types = { workspace = true, features = ["testing"] } tracing-test.workspace = true + +[[bench]] +harness = false +name = "starknet_gateway" +path = "benches/main.rs" +required-features = ["testing"] diff --git a/crates/starknet_gateway/benches/main.rs b/crates/starknet_gateway/benches/main.rs new file mode 100644 index 00000000000..d54f0398f33 --- /dev/null +++ b/crates/starknet_gateway/benches/main.rs @@ -0,0 +1,35 @@ +//! Benchmark module for the starknet gateway crate. It provides functionalities to benchmark +//! the performance of the gateway service, including declare, deploy account and invoke +//! transactions. +//! +//! There are four benchmark functions in this flow: `declare_benchmark`, +//! `deploy_account_benchmark`, `invoke_benchmark` and `gateway_benchmark` which combines all of the +//! types. Each of the functions measure the performance of the gateway handling randomly created +//! txs of the respective type. +//! +//! Run the benchmarks using `cargo bench --bench starknet_gateway`. + +// import the Gateway test utilities. +mod utils; + +use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; +use utils::{BenchTestSetup, BenchTestSetupConfig}; + +fn invoke_benchmark(criterion: &mut Criterion) { + let tx_generator_config = BenchTestSetupConfig::default(); + let n_txs = tx_generator_config.n_txs; + + let test_setup = BenchTestSetup::new(tx_generator_config); + criterion.bench_with_input( + BenchmarkId::new("invoke", n_txs), + &test_setup, + |bencher, test_setup| { + bencher + .to_async(tokio::runtime::Runtime::new().unwrap()) + .iter(|| test_setup.send_txs_to_gateway()); + }, + ); +} + +criterion_group!(benches, invoke_benchmark); +criterion_main!(benches); diff --git a/crates/starknet_gateway/benches/utils.rs b/crates/starknet_gateway/benches/utils.rs new file mode 100644 index 00000000000..314c665382e --- /dev/null +++ b/crates/starknet_gateway/benches/utils.rs @@ -0,0 +1,112 @@ +use std::sync::Arc; + +use blockifier::context::ChainInfo; +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; +use blockifier_test_utils::calldata::create_trivial_calldata; +use blockifier_test_utils::contracts::FeatureContract; +use mempool_test_utils::starknet_api_test_utils::test_valid_resource_bounds; +use starknet_api::core::ContractAddress; +use starknet_api::invoke_tx_args; +use starknet_api::rpc_transaction::RpcTransaction; +use starknet_api::test_utils::invoke::rpc_invoke_tx; +use starknet_api::test_utils::NonceManager; +use starknet_class_manager_types::transaction_converter::TransactionConverter; +use starknet_class_manager_types::EmptyClassManagerClient; +use starknet_gateway::config::GatewayConfig; +use starknet_gateway::gateway::Gateway; +use starknet_gateway::state_reader_test_utils::local_test_state_reader_factory; +use starknet_mempool_types::communication::MockMempoolClient; + +const N_TXS: usize = 100; + +// TODO(Arni): Use `AccountTransactionGenerator` from `starknet_api_test_utils`. +struct TransactionGenerator { + nonce_manager: NonceManager, + sender_address: ContractAddress, + test_contract_address: ContractAddress, +} + +impl TransactionGenerator { + fn new(cairo_version: CairoVersion) -> Self { + let account_contract = FeatureContract::AccountWithoutValidations(cairo_version); + let test_contract = FeatureContract::TestContract(cairo_version); + let sender_address = account_contract.get_instance_address(0); + let test_contract_address = test_contract.get_instance_address(0); + Self { nonce_manager: NonceManager::default(), sender_address, test_contract_address } + } + + fn generate_invoke(&mut self) -> RpcTransaction { + let invoke_args = invoke_tx_args!( + nonce: self.nonce_manager.next(self.sender_address), + sender_address: self.sender_address, + resource_bounds: test_valid_resource_bounds(), + calldata: create_trivial_calldata(self.test_contract_address), + ); + rpc_invoke_tx(invoke_args) + } +} + +pub struct BenchTestSetupConfig { + pub n_txs: usize, + pub gateway_config: GatewayConfig, +} + +impl Default for BenchTestSetupConfig { + fn default() -> Self { + Self { + n_txs: N_TXS, + gateway_config: GatewayConfig { + chain_info: ChainInfo::create_for_testing(), + ..Default::default() + }, + } + } +} + +pub struct BenchTestSetup { + gateway: Gateway, + txs: Vec, +} + +impl BenchTestSetup { + pub fn new(config: BenchTestSetupConfig) -> Self { + let cairo_version = CairoVersion::Cairo1(RunnableCairo1::Casm); + let mut tx_generator = TransactionGenerator::new(cairo_version); + + let mut txs: Vec = Vec::with_capacity(config.n_txs); + for _ in 0..config.n_txs { + txs.push(tx_generator. + // TODO(Arni): Do something smarter than generate raw invoke. + generate_invoke()); + } + + let state_reader_factory = local_test_state_reader_factory(cairo_version, false); + let mut mempool_client = MockMempoolClient::new(); + // TODO(noamsp): use MockTransactionConverter + let class_manager_client = Arc::new(EmptyClassManagerClient); + let transaction_converter = TransactionConverter::new( + class_manager_client.clone(), + config.gateway_config.chain_info.chain_id.clone(), + ); + mempool_client.expect_add_tx().returning(|_| Ok(())); + + let gateway_business_logic = Gateway::new( + config.gateway_config, + Arc::new(state_reader_factory), + Arc::new(mempool_client), + transaction_converter, + ); + + Self { gateway: gateway_business_logic, txs } + } + + pub async fn send_txs_to_gateway(&self) { + for tx in &self.txs { + let _tx_hash = self + .gateway + .add_tx(tx.clone(), None) + .await + .expect("Some txs has failed in the gateway."); + } + } +} diff --git a/crates/starknet_gateway/build.rs b/crates/starknet_gateway/build.rs deleted file mode 100644 index 74fc7c9940e..00000000000 --- a/crates/starknet_gateway/build.rs +++ /dev/null @@ -1,3 +0,0 @@ -// Sets up the environment variable OUT_DIR, which holds the cairo compiler binary. -// The binary is downloaded to OUT_DIR by the starknet_sierra_compile crate. -fn main() {} diff --git a/crates/starknet_gateway/src/communication.rs b/crates/starknet_gateway/src/communication.rs index ce592c408e8..1143bc187f0 100644 --- a/crates/starknet_gateway/src/communication.rs +++ b/crates/starknet_gateway/src/communication.rs @@ -3,7 +3,6 @@ use starknet_gateway_types::communication::{GatewayRequest, GatewayResponse}; use starknet_gateway_types::errors::GatewayError; use starknet_sequencer_infra::component_definitions::ComponentRequestHandler; use starknet_sequencer_infra::component_server::{LocalComponentServer, RemoteComponentServer}; -use tracing::instrument; use crate::gateway::Gateway; @@ -12,7 +11,6 @@ pub type RemoteGatewayServer = RemoteComponentServer for Gateway { - #[instrument(skip(self))] async fn handle_request(&mut self, request: GatewayRequest) -> GatewayResponse { match request { GatewayRequest::AddTransaction(gateway_input) => { diff --git a/crates/starknet_gateway/src/compilation.rs b/crates/starknet_gateway/src/compilation.rs deleted file mode 100644 index 5e8a4db1714..00000000000 --- a/crates/starknet_gateway/src/compilation.rs +++ /dev/null @@ -1,67 +0,0 @@ -use std::sync::Arc; - -use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass; -use cairo_lang_starknet_classes::contract_class::ContractClass as CairoLangContractClass; -use starknet_api::contract_class::{ClassInfo, ContractClass}; -use starknet_api::rpc_transaction::RpcDeclareTransaction; -use starknet_gateway_types::errors::GatewaySpecError; -use starknet_sierra_compile::command_line_compiler::CommandLineCompiler; -use starknet_sierra_compile::config::SierraToCasmCompilationConfig; -use starknet_sierra_compile::utils::into_contract_class_for_compilation; -use starknet_sierra_compile::SierraToCasmCompiler; -use tracing::{debug, error}; - -use crate::errors::GatewayResult; - -#[cfg(test)] -#[path = "compilation_test.rs"] -mod compilation_test; - -// TODO(Arni): Pass the compiler with dependancy injection. -#[derive(Clone)] -pub struct GatewayCompiler { - pub sierra_to_casm_compiler: Arc, -} - -impl GatewayCompiler { - pub fn new_command_line_compiler(config: SierraToCasmCompilationConfig) -> Self { - Self { sierra_to_casm_compiler: Arc::new(CommandLineCompiler::new(config)) } - } - - /// Formats the contract class for compilation, compiles it, and returns the compiled contract - /// class wrapped in a [`ClassInfo`]. - /// Assumes the contract class is of a Sierra program which is compiled to Casm. - pub(crate) fn process_declare_tx( - &self, - declare_tx: &RpcDeclareTransaction, - ) -> GatewayResult { - let RpcDeclareTransaction::V3(tx) = declare_tx; - let rpc_contract_class = &tx.contract_class; - let cairo_lang_contract_class = into_contract_class_for_compilation(rpc_contract_class); - - let casm_contract_class = self.compile(cairo_lang_contract_class)?; - - Ok(ClassInfo { - contract_class: ContractClass::V1(casm_contract_class), - sierra_program_length: rpc_contract_class.sierra_program.len(), - abi_length: rpc_contract_class.abi.len(), - }) - } - - fn compile( - &self, - cairo_lang_contract_class: CairoLangContractClass, - ) -> GatewayResult { - match self.sierra_to_casm_compiler.compile(cairo_lang_contract_class) { - Ok(casm_contract_class) => Ok(casm_contract_class), - Err(starknet_sierra_compile::errors::CompilationUtilError::UnexpectedError(error)) => { - error!("Compilation panicked. Error: {:?}", error); - Err(GatewaySpecError::UnexpectedError { data: "Internal server error.".to_owned() }) - } - Err(e) => { - debug!("Compilation failed: {:?}", e); - Err(GatewaySpecError::CompilationFailed) - } - } - } -} diff --git a/crates/starknet_gateway/src/compilation_test.rs b/crates/starknet_gateway/src/compilation_test.rs deleted file mode 100644 index 0958884ee6e..00000000000 --- a/crates/starknet_gateway/src/compilation_test.rs +++ /dev/null @@ -1,83 +0,0 @@ -use assert_matches::assert_matches; -use mempool_test_utils::starknet_api_test_utils::{ - declare_tx as rpc_declare_tx, - COMPILED_CLASS_HASH, -}; -use rstest::{fixture, rstest}; -use starknet_api::rpc_transaction::{ - RpcDeclareTransaction, - RpcDeclareTransactionV3, - RpcTransaction, -}; -use starknet_gateway_types::errors::GatewaySpecError; -use starknet_sierra_compile::config::SierraToCasmCompilationConfig; -use starknet_sierra_compile::errors::CompilationUtilError; -use tracing_test::traced_test; - -use crate::compilation::GatewayCompiler; - -#[fixture] -fn gateway_compiler() -> GatewayCompiler { - GatewayCompiler::new_command_line_compiler(SierraToCasmCompilationConfig::default()) -} - -#[fixture] -fn declare_tx_v3() -> RpcDeclareTransactionV3 { - assert_matches!( - rpc_declare_tx(), - RpcTransaction::Declare(RpcDeclareTransaction::V3(declare_tx)) => declare_tx - ) -} - -// TODO(Arni): Redesign this test once the compiler is passed with dependancy injection. -#[traced_test] -#[rstest] -fn test_compile_contract_class_bytecode_size_validation(declare_tx_v3: RpcDeclareTransactionV3) { - let gateway_compiler = - GatewayCompiler::new_command_line_compiler(SierraToCasmCompilationConfig { - max_bytecode_size: 1, - }); - - let result = gateway_compiler.process_declare_tx(&RpcDeclareTransaction::V3(declare_tx_v3)); - assert_matches!(result.unwrap_err(), GatewaySpecError::CompilationFailed); - let expected_compilation_error = CompilationUtilError::CompilationError( - "Error: Compilation failed.\n\nCaused by:\n Code size limit exceeded.\n".to_owned(), - ); - assert!(logs_contain(format!("Compilation failed: {:?}", expected_compilation_error).as_str())); -} - -#[traced_test] -#[rstest] -fn test_compile_contract_class_bad_sierra( - gateway_compiler: GatewayCompiler, - mut declare_tx_v3: RpcDeclareTransactionV3, -) { - // Truncate the sierra program to trigger an error. - declare_tx_v3.contract_class.sierra_program = - declare_tx_v3.contract_class.sierra_program[..100].to_vec(); - let declare_tx = RpcDeclareTransaction::V3(declare_tx_v3); - - let err = gateway_compiler.process_declare_tx(&declare_tx).unwrap_err(); - assert_eq!(err, GatewaySpecError::CompilationFailed); - - let expected_compilation_error = - CompilationUtilError::CompilationError("Error: Invalid Sierra program.\n".to_owned()); - assert!(logs_contain(format!("Compilation failed: {:?}", expected_compilation_error).as_str())); -} - -#[rstest] -fn test_process_declare_tx_success( - gateway_compiler: GatewayCompiler, - declare_tx_v3: RpcDeclareTransactionV3, -) { - let contract_class = &declare_tx_v3.contract_class; - let sierra_program_length = contract_class.sierra_program.len(); - let abi_length = contract_class.abi.len(); - let declare_tx = RpcDeclareTransaction::V3(declare_tx_v3); - - let class_info = gateway_compiler.process_declare_tx(&declare_tx).unwrap(); - let compiled_class_hash = class_info.contract_class.compiled_class_hash(); - assert_eq!(compiled_class_hash, *COMPILED_CLASS_HASH); - assert_eq!(class_info.sierra_program_length, sierra_program_length); - assert_eq!(class_info.abi_length, abi_length); -} diff --git a/crates/starknet_gateway/src/compiler_version.rs b/crates/starknet_gateway/src/compiler_version.rs index ce6fa55c23f..2b3dbcc6c40 100644 --- a/crates/starknet_gateway/src/compiler_version.rs +++ b/crates/starknet_gateway/src/compiler_version.rs @@ -5,7 +5,7 @@ use cairo_lang_starknet_classes::contract_class::version_id_from_serialized_sier use papyrus_config::dumping::{ser_param, SerializeConfig}; use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; use serde::{Deserialize, Serialize}; -use starknet_sierra_compile::utils::sierra_program_as_felts_to_big_uint_as_hex; +use starknet_sierra_multicompile::utils::sierra_program_as_felts_to_big_uint_as_hex; use starknet_types_core::felt::Felt; use thiserror::Error; diff --git a/crates/starknet_gateway/src/config.rs b/crates/starknet_gateway/src/config.rs index f0e02aee90f..fdae09a2393 100644 --- a/crates/starknet_gateway/src/config.rs +++ b/crates/starknet_gateway/src/config.rs @@ -1,7 +1,7 @@ use std::collections::BTreeMap; +use blockifier::blockifier_versioned_constants::VersionedConstantsOverrides; use blockifier::context::ChainInfo; -use blockifier::versioned_constants::VersionedConstantsOverrides; use papyrus_config::dumping::{append_sub_config_name, ser_param, SerializeConfig}; use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; use serde::{Deserialize, Serialize}; @@ -11,6 +11,8 @@ use validator::Validate; use crate::compiler_version::VersionId; +const JSON_RPC_VERSION: &str = "2.0"; + #[derive(Clone, Debug, Default, Serialize, Deserialize, Validate, PartialEq)] pub struct GatewayConfig { pub stateless_tx_validator_config: StatelessTransactionValidatorConfig, @@ -119,16 +121,28 @@ impl SerializeConfig for StatelessTransactionValidatorConfig { } } -#[derive(Clone, Debug, Default, Serialize, Deserialize, Validate, PartialEq)] +#[derive(Clone, Debug, Serialize, Deserialize, Validate, PartialEq)] pub struct RpcStateReaderConfig { pub url: String, pub json_rpc_version: String, } +impl RpcStateReaderConfig { + pub fn from_url(url: String) -> Self { + Self { url, ..Default::default() } + } +} + +impl Default for RpcStateReaderConfig { + fn default() -> Self { + Self { url: Default::default(), json_rpc_version: JSON_RPC_VERSION.to_string() } + } +} + #[cfg(any(feature = "testing", test))] impl RpcStateReaderConfig { pub fn create_for_testing() -> Self { - Self { url: "http://localhost:8080".to_string(), json_rpc_version: "2.0".to_string() } + Self::from_url("http://localhost:8080".to_string()) } } @@ -148,6 +162,7 @@ impl SerializeConfig for RpcStateReaderConfig { #[derive(Clone, Debug, Serialize, Deserialize, Validate, PartialEq)] pub struct StatefulTransactionValidatorConfig { + pub max_allowed_nonce_gap: u32, pub max_nonce_for_validation_skip: Nonce, pub versioned_constants_overrides: VersionedConstantsOverrides, } @@ -155,6 +170,7 @@ pub struct StatefulTransactionValidatorConfig { impl Default for StatefulTransactionValidatorConfig { fn default() -> Self { StatefulTransactionValidatorConfig { + max_allowed_nonce_gap: 50, max_nonce_for_validation_skip: Nonce(Felt::ONE), versioned_constants_overrides: VersionedConstantsOverrides::default(), } @@ -163,12 +179,20 @@ impl Default for StatefulTransactionValidatorConfig { impl SerializeConfig for StatefulTransactionValidatorConfig { fn dump(&self) -> BTreeMap { - let mut dump = BTreeMap::from_iter([ser_param( - "max_nonce_for_validation_skip", - &self.max_nonce_for_validation_skip, - "Maximum nonce for which the validation is skipped.", - ParamPrivacyInput::Public, - )]); + let mut dump = BTreeMap::from_iter([ + ser_param( + "max_nonce_for_validation_skip", + &self.max_nonce_for_validation_skip, + "Maximum nonce for which the validation is skipped.", + ParamPrivacyInput::Public, + ), + ser_param( + "max_allowed_nonce_gap", + &self.max_allowed_nonce_gap, + "The maximum allowed gap between the account nonce and the transaction nonce.", + ParamPrivacyInput::Public, + ), + ]); dump.append(&mut append_sub_config_name( self.versioned_constants_overrides.dump(), "versioned_constants_overrides", diff --git a/crates/starknet_gateway/src/errors.rs b/crates/starknet_gateway/src/errors.rs index fec0a49de4c..23e59c9b14b 100644 --- a/crates/starknet_gateway/src/errors.rs +++ b/crates/starknet_gateway/src/errors.rs @@ -5,7 +5,10 @@ use starknet_api::block::GasPrice; use starknet_api::transaction::fields::{Resource, ResourceBounds}; use starknet_api::StarknetApiError; use starknet_gateway_types::errors::GatewaySpecError; +use starknet_mempool_types::communication::{MempoolClientError, MempoolClientResult}; +use starknet_mempool_types::errors::MempoolError; use thiserror::Error; +use tracing::{debug, error, warn}; use crate::compiler_version::{VersionId, VersionIdError}; use crate::rpc_objects::{RpcErrorCode, RpcErrorResponse}; @@ -75,6 +78,44 @@ impl From for GatewaySpecError { } } +/// Converts a mempool client result to a gateway result. Some errors variants are unreachable in +/// Gateway context, and some are not considered errors from the gateway's perspective. +pub fn mempool_client_result_to_gw_spec_result( + value: MempoolClientResult<()>, +) -> GatewayResult<()> { + let err = match value { + Ok(()) => return Ok(()), + Err(err) => err, + }; + match err { + MempoolClientError::ClientError(client_error) => { + error!("Mempool client error: {}", client_error); + Err(GatewaySpecError::UnexpectedError { data: "Internal error".to_owned() }) + } + MempoolClientError::MempoolError(mempool_error) => { + debug!("Mempool error: {}", mempool_error); + match mempool_error { + MempoolError::DuplicateNonce { .. } + | MempoolError::NonceTooLarge { .. } + | MempoolError::NonceTooOld { .. } => { + Err(GatewaySpecError::InvalidTransactionNonce) + } + MempoolError::DuplicateTransaction { .. } => Err(GatewaySpecError::DuplicateTx), + MempoolError::P2pPropagatorClientError { .. } => { + // Not an error from the gateway's perspective. + warn!("P2p propagator client error: {}", mempool_error); + Ok(()) + } + MempoolError::TransactionNotFound { .. } => { + // This error is not expected to happen within the gateway, only from other + // mempool clients. + unreachable!("Unexpected mempool error in gateway context: {}", mempool_error); + } + } + } + } +} + pub type StatelessTransactionValidatorResult = Result; pub type StatefulTransactionValidatorResult = Result; diff --git a/crates/starknet_gateway/src/gateway.rs b/crates/starknet_gateway/src/gateway.rs index 5c720b7247a..67f3cb1bba8 100644 --- a/crates/starknet_gateway/src/gateway.rs +++ b/crates/starknet_gateway/src/gateway.rs @@ -1,26 +1,32 @@ use std::clone::Clone; use std::sync::Arc; +use axum::async_trait; use blockifier::context::ChainInfo; use papyrus_network_types::network_types::BroadcastedMessageMetadata; +use papyrus_proc_macros::sequencer_latency_histogram; use starknet_api::executable_transaction::AccountTransaction; use starknet_api::rpc_transaction::RpcTransaction; use starknet_api::transaction::TransactionHash; +use starknet_class_manager_types::transaction_converter::{ + TransactionConverter, + TransactionConverterTrait, +}; +use starknet_class_manager_types::SharedClassManagerClient; use starknet_gateway_types::errors::GatewaySpecError; use starknet_mempool_types::communication::{AddTransactionArgsWrapper, SharedMempoolClient}; use starknet_mempool_types::mempool_types::{AccountState, AddTransactionArgs}; use starknet_sequencer_infra::component_definitions::ComponentStarter; -use starknet_sierra_compile::config::SierraToCasmCompilationConfig; -use tracing::{error, instrument, Span}; +use starknet_state_sync_types::communication::SharedStateSyncClient; +use tracing::{debug, error, instrument, warn, Span}; -use crate::compilation::GatewayCompiler; -use crate::config::{GatewayConfig, RpcStateReaderConfig}; -use crate::errors::GatewayResult; -use crate::rpc_state_reader::RpcStateReaderFactory; +use crate::config::GatewayConfig; +use crate::errors::{mempool_client_result_to_gw_spec_result, GatewayResult}; +use crate::metrics::{register_metrics, GatewayMetricHandle, GATEWAY_ADD_TX_LATENCY}; use crate::state_reader::StateReaderFactory; use crate::stateful_transaction_validator::StatefulTransactionValidator; use crate::stateless_transaction_validator::StatelessTransactionValidator; -use crate::utils::compile_contract_and_build_executable_tx; +use crate::sync_state_reader::SyncStateReaderFactory; #[cfg(test)] #[path = "gateway_test.rs"] @@ -31,8 +37,8 @@ pub struct Gateway { pub stateless_tx_validator: Arc, pub stateful_tx_validator: Arc, pub state_reader_factory: Arc, - pub gateway_compiler: Arc, pub mempool_client: SharedMempoolClient, + pub transaction_converter: TransactionConverter, pub chain_info: ChainInfo, } @@ -40,8 +46,8 @@ impl Gateway { pub fn new( config: GatewayConfig, state_reader_factory: Arc, - gateway_compiler: GatewayCompiler, mempool_client: SharedMempoolClient, + transaction_converter: TransactionConverter, ) -> Self { Self { config: config.clone(), @@ -52,19 +58,25 @@ impl Gateway { config: config.stateful_tx_validator_config.clone(), }), state_reader_factory, - gateway_compiler: Arc::new(gateway_compiler), mempool_client, chain_info: config.chain_info.clone(), + transaction_converter, } } - #[instrument(skip(self))] + #[instrument(skip_all, ret)] + // TODO(Yael): add labels for http/p2p once labels are supported + #[sequencer_latency_histogram(GATEWAY_ADD_TX_LATENCY, true)] pub async fn add_tx( &self, tx: RpcTransaction, p2p_message_metadata: Option, ) -> GatewayResult { - let blocking_task = ProcessTxBlockingTask::new(self, tx); + debug!("Processing tx: {:?}", tx); + let mut metric_counters = GatewayMetricHandle::new(&tx, &p2p_message_metadata); + metric_counters.count_transaction_received(); + + let blocking_task = ProcessTxBlockingTask::new(self, tx, tokio::runtime::Handle::current()); // Run the blocking task in the current span. let curr_span = Span::current(); let add_tx_args = @@ -78,11 +90,11 @@ impl Gateway { let tx_hash = add_tx_args.tx.tx_hash(); let add_tx_args = AddTransactionArgsWrapper { args: add_tx_args, p2p_message_metadata }; - self.mempool_client.add_tx(add_tx_args).await.map_err(|e| { - error!("Failed to send tx to mempool: {}", e); - GatewaySpecError::UnexpectedError { data: "Internal server error".to_owned() } - })?; - // TODO: Also return `ContractAddress` for deploy and `ClassHash` for Declare. + mempool_client_result_to_gw_spec_result(self.mempool_client.add_tx(add_tx_args).await)?; + + metric_counters.transaction_sent_to_mempool(); + + // TODO(AlonH): Also return `ContractAddress` for deploy and `ClassHash` for Declare. Ok(tx_hash) } } @@ -93,36 +105,58 @@ struct ProcessTxBlockingTask { stateless_tx_validator: Arc, stateful_tx_validator: Arc, state_reader_factory: Arc, - gateway_compiler: Arc, + mempool_client: SharedMempoolClient, chain_info: ChainInfo, tx: RpcTransaction, + transaction_converter: TransactionConverter, + runtime: tokio::runtime::Handle, } impl ProcessTxBlockingTask { - pub fn new(gateway: &Gateway, tx: RpcTransaction) -> Self { + pub fn new(gateway: &Gateway, tx: RpcTransaction, runtime: tokio::runtime::Handle) -> Self { Self { stateless_tx_validator: gateway.stateless_tx_validator.clone(), stateful_tx_validator: gateway.stateful_tx_validator.clone(), state_reader_factory: gateway.state_reader_factory.clone(), - gateway_compiler: gateway.gateway_compiler.clone(), + mempool_client: gateway.mempool_client.clone(), chain_info: gateway.chain_info.clone(), tx, + transaction_converter: gateway.transaction_converter.clone(), + runtime, } } + // TODO(Arni): Make into async function and remove all block_on calls once we manage removing + // the spawn_blocking call. fn process_tx(self) -> GatewayResult { // TODO(Arni, 1/5/2024): Perform congestion control. // Perform stateless validations. self.stateless_tx_validator.validate(&self.tx)?; - let executable_tx = compile_contract_and_build_executable_tx( - self.tx, - self.gateway_compiler.as_ref(), - &self.chain_info.chain_id, - )?; - - // Perfom post compilation validations. + let internal_tx = self + .runtime + .block_on(self.transaction_converter.convert_rpc_tx_to_internal_rpc_tx(self.tx)) + .map_err(|err| { + warn!("Failed to convert RPC transaction to internal RPC transaction: {}", err); + GatewaySpecError::UnexpectedError { data: "Internal server error.".to_owned() } + })?; + + let executable_tx = self + .runtime + .block_on( + self.transaction_converter + .convert_internal_rpc_tx_to_executable_tx(internal_tx.clone()), + ) + .map_err(|err| { + warn!( + "Failed to convert internal RPC transaction to executable transaction: {}", + err + ); + GatewaySpecError::UnexpectedError { data: "Internal server error.".to_owned() } + })?; + + // Perform post compilation validations. if let AccountTransaction::Declare(executable_declare_tx) = &executable_tx { if !executable_declare_tx.validate_compiled_class_hash() { return Err(GatewaySpecError::CompiledClassHashMismatch); @@ -138,23 +172,38 @@ impl ProcessTxBlockingTask { GatewaySpecError::UnexpectedError { data: "Internal server error.".to_owned() } })?; - self.stateful_tx_validator.run_validate(&executable_tx, nonce, validator)?; + self.stateful_tx_validator.run_validate( + &executable_tx, + nonce, + self.mempool_client, + validator, + self.runtime, + )?; // TODO(Arni): Add the Sierra and the Casm to the mempool input. - Ok(AddTransactionArgs { tx: executable_tx, account_state: AccountState { address, nonce } }) + Ok(AddTransactionArgs { tx: internal_tx, account_state: AccountState { address, nonce } }) } } pub fn create_gateway( config: GatewayConfig, - rpc_state_reader_config: RpcStateReaderConfig, - compiler_config: SierraToCasmCompilationConfig, + shared_state_sync_client: SharedStateSyncClient, mempool_client: SharedMempoolClient, + class_manager_client: SharedClassManagerClient, ) -> Gateway { - let state_reader_factory = Arc::new(RpcStateReaderFactory { config: rpc_state_reader_config }); - let gateway_compiler = GatewayCompiler::new_command_line_compiler(compiler_config); - - Gateway::new(config, state_reader_factory, gateway_compiler, mempool_client) + let state_reader_factory = Arc::new(SyncStateReaderFactory { + shared_state_sync_client, + class_manager_client: class_manager_client.clone(), + }); + let transaction_converter = + TransactionConverter::new(class_manager_client, config.chain_info.chain_id.clone()); + + Gateway::new(config, state_reader_factory, mempool_client, transaction_converter) } -impl ComponentStarter for Gateway {} +#[async_trait] +impl ComponentStarter for Gateway { + async fn start(&mut self) { + register_metrics(); + } +} diff --git a/crates/starknet_gateway/src/gateway_test.rs b/crates/starknet_gateway/src/gateway_test.rs index c388f886c66..c4b07b0ec8f 100644 --- a/crates/starknet_gateway/src/gateway_test.rs +++ b/crates/starknet_gateway/src/gateway_test.rs @@ -2,27 +2,58 @@ use std::sync::Arc; use assert_matches::assert_matches; use blockifier::context::ChainInfo; -use blockifier::test_utils::CairoVersion; +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; use mempool_test_utils::starknet_api_test_utils::{declare_tx, invoke_tx}; +use metrics_exporter_prometheus::PrometheusBuilder; use mockall::predicate::eq; use papyrus_network_types::network_types::BroadcastedMessageMetadata; use papyrus_test_utils::{get_rng, GetTestInstance}; use rstest::{fixture, rstest}; -use starknet_api::core::{ChainId, CompiledClassHash, ContractAddress}; -use starknet_api::executable_transaction::{AccountTransaction, InvokeTransaction}; -use starknet_api::rpc_transaction::{RpcDeclareTransaction, RpcTransaction}; +use starknet_api::core::{CompiledClassHash, ContractAddress, Nonce}; +use starknet_api::rpc_transaction::{ + InternalRpcTransaction, + InternalRpcTransactionWithoutTxHash, + RpcDeclareTransaction, + RpcTransaction, + RpcTransactionLabelValue, +}; +use starknet_api::test_utils::CHAIN_ID_FOR_TESTS; +use starknet_api::transaction::{ + InvokeTransaction, + TransactionHash, + TransactionHasher, + TransactionVersion, +}; +use starknet_class_manager_types::transaction_converter::TransactionConverter; +use starknet_class_manager_types::{EmptyClassManagerClient, SharedClassManagerClient}; use starknet_gateway_types::errors::GatewaySpecError; -use starknet_mempool_types::communication::{AddTransactionArgsWrapper, MockMempoolClient}; +use starknet_mempool_types::communication::{ + AddTransactionArgsWrapper, + MempoolClientError, + MempoolClientResult, + MockMempoolClient, +}; +use starknet_mempool_types::errors::MempoolError; use starknet_mempool_types::mempool_types::{AccountState, AddTransactionArgs}; -use starknet_sierra_compile::config::SierraToCasmCompilationConfig; +use strum::VariantNames; -use crate::compilation::GatewayCompiler; use crate::config::{ GatewayConfig, StatefulTransactionValidatorConfig, StatelessTransactionValidatorConfig, }; use crate::gateway::Gateway; +use crate::metrics::{ + register_metrics, + GatewayMetricHandle, + SourceLabelValue, + GATEWAY_ADD_TX_LATENCY, + LABEL_NAME_SOURCE, + LABEL_NAME_TX_TYPE, + TRANSACTIONS_FAILED, + TRANSACTIONS_RECEIVED, + TRANSACTIONS_SENT_TO_MEMPOOL, +}; use crate::state_reader_test_utils::{local_test_state_reader_factory, TestStateReaderFactory}; #[fixture] @@ -34,52 +65,50 @@ fn config() -> GatewayConfig { } } -#[fixture] -fn compiler() -> GatewayCompiler { - GatewayCompiler::new_command_line_compiler(SierraToCasmCompilationConfig::default()) -} - #[fixture] fn state_reader_factory() -> TestStateReaderFactory { - local_test_state_reader_factory(CairoVersion::Cairo1, false) + local_test_state_reader_factory(CairoVersion::Cairo1(RunnableCairo1::Casm), false) } #[fixture] fn mock_dependencies( config: GatewayConfig, - compiler: GatewayCompiler, state_reader_factory: TestStateReaderFactory, ) -> MockDependencies { let mock_mempool_client = MockMempoolClient::new(); - MockDependencies { config, compiler, state_reader_factory, mock_mempool_client } + // TODO(noamsp): use MockTransactionConverter + let class_manager_client = Arc::new(EmptyClassManagerClient); + MockDependencies { config, state_reader_factory, mock_mempool_client, class_manager_client } } struct MockDependencies { config: GatewayConfig, - compiler: GatewayCompiler, state_reader_factory: TestStateReaderFactory, mock_mempool_client: MockMempoolClient, + class_manager_client: SharedClassManagerClient, } impl MockDependencies { fn gateway(self) -> Gateway { + register_metrics(); + let chain_id = self.config.chain_info.chain_id.clone(); Gateway::new( self.config, Arc::new(self.state_reader_factory), - self.compiler, Arc::new(self.mock_mempool_client), + TransactionConverter::new(self.class_manager_client, chain_id), ) } - fn expect_add_tx(&mut self, args: AddTransactionArgsWrapper) { - self.mock_mempool_client.expect_add_tx().once().with(eq(args)).return_once(|_| Ok(())); + fn expect_add_tx(&mut self, args: AddTransactionArgsWrapper, result: MempoolClientResult<()>) { + self.mock_mempool_client.expect_add_tx().once().with(eq(args)).return_once(|_| result); } } type SenderAddress = ContractAddress; fn create_tx() -> (RpcTransaction, SenderAddress) { - let tx = invoke_tx(CairoVersion::Cairo1); + let tx = invoke_tx(CairoVersion::Cairo1(RunnableCairo1::Casm)); let sender_address = match &tx { RpcTransaction::Invoke(starknet_api::rpc_transaction::RpcInvokeTransaction::V3( invoke_tx, @@ -89,34 +118,90 @@ fn create_tx() -> (RpcTransaction, SenderAddress) { (tx, sender_address) } -// TODO: add test with Some broadcasted message metadata +// TODO(AlonH): add test with Some broadcasted message metadata +// We use default nonce, address, and tx_hash since Gateway errors drop these details when +// converting Mempool errors. #[rstest] +#[case::successful_transaction_addition(Ok(()), None)] +#[case::duplicate_tx_hash( + Err(MempoolClientError::MempoolError(MempoolError::DuplicateTransaction { tx_hash: TransactionHash::default() })), + Some(GatewaySpecError::DuplicateTx) +)] +#[case::duplicate_nonce( + Err(MempoolClientError::MempoolError(MempoolError::DuplicateNonce { address: ContractAddress::default(), nonce: Nonce::default() })), + Some(GatewaySpecError::InvalidTransactionNonce) +)] +#[case::nonce_too_old( + Err(MempoolClientError::MempoolError(MempoolError::NonceTooOld { address: ContractAddress::default(), nonce: Nonce::default() })), + Some(GatewaySpecError::InvalidTransactionNonce) +)] +#[case::nonce_too_large( + Err(MempoolClientError::MempoolError(MempoolError::NonceTooLarge(Nonce::default()))), + Some(GatewaySpecError::InvalidTransactionNonce) +)] #[tokio::test] -async fn test_add_tx(mut mock_dependencies: MockDependencies) { +async fn test_add_tx( + mut mock_dependencies: MockDependencies, + #[case] expected_result: Result<(), MempoolClientError>, + #[case] expected_error: Option, +) { + let recorder = PrometheusBuilder::new().build_recorder(); + let _recorder_guard = metrics::set_default_local_recorder(&recorder); + let (rpc_tx, address) = create_tx(); let rpc_invoke_tx = assert_matches!(rpc_tx.clone(), RpcTransaction::Invoke(rpc_invoke_tx) => rpc_invoke_tx); - let executable_tx = AccountTransaction::Invoke( - InvokeTransaction::from_rpc_tx(rpc_invoke_tx, &ChainId::create_for_testing()).unwrap(), - ); - let tx_hash = executable_tx.tx_hash(); + let InvokeTransaction::V3(invoke_tx): InvokeTransaction = rpc_invoke_tx.clone().into() else { + panic!("Unexpected transaction version") + }; + + let tx_hash = invoke_tx + .calculate_transaction_hash(&CHAIN_ID_FOR_TESTS, &TransactionVersion::THREE) + .unwrap(); + + let internal_invoke_tx = InternalRpcTransaction { + tx: InternalRpcTransactionWithoutTxHash::Invoke(rpc_invoke_tx), + tx_hash, + }; let p2p_message_metadata = Some(BroadcastedMessageMetadata::get_test_instance(&mut get_rng())); let add_tx_args = AddTransactionArgs { - tx: executable_tx, + tx: internal_invoke_tx, account_state: AccountState { address, nonce: *rpc_tx.nonce() }, }; - mock_dependencies.expect_add_tx(AddTransactionArgsWrapper { - args: add_tx_args, - p2p_message_metadata: p2p_message_metadata.clone(), - }); + mock_dependencies.expect_add_tx( + AddTransactionArgsWrapper { + args: add_tx_args, + p2p_message_metadata: p2p_message_metadata.clone(), + }, + expected_result, + ); let gateway = mock_dependencies.gateway(); - let response_tx_hash = gateway.add_tx(rpc_tx, p2p_message_metadata).await.unwrap(); + let result = gateway.add_tx(rpc_tx.clone(), p2p_message_metadata.clone()).await; - assert_eq!(tx_hash, response_tx_hash); + let metric_counters_for_queries = GatewayMetricHandle::new(&rpc_tx, &p2p_message_metadata); + let metrics = recorder.handle().render(); + assert_eq!(metric_counters_for_queries.get_metric_value(TRANSACTIONS_RECEIVED, &metrics), 1); + match expected_error { + Some(expected_err) => { + assert_eq!( + metric_counters_for_queries.get_metric_value(TRANSACTIONS_FAILED, &metrics), + 1 + ); + assert_eq!(result.unwrap_err(), expected_err); + } + None => { + assert_eq!( + metric_counters_for_queries + .get_metric_value(TRANSACTIONS_SENT_TO_MEMPOOL, &metrics), + 1 + ); + assert_eq!(result.unwrap(), tx_hash); + } + } } // Gateway spec errors tests. @@ -124,9 +209,11 @@ async fn test_add_tx(mut mock_dependencies: MockDependencies) { // result of `add_tx`). // TODO(shahak): Test that when an error occurs in handle_request, then it returns the given p2p // metadata. - +// TODO(noamsp): Remove ignore from compiled_class_hash_mismatch once class manager component is +// implemented. #[rstest] #[tokio::test] +#[ignore] async fn test_compiled_class_hash_mismatch(mock_dependencies: MockDependencies) { let mut declare_tx = assert_matches!(declare_tx(), RpcTransaction::Declare(RpcDeclareTransaction::V3(tx)) => tx); @@ -138,3 +225,32 @@ async fn test_compiled_class_hash_mismatch(mock_dependencies: MockDependencies) let err = gateway.add_tx(tx, None).await.unwrap_err(); assert_matches!(err, GatewaySpecError::CompiledClassHashMismatch); } + +#[test] +fn test_register_metrics() { + let recorder = PrometheusBuilder::new().build_recorder(); + let _recorder_guard = metrics::set_default_local_recorder(&recorder); + register_metrics(); + let metrics = recorder.handle().render(); + for tx_type in RpcTransactionLabelValue::VARIANTS { + for source in SourceLabelValue::VARIANTS { + let labels: &[(&str, &str); 2] = + &[(LABEL_NAME_TX_TYPE, tx_type), (LABEL_NAME_SOURCE, source)]; + + assert_eq!( + TRANSACTIONS_RECEIVED.parse_numeric_metric::(&metrics, labels).unwrap(), + 0 + ); + assert_eq!( + TRANSACTIONS_FAILED.parse_numeric_metric::(&metrics, labels).unwrap(), + 0 + ); + assert_eq!( + TRANSACTIONS_SENT_TO_MEMPOOL.parse_numeric_metric::(&metrics, labels).unwrap(), + 0 + ); + assert_eq!(GATEWAY_ADD_TX_LATENCY.parse_histogram_metric(&metrics).unwrap().sum, 0.0); + assert_eq!(GATEWAY_ADD_TX_LATENCY.parse_histogram_metric(&metrics).unwrap().count, 0); + } + } +} diff --git a/crates/starknet_gateway/src/lib.rs b/crates/starknet_gateway/src/lib.rs index fe5bc05321a..83359e64877 100644 --- a/crates/starknet_gateway/src/lib.rs +++ b/crates/starknet_gateway/src/lib.rs @@ -1,18 +1,20 @@ pub mod communication; -pub mod compilation; mod compiler_version; pub mod config; pub mod errors; pub mod gateway; +pub mod metrics; pub mod rpc_objects; pub mod rpc_state_reader; #[cfg(test)] mod rpc_state_reader_test; pub mod state_reader; -#[cfg(test)] -mod state_reader_test_utils; +#[cfg(any(feature = "testing", test))] +pub mod state_reader_test_utils; mod stateful_transaction_validator; mod stateless_transaction_validator; +mod sync_state_reader; +#[cfg(test)] +mod sync_state_reader_test; #[cfg(test)] mod test_utils; -mod utils; diff --git a/crates/starknet_gateway/src/metrics.rs b/crates/starknet_gateway/src/metrics.rs new file mode 100644 index 00000000000..f03d4071552 --- /dev/null +++ b/crates/starknet_gateway/src/metrics.rs @@ -0,0 +1,93 @@ +use papyrus_network_types::network_types::BroadcastedMessageMetadata; +use starknet_api::rpc_transaction::{RpcTransaction, RpcTransactionLabelValue}; +use starknet_sequencer_metrics::metrics::{LabeledMetricCounter, MetricHistogram}; +use starknet_sequencer_metrics::{define_metrics, generate_permutation_labels}; +use strum::{EnumVariantNames, VariantNames}; +use strum_macros::IntoStaticStr; + +pub const LABEL_NAME_TX_TYPE: &str = "tx_type"; +pub const LABEL_NAME_SOURCE: &str = "source"; + +generate_permutation_labels! { + TRANSACTION_TYPE_AND_SOURCE_LABELS, + (LABEL_NAME_TX_TYPE, RpcTransactionLabelValue), + (LABEL_NAME_SOURCE, SourceLabelValue), +} + +define_metrics!( + Gateway => { + LabeledMetricCounter { TRANSACTIONS_RECEIVED, "gateway_transactions_received", "Counter of transactions received", init = 0 , labels = TRANSACTION_TYPE_AND_SOURCE_LABELS}, + LabeledMetricCounter { TRANSACTIONS_FAILED, "gateway_transactions_failed", "Counter of failed transactions", init = 0 , labels = TRANSACTION_TYPE_AND_SOURCE_LABELS}, + LabeledMetricCounter { TRANSACTIONS_SENT_TO_MEMPOOL, "gateway_transactions_sent_to_mempool", "Counter of transactions sent to the mempool", init = 0 , labels = TRANSACTION_TYPE_AND_SOURCE_LABELS}, + MetricHistogram { GATEWAY_ADD_TX_LATENCY, "gateway_add_tx_latency", "Latency of gateway add_tx function in secs" }, + MetricHistogram { GATEWAY_VALIDATE_TX_LATENCY, "gateway_validate_tx_latency", "Latency of gateway validate function in secs" }, + }, +); + +#[derive(Clone, Copy, Debug, IntoStaticStr, EnumVariantNames)] +#[strum(serialize_all = "snake_case")] +pub enum SourceLabelValue { + Http, + P2p, +} + +enum TransactionStatus { + SentToMempool, + Failed, +} + +pub(crate) struct GatewayMetricHandle { + tx_type: RpcTransactionLabelValue, + source: SourceLabelValue, + tx_status: TransactionStatus, +} + +impl GatewayMetricHandle { + pub fn new( + tx: &RpcTransaction, + p2p_message_metadata: &Option, + ) -> Self { + let tx_type = RpcTransactionLabelValue::from(tx); + let source = match p2p_message_metadata { + Some(_) => SourceLabelValue::P2p, + None => SourceLabelValue::Http, + }; + Self { tx_type, source, tx_status: TransactionStatus::Failed } + } + + fn label(&self) -> Vec<(&'static str, &'static str)> { + vec![(LABEL_NAME_TX_TYPE, self.tx_type.into()), (LABEL_NAME_SOURCE, self.source.into())] + } + + pub fn count_transaction_received(&self) { + TRANSACTIONS_RECEIVED.increment(1, &self.label()); + } + + pub fn transaction_sent_to_mempool(&mut self) { + self.tx_status = TransactionStatus::SentToMempool; + } + + #[cfg(test)] + pub fn get_metric_value(&self, metric_counter: LabeledMetricCounter, metrics: &str) -> u64 { + metric_counter.parse_numeric_metric::(metrics, &self.label()).unwrap() + } +} + +impl Drop for GatewayMetricHandle { + fn drop(&mut self) { + match self.tx_status { + TransactionStatus::SentToMempool => { + TRANSACTIONS_SENT_TO_MEMPOOL.increment(1, &self.label()) + } + TransactionStatus::Failed => TRANSACTIONS_FAILED.increment(1, &self.label()), + } + } +} + +pub(crate) fn register_metrics() { + TRANSACTIONS_RECEIVED.register(); + TRANSACTIONS_FAILED.register(); + TRANSACTIONS_SENT_TO_MEMPOOL.register(); + GATEWAY_ADD_TX_LATENCY.register(); + GATEWAY_VALIDATE_TX_LATENCY.register(); +} diff --git a/crates/starknet_gateway/src/rpc_objects.rs b/crates/starknet_gateway/src/rpc_objects.rs index 9d015fb8627..81b4be46d4a 100644 --- a/crates/starknet_gateway/src/rpc_objects.rs +++ b/crates/starknet_gateway/src/rpc_objects.rs @@ -1,7 +1,15 @@ -use blockifier::blockifier::block::{BlockInfo, GasPrices}; +use blockifier::blockifier::block::validated_gas_prices; use serde::{Deserialize, Serialize}; use serde_json::Value; -use starknet_api::block::{BlockHash, BlockNumber, BlockTimestamp, GasPrice, NonzeroGasPrice}; +use starknet_api::block::{ + BlockHash, + BlockInfo, + BlockNumber, + BlockTimestamp, + GasPrice, + GasPricePerToken, + NonzeroGasPrice, +}; use starknet_api::core::{ClassHash, ContractAddress, GlobalRoot}; use starknet_api::data_availability::L1DataAvailabilityMode; use starknet_api::state::StorageKey; @@ -48,7 +56,7 @@ pub struct GetClassHashAtParams { } #[derive(Serialize, Deserialize)] -pub struct GetCompiledContractClassParams { +pub struct GetCompiledClassParams { pub class_hash: ClassHash, pub block_id: BlockId, } @@ -58,12 +66,6 @@ pub struct GetBlockWithTxHashesParams { pub block_id: BlockId, } -#[derive(Debug, Default, Deserialize, Serialize)] -pub struct ResourcePrice { - pub price_in_wei: GasPrice, - pub price_in_fri: GasPrice, -} - #[derive(Debug, Default, Deserialize, Serialize)] pub struct BlockHeader { pub block_hash: BlockHash, @@ -72,9 +74,9 @@ pub struct BlockHeader { pub sequencer_address: ContractAddress, pub new_root: GlobalRoot, pub timestamp: BlockTimestamp, - pub l1_gas_price: ResourcePrice, - pub l1_data_gas_price: ResourcePrice, - pub l2_gas_price: ResourcePrice, + pub l1_gas_price: GasPricePerToken, + pub l1_data_gas_price: GasPricePerToken, + pub l2_gas_price: GasPricePerToken, pub l1_da_mode: L1DataAvailabilityMode, pub starknet_version: String, } @@ -86,7 +88,7 @@ impl TryInto for BlockHeader { block_number: self.block_number, sequencer_address: self.sequencer_address, block_timestamp: self.timestamp, - gas_prices: GasPrices::new( + gas_prices: validated_gas_prices( parse_gas_price(self.l1_gas_price.price_in_wei)?, parse_gas_price(self.l1_gas_price.price_in_fri)?, parse_gas_price(self.l1_data_gas_price.price_in_wei)?, diff --git a/crates/starknet_gateway/src/rpc_state_reader.rs b/crates/starknet_gateway/src/rpc_state_reader.rs index 57eb41212ca..f9b9da49c97 100644 --- a/crates/starknet_gateway/src/rpc_state_reader.rs +++ b/crates/starknet_gateway/src/rpc_state_reader.rs @@ -1,8 +1,7 @@ -use blockifier::blockifier::block::BlockInfo; use blockifier::execution::contract_class::{ - ContractClassV0, - ContractClassV1, - RunnableContractClass, + CompiledClassV0, + CompiledClassV1, + RunnableCompiledClass, }; use blockifier::state::errors::StateError; use blockifier::state::state_api::{StateReader as BlockifierStateReader, StateResult}; @@ -10,9 +9,11 @@ use papyrus_rpc::CompiledContractClass; use reqwest::blocking::Client as BlockingClient; use serde::Serialize; use serde_json::{json, Value}; -use starknet_api::block::BlockNumber; +use starknet_api::block::{BlockInfo, BlockNumber}; +use starknet_api::contract_class::SierraVersion; use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; use starknet_api::state::StorageKey; +use starknet_state_sync_types::communication::StateSyncClientResult; use starknet_types_core::felt::Felt; use crate::config::RpcStateReaderConfig; @@ -22,7 +23,7 @@ use crate::rpc_objects::{ BlockId, GetBlockWithTxHashesParams, GetClassHashAtParams, - GetCompiledContractClassParams, + GetCompiledClassParams, GetNonceParams, GetStorageAtParams, RpcResponse, @@ -33,6 +34,7 @@ use crate::rpc_objects::{ }; use crate::state_reader::{MempoolStateReader, StateReaderFactory}; +#[derive(Clone)] pub struct RpcStateReader { pub config: RpcStateReaderConfig, pub block_id: BlockId, @@ -139,23 +141,21 @@ impl BlockifierStateReader for RpcStateReader { } } - fn get_compiled_contract_class( - &self, - class_hash: ClassHash, - ) -> StateResult { + fn get_compiled_class(&self, class_hash: ClassHash) -> StateResult { let get_compiled_class_params = - GetCompiledContractClassParams { class_hash, block_id: self.block_id }; + GetCompiledClassParams { class_hash, block_id: self.block_id }; let result = self.send_rpc_request("starknet_getCompiledContractClass", get_compiled_class_params)?; - let contract_class: CompiledContractClass = + let (contract_class, sierra_version): (CompiledContractClass, SierraVersion) = serde_json::from_value(result).map_err(serde_err_to_state_err)?; match contract_class { - CompiledContractClass::V1(contract_class_v1) => Ok(RunnableContractClass::V1( - ContractClassV1::try_from(contract_class_v1).map_err(StateError::ProgramError)?, + CompiledContractClass::V1(contract_class_v1) => Ok(RunnableCompiledClass::V1( + CompiledClassV1::try_from((contract_class_v1, sierra_version)) + .map_err(StateError::ProgramError)?, )), - CompiledContractClass::V0(contract_class_v0) => Ok(RunnableContractClass::V0( - ContractClassV0::try_from(contract_class_v0).map_err(StateError::ProgramError)?, + CompiledContractClass::V0(contract_class_v0) => Ok(RunnableCompiledClass::V0( + CompiledClassV0::try_from(contract_class_v0).map_err(StateError::ProgramError)?, )), } } @@ -186,8 +186,10 @@ pub struct RpcStateReaderFactory { } impl StateReaderFactory for RpcStateReaderFactory { - fn get_state_reader_from_latest_block(&self) -> Box { - Box::new(RpcStateReader::from_latest(&self.config)) + fn get_state_reader_from_latest_block( + &self, + ) -> StateSyncClientResult> { + Ok(Box::new(RpcStateReader::from_latest(&self.config))) } fn get_state_reader(&self, block_number: BlockNumber) -> Box { diff --git a/crates/starknet_gateway/src/rpc_state_reader_test.rs b/crates/starknet_gateway/src/rpc_state_reader_test.rs index 034c9db09c9..07b1fadd947 100644 --- a/crates/starknet_gateway/src/rpc_state_reader_test.rs +++ b/crates/starknet_gateway/src/rpc_state_reader_test.rs @@ -1,10 +1,12 @@ -use blockifier::execution::contract_class::RunnableContractClass; +use blockifier::blockifier::block::validated_gas_prices; +use blockifier::execution::contract_class::RunnableCompiledClass; use blockifier::state::state_api::StateReader; use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass; use papyrus_rpc::CompiledContractClass; use serde::Serialize; use serde_json::json; -use starknet_api::block::BlockNumber; +use starknet_api::block::{BlockInfo, BlockNumber, GasPricePerToken}; +use starknet_api::contract_class::SierraVersion; use starknet_api::{class_hash, contract_address, felt, nonce}; use crate::config::RpcStateReaderConfig; @@ -13,10 +15,9 @@ use crate::rpc_objects::{ BlockId, GetBlockWithTxHashesParams, GetClassHashAtParams, - GetCompiledContractClassParams, + GetCompiledClassParams, GetNonceParams, GetStorageAtParams, - ResourcePrice, RpcResponse, RpcSuccessResponse, }; @@ -54,7 +55,23 @@ async fn test_get_block_info() { let mut server = run_rpc_server().await; let config = RpcStateReaderConfig { url: server.url(), ..Default::default() }; - let expected_result = BlockNumber(100); + // GasPrice must be non-zero. + let l1_gas_price = GasPricePerToken { price_in_wei: 1_u8.into(), price_in_fri: 1_u8.into() }; + let l1_data_gas_price = + GasPricePerToken { price_in_wei: 1_u8.into(), price_in_fri: 1_u8.into() }; + let l2_gas_price = GasPricePerToken { price_in_wei: 1_u8.into(), price_in_fri: 1_u8.into() }; + let gas_prices = validated_gas_prices( + l1_gas_price.price_in_wei.try_into().unwrap(), + l1_gas_price.price_in_fri.try_into().unwrap(), + l1_data_gas_price.price_in_wei.try_into().unwrap(), + l1_data_gas_price.price_in_fri.try_into().unwrap(), + l2_gas_price.price_in_wei.try_into().unwrap(), + l2_gas_price.price_in_fri.try_into().unwrap(), + ); + + let block_number = BlockNumber(100); + + let expected_result = BlockInfo { block_number, gas_prices, ..Default::default() }; let mock = mock_rpc_interaction( &mut server, @@ -63,20 +80,10 @@ async fn test_get_block_info() { GetBlockWithTxHashesParams { block_id: BlockId::Latest }, &RpcResponse::Success(RpcSuccessResponse { result: serde_json::to_value(BlockHeader { - block_number: expected_result, - // GasPrice must be non-zero. - l1_gas_price: ResourcePrice { - price_in_wei: 1_u8.into(), - price_in_fri: 1_u8.into(), - }, - l1_data_gas_price: ResourcePrice { - price_in_wei: 1_u8.into(), - price_in_fri: 1_u8.into(), - }, - l2_gas_price: ResourcePrice { - price_in_wei: 1_u8.into(), - price_in_fri: 1_u8.into(), - }, + block_number, + l1_gas_price, + l1_data_gas_price, + l2_gas_price, ..Default::default() }) .unwrap(), @@ -87,8 +94,7 @@ async fn test_get_block_info() { let client = RpcStateReader::from_latest(&config); let result = tokio::task::spawn_blocking(move || client.get_block_info()).await.unwrap().unwrap(); - // TODO(yair): Add partial_eq for BlockInfo and assert_eq the whole BlockInfo. - assert_eq!(result.block_number, expected_result); + assert_eq!(result, expected_result); mock.assert_async().await; } @@ -153,7 +159,7 @@ async fn test_get_nonce_at() { } #[tokio::test] -async fn test_get_compiled_contract_class() { +async fn test_get_compiled_class() { let mut server = run_rpc_server().await; let config = RpcStateReaderConfig { url: server.url(), ..Default::default() }; @@ -167,28 +173,32 @@ async fn test_get_compiled_contract_class() { entry_points_by_type: Default::default(), }; + let expected_sierra_version = SierraVersion::default(); + let mock = mock_rpc_interaction( &mut server, &config.json_rpc_version, "starknet_getCompiledContractClass", - GetCompiledContractClassParams { - block_id: BlockId::Latest, - class_hash: class_hash!("0x1"), - }, + GetCompiledClassParams { block_id: BlockId::Latest, class_hash: class_hash!("0x1") }, &RpcResponse::Success(RpcSuccessResponse { - result: serde_json::to_value(CompiledContractClass::V1(expected_result.clone())) - .unwrap(), + result: serde_json::to_value(( + CompiledContractClass::V1(expected_result.clone()), + SierraVersion::default(), + )) + .unwrap(), ..Default::default() }), ); let client = RpcStateReader::from_latest(&config); - let result = - tokio::task::spawn_blocking(move || client.get_compiled_contract_class(class_hash!("0x1"))) - .await - .unwrap() - .unwrap(); - assert_eq!(result, RunnableContractClass::V1(expected_result.try_into().unwrap())); + let result = tokio::task::spawn_blocking(move || client.get_compiled_class(class_hash!("0x1"))) + .await + .unwrap() + .unwrap(); + assert_eq!( + result, + RunnableCompiledClass::V1((expected_result, expected_sierra_version).try_into().unwrap()) + ); mock.assert_async().await; } diff --git a/crates/starknet_gateway/src/state_reader.rs b/crates/starknet_gateway/src/state_reader.rs index 993fe4b5d55..11a5acac299 100644 --- a/crates/starknet_gateway/src/state_reader.rs +++ b/crates/starknet_gateway/src/state_reader.rs @@ -1,12 +1,12 @@ -use blockifier::blockifier::block::BlockInfo; -use blockifier::execution::contract_class::RunnableContractClass; +use blockifier::execution::contract_class::RunnableCompiledClass; use blockifier::state::errors::StateError; use blockifier::state::state_api::{StateReader as BlockifierStateReader, StateResult}; #[cfg(test)] use mockall::automock; -use starknet_api::block::BlockNumber; +use starknet_api::block::{BlockInfo, BlockNumber}; use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; use starknet_api::state::StorageKey; +use starknet_state_sync_types::communication::StateSyncClientResult; use starknet_types_core::felt::Felt; pub trait MempoolStateReader: BlockifierStateReader + Send + Sync { @@ -15,7 +15,9 @@ pub trait MempoolStateReader: BlockifierStateReader + Send + Sync { #[cfg_attr(test, automock)] pub trait StateReaderFactory: Send + Sync { - fn get_state_reader_from_latest_block(&self) -> Box; + fn get_state_reader_from_latest_block( + &self, + ) -> StateSyncClientResult>; fn get_state_reader(&self, block_number: BlockNumber) -> Box; } @@ -45,11 +47,8 @@ impl BlockifierStateReader for Box { self.as_ref().get_class_hash_at(contract_address) } - fn get_compiled_contract_class( - &self, - class_hash: ClassHash, - ) -> StateResult { - self.as_ref().get_compiled_contract_class(class_hash) + fn get_compiled_class(&self, class_hash: ClassHash) -> StateResult { + self.as_ref().get_compiled_class(class_hash) } fn get_compiled_class_hash(&self, class_hash: ClassHash) -> StateResult { diff --git a/crates/starknet_gateway/src/state_reader_test_utils.rs b/crates/starknet_gateway/src/state_reader_test_utils.rs index faf1121a530..456db77be04 100644 --- a/crates/starknet_gateway/src/state_reader_test_utils.rs +++ b/crates/starknet_gateway/src/state_reader_test_utils.rs @@ -1,16 +1,17 @@ -use blockifier::blockifier::block::BlockInfo; use blockifier::context::BlockContext; -use blockifier::execution::contract_class::RunnableContractClass; +use blockifier::execution::contract_class::RunnableCompiledClass; use blockifier::state::errors::StateError; use blockifier::state::state_api::{StateReader as BlockifierStateReader, StateResult}; -use blockifier::test_utils::contracts::FeatureContract; use blockifier::test_utils::dict_state_reader::DictStateReader; use blockifier::test_utils::initial_test_state::test_state; -use blockifier::test_utils::{CairoVersion, BALANCE}; -use starknet_api::block::BlockNumber; +use blockifier_test_utils::cairo_versions::CairoVersion; +use blockifier_test_utils::contracts::FeatureContract; +use mempool_test_utils::starknet_api_test_utils::VALID_ACCOUNT_BALANCE; +use starknet_api::block::{BlockInfo, BlockNumber}; use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; use starknet_api::state::StorageKey; use starknet_api::transaction::fields::Fee; +use starknet_state_sync_types::communication::StateSyncClientResult; use starknet_types_core::felt::Felt; use crate::state_reader::{MempoolStateReader, StateReaderFactory}; @@ -44,11 +45,8 @@ impl BlockifierStateReader for TestStateReader { self.blockifier_state_reader.get_class_hash_at(contract_address) } - fn get_compiled_contract_class( - &self, - class_hash: ClassHash, - ) -> StateResult { - self.blockifier_state_reader.get_compiled_contract_class(class_hash) + fn get_compiled_class(&self, class_hash: ClassHash) -> StateResult { + self.blockifier_state_reader.get_compiled_class(class_hash) } fn get_compiled_class_hash(&self, class_hash: ClassHash) -> StateResult { @@ -61,8 +59,10 @@ pub struct TestStateReaderFactory { } impl StateReaderFactory for TestStateReaderFactory { - fn get_state_reader_from_latest_block(&self) -> Box { - Box::new(self.state_reader.clone()) + fn get_state_reader_from_latest_block( + &self, + ) -> StateSyncClientResult> { + Ok(Box::new(self.state_reader.clone())) } fn get_state_reader(&self, _block_number: BlockNumber) -> Box { @@ -75,7 +75,7 @@ pub fn local_test_state_reader_factory( zero_balance: bool, ) -> TestStateReaderFactory { let block_context = BlockContext::create_for_testing(); - let account_balance = if zero_balance { Fee(0) } else { BALANCE }; + let account_balance = if zero_balance { Fee(0) } else { VALID_ACCOUNT_BALANCE }; let account_contract = FeatureContract::AccountWithoutValidations(cairo_version); let test_contract = FeatureContract::TestContract(cairo_version); diff --git a/crates/starknet_gateway/src/stateful_transaction_validator.rs b/crates/starknet_gateway/src/stateful_transaction_validator.rs index ddcbe80e87d..362c8b7bfdc 100644 --- a/crates/starknet_gateway/src/stateful_transaction_validator.rs +++ b/crates/starknet_gateway/src/stateful_transaction_validator.rs @@ -1,26 +1,30 @@ -use blockifier::blockifier::block::BlockInfo; use blockifier::blockifier::stateful_validator::{ StatefulValidator, StatefulValidatorResult as BlockifierStatefulValidatorResult, }; +use blockifier::blockifier_versioned_constants::VersionedConstants; use blockifier::bouncer::BouncerConfig; use blockifier::context::{BlockContext, ChainInfo}; use blockifier::state::cached_state::CachedState; -use blockifier::transaction::account_transaction::AccountTransaction; -use blockifier::versioned_constants::VersionedConstants; +use blockifier::transaction::account_transaction::{AccountTransaction, ExecutionFlags}; +use blockifier::transaction::transactions::enforce_fee; #[cfg(test)] use mockall::automock; -use starknet_api::core::{ContractAddress, Nonce}; +use papyrus_proc_macros::sequencer_latency_histogram; +use starknet_api::block::BlockInfo; +use starknet_api::core::Nonce; use starknet_api::executable_transaction::{ AccountTransaction as ExecutableTransaction, InvokeTransaction as ExecutableInvokeTransaction, }; use starknet_gateway_types::errors::GatewaySpecError; +use starknet_mempool_types::communication::SharedMempoolClient; use starknet_types_core::felt::Felt; use tracing::error; use crate::config::StatefulTransactionValidatorConfig; use crate::errors::StatefulTransactionValidatorResult; +use crate::metrics::GATEWAY_VALIDATE_TX_LATENCY; use crate::state_reader::{MempoolStateReader, StateReaderFactory}; #[cfg(test)] @@ -36,48 +40,40 @@ type BlockifierStatefulValidator = StatefulValidator // TODO(yair): move the trait to Blockifier. #[cfg_attr(test, automock)] pub trait StatefulTransactionValidatorTrait { - fn validate( - &mut self, - account_tx: AccountTransaction, - skip_validate: bool, - ) -> BlockifierStatefulValidatorResult<()>; - - fn get_nonce( - &mut self, - account_address: ContractAddress, - ) -> BlockifierStatefulValidatorResult; + fn validate(&mut self, account_tx: AccountTransaction) + -> BlockifierStatefulValidatorResult<()>; } impl StatefulTransactionValidatorTrait for BlockifierStatefulValidator { + #[sequencer_latency_histogram(GATEWAY_VALIDATE_TX_LATENCY, true)] fn validate( &mut self, account_tx: AccountTransaction, - skip_validate: bool, ) -> BlockifierStatefulValidatorResult<()> { - self.perform_validations(account_tx, skip_validate) - } - - fn get_nonce( - &mut self, - account_address: ContractAddress, - ) -> BlockifierStatefulValidatorResult { - self.get_nonce(account_address) + self.perform_validations(account_tx) } } impl StatefulTransactionValidator { - // TODO(Arni): consider separating validation from transaction conversion, as transaction - // conversion is also relevant for the Mempool. pub fn run_validate( &self, executable_tx: &ExecutableTransaction, account_nonce: Nonce, + mempool_client: SharedMempoolClient, mut validator: V, + runtime: tokio::runtime::Handle, ) -> StatefulTransactionValidatorResult<()> { - let skip_validate = skip_stateful_validations(executable_tx, account_nonce); - let account_tx = AccountTransaction::new(executable_tx.clone()); + let skip_validate = + skip_stateful_validations(executable_tx, account_nonce, mempool_client, runtime)?; + let only_query = false; + let charge_fee = enforce_fee(executable_tx, only_query); + let strict_nonce_check = false; + let execution_flags = + ExecutionFlags { only_query, charge_fee, validate: !skip_validate, strict_nonce_check }; + + let account_tx = AccountTransaction { tx: executable_tx.clone(), execution_flags }; validator - .validate(account_tx, skip_validate) + .validate(account_tx) .map_err(|err| GatewaySpecError::ValidationFailure { data: err.to_string() })?; Ok(()) } @@ -110,25 +106,39 @@ impl StatefulTransactionValidator { } } -// Check if validation of an invoke transaction should be skipped due to deploy_account not being -// proccessed yet. This feature is used to improve UX for users sending deploy_account + invoke at -// once. -fn skip_stateful_validations(tx: &ExecutableTransaction, account_nonce: Nonce) -> bool { - match tx { - ExecutableTransaction::Invoke(ExecutableInvokeTransaction { tx, .. }) => { - // check if the transaction nonce is 1, meaning it is post deploy_account, and the - // account nonce is zero, meaning the account was not deployed yet. The mempool also - // verifies that the deploy_account transaction exists. - tx.nonce() == Nonce(Felt::ONE) && account_nonce == Nonce(Felt::ZERO) +/// Check if validation of an invoke transaction should be skipped due to deploy_account not being +/// processed yet. This feature is used to improve UX for users sending deploy_account + invoke at +/// once. +fn skip_stateful_validations( + tx: &ExecutableTransaction, + account_nonce: Nonce, + mempool_client: SharedMempoolClient, + runtime: tokio::runtime::Handle, +) -> StatefulTransactionValidatorResult { + if let ExecutableTransaction::Invoke(ExecutableInvokeTransaction { tx, .. }) = tx { + // check if the transaction nonce is 1, meaning it is post deploy_account, and the + // account nonce is zero, meaning the account was not deployed yet. + if tx.nonce() == Nonce(Felt::ONE) && account_nonce == Nonce(Felt::ZERO) { + // We verify that a deploy_account transaction exists for this account. It is sufficient + // to check if the account exists in the mempool since it means that either it has a + // deploy_account transaction or transactions with future nonces that passed + // validations. + return runtime.block_on(mempool_client.account_tx_in_pool_or_recent_block(tx.sender_address())) + // TODO(Arni): consider using mempool_client_result_to_gw_spec_result for error handling. + .map_err(|err| GatewaySpecError::UnexpectedError { data: err.to_string() }); } - ExecutableTransaction::DeployAccount(_) | ExecutableTransaction::Declare(_) => false, } + + Ok(false) } pub fn get_latest_block_info( state_reader_factory: &dyn StateReaderFactory, ) -> StatefulTransactionValidatorResult { - let state_reader = state_reader_factory.get_state_reader_from_latest_block(); + let state_reader = state_reader_factory.get_state_reader_from_latest_block().map_err(|e| { + error!("Failed to get state reader from latest block: {}", e); + GatewaySpecError::UnexpectedError { data: "Internal server error.".to_owned() } + })?; state_reader.get_block_info().map_err(|e| { error!("Failed to get latest block info: {}", e); GatewaySpecError::UnexpectedError { data: "Internal server error.".to_owned() } diff --git a/crates/starknet_gateway/src/stateful_transaction_validator_test.rs b/crates/starknet_gateway/src/stateful_transaction_validator_test.rs index ad1210a1ac2..a29491d012b 100644 --- a/crates/starknet_gateway/src/stateful_transaction_validator_test.rs +++ b/crates/starknet_gateway/src/stateful_transaction_validator_test.rs @@ -1,10 +1,12 @@ +use std::sync::Arc; + use blockifier::blockifier::stateful_validator::{ StatefulValidatorError as BlockifierStatefulValidatorError, StatefulValidatorResult as BlockifierStatefulValidatorResult, }; use blockifier::context::ChainInfo; -use blockifier::test_utils::CairoVersion; use blockifier::transaction::errors::{TransactionFeeError, TransactionPreValidationError}; +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; use mempool_test_utils::starknet_api_test_utils::{ executable_invoke_tx as create_executable_invoke_tx, VALID_L1_GAS_MAX_AMOUNT, @@ -18,13 +20,12 @@ use starknet_api::block::GasPrice; use starknet_api::core::Nonce; use starknet_api::executable_transaction::AccountTransaction; use starknet_api::execution_resources::GasAmount; -use starknet_api::test_utils::declare::TEST_SENDER_ADDRESS; use starknet_api::test_utils::deploy_account::executable_deploy_account_tx; use starknet_api::test_utils::invoke::executable_invoke_tx; -use starknet_api::test_utils::NonceManager; use starknet_api::transaction::fields::Resource; use starknet_api::{deploy_account_tx_args, invoke_tx_args, nonce}; use starknet_gateway_types::errors::GatewaySpecError; +use starknet_mempool_types::communication::MockMempoolClient; use crate::config::StatefulTransactionValidatorConfig; use crate::state_reader::{MockStateReaderFactory, StateReaderFactory}; @@ -54,14 +55,15 @@ fn stateful_validator() -> StatefulTransactionValidator { // TODO(Arni): consider testing declare and deploy account. #[rstest] #[case::valid_tx( - create_executable_invoke_tx(CairoVersion::Cairo1), + create_executable_invoke_tx(CairoVersion::Cairo1(RunnableCairo1::Casm)), Ok(()) )] #[case::invalid_tx( - create_executable_invoke_tx(CairoVersion::Cairo1), + create_executable_invoke_tx(CairoVersion::Cairo1(RunnableCairo1::Casm)), Err(STATEFUL_VALIDATOR_FEE_ERROR) )] -fn test_stateful_tx_validator( +#[tokio::test] +async fn test_stateful_tx_validator( #[case] executable_tx: AccountTransaction, #[case] expected_result: BlockifierStatefulValidatorResult<()>, stateful_validator: StatefulTransactionValidator, @@ -74,20 +76,39 @@ fn test_stateful_tx_validator( }); let mut mock_validator = MockStatefulTransactionValidatorTrait::new(); - mock_validator.expect_validate().return_once(|_, _| expected_result.map(|_| ())); + mock_validator.expect_validate().return_once(|_| expected_result.map(|_| ())); let account_nonce = nonce!(0); - let result = stateful_validator.run_validate(&executable_tx, account_nonce, mock_validator); - assert_eq!(result, expected_result_as_stateful_transaction_result); + let mut mock_mempool_client = MockMempoolClient::new(); + mock_mempool_client.expect_account_tx_in_pool_or_recent_block().returning(|_| { + // The mempool does not have any transactions from the sender. + Ok(false) + }); + let mempool_client = Arc::new(mock_mempool_client); + let runtime = tokio::runtime::Handle::current(); + + tokio::task::spawn_blocking(move || { + let result = stateful_validator.run_validate( + &executable_tx, + account_nonce, + mempool_client, + mock_validator, + runtime, + ); + assert_eq!(result, expected_result_as_stateful_transaction_result); + }) + .await + .unwrap(); } #[rstest] fn test_instantiate_validator(stateful_validator: StatefulTransactionValidator) { - let state_reader_factory = local_test_state_reader_factory(CairoVersion::Cairo1, false); + let state_reader_factory = + local_test_state_reader_factory(CairoVersion::Cairo1(RunnableCairo1::Casm), false); let mut mock_state_reader_factory = MockStateReaderFactory::new(); - // Make sure stateful_validator uses the latest block in the initiall call. + // Make sure stateful_validator uses the latest block in the initial call. let latest_state_reader = state_reader_factory.get_state_reader_from_latest_block(); mock_state_reader_factory .expect_get_state_reader_from_latest_block() @@ -109,42 +130,73 @@ fn test_instantiate_validator(stateful_validator: StatefulTransactionValidator) #[rstest] #[case::should_skip_validation( - AccountTransaction::Invoke(executable_invoke_tx(invoke_tx_args!(nonce: nonce!(1)))), + executable_invoke_tx(invoke_tx_args!(nonce: nonce!(1))), + nonce!(0), + true, + false +)] +#[case::should_not_skip_validation_nonce_zero( + executable_invoke_tx(invoke_tx_args!(nonce: nonce!(0))), nonce!(0), + true, true )] -#[case::should_not_skip_validation_nonce_over_max_nonce_for_skip( - AccountTransaction::Invoke(executable_invoke_tx(invoke_tx_args!(nonce: nonce!(0)))), +#[case::should_not_skip_validation_nonce_over_one( + executable_invoke_tx(invoke_tx_args!(nonce: nonce!(2))), nonce!(0), - false + true, + true )] +// TODO(Arni): Fix this test case. Ideally, we would have a non-invoke transaction with tx_nonce 1 +// and account_nonce 0. For deploy account the tx_nonce is always 0. Replace with a declare tx. #[case::should_not_skip_validation_non_invoke( - AccountTransaction::DeployAccount( - executable_deploy_account_tx(deploy_account_tx_args!(), &mut NonceManager::default()) - ), + executable_deploy_account_tx(deploy_account_tx_args!()), nonce!(0), - false) -] + true, + true + +)] #[case::should_not_skip_validation_account_nonce_1( - AccountTransaction::Invoke(executable_invoke_tx( - invoke_tx_args!( - nonce: nonce!(1), - sender_address: TEST_SENDER_ADDRESS.into() - ) - )), + executable_invoke_tx(invoke_tx_args!(nonce: nonce!(1))), nonce!(1), - false + true, + true )] -fn test_skip_stateful_validation( +#[case::should_not_skip_validation_no_tx_in_mempool( + executable_invoke_tx(invoke_tx_args!(nonce: nonce!(1))), + nonce!(0), + false, + true +)] +#[tokio::test] +async fn test_skip_stateful_validation( #[case] executable_tx: AccountTransaction, #[case] sender_nonce: Nonce, - #[case] should_skip_validate: bool, + #[case] contains_tx: bool, + #[case] should_validate: bool, stateful_validator: StatefulTransactionValidator, ) { let mut mock_validator = MockStatefulTransactionValidatorTrait::new(); mock_validator .expect_validate() - .withf(move |_, skip_validate| *skip_validate == should_skip_validate) - .returning(|_, _| Ok(())); - let _ = stateful_validator.run_validate(&executable_tx, sender_nonce, mock_validator); + .withf(move |tx| tx.execution_flags.validate == should_validate) + .returning(|_| Ok(())); + let mut mock_mempool_client = MockMempoolClient::new(); + mock_mempool_client + .expect_account_tx_in_pool_or_recent_block() + .returning(move |_| Ok(contains_tx)); + let mempool_client = Arc::new(mock_mempool_client); + let runtime = tokio::runtime::Handle::current(); + + tokio::task::spawn_blocking(move || { + let _ = stateful_validator.run_validate( + &executable_tx, + sender_nonce, + mempool_client, + mock_validator, + runtime, + ); + }) + .await + .unwrap(); } diff --git a/crates/starknet_gateway/src/stateless_transaction_validator.rs b/crates/starknet_gateway/src/stateless_transaction_validator.rs index 8dbd815540b..871e2a3d3ce 100644 --- a/crates/starknet_gateway/src/stateless_transaction_validator.rs +++ b/crates/starknet_gateway/src/stateless_transaction_validator.rs @@ -237,7 +237,7 @@ impl StatelessTransactionValidator { fn validate_class_length( &self, - contract_class: &starknet_api::rpc_transaction::ContractClass, + contract_class: &starknet_api::state::SierraContractClass, ) -> StatelessTransactionValidatorResult<()> { let contract_class_object_size = serde_json::to_string(&contract_class) .expect("Unexpected error serializing contract class.") @@ -254,7 +254,7 @@ impl StatelessTransactionValidator { fn validate_entry_points_sorted_and_unique( &self, - contract_class: &starknet_api::rpc_transaction::ContractClass, + contract_class: &starknet_api::state::SierraContractClass, ) -> StatelessTransactionValidatorResult<()> { let is_sorted_unique = |entry_points: &[EntryPoint]| { entry_points.windows(2).all(|pair| pair[0].selector < pair[1].selector) diff --git a/crates/starknet_gateway/src/stateless_transaction_validator_test.rs b/crates/starknet_gateway/src/stateless_transaction_validator_test.rs index dd79ded4df7..57319f1d3a6 100644 --- a/crates/starknet_gateway/src/stateless_transaction_validator_test.rs +++ b/crates/starknet_gateway/src/stateless_transaction_validator_test.rs @@ -5,8 +5,8 @@ use assert_matches::assert_matches; use rstest::rstest; use starknet_api::core::{EntryPointSelector, L2_ADDRESS_UPPER_BOUND}; use starknet_api::data_availability::DataAvailabilityMode; -use starknet_api::rpc_transaction::{ContractClass, EntryPointByType}; -use starknet_api::state::EntryPoint; +use starknet_api::rpc_transaction::EntryPointByType; +use starknet_api::state::{EntryPoint, SierraContractClass}; use starknet_api::test_utils::declare::rpc_declare_tx; use starknet_api::transaction::fields::{ AccountDeploymentData, @@ -359,7 +359,7 @@ fn test_declare_sierra_version_failure( let tx_validator = StatelessTransactionValidator { config: DEFAULT_VALIDATOR_CONFIG_FOR_TESTING.clone() }; - let contract_class = ContractClass { sierra_program, ..Default::default() }; + let contract_class = SierraContractClass { sierra_program, ..Default::default() }; let tx = rpc_declare_tx(declare_tx_args!(), contract_class); assert_eq!(tx_validator.validate(&tx).unwrap_err(), expected_error); @@ -379,7 +379,7 @@ fn test_declare_sierra_version_sucsses(#[case] sierra_program: Vec) { let tx_validator = StatelessTransactionValidator { config: DEFAULT_VALIDATOR_CONFIG_FOR_TESTING.clone() }; - let contract_class = ContractClass { sierra_program, ..Default::default() }; + let contract_class = SierraContractClass { sierra_program, ..Default::default() }; let tx = rpc_declare_tx(declare_tx_args!(), contract_class); assert_matches!(tx_validator.validate(&tx), Ok(())); @@ -394,7 +394,7 @@ fn test_declare_contract_class_size_too_long() { ..*DEFAULT_VALIDATOR_CONFIG_FOR_TESTING }, }; - let contract_class = ContractClass { + let contract_class = SierraContractClass { sierra_program: create_sierra_program(&MIN_SIERRA_VERSION), ..Default::default() }; @@ -458,7 +458,7 @@ fn test_declare_entry_points_not_sorted_by_selector( let tx_validator = StatelessTransactionValidator { config: DEFAULT_VALIDATOR_CONFIG_FOR_TESTING.clone() }; - let contract_class = ContractClass { + let contract_class = SierraContractClass { sierra_program: create_sierra_program(&MIN_SIERRA_VERSION), entry_points_by_type: EntryPointByType { constructor: entry_points.clone(), @@ -471,7 +471,7 @@ fn test_declare_entry_points_not_sorted_by_selector( assert_eq!(tx_validator.validate(&tx), expected); - let contract_class = ContractClass { + let contract_class = SierraContractClass { sierra_program: create_sierra_program(&MIN_SIERRA_VERSION), entry_points_by_type: EntryPointByType { constructor: vec![], @@ -484,7 +484,7 @@ fn test_declare_entry_points_not_sorted_by_selector( assert_eq!(tx_validator.validate(&tx), expected); - let contract_class = ContractClass { + let contract_class = SierraContractClass { sierra_program: create_sierra_program(&MIN_SIERRA_VERSION), entry_points_by_type: EntryPointByType { constructor: vec![], diff --git a/crates/starknet_gateway/src/sync_state_reader.rs b/crates/starknet_gateway/src/sync_state_reader.rs new file mode 100644 index 00000000000..871376681ca --- /dev/null +++ b/crates/starknet_gateway/src/sync_state_reader.rs @@ -0,0 +1,164 @@ +use blockifier::execution::contract_class::RunnableCompiledClass; +use blockifier::state::errors::StateError; +use blockifier::state::state_api::{StateReader as BlockifierStateReader, StateResult}; +use futures::executor::block_on; +use starknet_api::block::{BlockInfo, BlockNumber, GasPriceVector, GasPrices}; +use starknet_api::contract_class::ContractClass; +use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; +use starknet_api::data_availability::L1DataAvailabilityMode; +use starknet_api::state::StorageKey; +use starknet_class_manager_types::SharedClassManagerClient; +use starknet_state_sync_types::communication::{ + SharedStateSyncClient, + StateSyncClientError, + StateSyncClientResult, +}; +use starknet_state_sync_types::errors::StateSyncError; +use starknet_types_core::felt::Felt; + +use crate::state_reader::{MempoolStateReader, StateReaderFactory}; + +pub(crate) struct SyncStateReader { + block_number: BlockNumber, + state_sync_client: SharedStateSyncClient, + class_manager_client: SharedClassManagerClient, +} + +impl SyncStateReader { + pub fn from_number( + state_sync_client: SharedStateSyncClient, + class_manager_client: SharedClassManagerClient, + block_number: BlockNumber, + ) -> Self { + Self { block_number, state_sync_client, class_manager_client } + } +} + +impl MempoolStateReader for SyncStateReader { + fn get_block_info(&self) -> StateResult { + let block = block_on(self.state_sync_client.get_block(self.block_number)) + .map_err(|e| StateError::StateReadError(e.to_string()))? + .ok_or(StateError::StateReadError("Block not found".to_string()))?; + + let block_header = block.block_header_without_hash; + let block_info = BlockInfo { + block_number: block_header.block_number, + block_timestamp: block_header.timestamp, + sequencer_address: block_header.sequencer.0, + gas_prices: GasPrices { + eth_gas_prices: GasPriceVector { + l1_gas_price: block_header.l1_gas_price.price_in_wei.try_into()?, + l1_data_gas_price: block_header.l1_data_gas_price.price_in_wei.try_into()?, + l2_gas_price: block_header.l2_gas_price.price_in_wei.try_into()?, + }, + strk_gas_prices: GasPriceVector { + l1_gas_price: block_header.l1_gas_price.price_in_fri.try_into()?, + l1_data_gas_price: block_header.l1_data_gas_price.price_in_fri.try_into()?, + l2_gas_price: block_header.l2_gas_price.price_in_fri.try_into()?, + }, + }, + use_kzg_da: match block_header.l1_da_mode { + L1DataAvailabilityMode::Blob => true, + L1DataAvailabilityMode::Calldata => false, + }, + }; + + Ok(block_info) + } +} + +impl BlockifierStateReader for SyncStateReader { + fn get_storage_at( + &self, + contract_address: ContractAddress, + key: StorageKey, + ) -> StateResult { + let res = block_on(self.state_sync_client.get_storage_at( + self.block_number, + contract_address, + key, + )); + + match res { + Ok(value) => Ok(value), + Err(StateSyncClientError::StateSyncError(StateSyncError::ContractNotFound(_))) => { + Ok(Felt::default()) + } + Err(e) => Err(StateError::StateReadError(e.to_string())), + } + } + + fn get_nonce_at(&self, contract_address: ContractAddress) -> StateResult { + let res = + block_on(self.state_sync_client.get_nonce_at(self.block_number, contract_address)); + + match res { + Ok(value) => Ok(value), + Err(StateSyncClientError::StateSyncError(StateSyncError::ContractNotFound(_))) => { + Ok(Nonce::default()) + } + Err(e) => Err(StateError::StateReadError(e.to_string())), + } + } + + fn get_compiled_class(&self, class_hash: ClassHash) -> StateResult { + let contract_class = block_on(self.class_manager_client.get_executable(class_hash)) + .map_err(|e| StateError::StateReadError(e.to_string()))? + .ok_or(StateError::UndeclaredClassHash(class_hash))?; + + match contract_class { + ContractClass::V1(casm_contract_class) => { + Ok(RunnableCompiledClass::V1(casm_contract_class.try_into()?)) + } + ContractClass::V0(deprecated_contract_class) => { + Ok(RunnableCompiledClass::V0(deprecated_contract_class.try_into()?)) + } + } + } + + fn get_class_hash_at(&self, contract_address: ContractAddress) -> StateResult { + let res = + block_on(self.state_sync_client.get_class_hash_at(self.block_number, contract_address)); + + match res { + Ok(value) => Ok(value), + Err(StateSyncClientError::StateSyncError(StateSyncError::ContractNotFound(_))) => { + Ok(ClassHash::default()) + } + Err(e) => Err(StateError::StateReadError(e.to_string())), + } + } + + fn get_compiled_class_hash(&self, _class_hash: ClassHash) -> StateResult { + todo!() + } +} + +pub struct SyncStateReaderFactory { + pub shared_state_sync_client: SharedStateSyncClient, + pub class_manager_client: SharedClassManagerClient, +} + +impl StateReaderFactory for SyncStateReaderFactory { + fn get_state_reader_from_latest_block( + &self, + ) -> StateSyncClientResult> { + let latest_block_number = + block_on(self.shared_state_sync_client.get_latest_block_number())? + .ok_or(StateSyncClientError::StateSyncError(StateSyncError::EmptyState))?; + + Ok(Box::new(SyncStateReader::from_number( + self.shared_state_sync_client.clone(), + self.class_manager_client.clone(), + latest_block_number, + ))) + } + + fn get_state_reader(&self, block_number: BlockNumber) -> Box { + Box::new(SyncStateReader::from_number( + self.shared_state_sync_client.clone(), + self.class_manager_client.clone(), + block_number, + )) + } +} diff --git a/crates/starknet_gateway/src/sync_state_reader_test.rs b/crates/starknet_gateway/src/sync_state_reader_test.rs new file mode 100644 index 00000000000..97e787ec885 --- /dev/null +++ b/crates/starknet_gateway/src/sync_state_reader_test.rs @@ -0,0 +1,210 @@ +use std::sync::Arc; + +use blockifier::execution::contract_class::RunnableCompiledClass; +use blockifier::state::state_api::StateReader; +use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass; +use mockall::predicate; +use papyrus_test_utils::{get_rng, GetTestInstance}; +use starknet_api::block::{ + BlockHeaderWithoutHash, + BlockInfo, + BlockNumber, + BlockTimestamp, + GasPricePerToken, + GasPriceVector, + GasPrices, + NonzeroGasPrice, +}; +use starknet_api::contract_class::{ContractClass, SierraVersion}; +use starknet_api::core::SequencerContractAddress; +use starknet_api::data_availability::L1DataAvailabilityMode; +use starknet_api::{class_hash, contract_address, felt, nonce, storage_key}; +use starknet_class_manager_types::MockClassManagerClient; +use starknet_state_sync_types::communication::MockStateSyncClient; +use starknet_state_sync_types::state_sync_types::SyncBlock; + +use crate::state_reader::MempoolStateReader; +use crate::sync_state_reader::SyncStateReader; +#[tokio::test] +async fn test_get_block_info() { + let mut mock_state_sync_client = MockStateSyncClient::new(); + let mock_class_manager_client = MockClassManagerClient::new(); + let block_number = BlockNumber(1); + let block_timestamp = BlockTimestamp(2); + let sequencer_address = contract_address!("0x3"); + let l1_gas_price = GasPricePerToken { price_in_wei: 4_u8.into(), price_in_fri: 5_u8.into() }; + let l1_data_gas_price = + GasPricePerToken { price_in_wei: 6_u8.into(), price_in_fri: 7_u8.into() }; + let l2_gas_price = GasPricePerToken { price_in_wei: 8_u8.into(), price_in_fri: 9_u8.into() }; + let l1_da_mode = L1DataAvailabilityMode::get_test_instance(&mut get_rng()); + + mock_state_sync_client.expect_get_block().times(1).with(predicate::eq(block_number)).returning( + move |_| { + Ok(Some(SyncBlock { + state_diff: Default::default(), + transaction_hashes: Default::default(), + block_header_without_hash: BlockHeaderWithoutHash { + block_number, + l1_gas_price, + l1_data_gas_price, + l2_gas_price, + sequencer: SequencerContractAddress(sequencer_address), + timestamp: block_timestamp, + l1_da_mode, + ..Default::default() + }, + })) + }, + ); + + let state_sync_reader = SyncStateReader::from_number( + Arc::new(mock_state_sync_client), + Arc::new(mock_class_manager_client), + block_number, + ); + let result = state_sync_reader.get_block_info().unwrap(); + + assert_eq!( + result, + BlockInfo { + block_number, + block_timestamp, + sequencer_address, + gas_prices: GasPrices { + eth_gas_prices: GasPriceVector { + l1_gas_price: NonzeroGasPrice::new_unchecked(l1_gas_price.price_in_wei), + l1_data_gas_price: NonzeroGasPrice::new_unchecked( + l1_data_gas_price.price_in_wei + ), + l2_gas_price: NonzeroGasPrice::new_unchecked(l2_gas_price.price_in_wei), + }, + strk_gas_prices: GasPriceVector { + l1_gas_price: NonzeroGasPrice::new_unchecked(l1_gas_price.price_in_fri), + l1_data_gas_price: NonzeroGasPrice::new_unchecked( + l1_data_gas_price.price_in_fri + ), + l2_gas_price: NonzeroGasPrice::new_unchecked(l2_gas_price.price_in_fri), + }, + }, + use_kzg_da: match l1_da_mode { + L1DataAvailabilityMode::Blob => true, + L1DataAvailabilityMode::Calldata => false, + }, + } + ); +} + +#[tokio::test] +async fn test_get_storage_at() { + let mut mock_state_sync_client = MockStateSyncClient::new(); + let mock_class_manager_client = MockClassManagerClient::new(); + let block_number = BlockNumber(1); + let contract_address = contract_address!("0x2"); + let storage_key = storage_key!("0x3"); + let value = felt!("0x4"); + mock_state_sync_client + .expect_get_storage_at() + .times(1) + .with( + predicate::eq(block_number), + predicate::eq(contract_address), + predicate::eq(storage_key), + ) + .returning(move |_, _, _| Ok(value)); + + let state_sync_reader = SyncStateReader::from_number( + Arc::new(mock_state_sync_client), + Arc::new(mock_class_manager_client), + block_number, + ); + + let result = state_sync_reader.get_storage_at(contract_address, storage_key).unwrap(); + assert_eq!(result, value); +} + +#[tokio::test] +async fn test_get_nonce_at() { + let mut mock_state_sync_client = MockStateSyncClient::new(); + let mock_class_manager_client = MockClassManagerClient::new(); + let block_number = BlockNumber(1); + let contract_address = contract_address!("0x2"); + let expected_result = nonce!(0x3); + + mock_state_sync_client + .expect_get_nonce_at() + .times(1) + .with(predicate::eq(block_number), predicate::eq(contract_address)) + .returning(move |_, _| Ok(expected_result)); + + let state_sync_reader = SyncStateReader::from_number( + Arc::new(mock_state_sync_client), + Arc::new(mock_class_manager_client), + block_number, + ); + + let result = state_sync_reader.get_nonce_at(contract_address).unwrap(); + assert_eq!(result, expected_result); +} + +#[tokio::test] +async fn test_get_class_hash_at() { + let mut mock_state_sync_client = MockStateSyncClient::new(); + let mock_class_manager_client = MockClassManagerClient::new(); + let block_number = BlockNumber(1); + let contract_address = contract_address!("0x2"); + let expected_result = class_hash!("0x3"); + + mock_state_sync_client + .expect_get_class_hash_at() + .times(1) + .with(predicate::eq(block_number), predicate::eq(contract_address)) + .returning(move |_, _| Ok(expected_result)); + + let state_sync_reader = SyncStateReader::from_number( + Arc::new(mock_state_sync_client), + Arc::new(mock_class_manager_client), + block_number, + ); + + let result = state_sync_reader.get_class_hash_at(contract_address).unwrap(); + assert_eq!(result, expected_result); +} + +// TODO(NoamS): test undeclared class flow (when class manager client returns None). +#[tokio::test] +async fn test_get_compiled_class() { + let mock_state_sync_client = MockStateSyncClient::new(); + let mut mock_class_manager_client = MockClassManagerClient::new(); + let block_number = BlockNumber(1); + let class_hash = class_hash!("0x2"); + let casm_contract_class = CasmContractClass { + compiler_version: "0.0.0".to_string(), + prime: Default::default(), + bytecode: Default::default(), + bytecode_segment_lengths: Default::default(), + hints: Default::default(), + pythonic_hints: Default::default(), + entry_points_by_type: Default::default(), + }; + let expected_result = casm_contract_class.clone(); + + mock_class_manager_client + .expect_get_executable() + .times(1) + .with(predicate::eq(class_hash)) + .returning(move |_| { + Ok(Some(ContractClass::V1((casm_contract_class.clone(), SierraVersion::default())))) + }); + + let state_sync_reader = SyncStateReader::from_number( + Arc::new(mock_state_sync_client), + Arc::new(mock_class_manager_client), + block_number, + ); + + let result = state_sync_reader.get_compiled_class(class_hash).unwrap(); + assert_eq!( + result, + RunnableCompiledClass::V1((expected_result, SierraVersion::default()).try_into().unwrap()) + ); +} diff --git a/crates/starknet_gateway/src/test_utils.rs b/crates/starknet_gateway/src/test_utils.rs index d8866fdffea..f92bb5bce8e 100644 --- a/crates/starknet_gateway/src/test_utils.rs +++ b/crates/starknet_gateway/src/test_utils.rs @@ -2,7 +2,8 @@ use starknet_api::block::GasPrice; use starknet_api::core::ContractAddress; use starknet_api::data_availability::DataAvailabilityMode; use starknet_api::execution_resources::GasAmount; -use starknet_api::rpc_transaction::{ContractClass, RpcTransaction}; +use starknet_api::rpc_transaction::RpcTransaction; +use starknet_api::state::SierraContractClass; use starknet_api::test_utils::declare::{rpc_declare_tx, TEST_SENDER_ADDRESS}; use starknet_api::test_utils::deploy_account::rpc_deploy_account_tx; use starknet_api::test_utils::invoke::rpc_invoke_tx; @@ -89,7 +90,7 @@ pub fn rpc_tx_for_testing( match tx_type { TransactionType::Declare => { // Minimal contract class. - let contract_class = ContractClass { + let contract_class = SierraContractClass { sierra_program: vec![ // Sierra Version ID. felt!(1_u32), diff --git a/crates/starknet_gateway/src/utils.rs b/crates/starknet_gateway/src/utils.rs deleted file mode 100644 index bd6f81405f7..00000000000 --- a/crates/starknet_gateway/src/utils.rs +++ /dev/null @@ -1,78 +0,0 @@ -use starknet_api::core::ChainId; -use starknet_api::executable_transaction::{ - AccountTransaction as ExecutableTransaction, - DeclareTransaction as ExecutableDeclareTransaction, - DeployAccountTransaction as ExecutableDeployAccountTransaction, - InvokeTransaction as ExecutableInvokeTransaction, -}; -use starknet_api::rpc_transaction::{RpcDeclareTransaction, RpcTransaction}; -use starknet_gateway_types::errors::GatewaySpecError; -use tracing::{debug, error}; - -use crate::compilation::GatewayCompiler; -use crate::errors::GatewayResult; - -/// Converts an RPC transaction to an executable transaction. -/// Note, for declare transaction this step is heavy, as it requires compilation of Sierra to -/// executable contract class. -pub fn compile_contract_and_build_executable_tx( - rpc_tx: RpcTransaction, - gateway_compiler: &GatewayCompiler, - chain_id: &ChainId, -) -> GatewayResult { - Ok(match rpc_tx { - RpcTransaction::Declare(rpc_declare_tx) => { - let executable_declare_tx = compile_contract_and_build_executable_declare_tx( - rpc_declare_tx, - gateway_compiler, - chain_id, - )?; - ExecutableTransaction::Declare(executable_declare_tx) - } - RpcTransaction::DeployAccount(rpc_deploy_account_tx) => { - let executable_deploy_account_tx = - ExecutableDeployAccountTransaction::from_rpc_tx(rpc_deploy_account_tx, chain_id) - .map_err(|error| { - error!( - "Failed to convert RPC deploy account transaction to executable \ - transaction: {}", - error - ); - GatewaySpecError::UnexpectedError { - data: "Internal server error".to_owned(), - } - })?; - ExecutableTransaction::DeployAccount(executable_deploy_account_tx) - } - RpcTransaction::Invoke(rpc_invoke_tx) => { - let executable_invoke_tx = ExecutableInvokeTransaction::from_rpc_tx( - rpc_invoke_tx, - chain_id, - ) - .map_err(|error| { - error!( - "Failed to convert RPC invoke transaction to executable transaction: {}", - error - ); - GatewaySpecError::UnexpectedError { data: "Internal server error".to_owned() } - })?; - ExecutableTransaction::Invoke(executable_invoke_tx) - } - }) -} - -fn compile_contract_and_build_executable_declare_tx( - rpc_tx: RpcDeclareTransaction, - gateway_compiler: &GatewayCompiler, - chain_id: &ChainId, -) -> GatewayResult { - let class_info = gateway_compiler.process_declare_tx(&rpc_tx)?; - let declare_tx: starknet_api::transaction::DeclareTransaction = rpc_tx.into(); - let executable_declare_tx = - ExecutableDeclareTransaction::create(declare_tx, class_info, chain_id).map_err(|err| { - debug!("Failed to create executable declare transaction {:?}", err); - GatewaySpecError::UnexpectedError { data: "Internal server error.".to_owned() } - })?; - - Ok(executable_declare_tx) -} diff --git a/crates/starknet_gateway_types/Cargo.toml b/crates/starknet_gateway_types/Cargo.toml index cc51db42a93..87e2ca119b3 100644 --- a/crates/starknet_gateway_types/Cargo.toml +++ b/crates/starknet_gateway_types/Cargo.toml @@ -13,7 +13,6 @@ workspace = true [dependencies] async-trait.workspace = true -axum.workspace = true enum-assoc.workspace = true mockall = { workspace = true, optional = true } papyrus_network_types.workspace = true @@ -23,9 +22,9 @@ serde = { workspace = true, features = ["derive"] } serde_json.workspace = true starknet_api.workspace = true starknet_sequencer_infra.workspace = true +strum_macros.workspace = true thiserror.workspace = true tracing.workspace = true [dev-dependencies] -# Enable self with "testing" feature in tests. -starknet_gateway_types = { workspace = true, features = ["testing"] } +mockall.workspace = true diff --git a/crates/starknet_gateway_types/src/communication.rs b/crates/starknet_gateway_types/src/communication.rs index 75a6b56a87f..7b068587671 100644 --- a/crates/starknet_gateway_types/src/communication.rs +++ b/crates/starknet_gateway_types/src/communication.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use async_trait::async_trait; #[cfg(any(feature = "testing", test))] use mockall::automock; -use papyrus_proc_macros::handle_response_variants; +use papyrus_proc_macros::handle_all_response_variants; use serde::{Deserialize, Serialize}; use starknet_api::transaction::TransactionHash; use starknet_sequencer_infra::component_client::{ @@ -15,6 +15,8 @@ use starknet_sequencer_infra::component_definitions::{ ComponentClient, ComponentRequestAndResponseSender, }; +use starknet_sequencer_infra::impl_debug_for_infra_requests_and_responses; +use strum_macros::AsRefStr; use thiserror::Error; use crate::errors::GatewayError; @@ -36,15 +38,18 @@ pub trait GatewayClient: Send + Sync { async fn add_tx(&self, gateway_input: GatewayInput) -> GatewayClientResult; } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Serialize, Deserialize, AsRefStr)] pub enum GatewayRequest { AddTransaction(GatewayInput), } -#[derive(Clone, Debug, Serialize, Deserialize)] +impl_debug_for_infra_requests_and_responses!(GatewayRequest); + +#[derive(Clone, Serialize, Deserialize, AsRefStr)] pub enum GatewayResponse { AddTransaction(GatewayResult), } +impl_debug_for_infra_requests_and_responses!(GatewayResponse); #[derive(Clone, Debug, Error)] pub enum GatewayClientError { @@ -62,7 +67,12 @@ where #[instrument(skip(self))] async fn add_tx(&self, gateway_input: GatewayInput) -> GatewayClientResult { let request = GatewayRequest::AddTransaction(gateway_input); - let response = self.send(request).await; - handle_response_variants!(GatewayResponse, AddTransaction, GatewayClientError, GatewayError) + handle_all_response_variants!( + GatewayResponse, + AddTransaction, + GatewayClientError, + GatewayError, + Direct + ) } } diff --git a/crates/starknet_gateway_types/src/errors.rs b/crates/starknet_gateway_types/src/errors.rs index bca04f72cfd..84112d4ea47 100644 --- a/crates/starknet_gateway_types/src/errors.rs +++ b/crates/starknet_gateway_types/src/errors.rs @@ -1,5 +1,3 @@ -use axum::http::StatusCode; -use axum::response::{IntoResponse, Response}; use enum_assoc::Assoc; use papyrus_network_types::network_types::BroadcastedMessageMetadata; use papyrus_rpc::error::{ @@ -59,25 +57,6 @@ pub enum GatewaySpecError { ValidationFailure { data: String }, } -impl IntoResponse for GatewaySpecError { - fn into_response(self) -> Response { - let as_rpc = self.into_rpc(); - // TODO(Arni): Fix the status code. The status code should be a HTTP status code - not a - // Json RPC error code. status code. - let status = - StatusCode::from_u16(u16::try_from(as_rpc.code).expect("Expecting a valid u16")) - .expect("Expecting a valid error code"); - - let resp = Response::builder() - .status(status) - .body((as_rpc.message, as_rpc.data)) - .expect("Expecting valid response"); - let status = resp.status(); - let body = serde_json::to_string(resp.body()).expect("Expecting valid body"); - (status, body).into_response() - } -} - impl std::fmt::Display for GatewaySpecError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let as_rpc = self.clone().into_rpc(); diff --git a/crates/starknet_http_server/Cargo.toml b/crates/starknet_http_server/Cargo.toml index 0503a48283a..2f81b128c0e 100644 --- a/crates/starknet_http_server/Cargo.toml +++ b/crates/starknet_http_server/Cargo.toml @@ -5,21 +5,39 @@ edition.workspace = true license.workspace = true repository.workspace = true +[features] +testing = ["reqwest", "starknet_api/testing", "starknet_gateway_types/testing"] + [lints] workspace = true [dependencies] axum.workspace = true hyper.workspace = true +jsonrpsee = { workspace = true, features = ["full"] } papyrus_config.workspace = true +reqwest = { workspace = true, optional = true } serde.workspace = true +serde_json.workspace = true starknet_api.workspace = true starknet_gateway_types.workspace = true +starknet_infra_utils.workspace = true starknet_sequencer_infra.workspace = true +starknet_sequencer_metrics.workspace = true thiserror.workspace = true +tokio = { workspace = true, features = ["rt"] } tracing.workspace = true validator.workspace = true [dev-dependencies] +blockifier = { workspace = true, features = ["testing"] } +blockifier_test_utils.workspace = true +futures.workspace = true +mempool_test_utils.workspace = true +metrics.workspace = true +metrics-exporter-prometheus.workspace = true +reqwest.workspace = true serde_json.workspace = true -tokio = { workspace = true, features = ["rt"] } +starknet-types-core.workspace = true +starknet_gateway_types = { workspace = true, features = ["testing"] } +tracing-test.workspace = true diff --git a/crates/starknet_http_server/src/errors.rs b/crates/starknet_http_server/src/errors.rs index 4a0a5122bcb..423254334ae 100644 --- a/crates/starknet_http_server/src/errors.rs +++ b/crates/starknet_http_server/src/errors.rs @@ -1,4 +1,9 @@ +use axum::response::{IntoResponse, Response}; +use jsonrpsee::types::error::ErrorCode; +use starknet_gateway_types::communication::GatewayClientError; +use starknet_gateway_types::errors::GatewayError; use thiserror::Error; +use tracing::error; /// Errors originating from `[`HttpServer::run`]` command. #[derive(Debug, Error)] @@ -6,3 +11,46 @@ pub enum HttpServerRunError { #[error(transparent)] ServerStartupError(#[from] hyper::Error), } + +/// Errors that may occure during the runtime of the HTTP server. +#[derive(Error, Debug)] +pub enum HttpServerError { + #[error(transparent)] + GatewayClientError(#[from] GatewayClientError), +} + +impl IntoResponse for HttpServerError { + fn into_response(self) -> Response { + match self { + HttpServerError::GatewayClientError(e) => gw_client_err_into_response(e), + } + } +} + +fn gw_client_err_into_response(err: GatewayClientError) -> Response { + let general_rpc_error = match err { + GatewayClientError::ClientError(e) => { + error!("Encountered a ClientError: {}", e); + jsonrpsee::types::ErrorObject::owned( + ErrorCode::InternalError.code(), + "Internal error", + None::<()>, + ) + } + GatewayClientError::GatewayError(GatewayError::GatewaySpecError { + source, + p2p_message_metadata: _, + }) => { + // TODO(yair): Find out what is the p2p_message_metadata and whether it needs to be + // added to the error response. + let rpc_spec_error = source.into_rpc(); + jsonrpsee::types::ErrorObject::owned( + ErrorCode::ServerError(rpc_spec_error.code).code(), + rpc_spec_error.message, + rpc_spec_error.data, + ) + } + }; + + serde_json::to_vec(&general_rpc_error).expect("Expecting a serializable error.").into_response() +} diff --git a/crates/starknet_http_server/src/http_server.rs b/crates/starknet_http_server/src/http_server.rs index 5ebd88c26bd..fe6563ece66 100644 --- a/crates/starknet_http_server/src/http_server.rs +++ b/crates/starknet_http_server/src/http_server.rs @@ -1,27 +1,29 @@ -use std::any::type_name; use std::clone::Clone; use std::net::SocketAddr; use axum::extract::State; +use axum::http::HeaderMap; use axum::routing::post; use axum::{async_trait, Json, Router}; use starknet_api::rpc_transaction::RpcTransaction; use starknet_api::transaction::TransactionHash; use starknet_gateway_types::communication::SharedGatewayClient; -use starknet_gateway_types::errors::GatewaySpecError; use starknet_gateway_types::gateway_types::GatewayInput; +use starknet_infra_utils::type_name::short_type_name; use starknet_sequencer_infra::component_definitions::ComponentStarter; -use starknet_sequencer_infra::errors::ComponentError; -use tracing::{error, info, instrument}; +use tracing::{debug, info, instrument, trace}; use crate::config::HttpServerConfig; -use crate::errors::HttpServerRunError; +use crate::errors::{HttpServerError, HttpServerRunError}; +use crate::metrics::{init_metrics, record_added_transaction, record_added_transaction_status}; #[cfg(test)] #[path = "http_server_test.rs"] pub mod http_server_test; -pub type HttpServerResult = Result; +pub type HttpServerResult = Result; + +const CLIENT_REGION_HEADER: &str = "X-Client-Region"; pub struct HttpServer { pub config: HttpServerConfig, @@ -36,6 +38,7 @@ pub struct AppState { impl HttpServer { pub fn new(config: HttpServerConfig, gateway_client: SharedGatewayClient) -> Self { let app_state = AppState { gateway_client }; + init_metrics(); HttpServer { config, app_state } } @@ -60,20 +63,32 @@ impl HttpServer { #[instrument(skip(app_state))] async fn add_tx( State(app_state): State, + headers: HeaderMap, Json(tx): Json, ) -> HttpServerResult> { - let gateway_input: GatewayInput = GatewayInput { rpc_tx: tx.clone(), message_metadata: None }; - - let add_tx_result = app_state.gateway_client.add_tx(gateway_input).await.map_err(|join_err| { - error!("Failed to process tx: {}", join_err); - GatewaySpecError::UnexpectedError { data: "Internal server error".to_owned() } + record_added_transaction(); + let gateway_input: GatewayInput = GatewayInput { rpc_tx: tx, message_metadata: None }; + let add_tx_result = app_state.gateway_client.add_tx(gateway_input).await.map_err(|e| { + debug!("Error while adding transaction: {}", e); + HttpServerError::from(e) }); + let region = + headers.get(CLIENT_REGION_HEADER).and_then(|region| region.to_str().ok()).unwrap_or("N/A"); + record_added_transactions(&add_tx_result, region); add_tx_result_as_json(add_tx_result) } +fn record_added_transactions(add_tx_result: &HttpServerResult, region: &str) { + if let Ok(tx_hash) = add_tx_result { + trace!("Recorded transaction with hash: {} from region: {}", tx_hash, region); + } + record_added_transaction_status(add_tx_result.is_ok()); +} + +#[allow(clippy::result_large_err)] pub(crate) fn add_tx_result_as_json( - result: Result, + result: HttpServerResult, ) -> HttpServerResult> { let tx_hash = result?; Ok(Json(tx_hash)) @@ -88,8 +103,8 @@ pub fn create_http_server( #[async_trait] impl ComponentStarter for HttpServer { - async fn start(&mut self) -> Result<(), ComponentError> { - info!("Starting component {}.", type_name::()); - self.run().await.map_err(|_| ComponentError::InternalComponentError) + async fn start(&mut self) { + info!("Starting component {}.", short_type_name::()); + self.run().await.unwrap_or_else(|e| panic!("Failed to start HttpServer component: {:?}", e)) } } diff --git a/crates/starknet_http_server/src/http_server_test.rs b/crates/starknet_http_server/src/http_server_test.rs index 787bed37f10..15f611a4063 100644 --- a/crates/starknet_http_server/src/http_server_test.rs +++ b/crates/starknet_http_server/src/http_server_test.rs @@ -1,9 +1,24 @@ +use std::net::{IpAddr, Ipv4Addr}; +use std::panic::AssertUnwindSafe; + use axum::body::{Bytes, HttpBody}; use axum::http::StatusCode; use axum::response::{IntoResponse, Response}; +use blockifier_test_utils::cairo_versions::CairoVersion; +use futures::FutureExt; +use jsonrpsee::types::ErrorObjectOwned; +use mempool_test_utils::starknet_api_test_utils::invoke_tx; use starknet_api::transaction::TransactionHash; +use starknet_gateway_types::communication::{GatewayClientError, MockGatewayClient}; +use starknet_gateway_types::errors::{GatewayError, GatewaySpecError}; +use starknet_infra_utils::test_utils::{AvailablePorts, TestIdentifier}; +use starknet_sequencer_infra::component_client::ClientError; +use starknet_types_core::felt::Felt; +use tracing_test::traced_test; -use crate::http_server::add_tx_result_as_json; +use crate::config::HttpServerConfig; +use crate::http_server::{add_tx_result_as_json, CLIENT_REGION_HEADER}; +use crate::test_utils::http_client_server_setup; #[tokio::test] async fn test_tx_hash_json_conversion() { @@ -20,3 +35,103 @@ async fn test_tx_hash_json_conversion() { async fn to_bytes(res: Response) -> Bytes { res.into_body().collect().await.unwrap().to_bytes() } + +#[traced_test] +#[tokio::test] +/// Test that when an "add_tx" HTTP request is sent to the server, the region of the http request is +/// recorded to the info log. +async fn record_region_test() { + let mut mock_gateway_client = MockGatewayClient::new(); + // Set the successful response. + let tx_hash_1 = TransactionHash(Felt::ONE); + let tx_hash_2 = TransactionHash(Felt::TWO); + mock_gateway_client.expect_add_tx().times(1).return_const(Ok(tx_hash_1)); + mock_gateway_client.expect_add_tx().times(1).return_const(Ok(tx_hash_2)); + + let ip = IpAddr::from(Ipv4Addr::LOCALHOST); + let mut available_ports = AvailablePorts::new(TestIdentifier::HttpServerUnitTests.into(), 1); + let http_server_config = HttpServerConfig { ip, port: available_ports.get_next_port() }; + let add_tx_http_client = + http_client_server_setup(mock_gateway_client, http_server_config).await; + + // Send a transaction to the server, without a region. + let rpc_tx = invoke_tx(CairoVersion::default()); + add_tx_http_client.add_tx(rpc_tx).await; + assert!(logs_contain( + format!("Recorded transaction with hash: {} from region: {}", tx_hash_1, "N/A").as_str() + )); + + // Send transaction to the server, with a region. + let rpc_tx = invoke_tx(CairoVersion::default()); + let region = "test"; + add_tx_http_client.add_tx_with_headers(rpc_tx, [(CLIENT_REGION_HEADER, region)]).await; + assert!(logs_contain( + format!("Recorded transaction with hash: {} from region: {}", tx_hash_2, region).as_str() + )); +} + +#[traced_test] +#[tokio::test] +/// Test that when an "add_tx" HTTP request is sent to the server, and it fails in the Gateway, no +/// record of the region is logged. +async fn record_region_gateway_failing_tx() { + let mut mock_gateway_client = MockGatewayClient::new(); + // Set the failed response. + mock_gateway_client.expect_add_tx().times(1).return_const(Err( + GatewayClientError::ClientError(ClientError::UnexpectedResponse( + "mock response".to_string(), + )), + )); + + let ip = IpAddr::from(Ipv4Addr::LOCALHOST); + let mut available_ports = AvailablePorts::new(TestIdentifier::HttpServerUnitTests.into(), 2); + let http_server_config = HttpServerConfig { ip, port: available_ports.get_next_port() }; + // let http_server_config = HttpServerConfig { ip, port }; + let add_tx_http_client = + http_client_server_setup(mock_gateway_client, http_server_config).await; + + // Send a transaction to the server. + let rpc_tx = invoke_tx(CairoVersion::default()); + add_tx_http_client.add_tx(rpc_tx).await; + assert!(!logs_contain("Recorded transaction with hash: ")); +} + +#[tokio::test] +async fn test_response() { + let mut mock_gateway_client = MockGatewayClient::new(); + + // Set the successful response. + let expected_tx_hash = TransactionHash(Felt::ONE); + mock_gateway_client.expect_add_tx().times(1).return_const(Ok(expected_tx_hash)); + + // Set the failed response. + let expected_error = GatewaySpecError::ClassAlreadyDeclared; + let expected_err_str = format!( + "Gateway responded with: {}", + serde_json::to_string(&ErrorObjectOwned::from(expected_error.clone().into_rpc())).unwrap() + ); + mock_gateway_client.expect_add_tx().times(1).return_const(Err( + GatewayClientError::GatewayError(GatewayError::GatewaySpecError { + source: expected_error, + p2p_message_metadata: None, + }), + )); + + let ip = IpAddr::from(Ipv4Addr::LOCALHOST); + let mut available_ports = AvailablePorts::new(TestIdentifier::HttpServerUnitTests.into(), 3); + let http_server_config = HttpServerConfig { ip, port: available_ports.get_next_port() }; + let add_tx_http_client = + http_client_server_setup(mock_gateway_client, http_server_config).await; + + // Test a successful response. + let rpc_tx = invoke_tx(CairoVersion::default()); + let tx_hash = add_tx_http_client.assert_add_tx_success(rpc_tx).await; + assert_eq!(tx_hash, expected_tx_hash); + + // Test a failed response. + let rpc_tx = invoke_tx(CairoVersion::default()); + let panicking_task = AssertUnwindSafe(add_tx_http_client.assert_add_tx_success(rpc_tx)); + let error = panicking_task.catch_unwind().await.unwrap_err().downcast::().unwrap(); + let error_str = format!("{}", error); + assert_eq!(error_str, expected_err_str); +} diff --git a/crates/starknet_http_server/src/lib.rs b/crates/starknet_http_server/src/lib.rs index 762c8af043a..8088168c099 100644 --- a/crates/starknet_http_server/src/lib.rs +++ b/crates/starknet_http_server/src/lib.rs @@ -2,3 +2,6 @@ pub mod communication; pub mod config; pub mod errors; pub mod http_server; +pub mod metrics; +#[cfg(any(feature = "testing", test))] +pub mod test_utils; diff --git a/crates/starknet_http_server/src/metrics.rs b/crates/starknet_http_server/src/metrics.rs new file mode 100644 index 00000000000..97ab6a9340f --- /dev/null +++ b/crates/starknet_http_server/src/metrics.rs @@ -0,0 +1,35 @@ +use starknet_sequencer_metrics::define_metrics; +use starknet_sequencer_metrics::metrics::MetricCounter; +use tracing::info; + +#[cfg(test)] +#[path = "metrics_test.rs"] +pub mod metrics_test; + +define_metrics!( + HttpServer => { + MetricCounter { ADDED_TRANSACTIONS_TOTAL, "http_server_added_transactions_total", "Total number of transactions added", init = 0 }, + MetricCounter { ADDED_TRANSACTIONS_SUCCESS, "http_server_added_transactions_success", "Number of successfully added transactions", init = 0 }, + MetricCounter { ADDED_TRANSACTIONS_FAILURE, "http_server_added_transactions_failure", "Number of faulty added transactions", init = 0 }, + }, +); + +pub(crate) fn init_metrics() { + info!("Initializing HTTP Server metrics"); + ADDED_TRANSACTIONS_TOTAL.register(); + ADDED_TRANSACTIONS_SUCCESS.register(); + ADDED_TRANSACTIONS_FAILURE.register(); +} + +// TODO(Tsabary): call the inner fn directly. +pub(crate) fn record_added_transaction() { + ADDED_TRANSACTIONS_TOTAL.increment(1); +} + +pub(crate) fn record_added_transaction_status(add_tx_success: bool) { + if add_tx_success { + ADDED_TRANSACTIONS_SUCCESS.increment(1); + } else { + ADDED_TRANSACTIONS_FAILURE.increment(1); + } +} diff --git a/crates/starknet_http_server/src/metrics_test.rs b/crates/starknet_http_server/src/metrics_test.rs new file mode 100644 index 00000000000..d21eee51687 --- /dev/null +++ b/crates/starknet_http_server/src/metrics_test.rs @@ -0,0 +1,80 @@ +use std::net::{IpAddr, Ipv4Addr}; + +use blockifier_test_utils::cairo_versions::CairoVersion; +use mempool_test_utils::starknet_api_test_utils::invoke_tx; +use metrics_exporter_prometheus::PrometheusBuilder; +use starknet_api::transaction::TransactionHash; +use starknet_gateway_types::communication::{GatewayClientError, MockGatewayClient}; +use starknet_infra_utils::test_utils::{AvailablePorts, TestIdentifier}; +use starknet_sequencer_infra::component_client::ClientError; + +use crate::config::HttpServerConfig; +use crate::metrics::{ + ADDED_TRANSACTIONS_FAILURE, + ADDED_TRANSACTIONS_SUCCESS, + ADDED_TRANSACTIONS_TOTAL, +}; +use crate::test_utils::http_client_server_setup; + +#[tokio::test] +async fn get_metrics_test() { + // Create a mock gateway client that returns a successful response and a failure response. + const SUCCESS_TXS_TO_SEND: usize = 1; + const FAILURE_TXS_TO_SEND: usize = 1; + + let mut mock_gateway_client = MockGatewayClient::new(); + // Set the successful response. + mock_gateway_client + .expect_add_tx() + .times(1) + .return_once(move |_| Ok(TransactionHash::default())); + // Set the failure response. + mock_gateway_client.expect_add_tx().times(1).return_once(move |_| { + Err(GatewayClientError::ClientError(ClientError::UnexpectedResponse( + "mock response".to_string(), + ))) + }); + + // Initialize the metrics directly instead of spawning a monitoring endpoint task. + let recorder = PrometheusBuilder::new().build_recorder(); + let _recorder_guard = metrics::set_default_local_recorder(&recorder); + let prometheus_handle = recorder.handle(); + + let ip = IpAddr::from(Ipv4Addr::LOCALHOST); + let mut available_ports = AvailablePorts::new(TestIdentifier::HttpServerUnitTests.into(), 0); + let http_server_config = HttpServerConfig { ip, port: available_ports.get_next_port() }; + let add_tx_http_client = + http_client_server_setup(mock_gateway_client, http_server_config).await; + + // Send transactions to the server. + for _ in std::iter::repeat(()).take(SUCCESS_TXS_TO_SEND + FAILURE_TXS_TO_SEND) { + let rpc_tx = invoke_tx(CairoVersion::default()); + add_tx_http_client.add_tx(rpc_tx).await; + } + + // Obtain and parse metrics. + let metrics = prometheus_handle.render(); + let added_transactions_total_count = + ADDED_TRANSACTIONS_TOTAL.parse_numeric_metric::(&metrics); + let added_transactions_success_count = + ADDED_TRANSACTIONS_SUCCESS.parse_numeric_metric::(&metrics); + let added_transactions_failure_count = + ADDED_TRANSACTIONS_FAILURE.parse_numeric_metric::(&metrics); + + // Ensure the metric values are as expected. + assert_eq!( + added_transactions_total_count.unwrap(), + SUCCESS_TXS_TO_SEND + FAILURE_TXS_TO_SEND, + "Total transaction count mismatch" + ); + assert_eq!( + added_transactions_success_count.unwrap(), + SUCCESS_TXS_TO_SEND, + "Successful transaction count mismatch" + ); + assert_eq!( + added_transactions_failure_count.unwrap(), + FAILURE_TXS_TO_SEND, + "Failing transaction count mismatch" + ); +} diff --git a/crates/starknet_http_server/src/test_utils.rs b/crates/starknet_http_server/src/test_utils.rs new file mode 100644 index 00000000000..1914a7cd594 --- /dev/null +++ b/crates/starknet_http_server/src/test_utils.rs @@ -0,0 +1,88 @@ +use std::net::SocketAddr; +use std::sync::Arc; + +use axum::body::Body; +use reqwest::{Client, Response}; +use starknet_api::rpc_transaction::RpcTransaction; +use starknet_api::test_utils::rpc_tx_to_json; +use starknet_api::transaction::TransactionHash; +use starknet_gateway_types::communication::MockGatewayClient; +use starknet_gateway_types::errors::GatewaySpecError; + +use crate::config::HttpServerConfig; +use crate::http_server::HttpServer; + +/// A test utility client for interacting with an http server. +pub struct HttpTestClient { + socket: SocketAddr, + client: Client, +} + +impl HttpTestClient { + pub fn new(socket: SocketAddr) -> Self { + let client = Client::new(); + Self { socket, client } + } + + pub async fn assert_add_tx_success(&self, rpc_tx: RpcTransaction) -> TransactionHash { + let response = self.add_tx(rpc_tx).await; + assert!(response.status().is_success()); + let text = response.text().await.unwrap(); + serde_json::from_str(&text).unwrap_or_else(|_| panic!("Gateway responded with: {}", text)) + } + + // TODO(Tsabary): implement when usage eventually arises. + pub async fn assert_add_tx_error(&self, _tx: RpcTransaction) -> GatewaySpecError { + todo!() + } + + // Prefer using assert_add_tx_success or other higher level methods of this client, to ensure + // tests are boilerplate and implementation-detail free. + pub async fn add_tx(&self, rpc_tx: RpcTransaction) -> Response { + self.add_tx_with_headers(rpc_tx, []).await + } + + pub async fn add_tx_with_headers( + &self, + rpc_tx: RpcTransaction, + header_members: I, + ) -> Response + where + I: IntoIterator, + { + let tx_json = rpc_tx_to_json(&rpc_tx); + let mut request = self.client.post(format!("http://{}/add_tx", self.socket)); + for (key, value) in header_members { + request = request.header(key, value); + } + request + .header("content-type", "application/json") + .body(Body::from(tx_json)) + .send() + .await + .unwrap() + } +} + +pub fn create_http_server_config(socket: SocketAddr) -> HttpServerConfig { + HttpServerConfig { ip: socket.ip(), port: socket.port() } +} + +/// Creates an HTTP server and an HttpTestClient that can interact with it. +pub async fn http_client_server_setup( + mock_gateway_client: MockGatewayClient, + http_server_config: HttpServerConfig, +) -> HttpTestClient { + // Create and run the server. + let mut http_server = + HttpServer::new(http_server_config.clone(), Arc::new(mock_gateway_client)); + tokio::spawn(async move { http_server.run().await }); + + let HttpServerConfig { ip, port } = http_server_config; + let add_tx_http_client = HttpTestClient::new(SocketAddr::from((ip, port))); + + // Ensure the server starts running. + tokio::task::yield_now().await; + + add_tx_http_client +} diff --git a/crates/starknet_infra_utils/Cargo.toml b/crates/starknet_infra_utils/Cargo.toml new file mode 100644 index 00000000000..f4389941c1c --- /dev/null +++ b/crates/starknet_infra_utils/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "starknet_infra_utils" +version.workspace = true +edition.workspace = true +repository.workspace = true +license-file.workspace = true +description = "Infrastructure utility." + +[features] +testing = ["cached", "colored", "dep:assert-json-diff", "toml"] + +[lints] +workspace = true + +[dependencies] +assert-json-diff = { workspace = true, optional = true } +cached = { workspace = true, optional = true } +colored = { workspace = true, optional = true } +serde = { workspace = true, features = ["derive"] } +serde_json.workspace = true +tokio = { workspace = true, features = ["process", "rt", "time"] } +toml = { workspace = true, optional = true } +tracing.workspace = true + +[dev-dependencies] +cached.workspace = true +nix.workspace = true +pretty_assertions.workspace = true +rstest.workspace = true +tokio = { workspace = true, features = ["macros", "rt", "signal", "sync"] } +toml.workspace = true +tracing-subscriber = { workspace = true, features = ["env-filter"] } diff --git a/crates/starknet_infra_utils/src/cairo_compiler_version.rs b/crates/starknet_infra_utils/src/cairo_compiler_version.rs new file mode 100644 index 00000000000..11ca28d3a3d --- /dev/null +++ b/crates/starknet_infra_utils/src/cairo_compiler_version.rs @@ -0,0 +1,51 @@ +use cached::proc_macro::cached; +use serde::{Deserialize, Serialize}; + +/// Objects for simple deserialization of `Cargo.toml`, to fetch the Cairo1 compiler version. +/// The compiler itself isn't actually a dependency, so we compile by using the version of the +/// `cairo-lang-casm` crate. +/// The choice of this crate is arbitrary, as all compiler crate dependencies should have the +/// same version. +/// Deserializes: +/// """ +/// ... +/// [workspace.dependencies] +/// ... +/// cairo-lang-casm = VERSION +/// ... +/// """ +/// where `VERSION` can be a simple "x.y.z" version string or an object with a "version" field. +#[derive(Debug, Serialize, Deserialize)] +#[serde(untagged)] +enum DependencyValue { + // cairo-lang-casm = "x.y.z". + String(String), + // cairo-lang-casm = { version = "x.y.z", .. }. + Object { version: String }, +} + +#[derive(Debug, Serialize, Deserialize)] +struct CairoLangCasmDependency { + #[serde(rename = "cairo-lang-casm")] + cairo_lang_casm: DependencyValue, +} + +#[derive(Debug, Serialize, Deserialize)] +struct WorkspaceFields { + dependencies: CairoLangCasmDependency, +} + +#[derive(Debug, Serialize, Deserialize)] +struct CargoToml { + workspace: WorkspaceFields, +} + +#[cached] +/// Returns the version of the Cairo1 compiler defined in the root Cargo.toml (by checking the +/// package version of one of the crates from the compiler in the dependencies). +pub fn cairo1_compiler_version() -> String { + let cargo_toml: CargoToml = toml::from_str(include_str!("../../../Cargo.toml")).unwrap(); + match cargo_toml.workspace.dependencies.cairo_lang_casm { + DependencyValue::String(version) | DependencyValue::Object { version } => version.clone(), + } +} diff --git a/crates/infra_utils/src/command.rs b/crates/starknet_infra_utils/src/command.rs similarity index 89% rename from crates/infra_utils/src/command.rs rename to crates/starknet_infra_utils/src/command.rs index 3d4e9550303..6c78393a8e8 100644 --- a/crates/infra_utils/src/command.rs +++ b/crates/starknet_infra_utils/src/command.rs @@ -25,5 +25,7 @@ pub fn create_shell_command(command_name: &str) -> Command { env::vars().filter(|(key, _)| key.starts_with("CARGO_")).for_each(|(key, _)| { command.env_remove(key); }); + // Filter out (the potentially set) OUT_DIR environment variable. + command.env_remove("OUT_DIR"); command } diff --git a/crates/infra_utils/src/command_test.rs b/crates/starknet_infra_utils/src/command_test.rs similarity index 100% rename from crates/infra_utils/src/command_test.rs rename to crates/starknet_infra_utils/src/command_test.rs diff --git a/crates/starknet_infra_utils/src/dumping.rs b/crates/starknet_infra_utils/src/dumping.rs new file mode 100644 index 00000000000..1eb13ac2509 --- /dev/null +++ b/crates/starknet_infra_utils/src/dumping.rs @@ -0,0 +1,57 @@ +#[cfg(any(feature = "testing", test))] +use std::env; +use std::fs::File; +use std::io::{BufWriter, Write}; +use std::path::PathBuf; + +#[cfg(any(feature = "testing", test))] +use colored::Colorize; +use serde::Serialize; +use serde_json::to_writer_pretty; +#[cfg(any(feature = "testing", test))] +use serde_json::{from_reader, to_value, Value}; + +#[cfg(any(feature = "testing", test))] +use crate::path::resolve_project_relative_path; +#[cfg(any(feature = "testing", test))] +use crate::test_utils::assert_json_eq; + +#[cfg(any(feature = "testing", test))] +pub fn serialize_to_file_test(data: T, file_path: &str) { + env::set_current_dir(resolve_project_relative_path("").unwrap()) + .expect("Couldn't set working dir."); + + let loaded_data: Value = from_reader(File::open(file_path).unwrap()).unwrap(); + + let serialized_data = + to_value(&data).expect("Should have been able to serialize the data to JSON"); + + let error_message = format!( + "{}\n{}", + "Dump file doesn't match the data. Please update it using the binary.".purple().bold(), + "Diffs shown below (loaded file <<>> data serialization)." + ); + assert_json_eq(&loaded_data, &serialized_data, error_message); +} + +pub fn serialize_to_file(data: T, file_path: &str) { + // Create file writer. + let file = File::create(file_path) + .unwrap_or_else(|_| panic!("Failed generating data file: {:?}", file_path)); + + let mut writer = BufWriter::new(file); + + // Add config as JSON content to writer. + to_writer_pretty(&mut writer, &data) + .expect("Should have been able to serialize input data to JSON."); + + // Add an extra newline after the JSON content. + writer.write_all(b"\n").expect("Should have been able to write the newline to the file."); + + // Write to file. + writer.flush().expect("Should have been able to flush the writer."); + + assert!(PathBuf::from(&file_path).exists(), "Failed generating data file: {:?}", file_path); + + println!("Generated data file: {:?}", file_path); +} diff --git a/crates/starknet_infra_utils/src/global_allocator.rs b/crates/starknet_infra_utils/src/global_allocator.rs new file mode 100644 index 00000000000..e83d8186290 --- /dev/null +++ b/crates/starknet_infra_utils/src/global_allocator.rs @@ -0,0 +1,8 @@ +/// Override default allocator. +#[macro_export] +macro_rules! set_global_allocator { + () => { + #[global_allocator] + static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; + }; +} diff --git a/crates/starknet_infra_utils/src/lib.rs b/crates/starknet_infra_utils/src/lib.rs new file mode 100644 index 00000000000..d8e0389af27 --- /dev/null +++ b/crates/starknet_infra_utils/src/lib.rs @@ -0,0 +1,12 @@ +#[cfg(any(feature = "testing", test))] +pub mod cairo_compiler_version; +pub mod command; +pub mod dumping; +pub mod global_allocator; +pub mod path; +pub mod run_until; +pub mod tasks; +#[cfg(any(feature = "testing", test))] +pub mod test_utils; +pub mod tracing; +pub mod type_name; diff --git a/crates/starknet_infra_utils/src/metrics.rs b/crates/starknet_infra_utils/src/metrics.rs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/crates/starknet_infra_utils/src/path.rs b/crates/starknet_infra_utils/src/path.rs new file mode 100644 index 00000000000..e4c3281b625 --- /dev/null +++ b/crates/starknet_infra_utils/src/path.rs @@ -0,0 +1,59 @@ +use std::path::PathBuf; +use std::{env, fs}; + +use tracing::error; + +#[cfg(test)] +#[path = "path_test.rs"] +mod path_test; + +// TODO(Tsabary): find a stable way to get access to the current crate directory at compile time. +#[macro_export] +macro_rules! compile_time_cargo_manifest_dir { + () => { + env!("CARGO_MANIFEST_DIR") + }; +} + +/// Resolves a relative path from the project root directory and returns its absolute path. +/// +/// # Arguments +/// * `relative_path` - A string slice representing the relative path from the project root. +/// +/// # Returns +/// * A `PathBuf` representing the resolved path starting from the project root. +pub fn resolve_project_relative_path(relative_path: &str) -> Result { + let project_root_path = path_of_project_root(); + let path = project_root_path.join(relative_path); + let absolute_path = fs::canonicalize(path).inspect_err(|err| { + error!( + "Error: {:?}, project root path {:?}, relative path {:?}", + err, project_root_path, relative_path + ); + })?; + + Ok(absolute_path) +} + +/// Returns the absolute path of the project root directory. +/// +/// # Returns +/// * A `PathBuf` representing the path of the project root. +pub fn project_path() -> Result { + resolve_project_relative_path(".") +} + +fn path_of_project_root() -> PathBuf { + // Ascend two directories to get to the project root. This assumes that the project root is two + // directories above the current file. + PathBuf::from(compile_time_cargo_manifest_dir!()) + .ancestors() + .nth(2) + .expect("Cannot navigate up") + .into() +} + +// TODO(Tsabary/ Arni): consider alternatives. +pub fn current_dir() -> std::io::Result { + std::env::current_dir() +} diff --git a/crates/infra_utils/src/path_test.rs b/crates/starknet_infra_utils/src/path_test.rs similarity index 100% rename from crates/infra_utils/src/path_test.rs rename to crates/starknet_infra_utils/src/path_test.rs diff --git a/crates/starknet_infra_utils/src/run_until.rs b/crates/starknet_infra_utils/src/run_until.rs new file mode 100644 index 00000000000..a4fb3ee951d --- /dev/null +++ b/crates/starknet_infra_utils/src/run_until.rs @@ -0,0 +1,68 @@ +use std::future::Future; + +use tokio::time::{sleep, Duration}; + +use crate::tracing::CustomLogger; + +#[cfg(test)] +#[path = "run_until_test.rs"] +mod run_until_test; + +/// Runs an asynchronous function until a condition is met or max attempts are reached. +/// +/// # Arguments +/// - `interval`: Time between each attempt (in milliseconds). +/// - `max_attempts`: Maximum number of attempts. +/// - `executable`: An asynchronous function to execute, which returns a future type `T` value. +/// - `condition`: A closure that takes a value of type `T` and returns `true` if the condition is +/// met. +/// - `logger`: Optional trace logger. +/// +/// # Returns +/// - `Option`: Returns `Some(value)` if the condition is met within the attempts, otherwise +/// `None`. +pub async fn run_until( + interval: u64, + max_attempts: usize, + mut executable: F, + condition: C, + logger: Option, +) -> Option +where + T: Clone + Send + std::fmt::Debug + 'static, + F: FnMut() -> Fut, + Fut: Future, + C: Fn(&T) -> bool + Send + Sync, +{ + for attempt in 1..=max_attempts { + let result = executable().await; + + // Log attempt message. + if let Some(config) = &logger { + let attempt_message = + format!("Attempt {}/{}, Value {:?}", attempt, max_attempts, result); + config.log_message(&attempt_message); + } + + // Check if the condition is met. + if condition(&result) { + if let Some(config) = &logger { + let success_message = + format!("Condition met on attempt {}/{}", attempt, max_attempts); + config.log_message(&success_message); + } + return Some(result); + } + + // Wait for the interval before the next attempt. + sleep(Duration::from_millis(interval)).await; + } + + if let Some(config) = &logger { + let failure_message = + format!("Condition not met after the maximum number of {} attempts.", max_attempts); + config.log_message(&failure_message); + } + + None +} diff --git a/crates/starknet_infra_utils/src/run_until_test.rs b/crates/starknet_infra_utils/src/run_until_test.rs new file mode 100644 index 00000000000..6715666260d --- /dev/null +++ b/crates/starknet_infra_utils/src/run_until_test.rs @@ -0,0 +1,79 @@ +use std::future::Future; +use std::pin::Pin; +use std::sync::Arc; + +use pretty_assertions::assert_eq; +use rstest::rstest; +use tokio::sync::Mutex; + +use crate::run_until::run_until; + +#[rstest] +#[tokio::test] +async fn test_run_until_condition_met() { + let (inc_value_closure, get_value_closure, condition) = create_test_closures(3); + + // Run the function with a short interval and a maximum of 5 attempts. + let result = run_until(100, 5, inc_value_closure, condition, None).await; + + // Assert that the condition was met and the returned value is correct. + assert_eq!(result, Some(3)); + assert_eq!(get_value_closure().await, 3); // Counter should stop at 3 since the condition is met. +} + +#[rstest] +#[tokio::test] +async fn test_run_until_condition_not_met() { + let (inc_value_closure, get_value_closure, condition) = create_test_closures(3); + + // Test that it stops when the maximum attempts are exceeded without meeting the condition. + let failed_result = run_until(100, 2, inc_value_closure, condition, None).await; + + // The condition is not met within 2 attempts, so the result should be None. + assert_eq!(failed_result, None); + assert_eq!(get_value_closure().await, 2); // Counter should stop at 2 because of max attempts. +} + +// Type aliases to simplify the function signature +type AsyncFn = Box Pin + Send>> + Send + Sync>; +type SyncConditionFn = Box bool + Send + Sync>; + +fn create_test_closures(condition_value: u32) -> (AsyncFn, AsyncFn, SyncConditionFn) { + // Shared mutable state + let counter = Arc::new(Mutex::new(0)); + + // Async closure to increment the counter + let increment_closure: Box< + dyn Fn() -> Pin + Send>> + Send + Sync, + > = { + let counter = Arc::clone(&counter); + Box::new(move || { + let counter = Arc::clone(&counter); + Box::pin(async move { + let mut counter_lock = counter.lock().await; + *counter_lock += 1; + *counter_lock + }) + }) + }; + + // Async closure to get the current counter value + let get_counter_value: Box< + dyn Fn() -> Pin + Send>> + Send + Sync, + > = { + let counter = Arc::clone(&counter); + Box::new(move || { + let counter = Arc::clone(&counter); + Box::pin(async move { + let counter_lock = counter.lock().await; + *counter_lock + }) + }) + }; + + // Synchronous condition closure + let condition: Box bool + Send + Sync> = + Box::new(move |&result: &u32| result >= condition_value); + + (increment_closure, get_counter_value, condition) +} diff --git a/crates/starknet_infra_utils/src/tasks.rs b/crates/starknet_infra_utils/src/tasks.rs new file mode 100644 index 00000000000..0f40bf7e29c --- /dev/null +++ b/crates/starknet_infra_utils/src/tasks.rs @@ -0,0 +1,63 @@ +use std::future::Future; + +use tokio::task::JoinHandle; +use tracing::error; + +#[cfg(test)] +#[path = "tasks_test.rs"] +mod tasks_test; + +/// Spawns a monitored asynchronous task in Tokio. +/// +/// This function spawns two tasks: +/// 1. The first task executes the provided future. +/// 2. The second task awaits the completion of the first task. +/// - If the first task completes successfully, then it returns its result. +/// - If the first task panics, it logs the error and terminates the process with exit code 1. +/// +/// # Type Parameters +/// +/// - `F`: The type of the future to be executed. Must implement `Future` and be `Send + 'static`. +/// - `T`: The output type of the future. Must be `Send + 'static`. +/// +/// # Arguments +/// +/// - `future`: The future to be executed by the spawned task. +/// +/// # Returns +/// +/// A `JoinHandle` of the second monitoring task. +pub fn spawn_with_exit_on_panic(future: F) -> JoinHandle +where + F: Future + Send + 'static, + T: Send + 'static, +{ + inner_spawn_with_exit_on_panic(future, exit_process) +} + +// Use an inner function to enable injecting the exit function for testing. +pub(crate) fn inner_spawn_with_exit_on_panic(future: F, on_exit_f: E) -> JoinHandle +where + F: Future + Send + 'static, + E: FnOnce() + Send + 'static, + T: Send + 'static, +{ + // Spawn the first task to execute the future + let monitored_task = tokio::spawn(future); + + // Spawn the second task to await the first task and assert its completion + tokio::spawn(async move { + match monitored_task.await { + Ok(res) => res, + Err(err) => { + error!("Monitored task failed: {:?}", err); + on_exit_f(); + unreachable!() + } + } + }) +} + +pub(crate) fn exit_process() { + std::process::exit(1); +} diff --git a/crates/starknet_infra_utils/src/tasks_test.rs b/crates/starknet_infra_utils/src/tasks_test.rs new file mode 100644 index 00000000000..25d93437bd3 --- /dev/null +++ b/crates/starknet_infra_utils/src/tasks_test.rs @@ -0,0 +1,48 @@ +use rstest::rstest; +use tokio::signal::unix::{signal, SignalKind}; +use tokio::time::{sleep, timeout, Duration}; + +use crate::tasks::{inner_spawn_with_exit_on_panic, spawn_with_exit_on_panic}; + +#[rstest] +#[tokio::test] +async fn test_spawn_with_exit_on_panic_success() { + let handle = spawn_with_exit_on_panic(async { + sleep(Duration::from_millis(10)).await; + }); + + // Await the monitoring task + handle.await.unwrap(); +} + +#[rstest] +#[tokio::test] +async fn test_spawn_with_exit_on_panic_failure() { + // Mock exit process function: instead of calling `std::process::exit(1)`, send 'SIGTERM' to + // self. + let mock_exit_process = || { + // Use fully-qualified nix modules to avoid ambiguity with the tokio ones. + let pid = nix::unistd::getpid(); + nix::sys::signal::kill(pid, nix::sys::signal::Signal::SIGTERM) + .expect("Failed to send signal"); + }; + + // Set up a SIGTERM handler. + let mut sigterm = signal(SignalKind::terminate()).expect("Failed to set up SIGTERM handler"); + + // Spawn a task that panics, and uses the SIGTERM mocked exit process function. + inner_spawn_with_exit_on_panic( + async { + panic!("This task will fail!"); + }, + mock_exit_process, + ); + + // Assert the task failure is detected and that the mocked exit process function is called by + // awaiting for the SIGTERM signal. Bound the timeout to ensure the test does not hang + // indefinitely. + assert!( + timeout(Duration::from_millis(10), sigterm.recv()).await.is_ok(), + "Did not receive SIGTERM signal." + ); +} diff --git a/crates/starknet_infra_utils/src/test_utils.rs b/crates/starknet_infra_utils/src/test_utils.rs new file mode 100644 index 00000000000..ab6190c7814 --- /dev/null +++ b/crates/starknet_infra_utils/src/test_utils.rs @@ -0,0 +1,137 @@ +use std::net::{IpAddr, Ipv4Addr, SocketAddr}; + +use assert_json_diff::{assert_json_matches_no_panic, CompareMode, Config}; +use serde::Serialize; +use tracing::{info, instrument}; + +const PORTS_PER_INSTANCE: u16 = 60; +pub const MAX_NUMBER_OF_INSTANCES_PER_TEST: u16 = 28; +const MAX_NUMBER_OF_TESTS: u16 = 10; +const BASE_PORT: u16 = 43000; + +// Ensure available ports don't exceed u16::MAX. +const _: () = { + assert!( + BASE_PORT + MAX_NUMBER_OF_TESTS * MAX_NUMBER_OF_INSTANCES_PER_TEST * PORTS_PER_INSTANCE + < u16::MAX, + "Port numbers potentially exceeding u16::MAX" + ); +}; + +#[derive(Debug, Copy, Clone)] +// TODO(Nadin): Come up with a better name for this enum. +pub enum TestIdentifier { + EndToEndFlowTest, + EndToEndFlowTestManyTxs, + InfraUnitTests, + PositiveFlowIntegrationTest, + RestartFlowIntegrationTest, + RevertFlowIntegrationTest, + SystemTestDumpSingleNodeConfig, + HttpServerUnitTests, + SyncFlowIntegrationTest, +} + +impl From for u16 { + fn from(variant: TestIdentifier) -> Self { + match variant { + TestIdentifier::EndToEndFlowTest => 0, + TestIdentifier::EndToEndFlowTestManyTxs => 1, + TestIdentifier::InfraUnitTests => 2, + TestIdentifier::PositiveFlowIntegrationTest => 3, + TestIdentifier::RestartFlowIntegrationTest => 4, + TestIdentifier::RevertFlowIntegrationTest => 5, + TestIdentifier::SystemTestDumpSingleNodeConfig => 6, + TestIdentifier::HttpServerUnitTests => 7, + TestIdentifier::SyncFlowIntegrationTest => 8, + } + } +} + +#[derive(Debug)] +pub struct AvailablePorts { + start_port: u16, + current_port: u16, + max_port: u16, +} + +impl AvailablePorts { + pub fn new(test_unique_index: u16, instance_index: u16) -> Self { + assert!( + test_unique_index < MAX_NUMBER_OF_TESTS, + "Test unique index {:?} exceeded bound {:?}", + test_unique_index, + MAX_NUMBER_OF_TESTS + ); + assert!( + instance_index < MAX_NUMBER_OF_INSTANCES_PER_TEST, + "Instance index {:?} exceeded bound {:?}", + instance_index, + MAX_NUMBER_OF_INSTANCES_PER_TEST + ); + + let test_offset: u16 = + test_unique_index * MAX_NUMBER_OF_INSTANCES_PER_TEST * PORTS_PER_INSTANCE; + let instance_in_test_offset: u16 = instance_index * PORTS_PER_INSTANCE; + let current_port = BASE_PORT + test_offset + instance_in_test_offset; + let max_port: u16 = current_port + PORTS_PER_INSTANCE; + + AvailablePorts { start_port: current_port, current_port, max_port } + } + + #[instrument] + pub fn get_next_port(&mut self) -> u16 { + let port = self.current_port; + self.current_port += 1; + assert!(self.current_port < self.max_port, "Exceeded available ports."); + info!("Allocated port: {} in range [{},{}]", port, self.start_port, self.max_port); + port + } + + pub fn get_next_ports(&mut self, n: usize) -> Vec { + std::iter::repeat_with(|| self.get_next_port()).take(n).collect() + } + + #[instrument] + pub fn get_next_local_host_socket(&mut self) -> SocketAddr { + SocketAddr::new(IpAddr::from(Ipv4Addr::LOCALHOST), self.get_next_port()) + } +} + +#[derive(Debug)] +pub struct AvailablePortsGenerator { + test_unique_id: u16, + instance_index: u16, +} + +impl AvailablePortsGenerator { + pub fn new(test_unique_id: u16) -> Self { + Self { test_unique_id, instance_index: 0 } + } +} + +impl Iterator for AvailablePortsGenerator { + type Item = AvailablePorts; + + #[instrument] + fn next(&mut self) -> Option { + let res = Some(AvailablePorts::new(self.test_unique_id, self.instance_index)); + self.instance_index += 1; + res + } +} + +/// Compare two JSON values for an exact match. +/// +/// Extends the functionality of [`assert_json_diff::assert_json_eq`] by also adding a customizable +/// error message print. Uses [`assert_json_matches_no_panic`]. +pub fn assert_json_eq(lhs: &Lhs, rhs: &Rhs, message: String) +where + Lhs: Serialize, + Rhs: Serialize, +{ + if let Err(error) = assert_json_matches_no_panic(lhs, rhs, Config::new(CompareMode::Strict)) { + let printed_error = format!("\n\n{}\n{}\n\n", message, error); + panic!("{}", printed_error); + } +} diff --git a/crates/starknet_infra_utils/src/tracing.rs b/crates/starknet_infra_utils/src/tracing.rs new file mode 100644 index 00000000000..1fd40df8bb7 --- /dev/null +++ b/crates/starknet_infra_utils/src/tracing.rs @@ -0,0 +1,44 @@ +use tracing::{debug, error, info, trace, warn}; + +#[cfg(test)] +#[path = "tracing_test.rs"] +mod tracing_test; + +/// Enable setting a message tracing level at runtime. +pub struct CustomLogger { + level: TraceLevel, + base_message: Option, +} + +impl CustomLogger { + /// Creates a new trace configuration + pub fn new(level: TraceLevel, base_message: Option) -> Self { + Self { level, base_message } + } + + /// Logs a given message at the specified tracing level, concatenated with the base message if + /// it exists. + pub fn log_message(&self, message: &str) { + let message = match &self.base_message { + Some(base_message) => format!("{}: {}", base_message, message), + None => message.to_string(), + }; + + match self.level { + TraceLevel::Trace => trace!(message), + TraceLevel::Debug => debug!(message), + TraceLevel::Info => info!(message), + TraceLevel::Warn => warn!(message), + TraceLevel::Error => error!(message), + } + } +} + +#[derive(Clone, Copy)] +pub enum TraceLevel { + Trace, + Debug, + Info, + Warn, + Error, +} diff --git a/crates/starknet_infra_utils/src/tracing_test.rs b/crates/starknet_infra_utils/src/tracing_test.rs new file mode 100644 index 00000000000..422a2da5c0e --- /dev/null +++ b/crates/starknet_infra_utils/src/tracing_test.rs @@ -0,0 +1,159 @@ +use std::fmt::Debug; +use std::sync::{Arc, Mutex}; + +use tracing::field::{Field, Visit}; +use tracing::span::{Attributes, Id, Record}; +use tracing::subscriber::with_default; +use tracing::{Event, Metadata, Subscriber}; + +use crate::tracing::{CustomLogger, TraceLevel}; + +#[test] +fn test_dynamic_logger_without_base_message() { + let subscriber = TestSubscriber::new(); + + with_default(subscriber.clone(), || { + let logger = CustomLogger::new(TraceLevel::Info, None); + logger.log_message("Test message"); + }); + + let messages = subscriber.messages(); + assert_eq!(messages.len(), 1); + assert!(messages[0].contains("Test message")); + assert!(messages[0].contains("INFO")); +} + +#[test] +fn test_dynamic_logger_with_base_message() { + let subscriber = TestSubscriber::new(); + + with_default(subscriber.clone(), || { + let logger = CustomLogger::new(TraceLevel::Debug, Some("BaseMessage".to_string())); + logger.log_message("Test message"); + }); + + let messages = subscriber.messages(); + assert_eq!(messages.len(), 1); + assert!(messages[0].contains("BaseMessage: Test message")); + assert!(messages[0].contains("DEBUG")); +} + +#[test] +fn test_all_trace_levels() { + let subscriber = TestSubscriber::new(); + + let test_cases = [ + (TraceLevel::Trace, "TRACE"), + (TraceLevel::Debug, "DEBUG"), + (TraceLevel::Info, "INFO"), + (TraceLevel::Warn, "WARN"), + (TraceLevel::Error, "ERROR"), + ]; + + with_default(subscriber.clone(), || { + for (level, expected_level_str) in test_cases { + subscriber.clear(); + let logger = CustomLogger::new(level, None); + logger.log_message("Test message"); + + let messages = subscriber.messages(); + assert_eq!(messages.len(), 1); + assert!(messages[0].contains(expected_level_str)); + assert!(messages[0].contains("Test message")); + } + }); +} + +#[test] +fn test_message_formatting() { + let subscriber = TestSubscriber::new(); + + with_default(subscriber.clone(), || { + let base_message = Some("Component".to_string()); + let logger = CustomLogger::new(TraceLevel::Info, base_message); + logger.log_message("Operation completed"); + }); + + let messages = subscriber.messages(); + assert_eq!(messages.len(), 1); + assert!(messages[0].contains("Component: Operation completed")); + assert!(messages[0].contains("INFO")); +} + +#[test] +fn test_empty_message() { + let subscriber = TestSubscriber::new(); + + with_default(subscriber.clone(), || { + let logger = CustomLogger::new(TraceLevel::Warn, None); + logger.log_message(""); + }); + + let messages = subscriber.messages(); + assert_eq!(messages.len(), 1); + assert!(messages[0].contains("WARN")); +} + +// Custom visitor to capture event fields +struct MessageVisitor<'a> { + message: &'a mut String, +} + +impl Visit for MessageVisitor<'_> { + fn record_debug(&mut self, field: &Field, value: &dyn Debug) { + if field.name() == "message" { + self.message.push_str(&format!("{:?}", value)); + } + } +} + +// Custom subscriber to capture log output +#[derive(Default, Clone)] +struct TestSubscriber { + messages: Arc>>, +} + +impl TestSubscriber { + fn new() -> Self { + Self { messages: Arc::new(Mutex::new(Vec::new())) } + } + + fn messages(&self) -> Vec { + self.messages.lock().unwrap().clone() + } + + fn clear(&self) { + self.messages.lock().unwrap().clear(); + } +} + +impl Subscriber for TestSubscriber { + fn enabled(&self, _metadata: &Metadata<'_>) -> bool { + true + } + + fn event(&self, event: &Event<'_>) { + let mut message = String::new(); + let metadata = event.metadata(); + + // Add level prefix + message.push_str(&format!("{}: ", metadata.level())); + + // Capture the message field + let mut visitor = MessageVisitor { message: &mut message }; + event.record(&mut visitor); + + self.messages.lock().unwrap().push(message); + } + + fn enter(&self, _span: &Id) {} + fn exit(&self, _span: &Id) {} + + fn new_span(&self, _span: &Attributes<'_>) -> Id { + Id::from_u64(0) + } + + fn record(&self, _span: &Id, _values: &Record<'_>) {} + + fn record_follows_from(&self, _span: &Id, _follows: &Id) {} +} diff --git a/crates/starknet_infra_utils/src/type_name.rs b/crates/starknet_infra_utils/src/type_name.rs new file mode 100644 index 00000000000..ffe817f865e --- /dev/null +++ b/crates/starknet_infra_utils/src/type_name.rs @@ -0,0 +1,83 @@ +use std::any::type_name; + +#[cfg(test)] +#[path = "type_name_test.rs"] +mod type_name_test; + +pub fn short_type_name() -> String { + let full_name = type_name::(); + truncate_type(full_name) +} + +/// Truncates a fully qualified Rust type name by removing module paths, leaving only the type +/// name and its generic parameters. +/// +/// # Description +/// This function processes a Rust type string containing module paths, type names, and generic +/// parameters, such as: +/// ```text +/// starknet_sequencer_infra::component_client::local_component_client::LocalComponentClient +/// ``` +/// It removes the module paths (`::module_name`) and keeps only the type name and its +/// generic parameters: +/// ```text +/// LocalComponentClient +/// ``` +/// +/// # Algorithm +/// - Iterates over the input string using a character iterator with indices. +/// - When encountering two consecutive colons (`::`), skips the preceding module path. +/// - When encountering delimiters (`<`, `,`, `>`), slices the substring from the current segment +/// start to the current index, appends it to the result, and resets the segment start. +/// - At the end, appends the remaining segment to the result. +/// +/// # Examples +/// ```rust,ignore +/// let input = "a::b::c::Type"; +/// let output = truncate_type(input); +/// assert_eq!(output, "Type"); +/// ``` +/// +/// # Panics +/// This function does not panic as it only operates on valid UTF-8 strings. +/// +/// # Complexity +/// The function runs in O(n) time, where `n` is the length of the input string. +/// +/// # Limitations +/// - The function assumes well-formed Rust type strings. Incorrectly formatted input may yield +/// unexpected results. +/// +/// # Returns +/// A new `String` with module paths removed and generic parameters preserved. +fn truncate_type(input: &str) -> String { + let mut result = String::new(); + let mut segment_start = 0; + let mut iter = input.char_indices().peekable(); + + while let Some((index, c)) = iter.next() { + if c == ':' { + if let Some((_, next_char)) = iter.peek() { + if *next_char == ':' { + // Skip the next ':' + iter.next(); + segment_start = index + 2; // Move `segment_start` after the second ':' + } + } + } else if c == '<' || c == ',' || c == '>' { + // Add the slice from `segment_start` to the current index to the result + if segment_start < index { + result.push_str(input[segment_start..index].trim()); + result.push(c); + } + segment_start = index + 1; // Move `segment_start` after the current delimiter + } + } + + // Add the final slice from `segment_start` to the end + if segment_start < input.len() { + result.push_str(input[segment_start..].trim()); + } + + result +} diff --git a/crates/starknet_infra_utils/src/type_name_test.rs b/crates/starknet_infra_utils/src/type_name_test.rs new file mode 100644 index 00000000000..c10379f61e7 --- /dev/null +++ b/crates/starknet_infra_utils/src/type_name_test.rs @@ -0,0 +1,23 @@ +use pretty_assertions::assert_eq; + +use crate::type_name::short_type_name; + +struct TestStruct {} + +struct GenericTestStruct { + _placeholder: T, +} + +mod submodule { + pub struct SubmoduleStruct {} +} + +#[test] +fn resolve_project_relative_path_success() { + assert_eq!(short_type_name::().as_str(), "TestStruct"); + assert_eq!(short_type_name::>().as_str(), "GenericTestStruct"); + assert_eq!( + short_type_name::>().as_str(), + "GenericTestStruct" + ); +} diff --git a/crates/starknet_integration_tests/Cargo.toml b/crates/starknet_integration_tests/Cargo.toml index 8b3b43ef64d..1dedc5c0885 100644 --- a/crates/starknet_integration_tests/Cargo.toml +++ b/crates/starknet_integration_tests/Cargo.toml @@ -9,44 +9,73 @@ license.workspace = true workspace = true [dependencies] +alloy.workspace = true anyhow.workspace = true assert_matches.workspace = true axum.workspace = true blockifier.workspace = true +blockifier_test_utils.workspace = true cairo-lang-starknet-classes.workspace = true +clap.workspace = true futures.workspace = true indexmap.workspace = true +itertools.workspace = true mempool_test_utils.workspace = true -papyrus_common.workspace = true -papyrus_consensus.workspace = true -papyrus_execution.workspace = true +papyrus_base_layer = { workspace = true, features = ["testing"] } papyrus_network = { workspace = true, features = ["testing"] } papyrus_protobuf.workspace = true -papyrus_rpc.workspace = true papyrus_storage = { workspace = true, features = ["testing"] } -reqwest.workspace = true +papyrus_sync.workspace = true +serde.workspace = true serde_json.workspace = true starknet-types-core.workspace = true starknet_api.workspace = true starknet_batcher.workspace = true -starknet_client.workspace = true +starknet_class_manager = { workspace = true, features = ["testing"] } +starknet_consensus.workspace = true starknet_consensus_manager.workspace = true +starknet_consensus_orchestrator.workspace = true starknet_gateway = { workspace = true, features = ["testing"] } starknet_gateway_types.workspace = true -starknet_http_server.workspace = true +starknet_http_server = { workspace = true, features = ["testing"] } +starknet_infra_utils = { workspace = true, features = ["testing"] } +starknet_l1_gas_price.workspace = true +starknet_l1_provider.workspace = true +starknet_mempool.workspace = true starknet_mempool_p2p.workspace = true starknet_monitoring_endpoint = { workspace = true, features = ["testing"] } +starknet_sequencer_deployments.workspace = true starknet_sequencer_infra = { workspace = true, features = ["testing"] } starknet_sequencer_node = { workspace = true, features = ["testing"] } -starknet_task_executor.workspace = true +starknet_state_sync.workspace = true strum.workspace = true tempfile.workspace = true tokio.workspace = true tracing.workspace = true +url.workspace = true [dev-dependencies] futures.workspace = true -infra_utils.workspace = true pretty_assertions.workspace = true rstest.workspace = true starknet_sequencer_infra.workspace = true + +[[bin]] +name = "integration_test_positive_flow" +path = "src/bin/sequencer_node_end_to_end_integration_tests/integration_test_positive_flow.rs" + +[[bin]] +name = "integration_test_restart_flow" +path = "src/bin/sequencer_node_end_to_end_integration_tests/integration_test_restart_flow.rs" + +[[bin]] +name = "integration_test_revert_flow" +path = "src/bin/sequencer_node_end_to_end_integration_tests/integration_test_revert_flow.rs" + +[[bin]] +name = "integration_test_central_and_p2p_sync_flow" +path = "src/bin/sequencer_node_end_to_end_integration_tests/integration_test_central_and_p2p_sync_flow.rs" + +[[bin]] +name = "system_test_dump_single_node_config" +path = "src/bin/dump_test_preset_configs/system_test_dump_single_node_config.rs" diff --git a/crates/starknet_integration_tests/build.rs b/crates/starknet_integration_tests/build.rs deleted file mode 100644 index 74fc7c9940e..00000000000 --- a/crates/starknet_integration_tests/build.rs +++ /dev/null @@ -1,3 +0,0 @@ -// Sets up the environment variable OUT_DIR, which holds the cairo compiler binary. -// The binary is downloaded to OUT_DIR by the starknet_sierra_compile crate. -fn main() {} diff --git a/crates/starknet_integration_tests/src/bin/dummy_eth_to_strk_oracle.rs b/crates/starknet_integration_tests/src/bin/dummy_eth_to_strk_oracle.rs new file mode 100644 index 00000000000..6763fd17503 --- /dev/null +++ b/crates/starknet_integration_tests/src/bin/dummy_eth_to_strk_oracle.rs @@ -0,0 +1,18 @@ +use std::net::SocketAddr; + +use starknet_integration_tests::utils::spawn_eth_to_strk_oracle_server; +use starknet_sequencer_infra::trace_util::configure_tracing; +use tracing::info; + +const ETH_TO_STRK_ORACLE_PORT: u16 = 9000; + +#[tokio::main] +async fn main() { + configure_tracing().await; + + let socket_address = SocketAddr::from(([0, 0, 0, 0], ETH_TO_STRK_ORACLE_PORT)); + let join_handle = spawn_eth_to_strk_oracle_server(socket_address); + info!("Spawned the dummy eth to strk oracle successfully!"); + + join_handle.await.expect("The dummy eth to strk oracle has panicked!!! :("); +} diff --git a/crates/starknet_integration_tests/src/bin/dummy_recorder.rs b/crates/starknet_integration_tests/src/bin/dummy_recorder.rs new file mode 100644 index 00000000000..33dbaf5497c --- /dev/null +++ b/crates/starknet_integration_tests/src/bin/dummy_recorder.rs @@ -0,0 +1,18 @@ +use std::net::SocketAddr; + +use starknet_integration_tests::utils::spawn_success_recorder; +use starknet_sequencer_infra::trace_util::configure_tracing; +use tracing::info; + +const RECORDER_PORT: u16 = 8080; + +#[tokio::main] +async fn main() { + configure_tracing().await; + + let socket_address = SocketAddr::from(([0, 0, 0, 0], RECORDER_PORT)); + let join_handle = spawn_success_recorder(socket_address); + info!("Spawned the dummy success Recorder successfully!"); + + join_handle.await.expect("The dummy success Recorder has panicked!!! :("); +} diff --git a/crates/starknet_integration_tests/src/bin/dump_test_preset_configs/system_test_dump_single_node_config.rs b/crates/starknet_integration_tests/src/bin/dump_test_preset_configs/system_test_dump_single_node_config.rs new file mode 100644 index 00000000000..60161e9da70 --- /dev/null +++ b/crates/starknet_integration_tests/src/bin/dump_test_preset_configs/system_test_dump_single_node_config.rs @@ -0,0 +1,61 @@ +use std::fs::remove_dir_all; +use std::path::PathBuf; + +use clap::Parser; +use starknet_infra_utils::test_utils::TestIdentifier; +use starknet_integration_tests::consts::{DATA_PREFIX_PATH, SINGLE_NODE_CONFIG_PATH}; +use starknet_integration_tests::integration_test_manager::get_sequencer_setup_configs; +use starknet_integration_tests::storage::CustomPaths; +use starknet_integration_tests::utils::create_integration_test_tx_generator; +use tracing::info; + +const DB_DIR: &str = "./data"; + +#[tokio::main] +async fn main() { + const N_CONSOLIDATED_SEQUENCERS: usize = 1; + const N_DISTRIBUTED_SEQUENCERS: usize = 0; + info!("Generating system test preset for single node."); + let args = Args::parse(); + + // Creates a multi-account transaction generator for integration test + let tx_generator = create_integration_test_tx_generator(); + + let custom_paths = CustomPaths::new( + Some(PathBuf::from(args.db_dir.clone())), + None, + Some(PathBuf::from(args.data_prefix_path)), + ); + // TODO(Nadin): Align this with node_setup. + // Run node setup. + let (mut sequencers_setup, _node_indices) = get_sequencer_setup_configs( + &tx_generator, + N_CONSOLIDATED_SEQUENCERS, + N_DISTRIBUTED_SEQUENCERS, + Some(custom_paths), + TestIdentifier::SystemTestDumpSingleNodeConfig, + ) + .await; + + // Dump the config file in the single node path. + let single_node_path = PathBuf::from(args.config_output_path); + sequencers_setup[0].set_executable_config_path(0, single_node_path).unwrap(); + sequencers_setup[0].get_executables()[0].dump_config_file_changes(); + + remove_dir_all(args.db_dir).expect("Failed to remove db directory"); + + info!("System test preset for single node generated successfully."); +} + +#[derive(Parser, Debug)] +#[command(name = "system_test_dump_single_node_config", about = "Dump single node config.")] +struct Args { + #[arg(long, default_value_t = SINGLE_NODE_CONFIG_PATH.to_string())] + config_output_path: String, + + #[arg(long, default_value_t = DB_DIR.to_string())] + db_dir: String, + + #[arg(long, default_value_t = DATA_PREFIX_PATH.to_string())] + data_prefix_path: String, +} diff --git a/crates/starknet_integration_tests/src/bin/sequencer_node_end_to_end_integration_tests/integration_test_central_and_p2p_sync_flow.rs b/crates/starknet_integration_tests/src/bin/sequencer_node_end_to_end_integration_tests/integration_test_central_and_p2p_sync_flow.rs new file mode 100644 index 00000000000..fe73a70ce43 --- /dev/null +++ b/crates/starknet_integration_tests/src/bin/sequencer_node_end_to_end_integration_tests/integration_test_central_and_p2p_sync_flow.rs @@ -0,0 +1,56 @@ +use starknet_api::block::BlockNumber; +use starknet_infra_utils::test_utils::TestIdentifier; +use starknet_integration_tests::integration_test_manager::IntegrationTestManager; +use starknet_integration_tests::integration_test_utils::integration_test_setup; +use starknet_sequencer_node::config::component_execution_config::{ + ActiveComponentExecutionMode, + ReactiveComponentExecutionMode, +}; +use starknet_sequencer_node::config::node_config::SequencerNodeConfig; +use starknet_state_sync::config::CentralSyncClientConfig; +#[tokio::main] +async fn main() { + integration_test_setup("sync").await; + const BLOCK_TO_WAIT_FOR: BlockNumber = BlockNumber(20); + /// The number of consolidated local sequencers that participate in the test. + const N_CONSOLIDATED_SEQUENCERS: usize = 2; + /// The number of distributed remote sequencers that participate in the test. + const N_DISTRIBUTED_SEQUENCERS: usize = 0; + + const CENTRAL_SYNC_NODE: usize = 1; + + let mut integration_test_manager = IntegrationTestManager::new( + N_CONSOLIDATED_SEQUENCERS, + N_DISTRIBUTED_SEQUENCERS, + None, + TestIdentifier::SyncFlowIntegrationTest, + ) + .await; + + let update_config_disable_everything_but_sync = |config: &mut SequencerNodeConfig| { + config.components.batcher.execution_mode = ReactiveComponentExecutionMode::Disabled; + config.components.gateway.execution_mode = ReactiveComponentExecutionMode::Disabled; + config.components.mempool.execution_mode = ReactiveComponentExecutionMode::Disabled; + config.components.mempool_p2p.execution_mode = ReactiveComponentExecutionMode::Disabled; + config.components.l1_provider.execution_mode = ReactiveComponentExecutionMode::Disabled; + config.components.consensus_manager.execution_mode = ActiveComponentExecutionMode::Disabled; + config.components.http_server.execution_mode = ActiveComponentExecutionMode::Disabled; + config.components.l1_scraper.execution_mode = ActiveComponentExecutionMode::Disabled; + }; + + let update_config_use_central_sync = |config: &mut SequencerNodeConfig| { + config.state_sync_config.central_sync_client_config = + Some(CentralSyncClientConfig::default()); + config.state_sync_config.p2p_sync_client_config = None; + }; + + let node_indices = integration_test_manager.get_node_indices(); + integration_test_manager + .modify_config_idle_nodes(node_indices.clone(), update_config_disable_everything_but_sync); + integration_test_manager + .modify_config_idle_nodes([CENTRAL_SYNC_NODE].into(), update_config_use_central_sync); + + integration_test_manager.run_nodes(node_indices.clone()).await; + + integration_test_manager.await_sync_block_on_all_running_nodes(BLOCK_TO_WAIT_FOR).await; +} diff --git a/crates/starknet_integration_tests/src/bin/sequencer_node_end_to_end_integration_tests/integration_test_positive_flow.rs b/crates/starknet_integration_tests/src/bin/sequencer_node_end_to_end_integration_tests/integration_test_positive_flow.rs new file mode 100644 index 00000000000..5c9f50a71b4 --- /dev/null +++ b/crates/starknet_integration_tests/src/bin/sequencer_node_end_to_end_integration_tests/integration_test_positive_flow.rs @@ -0,0 +1,42 @@ +use starknet_api::block::BlockNumber; +use starknet_infra_utils::test_utils::TestIdentifier; +use starknet_integration_tests::integration_test_manager::IntegrationTestManager; +use starknet_integration_tests::integration_test_utils::integration_test_setup; +use tracing::info; + +#[tokio::main] +async fn main() { + integration_test_setup("positive").await; + const BLOCK_TO_WAIT_FOR: BlockNumber = BlockNumber(15); + const N_TXS: usize = 50; + // TODO(Yael/Arni): 0 is a temporary value till fixing the nonce issue. + const N_L1_HANDLER_TXS: usize = 0; + /// The number of consolidated local sequencers that participate in the test. + const N_CONSOLIDATED_SEQUENCERS: usize = 3; + /// The number of distributed remote sequencers that participate in the test. + const N_DISTRIBUTED_SEQUENCERS: usize = 2; + + // Get the sequencer configurations. + let mut integration_test_manager = IntegrationTestManager::new( + N_CONSOLIDATED_SEQUENCERS, + N_DISTRIBUTED_SEQUENCERS, + None, + TestIdentifier::PositiveFlowIntegrationTest, + ) + .await; + + let node_indices = integration_test_manager.get_node_indices(); + // Run the nodes. + integration_test_manager.run_nodes(node_indices.clone()).await; + + // Run the first block scenario to bootstrap the accounts. + integration_test_manager.send_bootstrap_txs_and_verify().await; + + // Run the test. + integration_test_manager.send_txs_and_verify(N_TXS, N_L1_HANDLER_TXS, BLOCK_TO_WAIT_FOR).await; + + info!("Shutting down nodes."); + integration_test_manager.shutdown_nodes(node_indices); + + info!("Positive flow integration test completed successfully!"); +} diff --git a/crates/starknet_integration_tests/src/bin/sequencer_node_end_to_end_integration_tests/integration_test_restart_flow.rs b/crates/starknet_integration_tests/src/bin/sequencer_node_end_to_end_integration_tests/integration_test_restart_flow.rs new file mode 100644 index 00000000000..971656c8761 --- /dev/null +++ b/crates/starknet_integration_tests/src/bin/sequencer_node_end_to_end_integration_tests/integration_test_restart_flow.rs @@ -0,0 +1,147 @@ +use std::collections::HashMap; +use std::time::Duration; + +use starknet_infra_utils::test_utils::TestIdentifier; +use starknet_integration_tests::integration_test_manager::{ + IntegrationTestManager, + DEFAULT_SENDER_ACCOUNT, +}; +use starknet_integration_tests::integration_test_utils::integration_test_setup; +use starknet_integration_tests::utils::{ConsensusTxs, N_TXS_IN_FIRST_BLOCK, TPS}; +use tokio::join; +use tokio::time::sleep; +use tracing::info; + +#[tokio::main] +async fn main() { + integration_test_setup("restart").await; + const TOTAL_PHASES: u64 = 4; + const PHASE_DURATION: u64 = 30; + const PHASE_DURATION_SECS: Duration = Duration::from_secs(PHASE_DURATION); + const TOTAL_DURATION: u64 = PHASE_DURATION * TOTAL_PHASES; + const TOTAL_INVOKE_TXS: u64 = TPS * TOTAL_DURATION; + /// The number of consolidated local sequencers that participate in the test. + const N_CONSOLIDATED_SEQUENCERS: usize = 5; + /// The number of distributed remote sequencers that participate in the test. + const N_DISTRIBUTED_SEQUENCERS: usize = 0; + // The indices of the nodes that we will be shutting down. Node 0 is skipped because we use it + // to verify the metrics. + const NODE_1: usize = 1; + const NODE_2: usize = 2; + + // Get the sequencer configurations. + let mut integration_test_manager = IntegrationTestManager::new( + N_CONSOLIDATED_SEQUENCERS, + N_DISTRIBUTED_SEQUENCERS, + None, + TestIdentifier::RestartFlowIntegrationTest, + ) + .await; + + let mut node_indices = integration_test_manager.get_node_indices(); + + info!("Running all nodes"); + integration_test_manager.run_nodes(node_indices.clone()).await; + + integration_test_manager.send_bootstrap_txs_and_verify().await; + + let mut nodes_accepted_txs_mapping = + integration_test_manager.get_num_accepted_txs_on_all_running_nodes().await; + + // Create a simulator for sustained transaction sending. + let simulator = integration_test_manager.create_simulator(); + let mut tx_generator = integration_test_manager.tx_generator().snapshot(); + let test_scenario = ConsensusTxs { + n_invoke_txs: TOTAL_INVOKE_TXS.try_into().expect("Failed to convert TPS to usize"), + n_l1_handler_txs: 0, + }; + + // TODO(noamsp): Try to refactor this to use tokio::spawn. + // Task that sends sustained transactions for the entire test duration. + let tx_sending_task = + simulator.send_txs(&mut tx_generator, &test_scenario, DEFAULT_SENDER_ACCOUNT); + + // Task that awaits transactions and restarts nodes in phases. + let await_and_restart_nodes_task = async { + info!("Awaiting transactions while all nodes are up"); + sleep(PHASE_DURATION_SECS).await; + verify_running_nodes_received_more_txs( + &mut nodes_accepted_txs_mapping, + &integration_test_manager, + ) + .await; + + integration_test_manager.shutdown_nodes([NODE_1].into()); + info!("Awaiting transactions while node {NODE_1} is down"); + sleep(PHASE_DURATION_SECS).await; + verify_running_nodes_received_more_txs( + &mut nodes_accepted_txs_mapping, + &integration_test_manager, + ) + .await; + + // We want node 1 to rejoin the network while its building blocks to check the catch-up + // mechanism. + integration_test_manager.run_nodes([NODE_1].into()).await; + info!( + "Awaiting transactions after node {NODE_1} was restarted and before node {NODE_2} is \ + shut down" + ); + sleep(PHASE_DURATION_SECS).await; + verify_running_nodes_received_more_txs( + &mut nodes_accepted_txs_mapping, + &integration_test_manager, + ) + .await; + + // Shutdown second node to test that the first node has joined consensus (the network can't + // reach consensus without the first node if the second node is down). + integration_test_manager.shutdown_nodes([NODE_2].into()); + // Shutting down a node that's already down results in an error so we remove it from the set + // here. + node_indices.remove(&NODE_2); + info!("Awaiting transactions while node {NODE_1} is up and node {NODE_2} is down"); + sleep(PHASE_DURATION_SECS).await; + verify_running_nodes_received_more_txs( + &mut nodes_accepted_txs_mapping, + &integration_test_manager, + ) + .await; + + // The expected accepted number of transactions is the total number of invoke transactions + // sent + the number of transactions sent during the bootstrap phase. + let expected_n_accepted_txs = N_TXS_IN_FIRST_BLOCK + + TryInto::::try_into(TOTAL_INVOKE_TXS) + .expect("Failed to convert TOTAL_INVOKE_TXS to usize"); + + info!("Verifying that all running nodes processed all transactions"); + integration_test_manager + .await_txs_accepted_on_all_running_nodes(expected_n_accepted_txs) + .await; + }; + + let _ = join!(tx_sending_task, await_and_restart_nodes_task); + + integration_test_manager.shutdown_nodes(node_indices); + info!("Restart flow integration test completed successfully!"); +} + +// Verifies that all running nodes processed more transactions since the last check. +// Takes a mutable reference to a mapping of the number of transactions processed by each node +// at the previous check, and updates it with the current number of transactions. +async fn verify_running_nodes_received_more_txs( + prev_txs: &mut HashMap, + integration_test_manager: &IntegrationTestManager, +) { + let curr_txs = integration_test_manager.get_num_accepted_txs_on_all_running_nodes().await; + for (node_idx, curr_n_processed) in curr_txs { + let prev_n_processed = + prev_txs.insert(node_idx, curr_n_processed).expect("Num txs not found"); + info!("Node {} processed {} transactions", node_idx, curr_n_processed); + assert!( + curr_n_processed > prev_n_processed, + "Node {} did not process more transactions", + node_idx + ); + } +} diff --git a/crates/starknet_integration_tests/src/bin/sequencer_node_end_to_end_integration_tests/integration_test_revert_flow.rs b/crates/starknet_integration_tests/src/bin/sequencer_node_end_to_end_integration_tests/integration_test_revert_flow.rs new file mode 100644 index 00000000000..053312082f0 --- /dev/null +++ b/crates/starknet_integration_tests/src/bin/sequencer_node_end_to_end_integration_tests/integration_test_revert_flow.rs @@ -0,0 +1,181 @@ +use std::collections::HashSet; +use std::time::Duration; + +use serde_json::Value; +use starknet_api::block::BlockNumber; +use starknet_infra_utils::test_utils::TestIdentifier; +use starknet_integration_tests::integration_test_manager::{ + IntegrationTestManager, + BLOCK_TO_WAIT_FOR_BOOTSTRAP, +}; +use starknet_integration_tests::integration_test_utils::integration_test_setup; +use starknet_sequencer_node::config::definitions::ConfigPointersMap; +use starknet_sequencer_node::config::node_config::SequencerNodeConfig; +use tracing::info; + +#[tokio::main] +async fn main() { + integration_test_setup("revert").await; + const BLOCK_TO_REVERT_FROM: BlockNumber = BlockNumber(10); + const BLOCK_TO_WAIT_FOR_AFTER_REVERT: BlockNumber = BlockNumber(15); + // can't use static assertion as comparison is non const. + assert!(BLOCK_TO_WAIT_FOR_BOOTSTRAP < BLOCK_TO_REVERT_FROM); + assert!(BLOCK_TO_REVERT_FROM < BLOCK_TO_WAIT_FOR_AFTER_REVERT); + + const N_TXS: usize = 50; + /// The number of consolidated local sequencers that participate in the test. + // TODO(noamsp): increase N_CONSOLIDATED_SEQUENCERS to 5 once restart flow test passes. + const N_CONSOLIDATED_SEQUENCERS: usize = 1; + /// The number of distributed remote sequencers that participate in the test. + const N_DISTRIBUTED_SEQUENCERS: usize = 0; + + const AWAIT_REVERT_INTERVAL_MS: u64 = 500; + const MAX_ATTEMPTS: usize = 50; + const AWAIT_REVERT_TIMEOUT_DURATION: Duration = Duration::from_secs(15); + + // Get the sequencer configurations. + let mut integration_test_manager = IntegrationTestManager::new( + N_CONSOLIDATED_SEQUENCERS, + N_DISTRIBUTED_SEQUENCERS, + None, + TestIdentifier::RevertFlowIntegrationTest, + ) + .await; + + let node_indices = integration_test_manager.get_node_indices(); + + integration_test_manager.run_nodes(node_indices.clone()).await; + + info!("Sending bootstrap transactions and verifying state."); + integration_test_manager.send_bootstrap_txs_and_verify().await; + + // Save a snapshot of the tx_generator so we can restore the state after reverting. + let tx_generator_snapshot = integration_test_manager.tx_generator().snapshot(); + + info!("Sending transactions and verifying state."); + integration_test_manager.send_txs_and_verify(N_TXS, 1, BLOCK_TO_REVERT_FROM).await; + + info!("Shutting down nodes."); + integration_test_manager.shutdown_nodes(node_indices.clone()); + + info!( + "Changing revert config for all nodes to revert from block {BLOCK_TO_REVERT_FROM} back to \ + block {BLOCK_TO_WAIT_FOR_BOOTSTRAP}." + ); + let revert_up_to_and_including = Some(BLOCK_TO_WAIT_FOR_BOOTSTRAP.unchecked_next()); + modify_revert_config_idle_nodes( + &mut integration_test_manager, + node_indices.clone(), + revert_up_to_and_including, + ); + + integration_test_manager.run_nodes(node_indices.clone()).await; + + info!("Awaiting for all running nodes to revert back to block {BLOCK_TO_WAIT_FOR_BOOTSTRAP}."); + integration_test_manager + .await_revert_all_running_nodes( + BLOCK_TO_WAIT_FOR_BOOTSTRAP, + AWAIT_REVERT_TIMEOUT_DURATION, + AWAIT_REVERT_INTERVAL_MS, + MAX_ATTEMPTS, + ) + .await; + + info!("All nodes reverted to block {BLOCK_TO_WAIT_FOR_BOOTSTRAP}. Shutting down nodes."); + integration_test_manager.shutdown_nodes(node_indices.clone()); + + // Restore the tx generator state. + *integration_test_manager.tx_generator_mut() = tx_generator_snapshot; + + info!( + "Modifying revert config for all nodes and resume sequencing from block \ + {BLOCK_TO_WAIT_FOR_BOOTSTRAP}." + ); + modify_revert_config_idle_nodes(&mut integration_test_manager, node_indices.clone(), None); + let node_start_height = BLOCK_TO_WAIT_FOR_BOOTSTRAP.unchecked_next(); + modify_height_configs_idle_nodes( + &mut integration_test_manager, + node_indices.clone(), + node_start_height, + ); + + integration_test_manager.run_nodes(node_indices.clone()).await; + + info!("Sending transactions and verifying state."); + integration_test_manager.send_txs_and_verify(N_TXS, 1, BLOCK_TO_WAIT_FOR_AFTER_REVERT).await; + + integration_test_manager.shutdown_nodes(node_indices); + + info!("Revert flow integration test completed successfully!"); +} + +// Modifies the revert config state in the given config. If `revert_up_to_and_including` is +// `None`, the revert config is disabled. Otherwise, the revert config is enabled and set +// to revert up to and including the given block number. +fn modify_revert_config_idle_nodes( + integration_test_manager: &mut IntegrationTestManager, + node_indices: HashSet, + revert_up_to_and_including: Option, +) { + integration_test_manager.modify_config_pointers_idle_nodes( + node_indices.clone(), + |config_pointers| { + modify_revert_config_pointers(config_pointers, revert_up_to_and_including) + }, + ); + integration_test_manager.modify_config_idle_nodes(node_indices, |config_pointers| { + modify_revert_config(config_pointers, revert_up_to_and_including) + }); +} + +fn modify_revert_config_pointers( + config_pointers: &mut ConfigPointersMap, + revert_up_to_and_including: Option, +) { + let should_revert = revert_up_to_and_including.is_some(); + config_pointers.change_target_value("revert_config.should_revert", Value::from(should_revert)); + + // If should revert is false, the revert_up_to_and_including value is irrelevant. + if should_revert { + let revert_up_to_and_including = revert_up_to_and_including.unwrap(); + config_pointers.change_target_value( + "revert_config.revert_up_to_and_including", + Value::from(revert_up_to_and_including.0), + ); + } +} + +fn modify_revert_config( + config: &mut SequencerNodeConfig, + revert_up_to_and_including: Option, +) { + let should_revert = revert_up_to_and_including.is_some(); + config.state_sync_config.revert_config.should_revert = should_revert; + config.consensus_manager_config.revert_config.should_revert = should_revert; + + // If should revert is false, the revert_up_to_and_including value is irrelevant. + if should_revert { + let revert_up_to_and_including = revert_up_to_and_including.unwrap(); + config.state_sync_config.revert_config.revert_up_to_and_including = + revert_up_to_and_including; + config.consensus_manager_config.revert_config.revert_up_to_and_including = + revert_up_to_and_including; + } +} + +fn modify_height_configs_idle_nodes( + integration_test_manager: &mut IntegrationTestManager, + node_indices: HashSet, + node_start_height: BlockNumber, +) { + integration_test_manager.modify_config_idle_nodes(node_indices, |config| { + // TODO(noamsp): Change these values point to a single config value and refactor this + // function accordingly. + config.consensus_manager_config.immediate_active_height = node_start_height; + config.consensus_manager_config.cende_config.skip_write_height = Some(node_start_height); + // TODO(Gilad): remove once we add support to updating the StarknetContract on Anvil. + // This will require mocking the required permissions in the contract that typically + // forbid one from updating the state through an API call. + config.l1_provider_config.provider_startup_height_override = Some(BlockNumber(1)); + }); +} diff --git a/crates/starknet_integration_tests/src/bin/sequencer_node_setup.rs b/crates/starknet_integration_tests/src/bin/sequencer_node_setup.rs new file mode 100644 index 00000000000..73d9e6e2b87 --- /dev/null +++ b/crates/starknet_integration_tests/src/bin/sequencer_node_setup.rs @@ -0,0 +1,63 @@ +use std::path::PathBuf; + +use clap::Parser; +use starknet_infra_utils::test_utils::TestIdentifier; +use starknet_integration_tests::integration_test_manager::IntegrationTestManager; +use starknet_integration_tests::integration_test_utils::set_panic_hook; +use starknet_integration_tests::storage::CustomPaths; +use starknet_sequencer_infra::trace_util::configure_tracing; +use tokio::fs::create_dir_all; +use tracing::info; + +#[tokio::main] +async fn main() { + configure_tracing().await; + info!("Running system test setup."); + + // Parse command line arguments. + let args = Args::parse(); + + set_panic_hook(); + + info!("Generate config and db files under {:?}", args.output_base_dir); + + let custom_paths = CustomPaths::new( + Some(PathBuf::from(args.output_base_dir.clone()).join("data")), + Some(PathBuf::from(args.output_base_dir.clone()).join("configs")), + args.data_prefix_path.map(PathBuf::from), + ); + + let test_manager = IntegrationTestManager::new( + args.n_consolidated, + args.n_distributed, + Some(custom_paths), + TestIdentifier::PositiveFlowIntegrationTest, + ) + .await; + + let simulator_ports_path = format!("{}/simulator_ports", args.output_base_dir); + info!("Generate simulator ports json files under {:?}", simulator_ports_path); + create_dir_all(&simulator_ports_path).await.unwrap(); + for (node_index, node_setup) in test_manager.get_idle_nodes().iter() { + let path = format!("{}/node_{}", simulator_ports_path, node_index); + node_setup.generate_simulator_ports_json(&path); + } + + info!("Node setup completed"); +} + +#[derive(Parser, Debug)] +#[command(name = "node_setup", about = "Generate sequencer db and config files.")] +struct Args { + #[arg(long)] + n_consolidated: usize, + + #[arg(long)] + n_distributed: usize, + + #[arg(long)] + output_base_dir: String, + + #[arg(long)] + data_prefix_path: Option, +} diff --git a/crates/starknet_integration_tests/src/bin/sequencer_simulator.rs b/crates/starknet_integration_tests/src/bin/sequencer_simulator.rs new file mode 100644 index 00000000000..0724204e70c --- /dev/null +++ b/crates/starknet_integration_tests/src/bin/sequencer_simulator.rs @@ -0,0 +1,143 @@ +use std::fs::read_to_string; + +use clap::Parser; +use mempool_test_utils::starknet_api_test_utils::MultiAccountTransactionGenerator; +use serde_json::Value; +use starknet_integration_tests::integration_test_manager::{HTTP_PORT_ARG, MONITORING_PORT_ARG}; +use starknet_integration_tests::integration_test_utils::set_panic_hook; +use starknet_integration_tests::sequencer_simulator_utils::SequencerSimulator; +use starknet_integration_tests::utils::{ + create_integration_test_tx_generator, + BootstrapTxs, + ConsensusTxs, + ACCOUNT_ID_0, + N_TXS_IN_FIRST_BLOCK, +}; +use starknet_sequencer_infra::trace_util::configure_tracing; +use tokio::time::{sleep, Duration}; +use tracing::info; + +fn read_ports_from_file(path: &str) -> (u16, u16) { + // Read the file content + let file_content = read_to_string(path).unwrap(); + + // Parse JSON + let json: Value = serde_json::from_str(&file_content).unwrap(); + + let http_port: u16 = json[HTTP_PORT_ARG] + .as_u64() + .unwrap_or_else(|| panic!("http port should be available in {}", path)) + .try_into() + .expect("http port should be within the valid range for u16"); + + let monitoring_port: u16 = json[MONITORING_PORT_ARG] + .as_u64() + .unwrap_or_else(|| panic!("monitoring port should be available in {}", path)) + .try_into() + .expect("monitoring port should be within the valid range for u16"); + + (http_port, monitoring_port) +} + +fn get_ports(args: &Args) -> (u16, u16) { + match (args.http_port, args.monitoring_port) { + (Some(http), Some(monitoring)) => (http, monitoring), + (None, None) => { + if let Some(ref path) = args.simulator_ports_path { + read_ports_from_file(path) + } else { + panic!( + "Either both --http-port and --monitoring-port should be supplied, or a \ + --simulator-ports-path should be provided." + ); + } + } + _ => panic!( + "Either supply both --http-port and --monitoring-port, or use --simulator-ports-path." + ), + } +} + +async fn run_simulation( + sequencer_simulator: &SequencerSimulator, + tx_generator: &mut MultiAccountTransactionGenerator, + run_forever: bool, +) { + const N_TXS: usize = 50; + const SLEEP_DURATION: Duration = Duration::from_secs(1); + + let mut i = 1; + loop { + sequencer_simulator + .send_txs( + tx_generator, + &ConsensusTxs { + n_invoke_txs: N_TXS, + // TODO(Arni): Add non-zero value. + n_l1_handler_txs: 0, + }, + ACCOUNT_ID_0, + ) + .await; + sequencer_simulator.await_txs_accepted(0, i * N_TXS + N_TXS_IN_FIRST_BLOCK).await; + + if !run_forever { + break; + } + + sleep(SLEEP_DURATION).await; + i += 1; + } +} + +#[derive(Parser, Debug)] +#[command(name = "sequencer_simulator", about = "Run sequencer simulator.")] +struct Args { + #[arg(long, default_value = "http://127.0.0.1")] + http_url: String, + + #[arg(long, default_value = "http://127.0.0.1")] + monitoring_url: String, + + #[arg(long)] + simulator_ports_path: Option, + + #[arg(long)] + http_port: Option, + + #[arg(long)] + monitoring_port: Option, + + #[arg(long, help = "Run the simulator in an infinite loop")] + run_forever: bool, +} + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + configure_tracing().await; + set_panic_hook(); + + let args = Args::parse(); + + let mut tx_generator = create_integration_test_tx_generator(); + + let (http_port, monitoring_port) = get_ports(&args); + + let sequencer_simulator = + SequencerSimulator::new(args.http_url, http_port, args.monitoring_url, monitoring_port); + + info!("Sending bootstrap txs"); + sequencer_simulator.send_txs(&mut tx_generator, &BootstrapTxs, ACCOUNT_ID_0).await; + + // Wait for the bootstrap transaction to be accepted in a separate block. + sequencer_simulator.await_txs_accepted(0, N_TXS_IN_FIRST_BLOCK).await; + + run_simulation(&sequencer_simulator, &mut tx_generator, args.run_forever).await; + + // TODO(Nadin): pass node index as an argument. + sequencer_simulator.verify_txs_accepted(0, &mut tx_generator, ACCOUNT_ID_0).await; + + info!("Simulation completed successfully"); + + Ok(()) +} diff --git a/crates/starknet_integration_tests/src/config_tests.rs b/crates/starknet_integration_tests/src/config_tests.rs new file mode 100644 index 00000000000..124081b6d00 --- /dev/null +++ b/crates/starknet_integration_tests/src/config_tests.rs @@ -0,0 +1,51 @@ +use std::fs::File; +use std::path::PathBuf; +use std::process::{Command, Stdio}; + +use serde_json::{from_reader, Value}; +use starknet_infra_utils::path::resolve_project_relative_path; +use starknet_infra_utils::test_utils::assert_json_eq; +use tempfile::NamedTempFile; + +use crate::consts::SINGLE_NODE_CONFIG_PATH; + +/// Test that the single node preset is up to date. To update it, run: +/// cargo run --bin system_test_dump_single_node_config -q +#[test] +fn single_node_preset_is_up_to_date() { + let config_path: PathBuf = resolve_project_relative_path(SINGLE_NODE_CONFIG_PATH).unwrap(); + assert!(config_path.exists(), "Config file does not exist at expected path: {:?}", config_path); + + // Current config path content. + let from_config_file: Value = from_reader(File::open(&config_path).unwrap()).unwrap(); + + // Use a named temporary file. + let tmp_file = NamedTempFile::new().expect("temporary file should be created"); + let tmp_file_path = tmp_file.path().to_path_buf(); + let child = Command::new("cargo") + .args([ + "run", + "--bin", + "system_test_dump_single_node_config", + "--", + "--config-output-path", + tmp_file_path.to_str().unwrap(), + ]) + .stderr(Stdio::inherit()) + .stdout(Stdio::piped()) + .spawn() + .expect("Spawning system_test_dump_single_node_config should succeed."); + + let output = child.wait_with_output().expect("child process output should be available"); + assert!(output.status.success(), "Binary execution failed"); + + assert!(tmp_file_path.exists(), "Temp config file was not created."); + + // Read and compare JSON + let from_code: serde_json::Value = + serde_json::from_reader(File::open(&tmp_file_path).unwrap()).unwrap(); + + let error_message = "Single node config file is not up to date."; + + assert_json_eq(&from_config_file, &from_code, error_message.to_string()); +} diff --git a/crates/starknet_integration_tests/src/config_utils.rs b/crates/starknet_integration_tests/src/config_utils.rs deleted file mode 100644 index 40f3f904344..00000000000 --- a/crates/starknet_integration_tests/src/config_utils.rs +++ /dev/null @@ -1,83 +0,0 @@ -use std::fs::File; -use std::io::Write; -use std::path::PathBuf; - -use serde_json::{json, Value}; -use starknet_sequencer_node::config::node_config::SequencerNodeConfig; -use starknet_sequencer_node::config::test_utils::RequiredParams; -use tracing::info; -// TODO(Tsabary): Move here all config-related functions from "integration_test_utils.rs". - -const NODE_CONFIG_CHANGES_FILE_PATH: &str = "node_integration_test_config_changes.json"; - -/// A utility macro that takes a list of config fields and returns a json dictionary with "field -/// name : field value" entries, where prefixed "config." name is removed from the entry key. -/// -/// # Example (not running, to avoid function visibility modifications): -/// -/// use serde_json::json; -/// struct ConfigStruct { -/// field_1: u32, -/// field_2: String, -/// field_3: u32, -/// } -/// let config = ConfigStruct { field_1: 1, field_2: "2".to_string() , field_3: 3}; -/// let json_data = config_fields_to_json!(config.field_1, config.field_2); -/// assert_eq!(json_data, json!({"field_1": 1, "field_2": "2"})); -macro_rules! config_fields_to_json { - ( $( $expr:expr ),+ , ) => { - json!({ - $( - strip_config_prefix(stringify!($expr)): $expr - ),+ - }) - }; -} - -/// Creates a config file for the sequencer node for the end to end integration test. -pub(crate) fn dump_config_file_changes( - config: &SequencerNodeConfig, - required_params: RequiredParams, - dir: PathBuf, -) -> PathBuf { - // Dump config changes file for the sequencer node. - // TODO(Tsabary): auto dump the entirety of RequiredParams fields. - let json_data = config_fields_to_json!( - required_params.chain_id, - required_params.eth_fee_token_address, - required_params.strk_fee_token_address, - required_params.sequencer_address, - config.rpc_state_reader_config.json_rpc_version, - config.rpc_state_reader_config.url, - config.batcher_config.storage.db_config.path_prefix, - config.http_server_config.ip, - config.http_server_config.port, - config.consensus_manager_config.consensus_config.start_height, - ); - let node_config_path = dump_json_data(json_data, NODE_CONFIG_CHANGES_FILE_PATH, dir); - assert!(node_config_path.exists(), "File does not exist: {:?}", node_config_path); - - node_config_path -} - -/// Dumps the input JSON data to a file at the specified path. -fn dump_json_data(json_data: Value, path: &str, dir: PathBuf) -> PathBuf { - let temp_dir_path = dir.join(path); - // Serialize the JSON data to a pretty-printed string - let json_string = serde_json::to_string_pretty(&json_data).unwrap(); - - // Write the JSON string to a file - let mut file = File::create(&temp_dir_path).unwrap(); - file.write_all(json_string.as_bytes()).unwrap(); - - info!("Writing required config changes to: {:?}", &temp_dir_path); - temp_dir_path -} - -/// Strips the "config." and "required_params." prefixes from the input string. -fn strip_config_prefix(input: &str) -> &str { - input - .strip_prefix("config.") - .or_else(|| input.strip_prefix("required_params.")) - .unwrap_or(input) -} diff --git a/crates/starknet_integration_tests/src/consts.rs b/crates/starknet_integration_tests/src/consts.rs new file mode 100644 index 00000000000..f084553ae0f --- /dev/null +++ b/crates/starknet_integration_tests/src/consts.rs @@ -0,0 +1,4 @@ +// TODO(Tsabray): avoid re-exporting here, and directly import when needed. +pub use starknet_sequencer_deployments::deployment_definitions::SINGLE_NODE_CONFIG_PATH; + +pub const DATA_PREFIX_PATH: &str = "/data"; diff --git a/crates/starknet_integration_tests/src/executable_setup.rs b/crates/starknet_integration_tests/src/executable_setup.rs new file mode 100644 index 00000000000..cac023ac666 --- /dev/null +++ b/crates/starknet_integration_tests/src/executable_setup.rs @@ -0,0 +1,155 @@ +use std::net::SocketAddr; +use std::path::{Path, PathBuf}; + +use starknet_infra_utils::test_utils::AvailablePorts; +use starknet_monitoring_endpoint::config::MonitoringEndpointConfig; +use starknet_monitoring_endpoint::test_utils::MonitoringClient; +use starknet_sequencer_node::config::component_config::ComponentConfig; +use starknet_sequencer_node::config::config_utils::{ + dump_config_file, + DeploymentBaseAppConfig, + PresetConfig, +}; +use starknet_sequencer_node::config::definitions::ConfigPointersMap; +use starknet_sequencer_node::config::node_config::{ + SequencerNodeConfig, + CONFIG_NON_POINTERS_WHITELIST, +}; +use starknet_sequencer_node::test_utils::node_runner::NodeRunner; +use tempfile::{tempdir, TempDir}; +use tokio::fs::create_dir_all; + +const NODE_CONFIG_CHANGES_FILE_PATH: &str = "node_integration_test_config_changes.json"; + +#[derive(Debug, Copy, Clone)] +pub struct NodeExecutionId { + node_index: usize, + executable_index: usize, +} + +impl NodeExecutionId { + pub fn new(node_index: usize, executable_index: usize) -> Self { + Self { node_index, executable_index } + } + pub fn get_node_index(&self) -> usize { + self.node_index + } + pub fn get_executable_index(&self) -> usize { + self.executable_index + } + + pub fn build_path(&self, base: &Path) -> PathBuf { + base.join(format!("node_{}", self.node_index)) + .join(format!("executable_{}", self.executable_index)) + } +} + +impl std::fmt::Display for NodeExecutionId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "Node id {} part {}", self.node_index, self.executable_index) + } +} + +impl From for NodeRunner { + fn from(val: NodeExecutionId) -> Self { + NodeRunner::new(val.node_index, val.executable_index) + } +} + +pub struct ExecutableSetup { + // Node test identifier. + pub node_execution_id: NodeExecutionId, + // Client for checking liveness of the sequencer node. + pub monitoring_client: MonitoringClient, + // Path to the node configuration file. + pub node_config_path: PathBuf, + // Config values. + pub config: SequencerNodeConfig, + // Configuration parameters that share the same value across multiple components. + pub config_pointers_map: ConfigPointersMap, + // Handles for the config files, maintained so the files are not deleted. Since + // these are only maintained to avoid dropping the handles, private visibility suffices, and + // as such, the '#[allow(dead_code)]' attributes are used to suppress the warning. + #[allow(dead_code)] + node_config_dir_handle: Option, +} + +impl ExecutableSetup { + pub async fn new( + bas_app_config: DeploymentBaseAppConfig, + config_pointers_map: ConfigPointersMap, + node_execution_id: NodeExecutionId, + mut available_ports: AvailablePorts, + config_path_dir: Option, + component_config: ComponentConfig, + ) -> Self { + // Explicitly collect metrics in the monitoring endpoint. + let monitoring_endpoint_config = MonitoringEndpointConfig { + port: available_ports.get_next_port(), + collect_metrics: true, + ..Default::default() + }; + + let (node_config_dir, node_config_dir_handle) = match config_path_dir { + Some(config_path_dir) => { + create_dir_all(&config_path_dir).await.unwrap(); + (config_path_dir, None) + } + None => { + let node_config_dir_handle = tempdir().unwrap(); + (node_config_dir_handle.path().to_path_buf(), Some(node_config_dir_handle)) + } + }; + // Wait for the node to start. + let MonitoringEndpointConfig { ip, port, .. } = monitoring_endpoint_config; + let monitoring_client = MonitoringClient::new(SocketAddr::from((ip, port))); + + let config_path = node_config_dir.join(NODE_CONFIG_CHANGES_FILE_PATH); + let preset_config = PresetConfig { + config_path: config_path.clone(), + component_config, + monitoring_endpoint_config, + }; + + let updated_config = bas_app_config.dump_config_file(preset_config); + + Self { + node_execution_id, + monitoring_client, + config: updated_config, + config_pointers_map, + node_config_dir_handle, + node_config_path: config_path, + } + } + + pub fn modify_config(&mut self, modify_config_fn: F) + where + F: Fn(&mut SequencerNodeConfig), + { + modify_config_fn(&mut self.config); + self.dump_config_file_changes(); + } + + pub fn modify_config_pointers(&mut self, modify_config_pointers_fn: F) + where + F: Fn(&mut ConfigPointersMap), + { + modify_config_pointers_fn(&mut self.config_pointers_map); + self.dump_config_file_changes(); + } + + pub fn config(&self) -> &SequencerNodeConfig { + &self.config + } + + /// Creates a config file for the sequencer node for an integration test. + pub fn dump_config_file_changes(&self) { + dump_config_file( + self.config.clone(), + &self.config_pointers_map.clone().into(), + &CONFIG_NON_POINTERS_WHITELIST, + &self.node_config_path, + ); + } +} diff --git a/crates/starknet_integration_tests/src/flow_test_setup.rs b/crates/starknet_integration_tests/src/flow_test_setup.rs index cecefd60cdf..9f7ea45c2f2 100644 --- a/crates/starknet_integration_tests/src/flow_test_setup.rs +++ b/crates/starknet_integration_tests/src/flow_test_setup.rs @@ -1,85 +1,271 @@ +use std::collections::HashMap; use std::net::SocketAddr; +use std::sync::Arc; -use mempool_test_utils::starknet_api_test_utils::MultiAccountTransactionGenerator; +use alloy::node_bindings::AnvilInstance; +use blockifier::context::ChainInfo; +use futures::StreamExt; +use mempool_test_utils::starknet_api_test_utils::{ + AccountTransactionGenerator, + MultiAccountTransactionGenerator, +}; +use papyrus_base_layer::ethereum_base_layer_contract::EthereumBaseLayerConfig; +use papyrus_base_layer::test_utils::{ + ethereum_base_layer_config_for_anvil, + spawn_anvil_and_deploy_starknet_l1_contract, + StarknetL1Contract, +}; +use papyrus_network::gossipsub_impl::Topic; +use papyrus_network::network_manager::test_utils::{ + create_connected_network_configs, + network_config_into_broadcast_channels, +}; use papyrus_network::network_manager::BroadcastTopicChannels; -use papyrus_protobuf::consensus::ProposalPart; +use papyrus_protobuf::consensus::{HeightAndRound, ProposalPart, StreamMessage, StreamMessageBody}; +use papyrus_storage::StorageConfig; +use starknet_api::block::BlockNumber; +use starknet_api::consensus_transaction::ConsensusTransaction; +use starknet_api::core::{ChainId, ContractAddress}; +use starknet_api::execution_resources::GasAmount; use starknet_api::rpc_transaction::RpcTransaction; -use starknet_api::transaction::TransactionHash; +use starknet_api::transaction::{ + L1HandlerTransaction, + TransactionHash, + TransactionHasher, + TransactionVersion, +}; +use starknet_consensus_manager::config::ConsensusManagerConfig; use starknet_gateway_types::errors::GatewaySpecError; use starknet_http_server::config::HttpServerConfig; -use starknet_sequencer_infra::trace_util::configure_tracing; +use starknet_http_server::test_utils::HttpTestClient; +use starknet_infra_utils::test_utils::AvailablePorts; +use starknet_mempool_p2p::config::MempoolP2pConfig; +use starknet_monitoring_endpoint::config::MonitoringEndpointConfig; +use starknet_monitoring_endpoint::test_utils::MonitoringClient; +use starknet_sequencer_node::clients::SequencerNodeClients; +use starknet_sequencer_node::config::component_config::ComponentConfig; +use starknet_sequencer_node::config::node_config::SequencerNodeConfig; use starknet_sequencer_node::servers::run_component_servers; use starknet_sequencer_node::utils::create_node_modules; -use starknet_task_executor::tokio_executor::TokioExecutor; -use tempfile::TempDir; -use tokio::runtime::Handle; -use tokio::task::JoinHandle; +use starknet_state_sync::config::StateSyncConfig; +use starknet_types_core::felt::Felt; +use tokio::sync::Mutex; +use tracing::{debug, instrument}; +use url::Url; -use crate::state_reader::{spawn_test_rpc_state_reader, StorageTestSetup}; -use crate::utils::{create_chain_info, create_config, HttpTestClient}; +use crate::state_reader::{StorageTestHandles, StorageTestSetup}; +use crate::utils::{ + create_consensus_manager_configs_from_network_configs, + create_mempool_p2p_configs, + create_node_config, + create_state_sync_configs, + send_message_to_l2, + set_validator_id, + spawn_local_eth_to_strk_oracle, + spawn_local_success_recorder, + AccumulatedTransactions, +}; -pub struct FlowTestSetup { - pub task_executor: TokioExecutor, +const SEQUENCER_0: usize = 0; +const SEQUENCER_1: usize = 1; +const SEQUENCER_INDICES: [usize; 2] = [SEQUENCER_0, SEQUENCER_1]; +const BUILDER_BASE_ADDRESS: Felt = Felt::from_hex_unchecked("0x42"); - // Client for adding transactions to the sequencer node. - pub add_tx_http_client: HttpTestClient, - - // Handlers for the storage files, maintained so the files are not deleted. - pub batcher_storage_file_handle: TempDir, - pub rpc_storage_file_handle: TempDir, +pub struct FlowTestSetup { + pub sequencer_0: FlowSequencerSetup, + pub sequencer_1: FlowSequencerSetup, - // Handle of the sequencer node. - pub sequencer_node_handle: JoinHandle>, + // Handle for L1 server: the server is dropped when handle is dropped. + #[allow(dead_code)] + l1_handle: AnvilInstance, + starknet_l1_contract: StarknetL1Contract, // Channels for consensus proposals, used for asserting the right transactions are proposed. - pub consensus_proposals_channels: BroadcastTopicChannels, + pub consensus_proposals_channels: + BroadcastTopicChannels>, } impl FlowTestSetup { - pub async fn new_from_tx_generator(tx_generator: &MultiAccountTransactionGenerator) -> Self { - let handle = Handle::current(); - let task_executor = TokioExecutor::new(handle); - let chain_info = create_chain_info(); - - // Configure and start tracing. - configure_tracing(); + #[instrument(skip(tx_generator), level = "debug")] + pub async fn new_from_tx_generator( + tx_generator: &MultiAccountTransactionGenerator, + test_unique_index: u16, + block_max_capacity_sierra_gas: GasAmount, + ) -> Self { + let chain_info = ChainInfo::create_for_testing(); + let mut available_ports = AvailablePorts::new(test_unique_index, 0); let accounts = tx_generator.accounts(); - let storage_for_test = StorageTestSetup::new(accounts, chain_info.chain_id.clone()); + let (consensus_manager_configs, consensus_proposals_channels) = + create_consensus_manager_configs_and_channels( + available_ports.get_next_ports(SEQUENCER_INDICES.len() + 1), + &chain_info.chain_id, + ); + let [sequencer_0_consensus_manager_config, sequencer_1_consensus_manager_config]: [ConsensusManagerConfig; + 2] = consensus_manager_configs.try_into().unwrap(); + + let ports = available_ports.get_next_ports(SEQUENCER_INDICES.len()); + let mempool_p2p_configs = create_mempool_p2p_configs(chain_info.chain_id.clone(), ports); + let [sequencer_0_mempool_p2p_config, sequencer_1_mempool_p2p_config]: [MempoolP2pConfig; + 2] = mempool_p2p_configs.try_into().unwrap(); + + let [sequencer_0_state_sync_config, sequencer_1_state_sync_config]: [StateSyncConfig; 2] = + create_state_sync_configs(StorageConfig::default(), available_ports.get_next_ports(2)) + .try_into() + .unwrap(); + + let base_layer_config = + ethereum_base_layer_config_for_anvil(Some(available_ports.get_next_port())); + let (anvil, starknet_l1_contract) = + spawn_anvil_and_deploy_starknet_l1_contract(&base_layer_config).await; - // Spawn a papyrus rpc server for a papyrus storage reader. - let rpc_server_addr = spawn_test_rpc_state_reader( - storage_for_test.rpc_storage_reader, - chain_info.chain_id.clone(), + // Create nodes one after the other in order to make sure the ports are not overlapping. + let sequencer_0 = FlowSequencerSetup::new( + accounts.to_vec(), + SEQUENCER_0, + chain_info.clone(), + base_layer_config.clone(), + sequencer_0_consensus_manager_config, + sequencer_0_mempool_p2p_config, + AvailablePorts::new(test_unique_index, 1), + sequencer_0_state_sync_config, + block_max_capacity_sierra_gas, ) .await; + let sequencer_1 = FlowSequencerSetup::new( + accounts.to_vec(), + SEQUENCER_1, + chain_info, + base_layer_config, + sequencer_1_consensus_manager_config, + sequencer_1_mempool_p2p_config, + AvailablePorts::new(test_unique_index, 2), + sequencer_1_state_sync_config, + block_max_capacity_sierra_gas, + ) + .await; + + Self { + sequencer_0, + sequencer_1, + l1_handle: anvil, + starknet_l1_contract, + consensus_proposals_channels, + } + } + + pub async fn assert_add_tx_error(&self, tx: RpcTransaction) -> GatewaySpecError { + self.sequencer_0.add_tx_http_client.assert_add_tx_error(tx).await + } + + pub fn chain_id(&self) -> &ChainId { + // TODO(Arni): Get the chain ID from a shared canonic location. + &self.sequencer_0.node_config.batcher_config.block_builder_config.chain_info.chain_id + } + + pub async fn send_messages_to_l2(&self, l1_handler_txs: &[L1HandlerTransaction]) { + for l1_handler in l1_handler_txs { + send_message_to_l2(l1_handler, &self.starknet_l1_contract).await; + } + } +} + +pub struct FlowSequencerSetup { + /// Used to differentiate between different sequencer nodes. + pub node_index: usize, + + // Client for adding transactions to the sequencer node. + pub add_tx_http_client: HttpTestClient, + + // Handles for the storage files, maintained so the files are not deleted. + pub storage_handles: StorageTestHandles, + + // Node configuration. + pub node_config: SequencerNodeConfig, + + // Monitoring client. + pub monitoring_client: MonitoringClient, + + // Retain clients to avoid closing communication channels, which crashes the server and + // subsequently the test. This occurs for components who are wrapped by servers, but no other + // component has their client, usually due to these clients being added in a later date. + clients: SequencerNodeClients, +} + +impl FlowSequencerSetup { + #[allow(clippy::too_many_arguments)] + #[instrument(skip(accounts, chain_info, consensus_manager_config), level = "debug")] + pub async fn new( + accounts: Vec, + node_index: usize, + chain_info: ChainInfo, + base_layer_config: EthereumBaseLayerConfig, + mut consensus_manager_config: ConsensusManagerConfig, + mempool_p2p_config: MempoolP2pConfig, + mut available_ports: AvailablePorts, + state_sync_config: StateSyncConfig, + block_max_capacity_sierra_gas: GasAmount, + ) -> Self { + let path = None; + let StorageTestSetup { storage_config, storage_handles } = + StorageTestSetup::new(accounts, &chain_info, path); + + let (recorder_url, _join_handle) = + spawn_local_success_recorder(available_ports.get_next_port()); + consensus_manager_config.cende_config.recorder_url = recorder_url; + + let (eth_to_strk_oracle_url, _join_handle) = + spawn_local_eth_to_strk_oracle(available_ports.get_next_port()); + consensus_manager_config.eth_to_strk_oracle_config.base_url = eth_to_strk_oracle_url; + + let validator_id = set_validator_id(&mut consensus_manager_config, node_index); + + let component_config = ComponentConfig::default(); + + // Explicitly avoid collecting metrics in the monitoring endpoint; metrics are collected + // using a global recorder, which fails when being set multiple times in the same + // process, as in this test. + let monitoring_endpoint_config = MonitoringEndpointConfig { + port: available_ports.get_next_port(), + collect_metrics: false, + ..Default::default() + }; + // Derive the configuration for the sequencer node. - let (config, _required_params, consensus_proposals_channels) = - create_config(chain_info, rpc_server_addr, storage_for_test.batcher_storage_config) - .await; + let (node_config, _config_pointers_map) = create_node_config( + &mut available_ports, + chain_info, + storage_config, + state_sync_config, + consensus_manager_config, + mempool_p2p_config, + monitoring_endpoint_config, + component_config, + base_layer_config, + block_max_capacity_sierra_gas, + validator_id, + ); - let (_clients, servers) = create_node_modules(&config); + debug!("Sequencer config: {:#?}", node_config); + let (clients, servers) = create_node_modules(&node_config).await; - let HttpServerConfig { ip, port } = config.http_server_config; - let add_tx_http_client = HttpTestClient::new(SocketAddr::from((ip, port))); + let MonitoringEndpointConfig { ip, port, .. } = node_config.monitoring_endpoint_config; + let monitoring_client = MonitoringClient::new(SocketAddr::from((ip, port))); - // Build and run the sequencer node. - let sequencer_node_future = run_component_servers(servers); - let sequencer_node_handle = task_executor.spawn_with_handle(sequencer_node_future); + let HttpServerConfig { ip, port } = node_config.http_server_config; + let add_tx_http_client = HttpTestClient::new(SocketAddr::from((ip, port))); - // Wait for server to spin up. - // TODO(Gilad): Replace with a persistent Client with a built-in retry to protect against CI - // flakiness. - tokio::time::sleep(std::time::Duration::from_millis(100)).await; + // Run the sequencer node. + tokio::spawn(run_component_servers(servers)); Self { - task_executor, + node_index, add_tx_http_client, - batcher_storage_file_handle: storage_for_test.batcher_storage_handle, - rpc_storage_file_handle: storage_for_test.rpc_storage_handle, - sequencer_node_handle, - consensus_proposals_channels, + storage_handles, + node_config, + monitoring_client, + clients, } } @@ -87,7 +273,148 @@ impl FlowTestSetup { self.add_tx_http_client.assert_add_tx_success(tx).await } - pub async fn assert_add_tx_error(&self, tx: RpcTransaction) -> GatewaySpecError { - self.add_tx_http_client.assert_add_tx_error(tx).await + pub async fn batcher_height(&self) -> BlockNumber { + self.clients.get_batcher_shared_client().unwrap().get_height().await.unwrap().height + } +} + +pub fn create_consensus_manager_configs_and_channels( + ports: Vec, + chain_id: &ChainId, +) -> ( + Vec, + BroadcastTopicChannels>, +) { + let mut network_configs = create_connected_network_configs(ports); + + // TODO(Tsabary): Need to also add a channel for votes, in addition to the proposals channel. + let channels_network_config = network_configs.pop().unwrap(); + + let n_network_configs = network_configs.len(); + let mut consensus_manager_configs = create_consensus_manager_configs_from_network_configs( + network_configs, + n_network_configs, + chain_id, + ); + + for (i, config) in consensus_manager_configs.iter_mut().enumerate() { + config.context_config.builder_address = + ContractAddress::try_from(BUILDER_BASE_ADDRESS + Felt::from(i)).unwrap(); + config.eth_to_strk_oracle_config.base_url = + Url::parse("https://eth_to_strk_oracle_url").expect("Should be a valid URL"); + } + + let broadcast_channels = network_config_into_broadcast_channels( + channels_network_config, + Topic::new(consensus_manager_configs[0].proposals_topic.clone()), + ); + + (consensus_manager_configs, broadcast_channels) +} + +// Collects batched transactions. +struct _TxCollector { + pub consensus_proposals_channels: + BroadcastTopicChannels>, + pub accumulated_txs: Arc>, + pub chain_id: ChainId, +} + +impl _TxCollector { + #[instrument(skip(self))] + pub async fn collect_streamd_txs(mut self) { + loop { + self.listen_to_broadcasted_messages().await; + } + } + + async fn listen_to_broadcasted_messages(&mut self) { + let broadcasted_messages_receiver = + &mut self.consensus_proposals_channels.broadcasted_messages_receiver; + // Collect messages in a map so that validations will use the ordering defined by + // `message_id`, meaning we ignore network reordering, like the StreamHandler. + let mut messages_cache = HashMap::new(); + let mut last_message_id = 0; + + while let Some((Ok(message), _)) = broadcasted_messages_receiver.next().await { + messages_cache.insert(message.message_id, message.clone()); + + if message.message == papyrus_protobuf::consensus::StreamMessageBody::Fin { + last_message_id = message.message_id; + } + // Check that we got the Fin message and all previous messages. + if last_message_id > 0 + && (0..=last_message_id).all(|id| messages_cache.contains_key(&id)) + { + break; + } + } + + let StreamMessage { + stream_id: first_stream_id, + message: init_message, + message_id: incoming_message_id, + } = messages_cache.remove(&0).expect("Stream is missing its first message"); + + assert_eq!( + incoming_message_id, 0, + "Expected the first message in the stream to have id 0, got {}", + incoming_message_id + ); + let StreamMessageBody::Content(ProposalPart::Init(incoming_proposal_init)) = init_message + else { + panic!("Expected an init message. Got: {:?}", init_message) + }; + + let mut received_tx_hashes = Vec::new(); + let mut got_proposal_fin = false; + let mut got_channel_fin = false; + for i in 1_u64..messages_cache.len().try_into().unwrap() { + let StreamMessage { message, stream_id, message_id: _ } = + messages_cache.remove(&i).expect("Stream should have all consecutive messages"); + assert_eq!(stream_id, first_stream_id, "Expected the same stream id for all messages"); + match message { + StreamMessageBody::Content(ProposalPart::Init(init)) => { + panic!("Unexpected init: {:?}", init) + } + StreamMessageBody::Content(ProposalPart::Fin(..)) => { + got_proposal_fin = true; + } + StreamMessageBody::Content(ProposalPart::BlockInfo(_)) => { + // TODO(Asmaa): Add validation for block info. + } + StreamMessageBody::Content(ProposalPart::Transactions(transactions)) => { + // TODO(Arni): add calculate_transaction_hash to consensus transaction and use + // it here. + received_tx_hashes.extend(transactions.transactions.iter().map(|tx| { + match tx { + ConsensusTransaction::RpcTransaction(tx) => { + let starknet_api_tx = + starknet_api::transaction::Transaction::from(tx.clone()); + starknet_api_tx.calculate_transaction_hash(&self.chain_id).unwrap() + } + ConsensusTransaction::L1Handler(tx) => tx + .calculate_transaction_hash( + &self.chain_id, + &TransactionVersion::ZERO, + ) + .unwrap(), + } + })); + + self.accumulated_txs.lock().await.add_transactions( + incoming_proposal_init.height, + incoming_proposal_init.round, + &received_tx_hashes, + ); + } + StreamMessageBody::Fin => { + got_channel_fin = true; + } + } + if got_proposal_fin && got_channel_fin { + break; + } + } } } diff --git a/crates/starknet_integration_tests/src/integration_test_manager.rs b/crates/starknet_integration_tests/src/integration_test_manager.rs new file mode 100644 index 00000000000..a934cbe64dd --- /dev/null +++ b/crates/starknet_integration_tests/src/integration_test_manager.rs @@ -0,0 +1,825 @@ +use std::collections::{HashMap, HashSet}; +use std::future::Future; +use std::net::{Ipv4Addr, SocketAddr}; +use std::path::PathBuf; +use std::time::Duration; + +use alloy::node_bindings::AnvilInstance; +use blockifier::context::ChainInfo; +use futures::future::join_all; +use futures::TryFutureExt; +use mempool_test_utils::starknet_api_test_utils::{AccountId, MultiAccountTransactionGenerator}; +use papyrus_base_layer::test_utils::{ + ethereum_base_layer_config_for_anvil, + spawn_anvil_and_deploy_starknet_l1_contract, + StarknetL1Contract, +}; +use papyrus_network::network_manager::test_utils::create_connected_network_configs; +use papyrus_storage::StorageConfig; +use starknet_api::block::BlockNumber; +use starknet_api::core::{ChainId, Nonce}; +use starknet_api::execution_resources::GasAmount; +use starknet_api::rpc_transaction::RpcTransaction; +use starknet_api::transaction::TransactionHash; +use starknet_http_server::config::HttpServerConfig; +use starknet_http_server::test_utils::HttpTestClient; +use starknet_infra_utils::test_utils::{AvailablePortsGenerator, TestIdentifier}; +use starknet_infra_utils::tracing::{CustomLogger, TraceLevel}; +use starknet_monitoring_endpoint::config::MonitoringEndpointConfig; +use starknet_monitoring_endpoint::test_utils::MonitoringClient; +use starknet_sequencer_node::config::component_config::ComponentConfig; +use starknet_sequencer_node::config::config_utils::{dump_json_data, DeploymentBaseAppConfig}; +use starknet_sequencer_node::config::definitions::ConfigPointersMap; +use starknet_sequencer_node::config::node_config::{ + SequencerNodeConfig, + CONFIG_NON_POINTERS_WHITELIST, +}; +use starknet_sequencer_node::test_utils::node_runner::{get_node_executable_path, spawn_run_node}; +use tokio::join; +use tokio::task::JoinHandle; +use tracing::info; + +use crate::executable_setup::{ExecutableSetup, NodeExecutionId}; +use crate::monitoring_utils::{ + await_batcher_block, + await_block, + await_sync_block, + await_txs_accepted, + sequencer_num_accepted_txs, + verify_txs_accepted, +}; +use crate::node_component_configs::{ + create_consolidated_sequencer_configs, + create_nodes_deployment_units_configs, +}; +use crate::sequencer_simulator_utils::SequencerSimulator; +use crate::state_reader::StorageTestHandles; +use crate::storage::{get_integration_test_storage, CustomPaths}; +use crate::utils::{ + create_consensus_manager_configs_from_network_configs, + create_integration_test_tx_generator, + create_mempool_p2p_configs, + create_node_config, + create_state_sync_configs, + send_consensus_txs, + send_message_to_l2_and_calculate_tx_hash, + set_validator_id, + spawn_local_eth_to_strk_oracle, + spawn_local_success_recorder, + BootstrapTxs, + ConsensusTxs, + TestScenario, +}; + +pub const DEFAULT_SENDER_ACCOUNT: AccountId = 0; +const BLOCK_MAX_CAPACITY_N_STEPS: GasAmount = GasAmount(30000000); +pub const BLOCK_TO_WAIT_FOR_BOOTSTRAP: BlockNumber = BlockNumber(2); + +pub const HTTP_PORT_ARG: &str = "http-port"; +pub const MONITORING_PORT_ARG: &str = "monitoring-port"; + +pub struct NodeSetup { + executables: Vec, + batcher_index: usize, + http_server_index: usize, + state_sync_index: usize, + + // Client for adding transactions to the sequencer node. + pub add_tx_http_client: HttpTestClient, + + // Handles for the storage files, maintained so the files are not deleted. Since + // these are only maintained to avoid dropping the handles, private visibility suffices, and + // as such, the '#[allow(dead_code)]' attributes are used to suppress the warning. + #[allow(dead_code)] + storage_handles: StorageTestHandles, +} + +// TODO(Nadin): reduce the number of arguments. +#[allow(clippy::too_many_arguments)] +impl NodeSetup { + pub fn new( + executables: Vec, + batcher_index: usize, + http_server_index: usize, + state_sync_index: usize, + add_tx_http_client: HttpTestClient, + storage_handles: StorageTestHandles, + ) -> Self { + let len = executables.len(); + + fn validate_index(index: usize, len: usize, label: &str) { + assert!( + index < len, + "{} index {} is out of range. There are {} executables.", + label, + index, + len + ); + } + + validate_index(batcher_index, len, "Batcher"); + validate_index(http_server_index, len, "HTTP server"); + validate_index(state_sync_index, len, "State sync"); + + Self { + executables, + batcher_index, + http_server_index, + state_sync_index, + add_tx_http_client, + storage_handles, + } + } + + async fn send_rpc_tx_fn(&self, rpc_tx: RpcTransaction) -> TransactionHash { + self.add_tx_http_client.assert_add_tx_success(rpc_tx).await + } + + pub fn batcher_monitoring_client(&self) -> &MonitoringClient { + &self.executables[self.batcher_index].monitoring_client + } + + pub fn state_sync_monitoring_client(&self) -> &MonitoringClient { + &self.executables[self.state_sync_index].monitoring_client + } + + pub fn get_executables(&self) -> &Vec { + &self.executables + } + + pub fn set_executable_config_path( + &mut self, + index: usize, + new_path: PathBuf, + ) -> Result<(), &'static str> { + if let Some(exec) = self.executables.get_mut(index) { + exec.node_config_path = new_path; + Ok(()) + } else { + panic!("Invalid executable index") + } + } + + pub fn generate_simulator_ports_json(&self, path: &str) { + let json_data = serde_json::json!({ + HTTP_PORT_ARG: self.executables[self.http_server_index].config.http_server_config.port, + MONITORING_PORT_ARG: self.executables[self.batcher_index].config.monitoring_endpoint_config.port + }); + + dump_json_data(json_data, &PathBuf::from(path)); + } + + pub fn get_batcher_index(&self) -> usize { + self.batcher_index + } + + pub fn get_http_server_index(&self) -> usize { + self.http_server_index + } + + pub fn get_state_sync_index(&self) -> usize { + self.state_sync_index + } + + pub fn run(self) -> RunningNode { + let executable_handles = self + .get_executables() + .iter() + .map(|executable| { + info!("Running {}.", executable.node_execution_id); + spawn_run_node( + executable.node_config_path.clone(), + executable.node_execution_id.into(), + ) + }) + .collect::>(); + + RunningNode { node_setup: self, executable_handles } + } + pub fn get_node_index(&self) -> Option { + self.executables.first().map(|executable| executable.node_execution_id.get_node_index()) + } +} + +pub struct RunningNode { + node_setup: NodeSetup, + executable_handles: Vec>, +} + +impl RunningNode { + async fn await_alive(&self, interval: u64, max_attempts: usize) { + let await_alive_tasks = self.node_setup.executables.iter().map(|executable| { + let result = executable.monitoring_client.await_alive(interval, max_attempts); + result.unwrap_or_else(|_| { + panic!("Executable {:?} should be alive.", executable.node_execution_id) + }) + }); + + join_all(await_alive_tasks).await; + } +} + +pub struct IntegrationTestManager { + node_indices: HashSet, + idle_nodes: HashMap, + running_nodes: HashMap, + tx_generator: MultiAccountTransactionGenerator, + // Handle for L1 server: the server is dropped when handle is dropped. + #[allow(dead_code)] + l1_handle: AnvilInstance, + starknet_l1_contract: StarknetL1Contract, +} + +impl IntegrationTestManager { + pub async fn new( + num_of_consolidated_nodes: usize, + num_of_distributed_nodes: usize, + custom_paths: Option, + test_unique_id: TestIdentifier, + ) -> Self { + let tx_generator = create_integration_test_tx_generator(); + + let (sequencers_setup, node_indices) = get_sequencer_setup_configs( + &tx_generator, + num_of_consolidated_nodes, + num_of_distributed_nodes, + custom_paths, + test_unique_id, + ) + .await; + + let base_layer_config = &sequencers_setup[0].executables[0].config.base_layer_config; + let (anvil, starknet_l1_contract) = + spawn_anvil_and_deploy_starknet_l1_contract(base_layer_config).await; + + let idle_nodes = create_map(sequencers_setup, |node| node.get_node_index()); + let running_nodes = HashMap::new(); + + Self { + node_indices, + idle_nodes, + running_nodes, + tx_generator, + l1_handle: anvil, + starknet_l1_contract, + } + } + + pub fn get_idle_nodes(&self) -> &HashMap { + &self.idle_nodes + } + + pub fn tx_generator(&self) -> &MultiAccountTransactionGenerator { + &self.tx_generator + } + + pub fn tx_generator_mut(&mut self) -> &mut MultiAccountTransactionGenerator { + &mut self.tx_generator + } + + pub async fn run_nodes(&mut self, nodes_to_run: HashSet) { + info!("Checking that the sequencer node executable is present."); + get_node_executable_path(); + // TODO(noamsp): Add size of nodes_to_run to the log. + info!("Running specified nodes."); + + nodes_to_run.into_iter().for_each(|index| { + let node_setup = self + .idle_nodes + .remove(&index) + .unwrap_or_else(|| panic!("Node {} does not exist in idle_nodes.", index)); + info!("Running node {}.", index); + let running_node = node_setup.run(); + assert!( + self.running_nodes.insert(index, running_node).is_none(), + "Node {} is already in the running map.", + index + ); + }); + + // Wait for the nodes to start + self.await_alive(5000, 50).await; + } + + pub fn modify_config_idle_nodes( + &mut self, + nodes_to_modify_config: HashSet, + modify_config_fn: F, + ) where + F: Fn(&mut SequencerNodeConfig) + Copy, + { + info!("Modifying specified nodes config."); + + nodes_to_modify_config.into_iter().for_each(|node_index| { + let node_setup = self + .idle_nodes + .get_mut(&node_index) + .unwrap_or_else(|| panic!("Node {} does not exist in idle_nodes.", node_index)); + node_setup.executables.iter_mut().for_each(|executable| { + info!("Modifying {} config.", executable.node_execution_id); + executable.modify_config(modify_config_fn); + }); + }); + } + + pub fn modify_config_pointers_idle_nodes( + &mut self, + nodes_to_modify_config_pointers: HashSet, + modify_config_pointers_fn: F, + ) where + F: Fn(&mut ConfigPointersMap) + Copy, + { + info!("Modifying specified nodes config pointers."); + + nodes_to_modify_config_pointers.into_iter().for_each(|node_index| { + let node_setup = self + .idle_nodes + .get_mut(&node_index) + .unwrap_or_else(|| panic!("Node {} does not exist in idle_nodes.", node_index)); + node_setup.executables.iter_mut().for_each(|executable| { + info!("Modifying {} config pointers.", executable.node_execution_id); + executable.modify_config_pointers(modify_config_pointers_fn); + }); + }); + } + + pub async fn await_revert_all_running_nodes( + &self, + expected_block_number: BlockNumber, + timeout_duration: Duration, + interval_ms: u64, + max_attempts: usize, + ) { + info!("Waiting for all idle nodes to finish reverting."); + let condition = + |&latest_block_number: &BlockNumber| latest_block_number == expected_block_number; + + let await_reverted_tasks = self.running_nodes.values().map(|running_node| async { + let running_node_setup = &running_node.node_setup; + let batcher_logger = CustomLogger::new( + TraceLevel::Info, + Some(format!( + "Waiting for batcher to reach block {expected_block_number} in sequencer {} \ + executable {}.", + running_node_setup.get_node_index().unwrap(), + running_node_setup.get_batcher_index(), + )), + ); + + // TODO(noamsp): rename batcher index/monitoringClient or use sync + // index/monitoringClient + let sync_logger = CustomLogger::new( + TraceLevel::Info, + Some(format!( + "Waiting for state sync to reach block {expected_block_number} in sequencer \ + {} executable {}.", + running_node_setup.get_node_index().unwrap(), + running_node_setup.get_state_sync_index(), + )), + ); + + join!( + await_batcher_block( + interval_ms, + condition, + max_attempts, + running_node_setup.batcher_monitoring_client(), + batcher_logger, + ), + await_sync_block( + interval_ms, + condition, + max_attempts, + running_node_setup.state_sync_monitoring_client(), + sync_logger, + ) + ) + }); + + tokio::time::timeout(timeout_duration, join_all(await_reverted_tasks)) + .await + .expect("Running Nodes should be reverted."); + + info!( + "All running nodes have been reverted succesfully to block number \ + {expected_block_number}." + ); + } + + pub fn get_node_indices(&self) -> HashSet { + self.node_indices.clone() + } + + pub fn shutdown_nodes(&mut self, nodes_to_shutdown: HashSet) { + nodes_to_shutdown.into_iter().for_each(|index| { + let running_node = self + .running_nodes + .remove(&index) + .unwrap_or_else(|| panic!("Node {} is not in the running map.", index)); + running_node.executable_handles.iter().for_each(|handle| { + assert!(!handle.is_finished(), "Node {} should still be running.", index); + handle.abort(); + }); + assert!( + self.idle_nodes.insert(index, running_node.node_setup).is_none(), + "Node {} is already in the idle map.", + index + ); + info!("Node {} has been shut down.", index); + }); + } + + pub async fn send_bootstrap_txs_and_verify(&mut self) { + self.test_and_verify(BootstrapTxs, DEFAULT_SENDER_ACCOUNT, BLOCK_TO_WAIT_FOR_BOOTSTRAP) + .await; + } + + pub async fn send_txs_and_verify( + &mut self, + n_invoke_txs: usize, + n_l1_handler_txs: usize, + wait_for_block: BlockNumber, + ) { + self.test_and_verify( + ConsensusTxs { n_invoke_txs, n_l1_handler_txs }, + DEFAULT_SENDER_ACCOUNT, + wait_for_block, + ) + .await; + } + + /// Create a simulator that's connected to the http server of Node 0. + pub fn create_simulator(&self) -> SequencerSimulator { + let node_0_setup = self + .running_nodes + .get(&0) + .map(|node| &(node.node_setup)) + .unwrap_or_else(|| self.idle_nodes.get(&0).expect("Node 0 doesn't exist")); + let config = node_0_setup + .executables + .get(node_0_setup.http_server_index) + .expect("http_server_index points to a non existing executable index") + .config(); + + let localhost_url = format!("http://{}", Ipv4Addr::LOCALHOST); + SequencerSimulator::new( + localhost_url.clone(), + config.http_server_config.port, + localhost_url, + config.monitoring_endpoint_config.port, + ) + } + + pub async fn await_txs_accepted_on_all_running_nodes(&mut self, target_n_txs: usize) { + self.perform_action_on_all_running_nodes(|sequencer_idx, running_node| { + let monitoring_client = running_node.node_setup.state_sync_monitoring_client(); + await_txs_accepted(monitoring_client, sequencer_idx, target_n_txs) + }) + .await; + } + + /// This function tests and verifies the integration of the transaction flow. + /// + /// # Parameters + /// - `expected_initial_value`: The initial amount of batched transactions. This represents the + /// starting state before any transactions are sent. + /// - `n_txs`: The number of transactions that will be sent during the test. After the test + /// completes, the nonce in the batcher's storage is expected to be `expected_initial_value + + /// n_txs`. + /// - `tx_generator`: A transaction generator used to create transactions for testing. + /// - `sender_account`: The ID of the account sending the transactions. + /// - `expected_block_number`: The block number up to which execution should be awaited. + /// + /// The function verifies the initial state, runs the test with the given number of + /// transactions, waits for execution to complete, and then verifies the final state. + async fn test_and_verify( + &mut self, + test_scenario: impl TestScenario, + sender_account: AccountId, + wait_for_block: BlockNumber, + ) { + self.verify_txs_accepted_on_all_running_nodes(sender_account).await; + self.run_integration_test_simulator(&test_scenario, sender_account).await; + self.await_block_on_all_running_nodes(wait_for_block).await; + self.verify_txs_accepted_on_all_running_nodes(sender_account).await; + } + + async fn await_alive(&self, interval: u64, max_attempts: usize) { + let await_alive_tasks = + self.running_nodes.values().map(|node| node.await_alive(interval, max_attempts)); + + join_all(await_alive_tasks).await; + } + + async fn run_integration_test_simulator( + &mut self, + test_scenario: &impl TestScenario, + sender_account: AccountId, + ) { + info!("Running integration test simulator."); + let chain_id = self.chain_id(); + let send_l1_handler_tx_fn = &mut |l1_handler_tx| { + send_message_to_l2_and_calculate_tx_hash( + l1_handler_tx, + &self.starknet_l1_contract, + &chain_id, + ) + }; + let send_rpc_tx_fn = &mut |rpc_tx| async { + let node_0 = self.running_nodes.get(&0).expect("Node 0 should be running."); + node_0.node_setup.send_rpc_tx_fn(rpc_tx).await + }; + + send_consensus_txs( + &mut self.tx_generator, + sender_account, + test_scenario, + send_rpc_tx_fn, + send_l1_handler_tx_fn, + ) + .await; + } + + /// Waits until all running nodes reach the specified block number. + /// Queries the batcher and state sync metrics to verify progress. + async fn await_block_on_all_running_nodes(&self, expected_block_number: BlockNumber) { + self.perform_action_on_all_running_nodes(|sequencer_idx, running_node| { + let node_setup = &running_node.node_setup; + let batcher_monitoring_client = node_setup.batcher_monitoring_client(); + let batcher_index = node_setup.get_batcher_index(); + let state_sync_monitoring_client = node_setup.state_sync_monitoring_client(); + let state_sync_index = node_setup.get_state_sync_index(); + await_block( + batcher_monitoring_client, + batcher_index, + state_sync_monitoring_client, + state_sync_index, + expected_block_number, + sequencer_idx, + ) + }) + .await; + } + + pub async fn await_sync_block_on_all_running_nodes( + &mut self, + expected_block_number: BlockNumber, + ) { + let condition = + |&latest_block_number: &BlockNumber| latest_block_number >= expected_block_number; + + self.perform_action_on_all_running_nodes(|sequencer_idx, running_node| async move { + let node_setup = &running_node.node_setup; + let monitoring_client = node_setup.batcher_monitoring_client(); + let batcher_index = node_setup.get_batcher_index(); + let expected_height = expected_block_number.unchecked_next(); + + let logger = CustomLogger::new( + TraceLevel::Info, + Some(format!( + "Waiting for sync height metric to reach block {expected_height} in sequencer \ + {sequencer_idx} executable {batcher_index}.", + )), + ); + await_sync_block(5000, condition, 50, monitoring_client, logger).await.unwrap(); + }) + .await; + } + + async fn verify_txs_accepted_on_all_running_nodes(&self, sender_account: AccountId) { + // We use state syncs processed txs metric via its monitoring client to verify that the + // transactions were accepted. + let account = self.tx_generator.account_with_id(sender_account); + let expected_n_accepted_account_txs = nonce_to_usize(account.get_nonce()); + let expected_n_l1_handler_txs = self.tx_generator.n_l1_txs(); + let expected_n_accepted_txs = expected_n_accepted_account_txs + expected_n_l1_handler_txs; + + self.perform_action_on_all_running_nodes(|sequencer_idx, running_node| { + // We use state syncs processed txs metric via its monitoring client to verify that the + // transactions were accepted. + let monitoring_client = running_node.node_setup.state_sync_monitoring_client(); + verify_txs_accepted(monitoring_client, sequencer_idx, expected_n_accepted_txs) + }) + .await; + } + + async fn perform_action_on_all_running_nodes<'a, F, Fut>(&'a self, f: F) + where + F: Fn(usize, &'a RunningNode) -> Fut, + Fut: Future + 'a, + { + let futures = self + .running_nodes + .iter() + .map(|(sequencer_idx, running_node)| f(*sequencer_idx, running_node)); + join_all(futures).await; + } + + pub fn chain_id(&self) -> ChainId { + // TODO(Arni): Get the chain ID from a shared canonic location. + let node_setup = self + .idle_nodes + .values() + .next() + .or_else(|| self.running_nodes.values().next().map(|node| &node.node_setup)) + .expect("There should be at least one running or idle node"); + + node_setup.executables[0] + .config + .batcher_config + .block_builder_config + .chain_info + .chain_id + .clone() + } + + /// This function returns the number of accepted transactions on all running nodes. + /// It queries the state sync monitoring client to get the latest value of the processed txs + /// metric. + pub async fn get_num_accepted_txs_on_all_running_nodes(&self) -> HashMap { + let mut result = HashMap::new(); + for (index, running_node) in self.running_nodes.iter() { + let monitoring_client = running_node.node_setup.state_sync_monitoring_client(); + let num_accepted = sequencer_num_accepted_txs(monitoring_client).await; + result.insert(*index, num_accepted); + } + result + } +} + +pub fn nonce_to_usize(nonce: Nonce) -> usize { + let prefixed_hex = nonce.0.to_hex_string(); + let unprefixed_hex = prefixed_hex.split_once("0x").unwrap().1; + usize::from_str_radix(unprefixed_hex, 16).unwrap() +} + +pub async fn get_sequencer_setup_configs( + tx_generator: &MultiAccountTransactionGenerator, + // TODO(Tsabary/Nadin): instead of number of nodes, this should be a vector of deployments. + num_of_consolidated_nodes: usize, + num_of_distributed_nodes: usize, + custom_paths: Option, + test_unique_id: TestIdentifier, +) -> (Vec, HashSet) { + let mut available_ports_generator = AvailablePortsGenerator::new(test_unique_id.into()); + + let mut node_component_configs = + Vec::with_capacity(num_of_consolidated_nodes + num_of_distributed_nodes); + for _ in 0..num_of_consolidated_nodes { + node_component_configs.push(create_consolidated_sequencer_configs()); + } + for _ in 0..num_of_distributed_nodes { + node_component_configs + .push(create_nodes_deployment_units_configs(&mut available_ports_generator)); + } + + info!("Creating node configurations."); + let chain_info = ChainInfo::create_for_testing(); + let accounts = tx_generator.accounts(); + let component_configs_len = node_component_configs.len(); + + // TODO(Nadin): Refactor to avoid directly mutating vectors + + let mut consensus_manager_ports = available_ports_generator + .next() + .expect("Failed to get an AvailablePorts instance for consensus manager configs"); + + // TODO(Nadin): pass recorder_url to this function to avoid mutating the resulting configs. + let mut consensus_manager_configs = create_consensus_manager_configs_from_network_configs( + create_connected_network_configs( + consensus_manager_ports.get_next_ports(component_configs_len), + ), + component_configs_len, + &chain_info.chain_id, + ); + + let node_indices: HashSet = (0..component_configs_len).collect(); + + // TODO(Nadin): define the test storage here and pass it to the create_state_sync_configs and to + // the ExecutableSetup + let mut state_sync_ports = available_ports_generator + .next() + .expect("Failed to get an AvailablePorts instance for state sync configs"); + let mut state_sync_configs = create_state_sync_configs( + StorageConfig::default(), + state_sync_ports.get_next_ports(component_configs_len), + ); + + let mut mempool_p2p_ports = available_ports_generator + .next() + .expect("Failed to get an AvailablePorts instance for mempool p2p configs"); + let mut mempool_p2p_configs = create_mempool_p2p_configs( + chain_info.chain_id.clone(), + mempool_p2p_ports.get_next_ports(component_configs_len), + ); + + let mut base_layer_ports = available_ports_generator + .next() + .expect("Failed to get an AvailablePorts instance for base layer config"); + let base_layer_config = + ethereum_base_layer_config_for_anvil(Some(base_layer_ports.get_next_port())); + + let mut nodes = Vec::new(); + + // All nodes use the same recorder_url and eth_to_strk_oracle_url. + let (recorder_url, _join_handle) = + spawn_local_success_recorder(base_layer_ports.get_next_port()); + let (eth_to_strk_oracle_url, _join_handle_eth_to_strk_oracle) = + spawn_local_eth_to_strk_oracle(base_layer_ports.get_next_port()); + + let mut config_available_ports = available_ports_generator + .next() + .expect("Failed to get an AvailablePorts instance for node configs"); + + for (node_index, node_component_config) in node_component_configs.into_iter().enumerate() { + let mut executables = Vec::new(); + let batcher_index = node_component_config.get_batcher_index(); + let http_server_index = node_component_config.get_http_server_index(); + let state_sync_index = node_component_config.get_state_sync_index(); + let class_manager_index = node_component_config.get_class_manager_index(); + + let mut consensus_manager_config = consensus_manager_configs.remove(0); + let mempool_p2p_config = mempool_p2p_configs.remove(0); + let state_sync_config = state_sync_configs.remove(0); + + consensus_manager_config.cende_config.recorder_url = recorder_url.clone(); + consensus_manager_config.eth_to_strk_oracle_config.base_url = + eth_to_strk_oracle_url.clone(); + + let validator_id = set_validator_id(&mut consensus_manager_config, node_index); + let chain_info = chain_info.clone(); + + let storage_setup = get_integration_test_storage( + node_index, + batcher_index, + state_sync_index, + class_manager_index, + custom_paths.clone(), + accounts.to_vec(), + &chain_info, + ); + + // Derive the configuration for the sequencer node. + let (config, config_pointers_map) = create_node_config( + &mut config_available_ports, + chain_info, + storage_setup.storage_config.clone(), + state_sync_config, + consensus_manager_config, + mempool_p2p_config, + MonitoringEndpointConfig::default(), + ComponentConfig::default(), + base_layer_config.clone(), + BLOCK_MAX_CAPACITY_N_STEPS, + validator_id, + ); + let base_app_config = DeploymentBaseAppConfig::new( + config.clone(), + config_pointers_map.clone(), + CONFIG_NON_POINTERS_WHITELIST.clone(), + ); + + let HttpServerConfig { ip, port } = config.http_server_config; + let add_tx_http_client = HttpTestClient::new(SocketAddr::from((ip, port))); + + for (executable_index, executable_component_config) in + node_component_config.into_iter().enumerate() + { + let node_execution_id = NodeExecutionId::new(node_index, executable_index); + let exec_config_path = + custom_paths.as_ref().and_then(|paths| paths.get_config_path(&node_execution_id)); + + executables.push( + ExecutableSetup::new( + base_app_config.clone(), + config_pointers_map.clone(), + node_execution_id, + available_ports_generator + .next() + .expect("Failed to get an AvailablePorts instance for executable configs"), + exec_config_path, + executable_component_config, + ) + .await, + ); + } + nodes.push(NodeSetup::new( + executables, + batcher_index, + http_server_index, + state_sync_index, + add_tx_http_client, + storage_setup.storage_handles, + )); + } + + (nodes, node_indices) +} + +fn create_map(items: Vec, key_extractor: F) -> HashMap +where + F: Fn(&T) -> Option, + K: std::hash::Hash + Eq, +{ + items.into_iter().filter_map(|item| key_extractor(&item).map(|key| (key, item))).collect() +} diff --git a/crates/starknet_integration_tests/src/integration_test_setup.rs b/crates/starknet_integration_tests/src/integration_test_setup.rs deleted file mode 100644 index 3beaf9cf172..00000000000 --- a/crates/starknet_integration_tests/src/integration_test_setup.rs +++ /dev/null @@ -1,78 +0,0 @@ -use std::net::SocketAddr; -use std::path::PathBuf; - -use mempool_test_utils::starknet_api_test_utils::MultiAccountTransactionGenerator; -use papyrus_storage::StorageConfig; -use starknet_http_server::config::HttpServerConfig; -use starknet_monitoring_endpoint::config::MonitoringEndpointConfig; -use starknet_monitoring_endpoint::test_utils::IsAliveClient; -use tempfile::{tempdir, TempDir}; - -use crate::config_utils::dump_config_file_changes; -use crate::state_reader::{spawn_test_rpc_state_reader, StorageTestSetup}; -use crate::utils::{create_chain_info, create_config, HttpTestClient}; - -pub struct IntegrationTestSetup { - // Client for adding transactions to the sequencer node. - pub add_tx_http_client: HttpTestClient, - // Client for checking liveness of the sequencer node. - pub is_alive_test_client: IsAliveClient, - // Path to the node configuration file. - pub node_config_path: PathBuf, - // Storage reader for the batcher. - pub batcher_storage_config: StorageConfig, - // Handlers for the storage and config files, maintained so the files are not deleted. Since - // these are only maintained to avoid dropping the handlers, private visibility suffices, and - // as such, the '#[allow(dead_code)]' attributes are used to suppress the warning. - #[allow(dead_code)] - batcher_storage_handle: TempDir, - #[allow(dead_code)] - rpc_storage_handle: TempDir, - #[allow(dead_code)] - node_config_dir_handle: TempDir, -} - -impl IntegrationTestSetup { - pub async fn new_from_tx_generator(tx_generator: &MultiAccountTransactionGenerator) -> Self { - let chain_info = create_chain_info(); - // Creating the storage for the test. - let storage_for_test = - StorageTestSetup::new(tx_generator.accounts(), chain_info.chain_id.clone()); - - // Spawn a papyrus rpc server for a papyrus storage reader. - let rpc_server_addr = spawn_test_rpc_state_reader( - storage_for_test.rpc_storage_reader, - chain_info.chain_id.clone(), - ) - .await; - - // Derive the configuration for the sequencer node. - let (config, required_params, _) = - create_config(chain_info, rpc_server_addr, storage_for_test.batcher_storage_config) - .await; - - let node_config_dir_handle = tempdir().unwrap(); - let node_config_path = dump_config_file_changes( - &config, - required_params, - node_config_dir_handle.path().to_path_buf(), - ); - - // Wait for the node to start. - let MonitoringEndpointConfig { ip, port } = config.monitoring_endpoint_config; - let is_alive_test_client = IsAliveClient::new(SocketAddr::from((ip, port))); - - let HttpServerConfig { ip, port } = config.http_server_config; - let add_tx_http_client = HttpTestClient::new(SocketAddr::from((ip, port))); - - IntegrationTestSetup { - add_tx_http_client, - is_alive_test_client, - batcher_storage_handle: storage_for_test.batcher_storage_handle, - batcher_storage_config: config.batcher_config.storage, - rpc_storage_handle: storage_for_test.rpc_storage_handle, - node_config_dir_handle, - node_config_path, - } - } -} diff --git a/crates/starknet_integration_tests/src/integration_test_utils.rs b/crates/starknet_integration_tests/src/integration_test_utils.rs new file mode 100644 index 00000000000..8c462e1c1f6 --- /dev/null +++ b/crates/starknet_integration_tests/src/integration_test_utils.rs @@ -0,0 +1,26 @@ +use starknet_sequencer_infra::trace_util::configure_tracing; +use starknet_sequencer_node::test_utils::node_runner::get_node_executable_path; +use tracing::{info, warn}; + +// TODO(Tsabary): remove the hook definition once we transition to proper usage of task +// spawning. +pub fn set_panic_hook() { + let default_panic = std::panic::take_hook(); + std::panic::set_hook(Box::new(move |info| { + default_panic(info); + std::process::exit(1); + })); +} + +pub async fn integration_test_setup(test_specifier: &str) { + configure_tracing().await; + info!("Running sequencer node end to end {test_specifier} flow integration test setup."); + set_panic_hook(); + + let sequencer_path = get_node_executable_path(); + warn!( + "This test uses a compiled sequencer node binary located at {sequencer_path}. Make sure \ + to pre-compile the binary before running this test. Alternatively, you can compile the \ + binary and run this test with './scripts/sequencer_integration_test.sh {test_specifier}'" + ); +} diff --git a/crates/starknet_integration_tests/src/lib.rs b/crates/starknet_integration_tests/src/lib.rs index 76d06d00041..1cf94d8d6c0 100644 --- a/crates/starknet_integration_tests/src/lib.rs +++ b/crates/starknet_integration_tests/src/lib.rs @@ -1,5 +1,13 @@ -pub mod config_utils; +#[cfg(test)] +pub mod config_tests; +pub mod consts; +pub mod executable_setup; pub mod flow_test_setup; -pub mod integration_test_setup; +pub mod integration_test_manager; +pub mod integration_test_utils; +pub mod monitoring_utils; +pub mod node_component_configs; +pub mod sequencer_simulator_utils; pub mod state_reader; +pub mod storage; pub mod utils; diff --git a/crates/starknet_integration_tests/src/monitoring_utils.rs b/crates/starknet_integration_tests/src/monitoring_utils.rs new file mode 100644 index 00000000000..7d9c7d8ce31 --- /dev/null +++ b/crates/starknet_integration_tests/src/monitoring_utils.rs @@ -0,0 +1,179 @@ +use papyrus_sync::metrics::{ + SYNC_BODY_MARKER, + SYNC_CLASS_MANAGER_MARKER, + SYNC_COMPILED_CLASS_MARKER, + SYNC_HEADER_MARKER, + SYNC_PROCESSED_TRANSACTIONS, + SYNC_STATE_MARKER, +}; +use starknet_api::block::BlockNumber; +use starknet_batcher::metrics::STORAGE_HEIGHT; +use starknet_infra_utils::run_until::run_until; +use starknet_infra_utils::tracing::{CustomLogger, TraceLevel}; +use starknet_monitoring_endpoint::test_utils::MonitoringClient; +use tokio::try_join; +use tracing::info; + +/// Gets the latest block number from the batcher's metrics. +pub async fn get_batcher_latest_block_number( + batcher_monitoring_client: &MonitoringClient, +) -> BlockNumber { + BlockNumber( + batcher_monitoring_client + .get_metric::(STORAGE_HEIGHT.get_name()) + .await + .expect("Failed to get storage height metric."), + ) + .prev() // The metric is the height marker so we need to subtract 1 to get the latest. + .expect("Storage height should be at least 1.") +} + +/// Gets the latest block number from the sync's metrics. +async fn get_sync_latest_block_number(sync_monitoring_client: &MonitoringClient) -> BlockNumber { + let metrics = sync_monitoring_client.get_metrics().await.expect("Failed to get metrics."); + + let latest_marker_value = [ + SYNC_HEADER_MARKER, + SYNC_BODY_MARKER, + SYNC_STATE_MARKER, + SYNC_CLASS_MANAGER_MARKER, + SYNC_COMPILED_CLASS_MARKER, + ] + .iter() + .map(|marker| { + marker + .parse_numeric_metric::(&metrics) + .unwrap_or_else(|| panic!("Failed to get {} metric.", marker.get_name())) + }) + // we keep only the positive values because class manager marker is not updated in central sync + // and compiled class marker is not updated in p2p sync + .filter(|&marker_value| marker_value > 0) + // we take the minimum value, or 0 if there are no positive values + .min() + .unwrap_or(0); + + BlockNumber(latest_marker_value) + .prev() // The metric is the height marker so we need to subtract 1 to get the latest. + .expect("Sync marker should be at least 1.") +} + +/// Sample the metrics until sufficiently many blocks have been reported by the batcher. Returns an +/// error if after the given number of attempts the target block number has not been reached. +pub async fn await_batcher_block( + interval: u64, + condition: impl Fn(&BlockNumber) -> bool + Send + Sync, + max_attempts: usize, + batcher_monitoring_client: &MonitoringClient, + logger: CustomLogger, +) -> Result { + let get_latest_block_number_closure = + || get_batcher_latest_block_number(batcher_monitoring_client); + + run_until(interval, max_attempts, get_latest_block_number_closure, condition, Some(logger)) + .await + .ok_or(()) +} + +pub async fn await_sync_block( + interval: u64, + condition: impl Fn(&BlockNumber) -> bool + Send + Sync, + max_attempts: usize, + sync_monitoring_client: &MonitoringClient, + logger: CustomLogger, +) -> Result { + let get_latest_block_number_closure = || get_sync_latest_block_number(sync_monitoring_client); + + run_until(interval, max_attempts, get_latest_block_number_closure, condition, Some(logger)) + .await + .ok_or(()) +} + +pub async fn await_block( + batcher_monitoring_client: &MonitoringClient, + batcher_executable_index: usize, + state_sync_monitoring_client: &MonitoringClient, + state_sync_executable_index: usize, + expected_block_number: BlockNumber, + node_index: usize, +) { + info!( + "Awaiting until {expected_block_number} blocks have been created in sequencer {}.", + node_index + ); + let condition = + |&latest_block_number: &BlockNumber| latest_block_number >= expected_block_number; + + let expected_height = expected_block_number.unchecked_next(); + let [batcher_logger, sync_logger] = + [("Batcher", batcher_executable_index), ("Sync", state_sync_executable_index)].map( + |(component_name, executable_index)| { + CustomLogger::new( + TraceLevel::Info, + Some(format!( + "Waiting for {component_name} height metric to reach block \ + {expected_height} in sequencer {node_index} executable \ + {executable_index}.", + )), + ) + }, + ); + // TODO(noamsp): Change this so we get both values with one metrics query. + try_join!( + await_batcher_block(5000, condition, 50, batcher_monitoring_client, batcher_logger), + await_sync_block(5000, condition, 50, state_sync_monitoring_client, sync_logger) + ) + .unwrap(); +} + +pub async fn verify_txs_accepted( + monitoring_client: &MonitoringClient, + sequencer_idx: usize, + expected_n_accepted_txs: usize, +) { + info!("Verifying that sequencer {sequencer_idx} accepted {expected_n_accepted_txs} txs."); + let n_accepted_txs = sequencer_num_accepted_txs(monitoring_client).await; + assert_eq!( + n_accepted_txs, expected_n_accepted_txs, + "Sequencer {sequencer_idx} accepted an unexpected number of txs. Expected \ + {expected_n_accepted_txs} got {n_accepted_txs}" + ); +} + +pub async fn await_txs_accepted( + monitoring_client: &MonitoringClient, + sequencer_idx: usize, + target_n_accepted_txs: usize, +) { + const INTERVAL_MILLIS: u64 = 5000; + const MAX_ATTEMPTS: usize = 50; + info!("Waiting until sequencer {sequencer_idx} accepts {target_n_accepted_txs} txs."); + + let condition = + |¤t_n_accepted_txs: &usize| current_n_accepted_txs >= target_n_accepted_txs; + + let get_current_n_accepted_txs_closure = || sequencer_num_accepted_txs(monitoring_client); + + let logger = CustomLogger::new( + TraceLevel::Info, + Some(format!( + "Waiting for sequencer {sequencer_idx} to accept {target_n_accepted_txs} txs.", + )), + ); + + run_until( + INTERVAL_MILLIS, + MAX_ATTEMPTS, + get_current_n_accepted_txs_closure, + condition, + Some(logger), + ) + .await + .unwrap_or_else(|| { + panic!("Sequencer {sequencer_idx} did not accept {target_n_accepted_txs} txs.") + }); +} + +pub async fn sequencer_num_accepted_txs(monitoring_client: &MonitoringClient) -> usize { + // If the sequencer accepted txs, sync should process them and update the respective metric. + monitoring_client.get_metric::(SYNC_PROCESSED_TRANSACTIONS.get_name()).await.unwrap() +} diff --git a/crates/starknet_integration_tests/src/node_component_configs.rs b/crates/starknet_integration_tests/src/node_component_configs.rs new file mode 100644 index 00000000000..448c9d9200e --- /dev/null +++ b/crates/starknet_integration_tests/src/node_component_configs.rs @@ -0,0 +1,115 @@ +use starknet_infra_utils::test_utils::AvailablePortsGenerator; +use starknet_sequencer_deployments::deployments::distributed::DistributedNodeServiceName; +use starknet_sequencer_deployments::service::{DeploymentName, ServiceName}; +use starknet_sequencer_node::config::component_config::{set_urls_to_localhost, ComponentConfig}; + +/// Holds the component configs for a set of sequencers, composing a single sequencer node. +pub struct NodeComponentConfigs { + component_configs: Vec, + batcher_index: usize, + http_server_index: usize, + state_sync_index: usize, + class_manager_index: usize, +} + +impl NodeComponentConfigs { + fn new( + component_configs: Vec, + batcher_index: usize, + http_server_index: usize, + state_sync_index: usize, + class_manager_index: usize, + ) -> Self { + Self { + component_configs, + batcher_index, + http_server_index, + state_sync_index, + class_manager_index, + } + } + + pub fn len(&self) -> usize { + self.component_configs.len() + } + + pub fn is_empty(&self) -> bool { + self.component_configs.is_empty() + } + + pub fn get_batcher_index(&self) -> usize { + self.batcher_index + } + + pub fn get_http_server_index(&self) -> usize { + self.http_server_index + } + + pub fn get_state_sync_index(&self) -> usize { + self.state_sync_index + } + + pub fn get_class_manager_index(&self) -> usize { + self.class_manager_index + } +} + +impl IntoIterator for NodeComponentConfigs { + type Item = ComponentConfig; + type IntoIter = std::vec::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.component_configs.into_iter() + } +} + +pub fn create_consolidated_sequencer_configs() -> NodeComponentConfigs { + // All components are in executable index 0. + NodeComponentConfigs::new( + DeploymentName::ConsolidatedNode.get_component_configs(None).into_values().collect(), + 0, + 0, + 0, + 0, + ) +} + +pub fn create_nodes_deployment_units_configs( + available_ports_generator: &mut AvailablePortsGenerator, +) -> NodeComponentConfigs { + let mut available_ports = available_ports_generator + .next() + .expect("Failed to get an AvailablePorts instance for distributed node configs"); + + // TODO(Tsabary): the following implicitly assumes there are sufficiently many ports + // available in the [`available_ports`] instance to support the deployment configuration. If + // the test breaks due to port binding conflicts then it might be required to revisit this + // assumption. + + let base_port = available_ports.get_next_port(); + + let services_component_config = + DeploymentName::DistributedNode.get_component_configs(Some(base_port)); + + let mut component_configs: Vec = + services_component_config.values().cloned().collect(); + set_urls_to_localhost(&mut component_configs); + + // TODO(Tsabary): transition to using the map instead of a vector and indices. + + NodeComponentConfigs::new( + component_configs, + services_component_config + .get_index_of::(&DistributedNodeServiceName::Batcher.into()) + .unwrap(), + services_component_config + .get_index_of::(&DistributedNodeServiceName::HttpServer.into()) + .unwrap(), + services_component_config + .get_index_of::(&DistributedNodeServiceName::StateSync.into()) + .unwrap(), + services_component_config + .get_index_of::(&DistributedNodeServiceName::ClassManager.into()) + .unwrap(), + ) +} diff --git a/crates/starknet_integration_tests/src/sequencer_simulator_utils.rs b/crates/starknet_integration_tests/src/sequencer_simulator_utils.rs new file mode 100644 index 00000000000..62c8610c90a --- /dev/null +++ b/crates/starknet_integration_tests/src/sequencer_simulator_utils.rs @@ -0,0 +1,102 @@ +use std::net::{SocketAddr, ToSocketAddrs}; + +use mempool_test_utils::starknet_api_test_utils::{AccountId, MultiAccountTransactionGenerator}; +use starknet_api::rpc_transaction::RpcTransaction; +use starknet_api::transaction::{L1HandlerTransaction, TransactionHash}; +use starknet_http_server::test_utils::HttpTestClient; +use starknet_monitoring_endpoint::test_utils::MonitoringClient; +use tracing::info; +use url::Url; + +use crate::integration_test_manager::nonce_to_usize; +use crate::monitoring_utils; +use crate::utils::{send_consensus_txs, TestScenario}; + +pub struct SequencerSimulator { + monitoring_client: MonitoringClient, + http_client: HttpTestClient, +} + +impl SequencerSimulator { + pub fn new( + http_url: String, + http_port: u16, + monitoring_url: String, + monitoring_port: u16, + ) -> Self { + let monitoring_client = + MonitoringClient::new(get_socket_addr(&monitoring_url, monitoring_port).unwrap()); + + let http_client = HttpTestClient::new(get_socket_addr(&http_url, http_port).unwrap()); + + Self { monitoring_client, http_client } + } + + pub async fn assert_add_tx_success(&self, tx: RpcTransaction) -> TransactionHash { + info!("Sending transaction: {:?}", tx); + self.http_client.assert_add_tx_success(tx).await + } + + pub async fn send_txs( + &self, + tx_generator: &mut MultiAccountTransactionGenerator, + test_scenario: &impl TestScenario, + sender_account: AccountId, + ) { + info!("Sending transactions"); + let send_rpc_tx_fn = &mut |tx| self.assert_add_tx_success(tx); + // TODO(Arni): Create an actual function that sends L1 handlers in the simulator. Requires + // setting up L1. + let send_l1_handler_tx_fn = + &mut |_l1_handler_tx: L1HandlerTransaction| async { TransactionHash::default() }; + let tx_hashes = send_consensus_txs( + tx_generator, + sender_account, + test_scenario, + send_rpc_tx_fn, + send_l1_handler_tx_fn, + ) + .await; + assert_eq!(tx_hashes.len(), test_scenario.n_txs()); + } + + pub async fn await_txs_accepted(&self, sequencer_idx: usize, target_n_batched_txs: usize) { + monitoring_utils::await_txs_accepted( + &self.monitoring_client, + sequencer_idx, + target_n_batched_txs, + ) + .await; + } + + pub async fn verify_txs_accepted( + &self, + sequencer_idx: usize, + tx_generator: &mut MultiAccountTransactionGenerator, + sender_account: AccountId, + ) { + let account = tx_generator.account_with_id(sender_account); + let expected_n_batched_txs = nonce_to_usize(account.get_nonce()); + info!( + "Verifying that sequencer {} got {} batched txs.", + sequencer_idx, expected_n_batched_txs + ); + monitoring_utils::verify_txs_accepted( + &self.monitoring_client, + sequencer_idx, + expected_n_batched_txs, + ) + .await; + } +} + +fn get_socket_addr(url_str: &str, port: u16) -> Result> { + let url = Url::parse(url_str)?; + let host = url.host_str().ok_or("Invalid URL: no host found")?; + let addr = format!("{}:{}", host, port) + .to_socket_addrs()? + .next() + .ok_or("Failed to resolve address")?; + + Ok(addr) +} diff --git a/crates/starknet_integration_tests/src/state_reader.rs b/crates/starknet_integration_tests/src/state_reader.rs index 5015d526296..49cb3f5eedd 100644 --- a/crates/starknet_integration_tests/src/state_reader.rs +++ b/crates/starknet_integration_tests/src/state_reader.rs @@ -1,31 +1,24 @@ -use std::net::SocketAddr; -use std::sync::Arc; +use std::collections::HashMap; use assert_matches::assert_matches; -use blockifier::context::{BlockContext, ChainInfo}; -use blockifier::test_utils::contracts::FeatureContract; -use blockifier::test_utils::{ - CairoVersion, - BALANCE, - CURRENT_BLOCK_TIMESTAMP, - DEFAULT_ETH_L1_GAS_PRICE, - DEFAULT_STRK_L1_GAS_PRICE, - TEST_SEQUENCER_ADDRESS, -}; -use blockifier::transaction::objects::FeeType; -use blockifier::versioned_constants::VersionedConstants; +use blockifier::blockifier_versioned_constants::VersionedConstants; +use blockifier::context::ChainInfo; +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; +use blockifier_test_utils::contracts::FeatureContract; use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass; use indexmap::IndexMap; -use mempool_test_utils::starknet_api_test_utils::Contract; -use papyrus_common::pending_classes::PendingClasses; -use papyrus_rpc::{run_server, RpcConfig}; +use mempool_test_utils::starknet_api_test_utils::{ + AccountTransactionGenerator, + Contract, + VALID_ACCOUNT_BALANCE, +}; use papyrus_storage::body::BodyStorageWriter; use papyrus_storage::class::ClassStorageWriter; use papyrus_storage::compiled_class::CasmStorageWriter; use papyrus_storage::header::HeaderStorageWriter; use papyrus_storage::state::StateStorageWriter; use papyrus_storage::test_utils::TestStorageBuilder; -use papyrus_storage::{StorageConfig, StorageReader, StorageScope, StorageWriter}; +use papyrus_storage::{StorageConfig, StorageScope, StorageWriter}; use starknet_api::abi::abi_utils::get_fee_token_var_address; use starknet_api::block::{ BlockBody, @@ -33,112 +26,255 @@ use starknet_api::block::{ BlockHeaderWithoutHash, BlockNumber, BlockTimestamp, + FeeType, GasPricePerToken, }; -use starknet_api::core::{ChainId, ClassHash, ContractAddress, Nonce, SequencerContractAddress}; +use starknet_api::contract_class::{ContractClass, SierraVersion}; +use starknet_api::core::{ClassHash, ContractAddress, Nonce, SequencerContractAddress}; use starknet_api::deprecated_contract_class::ContractClass as DeprecatedContractClass; -use starknet_api::state::{StorageKey, ThinStateDiff}; -use starknet_api::transaction::fields::Fee; +use starknet_api::state::{SierraContractClass, StorageKey, ThinStateDiff}; +use starknet_api::test_utils::{ + CURRENT_BLOCK_TIMESTAMP, + DEFAULT_ETH_L1_GAS_PRICE, + DEFAULT_STRK_L1_GAS_PRICE, + TEST_SEQUENCER_ADDRESS, +}; use starknet_api::{contract_address, felt}; -use starknet_client::reader::PendingData; -use starknet_sequencer_infra::test_utils::get_available_socket; +use starknet_class_manager::class_storage::{ClassStorage, FsClassStorage}; +use starknet_class_manager::config::FsClassStorageConfig; +use starknet_class_manager::test_utils::FsClassStorageBuilderForTesting; use starknet_types_core::felt::Felt; use strum::IntoEnumIterator; use tempfile::TempDir; -use tokio::sync::RwLock; -type ContractClassesMap = - (Vec<(ClassHash, DeprecatedContractClass)>, Vec<(ClassHash, CasmContractClass)>); +use crate::storage::StorageExecutablePaths; -pub struct StorageTestSetup { - pub rpc_storage_reader: StorageReader, - pub rpc_storage_handle: TempDir, +pub type TempDirHandlePair = (TempDir, TempDir); +type ContractClassesMap = ( + Vec<(ClassHash, DeprecatedContractClass)>, + Vec<(ClassHash, (SierraContractClass, CasmContractClass))>, +); + +pub(crate) const BATCHER_DB_PATH_SUFFIX: &str = "batcher"; +pub(crate) const CLASS_MANAGER_DB_PATH_SUFFIX: &str = "class_manager"; +pub(crate) const CLASS_HASH_STORAGE_DB_PATH_SUFFIX: &str = "class_hash_storage"; +pub(crate) const CLASSES_STORAGE_DB_PATH_SUFFIX: &str = "classes"; +pub(crate) const STATE_SYNC_DB_PATH_SUFFIX: &str = "state_sync"; + +#[derive(Debug, Clone)] +pub struct StorageTestConfig { pub batcher_storage_config: StorageConfig, - pub batcher_storage_handle: TempDir, + pub state_sync_storage_config: StorageConfig, + pub class_manager_storage_config: FsClassStorageConfig, +} + +impl StorageTestConfig { + pub fn new( + batcher_storage_config: StorageConfig, + state_sync_storage_config: StorageConfig, + class_manager_storage_config: FsClassStorageConfig, + ) -> Self { + Self { batcher_storage_config, state_sync_storage_config, class_manager_storage_config } + } +} + +#[derive(Debug)] +pub struct StorageTestHandles { + pub batcher_storage_handle: Option, + pub state_sync_storage_handle: Option, + pub class_manager_storage_handles: Option, +} + +impl StorageTestHandles { + pub fn new( + batcher_storage_handle: Option, + state_sync_storage_handle: Option, + class_manager_storage_handles: Option, + ) -> Self { + Self { batcher_storage_handle, state_sync_storage_handle, class_manager_storage_handles } + } +} + +#[derive(Debug)] +pub struct StorageTestSetup { + pub storage_config: StorageTestConfig, + pub storage_handles: StorageTestHandles, } impl StorageTestSetup { - pub fn new(test_defined_accounts: Vec, chain_id: ChainId) -> Self { - let ((rpc_storage_reader, mut rpc_storage_writer), _, rpc_storage_file_handle) = - TestStorageBuilder::default().chain_id(chain_id.clone()).build(); - create_test_state(&mut rpc_storage_writer, test_defined_accounts.clone()); - let ((_, mut batcher_storage_writer), batcher_storage_config, batcher_storage_file_handle) = - TestStorageBuilder::default() + pub fn new( + test_defined_accounts: Vec, + chain_info: &ChainInfo, + storage_exec_paths: Option, + ) -> Self { + let preset_test_contracts = PresetTestContracts::new(); + // TODO(yair): Avoid cloning. + let classes = TestClasses::new(&test_defined_accounts, preset_test_contracts.clone()); + + let batcher_db_path = + storage_exec_paths.as_ref().map(|p| p.get_batcher_path_with_db_suffix()); + let ((_, mut batcher_storage_writer), batcher_storage_config, batcher_storage_handle) = + TestStorageBuilder::new(batcher_db_path) .scope(StorageScope::StateOnly) - .chain_id(chain_id.clone()) + .chain_id(chain_info.chain_id.clone()) .build(); - create_test_state(&mut batcher_storage_writer, test_defined_accounts); + initialize_papyrus_test_state( + &mut batcher_storage_writer, + chain_info, + &test_defined_accounts, + preset_test_contracts.clone(), + &classes, + ); + + let state_sync_db_path = + storage_exec_paths.as_ref().map(|p| p.get_state_sync_path_with_db_suffix()); + let ( + (_, mut state_sync_storage_writer), + state_sync_storage_config, + state_sync_storage_handle, + ) = TestStorageBuilder::new(state_sync_db_path) + .scope(StorageScope::FullArchive) + .chain_id(chain_info.chain_id.clone()) + .build(); + initialize_papyrus_test_state( + &mut state_sync_storage_writer, + chain_info, + &test_defined_accounts, + preset_test_contracts, + &classes, + ); + + let fs_class_storage_db_path = + storage_exec_paths.as_ref().map(|p| p.get_class_manager_path_with_db_suffix()); + let mut fs_class_storage_builder = FsClassStorageBuilderForTesting::default(); + if let Some(class_manager_path) = fs_class_storage_db_path.as_ref() { + let class_hash_storage_path_prefix = + class_manager_path.join(CLASS_HASH_STORAGE_DB_PATH_SUFFIX); + let persistent_root = class_manager_path.join(CLASSES_STORAGE_DB_PATH_SUFFIX); + // The paths will be created in the first time the storage is opened (passing + // `enforce_file_exists: false`). + fs_class_storage_builder = fs_class_storage_builder + .with_existing_paths(class_hash_storage_path_prefix, persistent_root); + } + let ( + mut class_manager_storage, + class_manager_storage_config, + class_manager_storage_handles, + ) = fs_class_storage_builder.build(); + + initialize_class_manager_test_state(&mut class_manager_storage, classes); + Self { - rpc_storage_reader, - rpc_storage_handle: rpc_storage_file_handle, - batcher_storage_config, - batcher_storage_handle: batcher_storage_file_handle, + storage_config: StorageTestConfig::new( + batcher_storage_config, + state_sync_storage_config, + class_manager_storage_config, + ), + storage_handles: StorageTestHandles::new( + batcher_storage_handle, + state_sync_storage_handle, + class_manager_storage_handles, + ), } } } -/// A variable number of identical accounts and test contracts are initialized and funded. -fn create_test_state(storage_writer: &mut StorageWriter, test_defined_accounts: Vec) { - let block_context = BlockContext::create_for_testing(); - - let into_contract = |contract: FeatureContract| Contract { - contract, - sender_address: contract.get_instance_address(0), - }; - let default_test_contracts = [ - FeatureContract::TestContract(CairoVersion::Cairo0), - FeatureContract::TestContract(CairoVersion::Cairo1), - ] - .into_iter() - .map(into_contract) - .collect(); - - let erc20_contract = FeatureContract::ERC20(CairoVersion::Cairo0); - let erc20_contract = into_contract(erc20_contract); - - initialize_papyrus_test_state( - storage_writer, - block_context.chain_info(), - test_defined_accounts, - default_test_contracts, - erc20_contract, - ); +#[derive(Clone)] +struct PresetTestContracts { + pub default_test_contracts: Vec, + pub erc20_contract: Contract, } +impl PresetTestContracts { + pub fn new() -> Self { + let into_contract = |contract: FeatureContract| Contract { + contract, + sender_address: contract.get_instance_address(0), + }; + let default_test_contracts = [ + FeatureContract::TestContract(CairoVersion::Cairo0), + FeatureContract::TestContract(CairoVersion::Cairo1(RunnableCairo1::Casm)), + ] + .into_iter() + .map(into_contract) + .collect(); + + let erc20_contract = FeatureContract::ERC20(CairoVersion::Cairo0); + let erc20_contract = into_contract(erc20_contract); + + Self { default_test_contracts, erc20_contract } + } +} + +struct TestClasses { + pub cairo0_contract_classes: Vec<(ClassHash, DeprecatedContractClass)>, + pub cairo1_contract_classes: Vec<(ClassHash, (SierraContractClass, CasmContractClass))>, +} + +impl TestClasses { + pub fn new( + test_defined_accounts: &[AccountTransactionGenerator], + preset_test_contracts: PresetTestContracts, + ) -> TestClasses { + let PresetTestContracts { default_test_contracts, erc20_contract } = preset_test_contracts; + let contract_classes_to_retrieve = test_defined_accounts + .iter() + .map(|acc| acc.account) + .chain(default_test_contracts) + .chain([erc20_contract]); + let (cairo0_contract_classes, cairo1_contract_classes) = + prepare_contract_classes(contract_classes_to_retrieve); + + Self { cairo0_contract_classes, cairo1_contract_classes } + } +} + +fn initialize_class_manager_test_state( + class_manager_storage: &mut FsClassStorage, + classes: TestClasses, +) { + let TestClasses { cairo0_contract_classes, cairo1_contract_classes } = classes; + + for (class_hash, casm) in cairo0_contract_classes { + let casm = ContractClass::V0(casm).try_into().unwrap(); + class_manager_storage.set_deprecated_class(class_hash, casm).unwrap(); + } + for (class_hash, (sierra, casm)) in cairo1_contract_classes { + let sierra_version = SierraVersion::extract_from_program(&sierra.sierra_program).unwrap(); + let class = ContractClass::V1((casm, sierra_version)); + class_manager_storage + .set_class( + class_hash, + sierra.try_into().unwrap(), + class.compiled_class_hash(), + class.try_into().unwrap(), + ) + .unwrap(); + } +} + +// TODO(Yair): Make the storage setup part of [MultiAccountTransactionGenerator] and remove this +// functionality. +/// A variable number of identical accounts and test contracts are initialized and funded. fn initialize_papyrus_test_state( storage_writer: &mut StorageWriter, chain_info: &ChainInfo, - test_defined_accounts: Vec, - default_test_contracts: Vec, - erc20_contract: Contract, + test_defined_accounts: &[AccountTransactionGenerator], + preset_test_contracts: PresetTestContracts, + classes: &TestClasses, ) { - let state_diff = prepare_state_diff( - chain_info, - &test_defined_accounts, - &default_test_contracts, - &erc20_contract, - ); - - let contract_classes_to_retrieve = - test_defined_accounts.into_iter().chain(default_test_contracts).chain([erc20_contract]); - let (cairo0_contract_classes, cairo1_contract_classes) = - prepare_compiled_contract_classes(contract_classes_to_retrieve); - - write_state_to_papyrus_storage( - storage_writer, - state_diff, - &cairo0_contract_classes, - &cairo1_contract_classes, - ) + let state_diff = prepare_state_diff(chain_info, test_defined_accounts, &preset_test_contracts); + + write_state_to_papyrus_storage(storage_writer, state_diff, classes) } fn prepare_state_diff( chain_info: &ChainInfo, - test_defined_accounts: &[Contract], - default_test_contracts: &[Contract], - erc20_contract: &Contract, + test_defined_accounts: &[AccountTransactionGenerator], + preset_test_contracts: &PresetTestContracts, ) -> ThinStateDiff { let mut state_diff_builder = ThinStateDiffBuilder::new(chain_info); + let PresetTestContracts { default_test_contracts, erc20_contract } = preset_test_contracts; // Setup the common test contracts that are used by default in all test invokes. // TODO(batcher): this does nothing until we actually start excuting stuff in the batcher. @@ -152,54 +288,66 @@ fn prepare_state_diff( // state_diff_builder.set_contracts(accounts_defined_in_the_test).declare().fund(); // ``` // or use declare txs and transfers for both. - state_diff_builder.inject_accounts_into_state(test_defined_accounts); + let (deployed_accounts, undeployed_accounts): (Vec<_>, Vec<_>) = + test_defined_accounts.iter().partition(|account| account.is_deployed()); + + let deployed_accounts_contracts: Vec<_> = + deployed_accounts.iter().map(|acc| acc.account).collect(); + let undeployed_accounts_contracts: Vec<_> = + undeployed_accounts.iter().map(|acc| acc.account).collect(); + + state_diff_builder.inject_deployed_accounts_into_state(deployed_accounts_contracts.as_slice()); + state_diff_builder + .inject_undeployed_accounts_into_state(undeployed_accounts_contracts.as_slice()); state_diff_builder.build() } -fn prepare_compiled_contract_classes( +fn prepare_contract_classes( contract_classes_to_retrieve: impl Iterator, ) -> ContractClassesMap { - let mut cairo0_contract_classes = Vec::new(); - let mut cairo1_contract_classes = Vec::new(); + let mut cairo0_contract_classes = HashMap::new(); + let mut cairo1_contract_classes = HashMap::new(); for contract in contract_classes_to_retrieve { match contract.cairo_version() { CairoVersion::Cairo0 => { - cairo0_contract_classes.push(( + cairo0_contract_classes.insert( contract.class_hash(), serde_json::from_str(&contract.raw_class()).unwrap(), - )); + ); } // todo(rdr): including both Cairo1 and Native versions for now. Temporal solution to // avoid compilation errors when using the "cairo_native" feature _ => { - cairo1_contract_classes.push(( - contract.class_hash(), - serde_json::from_str(&contract.raw_class()).unwrap(), - )); + let sierra = contract.sierra(); + let casm = serde_json::from_str(&contract.raw_class()).unwrap(); + cairo1_contract_classes.insert(contract.class_hash(), (sierra, casm)); } } } - (cairo0_contract_classes, cairo1_contract_classes) + (cairo0_contract_classes.into_iter().collect(), cairo1_contract_classes.into_iter().collect()) } fn write_state_to_papyrus_storage( storage_writer: &mut StorageWriter, state_diff: ThinStateDiff, - cairo0_contract_classes: &[(ClassHash, DeprecatedContractClass)], - cairo1_contract_classes: &[(ClassHash, CasmContractClass)], + classes: &TestClasses, ) { let block_number = BlockNumber(0); let block_header = test_block_header(block_number); + let TestClasses { cairo0_contract_classes, cairo1_contract_classes } = classes; let cairo0_contract_classes: Vec<_> = cairo0_contract_classes.iter().map(|(hash, contract)| (*hash, contract)).collect(); let mut write_txn = storage_writer.begin_rw_txn().unwrap(); - for (class_hash, casm) in cairo1_contract_classes { + let mut sierras = Vec::with_capacity(cairo1_contract_classes.len()); + for (class_hash, (sierra, casm)) in cairo1_contract_classes { write_txn = write_txn.append_casm(class_hash, casm).unwrap(); + sierras.push((*class_hash, sierra)); } + write_txn .append_header(block_number, &block_header) .unwrap() @@ -207,7 +355,7 @@ fn write_state_to_papyrus_storage( .unwrap() .append_state_diff(block_number, state_diff) .unwrap() - .append_classes(block_number, &[], &cairo0_contract_classes) + .append_classes(block_number, &sierras, &cairo0_contract_classes) .unwrap() .commit() .unwrap(); @@ -239,33 +387,6 @@ fn test_block_header(block_number: BlockNumber) -> BlockHeader { } } -/// Spawns a papyrus rpc server for given state reader. -/// Returns the address of the rpc server. -pub async fn spawn_test_rpc_state_reader( - storage_reader: StorageReader, - chain_id: ChainId, -) -> SocketAddr { - let rpc_config = RpcConfig { - chain_id, - server_address: get_available_socket().await.to_string(), - ..Default::default() - }; - let (addr, handle) = run_server( - &rpc_config, - Arc::new(RwLock::new(None)), - Arc::new(RwLock::new(PendingData::default())), - Arc::new(RwLock::new(PendingClasses::default())), - storage_reader, - "NODE VERSION", - ) - .await - .unwrap(); - // Spawn the server handle to keep the server running, otherwise the server will stop once the - // handler is out of scope. - tokio::spawn(handle.stopped()); - addr -} - /// Constructs a thin state diff from lists of contracts, where each contract can be declared, /// deployed, and in case it is an account, funded. #[derive(Default)] @@ -283,7 +404,6 @@ struct ThinStateDiffBuilder<'a> { impl<'a> ThinStateDiffBuilder<'a> { fn new(chain_info: &ChainInfo) -> Self { - const TEST_INITIAL_ACCOUNT_BALANCE: Fee = BALANCE; let erc20 = FeatureContract::ERC20(CairoVersion::Cairo0); let erc20_class_hash = erc20.get_class_hash(); @@ -293,7 +413,7 @@ impl<'a> ThinStateDiffBuilder<'a> { Self { chain_info: chain_info.clone(), - initial_account_balance: felt!(TEST_INITIAL_ACCOUNT_BALANCE.0), + initial_account_balance: felt!(VALID_ACCOUNT_BALANCE.0), deployed_contracts, ..Default::default() } @@ -350,9 +470,11 @@ impl<'a> ThinStateDiffBuilder<'a> { self } - // TODO(deploy_account_support): delete method once we have batcher with execution. - fn inject_accounts_into_state(&mut self, accounts_defined_in_the_test: &'a [Contract]) { - self.set_contracts(accounts_defined_in_the_test).declare().deploy().fund(); + fn inject_deployed_accounts_into_state( + &mut self, + deployed_accounts_defined_in_the_test: &'a [Contract], + ) { + self.set_contracts(deployed_accounts_defined_in_the_test).declare().deploy().fund(); // Set nonces as 1 in the state so that subsequent invokes can pass validation. self.nonces = self @@ -362,6 +484,13 @@ impl<'a> ThinStateDiffBuilder<'a> { .collect(); } + fn inject_undeployed_accounts_into_state( + &mut self, + undeployed_accounts_defined_in_the_test: &'a [Contract], + ) { + self.set_contracts(undeployed_accounts_defined_in_the_test).declare().fund(); + } + fn build(self) -> ThinStateDiff { ThinStateDiff { storage_diffs: self.storage_diffs, @@ -369,7 +498,6 @@ impl<'a> ThinStateDiffBuilder<'a> { declared_classes: self.declared_classes, deprecated_declared_classes: self.deprecated_declared_classes, nonces: self.nonces, - ..Default::default() } } } diff --git a/crates/starknet_integration_tests/src/storage.rs b/crates/starknet_integration_tests/src/storage.rs new file mode 100644 index 00000000000..a68451d2d62 --- /dev/null +++ b/crates/starknet_integration_tests/src/storage.rs @@ -0,0 +1,157 @@ +use std::path::{Path, PathBuf}; + +use blockifier::context::ChainInfo; +use mempool_test_utils::starknet_api_test_utils::AccountTransactionGenerator; + +use crate::executable_setup::NodeExecutionId; +use crate::state_reader::{ + StorageTestConfig, + StorageTestSetup, + BATCHER_DB_PATH_SUFFIX, + CLASSES_STORAGE_DB_PATH_SUFFIX, + CLASS_HASH_STORAGE_DB_PATH_SUFFIX, + CLASS_MANAGER_DB_PATH_SUFFIX, + STATE_SYNC_DB_PATH_SUFFIX, +}; + +#[derive(Debug)] +pub struct StorageExecutablePaths { + batcher_path: PathBuf, + state_sync_path: PathBuf, + class_manager_path: PathBuf, +} + +impl StorageExecutablePaths { + pub fn new( + db_base: &Path, + node_index: usize, + batcher_index: usize, + state_sync_index: usize, + class_manager_index: usize, + ) -> Self { + let batcher_node_index = NodeExecutionId::new(node_index, batcher_index); + let state_sync_node_index = NodeExecutionId::new(node_index, state_sync_index); + let class_manager_node_index = NodeExecutionId::new(node_index, class_manager_index); + + let batcher_path = batcher_node_index.build_path(db_base); + let state_sync_path = state_sync_node_index.build_path(db_base); + let class_manager_path = class_manager_node_index.build_path(db_base); + + Self { batcher_path, state_sync_path, class_manager_path } + } + + pub fn get_batcher_exec_path(&self) -> &PathBuf { + &self.batcher_path + } + + pub fn get_state_sync_exec_path(&self) -> &PathBuf { + &self.state_sync_path + } + + pub fn get_class_manager_exec_path(&self) -> &PathBuf { + &self.class_manager_path + } + + pub fn get_batcher_path_with_db_suffix(&self) -> PathBuf { + self.batcher_path.join(BATCHER_DB_PATH_SUFFIX) + } + + pub fn get_state_sync_path_with_db_suffix(&self) -> PathBuf { + self.state_sync_path.join(STATE_SYNC_DB_PATH_SUFFIX) + } + + pub fn get_class_manager_path_with_db_suffix(&self) -> PathBuf { + self.class_manager_path.join(CLASS_MANAGER_DB_PATH_SUFFIX) + } +} + +#[derive(Debug, Clone)] +pub struct CustomPaths { + db_base: Option, + config_base: Option, + data_prefix_base: Option, +} + +impl CustomPaths { + pub fn new( + db_base: Option, + config_base: Option, + data_prefix_base: Option, + ) -> Self { + Self { db_base, config_base, data_prefix_base } + } + + pub fn get_db_base(&self) -> Option<&PathBuf> { + self.db_base.as_ref() + } + + pub fn get_config_path(&self, node_execution_id: &NodeExecutionId) -> Option { + self.config_base.as_ref().map(|p| node_execution_id.build_path(p)) + } + + pub fn get_data_prefix_path(&self) -> Option<&PathBuf> { + self.data_prefix_base.as_ref() + } +} + +pub fn get_integration_test_storage( + node_index: usize, + batcher_index: usize, + state_sync_index: usize, + class_manager_index: usize, + custom_paths: Option, + accounts: Vec, + chain_info: &ChainInfo, +) -> StorageTestSetup { + let storage_exec_paths = custom_paths.as_ref().and_then(|paths| { + paths.get_db_base().map(|db_base| { + StorageExecutablePaths::new( + db_base, + node_index, + batcher_index, + state_sync_index, + class_manager_index, + ) + }) + }); + + let StorageTestSetup { mut storage_config, storage_handles } = + StorageTestSetup::new(accounts, chain_info, storage_exec_paths); + + // Allow overriding the path with a custom prefix for Docker mode in system tests. + if let Some(paths) = custom_paths { + if let Some(prefix) = paths.get_data_prefix_path() { + let custom_storage_exec_paths = StorageExecutablePaths::new( + prefix, + node_index, + batcher_index, + state_sync_index, + class_manager_index, + ); + storage_config.batcher_storage_config.db_config.path_prefix = + custom_storage_exec_paths.get_batcher_exec_path().join(BATCHER_DB_PATH_SUFFIX); + storage_config.state_sync_storage_config.db_config.path_prefix = + custom_storage_exec_paths + .get_state_sync_exec_path() + .join(STATE_SYNC_DB_PATH_SUFFIX); + storage_config.class_manager_storage_config.class_hash_storage_config.path_prefix = + custom_storage_exec_paths + .get_class_manager_exec_path() + .join(CLASS_MANAGER_DB_PATH_SUFFIX) + .join(CLASS_HASH_STORAGE_DB_PATH_SUFFIX); + storage_config.class_manager_storage_config.persistent_root = custom_storage_exec_paths + .get_class_manager_exec_path() + .join(CLASS_MANAGER_DB_PATH_SUFFIX) + .join(CLASSES_STORAGE_DB_PATH_SUFFIX); + } + } + + StorageTestSetup { + storage_config: StorageTestConfig::new( + storage_config.batcher_storage_config, + storage_config.state_sync_storage_config, + storage_config.class_manager_storage_config, + ), + storage_handles, + } +} diff --git a/crates/starknet_integration_tests/src/utils.rs b/crates/starknet_integration_tests/src/utils.rs index fb89e980518..415b99316c5 100644 --- a/crates/starknet_integration_tests/src/utils.rs +++ b/crates/starknet_integration_tests/src/utils.rs @@ -2,241 +2,578 @@ use std::future::Future; use std::net::SocketAddr; use std::time::Duration; -use axum::body::Body; +use alloy::primitives::U256; +use axum::extract::Query; +use axum::http::StatusCode; +use axum::routing::{get, post}; +use axum::{Json, Router}; +use blockifier::blockifier::config::TransactionExecutorConfig; +use blockifier::bouncer::{BouncerConfig, BouncerWeights}; use blockifier::context::ChainInfo; -use blockifier::test_utils::contracts::FeatureContract; -use blockifier::test_utils::CairoVersion; +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; +use blockifier_test_utils::contracts::FeatureContract; +use futures::future::join_all; use mempool_test_utils::starknet_api_test_utils::{ - rpc_tx_to_json, AccountId, + AccountTransactionGenerator, + Contract, MultiAccountTransactionGenerator, }; -use papyrus_consensus::config::ConsensusConfig; -use papyrus_network::network_manager::test_utils::create_network_config_connected_to_broadcast_channels; -use papyrus_network::network_manager::BroadcastTopicChannels; -use papyrus_protobuf::consensus::ProposalPart; +use papyrus_base_layer::ethereum_base_layer_contract::EthereumBaseLayerConfig; +use papyrus_base_layer::test_utils::StarknetL1Contract; +use papyrus_network::network_manager::test_utils::create_connected_network_configs; +use papyrus_network::NetworkConfig; use papyrus_storage::StorageConfig; -use reqwest::{Client, Response}; +use serde::Deserialize; +use serde_json::{json, to_value}; use starknet_api::block::BlockNumber; -use starknet_api::contract_address; -use starknet_api::core::ContractAddress; +use starknet_api::core::{ChainId, ContractAddress}; +use starknet_api::execution_resources::GasAmount; use starknet_api::rpc_transaction::RpcTransaction; -use starknet_api::transaction::TransactionHash; +use starknet_api::transaction::fields::ContractAddressSalt; +use starknet_api::transaction::{L1HandlerTransaction, TransactionHash, TransactionHasher}; use starknet_batcher::block_builder::BlockBuilderConfig; use starknet_batcher::config::BatcherConfig; +use starknet_class_manager::class_storage::CachedClassStorageConfig; +use starknet_class_manager::config::{ + ClassManagerConfig, + FsClassManagerConfig, + FsClassStorageConfig, +}; +use starknet_consensus::config::{ConsensusConfig, TimeoutsConfig}; +use starknet_consensus::types::ValidatorId; use starknet_consensus_manager::config::ConsensusManagerConfig; +use starknet_consensus_orchestrator::cende::{CendeConfig, RECORDER_WRITE_BLOB_PATH}; +use starknet_consensus_orchestrator::config::ContextConfig; use starknet_gateway::config::{ GatewayConfig, - RpcStateReaderConfig, StatefulTransactionValidatorConfig, StatelessTransactionValidatorConfig, }; -use starknet_gateway_types::errors::GatewaySpecError; -use starknet_http_server::config::HttpServerConfig; -use starknet_sequencer_infra::test_utils::get_available_socket; -use starknet_sequencer_node::config::node_config::SequencerNodeConfig; -use starknet_sequencer_node::config::test_utils::RequiredParams; +use starknet_http_server::test_utils::create_http_server_config; +use starknet_infra_utils::test_utils::AvailablePorts; +use starknet_l1_gas_price::eth_to_strk_oracle::{EthToStrkOracleConfig, ETH_TO_STRK_QUANTIZATION}; +use starknet_l1_provider::l1_scraper::L1ScraperConfig; +use starknet_l1_provider::L1ProviderConfig; +use starknet_mempool::config::MempoolConfig; +use starknet_mempool_p2p::config::MempoolP2pConfig; +use starknet_monitoring_endpoint::config::MonitoringEndpointConfig; +use starknet_sequencer_node::config::component_config::ComponentConfig; +use starknet_sequencer_node::config::definitions::ConfigPointersMap; +use starknet_sequencer_node::config::node_config::{SequencerNodeConfig, CONFIG_POINTERS}; +use starknet_state_sync::config::StateSyncConfig; +use starknet_types_core::felt::Felt; +use tokio::task::JoinHandle; +use tracing::{debug, info, Instrument}; +use url::Url; + +use crate::state_reader::StorageTestConfig; + +pub const ACCOUNT_ID_0: AccountId = 0; +pub const ACCOUNT_ID_1: AccountId = 1; +pub const NEW_ACCOUNT_SALT: ContractAddressSalt = ContractAddressSalt(Felt::THREE); +pub const UNDEPLOYED_ACCOUNT_ID: AccountId = 2; +// Transactions per second sent to the gateway. This rate makes each block contain ~10 transactions +// with the set [TimeoutsConfig] . +pub const TPS: u64 = 2; +pub const N_TXS_IN_FIRST_BLOCK: usize = 2; + +const PAID_FEE_ON_L1: U256 = U256::from_be_slice(b"paid"); // Arbitrary value. + +pub type CreateRpcTxsFn = fn(&mut MultiAccountTransactionGenerator) -> Vec; +pub type CreateL1HandlerTxsFn = + fn(&mut MultiAccountTransactionGenerator) -> Vec; +pub type TestTxHashesFn = fn(&[TransactionHash]) -> Vec; +pub type ExpectedContentId = Felt; + +pub trait TestScenario { + fn create_txs( + &self, + tx_generator: &mut MultiAccountTransactionGenerator, + account_id: AccountId, + ) -> (Vec, Vec); + + fn n_txs(&self) -> usize; +} -pub fn create_chain_info() -> ChainInfo { - let mut chain_info = ChainInfo::create_for_testing(); - // Note that the chain_id affects hashes of transactions and blocks, therefore affecting the - // test. - chain_info.chain_id = papyrus_storage::test_utils::CHAIN_ID_FOR_TESTS.clone(); - chain_info +pub struct ConsensusTxs { + pub n_invoke_txs: usize, + pub n_l1_handler_txs: usize, } -pub async fn create_config( +impl TestScenario for ConsensusTxs { + fn create_txs( + &self, + tx_generator: &mut MultiAccountTransactionGenerator, + account_id: AccountId, + ) -> (Vec, Vec) { + ( + create_invoke_txs(tx_generator, account_id, self.n_invoke_txs), + create_l1_handler_txs(tx_generator, self.n_l1_handler_txs), + ) + } + + fn n_txs(&self) -> usize { + self.n_invoke_txs + self.n_l1_handler_txs + } +} + +pub struct BootstrapTxs; + +impl TestScenario for BootstrapTxs { + fn create_txs( + &self, + tx_generator: &mut MultiAccountTransactionGenerator, + account_id: AccountId, + ) -> (Vec, Vec) { + let txs = create_deploy_account_tx_and_invoke_tx(tx_generator, account_id); + assert_eq!( + txs.len(), + N_TXS_IN_FIRST_BLOCK, + "First block should contain exactly {} transactions, but {} transactions were created", + N_TXS_IN_FIRST_BLOCK, + txs.len(), + ); + (txs, vec![]) + } + + fn n_txs(&self) -> usize { + N_TXS_IN_FIRST_BLOCK + } +} + +// TODO(Tsabary/Shahak/Yair/AlonH): this function needs a proper cleaning. +#[allow(clippy::too_many_arguments)] +pub fn create_node_config( + available_ports: &mut AvailablePorts, chain_info: ChainInfo, - rpc_server_addr: SocketAddr, - batcher_storage_config: StorageConfig, -) -> (SequencerNodeConfig, RequiredParams, BroadcastTopicChannels) { + storage_config: StorageTestConfig, + mut state_sync_config: StateSyncConfig, + consensus_manager_config: ConsensusManagerConfig, + mempool_p2p_config: MempoolP2pConfig, + monitoring_endpoint_config: MonitoringEndpointConfig, + component_config: ComponentConfig, + base_layer_config: EthereumBaseLayerConfig, + block_max_capacity_sierra_gas: GasAmount, + validator_id: ValidatorId, +) -> (SequencerNodeConfig, ConfigPointersMap) { + let recorder_url = consensus_manager_config.cende_config.recorder_url.clone(); let fee_token_addresses = chain_info.fee_token_addresses.clone(); - let batcher_config = create_batcher_config(batcher_storage_config, chain_info.clone()); - let gateway_config = create_gateway_config(chain_info.clone()).await; - let http_server_config = create_http_server_config().await; - let rpc_state_reader_config = test_rpc_state_reader_config(rpc_server_addr); - let (consensus_manager_config, consensus_proposals_channels) = - create_consensus_manager_config_and_channels(); + let batcher_config = create_batcher_config( + storage_config.batcher_storage_config, + chain_info.clone(), + block_max_capacity_sierra_gas, + ); + let gateway_config = create_gateway_config(chain_info.clone()); + let l1_scraper_config = + L1ScraperConfig { chain_id: chain_info.chain_id.clone(), ..Default::default() }; + let l1_provider_config = L1ProviderConfig { + provider_startup_height_override: Some(BlockNumber(1)), + ..Default::default() + }; + let mempool_config = create_mempool_config(); + let http_server_config = + create_http_server_config(available_ports.get_next_local_host_socket()); + let class_manager_config = + create_class_manager_config(storage_config.class_manager_storage_config); + state_sync_config.storage_config = storage_config.state_sync_storage_config; + + // Update config pointer values. + let mut config_pointers_map = ConfigPointersMap::new(CONFIG_POINTERS.clone()); + config_pointers_map.change_target_value( + "chain_id", + to_value(chain_info.chain_id).expect("Failed to serialize ChainId"), + ); + config_pointers_map.change_target_value( + "eth_fee_token_address", + to_value(fee_token_addresses.eth_fee_token_address) + .expect("Failed to serialize ContractAddress"), + ); + config_pointers_map.change_target_value( + "strk_fee_token_address", + to_value(fee_token_addresses.strk_fee_token_address) + .expect("Failed to serialize ContractAddress"), + ); + config_pointers_map.change_target_value( + "validator_id", + to_value(validator_id).expect("Failed to serialize ContractAddress"), + ); + config_pointers_map.change_target_value( + "recorder_url", + to_value(recorder_url).expect("Failed to serialize Url"), + ); ( SequencerNodeConfig { + base_layer_config, batcher_config, + class_manager_config, consensus_manager_config, gateway_config, http_server_config, - rpc_state_reader_config, - ..SequencerNodeConfig::default() - }, - RequiredParams { - chain_id: chain_info.chain_id, - eth_fee_token_address: fee_token_addresses.eth_fee_token_address, - strk_fee_token_address: fee_token_addresses.strk_fee_token_address, - sequencer_address: ContractAddress::from(1312_u128), // Arbitrary non-zero value. + mempool_config, + mempool_p2p_config, + monitoring_endpoint_config, + state_sync_config, + components: component_config, + l1_scraper_config, + l1_provider_config, + ..Default::default() }, - consensus_proposals_channels, + config_pointers_map, ) } -fn create_consensus_manager_config_and_channels() --> (ConsensusManagerConfig, BroadcastTopicChannels) { - let (network_config, broadcast_channels) = - create_network_config_connected_to_broadcast_channels( - papyrus_network::gossipsub_impl::Topic::new( - starknet_consensus_manager::consensus_manager::NETWORK_TOPIC, - ), - ); - let consensus_manager_config = ConsensusManagerConfig { - consensus_config: ConsensusConfig { - start_height: BlockNumber(1), - consensus_delay: Duration::from_secs(1), +pub(crate) fn create_consensus_manager_configs_from_network_configs( + network_configs: Vec, + n_composed_nodes: usize, + chain_id: &ChainId, +) -> Vec { + // TODO(Matan, Dan): set reasonable default timeouts. + let mut timeouts = TimeoutsConfig::default(); + timeouts.precommit_timeout *= 3; + timeouts.prevote_timeout *= 3; + timeouts.proposal_timeout *= 3; + + let num_validators = u64::try_from(n_composed_nodes).unwrap(); + + network_configs + .into_iter() + // TODO(Matan): Get config from default config file. + .map(|network_config| ConsensusManagerConfig { network_config, + immediate_active_height: BlockNumber(1), + consensus_config: ConsensusConfig { + // TODO(Matan, Dan): Set the right amount + startup_delay: Duration::from_secs(15), + timeouts: timeouts.clone(), + ..Default::default() + }, + context_config: ContextConfig { + num_validators, + chain_id: chain_id.clone(), + builder_address: ContractAddress::from(4_u128), + ..Default::default() + }, + cende_config: CendeConfig{ + skip_write_height: Some(BlockNumber(1)), + ..Default::default() + }, + eth_to_strk_oracle_config: EthToStrkOracleConfig { + base_url: Url::parse("https://eth_to_strk_oracle_url") + .expect("Should be a valid URL"), + ..Default::default() + }, ..Default::default() - }, - }; - (consensus_manager_config, broadcast_channels) + }) + .collect() } -pub fn test_rpc_state_reader_config(rpc_server_addr: SocketAddr) -> RpcStateReaderConfig { - // TODO(Tsabary): get the latest version from the RPC crate. - const RPC_SPEC_VERSION: &str = "V0_8"; - const JSON_RPC_VERSION: &str = "2.0"; - RpcStateReaderConfig { - url: format!("http://{rpc_server_addr:?}/rpc/{RPC_SPEC_VERSION}"), - json_rpc_version: JSON_RPC_VERSION.to_string(), - } +// Creates a local recorder server that always returns a success status. +pub fn spawn_success_recorder(socket_address: SocketAddr) -> JoinHandle<()> { + tokio::spawn(async move { + let router = Router::new().route( + RECORDER_WRITE_BLOB_PATH, + post(move || { + async { + debug!("Received a request to write a blob."); + StatusCode::OK.to_string() + } + .instrument(tracing::debug_span!("success recorder write_blob")) + }), + ); + axum::Server::bind(&socket_address).serve(router.into_make_service()).await.unwrap(); + }) } -/// A test utility client for interacting with an http server. -pub struct HttpTestClient { - socket: SocketAddr, - client: Client, +pub fn spawn_local_success_recorder(port: u16) -> (Url, JoinHandle<()>) { + // [127, 0, 0, 1] is the localhost IP address. + let socket_address = SocketAddr::from(([127, 0, 0, 1], port)); + // TODO(Tsabary): create a socket-to-url function. + let url = Url::parse(&format!("http://{}", socket_address)).unwrap(); + let join_handle = spawn_success_recorder(socket_address); + (url, join_handle) } -impl HttpTestClient { - pub fn new(socket: SocketAddr) -> Self { - let client = Client::new(); - Self { socket, client } - } +/// Fake eth to strk oracle endpoint. +const ETH_TO_STRK_ORACLE_PATH: &str = "/eth_to_strk_oracle"; - pub async fn assert_add_tx_success(&self, rpc_tx: RpcTransaction) -> TransactionHash { - let response = self.add_tx(rpc_tx).await; - assert!(response.status().is_success()); +/// Expected query parameters. +#[derive(Deserialize)] +struct EthToStrkOracleQuery { + timestamp: u64, +} - response.json().await.unwrap() - } +/// Returns a fake eth to fri rate response. +async fn get_price(Query(query): Query) -> Json { + // TODO(Asmaa): Retrun timestamp as price once we start mocking out time in the tests. + let price = format!("0x{:x}", 10000); + let response = json!({ "timestamp": query.timestamp ,"price": price, "decimals": ETH_TO_STRK_QUANTIZATION }); + Json(response) +} - // TODO: implement when usage eventually arises. - pub async fn assert_add_tx_error(&self, _tx: RpcTransaction) -> GatewaySpecError { - todo!() - } +/// Spawns a local fake eth to fri oracle server. +pub fn spawn_eth_to_strk_oracle_server(socket_address: SocketAddr) -> JoinHandle<()> { + tokio::spawn(async move { + let router = Router::new().route(ETH_TO_STRK_ORACLE_PATH, get(get_price)); + axum::Server::bind(&socket_address).serve(router.into_make_service()).await.unwrap(); + }) +} - // Prefer using assert_add_tx_success or other higher level methods of this client, to ensure - // tests are boilerplate and implementation-detail free. - pub async fn add_tx(&self, rpc_tx: RpcTransaction) -> Response { - let tx_json = rpc_tx_to_json(&rpc_tx); - self.client - .post(format!("http://{}/add_tx", self.socket)) - .header("content-type", "application/json") - .body(Body::from(tx_json)) - .send() - .await - .unwrap() - } +/// Starts the fake eth to fri oracle server and returns its URL and handle. +pub fn spawn_local_eth_to_strk_oracle(port: u16) -> (Url, JoinHandle<()>) { + let socket_address = SocketAddr::from(([127, 0, 0, 1], port)); + let url = + Url::parse(&format!("http://{}{}?timestamp=", socket_address, ETH_TO_STRK_ORACLE_PATH)) + .unwrap(); + let join_handle = spawn_eth_to_strk_oracle_server(socket_address); + (url, join_handle) } -/// Creates a multi-account transaction generator for integration tests. +pub fn create_mempool_p2p_configs(chain_id: ChainId, ports: Vec) -> Vec { + create_connected_network_configs(ports) + .into_iter() + .map(|mut network_config| { + network_config.chain_id = chain_id.clone(); + MempoolP2pConfig { network_config, ..Default::default() } + }) + .collect() +} + +/// Creates a multi-account transaction generator for the integration test. pub fn create_integration_test_tx_generator() -> MultiAccountTransactionGenerator { let mut tx_generator: MultiAccountTransactionGenerator = MultiAccountTransactionGenerator::new(); + let account = + FeatureContract::AccountWithoutValidations(CairoVersion::Cairo1(RunnableCairo1::Casm)); + tx_generator.register_undeployed_account(account, ContractAddressSalt(Felt::ZERO)); + tx_generator +} + +/// Creates a multi-account transaction generator for the flow test. +pub fn create_flow_test_tx_generator() -> MultiAccountTransactionGenerator { + let mut tx_generator: MultiAccountTransactionGenerator = + MultiAccountTransactionGenerator::new(); + for account in [ - FeatureContract::AccountWithoutValidations(CairoVersion::Cairo1), + FeatureContract::AccountWithoutValidations(CairoVersion::Cairo1(RunnableCairo1::Casm)), FeatureContract::AccountWithoutValidations(CairoVersion::Cairo0), ] { - tx_generator.register_account_for_flow_test(account); + tx_generator.register_deployed_account(account); } + // TODO(yair): This is a hack to fund the new account during the setup. Move the registration to + // the test body once funding is supported. + let new_account_id = tx_generator.register_undeployed_account( + FeatureContract::AccountWithoutValidations(CairoVersion::Cairo1(RunnableCairo1::Casm)), + NEW_ACCOUNT_SALT, + ); + assert_eq!(new_account_id, UNDEPLOYED_ACCOUNT_ID); tx_generator } -fn create_txs_for_integration_test( - mut tx_generator: MultiAccountTransactionGenerator, +pub fn create_multiple_account_txs( + tx_generator: &mut MultiAccountTransactionGenerator, ) -> Vec { - const ACCOUNT_ID_0: AccountId = 0; - const ACCOUNT_ID_1: AccountId = 1; - // Create RPC transactions. let account0_invoke_nonce1 = - tx_generator.account_with_id(ACCOUNT_ID_0).generate_invoke_with_tip(2); + tx_generator.account_with_id_mut(ACCOUNT_ID_0).generate_invoke_with_tip(2); let account0_invoke_nonce2 = - tx_generator.account_with_id(ACCOUNT_ID_0).generate_invoke_with_tip(3); + tx_generator.account_with_id_mut(ACCOUNT_ID_0).generate_invoke_with_tip(3); let account1_invoke_nonce1 = - tx_generator.account_with_id(ACCOUNT_ID_1).generate_invoke_with_tip(4); + tx_generator.account_with_id_mut(ACCOUNT_ID_1).generate_invoke_with_tip(4); vec![account0_invoke_nonce1, account0_invoke_nonce2, account1_invoke_nonce1] } -fn create_account_txs( - mut tx_generator: MultiAccountTransactionGenerator, +/// Creates and sends more transactions than can fit in a block. +pub fn create_many_invoke_txs( + tx_generator: &mut MultiAccountTransactionGenerator, +) -> Vec { + const N_TXS: usize = 15; + create_invoke_txs(tx_generator, ACCOUNT_ID_1, N_TXS) +} + +pub fn create_funding_txs( + tx_generator: &mut MultiAccountTransactionGenerator, +) -> Vec { + // TODO(yair): Register the undeployed account here instead of in the test setup + // once funding is implemented. + let undeployed_account = tx_generator.account_with_id(UNDEPLOYED_ACCOUNT_ID).account; + assert!(tx_generator.undeployed_accounts().contains(&undeployed_account)); + fund_new_account(tx_generator.account_with_id_mut(ACCOUNT_ID_0), &undeployed_account) +} + +fn fund_new_account( + funding_account: &mut AccountTransactionGenerator, + recipient: &Contract, +) -> Vec { + let funding_tx = funding_account.generate_transfer(recipient); + vec![funding_tx] +} + +/// Generates a deploy account transaction followed by an invoke transaction from the same account. +/// The first invoke_tx can be inserted to the first block right after the deploy_tx due to +/// the skip_validate feature. This feature allows the gateway to accept this transaction although +/// the account does not exist yet. +pub fn create_deploy_account_tx_and_invoke_tx( + tx_generator: &mut MultiAccountTransactionGenerator, + account_id: AccountId, +) -> Vec { + let undeployed_account_tx_generator = tx_generator.account_with_id_mut(account_id); + assert!(!undeployed_account_tx_generator.is_deployed()); + let deploy_tx = undeployed_account_tx_generator.generate_deploy_account(); + let invoke_tx = undeployed_account_tx_generator.generate_invoke_with_tip(1); + vec![deploy_tx, invoke_tx] +} + +pub fn create_invoke_txs( + tx_generator: &mut MultiAccountTransactionGenerator, account_id: AccountId, n_txs: usize, ) -> Vec { (0..n_txs) - .map(|_| tx_generator.account_with_id(account_id).generate_invoke_with_tip(1)) + .map(|_| tx_generator.account_with_id_mut(account_id).generate_invoke_with_tip(1)) .collect() } +pub fn create_l1_handler_tx( + tx_generator: &mut MultiAccountTransactionGenerator, +) -> Vec { + const N_TXS: usize = 1; + create_l1_handler_txs(tx_generator, N_TXS) +} + +pub fn create_l1_handler_txs( + tx_generator: &mut MultiAccountTransactionGenerator, + n_txs: usize, +) -> Vec { + (0..n_txs).map(|_| tx_generator.create_l1_handler_tx()).collect() +} + +pub async fn send_message_to_l2_and_calculate_tx_hash( + l1_handler: L1HandlerTransaction, + starknet_l1_contract: &StarknetL1Contract, + chain_id: &ChainId, +) -> TransactionHash { + send_message_to_l2(&l1_handler, starknet_l1_contract).await; + l1_handler.calculate_transaction_hash(chain_id, &l1_handler.version).unwrap() +} + +/// Converts a given [L1 handler transaction](L1HandlerTransaction) to match the interface of the +/// given [starknet l1 contract](StarknetL1Contract), and triggers the L1 entry point which sends +/// the message to L2. +pub(crate) async fn send_message_to_l2( + l1_handler: &L1HandlerTransaction, + starknet_l1_contract: &StarknetL1Contract, +) { + let l2_contract_address = l1_handler.contract_address.0.key().to_hex_string().parse().unwrap(); + let l2_entry_point = l1_handler.entry_point_selector.0.to_hex_string().parse().unwrap(); + + // The calldata of an L1 handler transaction consists of the L1 sender address followed by the + // transaction payload. We remove the sender address to extract the message payload. + let payload = + l1_handler.calldata.0[1..].iter().map(|x| x.to_hex_string().parse().unwrap()).collect(); + let msg = starknet_l1_contract.sendMessageToL2(l2_contract_address, l2_entry_point, payload); + + let _tx_receipt = msg + // Sets a non-zero fee to be paid on L1. + .value(PAID_FEE_ON_L1) + // Sends the transaction to the Starknet L1 contract. For debugging purposes, replace + // `.send()` with `.call_raw()` to retrieve detailed error messages from L1. + .send().await.expect("Transaction submission to Starknet L1 contract failed.") + // Waits until the transaction is received on L1 and then fetches its receipt. + .get_receipt().await.expect("Transaction was not received on L1 or receipt retrieval failed."); +} + async fn send_rpc_txs<'a, Fut>( rpc_txs: Vec, - send_rpc_tx_fn: &'a mut dyn FnMut(RpcTransaction) -> Fut, + send_rpc_tx_fn: &'a mut dyn Fn(RpcTransaction) -> Fut, ) -> Vec where Fut: Future + 'a, { let mut tx_hashes = vec![]; for rpc_tx in rpc_txs { + tokio::time::sleep(Duration::from_millis(1000 / TPS)).await; tx_hashes.push(send_rpc_tx_fn(rpc_tx).await); } tx_hashes } +// TODO(yair): Consolidate create_rpc_txs_fn and test_tx_hashes_fn into a single function. /// Creates and runs the integration test scenario for the sequencer integration test. Returns a /// list of transaction hashes, in the order they are expected to be in the mempool. -pub async fn run_integration_test_scenario<'a, Fut>( - tx_generator: MultiAccountTransactionGenerator, - send_rpc_tx_fn: &'a mut dyn FnMut(RpcTransaction) -> Fut, +pub async fn run_test_scenario<'a, Fut>( + tx_generator: &mut MultiAccountTransactionGenerator, + create_rpc_txs_fn: CreateRpcTxsFn, + l1_handler_txs: Vec, + send_rpc_tx_fn: &'a mut dyn Fn(RpcTransaction) -> Fut, + test_tx_hashes_fn: TestTxHashesFn, + chain_id: &ChainId, ) -> Vec where Fut: Future + 'a, { - let rpc_txs = create_txs_for_integration_test(tx_generator); - let tx_hashes = send_rpc_txs(rpc_txs, send_rpc_tx_fn).await; + let mut tx_hashes: Vec = l1_handler_txs + .iter() + .map(|l1_handler| { + l1_handler.calculate_transaction_hash(chain_id, &l1_handler.version).unwrap() + }) + .collect(); + + let rpc_txs = create_rpc_txs_fn(tx_generator); + tx_hashes.extend(send_rpc_txs(rpc_txs, send_rpc_tx_fn).await); + test_tx_hashes_fn(&tx_hashes) +} +pub fn test_multiple_account_txs(tx_hashes: &[TransactionHash]) -> Vec { // Return the transaction hashes in the order they should be given by the mempool: // Transactions from the same account are ordered by nonce; otherwise, higher tips are given // priority. assert!( tx_hashes.len() == 3, - "Unexpected number of transactions sent in the integration test scenario. Found {} \ - transactions", + "Unexpected number of transactions sent in the test scenario. Found {} transactions", tx_hashes.len() ); vec![tx_hashes[2], tx_hashes[0], tx_hashes[1]] } +pub fn test_many_invoke_txs(tx_hashes: &[TransactionHash]) -> Vec { + assert!( + tx_hashes.len() == 15, + "Unexpected number of transactions sent in the test scenario. Found {} transactions", + tx_hashes.len() + ); + // Only 12 transactions make it into the block (because the block is full). + tx_hashes[..12].to_vec() +} + /// Returns a list of the transaction hashes, in the order they are expected to be in the mempool. -pub async fn send_account_txs<'a, Fut>( - tx_generator: MultiAccountTransactionGenerator, +pub async fn send_consensus_txs<'a, 'b, FutA, FutB>( + tx_generator: &mut MultiAccountTransactionGenerator, account_id: AccountId, - n_txs: usize, - send_rpc_tx_fn: &'a mut dyn FnMut(RpcTransaction) -> Fut, + test_scenario: &impl TestScenario, + send_rpc_tx_fn: &'a mut dyn Fn(RpcTransaction) -> FutA, + send_l1_handler_tx_fn: &'b mut dyn Fn(L1HandlerTransaction) -> FutB, ) -> Vec where - Fut: Future + 'a, + FutA: Future + 'a, + FutB: Future + 'b, { - let rpc_txs = create_account_txs(tx_generator, n_txs, account_id); - send_rpc_txs(rpc_txs, send_rpc_tx_fn).await + let n_txs = test_scenario.n_txs(); + info!("Sending {n_txs} txs."); + + let (rpc_txs, l1_txs) = test_scenario.create_txs(tx_generator, account_id); + let mut tx_hashes = Vec::new(); + let l1_handler_tx_hashes = join_all(l1_txs.into_iter().map(send_l1_handler_tx_fn)).await; + tracing::info!("Sent L1 handlers with tx hashes: {l1_handler_tx_hashes:?}"); + tx_hashes.extend(l1_handler_tx_hashes); + tx_hashes.extend(send_rpc_txs(rpc_txs, send_rpc_tx_fn).await); + assert_eq!(tx_hashes.len(), n_txs); + tx_hashes } -pub async fn create_gateway_config(chain_info: ChainInfo) -> GatewayConfig { +pub fn create_gateway_config(chain_info: ChainInfo) -> GatewayConfig { let stateless_tx_validator_config = StatelessTransactionValidatorConfig { validate_non_zero_l1_gas_fee: true, max_calldata_length: 10, @@ -248,26 +585,127 @@ pub async fn create_gateway_config(chain_info: ChainInfo) -> GatewayConfig { GatewayConfig { stateless_tx_validator_config, stateful_tx_validator_config, chain_info } } -pub async fn create_http_server_config() -> HttpServerConfig { - // TODO(Tsabary): use ser_generated_param. - let socket = get_available_socket().await; - HttpServerConfig { ip: socket.ip(), port: socket.port() } -} - pub fn create_batcher_config( batcher_storage_config: StorageConfig, chain_info: ChainInfo, + block_max_capacity_sierra_gas: GasAmount, ) -> BatcherConfig { // TODO(Arni): Create BlockBuilderConfig create for testing method and use here. - const SEQUENCER_ADDRESS_FOR_TESTING: u128 = 1991; - + let concurrency_enabled = true; BatcherConfig { storage: batcher_storage_config, block_builder_config: BlockBuilderConfig { chain_info, - sequencer_address: contract_address!(SEQUENCER_ADDRESS_FOR_TESTING), + bouncer_config: BouncerConfig { + block_max_capacity: BouncerWeights { + sierra_gas: block_max_capacity_sierra_gas, + ..Default::default() + }, + }, + execute_config: TransactionExecutorConfig::create_for_testing(concurrency_enabled), ..Default::default() }, ..Default::default() } } + +pub fn create_mempool_config() -> MempoolConfig { + MempoolConfig { transaction_ttl: Duration::from_secs(5 * 60), ..Default::default() } +} + +pub fn create_class_manager_config( + class_storage_config: FsClassStorageConfig, +) -> FsClassManagerConfig { + let cached_class_storage_config = + CachedClassStorageConfig { class_cache_size: 100, deprecated_class_cache_size: 100 }; + let class_manager_config = ClassManagerConfig { cached_class_storage_config }; + FsClassManagerConfig { class_manager_config, class_storage_config } +} + +pub fn set_validator_id( + consensus_manager_config: &mut ConsensusManagerConfig, + node_index: usize, +) -> ValidatorId { + let validator_id = ValidatorId::try_from( + Felt::from(consensus_manager_config.consensus_config.validator_id) + Felt::from(node_index), + ) + .unwrap(); + consensus_manager_config.consensus_config.validator_id = validator_id; + validator_id +} + +pub fn create_state_sync_configs( + state_sync_storage_config: StorageConfig, + ports: Vec, +) -> Vec { + create_connected_network_configs(ports) + .into_iter() + .map(|network_config| StateSyncConfig { + storage_config: state_sync_storage_config.clone(), + network_config, + ..Default::default() + }) + .collect() +} + +/// Stores tx hashes streamed so far. +/// Assumes that rounds are monotonically increasing and that the last round is the chosen one. +#[derive(Debug, Default)] +pub struct AccumulatedTransactions { + pub latest_block_number: BlockNumber, + pub round: u32, + pub accumulated_tx_hashes: Vec, + // Will be added when next height starts. + current_round_tx_hashes: Vec, +} + +impl AccumulatedTransactions { + pub fn add_transactions( + &mut self, + height: BlockNumber, + round: u32, + tx_hashes: &[TransactionHash], + ) { + self.validate_coherent_height_and_round(height, round); + if self.latest_block_number < height { + info!( + "New height started, total {} txs streamed from block {}.", + self.current_round_tx_hashes.len(), + self.latest_block_number + ); + self.latest_block_number = height; + self.round = round; + self.accumulated_tx_hashes.append(&mut self.current_round_tx_hashes); + self.current_round_tx_hashes = tx_hashes.to_vec(); + } else if self.latest_block_number == height && self.round < round { + info!( + "New round started ({}). Dropping {} txs of round {}. Adding {} pending txs to \ + block {})", + round, + self.current_round_tx_hashes.len(), + self.round, + tx_hashes.len(), + height, + ); + self.round = round; + self.current_round_tx_hashes = tx_hashes.to_vec(); + } else { + info!( + "Adding {} streamed txs in block {} round {}.", + tx_hashes.len(), + self.latest_block_number, + self.round + ); + self.current_round_tx_hashes.extend_from_slice(tx_hashes); + } + } + + fn validate_coherent_height_and_round(&self, height: BlockNumber, round: u32) { + if self.latest_block_number > height { + panic!("Expected height to be greater or equal to the last height with transactions."); + } + if self.latest_block_number == height && self.round > round { + panic!("Expected round to be greater or equal to the last round."); + } + } +} diff --git a/crates/starknet_integration_tests/tests/end_to_end_flow_test.rs b/crates/starknet_integration_tests/tests/end_to_end_flow_test.rs index 367a97c1388..4f74bf3f569 100644 --- a/crates/starknet_integration_tests/tests/end_to_end_flow_test.rs +++ b/crates/starknet_integration_tests/tests/end_to_end_flow_test.rs @@ -1,96 +1,437 @@ -use std::collections::HashSet; +use std::collections::HashMap; +use std::time::Duration; use futures::StreamExt; use mempool_test_utils::starknet_api_test_utils::MultiAccountTransactionGenerator; use papyrus_network::network_manager::BroadcastTopicChannels; -use papyrus_protobuf::consensus::{ProposalFin, ProposalInit, ProposalPart}; -use papyrus_storage::test_utils::CHAIN_ID_FOR_TESTS; +use papyrus_protobuf::consensus::{ + HeightAndRound, + ProposalFin, + ProposalInit, + ProposalPart, + StreamMessage, + StreamMessageBody, +}; use pretty_assertions::assert_eq; use rstest::{fixture, rstest}; use starknet_api::block::{BlockHash, BlockNumber}; -use starknet_api::core::ContractAddress; -use starknet_api::transaction::TransactionHash; -use starknet_integration_tests::flow_test_setup::FlowTestSetup; +use starknet_api::consensus_transaction::ConsensusTransaction; +use starknet_api::core::ChainId; +use starknet_api::execution_resources::GasAmount; +use starknet_api::rpc_transaction::RpcTransaction; +use starknet_api::transaction::{TransactionHash, TransactionHasher, TransactionVersion}; +use starknet_consensus::types::ValidatorId; +use starknet_infra_utils::test_utils::TestIdentifier; +use starknet_integration_tests::flow_test_setup::{FlowSequencerSetup, FlowTestSetup}; use starknet_integration_tests::utils::{ - create_integration_test_tx_generator, - run_integration_test_scenario, + create_deploy_account_tx_and_invoke_tx, + create_flow_test_tx_generator, + create_funding_txs, + create_l1_handler_tx, + create_many_invoke_txs, + create_multiple_account_txs, + run_test_scenario, + test_many_invoke_txs, + test_multiple_account_txs, + CreateL1HandlerTxsFn, + CreateRpcTxsFn, + ExpectedContentId, + TestTxHashesFn, + ACCOUNT_ID_0, + UNDEPLOYED_ACCOUNT_ID, }; -use starknet_types_core::felt::Felt; +use starknet_sequencer_infra::trace_util::configure_tracing; +use tracing::debug; + +const INITIAL_HEIGHT: BlockNumber = BlockNumber(0); +const LAST_HEIGHT: BlockNumber = BlockNumber(5); +const LAST_HEIGHT_FOR_MANY_TXS: BlockNumber = BlockNumber(1); + +struct TestBlockScenario { + height: BlockNumber, + create_rpc_txs_fn: CreateRpcTxsFn, + create_l1_handler_txs_fn: CreateL1HandlerTxsFn, + test_tx_hashes_fn: TestTxHashesFn, + expected_content_id: ExpectedContentId, +} #[fixture] fn tx_generator() -> MultiAccountTransactionGenerator { - create_integration_test_tx_generator() + create_flow_test_tx_generator() } #[rstest] +#[case::end_to_end_flow( + TestIdentifier::EndToEndFlowTest, + create_test_blocks(), + GasAmount(29000000), + LAST_HEIGHT +)] +#[case::many_txs_scenario( + TestIdentifier::EndToEndFlowTestManyTxs, + create_test_blocks_for_many_txs_scenario(), + GasAmount(17500000), + LAST_HEIGHT_FOR_MANY_TXS +)] #[tokio::test] -async fn end_to_end(tx_generator: MultiAccountTransactionGenerator) { +async fn end_to_end_flow( + mut tx_generator: MultiAccountTransactionGenerator, + #[case] test_identifier: TestIdentifier, + #[case] test_blocks_scenarios: Vec, + #[case] block_max_capacity_sierra_gas: GasAmount, + #[case] expected_last_height: BlockNumber, +) { + configure_tracing().await; + const LISTEN_TO_BROADCAST_MESSAGES_TIMEOUT: std::time::Duration = - std::time::Duration::from_secs(5); + std::time::Duration::from_secs(50); // Setup. - let mut mock_running_system = FlowTestSetup::new_from_tx_generator(&tx_generator).await; - - // Create and send transactions. - let expected_batched_tx_hashes = run_integration_test_scenario(tx_generator, &mut |tx| { - mock_running_system.assert_add_tx_success(tx) - }) + let mut mock_running_system = FlowTestSetup::new_from_tx_generator( + &tx_generator, + test_identifier.into(), + block_max_capacity_sierra_gas, + ) .await; - // TODO(Dan, Itay): Consider adding a utility function that waits for something to happen. - tokio::time::timeout( - LISTEN_TO_BROADCAST_MESSAGES_TIMEOUT, - listen_to_broadcasted_messages( - &mut mock_running_system.consensus_proposals_channels, - &expected_batched_tx_hashes, + + tokio::join!( + wait_for_sequencer_node(&mock_running_system.sequencer_0), + wait_for_sequencer_node(&mock_running_system.sequencer_1), + ); + + let sequencers = [&mock_running_system.sequencer_0, &mock_running_system.sequencer_1]; + // We use only the first sequencer's gateway to test that the mempools are syncing. + let sequencer_to_add_txs = *sequencers.first().unwrap(); + let mut expected_proposer_iter = sequencers.iter().cycle(); + // We start at height 1, so we need to skip the proposer of the initial height. + expected_proposer_iter.next().unwrap(); + let chain_id = mock_running_system.chain_id().clone(); + let mut send_rpc_tx_fn = |tx| sequencer_to_add_txs.assert_add_tx_success(tx); + + // Build multiple heights to ensure heights are committed. + for TestBlockScenario { + height, + create_rpc_txs_fn, + create_l1_handler_txs_fn, + test_tx_hashes_fn, + expected_content_id, + } in test_blocks_scenarios + { + debug!("Starting height {}.", height); + // Create and send transactions. + // TODO(Arni): move send messages to l2 into [run_test_scenario]. + let l1_handler_txs = create_l1_handler_txs_fn(&mut tx_generator); + mock_running_system.send_messages_to_l2(&l1_handler_txs).await; + let expected_batched_tx_hashes = run_test_scenario( + &mut tx_generator, + create_rpc_txs_fn, + l1_handler_txs, + &mut send_rpc_tx_fn, + test_tx_hashes_fn, + &chain_id, + ) + .await; + let expected_validator_id = expected_proposer_iter + .next() + .unwrap() + .node_config + .consensus_manager_config + .consensus_config + .validator_id; + // TODO(Dan, Itay): Consider adding a utility function that waits for something to happen. + tokio::time::timeout( + LISTEN_TO_BROADCAST_MESSAGES_TIMEOUT, + listen_to_broadcasted_messages( + &mut mock_running_system.consensus_proposals_channels, + &expected_batched_tx_hashes, + height, + expected_content_id, + expected_validator_id, + &chain_id, + ), + ) + .await + .expect("listen to broadcasted messages should finish in time"); + } + + // Wait for all sequencer to commit the last tested block. + tokio::time::sleep(Duration::from_millis(2000)).await; + for sequencer in sequencers { + let height = sequencer.batcher_height().await; + assert!( + height >= expected_last_height.unchecked_next(), + "Sequencer {} didn't reach last height.", + sequencer.node_index + ); + } +} + +fn create_test_blocks() -> Vec { + let next_height = INITIAL_HEIGHT.unchecked_next(); + let heights_to_build = next_height.iter_up_to(LAST_HEIGHT.unchecked_next()); + let test_scenarios: Vec<( + CreateRpcTxsFn, + CreateL1HandlerTxsFn, + TestTxHashesFn, + ExpectedContentId, + )> = vec![ + // This block should be the first to be tested, as the addition of L1 handler transaction + // does not work smoothly with the current architecture of the test. + // TODO(Arni): Fix this. Move the L1 handler to be not the first block. + ( + |_| vec![], + create_l1_handler_tx, + test_single_tx, + ExpectedContentId::from_hex_unchecked( + "0x32a9c3b503e51b4330fe735b73975a62df996d6d6ebfe6cd1514ba2a68797cb", + ), ), - ) - .await - .expect("listen to broadcasted messages should finish in time"); + ( + create_multiple_account_txs, + |_| vec![], + test_multiple_account_txs, + ExpectedContentId::from_hex_unchecked( + "0x10935b9abad4ddc2b0a49423419b681f1bfc4193a904d08ef6da47a07b44a2d", + ), + ), + ( + create_funding_txs, + |_| vec![], + test_single_tx, + ExpectedContentId::from_hex_unchecked( + "0x1a28eb032f203df7b7b482e6ff20c3ea430b226bf76ea88a2fe4f68bcfc8319", + ), + ), + ( + deploy_account_and_invoke, + |_| vec![], + test_two_txs, + ExpectedContentId::from_hex_unchecked( + "0x70760eb94765a4ee0a58183bcf060880a2ebec126958931a89e86de6ba7097f", + ), + ), + ( + create_declare_tx, + |_| vec![], + test_single_tx, + ExpectedContentId::from_hex_unchecked( + "0x1fb51c3b6265b4a48931aecd64e5fae84e7138cfdf127ccf764d33916c74dee", + ), + ), + ]; + itertools::zip_eq(heights_to_build, test_scenarios) + .map( + |( + height, + ( + create_rpc_txs_fn, + create_l1_handler_txs_fn, + test_tx_hashes_fn, + expected_content_id, + ), + )| { + TestBlockScenario { + height, + create_rpc_txs_fn, + create_l1_handler_txs_fn, + test_tx_hashes_fn, + expected_content_id, + } + }, + ) + .collect() +} + +fn create_test_blocks_for_many_txs_scenario() -> Vec { + let next_height = INITIAL_HEIGHT.unchecked_next(); + let heights_to_build = next_height.iter_up_to(LAST_HEIGHT_FOR_MANY_TXS.unchecked_next()); + let test_scenarios: Vec<( + CreateRpcTxsFn, + CreateL1HandlerTxsFn, + TestTxHashesFn, + ExpectedContentId, + )> = vec![ + // Note: The following test scenario sends 15 transactions but only 12 are included in the + // block. This means that the last 3 transactions could be included in the next block if + // one is added to the test. + ( + create_many_invoke_txs, + |_| vec![], + test_many_invoke_txs, + ExpectedContentId::from_hex_unchecked( + "0x561142c073c705fb0028524e9fbbda1c362ebd175f72831450ef35e00a969e9", + ), + ), + ]; + itertools::zip_eq(heights_to_build, test_scenarios) + .map( + |( + height, + ( + create_rpc_txs_fn, + create_l1_handler_txs_fn, + test_tx_hashes_fn, + expected_content_id, + ), + )| { + TestBlockScenario { + height, + create_rpc_txs_fn, + create_l1_handler_txs_fn, + test_tx_hashes_fn, + expected_content_id, + } + }, + ) + .collect() +} + +async fn wait_for_sequencer_node(sequencer: &FlowSequencerSetup) { + sequencer.monitoring_client.await_alive(5000, 50).await.expect("Node should be alive."); } async fn listen_to_broadcasted_messages( - consensus_proposals_channels: &mut BroadcastTopicChannels, + consensus_proposals_channels: &mut BroadcastTopicChannels< + StreamMessage, + >, expected_batched_tx_hashes: &[TransactionHash], + expected_height: BlockNumber, + expected_content_id: ExpectedContentId, + expected_proposer_id: ValidatorId, + chain_id: &ChainId, ) { - let chain_id = CHAIN_ID_FOR_TESTS.clone(); let broadcasted_messages_receiver = &mut consensus_proposals_channels.broadcasted_messages_receiver; - let mut received_tx_hashes = HashSet::new(); - // TODO (Dan, Guy): retrieve / calculate the expected proposal init and fin. + // Collect messages in a map so that validations will use the ordering defined by `message_id`, + // meaning we ignore network reordering, like the StreamHandler. + let mut messages_cache = HashMap::new(); + let mut last_message_id = 0; + + while let Some((Ok(message), _)) = broadcasted_messages_receiver.next().await { + if message.stream_id.0 == expected_height.0 { + messages_cache.insert(message.message_id, message.clone()); + } else { + panic!( + "Expected height: {}. Received message from unexpected height: {}", + expected_height.0, message.stream_id.0 + ); + } + if message.message == papyrus_protobuf::consensus::StreamMessageBody::Fin { + last_message_id = message.message_id; + } + // Check that we got the Fin message and all previous messages. + if last_message_id > 0 && (0..=last_message_id).all(|id| messages_cache.contains_key(&id)) { + break; + } + } + // TODO(Dan, Guy): retrieve / calculate the expected proposal init and fin. let expected_proposal_init = ProposalInit { - height: BlockNumber(1), - round: 0, - valid_round: None, - proposer: ContractAddress::default(), + height: expected_height, + proposer: expected_proposer_id, + ..Default::default() }; - let expected_proposal_fin = ProposalFin { - proposal_content_id: BlockHash(Felt::from_hex_unchecked( - "0x4597ceedbef644865917bf723184538ef70d43954d63f5b7d8cb9d1bd4c2c32", - )), + let expected_proposal_fin = ProposalFin { proposal_commitment: BlockHash(expected_content_id) }; + + let StreamMessage { + stream_id: first_stream_id, + message: init_message, + message_id: incoming_message_id, + } = messages_cache.remove(&0).expect("Stream is missing its first message"); + + assert_eq!( + incoming_message_id, 0, + "Expected the first message in the stream to have id 0, got {}", + incoming_message_id + ); + let StreamMessageBody::Content(ProposalPart::Init(incoming_proposal_init)) = init_message + else { + panic!("Expected an init message. Got: {:?}", init_message) }; assert_eq!( - broadcasted_messages_receiver.next().await.unwrap().0.unwrap(), - ProposalPart::Init(expected_proposal_init) + incoming_proposal_init, expected_proposal_init, + "Unexpected init message: {:?}, expected: {:?}", + incoming_proposal_init, expected_proposal_init ); - loop { - match broadcasted_messages_receiver.next().await.unwrap().0.unwrap() { - ProposalPart::Init(init) => panic!("Unexpected init: {:?}", init), - ProposalPart::Fin(proposal_fin) => { - assert_eq!(proposal_fin, expected_proposal_fin); - break; + + let mut received_tx_hashes = Vec::new(); + let mut got_proposal_fin = false; + let mut got_channel_fin = false; + for i in 1_u64..messages_cache.len().try_into().unwrap() { + let StreamMessage { message, stream_id, message_id: _ } = + messages_cache.remove(&i).expect("Stream should have all consecutive messages"); + assert_eq!(stream_id, first_stream_id, "Expected the same stream id for all messages"); + match message { + StreamMessageBody::Content(ProposalPart::Init(init)) => { + panic!("Unexpected init: {:?}", init) } - ProposalPart::Transactions(transactions) => { - received_tx_hashes.extend( - transactions - .transactions - .iter() - .map(|tx| tx.calculate_transaction_hash(&chain_id).unwrap()), + StreamMessageBody::Content(ProposalPart::Fin(proposal_fin)) => { + assert_eq!( + proposal_fin, expected_proposal_fin, + "Unexpected fin message: {:?}, expected: {:?}", + proposal_fin, expected_proposal_fin ); + got_proposal_fin = true; + } + StreamMessageBody::Content(ProposalPart::BlockInfo(_)) => { + // TODO(Asmaa): Add validation for block info. } + StreamMessageBody::Content(ProposalPart::Transactions(transactions)) => { + // TODO(Arni): add calculate_transaction_hash to consensus transaction and use it + // here. + received_tx_hashes.extend(transactions.transactions.iter().map(|tx| match tx { + ConsensusTransaction::RpcTransaction(tx) => { + let starknet_api_tx = + starknet_api::transaction::Transaction::from(tx.clone()); + starknet_api_tx.calculate_transaction_hash(chain_id).unwrap() + } + ConsensusTransaction::L1Handler(tx) => { + tx.calculate_transaction_hash(chain_id, &TransactionVersion::ZERO).unwrap() + } + })); + } + StreamMessageBody::Fin => { + got_channel_fin = true; + } + } + if got_proposal_fin && got_channel_fin { + assert!( + received_tx_hashes.len() == expected_batched_tx_hashes.len(), + "Expected {} transactions, got {}", + expected_batched_tx_hashes.len(), + received_tx_hashes.len() + ); + break; } } - // Using HashSet to ignore the order of the transactions (broadcast can lead to reordering). + + received_tx_hashes.sort(); + let mut expected_batched_tx_hashes = expected_batched_tx_hashes.to_vec(); + expected_batched_tx_hashes.sort(); assert_eq!( - received_tx_hashes, - expected_batched_tx_hashes.iter().cloned().collect::>() + received_tx_hashes, expected_batched_tx_hashes, + "Unexpected transactions in block number {expected_height}" ); } + +/// Generates a deploy account transaction followed by an invoke transaction from the same deployed +/// account. +fn deploy_account_and_invoke( + tx_generator: &mut MultiAccountTransactionGenerator, +) -> Vec { + create_deploy_account_tx_and_invoke_tx(tx_generator, UNDEPLOYED_ACCOUNT_ID) +} + +fn test_single_tx(tx_hashes: &[TransactionHash]) -> Vec { + assert_eq!(tx_hashes.len(), 1, "Expected a single transaction"); + tx_hashes.to_vec() +} + +fn test_two_txs(tx_hashes: &[TransactionHash]) -> Vec { + assert_eq!(tx_hashes.len(), 2, "Expected two transactions"); + tx_hashes.to_vec() +} + +fn create_declare_tx(tx_generator: &mut MultiAccountTransactionGenerator) -> Vec { + let account_tx_generator = tx_generator.account_with_id_mut(ACCOUNT_ID_0); + let declare_tx = account_tx_generator.generate_declare(); + vec![declare_tx] +} diff --git a/crates/starknet_integration_tests/tests/end_to_end_integration_test.rs b/crates/starknet_integration_tests/tests/end_to_end_integration_test.rs deleted file mode 100644 index d2af0e5e309..00000000000 --- a/crates/starknet_integration_tests/tests/end_to_end_integration_test.rs +++ /dev/null @@ -1,179 +0,0 @@ -use std::path::PathBuf; -use std::process::Stdio; -use std::time::Duration; - -use infra_utils::command::create_shell_command; -use infra_utils::path::resolve_project_relative_path; -use mempool_test_utils::starknet_api_test_utils::{AccountId, MultiAccountTransactionGenerator}; -use papyrus_execution::execution_utils::get_nonce_at; -use papyrus_storage::state::StateStorageReader; -use papyrus_storage::StorageReader; -use rstest::{fixture, rstest}; -use starknet_api::block::BlockNumber; -use starknet_api::core::{ContractAddress, Nonce}; -use starknet_api::state::StateNumber; -use starknet_integration_tests::integration_test_setup::IntegrationTestSetup; -use starknet_integration_tests::utils::{create_integration_test_tx_generator, send_account_txs}; -use starknet_sequencer_infra::trace_util::configure_tracing; -use starknet_sequencer_node::test_utils::compilation::{compile_node_result, NODE_EXECUTABLE_PATH}; -use starknet_types_core::felt::Felt; -use tokio::process::Child; -use tokio::task::{self, JoinHandle}; -use tokio::time::interval; -use tracing::{error, info}; - -#[fixture] -fn tx_generator() -> MultiAccountTransactionGenerator { - create_integration_test_tx_generator() -} - -// TODO(Tsabary): Move to a suitable util location. -async fn spawn_node_child_task(node_config_path: PathBuf) -> Child { - // TODO(Tsabary): Capture output to a log file, and present it in case of a failure. - info!("Compiling the node."); - compile_node_result().await.expect("Failed to compile the sequencer node."); - let node_executable = resolve_project_relative_path(NODE_EXECUTABLE_PATH) - .expect("Node executable should be available") - .to_string_lossy() - .to_string(); - - info!("Running the node from: {}", node_executable); - create_shell_command(node_executable.as_str()) - .arg("--config_file") - .arg(node_config_path.to_str().unwrap()) - .stderr(Stdio::inherit()) - .stdout(Stdio::null()) - .kill_on_drop(true) // Required for stopping the node when the handle is dropped. - .spawn() - .expect("Failed to spawn the sequencer node.") -} - -async fn spawn_run_node(node_config_path: PathBuf) -> JoinHandle<()> { - task::spawn(async move { - info!("Running the node from its spawned task."); - let _node_run_result = spawn_node_child_task(node_config_path). - await. // awaits the completion of spawn_node_child_task. - wait(). // runs the node until completion -- should be running indefinitely. - await; // awaits the completion of the node. - panic!("Node stopped unexpectedly."); - }) -} - -/// Reads the latest block number from the storage. -fn get_latest_block_number(storage_reader: &StorageReader) -> BlockNumber { - let txn = storage_reader.begin_ro_txn().unwrap(); - txn.get_state_marker() - .expect("There should always be a state marker") - .prev() - .expect("There should be a previous block in the storage, set by the test setup") -} - -/// Reads an account nonce after a block number from storage. -fn get_account_nonce( - storage_reader: &StorageReader, - block_number: BlockNumber, - contract_address: ContractAddress, -) -> Nonce { - let txn = storage_reader.begin_ro_txn().unwrap(); - let state_number = StateNumber::unchecked_right_after_block(block_number); - get_nonce_at(&txn, state_number, None, contract_address) - .expect("Should always be Ok(Some(Nonce))") - .expect("Should always be Some(Nonce)") -} - -/// Sample a storage until sufficiently many blocks have been stored. Returns an error if after -/// the given number of attempts the target block number has not been reached. -async fn await_block( - interval_duration: Duration, - target_block_number: BlockNumber, - max_attempts: usize, - storage_reader: &StorageReader, -) -> Result<(), ()> { - let mut interval = interval(interval_duration); - let mut count = 0; - loop { - // Read the latest block number. - let latest_block_number = get_latest_block_number(storage_reader); - count += 1; - - // Check if reached the target block number. - if latest_block_number >= target_block_number { - info!("Found block {} after {} queries.", target_block_number, count); - return Ok(()); - } - - // Check if reached the maximum attempts. - if count > max_attempts { - error!( - "Latest block is {}, expected {}, stopping sampling.", - latest_block_number, target_block_number - ); - return Err(()); - } - - // Wait for the next interval. - interval.tick().await; - } -} - -#[rstest] -#[tokio::test] -async fn test_end_to_end_integration(mut tx_generator: MultiAccountTransactionGenerator) { - const EXPECTED_BLOCK_NUMBER: BlockNumber = BlockNumber(15); - - configure_tracing(); - info!("Running integration test setup."); - - // Creating the storage for the test. - - let integration_test_setup = IntegrationTestSetup::new_from_tx_generator(&tx_generator).await; - - info!("Running sequencer node."); - let node_run_handle = spawn_run_node(integration_test_setup.node_config_path).await; - - // Wait for the node to start. - match integration_test_setup.is_alive_test_client.await_alive(Duration::from_secs(5), 50).await - { - Ok(_) => {} - Err(_) => panic!("Node is not alive."), - } - - info!("Running integration test simulator."); - - let send_rpc_tx_fn = - &mut |rpc_tx| integration_test_setup.add_tx_http_client.assert_add_tx_success(rpc_tx); - - const ACCOUNT_ID_0: AccountId = 0; - let n_txs = 50; - let sender_address = tx_generator.account_with_id(ACCOUNT_ID_0).sender_address(); - info!("Sending {n_txs} txs."); - let tx_hashes = send_account_txs(tx_generator, ACCOUNT_ID_0, n_txs, send_rpc_tx_fn).await; - - info!("Awaiting until {EXPECTED_BLOCK_NUMBER} blocks have been created."); - - let (batcher_storage_reader, _) = - papyrus_storage::open_storage(integration_test_setup.batcher_storage_config) - .expect("Failed to open batcher's storage"); - - match await_block(Duration::from_secs(5), EXPECTED_BLOCK_NUMBER, 15, &batcher_storage_reader) - .await - { - Ok(_) => {} - Err(_) => panic!("Did not reach expected block number."), - } - - info!("Shutting the node down."); - node_run_handle.abort(); - let res = node_run_handle.await; - assert!( - res.expect_err("Node should have been stopped.").is_cancelled(), - "Node should have been stopped." - ); - - info!("Verifying tx sender account nonce."); - let expected_nonce_value = tx_hashes.len() + 1; - let expected_nonce = - Nonce(Felt::from_hex_unchecked(format!("0x{:X}", expected_nonce_value).as_str())); - let nonce = get_account_nonce(&batcher_storage_reader, EXPECTED_BLOCK_NUMBER, sender_address); - assert_eq!(nonce, expected_nonce); -} diff --git a/crates/starknet_integration_tests/tests/gateway_mempool_tests.rs b/crates/starknet_integration_tests/tests/gateway_mempool_tests.rs deleted file mode 100644 index 51b9023f328..00000000000 --- a/crates/starknet_integration_tests/tests/gateway_mempool_tests.rs +++ /dev/null @@ -1,41 +0,0 @@ -#[tokio::test] -#[ignore = "Not yet implemented: Simulate mempool non-responsiveness without crash (simulate \ - latency issue)"] -async fn test_mempool_non_responsive() {} - -#[tokio::test] -#[ignore = "Not yet implemented: On crash, mempool resets and starts empty"] -async fn test_mempool_crash() {} - -#[tokio::test] -#[ignore = "Not yet implemented: Simulate gateway state non-responsiveness (latency issue)"] -async fn test_gateway_state_non_responsive() {} - -#[tokio::test] -#[ignore = "Not yet implemented: Add high-priority transaction to a full mempool"] -async fn test_add_tx_high_priority_full_mempool() {} - -#[tokio::test] -#[ignore = "Not yet implemented: Add low-priority transaction to a full mempool (should not enter)"] -async fn test_add_tx_low_priority_full_mempool() {} - -#[tokio::test] -#[ignore = "Not yet implemented: Simulate a single account sending many transactions (e.g., an \ - exchange)"] -async fn test_single_account_stress() {} - -#[tokio::test] -#[ignore = "Not yet implemented"] -async fn test_duplicate_tx_error_handling() {} - -#[tokio::test] -#[ignore = "Not yet implemented"] -async fn test_duplicate_nonce_error_handling() {} - -#[tokio::test] -#[ignore = "Not yet implemented: go over edge cases that occur when commit_block arrived at the - mempool before it arrived at the gateway, and vice versa. For example, account nonces - in the GW during add_tx will be different from what the mempool knows about. - NOTE: this is for after the first POC, in the first POC the mempool tracks account - nonces internally, indefinitely (which is of course not scalable and is only for POC)"] -async fn test_commit_block_races() {} diff --git a/crates/starknet_integration_tests/tests/mempool_p2p_flow_test.rs b/crates/starknet_integration_tests/tests/mempool_p2p_flow_test.rs deleted file mode 100644 index 2c1f5d42ae4..00000000000 --- a/crates/starknet_integration_tests/tests/mempool_p2p_flow_test.rs +++ /dev/null @@ -1,123 +0,0 @@ -use std::collections::HashSet; -use std::net::SocketAddr; - -use futures::StreamExt; -use mempool_test_utils::starknet_api_test_utils::MultiAccountTransactionGenerator; -use papyrus_network::gossipsub_impl::Topic; -use papyrus_network::network_manager::test_utils::create_network_config_connected_to_broadcast_channels; -use papyrus_protobuf::mempool::RpcTransactionWrapper; -use rstest::{fixture, rstest}; -use starknet_api::rpc_transaction::RpcTransaction; -use starknet_http_server::config::HttpServerConfig; -use starknet_integration_tests::state_reader::{spawn_test_rpc_state_reader, StorageTestSetup}; -use starknet_integration_tests::utils::{ - create_batcher_config, - create_chain_info, - create_gateway_config, - create_http_server_config, - create_integration_test_tx_generator, - run_integration_test_scenario, - test_rpc_state_reader_config, - HttpTestClient, -}; -use starknet_mempool_p2p::config::MempoolP2pConfig; -use starknet_mempool_p2p::MEMPOOL_TOPIC; -use starknet_sequencer_node::config::component_config::ComponentConfig; -use starknet_sequencer_node::config::component_execution_config::{ - ComponentExecutionConfig, - ComponentExecutionMode, -}; -use starknet_sequencer_node::config::node_config::SequencerNodeConfig; -use starknet_sequencer_node::servers::run_component_servers; -use starknet_sequencer_node::utils::create_node_modules; -use starknet_task_executor::tokio_executor::TokioExecutor; -use tokio::runtime::Handle; - -#[fixture] -fn tx_generator() -> MultiAccountTransactionGenerator { - create_integration_test_tx_generator() -} - -// TODO: remove code duplication with FlowTestSetup -#[rstest] -#[tokio::test] -async fn test_mempool_sends_tx_to_other_peer(tx_generator: MultiAccountTransactionGenerator) { - let handle = Handle::current(); - let task_executor = TokioExecutor::new(handle); - - let chain_info = create_chain_info(); - let accounts = tx_generator.accounts(); - let storage_for_test = StorageTestSetup::new(accounts, chain_info.chain_id.clone()); - - // Spawn a papyrus rpc server for a papyrus storage reader. - let rpc_server_addr = spawn_test_rpc_state_reader( - storage_for_test.rpc_storage_reader, - chain_info.chain_id.clone(), - ) - .await; - - // Derive the configuration for the mempool node. - let components = ComponentConfig { - consensus_manager: ComponentExecutionConfig { - execution_mode: ComponentExecutionMode::Disabled, - local_server_config: None, - ..Default::default() - }, - batcher: ComponentExecutionConfig { - execution_mode: ComponentExecutionMode::Disabled, - local_server_config: None, - ..Default::default() - }, - ..Default::default() - }; - - let batcher_config = - create_batcher_config(storage_for_test.batcher_storage_config, chain_info.clone()); - let gateway_config = create_gateway_config(chain_info).await; - let http_server_config = create_http_server_config().await; - let rpc_state_reader_config = test_rpc_state_reader_config(rpc_server_addr); - let (network_config, mut broadcast_channels) = - create_network_config_connected_to_broadcast_channels::(Topic::new( - MEMPOOL_TOPIC, - )); - let mempool_p2p_config = MempoolP2pConfig { network_config, ..Default::default() }; - let config = SequencerNodeConfig { - components, - batcher_config, - gateway_config, - http_server_config, - rpc_state_reader_config, - mempool_p2p_config, - ..SequencerNodeConfig::default() - }; - - let (_clients, servers) = create_node_modules(&config); - - let HttpServerConfig { ip, port } = config.http_server_config; - let add_tx_http_client = HttpTestClient::new(SocketAddr::from((ip, port))); - - // Build and run the sequencer node. - let sequencer_node_future = run_component_servers(servers); - let _sequencer_node_handle = task_executor.spawn_with_handle(sequencer_node_future); - - // Wait for server to spin up and for p2p to discover other peer. - // TODO(Gilad): Replace with a persistent Client with a built-in retry to protect against CI - // flakiness. - tokio::time::sleep(std::time::Duration::from_millis(1000)).await; - - let mut expected_txs = HashSet::new(); - - // Create and send transactions. - let _tx_hashes = run_integration_test_scenario(tx_generator, &mut |tx: RpcTransaction| { - expected_txs.insert(tx.clone()); // push the sent tx to the expected_txs list - add_tx_http_client.assert_add_tx_success(tx) - }) - .await; - - while !expected_txs.is_empty() { - let tx = - broadcast_channels.broadcasted_messages_receiver.next().await.unwrap().0.unwrap().0; - assert!(expected_txs.contains(&tx)); - expected_txs.remove(&tx); - } -} diff --git a/crates/starknet_l1_gas_price/Cargo.toml b/crates/starknet_l1_gas_price/Cargo.toml new file mode 100644 index 00000000000..83284930412 --- /dev/null +++ b/crates/starknet_l1_gas_price/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "starknet_l1_gas_price" +version.workspace = true +edition.workspace = true +repository.workspace = true +license.workspace = true + +[dependencies] +async-trait.workspace = true +papyrus_base_layer.workspace = true +papyrus_config.workspace = true +reqwest.workspace = true +serde.workspace = true +serde_json.workspace = true +starknet_api.workspace = true +starknet_l1_gas_price_types.workspace = true +starknet_sequencer_infra.workspace = true +thiserror.workspace = true +tokio.workspace = true +tracing.workspace = true +url.workspace = true +validator.workspace = true + +[dev-dependencies] +mockall.workspace = true +mockito.workspace = true +papyrus_base_layer = { workspace = true, features = ["testing"] } +starknet_l1_gas_price_types = { workspace = true, features = ["testing"] } + +[lints] +workspace = true diff --git a/crates/starknet_l1_gas_price/src/communication.rs b/crates/starknet_l1_gas_price/src/communication.rs new file mode 100644 index 00000000000..93213b2196b --- /dev/null +++ b/crates/starknet_l1_gas_price/src/communication.rs @@ -0,0 +1,41 @@ +use async_trait::async_trait; +use starknet_l1_gas_price_types::{L1GasPriceRequest, L1GasPriceResponse}; +use starknet_sequencer_infra::component_client::{LocalComponentClient, RemoteComponentClient}; +use starknet_sequencer_infra::component_definitions::{ + ComponentRequestAndResponseSender, + ComponentRequestHandler, +}; +use starknet_sequencer_infra::component_server::{ + LocalComponentServer, + RemoteComponentServer, + WrapperServer, +}; +use tracing::instrument; + +use crate::l1_gas_price_provider::L1GasPriceProvider; +use crate::l1_gas_price_scraper::L1GasPriceScraper; + +pub type LocalL1GasPriceServer = + LocalComponentServer; +pub type RemoteL1GasPriceServer = RemoteComponentServer; +pub type L1GasPriceRequestAndResponseSender = + ComponentRequestAndResponseSender; +pub type LocalL1GasPriceClient = LocalComponentClient; +pub type RemoteL1GasPriceClient = RemoteComponentClient; + +pub type L1GasPriceScraperServer = WrapperServer>; + +#[async_trait] +impl ComponentRequestHandler for L1GasPriceProvider { + #[instrument(skip(self))] + async fn handle_request(&mut self, request: L1GasPriceRequest) -> L1GasPriceResponse { + match request { + L1GasPriceRequest::GetGasPrice(timestamp) => { + L1GasPriceResponse::GetGasPrice(self.get_price_info(timestamp)) + } + L1GasPriceRequest::AddGasPrice(height, sample) => { + L1GasPriceResponse::AddGasPrice(self.add_price_info(height, sample)) + } + } + } +} diff --git a/crates/starknet_l1_gas_price/src/eth_to_strk_oracle.rs b/crates/starknet_l1_gas_price/src/eth_to_strk_oracle.rs new file mode 100644 index 00000000000..706dbeea884 --- /dev/null +++ b/crates/starknet_l1_gas_price/src/eth_to_strk_oracle.rs @@ -0,0 +1,116 @@ +use std::collections::{BTreeMap, HashMap}; + +use async_trait::async_trait; +use papyrus_config::converters::{deserialize_optional_map, serialize_optional_map}; +use papyrus_config::dumping::{ser_param, SerializeConfig}; +use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; +use reqwest::header::{HeaderMap, HeaderName, HeaderValue}; +use serde::{Deserialize, Serialize}; +use serde_json; +use starknet_l1_gas_price_types::errors::EthToStrkOracleClientError; +use starknet_l1_gas_price_types::EthToStrkOracleClientTrait; +use tracing::{debug, info}; +use url::Url; + +#[cfg(test)] +#[path = "eth_to_strk_oracle_test.rs"] +pub mod eth_to_strk_oracle_test; + +pub const ETH_TO_STRK_QUANTIZATION: u64 = 18; + +fn hashmap_to_headermap(hash_map: Option>) -> HeaderMap { + let mut header_map = HeaderMap::new(); + if let Some(map) = hash_map { + for (key, value) in map { + header_map.insert( + HeaderName::from_bytes(key.as_bytes()).expect("Failed to parse header name"), + HeaderValue::from_str(&value).expect("Failed to parse header value"), + ); + } + } + header_map +} + +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)] +pub struct EthToStrkOracleConfig { + pub base_url: Url, + #[serde(deserialize_with = "deserialize_optional_map")] + pub headers: Option>, +} + +impl SerializeConfig for EthToStrkOracleConfig { + fn dump(&self) -> BTreeMap { + BTreeMap::from_iter([ + ser_param( + "base_url", + &self.base_url, + "URL to query. This must end with the query parameter `timestamp=` as we append a \ + UNIX timestamp.", + ParamPrivacyInput::Private, + ), + ser_param( + "headers", + &serialize_optional_map(&self.headers), + "HTTP headers for the eth to strk oracle, formatted as 'k1:v1 k2:v2 ...'.", + ParamPrivacyInput::Private, + ), + ]) + } +} + +impl Default for EthToStrkOracleConfig { + fn default() -> Self { + Self { base_url: Url::parse("https://example.com/api?timestamp=").unwrap(), headers: None } + } +} + +/// Client for interacting with the eth to strk Oracle API. +pub struct EthToStrkOracleClient { + /// The base URL of the eth to strk Oracle API. + /// This must end with the query parameter `timestamp=` as we append a UNIX timestamp. + base_url: Url, + /// HTTP headers required for requests. + headers: HeaderMap, + client: reqwest::Client, +} + +impl EthToStrkOracleClient { + pub fn new(base_url: Url, headers: Option>) -> Self { + info!("Creating EthToStrkOracleClient with: base_url={base_url} headers={:?}", headers); + Self { base_url, headers: hashmap_to_headermap(headers), client: reqwest::Client::new() } + } +} + +#[async_trait] +impl EthToStrkOracleClientTrait for EthToStrkOracleClient { + /// The HTTP response must include the following fields: + /// - `"price"`: a hexadecimal string representing the price. + /// - `"decimals"`: a `u64` value, must be equal to `ETH_TO_STRK_QUANTIZATION`. + async fn eth_to_fri_rate(&self, timestamp: u64) -> Result { + let url = format!("{}{}", self.base_url, timestamp); + let response = self.client.get(&url).headers(self.headers.clone()).send().await?; + let body = response.text().await?; + + let json: serde_json::Value = serde_json::from_str(&body)?; + let price = json + .get("price") + .and_then(|v| v.as_str()) + .ok_or(EthToStrkOracleClientError::MissingFieldError("price"))?; + // Convert hex to u128 + let rate = u128::from_str_radix(price.trim_start_matches("0x"), 16) + .expect("Failed to parse price as u128"); + // Extract decimals from API response + let decimals = json + .get("decimals") + .and_then(|v| v.as_u64()) + .ok_or(EthToStrkOracleClientError::MissingFieldError("decimals"))?; + if decimals != ETH_TO_STRK_QUANTIZATION { + return Err(EthToStrkOracleClientError::InvalidDecimalsError( + ETH_TO_STRK_QUANTIZATION, + decimals, + )); + } + debug!("Conversion rate for timestamp {timestamp} is {rate}"); + Ok(rate) + } +} diff --git a/crates/starknet_l1_gas_price/src/eth_to_strk_oracle_test.rs b/crates/starknet_l1_gas_price/src/eth_to_strk_oracle_test.rs new file mode 100644 index 00000000000..c99a85e0a9e --- /dev/null +++ b/crates/starknet_l1_gas_price/src/eth_to_strk_oracle_test.rs @@ -0,0 +1,36 @@ +use serde_json::json; +use starknet_l1_gas_price_types::EthToStrkOracleClientTrait; +use tokio; +use url::Url; + +use crate::eth_to_strk_oracle::EthToStrkOracleClient; + +#[tokio::test] +async fn eth_to_fri_rate() { + let expected_rate = 123456; + let expected_rate_hex = format!("0x{:x}", expected_rate); + let timestamp = 1234567890; + // Create a mock HTTP server. + let mut server = mockito::Server::new_async().await; + + // Define a mock response for a GET request with a specific timestamp in the path + let _m = server + .mock("GET", format!("/{}", timestamp).as_str()) + .with_header("Content-Type", "application/json") + .with_body( + json!({ + "price": expected_rate_hex, + "decimals": 18 + }) + .to_string(), + ) + .create(); + + // Construct the base URL from the mock server + let base_url = Url::parse(&server.url()).unwrap(); + + let client = EthToStrkOracleClient::new(base_url, None); + let rate = client.eth_to_fri_rate(timestamp).await.unwrap(); + + assert_eq!(rate, expected_rate); +} diff --git a/crates/starknet_l1_gas_price/src/l1_gas_price_provider.rs b/crates/starknet_l1_gas_price/src/l1_gas_price_provider.rs new file mode 100644 index 00000000000..04839c276d3 --- /dev/null +++ b/crates/starknet_l1_gas_price/src/l1_gas_price_provider.rs @@ -0,0 +1,165 @@ +use std::collections::{BTreeMap, VecDeque}; + +use papyrus_base_layer::{L1BlockNumber, PriceSample}; +use papyrus_config::dumping::{ser_param, SerializeConfig}; +use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; +use serde::{Deserialize, Serialize}; +use starknet_api::block::BlockTimestamp; +use starknet_l1_gas_price_types::errors::L1GasPriceProviderError; +use starknet_l1_gas_price_types::{L1GasPriceProviderResult, PriceInfo}; +use starknet_sequencer_infra::component_definitions::ComponentStarter; +use validator::Validate; + +#[cfg(test)] +#[path = "l1_gas_price_provider_test.rs"] +pub mod l1_gas_price_provider_test; + +#[derive(Clone, Debug, Serialize, Deserialize, Validate, PartialEq)] +pub struct L1GasPriceProviderConfig { + // TODO(guyn): these two fields need to go into VersionedConstants. + pub number_of_blocks_for_mean: u64, + // Use seconds not Duration since seconds is the basic quanta of time for both Starknet and + // Ethereum. + pub lag_margin_seconds: u64, + pub storage_limit: usize, +} + +impl Default for L1GasPriceProviderConfig { + fn default() -> Self { + const MEAN_NUMBER_OF_BLOCKS: u64 = 300; + Self { + number_of_blocks_for_mean: MEAN_NUMBER_OF_BLOCKS, + lag_margin_seconds: 60, + storage_limit: usize::try_from(10 * MEAN_NUMBER_OF_BLOCKS).unwrap(), + } + } +} + +impl SerializeConfig for L1GasPriceProviderConfig { + fn dump(&self) -> BTreeMap { + BTreeMap::from([ + ser_param( + "number_of_blocks_for_mean", + &self.number_of_blocks_for_mean, + "Number of blocks to use for the mean gas price calculation", + ParamPrivacyInput::Public, + ), + ser_param( + "lag_margin_seconds", + &self.lag_margin_seconds, + "Difference between the time of the block from L1 used to calculate the gas price \ + and the time of the L2 block this price is used in", + ParamPrivacyInput::Public, + ), + ser_param( + "storage_limit", + &self.storage_limit, + "Maximum number of L1 blocks to keep cached", + ParamPrivacyInput::Public, + ), + ]) + } +} + +#[derive(Clone, Debug, Eq, PartialEq)] +struct RingBuffer(VecDeque); +impl RingBuffer { + fn new(size: usize) -> Self { + Self(VecDeque::with_capacity(size)) + } + + fn push(&mut self, item: T) { + if self.0.len() == self.0.capacity() { + self.0.pop_front(); + } + self.0.push_back(item); + } +} +// Deref lets us use .iter() and .back(), etc. +// Do not implement mut_deref, as that could break the +// size restriction of the RingBuffer. +impl std::ops::Deref for RingBuffer { + type Target = VecDeque; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +#[derive(Clone, Debug)] +pub struct GasPriceData { + pub height: L1BlockNumber, + pub sample: PriceSample, +} + +#[derive(Clone, Debug)] +pub struct L1GasPriceProvider { + config: L1GasPriceProviderConfig, + price_samples_by_block: RingBuffer, +} + +impl L1GasPriceProvider { + pub fn new(config: L1GasPriceProviderConfig) -> Self { + let storage_limit = config.storage_limit; + Self { config, price_samples_by_block: RingBuffer::new(storage_limit) } + } + + pub fn add_price_info( + &mut self, + height: L1BlockNumber, + sample: PriceSample, + ) -> L1GasPriceProviderResult<()> { + if let Some(data) = self.price_samples_by_block.back() { + if height != data.height + 1 { + return Err(L1GasPriceProviderError::UnexpectedHeightError { + expected: data.height + 1, + found: height, + }); + } + } + self.price_samples_by_block.push(GasPriceData { height, sample }); + Ok(()) + } + + pub fn get_price_info(&self, timestamp: BlockTimestamp) -> L1GasPriceProviderResult { + // This index is for the last block in the mean (inclusive). + let index_last_timestamp_rev = + self.price_samples_by_block.iter().rev().position(|data| { + data.sample.timestamp <= timestamp.0 - self.config.lag_margin_seconds + }); + + // Could not find a block with the requested timestamp and lag. + let Some(last_index_rev) = index_last_timestamp_rev else { + return Err(L1GasPriceProviderError::MissingDataError { + timestamp: timestamp.0, + lag: self.config.lag_margin_seconds, + }); + }; + // We need to convert the index to the forward direction. + let last_index = self.price_samples_by_block.len() - last_index_rev; + + let num_blocks = usize::try_from(self.config.number_of_blocks_for_mean) + .expect("number_of_blocks_for_mean is too large to fit into a usize"); + if last_index < num_blocks { + return Err(L1GasPriceProviderError::InsufficientHistoryError { + expected: num_blocks, + found: last_index, + }); + } + // Go over all elements between last_index-num_blocks to last_index (non-inclusive). + let (gas_price, data_gas_price) = + self.price_samples_by_block.iter().skip(last_index - num_blocks).take(num_blocks).fold( + (0, 0), + |(sum_base, sum_blob), data| { + (sum_base + data.sample.base_fee_per_gas, sum_blob + data.sample.blob_fee) + }, + ); + + Ok(PriceInfo { + base_fee_per_gas: gas_price / u128::from(self.config.number_of_blocks_for_mean), + blob_fee: data_gas_price / u128::from(self.config.number_of_blocks_for_mean), + }) + } +} + +impl ComponentStarter for L1GasPriceProvider {} diff --git a/crates/starknet_l1_gas_price/src/l1_gas_price_provider_test.rs b/crates/starknet_l1_gas_price/src/l1_gas_price_provider_test.rs new file mode 100644 index 00000000000..0559ba01d49 --- /dev/null +++ b/crates/starknet_l1_gas_price/src/l1_gas_price_provider_test.rs @@ -0,0 +1,110 @@ +use papyrus_base_layer::PriceSample; +use starknet_api::block::BlockTimestamp; +use starknet_l1_gas_price_types::PriceInfo; + +use crate::l1_gas_price_provider::{ + L1GasPriceProvider, + L1GasPriceProviderConfig, + L1GasPriceProviderError, +}; + +// Make a provider with five samples. Timestamps are 2 seconds apart, starting from 0. +// To get the prices for a specific set of blocks (according to the final block) use +// samples[final_index].timestamp + config.lag. Returns the provider and a vector of samples to +// compare with. +fn make_provider() -> (L1GasPriceProvider, Vec) { + let mut provider = L1GasPriceProvider::new(L1GasPriceProviderConfig { + number_of_blocks_for_mean: 3, + ..Default::default() + }); + let mut samples = Vec::new(); + for i in 0..5 { + let block_num = i.try_into().unwrap(); + let price = (i * i).try_into().unwrap(); + let time = (i * 2).try_into().unwrap(); + let sample = PriceSample { timestamp: time, base_fee_per_gas: price, blob_fee: price + 1 }; + samples.push(sample.clone()); + provider.add_price_info(block_num, sample).unwrap(); + } + (provider, samples) +} + +#[test] +fn gas_price_provider_mean_prices() { + let (provider, samples) = make_provider(); + let lag = provider.config.lag_margin_seconds; + let num_samples: u128 = provider.config.number_of_blocks_for_mean.into(); + // Timestamp for sample[3] is used to define the interval of samples 1 to 3. + let final_timestamp = samples[3].timestamp; + + // This calculation will grab config.number_of_blocks_for_mean samples from the middle of the + // range. + let PriceInfo { base_fee_per_gas: gas_price, blob_fee: data_gas_price } = + provider.get_price_info(BlockTimestamp(final_timestamp + lag)).unwrap(); + + // The gas prices should go from block 1 to 3. + let gas_price_calculation = + (samples[1].base_fee_per_gas + samples[2].base_fee_per_gas + samples[3].base_fee_per_gas) + / num_samples; + let data_price_calculation = + (samples[1].blob_fee + samples[2].blob_fee + samples[3].blob_fee) / num_samples; + assert_eq!(gas_price, gas_price_calculation); + assert_eq!(data_gas_price, data_price_calculation); +} + +#[test] +fn gas_price_provider_adding_samples() { + let (mut provider, samples) = make_provider(); + let lag = provider.config.lag_margin_seconds; + // Timestamp for sample[3] is used to define the interval of samples 1 to 3. + let final_timestamp = samples[3].timestamp; + + let PriceInfo { base_fee_per_gas: gas_price, blob_fee: data_gas_price } = + provider.get_price_info(BlockTimestamp(final_timestamp + lag)).unwrap(); + + // Add a block to the provider. + let sample = PriceSample { timestamp: 10, base_fee_per_gas: 10, blob_fee: 11 }; + provider.add_price_info(5, sample).unwrap(); + + let PriceInfo { base_fee_per_gas: gas_price_new, blob_fee: data_gas_price_new } = + provider.get_price_info(BlockTimestamp(final_timestamp + lag)).unwrap(); + + // This should not change the results if we ask for the same timestamp. + assert_eq!(gas_price, gas_price_new); + assert_eq!(data_gas_price, data_gas_price_new); + + // Add another block to the provider. + let sample = PriceSample { timestamp: 12, base_fee_per_gas: 12, blob_fee: 13 }; + provider.add_price_info(6, sample).unwrap(); + + // Should fail because the memory of the provider is full, and we added another block. + let ret = provider.get_price_info(BlockTimestamp(final_timestamp + lag)); + matches!(ret, Result::Err(L1GasPriceProviderError::MissingDataError { .. })); +} + +#[test] +fn gas_price_provider_timestamp_changes_mean() { + let (provider, samples) = make_provider(); + let lag = provider.config.lag_margin_seconds; + // Timestamp for sample[3] is used to define the interval of samples 1 to 3. + let final_timestamp = samples[3].timestamp; + + let PriceInfo { base_fee_per_gas: gas_price, blob_fee: data_gas_price } = + provider.get_price_info(BlockTimestamp(final_timestamp + lag)).unwrap(); + + // If we take a higher timestamp the gas prices should change. + let PriceInfo { base_fee_per_gas: gas_price_new, blob_fee: data_gas_price_new } = + provider.get_price_info(BlockTimestamp(final_timestamp + lag * 2)).unwrap(); + assert_ne!(gas_price_new, gas_price); + assert_ne!(data_gas_price_new, data_gas_price); +} + +#[test] +fn gas_price_provider_can_start_at_nonzero_height() { + let mut provider = L1GasPriceProvider::new(L1GasPriceProviderConfig { + number_of_blocks_for_mean: 3, + ..Default::default() + }); + let sample = PriceSample { timestamp: 0, base_fee_per_gas: 0, blob_fee: 0 }; + provider.add_price_info(42, sample.clone()).unwrap(); +} diff --git a/crates/starknet_l1_gas_price/src/l1_gas_price_scraper.rs b/crates/starknet_l1_gas_price/src/l1_gas_price_scraper.rs new file mode 100644 index 00000000000..584af295ea5 --- /dev/null +++ b/crates/starknet_l1_gas_price/src/l1_gas_price_scraper.rs @@ -0,0 +1,182 @@ +use std::any::type_name; +use std::collections::BTreeMap; +use std::sync::Arc; +use std::time::Duration; + +use async_trait::async_trait; +use papyrus_base_layer::{BaseLayerContract, L1BlockNumber}; +use papyrus_config::converters::deserialize_float_seconds_to_duration; +use papyrus_config::dumping::{ser_optional_param, ser_param, SerializeConfig}; +use papyrus_config::validators::validate_ascii; +use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; +use serde::{Deserialize, Serialize}; +use starknet_api::core::ChainId; +use starknet_l1_gas_price_types::errors::L1GasPriceClientError; +use starknet_l1_gas_price_types::L1GasPriceProviderClient; +use starknet_sequencer_infra::component_client::ClientError; +use starknet_sequencer_infra::component_definitions::ComponentStarter; +use thiserror::Error; +use tracing::{error, info}; +use validator::Validate; + +#[cfg(test)] +#[path = "l1_gas_price_scraper_test.rs"] +pub mod l1_gas_price_scraper_test; + +type L1GasPriceScraperResult = Result>; +pub type SharedL1GasPriceProvider = Arc; + +#[derive(Error, Debug)] +pub enum L1GasPriceScraperError { + #[error("Base layer error: {0}")] + BaseLayerError(T::Error), + #[error("Could not update gas price provider: {0}")] + GasPriceClientError(L1GasPriceClientError), + // Leaky abstraction, these errors should not propagate here. + #[error(transparent)] + NetworkError(ClientError), +} + +// TODO(guyn): find a way to synchronize the value of number_of_blocks_for_mean +// with the one in L1GasPriceProviderConfig. In the end they should both be loaded +// from VersionedConstants. +#[derive(Clone, Debug, Serialize, Deserialize, Validate, PartialEq)] +pub struct L1GasPriceScraperConfig { + /// This field is ignored by the L1Scraper. + /// Manual override to specify where the scraper should start. + /// If None, the node will start scraping from 2*number_of_blocks_for_mean before the tip of + /// L1. + pub starting_block: Option, + #[validate(custom = "validate_ascii")] + pub chain_id: ChainId, + pub finality: u64, + #[serde(deserialize_with = "deserialize_float_seconds_to_duration")] + pub polling_interval: Duration, + pub number_of_blocks_for_mean: u64, +} + +impl Default for L1GasPriceScraperConfig { + fn default() -> Self { + Self { + starting_block: None, + chain_id: ChainId::Other("0x0".to_string()), + finality: 0, + polling_interval: Duration::from_secs(1), + number_of_blocks_for_mean: 300, + } + } +} + +impl SerializeConfig for L1GasPriceScraperConfig { + fn dump(&self) -> BTreeMap { + let mut config = BTreeMap::from([ + ser_param( + "chain_id", + &self.chain_id, + "The chain to follow. For more details see https://docs.starknet.io/documentation/architecture_and_concepts/Blocks/transactions/#chain-id", + ParamPrivacyInput::Public, + ), + ser_param( + "finality", + &self.finality, + "Number of blocks to wait for finality in L1", + ParamPrivacyInput::Public, + ), + ser_param( + "polling_interval", + &self.polling_interval.as_secs(), + "The duration (seconds) between each scraping attempt of L1", + ParamPrivacyInput::Public, + ), + ser_param( + "number_of_blocks_for_mean", + &self.number_of_blocks_for_mean, + "Number of blocks to use for the mean gas price calculation", + ParamPrivacyInput::Public, + ), + ]); + config.extend(ser_optional_param( + &self.starting_block, + 0, // This value is never used, since #is_none turns it to a None. + "starting_block", + "Starting block to scrape from", + ParamPrivacyInput::Public, + )); + config + } +} + +pub struct L1GasPriceScraper { + pub config: L1GasPriceScraperConfig, + pub base_layer: B, + pub l1_gas_price_provider: SharedL1GasPriceProvider, +} + +impl L1GasPriceScraper { + pub fn new( + config: L1GasPriceScraperConfig, + l1_gas_price_provider: SharedL1GasPriceProvider, + base_layer: B, + ) -> Self { + Self { config, l1_gas_price_provider, base_layer } + } + + /// Run the scraper, starting from the given L1 `block_num`, indefinitely. + async fn run(&mut self, mut block_num: L1BlockNumber) -> L1GasPriceScraperResult<(), B> { + loop { + block_num = self.update_prices(block_num).await?; + tokio::time::sleep(self.config.polling_interval).await; + } + } + + /// Scrape all blocks the provider knows starting from `block_num`. + /// Returns the next `block_num` to be scraped. + async fn update_prices( + &mut self, + mut block_num: L1BlockNumber, + ) -> L1GasPriceScraperResult { + while let Some(sample) = self + .base_layer + .get_price_sample(block_num) + .await + .map_err(L1GasPriceScraperError::BaseLayerError)? + { + self.l1_gas_price_provider + .add_price_info(block_num, sample) + .await + .map_err(L1GasPriceScraperError::GasPriceClientError)?; + + block_num += 1; + } + Ok(block_num) + } +} + +#[async_trait] +impl ComponentStarter for L1GasPriceScraper +where + B::Error: Send, +{ + async fn start(&mut self) { + info!("Starting component {}.", type_name::()); + let start_from = match self.config.starting_block { + Some(block) => block, + None => { + let latest = self + .base_layer + .latest_l1_block_number(self.config.finality) + .await + .expect("Failed to get the latest L1 block number") + .expect("Failed to get the latest L1 block number"); + // If no starting block is provided, the default is to start from + // 2 * number_of_blocks_for_mean before the tip of L1. + // Note that for new chains this subtraction may be negative, + // hence the use of saturating_sub. + latest.saturating_sub(self.config.number_of_blocks_for_mean * 2) + } + }; + self.run(start_from) + .await + .unwrap_or_else(|e| panic!("Failed to start L1Scraper component: {}", e)) + } +} diff --git a/crates/starknet_l1_gas_price/src/l1_gas_price_scraper_test.rs b/crates/starknet_l1_gas_price/src/l1_gas_price_scraper_test.rs new file mode 100644 index 00000000000..7ff622d2bf0 --- /dev/null +++ b/crates/starknet_l1_gas_price/src/l1_gas_price_scraper_test.rs @@ -0,0 +1,126 @@ +use std::sync::Arc; + +use papyrus_base_layer::{MockBaseLayerContract, PriceSample}; +use starknet_l1_gas_price_types::MockL1GasPriceProviderClient; + +use crate::l1_gas_price_scraper::{L1GasPriceScraper, L1GasPriceScraperConfig}; + +const BLOCK_TIME: u64 = 2; +const GAS_PRICE: u128 = 42; +const DATA_PRICE: u128 = 137; + +fn setup_scraper( + end_block: u64, + expected_number_of_blocks: usize, +) -> L1GasPriceScraper { + let mut mock_contract = MockBaseLayerContract::new(); + mock_contract.expect_get_price_sample().returning(move |block_number| { + if block_number >= end_block { + Ok(None) + } else { + Ok(Some(PriceSample { + timestamp: block_number * BLOCK_TIME, + base_fee_per_gas: u128::from(block_number) * GAS_PRICE, + blob_fee: u128::from(block_number) * DATA_PRICE, + })) + } + }); + + let mut mock_provider = MockL1GasPriceProviderClient::new(); + mock_provider + .expect_add_price_info() + .withf(|&block_number, price_sample| { + price_sample.timestamp == block_number * BLOCK_TIME + && price_sample.base_fee_per_gas == u128::from(block_number) * GAS_PRICE + && price_sample.blob_fee == u128::from(block_number) * DATA_PRICE + }) + .times(expected_number_of_blocks) + .returning(|_, _| Ok(())); + + L1GasPriceScraper::new( + L1GasPriceScraperConfig::default(), + Arc::new(mock_provider), + mock_contract, + ) +} + +#[tokio::test] +async fn run_l1_gas_price_scraper_single_block() { + const START_BLOCK: u64 = 0; + const END_BLOCK: u64 = 1; + const EXPECT_NUMBER: usize = 1; + let mut scraper = setup_scraper(END_BLOCK, EXPECT_NUMBER); + scraper.update_prices(START_BLOCK).await.unwrap(); +} + +#[tokio::test] +async fn run_l1_gas_price_scraper_two_blocks() { + const START_BLOCK: u64 = 2; + const END_BLOCK1: u64 = 7; + const END_BLOCK2: u64 = 12; + + // Explicitly making the mocks here, so we can customize them for the test. + let mut mock_contract = MockBaseLayerContract::new(); + // Note the order of the expectation is important! Can only scrape the first blocks first. + mock_contract + .expect_get_price_sample() + .times(usize::try_from(END_BLOCK1 - START_BLOCK + 1).unwrap()) + .returning(move |block_number| { + if block_number >= END_BLOCK1 { + Ok(None) + } else { + Ok(Some(PriceSample { + timestamp: block_number * BLOCK_TIME, + base_fee_per_gas: u128::from(block_number) * GAS_PRICE, + blob_fee: u128::from(block_number) * DATA_PRICE, + })) + } + }); + mock_contract + .expect_get_price_sample() + .times(usize::try_from(END_BLOCK2 - END_BLOCK1 + 1).unwrap()) + .returning(move |block_number| { + if block_number >= END_BLOCK2 { + Ok(None) + } else { + Ok(Some(PriceSample { + timestamp: block_number * BLOCK_TIME, + base_fee_per_gas: u128::from(block_number) * GAS_PRICE, + blob_fee: u128::from(block_number) * DATA_PRICE, + })) + } + }); + + let mut mock_provider = MockL1GasPriceProviderClient::new(); + mock_provider + .expect_add_price_info() + .withf(|&block_number, price_sample| { + price_sample.timestamp == block_number * BLOCK_TIME + && price_sample.base_fee_per_gas == u128::from(block_number) * GAS_PRICE + && price_sample.blob_fee == u128::from(block_number) * DATA_PRICE + }) + .times(usize::try_from(END_BLOCK2 - START_BLOCK).unwrap()) + .returning(|_, _| Ok(())); + + let mut scraper = L1GasPriceScraper::new( + L1GasPriceScraperConfig::default(), + Arc::new(mock_provider), + mock_contract, + ); + + let block_number = scraper.update_prices(START_BLOCK).await.unwrap(); + assert_eq!(block_number, END_BLOCK1); + let block_number = scraper.update_prices(block_number).await.unwrap(); + assert_eq!(block_number, END_BLOCK2); +} + +#[tokio::test] +async fn run_l1_gas_price_scraper_multiple_blocks() { + const START_BLOCK: u64 = 5; + const END_BLOCK: u64 = 10; + const EXPECT_NUMBER: usize = 5; + let mut scraper = setup_scraper(END_BLOCK, EXPECT_NUMBER); + + // Should update prices from 5 to 10 (not inclusive) and on 10 get a None from base layer. + scraper.update_prices(START_BLOCK).await.unwrap(); +} diff --git a/crates/starknet_l1_gas_price/src/lib.rs b/crates/starknet_l1_gas_price/src/lib.rs new file mode 100644 index 00000000000..ab0fdfb6c51 --- /dev/null +++ b/crates/starknet_l1_gas_price/src/lib.rs @@ -0,0 +1,4 @@ +pub mod communication; +pub mod eth_to_strk_oracle; +pub mod l1_gas_price_provider; +pub mod l1_gas_price_scraper; diff --git a/crates/starknet_l1_gas_price_types/Cargo.toml b/crates/starknet_l1_gas_price_types/Cargo.toml new file mode 100644 index 00000000000..3dbbbc5a4a8 --- /dev/null +++ b/crates/starknet_l1_gas_price_types/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "starknet_l1_gas_price_types" +version.workspace = true +edition.workspace = true +repository.workspace = true +license.workspace = true + +[dependencies] +async-trait.workspace = true +mockall.workspace = true +papyrus_base_layer.workspace = true +papyrus_proc_macros.workspace = true +reqwest.workspace = true +serde.workspace = true +serde_json.workspace = true +starknet_api.workspace = true +starknet_sequencer_infra.workspace = true +strum_macros.workspace = true +thiserror.workspace = true +tracing.workspace = true + +[dev-dependencies] +mockall.workspace = true +papyrus_base_layer = { workspace = true, features = ["testing"] } + +[lints] +workspace = true + +[features] +testing = [] diff --git a/crates/starknet_l1_gas_price_types/src/errors.rs b/crates/starknet_l1_gas_price_types/src/errors.rs new file mode 100644 index 00000000000..ee87f23827e --- /dev/null +++ b/crates/starknet_l1_gas_price_types/src/errors.rs @@ -0,0 +1,33 @@ +use serde::{Deserialize, Serialize}; +use starknet_sequencer_infra::component_client::ClientError; +use thiserror::Error; + +#[derive(Clone, Debug, Error, PartialEq, Eq, Serialize, Deserialize)] +pub enum L1GasPriceProviderError { + #[error("Block height is not consecutive: expected {expected}, got {found}")] + UnexpectedHeightError { expected: u64, found: u64 }, + #[error("No price data saved for blocks starting at {timestamp} - {lag} seconds")] + MissingDataError { timestamp: u64, lag: u64 }, + #[error("Insufficient block price history: expected at least {expected}, found only {found}")] + InsufficientHistoryError { expected: usize, found: usize }, +} + +#[derive(Clone, Debug, Error)] +pub enum L1GasPriceClientError { + #[error(transparent)] + ClientError(#[from] ClientError), + #[error(transparent)] + L1GasPriceProviderError(#[from] L1GasPriceProviderError), +} + +#[derive(Debug, Error)] +pub enum EthToStrkOracleClientError { + #[error(transparent)] + RequestError(#[from] reqwest::Error), + #[error(transparent)] + ParseError(#[from] serde_json::Error), + #[error("Missing or invalid field: {0}")] + MissingFieldError(&'static str), + #[error("Invalid decimals value: expected {0}, got {1}")] + InvalidDecimalsError(u64, u64), +} diff --git a/crates/starknet_l1_gas_price_types/src/lib.rs b/crates/starknet_l1_gas_price_types/src/lib.rs new file mode 100644 index 00000000000..72ce0195f85 --- /dev/null +++ b/crates/starknet_l1_gas_price_types/src/lib.rs @@ -0,0 +1,101 @@ +pub mod errors; + +use std::sync::Arc; + +use async_trait::async_trait; +use errors::{EthToStrkOracleClientError, L1GasPriceClientError, L1GasPriceProviderError}; +#[cfg(any(feature = "testing", test))] +use mockall::automock; +use papyrus_base_layer::{L1BlockNumber, PriceSample}; +use papyrus_proc_macros::handle_all_response_variants; +use serde::{Deserialize, Serialize}; +use starknet_api::block::BlockTimestamp; +use starknet_sequencer_infra::component_client::ClientError; +use starknet_sequencer_infra::component_definitions::ComponentClient; +use starknet_sequencer_infra::impl_debug_for_infra_requests_and_responses; +use strum_macros::AsRefStr; +use tracing::instrument; + +pub type SharedL1GasPriceClient = Arc; +pub type L1GasPriceProviderResult = Result; +pub type L1GasPriceProviderClientResult = Result; + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct PriceInfo { + pub base_fee_per_gas: u128, + pub blob_fee: u128, +} + +#[derive(Clone, Serialize, Deserialize, AsRefStr)] +pub enum L1GasPriceRequest { + GetGasPrice(BlockTimestamp), + AddGasPrice(L1BlockNumber, PriceSample), +} +impl_debug_for_infra_requests_and_responses!(L1GasPriceRequest); + +#[derive(Clone, Serialize, Deserialize, AsRefStr)] +pub enum L1GasPriceResponse { + GetGasPrice(L1GasPriceProviderResult), + AddGasPrice(L1GasPriceProviderResult<()>), +} +impl_debug_for_infra_requests_and_responses!(L1GasPriceResponse); + +/// Serves as the provider's shared interface. Requires `Send + Sync` to allow transferring and +/// sharing resources (inputs, futures) across threads. +#[cfg_attr(any(feature = "testing", test), automock)] +#[async_trait] +pub trait L1GasPriceProviderClient: Send + Sync { + async fn add_price_info( + &self, + height: L1BlockNumber, + sample: PriceSample, + ) -> L1GasPriceProviderClientResult<()>; + + async fn get_price_info( + &self, + timestamp: BlockTimestamp, + ) -> L1GasPriceProviderClientResult; +} + +#[cfg_attr(any(feature = "testing", test), automock)] +#[async_trait] +pub trait EthToStrkOracleClientTrait: Send + Sync { + /// Fetches the eth to fri rate for a given timestamp. + async fn eth_to_fri_rate(&self, timestamp: u64) -> Result; +} + +#[async_trait] +impl L1GasPriceProviderClient for ComponentClientType +where + ComponentClientType: Send + Sync + ComponentClient, +{ + #[instrument(skip(self))] + async fn add_price_info( + &self, + height: L1BlockNumber, + sample: PriceSample, + ) -> L1GasPriceProviderClientResult<()> { + let request = L1GasPriceRequest::AddGasPrice(height, sample); + handle_all_response_variants!( + L1GasPriceResponse, + AddGasPrice, + L1GasPriceClientError, + L1GasPriceProviderError, + Direct + ) + } + #[instrument(skip(self))] + async fn get_price_info( + &self, + timestamp: BlockTimestamp, + ) -> L1GasPriceProviderClientResult { + let request = L1GasPriceRequest::GetGasPrice(timestamp); + handle_all_response_variants!( + L1GasPriceResponse, + GetGasPrice, + L1GasPriceClientError, + L1GasPriceProviderError, + Direct + ) + } +} diff --git a/crates/starknet_l1_provider/Cargo.toml b/crates/starknet_l1_provider/Cargo.toml index be12f4533d6..662b474f435 100644 --- a/crates/starknet_l1_provider/Cargo.toml +++ b/crates/starknet_l1_provider/Cargo.toml @@ -5,16 +5,38 @@ edition.workspace = true repository.workspace = true license.workspace = true +[features] +testing = ["itertools", "pretty_assertions", "starknet_api/testing"] + [dependencies] +async-trait.workspace = true +hex.workspace = true indexmap.workspace = true +itertools = { workspace = true, optional = true } papyrus_base_layer.workspace = true +papyrus_config.workspace = true +pretty_assertions = { workspace = true, optional = true } +serde.workspace = true starknet_api.workspace = true +starknet_l1_provider_types.workspace = true +starknet_sequencer_infra.workspace = true +starknet_state_sync_types.workspace = true thiserror.workspace = true +tokio.workspace = true +tracing.workspace = true +validator.workspace = true [dev-dependencies] +alloy.workspace = true assert_matches.workspace = true +itertools.workspace = true +mempool_test_utils.workspace = true +papyrus_base_layer = { workspace = true, features = ["testing"] } pretty_assertions.workspace = true +starknet-types-core.workspace = true starknet_api = { workspace = true, features = ["testing"] } +starknet_l1_provider_types = { workspace = true, features = ["testing"] } +starknet_state_sync_types = { workspace = true, features = ["testing"] } [lints] workspace = true diff --git a/crates/starknet_l1_provider/src/bootstrapper.rs b/crates/starknet_l1_provider/src/bootstrapper.rs new file mode 100644 index 00000000000..d05783177c4 --- /dev/null +++ b/crates/starknet_l1_provider/src/bootstrapper.rs @@ -0,0 +1,168 @@ +use std::sync::Arc; +use std::time::Duration; + +use starknet_api::block::BlockNumber; +use starknet_api::transaction::TransactionHash; +use starknet_l1_provider_types::SharedL1ProviderClient; +use starknet_state_sync_types::communication::SharedStateSyncClient; +use tokio::sync::OnceCell; +use tracing::{debug, info}; + +pub type LazyCatchUpHeight = Arc>; + +/// Cache's commits to be applied later. This flow is only relevant while the node is starting up. +#[derive(Clone)] +pub struct Bootstrapper { + /// The catch-up height for the bootstrapper is the sync height (unless overridden explicitly). + /// This value, due to infra constraints as of now, is only fetchable _after_ the provider is + /// running, and not during its initialization, hence we are forced to lazily fetch it at + /// runtime. + pub catch_up_height: LazyCatchUpHeight, + pub sync_retry_interval: Duration, + pub commit_block_backlog: Vec, + pub l1_provider_client: SharedL1ProviderClient, + pub sync_client: SharedStateSyncClient, + // Keep track of sync task for health checks and logging status. + pub sync_task_handle: SyncTaskHandle, +} + +impl Bootstrapper { + pub fn new( + l1_provider_client: SharedL1ProviderClient, + sync_client: SharedStateSyncClient, + sync_retry_interval: Duration, + catch_up_height: LazyCatchUpHeight, + ) -> Self { + Self { + sync_retry_interval, + commit_block_backlog: Default::default(), + l1_provider_client, + sync_client, + sync_task_handle: SyncTaskHandle::NotStartedYet, + catch_up_height, + } + } + + /// Check if the caller has caught up with the bootstrapper. + /// If catch_up_height is unset, the sync isn't even ready yet. + pub fn is_caught_up(&self, current_provider_height: BlockNumber) -> bool { + self.catch_up_height() + .is_some_and(|catch_up_height| current_provider_height > catch_up_height) + // TODO(Gilad): add health_check here, making sure that the sync task isn't stuck, which is + // `handle dropped && backlog empty && not caught up`. + } + + pub fn add_commit_block_to_backlog( + &mut self, + committed_txs: &[TransactionHash], + height: BlockNumber, + ) { + assert!( + self.commit_block_backlog + .last() + .is_none_or(|commit_block| commit_block.height.unchecked_next() == height), + "Heights should be sequential." + ); + + self.commit_block_backlog + .push(CommitBlockBacklog { height, committed_txs: committed_txs.to_vec() }); + } + + /// Spawns async task that produces and sends commit block messages to the provider, according + /// to information from the sync client, until the provider is caught up. + pub async fn start_l2_sync(&mut self, current_provider_height: BlockNumber) { + // FIXME: spawning a task like this is evil. + // However, we aren't using the task executor, so no choice :( + // Once we start using a centralized threadpool, spawn through it instead of the + // tokio runtime. + let sync_task_handle = tokio::spawn(l2_sync_task( + self.l1_provider_client.clone(), + self.sync_client.clone(), + current_provider_height, + self.catch_up_height.clone(), + self.sync_retry_interval, + )); + + self.sync_task_handle = SyncTaskHandle::Started(sync_task_handle.into()); + } + + pub fn catch_up_height(&self) -> Option { + self.catch_up_height.get().copied() + } +} + +impl PartialEq for Bootstrapper { + fn eq(&self, other: &Self) -> bool { + self.catch_up_height == other.catch_up_height + && self.commit_block_backlog == other.commit_block_backlog + } +} + +impl Eq for Bootstrapper {} + +impl std::fmt::Debug for Bootstrapper { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Bootstrapper") + .field("catch_up_height", &self.catch_up_height) + .field("commit_block_backlog", &self.commit_block_backlog) + .field("sync_task_handle", &self.sync_task_handle) + .finish_non_exhaustive() + } +} + +async fn l2_sync_task( + l1_provider_client: SharedL1ProviderClient, + sync_client: SharedStateSyncClient, + mut current_height: BlockNumber, + catch_up_height: LazyCatchUpHeight, + retry_interval: Duration, +) { + // Currently infra doesn't support starting up the provider only after sync is ready. + while !catch_up_height.initialized() { + info!("Try fetching sync height to initialize catch up point"); + let Some(sync_height) = sync_client + .get_latest_block_number() + .await + .expect("network error handling not supported yet") + else { + debug!("Sync state not ready yet, trying again later"); + tokio::time::sleep(retry_interval).await; + continue; + }; + info!("Catch up height set: {sync_height}"); + catch_up_height.set(sync_height).expect("This is the only write-point, cannot fail") + } + let catch_up_height = *catch_up_height.get().expect("Initialized above"); + + while current_height <= catch_up_height { + // TODO(Gilad): add tracing instrument. + debug!("Try syncing L1Provider with L2 height: {}", current_height); + let block = sync_client.get_block(current_height).await.inspect_err(|err| debug!("{err}")); + + match block { + Ok(Some(block)) => { + // FIXME: block.transaction_hashes should be `block.l1_transaction_hashes`! + l1_provider_client + .commit_block(block.transaction_hashes, current_height) + .await + .unwrap(); + current_height = current_height.unchecked_next(); + } + _ => tokio::time::sleep(retry_interval).await, + } + } +} + +#[derive(Clone, Debug, Default, Eq, PartialEq)] +pub struct CommitBlockBacklog { + pub height: BlockNumber, + pub committed_txs: Vec, +} + +#[derive(Clone, Debug, Default)] +pub enum SyncTaskHandle { + #[default] + NotStartedYet, + // Adding `Arc` to make this clonable and since this handle isn't modified. + Started(Arc>), +} diff --git a/crates/starknet_l1_provider/src/communication.rs b/crates/starknet_l1_provider/src/communication.rs new file mode 100644 index 00000000000..8f6fe6c978c --- /dev/null +++ b/crates/starknet_l1_provider/src/communication.rs @@ -0,0 +1,53 @@ +use async_trait::async_trait; +use starknet_l1_provider_types::{L1ProviderRequest, L1ProviderResponse}; +use starknet_sequencer_infra::component_client::{LocalComponentClient, RemoteComponentClient}; +use starknet_sequencer_infra::component_definitions::{ + ComponentRequestAndResponseSender, + ComponentRequestHandler, +}; +use starknet_sequencer_infra::component_server::{ + LocalComponentServer, + RemoteComponentServer, + WrapperServer, +}; +use tracing::instrument; + +pub type LocalL1ProviderServer = + LocalComponentServer; +pub type RemoteL1ProviderServer = RemoteComponentServer; +pub type L1ProviderRequestAndResponseSender = + ComponentRequestAndResponseSender; +pub type LocalL1ProviderClient = LocalComponentClient; +pub type RemoteL1ProviderClient = RemoteComponentClient; + +use crate::l1_provider::L1Provider; +use crate::l1_scraper::L1Scraper; + +pub type L1ScraperServer = WrapperServer>; + +#[async_trait] +impl ComponentRequestHandler for L1Provider { + #[instrument(skip(self))] + async fn handle_request(&mut self, request: L1ProviderRequest) -> L1ProviderResponse { + match request { + L1ProviderRequest::AddEvents(events) => { + L1ProviderResponse::AddEvents(self.process_l1_events(events)) + } + L1ProviderRequest::CommitBlock { l1_handler_tx_hashes, height } => { + L1ProviderResponse::CommitBlock(self.commit_block(&l1_handler_tx_hashes, height)) + } + L1ProviderRequest::GetTransactions { n_txs, height } => { + L1ProviderResponse::GetTransactions(self.get_txs(n_txs, height)) + } + L1ProviderRequest::StartBlock { state, height } => { + L1ProviderResponse::StartBlock(self.start_block(height, state)) + } + L1ProviderRequest::Validate { tx_hash, height } => { + L1ProviderResponse::Validate(self.validate(tx_hash, height)) + } + L1ProviderRequest::Initialize(events) => { + L1ProviderResponse::Initialize(self.initialize(events).await) + } + } + } +} diff --git a/crates/starknet_l1_provider/src/errors.rs b/crates/starknet_l1_provider/src/errors.rs deleted file mode 100644 index ff99524eaa2..00000000000 --- a/crates/starknet_l1_provider/src/errors.rs +++ /dev/null @@ -1,24 +0,0 @@ -use papyrus_base_layer::ethereum_base_layer_contract::EthereumBaseLayerError; -use thiserror::Error; - -use crate::ProviderState; - -#[derive(Error, Debug)] -pub enum L1ProviderError { - #[error(transparent)] - BaseLayer(#[from] EthereumBaseLayerError), - #[error( - "`get_txs` called while in `Pending` state, likely due to a crash; restart block proposal" - )] - GetTransactionsInPendingState, - #[error("`get_txs` while in validate state")] - GetTransactionConsensusBug, - #[error("Cannot transition from {from} to {to}")] - UnexpectedProviderStateTransition { from: ProviderState, to: ProviderState }, - #[error( - "`validate` called while in `Pending` state, likely due to a crash; restart block proposal" - )] - ValidateInPendingState, - #[error("`validate` called while in `Propose`")] - ValidateTransactionConsensusBug, -} diff --git a/crates/starknet_l1_provider/src/l1_provider.rs b/crates/starknet_l1_provider/src/l1_provider.rs new file mode 100644 index 00000000000..078a2557fb2 --- /dev/null +++ b/crates/starknet_l1_provider/src/l1_provider.rs @@ -0,0 +1,270 @@ +use std::cmp::Ordering::{Equal, Greater, Less}; +use std::sync::Arc; + +use starknet_api::block::BlockNumber; +use starknet_api::executable_transaction::L1HandlerTransaction; +use starknet_api::transaction::TransactionHash; +use starknet_l1_provider_types::errors::L1ProviderError; +use starknet_l1_provider_types::{ + Event, + L1ProviderResult, + SessionState, + SharedL1ProviderClient, + ValidationStatus, +}; +use starknet_sequencer_infra::component_definitions::ComponentStarter; +use starknet_state_sync_types::communication::SharedStateSyncClient; +use tracing::{debug, info, instrument, trace, warn}; + +use crate::bootstrapper::Bootstrapper; +use crate::transaction_manager::TransactionManager; +use crate::{L1ProviderConfig, ProviderState}; + +#[cfg(test)] +#[path = "l1_provider_tests.rs"] +pub mod l1_provider_tests; + +// TODO(Gilad): optimistic proposer support, will add later to keep things simple, but the design +// here is compatible with it. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct L1Provider { + /// Represents the L2 block height being built. + pub current_height: BlockNumber, + pub tx_manager: TransactionManager, + // TODO(Gilad): consider transitioning to a generic phantom state once the infra is stabilized + // and we see how well it handles consuming the L1Provider when moving between states. + pub state: ProviderState, +} + +impl L1Provider { + #[instrument(skip(self), err)] + pub fn start_block( + &mut self, + height: BlockNumber, + state: SessionState, + ) -> L1ProviderResult<()> { + self.validate_height(height)?; + self.state = state.into(); + self.tx_manager.start_block(); + Ok(()) + } + + pub async fn initialize(&mut self, events: Vec) -> L1ProviderResult<()> { + self.process_l1_events(events)?; + let ProviderState::Bootstrap(bootstrapper) = &mut self.state else { + panic!("Unexpected state {} while attempting to bootstrap", self.state) + }; + bootstrapper.start_l2_sync(self.current_height).await; + + Ok(()) + } + + /// Retrieves up to `n_txs` transactions that have yet to be proposed or accepted on L2. + #[instrument(skip(self), err)] + pub fn get_txs( + &mut self, + n_txs: usize, + height: BlockNumber, + ) -> L1ProviderResult> { + self.validate_height(height)?; + + match self.state { + ProviderState::Propose => { + let txs = self.tx_manager.get_txs(n_txs); + info!( + "Returned {} out of {} transactions, ready for sequencing.", + txs.len(), + n_txs + ); + debug!( + "Returned L1Handler txs: {:#?}", + txs.iter().map(|tx| tx.tx_hash).collect::>() + ); + Ok(txs) + } + ProviderState::Pending | ProviderState::Bootstrap(_) => { + Err(L1ProviderError::OutOfSessionGetTransactions) + } + ProviderState::Validate => Err(L1ProviderError::GetTransactionConsensusBug), + } + } + + /// Returns true if and only if the given transaction is both not included in an L2 block, and + /// unconsumed on L1. + #[instrument(skip(self), err)] + pub fn validate( + &mut self, + tx_hash: TransactionHash, + height: BlockNumber, + ) -> L1ProviderResult { + self.validate_height(height)?; + match self.state { + ProviderState::Validate => Ok(self.tx_manager.validate_tx(tx_hash)), + ProviderState::Propose => Err(L1ProviderError::ValidateTransactionConsensusBug), + ProviderState::Pending | ProviderState::Bootstrap(_) => { + Err(L1ProviderError::OutOfSessionValidate) + } + } + } + + // TODO(Gilad): when deciding on consensus, if possible, have commit_block also tell the node if + // it's about to [optimistically-]propose or validate the next block. + #[instrument(skip(self), err)] + pub fn commit_block( + &mut self, + committed_txs: &[TransactionHash], + height: BlockNumber, + ) -> L1ProviderResult<()> { + if self.state.is_bootstrapping() { + // Once bootstrap completes it will transition to Pending state by itself. + return self.bootstrap(committed_txs, height); + } + + self.validate_height(height)?; + self.apply_commit_block(committed_txs); + + self.state = self.state.transition_to_pending(); + Ok(()) + } + + /// Try to apply commit_block backlog, and if all caught up, drop bootstrapping state. + fn bootstrap( + &mut self, + committed_txs: &[TransactionHash], + new_height: BlockNumber, + ) -> L1ProviderResult<()> { + let current_height = self.current_height; + match new_height.cmp(¤t_height) { + // This is likely a bug in the batcher/sync, it should never be _behind_ the provider. + Less => Err(L1ProviderError::UnexpectedHeight { + expected_height: current_height, + got: new_height, + })?, + Equal => self.apply_commit_block(committed_txs), + // We're still syncing, backlog it, it'll get applied later. + Greater => { + self.state + .get_bootstrapper() + .expect("This method should only be called when bootstrapping.") + .add_commit_block_to_backlog(committed_txs, new_height); + // No need to check the backlog or bootstrap completion, since those are only + // applicable if we just increased the provider's height, like in the `Equal` case. + return Ok(()); + } + }; + + let bootstrapper = self + .state + .get_bootstrapper() + .expect("This method should only be called when bootstrapping."); + + // If caught up, apply the backlog, drop the Bootstrapper and transition to Pending. + if bootstrapper.is_caught_up(self.current_height) { + let backlog = std::mem::take(&mut bootstrapper.commit_block_backlog); + assert!( + backlog.is_empty() + || self.current_height == backlog.first().unwrap().height + && backlog + .windows(2) + .all(|height| height[1].height == height[0].height.unchecked_next()), + "Backlog must have sequential heights starting sequentially after current height: \ + {}, backlog: {:?}", + self.current_height, + backlog.iter().map(|commit_block| commit_block.height).collect::>() + ); + for commit_block in backlog { + self.apply_commit_block(&commit_block.committed_txs); + } + + // Drops bootstrapper and all of its assets. + self.state = ProviderState::Pending; + } + + Ok(()) + } + + #[instrument(skip_all, err)] + pub fn process_l1_events(&mut self, events: Vec) -> L1ProviderResult<()> { + trace!(?events); + + for event in events { + match event { + Event::L1HandlerTransaction(l1_handler_tx) => { + // TODO(Gilad): can we ignore this silently? + let _is_known_or_committed = self.tx_manager.add_tx(l1_handler_tx); + } + _ => todo!(), + } + } + Ok(()) + } + + fn validate_height(&mut self, height: BlockNumber) -> L1ProviderResult<()> { + if height != self.current_height { + return Err(L1ProviderError::UnexpectedHeight { + expected_height: self.current_height, + got: height, + }); + } + Ok(()) + } + + fn apply_commit_block(&mut self, committed_txs: &[TransactionHash]) { + self.tx_manager.commit_txs(committed_txs); + self.current_height = self.current_height.unchecked_next(); + } +} + +impl ComponentStarter for L1Provider {} + +/// Initializes L1Provider at specified height (≤ scraper's last state update height). +/// Bootstrap catch-up height defaults to current sync height. +#[instrument(skip(l1_provider_client, sync_client, config))] +pub fn create_l1_provider( + config: L1ProviderConfig, + l1_provider_client: SharedL1ProviderClient, + sync_client: SharedStateSyncClient, + scraper_synced_startup_height: BlockNumber, +) -> L1Provider { + let l1_provider_startup_height = config + .provider_startup_height_override + .inspect(|&startup_height_override| { + assert!( + startup_height_override <= scraper_synced_startup_height, + "L2 Reorgs possible: during startup, the l1 provider height should not exceed the \ + scraper's last known LogStateUpdate (scraper_synced_startup_height) since at \ + startup it has no way of checking if a given l1 handler has already been \ + committed" + ); + warn!( + "Initializing L1Provider with overridden startup height: {startup_height_override}" + ); + }) + .unwrap_or(scraper_synced_startup_height); + + let catch_up_height = config + .bootstrap_catch_up_height_override + .map(|catch_up_height_override| { + warn!( + "Initializing L1Provider with OVERRIDDEN catch-up height: \ + {catch_up_height_override}, this MUST be greater or equal to the default \ + non-overridden value, which is the current sync height, or the sync will never \ + complete!" + ); + Arc::new(catch_up_height_override.into()) + }) + .unwrap_or_default(); + + let bootstrapper = Bootstrapper::new( + l1_provider_client, + sync_client, + config.startup_sync_sleep_retry_interval, + catch_up_height, + ); + + L1Provider { + current_height: l1_provider_startup_height, + tx_manager: TransactionManager::default(), + state: ProviderState::Bootstrap(bootstrapper), + } +} diff --git a/crates/starknet_l1_provider/src/l1_provider_tests.rs b/crates/starknet_l1_provider/src/l1_provider_tests.rs index 09bf6ce5694..63c62c0453d 100644 --- a/crates/starknet_l1_provider/src/l1_provider_tests.rs +++ b/crates/starknet_l1_provider/src/l1_provider_tests.rs @@ -1,114 +1,312 @@ +use std::sync::Arc; +use std::time::Duration; + use assert_matches::assert_matches; +use itertools::Itertools; use pretty_assertions::assert_eq; -use starknet_api::hash::StarkHash; -use starknet_api::l1_handler_tx_args; -use starknet_api::test_utils::l1_handler::executable_l1_handler_tx; +use starknet_api::block::BlockNumber; +use starknet_api::test_utils::l1_handler::{executable_l1_handler_tx, L1HandlerTxArgs}; use starknet_api::transaction::TransactionHash; +use starknet_api::tx_hash; +use starknet_l1_provider_types::errors::L1ProviderError; +use starknet_l1_provider_types::SessionState::{ + self, + Propose as ProposeSession, + Validate as ValidateSession, +}; +use starknet_l1_provider_types::{Event, InvalidValidationStatus, ValidationStatus}; +use starknet_state_sync_types::communication::MockStateSyncClient; + +use crate::bootstrapper::{Bootstrapper, CommitBlockBacklog, SyncTaskHandle}; +use crate::test_utils::{l1_handler, FakeL1ProviderClient, L1ProviderContentBuilder}; +use crate::ProviderState; -use crate::errors::L1ProviderError; -use crate::test_utils::L1ProviderContentBuilder; -use crate::ProviderState::{Propose, Validate}; -use crate::{L1Provider, ValidationStatus}; - -macro_rules! tx { - (tx_hash: $tx_hash:expr) => {{ - executable_l1_handler_tx( - l1_handler_tx_args!( - tx_hash: TransactionHash(StarkHash::from($tx_hash)) , ..Default::default() - ) - ) +macro_rules! bootstrapper { + (backlog: [$($height:literal => [$($tx:literal),* $(,)*]),* $(,)*], catch_up: $catch:expr) => {{ + Bootstrapper { + commit_block_backlog: vec![ + $(CommitBlockBacklog { + height: BlockNumber($height), + committed_txs: vec![$(tx_hash!($tx)),*] + }),* + ].into_iter().collect(), + catch_up_height: Arc::new(BlockNumber($catch).into()), + l1_provider_client: Arc::new(FakeL1ProviderClient::default()), + sync_client: Arc::new(MockStateSyncClient::default()), + sync_task_handle: SyncTaskHandle::default(), + sync_retry_interval: Duration::from_millis(10) + } }}; } -macro_rules! tx_hash { - ($tx_hash:expr) => { - TransactionHash(StarkHash::from($tx_hash)) - }; +fn l1_handler_event(tx_hash: TransactionHash) -> Event { + Event::L1HandlerTransaction(executable_l1_handler_tx(L1HandlerTxArgs { + tx_hash, + ..Default::default() + })) } #[test] fn get_txs_happy_flow() { // Setup. - let txs = [tx!(tx_hash: 0), tx!(tx_hash: 1), tx!(tx_hash: 2)]; + let txs = [l1_handler(0), l1_handler(1), l1_handler(2)]; let mut l1_provider = L1ProviderContentBuilder::new() .with_txs(txs.clone()) - .with_state(Propose) + .with_state(ProviderState::Propose) .build_into_l1_provider(); // Test. - assert_eq!(l1_provider.get_txs(0).unwrap(), []); - assert_eq!(l1_provider.get_txs(1).unwrap(), [txs[0].clone()]); - assert_eq!(l1_provider.get_txs(3).unwrap(), txs[1..=2]); - assert_eq!(l1_provider.get_txs(1).unwrap(), []); + assert_eq!(l1_provider.get_txs(0, BlockNumber(0)).unwrap(), []); + assert_eq!(l1_provider.get_txs(1, BlockNumber(0)).unwrap(), [txs[0].clone()]); + assert_eq!(l1_provider.get_txs(3, BlockNumber(0)).unwrap(), txs[1..=2]); + assert_eq!(l1_provider.get_txs(1, BlockNumber(0)).unwrap(), []); } #[test] fn validate_happy_flow() { // Setup. - let l1_provider = L1ProviderContentBuilder::new() - .with_txs([tx!(tx_hash: 1)]) - .with_on_l2_awaiting_l1_consumption([tx_hash!(2)]) - .with_state(Validate) + let mut l1_provider = L1ProviderContentBuilder::new() + .with_txs([l1_handler(1)]) + .with_committed([tx_hash!(2)]) + .with_state(ProviderState::Validate) .build_into_l1_provider(); // Test. - assert_eq!(l1_provider.validate(tx_hash!(1)).unwrap(), ValidationStatus::Validated); - assert_eq!(l1_provider.validate(tx_hash!(2)).unwrap(), ValidationStatus::AlreadyIncludedOnL2); - assert_eq!(l1_provider.validate(tx_hash!(3)).unwrap(), ValidationStatus::ConsumedOnL1OrUnknown); + assert_eq!( + l1_provider.validate(tx_hash!(1), BlockNumber(0)).unwrap(), + ValidationStatus::Validated + ); + assert_eq!( + l1_provider.validate(tx_hash!(2), BlockNumber(0)).unwrap(), + ValidationStatus::Invalid(InvalidValidationStatus::AlreadyIncludedOnL2) + ); + assert_eq!( + l1_provider.validate(tx_hash!(3), BlockNumber(0)).unwrap(), + ValidationStatus::Invalid(InvalidValidationStatus::ConsumedOnL1OrUnknown) + ); // Transaction wasn't deleted after the validation. - assert_eq!(l1_provider.validate(tx_hash!(1)).unwrap(), ValidationStatus::Validated); + assert_eq!( + l1_provider.validate(tx_hash!(1), BlockNumber(0)).unwrap(), + ValidationStatus::Invalid(InvalidValidationStatus::AlreadyIncludedInProposedBlock) + ); +} + +#[test] +fn process_events_happy_flow() { + // Setup. + for state in [ProviderState::Propose, ProviderState::Validate, ProviderState::Pending] { + let mut l1_provider = L1ProviderContentBuilder::new() + .with_txs([l1_handler(1)]) + .with_committed(vec![]) + .with_state(state.clone()) + .build_into_l1_provider(); + + // Test. + l1_provider + .process_l1_events(vec![l1_handler_event(tx_hash!(4)), l1_handler_event(tx_hash!(3))]) + .unwrap(); + l1_provider.process_l1_events(vec![l1_handler_event(tx_hash!(6))]).unwrap(); + + let expected_l1_provider = L1ProviderContentBuilder::new() + .with_txs([ + l1_handler(1), + l1_handler(4), + l1_handler(3), + l1_handler(6), + ]) + .with_committed(vec![]) + // State should be unchanged. + .with_state(state) + .build(); + + expected_l1_provider.assert_eq(&l1_provider); + } +} + +#[test] +fn process_events_committed_txs() { + // Setup. + let mut l1_provider = L1ProviderContentBuilder::new() + .with_txs([l1_handler(1)]) + .with_committed(vec![tx_hash!(2)]) + .with_state(ProviderState::Pending) + .build_into_l1_provider(); + + let expected_l1_provider = l1_provider.clone(); + + // Test. + // Unconsumed transaction, should fail silently. + l1_provider.process_l1_events(vec![l1_handler_event(tx_hash!(1))]).unwrap(); + assert_eq!(l1_provider, expected_l1_provider); + + // Committed transaction, should fail silently. + l1_provider.process_l1_events(vec![l1_handler_event(tx_hash!(2))]).unwrap(); + assert_eq!(l1_provider, expected_l1_provider); } #[test] fn pending_state_errors() { // Setup. - let mut l1_provider = - L1ProviderContentBuilder::new().with_txs([tx!(tx_hash: 1)]).build_into_l1_provider(); + let mut l1_provider = L1ProviderContentBuilder::new() + .with_state(ProviderState::Pending) + .with_txs([l1_handler(1)]) + .build_into_l1_provider(); // Test. assert_matches!( - l1_provider.get_txs(1).unwrap_err(), - L1ProviderError::GetTransactionsInPendingState + l1_provider.get_txs(1, BlockNumber(0)).unwrap_err(), + L1ProviderError::OutOfSessionGetTransactions ); assert_matches!( - l1_provider.validate(tx_hash!(1)).unwrap_err(), - L1ProviderError::ValidateInPendingState + l1_provider.validate(tx_hash!(1), BlockNumber(0)).unwrap_err(), + L1ProviderError::OutOfSessionValidate ); } #[test] -fn proposal_start_errors() { +fn proposal_start_multiple_proposals_same_height() { // Setup. - let mut l1_provider = L1Provider::default(); + let mut l1_provider = + L1ProviderContentBuilder::new().with_state(ProviderState::Pending).build_into_l1_provider(); - // Test. - l1_provider.proposal_start().unwrap(); + // Test all single-height combinations. + const SESSION_TYPES: [SessionState; 2] = [ProposeSession, ValidateSession]; + for (session_1, session_2) in SESSION_TYPES.into_iter().cartesian_product(SESSION_TYPES) { + l1_provider.start_block(BlockNumber(0), session_1).unwrap(); + l1_provider.start_block(BlockNumber(0), session_2).unwrap(); + } +} - assert_matches!( - l1_provider.proposal_start().unwrap_err(), - L1ProviderError::UnexpectedProviderStateTransition { from: Propose, to: Propose } - ); - assert_matches!( - l1_provider.validation_start().unwrap_err(), - L1ProviderError::UnexpectedProviderStateTransition { from: Propose, to: Validate } - ); +#[test] +fn commit_block_empty_block() { + // Setup. + let txs = [l1_handler(1), l1_handler(2)]; + let mut l1_provider = L1ProviderContentBuilder::new() + .with_txs(txs.clone()) + .with_height(BlockNumber(10)) + .with_state(ProviderState::Propose) + .build_into_l1_provider(); + + // Test: empty commit_block + l1_provider.commit_block(&[], BlockNumber(10)).unwrap(); + + let expected_l1_provider = L1ProviderContentBuilder::new() + .with_txs(txs) + .with_height(BlockNumber(11)) + .with_state(ProviderState::Pending) + .build(); + expected_l1_provider.assert_eq(&l1_provider); +} + +#[test] +fn commit_block_during_proposal() { + // Setup. + let mut l1_provider = L1ProviderContentBuilder::new() + .with_txs([l1_handler(1), l1_handler(2), l1_handler(3)]) + .with_height(BlockNumber(5)) + .with_state(ProviderState::Propose) + .build_into_l1_provider(); + + // Test: commit block during proposal. + l1_provider.commit_block(&[tx_hash!(1)], BlockNumber(5)).unwrap(); + + let expected_l1_provider = L1ProviderContentBuilder::new() + .with_txs([l1_handler(2), l1_handler(3)]) + .with_height(BlockNumber(6)) + .with_state(ProviderState::Pending) + .build(); + expected_l1_provider.assert_eq(&l1_provider); +} + +#[test] +fn commit_block_during_pending() { + // Setup. + let mut l1_provider = L1ProviderContentBuilder::new() + .with_txs([l1_handler(1), l1_handler(2), l1_handler(3)]) + .with_height(BlockNumber(5)) + .with_state(ProviderState::Pending) + .build_into_l1_provider(); + + // Test: commit block during pending. + l1_provider.commit_block(&[tx_hash!(2)], BlockNumber(5)).unwrap(); + + let expected_l1_provider = L1ProviderContentBuilder::new() + .with_txs([l1_handler(1), l1_handler(3)]) + .with_height(BlockNumber(6)) + .with_state(ProviderState::Pending) + .build(); + expected_l1_provider.assert_eq(&l1_provider); +} + +#[test] +fn commit_block_during_validation() { + // Setup. + let mut l1_provider = L1ProviderContentBuilder::new() + .with_txs([l1_handler(1), l1_handler(2), l1_handler(3)]) + .with_height(BlockNumber(5)) + .with_state(ProviderState::Validate) + .build_into_l1_provider(); + + // Test: commit block during validate. + l1_provider.state = ProviderState::Validate; + + l1_provider.commit_block(&[tx_hash!(3)], BlockNumber(5)).unwrap(); + let expected_l1_provider = L1ProviderContentBuilder::new() + .with_txs([l1_handler(1), l1_handler(2)]) + .with_height(BlockNumber(6)) + .with_state(ProviderState::Pending) + .build(); + expected_l1_provider.assert_eq(&l1_provider); } #[test] -fn validation_start_errors() { +fn commit_block_backlog() { // Setup. - let mut l1_provider = L1Provider::default(); + let initial_bootstrap_state = ProviderState::Bootstrap(bootstrapper!( + backlog: [10 => [2], 11 => [4]], + catch_up: 9 + )); + let mut l1_provider = L1ProviderContentBuilder::new() + .with_txs([l1_handler(1), l1_handler(2), l1_handler(4)]) + .with_height(BlockNumber(8)) + .with_state(initial_bootstrap_state.clone()) + .build_into_l1_provider(); // Test. - l1_provider.validation_start().unwrap(); + // Commit height too low to affect backlog. + l1_provider.commit_block(&[tx_hash!(1)], BlockNumber(8)).unwrap(); + let expected_l1_provider = L1ProviderContentBuilder::new() + .with_txs([l1_handler(2), l1_handler(4)]) + .with_height(BlockNumber(9)) + .with_state(initial_bootstrap_state) + .build(); + expected_l1_provider.assert_eq(&l1_provider); - assert_matches!( - l1_provider.validation_start().unwrap_err(), - L1ProviderError::UnexpectedProviderStateTransition { from: Validate, to: Validate } - ); - assert_matches!( - l1_provider.proposal_start().unwrap_err(), - L1ProviderError::UnexpectedProviderStateTransition { from: Validate, to: Propose } - ); + // Backlog is consumed, bootstrapping complete. + l1_provider.commit_block(&[], BlockNumber(9)).unwrap(); + let expected_l1_provider = L1ProviderContentBuilder::new() + .with_txs([]) + .with_height(BlockNumber(12)) + .with_state(ProviderState::Pending) + .build(); + expected_l1_provider.assert_eq(&l1_provider); +} + +#[test] +fn tx_in_commit_block_before_processed_is_skipped() { + // Setup + let mut l1_provider = + L1ProviderContentBuilder::new().with_committed([tx_hash!(1)]).build_into_l1_provider(); + + // Transactions unknown yet. + l1_provider.commit_block(&[tx_hash!(2), tx_hash!(3)], BlockNumber(0)).unwrap(); + let expected_l1_provider = L1ProviderContentBuilder::new() + .with_committed([tx_hash!(1), tx_hash!(2), tx_hash!(3)]) + .build(); + expected_l1_provider.assert_eq(&l1_provider); + + // Parsing the tx after getting it from commit-block is a NOP. + l1_provider.process_l1_events(vec![l1_handler_event(tx_hash!(2))]).unwrap(); + expected_l1_provider.assert_eq(&l1_provider); } diff --git a/crates/starknet_l1_provider/src/l1_scraper.rs b/crates/starknet_l1_provider/src/l1_scraper.rs new file mode 100644 index 00000000000..6383fd5c45d --- /dev/null +++ b/crates/starknet_l1_provider/src/l1_scraper.rs @@ -0,0 +1,301 @@ +use std::any::type_name; +use std::collections::BTreeMap; +use std::time::Duration; + +use async_trait::async_trait; +use papyrus_base_layer::constants::EventIdentifier; +use papyrus_base_layer::{BaseLayerContract, L1BlockNumber, L1BlockReference, L1Event}; +use papyrus_config::converters::deserialize_float_seconds_to_duration; +use papyrus_config::dumping::{ser_param, SerializeConfig}; +use papyrus_config::validators::validate_ascii; +use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; +use serde::{Deserialize, Serialize}; +use starknet_api::core::ChainId; +use starknet_api::executable_transaction::L1HandlerTransaction as ExecutableL1HandlerTransaction; +use starknet_api::StarknetApiError; +use starknet_l1_provider_types::errors::L1ProviderClientError; +use starknet_l1_provider_types::{Event, SharedL1ProviderClient}; +use starknet_sequencer_infra::component_client::ClientError; +use starknet_sequencer_infra::component_definitions::ComponentStarter; +use thiserror::Error; +use tokio::time::sleep; +use tracing::{error, info, instrument}; +use validator::Validate; + +#[cfg(test)] +#[path = "l1_scraper_tests.rs"] +pub mod l1_scraper_tests; + +type L1ScraperResult = Result>; + +// Sensible lower bound. +const L1_BLOCK_TIME: u64 = 10; + +pub struct L1Scraper { + pub config: L1ScraperConfig, + pub base_layer: B, + pub last_l1_block_processed: L1BlockReference, + pub l1_provider_client: SharedL1ProviderClient, + tracked_event_identifiers: Vec, +} + +impl L1Scraper { + pub async fn new( + config: L1ScraperConfig, + l1_provider_client: SharedL1ProviderClient, + base_layer: B, + events_identifiers_to_track: &[EventIdentifier], + ) -> L1ScraperResult { + let latest_l1_block = get_latest_l1_block_number(config.finality, &base_layer).await?; + // Estimate the number of blocks in the interval, to rewind from the latest block. + let blocks_in_interval = config.startup_rewind_time.as_secs() / L1_BLOCK_TIME; + // Add 50% safety margin. + let safe_blocks_in_interval = blocks_in_interval + blocks_in_interval / 2; + + let l1_block_number_rewind = latest_l1_block.saturating_sub(safe_blocks_in_interval); + + let block_reference_rewind = base_layer + .l1_block_at(l1_block_number_rewind) + .await + .map_err(L1ScraperError::BaseLayerError)? + .expect( + "Rewound L1 block number is between 0 and the verified latest L1 block, so should \ + exist", + ); + + Ok(Self { + l1_provider_client, + base_layer, + last_l1_block_processed: block_reference_rewind, + config, + tracked_event_identifiers: events_identifiers_to_track.to_vec(), + }) + } + + #[instrument(skip(self), err)] + pub async fn initialize(&mut self) -> L1ScraperResult<(), B> { + let (latest_l1_block, events) = self.fetch_events().await?; + + // If this gets too high, send in batches. + let initialize_result = self.l1_provider_client.initialize(events).await; + handle_client_error(initialize_result)?; + + self.last_l1_block_processed = latest_l1_block; + + Ok(()) + } + + pub async fn send_events_to_l1_provider(&mut self) -> L1ScraperResult<(), B> { + self.assert_no_l1_reorgs().await?; + + let (latest_l1_block, events) = self.fetch_events().await?; + + // Sending even if there are no events, to keep the flow as simple/debuggable as possible. + // Perf hit is minimal, since the scraper is on the same machine as the provider (no net). + // If this gets spammy, short-circuit on events.empty(). + let add_events_result = self.l1_provider_client.add_events(events).await; + handle_client_error(add_events_result)?; + + self.last_l1_block_processed = latest_l1_block; + + Ok(()) + } + + async fn fetch_events(&self) -> L1ScraperResult<(L1BlockReference, Vec), B> { + let latest_l1_block = self + .base_layer + .latest_l1_block(self.config.finality) + .await + .map_err(L1ScraperError::BaseLayerError)?; + + let Some(latest_l1_block) = latest_l1_block else { + return Err( + L1ScraperError::finality_too_high(self.config.finality, &self.base_layer).await + ); + }; + + let scraping_start_number = self.last_l1_block_processed.number + 1; + let scraping_result = self + .base_layer + .events(scraping_start_number..=latest_l1_block.number, &self.tracked_event_identifiers) + .await; + + let events = scraping_result.map_err(L1ScraperError::BaseLayerError)?; + let events = events + .into_iter() + .map(|event| self.event_from_raw_l1_event(event)) + .collect::, _>>()?; + + Ok((latest_l1_block, events)) + } + + #[instrument(skip(self), err)] + async fn run(&mut self) -> L1ScraperResult<(), B> { + self.initialize().await?; + loop { + sleep(self.config.polling_interval).await; + + self.send_events_to_l1_provider().await?; + } + } + + fn event_from_raw_l1_event(&self, l1_event: L1Event) -> L1ScraperResult { + match l1_event { + L1Event::LogMessageToL2 { tx, fee } => { + let chain_id = &self.config.chain_id; + match ExecutableL1HandlerTransaction::create(tx, chain_id, fee) { + Ok(tx) => Ok(Event::L1HandlerTransaction(tx)), + Err(hash_calc_err) => Err(L1ScraperError::HashCalculationError(hash_calc_err)), + } + } + L1Event::MessageToL2CancellationStarted(_messsage_data) => todo!(), + L1Event::MessageToL2Canceled(_messsage_data) => todo!(), + L1Event::ConsumedMessageToL2(_messsage_data) => todo!(), + } + } + + async fn assert_no_l1_reorgs(&self) -> L1ScraperResult<(), B> { + let last_processed_l1_block_number = self.last_l1_block_processed.number; + let last_block_processed_fresh = self + .base_layer + .l1_block_at(last_processed_l1_block_number) + .await + .map_err(L1ScraperError::BaseLayerError)?; + + let Some(last_block_processed_fresh) = last_block_processed_fresh else { + return Err(L1ScraperError::L1ReorgDetected { + reason: format!( + "Last processed L1 block with number {last_processed_l1_block_number} no \ + longer exists." + ), + }); + }; + + if last_block_processed_fresh.hash != self.last_l1_block_processed.hash { + return Err(L1ScraperError::L1ReorgDetected { + reason: format!( + "Last processed L1 block hash, {}, for block number {}, is different from the \ + hash stored, {}", + hex::encode(last_block_processed_fresh.hash), + last_processed_l1_block_number, + hex::encode(self.last_l1_block_processed.hash), + ), + }); + } + + Ok(()) + } +} + +#[async_trait] +impl ComponentStarter for L1Scraper { + async fn start(&mut self) { + info!("Starting component {}.", type_name::()); + self.run().await.unwrap_or_else(|e| panic!("Failed to start L1Scraper component: {}", e)) + } +} + +#[derive(Clone, Debug, Serialize, Deserialize, Validate, PartialEq)] +pub struct L1ScraperConfig { + #[serde(deserialize_with = "deserialize_float_seconds_to_duration")] + pub startup_rewind_time: Duration, + #[validate(custom = "validate_ascii")] + pub chain_id: ChainId, + pub finality: u64, + #[serde(deserialize_with = "deserialize_float_seconds_to_duration")] + pub polling_interval: Duration, +} + +impl Default for L1ScraperConfig { + fn default() -> Self { + Self { + startup_rewind_time: Duration::from_secs(0), + chain_id: ChainId::Mainnet, + finality: 0, + polling_interval: Duration::from_secs(1), + } + } +} + +impl SerializeConfig for L1ScraperConfig { + fn dump(&self) -> BTreeMap { + BTreeMap::from([ + ser_param( + "startup_rewind_time", + &self.startup_rewind_time.as_secs(), + "Duration to rewind from latest L1 block when starting scraping.", + ParamPrivacyInput::Public, + ), + ser_param( + "finality", + &self.finality, + "Number of blocks to wait for finality", + ParamPrivacyInput::Public, + ), + ser_param( + "polling_interval", + &self.polling_interval.as_secs(), + "Interval in Seconds between each scraping attempt of L1.", + ParamPrivacyInput::Public, + ), + ser_param( + "chain_id", + &self.chain_id, + "The chain to follow. For more details see https://docs.starknet.io/documentation/architecture_and_concepts/Blocks/transactions/#chain-id.", + ParamPrivacyInput::Public, + ), + ]) + } +} + +#[derive(Error, Debug)] +pub enum L1ScraperError { + #[error("Base layer error: {0}")] + BaseLayerError(T::Error), + #[error("Finality too high: {finality:?} > {latest_l1_block_no_finality:?}")] + FinalityTooHigh { finality: u64, latest_l1_block_no_finality: L1BlockNumber }, + #[error("Failed to calculate hash: {0}")] + HashCalculationError(StarknetApiError), + // Leaky abstraction, these errors should not propagate here. + #[error(transparent)] + NetworkError(ClientError), + #[error("L1 reorg detected: {reason}. Restart both the L1 provider and the scraper.")] + L1ReorgDetected { reason: String }, +} + +impl L1ScraperError { + pub async fn finality_too_high(finality: u64, base_layer: &B) -> L1ScraperError { + let latest_l1_block_number_no_finality = base_layer.latest_l1_block_number(0).await; + let latest_l1_block_no_finality = match latest_l1_block_number_no_finality { + Ok(block_number) => block_number + .expect("Latest *L1* block without finality is assumed to always exist."), + Err(error) => return Self::BaseLayerError(error), + }; + + Self::FinalityTooHigh { finality, latest_l1_block_no_finality } + } +} + +fn handle_client_error( + client_result: Result<(), L1ProviderClientError>, +) -> Result<(), L1ScraperError> { + if let Err(L1ProviderClientError::ClientError(client_error)) = client_result { + return Err(L1ScraperError::NetworkError(client_error)); + } + Ok(()) +} + +async fn get_latest_l1_block_number( + finality: u64, + base_layer: &B, +) -> Result> { + let latest_l1_block_number = base_layer + .latest_l1_block_number(finality) + .await + .map_err(L1ScraperError::BaseLayerError)?; + + match latest_l1_block_number { + Some(latest_l1_block_number) => Ok(latest_l1_block_number), + None => Err(L1ScraperError::finality_too_high(finality, base_layer).await), + } +} diff --git a/crates/starknet_l1_provider/src/l1_scraper_tests.rs b/crates/starknet_l1_provider/src/l1_scraper_tests.rs new file mode 100644 index 00000000000..93752baf2ae --- /dev/null +++ b/crates/starknet_l1_provider/src/l1_scraper_tests.rs @@ -0,0 +1,434 @@ +use std::collections::HashMap; +use std::sync::{Arc, Mutex}; +use std::time::Duration; + +use alloy::primitives::U256; +use itertools::Itertools; +use mempool_test_utils::starknet_api_test_utils::DEFAULT_ANVIL_L1_ACCOUNT_ADDRESS; +use papyrus_base_layer::ethereum_base_layer_contract::{ + EthereumBaseLayerConfig, + EthereumBaseLayerContract, + Starknet, +}; +use papyrus_base_layer::test_utils::{ + anvil_instance_from_config, + ethereum_base_layer_config_for_anvil, +}; +use starknet_api::block::BlockNumber; +use starknet_api::contract_address; +use starknet_api::core::{EntryPointSelector, Nonce}; +use starknet_api::executable_transaction::L1HandlerTransaction as ExecutableL1HandlerTransaction; +use starknet_api::hash::StarkHash; +use starknet_api::transaction::fields::{Calldata, Fee}; +use starknet_api::transaction::{L1HandlerTransaction, TransactionHasher, TransactionVersion}; +use starknet_l1_provider_types::{Event, L1ProviderClient}; +use starknet_sequencer_infra::trace_util::configure_tracing; +use starknet_state_sync_types::communication::MockStateSyncClient; +use starknet_state_sync_types::state_sync_types::SyncBlock; + +use crate::l1_provider::create_l1_provider; +use crate::l1_scraper::{L1Scraper, L1ScraperConfig}; +use crate::test_utils::FakeL1ProviderClient; +use crate::{event_identifiers_to_track, L1ProviderConfig}; + +pub fn in_ci() -> bool { + std::env::var("CI").is_ok() +} + +const fn height_add(block_number: BlockNumber, k: u64) -> BlockNumber { + BlockNumber(block_number.0 + k) +} + +// TODO(Gilad): Replace EthereumBaseLayerContract with a mock that has a provider initialized with +// `with_recommended_fillers`, in order to be able to create txs from non-default users. +async fn scraper( + base_layer_config: EthereumBaseLayerConfig, +) -> (L1Scraper, Arc) { + let fake_client = Arc::new(FakeL1ProviderClient::default()); + let base_layer = EthereumBaseLayerContract::new(base_layer_config); + + // Deploy a fresh Starknet contract on Anvil from the bytecode in the JSON file. + Starknet::deploy(base_layer.contract.provider().clone()).await.unwrap(); + + let scraper = L1Scraper::new( + L1ScraperConfig::default(), + fake_client.clone(), + base_layer, + event_identifiers_to_track(), + ) + .await + .unwrap(); + + (scraper, fake_client) +} + +#[tokio::test] +// TODO(Gilad): extract setup stuff into test helpers once more tests are added and patterns emerge. +async fn txs_happy_flow() { + if !in_ci() { + return; + } + + let base_layer_config = ethereum_base_layer_config_for_anvil(None); + let _anvil = anvil_instance_from_config(&base_layer_config); + // Setup. + let (mut scraper, fake_client) = scraper(base_layer_config).await; + + // Test. + // Scrape multiple events. + let l2_contract_address = "0x12"; + let l2_entry_point = "0x34"; + + let message_to_l2_0 = scraper.base_layer.contract.sendMessageToL2( + l2_contract_address.parse().unwrap(), + l2_entry_point.parse().unwrap(), + vec![U256::from(1_u8), U256::from(2_u8)], + ); + let message_to_l2_1 = scraper.base_layer.contract.sendMessageToL2( + l2_contract_address.parse().unwrap(), + l2_entry_point.parse().unwrap(), + vec![U256::from(3_u8), U256::from(4_u8)], + ); + + // Send the transactions. + for msg in &[message_to_l2_0, message_to_l2_1] { + msg.send().await.unwrap().get_receipt().await.unwrap(); + } + + const EXPECTED_VERSION: TransactionVersion = TransactionVersion(StarkHash::ZERO); + let expected_internal_l1_tx = L1HandlerTransaction { + version: EXPECTED_VERSION, + nonce: Nonce(StarkHash::ZERO), + contract_address: contract_address!(l2_contract_address), + entry_point_selector: EntryPointSelector(StarkHash::from_hex_unchecked(l2_entry_point)), + calldata: Calldata( + vec![DEFAULT_ANVIL_L1_ACCOUNT_ADDRESS, StarkHash::ONE, StarkHash::from(2)].into(), + ), + }; + let tx = ExecutableL1HandlerTransaction { + tx_hash: expected_internal_l1_tx + .calculate_transaction_hash(&scraper.config.chain_id, &EXPECTED_VERSION) + .unwrap(), + tx: expected_internal_l1_tx, + paid_fee_on_l1: Fee(0), + }; + let first_expected_log = Event::L1HandlerTransaction(tx.clone()); + + let expected_internal_l1_tx_2 = L1HandlerTransaction { + nonce: Nonce(StarkHash::ONE), + calldata: Calldata( + vec![DEFAULT_ANVIL_L1_ACCOUNT_ADDRESS, StarkHash::from(3), StarkHash::from(4)].into(), + ), + ..tx.tx + }; + let second_expected_log = Event::L1HandlerTransaction(ExecutableL1HandlerTransaction { + tx_hash: expected_internal_l1_tx_2 + .calculate_transaction_hash(&scraper.config.chain_id, &EXPECTED_VERSION) + .unwrap(), + tx: expected_internal_l1_tx_2, + ..tx + }); + + // Assert. + scraper.send_events_to_l1_provider().await.unwrap(); + fake_client.assert_add_events_received_with(&[first_expected_log, second_expected_log]); + + // Previous events had been scraped, should no longer appear. + scraper.send_events_to_l1_provider().await.unwrap(); + fake_client.assert_add_events_received_with(&[]); +} + +// TODO(Gilad): figure out how To setup anvil on a specific L1 block (through genesis.json?) and +// with a specified L2 block logged to L1 (hopefully without having to use real backup). +/// This test simulates a bootstrapping flow, in which 3 blocks are synced from L2, during which two +/// new blocks from past the catch-up height arrive. The expected behavior is that the synced +/// commit_blocks are processed as they come, and the two new blocks are backlogged until the synced +/// blocks are processed, after which they are processed in order. +#[tokio::test] +#[ignore = "stale and broken, will be fixed in next PR"] +async fn bootstrap_e2e() { + if !in_ci() { + return; + } + configure_tracing().await; + + // Setup. + + let l1_provider_client = Arc::new(FakeL1ProviderClient::default()); + const STARTUP_HEIGHT: BlockNumber = BlockNumber(2); + const CATCH_UP_HEIGHT: BlockNumber = BlockNumber(5); + + // Make the mocked sync client try removing from a hashmap as a response to get block. + let mut sync_client = MockStateSyncClient::default(); + let sync_response = Arc::new(Mutex::new(HashMap::::new())); + let mut sync_response_clone = sync_response.lock().unwrap().clone(); + sync_client.expect_get_block().returning(move |input| Ok(sync_response_clone.remove(&input))); + sync_client.expect_get_latest_block_number().returning(move || Ok(Some(CATCH_UP_HEIGHT))); + let config = L1ProviderConfig { + startup_sync_sleep_retry_interval: Duration::from_millis(10), + ..Default::default() + }; + let mut l1_provider = create_l1_provider( + config, + l1_provider_client.clone(), + Arc::new(sync_client), + STARTUP_HEIGHT, + ); + + // Test. + + // Trigger the bootstrapper: this will trigger the sync task to start trying to fetch blocks + // from the sync client, which will always return nothing since the hash map above is still + // empty. The sync task will busy-wait on the height until we feed the hashmap. + // TODO(Gilad): Consider adding txs here and in the commit blocks, might make the test harder to + // understand though. + let scraped_l1_handler_txs = vec![]; // No txs to scrape in this test. + l1_provider.initialize(scraped_l1_handler_txs).await.unwrap(); + + // Load first **Sync** response: the initializer task will pick it up within the specified + // interval. + sync_response.lock().unwrap().insert(STARTUP_HEIGHT, SyncBlock::default()); + tokio::time::sleep(config.startup_sync_sleep_retry_interval).await; + + // **Commit** 2 blocks past catchup height, should be received after the previous sync. + let no_txs_committed = vec![]; // Not testing txs in this test. + l1_provider_client.commit_block(no_txs_committed.clone(), CATCH_UP_HEIGHT).await.unwrap(); + tokio::time::sleep(config.startup_sync_sleep_retry_interval).await; + l1_provider_client + .commit_block(no_txs_committed, height_add(CATCH_UP_HEIGHT, 1)) + .await + .unwrap(); + tokio::time::sleep(config.startup_sync_sleep_retry_interval).await; + + // Feed sync task the remaining blocks, will be received after the commits above. + sync_response.lock().unwrap().insert(height_add(STARTUP_HEIGHT, 1), SyncBlock::default()); + sync_response.lock().unwrap().insert(height_add(STARTUP_HEIGHT, 2), SyncBlock::default()); + tokio::time::sleep(2 * config.startup_sync_sleep_retry_interval).await; + + // Assert that initializer task has received the stubbed responses from the sync client and sent + // the corresponding commit blocks to the provider, in the order implied to by the test + // structure. + let mut commit_blocks = l1_provider_client.commit_blocks_received.lock().unwrap(); + let received_order = commit_blocks.iter().map(|block| block.height).collect_vec(); + let expected_order = + vec![BlockNumber(2), BlockNumber(5), BlockNumber(6), BlockNumber(3), BlockNumber(4)]; + assert_eq!( + received_order, expected_order, + "Sanity check failed: commit block order mismatch. Expected {:?}, got {:?}", + expected_order, received_order + ); + + // Apply commit blocks and assert that correct height commit_blocks are applied, but commit + // blocks past catch_up_height are backlogged. + // TODO(Gilad): once we are able to create clients on top of channels, this manual'ness won't + // be necessary. Right now we cannot create clients without spinning up all servers, so we have + // to use a mock. + + let mut commit_blocks = commit_blocks.drain(..); + + // Apply height 2. + let next_block = commit_blocks.next().unwrap(); + l1_provider.commit_block(&next_block.committed_txs, next_block.height).unwrap(); + assert_eq!(l1_provider.current_height, BlockNumber(3)); + + // Backlog height 5. + let next_block = commit_blocks.next().unwrap(); + l1_provider.commit_block(&next_block.committed_txs, next_block.height).unwrap(); + // Assert that this didn't affect height; this commit block is too high so is backlogged. + assert_eq!(l1_provider.current_height, BlockNumber(3)); + + // Backlog height 6. + let next_block = commit_blocks.next().unwrap(); + l1_provider.commit_block(&next_block.committed_txs, next_block.height).unwrap(); + // Assert backlogged, like height 5. + assert_eq!(l1_provider.current_height, BlockNumber(3)); + + // Apply height 3 + let next_block = commit_blocks.next().unwrap(); + l1_provider.commit_block(&next_block.committed_txs, next_block.height).unwrap(); + assert_eq!(l1_provider.current_height, BlockNumber(4)); + + // Apply height 4 ==> this triggers committing the backlogged heights 5 and 6. + let next_block = commit_blocks.next().unwrap(); + l1_provider.commit_block(&next_block.committed_txs, next_block.height).unwrap(); + assert_eq!(l1_provider.current_height, BlockNumber(7)); + + // Assert that the bootstrapper has been dropped. + assert!(!l1_provider.state.is_bootstrapping()); +} + +#[tokio::test] +async fn bootstrap_delayed_sync_state_with_trivial_catch_up() { + if !in_ci() { + return; + } + configure_tracing().await; + + // Setup. + + let l1_provider_client = Arc::new(FakeL1ProviderClient::default()); + const STARTUP_HEIGHT: BlockNumber = BlockNumber(3); + + let mut sync_client = MockStateSyncClient::default(); + // Mock sync response for an arbitrary number of calls to get_latest_block_number. + // Later in the test we modify it to become something else. + let sync_height_response = Arc::new(Mutex::new(None)); + let sync_response_clone = sync_height_response.clone(); + sync_client + .expect_get_latest_block_number() + .returning(move || Ok(*sync_response_clone.lock().unwrap())); + + let config = L1ProviderConfig { + startup_sync_sleep_retry_interval: Duration::from_millis(10), + ..Default::default() + }; + let mut l1_provider = create_l1_provider( + config, + l1_provider_client.clone(), + Arc::new(sync_client), + STARTUP_HEIGHT, + ); + + // Test. + + // Start the sync sequence, should busy-wait until the sync height is sent. + let scraped_l1_handler_txs = []; // No txs to scrape in this test. + l1_provider.initialize(scraped_l1_handler_txs.into()).await.unwrap(); + + // **Commit** a few blocks. The height starts from the provider's current height, since this + // is a trivial catchup scenario (nothing to catch up). + // This checks that the trivial catch_up_height doesn't mess up this flow. + let no_txs_committed = []; // Not testing txs in this test. + l1_provider_client.commit_block(no_txs_committed.to_vec(), STARTUP_HEIGHT).await.unwrap(); + l1_provider_client + .commit_block(no_txs_committed.to_vec(), height_add(STARTUP_HEIGHT, 1)) + .await + .unwrap(); + + // Forward all messages buffered in the client to the provider. + l1_provider_client.flush_messages(&mut l1_provider).await; + + // Commit blocks should have been applied. + let start_height_plus_2 = height_add(STARTUP_HEIGHT, 2); + assert_eq!(l1_provider.current_height, start_height_plus_2); + // Should still be bootstrapping, since catchup height isn't determined yet. + // Technically we could end bootstrapping at this point, but its simpler to let it + // terminate gracefully once the the sync is ready. + assert!(l1_provider.state.is_bootstrapping()); + + *sync_height_response.lock().unwrap() = Some(BlockNumber(2)); + + // Let the sync task continue, it should short circuit. + tokio::time::sleep(config.startup_sync_sleep_retry_interval).await; + // Assert height is unchanged from last time, no commit block was called from the sync task. + assert_eq!(l1_provider.current_height, start_height_plus_2); + // Finally, commit a new block to trigger the bootstrapping check, should switch to steady + // state. + l1_provider.commit_block(&no_txs_committed, start_height_plus_2).unwrap(); + assert_eq!(l1_provider.current_height, height_add(start_height_plus_2, 1)); + // The new commit block triggered the catch-up check, which ended the bootstrapping phase. + assert!(!l1_provider.state.is_bootstrapping()); +} + +#[tokio::test] +async fn bootstrap_delayed_sync_state_with_sync_behind_batcher() { + if !in_ci() { + return; + } + configure_tracing().await; + + // Setup. + + let l1_provider_client = Arc::new(FakeL1ProviderClient::default()); + let startup_height = BlockNumber(1); + let sync_height = BlockNumber(3); + + let mut sync_client = MockStateSyncClient::default(); + // Mock sync response for an arbitrary number of calls to get_latest_block_number. + // Later in the test we modify it to become something else. + let sync_height_response = Arc::new(Mutex::new(None)); + let sync_response_clone = sync_height_response.clone(); + sync_client + .expect_get_latest_block_number() + .returning(move || Ok(*sync_response_clone.lock().unwrap())); + sync_client.expect_get_block().returning(|_| Ok(Some(SyncBlock::default()))); + + let config = L1ProviderConfig { + startup_sync_sleep_retry_interval: Duration::from_millis(10), + ..Default::default() + }; + let mut l1_provider = create_l1_provider( + config, + l1_provider_client.clone(), + Arc::new(sync_client), + startup_height, + ); + + // Test. + + // Start the sync sequence, should busy-wait until the sync height is sent. + let scraped_l1_handler_txs = []; // No txs to scrape in this test. + l1_provider.initialize(scraped_l1_handler_txs.into()).await.unwrap(); + + // **Commit** a few blocks. These should get backlogged since they are post-sync-height. + // Sleeps are sprinkled in to give the async task a couple shots at attempting to get the sync + // height (see DEBUG log). + let no_txs_committed = []; // Not testing txs in this test. + l1_provider_client + .commit_block(no_txs_committed.to_vec(), sync_height.unchecked_next()) + .await + .unwrap(); + tokio::time::sleep(config.startup_sync_sleep_retry_interval).await; + l1_provider_client + .commit_block(no_txs_committed.to_vec(), sync_height.unchecked_next().unchecked_next()) + .await + .unwrap(); + + // Forward all messages buffered in the client to the provider. + l1_provider_client.flush_messages(&mut l1_provider).await; + tokio::time::sleep(config.startup_sync_sleep_retry_interval).await; + + // Assert commit blocks are backlogged (didn't affect start height). + assert_eq!(l1_provider.current_height, startup_height); + // Should still be bootstrapping, since catchup height isn't determined yet. + assert!(l1_provider.state.is_bootstrapping()); + + // Simulate the state sync service finally being ready, and give the async task enough time to + // pick this up and sync up the provider. + *sync_height_response.lock().unwrap() = Some(sync_height); + tokio::time::sleep(config.startup_sync_sleep_retry_interval).await; + // Forward all messages buffered in the client to the provider. + l1_provider_client.flush_messages(&mut l1_provider).await; + + // Two things happened here: the async task sent 2 commit blocks it got from the sync_client, + // which bumped the provider height to sync_height+1, then the backlog was applied which bumped + // it twice again. + assert_eq!( + l1_provider.current_height, + sync_height.unchecked_next().unchecked_next().unchecked_next() + ); + // Sync height was reached, bootstrapping was completed. + assert!(!l1_provider.state.is_bootstrapping()); +} + +#[test] +#[ignore = "similar to backlog_happy_flow, only shorter, and sprinkle some start_block/get_txs \ + attempts while its bootstrapping (and assert failure on height), then assert that they \ + succeed after bootstrapping ends."] +fn bootstrap_completion() { + todo!() +} + +#[tokio::test] +#[ignore = "Not yet implemented: generate an l1 and an cancel event for that tx, also check an \ + abort for a different tx"] +async fn cancel_l1_handlers() {} + +#[tokio::test] +#[ignore = "Not yet implemented: check that when the scraper resets all txs from the last T time +are processed"] +async fn reset() {} + +#[tokio::test] +#[ignore = "Not yet implemented: check successful consume."] +async fn consume() {} diff --git a/crates/starknet_l1_provider/src/lib.rs b/crates/starknet_l1_provider/src/lib.rs index 07db3aa9dc5..91890afac9d 100644 --- a/crates/starknet_l1_provider/src/lib.rs +++ b/crates/starknet_l1_provider/src/lib.rs @@ -1,200 +1,139 @@ -pub mod errors; +pub mod bootstrapper; -#[cfg(test)] -pub mod test_utils; - -use indexmap::{IndexMap, IndexSet}; -use starknet_api::executable_transaction::L1HandlerTransaction; -use starknet_api::transaction::TransactionHash; +use papyrus_config::converters::deserialize_float_seconds_to_duration; +pub mod communication; +pub mod l1_provider; +pub mod l1_scraper; +pub mod soft_delete_index_map; +pub mod transaction_manager; -use crate::errors::L1ProviderError; - -type L1ProviderResult = Result; +#[cfg(any(test, feature = "testing"))] +pub mod test_utils; -#[cfg(test)] -#[path = "l1_provider_tests.rs"] -pub mod l1_provider_tests; +use std::collections::BTreeMap; +use std::time::Duration; + +use papyrus_base_layer::constants::{ + EventIdentifier, + CONSUMED_MESSAGE_TO_L1_EVENT_IDENTIFIER, + LOG_MESSAGE_TO_L2_EVENT_IDENTIFIER, + MESSAGE_TO_L2_CANCELED_EVENT_IDENTIFIER, + MESSAGE_TO_L2_CANCELLATION_STARTED_EVENT_IDENTIFIER, +}; +use papyrus_config::dumping::{ser_optional_param, ser_param, SerializeConfig}; +use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; +use serde::{Deserialize, Serialize}; +use starknet_api::block::BlockNumber; +use starknet_l1_provider_types::SessionState; +use validator::Validate; + +use crate::bootstrapper::Bootstrapper; -// TODO: optimistic proposer support, will add later to keep things simple, but the design here -// is compatible with it. -#[derive(Debug, Default)] -pub struct L1Provider { - tx_manager: TransactionManager, - // TODO(Gilad): consider transitioning to a generic phantom state once the infra is stabilized - // and we see how well it handles consuming the L1Provider when moving between states. - state: ProviderState, +/// Current state of the provider, where pending means: idle, between proposal/validation cycles. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum ProviderState { + Pending, + Propose, + Bootstrap(Bootstrapper), + Validate, } -impl L1Provider { - pub async fn new(_config: L1ProviderConfig) -> L1ProviderResult { - todo!( - "init crawler to start next crawl from ~1 hour ago, this can have l1 errors when \ - finding the latest block on L1 to 'subtract' 1 hour from." - ); - } - - /// Retrieves up to `n_txs` transactions that have yet to be proposed or accepted on L2. - pub fn get_txs(&mut self, n_txs: usize) -> L1ProviderResult> { - match self.state { - ProviderState::Propose => Ok(self.tx_manager.get_txs(n_txs)), - ProviderState::Pending => Err(L1ProviderError::GetTransactionsInPendingState), - ProviderState::Validate => Err(L1ProviderError::GetTransactionConsensusBug), +impl ProviderState { + pub fn as_str(&self) -> &str { + match self { + ProviderState::Pending => "Pending", + ProviderState::Propose => "Propose", + ProviderState::Bootstrap(_) => "Bootstrap", + ProviderState::Validate => "Validate", } } - /// Returns true if and only if the given transaction is both not included in an L2 block, and - /// unconsumed on L1. - pub fn validate(&self, tx_hash: TransactionHash) -> L1ProviderResult { - match self.state { - ProviderState::Validate => Ok(self.tx_manager.tx_status(tx_hash)), - ProviderState::Propose => Err(L1ProviderError::ValidateTransactionConsensusBug), - ProviderState::Pending => Err(L1ProviderError::ValidateInPendingState), + pub fn is_bootstrapping(&self) -> bool { + if let ProviderState::Bootstrap { .. } = self { + return true; } - } - - // TODO: when deciding on consensus, if possible, have commit_block also tell the node if it's - // about to [optimistically-]propose or validate the next block. - pub fn commit_block(&mut self, _commited_txs: &[TransactionHash]) { - todo!( - "Purges txs from internal buffers, if was proposer clear staging buffer, - reset state to Pending until we get proposing/validating notice from consensus." - ) - } - - // TODO: pending formal consensus API, guessing the API here to keep things moving. - // TODO: consider adding block number, it isn't strictly necessary, but will help debugging. - pub fn validation_start(&mut self) -> L1ProviderResult<()> { - self.state = self.state.transition_to_validate()?; - Ok(()) - } - pub fn proposal_start(&mut self) -> L1ProviderResult<()> { - self.state = self.state.transition_to_propose()?; - Ok(()) + false } - /// Simple recovery from L1 and L2 reorgs by reseting the service, which rewinds L1 and L2 - /// information. - pub fn handle_reorg(&mut self) -> L1ProviderResult<()> { - self.reset() - } + pub fn get_bootstrapper(&mut self) -> Option<&mut Bootstrapper> { + if let ProviderState::Bootstrap(bootstrapper) = self { + return Some(bootstrapper); + } - // TODO: this will likely change during integration with infra team. - pub async fn start(&self) { - todo!( - "Create a process that wakes up every config.poll_interval seconds and updates - internal L1 and L2 buffers according to collected L1 events and recent blocks created on - L2." - ) + None } - fn reset(&mut self) -> L1ProviderResult<()> { - todo!( - "resets internal buffers and rewinds the internal crawler _pointer_ back for ~1 \ - hour,so that the main loop will start collecting from that time gracefully. May hit \ - base layer errors." + fn transition_to_pending(&self) -> ProviderState { + assert!( + !self.is_bootstrapping(), + "Transitioning from bootstrapping should be done manually by the L1Provider." ); + ProviderState::Pending } } -#[derive(Debug, Default)] -struct TransactionManager { - txs: IndexMap, - proposed_txs: IndexSet, - on_l2_awaiting_l1_consumption: IndexSet, -} - -impl TransactionManager { - pub fn get_txs(&mut self, n_txs: usize) -> Vec { - let (tx_hashes, txs): (Vec<_>, Vec<_>) = self - .txs - .iter() - .skip(self.proposed_txs.len()) // Transactions are proposed FIFO. - .take(n_txs) - .map(|(&hash, tx)| (hash, tx.clone())) - .unzip(); - - self.proposed_txs.extend(tx_hashes); - txs - } - - pub fn tx_status(&self, tx_hash: TransactionHash) -> ValidationStatus { - if self.txs.contains_key(&tx_hash) { - ValidationStatus::Validated - } else if self.on_l2_awaiting_l1_consumption.contains(&tx_hash) { - ValidationStatus::AlreadyIncludedOnL2 - } else { - ValidationStatus::ConsumedOnL1OrUnknown +impl From for ProviderState { + fn from(state: SessionState) -> Self { + match state { + SessionState::Propose => ProviderState::Propose, + SessionState::Validate => ProviderState::Validate, } } - - pub fn _add_unconsumed_l1_not_in_l2_block_tx(&mut self, _tx: L1HandlerTransaction) { - todo!( - "Check if tx is in L2, if it isn't on L2 add it to the txs buffer, otherwise print - debug and do nothing." - ) - } - - pub fn _mark_tx_included_on_l2(&mut self, _tx_hash: &TransactionHash) { - todo!("Adds the tx hash to l2 buffer; remove tx from the txs storage if it's there.") - } } -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum ValidationStatus { - Validated, - AlreadyIncludedOnL2, - ConsumedOnL1OrUnknown, +impl std::fmt::Display for ProviderState { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(self.as_str()) + } } -/// Current state of the provider, where pending means: idle, between proposal/validation cycles. -#[derive(Clone, Copy, Debug, Default)] -pub enum ProviderState { - #[default] - Pending, - Propose, - Validate, +#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, Validate, PartialEq, Eq)] +pub struct L1ProviderConfig { + /// In most cases this can remain None: the provider defaults to using the + /// LastStateUpdate height at the L1 Height that the L1Scraper is initialized on. + /// **WARNING**: Take care when setting this value, it must be no higher than the + /// LastStateUpdate height at the L1 Height that the L1Scraper is initialized on. + pub provider_startup_height_override: Option, + /// In most cases this can remain None: the provider defaults to using the sync height at + /// startup. + pub bootstrap_catch_up_height_override: Option, + #[serde(deserialize_with = "deserialize_float_seconds_to_duration")] + pub startup_sync_sleep_retry_interval: Duration, } -impl ProviderState { - fn transition_to_propose(self) -> L1ProviderResult { - match self { - ProviderState::Pending => Ok(ProviderState::Propose), - _ => Err(L1ProviderError::UnexpectedProviderStateTransition { - from: self, - to: ProviderState::Propose, - }), - } - } - - fn transition_to_validate(self) -> L1ProviderResult { - match self { - ProviderState::Pending => Ok(ProviderState::Validate), - _ => Err(L1ProviderError::UnexpectedProviderStateTransition { - from: self, - to: ProviderState::Validate, - }), - } - } - - fn _transition_to_pending(self) -> L1ProviderResult { - todo!() - } - - pub fn as_str(&self) -> &str { - match self { - ProviderState::Pending => "Pending", - ProviderState::Propose => "Propose", - ProviderState::Validate => "Validate", - } +impl SerializeConfig for L1ProviderConfig { + fn dump(&self) -> BTreeMap { + let mut dump = BTreeMap::from([ser_param( + "startup_sync_sleep_retry_interval", + &self.startup_sync_sleep_retry_interval.as_secs_f64(), + "Interval in seconds between each retry of syncing with L2 during startup.", + ParamPrivacyInput::Public, + )]); + + dump.extend(ser_optional_param( + &self.provider_startup_height_override, + Default::default(), + "provider_startup_height_override", + "Override height at which the provider should start", + ParamPrivacyInput::Public, + )); + dump.extend(ser_optional_param( + &self.bootstrap_catch_up_height_override, + Default::default(), + "bootstrap_catch_up_height_override", + "Override height at which the provider should catch up to the bootstrapper.", + ParamPrivacyInput::Public, + )); + dump } } -impl std::fmt::Display for ProviderState { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str(self.as_str()) - } +pub const fn event_identifiers_to_track() -> &'static [EventIdentifier] { + &[ + LOG_MESSAGE_TO_L2_EVENT_IDENTIFIER, + CONSUMED_MESSAGE_TO_L1_EVENT_IDENTIFIER, + MESSAGE_TO_L2_CANCELLATION_STARTED_EVENT_IDENTIFIER, + MESSAGE_TO_L2_CANCELED_EVENT_IDENTIFIER, + ] } - -#[derive(Debug)] -pub struct L1ProviderConfig; diff --git a/crates/starknet_l1_provider/src/soft_delete_index_map.rs b/crates/starknet_l1_provider/src/soft_delete_index_map.rs new file mode 100644 index 00000000000..1218bfbe0e7 --- /dev/null +++ b/crates/starknet_l1_provider/src/soft_delete_index_map.rs @@ -0,0 +1,135 @@ +use std::collections::HashSet; + +use indexmap::map::Entry; +use indexmap::IndexMap; +use starknet_api::executable_transaction::L1HandlerTransaction; +use starknet_api::transaction::TransactionHash; + +/// An IndexMap that supports soft deletion of entries. +/// Entries marked as deleted remain hidden in the map, allowing for potential recovery, +/// selective permanent deletion, or rollback before being purged. +// Note: replace with a fully generic struct if there's a need for it. +// Note: replace with a BTreeIndexMap if commit performance becomes an issue, see note in commit. +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub struct SoftDeleteIndexMap { + pub txs: IndexMap, + pub staged_txs: HashSet, +} + +impl SoftDeleteIndexMap { + pub fn _new() -> Self { + Self::default() + } + + /// Inserts a transaction into the map, returning false if the transaction already existed. + pub fn insert(&mut self, tx: L1HandlerTransaction) -> bool { + let tx_hash = tx.tx_hash; + match self.txs.entry(tx_hash) { + Entry::Occupied(entry) => { + assert_eq!(entry.get().transaction, tx); + false + } + Entry::Vacant(entry) => { + entry.insert(TransactionEntry::new(tx)); + true + } + } + } + + /// Soft delete and return a reference to the first unstaged transaction, by insertion order. + pub fn soft_pop_front(&mut self) -> Option<&L1HandlerTransaction> { + let entry = self.txs.iter().find(|(_, tx)| tx.is_available()); + let (&tx_hash, _) = entry?; + self.soft_remove(tx_hash) + } + + /// Stages the given transaction with the given hash if it exists and is not already staged, and + /// returns a reference to it. + pub fn soft_remove(&mut self, tx_hash: TransactionHash) -> Option<&L1HandlerTransaction> { + let entry = self.txs.get_mut(&tx_hash)?; + + if !entry.is_available() { + return None; + } + + assert_eq!(self.staged_txs.get(&tx_hash), None); + entry.set_state(TxState::Staged); + self.staged_txs.insert(tx_hash); + + Some(&entry.transaction) + } + + /// Commits given transactions by removing them entirely and returning the removed transactions. + /// Uncommitted staged transactions are rolled back to unstaged first. + // Performance note: This operation is linear time with both the number + // of known transactions and the number of committed transactions. This is assumed to be + // good enough while l1-handler numbers remain low, but if this changes and we need log(n) + // removals (amortized), replace indexmap with this (basically a BTreeIndexMap): + // BTreeMap, Hashmap and a counter: u32, such that + // every new tx is inserted to the map with key counter++ and the counter is not reduced + // when removing entries. Once the counter reaches u32::MAX/2 we recreate the DS in Theta(n). + pub fn commit(&mut self, tx_hashes: &[TransactionHash]) -> Vec { + self.rollback_staging(); + let tx_hashes: HashSet<_> = tx_hashes.iter().copied().collect(); + if tx_hashes.is_empty() { + return Vec::new(); + } + + // NOTE: this takes Theta(|self.txs|), see docstring. + let (committed, not_committed): (Vec<_>, Vec<_>) = + self.txs.drain(..).partition(|(hash, _)| tx_hashes.contains(hash)); + self.txs.extend(not_committed); + + committed.into_iter().map(|(_, entry)| entry.transaction).collect() + } + + /// Rolls back all staged transactions, converting them to unstaged. + pub fn rollback_staging(&mut self) { + for tx_hash in self.staged_txs.drain() { + self.txs.entry(tx_hash).and_modify(|entry| entry.set_state(TxState::Unstaged)); + } + } + + pub fn is_staged(&self, tx_hash: &TransactionHash) -> bool { + self.staged_txs.contains(tx_hash) + } +} + +impl From> for SoftDeleteIndexMap { + fn from(txs: Vec) -> Self { + let txs = txs.into_iter().map(|tx| (tx.tx_hash, TransactionEntry::new(tx))).collect(); + SoftDeleteIndexMap { txs, ..Default::default() } + } +} + +/// Indicates whether a transaction is unstaged or staged. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum TxState { + Unstaged, + Staged, +} + +/// Wraps an L1HandlerTransaction along with its current TxState, +/// and provides convenience methods for stage/unstage. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct TransactionEntry { + pub transaction: L1HandlerTransaction, + pub state: TxState, +} + +impl TransactionEntry { + pub fn new(transaction: L1HandlerTransaction) -> Self { + Self { transaction, state: TxState::Unstaged } + } + + pub fn set_state(&mut self, state: TxState) { + self.state = state + } + + pub fn is_available(&self) -> bool { + match self.state { + TxState::Unstaged => true, + TxState::Staged => false, + } + } +} diff --git a/crates/starknet_l1_provider/src/test_utils.rs b/crates/starknet_l1_provider/src/test_utils.rs index a987fe7eeee..f985c49f883 100644 --- a/crates/starknet_l1_provider/src/test_utils.rs +++ b/crates/starknet_l1_provider/src/test_utils.rs @@ -1,25 +1,71 @@ -use indexmap::{IndexMap, IndexSet}; -use starknet_api::executable_transaction::L1HandlerTransaction; +use std::collections::HashSet; +use std::mem; +use std::sync::Mutex; + +use async_trait::async_trait; +use itertools::Itertools; +use pretty_assertions::assert_eq; +use starknet_api::block::BlockNumber; +use starknet_api::executable_transaction::{ + L1HandlerTransaction as ExecutableL1HandlerTransaction, + L1HandlerTransaction, +}; +use starknet_api::hash::StarkHash; +use starknet_api::test_utils::l1_handler::{executable_l1_handler_tx, L1HandlerTxArgs}; use starknet_api::transaction::TransactionHash; +use starknet_l1_provider_types::{ + Event, + L1ProviderClient, + L1ProviderClientResult, + SessionState, + ValidationStatus, +}; + +use crate::bootstrapper::CommitBlockBacklog; +use crate::l1_provider::L1Provider; +use crate::soft_delete_index_map::SoftDeleteIndexMap; +use crate::transaction_manager::TransactionManager; +use crate::ProviderState; -use crate::{L1Provider, ProviderState, TransactionManager}; +pub fn l1_handler(tx_hash: usize) -> L1HandlerTransaction { + let tx_hash = TransactionHash(StarkHash::from(tx_hash)); + executable_l1_handler_tx(L1HandlerTxArgs { tx_hash, ..Default::default() }) +} // Represents the internal content of the L1 provider for testing. // Enables customized (and potentially inconsistent) creation for unit testing. -#[derive(Debug, Default)] +#[derive(Default)] pub struct L1ProviderContent { tx_manager_content: Option, state: Option, + current_height: Option, +} + +impl L1ProviderContent { + #[track_caller] + pub fn assert_eq(&self, l1_provider: &L1Provider) { + if let Some(tx_manager_content) = &self.tx_manager_content { + tx_manager_content.assert_eq(&l1_provider.tx_manager); + } + + if let Some(state) = &self.state { + assert_eq!(&l1_provider.state, state); + } + + if let Some(current_height) = &self.current_height { + assert_eq!(&l1_provider.current_height, current_height); + } + } } impl From for L1Provider { fn from(content: L1ProviderContent) -> L1Provider { L1Provider { - tx_manager: content - .tx_manager_content - .map(|tm_content| tm_content.complete_to_tx_manager()) - .unwrap_or_default(), - state: content.state.unwrap_or_default(), + tx_manager: content.tx_manager_content.map(Into::into).unwrap_or_default(), + // Defaulting to Pending state, since a provider with a "default" Bootstrapper + // is functionally equivalent to Pending for testing purposes. + state: content.state.unwrap_or(ProviderState::Pending), + current_height: content.current_height.unwrap_or_default(), } } } @@ -28,6 +74,7 @@ impl From for L1Provider { pub struct L1ProviderContentBuilder { tx_manager_content_builder: TransactionManagerContentBuilder, state: Option, + current_height: Option, } impl L1ProviderContentBuilder { @@ -45,12 +92,13 @@ impl L1ProviderContentBuilder { self } - pub fn with_on_l2_awaiting_l1_consumption( - mut self, - tx_hashes: impl IntoIterator, - ) -> Self { - self.tx_manager_content_builder = - self.tx_manager_content_builder.with_on_l2_awaiting_l1_consumption(tx_hashes); + pub fn with_height(mut self, height: BlockNumber) -> Self { + self.current_height = Some(height); + self + } + + pub fn with_committed(mut self, tx_hashes: impl IntoIterator) -> Self { + self.tx_manager_content_builder = self.tx_manager_content_builder.with_committed(tx_hashes); self } @@ -58,6 +106,7 @@ impl L1ProviderContentBuilder { L1ProviderContent { tx_manager_content: self.tx_manager_content_builder.build(), state: self.state, + current_height: self.current_height, } } @@ -70,37 +119,50 @@ impl L1ProviderContentBuilder { // Enables customized (and potentially inconsistent) creation for unit testing. #[derive(Debug, Default)] struct TransactionManagerContent { - txs: Option>, - on_l2_awaiting_l1_consumption: Option>, + pub txs: Option>, + pub committed: Option>, } impl TransactionManagerContent { - fn complete_to_tx_manager(self) -> TransactionManager { + #[track_caller] + fn assert_eq(&self, tx_manager: &TransactionManager) { + if let Some(txs) = &self.txs { + assert_eq!( + txs, + &tx_manager.txs.txs.values().map(|tx| tx.transaction.clone()).collect_vec() + ); + } + + if let Some(committed) = &self.committed { + assert_eq!(committed, &tx_manager.committed); + } + } +} + +impl From for TransactionManager { + fn from(mut content: TransactionManagerContent) -> TransactionManager { + let txs: Vec<_> = mem::take(&mut content.txs).unwrap_or_default(); TransactionManager { - txs: self.txs.unwrap_or_default(), - on_l2_awaiting_l1_consumption: self.on_l2_awaiting_l1_consumption.unwrap_or_default(), - ..Default::default() + txs: SoftDeleteIndexMap::from(txs), + committed: content.committed.unwrap_or_default(), } } } #[derive(Debug, Default)] struct TransactionManagerContentBuilder { - txs: Option>, - on_l2_awaiting_l1_consumption: Option>, + txs: Option>, + committed: Option>, } impl TransactionManagerContentBuilder { fn with_txs(mut self, txs: impl IntoIterator) -> Self { - self.txs = Some(txs.into_iter().map(|tx| (tx.tx_hash, tx)).collect()); + self.txs = Some(txs.into_iter().collect()); self } - fn with_on_l2_awaiting_l1_consumption( - mut self, - tx_hashes: impl IntoIterator, - ) -> Self { - self.on_l2_awaiting_l1_consumption = Some(tx_hashes.into_iter().collect()); + fn with_committed(mut self, tx_hashes: impl IntoIterator) -> Self { + self.committed = Some(tx_hashes.into_iter().collect()); self } @@ -109,13 +171,86 @@ impl TransactionManagerContentBuilder { return None; } - Some(TransactionManagerContent { - txs: self.txs, - on_l2_awaiting_l1_consumption: self.on_l2_awaiting_l1_consumption, - }) + Some(TransactionManagerContent { txs: self.txs, committed: self.committed }) } fn is_default(&self) -> bool { - self.txs.is_none() && self.on_l2_awaiting_l1_consumption.is_none() + self.txs.is_none() && self.committed.is_none() + } +} + +/// A fake L1 provider client that buffers all received messages, allow asserting the order in which +/// they were received, and forward them to the l1 provider (flush the messages). +#[derive(Default)] +pub struct FakeL1ProviderClient { + // Interior mutability needed since this is modifying during client API calls, which are all + // immutable. + pub events_received: Mutex>, + pub commit_blocks_received: Mutex>, +} + +impl FakeL1ProviderClient { + /// Apply all messages received to the l1 provider. + pub async fn flush_messages(&self, l1_provider: &mut L1Provider) { + let commit_blocks = self.commit_blocks_received.lock().unwrap().drain(..).collect_vec(); + for CommitBlockBacklog { height, committed_txs } in commit_blocks { + l1_provider.commit_block(&committed_txs, height).unwrap(); + } + + // TODO(gilad): flush other buffers if necessary. + } + + #[track_caller] + pub fn assert_add_events_received_with(&self, expected: &[Event]) { + let events_received = mem::take(&mut *self.events_received.lock().unwrap()); + assert_eq!(events_received, expected); + } +} + +#[async_trait] +impl L1ProviderClient for FakeL1ProviderClient { + async fn start_block( + &self, + _state: SessionState, + _height: BlockNumber, + ) -> L1ProviderClientResult<()> { + todo!() + } + + async fn get_txs( + &self, + _n_txs: usize, + _height: BlockNumber, + ) -> L1ProviderClientResult> { + todo!() + } + + async fn add_events(&self, events: Vec) -> L1ProviderClientResult<()> { + self.events_received.lock().unwrap().extend(events); + Ok(()) + } + + async fn commit_block( + &self, + l1_handler_tx_hashes: Vec, + height: BlockNumber, + ) -> L1ProviderClientResult<()> { + self.commit_blocks_received + .lock() + .unwrap() + .push(CommitBlockBacklog { height, committed_txs: l1_handler_tx_hashes }); + Ok(()) + } + + async fn validate( + &self, + _tx_hash: TransactionHash, + _height: BlockNumber, + ) -> L1ProviderClientResult { + todo!() + } + + async fn initialize(&self, _events: Vec) -> L1ProviderClientResult<()> { + todo!() } } diff --git a/crates/starknet_l1_provider/src/transaction_manager.rs b/crates/starknet_l1_provider/src/transaction_manager.rs new file mode 100644 index 00000000000..719d6974816 --- /dev/null +++ b/crates/starknet_l1_provider/src/transaction_manager.rs @@ -0,0 +1,59 @@ +use std::collections::HashSet; + +use starknet_api::executable_transaction::L1HandlerTransaction; +use starknet_api::transaction::TransactionHash; +use starknet_l1_provider_types::{InvalidValidationStatus, ValidationStatus}; + +use crate::soft_delete_index_map::SoftDeleteIndexMap; + +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub struct TransactionManager { + pub txs: SoftDeleteIndexMap, + pub committed: HashSet, +} + +impl TransactionManager { + pub fn start_block(&mut self) { + self.txs.rollback_staging(); + } + + pub fn get_txs(&mut self, n_txs: usize) -> Vec { + let mut txs = Vec::with_capacity(n_txs); + + for _ in 0..n_txs { + match self.txs.soft_pop_front().cloned() { + Some(tx) => txs.push(tx), + None => break, + } + } + txs + } + + pub fn validate_tx(&mut self, tx_hash: TransactionHash) -> ValidationStatus { + if self.committed.contains(&tx_hash) { + return ValidationStatus::Invalid(InvalidValidationStatus::AlreadyIncludedOnL2); + } + + if self.txs.soft_remove(tx_hash).is_some() { + ValidationStatus::Validated + } else if self.txs.is_staged(&tx_hash) { + ValidationStatus::Invalid(InvalidValidationStatus::AlreadyIncludedInProposedBlock) + } else { + ValidationStatus::Invalid(InvalidValidationStatus::ConsumedOnL1OrUnknown) + } + } + + pub fn commit_txs(&mut self, committed_txs: &[TransactionHash]) { + // Committed L1 transactions are dropped here, do we need to them for anything? + self.txs.commit(committed_txs); + // Add all committed tx hashes to the committed buffer, regardless of if they're known or + // not, in case we haven't scraped them yet and another node did. + self.committed.extend(committed_txs) + } + + /// Adds a transaction to the transaction manager, return false iff the transaction already + /// existed. + pub fn add_tx(&mut self, tx: L1HandlerTransaction) -> bool { + self.committed.contains(&tx.tx_hash) || self.txs.insert(tx) + } +} diff --git a/crates/starknet_l1_provider_types/Cargo.toml b/crates/starknet_l1_provider_types/Cargo.toml new file mode 100644 index 00000000000..f8dfce533c8 --- /dev/null +++ b/crates/starknet_l1_provider_types/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "starknet_l1_provider_types" +version.workspace = true +edition.workspace = true +repository.workspace = true +license.workspace = true + +[features] +testing = ["mockall"] + +[dependencies] +async-trait.workspace = true +mockall = { workspace = true, optional = true } +papyrus_base_layer.workspace = true +papyrus_proc_macros.workspace = true +serde.workspace = true +starknet_api.workspace = true +starknet_sequencer_infra.workspace = true +strum_macros.workspace = true +thiserror.workspace = true +tracing.workspace = true + +[dev-dependencies] +mockall.workspace = true + +[lints] +workspace = true diff --git a/crates/starknet_l1_provider_types/src/errors.rs b/crates/starknet_l1_provider_types/src/errors.rs new file mode 100644 index 00000000000..e6a059d86ce --- /dev/null +++ b/crates/starknet_l1_provider_types/src/errors.rs @@ -0,0 +1,38 @@ +use std::fmt::Debug; + +use serde::{Deserialize, Serialize}; +use starknet_api::block::BlockNumber; +use starknet_sequencer_infra::component_client::ClientError; +use thiserror::Error; + +#[derive(Clone, Debug, Error, PartialEq, Eq, Serialize, Deserialize)] +pub enum L1ProviderError { + #[error("`get_txs` while in `Validate` state")] + GetTransactionConsensusBug, + // This is likely due to a crash, restart block proposal. + #[error("`get_txs` called when provider is not in proposer state")] + OutOfSessionGetTransactions, + // This is likely due to a crash, restart block proposal. + #[error("`validate` called when provider is not in proposer state")] + OutOfSessionValidate, + #[error("Unexpected height: expected {expected_height}, got {got}")] + UnexpectedHeight { expected_height: BlockNumber, got: BlockNumber }, + #[error("Cannot transition from {from} to {to}")] + UnexpectedProviderStateTransition { from: String, to: String }, + #[error("`validate` called while in `Propose` state")] + ValidateTransactionConsensusBug, +} + +impl L1ProviderError { + pub fn unexpected_transition(from: impl ToString, to: impl ToString) -> Self { + Self::UnexpectedProviderStateTransition { from: from.to_string(), to: to.to_string() } + } +} + +#[derive(Clone, Debug, Error)] +pub enum L1ProviderClientError { + #[error(transparent)] + ClientError(#[from] ClientError), + #[error(transparent)] + L1ProviderError(#[from] L1ProviderError), +} diff --git a/crates/starknet_l1_provider_types/src/lib.rs b/crates/starknet_l1_provider_types/src/lib.rs new file mode 100644 index 00000000000..12b4c29681a --- /dev/null +++ b/crates/starknet_l1_provider_types/src/lib.rs @@ -0,0 +1,197 @@ +pub mod errors; + +use std::sync::Arc; + +use async_trait::async_trait; +#[cfg(any(feature = "testing", test))] +use mockall::automock; +use papyrus_base_layer::L1Event; +use papyrus_proc_macros::handle_all_response_variants; +use serde::{Deserialize, Serialize}; +use starknet_api::block::BlockNumber; +use starknet_api::executable_transaction::L1HandlerTransaction; +use starknet_api::transaction::TransactionHash; +use starknet_sequencer_infra::component_client::ClientError; +use starknet_sequencer_infra::component_definitions::ComponentClient; +use starknet_sequencer_infra::impl_debug_for_infra_requests_and_responses; +use strum_macros::AsRefStr; +use tracing::instrument; + +use crate::errors::{L1ProviderClientError, L1ProviderError}; + +pub type L1ProviderResult = Result; +pub type L1ProviderClientResult = Result; +pub type SharedL1ProviderClient = Arc; + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub enum ValidationStatus { + Invalid(InvalidValidationStatus), + Validated, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub enum InvalidValidationStatus { + AlreadyIncludedInProposedBlock, + AlreadyIncludedOnL2, + ConsumedOnL1OrUnknown, +} + +#[derive(Clone, Serialize, Deserialize, AsRefStr)] +pub enum L1ProviderRequest { + AddEvents(Vec), + CommitBlock { l1_handler_tx_hashes: Vec, height: BlockNumber }, + GetTransactions { n_txs: usize, height: BlockNumber }, + Initialize(Vec), + StartBlock { state: SessionState, height: BlockNumber }, + Validate { tx_hash: TransactionHash, height: BlockNumber }, +} +impl_debug_for_infra_requests_and_responses!(L1ProviderRequest); + +#[derive(Clone, Serialize, Deserialize, AsRefStr)] +pub enum L1ProviderResponse { + AddEvents(L1ProviderResult<()>), + CommitBlock(L1ProviderResult<()>), + GetTransactions(L1ProviderResult>), + Initialize(L1ProviderResult<()>), + StartBlock(L1ProviderResult<()>), + Validate(L1ProviderResult), +} +impl_debug_for_infra_requests_and_responses!(L1ProviderResponse); + +/// Serves as the provider's shared interface. Requires `Send + Sync` to allow transferring and +/// sharing resources (inputs, futures) across threads. +#[cfg_attr(any(feature = "testing", test), automock)] +#[async_trait] +pub trait L1ProviderClient: Send + Sync { + async fn start_block( + &self, + state: SessionState, + height: BlockNumber, + ) -> L1ProviderClientResult<()>; + + async fn get_txs( + &self, + n_txs: usize, + height: BlockNumber, + ) -> L1ProviderClientResult>; + + async fn validate( + &self, + _tx_hash: TransactionHash, + _height: BlockNumber, + ) -> L1ProviderClientResult; + + async fn commit_block( + &self, + l1_handler_tx_hashes: Vec, + height: BlockNumber, + ) -> L1ProviderClientResult<()>; + + async fn add_events(&self, events: Vec) -> L1ProviderClientResult<()>; + async fn initialize(&self, events: Vec) -> L1ProviderClientResult<()>; +} + +#[async_trait] +impl L1ProviderClient for ComponentClientType +where + ComponentClientType: Send + Sync + ComponentClient, +{ + #[instrument(skip(self))] + async fn start_block( + &self, + state: SessionState, + height: BlockNumber, + ) -> L1ProviderClientResult<()> { + let request = L1ProviderRequest::StartBlock { state, height }; + handle_all_response_variants!( + L1ProviderResponse, + StartBlock, + L1ProviderClientError, + L1ProviderError, + Direct + ) + } + + #[instrument(skip(self))] + async fn get_txs( + &self, + n_txs: usize, + height: BlockNumber, + ) -> L1ProviderClientResult> { + let request = L1ProviderRequest::GetTransactions { n_txs, height }; + handle_all_response_variants!( + L1ProviderResponse, + GetTransactions, + L1ProviderClientError, + L1ProviderError, + Direct + ) + } + + async fn validate( + &self, + tx_hash: TransactionHash, + height: BlockNumber, + ) -> L1ProviderClientResult { + let request = L1ProviderRequest::Validate { tx_hash, height }; + handle_all_response_variants!( + L1ProviderResponse, + Validate, + L1ProviderClientError, + L1ProviderError, + Direct + ) + } + + async fn commit_block( + &self, + l1_handler_tx_hashes: Vec, + height: BlockNumber, + ) -> L1ProviderClientResult<()> { + let request = L1ProviderRequest::CommitBlock { l1_handler_tx_hashes, height }; + handle_all_response_variants!( + L1ProviderResponse, + CommitBlock, + L1ProviderClientError, + L1ProviderError, + Direct + ) + } + + #[instrument(skip(self))] + async fn add_events(&self, events: Vec) -> L1ProviderClientResult<()> { + let request = L1ProviderRequest::AddEvents(events); + handle_all_response_variants!( + L1ProviderResponse, + AddEvents, + L1ProviderClientError, + L1ProviderError, + Direct + ) + } + + async fn initialize(&self, events: Vec) -> L1ProviderClientResult<()> { + let request = L1ProviderRequest::Initialize(events); + handle_all_response_variants!( + L1ProviderResponse, + Initialize, + L1ProviderClientError, + L1ProviderError, + Direct + ) + } +} + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] +pub enum Event { + L1HandlerTransaction(L1HandlerTransaction), + TransactionCanceled(L1Event), + TransactionCancellationStarted(L1Event), + TransactionConsumed(L1Event), +} + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] +pub enum SessionState { + Propose, + Validate, +} diff --git a/crates/starknet_mempool/Cargo.toml b/crates/starknet_mempool/Cargo.toml index efd35caccd1..f508dd9226f 100644 --- a/crates/starknet_mempool/Cargo.toml +++ b/crates/starknet_mempool/Cargo.toml @@ -5,32 +5,45 @@ edition.workspace = true repository.workspace = true license.workspace = true +[features] +testing = [] + [lints] workspace = true [dependencies] async-trait.workspace = true derive_more.workspace = true -mempool_test_utils = { workspace = true, optional = true } +papyrus_config.workspace = true papyrus_network_types.workspace = true -pretty_assertions = { workspace = true, optional = true } -starknet-types-core = { workspace = true, optional = true } +serde.workspace = true starknet_api.workspace = true starknet_sequencer_infra.workspace = true +starknet_sequencer_metrics.workspace = true starknet_mempool_p2p_types.workspace = true starknet_mempool_types.workspace = true +strum.workspace = true +strum_macros.workspace = true +tokio.workspace = true tracing.workspace = true +validator.workspace = true [dev-dependencies] assert_matches.workspace = true itertools.workspace = true +mempool_test_utils.workspace = true +metrics.workspace = true +metrics-exporter-prometheus.workspace = true +mockall.workspace = true +papyrus_network = { workspace = true, features = ["testing"] } +papyrus_network_types = { workspace = true, features = ["testing"] } +papyrus_test_utils.workspace = true +pretty_assertions.workspace = true rstest.workspace = true +starknet-types-core.workspace = true starknet_api = { workspace = true, features = ["testing"] } -# Enable test utils feature for integration tests. -starknet_mempool = { workspace = true, features = ["testing"] } - -[features] -testing = ["mempool_test_utils", "pretty_assertions", "starknet-types-core"] +starknet_mempool_p2p_types = { workspace = true, features = ["testing"] } +starknet_sequencer_metrics = { workspace = true, features = ["testing"] } [package.metadata.cargo-machete] ignored = ["starknet-types-core"] diff --git a/crates/starknet_mempool/src/communication.rs b/crates/starknet_mempool/src/communication.rs index 7acafea8669..c05bd6ff7e7 100644 --- a/crates/starknet_mempool/src/communication.rs +++ b/crates/starknet_mempool/src/communication.rs @@ -1,11 +1,10 @@ +use std::sync::Arc; + use async_trait::async_trait; use papyrus_network_types::network_types::BroadcastedMessageMetadata; -use starknet_api::executable_transaction::AccountTransaction; -use starknet_api::rpc_transaction::{ - RpcDeployAccountTransaction, - RpcInvokeTransaction, - RpcTransaction, -}; +use starknet_api::block::NonzeroGasPrice; +use starknet_api::core::ContractAddress; +use starknet_api::rpc_transaction::InternalRpcTransaction; use starknet_mempool_p2p_types::communication::SharedMempoolP2pPropagatorClient; use starknet_mempool_types::communication::{ AddTransactionArgsWrapper, @@ -13,20 +12,27 @@ use starknet_mempool_types::communication::{ MempoolResponse, }; use starknet_mempool_types::errors::MempoolError; -use starknet_mempool_types::mempool_types::{CommitBlockArgs, MempoolResult}; +use starknet_mempool_types::mempool_types::{CommitBlockArgs, MempoolResult, MempoolSnapshot}; use starknet_sequencer_infra::component_definitions::{ComponentRequestHandler, ComponentStarter}; use starknet_sequencer_infra::component_server::{LocalComponentServer, RemoteComponentServer}; +use crate::config::MempoolConfig; use crate::mempool::Mempool; +use crate::metrics::register_metrics; +use crate::utils::InstantClock; pub type LocalMempoolServer = LocalComponentServer; pub type RemoteMempoolServer = RemoteComponentServer; pub fn create_mempool( + config: MempoolConfig, mempool_p2p_propagator_client: SharedMempoolP2pPropagatorClient, ) -> MempoolCommunicationWrapper { - MempoolCommunicationWrapper::new(Mempool::default(), mempool_p2p_propagator_client) + MempoolCommunicationWrapper::new( + Mempool::new(config, Arc::new(InstantClock)), + mempool_p2p_propagator_client, + ) } /// Wraps the mempool to enable inbound async communication from other components. @@ -46,55 +52,58 @@ impl MempoolCommunicationWrapper { async fn send_tx_to_p2p( &self, message_metadata: Option, - tx: AccountTransaction, + tx: InternalRpcTransaction, ) -> MempoolResult<()> { match message_metadata { Some(message_metadata) => self .mempool_p2p_propagator_client .continue_propagation(message_metadata) .await - .map_err(|_| MempoolError::P2pPropagatorClientError { tx_hash: tx.tx_hash() }), + .map_err(|_| MempoolError::P2pPropagatorClientError { tx_hash: tx.tx_hash }), None => { - let tx_hash = tx.tx_hash(); - match tx { - AccountTransaction::Invoke(invoke_tx) => self - .mempool_p2p_propagator_client - .add_transaction(RpcTransaction::Invoke(RpcInvokeTransaction::V3( - invoke_tx.into(), - ))) - .await - .map_err(|_| MempoolError::P2pPropagatorClientError { tx_hash })?, - AccountTransaction::DeployAccount(deploy_account_tx) => self - .mempool_p2p_propagator_client - .add_transaction(RpcTransaction::DeployAccount( - RpcDeployAccountTransaction::V3(deploy_account_tx.into()), - )) - .await - .map_err(|_| MempoolError::P2pPropagatorClientError { tx_hash })?, - AccountTransaction::Declare(_) => {} - } + let tx_hash = tx.tx_hash; + self.mempool_p2p_propagator_client + .add_transaction(tx) + .await + .map_err(|_| MempoolError::P2pPropagatorClientError { tx_hash })?; Ok(()) } } } - async fn add_tx(&mut self, args_wrapper: AddTransactionArgsWrapper) -> MempoolResult<()> { + pub(crate) async fn add_tx( + &mut self, + args_wrapper: AddTransactionArgsWrapper, + ) -> MempoolResult<()> { self.mempool.add_tx(args_wrapper.args.clone())?; - // TODO: Verify that only transactions that were added to the mempool are sent. - // TODO: handle declare correctly and remove this match. - match args_wrapper.args.tx { - AccountTransaction::Declare(_) => Ok(()), - _ => self.send_tx_to_p2p(args_wrapper.p2p_message_metadata, args_wrapper.args.tx).await, - } + // TODO(AlonH): Verify that only transactions that were added to the mempool are sent. + self.send_tx_to_p2p(args_wrapper.p2p_message_metadata, args_wrapper.args.tx).await } fn commit_block(&mut self, args: CommitBlockArgs) -> MempoolResult<()> { - self.mempool.commit_block(args) + self.mempool.commit_block(args); + Ok(()) } - fn get_txs(&mut self, n_txs: usize) -> MempoolResult> { + fn get_txs(&mut self, n_txs: usize) -> MempoolResult> { self.mempool.get_txs(n_txs) } + + fn account_tx_in_pool_or_recent_block( + &self, + account_address: ContractAddress, + ) -> MempoolResult { + Ok(self.mempool.account_tx_in_pool_or_recent_block(account_address)) + } + + fn update_gas_price(&mut self, gas_price: NonzeroGasPrice) -> MempoolResult<()> { + self.mempool.update_gas_price(gas_price); + Ok(()) + } + + fn get_mempool_snapshot(&self) -> MempoolResult { + self.mempool.get_mempool_snapshot() + } } #[async_trait] @@ -110,8 +119,24 @@ impl ComponentRequestHandler for MempoolCommuni MempoolRequest::GetTransactions(n_txs) => { MempoolResponse::GetTransactions(self.get_txs(n_txs)) } + MempoolRequest::AccountTxInPoolOrRecentBlock(account_address) => { + MempoolResponse::AccountTxInPoolOrRecentBlock( + self.account_tx_in_pool_or_recent_block(account_address), + ) + } + MempoolRequest::UpdateGasPrice(gas_price) => { + MempoolResponse::UpdateGasPrice(self.update_gas_price(gas_price)) + } + MempoolRequest::GetMempoolSnapshot() => { + MempoolResponse::GetMempoolSnapshot(self.get_mempool_snapshot()) + } } } } -impl ComponentStarter for MempoolCommunicationWrapper {} +#[async_trait] +impl ComponentStarter for MempoolCommunicationWrapper { + async fn start(&mut self) { + register_metrics(); + } +} diff --git a/crates/starknet_mempool/src/config.rs b/crates/starknet_mempool/src/config.rs new file mode 100644 index 00000000000..5d40aa25ebc --- /dev/null +++ b/crates/starknet_mempool/src/config.rs @@ -0,0 +1,76 @@ +use std::collections::BTreeMap; +use std::time::Duration; + +use papyrus_config::converters::deserialize_seconds_to_duration; +use papyrus_config::dumping::{ser_param, SerializeConfig}; +use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; +use serde::{Deserialize, Serialize}; +use validator::Validate; + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Validate)] +pub struct MempoolConfig { + pub enable_fee_escalation: bool, + // TODO(AlonH): consider adding validations; should be bounded? + // Percentage increase for tip and max gas price to enable transaction replacement. + pub fee_escalation_percentage: u8, // E.g., 10 for a 10% increase. + // Time-to-live for transactions in the mempool, in seconds. + // Transactions older than this value will be lazily removed. + #[serde(deserialize_with = "deserialize_seconds_to_duration")] + pub transaction_ttl: Duration, + // Time to wait before allowing a Declare transaction to be returned in `get_txs`. + // Declare transactions are delayed to allow other nodes sufficient time to compile them. + #[serde(deserialize_with = "deserialize_seconds_to_duration")] + pub declare_delay: Duration, + // Number of latest committed blocks for which committed account nonces are preserved. + pub committed_nonce_retention_block_count: usize, +} + +impl Default for MempoolConfig { + fn default() -> Self { + MempoolConfig { + enable_fee_escalation: true, + fee_escalation_percentage: 10, + transaction_ttl: Duration::from_secs(60), // 1 minute. + declare_delay: Duration::from_secs(1), + committed_nonce_retention_block_count: 100, + } + } +} + +impl SerializeConfig for MempoolConfig { + fn dump(&self) -> BTreeMap { + BTreeMap::from_iter([ + ser_param( + "enable_fee_escalation", + &self.enable_fee_escalation, + "If true, transactions can be replaced with higher fee transactions.", + ParamPrivacyInput::Public, + ), + ser_param( + "fee_escalation_percentage", + &self.fee_escalation_percentage, + "Percentage increase for tip and max gas price to enable transaction replacement.", + ParamPrivacyInput::Public, + ), + ser_param( + "transaction_ttl", + &self.transaction_ttl.as_secs(), + "Time-to-live for transactions in the mempool, in seconds.", + ParamPrivacyInput::Public, + ), + ser_param( + "declare_delay", + &self.declare_delay.as_secs(), + "Time to wait before allowing a Declare transaction to be returned, in seconds.", + ParamPrivacyInput::Public, + ), + ser_param( + "committed_nonce_retention_block_count", + &self.committed_nonce_retention_block_count, + "Number of latest committed blocks for which committed account nonces are \ + retained.", + ParamPrivacyInput::Public, + ), + ]) + } +} diff --git a/crates/starknet_mempool/src/lib.rs b/crates/starknet_mempool/src/lib.rs index 2ff3401218a..12f4de4802e 100644 --- a/crates/starknet_mempool/src/lib.rs +++ b/crates/starknet_mempool/src/lib.rs @@ -1,9 +1,11 @@ pub mod communication; +pub mod config; pub mod mempool; +pub mod metrics; pub(crate) mod suspended_transaction_pool; pub(crate) mod transaction_pool; pub(crate) mod transaction_queue; pub(crate) mod utils; -#[cfg(any(feature = "testing", test))] +#[cfg(test)] pub mod test_utils; diff --git a/crates/starknet_mempool/src/mempool.rs b/crates/starknet_mempool/src/mempool.rs index 2962e47ba91..dd08d43bd3e 100644 --- a/crates/starknet_mempool/src/mempool.rs +++ b/crates/starknet_mempool/src/mempool.rs @@ -1,8 +1,10 @@ -use std::collections::HashMap; +use std::collections::{HashMap, VecDeque}; +use std::sync::Arc; +use std::time::Instant; -use starknet_api::block::GasPrice; +use starknet_api::block::NonzeroGasPrice; use starknet_api::core::{ContractAddress, Nonce}; -use starknet_api::executable_transaction::AccountTransaction; +use starknet_api::rpc_transaction::{InternalRpcTransaction, InternalRpcTransactionWithoutTxHash}; use starknet_api::transaction::fields::Tip; use starknet_api::transaction::TransactionHash; use starknet_mempool_types::errors::MempoolError; @@ -11,72 +13,83 @@ use starknet_mempool_types::mempool_types::{ AddTransactionArgs, CommitBlockArgs, MempoolResult, + MempoolSnapshot, +}; +use tracing::{debug, info, instrument, trace}; + +use crate::config::MempoolConfig; +use crate::metrics::{ + metric_count_committed_txs, + metric_count_expired_txs, + metric_count_rejected_txs, + metric_set_get_txs_size, + MempoolMetricHandle, }; - use crate::transaction_pool::TransactionPool; use crate::transaction_queue::TransactionQueue; -use crate::utils::try_increment_nonce; +use crate::utils::{try_increment_nonce, Clock}; #[cfg(test)] #[path = "mempool_test.rs"] pub mod mempool_test; +#[cfg(test)] +#[path = "mempool_flow_tests.rs"] +pub mod mempool_flow_tests; + +type AddressToNonce = HashMap; + #[derive(Debug)] -pub struct MempoolConfig { - enable_fee_escalation: bool, - // TODO: consider adding validations; should be bounded? - // Percentage increase for tip and max gas price to enable transaction replacement. - fee_escalation_percentage: u8, // E.g., 10 for a 10% increase. +#[cfg_attr(test, derive(Clone))] +struct CommitHistory { + commits: VecDeque, } -impl Default for MempoolConfig { - fn default() -> Self { - MempoolConfig { enable_fee_escalation: true, fee_escalation_percentage: 10 } +impl CommitHistory { + fn new(capacity: usize) -> Self { + CommitHistory { commits: std::iter::repeat(AddressToNonce::new()).take(capacity).collect() } } -} -type AddressToNonce = HashMap; + fn push(&mut self, commit: AddressToNonce) -> AddressToNonce { + let removed = self.commits.pop_front(); + self.commits.push_back(commit); + removed.expect("Commit history should be initialized with capacity.") + } +} /// Represents the state tracked by the mempool. /// It is partitioned into categories, each serving a distinct role in the lifecycle of transaction /// management. -#[derive(Debug, Default)] +#[derive(Debug)] +#[cfg_attr(test, derive(Clone))] pub struct MempoolState { + /// Records recent commit_block events to preserve the committed nonces of the latest blocks. + commit_history: CommitHistory, /// Finalized nonces committed in blocks. committed: AddressToNonce, /// Provisionally incremented nonces during block creation. staged: AddressToNonce, - /// Temporary information on accounts that haven't appeared in recent blocks, - /// nor proposed for sequencing. - tentative: AddressToNonce, } impl MempoolState { - fn get(&self, address: ContractAddress) -> Option { + fn new(committed_nonce_retention_block_count: usize) -> Self { + MempoolState { + commit_history: CommitHistory::new(committed_nonce_retention_block_count), + committed: HashMap::new(), + staged: HashMap::new(), + } + } + + fn resolve_nonce(&self, address: ContractAddress, incoming_account_nonce: Nonce) -> Nonce { self.staged .get(&address) .or_else(|| self.committed.get(&address)) - .or_else(|| self.tentative.get(&address)) .copied() + .unwrap_or(incoming_account_nonce) } - fn get_or_insert(&mut self, address: ContractAddress, nonce: Nonce) -> Nonce { - if let Some(staged_or_committed_nonce) = - self.staged.get(&address).or_else(|| self.committed.get(&address)).copied() - { - return staged_or_committed_nonce; - } - - let tentative_nonce = self - .tentative - .entry(address) - .and_modify(|tentative_nonce| { - if nonce > *tentative_nonce { - *tentative_nonce = nonce; - } - }) - .or_insert(nonce); - *tentative_nonce + fn contains_account(&self, address: ContractAddress) -> bool { + self.staged.contains_key(&address) || self.committed.contains_key(&address) } fn stage(&mut self, tx_reference: &TransactionReference) -> MempoolResult<()> { @@ -100,16 +113,34 @@ impl MempoolState { .copied() .collect(); - self.tentative.retain(|address, _| !address_to_nonce.contains_key(address)); - self.committed.extend(address_to_nonce); + self.committed.extend(address_to_nonce.clone()); self.staged.clear(); + // Add the commit event to the history. + // If an old event has been removed (due to history size limit), delete the associated + // committed nonces. + let removed_commit = self.commit_history.push(address_to_nonce); + for (address, removed_nonce) in removed_commit { + let last_committed_nonce = *self + .committed + .get(&address) + .expect("Account in commit history must appear in the committed nonces."); + if last_committed_nonce == removed_nonce { + self.committed.remove(&address); + } + } + addresses_to_rewind } - fn validate_incoming_tx(&self, tx_reference: TransactionReference) -> MempoolResult<()> { + fn validate_incoming_tx( + &self, + tx_reference: TransactionReference, + incoming_account_nonce: Nonce, + ) -> MempoolResult<()> { let TransactionReference { address, nonce: tx_nonce, .. } = tx_reference; - if self.get(address).is_some_and(|existing_nonce| tx_nonce < existing_nonce) { + let account_nonce = self.resolve_nonce(address, incoming_account_nonce); + if tx_nonce < account_nonce { return Err(MempoolError::NonceTooOld { address, nonce: tx_nonce }); } @@ -132,18 +163,47 @@ impl MempoolState { } } -#[derive(Debug, Default)] pub struct Mempool { config: MempoolConfig, - // TODO: add docstring explaining visibility and coupling of the fields. - // All transactions currently held in the mempool. + // TODO(AlonH): add docstring explaining visibility and coupling of the fields. + // Declare transactions that are waiting to be added to the tx pool after a delay. + delayed_declares: VecDeque<(Instant, AddTransactionArgs)>, + // All transactions currently held in the mempool (excluding the delayed declares). tx_pool: TransactionPool, // Transactions eligible for sequencing. tx_queue: TransactionQueue, state: MempoolState, + clock: Arc, } impl Mempool { + pub fn new(config: MempoolConfig, clock: Arc) -> Self { + Mempool { + config: config.clone(), + delayed_declares: VecDeque::new(), + tx_pool: TransactionPool::new(clock.clone()), + tx_queue: TransactionQueue::default(), + state: MempoolState::new(config.committed_nonce_retention_block_count), + clock, + } + } + + pub fn priority_queue_len(&self) -> usize { + self.tx_queue.priority_queue_len() + } + + pub fn pending_queue_len(&self) -> usize { + self.tx_queue.pending_queue_len() + } + + pub fn tx_pool_len(&self) -> usize { + self.tx_pool.capacity() + } + + pub fn delayed_declares_len(&self) -> usize { + self.delayed_declares.len() + } + /// Returns an iterator of the current eligible transactions for sequencing, ordered by their /// priority. pub fn iter(&self) -> impl Iterator { @@ -153,17 +213,20 @@ impl Mempool { /// Retrieves up to `n_txs` transactions with the highest priority from the mempool. /// Transactions are guaranteed to be unique across calls until the block in-progress is /// created. - // TODO: Consider renaming to `pop_txs` to be more consistent with the standard library. - #[tracing::instrument(skip(self), err)] - pub fn get_txs(&mut self, n_txs: usize) -> MempoolResult> { + // TODO(AlonH): Consider renaming to `pop_txs` to be more consistent with the standard library. + #[instrument(skip(self), err)] + pub fn get_txs(&mut self, n_txs: usize) -> MempoolResult> { + self.add_ready_declares(); let mut eligible_tx_references: Vec = Vec::with_capacity(n_txs); let mut n_remaining_txs = n_txs; while n_remaining_txs > 0 && self.tx_queue.has_ready_txs() { let chunk = self.tx_queue.pop_ready_chunk(n_remaining_txs); - self.enqueue_next_eligible_txs(&chunk)?; - n_remaining_txs -= chunk.len(); - eligible_tx_references.extend(chunk); + let valid_txs = self.prune_expired_nonqueued_txs(chunk); + + self.enqueue_next_eligible_txs(&valid_txs)?; + n_remaining_txs -= valid_txs.len(); + eligible_tx_references.extend(valid_txs); } // Update the mempool state with the given transactions' nonces. @@ -171,10 +234,17 @@ impl Mempool { self.state.stage(tx_reference)?; } - tracing::debug!( + info!( "Returned {} out of {n_txs} transactions, ready for sequencing.", eligible_tx_references.len() ); + debug!( + "Returned mempool txs: {:#?}", + eligible_tx_references.iter().map(|tx| tx.tx_hash).collect::>() + ); + + metric_set_get_txs_size(eligible_tx_references.len()); + self.update_state_metrics(); Ok(eligible_tx_references .iter() @@ -188,42 +258,81 @@ impl Mempool { } /// Adds a new transaction to the mempool. - #[tracing::instrument( + #[instrument( skip(self, args), fields( // Log subset of (informative) fields. tx_nonce = %args.tx.nonce(), - tx_hash = %args.tx.tx_hash(), - tx_tip = %tip(&args.tx), - tx_max_l2_gas_price = %max_l2_gas_price(&args.tx), + tx_hash = %args.tx.tx_hash, + tx_tip = %args.tx.tip(), + tx_max_l2_gas_price = %args.tx.resource_bounds().l2_gas.max_price_per_unit, account_state = %args.account_state ), err )] pub fn add_tx(&mut self, args: AddTransactionArgs) -> MempoolResult<()> { + let mut metric_handle = MempoolMetricHandle::new(&args.tx.tx); + metric_handle.count_transaction_received(); + + // First remove old transactions from the pool. + self.remove_expired_txs(); + self.add_ready_declares(); + + let tx_reference = TransactionReference::new(&args.tx); + self.validate_incoming_tx(tx_reference, args.account_state.nonce)?; + self.handle_fee_escalation(&args.tx)?; + + metric_handle.transaction_inserted(); + + if let InternalRpcTransactionWithoutTxHash::Declare(_) = &args.tx.tx { + self.delayed_declares.push_back((self.clock.now(), args)); + } else { + self.add_tx_inner(args); + } + + self.update_state_metrics(); + Ok(()) + } + + fn add_tx_inner(&mut self, args: AddTransactionArgs) { let AddTransactionArgs { tx, account_state } = args; + info!("Adding transaction to mempool."); + trace!("{tx:#?}"); + let tx_reference = TransactionReference::new(&tx); - self.validate_incoming_tx(tx_reference)?; - self.handle_fee_escalation(&tx)?; - self.tx_pool.insert(tx)?; + self.tx_pool.insert(tx).expect("Duplicate transactions should error in validation stage."); - // Align to account nonce, only if it is at least the one stored. let AccountState { address, nonce: incoming_account_nonce } = account_state; - let stored_account_nonce = self.state.get_or_insert(address, incoming_account_nonce); - if tx_reference.nonce == stored_account_nonce { + let account_nonce = self.state.resolve_nonce(address, incoming_account_nonce); + if tx_reference.nonce == account_nonce { self.tx_queue.remove(address); self.tx_queue.insert(tx_reference); } + } - Ok(()) + fn add_ready_declares(&mut self) { + let now = self.clock.now(); + while let Some((submission_time, _args)) = self.delayed_declares.front() { + if now - *submission_time < self.config.declare_delay { + break; + } + let (_submission_time, args) = + self.delayed_declares.pop_front().expect("Delay declare should exist."); + self.add_tx_inner(args); + } + self.update_state_metrics(); } /// Update the mempool's internal state according to the committed block (resolves nonce gaps, /// updates account balances). - #[tracing::instrument(skip(self, args), err)] - pub fn commit_block(&mut self, args: CommitBlockArgs) -> MempoolResult<()> { - let CommitBlockArgs { address_to_nonce, tx_hashes } = args; - tracing::debug!("Committing block with {} transactions to mempool.", tx_hashes.len()); + #[instrument(skip(self, args))] + pub fn commit_block(&mut self, args: CommitBlockArgs) { + let CommitBlockArgs { address_to_nonce, rejected_tx_hashes } = args; + debug!( + "Committing block with {} addresses and {} rejected tx to the mempool.", + address_to_nonce.len(), + rejected_tx_hashes.len() + ); // Align mempool data to committed nonces. for (&address, &next_nonce) in &address_to_nonce { @@ -239,7 +348,8 @@ impl Mempool { } // Remove from pool. - self.tx_pool.remove_up_to_nonce(address, next_nonce); + let n_removed_txs = self.tx_pool.remove_up_to_nonce(address, next_nonce); + metric_count_committed_txs(n_removed_txs); // Maybe close nonce gap. if self.tx_queue.get_nonce(address).is_none() { @@ -255,42 +365,75 @@ impl Mempool { let addresses_to_rewind = self.state.commit(address_to_nonce); for address in addresses_to_rewind { // Account nonce is the minimal nonce of this address: it was proposed but not included. - let tx_reference = self - .tx_pool - .account_txs_sorted_by_nonce(address) - .next() - .expect("Address {address} should appear in transaction pool."); + let tx_reference = + self.tx_pool.account_txs_sorted_by_nonce(address).next().unwrap_or_else(|| { + panic!("Address {address} should appear in transaction pool.") + }); self.tx_queue.remove(address); self.tx_queue.insert(*tx_reference); } - tracing::debug!("Aligned mempool to committed nonces."); + debug!("Aligned mempool to committed nonces."); - // Hard-delete: finally, remove committed transactions from the mempool. - for tx_hash in tx_hashes { - let Ok(_tx) = self.tx_pool.remove(tx_hash) else { + // Remove rejected transactions from the mempool. + metric_count_rejected_txs(rejected_tx_hashes.len()); + for tx_hash in rejected_tx_hashes { + if let Ok(tx) = self.tx_pool.remove(tx_hash) { + self.tx_queue.remove(tx.contract_address()); + } else { continue; // Transaction hash unknown to mempool, from a different node. }; // TODO(clean_accounts): remove address with no transactions left after a block cycle / // TTL. } - tracing::debug!("Removed committed transactions known to mempool."); + debug!("Removed rejected transactions known to mempool."); - Ok(()) + self.update_state_metrics(); + } + + pub fn account_tx_in_pool_or_recent_block(&self, account_address: ContractAddress) -> bool { + self.state.contains_account(account_address) + || self.tx_pool.contains_account(account_address) + } + + fn validate_incoming_tx( + &self, + tx_reference: TransactionReference, + incoming_account_nonce: Nonce, + ) -> MempoolResult<()> { + if self.tx_pool.get_by_tx_hash(tx_reference.tx_hash).is_ok() { + return Err(MempoolError::DuplicateTransaction { tx_hash: tx_reference.tx_hash }); + } + self.state.validate_incoming_tx(tx_reference, incoming_account_nonce) } - fn validate_incoming_tx(&self, tx_reference: TransactionReference) -> MempoolResult<()> { - self.state.validate_incoming_tx(tx_reference) + /// Validates that the given transaction does not front run a delayed declare. This means in + /// particular that no fee escalation can occur to a declare that is being delayed. + fn validate_no_delayed_declare_front_run( + &self, + tx_reference: TransactionReference, + ) -> MempoolResult<()> { + if self.delayed_declares.iter().any(|(_, tx_args)| { + let tx = &tx_args.tx; + tx.contract_address() == tx_reference.address && tx.nonce() == tx_reference.nonce + }) { + return Err(MempoolError::DuplicateNonce { + address: tx_reference.address, + nonce: tx_reference.nonce, + }); + } + Ok(()) } fn validate_commitment(&self, address: ContractAddress, next_nonce: Nonce) { self.state.validate_commitment(address, next_nonce); } - // TODO(Mohammad): Rename this method once consensus API is added. - pub fn update_gas_price_threshold(&mut self, threshold: GasPrice) { + /// Updates the gas price threshold for transactions that are eligible for sequencing. + pub fn update_gas_price(&mut self, threshold: NonzeroGasPrice) { self.tx_queue.update_gas_price_threshold(threshold); + self.update_state_metrics(); } fn enqueue_next_eligible_txs(&mut self, txs: &[TransactionReference]) -> MempoolResult<()> { @@ -307,11 +450,13 @@ impl Mempool { Ok(()) } - #[tracing::instrument(level = "debug", skip(self, incoming_tx), err)] - fn handle_fee_escalation(&mut self, incoming_tx: &AccountTransaction) -> MempoolResult<()> { + #[instrument(level = "debug", skip(self, incoming_tx), err)] + fn handle_fee_escalation(&mut self, incoming_tx: &InternalRpcTransaction) -> MempoolResult<()> { let incoming_tx_reference = TransactionReference::new(incoming_tx); let TransactionReference { address, nonce, .. } = incoming_tx_reference; + self.validate_no_delayed_declare_front_run(incoming_tx_reference)?; + if !self.config.enable_fee_escalation { if self.tx_pool.get_by_address_and_nonce(address, nonce).is_some() { return Err(MempoolError::DuplicateNonce { address, nonce }); @@ -327,7 +472,7 @@ impl Mempool { }; if !self.should_replace_tx(&existing_tx_reference, &incoming_tx_reference) { - tracing::debug!( + debug!( "{existing_tx_reference} was not replaced by {incoming_tx_reference} due to insufficient fee escalation." ); @@ -335,9 +480,9 @@ impl Mempool { return Err(MempoolError::DuplicateNonce { address, nonce }); } - tracing::debug!("{existing_tx_reference} will be replaced by {incoming_tx_reference}."); + debug!("{existing_tx_reference} will be replaced by {incoming_tx_reference}."); - self.tx_queue.remove(address); + self.tx_queue.remove_txs(&[existing_tx_reference]); self.tx_pool .remove(existing_tx_reference.tx_hash) .expect("Transaction hash from pool must exist."); @@ -353,7 +498,7 @@ impl Mempool { let [existing_tip, incoming_tip] = [existing_tx, incoming_tx].map(|tx| u128::from(tx.tip.0)); let [existing_max_l2_gas_price, incoming_max_l2_gas_price] = - [existing_tx, incoming_tx].map(|tx| tx.max_l2_gas_price.0); + [existing_tx, incoming_tx].map(|tx| tx.max_l2_gas_price.get().0); self.increased_enough(existing_tip, incoming_tip) && self.increased_enough(existing_max_l2_gas_price, incoming_max_l2_gas_price) @@ -362,6 +507,9 @@ impl Mempool { fn increased_enough(&self, existing_value: u128, incoming_value: u128) -> bool { let percentage = u128::from(self.config.fee_escalation_percentage); + // Note: To reduce precision loss, we first multiply by the percentage and then divide by + // 100. This could cause an overflow and an automatic rejection of the transaction, but the + // values aren't expected to be large enough for this to be an issue. let Some(escalation_qualified_value) = existing_value .checked_mul(percentage) .map(|v| v / 100) @@ -373,15 +521,65 @@ impl Mempool { incoming_value >= escalation_qualified_value } -} -// TODO(Elin): move to a shared location with other next-gen node crates. -fn tip(tx: &AccountTransaction) -> Tip { - tx.tip() + fn remove_expired_txs(&mut self) { + let removed_txs = + self.tx_pool.remove_txs_older_than(self.config.transaction_ttl, &self.state.staged); + self.tx_queue.remove_txs(&removed_txs); + + metric_count_expired_txs(removed_txs.len()); + self.update_state_metrics(); + } + + /// Given a chunk of transactions, removes from the pool those that are old, and returns the + /// remaining valid ones. + /// Note: This function assumes that the given transactions were already removed from the queue. + fn prune_expired_nonqueued_txs( + &mut self, + txs: Vec, + ) -> Vec { + // Divide the chunk into transactions that are old and no longer valid and those that + // remain valid. + let submission_cutoff_time = self.clock.now() - self.config.transaction_ttl; + let (old_txs, valid_txs): (Vec<_>, Vec<_>) = txs.into_iter().partition(|tx| { + let tx_submission_time = self + .tx_pool + .get_submission_time(tx.tx_hash) + .expect("Transaction hash from queue must appear in pool."); + tx_submission_time < submission_cutoff_time + }); + + // Remove old transactions from the pool. + metric_count_expired_txs(old_txs.len()); + for tx in old_txs { + self.tx_pool + .remove(tx.tx_hash) + .expect("Transaction hash from queue must appear in pool."); + } + + valid_txs + } + + pub fn get_mempool_snapshot(&self) -> MempoolResult { + Ok(MempoolSnapshot { transactions: self.tx_pool.get_chronological_txs_hashes() }) + } + + #[cfg(test)] + fn content(&self) -> MempoolContent { + MempoolContent { + tx_pool: self.tx_pool.tx_pool(), + priority_txs: self.tx_queue.iter_over_ready_txs().cloned().collect(), + pending_txs: self.tx_queue.pending_txs(), + } + } } -fn max_l2_gas_price(tx: &AccountTransaction) -> GasPrice { - tx.resource_bounds().get_l2_bounds().max_price_per_unit +#[cfg(test)] +#[derive(Debug, Default, PartialEq, Eq)] +struct MempoolContent { + tx_pool: HashMap, + priority_txs: Vec, + pending_txs: Vec, } /// Provides a lightweight representation of a transaction for mempool usage (e.g., excluding @@ -394,17 +592,18 @@ pub struct TransactionReference { pub nonce: Nonce, pub tx_hash: TransactionHash, pub tip: Tip, - pub max_l2_gas_price: GasPrice, + pub max_l2_gas_price: NonzeroGasPrice, } impl TransactionReference { - pub fn new(tx: &AccountTransaction) -> Self { + pub fn new(tx: &InternalRpcTransaction) -> Self { TransactionReference { address: tx.contract_address(), nonce: tx.nonce(), tx_hash: tx.tx_hash(), - tip: tip(tx), - max_l2_gas_price: max_l2_gas_price(tx), + tip: tx.tip(), + max_l2_gas_price: NonzeroGasPrice::new(tx.resource_bounds().l2_gas.max_price_per_unit) + .expect("Max L2 gas price must be non-zero."), } } } diff --git a/crates/starknet_mempool/tests/flow_test.rs b/crates/starknet_mempool/src/mempool_flow_tests.rs similarity index 81% rename from crates/starknet_mempool/tests/flow_test.rs rename to crates/starknet_mempool/src/mempool_flow_tests.rs index af279711a97..4edb95c712c 100644 --- a/crates/starknet_mempool/tests/flow_test.rs +++ b/crates/starknet_mempool/src/mempool_flow_tests.rs @@ -1,21 +1,26 @@ +use std::sync::Arc; + use rstest::{fixture, rstest}; -use starknet_api::block::GasPrice; +use starknet_api::block::{GasPrice, NonzeroGasPrice}; use starknet_api::{contract_address, nonce}; -use starknet_mempool::add_tx_input; -use starknet_mempool::mempool::Mempool; -use starknet_mempool::test_utils::{ +use starknet_mempool_types::errors::MempoolError; + +use crate::add_tx_input; +use crate::config::MempoolConfig; +use crate::mempool::Mempool; +use crate::test_utils::{ add_tx, add_tx_expect_error, commit_block, get_txs_and_assert_expected, + FakeClock, }; -use starknet_mempool_types::errors::MempoolError; // Fixtures. #[fixture] fn mempool() -> Mempool { - Mempool::default() + Mempool::new(MempoolConfig::default(), Arc::new(FakeClock::default())) } // Tests. @@ -88,8 +93,7 @@ fn test_add_same_nonce_tx_after_previous_not_included_in_block(mut mempool: Memp ); let nonces = [("0x0", 4)]; // Transaction with nonce 3 was included, 4 was not. - let tx_hashes = [1]; - commit_block(&mut mempool, nonces, tx_hashes); + commit_block(&mut mempool, nonces, []); let tx_nonce_4_account_nonce_4 = add_tx_input!(tx_hash: 4, address: "0x0", tx_nonce: 4, account_nonce: 4); @@ -178,8 +182,7 @@ fn test_commit_block_includes_proposed_txs_subset(mut mempool: Mempool) { // Address 0x0 stays as proposed, address 0x1 rewinds nonce 4, address 0x2 rewinds completely. let nonces = [("0x0", 2), ("0x1", 4)]; - let tx_hashes = [1, 4]; - commit_block(&mut mempool, nonces, tx_hashes); + commit_block(&mut mempool, nonces, []); get_txs_and_assert_expected( &mut mempool, @@ -204,8 +207,7 @@ fn test_commit_block_fills_nonce_gap(mut mempool: Mempool) { get_txs_and_assert_expected(&mut mempool, 2, &[tx_nonce_3_account_nonce_3.tx]); let nonces = [("0x0", 5)]; - let tx_hashes = [1, 3]; - commit_block(&mut mempool, nonces, tx_hashes); + commit_block(&mut mempool, nonces, []); // Assert: hole was indeed closed. let tx_nonce_4_account_nonce_4 = @@ -249,11 +251,10 @@ fn test_commit_block_rewinds_queued_nonce(mut mempool: Mempool) { ); // Test. - let nonces = [("0x0", 3)]; - let tx_hashes = [1]; // Address 0x0: nonce 2 was accepted, but 3 was not, so is rewound. // Address 0x1: nonce 2 was not accepted, both 2 and 3 were rewound. - commit_block(&mut mempool, nonces, tx_hashes); + let nonces = [("0x0", 3)]; + commit_block(&mut mempool, nonces, []); // Nonces 3 and 4 were re-enqueued correctly. get_txs_and_assert_expected( @@ -266,7 +267,7 @@ fn test_commit_block_rewinds_queued_nonce(mut mempool: Mempool) { #[rstest] fn test_commit_block_from_different_leader(mut mempool: Mempool) { // Setup. - // TODO: set the mempool to `validate` mode once supported. + // TODO(AlonH): set the mempool to `validate` mode once supported. let tx_nonce_2 = add_tx_input!(tx_hash: 1, address: "0x0", tx_nonce: 2, account_nonce: 2); let tx_nonce_3 = add_tx_input!(tx_hash: 2, address: "0x0", tx_nonce: 3, account_nonce: 2); @@ -277,13 +278,11 @@ fn test_commit_block_from_different_leader(mut mempool: Mempool) { } // Test. + // Address 0: known hash accepted for nonce 2. + // Address 0: unknown hash accepted for nonce 3. + // Unknown Address 1 (with unknown hash) for nonce 2. let nonces = [("0x0", 4), ("0x1", 2)]; - let tx_hashes = [ - 1, // Address 0: known hash accepted for nonce 2. - 99, // Address 0: unknown hash accepted for nonce 3. - 4, // Unknown Address 1 (with unknown hash) for nonce 2. - ]; - commit_block(&mut mempool, nonces, tx_hashes); + commit_block(&mut mempool, nonces, []); // Assert: two stale transactions were removed, one was added to a block by a different leader // and the other "lost" to a different transaction with the same nonce that was added by the @@ -300,16 +299,43 @@ fn test_update_gas_price_threshold(mut mempool: Mempool) { add_tx_input!(tx_hash: 2, address: "0x1", tip: 50, max_l2_gas_price: 30); // Test: only txs with gas price above the threshold are returned. - mempool.update_gas_price_threshold(GasPrice(30)); + mempool.update_gas_price(NonzeroGasPrice::new_unchecked(GasPrice(30))); for input in [&input_gas_price_20, &input_gas_price_30] { add_tx(&mut mempool, input); } get_txs_and_assert_expected(&mut mempool, 2, &[input_gas_price_30.tx]); let nonces = [("0x1", 1)]; - let tx_hashes = [2]; - commit_block(&mut mempool, nonces, tx_hashes); + commit_block(&mut mempool, nonces, []); - mempool.update_gas_price_threshold(GasPrice(10)); + mempool.update_gas_price(NonzeroGasPrice::new_unchecked(GasPrice(10))); get_txs_and_assert_expected(&mut mempool, 2, &[input_gas_price_20.tx]); } + +/// Test that the API function [Mempool::account_tx_in_pool_or_recent_block] behaves as expected +/// under various conditions. +#[rstest] +fn mempool_state_retains_address_across_api_calls(mut mempool: Mempool) { + // Setup. + let address = "0x1"; + let input_address_1 = add_tx_input!(address: address); + let account_address = contract_address!(address); + + // Test. + add_tx(&mut mempool, &input_address_1); + // Assert: Mempool state includes the address of the added transaction. + assert!(mempool.account_tx_in_pool_or_recent_block(account_address)); + + // Test. + mempool.get_txs(1).unwrap(); + // Assert: The Mempool state still contains the address, even after it was sent to the batcher. + assert!(mempool.account_tx_in_pool_or_recent_block(account_address)); + + // Test. + let nonces = [(address, 1)]; + commit_block(&mut mempool, nonces, []); + // Assert: Mempool state still contains the address, even though the transaction was committed. + // Note that in the future, the Mempool's state may be periodically cleared from records of old + // committed transactions. Mirroring this behavior may require a modification of this test. + assert!(mempool.account_tx_in_pool_or_recent_block(account_address)); +} diff --git a/crates/starknet_mempool/src/mempool_test.rs b/crates/starknet_mempool/src/mempool_test.rs index 08ab9ad79d1..a2053312000 100644 --- a/crates/starknet_mempool/src/mempool_test.rs +++ b/crates/starknet_mempool/src/mempool_test.rs @@ -1,18 +1,38 @@ +use std::collections::{HashMap, VecDeque}; +use std::sync::Arc; +use std::time::Duration; + +use mempool_test_utils::starknet_api_test_utils::test_valid_resource_bounds; +use metrics_exporter_prometheus::PrometheusBuilder; +use mockall::predicate; +use papyrus_network_types::network_types::BroadcastedMessageMetadata; +use papyrus_test_utils::{get_rng, GetTestInstance}; use pretty_assertions::assert_eq; use rstest::{fixture, rstest}; -use starknet_api::block::GasPrice; -use starknet_api::executable_transaction::AccountTransaction; -use starknet_api::{contract_address, nonce}; +use starknet_api::block::{GasPrice, NonzeroGasPrice}; +use starknet_api::rpc_transaction::InternalRpcTransaction; +use starknet_api::test_utils::declare::{internal_rpc_declare_tx, DeclareTxArgs}; +use starknet_api::transaction::TransactionHash; +use starknet_api::{contract_address, declare_tx_args, nonce, tx_hash}; +use starknet_mempool_p2p_types::communication::MockMempoolP2pPropagatorClient; +use starknet_mempool_types::communication::AddTransactionArgsWrapper; use starknet_mempool_types::errors::MempoolError; -use starknet_mempool_types::mempool_types::AddTransactionArgs; - -use crate::mempool::{Mempool, MempoolConfig, TransactionReference}; -use crate::test_utils::{add_tx, add_tx_expect_error, commit_block, get_txs_and_assert_expected}; -use crate::transaction_pool::TransactionPool; -use crate::transaction_queue::transaction_queue_test_utils::{ - TransactionQueueContent, - TransactionQueueContentBuilder, +use starknet_mempool_types::mempool_types::{AccountState, AddTransactionArgs}; +use starknet_sequencer_metrics::metrics::HistogramValue; + +use crate::communication::MempoolCommunicationWrapper; +use crate::mempool::{Mempool, MempoolConfig, MempoolContent, MempoolState, TransactionReference}; +use crate::metrics::register_metrics; +use crate::test_utils::{ + add_tx, + add_tx_expect_error, + commit_block, + get_txs_and_assert_expected, + FakeClock, + MempoolMetrics, }; +use crate::transaction_pool::TransactionPool; +use crate::transaction_queue::TransactionQueue; use crate::{add_tx_input, tx}; // Utils. @@ -20,61 +40,50 @@ use crate::{add_tx_input, tx}; /// Represents the internal content of the mempool. /// Enables customized (and potentially inconsistent) creation for unit testing. #[derive(Debug, Default)] -struct MempoolContent { - config: MempoolConfig, - tx_pool: Option, - tx_queue_content: Option, +struct MempoolTestContent { + pub tx_pool: Option>, + pub priority_txs: Option>, + pub pending_txs: Option>, } -impl MempoolContent { +impl MempoolTestContent { #[track_caller] - fn assert_eq(&self, mempool: &Mempool) { + fn assert_eq(&self, mempool_content: &MempoolContent) { if let Some(tx_pool) = &self.tx_pool { - assert_eq!(&mempool.tx_pool, tx_pool); + assert_eq!(&mempool_content.tx_pool, tx_pool); } - if let Some(tx_queue_content) = &self.tx_queue_content { - tx_queue_content.assert_eq(&mempool.tx_queue); + if let Some(priority_txs) = &self.priority_txs { + assert_eq!(&mempool_content.priority_txs, priority_txs); } - } -} -impl From for Mempool { - fn from(mempool_content: MempoolContent) -> Mempool { - let MempoolContent { tx_pool, tx_queue_content, config } = mempool_content; - Mempool { - config, - tx_pool: tx_pool.unwrap_or_default(), - tx_queue: tx_queue_content - .map(|content| content.complete_to_tx_queue()) - .unwrap_or_default(), - // TODO: Add implementation when needed. - state: Default::default(), + if let Some(pending_txs) = &self.pending_txs { + assert_eq!(&mempool_content.pending_txs, pending_txs); } } } #[derive(Debug)] -struct MempoolContentBuilder { +struct MempoolTestContentBuilder { config: MempoolConfig, - tx_pool: Option, - tx_queue_content_builder: TransactionQueueContentBuilder, + content: MempoolTestContent, + gas_price_threshold: NonzeroGasPrice, } -impl MempoolContentBuilder { +impl MempoolTestContentBuilder { fn new() -> Self { Self { config: MempoolConfig { enable_fee_escalation: false, ..Default::default() }, - tx_pool: None, - tx_queue_content_builder: Default::default(), + content: MempoolTestContent::default(), + gas_price_threshold: NonzeroGasPrice::default(), } } fn with_pool

(mut self, pool_txs: P) -> Self where - P: IntoIterator, + P: IntoIterator, { - self.tx_pool = Some(pool_txs.into_iter().collect()); + self.content.tx_pool = Some(pool_txs.into_iter().map(|tx| (tx.tx_hash, tx)).collect()); self } @@ -82,7 +91,7 @@ impl MempoolContentBuilder { where Q: IntoIterator, { - self.tx_queue_content_builder = self.tx_queue_content_builder.with_priority(queue_txs); + self.content.priority_txs = Some(queue_txs.into_iter().collect()); self } @@ -90,37 +99,47 @@ impl MempoolContentBuilder { where Q: IntoIterator, { - self.tx_queue_content_builder = self.tx_queue_content_builder.with_pending(queue_txs); + self.content.pending_txs = Some(queue_txs.into_iter().collect()); self } fn with_gas_price_threshold(mut self, gas_price_threshold: u128) -> Self { - self.tx_queue_content_builder = - self.tx_queue_content_builder.with_gas_price_threshold(gas_price_threshold); + self.gas_price_threshold = NonzeroGasPrice::new_unchecked(gas_price_threshold.into()); self } fn with_fee_escalation_percentage(mut self, fee_escalation_percentage: u8) -> Self { - self.config = MempoolConfig { enable_fee_escalation: true, fee_escalation_percentage }; + self.config = MempoolConfig { + enable_fee_escalation: true, + fee_escalation_percentage, + ..Default::default() + }; self } - fn build(self) -> MempoolContent { - MempoolContent { - config: self.config, - tx_pool: self.tx_pool, - tx_queue_content: self.tx_queue_content_builder.build(), - } + fn build(self) -> MempoolTestContent { + self.content } - fn build_into_mempool(self) -> Mempool { - self.build().into() + fn build_full_mempool(self) -> Mempool { + Mempool { + config: self.config.clone(), + delayed_declares: VecDeque::new(), + tx_pool: self.content.tx_pool.unwrap_or_default().into_values().collect(), + tx_queue: TransactionQueue::new( + self.content.priority_txs.unwrap_or_default(), + self.content.pending_txs.unwrap_or_default(), + self.gas_price_threshold, + ), + state: MempoolState::new(self.config.committed_nonce_retention_block_count), + clock: Arc::new(FakeClock::default()), + } } } -impl FromIterator for TransactionPool { - fn from_iter>(txs: T) -> Self { - let mut pool = Self::default(); +impl FromIterator for TransactionPool { + fn from_iter>(txs: T) -> Self { + let mut pool = Self::new(Arc::new(FakeClock::default())); for tx in txs { pool.insert(tx).unwrap(); } @@ -128,6 +147,37 @@ impl FromIterator for TransactionPool { } } +fn declare_add_tx_input(args: DeclareTxArgs) -> AddTransactionArgs { + let tx = internal_rpc_declare_tx(args); + let account_state = AccountState { address: tx.contract_address(), nonce: tx.nonce() }; + + AddTransactionArgs { tx, account_state } +} + +#[track_caller] +fn builder_with_queue( + in_priority_queue: bool, + in_pending_queue: bool, + tx: &InternalRpcTransaction, +) -> MempoolTestContentBuilder { + assert!( + !(in_priority_queue && in_pending_queue), + "A transaction can be in at most one queue at a time." + ); + + let mut builder = MempoolTestContentBuilder::new(); + + if in_priority_queue { + builder = builder.with_priority_queue([TransactionReference::new(tx)]); + } + + if in_pending_queue { + builder = builder.with_pending_queue([TransactionReference::new(tx)]); + } + + builder +} + #[track_caller] fn add_tx_and_verify_replacement( mut mempool: Mempool, @@ -135,23 +185,14 @@ fn add_tx_and_verify_replacement( in_priority_queue: bool, in_pending_queue: bool, ) { - // Ensure that the transaction is not in both queues. - assert!(!(in_priority_queue && in_pending_queue)); - add_tx(&mut mempool, &valid_replacement_input); // Verify transaction was replaced. - let mut builder = MempoolContentBuilder::new(); - if in_priority_queue { - builder = - builder.with_priority_queue([TransactionReference::new(&valid_replacement_input.tx)]); - } - if in_pending_queue { - builder = - builder.with_pending_queue([TransactionReference::new(&valid_replacement_input.tx)]); - } + let builder = + builder_with_queue(in_priority_queue, in_pending_queue, &valid_replacement_input.tx); + let expected_mempool_content = builder.with_pool([valid_replacement_input.tx]).build(); - expected_mempool_content.assert_eq(&mempool); + expected_mempool_content.assert_eq(&mempool.content()); } #[track_caller] @@ -172,8 +213,10 @@ fn add_tx_and_verify_replacement_in_pool( #[track_caller] fn add_txs_and_verify_no_replacement( mut mempool: Mempool, - existing_tx: AccountTransaction, + existing_tx: InternalRpcTransaction, invalid_replacement_inputs: impl IntoIterator, + in_priority_queue: bool, + in_pending_queue: bool, ) { for input in invalid_replacement_inputs { add_tx_expect_error( @@ -187,15 +230,34 @@ fn add_txs_and_verify_no_replacement( } // Verify transaction was not replaced. - let expected_mempool_content = MempoolContentBuilder::new().with_pool([existing_tx]).build(); - expected_mempool_content.assert_eq(&mempool); + let builder = builder_with_queue(in_priority_queue, in_pending_queue, &existing_tx); + + let expected_mempool_content = builder.with_pool([existing_tx]).build(); + expected_mempool_content.assert_eq(&mempool.content()); +} + +#[track_caller] +fn add_txs_and_verify_no_replacement_in_pool( + mempool: Mempool, + existing_tx: InternalRpcTransaction, + invalid_replacement_inputs: impl IntoIterator, +) { + let in_priority_queue = false; + let in_pending_queue = false; + add_txs_and_verify_no_replacement( + mempool, + existing_tx, + invalid_replacement_inputs, + in_priority_queue, + in_pending_queue, + ); } // Fixtures. #[fixture] fn mempool() -> Mempool { - MempoolContentBuilder::new().build_into_mempool() + MempoolTestContentBuilder::new().build_full_mempool() } // Tests. @@ -207,7 +269,7 @@ fn mempool() -> Mempool { #[case::test_get_exactly_all_eligible_txs(3)] #[case::test_get_more_than_all_eligible_txs(5)] #[case::test_get_less_than_all_eligible_txs(2)] -fn test_get_txs_returns_by_priority_order(#[case] n_requested_txs: usize) { +fn test_get_txs_returns_by_priority(#[case] n_requested_txs: usize) { // Setup. let tx_tip_20 = tx!(tx_hash: 1, address: "0x0", tip: 20); let tx_tip_30 = tx!(tx_hash: 2, address: "0x1", tip: 30); @@ -215,10 +277,10 @@ fn test_get_txs_returns_by_priority_order(#[case] n_requested_txs: usize) { let queue_txs = [&tx_tip_20, &tx_tip_30, &tx_tip_10].map(TransactionReference::new); let pool_txs = [&tx_tip_20, &tx_tip_30, &tx_tip_10].map(|tx| tx.clone()); - let mut mempool = MempoolContentBuilder::new() + let mut mempool = MempoolTestContentBuilder::new() .with_pool(pool_txs) .with_priority_queue(queue_txs) - .build_into_mempool(); + .build_full_mempool(); // Test. let fetched_txs = mempool.get_txs(n_requested_txs).unwrap(); @@ -231,8 +293,23 @@ fn test_get_txs_returns_by_priority_order(#[case] n_requested_txs: usize) { // Assert: non-returned transactions are still in the mempool. let remaining_tx_references = remaining_txs.iter().map(TransactionReference::new); let expected_mempool_content = - MempoolContentBuilder::new().with_priority_queue(remaining_tx_references).build(); - expected_mempool_content.assert_eq(&mempool); + MempoolTestContentBuilder::new().with_priority_queue(remaining_tx_references).build(); + expected_mempool_content.assert_eq(&mempool.content()); +} + +#[rstest] +fn test_get_txs_returns_by_secondary_priority_on_tie() { + // Setup. + let tx_tip_10_hash_9 = tx!(tx_hash: 9, address: "0x2", tip: 10); + let tx_tip_10_hash_15 = tx!(tx_hash: 15, address: "0x0", tip: 10); + + let mut mempool = MempoolTestContentBuilder::new() + .with_pool([&tx_tip_10_hash_9, &tx_tip_10_hash_15].map(|tx| tx.clone())) + .with_priority_queue([&tx_tip_10_hash_9, &tx_tip_10_hash_15].map(TransactionReference::new)) + .build_full_mempool(); + + // Test and assert. + get_txs_and_assert_expected(&mut mempool, 2, &[tx_tip_10_hash_15, tx_tip_10_hash_9]); } #[rstest] @@ -240,10 +317,10 @@ fn test_get_txs_does_not_return_pending_txs() { // Setup. let tx = tx!(); - let mut mempool = MempoolContentBuilder::new() + let mut mempool = MempoolTestContentBuilder::new() .with_pending_queue([TransactionReference::new(&tx)]) .with_pool([tx]) - .build_into_mempool(); + .build_full_mempool(); // Test and assert. get_txs_and_assert_expected(&mut mempool, 1, &[]); @@ -256,16 +333,16 @@ fn test_get_txs_does_not_remove_returned_txs_from_pool() { let queue_txs = [TransactionReference::new(&tx)]; let pool_txs = [tx]; - let mut mempool = MempoolContentBuilder::new() + let mut mempool = MempoolTestContentBuilder::new() .with_pool(pool_txs.clone()) .with_priority_queue(queue_txs) - .build_into_mempool(); + .build_full_mempool(); // Test and assert: all transactions are returned. get_txs_and_assert_expected(&mut mempool, 2, &pool_txs); let expected_mempool_content = - MempoolContentBuilder::new().with_pool(pool_txs).with_priority_queue([]).build(); - expected_mempool_content.assert_eq(&mempool); + MempoolTestContentBuilder::new().with_pool(pool_txs).with_priority_queue([]).build(); + expected_mempool_content.assert_eq(&mempool.content()); } #[rstest] @@ -278,10 +355,10 @@ fn test_get_txs_replenishes_queue_only_between_chunks() { let queue_txs = [&tx_address_0_nonce_0, &tx_address_1_nonce_0].map(TransactionReference::new); let pool_txs = [&tx_address_0_nonce_0, &tx_address_0_nonce_1, &tx_address_1_nonce_0].map(|tx| tx.clone()); - let mut mempool = MempoolContentBuilder::new() + let mut mempool = MempoolTestContentBuilder::new() .with_pool(pool_txs) .with_priority_queue(queue_txs) - .build_into_mempool(); + .build_full_mempool(); // Test and assert: all transactions returned. // Replenishment done in chunks: account 1 transaction is returned before the one of account 0, @@ -291,8 +368,8 @@ fn test_get_txs_replenishes_queue_only_between_chunks() { 3, &[tx_address_0_nonce_0, tx_address_1_nonce_0, tx_address_0_nonce_1], ); - let expected_mempool_content = MempoolContentBuilder::new().with_priority_queue([]).build(); - expected_mempool_content.assert_eq(&mempool); + let expected_mempool_content = MempoolTestContentBuilder::new().with_priority_queue([]).build(); + expected_mempool_content.assert_eq(&mempool.content()); } #[rstest] @@ -303,24 +380,26 @@ fn test_get_txs_with_nonce_gap() { let queue_txs = [TransactionReference::new(&tx_address_1_nonce_0)]; let pool_txs = [tx_address_0_nonce_1, tx_address_1_nonce_0.clone()]; - let mut mempool = MempoolContentBuilder::new() + let mut mempool = MempoolTestContentBuilder::new() .with_pool(pool_txs) .with_priority_queue(queue_txs) - .build_into_mempool(); + .build_full_mempool(); // Test and assert. get_txs_and_assert_expected(&mut mempool, 2, &[tx_address_1_nonce_0]); - let expected_mempool_content = MempoolContentBuilder::new().with_priority_queue([]).build(); - expected_mempool_content.assert_eq(&mempool); + let expected_mempool_content = MempoolTestContentBuilder::new().with_priority_queue([]).build(); + expected_mempool_content.assert_eq(&mempool.content()); } // `add_tx` tests. #[rstest] -fn test_add_tx(mut mempool: Mempool) { +fn test_add_tx_insertion_sorted_by_priority(mut mempool: Mempool) { // Setup. let input_tip_50 = add_tx_input!(tx_hash: 1, address: "0x0", tx_nonce: 0, account_nonce: 0, tip: 50); + // The following transactions test a scenario with a higher tip and lower hash, covering + // both primary and secondary priority. let input_tip_100 = add_tx_input!(tx_hash: 2, address: "0x1", tx_nonce: 1, account_nonce: 1, tip: 100); let input_tip_80 = @@ -334,12 +413,9 @@ fn test_add_tx(mut mempool: Mempool) { // Assert: transactions are ordered by priority. let expected_queue_txs = [&input_tip_100.tx, &input_tip_80.tx, &input_tip_50.tx].map(TransactionReference::new); - let expected_pool_txs = [input_tip_50.tx, input_tip_100.tx, input_tip_80.tx]; - let expected_mempool_content = MempoolContentBuilder::new() - .with_pool(expected_pool_txs) - .with_priority_queue(expected_queue_txs) - .build(); - expected_mempool_content.assert_eq(&mempool); + let expected_mempool_content = + MempoolTestContentBuilder::new().with_priority_queue(expected_queue_txs).build(); + expected_mempool_content.assert_eq(&mempool.content()); } #[rstest] @@ -362,16 +438,20 @@ fn test_add_tx_correctly_places_txs_in_queue_and_pool(mut mempool: Mempool) { [&input_address_1_nonce_0.tx, &input_address_0_nonce_0.tx].map(TransactionReference::new); let expected_pool_txs = [input_address_0_nonce_0.tx, input_address_1_nonce_0.tx, input_address_0_nonce_1.tx]; - let expected_mempool_content = MempoolContentBuilder::new() + let expected_mempool_content = MempoolTestContentBuilder::new() .with_pool(expected_pool_txs) .with_priority_queue(expected_queue_txs) .build(); - expected_mempool_content.assert_eq(&mempool); + expected_mempool_content.assert_eq(&mempool.content()); } // TODO(Elin): reconsider this test in a more realistic scenario. #[rstest] -fn test_add_tx_failure_on_duplicate_tx_hash(mut mempool: Mempool) { +fn test_add_tx_rejects_duplicate_tx_hash(mut mempool: Mempool) { + let recorder = PrometheusBuilder::new().build_recorder(); + let _recorder_guard = metrics::set_default_local_recorder(&recorder); + register_metrics(); + // Setup. let input = add_tx_input!(tx_hash: 1, tx_nonce: 1, account_nonce: 0); // Same hash is possible if signature is different, for example. @@ -388,30 +468,35 @@ fn test_add_tx_failure_on_duplicate_tx_hash(mut mempool: Mempool) { ); // Assert: the original transaction remains. - let expected_mempool_content = MempoolContentBuilder::new().with_pool([input.tx]).build(); - expected_mempool_content.assert_eq(&mempool); + let expected_mempool_content = MempoolTestContentBuilder::new().with_pool([input.tx]).build(); + expected_mempool_content.assert_eq(&mempool.content()); + + // Assert: metrics. + let expected_metrics = MempoolMetrics { + txs_received_invoke: 2, + txs_dropped_failed_add_tx_checks: 1, + pool_size: 1, + ..Default::default() + }; + expected_metrics.verify_metrics(&recorder); } #[rstest] -fn test_add_tx_lower_than_queued_nonce(mut mempool: Mempool) { +#[case::lower_nonce(0, MempoolError::NonceTooOld { address: contract_address!("0x0"), nonce: nonce!(0) })] +#[case::equal_nonce(1, MempoolError::DuplicateNonce { address: contract_address!("0x0"), nonce: nonce!(1) })] +fn test_add_tx_rejects_tx_of_queued_nonce( + #[case] tx_nonce: u64, + #[case] expected_error: MempoolError, + mut mempool: Mempool, +) { // Setup. let input = add_tx_input!(tx_hash: 1, address: "0x0", tx_nonce: 1, account_nonce: 1); add_tx(&mut mempool, &input); // Test and assert: original transaction remains. - let invalid_input = add_tx_input!(tx_hash: 2, address: "0x0", tx_nonce: 0, account_nonce: 1); - add_tx_expect_error( - &mut mempool, - &invalid_input, - MempoolError::NonceTooOld { address: contract_address!("0x0"), nonce: nonce!(0) }, - ); - - let invalid_input = add_tx_input!(tx_hash: 2, address: "0x0", tx_nonce: 1, account_nonce: 1); - add_tx_expect_error( - &mut mempool, - &invalid_input, - MempoolError::DuplicateNonce { address: contract_address!("0x0"), nonce: nonce!(1) }, - ); + let invalid_input = + add_tx_input!(tx_hash: 2, address: "0x0", tx_nonce: tx_nonce, account_nonce: 1); + add_tx_expect_error(&mut mempool, &invalid_input, expected_error); } #[rstest] @@ -430,35 +515,32 @@ fn test_add_tx_with_identical_tip_succeeds(mut mempool: Mempool) { // Assert: both transactions are in the mempool. let expected_queue_txs = [&input1.tx, &input2.tx].map(TransactionReference::new); let expected_pool_txs = [input1.tx, input2.tx]; - let expected_mempool_content = MempoolContentBuilder::new() + let expected_mempool_content = MempoolTestContentBuilder::new() .with_pool(expected_pool_txs) .with_priority_queue(expected_queue_txs) .build(); - // TODO: currently hash comparison tie-breaks the two. Once more robust tie-breaks are added - // replace this assertion with a dedicated test. - expected_mempool_content.assert_eq(&mempool); + // TODO(AlonH): currently hash comparison tie-breaks the two. Once more robust tie-breaks are + // added replace this assertion with a dedicated test. + expected_mempool_content.assert_eq(&mempool.content()); } #[rstest] -fn test_add_tx_tip_priority_over_tx_hash(mut mempool: Mempool) { - // Setup. - let input_big_tip_small_hash = add_tx_input!(tx_hash: 1, address: "0x0", tip: 2); - // Create a transaction with identical tip, it should be allowed through since the priority - // queue tie-breaks identical tips by other tx-unique identifiers (for example tx hash). - let input_small_tip_big_hash = add_tx_input!(tx_hash: 2, address: "0x1", tip: 1); +fn add_tx_with_committed_account_nonce(mut mempool: Mempool) { + // Setup: commit a block with account nonce 1. + commit_block(&mut mempool, [("0x0", 1)], []); - // Test. - for input in [&input_big_tip_small_hash, &input_small_tip_big_hash] { - add_tx(&mut mempool, input); - } + // Add a transaction with nonce 0. Should be rejected with NonceTooOld. + let input = add_tx_input!(tx_hash: 1, address: "0x0", tx_nonce: 0, account_nonce: 0); + add_tx_expect_error( + &mut mempool, + &input, + MempoolError::NonceTooOld { address: contract_address!("0x0"), nonce: nonce!(0) }, + ); - // Assert: ensure that the transaction with the higher tip is prioritized higher. - let expected_queue_txs = - [&input_big_tip_small_hash.tx, &input_small_tip_big_hash.tx].map(TransactionReference::new); - let expected_mempool_content = - MempoolContentBuilder::new().with_priority_queue(expected_queue_txs).build(); - expected_mempool_content.assert_eq(&mempool); + // Add a transaction with nonce 1. Should be accepted. + let input = add_tx_input!(tx_hash: 2, address: "0x0", tx_nonce: 1, account_nonce: 0); + add_tx(&mut mempool, &input); } #[rstest] @@ -472,9 +554,11 @@ fn test_add_tx_fills_nonce_gap(mut mempool: Mempool) { // Assert: the second transaction is in the pool and not in the queue. let expected_pool_txs = [input_nonce_1.tx.clone()]; - let expected_mempool_content = - MempoolContentBuilder::new().with_pool(expected_pool_txs).with_priority_queue([]).build(); - expected_mempool_content.assert_eq(&mempool); + let expected_mempool_content = MempoolTestContentBuilder::new() + .with_pool(expected_pool_txs) + .with_priority_queue([]) + .build(); + expected_mempool_content.assert_eq(&mempool.content()); // Test: add the first transaction, which fills the hole. add_tx(&mut mempool, &input_nonce_0); @@ -482,30 +566,11 @@ fn test_add_tx_fills_nonce_gap(mut mempool: Mempool) { // Assert: only the eligible transaction appears in the queue. let expected_queue_txs = [TransactionReference::new(&input_nonce_0.tx)]; let expected_pool_txs = [input_nonce_1.tx, input_nonce_0.tx]; - let expected_mempool_content = MempoolContentBuilder::new() + let expected_mempool_content = MempoolTestContentBuilder::new() .with_pool(expected_pool_txs) .with_priority_queue(expected_queue_txs) .build(); - expected_mempool_content.assert_eq(&mempool); -} - -#[rstest] -fn test_add_tx_does_not_decrease_account_nonce(mut mempool: Mempool) { - // Setup. - let input_account_nonce_0 = - add_tx_input!(tx_hash: 2, address: "0x0", tx_nonce: 2, account_nonce: 0); - let input_account_nonce_1 = - add_tx_input!(tx_hash: 1, address: "0x0", tx_nonce: 1, account_nonce: 1); - let input_account_nonce_2 = - add_tx_input!(tx_hash: 3, address: "0x0", tx_nonce: 3, account_nonce: 2); - - // Test. - add_tx(&mut mempool, &input_account_nonce_1); - add_tx(&mut mempool, &input_account_nonce_0); - assert_eq!(mempool.state.get(contract_address!("0x0")), Some(nonce!(1))); - - add_tx(&mut mempool, &input_account_nonce_2); - assert_eq!(mempool.state.get(contract_address!("0x0")), Some(nonce!(2))); + expected_mempool_content.assert_eq(&mempool.content()); } // `commit_block` tests. @@ -530,22 +595,21 @@ fn test_commit_block_includes_all_proposed_txs() { tx_address_1_nonce_3.clone(), tx_address_2_nonce_1.clone(), ]; - let mut mempool = MempoolContentBuilder::new() + let mut mempool = MempoolTestContentBuilder::new() .with_pool(pool_txs.clone()) .with_priority_queue(queue_txs) - .build_into_mempool(); + .build_full_mempool(); // Test. let nonces = [("0x0", 4), ("0x1", 3)]; - let tx_hashes = [1, 4]; - commit_block(&mut mempool, nonces, tx_hashes); + commit_block(&mut mempool, nonces, []); // Assert. let pool_txs = [tx_address_0_nonce_4, tx_address_0_nonce_5, tx_address_1_nonce_3, tx_address_2_nonce_1]; let expected_mempool_content = - MempoolContentBuilder::new().with_pool(pool_txs).with_priority_queue(queue_txs).build(); - expected_mempool_content.assert_eq(&mempool); + MempoolTestContentBuilder::new().with_pool(pool_txs).with_priority_queue(queue_txs).build(); + expected_mempool_content.assert_eq(&mempool.content()); } // Fee escalation tests. @@ -565,23 +629,18 @@ fn test_fee_escalation_valid_replacement( ]; for increased_value in increased_values { // Setup. - let tx = tx!(tip: 90, max_l2_gas_price: 90); - let mut builder = MempoolContentBuilder::new().with_fee_escalation_percentage(10); + let tx = tx!(tx_hash: 0, tip: 90, max_l2_gas_price: 90); - if in_priority_queue { - builder = builder.with_priority_queue([TransactionReference::new(&tx)]); - } + let mut builder = builder_with_queue(in_priority_queue, in_pending_queue, &tx) + .with_fee_escalation_percentage(10); if in_pending_queue { - builder = builder - .with_pending_queue([TransactionReference::new(&tx)]) - .with_gas_price_threshold(1000); + builder = builder.with_gas_price_threshold(1000); } - let mempool = builder.with_pool([tx]).build_into_mempool(); + let mempool = builder.with_pool([tx]).build_full_mempool(); - let valid_replacement_input = - add_tx_input!(tip: increased_value, max_l2_gas_price: u128::from(increased_value)); + let valid_replacement_input = add_tx_input!(tx_hash: 1, tip: increased_value, max_l2_gas_price: u128::from(increased_value)); // Test and assert. add_tx_and_verify_replacement( @@ -594,13 +653,24 @@ fn test_fee_escalation_valid_replacement( } #[rstest] -fn test_fee_escalation_invalid_replacement() { +#[case::pool(false, false)] +#[case::pool_and_priority_queue(true, false)] +#[case::pool_and_pending_queue(false, true)] +fn test_fee_escalation_invalid_replacement( + #[case] in_priority_queue: bool, + #[case] in_pending_queue: bool, +) { // Setup. let existing_tx = tx!(tx_hash: 1, tip: 100, max_l2_gas_price: 100); - let mempool = MempoolContentBuilder::new() - .with_pool([existing_tx.clone()]) - .with_fee_escalation_percentage(10) - .build_into_mempool(); + + let mut builder = builder_with_queue(in_priority_queue, in_pending_queue, &existing_tx) + .with_fee_escalation_percentage(10); + + if in_pending_queue { + builder = builder.with_gas_price_threshold(1000); + } + + let mempool = builder.with_pool([existing_tx.clone()]).build_full_mempool(); let input_not_enough_tip = add_tx_input!(tx_hash: 3, tip: 109, max_l2_gas_price: 110); let input_not_enough_gas_price = add_tx_input!(tx_hash: 4, tip: 110, max_l2_gas_price: 109); @@ -609,37 +679,69 @@ fn test_fee_escalation_invalid_replacement() { // Test and assert. let invalid_replacement_inputs = [input_not_enough_tip, input_not_enough_gas_price, input_not_enough_both]; - add_txs_and_verify_no_replacement(mempool, existing_tx, invalid_replacement_inputs); + add_txs_and_verify_no_replacement( + mempool, + existing_tx, + invalid_replacement_inputs, + in_priority_queue, + in_pending_queue, + ); +} + +#[rstest] +fn fee_escalation_queue_removal() { + // Setup. + let min_gas_price = 1; + let queued_tx = + tx!(tx_hash: 0, address: "0x0", tx_nonce: 0, tip: 0, max_l2_gas_price: min_gas_price); + let queued_tx_reference = TransactionReference::new(&queued_tx); + let tx_to_be_replaced = + tx!(tx_hash: 1, address: "0x0", tx_nonce: 1, tip: 0, max_l2_gas_price: min_gas_price); + let mut mempool = MempoolTestContentBuilder::new() + .with_priority_queue([queued_tx_reference]) + .with_pool([queued_tx.clone(), tx_to_be_replaced]) + .with_fee_escalation_percentage(0) // Always replace. + .build_full_mempool(); + + // Test and assert: replacement doesn't affect queue. + + let valid_replacement_input = add_tx_input!(tx_hash: 2, address: "0x0", tx_nonce: 1, tip: 0, max_l2_gas_price: min_gas_price); + add_tx(&mut mempool, &valid_replacement_input); + let expected_mempool_content = MempoolTestContentBuilder::new() + .with_pool([queued_tx, valid_replacement_input.tx]) + .with_priority_queue([queued_tx_reference]) + .build(); + expected_mempool_content.assert_eq(&mempool.content()); } #[rstest] -// TODO(Elin): add a test staring with low nonzero values, too check they are not accidentally -// zeroed. fn test_fee_escalation_valid_replacement_minimum_values() { // Setup. - let tx = tx!(tip: 0, max_l2_gas_price: 0); - let mempool = MempoolContentBuilder::new() + let min_gas_price = 1; + let tx = tx!(tx_hash: 0, tip: 0, max_l2_gas_price: min_gas_price); + let mempool = MempoolTestContentBuilder::new() .with_pool([tx]) .with_fee_escalation_percentage(0) // Always replace. - .build_into_mempool(); + .build_full_mempool(); // Test and assert: replacement with maximum values. - let valid_replacement_input = add_tx_input!(tip: 0, max_l2_gas_price: 0); + let valid_replacement_input = + add_tx_input!(tx_hash: 1, tip: 0, max_l2_gas_price: min_gas_price); add_tx_and_verify_replacement_in_pool(mempool, valid_replacement_input); } #[rstest] -#[ignore = "Reenable when overflow bug fixed"] fn test_fee_escalation_valid_replacement_maximum_values() { // Setup. - let tx = tx!(tip: u64::MAX >> 1, max_l2_gas_price: u128::MAX >> 1); - let mempool = MempoolContentBuilder::new() + let tx = tx!(tx_hash: 0, tip: u64::MAX / 100, max_l2_gas_price: u128::MAX / 100 ); + let mempool = MempoolTestContentBuilder::new() .with_pool([tx]) .with_fee_escalation_percentage(100) - .build_into_mempool(); + .build_full_mempool(); // Test and assert: replacement with maximum values. - let valid_replacement_input = add_tx_input!(tip: u64::MAX, max_l2_gas_price: u128::MAX); + let valid_replacement_input = + add_tx_input!(tx_hash: 1, tip: u64::MAX / 50 , max_l2_gas_price: u128::MAX / 50); add_tx_and_verify_replacement_in_pool(mempool, valid_replacement_input); } @@ -657,35 +759,45 @@ fn test_fee_escalation_invalid_replacement_overflow_gracefully_handled() { (u64::MAX, u128::MAX), ]; for (tip, max_l2_gas_price) in initial_values { - let existing_tx = tx!(tip: tip, max_l2_gas_price: max_l2_gas_price); - let mempool = MempoolContentBuilder::new() + let existing_tx = tx!(tx_hash: 0, tip: tip, max_l2_gas_price: max_l2_gas_price); + let mempool = MempoolTestContentBuilder::new() .with_pool([existing_tx.clone()]) .with_fee_escalation_percentage(10) - .build_into_mempool(); + .build_full_mempool(); // Test and assert: overflow gracefully handled. - let invalid_replacement_input = add_tx_input!(tip: u64::MAX, max_l2_gas_price: u128::MAX); - add_txs_and_verify_no_replacement(mempool, existing_tx, [invalid_replacement_input]); + let invalid_replacement_input = + add_tx_input!(tx_hash: 1, tip: u64::MAX, max_l2_gas_price: u128::MAX); + add_txs_and_verify_no_replacement_in_pool( + mempool, + existing_tx, + [invalid_replacement_input], + ); } // Large percentage. // Setup. - let existing_tx = tx!(tip: u64::MAX >> 1, max_l2_gas_price: u128::MAX >> 1); - let mempool = MempoolContentBuilder::new() + let existing_tx = tx!(tx_hash: 0, tip: u64::MAX >> 1, max_l2_gas_price: u128::MAX >> 1); + let mempool = MempoolTestContentBuilder::new() .with_pool([existing_tx.clone()]) .with_fee_escalation_percentage(200) - .build_into_mempool(); + .build_full_mempool(); // Test and assert: overflow gracefully handled. - let invalid_replacement_input = add_tx_input!(tip: u64::MAX, max_l2_gas_price: u128::MAX); - add_txs_and_verify_no_replacement(mempool, existing_tx, [invalid_replacement_input]); + let invalid_replacement_input = + add_tx_input!(tx_hash: 1, tip: u64::MAX, max_l2_gas_price: u128::MAX); + add_txs_and_verify_no_replacement_in_pool(mempool, existing_tx, [invalid_replacement_input]); } // `update_gas_price_threshold` tests. #[rstest] fn test_update_gas_price_threshold_increases_threshold() { + let recorder = PrometheusBuilder::new().build_recorder(); + let _recorder_guard = metrics::set_default_local_recorder(&recorder); + register_metrics(); + // Setup. let [tx_low_gas, tx_high_gas] = [ &tx!(tx_hash: 0, address: "0x0", max_l2_gas_price: 100), @@ -693,21 +805,25 @@ fn test_update_gas_price_threshold_increases_threshold() { ] .map(TransactionReference::new); - let mut mempool: Mempool = MempoolContentBuilder::new() + let mut mempool: Mempool = MempoolTestContentBuilder::new() .with_priority_queue([tx_low_gas, tx_high_gas]) .with_gas_price_threshold(100) - .build() - .into(); + .build_full_mempool(); // Test. - mempool.update_gas_price_threshold(GasPrice(101)); + mempool.update_gas_price(NonzeroGasPrice::new_unchecked(GasPrice(101))); // Assert. - let expected_mempool_content = MempoolContentBuilder::new() + let expected_mempool_content = MempoolTestContentBuilder::new() .with_pending_queue([tx_low_gas]) .with_priority_queue([tx_high_gas]) .build(); - expected_mempool_content.assert_eq(&mempool); + expected_mempool_content.assert_eq(&mempool.content()); + + // Assert: metrics. + let expected_metrics = + MempoolMetrics { priority_queue_size: 1, pending_queue_size: 1, ..Default::default() }; + expected_metrics.verify_metrics(&recorder); } #[rstest] @@ -719,19 +835,430 @@ fn test_update_gas_price_threshold_decreases_threshold() { ] .map(TransactionReference::new); - let mut mempool: Mempool = MempoolContentBuilder::new() + let mut mempool: Mempool = MempoolTestContentBuilder::new() .with_pending_queue([tx_low_gas, tx_high_gas]) .with_gas_price_threshold(100) - .build() - .into(); + .build_full_mempool(); // Test. - mempool.update_gas_price_threshold(GasPrice(90)); + mempool.update_gas_price(NonzeroGasPrice::new_unchecked(GasPrice(90))); // Assert. - let expected_mempool_content = MempoolContentBuilder::new() + let expected_mempool_content = MempoolTestContentBuilder::new() .with_pending_queue([tx_low_gas]) .with_priority_queue([tx_high_gas]) .build(); - expected_mempool_content.assert_eq(&mempool); + expected_mempool_content.assert_eq(&mempool.content()); +} + +#[rstest] +#[tokio::test] +async fn test_new_tx_sent_to_p2p(mempool: Mempool) { + // add_tx_input! creates an Invoke Transaction + let tx_args = add_tx_input!(tx_hash: 1, address: "0x0", tx_nonce: 2, account_nonce: 2); + let propagateor_args = + AddTransactionArgsWrapper { args: tx_args.clone(), p2p_message_metadata: None }; + let mut mock_mempool_p2p_propagator_client = MockMempoolP2pPropagatorClient::new(); + mock_mempool_p2p_propagator_client + .expect_add_transaction() + .times(1) + .with(predicate::eq(tx_args.tx)) + .returning(|_| Ok(())); + let mut mempool_wrapper = + MempoolCommunicationWrapper::new(mempool, Arc::new(mock_mempool_p2p_propagator_client)); + + mempool_wrapper.add_tx(propagateor_args).await.unwrap(); +} + +#[rstest] +#[tokio::test] +async fn test_propagated_tx_sent_to_p2p(mempool: Mempool) { + // add_tx_input! creates an Invoke Transaction + let tx_args = add_tx_input!(tx_hash: 2, address: "0x0", tx_nonce: 3, account_nonce: 2); + let expected_message_metadata = BroadcastedMessageMetadata::get_test_instance(&mut get_rng()); + let propagated_args = AddTransactionArgsWrapper { + args: tx_args.clone(), + p2p_message_metadata: Some(expected_message_metadata.clone()), + }; + + let mut mock_mempool_p2p_propagator_client = MockMempoolP2pPropagatorClient::new(); + mock_mempool_p2p_propagator_client + .expect_continue_propagation() + .times(1) + .with(predicate::eq(expected_message_metadata.clone())) + .returning(|_| Ok(())); + + let mut mempool_wrapper = + MempoolCommunicationWrapper::new(mempool, Arc::new(mock_mempool_p2p_propagator_client)); + + mempool_wrapper.add_tx(propagated_args).await.unwrap(); +} + +#[rstest] +fn test_rejected_tx_deleted_from_mempool(mut mempool: Mempool) { + let recorder = PrometheusBuilder::new().build_recorder(); + let _recorder_guard = metrics::set_default_local_recorder(&recorder); + register_metrics(); + + // Setup. The tip is used here to control the order of transactions in the mempool. + let tx_address_1_rejected = + add_tx_input!(tx_hash: 4, address: "0x1", tx_nonce: 2, account_nonce: 2, tip: 1); + let tx_address_1_not_executed = + add_tx_input!(tx_hash: 5, address: "0x1", tx_nonce: 3, account_nonce: 2, tip: 1); + + let tx_address_2_accepted = + add_tx_input!(tx_hash: 7, address: "0x2", tx_nonce: 1, account_nonce: 1, tip: 0); + let tx_address_2_rejected = + add_tx_input!(tx_hash: 8, address: "0x2", tx_nonce: 2, account_nonce: 1, tip: 0); + + let mut expected_pool_txs = vec![]; + for input in [ + &tx_address_1_rejected, + &tx_address_2_accepted, + &tx_address_1_not_executed, + &tx_address_2_rejected, + ] { + add_tx(&mut mempool, input); + expected_pool_txs.push(input.tx.clone()); + } + + // Assert initial mempool content. + let expected_mempool_content = MempoolTestContentBuilder::new() + .with_pool(expected_pool_txs.clone()) + .with_priority_queue( + [&tx_address_1_rejected.tx, &tx_address_2_accepted.tx].map(TransactionReference::new), + ) + .build(); + expected_mempool_content.assert_eq(&mempool.content()); + + // Test and assert: get all transactions from the Mempool. + get_txs_and_assert_expected(&mut mempool, expected_pool_txs.len(), &expected_pool_txs); + + // Commit block with transactions 4 and 8 rejected. + let rejected_tx = [tx_address_1_rejected.tx.tx_hash, tx_address_2_rejected.tx.tx_hash]; + commit_block(&mut mempool, [("0x2", 2)], rejected_tx); + + // Assert transactions 4 and 8 are removed from the mempool. + let expected_mempool_content = MempoolTestContentBuilder::new() + .with_pool([tx_address_1_not_executed.tx]) + .with_priority_queue(vec![]) + .build(); + expected_mempool_content.assert_eq(&mempool.content()); + + // Assert: metrics. + let expected_metrics = MempoolMetrics { + txs_received_invoke: 4, + txs_dropped_rejected: 2, + txs_committed: 1, + pool_size: 1, + get_txs_size: 4, + transaction_time_spent_in_mempool: HistogramValue { count: 3, ..Default::default() }, + ..Default::default() + }; + expected_metrics.verify_metrics(&recorder); +} + +#[rstest] +fn tx_from_address_exists(mut mempool: Mempool) { + const ACCOUNT_ADDRESS: &str = "0x1"; + let account_address = contract_address!(ACCOUNT_ADDRESS); + + // Account is not known to the mempool. + assert_eq!(mempool.account_tx_in_pool_or_recent_block(account_address), false); + + // The account has a tx in the mempool. + add_tx( + &mut mempool, + &add_tx_input!(tx_hash: 1, address: ACCOUNT_ADDRESS, tx_nonce: 0, account_nonce: 0), + ); + assert_eq!(mempool.account_tx_in_pool_or_recent_block(account_address), true); + + // The account has a staged tx in the mempool. + let get_tx_response = mempool.get_txs(1).unwrap(); + assert_eq!(get_tx_response.first().unwrap().contract_address(), account_address); + assert_eq!(mempool.account_tx_in_pool_or_recent_block(account_address), true); + + // The account has no txs in the pool, but is known through a committed block. + commit_block(&mut mempool, [(ACCOUNT_ADDRESS, 1)], []); + MempoolTestContentBuilder::new().with_pool([]).build().assert_eq(&mempool.content()); + assert_eq!(mempool.account_tx_in_pool_or_recent_block(account_address), true); +} + +#[rstest] +fn add_tx_old_transactions_cleanup() { + // Create a mempool with a fake clock. + let fake_clock = Arc::new(FakeClock::default()); + let mut mempool = Mempool::new( + MempoolConfig { transaction_ttl: Duration::from_secs(60), ..Default::default() }, + fake_clock.clone(), + ); + + // Add a new transaction to the mempool. + let first_tx = + add_tx_input!(tx_hash: 1, address: "0x0", tx_nonce: 0, account_nonce: 0, tip: 100); + add_tx(&mut mempool, &first_tx); + + // Advance the clock and add another transaction. + fake_clock.advance(mempool.config.transaction_ttl / 2); + let second_tx = + add_tx_input!(tx_hash: 2, address: "0x1", tx_nonce: 0, account_nonce: 0, tip: 50); + add_tx(&mut mempool, &second_tx); + + // Verify that both transactions are in the mempool. + let expected_txs = [&first_tx.tx, &second_tx.tx]; + let expected_mempool_content = MempoolTestContentBuilder::new() + .with_pool(expected_txs.map(|tx| tx.clone())) + .with_priority_queue(expected_txs.map(TransactionReference::new)) + .build(); + expected_mempool_content.assert_eq(&mempool.content()); + + // Advance the clock and add a new transaction. + fake_clock.advance(mempool.config.transaction_ttl / 2 + Duration::from_secs(5)); + let third_tx = + add_tx_input!(tx_hash: 3, address: "0x2", tx_nonce: 0, account_nonce: 0, tip: 10); + add_tx(&mut mempool, &third_tx); + + // The first transaction should be removed from the mempool. + let expected_txs = [&second_tx.tx, &third_tx.tx]; + let expected_mempool_content = MempoolTestContentBuilder::new() + .with_pool(expected_txs.map(|tx| tx.clone())) + .with_priority_queue(expected_txs.map(TransactionReference::new)) + .build(); + expected_mempool_content.assert_eq(&mempool.content()); +} + +#[rstest] +fn get_txs_old_transactions_cleanup() { + let recorder = PrometheusBuilder::new().build_recorder(); + let _recorder_guard = metrics::set_default_local_recorder(&recorder); + register_metrics(); + + // Create a mempool with a fake clock. + let fake_clock = Arc::new(FakeClock::default()); + let mut mempool = Mempool::new( + MempoolConfig { transaction_ttl: Duration::from_secs(60), ..Default::default() }, + fake_clock.clone(), + ); + + // Add a new transaction to the mempool. + let first_tx = + add_tx_input!(tx_hash: 1, address: "0x0", tx_nonce: 0, account_nonce: 0, tip: 100); + add_tx(&mut mempool, &first_tx); + + // Advance the clock and add another transaction. + fake_clock.advance(mempool.config.transaction_ttl / 2); + + let second_tx = + add_tx_input!(tx_hash: 2, address: "0x1", tx_nonce: 0, account_nonce: 0, tip: 50); + add_tx(&mut mempool, &second_tx); + + // Verify that both transactions are in the mempool. + let expected_txs = [&first_tx.tx, &second_tx.tx]; + let expected_mempool_content = MempoolTestContentBuilder::new() + .with_pool(expected_txs.map(|tx| tx.clone())) + .with_priority_queue(expected_txs.map(TransactionReference::new)) + .build(); + expected_mempool_content.assert_eq(&mempool.content()); + + // Advance the clock. Now only the second transaction should be returned from get_txs, and the + // first should be removed. + fake_clock.advance(mempool.config.transaction_ttl / 2 + Duration::from_secs(5)); + + assert_eq!(mempool.get_txs(2).unwrap(), vec![second_tx.tx.clone()]); + + let expected_mempool_content = MempoolTestContentBuilder::new() + .with_pool([second_tx.tx.clone()]) + .with_priority_queue([]) + .with_pending_queue([]) + .build(); + expected_mempool_content.assert_eq(&mempool.content()); + + // Assert: metrics. + let expected_metrics = MempoolMetrics { + txs_received_invoke: 2, + txs_dropped_expired: 1, + pool_size: 1, + get_txs_size: 1, + transaction_time_spent_in_mempool: HistogramValue { + sum: 65.0, + count: 1, + ..Default::default() + }, + ..Default::default() + }; + expected_metrics.verify_metrics(&recorder); +} + +#[test] +fn test_register_metrics() { + let recorder = PrometheusBuilder::new().build_recorder(); + let _recorder_guard = metrics::set_default_local_recorder(&recorder); + register_metrics(); + + let expected_metrics = MempoolMetrics::default(); + expected_metrics.verify_metrics(&recorder); +} + +#[rstest] +fn expired_staged_txs_are_not_deleted() { + // Create a mempool with a fake clock. + let fake_clock = Arc::new(FakeClock::default()); + let mut mempool = Mempool::new( + MempoolConfig { transaction_ttl: Duration::from_secs(60), ..Default::default() }, + fake_clock.clone(), + ); + + // Add 2 transactions to the mempool, and stage one. + let staged_tx = + add_tx_input!(tx_hash: 1, address: "0x0", tx_nonce: 0, account_nonce: 0, tip: 100); + let nonstaged_tx = + add_tx_input!(tx_hash: 2, address: "0x0", tx_nonce: 1, account_nonce: 0, tip: 100); + add_tx(&mut mempool, &staged_tx); + add_tx(&mut mempool, &nonstaged_tx); + assert_eq!(mempool.get_txs(1).unwrap(), vec![staged_tx.tx.clone()]); + + // Advance the clock beyond the TTL. + fake_clock.advance(mempool.config.transaction_ttl + Duration::from_secs(5)); + + // Add another transaction to trigger the cleanup, and verify the staged tx is still in the + // mempool. The non-staged tx should be removed. + let another_tx = + add_tx_input!(tx_hash: 3, address: "0x1", tx_nonce: 0, account_nonce: 0, tip: 100); + add_tx(&mut mempool, &another_tx); + let expected_mempool_content = + MempoolTestContentBuilder::new().with_pool([staged_tx.tx, another_tx.tx]).build(); + expected_mempool_content.assert_eq(&mempool.content()); +} + +#[rstest] +fn delay_declare_txs() { + let recorder = PrometheusBuilder::new().build_recorder(); + let _recorder_guard = metrics::set_default_local_recorder(&recorder); + register_metrics(); + + // Create a mempool with a fake clock. + let fake_clock = Arc::new(FakeClock::default()); + let declare_delay = Duration::from_secs(5); + let mut mempool = + Mempool::new(MempoolConfig { declare_delay, ..Default::default() }, fake_clock.clone()); + let first_declare = declare_add_tx_input( + declare_tx_args!(resource_bounds: test_valid_resource_bounds(), sender_address: contract_address!("0x0"), tx_hash: tx_hash!(0)), + ); + add_tx(&mut mempool, &first_declare); + + fake_clock.advance(Duration::from_secs(1)); + let second_declare = declare_add_tx_input( + declare_tx_args!(resource_bounds: test_valid_resource_bounds(), sender_address: contract_address!("0x1"), tx_hash: tx_hash!(1)), + ); + add_tx(&mut mempool, &second_declare); + + assert_eq!(mempool.get_txs(2).unwrap(), vec![]); + + // Assert: metrics. + let expected_metrics = + MempoolMetrics { txs_received_declare: 2, delayed_declares_size: 2, ..Default::default() }; + expected_metrics.verify_metrics(&recorder); + + // Complete the first declare's delay. + fake_clock.advance(declare_delay - Duration::from_secs(1)); + // Add another transaction to trigger `add_ready_declares`. + let another_tx_1 = + add_tx_input!(tx_hash: 123, address: "0x123", tx_nonce: 123, account_nonce: 0, tip: 123); + add_tx(&mut mempool, &another_tx_1); + + // Assert only the first declare is in the mempool. + assert_eq!(mempool.get_txs(2).unwrap(), vec![first_declare.tx]); + + // Complete the second declare's delay. + fake_clock.advance(Duration::from_secs(1)); + // Add another transaction to trigger `add_ready_declares` + let another_tx_2 = + add_tx_input!(tx_hash: 2, address: "0x1", tx_nonce: 5, account_nonce: 0, tip: 100); + add_tx(&mut mempool, &another_tx_2); + + // Assert the second declare was also added to the mempool. + assert_eq!(mempool.get_txs(2).unwrap(), vec![second_declare.tx]); +} + +#[rstest] +fn no_delay_declare_front_run() { + // Create a mempool with a fake clock. + let fake_clock = Arc::new(FakeClock::default()); + let mut mempool = Mempool::new( + MempoolConfig { + declare_delay: Duration::from_secs(5), + // Always accept fee escalation to test only the delayed declare duplicate nonce. + enable_fee_escalation: true, + fee_escalation_percentage: 0, + ..Default::default() + }, + fake_clock.clone(), + ); + let declare = declare_add_tx_input( + declare_tx_args!(resource_bounds: test_valid_resource_bounds(), sender_address: contract_address!("0x0"), tx_hash: tx_hash!(0)), + ); + add_tx(&mut mempool, &declare); + add_tx_expect_error( + &mut mempool, + &declare, + MempoolError::DuplicateNonce { + address: declare.tx.contract_address(), + nonce: declare.tx.nonce(), + }, + ); +} + +#[rstest] +fn committed_account_nonce_cleanup() { + let mut mempool = Mempool::new( + MempoolConfig { committed_nonce_retention_block_count: 2, ..Default::default() }, + Arc::new(FakeClock::default()), + ); + + // Setup: commit a block with account nonce 1. + commit_block(&mut mempool, [("0x0", 1)], []); + + // Add a transaction with nonce 0. Should be rejected with NonceTooOld. + let input_tx = add_tx_input!(tx_hash: 1, address: "0x0", tx_nonce: 0, account_nonce: 0); + add_tx_expect_error( + &mut mempool, + &input_tx, + MempoolError::NonceTooOld { address: contract_address!("0x0"), nonce: nonce!(0) }, + ); + + // Commit an empty block, and check the transaction is still rejected. + commit_block(&mut mempool, [], []); + add_tx_expect_error( + &mut mempool, + &input_tx, + MempoolError::NonceTooOld { address: contract_address!("0x0"), nonce: nonce!(0) }, + ); + + // Commit another empty block. This should remove the previously committed nonce, and + // the transaction should be accepted. + commit_block(&mut mempool, [], []); + add_tx(&mut mempool, &input_tx); +} + +#[rstest] +fn test_get_mempool_snapshot() { + // Create a mempool with a fake clock. + let fake_clock = Arc::new(FakeClock::default()); + let mut mempool = Mempool::new(MempoolConfig::default(), fake_clock.clone()); + + for i in 1..10 { + fake_clock.advance(Duration::from_secs(1)); + add_tx( + &mut mempool, + &add_tx_input!(tx_hash: i, address: format!("0x{}", i).as_str(), tip: 10), + ); + } + + // Test. + let mempool_snapshot = mempool.get_mempool_snapshot().unwrap(); + + // Check that the returned hashes are sorted by submission time. + let expected_chronological_hashes = (1..10).rev().map(|i| tx_hash!(i)).collect::>(); + + assert_eq!(mempool_snapshot.transactions, expected_chronological_hashes); } diff --git a/crates/starknet_mempool/src/metrics.rs b/crates/starknet_mempool/src/metrics.rs new file mode 100644 index 00000000000..4713b34e170 --- /dev/null +++ b/crates/starknet_mempool/src/metrics.rs @@ -0,0 +1,136 @@ +use starknet_api::rpc_transaction::{ + InternalRpcTransactionLabelValue, + InternalRpcTransactionWithoutTxHash, +}; +use starknet_sequencer_metrics::metrics::{ + LabeledMetricCounter, + MetricCounter, + MetricGauge, + MetricHistogram, +}; +use starknet_sequencer_metrics::{define_metrics, generate_permutation_labels}; +use strum::{EnumVariantNames, VariantNames}; +use strum_macros::{EnumIter, IntoStaticStr}; + +use crate::mempool::Mempool; + +define_metrics!( + Mempool => { + MetricCounter { MEMPOOL_TRANSACTIONS_COMMITTED, "mempool_txs_committed", "The number of transactions that were committed to block", init = 0 }, + LabeledMetricCounter { MEMPOOL_TRANSACTIONS_RECEIVED, "mempool_transactions_received", "Counter of transactions received by the mempool", init = 0, labels = INTERNAL_RPC_TRANSACTION_LABELS }, + LabeledMetricCounter { MEMPOOL_TRANSACTIONS_DROPPED, "mempool_transactions_dropped", "Counter of transactions dropped from the mempool", init = 0, labels = DROP_REASON_LABELS }, + MetricGauge { MEMPOOL_POOL_SIZE, "mempool_pool_size", "The size of the mempool's transaction pool" }, + MetricGauge { MEMPOOL_PRIORITY_QUEUE_SIZE, "mempool_priority_queue_size", "The size of the mempool's priority queue" }, + MetricGauge { MEMPOOL_PENDING_QUEUE_SIZE, "mempool_pending_queue_size", "The size of the mempool's pending queue" }, + MetricGauge { MEMPOOL_GET_TXS_SIZE, "mempool_get_txs_size", "The number of transactions returned in the last get_txs() api call" }, + MetricGauge { MEMPOOL_DELAYED_DECLARES_SIZE, "mempool_delayed_declare_size", "The number of declare transactions that are being delayed" }, + MetricHistogram { TRANSACTION_TIME_SPENT_IN_MEMPOOL, "mempool_transaction_time_spent", "The time (secs) that a transaction spent in the mempool" }, + }, +); + +pub const LABEL_NAME_TX_TYPE: &str = "tx_type"; +pub const LABEL_NAME_DROP_REASON: &str = "drop_reason"; + +generate_permutation_labels! { + INTERNAL_RPC_TRANSACTION_LABELS, + (LABEL_NAME_TX_TYPE, InternalRpcTransactionLabelValue), +} + +generate_permutation_labels! { + DROP_REASON_LABELS, + (LABEL_NAME_DROP_REASON, DropReason), +} + +enum TransactionStatus { + AddedToMempool, + Dropped, +} + +#[derive(IntoStaticStr, EnumIter, EnumVariantNames)] +#[strum(serialize_all = "snake_case")] +pub(crate) enum DropReason { + FailedAddTxChecks, + Expired, + Rejected, +} + +pub(crate) struct MempoolMetricHandle { + tx_type: InternalRpcTransactionLabelValue, + tx_status: TransactionStatus, +} + +impl MempoolMetricHandle { + pub fn new(tx: &InternalRpcTransactionWithoutTxHash) -> Self { + let tx_type = InternalRpcTransactionLabelValue::from(tx); + Self { tx_type, tx_status: TransactionStatus::Dropped } + } + + fn label(&self) -> Vec<(&'static str, &'static str)> { + vec![(LABEL_NAME_TX_TYPE, self.tx_type.into())] + } + + pub fn count_transaction_received(&self) { + MEMPOOL_TRANSACTIONS_RECEIVED.increment(1, &self.label()); + } + + pub fn transaction_inserted(&mut self) { + self.tx_status = TransactionStatus::AddedToMempool; + } +} + +impl Drop for MempoolMetricHandle { + fn drop(&mut self) { + match self.tx_status { + TransactionStatus::Dropped => MEMPOOL_TRANSACTIONS_DROPPED + .increment(1, &[(LABEL_NAME_DROP_REASON, DropReason::FailedAddTxChecks.into())]), + TransactionStatus::AddedToMempool => {} + } + } +} + +pub(crate) fn metric_count_expired_txs(n_txs: usize) { + MEMPOOL_TRANSACTIONS_DROPPED.increment( + n_txs.try_into().expect("The number of expired_txs should fit u64"), + &[(LABEL_NAME_DROP_REASON, DropReason::Expired.into())], + ); +} + +pub(crate) fn metric_count_rejected_txs(n_txs: usize) { + MEMPOOL_TRANSACTIONS_DROPPED.increment( + n_txs.try_into().expect("The number of rejected_txs should fit u64"), + &[(LABEL_NAME_DROP_REASON, DropReason::Rejected.into())], + ); +} + +pub(crate) fn metric_count_committed_txs(committed_txs: usize) { + MEMPOOL_TRANSACTIONS_COMMITTED + .increment(committed_txs.try_into().expect("The number of committed_txs should fit u64")); +} + +pub(crate) fn metric_set_get_txs_size(size: usize) { + MEMPOOL_GET_TXS_SIZE.set_lossy(size); +} + +impl Mempool { + pub(crate) fn update_state_metrics(&self) { + MEMPOOL_POOL_SIZE.set_lossy(self.tx_pool_len()); + MEMPOOL_PRIORITY_QUEUE_SIZE.set_lossy(self.priority_queue_len()); + MEMPOOL_PENDING_QUEUE_SIZE.set_lossy(self.pending_queue_len()); + MEMPOOL_DELAYED_DECLARES_SIZE.set_lossy(self.delayed_declares_len()); + } +} + +pub(crate) fn register_metrics() { + // Register Counters. + MEMPOOL_TRANSACTIONS_COMMITTED.register(); + MEMPOOL_TRANSACTIONS_RECEIVED.register(); + MEMPOOL_TRANSACTIONS_DROPPED.register(); + // Register Gauges. + MEMPOOL_POOL_SIZE.register(); + MEMPOOL_PRIORITY_QUEUE_SIZE.register(); + MEMPOOL_PENDING_QUEUE_SIZE.register(); + MEMPOOL_GET_TXS_SIZE.register(); + MEMPOOL_DELAYED_DECLARES_SIZE.register(); + // Register Histograms. + TRANSACTION_TIME_SPENT_IN_MEMPOOL.register(); +} diff --git a/crates/starknet_mempool/src/test_utils.rs b/crates/starknet_mempool/src/test_utils.rs index 472b4ae91da..c79cbbad89e 100644 --- a/crates/starknet_mempool/src/test_utils.rs +++ b/crates/starknet_mempool/src/test_utils.rs @@ -1,13 +1,32 @@ -use std::collections::{HashMap, HashSet}; +use std::collections::HashMap; +use std::sync::Mutex; +use std::time::Instant; +use metrics_exporter_prometheus::PrometheusRecorder; use pretty_assertions::assert_eq; -use starknet_api::executable_transaction::AccountTransaction; +use starknet_api::rpc_transaction::{InternalRpcTransaction, RpcTransactionLabelValue}; use starknet_api::transaction::TransactionHash; -use starknet_api::{contract_address, felt, nonce}; +use starknet_api::{contract_address, nonce}; use starknet_mempool_types::errors::MempoolError; use starknet_mempool_types::mempool_types::{AddTransactionArgs, CommitBlockArgs}; +use starknet_sequencer_metrics::metrics::HistogramValue; use crate::mempool::Mempool; +use crate::metrics::{ + DropReason, + LABEL_NAME_DROP_REASON, + LABEL_NAME_TX_TYPE, + MEMPOOL_DELAYED_DECLARES_SIZE, + MEMPOOL_GET_TXS_SIZE, + MEMPOOL_PENDING_QUEUE_SIZE, + MEMPOOL_POOL_SIZE, + MEMPOOL_PRIORITY_QUEUE_SIZE, + MEMPOOL_TRANSACTIONS_COMMITTED, + MEMPOOL_TRANSACTIONS_DROPPED, + MEMPOOL_TRANSACTIONS_RECEIVED, + TRANSACTION_TIME_SPENT_IN_MEMPOOL, +}; +use crate::utils::Clock; /// Creates an executable invoke transaction with the given field subset (the rest receive default /// values). @@ -21,17 +40,14 @@ macro_rules! tx { max_l2_gas_price: $max_l2_gas_price:expr ) => {{ use starknet_api::block::GasPrice; - use starknet_api::executable_transaction::AccountTransaction; - use starknet_api::hash::StarkHash; - use starknet_api::invoke_tx_args; - use starknet_api::test_utils::invoke::executable_invoke_tx; + use starknet_api::{invoke_tx_args, tx_hash}; + use starknet_api::test_utils::invoke::internal_invoke_tx; use starknet_api::transaction::fields::{ AllResourceBounds, ResourceBounds, Tip, ValidResourceBounds, }; - use starknet_api::transaction::TransactionHash; let resource_bounds = ValidResourceBounds::AllResources(AllResourceBounds { l2_gas: ResourceBounds { @@ -41,13 +57,13 @@ macro_rules! tx { ..Default::default() }); - AccountTransaction::Invoke(executable_invoke_tx(invoke_tx_args!{ - tx_hash: TransactionHash(StarkHash::from($tx_hash)), + internal_invoke_tx(invoke_tx_args!{ + tx_hash: tx_hash!($tx_hash), sender_address: contract_address!($address), nonce: nonce!($tx_nonce), tip: Tip($tip), resource_bounds, - })) + }) }}; (tx_hash: $tx_hash:expr, address: $address:expr, tx_nonce: $tx_nonce:expr, tip: $tip:expr) => {{ use mempool_test_utils::starknet_api_test_utils::VALID_L2_GAS_MAX_PRICE_PER_UNIT; @@ -217,6 +233,13 @@ macro_rules! add_tx_input { max_l2_gas_price: $max_l2_gas_price ) }; + (address: $address:expr) => { + add_tx_input!( + tx_hash: 0, + address: $address, + tip: 0 + ) + }; } #[track_caller] @@ -237,24 +260,106 @@ pub fn add_tx_expect_error( pub fn commit_block( mempool: &mut Mempool, nonces: impl IntoIterator, - tx_hashes: impl IntoIterator, + rejected_tx_hashes: impl IntoIterator, ) { let nonces = HashMap::from_iter( nonces.into_iter().map(|(address, nonce)| (contract_address!(address), nonce!(nonce))), ); - let tx_hashes = - HashSet::from_iter(tx_hashes.into_iter().map(|tx_hash| TransactionHash(felt!(tx_hash)))); - let args = CommitBlockArgs { address_to_nonce: nonces, tx_hashes }; + let rejected_tx_hashes = rejected_tx_hashes.into_iter().collect(); + let args = CommitBlockArgs { address_to_nonce: nonces, rejected_tx_hashes }; - assert_eq!(mempool.commit_block(args), Ok(())); + mempool.commit_block(args); } #[track_caller] pub fn get_txs_and_assert_expected( mempool: &mut Mempool, n_txs: usize, - expected_txs: &[AccountTransaction], + expected_txs: &[InternalRpcTransaction], ) { let txs = mempool.get_txs(n_txs).unwrap(); assert_eq!(txs, expected_txs); } + +pub struct FakeClock { + pub now: Mutex, +} + +impl Default for FakeClock { + fn default() -> Self { + FakeClock { now: Mutex::new(Instant::now()) } + } +} + +impl FakeClock { + pub fn advance(&self, duration: std::time::Duration) { + *self.now.lock().unwrap() += duration; + } +} + +impl Clock for FakeClock { + fn now(&self) -> Instant { + *self.now.lock().unwrap() + } +} + +#[derive(Default)] +pub struct MempoolMetrics { + pub txs_received_invoke: u64, + pub txs_received_declare: u64, + pub txs_received_deploy_account: u64, + pub txs_committed: u64, + pub txs_dropped_expired: u64, + pub txs_dropped_failed_add_tx_checks: u64, + pub txs_dropped_rejected: u64, + pub pool_size: u64, + pub priority_queue_size: u64, + pub pending_queue_size: u64, + pub get_txs_size: u64, + pub delayed_declares_size: u64, + pub transaction_time_spent_in_mempool: HistogramValue, +} + +impl MempoolMetrics { + pub fn verify_metrics(&self, recorder: &PrometheusRecorder) { + let metrics = &recorder.handle().render(); + MEMPOOL_TRANSACTIONS_RECEIVED.assert_eq( + metrics, + self.txs_received_invoke, + &[(LABEL_NAME_TX_TYPE, RpcTransactionLabelValue::Invoke.into())], + ); + MEMPOOL_TRANSACTIONS_RECEIVED.assert_eq( + metrics, + self.txs_received_declare, + &[(LABEL_NAME_TX_TYPE, RpcTransactionLabelValue::Declare.into())], + ); + MEMPOOL_TRANSACTIONS_RECEIVED.assert_eq( + metrics, + self.txs_received_deploy_account, + &[(LABEL_NAME_TX_TYPE, RpcTransactionLabelValue::DeployAccount.into())], + ); + MEMPOOL_TRANSACTIONS_COMMITTED.assert_eq(metrics, self.txs_committed); + MEMPOOL_TRANSACTIONS_DROPPED.assert_eq( + metrics, + self.txs_dropped_expired, + &[(LABEL_NAME_DROP_REASON, DropReason::Expired.into())], + ); + MEMPOOL_TRANSACTIONS_DROPPED.assert_eq( + metrics, + self.txs_dropped_failed_add_tx_checks, + &[(LABEL_NAME_DROP_REASON, DropReason::FailedAddTxChecks.into())], + ); + MEMPOOL_TRANSACTIONS_DROPPED.assert_eq( + metrics, + self.txs_dropped_rejected, + &[(LABEL_NAME_DROP_REASON, DropReason::Rejected.into())], + ); + MEMPOOL_POOL_SIZE.assert_eq(metrics, self.pool_size); + MEMPOOL_PRIORITY_QUEUE_SIZE.assert_eq(metrics, self.priority_queue_size); + MEMPOOL_PENDING_QUEUE_SIZE.assert_eq(metrics, self.pending_queue_size); + MEMPOOL_GET_TXS_SIZE.assert_eq(metrics, self.get_txs_size); + MEMPOOL_DELAYED_DECLARES_SIZE.assert_eq(metrics, self.delayed_declares_size); + TRANSACTION_TIME_SPENT_IN_MEMPOOL + .assert_eq(metrics, &self.transaction_time_spent_in_mempool); + } +} diff --git a/crates/starknet_mempool/src/transaction_pool.rs b/crates/starknet_mempool/src/transaction_pool.rs index 7da94658dd8..aeec60b23c2 100644 --- a/crates/starknet_mempool/src/transaction_pool.rs +++ b/crates/starknet_mempool/src/transaction_pool.rs @@ -1,32 +1,50 @@ +use std::cmp::Ordering; use std::collections::{hash_map, BTreeMap, HashMap}; +use std::sync::Arc; +use std::time::{Duration, Instant}; use starknet_api::core::{ContractAddress, Nonce}; -use starknet_api::executable_transaction::AccountTransaction; +use starknet_api::rpc_transaction::InternalRpcTransaction; use starknet_api::transaction::TransactionHash; use starknet_mempool_types::errors::MempoolError; use starknet_mempool_types::mempool_types::{AccountState, MempoolResult}; use crate::mempool::TransactionReference; -use crate::utils::try_increment_nonce; +use crate::metrics::TRANSACTION_TIME_SPENT_IN_MEMPOOL; +use crate::utils::{try_increment_nonce, Clock}; -type HashToTransaction = HashMap; +type HashToTransaction = HashMap; /// Contains all transactions currently held in the mempool. /// Invariant: both data structures are consistent regarding the existence of transactions: /// A transaction appears in one if and only if it appears in the other. /// No duplicate transactions appear in the pool. -#[derive(Debug, Default, Eq, PartialEq)] pub struct TransactionPool { // Holds the complete transaction objects; it should be the sole entity that does so. tx_pool: HashToTransaction, // Transactions organized by account address, sorted by ascending nonce values. txs_by_account: AccountTransactionIndex, + // Transactions sorted by their time spent in the pool (i.e. newest to oldest). + txs_by_submission_time: TimedTransactionMap, // Tracks the capacity of the pool. capacity: PoolCapacity, } impl TransactionPool { - pub fn insert(&mut self, tx: AccountTransaction) -> MempoolResult<()> { + pub fn new(clock: Arc) -> Self { + TransactionPool { + tx_pool: HashMap::new(), + txs_by_account: AccountTransactionIndex::default(), + txs_by_submission_time: TimedTransactionMap::new(clock), + capacity: PoolCapacity::default(), + } + } + + pub fn capacity(&self) -> usize { + self.capacity.n_txs() + } + + pub fn insert(&mut self, tx: InternalRpcTransaction) -> MempoolResult<()> { let tx_reference = TransactionReference::new(&tx); let tx_hash = tx_reference.tx_hash; @@ -47,42 +65,59 @@ impl TransactionPool { ) }; + // Insert to timed mapping. + let unexpected_existing_tx = self.txs_by_submission_time.insert(tx_reference); + if unexpected_existing_tx.is_some() { + panic!( + "Transaction pool consistency error: transaction with hash {tx_hash} does not + appear in main mapping, but transaction with same hash appears in the timed + mapping", + ) + }; + self.capacity.add(); Ok(()) } - pub fn remove(&mut self, tx_hash: TransactionHash) -> MempoolResult { + pub fn remove(&mut self, tx_hash: TransactionHash) -> MempoolResult { // Remove from pool. let tx = self.tx_pool.remove(&tx_hash).ok_or(MempoolError::TransactionNotFound { tx_hash })?; - // Remove from account mapping. - self.txs_by_account.remove(TransactionReference::new(&tx)).unwrap_or_else(|| { - panic!( - "Transaction pool consistency error: transaction with hash {tx_hash} appears in - main mapping, but does not appear in the account mapping" - ) - }); + // Remove reference from other mappings. + let removed_tx = vec![TransactionReference::new(&tx)]; + self.remove_from_account_mapping(&removed_tx); + self.remove_from_timed_mapping(&removed_tx); self.capacity.remove(); Ok(tx) } - pub fn remove_up_to_nonce(&mut self, address: ContractAddress, nonce: Nonce) { + pub fn remove_up_to_nonce(&mut self, address: ContractAddress, nonce: Nonce) -> usize { let removed_txs = self.txs_by_account.remove_up_to_nonce(address, nonce); - for TransactionReference { tx_hash, .. } in removed_txs { - self.tx_pool.remove(&tx_hash).unwrap_or_else(|| { - panic!( - "Transaction pool consistency error: transaction with hash {tx_hash} appears - in account mapping, but does not appear in the main mapping" - ); - }); + self.remove_from_main_mapping(&removed_txs); + self.remove_from_timed_mapping(&removed_txs); - self.capacity.remove(); - } + self.capacity.remove_n(removed_txs.len()); + removed_txs.len() + } + + pub fn remove_txs_older_than( + &mut self, + duration: Duration, + exclude_txs: &HashMap, + ) -> Vec { + let removed_txs = self.txs_by_submission_time.remove_txs_older_than(duration, exclude_txs); + + self.remove_from_main_mapping(&removed_txs); + self.remove_from_account_mapping(&removed_txs); + + self.capacity.remove_n(removed_txs.len()); + + removed_txs } pub fn account_txs_sorted_by_nonce( @@ -92,7 +127,10 @@ impl TransactionPool { self.txs_by_account.account_txs_sorted_by_nonce(address) } - pub fn get_by_tx_hash(&self, tx_hash: TransactionHash) -> MempoolResult<&AccountTransaction> { + pub fn get_by_tx_hash( + &self, + tx_hash: TransactionHash, + ) -> MempoolResult<&InternalRpcTransaction> { self.tx_pool.get(&tx_hash).ok_or(MempoolError::TransactionNotFound { tx_hash }) } @@ -113,8 +151,63 @@ impl TransactionPool { Ok(self.get_by_address_and_nonce(address, next_nonce)) } - pub fn _contains_account(&self, address: ContractAddress) -> bool { - self.txs_by_account._contains(address) + pub fn contains_account(&self, address: ContractAddress) -> bool { + self.txs_by_account.contains(address) + } + + pub fn get_submission_time(&self, tx_hash: TransactionHash) -> MempoolResult { + self.txs_by_submission_time + .hash_to_submission_id + .get(&tx_hash) + .map(|submission_id| submission_id.submission_time) + .ok_or(MempoolError::TransactionNotFound { tx_hash }) + } + + fn remove_from_main_mapping(&mut self, removed_txs: &Vec) { + for TransactionReference { tx_hash, .. } in removed_txs { + self.tx_pool.remove(tx_hash).unwrap_or_else(|| { + panic!( + "Transaction pool consistency error: transaction with hash {tx_hash} does not \ + appear in the main mapping.", + ) + }); + } + } + + fn remove_from_account_mapping(&mut self, removed_txs: &Vec) { + for tx in removed_txs { + let tx_hash = tx.tx_hash; + self.txs_by_account.remove(*tx).unwrap_or_else(|| { + panic!( + "Transaction pool consistency error: transaction with hash {tx_hash} does not \ + appear in the account index mapping.", + ) + }); + } + } + + fn remove_from_timed_mapping(&mut self, removed_txs: &Vec) { + for TransactionReference { tx_hash, .. } in removed_txs { + self.txs_by_submission_time.remove(*tx_hash).unwrap_or_else(|| { + panic!( + "Transaction pool consistency error: transaction with hash {tx_hash} does not \ + appear in the timed mapping.", + ) + }); + } + } + + pub fn get_chronological_txs_hashes(&self) -> Vec { + self.txs_by_submission_time + .txs_by_submission_time + .keys() + .map(|submission_id| submission_id.tx_hash) + .collect() + } + + #[cfg(test)] + pub fn tx_pool(&self) -> HashMap { + self.tx_pool.clone() } } @@ -172,12 +265,12 @@ impl AccountTransactionIndex { txs_with_lower_nonce.into_values().collect() } - fn _contains(&self, address: ContractAddress) -> bool { + fn contains(&self, address: ContractAddress) -> bool { self.0.contains_key(&address) } } -#[derive(Debug, Default, Eq, PartialEq)] +#[derive(Debug, Default, Eq, PartialEq, Clone)] pub struct PoolCapacity { n_txs: usize, // TODO(Ayelet): Add size tracking. @@ -192,4 +285,105 @@ impl PoolCapacity { self.n_txs = self.n_txs.checked_sub(1).expect("Underflow: Cannot subtract from an empty pool."); } + + fn remove_n(&mut self, n: usize) { + self.n_txs = + self.n_txs.checked_sub(n).expect("Underflow: Cannot subtract from an empty pool."); + } + + fn n_txs(&self) -> usize { + self.n_txs + } +} + +/// Uniquely identify a transaction submission. +#[derive(Clone, Debug, PartialEq, Eq)] +struct SubmissionID { + submission_time: Instant, + tx_hash: TransactionHash, +} + +// Implementing the `Ord` trait based on the transaction's duration in the pool. I.e. a transaction +// that has been in the pool for a longer time will be considered "greater" than a transaction that +// has been in the pool for a shorter time. +impl Ord for SubmissionID { + fn cmp(&self, other: &Self) -> Ordering { + self.submission_time + .cmp(&other.submission_time) + .reverse() + .then_with(|| self.tx_hash.cmp(&other.tx_hash)) + } +} + +impl PartialOrd for SubmissionID { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +struct TimedTransactionMap { + txs_by_submission_time: BTreeMap, + hash_to_submission_id: HashMap, + clock: Arc, +} + +impl TimedTransactionMap { + fn new(clock: Arc) -> Self { + TimedTransactionMap { + txs_by_submission_time: BTreeMap::new(), + hash_to_submission_id: HashMap::new(), + clock, + } + } + + /// If a transaction with the same transaction hash already exists in the mapping, the previous + /// submission ID is returned. + fn insert(&mut self, tx: TransactionReference) -> Option { + let submission_id = SubmissionID { submission_time: self.clock.now(), tx_hash: tx.tx_hash }; + self.txs_by_submission_time.insert(submission_id.clone(), tx); + self.hash_to_submission_id.insert(tx.tx_hash, submission_id) + } + + /// Removes the transaction with the given transaction hash from the mapping. + /// Returns the removed transaction reference if it exists in the mapping. + fn remove(&mut self, tx_hash: TransactionHash) -> Option { + let submission_id = self.hash_to_submission_id.remove(&tx_hash)?; + TRANSACTION_TIME_SPENT_IN_MEMPOOL + .record((self.clock.now() - submission_id.submission_time).as_secs_f64()); + self.txs_by_submission_time.remove(&submission_id) + } + + /// Removes all transactions that were submitted to the pool before the given duration. + /// Transactions for accounts listed in exclude_txs with nonces lower than the specified nonce + /// are preserved. + pub fn remove_txs_older_than( + &mut self, + duration: Duration, + exclude_txs: &HashMap, + ) -> Vec { + let split_off_value = SubmissionID { + submission_time: self.clock.now() - duration, + tx_hash: Default::default(), + }; + let old_txs = self.txs_by_submission_time.split_off(&split_off_value); + + let mut removed_txs = Vec::new(); + for (submission_id, tx) in old_txs.into_iter() { + if exclude_txs.get(&tx.address).is_some_and(|nonce| tx.nonce < *nonce) { + // The transaction should be preserved. Add it back. + self.txs_by_submission_time.insert(submission_id, tx); + } else { + let submission_id = self.hash_to_submission_id.remove(&tx.tx_hash).expect( + "Transaction should have a submission ID if it is in the timed transaction \ + map.", + ); + removed_txs.push(tx); + + TRANSACTION_TIME_SPENT_IN_MEMPOOL + .record((self.clock.now() - submission_id.submission_time).as_secs_f64()); + } + } + + removed_txs + } } diff --git a/crates/starknet_mempool/src/transaction_queue.rs b/crates/starknet_mempool/src/transaction_queue.rs index e0335dac692..dc1603ff924 100644 --- a/crates/starknet_mempool/src/transaction_queue.rs +++ b/crates/starknet_mempool/src/transaction_queue.rs @@ -1,7 +1,7 @@ use std::cmp::Ordering; use std::collections::{BTreeSet, HashMap}; -use starknet_api::block::GasPrice; +use starknet_api::block::NonzeroGasPrice; use starknet_api::core::{ContractAddress, Nonce}; use starknet_api::transaction::fields::Tip; use starknet_api::transaction::TransactionHash; @@ -15,9 +15,9 @@ pub mod transaction_queue_test_utils; // A queue holding the transaction that with nonces that match account nonces. // Note: the derived comparison functionality considers the order guaranteed by the data structures // used. -#[derive(Debug, Default, Eq, PartialEq)] +#[derive(Debug, Default)] pub struct TransactionQueue { - gas_price_threshold: GasPrice, + gas_price_threshold: NonzeroGasPrice, // Transactions with gas price above gas price threshold (sorted by tip). priority_queue: BTreeSet, // Transactions with gas price below gas price threshold (sorted by price). @@ -49,6 +49,14 @@ impl TransactionQueue { ); } + pub fn priority_queue_len(&self) -> usize { + self.priority_queue.len() + } + + pub fn pending_queue_len(&self) -> usize { + self.pending_queue.len() + } + // TODO(gilad): remove collect, if returning an iterator is possible. pub fn pop_ready_chunk(&mut self, n_txs: usize) -> Vec { let txs: Vec = @@ -81,11 +89,22 @@ impl TransactionQueue { || self.pending_queue.remove(&tx_reference.into()) } + /// Removes the given transactions from the queue. + /// If a transaction is not found, it is ignored. + pub fn remove_txs(&mut self, txs: &[TransactionReference]) { + for tx in txs { + let queued_tx = self.address_to_tx.get(&tx.address); + if queued_tx.is_some_and(|queued_tx| queued_tx.tx_hash == tx.tx_hash) { + self.remove(tx.address); + }; + } + } + pub fn has_ready_txs(&self) -> bool { !self.priority_queue.is_empty() } - pub fn update_gas_price_threshold(&mut self, threshold: GasPrice) { + pub fn update_gas_price_threshold(&mut self, threshold: NonzeroGasPrice) { match threshold.cmp(&self.gas_price_threshold) { Ordering::Less => self.promote_txs_to_priority(threshold), Ordering::Greater => self.demote_txs_to_pending(threshold), @@ -95,7 +114,7 @@ impl TransactionQueue { self.gas_price_threshold = threshold; } - fn promote_txs_to_priority(&mut self, threshold: GasPrice) { + fn promote_txs_to_priority(&mut self, threshold: NonzeroGasPrice) { let tmp_split_tx = PendingTransaction(TransactionReference { max_l2_gas_price: threshold, address: ContractAddress::default(), @@ -114,7 +133,7 @@ impl TransactionQueue { self.priority_queue.extend(txs_over_threshold.map(|tx| PriorityTransaction::from(tx.0))); } - fn demote_txs_to_pending(&mut self, threshold: GasPrice) { + fn demote_txs_to_pending(&mut self, threshold: NonzeroGasPrice) { let mut txs_to_remove = Vec::new(); // Remove all transactions from the priority queue that are below the threshold. diff --git a/crates/starknet_mempool/src/transaction_queue_test_utils.rs b/crates/starknet_mempool/src/transaction_queue_test_utils.rs index 6e1636ee72f..1847d47d18a 100644 --- a/crates/starknet_mempool/src/transaction_queue_test_utils.rs +++ b/crates/starknet_mempool/src/transaction_queue_test_utils.rs @@ -1,112 +1,35 @@ use std::collections::HashMap; -use starknet_api::block::GasPrice; +use starknet_api::block::NonzeroGasPrice; use crate::mempool::TransactionReference; use crate::transaction_queue::{PendingTransaction, PriorityTransaction, TransactionQueue}; -type OptionalPriorityTransactions = Option>; -type OptionalPendingTransactions = Option>; - -/// Represents the internal content of the transaction queue. -/// Enables customized (and potentially inconsistent) creation for unit testing. -/// Note: gas price threshold is only used for building the (non-test) queue struct. -#[derive(Debug, Default)] -pub struct TransactionQueueContent { - priority_queue: OptionalPriorityTransactions, - pending_queue: OptionalPendingTransactions, - gas_price_threshold: Option, -} - -impl TransactionQueueContent { - #[track_caller] - pub fn assert_eq(&self, tx_queue: &TransactionQueue) { - if let Some(priority_queue) = &self.priority_queue { - let expected_priority_txs: Vec<_> = priority_queue.iter().map(|tx| &tx.0).collect(); - let actual_priority_txs: Vec<_> = tx_queue.iter_over_ready_txs().collect(); - assert_eq!(actual_priority_txs, expected_priority_txs); - } - - if let Some(pending_queue) = &self.pending_queue { - let expected_pending_txs: Vec<_> = pending_queue.iter().map(|tx| &tx.0).collect(); - let actual_pending_txs: Vec<_> = - tx_queue.pending_queue.iter().rev().map(|tx| &tx.0).collect(); - assert_eq!(actual_pending_txs, expected_pending_txs); - } - } - - pub fn complete_to_tx_queue(self) -> TransactionQueue { - let pending_queue = self.pending_queue.unwrap_or_default(); - let priority_queue = self.priority_queue.unwrap_or_default(); - let gas_price_threshold = self.gas_price_threshold.unwrap_or_default(); - +impl TransactionQueue { + pub fn new( + priority_queue: Vec, + pending_queue: Vec, + gas_price_threshold: NonzeroGasPrice, + ) -> Self { // Build address to nonce mapping, check queues are mutually exclusive in addresses. - let tx_references = pending_queue - .iter() - .map(|pending_tx| pending_tx.0) - .chain(priority_queue.iter().map(|priority_tx| priority_tx.0)); + let tx_references = pending_queue.iter().chain(priority_queue.iter()); let mut address_to_tx = HashMap::new(); for tx_ref in tx_references { let address = tx_ref.address; - if address_to_tx.insert(address, tx_ref).is_some() { + if address_to_tx.insert(address, *tx_ref).is_some() { panic!("Duplicate address: {address}; queues must be mutually exclusive."); } } TransactionQueue { - priority_queue: priority_queue.into_iter().collect(), - pending_queue: pending_queue.into_iter().collect(), + priority_queue: priority_queue.into_iter().map(PriorityTransaction).collect(), + pending_queue: pending_queue.into_iter().map(PendingTransaction).collect(), address_to_tx, gas_price_threshold, } } -} - -#[derive(Debug, Default)] -pub struct TransactionQueueContentBuilder { - priority_queue: OptionalPriorityTransactions, - pending_queue: OptionalPendingTransactions, - gas_price_threshold: Option, -} - -impl TransactionQueueContentBuilder { - pub fn with_priority

(mut self, priority_txs: P) -> Self - where - P: IntoIterator, - { - self.priority_queue = - Some(priority_txs.into_iter().map(PriorityTransaction::from).collect()); - self - } - - pub fn with_pending

(mut self, pending_txs: P) -> Self - where - P: IntoIterator, - { - self.pending_queue = Some(pending_txs.into_iter().map(PendingTransaction::from).collect()); - self - } - - pub fn with_gas_price_threshold(mut self, gas_price_threshold: u128) -> Self { - self.gas_price_threshold = Some(gas_price_threshold.into()); - self - } - - pub fn build(self) -> Option { - if self.is_default() { - return None; - } - - Some(TransactionQueueContent { - priority_queue: self.priority_queue, - pending_queue: self.pending_queue, - gas_price_threshold: self.gas_price_threshold, - }) - } - fn is_default(&self) -> bool { - self.priority_queue.is_none() - && self.pending_queue.is_none() - && self.gas_price_threshold.is_none() + pub fn pending_txs(&self) -> Vec { + self.pending_queue.iter().rev().map(|tx| tx.0).collect() } } diff --git a/crates/starknet_mempool/src/utils.rs b/crates/starknet_mempool/src/utils.rs index b2e5da1459f..218581f90e6 100644 --- a/crates/starknet_mempool/src/utils.rs +++ b/crates/starknet_mempool/src/utils.rs @@ -1,3 +1,5 @@ +use std::time::Instant; + use starknet_api::core::Nonce; use starknet_mempool_types::communication::MempoolResult; use starknet_mempool_types::errors::MempoolError; @@ -5,3 +7,16 @@ use starknet_mempool_types::errors::MempoolError; pub fn try_increment_nonce(nonce: Nonce) -> MempoolResult { nonce.try_increment().map_err(|_| MempoolError::NonceTooLarge(nonce)) } + +// TODO(dafna, 01/03/2025): Move to a common utils crate. +pub trait Clock: Send + Sync { + fn now(&self) -> Instant; +} + +pub struct InstantClock; + +impl Clock for InstantClock { + fn now(&self) -> Instant { + Instant::now() + } +} diff --git a/crates/starknet_mempool_p2p/Cargo.toml b/crates/starknet_mempool_p2p/Cargo.toml index 5e5b278e499..e80ba6e2b18 100644 --- a/crates/starknet_mempool_p2p/Cargo.toml +++ b/crates/starknet_mempool_p2p/Cargo.toml @@ -5,6 +5,9 @@ edition.workspace = true license.workspace = true repository.workspace = true +[features] +testing = [] + [lints] workspace = true @@ -13,23 +16,30 @@ async-trait.workspace = true futures.workspace = true papyrus_config.workspace = true papyrus_network.workspace = true -papyrus_network_types = { workspace = true, features = ["testing"] } +papyrus_network_types.workspace = true papyrus_protobuf.workspace = true serde.workspace = true starknet_api.workspace = true +starknet_class_manager_types.workspace = true starknet_gateway_types.workspace = true starknet_mempool_p2p_types.workspace = true starknet_sequencer_infra.workspace = true +starknet_sequencer_metrics.workspace = true tokio.workspace = true tracing.workspace = true validator.workspace = true [dev-dependencies] futures.workspace = true +libp2p.workspace = true +mockall.workspace = true papyrus_network = { workspace = true, features = ["testing"] } papyrus_network_types = { workspace = true, features = ["testing"] } papyrus_protobuf.workspace = true papyrus_test_utils.workspace = true rand_chacha.workspace = true starknet_api.workspace = true +starknet_class_manager_types = { workspace = true, features = ["testing"] } +starknet_gateway_types = { workspace = true, features = ["testing"] } +starknet_mempool_p2p_types = { workspace = true, features = ["testing"] } tokio = { workspace = true, features = ["full", "sync", "test-util"] } diff --git a/crates/starknet_mempool_p2p/src/config.rs b/crates/starknet_mempool_p2p/src/config.rs index ff32d0f3545..c0b84ac96ec 100644 --- a/crates/starknet_mempool_p2p/src/config.rs +++ b/crates/starknet_mempool_p2p/src/config.rs @@ -1,33 +1,61 @@ use std::collections::BTreeMap; +use std::time::Duration; +use papyrus_config::converters::deserialize_milliseconds_to_duration; use papyrus_config::dumping::{append_sub_config_name, ser_param, SerializeConfig}; use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; use papyrus_network::NetworkConfig; use serde::{Deserialize, Serialize}; use validator::Validate; +const MEMPOOL_TCP_PORT: u16 = 11111; + #[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Validate)] pub struct MempoolP2pConfig { #[validate] pub network_config: NetworkConfig, pub network_buffer_size: usize, + pub max_transaction_batch_size: usize, + #[serde(deserialize_with = "deserialize_milliseconds_to_duration")] + pub transaction_batch_rate_millis: Duration, } impl Default for MempoolP2pConfig { fn default() -> Self { - Self { network_config: NetworkConfig::default(), network_buffer_size: 10000 } + Self { + network_config: NetworkConfig { port: MEMPOOL_TCP_PORT, ..Default::default() }, + network_buffer_size: 10000, + // TODO(Eitan): Change to appropriate values. + max_transaction_batch_size: 1, + transaction_batch_rate_millis: Duration::from_secs(1), + } } } impl SerializeConfig for MempoolP2pConfig { fn dump(&self) -> BTreeMap { vec![ - BTreeMap::from_iter([ser_param( - "network_buffer_size", - &self.network_buffer_size, - "Network buffer size.", - ParamPrivacyInput::Public, - )]), + BTreeMap::from_iter([ + ser_param( + "network_buffer_size", + &self.network_buffer_size, + "Network buffer size.", + ParamPrivacyInput::Public, + ), + ser_param( + "max_transaction_batch_size", + &self.max_transaction_batch_size, + "Maximum number of transactions in each batch.", + ParamPrivacyInput::Public, + ), + ser_param( + "transaction_batch_rate_millis", + &self.transaction_batch_rate_millis.as_millis(), + "Maximum time until a transaction batch is closed and propagated in \ + milliseconds.", + ParamPrivacyInput::Public, + ), + ]), append_sub_config_name(self.network_config.dump(), "network_config"), ] .into_iter() diff --git a/crates/starknet_mempool_p2p/src/lib.rs b/crates/starknet_mempool_p2p/src/lib.rs index 08150ddebb5..53ce69e50bb 100644 --- a/crates/starknet_mempool_p2p/src/lib.rs +++ b/crates/starknet_mempool_p2p/src/lib.rs @@ -1,12 +1,26 @@ pub mod config; +pub mod metrics; pub mod propagator; pub mod runner; +use std::collections::HashMap; + +use futures::FutureExt; +use metrics::MEMPOOL_P2P_NUM_BLACKLISTED_PEERS; use papyrus_network::gossipsub_impl::Topic; +use papyrus_network::network_manager::metrics::{BroadcastNetworkMetrics, NetworkMetrics}; use papyrus_network::network_manager::{BroadcastTopicChannels, NetworkManager}; +use starknet_class_manager_types::transaction_converter::TransactionConverter; +use starknet_class_manager_types::SharedClassManagerClient; use starknet_gateway_types::communication::SharedGatewayClient; +use starknet_mempool_p2p_types::communication::SharedMempoolP2pPropagatorClient; use crate::config::MempoolP2pConfig; +use crate::metrics::{ + MEMPOOL_P2P_NUM_CONNECTED_PEERS, + MEMPOOL_P2P_NUM_RECEIVED_MESSAGES, + MEMPOOL_P2P_NUM_SENT_MESSAGES, +}; use crate::propagator::MempoolP2pPropagator; use crate::runner::MempoolP2pRunner; @@ -15,11 +29,32 @@ pub const MEMPOOL_TOPIC: &str = "starknet_mempool_transaction_propagation/0.1.0" pub fn create_p2p_propagator_and_runner( mempool_p2p_config: MempoolP2pConfig, gateway_client: SharedGatewayClient, + class_manager_client: SharedClassManagerClient, + mempool_p2p_propagator_client: SharedMempoolP2pPropagatorClient, ) -> (MempoolP2pPropagator, MempoolP2pRunner) { + let transaction_converter = TransactionConverter::new( + class_manager_client.clone(), + mempool_p2p_config.network_config.chain_id.clone(), + ); + let mut broadcast_metrics_by_topic = HashMap::new(); + broadcast_metrics_by_topic.insert( + Topic::new(MEMPOOL_TOPIC).hash(), + BroadcastNetworkMetrics { + num_sent_broadcast_messages: MEMPOOL_P2P_NUM_SENT_MESSAGES, + num_received_broadcast_messages: MEMPOOL_P2P_NUM_RECEIVED_MESSAGES, + }, + ); + let network_manager_metrics = Some(NetworkMetrics { + num_connected_peers: MEMPOOL_P2P_NUM_CONNECTED_PEERS, + num_blacklisted_peers: MEMPOOL_P2P_NUM_BLACKLISTED_PEERS, + broadcast_metrics_by_topic: Some(broadcast_metrics_by_topic), + sqmr_metrics: None, + }); let mut network_manager = NetworkManager::new( mempool_p2p_config.network_config, - // TODO: Consider filling this once the sequencer node has a name. + // TODO(Shahak): Consider filling this once the sequencer node has a name. None, + network_manager_metrics, ); let BroadcastTopicChannels { broadcasted_messages_receiver, broadcast_topic_client } = network_manager @@ -28,12 +63,19 @@ pub fn create_p2p_propagator_and_runner( mempool_p2p_config.network_buffer_size, ) .expect("Failed to register broadcast topic"); - let mempool_p2p_propagator = MempoolP2pPropagator::new(broadcast_topic_client.clone()); + let network_future = network_manager.run(); + let mempool_p2p_propagator = MempoolP2pPropagator::new( + broadcast_topic_client.clone(), + Box::new(transaction_converter), + mempool_p2p_config.max_transaction_batch_size, + ); let mempool_p2p_runner = MempoolP2pRunner::new( - Some(network_manager), + network_future.boxed(), broadcasted_messages_receiver, broadcast_topic_client, gateway_client, + mempool_p2p_propagator_client, + mempool_p2p_config.transaction_batch_rate_millis, ); (mempool_p2p_propagator, mempool_p2p_runner) } diff --git a/crates/starknet_mempool_p2p/src/metrics.rs b/crates/starknet_mempool_p2p/src/metrics.rs new file mode 100644 index 00000000000..383ed060b57 --- /dev/null +++ b/crates/starknet_mempool_p2p/src/metrics.rs @@ -0,0 +1,15 @@ +use starknet_sequencer_metrics::define_metrics; +use starknet_sequencer_metrics::metrics::{MetricCounter, MetricGauge, MetricHistogram}; + +define_metrics!( + MempoolP2p => { + // Gauges + MetricGauge { MEMPOOL_P2P_NUM_CONNECTED_PEERS, "apollo_mempool_p2p_num_connected_peers", "The number of connected peers to the mempool p2p component" }, + MetricGauge { MEMPOOL_P2P_NUM_BLACKLISTED_PEERS, "apollo_mempool_p2p_num_blacklisted_peers", "The number of currently blacklisted peers by the mempool p2p component" }, + // Counters + MetricCounter { MEMPOOL_P2P_NUM_SENT_MESSAGES, "apollo_mempool_p2p_num_sent_messages", "The number of messages sent by the mempool p2p component", init = 0 }, + MetricCounter { MEMPOOL_P2P_NUM_RECEIVED_MESSAGES, "apollo_mempool_p2p_num_received_messages", "The number of messages received by the mempool p2p component", init = 0 }, + // Histogram + MetricHistogram { MEMPOOL_P2P_BROADCASTED_BATCH_SIZE, "apollo_mempool_p2p_broadcasted_transaction_batch_size", "The number of transactions in batches broadcast by the mempool p2p component" } + }, +); diff --git a/crates/starknet_mempool_p2p/src/propagator/mod.rs b/crates/starknet_mempool_p2p/src/propagator/mod.rs index dc896fc6143..292dc30c01c 100644 --- a/crates/starknet_mempool_p2p/src/propagator/mod.rs +++ b/crates/starknet_mempool_p2p/src/propagator/mod.rs @@ -3,22 +3,43 @@ mod test; use async_trait::async_trait; use papyrus_network::network_manager::{BroadcastTopicClient, BroadcastTopicClientTrait}; -use papyrus_protobuf::mempool::RpcTransactionWrapper; +use papyrus_network_types::network_types::BroadcastedMessageMetadata; +use papyrus_protobuf::mempool::RpcTransactionBatch; +use starknet_api::rpc_transaction::{InternalRpcTransaction, RpcTransaction}; +use starknet_class_manager_types::transaction_converter::TransactionConverterTrait; use starknet_mempool_p2p_types::communication::{ MempoolP2pPropagatorRequest, MempoolP2pPropagatorResponse, }; use starknet_mempool_p2p_types::errors::MempoolP2pPropagatorError; +use starknet_mempool_p2p_types::mempool_p2p_types::MempoolP2pPropagatorResult; use starknet_sequencer_infra::component_definitions::{ComponentRequestHandler, ComponentStarter}; use starknet_sequencer_infra::component_server::{LocalComponentServer, RemoteComponentServer}; +use starknet_sequencer_metrics::metrics::LossyIntoF64; +use tracing::{debug, info, warn}; + +use crate::metrics::MEMPOOL_P2P_BROADCASTED_BATCH_SIZE; pub struct MempoolP2pPropagator { - broadcast_topic_client: BroadcastTopicClient, + broadcast_topic_client: BroadcastTopicClient, + transaction_converter: Box, + max_transaction_batch_size: usize, + transaction_queue: Vec, } impl MempoolP2pPropagator { - pub fn new(broadcast_topic_client: BroadcastTopicClient) -> Self { - Self { broadcast_topic_client } + pub fn new( + broadcast_topic_client: BroadcastTopicClient, + transaction_converter: Box, + max_transaction_batch_size: usize, + ) -> Self { + MEMPOOL_P2P_BROADCASTED_BATCH_SIZE.register(); + Self { + broadcast_topic_client, + transaction_converter, + max_transaction_batch_size, + transaction_queue: vec![], + } } } @@ -32,22 +53,83 @@ impl ComponentRequestHandler MempoolP2pPropagatorResponse { match request { MempoolP2pPropagatorRequest::AddTransaction(transaction) => { - let result = self - .broadcast_topic_client - .broadcast_message(RpcTransactionWrapper(transaction)) - .await - .map_err(|_| MempoolP2pPropagatorError::NetworkSendError); - MempoolP2pPropagatorResponse::AddTransaction(result) + MempoolP2pPropagatorResponse::AddTransaction( + self.add_transaction(transaction).await, + ) } - MempoolP2pPropagatorRequest::ContinuePropagation(propagation_manager) => { - let result = self - .broadcast_topic_client - .continue_propagation(&propagation_manager) - .await - .map_err(|_| MempoolP2pPropagatorError::NetworkSendError); - MempoolP2pPropagatorResponse::ContinuePropagation(result) + MempoolP2pPropagatorRequest::ContinuePropagation(broadcasted_message_metadata) => { + MempoolP2pPropagatorResponse::ContinuePropagation( + self.continue_propagation(broadcasted_message_metadata).await, + ) } + MempoolP2pPropagatorRequest::BroadcastQueuedTransactions() => { + MempoolP2pPropagatorResponse::BroadcastQueuedTransactions( + self.broadcast_queued_transactions().await, + ) + } + } + } +} + +impl MempoolP2pPropagator { + async fn add_transaction( + &mut self, + transaction: InternalRpcTransaction, + ) -> MempoolP2pPropagatorResult<()> { + info!("Received a new transaction to broadcast to other mempool peers"); + debug!("broadcasted tx_hash: {:?}", transaction.tx_hash); + let transaction = + match self.transaction_converter.convert_internal_rpc_tx_to_rpc_tx(transaction).await { + Ok(transaction) => transaction, + Err(err) => { + return Err(MempoolP2pPropagatorError::TransactionConversionError( + err.to_string(), + )); + } + }; + + self.transaction_queue.push(transaction); + if self.transaction_queue.len() == self.max_transaction_batch_size { + info!("Transaction batch is full. Broadcasting the transaction batch"); + return self.broadcast_queued_transactions().await; + } + Ok(()) + } + + async fn continue_propagation( + &mut self, + broadcasted_message_metadata: BroadcastedMessageMetadata, + ) -> MempoolP2pPropagatorResult<()> { + info!("Continuing propagation of received transaction"); + debug!("Propagated transaction metadata: {:?}", broadcasted_message_metadata); + self.broadcast_topic_client + .continue_propagation(&broadcasted_message_metadata) + .await + .map_err(|_| MempoolP2pPropagatorError::NetworkSendError) + } + + async fn broadcast_queued_transactions(&mut self) -> MempoolP2pPropagatorResult<()> { + let queued_transactions: Vec = self.transaction_queue.drain(..).collect(); + if queued_transactions.is_empty() { + return Ok(()); } + let number_of_transactions_in_batch = queued_transactions.len().into_f64(); + let result = self + .broadcast_topic_client + .broadcast_message(RpcTransactionBatch(queued_transactions)) + .await + .or_else(|err| { + if !err.is_full() { + return Err(MempoolP2pPropagatorError::NetworkSendError); + } + warn!( + "Trying to send a transaction batch to other mempool peers but the buffer is \ + full. Dropping the transaction batch." + ); + Ok(()) + }); + MEMPOOL_P2P_BROADCASTED_BATCH_SIZE.record(number_of_transactions_in_batch); + result } } diff --git a/crates/starknet_mempool_p2p/src/propagator/test.rs b/crates/starknet_mempool_p2p/src/propagator/test.rs index 155e8320606..8e3b30a9886 100644 --- a/crates/starknet_mempool_p2p/src/propagator/test.rs +++ b/crates/starknet_mempool_p2p/src/propagator/test.rs @@ -1,14 +1,22 @@ +use futures::channel::mpsc::Receiver; use futures::stream::StreamExt; +use futures::FutureExt; +use mockall::predicate; use papyrus_network::network_manager::test_utils::{ mock_register_broadcast_topic, BroadcastNetworkMock, + MockMessagesToBroadcastReceiver, TestSubscriberChannels, }; -use papyrus_network::network_manager::BroadcastTopicChannels; +use papyrus_network::network_manager::{BroadcastTopicChannels, BroadcastTopicClient}; use papyrus_network_types::network_types::BroadcastedMessageMetadata; -use papyrus_protobuf::mempool::RpcTransactionWrapper; +use papyrus_protobuf::mempool::RpcTransactionBatch; use papyrus_test_utils::{get_rng, GetTestInstance}; -use starknet_api::rpc_transaction::RpcTransaction; +use starknet_api::rpc_transaction::{InternalRpcTransaction, RpcTransaction}; +use starknet_class_manager_types::transaction_converter::{ + MockTransactionConverterTrait, + TransactionConverterTrait, +}; use starknet_mempool_p2p_types::communication::MempoolP2pPropagatorRequest; use starknet_sequencer_infra::component_definitions::ComponentRequestHandler; use tokio::time::timeout; @@ -16,32 +24,72 @@ use tokio::time::timeout; use super::MempoolP2pPropagator; const TIMEOUT: std::time::Duration = std::time::Duration::from_secs(1); +const MAX_TRANSACTION_BATCH_SIZE: usize = 5; -#[tokio::test] -async fn process_handle_add_tx() { +fn setup() -> ( + BroadcastTopicClient, + MockMessagesToBroadcastReceiver, + Receiver, +) { let TestSubscriberChannels { mock_network, subscriber_channels } = mock_register_broadcast_topic().expect("Failed to create mock network"); let BroadcastTopicChannels { broadcasted_messages_receiver: _, broadcast_topic_client } = subscriber_channels; - let BroadcastNetworkMock { mut messages_to_broadcast_receiver, .. } = mock_network; - let rpc_transaction = RpcTransaction::get_test_instance(&mut get_rng()); - let mut mempool_p2p_propagator = MempoolP2pPropagator::new(broadcast_topic_client); + let BroadcastNetworkMock { + messages_to_broadcast_receiver, continue_propagation_receiver, .. + } = mock_network; + (broadcast_topic_client, messages_to_broadcast_receiver, continue_propagation_receiver) +} + +fn mock_transaction_conversions( + num_transactions: usize, +) -> ( + Box, + Vec, + Vec, +) { + let mut seq = mockall::Sequence::new(); + let mut transaction_converter = MockTransactionConverterTrait::new(); + let mut rpc_transactions = vec![]; + let mut internal_transactions = vec![]; + for _ in 0..num_transactions { + let internal_tx = InternalRpcTransaction::get_test_instance(&mut get_rng()); + let rpc_transaction = RpcTransaction::get_test_instance(&mut get_rng()); + rpc_transactions.push(rpc_transaction.clone()); + internal_transactions.push(internal_tx.clone()); + transaction_converter + .expect_convert_internal_rpc_tx_to_rpc_tx() + .with(predicate::eq(internal_tx)) + .times(1) + .in_sequence(&mut seq) + .return_once(move |_| Ok(rpc_transaction)); + } + (Box::new(transaction_converter), rpc_transactions, internal_transactions) +} + +#[tokio::test] +async fn process_handle_add_tx() { + let (broadcast_topic_client, mut messages_to_broadcast_receiver, _) = setup(); + let (transaction_converter, rpc_transactions, internal_transactions) = + mock_transaction_conversions(1); + let rpc_transaction = rpc_transactions.first().unwrap().to_owned(); + let internal_tx = internal_transactions.first().unwrap().to_owned(); + let mut mempool_p2p_propagator = + MempoolP2pPropagator::new(broadcast_topic_client, transaction_converter, 1); mempool_p2p_propagator - .handle_request(MempoolP2pPropagatorRequest::AddTransaction(rpc_transaction.clone())) + .handle_request(MempoolP2pPropagatorRequest::AddTransaction(internal_tx)) .await; let message = timeout(TIMEOUT, messages_to_broadcast_receiver.next()).await.unwrap().unwrap(); - assert_eq!(message, RpcTransactionWrapper(rpc_transaction)); + assert_eq!(message, RpcTransactionBatch(vec![rpc_transaction])); } #[tokio::test] async fn process_handle_continue_propagation() { - let TestSubscriberChannels { mock_network, subscriber_channels } = - mock_register_broadcast_topic().expect("Failed to create mock network"); - let BroadcastTopicChannels { broadcasted_messages_receiver: _, broadcast_topic_client } = - subscriber_channels; - let BroadcastNetworkMock { mut continue_propagation_receiver, .. } = mock_network; + let (broadcast_topic_client, _, mut continue_propagation_receiver) = setup(); let propagation_metadata = BroadcastedMessageMetadata::get_test_instance(&mut get_rng()); - let mut mempool_p2p_propagator = MempoolP2pPropagator::new(broadcast_topic_client); + let transaction_converter = MockTransactionConverterTrait::new(); + let mut mempool_p2p_propagator = + MempoolP2pPropagator::new(broadcast_topic_client, Box::new(transaction_converter), 1); mempool_p2p_propagator .handle_request(MempoolP2pPropagatorRequest::ContinuePropagation( propagation_metadata.clone(), @@ -50,3 +98,86 @@ async fn process_handle_continue_propagation() { let message = timeout(TIMEOUT, continue_propagation_receiver.next()).await.unwrap().unwrap(); assert_eq!(message, propagation_metadata); } + +#[tokio::test] +async fn transaction_batch_broadcasted_on_max_size() { + let (broadcast_topic_client, mut messages_to_broadcast_receiver, _) = setup(); + + let (transaction_converter, rpc_transactions, mut internal_transactions) = + mock_transaction_conversions(MAX_TRANSACTION_BATCH_SIZE); + + let mut mempool_p2p_propagator = MempoolP2pPropagator::new( + broadcast_topic_client, + transaction_converter, + MAX_TRANSACTION_BATCH_SIZE, + ); + + // Assert the first (MAX_TRANSACTION_BATCH_SIZE - 1) transactions do not trigger batch broadcast + let final_internal_tx = internal_transactions.pop().unwrap(); + + for internal_tx in internal_transactions { + mempool_p2p_propagator + .handle_request(MempoolP2pPropagatorRequest::AddTransaction(internal_tx)) + .await; + } + + assert!(messages_to_broadcast_receiver.next().now_or_never().is_none()); + + mempool_p2p_propagator + .handle_request(MempoolP2pPropagatorRequest::AddTransaction(final_internal_tx)) + .await; + + // Assert the MAX_TRANSACTION_BATCH_SIZE message does trigger batch broadcast + let message = timeout(TIMEOUT, messages_to_broadcast_receiver.next()).await.unwrap().unwrap(); + assert_eq!(message, RpcTransactionBatch(rpc_transactions)); +} + +#[tokio::test] +async fn transaction_batch_broadcasted_on_request() { + let (broadcast_topic_client, mut messages_to_broadcast_receiver, _) = setup(); + + let (transaction_converter, rpc_transactions, internal_transactions) = + mock_transaction_conversions(MAX_TRANSACTION_BATCH_SIZE - 1); + + let mut mempool_p2p_propagator = MempoolP2pPropagator::new( + broadcast_topic_client, + transaction_converter, + MAX_TRANSACTION_BATCH_SIZE, + ); + + for internal_tx in internal_transactions { + mempool_p2p_propagator + .handle_request(MempoolP2pPropagatorRequest::AddTransaction(internal_tx)) + .await; + } + + // Assert adding the transaction does not trigger batch broadcast + assert!(messages_to_broadcast_receiver.next().now_or_never().is_none()); + + mempool_p2p_propagator + .handle_request(MempoolP2pPropagatorRequest::BroadcastQueuedTransactions()) + .await; + + // Assert the request triggered batch broadcast + let message = timeout(TIMEOUT, messages_to_broadcast_receiver.next()).await.unwrap().unwrap(); + assert_eq!(message, RpcTransactionBatch(rpc_transactions)); +} + +#[tokio::test] +async fn broadcast_queued_transactions_does_not_broadcast_empty_batch() { + let (broadcast_topic_client, mut messages_to_broadcast_receiver, _) = setup(); + let transaction_converter = MockTransactionConverterTrait::new(); + let mut mempool_p2p_propagator = MempoolP2pPropagator::new( + broadcast_topic_client, + Box::new(transaction_converter), + MAX_TRANSACTION_BATCH_SIZE, + ); + + mempool_p2p_propagator + .handle_request(MempoolP2pPropagatorRequest::BroadcastQueuedTransactions()) + .await; + + // Assert receiving the request does not trigger batch broadcast (because there are no queued + // transactions) + assert!(messages_to_broadcast_receiver.next().now_or_never().is_none()); +} diff --git a/crates/starknet_mempool_p2p/src/runner/mod.rs b/crates/starknet_mempool_p2p/src/runner/mod.rs index 8f2e6563cbc..8914027fcac 100644 --- a/crates/starknet_mempool_p2p/src/runner/mod.rs +++ b/crates/starknet_mempool_p2p/src/runner/mod.rs @@ -1,69 +1,94 @@ #[cfg(test)] mod test; +use std::time::Duration; + use async_trait::async_trait; +use futures::future::BoxFuture; use futures::stream::FuturesUnordered; -use futures::{pin_mut, StreamExt, TryFutureExt}; +use futures::StreamExt; use papyrus_network::network_manager::{ BroadcastTopicClient, BroadcastTopicClientTrait, BroadcastTopicServer, - NetworkManager, + NetworkError, }; -use papyrus_protobuf::mempool::RpcTransactionWrapper; +use papyrus_protobuf::mempool::RpcTransactionBatch; use starknet_gateway_types::communication::{GatewayClientError, SharedGatewayClient}; use starknet_gateway_types::errors::GatewayError; use starknet_gateway_types::gateway_types::GatewayInput; +use starknet_mempool_p2p_types::communication::SharedMempoolP2pPropagatorClient; use starknet_sequencer_infra::component_definitions::ComponentStarter; use starknet_sequencer_infra::component_server::WrapperServer; -use starknet_sequencer_infra::errors::ComponentError; -use tracing::warn; +use tokio::time::MissedTickBehavior::Delay; +use tracing::{debug, info, warn}; pub struct MempoolP2pRunner { - network_manager: Option, - broadcasted_topic_server: BroadcastTopicServer, - broadcast_topic_client: BroadcastTopicClient, + network_future: BoxFuture<'static, Result<(), NetworkError>>, + broadcasted_topic_server: BroadcastTopicServer, + broadcast_topic_client: BroadcastTopicClient, gateway_client: SharedGatewayClient, + _mempool_p2p_propagator_client: SharedMempoolP2pPropagatorClient, + transaction_batch_rate_millis: Duration, } impl MempoolP2pRunner { pub fn new( - network_manager: Option, - broadcasted_topic_server: BroadcastTopicServer, - broadcast_topic_client: BroadcastTopicClient, + network_future: BoxFuture<'static, Result<(), NetworkError>>, + broadcasted_topic_server: BroadcastTopicServer, + broadcast_topic_client: BroadcastTopicClient, gateway_client: SharedGatewayClient, + mempool_p2p_propagator_client: SharedMempoolP2pPropagatorClient, + transaction_batch_rate_millis: Duration, ) -> Self { - Self { network_manager, broadcasted_topic_server, broadcast_topic_client, gateway_client } + Self { + network_future, + broadcasted_topic_server, + broadcast_topic_client, + gateway_client, + _mempool_p2p_propagator_client: mempool_p2p_propagator_client, + transaction_batch_rate_millis, + } } } #[async_trait] impl ComponentStarter for MempoolP2pRunner { - async fn start(&mut self) -> Result<(), ComponentError> { - let network_future = self - .network_manager - .take() - .expect("Network manager not found") - .run() - .map_err(|_| ComponentError::InternalComponentError); - pin_mut!(network_future); + async fn start(&mut self) { let mut gateway_futures = FuturesUnordered::new(); + let mut transaction_batch_broadcast_interval = + tokio::time::interval(self.transaction_batch_rate_millis); + transaction_batch_broadcast_interval.set_missed_tick_behavior(Delay); loop { tokio::select! { - result = &mut network_future => { - result?; - panic!("Network stopped unexpectedly"); + _ = &mut self.network_future => { + panic!("MempoolP2pRunner failed - network stopped unexpectedly"); + } + _ = transaction_batch_broadcast_interval.tick() => { + if (self._mempool_p2p_propagator_client.broadcast_queued_transactions().await).is_err() { + warn!("MempoolP2pPropagatorClient denied BroadcastQueuedTransactions request"); + }; } Some(result) = gateway_futures.next() => { match result { Ok(_) => {} Err(gateway_client_error) => { + // TODO(shahak): Analyze the error to see if it's the tx's fault or an + // internal error. Widen GatewayError's variants if necessary. if let GatewayClientError::GatewayError( GatewayError::GatewaySpecError{p2p_message_metadata: Some(p2p_message_metadata), ..} ) = gateway_client_error { + warn!( + "Gateway rejected transaction we received from another peer. Reporting peer." + ); if let Err(e) = self.broadcast_topic_client.report_peer(p2p_message_metadata.clone()).await { warn!("Failed to report peer: {:?}", e); } + } else { + warn!( + "Failed sending transaction to gateway. {:?}", + gateway_client_error + ); } } } @@ -71,9 +96,14 @@ impl ComponentStarter for MempoolP2pRunner { Some((message_result, broadcasted_message_metadata)) = self.broadcasted_topic_server.next() => { match message_result { Ok(message) => { - gateway_futures.push(self.gateway_client.add_tx( - GatewayInput { rpc_tx: message.0, message_metadata: Some(broadcasted_message_metadata.clone()) } - )); + // TODO(alonl): consider calculating the tx_hash and pringing it instead of the entire tx. + info!("Received transaction from network, forwarding to gateway"); + debug!("received transaction: {:?}", message.0); + for rpc_tx in message.0 { + gateway_futures.push(self.gateway_client.add_tx( + GatewayInput { rpc_tx, message_metadata: Some(broadcasted_message_metadata.clone()) } + )); + } } Err(e) => { warn!("Received a faulty transaction from network: {:?}. Attempting to report the sending peer", e); diff --git a/crates/starknet_mempool_p2p/src/runner/test.rs b/crates/starknet_mempool_p2p/src/runner/test.rs index e64f272c327..b8c59bebb01 100644 --- a/crates/starknet_mempool_p2p/src/runner/test.rs +++ b/crates/starknet_mempool_p2p/src/runner/test.rs @@ -1,80 +1,236 @@ use std::sync::Arc; use std::time::Duration; -use async_trait::async_trait; -use futures::channel::mpsc::Sender; +use futures::future::{pending, ready, BoxFuture}; use futures::stream::StreamExt; -use futures::SinkExt; +use futures::{FutureExt, SinkExt}; use papyrus_network::network_manager::test_utils::{ mock_register_broadcast_topic, BroadcastNetworkMock, TestSubscriberChannels, }; -use papyrus_network::network_manager::{BroadcastTopicChannels, NetworkManager}; -use papyrus_network::NetworkConfig; +use papyrus_network::network_manager::{BroadcastTopicChannels, NetworkError}; use papyrus_network_types::network_types::BroadcastedMessageMetadata; -use papyrus_protobuf::mempool::RpcTransactionWrapper; +use papyrus_protobuf::mempool::RpcTransactionBatch; use papyrus_test_utils::{get_rng, GetTestInstance}; use starknet_api::rpc_transaction::RpcTransaction; use starknet_api::transaction::TransactionHash; -use starknet_gateway_types::communication::{GatewayClient, GatewayClientResult}; +use starknet_gateway_types::communication::{GatewayClient, GatewayClientError, MockGatewayClient}; +use starknet_gateway_types::errors::{GatewayError, GatewaySpecError}; use starknet_gateway_types::gateway_types::GatewayInput; +use starknet_mempool_p2p_types::communication::{ + MempoolP2pPropagatorClient, + MockMempoolP2pPropagatorClient, +}; use starknet_sequencer_infra::component_definitions::ComponentStarter; -use tokio::time::sleep; use super::MempoolP2pRunner; -// TODO(eitan): Make it an automock -#[derive(Clone)] -struct MockGatewayClient { - add_tx_sender: Sender, -} - -#[async_trait] -impl GatewayClient for MockGatewayClient { - async fn add_tx(&self, gateway_input: GatewayInput) -> GatewayClientResult { - let _ = self.clone().add_tx_sender.send(gateway_input.rpc_tx).await; - Ok(TransactionHash::default()) - } -} +const MAX_TRANSACTION_BATCH_RATE: Duration = Duration::MAX; -#[tokio::test] -async fn start_component_receive_tx_happy_flow() { +fn setup( + network_future: BoxFuture<'static, Result<(), NetworkError>>, + gateway_client: Arc, + mempool_p2p_propagator_client: Arc, + transaction_batch_rate_millis: Duration, +) -> (MempoolP2pRunner, BroadcastNetworkMock) { let TestSubscriberChannels { mock_network, subscriber_channels } = mock_register_broadcast_topic().expect("Failed to create mock network"); let BroadcastTopicChannels { broadcasted_messages_receiver, broadcast_topic_client } = subscriber_channels; + let mempool_p2p_runner = MempoolP2pRunner::new( + network_future, + broadcasted_messages_receiver, + broadcast_topic_client, + gateway_client, + mempool_p2p_propagator_client, + transaction_batch_rate_millis, + ); + (mempool_p2p_runner, mock_network) +} + +#[test] +#[should_panic] +fn run_panics_when_network_future_returns() { + let network_future = ready(Ok(())).boxed(); + let gateway_client = Arc::new(MockGatewayClient::new()); + let (mut mempool_p2p_runner, _) = setup( + network_future, + gateway_client, + Arc::new(MockMempoolP2pPropagatorClient::new()), + MAX_TRANSACTION_BATCH_RATE, + ); + mempool_p2p_runner.start().now_or_never().unwrap(); +} + +#[test] +#[should_panic] +fn run_panics_when_network_future_returns_error() { + let network_future = + ready(Err(NetworkError::DialError(libp2p::swarm::DialError::Aborted))).boxed(); + let gateway_client = Arc::new(MockGatewayClient::new()); + let (mut mempool_p2p_runner, _) = setup( + network_future, + gateway_client, + Arc::new(MockMempoolP2pPropagatorClient::new()), + MAX_TRANSACTION_BATCH_RATE, + ); + mempool_p2p_runner.start().now_or_never().unwrap(); +} + +#[tokio::test] +async fn incoming_p2p_tx_reaches_gateway_client() { + let network_future = pending().boxed(); + + // Create channels for sending an empty message to indicate that the tx reached the gateway + // client. + let (add_tx_indicator_sender, add_tx_indicator_receiver) = futures::channel::oneshot::channel(); + + let message_metadata = BroadcastedMessageMetadata::get_test_instance(&mut get_rng()); + let expected_rpc_transaction_batch = + RpcTransactionBatch(vec![RpcTransaction::get_test_instance(&mut get_rng())]); + let gateway_input = GatewayInput { + rpc_tx: expected_rpc_transaction_batch.0.first().unwrap().clone(), + message_metadata: Some(message_metadata.clone()), + }; + + let mut mock_gateway_client = MockGatewayClient::new(); + mock_gateway_client.expect_add_tx().with(mockall::predicate::eq(gateway_input)).return_once( + move |_| { + add_tx_indicator_sender.send(()).unwrap(); + Ok(TransactionHash::default()) + }, + ); + let (mut mempool_p2p_runner, mock_network) = setup( + network_future, + Arc::new(mock_gateway_client), + Arc::new(MockMempoolP2pPropagatorClient::new()), + MAX_TRANSACTION_BATCH_RATE, + ); + let BroadcastNetworkMock { broadcasted_messages_sender: mut mock_broadcasted_messages_sender, .. } = mock_network; - // Creating a placeholder network manager with default config for init of a mempool receiver - let placeholder_network_manager = NetworkManager::new(NetworkConfig::default(), None); - let (add_tx_sender, mut add_tx_receiver) = futures::channel::mpsc::channel(1); - let mock_gateway_client = Arc::new(MockGatewayClient { add_tx_sender }); - let mut mempool_p2p_runner = MempoolP2pRunner::new( - Some(placeholder_network_manager), - broadcasted_messages_receiver, - broadcast_topic_client, - mock_gateway_client, - ); + + let res = mock_broadcasted_messages_sender + .send((expected_rpc_transaction_batch.clone(), message_metadata)); + + res.await.expect("Failed to send message"); + + tokio::select! { + // if the runner fails, there was a network issue => panic. + // if the runner returns successfully, we panic because the runner should never terminate. + res = tokio::time::timeout(Duration::from_secs(5), mempool_p2p_runner.start()) => { + res.expect("Test timed out"); + panic!("MempoolP2pRunner terminated"); + }, + // if a message was received on this oneshot channel, the gateway client received the tx and the test succeeded. + res = add_tx_indicator_receiver => {res.unwrap()} + } +} + +// The p2p runner receives a tx from network, and the gateway declines it, triggering report_peer. +#[tokio::test] +async fn incoming_p2p_tx_fails_on_gateway_client() { + let network_future = pending().boxed(); + // Create channels for sending an empty message to indicate that the tx reached the gateway + // client. + let (add_tx_indicator_sender, add_tx_indicator_receiver) = futures::channel::oneshot::channel(); + let message_metadata = BroadcastedMessageMetadata::get_test_instance(&mut get_rng()); - let expected_rpc_transaction = - RpcTransactionWrapper(RpcTransaction::get_test_instance(&mut get_rng())); + let message_metadata_clone = message_metadata.clone(); + let expected_rpc_transaction_batch = + RpcTransactionBatch(vec![RpcTransaction::get_test_instance(&mut get_rng())]); + + let mut mock_gateway_client = MockGatewayClient::new(); + mock_gateway_client.expect_add_tx().return_once(move |_| { + add_tx_indicator_sender.send(()).unwrap(); + Err(GatewayClientError::GatewayError(GatewayError::GatewaySpecError { + source: GatewaySpecError::DuplicateTx, + p2p_message_metadata: Some(message_metadata_clone), + })) + }); + + let (mut mempool_p2p_runner, mock_network) = setup( + network_future, + Arc::new(mock_gateway_client), + Arc::new(MockMempoolP2pPropagatorClient::new()), + MAX_TRANSACTION_BATCH_RATE, + ); + + let BroadcastNetworkMock { + broadcasted_messages_sender: mut mock_broadcasted_messages_sender, + reported_messages_receiver: mut mock_reported_messages_receiver, + .. + } = mock_network; - // Sending the expected transaction to the mempool receiver - let res = - mock_broadcasted_messages_sender.send((expected_rpc_transaction.clone(), message_metadata)); + let res = mock_broadcasted_messages_sender + .send((expected_rpc_transaction_batch.clone(), message_metadata.clone())); res.await.expect("Failed to send message"); + tokio::select! { - _ = mempool_p2p_runner.start() => {panic!("Mempool receiver failed to start");} - actual_rpc_transaction = add_tx_receiver.next() => { - assert_eq!(actual_rpc_transaction, Some(expected_rpc_transaction.0)); - } - _ = sleep(Duration::from_secs(5)) => { - panic!("Test timed out"); + // if the runner fails, there was a network issue => panic. + // if the runner returns successfully, we panic because the runner should never terminate. + res = tokio::time::timeout(Duration::from_secs(5), mempool_p2p_runner.start()) => { + res.expect("Test timed out (MempoolP2pRunner took too long to start)"); + panic!("MempoolP2pRunner terminated"); + }, + // if a message was received on this oneshot channel, the gateway client received the tx. + res = add_tx_indicator_receiver => { + // if unwrap fails, the tx wasn't forwarded to the gateway client. + res.unwrap(); + // After gateway client fails to add the tx, the p2p runner should have reported the peer. + let peer_reported = mock_reported_messages_receiver.next().await.expect("Failed to receive report"); + // TODO(Shahak): add this functionality to network manager test utils + assert_eq!(peer_reported, message_metadata.originator_id.private_get_peer_id()) } } } -// TODO(eitan): Add test for when the gateway client fails to add the transaction + +#[tokio::test] +async fn send_broadcast_queued_transactions_request_after_transaction_batch_rate() { + let transaction_batch_rate_millis = Duration::from_secs(30); + + let network_future = pending().boxed(); + let gateway_client = Arc::new(MockGatewayClient::new()); + + // Create channels for sending an empty message to indicate that the request reached the + // propagator client + let (broadcast_queued_tx_indicator_sender, mut broadcast_queued_tx_indicator_receiver) = + futures::channel::oneshot::channel(); + + let mut mempool_p2p_propagator_client = MockMempoolP2pPropagatorClient::new(); + mempool_p2p_propagator_client.expect_broadcast_queued_transactions().return_once(move || { + broadcast_queued_tx_indicator_sender.send(()).unwrap(); + Ok(()) + }); + + let (mut mempool_p2p_runner, _) = setup( + network_future, + gateway_client, + Arc::new(mempool_p2p_propagator_client), + transaction_batch_rate_millis, + ); + + tokio::time::pause(); + + let handle = tokio::spawn(async move { + mempool_p2p_runner.start().await; + }); + + // The event for which we want to advance the clock is polled by a tokio::select, and not + // directly awaited. + // Because of that, advancing the clock using tokio::time::advance won't actually push the + // time forward (thanks to tokio lazy implementation). This is why we need to await a future + // that will actually advance the clock (the clock is advanced without calling + // tokio::time::advance thanks to the auto-advance feature of tokio::time::pause). + // The auto-advance feature will instantly push the clock to the next awaited future, in this + // case pushing it exactly to when a batch should be closed. + tokio::time::sleep(transaction_batch_rate_millis).await; + + assert!(broadcast_queued_tx_indicator_receiver.try_recv().unwrap().is_some()); + + handle.abort(); +} diff --git a/crates/starknet_mempool_p2p_types/Cargo.toml b/crates/starknet_mempool_p2p_types/Cargo.toml index 352de1ab630..9b9fd810c97 100644 --- a/crates/starknet_mempool_p2p_types/Cargo.toml +++ b/crates/starknet_mempool_p2p_types/Cargo.toml @@ -10,9 +10,17 @@ workspace = true [dependencies] async-trait.workspace = true +mockall = { workspace = true, optional = true } papyrus_network_types.workspace = true papyrus_proc_macros.workspace = true serde = { workspace = true, features = ["derive"] } starknet_api.workspace = true starknet_sequencer_infra.workspace = true +strum_macros.workspace = true thiserror.workspace = true + +[dev-dependencies] +mockall.workspace = true + +[features] +testing = ["mockall"] diff --git a/crates/starknet_mempool_p2p_types/src/communication.rs b/crates/starknet_mempool_p2p_types/src/communication.rs index 09878fe7644..07e35488999 100644 --- a/crates/starknet_mempool_p2p_types/src/communication.rs +++ b/crates/starknet_mempool_p2p_types/src/communication.rs @@ -2,9 +2,9 @@ use std::sync::Arc; use async_trait::async_trait; use papyrus_network_types::network_types::BroadcastedMessageMetadata; -use papyrus_proc_macros::handle_response_variants; +use papyrus_proc_macros::handle_all_response_variants; use serde::{Deserialize, Serialize}; -use starknet_api::rpc_transaction::RpcTransaction; +use starknet_api::rpc_transaction::InternalRpcTransaction; use starknet_sequencer_infra::component_client::{ ClientError, LocalComponentClient, @@ -14,11 +14,14 @@ use starknet_sequencer_infra::component_definitions::{ ComponentClient, ComponentRequestAndResponseSender, }; +use starknet_sequencer_infra::impl_debug_for_infra_requests_and_responses; +use strum_macros::AsRefStr; use thiserror::Error; use crate::errors::MempoolP2pPropagatorError; use crate::mempool_p2p_types::MempoolP2pPropagatorResult; +#[cfg_attr(any(feature = "testing", test), mockall::automock)] #[async_trait] pub trait MempoolP2pPropagatorClient: Send + Sync { /// Adds a transaction to be propagated to other peers. This should only be called on a new @@ -26,7 +29,7 @@ pub trait MempoolP2pPropagatorClient: Send + Sync { /// from other peers, use `continue_propagation`. async fn add_transaction( &self, - transaction: RpcTransaction, + transaction: InternalRpcTransaction, ) -> MempoolP2pPropagatorClientResult<()>; /// Continues the propagation of a transaction we've received from another peer. @@ -34,6 +37,9 @@ pub trait MempoolP2pPropagatorClient: Send + Sync { &self, propagation_metadata: BroadcastedMessageMetadata, ) -> MempoolP2pPropagatorClientResult<()>; + + /// Broadcast the queued transactions as a new transaction batch. + async fn broadcast_queued_transactions(&self) -> MempoolP2pPropagatorClientResult<()>; } pub type LocalMempoolP2pPropagatorClient = @@ -45,17 +51,21 @@ pub type MempoolP2pPropagatorClientResult = Result; -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Serialize, Deserialize, AsRefStr)] pub enum MempoolP2pPropagatorRequest { - AddTransaction(RpcTransaction), + AddTransaction(InternalRpcTransaction), ContinuePropagation(BroadcastedMessageMetadata), + BroadcastQueuedTransactions(), } +impl_debug_for_infra_requests_and_responses!(MempoolP2pPropagatorRequest); -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Serialize, Deserialize, AsRefStr)] pub enum MempoolP2pPropagatorResponse { AddTransaction(MempoolP2pPropagatorResult<()>), ContinuePropagation(MempoolP2pPropagatorResult<()>), + BroadcastQueuedTransactions(MempoolP2pPropagatorResult<()>), } +impl_debug_for_infra_requests_and_responses!(MempoolP2pPropagatorResponse); #[derive(Clone, Debug, Error)] pub enum MempoolP2pPropagatorClientError { @@ -73,15 +83,15 @@ where { async fn add_transaction( &self, - transaction: RpcTransaction, + transaction: InternalRpcTransaction, ) -> MempoolP2pPropagatorClientResult<()> { let request = MempoolP2pPropagatorRequest::AddTransaction(transaction); - let response = self.send(request).await; - handle_response_variants!( + handle_all_response_variants!( MempoolP2pPropagatorResponse, AddTransaction, MempoolP2pPropagatorClientError, - MempoolP2pPropagatorError + MempoolP2pPropagatorError, + Direct ) } @@ -90,12 +100,23 @@ where propagation_metadata: BroadcastedMessageMetadata, ) -> MempoolP2pPropagatorClientResult<()> { let request = MempoolP2pPropagatorRequest::ContinuePropagation(propagation_metadata); - let response = self.send(request).await; - handle_response_variants!( + handle_all_response_variants!( MempoolP2pPropagatorResponse, ContinuePropagation, MempoolP2pPropagatorClientError, - MempoolP2pPropagatorError + MempoolP2pPropagatorError, + Direct + ) + } + + async fn broadcast_queued_transactions(&self) -> MempoolP2pPropagatorClientResult<()> { + let request = MempoolP2pPropagatorRequest::BroadcastQueuedTransactions(); + handle_all_response_variants!( + MempoolP2pPropagatorResponse, + BroadcastQueuedTransactions, + MempoolP2pPropagatorClientError, + MempoolP2pPropagatorError, + Direct ) } } diff --git a/crates/starknet_mempool_p2p_types/src/errors.rs b/crates/starknet_mempool_p2p_types/src/errors.rs index 3037dd1ced2..6204f6beb7c 100644 --- a/crates/starknet_mempool_p2p_types/src/errors.rs +++ b/crates/starknet_mempool_p2p_types/src/errors.rs @@ -5,4 +5,6 @@ use thiserror::Error; pub enum MempoolP2pPropagatorError { #[error("Sender request error")] NetworkSendError, + #[error("Transaction conversion error: {0}")] + TransactionConversionError(String), } diff --git a/crates/starknet_mempool_types/Cargo.toml b/crates/starknet_mempool_types/Cargo.toml index 93b3083c2fe..5be17accd31 100644 --- a/crates/starknet_mempool_types/Cargo.toml +++ b/crates/starknet_mempool_types/Cargo.toml @@ -19,8 +19,8 @@ papyrus_proc_macros.workspace = true serde = { workspace = true, features = ["derive"] } starknet_api.workspace = true starknet_sequencer_infra.workspace = true +strum_macros.workspace = true thiserror.workspace = true [dev-dependencies] -# Enable self with "testing" feature in tests. -starknet_mempool_types = { workspace = true, features = ["testing"] } +mockall.workspace = true diff --git a/crates/starknet_mempool_types/src/communication.rs b/crates/starknet_mempool_types/src/communication.rs index bf6b83df784..caabc09a9f9 100644 --- a/crates/starknet_mempool_types/src/communication.rs +++ b/crates/starknet_mempool_types/src/communication.rs @@ -4,9 +4,11 @@ use async_trait::async_trait; #[cfg(any(feature = "testing", test))] use mockall::automock; use papyrus_network_types::network_types::BroadcastedMessageMetadata; -use papyrus_proc_macros::handle_response_variants; +use papyrus_proc_macros::handle_all_response_variants; use serde::{Deserialize, Serialize}; -use starknet_api::executable_transaction::AccountTransaction; +use starknet_api::block::NonzeroGasPrice; +use starknet_api::core::ContractAddress; +use starknet_api::rpc_transaction::InternalRpcTransaction; use starknet_sequencer_infra::component_client::{ ClientError, LocalComponentClient, @@ -16,10 +18,12 @@ use starknet_sequencer_infra::component_definitions::{ ComponentClient, ComponentRequestAndResponseSender, }; +use starknet_sequencer_infra::impl_debug_for_infra_requests_and_responses; +use strum_macros::AsRefStr; use thiserror::Error; use crate::errors::MempoolError; -use crate::mempool_types::{AddTransactionArgs, CommitBlockArgs}; +use crate::mempool_types::{AddTransactionArgs, CommitBlockArgs, MempoolSnapshot}; pub type LocalMempoolClient = LocalComponentClient; pub type RemoteMempoolClient = RemoteComponentClient; @@ -40,26 +44,41 @@ pub struct AddTransactionArgsWrapper { #[cfg_attr(any(feature = "testing", test), automock)] #[async_trait] pub trait MempoolClient: Send + Sync { - // TODO: Add Option as an argument for add_transaction - // TODO: Rename tx to transaction + // TODO(AlonH): Add Option as an argument for add_transaction + // TODO(AlonH): Rename tx to transaction async fn add_tx(&self, args: AddTransactionArgsWrapper) -> MempoolClientResult<()>; async fn commit_block(&self, args: CommitBlockArgs) -> MempoolClientResult<()>; - async fn get_txs(&self, n_txs: usize) -> MempoolClientResult>; + async fn get_txs(&self, n_txs: usize) -> MempoolClientResult>; + async fn account_tx_in_pool_or_recent_block( + &self, + contract_address: ContractAddress, + ) -> MempoolClientResult; + async fn update_gas_price(&self, gas_price: NonzeroGasPrice) -> MempoolClientResult<()>; + async fn get_mempool_snapshot(&self) -> MempoolClientResult; } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Serialize, Deserialize, AsRefStr)] pub enum MempoolRequest { AddTransaction(AddTransactionArgsWrapper), CommitBlock(CommitBlockArgs), GetTransactions(usize), + AccountTxInPoolOrRecentBlock(ContractAddress), + // TODO(yair): Rename to `StartBlock` and add cleanup of staged txs. + UpdateGasPrice(NonzeroGasPrice), + GetMempoolSnapshot(), } +impl_debug_for_infra_requests_and_responses!(MempoolRequest); -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Serialize, Deserialize, AsRefStr)] pub enum MempoolResponse { AddTransaction(MempoolResult<()>), CommitBlock(MempoolResult<()>), - GetTransactions(MempoolResult>), + GetTransactions(MempoolResult>), + AccountTxInPoolOrRecentBlock(MempoolResult), + UpdateGasPrice(MempoolResult<()>), + GetMempoolSnapshot(MempoolResult), } +impl_debug_for_infra_requests_and_responses!(MempoolResponse); #[derive(Clone, Debug, Error)] pub enum MempoolClientError { @@ -76,24 +95,70 @@ where { async fn add_tx(&self, args: AddTransactionArgsWrapper) -> MempoolClientResult<()> { let request = MempoolRequest::AddTransaction(args); - let response = self.send(request).await; - handle_response_variants!(MempoolResponse, AddTransaction, MempoolClientError, MempoolError) + handle_all_response_variants!( + MempoolResponse, + AddTransaction, + MempoolClientError, + MempoolError, + Direct + ) } async fn commit_block(&self, args: CommitBlockArgs) -> MempoolClientResult<()> { let request = MempoolRequest::CommitBlock(args); - let response = self.send(request).await; - handle_response_variants!(MempoolResponse, CommitBlock, MempoolClientError, MempoolError) + handle_all_response_variants!( + MempoolResponse, + CommitBlock, + MempoolClientError, + MempoolError, + Direct + ) } - async fn get_txs(&self, n_txs: usize) -> MempoolClientResult> { + async fn get_txs(&self, n_txs: usize) -> MempoolClientResult> { let request = MempoolRequest::GetTransactions(n_txs); - let response = self.send(request).await; - handle_response_variants!( + handle_all_response_variants!( MempoolResponse, GetTransactions, MempoolClientError, - MempoolError + MempoolError, + Direct + ) + } + + async fn account_tx_in_pool_or_recent_block( + &self, + account_address: ContractAddress, + ) -> MempoolClientResult { + let request = MempoolRequest::AccountTxInPoolOrRecentBlock(account_address); + handle_all_response_variants!( + MempoolResponse, + AccountTxInPoolOrRecentBlock, + MempoolClientError, + MempoolError, + Direct + ) + } + + async fn update_gas_price(&self, gas_price: NonzeroGasPrice) -> MempoolClientResult<()> { + let request = MempoolRequest::UpdateGasPrice(gas_price); + handle_all_response_variants!( + MempoolResponse, + UpdateGasPrice, + MempoolClientError, + MempoolError, + Direct + ) + } + + async fn get_mempool_snapshot(&self) -> MempoolClientResult { + let request = MempoolRequest::GetMempoolSnapshot(); + handle_all_response_variants!( + MempoolResponse, + GetMempoolSnapshot, + MempoolClientError, + MempoolError, + Direct ) } } diff --git a/crates/starknet_mempool_types/src/mempool_types.rs b/crates/starknet_mempool_types/src/mempool_types.rs index 65199db6d6b..56a9cc3283c 100644 --- a/crates/starknet_mempool_types/src/mempool_types.rs +++ b/crates/starknet_mempool_types/src/mempool_types.rs @@ -2,7 +2,7 @@ use std::collections::{HashMap, HashSet}; use serde::{Deserialize, Serialize}; use starknet_api::core::{ContractAddress, Nonce}; -use starknet_api::executable_transaction::AccountTransaction; +use starknet_api::rpc_transaction::InternalRpcTransaction; use starknet_api::transaction::TransactionHash; use crate::errors::MempoolError; @@ -23,14 +23,19 @@ impl std::fmt::Display for AccountState { #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct AddTransactionArgs { - pub tx: AccountTransaction, + pub tx: InternalRpcTransaction, pub account_state: AccountState, } -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] pub struct CommitBlockArgs { pub address_to_nonce: HashMap, - pub tx_hashes: HashSet, + pub rejected_tx_hashes: HashSet, } pub type MempoolResult = Result; + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct MempoolSnapshot { + pub transactions: Vec, +} diff --git a/crates/starknet_monitoring_endpoint/Cargo.toml b/crates/starknet_monitoring_endpoint/Cargo.toml index 657132f74c5..794fc06ba8b 100644 --- a/crates/starknet_monitoring_endpoint/Cargo.toml +++ b/crates/starknet_monitoring_endpoint/Cargo.toml @@ -5,11 +5,8 @@ edition.workspace = true repository.workspace = true license-file.workspace = true -[package.metadata.cargo-udeps.ignore] -normal = ["tokio"] - [features] -testing = ["tokio", "tower"] +testing = ["num-traits", "thiserror", "tokio", "tower"] [lints] workspace = true @@ -17,15 +14,23 @@ workspace = true [dependencies] axum.workspace = true hyper = { workspace = true } +metrics-exporter-prometheus.workspace = true +num-traits = { workspace = true, optional = true } papyrus_config.workspace = true serde.workspace = true +starknet_infra_utils.workspace = true starknet_sequencer_infra.workspace = true +starknet_sequencer_metrics.workspace = true +thiserror = { workspace = true, optional = true } tokio = { workspace = true, optional = true } tower = { workspace = true, optional = true } tracing.workspace = true validator.workspace = true [dev-dependencies] +metrics.workspace = true +num-traits.workspace = true pretty_assertions.workspace = true +thiserror.workspace = true tokio.workspace = true tower.workspace = true diff --git a/crates/starknet_monitoring_endpoint/src/config.rs b/crates/starknet_monitoring_endpoint/src/config.rs index 82384cf7da4..da88458ff58 100644 --- a/crates/starknet_monitoring_endpoint/src/config.rs +++ b/crates/starknet_monitoring_endpoint/src/config.rs @@ -1,21 +1,31 @@ use std::collections::BTreeMap; use std::fmt::{Display, Formatter, Result}; -use std::net::IpAddr; +use std::net::{IpAddr, Ipv4Addr}; use papyrus_config::dumping::{ser_param, SerializeConfig}; use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; use serde::{Deserialize, Serialize}; use validator::Validate; +pub(crate) const DEFAULT_IP: IpAddr = IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)); +pub(crate) const DEFAULT_PORT: u16 = 8082; + #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Validate)] pub struct MonitoringEndpointConfig { pub ip: IpAddr, pub port: u16, + pub collect_metrics: bool, + pub collect_profiling_metrics: bool, } impl Default for MonitoringEndpointConfig { fn default() -> Self { - Self { ip: "0.0.0.0".parse().unwrap(), port: 8082 } + Self { + ip: DEFAULT_IP, + port: DEFAULT_PORT, + collect_metrics: true, + collect_profiling_metrics: true, + } } } @@ -34,6 +44,18 @@ impl SerializeConfig for MonitoringEndpointConfig { "The monitoring endpoint port.", ParamPrivacyInput::Public, ), + ser_param( + "collect_metrics", + &self.collect_metrics, + "If true, collect and return metrics in the monitoring endpoint.", + ParamPrivacyInput::Public, + ), + ser_param( + "collect_profiling_metrics", + &self.collect_profiling_metrics, + "If true, collect and return profiling metrics in the monitoring endpoint.", + ParamPrivacyInput::Public, + ), ]) } } diff --git a/crates/starknet_monitoring_endpoint/src/monitoring_endpoint.rs b/crates/starknet_monitoring_endpoint/src/monitoring_endpoint.rs index c14153ec02a..9ba051ef161 100644 --- a/crates/starknet_monitoring_endpoint/src/monitoring_endpoint.rs +++ b/crates/starknet_monitoring_endpoint/src/monitoring_endpoint.rs @@ -1,12 +1,14 @@ -use std::any::type_name; use std::net::SocketAddr; use axum::http::StatusCode; +use axum::response::{IntoResponse, Response}; use axum::routing::get; use axum::{async_trait, Router, Server}; use hyper::Error; +use metrics_exporter_prometheus::{PrometheusBuilder, PrometheusHandle}; +use starknet_infra_utils::type_name::short_type_name; use starknet_sequencer_infra::component_definitions::ComponentStarter; -use starknet_sequencer_infra::errors::ComponentError; +use starknet_sequencer_metrics::metrics::COLLECT_SEQUENCER_PROFILING_METRICS; use tracing::{info, instrument}; use crate::config::MonitoringEndpointConfig; @@ -19,15 +21,33 @@ pub(crate) const MONITORING_PREFIX: &str = "monitoring"; pub(crate) const ALIVE: &str = "alive"; pub(crate) const READY: &str = "ready"; pub(crate) const VERSION: &str = "nodeVersion"; +pub(crate) const METRICS: &str = "metrics"; pub struct MonitoringEndpoint { config: MonitoringEndpointConfig, version: &'static str, + prometheus_handle: Option, } impl MonitoringEndpoint { pub fn new(config: MonitoringEndpointConfig, version: &'static str) -> Self { - MonitoringEndpoint { config, version } + // TODO(Tsabary): consider error handling + let prometheus_handle = if config.collect_metrics { + // TODO(Lev): add tests that show the metrics are collected / not collected based on the + // config value. + COLLECT_SEQUENCER_PROFILING_METRICS + .set(config.collect_profiling_metrics) + .expect("Should be able to set profiling metrics collection."); + + Some( + PrometheusBuilder::new() + .install_recorder() + .expect("should be able to build the recorder and install it globally"), + ) + } else { + None + }; + MonitoringEndpoint { config, version, prometheus_handle } } #[instrument( @@ -38,7 +58,7 @@ impl MonitoringEndpoint { ), level = "debug")] pub async fn run(&self) -> Result<(), Error> { - let MonitoringEndpointConfig { ip, port } = self.config; + let MonitoringEndpointConfig { ip, port, .. } = self.config; let endpoint_addr = SocketAddr::new(ip, port); let app = self.app(); @@ -49,6 +69,7 @@ impl MonitoringEndpoint { fn app(&self) -> Router { let version = self.version.to_string(); + let prometheus_handle = self.prometheus_handle.clone(); Router::new() .route( @@ -63,6 +84,10 @@ impl MonitoringEndpoint { format!("/{MONITORING_PREFIX}/{VERSION}").as_str(), get(move || async { version }), ) + .route( + format!("/{MONITORING_PREFIX}/{METRICS}").as_str(), + get(move || metrics(prometheus_handle)), + ) } } @@ -75,8 +100,20 @@ pub fn create_monitoring_endpoint( #[async_trait] impl ComponentStarter for MonitoringEndpoint { - async fn start(&mut self) -> Result<(), ComponentError> { - info!("Starting component {}.", type_name::()); - self.run().await.map_err(|_| ComponentError::InternalComponentError) + async fn start(&mut self) { + info!("Starting component {}.", short_type_name::()); + self.run().await.unwrap_or_else(|e| panic!("Failed to start MointoringEndpoint: {:?}", e)); + } +} + +/// Returns prometheus metrics. +/// In case the node doesn’t collect metrics returns an empty response with status code 405: method +/// not allowed. +#[instrument(level = "debug", ret, skip(prometheus_handle))] +// TODO(tsabary): handle the Option setup. +async fn metrics(prometheus_handle: Option) -> Response { + match prometheus_handle { + Some(handle) => handle.render().into_response(), + None => StatusCode::METHOD_NOT_ALLOWED.into_response(), } } diff --git a/crates/starknet_monitoring_endpoint/src/monitoring_endpoint_test.rs b/crates/starknet_monitoring_endpoint/src/monitoring_endpoint_test.rs index 76c521cfc5a..47fad861fcc 100644 --- a/crates/starknet_monitoring_endpoint/src/monitoring_endpoint_test.rs +++ b/crates/starknet_monitoring_endpoint/src/monitoring_endpoint_test.rs @@ -5,16 +5,19 @@ use axum::response::Response; use axum::Router; use hyper::body::to_bytes; use hyper::Client; +use metrics::{counter, describe_counter}; use pretty_assertions::assert_eq; use tokio::spawn; use tokio::task::yield_now; use tower::ServiceExt; use super::MonitoringEndpointConfig; +use crate::config::{DEFAULT_IP, DEFAULT_PORT}; use crate::monitoring_endpoint::{ create_monitoring_endpoint, MonitoringEndpoint, ALIVE, + METRICS, READY, VERSION, }; @@ -22,8 +25,18 @@ use crate::test_utils::build_request; const TEST_VERSION: &str = "1.2.3-dev"; -fn setup_monitoring_endpoint() -> MonitoringEndpoint { - create_monitoring_endpoint(MonitoringEndpointConfig::default(), TEST_VERSION) +// Note: the metrics recorder is installed globally, causing tests to conflict when run in parallel. +// Most tests do not require it, and as such, use the following disabling config. +const CONFIG_WITHOUT_METRICS: MonitoringEndpointConfig = MonitoringEndpointConfig { + ip: DEFAULT_IP, + port: DEFAULT_PORT, + collect_metrics: false, + collect_profiling_metrics: false, +}; + +fn setup_monitoring_endpoint(config: Option) -> MonitoringEndpoint { + let config = config.unwrap_or(CONFIG_WITHOUT_METRICS); + create_monitoring_endpoint(config, TEST_VERSION) } async fn request_app(app: Router, method: &str) -> Response { @@ -31,8 +44,8 @@ async fn request_app(app: Router, method: &str) -> Response { } #[tokio::test] -async fn test_node_version() { - let response = request_app(setup_monitoring_endpoint().app(), VERSION).await; +async fn node_version() { + let response = request_app(setup_monitoring_endpoint(None).app(), VERSION).await; assert_eq!(response.status(), StatusCode::OK); let body = to_bytes(response.into_body()).await.unwrap(); @@ -40,23 +53,52 @@ async fn test_node_version() { } #[tokio::test] -async fn test_alive() { - let response = request_app(setup_monitoring_endpoint().app(), ALIVE).await; +async fn alive_endpoint() { + let response = request_app(setup_monitoring_endpoint(None).app(), ALIVE).await; + assert_eq!(response.status(), StatusCode::OK); +} + +#[tokio::test] +async fn ready_endpoint() { + let response = request_app(setup_monitoring_endpoint(None).app(), READY).await; assert_eq!(response.status(), StatusCode::OK); } #[tokio::test] -async fn test_ready() { - let response = request_app(setup_monitoring_endpoint().app(), READY).await; +async fn with_metrics() { + let config = MonitoringEndpointConfig { collect_metrics: true, ..Default::default() }; + let app = setup_monitoring_endpoint(Some(config)).app(); + + // Register a metric. + let metric_name = "metric_name"; + let metric_help = "metric_help"; + let metric_value = 8224; + counter!(metric_name).absolute(metric_value); + describe_counter!(metric_name, metric_help); + let response = request_app(app, METRICS).await; assert_eq!(response.status(), StatusCode::OK); + let body_bytes = hyper::body::to_bytes(response.into_body()).await.unwrap(); + let body_string = String::from_utf8(body_bytes.to_vec()).unwrap(); + let expected_prefix = format!( + "# HELP {metric_name} {metric_help}\n# TYPE {metric_name} counter\n{metric_name} \ + {metric_value}\n\n" + ); + assert!(body_string.starts_with(&expected_prefix)); +} + +#[tokio::test] +async fn without_metrics() { + let app = setup_monitoring_endpoint(None).app(); + let response = request_app(app, METRICS).await; + assert_eq!(response.status(), StatusCode::METHOD_NOT_ALLOWED); } #[tokio::test] -async fn test_endpoint_as_server() { - spawn(async move { setup_monitoring_endpoint().run().await }); +async fn endpoint_as_server() { + spawn(async move { setup_monitoring_endpoint(None).run().await }); yield_now().await; - let MonitoringEndpointConfig { ip, port } = MonitoringEndpointConfig::default(); + let MonitoringEndpointConfig { ip, port, .. } = MonitoringEndpointConfig::default(); let client = Client::new(); diff --git a/crates/starknet_monitoring_endpoint/src/test_utils.rs b/crates/starknet_monitoring_endpoint/src/test_utils.rs index 595a537be04..ce993cf0a43 100644 --- a/crates/starknet_monitoring_endpoint/src/test_utils.rs +++ b/crates/starknet_monitoring_endpoint/src/test_utils.rs @@ -1,21 +1,37 @@ use std::net::{IpAddr, SocketAddr}; -use std::time::Duration; +use std::str::FromStr; use axum::body::Body; use axum::http::Request; +use hyper::body::to_bytes; use hyper::client::HttpConnector; use hyper::Client; +use num_traits::Num; +use starknet_infra_utils::run_until::run_until; +use starknet_infra_utils::tracing::{CustomLogger, TraceLevel}; +use starknet_sequencer_metrics::metrics::parse_numeric_metric; +use thiserror::Error; use tracing::info; -use crate::monitoring_endpoint::{ALIVE, MONITORING_PREFIX}; +use crate::monitoring_endpoint::{ALIVE, METRICS, MONITORING_PREFIX}; + +#[derive(Clone, Debug, Error, PartialEq, Eq)] +pub enum MonitoringClientError { + #[error("Failed to connect, error details: {}", connection_error)] + ConnectionError { connection_error: String }, + #[error("Erroneous status: {}", status)] + ResponseStatusError { status: String }, + #[error("Missing metric name: {}", metric_name)] + MetricNotFound { metric_name: String }, +} /// Client for querying 'alive' status of an http server. -pub struct IsAliveClient { +pub struct MonitoringClient { socket: SocketAddr, client: Client, } -impl IsAliveClient { +impl MonitoringClient { pub fn new(socket: SocketAddr) -> Self { let client = Client::new(); Self { socket, client } @@ -28,36 +44,61 @@ impl IsAliveClient { self.client .request(build_request(&self.socket.ip(), self.socket.port(), ALIVE)) .await - .map_or(false, |response| response.status().is_success()) + .is_ok_and(|response| response.status().is_success()) } - // TODO(Tsabary/Lev): add sleep time as a parameter, and max retries. Consider using - // 'starknet_client::RetryConfig'. /// Blocks until 'alive', up to a maximum number of query attempts. Returns 'Ok(())' if the /// target is alive, otherwise 'Err(())'. - pub async fn await_alive( - &self, - retry_interval: Duration, - max_attempts: usize, - ) -> Result<(), ()> { - let mut counter = 0; - while counter < max_attempts { - match self.query_alive().await { - true => { - info!("Node is alive."); - return Ok(()); - } - false => { - info!("Waiting for node to be alive: {}.", counter); - tokio::time::sleep(retry_interval).await; - counter += 1; - } - } + pub async fn await_alive(&self, interval: u64, max_attempts: usize) -> Result<(), ()> { + let condition = |node_is_alive: &bool| *node_is_alive; + let query_alive_closure = || async move { self.query_alive().await }; + + let logger = + CustomLogger::new(TraceLevel::Info, Some("Waiting for node to be alive".to_string())); + + run_until(interval, max_attempts, query_alive_closure, condition, Some(logger)) + .await + .ok_or(()) + .map(|_| ()) + } + + pub async fn get_metrics(&self) -> Result { + // Query the server for metrics. + let response = self + .client + .request(build_request(&self.socket.ip(), self.socket.port(), METRICS)) + .await + .map_err(|err| MonitoringClientError::ConnectionError { + connection_error: err.to_string(), + })?; + + // Check response status. + if !response.status().is_success() { + return Err(MonitoringClientError::ResponseStatusError { + status: format!("{:?}", response.status()), + }); } - Err(()) + + // Parse the response body. + let body_bytes = to_bytes(response.into_body()).await.unwrap(); + Ok(String::from_utf8(body_bytes.to_vec()).unwrap()) + } + + // TODO(Yael/Itay): add labels support + // TODO(Itay): Consider making this private + pub async fn get_metric( + &self, + metric_name: &str, + ) -> Result { + let body_string = self.get_metrics().await?; + + // Extract and return the metric value, or a suitable error. + parse_numeric_metric::(&body_string, metric_name, None) + .ok_or(MonitoringClientError::MetricNotFound { metric_name: metric_name.to_string() }) } } +// TODO(Tsabary): use socket instead of ip and port. pub(crate) fn build_request(ip: &IpAddr, port: u16, method: &str) -> Request { Request::builder() .uri(format!("http://{ip}:{port}/{MONITORING_PREFIX}/{method}").as_str()) diff --git a/crates/starknet_os/Cargo.toml b/crates/starknet_os/Cargo.toml new file mode 100644 index 00000000000..7f444e0c946 --- /dev/null +++ b/crates/starknet_os/Cargo.toml @@ -0,0 +1,52 @@ +[package] +name = "starknet_os" +version.workspace = true +edition.workspace = true +repository.workspace = true +license-file.workspace = true +description = "The Starknet OS." + +[features] +deserialize = [ + "blockifier/transaction_serde", + "shared_execution_objects/deserialize", + "starknet-types-core/serde", + "starknet_patricia/deserialize", +] +testing = ["blockifier/testing"] + +[dependencies] +ark-bls12-381.workspace = true +ark-ff.workspace = true +ark-poly.workspace = true +blockifier.workspace = true +c-kzg.workspace = true +cairo-lang-starknet-classes.workspace = true +cairo-vm = { workspace = true, features = ["extensive_hints"] } +indexmap.workspace = true +indoc.workspace = true +log.workspace = true +num-bigint.workspace = true +num-traits.workspace = true +papyrus_common.workspace = true +serde = { workspace = true, features = ["derive"] } +serde_json = { workspace = true, features = ["raw_value"] } +sha3.workspace = true +shared_execution_objects.workspace = true +starknet-types-core = { workspace = true, features = ["hash"] } +starknet_api.workspace = true +starknet_infra_utils.workspace = true +starknet_patricia.workspace = true +strum.workspace = true +strum_macros.workspace = true +thiserror.workspace = true + +[dev-dependencies] +assert_matches.workspace = true +blockifier = { workspace = true, features = ["testing"] } +num-integer.workspace = true +rand.workspace = true +rstest.workspace = true + +[lints] +workspace = true diff --git a/crates/starknet_os/resources/legacy_contract.json b/crates/starknet_os/resources/legacy_contract.json new file mode 100644 index 00000000000..2cff1f585ea --- /dev/null +++ b/crates/starknet_os/resources/legacy_contract.json @@ -0,0 +1,491 @@ +{ + "program": { + "prime": "0x800000000000011000000000000000000000000000000000000000000000001", + "data": [], + "hints": {}, + "builtins": [], + "main_scope": "__main__", + "identifiers": { + "starkware.cairo.common.ec_point.EcPoint": { + "full_name": "starkware.cairo.common.ec_point.EcPoint", + "members": { + "x": { + "offset": 0, + "cairo_type": "felt" + }, + "y": { + "offset": 1, + "cairo_type": "felt" + } + }, + "size": 2, + "type": "struct" + }, + "starkware.cairo.common.cairo_builtins.EcPoint": { + "destination": "starkware.cairo.common.ec_point.EcPoint", + "type": "alias" + }, + "starkware.cairo.common.cairo_builtins.HashBuiltin": { + "full_name": "starkware.cairo.common.cairo_builtins.HashBuiltin", + "members": { + "x": { + "offset": 0, + "cairo_type": "felt" + }, + "y": { + "offset": 1, + "cairo_type": "felt" + }, + "result": { + "offset": 2, + "cairo_type": "felt" + } + }, + "size": 3, + "type": "struct" + }, + "starkware.cairo.common.cairo_builtins.SignatureBuiltin": { + "full_name": "starkware.cairo.common.cairo_builtins.SignatureBuiltin", + "members": { + "pub_key": { + "offset": 0, + "cairo_type": "felt" + }, + "message": { + "offset": 1, + "cairo_type": "felt" + } + }, + "size": 2, + "type": "struct" + }, + "starkware.cairo.common.cairo_builtins.BitwiseBuiltin": { + "full_name": "starkware.cairo.common.cairo_builtins.BitwiseBuiltin", + "members": { + "x": { + "offset": 0, + "cairo_type": "felt" + }, + "y": { + "offset": 1, + "cairo_type": "felt" + }, + "x_and_y": { + "offset": 2, + "cairo_type": "felt" + }, + "x_xor_y": { + "offset": 3, + "cairo_type": "felt" + }, + "x_or_y": { + "offset": 4, + "cairo_type": "felt" + } + }, + "size": 5, + "type": "struct" + }, + "starkware.cairo.common.cairo_builtins.EcOpBuiltin": { + "full_name": "starkware.cairo.common.cairo_builtins.EcOpBuiltin", + "members": { + "p": { + "offset": 0, + "cairo_type": "starkware.cairo.common.ec_point.EcPoint" + }, + "q": { + "offset": 2, + "cairo_type": "starkware.cairo.common.ec_point.EcPoint" + }, + "m": { + "offset": 4, + "cairo_type": "felt" + }, + "r": { + "offset": 5, + "cairo_type": "starkware.cairo.common.ec_point.EcPoint" + } + }, + "size": 7, + "type": "struct" + }, + "starkware.cairo.common.hash.HashBuiltin": { + "destination": "starkware.cairo.common.cairo_builtins.HashBuiltin", + "type": "alias" + }, + "starkware.starknet.common.storage.assert_250_bit": { + "destination": "starkware.cairo.common.math.assert_250_bit", + "type": "alias" + }, + "starkware.starknet.common.storage.MAX_STORAGE_ITEM_SIZE": { + "value": 256, + "type": "const" + }, + "starkware.starknet.common.storage.ADDR_BOUND": { + "value": -106710729501573572985208420194530329073740042555888586719489, + "type": "const" + }, + "starkware.cairo.common.dict_access.DictAccess": { + "full_name": "starkware.cairo.common.dict_access.DictAccess", + "members": { + "key": { + "offset": 0, + "cairo_type": "felt" + }, + "prev_value": { + "offset": 1, + "cairo_type": "felt" + }, + "new_value": { + "offset": 2, + "cairo_type": "felt" + } + }, + "size": 3, + "type": "struct" + }, + "starkware.starknet.common.syscalls.DictAccess": { + "destination": "starkware.cairo.common.dict_access.DictAccess", + "type": "alias" + }, + "starkware.starknet.common.syscalls.SEND_MESSAGE_TO_L1_SELECTOR": { + "value": 433017908768303439907196859243777073, + "type": "const" + }, + "starkware.starknet.common.syscalls.SendMessageToL1SysCall": { + "full_name": "starkware.starknet.common.syscalls.SendMessageToL1SysCall", + "members": { + "selector": { + "offset": 0, + "cairo_type": "felt" + }, + "to_address": { + "offset": 1, + "cairo_type": "felt" + }, + "payload_size": { + "offset": 2, + "cairo_type": "felt" + }, + "payload_ptr": { + "offset": 3, + "cairo_type": "felt*" + } + }, + "size": 4, + "type": "struct" + }, + "starkware.starknet.common.syscalls.CALL_CONTRACT_SELECTOR": { + "value": 20853273475220472486191784820, + "type": "const" + }, + "starkware.starknet.common.syscalls.DELEGATE_CALL_SELECTOR": { + "value": 21167594061783206823196716140, + "type": "const" + }, + "starkware.starknet.common.syscalls.CallContractRequest": { + "full_name": "starkware.starknet.common.syscalls.CallContractRequest", + "members": { + "selector": { + "offset": 0, + "cairo_type": "felt" + }, + "contract_address": { + "offset": 1, + "cairo_type": "felt" + }, + "function_selector": { + "offset": 2, + "cairo_type": "felt" + }, + "calldata_size": { + "offset": 3, + "cairo_type": "felt" + }, + "calldata": { + "offset": 4, + "cairo_type": "felt*" + } + }, + "size": 5, + "type": "struct" + }, + "starkware.starknet.common.syscalls.CallContractResponse": { + "full_name": "starkware.starknet.common.syscalls.CallContractResponse", + "members": { + "retdata_size": { + "offset": 0, + "cairo_type": "felt" + }, + "retdata": { + "offset": 1, + "cairo_type": "felt*" + } + }, + "size": 2, + "type": "struct" + }, + "starkware.starknet.common.syscalls.CallContract": { + "full_name": "starkware.starknet.common.syscalls.CallContract", + "members": { + "request": { + "offset": 0, + "cairo_type": "starkware.starknet.common.syscalls.CallContractRequest" + }, + "response": { + "offset": 5, + "cairo_type": "starkware.starknet.common.syscalls.CallContractResponse" + } + }, + "size": 7, + "type": "struct" + }, + "starkware.starknet.common.syscalls.GET_CALLER_ADDRESS_SELECTOR": { + "value": 94901967781393078444254803017658102643, + "type": "const" + }, + "starkware.starknet.common.syscalls.GetCallerAddressRequest": { + "full_name": "starkware.starknet.common.syscalls.GetCallerAddressRequest", + "members": { + "selector": { + "offset": 0, + "cairo_type": "felt" + } + }, + "size": 1, + "type": "struct" + }, + "starkware.starknet.common.syscalls.GetCallerAddressResponse": { + "full_name": "starkware.starknet.common.syscalls.GetCallerAddressResponse", + "members": { + "caller_address": { + "offset": 0, + "cairo_type": "felt" + } + }, + "size": 1, + "type": "struct" + }, + "starkware.starknet.common.syscalls.GetCallerAddress": { + "full_name": "starkware.starknet.common.syscalls.GetCallerAddress", + "members": { + "request": { + "offset": 0, + "cairo_type": "starkware.starknet.common.syscalls.GetCallerAddressRequest" + }, + "response": { + "offset": 1, + "cairo_type": "starkware.starknet.common.syscalls.GetCallerAddressResponse" + } + }, + "size": 2, + "type": "struct" + }, + "starkware.starknet.common.syscalls.GET_SEQUENCER_ADDRESS_SELECTOR": { + "value": 1592190833581991703053805829594610833820054387, + "type": "const" + }, + "starkware.starknet.common.syscalls.GetSequencerAddressRequest": { + "full_name": "starkware.starknet.common.syscalls.GetSequencerAddressRequest", + "members": { + "selector": { + "offset": 0, + "cairo_type": "felt" + } + }, + "size": 1, + "type": "struct" + }, + "starkware.starknet.common.syscalls.GetSequencerAddressResponse": { + "full_name": "starkware.starknet.common.syscalls.GetSequencerAddressResponse", + "members": { + "sequencer_address": { + "offset": 0, + "cairo_type": "felt" + } + }, + "size": 1, + "type": "struct" + }, + "starkware.starknet.common.syscalls.GetSequencerAddress": { + "full_name": "starkware.starknet.common.syscalls.GetSequencerAddress", + "members": { + "request": { + "offset": 0, + "cairo_type": "starkware.starknet.common.syscalls.GetSequencerAddressRequest" + }, + "response": { + "offset": 1, + "cairo_type": "starkware.starknet.common.syscalls.GetSequencerAddressResponse" + } + }, + "size": 2, + "type": "struct" + }, + "starkware.starknet.common.syscalls.GET_CONTRACT_ADDRESS_SELECTOR": { + "value": 6219495360805491471215297013070624192820083, + "type": "const" + }, + "starkware.starknet.common.syscalls.GetContractAddressRequest": { + "full_name": "starkware.starknet.common.syscalls.GetContractAddressRequest", + "members": { + "selector": { + "offset": 0, + "cairo_type": "felt" + } + }, + "size": 1, + "type": "struct" + }, + "starkware.starknet.common.syscalls.GetContractAddressResponse": { + "full_name": "starkware.starknet.common.syscalls.GetContractAddressResponse", + "members": { + "contract_address": { + "offset": 0, + "cairo_type": "felt" + } + }, + "size": 1, + "type": "struct" + }, + "starkware.starknet.common.syscalls.GetContractAddress": { + "full_name": "starkware.starknet.common.syscalls.GetContractAddress", + "members": { + "request": { + "offset": 0, + "cairo_type": "starkware.starknet.common.syscalls.GetContractAddressRequest" + }, + "response": { + "offset": 1, + "cairo_type": "starkware.starknet.common.syscalls.GetContractAddressResponse" + } + }, + "size": 2, + "type": "struct" + }, + "starkware.starknet.common.syscalls.GET_TX_SIGNATURE_SELECTOR": { + "value": 1448089128652340074717162277007973, + "type": "const" + }, + "starkware.starknet.common.syscalls.GetTxSignatureRequest": { + "full_name": "starkware.starknet.common.syscalls.GetTxSignatureRequest", + "members": { + "selector": { + "offset": 0, + "cairo_type": "felt" + } + }, + "size": 1, + "type": "struct" + }, + "starkware.starknet.common.syscalls.GetTxSignatureResponse": { + "full_name": "starkware.starknet.common.syscalls.GetTxSignatureResponse", + "members": { + "signature_len": { + "offset": 0, + "cairo_type": "felt" + }, + "signature": { + "offset": 1, + "cairo_type": "felt*" + } + }, + "size": 2, + "type": "struct" + }, + "starkware.starknet.common.syscalls.GetTxSignature": { + "full_name": "starkware.starknet.common.syscalls.GetTxSignature", + "members": { + "request": { + "offset": 0, + "cairo_type": "starkware.starknet.common.syscalls.GetTxSignatureRequest" + }, + "response": { + "offset": 1, + "cairo_type": "starkware.starknet.common.syscalls.GetTxSignatureResponse" + } + }, + "size": 3, + "type": "struct" + }, + "starkware.starknet.common.syscalls.STORAGE_READ_SELECTOR": { + "value": 100890693370601760042082660, + "type": "const" + }, + "starkware.starknet.common.syscalls.StorageReadRequest": { + "full_name": "starkware.starknet.common.syscalls.StorageReadRequest", + "members": { + "selector": { + "offset": 0, + "cairo_type": "felt" + }, + "address": { + "offset": 1, + "cairo_type": "felt" + } + }, + "size": 2, + "type": "struct" + }, + "starkware.starknet.common.syscalls.StorageReadResponse": { + "full_name": "starkware.starknet.common.syscalls.StorageReadResponse", + "members": { + "value": { + "offset": 0, + "cairo_type": "felt" + } + }, + "size": 1, + "type": "struct" + }, + "starkware.starknet.common.syscalls.StorageRead": { + "full_name": "starkware.starknet.common.syscalls.StorageRead", + "members": { + "request": { + "offset": 0, + "cairo_type": "starkware.starknet.common.syscalls.StorageReadRequest" + }, + "response": { + "offset": 2, + "cairo_type": "starkware.starknet.common.syscalls.StorageReadResponse" + } + }, + "size": 3, + "type": "struct" + }, + "starkware.starknet.common.syscalls.STORAGE_WRITE_SELECTOR": { + "value": 25828017502874050592466629733, + "type": "const" + }, + "starkware.starknet.common.syscalls.StorageWrite": { + "full_name": "starkware.starknet.common.syscalls.StorageWrite", + "members": { + "selector": { + "offset": 0, + "cairo_type": "felt" + }, + "address": { + "offset": 1, + "cairo_type": "felt" + }, + "value": { + "offset": 2, + "cairo_type": "felt" + } + }, + "size": 3, + "type": "struct" + } + }, + "reference_manager": { + "references": [] + }, + "debug_info": null + }, + "entry_points_by_type": { + "EXTERNAL": [], + "L1_HANDLER": [], + "CONSTRUCTOR": [] + }, + "abi": [] +} diff --git a/crates/starknet_os/resources/trusted_setup.txt b/crates/starknet_os/resources/trusted_setup.txt new file mode 100644 index 00000000000..d2519656fb2 --- /dev/null +++ b/crates/starknet_os/resources/trusted_setup.txt @@ -0,0 +1,4163 @@ +4096 +65 +a0413c0dcafec6dbc9f47d66785cf1e8c981044f7d13cfe3e4fcbb71b5408dfde6312493cb3c1d30516cb3ca88c03654 +8b997fb25730d661918371bb41f2a6e899cac23f04fc5365800b75433c0a953250e15e7a98fb5ca5cc56a8cd34c20c57 +83302852db89424d5699f3f157e79e91dc1380f8d5895c5a772bb4ea3a5928e7c26c07db6775203ce33e62a114adaa99 +a759c48b7e4a685e735c01e5aa6ef9c248705001f470f9ad856cd87806983e917a8742a3bd5ee27db8d76080269b7c83 +967f8dc45ebc3be14c8705f43249a30ff48e96205fb02ae28daeab47b72eb3f45df0625928582aa1eb4368381c33e127 +a418eb1e9fb84cb32b370610f56f3cb470706a40ac5a47c411c464299c45c91f25b63ae3fcd623172aa0f273c0526c13 +8f44e3f0387293bc7931e978165abbaed08f53acd72a0a23ac85f6da0091196b886233bcee5b4a194db02f3d5a9b3f78 +97173434b336be73c89412a6d70d416e170ea355bf1956c32d464090b107c090ef2d4e1a467a5632fbc332eeb679bf2d +a24052ad8d55ad04bc5d951f78e14213435681594110fd18173482609d5019105b8045182d53ffce4fc29fc8810516c1 +b950768136b260277590b5bec3f56bbc2f7a8bc383d44ce8600e85bf8cf19f479898bcc999d96dfbd2001ede01d94949 +92ab8077871037bd3b57b95cbb9fb10eb11efde9191690dcac655356986fd02841d8fdb25396faa0feadfe3f50baf56d +a79b096dff98038ac30f91112dd14b78f8ad428268af36d20c292e2b3b6d9ed4fb28480bb04e465071cc67d05786b6d1 +b9ff71461328f370ce68bf591aa7fb13027044f42a575517f3319e2be4aa4843fa281e756d0aa5645428d6dfa857cef2 +8d765808c00b3543ff182e2d159c38ae174b12d1314da88ea08e13bd9d1c37184cb515e6bf6420531b5d41767987d7ce +b8c9a837d20c3b53e6f578e4a257bb7ef8fc43178614ec2a154915b267ad2be135981d01ed2ee1b5fbd9d9bb27f0800a +a9773d92cf23f65f98ef68f6cf95c72b53d0683af2f9bf886bb9036e4a38184b1131b26fd24397910b494fbef856f3aa +b41ebe38962d112da4a01bf101cb248d808fbd50aaf749fc7c151cf332032eb3e3bdbd716db899724b734d392f26c412 +90fbb030167fb47dcc13d604a726c0339418567c1d287d1d87423fa0cb92eec3455fbb46bcbe2e697144a2d3972142e4 +b11d298bd167464b35fb923520d14832bd9ed50ed841bf6d7618424fd6f3699190af21759e351b89142d355952149da1 +8bc36066f69dc89f7c4d1e58d67497675050c6aa002244cebd9fc957ec5e364c46bab4735ea3db02b73b3ca43c96e019 +ab7ab92c5d4d773068e485aa5831941ebd63db7118674ca38089635f3b4186833af2455a6fb9ed2b745df53b3ce96727 +af191ca3089892cb943cd97cf11a51f38e38bd9be50844a4e8da99f27e305e876f9ed4ab0628e8ae3939066b7d34a15f +a3204c1747feabc2c11339a542195e7cb6628fd3964f846e71e2e3f2d6bb379a5e51700682ea1844eba12756adb13216 +903a29883846b7c50c15968b20e30c471aeac07b872c40a4d19eb1a42da18b649d5bbfde4b4cf6225d215a461b0deb6d +8e6e9c15ffbf1e16e5865a5fef7ed751dc81957a9757b535cb38b649e1098cda25d42381dc4f776778573cdf90c3e6e0 +a8f6dd26100b512a8c96c52e00715c4b2cb9ac457f17aed8ffe1cf1ea524068fe5a1ddf218149845fc1417b789ecfc98 +a5b0ffc819451ea639cfd1c18cbc9365cc79368d3b2e736c0ae54eba2f0801e6eb0ee14a5f373f4a70ca463bdb696c09 +879f91ccd56a1b9736fbfd20d8747354da743fb121f0e308a0d298ff0d9344431890e41da66b5009af3f442c636b4f43 +81bf3a2d9755e206b515a508ac4d1109bf933c282a46a4ae4a1b4cb4a94e1d23642fad6bd452428845afa155742ade7e +8de778d4742f945df40004964e165592f9c6b1946263adcdd5a88b00244bda46c7bb49098c8eb6b3d97a0dd46148a8ca +b7a57b21d13121907ee28c5c1f80ee2e3e83a3135a8101e933cf57171209a96173ff5037f5af606e9fd6d066de6ed693 +b0877d1963fd9200414a38753dffd9f23a10eb3198912790d7eddbc9f6b477019d52ddd4ebdcb9f60818db076938a5a9 +88da2d7a6611bc16adc55fc1c377480c828aba4496c645e3efe0e1a67f333c05a0307f7f1d2df8ac013602c655c6e209 +95719eb02e8a9dede1a888c656a778b1c69b7716fbe3d1538fe8afd4a1bc972183c7d32aa7d6073376f7701df80116d8 +8e8a1ca971f2444b35af3376e85dccda3abb8e8e11d095d0a4c37628dfe5d3e043a377c3de68289ef142e4308e9941a0 +b720caaff02f6d798ac84c4f527203e823ff685869e3943c979e388e1c34c3f77f5c242c6daa7e3b30e511aab917b866 +86040d55809afeec10e315d1ad950d269d37cfee8c144cd8dd4126459e3b15a53b3e68df5981df3c2346d23c7b4baaf4 +82d8cabf13ab853db0377504f0aec00dba3a5cd3119787e8ad378ddf2c40b022ecfc67c642b7acc8c1e3dd03ab50993e +b8d873927936719d2484cd03a6687d65697e17dcf4f0d5aed6f5e4750f52ef2133d4645894e7ebfc4ef6ce6788d404c8 +b1235594dbb15b674a419ff2b2deb644ad2a93791ca05af402823f87114483d6aa1689b7a9bea0f547ad12fe270e4344 +a53fda86571b0651f5affb74312551a082fffc0385cfd24c1d779985b72a5b1cf7c78b42b4f7e51e77055f8e5e915b00 +b579adcfd9c6ef916a5a999e77a0cb21d378c4ea67e13b7c58709d5da23a56c2e54218691fc4ac39a4a3d74f88cc31f7 +ab79e584011713e8a2f583e483a91a0c2a40771b77d91475825b5acbea82db4262132901cb3e4a108c46d7c9ee217a4e +a0fe58ea9eb982d7654c8aaf9366230578fc1362f6faae0594f8b9e659bcb405dff4aac0c7888bbe07f614ecf0d800a6 +867e50e74281f28ecd4925560e2e7a6f8911b135557b688254623acce0dbc41e23ac3e706a184a45d54c586edc416eb0 +89f81b61adda20ea9d0b387a36d0ab073dc7c7cbff518501962038be19867042f11fcc7ff78096e5d3b68c6d8dc04d9b +a58ee91bb556d43cf01f1398c5811f76dc0f11efdd569eed9ef178b3b0715e122060ec8f945b4dbf6eebfa2b90af6fa6 +ac460be540f4c840def2eef19fc754a9af34608d107cbadb53334cf194cc91138d53b9538fcd0ec970b5d4aa455b224a +b09b91f929de52c09d48ca0893be6eb44e2f5210a6c394689dc1f7729d4be4e11d0474b178e80cea8c2ac0d081f0e811 +8d37a442a76b06a02a4e64c2504aea72c8b9b020ab7bcc94580fe2b9603c7c50d7b1e9d70d2a7daea19c68667e8f8c31 +a9838d4c4e3f3a0075a952cf7dd623307ec633fcc81a7cf9e52e66c31780de33dbb3d74c320dc7f0a4b72f7a49949515 +a44766b6251af458fe4f5f9ed1e02950f35703520b8656f09fc42d9a2d38a700c11a7c8a0436ac2e5e9f053d0bb8ff91 +ad78d9481c840f5202546bea0d13c776826feb8b1b7c72e83d99a947622f0bf38a4208551c4c41beb1270d7792075457 +b619ffa8733b470039451e224b777845021e8dc1125f247a4ff2476cc774657d0ff9c5279da841fc1236047de9d81c60 +af760b0a30a1d6af3bc5cd6686f396bd41779aeeb6e0d70a09349bd5da17ca2e7965afc5c8ec22744198fbe3f02fb331 +a0cc209abdb768b589fcb7b376b6e1cac07743288c95a1cf1a0354b47f0cf91fca78a75c1fcafa6f5926d6c379116608 +864add673c89c41c754eeb3cd8dcff5cdde1d739fce65c30e474a082bb5d813cba6412e61154ce88fdb6c12c5d9be35b +b091443b0ce279327dc37cb484e9a5b69b257a714ce21895d67539172f95ffa326903747b64a3649e99aea7bb10d03f7 +a8c452b8c4ca8e0a61942a8e08e28f17fb0ef4c5b018b4e6d1a64038280afa2bf1169202f05f14af24a06ca72f448ccd +a23c24721d18bc48d5dcf70effcbef89a7ae24e67158d70ae1d8169ee75d9a051d34b14e9cf06488bac324fe58549f26 +92a730e30eb5f3231feb85f6720489dbb1afd42c43f05a1610c6b3c67bb949ec8fde507e924498f4ffc646f7b07d9123 +8dbe5abf4031ec9ba6bb06d1a47dd1121fb9e03b652804069250967fd5e9577d0039e233441b7f837a7c9d67ba18c28e +aa456bcfef6a21bb88181482b279df260297b3778e84594ebddbdf337e85d9e3d46ca1d0b516622fb0b103df8ec519b7 +a3b31ae621bd210a2b767e0e6f22eb28fe3c4943498a7e91753225426168b9a26da0e02f1dc5264da53a5ad240d9f51b +aa8d66857127e6e71874ce2202923385a7d2818b84cb73a6c42d71afe70972a70c6bdd2aad1a6e8c5e4ca728382a8ea8 +ac7e8e7a82f439127a5e40558d90d17990f8229852d21c13d753c2e97facf077cf59582b603984c3dd3faebd80aff4f5 +93a8bcf4159f455d1baa73d2ef2450dcd4100420de84169bbe28b8b7a5d1746273f870091a87a057e834f754f34204b1 +89d0ebb287c3613cdcae7f5acc43f17f09c0213fc40c074660120b755d664109ffb9902ed981ede79e018ddb0c845698 +a87ccbfad431406aadbee878d9cf7d91b13649d5f7e19938b7dfd32645a43b114eef64ff3a13201398bd9b0337832e5a +833c51d0d0048f70c3eefb4e70e4ff66d0809c41838e8d2c21c288dd3ae9d9dfaf26d1742bf4976dab83a2b381677011 +8bcd6b1c3b02fffead432e8b1680bad0a1ac5a712d4225e220690ee18df3e7406e2769e1f309e2e803b850bc96f0e768 +b61e3dbd88aaf4ff1401521781e2eea9ef8b66d1fac5387c83b1da9e65c2aa2a56c262dea9eceeb4ad86c90211672db0 +866d3090db944ecf190dd0651abf67659caafd31ae861bab9992c1e3915cb0952da7c561cc7e203560a610f48fae633b +a5e8971543c14274a8dc892b0be188c1b4fbc75c692ed29f166e0ea80874bc5520c2791342b7c1d2fb5dd454b03b8a5b +8f2f9fc50471bae9ea87487ebd1bc8576ef844cc42d606af5c4c0969670fdf2189afd643e4de3145864e7773d215f37f +b1bb0f2527db6d51f42b9224383c0f96048bbc03d469bf01fe1383173ef8b1cc9455d9dd8ba04d46057f46949bfc92b5 +aa7c99d906b4d7922296cfe2520473fc50137c03d68b7865c5bfb8adbc316b1034310ec4b5670c47295f4a80fb8d61e9 +a5d1da4d6aba555919df44cbaa8ff79378a1c9e2cfdfbf9d39c63a4a00f284c5a5724e28ecbc2d9dba27fe4ee5018bd5 +a8db53224f70af4d991b9aae4ffe92d2aa5b618ad9137784b55843e9f16cefbfd25ada355d308e9bbf55f6d2f7976fb3 +b6536c4232bb20e22af1a8bb12de76d5fec2ad9a3b48af1f38fa67e0f8504ef60f305a73d19385095bb6a9603fe29889 +87f7e371a1817a63d6838a8cf4ab3a8473d19ce0d4f40fd013c03d5ddd5f4985df2956531cc9f187928ef54c68f4f9a9 +ae13530b1dbc5e4dced9d909ea61286ec09e25c12f37a1ed2f309b0eb99863d236c3b25ed3484acc8c076ad2fa8cd430 +98928d850247c6f7606190e687d5c94a627550198dbdbea0161ef9515eacdb1a0f195cae3bb293112179082daccf8b35 +918528bb8e6a055ad4db6230d3a405e9e55866da15c4721f5ddd1f1f37962d4904aad7a419218fe6d906fe191a991806 +b71e31a06afe065773dd3f4a6e9ef81c3292e27a3b7fdfdd452d03e05af3b6dd654c355f7516b2a93553360c6681a73a +8870b83ab78a98820866f91ac643af9f3ff792a2b7fda34185a9456a63abdce42bfe8ad4dc67f08a6392f250d4062df4 +91eea1b668e52f7a7a5087fabf1cab803b0316f78d9fff469fbfde2162f660c250e4336a9eea4cb0450bd30ac067bc8b +8b74990946de7b72a92147ceac1bd9d55999a8b576e8df68639e40ed5dc2062cfcd727903133de482b6dca19d0aaed82 +8ebad537fece090ebbab662bdf2618e21ca30cf6329c50935e8346d1217dcbe3c1fe1ea28efca369c6003ce0a94703c1 +a8640479556fb59ebd1c40c5f368fbd960932fdbb782665e4a0e24e2bdb598fc0164ce8c0726d7759cfc59e60a62e182 +a9a52a6bf98ee4d749f6d38be2c60a6d54b64d5cbe4e67266633dc096cf28c97fe998596707d31968cbe2064b72256bf +847953c48a4ce6032780e9b39d0ed4384e0be202c2bbe2dfda3910f5d87aa5cd3c2ffbfcfae4dddce16d6ab657599b95 +b6f6e1485d3ec2a06abaecd23028b200b2e4a0096c16144d07403e1720ff8f9ba9d919016b5eb8dc5103880a7a77a1d3 +98dfc2065b1622f596dbe27131ea60bef7a193b12922cecb27f8c571404f483014f8014572e86ae2e341ab738e4887ef +acb0d205566bacc87bbe2e25d10793f63f7a1f27fd9e58f4f653ceae3ffeba511eaf658e068fad289eeb28f9edbeb35b +ae4411ed5b263673cee894c11fe4abc72a4bf642d94022a5c0f3369380fcdfc1c21e277f2902972252503f91ada3029a +ac4a7a27ba390a75d0a247d93d4a8ef1f0485f8d373a4af4e1139369ec274b91b3464d9738eeaceb19cd6f509e2f8262 +87379c3bf231fdafcf6472a79e9e55a938d851d4dd662ab6e0d95fd47a478ed99e2ad1e6e39be3c0fc4f6d996a7dd833 +81316904b035a8bcc2041199a789a2e6879486ba9fddcba0a82c745cc8dd8374a39e523b91792170cd30be7aa3005b85 +b8206809c6cd027ed019f472581b45f7e12288f89047928ba32b4856b6560ad30395830d71e5e30c556f6f182b1fe690 +88d76c028f534a62e019b4a52967bb8642ede6becfa3807be68fdd36d366fc84a4ac8dc176e80a68bc59eb62caf5dff9 +8c3b8be685b0f8aad131ee7544d0e12f223f08a6f8edaf464b385ac644e0ddc9eff7cc7cb5c1b50ab5d71ea0f41d2213 +8d91410e004f76c50fdc05784157b4d839cb5090022c629c7c97a5e0c3536eeafee17a527b54b1165c3cd81774bb54ce +b25c2863bc28ec5281ce800ddf91a7e1a53f4c6d5da1e6c86ef4616e93bcf55ed49e297216d01379f5c6e7b3c1e46728 +865f7b09ac3ca03f20be90c48f6975dd2588838c2536c7a3532a6aa5187ed0b709cd03d91ff4048061c10d0aa72b69ce +b3f7477c90c11596eb4f8bbf34adbcb832638c4ff3cdd090d4d477ee50472ac9ddaf5be9ad7eca3f148960d362bbd098 +8db35fd53fca04faecd1c76a8227160b3ab46ac1af070f2492445a19d8ff7c25bbaef6c9fa0c8c088444561e9f7e4eb2 +a478b6e9d058a2e01d2fc053b739092e113c23a6a2770a16afbef044a3709a9e32f425ace9ba7981325f02667c3f9609 +98caa6bd38916c08cf221722a675a4f7577f33452623de801d2b3429595f988090907a7e99960fff7c076d6d8e877b31 +b79aaaacefc49c3038a14d2ac468cfec8c2161e88bdae91798d63552cdbe39e0e02f9225717436b9b8a40a022c633c6e +845a31006c680ee6a0cc41d3dc6c0c95d833fcf426f2e7c573fa15b2c4c641fbd6fe5ebb0e23720cc3467d6ee1d80dc4 +a1bc287e272cf8b74dbf6405b3a5190883195806aa351f1dc8e525aa342283f0a35ff687e3b434324dedee74946dd185 +a4fd2dc8db75d3783a020856e2b3aa266dc6926e84f5c491ef739a3bddd46dc8e9e0fc1177937839ef1b18d062ffbb9e +acbf0d3c697f57c202bb8c5dc4f3fc341b8fc509a455d44bd86acc67cad2a04495d5537bcd3e98680185e8aa286f2587 +a5caf423a917352e1b8e844f5968a6da4fdeae467d10c6f4bbd82b5eea46a660b82d2f5440d3641c717b2c3c9ed0be52 +8a39d763c08b926599ab1233219c49c825368fad14d9afc7c0c039224d37c00d8743293fd21645bf0b91eaf579a99867 +b2b53a496def0ba06e80b28f36530fbe0fb5d70a601a2f10722e59abee529369c1ae8fd0f2db9184dd4a2519bb832d94 +a73980fcef053f1b60ebbb5d78ba6332a475e0b96a0c724741a3abf3b59dd344772527f07203cf4c9cb5155ebed81fa0 +a070d20acce42518ece322c9db096f16aed620303a39d8d5735a0df6e70fbeceb940e8d9f5cc38f3314b2240394ec47b +a50cf591f522f19ca337b73089557f75929d9f645f3e57d4f241e14cdd1ea3fb48d84bcf05e4f0377afbb789fbdb5d20 +82a5ffce451096aca8eeb0cd2ae9d83db3ed76da3f531a80d9a70a346359bf05d74863ce6a7c848522b526156a5e20cd +88e0e84d358cbb93755a906f329db1537c3894845f32b9b0b691c29cbb455373d9452fadd1e77e20a623f6eaf624de6f +aa07ac7b84a6d6838826e0b9e350d8ec75e398a52e9824e6b0da6ae4010e5943fec4f00239e96433f291fef9d1d1e609 +ac8887bf39366034bc63f6cc5db0c26fd27307cbc3d6cce47894a8a019c22dd51322fb5096edc018227edfafc053a8f6 +b7d26c26c5b33f77422191dca94977588ab1d4b9ce7d0e19c4a3b4cd1c25211b78c328dbf81e755e78cd7d1d622ad23e +99a676d5af49f0ba44047009298d8474cabf2d5bca1a76ba21eff7ee3c4691a102fdefea27bc948ccad8894a658abd02 +b0d09a91909ab3620c183bdf1d53d43d39eb750dc7a722c661c3de3a1a5d383ad221f71bae374f8a71867505958a3f76 +84681a883de8e4b93d68ac10e91899c2bbb815ce2de74bb48a11a6113b2a3f4df8aceabda1f5f67bc5aacac8c9da7221 +9470259957780fa9b43521fab3644f555f5343281c72582b56d2efd11991d897b3b481cafa48681c5aeb80c9663b68f7 +ab1b29f7ece686e6fa968a4815da1d64f3579fed3bc92e1f3e51cd13a3c076b6cf695ed269d373300a62463dc98a4234 +8ab415bfcd5f1061f7687597024c96dd9c7cb4942b5989379a7a3b5742f7d394337886317659cbeacaf030234a24f972 +b9b524aad924f9acc63d002d617488f31b0016e0f0548f050cada285ce7491b74a125621638f19e9c96eabb091d945be +8c4c373e79415061837dd0def4f28a2d5d74d21cb13a76c9049ad678ca40228405ab0c3941df49249847ecdefc1a5b78 +a8edf4710b5ab2929d3db6c1c0e3e242261bbaa8bcec56908ddadd7d2dad2dca9d6eb9de630b960b122ebeea41040421 +8d66bb3b50b9df8f373163629f9221b3d4b6980a05ea81dc3741bfe9519cf3ebba7ab98e98390bae475e8ede5821bd5c +8d3c21bae7f0cfb97c56952bb22084b58e7bb718890935b73103f33adf5e4d99cd262f929c6eeab96209814f0dbae50a +a5c66cfab3d9ebf733c4af24bebc97070e7989fe3c73e79ac85fb0e4d40ae44fb571e0fad4ad72560e13ed453900d14f +9362e6b50b43dbefbc3254471372297b5dcce809cd3b60bf74a1268ab68bdb50e46e462cbd78f0d6c056330e982846af +854630d08e3f0243d570cc2e856234cb4c1a158d9c1883bf028a76525aaa34be897fe918d5f6da9764a3735fa9ebd24a +8c7d246985469ff252c3f4df6c7c9196fc79f05c1c66a609d84725c78001d0837c7a7049394ba5cf7e863e2d58af8417 +ae050271e01b528925302e71903f785b782f7bf4e4e7a7f537140219bc352dc7540c657ed03d3a297ad36798ecdb98cd +8d2ae9179fcf2b0c69850554580b52c1f4a5bd865af5f3028f222f4acad9c1ad69a8ef6c7dc7b03715ee5c506b74325e +b8ef8de6ce6369a8851cd36db0ccf00a85077e816c14c4e601f533330af9e3acf0743a95d28962ed8bfcfc2520ef3cfe +a6ecad6fdfb851b40356a8b1060f38235407a0f2706e7b8bb4a13465ca3f81d4f5b99466ac2565c60af15f022d26732e +819ff14cdea3ab89d98e133cd2d0379361e2e2c67ad94eeddcdb9232efd509f51d12f4f03ebd4dd953bd262a886281f7 +8561cd0f7a6dbcddd83fcd7f472d7dbcba95b2d4fb98276f48fccf69f76d284e626d7e41314b633352df8e6333fd52a1 +b42557ccce32d9a894d538c48712cb3e212d06ac05cd5e0527ccd2db1078ee6ae399bf6a601ffdab1f5913d35fc0b20c +89b4008d767aad3c6f93c349d3b956e28307311a5b1cec237e8d74bb0dee7e972c24f347fd56afd915a2342bd7bc32f0 +877487384b207e53f5492f4e36c832c2227f92d1bb60542cfeb35e025a4a7afc2b885fae2528b33b40ab09510398f83e +8c411050b63c9053dd0cd81dacb48753c3d7f162028098e024d17cd6348482703a69df31ad6256e3d25a8bbf7783de39 +a8506b54a88d17ac10fb1b0d1fe4aa40eae7553a064863d7f6b52ccc4236dd4b82d01dca6ba87da9a239e3069ba879fb +b1a24caef9df64750c1350789bb8d8a0db0f39474a1c74ea9ba064b1516db6923f00af8d57c632d58844fb8786c3d47a +959d6e255f212b0708c58a2f75cb1fe932248c9d93424612c1b8d1e640149656059737e4db2139afd5556bcdacf3eda2 +84525af21a8d78748680b6535bbc9dc2f0cf9a1d1740d12f382f6ecb2e73811d6c1da2ad9956070b1a617c61fcff9fe5 +b74417d84597a485d0a8e1be07bf78f17ebb2e7b3521b748f73935b9afbbd82f34b710fb7749e7d4ab55b0c7f9de127d +a4a9aecb19a6bab167af96d8b9d9aa5308eab19e6bfb78f5a580f9bf89bdf250a7b52a09b75f715d651cb73febd08e84 +9777b30be2c5ffe7d29cc2803a562a32fb43b59d8c3f05a707ab60ec05b28293716230a7d264d7cd9dd358fc031cc13e +95dce7a3d4f23ac0050c510999f5fbf8042f771e8f8f94192e17bcbfa213470802ebdbe33a876cb621cf42e275cbfc8b +b0b963ebcbbee847ab8ae740478544350b3ac7e86887e4dfb2299ee5096247cd2b03c1de74c774d9bde94ae2ee2dcd59 +a4ab20bafa316030264e13f7ef5891a2c3b29ab62e1668fcb5881f50a9acac6adbe3d706c07e62f2539715db768f6c43 +901478a297669d608e406fe4989be75264b6c8be12169aa9e0ad5234f459ca377f78484ffd2099a2fe2db5e457826427 +88c76e5c250810c057004a03408b85cd918e0c8903dc55a0dd8bb9b4fc2b25c87f9b8cf5943eb19fbbe99d36490050c5 +91607322bbad4a4f03fc0012d0821eff5f8c516fda45d1ec1133bface6f858bf04b25547be24159cab931a7aa08344d4 +843203e07fce3c6c81f84bc6dc5fb5e9d1c50c8811ace522dc66e8658433a0ef9784c947e6a62c11bf705307ef05212e +91dd8813a5d6dddcda7b0f87f672b83198cd0959d8311b2b26fb1fae745185c01f796fbd03aad9db9b58482483fdadd8 +8d15911aacf76c8bcd7136e958febd6963104addcd751ce5c06b6c37213f9c4fb0ffd4e0d12c8e40c36d658999724bfd +8a36c5732d3f1b497ebe9250610605ee62a78eaa9e1a45f329d09aaa1061131cf1d9df00f3a7d0fe8ad614a1ff9caaae +a407d06affae03660881ce20dab5e2d2d6cddc23cd09b95502a9181c465e57597841144cb34d22889902aff23a76d049 +b5fd856d0578620a7e25674d9503be7d97a2222900e1b4738c1d81ff6483b144e19e46802e91161e246271f90270e6cf +91b7708869cdb5a7317f88c0312d103f8ce90be14fb4f219c2e074045a2a83636fdc3e69e862049fc7c1ef000e832541 +b64719cc5480709d1dae958f1d3082b32a43376da446c8f9f64cb02a301effc9c34d9102051733315a8179aed94d53cc +94347a9542ff9d18f7d9eaa2f4d9b832d0e535fe49d52aa2de08aa8192400eddabdb6444a2a78883e27c779eed7fdf5a +840ef44a733ff1376466698cd26f82cf56bb44811e196340467f932efa3ae1ef9958a0701b3b032f50fd9c1d2aed9ab5 +90ab3f6f67688888a31ffc2a882bb37adab32d1a4b278951a21646f90d03385fc976715fc639a785d015751171016f10 +b56f35d164c24b557dbcbc8a4bfa681ec916f8741ffcb27fb389c164f4e3ed2be325210ef5bdaeae7a172ca9599ab442 +a7921a5a80d7cf6ae81ba9ee05e0579b18c20cd2852762c89d6496aa4c8ca9d1ca2434a67b2c16d333ea8e382cdab1e3 +a506bcfbd7e7e5a92f68a1bd87d07ad5fe3b97aeee40af2bf2cae4efcd77fff03f872732c5b7883aa6584bee65d6f8cb +a8c46cff58931a1ce9cbe1501e1da90b174cddd6d50f3dfdfb759d1d4ad4673c0a8feed6c1f24c7af32865a7d6c984e5 +b45686265a83bff69e312c5149db7bb70ac3ec790dc92e392b54d9c85a656e2bf58596ce269f014a906eafc97461aa5f +8d4009a75ccb2f29f54a5f16684b93202c570d7a56ec1a8b20173269c5f7115894f210c26b41e8d54d4072de2d1c75d0 +aef8810af4fc676bf84a0d57b189760ddc3375c64e982539107422e3de2580b89bd27aa6da44e827b56db1b5555e4ee8 +888f0e1e4a34f48eb9a18ef4de334c27564d72f2cf8073e3d46d881853ac1424d79e88d8ddb251914890588937c8f711 +b64b0aa7b3a8f6e0d4b3499fe54e751b8c3e946377c0d5a6dbb677be23736b86a7e8a6be022411601dd75012012c3555 +8d57776f519f0dd912ea14f79fbab53a30624e102f9575c0bad08d2dc754e6be54f39b11278c290977d9b9c7c0e1e0ad +a018fc00d532ceb2e4de908a15606db9b6e0665dd77190e2338da7c87a1713e6b9b61554e7c1462f0f6d4934b960b15c +8c932be83ace46f65c78e145b384f58e41546dc0395270c1397874d88626fdeda395c8a289d602b4c312fe98c1311856 +89174838e21639d6bdd91a0621f04dc056907b88e305dd66e46a08f6d65f731dea72ae87ca5e3042d609e8de8de9aa26 +b7b7f508bb74f7a827ac8189daa855598ff1d96fa3a02394891fd105d8f0816224cd50ac4bf2ed1cf469ace516c48184 +b31877ad682583283baadd68dc1bebd83f5748b165aadd7fe9ef61a343773b88bcd3a022f36d6c92f339b7bfd72820a9 +b79d77260b25daf9126dab7a193df2d7d30542786fa1733ffaf6261734770275d3ca8bae1d9915d1181a78510b3439db +91894fb94cd4c1dd2ceaf9c53a7020c5799ba1217cf2d251ea5bc91ed26e1159dd758e98282ebe35a0395ef9f1ed15a0 +ab59895cdafd33934ceedfc3f0d5d89880482cba6c99a6db93245f9e41987efd76e0640e80aef31782c9a8c7a83fccec +aa22ea63654315e033e09d4d4432331904a6fc5fb1732557987846e3c564668ca67c60a324b4af01663a23af11a9ce4b +b53ba3ef342601467e1f71aa280e100fbabbd38518fa0193e0099505036ee517c1ac78e96e9baeb549bb6879bb698fb0 +943fd69fd656f37487cca3605dc7e5a215fddd811caf228595ec428751fc1de484a0cb84c667fe4d7c35599bfa0e5e34 +9353128b5ebe0dddc555093cf3e5942754f938173541033e8788d7331fafc56f68d9f97b4131e37963ab7f1c8946f5f1 +a76cd3c566691f65cfb86453b5b31dbaf3cab8f84fe1f795dd1e570784b9b01bdd5f0b3c1e233942b1b5838290e00598 +983d84b2e53ffa4ae7f3ba29ef2345247ea2377686b74a10479a0ef105ecf90427bf53b74c96dfa346d0f842b6ffb25b +92e0fe9063306894a2c6970c001781cff416c87e87cb5fbac927a3192655c3da4063e6fa93539f6ff58efac6adcc5514 +b00a81f03c2b8703acd4e2e4c21e06973aba696415d0ea1a648ace2b0ea19b242fede10e4f9d7dcd61c546ab878bc8f9 +b0d08d880f3b456a10bf65cff983f754f545c840c413aea90ce7101a66eb0a0b9b1549d6c4d57725315828607963f15a +90cb64d03534f913b411375cce88a9e8b1329ce67a9f89ca5df8a22b8c1c97707fec727dbcbb9737f20c4cf751359277 +8327c2d42590dfcdb78477fc18dcf71608686ad66c49bce64d7ee874668be7e1c17cc1042a754bbc77c9daf50b2dae07 +8532171ea13aa7e37178e51a6c775da469d2e26ec854eb16e60f3307db4acec110d2155832c202e9ba525fc99174e3b0 +83ca44b15393d021de2a511fa5511c5bd4e0ac7d67259dce5a5328f38a3cce9c3a269405959a2486016bc27bb140f9ff +b1d36e8ca812be545505c8214943b36cabee48112cf0de369957afa796d37f86bf7249d9f36e8e990f26f1076f292b13 +9803abf45be5271e2f3164c328d449efc4b8fc92dfc1225d38e09630909fe92e90a5c77618daa5f592d23fc3ad667094 +b268ad68c7bf432a01039cd889afae815c3e120f57930d463aece10af4fd330b5bd7d8869ef1bcf6b2e78e4229922edc +a4c91a0d6f16b1553264592b4cbbbf3ca5da32ab053ffbdd3dbb1aed1afb650fb6e0dc5274f71a51d7160856477228db +ad89d043c2f0f17806277ffdf3ecf007448e93968663f8a0b674254f36170447b7527d5906035e5e56f4146b89b5af56 +8b6964f757a72a22a642e4d69102951897e20c21449184e44717bd0681d75f7c5bfa5ee5397f6e53febf85a1810d6ed1 +b08f5cdaabec910856920cd6e836c830b863eb578423edf0b32529488f71fe8257d90aed4a127448204df498b6815d79 +af26bb3358be9d280d39b21d831bb53145c4527a642446073fee5a86215c4c89ff49a3877a7a549486262f6f57a0f476 +b4010b37ec4d7c2af20800e272539200a6b623ae4636ecbd0e619484f4ab9240d02bc5541ace3a3fb955dc0a3d774212 +82752ab52bdcc3cc2fc405cb05a2e694d3df4a3a68f2179ec0652536d067b43660b96f85f573f26fbd664a9ef899f650 +96d392dde067473a81faf2d1fea55b6429126b88b160e39b4210d31d0a82833ffd3a80e07d24d495aea2d96be7251547 +a76d8236d6671204d440c33ac5b8deb71fa389f6563d80e73be8b043ec77d4c9b06f9a586117c7f957f4af0331cbc871 +b6c90961f68b5e385d85c9830ec765d22a425f506904c4d506b87d8944c2b2c09615e740ed351df0f9321a7b93979cae +a6ec5ea80c7558403485b3b1869cdc63bde239bafdf936d9b62a37031628402a36a2cfa5cfbb8e26ac922cb0a209b3ba +8c3195bbdbf9bc0fc95fa7e3d7f739353c947f7767d1e3cb24d8c8602d8ea0a1790ac30b815be2a2ba26caa5227891e2 +a7f8a63d809f1155722c57f375ea00412b00147776ae4444f342550279ef4415450d6f400000a326bf11fea6c77bf941 +97fa404df48433a00c85793440e89bb1af44c7267588ae937a1f5d53e01e1c4d4fc8e4a6d517f3978bfdd6c2dfde012f +a984a0a3836de3d8d909c4629a2636aacb85393f6f214a2ef68860081e9db05ad608024762db0dc35e895dc00e2d4cdd +9526cf088ab90335add1db4d3a4ac631b58cbfbe88fa0845a877d33247d1cfeb85994522e1eb8f8874651bfb1df03e2a +ac83443fd0afe99ad49de9bf8230158c118e2814c9c89db5ac951c240d6c2ce45e7677221279d9e97848ec466b99aafe +aeeefdbaba612e971697798ceaf63b247949dc823a0ad771ae5b988a5e882b338a98d3d0796230f49d533ec5ba411b39 +ae3f248b5a7b0f92b7820a6c5ae21e5bd8f4265d4f6e21a22512079b8ee9be06393fd3133ce8ebac0faf23f4f8517e36 +a64a831b908eee784b8388b45447d2885ec0551b26b0c2b15e5f417d0a12c79e867fb7bd3d008d0af98b44336f8ec1ad +b242238cd8362b6e440ba21806905714dd55172db25ec7195f3fc4937b2aba146d5cbf3cf691a1384b4752dc3b54d627 +819f97f337eea1ffb2a678cc25f556f1aab751c6b048993a1d430fe1a3ddd8bb411c152e12ca60ec6e057c190cd1db9a +b9d7d187407380df54ee9fef224c54eec1bfabf17dc8abf60765b7951f538f59aa26fffd5846cfe05546c35f59b573f4 +aa6e3c14efa6a5962812e3f94f8ce673a433f4a82d07a67577285ea0eaa07f8be7115853122d12d6d4e1fdf64c504be1 +82268bee9c1662d3ddb5fb785abfae6fb8b774190f30267f1d47091d2cd4b3874db4372625aa36c32f27b0eee986269b +b236459565b7b966166c4a35b2fa71030b40321821b8e96879d95f0e83a0baf33fa25721f30af4a631df209e25b96061 +8708d752632d2435d2d5b1db4ad1fa2558d776a013655f88e9a3556d86b71976e7dfe5b8834fdec97682cd94560d0d0d +ae1424a68ae2dbfb0f01211f11773732a50510b5585c1fb005cb892b2c6a58f4a55490b5c5b4483c6fce40e9d3236a52 +b3f5f722af9dddb07293c871ce97abbccba0093ca98c8d74b1318fa21396fc1b45b69c15084f63d728f9908442024506 +9606f3ce5e63886853ca476dc0949e7f1051889d529365c0cb0296fdc02abd088f0f0318ecd2cf36740a3634132d36f6 +b11a833a49fa138db46b25ff8cdda665295226595bc212c0931b4931d0a55c99da972c12b4ef753f7e37c6332356e350 +afede34e7dab0a9e074bc19a7daddb27df65735581ca24ad70c891c98b1349fcebbcf3ba6b32c2617fe06a5818dabc2d +97993d456e459e66322d01f8eb13918979761c3e8590910453944bdff90b24091bb018ac6499792515c9923be289f99f +977e3e967eff19290a192cd11df3667d511b398fb3ac9a5114a0f3707e25a0edcb56105648b1b85a8b7519fc529fc6f6 +b873a7c88bf58731fe1bf61ff6828bf114cf5228f254083304a4570e854e83748fc98683ddba62d978fff7909f2c5c47 +ad4b2691f6f19da1d123aaa23cca3e876247ed9a4ab23c599afdbc0d3aa49776442a7ceaa996ac550d0313d9b9a36cee +b9210713c78e19685608c6475bfa974b57ac276808a443f8b280945c5d5f9c39da43effa294bfb1a6c6f7b6b9f85bf6c +a65152f376113e61a0e468759de38d742caa260291b4753391ee408dea55927af08a4d4a9918600a3bdf1df462dffe76 +8bf8c27ad5140dde7f3d2280fd4cc6b29ab76537e8d7aa7011a9d2796ee3e56e9a60c27b5c2da6c5e14fc866301dc195 +92fde8effc9f61393a2771155812b863cff2a0c5423d7d40aa04d621d396b44af94ddd376c28e7d2f53c930aea947484 +97a01d1dd9ee30553ce676011aea97fa93d55038ada95f0057d2362ae9437f3ed13de8290e2ff21e3167dd7ba10b9c3f +89affffaa63cb2df3490f76f0d1e1d6ca35c221dd34057176ba739fa18d492355e6d2a5a5ad93a136d3b1fed0bb8aa19 +928b8e255a77e1f0495c86d3c63b83677b4561a5fcbbe5d3210f1e0fc947496e426d6bf3b49394a5df796c9f25673fc4 +842a0af91799c9b533e79ee081efe2a634cac6c584c2f054fb7d1db67dde90ae36de36cbf712ec9cd1a0c7ee79e151ea +a65b946cf637e090baf2107c9a42f354b390e7316beb8913638130dbc67c918926eb87bec3b1fe92ef72bc77a170fa3b +aafc0f19bfd71ab5ae4a8510c7861458b70ad062a44107b1b1dbacbfa44ba3217028c2824bd7058e2fa32455f624040b +95269dc787653814e0be899c95dba8cfa384f575a25e671c0806fd80816ad6797dc819d30ae06e1d0ed9cb01c3950d47 +a1e760f7fa5775a1b2964b719ff961a92083c5c617f637fc46e0c9c20ab233f8686f7f38c3cb27d825c54dd95e93a59b +ac3b8a7c2317ea967f229eddc3e23e279427f665c4705c7532ed33443f1243d33453c1088f57088d2ab1e3df690a9cc9 +b787beeddfbfe36dd51ec4efd9cf83e59e84d354c3353cc9c447be53ae53d366ed1c59b686e52a92f002142c8652bfe0 +b7a64198300cb6716aa7ac6b25621f8bdec46ad5c07a27e165b3f774cdf65bcfdbf31e9bae0c16b44de4b00ada7a4244 +b8ae9f1452909e0c412c7a7fe075027691ea8df1347f65a5507bc8848f1d2c833d69748076db1129e5b4fb912f65c86c +9682e41872456b9fa67def89e71f06d362d6c8ca85c9c48536615bc401442711e1c9803f10ab7f8ab5feaec0f9df20a6 +88889ff4e271dc1c7e21989cc39f73cde2f0475acd98078281591ff6c944fadeb9954e72334319050205d745d4df73df +8f79b5b8159e7fd0d93b0645f3c416464f39aec353b57d99ecf24f96272df8a068ad67a6c90c78d82c63b40bb73989bb +838c01a009a3d8558a3f0bdd5e22de21af71ca1aefc8423c91dc577d50920e9516880e87dce3e6d086e11cd45c9052d9 +b97f1c6eee8a78f137c840667cc288256e39294268a3009419298a04a1d0087c9c9077b33c917c65caf76637702dda8a +972284ce72f96a61c899260203dfa06fc3268981732bef74060641c1a5068ead723e3399431c247ca034b0dae861e8df +945a8d52d6d3db6663dbd3110c6587f9e9c44132045eeffba15621576d178315cb52870fa5861669f84f0bee646183fe +a0a547b5f0967b1c3e5ec6c6a9a99f0578521489180dfdfbb5561f4d166baac43a2f06f950f645ce991664e167537eed +a0592cda5cdddf1340033a745fd13a6eff2021f2e26587116c61c60edead067e0f217bc2bef4172a3c9839b0b978ab35 +b9c223b65a3281587fa44ec829e609154b32f801fd1de6950e01eafb07a8324243b960d5735288d0f89f0078b2c42b5b +99ebfc3b8f9f98249f4d37a0023149ed85edd7a5abe062c8fb30c8c84555258b998bdcdd1d400bc0fa2a4aaa8b224466 +955b68526e6cb3937b26843270f4e60f9c6c8ece2fa9308fe3e23afa433309c068c66a4bc16ee2cf04220f095e9afce4 +b766caeafcc00378135ae53397f8a67ed586f5e30795462c4a35853de6681b1f17401a1c40958de32b197c083b7279c1 +921bf87cad947c2c33fa596d819423c10337a76fe5a63813c0a9dc78a728207ae7b339407a402fc4d0f7cba3af6da6fc +a74ba1f3bc3e6c025db411308f49b347ec91da1c916bda9da61e510ec8d71d25e0ac0f124811b7860e5204f93099af27 +a29b4d144e0bf17a7e8353f2824cef0ce85621396babe8a0b873ca1e8a5f8d508b87866cf86da348470649fceefd735c +a8040e12ffc3480dd83a349d06741d1572ef91932c46f5cf03aee8454254156ee95786fd013d5654725e674c920cec32 +8c4cf34ca60afd33923f219ffed054f90cd3f253ffeb2204a3b61b0183417e366c16c07fae860e362b0f2bfe3e1a1d35 +8195eede4ddb1c950459df6c396b2e99d83059f282b420acc34220cadeed16ab65c856f2c52568d86d3c682818ed7b37 +91fff19e54c15932260aa990c7fcb3c3c3da94845cc5aa8740ef56cf9f58d19b4c3c55596f8d6c877f9f4d22921d93aa +a3e0bf7e5d02a80b75cf75f2db7e66cb625250c45436e3c136d86297d652590ec97c2311bafe407ad357c79ab29d107b +81917ff87e5ed2ae4656b481a63ced9e6e5ff653b8aa6b7986911b8bc1ee5b8ef4f4d7882c3f250f2238e141b227e510 +915fdbe5e7de09c66c0416ae14a8750db9412e11dc576cf6158755fdcaf67abdbf0fa79b554cac4fe91c4ec245be073f +8df27eafb5c3996ba4dc5773c1a45ca77e626b52e454dc1c4058aa94c2067c18332280630cc3d364821ee53bf2b8c130 +934f8a17c5cbb827d7868f5c8ca00cb027728a841000a16a3428ab16aa28733f16b52f58c9c4fbf75ccc45df72d9c4df +b83f4da811f9183c25de8958bc73b504cf790e0f357cbe74ef696efa7aca97ad3b7ead1faf76e9f982c65b6a4d888fc2 +87188213c8b5c268dc2b6da413f0501c95749e953791b727450af3e43714149c115b596b33b63a2f006a1a271b87efd0 +83e9e888ab9c3e30761de635d9aabd31248cdd92f7675fc43e4b21fd96a03ec1dc4ad2ec94fec857ffb52683ac98e360 +b4b9a1823fe2d983dc4ec4e3aaea297e581c3fc5ab4b4af5fa1370caa37af2d1cc7fc6bfc5e7da60ad8fdce27dfe4b24 +856388bc78aef465dbcdd1f559252e028c9e9a2225c37d645c138e78f008f764124522705822a61326a6d1c79781e189 +a6431b36db93c3b47353ba22e7c9592c9cdfb9cbdd052ecf2cc3793f5b60c1e89bc96e6bae117bfd047f2308da00dd2f +b619972d48e7e4291542dcde08f7a9cdc883c892986ded2f23ccb216e245cd8d9ad1d285347b0f9d7611d63bf4cee2bc +8845cca6ff8595955f37440232f8e61d5351500bd016dfadd182b9d39544db77a62f4e0102ff74dd4173ae2c181d24ef +b2f5f7fa26dcd3b6550879520172db2d64ee6aaa213cbef1a12befbce03f0973a22eb4e5d7b977f466ac2bf8323dcedd +858b7f7e2d44bdf5235841164aa8b4f3d33934e8cb122794d90e0c1cac726417b220529e4f896d7b77902ab0ccd35b3a +80b0408a092dae2b287a5e32ea1ad52b78b10e9c12f49282976cd738f5d834e03d1ad59b09c5ccaccc39818b87d06092 +b996b0a9c6a2d14d984edcd6ab56bc941674102980d65b3ad9733455f49473d3f587c8cbf661228a7e125ddbe07e3198 +90224fcebb36865293bd63af786e0c5ade6b67c4938d77eb0cbae730d514fdd0fe2d6632788e858afd29d46310cf86df +b71351fdfff7168b0a5ec48397ecc27ac36657a8033d9981e97002dcca0303e3715ce6dd3f39423bc8ef286fa2e9e669 +ae2a3f078b89fb753ce4ed87e0c1a58bb19b4f0cfb6586dedb9fcab99d097d659a489fb40e14651741e1375cfc4b6c5f +8ef476b118e0b868caed297c161f4231bbeb863cdfa5e2eaa0fc6b6669425ce7af50dc374abceac154c287de50c22307 +92e46ab472c56cfc6458955270d3c72b7bde563bb32f7d4ab4d959db6f885764a3d864e1aa19802fefaa5e16b0cb0b54 +96a3f68323d1c94e73d5938a18a377af31b782f56212de3f489d22bc289cf24793a95b37f1d6776edf88114b5c1fa695 +962cc068cfce6faaa27213c4e43e44eeff0dfbb6d25b814e82c7da981fb81d7d91868fa2344f05fb552362f98cfd4a72 +895d4e4c4ad670abf66d43d59675b1add7afad7438ada8f42a0360c704cee2060f9ac15b4d27e9b9d0996bb801276fe3 +b3ad18d7ece71f89f2ef749b853c45dc56bf1c796250024b39a1e91ed11ca32713864049c9aaaea60cde309b47486bbf +8f05404e0c0258fdbae50e97ccb9b72ee17e0bd2400d9102c0dad981dac8c4c71585f03e9b5d50086d0a2d3334cb55d1 +8bd877e9d4591d02c63c6f9fc9976c109de2d0d2df2bfa5f6a3232bab5b0b8b46e255679520480c2d7a318545efa1245 +8d4c16b5d98957c9da13d3f36c46f176e64e5be879f22be3179a2c0e624fe4758a82bf8c8027410002f973a3b84cd55a +86e2a8dea86427b424fa8eada881bdff896907084a495546e66556cbdf070b78ba312bf441eb1be6a80006d25d5097a3 +8608b0c117fd8652fdab0495b08fadbeba95d9c37068e570de6fddfef1ba4a1773b42ac2be212836141d1bdcdef11a17 +a13d6febf5fb993ae76cae08423ca28da8b818d6ef0fde32976a4db57839cd45b085026b28ee5795f10a9a8e3098c683 +8e261967fa6de96f00bc94a199d7f72896a6ad8a7bbb1d6187cca8fad824e522880e20f766620f4f7e191c53321d70f9 +8b8e8972ac0218d7e3d922c734302803878ad508ca19f5f012bc047babd8a5c5a53deb5fe7c15a4c00fd6d1cb9b1dbd0 +b5616b233fb3574a2717d125a434a2682ff68546dccf116dd8a3b750a096982f185614b9fb6c7678107ff40a451f56fa +aa6adf9b0c3334b0d0663f583a4914523b2ac2e7adffdb026ab9109295ff6af003ef8357026dbcf789896d2afded8d73 +acb72df56a0b65496cd534448ed4f62950bb1e11e50873b6ed349c088ee364441821294ce0f7c61bd7d38105bea3b442 +abae12df83e01ec947249fedd0115dc501d2b03ff7232092979eda531dbbca29ace1d46923427c7dde4c17bdf3fd7708 +820b4fc2b63a9fda7964acf5caf19a2fc4965007cb6d6b511fcafcb1f71c3f673a1c0791d3f86e3a9a1eb6955b191cc0 +af277259d78c6b0f4f030a10c53577555df5e83319ddbad91afbd7c30bc58e7671c56d00d66ec3ab5ef56470cd910cee +ad4a861c59f1f5ca1beedd488fb3d131dea924fffd8e038741a1a7371fad7370ca5cf80dc01f177fbb9576713bb9a5b3 +b67a5162982ce6a55ccfb2f177b1ec26b110043cf18abd6a6c451cf140b5af2d634591eb4f28ad92177d8c7e5cd0a5e8 +96176d0a83816330187798072d449cbfccff682561e668faf6b1220c9a6535b32a6e4f852e8abb00f79abb87493df16b +b0afe6e7cb672e18f0206e4423f51f8bd0017bf464c4b186d46332c5a5847647f89ff7fa4801a41c1b0b42f6135bcc92 +8fc5e7a95ef20c1278c645892811f6fe3f15c431ebc998a32ec0da44e7213ea934ed2be65239f3f49b8ec471e9914160 +b7793e41adda6c82ba1f2a31f656f6205f65bf8a3d50d836ee631bc7ce77c153345a2d0fc5c60edf8b37457c3729c4ec +a504dd7e4d6b2f4379f22cc867c65535079c75ccc575955f961677fa63ecb9f74026fa2f60c9fb6323c1699259e5e9c8 +ab899d00ae693649cc1afdf30fb80d728973d2177c006e428bf61c7be01e183866614e05410041bc82cb14a33330e69c +8a3bd8b0b1be570b65c4432a0f6dc42f48a2000e30ab089cf781d38f4090467b54f79c0d472fcbf18ef6a00df69cc6f3 +b4d7028f7f76a96a3d7803fca7f507ae11a77c5346e9cdfccb120a833a59bda1f4264e425aa588e7a16f8e7638061d84 +b9c7511a76ea5fb105de905d44b02edb17008335766ee357ed386b7b3cf19640a98b38785cb14603c1192bee5886c9b6 +8563afb12e53aed71ac7103ab8602bfa8371ae095207cb0d59e8fd389b6ad1aff0641147e53cb6a7ca16c7f37c9c5e6b +8e108be614604e09974a9ed90960c28c4ea330a3d9a0cb4af6dd6f193f84ab282b243ecdf549b3131036bebc8905690c +b794d127fbedb9c5b58e31822361706ffac55ce023fbfe55716c3c48c2fd2f2c7660a67346864dfe588812d369cb50b6 +b797a3442fc3b44f41baefd30346f9ac7f96e770d010d53c146ce74ce424c10fb62758b7e108b8abfdc5fafd89d745cb +993bb71e031e8096442e6205625e1bfddfe6dd6a83a81f3e2f84fafa9e5082ab4cad80a099f21eff2e81c83457c725c3 +8711ab833fc03e37acf2e1e74cfd9133b101ff4144fe30260654398ae48912ab46549d552eb9d15d2ea57760d35ac62e +b21321fd2a12083863a1576c5930e1aecb330391ef83326d9d92e1f6f0d066d1394519284ddab55b2cb77417d4b0292f +877d98f731ffe3ee94b0b5b72d127630fa8a96f6ca4f913d2aa581f67732df6709493693053b3e22b0181632ac6c1e3b +ae391c12e0eb8c145103c62ea64f41345973311c3bf7281fa6bf9b7faafac87bcf0998e5649b9ef81e288c369c827e07 +b83a2842f36998890492ab1cd5a088d9423d192681b9a3a90ec518d4c541bce63e6c5f4df0f734f31fbfdd87785a2463 +a21b6a790011396e1569ec5b2a423857b9bec16f543e63af28024e116c1ea24a3b96e8e4c75c6537c3e4611fd265e896 +b4251a9c4aab3a495da7a42e684ba4860dbcf940ad1da4b6d5ec46050cbe8dab0ab9ae6b63b5879de97b905723a41576 +8222f70aebfe6ac037f8543a08498f4cadb3edaac00336fc00437eb09f2cba758f6c38e887cc634b4d5b7112b6334836 +86f05038e060594c46b5d94621a1d9620aa8ba59a6995baf448734e21f58e23c1ea2993d3002ad5250d6edd5ba59b34f +a7c0c749baef811ab31b973c39ceb1d94750e2bc559c90dc5eeb20d8bb6b78586a2b363c599ba2107d6be65cd435f24e +861d46a5d70b38d6c1cd72817a2813803d9f34c00320c8b62f8b9deb67f5b5687bc0b37c16d28fd017367b92e05da9ca +b3365d3dab639bffbe38e35383686a435c8c88b397b717cd4aeced2772ea1053ceb670f811f883f4e02975e5f1c4ac58 +a5750285f61ab8f64cd771f6466e2c0395e01b692fd878f2ef2d5c78bdd8212a73a3b1dfa5e4c8d9e1afda7c84857d3b +835a10809ccf939bc46cf950a33b36d71be418774f51861f1cd98a016ade30f289114a88225a2c11e771b8b346cbe6ef +a4f59473a037077181a0a62f1856ec271028546ca9452b45cedfcb229d0f4d1aabfc13062b07e536cc8a0d4b113156a2 +95cd14802180b224d44a73cc1ed599d6c4ca62ddcaa503513ccdc80aaa8be050cc98bd4b4f3b639549beb4587ac6caf9 +973b731992a3e69996253d7f36dd7a0af1982b5ed21624b77a7965d69e9a377b010d6dabf88a8a97eec2a476259859cc +af8a1655d6f9c78c8eb9a95051aa3baaf9c811adf0ae8c944a8d3fcba87b15f61021f3baf6996fa0aa51c81b3cb69de1 +835aad5c56872d2a2d6c252507b85dd742bf9b8c211ccb6b25b52d15c07245b6d89b2a40f722aeb5083a47cca159c947 +abf4e970b02bef8a102df983e22e97e2541dd3650b46e26be9ee394a3ea8b577019331857241d3d12b41d4eacd29a3ac +a13c32449dbedf158721c13db9539ae076a6ce5aeaf68491e90e6ad4e20e20d1cdcc4a89ed9fd49cb8c0dd50c17633c1 +8c8f78f88b7e22dd7e9150ab1c000f10c28e696e21d85d6469a6fe315254740f32e73d81ab1f3c1cf8f544c86df506e8 +b4b77f2acfe945abf81f2605f906c10b88fb4d28628487fb4feb3a09f17f28e9780445dfcee4878349d4c6387a9d17d4 +8d255c235f3812c6ecc646f855fa3832be5cb4dbb9c9e544989fafdf3f69f05bfd370732eaf954012f0044aa013fc9c6 +b982efd3f34b47df37c910148ac56a84e8116647bea24145a49e34e0a6c0176e3284d838dae6230cb40d0be91c078b85 +983f365aa09bd85df2a6a2ad8e4318996b1e27d02090755391d4486144e40d80b1fbfe1c798d626db92f52e33aa634da +95fd1981271f3ea3a41d654cf497e6696730d9ff7369f26bc4d7d15c7adb4823dd0c42e4a005a810af12d234065e5390 +a9f5219bd4b913c186ef30c02f995a08f0f6f1462614ea5f236964e02bdaa33db9d9b816c4aee5829947840a9a07ba60 +9210e6ceb05c09b46fd09d036287ca33c45124ab86315e5d6911ff89054f1101faaa3e83d123b7805056d388bcec6664 +8ed9cbf69c6ff3a5c62dd9fe0d7264578c0f826a29e614bc2fb4d621d90c8c9992438accdd7a614b1dca5d1bb73dc315 +85cf2a8cca93e00da459e3cecd22c342d697eee13c74d5851634844fc215f60053cf84b0e03c327cb395f48d1c71a8a4 +8818a18e9a2ec90a271b784400c1903089ffb0e0b40bc5abbbe12fbebe0f731f91959d98c5519ef1694543e31e2016d4 +8dabc130f296fa7a82870bf9a8405aaf542b222ed9276bba9bd3c3555a0f473acb97d655ee7280baff766a827a8993f0 +ac7952b84b0dc60c4d858f034093b4d322c35959605a3dad2b806af9813a4680cb038c6d7f4485b4d6b2ff502aaeca25 +ad65cb6d57b48a2602568d2ec8010baed0eb440eec7638c5ec8f02687d764e9de5b5d42ad5582934e592b48471c22d26 +a02ab8bd4c3d114ea23aebdd880952f9495912817da8c0c08eabc4e6755439899d635034413d51134c72a6320f807f1c +8319567764b8295402ec1ebef4c2930a138480b37e6d7d01c8b4c9cd1f2fc3f6e9a44ae6e380a0c469b25b06db23305f +afec53b2301dc0caa8034cd9daef78c48905e6068d692ca23d589b84a6fa9ddc2ed24a39480597e19cb3e83eec213b3f +ac0b4ffdb5ae08e586a9cdb98f9fe56f4712af3a97065e89e274feacfb52b53c839565aee93c4cfaaccfe51432c4fab0 +8972cbf07a738549205b1094c5987818124144bf187bc0a85287c94fdb22ce038c0f11df1aa16ec5992e91b44d1af793 +b7267aa6f9e3de864179b7da30319f1d4cb2a3560f2ea980254775963f1523b44c680f917095879bebfa3dc2b603efcf +80f68f4bfc337952e29504ee5149f15093824ea7ab02507efd1317a670f6cbc3611201848560312e3e52e9d9af72eccf +8897fee93ce8fc1e1122e46b6d640bba309384dbd92e46e185e6364aa8210ebf5f9ee7e5e604b6ffba99aa80a10dd7d0 +b58ea6c02f2360be60595223d692e82ee64874fda41a9f75930f7d28586f89be34b1083e03bbc1575bbfdda2d30db1ea +85a523a33d903280d70ac5938770453a58293480170c84926457ac2df45c10d5ff34322ab130ef4a38c916e70d81af53 +a2cbf045e1bed38937492c1f2f93a5ba41875f1f262291914bc1fc40c60bd0740fb3fea428faf6da38b7c180fe8ac109 +8c09328770ed8eb17afc6ac7ddd87bb476de18ed63cab80027234a605806895959990c47bd10d259d7f3e2ecb50074c9 +b4b9e19edb4a33bde8b7289956568a5b6b6557404e0a34584b5721fe6f564821091013fbb158e2858c6d398293bb4b59 +8a47377df61733a2aa5a0e945fce00267f8e950f37e109d4487d92d878fb8b573317bb382d902de515b544e9e233458d +b5804c9d97efeff5ca94f3689b8088c62422d92a1506fd1d8d3b1b30e8a866ad0d6dad4abfa051dfc4471250cac4c5d9 +9084a6ee8ec22d4881e9dcc8a9eb3c2513523d8bc141942370fd191ad2601bf9537a0b1e84316f3209b3d8a54368051e +85447eea2fa26656a649f8519fa67279183044791d61cf8563d0783d46d747d96af31d0a93507bbb2242666aa87d3720 +97566a84481027b60116c751aec552adfff2d9038e68d48c4db9811fb0cbfdb3f1d91fc176a0b0d988a765f8a020bce1 +ae87e5c1b9e86c49a23dceda4ecfd1dcf08567f1db8e5b6ec752ebd45433c11e7da4988573cdaebbb6f4135814fc059e +abee05cf9abdbc52897ac1ce9ed157f5466ed6c383d6497de28616238d60409e5e92619e528af8b62cc552bf09970dc2 +ae6d31cd7bf9599e5ee0828bab00ceb4856d829bba967278a73706b5f388465367aa8a6c7da24b5e5f1fdd3256ef8e63 +ac33e7b1ee47e1ee4af472e37ab9e9175260e506a4e5ce449788075da1b53c44cb035f3792d1eea2aa24b1f688cc6ed3 +80f65b205666b0e089bb62152251c48c380a831e5f277f11f3ef4f0d52533f0851c1b612267042802f019ec900dc0e8f +858520ad7aa1c9fed738e3b583c84168f2927837ad0e1d326afe9935c26e9b473d7f8c382e82ef1fe37d2b39bb40a1ee +b842dd4af8befe00a97c2d0f0c33c93974761e2cb9e5ab8331b25170318ddd5e4bdbc02d8f90cbfdd5f348f4f371c1f7 +8bf2cb79bc783cb57088aae7363320cbeaabd078ffdec9d41bc74ff49e0043d0dad0086a30e5112b689fd2f5a606365d +982eb03bbe563e8850847cd37e6a3306d298ab08c4d63ab6334e6b8c1fa13fce80cf2693b09714c7621d74261a0ff306 +b143edb113dec9f1e5105d4a93fbe502b859e587640d3db2f628c09a17060e6aec9e900e2c8c411cda99bc301ff96625 +af472d9befa750dcebc5428fe1a024f18ec1c07bca0f95643ce6b5f4189892a910285afb03fd7ed7068fbe614e80d33c +a97e3bc57ede73ecd1bbf02de8f51b4e7c1a067da68a3cd719f4ba26a0156cbf1cef2169fd35a18c5a4cced50d475998 +a862253c937cf3d75d7183e5f5be6a4385d526aeda5171c1c60a8381fea79f88f5f52a4fab244ecc70765d5765e6dfd5 +90cb776f8e5a108f1719df4a355bebb04bf023349356382cae55991b31720f0fd03206b895fa10c56c98f52453be8778 +a7614e8d0769dccd520ea4b46f7646e12489951efaef5176bc889e9eb65f6e31758df136b5bf1e9107e68472fa9b46ec +ac3a9b80a3254c42e5ed3a090a0dd7aee2352f480de96ad187027a3bb6c791eddfc3074b6ffd74eea825188f107cda4d +82a01d0168238ef04180d4b6e0a0e39024c02c2d75b065017c2928039e154d093e1af4503f4d1f3d8a948917abb5d09f +8fab000a2b0eef851a483aec8d2dd85fe60504794411a2f73ed82e116960547ac58766cb73df71aea71079302630258d +872451a35c6db61c63e9b8bb9f16b217f985c20be4451c14282c814adb29d7fb13f201367c664435c7f1d4d9375d7a58 +887d9ff54cc96b35d562df4a537ff972d7c4b3fd91ab06354969a4cfede0b9fc68bbffb61d0dbf1a58948dc701e54f5a +8cb5c2a6bd956875d88f41ae24574434f1308514d44057b55c9c70f13a3366ed054150eed0955a38fda3f757be73d55f +89ad0163cad93e24129d63f8e38422b7674632a8d0a9016ee8636184cab177659a676c4ee7efba3abe1a68807c656d60 +b9ec01c7cab6d00359b5a0b4a1573467d09476e05ca51a9227cd16b589a9943d161eef62dcc73f0de2ec504d81f4d252 +8031d17635d39dfe9705c485d2c94830b6fc9bc67b91300d9d2591b51e36a782e77ab5904662effa9382d9cca201f525 +8be5a5f6bc8d680e5092d6f9a6585acbaaaa2ddc671da560dcf5cfa4472f4f184b9597b5b539438accd40dda885687cc +b1fc0f052fae038a2e3de3b3a96b0a1024b009de8457b8b3adb2d315ae68a89af905720108a30038e5ab8d0d97087785 +8b8bdc77bd3a6bc7ca5492b6f8c614852c39a70d6c8a74916eaca0aeb4533b11898b8820a4c2620a97bf35e275480029 +af35f4dc538d4ad5cdf710caa38fd1eb496c3fa890a047b6a659619c5ad3054158371d1e88e0894428282eed9f47f76b +8166454a7089cc07758ad78724654f4e7a1a13e305bbf88ddb86f1a4b2904c4fc8ab872d7da364cdd6a6c0365239e2ad +ab287c7d3addce74ce40491871c768abe01daaa0833481276ff2e56926b38a7c6d2681ffe837d2cc323045ad1a4414f9 +b90317f4505793094d89365beb35537f55a6b5618904236258dd04ca61f21476837624a2f45fef8168acf732cab65579 +98ae5ea27448e236b6657ab5ef7b1cccb5372f92ab25f5fa651fbac97d08353a1dae1b280b1cd42b17d2c6a70a63ab9d +adcf54e752d32cbaa6cb98fbca48d8cd087b1db1d131d465705a0d8042c8393c8f4d26b59006eb50129b21e6240f0c06 +b591a3e4db18a7345fa935a8dd7994bbac5cc270b8ebd84c8304c44484c7a74afb45471fdbe4ab22156a30fae1149b40 +806b53ac049a42f1dcc1d6335505371da0bf27c614f441b03bbf2e356be7b2fb4eed7117eabcce9e427a542eaa2bf7d8 +800482e7a772d49210b81c4a907f5ce97f270b959e745621ee293cf8c71e8989363d61f66a98f2d16914439544ca84c7 +99de9eafdad3617445312341644f2bb888680ff01ce95ca9276b1d2e5ef83fa02dab5e948ebf66c17df0752f1bd37b70 +961ee30810aa4c93ae157fbe9009b8e443c082192bd36a73a6764ff9b2ad8b0948fe9a73344556e01399dd77badb4257 +ae0a361067c52efbe56c8adf982c00432cd478929459fc7f74052c8ee9531cd031fe1335418fde53f7c2ef34254eb7ac +a3503d16b6b27eb20c1b177bcf90d13706169220523a6271b85b2ce35a9a2b9c5bed088540031c0a4ebfdae3a4c6ab04 +909420122c3e723289ca4e7b81c2df5aff312972a2203f4c45821b176e7c862bf9cac7f7df3adf1d59278f02694d06e7 +989f42380ae904b982f85d0c6186c1aef5d6bcba29bcfbb658e811b587eb2749c65c6e4a8cc6409c229a107499a4f5d7 +8037a6337195c8e26a27ea4ef218c6e7d79a9720aaab43932d343192abc2320fe72955f5e431c109093bda074103330a +b312e168663842099b88445e940249cc508f080ab0c94331f672e7760258dbd86be5267e4cf25ea25facb80bff82a7e9 +aaa3ff8639496864fcdbfdda1ac97edc4f08e3c9288b768f6c8073038c9fbbf7e1c4bea169b4d45c31935cdf0680d45e +97dbd3df37f0b481a311dfc5f40e59227720f367912200d71908ef6650f32cc985cb05b981e3eea38958f7e48d10a15d +a89d49d1e267bb452d6cb621b9a90826fe55e9b489c0427b94442d02a16f390eed758e209991687f73f6b5a032321f42 +9530dea4e0e19d6496f536f2e75cf7d814d65fde567055eb20db48fd8d20d501cd2a22fb506db566b94c9ee10f413d43 +81a7009b9e67f1965fa7da6a57591c307de91bf0cd35ab4348dc4a98a4961e096d004d7e7ad318000011dc4342c1b809 +83440a9402b766045d7aca61a58bba2aa29cac1cf718199e472ba086f5d48093d9dda4d135292ba51d049a23964eceae +a06c9ce5e802df14f6b064a3d1a0735d429b452f0e2e276042800b0a4f16df988fd94cf3945921d5dd3802ab2636f867 +b1359e358b89936dee9e678a187aad3e9ab14ac40e96a0a68f70ee2583cdcf467ae03bef4215e92893f4e12f902adec8 +835304f8619188b4d14674d803103d5a3fa594d48e96d9699e653115dd05fdc2dda6ba3641cf7ad53994d448da155f02 +8327cba5a9ff0d3f5cd0ae55e77167448926d5fcf76550c0ad978092a14122723090c51c415e88e42a2b62eb07cc3981 +b373dcdaea85f85ce9978b1426a7ef4945f65f2d3467a9f1cc551a99766aac95df4a09e2251d3f89ca8c9d1a7cfd7b0e +ab1422dc41af2a227b973a6fd124dfcb2367e2a11a21faa1d381d404f51b7257e5bc82e9cf20cd7fe37d7ae761a2ab37 +a93774a03519d2f20fdf2ef46547b0a5b77c137d6a3434b48d56a2cbef9e77120d1b85d0092cf8842909213826699477 +8eb967a495a38130ea28711580b7e61bcd1d051cd9e4f2dbf62f1380bd86e0d60e978d72f6f31e909eb97b3b9a2b867c +ae8213378da1287ba1fe4242e1acaec19b877b6fe872400013c6eac1084b8d03156792fa3020201725b08228a1e80f49 +b143daf6893d674d607772b3b02d8ac48f294237e2f2c87963c0d4e26d9227d94a2a13512457c3d5883544bbc259f0ef +b343bd2aca8973888e42542218924e2dda2e938fd1150d06878af76f777546213912b7c7a34a0f94186817d80ffa185c +b188ebc6a8c3007001aa347ae72cc0b15d09bc6c19a80e386ee4b334734ec0cc2fe8b493c2422f38d1e6d133cc3db6fe +b795f6a8b9b826aaeee18ccd6baf6c5adeeec85f95eb5b6d19450085ec7217e95a2d9e221d77f583b297d0872073ba0e +b1c7dbd998ad32ae57bfa95deafa147024afd57389e98992c36b6e52df915d3d5a39db585141ec2423173e85d212fed8 +812bcdeb9fe5f12d0e1df9964798056e1f1c3de3b17b6bd2919b6356c4b86d8e763c01933efbe0224c86a96d5198a4be +b19ebeda61c23d255cbf472ef0b8a441f4c55b70f0d8ed47078c248b1d3c7c62e076b43b95c00a958ec8b16d5a7cb0d7 +b02adc9aaa20e0368a989c2af14ff48b67233d28ebee44ff3418bb0473592e6b681af1cc45450bd4b175df9051df63d9 +8d87f0714acee522eb58cec00360e762adc411901dba46adc9227124fa70ee679f9a47e91a6306d6030dd4eb8de2f3c1 +8be54cec21e74bcc71de29dc621444263737db15f16d0bb13670f64e42f818154e04b484593d19ef95f2ee17e4b3fe21 +ab8e20546c1db38d31493b5d5f535758afb17e459645c1b70813b1cf7d242fd5d1f4354a7c929e8f7259f6a25302e351 +89f035a1ed8a1e302ac893349ba8ddf967580fcb6e73d44af09e3929cde445e97ff60c87dafe489e2c0ab9c9986cfa00 +8b2b0851a795c19191a692af55f7e72ad2474efdc5401bc3733cfdd910e34c918aaebe69d5ea951bdddf3c01cabbfc67 +a4edb52c2b51495ccd1ee6450fc14b7b3ede8b3d106808929d02fb31475bacb403e112ba9c818d2857651e508b3a7dd1 +9569341fded45d19f00bcf3cbf3f20eb2b4d82ef92aba3c8abd95866398438a2387437e580d8b646f17cf6fde8c5af23 +aa4b671c6d20f72f2f18a939a6ff21cc37e0084b44b4a717f1be859a80b39fb1be026b3205adec2a66a608ec2bcd578f +94902e980de23c4de394ad8aec91b46f888d18f045753541492bfbb92c59d3daa8de37ae755a6853744af8472ba7b72b +af651ef1b2a0d30a7884557edfad95b6b5d445a7561caebdc46a485aedd25932c62c0798465c340a76f6feaa196dd712 +b7b669b8e5a763452128846dd46b530dca4893ace5cc5881c7ddcd3d45969d7e73fbebdb0e78aa81686e5f7b22ec5759 +82507fd4ebe9fa656a7f2e084d64a1fa6777a2b0bc106d686e2d9d2edafc58997e58cb6bfd0453b2bf415704aa82ae62 +b40bce2b42b88678400ecd52955bbdadd15f8b9e1b3751a1a3375dc0efb5ca3ee258cf201e1140b3c09ad41217d1d49e +b0210d0cbb3fbf3b8cdb39e862f036b0ff941cd838e7aaf3a8354e24246e64778d22f3de34572e6b2a580614fb6425be +876693cba4301b251523c7d034108831df3ce133d8be5a514e7a2ca494c268ca0556fa2ad8310a1d92a16b55bcd99ea9 +8660281406d22a4950f5ef050bf71dd3090edb16eff27fa29ef600cdea628315e2054211ed2cc6eaf8f2a1771ef689fd +a610e7e41e41ab66955b809ba4ade0330b8e9057d8efc9144753caed81995edeb1a42a53f93ce93540feca1fae708dac +a49e2c176a350251daef1218efaccc07a1e06203386ede59c136699d25ca5cb2ac1b800c25b28dd05678f14e78e51891 +83e0915aa2b09359604566080d411874af8c993beba97d4547782fdbe1a68e59324b800ff1f07b8db30c71adcbd102a8 +a19e84e3541fb6498e9bb8a099c495cbfcad113330e0262a7e4c6544495bb8a754b2208d0c2d895c93463558013a5a32 +87f2bd49859a364912023aca7b19a592c60214b8d6239e2be887ae80b69ebdeb59742bdebcfa73a586ab23b2c945586c +b8e8fdddae934a14b57bc274b8dcd0d45ebb95ddbaabef4454e0f6ce7d3a5a61c86181929546b3d60c447a15134d08e1 +87e0c31dcb736ea4604727e92dc1d9a3cf00adcff79df3546e02108355260f3dd171531c3c0f57be78d8b28058fcc8c0 +9617d74e8f808a4165a8ac2e30878c349e1c3d40972006f0787b31ea62d248c2d9f3fc3da83181c6e57e95feedfd0e8c +8949e2cee582a2f8db86e89785a6e46bc1565c2d8627d5b6bf43ba71ffadfab7e3c5710f88dcb5fb2fc6edf6f4fae216 +ad3fa7b0edceb83118972a2935a09f409d09a8db3869f30be3a76f67aa9fb379cabb3a3aff805ba023a331cad7d7eb64 +8c95718a4112512c4efbd496be38bf3ca6cdcaad8a0d128f32a3f9aae57f3a57bdf295a3b372a8c549fda8f4707cffed +88f3261d1e28a58b2dee3fcc799777ad1c0eb68b3560f9b4410d134672d9533532a91ea7be28a041784872632d3c9d80 +b47472a41d72dd2e8b72f5c4f8ad626737dde3717f63d6bc776639ab299e564cbad0a2ad5452a07f02ff49a359c437e5 +9896d21dc2e8aad87b76d6df1654f10cd7bceed4884159d50a818bea391f8e473e01e14684814c7780235f28e69dca6e +82d47c332bbd31bbe83b5eb44a23da76d4a7a06c45d7f80f395035822bc27f62f59281d5174e6f8e77cc9b5c3193d6f0 +95c74cd46206e7f70c9766117c34c0ec45c2b0f927a15ea167901a160e1530d8522943c29b61e03568aa0f9c55926c53 +a89d7757825ae73a6e81829ff788ea7b3d7409857b378ebccd7df73fdbe62c8d9073741cf038314971b39af6c29c9030 +8c1cd212d0b010905d560688cfc036ae6535bc334fa8b812519d810b7e7dcf1bb7c5f43deaa40f097158358987324a7f +b86993c383c015ed8d847c6b795164114dd3e9efd25143f509da318bfba89389ea72a420699e339423afd68b6512fafb +8d06bd379c6d87c6ed841d8c6e9d2d0de21653a073725ff74be1934301cc3a79b81ef6dd0aad4e7a9dc6eac9b73019bc +81af4d2d87219985b9b1202d724fe39ef988f14fef07dfe3c3b11714e90ffba2a97250838e8535eb63f107abfe645e96 +8c5e0af6330a8becb787e4b502f34f528ef5756e298a77dc0c7467433454347f3a2e0bd2641fbc2a45b95e231c6e1c02 +8e2a8f0f04562820dc8e7da681d5cad9fe2e85dd11c785fb6fba6786c57a857e0b3bd838fb849b0376c34ce1665e4837 +a39be8269449bfdfc61b1f62077033649f18dae9bef7c6163b9314ca8923691fb832f42776f0160b9e8abd4d143aa4e1 +8c154e665706355e1cc98e0a4cabf294ab019545ba9c4c399d666e6ec5c869ca9e1faf8fb06cd9c0a5c2f51a7d51b70a +a046a7d4de879d3ebd4284f08f24398e9e3bf006cd4e25b5c67273ade248689c69affff92ae810c07941e4904296a563 +afd94c1cb48758e5917804df03fb38a6da0e48cd9b6262413ea13b26973f9e266690a1b7d9d24bbaf7e82718e0e594b0 +859e21080310c8d6a38e12e2ac9f90a156578cdeb4bb2e324700e97d9a5511cd6045dc39d1d0de3f94aeed043a24119d +a219fb0303c379d0ab50893264919f598e753aac9065e1f23ef2949abc992577ab43c636a1d2c089203ec9ddb941e27d +b0fdb639d449588a2ca730afcba59334e7c387342d56defdfb7ef79c493f7fd0e5277eff18e7203e756c7bdda5803047 +87f9c3b7ed01f54368aca6dbcf2f6e06bff96e183c4b2c65f8baa23b377988863a0a125d5cdd41a072da8462ced4c070 +99ef7a5d5ac2f1c567160e1f8c95f2f38d41881850f30c461a205f7b1b9fb181277311333839b13fb3ae203447e17727 +aeaca9b1c2afd24e443326cc68de67b4d9cedb22ad7b501a799d30d39c85bb2ea910d4672673e39e154d699e12d9b3dc +a11675a1721a4ba24dd3d0e4c3c33a6edf4cd1b9f6b471070b4386c61f77452266eae6e3f566a40cfc885eada9a29f23 +b228334445e37b9b49cb4f2cc56b454575e92173ddb01370a553bba665adadd52df353ad74470d512561c2c3473c7bb9 +a18177087c996572d76f81178d18ed1ceebc8362a396348ce289f1d8bd708b9e99539be6fccd4acb1112381cfc5749b4 +8e7b8bf460f0d3c99abb19803b9e43422e91507a1c0c22b29ee8b2c52d1a384da4b87c292e28eff040db5be7b1f8641f +b03d038d813e29688b6e6f444eb56fec3abba64c3d6f890a6bcf2e916507091cdb2b9d2c7484617be6b26552ed1c56cb +a1c88ccd30e934adfc5494b72655f8afe1865a84196abfb376968f22ddc07761210b6a9fb7638f1413d1b4073d430290 +961b714faebf172ad2dbc11902461e286e4f24a99a939152a53406117767682a571057044decbeb3d3feef81f4488497 +a03dc4059b46effdd786a0a03cc17cfee8585683faa35bb07936ded3fa3f3a097f518c0b8e2db92fd700149db1937789 +adf60180c99ca574191cbcc23e8d025b2f931f98ca7dfcebfc380226239b6329347100fcb8b0fcb12db108c6ad101c07 +805d4f5ef24d46911cbf942f62cb84b0346e5e712284f82b0db223db26d51aabf43204755eb19519b00e665c7719fcaa +8dea7243e9c139662a7fe3526c6c601eee72fd8847c54c8e1f2ad93ef7f9e1826b170afe58817dac212427164a88e87f +a2ba42356606d651b077983de1ad643650997bb2babb188c9a3b27245bb65d2036e46667c37d4ce02cb1be5ae8547abe +af2ae50b392bdc013db2d12ce2544883472d72424fc767d3f5cb0ca2d973fc7d1f425880101e61970e1a988d0670c81b +98e6bec0568d3939b31d00eb1040e9b8b2a35db46ddf4369bdaee41bbb63cc84423d29ee510a170fb5b0e2df434ba589 +822ff3cd12fbef4f508f3ca813c04a2e0b9b799c99848e5ad3563265979e753ee61a48f6adc2984a850f1b46c1a43d35 +891e8b8b92a394f36653d55725ef514bd2e2a46840a0a2975c76c2a935577f85289026aaa74384da0afe26775cbddfb9 +b2a3131a5d2fe7c8967047aa66e4524babae941d90552171cc109527f345f42aa0df06dcbb2fa01b33d0043917bbed69 +80c869469900431f3eeefafdbe07b8afd8cee7739e659e6d0109b397cacff85a88247698f87dc4e2fe39a592f250ac64 +9091594f488b38f9d2bb5df49fd8b4f8829d9c2f11a197dd1431ed5abbc5c954bbde3387088f9ee3a5a834beb7619bce +b472e241e6956146cca57b97a8a204668d050423b4e76f857bad5b47f43b203a04c8391ba9d9c3e95093c071f9d376a1 +b7dd2de0284844392f7dfb56fe7ca3ede41e27519753ffc579a0a8d2d65ceb8108d06b6b0d4c3c1a2588951297bd1a1e +902116ce70d0a079ac190321c1f48701318c05f8e69ee09694754885d33a835a849cafe56f499a2f49f6cda413ddf9a7 +b18105cc736787fafaf7c3c11c448bce9466e683159dff52723b7951dff429565e466e4841d982e3aaa9ee2066838666 +97ab9911f3f659691762d568ae0b7faa1047b0aed1009c319fa79d15d0db8db9f808fc385dc9a68fa388c10224985379 +b2a2cba65f5b927e64d2904ba412e2bac1cf18c9c3eda9c72fb70262497ecf505b640827e2afebecf10eebbcf48ccd3e +b36a3fd677baa0d3ef0dac4f1548ff50a1730286b8c99d276a0a45d576e17b39b3cbadd2fe55e003796d370d4be43ce3 +a5dfec96ca3c272566e89dc453a458909247e3895d3e44831528130bc47cc9d0a0dac78dd3cad680a4351d399d241967 +8029382113909af6340959c3e61db27392531d62d90f92370a432aec3eb1e4c36ae1d4ef2ba8ec6edb4d7320c7a453f6 +971d85121ea108e6769d54f9c51299b0381ece8b51d46d49c89f65bedc123bab4d5a8bc14d6f67f4f680077529cbae4c +98ff6afc01d0bec80a278f25912e1b1ebff80117adae72e31d5b9fa4d9624db4ba2065b444df49b489b0607c45e26c4c +8fa29be10fb3ab30ce25920fec0187e6e91e458947009dabb869aade7136c8ba23602682b71e390c251f3743164cbdaa +b3345c89eb1653418fe3940cf3e56a9a9c66526389b98f45ca02dd62bfb37baa69a4baaa7132d7320695f8ea6ad1fd94 +b72c7f5541c9ac6b60a7ec9f5415e7fb14da03f7164ea529952a29399f3a071576608dbbcc0d45994f21f92ddbeb1e19 +aa3450bb155a5f9043d0ef95f546a2e6ade167280bfb75c9f09c6f9cdb1fffb7ce8181436161a538433afa3681c7a141 +92a18fecaded7854b349f441e7102b638ababa75b1b0281dd0bded6541abe7aa37d96693595be0b01fe0a2e2133d50f9 +980756ddf9d2253cfe6c94960b516c94889d09e612810935150892627d2ecee9a2517e04968eea295d0106850c04ca44 +ae68c6ccc454318cdd92f32b11d89116a3b8350207a36d22a0f626718cad671d960090e054c0c77ac3162ae180ecfd4b +99f31f66eaaa551749ad91d48a0d4e3ff4d82ef0e8b28f3184c54e852422ba1bdafd53b1e753f3a070f3b55f3c23b6a2 +a44eaeaa6589206069e9c0a45ff9fc51c68da38d4edff1d15529b7932e6f403d12b9387019c44a1488a5d5f27782a51f +b80b5d54d4b344840e45b79e621bd77a3f83fb4ce6d8796b7d6915107b3f3c34d2e7d95bdafd120f285669e5acf2437a +b36c069ec085a612b5908314d6b84c00a83031780261d1c77a0384c406867c9847d5b0845deddfa512cc04a8df2046fb +b09dbe501583220f640d201acea7ee3e39bf9eda8b91aa07b5c50b7641d86d71acb619b38d27835ce97c3759787f08e9 +87403d46a2bf63170fff0b857acacf42ee801afe9ccba8e5b4aea967b68eac73a499a65ca46906c2eb4c8f27bc739faa +82b93669f42a0a2aa5e250ffe6097269da06a9c02fcd1801abbad415a7729a64f830754bafc702e64600ba47671c2208 +8e3a3029be7edb8dd3ab1f8216664c8dc50d395f603736061d802cef77627db7b859ef287ed850382c13b4d22d6a2d80 +968e9ec7194ff424409d182ce0259acd950c384c163c04463bc8700a40b79beba6146d22b7fa7016875a249b7b31c602 +8b42c984bbe4996e0c20862059167c6bdc5164b1ffcd928f29512664459212d263e89f0f0e30eed4e672ffa5ed0b01b5 +96bac54062110dada905363211133f1f15dc7e4fd80a4c6e4a83bc9a0bcbbaba11cd2c7a13debcf0985e1a954c1da66b +a16dc8a653d67a7cd7ae90b2fffac0bf1ca587005430fe5ba9403edd70ca33e38ba5661d2ed6e9d2864400d997626a62 +a68ab11a570a27853c8d67e491591dcba746bfbee08a2e75ae0790399130d027ed387f41ef1d7de8df38b472df309161 +92532b74886874447c0300d07eda9bbe4b41ed25349a3da2e072a93fe32c89d280f740d8ff70d5816793d7f2b97373cc +88e35711b471e89218fd5f4d0eadea8a29405af1cd81974427bc4a5fb26ed60798daaf94f726c96e779b403a2cd82820 +b5c72aa4147c19f8c4f3a0a62d32315b0f4606e0a7025edc5445571eaf4daff64f4b7a585464821574dd50dbe1b49d08 +9305d9b4095258e79744338683fd93f9e657367b3ab32d78080e51d54eec331edbc224fad5093ebf8ee4bd4286757eb8 +b2a17abb3f6a05bcb14dc7b98321fa8b46d299626c73d7c6eb12140bf4c3f8e1795250870947af817834f033c88a59d6 +b3477004837dbd8ba594e4296f960fc91ab3f13551458445e6c232eb04b326da803c4d93e2e8dcd268b4413305ff84da +924b4b2ebaafdcfdfedb2829a8bf46cd32e1407d8d725a5bd28bdc821f1bafb3614f030ea4352c671076a63494275a3f +8b81b9ef6125c82a9bece6fdcb9888a767ac16e70527753428cc87c56a1236e437da8be4f7ecfe57b9296dc3ae7ba807 +906e19ec8b8edd58bdf9ae05610a86e4ea2282b1bbc1e8b00b7021d093194e0837d74cf27ac9916bdb8ec308b00da3da +b41c5185869071760ac786078a57a2ab4e2af60a890037ac0c0c28d6826f15c2cf028fddd42a9b6de632c3d550bfbc14 +a646e5dec1b713ae9dfdf7bdc6cd474d5731a320403c7dfcfd666ffc9ae0cff4b5a79530e8df3f4aa9cb80568cb138e9 +b0efad22827e562bd3c3e925acbd0d9425d19057868608d78c2209a531cccd0f2c43dc5673acf9822247428ffa2bb821 +a94c19468d14b6f99002fc52ac06bbe59e5c472e4a0cdb225144a62f8870b3f10593749df7a2de0bd3c9476ce682e148 +803864a91162f0273d49271dafaab632d93d494d1af935aefa522768af058fce52165018512e8d6774976d52bd797e22 +a08711c2f7d45c68fb340ac23597332e1bcaec9198f72967b9921204b9d48a7843561ff318f87908c05a44fc35e3cc9d +91c3cad94a11a3197ae4f9461faab91a669e0dddb0371d3cab3ed9aeb1267badc797d8375181130e461eadd05099b2a2 +81bdaaf48aae4f7b480fc13f1e7f4dd3023a41439ba231760409ce9292c11128ab2b0bdbbf28b98af4f97b3551f363af +8d60f9df9fd303f625af90e8272c4ecb95bb94e6efc5da17b8ab663ee3b3f673e9f6420d890ccc94acf4d2cae7a860d8 +a7b75901520c06e9495ab983f70b61483504c7ff2a0980c51115d11e0744683ce022d76e3e09f4e99e698cbd21432a0d +82956072df0586562fda7e7738226f694e1c73518dd86e0799d2e820d7f79233667192c9236dcb27637e4c65ef19d493 +a586beb9b6ffd06ad200957490803a7cd8c9bf76e782734e0f55e04a3dc38949de75dc607822ec405736c576cf83bca3 +a179a30d00def9b34a7e85607a447eea0401e32ab5abeee1a281f2acd1cf6ec81a178020666f641d9492b1bdf66f05a3 +83e129705c538787ed8e0fdc1275e6466a3f4ee21a1e6abedd239393b1df72244723b92f9d9d9339a0cab6ebf28f5a16 +811bd8d1e3722b64cd2f5b431167e7f91456e8bba2cc669d3fbbce7d553e29c3c19f629fcedd2498bc26d33a24891d17 +a243c030c858f1f60cccd26b45b024698cc6d9d9e6198c1ed4964a235d9f8d0baf9cde10c8e63dfaa47f8e74e51a6e85 +ab839eb82e23ca52663281f863b55b0a3d6d4425c33ffb4eeb1d7979488ab068bf99e2a60e82cea4dc42c56c26cbfebe +8b896f9bb21d49343e67aec6ad175b58c0c81a3ca73d44d113ae4354a0065d98eb1a5cafedaf232a2bb9cdc62152f309 +af6230340cc0b66f5bf845540ed4fc3e7d6077f361d60762e488d57834c3e7eb7eacc1b0ed73a7d134f174a01410e50c +88975e1b1af678d1b5179f72300a30900736af580dd748fd9461ef7afccc91ccd9bed33f9da55c8711a7635b800e831f +a97486bb9047391661718a54b8dd5a5e363964e495eae6c692730264478c927cf3e66dd3602413189a3699fbeae26e15 +a5973c161ab38732885d1d2785fd74bf156ba34881980cba27fe239caef06b24a533ffe6dbbbeca5e6566682cc00300a +a24776e9a840afda0003fa73b415d5bd6ecd9b5c2cc842b643ee51b8c6087f4eead4d0bfbd987eb174c489a7b952ff2a +a8a6ee06e3af053b705a12b59777267c546f33ba8a0f49493af8e6df4e15cf8dd2d4fb4daf7e84c6b5d3a7363118ff03 +a28e59ce6ad02c2ce725067c0123117e12ac5a52c8f5af13eec75f4a9efc4f696777db18a374fa33bcae82e0734ebd16 +86dfc3b78e841c708aff677baa8ee654c808e5d257158715097c1025d46ece94993efe12c9d188252ad98a1e0e331fec +a88d0275510f242eab11fdb0410ff6e1b9d7a3cbd3658333539815f1b450a84816e6613d15aa8a8eb15d87cdad4b27a2 +8440acea2931118a5b481268ff9f180ee4ede85d14a52c026adc882410825b8275caa44aff0b50c2b88d39f21b1a0696 +a7c3182eab25bd6785bacf12079d0afb0a9b165d6ed327814e2177148539f249eb9b5b2554538f54f3c882d37c0a8abe +85291fbe10538d7da38efdd55a7acebf03b1848428a2f664c3ce55367aece60039f4f320b1771c9c89a35941797f717c +a2c6414eeb1234728ab0de94aa98fc06433a58efa646ca3fcbd97dbfb8d98ae59f7ce6d528f669c8149e1e13266f69c9 +840c8462785591ee93aee2538d9f1ec44ba2ca61a569ab51d335ac873f5d48099ae8d7a7efa0725d9ff8f9475bfa4f56 +a7065a9d02fb3673acf7702a488fbc01aa69580964932f6f40b6c2d1c386b19e50b0e104fcac24ea26c4e723611d0238 +b72db6d141267438279e032c95e6106c2ccb3164b842ba857a2018f3a35f4b040da92680881eb17cd61d0920d5b8f006 +a8005d6c5960e090374747307ef0be2871a7a43fa4e76a16c35d2baab808e9777b496e9f57a4218b23390887c33a0b55 +8e152cea1e00a451ca47c20a1e8875873419700af15a5f38ee2268d3fbc974d4bd5f4be38008fa6f404dbdedd6e6e710 +a3391aed1fcd68761f06a7d1008ec62a09b1cb3d0203cd04e300a0c91adfed1812d8bc1e4a3fd7976dc0aae0e99f52f1 +967eb57bf2aa503ee0c6e67438098149eac305089c155f1762cf5e84e31f0fbf27c34a9af05621e34645c1ec96afaec8 +88af97ddc4937a95ec0dcd25e4173127260f91c8db2f6eac84afb789b363705fb3196235af631c70cafd09411d233589 +a32df75b3f2c921b8767638fd289bcfc61e08597170186637a7128ffedd52c798c434485ac2c7de07014f9e895c2c3d8 +b0a783832153650aa0d766a3a73ec208b6ce5caeb40b87177ffc035ab03c7705ecdd1090b6456a29f5fb7e90e2fa8930 +b59c8e803b4c3486777d15fc2311b97f9ded1602fa570c7b0200bada36a49ee9ef4d4c1474265af8e1c38a93eb66b18b +982f2c85f83e852022998ff91bafbb6ff093ef22cf9d5063e083a48b29175ccbd51b9c6557151409e439096300981a6c +939e3b5989fefebb9d272a954659a4eb125b98c9da6953f5e628d26266bd0525ec38304b8d56f08d65abc4d6da4a8dbb +8898212fe05bc8de7d18503cb84a1c1337cc2c09d1eeef2b475aa79185b7322bf1f8e065f1bf871c0c927dd19faf1f6d +94b0393a41cd00f724aee2d4bc72103d626a5aecb4b5486dd1ef8ac27528398edf56df9db5c3d238d8579af368afeb09 +96ac564450d998e7445dd2ea8e3fc7974d575508fa19e1c60c308d83b645864c029f2f6b7396d4ff4c1b24e92e3bac37 +8adf6638e18aff3eb3b47617da696eb6c4bdfbecbbc3c45d3d0ab0b12cbad00e462fdfbe0c35780d21aa973fc150285e +b53f94612f818571b5565bbb295e74bada9b5f9794b3b91125915e44d6ddcc4da25510eab718e251a09c99534d6042d9 +8b96462508d77ee083c376cd90807aebad8de96bca43983c84a4a6f196d5faf6619a2351f43bfeec101864c3bf255519 +aeadf34657083fc71df33bd44af73bf5281c9ca6d906b9c745536e1819ea90b56107c55e2178ebad08f3ba75b3f81c86 +9784ba29b2f0057b5af1d3ab2796d439b8753f1f749c73e791037461bdfc3f7097394283105b8ab01788ea5255a96710 +8756241bda159d4a33bf74faba0d4594d963c370fb6a18431f279b4a865b070b0547a6d1613cf45b8cfb5f9236bbf831 +b03ebfd6b71421dfd49a30460f9f57063eebfe31b9ceaa2a05c37c61522b35bdc09d7db3ad75c76c253c00ba282d3cd2 +b34e7e6341fa9d854b2d3153bdda0c4ae2b2f442ab7af6f99a0975d45725aa48e36ae5f7011edd249862e91f499687d4 +b462ee09dc3963a14354244313e3444de5cc37ea5ccfbf14cd9aca8027b59c4cb2a949bc30474497cab8123e768460e6 +aea753290e51e2f6a21a9a0ee67d3a2713f95c2a5c17fe41116c87d3aa77b1683761264d704df1ac34f8b873bc88ef7b +98430592afd414394f98ddfff9f280fcb1c322dbe3510f45e1e9c4bb8ee306b3e0cf0282c0ee73ebb8ba087d4d9e0858 +b95d3b5aaf54ffca11f4be8d57f76e14afdb20afc859dc7c7471e0b42031e8f3d461b726ecb979bdb2f353498dfe95ea +984d17f9b11a683132e0b5a9ee5945e3ff7054c2d5c716be73b29078db1d36f54c6e652fd2f52a19da313112e97ade07 +ab232f756b3fff3262be418a1af61a7e0c95ceebbc775389622a8e10610508cd6784ab7960441917a83cc191c58829ea +a28f41678d6e60de76b0e36ab10e4516e53e02e9c77d2b5af3cfeee3ce94cfa30c5797bd1daab20c98e1cad83ad0f633 +b55395fca84dd3ccc05dd480cb9b430bf8631ff06e24cb51d54519703d667268c2f8afcde4ba4ed16bece8cc7bc8c6e0 +8a8a5392a0e2ea3c7a8c51328fab11156004e84a9c63483b64e8f8ebf18a58b6ffa8fe8b9d95af0a2f655f601d096396 +ab480000fe194d23f08a7a9ec1c392334e9c687e06851f083845121ce502c06b54dda8c43092bcc1035df45cc752fe9b +b265644c29f628d1c7e8e25a5e845cabb21799371814730a41a363e1bda8a7be50fee7c3996a365b7fcba4642add10db +b8a915a3c685c2d4728f6931c4d29487cad764c5ce23c25e64b1a3259ac27235e41b23bfe7ae982921b4cb84463097df +8efa7338442a4b6318145a5440fc213b97869647eeae41b9aa3c0a27ee51285b73e3ae3b4a9423df255e6add58864aa9 +9106d65444f74d217f4187dfc8fcf3810b916d1e4275f94f6a86d1c4f3565b131fd6cde1fa708bc05fe183c49f14941a +948252dac8026bbbdb0a06b3c9d66ec4cf9532163bab68076fda1bd2357b69e4b514729c15aaa83b5618b1977bbc60c4 +ae6596ccfdf5cbbc5782efe3bb0b101bb132dbe1d568854ca24cacc0b2e0e9fabcb2ca7ab42aecec412efd15cf8cb7a2 +84a0b6c198ff64fd7958dfd1b40eac9638e8e0b2c4cd8cf5d8cdf80419baee76a05184bce6c5b635f6bf2d30055476a7 +8893118be4a055c2b3da593dbca51b1ae2ea2469911acfb27ee42faf3e6c3ad0693d3914c508c0b05b36a88c8b312b76 +b097479e967504deb6734785db7e60d1d8034d6ca5ba9552887e937f5e17bb413fccac2c1d1082154ed76609127860ad +a0294e6b9958f244d29943debf24b00b538b3da1116269b6e452bb12dc742226712fd1a15b9c88195afeb5d2415f505c +b3cc15f635080bc038f61b615f62b5b5c6f2870586191f59476e8368a73641d6ac2f7d0c1f54621982defdb318020230 +99856f49b9fe1604d917c94d09cc0ed753d13d015d30587a94e6631ffd964b214e607deb8a69a8b5e349a7edf4309206 +a8571e113ea22b4b4fce41a094da8c70de37830ae32e62c65c2fa5ad06a9bc29e884b945e73d448c72b176d6ecebfb58 +a9e9c6e52beb0013273c29844956b3ce291023678107cdc785f7b44eff5003462841ad8780761b86aefc6b734adde7cf +80a784b0b27edb51ef2bad3aee80e51778dcaa0f3f5d3dcb5dc5d4f4b2cf7ae35b08de6680ea9dac53f8438b92eb09ef +827b543e609ea328e97e373f70ad72d4915a2d1daae0c60d44ac637231070e164c43a2a58db80a64df1c624a042b38f9 +b449c65e8195202efdcb9bdb4e869a437313b118fef8b510cbbf8b79a4e99376adb749b37e9c20b51b31ed3310169e27 +8ea3028f4548a79a94c717e1ed28ad4d8725b8d6ab18b021063ce46f665c79da3c49440c6577319dab2d036b7e08f387 +897798431cfb17fe39f08f5f854005dc37b1c1ec1edba6c24bc8acb3b88838d0534a75475325a5ea98b326ad47dbad75 +89cf232e6303b0751561960fd4dea5754a28c594daf930326b4541274ffb03c7dd75938e411eb9a375006a70ce38097f +9727c6ae7f0840f0b6c8bfb3a1a5582ceee705e0b5c59b97def7a7a2283edd4d3f47b7971e902a3a2079e40b53ff69b8 +b76ed72b122c48679d221072efc0eeea063cb205cbf5f9ef0101fd10cb1075b8628166c83577cced654e1c001c7882f7 +ae908c42d208759da5ee9b405df85a6532ea35c6f0f6a1288d22870f59d98edc896841b8ac890a538e6c8d1e8b02d359 +809d12fe4039a0ec80dc9be6a89acaab7797e5f7f9b163378f52f9a75a1d73b2e9ae6e3dd49e32ced439783c1cabbef5 +a4149530b7f85d1098ba534d69548c6c612c416e8d35992fc1f64f4deeb41e09e49c6cf7aadbed7e846b91299358fe2d +a49342eacd1ec1148b8df1e253b1c015f603c39de11fa0a364ccb86ea32d69c34fd7aa6980a1fadcd8e785a57fa46f60 +87d43eff5a006dc4dddcf76cc96c656a1f3a68f19f124181feab86c6cc9a52cb9189cdbb423414defdd9bb0ca8ff1ddc +861367e87a9aa2f0f68296ba50aa5dbc5713008d260cc2c7e62d407c2063064749324c4e8156dc21b749656cfebce26b +b5303c2f72e84e170e66ae1b0fbd51b8c7a6f27476eaf5694b64e8737d5c84b51fe90100b256465a4c4156dd873cddb0 +b62849a4f891415d74f434cdc1d23c4a69074487659ca96e1762466b2b7a5d8525b056b891d0feea6fe6845cba8bc7fb +923dd9e0d6590a9307e8c4c23f13bae3306b580e297a937711a8b13e8de85e41a61462f25b7d352b682e8437bf2b4ab3 +9147379860cd713cd46c94b8cdf75125d36c37517fbecf81ace9680b98ce6291cd1c3e472f84249cc3b2b445e314b1b6 +a808a4f17ac21e3fb5cfef404e61fae3693ca3e688d375f99b6116779696059a146c27b06de3ac36da349b0649befd56 +87787e9322e1b75e66c1f0d9ea0915722a232770930c2d2a95e9478c4b950d15ab767e30cea128f9ed65893bfc2d0743 +9036a6ee2577223be105defe1081c48ea7319e112fff9110eb9f61110c319da25a6cea0464ce65e858635b079691ef1f +af5548c7c24e1088c23b57ee14d26c12a83484c9fd9296edf1012d8dcf88243f20039b43c8c548c265ef9a1ffe9c1c88 +a0fff520045e14065965fb8accd17e878d3fcaf9e0af2962c8954e50be6683d31fa0bf4816ab68f08630dbac6bfce52a +b4c1b249e079f6ae1781af1d97a60b15855f49864c50496c09c91fe1946266915b799f0406084d7783f5b1039116dd8b +8b0ffa5e7c498cb3879dddca34743b41eee8e2dea3d4317a6e961b58adb699ef0c92400c068d5228881a2b08121226bf +852ae8b19a1d80aa8ae5382e7ee5c8e7670ceb16640871c56b20b96b66b3b60e00015a3dde039446972e57b49a999ddd +a49942f04234a7d8492169da232cfff8051df86e8e1ba3db46aede02422c689c87dc1d99699c25f96cb763f5ca0983e5 +b04b597b7760cf5dcf411ef896d1661e6d5b0db3257ac2cf64b20b60c6cc18fa10523bb958a48d010b55bac7b02ab3b1 +a494591b51ea8285daecc194b5e5bd45ae35767d0246ac94fae204d674ee180c8e97ff15f71f28b7aeb175b8aea59710 +97d2624919e78406e7460730680dea8e71c8571cf988e11441aeea54512b95bd820e78562c99372d535d96f7e200d20d +ac693ddb00e48f76e667243b9b6a7008424043fb779e4f2252330285232c3fccac4da25cbd6d95fe9ad959ff305a91f6 +8d20ca0a71a64a3f702a0825bb46bd810d03bebfb227683680d474a52f965716ff99e19a165ebaf6567987f4f9ee3c94 +a5c516a438f916d1d68ca76996404792e0a66e97b7f18fc54c917bf10cf3211b62387932756e39e67e47b0bd6e88385a +b089614d830abc0afa435034cec7f851f2f095d479cacf1a3fb57272da826c499a52e7dcbc0eb85f4166fb94778e18e9 +a8dacc943765d930848288192f4c69e2461c4b9bc6e79e30eeef9a543318cf9ae9569d6986c65c5668a89d49993f8e07 +ab5a9361fa339eec8c621bdad0a58078983abd8942d4282b22835d7a3a47e132d42414b7c359694986f7db39386c2e19 +94230517fb57bd8eb26c6f64129b8b2abd0282323bf7b94b8bac7fab27b4ecc2c4290c294275e1a759de19f2216134f3 +b8f158ea5006bc3b90b285246625faaa6ac9b5f5030dc69701b12f3b79a53ec7e92eeb5a63bbd1f9509a0a3469ff3ffc +8b6944fd8cb8540957a91a142fdcda827762aa777a31e8810ca6d026e50370ee1636fc351724767e817ca38804ebe005 +82d1ee40fe1569c29644f79fa6c4033b7ed45cd2c3b343881f6eb0de2e79548fded4787fae19bed6ee76ed76ff9f2f11 +a8924c7035e99eaed244ca165607e7e568b6c8085510dcdbaf6ebdbed405af2e6c14ee27d94ffef10d30aa52a60bf66d +956f82a6c2ae044635e85812581e4866c5fa2f427b01942047d81f6d79a14192f66fbbe77c9ffeaef4e6147097fdd2b5 +b1100255a1bcf5e05b6aff1dfeb6e1d55b5d68d43a7457ba10cc76b61885f67f4d0d5179abda786e037ae95deb8eea45 +99510799025e3e5e8fbf06dedb14c060c6548ba2bda824f687d3999dc395e794b1fb6514b9013f3892b6cf65cb0d65aa +8f9091cebf5e9c809aab415942172258f894e66e625d7388a05289183f01b8d994d52e05a8e69f784fba41db9ea357f0 +a13d2eeb0776bdee9820ecb6693536720232848c51936bb4ef4fe65588d3f920d08a21907e1fdb881c1ad70b3725e726 +a68b8f18922d550284c5e5dc2dda771f24c21965a6a4d5e7a71678178f46df4d8a421497aad8fcb4c7e241aba26378a0 +8b7601f0a3c6ad27f03f2d23e785c81c1460d60100f91ea9d1cab978aa03b523150206c6d52ce7c7769c71d2c8228e9e +a8e02926430813caa851bb2b46de7f0420f0a64eb5f6b805401c11c9091d3b6d67d841b5674fa2b1dce0867714124cd8 +b7968ecba568b8193b3058400af02c183f0a6df995a744450b3f7e0af7a772454677c3857f99c140bbdb2a09e832e8e0 +8f20b1e9ba87d0a3f35309b985f3c18d2e8800f1ca7f0c52cadef773f1496b6070c936eea48c4a1cae83fd2524e9d233 +88aef260042db0d641a51f40639dbeeefa9e9811df30bee695f3791f88a2f84d318f04e8926b7f47bf25956cb9e3754f +9725345893b647e9ba4e6a29e12f96751f1ae25fcaec2173e9a259921a1a7edb7a47159b3c8767e44d9e2689f5aa0f72 +8c281e6f72752cb11e239e4df9341c45106eb7993c160e54423c2bffe10bc39d42624b45a1f673936ef2e1a02fc92f1a +90aba2f68bddb2fcce6c51430dacdfeec43ea8dc379660c99095df11017691ccf5faa27665cf4b9f0eea7728ae53c327 +b7022695c16521c5704f49b7ddbdbec9b5f57ce0ceebe537bc0ebb0906d8196cc855a9afeb8950a1710f6a654464d93f +8fe1b9dd3c6a258116415d36e08374e094b22f0afb104385a5da48be17123e86fb8327baacc4f0d9ebae923d55d99bb5 +817e85d8e3d19a4cbc1dec31597142c2daa4871bda89c2177fa719c00eda3344eb08b82eb92d4aa91a9eaacb3fc09783 +b59053e1081d2603f1ca0ba553804d6fa696e1fd996631db8f62087b26a40dfef02098b0326bb75f99ec83b9267ca738 +990a173d857d3ba81ff3789b931bfc9f5609cde0169b7f055fa3cb56451748d593d62d46ba33f80f9cafffe02b68dd14 +b0c538dbba4954b809ab26f9f94a3cf1dcb77ce289eaec1d19f556c0ae4be1fa03af4a9b7057837541c3cc0a80538736 +ac3ba42f5f44f9e1fc453ce49c4ab79d0e1d5c42d3b30b1e098f3ab3f414c4c262fa12fb2be249f52d4aaf3c5224beb9 +af47467eb152e59870e21f0d4da2f43e093daf40180ab01438030684b114d025326928eaab12c41b81a066d94fce8436 +98d1b58ba22e7289b1c45c79a24624f19b1d89e00f778eef327ec4856a9a897278e6f1a9a7e673844b31dde949153000 +97ccb15dfadc7c59dca08cfe0d22df2e52c684cf97de1d94bc00d7ba24e020025130b0a39c0f4d46e4fc872771ee7875 +b699e4ed9a000ff96ca296b2f09dce278832bc8ac96851ff3cff99ed3f6f752cfc0fea8571be28cd9b5a7ec36f1a08ee +b9f49f0edb7941cc296435ff0a912e3ad16848ee8765ab5f60a050b280d6ea585e5b34051b15f6b8934ef01ceb85f648 +ac3893df7b4ceab23c6b9054e48e8ba40d6e5beda8fbe90b814f992f52494186969b35d8c4cdc3c99890a222c9c09008 +a41293ad22fae81dea94467bc1488c3707f3d4765059173980be93995fa4fcc3c9340796e3eed0beeb0ba0d9bb4fa3aa +a0543e77acd2aeecde13d18d258aeb2c7397b77f17c35a1992e8666ea7abcd8a38ec6c2741bd929abba2f766138618cc +92e79b22bc40e69f6527c969500ca543899105837b6b1075fa1796755c723462059b3d1b028e0b3df2559fa440e09175 +a1fa1eac8f41a5197a6fb4aa1eae1a031c89f9c13ff9448338b222780cf9022e0b0925d930c37501a0ef7b2b00fdaf83 +b3cb29ff73229f0637335f28a08ad8c5f166066f27c6c175164d0f26766a927f843b987ee9b309ed71cbf0a65d483831 +84d4ab787f0ac00f104f4a734dc693d62d48c2aeb03913153da62c2ae2c27d11b1110dcef8980368dd84682ea2c1a308 +ab6a8e4bbc78d4a7b291ad3e9a8fe2d65f640524ba3181123b09d2d18a9e300e2509ccf7000fe47e75b65f3e992a2e7e +b7805ebe4f1a4df414003dc10bca805f2ab86ca75820012653e8f9b79c405196b0e2cab099f2ab953d67f0d60d31a0f9 +b12c582454148338ea605d22bd00a754109063e22617f1f8ac8ddf5502c22a181c50c216c3617b9852aa5f26af56b323 +86333ad9f898947e31ce747728dc8c887479e18d36ff3013f69ebef807d82c6981543b5c3788af93c4d912ba084d3cba +b514efa310dc4ad1258add138891e540d8c87142a881b5f46563cc58ecd1488e6d3a2fca54c0b72a929f3364ca8c333e +aa0a30f92843cf2f484066a783a1d75a7aa6f41f00b421d4baf20a6ac7886c468d0eea7ca8b17dd22f4f74631b62b640 +b3b7dc63baec9a752e8433c0cdee4d0f9bc41f66f2b8d132faf925eef9cf89aae756fc132c45910f057122462605dc10 +b9b8190dac5bfdeb59fd44f4da41a57e7f1e7d2c21faba9da91fa45cbeca06dcf299c9ae22f0c89ece11ac46352d619f +89f8cf36501ad8bdfeab863752a9090e3bfda57cf8fdeca2944864dc05925f501e252c048221bcc57136ab09a64b64b2 +b0cbfaf317f05f97be47fc9d69eda2dd82500e00d42612f271a1fe24626408c28881f171e855bd5bd67409f9847502b4 +a7c21a8fcede581bfd9847b6835eda62ba250bea81f1bb17372c800a19c732abe03064e64a2f865d974fb636cab4b859 +95f9df524ba7a4667351696c4176b505d8ea3659f5ff2701173064acc624af69a0fad4970963736383b979830cb32260 +856a74fe8b37a2e3afeac858c8632200485d438422a16ae3b29f359e470e8244995c63ad79c7e007ed063f178d0306fd +b37faa4d78fdc0bb9d403674dbea0176c2014a171c7be8527b54f7d1a32a76883d3422a3e7a5f5fcc5e9b31b57822eeb +8d37234d8594ec3fe75670b5c9cc1ec3537564d4739b2682a75b18b08401869a4264c0f264354219d8d896cded715db4 +b5289ee5737f0e0bde485d32096d23387d68dab8f01f47821ab4f06cc79a967afe7355e72dc0c751d96b2747b26f6255 +9085e1fdf9f813e9c3b8232d3c8863cd84ab30d45e8e0d3d6a0abd9ebc6fd70cdf749ff4d04390000e14c7d8c6655fc7 +93a388c83630331eca4da37ea4a97b3b453238af474817cc0a0727fd3138dcb4a22de38c04783ec829c22cb459cb4e8e +a5377116027c5d061dbe24c240b891c08cdd8cd3f0899e848d682c873aff5b8132c1e7cfe76d2e5ed97ee0eb1d42cb68 +a274c84b04338ed28d74683e2a7519c2591a3ce37c294d6f6e678f7d628be2db8eff253ede21823e2df7183e6552f622 +8bc201147a842453a50bec3ac97671397bc086d6dfc9377fa38c2124cdc286abda69b7324f47d64da094ae011d98d9d9 +9842d0c066c524592b76fbec5132bc628e5e1d21c424bec4555efca8619cc1fd8ea3161febcb8b9e8ab54702f4e815e2 +a19191b713a07efe85c266f839d14e25660ee74452e6c691cd9997d85ae4f732052d802d3deb018bdd847caa298a894b +a24f71fc0db504da4e287dd118a4a74301cbcd16033937ba2abc8417956fcb4ae19b8e63b931795544a978137eff51cb +a90eec4a6a3a4b8f9a5b93d978b5026fcf812fe65585b008d7e08c4aaf21195a1d0699f12fc16f79b6a18a369af45771 +8b551cf89737d7d06d9b3b9c4c1c73b41f2ea0af4540999c70b82dabff8580797cf0a3caf34c86c59a7069eb2e38f087 +b8d312e6c635e7a216a1cda075ae77ba3e1d2fd501dc31e83496e6e81ed5d9c7799f8e578869c2e0e256fb29f5de10a7 +8d144bdb8cae0b2cdb5b33d44bbc96984a5925202506a8cc65eb67ac904b466f5a7fe3e1cbf04aa785bbb7348c4bb73c +a101b3d58b7a98659244b88de0b478b3fb87dc5fc6031f6e689b99edf498abd43e151fd32bd4bbd240e0b3e59c440359 +907453abca7d8e7151a05cc3d506c988007692fe7401395dc93177d0d07d114ab6cca0cc658eb94c0223fe8658295cad +825329ffbe2147ddb68f63a0a67f32d7f309657b8e5d9ab5bb34b3730bfa2c77a23eaaadb05def7d9f94a9e08fdc1e96 +88ee923c95c1dac99ae7ed6067906d734d793c5dc5d26339c1bb3314abe201c5dccb33b9007351885eb2754e9a8ea06c +98bc9798543f5f1adc9f2cfcfa72331989420e9c3f6598c45269f0dc9b7c8607bbeaf03faa0aea2ddde2b8f17fdceff5 +8ee87877702a79aef923ab970db6fa81561b3c07d5bf1a072af0a7bad765b4cbaec910afe1a91703feacc7822fa38a94 +8060b9584aa294fe8adc2b22f67e988bc6da768eae91e429dcc43ddc53cfcc5d6753fdc1b420b268c7eb2fb50736a970 +b344a5524d80a2f051870c7001f74fcf348a70fcf78dbd20c6ff9ca85d81567d2318c8b8089f2c4f195d6aec9fc15fa6 +8f5a5d893e1936ed062149d20eb73d98b62b7f50ab5d93a6429c03656b36688d1c80cb5010e4977491e51fa0d7dd35d5 +86fa32ebbf97328c5f5f15564e1238297e289ec3219b9a741724e9f3ae8d5c15277008f555863a478b247ba5dc601d44 +9557e55377e279f4b6b5e0ffe01eca037cc13aac242d67dfcd0374a1e775c5ed5cb30c25fe21143fee54e3302d34a3ea +8cb6bcbc39372d23464a416ea7039f57ba8413cf3f00d9a7a5b356ab20dcb8ed11b3561f7bce372b8534d2870c7ee270 +b5d59075cb5abde5391f64b6c3b8b50adc6e1f654e2a580b6d6d6eff3f4fbdd8fffc92e06809c393f5c8eab37f774c4b +afcfb6903ef13e493a1f7308675582f15af0403b6553e8c37afb8b2808ad21b88b347dc139464367dc260df075fea1ad +810fbbe808375735dd22d5bc7fc3828dc49fdd22cc2d7661604e7ac9c4535c1df578780affb3b895a0831640a945bcad +8056b0c678803b416f924e09a6299a33cf9ad7da6fe1ad7accefe95c179e0077da36815fde3716711c394e2c5ea7127f +8b67403702d06979be19f1d6dc3ec73cc2e81254d6b7d0cc49cd4fdda8cd51ab0835c1d2d26fc0ecab5df90585c2f351 +87f97f9e6d4be07e8db250e5dd2bffdf1390665bc5709f2b631a6fa69a7fca958f19bd7cc617183da1f50ee63e9352b5 +ae151310985940471e6803fcf37600d7fa98830613e381e00dab943aec32c14162d51c4598e8847148148000d6e5af5c +81eb537b35b7602c45441cfc61b27fa9a30d3998fad35a064e05bc9479e9f10b62eba2b234b348219eea3cadcaac64bb +8a441434934180ab6f5bc541f86ebd06eadbee01f438836d797e930fa803a51510e005c9248cecc231a775b74d12b5e9 +81f3c250a27ba14d8496a5092b145629eb2c2e6a5298438670375363f57e2798207832c8027c3e9238ad94ecdadfc4df +a6217c311f2f3db02ceaa5b6096849fe92b6f4b6f1491535ef8525f6ccee6130bed2809e625073ecbaddd4a3eb3df186 +82d1c396f0388b942cf22b119d7ef1ad03d3dad49a74d9d01649ee284f377c8daddd095d596871669e16160299a210db +a40ddf7043c5d72a7246bd727b07f7fff1549f0e443d611de6f9976c37448b21664c5089c57f20105102d935ab82f27b +b6c03c1c97adf0c4bf4447ec71366c6c1bff401ba46236cd4a33d39291e7a1f0bb34bd078ba3a18d15c98993b153a279 +8a94f5f632068399c359c4b3a3653cb6df2b207379b3d0cdace51afdf70d6d5cce6b89a2b0fee66744eba86c98fb21c2 +b2f19e78ee85073f680c3bba1f07fd31b057c00b97040357d97855b54a0b5accb0d3b05b2a294568fcd6a4be6f266950 +a74632d13bbe2d64b51d7a9c3ae0a5a971c19f51cf7596a807cea053e6a0f3719700976d4e394b356c0329a2dced9aa2 +afef616d341a9bc94393b8dfba68ff0581436aa3a3adb7c26a1bbf2cf19fa877066191681f71f17f3cd6f9cf6bf70b5a +8ce96d93ae217408acf7eb0f9cbb9563363e5c7002e19bbe1e80760bc9d449daee2118f3878b955163ed664516b97294 +8414f79b496176bc8b8e25f8e4cfee28f4f1c2ddab099d63d2aca1b6403d26a571152fc3edb97794767a7c4686ad557c +b6c61d01fd8ce087ef9f079bf25bf10090db483dd4f88c4a786d31c1bdf52065651c1f5523f20c21e75cea17df69ab73 +a5790fd629be70545093631efadddc136661f63b65ec682609c38ef7d3d7fa4e56bdf94f06e263bc055b90cb1c6bcefe +b515a767e95704fb7597bca9e46f1753abacdc0e56e867ee3c6f4cd382643c2a28e65312c05ad040eaa3a8cbe7217a65 +8135806a02ead6aa92e9adb6fefb91349837ab73105aaa7be488ef966aa8dfaafdfa64bbae30fcbfa55dd135a036a863 +8f22435702716d76b1369750694540742d909d5e72b54d0878245fab7c269953b1c6f2b29c66f08d5e0263ca3a731771 +8e0f8a8e8753e077dac95848212aeffd51c23d9b6d611df8b102f654089401954413ecbedc6367561ca599512ae5dda7 +815a9084e3e2345f24c5fa559deec21ee1352fb60f4025c0779be65057f2d528a3d91593bd30d3a185f5ec53a9950676 +967e6555ccba395b2cc1605f8484c5112c7b263f41ce8439a99fd1c71c5ed14ad02684d6f636364199ca48afbbde13be +8cd0ccf17682950b34c796a41e2ea7dd5367aba5e80a907e01f4cdc611e4a411918215e5aebf4292f8b24765d73314a6 +a58bf1bbb377e4b3915df6f058a0f53b8fb8130fdec8c391f6bc82065694d0be59bb67ffb540e6c42cc8b380c6e36359 +92af3151d9e6bfb3383d85433e953c0160859f759b0988431ec5893542ba40288f65db43c78a904325ef8d324988f09d +8011bbb05705167afb47d4425065630f54cb86cd462095e83b81dfebf348f846e4d8fbcf1c13208f5de1931f81da40b9 +81c743c104fc3cb047885c9fa0fb9705c3a83ee24f690f539f4985509c3dafd507af3f6a2128276f45d5939ef70c167f +a2c9679b151c041aaf5efeac5a737a8f70d1631d931609fca16be1905682f35e291292874cb3b03f14994f98573c6f44 +a4949b86c4e5b1d5c82a337e5ce6b2718b1f7c215148c8bfb7e7c44ec86c5c9476048fc5c01f57cb0920876478c41ad6 +86c2495088bd1772152e527a1da0ef473f924ea9ab0e5b8077df859c28078f73c4e22e3a906b507fdf217c3c80808b5c +892e0a910dcf162bcea379763c3e2349349e4cda9402949255ac4a78dd5a47e0bf42f5bd0913951576b1d206dc1e536a +a7009b2c6b396138afe4754b7cc10dee557c51c7f1a357a11486b3253818531f781ea8107360c8d4c3b1cd96282353c0 +911763ef439c086065cc7b4e57484ed6d693ea44acee4b18c9fd998116da55fbe7dcb8d2a0f0f9b32132fca82d73dff6 +a722000b95a4a2d40bed81870793f15ba2af633f9892df507f2842e52452e02b5ea8dea6a043c2b2611d82376e33742a +9387ac49477bd719c2f92240d0bdfcf9767aad247ca93dc51e56106463206bc343a8ec855eb803471629a66fffb565d6 +92819a1fa48ab4902939bb72a0a4e6143c058ea42b42f9bc6cea5df45f49724e2530daf3fc4f097cceefa2a8b9db0076 +98eac7b04537653bc0f4941aae732e4b1f84bd276c992c64a219b8715eb1fb829b5cbd997d57feb15c7694c468f95f70 +b275e7ba848ce21bf7996e12dbeb8dadb5d0e4f1cb5a0248a4f8f9c9fe6c74e3c93f4b61edbcb0a51af5a141e1c14bc7 +97243189285aba4d49c53770c242f2faf5fd3914451da4931472e3290164f7663c726cf86020f8f181e568c72fd172d1 +839b0b3c25dd412bee3dc24653b873cc65454f8f16186bb707bcd58259c0b6765fa4c195403209179192a4455c95f3b8 +8689d1a870514568a074a38232e2ceb4d7df30fabeb76cff0aed5b42bf7f02baea12c5fadf69f4713464dbd52aafa55f +8958ae7b290f0b00d17c3e9fdb4dbf168432b457c7676829299dd428984aba892de1966fc106cfc58a772862ecce3976 +a422bc6bd68b8870cfa5bc4ce71781fd7f4368b564d7f1e0917f6013c8bbb5b240a257f89ecfdbecb40fe0f3aa31d310 +aa61f78130cebe09bc9a2c0a37f0dd57ed2d702962e37d38b1df7f17dc554b1d4b7a39a44182a452ce4c5eb31fa4cfcc +b7918bd114f37869bf1a459023386825821bfadce545201929d13ac3256d92a431e34f690a55d944f77d0b652cefeffc +819bba35fb6ace1510920d4dcff30aa682a3c9af9022e287751a6a6649b00c5402f14b6309f0aeef8fce312a0402915e +8b7c9ad446c6f63c11e1c24e24014bd570862b65d53684e107ba9ad381e81a2eaa96731b4b33536efd55e0f055071274 +8fe79b53f06d33386c0ec7d6d521183c13199498594a46d44a8a716932c3ec480c60be398650bbfa044fa791c4e99b65 +9558e10fb81250b9844c99648cf38fa05ec1e65d0ccbb18aa17f2d1f503144baf59d802c25be8cc0879fff82ed5034ad +b538a7b97fbd702ba84645ca0a63725be1e2891c784b1d599e54e3480e4670d0025526674ef5cf2f87dddf2290ba09f0 +92eafe2e869a3dd8519bbbceb630585c6eb21712b2f31e1b63067c0acb5f9bdbbcbdb612db4ea7f9cc4e7be83d31973f +b40d21390bb813ab7b70a010dff64c57178418c62685761784e37d327ba3cb9ef62df87ecb84277c325a637fe3709732 +b349e6fbf778c4af35fbed33130bd8a7216ed3ba0a79163ebb556e8eb8e1a7dad3456ddd700dad9d08d202491c51b939 +a8fdaedecb251f892b66c669e34137f2650509ade5d38fbe8a05d9b9184bb3b2d416186a3640429bd1f3e4b903c159dd +ac6167ebfee1dbab338eff7642f5e785fc21ef0b4ddd6660333fe398068cbd6c42585f62e81e4edbb72161ce852a1a4f +874b1fbf2ebe140c683bd7e4e0ab017afa5d4ad38055aaa83ee6bbef77dbc88a6ce8eb0dcc48f0155244af6f86f34c2d +903c58e57ddd9c446afab8256a6bb6c911121e6ccfb4f9b4ed3e2ed922a0e500a5cb7fa379d5285bc16e11dac90d1fda +8dae7a0cffa2fd166859cd1bf10ff82dd1932e488af377366b7efc0d5dec85f85fe5e8150ff86a79a39cefc29631733a +aa047857a47cc4dfc08585f28640420fcf105b881fd59a6cf7890a36516af0644d143b73f3515ab48faaa621168f8c31 +864508f7077c266cc0cb3f7f001cb6e27125ebfe79ab57a123a8195f2e27d3799ff98413e8483c533b46a816a3557f1f +8bcd45ab1f9cbab36937a27e724af819838f66dfeb15923f8113654ff877bd8667c54f6307aaf0c35027ca11b6229bfd +b21aa34da9ab0a48fcfdd291df224697ce0c1ebc0e9b022fdee8750a1a4b5ba421c419541ed5c98b461eecf363047471 +a9a18a2ab2fae14542dc336269fe612e9c1af6cf0c9ac933679a2f2cb77d3c304114f4d219ca66fe288adde30716775b +b5205989b92c58bdda71817f9a897e84100b5c4e708de1fced5c286f7a6f01ae96b1c8d845f3a320d77c8e2703c0e8b1 +a364059412bbcc17b8907d43ac8e5df90bc87fd1724b5f99832d0d24559fae6fa76a74cff1d1eac8cbac6ec80b44af20 +ae709f2c339886b31450834cf29a38b26eb3b0779bd77c9ac269a8a925d1d78ea3837876c654b61a8fe834b3b6940808 +8802581bba66e1952ac4dab36af371f66778958f4612901d95e5cac17f59165e6064371d02de8fb6fccf89c6dc8bd118 +a313252df653e29c672cbcfd2d4f775089cb77be1077381cf4dc9533790e88af6cedc8a119158e7da5bf6806ad9b91a1 +992a065b4152c7ef11515cd54ba9d191fda44032a01aed954acff3443377ee16680c7248d530b746b8c6dee2d634e68c +b627b683ee2b32c1ab4ccd27b9f6cce2fe097d96386fa0e5c182ad997c4c422ab8dfc03870cd830b8c774feb66537282 +b823cf8a9aee03dadd013eb9efe40a201b4b57ef67efaae9f99683005f5d1bf55e950bf4af0774f50859d743642d3fea +b8a7449ffac0a3f206677097baf7ce00ca07a4d2bd9b5356fbcb83f3649b0fda07cfebad220c1066afba89e5a52abf4b +b2dd1a2f986395bb4e3e960fbbe823dbb154f823284ebc9068502c19a7609790ec0073d08bfa63f71e30c7161b6ef966 +98e5236de4281245234f5d40a25b503505af140b503a035fc25a26159a9074ec81512b28f324c56ea2c9a5aa7ce90805 +89070847dc8bbf5bc4ed073aa2e2a1f699cf0c2ca226f185a0671cecc54e7d3e14cd475c7752314a7a8e7476829da4bc +a9402dc9117fdb39c4734c0688254f23aed3dce94f5f53f5b7ef2b4bf1b71a67f85ab1a38ec224a59691f3bee050aeb3 +957288f9866a4bf56a4204218ccc583f717d7ce45c01ea27142a7e245ad04a07f289cc044f8cf1f21d35e67e39299e9c +b2fb31ccb4e69113763d7247d0fc8edaae69b550c5c56aecacfd780c7217dc672f9fb7496edf4aba65dacf3361268e5b +b44a4526b2f1d6eb2aa8dba23bfa385ff7634572ab2afddd0546c3beb630fbfe85a32f42dd287a7fec069041411537f7 +8db5a6660c3ac7fd7a093573940f068ee79a82bc17312af900b51c8c439336bc86ca646c6b7ab13aaaa008a24ca508ab +8f9899a6d7e8eb4367beb5c060a1f8e94d8a21099033ae582118477265155ba9e72176a67f7f25d7bad75a152b56e21a +a67de0e91ade8d69a0e00c9ff33ee2909b8a609357095fa12319e6158570c232e5b6f4647522efb7345ce0052aa9d489 +82eb2414898e9c3023d57907a2b17de8e7eea5269029d05a94bfd7bf5685ac4a799110fbb375eb5e0e2bd16acf6458ae +94451fc7fea3c5a89ba701004a9693bab555cb622caf0896b678faba040409fdfd14a978979038b2a81e8f0abc4994d2 +ac879a5bb433998e289809a4a966bd02b4bf6a9c1cc276454e39c886efcf4fc68baebed575826bde577ab5aa71d735a9 +880c0f8f49c875dfd62b4ddedde0f5c8b19f5687e693717f7e5c031bc580e58e13ab497d48b4874130a18743c59fdce3 +b582af8d8ff0bf76f0a3934775e0b54c0e8fed893245d7d89cae65b03c8125b7237edc29dc45b4fe1a3fe6db45d280ee +89f337882ed3ae060aaee98efa20d79b6822bde9708c1c5fcee365d0ec9297f694cae37d38fd8e3d49717c1e86f078e7 +826d2c1faea54061848b484e288a5f4de0d221258178cf87f72e14baaa4acc21322f8c9eab5dde612ef497f2d2e1d60b +a5333d4f227543e9cd741ccf3b81db79f2f03ca9e649e40d6a6e8ff9073e06da83683566d3b3c8d7b258c62970fb24d1 +a28f08c473db06aaf4c043a2fae82b3c8cfaa160bce793a4c208e4e168fb1c65115ff8139dea06453c5963d95e922b94 +8162546135cc5e124e9683bdfaa45833c18553ff06a0861c887dc84a5b12ae8cd4697f6794c7ef6230492c32faba7014 +b23f0d05b74c08d6a7df1760792be83a761b36e3f8ae360f3c363fb196e2a9dd2de2e492e49d36561366e14daa77155c +b6f70d6c546722d3907c708d630dbe289771d2c8bf059c2e32b77f224696d750b4dda9b3a014debda38e7d02c9a77585 +83bf4c4a9f3ca022c631017e7a30ea205ba97f7f5927cba8fc8489a4646eac6712cb821c5668c9ffe94d69d524374a27 +b0371475425a8076d0dd5f733f55aabbe42d20a7c8ea7da352e736d4d35a327b2beb370dfcb05284e22cfd69c5f6c4cc +a0031ba7522c79211416c2cca3aa5450f96f8fee711552a30889910970ba13608646538781a2c08b834b140aadd7166f +99d273c80c7f2dc6045d4ed355d9fc6f74e93549d961f4a3b73cd38683f905934d359058cd1fc4da8083c7d75070487f +b0e4b0efa3237793e9dcce86d75aafe9879c5fa23f0d628649aef2130454dcf72578f9bf227b9d2b9e05617468e82588 +a5ab076fa2e1c5c51f3ae101afdd596ad9d106bba7882b359c43d8548b64f528af19afa76cd6f40da1e6c5fca4def3fa +8ce2299e570331d60f6a6eff1b271097cd5f1c0e1113fc69b89c6a0f685dabea3e5bc2ac6bd789aa492ab189f89be494 +91b829068874d911a310a5f9dee001021f97471307b5a3de9ec336870ec597413e1d92010ce320b619f38bed7c4f7910 +b14fe91f4b07bf33b046e9285b66cb07927f3a8da0af548ac2569b4c4fb1309d3ced76d733051a20814e90dd5b75ffd1 +abaab92ea6152d40f82940277c725aa768a631ee0b37f5961667f82fb990fc11e6d3a6a2752b0c6f94563ed9bb28265c +b7fe28543eca2a716859a76ab9092f135337e28109544f6bd2727728d0a7650428af5713171ea60bfc273d1c821d992c +8a4917b2ab749fc7343fc64bdf51b6c0698ff15d740cc7baf248c030475c097097d5a473bcc00d8c25817563fe0447b4 +aa96156d1379553256350a0a3250166add75948fb9cde62aa555a0a9dc0a9cb7f2f7b8428aff66097bf6bfedaf14bbe2 +ae4ffeb9bdc76830d3eca2b705f30c1bdede6412fa064260a21562c8850c7fb611ec62bc68479fe48f692833e6f66d8d +b96543caaba9d051600a14997765d49e4ab10b07c7a92cccf0c90b309e6da334fdd6d18c96806cbb67a7801024fbd3c7 +97b2b9ad76f19f500fcc94ca8e434176249f542ac66e5881a3dccd07354bdab6a2157018b19f8459437a68d8b86ba8e0 +a8d206f6c5a14c80005849474fde44b1e7bcf0b2d52068f5f97504c3c035b09e65e56d1cf4b5322791ae2c2fdbd61859 +936bad397ad577a70cf99bf9056584a61bd7f02d2d5a6cf219c05d770ae30a5cd902ba38366ce636067fc1dd10108d31 +a77e30195ee402b84f3882e2286bf5380c0ed374a112dbd11e16cef6b6b61ab209d4635e6f35cdaaa72c1a1981d5dabe +a46ba4d3947188590a43c180757886a453a0503f79cc435322d92490446f37419c7b999fdf868a023601078070e03346 +80d8d4c5542f223d48240b445d4d8cf6a75d120b060bc08c45e99a13028b809d910b534d2ac47fb7068930c54efd8da9 +803be9c68c91b42b68e1f55e58917a477a9a6265e679ca44ee30d3eb92453f8c89c64eafc04c970d6831edd33d066902 +b14b2b3d0dfe2bb57cee4cd72765b60ac33c1056580950be005790176543826c1d4fbd737f6cfeada6c735543244ab57 +a9e480188bba1b8fb7105ff12215706665fd35bf1117bacfb6ab6985f4dbc181229873b82e5e18323c2b8f5de03258e0 +a66a0f0779436a9a3999996d1e6d3000f22c2cac8e0b29cddef9636393c7f1457fb188a293b6c875b05d68d138a7cc4a +848397366300ab40c52d0dbbdafbafef6cd3dadf1503bb14b430f52bb9724188928ac26f6292a2412bc7d7aa620763c8 +95466cc1a78c9f33a9aaa3829a4c8a690af074916b56f43ae46a67a12bb537a5ac6dbe61590344a25b44e8512355a4a7 +8b5f7a959f818e3baf0887f140f4575cac093d0aece27e23b823cf421f34d6e4ff4bb8384426e33e8ec7b5eed51f6b5c +8d5e1368ec7e3c65640d216bcc5d076f3d9845924c734a34f3558ac0f16e40597c1a775a25bf38b187213fbdba17c93b +b4647c1b823516880f60d20c5cc38c7f80b363c19d191e8992226799718ee26b522a12ecb66556ed3d483aa4824f3326 +ac3abaea9cd283eb347efda4ed9086ea3acf495043e08d0d19945876329e8675224b685612a6badf8fd72fb6274902b1 +8eae1ce292d317aaa71bcf6e77e654914edd5090e2e1ebab78b18bb41b9b1bc2e697439f54a44c0c8aa0d436ebe6e1a9 +94dc7d1aec2c28eb43d93b111fa59aaa0d77d5a09501220bd411768c3e52208806abf973c6a452fd8292ff6490e0c9e2 +8fd8967f8e506fef27d17b435d6b86b232ec71c1036351f12e6fb8a2e12daf01d0ee04451fb944d0f1bf7fd20e714d02 +824e6865be55d43032f0fec65b3480ea89b0a2bf860872237a19a54bc186a85d2f8f9989cc837fbb325b7c72d9babe2c +8bd361f5adb27fd6f4e3f5de866e2befda6a8454efeb704aacc606f528c03f0faae888f60310e49440496abd84083ce2 +b098a3c49f2aaa28b6b3e85bc40ce6a9cdd02134ee522ae73771e667ad7629c8d82c393fba9f27f5416986af4c261438 +b385f5ca285ff2cfe64dcaa32dcde869c28996ed091542600a0b46f65f3f5a38428cca46029ede72b6cf43e12279e3d3 +8196b03d011e5be5288196ef7d47137d6f9237a635ab913acdf9c595fa521d9e2df722090ec7eb0203544ee88178fc5f +8ed1270211ef928db18e502271b7edf24d0bbd11d97f2786aee772d70c2029e28095cf8f650b0328cc8a4c38d045316d +a52ab60e28d69b333d597a445884d44fd2a7e1923dd60f763951e1e45f83e27a4dac745f3b9eff75977b3280e132c15d +91e9fe78cdac578f4a4687f71b800b35da54b824b1886dafec073a3c977ce7a25038a2f3a5b1e35c2c8c9d1a7312417c +a42832173f9d9491c7bd93b21497fbfa4121687cd4d2ab572e80753d7edcbb42cfa49f460026fbde52f420786751a138 +97b947126d84dcc70c97be3c04b3de3f239b1c4914342fa643b1a4bb8c4fe45c0fcb585700d13a7ed50784790c54bef9 +860e407d353eac070e2418ef6cb80b96fc5f6661d6333e634f6f306779651588037be4c2419562c89c61f9aa2c4947f5 +b2c9d93c3ba4e511b0560b55d3501bf28a510745fd666b3cb532db051e6a8617841ea2f071dda6c9f15619c7bfd2737f +8596f4d239aeeac78311207904d1bd863ef68e769629cc379db60e019aaf05a9d5cd31dc8e630b31e106a3a93e47cbc5 +8b26e14e2e136b65c5e9e5c2022cee8c255834ea427552f780a6ca130a6446102f2a6f334c3f9a0308c53df09e3dba7e +b54724354eb515a3c8bed0d0677ff1db94ac0a07043459b4358cb90e3e1aa38ac23f2caa3072cf9647275d7cd61d0e80 +b7ce9fe0e515e7a6b2d7ddcb92bc0196416ff04199326aea57996eef8c5b1548bd8569012210da317f7c0074691d01b7 +a1a13549c82c877253ddefa36a29ea6a23695ee401fdd48e65f6f61e5ebd956d5e0edeff99484e9075cb35071fec41e2 +838ba0c1e5bd1a6da05611ff1822b8622457ebd019cb065ece36a2d176bd2d889511328120b8a357e44569e7f640c1e6 +b916eccff2a95519400bbf76b5f576cbe53cf200410370a19d77734dc04c05b585cfe382e8864e67142d548cd3c4c2f4 +a610447cb7ca6eea53a6ff1f5fe562377dcb7f4aaa7300f755a4f5e8eba61e863c51dc2aa9a29b35525b550fbc32a0fe +9620e8f0f0ee9a4719aa9685eeb1049c5c77659ba6149ec4c158f999cfd09514794b23388879931fe26fea03fa471fd3 +a9dcf8b679e276583cf5b9360702a185470d09aea463dc474ee9c8aee91ef089dacb073e334e47fbc78ec5417c90465c +8c9adee8410bdd99e5b285744cee61e2593b6300ff31a8a83b0ec28da59475a5c6fb9346fe43aadea2e6c3dad2a8e30a +97d5afe9b3897d7b8bb628b7220cf02d8ee4e9d0b78f5000d500aaf4c1df9251aaaabfd1601626519f9d66f00a821d4e +8a382418157b601ce4c3501d3b8409ca98136a4ef6abcbf62885e16e215b76b035c94d149cc41ff92e42ccd7c43b9b3d +b64b8d11fb3b01abb2646ac99fdb9c02b804ce15d98f9fe0fbf1c9df8440c71417487feb6cdf51e3e81d37104b19e012 +849d7d044f9d8f0aab346a9374f0b3a5d14a9d1faa83dbacccbdc629ad1ef903a990940255564770537f8567521d17f0 +829dbb0c76b996c2a91b4cbbe93ba455ca0d5729755e5f0c92aaee37dff7f36fcdc06f33aca41f1b609c784127b67d88 +85a7c0069047b978422d264d831ab816435f63938015d2e977222b6b5746066c0071b7f89267027f8a975206ed25c1b0 +84b9fbc1cfb302df1acdcf3dc5d66fd1edfe7839f7a3b2fb3a0d5548656249dd556104d7c32b73967bccf0f5bdcf9e3b +972220ac5b807f53eac37dccfc2ad355d8b21ea6a9c9b011c09fe440ddcdf7513e0b43d7692c09ded80d7040e26aa28f +855885ed0b21350baeca890811f344c553cf9c21024649c722453138ba29193c6b02c4b4994cd414035486f923472e28 +841874783ae6d9d0e59daea03e96a01cbbe4ecaced91ae4f2c8386e0d87b3128e6d893c98d17c59e4de1098e1ad519dd +827e50fc9ce56f97a4c3f2f4cbaf0b22f1c3ce6f844ff0ef93a9c57a09b8bf91ebfbd2ba9c7f83c442920bffdaf288cc +a441f9136c7aa4c08d5b3534921b730e41ee91ab506313e1ba5f7c6f19fd2d2e1594e88c219834e92e6fb95356385aa7 +97d75b144471bf580099dd6842b823ec0e6c1fb86dd0da0db195e65524129ea8b6fd4a7a9bbf37146269e938a6956596 +a4b6fa87f09d5a29252efb2b3aaab6b3b6ea9fab343132a651630206254a25378e3e9d6c96c3d14c150d01817d375a8e +a31a671876d5d1e95fe2b8858dc69967231190880529d57d3cab7f9f4a2b9b458ac9ee5bdaa3289158141bf18f559efb +90bee6fff4338ba825974021b3b2a84e36d617e53857321f13d2b3d4a28954e6de3b3c0e629d61823d18a9763313b3bf +96b622a63153f393bb419bfcf88272ea8b3560dbd46b0aa07ada3a6223990d0abdd6c2adb356ef4be5641688c8d83941 +84c202adeaff9293698022bc0381adba2cd959f9a35a4e8472288fd68f96f6de8be9da314c526d88e291c96b1f3d6db9 +8ca01a143b8d13809e5a8024d03e6bc9492e22226073ef6e327edf1328ef4aff82d0bcccee92cb8e212831fa35fe1204 +b2f970dbad15bfbefb38903c9bcc043d1367055c55dc1100a850f5eb816a4252c8c194b3132c929105511e14ea10a67d +a5e36556472a95ad57eb90c3b6623671b03eafd842238f01a081997ffc6e2401f76e781d049bb4aa94d899313577a9cf +8d1057071051772f7c8bedce53a862af6fd530dd56ae6321eaf2b9fc6a68beff5ed745e1c429ad09d5a118650bfd420a +8aadc4f70ace4fcb8d93a78610779748dcffc36182d45b932c226dc90e48238ea5daa91f137c65ed532352c4c4d57416 +a2ea05ae37e673b4343232ae685ee14e6b88b867aef6dfac35db3589cbcd76f99540fed5c2641d5bb5a4a9f808e9bf0d +947f1abad982d65648ae4978e094332b4ecb90f482c9be5741d5d1cf5a28acf4680f1977bf6e49dd2174c37f11e01296 +a27b144f1565e4047ba0e3f4840ef19b5095d1e281eaa463c5358f932114cbd018aa6dcf97546465cf2946d014d8e6d6 +8574e1fc3acade47cd4539df578ce9205e745e161b91e59e4d088711a7ab5aa3b410d517d7304b92109924d9e2af8895 +a48ee6b86b88015d6f0d282c1ae01d2a5b9e8c7aa3d0c18b35943dceb1af580d08a65f54dc6903cde82fd0d73ce94722 +8875650cec543a7bf02ea4f2848a61d167a66c91ffaefe31a9e38dc8511c6a25bde431007eefe27a62af3655aca208dc +999b0a6e040372e61937bf0d68374e230346b654b5a0f591a59d33a4f95bdb2f3581db7c7ccb420cd7699ed709c50713 +878c9e56c7100c5e47bbe77dc8da5c5fe706cec94d37fa729633bca63cace7c40102eee780fcdabb655f5fa47a99600e +865006fb5b475ada5e935f27b96f9425fc2d5449a3c106aa366e55ebed3b4ee42adc3c3f0ac19fd129b40bc7d6bc4f63 +b7a7da847f1202e7bc1672553e68904715e84fd897d529243e3ecda59faa4e17ba99c649a802d53f6b8dfdd51f01fb74 +8b2fb4432c05653303d8c8436473682933a5cb604da10c118ecfcd2c8a0e3132e125afef562bdbcc3df936164e5ce4f2 +808d95762d33ddfa5d0ee3d7d9f327de21a994d681a5f372e2e3632963ea974da7f1f9e5bac8ccce24293509d1f54d27 +932946532e3c397990a1df0e94c90e1e45133e347a39b6714c695be21aeb2d309504cb6b1dde7228ff6f6353f73e1ca2 +9705e7c93f0cdfaa3fa96821f830fe53402ad0806036cd1b48adc2f022d8e781c1fbdab60215ce85c653203d98426da3 +aa180819531c3ec1feb829d789cb2092964c069974ae4faad60e04a6afcce5c3a59aec9f11291e6d110a788d22532bc6 +88f755097f7e25cb7dd3c449520c89b83ae9e119778efabb54fbd5c5714b6f37c5f9e0346c58c6ab09c1aef2483f895d +99fc03ab7810e94104c494f7e40b900f475fde65bdec853e60807ffd3f531d74de43335c3b2646b5b8c26804a7448898 +af2dea9683086bed1a179110efb227c9c00e76cd00a2015b089ccbcee46d1134aa18bda5d6cab6f82ae4c5cd2461ac21 +a500f87ba9744787fdbb8e750702a3fd229de6b8817594348dec9a723b3c4240ddfa066262d002844b9e38240ce55658 +924d0e45c780f5bc1c1f35d15dfc3da28036bdb59e4c5440606750ecc991b85be18bc9a240b6c983bc5430baa4c68287 +865b11e0157b8bf4c5f336024b016a0162fc093069d44ac494723f56648bc4ded13dfb3896e924959ea11c96321afefc +93672d8607d4143a8f7894f1dcca83fb84906dc8d6dd7dd063bb0049cfc20c1efd933e06ca7bd03ea4cb5a5037990bfe +826891efbdff0360446825a61cd1fa04326dd90dae8c33dfb1ed97b045e165766dd070bd7105560994d0b2044bdea418 +93c4a4a8bcbc8b190485cc3bc04175b7c0ed002c28c98a540919effd6ed908e540e6594f6db95cd65823017258fb3b1c +aeb2a0af2d2239fda9aa6b8234b019708e8f792834ff0dd9c487fa09d29800ddceddd6d7929faa9a3edcb9e1b3aa0d6b +87f11de7236d387863ec660d2b04db9ac08143a9a2c4dfff87727c95b4b1477e3bc473a91e5797313c58754905079643 +80dc1db20067a844fe8baceca77f80db171a5ca967acb24e2d480eae9ceb91a3343c31ad1c95b721f390829084f0eae6 +9825c31f1c18da0de3fa84399c8b40f8002c3cae211fb6a0623c76b097b4d39f5c50058f57a16362f7a575909d0a44a2 +a99fc8de0c38dbf7b9e946de83943a6b46a762167bafe2a603fb9b86f094da30d6de7ed55d639aafc91936923ee414b3 +ad594678b407db5d6ea2e90528121f84f2b96a4113a252a30d359a721429857c204c1c1c4ff71d8bb5768c833f82e80e +b33d985e847b54510b9b007e31053732c8a495e43be158bd2ffcea25c6765bcbc7ca815f7c60b36ad088b955dd6e9350 +815f8dfc6f90b3342ca3fbd968c67f324dae8f74245cbf8bc3bef10e9440c65d3a2151f951e8d18959ba01c1b50b0ec1 +94c608a362dd732a1abc56e338637c900d59013db8668e49398b3c7a0cae3f7e2f1d1bf94c0299eeafe6af7f76c88618 +8ebd8446b23e5adfcc393adc5c52fe172f030a73e63cd2d515245ca0dd02782ceed5bcdd9ccd9c1b4c5953dfac9c340c +820437f3f6f9ad0f5d7502815b221b83755eb8dc56cd92c29e9535eb0b48fb8d08c9e4fcc26945f9c8cca60d89c44710 +8910e4e8a56bf4be9cc3bbf0bf6b1182a2f48837a2ed3c2aaec7099bfd7f0c83e14e608876b17893a98021ff4ab2f20d +9633918fde348573eec15ce0ad53ac7e1823aac86429710a376ad661002ae6d049ded879383faaa139435122f64047c6 +a1f5e3fa558a9e89318ca87978492f0fb4f6e54a9735c1b8d2ecfb1d1c57194ded6e0dd82d077b2d54251f3bee1279e1 +b208e22d04896abfd515a95c429ff318e87ff81a5d534c8ac2c33c052d6ffb73ef1dccd39c0bbe0734b596c384014766 +986d5d7d2b5bde6d16336f378bd13d0e671ad23a8ec8a10b3fc09036faeeb069f60662138d7a6df3dfb8e0d36180f770 +a2d4e6c5f5569e9cef1cddb569515d4b6ace38c8aed594f06da7434ba6b24477392cc67ba867c2b079545ca0c625c457 +b5ac32b1d231957d91c8b7fc43115ce3c5c0d8c13ca633374402fa8000b6d9fb19499f9181844f0c10b47357f3f757ce +96b8bf2504b4d28fa34a4ec378e0e0b684890c5f44b7a6bb6e19d7b3db2ab27b1e2686389d1de9fbd981962833a313ea +953bfd7f6c3a0469ad432072b9679a25486f5f4828092401eff494cfb46656c958641a4e6d0d97d400bc59d92dba0030 +876ab3cea7484bbfd0db621ec085b9ac885d94ab55c4bb671168d82b92e609754b86aaf472c55df3d81421d768fd108a +885ff4e67d9ece646d02dd425aa5a087e485c3f280c3471b77532b0db6145b69b0fbefb18aa2e3fa5b64928b43a94e57 +b91931d93f806d0b0e6cc62a53c718c099526140f50f45d94b8bbb57d71e78647e06ee7b42aa5714aed9a5c05ac8533f +a0313eeadd39c720c9c27b3d671215331ab8d0a794e71e7e690f06bcd87722b531d6525060c358f35f5705dbb7109ccb +874c0944b7fedc6701e53344100612ddcb495351e29305c00ec40a7276ea5455465ffb7bded898886c1853139dfb1fc7 +8dc31701a01ee8137059ca1874a015130d3024823c0576aa9243e6942ec99d377e7715ed1444cd9b750a64b85dcaa3e5 +836d2a757405e922ec9a2dfdcf489a58bd48b5f9683dd46bf6047688f778c8dee9bc456de806f70464df0b25f3f3d238 +b30b0a1e454a503ea3e2efdec7483eaf20b0a5c3cefc42069e891952b35d4b2c955cf615f3066285ed8fafd9fcfbb8f6 +8e6d4044b55ab747e83ec8762ea86845f1785cc7be0279c075dadf08aca3ccc5a096c015bb3c3f738f647a4eadea3ba5 +ad7735d16ab03cbe09c029610aa625133a6daecfc990b297205b6da98eda8c136a7c50db90f426d35069708510d5ae9c +8d62d858bbb59ec3c8cc9acda002e08addab4d3ad143b3812098f3d9087a1b4a1bb255dcb1635da2402487d8d0249161 +805beec33238b832e8530645a3254aeef957e8f7ea24bcfc1054f8b9c69421145ebb8f9d893237e8a001c857fedfc77e +b1005644be4b085e3f5775aa9bd3e09a283e87ddada3082c04e7a62d303dcef3b8cf8f92944c200c7ae6bb6bdf63f832 +b4ba0e0790dc29063e577474ffe3b61f5ea2508169f5adc1e394934ebb473e356239413a17962bc3e5d3762d72cce8c2 +a157ba9169c9e3e6748d9f1dd67fbe08b9114ade4c5d8fc475f87a764fb7e6f1d21f66d7905cd730f28a1c2d8378682a +913e52b5c93989b5d15e0d91aa0f19f78d592bc28bcfdfddc885a9980c732b1f4debb8166a7c4083c42aeda93a702898 +90fbfc1567e7cd4e096a38433704d3f96a2de2f6ed3371515ccc30bc4dd0721a704487d25a97f3c3d7e4344472702d8d +89646043028ffee4b69d346907586fd12c2c0730f024acb1481abea478e61031966e72072ff1d5e65cb8c64a69ad4eb1 +b125a45e86117ee11d2fb42f680ab4a7894edd67ff927ae2c808920c66c3e55f6a9d4588eee906f33a05d592e5ec3c04 +aad47f5b41eae9be55fb4f67674ff1e4ae2482897676f964a4d2dcb6982252ee4ff56aac49578b23f72d1fced707525e +b9ddff8986145e33851b4de54d3e81faa3352e8385895f357734085a1616ef61c692d925fe62a5ed3be8ca49f5d66306 +b3cb0963387ed28c0c0adf7fe645f02606e6e1780a24d6cecef5b7c642499109974c81a7c2a198b19862eedcea2c2d8c +ac9c53c885457aaf5cb36c717a6f4077af701e0098eebd7aa600f5e4b14e6c1067255b3a0bc40e4a552025231be7de60 +8e1a8d823c4603f6648ec21d064101094f2a762a4ed37dd2f0a2d9aa97b2d850ce1e76f4a4b8cae58819b058180f7031 +b268b73bf7a179b6d22bd37e5e8cb514e9f5f8968c78e14e4f6d5700ca0d0ca5081d0344bb73b028970eebde3cb4124e +a7f57d71940f0edbd29ed8473d0149cae71d921dd15d1ff589774003e816b54b24de2620871108cec1ab9fa956ad6ce6 +8053e6416c8b120e2b999cc2fc420a6a55094c61ac7f2a6c6f0a2c108a320890e389af96cbe378936132363c0d551277 +b3823f4511125e5aa0f4269e991b435a0d6ceb523ebd91c04d7add5534e3df5fc951c504b4fd412a309fd3726b7f940b +ae6eb04674d04e982ca9a6add30370ab90e303c71486f43ed3efbe431af1b0e43e9d06c11c3412651f304c473e7dbf39 +96ab55e641ed2e677591f7379a3cd126449614181fce403e93e89b1645d82c4af524381ff986cae7f9cebe676878646d +b52423b4a8c37d3c3e2eca8f0ddbf7abe0938855f33a0af50f117fab26415fb0a3da5405908ec5fdc22a2c1f2ca64892 +82a69ce1ee92a09cc709d0e3cd22116c9f69d28ea507fe5901f5676000b5179b9abe4c1875d052b0dd42d39925e186bb +a84c8cb84b9d5cfb69a5414f0a5283a5f2e90739e9362a1e8c784b96381b59ac6c18723a4aa45988ee8ef5c1f45cc97d +afd7efce6b36813082eb98257aae22a4c1ae97d51cac7ea9c852d4a66d05ef2732116137d8432e3f117119725a817d24 +a0f5fe25af3ce021b706fcff05f3d825384a272284d04735574ce5fb256bf27100fad0b1f1ba0e54ae9dcbb9570ecad3 +8751786cb80e2e1ff819fc7fa31c2833d25086534eb12b373d31f826382430acfd87023d2a688c65b5e983927e146336 +8cf5c4b17fa4f3d35c78ce41e1dc86988fd1135cd5e6b2bb0c108ee13538d0d09ae7102609c6070f39f937b439b31e33 +a9108967a2fedd7c322711eca8159c533dd561bedcb181b646de98bf5c3079449478eab579731bee8d215ae8852c7e21 +b54c5171704f42a6f0f4e70767cdb3d96ffc4888c842eece343a01557da405961d53ffdc34d2f902ea25d3e1ed867cad +ae8d4b764a7a25330ba205bf77e9f46182cd60f94a336bbd96773cf8064e3d39caf04c310680943dc89ed1fbad2c6e0d +aa5150e911a8e1346868e1b71c5a01e2a4bb8632c195861fb6c3038a0e9b85f0e09b3822e9283654a4d7bb17db2fc5f4 +9685d3756ce9069bf8bb716cf7d5063ebfafe37e15b137fc8c3159633c4e006ff4887ddd0ae90360767a25c3f90cba7f +82155fd70f107ab3c8e414eadf226c797e07b65911508c76c554445422325e71af8c9a8e77fd52d94412a6fc29417cd3 +abfae52f53a4b6e00760468d973a267f29321997c3dbb5aee36dc1f20619551229c0c45b9d9749f410e7f531b73378e8 +81a76d921f8ef88e774fd985e786a4a330d779b93fad7def718c014685ca0247379e2e2a007ad63ee7f729cd9ed6ce1b +81947c84bc5e28e26e2e533af5ae8fe10407a7b77436dbf8f1d5b0bbe86fc659eae10f974659dc7c826c6dabd03e3a4b +92b8c07050d635b8dd4fd09df9054efe4edae6b86a63c292e73cc819a12a21dd7d104ce51fa56af6539dedf6dbe6f7b6 +b44c579e3881f32b32d20c82c207307eca08e44995dd2aac3b2692d2c8eb2a325626c80ac81c26eeb38c4137ff95add5 +97efab8941c90c30860926dea69a841f2dcd02980bf5413b9fd78d85904588bf0c1021798dbc16c8bbb32cce66c82621 +913363012528b50698e904de0588bf55c8ec5cf6f0367cfd42095c4468fcc64954fbf784508073e542fee242d0743867 +8ed203cf215148296454012bd10fddaf119203db1919a7b3d2cdc9f80e66729464fdfae42f1f2fc5af1ed53a42b40024 +ab84312db7b87d711e9a60824f4fe50e7a6190bf92e1628688dfcb38930fe87b2d53f9e14dd4de509b2216856d8d9188 +880726def069c160278b12d2258eac8fa63f729cd351a710d28b7e601c6712903c3ac1e7bbd0d21e4a15f13ca49db5aa +980699cd51bac6283959765f5174e543ed1e5f5584b5127980cbc2ef18d984ecabba45042c6773b447b8e694db066028 +aeb019cb80dc4cb4207430d0f2cd24c9888998b6f21d9bf286cc638449668d2eec0018a4cf3fe6448673cd6729335e2b +b29852f6aa6c60effdffe96ae88590c88abae732561d35cc19e82d3a51e26cb35ea00986193e07f90060756240f5346e +a0fa855adc5ba469f35800c48414b8921455950a5c0a49945d1ef6e8f2a1881f2e2dfae47de6417270a6bf49deeb091d +b6c7332e3b14813641e7272d4f69ecc7e09081df0037d6dab97ce13a9e58510f5c930d300633f208181d9205c5534001 +85a6c050f42fce560b5a8d54a11c3bbb8407abbadd859647a7b0c21c4b579ec65671098b74f10a16245dc779dff7838e +8f3eb34bb68759d53c6677de4de78a6c24dd32c8962a7fb355ed362572ef8253733e6b52bc21c9f92ecd875020a9b8de +a17dd44181e5dab4dbc128e1af93ec22624b57a448ca65d2d9e246797e4af7d079e09c6e0dfb62db3a9957ce92f098d5 +a56a1b854c3183082543a8685bb34cae1289f86cfa8123a579049dbd059e77982886bfeb61bf6e05b4b1fe4e620932e7 +aedae3033cb2fb7628cb4803435bdd7757370a86f808ae4cecb9a268ad0e875f308c048c80cbcac523de16b609683887 +9344905376aa3982b1179497fac5a1d74b14b7038fd15e3b002db4c11c8bfc7c39430db492cdaf58b9c47996c9901f28 +a3bfafdae011a19f030c749c3b071f83580dee97dd6f949e790366f95618ca9f828f1daaeabad6dcd664fcef81b6556d +81c03d8429129e7e04434dee2c529194ddb01b414feda3adee2271eb680f6c85ec872a55c9fa9d2096f517e13ed5abcc +98205ef3a72dff54c5a9c82d293c3e45d908946fa74bb749c3aabe1ab994ea93c269bcce1a266d2fe67a8f02133c5985 +85a70aeed09fda24412fadbafbbbf5ba1e00ac92885df329e147bfafa97b57629a3582115b780d8549d07d19b7867715 +b0fbe81c719f89a57d9ea3397705f898175808c5f75f8eb81c2193a0b555869ba7bd2e6bc54ee8a60cea11735e21c68c +b03a0bd160495ee626ff3a5c7d95bc79d7da7e5a96f6d10116600c8fa20bedd1132f5170f25a22371a34a2d763f2d6d0 +a90ab04091fbca9f433b885e6c1d60ab45f6f1daf4b35ec22b09909d493a6aab65ce41a6f30c98239cbca27022f61a8b +b66f92aa3bf2549f9b60b86f99a0bd19cbdd97036d4ae71ca4b83d669607f275260a497208f6476cde1931d9712c2402 +b08e1fdf20e6a9b0b4942f14fa339551c3175c1ffc5d0ab5b226b6e6a322e9eb0ba96adc5c8d59ca4259e2bdd04a7eb0 +a2812231e92c1ce74d4f5ac3ab6698520288db6a38398bb38a914ac9326519580af17ae3e27cde26607e698294022c81 +abfcbbcf1d3b9e84c02499003e490a1d5d9a2841a9e50c7babbef0b2dd20d7483371d4dc629ba07faf46db659459d296 +b0fe9f98c3da70927c23f2975a9dc4789194d81932d2ad0f3b00843dd9cbd7fb60747a1da8fe5a79f136a601becf279d +b130a6dba7645165348cb90f023713bed0eefbd90a976b313521c60a36d34f02032e69a2bdcf5361e343ed46911297ec +862f0cffe3020cea7a5fd4703353aa1eb1be335e3b712b29d079ff9f7090d1d8b12013011e1bdcbaa80c44641fd37c9f +8c6f11123b26633e1abb9ed857e0bce845b2b3df91cc7b013b2fc77b477eee445da0285fc6fc793e29d5912977f40916 +91381846126ea819d40f84d3005e9fb233dc80071d1f9bb07f102bf015f813f61e5884ffffb4f5cd333c1b1e38a05a58 +8add7d908de6e1775adbd39c29a391f06692b936518db1f8fde74eb4f533fc510673a59afb86e3a9b52ade96e3004c57 +8780e086a244a092206edcde625cafb87c9ab1f89cc3e0d378bc9ee776313836160960a82ec397bc3800c0a0ec3da283 +a6cb4cd9481e22870fdd757fae0785edf4635e7aacb18072fe8dc5876d0bab53fb99ce40964a7d3e8bcfff6f0ab1332f +af30ff47ecc5b543efba1ba4706921066ca8bb625f40e530fb668aea0551c7647a9d126e8aba282fbcce168c3e7e0130 +91b0bcf408ce3c11555dcb80c4410b5bc2386d3c05caec0b653352377efdcb6bab4827f2018671fc8e4a0e90d772acc1 +a9430b975ef138b6b2944c7baded8fe102d31da4cfe3bd3d8778bda79189c99d38176a19c848a19e2d1ee0bddd9a13c1 +aa5a4eef849d7c9d2f4b018bd01271c1dd83f771de860c4261f385d3bdcc130218495860a1de298f14b703ec32fa235f +b0ce79e7f9ae57abe4ff366146c3b9bfb38b0dee09c28c28f5981a5d234c6810ad4d582751948affb480d6ae1c8c31c4 +b75122748560f73d15c01a8907d36d06dc068e82ce22b84b322ac1f727034493572f7907dec34ebc3ddcc976f2f89ed7 +b0fc7836369a3e4411d34792d6bd5617c14f61d9bba023dda64e89dc5fb0f423244e9b48ee64869258931daa9753a56f +8956d7455ae9009d70c6e4a0bcd7610e55f37494cf9897a8f9e1b904cc8febc3fd2d642ebd09025cfff4609ad7e3bc52 +ad741efe9e472026aa49ae3d9914cb9c1a6f37a54f1a6fe6419bebd8c7d68dca105a751c7859f4389505ede40a0de786 +b52f418797d719f0d0d0ffb0846788b5cba5d0454a69a2925de4b0b80fa4dd7e8c445e5eac40afd92897ed28ca650566 +a0ab65fb9d42dd966cd93b1de01d7c822694669dd2b7a0c04d99cd0f3c3de795f387b9c92da11353412f33af5c950e9a +a0052f44a31e5741a331f7cac515a08b3325666d388880162d9a7b97598fde8b61f9ff35ff220df224eb5c4e40ef0567 +a0101cfdc94e42b2b976c0d89612a720e55d145a5ef6ef6f1f78cf6de084a49973d9b5d45915349c34ce712512191e3c +a0dd99fcf3f5cead5aaf08e82212df3a8bb543c407a4d6fab88dc5130c1769df3f147e934a46f291d6c1a55d92b86917 +a5939153f0d1931bbda5cf6bdf20562519ea55fbfa978d6dbc6828d298260c0da7a50c37c34f386e59431301a96c2232 +9568269f3f5257200f9ca44afe1174a5d3cf92950a7f553e50e279c239e156a9faaa2a67f288e3d5100b4142efe64856 +b746b0832866c23288e07f24991bbf687cad794e7b794d3d3b79367566ca617d38af586cdc8d6f4a85a34835be41d54f +a871ce28e39ab467706e32fec1669fda5a4abba2f8c209c6745df9f7a0fa36bbf1919cf14cb89ea26fa214c4c907ae03 +a08dacdd758e523cb8484f6bd070642c0c20e184abdf8e2a601f61507e93952d5b8b0c723c34fcbdd70a8485eec29db2 +85bdb78d501382bb95f1166b8d032941005661aefd17a5ac32df9a3a18e9df2fc5dc2c1f07075f9641af10353cecc0c9 +98d730c28f6fa692a389e97e368b58f4d95382fad8f0baa58e71a3d7baaea1988ead47b13742ce587456f083636fa98e +a557198c6f3d5382be9fb363feb02e2e243b0c3c61337b3f1801c4a0943f18e38ce1a1c36b5c289c8fa2aa9d58742bab +89174f79201742220ac689c403fc7b243eed4f8e3f2f8aba0bf183e6f5d4907cb55ade3e238e3623d9885f03155c4d2b +b891d600132a86709e06f3381158db300975f73ea4c1f7c100358e14e98c5fbe792a9af666b85c4e402707c3f2db321e +b9e5b2529ef1043278c939373fc0dbafe446def52ddd0a8edecd3e4b736de87e63e187df853c54c28d865de18a358bb6 +8589b2e9770340c64679062c5badb7bbef68f55476289b19511a158a9a721f197da03ece3309e059fc4468b15ac33aa3 +aad8c6cd01d785a881b446f06f1e9cd71bca74ba98674c2dcddc8af01c40aa7a6d469037498b5602e76e9c91a58d3dbd +abaccb1bd918a8465f1bf8dbe2c9ad4775c620b055550b949a399f30cf0d9eb909f3851f5b55e38f9e461e762f88f499 +ae62339d26db46e85f157c0151bd29916d5cc619bd4b832814b3fd2f00af8f38e7f0f09932ffe5bba692005dab2d9a74 +93a6ff30a5c0edf8058c89aba8c3259e0f1b1be1b80e67682de651e5346f7e1b4b4ac3d87cbaebf198cf779524aff6bf +8980a2b1d8f574af45b459193c952400b10a86122b71fca2acb75ee0dbd492e7e1ef5b959baf609a5172115e371f3177 +8c2f49f3666faee6940c75e8c7f6f8edc3f704cca7a858bbb7ee5e96bba3b0cf0993996f781ba6be3b0821ef4cb75039 +b14b9e348215b278696018330f63c38db100b0542cfc5be11dc33046e3bca6a13034c4ae40d9cef9ea8b34fef0910c4e +b59bc3d0a30d66c16e6a411cb641f348cb1135186d5f69fda8b0a0934a5a2e7f6199095ba319ec87d3fe8f1ec4a06368 +8874aca2a3767aa198e4c3fec2d9c62d496bc41ff71ce242e9e082b7f38cdf356089295f80a301a3cf1182bde5308c97 +b1820ebd61376d91232423fc20bf008b2ba37e761199f4ef0648ea2bd70282766799b4de814846d2f4d516d525c8daa7 +a6b202e5dedc16a4073e04a11af3a8509b23dfe5a1952f899adeb240e75c3f5bde0c424f811a81ea48d343591faffe46 +a69becee9c93734805523b92150a59a62eed4934f66056b645728740d42223f2925a1ad38359ba644da24d9414f4cdda +ad72f0f1305e37c7e6b48c272323ee883320994cb2e0d850905d6655fafc9f361389bcb9c66b3ff8d2051dbb58c8aa96 +b563600bd56fad7c8853af21c6a02a16ed9d8a8bbeea2c31731d63b976d83cb05b9779372d898233e8fd597a75424797 +b0abb78ce465bf7051f563c62e8be9c57a2cc997f47c82819300f36e301fefd908894bb2053a9d27ce2d0f8c46d88b5b +a071a85fb8274bac2202e0cb8e0e2028a5e138a82d6e0374d39ca1884a549c7c401312f00071b91f455c3a2afcfe0cda +b931c271513a0f267b9f41444a5650b1918100b8f1a64959c552aff4e2193cc1b9927906c6fa7b8a8c68ef13d79aaa52 +a6a1bb9c7d32cb0ca44d8b75af7e40479fbce67d216b48a2bb680d3f3a772003a49d3cd675fc64e9e0f8fabeb86d6d61 +b98d609858671543e1c3b8564162ad828808bb50ded261a9f8690ded5b665ed8368c58f947365ed6e84e5a12e27b423d +b3dca58cd69ec855e2701a1d66cad86717ff103ef862c490399c771ad28f675680f9500cb97be48de34bcdc1e4503ffd +b34867c6735d3c49865e246ddf6c3b33baf8e6f164db3406a64ebce4768cb46b0309635e11be985fee09ab7a31d81402 +acb966c554188c5b266624208f31fab250b3aa197adbdd14aee5ab27d7fb886eb4350985c553b20fdf66d5d332bfd3fe +943c36a18223d6c870d54c3b051ef08d802b85e9dd6de37a51c932f90191890656c06adfa883c87b906557ae32d09da0 +81bca7954d0b9b6c3d4528aadf83e4bc2ef9ea143d6209bc45ae9e7ae9787dbcd8333c41f12c0b6deee8dcb6805e826a +aba176b92256efb68f574e543479e5cf0376889fb48e3db4ebfb7cba91e4d9bcf19dcfec444c6622d9398f06de29e2b9 +b9f743691448053216f6ece7cd699871fff4217a1409ceb8ab7bdf3312d11696d62c74b0664ba0a631b1e0237a8a0361 +a383c2b6276fa9af346b21609326b53fb14fdf6f61676683076e80f375b603645f2051985706d0401e6fbed7eb0666b6 +a9ef2f63ec6d9beb8f3d04e36807d84bda87bdd6b351a3e4a9bf7edcb5618c46c1f58cfbf89e64b40f550915c6988447 +a141b2d7a82f5005eaea7ae7d112c6788b9b95121e5b70b7168d971812f3381de8b0082ac1f0a82c7d365922ebd2d26a +b1b76ef8120e66e1535c17038b75255a07849935d3128e3e99e56567b842fb1e8d56ef932d508d2fb18b82f7868fe1a9 +8e2e234684c81f21099f5c54f6bbe2dd01e3b172623836c77668a0c49ce1fe218786c3827e4d9ae2ea25c50a8924fb3c +a5caf5ff948bfd3c4ca3ffbdfcd91eec83214a6c6017235f309a0bbf7061d3b0b466307c00b44a1009cf575163898b43 +986415a82ca16ebb107b4c50b0c023c28714281db0bcdab589f6cb13d80e473a3034b7081b3c358e725833f6d845cb14 +b94836bf406ac2cbacb10e6df5bcdfcc9d9124ae1062767ca4e322d287fd5e353fdcebd0e52407cb3cd68571258a8900 +83c6d70a640b33087454a4788dfd9ef3ed00272da084a8d36be817296f71c086b23b576f98178ab8ca6a74f04524b46b +ad4115182ad784cfe11bcfc5ce21fd56229cc2ce77ac82746e91a2f0aa53ca6593a22efd2dc4ed8d00f84542643d9c58 +ab1434c5e5065da826d10c2a2dba0facccab0e52b506ce0ce42fbe47ced5a741797151d9ecc99dc7d6373cfa1779bbf6 +8a8b591d82358d55e6938f67ea87a89097ab5f5496f7260adb9f649abb289da12b498c5b2539c2f9614fb4e21b1f66b0 +964f355d603264bc1f44c64d6d64debca66f37dff39c971d9fc924f2bc68e6c187b48564a6dc82660a98b035f8addb5d +b66235eaaf47456bc1dc4bde454a028e2ce494ece6b713a94cd6bf27cf18c717fd0c57a5681caaa2ad73a473593cdd7a +9103e3bb74304186fa4e3e355a02da77da4aca9b7e702982fc2082af67127ebb23a455098313c88465bc9b7d26820dd5 +b6a42ff407c9dd132670cdb83cbad4b20871716e44133b59a932cd1c3f97c7ac8ff7f61acfaf8628372508d8dc8cad7c +883a9c21c16a167a4171b0f084565c13b6f28ba7c4977a0de69f0a25911f64099e7bbb4da8858f2e93068f4155d04e18 +8dbb3220abc6a43220adf0331e3903d3bfd1d5213aadfbd8dfcdf4b2864ce2e96a71f35ecfb7a07c3bbabf0372b50271 +b4ad08aee48e176bda390b7d9acf2f8d5eb008f30d20994707b757dc6a3974b2902d29cd9b4d85e032810ad25ac49e97 +865bb0f33f7636ec501bb634e5b65751c8a230ae1fa807a961a8289bbf9c7fe8c59e01fbc4c04f8d59b7f539cf79ddd5 +86a54d4c12ad1e3605b9f93d4a37082fd26e888d2329847d89afa7802e815f33f38185c5b7292293d788ad7d7da1df97 +b26c8615c5e47691c9ff3deca3021714662d236c4d8401c5d27b50152ce7e566266b9d512d14eb63e65bc1d38a16f914 +827639d5ce7db43ba40152c8a0eaad443af21dc92636cc8cc2b35f10647da7d475a1e408901cd220552fddad79db74df +a2b79a582191a85dbe22dc384c9ca3de345e69f6aa370aa6d3ff1e1c3de513e30b72df9555b15a46586bd27ea2854d9d +ae0d74644aba9a49521d3e9553813bcb9e18f0b43515e4c74366e503c52f47236be92dfbd99c7285b3248c267b1de5a0 +80fb0c116e0fd6822a04b9c25f456bdca704e2be7bdc5d141dbf5d1c5eeb0a2c4f5d80db583b03ef3e47517e4f9a1b10 +ac3a1fa3b4a2f30ea7e0a114cdc479eb51773573804c2a158d603ad9902ae8e39ffe95df09c0d871725a5d7f9ba71a57 +b56b2b0d601cba7f817fa76102c68c2e518c6f20ff693aad3ff2e07d6c4c76203753f7f91686b1801e8c4659e4d45c48 +89d50c1fc56e656fb9d3915964ebce703cb723fe411ab3c9eaa88ccc5d2b155a9b2e515363d9c600d3c0cee782c43f41 +b24207e61462f6230f3cd8ccf6828357d03e725769f7d1de35099ef9ee4dca57dbce699bb49ed994462bee17059d25ce +b886f17fcbcbfcd08ac07f04bb9543ef58510189decaccea4b4158c9174a067cb67d14b6be3c934e6e2a18c77efa9c9c +b9c050ad9cafd41c6e2e192b70d080076eed59ed38ea19a12bd92fa17b5d8947d58d5546aaf5e8e27e1d3b5481a6ce51 +aaf7a34d3267e3b1ddbc54c641e3922e89303f7c86ebebc7347ebca4cffad5b76117dac0cbae1a133053492799cd936f +a9ee604ada50adef82e29e893070649d2d4b7136cc24fa20e281ce1a07bd736bf0de7c420369676bcbcecff26fb6e900 +9855315a12a4b4cf80ab90b8bd13003223ba25206e52fd4fe6a409232fbed938f30120a3db23eab9c53f308bd8b9db81 +8cd488dd7a24f548a3cf03c54dec7ff61d0685cb0f6e5c46c2d728e3500d8c7bd6bba0156f4bf600466fda53e5b20444 +890ad4942ebac8f5b16c777701ab80c68f56fa542002b0786f8fea0fb073154369920ac3dbfc07ea598b82f4985b8ced +8de0cf9ddc84c9b92c59b9b044387597799246b30b9f4d7626fc12c51f6e423e08ee4cbfe9289984983c1f9521c3e19d +b474dfb5b5f4231d7775b3c3a8744956b3f0c7a871d835d7e4fd9cc895222c7b868d6c6ce250de568a65851151fac860 +86433b6135d9ed9b5ee8cb7a6c40e5c9d30a68774cec04988117302b8a02a11a71a1e03fd8e0264ef6611d219f103007 +80b9ed4adbe9538fb1ef69dd44ec0ec5b57cbfea820054d8d445b4261962624b4c70ac330480594bc5168184378379c3 +8b2e83562ccd23b7ad2d17f55b1ab7ef5fbef64b3a284e6725b800f3222b8bdf49937f4a873917ada9c4ddfb090938c2 +abe78cebc0f5a45d754140d1f685e387489acbfa46d297a8592aaa0d676a470654f417a4f7d666fc0b2508fab37d908e +a9c5f8ff1f8568e252b06d10e1558326db9901840e6b3c26bbd0cd5e850cb5fb3af3f117dbb0f282740276f6fd84126f +975f8dc4fb55032a5df3b42b96c8c0ffecb75456f01d4aef66f973cb7270d4eff32c71520ceefc1adcf38d77b6b80c67 +b043306ed2c3d8a5b9a056565afd8b5e354c8c4569fda66b0d797a50a3ce2c08cffbae9bbe292da69f39e89d5dc7911e +8d2afc36b1e44386ba350c14a6c1bb31ff6ea77128a0c5287584ac3584282d18516901ce402b4644a53db1ed8e7fa581 +8c294058bed53d7290325c363fe243f6ec4f4ea2343692f4bac8f0cb86f115c069ccb8334b53d2e42c067691ad110dba +b92157b926751aaf7ef82c1aa8c654907dccab6376187ee8b3e8c0c82811eae01242832de953faa13ebaff7da8698b3e +a780c4bdd9e4ba57254b09d745075cecab87feda78c88ffee489625c5a3cf96aa6b3c9503a374a37927d9b78de9bd22b +811f548ef3a2e6a654f7dcb28ac9378de9515ed61e5a428515d9594a83e80b35c60f96a5cf743e6fab0d3cb526149f49 +85a4dccf6d90ee8e094731eec53bd00b3887aec6bd81a0740efddf812fd35e3e4fe4f983afb49a8588691c202dabf942 +b152c2da6f2e01c8913079ae2b40a09b1f361a80f5408a0237a8131b429677c3157295e11b365b1b1841924b9efb922e +849b9efee8742502ffd981c4517c88ed33e4dd518a330802caff168abae3cd09956a5ee5eda15900243bc2e829016b74 +955a933f3c18ec0f1c0e38fa931e4427a5372c46a3906ebe95082bcf878c35246523c23f0266644ace1fa590ffa6d119 +911989e9f43e580c886656377c6f856cdd4ff1bd001b6db3bbd86e590a821d34a5c6688a29b8d90f28680e9fdf03ba69 +b73b8b4f1fd6049fb68d47cd96a18fcba3f716e0a1061aa5a2596302795354e0c39dea04d91d232aec86b0bf2ba10522 +90f87456d9156e6a1f029a833bf3c7dbed98ca2f2f147a8564922c25ae197a55f7ea9b2ee1f81bf7383197c4bad2e20c +903cba8b1e088574cb04a05ca1899ab00d8960580c884bd3c8a4c98d680c2ad11410f2b75739d6050f91d7208cac33a5 +9329987d42529c261bd15ecedd360be0ea8966e7838f32896522c965adfc4febf187db392bd441fb43bbd10c38fdf68b +8178ee93acf5353baa349285067b20e9bb41aa32d77b5aeb7384fe5220c1fe64a2461bd7a83142694fe673e8bbf61b7c +a06a8e53abcff271b1394bcc647440f81fb1c1a5f29c27a226e08f961c3353f4891620f2d59b9d1902bf2f5cc07a4553 +aaf5fe493b337810889e777980e6bbea6cac39ac66bc0875c680c4208807ac866e9fda9b5952aa1d04539b9f4a4bec57 +aa058abb1953eceac14ccfa7c0cc482a146e1232905dcecc86dd27f75575285f06bbae16a8c9fe8e35d8713717f5f19f +8f15dd732799c879ca46d2763453b359ff483ca33adb1d0e0a57262352e0476c235987dc3a8a243c74bc768f93d3014c +a61cc8263e9bc03cce985f1663b8a72928a607121005a301b28a278e9654727fd1b22bc8a949af73929c56d9d3d4a273 +98d6dc78502d19eb9f921225475a6ebcc7b44f01a2df6f55ccf6908d65b27af1891be2a37735f0315b6e0f1576c1f8d8 +8bd258b883f3b3793ec5be9472ad1ff3dc4b51bc5a58e9f944acfb927349ead8231a523cc2175c1f98e7e1e2b9f363b8 +aeacc2ecb6e807ad09bedd99654b097a6f39840e932873ace02eabd64ccfbb475abdcb62939a698abf17572d2034c51e +b8ccf78c08ccd8df59fd6eda2e01de328bc6d8a65824d6f1fc0537654e9bc6bf6f89c422dd3a295cce628749da85c864 +8f91fd8cb253ba2e71cc6f13da5e05f62c2c3b485c24f5d68397d04665673167fce1fc1aec6085c69e87e66ec555d3fd +a254baa10cb26d04136886073bb4c159af8a8532e3fd36b1e9c3a2e41b5b2b6a86c4ebc14dbe624ee07b7ccdaf59f9ab +94e3286fe5cd68c4c7b9a7d33ae3d714a7f265cf77cd0e9bc19fc51015b1d1c34ad7e3a5221c459e89f5a043ee84e3a9 +a279da8878af8d449a9539bec4b17cea94f0242911f66fab275b5143ab040825f78c89cb32a793930609415cfa3a1078 +ac846ceb89c9e5d43a2991c8443079dc32298cd63e370e64149cec98cf48a6351c09c856f2632fd2f2b3d685a18bbf8b +a847b27995c8a2e2454aaeb983879fb5d3a23105c33175839f7300b7e1e8ec3efd6450e9fa3f10323609dee7b98c6fd5 +a2f432d147d904d185ff4b2de8c6b82fbea278a2956bc406855b44c18041854c4f0ecccd472d1d0dff1d8aa8e281cb1d +94a48ad40326f95bd63dff4755f863a1b79e1df771a1173b17937f9baba57b39e651e7695be9f66a472f098b339364fc +a12a0ccd8f96e96e1bc6494341f7ebce959899341b3a084aa1aa87d1c0d489ac908552b7770b887bb47e7b8cbc3d8e66 +81a1f1681bda923bd274bfe0fbb9181d6d164fe738e54e25e8d4849193d311e2c4253614ed673c98af2c798f19a93468 +abf71106a05d501e84cc54610d349d7d5eae21a70bd0250f1bebbf412a130414d1c8dbe673ffdb80208fd72f1defa4d4 +96266dc2e0df18d8136d79f5b59e489978eee0e6b04926687fe389d4293c14f36f055c550657a8e27be4118b64254901 +8df5dcbefbfb4810ae3a413ca6b4bf08619ca53cd50eb1dde2a1c035efffc7b7ac7dff18d403253fd80104bd83dc029e +9610b87ff02e391a43324a7122736876d5b3af2a137d749c52f75d07b17f19900b151b7f439d564f4529e77aa057ad12 +a90a5572198b40fe2fcf47c422274ff36c9624df7db7a89c0eb47eb48a73a03c985f4ac5016161c76ca317f64339bce1 +98e5e61a6ab6462ba692124dba7794b6c6bde4249ab4fcc98c9edd631592d5bc2fb5e38466691a0970a38e48d87c2e43 +918cefb8f292f78d4db81462c633daf73b395e772f47b3a7d2cea598025b1d8c3ec0cbff46cdb23597e74929981cde40 +a98918a5dc7cf610fe55f725e4fd24ce581d594cb957bb9b4e888672e9c0137003e1041f83e3f1d7b9caab06462c87d4 +b92b74ac015262ca66c33f2d950221e19d940ba3bf4cf17845f961dc1729ae227aa9e1f2017829f2135b489064565c29 +a053ee339f359665feb178b4e7ee30a85df37debd17cacc5a27d6b3369d170b0114e67ad1712ed26d828f1df641bcd99 +8c3c8bad510b35da5ce5bd84b35c958797fbea024ad1c97091d2ff71d9b962e9222f65a9b776e5b3cc29c36e1063d2ee +af99dc7330fe7c37e850283eb47cc3257888e7c197cb0d102edf94439e1e02267b6a56306d246c326c4c79f9dc8c6986 +afecb2dc34d57a725efbd7eb93d61eb29dbe8409b668ab9ea040791f5b796d9be6d4fc10d7f627bf693452f330cf0435 +93334fedf19a3727a81a6b6f2459db859186227b96fe7a391263f69f1a0884e4235de64d29edebc7b99c44d19e7c7d7a +89579c51ac405ad7e9df13c904061670ce4b38372492764170e4d3d667ed52e5d15c7cd5c5991bbfa3a5e4e3fa16363e +9778f3e8639030f7ef1c344014f124e375acb8045bd13d8e97a92c5265c52de9d1ffebaa5bc3e1ad2719da0083222991 +88f77f34ee92b3d36791bdf3326532524a67d544297dcf1a47ff00b47c1b8219ff11e34034eab7d23b507caa2fd3c6b9 +a699c1e654e7c484431d81d90657892efeb4adcf72c43618e71ca7bd7c7a7ebbb1db7e06e75b75dc4c74efd306b5df3f +81d13153baebb2ef672b5bdb069d3cd669ce0be96b742c94e04038f689ff92a61376341366b286eee6bf3ae85156f694 +81efb17de94400fdacc1deec2550cbe3eecb27c7af99d8207e2f9be397e26be24a40446d2a09536bb5172c28959318d9 +989b21ebe9ceab02488992673dc071d4d5edec24bff0e17a4306c8cb4b3c83df53a2063d1827edd8ed16d6e837f0d222 +8d6005d6536825661b13c5fdce177cb37c04e8b109b7eb2b6d82ea1cb70efecf6a0022b64f84d753d165edc2bba784a3 +a32607360a71d5e34af2271211652d73d7756d393161f4cf0da000c2d66a84c6826e09e759bd787d4fd0305e2439d342 +aaad8d6f6e260db45d51b2da723be6fa832e76f5fbcb77a9a31e7f090dd38446d3b631b96230d78208cae408c288ac4e +abcfe425255fd3c5cffd3a818af7650190c957b6b07b632443f9e33e970a8a4c3bf79ac9b71f4d45f238a04d1c049857 +aeabf026d4c783adc4414b5923dbd0be4b039cc7201219f7260d321f55e9a5b166d7b5875af6129c034d0108fdc5d666 +af49e740c752d7b6f17048014851f437ffd17413c59797e5078eaaa36f73f0017c3e7da020310cfe7d3c85f94a99f203 +8854ca600d842566e3090040cd66bb0b3c46dae6962a13946f0024c4a8aca447e2ccf6f240045f1ceee799a88cb9210c +b6c03b93b1ab1b88ded8edfa1b487a1ed8bdce8535244dddb558ffb78f89b1c74058f80f4db2320ad060d0c2a9c351cc +b5bd7d17372faff4898a7517009b61a7c8f6f0e7ed4192c555db264618e3f6e57fb30a472d169fea01bf2bf0362a19a8 +96eb1d38319dc74afe7e7eb076fcd230d19983f645abd14a71e6103545c01301b31c47ae931e025f3ecc01fb3d2f31fa +b55a8d30d4403067def9b65e16f867299f8f64c9b391d0846d4780bc196569622e7e5b64ce799b5aefac8f965b2a7a7b +8356d199a991e5cbbff608752b6291731b6b6771aed292f8948b1f41c6543e4ab1bedc82dd26d10206c907c03508df06 +97f4137445c2d98b0d1d478049de952610ad698c91c9d0f0e7227d2aae690e9935e914ec4a2ea1fbf3fc1dddfeeacebb +af5621707e0938320b15ddfc87584ab325fbdfd85c30efea36f8f9bd0707d7ec12c344eff3ec21761189518d192df035 +8ac7817e71ea0825b292687928e349da7140285d035e1e1abff0c3704fa8453faaae343a441b7143a74ec56539687cc4 +8a5e0a9e4758449489df10f3386029ada828d1762e4fb0a8ffe6b79e5b6d5d713cb64ed95960e126398b0cdb89002bc9 +81324be4a71208bbb9bca74b77177f8f1abb9d3d5d9db195d1854651f2cf333cd618d35400da0f060f3e1b025124e4b2 +849971d9d095ae067525b3cbc4a7dfae81f739537ade6d6cec1b42fb692d923176197a8770907c58069754b8882822d6 +89f830825416802477cc81fdf11084885865ee6607aa15aa4eb28e351c569c49b8a1b9b5e95ddc04fa0ebafe20071313 +9240aeeaff37a91af55f860b9badd466e8243af9e8c96a7aa8cf348cd270685ab6301bc135b246dca9eda696f8b0e350 +acf74db78cc33138273127599eba35b0fb4e7b9a69fe02dae18fc6692d748ca332bd00b22afa8e654ed587aab11833f3 +b091e6d37b157b50d76bd297ad752220cd5c9390fac16dc838f8557aed6d9833fc920b61519df21265406216315e883f +a6446c429ebf1c7793c622250e23594c836b2fbcaf6c5b3d0995e1595a37f50ea643f3e549b0be8bbdadd69044d72ab9 +93e675353bd60e996bf1c914d5267eeaa8a52fc3077987ccc796710ef9becc6b7a00e3d82671a6bdfb8145ee3c80245a +a2f731e43251d04ed3364aa2f072d05355f299626f2d71a8a38b6f76cf08c544133f7d72dd0ab4162814b674b9fc7fa6 +97a8b791a5a8f6e1d0de192d78615d73d0c38f1e557e4e15d15adc663d649e655bc8da3bcc499ef70112eafe7fb45c7a +98cd624cbbd6c53a94469be4643c13130916b91143425bcb7d7028adbbfede38eff7a21092af43b12d4fab703c116359 +995783ce38fd5f6f9433027f122d4cf1e1ff3caf2d196ce591877f4a544ce9113ead60de2de1827eaff4dd31a20d79a8 +8cf251d6f5229183b7f3fe2f607a90b4e4b6f020fb4ba2459d28eb8872426e7be8761a93d5413640a661d73e34a5b81f +b9232d99620652a3aa7880cad0876f153ff881c4ed4c0c2e7b4ea81d5d42b70daf1a56b869d752c3743c6d4c947e6641 +849716f938f9d37250cccb1bf77f5f9fde53096cdfc6f2a25536a6187029a8f1331cdbed08909184b201f8d9f04b792f +80c7c4de098cbf9c6d17b14eba1805e433b5bc905f6096f8f63d34b94734f2e4ebf4bce8a177efd1186842a61204a062 +b790f410cf06b9b8daadceeb4fd5ff40a2deda820c8df2537e0a7554613ae3948e149504e3e79aa84889df50c8678eeb +813aab8bd000299cd37485b73cd7cba06e205f8efb87f1efc0bae8b70f6db2bc7702eb39510ad734854fb65515fe9d0f +94f0ab7388ac71cdb67f6b85dfd5945748afb2e5abb622f0b5ad104be1d4d0062b651f134ba22385c9e32c2dfdcccce1 +ab6223dca8bd6a4f969e21ccd9f8106fc5251d321f9e90cc42cea2424b3a9c4e5060a47eeef6b23c7976109b548498e8 +859c56b71343fce4d5c5b87814c47bf55d581c50fd1871a17e77b5e1742f5af639d0e94d19d909ec7dfe27919e954e0c +aae0d632b6191b8ad71b027791735f1578e1b89890b6c22e37de0e4a6074886126988fe8319ae228ac9ef3b3bcccb730 +8ca9f32a27a024c3d595ecfaf96b0461de57befa3b331ab71dc110ec3be5824fed783d9516597537683e77a11d334338 +a061df379fb3f4b24816c9f6cd8a94ecb89b4c6dc6cd81e4b8096fa9784b7f97ab3540259d1de9c02eb91d9945af4823 +998603102ac63001d63eb7347a4bb2bf4cf33b28079bb48a169076a65c20d511ccd3ef696d159e54cc8e772fb5d65d50 +94444d96d39450872ac69e44088c252c71f46be8333a608a475147752dbb99db0e36acfc5198f158509401959c12b709 +ac1b51b6c09fe055c1d7c9176eea9adc33f710818c83a1fbfa073c8dc3a7eb3513cbdd3f5960b7845e31e3e83181e6ba +803d530523fc9e1e0f11040d2412d02baef3f07eeb9b177fa9bfa396af42eea898a4276d56e1db998dc96ae47b644cb2 +85a3c9fc7638f5bf2c3e15ba8c2fa1ae87eb1ceb44c6598c67a2948667a9dfa41e61f66d535b4e7fda62f013a5a8b885 +a961cf5654c46a1a22c29baf7a4e77837a26b7f138f410e9d1883480ed5fa42411d522aba32040b577046c11f007388e +ad1154142344f494e3061ef45a34fab1aaacf5fdf7d1b26adbb5fbc3d795655fa743444e39d9a4119b4a4f82a6f30441 +b1d6c30771130c77806e7ab893b73d4deb590b2ff8f2f8b5e54c2040c1f3e060e2bd99afc668cf706a2df666a508bbf6 +a00361fd440f9decabd98d96c575cd251dc94c60611025095d1201ef2dedde51cb4de7c2ece47732e5ed9b3526c2012c +a85c5ab4d17d328bda5e6d839a9a6adcc92ff844ec25f84981e4f44a0e8419247c081530f8d9aa629c7eb4ca21affba6 +a4ddd3eab4527a2672cf9463db38bc29f61460e2a162f426b7852b7a7645fbd62084fd39a8e4d60e1958cce436dd8f57 +811648140080fe55b8618f4cf17f3c5a250adb0cd53d885f2ddba835d2b4433188e41fc0661faac88e4ff910b16278c0 +b85c7f1cfb0ed29addccf7546023a79249e8f15ac2d14a20accbfef4dd9dc11355d599815fa09d2b6b4e966e6ea8cff1 +a10b5d8c260b159043b020d5dd62b3467df2671afea6d480ca9087b7e60ed170c82b121819d088315902842d66c8fb45 +917e191df1bcf3f5715419c1e2191da6b8680543b1ba41fe84ed07ef570376e072c081beb67b375fca3565a2565bcabb +881fd967407390bfd7badc9ab494e8a287559a01eb07861f527207c127eadea626e9bcc5aa9cca2c5112fbac3b3f0e9c +959fd71149af82cc733619e0e5bf71760ca2650448c82984b3db74030d0e10f8ab1ce1609a6de6f470fe8b5bd90df5b3 +a3370898a1c5f33d15adb4238df9a6c945f18b9ada4ce2624fc32a844f9ece4c916a64e9442225b6592afa06d2e015f2 +817efb8a791435e4236f7d7b278181a5fa34587578c629dbc14fbf9a5c26772290611395eecd20222a4c58649fc256d8 +a04c9876acf2cfdc8ef96de4879742709270fa1d03fe4c8511fbef2d59eb0aaf0336fa2c7dfe41a651157377fa217813 +81e15875d7ea7f123e418edf14099f2e109d4f3a6ce0eb65f67fe9fb10d2f809a864a29f60ad3fc949f89e2596b21783 +b49f529975c09e436e6bc202fdc16e3fdcbe056db45178016ad6fdece9faad4446343e83aed096209690b21a6910724f +879e8eda589e1a279f7f49f6dd0580788c040d973748ec4942dbe51ea8fbd05983cc919b78f0c6b92ef3292ae29db875 +81a2b74b2118923f34139a102f3d95e7eee11c4c2929c2576dee200a5abfd364606158535a6c9e4178a6a83dbb65f3c4 +8913f281d8927f2b45fc815d0f7104631cb7f5f7278a316f1327d670d15868daadd2a64e3eb98e1f53fe7e300338cc80 +a6f815fba7ef9af7fbf45f93bc952e8b351f5de6568a27c7c47a00cb39a254c6b31753794f67940fc7d2e9cc581529f4 +b3722a15c66a0014ce4d082de118def8d39190c15678a472b846225585f3a83756ae1b255b2e3f86a26168878e4773b2 +817ae61ab3d0dd5b6e24846b5a5364b1a7dc2e77432d9fed587727520ae2f307264ea0948c91ad29f0aea3a11ff38624 +b3db467464415fcad36dc1de2d6ba7686772a577cc2619242ac040d6734881a45d3b40ed4588db124e4289cfeec4bbf6 +ad66a14f5a54ac69603b16e5f1529851183da77d3cc60867f10aea41339dd5e06a5257982e9e90a352cdd32750f42ee4 +adafa3681ef45d685555601a25a55cf23358319a17f61e2179e704f63df83a73bdd298d12cf6cef86db89bd17119e11d +a379dc44cb6dd3b9d378c07b2ec654fec7ca2f272de6ba895e3d00d20c9e4c5550498a843c8ac67e4221db2115bedc1c +b7bf81c267a78efc6b9e5a904574445a6487678d7ef70054e3e93ea6a23f966c2b68787f9164918e3b16d2175459ed92 +b41d66a13a4afafd5760062b77f79de7e6ab8ccacde9c6c5116a6d886912fb491dc027af435b1b44aacc6af7b3c887f2 +9904d23a7c1c1d2e4bab85d69f283eb0a8e26d46e8b7b30224438015c936729b2f0af7c7c54c03509bb0500acb42d8a4 +ae30d65e9e20c3bfd603994ae2b175ff691d51f3e24b2d058b3b8556d12ca4c75087809062dddd4aaac81c94d15d8a17 +9245162fab42ac01527424f6013310c3eb462982518debef6c127f46ba8a06c705d7dc9f0a41e796ba8d35d60ae6cc64 +87fab853638d7a29a20f3ba2b1a7919d023e9415bfa78ebb27973d8cbc7626f584dc5665d2e7ad71f1d760eba9700d88 +85aac46ecd330608e5272430970e6081ff02a571e8ea444f1e11785ea798769634a22a142d0237f67b75369d3c484a8a +938c85ab14894cc5dfce3d80456f189a2e98eddbc8828f4ff6b1df1dcb7b42b17ca2ff40226a8a1390a95d63dca698dd +a18ce1f846e3e3c4d846822f60271eecf0f5d7d9f986385ac53c5ace9589dc7c0188910448c19b91341a1ef556652fa9 +8611608a9d844f0e9d7584ad6ccf62a5087a64f764caf108db648a776b5390feb51e5120f0ef0e9e11301af3987dd7dc +8106333ba4b4de8d1ae43bc9735d3fea047392e88efd6a2fa6f7b924a18a7a265ca6123c3edc0f36307dd7fb7fe89257 +a91426fa500951ff1b051a248c050b7139ca30dde8768690432d597d2b3c4357b11a577be6b455a1c5d145264dcf81fc +b7f9f90e0e450f37b081297f7f651bad0496a8b9afd2a4cf4120a2671aaaa8536dce1af301258bfbfdb122afa44c5048 +84126da6435699b0c09fa4032dec73d1fca21d2d19f5214e8b0bea43267e9a8dd1fc44f8132d8315e734c8e2e04d7291 +aff064708103884cb4f1a3c1718b3fc40a238d35cf0a7dc24bdf9823693b407c70da50df585bf5bc4e9c07d1c2d203e8 +a8b40fc6533752983a5329c31d376c7a5c13ce6879cc7faee648200075d9cd273537001fb4c86e8576350eaac6ba60c2 +a02db682bdc117a84dcb9312eb28fcbde12d49f4ce915cc92c610bb6965ec3cc38290f8c5b5ec70afe153956692cda95 +86decd22b25d300508472c9ce75d3e465b737e7ce13bc0fcce32835e54646fe12322ba5bc457be18bfd926a1a6ca4a38 +a18666ef65b8c2904fd598791f5627207165315a85ee01d5fb0e6b2e10bdd9b00babc447da5bd63445e3337de33b9b89 +89bb0c06effadefdaf34ffe4b123e1678a90d4451ee856c863df1e752eef41fd984689ded8f0f878bf8916d5dd8e8024 +97cfcba08ebec05d0073992a66b1d7d6fb9d95871f2cdc36db301f78bf8069294d1c259efef5c93d20dc937eedae3a1a +ac2643b14ece79dcb2e289c96776a47e2bebd40dd6dc74fd035df5bb727b5596f40e3dd2d2202141e69b0993717ede09 +a5e6fd88a2f9174d9bd4c6a55d9c30974be414992f22aa852f552c7648f722ed8077acf5aba030abd47939bb451b2c60 +8ad40a612824a7994487731a40b311b7349038c841145865539c6ada75c56de6ac547a1c23df190e0caaafecddd80ccc +953a7cea1d857e09202c438c6108060961f195f88c32f0e012236d7a4b39d840c61b162ec86436e8c38567328bea0246 +80d8b47a46dae1868a7b8ccfe7029445bbe1009dad4a6c31f9ef081be32e8e1ac1178c3c8fb68d3e536c84990cc035b1 +81ecd99f22b3766ce0aca08a0a9191793f68c754fdec78b82a4c3bdc2db122bbb9ebfd02fc2dcc6e1567a7d42d0cc16a +b1dd0446bccc25846fb95d08c1c9cc52fb51c72c4c5d169ffde56ecfe800f108dc1106d65d5c5bd1087c656de3940b63 +b87547f0931e164e96de5c550ca5aa81273648fe34f6e193cd9d69cf729cb432e17aa02e25b1c27a8a0d20a3b795e94e +820a94e69a927e077082aae66f6b292cfbe4589d932edf9e68e268c9bd3d71ef76cf7d169dd445b93967c25db11f58f1 +b0d07ddf2595270c39adfa0c8cf2ab1322979b0546aa4d918f641be53cd97f36c879bb75d205e457c011aca3bbd9f731 +8700b876b35b4b10a8a9372c5230acecd39539c1bb87515640293ad4464a9e02929d7d6a6a11112e8a29564815ac0de4 +a61a601c5bb27dcb97e37c8e2b9ce479c6b192a5e04d9ed5e065833c5a1017ee5f237b77d1a17be5d48f8e7cc0bcacf6 +92fb88fe774c1ba1d4a08cae3c0e05467ad610e7a3f1d2423fd47751759235fe0a3036db4095bd6404716aa03820f484 +b274f140d77a3ce0796f5e09094b516537ccaf27ae1907099bff172e6368ba85e7c3ef8ea2a07457cac48ae334da95b3 +b2292d9181f16581a9a9142490b2bdcdfb218ca6315d1effc8592100d792eb89d5356996c890441f04f2b4a95763503e +8897e73f576d86bc354baa3bd96e553107c48cf5889dcc23c5ba68ab8bcd4e81f27767be2233fdfa13d39f885087e668 +a29eac6f0829791c728d71abc49569df95a4446ecbfc534b39f24f56c88fe70301838dfc1c19751e7f3c5c1b8c6af6a0 +9346dc3720adc5df500a8df27fd9c75ef38dc5c8f4e8ed66983304750e66d502c3c59b8e955be781b670a0afc70a2167 +9566d534e0e30a5c5f1428665590617e95fd05d45f573715f58157854ad596ece3a3cfec61356aee342308d623e029d5 +a464fb8bffe6bd65f71938c1715c6e296cc6d0311a83858e4e7eb5873b7f2cf0c584d2101e3407b85b64ca78b2ac93ce +b54088f7217987c87e9498a747569ac5b2f8afd5348f9c45bf3fd9fbf713a20f495f49c8572d087efe778ac7313ad6d3 +91fa9f5f8000fe050f5b224d90b59fcce13c77e903cbf98ded752e5b3db16adb2bc1f8c94be48b69f65f1f1ad81d6264 +92d04a5b0ac5d8c8e313709b432c9434ecd3e73231f01e9b4e7952b87df60cbfa97b5dedd2200bd033b4b9ea8ba45cc1 +a94b90ad3c3d6c4bbe169f8661a790c40645b40f0a9d1c7220f01cf7fc176e04d80bab0ced9323fcafb93643f12b2760 +94d86149b9c8443b46196f7e5a3738206dd6f3be7762df488bcbb9f9ee285a64c997ed875b7b16b26604fa59020a8199 +82efe4ae2c50a2d7645240c173a047f238536598c04a2c0b69c96e96bd18e075a99110f1206bc213f39edca42ba00cc1 +ab8667685f831bc14d4610f84a5da27b4ea5b133b4d991741a9e64dceb22cb64a3ce8f1b6e101d52af6296df7127c9ad +83ba433661c05dcc5d562f4a9a261c8110dac44b8d833ae1514b1fc60d8b4ee395b18804baea04cb10adb428faf713c3 +b5748f6f660cc5277f1211d2b8649493ed8a11085b871cd33a5aea630abd960a740f08c08be5f9c21574600ac9bf5737 +a5c8dd12af48fb710642ad65ebb97ca489e8206741807f7acfc334f8035d3c80593b1ff2090c9bb7bd138f0c48714ca8 +a2b382fd5744e3babf454b1d806cc8783efeb4761bc42b6914ea48a46a2eae835efbe0a18262b6bc034379e03cf1262b +b3145ffaf603f69f15a64936d32e3219eea5ed49fdfd2f5bf40ea0dfd974b36fb6ff12164d4c2282d892db4cf3ff3ce1 +87a316fb213f4c5e30c5e3face049db66be4f28821bd96034714ec23d3e97849d7b301930f90a4323c7ccf53de23050c +b9de09a919455070fed6220fc179c8b7a4c753062bcd27acf28f5b9947a659c0b364298daf7c85c4ca6fca7f945add1f +806fbd98d411b76979464c40ad88bc07a151628a27fcc1012ba1dfbaf5b5cc9d962fb9b3386008978a12515edce934bc +a15268877fae0d21610ae6a31061ed7c20814723385955fac09fdc9693a94c33dea11db98bb89fdfe68f933490f5c381 +8d633fb0c4da86b2e0b37d8fad5972d62bff2ac663c5ec815d095cd4b7e1fe66ebef2a2590995b57eaf941983c7ad7a4 +8139e5dd9cf405e8ef65f11164f0440827d98389ce1b418b0c9628be983a9ddd6cf4863036ccb1483b40b8a527acd9ed +88b15fa94a08eac291d2b94a2b30eb851ff24addf2cc30b678e72e32cfcb3424cf4b33aa395d741803f3e578ddf524de +b5eaf0c8506e101f1646bcf049ee38d99ea1c60169730da893fd6020fd00a289eb2f415947e44677af49e43454a7b1be +8489822ad0647a7e06aa2aa5595960811858ddd4542acca419dd2308a8c5477648f4dd969a6740bb78aa26db9bfcc555 +b1e9a7b9f3423c220330d45f69e45fa03d7671897cf077f913c252e3e99c7b1b1cf6d30caad65e4228d5d7b80eb86e5e +b28fe9629592b9e6a55a1406903be76250b1c50c65296c10c5e48c64b539fb08fe11f68cf462a6edcbba71b0cee3feb2 +a41acf96a02c96cd8744ff6577c244fc923810d17ade133587e4c223beb7b4d99fa56eae311a500d7151979267d0895c +880798938fe4ba70721be90e666dfb62fcab4f3556fdb7b0dc8ec5bc34f6b4513df965eae78527136eb391889fe2caf9 +98d4d89d358e0fb7e212498c73447d94a83c1b66e98fc81427ab13acddb17a20f52308983f3a5a8e0aaacec432359604 +81430b6d2998fc78ba937a1639c6020199c52da499f68109da227882dc26d005b73d54c5bdcac1a04e8356a8ca0f7017 +a8d906a4786455eb74613aba4ce1c963c60095ffb8658d368df9266fdd01e30269ce10bf984e7465f34b4fd83beba26a +af54167ac1f954d10131d44a8e0045df00d581dd9e93596a28d157543fbe5fb25d213806ed7fb3cba6b8f5b5423562db +8511e373a978a12d81266b9afbd55035d7bc736835cfa921903a92969eeba3624437d1346b55382e61415726ab84a448 +8cf43eea93508ae586fa9a0f1354a1e16af659782479c2040874a46317f9e8d572a23238efa318fdfb87cc63932602b7 +b0bdd3bacff077173d302e3a9678d1d37936188c7ecc34950185af6b462b7c679815176f3cce5db19aac8b282f2d60ad +a355e9b87f2f2672052f5d4d65b8c1c827d24d89b0d8594641fccfb69aef1b94009105f3242058bb31c8bf51caae5a41 +b8baa9e4b950b72ff6b88a6509e8ed1304bc6fd955748b2e59a523a1e0c5e99f52aec3da7fa9ff407a7adf259652466c +840bc3dbb300ea6f27d1d6dd861f15680bd098be5174f45d6b75b094d0635aced539fa03ddbccb453879de77fb5d1fe9 +b4bc7e7e30686303856472bae07e581a0c0bfc815657c479f9f5931cff208d5c12930d2fd1ff413ebd8424bcd7a9b571 +89b5d514155d7999408334a50822508b9d689add55d44a240ff2bdde2eee419d117031f85e924e2a2c1ca77db9b91eea +a8604b6196f87a04e1350302e8aa745bba8dc162115d22657b37a1d1a98cb14876ddf7f65840b5dbd77e80cd22b4256c +83cb7acdb9e03247515bb2ce0227486ccf803426717a14510f0d59d45e998b245797d356f10abca94f7a14e1a2f0d552 +aeb3266a9f16649210ab2df0e1908ac259f34ce1f01162c22b56cf1019096ee4ea5854c36e30bb2feb06c21a71e8a45c +89e72e86edf2aa032a0fc9acf4d876a40865fbb2c8f87cb7e4d88856295c4ac14583e874142fd0c314a49aba68c0aa3c +8c3576eba0583c2a7884976b4ed11fe1fda4f6c32f6385d96c47b0e776afa287503b397fa516a455b4b8c3afeedc76db +a31e5b633bda9ffa174654fee98b5d5930a691c3c42fcf55673d927dbc8d91c58c4e42e615353145431baa646e8bbb30 +89f2f3f7a8da1544f24682f41c68114a8f78c86bd36b066e27da13acb70f18d9f548773a16bd8e24789420e17183f137 +ada27fa4e90a086240c9164544d2528621a415a5497badb79f8019dc3dce4d12eb6b599597e47ec6ac39c81efda43520 +90dc1eb21bf21c0187f359566fc4bf5386abea52799306a0e5a1151c0817c5f5bc60c86e76b1929c092c0f3ff48cedd2 +b702a53ebcc17ae35d2e735a347d2c700e9cbef8eadbece33cac83df483b2054c126593e1f462cfc00a3ce9d737e2af5 +9891b06455ec925a6f8eafffba05af6a38cc5e193acaaf74ffbf199df912c5197106c5e06d72942bbb032ce277b6417f +8c0ee71eb01197b019275bcf96cae94e81d2cdc3115dbf2d8e3080074260318bc9303597e8f72b18f965ad601d31ec43 +8aaf580aaf75c1b7a5f99ccf60503506e62058ef43b28b02f79b8536a96be3f019c9f71caf327b4e6730134730d1bef5 +ae6f9fc21dd7dfa672b25a87eb0a41644f7609fab5026d5cedb6e43a06dbbfd6d6e30322a2598c8dedde88c52eaed626 +8159b953ffece5693edadb2e906ebf76ff080ee1ad22698950d2d3bfc36ac5ea78f58284b2ca180664452d55bd54716c +ab7647c32ca5e9856ac283a2f86768d68de75ceeba9e58b74c5324f8298319e52183739aba4340be901699d66ac9eb3f +a4d85a5701d89bcfaf1572db83258d86a1a0717603d6f24ac2963ffcf80f1265e5ab376a4529ca504f4396498791253c +816080c0cdbfe61b4d726c305747a9eb58ac26d9a35f501dd32ba43c098082d20faf3ccd41aad24600aa73bfa453dfac +84f3afac024f576b0fd9acc6f2349c2fcefc3f77dbe5a2d4964d14b861b88e9b1810334b908cf3427d9b67a8aee74b18 +94b390655557b1a09110018e9b5a14490681ade275bdc83510b6465a1218465260d9a7e2a6e4ec700f58c31dc3659962 +a8c66826b1c04a2dd4c682543242e7a57acae37278bd09888a3d17747c5b5fec43548101e6f46d703638337e2fd3277b +86e6f4608a00007fa533c36a5b054c5768ccafe41ad52521d772dcae4c8a4bcaff8f7609be30d8fab62c5988cbbb6830 +837da4cf09ae8aa0bceb16f8b3bfcc3b3367aecac9eed6b4b56d7b65f55981ef066490764fb4c108792623ecf8cad383 +941ff3011462f9b5bf97d8cbdb0b6f5d37a1b1295b622f5485b7d69f2cb2bcabc83630dae427f0259d0d9539a77d8424 +b99e5d6d82aa9cf7d5970e7f710f4039ac32c2077530e4c2779250c6b9b373bc380adb0a03b892b652f649720672fc8c +a791c78464b2d65a15440b699e1e30ebd08501d6f2720adbc8255d989a82fcded2f79819b5f8f201bed84a255211b141 +84af7ad4a0e31fcbb3276ab1ad6171429cf39adcf78dc03750dc5deaa46536d15591e26d53e953dfb31e1622bc0743ab +a833e62fe97e1086fae1d4917fbaf09c345feb6bf1975b5cb863d8b66e8d621c7989ab3dbecda36bc9eaffc5eaa6fa66 +b4ef79a46a2126f53e2ebe62770feb57fd94600be29459d70a77c5e9cc260fa892be06cd60f886bf48459e48eb50d063 +b43b8f61919ea380bf151c294e54d3a3ff98e20d1ee5efbfe38aa2b66fafbc6a49739793bd5cb1c809f8b30466277c3a +ab37735af2412d2550e62df9d8b3b5e6f467f20de3890bf56faf1abf2bf3bd1d98dc3fa0ad5e7ab3fce0fa20409eb392 +82416b74b1551d484250d85bb151fabb67e29cce93d516125533df585bc80779ab057ea6992801a3d7d5c6dcff87a018 +8145d0787f0e3b5325190ae10c1d6bee713e6765fb6a0e9214132c6f78f4582bb2771aaeae40d3dad4bafb56bf7e36d8 +b6935886349ecbdd5774e12196f4275c97ec8279fdf28ccf940f6a022ebb6de8e97d6d2173c3fe402cbe9643bed3883b +87ef9b4d3dc71ac86369f8ed17e0dd3b91d16d14ae694bc21a35b5ae37211b043d0e36d8ff07dcc513fb9e6481a1f37f +ae1d0ded32f7e6f1dc8fef495879c1d9e01826f449f903c1e5034aeeabc5479a9e323b162b688317d46d35a42d570d86 +a40d16497004db4104c6794e2f4428d75bdf70352685944f3fbe17526df333e46a4ca6de55a4a48c02ecf0bde8ba03c0 +8d45121efba8cc308a498e8ee39ea6fa5cae9fb2e4aab1c2ff9d448aa8494ccbec9a078f978a86fcd97b5d5e7be7522a +a8173865c64634ba4ac2fa432740f5c05056a9deaf6427cb9b4b8da94ca5ddbc8c0c5d3185a89b8b28878194de9cdfcd +b6ec06a74d690f6545f0f0efba236e63d1fdfba54639ca2617408e185177ece28901c457d02b849fd00f1a53ae319d0a +b69a12df293c014a40070e3e760169b6f3c627caf9e50b35a93f11ecf8df98b2bc481b410eecb7ab210bf213bbe944de +97e7dc121795a533d4224803e591eef3e9008bab16f12472210b73aaf77890cf6e3877e0139403a0d3003c12c8f45636 +acdfa6fdd4a5acb7738cc8768f7cba84dbb95c639399b291ae8e4e63df37d2d4096900a84d2f0606bf534a9ccaa4993f +86ee253f3a9446a33e4d1169719b7d513c6b50730988415382faaf751988c10a421020609f7bcdef91be136704b906e2 +aac9438382a856caf84c5a8a234282f71b5fc5f65219103b147e7e6cf565522285fbfd7417b513bdad8277a00f652ca1 +83f3799d8e5772527930f5dc071a2e0a65471618993ec8990a96ccdeee65270e490bda9d26bb877612475268711ffd80 +93f28a81ac8c0ec9450b9d762fae9c7f8feaace87a6ee6bd141ef1d2d0697ef1bbd159fe6e1de640dbdab2b0361fca8a +a0825c95ba69999b90eac3a31a3fd830ea4f4b2b7409bde5f202b61d741d6326852ce790f41de5cb0eccec7af4db30c1 +83924b0e66233edd603c3b813d698daa05751fc34367120e3cf384ea7432e256ccee4d4daf13858950549d75a377107d +956fd9fa58345277e06ba2ec72f49ed230b8d3d4ff658555c52d6cddeb84dd4e36f1a614f5242d5ca0192e8daf0543c2 +944869912476baae0b114cced4ff65c0e4c90136f73ece5656460626599051b78802df67d7201c55d52725a97f5f29fe +865cb25b64b4531fb6fe4814d7c8cd26b017a6c6b72232ff53defc18a80fe3b39511b23f9e4c6c7249d06e03b2282ed2 +81e09ff55214960775e1e7f2758b9a6c4e4cd39edf7ec1adfaad51c52141182b79fe2176b23ddc7df9fd153e5f82d668 +b31006896f02bc90641121083f43c3172b1039334501fbaf1672f7bf5d174ddd185f945adf1a9c6cf77be34c5501483d +88b92f6f42ae45e9f05b16e52852826e933efd0c68b0f2418ac90957fd018df661bc47c8d43c2a7d7bfcf669dab98c3c +92fc68f595853ee8683930751789b799f397135d002eda244fe63ecef2754e15849edde3ba2f0cc8b865c9777230b712 +99ca06a49c5cd0bb097c447793fcdd809869b216a34c66c78c7e41e8c22f05d09168d46b8b1f3390db9452d91bc96dea +b48b9490a5d65296802431852d548d81047bbefc74fa7dc1d4e2a2878faacdfcb365ae59209cb0ade01901a283cbd15d +aff0fdbef7c188b120a02bc9085d7b808e88f73973773fef54707bf2cd772cd066740b1b6f4127b5c349f657bd97e738 +966fd4463b4f43dd8ccba7ad50baa42292f9f8b2e70da23bb6780e14155d9346e275ef03ddaf79e47020dcf43f3738bd +9330c3e1fadd9e08ac85f4839121ae20bbeb0a5103d84fa5aadbd1213805bdcda67bf2fb75fc301349cbc851b5559d20 +993bb99867bd9041a71a55ad5d397755cfa7ab6a4618fc526179bfc10b7dc8b26e4372fe9a9b4a15d64f2b63c1052dda +a29b59bcfab51f9b3c490a3b96f0bf1934265c315349b236012adbd64a56d7f6941b2c8cc272b412044bc7731f71e1dc +a65c9cefe1fc35d089fe8580c2e7671ebefdb43014ac291528ff4deefd4883fd4df274af83711dad610dad0d615f9d65 +944c78c56fb227ae632805d448ca3884cd3d2a89181cead3d2b7835e63297e6d740aa79a112edb1d4727824991636df5 +a73d782da1db7e4e65d7b26717a76e16dd9fab4df65063310b8e917dc0bc24e0d6755df5546c58504d04d9e68c3b474a +af80f0b87811ae3124f68108b4ca1937009403f87928bbc53480e7c5408d072053ace5eeaf5a5aba814dab8a45502085 +88aaf1acfc6e2e19b8387c97da707cb171c69812fefdd4650468e9b2c627bd5ccfb459f4d8e56bdfd84b09ddf87e128f +92c97276ff6f72bab6e9423d02ad6dc127962dbce15a0dd1e4a393b4510c555df6aa27be0f697c0d847033a9ca8b8dfd +a0e07d43d96e2d85b6276b3c60aadb48f0aedf2de8c415756dc597249ea64d2093731d8735231dadc961e5682ac59479 +adc9e6718a8f9298957d1da3842a7751c5399bbdf56f8de6c1c4bc39428f4aee6f1ba6613d37bf46b9403345e9d6fc81 +951da434da4b20d949b509ceeba02e24da7ed2da964c2fcdf426ec787779c696b385822c7dbea4df3e4a35921f1e912c +a04cbce0d2b2e87bbf038c798a12ec828423ca6aca08dc8d481cf6466e3c9c73d4d4a7fa47df9a7e2e15aae9e9f67208 +8f855cca2e440d248121c0469de1f94c2a71b8ee2682bbad3a78243a9e03da31d1925e6760dbc48a1957e040fae9abe8 +b642e5b17c1df4a4e101772d73851180b3a92e9e8b26c918050f51e6dd3592f102d20b0a1e96f0e25752c292f4c903ff +a92454c300781f8ae1766dbbb50a96192da7d48ef4cbdd72dd8cbb44c6eb5913c112cc38e9144615fdc03684deb99420 +8b74f7e6c2304f8e780df4649ef8221795dfe85fdbdaa477a1542d135b75c8be45bf89adbbb6f3ddf54ca40f02e733e9 +85cf66292cbb30cec5fd835ab10c9fcb3aea95e093aebf123e9a83c26f322d76ebc89c4e914524f6c5f6ee7d74fc917d +ae0bfe0cdc97c09542a7431820015f2d16067b30dca56288013876025e81daa8c519e5e347268e19aa1a85fa1dc28793 +921322fc6a47dc091afa0ad6df18ed14cde38e48c6e71550aa513918b056044983aee402de21051235eecf4ce8040fbe +96c030381e97050a45a318d307dcb3c8377b79b4dd5daf6337cded114de26eb725c14171b9b8e1b3c08fe1f5ea6b49e0 +90c23b86b6111818c8baaf53a13eaee1c89203b50e7f9a994bf0edf851919b48edbac7ceef14ac9414cf70c486174a77 +8bf6c301240d2d1c8d84c71d33a6dfc6d9e8f1cfae66d4d0f7a256d98ae12b0bcebfa94a667735ee89f810bcd7170cff +a41a4ffbbea0e36874d65c009ee4c3feffff322f6fc0e30d26ee4dbc1f46040d05e25d9d0ecb378cef0d24a7c2c4b850 +a8d4cdd423986bb392a0a92c12a8bd4da3437eec6ef6af34cf5310944899287452a2eb92eb5386086d5063381189d10e +a81dd26ec057c4032a4ed7ad54d926165273ed51d09a1267b2e477535cf6966835a257c209e4e92d165d74fa75695fa3 +8d7f708c3ee8449515d94fc26b547303b53d8dd55f177bc3b25d3da2768accd9bc8e9f09546090ebb7f15c66e6c9c723 +839ba65cffcd24cfffa7ab3b21faabe3c66d4c06324f07b2729c92f15cad34e474b0f0ddb16cd652870b26a756b731d3 +87f1a3968afec354d92d77e2726b702847c6afcabb8438634f9c6f7766de4c1504317dc4fa9a4a735acdbf985e119564 +91a8a7fd6542f3e0673f07f510d850864b34ac087eb7eef8845a1d14b2b1b651cbdc27fa4049bdbf3fea54221c5c8549 +aef3cf5f5e3a2385ead115728d7059e622146c3457d266c612e778324b6e06fbfb8f98e076624d2f3ce1035d65389a07 +819915d6232e95ccd7693fdd78d00492299b1983bc8f96a08dcb50f9c0a813ed93ae53c0238345d5bea0beda2855a913 +8e9ba68ded0e94935131b392b28218315a185f63bf5e3c1a9a9dd470944509ca0ba8f6122265f8da851b5cc2abce68f1 +b28468e9b04ee9d69003399a3cf4457c9bf9d59f36ab6ceeb8e964672433d06b58beeea198fedc7edbaa1948577e9fa2 +a633005e2c9f2fd94c8bce2dd5bb708fe946b25f1ec561ae65e54e15cdd88dc339f1a083e01f0d39610c8fe24151aaf0 +841d0031e22723f9328dd993805abd13e0c99b0f59435d2426246996b08d00ce73ab906f66c4eab423473b409e972ce0 +85758d1b084263992070ec8943f33073a2d9b86a8606672550c17545507a5b3c88d87382b41916a87ee96ff55a7aa535 +8581b06b0fc41466ef94a76a1d9fb8ae0edca6d018063acf6a8ca5f4b02d76021902feba58972415691b4bdbc33ae3b4 +83539597ff5e327357ee62bc6bf8c0bcaec2f227c55c7c385a4806f0d37fb461f1690bad5066b8a5370950af32fafbef +aee3557290d2dc10827e4791d00e0259006911f3f3fce4179ed3c514b779160613eca70f720bff7804752715a1266ffa +b48d2f0c4e90fc307d5995464e3f611a9b0ef5fe426a289071f4168ed5cc4f8770c9332960c2ca5c8c427f40e6bb389f +847af8973b4e300bb06be69b71b96183fd1a0b9d51b91701bef6fcfde465068f1eb2b1503b07afda380f18d69de5c9e1 +a70a6a80ce407f07804c0051ac21dc24d794b387be94eb24e1db94b58a78e1bcfb48cd0006db8fc1f9bedaece7a44fbe +b40e942b8fa5336910ff0098347df716bff9d1fa236a1950c16eeb966b3bc1a50b8f7b0980469d42e75ae13ced53cead +b208fabaa742d7db3148515330eb7a3577487845abdb7bd9ed169d0e081db0a5816595c33d375e56aeac5b51e60e49d3 +b7c8194b30d3d6ef5ab66ec88ad7ebbc732a3b8a41731b153e6f63759a93f3f4a537eab9ad369705bd730184bdbbdc34 +9280096445fe7394d04aa1bc4620c8f9296e991cc4d6c131bd703cb1cc317510e6e5855ac763f4d958c5edfe7eebeed7 +abc2aa4616a521400af1a12440dc544e3c821313d0ab936c86af28468ef8bbe534837e364598396a81cf8d06274ed5a6 +b18ca8a3325adb0c8c18a666d4859535397a1c3fe08f95eebfac916a7a99bbd40b3c37b919e8a8ae91da38bc00fa56c0 +8a40c33109ecea2a8b3558565877082f79121a432c45ec2c5a5e0ec4d1c203a6788e6b69cb37f1fd5b8c9a661bc5476d +88c47301dd30998e903c84e0b0f2c9af2e1ce6b9f187dab03528d44f834dc991e4c86d0c474a2c63468cf4020a1e24a0 +920c832853e6ab4c851eecfa9c11d3acc7da37c823be7aa1ab15e14dfd8beb5d0b91d62a30cec94763bd8e4594b66600 +98e1addbe2a6b8edc7f12ecb9be81c3250aeeca54a1c6a7225772ca66549827c15f3950d01b8eb44aecb56fe0fff901a +8cfb0fa1068be0ec088402f5950c4679a2eb9218c729da67050b0d1b2d7079f3ddf4bf0f57d95fe2a8db04bc6bcdb20c +b70f381aafe336b024120453813aeab70baac85b9c4c0f86918797b6aee206e6ed93244a49950f3d8ec9f81f4ac15808 +a4c8edf4aa33b709a91e1062939512419711c1757084e46f8f4b7ed64f8e682f4e78b7135920c12f0eb0422fe9f87a6a +b4817e85fd0752d7ebb662d3a51a03367a84bac74ebddfba0e5af5e636a979500f72b148052d333b3dedf9edd2b4031b +a87430169c6195f5d3e314ff2d1c2f050e766fd5d2de88f5207d72dba4a7745bb86d0baca6e9ae156582d0d89e5838c7 +991b00f8b104566b63a12af4826b61ce7aa40f4e5b8fff3085e7a99815bdb4471b6214da1e480214fac83f86a0b93cc5 +b39966e3076482079de0678477df98578377a094054960ee518ef99504d6851f8bcd3203e8da5e1d4f6f96776e1fe6eb +a448846d9dc2ab7a0995fa44b8527e27f6b3b74c6e03e95edb64e6baa4f1b866103f0addb97c84bef1d72487b2e21796 +894bec21a453ae84b592286e696c35bc30e820e9c2fd3e63dd4fbe629e07df16439c891056070faa490155f255bf7187 +a9ec652a491b11f6a692064e955f3f3287e7d2764527e58938571469a1e29b5225b9415bd602a45074dfbfe9c131d6ca +b39d37822e6cbe28244b5f42ce467c65a23765bd16eb6447c5b3e942278069793763483dafd8c4dd864f8917aad357fe +88dba51133f2019cb266641c56101e3e5987d3b77647a2e608b5ff9113dfc5f85e2b7c365118723131fbc0c9ca833c9c +b566579d904b54ecf798018efcb824dccbebfc6753a0fd2128ac3b4bd3b038c2284a7c782b5ca6f310eb7ea4d26a3f0a +a97a55c0a492e53c047e7d6f9d5f3e86fb96f3dddc68389c0561515343b66b4bc02a9c0d5722dff1e3445308240b27f7 +a044028ab4bcb9e1a2b9b4ca4efbf04c5da9e4bf2fff0e8bd57aa1fc12a71e897999c25d9117413faf2f45395dee0f13 +a78dc461decbeaeed8ebd0909369b491a5e764d6a5645a7dac61d3140d7dc0062526f777b0eb866bff27608429ebbdde +b2c2a8991f94c39ca35fea59f01a92cb3393e0eccb2476dfbf57261d406a68bd34a6cff33ed80209991688c183609ef4 +84189eefb521aff730a4fd3fd5b10ddfd29f0d365664caef63bb015d07e689989e54c33c2141dd64427805d37a7e546e +85ac80bd734a52235da288ff042dea9a62e085928954e8eacd2c751013f61904ed110e5b3afe1ab770a7e6485efb7b5e +9183a560393dcb22d0d5063e71182020d0fbabb39e32493eeffeb808df084aa243eb397027f150b55a247d1ed0c8513e +81c940944df7ecc58d3c43c34996852c3c7915ed185d7654627f7af62abae7e0048dd444a6c09961756455000bd96d09 +aa8c34e164019743fd8284b84f06c3b449aae7996e892f419ee55d82ad548cb300fd651de329da0384243954c0ef6a60 +89a7b7bdfc7e300d06a14d463e573d6296d8e66197491900cc9ae49504c4809ff6e61b758579e9091c61085ba1237b83 +878d21809ba540f50bd11f4c4d9590fb6f3ab9de5692606e6e2ef4ed9d18520119e385be5e1f4b3f2e2b09c319f0e8fc +8eb248390193189cf0355365e630b782cd15751e672dc478b39d75dc681234dcd9309df0d11f4610dbb249c1e6be7ef9 +a1d7fb3aecb896df3a52d6bd0943838b13f1bd039c936d76d03de2044c371d48865694b6f532393b27fd10a4cf642061 +a34bca58a24979be442238cbb5ece5bee51ae8c0794dd3efb3983d4db713bc6f28a96e976ac3bd9a551d3ed9ba6b3e22 +817c608fc8cacdd178665320b5a7587ca21df8bdd761833c3018b967575d25e3951cf3d498a63619a3cd2ad4406f5f28 +86c95707db0495689afd0c2e39e97f445f7ca0edffad5c8b4cacd1421f2f3cc55049dfd504f728f91534e20383955582 +99c3b0bb15942c301137765d4e19502f65806f3b126dc01a5b7820c87e8979bce6a37289a8f6a4c1e4637227ad5bf3bf +8aa1518a80ea8b074505a9b3f96829f5d4afa55a30efe7b4de4e5dbf666897fdd2cf31728ca45921e21a78a80f0e0f10 +8d74f46361c79e15128ac399e958a91067ef4cec8983408775a87eca1eed5b7dcbf0ddf30e66f51780457413496c7f07 +a41cde4a786b55387458a1db95171aca4fd146507b81c4da1e6d6e495527c3ec83fc42fad1dfe3d92744084a664fd431 +8c352852c906fae99413a84ad11701f93f292fbf7bd14738814f4c4ceab32db02feb5eb70bc73898b0bc724a39d5d017 +a5993046e8f23b71ba87b7caa7ace2d9023fb48ce4c51838813174880d918e9b4d2b0dc21a2b9c6f612338c31a289df8 +83576d3324bf2d8afbfb6eaecdc5d767c8e22e7d25160414924f0645491df60541948a05e1f4202e612368e78675de8a +b43749b8df4b15bc9a3697e0f1c518e6b04114171739ef1a0c9c65185d8ec18e40e6954d125cbc14ebc652cf41ad3109 +b4eebd5d80a7327a040cafb9ccdb12b2dfe1aa86e6bc6d3ac8a57fadfb95a5b1a7332c66318ff72ba459f525668af056 +9198be7f1d413c5029b0e1c617bcbc082d21abe2c60ec8ce9b54ca1a85d3dba637b72fda39dae0c0ae40d047eab9f55a +8d96a0232832e24d45092653e781e7a9c9520766c3989e67bbe86b3a820c4bf621ea911e7cd5270a4bfea78b618411f6 +8d7160d0ea98161a2d14d46ef01dff72d566c330cd4fabd27654d300e1bc7644c68dc8eabf2a20a59bfe7ba276545f9b +abb60fce29dec7ba37e3056e412e0ec3e05538a1fc0e2c68877378c867605966108bc5742585ab6a405ce0c962b285b6 +8fabffa3ed792f05e414f5839386f6449fd9f7b41a47595c5d71074bd1bb3784cc7a1a7e1ad6b041b455035957e5b2dc +90ff017b4804c2d0533b72461436b10603ab13a55f86fd4ec11b06a70ef8166f958c110519ca1b4cc7beba440729fe2d +b340cfd120f6a4623e3a74cf8c32bfd7cd61a280b59dfd17b15ca8fae4d82f64a6f15fbde4c02f424debc72b7db5fe67 +871311c9c7220c932e738d59f0ecc67a34356d1429fe570ca503d340c9996cb5ee2cd188fad0e3bd16e4c468ec1dbebd +a772470262186e7b94239ba921b29f2412c148d6f97c4412e96d21e55f3be73f992f1ad53c71008f0558ec3f84e2b5a7 +b2a897dcb7ffd6257f3f2947ec966f2077d57d5191a88840b1d4f67effebe8c436641be85524d0a21be734c63ab5965d +a044f6eacc48a4a061fa149500d96b48cbf14853469aa4d045faf3dca973be1bd4b4ce01646d83e2f24f7c486d03205d +981af5dc2daa73f7fa9eae35a93d81eb6edba4a7f673b55d41f6ecd87a37685d31bb40ef4f1c469b3d72f2f18b925a17 +912d2597a07864de9020ac77083eff2f15ceb07600f15755aba61251e8ce3c905a758453b417f04d9c38db040954eb65 +9642b7f6f09394ba5e0805734ef6702c3eddf9eea187ba98c676d5bbaec0e360e3e51dc58433aaa1e2da6060c8659cb7 +8ab3836e0a8ac492d5e707d056310c4c8e0489ca85eb771bff35ba1d658360084e836a6f51bb990f9e3d2d9aeb18fbb5 +879e058e72b73bb1f4642c21ffdb90544b846868139c6511f299aafe59c2d0f0b944dffc7990491b7c4edcd6a9889250 +b9e60b737023f61479a4a8fd253ed0d2a944ea6ba0439bbc0a0d3abf09b0ad1f18d75555e4a50405470ae4990626f390 +b9c2535d362796dcd673640a9fa2ebdaec274e6f8b850b023153b0a7a30fffc87f96e0b72696f647ebe7ab63099a6963 +94aeff145386a087b0e91e68a84a5ede01f978f9dd9fe7bebca78941938469495dc30a96bba9508c0d017873aeea9610 +98b179f8a3d9f0d0a983c30682dd425a2ddc7803be59bd626c623c8951a5179117d1d2a68254c95c9952989877d0ee55 +889ecf5f0ee56938273f74eb3e9ecfb5617f04fb58e83fe4c0e4aef51615cf345bc56f3f61b17f6eed3249d4afd54451 +a0f2b2c39bcea4b50883e2587d16559e246248a66ecb4a4b7d9ab3b51fb39fe98d83765e087eee37a0f86b0ba4144c02 +b2a61e247ed595e8a3830f7973b07079cbda510f28ad8c78c220b26cb6acde4fbb5ee90c14a665f329168ee951b08cf0 +95bd0fcfb42f0d6d8a8e73d7458498a85bcddd2fb132fd7989265648d82ac2707d6d203fac045504977af4f0a2aca4b7 +843e5a537c298666e6cf50fcc044f13506499ef83c802e719ff2c90e85003c132024e04711be7234c04d4b0125512d5d +a46d1797c5959dcd3a5cfc857488f4d96f74277c3d13b98b133620192f79944abcb3a361d939a100187f1b0856eae875 +a1c7786736d6707a48515c38660615fcec67eb8a2598f46657855215f804fd72ab122d17f94fcffad8893f3be658dca7 +b23dc9e610abc7d8bd21d147e22509a0fa49db5be6ea7057b51aae38e31654b3aa044df05b94b718153361371ba2f622 +b00cc8f257d659c22d30e6d641f79166b1e752ea8606f558e4cad6fc01532e8319ea4ee12265ba4140ac45aa4613c004 +ac7019af65221b0cc736287b32d7f1a3561405715ba9a6a122342e04e51637ba911c41573de53e4781f2230fdcb2475f +81a630bc41b3da8b3eb4bf56cba10cd9f93153c3667f009dc332287baeb707d505fb537e6233c8e53d299ec0f013290c +a6b7aea5c545bb76df0f230548539db92bc26642572cb7dd3d5a30edca2b4c386f44fc8466f056b42de2a452b81aff5b +8271624ff736b7b238e43943c81de80a1612207d32036d820c11fc830c737972ccc9c60d3c2359922b06652311e3c994 +8a684106458cb6f4db478170b9ad595d4b54c18bf63b9058f095a2fa1b928c15101472c70c648873d5887880059ed402 +a5cc3c35228122f410184e4326cf61a37637206e589fcd245cb5d0cec91031f8f7586b80503070840fdfd8ce75d3c88b +9443fc631aed8866a7ed220890911057a1f56b0afe0ba15f0a0e295ab97f604b134b1ed9a4245e46ee5f9a93aa74f731 +984b6f7d79835dffde9558c6bb912d992ca1180a2361757bdba4a7b69dc74b056e303adc69fe67414495dd9c2dd91e64 +b15a5c8cba5de080224c274d31c68ed72d2a7126d347796569aef0c4e97ed084afe3da4d4b590b9dda1a07f0c2ff3dfb +991708fe9650a1f9a4e43938b91d45dc68c230e05ee999c95dbff3bf79b1c1b2bb0e7977de454237c355a73b8438b1d9 +b4f7edc7468b176a4a7c0273700c444fa95c726af6697028bed4f77eee887e3400f9c42ee15b782c0ca861c4c3b8c98a +8c60dcc16c51087eb477c13e837031d6c6a3dc2b8bf8cb43c23f48006bc7173151807e866ead2234b460c2de93b31956 +83ad63e9c910d1fc44bc114accfb0d4d333b7ebe032f73f62d25d3e172c029d5e34a1c9d547273bf6c0fead5c8801007 +85de73213cc236f00777560756bdbf2b16841ba4b55902cf2cad9742ecaf5d28209b012ceb41f337456dfeca93010cd7 +a7561f8827ccd75b6686ba5398bb8fc3083351c55a589b18984e186820af7e275af04bcd4c28e1dc11be1e8617a0610b +88c0a4febd4068850557f497ea888035c7fc9f404f6cc7794e7cc8722f048ad2f249e7dc62743e7a339eb7473ad3b0cd +932b22b1d3e6d5a6409c34980d176feb85ada1bf94332ef5c9fc4d42b907dabea608ceef9b5595ef3feee195151f18d8 +a2867bb3f5ab88fbdae3a16c9143ab8a8f4f476a2643c505bb9f37e5b1fd34d216cab2204c9a017a5a67b7ad2dda10e8 +b573d5f38e4e9e8a3a6fd82f0880dc049efa492a946d00283019bf1d5e5516464cf87039e80aef667cb86fdea5075904 +b948f1b5ab755f3f5f36af27d94f503b070696d793b1240c1bdfd2e8e56890d69e6904688b5f8ff5a4bdf5a6abfe195f +917eae95ebc4109a2e99ddd8fec7881d2f7aaa0e25fda44dec7ce37458c2ee832f1829db7d2dcfa4ca0f06381c7fe91d +95751d17ed00a3030bce909333799bb7f4ab641acf585807f355b51d6976dceee410798026a1a004ef4dcdff7ec0f5b8 +b9b7bd266f449a79bbfe075e429613e76c5a42ac61f01c8f0bbbd34669650682efe01ff9dbbc400a1e995616af6aa278 +ac1722d097ce9cd7617161f8ec8c23d68f1fb1c9ca533e2a8b4f78516c2fd8fb38f23f834e2b9a03bb06a9d655693ca9 +a7ad9e96ffd98db2ecdb6340c5d592614f3c159abfd832fe27ee9293519d213a578e6246aae51672ee353e3296858873 +989b8814d5de7937c4acafd000eec2b4cd58ba395d7b25f98cafd021e8efa37029b29ad8303a1f6867923f5852a220eb +a5bfe6282c771bc9e453e964042d44eff4098decacb89aecd3be662ea5b74506e1357ab26f3527110ba377711f3c9f41 +8900a7470b656639721d2abbb7b06af0ac4222ab85a1976386e2a62eb4b88bfb5b72cf7921ddb3cf3a395d7eeb192a2e +95a71b55cd1f35a438cf5e75f8ff11c5ec6a2ebf2e4dba172f50bfad7d6d5dca5de1b1afc541662c81c858f7604c1163 +82b5d62fea8db8d85c5bc3a76d68dedd25794cf14d4a7bc368938ffca9e09f7e598fdad2a5aac614e0e52f8112ae62b9 +997173f07c729202afcde3028fa7f52cefc90fda2d0c8ac2b58154a5073140683e54c49ed1f254481070d119ce0ce02a +aeffb91ccc7a72bbd6ffe0f9b99c9e66e67d59cec2e02440465e9636a613ab3017278cfa72ea8bc4aba9a8dc728cb367 +952743b06e8645894aeb6440fc7a5f62dd3acf96dab70a51e20176762c9751ea5f2ba0b9497ccf0114dc4892dc606031 +874c63baeddc56fbbca2ff6031f8634b745f6e34ea6791d7c439201aee8f08ef5ee75f7778700a647f3b21068513fce6 +85128fec9c750c1071edfb15586435cc2f317e3e9a175bb8a9697bcda1eb9375478cf25d01e7fed113483b28f625122d +85522c9576fd9763e32af8495ae3928ed7116fb70d4378448926bc9790e8a8d08f98cf47648d7da1b6e40d6a210c7924 +97d0f37a13cfb723b848099ca1c14d83e9aaf2f7aeb71829180e664b7968632a08f6a85f557d74b55afe6242f2a36e7c +abaa472d6ad61a5fccd1a57c01aa1bc081253f95abbcba7f73923f1f11c4e79b904263890eeb66926de3e2652f5d1c70 +b3c04945ba727a141e5e8aec2bf9aa3772b64d8fd0e2a2b07f3a91106a95cbcb249adcd074cbe498caf76fffac20d4ef +82c46781a3d730d9931bcabd7434a9171372dde57171b6180e5516d4e68db8b23495c8ac3ab96994c17ddb1cf249b9fb +a202d8b65613c42d01738ccd68ed8c2dbc021631f602d53f751966e04182743ebc8e0747d600b8a8676b1da9ae7f11ab +ae73e7256e9459db04667a899e0d3ea5255211fb486d084e6550b6dd64ca44af6c6b2d59d7aa152de9f96ce9b58d940d +b67d87b176a9722945ec7593777ee461809861c6cfd1b945dde9ee4ff009ca4f19cf88f4bbb5c80c9cbab2fe25b23ac8 +8f0b7a317a076758b0dac79959ee4a06c08b07d0f10538a4b53d3da2eda16e2af26922feb32c090330dc4d969cf69bd3 +90b36bf56adbd8c4b6cb32febc3a8d5f714370c2ac3305c10fa6d168dffb2a026804517215f9a2d4ec8310cdb6bb459b +aa80c19b0682ead69934bf18cf476291a0beddd8ef4ed75975d0a472e2ab5c70f119722a8574ae4973aceb733d312e57 +a3fc9abb12574e5c28dcb51750b4339b794b8e558675eef7d26126edf1de920c35e992333bcbffcbf6a5f5c0d383ce62 +a1573ff23ab972acdcd08818853b111fc757fdd35aa070186d3e11e56b172fb49d840bf297ac0dd222e072fc09f26a81 +98306f2be4caa92c2b4392212d0cbf430b409b19ff7d5b899986613bd0e762c909fc01999aa94be3bd529d67f0113d7f +8c1fc42482a0819074241746d17dc89c0304a2acdae8ed91b5009e9e3e70ff725ba063b4a3e68fdce05b74f5180c545e +a6c6113ebf72d8cf3163b2b8d7f3fa24303b13f55752522c660a98cd834d85d8c79214d900fa649499365e2e7641f77a +ab95eea424f8a2cfd9fb1c78bb724e5b1d71a0d0d1e4217c5d0f98b0d8bbd3f8400a2002abc0a0e4576d1f93f46fefad +823c5a4fd8cf4a75fdc71d5f2dd511b6c0f189b82affeacd2b7cfcad8ad1a5551227dcc9bfdb2e34b2097eaa00efbb51 +b97314dfff36d80c46b53d87a61b0e124dc94018a0bb680c32765b9a2d457f833a7c42bbc90b3b1520c33a182580398d +b17566ee3dcc6bb3b004afe4c0136dfe7dd27df9045ae896dca49fb36987501ae069eb745af81ba3fc19ff037e7b1406 +b0bdc0f55cfd98d331e3a0c4fbb776a131936c3c47c6bffdc3aaf7d8c9fa6803fbc122c2fefbb532e634228687d52174 +aa5d9e60cc9f0598559c28bb9bdd52aa46605ab4ffe3d192ba982398e72cec9a2a44c0d0d938ce69935693cabc0887ea +802b6459d2354fa1d56c592ac1346c428dadea6b6c0a87bf7d309bab55c94e1cf31dd98a7a86bd92a840dd51f218b91b +a526914efdc190381bf1a73dd33f392ecf01350b9d3f4ae96b1b1c3d1d064721c7d6eec5788162c933245a3943f5ee51 +b3b8fcf637d8d6628620a1a99dbe619eabb3e5c7ce930d6efd2197e261bf394b74d4e5c26b96c4b8009c7e523ccfd082 +8f7510c732502a93e095aba744535f3928f893f188adc5b16008385fb9e80f695d0435bfc5b91cdad4537e87e9d2551c +97b90beaa56aa936c3ca45698f79273a68dd3ccd0076eab48d2a4db01782665e63f33c25751c1f2e070f4d1a8525bf96 +b9fb798324b1d1283fdc3e48288e3861a5449b2ab5e884b34ebb8f740225324af86e4711da6b5cc8361c1db15466602f +b6d52b53cea98f1d1d4c9a759c25bf9d8a50b604b144e4912acbdbdc32aab8b9dbb10d64a29aa33a4f502121a6fb481c +9174ffff0f2930fc228f0e539f5cfd82c9368d26b074467f39c07a774367ff6cccb5039ac63f107677d77706cd431680 +a33b6250d4ac9e66ec51c063d1a6a31f253eb29bbaed12a0d67e2eccfffb0f3a52750fbf52a1c2aaba8c7692346426e7 +a97025fd5cbcebe8ef865afc39cd3ea707b89d4e765ec817fd021d6438e02fa51e3544b1fd45470c58007a08efac6edd +b32a78480edd9ff6ba2f1eec4088db5d6ceb2d62d7e59e904ecaef7bb4a2e983a4588e51692b3be76e6ffbc0b5f911a5 +b5ab590ef0bb77191f00495b33d11c53c65a819f7d0c1f9dc4a2caa147a69c77a4fff7366a602d743ee1f395ce934c1e +b3fb0842f9441fb1d0ee0293b6efbc70a8f58d12d6f769b12872db726b19e16f0f65efbc891cf27a28a248b0ef9c7e75 +9372ad12856fefb928ccb0d34e198df99e2f8973b07e9d417a3134d5f69e12e79ff572c4e03ccd65415d70639bc7c73e +aa8d6e83d09ce216bfe2009a6b07d0110d98cf305364d5529c170a23e693aabb768b2016befb5ada8dabdd92b4d012bb +a954a75791eeb0ce41c85200c3763a508ed8214b5945a42c79bfdcfb1ec4f86ad1dd7b2862474a368d4ac31911a2b718 +8e2081cfd1d062fe3ab4dab01f68062bac802795545fede9a188f6c9f802cb5f884e60dbe866710baadbf55dc77c11a4 +a2f06003b9713e7dd5929501ed485436b49d43de80ea5b15170763fd6346badf8da6de8261828913ee0dacd8ff23c0e1 +98eecc34b838e6ffd1931ca65eec27bcdb2fdcb61f33e7e5673a93028c5865e0d1bf6d3bec040c5e96f9bd08089a53a4 +88cc16019741b341060b95498747db4377100d2a5bf0a5f516f7dec71b62bcb6e779de2c269c946d39040e03b3ae12b7 +ad1135ccbc3019d5b2faf59a688eef2500697642be8cfbdf211a1ab59abcc1f24483e50d653b55ff1834675ac7b4978f +a946f05ed9972f71dfde0020bbb086020fa35b482cce8a4cc36dd94355b2d10497d7f2580541bb3e81b71ac8bba3c49f +a83aeed488f9a19d8cfd743aa9aa1982ab3723560b1cd337fc2f91ad82f07afa412b3993afb845f68d47e91ba4869840 +95eebe006bfc316810cb71da919e5d62c2cebb4ac99d8e8ef67be420302320465f8b69873470982de13a7c2e23516be9 +a55f8961295a11e91d1e5deadc0c06c15dacbfc67f04ccba1d069cba89d72aa3b3d64045579c3ea8991b150ac29366ae +b321991d12f6ac07a5de3c492841d1a27b0d3446082fbce93e7e1f9e8d8fe3b45d41253556261c21b70f5e189e1a7a6f +a0b0822f15f652ce7962a4f130104b97bf9529797c13d6bd8e24701c213cc37f18157bd07f3d0f3eae6b7cd1cb40401f +96e2fa4da378aa782cc2d5e6e465fc9e49b5c805ed01d560e9b98abb5c0de8b74a2e7bec3aa5e2887d25cccb12c66f0c +97e4ab610d414f9210ed6f35300285eb3ccff5b0b6a95ed33425100d7725e159708ea78704497624ca0a2dcabce3a2f9 +960a375b17bdb325761e01e88a3ea57026b2393e1d887b34b8fa5d2532928079ce88dc9fd06a728b26d2bb41b12b9032 +8328a1647398e832aadc05bd717487a2b6fcdaa0d4850d2c4da230c6a2ed44c3e78ec4837b6094f3813f1ee99414713f +aa283834ebd18e6c99229ce4b401eda83f01d904f250fedd4e24f1006f8fa0712a6a89a7296a9bf2ce8de30e28d1408e +b29e097f2caadae3e0f0ae3473c072b0cd0206cf6d2e9b22c1a5ad3e07d433e32bd09ed1f4e4276a2da4268633357b7f +9539c5cbba14538b2fe077ecf67694ef240da5249950baaabea0340718b882a966f66d97f08556b08a4320ceb2cc2629 +b4529f25e9b42ae8cf8338d2eface6ba5cd4b4d8da73af502d081388135c654c0b3afb3aa779ffc80b8c4c8f4425dd2b +95be0739c4330619fbe7ee2249c133c91d6c07eab846c18c5d6c85fc21ac5528c5d56dcb0145af68ed0c6a79f68f2ccd +ac0c83ea802227bfc23814a24655c9ff13f729619bcffdb487ccbbf029b8eaee709f8bddb98232ef33cd70e30e45ca47 +b503becb90acc93b1901e939059f93e671900ca52c6f64ae701d11ac891d3a050b505d89324ce267bc43ab8275da6ffe +98e3811b55b1bacb70aa409100abb1b870f67e6d059475d9f278c751b6e1e2e2d6f2e586c81a9fb6597fda06e7923274 +b0b0f61a44053fa6c715dbb0731e35d48dba257d134f851ee1b81fd49a5c51a90ebf5459ec6e489fce25da4f184fbdb1 +b1d2117fe811720bb997c7c93fe9e4260dc50fca8881b245b5e34f724aaf37ed970cdad4e8fcb68e05ac8cf55a274a53 +a10f502051968f14b02895393271776dee7a06db9de14effa0b3471825ba94c3f805302bdddac4d397d08456f620999d +a3dbad2ef060ae0bb7b02eaa4a13594f3f900450faa1854fc09620b01ac94ab896321dfb1157cf2374c27e5718e8026a +b550fdec503195ecb9e079dcdf0cad559d64d3c30818ef369b4907e813e689da316a74ad2422e391b4a8c2a2bef25fc0 +a25ba865e2ac8f28186cea497294c8649a201732ecb4620c4e77b8e887403119910423df061117e5f03fc5ba39042db1 +b3f88174e03fdb443dd6addd01303cf88a4369352520187c739fc5ae6b22fa99629c63c985b4383219dab6acc5f6f532 +97a7503248e31e81b10eb621ba8f5210c537ad11b539c96dfb7cf72b846c7fe81bd7532c5136095652a9618000b7f8d3 +a8bcdc1ce5aa8bfa683a2fc65c1e79de8ff5446695dcb8620f7350c26d2972a23da22889f9e2b1cacb3f688c6a2953dc +8458c111df2a37f5dd91a9bee6c6f4b79f4f161c93fe78075b24a35f9817da8dde71763218d627917a9f1f0c4709c1ed +ac5f061a0541152b876cbc10640f26f1cc923c9d4ae1b6621e4bb3bf2cec59bbf87363a4eb72fb0e5b6d4e1c269b52d5 +a9a25ca87006e8a9203cbb78a93f50a36694aa4aad468b8d80d3feff9194455ca559fcc63838128a0ab75ad78c07c13a +a450b85f5dfffa8b34dfd8bc985f921318efacf8857cf7948f93884ba09fb831482ee90a44224b1a41e859e19b74962f +8ed91e7f92f5c6d7a71708b6132f157ac226ecaf8662af7d7468a4fa25627302efe31e4620ad28719318923e3a59bf82 +ab524165fd4c71b1fd395467a14272bd2b568592deafa039d8492e9ef36c6d3f96927c95c72d410a768dc0b6d1fbbc9b +b662144505aa8432c75ffb8d10318526b6d5777ac7af9ebfad87d9b0866c364f7905a6352743bd8fd79ffd9d5dd4f3e6 +a48f1677550a5cd40663bb3ba8f84caaf8454f332d0ceb1d94dbea52d0412fe69c94997f7749929712fd3995298572f7 +8391cd6e2f6b0c242de1117a612be99776c3dc95cb800b187685ea5bf7e2722275eddb79fd7dfc8be8e389c4524cdf70 +875d3acb9af47833b72900bc0a2448999d638f153c5e97e8a14ec02d0c76f6264353a7e275e1f1a5855daced523d243b +91f1823657d30b59b2f627880a9a9cb530f5aca28a9fd217fe6f2f5133690dfe7ad5a897872e400512db2e788b3f7628 +ad3564332aa56cea84123fc7ca79ea70bb4fef2009fa131cb44e4b15e8613bd11ca1d83b9d9bf456e4b7fee9f2e8b017 +8c530b84001936d5ab366c84c0b105241a26d1fb163669f17c8f2e94776895c2870edf3e1bc8ccd04d5e65531471f695 +932d01fa174fdb0c366f1230cffde2571cc47485f37f23ba5a1825532190cc3b722aeb1f15aed62cf83ccae9403ba713 +88b28c20585aca50d10752e84b901b5c2d58efef5131479fbbe53de7bce2029e1423a494c0298e1497669bd55be97a5d +b914148ca717721144ebb3d3bf3fcea2cd44c30c5f7051b89d8001502f3856fef30ec167174d5b76265b55d70f8716b5 +81d0173821c6ddd2a068d70766d9103d1ee961c475156e0cbd67d54e668a796310474ef698c7ab55abe6f2cf76c14679 +8f28e8d78e2fe7fa66340c53718e0db4b84823c8cfb159c76eac032a62fb53da0a5d7e24ca656cf9d2a890cb2a216542 +8a26360335c73d1ab51cec3166c3cf23b9ea51e44a0ad631b0b0329ef55aaae555420348a544e18d5760969281759b61 +94f326a32ed287545b0515be9e08149eb0a565025074796d72387cc3a237e87979776410d78339e23ef3172ca43b2544 +a785d2961a2fa5e70bffa137858a92c48fe749fee91b02599a252b0cd50d311991a08efd7fa5e96b78d07e6e66ffe746 +94af9030b5ac792dd1ce517eaadcec1482206848bea4e09e55cc7f40fd64d4c2b3e9197027c5636b70d6122c51d2235d +9722869f7d1a3992850fe7be405ec93aa17dc4d35e9e257d2e469f46d2c5a59dbd504056c85ab83d541ad8c13e8bcd54 +b13c4088b61a06e2c03ac9813a75ff1f68ffdfee9df6a8f65095179a475e29cc49119cad2ce05862c3b1ac217f3aace9 +8c64d51774753623666b10ca1b0fe63ae42f82ed6aa26b81dc1d48c86937c5772eb1402624c52a154b86031854e1fb9f +b47e4df18002b7dac3fee945bf9c0503159e1b8aafcce2138818e140753011b6d09ef1b20894e08ba3006b093559061b +93cb5970076522c5a0483693f6a35ffd4ea2aa7aaf3730c4eccd6af6d1bebfc1122fc4c67d53898ae13eb6db647be7e2 +a68873ef80986795ea5ed1a597d1cd99ed978ec25e0abb57fdcc96e89ef0f50aeb779ff46e3dce21dc83ada3157a8498 +8cab67f50949cc8eee6710e27358aea373aae3c92849f8f0b5531c080a6300cdf2c2094fe6fecfef6148de0d28446919 +993e932bcb616dbaa7ad18a4439e0565211d31071ef1b85a0627db74a05d978c60d507695eaeea5c7bd9868a21d06923 +acdadff26e3132d9478a818ef770e9fa0d2b56c6f5f48bd3bd674436ccce9bdfc34db884a73a30c04c5f5e9764cb2218 +a0d3e64c9c71f84c0eef9d7a9cb4fa184224b969db5514d678e93e00f98b41595588ca802643ea225512a4a272f5f534 +91c9140c9e1ba6e330cb08f6b2ce4809cd0d5a0f0516f70032bf30e912b0ed684d07b413b326ab531ee7e5b4668c799b +87bc2ee7a0c21ba8334cd098e35cb703f9af57f35e091b8151b9b63c3a5b0f89bd7701dbd44f644ea475901fa6d9ef08 +9325ccbf64bf5d71b303e31ee85d486298f9802c5e55b2c3d75427097bf8f60fa2ab4fcaffa9b60bf922c3e24fbd4b19 +95d0506e898318f3dc8d28d16dfd9f0038b54798838b3c9be2a2ae3c2bf204eb496166353fc042220b0bd4f6673b9285 +811de529416331fe9c416726d45df9434c29dcd7e949045eb15740f47e97dde8f31489242200e19922cac2a8b7c6fd1f +ade632d04a4c8bbab6ca7df370b2213cb9225023e7973f0e29f4f5e52e8aeaabc65171306bbdd12a67b195dfbb96d48f +88b7f029e079b6ae956042c0ea75d53088c5d0efd750dd018adaeacf46be21bf990897c58578c491f41afd3978d08073 +91f477802de507ffd2be3f4319903119225b277ad24f74eb50f28b66c14d32fae53c7edb8c7590704741af7f7f3e3654 +809838b32bb4f4d0237e98108320d4b079ee16ed80c567e7548bd37e4d7915b1192880f4812ac0e00476d246aec1dbc8 +84183b5fc4a7997a8ae5afedb4d21dce69c480d5966b5cbdafd6dd10d29a9a6377f3b90ce44da0eb8b176ac3af0253bb +8508abbf6d3739a16b9165caf0f95afb3b3ac1b8c38d6d374cf0c91296e2c1809a99772492b539cda184510bce8a0271 +8722054e59bab2062e6419a6e45fc803af77fde912ef2cd23055ad0484963de65a816a2debe1693d93c18218d2b8e81a +8e895f80e485a7c4f56827bf53d34b956281cdc74856c21eb3b51f6288c01cc3d08565a11cc6f3e2604775885490e8c5 +afc92714771b7aa6e60f3aee12efd9c2595e9659797452f0c1e99519f67c8bc3ac567119c1ddfe82a3e961ee9defea9a +818ff0fd9cefd32db87b259e5fa32967201016fc02ef44116cdca3c63ce5e637756f60477a408709928444a8ad69c471 +8251e29af4c61ae806fc5d032347fb332a94d472038149225298389495139ce5678fae739d02dfe53a231598a992e728 +a0ea39574b26643f6f1f48f99f276a8a64b5481989cfb2936f9432a3f8ef5075abfe5c067dc5512143ce8bf933984097 +af67a73911b372bf04e57e21f289fc6c3dfac366c6a01409b6e76fea4769bdb07a6940e52e8d7d3078f235c6d2f632c6 +b5291484ef336024dd2b9b4cf4d3a6b751133a40656d0a0825bcc6d41c21b1c79cb50b0e8f4693f90c29c8f4358641f9 +8bc0d9754d70f2cb9c63f991902165a87c6535a763d5eece43143b5064ae0bcdce7c7a8f398f2c1c29167b2d5a3e6867 +8d7faff53579ec8f6c92f661c399614cc35276971752ce0623270f88be937c414eddcb0997e14724a783905a026c8883 +9310b5f6e675fdf60796f814dbaa5a6e7e9029a61c395761e330d9348a7efab992e4e115c8be3a43d08e90d21290c892 +b5eb4f3eb646038ad2a020f0a42202532d4932e766da82b2c1002bf9c9c2e5336b54c8c0ffcc0e02d19dde2e6a35b6cc +91dabfd30a66710f1f37a891136c9be1e23af4abf8cb751f512a40c022a35f8e0a4fb05b17ec36d4208de02d56f0d53a +b3ded14e82d62ac7a5a036122a62f00ff8308498f3feae57d861babaff5a6628d43f0a0c5fc903f10936bcf4e2758ceb +a88e8348fed2b26acca6784d19ef27c75963450d99651d11a950ea81d4b93acd2c43e0ecce100eaf7e78508263d5baf3 +b1f5bbf7c4756877b87bb42163ac570e08c6667c4528bf68b5976680e19beeff7c5effd17009b0718797077e2955457a +ad2e7b516243f915d4d1415326e98b1a7390ae88897d0b03b66c2d9bd8c3fba283d7e8fe44ed3333296a736454cef6d8 +8f82eae096d5b11f995de6724a9af895f5e1c58d593845ad16ce8fcae8507e0d8e2b2348a0f50a1f66a17fd6fac51a5c +890e4404d0657c6c1ee14e1aac132ecf7a568bb3e04137b85ac0f84f1d333bd94993e8750f88eee033a33fb00f85dcc7 +82ac7d3385e035115f1d39a99fc73e5919de44f5e6424579776d118d711c8120b8e5916372c6f27bed4cc64cac170b6c +85ee16d8901c272cfbbe966e724b7a891c1bd5e68efd5d863043ad8520fc409080af61fd726adc680b3f1186fe0ac8b8 +86dc564c9b545567483b43a38f24c41c6551a49cabeebb58ce86404662a12dbfafd0778d30d26e1c93ce222e547e3898 +a29f5b4522db26d88f5f95f18d459f8feefab02e380c2edb65aa0617a82a3c1a89474727a951cef5f15050bcf7b380fb +a1ce039c8f6cac53352899edb0e3a72c76da143564ad1a44858bd7ee88552e2fe6858d1593bbd74aeee5a6f8034b9b9d +97f10d77983f088286bd7ef3e7fdd8fa275a56bec19919adf33cf939a90c8f2967d2b1b6fc51195cb45ad561202a3ed7 +a25e2772e8c911aaf8712bdac1dd40ee061c84d3d224c466cfaae8e5c99604053f940cde259bd1c3b8b69595781dbfec +b31bb95a0388595149409c48781174c340960d59032ab2b47689911d03c68f77a2273576fbe0c2bf4553e330656058c7 +b8b2e9287ad803fb185a13f0d7456b397d4e3c8ad5078f57f49e8beb2e85f661356a3392dbd7bcf6a900baa5582b86a1 +a3d0893923455eb6e96cc414341cac33d2dbc88fba821ac672708cce131761d85a0e08286663a32828244febfcae6451 +82310cb42f647d99a136014a9f881eb0b9791efd2e01fc1841907ad3fc8a9654d3d1dab6689c3607214b4dc2aca01cee +874022d99c16f60c22de1b094532a0bc6d4de700ad01a31798fac1d5088b9a42ad02bef8a7339af7ed9c0d4f16b186ee +94981369e120265aed40910eebc37eded481e90f4596b8d57c3bec790ab7f929784bd33ddd05b7870aad6c02e869603b +a4f1f50e1e2a73f07095e0dd31cb45154f24968dae967e38962341c1241bcd473102fff1ff668b20c6547e9732d11701 +ae2328f3b0ad79fcda807e69a1b5278145225083f150f67511dafc97e079f860c3392675f1752ae7e864c056e592205b +875d8c971e593ca79552c43d55c8c73b17cd20c81ff2c2fed1eb19b1b91e4a3a83d32df150dbfd5db1092d0aebde1e1f +add2e80aa46aae95da73a11f130f4bda339db028e24c9b11e5316e75ba5e63bc991d2a1da172c7c8e8fee038baae3433 +b46dbe1cb3424002aa7de51e82f600852248e251465c440695d52538d3f36828ff46c90ed77fc1d11534fe3c487df8ef +a5e5045d28b4e83d0055863c30c056628c58d4657e6176fd0536f5933f723d60e851bb726d5bf3c546b8ce4ac4a57ef8 +91fec01e86dd1537e498fff7536ea3ca012058b145f29d9ada49370cd7b7193ac380e116989515df1b94b74a55c45df3 +a7428176d6918cd916a310bdc75483c72de660df48cac4e6e7478eef03205f1827ea55afc0df5d5fa7567d14bbea7fc9 +851d89bef45d9761fe5fdb62972209335193610015e16a675149519f9911373bac0919add226ef118d9f3669cfdf4734 +b74acf5c149d0042021cb2422ea022be4c4f72a77855f42393e71ffd12ebb3eec16bdf16f812159b67b79a9706e7156d +99f35dce64ec99aa595e7894b55ce7b5a435851b396e79036ffb249c28206087db4c85379df666c4d95857db02e21ff9 +b6b9a384f70db9e298415b8ab394ee625dafff04be2886476e59df8d052ca832d11ac68a9b93fba7ab055b7bc36948a4 +898ee4aefa923ffec9e79f2219c7389663eb11eb5b49014e04ed4a336399f6ea1691051d86991f4c46ca65bcd4fdf359 +b0f948217b0d65df7599a0ba4654a5e43c84db477936276e6f11c8981efc6eaf14c90d3650107ed4c09af4cc8ec11137 +aa6286e27ac54f73e63dbf6f41865dd94d24bc0cf732262fcaff67319d162bb43af909f6f8ee27b1971939cfbba08141 +8bca7cdf730cf56c7b2c8a2c4879d61361a6e1dba5a3681a1a16c17a56e168ace0e99cf0d15826a1f5e67e6b8a8a049a +a746d876e8b1ce225fcafca603b099b36504846961526589af977a88c60d31ba2cc56e66a3dec8a77b3f3531bf7524c9 +a11e2e1927e6704cdb8874c75e4f1842cef84d7d43d7a38e339e61dc8ba90e61bbb20dd3c12e0b11d2471d58eed245be +a36395e22bc1d1ba8b0459a235203177737397da5643ce54ded3459d0869ff6d8d89f50c73cb62394bf66a959cde9b90 +8b49f12ba2fdf9aca7e5f81d45c07d47f9302a2655610e7634d1e4bd16048381a45ef2c95a8dd5b0715e4b7cf42273af +91cffa2a17e64eb7f76bccbe4e87280ee1dd244e04a3c9eac12e15d2d04845d876eb24fe2ec6d6d266cce9efb281077f +a6b8afabf65f2dee01788114e33a2f3ce25376fb47a50b74da7c3c25ff1fdc8aa9f41307534abbf48acb6f7466068f69 +8d13db896ccfea403bd6441191995c1a65365cab7d0b97fbe9526da3f45a877bd1f4ef2edef160e8a56838cd1586330e +98c717de9e01bef8842c162a5e757fe8552d53269c84862f4d451e7c656ae6f2ae473767b04290b134773f63be6fdb9d +8c2036ace1920bd13cf018e82848c49eb511fad65fd0ff51f4e4b50cf3bfc294afb63cba682c16f52fb595a98fa84970 +a3520fdff05dbad9e12551b0896922e375f9e5589368bcb2cc303bde252743b74460cb5caf99629325d3620f13adc796 +8d4f83a5bfec05caf5910e0ce538ee9816ee18d0bd44c1d0da2a87715a23cd2733ad4d47552c6dc0eb397687d611dd19 +a7b39a0a6a02823452d376533f39d35029867b3c9a6ad6bca181f18c54132d675613a700f9db2440fb1b4fa13c8bf18a +80bcb114b2544b80f404a200fc36860ed5e1ad31fe551acd4661d09730c452831751baa9b19d7d311600d267086a70bc +90dcce03c6f88fc2b08f2b42771eedde90cc5330fe0336e46c1a7d1b5a6c1641e5fcc4e7b3d5db00bd8afca9ec66ed81 +aec15f40805065c98e2965b1ae12a6c9020cfdb094c2d0549acfc7ea2401a5fb48d3ea7d41133cf37c4e096e7ff53eb9 +80e129b735dba49fa627a615d6c273119acec8e219b2f2c4373a332b5f98d66cbbdd688dfbe72a8f8bfefaccc02c50c1 +a9b596da3bdfe23e6799ece5f7975bf7a1979a75f4f546deeaf8b34dfe3e0d623217cb4cf4ccd504cfa3625b88cd53f1 +abcbbb70b16f6e517c0ab4363ab76b46e4ff58576b5f8340e5c0e8cc0e02621b6e23d742d73b015822a238b17cfd7665 +a046937cc6ea6a2e1adae543353a9fe929c1ae4ad655be1cc051378482cf88b041e28b1e9a577e6ccff2d3570f55e200 +831279437282f315e65a60184ef158f0a3dddc15a648dc552bdc88b3e6fe8288d3cfe9f0031846d81350f5e7874b4b33 +993d7916fa213c6d66e7c4cafafc1eaec9a2a86981f91c31eb8a69c5df076c789cbf498a24c84e0ee77af95b42145026 +823907a3b6719f8d49b3a4b7c181bd9bb29fcf842d7c70660c4f351852a1e197ca46cf5e879b47fa55f616fa2b87ce5e +8d228244e26132b234930ee14c75d88df0943cdb9c276a8faf167d259b7efc1beec2a87c112a6c608ad1600a239e9aae +ab6e55766e5bfb0cf0764ed909a8473ab5047d3388b4f46faeba2d1425c4754c55c6daf6ad4751e634c618b53e549529 +ab0cab6860e55a84c5ad2948a7e0989e2b4b1fd637605634b118361497332df32d9549cb854b2327ca54f2bcb85eed8f +b086b349ae03ef34f4b25a57bcaa5d1b29bd94f9ebf87e22be475adfe475c51a1230c1ebe13506cb72c4186192451658 +8a0b49d8a254ca6d91500f449cbbfbb69bb516c6948ac06808c65595e46773e346f97a5ce0ef7e5a5e0de278af22709c +ac49de11edaaf04302c73c578cc0824bdd165c0d6321be1c421c1950e68e4f3589aa3995448c9699e93c6ebae8803e27 +884f02d841cb5d8f4c60d1402469216b114ab4e93550b5bc1431756e365c4f870a9853449285384a6fa49e12ce6dc654 +b75f3a28fa2cc8d36b49130cb7448a23d73a7311d0185ba803ad55c8219741d451c110f48b786e96c728bc525903a54f +80ae04dbd41f4a35e33f9de413b6ad518af0919e5a30cb0fa1b061b260420780bb674f828d37fd3b52b5a31673cbd803 +b9a8011eb5fcea766907029bf743b45262db3e49d24f84503687e838651ed11cb64c66281e20a0ae9f6aa51acc552263 +90bfdd75e2dc9cf013e22a5d55d2d2b8a754c96103a17524488e01206e67f8b6d52b1be8c4e3d5307d4fe06d0e51f54c +b4af353a19b06203a815ec43e79a88578cc678c46f5a954b85bc5c53b84059dddba731f3d463c23bfd5273885c7c56a4 +aa125e96d4553b64f7140e5453ff5d2330318b69d74d37d283e84c26ad672fa00e3f71e530eb7e28be1e94afb9c4612e +a18e060aee3d49cde2389b10888696436bb7949a79ca7d728be6456a356ea5541b55492b2138da90108bd1ce0e6f5524 +93e55f92bdbccc2de655d14b1526836ea2e52dba65eb3f87823dd458a4cb5079bf22ce6ef625cb6d6bfdd0995ab9a874 +89f5a683526b90c1c3ceebbb8dc824b21cff851ce3531b164f6626e326d98b27d3e1d50982e507d84a99b1e04e86a915 +83d1c38800361633a3f742b1cb2bfc528129496e80232611682ddbe403e92c2ac5373aea0bca93ecb5128b0b2b7a719e +8ecba560ac94905e19ce8d9c7af217bf0a145d8c8bd38e2db82f5e94cc3f2f26f55819176376b51f154b4aab22056059 +a7e2a4a002b60291924850642e703232994acb4cfb90f07c94d1e0ecd2257bb583443283c20fc6017c37e6bfe85b7366 +93ed7316fa50b528f1636fc6507683a672f4f4403e55e94663f91221cc198199595bd02eef43d609f451acc9d9b36a24 +a1220a8ebc5c50ceed76a74bc3b7e0aa77f6884c71b64b67c4310ac29ce5526cb8992d6abc13ef6c8413ce62486a6795 +b2f6eac5c869ad7f4a25161d3347093e2f70e66cd925032747e901189355022fab3038bca4d610d2f68feb7e719c110b +b703fa11a4d511ca01c7462979a94acb40b5d933759199af42670eb48f83df202fa0c943f6ab3b4e1cc54673ea3aab1e +b5422912afbfcb901f84791b04f1ddb3c3fbdc76d961ee2a00c5c320e06d3cc5b5909c3bb805df66c5f10c47a292b13d +ad0934368da823302e1ac08e3ede74b05dfdbfffca203e97ffb0282c226814b65c142e6e15ec1e754518f221f01b30f7 +a1dd302a02e37df15bf2f1147efe0e3c06933a5a767d2d030e1132f5c3ce6b98e216b6145eb39e1e2f74e76a83165b8d +a346aab07564432f802ae44738049a36f7ca4056df2d8f110dbe7fef4a3e047684dea609b2d03dc6bf917c9c2a47608f +b96c5f682a5f5d02123568e50f5d0d186e4b2c4c9b956ec7aabac1b3e4a766d78d19bd111adb5176b898e916e49be2aa +8a96676d56876fc85538db2e806e1cba20fd01aeb9fa3cb43ca6ca94a2c102639f65660db330e5d74a029bb72d6a0b39 +ab0048336bd5c3def1a4064eadd49e66480c1f2abb4df46e03afbd8a3342c2c9d74ee35d79f08f4768c1646681440984 +888427bdf76caec90814c57ee1c3210a97d107dd88f7256f14f883ad0f392334b82be11e36dd8bfec2b37935177c7831 +b622b282becf0094a1916fa658429a5292ba30fb48a4c8066ce1ddcefb71037948262a01c95bab6929ed3a76ba5db9fe +b5b9e005c1f456b6a368a3097634fb455723abe95433a186e8278dceb79d4ca2fbe21f8002e80027b3c531e5bf494629 +a3c6707117a1e48697ed41062897f55d8119403eea6c2ee88f60180f6526f45172664bfee96bf61d6ec0b7fbae6aa058 +b02a9567386a4fbbdb772d8a27057b0be210447348efe6feb935ceec81f361ed2c0c211e54787dc617cdffed6b4a6652 +a9b8364e40ef15c3b5902e5534998997b8493064fa2bea99600def58279bb0f64574c09ba11e9f6f669a8354dd79dc85 +9998a2e553a9aa9a206518fae2bc8b90329ee59ab23005b10972712389f2ec0ee746033c733092ffe43d73d33abbb8ef +843a4b34d9039bf79df96d79f2d15e8d755affb4d83d61872daf540b68c0a3888cf8fc00d5b8b247b38524bcb3b5a856 +84f7128920c1b0bb40eee95701d30e6fc3a83b7bb3709f16d97e72acbb6057004ee7ac8e8f575936ca9dcb7866ab45f7 +918d3e2222e10e05edb34728162a899ad5ada0aaa491aeb7c81572a9c0d506e31d5390e1803a91ff3bd8e2bb15d47f31 +9442d18e2489613a7d47bb1cb803c8d6f3259d088cd079460976d87f7905ee07dea8f371b2537f6e1d792d36d7e42723 +b491976970fe091995b2ed86d629126523ccf3e9daf8145302faca71b5a71a5da92e0e05b62d7139d3efac5c4e367584 +aa628006235dc77c14cef4c04a308d66b07ac92d377df3de1a2e6ecfe3144f2219ad6d7795e671e1cb37a3641910b940 +99d386adaea5d4981d7306feecac9a555b74ffdc218c907c5aa7ac04abaead0ec2a8237300d42a3fbc464673e417ceed +8f78e8b1556f9d739648ea3cab9606f8328b52877fe72f9305545a73b74d49884044ba9c1f1c6db7d9b7c7b7c661caba +8fb357ae49932d0babdf74fc7aa7464a65d3b6a2b3acf4f550b99601d3c0215900cfd67f2b6651ef94cfc323bac79fae +9906f2fa25c0290775aa001fb6198113d53804262454ae8b83ef371b5271bde189c0460a645829cb6c59f9ee3a55ce4d +8f4379b3ebb50e052325b27655ca6a82e6f00b87bf0d2b680d205dd2c7afdc9ff32a9047ae71a1cdf0d0ce6b9474d878 +a85534e88c2bd43c043792eaa75e50914b21741a566635e0e107ae857aed0412035f7576cf04488ade16fd3f35fdbb87 +b4ce93199966d3c23251ca7f28ec5af7efea1763d376b0385352ffb2e0a462ef95c69940950278cf0e3dafd638b7bd36 +b10cb3d0317dd570aa73129f4acf63c256816f007607c19b423fb42f65133ce21f2f517e0afb41a5378cccf893ae14d0 +a9b231c9f739f7f914e5d943ed9bff7eba9e2c333fbd7c34eb1648a362ee01a01af6e2f7c35c9fe962b11152cddf35de +99ff6a899e156732937fb81c0cced80ae13d2d44c40ba99ac183aa246103b31ec084594b1b7feb96da58f4be2dd5c0ed +8748d15d18b75ff2596f50d6a9c4ce82f61ecbcee123a6ceae0e43cab3012a29b6f83cf67b48c22f6f9d757c6caf76b2 +b88ab05e4248b7fb634cf640a4e6a945d13e331237410f7217d3d17e3e384ddd48897e7a91e4516f1b9cbd30f35f238b +8d826deaeeb84a3b2d2c04c2300ca592501f992810582d6ae993e0d52f6283a839dba66c6c72278cff5871802b71173b +b36fed027c2f05a5ef625ca00b0364b930901e9e4420975b111858d0941f60e205546474bb25d6bfa6928d37305ae95f +af2fcfc6b87967567e8b8a13a4ed914478185705724e56ce68fb2df6d1576a0cf34a61e880997a0d35dc2c3276ff7501 +ac351b919cd1fbf106feb8af2c67692bfcddc84762d18cea681cfa7470a5644839caace27efee5f38c87d3df306f4211 +8d6665fb1d4d8d1fa23bd9b8a86e043b8555663519caac214d1e3e3effbc6bee7f2bcf21e645f77de0ced279d69a8a8b +a9fc1c2061756b2a1a169c1b149f212ff7f0d2488acd1c5a0197eba793cffa593fc6d1d1b40718aa75ca3ec77eff10e1 +aff64f0fa009c7a6cf0b8d7a22ddb2c8170c3cb3eec082e60d5aadb00b0040443be8936d728d99581e33c22178c41c87 +82e0b181adc5e3b1c87ff8598447260e839d53debfae941ebea38265575546c3a74a14b4325a030833a62ff6c52d9365 +b7ad43cbb22f6f892c2a1548a41dc120ab1f4e1b8dea0cb6272dd9cb02054c542ecabc582f7e16de709d48f5166cae86 +985e0c61094281532c4afb788ecb2dfcba998e974b5d4257a22040a161883908cdd068fe80f8eb49b8953cfd11acf43a +ae46895c6d67ea6d469b6c9c07b9e5d295d9ae73b22e30da4ba2c973ba83a130d7eef39717ec9d0f36e81d56bf742671 +8600177ea1f7e7ef90514b38b219a37dedfc39cb83297e4c7a5b479817ef56479d48cf6314820960c751183f6edf8b0e +b9208ec1c1d7a1e99b59c62d3e4e61dfb706b0e940d09d3abfc3454c19749083260614d89cfd7e822596c3cdbcc6bb95 +a1e94042c796c2b48bc724352d2e9f3a22291d9a34705993357ddb6adabd76da6fc25dac200a8cb0b5bbd99ecddb7af6 +b29c3adedd0bcad8a930625bc4dfdc3552a9afd5ca6dd9c0d758f978068c7982b50b711aa0eb5b97f2b84ee784637835 +af0632a238bb1f413c7ea8e9b4c3d68f2827bd2e38cd56024391fba6446ac5d19a780d0cfd4a78fe497d537b766a591a +aaf6e7f7d54f8ef5e2e45dd59774ecbeecf8683aa70483b2a75be6a6071b5981bbaf1627512a65d212817acdfab2e428 +8c751496065da2e927cf492aa5ca9013b24f861d5e6c24b30bbf52ec5aaf1905f40f9a28175faef283dd4ed4f2182a09 +8952377d8e80a85cf67d6b45499f3bad5fd452ea7bcd99efc1b066c4720d8e5bff1214cea90fd1f972a7f0baac3d29be +a1946ee543d1a6e21f380453be4d446e4130950c5fc3d075794eb8260f6f52d0a795c1ff91d028a648dc1ce7d9ab6b47 +89f3fefe37af31e0c17533d2ca1ce0884cc1dc97c15cbfab9c331b8debd94781c9396abef4bb2f163d09277a08d6adf0 +a2753f1e6e1a154fb117100a5bd9052137add85961f8158830ac20541ab12227d83887d10acf7fd36dcaf7c2596d8d23 +814955b4198933ee11c3883863b06ff98c7eceb21fc3e09df5f916107827ccf3323141983e74b025f46ae00284c9513b +8cc5c6bb429073bfef47cae7b3bfccb0ffa076514d91a1862c6bda4d581e0df87db53cc6c130bf8a7826304960f5a34e +909f22c1f1cdc87f7be7439c831a73484a49acbf8f23d47087d7cf867c64ef61da3bde85dc57d705682b4c3fc710d36e +8048fee7f276fcd504aed91284f28e73693615e0eb3858fa44bcf79d7285a9001c373b3ef71d9a3054817ba293ebe28c +94400e5cf5d2700ca608c5fe35ce14623f71cc24959f2bc27ca3684092850f76b67fb1f07ca9e5b2ca3062cf8ad17bd4 +81c2ae7d4d1b17f8b6de6a0430acc0d58260993980fe48dc2129c4948269cdc74f9dbfbf9c26b19360823fd913083d48 +8c41fe765128e63f6889d6a979f6a4342300327c8b245a8cfe3ecfbcac1e09c3da30e2a1045b24b78efc6d6d50c8c6ac +a5dd4ae51ae48c8be4b218c312ade226cffce671cf121cb77810f6c0990768d6dd767badecb5c69921d5574d5e8433d3 +b7642e325f4ba97ae2a39c1c9d97b35aafd49d53dba36aed3f3cb0ca816480b3394079f46a48252d46596559c90f4d58 +ae87375b40f35519e7bd4b1b2f73cd0b329b0c2cb9d616629342a71c6c304338445eda069b78ea0fbe44087f3de91e09 +b08918cb6f736855e11d3daca1ddfbdd61c9589b203b5493143227bf48e2c77c2e8c94b0d1aa2fab2226e0eae83f2681 +ac36b84a4ac2ebd4d6591923a449c564e3be8a664c46092c09e875c2998eba16b5d32bfd0882fd3851762868e669f0b1 +a44800a3bb192066fa17a3f29029a23697240467053b5aa49b9839fb9b9b8b12bcdcbfc557f024b61f4f51a9aacdefcb +9064c688fec23441a274cdf2075e5a449caf5c7363cc5e8a5dc9747183d2e00a0c69f2e6b3f6a7057079c46014c93b3b +aa367b021469af9f5b764a79bb3afbe2d87fe1e51862221672d1a66f954b165778b7c27a705e0f93841fab4c8468344d +a1a8bfc593d4ab71f91640bc824de5c1380ab2591cfdafcbc78a14b32de3c0e15f9d1b461d85c504baa3d4232c16bb53 +97df48da1799430f528184d30b6baa90c2a2f88f34cdfb342d715339c5ebd6d019aa693cea7c4993daafc9849063a3aa +abd923831fbb427e06e0dd335253178a9e5791395c84d0ab1433c07c53c1209161097e9582fb8736f8a60bde62d8693e +84cd1a43f1a438b43dc60ffc775f646937c4f6871438163905a3cebf1115f814ccd38a6ccb134130bff226306e412f32 +91426065996b0743c5f689eb3ca68a9f7b9e4d01f6c5a2652b57fa9a03d8dc7cd4bdbdab0ca5a891fee1e97a7f00cf02 +a4bee50249db3df7fd75162b28f04e57c678ba142ce4d3def2bc17bcb29e4670284a45f218dad3969af466c62a903757 +83141ebcc94d4681404e8b67a12a46374fded6df92b506aff3490d875919631408b369823a08b271d006d5b93136f317 +a0ea1c8883d58d5a784da3d8c8a880061adea796d7505c1f903d07c287c5467f71e4563fc0faafbc15b5a5538b0a7559 +89d9d480574f201a87269d26fb114278ed2c446328df431dc3556e3500e80e4cd01fcac196a2459d8646361ebda840df +8bf302978973632dd464bec819bdb91304712a3ec859be071e662040620422c6e75eba6f864f764cffa2799272efec39 +922f666bc0fd58b6d7d815c0ae4f66d193d32fc8382c631037f59eeaeae9a8ca6c72d08e72944cf9e800b8d639094e77 +81ad8714f491cdff7fe4399f2eb20e32650cff2999dd45b9b3d996d54a4aba24cc6c451212e78c9e5550368a1a38fb3f +b58fcf4659d73edb73175bd9139d18254e94c3e32031b5d4b026f2ed37aa19dca17ec2eb54c14340231615277a9d347e +b365ac9c2bfe409b710928c646ea2fb15b28557e0f089d39878e365589b9d1c34baf5566d20bb28b33bb60fa133f6eff +8fcae1d75b53ab470be805f39630d204853ca1629a14158bac2f52632277d77458dec204ff84b7b2d77e641c2045be65 +a03efa6bebe84f4f958a56e2d76b5ba4f95dd9ed7eb479edc7cc5e646c8d4792e5b0dfc66cc86aa4b4afe2f7a4850760 +af1c823930a3638975fb0cc5c59651771b2719119c3cd08404fbd4ce77a74d708cefbe3c56ea08c48f5f10e6907f338f +8260c8299b17898032c761c325ac9cabb4c5b7e735de81eacf244f647a45fb385012f4f8df743128888c29aefcaaad16 +ab2f37a573c82e96a8d46198691cd694dfa860615625f477e41f91b879bc58a745784fccd8ffa13065834ffd150d881d +986c746c9b4249352d8e5c629e8d7d05e716b3c7aab5e529ca969dd1e984a14b5be41528baef4c85d2369a42d7209216 +b25e32da1a8adddf2a6080725818b75bc67240728ad1853d90738485d8924ea1e202df0a3034a60ffae6f965ec55cf63 +a266e627afcebcefea6b6b44cbc50f5c508f7187e87d047b0450871c2a030042c9e376f3ede0afcf9d1952f089582f71 +86c3bbca4c0300606071c0a80dbdec21ce1dd4d8d4309648151c420854032dff1241a1677d1cd5de4e4de4385efda986 +b9a21a1fe2d1f3273a8e4a9185abf2ff86448cc98bfa435e3d68306a2b8b4a6a3ea33a155be3cb62a2170a86f77679a5 +b117b1ea381adce87d8b342cba3a15d492ff2d644afa28f22424cb9cbc820d4f7693dfc1a4d1b3697046c300e1c9b4c8 +9004c425a2e68870d6c69b658c344e3aa3a86a8914ee08d72b2f95c2e2d8a4c7bb0c6e7e271460c0e637cec11117bf8e +86a18aa4783b9ebd9131580c8b17994825f27f4ac427b0929a1e0236907732a1c8139e98112c605488ee95f48bbefbfc +84042243b955286482ab6f0b5df4c2d73571ada00716d2f737ca05a0d2e88c6349e8ee9e67934cfee4a1775dbf7f4800 +92c2153a4733a62e4e1d5b60369f3c26777c7d01cd3c8679212660d572bd3bac9b8a8a64e1f10f7dbf5eaa7579c4e423 +918454b6bb8e44a2afa144695ba8d48ae08d0cdfef4ad078f67709eddf3bb31191e8b006f04e82ea45a54715ef4d5817 +acf0b54f6bf34cf6ed6c2b39cf43194a40d68de6bcf1e4b82c34c15a1343e9ac3737885e1a30b78d01fa3a5125463db8 +a7d60dbe4b6a7b054f7afe9ee5cbbfeca0d05dc619e6041fa2296b549322529faddb8a11e949562309aecefb842ac380 +91ffb53e6d7e5f11159eaf13e783d6dbdfdb1698ed1e6dbf3413c6ea23492bbb9e0932230a9e2caac8fe899a17682795 +b6e8d7be5076ee3565d5765a710c5ecf17921dd3cf555c375d01e958a365ae087d4a88da492a5fb81838b7b92bf01143 +a8c6b763de2d4b2ed42102ef64eccfef31e2fb2a8a2776241c82912fa50fc9f77f175b6d109a97ede331307c016a4b1a +99839f86cb700c297c58bc33e28d46b92931961548deac29ba8df91d3e11721b10ea956c8e16984f9e4acf1298a79b37 +8c2e2c338f25ea5c25756b7131cde0d9a2b35abf5d90781180a00fe4b8e64e62590dc63fe10a57fba3a31c76d784eb01 +9687d7df2f41319ca5469d91978fed0565a5f11f829ebadaa83db92b221755f76c6eacd7700735e75c91e257087512e3 +8795fdfb7ff8439c58b9bf58ed53873d2780d3939b902b9ddaaa4c99447224ced9206c3039a23c2c44bcc461e2bb637f +a803697b744d2d087f4e2307218d48fa88620cf25529db9ce71e2e3bbcc65bac5e8bb9be04777ef7bfb5ed1a5b8e6170 +80f3d3efbbb9346ddd413f0a8e36b269eb5d7ff6809d5525ff9a47c4bcab2c01b70018b117f6fe05253775612ff70c6b +9050e0e45bcc83930d4c505af35e5e4d7ca01cd8681cba92eb55821aececcebe32bb692ebe1a4daac4e7472975671067 +8d206812aac42742dbaf233e0c080b3d1b30943b54b60283515da005de05ea5caa90f91fedcfcba72e922f64d7040189 +a2d44faaeb2eff7915c83f32b13ca6f31a6847b1c1ce114ea240bac3595eded89f09b2313b7915ad882292e2b586d5b4 +961776c8576030c39f214ea6e0a3e8b3d32f023d2600958c098c95c8a4e374deeb2b9dc522adfbd6bda5949bdc09e2a2 +993fa7d8447407af0fbcd9e6d77f815fa5233ab00674efbcf74a1f51c37481445ae291cc7b76db7c178f9cb0e570e0fc +abd5b1c78e05f9d7c8cc99bdaef8b0b6a57f2daf0f02bf492bec48ea4a27a8f1e38b5854da96efff11973326ff980f92 +8f15af4764bc275e6ccb892b3a4362cacb4e175b1526a9a99944e692fe6ccb1b4fc19abf312bb2a089cb1f344d91a779 +a09b27ccd71855512aba1d0c30a79ffbe7f6707a55978f3ced50e674b511a79a446dbc6d7946add421ce111135a460af +94b2f98ce86a9271fbd4153e1fc37de48421fe3490fb3840c00f2d5a4d0ba8810c6a32880b002f6374b59e0a7952518b +8650ac644f93bbcb88a6a0f49fee2663297fd4bc6fd47b6a89b9d8038d32370438ab3a4775ec9b58cb10aea8a95ef7b6 +95e5c2f2e84eed88c6980bbba5a1c0bb375d5a628bff006f7516d45bb7d723da676add4fdd45956f312e7bab0f052644 +b3278a3fa377ac93af7cfc9453f8cb594aae04269bbc99d2e0e45472ff4b6a2f97a26c4c57bf675b9d86f5e77a5d55d1 +b4bcbe6eb666a206e2ea2f877912c1d3b5bdbd08a989fc4490eb06013e1a69ad1ba08bcdac048bf29192312be399077b +a76d70b78c99fffcbf9bb9886eab40f1ea4f99a309710b660b64cbf86057cbcb644d243f6e341711bb7ef0fedf0435a7 +b2093c1ee945dca7ac76ad5aed08eae23af31dd5a77c903fd7b6f051f4ab84425d33a03c3d45bf2907bc93c02d1f3ad8 +904b1f7534e053a265b22d20be859912b9c9ccb303af9a8d6f1d8f6ccdc5c53eb4a45a1762b880d8444d9be0cd55e7f9 +8f664a965d65bc730c9ef1ec7467be984d4b8eb46bd9b0d64e38e48f94e6e55dda19aeac82cbcf4e1473440e64c4ca18 +8bcee65c4cc7a7799353d07b114c718a2aae0cd10a3f22b7eead5185d159dafd64852cb63924bf87627d176228878bce +8c78f2e3675096fef7ebaa898d2615cd50d39ca3d8f02b9bdfb07e67da648ae4be3da64838dffc5935fd72962c4b96c7 +8c40afd3701629421fec1df1aac4e849384ef2e80472c0e28d36cb1327acdf2826f99b357f3d7afdbc58a6347fc40b3c +a197813b1c65a8ea5754ef782522a57d63433ef752215ecda1e7da76b0412ee619f58d904abd2e07e0c097048b6ae1dd +a670542629e4333884ad7410f9ea3bd6f988df4a8f8a424ca74b9add2312586900cf9ae8bd50411f9146e82626b4af56 +a19875cc07ab84e569d98b8b67fb1dbbdfb59093c7b748fae008c8904a6fd931a63ca8d03ab5fea9bc8d263568125a9b +b57e7f68e4eb1bd04aafa917b1db1bdab759a02aa8a9cdb1cba34ba8852b5890f655645c9b4e15d5f19bf37e9f2ffe9f +8abe4e2a4f6462b6c64b3f10e45db2a53c2b0d3c5d5443d3f00a453e193df771eda635b098b6c8604ace3557514027af +8459e4fb378189b22b870a6ef20183deb816cefbf66eca1dc7e86d36a2e011537db893729f500dc154f14ce24633ba47 +930851df4bc7913c0d8c0f7bd3b071a83668987ed7c397d3d042fdc0d9765945a39a3bae83da9c88cb6b686ed8aeeb26 +8078c9e5cd05e1a8c932f8a1d835f61a248b6e7133fcbb3de406bf4ffc0e584f6f9f95062740ba6008d98348886cf76b +addff62bb29430983fe578e3709b0949cdc0d47a13a29bc3f50371a2cb5c822ce53e2448cfaa01bcb6e0aa850d5a380e +9433add687b5a1e12066721789b1db2edf9b6558c3bdc0f452ba33b1da67426abe326e9a34d207bfb1c491c18811bde1 +822beda3389963428cccc4a2918fa9a8a51cf0919640350293af70821967108cded5997adae86b33cb917780b097f1ca +a7a9f52bda45e4148ed56dd176df7bd672e9b5ed18888ccdb405f47920fdb0844355f8565cefb17010b38324edd8315f +b35c3a872e18e607b2555c51f9696a17fa18da1f924d503b163b4ec9fe22ed0c110925275cb6c93ce2d013e88f173d6a +adf34b002b2b26ab84fc1bf94e05bd8616a1d06664799ab149363c56a6e0c807fdc473327d25632416e952ea327fcd95 +ae4a6b9d22a4a3183fac29e2551e1124a8ce4a561a9a2afa9b23032b58d444e6155bb2b48f85c7b6d70393274e230db7 +a2ea3be4fc17e9b7ce3110284038d46a09e88a247b6971167a7878d9dcf36925d613c382b400cfa4f37a3ebea3699897 +8e5863786b641ce3140fbfe37124d7ad3925472e924f814ebfc45959aaf3f61dc554a597610b5defaecc85b59a99b50f +aefde3193d0f700d0f515ab2aaa43e2ef1d7831c4f7859f48e52693d57f97fa9e520090f3ed700e1c966f4b76048e57f +841a50f772956622798e5cd208dc7534d4e39eddee30d8ce133383d66e5f267e389254a0cdae01b770ecd0a9ca421929 +8fbc2bfd28238c7d47d4c03b1b910946c0d94274a199575e5b23242619b1de3497784e646a92aa03e3e24123ae4fcaba +926999579c8eec1cc47d7330112586bdca20b4149c8b2d066f527c8b9f609e61ce27feb69db67eea382649c6905efcf9 +b09f31f305efcc65589adf5d3690a76cf339efd67cd43a4e3ced7b839507466e4be72dd91f04e89e4bbef629d46e68c0 +b917361f6b95f759642638e0b1d2b3a29c3bdef0b94faa30de562e6078c7e2d25976159df3edbacbf43614635c2640b4 +8e7e8a1253bbda0e134d62bfe003a2669d471b47bd2b5cde0ff60d385d8e62279d54022f5ac12053b1e2d3aaa6910b4c +b69671a3c64e0a99d90b0ed108ce1912ff8ed983e4bddd75a370e9babde25ee1f5efb59ec707edddd46793207a8b1fe7 +910b2f4ebd37b7ae94108922b233d0920b4aba0bd94202c70f1314418b548d11d8e9caa91f2cd95aff51b9432d122b7f +82f645c90dfb52d195c1020346287c43a80233d3538954548604d09fbab7421241cde8593dbc4acc4986e0ea39a27dd9 +8fee895f0a140d88104ce442fed3966f58ff9d275e7373483f6b4249d64a25fb5374bbdc6bce6b5ab0270c2847066f83 +84f5bd7aab27b2509397aeb86510dd5ac0a53f2c8f73799bf720f2f87a52277f8d6b0f77f17bc80739c6a7119b7eb062 +9903ceced81099d7e146e661bcf01cbaccab5ba54366b85e2177f07e2d8621e19d9c9c3eee14b9266de6b3f9b6ea75ae +b9c16ea2a07afa32dd6c7c06df0dec39bca2067a9339e45475c98917f47e2320f6f235da353fd5e15b477de97ddc68dd +9820a9bbf8b826bec61ebf886de2c4f404c1ebdc8bab82ee1fea816d9de29127ce1852448ff717a3fe8bbfe9e92012e5 +817224d9359f5da6f2158c2c7bf9165501424f063e67ba9859a07ab72ee2ee62eb00ca6da821cfa19065c3282ca72c74 +94b95c465e6cb00da400558a3c60cfec4b79b27e602ca67cbc91aead08de4b6872d8ea096b0dc06dca4525c8992b8547 +a2b539a5bccd43fa347ba9c15f249b417997c6a38c63517ca38394976baa08e20be384a360969ff54e7e721db536b3e5 +96caf707e34f62811ee8d32ccf28d8d6ec579bc33e424d0473529af5315c456fd026aa910c1fed70c91982d51df7d3ca +8a77b73e890b644c6a142bdbac59b22d6a676f3b63ddafb52d914bb9d395b8bf5aedcbcc90429337df431ebd758a07a6 +8857830a7351025617a08bc44caec28d2fae07ebf5ffc9f01d979ce2a53839a670e61ae2783e138313929129790a51a1 +aa3e420321ed6f0aa326d28d1a10f13facec6f605b6218a6eb9cbc074801f3467bf013a456d1415a5536f12599efa3d3 +824aed0951957b00ea2f3d423e30328a3527bf6714cf9abbae84cf27e58e5c35452ba89ccc011de7c68c75d6e021d8f1 +a2e87cc06bf202e953fb1081933d8b4445527dde20e38ed1a4f440144fd8fa464a2b73e068b140562e9045e0f4bd3144 +ae3b8f06ad97d7ae3a5e5ca839efff3e4824dc238c0c03fc1a8d2fc8aa546cdfd165b784a31bb4dec7c77e9305b99a4b +b30c3e12395b1fb8b776f3ec9f87c70e35763a7b2ddc68f0f60a4982a84017f27c891a98561c830038deb033698ed7fc +874e507757cd1177d0dff0b0c62ce90130324442a33da3b2c8ee09dbca5d543e3ecfe707e9f1361e7c7db641c72794bb +b53012dd10b5e7460b57c092eaa06d6502720df9edbbe3e3f61a9998a272bf5baaac4a5a732ad4efe35d6fac6feca744 +85e6509d711515534d394e6cacbed6c81da710074d16ef3f4950bf2f578d662a494d835674f79c4d6315bced4defc5f0 +b6132b2a34b0905dcadc6119fd215419a7971fe545e52f48b768006944b4a9d7db1a74b149e2951ea48c083b752d0804 +989867da6415036d19b4bacc926ce6f4df7a556f50a1ba5f3c48eea9cefbb1c09da81481c8009331ee83f0859185e164 +960a6c36542876174d3fbc1505413e29f053ed87b8d38fef3af180491c7eff25200b45dd5fe5d4d8e63c7e8c9c00f4c8 +9040b59bd739d9cc2e8f6e894683429e4e876a8106238689ff4c22770ae5fdae1f32d962b30301fa0634ee163b524f35 +af3fcd0a45fe9e8fe256dc7eab242ef7f582dd832d147444483c62787ac820fafc6ca55d639a73f76bfa5e7f5462ab8f +b934c799d0736953a73d91e761767fdb78454355c4b15c680ce08accb57ccf941b13a1236980001f9e6195801cffd692 +8871e8e741157c2c326b22cf09551e78da3c1ec0fc0543136f581f1550f8bab03b0a7b80525c1e99812cdbf3a9698f96 +a8a977f51473a91d178ee8cfa45ffef8d6fd93ab1d6e428f96a3c79816d9c6a93cd70f94d4deda0125fd6816e30f3bea +a7688b3b0a4fc1dd16e8ba6dc758d3cfe1b7cf401c31739484c7fa253cce0967df1b290769bcefc9d23d3e0cb19e6218 +8ae84322662a57c6d729e6ff9d2737698cc2da2daeb1f39e506618750ed23442a6740955f299e4a15dda6db3e534d2c6 +a04a961cdccfa4b7ef83ced17ab221d6a043b2c718a0d6cc8e6f798507a31f10bf70361f70a049bc8058303fa7f96864 +b463e39732a7d9daec8a456fb58e54b30a6e160aa522a18b9a9e836488cce3342bcbb2e1deab0f5e6ec0a8796d77197d +b1434a11c6750f14018a2d3bcf94390e2948f4f187e93bb22070ca3e5393d339dc328cbfc3e48815f51929465ffe7d81 +84ff81d73f3828340623d7e3345553610aa22a5432217ef0ebd193cbf4a24234b190c65ca0873c22d10ea7b63bd1fbed +b6fe2723f0c47757932c2ddde7a4f8434f665612f7b87b4009c2635d56b6e16b200859a8ade49276de0ef27a2b6c970a +9742884ed7cd52b4a4a068a43d3faa02551a424136c85a9313f7cb58ea54c04aa83b0728fd741d1fe39621e931e88f8f +b7d2d65ea4d1ad07a5dee39e40d6c03a61264a56b1585b4d76fc5b2a68d80a93a42a0181d432528582bf08d144c2d6a9 +88c0f66bada89f8a43e5a6ead2915088173d106c76f724f4a97b0f6758aed6ae5c37c373c6b92cdd4aea8f6261f3a374 +81f9c43582cb42db3900747eb49ec94edb2284999a499d1527f03315fd330e5a509afa3bff659853570e9886aab5b28b +821f9d27d6beb416abf9aa5c79afb65a50ed276dbda6060103bc808bcd34426b82da5f23e38e88a55e172f5c294b4d40 +8ba307b9e7cb63a6c4f3851b321aebfdb6af34a5a4c3bd949ff7d96603e59b27ff4dc4970715d35f7758260ff942c9e9 +b142eb6c5f846de33227d0bda61d445a7c33c98f0a8365fe6ab4c1fabdc130849be597ef734305894a424ea715372d08 +a732730ae4512e86a741c8e4c87fee8a05ee840fec0e23b2e037d58dba8dde8d10a9bc5191d34d00598941becbbe467f +adce6f7c30fd221f6b10a0413cc76435c4bb36c2d60bca821e5c67409fe9dbb2f4c36ef85eb3d734695e4be4827e9fd3 +a74f00e0f9b23aff7b2527ce69852f8906dab9d6abe62ecd497498ab21e57542e12af9918d4fd610bb09e10b0929c510 +a593b6b0ef26448ce4eb3ab07e84238fc020b3cb10d542ff4b16d4e2be1bcde3797e45c9cf753b8dc3b0ffdb63984232 +aed3913afccf1aa1ac0eb4980eb8426d0baccebd836d44651fd72af00d09fac488a870223c42aca3ceb39752070405ae +b2c44c66a5ea7fde626548ba4cef8c8710191343d3dadfd3bb653ce715c0e03056a5303a581d47dde66e70ea5a2d2779 +8e5029b2ccf5128a12327b5103f7532db599846e422531869560ceaff392236434d87159f597937dbf4054f810c114f4 +82beed1a2c4477e5eb39fc5b0e773b30cfec77ef2b1bf17eadaf60eb35b6d0dd9d8cf06315c48d3546badb3f21cd0cca +90077bd6cc0e4be5fff08e5d07a5a158d36cebd1d1363125bc4fae0866ffe825b26f933d4ee5427ba5cd0c33c19a7b06 +a7ec0d8f079970e8e34f0ef3a53d3e0e45428ddcef9cc776ead5e542ef06f3c86981644f61c5a637e4faf001fb8c6b3e +ae6d4add6d1a6f90b22792bc9d40723ee6850c27d0b97eefafd5b7fd98e424aa97868b5287cc41b4fbd7023bca6a322c +831aa917533d077da07c01417feaa1408846363ba2b8d22c6116bb858a95801547dd88b7d7fa1d2e3f0a02bdeb2e103d +96511b860b07c8a5ed773f36d4aa9d02fb5e7882753bf56303595bcb57e37ccc60288887eb83bef08c657ec261a021a2 +921d2a3e7e9790f74068623de327443666b634c8443aba80120a45bba450df920b2374d96df1ce3fb1b06dd06f8cf6e3 +aa74451d51fe82b4581ead8e506ec6cd881010f7e7dd51fc388eb9a557db5d3c6721f81c151d08ebd9c2591689fbc13e +a972bfbcf4033d5742d08716c927c442119bdae336bf5dff914523b285ccf31953da2733759aacaa246a9af9f698342c +ad1fcd0cae0e76840194ce4150cb8a56ebed728ec9272035f52a799d480dfc85840a4d52d994a18b6edb31e79be6e8ad +a2c69fe1d36f235215432dad48d75887a44c99dfa0d78149acc74087da215a44bdb5f04e6eef88ff7eff80a5a7decc77 +a94ab2af2b6ee1bc6e0d4e689ca45380d9fbd3c5a65b9bd249d266a4d4c07bf5d5f7ef2ae6000623aee64027892bf8fe +881ec1fc514e926cdc66480ac59e139148ff8a2a7895a49f0dff45910c90cdda97b66441a25f357d6dd2471cddd99bb3 +884e6d3b894a914c8cef946a76d5a0c8351843b2bffa2d1e56c6b5b99c84104381dd1320c451d551c0b966f4086e60f9 +817c6c10ce2677b9fc5223500322e2b880583254d0bb0d247d728f8716f5e05c9ff39f135854342a1afecd9fbdcf7c46 +aaf4a9cb686a14619aa1fc1ac285dd3843ac3dd99f2b2331c711ec87b03491c02f49101046f3c5c538dc9f8dba2a0ac2 +97ecea5ce53ca720b5d845227ae61d70269a2f53540089305c86af35f0898bfd57356e74a8a5e083fa6e1ea70080bd31 +a22d811e1a20a75feac0157c418a4bfe745ccb5d29466ffa854dca03e395b6c3504a734341746b2846d76583a780b32e +940cbaa0d2b2db94ae96b6b9cf2deefbfd059e3e5745de9aec4a25f0991b9721e5cd37ef71c631575d1a0c280b01cd5b +ae33cb4951191258a11044682de861bf8d92d90ce751b354932dd9f3913f542b6a0f8a4dc228b3cd9244ac32c4582832 +a580df5e58c4274fe0f52ac2da1837e32f5c9db92be16c170187db4c358f43e5cfdda7c5911dcc79d77a5764e32325f5 +81798178cb9d8affa424f8d3be67576ba94d108a28ccc01d330c51d5a63ca45bb8ca63a2f569b5c5fe1303cecd2d777f +89975b91b94c25c9c3660e4af4047a8bacf964783010820dbc91ff8281509379cb3b24c25080d5a01174dd9a049118d5 +a7327fcb3710ed3273b048650bde40a32732ef40a7e58cf7f2f400979c177944c8bc54117ba6c80d5d4260801dddab79 +92b475dc8cb5be4b90c482f122a51bcb3b6c70593817e7e2459c28ea54a7845c50272af38119406eaadb9bcb993368d0 +9645173e9ecefc4f2eae8363504f7c0b81d85f8949a9f8a6c01f2d49e0a0764f4eacecf3e94016dd407fc14494fce9f9 +9215fd8983d7de6ae94d35e6698226fc1454977ae58d42d294be9aad13ac821562ad37d5e7ee5cdfe6e87031d45cd197 +810360a1c9b88a9e36f520ab5a1eb8bed93f52deefbe1312a69225c0a08edb10f87cc43b794aced9c74220cefcc57e7d +ad7e810efd61ed4684aeda9ed8bb02fb9ae4b4b63fda8217d37012b94ff1b91c0087043bfa4e376f961fff030c729f3b +8b07c95c6a06db8738d10bb03ec11b89375c08e77f0cab7e672ce70b2685667ca19c7e1c8b092821d31108ea18dfd4c7 +968825d025ded899ff7c57245250535c732836f7565eab1ae23ee7e513201d413c16e1ba3f5166e7ac6cf74de8ceef4f +908243370c5788200703ade8164943ad5f8c458219186432e74dbc9904a701ea307fd9b94976c866e6c58595fd891c4b +959969d16680bc535cdc6339e6186355d0d6c0d53d7bbfb411641b9bf4b770fd5f575beef5deec5c4fa4d192d455c350 +ad177f4f826a961adeac76da40e2d930748effff731756c797eddc4e5aa23c91f070fb69b19221748130b0961e68a6bb +82f8462bcc25448ef7e0739425378e9bb8a05e283ce54aae9dbebaf7a3469f57833c9171672ad43a79778366c72a5e37 +a28fb275b1845706c2814d9638573e9bc32ff552ebaed761fe96fdbce70395891ca41c400ae438369264e31a2713b15f +8a9c613996b5e51dadb587a787253d6081ea446bf5c71096980bf6bd3c4b69905062a8e8a3792de2d2ece3b177a71089 +8d5aefef9f60cb27c1db2c649221204dda48bb9bf8bf48f965741da051340e8e4cab88b9d15c69f3f84f4c854709f48a +93ebf2ca6ad85ab6deace6de1a458706285b31877b1b4d7dcb9d126b63047efaf8c06d580115ec9acee30c8a7212fa55 +b3ee46ce189956ca298057fa8223b7fd1128cf52f39159a58bca03c71dd25161ac13f1472301f72aef3e1993fe1ab269 +a24d7a8d066504fc3f5027ccb13120e2f22896860e02c45b5eba1dbd512d6a17c28f39155ea581619f9d33db43a96f92 +ae9ceacbfe12137db2c1a271e1b34b8f92e4816bad1b3b9b6feecc34df0f8b3b0f7ed0133acdf59c537d43d33fc8d429 +83967e69bf2b361f86361bd705dce0e1ad26df06da6c52b48176fe8dfcbeb03c462c1a4c9e649eff8c654b18c876fdef +9148e6b814a7d779c19c31e33a068e97b597de1f8100513db3c581190513edc4d544801ce3dd2cf6b19e0cd6daedd28a +94ccdafc84920d320ed22de1e754adea072935d3c5f8c2d1378ebe53d140ea29853f056fb3fb1e375846061a038cc9bc +afb43348498c38b0fa5f971b8cdd3a62c844f0eb52bc33daf2f67850af0880fce84ecfb96201b308d9e6168a0d443ae3 +86d5736520a83538d4cd058cc4b4e84213ed00ebd6e7af79ae787adc17a92ba5359e28ba6c91936d967b4b28d24c3070 +b5210c1ff212c5b1e9ef9126e08fe120a41e386bb12c22266f7538c6d69c7fd8774f11c02b81fd4e88f9137b020801fe +b78cfd19f94d24e529d0f52e18ce6185cb238edc6bd43086270fd51dd99f664f43dd4c7d2fe506762fbd859028e13fcf +a6e7220598c554abdcc3fdc587b988617b32c7bb0f82c06205467dbedb58276cc07cae317a190f19d19078773f4c2bbb +b88862809487ee430368dccd85a5d72fa4d163ca4aad15c78800e19c1a95be2192719801e315d86cff7795e0544a77e4 +87ecb13a03921296f8c42ceb252d04716f10e09c93962239fcaa0a7fef93f19ab3f2680bc406170108bc583e9ff2e721 +a810cd473832b6581c36ec4cb403f2849357ba2d0b54df98ef3004b8a530c078032922a81d40158f5fb0043d56477f6e +a247b45dd85ca7fbb718b328f30a03f03c84aef2c583fbdc9fcc9eb8b52b34529e8c8f535505c10598b1b4dac3d7c647 +96ee0b91313c68bac4aa9e065ce9e1d77e51ca4cff31d6a438718c58264dee87674bd97fc5c6b8008be709521e4fd008 +837567ad073e42266951a9a54750919280a2ac835a73c158407c3a2b1904cf0d17b7195a393c71a18ad029cbd9cf79ee +a6a469c44b67ebf02196213e7a63ad0423aab9a6e54acc6fcbdbb915bc043586993454dc3cd9e4be8f27d67c1050879b +8712d380a843b08b7b294f1f06e2f11f4ad6bcc655fdde86a4d8bc739c23916f6fad2b902fe47d6212f03607907e9f0e +920adfb644b534789943cdae1bdd6e42828dda1696a440af2f54e6b97f4f97470a1c6ea9fa6a2705d8f04911d055acd1 +a161c73adf584a0061e963b062f59d90faac65c9b3a936b837a10d817f02fcabfa748824607be45a183dd40f991fe83f +874f4ecd408c76e625ea50bc59c53c2d930ee25baf4b4eca2440bfbffb3b8bc294db579caa7c68629f4d9ec24187c1ba +8bff18087f112be7f4aa654e85c71fef70eee8ae480f61d0383ff6f5ab1a0508f966183bb3fc4d6f29cb7ca234aa50d3 +b03b46a3ca3bc743a173cbc008f92ab1aedd7466b35a6d1ca11e894b9482ea9dc75f8d6db2ddd1add99bfbe7657518b7 +8b4f3691403c3a8ad9e097f02d130769628feddfa8c2b3dfe8cff64e2bed7d6e5d192c1e2ba0ac348b8585e94acd5fa1 +a0d9ca4a212301f97591bf65d5ef2b2664766b427c9dd342e23cb468426e6a56be66b1cb41fea1889ac5d11a8e3c50a5 +8c93ed74188ca23b3df29e5396974b9cc135c91fdefdea6c0df694c8116410e93509559af55533a3776ac11b228d69b1 +82dd331fb3f9e344ebdeeb557769b86a2cc8cc38f6c298d7572a33aea87c261afa9dbd898989139b9fc16bc1e880a099 +a65faedf326bcfd8ef98a51410c78b021d39206704e8291cd1f09e096a66b9b0486be65ff185ca224c45918ac337ddeb +a188b37d363ac072a766fd5d6fa27df07363feff1342217b19e3c37385e42ffde55e4be8355aceaa2f267b6d66b4ac41 +810fa3ba3e96d843e3bafd3f2995727f223d3567c8ba77d684c993ba1773c66551eb5009897c51b3fe9b37196984f5ec +87631537541852da323b4353af45a164f68b304d24c01183bf271782e11687f3fcf528394e1566c2a26cb527b3148e64 +b721cb2b37b3c477a48e3cc0044167d51ff568a5fd2fb606e5aec7a267000f1ddc07d3db919926ae12761a8e017c767c +904dfad4ba2cc1f6e60d1b708438a70b1743b400164cd981f13c064b8328d5973987d4fb9cf894068f29d3deaf624dfb +a70491538893552c20939fae6be2f07bfa84d97e2534a6bbcc0f1729246b831103505e9f60e97a8fa7d2e6c1c2384579 +8726cf1b26b41f443ff7485adcfddc39ace2e62f4d65dd0bb927d933e262b66f1a9b367ded5fbdd6f3b0932553ac1735 +ae8a11cfdf7aa54c08f80cb645e3339187ab3886babe9fae5239ba507bb3dd1c0d161ca474a2df081dcd3d63e8fe445e +92328719e97ce60e56110f30a00ac5d9c7a2baaf5f8d22355d53c1c77941e3a1fec7d1405e6fbf8959665fe2ba7a8cad +8d9d6255b65798d0018a8cccb0b6343efd41dc14ff2058d3eed9451ceaad681e4a0fa6af67b0a04318aa628024e5553d +b70209090055459296006742d946a513f0cba6d83a05249ee8e7a51052b29c0ca9722dc4af5f9816a1b7938a5dac7f79 +aab7b766b9bf91786dfa801fcef6d575dc6f12b77ecc662eb4498f0312e54d0de9ea820e61508fc8aeee5ab5db529349 +a8104b462337748b7f086a135d0c3f87f8e51b7165ca6611264b8fb639d9a2f519926cb311fa2055b5fadf03da70c678 +b0d2460747d5d8b30fc6c6bd0a87cb343ddb05d90a51b465e8f67d499cfc5e3a9e365da05ae233bbee792cdf90ec67d5 +aa55f5bf3815266b4a149f85ed18e451c93de9163575e3ec75dd610381cc0805bb0a4d7c4af5b1f94d10231255436d2c +8d4c6a1944ff94426151909eb5b99cfd92167b967dabe2bf3aa66bb3c26c449c13097de881b2cfc1bf052862c1ef7b03 +8862296162451b9b6b77f03bf32e6df71325e8d7485cf3335d66fd48b74c2a8334c241db8263033724f26269ad95b395 +901aa96deb26cda5d9321190ae6624d357a41729d72ef1abfd71bebf6139af6d690798daba53b7bc5923462115ff748a +96c195ec4992728a1eb38cdde42d89a7bce150db43adbc9e61e279ea839e538deec71326b618dd39c50d589f78fc0614 +b6ff8b8aa0837b99a1a8b46fb37f20ad4aecc6a98381b1308697829a59b8442ffc748637a88cb30c9b1f0f28a926c4f6 +8d807e3dca9e7bef277db1d2cfb372408dd587364e8048b304eff00eacde2c723bfc84be9b98553f83cba5c7b3cba248 +8800c96adb0195c4fc5b24511450dee503c32bf47044f5e2e25bd6651f514d79a2dd9b01cd8c09f3c9d3859338490f57 +89fe366096097e38ec28dd1148887112efa5306cc0c3da09562aafa56f4eb000bf46ff79bf0bdd270cbde6bf0e1c8957 +af409a90c2776e1e7e3760b2042507b8709e943424606e31e791d42f17873a2710797f5baaab4cc4a19998ef648556b0 +8d761863c9b6edbd232d35ab853d944f5c950c2b643f84a1a1327ebb947290800710ff01dcfa26dc8e9828481240e8b1 +90b95e9be1e55c463ed857c4e0617d6dc3674e99b6aa62ed33c8e79d6dfcf7d122f4f4cc2ee3e7c5a49170cb617d2e2e +b3ff381efefabc4db38cc4727432e0301949ae4f16f8d1dea9b4f4de611cf5a36d84290a0bef160dac4e1955e516b3b0 +a8a84564b56a9003adcadb3565dc512239fc79572762cda7b5901a255bc82656bb9c01212ad33d6bef4fbbce18dacc87 +90a081890364b222eef54bf0075417f85e340d2fec8b7375995f598aeb33f26b44143ebf56fca7d8b4ebb36b5747b0eb +ade6ee49e1293224ddf2d8ab7f14bb5be6bc6284f60fd5b3a1e0cf147b73cff57cf19763b8a36c5083badc79c606b103 +b2fa99806dd2fa3de09320b615a2570c416c9bcdb052e592b0aead748bbe407ec9475a3d932ae48b71c2627eb81986a6 +91f3b7b73c8ccc9392542711c45fe6f236057e6efad587d661ad5cb4d6e88265f86b807bb1151736b1009ab74fd7acb4 +8800e2a46af96696dfbdcbf2ca2918b3dcf28ad970170d2d1783b52b8d945a9167d052beeb55f56c126da7ffa7059baa +9862267a1311c385956b977c9aa08548c28d758d7ba82d43dbc3d0a0fd1b7a221d39e8399997fea9014ac509ff510ac4 +b7d24f78886fd3e2d283e18d9ad5a25c1a904e7d9b9104bf47da469d74f34162e27e531380dbbe0a9d051e6ffd51d6e7 +b0f445f9d143e28b9df36b0f2c052da87ee2ca374d9d0fbe2eff66ca6fe5fe0d2c1951b428d58f7314b7e74e45d445ea +b63fc4083eabb8437dafeb6a904120691dcb53ce2938b820bb553da0e1eecd476f72495aacb72600cf9cad18698fd3db +b9ffd8108eaebd582d665f8690fe8bb207fd85185e6dd9f0b355a09bac1bbff26e0fdb172bc0498df025414e88fe2eda +967ed453e1f1a4c5b7b6834cc9f75c13f6889edc0cc91dc445727e9f408487bbf05c337103f61397a10011dfbe25d61d +98ceb673aff36e1987d5521a3984a07079c3c6155974bb8b413e8ae1ce84095fe4f7862fba7aefa14753eb26f2a5805f +85f01d28603a8fdf6ce6a50cb5c44f8a36b95b91302e3f4cd95c108ce8f4d212e73aec1b8d936520d9226802a2bd9136 +88118e9703200ca07910345fbb789e7a8f92bd80bbc79f0a9e040e8767d33df39f6eded403a9b636eabf9101e588482a +90833a51eef1b10ed74e8f9bbd6197e29c5292e469c854eed10b0da663e2bceb92539710b1858bbb21887bd538d28d89 +b513b905ec19191167c6193067b5cfdf5a3d3828375360df1c7e2ced5815437dfd37f0c4c8f009d7fb29ff3c8793f560 +b1b6d405d2d18f9554b8a358cc7e2d78a3b34269737d561992c8de83392ac9a2857be4bf15de5a6c74e0c9d0f31f393c +b828bd3e452b797323b798186607849f85d1fb20c616833c0619360dfd6b3e3aa000fd09dafe4b62d74abc41072ff1a9 +8efde67d0cca56bb2c464731879c9ac46a52e75bac702a63200a5e192b4f81c641f855ca6747752b84fe469cb7113b6c +b2762ba1c89ac3c9a983c242e4d1c2610ff0528585ed5c0dfc8a2c0253551142af9b59f43158e8915a1da7cc26b9df67 +8a3f1157fb820d1497ef6b25cd70b7e16bb8b961b0063ad340d82a79ee76eb2359ca9e15e6d42987ed7f154f5eeaa2da +a75e29f29d38f09c879f971c11beb5368affa084313474a5ecafa2896180b9e47ea1995c2733ec46f421e395a1d9cffe +8e8c3dd3e7196ef0b4996b531ec79e4a1f211db5d5635e48ceb80ff7568b2ff587e845f97ee703bb23a60945ad64314a +8e7f32f4a3e3c584af5e3d406924a0aa34024c42eca74ef6cc2a358fd3c9efaf25f1c03aa1e66bb94b023a2ee2a1cace +ab7dce05d59c10a84feb524fcb62478906b3fa045135b23afbede3bb32e0c678d8ebe59feabccb5c8f3550ea76cae44b +b38bb4b44d827f6fd3bd34e31f9186c59e312dbfadd4a7a88e588da10146a78b1f8716c91ad8b806beb8da65cab80c4c +9490ce9442bbbd05438c7f5c4dea789f74a7e92b1886a730544b55ba377840740a3ae4f2f146ee73f47c9278b0e233bc +83c003fab22a7178eed1a668e0f65d4fe38ef3900044e9ec63070c23f2827d36a1e73e5c2b883ec6a2afe2450171b3b3 +9982f02405978ddc4fca9063ebbdb152f524c84e79398955e66fe51bc7c1660ec1afc3a86ec49f58d7b7dde03505731c +ab337bd83ccdd2322088ffa8d005f450ced6b35790f37ab4534313315ee84312adc25e99cce052863a8bedee991729ed +8312ce4bec94366d88f16127a17419ef64285cd5bf9e5eda010319b48085966ed1252ed2f5a9fd3e0259b91bb65f1827 +a60d5a6327c4041b0c00a1aa2f0af056520f83c9ce9d9ccd03a0bd4d9e6a1511f26a422ea86bd858a1f77438adf07e6c +b84a0a0b030bdad83cf5202aa9afe58c9820e52483ab41f835f8c582c129ee3f34aa096d11c1cd922eda02ea1196a882 +8077d105317f4a8a8f1aadeb05e0722bb55f11abcb490c36c0904401107eb3372875b0ac233144829e734f0c538d8c1d +9202503bd29a6ec198823a1e4e098f9cfe359ed51eb5174d1ca41368821bfeebcbd49debfd02952c41359d1c7c06d2b1 +abc28c155e09365cb77ffead8dc8f602335ef93b2f44e4ef767ce8fc8ef9dd707400f3a722e92776c2e0b40192c06354 +b0f6d1442533ca45c9399e0a63a11f85ff288d242cea6cb3b68c02e77bd7d158047cae2d25b3bcd9606f8f66d9b32855 +b01c3d56a0db84dc94575f4b6ee2de4beca3230e86bed63e2066beb22768b0a8efb08ebaf8ac3dedb5fe46708b084807 +8c8634b0432159f66feaabb165842d1c8ac378f79565b1b90c381aa8450eb4231c3dad11ec9317b9fc2b155c3a771e32 +8e67f623d69ecd430c9ee0888520b6038f13a2b6140525b056dc0951f0cfed2822e62cf11d952a483107c5c5acac4826 +9590bb1cba816dd6acd5ac5fba5142c0a19d53573e422c74005e0bcf34993a8138c83124cad35a3df65879dba6134edd +801cd96cde0749021a253027118d3ea135f3fcdbe895db08a6c145641f95ebd368dd6a1568d995e1d0084146aebe224a +848b5d196427f6fc1f762ee3d36e832b64a76ec1033cfedc8b985dea93932a7892b8ef1035c653fb9dcd9ab2d9a44ac8 +a1017eb83d5c4e2477e7bd2241b2b98c4951a3b391081cae7d75965cadc1acaec755cf350f1f3d29741b0828e36fedea +8d6d2785e30f3c29aad17bd677914a752f831e96d46caf54446d967cb2432be2c849e26f0d193a60bee161ea5c6fe90a +935c0ba4290d4595428e034b5c8001cbd400040d89ab00861108e8f8f4af4258e41f34a7e6b93b04bc253d3b9ffc13bf +aac02257146246998477921cef2e9892228590d323b839f3e64ea893b991b463bc2f47e1e5092ddb47e70b2f5bce7622 +b921fde9412970a5d4c9a908ae8ce65861d06c7679af577cf0ad0d5344c421166986bee471fd6a6cecb7d591f06ec985 +8ef4c37487b139d6756003060600bb6ebac7ea810b9c4364fc978e842f13ac196d1264fbe5af60d76ff6d9203d8e7d3f +94b65e14022b5cf6a9b95f94be5ace2711957c96f4211c3f7bb36206bd39cfbd0ea82186cab5ad0577a23214a5c86e9e +a31c166d2a2ca1d5a75a5920fef7532681f62191a50d8555fdaa63ba4581c3391cc94a536fc09aac89f64eafceec3f90 +919a8cc128de01e9e10f5d83b08b52293fdd41bde2b5ae070f3d95842d4a16e5331cf2f3d61c765570c8022403610fa4 +b23d6f8331eef100152d60483cfa14232a85ee712c8538c9b6417a5a7c5b353c2ac401390c6c215cb101f5cee6b5f43e +ab357160c08a18319510a571eafff154298ce1020de8e1dc6138a09fcb0fcbcdd8359f7e9386bda00b7b9cdea745ffdc +ab55079aea34afa5c0bd1124b9cdfe01f325b402fdfa017301bf87812eaa811ea5798c3aaf818074d420d1c782b10ada +ade616010dc5009e7fc4f8d8b00dc716686a5fa0a7816ad9e503e15839d3b909b69d9dd929b7575376434ffec0d2bea8 +863997b97ed46898a8a014599508fa3079f414b1f4a0c4fdc6d74ae8b444afa350f327f8bfc2a85d27f9e2d049c50135 +8d602ff596334efd4925549ed95f2aa762b0629189f0df6dbb162581657cf3ea6863cd2287b4d9c8ad52813d87fcd235 +b70f68c596dcdeed92ad5c6c348578b26862a51eb5364237b1221e840c47a8702f0fbc56eb520a22c0eed99795d3903e +9628088f8e0853cefadee305a8bf47fa990c50fa96a82511bbe6e5dc81ef4b794e7918a109070f92fc8384d77ace226f +97e26a46e068b605ce96007197ecd943c9a23881862f4797a12a3e96ba2b8d07806ad9e2a0646796b1889c6b7d75188c +b1edf467c068cc163e2d6413cc22b16751e78b3312fe47b7ea82b08a1206d64415b2c8f2a677fa89171e82cc49797150 +a44d15ef18745b251429703e3cab188420e2d974de07251501799b016617f9630643fcd06f895634d8ecdd579e1bf000 +abd126df3917ba48c618ee4dbdf87df506193462f792874439043fa1b844466f6f4e0ff2e42516e63b5b23c0892b2695 +a2a67f57c4aa3c2aa1eeddbfd5009a89c26c2ce8fa3c96a64626aba19514beb125f27df8559506f737de3eae0f1fc18f +a633e0132197e6038197304b296ab171f1d8e0d0f34dcf66fe9146ac385b0239232a8470b9205a4802ab432389f4836d +a914b3a28509a906c3821463b936455d58ff45dcbe158922f9efb2037f2eb0ce8e92532d29b5d5a3fcd0d23fa773f272 +a0e1412ce4505daf1a2e59ce4f0fc0e0023e335b50d2b204422f57cd65744cc7a8ed35d5ef131a42c70b27111d3115b7 +a2339e2f2b6072e88816224fdd612c04d64e7967a492b9f8829db15367f565745325d361fd0607b0def1be384d010d9e +a7309fc41203cb99382e8193a1dcf03ac190a7ce04835304eb7e341d78634e83ea47cb15b885601956736d04cdfcaa01 +81f3ccd6c7f5b39e4e873365f8c37b214e8ab122d04a606fbb7339dc3298c427e922ec7418002561d4106505b5c399ee +92c121cf914ca549130e352eb297872a63200e99b148d88fbc9506ad882bec9d0203d65f280fb5b0ba92e336b7f932e8 +a4b330cf3f064f5b131578626ad7043ce2a433b6f175feb0b52d36134a454ca219373fd30d5e5796410e005b69082e47 +86fe5774112403ad83f9c55d58317eeb17ad8e1176d9f2f69c2afb7ed83bc718ed4e0245ceab4b377f5f062dcd4c00e7 +809d152a7e2654c7fd175b57f7928365a521be92e1ed06c05188a95864ddb25f7cab4c71db7d61bbf4cae46f3a1d96ce +b82d663e55c2a5ada7e169e9b1a87bc1c0177baf1ec1c96559b4cb1c5214ce1ddf2ab8d345014cab6402f3774235cf5a +86580af86df1bd2c385adb8f9a079e925981b7184db66fc5fe5b14cddb82e7d836b06eaeef14924ac529487b23dae111 +b5f5f4c5c94944ecc804df6ab8687d64e27d988cbfeae1ba7394e0f6adbf778c5881ead7cd8082dd7d68542b9bb4ecd5 +a6016916146c2685c46e8fdd24186394e2d5496e77e08c0c6a709d4cd7dfa97f1efcef94922b89196819076a91ad37b5 +b778e7367ded3b6eab53d5fc257f7a87e8faf74a593900f2f517220add2125be3f6142022660d8181df8d164ad9441ce +8581b2d36abe6f553add4d24be761bec1b8efaa2929519114346615380b3c55b59e6ad86990e312f7e234d0203bdf59b +9917e74fd45c3f71a829ff5498a7f6b5599b48c098dda2339bf04352bfc7f368ccf1a407f5835901240e76452ae807d7 +afd196ce6f9335069138fd2e3d133134da253978b4ce373152c0f26affe77a336505787594022e610f8feb722f7cc1fb +a477491a1562e329764645e8f24d8e228e5ef28c9f74c6b5b3abc4b6a562c15ffb0f680d372aed04d9e1bf944dece7be +9767440d58c57d3077319d3a330e5322b9ba16981ec74a5a14d53462eab59ae7fd2b14025bfc63b268862094acb444e6 +80986d921be3513ef69264423f351a61cb48390c1be8673aee0f089076086aaebea7ebe268fd0aa7182695606116f679 +a9554c5c921c07b450ee04e34ec58e054ac1541b26ce2ce5a393367a97348ba0089f53db6660ad76b60278b66fd12e3e +95097e7d2999b3e84bf052c775581cf361325325f4a50192521d8f4693c830bed667d88f482dc1e3f833aa2bd22d2cbf +9014c91d0f85aefd28436b5228c12f6353c055a9326c7efbf5e071e089e2ee7c070fcbc84c5fafc336cbb8fa6fec1ca1 +90f57ba36ee1066b55d37384942d8b57ae00f3cf9a3c1d6a3dfee1d1af42d4b5fa9baeb0cd7e46687d1d6d090ddb931d +8e4b1db12fd760a17214c9e47f1fce6e43c0dbb4589a827a13ac61aaae93759345697bb438a00edab92e0b7b62414683 +8022a959a513cdc0e9c705e0fc04eafd05ff37c867ae0f31f6d01cddd5df86138a426cab2ff0ac8ff03a62e20f7e8f51 +914e9a38829834c7360443b8ed86137e6f936389488eccf05b4b4db7c9425611705076ecb3f27105d24b85c852be7511 +957fb10783e2bd0db1ba66b18e794df710bc3b2b05776be146fa5863c15b1ebdd39747b1a95d9564e1772cdfc4f37b8a +b6307028444daed8ed785ac9d0de76bc3fe23ff2cc7e48102553613bbfb5afe0ebe45e4212a27021c8eb870721e62a1f +8f76143597777d940b15a01b39c5e1b045464d146d9a30a6abe8b5d3907250e6c7f858ff2308f8591e8b0a7b3f3c568a +96163138ac0ce5fd00ae9a289648fd9300a0ca0f63a88481d703ecd281c06a52a3b5178e849e331f9c85ca4ba398f4cc +a63ef47c3e18245b0482596a09f488a716df3cbd0f9e5cfabed0d742843e65db8961c556f45f49762f3a6ac8b627b3ef +8cb595466552e7c4d42909f232d4063e0a663a8ef6f6c9b7ce3a0542b2459cde04e0e54c7623d404acb5b82775ac04f6 +b47fe69960eb45f399368807cff16d941a5a4ebad1f5ec46e3dc8a2e4d598a7e6114d8f0ca791e9720fd786070524e2b +89eb5ff83eea9df490e5beca1a1fbbbbcf7184a37e2c8c91ede7a1e654c81e8cd41eceece4042ea7918a4f4646b67fd6 +a84f5d155ed08b9054eecb15f689ba81e44589e6e7207a99790c598962837ca99ec12344105b16641ca91165672f7153 +a6cc8f25c2d5b2d2f220ec359e6a37a52b95fa6af6e173c65e7cd55299eff4aa9e6d9e6f2769e6459313f1f2aecb0fab +afcde944411f017a9f7979755294981e941cc41f03df5e10522ef7c7505e5f1babdd67b3bf5258e8623150062eb41d9b +8fab39f39c0f40182fcd996ade2012643fe7731808afbc53f9b26900b4d4d1f0f5312d9d40b3df8baa4739970a49c732 +ae193af9726da0ebe7df1f9ee1c4846a5b2a7621403baf8e66c66b60f523e719c30c6b4f897bb14b27d3ff3da8392eeb +8ac5adb82d852eba255764029f42e6da92dcdd0e224d387d1ef94174038db9709ac558d90d7e7c57ad4ce7f89bbfc38c +a2066b3458fdf678ee487a55dd5bfb74fde03b54620cb0e25412a89ee28ad0d685e309a51e3e4694be2fa6f1593a344c +88d031745dd0ae07d61a15b594be5d4b2e2a29e715d081649ad63605e3404b0c3a5353f0fd9fad9c05c18e93ce674fa1 +8283cfb0ef743a043f2b77ecaeba3005e2ca50435585b5dd24777ee6bce12332f85e21b446b536da38508807f0f07563 +b376de22d5f6b0af0b59f7d9764561f4244cf8ffe22890ecd3dcf2ff1832130c9b821e068c9d8773136f4796721e5963 +ae3afc50c764f406353965363840bf28ee85e7064eb9d5f0bb3c31c64ab10f48c853e942ee2c9b51bae59651eaa08c2f +948b204d103917461a01a6c57a88f2d66b476eae5b00be20ec8c747650e864bc8a83aee0aff59cb7584b7a3387e0ee48 +81ab098a082b07f896c5ffd1e4446cb7fb44804cbbf38d125208b233fc82f8ec9a6a8d8dd1c9a1162dc28ffeec0dde50 +a149c6f1312821ced2969268789a3151bdda213451760b397139a028da609c4134ac083169feb0ee423a0acafd10eceb +b0ac9e27a5dadaf523010f730b28f0ebac01f460d3bbbe277dc9d44218abb5686f4fac89ae462682fef9edbba663520a +8d0e0073cca273daaaa61b6fc54bfe5a009bc3e20ae820f6c93ba77b19eca517d457e948a2de5e77678e4241807157cb +ad61d3a2edf7c7533a04964b97499503fd8374ca64286dba80465e68fe932e96749b476f458c6fc57cb1a7ca85764d11 +90eb5e121ae46bc01a30881eaa556f46bd8457a4e80787cf634aab355082de34ac57d7f497446468225f7721e68e2a47 +8cdac557de7c42d1f3780e33dec1b81889f6352279be81c65566cdd4952d4c15d79e656cbd46035ab090b385e90245ef +82b67e61b88b84f4f4d4f65df37b3e3dcf8ec91ea1b5c008fdccd52da643adbe6468a1cfdb999e87d195afe2883a3b46 +8503b467e8f5d6048a4a9b78496c58493a462852cab54a70594ae3fd064cfd0deb4b8f336a262155d9fedcaa67d2f6fd +8db56c5ac763a57b6ce6832930c57117058e3e5a81532b7d19346346205e2ec614eb1a2ee836ef621de50a7bc9b7f040 +ad344699198f3c6e8c0a3470f92aaffc805b76266734414c298e10b5b3797ca53578de7ccb2f458f5e0448203f55282b +80602032c43c9e2a09154cc88b83238343b7a139f566d64cb482d87436b288a98f1ea244fd3bff8da3c398686a900c14 +a6385bd50ecd548cfb37174cdbb89e10025b5cadaf3cff164c95d7aef5a33e3d6a9bf0c681b9e11db9ef54ebeee2a0c1 +abf2d95f4aa34b0581eb9257a0cc8462b2213941a5deb8ba014283293e8b36613951b61261cc67bbd09526a54cbbff76 +a3d5de52f48df72c289ff713e445991f142390798cd42bd9d9dbefaee4af4f5faf09042d126b975cf6b98711c3072553 +8e627302ff3d686cff8872a1b7c2a57b35f45bf2fc9aa42b049d8b4d6996a662b8e7cbac6597f0cb79b0cc4e29fbf133 +8510702e101b39a1efbf4e504e6123540c34b5689645e70d0bac1ecc1baf47d86c05cef6c4317a4e99b4edaeb53f2d00 +aa173f0ecbcc6088f878f8726d317748c81ebf501bba461f163b55d66099b191ec7c55f7702f351a9c8eb42cfa3280e2 +b560a697eafab695bcef1416648a0a664a71e311ecbe5823ae903bd0ed2057b9d7574b9a86d3fe22aa3e6ddce38ea513 +8df6304a3d9cf40100f3f687575419c998cd77e5cc27d579cf4f8e98642de3609af384a0337d145dd7c5635172d26a71 +8105c7f3e4d30a29151849673853b457c1885c186c132d0a98e63096c3774bc9deb956cf957367e633d0913680bda307 +95373fc22c0917c3c2044ac688c4f29a63ed858a45c0d6d2d0fe97afd6f532dcb648670594290c1c89010ecc69259bef +8c2fae9bcadab341f49b55230310df93cac46be42d4caa0d42e45104148a91e527af1b4209c0d972448162aed28fab64 +b05a77baab70683f76209626eaefdda2d36a0b66c780a20142d23c55bd479ddd4ad95b24579384b6cf62c8eb4c92d021 +8e6bc6a7ea2755b4aaa19c1c1dee93811fcde514f03485fdc3252f0ab7f032c315614f6336e57cea25dcfb8fb6084eeb +b656a27d06aade55eadae2ad2a1059198918ea6cc3fd22c0ed881294d34d5ac7b5e4700cc24350e27d76646263b223aa +a296469f24f6f56da92d713afcd4dd606e7da1f79dc4e434593c53695847eefc81c7c446486c4b3b8c8d00c90c166f14 +87a326f57713ac2c9dffeb3af44b9f3c613a8f952676fc46343299122b47ee0f8d792abaa4b5db6451ced5dd153aabd0 +b689e554ba9293b9c1f6344a3c8fcb6951d9f9eac4a2e2df13de021aade7c186be27500e81388e5b8bcab4c80f220a31 +87ae0aa0aa48eac53d1ca5a7b93917de12db9e40ceabf8fdb40884ae771cfdf095411deef7c9f821af0b7070454a2608 +a71ffa7eae8ace94e6c3581d4cb2ad25d48cbd27edc9ec45baa2c8eb932a4773c3272b2ffaf077b40f76942a1f3af7f2 +94c218c91a9b73da6b7a495b3728f3028df8ad9133312fc0c03e8c5253b7ccb83ed14688fd4602e2fd41f29a0bc698bd +ae1e77b90ca33728af07a4c03fb2ef71cd92e2618e7bf8ed4d785ce90097fc4866c29999eb84a6cf1819d75285a03af2 +b7a5945b277dab9993cf761e838b0ac6eaa903d7111fca79f9fde3d4285af7a89bf6634a71909d095d7619d913972c9c +8c43b37be02f39b22029b20aca31bff661abce4471dca88aa3bddefd9c92304a088b2dfc8c4795acc301ca3160656af2 +b32e5d0fba024554bd5fe8a793ebe8003335ddd7f585876df2048dcf759a01285fecb53daae4950ba57f3a282a4d8495 +85ea7fd5e10c7b659df5289b2978b2c89e244f269e061b9a15fcab7983fc1962b63546e82d5731c97ec74b6804be63ef +96b89f39181141a7e32986ac02d7586088c5a9662cec39843f397f3178714d02f929af70630c12cbaba0268f8ba2d4fa +929ab1a2a009b1eb37a2817c89696a06426529ebe3f306c586ab717bd34c35a53eca2d7ddcdef36117872db660024af9 +a696dccf439e9ca41511e16bf3042d7ec0e2f86c099e4fc8879d778a5ea79e33aa7ce96b23dc4332b7ba26859d8e674d +a8fe69a678f9a194b8670a41e941f0460f6e2dbc60470ab4d6ae2679cc9c6ce2c3a39df2303bee486dbfde6844e6b31a +95f58f5c82de2f2a927ca99bf63c9fc02e9030c7e46d0bf6b67fe83a448d0ae1c99541b59caf0e1ccab8326231af09a5 +a57badb2c56ca2c45953bd569caf22968f76ed46b9bac389163d6fe22a715c83d5e94ae8759b0e6e8c2f27bff7748f3f +868726fd49963b24acb5333364dffea147e98f33aa19c7919dc9aca0fd26661cfaded74ede7418a5fadbe7f5ae67b67b +a8d8550dcc64d9f1dd7bcdab236c4122f2b65ea404bb483256d712c7518f08bb028ff8801f1da6aed6cbfc5c7062e33b +97e25a87dae23155809476232178538d4bc05d4ff0882916eb29ae515f2a62bfce73083466cc0010ca956aca200aeacc +b4ea26be3f4bd04aa82d7c4b0913b97bcdf5e88b76c57eb1a336cbd0a3eb29de751e1bc47c0e8258adec3f17426d0c71 +99ee555a4d9b3cf2eb420b2af8e3bc99046880536116d0ce7193464ac40685ef14e0e3c442f604e32f8338cb0ef92558 +8c64efa1da63cd08f319103c5c7a761221080e74227bbc58b8fb35d08aa42078810d7af3e60446cbaff160c319535648 +8d9fd88040076c28420e3395cbdfea402e4077a3808a97b7939d49ecbcf1418fe50a0460e1c1b22ac3f6e7771d65169a +ae3c19882d7a9875d439265a0c7003c8d410367627d21575a864b9cb4918de7dbdb58a364af40c5e045f3df40f95d337 +b4f7bfacab7b2cafe393f1322d6dcc6f21ffe69cd31edc8db18c06f1a2b512c27bd0618091fd207ba8df1808e9d45914 +94f134acd0007c623fb7934bcb65ef853313eb283a889a3ffa79a37a5c8f3665f3d5b4876bc66223610c21dc9b919d37 +aa15f74051171daacdc1f1093d3f8e2d13da2833624b80a934afec86fc02208b8f55d24b7d66076444e7633f46375c6a +a32d6bb47ef9c836d9d2371807bafbbbbb1ae719530c19d6013f1d1f813c49a60e4fa51d83693586cba3a840b23c0404 +b61b3599145ea8680011aa2366dc511a358b7d67672d5b0c5be6db03b0efb8ca5a8294cf220ea7409621f1664e00e631 +859cafc3ee90b7ececa1ed8ef2b2fc17567126ff10ca712d5ffdd16aa411a5a7d8d32c9cab1fbf63e87dce1c6e2f5f53 +a2fef1b0b2874387010e9ae425f3a9676d01a095d017493648bcdf3b31304b087ccddb5cf76abc4e1548b88919663b6b +939e18c73befc1ba2932a65ede34c70e4b91e74cc2129d57ace43ed2b3af2a9cc22a40fbf50d79a63681b6d98852866d +b3b4259d37b1b14aee5b676c9a0dd2d7f679ab95c120cb5f09f9fbf10b0a920cb613655ddb7b9e2ba5af4a221f31303c +997255fe51aaca6e5a9cb3359bcbf25b2bb9e30649bbd53a8a7c556df07e441c4e27328b38934f09c09d9500b5fabf66 +abb91be2a2d860fd662ed4f1c6edeefd4da8dc10e79251cf87f06029906e7f0be9b486462718f0525d5e049472692cb7 +b2398e593bf340a15f7801e1d1fbda69d93f2a32a889ec7c6ae5e8a37567ac3e5227213c1392ee86cfb3b56ec2787839 +8ddf10ccdd72922bed36829a36073a460c2118fc7a56ff9c1ac72581c799b15c762cb56cb78e3d118bb9f6a7e56cb25e +93e6bc0a4708d16387cacd44cf59363b994dc67d7ada7b6d6dbd831c606d975247541b42b2a309f814c1bfe205681fc6 +b93fc35c05998cffda2978e12e75812122831523041f10d52f810d34ff71944979054b04de0117e81ddf5b0b4b3e13c0 +92221631c44d60d68c6bc7b287509f37ee44cbe5fdb6935cee36b58b17c7325098f98f7910d2c3ca5dc885ad1d6dabc7 +a230124424a57fad3b1671f404a94d7c05f4c67b7a8fbacfccea28887b78d7c1ed40b92a58348e4d61328891cd2f6cee +a6a230edb8518a0f49d7231bc3e0bceb5c2ac427f045819f8584ba6f3ae3d63ed107a9a62aad543d7e1fcf1f20605706 +845be1fe94223c7f1f97d74c49d682472585d8f772762baad8a9d341d9c3015534cc83d102113c51a9dea2ab10d8d27b +b44262515e34f2db597c8128c7614d33858740310a49cdbdf9c8677c5343884b42c1292759f55b8b4abc4c86e4728033 +805592e4a3cd07c1844bc23783408310accfdb769cca882ad4d07d608e590a288b7370c2cb327f5336e72b7083a0e30f +95153e8b1140df34ee864f4ca601cb873cdd3efa634af0c4093fbaede36f51b55571ab271e6a133020cd34db8411241f +82878c1285cfa5ea1d32175c9401f3cc99f6bb224d622d3fd98cc7b0a27372f13f7ab463ce3a33ec96f9be38dbe2dfe3 +b7588748f55783077c27fc47d33e20c5c0f5a53fc0ac10194c003aa09b9f055d08ec971effa4b7f760553997a56967b3 +b36b4de6d1883b6951f59cfae381581f9c6352fcfcf1524fccdab1571a20f80441d9152dc6b48bcbbf00371337ca0bd5 +89c5523f2574e1c340a955cbed9c2f7b5fbceb260cb1133160dabb7d41c2f613ec3f6e74bbfab3c4a0a6f0626dbe068f +a52f58cc39f968a9813b1a8ddc4e83f4219e4dd82c7aa1dd083bea7edf967151d635aa9597457f879771759b876774e4 +8300a67c2e2e123f89704abfde095463045dbd97e20d4c1157bab35e9e1d3d18f1f4aaba9cbe6aa2d544e92578eaa1b6 +ac6a7f2918768eb6a43df9d3a8a04f8f72ee52f2e91c064c1c7d75cad1a3e83e5aba9fe55bb94f818099ac91ccf2e961 +8d64a2b0991cf164e29835c8ddef6069993a71ec2a7de8157bbfa2e00f6367be646ed74cbaf524f0e9fe13fb09fa15fd +8b2ffe5a545f9f680b49d0a9797a4a11700a2e2e348c34a7a985fc278f0f12def6e06710f40f9d48e4b7fbb71e072229 +8ab8f71cd337fa19178924e961958653abf7a598e3f022138b55c228440a2bac4176cea3aea393549c03cd38a13eb3fc +8419d28318c19ea4a179b7abb43669fe96347426ef3ac06b158d79c0acf777a09e8e770c2fb10e14b3a0421705990b23 +8bacdac310e1e49660359d0a7a17fe3d334eb820e61ae25e84cb52f863a2f74cbe89c2e9fc3283745d93a99b79132354 +b57ace3fa2b9f6b2db60c0d861ace7d7e657c5d35d992588aeed588c6ce3a80b6f0d49f8a26607f0b17167ab21b675e4 +83e265cde477f2ecc164f49ddc7fb255bb05ff6adc347408353b7336dc3a14fdedc86d5a7fb23f36b8423248a7a67ed1 +a60ada971f9f2d79d436de5d3d045f5ab05308cae3098acaf5521115134b2a40d664828bb89895840db7f7fb499edbc5 +a63eea12efd89b62d3952bf0542a73890b104dd1d7ff360d4755ebfa148fd62de668edac9eeb20507967ea37fb220202 +a0275767a270289adc991cc4571eff205b58ad6d3e93778ddbf95b75146d82517e8921bd0d0564e5b75fa0ccdab8e624 +b9b03fd3bf07201ba3a039176a965d736b4ef7912dd9e9bf69fe1b57c330a6aa170e5521fe8be62505f3af81b41d7806 +a95f640e26fb1106ced1729d6053e41a16e4896acac54992279ff873e5a969aad1dcfa10311e28b8f409ac1dab7f03bb +b144778921742418053cb3c70516c63162c187f00db2062193bb2c14031075dbe055d020cde761b26e8c58d0ea6df2c1 +8432fbb799e0435ef428d4fefc309a05dd589bce74d7a87faf659823e8c9ed51d3e42603d878e80f439a38be4321c2fa +b08ddef14e42d4fd5d8bf39feb7485848f0060d43b51ed5bdda39c05fe154fb111d29719ee61a23c392141358c0cfcff +8ae3c5329a5e025b86b5370e06f5e61177df4bda075856fade20a17bfef79c92f54ed495f310130021ba94fb7c33632b +92b6d3c9444100b4d7391febfc1dddaa224651677c3695c47a289a40d7a96d200b83b64e6d9df51f534564f272a2c6c6 +b432bc2a3f93d28b5e506d68527f1efeb2e2570f6be0794576e2a6ef9138926fdad8dd2eabfa979b79ab7266370e86bc +8bc315eacedbcfc462ece66a29662ca3dcd451f83de5c7626ef8712c196208fb3d8a0faf80b2e80384f0dd9772f61a23 +a72375b797283f0f4266dec188678e2b2c060dfed5880fc6bb0c996b06e91a5343ea2b695adaab0a6fd183b040b46b56 +a43445036fbaa414621918d6a897d3692fdae7b2961d87e2a03741360e45ebb19fcb1703d23f1e15bb1e2babcafc56ac +b9636b2ffe305e63a1a84bd44fb402442b1799bd5272638287aa87ca548649b23ce8ce7f67be077caed6aa2dbc454b78 +99a30bf0921d854c282b83d438a79f615424f28c2f99d26a05201c93d10378ab2cd94a792b571ddae5d4e0c0013f4006 +8648e3c2f93d70b392443be116b48a863e4b75991bab5db656a4ef3c1e7f645e8d536771dfe4e8d1ceda3be8d32978b0 +ab50dc9e6924c1d2e9d2e335b2d679fc7d1a7632e84964d3bac0c9fe57e85aa5906ec2e7b0399d98ddd022e9b19b5904 +ab729328d98d295f8f3272afaf5d8345ff54d58ff9884da14f17ecbdb7371857fdf2f3ef58080054e9874cc919b46224 +83fa5da7592bd451cad3ad7702b4006332b3aae23beab4c4cb887fa6348317d234bf62a359e665b28818e5410c278a09 +8bdbff566ae9d368f114858ef1f009439b3e9f4649f73efa946e678d6c781d52c69af195df0a68170f5f191b2eac286b +91245e59b4425fd4edb2a61d0d47c1ccc83d3ced8180de34887b9655b5dcda033d48cde0bdc3b7de846d246c053a02e8 +a2cb00721e68f1cad8933947456f07144dc69653f96ceed845bd577d599521ba99cdc02421118971d56d7603ed118cbf +af8cd66d303e808b22ec57860dd909ca64c27ec2c60e26ffecfdc1179d8762ffd2739d87b43959496e9fee4108df71df +9954136812dffcd5d3f167a500e7ab339c15cfc9b3398d83f64b0daa3dd5b9a851204f424a3493b4e326d3de81e50a62 +93252254d12511955f1aa464883ad0da793f84d900fea83e1df8bca0f2f4cf5b5f9acbaec06a24160d33f908ab5fea38 +997cb55c26996586ba436a95566bd535e9c22452ca5d2a0ded2bd175376557fa895f9f4def4519241ff386a063f2e526 +a12c78ad451e0ac911260ade2927a768b50cb4125343025d43474e7f465cdc446e9f52a84609c5e7e87ae6c9b3f56cda +a789d4ca55cbba327086563831b34487d63d0980ba8cf55197c016702ed6da9b102b1f0709ce3da3c53ff925793a3d73 +a5d76acbb76741ce85be0e655b99baa04f7f587347947c0a30d27f8a49ae78cce06e1cde770a8b618d3db402be1c0c4b +873c0366668c8faddb0eb7c86f485718d65f8c4734020f1a18efd5fa123d3ea8a990977fe13592cd01d17e60809cb5ff +b659b71fe70f37573ff7c5970cc095a1dc0da3973979778f80a71a347ef25ad5746b2b9608bad4ab9a4a53a4d7df42d7 +a34cbe05888e5e5f024a2db14cb6dcdc401a9cbd13d73d3c37b348f68688f87c24ca790030b8f84fef9e74b4eab5e412 +94ce8010f85875c045b0f014db93ef5ab9f1f6842e9a5743dce9e4cb872c94affd9e77c1f1d1ab8b8660b52345d9acb9 +adefa9b27a62edc0c5b019ddd3ebf45e4de846165256cf6329331def2e088c5232456d3de470fdce3fa758bfdd387512 +a6b83821ba7c1f83cc9e4529cf4903adb93b26108e3d1f20a753070db072ad5a3689643144bdd9c5ea06bb9a7a515cd0 +a3a9ddedc2a1b183eb1d52de26718151744db6050f86f3580790c51d09226bf05f15111691926151ecdbef683baa992c +a64bac89e7686932cdc5670d07f0b50830e69bfb8c93791c87c7ffa4913f8da881a9d8a8ce8c1a9ce5b6079358c54136 +a77b5a63452cb1320b61ab6c7c2ef9cfbcade5fd4727583751fb2bf3ea330b5ca67757ec1f517bf4d503ec924fe32fbd +8746fd8d8eb99639d8cd0ca34c0d9c3230ed5a312aab1d3d925953a17973ee5aeb66e68667e93caf9cb817c868ea8f3d +88a2462a26558fc1fbd6e31aa8abdc706190a17c27fdc4217ffd2297d1b1f3321016e5c4b2384c5454d5717dc732ed03 +b78893a97e93d730c8201af2e0d3b31cb923d38dc594ffa98a714e627c473d42ea82e0c4d2eeb06862ee22a9b2c54588 +920cc8b5f1297cf215a43f6fc843e379146b4229411c44c0231f6749793d40f07b9af7699fd5d21fd69400b97febe027 +a0f0eafce1e098a6b58c7ad8945e297cd93aaf10bc55e32e2e32503f02e59fc1d5776936577d77c0b1162cb93b88518b +98480ba0064e97a2e7a6c4769b4d8c2a322cfc9a3b2ca2e67e9317e2ce04c6e1108169a20bd97692e1cb1f1423b14908 +83dbbb2fda7e287288011764a00b8357753a6a44794cc8245a2275237f11affdc38977214e463ad67aec032f3dfa37e9 +86442fff37598ce2b12015ff19b01bb8a780b40ad353d143a0f30a06f6d23afd5c2b0a1253716c855dbf445cc5dd6865 +b8a4c60c5171189414887847b9ed9501bff4e4c107240f063e2d254820d2906b69ef70406c585918c4d24f1dd052142b +919f33a98e84015b2034b57b5ffe9340220926b2c6e45f86fd79ec879dbe06a148ae68b77b73bf7d01bd638a81165617 +95c13e78d89474a47fbc0664f6f806744b75dede95a479bbf844db4a7f4c3ae410ec721cb6ffcd9fa9c323da5740d5ae +ab7151acc41fffd8ec6e90387700bcd7e1cde291ea669567295bea1b9dd3f1df2e0f31f3588cd1a1c08af8120aca4921 +80e74c5c47414bd6eeef24b6793fb1fa2d8fb397467045fcff887c52476741d5bc4ff8b6d3387cb53ad285485630537f +a296ad23995268276aa351a7764d36df3a5a3cffd7dbeddbcea6b1f77adc112629fdeffa0918b3242b3ccd5e7587e946 +813d2506a28a2b01cb60f49d6bd5e63c9b056aa56946faf2f33bd4f28a8d947569cfead3ae53166fc65285740b210f86 +924b265385e1646287d8c09f6c855b094daaee74b9e64a0dddcf9ad88c6979f8280ba30c8597b911ef58ddb6c67e9fe3 +8d531513c70c2d3566039f7ca47cd2352fd2d55b25675a65250bdb8b06c3843db7b2d29c626eed6391c238fc651cf350 +82b338181b62fdc81ceb558a6843df767b6a6e3ceedc5485664b4ea2f555904b1a45fbb35f6cf5d96f27da10df82a325 +92e62faaedea83a37f314e1d3cb4faaa200178371d917938e59ac35090be1db4b4f4e0edb78b9c991de202efe4f313d8 +99d645e1b642c2dc065bac9aaa0621bc648c9a8351efb6891559c3a41ba737bd155fb32d7731950514e3ecf4d75980e4 +b34a13968b9e414172fb5d5ece9a39cf2eb656128c3f2f6cc7a9f0c69c6bae34f555ecc8f8837dc34b5e470e29055c78 +a2a0bb7f3a0b23a2cbc6585d59f87cd7e56b2bbcb0ae48f828685edd9f7af0f5edb4c8e9718a0aaf6ef04553ba71f3b7 +8e1a94bec053ed378e524b6685152d2b52d428266f2b6eadd4bcb7c4e162ed21ab3e1364879673442ee2162635b7a4d8 +9944adaff14a85eab81c73f38f386701713b52513c4d4b838d58d4ffa1d17260a6d056b02334850ea9a31677c4b078bd +a450067c7eceb0854b3eca3db6cf38669d72cb7143c3a68787833cbca44f02c0be9bfbe082896f8a57debb13deb2afb1 +8be4ad3ac9ef02f7df09254d569939757101ee2eda8586fefcd8c847adc1efe5bdcb963a0cafa17651befaafb376a531 +90f6de91ea50255f148ac435e08cf2ac00c772a466e38155bd7e8acf9197af55662c7b5227f88589b71abe9dcf7ba343 +86e5a24f0748b106dee2d4d54e14a3b0af45a96cbee69cac811a4196403ebbee17fd24946d7e7e1b962ac7f66dbaf610 +afdd96fbcda7aa73bf9eeb2292e036c25753d249caee3b9c013009cc22e10d3ec29e2aa6ddbb21c4e949b0c0bccaa7f4 +b5a4e7436d5473647c002120a2cb436b9b28e27ad4ebdd7c5f122b91597c507d256d0cbd889d65b3a908531936e53053 +b632414c3da704d80ac2f3e5e0e9f18a3637cdc2ebeb613c29300745582427138819c4e7b0bec3099c1b8739dac1807b +a28df1464d3372ce9f37ef1db33cc010f752156afae6f76949d98cd799c0cf225c20228ae86a4da592d65f0cffe3951b +898b93d0a31f7d3f11f253cb7a102db54b669fd150da302d8354d8e02b1739a47cb9bd88015f3baf12b00b879442464e +96fb88d89a12049091070cb0048a381902965e67a8493e3991eaabe5d3b7ff7eecd5c94493a93b174df3d9b2c9511755 +b899cb2176f59a5cfba3e3d346813da7a82b03417cad6342f19cc8f12f28985b03bf031e856a4743fd7ebe16324805b0 +a60e2d31bc48e0c0579db15516718a03b73f5138f15037491f4dae336c904e312eda82d50862f4debd1622bb0e56d866 +979fc8b987b5cef7d4f4b58b53a2c278bd25a5c0ea6f41c715142ea5ff224c707de38451b0ad3aa5e749aa219256650a +b2a75bff18e1a6b9cf2a4079572e41205741979f57e7631654a3c0fcec57c876c6df44733c9da3d863db8dff392b44a3 +b7a0f0e811222c91e3df98ff7f286b750bc3b20d2083966d713a84a2281744199e664879401e77470d44e5a90f3e5181 +82b74ba21c9d147fbc338730e8f1f8a6e7fc847c3110944eb17a48bea5e06eecded84595d485506d15a3e675fd0e5e62 +a7f44eef817d5556f0d1abcf420301217d23c69dd2988f44d91ea1f1a16c322263cbacd0f190b9ba22b0f141b9267b4f +aadb68164ede84fc1cb3334b3194d84ba868d5a88e4c9a27519eef4923bc4abf81aab8114449496c073c2a6a0eb24114 +b5378605fabe9a8c12a5dc55ef2b1de7f51aedb61960735c08767a565793cea1922a603a6983dc25f7cea738d0f7c40d +a97a4a5cd8d51302e5e670aee78fe6b5723f6cc892902bbb4f131e82ca1dfd5de820731e7e3367fb0c4c1922a02196e3 +8bdfeb15c29244d4a28896f2b2cb211243cd6a1984a3f5e3b0ebe5341c419beeab3304b390a009ffb47588018034b0ea +a9af3022727f2aa2fca3b096968e97edad3f08edcbd0dbca107b892ae8f746a9c0485e0d6eb5f267999b23a845923ed0 +8e7594034feef412f055590fbb15b6322dc4c6ab7a4baef4685bd13d71a83f7d682b5781bdfa0d1c659489ce9c2b8000 +84977ca6c865ebee021c58106c1a4ad0c745949ecc5332948002fd09bd9b890524878d0c29da96fd11207621136421fe +8687551a79158e56b2375a271136756313122132a6670fa51f99a1b5c229ed8eea1655a734abae13228b3ebfd2a825dd +a0227d6708979d99edfc10f7d9d3719fd3fc68b0d815a7185b60307e4c9146ad2f9be2b8b4f242e320d4288ceeb9504c +89f75583a16735f9dd8b7782a130437805b34280ccea8dac6ecaee4b83fe96947e7b53598b06fecfffdf57ffc12cc445 +a0056c3353227f6dd9cfc8e3399aa5a8f1d71edf25d3d64c982910f50786b1e395c508d3e3727ac360e3e040c64b5298 +b070e61a6d813626144b312ded1788a6d0c7cec650a762b2f8df6e4743941dd82a2511cd956a3f141fc81e15f4e092da +b4e6db232e028a1f989bb5fc13416711f42d389f63564d60851f009dcffac01acfd54efa307aa6d4c0f932892d4e62b0 +89b5991a67db90024ddd844e5e1a03ef9b943ad54194ae0a97df775dde1addf31561874f4e40fbc37a896630f3bbda58 +ad0e8442cb8c77d891df49cdb9efcf2b0d15ac93ec9be1ad5c3b3cca1f4647b675e79c075335c1f681d56f14dc250d76 +b5d55a6ae65bb34dd8306806cb49b5ccb1c83a282ee47085cf26c4e648e19a52d9c422f65c1cd7e03ca63e926c5e92ea +b749501347e5ec07e13a79f0cb112f1b6534393458b3678a77f02ca89dca973fa7b30e55f0b25d8b92b97f6cb0120056 +94144b4a3ffc5eec6ba35ce9c245c148b39372d19a928e236a60e27d7bc227d18a8cac9983851071935d8ffb64b3a34f +92bb4f9f85bc8c028a3391306603151c6896673135f8a7aefedd27acb322c04ef5dac982fc47b455d6740023e0dd3ea3 +b9633a4a101461a782fc2aa092e9dbe4e2ad00987578f18cd7cf0021a909951d60fe79654eb7897806795f93c8ff4d1c +809f0196753024821b48a016eca5dbb449a7c55750f25981bb7a4b4c0e0846c09b8f6128137905055fc43a3f0deb4a74 +a27dc9cdd1e78737a443570194a03d89285576d3d7f3a3cf15cc55b3013e42635d4723e2e8fe1d0b274428604b630db9 +861f60f0462e04cd84924c36a28163def63e777318d00884ab8cb64c8df1df0bce5900342163edb60449296484a6c5bf +b7bc23fb4e14af4c4704a944253e760adefeca8caee0882b6bbd572c84434042236f39ae07a8f21a560f486b15d82819 +b9a6eb492d6dd448654214bd01d6dc5ff12067a11537ab82023fc16167507ee25eed2c91693912f4155d1c07ed9650b3 +97678af29c68f9a5e213bf0fb85c265303714482cfc4c2c00b4a1e8a76ed08834ee6af52357b143a1ca590fb0265ea5a +8a15b499e9eca5b6cac3070b5409e8296778222018ad8b53a5d1f6b70ad9bb10c68a015d105c941ed657bf3499299e33 +b487fefede2e8091f2c7bfe85770db2edff1db83d4effe7f7d87bff5ab1ace35e9b823a71adfec6737fede8d67b3c467 +8b51b916402aa2c437fce3bcad6dad3be8301a1a7eab9d163085b322ffb6c62abf28637636fe6114573950117fc92898 +b06a2106d031a45a494adec0881cb2f82275dff9dcdd2bc16807e76f3bec28a6734edd3d54f0be8199799a78cd6228ad +af0a185391bbe2315eb97feac98ad6dd2e5d931d012c621abd6e404a31cc188b286fef14871762190acf086482b2b5e2 +8e78ee8206506dd06eb7729e32fceda3bebd8924a64e4d8621c72e36758fda3d0001af42443851d6c0aea58562870b43 +a1ba52a569f0461aaf90b49b92be976c0e73ec4a2c884752ee52ffb62dd137770c985123d405dfb5de70692db454b54a +8d51b692fa1543c51f6b62b9acb8625ed94b746ef96c944ca02859a4133a5629da2e2ce84e111a7af8d9a5b836401c64 +a7a20d45044cf6492e0531d0b8b26ffbae6232fa05a96ed7f06bdb64c2b0f5ca7ec59d5477038096a02579e633c7a3ff +84df867b98c53c1fcd4620fef133ee18849c78d3809d6aca0fb6f50ff993a053a455993f216c42ab6090fa5356b8d564 +a7227c439f14c48e2577d5713c97a5205feb69acb0b449152842e278fa71e8046adfab468089c8b2288af1fc51fa945b +855189b3a105670779997690876dfaa512b4a25a24931a912c2f0f1936971d2882fb4d9f0b3d9daba77eaf660e9d05d5 +b5696bd6706de51c502f40385f87f43040a5abf99df705d6aac74d88c913b8ecf7a99a63d7a37d9bdf3a941b9e432ff5 +ab997beb0d6df9c98d5b49864ef0b41a2a2f407e1687dfd6089959757ba30ed02228940b0e841afe6911990c74d536c4 +b36b65f85546ebfdbe98823d5555144f96b4ab39279facd19c0de3b8919f105ba0315a0784dce4344b1bc62d8bb4a5a3 +b8371f0e4450788720ac5e0f6cd3ecc5413d33895083b2c168d961ec2b5c3de411a4cc0712481cbe8df8c2fa1a7af006 +98325d8026b810a8b7a114171ae59a57e8bbc9848e7c3df992efc523621729fd8c9f52114ce01d7730541a1ada6f1df1 +8d0e76dbd37806259486cd9a31bc8b2306c2b95452dc395546a1042d1d17863ef7a74c636b782e214d3aa0e8d717f94a +a4e15ead76da0214d702c859fb4a8accdcdad75ed08b865842bd203391ec4cba2dcc916455e685f662923b96ee0c023f +8618190972086ebb0c4c1b4a6c94421a13f378bc961cc8267a301de7390c5e73c3333864b3b7696d81148f9d4843fd02 +85369d6cc7342e1aa15b59141517d8db8baaaeb7ab9670f3ba3905353948d575923d283b7e5a05b13a30e7baf1208a86 +87c51ef42233c24a6da901f28c9a075d9ba3c625687c387ad6757b72ca6b5a8885e6902a3082da7281611728b1e45f26 +aa6348a4f71927a3106ad0ea8b02fc8d8c65531e4ab0bd0a17243e66f35afe252e40ab8eef9f13ae55a72566ffdaff5c +96a3bc976e9d03765cc3fee275fa05b4a84c94fed6b767e23ca689394501e96f56f7a97cffddc579a6abff632bf153be +97dbf96c6176379fdb2b888be4e757b2bca54e74124bd068d3fa1dbd82a011bbeb75079da38e0cd22a761fe208ecad9b +b70cf0a1d14089a4129ec4e295313863a59da8c7e26bf74cc0e704ed7f0ee4d7760090d0ddf7728180f1bf2c5ac64955 +882d664714cc0ffe53cbc9bef21f23f3649824f423c4dbad1f893d22c4687ab29583688699efc4d5101aa08b0c3e267a +80ecb7cc963e677ccaddbe3320831dd6ee41209acf4ed41b16dc4817121a3d86a1aac9c4db3d8c08a55d28257088af32 +a25ba667d832b145f9ce18c3f9b1bd00737aa36db020e1b99752c8ef7d27c6c448982bd8d352e1b6df266b8d8358a8d5 +83734841c13dee12759d40bdd209b277e743b0d08cc0dd1e0b7afd2d65bfa640400eefcf6be4a52e463e5b3d885eeac6 +848d16505b04804afc773aebabb51b36fd8aacfbb0e09b36c0d5d57df3c0a3b92f33e7d5ad0a7006ec46ebb91df42b8c +909a8d793f599e33bb9f1dc4792a507a97169c87cd5c087310bc05f30afcd247470b4b56dec59894c0fb1d48d39bb54e +8e558a8559df84a1ba8b244ece667f858095c50bb33a5381e60fcc6ba586b69693566d8819b4246a27287f16846c1dfa +84d6b69729f5aaa000cd710c2352087592cfbdf20d5e1166977e195818e593fa1a50d1e04566be23163a2523dc1612f1 +9536d262b7a42125d89f4f32b407d737ba8d9242acfc99d965913ab3e043dcac9f7072a43708553562cac4cba841df30 +9598548923ca119d6a15fd10861596601dd1dedbcccca97bb208cdc1153cf82991ea8cc17686fbaa867921065265970c +b87f2d4af6d026e4d2836bc3d390a4a18e98a6e386282ce96744603bab74974272e97ac2da281afa21885e2cbb3a8001 +991ece62bf07d1a348dd22191868372904b9f8cf065ae7aa4e44fd24a53faf6d851842e35fb472895963aa1992894918 +a8c53dea4c665b30e51d22ca6bc1bc78aaf172b0a48e64a1d4b93439b053877ec26cb5221c55efd64fa841bbf7d5aff4 +93487ec939ed8e740f15335b58617c3f917f72d07b7a369befd479ae2554d04deb240d4a14394b26192efae4d2f4f35d +a44793ab4035443f8f2968a40e043b4555960193ffa3358d22112093aadfe2c136587e4139ffd46d91ed4107f61ea5e0 +b13fe033da5f0d227c75927d3dacb06dbaf3e1322f9d5c7c009de75cdcba5e308232838785ab69a70f0bedea755e003f +970a29b075faccd0700fe60d1f726bdebf82d2cc8252f4a84543ebd3b16f91be42a75c9719a39c4096139f0f31393d58 +a4c3eb1f7160f8216fc176fb244df53008ff32f2892363d85254002e66e2de21ccfe1f3b1047589abee50f29b9d507e3 +8c552885eab04ba40922a8f0c3c38c96089c95ff1405258d3f1efe8d179e39e1295cbf67677894c607ae986e4e6b1fb0 +b3671746fa7f848c4e2ae6946894defadd815230b906b419143523cc0597bc1d6c0a4c1e09d49b66b4a2c11cde3a4de3 +937a249a95813a5e2ef428e355efd202e15a37d73e56cfb7e57ea9f943f2ce5ca8026f2f1fd25bf164ba89d07077d858 +83646bdf6053a04aa9e2f112499769e5bd5d0d10f2e13db3ca89bd45c0b3b7a2d752b7d137fb3909f9c62b78166c9339 +b4eac4b91e763666696811b7ed45e97fd78310377ebea1674b58a2250973f80492ac35110ed1240cd9bb2d17493d708c +82db43a99bc6573e9d92a3fd6635dbbb249ac66ba53099c3c0c8c8080b121dd8243cd5c6e36ba0a4d2525bae57f5c89c +a64d6a264a681b49d134c655d5fc7756127f1ee7c93d328820f32bca68869f53115c0d27fef35fe71f7bc4fdaed97348 +8739b7a9e2b4bc1831e7f04517771bc7cde683a5e74e052542517f8375a2f64e53e0d5ac925ef722327e7bb195b4d1d9 +8f337cdd29918a2493515ebb5cf702bbe8ecb23b53c6d18920cc22f519e276ca9b991d3313e2d38ae17ae8bdfa4f8b7e +b0edeab9850e193a61f138ef2739fc42ceec98f25e7e8403bfd5fa34a7bc956b9d0898250d18a69fa4625a9b3d6129da +a9920f26fe0a6d51044e623665d998745c9eca5bce12051198b88a77d728c8238f97d4196f26e43b24f8841500b998d0 +86e655d61502b979eeeeb6f9a7e1d0074f936451d0a1b0d2fa4fb3225b439a3770767b649256fe481361f481a8dbc276 +84d3b32fa62096831cc3bf013488a9f3f481dfe293ae209ed19585a03f7db8d961a7a9dd0db82bd7f62d612707575d9c +81c827826ec9346995ffccf62a241e3b2d32f7357acd1b1f8f7a7dbc97022d3eb51b8a1230e23ce0b401d2e535e8cd78 +94a1e40c151191c5b055b21e86f32e69cbc751dcbdf759a48580951834b96a1eed75914c0d19a38aefd21fb6c8d43d0c +ab890222b44bc21b71f7c75e15b6c6e16bb03371acce4f8d4353ff3b8fcd42a14026589c5ed19555a3e15e4d18bfc3a3 +accb0be851e93c6c8cc64724cdb86887eea284194b10e7a43c90528ed97e9ec71ca69c6fac13899530593756dd49eab2 +b630220aa9e1829c233331413ee28c5efe94ea8ea08d0c6bfd781955078b43a4f92915257187d8526873e6c919c6a1de +add389a4d358c585f1274b73f6c3c45b58ef8df11f9d11221f620e241bf3579fba07427b288c0c682885a700cc1fa28d +a9fe6ca8bf2961a3386e8b8dcecc29c0567b5c0b3bcf3b0f9169f88e372b80151af883871fc5229815f94f43a6f5b2b0 +ad839ae003b92b37ea431fa35998b46a0afc3f9c0dd54c3b3bf7a262467b13ff3c323ada1c1ae02ac7716528bdf39e3e +9356d3fd0edcbbb65713c0f2a214394f831b26f792124b08c5f26e7f734b8711a87b7c4623408da6a091c9aef1f6af3c +896b25b083c35ac67f0af3784a6a82435b0e27433d4d74cd6d1eafe11e6827827799490fb1c77c11de25f0d75f14e047 +8bfa019391c9627e8e5f05c213db625f0f1e51ec68816455f876c7e55b8f17a4f13e5aae9e3fb9e1cf920b1402ee2b40 +8ba3a6faa6a860a8f3ce1e884aa8769ceded86380a86520ab177ab83043d380a4f535fe13884346c5e51bee68da6ab41 +a8292d0844084e4e3bb7af92b1989f841a46640288c5b220fecfad063ee94e86e13d3d08038ec2ac82f41c96a3bfe14d +8229bb030b2fc566e11fd33c7eab7a1bb7b49fed872ea1f815004f7398cb03b85ea14e310ec19e1f23e0bdaf60f8f76c +8cfbf869ade3ec551562ff7f63c2745cc3a1f4d4dc853a0cd42dd5f6fe54228f86195ea8fe217643b32e9f513f34a545 +ac52a3c8d3270ddfe1b5630159da9290a5ccf9ccbdef43b58fc0a191a6c03b8a5974cf6e2bbc7bd98d4a40a3581482d7 +ab13decb9e2669e33a7049b8eca3ca327c40dea15ad6e0e7fa63ed506db1d258bc36ac88b35f65cae0984e937eb6575d +b5e748eb1a7a1e274ff0cc56311c198f2c076fe4b7e73e5f80396fe85358549df906584e6bb2c8195b3e2be7736850a5 +b5cb911325d8f963c41f691a60c37831c7d3bbd92736efa33d1f77a22b3fde7f283127256c2f47e197571e6fe0b46149 +8a01dc6ed1b55f26427a014faa347130738b191a06b800e32042a46c13f60b49534520214359d68eb2e170c31e2b8672 +a72fa874866e19b2efb8e069328362bf7921ec375e3bcd6b1619384c3f7ee980f6cf686f3544e9374ff54b4d17a1629c +8db21092f7c5f110fba63650b119e82f4b42a997095d65f08f8237b02dd66fdf959f788df2c35124db1dbd330a235671 +8c65d50433d9954fe28a09fa7ba91a70a590fe7ba6b3060f5e4be0f6cef860b9897fa935fb4ebc42133524eb071dd169 +b4614058e8fa21138fc5e4592623e78b8982ed72aa35ee4391b164f00c68d277fa9f9eba2eeefc890b4e86eba5124591 +ab2ad3a1bce2fbd55ca6b7c23786171fe1440a97d99d6df4d80d07dd56ac2d7203c294b32fc9e10a6c259381a73f24a1 +812ae3315fdc18774a8da3713a4679e8ed10b9405edc548c00cacbe25a587d32040566676f135e4723c5dc25df5a22e9 +a464b75f95d01e5655b54730334f443c8ff27c3cb79ec7af4b2f9da3c2039c609908cd128572e1fd0552eb597e8cef8d +a0db3172e93ca5138fe419e1c49a1925140999f6eff7c593e5681951ee0ec1c7e454c851782cbd2b8c9bc90d466e90e0 +806db23ba7d00b87d544eed926b3443f5f9c60da6b41b1c489fba8f73593b6e3b46ebfcab671ee009396cd77d5e68aa1 +8bfdf2c0044cc80260994e1c0374588b6653947b178e8b312be5c2a05e05767e98ea15077278506aee7df4fee1aaf89e +827f6558c16841b5592ff089c9c31e31eb03097623524394813a2e4093ad2d3f8f845504e2af92195aaa8a1679d8d692 +925c4f8eab2531135cd71a4ec88e7035b5eea34ba9d799c5898856080256b4a15ed1a746e002552e2a86c9c157e22e83 +a9f9a368f0e0b24d00a35b325964c85b69533013f9c2cfad9708be5fb87ff455210f8cb8d2ce3ba58ca3f27495552899 +8ac0d3bebc1cae534024187e7c71f8927ba8fcc6a1926cb61c2b6c8f26bb7831019e635a376146c29872a506784a4aaa +97c577be2cbbfdb37ad754fae9df2ada5fc5889869efc7e18a13f8e502fbf3f4067a509efbd46fd990ab47ce9a70f5a8 +935e7d82bca19f16614aa43b4a3474e4d20d064e4bfdf1cea2909e5c9ab72cfe3e54dc50030e41ee84f3588cebc524e9 +941aafc08f7c0d94cebfbb1f0aad5202c02e6e37f2c12614f57e727efa275f3926348f567107ee6d8914dd71e6060271 +af0fbc1ba05b4b5b63399686df3619968be5d40073de0313cbf5f913d3d4b518d4c249cdd2176468ccaa36040a484f58 +a0c414f23f46ca6d69ce74c6f8a00c036cb0edd098af0c1a7d39c802b52cfb2d5dbdf93fb0295453d4646e2af7954d45 +909cf39e11b3875bb63b39687ae1b5d1f5a15445e39bf164a0b14691b4ddb39a8e4363f584ef42213616abc4785b5d66 +a92bac085d1194fbd1c88299f07a061d0bdd3f980b663e81e6254dbb288bf11478c0ee880e28e01560f12c5ccb3c0103 +841705cd5cd76b943e2b7c5e845b9dd3c8defe8ef67e93078d6d5e67ade33ad4b0fd413bc196f93b0a4073c855cd97d4 +8e7eb8364f384a9161e81d3f1d52ceca9b65536ae49cc35b48c3e2236322ba4ae9973e0840802d9fa4f4d82ea833544f +aed3ab927548bc8bec31467ba80689c71a168e34f50dcb6892f19a33a099f5aa6b3f9cb79f5c0699e837b9a8c7f27efe +b8fbf7696210a36e20edabd77839f4dfdf50d6d015cdf81d587f90284a9bcef7d2a1ff520728d7cc69a4843d6c20dedd +a9d533769ce6830211c884ae50a82a7bf259b44ac71f9fb11f0296fdb3981e6b4c1753fe744647b247ebc433a5a61436 +8b4bdf90d33360b7f428c71cde0a49fb733badba8c726876945f58c620ce7768ae0e98fc8c31fa59d8955a4823336bb1 +808d42238e440e6571c59e52a35ae32547d502dc24fd1759d8ea70a7231a95859baf30b490a4ba55fa2f3aaa11204597 +85594701f1d2fee6dc1956bc44c7b31db93bdeec2f3a7d622c1a08b26994760773e3d57521a44cfd7e407ac3fd430429 +a66de045ce7173043a6825e9dc440ac957e2efb6df0a337f4f8003eb0c719d873a52e6eba3cb0d69d977ca37d9187674 +87a1c6a1fdff993fa51efa5c3ba034c079c0928a7d599b906336af7c2dcab9721ceaf3108c646490af9dff9a754f54b3 +926424223e462ceb75aed7c22ade8a7911a903b7e5dd4bc49746ddce8657f4616325cd12667d4393ac52cdd866396d0e +b5dc96106593b42b30f06f0b0a1e0c1aafc70432e31807252d3674f0b1ea5e58eac8424879d655c9488d85a879a3e572 +997ca0987735cc716507cb0124b1d266d218b40c9d8e0ecbf26a1d65719c82a637ce7e8be4b4815d307df717bde7c72a +92994d3f57a569b7760324bb5ae4e8e14e1633d175dab06aa57b8e391540e05f662fdc08b8830f489a063f59b689a688 +a8087fcc6aa4642cb998bea11facfe87eb33b90a9aa428ab86a4124ad032fc7d2e57795311a54ec9f55cc120ebe42df1 +a9bd7d1de6c0706052ca0b362e2e70e8c8f70f1f026ea189b4f87a08ce810297ebfe781cc8004430776c54c1a05ae90c +856d33282e8a8e33a3d237fb0a0cbabaf77ba9edf2fa35a831fdafcadf620561846aa6cbb6bdc5e681118e1245834165 +9524a7aa8e97a31a6958439c5f3339b19370f03e86b89b1d02d87e4887309dbbe9a3a8d2befd3b7ed5143c8da7e0a8ad +824fdf433e090f8acbd258ac7429b21f36f9f3b337c6d0b71d1416a5c88a767883e255b2888b7c906dd2e9560c4af24c +88c7fee662ca7844f42ed5527996b35723abffd0d22d4ca203b9452c639a5066031207a5ae763dbc0865b3299d19b1ec +919dca5c5595082c221d5ab3a5bc230f45da7f6dec4eb389371e142c1b9c6a2c919074842479c2844b72c0d806170c0c +b939be8175715e55a684578d8be3ceff3087f60fa875fff48e52a6e6e9979c955efef8ff67cfa2b79499ea23778e33b0 +873b6db725e7397d11bc9bed9ac4468e36619135be686790a79bc6ed4249058f1387c9a802ea86499f692cf635851066 +aeae06db3ec47e9e5647323fa02fac44e06e59b885ad8506bf71b184ab3895510c82f78b6b22a5d978e8218e7f761e9f +b99c0a8359c72ab88448bae45d4bf98797a26bca48b0d4460cd6cf65a4e8c3dd823970ac3eb774ae5d0cea4e7fadf33e +8f10c8ec41cdfb986a1647463076a533e6b0eec08520c1562401b36bb063ac972aa6b28a0b6ce717254e35940b900e3c +a106d9be199636d7add43b942290269351578500d8245d4aae4c083954e4f27f64740a3138a66230391f2d0e6043a8de +a469997908244578e8909ff57cffc070f1dbd86f0098df3cfeb46b7a085cfecc93dc69ee7cad90ff1dc5a34d50fe580c +a4ef087bea9c20eb0afc0ee4caba7a9d29dfa872137828c721391273e402fb6714afc80c40e98bbd8276d3836bffa080 +b07a013f73cd5b98dae0d0f9c1c0f35bff8a9f019975c4e1499e9bee736ca6fcd504f9bc32df1655ff333062382cff04 +b0a77188673e87cc83348c4cc5db1eecf6b5184e236220c8eeed7585e4b928db849944a76ec60ef7708ef6dac02d5592 +b1284b37e59b529f0084c0dacf0af6c0b91fc0f387bf649a8c74819debf606f7b07fc3e572500016fb145ec2b24e9f17 +97b20b5b4d6b9129da185adfbf0d3d0b0faeba5b9715f10299e48ea0521709a8296a9264ce77c275a59c012b50b6519a +b9d37e946fae5e4d65c1fbfacc8a62e445a1c9d0f882e60cca649125af303b3b23af53c81d7bac544fb7fcfc7a314665 +8e5acaac379f4bb0127efbef26180f91ff60e4c525bc9b798fc50dfaf4fe8a5aa84f18f3d3cfb8baead7d1e0499af753 +b0c0b8ab1235bf1cda43d4152e71efc1a06c548edb964eb4afceb201c8af24240bf8ab5cae30a08604e77432b0a5faf0 +8cc28d75d5c8d062d649cbc218e31c4d327e067e6dbd737ec0a35c91db44fbbd0d40ec424f5ed79814add16947417572 +95ae6219e9fd47efaa9cb088753df06bc101405ba50a179d7c9f7c85679e182d3033f35b00dbba71fdcd186cd775c52e +b5d28fa09f186ebc5aa37453c9b4d9474a7997b8ae92748ecb940c14868792292ac7d10ade01e2f8069242b308cf97e5 +8c922a0faa14cc6b7221f302df3342f38fc8521ec6c653f2587890192732c6da289777a6cd310747ea7b7d104af95995 +b9ad5f660b65230de54de535d4c0fcae5bc6b59db21dea5500fdc12eea4470fb8ea003690fdd16d052523418d5e01e8c +a39a9dd41a0ff78c82979483731f1cd68d3921c3e9965869662c22e02dde3877802e180ba93f06e7346f96d9fa9261d2 +8b32875977ec372c583b24234c27ed73aef00cdff61eb3c3776e073afbdeade548de9497c32ec6d703ff8ad0a5cb7fe4 +9644cbe755a5642fe9d26cfecf170d3164f1848c2c2e271d5b6574a01755f3980b3fc870b98cf8528fef6ecef4210c16 +81ea9d1fdd9dd66d60f40ce0712764b99da9448ae0b300f8324e1c52f154e472a086dda840cb2e0b9813dc8ce8afd4b5 +906aaa4a7a7cdf01909c5cfbc7ded2abc4b869213cbf7c922d4171a4f2e637e56f17020b852ad339d83b8ac92f111666 +939b5f11acbdeff998f2a080393033c9b9d8d5c70912ea651c53815c572d36ee822a98d6dfffb2e339f29201264f2cf4 +aba4898bf1ccea9b9e2df1ff19001e05891581659c1cbbde7ee76c349c7fc7857261d9785823c9463a8aea3f40e86b38 +83ca1a56b8a0be4820bdb5a9346357c68f9772e43f0b887729a50d2eb2a326bbcede676c8bf2e51d7c89bbd8fdb778a6 +94e86e9fe6addfe2c3ee3a547267ed921f4230d877a85bb4442c2d9350c2fa9a9c54e6fe662de82d1a2407e4ab1691c2 +a0cc3bdef671a59d77c6984338b023fa2b431b32e9ed2abe80484d73edc6540979d6f10812ecc06d4d0c5d4eaca7183c +b5343413c1b5776b55ea3c7cdd1f3af1f6bd802ea95effe3f2b91a523817719d2ecc3f8d5f3cc2623ace7e35f99ca967 +92085d1ed0ed28d8cabe3e7ff1905ed52c7ceb1eac5503760c52fb5ee3a726aba7c90b483c032acc3f166b083d7ec370 +8ec679520455275cd957fca8122724d287db5df7d29f1702a322879b127bff215e5b71d9c191901465d19c86c8d8d404 +b65eb2c63d8a30332eb24ee8a0c70156fc89325ebbb38bacac7cf3f8636ad8a472d81ccca80423772abc00192d886d8a +a9fe1c060b974bee4d590f2873b28635b61bfcf614e61ff88b1be3eee4320f4874e21e8d666d8ac8c9aba672efc6ecae +b3fe2a9a389c006a831dea7e777062df84b5c2803f9574d7fbe10b7e1c125817986af8b6454d6be9d931a5ac94cfe963 +95418ad13b734b6f0d33822d9912c4c49b558f68d08c1b34a0127fcfa666bcae8e6fda8832d2c75bb9170794a20e4d7c +a9a7df761e7f18b79494bf429572140c8c6e9d456c4d4e336184f3f51525a65eb9582bea1e601bdb6ef8150b7ca736a5 +a0de03b1e75edf7998c8c1ac69b4a1544a6fa675a1941950297917366682e5644a4bda9cdeedfaf9473d7fccd9080b0c +a61838af8d95c95edf32663a68f007d95167bf6e41b0c784a30b22d8300cfdd5703bd6d16e86396638f6db6ae7e42a85 +8866d62084d905c145ff2d41025299d8b702ac1814a7dec4e277412c161bc9a62fed735536789cb43c88693c6b423882 +91da22c378c81497fe363e7f695c0268443abee50f8a6625b8a41e865638a643f07b157ee566de09ba09846934b4e2d7 +941d21dd57c9496aa68f0c0c05507405fdd413acb59bc668ce7e92e1936c68ec4b065c3c30123319884149e88228f0b2 +a77af9b094bc26966ddf2bf9e1520c898194a5ccb694915950dadc204facbe3066d3d89f50972642d76b14884cfbaa21 +8e76162932346869f4618bde744647f7ab52ab498ad654bdf2a4feeb986ac6e51370841e5acbb589e38b6e7142bb3049 +b60979ace17d6937ece72e4f015da4657a443dd01cebc7143ef11c09e42d4aa8855999a65a79e2ea0067f31c9fc2ab0f +b3e2ffdd5ee6fd110b982fd4fad4b93d0fca65478f986d086eeccb0804960bfaa1919afa743c2239973ea65091fe57d2 +8ce0ce05e7d7160d44574011da687454dbd3c8b8290aa671731b066e2c82f8cf2d63cb8e932d78c6122ec610e44660e6 +ab005dd8d297045c39e2f72fb1c48edb501ccf3575d3d04b9817b3afee3f0bb0f3f53f64bda37d1d9cde545aae999bae +95bd7edb4c4cd60e3cb8a72558845a3cce6bb7032ccdf33d5a49ebb6ddf203bc3c79e7b7e550735d2d75b04c8b2441e8 +889953ee256206284094e4735dbbb17975bafc7c3cb94c9fbfee4c3e653857bfd49e818f64a47567f721b98411a3b454 +b188423e707640ab0e75a061e0b62830cde8afab8e1ad3dae30db69ffae4e2fc005bababbdcbd7213b918ed4f70e0c14 +a97e0fafe011abd70d4f99a0b36638b3d6e7354284588f17a88970ed48f348f88392779e9a038c6cbc9208d998485072 +87db11014a91cb9b63e8dfaa82cdebca98272d89eb445ee1e3ff9dbaf2b3fad1a03b888cffc128e4fe208ed0dddece0f +aad2e40364edd905d66ea4ac9d51f9640d6fda9a54957d26ba233809851529b32c85660fa401dbee3679ec54fa6dd966 +863e99336ca6edf03a5a259e59a2d0f308206e8a2fb320cfc0be06057366df8e0f94b33a28f574092736b3c5ada84270 +b34bcc56a057589f34939a1adc51de4ff6a9f4fee9c7fa9aa131e28d0cf0759a0c871b640162acdfbf91f3f1b59a3703 +935dd28f2896092995c5eff1618e5b6efe7a40178888d7826da9b0503c2d6e68a28e7fac1a334e166d0205f0695ef614 +b842cd5f8f5de5ca6c68cb4a5c1d7b451984930eb4cc18fd0934d52fdc9c3d2d451b1c395594d73bc3451432bfba653f +9014537885ce2debad736bc1926b25fdab9f69b216bf024f589c49dc7e6478c71d595c3647c9f65ff980b14f4bb2283b +8e827ccca1dd4cd21707140d10703177d722be0bbe5cac578db26f1ef8ad2909103af3c601a53795435b27bf95d0c9ed +8a0b8ad4d466c09d4f1e9167410dbe2edc6e0e6229d4b3036d30f85eb6a333a18b1c968f6ca6d6889bb08fecde017ef4 +9241ee66c0191b06266332dc9161dede384c4bb4e116dbd0890f3c3790ec5566da4568243665c4725b718ac0f6b5c179 +aeb4d5fad81d2b505d47958a08262b6f1b1de9373c2c9ba6362594194dea3e002ab03b8cbb43f867be83065d3d370f19 +8781bc83bb73f7760628629fe19e4714b494dbed444c4e4e4729b7f6a8d12ee347841a199888794c2234f51fa26fc2b9 +b58864f0acd1c2afa29367e637cbde1968d18589245d9936c9a489c6c495f54f0113ecdcbe4680ac085dd3c397c4d0c3 +94a24284afaeead61e70f3e30f87248d76e9726759445ca18cdb9360586c60cc9f0ec1c397f9675083e0b56459784e2e +aed358853f2b54dcbddf865e1816c2e89be12e940e1abfa661e2ee63ffc24a8c8096be2072fa83556482c0d89e975124 +b95374e6b4fc0765708e370bc881e271abf2e35c08b056a03b847e089831ef4fe3124b9c5849d9c276eb2e35b3daf264 +b834cdbcfb24c8f84bfa4c552e7fadc0028a140952fd69ed13a516e1314a4cd35d4b954a77d51a1b93e1f5d657d0315d +8fb6d09d23bfa90e7443753d45a918d91d75d8e12ec7d016c0dfe94e5c592ba6aaf483d2f16108d190822d955ad9cdc3 +aa315cd3c60247a6ad4b04f26c5404c2713b95972843e4b87b5a36a89f201667d70f0adf20757ebe1de1b29ae27dda50 +a116862dca409db8beff5b1ccd6301cdd0c92ca29a3d6d20eb8b87f25965f42699ca66974dd1a355200157476b998f3b +b4c2f5fe173c4dc8311b60d04a65ce1be87f070ac42e13cd19c6559a2931c6ee104859cc2520edebbc66a13dc7d30693 +8d4a02bf99b2260c334e7d81775c5cf582b00b0c982ce7745e5a90624919028278f5e9b098573bad5515ce7fa92a80c8 +8543493bf564ce6d97bd23be9bff1aba08bd5821ca834f311a26c9139c92a48f0c2d9dfe645afa95fec07d675d1fd53b +9344239d13fde08f98cb48f1f87d34cf6abe8faecd0b682955382a975e6eed64e863fa19043290c0736261622e00045c +aa49d0518f343005ca72b9e6c7dcaa97225ce6bb8b908ebbe7b1a22884ff8bfb090890364e325a0d414ad180b8f161d1 +907d7fd3e009355ab326847c4a2431f688627faa698c13c03ffdd476ecf988678407f029b8543a475dcb3dafdf2e7a9c +845f1f10c6c5dad2adc7935f5cd2e2b32f169a99091d4f1b05babe7317b9b1cdce29b5e62f947dc621b9acbfe517a258 +8f3be8e3b380ea6cdf9e9c237f5e88fd5a357e5ded80ea1fc2019810814de82501273b4da38916881125b6fa0cfd4459 +b9c7f487c089bf1d20c822e579628db91ed9c82d6ca652983aa16d98b4270c4da19757f216a71b9c13ddee3e6e43705f +8ba2d8c88ad2b872db104ea8ddbb006ec2f3749fd0e19298a804bb3a5d94de19285cc7fb19fee58a66f7851d1a66c39f +9375ecd3ed16786fe161af5d5c908f56eeb467a144d3bbddfc767e90065b7c94fc53431adebecba2b6c9b5821184d36e +a49e069bfadb1e2e8bff6a4286872e2a9765d62f0eaa4fcb0e5af4bbbed8be3510fb19849125a40a8a81d1e33e81c3eb +9522cc66757b386aa6b88619525c8ce47a5c346d590bb3647d12f991e6c65c3ab3c0cfc28f0726b6756c892eae1672be +a9a0f1f51ff877406fa83a807aeb17b92a283879f447b8a2159653db577848cc451cbadd01f70441e351e9ed433c18bc +8ff7533dcff6be8714df573e33f82cf8e9f2bcaaa43e939c4759d52b754e502717950de4b4252fb904560fc31dce94a4 +959724671e265a28d67c29d95210e97b894b360da55e4cf16e6682e7912491ed8ca14bfaa4dce9c25a25b16af580494f +92566730c3002f4046c737032487d0833c971e775de59fe02d9835c9858e2e3bc37f157424a69764596c625c482a2219 +a84b47ceff13ed9c3e5e9cdf6739a66d3e7c2bd8a6ba318fefb1a9aecf653bb2981da6733ddb33c4b0a4523acc429d23 +b4ddf571317e44f859386d6140828a42cf94994e2f1dcbcc9777f4eebbfc64fc1e160b49379acc27c4672b8e41835c5d +8ab95c94072b853d1603fdd0a43b30db617d13c1d1255b99075198e1947bfa5f59aed2b1147548a1b5e986cd9173d15c +89511f2eab33894fd4b3753d24249f410ff7263052c1fef6166fc63a79816656b0d24c529e45ccce6be28de6e375d916 +a0866160ca63d4f2be1b4ea050dac6b59db554e2ebb4e5b592859d8df339b46fd7cb89aaed0951c3ee540aee982c238a +8fcc5cbba1b94970f5ff2eb1922322f5b0aa7d918d4b380c9e7abfd57afd8b247c346bff7b87af82efbce3052511cd1b +99aeb2a5e846b0a2874cca02c66ed40d5569eb65ab2495bc3f964a092e91e1517941f2688e79f8cca49cd3674c4e06dc +b7a096dc3bad5ca49bee94efd884aa3ff5615cf3825cf95fbe0ce132e35f46581d6482fa82666c7ef5f1643eaee8f1ca +94393b1da6eaac2ffd186b7725eca582f1ddc8cdd916004657f8a564a7c588175cb443fc6943b39029f5bbe0add3fad8 +884b85fe012ccbcd849cb68c3ad832d83b3ef1c40c3954ffdc97f103b1ed582c801e1a41d9950f6bddc1d11f19d5ec76 +b00061c00131eded8305a7ce76362163deb33596569afb46fe499a7c9d7a0734c084d336b38d168024c2bb42b58e7660 +a439153ac8e6ca037381e3240e7ba08d056c83d7090f16ed538df25901835e09e27de2073646e7d7f3c65056af6e4ce7 +830fc9ca099097d1f38b90e6843dc86f702be9d20bdacc3e52cae659dc41df5b8d2c970effa6f83a5229b0244a86fe22 +b81ea2ffaaff2bb00dd59a9ab825ba5eed4db0d8ac9c8ed1a632ce8f086328a1cddd045fbe1ace289083c1325881b7e7 +b51ea03c58daf2db32c99b9c4789b183365168cb5019c72c4cc91ac30b5fb7311d3db76e6fa41b7cd4a8c81e2f6cdc94 +a4170b2c6d09ca5beb08318730419b6f19215ce6c631c854116f904be3bc30dd85a80c946a8ab054d3e307afaa3f8fbc +897cc42ff28971ff54d2a55dd6b35cfb8610ac902f3c06e3a5cea0e0a257e870c471236a8e84709211c742a09c5601a6 +a18f2e98d389dace36641621488664ecbb422088ab03b74e67009b8b8acacaaa24fdcf42093935f355207d934adc52a8 +92adcfb678cc2ba19c866f3f2b988fdcb4610567f3ab436cc0cb9acaf5a88414848d71133ebdbec1983e38e6190f1b5f +a86d43c2ce01b366330d3b36b3ca85f000c3548b8297e48478da1ee7d70d8576d4650cba7852ed125c0d7cb6109aa7f3 +8ed31ceed9445437d7732dce78a762d72ff32a7636bfb3fd7974b7ae15db414d8184a1766915244355deb354fbc5803b +9268f70032584f416e92225d65af9ea18c466ebc7ae30952d56a4e36fd9ea811dde0a126da9220ba3c596ec54d8a335e +9433b99ee94f2d3fbdd63b163a2bdf440379334c52308bd24537f7defd807145a062ff255a50d119a7f29f4b85d250e3 +90ce664f5e4628a02278f5cf5060d1a34f123854634b1870906e5723ac9afd044d48289be283b267d45fcbf3f4656aaf +aaf21c4d59378bb835d42ae5c5e5ab7a3c8c36a59e75997989313197752b79a472d866a23683b329ea69b048b87fa13e +b83c0589b304cec9ede549fde54f8a7c2a468c6657da8c02169a6351605261202610b2055c639b9ed2d5b8c401fb8f56 +9370f326ea0f170c2c05fe2c5a49189f20aec93b6b18a5572a818cd4c2a6adb359e68975557b349fb54f065d572f4c92 +ac3232fa5ce6f03fca238bef1ce902432a90b8afce1c85457a6bee5571c033d4bceefafc863af04d4e85ac72a4d94d51 +80d9ea168ff821b22c30e93e4c7960ce3ad3c1e6deeebedd342a36d01bd942419b187e2f382dbfd8caa34cca08d06a48 +a387a3c61676fb3381eefa2a45d82625635a666e999aba30e3b037ec9e040f414f9e1ad9652abd3bcad63f95d85038db +a1b229fe32121e0b391b0f6e0180670b9dc89d79f7337de4c77ea7ad0073e9593846f06797c20e923092a08263204416 +92164a9d841a2b828cedf2511213268b698520f8d1285852186644e9a0c97512cafa4bfbe29af892c929ebccd102e998 +82ee2fa56308a67c7db4fd7ef539b5a9f26a1c2cc36da8c3206ba4b08258fbb3cec6fe5cdbd111433fb1ba2a1e275927 +8c77bfe9e191f190a49d46f05600603fa42345592539b82923388d72392404e0b29a493a15e75e8b068dddcd444c2928 +80b927f93ccf79dcf5c5b20bcf5a7d91d7a17bc0401bb7cc9b53a6797feac31026eb114257621f5a64a52876e4474cc1 +b6b68b6501c37804d4833d5a063dd108a46310b1400549074e3cac84acc6d88f73948b7ad48d686de89c1ec043ae8c1a +ab3da00f9bdc13e3f77624f58a3a18fc3728956f84b5b549d62f1033ae4b300538e53896e2d943f160618e05af265117 +b6830e87233b8eace65327fdc764159645b75d2fd4024bf8f313b2dd5f45617d7ecfb4a0b53ccafb5429815a9a1adde6 +b9251cfe32a6dc0440615aadcd98b6b1b46e3f4e44324e8f5142912b597ee3526bea2431e2b0282bb58f71be5b63f65e +af8d70711e81cdddfb39e67a1b76643292652584c1ce7ce4feb1641431ad596e75c9120e85f1a341e7a4da920a9cdd94 +98cd4e996594e89495c078bfd52a4586b932c50a449a7c8dfdd16043ca4cda94dafbaa8ad1b44249c99bbcc52152506e +b9fc6d1c24f48404a4a64fbe3e43342738797905db46e4132aee5f086aaa4c704918ad508aaefa455cfe1b36572e6242 +a365e871d30ba9291cedaba1be7b04e968905d003e9e1af7e3b55c5eb048818ae5b913514fb08b24fb4fbdccbb35d0b8 +93bf99510971ea9af9f1e364f1234c898380677c8e8de9b0dd24432760164e46c787bc9ec42a7ad450500706cf247b2d +b872f825a5b6e7b9c7a9ddfeded3516f0b1449acc9b4fd29fc6eba162051c17416a31e5be6d3563f424d28e65bab8b8f +b06b780e5a5e8eb4f4c9dc040f749cf9709c8a4c9ef15e925f442b696e41e5095db0778a6c73bcd329b265f2c6955c8b +848f1a981f5fc6cd9180cdddb8d032ad32cdfa614fc750d690dbae36cc0cd355cbf1574af9b3ffc8b878f1b2fafb9544 +a03f48cbff3e9e8a3a655578051a5ae37567433093ac500ed0021c6250a51b767afac9bdb194ee1e3eac38a08c0eaf45 +b5be78ce638ff8c4aa84352b536628231d3f7558c5be3bf010b28feac3022e64691fa672f358c8b663904aebe24a54ed +a9d4da70ff676fa55d1728ba6ab03b471fa38b08854d99e985d88c2d050102d8ccffbe1c90249a5607fa7520b15fe791 +8fe9f7092ffb0b69862c8e972fb1ecf54308c96d41354ed0569638bb0364f1749838d6d32051fff1599112978c6e229c +ae6083e95f37770ecae0df1e010456f165d96cfe9a7278c85c15cffd61034081ce5723e25e2bede719dc9341ec8ed481 +a260891891103089a7afbd9081ea116cfd596fd1015f5b65e10b0961eb37fab7d09c69b7ce4be8bf35e4131848fb3fe4 +8d729fa32f6eb9fd2f6a140bef34e8299a2f3111bffd0fe463aa8622c9d98bfd31a1df3f3e87cd5abc52a595f96b970e +a30ec6047ae4bc7da4daa7f4c28c93aedb1112cfe240e681d07e1a183782c9ff6783ac077c155af23c69643b712a533f +ac830726544bfe7b5467339e5114c1a75f2a2a8d89453ce86115e6a789387e23551cd64620ead6283dfa4538eb313d86 +8445c135b7a48068d8ed3e011c6d818cfe462b445095e2fbf940301e50ded23f272d799eea47683fc027430ce14613ef +95785411715c9ae9d8293ce16a693a2aa83e3cb1b4aa9f76333d0da2bf00c55f65e21e42e50e6c5772ce213dd7b4f7a0 +b273b024fa18b7568c0d1c4d2f0c4e79ec509dafac8c5951f14192d63ddbcf2d8a7512c1c1b615cc38fa3e336618e0c5 +a78b9d3ea4b6a90572eb27956f411f1d105fdb577ee2ffeec9f221da9b45db84bfe866af1f29597220c75e0c37a628d8 +a4be2bf058c36699c41513c4d667681ce161a437c09d81383244fc55e1c44e8b1363439d0cce90a3e44581fb31d49493 +b6eef13040f17dd4eba22aaf284d2f988a4a0c4605db44b8d2f4bf9567ac794550b543cc513c5f3e2820242dd704152e +87eb00489071fa95d008c5244b88e317a3454652dcb1c441213aa16b28cd3ecaa9b22fec0bdd483c1df71c37119100b1 +92d388acdcb49793afca329cd06e645544d2269234e8b0b27d2818c809c21726bc9cf725651b951e358a63c83dedee24 +ae27e219277a73030da27ab5603c72c8bd81b6224b7e488d7193806a41343dff2456132274991a4722fdb0ef265d04cd +97583e08ecb82bbc27c0c8476d710389fa9ffbead5c43001bd36c1b018f29faa98de778644883e51870b69c5ffb558b5 +90a799a8ce73387599babf6b7da12767c0591cadd36c20a7990e7c05ea1aa2b9645654ec65308ee008816623a2757a6a +a1b47841a0a2b06efd9ab8c111309cc5fc9e1d5896b3e42ed531f6057e5ade8977c29831ce08dbda40348386b1dcc06d +b92b8ef59bbddb50c9457691bc023d63dfcc54e0fd88bd5d27a09e0d98ac290fc90e6a8f6b88492043bf7c87fac8f3e4 +a9d6240b07d62e22ec8ab9b1f6007c975a77b7320f02504fc7c468b4ee9cfcfd945456ff0128bc0ef2174d9e09333f8d +8e96534c94693226dc32bca79a595ca6de503af635f802e86442c67e77564829756961d9b701187fe91318da515bf0e6 +b6ba290623cd8dd5c2f50931c0045d1cfb0c30877bc8fe58cbc3ff61ee8da100045a39153916efa1936f4aee0892b473 +b43baa7717fac02d4294f5b3bb5e58a65b3557747e3188b482410388daac7a9c177f762d943fd5dcf871273921213da8 +b9cf00f8fb5e2ef2b836659fece15e735060b2ea39b8e901d3dcbdcf612be8bf82d013833718c04cd46ffaa70b85f42e +8017d0c57419e414cbba504368723e751ef990cc6f05dad7b3c2de6360adc774ad95512875ab8337d110bf39a42026fa +ae7401048b838c0dcd4b26bb6c56d79d51964a0daba780970b6c97daee4ea45854ea0ac0e4139b3fe60dac189f84df65 +887b237b0cd0f816b749b21db0b40072f9145f7896c36916296973f9e6990ede110f14e5976c906d08987c9836cca57f +a88c3d5770148aee59930561ca1223aceb2c832fb5417e188dca935905301fc4c6c2c9270bc1dff7add490a125eb81c6 +b6cf9b02c0cd91895ad209e38c54039523f137b5848b9d3ad33ae43af6c20c98434952db375fe378de7866f2d0e8b18a +84ef3d322ff580c8ad584b1fe4fe346c60866eb6a56e982ba2cf3b021ecb1fdb75ecc6c29747adda86d9264430b3f816 +a0561c27224baf0927ad144cb71e31e54a064c598373fcf0d66aebf98ab7af1d8e2f343f77baefff69a6da750a219e11 +aa5cc43f5b8162b016f5e1b61214c0c9d15b1078911c650b75e6cdfb49b85ee04c6739f5b1687d15908444f691f732de +ad4ac099b935589c7b8fdfdf3db332b7b82bb948e13a5beb121ebd7db81a87d278024a1434bcf0115c54ca5109585c3d +8a00466abf3f109a1dcd19e643b603d3af23d42794ef8ca2514dd507ecea44a031ac6dbc18bd02f99701168b25c1791e +b00b5900dfad79645f8bee4e5adc7b84eb22e5b1e67df77ccb505b7fc044a6c08a8ea5faca662414eb945f874f884cea +950e204e5f17112250b22ea6bb8423baf522fc0af494366f18fe0f949f51d6e6812074a80875cf1ed9c8e7420058d541 +91e5cbf8bb1a1d50c81608c9727b414d0dd2fb467ebc92f100882a3772e54f94979cfdf8e373fdef7c7fcdd60fec9e00 +a093f6a857b8caaff80599c2e89c962b415ecbaa70d8fd973155fa976a284c6b29a855f5f7a3521134d00d2972755188 +b4d55a3551b00da54cc010f80d99ddd2544bde9219a3173dfaadf3848edc7e4056ab532fb75ac26f5f7141e724267663 +a03ea050fc9b011d1b04041b5765d6f6453a93a1819cd9bd6328637d0b428f08526466912895dcc2e3008ee58822e9a7 +99b12b3665e473d01bc6985844f8994fb65cb15745024fb7af518398c4a37ff215da8f054e8fdf3286984ae36a73ca5e +9972c7e7a7fb12e15f78d55abcaf322c11249cd44a08f62c95288f34f66b51f146302bce750ff4d591707075d9123bd2 +a64b4a6d72354e596d87cda213c4fc2814009461570ccb27d455bbe131f8d948421a71925425b546d8cf63d5458cd64b +91c215c73b195795ede2228b7ed1f6e37892e0c6b0f4a0b5a16c57aa1100c84df9239054a173b6110d6c2b7f4bf1ce52 +88807198910ec1303480f76a3683870246a995e36adaeadc29c22f0bdba8152fe705bd070b75de657b04934f7d0ccf80 +b37c0026c7b32eb02cacac5b55cb5fe784b8e48b2945c64d3037af83ece556a117f0ff053a5968c2f5fa230e291c1238 +94c768384ce212bc2387e91ce8b45e4ff120987e42472888a317abc9dcdf3563b62e7a61c8e98d7cdcbe272167d91fc6 +a10c2564936e967a390cb14ef6e8f8b04ea9ece5214a38837eda09e79e0c7970b1f83adf017c10efd6faa8b7ffa2c567 +a5085eed3a95f9d4b1269182ea1e0d719b7809bf5009096557a0674bde4201b0ddc1f0f16a908fc468846b3721748ce3 +87468eb620b79a0a455a259a6b4dfbc297d0d53336537b771254dd956b145dc816b195b7002647ea218552e345818a3f +ace2b77ffb87366af0a9cb5d27d6fc4a14323dbbf1643f5f3c4559306330d86461bb008894054394cbfaefeaa0bc2745 +b27f56e840a54fbd793f0b7a7631aa4cee64b5947e4382b2dfb5eb1790270288884c2a19afebe5dc0c6ef335d4531c1c +876e438633931f7f895062ee16c4b9d10428875f7bc79a8e156a64d379a77a2c45bf5430c5ab94330f03da352f1e9006 +a2512a252587d200d2092b44c914df54e04ff8bcef36bf631f84bde0cf5a732e3dc7f00f662842cfd74b0b0f7f24180e +827f1bc8f54a35b7a4bd8154f79bcc055e45faed2e74adf7cf21cca95df44d96899e847bd70ead6bb27b9c0ed97bbd8b +a0c92cf5a9ed843714f3aea9fe7b880f622d0b4a3bf66de291d1b745279accf6ba35097849691370f41732ba64b5966b +a63f5c1e222775658421c487b1256b52626c6f79cb55a9b7deb2352622cedffb08502042d622eb3b02c97f9c09f9c957 +8cc093d52651e65fb390e186db6cc4de559176af4624d1c44cb9b0e836832419dacac7b8db0627b96288977b738d785d +aa7b6a17dfcec146134562d32a12f7bd7fe9522e300859202a02939e69dbd345ed7ff164a184296268f9984f9312e8fc +8ac76721f0d2b679f023d06cbd28c85ae5f4b43c614867ccee88651d4101d4fd352dbdb65bf36bfc3ebc0109e4b0c6f9 +8d350f7c05fc0dcd9a1170748846fb1f5d39453e4cb31e6d1457bed287d96fc393b2ecc53793ca729906a33e59c6834a +b9913510dfc5056d7ec5309f0b631d1ec53e3a776412ada9aefdaf033c90da9a49fdde6719e7c76340e86599b1f0eec2 +94955626bf4ce87612c5cfffcf73bf1c46a4c11a736602b9ba066328dc52ad6d51e6d4f53453d4ed55a51e0aad810271 +b0fcab384fd4016b2f1e53f1aafd160ae3b1a8865cd6c155d7073ecc1664e05b1d8bca1def39c158c7086c4e1103345e +827de3f03edfbde08570b72de6662c8bfa499b066a0a27ebad9b481c273097d17a5a0a67f01553da5392ec3f149b2a78 +ab7940384c25e9027c55c40df20bd2a0d479a165ced9b1046958353cd69015eeb1e44ed2fd64e407805ba42df10fc7bf +8ad456f6ff8cd58bd57567d931f923d0c99141978511b17e03cab7390a72b9f62498b2893e1b05c7c22dd274e9a31919 +ac75399e999effe564672db426faa17a839e57c5ef735985c70cd559a377adec23928382767b55ed5a52f7b11b54b756 +b17f975a00b817299ac7af5f2024ea820351805df58b43724393bfb3920a8cd747a3bbd4b8286e795521489db3657168 +a2bed800a6d95501674d9ee866e7314063407231491d794f8cf57d5be020452729c1c7cefd8c50dc1540181f5caab248 +9743f5473171271ffdd3cc59a3ae50545901a7b45cd4bc3570db487865f3b73c0595bebabbfe79268809ee1862e86e4a +b7eab77c2d4687b60d9d7b04e842b3880c7940140012583898d39fcc22d9b9b0a9be2c2e3788b3e6f30319b39c338f09 +8e2b8f797a436a1b661140e9569dcf3e1eea0a77c7ff2bc4ff0f3e49af04ed2de95e255df8765f1d0927fb456a9926b1 +8aefea201d4a1f4ff98ffce94e540bb313f2d4dfe7e9db484a41f13fc316ed02b282e1acc9bc6f56cad2dc2e393a44c9 +b950c17c0e5ca6607d182144aa7556bb0efe24c68f06d79d6413a973b493bfdf04fd147a4f1ab03033a32004cc3ea66f +b7b8dcbb179a07165f2dc6aa829fad09f582a71b05c3e3ea0396bf9e6fe73076f47035c031c2101e8e38e0d597eadd30 +a9d77ed89c77ec1bf8335d08d41c3c94dcca9fd1c54f22837b4e54506b212aa38d7440126c80648ab7723ff18e65ed72 +a819d6dfd4aef70e52b8402fe5d135f8082d40eb7d3bb5c4d7997395b621e2bb10682a1bad2c9caa33dd818550fc3ec6 +8f6ee34128fac8bbf13ce2d68b2bb363eb4fd65b297075f88e1446ddeac242500eeb4ef0735e105882ff5ba8c44c139b +b4440e48255c1644bcecf3a1e9958f1ec4901cb5b1122ee5b56ffd02cad1c29c4266999dbb85aa2605c1b125490074d4 +a43304a067bede5f347775d5811cf65a6380a8d552a652a0063580b5c5ef12a0867a39c7912fa219e184f4538eba1251 +a891ad67a790089ffc9f6d53e6a3d63d3556f5f693e0cd8a7d0131db06fd4520e719cfcc3934f0a8f62a95f90840f1d4 +aea6df8e9bb871081aa0fc5a9bafb00be7d54012c5baf653791907d5042a326aeee966fd9012a582cc16695f5baf7042 +8ffa2660dc52ed1cd4eff67d6a84a8404f358a5f713d04328922269bee1e75e9d49afeec0c8ad751620f22352a438e25 +87ec6108e2d63b06abed350f8b363b7489d642486f879a6c3aa90e5b0f335efc2ff2834eef9353951a42136f8e6a1b32 +865619436076c2760d9e87ddc905023c6de0a8d56eef12c98a98c87837f2ca3f27fd26a2ad752252dbcbe2b9f1d5a032 +980437dce55964293cb315c650c5586ffd97e7a944a83f6618af31c9d92c37b53ca7a21bb5bc557c151b9a9e217e7098 +95d128fc369df4ad8316b72aea0ca363cbc7b0620d6d7bb18f7076a8717a6a46956ff140948b0cc4f6d2ce33b5c10054 +8c7212d4a67b9ec70ebbca04358ad2d36494618d2859609163526d7b3acc2fc935ca98519380f55e6550f70a9bc76862 +893a2968819401bf355e85eee0f0ed0406a6d4a7d7f172d0017420f71e00bb0ba984f6020999a3cdf874d3cd8ebcd371 +9103c1af82dece25d87274e89ea0acd7e68c2921c4af3d8d7c82ab0ed9990a5811231b5b06113e7fa43a6bd492b4564f +99cfd87a94eab7d35466caa4ed7d7bb45e5c932b2ec094258fb14bf205659f83c209b83b2f2c9ccb175974b2a33e7746 +874b6b93e4ee61be3f00c32dd84c897ccd6855c4b6251eb0953b4023634490ed17753cd3223472873cbc6095b2945075 +84a32c0dc4ea60d33aac3e03e70d6d639cc9c4cc435c539eff915017be3b7bdaba33349562a87746291ebe9bc5671f24 +a7057b24208928ad67914e653f5ac1792c417f413d9176ba635502c3f9c688f7e2ee81800d7e3dc0a340c464da2fd9c5 +a03fb9ed8286aacfa69fbd5d953bec591c2ae4153400983d5dbb6cd9ea37fff46ca9e5cceb9d117f73e9992a6c055ad2 +863b2de04e89936c9a4a2b40380f42f20aefbae18d03750fd816c658aee9c4a03df7b12121f795c85d01f415baaeaa59 +8526eb9bd31790fe8292360d7a4c3eed23be23dd6b8b8f01d2309dbfdc0cfd33ad1568ddd7f8a610f3f85a9dfafc6a92 +b46ab8c5091a493d6d4d60490c40aa27950574a338ea5bbc045be3a114af87bdcb160a8c80435a9b7ad815f3cb56a3f3 +aeadc47b41a8d8b4176629557646202f868b1d728b2dda58a347d937e7ffc8303f20d26d6c00b34c851b8aeec547885d +aebb19fc424d72c1f1822aa7adc744cd0ef7e55727186f8df8771c784925058c248406ebeeaf3c1a9ee005a26e9a10c6 +8ff96e81c1a4a2ab1b4476c21018fae0a67e92129ee36120cae8699f2d7e57e891f5c624902cb1b845b944926a605cc3 +8251b8d2c43fadcaa049a9e7aff838dae4fb32884018d58d46403ac5f3beb5c518bfd45f03b8abb710369186075eb71c +a8b2a64f865f51a5e5e86a66455c093407933d9d255d6b61e1fd81ffafc9538d73caaf342338a66ba8ee166372a3d105 +aad915f31c6ba7fdc04e2aaac62e84ef434b7ee76a325f07dc430d12c84081999720181067b87d792efd0117d7ee1eab +a13db3bb60389883fd41d565c54fb5180d9c47ce2fe7a169ae96e01d17495f7f4fa928d7e556e7c74319c4c25d653eb2 +a4491b0198459b3f552855d680a59214eb74e6a4d6c5fa3b309887dc50ebea2ecf6d26c040550f7dc478b452481466fb +8f017f13d4b1e3f0c087843582b52d5f8d13240912254d826dd11f8703a99a2f3166dfbdfdffd9a3492979d77524276b +96c3d5dcd032660d50d7cd9db2914f117240a63439966162b10c8f1f3cf74bc83b0f15451a43b31dbd85e4a7ce0e4bb1 +b479ec4bb79573d32e0ec93b92bdd7ec8c26ddb5a2d3865e7d4209d119fd3499eaac527615ffac78c440e60ef3867ae0 +b2c49c4a33aa94b52b6410b599e81ff15490aafa7e43c8031c865a84e4676354a9c81eb4e7b8be6825fdcefd1e317d44 +906dc51d6a90c089b6704b47592805578a6eed106608eeb276832f127e1b8e858b72e448edcbefb497d152447e0e68ff +b0e81c63b764d7dfbe3f3fddc9905aef50f3633e5d6a4af6b340495124abedcff5700dfd1577bbbed7b6bf97d02719cb +9304c64701e3b4ed6d146e48a881f7d83a17f58357cca0c073b2bb593afd2d94f6e2a7a1ec511d0a67ad6ff4c3be5937 +b6fdbd12ba05aa598d80b83f70a15ef90e5cba7e6e75fa038540ee741b644cd1f408a6cecfd2a891ef8d902de586c6b5 +b80557871a6521b1b3c74a1ba083ae055b575df607f1f7b04c867ba8c8c181ea68f8d90be6031f4d25002cca27c44da2 +aa7285b8e9712e06b091f64163f1266926a36607f9d624af9996856ed2aaf03a580cb22ce407d1ade436c28b44ca173f +8148d72b975238b51e6ea389e5486940d22641b48637d7dfadfa603a605bfc6d74a016480023945d0b85935e396aea5d +8a014933a6aea2684b5762af43dcf4bdbb633cd0428d42d71167a2b6fc563ece5e618bff22f1db2ddb69b845b9a2db19 +990d91740041db770d0e0eb9d9d97d826f09fd354b91c41e0716c29f8420e0e8aac0d575231efba12fe831091ec38d5a +9454d0d32e7e308ddec57cf2522fb1b67a2706e33fb3895e9e1f18284129ab4f4c0b7e51af25681d248d7832c05eb698 +a5bd434e75bac105cb3e329665a35bce6a12f71dd90c15165777d64d4c13a82bceedb9b48e762bd24034e0fc9fbe45f4 +b09e3b95e41800d4dc29c6ffdaab2cd611a0050347f6414f154a47ee20ee59bf8cf7181454169d479ebce1eb5c777c46 +b193e341d6a047d15eea33766d656d807b89393665a783a316e9ba10518e5515c8e0ade3d6e15641d917a8a172a5a635 +ade435ec0671b3621dde69e07ead596014f6e1daa1152707a8c18877a8b067bde2895dd47444ffa69db2bbef1f1d8816 +a7fd3d6d87522dfc56fb47aef9ce781a1597c56a8bbfd796baba907afdc872f753d732bfda1d3402aee6c4e0c189f52d +a298cb4f4218d0464b2fab393e512bbc477c3225aa449743299b2c3572f065bc3a42d07e29546167ed9e1b6b3b3a3af3 +a9ee57540e1fd9c27f4f0430d194b91401d0c642456c18527127d1f95e2dba41c2c86d1990432eb38a692fda058fafde +81d6c1a5f93c04e6d8e5a7e0678c1fc89a1c47a5c920bcd36180125c49fcf7c114866b90e90a165823560b19898a7c16 +a4b7a1ec9e93c899b9fd9aaf264c50e42c36c0788d68296a471f7a3447af4dbc81e4fa96070139941564083ec5b5b5a1 +b3364e327d381f46940c0e11e29f9d994efc6978bf37a32586636c0070b03e4e23d00650c1440f448809e1018ef9f6d8 +8056e0913a60155348300e3a62e28b5e30629a90f7dd4fe11289097076708110a1d70f7855601782a3cdc5bdb1ca9626 +b4980fd3ea17bac0ba9ee1c470b17e575bb52e83ebdd7d40c93f4f87bebeaff1c8a679f9d3d09d635f068d37d5bd28bd +905a9299e7e1853648e398901dfcd437aa575c826551f83520df62984f5679cb5f0ea86aa45ed3e18b67ddc0dfafe809 +ab99553bf31a84f2e0264eb34a08e13d8d15e2484aa9352354becf9a15999c76cc568d68274b70a65e49703fc23540d0 +a43681597bc574d2dae8964c9a8dc1a07613d7a1272bdcb818d98c85d44e16d744250c33f3b5e4d552d97396b55e601f +a54e5a31716fccb50245898c99865644405b8dc920ded7a11f3d19bdc255996054b268e16f2e40273f11480e7145f41e +8134f3ad5ef2ad4ba12a8a4e4d8508d91394d2bcdc38b7c8c8c0b0a820357ac9f79d286c65220f471eb1adca1d98fc68 +94e2f755e60471578ab2c1adb9e9cea28d4eec9b0e92e0140770bca7002c365fcabfe1e5fb4fe6cfe79a0413712aa3ef +ad48f8d0ce7eb3cc6e2a3086ad96f562e5bed98a360721492ae2e74dc158586e77ec8c35d5fd5927376301b7741bad2b +8614f0630bdd7fbad3a31f55afd9789f1c605dc85e7dc67e2edfd77f5105f878bb79beded6e9f0b109e38ea7da67e8d5 +9804c284c4c5e77dabb73f655b12181534ca877c3e1e134aa3f47c23b7ec92277db34d2b0a5d38d2b69e5d1c3008a3e3 +a51b99c3088e473afdaa9e0a9f7e75a373530d3b04e44e1148da0726b95e9f5f0c7e571b2da000310817c36f84b19f7f +ac4ff909933b3b76c726b0a382157cdc74ab851a1ac6cef76953c6444441804cc43abb883363f416592e8f6cfbc4550b +ae7d915eb9fc928b65a29d6edbc75682d08584d0014f7bcf17d59118421ae07d26a02137d1e4de6938bcd1ab8ef48fad +852f7e453b1af89b754df6d11a40d5d41ea057376e8ecacd705aacd2f917457f4a093d6b9a8801837fa0f62986ad7149 +92c6bf5ada5d0c3d4dd8058483de36c215fa98edab9d75242f3eff9db07c734ad67337da6f0eefe23a487bf75a600dee +a2b42c09d0db615853763552a48d2e704542bbd786aae016eb58acbf6c0226c844f5fb31e428cb6450b9db855f8f2a6f +880cc07968266dbfdcfbc21815cd69e0eddfee239167ac693fb0413912d816f2578a74f7716eecd6deefa68c6eccd394 +b885b3ace736cd373e8098bf75ba66fa1c6943ca1bc4408cd98ac7074775c4478594f91154b8a743d9c697e1b29f5840 +a51ce78de512bd87bfa0835de819941dffbf18bec23221b61d8096fc9436af64e0693c335b54e7bfc763f287bdca2db6 +a3c76166a3bdb9b06ef696e57603b58871bc72883ee9d45171a30fe6e1d50e30bc9c51b4a0f5a7270e19a77b89733850 +acefc5c6f8a1e7c24d7b41e0fc7f6f3dc0ede6cf3115ffb9a6e54b1d954cbca9bda8ad7a084be9be245a1b8e9770d141 +b420ed079941842510e31cfad117fa11fb6b4f97dfbc6298cb840f27ebaceba23eeaf3f513bcffbf5e4aae946310182d +95c3bb5ef26c5ed2f035aa5d389c6b3c15a6705b9818a3fefaed28922158b35642b2e8e5a1a620fdad07e75ad4b43af4 +825149f9081ecf07a2a4e3e8b5d21bade86c1a882475d51c55ee909330b70c5a2ac63771c8600c6f38df716af61a3ea1 +873b935aae16d9f08adbc25353cee18af2f1b8d5f26dec6538d6bbddc515f2217ed7d235dcfea59ae61b428798b28637 +9294150843a2bedcedb3bb74c43eb28e759cf9499582c5430bccefb574a8ddd4f11f9929257ff4c153990f9970a2558f +b619563a811cc531da07f4f04e5c4c6423010ff9f8ed7e6ec9449162e3d501b269fb1c564c09c0429431879b0f45df02 +91b509b87eb09f007d839627514658c7341bc76d468920fe8a740a8cb96a7e7e631e0ea584a7e3dc1172266f641d0f5c +8b8aceace9a7b9b4317f1f01308c3904d7663856946afbcea141a1c615e21ccad06b71217413e832166e9dd915fbe098 +87b3b36e725833ea0b0f54753c3728c0dbc87c52d44d705ffc709f2d2394414c652d3283bab28dcce09799504996cee0 +b2670aad5691cbf308e4a6a77a075c4422e6cbe86fdba24e9f84a313e90b0696afb6a067eebb42ba2d10340d6a2f6e51 +876784a9aff3d54faa89b2bacd3ff5862f70195d0b2edc58e8d1068b3c9074c0da1cfa23671fe12f35e33b8a329c0ccd +8b48b9e758e8a8eae182f5cbec96f67d20cca6d3eee80a2d09208eb1d5d872e09ef23d0df8ebbb9b01c7449d0e3e3650 +b79303453100654c04a487bdcadc9e3578bc80930c489a7069a52e8ca1dba36c492c8c899ce025f8364599899baa287d +961b35a6111da54ece6494f24dacd5ea46181f55775b5f03df0e370c34a5046ac2b4082925855325bb42bc2a2c98381d +a31feb1be3f5a0247a1f7d487987eb622e34fca817832904c6ee3ee60277e5847945a6f6ea1ac24542c72e47bdf647df +a12a2aa3e7327e457e1aae30e9612715dd2cfed32892c1cd6dcda4e9a18203af8a44afb46d03b2eed89f6b9c5a2c0c23 +a08265a838e69a2ca2f80fead6ccf16f6366415b920c0b22ee359bcd8d4464ecf156f400a16a7918d52e6d733dd64211 +b723d6344e938d801cca1a00032af200e541d4471fd6cbd38fb9130daa83f6a1dffbbe7e67fc20f9577f884acd7594b2 +a6733d83ec78ba98e72ddd1e7ff79b7adb0e559e256760d0c590a986e742445e8cdf560d44b29439c26d87edd0b07c8c +a61c2c27d3f7b9ff4695a17afedf63818d4bfba390507e1f4d0d806ce8778d9418784430ce3d4199fd3bdbc2504d2af3 +8332f3b63a6dc985376e8b1b25eeae68be6160fbe40053ba7bcf6f073204f682da72321786e422d3482fd60c9e5aa034 +a280f44877583fbb6b860d500b1a3f572e3ee833ec8f06476b3d8002058e25964062feaa1e5bec1536d734a5cfa09145 +a4026a52d277fcea512440d2204f53047718ebfcae7b48ac57ea7f6bfbc5de9d7304db9a9a6cbb273612281049ddaec5 +95cdf69c831ab2fad6c2535ede9c07e663d2ddccc936b64e0843d2df2a7b1c31f1759c3c20f1e7a57b1c8f0dbb21b540 +95c96cec88806469c277ab567863c5209027cecc06c7012358e5f555689c0d9a5ffb219a464f086b45817e8536b86d2f +afe38d4684132a0f03d806a4c8df556bf589b25271fbc6fe2e1ed16de7962b341c5003755da758d0959d2e6499b06c68 +a9b77784fda64987f97c3a23c5e8f61b918be0f7c59ba285084116d60465c4a2aaafc8857eb16823282cc83143eb9126 +a830f05881ad3ce532a55685877f529d32a5dbe56cea57ffad52c4128ee0fad0eeaf0da4362b55075e77eda7babe70e5 +992b3ad190d6578033c13ed5abfee4ef49cbc492babb90061e3c51ee4b5790cdd4c8fc1abff1fa2c00183b6b64f0bbbe +b1015424d9364aeff75de191652dc66484fdbec3e98199a9eb9671ec57bec6a13ff4b38446e28e4d8aedb58dd619cd90 +a745304604075d60c9db36cada4063ac7558e7ec2835d7da8485e58d8422e817457b8da069f56511b02601289fbb8981 +a5ba4330bc5cb3dbe0486ddf995632a7260a46180a08f42ae51a2e47778142132463cc9f10021a9ad36986108fefa1a9 +b419e9fd4babcaf8180d5479db188bb3da232ae77a1c4ed65687c306e6262f8083070a9ac32220cddb3af2ec73114092 +a49e23dc5f3468f3bf3a0bb7e4a114a788b951ff6f23a3396ae9e12cbff0abd1240878a3d1892105413dbc38818e807c +b7ecc7b4831f650202987e85b86bc0053f40d983f252e9832ef503aea81c51221ce93279da4aa7466c026b2d2070e55d +96a8c35cb87f84fa84dcd6399cc2a0fd79cc9158ef4bdde4bae31a129616c8a9f2576cd19baa3f497ca34060979aed7d +8681b2c00aa62c2b519f664a95dcb8faef601a3b961bb4ce5d85a75030f40965e2983871d41ea394aee934e859581548 +85c229a07efa54a713d0790963a392400f55fbb1a43995a535dc6c929f20d6a65cf4efb434e0ad1cb61f689b8011a3bc +90856f7f3444e5ad44651c28e24cc085a5db4d2ffe79aa53228c26718cf53a6e44615f3c5cda5aa752d5f762c4623c66 +978999b7d8aa3f28a04076f74d11c41ef9c89fdfe514936c4238e0f13c38ec97e51a5c078ebc6409e517bfe7ccb42630 +a099914dd7ed934d8e0d363a648e9038eb7c1ec03fa04dbcaa40f7721c618c3ef947afef7a16b4d7ac8c12aa46637f03 +ab2a104fed3c83d16f2cda06878fa5f30c8c9411de71bfb67fd2fc9aa454dcbcf3d299d72f8cc12e919466a50fcf7426 +a4471d111db4418f56915689482f6144efc4664cfb0311727f36c864648d35734351becc48875df96f4abd3cfcf820f9 +83be11727cd30ea94ccc8fa31b09b81c9d6a9a5d3a4686af9da99587332fe78c1f94282f9755854bafd6033549afec91 +88020ff971dc1a01a9e993cd50a5d2131ffdcbb990c1a6aaa54b20d8f23f9546a70918ea57a21530dcc440c1509c24ad +ae24547623465e87905eaffa1fa5d52bb7c453a8dbd89614fa8819a2abcedaf455c2345099b7324ae36eb0ad7c8ef977 +b59b0c60997de1ee00b7c388bc7101d136c9803bf5437b1d589ba57c213f4f835a3e4125b54738e78abbc21b000f2016 +a584c434dfe194546526691b68fa968c831c31da42303a1d735d960901c74011d522246f37f299555416b8cf25c5a548 +80408ce3724f4837d4d52376d255e10f69eb8558399ae5ca6c11b78b98fe67d4b93157d2b9b639f1b5b64198bfe87713 +abb941e8d406c2606e0ddc35c113604fdd9d249eacc51cb64e2991e551b8639ce44d288cc92afa7a1e7fc599cfc84b22 +b223173f560cacb1c21dba0f1713839e348ad02cbfdef0626748604c86f89e0f4c919ed40b583343795bdd519ba952c8 +af1c70512ec3a19d98b8a1fc3ff7f7f5048a27d17d438d43f561974bbdd116fcd5d5c21040f3447af3f0266848d47a15 +8a44809568ebe50405bede19b4d2607199159b26a1b33e03d180e6840c5cf59d991a4fb150d111443235d75ecad085b7 +b06207cdca46b125a27b3221b5b50cf27af4c527dd7c80e2dbcebbb09778a96df3af67e50f07725239ce3583dad60660 +993352d9278814ec89b26a11c4a7c4941bf8f0e6781ae79559d14749ee5def672259792db4587f85f0100c7bb812f933 +9180b8a718b971fd27bc82c8582d19c4b4f012453e8c0ffeeeffe745581fc6c07875ab28be3af3fa3896d19f0c89ac5b +8b8e1263eb48d0fe304032dd5ea1f30e73f0121265f7458ba9054d3626894e8a5fef665340abd2ede9653045c2665938 +99a2beee4a10b7941c24b2092192faf52b819afd033e4a2de050fd6c7f56d364d0cf5f99764c3357cf32399e60fc5d74 +946a4aad7f8647ea60bee2c5fcdeb6f9a58fb2cfca70c4d10e458027a04846e13798c66506151be3df9454b1e417893f +a672a88847652d260b5472d6908d1d57e200f1e492d30dd1cecc441cdfc9b76e016d9bab560efd4d7f3c30801de884a9 +9414e1959c156cde1eb24e628395744db75fc24b9df4595350aaad0bc38e0246c9b4148f6443ef68b8e253a4a6bcf11c +9316e9e4ec5fab4f80d6540df0e3a4774db52f1d759d2e5b5bcd3d7b53597bb007eb1887cb7dc61f62497d51ffc8d996 +902d6d77bb49492c7a00bc4b70277bc28c8bf9888f4307bb017ac75a962decdedf3a4e2cf6c1ea9f9ba551f4610cbbd7 +b07025a18b0e32dd5e12ec6a85781aa3554329ea12c4cd0d3b2c22e43d777ef6f89876dd90a9c8fb097ddf61cf18adc5 +b355a849ad3227caa4476759137e813505ec523cbc2d4105bc7148a4630f9e81918d110479a2d5f5e4cd9ccec9d9d3e3 +b49532cfdf02ee760109881ad030b89c48ee3bb7f219ccafc13c93aead754d29bdafe345be54c482e9d5672bd4505080 +9477802410e263e4f938d57fa8f2a6cac7754c5d38505b73ee35ea3f057aad958cb9722ba6b7b3cfc4524e9ca93f9cdc +9148ea83b4436339580f3dbc9ba51509e9ab13c03063587a57e125432dd0915f5d2a8f456a68f8fff57d5f08c8f34d6e +b00b6b5392b1930b54352c02b1b3b4f6186d20bf21698689bbfc7d13e86538a4397b90e9d5c93fd2054640c4dbe52a4f +926a9702500441243cd446e7cbf15dde16400259726794694b1d9a40263a9fc9e12f7bcbf12a27cb9aaba9e2d5848ddc +a0c6155f42686cbe7684a1dc327100962e13bafcf3db97971fc116d9f5c0c8355377e3d70979cdbd58fd3ea52440901c +a277f899f99edb8791889d0817ea6a96c24a61acfda3ad8c3379e7c62b9d4facc4b965020b588651672fd261a77f1bfc +8f528cebb866b501f91afa50e995234bef5bf20bff13005de99cb51eaac7b4f0bf38580cfd0470de40f577ead5d9ba0f +963fc03a44e9d502cc1d23250efef44d299befd03b898d07ce63ca607bb474b5cf7c965a7b9b0f32198b04a8393821f7 +ab087438d0a51078c378bf4a93bd48ef933ff0f1fa68d02d4460820df564e6642a663b5e50a5fe509527d55cb510ae04 +b0592e1f2c54746bb076be0fa480e1c4bebc4225e1236bcda3b299aa3853e3afb401233bdbcfc4a007b0523a720fbf62 +851613517966de76c1c55a94dc4595f299398a9808f2d2f0a84330ba657ab1f357701d0895f658c18a44cb00547f6f57 +a2fe9a1dd251e72b0fe4db27be508bb55208f8f1616b13d8be288363ec722826b1a1fd729fc561c3369bf13950bf1fd6 +b896cb2bc2d0c77739853bc59b0f89b2e008ba1f701c9cbe3bef035f499e1baee8f0ff1e794854a48c320586a2dfc81a +a1b60f98e5e5106785a9b81a85423452ee9ef980fa7fa8464f4366e73f89c50435a0c37b2906052b8e58e212ebd366cf +a853b0ebd9609656636df2e6acd5d8839c0fda56f7bf9288a943b06f0b67901a32b95e016ca8bc99bd7b5eab31347e72 +b290fa4c1346963bd5225235e6bdf7c542174dab4c908ab483d1745b9b3a6015525e398e1761c90e4b49968d05e30eea +b0f65a33ad18f154f1351f07879a183ad62e5144ad9f3241c2d06533dad09cbb2253949daff1bb02d24d16a3569f7ef0 +a00db59b8d4218faf5aeafcd39231027324408f208ec1f54d55a1c41228b463b88304d909d16b718cfc784213917b71e +b8d695dd33dc2c3bc73d98248c535b2770ad7fa31aa726f0aa4b3299efb0295ba9b4a51c71d314a4a1bd5872307534d1 +b848057cca2ca837ee49c42b88422303e58ea7d2fc76535260eb5bd609255e430514e927cc188324faa8e657396d63ec +92677836061364685c2aaf0313fa32322746074ed5666fd5f142a7e8f87135f45cd10e78a17557a4067a51dfde890371 +a854b22c9056a3a24ab164a53e5c5cf388616c33e67d8ebb4590cb16b2e7d88b54b1393c93760d154208b5ca822dc68f +86fff174920388bfab841118fb076b2b0cdec3fdb6c3d9a476262f82689fb0ed3f1897f7be9dbf0932bb14d346815c63 +99661cf4c94a74e182752bcc4b98a8c2218a8f2765642025048e12e88ba776f14f7be73a2d79bd21a61def757f47f904 +8a8893144d771dca28760cba0f950a5d634195fd401ec8cf1145146286caffb0b1a6ba0c4c1828d0a5480ce49073c64c +938a59ae761359ee2688571e7b7d54692848eb5dde57ffc572b473001ea199786886f8c6346a226209484afb61d2e526 +923f68a6aa6616714cf077cf548aeb845bfdd78f2f6851d8148cba9e33a374017f2f3da186c39b82d14785a093313222 +ac923a93d7da7013e73ce8b4a2b14b8fd0cc93dc29d5de941a70285bdd19be4740fedfe0c56b046689252a3696e9c5bc +b49b32c76d4ec1a2c68d4989285a920a805993bc6fcce6dacd3d2ddae73373050a5c44ba8422a3781050682fa0ef6ba2 +8a367941c07c3bdca5712524a1411bad7945c7c48ffc7103b1d4dff2c25751b0624219d1ccde8c3f70c465f954be5445 +b838f029df455efb6c530d0e370bbbf7d87d61a9aea3d2fe5474c5fe0a39cf235ceecf9693c5c6c5820b1ba8f820bd31 +a8983b7c715eaac7f13a001d2abc462dfc1559dab4a6b554119c271aa8fe00ffcf6b6949a1121f324d6d26cb877bcbae +a2afb24ad95a6f14a6796315fbe0d8d7700d08f0cfaf7a2abe841f5f18d4fecf094406cbd54da7232a159f9c5b6e805e +87e8e95ad2d62f947b2766ff405a23f7a8afba14e7f718a691d95369c79955cdebe24c54662553c60a3f55e6322c0f6f +87c2cbcecb754e0cc96128e707e5c5005c9de07ffd899efa3437cadc23362f5a1d3fcdd30a1f5bdc72af3fb594398c2a +91afd6ee04f0496dc633db88b9370d41c428b04fd991002502da2e9a0ef051bcd7b760e860829a44fbe5539fa65f8525 +8c50e5d1a24515a9dd624fe08b12223a75ca55196f769f24748686315329b337efadca1c63f88bee0ac292dd0a587440 +8a07e8f912a38d94309f317c32068e87f68f51bdfa082d96026f5f5f8a2211621f8a3856dda8069386bf15fb2d28c18f +94ad1dbe341c44eeaf4dc133eed47d8dbfe752575e836c075745770a6679ff1f0e7883b6aa917462993a7f469d74cab5 +8745f8bd86c2bb30efa7efb7725489f2654f3e1ac4ea95bd7ad0f3cfa223055d06c187a16192d9d7bdaea7b050c6a324 +900d149c8d79418cda5955974c450a70845e02e5a4ecbcc584a3ca64d237df73987c303e3eeb79da1af83bf62d9e579f +8f652ab565f677fb1a7ba03b08004e3cda06b86c6f1b0b9ab932e0834acf1370abb2914c15b0d08327b5504e5990681c +9103097d088be1f75ab9d3da879106c2f597e2cc91ec31e73430647bdd5c33bcfd771530d5521e7e14df6acda44f38a6 +b0fec7791cfb0f96e60601e1aeced9a92446b61fedab832539d1d1037558612d78419efa87ff5f6b7aab8fd697d4d9de +b9d2945bdb188b98958854ba287eb0480ef614199c4235ce5f15fc670b8c5ffe8eeb120c09c53ea8a543a022e6a321ac +a9461bb7d5490973ebaa51afc0bb4a5e42acdccb80e2f939e88b77ac28a98870e103e1042899750f8667a8cc9123bae9 +a37fdf11d4bcb2aed74b9f460a30aa34afea93386fa4cdb690f0a71bc58f0b8df60bec56e7a24f225978b862626fa00e +a214420e183e03d531cf91661466ea2187d84b6e814b8b20b3730a9400a7d25cf23181bb85589ebc982cec414f5c2923 +ad09a45a698a6beb3e0915f540ef16e9af7087f53328972532d6b5dfe98ce4020555ece65c6cbad8bd6be8a4dfefe6fd +ab6742800b02728c92d806976764cb027413d6f86edd08ad8bb5922a2969ee9836878cd39db70db0bd9a2646862acc4f +974ca9305bd5ea1dc1755dff3b63e8bfe9f744321046c1395659bcea2a987b528e64d5aa96ac7b015650b2253b37888d +84eee9d6bce039c52c2ebc4fccc0ad70e20c82f47c558098da4be2f386a493cbc76adc795b5488c8d11b6518c2c4fab8 +875d7bda46efcb63944e1ccf760a20144df3b00d53282b781e95f12bfc8f8316dfe6492c2efbf796f1150e36e436e9df +b68a2208e0c587b5c31b5f6cb32d3e6058a9642e2d9855da4f85566e1412db528475892060bb932c55b3a80877ad7b4a +ba006368ecab5febb6ab348644d9b63de202293085ed468df8bc24d992ae8ce468470aa37f36a73630c789fb9c819b30 +90a196035150846cd2b482c7b17027471372a8ce7d914c4d82b6ea7fa705d8ed5817bd42d63886242585baf7d1397a1c +a223b4c85e0daa8434b015fd9170b5561fe676664b67064974a1e9325066ecf88fc81f97ab5011c59fad28cedd04b240 +82e8ec43139cf15c6bbeed484b62e06cded8a39b5ce0389e4cbe9c9e9c02f2f0275d8d8d4e8dfec8f69a191bef220408 +81a3fc07a7b68d92c6ee4b6d28f5653ee9ec85f7e2ee1c51c075c1b130a8c5097dc661cf10c5aff1c7114b1a6a19f11a +8ed2ef8331546d98819a5dd0e6c9f8cb2630d0847671314a28f277faf68da080b53891dd75c82cbcf7788b255490785d +acecabf84a6f9bbed6b2fc2e7e4b48f02ef2f15e597538a73aea8f98addc6badda15e4695a67ecdb505c1554e8f345ec +b8f51019b2aa575f8476e03dcadf86cc8391f007e5f922c2a36b2daa63f5a503646a468990cd5c65148d323942193051 +aaa595a84b403ec65729bc1c8055a94f874bf9adddc6c507b3e1f24f79d3ad359595a672b93aab3394db4e2d4a7d8970 +895144c55fcbd0f64d7dd69e6855cfb956e02b5658eadf0f026a70703f3643037268fdd673b0d21b288578a83c6338dd +a2e92ae6d0d237d1274259a8f99d4ea4912a299816350b876fba5ebc60b714490e198a916e1c38c6e020a792496fa23c +a45795fda3b5bb0ad1d3c628f6add5b2a4473a1414c1a232e80e70d1cfffd7f8a8d9861f8df2946999d7dbb56bf60113 +b6659bf7f6f2fef61c39923e8c23b8c70e9c903028d8f62516d16755cd3fba2fe41c285aa9432dc75ab08f8a1d8a81fc +a735609a6bc5bfd85e58234fc439ff1f58f1ff1dd966c5921d8b649e21f006bf2b8642ad8a75063c159aaf6935789293 +a3c622eb387c9d15e7bda2e3e84d007cb13a6d50d655c3f2f289758e49d3b37b9a35e4535d3cc53d8efd51f407281f19 +8afe147b53ad99220f5ef9d763bfc91f9c20caecbcf823564236fb0e6ede49414c57d71eec4772c8715cc65a81af0047 +b5f0203233cf71913951e9c9c4e10d9243e3e4a1f2cb235bf3f42009120ba96e04aa414c9938ea8873b63148478927e8 +93c52493361b458d196172d7ba982a90a4f79f03aa8008edc322950de3ce6acf4c3977807a2ffa9e924047e02072b229 +b9e72b805c8ac56503f4a86c82720afbd5c73654408a22a2ac0b2e5caccdfb0e20b59807433a6233bc97ae58cf14c70a +af0475779b5cee278cca14c82da2a9f9c8ef222eb885e8c50cca2315fea420de6e04146590ed0dd5a29c0e0812964df5 +b430ccab85690db02c2d0eb610f3197884ca12bc5f23c51e282bf3a6aa7e4a79222c3d8761454caf55d6c01a327595f9 +830032937418b26ee6da9b5206f3e24dc76acd98589e37937e963a8333e5430abd6ce3dd93ef4b8997bd41440eed75d6 +8820a6d73180f3fe255199f3f175c5eb770461ad5cfdde2fb11508041ed19b8c4ce66ad6ecebf7d7e836cc2318df47ca +aef1393e7d97278e77bbf52ef6e1c1d5db721ccf75fe753cf47a881fa034ca61eaa5098ee5a344c156d2b14ff9e284ad +8a4a26c07218948c1196c45d927ef4d2c42ade5e29fe7a91eaebe34a29900072ce5194cf28d51f746f4c4c649daf4396 +84011dc150b7177abdcb715efbd8c201f9cb39c36e6069af5c50a096021768ba40cef45b659c70915af209f904ede3b6 +b1bd90675411389bb66910b21a4bbb50edce5330850c5ab0b682393950124252766fc81f5ecfc72fb7184387238c402e +8dfdcd30583b696d2c7744655f79809f451a60c9ad5bf1226dc078b19f4585d7b3ef7fa9d54e1ac09520d95cbfd20928 +b351b4dc6d98f75b8e5a48eb7c6f6e4b78451991c9ba630e5a1b9874c15ac450cd409c1a024713bf2cf82dc400e025ef +a462b8bc97ac668b97b28b3ae24b9f5de60e098d7b23ecb600d2194cd35827fb79f77c3e50d358f5bd72ee83fef18fa0 +a183753265c5f7890270821880cce5f9b2965b115ba783c6dba9769536f57a04465d7da5049c7cf8b3fcf48146173c18 +a8a771b81ed0d09e0da4d79f990e58eabcd2be3a2680419502dd592783fe52f657fe55125b385c41d0ba3b9b9cf54a83 +a71ec577db46011689d073245e3b1c3222a9b1fe6aa5b83629adec5733dd48617ebea91346f0dd0e6cdaa86e4931b168 +a334b8b244f0d598a02da6ae0f918a7857a54dce928376c4c85df15f3b0f2ba3ac321296b8b7c9dd47d770daf16c8f8c +a29037f8ef925c417c90c4df4f9fb27fb977d04e2b3dd5e8547d33e92ab72e7a00f5461de21e28835319eae5db145eb7 +b91054108ae78b00e3298d667b913ebc44d8f26e531eae78a8fe26fdfb60271c97efb2dee5f47ef5a3c15c8228138927 +926c13efbe90604f6244be9315a34f72a1f8d1aab7572df431998949c378cddbf2fe393502c930fff614ff06ae98a0ce +995c758fd5600e6537089b1baa4fbe0376ab274ff3e82a17768b40df6f91c2e443411de9cafa1e65ea88fb8b87d504f4 +9245ba307a7a90847da75fca8d77ec03fdfc812c871e7a2529c56a0a79a6de16084258e7a9ac4ae8a3756f394336e21c +99e0cfa2bb57a7e624231317044c15e52196ecce020db567c8e8cb960354a0be9862ee0c128c60b44777e65ac315e59f +ad4f6b3d27bbbb744126601053c3dc98c07ff0eb0b38a898bd80dce778372846d67e5ab8fb34fb3ad0ef3f235d77ba7f +a0f12cae3722bbbca2e539eb9cc7614632a2aefe51410430070a12b5bc5314ecec5857b7ff8f41e9980cac23064f7c56 +b487f1bc59485848c98222fd3bc36c8c9bb3d2912e2911f4ceca32c840a7921477f9b1fe00877e05c96c75d3eecae061 +a6033db53925654e18ecb3ce715715c36165d7035db9397087ac3a0585e587998a53973d011ac6d48af439493029cee6 +a6b4d09cd01c70a3311fd131d3710ccf97bde3e7b80efd5a8c0eaeffeb48cca0f951ced905290267b115b06d46f2693b +a9dff1df0a8f4f218a98b6f818a693fb0d611fed0fc3143537cbd6578d479af13a653a8155e535548a2a0628ae24fa58 +a58e469f65d366b519f9a394cacb7edaddac214463b7b6d62c2dbc1316e11c6c5184ce45c16de2d77f990dcdd8b55430 +989e71734f8119103586dc9a3c5f5033ddc815a21018b34c1f876cdfc112efa868d5751bf6419323e4e59fa6a03ece1c +a2da00e05036c884369e04cf55f3de7d659cd5fa3f849092b2519dd263694efe0f051953d9d94b7e121f0aee8b6174d7 +968f3c029f57ee31c4e1adea89a7f92e28483af9a74f30fbdb995dc2d40e8e657dff8f8d340d4a92bf65f54440f2859f +932778df6f60ac1639c1453ef0cbd2bf67592759dcccb3e96dcc743ff01679e4c7dd0ef2b0833dda548d32cb4eba49e2 +a805a31139f8e0d6dae1ac87d454b23a3dc9fc653d4ca18d4f8ebab30fc189c16e73981c2cb7dd6f8c30454a5208109d +a9ba0991296caa2aaa4a1ceacfb205544c2a2ec97088eace1d84ee5e2767656a172f75d2f0c4e16a3640a0e0dec316e0 +b1e49055c968dced47ec95ae934cf45023836d180702e20e2df57e0f62fb85d7ac60d657ba3ae13b8560b67210449459 +a94e1da570a38809c71e37571066acabff7bf5632737c9ab6e4a32856924bf6211139ab3cedbf083850ff2d0e0c0fcfc +88ef1bb322000c5a5515b310c838c9af4c1cdbb32eab1c83ac3b2283191cd40e9573747d663763a28dad0d64adc13840 +a987ce205f923100df0fbd5a85f22c9b99b9b9cbe6ddfa8dfda1b8fe95b4f71ff01d6c5b64ca02eb24edb2b255a14ef0 +84fe8221a9e95d9178359918a108de4763ebfa7a6487facb9c963406882a08a9a93f492f8e77cf9e7ea41ae079c45993 +aa1cf3dc7c5dcfa15bbbc811a4bb6dbac4fba4f97fb1ed344ab60264d7051f6eef19ea9773441d89929ee942ed089319 +8f6a7d610d59d9f54689bbe6a41f92d9f6096cde919c1ab94c3c7fcecf0851423bc191e5612349e10f855121c0570f56 +b5af1fa7894428a53ea520f260f3dc3726da245026b6d5d240625380bfb9c7c186df0204bb604efac5e613a70af5106e +a5bce6055ff812e72ce105f147147c7d48d7a2313884dd1f488b1240ee320f13e8a33f5441953a8e7a3209f65b673ce1 +b9b55b4a1422677d95821e1d042ab81bbf0bf087496504021ec2e17e238c2ca6b44fb3b635a5c9eac0871a724b8d47c3 +941c38e533ce4a673a3830845b56786585e5fe49c427f2e5c279fc6db08530c8f91db3e6c7822ec6bb4f956940052d18 +a38e191d66c625f975313c7007bbe7431b5a06ed2da1290a7d5d0f2ec73770d476efd07b8e632de64597d47df175cbb0 +94ba76b667abf055621db4c4145d18743a368d951565632ed4e743dd50dd3333507c0c34f286a5c5fdbf38191a2255cd +a5ca38c60be5602f2bfa6e00c687ac96ac36d517145018ddbee6f12eb0faa63dd57909b9eeed26085fe5ac44e55d10ab +b00fea3b825e60c1ed1c5deb4b551aa65a340e5af36b17d5262c9cd2c508711e4dc50dc2521a2c16c7c901902266e64a +971b86fc4033485e235ccb0997a236206ba25c6859075edbcdf3c943116a5030b7f75ebca9753d863a522ba21a215a90 +b3b31f52370de246ee215400975b674f6da39b2f32514fe6bd54e747752eedca22bb840493b44a67df42a3639c5f901f +affbbfac9c1ba7cbfa1839d2ae271dd6149869b75790bf103230637da41857fc326ef3552ff31c15bda0694080198143 +a95d42aa7ef1962520845aa3688f2752d291926f7b0d73ea2ee24f0612c03b43f2b0fe3c9a9a99620ffc8d487b981bc2 +914a266065caf64985e8c5b1cb2e3f4e3fe94d7d085a1881b1fefa435afef4e1b39a98551d096a62e4f5cc1a7f0fdc2e +81a0b4a96e2b75bc1bf2dbd165d58d55cfd259000a35504d1ffb18bc346a3e6f07602c683723864ffb980f840836fd8d +91c1556631cddd4c00b65b67962b39e4a33429029d311c8acf73a18600e362304fb68bccb56fde40f49e95b7829e0b87 +8befbacc19e57f7c885d1b7a6028359eb3d80792fe13b92a8400df21ce48deb0bb60f2ddb50e3d74f39f85d7eab23adc +92f9458d674df6e990789690ec9ca73dacb67fc9255b58c417c555a8cc1208ace56e8e538f86ba0f3615573a0fbac00d +b4b1b3062512d6ae7417850c08c13f707d5838e43d48eb98dd4621baf62eee9e82348f80fe9b888a12874bfa538771f8 +a13c4a3ac642ede37d9c883f5319e748d2b938f708c9d779714108a449b343f7b71a6e3ef4080fee125b416762920273 +af44983d5fc8cceee0551ef934e6e653f2d3efa385e5c8a27a272463a6f333e290378cc307c2b664eb923c78994e706e +a389fd6c59fe2b4031cc244e22d3991e541bd203dd5b5e73a6159e72df1ab41d49994961500dcde7989e945213184778 +8d2141e4a17836c548de9598d7b298b03f0e6c73b7364979a411c464e0628e21cff6ac3d6decdba5d1c4909eff479761 +980b22ef53b7bdf188a3f14bc51b0dbfdf9c758826daa3cbc1e3986022406a8aa9a6a79e400567120b88c67faa35ce5f +a28882f0a055f96df3711de5d0aa69473e71245f4f3e9aa944e9d1fb166e02caa50832e46da6d3a03b4801735fd01b29 +8db106a37d7b88f5d995c126abb563934dd8de516af48e85695d02b1aea07f79217e3cdd03c6f5ca57421830186c772b +b5a7e50da0559a675c472f7dfaee456caab6695ab7870541b2be8c2b118c63752427184aad81f0e1afc61aef1f28c46f +9962118780e20fe291d10b64f28d09442a8e1b5cffd0f3dd68d980d0614050a626c616b44e9807fbee7accecae00686a +b38ddf33745e8d2ad6a991aefaf656a33c5f8cbe5d5b6b6fd03bd962153d8fd0e01b5f8f96d80ae53ab28d593ab1d4e7 +857dc12c0544ff2c0c703761d901aba636415dee45618aba2e3454ff9cbc634a85c8b05565e88520ff9be2d097c8b2b1 +a80d465c3f8cc63af6d74a6a5086b626c1cb4a8c0fee425964c3bd203d9d7094e299f81ce96d58afc20c8c9a029d9dae +89e1c8fbde8563763be483123a3ed702efac189c6d8ab4d16c85e74bbaf856048cc42d5d6e138633a38572ba5ec3f594 +893a594cf495535f6d216508f8d03c317dcf03446668cba688da90f52d0111ac83d76ad09bf5ea47056846585ee5c791 +aadbd8be0ae452f7f9450c7d2957598a20cbf10139a4023a78b4438172d62b18b0de39754dd2f8862dbd50a3a0815e53 +ae7d39670ecca3eb6db2095da2517a581b0e8853bdfef619b1fad9aacd443e7e6a40f18209fadd44038a55085c5fe8b2 +866ef241520eacb6331593cfcb206f7409d2f33d04542e6e52cba5447934e02d44c471f6c9a45963f9307e9809ab91d9 +b1a09911ad3864678f7be79a9c3c3eb5c84a0a45f8dcb52c67148f43439aeaaa9fd3ed3471276b7e588b49d6ebe3033a +add07b7f0dbb34049cd8feeb3c18da5944bf706871cfd9f14ff72f6c59ad217ebb1f0258b13b167851929387e4e34cfe +ae048892d5c328eefbdd4fba67d95901e3c14d974bfc0a1fc68155ca9f0d59e61d7ba17c6c9948b120cf35fd26e6fee9 +9185b4f3b7da0ddb4e0d0f09b8a9e0d6943a4611e43f13c3e2a767ed8592d31e0ba3ebe1914026a3627680274291f6e5 +a9c022d4e37b0802284ce3b7ee9258628ab4044f0db4de53d1c3efba9de19d15d65cc5e608dbe149c21c2af47d0b07b5 +b24dbd5852f8f24921a4e27013b6c3fa8885b973266cb839b9c388efad95821d5d746348179dcc07542bd0d0aefad1ce +b5fb4f279300876a539a27a441348764908bc0051ebd66dc51739807305e73db3d2f6f0f294ffb91b508ab150eaf8527 +ace50841e718265b290c3483ed4b0fdd1175338c5f1f7530ae9a0e75d5f80216f4de37536adcbc8d8c95982e88808cd0 +b19cadcde0f63bd1a9c24bd9c2806f53c14c0b9735bf351601498408ba503ddbd2037c891041cbba47f58b8c483f3b21 +b6061e63558d312eb891b97b39aa552fa218568d79ee26fe6dd5b864aea9e3216d8f2e2f3b093503be274766dac41426 +89730fdb2876ab6f0fe780d695f6e12090259027e789b819956d786e977518057e5d1d7f5ab24a3ae3d5d4c97773bd2b +b6fa841e81f9f2cad0163a02a63ae96dc341f7ae803b616efc6e1da2fbea551c1b96b11ad02c4afbdf6d0cc9f23da172 +8fb66187182629c861ddb6896d7ed3caf2ad050c3dba8ab8eb0d7a2c924c3d44c48d1a148f9e33fb1f061b86972f8d21 +86022ac339c1f84a7fa9e05358c1a5b316b4fc0b83dbe9c8c7225dc514f709d66490b539359b084ce776e301024345fa +b50b9c321468da950f01480bb62b6edafd42f83c0001d6e97f2bd523a1c49a0e8574fb66380ea28d23a7c4d54784f9f0 +a31c05f7032f30d1dac06678be64d0250a071fd655e557400e4a7f4c152be4d5c7aa32529baf3e5be7c4bd49820054f6 +b95ac0848cd322684772119f5b682d90a66bbf9dac411d9d86d2c34844bbd944dbaf8e47aa41380455abd51687931a78 +ae4a6a5ce9553b65a05f7935e61e496a4a0f6fd8203367a2c627394c9ce1e280750297b74cdc48fd1d9a31e93f97bef4 +a22daf35f6e9b05e52e0b07f7bd1dbbebd2c263033fb0e1b2c804e2d964e2f11bc0ece6aca6af079dd3a9939c9c80674 +902150e0cb1f16b9b59690db35281e28998ce275acb313900da8b2d8dfd29fa1795f8ca3ff820c31d0697de29df347c1 +b17b5104a5dc665cdd7d47e476153d715eb78c6e5199303e4b5445c21a7fa7cf85fe7cfd08d7570f4e84e579b005428c +a03f49b81c15433f121680aa02d734bb9e363af2156654a62bcb5b2ba2218398ccb0ff61104ea5d7df5b16ea18623b1e +802101abd5d3c88876e75a27ffc2f9ddcce75e6b24f23dba03e5201281a7bd5cc7530b6a003be92d225093ca17d3c3bb +a4d183f63c1b4521a6b52226fc19106158fc8ea402461a5cccdaa35fee93669df6a8661f45c1750cd01308149b7bf08e +8d17c22e0c8403b69736364d460b3014775c591032604413d20a5096a94d4030d7c50b9fe3240e31d0311efcf9816a47 +947225acfcce5992eab96276f668c3cbe5f298b90a59f2bb213be9997d8850919e8f496f182689b5cbd54084a7332482 +8df6f4ed216fc8d1905e06163ba1c90d336ab991a18564b0169623eb39b84e627fa267397da15d3ed754d1f3423bff07 +83480007a88f1a36dea464c32b849a3a999316044f12281e2e1c25f07d495f9b1710b4ba0d88e9560e72433addd50bc2 +b3019d6e591cf5b33eb972e49e06c6d0a82a73a75d78d383dd6f6a4269838289e6e07c245f54fed67f5c9bb0fd5e1c5f +92e8ce05e94927a9fb02debadb99cf30a26172b2705003a2c0c47b3d8002bf1060edb0f6a5750aad827c98a656b19199 +ac2aff801448dbbfc13cca7d603fd9c69e82100d997faf11f465323b97255504f10c0c77401e4d1890339d8b224f5803 +b0453d9903d08f508ee27e577445dc098baed6cde0ac984b42e0f0efed62760bd58d5816cf1e109d204607b7b175e30c +ae68dc4ba5067e825d46d2c7c67f1009ceb49d68e8d3e4c57f4bcd299eb2de3575d42ea45e8722f8f28497a6e14a1cfe +b22486c2f5b51d72335ce819bbafb7fa25eb1c28a378a658f13f9fc79cd20083a7e573248d911231b45a5cf23b561ca7 +89d1201d1dbd6921867341471488b4d2fd0fc773ae1d4d074c78ae2eb779a59b64c00452c2a0255826fca6b3d03be2b1 +a2998977c91c7a53dc6104f5bc0a5b675e5350f835e2f0af69825db8af4aeb68435bdbcc795f3dd1f55e1dd50bc0507f +b0be4937a925b3c05056ed621910d535ccabf5ab99fd3b9335080b0e51d9607d0fd36cb5781ff340018f6acfca4a9736 +aea145a0f6e0ba9df8e52e84bb9c9de2c2dc822f70d2724029b153eb68ee9c17de7d35063dcd6a39c37c59fdd12138f7 +91cb4545d7165ee8ffbc74c874baceca11fdebbc7387908d1a25877ca3c57f2c5def424dab24148826832f1e880bede0 +b3b579cb77573f19c571ad5eeeb21f65548d7dff9d298b8d7418c11f3e8cd3727c5b467f013cb87d6861cfaceee0d2e3 +b98a1eeec2b19fecc8378c876d73645aa52fb99e4819903735b2c7a885b242787a30d1269a04bfb8573d72d9bbc5f0f0 +940c1f01ed362bd588b950c27f8cc1d52276c71bb153d47f07ec85b038c11d9a8424b7904f424423e714454d5e80d1cd +aa343a8ecf09ce11599b8cf22f7279cf80f06dbf9f6d62cb05308dbbb39c46fd0a4a1240b032665fbb488a767379b91b +87c3ac72084aca5974599d3232e11d416348719e08443acaba2b328923af945031f86432e170dcdd103774ec92e988c9 +91d6486eb5e61d2b9a9e742c20ec974a47627c6096b3da56209c2b4e4757f007e793ebb63b2b246857c9839b64dc0233 +aebcd3257d295747dd6fc4ff910d839dd80c51c173ae59b8b2ec937747c2072fa85e3017f9060aa509af88dfc7529481 +b3075ba6668ca04eff19efbfa3356b92f0ab12632dcda99cf8c655f35b7928c304218e0f9799d68ef9f809a1492ff7db +93ba7468bb325639ec2abd4d55179c69fd04eaaf39fc5340709227bbaa4ad0a54ea8b480a1a3c8d44684e3be0f8d1980 +a6aef86c8c0d92839f38544d91b767c582568b391071228ff5a5a6b859c87bf4f81a7d926094a4ada1993ddbd677a920 +91dcd6d14207aa569194aa224d1e5037b999b69ade52843315ca61ba26abe9a76412c9e88259bc5cf5d7b95b97d9c3bc +b3b483d31c88f78d49bd065893bc1e3d2aa637e27dedb46d9a7d60be7660ce7a10aaaa7deead362284a52e6d14021178 +8e5730070acf8371461ef301cc4523e8e672aa0e3d945d438a0e0aa6bdf8cb9c685dcf38df429037b0c8aff3955c6f5b +b8c6d769890a8ee18dc4f9e917993315877c97549549b34785a92543cbeec96a08ae3a28d6e809c4aacd69de356c0012 +95ca86cd384eaceaa7c077c5615736ca31f36824bd6451a16142a1edc129fa42b50724aeed7c738f08d7b157f78b569e +94df609c6d71e8eee7ab74226e371ccc77e01738fe0ef1a6424435b4570fe1e5d15797b66ed0f64eb88d4a3a37631f0e +89057b9783212add6a0690d6bb99097b182738deff2bd9e147d7fd7d6c8eacb4c219923633e6309ad993c24572289901 +83a0f9f5f265c5a0e54defa87128240235e24498f20965009fef664f505a360b6fb4020f2742565dfc7746eb185bcec0 +91170da5306128931349bc3ed50d7df0e48a68b8cc8420975170723ac79d8773e4fa13c5f14dc6e3fafcad78379050b1 +b7178484d1b55f7e56a4cc250b6b2ec6040437d96bdfddfa7b35ed27435860f3855c2eb86c636f2911b012eb83b00db8 +ac0b00c4322d1e4208e09cd977b4e54d221133ff09551f75b32b0b55d0e2be80941dda26257b0e288c162e63c7e9cf68 +9690ed9e7e53ed37ff362930e4096b878b12234c332fd19d5d064824084245952eda9f979e0098110d6963e468cf513e +b6fa547bb0bb83e5c5be0ed462a8783fba119041c136a250045c09d0d2af330c604331e7de960df976ff76d67f8000cd +814603907c21463bcf4e59cfb43066dfe1a50344ae04ef03c87c0f61b30836c3f4dea0851d6fa358c620045b7f9214c8 +9495639e3939fad2a3df00a88603a5a180f3c3a0fe4d424c35060e2043e0921788003689887b1ed5be424d9a89bb18bb +aba4c02d8d57f2c92d5bc765885849e9ff8393d6554f5e5f3e907e5bfac041193a0d8716d7861104a4295d5a03c36b03 +8ead0b56c1ca49723f94a998ba113b9058059321da72d9e395a667e6a63d5a9dac0f5717cec343f021695e8ced1f72af +b43037f7e3852c34ed918c5854cd74e9d5799eeddfe457d4f93bb494801a064735e326a76e1f5e50a339844a2f4a8ec9 +99db8422bb7302199eb0ff3c3d08821f8c32f53a600c5b6fb43e41205d96adae72be5b460773d1280ad1acb806af9be8 +8a9be08eae0086c0f020838925984df345c5512ff32e37120b644512b1d9d4fecf0fd30639ca90fc6cf334a86770d536 +81b43614f1c28aa3713a309a88a782fb2bdfc4261dd52ddc204687791a40cf5fd6a263a8179388596582cccf0162efc2 +a9f3a8b76912deb61d966c75daf5ddb868702ebec91bd4033471c8e533183df548742a81a2671de5be63a502d827437d +902e2415077f063e638207dc7e14109652e42ab47caccd6204e2870115791c9defac5425fd360b37ac0f7bd8fe7011f8 +aa18e4fdc1381b59c18503ae6f6f2d6943445bd00dd7d4a2ad7e5adad7027f2263832690be30d456e6d772ad76f22350 +a348b40ba3ba7d81c5d4631f038186ebd5e5f314f1ea737259151b07c3cc8cf0c6ed4201e71bcc1c22fefda81a20cde6 +aa1306f7ac1acbfc47dc6f7a0cb6d03786cec8c8dc8060388ccda777bca24bdc634d03e53512c23dba79709ff64f8620 +818ccfe46e700567b7f3eb400e5a35f6a5e39b3db3aa8bc07f58ace35d9ae5a242faf8dbccd08d9a9175bbce15612155 +b7e3da2282b65dc8333592bb345a473f03bd6df69170055fec60222de9897184536bf22b9388b08160321144d0940279 +a4d976be0f0568f4e57de1460a1729129252b44c552a69fceec44e5b97c96c711763360d11f9e5bf6d86b4976bf40d69 +85d185f0397c24c2b875b09b6328a23b87982b84ee880f2677a22ff4c9a1ba9f0fea000bb3f7f66375a00d98ebafce17 +b4ccbb8c3a2606bd9b87ce022704663af71d418351575f3b350d294f4efc68c26f9a2ce49ff81e6ff29c3b63d746294e +93ffd3265fddb63724dfde261d1f9e22f15ecf39df28e4d89e9fea03221e8e88b5dd9b77628bacaa783c6f91802d47cc +b1fd0f8d7a01378e693da98d03a2d2fda6b099d03454b6f2b1fa6472ff6bb092751ce6290059826b74ac0361eab00e1e +a89f440c71c561641589796994dd2769616b9088766e983c873fae0716b95c386c8483ab8a4f367b6a68b72b7456dd32 +af4fe92b01d42d03dd5d1e7fa55e96d4bbcb7bf7d4c8c197acd16b3e0f3455807199f683dcd263d74547ef9c244b35cc +a8227f6e0a344dfe76bfbe7a1861be32c4f4bed587ccce09f9ce2cf481b2dda8ae4f566154bc663d15f962f2d41761bd +a7b361663f7495939ed7f518ba45ea9ff576c4e628995b7aea026480c17a71d63fc2c922319f0502eb7ef8f14a406882 +8ddcf382a9f39f75777160967c07012cfa89e67b19714a7191f0c68eaf263935e5504e1104aaabd0899348c972a8d3c6 +98c95b9f6f5c91f805fb185eedd06c6fc4457d37dd248d0be45a6a168a70031715165ea20606245cbdf8815dc0ac697f +805b44f96e001e5909834f70c09be3efcd3b43632bcac5b6b66b6d227a03a758e4b1768ce2a723045681a1d34562aaeb +b0e81b07cdc45b3dca60882676d9badb99f25c461b7efe56e3043b80100bb62d29e1873ae25eb83087273160ece72a55 +b0c53f0abe78ee86c7b78c82ae1f7c070bb0b9c45c563a8b3baa2c515d482d7507bb80771e60b38ac13f78b8af92b4a9 +a7838ef6696a9e4d2e5dfd581f6c8d6a700467e8fd4e85adabb5f7a56f514785dd4ab64f6f1b48366f7d94728359441b +88c76f7700a1d23c30366a1d8612a796da57b2500f97f88fdf2d76b045a9d24e7426a8ffa2f4e86d3046937a841dad58 +ad8964baf98c1f02e088d1d9fcb3af6b1dfa44cdfe0ed2eae684e7187c33d3a3c28c38e8f4e015f9c04d451ed6f85ff6 +90e9d00a098317ececaa9574da91fc149eda5b772dedb3e5a39636da6603aa007804fa86358550cfeff9be5a2cb7845e +a56ff4ddd73d9a6f5ab23bb77efa25977917df63571b269f6a999e1ad6681a88387fcc4ca3b26d57badf91b236503a29 +97ad839a6302c410a47e245df84c01fb9c4dfef86751af3f9340e86ff8fc3cd52fa5ff0b9a0bd1d9f453e02ca80658a6 +a4c8c44cbffa804129e123474854645107d1f0f463c45c30fd168848ebea94880f7c0c5a45183e9eb837f346270bdb35 +a72e53d0a1586d736e86427a93569f52edd2f42b01e78aee7e1961c2b63522423877ae3ac1227a2cf1e69f8e1ff15bc3 +8559f88a7ef13b4f09ac82ae458bbae6ab25671cfbf52dae7eac7280d6565dd3f0c3286aec1a56a8a16dc3b61d78ce47 +8221503f4cdbed550876c5dc118a3f2f17800c04e8be000266633c83777b039a432d576f3a36c8a01e8fd18289ebc10b +99bfbe5f3e46d4d898a578ba86ed26de7ed23914bd3bcdf3c791c0bcd49398a52419077354a5ab75cea63b6c871c6e96 +aa134416d8ff46f2acd866c1074af67566cfcf4e8be8d97329dfa0f603e1ff208488831ce5948ac8d75bfcba058ddcaa +b02609d65ebfe1fe8e52f21224a022ea4b5ea8c1bd6e7b9792eed8975fc387cdf9e3b419b8dd5bcce80703ab3a12a45f +a4f14798508698fa3852e5cac42a9db9797ecee7672a54988aa74037d334819aa7b2ac7b14efea6b81c509134a6b7ad2 +884f01afecbcb987cb3e7c489c43155c416ed41340f61ecb651d8cba884fb9274f6d9e7e4a46dd220253ae561614e44c +a05523c9e71dce1fe5307cc71bd721feb3e1a0f57a7d17c7d1c9fb080d44527b7dbaa1f817b1af1c0b4322e37bc4bb1e +8560aec176a4242b39f39433dd5a02d554248c9e49d3179530815f5031fee78ba9c71a35ceeb2b9d1f04c3617c13d8f0 +996aefd402748d8472477cae76d5a2b92e3f092fc834d5222ae50194dd884c9fb8b6ed8e5ccf8f6ed483ddbb4e80c747 +8fd09900320000cbabc40e16893e2fcf08815d288ec19345ad7b6bb22f7d78a52b6575a3ca1ca2f8bc252d2eafc928ec +939e51f73022bc5dc6862a0adf8fb8a3246b7bfb9943cbb4b27c73743926cc20f615a036c7e5b90c80840e7f1bfee0e7 +a0a6258700cadbb9e241f50766573bf9bdb7ad380b1079dc3afb4054363d838e177b869cad000314186936e40359b1f2 +972699a4131c8ed27a2d0e2104d54a65a7ff1c450ad9da3a325c662ab26869c21b0a84d0700b98c8b5f6ce3b746873d7 +a454c7fe870cb8aa6491eafbfb5f7872d6e696033f92e4991d057b59d70671f2acdabef533e229878b60c7fff8f748b1 +a167969477214201f09c79027b10221e4707662e0c0fde81a0f628249f2f8a859ce3d30a7dcc03b8ecca8f7828ad85c7 +8ff6b7265175beb8a63e1dbf18c9153fb2578c207c781282374f51b40d57a84fd2ef2ea2b9c6df4a54646788a62fd17f +a3d7ebeccde69d73d8b3e76af0da1a30884bb59729503ff0fb0c3bccf9221651b974a6e72ea33b7956fc3ae758226495 +b71ef144c9a98ce5935620cb86c1590bd4f48e5a2815d25c0cdb008fde628cf628c31450d3d4f67abbfeb16178a74cfd +b5e0a16d115134f4e2503990e3f2035ed66b9ccf767063fe6747870d97d73b10bc76ed668550cb82eedc9a2ca6f75524 +b30ffaaf94ee8cbc42aa2c413175b68afdb207dbf351fb20be3852cb7961b635c22838da97eaf43b103aff37e9e725cc +98aa7d52284f6c1f22e272fbddd8c8698cf8f5fbb702d5de96452141fafb559622815981e50b87a72c2b1190f59a7deb +81fbacda3905cfaf7780bb4850730c44166ed26a7c8d07197a5d4dcd969c09e94a0461638431476c16397dd7bdc449f9 +95e47021c1726eac2e5853f570d6225332c6e48e04c9738690d53e07c6b979283ebae31e2af1fc9c9b3e59f87e5195b1 +ac024a661ba568426bb8fce21780406537f518075c066276197300841e811860696f7588188bc01d90bace7bc73d56e3 +a4ebcaf668a888dd404988ab978594dee193dad2d0aec5cdc0ccaf4ec9a7a8228aa663db1da8ddc52ec8472178e40c32 +a20421b8eaf2199d93b083f2aff37fb662670bd18689d046ae976d1db1fedd2c2ff897985ecc6277b396db7da68bcb27 +8bc33d4b40197fd4d49d1de47489d10b90d9b346828f53a82256f3e9212b0cbc6930b895e879da9cec9fedf026aadb3e +aaafdd1bec8b757f55a0433eddc0a39f818591954fd4e982003437fcceb317423ad7ee74dbf17a2960380e7067a6b4e2 +aad34277ebaed81a6ec154d16736866f95832803af28aa5625bf0461a71d02b1faba02d9d9e002be51c8356425a56867 +976e9c8b150d08706079945bd0e84ab09a648ecc6f64ded9eb5329e57213149ae409ae93e8fbd8eda5b5c69f5212b883 +8097fae1653247d2aed4111533bc378171d6b2c6d09cbc7baa9b52f188d150d645941f46d19f7f5e27b7f073c1ebd079 +83905f93b250d3184eaba8ea7d727c4464b6bdb027e5cbe4f597d8b9dc741dcbea709630bd4fd59ce24023bec32fc0f3 +8095030b7045cff28f34271386e4752f9a9a0312f8df75de4f424366d78534be2b8e1720a19cb1f9a2d21105d790a225 +a7b7b73a6ae2ed1009c49960374b0790f93c74ee03b917642f33420498c188a169724945a975e5adec0a1e83e07fb1b2 +856a41c54df393b6660b7f6354572a4e71c8bfca9cabaffb3d4ef2632c015e7ee2bc10056f3eccb3dbed1ad17d939178 +a8f7a55cf04b38cd4e330394ee6589da3a07dc9673f74804fdf67b364e0b233f14aec42e783200a2e4666f7c5ff62490 +82c529f4e543c6bca60016dc93232c115b359eaee2798a9cf669a654b800aafe6ab4ba58ea8b9cdda2b371c8d62fa845 +8caab020c1baddce77a6794113ef1dfeafc5f5000f48e97f4351b588bf02f1f208101745463c480d37f588d5887e6d8c +8fa91b3cc400f48b77b6fd77f3b3fbfb3f10cdff408e1fd22d38f77e087b7683adad258804409ba099f1235b4b4d6fea +8aa02787663d6be9a35677d9d8188b725d5fcd770e61b11b64e3def8808ea5c71c0a9afd7f6630c48634546088fcd8e2 +b5635b7b972e195cab878b97dea62237c7f77eb57298538582a330b1082f6207a359f2923864630136d8b1f27c41b9aa +8257bb14583551a65975946980c714ecd6e5b629672bb950b9caacd886fbd22704bc9e3ba7d30778adab65dc74f0203a +ab5fe1cd12634bfa4e5c60d946e2005cbd38f1063ec9a5668994a2463c02449a0a185ef331bd86b68b6e23a8780cb3ba +a7d3487da56cda93570cc70215d438204f6a2709bfb5fda6c5df1e77e2efc80f4235c787e57fbf2c74aaff8cbb510a14 +b61cff7b4c49d010e133319fb828eb900f8a7e55114fc86b39c261a339c74f630e1a7d7e1350244ada566a0ff3d46c4b +8d4d1d55d321d278db7a85522ccceca09510374ca81d4d73e3bb5249ace7674b73900c35a531ec4fa6448fabf7ad00dc +966492248aee24f0f56c8cfca3c8ec6ba3b19abb69ae642041d4c3be8523d22c65c4dafcab4c58989ccc4e0bd2f77919 +b20c320a90cb220b86e1af651cdc1e21315cd215da69f6787e28157172f93fc8285dcd59b039c626ed8ca4633cba1a47 +aae9e6b22f018ceb5c0950210bb8182cb8cb61014b7e14581a09d36ebd1bbfebdb2b82afb7fdb0cf75e58a293d9c456d +875547fb67951ad37b02466b79f0c9b985ccbc500cfb431b17823457dc79fb9597ec42cd9f198e15523fcd88652e63a4 +92afce49773cb2e20fb21e4f86f18e0959ebb9c33361547ddb30454ee8e36b1e234019cbdca0e964cb292f7f77df6b90 +8af85343dfe1821464c76ba11c216cbef697b5afc69c4d821342e55afdac047081ec2e3f7b09fc14b518d9a23b78c003 +b7de4a1648fd63f3a918096ea669502af5357438e69dac77cb8102b6e6c15c76e033cfaa80dafc806e535ede5c1a20aa +ac80e9b545e8bd762951d96c9ce87f629d01ffcde07efc2ef7879ca011f1d0d8a745abf26c9d452541008871304fac00 +a4cf0f7ed724e481368016c38ea5816698a5f68eb21af4d3c422d2ba55f96a33e427c2aa40de1b56a7cfac7f7cf43ab0 +899b0a678bb2db2cae1b44e75a661284844ebcdd87abf308fedeb2e4dbe5c5920c07db4db7284a7af806a2382e8b111a +af0588a2a4afce2b1b13c1230816f59e8264177e774e4a341b289a101dcf6af813638fed14fb4d09cb45f35d5d032609 +a4b8df79e2be76e9f5fc5845f06fe745a724cf37c82fcdb72719b77bdebea3c0e763f37909373e3a94480cc5e875cba0 +83e42c46d88930c8f386b19fd999288f142d325e2ebc86a74907d6d77112cb0d449bc511c95422cc810574031a8cbba9 +b5e39534070de1e5f6e27efbdd3dc917d966c2a9b8cf2d893f964256e95e954330f2442027dc148c776d63a95bcde955 +958607569dc28c075e658cd4ae3927055c6bc456eef6212a6fea8205e48ed8777a8064f584cda38fe5639c371e2e7fba +812adf409fa63575113662966f5078a903212ffb65c9b0bbe62da0f13a133443a7062cb8fd70f5e5dd5559a32c26d2c8 +a679f673e5ce6a3cce7fa31f22ee3785e96bcb55e5a776e2dd3467bef7440e3555d1a9b87cb215e86ee9ed13a090344b +afedbb34508b159eb25eb2248d7fe328f86ef8c7d84c62d5b5607d74aae27cc2cc45ee148eb22153b09898a835c58df4 +b75505d4f6b67d31e665cfaf5e4acdb5838ae069166b7fbcd48937c0608a59e40a25302fcc1873d2e81c1782808c70f0 +b62515d539ec21a155d94fc00ea3c6b7e5f6636937bce18ed5b618c12257fb82571886287fd5d1da495296c663ebc512 +ab8e1a9446bbdd588d1690243b1549d230e6149c28f59662b66a8391a138d37ab594df38e7720fae53217e5c3573b5be +b31e8abf4212e03c3287bb2c0a153065a7290a16764a0bac8f112a72e632185a654bb4e88fdd6053e6c7515d9719fadb +b55165477fe15b6abd2d0f4fddaa9c411710dcc4dd712daba3d30e303c9a3ee5415c256f9dc917ecf18c725b4dbab059 +a0939d4f57cacaae549b78e87cc234de4ff6a35dc0d9cd5d7410abc30ebcd34c135e008651c756e5a9d2ca79c40ef42b +8cf10e50769f3443340844aad4d56ec790850fed5a41fcbd739abac4c3015f0a085a038fbe7fae9f5ad899cce5069f6b +924055e804d82a99ea4bb160041ea4dc14b568abf379010bc1922fde5d664718c31d103b8b807e3a1ae809390e708c73 +8ec0f9d26f71b0f2e60a179e4fd1778452e2ffb129d50815e5d7c7cb9415fa69ae5890578086e8ef6bfde35ad2a74661 +98c7f12b15ec4426b59f737f73bf5faea4572340f4550b7590dfb7f7ffedb2372e3e555977c63946d579544c53210ad0 +8a935f7a955c78f69d66f18eee0092e5e833fa621781c9581058e219af4d7ceee48b84e472e159dda6199715fb2f9acf +b78d4219f95a2dbfaa7d0c8a610c57c358754f4f43c2af312ab0fe8f10a5f0177e475332fb8fd23604e474fc2abeb051 +8d086a14803392b7318c28f1039a17e3cfdcece8abcaca3657ec3d0ac330842098a85c0212f889fabb296dfb133ce9aa +a53249f417aac82f2c2a50c244ce21d3e08a5e5a8bd33bec2a5ab0d6cd17793e34a17edfa3690899244ce201e2fb9986 +8619b0264f9182867a1425be514dc4f1ababc1093138a728a28bd7e4ecc99b9faaff68c23792264bc6e4dce5f52a5c52 +8c171edbbbde551ec19e31b2091eb6956107dd9b1f853e1df23bff3c10a3469ac77a58335eee2b79112502e8e163f3de +a9d19ec40f0ca07c238e9337c6d6a319190bdba2db76fb63902f3fb459aeeb50a1ac30db5b25ee1b4201f3ca7164a7f4 +b9c6ec14b1581a03520b8d2c1fbbc31fb8ceaef2c0f1a0d0080b6b96e18442f1734bea7ef7b635d787c691de4765d469 +8cb437beb4cfa013096f40ccc169a713dc17afee6daa229a398e45fd5c0645a9ad2795c3f0cd439531a7151945d7064d +a6e8740cc509126e146775157c2eb278003e5bb6c48465c160ed27888ca803fa12eee1f6a8dd7f444f571664ed87fdc1 +b75c1fecc85b2732e96b3f23aefb491dbd0206a21d682aee0225838dc057d7ed3b576176353e8e90ae55663f79e986e4 +ad8d249b0aea9597b08358bce6c77c1fd552ef3fbc197d6a1cfe44e5e6f89b628b12a6fb04d5dcfcbacc51f46e4ae7bb +b998b2269932cbd58d04b8e898d373ac4bb1a62e8567484f4f83e224061bc0f212459f1daae95abdbc63816ae6486a55 +827988ef6c1101cddc96b98f4a30365ff08eea2471dd949d2c0a9b35c3bbfa8c07054ad1f4c88c8fbf829b20bb5a9a4f +8692e638dd60babf7d9f2f2d2ce58e0ac689e1326d88311416357298c6a2bffbfebf55d5253563e7b3fbbf5072264146 +a685d75b91aea04dbc14ab3c1b1588e6de96dae414c8e37b8388766029631b28dd860688079b12d09cd27f2c5af11adf +b57eced93eec3371c56679c259b34ac0992286be4f4ff9489d81cf9712403509932e47404ddd86f89d7c1c3b6391b28c +a1c8b4e42ebcbd8927669a97f1b72e236fb19249325659e72be7ddaaa1d9e81ca2abb643295d41a8c04a2c01f9c0efd7 +877c33de20d4ed31674a671ba3e8f01a316581e32503136a70c9c15bf0b7cb7b1cba6cd4eb641fad165fb3c3c6c235fd +a2a469d84ec478da40838f775d11ad38f6596eb41caa139cc190d6a10b5108c09febae34ffdafac92271d2e73c143693 +972f817caedb254055d52e963ed28c206848b6c4cfdb69dbc961c891f8458eaf582a6d4403ce1177d87bc2ea410ef60a +accbd739e138007422f28536381decc54bb6bd71d93edf3890e54f9ef339f83d2821697d1a4ac1f5a98175f9a9ecb9b5 +8940f8772e05389f823b62b3adc3ed541f91647f0318d7a0d3f293aeeb421013de0d0a3664ea53dd24e5fbe02d7efef6 +8ecce20f3ef6212edef07ec4d6183fda8e0e8cad2c6ccd0b325e75c425ee1faba00b5c26b4d95204238931598d78f49d +97cc72c36335bd008afbed34a3b0c7225933faba87f7916d0a6d2161e6f82e0cdcda7959573a366f638ca75d30e9dab1 +9105f5de8699b5bdb6bd3bb6cc1992d1eac23929c29837985f83b22efdda92af64d9c574aa9640475087201bbbe5fd73 +8ffb33c4f6d05c413b9647eb6933526a350ed2e4278ca2ecc06b0e8026d8dbe829c476a40e45a6df63a633090a3f82ef +8bfc6421fdc9c2d2aaa68d2a69b1a2728c25b84944cc3e6a57ff0c94bfd210d1cbf4ff3f06702d2a8257024d8be7de63 +a80e1dc1dddfb41a70220939b96dc6935e00b32fb8be5dff4eed1f1c650002ff95e4af481c43292e3827363b7ec4768a +96f714ebd54617198bd636ba7f7a7f8995a61db20962f2165078d9ed8ee764d5946ef3cbdc7ebf8435bb8d5dd4c1deac +8cdb0890e33144d66391d2ae73f5c71f5a861f72bc93bff6cc399fc25dd1f9e17d8772592b44593429718784802ac377 +8ccf9a7f80800ee770b92add734ed45a73ecc31e2af0e04364eefc6056a8223834c7c0dc9dfc52495bdec6e74ce69994 +aa0875f423bd68b5f10ba978ddb79d3b96ec093bfbac9ff366323193e339ed7c4578760fb60f60e93598bdf1e5cc4995 +a9214f523957b59c7a4cb61a40251ad72aba0b57573163b0dc0f33e41d2df483fb9a1b85a5e7c080e9376c866790f8cb +b6224b605028c6673a536cc8ff9aeb94e7a22e686fda82cf16068d326469172f511219b68b2b3affb7933af0c1f80d07 +b6d58968d8a017c6a34e24c2c09852f736515a2c50f37232ac6b43a38f8faa7572cc31dade543b594b61b5761c4781d0 +8a97cefe5120020c38deeb861d394404e6c993c6cbd5989b6c9ebffe24f46ad11b4ba6348e2991cbf3949c28cfc3c99d +95bf046f8c3a9c0ce2634be4de3713024daec3fc4083e808903b25ce3ac971145af90686b451efcc72f6b22df0216667 +a6a4e2f71b8fa28801f553231eff2794c0f10d12e7e414276995e21195abc9c2983a8997e41af41e78d19ff6fbb2680b +8e5e62a7ca9c2f58ebaab63db2ff1fb1ff0877ae94b7f5e2897f273f684ae639dff44cc65718f78a9c894787602ab26a +8542784383eec4f565fcb8b9fc2ad8d7a644267d8d7612a0f476fc8df3aff458897a38003d506d24142ad18f93554f2b +b7db68ba4616ea072b37925ec4fb39096358c2832cc6d35169e032326b2d6614479f765ae98913c267105b84afcb9bf2 +8b31dbb9457d23d416c47542c786e07a489af35c4a87dadb8ee91bea5ac4a5315e65625d78dad2cf8f9561af31b45390 +a8545a1d91ac17257732033d89e6b7111db8242e9c6ebb0213a88906d5ef407a2c6fdb444e29504b06368b6efb4f4839 +b1bd85d29ebb28ccfb05779aad8674906b267c2bf8cdb1f9a0591dd621b53a4ee9f2942687ee3476740c0b4a7621a3ae +a2b54534e152e46c50d91fff03ae9cd019ff7cd9f4168b2fe7ac08ef8c3bbc134cadd3f9d6bd33d20ae476c2a8596c8a +b19b571ff4ae3e9f5d95acda133c455e72c9ea9973cae360732859836c0341c4c29ab039224dc5bc3deb824e031675d8 +940b5f80478648bac025a30f3efeb47023ce20ee98be833948a248bca6979f206bb28fc0f17b90acf3bb4abd3d14d731 +8f106b40588586ac11629b96d57808ad2808915d89539409c97414aded90b4ff23286a692608230a52bff696055ba5d6 +ae6bda03aa10da3d2abbc66d764ca6c8d0993e7304a1bdd413eb9622f3ca1913baa6da1e9f4f9e6cf847f14f44d6924d +a18e7796054a340ef826c4d6b5a117b80927afaf2ebd547794c400204ae2caf277692e2eabb55bc2f620763c9e9da66d +8d2d25180dc2c65a4844d3e66819ccfcf48858f0cc89e1c77553b463ec0f7feb9a4002ce26bc618d1142549b9850f232 +863f413a394de42cc8166c1c75d513b91d545fff1de6b359037a742c70b008d34bf8e587afa2d62c844d0c6f0ea753e7 +83cd0cf62d63475e7fcad18a2e74108499cdbf28af2113cfe005e3b5887794422da450b1944d0a986eb7e1f4c3b18f25 +b4f8b350a6d88fea5ab2e44715a292efb12eb52df738c9b2393da3f1ddee68d0a75b476733ccf93642154bceb208f2b8 +b3f52aaa4cd4221cb9fc45936cc67fd3864bf6d26bf3dd86aa85aa55ecfc05f5e392ecce5e7cf9406b4b1c4fce0398c8 +b33137084422fb643123f40a6df2b498065e65230fc65dc31791c330e898c51c3a65ff738930f32c63d78f3c9315f85b +91452bfa75019363976bb7337fe3a73f1c10f01637428c135536b0cdc7da5ce558dae3dfc792aa55022292600814a8ef +ad6ba94c787cd4361ca642c20793ea44f1f127d4de0bb4a77c7fbfebae0fcadbf28e2cb6f0c12c12a07324ec8c19761d +890aa6248b17f1501b0f869c556be7bf2b1d31a176f9978bb97ab7a6bd4138eed32467951c5ef1871944b7f620542f43 +82111db2052194ee7dd22ff1eafffac0443cf969d3762cceae046c9a11561c0fdce9c0711f88ac01d1bed165f8a7cee3 +b1527b71df2b42b55832f72e772a466e0fa05743aacc7814f4414e4bcc8d42a4010c9e0fd940e6f254cafedff3cd6543 +922370fa49903679fc565f09c16a5917f8125e72acfeb060fcdbadbd1644eb9f4016229756019c93c6d609cda5d5d174 +aa4c7d98a96cab138d2a53d4aee8ebff6ef903e3b629a92519608d88b3bbd94de5522291a1097e6acf830270e64c8ee1 +b3dc21608a389a72d3a752883a382baaafc61ecc44083b832610a237f6a2363f24195acce529eb4aed4ef0e27a12b66e +94619f5de05e07b32291e1d7ab1d8b7337a2235e49d4fb5f3055f090a65e932e829efa95db886b32b153bdd05a53ec8c +ade1e92722c2ffa85865d2426fb3d1654a16477d3abf580cfc45ea4b92d5668afc9d09275d3b79283e13e6b39e47424d +b7201589de7bed094911dd62fcd25c459a8e327ac447b69f541cdba30233063e5ddffad0b67e9c3e34adcffedfd0e13d +809d325310f862d6549e7cb40f7e5fc9b7544bd751dd28c4f363c724a0378c0e2adcb5e42ec8f912f5f49f18f3365c07 +a79c20aa533de7a5d671c99eb9eb454803ba54dd4f2efa3c8fec1a38f8308e9905c71e9282955225f686146388506ff6 +a85eeacb5e8fc9f3ed06a3fe2dc3108ab9f8c5877b148c73cf26e4e979bf5795edbe2e63a8d452565fd1176ed40402b2 +97ef55662f8a1ec0842b22ee21391227540adf7708f491436044f3a2eb18c471525e78e1e14fa292507c99d74d7437c6 +93110d64ed5886f3d16ce83b11425576a3a7a9bb831cd0de3f9a0b0f2270a730d68136b4ef7ff035ede004358f419b5c +ac9ed0a071517f0ae4f61ce95916a90ba9a77a3f84b0ec50ef7298acdcd44d1b94525d191c39d6bd1bb68f4471428760 +98abd6a02c7690f5a339adf292b8c9368dfc12e0f8069cf26a5e0ce54b4441638f5c66ea735142f3c28e00a0024267e6 +b51efb73ba6d44146f047d69b19c0722227a7748b0e8f644d0fc9551324cf034c041a2378c56ce8b58d06038fb8a78de +8f115af274ef75c1662b588b0896b97d71f8d67986ae846792702c4742ab855952865ce236b27e2321967ce36ff93357 +b3c4548f14d58b3ab03c222da09e4381a0afe47a72d18d50a94e0008797f78e39e99990e5b4757be62310d400746e35a +a9b1883bd5f31f909b8b1b6dcb48c1c60ed20aa7374b3ffa7f5b2ed036599b5bef33289d23c80a5e6420d191723b92f7 +85d38dffd99487ae5bb41ab4a44d80a46157bbbe8ef9497e68f061721f74e4da513ccc3422936b059575975f6787c936 +adf870fcb96e972c033ab7a35d28ae79ee795f82bc49c3bd69138f0e338103118d5529c53f2d72a9c0d947bf7d312af2 +ab4c7a44e2d9446c6ff303eb49aef0e367a58b22cc3bb27b4e69b55d1d9ee639c9234148d2ee95f9ca8079b1457d5a75 +a386420b738aba2d7145eb4cba6d643d96bda3f2ca55bb11980b318d43b289d55a108f4bc23a9606fb0bccdeb3b3bb30 +847020e0a440d9c4109773ecca5d8268b44d523389993b1f5e60e541187f7c597d79ebd6e318871815e26c96b4a4dbb1 +a530aa7e5ca86fcd1bec4b072b55cc793781f38a666c2033b510a69e110eeabb54c7d8cbcb9c61fee531a6f635ffa972 +87364a5ea1d270632a44269d686b2402da737948dac27f51b7a97af80b66728b0256547a5103d2227005541ca4b7ed04 +8816fc6e16ea277de93a6d793d0eb5c15e9e93eb958c5ef30adaf8241805adeb4da8ce19c3c2167f971f61e0b361077d +8836a72d301c42510367181bb091e4be377777aed57b73c29ef2ce1d475feedd7e0f31676284d9a94f6db01cc4de81a2 +b0d9d8b7116156d9dde138d28aa05a33e61f8a85839c1e9071ccd517b46a5b4b53acb32c2edd7150c15bc1b4bd8db9e3 +ae931b6eaeda790ba7f1cd674e53dc87f6306ff44951fa0df88d506316a5da240df9794ccbd7215a6470e6b31c5ea193 +8c6d5bdf87bd7f645419d7c6444e244fe054d437ed1ba0c122fde7800603a5fadc061e5b836cb22a6cfb2b466f20f013 +90d530c6d0cb654999fa771b8d11d723f54b8a8233d1052dc1e839ea6e314fbed3697084601f3e9bbb71d2b4eaa596df +b0d341a1422588c983f767b1ed36c18b141774f67ef6a43cff8e18b73a009da10fc12120938b8bba27f225bdfd3138f9 +a131b56f9537f460d304e9a1dd75702ace8abd68cb45419695cb8dee76998139058336c87b7afd6239dc20d7f8f940cc +aa6c51fa28975f709329adee1bbd35d49c6b878041841a94465e8218338e4371f5cb6c17f44a63ac93644bf28f15d20f +88440fb584a99ebd7f9ea04aaf622f6e44e2b43bbb49fb5de548d24a238dc8f26c8da2ccf03dd43102bda9f16623f609 +9777b8695b790e702159a4a750d5e7ff865425b95fa0a3c15495af385b91c90c00a6bd01d1b77bffe8c47d01baae846f +8b9d764ece7799079e63c7f01690c8eff00896a26a0d095773dea7a35967a8c40db7a6a74692f0118bf0460c26739af4 +85808c65c485520609c9e61fa1bb67b28f4611d3608a9f7a5030ee61c3aa3c7e7dc17fff48af76b4aecee2cb0dbd22ac +ad2783a76f5b3db008ef5f7e67391fda4e7e36abde6b3b089fc4835b5c339370287935af6bd53998bed4e399eda1136d +96f18ec03ae47c205cc4242ca58e2eff185c9dca86d5158817e2e5dc2207ab84aadda78725f8dc080a231efdc093b940 +97de1ab6c6cc646ae60cf7b86df73b9cf56cc0cd1f31b966951ebf79fc153531af55ca643b20b773daa7cab784b832f7 +870ba266a9bfa86ef644b1ef025a0f1b7609a60de170fe9508de8fd53170c0b48adb37f19397ee8019b041ce29a16576 +ad990e888d279ac4e8db90619d663d5ae027f994a3992c2fbc7d262b5990ae8a243e19157f3565671d1cb0de17fe6e55 +8d9d5adcdd94c5ba3be4d9a7428133b42e485f040a28d16ee2384758e87d35528f7f9868de9bd23d1a42a594ce50a567 +85a33ed75d514ece6ad78440e42f7fcdb59b6f4cff821188236d20edae9050b3a042ce9bc7d2054296e133d033e45022 +92afd2f49a124aaba90de59be85ff269457f982b54c91b06650c1b8055f9b4b0640fd378df02a00e4fc91f7d226ab980 +8c0ee09ec64bd831e544785e3d65418fe83ed9c920d9bb4d0bf6dd162c1264eb9d6652d2def0722e223915615931581c +8369bedfa17b24e9ad48ebd9c5afea4b66b3296d5770e09b00446c5b0a8a373d39d300780c01dcc1c6752792bccf5fd0 +8b9e960782576a59b2eb2250d346030daa50bbbec114e95cdb9e4b1ba18c3d34525ae388f859708131984976ca439d94 +b682bface862008fea2b5a07812ca6a28a58fd151a1d54c708fc2f8572916e0d678a9cb8dc1c10c0470025c8a605249e +a38d5e189bea540a824b36815fc41e3750760a52be0862c4cac68214febdc1a754fb194a7415a8fb7f96f6836196d82a +b9e7fbda650f18c7eb8b40e42cc42273a7298e65e8be524292369581861075c55299ce69309710e5b843cb884de171bd +b6657e5e31b3193874a1bace08f42faccbd3c502fb73ad87d15d18a1b6c2a146f1baa929e6f517db390a5a47b66c0acf +ae15487312f84ed6265e4c28327d24a8a0f4d2d17d4a5b7c29b974139cf93223435aaebe3af918f5b4bb20911799715f +8bb4608beb06bc394e1a70739b872ce5a2a3ffc98c7547bf2698c893ca399d6c13686f6663f483894bccaabc3b9c56ad +b58ac36bc6847077584308d952c5f3663e3001af5ecf2e19cb162e1c58bd6c49510205d453cffc876ca1dc6b8e04a578 +924f65ced61266a79a671ffb49b300f0ea44c50a0b4e3b02064faa99fcc3e4f6061ea8f38168ab118c5d47bd7804590e +8d67d43b8a06b0ff4fafd7f0483fa9ed1a9e3e658a03fb49d9d9b74e2e24858dc1bed065c12392037b467f255d4e5643 +b4d4f87813125a6b355e4519a81657fa97c43a6115817b819a6caf4823f1d6a1169683fd68f8d025cdfa40ebf3069acb +a7fd4d2c8e7b59b8eed3d4332ae94b77a89a2616347402f880bc81bde072220131e6dbec8a605be3a1c760b775375879 +8d4a7d8fa6f55a30df37bcf74952e2fa4fd6676a2e4606185cf154bdd84643fd01619f8fb8813a564f72e3f574f8ce30 +8086fb88e6260e9a9c42e9560fde76315ff5e5680ec7140f2a18438f15bc2cc7d7d43bfb5880b180b738c20a834e6134 +916c4c54721de03934fee6f43de50bb04c81f6f8dd4f6781e159e71c40c60408aa54251d457369d133d4ba3ed7c12cb4 +902e5bf468f11ed9954e2a4a595c27e34abe512f1d6dc08bbca1c2441063f9af3dc5a8075ab910a10ff6c05c1c644a35 +a1302953015e164bf4c15f7d4d35e3633425a78294406b861675667eec77765ff88472306531e5d3a4ec0a2ff0dd6a9e +87874461df3c9aa6c0fa91325576c0590f367075f2f0ecfeb34afe162c04c14f8ce9d608c37ac1adc8b9985bc036e366 +84b50a8a61d3cc609bfb0417348133e698fe09a6d37357ce3358de189efcf35773d78c57635c2d26c3542b13cc371752 +acaed2cff8633d12c1d12bb7270c54d65b0b0733ab084fd47f81d0a6e1e9b6f300e615e79538239e6160c566d8bb8d29 +889e6a0e136372ca4bac90d1ab220d4e1cad425a710e8cdd48b400b73bb8137291ceb36a39440fa84305783b1d42c72f +90952e5becec45b2b73719c228429a2c364991cf1d5a9d6845ae5b38018c2626f4308daa322cab1c72e0f6c621bb2b35 +8f5a97a801b6e9dcd66ccb80d337562c96f7914e7169e8ff0fda71534054c64bf2a9493bb830623d612cfe998789be65 +84f3df8b9847dcf1d63ca470dc623154898f83c25a6983e9b78c6d2d90a97bf5e622445be835f32c1e55e6a0a562ea78 +91d12095cd7a88e7f57f254f02fdb1a1ab18984871dead2f107404bcf8069fe68258c4e6f6ebd2477bddf738135400bb +b771a28bc04baef68604d4723791d3712f82b5e4fe316d7adc2fc01b935d8e644c06d59b83bcb542afc40ebafbee0683 +872f6341476e387604a7e93ae6d6117e72d164e38ebc2b825bc6df4fcce815004d7516423c190c1575946b5de438c08d +90d6b4aa7d40a020cdcd04e8b016d041795961a8e532a0e1f4041252131089114a251791bf57794cadb7d636342f5d1c +899023ba6096a181448d927fed7a0fe858be4eac4082a42e30b3050ee065278d72fa9b9d5ce3bc1372d4cbd30a2f2976 +a28f176571e1a9124f95973f414d5bdbf5794d41c3839d8b917100902ac4e2171eb940431236cec93928a60a77ede793 +838dbe5bcd29c4e465d02350270fa0036cd46f8730b13d91e77afb7f5ed16525d0021d3b2ae173a76c378516a903e0cb +8e105d012dd3f5d20f0f1c4a7e7f09f0fdd74ce554c3032e48da8cce0a77260d7d47a454851387770f5c256fa29bcb88 +8f4df0f9feeb7a487e1d138d13ea961459a6402fd8f8cabb226a92249a0d04ded5971f3242b9f90d08da5ff66da28af6 +ad1cfda4f2122a20935aa32fb17c536a3653a18617a65c6836700b5537122af5a8206befe9eaea781c1244c43778e7f1 +832c6f01d6571964ea383292efc8c8fa11e61c0634a25fa180737cc7ab57bc77f25e614aac9a2a03d98f27b3c1c29de2 +903f89cc13ec6685ac7728521898781fecb300e9094ef913d530bf875c18bcc3ceed7ed51e7b482d45619ab4b025c2e9 +a03c474bb915aad94f171e8d96f46abb2a19c9470601f4c915512ec8b9e743c3938450a2a5b077b4618b9df8809e1dc1 +83536c8456f306045a5f38ae4be2e350878fa7e164ea408d467f8c3bc4c2ee396bd5868008c089183868e4dfad7aa50b +88f26b4ea1b236cb326cd7ad7e2517ec8c4919598691474fe15d09cabcfc37a8d8b1b818f4d112432ee3a716b0f37871 +a44324e3fe96e9c12b40ded4f0f3397c8c7ee8ff5e96441118d8a6bfad712d3ac990b2a6a23231a8f691491ac1fd480f +b0de4693b4b9f932191a21ee88629964878680152a82996c0019ffc39f8d9369bbe2fe5844b68d6d9589ace54af947e4 +8e5d8ba948aea5fd26035351a960e87f0d23efddd8e13236cc8e4545a3dda2e9a85e6521efb8577e03772d3637d213d9 +93efc82d2017e9c57834a1246463e64774e56183bb247c8fc9dd98c56817e878d97b05f5c8d900acf1fbbbca6f146556 +8731176363ad7658a2862426ee47a5dce9434216cef60e6045fa57c40bb3ce1e78dac4510ae40f1f31db5967022ced32 +b10c9a96745722c85bdb1a693100104d560433d45b9ac4add54c7646a7310d8e9b3ca9abd1039d473ae768a18e489845 +a2ac374dfbb464bf850b4a2caf15b112634a6428e8395f9c9243baefd2452b4b4c61b0cb2836d8eae2d57d4900bf407e +b69fe3ded0c4f5d44a09a0e0f398221b6d1bf5dbb8bc4e338b93c64f1a3cac1e4b5f73c2b8117158030ec03787f4b452 +8852cdbaf7d0447a8c6f211b4830711b3b5c105c0f316e3a6a18dcfbb9be08bd6f4e5c8ae0c3692da08a2dfa532f9d5c +93bbf6d7432a7d98ade3f94b57bf9f4da9bc221a180a370b113066dd42601bb9e09edd79e2e6e04e00423399339eebda +a80941c391f1eeafc1451c59e4775d6a383946ff22997aeaadf806542ba451d3b0f0c6864eeba954174a296efe2c1550 +a045fe2bb011c2a2f71a0181a8f457a3078470fb74c628eab8b59aef69ffd0d649723bf74d6885af3f028bc5a104fb39 +b9d8c35911009c4c8cad64692139bf3fc16b78f5a19980790cb6a7aea650a25df4231a4437ae0c351676a7e42c16134f +94c79501ded0cfcbab99e1841abe4a00a0252b3870e20774c3da16c982d74c501916ec28304e71194845be6e3113c7ab +900a66418b082a24c6348d8644ddb1817df5b25cb33044a519ef47cc8e1f7f1e38d2465b7b96d32ed472d2d17f8414c6 +b26f45d393b8b2fcb29bdbb16323dc7f4b81c09618519ab3a39f8ee5bd148d0d9f3c0b5dfab55b5ce14a1cb9206d777b +aa1a87735fc493a80a96a9a57ca40a6d9c32702bfcaa9869ce1a116ae65d69cefe2f3e79a12454b4590353e96f8912b4 +a922b188d3d0b69b4e4ea2a2aa076566962844637da12c0832105d7b31dea4a309eee15d12b7a336be3ea36fcbd3e3b7 +8f3841fcf4105131d8c4d9885e6e11a46c448226401cf99356c291fadb864da9fa9d30f3a73c327f23f9fd99a11d633e +9791d1183fae270e226379af6c497e7da803ea854bb20afa74b253239b744c15f670ee808f708ede873e78d79a626c9a +a4cad52e3369491ada61bf28ada9e85de4516d21c882e5f1cd845bea9c06e0b2887b0c5527fcff6fc28acd3c04f0a796 +b9ac86a900899603452bd11a7892a9bfed8054970bfcbeaa8c9d1930db891169e38d6977f5258c25734f96c8462eee3b +a3a154c28e5580656a859f4efc2f5ebfa7eaa84ca40e3f134fa7865e8581586db74992dbfa4036aa252fba103773ddde +95cc2a0c1885a029e094f5d737e3ecf4d26b99036453a8773c77e360101f9f98676ee246f6f732a377a996702d55691f +842651bbe99720438d8d4b0218feb60481280c05beb17750e9ca0d8c0599a60f873b7fbdcc7d8835ba9a6d57b16eec03 +81ee54699da98f5620307893dcea8f64670609fa20e5622265d66283adeac122d458b3308c5898e6c57c298db2c8b24f +b97868b0b2bc98032d68352a535a1b341b9ff3c7af4e3a7f3ebc82d3419daa1b5859d6aedc39994939623c7cd878bd9b +b60325cd5d36461d07ef253d826f37f9ee6474a760f2fff80f9873d01fd2b57711543cdc8d7afa1c350aa753c2e33dea +8c205326c11d25a46717b780c639d89714c7736c974ae71287e3f4b02e6605ac2d9b4928967b1684f12be040b7bf2dd3 +95a392d82db51e26ade6c2ccd3396d7e40aff68fa570b5951466580d6e56dda51775dce5cf3a74a7f28c3cb2eb551c4d +8f2cc8071eb56dffb70bda6dd433b556221dc8bba21c53353c865f00e7d4d86c9e39f119ea9a8a12ef583e9a55d9a6b6 +9449a71af9672aaf8856896d7e3d788b22991a7103f75b08c0abbcc2bfe60fda4ed8ce502cea4511ff0ea52a93e81222 +857090ab9fdb7d59632d068f3cc8cf27e61f0d8322d30e6b38e780a1f05227199b4cd746aac1311c36c659ef20931f28 +98a891f4973e7d9aaf9ac70854608d4f7493dffc7e0987d7be9dd6029f6ea5636d24ef3a83205615ca1ff403750058e1 +a486e1365bbc278dd66a2a25d258dc82f46b911103cb16aab3945b9c95ae87b386313a12b566df5b22322ede0afe25ad +a9a1eb399ed95d396dccd8d1ac718043446f8b979ec62bdce51c617c97a312f01376ab7fb87d27034e5f5570797b3c33 +b7abc3858d7a74bb446218d2f5a037e0fae11871ed9caf44b29b69c500c1fa1dcfad64c9cdccc9d80d5e584f06213deb +8cfb09fe2e202faa4cebad932b1d35f5ca204e1c2a0c740a57812ac9a6792130d1312aabd9e9d4c58ca168bfebd4c177 +a90a305c2cd0f184787c6be596fa67f436afd1f9b93f30e875f817ac2aae8bdd2e6e656f6be809467e6b3ad84adb86b1 +80a9ef993c2b009ae172cc8f7ec036f5734cf4f4dfa06a7db4d54725e7fbfae5e3bc6f22687bdbb6961939d6f0c87537 +848ade1901931e72b955d7db1893f07003e1708ff5d93174bac5930b9a732640f0578839203e9b77eb27965c700032d3 +93fdf4697609c5ae9c33b9ca2f5f1af44abeb2b98dc4fdf732cf7388de086f410730dc384d9b7a7f447bb009653c8381 +89ce3fb805aea618b5715c0d22a9f46da696b6fa86794f56fdf1d44155a33d42daf1920bcbe36cbacf3cf4c92df9cbc7 +829ce2c342cf82aa469c65f724f308f7a750bd1494adc264609cd790c8718b8b25b5cab5858cf4ee2f8f651d569eea67 +af2f0cee7bf413204be8b9df59b9e4991bc9009e0d6dbe6815181df0ec2ca93ab8f4f3135b1c14d8f53d74bff0bd6f27 +b87998cecf7b88cde93d1779f10a521edd5574a2fbd240102978639ec57433ba08cdb53849038a329cebbe74657268d2 +a64542a1261a6ed3d720c2c3a802303aad8c4c110c95d0f12e05c1065e66f42da494792b6bfc5b9272363f3b1d457f58 +86a6fd042e4f282fadf07a4bfee03fc96a3aea49f7a00f52bf249a20f1ec892326855410e61f37fbb27d9305eb2fc713 +967ea5bc403b6db269682f7fd0df90659350d7e1aa66bc4fab4c9dfcd75ed0bba4b52f1cebc5f34dc8ba810793727629 +a52990f9f3b8616ce3cdc2c74cd195029e6a969753dcf2d1630438700e7d6ebde36538532b3525ac516f5f2ce9dd27a3 +a64f7ff870bab4a8bf0d4ef6f5c744e9bf1021ed08b4c80903c7ad318e80ba1817c3180cc45cb5a1cae1170f0241655f +b00f706fa4de1f663f021e8ad3d155e84ce6084a409374b6e6cd0f924a0a0b51bebaaaf1d228c77233a73b0a5a0df0e9 +8b882cc3bff3e42babdb96df95fb780faded84887a0a9bab896bef371cdcf169d909f5658649e93006aa3c6e1146d62e +9332663ef1d1dcf805c3d0e4ce7a07d9863fb1731172e766b3cde030bf81682cc011e26b773fb9c68e0477b4ae2cfb79 +a8aa8151348dbd4ef40aaeb699b71b4c4bfd3218560c120d85036d14f678f6736f0ec68e80ce1459d3d35feccc575164 +a16cd8b729768f51881c213434aa28301fa78fcb554ddd5f9012ee1e4eae7b5cb3dd88d269d53146dea92d10790faf0b +86844f0ef9d37142faf3b1e196e44fbe280a3ba4189aa05c356778cb9e3b388a2bff95eed305ada8769935c9974e4c57 +ae2eec6b328fccf3b47bcdac32901ac2744a51beb410b04c81dea34dee4912b619466a4f5e2780d87ecefaebbe77b46d +915df4c38d301c8a4eb2dc5b1ba0ffaad67cbb177e0a80095614e9c711f4ef24a4cef133f9d982a63d2a943ba6c8669d +ae6a2a4dedfc2d1811711a8946991fede972fdf2a389b282471280737536ffc0ac3a6d885b1f8bda0366eb0b229b9979 +a9b628c63d08b8aba6b1317f6e91c34b2382a6c85376e8ef2410a463c6796740ae936fc4e9e0737cb9455d1daa287bd8 +848e30bf7edf2546670b390d5cf9ab71f98fcb6add3c0b582cb34996c26a446dee5d1bde4fdcde4fc80c10936e117b29 +907d6096c7c8c087d1808dd995d5d2b9169b3768c3f433475b50c2e2bd4b082f4d543afd8b0b0ddffa9c66222a72d51d +a59970a2493b07339124d763ac9d793c60a03354539ecbcf6035bc43d1ea6e35718202ae6d7060b7d388f483d971573c +b9cfef2af9681b2318f119d8611ff6d9485a68d8044581b1959ab1840cbca576dbb53eec17863d2149966e9feb21122f +ad47271806161f61d3afa45cdfe2babceef5e90031a21779f83dc8562e6076680525b4970b2f11fe9b2b23c382768323 +8e425a99b71677b04fe044625d338811fbb8ee32368a424f6ab2381c52e86ee7a6cecedf777dc97181519d41c351bc22 +86b55b54d7adefc12954a9252ee23ae83efe8b5b4b9a7dc307904413e5d69868c7087a818b2833f9b004213d629be8ad +a14fda6b93923dd11e564ae4457a66f397741527166e0b16a8eb91c6701c244fd1c4b63f9dd3515193ec88fa6c266b35 +a9b17c36ae6cd85a0ed7f6cabc5b47dc8f80ced605db327c47826476dc1fb8f8669aa7a7dc679fbd4ee3d8e8b4bd6a6f +82a0829469c1458d959c821148f15dacae9ea94bf56c59a6ab2d4dd8b3d16d73e313b5a3912a6c1f131d73a8f06730c4 +b22d56d549a53eaef549595924bdb621ff807aa4513feedf3fdcbf7ba8b6b9cfa4481c2f67fc642db397a6b794a8b63a +974c59c24392e2cb9294006cbe3c52163e255f3bd0c2b457bdc68a6338e6d5b6f87f716854492f8d880a6b896ccf757c +b70d247ba7cad97c50b57f526c2ba915786e926a94e8f8c3eebc2e1be6f4255411b9670e382060049c8f4184302c40b2 +ad80201fe75ef21c3ddbd98cf23591e0d7a3ba1036dfe77785c32f44755a212c31f0ceb0a0b6f5ee9b6dc81f358d30c3 +8c656e841f9bb90b9a42d425251f3fdbc022a604d75f5845f479ed4be23e02aaf9e6e56cde351dd7449c50574818a199 +8b88dd3fa209d3063b7c5b058f7249ee9900fbc2287d16da61a0704a0a1d71e45d9c96e1cda7fdf9654534ec44558b22 +961da00cc8750bd84d253c08f011970ae1b1158ad6778e8ed943d547bceaf52d6d5a212a7de3bf2706688c4389b827d2 +a5dd379922549a956033e3d51a986a4b1508e575042b8eaa1df007aa77cf0b8c2ab23212f9c075702788fa9c53696133 +ac8fcfde3a349d1e93fc8cf450814e842005c545c4844c0401bc80e6b96cdb77f29285a14455e167c191d4f312e866cd +ac63d79c799783a8466617030c59dd5a8f92ee6c5204676fd8d881ce5f7f8663bdbeb0379e480ea9b6340ab0dc88e574 +805874fde19ce359041ae2bd52a39e2841acabfd31f965792f2737d7137f36d4e4722ede8340d8c95afa6af278af8acb +8d2f323a228aa8ba7b7dc1399138f9e6b41df1a16a7069003ab8104b8b68506a45141bc5fe66acf430e23e13a545190b +a1610c721a2d9af882bb6b39bea97cff1527a3aea041d25934de080214ae77c959e79957164440686d15ab301e897d4d +aba16d29a47fc36f12b654fde513896723e2c700c4190f11b26aa4011da57737ad717daa02794aa3246e4ae5f0b0cc3a +a406db2f15fdd135f346cc4846623c47edd195e80ba8c7cb447332095314d565e4040694ca924696bb5ee7f8996ea0ba +8b30e2cd9b47d75ba57b83630e40f832249af6c058d4f490416562af451993eec46f3e1f90bc4d389e4c06abd1b32a46 +aacf9eb7036e248e209adbfc3dd7ce386569ea9b312caa4b240726549db3c68c4f1c8cbf8ed5ea9ea60c7e57c9df3b8e +b20fcac63bf6f5ee638a42d7f89be847f348c085ddcbec3fa318f4323592d136c230495f188ef2022aa355cc2b0da6f9 +811eff750456a79ec1b1249d76d7c1547065b839d8d4aaad860f6d4528eb5b669473dcceeeea676cddbc3980b68461b7 +b52d14ae33f4ab422f953392ae76a19c618cc31afc96290bd3fe2fb44c954b5c92c4789f3f16e8793f2c0c1691ade444 +a7826dafeeba0db5b66c4dfcf2b17fd7b40507a5a53ac2e42942633a2cb30b95ba1739a6e9f3b7a0e0f1ec729bf274e2 +8acfd83ddf7c60dd7c8b20c706a3b972c65d336b8f9b3d907bdd8926ced271430479448100050b1ef17578a49c8fa616 +af0c69f65184bb06868029ad46f8465d75c36814c621ac20a5c0b06a900d59305584f5a6709683d9c0e4b6cd08d650a6 +b6cc8588191e00680ee6c3339bd0f0a17ad8fd7f4be57d5d7075bede0ea593a19e67f3d7c1a20114894ee5bfcab71063 +a82fd4f58635129dbb6cc3eb9391cf2d28400018b105fc41500fbbd12bd890b918f97d3d359c29dd3b4c4e34391dfab0 +92fc544ed65b4a3625cf03c41ddff7c039bc22d22c0d59dcc00efd5438401f2606adb125a1d5de294cca216ec8ac35a3 +906f67e4a32582b71f15940523c0c7ce370336935e2646bdaea16a06995256d25e99df57297e39d6c39535e180456407 +97510337ea5bbd5977287339197db55c60533b2ec35c94d0a460a416ae9f60e85cee39be82abeeacd5813cf54df05862 +87e6894643815c0ea48cb96c607266c5ee4f1f82ba5fe352fb77f9b6ed14bfc2b8e09e80a99ac9047dfcf62b2ae26795 +b6fd55dd156622ad7d5d51b7dde75e47bd052d4e542dd6449e72411f68275775c846dde301e84613312be8c7bce58b07 +b98461ac71f554b2f03a94e429b255af89eec917e208a8e60edf5fc43b65f1d17a20de3f31d2ce9f0cb573c25f2f4d98 +96f0dea40ca61cefbee41c4e1fe9a7d81fbe1f49bb153d083ab70f5d0488a1f717fd28cedcf6aa18d07cce2c62801898 +8d7c3ab310184f7dc34b6ce4684e4d29a31e77b09940448ea4daac730b7eb308063125d4dd229046cf11bfd521b771e0 +96f0564898fe96687918bbf0a6adead99cf72e3a35ea3347e124af9d006221f8e82e5a9d2fe80094d5e8d48e610f415e +ad50fcb92c2675a398cf07d4c40a579e44bf8d35f27cc330b57e54d5ea59f7d898af0f75dccfe3726e5471133d70f92b +828beed62020361689ae7481dd8f116902b522fb0c6c122678e7f949fdef70ead011e0e6bffd25678e388744e17cdb69 +8349decac1ca16599eee2efc95bcaabf67631107da1d34a2f917884bd70dfec9b4b08ab7bc4379d6c73b19c0b6e54fb8 +b2a6a2e50230c05613ace9e58bb2e98d94127f196f02d9dddc53c43fc68c184549ca12d713cb1b025d8260a41e947155 +94ff52181aadae832aed52fc3b7794536e2a31a21fc8be3ea312ca5c695750d37f08002f286b33f4023dba1e3253ecfa +a21d56153c7e5972ee9a319501be4faff199fdf09bb821ea9ce64aa815289676c00f105e6f00311b3a5b627091b0d0fc +a27a60d219f1f0c971db73a7f563b371b5c9fc3ed1f72883b2eac8a0df6698400c9954f4ca17d7e94e44bd4f95532afb +a2fc56fae99b1f18ba5e4fe838402164ce82f8a7f3193d0bbd360c2bac07c46f9330c4c7681ffb47074c6f81ee6e7ac6 +b748e530cd3afb96d879b83e89c9f1a444f54e55372ab1dcd46a0872f95ce8f49cf2363fc61be82259e04f555937ed16 +8bf8993e81080c7cbba1e14a798504af1e4950b2f186ab3335b771d6acaee4ffe92131ae9c53d74379d957cb6344d9cd +96774d0ef730d22d7ab6d9fb7f90b9ead44285219d076584a901960542756700a2a1603cdf72be4708b267200f6c36a9 +b47703c2ab17be1e823cc7bf3460db1d6760c0e33862c90ca058845b2ff234b0f9834ddba2efb2ee1770eb261e7d8ffd +84319e67c37a9581f8b09b5e4d4ae88d0a7fb4cbb6908971ab5be28070c3830f040b1de83ee663c573e0f2f6198640e4 +96811875fa83133e0b3c0e0290f9e0e28bca6178b77fdf5350eb19344d453dbd0d71e55a0ef749025a5a2ca0ad251e81 +81a423423e9438343879f2bfd7ee9f1c74ebebe7ce3cfffc8a11da6f040cc4145c3b527bd3cf63f9137e714dbcb474ef +b8c3535701ddbeec2db08e17a4fa99ba6752d32ece5331a0b8743676f421fcb14798afc7c783815484f14693d2f70db8 +81aee980c876949bf40782835eec8817d535f6f3f7e00bf402ddd61101fdcd60173961ae90a1cf7c5d060339a18c959d +87e67b928d97b62c49dac321ce6cb680233f3a394d4c9a899ac2e8db8ccd8e00418e66cdfd68691aa3cb8559723b580c +8eac204208d99a2b738648df96353bbb1b1065e33ee4f6bba174b540bbbd37d205855e1f1e69a6b7ff043ca377651126 +848e6e7a54ad64d18009300b93ea6f459ce855971dddb419b101f5ac4c159215626fadc20cc3b9ab1701d8f6dfaddd8b +88aa123d9e0cf309d46dddb6acf634b1ade3b090a2826d6e5e78669fa1220d6df9a6697d7778cd9b627db17eea846126 +9200c2a629b9144d88a61151b661b6c4256cc5dadfd1e59a8ce17a013c2d8f7e754aabe61663c3b30f1bc47784c1f8cf +b6e1a2827c3bdda91715b0e1b1f10dd363cef337e7c80cac1f34165fc0dea7c8b69747e310563db5818390146ce3e231 +92c333e694f89f0d306d54105b2a5dcc912dbe7654d9e733edab12e8537350815be472b063e56cfde5286df8922fdecb +a6fac04b6d86091158ebb286586ccfec2a95c9786e14d91a9c743f5f05546073e5e3cc717635a0c602cad8334e922346 +a581b4af77feebc1fb897d49b5b507c6ad513d8f09b273328efbb24ef0d91eb740d01b4d398f2738125dacfe550330cd +81c4860cccf76a34f8a2bc3f464b7bfd3e909e975cce0d28979f457738a56e60a4af8e68a3992cf273b5946e8d7f76e2 +8d1eaa09a3180d8af1cbaee673db5223363cc7229a69565f592fa38ba0f9d582cedf91e15dabd06ebbf2862fc0feba54 +9832f49b0147f4552402e54593cfa51f99540bffada12759b71fcb86734be8e500eea2d8b3d036710bdf04c901432de9 +8bdb0e8ec93b11e5718e8c13cb4f5de545d24829fd76161216340108098dfe5148ed25e3b57a89a516f09fa79043734d +ab96f06c4b9b0b2c0571740b24fca758e6976315053a7ecb20119150a9fa416db2d3a2e0f8168b390bb063f0c1caf785 +ab777f5c52acd62ecf4d1f168b9cc8e1a9b45d4ec6a8ff52c583e867c2239aba98d7d3af977289b367edce03d9c2dfb1 +a09d3ce5e748da84802436951acc3d3ea5d8ec1d6933505ed724d6b4b0d69973ab0930daec9c6606960f6e541e4a3ce2 +8ef94f7be4d85d5ad3d779a5cf4d7b2fc3e65c52fb8e1c3c112509a4af77a0b5be994f251e5e40fabeeb1f7d5615c22b +a7406a5bf5708d9e10922d3c5c45c03ef891b8d0d74ec9f28328a72be4cdc05b4f2703fa99366426659dfca25d007535 +b7f52709669bf92a2e070bfe740f422f0b7127392c5589c7f0af71bb5a8428697c762d3c0d74532899da24ea7d8695c2 +b9dfb0c8df84104dbf9239ccefa4672ef95ddabb8801b74997935d1b81a78a6a5669a3c553767ec19a1281f6e570f4ff +ae4d5c872156061ce9195ac640190d8d71dd406055ee43ffa6f9893eb24b870075b74c94d65bc1d5a07a6573282b5520 +afe6bd3eb72266d333f1807164900dcfa02a7eb5b1744bb3c86b34b3ee91e3f05e38fa52a50dc64eeb4bdb1dd62874b8 +948043cf1bc2ef3c01105f6a78dc06487f57548a3e6ef30e6ebc51c94b71e4bf3ff6d0058c72b6f3ecc37efd7c7fa8c0 +a22fd17c2f7ffe552bb0f23fa135584e8d2d8d75e3f742d94d04aded2a79e22a00dfe7acbb57d44e1cdb962fb22ae170 +8cd0f4e9e4fb4a37c02c1bde0f69359c43ab012eb662d346487be0c3758293f1ca560122b059b091fddce626383c3a8f +90499e45f5b9c81426f3d735a52a564cafbed72711d9279fdd88de8038e953bc48c57b58cba85c3b2e4ce56f1ddb0e11 +8c30e4c034c02958384564cac4f85022ef36ab5697a3d2feaf6bf105049675bbf23d01b4b6814711d3d9271abff04cac +81f7999e7eeea30f3e1075e6780bbf054f2fb6f27628a2afa4d41872a385b4216dd5f549da7ce6cf39049b2251f27fb7 +b36a7191f82fc39c283ffe53fc1f5a9a00b4c64eee7792a8443475da9a4d226cf257f226ea9d66e329af15d8f04984ec +aad4da528fdbb4db504f3041c747455baff5fcd459a2efd78f15bdf3aea0bdb808343e49df88fe7a7c8620009b7964a3 +99ebd8c6dd5dd299517fb6381cfc2a7f443e6e04a351440260dd7c2aee3f1d8ef06eb6c18820b394366ecdfd2a3ce264 +8873725b81871db72e4ec3643084b1cdce3cbf80b40b834b092767728605825c19b6847ad3dcf328438607e8f88b4410 +b008ee2f895daa6abd35bd39b6f7901ae4611a11a3271194e19da1cdcc7f1e1ea008fe5c5440e50d2c273784541ad9c5 +9036feafb4218d1f576ef89d0e99124e45dacaa6d816988e34d80f454d10e96809791d5b78f7fd65f569e90d4d7238c5 +92073c1d11b168e4fa50988b0288638b4868e48bbc668c5a6dddf5499875d53be23a285acb5e4bad60114f6cf6c556e9 +88c87dfcb8ba6cbfe7e1be081ccfadbd589301db2cb7c99f9ee5d7db90aa297ed1538d5a867678a763f2deede5fd219a +b42a562805c661a50f5dea63108002c0f27c0da113da6a9864c9feb5552225417c0356c4209e8e012d9bcc9d182c7611 +8e6317d00a504e3b79cd47feb4c60f9df186467fe9ca0f35b55c0364db30528f5ff071109dabb2fc80bb9cd4949f0c24 +b7b1ea6a88694f8d2f539e52a47466695e39e43a5eb9c6f23bca15305fe52939d8755cc3ac9d6725e60f82f994a3772f +a3cd55161befe795af93a38d33290fb642b8d80da8b786c6e6fb02d393ea308fbe87f486994039cbd7c7b390414594b6 +b416d2d45b44ead3b1424e92c73c2cf510801897b05d1724ff31cbd741920cd858282fb5d6040fe1f0aa97a65bc49424 +950ee01291754feace97c2e933e4681e7ddfbc4fcd079eb6ff830b0e481d929c93d0c7fb479c9939c28ca1945c40da09 +869bd916aee8d86efe362a49010382674825d49195b413b4b4018e88ce43fe091b475d0b863ff0ba2259400f280c2b23 +9782f38cd9c9d3385ec286ebbc7cba5b718d2e65a5890b0a5906b10a89dc8ed80d417d71d7c213bf52f2af1a1f513ea7 +91cd33bc2628d096269b23faf47ee15e14cb7fdc6a8e3a98b55e1031ea0b68d10ba30d97e660f7e967d24436d40fad73 +8becc978129cc96737034c577ae7225372dd855da8811ae4e46328e020c803833b5bdbc4a20a93270e2b8bd1a2feae52 +a36b1d8076783a9522476ce17f799d78008967728ce920531fdaf88303321bcaf97ecaa08e0c01f77bc32e53c5f09525 +b4720e744943f70467983aa34499e76de6d59aa6fadf86f6b787fdce32a2f5b535b55db38fe2da95825c51002cfe142d +91ad21fc502eda3945f6de874d1b6bf9a9a7711f4d61354f9e5634fc73f9c06ada848de15ab0a75811d3250be862827d +84f78e2ebf5fc077d78635f981712daf17e2475e14c2a96d187913006ad69e234746184a51a06ef510c9455b38acb0d7 +960aa7906e9a2f11db64a26b5892ac45f20d2ccb5480f4888d89973beb6fa0dfdc06d68d241ff5ffc7f1b82b1aac242d +a99365dcd1a00c66c9db6924b97c920f5c723380e823b250db85c07631b320ec4e92e586f7319e67a522a0578f7b6d6c +a25d92d7f70cf6a88ff317cfec071e13774516da664f5fac0d4ecaa65b8bf4eb87a64a4d5ef2bd97dfae98d388dbf5cc +a7af47cd0041295798f9779020a44653007444e8b4ef0712982b06d0dcdd434ec4e1f7c5f7a049326602cb605c9105b7 +aefe172eac5568369a05980931cc476bebd9dea573ba276d59b9d8c4420784299df5a910033b7e324a6c2dfc62e3ef05 +b69bc9d22ffa645baa55e3e02522e9892bb2daa7fff7c15846f13517d0799766883ee09ae0869df4139150c5b843ca8a +95a10856140e493354fdd12722c7fdded21b6a2ffbc78aa2697104af8ad0c8e2206f44b0bfee077ef3949d46bbf7c16b +891f2fcd2c47cbea36b7fa715968540c233313f05333f09d29aba23c193f462ed490dd4d00969656e89c53155fdfe710 +a6c33e18115e64e385c843dde34e8a228222795c7ca90bc2cc085705d609025f3351d9be61822c69035a49fb3e48f2d5 +b87fb12f12c0533b005adad0487f03393ff682e13575e3cb57280c3873b2c38ba96a63c49eef7a442753d26b7005230b +b905c02ba451bfd411c135036d92c27af3b0b1c9c2f1309d6948544a264b125f39dd41afeff4666b12146c545adc168a +8b29c513f43a78951cf742231cf5457a6d9d55edf45df5481a0f299a418d94effef561b15d2c1a01d1b8067e7153fda9 +b9941cccd51dc645920d2781c81a317e5a33cb7cf76427b60396735912cb6d2ca9292bb4d36b6392467d390d2c58d9f3 +a8546b627c76b6ef5c93c6a98538d8593dbe21cb7673fd383d5401b0c935eea0bdeeefeb1af6ad41bad8464fb87bbc48 +aa286b27de2812de63108a1aec29d171775b69538dc6198640ac1e96767c2b83a50391f49259195957d457b493b667c9 +a932fb229f641e9abbd8eb2bd874015d97b6658ab6d29769fc23b7db9e41dd4f850382d4c1f08af8f156c5937d524473 +a1412840fcc86e2aeec175526f2fb36e8b3b8d21a78412b7266daf81e51b3f68584ed8bd42a66a43afdd8c297b320520 +89c78be9efb624c97ebca4fe04c7704fa52311d183ffd87737f76b7dadc187c12c982bd8e9ed7cd8beb48cdaafd2fd01 +a3f5ddec412a5bec0ce15e3bcb41c6214c2b05d4e9135a0d33c8e50a78eaba71e0a5a6ea8b45854dec5c2ed300971fc2 +9721f9cec7a68b7758e3887548790de49fa6a442d0396739efa20c2f50352a7f91d300867556d11a703866def2d5f7b5 +a23764e140a87e5991573521af039630dd28128bf56eed2edbed130fd4278e090b60cf5a1dca9de2910603d44b9f6d45 +a1a6494a994215e48ab55c70efa8ffdddce6e92403c38ae7e8dd2f8288cad460c6c7db526bbdf578e96ca04d9fe12797 +b1705ea4cb7e074efe0405fc7b8ee2ec789af0426142f3ec81241cacd4f7edcd88e39435e4e4d8e7b1df64f3880d6613 +85595d061d677116089a6064418b93eb44ff79e68d12bd9625078d3bbc440a60d0b02944eff6054433ee34710ae6fbb4 +9978d5e30bedb7526734f9a1febd973a70bfa20890490e7cc6f2f9328feab1e24f991285dbc3711d892514e2d7d005ad +af30243c66ea43b9f87a061f947f7bce745f09194f6e95f379c7582b9fead920e5d6957eaf05c12ae1282ada4670652f +a1930efb473f88001e47aa0b2b2a7566848cccf295792e4544096ecd14ee5d7927c173a8576b405bfa2eec551cd67eb5 +b0446d1c590ee5a45f7e22d269c044f3848c97aec1d226b44bfd0e94d9729c28a38bccddc3a1006cc5fe4e3c24f001f2 +b8a8380172df3d84b06176df916cf557966d4f2f716d3e9437e415d75b646810f79f2b2b71d857181b7fc944018883a3 +a563afec25b7817bfa26e19dc9908bc00aa8fc3d19be7d6de23648701659009d10e3e4486c28e9c6b13d48231ae29ac5 +a5a8e80579de886fb7d6408f542791876885947b27ad6fa99a8a26e381f052598d7b4e647b0115d4b5c64297e00ce28e +8f87afcc7ad33c51ac719bade3cd92da671a37a82c14446b0a2073f4a0a23085e2c8d31913ed2d0be928f053297de8f6 +a43c455ce377e0bc434386c53c752880687e017b2f5ae7f8a15c044895b242dffde4c92fb8f8bb50b18470b17351b156 +8368f8b12a5bceb1dba25adb3a2e9c7dc9b1a77a1f328e5a693f5aec195cd1e06b0fe9476b554c1c25dac6c4a5b640a3 +919878b27f3671fc78396f11531c032f3e2bd132d04cc234fa4858676b15fb1db3051c0b1db9b4fc49038216f11321ce +b48cd67fb7f1242696c1f877da4bdf188eac676cd0e561fbac1a537f7b8229aff5a043922441d603a26aae56a15faee4 +a3e0fdfd4d29ea996517a16f0370b54787fefe543c2fe73bfc6f9e560c1fd30dad8409859e2d7fa2d44316f24746c712 +8bb156ade8faf149df7bea02c140c7e392a4742ae6d0394d880a849127943e6f26312033336d3b9fdc0092d71b5efe87 +8845e5d5cc555ca3e0523244300f2c8d7e4d02aaebcb5bd749d791208856c209a6f84dd99fd55968c9f0ab5f82916707 +a3e90bb5c97b07789c2f32dff1aec61d0a2220928202f5ad5355ae71f8249237799d6c8a22602e32e572cb12eabe0c17 +b150bcc391884c996149dc3779ce71f15dda63a759ee9cc05871f5a8379dcb62b047098922c0f26c7bd04deb394c33f9 +95cd4ad88d51f0f2efcfd0c2df802fe252bb9704d1afbf9c26a248df22d55da87bdfaf41d7bc6e5df38bd848f0b13f42 +a05a49a31e91dff6a52ac8b9c2cfdd646a43f0d488253f9e3cfbce52f26667166bbb9b608fc358763a65cbf066cd6d05 +a59c3c1227fdd7c2e81f5e11ef5c406da44662987bac33caed72314081e2eed66055d38137e01b2268e58ec85dd986c0 +b7020ec3bd73a99861f0f1d88cf5a19abab1cbe14b7de77c9868398c84bb8e18dbbe9831838a96b6d6ca06e82451c67b +98d1ff2525e9718ee59a21d8900621636fcd873d9a564b8dceb4be80a194a0148daf1232742730b3341514b2e5a5436c +886d97b635975fc638c1b6afc493e5998ca139edba131b75b65cfe5a8e814f11bb678e0eeee5e6e5cd913ad3f2fefdfc +8fb9fd928d38d5d813b671c924edd56601dd7163b686c13f158645c2f869d9250f3859aa5463a39258c90fef0f41190a +aac35e1cd655c94dec3580bb3800bd9c2946c4a9856f7d725af15fbea6a2d8ca51c8ad2772abed60ee0e3fb9cb24046b +b8d71fa0fa05ac9e443c9b4929df9e7f09a919be679692682e614d24227e04894bfc14a5c73a62fb927fedff4a0e4aa7 +a45a19f11fbbb531a704badbb813ed8088ab827c884ee4e4ebf363fa1132ff7cfa9d28be9c85b143e4f7cdbc94e7cf1a +82b54703a4f295f5471b255ab59dce00f0fe90c9fb6e06b9ee48b15c91d43f4e2ef4a96c3118aeb03b08767be58181bb +8283264c8e6d2a36558f0d145c18576b6600ff45ff99cc93eca54b6c6422993cf392668633e5df396b9331e873d457e5 +8c549c03131ead601bc30eb6b9537b5d3beb7472f5bb1bcbbfd1e9f3704477f7840ab3ab7f7dc13bbbbcdff886a462d4 +afbb0c520ac1b5486513587700ad53e314cb74bfbc12e0b5fbdcfdaac36d342e8b59856196a0d84a25cff6e6e1d17e76 +89e4c22ffb51f2829061b3c7c1983c5c750cad158e3a825d46f7cf875677da5d63f653d8a297022b5db5845c9271b32b +afb27a86c4c2373088c96b9adf4433f2ebfc78ac5c526e9f0510670b6e4e5e0057c0a4f75b185e1a30331b9e805c1c15 +a18e16b57445f88730fc5d3567bf5a176861dc14c7a08ed2996fe80eed27a0e7628501bcb78a1727c5e9ac55f29c12c4 +93d61bf88b192d6825cf4e1120af1c17aa0f994d158b405e25437eaeefae049f7b721a206e7cc8a04fdc29d3c42580a1 +a99f2995a2e3ed2fd1228d64166112038de2f516410aa439f4c507044e2017ea388604e2d0f7121256fadf7fbe7023d1 +914fd91cffc23c32f1c6d0e98bf660925090d873367d543034654389916f65f552e445b0300b71b61b721a72e9a5983c +b42a578a7787b71f924e7def425d849c1c777156b1d4170a8ee7709a4a914e816935131afd9a0412c4cb952957b20828 +82fb30590e84b9e45db1ec475a39971cf554dc01bcc7050bc89265740725c02e2be5a972168c5170c86ae83e5b0ad2c0 +b14f8d8e1e93a84976289e0cf0dfa6f3a1809e98da16ee5c4932d0e1ed6bf8a07697fdd4dd86a3df84fb0003353cdcc0 +85d7a2f4bda31aa2cb208b771fe03291a4ebdaf6f1dc944c27775af5caec412584c1f45bc741fca2a6a85acb3f26ad7d +af02e56ce886ff2253bc0a68faad76f25ead84b2144e5364f3fb9b648f03a50ee9dc0b2c33ebacf7c61e9e43201ef9ef +87e025558c8a0b0abd06dfc350016847ea5ced7af2d135a5c9eec9324a4858c4b21510fb0992ec52a73447f24945058e +80fff0bafcd058118f5e7a4d4f1ae0912efeb281d2cbe4d34ba8945cc3dbe5d8baf47fb077343b90b8d895c90b297aca +b6edcf3a40e7b1c3c0148f47a263cd819e585a51ef31c2e35a29ce6f04c53e413f743034c0d998d9c00a08ba00166f31 +abb87ed86098c0c70a76e557262a494ff51a30fb193f1c1a32f8e35eafa34a43fcc07aa93a3b7a077d9e35afa07b1a3d +a280214cd3bb0fb7ecd2d8bcf518cbd9078417f2b91d2533ec2717563f090fb84f2a5fcfdbbeb2a2a1f8a71cc5aa5941 +a63083ca7238ea2b57d15a475963cf1d4f550d8cd76db290014a0461b90351f1f26a67d674c837b0b773b330c7c3d534 +a8fa39064cb585ece5263e2f42f430206476bf261bd50f18d2b694889bd79d04d56410664cecad62690e5c5a20b3f6ff +85ba52ce9d700a5dcf6c5b00559acbe599d671ce5512467ff4b6179d7fad550567ce2a9c126a50964e3096458ea87920 +b913501e1008f076e5eac6d883105174f88b248e1c9801e568fefaffa1558e4909364fc6d9512aa4d125cbd7cc895f05 +8eb33b5266c8f2ed4725a6ad147a322e44c9264cf261c933cbbe230a43d47fca0f29ec39756b20561dabafadd5796494 +850ebc8b661a04318c9db5a0515066e6454fa73865aa4908767a837857ecd717387f614acb614a88e075d4edc53a2f5a +a08d6b92d866270f29f4ce23a3f5d99b36b1e241a01271ede02817c8ec3f552a5c562db400766c07b104a331835c0c64 +8131804c89bb3e74e9718bfc4afa547c1005ff676bd4db9604335032b203390cfa54478d45c6c78d1fe31a436ed4be9f +9106d94f23cc1eacec8316f16d6f0a1cc160967c886f51981fdb9f3f12ee1182407d2bb24e5b873de58cb1a3ee915a6b +a13806bfc3eae7a7000c9d9f1bd25e10218d4e67f59ae798b145b098bca3edad2b1040e3fc1e6310e612fb8818f459ac +8c69fbca502046cb5f6db99900a47b34117aef3f4b241690cdb3b84ca2a2fc7833e149361995dc41fa78892525bce746 +852c473150c91912d58ecb05769222fa18312800c3f56605ad29eec9e2d8667b0b81c379048d3d29100ed2773bb1f3c5 +b1767f6074426a00e01095dbb1795beb4e4050c6411792cbad6537bc444c3165d1058bafd1487451f9c5ddd209e0ae7e +80c600a5fe99354ce59ff0f84c760923dc8ff66a30bf47dc0a086181785ceb01f9b951c4e66df800ea6d705e8bc47055 +b5cf19002fbc88a0764865b82afcb4d64a50196ea361e5c71dff7de084f4dcbbc34ec94a45cc9e0247bd51da565981aa +93e67a254ea8ce25e112d93cc927fadaa814152a2c4ec7d9a56eaa1ed47aec99b7e9916b02e64452cc724a6641729bbb +ace70b32491bda18eee4a4d041c3bc9effae9340fe7e6c2f5ad975ee0874c17f1a7da7c96bd85fccff9312c518fac6e9 +ab4cfa02065017dd7f1aadc66f2c92f78f0f11b8597c03a5d69d82cb2eaf95a4476a836ac102908f137662472c8d914b +a40b8cd8deb8ae503d20364d64cab7c2801b7728a9646ed19c65edea6a842756a2f636283494299584ad57f4bb12cd0b +8594e11d5fc2396bcd9dbf5509ce4816dbb2b7305168021c426171fb444d111da5a152d6835ad8034542277011c26c0e +8024de98c26b4c994a66628dc304bb737f4b6859c86ded552c5abb81fd4c6c2e19d5a30beed398a694b9b2fdea1dd06a +8843f5872f33f54df8d0e06166c1857d733995f67bc54abb8dfa94ad92407cf0179bc91b0a50bbb56cdc2b350d950329 +b8bab44c7dd53ef9edf497dcb228e2a41282c90f00ba052fc52d57e87b5c8ab132d227af1fcdff9a12713d1f980bcaae +982b4d7b29aff22d527fd82d2a52601d95549bfb000429bb20789ed45e5abf1f4b7416c7b7c4b79431eb3574b29be658 +8eb1f571b6a1878e11e8c1c757e0bc084bab5e82e897ca9be9b7f4b47b91679a8190bf0fc8f799d9b487da5442415857 +a6e74b588e5af935c8b243e888582ef7718f8714569dd4992920740227518305eb35fab674d21a5551cca44b3e511ef2 +a30fc2f3a4cb4f50566e82307de73cd7bd8fe2c1184e9293c136a9b9e926a018d57c6e4f308c95b9eb8299e94d90a2a1 +a50c5869ca5d2b40722c056a32f918d47e0b65ca9d7863ca7d2fb4a7b64fe523fe9365cf0573733ceaadebf20b48fff8 +83bbdd32c04d17581418cf360749c7a169b55d54f2427390defd9f751f100897b2d800ce6636c5bbc046c47508d60c8c +a82904bdf614de5d8deaff688c8a5e7ac5b3431687acbcda8fa53960b7c417a39c8b2e462d7af91ce6d79260f412db8e +a4362e31ff4b05d278b033cf5eebea20de01714ae16d4115d04c1da4754269873afc8171a6f56c5104bfd7b0db93c3e7 +b5b8daa63a3735581e74a021b684a1038cea77168fdb7fdf83c670c2cfabcfc3ab2fc7359069b5f9048188351aef26b5 +b48d723894b7782d96ac8433c48faca1bdfa5238019c451a7f47d958097cce3ae599b876cf274269236b9d6ff8b6d7ca +98ffff6a61a3a6205c7820a91ca2e7176fab5dba02bc194c4d14942ac421cb254183c705506ab279e4f8db066f941c6c +ae7db24731da2eaa6efc4f7fcba2ecc26940ddd68038dce43acf2cee15b72dc4ef42a7bfdd32946d1ed78786dd7696b3 +a656db14f1de9a7eb84f6301b4acb2fbf78bfe867f48a270e416c974ab92821eb4df1cb881b2d600cfed0034ac784641 +aa315f8ecba85a5535e9a49e558b15f39520fce5d4bf43131bfbf2e2c9dfccc829074f9083e8d49f405fb221d0bc4c3c +90bffba5d9ff40a62f6c8e9fc402d5b95f6077ed58d030c93e321b8081b77d6b8dac3f63a92a7ddc01585cf2c127d66c +abdd733a36e0e0f05a570d0504e73801bf9b5a25ff2c78786f8b805704997acb2e6069af342538c581144d53149fa6d3 +b4a723bb19e8c18a01bd449b1bb3440ddb2017f10bb153da27deb7a6a60e9bb37619d6d5435fbb1ba617687838e01dd0 +870016b4678bab3375516db0187a2108b2e840bae4d264b9f4f27dbbc7cc9cac1d7dc582d7a04d6fd1ed588238e5e513 +80d33d2e20e8fc170aa3cb4f69fffb72aeafb3b5bb4ea0bc79ab55da14142ca19b2d8b617a6b24d537366e3b49cb67c3 +a7ee76aec273aaae03b3b87015789289551969fb175c11557da3ab77e39ab49d24634726f92affae9f4d24003050d974 +8415ea4ab69d779ebd42d0fe0c6aef531d6a465a5739e429b1fcf433ec45aa8296c527e965a20f0ec9f340c9273ea3cf +8c7662520794e8b4405d0b33b5cac839784bc86a5868766c06cbc1fa306dbe334978177417b31baf90ce7b0052a29c56 +902b2abecc053a3dbdea9897ee21e74821f3a1b98b2d560a514a35799f4680322550fd3a728d4f6d64e1de98033c32b8 +a05e84ed9ecab8d508d670c39f2db61ad6e08d2795ec32a3c9d0d3737ef3801618f4fc2a95f90ec2f068606131e076c5 +8b9208ff4d5af0c2e3f53c9375da666773ac57197dfabb0d25b1c8d0588ba7f3c15ee9661bb001297f322ea2fbf6928b +a3c827741b34a03254d4451b5ab74a96f2b9f7fb069e2f5adaf54fd97cc7a4d516d378db5ca07da87d8566d6eef13726 +8509d8a3f4a0ed378e0a1e28ea02f6bf1d7f6c819c6c2f5297c7df54c895b848f841653e32ba2a2c22c2ff739571acb8 +a0ce988b7d3c40b4e496aa83a09e4b5472a2d98679622f32bea23e6d607bc7de1a5374fb162bce0549a67dad948519be +aa8a3dd12bd60e3d2e05f9c683cdcb8eab17fc59134815f8d197681b1bcf65108cba63ac5c58ee632b1e5ed6bba5d474 +8b955f1d894b3aefd883fb4b65f14cd37fc2b9db77db79273f1700bef9973bf3fd123897ea2b7989f50003733f8f7f21 +ac79c00ddac47f5daf8d9418d798d8af89fc6f1682e7e451f71ea3a405b0d36af35388dd2a332af790bc83ca7b819328 +a0d44dd2a4438b809522b130d0938c3fe7c5c46379365dbd1810a170a9aa5818e1c783470dd5d0b6d4ac7edbb7330910 +a30b69e39ad43dd540a43c521f05b51b5f1b9c4eed54b8162374ae11eac25da4f5756e7b70ce9f3c92c2eeceee7431ed +ac43220b762c299c7951222ea19761ab938bf38e4972deef58ed84f4f9c68c230647cf7506d7cbfc08562fcca55f0485 +b28233b46a8fb424cfa386a845a3b5399d8489ceb83c8f3e05c22c934798d639c93718b7b68ab3ce24c5358339e41cbb +ac30d50ee8ce59a10d4b37a3a35e62cdb2273e5e52232e202ca7d7b8d09d28958ee667fae41a7bb6cdc6fe8f6e6c9c85 +b199842d9141ad169f35cc7ff782b274cbaa645fdb727761e0a89edbf0d781a15f8218b4bf4eead326f2903dd88a9cc1 +85e018c7ddcad34bb8285a737c578bf741ccd547e68c734bdb3808380e12c5d4ef60fc896b497a87d443ff9abd063b38 +8c856e6ba4a815bdb891e1276f93545b7072f6cb1a9aa6aa5cf240976f29f4dee01878638500a6bf1daf677b96b54343 +b8a47555fa8710534150e1a3f13eab33666017be6b41005397afa647ea49708565f2b86b77ad4964d140d9ced6b4d585 +8cd1f1db1b2f4c85a3f46211599caf512d5439e2d8e184663d7d50166fd3008f0e9253272f898d81007988435f715881 +b1f34b14612c973a3eceb716dc102b82ab18afef9de7630172c2780776679a7706a4874e1df3eaadf541fb009731807f +b25464af9cff883b55be2ff8daf610052c02df9a5e147a2cf4df6ce63edcdee6dc535c533590084cc177da85c5dc0baa +91c3c4b658b42d8d3448ae1415d4541d02379a40dc51e36a59bd6e7b9ba3ea51533f480c7c6e8405250ee9b96a466c29 +86dc027b95deb74c36a58a1333a03e63cb5ae22d3b29d114cfd2271badb05268c9d0c819a977f5e0c6014b00c1512e3a +ae0e6ff58eb5fa35da5107ebeacf222ab8f52a22bb1e13504247c1dfa65320f40d97b0e6b201cb6613476687cb2f0681 +8f13415d960b9d7a1d93ef28afc2223e926639b63bdefce0f85e945dfc81670a55df288893a0d8b3abe13c5708f82f91 +956f67ca49ad27c1e3a68c1faad5e7baf0160c459094bf6b7baf36b112de935fdfd79fa4a9ea87ea8de0ac07272969f4 +835e45e4a67df9fb51b645d37840b3a15c171d571a10b03a406dd69d3c2f22df3aa9c5cbe1e73f8d767ce01c4914ea9a +919b938e56d4b32e2667469d0bdccb95d9dda3341aa907683ee70a14bbbe623035014511c261f4f59b318b610ac90aa3 +96b48182121ccd9d689bf1dfdc228175564cd68dc904a99c808a7f0053a6f636c9d953e12198bdf2ea49ea92772f2e18 +ac5e5a941d567fa38fdbcfa8cf7f85bb304e3401c52d88752bcd516d1fa9bac4572534ea2205e38423c1df065990790f +ac0bd594fb85a8d4fc26d6df0fa81f11919401f1ecf9168b891ec7f061a2d9368af99f7fd8d9b43b2ce361e7b8482159 +83d92c69ca540d298fe80d8162a1c7af3fa9b49dfb69e85c1d136a3ec39fe419c9fa78e0bb6d96878771fbd37fe92e40 +b35443ae8aa66c763c2db9273f908552fe458e96696b90e41dd509c17a5c04ee178e3490d9c6ba2dc0b8f793c433c134 +923b2d25aa45b2e580ffd94cbb37dc8110f340f0f011217ee1bd81afb0714c0b1d5fb4db86006cdd2457563276f59c59 +96c9125d38fca1a61ac21257b696f8ac3dae78def50285e44d90ea293d591d1c58f703540a7e4e99e070afe4646bbe15 +b57946b2332077fbcdcb406b811779aefd54473b5559a163cd65cb8310679b7e2028aa55c12a1401fdcfcac0e6fae29a +845daedc5cf972883835d7e13c937b63753c2200324a3b8082a6c4abb4be06c5f7c629d4abe4bfaf1d80a1f073eb6ce6 +91a55dfd0efefcd03dc6dacc64ec93b8d296cb83c0ee72400a36f27246e7f2a60e73b7b70ba65819e9cfb73edb7bd297 +8874606b93266455fe8fdd25df9f8d2994e927460af06f2e97dd4d2d90db1e6b06d441b72c2e76504d753badca87fb37 +8ee99e6d231274ff9252c0f4e84549da173041299ad1230929c3e3d32399731c4f20a502b4a307642cac9306ccd49d3c +8836497714a525118e20849d6933bb8535fb6f72b96337d49e3133d936999c90a398a740f42e772353b5f1c63581df6d +a6916945e10628f7497a6cdc5e2de113d25f7ade3e41e74d3de48ccd4fce9f2fa9ab69645275002e6f49399b798c40af +9597706983107eb23883e0812e1a2c58af7f3499d50c6e29b455946cb9812fde1aa323d9ed30d1c0ffd455abe32303cd +a24ee89f7f515cc33bdbdb822e7d5c1877d337f3b2162303cfc2dae028011c3a267c5cb4194afa63a4856a6e1c213448 +8cd25315e4318801c2776824ae6e7d543cb85ed3bc2498ba5752df2e8142b37653cf9e60104d674be3aeb0a66912e97a +b5085ecbe793180b40dbeb879f4c976eaaccaca3a5246807dced5890e0ed24d35f3f86955e2460e14fb44ff5081c07ba +960188cc0b4f908633a6840963a6fa2205fc42c511c6c309685234911c5304ef4c304e3ae9c9c69daa2fb6a73560c256 +a32d0a70bf15d569b4cda5aebe3e41e03c28bf99cdd34ffa6c5d58a097f322772acca904b3a47addb6c7492a7126ebac +977f72d06ad72d4aa4765e0f1f9f4a3231d9f030501f320fe7714cc5d329d08112789fa918c60dd7fdb5837d56bb7fc6 +99fa038bb0470d45852bb871620d8d88520adb701712fcb1f278fed2882722b9e729e6cdce44c82caafad95e37d0e6f7 +b855e8f4fc7634ada07e83b6c719a1e37acb06394bc8c7dcab7747a8c54e5df3943915f021364bd019fdea103864e55f +88bc2cd7458532e98c596ef59ea2cf640d7cc31b4c33cef9ed065c078d1d4eb49677a67de8e6229cc17ea48bace8ee5a +aaa78a3feaa836d944d987d813f9b9741afb076e6aca1ffa42682ab06d46d66e0c07b8f40b9dbd63e75e81efa1ef7b08 +b7b080420cc4d808723b98b2a5b7b59c81e624ab568ecdfdeb8bf3aa151a581b6f56e983ef1b6f909661e25db40b0c69 +abee85c462ac9a2c58e54f06c91b3e5cd8c5f9ab5b5deb602b53763c54826ed6deb0d6db315a8d7ad88733407e8d35e2 +994d075c1527407547590df53e9d72dd31f037c763848d1662eebd4cefec93a24328c986802efa80e038cb760a5300f5 +ab8777640116dfb6678e8c7d5b36d01265dfb16321abbfc277da71556a34bb3be04bc4ae90124ed9c55386d2bfb3bda0 +967e3a828bc59409144463bcf883a3a276b5f24bf3cbfdd7a42343348cba91e00b46ac285835a9b91eef171202974204 +875a9f0c4ffe5bb1d8da5e3c8e41d0397aa6248422a628bd60bfae536a651417d4e8a7d2fb98e13f2dad3680f7bd86d3 +acaa330c3e8f95d46b1880126572b238dbb6d04484d2cd4f257ab9642d8c9fc7b212188b9c7ac9e0fd135c520d46b1bf +aceb762edbb0f0c43dfcdb01ea7a1ac5918ca3882b1e7ebc4373521742f1ed5250d8966b498c00b2b0f4d13212e6dd0b +81d072b4ad258b3646f52f399bced97c613b22e7ad76373453d80b1650c0ca87edb291a041f8253b649b6e5429bb4cff +980a47d27416ac39c7c3a0ebe50c492f8c776ea1de44d5159ac7d889b6d554357f0a77f0e5d9d0ff41aae4369eba1fc2 +8b4dfd5ef5573db1476d5e43aacfb5941e45d6297794508f29c454fe50ea622e6f068b28b3debe8635cf6036007de2e3 +a60831559d6305839515b68f8c3bc7abbd8212cc4083502e19dd682d56ca37c9780fc3ce4ec2eae81ab23b221452dc57 +951f6b2c1848ced9e8a2339c65918e00d3d22d3e59a0a660b1eca667d18f8430d737884e9805865ef3ed0fe1638a22d9 +b02e38fe790b492aa5e89257c4986c9033a8b67010fa2add9787de857d53759170fdd67715ca658220b4e14b0ca48124 +a51007e4346060746e6b0e4797fc08ef17f04a34fe24f307f6b6817edbb8ce2b176f40771d4ae8a60d6152cbebe62653 +a510005b05c0b305075b27b243c9d64bcdce85146b6ed0e75a3178b5ff9608213f08c8c9246f2ca6035a0c3e31619860 +aaff4ef27a7a23be3419d22197e13676d6e3810ceb06a9e920d38125745dc68a930f1741c9c2d9d5c875968e30f34ab5 +864522a9af9857de9814e61383bebad1ba9a881696925a0ea6bfc6eff520d42c506bbe5685a9946ed710e889765be4a0 +b63258c080d13f3b7d5b9f3ca9929f8982a6960bdb1b0f8676f4dca823971601672f15e653917bf5d3746bb220504913 +b51ce0cb10869121ae310c7159ee1f3e3a9f8ad498827f72c3d56864808c1f21fa2881788f19ece884d3f705cd7bd0c5 +95d9cecfc018c6ed510e441cf84c712d9909c778c16734706c93222257f64dcd2a9f1bd0b400ca271e22c9c487014274 +8beff4d7d0140b86380ff4842a9bda94c2d2be638e20ac68a4912cb47dbe01a261857536375208040c0554929ced1ddc +891ff49258749e2b57c1e9b8e04b12c77d79c3308b1fb615a081f2aacdfb4b39e32d53e069ed136fdbd43c53b87418fa +9625cad224e163d387738825982d1e40eeff35fe816d10d7541d15fdc4d3eee48009090f3faef4024b249205b0b28f72 +8f3947433d9bd01aa335895484b540a9025a19481a1c40b4f72dd676bfcf332713714fd4010bde936eaf9470fd239ed0 +a00ec2d67789a7054b53f0e858a8a232706ccc29a9f3e389df7455f1a51a2e75801fd78469a13dbc25d28399ae4c6182 +a3f65884506d4a62b8775a0ea0e3d78f5f46bc07910a93cd604022154eabdf1d73591e304d61edc869e91462951975e1 +a14eef4fd5dfac311713f0faa9a60415e3d30b95a4590cbf95f2033dffb4d16c02e7ceff3dcd42148a4e3bc49cce2dd4 +8afa11c0eef3c540e1e3460bc759bb2b6ea90743623f88e62950c94e370fe4fd01c22b6729beba4dcd4d581198d9358f +afb05548a69f0845ffcc5f5dc63e3cdb93cd270f5655173b9a950394b0583663f2b7164ba6df8d60c2e775c1d9f120af +97f179e01a947a906e1cbeafa083960bc9f1bade45742a3afee488dfb6011c1c6e2db09a355d77f5228a42ccaa7bdf8e +8447fca4d35f74b3efcbd96774f41874ca376bf85b79b6e66c92fa3f14bdd6e743a051f12a7fbfd87f319d1c6a5ce217 +a57ca39c23617cd2cf32ff93b02161bd7baf52c4effb4679d9d5166406e103bc8f3c6b5209e17c37dbb02deb8bc72ddd +9667c7300ff80f0140be002b0e36caab07aaee7cce72679197c64d355e20d96196acaf54e06e1382167d081fe6f739c1 +828126bb0559ce748809b622677267ca896fa2ee76360fd2c02990e6477e06a667241379ca7e65d61a5b64b96d7867de +8b8835dea6ba8cf61c91f01a4b3d2f8150b687a4ee09b45f2e5fc8f80f208ae5d142d8e3a18153f0722b90214e60c5a7 +a98e8ff02049b4da386e3ee93db23bbb13dfeb72f1cfde72587c7e6d962780b7671c63e8ac3fbaeb1a6605e8d79e2f29 +87a4892a0026d7e39ef3af632172b88337cb03669dea564bcdb70653b52d744730ebb5d642e20cb627acc9dbb547a26b +877352a22fc8052878a57effc159dac4d75fe08c84d3d5324c0bab6d564cdf868f33ceee515eee747e5856b62cfa0cc7 +8b801ba8e2ff019ee62f64b8cb8a5f601fc35423eb0f9494b401050103e1307dc584e4e4b21249cd2c686e32475e96c3 +a9e7338d6d4d9bfec91b2af28a8ed13b09415f57a3a00e5e777c93d768fdb3f8e4456ae48a2c6626b264226e911a0e28 +99c05fedf40ac4726ed585d7c1544c6e79619a0d3fb6bda75a08c7f3c0008e8d5e19ed4da48de3216135f34a15eba17c +a61cce8a1a8b13a4a650fdbec0eeea8297c352a8238fb7cac95a0df18ed16ee02a3daa2de108fa122aca733bd8ad7855 +b97f37da9005b440b4cb05870dd881bf8491fe735844f2d5c8281818583b38e02286e653d9f2e7fa5e74c3c3eb616540 +a72164a8554da8e103f692ac5ebb4aece55d5194302b9f74b6f2a05335b6e39beede0bf7bf8c5bfd4d324a784c5fb08c +b87e8221c5341cd9cc8bb99c10fe730bc105550f25ed4b96c0d45e6142193a1b2e72f1b3857373a659b8c09be17b3d91 +a41fb1f327ef91dcb7ac0787918376584890dd9a9675c297c45796e32d6e5985b12f9b80be47fc3a8596c245f419d395 +90dafa3592bdbb3465c92e2a54c2531822ba0459d45d3e7a7092fa6b823f55af28357cb51896d4ec2d66029c82f08e26 +a0a9adc872ebc396557f484f1dd21954d4f4a21c4aa5eec543f5fa386fe590839735c01f236574f7ff95407cd12de103 +b8c5c940d58be7538acf8672852b5da3af34f82405ef2ce8e4c923f1362f97fc50921568d0fd2fe846edfb0823e62979 +85aaf06a8b2d0dac89dafd00c28533f35dbd074978c2aaa5bef75db44a7b12aeb222e724f395513b9a535809a275e30b +81f3cbe82fbc7028c26a6c1808c604c63ba023a30c9f78a4c581340008dbda5ec07497ee849a2183fcd9124f7936af32 +a11ac738de75fd60f15a34209d3825d5e23385796a4c7fc5931822f3f380af977dd0f7b59fbd58eed7777a071e21b680 +85a279c493de03db6fa6c3e3c1b1b29adc9a8c4effc12400ae1128da8421954fa8b75ad19e5388fe4543b76fb0812813 +83a217b395d59ab20db6c4adb1e9713fc9267f5f31a6c936042fe051ce8b541f579442f3dcf0fa16b9e6de9fd3518191 +83a0b86e7d4ed8f9ccdc6dfc8ff1484509a6378fa6f09ed908e6ab9d1073f03011dc497e14304e4e3d181b57de06a5ab +a63ad69c9d25704ce1cc8e74f67818e5ed985f8f851afa8412248b2df5f833f83b95b27180e9e7273833ed0d07113d3b +99b1bc2021e63b561fe44ddd0af81fcc8627a91bfeecbbc989b642bc859abc0c8d636399701aad7bbaf6a385d5f27d61 +b53434adb66f4a807a6ad917c6e856321753e559b1add70824e5c1e88191bf6993fccb9b8b911fc0f473fb11743acacd +97ed3b9e6fb99bf5f945d4a41f198161294866aa23f2327818cdd55cb5dc4c1a8eff29dd8b8d04902d6cd43a71835c82 +b1e808260e368a18d9d10bdea5d60223ba1713b948c782285a27a99ae50cc5fc2c53d407de07155ecc16fb8a36d744a0 +a3eb4665f18f71833fec43802730e56b3ee5a357ea30a888ad482725b169d6f1f6ade6e208ee081b2e2633079b82ba7d +ab8beb2c8353fc9f571c18fdd02bdb977fc883313469e1277b0372fbbb33b80dcff354ca41de436d98d2ed710faa467e +aa9071cfa971e4a335a91ad634c98f2be51544cb21f040f2471d01bb97e1df2277ae1646e1ea8f55b7ba9f5c8c599b39 +80b7dbfdcaf40f0678012acc634eba44ea51181475180d9deb2050dc4f2de395289edd0223018c81057ec79b04b04c49 +89623d7f6cb17aa877af14de842c2d4ab7fd576d61ddd7518b5878620a01ded40b6010de0da3cdf31d837eecf30e9847 +a773bb024ae74dd24761f266d4fb27d6fd366a8634febe8235376b1ae9065c2fe12c769f1d0407867dfbe9f5272c352f +8455a561c3aaa6ba64c881a5e13921c592b3a02e968f4fb24a2243c36202795d0366d9cc1a24e916f84d6e158b7aeac7 +81d8bfc4b283cf702a40b87a2b96b275bdbf0def17e67d04842598610b67ea08c804d400c3e69fa09ea001eaf345b276 +b8f8f82cb11fea1c99467013d7e167ff03deb0c65a677fab76ded58826d1ba29aa7cf9fcd7763615735ea3ad38e28719 +89a6a04baf9cccc1db55179e1650b1a195dd91fb0aebc197a25143f0f393524d2589975e3fbfc2547126f0bced7fd6f2 +b81b2162df045390f04df07cbd0962e6b6ca94275a63edded58001a2f28b2ae2af2c7a6cba4ecd753869684e77e7e799 +a3757f722776e50de45c62d9c4a2ee0f5655a512344c4cbec542d8045332806568dd626a719ef21a4eb06792ca70f204 +8c5590df96ec22179a4e8786de41beb44f987a1dcc508eb341eecbc0b39236fdfad47f108f852e87179ccf4e10091e59 +87502f026ed4e10167419130b88c3737635c5b9074c364e1dd247cef5ef0fc064b4ae99b187e33301e438bbd2fe7d032 +af925a2165e980ced620ff12289129fe17670a90ae0f4db9d4b39bd887ccb1f5d2514ac9ecf910f6390a8fc66bd5be17 +857fca899828cf5c65d26e3e8a6e658542782fc72762b3b9c73514919f83259e0f849a9d4838b40dc905fe43024d0d23 +87ffebdbfb69a9e1007ebac4ffcb4090ff13705967b73937063719aa97908986effcb7262fdadc1ae0f95c3690e3245d +a9ff6c347ac6f4c6ab993b748802e96982eaf489dc69032269568412fc9a79e7c2850dfc991b28211b3522ee4454344b +a65b3159df4ec48bebb67cb3663cd744027ad98d970d620e05bf6c48f230fa45bf17527fe726fdf705419bb7a1bb913e +84b97b1e6408b6791831997b03cd91f027e7660fd492a93d95daafe61f02427371c0e237c75706412f442991dfdff989 +ab761c26527439b209af0ae6afccd9340bbed5fbe098734c3145b76c5d2cd7115d9227b2eb523882b7317fbb09180498 +a0479a8da06d7a69c0b0fee60df4e691c19c551f5e7da286dab430bfbcabf31726508e20d26ea48c53365a7f00a3ad34 +a732dfc9baa0f4f40b5756d2e8d8937742999623477458e0bc81431a7b633eefc6f53b3b7939fe0a020018549c954054 +901502436a1169ba51dc479a5abe7c8d84e0943b16bc3c6a627b49b92cd46263c0005bc324c67509edd693f28e612af1 +b627aee83474e7f84d1bab9b7f6b605e33b26297ac6bbf52d110d38ba10749032bd551641e73a383a303882367af429b +95108866745760baef4a46ef56f82da6de7e81c58b10126ebd2ba2cd13d339f91303bf2fb4dd104a6956aa3b13739503 +899ed2ade37236cec90056f3569bc50f984f2247792defafcceb49ad0ca5f6f8a2f06573705300e07f0de0c759289ff5 +a9f5eee196d608efe4bcef9bf71c646d27feb615e21252cf839a44a49fd89da8d26a758419e0085a05b1d59600e2dc42 +b36c6f68fed6e6c85f1f4a162485f24817f2843ec5cbee45a1ebfa367d44892e464949c6669f7972dc7167af08d55d25 +aaaede243a9a1b6162afbc8f571a52671a5a4519b4062e3f26777664e245ba873ed13b0492c5dbf0258c788c397a0e9e +972b4fb39c31cbe127bf9a32a5cc10d621ebdd9411df5e5da3d457f03b2ab2cd1f6372d8284a4a9400f0b06ecdbfd38e +8f6ca1e110e959a4b1d9a5ce5f212893cec21db40d64d5ac4d524f352d72198f923416a850bf845bc5a22a79c0ea2619 +a0f3c93b22134f66f04b2553a53b738644d1665ceb196b8494b315a4c28236fb492017e4a0de4224827c78e42f9908b7 +807fb5ee74f6c8735b0b5ca07e28506214fe4047dbeb00045d7c24f7849e98706aea79771241224939cb749cf1366c7d +915eb1ff034224c0b645442cdb7d669303fdc00ca464f91aaf0b6fde0b220a3a74ff0cb043c26c9f3a5667b3fdaa9420 +8fda6cef56ed33fefffa9e6ac8e6f76b1af379f89761945c63dd448801f7bb8ca970504a7105fac2f74f652ccff32327 +87380cffdcffb1d0820fa36b63cc081e72187f86d487315177d4d04da4533eb19a0e2ff6115ceab528887819c44a5164 +8cd89e03411a18e7f16f968b89fb500c36d47d229f6487b99e62403a980058db5925ce249206743333538adfad168330 +974451b1df33522ce7056de9f03e10c70bf302c44b0741a59df3d6877d53d61a7394dcee1dd46e013d7cb9d73419c092 +98c35ddf645940260c490f384a49496a7352bb8e3f686feed815b1d38f59ded17b1ad6e84a209e773ed08f7b8ff1e4c2 +963f386cf944bb9b2ddebb97171b64253ea0a2894ac40049bdd86cda392292315f3a3d490ca5d9628c890cfb669f0acb +8d507712152babd6d142ee682638da8495a6f3838136088df9424ef50d5ec28d815a198c9a4963610b22e49b4cdf95e9 +83d4bc6b0be87c8a4f1e9c53f257719de0c73d85b490a41f7420e777311640937320557ff2f1d9bafd1daaa54f932356 +82f5381c965b7a0718441131c4d13999f4cdce637698989a17ed97c8ea2e5bdb5d07719c5f7be8688edb081b23ede0f4 +a6ebecab0b72a49dfd01d69fa37a7f74d34fb1d4fef0aa10e3d6fceb9eccd671225c230af89f6eb514250e41a5f91f52 +846d185bdad6e11e604df7f753b7a08a28b643674221f0e750ebdb6b86ec584a29c869e131bca868972a507e61403f6a +85a98332292acb744bd1c0fd6fdcf1f889a78a2c9624d79413ffa194cc8dfa7821a4b60cde8081d4b5f71f51168dd67f +8f7d97c3b4597880d73200d074eb813d95432306e82dafc70b580b8e08cb8098b70f2d07b4b3ac6a4d77e92d57035031 +8185439c8751e595825d7053518cbe121f191846a38d4dbcb558c3f9d7a3104f3153401adaaaf27843bbe2edb504bfe3 +b3c00d8ece1518fca6b1215a139b0a0e26d9cba1b3a424f7ee59f30ce800a5db967279ed60958dd1f3ee69cf4dd1b204 +a2e6cb6978e883f9719c3c0d44cfe8de0cc6f644b98f98858433bea8bbe7b612c8aca5952fccce4f195f9d54f9722dc2 +99663087e3d5000abbec0fbda4e7342ec38846cc6a1505191fb3f1a337cb369455b7f8531a6eb8b0f7b2c4baf83cbe2b +ab0836c6377a4dbc7ca6a4d6cf021d4cd60013877314dd05f351706b128d4af6337711ed3443cb6ca976f40d74070a9a +87abfd5126152fd3bac3c56230579b489436755ea89e0566aa349490b36a5d7b85028e9fb0710907042bcde6a6f5d7e3 +974ba1033f75f60e0cf7c718a57ae1da3721cf9d0fb925714c46f027632bdd84cd9e6de4cf4d00bc55465b1c5ebb7384 +a607b49d73689ac64f25cec71221d30d53e781e1100d19a2114a21da6507a60166166369d860bd314acb226596525670 +a7c2b0b915d7beba94954f2aa7dd08ec075813661e2a3ecca5d28a0733e59583247fed9528eb28aba55b972cdbaf06eb +b8b3123e44128cc8efbe3270f2f94e50ca214a4294c71c3b851f8cbb70cb67fe9536cf07d04bf7fe380e5e3a29dd3c15 +a59a07e343b62ad6445a0859a32b58c21a593f9ddbfe52049650f59628c93715aa1f4e1f45b109321756d0eeec8a5429 +94f51f8a4ed18a6030d0aaa8899056744bd0e9dc9ac68f62b00355cddab11da5da16798db75f0bfbce0e5bdfe750c0b6 +97460a97ca1e1fa5ce243b81425edc0ec19b7448e93f0b55bc9785eedeeafe194a3c8b33a61a5c72990edf375f122777 +8fa859a089bc17d698a7ee381f37ce9beadf4e5b44fce5f6f29762bc04f96faff5d58c48c73631290325f05e9a1ecf49 +abdf38f3b20fc95eff31de5aa9ef1031abfa48f1305ee57e4d507594570401503476d3bcc493838fc24d6967a3082c7f +b8914bfb82815abb86da35c64d39ab838581bc0bf08967192697d9663877825f2b9d6fbdcf9b410463482b3731361aef +a8187f9d22b193a5f578999954d6ec9aa9b32338ccadb8a3e1ce5bad5ea361d69016e1cdfac44e9d6c54e49dd88561b9 +aac262cb7cba7fd62c14daa7b39677cabc1ef0947dd06dd89cac8570006a200f90d5f0353e84f5ff03179e3bebe14231 +a630ef5ece9733b8c46c0a2df14a0f37647a85e69c63148e79ffdcc145707053f9f9d305c3f1cf3c7915cb46d33abd07 +b102c237cb2e254588b6d53350dfda6901bd99493a3fbddb4121d45e0b475cf2663a40d7b9a75325eda83e4ba1e68cb3 +86a930dd1ddcc16d1dfa00aa292cb6c2607d42c367e470aa920964b7c17ab6232a7108d1c2c11fc40fb7496547d0bbf8 +a832fdc4500683e72a96cce61e62ac9ee812c37fe03527ad4cf893915ca1962cee80e72d4f82b20c8fc0b764376635a1 +88ad985f448dabb04f8808efd90f273f11f5e6d0468b5489a1a6a3d77de342992a73eb842d419034968d733f101ff683 +98a8538145f0d86f7fbf9a81c9140f6095c5bdd8960b1c6f3a1716428cd9cca1bf8322e6d0af24e6169abcf7df2b0ff6 +9048c6eba5e062519011e177e955a200b2c00b3a0b8615bdecdebc217559d41058d3315f6d05617be531ef0f6aef0e51 +833bf225ab6fc68cdcacf1ec1b50f9d05f5410e6cdcd8d56a3081dc2be8a8d07b81534d1ec93a25c2e270313dfb99e3b +a84bcd24c3da5e537e64a811b93c91bfc84d7729b9ead7f79078989a6eb76717d620c1fad17466a0519208651e92f5ff +b7cdd0a3fbd79aed93e1b5a44ca44a94e7af5ed911e4492f332e3a5ed146c7286bde01b52276a2fcc02780d2109874dd +8a19a09854e627cb95750d83c20c67442b66b35896a476358f993ba9ac114d32c59c1b3d0b8787ee3224cf3888b56c64 +a9abd5afb8659ee52ada8fa5d57e7dd355f0a7350276f6160bec5fbf70d5f99234dd179eb221c913e22a49ec6d267846 +8c13c4274c0d30d184e73eaf812200094bbbd57293780bdadbceb262e34dee5b453991e7f37c7333a654fc71c69d6445 +a4320d73296ff8176ce0127ca1921c450e2a9c06eff936681ebaffb5a0b05b17fded24e548454de89aca2dcf6d7a9de4 +b2b8b3e15c1f645f07783e5628aba614e60157889db41d8161d977606788842b67f83f361eae91815dc0abd84e09abd5 +ad26c3aa35ddfddc15719b8bb6c264aaec7065e88ac29ba820eb61f220fef451609a7bb037f3722d022e6c86e4f1dc88 +b8615bf43e13ae5d7b8dd903ce37190800cd490f441c09b22aa29d7a29ed2c0417b7a08ead417868f1de2589deaadd80 +8d3425e1482cd1e76750a76239d33c06b3554c3c3c87c15cb7ab58b1cee86a4c5c4178b44e23f36928365a1b484bde02 +806893a62e38c941a7dd6f249c83af16596f69877cc737d8f73f6b8cd93cbc01177a7a276b2b8c6b0e5f2ad864db5994 +86618f17fa4b0d65496b661bbb5ba3bc3a87129d30a4b7d4f515b904f4206ca5253a41f49fd52095861e5e065ec54f21 +9551915da1304051e55717f4c31db761dcdcf3a1366c89a4af800a9e99aca93a357bf928307f098e62b44a02cb689a46 +8f79c4ec0ec1146cb2a523b52fe33def90d7b5652a0cb9c2d1c8808a32293e00aec6969f5b1538e3a94cd1efa3937f86 +a0c03e329a707300081780f1e310671315b4c6a4cedcb29697aedfabb07a9d5df83f27b20e9c44cf6b16e39d9ded5b98 +86a7cfa7c8e7ce2c01dd0baec2139e97e8e090ad4e7b5f51518f83d564765003c65968f85481bbb97cb18f005ccc7d9f +a33811770c6dfda3f7f74e6ad0107a187fe622d61b444bbd84fd7ef6e03302e693b093df76f6ab39bb4e02afd84a575a +85480f5c10d4162a8e6702b5e04f801874d572a62a130be94b0c02b58c3c59bdcd48cd05f0a1c2839f88f06b6e3cd337 +8e181011564b17f7d787fe0e7f3c87f6b62da9083c54c74fd6c357a1f464c123c1d3d8ade3cf72475000b464b14e2be3 +8ee178937294b8c991337e0621ab37e9ffa4ca2bdb3284065c5e9c08aad6785d50cf156270ff9daf9a9127289710f55b +8bd1e8e2d37379d4b172f1aec96f2e41a6e1393158d7a3dbd9a95c8dd4f8e0b05336a42efc11a732e5f22b47fc5c271d +8f3da353cd487c13136a85677de8cedf306faae0edec733cf4f0046f82fa4639db4745b0095ff33a9766aba50de0cbcf +8d187c1e97638df0e4792b78e8c23967dac43d98ea268ca4aabea4e0fa06cb93183fd92d4c9df74118d7cc27bf54415e +a4c992f08c2f8bac0b74b3702fb0c75c9838d2ce90b28812019553d47613c14d8ce514d15443159d700b218c5a312c49 +a6fd1874034a34c3ea962a316c018d9493d2b3719bb0ec4edbc7c56b240802b2228ab49bee6f04c8a3e9f6f24a48c1c2 +b2efed8e799f8a15999020900dc2c58ece5a3641c90811b86a5198e593d7318b9d53b167818ccdfbe7df2414c9c34011 +995ff7de6181ddf95e3ead746089c6148da3508e4e7a2323c81785718b754d356789b902e7e78e2edc6b0cbd4ff22c78 +944073d24750a9068cbd020b834afc72d2dde87efac04482b3287b40678ad07588519a4176b10f2172a2c463d063a5cd +99db4b1bb76475a6fd75289986ef40367960279524378cc917525fb6ba02a145a218c1e9caeb99332332ab486a125ac0 +89fce4ecd420f8e477af4353b16faabb39e063f3f3c98fde2858b1f2d1ef6eed46f0975a7c08f233b97899bf60ccd60a +8c09a4f07a02b80654798bc63aada39fd638d3e3c4236ccd8a5ca280350c31e4a89e5f4c9aafb34116e71da18c1226b8 +85325cfa7ded346cc51a2894257eab56e7488dbff504f10f99f4cd2b630d913003761a50f175ed167e8073f1b6b63fb0 +b678b4fbec09a8cc794dcbca185f133578f29e354e99c05f6d07ac323be20aecb11f781d12898168e86f2e0f09aca15e +a249cfcbca4d9ba0a13b5f6aac72bf9b899adf582f9746bb2ad043742b28915607467eb794fca3704278f9136f7642be +9438e036c836a990c5e17af3d78367a75b23c37f807228362b4d13e3ddcb9e431348a7b552d09d11a2e9680704a4514f +925ab70450af28c21a488bfb5d38ac994f784cf249d7fd9ad251bb7fd897a23e23d2528308c03415074d43330dc37ef4 +a290563904d5a8c0058fc8330120365bdd2ba1fdbaef7a14bc65d4961bb4217acfaed11ab82669e359531f8bf589b8db +a7e07a7801b871fc9b981a71e195a3b4ba6b6313bc132b04796a125157e78fe5c11a3a46cf731a255ac2d78a4ae78cd0 +b26cd2501ee72718b0eebab6fb24d955a71f363f36e0f6dff0ab1d2d7836dab88474c0cef43a2cc32701fca7e82f7df3 +a1dc3b6c968f3de00f11275092290afab65b2200afbcfa8ddc70e751fa19dbbc300445d6d479a81bda3880729007e496 +a9bc213e28b630889476a095947d323b9ac6461dea726f2dc9084473ae8e196d66fb792a21905ad4ec52a6d757863e7d +b25d178df8c2df8051e7c888e9fa677fde5922e602a95e966db9e4a3d6b23ce043d7dc48a5b375c6b7c78e966893e8c3 +a1c8d88d72303692eaa7adf68ea41de4febec40cc14ae551bb4012afd786d7b6444a3196b5d9d5040655a3366d96b7cd +b22bd44f9235a47118a9bbe2ba5a2ba9ec62476061be2e8e57806c1a17a02f9a51403e849e2e589520b759abd0117683 +b8add766050c0d69fe81d8d9ea73e1ed05f0135d093ff01debd7247e42dbb86ad950aceb3b50b9af6cdc14ab443b238f +af2cf95f30ef478f018cf81d70d47d742120b09193d8bb77f0d41a5d2e1a80bfb467793d9e2471b4e0ad0cb2c3b42271 +8af5ef2107ad284e246bb56e20fef2a255954f72de791cbdfd3be09f825298d8466064f3c98a50496c7277af32b5c0bc +85dc19558572844c2849e729395a0c125096476388bd1b14fa7f54a7c38008fc93e578da3aac6a52ff1504d6ca82db05 +ae8c9b43c49572e2e166d704caf5b4b621a3b47827bb2a3bcd71cdc599bba90396fd9a405261b13e831bb5d44c0827d7 +a7ba7efede25f02e88f6f4cbf70643e76784a03d97e0fbd5d9437c2485283ad7ca3abb638a5f826cd9f6193e5dec0b6c +94a9d122f2f06ef709fd8016fd4b712d88052245a65a301f5f177ce22992f74ad05552b1f1af4e70d1eac62cef309752 +82d999b3e7cf563833b8bc028ff63a6b26eb357dfdb3fd5f10e33a1f80a9b2cfa7814d871b32a7ebfbaa09e753e37c02 +aec6edcde234df502a3268dd2c26f4a36a2e0db730afa83173f9c78fcb2b2f75510a02b80194327b792811caefda2725 +94c0bfa66c9f91d462e9194144fdd12d96f9bbe745737e73bab8130607ee6ea9d740e2cfcbbd00a195746edb6369ee61 +ab7573dab8c9d46d339e3f491cb2826cabe8b49f85f1ede78d845fc3995537d1b4ab85140b7d0238d9c24daf0e5e2a7e +87e8b16832843251fe952dadfd01d41890ed4bb4b8fa0254550d92c8cced44368225eca83a6c3ad47a7f81ff8a80c984 +9189d2d9a7c64791b19c0773ad4f0564ce6bea94aa275a917f78ad987f150fdb3e5e26e7fef9982ac184897ecc04683f +b3661bf19e2da41415396ae4dd051a9272e8a2580b06f1a1118f57b901fa237616a9f8075af1129af4eabfefedbe2f1c +af43c86661fb15daf5d910a4e06837225e100fb5680bd3e4b10f79a2144c6ec48b1f8d6e6b98e067d36609a5d038889a +82ac0c7acaa83ddc86c5b4249aae12f28155989c7c6b91e5137a4ce05113c6cbc16f6c44948b0efd8665362d3162f16a +8f268d1195ab465beeeb112cd7ffd5d5548559a8bc01261106d3555533fc1971081b25558d884d552df0db1cddda89d8 +8ef7caa5521f3e037586ce8ac872a4182ee20c7921c0065ed9986c047e3dda08294da1165f385d008b40d500f07d895f +8c2f98f6880550573fad46075d3eba26634b5b025ce25a0b4d6e0193352c8a1f0661064027a70fe8190b522405f9f4e3 +b7653f353564feb164f0f89ec7949da475b8dad4a4d396d252fc2a884f6932d027b7eb2dc4d280702c74569319ed701a +a026904f4066333befd9b87a8fad791d014096af60cdd668ef919c24dbe295ff31f7a790e1e721ba40cf5105abca67f4 +988f982004ada07a22dd345f2412a228d7a96b9cae2c487de42e392afe1e35c2655f829ce07a14629148ce7079a1f142 +9616add009067ed135295fb74d5b223b006b312bf14663e547a0d306694ff3a8a7bb9cfc466986707192a26c0bce599f +ad4c425de9855f6968a17ee9ae5b15e0a5b596411388cf976df62ecc6c847a6e2ddb2cea792a5f6e9113c2445dba3e5c +b698ac9d86afa3dc69ff8375061f88e3b0cff92ff6dfe747cebaf142e813c011851e7a2830c10993b715e7fd594604a9 +a386fa189847bb3b798efca917461e38ead61a08b101948def0f82cd258b945ed4d45b53774b400af500670149e601b7 +905c95abda2c68a6559d8a39b6db081c68cef1e1b4be63498004e1b2f408409be9350b5b5d86a30fd443e2b3e445640a +9116dade969e7ce8954afcdd43e5cab64dc15f6c1b8da9d2d69de3f02ba79e6c4f6c7f54d6bf586d30256ae405cd1e41 +a3084d173eacd08c9b5084a196719b57e47a0179826fda73466758235d7ecdb87cbcf097bd6b510517d163a85a7c7edd +85bb00415ad3c9be99ff9ba83672cc59fdd24356b661ab93713a3c8eab34e125d8867f628a3c3891b8dc056e69cd0e83 +8d58541f9f39ed2ee4478acce5d58d124031338ec11b0d55551f00a5a9a6351faa903a5d7c132dc5e4bb026e9cbd18e4 +a622adf72dc250e54f672e14e128c700166168dbe0474cecb340da175346e89917c400677b1bc1c11fcc4cc26591d9db +b3f865014754b688ca8372e8448114fff87bf3ca99856ab9168894d0c4679782c1ced703f5b74e851b370630f5e6ee86 +a7e490b2c40c2446fcd91861c020da9742c326a81180e38110558bb5d9f2341f1c1885e79b364e6419023d1cbdc47380 +b3748d472b1062e54572badbb8e87ac36534407f74932e7fc5b8392d008e8e89758f1671d1e4d30ab0fa40551b13bb5e +89898a5c5ec4313aabc607b0049fd1ebad0e0c074920cf503c9275b564d91916c2c446d3096491c950b7af3ac5e4b0ed +8eb8c83fef2c9dd30ea44e286e9599ec5c20aba983f702e5438afe2e5b921884327ad8d1566c72395587efac79ca7d56 +b92479599e806516ce21fb0bd422a1d1d925335ebe2b4a0a7e044dd275f30985a72b97292477053ac5f00e081430da80 +a34ae450a324fe8a3c25a4d653a654f9580ed56bbea213b8096987bbad0f5701d809a17076435e18017fea4d69f414bc +81381afe6433d62faf62ea488f39675e0091835892ecc238e02acf1662669c6d3962a71a3db652f6fe3bc5f42a0e5dc5 +a430d475bf8580c59111103316fe1aa79c523ea12f1d47a976bbfae76894717c20220e31cf259f08e84a693da6688d70 +b842814c359754ece614deb7d184d679d05d16f18a14b288a401cef5dad2cf0d5ee90bad487b80923fc5573779d4e4e8 +971d9a2627ff2a6d0dcf2af3d895dfbafca28b1c09610c466e4e2bff2746f8369de7f40d65b70aed135fe1d72564aa88 +8f4ce1c59e22b1ce7a0664caaa7e53735b154cfba8d2c5cc4159f2385843de82ab58ed901be876c6f7fce69cb4130950 +86cc9dc321b6264297987000d344fa297ef45bcc2a4df04e458fe2d907ad304c0ea2318e32c3179af639a9a56f3263cf +8229e0876dfe8f665c3fb19b250bd89d40f039bbf1b331468b403655be7be2e104c2fd07b9983580c742d5462ca39a43 +99299d73066e8eb128f698e56a9f8506dfe4bd014931e86b6b487d6195d2198c6c5bf15cccb40ccf1f8ddb57e9da44a2 +a3a3be37ac554c574b393b2f33d0a32a116c1a7cfeaf88c54299a4da2267149a5ecca71f94e6c0ef6e2f472b802f5189 +a91700d1a00387502cdba98c90f75fbc4066fefe7cc221c8f0e660994c936badd7d2695893fde2260c8c11d5bdcdd951 +8e03cae725b7f9562c5c5ab6361644b976a68bada3d7ca508abca8dfc80a469975689af1fba1abcf21bc2a190dab397d +b01461ad23b2a8fa8a6d241e1675855d23bc977dbf4714add8c4b4b7469ccf2375cec20e80cedfe49361d1a30414ac5b +a2673bf9bc621e3892c3d7dd4f1a9497f369add8cbaa3472409f4f86bd21ac67cfac357604828adfee6ada1835365029 +a042dff4bf0dfc33c178ba1b335e798e6308915128de91b12e5dbbab7c4ac8d60a01f6aea028c3a6d87b9b01e4e74c01 +86339e8a75293e4b3ae66b5630d375736b6e6b6b05c5cda5e73fbf7b2f2bd34c18a1d6cefede08625ce3046e77905cb8 +af2ebe1b7d073d03e3d98bc61af83bf26f7a8c130fd607aa92b75db22d14d016481b8aa231e2c9757695f55b7224a27f +a00ee882c9685e978041fd74a2c465f06e2a42ffd3db659053519925be5b454d6f401e3c12c746e49d910e4c5c9c5e8c +978a781c0e4e264e0dad57e438f1097d447d891a1e2aa0d5928f79a9d5c3faae6f258bc94fdc530b7b2fa6a9932bb193 +aa4b7ce2e0c2c9e9655bf21e3e5651c8503bce27483017b0bf476be743ba06db10228b3a4c721219c0779747f11ca282 +b003d1c459dacbcf1a715551311e45d7dbca83a185a65748ac74d1800bbeaba37765d9f5a1a221805c571910b34ebca8 +95b6e531b38648049f0d19de09b881baa1f7ea3b2130816b006ad5703901a05da57467d1a3d9d2e7c73fb3f2e409363c +a6cf9c06593432d8eba23a4f131bb7f72b9bd51ab6b4b772a749fe03ed72b5ced835a349c6d9920dba2a39669cb7c684 +aa3d59f6e2e96fbb66195bc58c8704e139fa76cd15e4d61035470bd6e305db9f98bcbf61ac1b95e95b69ba330454c1b3 +b57f97959c208361de6d7e86dff2b873068adb0f158066e646f42ae90e650079798f165b5cd713141cd3a2a90a961d9a +a76ee8ed9052f6a7a8c69774bb2597be182942f08115baba03bf8faaeaee526feba86120039fe8ca7b9354c3b6e0a8e6 +95689d78c867724823f564627d22d25010f278674c6d2d0cdb10329169a47580818995d1d727ce46c38a1e47943ebb89 +ab676d2256c6288a88e044b3d9ffd43eb9d5aaee00e8fc60ac921395fb835044c71a26ca948e557fed770f52d711e057 +96351c72785c32e5d004b6f4a1259fb8153d631f0c93fed172f18e8ba438fbc5585c1618deeabd0d6d0b82173c2e6170 +93dd8d3db576418e22536eba45ab7f56967c6c97c64260d6cddf38fb19c88f2ec5cd0e0156f50e70855eee8a2b879ffd +ad6ff16f40f6de3d7a737f8e6cebd8416920c4ff89dbdcd75eabab414af9a6087f83ceb9aff7680aa86bff98bd09c8cc +84de53b11671abc9c38710e19540c5c403817562aeb22a88404cdaff792c1180f717dbdfe8f54940c062c4d032897429 +872231b9efa1cdd447b312099a5c164c560440a9441d904e70f5abfc3b2a0d16be9a01aca5e0a2599a61e19407587e3d +88f44ac27094a2aa14e9dc40b099ee6d68f97385950f303969d889ee93d4635e34dff9239103bdf66a4b7cbba3e7eb7a +a59afebadf0260e832f6f44468443562f53fbaf7bcb5e46e1462d3f328ac437ce56edbca617659ac9883f9e13261fad7 +b1990e42743a88de4deeacfd55fafeab3bc380cb95de43ed623d021a4f2353530bcab9594389c1844b1c5ea6634c4555 +85051e841149a10e83f56764e042182208591396d0ce78c762c4a413e6836906df67f38c69793e158d64fef111407ba3 +9778172bbd9b1f2ec6bbdd61829d7b39a7df494a818e31c654bf7f6a30139899c4822c1bf418dd4f923243067759ce63 +9355005b4878c87804fc966e7d24f3e4b02bed35b4a77369d01f25a3dcbff7621b08306b1ac85b76fe7b4a3eb5f839b1 +8f9dc6a54fac052e236f8f0e1f571ac4b5308a43acbe4cc8183bce26262ddaf7994e41cf3034a4cbeca2c505a151e3b1 +8cc59c17307111723fe313046a09e0e32ea0cce62c13814ab7c6408c142d6a0311d801be4af53fc9240523f12045f9ef +8e6057975ed40a1932e47dd3ac778f72ee2a868d8540271301b1aa6858de1a5450f596466494a3e0488be4fbeb41c840 +812145efbd6559ae13325d56a15940ca4253b17e72a9728986b563bb5acc13ec86453796506ac1a8f12bd6f9e4a288c3 +911da0a6d6489eb3dab2ec4a16e36127e8a291ae68a6c2c9de33e97f3a9b1f00da57a94e270a0de79ecc5ecb45d19e83 +b72ea85973f4b2a7e6e71962b0502024e979a73c18a9111130e158541fa47bbaaf53940c8f846913a517dc69982ba9e1 +a7a56ad1dbdc55f177a7ad1d0af78447dc2673291e34e8ab74b26e2e2e7d8c5fe5dc89e7ef60f04a9508847b5b3a8188 +b52503f6e5411db5d1e70f5fb72ccd6463fa0f197b3e51ca79c7b5a8ab2e894f0030476ada72534fa4eb4e06c3880f90 +b51c7957a3d18c4e38f6358f2237b3904618d58b1de5dec53387d25a63772e675a5b714ad35a38185409931157d4b529 +b86b4266e719d29c043d7ec091547aa6f65bbf2d8d831d1515957c5c06513b72aa82113e9645ad38a7bc3f5383504fa6 +b95b547357e6601667b0f5f61f261800a44c2879cf94e879def6a105b1ad2bbf1795c3b98a90d588388e81789bd02681 +a58fd4c5ae4673fa350da6777e13313d5d37ed1dafeeb8f4f171549765b84c895875d9d3ae6a9741f3d51006ef81d962 +9398dc348d078a604aadc154e6eef2c0be1a93bb93ba7fe8976edc2840a3a318941338cc4d5f743310e539d9b46613d2 +902c9f0095014c4a2f0dccaaab543debba6f4cc82c345a10aaf4e72511725dbed7a34cd393a5f4e48a3e5142b7be84ed +a7c0447849bb44d04a0393a680f6cd390093484a79a147dd238f5d878030d1c26646d88211108e59fe08b58ad20c6fbd +80db045535d6e67a422519f5c89699e37098449d249698a7cc173a26ccd06f60238ae6cc7242eb780a340705c906790c +8e52b451a299f30124505de2e74d5341e1b5597bdd13301cc39b05536c96e4380e7f1b5c7ef076f5b3005a868657f17c +824499e89701036037571761e977654d2760b8ce21f184f2879fda55d3cda1e7a95306b8abacf1caa79d3cc075b9d27f +9049b956b77f8453d2070607610b79db795588c0cec12943a0f5fe76f358dea81e4f57a4692112afda0e2c05c142b26f +81911647d818a4b5f4990bfd4bc13bf7be7b0059afcf1b6839333e8569cdb0172fd2945410d88879349f677abaed5eb3 +ad4048f19b8194ed45b6317d9492b71a89a66928353072659f5ce6c816d8f21e69b9d1817d793effe49ca1874daa1096 +8d22f7b2ddb31458661abd34b65819a374a1f68c01fc6c9887edeba8b80c65bceadb8f57a3eb686374004b836261ef67 +92637280c259bc6842884db3d6e32602a62252811ae9b019b3c1df664e8809ffe86db88cfdeb8af9f46435c9ee790267 +a2f416379e52e3f5edc21641ea73dc76c99f7e29ea75b487e18bd233856f4c0183429f378d2bfc6cd736d29d6cadfa49 +882cb6b76dbdc188615dcf1a8439eba05ffca637dd25197508156e03c930b17b9fed2938506fdd7b77567cb488f96222 +b68b621bb198a763fb0634eddb93ed4b5156e59b96c88ca2246fd1aea3e6b77ed651e112ac41b30cd361fadc011d385e +a3cb22f6b675a29b2d1f827cacd30df14d463c93c3502ef965166f20d046af7f9ab7b2586a9c64f4eae4fad2d808a164 +8302d9ce4403f48ca217079762ce42cee8bc30168686bb8d3a945fbd5acd53b39f028dce757b825eb63af2d5ae41169d +b2eef1fbd1a176f1f4cd10f2988c7329abe4eb16c7405099fb92baa724ab397bc98734ef7d4b24c0f53dd90f57520d04 +a1bbef0bd684a3f0364a66bde9b29326bac7aa3dde4caed67f14fb84fed3de45c55e406702f1495a3e2864d4ee975030 +976acdb0efb73e3a3b65633197692dedc2adaed674291ae3df76b827fc866d214e9cac9ca46baefc4405ff13f953d936 +b9fbf71cc7b6690f601f0b1c74a19b7d14254183a2daaafec7dc3830cba5ae173d854bbfebeca985d1d908abe5ef0cda +90591d7b483598c94e38969c4dbb92710a1a894bcf147807f1bcbd8aa3ac210b9f2be65519aa829f8e1ccdc83ad9b8cf +a30568577c91866b9c40f0719d46b7b3b2e0b4a95e56196ac80898a2d89cc67880e1229933f2cd28ee3286f8d03414d7 +97589a88c3850556b359ec5e891f0937f922a751ac7c95949d3bbc7058c172c387611c0f4cb06351ef02e5178b3dd9e4 +98e7bbe27a1711f4545df742f17e3233fbcc63659d7419e1ca633f104cb02a32c84f2fac23ca2b84145c2672f68077ab +a7ddb91636e4506d8b7e92aa9f4720491bb71a72dadc47c7f4410e15f93e43d07d2b371951a0e6a18d1bd087aa96a5c4 +a7c006692227a06db40bceac3d5b1daae60b5692dd9b54772bedb5fea0bcc91cbcdb530cac31900ffc70c5b3ffadc969 +8d3ec6032778420dfa8be52066ba0e623467df33e4e1901dbadd586c5d750f4ccde499b5197e26b9ea43931214060f69 +8d9a8410518ea64f89df319bfd1fc97a0971cdb9ad9b11d1f8fe834042ea7f8dce4db56eeaf179ff8dda93b6db93e5ce +a3c533e9b3aa04df20b9ff635cb1154ce303e045278fcf3f10f609064a5445552a1f93989c52ce852fd0bbd6e2b6c22e +81934f3a7f8c1ae60ec6e4f212986bcc316118c760a74155d06ce0a8c00a9b9669ec4e143ca214e1b995e41271774fd9 +ab8e2d01a71192093ef8fafa7485e795567cc9db95a93fb7cc4cf63a391ef89af5e2bfad4b827fffe02b89271300407f +83064a1eaa937a84e392226f1a60b7cfad4efaa802f66de5df7498962f7b2649924f63cd9962d47906380b97b9fe80e1 +b4f5e64a15c6672e4b55417ee5dc292dcf93d7ea99965a888b1cc4f5474a11e5b6520eacbcf066840b343f4ceeb6bf33 +a63d278b842456ef15c278b37a6ea0f27c7b3ffffefca77c7a66d2ea06c33c4631eb242bbb064d730e70a8262a7b848a +83a41a83dbcdf0d22dc049de082296204e848c453c5ab1ba75aa4067984e053acf6f8b6909a2e1f0009ed051a828a73b +819485b036b7958508f15f3c19436da069cbe635b0318ebe8c014cf1ef9ab2df038c81161b7027475bcfa6fff8dd9faf +aa40e38172806e1e045e167f3d1677ef12d5dcdc89b43639a170f68054bd196c4fae34c675c1644d198907a03f76ba57 +969bae484883a9ed1fbed53b26b3d4ee4b0e39a6c93ece5b3a49daa01444a1c25727dabe62518546f36b047b311b177c +80a9e73a65da99664988b238096a090d313a0ee8e4235bc102fa79bb337b51bb08c4507814eb5baec22103ec512eaab0 +86604379aec5bddda6cbe3ef99c0ac3a3c285b0b1a15b50451c7242cd42ae6b6c8acb717dcca7917838432df93a28502 +a23407ee02a495bed06aa7e15f94cfb05c83e6d6fba64456a9bbabfa76b2b68c5c47de00ba169e710681f6a29bb41a22 +98cff5ecc73b366c6a01b34ac9066cb34f7eeaf4f38a5429bad2d07e84a237047e2a065c7e8a0a6581017dadb4695deb +8de9f68a938f441f3b7ab84bb1f473c5f9e5c9e139e42b7ccee1d254bd57d0e99c2ccda0f3198f1fc5737f6023dd204e +b0ce48d815c2768fb472a315cad86aa033d0e9ca506f146656e2941829e0acb735590b4fbc713c2d18d3676db0a954ac +82f485cdefd5642a6af58ac6817991c49fac9c10ace60f90b27f1788cc026c2fe8afc83cf499b3444118f9f0103598a8 +82c24550ed512a0d53fc56f64cc36b553823ae8766d75d772dacf038c460f16f108f87a39ceef7c66389790f799dbab3 +859ffcf1fe9166388316149b9acc35694c0ea534d43f09dae9b86f4aa00a23b27144dda6a352e74b9516e8c8d6fc809c +b8f7f353eec45da77fb27742405e5ad08d95ec0f5b6842025be9def3d9892f85eb5dd0921b41e6eff373618dba215bca +8ccca4436f9017e426229290f5cd05eac3f16571a4713141a7461acfe8ae99cd5a95bf5b6df129148693c533966145da +a2c67ecc19c0178b2994846fea4c34c327a5d786ac4b09d1d13549d5be5996d8a89021d63d65cb814923388f47cc3a03 +aa0ff87d676b418ec08f5cbf577ac7e744d1d0e9ebd14615b550eb86931eafd2a36d4732cc5d6fab1713fd7ab2f6f7c0 +8aef4730bb65e44efd6bb9441c0ae897363a2f3054867590a2c2ecf4f0224e578c7a67f10b40f8453d9f492ac15a9b2d +86a187e13d8fba5addcfdd5b0410cedd352016c930f913addd769ee09faa6be5ca3e4b1bdb417a965c643a99bd92be42 +a0a4e9632a7a094b14b29b78cd9c894218cdf6783e61671e0203865dc2a835350f465fbaf86168f28af7c478ca17bc89 +a8c7b02d8deff2cd657d8447689a9c5e2cd74ef57c1314ac4d69084ac24a7471954d9ff43fe0907d875dcb65fd0d3ce5 +97ded38760aa7be6b6960b5b50e83b618fe413cbf2bcc1da64c05140bcc32f5e0e709cd05bf8007949953fac5716bad9 +b0d293835a24d64c2ae48ce26e550b71a8c94a0883103757fb6b07e30747f1a871707d23389ba2b2065fa6bafe220095 +8f9e291bf849feaa575592e28e3c8d4b7283f733d41827262367ea1c40f298c7bcc16505255a906b62bf15d9f1ba85fb +998f4e2d12708b4fd85a61597ca2eddd750f73c9e0c9b3cf0825d8f8e01f1628fd19797dcaed3b16dc50331fc6b8b821 +b30d1f8c115d0e63bf48f595dd10908416774c78b3bbb3194192995154d80ea042d2e94d858de5f8aa0261b093c401fd +b5d9c75bb41f964cbff3f00e96d9f1480c91df8913f139f0d385d27a19f57a820f838eb728e46823cbff00e21c660996 +a6edec90b5d25350e2f5f0518777634f9e661ec9d30674cf5b156c4801746d62517751d90074830ac0f4b09911c262f1 +82f98da1264b6b75b8fbeb6a4d96d6a05b25c24db0d57ba3a38efe3a82d0d4e331b9fc4237d6494ccfe4727206457519 +b89511843453cf4ecd24669572d6371b1e529c8e284300c43e0d5bb6b3aaf35aeb634b3cb5c0a2868f0d5e959c1d0772 +a82bf065676583e5c1d3b81987aaae5542f522ba39538263a944bb33ea5b514c649344a96c0205a3b197a3f930fcda6c +a37b47ea527b7e06c460776aa662d9a49ff4149d3993f1a974b0dd165f7171770d189b0e2ea54fd5fccb6a14b116e68a +a1017677f97dda818274d47556d09d0e4ccacb23a252f82a6cfe78c630ad46fb9806307445a59fb61262182de3a2b29c +b01e9fcac239ba270e6877b79273ddd768bf8a51d2ed8a051b1c11e18eff3de5920e2fcbfbd26f06d381eddd3b1f1e1b +82fcd53d803b1c8e4ed76adc339b7f3a5962d37042b9683aabac7513ac68775d4a566a9460183926a6a95dbe7d551a1f +a763e78995d55cd21cdb7ef75d9642d6e1c72453945e346ab6690c20a4e1eeec61bb848ef830ae4b56182535e3c71d8f +b769f4db602251d4b0a1186782799bdcef66de33c110999a5775c50b349666ffd83d4c89714c4e376f2efe021a5cfdb2 +a59cbd1b785efcfa6e83fc3b1d8cf638820bc0c119726b5368f3fba9dce8e3414204fb1f1a88f6c1ff52e87961252f97 +95c8c458fd01aa23ecf120481a9c6332ebec2e8bb70a308d0576926a858457021c277958cf79017ddd86a56cacc2d7db +82eb41390800287ae56e77f2e87709de5b871c8bdb67c10a80fc65f3acb9f7c29e8fa43047436e8933f27449ea61d94d +b3ec25e3545eb83aed2a1f3558d1a31c7edde4be145ecc13b33802654b77dc049b4f0065069dd9047b051e52ab11dcdd +b78a0c715738f56f0dc459ab99e252e3b579b208142836b3c416b704ca1de640ca082f29ebbcee648c8c127df06f6b1e +a4083149432eaaf9520188ebf4607d09cf664acd1f471d4fb654476e77a9eaae2251424ffda78d09b6cb880df35c1219 +8c52857d68d6e9672df3db2df2dbf46b516a21a0e8a18eec09a6ae13c1ef8f369d03233320dd1c2c0bbe00abfc1ea18b +8c856089488803066bff3f8d8e09afb9baf20cecc33c8823c1c0836c3d45498c3de37e87c016b705207f60d2b00f8609 +831a3df39be959047b2aead06b4dcd3012d7b29417f642b83c9e8ce8de24a3dbbd29c6fdf55e2db3f7ea04636c94e403 +aed84d009f66544addabe404bf6d65af7779ce140dc561ff0c86a4078557b96b2053b7b8a43432ffb18cd814f143b9da +93282e4d72b0aa85212a77b336007d8ba071eea17492da19860f1ad16c1ea8867ccc27ef5c37c74b052465cc11ea4f52 +a7b78b8c8d057194e8d68767f1488363f77c77bddd56c3da2bc70b6354c7aa76247c86d51f7371aa38a4aa7f7e3c0bb7 +b1c77283d01dcd1bde649b5b044eac26befc98ff57cbee379fb5b8e420134a88f2fc7f0bf04d15e1fbd45d29e7590fe6 +a4aa8de70330a73b2c6458f20a1067eed4b3474829b36970a8df125d53bbdda4f4a2c60063b7cccb0c80fc155527652f +948a6c79ba1b8ad7e0bed2fae2f0481c4e41b4d9bbdd9b58164e28e9065700e83f210c8d5351d0212e0b0b68b345b3a5 +86a48c31dcbbf7b082c92d28e1f613a2378a910677d7db3a349dc089e4a1e24b12eee8e8206777a3a8c64748840b7387 +976adb1af21e0fc34148917cf43d933d7bfd3fd12ed6c37039dcd5a4520e3c6cf5868539ba5bf082326430deb8a4458d +b93e1a4476f2c51864bb4037e7145f0635eb2827ab91732b98d49b6c07f6ac443111aa1f1da76d1888665cb897c3834e +8afd46fb23bf869999fa19784b18a432a1f252d09506b8dbb756af900518d3f5f244989b3d7c823d9029218c655d3dc6 +83f1e59e3abeed18cdc632921672673f1cb6e330326e11c4e600e13e0d5bc11bdc970ae12952e15103a706fe720bf4d6 +90ce4cc660714b0b673d48010641c09c00fc92a2c596208f65c46073d7f349dd8e6e077ba7dcef9403084971c3295b76 +8b09b0f431a7c796561ecf1549b85048564de428dac0474522e9558b6065fede231886bc108539c104ce88ebd9b5d1b0 +85d6e742e2fb16a7b0ba0df64bc2c0dbff9549be691f46a6669bca05e89c884af16822b85faefefb604ec48c8705a309 +a87989ee231e468a712c66513746fcf03c14f103aadca0eac28e9732487deb56d7532e407953ab87a4bf8961588ef7b0 +b00da10efe1c29ee03c9d37d5918e391ae30e48304e294696b81b434f65cf8c8b95b9d1758c64c25e534d045ba28696f +91c0e1fb49afe46c7056400baa06dbb5f6e479db78ee37e2d76c1f4e88994357e257b83b78624c4ef6091a6c0eb8254d +883fb797c498297ccbf9411a3e727c3614af4eccde41619b773dc7f3259950835ee79453debf178e11dec4d3ada687a0 +a14703347e44eb5059070b2759297fcfcfc60e6893c0373eea069388eba3950aa06f1c57cd2c30984a2d6f9e9c92c79e +afebc7585b304ceba9a769634adff35940e89cd32682c78002822aab25eec3edc29342b7f5a42a56a1fec67821172ad5 +aea3ff3822d09dba1425084ca95fd359718d856f6c133c5fabe2b2eed8303b6e0ba0d8698b48b93136a673baac174fd9 +af2456a09aa777d9e67aa6c7c49a1845ea5cdda2e39f4c935c34a5f8280d69d4eec570446998cbbe31ede69a91e90b06 +82cada19fed16b891ef3442bafd49e1f07c00c2f57b2492dd4ee36af2bd6fd877d6cb41188a4d6ce9ec8d48e8133d697 +82a21034c832287f616619a37c122cee265cc34ae75e881fcaea4ea7f689f3c2bc8150bbf7dbcfd123522bfb7f7b1d68 +86877217105f5d0ec3eeff0289fc2a70d505c9fdf7862e8159553ef60908fb1a27bdaf899381356a4ef4649072a9796c +82b196e49c6e861089a427c0b4671d464e9d15555ffb90954cd0d630d7ae02eb3d98ceb529d00719c2526cd96481355a +a29b41d0d43d26ce76d4358e0db2b77df11f56e389f3b084d8af70a636218bd3ac86b36a9fe46ec9058c26a490f887f7 +a4311c4c20c4d7dd943765099c50f2fd423e203ccfe98ff00087d205467a7873762510cac5fdce7a308913ed07991ed7 +b1f040fc5cc51550cb2c25cf1fd418ecdd961635a11f365515f0cb4ffb31da71f48128c233e9cc7c0cf3978d757ec84e +a9ebae46f86d3bd543c5f207ed0d1aed94b8375dc991161d7a271f01592912072e083e2daf30c146430894e37325a1b9 +826418c8e17ad902b5fe88736323a47e0ca7a44bce4cbe27846ec8fe81de1e8942455dda6d30e192cdcc73e11df31256 +85199db563427c5edcbac21f3d39fec2357be91fb571982ddcdc4646b446ad5ced84410de008cb47b3477ee0d532daf8 +b7eed9cd400b2ca12bf1d9ae008214b8561fb09c8ad9ff959e626ffde00fee5ff2f5b6612e231f2a1a9b1646fcc575e3 +8b40bf12501dcbac78f5a314941326bfcddf7907c83d8d887d0bb149207f85d80cd4dfbd7935439ea7b14ea39a3fded7 +83e3041af302485399ba6cd5120e17af61043977083887e8d26b15feec4a6b11171ac5c06e6ad0971d4b58a81ff12af3 +8f5b9a0eecc589dbf8c35a65d5e996a659277ef6ea509739c0cb7b3e2da9895e8c8012de662e5b23c5fa85d4a8f48904 +835d71ed5e919d89d8e6455f234f3ff215462c4e3720c371ac8c75e83b19dfe3ae15a81547e4dc1138e5f5997f413cc9 +8b7d2e4614716b1db18e9370176ea483e6abe8acdcc3dcdf5fb1f4d22ca55d652feebdccc171c6de38398d9f7bfdec7a +93eace72036fe57d019676a02acf3d224cf376f166658c1bf705db4f24295881d477d6fdd7916efcfceff8c7a063deda +b1ac460b3d516879a84bc886c54f020a9d799e7c49af3e4d7de5bf0d2793c852254c5d8fe5616147e6659512e5ccb012 +acd0947a35cb167a48bcd9667620464b54ac0e78f9316b4aa92dcaab5422d7a732087e52e1c827faa847c6b2fe6e7766 +94ac33d21c3d12ff762d32557860e911cd94d666609ddcc42161b9c16f28d24a526e8b10bb03137257a92cec25ae637d +832e02058b6b994eadd8702921486241f9a19e68ed1406dad545e000a491ae510f525ccf9d10a4bba91c68f2c53a0f58 +9471035d14f78ff8f463b9901dd476b587bb07225c351161915c2e9c6114c3c78a501379ab6fb4eb03194c457cbd22bf +ab64593e034c6241d357fcbc32d8ea5593445a5e7c24cac81ad12bd2ef01843d477a36dc1ba21dbe63b440750d72096a +9850f3b30045e927ad3ec4123a32ed2eb4c911f572b6abb79121873f91016f0d80268de8b12e2093a4904f6e6cab7642 +987212c36b4722fe2e54fa30c52b1e54474439f9f35ca6ad33c5130cd305b8b54b532dd80ffd2c274105f20ce6d79f6e +8b4d0c6abcb239b5ed47bef63bc17efe558a27462c8208fa652b056e9eae9665787cd1aee34fbb55beb045c8bfdb882b +a9f3483c6fee2fe41312d89dd4355d5b2193ac413258993805c5cbbf0a59221f879386d3e7a28e73014f10e65dd503d9 +a2225da3119b9b7c83d514b9f3aeb9a6d9e32d9cbf9309cbb971fd53c4b2c001d10d880a8ad8a7c281b21d85ceca0b7c +a050be52e54e676c151f7a54453bbb707232f849beab4f3bf504b4d620f59ed214409d7c2bd3000f3ff13184ccda1c35 +adbccf681e15b3edb6455a68d292b0a1d0f5a4cb135613f5e6db9943f02181341d5755875db6ee474e19ace1c0634a28 +8b6eff675632a6fad0111ec72aacc61c7387380eb87933fd1d098856387d418bd38e77d897e65d6fe35951d0627c550b +aabe2328ddf90989b15e409b91ef055cb02757d34987849ae6d60bef2c902bf8251ed21ab30acf39e500d1d511e90845 +92ba4eb1f796bc3d8b03515f65c045b66e2734c2da3fc507fdd9d6b5d1e19ab3893726816a32141db7a31099ca817d96 +8a98b3cf353138a1810beb60e946183803ef1d39ac4ea92f5a1e03060d35a4774a6e52b14ead54f6794d5f4022b8685c +909f8a5c13ec4a59b649ed3bee9f5d13b21d7f3e2636fd2bb3413c0646573fdf9243d63083356f12f5147545339fcd55 +9359d914d1267633141328ed0790d81c695fea3ddd2d406c0df3d81d0c64931cf316fe4d92f4353c99ff63e2aefc4e34 +b88302031681b54415fe8fbfa161c032ea345c6af63d2fb8ad97615103fd4d4281c5a9cae5b0794c4657b97571a81d3b +992c80192a519038082446b1fb947323005b275e25f2c14c33cc7269e0ec038581cc43705894f94bad62ae33a8b7f965 +a78253e3e3eece124bef84a0a8807ce76573509f6861d0b6f70d0aa35a30a123a9da5e01e84969708c40b0669eb70aa6 +8d5724de45270ca91c94792e8584e676547d7ac1ac816a6bb9982ee854eb5df071d20545cdfd3771cd40f90e5ba04c8e +825a6f586726c68d45f00ad0f5a4436523317939a47713f78fd4fe81cd74236fdac1b04ecd97c2d0267d6f4981d7beb1 +93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8 +b5bfd7dd8cdeb128843bc287230af38926187075cbfbefa81009a2ce615ac53d2914e5870cb452d2afaaab24f3499f72185cbfee53492714734429b7b38608e23926c911cceceac9a36851477ba4c60b087041de621000edc98edada20c1def2 +b5337ba0ce5d37224290916e268e2060e5c14f3f9fc9e1ec3af5a958e7a0303122500ce18f1a4640bf66525bd10e763501fe986d86649d8d45143c08c3209db3411802c226e9fe9a55716ac4a0c14f9dcef9e70b2bb309553880dc5025eab3cc +b3c1dcdc1f62046c786f0b82242ef283e7ed8f5626f72542aa2c7a40f14d9094dd1ebdbd7457ffdcdac45fd7da7e16c51200b06d791e5e43e257e45efdf0bd5b06cd2333beca2a3a84354eb48662d83aef5ecf4e67658c851c10b13d8d87c874 +954d91c7688983382609fca9e211e461f488a5971fd4e40d7e2892037268eacdfd495cfa0a7ed6eb0eb11ac3ae6f651716757e7526abe1e06c64649d80996fd3105c20c4c94bc2b22d97045356fe9d791f21ea6428ac48db6f9e68e30d875280 +88a6b6bb26c51cf9812260795523973bb90ce80f6820b6c9048ab366f0fb96e48437a7f7cb62aedf64b11eb4dfefebb0147608793133d32003cb1f2dc47b13b5ff45f1bb1b2408ea45770a08dbfaec60961acb8119c47b139a13b8641e2c9487 +85cd7be9728bd925d12f47fb04b32d9fad7cab88788b559f053e69ca18e463113ecc8bbb6dbfb024835f901b3a957d3108d6770fb26d4c8be0a9a619f6e3a4bf15cbfd48e61593490885f6cee30e4300c5f9cf5e1c08e60a2d5b023ee94fcad0 +80477dba360f04399821a48ca388c0fa81102dd15687fea792ee8c1114e00d1bc4839ad37ac58900a118d863723acfbe08126ea883be87f50e4eabe3b5e72f5d9e041db8d9b186409fd4df4a7dde38c0e0a3b1ae29b098e5697e7f110b6b27e4 +b7a6aec08715a9f8672a2b8c367e407be37e59514ac19dd4f0942a68007bba3923df22da48702c63c0d6b3efd3c2d04e0fe042d8b5a54d562f9f33afc4865dcbcc16e99029e25925580e87920c399e710d438ac1ce3a6dc9b0d76c064a01f6f7 +ac1b001edcea02c8258aeffbf9203114c1c874ad88dae1184fadd7d94cd09053649efd0ca413400e6e9b5fa4eac33261000af88b6bd0d2abf877a4f0355d2fb4d6007adb181695201c5432e50b850b51b3969f893bddf82126c5a71b042b7686 +90043fda4de53fb364fab2c04be5296c215599105ecff0c12e4917c549257125775c29f2507124d15f56e30447f367db0596c33237242c02d83dfd058735f1e3c1ff99069af55773b6d51d32a68bf75763f59ec4ee7267932ae426522b8aaab6 +a8660ce853e9dc08271bf882e29cd53397d63b739584dda5263da4c7cc1878d0cf6f3e403557885f557e184700575fee016ee8542dec22c97befe1d10f414d22e84560741cdb3e74c30dda9b42eeaaf53e27822de2ee06e24e912bf764a9a533 +8fe3921a96d0d065e8aa8fce9aa42c8e1461ca0470688c137be89396dd05103606dab6cdd2a4591efd6addf72026c12e065da7be276dee27a7e30afa2bd81c18f1516e7f068f324d0bad9570b95f6bd02c727cd2343e26db0887c3e4e26dceda +8ae1ad97dcb9c192c9a3933541b40447d1dc4eebf380151440bbaae1e120cc5cdf1bcea55180b128d8e180e3af623815191d063cc0d7a47d55fb7687b9d87040bf7bc1a7546b07c61db5ccf1841372d7c2fe4a5431ffff829f3c2eb590b0b710 +8c2fa96870a88150f7876c931e2d3cc2adeaaaf5c73ef5fa1cf9dfa0991ae4819f9321af7e916e5057d87338e630a2f21242c29d76963cf26035b548d2a63d8ad7bd6efefa01c1df502cbdfdfe0334fb21ceb9f686887440f713bf17a89b8081 +b9aa98e2f02bb616e22ee5dd74c7d1049321ac9214d093a738159850a1dbcc7138cb8d26ce09d8296368fd5b291d74fa17ac7cc1b80840fdd4ee35e111501e3fa8485b508baecda7c1ab7bd703872b7d64a2a40b3210b6a70e8a6ffe0e5127e3 +9292db67f8771cdc86854a3f614a73805bf3012b48f1541e704ea4015d2b6b9c9aaed36419769c87c49f9e3165f03edb159c23b3a49c4390951f78e1d9b0ad997129b17cdb57ea1a6638794c0cca7d239f229e589c5ae4f9fe6979f7f8cba1d7 +91cd9e86550f230d128664f7312591fee6a84c34f5fc7aed557bcf986a409a6de722c4330453a305f06911d2728626e611acfdf81284f77f60a3a1595053a9479964fd713117e27c0222cc679674b03bc8001501aaf9b506196c56de29429b46 +a9516b73f605cc31b89c68b7675dc451e6364595243d235339437f556cf22d745d4250c1376182273be2d99e02c10eee047410a43eff634d051aeb784e76cb3605d8e079b9eb6ad1957dfdf77e1cd32ce4a573c9dfcc207ca65af6eb187f6c3d +a9667271f7d191935cc8ad59ef3ec50229945faea85bfdfb0d582090f524436b348aaa0183b16a6231c00332fdac2826125b8c857a2ed9ec66821cfe02b3a2279be2412441bc2e369b255eb98614e4be8490799c4df22f18d47d24ec70bba5f7 +a4371144d2aa44d70d3cb9789096d3aa411149a6f800cb46f506461ee8363c8724667974252f28aea61b6030c05930ac039c1ee64bb4bd56532a685cae182bf2ab935eee34718cffcb46cae214c77aaca11dbb1320faf23c47247db1da04d8dc +89a7eb441892260b7e81168c386899cd84ffc4a2c5cad2eae0d1ab9e8b5524662e6f660fe3f8bfe4c92f60b060811bc605b14c5631d16709266886d7885a5eb5930097127ec6fb2ebbaf2df65909cf48f253b3d5e22ae48d3e9a2fd2b01f447e +9648c42ca97665b5eccb49580d8532df05eb5a68db07f391a2340769b55119eaf4c52fe4f650c09250fa78a76c3a1e271799b8333cc2628e3d4b4a6a3e03da1f771ecf6516dd63236574a7864ff07e319a6f11f153406280d63af9e2b5713283 +9663bf6dd446ea7a90658ee458578d4196dc0b175ef7fcfa75f44d41670850774c2e46c5a6be132a2c072a3c0180a24f0305d1acac49d2d79878e5cda80c57feda3d01a6af12e78b5874e2a4b3717f11c97503b41a4474e2e95b179113726199 +b212aeb4814e0915b432711b317923ed2b09e076aaf558c3ae8ef83f9e15a83f9ea3f47805b2750ab9e8106cb4dc6ad003522c84b03dc02829978a097899c773f6fb31f7fe6b8f2d836d96580f216fec20158f1590c3e0d7850622e15194db05 +925f005059bf07e9ceccbe66c711b048e236ade775720d0fe479aebe6e23e8af281225ad18e62458dc1b03b42ad4ca290d4aa176260604a7aad0d9791337006fbdebe23746f8060d42876f45e4c83c3643931392fde1cd13ff8bddf8111ef974 +9553edb22b4330c568e156a59ef03b26f5c326424f830fe3e8c0b602f08c124730ffc40bc745bec1a22417adb22a1a960243a10565c2be3066bfdb841d1cd14c624cd06e0008f4beb83f972ce6182a303bee3fcbcabc6cfe48ec5ae4b7941bfc +935f5a404f0a78bdcce709899eda0631169b366a669e9b58eacbbd86d7b5016d044b8dfc59ce7ed8de743ae16c2343b50e2f925e88ba6319e33c3fc76b314043abad7813677b4615c8a97eb83cc79de4fedf6ccbcfa4d4cbf759a5a84e4d9742 +a5b014ab936eb4be113204490e8b61cd38d71da0dec7215125bcd131bf3ab22d0a32ce645bca93e7b3637cf0c2db3d6601a0ddd330dc46f9fae82abe864ffc12d656c88eb50c20782e5bb6f75d18760666f43943abb644b881639083e122f557 +935b7298ae52862fa22bf03bfc1795b34c70b181679ae27de08a9f5b4b884f824ef1b276b7600efa0d2f1d79e4a470d51692fd565c5cf8343dd80e5d3336968fc21c09ba9348590f6206d4424eb229e767547daefa98bc3aa9f421158dee3f2a +9830f92446e708a8f6b091cc3c38b653505414f8b6507504010a96ffda3bcf763d5331eb749301e2a1437f00e2415efb01b799ad4c03f4b02de077569626255ac1165f96ea408915d4cf7955047620da573e5c439671d1fa5c833fb11de7afe6 +840dcc44f673fff3e387af2bb41e89640f2a70bcd2b92544876daa92143f67c7512faf5f90a04b7191de01f3e2b1bde00622a20dc62ca23bbbfaa6ad220613deff43908382642d4d6a86999f662efd64b1df448b68c847cfa87630a3ffd2ec76 +92950c895ed54f7f876b2fda17ecc9c41b7accfbdd42c210cc5b475e0737a7279f558148531b5c916e310604a1de25a80940c94fe5389ae5d6a5e9c371be67bceea1877f5401725a6595bcf77ece60905151b6dfcb68b75ed2e708c73632f4fd +8010246bf8e94c25fd029b346b5fbadb404ef6f44a58fd9dd75acf62433d8cc6db66974f139a76e0c26dddc1f329a88214dbb63276516cf325c7869e855d07e0852d622c332ac55609ba1ec9258c45746a2aeb1af0800141ee011da80af175d4 +b0f1bad257ebd187bdc3f37b23f33c6a5d6a8e1f2de586080d6ada19087b0e2bf23b79c1b6da1ee82271323f5bdf3e1b018586b54a5b92ab6a1a16bb3315190a3584a05e6c37d5ca1e05d702b9869e27f513472bcdd00f4d0502a107773097da +9636d24f1ede773ce919f309448dd7ce023f424afd6b4b69cb98c2a988d849a283646dc3e469879daa1b1edae91ae41f009887518e7eb5578f88469321117303cd3ac2d7aee4d9cb5f82ab9ae3458e796dfe7c24284b05815acfcaa270ff22e2 +b373feb5d7012fd60578d7d00834c5c81df2a23d42794fed91aa9535a4771fde0341c4da882261785e0caca40bf83405143085e7f17e55b64f6c5c809680c20b050409bf3702c574769127c854d27388b144b05624a0e24a1cbcc4d08467005b +b15680648949ce69f82526e9b67d9b55ce5c537dc6ab7f3089091a9a19a6b90df7656794f6edc87fb387d21573ffc847062623685931c2790a508cbc8c6b231dd2c34f4d37d4706237b1407673605a604bcf6a50cc0b1a2db20485e22b02c17e +8817e46672d40c8f748081567b038a3165f87994788ec77ee8daea8587f5540df3422f9e120e94339be67f186f50952504cb44f61e30a5241f1827e501b2de53c4c64473bcc79ab887dd277f282fbfe47997a930dd140ac08b03efac88d81075 +a6e4ef6c1d1098f95aae119905f87eb49b909d17f9c41bcfe51127aa25fee20782ea884a7fdf7d5e9c245b5a5b32230b07e0dbf7c6743bf52ee20e2acc0b269422bd6cf3c07115df4aa85b11b2c16630a07c974492d9cdd0ec325a3fabd95044 +8634aa7c3d00e7f17150009698ce440d8e1b0f13042b624a722ace68ead870c3d2212fbee549a2c190e384d7d6ac37ce14ab962c299ea1218ef1b1489c98906c91323b94c587f1d205a6edd5e9d05b42d591c26494a6f6a029a2aadb5f8b6f67 +821a58092900bdb73decf48e13e7a5012a3f88b06288a97b855ef51306406e7d867d613d9ec738ebacfa6db344b677d21509d93f3b55c2ebf3a2f2a6356f875150554c6fff52e62e3e46f7859be971bf7dd9d5b3e1d799749c8a97c2e04325df +8dba356577a3a388f782e90edb1a7f3619759f4de314ad5d95c7cc6e197211446819c4955f99c5fc67f79450d2934e3c09adefc91b724887e005c5190362245eec48ce117d0a94d6fa6db12eda4ba8dde608fbbd0051f54dcf3bb057adfb2493 +a32a690dc95c23ed9fb46443d9b7d4c2e27053a7fcc216d2b0020a8cf279729c46114d2cda5772fd60a97016a07d6c5a0a7eb085a18307d34194596f5b541cdf01b2ceb31d62d6b55515acfd2b9eec92b27d082fbc4dc59fc63b551eccdb8468 +a040f7f4be67eaf0a1d658a3175d65df21a7dbde99bfa893469b9b43b9d150fc2e333148b1cb88cfd0447d88fa1a501d126987e9fdccb2852ecf1ba907c2ca3d6f97b055e354a9789854a64ecc8c2e928382cf09dda9abde42bbdf92280cdd96 +864baff97fa60164f91f334e0c9be00a152a416556b462f96d7c43b59fe1ebaff42f0471d0bf264976f8aa6431176eb905bd875024cf4f76c13a70bede51dc3e47e10b9d5652d30d2663b3af3f08d5d11b9709a0321aba371d2ef13174dcfcaf +95a46f32c994133ecc22db49bad2c36a281d6b574c83cfee6680b8c8100466ca034b815cfaedfbf54f4e75188e661df901abd089524e1e0eb0bf48d48caa9dd97482d2e8c1253e7e8ac250a32fd066d5b5cb08a8641bdd64ecfa48289dca83a3 +a2cce2be4d12144138cb91066e0cd0542c80b478bf467867ebef9ddaf3bd64e918294043500bf5a9f45ee089a8d6ace917108d9ce9e4f41e7e860cbce19ac52e791db3b6dde1c4b0367377b581f999f340e1d6814d724edc94cb07f9c4730774 +b145f203eee1ac0a1a1731113ffa7a8b0b694ef2312dabc4d431660f5e0645ef5838e3e624cfe1228cfa248d48b5760501f93e6ab13d3159fc241427116c4b90359599a4cb0a86d0bb9190aa7fabff482c812db966fd2ce0a1b48cb8ac8b3bca +adabe5d215c608696e03861cbd5f7401869c756b3a5aadc55f41745ad9478145d44393fec8bb6dfc4ad9236dc62b9ada0f7ca57fe2bae1b71565dbf9536d33a68b8e2090b233422313cc96afc7f1f7e0907dc7787806671541d6de8ce47c4cd0 +ae7845fa6b06db53201c1080e01e629781817f421f28956589c6df3091ec33754f8a4bd4647a6bb1c141ac22731e3c1014865d13f3ed538dcb0f7b7576435133d9d03be655f8fbb4c9f7d83e06d1210aedd45128c2b0c9bab45a9ddde1c862a5 +9159eaa826a24adfa7adf6e8d2832120ebb6eccbeb3d0459ffdc338548813a2d239d22b26451fda98cc0c204d8e1ac69150b5498e0be3045300e789bcb4e210d5cd431da4bdd915a21f407ea296c20c96608ded0b70d07188e96e6c1a7b9b86b +a9fc6281e2d54b46458ef564ffaed6944bff71e389d0acc11fa35d3fcd8e10c1066e0dde5b9b6516f691bb478e81c6b20865281104dcb640e29dc116daae2e884f1fe6730d639dbe0e19a532be4fb337bf52ae8408446deb393d224eee7cfa50 +84291a42f991bfb36358eedead3699d9176a38f6f63757742fdbb7f631f2c70178b1aedef4912fed7b6cf27e88ddc7eb0e2a6aa4b999f3eb4b662b93f386c8d78e9ac9929e21f4c5e63b12991fcde93aa64a735b75b535e730ff8dd2abb16e04 +a1b7fcacae181495d91765dfddf26581e8e39421579c9cbd0dd27a40ea4c54af3444a36bf85a11dda2114246eaddbdd619397424bb1eb41b5a15004b902a590ede5742cd850cf312555be24d2df8becf48f5afba5a8cd087cb7be0a521728386 +92feaaf540dbd84719a4889a87cdd125b7e995a6782911931fef26da9afcfbe6f86aaf5328fe1f77631491ce6239c5470f44c7791506c6ef1626803a5794e76d2be0af92f7052c29ac6264b7b9b51f267ad820afc6f881460521428496c6a5f1 +a525c925bfae1b89320a5054acc1fa11820f73d0cf28d273092b305467b2831fab53b6daf75fb926f332782d50e2522a19edcd85be5eb72f1497193c952d8cd0bcc5d43b39363b206eae4cb1e61668bde28a3fb2fc1e0d3d113f6dfadb799717 +98752bb6f5a44213f40eda6aa4ff124057c1b13b6529ab42fe575b9afa66e59b9c0ed563fb20dff62130c436c3e905ee17dd8433ba02c445b1d67182ab6504a90bbe12c26a754bbf734665c622f76c62fe2e11dd43ce04fd2b91a8463679058b +a9aa9a84729f7c44219ff9e00e651e50ddea3735ef2a73fdf8ed8cd271961d8ed7af5cd724b713a89a097a3fe65a3c0202f69458a8b4c157c62a85668b12fc0d3957774bc9b35f86c184dd03bfefd5c325da717d74192cc9751c2073fe9d170e +b221c1fd335a4362eff504cd95145f122bf93ea02ae162a3fb39c75583fc13a932d26050e164da97cff3e91f9a7f6ff80302c19dd1916f24acf6b93b62f36e9665a8785413b0c7d930c7f1668549910f849bca319b00e59dd01e5dec8d2edacc +a71e2b1e0b16d754b848f05eda90f67bedab37709550171551050c94efba0bfc282f72aeaaa1f0330041461f5e6aa4d11537237e955e1609a469d38ed17f5c2a35a1752f546db89bfeff9eab78ec944266f1cb94c1db3334ab48df716ce408ef +b990ae72768779ba0b2e66df4dd29b3dbd00f901c23b2b4a53419226ef9232acedeb498b0d0687c463e3f1eead58b20b09efcefa566fbfdfe1c6e48d32367936142d0a734143e5e63cdf86be7457723535b787a9cfcfa32fe1d61ad5a2617220 +8d27e7fbff77d5b9b9bbc864d5231fecf817238a6433db668d5a62a2c1ee1e5694fdd90c3293c06cc0cb15f7cbeab44d0d42be632cb9ff41fc3f6628b4b62897797d7b56126d65b694dcf3e298e3561ac8813fbd7296593ced33850426df42db +a92039a08b5502d5b211a7744099c9f93fa8c90cedcb1d05e92f01886219dd464eb5fb0337496ad96ed09c987da4e5f019035c5b01cc09b2a18b8a8dd419bc5895388a07e26958f6bd26751929c25f89b8eb4a299d822e2d26fec9ef350e0d3c +92dcc5a1c8c3e1b28b1524e3dd6dbecd63017c9201da9dbe077f1b82adc08c50169f56fc7b5a3b28ec6b89254de3e2fd12838a761053437883c3e01ba616670cea843754548ef84bcc397de2369adcca2ab54cd73c55dc68d87aec3fc2fe4f10 diff --git a/crates/starknet_os/src/errors.rs b/crates/starknet_os/src/errors.rs new file mode 100644 index 00000000000..501042d3b47 --- /dev/null +++ b/crates/starknet_os/src/errors.rs @@ -0,0 +1,16 @@ +use cairo_vm::types::errors::program_errors::ProgramError; +use cairo_vm::vm::errors::runner_errors::RunnerError; +use cairo_vm::vm::errors::vm_errors::VirtualMachineError; +use cairo_vm::vm::errors::vm_exception::VmException; + +#[derive(Debug, thiserror::Error)] +pub enum StarknetOsError { + #[error(transparent)] + LoadProgramError(#[from] ProgramError), + #[error(transparent)] + RunnerError(#[from] RunnerError), + #[error(transparent)] + VmException(#[from] VmException), + #[error(transparent)] + VirtualMachineError(#[from] VirtualMachineError), +} diff --git a/crates/starknet_os/src/hint_processor.rs b/crates/starknet_os/src/hint_processor.rs new file mode 100644 index 00000000000..0e8c14559a8 --- /dev/null +++ b/crates/starknet_os/src/hint_processor.rs @@ -0,0 +1,5 @@ +pub mod constants; +pub mod execution_helper; +pub mod os_logger; +pub mod panicking_state_reader; +pub mod snos_hint_processor; diff --git a/crates/starknet_os/src/hint_processor/constants.rs b/crates/starknet_os/src/hint_processor/constants.rs new file mode 100644 index 00000000000..d62a2d4d015 --- /dev/null +++ b/crates/starknet_os/src/hint_processor/constants.rs @@ -0,0 +1,21 @@ +use std::collections::HashMap; +use std::sync::LazyLock; + +use cairo_vm::types::builtin_name::BuiltinName; + +pub(crate) static BUILTIN_INSTANCE_SIZES: LazyLock> = + LazyLock::new(|| { + HashMap::from([ + (BuiltinName::pedersen, 3), + (BuiltinName::range_check, 1), + (BuiltinName::ecdsa, 2), + (BuiltinName::bitwise, 5), + (BuiltinName::ec_op, 7), + (BuiltinName::poseidon, 6), + (BuiltinName::segment_arena, 3), + (BuiltinName::range_check96, 1), + (BuiltinName::add_mod, 7), + (BuiltinName::mul_mod, 7), + (BuiltinName::keccak, 16), + ]) + }); diff --git a/crates/starknet_os/src/hint_processor/execution_helper.rs b/crates/starknet_os/src/hint_processor/execution_helper.rs new file mode 100644 index 00000000000..69ec18dfc31 --- /dev/null +++ b/crates/starknet_os/src/hint_processor/execution_helper.rs @@ -0,0 +1,71 @@ +use std::collections::HashMap; + +use blockifier::state::cached_state::{CachedState, StateMaps}; +use blockifier::state::state_api::StateReader; +#[cfg(any(feature = "testing", test))] +use blockifier::test_utils::dict_state_reader::DictStateReader; +use cairo_vm::types::program::Program; + +use crate::errors::StarknetOsError; +use crate::io::os_input::{CachedStateInput, StarknetOsInput}; + +/// A helper struct that provides access to the OS state and commitments. +pub struct OsExecutionHelper { + pub(crate) cached_state: CachedState, + pub(crate) os_input: StarknetOsInput, + pub(crate) os_program: Program, +} + +impl OsExecutionHelper { + pub fn new( + os_input: StarknetOsInput, + os_program: Program, + state_reader: S, + state_input: CachedStateInput, + ) -> Result { + Ok(Self { + cached_state: Self::initialize_cached_state(state_reader, state_input)?, + os_input, + os_program, + }) + } + + fn initialize_cached_state( + state_reader: S, + state_input: CachedStateInput, + ) -> Result, StarknetOsError> { + let mut empty_cached_state = CachedState::new(state_reader); + let mut state_maps = StateMaps::default(); + + // Insert storage. + for (contract_address, storage) in state_input.storage.into_iter() { + for (key, value) in storage.into_iter() { + state_maps.storage.insert((contract_address, key), value); + } + } + // Insert nonces. + state_maps.nonces = state_input.address_to_nonce; + + // Insert class hashes. + state_maps.class_hashes = state_input.address_to_class_hash; + + // Insert compiled class hashes. + state_maps.compiled_class_hashes = state_input.class_hash_to_compiled_class_hash; + + // Update the cached state. + empty_cached_state.update_cache(&state_maps, HashMap::new()); + + Ok(empty_cached_state) + } +} + +#[cfg(any(feature = "testing", test))] +impl OsExecutionHelper { + pub fn new_for_testing( + state_reader: DictStateReader, + os_input: StarknetOsInput, + os_program: Program, + ) -> Self { + Self { cached_state: CachedState::from(state_reader), os_input, os_program } + } +} diff --git a/crates/starknet_os/src/hint_processor/os_logger.rs b/crates/starknet_os/src/hint_processor/os_logger.rs new file mode 100644 index 00000000000..34f72cd7b35 --- /dev/null +++ b/crates/starknet_os/src/hint_processor/os_logger.rs @@ -0,0 +1,510 @@ +use std::collections::HashMap; + +use blockifier::execution::syscalls::SyscallSelector; +use blockifier::transaction::transaction_types::TransactionType; +use cairo_vm::hint_processor::hint_processor_definition::HintReference; +use cairo_vm::serde::deserialize_program::ApTracking; +use cairo_vm::types::builtin_name::BuiltinName; +use cairo_vm::types::program::Program; +use cairo_vm::types::relocatable::Relocatable; +use cairo_vm::vm::runners::cairo_runner::ExecutionResources; +use cairo_vm::vm::vm_core::VirtualMachine; +use starknet_api::transaction::TransactionHash; + +use crate::hint_processor::constants::BUILTIN_INSTANCE_SIZES; +use crate::hints::error::OsHintError; +use crate::hints::vars::{CairoStruct, Ids}; +use crate::vm_utils::get_address_of_nested_fields; + +#[derive(Debug, thiserror::Error)] +pub enum OsLoggerError { + #[error( + "Builtin {builtin} in self and in the enter call counter are not in the same segment: \ + {self_ptr}, {enter_ptr}." + )] + BuiltinsNotInSameSegment { builtin: BuiltinName, self_ptr: Relocatable, enter_ptr: Relocatable }, + #[error("Failed to build builtin pointer map: {0}.")] + BuiltinPtrs(OsHintError), + #[error("Called exit_syscall with empty call stack.")] + CallStackEmpty, + #[error("SyscallTrace should be finalized only once.")] + DoubleFinalize, + #[error("No transaction should exit without entering.")] + ExitBeforeEnter, + #[error("Failed to fetch identifier data for struct {0}.")] + InnerBuiltinPtrsIdentifierMissing(String), + #[error("No transaction should call another transaction.")] + InTxContext, + #[error("{0}")] + MissingBuiltinPtr(String), + #[error("The `members` field is None in identifier data for struct {0}.")] + MissingMembers(String), + #[error("All syscalls should be called inside a transaction.")] + NotInTxContext, + #[error( + "Range check in self and in the enter call counter are not in the same segment: \ + {self_ptr}, {enter_ptr}." + )] + RangeCheckNotInSameSegment { self_ptr: Relocatable, enter_ptr: Relocatable }, + #[error("All Syscalls should end when exiting a transaction.")] + RemainingSyscalls, + #[error("SyscallTrace should be finalized before accessing resources.")] + ResourceAccessBeforeFinalize, + #[error("The {0} syscall is not supposed to have an inner syscall.")] + UnexpectedParentSyscall(String), + #[error("Unexpected syscall {actual:?}, expected {expected:?}.")] + UnexpectedSyscall { expected: SyscallSelector, actual: SyscallSelector }, + #[error("{0}")] + UnknownBuiltin(String), + #[error("Builtin {0} is not in the known sizes mapping {:?}.", BUILTIN_INSTANCE_SIZES)] + UnknownBuiltinSize(String), +} + +pub type OsLoggerResult = Result; + +pub trait ResourceFinalizer { + fn get_optional_resources(&self) -> Option<&ExecutionResources>; + + fn set_resources(&mut self, resources: ExecutionResources); + + fn get_resources(&self) -> OsLoggerResult<&ExecutionResources> { + self.get_optional_resources().ok_or(OsLoggerError::ResourceAccessBeforeFinalize) + } + + fn finalize_resources(&mut self, resources: ExecutionResources) -> OsLoggerResult<()> { + if self.get_optional_resources().is_some() { + return Err(OsLoggerError::DoubleFinalize); + } + self.set_resources(resources); + Ok(()) + } +} + +pub struct SyscallTrace { + selector: SyscallSelector, + is_deprecated: bool, + tab_count: usize, + inner_syscalls: Vec, + resources: Option, +} + +impl SyscallTrace { + pub fn new(selector: SyscallSelector, is_deprecated: bool, tab_count: usize) -> Self { + Self { selector, is_deprecated, tab_count, inner_syscalls: Vec::new(), resources: None } + } + + pub fn push_inner_syscall(&mut self, inner: SyscallTrace) { + self.inner_syscalls.push(inner); + } +} + +impl ResourceFinalizer for SyscallTrace { + fn get_optional_resources(&self) -> Option<&ExecutionResources> { + self.resources.as_ref() + } + + fn set_resources(&mut self, resources: ExecutionResources) { + self.resources = Some(resources); + } +} + +impl TryFrom<&SyscallTrace> for String { + type Error = OsLoggerError; + + fn try_from(trace: &SyscallTrace) -> OsLoggerResult { + let deprecated_prefix = if trace.is_deprecated { "deprecated " } else { "" }; + let indentation = " ".repeat(trace.tab_count + 1); + let resources = trace.get_resources()?; + + let builtins = if !resources.builtin_instance_counter.is_empty() { + format!("\n{indentation}Builtins: {:?}", resources.builtin_instance_counter) + } else { + "".to_string() + }; + + let inner_syscalls = if !trace.inner_syscalls.is_empty() { + // Count inner syscalls. + let mut syscall_count: HashMap = HashMap::new(); + for inner_syscall in &trace.inner_syscalls { + *syscall_count.entry(inner_syscall.selector).or_insert(0) += 1; + } + format!("\n{indentation}Inner syscalls: {syscall_count:?}") + } else { + "".to_string() + }; + + Ok(format!( + "{deprecated_prefix}Syscall: {:?}\n{indentation}Steps: {}{builtins}{inner_syscalls}", + trace.selector, resources.n_steps + )) + } +} + +pub struct OsTransactionTrace { + tx_type: TransactionType, + tx_hash: TransactionHash, + syscalls: Vec, + resources: Option, +} + +impl OsTransactionTrace { + pub fn new(tx_type: TransactionType, tx_hash: TransactionHash) -> Self { + Self { tx_type, tx_hash, syscalls: Vec::new(), resources: None } + } + + pub fn push_syscall(&mut self, syscall: SyscallTrace) { + self.syscalls.push(syscall); + } +} + +impl ResourceFinalizer for OsTransactionTrace { + fn get_optional_resources(&self) -> Option<&ExecutionResources> { + self.resources.as_ref() + } + + fn set_resources(&mut self, resources: ExecutionResources) { + self.resources = Some(resources); + } +} + +impl TryFrom<&OsTransactionTrace> for String { + type Error = OsLoggerError; + + fn try_from(trace: &OsTransactionTrace) -> OsLoggerResult { + let resources = trace.get_resources()?; + let builtins = if !resources.builtin_instance_counter.is_empty() { + format!("\n\tBuiltins: {:?}", resources.builtin_instance_counter) + } else { + "".to_string() + }; + Ok(format!( + "Transaction: {:?}\n\tHash: {}\n\tSteps: {}{builtins}", + trace.tx_type, trace.tx_hash, resources.n_steps + )) + } +} + +pub struct ResourceCounter { + n_steps: usize, + range_check_ptr: Relocatable, + builtin_ptrs_dict: HashMap, +} + +impl ResourceCounter { + pub(crate) fn new( + n_steps: usize, + range_check_ptr: Relocatable, + ids_data: &HashMap, + vm: &VirtualMachine, + ap_tracking: &ApTracking, + os_program: &Program, + ) -> OsLoggerResult { + Ok(Self { + n_steps, + range_check_ptr, + builtin_ptrs_dict: Self::build_builtin_ptrs_dict( + ids_data, + vm, + ap_tracking, + os_program, + )?, + }) + } + + pub fn sub_counter(&self, enter_counter: &Self) -> OsLoggerResult { + // Subtract pointers to count usage. + let mut builtins_count_ptr: HashMap = HashMap::new(); + for (builtin_name, builtin_ptr) in self.builtin_ptrs_dict.iter() { + let enter_counter_ptr = enter_counter + .builtin_ptrs_dict + .get(builtin_name) + .ok_or(OsLoggerError::MissingBuiltinPtr(builtin_name.to_str().to_string()))?; + let mut builtin_count = (*builtin_ptr - *enter_counter_ptr).map_err(|_error| { + OsLoggerError::BuiltinsNotInSameSegment { + builtin: *builtin_name, + self_ptr: *builtin_ptr, + enter_ptr: *enter_counter_ptr, + } + })?; + + // Adds the OS range_check resources of the current entry point. + if builtin_name == &BuiltinName::range_check { + builtin_count += + (self.range_check_ptr - enter_counter.range_check_ptr).map_err(|_error| { + OsLoggerError::RangeCheckNotInSameSegment { + self_ptr: self.range_check_ptr, + enter_ptr: enter_counter.range_check_ptr, + } + })?; + } + + // Divide by the builtin size to get the actual usage count. + let builtin_size = BUILTIN_INSTANCE_SIZES + .get(builtin_name) + .ok_or(OsLoggerError::UnknownBuiltinSize(builtin_name.to_str().to_string()))?; + builtin_count /= *builtin_size; + + builtins_count_ptr.insert(*builtin_name, builtin_count); + } + + Ok(ExecutionResources { + n_steps: self.n_steps - enter_counter.n_steps, + builtin_instance_counter: builtins_count_ptr, + n_memory_holes: 0, + }) + } + + fn build_builtin_ptrs_dict( + ids_data: &HashMap, + vm: &VirtualMachine, + ap_tracking: &ApTracking, + os_program: &Program, + ) -> OsLoggerResult> { + let mut builtin_ptrs_dict: HashMap = HashMap::new(); + + // The `BuiltinPointers` struct has two fields: selectable and non-selectable builtins. + Self::insert_builtins( + "selectable", + CairoStruct::SelectableBuiltins, + &mut builtin_ptrs_dict, + ids_data, + vm, + ap_tracking, + os_program, + )?; + Self::insert_builtins( + "non_selectable", + CairoStruct::NonSelectableBuiltins, + &mut builtin_ptrs_dict, + ids_data, + vm, + ap_tracking, + os_program, + )?; + + Ok(builtin_ptrs_dict) + } + + fn insert_builtins( + inner_field_name: &str, + inner_field_type: CairoStruct, + builtin_ptrs_dict: &mut HashMap, + ids_data: &HashMap, + vm: &VirtualMachine, + ap_tracking: &ApTracking, + os_program: &Program, + ) -> OsLoggerResult<()> { + // We want all pointers except `segment_arena` and `sha256`. + let excluded_builtins = ["segment_arena", "sha256"]; + let inner_struct_name: &str = inner_field_type.into(); + let inner_members = os_program + .get_identifier(inner_struct_name) + .ok_or(OsLoggerError::InnerBuiltinPtrsIdentifierMissing(inner_struct_name.into()))? + .members + .as_ref() + .ok_or(OsLoggerError::MissingMembers(inner_struct_name.into()))?; + + for member_name in inner_members.keys() { + if excluded_builtins.contains(&member_name.as_str()) { + continue; + } + let member_ptr = get_address_of_nested_fields( + ids_data, + Ids::BuiltinPtrs, + CairoStruct::BuiltinPointersPtr, + vm, + ap_tracking, + &[inner_field_name, member_name.as_str()], + os_program, + ) + .map_err(OsLoggerError::BuiltinPtrs)?; + builtin_ptrs_dict.insert( + BuiltinName::from_str(member_name) + .ok_or_else(|| OsLoggerError::UnknownBuiltin(member_name.clone()))?, + member_ptr, + ); + } + Ok(()) + } +} + +pub struct OsLogger { + debug: bool, + current_tx: Option, + tab_count: usize, + syscall_stack: Vec, + txs: Vec, + resource_counter_stack: Vec, +} + +impl OsLogger { + pub fn new(debug: bool) -> Self { + Self { + debug, + current_tx: None, + tab_count: 0, + syscall_stack: Vec::new(), + txs: Vec::new(), + resource_counter_stack: Vec::new(), + } + } + + pub fn log(&mut self, msg: &str, enter: bool) { + if self.debug { + if enter { + self.tab_count += 1; + } + let indentation = " ".repeat(self.tab_count); + log::debug!("{indentation}{msg}"); + if !enter { + self.tab_count -= 1; + } + } + } + + #[allow(clippy::too_many_arguments)] + pub fn enter_syscall( + &mut self, + selector: SyscallSelector, + is_deprecated: bool, + n_steps: usize, + range_check_ptr: Relocatable, + ids_data: &HashMap, + vm: &VirtualMachine, + ap_tracking: &ApTracking, + os_program: &Program, + ) -> OsLoggerResult<()> { + if self.current_tx.is_none() { + return Err(OsLoggerError::NotInTxContext); + } + + if let Some(last_call) = self.syscall_stack.last() { + if !last_call.selector.is_calling_syscall() { + return Err(OsLoggerError::UnexpectedParentSyscall(format!( + "{:?}", + last_call.selector + ))); + } + } + + self.resource_counter_stack.push(ResourceCounter::new( + n_steps, + range_check_ptr, + ids_data, + vm, + ap_tracking, + os_program, + )?); + self.syscall_stack.push(SyscallTrace::new(selector, is_deprecated, self.tab_count)); + + if selector.is_calling_syscall() { + let deprecated_str = if is_deprecated { "deprecated " } else { "" }; + self.log(&format!("Entering {deprecated_str}{:?}.", selector), true); + } + + Ok(()) + } + + #[allow(clippy::too_many_arguments)] + pub fn exit_syscall( + &mut self, + selector: SyscallSelector, + n_steps: usize, + range_check_ptr: Relocatable, + ids_data: &HashMap, + vm: &VirtualMachine, + ap_tracking: &ApTracking, + os_program: &Program, + ) -> OsLoggerResult<()> { + let mut current_syscall = self.syscall_stack.pop().ok_or(OsLoggerError::CallStackEmpty)?; + let enter_resources_counter = + self.resource_counter_stack.pop().ok_or(OsLoggerError::CallStackEmpty)?; + // A sanity check to ensure we store the syscall we work on. + if selector != current_syscall.selector { + return Err(OsLoggerError::UnexpectedSyscall { + actual: selector, + expected: current_syscall.selector, + }); + } + + let exit_resources_counter = + ResourceCounter::new(n_steps, range_check_ptr, ids_data, vm, ap_tracking, os_program)?; + + current_syscall + .finalize_resources(exit_resources_counter.sub_counter(&enter_resources_counter)?)?; + + if current_syscall.selector.is_calling_syscall() { + self.log(&format!("Exiting {}.", String::try_from(¤t_syscall)?), false); + } + + match self.syscall_stack.last_mut() { + Some(last_call) => { + last_call.push_inner_syscall(current_syscall); + } + None => { + self.current_tx + .as_mut() + .ok_or(OsLoggerError::NotInTxContext)? + .push_syscall(current_syscall); + } + } + + Ok(()) + } + + #[allow(clippy::too_many_arguments)] + pub fn enter_tx( + &mut self, + tx_type: TransactionType, + tx_hash: TransactionHash, + n_steps: usize, + range_check_ptr: Relocatable, + ids_data: &HashMap, + vm: &VirtualMachine, + ap_tracking: &ApTracking, + os_program: &Program, + ) -> OsLoggerResult<()> { + if self.current_tx.is_some() { + return Err(OsLoggerError::InTxContext); + } + self.resource_counter_stack.push(ResourceCounter::new( + n_steps, + range_check_ptr, + ids_data, + vm, + ap_tracking, + os_program, + )?); + self.current_tx = Some(OsTransactionTrace::new(tx_type, tx_hash)); + self.log(&format!("Entering {tx_type:?}: {tx_hash}."), true); + Ok(()) + } + + pub fn exit_tx( + &mut self, + n_steps: usize, + range_check_ptr: Relocatable, + ids_data: &HashMap, + vm: &VirtualMachine, + ap_tracking: &ApTracking, + os_program: &Program, + ) -> OsLoggerResult<()> { + let mut current_tx = self.current_tx.take().ok_or(OsLoggerError::ExitBeforeEnter)?; + + // Sanity check. + if !self.syscall_stack.is_empty() { + return Err(OsLoggerError::RemainingSyscalls); + } + + let enter_resources_counter = + self.resource_counter_stack.pop().ok_or(OsLoggerError::CallStackEmpty)?; + let exit_resources_counter = + ResourceCounter::new(n_steps, range_check_ptr, ids_data, vm, ap_tracking, os_program)?; + + current_tx + .finalize_resources(exit_resources_counter.sub_counter(&enter_resources_counter)?)?; + self.log(&format!("Exiting {}.", String::try_from(¤t_tx)?), false); + self.txs.push(current_tx); + Ok(()) + } +} diff --git a/crates/starknet_os/src/hint_processor/panicking_state_reader.rs b/crates/starknet_os/src/hint_processor/panicking_state_reader.rs new file mode 100644 index 00000000000..bb19b615097 --- /dev/null +++ b/crates/starknet_os/src/hint_processor/panicking_state_reader.rs @@ -0,0 +1,35 @@ +use blockifier::execution::contract_class::RunnableCompiledClass; +use blockifier::state::state_api::{StateReader, StateResult}; +use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; +use starknet_api::state::StorageKey; +use starknet_types_core::felt::Felt; + +/// State reader that always panics. +/// Use this as the `OsExecutionHelper`'s state reader to ensure the OS execution is "stateless". +pub struct PanickingStateReader; + +impl StateReader for PanickingStateReader { + fn get_storage_at( + &self, + contract_address: ContractAddress, + key: StorageKey, + ) -> StateResult { + panic!("Called get_storage_at with address {contract_address} and key {key:?}."); + } + + fn get_nonce_at(&self, contract_address: ContractAddress) -> StateResult { + panic!("Called get_nonce_at with address {contract_address}."); + } + + fn get_class_hash_at(&self, contract_address: ContractAddress) -> StateResult { + panic!("Called get_class_hash_at with address {contract_address}."); + } + + fn get_compiled_class(&self, class_hash: ClassHash) -> StateResult { + panic!("Called get_compiled_class with class hash {class_hash}."); + } + + fn get_compiled_class_hash(&self, class_hash: ClassHash) -> StateResult { + panic!("Called get_compiled_class_hash with class hash {class_hash}."); + } +} diff --git a/crates/starknet_os/src/hint_processor/snos_hint_processor.rs b/crates/starknet_os/src/hint_processor/snos_hint_processor.rs new file mode 100644 index 00000000000..b45c8e649a0 --- /dev/null +++ b/crates/starknet_os/src/hint_processor/snos_hint_processor.rs @@ -0,0 +1,176 @@ +use blockifier::state::state_api::StateReader; +#[cfg(any(feature = "testing", test))] +use blockifier::test_utils::dict_state_reader::DictStateReader; +use cairo_vm::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::{ + BuiltinHintProcessor, + HintProcessorData, +}; +use cairo_vm::hint_processor::hint_processor_definition::{HintExtension, HintProcessorLogic}; +use cairo_vm::stdlib::any::Any; +use cairo_vm::stdlib::boxed::Box; +use cairo_vm::stdlib::collections::HashMap; +use cairo_vm::types::exec_scope::ExecutionScopes; +#[cfg(any(feature = "testing", test))] +use cairo_vm::types::program::Program; +use cairo_vm::types::relocatable::Relocatable; +use cairo_vm::vm::errors::hint_errors::HintError as VmHintError; +use cairo_vm::vm::runners::cairo_runner::ResourceTracker; +use cairo_vm::vm::vm_core::VirtualMachine; +use starknet_types_core::felt::Felt; + +use crate::hint_processor::execution_helper::OsExecutionHelper; +use crate::hints::enum_definition::AllHints; +use crate::hints::error::OsHintError; +use crate::hints::types::{HintArgs, HintEnum, HintExtensionImplementation, HintImplementation}; +#[cfg(any(feature = "testing", test))] +use crate::io::os_input::StarknetOsInput; + +type VmHintResultType = Result; +type VmHintResult = VmHintResultType<()>; +type VmHintExtensionResult = VmHintResultType; + +pub struct SnosHintProcessor { + pub execution_helper: OsExecutionHelper, + pub syscall_hint_processor: SyscallHintProcessor, + _deprecated_syscall_hint_processor: DeprecatedSyscallHintProcessor, + builtin_hint_processor: BuiltinHintProcessor, + // KZG fields. + da_segment: Option>, +} + +impl SnosHintProcessor { + pub fn new( + execution_helper: OsExecutionHelper, + syscall_hint_processor: SyscallHintProcessor, + deprecated_syscall_hint_processor: DeprecatedSyscallHintProcessor, + ) -> Self { + Self { + execution_helper, + syscall_hint_processor, + _deprecated_syscall_hint_processor: deprecated_syscall_hint_processor, + da_segment: None, + builtin_hint_processor: BuiltinHintProcessor::new_empty(), + } + } + + /// Stores the data-availabilty segment, to be used for computing the KZG commitment in blob + /// mode. + pub(crate) fn set_da_segment(&mut self, da_segment: Vec) -> Result<(), OsHintError> { + if self.da_segment.is_some() { + return Err(OsHintError::AssertionFailed { + message: "DA segment is already initialized.".to_string(), + }); + } + self.da_segment = Some(da_segment); + Ok(()) + } +} + +impl HintProcessorLogic for SnosHintProcessor { + fn execute_hint( + &mut self, + _vm: &mut VirtualMachine, + _exec_scopes: &mut ExecutionScopes, + _hint_data: &Box, + _constants: &HashMap, + ) -> VmHintResult { + Ok(()) + } + + fn execute_hint_extensive( + &mut self, + vm: &mut VirtualMachine, + exec_scopes: &mut ExecutionScopes, + hint_data: &Box, + constants: &HashMap, + ) -> VmHintExtensionResult { + // OS hint, aggregator hint, Cairo0 syscall or Cairo0 core hint. + if let Some(hint_processor_data) = hint_data.downcast_ref::() { + let hint_args = HintArgs { + hint_processor: self, + vm, + exec_scopes, + ids_data: &hint_processor_data.ids_data, + ap_tracking: &hint_processor_data.ap_tracking, + constants, + }; + if let Ok(hint) = AllHints::from_str(hint_processor_data.code.as_str()) { + // OS hint, aggregator hint, Cairo0 syscall. + return match hint { + AllHints::OsHint(os_hint) => { + os_hint.execute_hint(hint_args)?; + Ok(HintExtension::default()) + } + AllHints::AggregatorHint(aggregator_hint) => { + aggregator_hint.execute_hint(hint_args)?; + Ok(HintExtension::default()) + } + AllHints::SyscallHint(syscall_hint) => { + syscall_hint.execute_hint(hint_args)?; + Ok(HintExtension::default()) + } + AllHints::HintExtension(hint_extension) => { + Ok(hint_extension.execute_hint_extensive(hint_args)?) + } + }; + } else { + // Cairo0 core hint. + self.builtin_hint_processor.execute_hint(vm, exec_scopes, hint_data, constants)?; + return Ok(HintExtension::default()); + } + } + + // Cairo1 syscall or Cairo1 core hint. + todo!() + } +} + +#[cfg(any(test, feature = "testing"))] +impl SnosHintProcessor { + pub fn new_for_testing( + state_reader: Option, + os_input: Option, + os_program: Option, + ) -> Self { + let state_reader = state_reader.unwrap_or_default(); + let os_input = os_input.unwrap_or_default(); + let os_program = os_program.unwrap_or_default(); + let execution_helper = OsExecutionHelper::::new_for_testing( + state_reader, + os_input, + os_program, + ); + + let syscall_handler = SyscallHintProcessor::new(); + let deprecated_syscall_handler = DeprecatedSyscallHintProcessor {}; + + SnosHintProcessor::new(execution_helper, syscall_handler, deprecated_syscall_handler) + } +} + +/// Default implementation (required for the VM to use the type as a hint processor). +impl ResourceTracker for SnosHintProcessor {} + +pub struct SyscallHintProcessor { + // Sha256 segments. + sha256_segment: Option, + syscall_ptr: Option, +} + +// TODO(Dori): remove this #[allow] after the constructor is no longer trivial. +#[allow(clippy::new_without_default)] +impl SyscallHintProcessor { + pub fn new() -> Self { + Self { sha256_segment: None, syscall_ptr: None } + } + + pub fn set_sha256_segment(&mut self, sha256_segment: Relocatable) { + self.sha256_segment = Some(sha256_segment); + } + + pub fn set_syscall_ptr(&mut self, syscall_ptr: Relocatable) { + self.syscall_ptr = Some(syscall_ptr); + } +} + +pub struct DeprecatedSyscallHintProcessor; diff --git a/crates/starknet_os/src/hints.rs b/crates/starknet_os/src/hints.rs new file mode 100644 index 00000000000..1121106f5df --- /dev/null +++ b/crates/starknet_os/src/hints.rs @@ -0,0 +1,8 @@ +pub mod class_hash; +pub mod enum_definition; +pub mod enum_generation; +pub mod error; +pub(crate) mod hint_implementation; +pub(crate) mod nondet_offsets; +pub mod types; +pub mod vars; diff --git a/crates/starknet_os/src/hints/class_hash.rs b/crates/starknet_os/src/hints/class_hash.rs new file mode 100644 index 00000000000..42139adc60c --- /dev/null +++ b/crates/starknet_os/src/hints/class_hash.rs @@ -0,0 +1,3 @@ +pub mod hinted_class_hash; +#[cfg(test)] +mod hinted_class_hash_test; diff --git a/crates/starknet_os/src/hints/class_hash/hinted_class_hash.rs b/crates/starknet_os/src/hints/class_hash/hinted_class_hash.rs new file mode 100644 index 00000000000..08d1fde6d32 --- /dev/null +++ b/crates/starknet_os/src/hints/class_hash/hinted_class_hash.rs @@ -0,0 +1,117 @@ +use std::borrow::Cow; +use std::collections::{BTreeMap, HashMap}; +use std::io::Write; + +use papyrus_common::python_json::PythonJsonFormatter; +use serde::{Deserialize, Serialize}; +use sha3::digest::Digest; +use starknet_api::contract_class::EntryPointType; +use starknet_api::deprecated_contract_class::EntryPointV0; +use starknet_api::state::truncated_keccak; +use starknet_types_core::felt::Felt; + +use crate::hints::error::OsHintError; + +/// Our version of the cairo contract definition used to deserialize and re-serialize a modified +/// version for a hash of the contract definition. +/// +/// The implementation uses `serde_json::Value` extensively for the unknown/undefined structure, and +/// the correctness of this implementation depends on the following features of serde_json: +/// +/// - feature `raw_value` has to be enabled for the thrown away `program.debug_info` +/// - feature `preserve_order` has to be disabled, as we want everything sorted +/// - feature `arbitrary_precision` has to be enabled, as there are big integers in the input +// TODO(Yoav): For more efficiency, have only borrowed types of serde_json::Value. +#[derive(Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub struct CairoContractDefinition<'a> { + /// Contract ABI, which has no schema definition. + pub abi: serde_json::Value, + + /// Main program definition. + #[serde(borrow)] + pub program: CairoProgram<'a>, + + /// The contract entry points. + /// + /// These are left out of the re-serialized version with the ordering requirement to a + /// Keccak256 hash. + #[serde(skip_serializing)] + pub entry_points_by_type: HashMap>, +} + +// It's important that this is ordered alphabetically because the fields need to be in sorted order +// for the keccak hashed representation. +#[derive(Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub struct CairoProgram<'a> { + #[serde(skip_serializing_if = "Vec::is_empty", default)] + pub attributes: Vec, + + #[serde(borrow)] + pub builtins: Vec>, + + // Added in Starknet 0.10, so we have to handle this not being present. + #[serde(borrow, skip_serializing_if = "Option::is_none")] + pub compiler_version: Option>, + + #[serde(borrow)] + pub data: Vec>, + + #[serde(borrow)] + pub debug_info: Option<&'a serde_json::value::RawValue>, + + // Important that this is ordered by the numeric keys, not lexicographically + pub hints: BTreeMap>, + + pub identifiers: serde_json::Value, + + #[serde(borrow)] + pub main_scope: Cow<'a, str>, + + // Unlike most other integers, this one is hex string. We don't need to interpret it, it just + // needs to be part of the hashed output. + #[serde(borrow)] + pub prime: Cow<'a, str>, + + pub reference_manager: serde_json::Value, +} + +/// `std::io::Write` adapter for Keccak256; we don't need the serialized version in +/// compute_class_hash, but we need the truncated_keccak hash. +/// +/// When debugging mismatching hashes, it might be useful to check the length of each before trying +/// to find the wrongly serialized spot. Example length > 500kB. +#[derive(Default)] +struct KeccakWriter(sha3::Keccak256); + +impl std::io::Write for KeccakWriter { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + self.0.update(buf); + Ok(buf.len()) + } + + fn flush(&mut self) -> std::io::Result<()> { + // noop is fine, we'll finalize after the write phase. + Ok(()) + } +} + +pub fn compute_cairo_hinted_class_hash( + contract_definition: &CairoContractDefinition<'_>, +) -> Result { + let mut string_buffer = vec![]; + + let mut ser = serde_json::Serializer::with_formatter(&mut string_buffer, PythonJsonFormatter); + contract_definition.serialize(&mut ser)?; + + let raw_json_output = String::from_utf8(string_buffer)?; + + let mut keccak_writer = KeccakWriter::default(); + keccak_writer + .write_all(raw_json_output.as_bytes()) + .expect("writing to KeccakWriter never fails"); + + let KeccakWriter(hash) = keccak_writer; + Ok(truncated_keccak(<[u8; 32]>::from(hash.finalize()))) +} diff --git a/crates/starknet_os/src/hints/class_hash/hinted_class_hash_test.rs b/crates/starknet_os/src/hints/class_hash/hinted_class_hash_test.rs new file mode 100644 index 00000000000..14130c542ca --- /dev/null +++ b/crates/starknet_os/src/hints/class_hash/hinted_class_hash_test.rs @@ -0,0 +1,31 @@ +use std::env::current_dir; +use std::fs::File; +use std::io::Read; + +use starknet_types_core::felt::Felt; + +use crate::hints::class_hash::hinted_class_hash::{ + compute_cairo_hinted_class_hash, + CairoContractDefinition, +}; + +// The contract and the expected hash are taken from the python side. +#[test] +fn test_compute_cairo_hinted_class_hash() { + let contract_path = current_dir().unwrap().join("resources/legacy_contract.json"); + let mut file = File::open(&contract_path) + .unwrap_or_else(|_| panic!("Unable to open file {contract_path:?}")); + let mut data = String::new(); + file.read_to_string(&mut data) + .unwrap_or_else(|_| panic!("Unable to read file {contract_path:?}")); + + let contract_definition: CairoContractDefinition<'_> = + serde_json::from_str(&data).expect("JSON was not well-formatted"); + let computed_hash = compute_cairo_hinted_class_hash(&contract_definition) + .expect("Failed to compute class hash"); + + let expected_hash = Felt::from_hex_unchecked( + "0x1DBF36F651C9917E703BF6932FA4E866BFB6BCBFF18765F769CA9401C2CAF4F", + ); + assert_eq!(computed_hash, expected_hash, "Computed hash does not match expected hash"); +} diff --git a/crates/starknet_os/src/hints/enum_definition.rs b/crates/starknet_os/src/hints/enum_definition.rs new file mode 100644 index 00000000000..9c779facb03 --- /dev/null +++ b/crates/starknet_os/src/hints/enum_definition.rs @@ -0,0 +1,1885 @@ +use blockifier::state::state_api::StateReader; +use indoc::indoc; +#[cfg(any(test, feature = "testing"))] +use strum::IntoEnumIterator; + +use crate::hints::error::{OsHintError, OsHintExtensionResult, OsHintResult}; +use crate::hints::hint_implementation::aggregator::{ + allocate_segments_for_messages, + disable_da_page_creation, + get_aggregator_output, + get_full_output_from_input, + get_os_output_for_inner_blocks, + get_use_kzg_da_from_input, + set_state_update_pointers_to_none, + write_da_segment, +}; +use crate::hints::hint_implementation::block_context::{ + block_number, + block_timestamp, + chain_id, + fee_token_address, + get_block_mapping, + sequencer_address, + write_use_kzg_da_to_memory, +}; +use crate::hints::hint_implementation::bls_field::compute_ids_low; +use crate::hints::hint_implementation::builtins::{ + select_builtin, + selected_builtins, + update_builtin_ptrs, +}; +use crate::hints::hint_implementation::cairo1_revert::{ + generate_dummy_os_output_segment, + prepare_state_entry_for_revert, + read_storage_key_for_revert, + write_storage_key_for_revert, +}; +use crate::hints::hint_implementation::compiled_class::implementation::{ + assert_end_of_bytecode_segments, + assign_bytecode_segments, + bytecode_segment_structure, + delete_memory_data, + is_leaf, + iter_current_segment_info, + load_class, + load_class_inner, + set_ap_to_segment_hash, + validate_compiled_class_facts_post_execution, +}; +use crate::hints::hint_implementation::deprecated_compiled_class::implementation::{ + load_deprecated_class, + load_deprecated_class_facts, + load_deprecated_class_inner, +}; +use crate::hints::hint_implementation::execute_syscalls::is_block_number_in_block_hash_buffer; +use crate::hints::hint_implementation::execute_transactions::{ + fill_holes_in_rc96_segment, + log_remaining_txs, + os_input_transactions, + segments_add, + segments_add_temp, + set_ap_to_actual_fee, + set_component_hashes, + set_sha256_segment_in_syscall_handler, + sha2_finalize, + skip_tx, + start_tx, +}; +use crate::hints::hint_implementation::execution::implementation::{ + assert_transaction_hash, + cache_contract_storage_request_key, + cache_contract_storage_syscall_request_address, + check_execution, + check_is_deprecated, + check_new_deploy_response, + check_new_syscall_response, + check_syscall_response, + contract_address, + declare_tx_fields, + end_tx, + enter_call, + enter_scope_deprecated_syscall_handler, + enter_scope_descend_edge, + enter_scope_left_child, + enter_scope_new_node, + enter_scope_next_node_bit_0, + enter_scope_next_node_bit_1, + enter_scope_node, + enter_scope_right_child, + enter_scope_syscall_handler, + enter_syscall_scopes, + exit_call, + exit_tx, + fetch_result, + gen_signature_arg, + get_block_hash_contract_address_state_entry_and_set_new_state_entry, + get_contract_address_state_entry, + get_contract_address_state_entry_and_set_new_state_entry, + get_old_block_number_and_hash, + initial_ge_required_gas, + is_deprecated, + is_remaining_gas_lt_initial_budget, + is_reverted, + load_next_tx, + load_resource_bounds, + log_enter_syscall, + prepare_constructor_execution, + set_ap_to_tx_nonce, + set_fp_plus_4_to_tx_nonce, + set_state_entry_to_account_contract_address, + tx_account_deployment_data, + tx_account_deployment_data_len, + tx_calldata, + tx_calldata_len, + tx_entry_point_selector, + tx_fee_data_availability_mode, + tx_nonce_data_availability_mode, + tx_paymaster_data, + tx_paymaster_data_len, + tx_tip, + tx_version, + write_old_block_to_storage, + write_syscall_result, + write_syscall_result_deprecated, +}; +use crate::hints::hint_implementation::find_element::search_sorted_optimistic; +use crate::hints::hint_implementation::kzg::implementation::{ + store_da_segment, + write_split_result, +}; +use crate::hints::hint_implementation::math::log2_ceil; +use crate::hints::hint_implementation::os::{ + configure_kzg_manager, + create_block_additional_hints, + get_n_blocks, + init_state_update_pointer, + initialize_class_hashes, + initialize_state_changes, + set_ap_to_new_block_hash, + set_ap_to_prev_block_hash, + starknet_os_input, + write_full_output_to_memory, +}; +use crate::hints::hint_implementation::os_logger::{ + os_logger_enter_syscall_prepare_exit_syscall, + os_logger_exit_syscall, +}; +use crate::hints::hint_implementation::output::{ + set_compressed_start, + set_n_updates_small, + set_state_updates_start, + set_tree_structure, +}; +use crate::hints::hint_implementation::patricia::implementation::{ + assert_case_is_right, + build_descent_map, + height_is_zero_or_len_node_preimage_is_two, + is_case_right, + prepare_preimage_validation_non_deterministic_hashes, + set_ap_to_descend, + set_bit, + set_siblings, + split_descend, + write_case_not_left_to_ap, +}; +use crate::hints::hint_implementation::resources::{ + debug_expected_initial_gas, + is_sierra_gas_mode, + remaining_gas_gt_max, +}; +use crate::hints::hint_implementation::secp::{is_on_curve, read_ec_point_from_address}; +use crate::hints::hint_implementation::state::{ + decode_node, + load_bottom, + load_edge, + set_preimage_for_class_commitments, + set_preimage_for_current_commitment_info, + set_preimage_for_state_commitments, +}; +use crate::hints::hint_implementation::stateful_compression::{ + assert_key_big_enough_for_alias, + compute_commitments_on_finalized_state_with_aliases, + contract_address_le_max_for_compression, + enter_scope_with_aliases, + guess_aliases_contract_storage_ptr, + guess_classes_ptr, + guess_contract_addr_storage_ptr, + guess_state_ptr, + initialize_alias_counter, + key_lt_min_alias_alloc_value, + read_alias_counter, + read_alias_from_key, + update_alias_counter, + update_aliases_contract_to_storage_ptr, + update_classes_ptr, + update_contract_addr_to_storage_ptr, + update_state_ptr, + write_next_alias_from_key, +}; +use crate::hints::hint_implementation::stateless_compression::implementation::{ + compression_hint, + dictionary_from_bucket, + get_prev_offset, + set_decompressed_dst, +}; +use crate::hints::hint_implementation::syscalls::{ + call_contract, + delegate_call, + delegate_l1_handler, + deploy, + emit_event, + get_block_number, + get_block_timestamp, + get_caller_address, + get_contract_address, + get_sequencer_address, + get_tx_info, + get_tx_signature, + library_call, + library_call_l1_handler, + replace_class, + send_message_to_l1, + set_syscall_ptr, + storage_read, + storage_write, +}; +use crate::hints::types::{HintArgs, HintEnum, HintExtensionImplementation, HintImplementation}; +use crate::{define_hint_enum, define_hint_extension_enum}; + +#[cfg(test)] +#[path = "enum_definition_test.rs"] +pub mod test; + +macro_rules! all_hints_enum { + ($($inner_enum:ident),+) => { + #[cfg_attr(any(test, feature = "testing"), derive(strum_macros::EnumIter))] + #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] + pub enum AllHints { + $($inner_enum($inner_enum)),+ + } + + #[cfg(any(test, feature = "testing"))] + impl AllHints { + pub fn all_iter() -> impl Iterator { + Self::iter().flat_map(|default_inner_variant| match default_inner_variant { + $( + Self::$inner_enum(_) => { + $inner_enum::iter().map(Self::from).collect::>() + } + )+ + }) + } + } + + impl HintEnum for AllHints { + fn from_str(hint_str: &str) -> Result { + $( + if let Ok(hint) = $inner_enum::from_str(hint_str) { + return Ok(hint.into()) + } + )+ + Err(OsHintError::UnknownHint(hint_str.to_string())) + } + + fn to_str(&self) -> &'static str { + match self { + $(Self::$inner_enum(hint) => hint.to_str(),)+ + } + } + } + } +} + +all_hints_enum!(SyscallHint, OsHint, HintExtension, AggregatorHint); + +define_hint_enum!( + SyscallHint, + ( + CallContract, + call_contract, + "syscall_handler.call_contract(segments=segments, syscall_ptr=ids.syscall_ptr)" + ), + ( + DelegateCall, + delegate_call, + "syscall_handler.delegate_call(segments=segments, syscall_ptr=ids.syscall_ptr)" + ), + ( + DelegateL1Handler, + delegate_l1_handler, + "syscall_handler.delegate_l1_handler(segments=segments, syscall_ptr=ids.syscall_ptr)" + ), + (Deploy, deploy, "syscall_handler.deploy(segments=segments, syscall_ptr=ids.syscall_ptr)"), + ( + EmitEvent, + emit_event, + "syscall_handler.emit_event(segments=segments, syscall_ptr=ids.syscall_ptr)" + ), + ( + GetBlockNumber, + get_block_number, + "syscall_handler.get_block_number(segments=segments, syscall_ptr=ids.syscall_ptr)" + ), + ( + GetBlockTimestamp, + get_block_timestamp, + "syscall_handler.get_block_timestamp(segments=segments, syscall_ptr=ids.syscall_ptr)" + ), + ( + GetCallerAddress, + get_caller_address, + "syscall_handler.get_caller_address(segments=segments, syscall_ptr=ids.syscall_ptr)" + ), + ( + GetContractAddress, + get_contract_address, + "syscall_handler.get_contract_address(segments=segments, syscall_ptr=ids.syscall_ptr)" + ), + ( + GetSequencerAddress, + get_sequencer_address, + "syscall_handler.get_sequencer_address(segments=segments, syscall_ptr=ids.syscall_ptr)" + ), + ( + GetTxInfo, + get_tx_info, + "syscall_handler.get_tx_info(segments=segments, syscall_ptr=ids.syscall_ptr)" + ), + ( + GetTxSignature, + get_tx_signature, + "syscall_handler.get_tx_signature(segments=segments, syscall_ptr=ids.syscall_ptr)" + ), + ( + LibraryCall, + library_call, + "syscall_handler.library_call(segments=segments, syscall_ptr=ids.syscall_ptr)" + ), + ( + LibraryCallL1Handler, + library_call_l1_handler, + "syscall_handler.library_call_l1_handler(segments=segments, syscall_ptr=ids.syscall_ptr)" + ), + ( + ReplaceClass, + replace_class, + "syscall_handler.replace_class(segments=segments, syscall_ptr=ids.syscall_ptr)" + ), + ( + SendMessageToL1, + send_message_to_l1, + "syscall_handler.send_message_to_l1(segments=segments, syscall_ptr=ids.syscall_ptr)" + ), + ( + StorageRead, + storage_read, + "syscall_handler.storage_read(segments=segments, syscall_ptr=ids.syscall_ptr)" + ), + ( + StorageWrite, + storage_write, + "syscall_handler.storage_write(segments=segments, syscall_ptr=ids.syscall_ptr)" + ), +); + +define_hint_enum!( + OsHint, + ( + IsBlockNumberInBlockHashBuffer, + is_block_number_in_block_hash_buffer, + // CHANGED: whitespaces. + r#"memory[ap] = to_felt_or_relocatable(ids.request_block_number > \ + ids.current_block_number - ids.STORED_BLOCK_HASH_BUFFER)"# + ), + ( + LoadClass, + load_class, + indoc! {r#" + vm_exit_scope() + + computed_hash = ids.hash + expected_hash = ids.compiled_class_fact.hash + assert computed_hash == expected_hash, ( + "Computed compiled_class_hash is inconsistent with the hash in the os_input. " + f"Computed hash = {computed_hash}, Expected hash = {expected_hash}.")"# + } + ), + ( + BytecodeSegmentStructure, + bytecode_segment_structure, + indoc! {r#" + vm_enter_scope({ + "bytecode_segment_structure": bytecode_segment_structures[ids.compiled_class_fact.hash], + "is_segment_used_callback": is_segment_used_callback + })"#} + ), + ( + BlockNumber, + block_number, + "memory[ap] = to_felt_or_relocatable(syscall_handler.block_info.block_number)" + ), + ( + BlockTimestamp, + block_timestamp, + "memory[ap] = to_felt_or_relocatable(syscall_handler.block_info.block_timestamp)" + ), + // TODO(Meshi): Fix hint implantation. + ( + ChainId, + chain_id, + "memory[ap] = to_felt_or_relocatable(block_input.general_config.chain_id.value)" + ), + // TODO(Meshi): Fix hint implantation. + ( + FeeTokenAddress, + fee_token_address, + "memory[ap] = to_felt_or_relocatable(block_input.general_config.fee_token_address)" + ), + ( + SequencerAddress, + sequencer_address, + "memory[ap] = to_felt_or_relocatable(syscall_handler.block_info.sequencer_address)" + ), + ( + GetBlockMapping, + get_block_mapping, + indoc! {r#" + ids.state_entry = __dict_manager.get_dict(ids.contract_state_changes)[ + ids.BLOCK_HASH_CONTRACT_ADDRESS + ]"#} + ), + ( + IsLeaf, + is_leaf, + indoc! {r#" + from starkware.starknet.core.os.contract_class.compiled_class_hash_objects import ( + BytecodeLeaf, + ) + ids.is_leaf = 1 if isinstance(bytecode_segment_structure, BytecodeLeaf) else 0"#} + ), + // TODO(Meshi): Fix hint implantation. + ( + WriteUseKzgDaToMemory, + write_use_kzg_da_to_memory, + indoc! {r#"memory[fp + 19] = to_felt_or_relocatable(syscall_handler.block_info.use_kzg_da and ( + not os_hints_config.full_output +))"#} + ), + ( + ComputeIdsLow, + compute_ids_low, + indoc! {r#" + ids.low = (ids.value.d0 + ids.value.d1 * ids.BASE) & ((1 << 128) - 1)"# + } + ), + ( + SelectedBuiltins, + selected_builtins, + "vm_enter_scope({'n_selected_builtins': ids.n_selected_builtins})" + ), + ( + SelectBuiltin, + select_builtin, + indoc! {r##" + # A builtin should be selected iff its encoding appears in the selected encodings list + # and the list wasn't exhausted. + # Note that testing inclusion by a single comparison is possible since the lists are sorted. + ids.select_builtin = int( + n_selected_builtins > 0 and memory[ids.selected_encodings] == memory[ids.all_encodings]) + if ids.select_builtin: + n_selected_builtins = n_selected_builtins - 1"## + } + ), + ( + UpdateBuiltinPtrs, + update_builtin_ptrs, + indoc! {r#" + from starkware.starknet.core.os.os_utils import update_builtin_pointers + + # Fill the values of all builtin pointers after the current transaction. + ids.return_builtin_ptrs = segments.gen_arg( + update_builtin_pointers( + memory=memory, + n_builtins=ids.n_builtins, + builtins_encoding_addr=ids.builtin_params.builtin_encodings.address_, + n_selected_builtins=ids.n_selected_builtins, + selected_builtins_encoding_addr=ids.selected_encodings, + orig_builtin_ptrs_addr=ids.builtin_ptrs.selectable.address_, + selected_builtin_ptrs_addr=ids.selected_ptrs, + ), + )"# + } + ), + ( + PrepareStateEntryForRevert, + prepare_state_entry_for_revert, + indoc! {r#"# Fetch a state_entry in this hint and validate it in the update that comes next. + ids.state_entry = __dict_manager.get_dict(ids.contract_state_changes)[ids.contract_address] + + # Fetch the relevant storage. + storage = execution_helper.storage_by_address[ids.contract_address]"#} + ), + ( + ReadStorageKeyForRevert, + read_storage_key_for_revert, + "memory[ap] = to_felt_or_relocatable(storage.read(key=ids.storage_key))" + ), + ( + WriteStorageKeyForRevert, + write_storage_key_for_revert, + "storage.write(key=ids.storage_key, value=ids.value)" + ), + ( + GenerateDummyOsOutputSegment, + generate_dummy_os_output_segment, + "memory[ap] = to_felt_or_relocatable(segments.gen_arg([[], 0]))" + ), + ( + AssignBytecodeSegments, + assign_bytecode_segments, + indoc! {r#" + bytecode_segments = iter(bytecode_segment_structure.segments)"# + } + ), + ( + AssertEndOfBytecodeSegments, + assert_end_of_bytecode_segments, + indoc! {r#" + assert next(bytecode_segments, None) is None"# + } + ), + ( + DeleteMemoryData, + delete_memory_data, + indoc! {r#" + # Sanity check. + assert not is_accessed(ids.data_ptr), "The segment is skipped but was accessed." + del memory.data[ids.data_ptr]"# + } + ), + ( + IterCurrentSegmentInfo, + iter_current_segment_info, + indoc! {r#" + current_segment_info = next(bytecode_segments) + + is_used = is_segment_used_callback(ids.data_ptr, current_segment_info.segment_length) + ids.is_segment_used = 1 if is_used else 0 + + is_used_leaf = is_used and isinstance(current_segment_info.inner_structure, BytecodeLeaf) + ids.is_used_leaf = 1 if is_used_leaf else 0 + + ids.segment_length = current_segment_info.segment_length + vm_enter_scope(new_scope_locals={ + "bytecode_segment_structure": current_segment_info.inner_structure, + "is_segment_used_callback": is_segment_used_callback + })"# + } + ), + ( + SetApToSegmentHash, + set_ap_to_segment_hash, + indoc! {r#" + memory[ap] = to_felt_or_relocatable(bytecode_segment_structure.hash())"# + } + ), + ( + ValidateCompiledClassFactsPostExecution, + validate_compiled_class_facts_post_execution, + indoc! {r#" + from starkware.starknet.core.os.contract_class.compiled_class_hash import ( + BytecodeAccessOracle, + ) + + # Build the bytecode segment structures. + bytecode_segment_structures = { + compiled_hash: create_bytecode_segment_structure( + bytecode=compiled_class.bytecode, + bytecode_segment_lengths=compiled_class.bytecode_segment_lengths, + ) for compiled_hash, compiled_class in os_input.compiled_classes.items() + } + bytecode_segment_access_oracle = BytecodeAccessOracle(is_pc_accessed_callback=is_accessed) + vm_enter_scope({ + "bytecode_segment_structures": bytecode_segment_structures, + "is_segment_used_callback": bytecode_segment_access_oracle.is_segment_used + })"#} + ), + // TODO(Meshi): Fix hint implantation. + ( + EnterScopeWithAliases, + enter_scope_with_aliases, + indoc! {r#"from starkware.starknet.definitions.constants import ALIAS_CONTRACT_ADDRESS + +# This hint shouldn't be whitelisted. +vm_enter_scope(dict( + state_update_pointers=state_update_pointers, + aliases=execution_helper.storage_by_address[ALIAS_CONTRACT_ADDRESS], + execution_helper=execution_helper, + __dict_manager=__dict_manager, + block_input=block_input, +))"#} + ), + ( + KeyLtMinAliasAllocValue, + key_lt_min_alias_alloc_value, + "memory[ap] = to_felt_or_relocatable(ids.key < ids.MIN_VALUE_FOR_ALIAS_ALLOC)" + ), + ( + AssertKeyBigEnoughForAlias, + assert_key_big_enough_for_alias, + r#"assert ids.key >= ids.MIN_VALUE_FOR_ALIAS_ALLOC, f"Key {ids.key} is too small.""# + ), + ( + ReadAliasFromKey, + read_alias_from_key, + "memory[fp + 0] = to_felt_or_relocatable(aliases.read(key=ids.key))" + ), + ( + WriteNextAliasFromKey, + write_next_alias_from_key, + "aliases.write(key=ids.key, value=ids.next_available_alias)" + ), + ( + ReadAliasCounter, + read_alias_counter, + "memory[ap] = to_felt_or_relocatable(aliases.read(key=ids.ALIAS_COUNTER_STORAGE_KEY))" + ), + ( + InitializeAliasCounter, + initialize_alias_counter, + "aliases.write(key=ids.ALIAS_COUNTER_STORAGE_KEY, value=ids.INITIAL_AVAILABLE_ALIAS)" + ), + ( + UpdateAliasCounter, + update_alias_counter, + "aliases.write(key=ids.ALIAS_COUNTER_STORAGE_KEY, value=ids.next_available_alias)" + ), + ( + ContractAddressLeMaxForCompression, + contract_address_le_max_for_compression, + "memory[ap] = to_felt_or_relocatable(ids.contract_address <= \ + ids.MAX_NON_COMPRESSED_CONTRACT_ADDRESS)" + ), + ( + ComputeCommitmentsOnFinalizedStateWithAliases, + compute_commitments_on_finalized_state_with_aliases, + "commitment_info_by_address=execution_helper.compute_storage_commitments()" + ), + ( + GuessContractAddrStoragePtr, + guess_contract_addr_storage_ptr, + r#"if state_update_pointers is None: + ids.squashed_storage_ptr = segments.add() + ids.squashed_prev_state = segments.add() +else: + ids.squashed_prev_state, ids.squashed_storage_ptr = ( + state_update_pointers.get_contract_state_entry_and_storage_ptr( + contract_address=ids.state_changes.key + ) + )"# + ), + ( + UpdateContractAddrToStoragePtr, + update_contract_addr_to_storage_ptr, + "if state_update_pointers is not None: + state_update_pointers.contract_address_to_state_entry_and_storage_ptr[ + ids.state_changes.key + ] = ( + ids.squashed_new_state.address_, + ids.squashed_storage_ptr_end.address_, + )" + ), + ( + GuessAliasesContractStoragePtr, + guess_aliases_contract_storage_ptr, + r#"if state_update_pointers is None: + ids.squashed_aliases_storage_start = segments.add() + ids.prev_aliases_state_entry = segments.add() +else: + ids.prev_aliases_state_entry, ids.squashed_aliases_storage_start = ( + state_update_pointers.get_contract_state_entry_and_storage_ptr( + ids.ALIAS_CONTRACT_ADDRESS + ) + )"# + ), + ( + UpdateAliasesContractToStoragePtr, + update_aliases_contract_to_storage_ptr, + "if state_update_pointers is not None: + state_update_pointers.contract_address_to_state_entry_and_storage_ptr[ + ids.ALIAS_CONTRACT_ADDRESS + ] = ( + ids.new_aliases_state_entry.address_, + ids.squashed_aliases_storage_end.address_, + )" + ), + ( + GuessStatePtr, + guess_state_ptr, + "if state_update_pointers is None: + ids.final_squashed_contract_state_changes_start = segments.add() +else: + ids.final_squashed_contract_state_changes_start = ( + state_update_pointers.state_tree_ptr + )" + ), + ( + UpdateStatePtr, + update_state_ptr, + "if state_update_pointers is not None: + state_update_pointers.state_tree_ptr = ( + ids.final_squashed_contract_state_changes_end.address_ + )" + ), + ( + GuessClassesPtr, + guess_classes_ptr, + "if state_update_pointers is None: + ids.squashed_dict = segments.add() +else: + ids.squashed_dict = state_update_pointers.class_tree_ptr" + ), + ( + UpdateClassesPtr, + update_classes_ptr, + "if state_update_pointers is not None: + state_update_pointers.class_tree_ptr = ids.squashed_dict_end.address_" + ), + ( + DictionaryFromBucket, + dictionary_from_bucket, + indoc! { + r#"initial_dict = {bucket_index: 0 for bucket_index in range(ids.TOTAL_N_BUCKETS)}"# + } + ), + ( + GetPrevOffset, + get_prev_offset, + indoc! {r#"dict_tracker = __dict_manager.get_tracker(ids.dict_ptr) + ids.prev_offset = dict_tracker.data[ids.bucket_index]"# + } + ), + ( + CompressionHint, + compression_hint, + indoc! {r#"from starkware.starknet.core.os.data_availability.compression import compress + data = memory.get_range_as_ints(addr=ids.data_start, size=ids.data_end - ids.data_start) + segments.write_arg(ids.compressed_dst, compress(data))"#} + ), + ( + SetDecompressedDst, + set_decompressed_dst, + indoc! {r#"memory[ids.decompressed_dst] = ids.packed_felt % ids.elm_bound"# + } + ), + ( + LoadDeprecatedClassFacts, + load_deprecated_class_facts, + indoc! {r##" + # Creates a set of deprecated class hashes to distinguish calls to deprecated entry points. + __deprecated_class_hashes=set(os_input.deprecated_compiled_classes.keys()) + ids.n_compiled_class_facts = len(os_input.deprecated_compiled_classes) + vm_enter_scope({ + 'compiled_class_facts': iter(os_input.deprecated_compiled_classes.items()), + })"## + } + ), + ( + LoadDeprecatedClassInner, + load_deprecated_class_inner, + indoc! {r#" + from starkware.starknet.core.os.contract_class.deprecated_class_hash import ( + get_deprecated_contract_class_struct, + ) + + compiled_class_hash, compiled_class = next(compiled_class_facts) + + cairo_contract = get_deprecated_contract_class_struct( + identifiers=ids._context.identifiers, contract_class=compiled_class) + ids.compiled_class = segments.gen_arg(cairo_contract)"# + } + ), + ( + SegmentsAddTemp, + segments_add_temp, + indoc! {r#"memory[fp + 7] = to_felt_or_relocatable(segments.add_temp_segment())"# + } + ), + (StartTx, start_tx, indoc! {r#"execution_helper.start_tx()"# }), + // TODO(Meshi): Fix hint implantation. + ( + OsInputTransactions, + os_input_transactions, + indoc! {r#"memory[fp + 12] = to_felt_or_relocatable(len(block_input.transactions))"# + } + ), + ( + SegmentsAdd, + segments_add, + indoc! {r#"memory[ap] = to_felt_or_relocatable(segments.add())"# + } + ), + ( + SetApToActualFee, + set_ap_to_actual_fee, + indoc! { + r#"memory[ap] = to_felt_or_relocatable(execution_helper.tx_execution_info.actual_fee)"# + } + ), + ( + SkipTx, + skip_tx, + indoc! {r#"execution_helper.skip_tx()"# + } + ), + ( + SetSha256SegmentInSyscallHandler, + set_sha256_segment_in_syscall_handler, + indoc! {r#"syscall_handler.sha256_segment = ids.sha256_ptr"#} + ), + ( + LogRemainingTxs, + log_remaining_txs, + indoc! {r#"print(f"execute_transactions_inner: {ids.n_txs} transactions remaining.")"#} + ), + ( + FillHolesInRc96Segment, + fill_holes_in_rc96_segment, + indoc! {r#" +rc96_ptr = ids.range_check96_ptr +segment_size = rc96_ptr.offset +base = rc96_ptr - segment_size + +for i in range(segment_size): + memory.setdefault(base + i, 0)"#} + ), + ( + SetComponentHashes, + set_component_hashes, + indoc! {r#" +class_component_hashes = component_hashes[tx.class_hash] +assert ( + len(class_component_hashes) == ids.ContractClassComponentHashes.SIZE +), "Wrong number of class component hashes." +ids.contract_class_component_hashes = segments.gen_arg(class_component_hashes)"# + } + ), + ( + Sha2Finalize, + sha2_finalize, + indoc! {r#"# Add dummy pairs of input and output. +from starkware.cairo.common.cairo_sha256.sha256_utils import ( + IV, + compute_message_schedule, + sha2_compress_function, +) + +number_of_missing_blocks = (-ids.n) % ids.BATCH_SIZE +assert 0 <= number_of_missing_blocks < 20 +_sha256_input_chunk_size_felts = ids.SHA256_INPUT_CHUNK_SIZE_FELTS +assert 0 <= _sha256_input_chunk_size_felts < 100 + +message = [0] * _sha256_input_chunk_size_felts +w = compute_message_schedule(message) +output = sha2_compress_function(IV, w) +padding = (message + IV + output) * number_of_missing_blocks +segments.write_arg(ids.sha256_ptr_end, padding)"#} + ), + ( + LoadNextTx, + load_next_tx, + indoc! {r#" + tx = next(transactions) + assert tx.tx_type.name in ('INVOKE_FUNCTION', 'L1_HANDLER', 'DEPLOY_ACCOUNT', 'DECLARE'), ( + f"Unexpected transaction type: {tx.type.name}." + ) + + tx_type_bytes = tx.tx_type.name.encode("ascii") + ids.tx_type = int.from_bytes(tx_type_bytes, "big") + execution_helper.os_logger.enter_tx( + tx=tx, + n_steps=current_step, + builtin_ptrs=ids.builtin_ptrs, + range_check_ptr=ids.range_check_ptr, + ) + + # Prepare a short callable to save code duplication. + exit_tx = lambda: execution_helper.os_logger.exit_tx( + n_steps=current_step, + builtin_ptrs=ids.builtin_ptrs, + range_check_ptr=ids.range_check_ptr, + )"# + } + ), + ( + LoadResourceBounds, + load_resource_bounds, + indoc! {r#" + from src.starkware.starknet.core.os.transaction_hash.transaction_hash import ( + create_resource_bounds_list, + ) + assert len(tx.resource_bounds) == 3, ( + "Only transactions with 3 resource bounds are supported. " + f"Got {len(tx.resource_bounds)} resource bounds." + ) + ids.resource_bounds = segments.gen_arg(create_resource_bounds_list(tx.resource_bounds))"# + } + ), + (ExitTx, exit_tx, "exit_tx()"), + ( + PrepareConstructorExecution, + prepare_constructor_execution, + indoc! {r#" + ids.contract_address_salt = tx.contract_address_salt + ids.class_hash = tx.class_hash + ids.constructor_calldata_size = len(tx.constructor_calldata) + ids.constructor_calldata = segments.gen_arg(arg=tx.constructor_calldata)"# + } + ), + ( + AssertTransactionHash, + assert_transaction_hash, + indoc! {r#" + assert ids.transaction_hash == tx.hash_value, ( + "Computed transaction_hash is inconsistent with the hash in the transaction. " + f"Computed hash = {ids.transaction_hash}, Expected hash = {tx.hash_value}.")"# + } + ), + ( + EnterScopeDeprecatedSyscallHandler, + enter_scope_deprecated_syscall_handler, + "vm_enter_scope({'syscall_handler': deprecated_syscall_handler})" + ), + ( + EnterScopeSyscallHandler, + enter_scope_syscall_handler, + "vm_enter_scope({'syscall_handler': syscall_handler})" + ), + ( + GetContractAddressStateEntry, + get_contract_address_state_entry, + indoc! {r#" + # Fetch a state_entry in this hint and validate it in the update at the end + # of this function. + ids.state_entry = __dict_manager.get_dict(ids.contract_state_changes)[ids.contract_address]"# + } + ), + ( + SetStateEntryToAccountContractAddress, + set_state_entry_to_account_contract_address, + indoc! {r#" + # Fetch a state_entry in this hint and validate it in the update that comes next. + ids.state_entry = __dict_manager.get_dict(ids.contract_state_changes)[ + ids.tx_info.account_contract_address + ]"# + } + ), + ( + GetBlockHashContractAddressStateEntryAndSetNewStateEntry, + get_block_hash_contract_address_state_entry_and_set_new_state_entry, + indoc! {r#" + # Fetch a state_entry in this hint. Validate it in the update that comes next. + ids.state_entry = __dict_manager.get_dict(ids.contract_state_changes)[ + ids.BLOCK_HASH_CONTRACT_ADDRESS]"# + } + ), + ( + GetContractAddressStateEntryAndSetNewStateEntry, + get_contract_address_state_entry_and_set_new_state_entry, + indoc! {r#" + # Fetch a state_entry in this hint and validate it in the update that comes next. + ids.state_entry = __dict_manager.get_dict(ids.contract_state_changes)[ids.contract_address]"# + } + ), + ( + GetContractAddressStateEntryAndSetNewStateEntry2, + get_contract_address_state_entry_and_set_new_state_entry, + indoc! {r#" + # Fetch a state_entry in this hint and validate it in the update that comes next. + ids.state_entry = __dict_manager.get_dict(ids.contract_state_changes)[ + ids.contract_address + ]"# + } + ), + ( + CheckIsDeprecated, + check_is_deprecated, + "is_deprecated = 1 if ids.execution_context.class_hash in __deprecated_class_hashes else 0" + ), + (IsDeprecated, is_deprecated, "memory[ap] = to_felt_or_relocatable(is_deprecated)"), + // TODO(Meshi): Fix hint implantation. + ( + EnterSyscallScopes, + enter_syscall_scopes, + indoc! {r#"vm_enter_scope({ + '__deprecated_class_hashes': __deprecated_class_hashes, + 'transactions': iter(block_input.transactions), + 'component_hashes': block_input.declared_class_hash_to_component_hashes, + 'execution_helper': execution_helper, + 'deprecated_syscall_handler': deprecated_syscall_handler, + 'syscall_handler': syscall_handler, + '__dict_manager': __dict_manager, + })"# + } + ), + (EndTx, end_tx, "execution_helper.end_tx()"), + ( + EnterCall, + enter_call, + indoc! {r#" + execution_helper.enter_call( + cairo_execution_info=ids.execution_context.execution_info, + deprecated_tx_info=ids.execution_context.deprecated_tx_info, + )"#} + ), + (ExitCall, exit_call, "execution_helper.exit_call()"), + ( + ContractAddress, + contract_address, + indoc! {r#" + from starkware.starknet.business_logic.transaction.deprecated_objects import ( + InternalL1Handler, + ) + ids.contract_address = ( + tx.contract_address if isinstance(tx, InternalL1Handler) else tx.sender_address + )"# + } + ), + (TxCalldataLen, tx_calldata_len, "memory[ap] = to_felt_or_relocatable(len(tx.calldata))"), + (TxCalldata, tx_calldata, "memory[ap] = to_felt_or_relocatable(segments.gen_arg(tx.calldata))"), + ( + TxEntryPointSelector, + tx_entry_point_selector, + "memory[ap] = to_felt_or_relocatable(tx.entry_point_selector)" + ), + (TxVersion, tx_version, "memory[ap] = to_felt_or_relocatable(tx.version)"), + (TxTip, tx_tip, "memory[ap] = to_felt_or_relocatable(tx.tip)"), + ( + TxPaymasterDataLen, + tx_paymaster_data_len, + "memory[ap] = to_felt_or_relocatable(len(tx.paymaster_data))" + ), + ( + TxPaymasterData, + tx_paymaster_data, + "memory[ap] = to_felt_or_relocatable(segments.gen_arg(tx.paymaster_data))" + ), + ( + TxNonceDataAvailabilityMode, + tx_nonce_data_availability_mode, + "memory[ap] = to_felt_or_relocatable(tx.nonce_data_availability_mode)" + ), + ( + TxFeeDataAvailabilityMode, + tx_fee_data_availability_mode, + "memory[ap] = to_felt_or_relocatable(tx.fee_data_availability_mode)" + ), + ( + TxAccountDeploymentDataLen, + tx_account_deployment_data_len, + "memory[fp + 4] = to_felt_or_relocatable(len(tx.account_deployment_data))" + ), + ( + TxAccountDeploymentData, + tx_account_deployment_data, + "memory[ap] = to_felt_or_relocatable(segments.gen_arg(tx.account_deployment_data))" + ), + ( + GenSignatureArg, + gen_signature_arg, + indoc! {r#" + ids.signature_start = segments.gen_arg(arg=tx.signature) + ids.signature_len = len(tx.signature)"# + } + ), + ( + IsReverted, + is_reverted, + "memory[ap] = to_felt_or_relocatable(execution_helper.tx_execution_info.is_reverted)" + ), + ( + CheckExecution, + check_execution, + indoc! {r#" + if execution_helper.debug_mode: + # Validate the predicted gas cost. + actual = ids.remaining_gas - ids.entry_point_return_values.gas_builtin + predicted = execution_helper.call_info.gas_consumed + if execution_helper.call_info.tracked_resource.is_sierra_gas(): + predicted = predicted - ids.ENTRY_POINT_INITIAL_BUDGET + assert actual == predicted, ( + "Predicted gas costs are inconsistent with the actual execution; " + f"{predicted=}, {actual=}." + ) + else: + assert predicted == 0, "Predicted gas cost must be zero in CairoSteps mode." + + + # Exit call. + syscall_handler.validate_and_discard_syscall_ptr( + syscall_ptr_end=ids.entry_point_return_values.syscall_ptr + ) + execution_helper.exit_call()"# + } + ), + ( + IsRemainingGasLtInitialBudget, + is_remaining_gas_lt_initial_budget, + "memory[ap] = to_felt_or_relocatable(ids.remaining_gas < ids.ENTRY_POINT_INITIAL_BUDGET)" + ), + ( + CheckSyscallResponse, + check_syscall_response, + indoc! {r#" + # Check that the actual return value matches the expected one. + expected = memory.get_range( + addr=ids.call_response.retdata, size=ids.call_response.retdata_size + ) + actual = memory.get_range(addr=ids.retdata, size=ids.retdata_size) + + assert expected == actual, f'Return value mismatch expected={expected}, actual={actual}.'"# + } + ), + ( + CheckNewSyscallResponse, + check_new_syscall_response, + indoc! {r#" + # Check that the actual return value matches the expected one. + expected = memory.get_range( + addr=ids.response.retdata_start, + size=ids.response.retdata_end - ids.response.retdata_start, + ) + actual = memory.get_range(addr=ids.retdata, size=ids.retdata_size) + + assert expected == actual, f'Return value mismatch; expected={expected}, actual={actual}.'"# + } + ), + ( + CheckNewDeployResponse, + check_new_deploy_response, + indoc! {r#" + # Check that the actual return value matches the expected one. + expected = memory.get_range( + addr=ids.response.constructor_retdata_start, + size=ids.response.constructor_retdata_end - ids.response.constructor_retdata_start, + ) + actual = memory.get_range(addr=ids.retdata, size=ids.retdata_size) + assert expected == actual, f'Return value mismatch; expected={expected}, actual={actual}.'"# + } + ), + ( + LogEnterSyscall, + log_enter_syscall, + indoc! {r#" + execution_helper.os_logger.enter_syscall( + n_steps=current_step, + builtin_ptrs=ids.builtin_ptrs, + range_check_ptr=ids.range_check_ptr, + deprecated=False, + selector=ids.selector, + ) + + # Prepare a short callable to save code duplication. + exit_syscall = lambda: execution_helper.os_logger.exit_syscall( + n_steps=current_step, + builtin_ptrs=ids.builtin_ptrs, + range_check_ptr=ids.range_check_ptr, + selector=ids.selector, + )"# + } + ), + ( + InitialGeRequiredGas, + initial_ge_required_gas, + "memory[ap] = to_felt_or_relocatable(ids.initial_gas >= ids.required_gas)" + ), + (SetApToTxNonce, set_ap_to_tx_nonce, "memory[ap] = to_felt_or_relocatable(tx.nonce)"), + ( + SetFpPlus4ToTxNonce, + set_fp_plus_4_to_tx_nonce, + "memory[fp + 4] = to_felt_or_relocatable(tx.nonce)" + ), + (EnterScopeNode, enter_scope_node, "vm_enter_scope(dict(node=node, **common_args))"), + ( + EnterScopeNewNode, + enter_scope_new_node, + indoc! {r#" + ids.child_bit = 0 if case == 'left' else 1 + new_node = left_child if case == 'left' else right_child + vm_enter_scope(dict(node=new_node, **common_args))"# + } + ), + ( + EnterScopeNextNodeBit0, + enter_scope_next_node_bit_0, + indoc! {r#" + new_node = left_child if ids.bit == 0 else right_child + vm_enter_scope(dict(node=new_node, **common_args))"# + } + ), + ( + EnterScopeNextNodeBit1, + enter_scope_next_node_bit_1, + indoc! {r#" + new_node = left_child if ids.bit == 1 else right_child + vm_enter_scope(dict(node=new_node, **common_args))"# + } + ), + ( + EnterScopeLeftChild, + enter_scope_left_child, + "vm_enter_scope(dict(node=left_child, **common_args))" + ), + ( + EnterScopeRightChild, + enter_scope_right_child, + "vm_enter_scope(dict(node=right_child, **common_args))" + ), + ( + EnterScopeDescendEdge, + enter_scope_descend_edge, + indoc! {r#" + new_node = node + for i in range(ids.length - 1, -1, -1): + new_node = new_node[(ids.word >> i) & 1] + vm_enter_scope(dict(node=new_node, **common_args))"# + } + ), + ( + WriteSyscallResultDeprecated, + write_syscall_result_deprecated, + indoc! {r#" + storage = execution_helper.storage_by_address[ids.contract_address] + ids.prev_value = storage.read(key=ids.syscall_ptr.address) + storage.write(key=ids.syscall_ptr.address, value=ids.syscall_ptr.value) + + # Fetch a state_entry in this hint and validate it in the update that comes next. + ids.state_entry = __dict_manager.get_dict(ids.contract_state_changes)[ids.contract_address]"# + } + ), + ( + WriteSyscallResult, + write_syscall_result, + indoc! {r#" + storage = execution_helper.storage_by_address[ids.contract_address] + ids.prev_value = storage.read(key=ids.request.key) + storage.write(key=ids.request.key, value=ids.request.value) + + # Fetch a state_entry in this hint and validate it in the update that comes next. + ids.state_entry = __dict_manager.get_dict(ids.contract_state_changes)[ids.contract_address]"# + } + ), + ( + DeclareTxFields, + declare_tx_fields, + indoc! {r#" + assert tx.version == 3, f"Unsupported declare version: {tx.version}." + ids.sender_address = tx.sender_address + ids.account_deployment_data_size = len(tx.account_deployment_data) + ids.account_deployment_data = segments.gen_arg(tx.account_deployment_data) + ids.class_hash_ptr = segments.gen_arg([tx.class_hash]) + ids.compiled_class_hash = tx.compiled_class_hash"# + } + ), + ( + WriteOldBlockToStorage, + write_old_block_to_storage, + indoc! {r#" + storage = execution_helper.storage_by_address[ids.BLOCK_HASH_CONTRACT_ADDRESS] + storage.write(key=ids.old_block_number, value=ids.old_block_hash)"# + } + ), + ( + CacheContractStorageRequestKey, + cache_contract_storage_request_key, + indoc! {r#" + # Make sure the value is cached (by reading it), to be used later on for the + # commitment computation. + value = execution_helper.storage_by_address[ids.contract_address].read(key=ids.request.key) + assert ids.value == value, "Inconsistent storage value.""# + } + ), + ( + CacheContractStorageSyscallRequestAddress, + cache_contract_storage_syscall_request_address, + indoc! {r#" + # Make sure the value is cached (by reading it), to be used later on for the + # commitment computation. + value = execution_helper.storage_by_address[ids.contract_address].read( + key=ids.syscall_ptr.request.address + ) + assert ids.value == value, "Inconsistent storage value.""# + } + ), + // TODO(Meshi): Fix hint implantation. + ( + GetOldBlockNumberAndHash, + get_old_block_number_and_hash, + indoc! {r#" + old_block_number_and_hash = block_input.old_block_number_and_hash + assert ( + old_block_number_and_hash is not None + ), f"Block number is probably < {ids.STORED_BLOCK_HASH_BUFFER}." + ( + old_block_number, old_block_hash + ) = old_block_number_and_hash + assert old_block_number == ids.old_block_number,( + "Inconsistent block number. " + "The constant STORED_BLOCK_HASH_BUFFER is probably out of sync." + ) + ids.old_block_hash = old_block_hash"#} + ), + ( + FetchResult, + fetch_result, + indoc! {r#" + # Fetch the result, up to 100 elements. + result = memory.get_range(ids.retdata, min(100, ids.retdata_size)) + + if result != [ids.VALIDATED]: + print("Invalid return value from __validate__:") + print(f" Size: {ids.retdata_size}") + print(f" Result (at most 100 elements): {result}")"# + } + ), + ( + SearchSortedOptimistic, + search_sorted_optimistic, + indoc! {r#"array_ptr = ids.array_ptr + elm_size = ids.elm_size + assert isinstance(elm_size, int) and elm_size > 0, \ + f'Invalid value for elm_size. Got: {elm_size}.' + + n_elms = ids.n_elms + assert isinstance(n_elms, int) and n_elms >= 0, \ + f'Invalid value for n_elms. Got: {n_elms}.' + if '__find_element_max_size' in globals(): + assert n_elms <= __find_element_max_size, \ + f'find_element() can only be used with n_elms<={__find_element_max_size}. ' \ + f'Got: n_elms={n_elms}.' + + for i in range(n_elms): + if memory[array_ptr + elm_size * i] >= ids.key: + ids.index = i + ids.exists = 1 if memory[array_ptr + elm_size * i] == ids.key else 0 + break + else: + ids.index = n_elms + ids.exists = 0"#} + ), + // TODO(Meshi): Fix hint implantation. + ( + GetBlocksNumber, + get_n_blocks, + r#"memory[fp + 0] = to_felt_or_relocatable(len(os_input.block_inputs))"# + ), + ( + StoreDaSegment, + store_da_segment, + indoc! {r#"import itertools + + from starkware.python.utils import blockify + + kzg_manager.store_da_segment( + da_segment=memory.get_range_as_ints(addr=ids.state_updates_start, size=ids.da_size) + ) + kzg_commitments = [ + kzg_manager.polynomial_coefficients_to_kzg_commitment_callback(chunk) + for chunk in blockify(kzg_manager.da_segment, chunk_size=ids.BLOB_LENGTH) + ] + + ids.n_blobs = len(kzg_commitments) + ids.kzg_commitments = segments.add_temp_segment() + ids.evals = segments.add_temp_segment() + + segments.write_arg(ids.kzg_commitments.address_, list(itertools.chain(*kzg_commitments)))"#} + ), + ( + Log2Ceil, + log2_ceil, + indoc! {r#"from starkware.python.math_utils import log2_ceil + ids.res = log2_ceil(ids.value)"# + } + ), + // TODO(Meshi): Fix hint implantation. + ( + WriteFullOutputToMemory, + write_full_output_to_memory, + indoc! {r#"memory[fp + 20] = to_felt_or_relocatable(os_hints_config.full_output)"#} + ), + ( + ConfigureKzgManager, + configure_kzg_manager, + indoc! {r#"__serialize_data_availability_create_pages__ = True + kzg_manager = global_hints.kzg_manager"#} + ), + // TODO(Meshi): Fix hint implantation. + ( + SetApToPrevBlockHash, + set_ap_to_prev_block_hash, + indoc! {r#"memory[ap] = to_felt_or_relocatable(block_input.prev_block_hash)"#} + ), + // TODO(Meshi): Fix hint implantation. + ( + SetApToNewBlockHash, + set_ap_to_new_block_hash, + "memory[ap] = to_felt_or_relocatable(block_input.new_block_hash)" + ), + ( + SetTreeStructure, + set_tree_structure, + indoc! {r#"from starkware.python.math_utils import div_ceil + + if __serialize_data_availability_create_pages__: + onchain_data_start = ids.da_start + onchain_data_size = ids.output_ptr - onchain_data_start + + max_page_size = 3800 + n_pages = div_ceil(onchain_data_size, max_page_size) + for i in range(n_pages): + start_offset = i * max_page_size + output_builtin.add_page( + page_id=1 + i, + page_start=onchain_data_start + start_offset, + page_size=min(onchain_data_size - start_offset, max_page_size), + ) + # Set the tree structure to a root with two children: + # * A leaf which represents the main part + # * An inner node for the onchain data part (which contains n_pages children). + # + # This is encoded using the following sequence: + output_builtin.add_attribute('gps_fact_topology', [ + # Push 1 + n_pages pages (all of the pages). + 1 + n_pages, + # Create a parent node for the last n_pages. + n_pages, + # Don't push additional pages. + 0, + # Take the first page (the main part) and the node that was created (onchain data) + # and use them to construct the root of the fact tree. + 2, + ])"#} + ), + ( + SetStateUpdatesStart, + set_state_updates_start, + indoc! {r#"# `use_kzg_da` is used in a hint in `process_data_availability`. + use_kzg_da = ids.use_kzg_da + if use_kzg_da or ids.compress_state_updates: + ids.state_updates_start = segments.add() + else: + # Assign a temporary segment, to be relocated into the output segment. + ids.state_updates_start = segments.add_temp_segment()"#} + ), + ( + SetCompressedStart, + set_compressed_start, + indoc! {r#"if use_kzg_da: + ids.compressed_start = segments.add() +else: + # Assign a temporary segment, to be relocated into the output segment. + ids.compressed_start = segments.add_temp_segment()"#} + ), + ( + SetNUpdatesSmall, + set_n_updates_small, + indoc! {r#"ids.is_n_updates_small = ids.n_updates < ids.N_UPDATES_SMALL_PACKING_BOUND"#} + ), + (SetSiblings, set_siblings, "memory[ids.siblings], ids.word = descend"), + (IsCaseRight, is_case_right, "memory[ap] = int(case == 'right') ^ ids.bit"), + (SetBit, set_bit, "ids.bit = (ids.edge.path >> ids.new_length) & 1"), + ( + SetApToDescend, + set_ap_to_descend, + indoc! {r#" + descend = descent_map.get((ids.height, ids.path)) + memory[ap] = 0 if descend is None else 1"# + } + ), + (AssertCaseIsRight, assert_case_is_right, "assert case == 'right'"), + ( + WriteCaseNotLeftToAp, + write_case_not_left_to_ap, + indoc! {r#" + memory[ap] = int(case != 'left')"# + } + ), + (SplitDescend, split_descend, "ids.length, ids.word = descend"), + ( + HeightIsZeroOrLenNodePreimageIsTwo, + height_is_zero_or_len_node_preimage_is_two, + "memory[ap] = 1 if ids.height == 0 or len(preimage[ids.node]) == 2 else 0" + ), + ( + PreparePreimageValidationNonDeterministicHashes, + prepare_preimage_validation_non_deterministic_hashes, + indoc! {r#" + from starkware.python.merkle_tree import decode_node + left_child, right_child, case = decode_node(node) + left_hash, right_hash = preimage[ids.node] + + # Fill non deterministic hashes. + hash_ptr = ids.current_hash.address_ + memory[hash_ptr + ids.HashBuiltin.x] = left_hash + memory[hash_ptr + ids.HashBuiltin.y] = right_hash + + if __patricia_skip_validation_runner: + # Skip validation of the preimage dict to speed up the VM. When this flag is set, + # mistakes in the preimage dict will be discovered only in the prover. + __patricia_skip_validation_runner.verified_addresses.add( + hash_ptr + ids.HashBuiltin.result) + + memory[ap] = int(case != 'both')"# + } + ), + ( + BuildDescentMap, + build_descent_map, + indoc! {r#" + from starkware.cairo.common.patricia_utils import canonic, patricia_guess_descents + from starkware.python.merkle_tree import build_update_tree + + # Build modifications list. + modifications = [] + DictAccess_key = ids.DictAccess.key + DictAccess_new_value = ids.DictAccess.new_value + DictAccess_SIZE = ids.DictAccess.SIZE + for i in range(ids.n_updates): + curr_update_ptr = ids.update_ptr.address_ + i * DictAccess_SIZE + modifications.append(( + memory[curr_update_ptr + DictAccess_key], + memory[curr_update_ptr + DictAccess_new_value])) + + node = build_update_tree(ids.height, modifications) + descent_map = patricia_guess_descents( + ids.height, node, preimage, ids.prev_root, ids.new_root) + del modifications + __patricia_skip_validation_runner = globals().get( + '__patricia_skip_validation_runner') + + common_args = dict( + preimage=preimage, descent_map=descent_map, + __patricia_skip_validation_runner=__patricia_skip_validation_runner) + common_args['common_args'] = common_args"# + } + ), + ( + RemainingGasGtMax, + remaining_gas_gt_max, + "memory[ap] = to_felt_or_relocatable(ids.remaining_gas > ids.max_gas)" + ), + ( + DebugExpectedInitialGas, + debug_expected_initial_gas, + indoc! {r#" + if execution_helper.debug_mode: + expected_initial_gas = execution_helper.call_info.call.initial_gas + call_initial_gas = ids.remaining_gas + assert expected_initial_gas == call_initial_gas, ( + f"Expected remaining_gas {expected_initial_gas}. Got: {call_initial_gas}.\n" + f"{execution_helper.call_info=}" + )"#} + ), + ( + IsSierraGasMode, + is_sierra_gas_mode, + "ids.is_sierra_gas_mode = execution_helper.call_info.tracked_resource.is_sierra_gas()" + ), + ( + ReadEcPointFromAddress, + read_ec_point_from_address, + r#"memory[ap] = to_felt_or_relocatable(ids.response.ec_point.address_ if ids.not_on_curve == 0 else segments.add())"# + ), + // TODO(Meshi): Fix hint implantation. + ( + SetPreimageForStateCommitments, + set_preimage_for_state_commitments, + indoc! {r#"ids.initial_root = block_input.contract_state_commitment_info.previous_root +ids.final_root = block_input.contract_state_commitment_info.updated_root +commitment_facts = block_input.contract_state_commitment_info.commitment_facts.items() +preimage = { + int(root): children + for root, children in commitment_facts +} +assert block_input.contract_state_commitment_info.tree_height == ids.MERKLE_HEIGHT"# + } + ), + // TODO(Meshi): Fix hint implantation. + ( + SetPreimageForClassCommitments, + set_preimage_for_class_commitments, + indoc! {r#"ids.initial_root = block_input.contract_class_commitment_info.previous_root +ids.final_root = block_input.contract_class_commitment_info.updated_root +commitment_facts = block_input.contract_class_commitment_info.commitment_facts.items() +preimage = { + int(root): children + for root, children in commitment_facts +} +assert block_input.contract_class_commitment_info.tree_height == ids.MERKLE_HEIGHT"# + } + ), + ( + SetPreimageForCurrentCommitmentInfo, + set_preimage_for_current_commitment_info, + indoc! {r#"commitment_info = commitment_info_by_address[ids.contract_address] +ids.initial_contract_state_root = commitment_info.previous_root +ids.final_contract_state_root = commitment_info.updated_root +preimage = { + int(root): children + for root, children in commitment_info.commitment_facts.items() +} +assert commitment_info.tree_height == ids.MERKLE_HEIGHT"# + } + ), + ( + LoadEdge, + load_edge, + indoc! {r#" + ids.edge = segments.add() + ids.edge.length, ids.edge.path, ids.edge.bottom = preimage[ids.node] + ids.hash_ptr.result = ids.node - ids.edge.length + if __patricia_skip_validation_runner is not None: + # Skip validation of the preimage dict to speed up the VM. When this flag is set, + # mistakes in the preimage dict will be discovered only in the prover. + __patricia_skip_validation_runner.verified_addresses.add( + ids.hash_ptr + ids.HashBuiltin.result)"# + } + ), + ( + LoadBottom, + load_bottom, + indoc! {r#" + ids.hash_ptr.x, ids.hash_ptr.y = preimage[ids.edge.bottom] + if __patricia_skip_validation_runner: + # Skip validation of the preimage dict to speed up the VM. When this flag is + # set, mistakes in the preimage dict will be discovered only in the prover. + __patricia_skip_validation_runner.verified_addresses.add( + ids.hash_ptr + ids.HashBuiltin.result)"# + } + ), + ( + DecodeNode, + decode_node, + indoc! {r#" + from starkware.python.merkle_tree import decode_node + left_child, right_child, case = decode_node(node) + memory[ap] = int(case != 'both')"# + } + ), + ( + DecodeNode2, + decode_node, + indoc! {r#" +from starkware.python.merkle_tree import decode_node +left_child, right_child, case = decode_node(node) +memory[ap] = 1 if case != 'both' else 0"# + } + ), + ( + WriteSplitResult, + write_split_result, + indoc! {r#" + from starkware.starknet.core.os.data_availability.bls_utils import split + + segments.write_arg(ids.res.address_, split(ids.value))"# + } + ), + ( + SetSyscallPtr, + set_syscall_ptr, + indoc! {r#" + syscall_handler.set_syscall_ptr(syscall_ptr=ids.syscall_ptr)"# + } + ), + ( + OsLoggerEnterSyscallPrepareExitSyscall, + os_logger_enter_syscall_prepare_exit_syscall, + indoc! {r#" + execution_helper.os_logger.enter_syscall( + n_steps=current_step, + builtin_ptrs=ids.builtin_ptrs, + deprecated=True, + selector=ids.selector, + range_check_ptr=ids.range_check_ptr, + ) + + # Prepare a short callable to save code duplication. + exit_syscall = lambda: execution_helper.os_logger.exit_syscall( + n_steps=current_step, + builtin_ptrs=ids.builtin_ptrs, + range_check_ptr=ids.range_check_ptr, + selector=ids.selector, + )"# + } + ), + (OsLoggerExitSyscall, os_logger_exit_syscall, "exit_syscall()"), + (IsOnCurve, is_on_curve, "ids.is_on_curve = (y * y) % SECP_P == y_square_int"), + // TODO(Meshi): Fix hint implantation. + ( + StarknetOsInput, + starknet_os_input, + indoc! {r#"from starkware.starknet.core.os.os_hints import OsHintsConfig + from starkware.starknet.core.os.os_input import StarknetOsInput + + os_input = StarknetOsInput.load(data=program_input) + os_hints_config = OsHintsConfig.load(data=os_hints_config) + block_input_iterator = iter(os_input.block_inputs)"# + } + ), + ( + InitStateUpdatePointers, + init_state_update_pointer, + indoc! {r#"from starkware.starknet.core.os.execution_helper import StateUpdatePointers + state_update_pointers = StateUpdatePointers(segments=segments)"# + } + ), + // TODO(Meshi): Fix hint implantation. + ( + InitializeStateChanges, + initialize_state_changes, + indoc! {r#"from starkware.python.utils import from_bytes + +initial_dict = { + address: segments.gen_arg( + (from_bytes(contract.contract_hash), segments.add(), contract.nonce)) + for address, contract in block_input.contracts.items() +}"# + } + ), + // TODO(Meshi): Fix hint implantation. + ( + InitializeClassHashes, + initialize_class_hashes, + "initial_dict = block_input.class_hash_to_compiled_class_hash" + ), + ( + CreateBlockAdditionalHints, + create_block_additional_hints, + indoc! {r#"from starkware.starknet.core.os.os_hints import get_execution_helper_and_syscall_handlers +block_input = next(block_input_iterator) +( + execution_helper, + syscall_handler, + deprecated_syscall_handler +) = get_execution_helper_and_syscall_handlers( + block_input=block_input, global_hints=global_hints, os_hints_config=os_hints_config +)"#} + ) +); + +define_hint_enum!( + AggregatorHint, + ( + AllocateSegmentsForMessages, + allocate_segments_for_messages, + r#"# Allocate segments for the messages. +ids.initial_carried_outputs = segments.gen_arg( + [segments.add_temp_segment(), segments.add_temp_segment()] +)"# + ), + ( + DisableDaPageCreation, + disable_da_page_creation, + r#"# Note that `serialize_os_output` splits its output to memory pages +# (see OutputBuiltinRunner.add_page). +# Since this output is only used internally and will not be used in the final fact, +# we need to disable page creation. +__serialize_data_availability_create_pages__ = False"# + ), + ( + GetOsOuputForInnerBlocks, + get_os_output_for_inner_blocks, + r#"from starkware.starknet.core.aggregator.output_parser import parse_bootloader_output +from starkware.starknet.core.aggregator.utils import OsOutputToCairo + +tasks = parse_bootloader_output(program_input["bootloader_output"]) +assert len(tasks) > 0, "No tasks found in the bootloader output." +ids.os_program_hash = tasks[0].program_hash +ids.n_tasks = len(tasks) +os_output_to_cairo = OsOutputToCairo(segments) +for i, task in enumerate(tasks): + os_output_to_cairo.process_os_output( + segments=segments, + dst_ptr=ids.os_outputs[i].address_, + os_output=task.os_output, + )"# + ), + ( + GetAggregatorOutput, + get_aggregator_output, + r#"from starkware.starknet.core.os.kzg_manager import KzgManager + +__serialize_data_availability_create_pages__ = True +if "polynomial_coefficients_to_kzg_commitment_callback" not in globals(): + from services.utils import kzg_utils + polynomial_coefficients_to_kzg_commitment_callback = ( + kzg_utils.polynomial_coefficients_to_kzg_commitment + ) +kzg_manager = KzgManager(polynomial_coefficients_to_kzg_commitment_callback)"# + ), + ( + WriteDaSegment, + write_da_segment, + r#"import json + +da_path = program_input.get("da_path") +if da_path is not None: + da_segment = kzg_manager.da_segment if program_input["use_kzg_da"] else None + with open(da_path, "w") as da_file: + json.dump(da_segment, da_file)"# + ), + ( + GetFullOutputFromInput, + get_full_output_from_input, + r#"memory[ap] = to_felt_or_relocatable(program_input["full_output"])"# + ), + ( + GetUseKzgDaFromInput, + get_use_kzg_da_from_input, + r#"memory[ap] = to_felt_or_relocatable(program_input["use_kzg_da"])"# + ), + ( + SetStateUpdatePointersToNone, + set_state_update_pointers_to_none, + r#"state_update_pointers = None"# + ) +); + +define_hint_extension_enum!( + HintExtension, + ( + LoadDeprecatedClass, + load_deprecated_class, + indoc! {r#" + from starkware.python.utils import from_bytes + + computed_hash = ids.compiled_class_fact.hash + expected_hash = compiled_class_hash + assert computed_hash == expected_hash, ( + "Computed compiled_class_hash is inconsistent with the hash in the os_input. " + f"Computed hash = {computed_hash}, Expected hash = {expected_hash}.") + + vm_load_program(compiled_class.program, ids.compiled_class.bytecode_ptr)"# + } + ), + ( + LoadClassInner, + load_class_inner, + indoc! {r#" + from starkware.starknet.core.os.contract_class.compiled_class_hash import ( + create_bytecode_segment_structure, + get_compiled_class_struct, + ) + + ids.n_compiled_class_facts = len(os_input.compiled_classes) + ids.compiled_class_facts = (compiled_class_facts_end := segments.add()) + for i, (compiled_class_hash, compiled_class) in enumerate( + os_input.compiled_classes.items() + ): + # Load the compiled class. + cairo_contract = get_compiled_class_struct( + identifiers=ids._context.identifiers, + compiled_class=compiled_class, + # Load the entire bytecode - the unaccessed segments will be overriden and skipped + # after the execution, in `validate_compiled_class_facts_post_execution`. + bytecode=compiled_class.bytecode, + ) + segments.load_data( + ptr=ids.compiled_class_facts[i].address_, + data=(compiled_class_hash, segments.gen_arg(cairo_contract)) + ) + + bytecode_ptr = ids.compiled_class_facts[i].compiled_class.bytecode_ptr + # Compiled classes are expected to end with a `ret` opcode followed by a pointer to + # the builtin costs. + segments.load_data( + ptr=bytecode_ptr + cairo_contract.bytecode_length, + data=[0x208b7fff7fff7ffe, ids.builtin_costs] + ) + + # Load hints and debug info. + vm_load_program( + compiled_class.get_runnable_program(entrypoint_builtins=[]), bytecode_ptr)"#} + ), +); diff --git a/crates/starknet_os/src/hints/enum_definition_test.rs b/crates/starknet_os/src/hints/enum_definition_test.rs new file mode 100644 index 00000000000..371145e9c06 --- /dev/null +++ b/crates/starknet_os/src/hints/enum_definition_test.rs @@ -0,0 +1,36 @@ +use std::collections::HashSet; + +use blockifier::execution::hint_code::SYSCALL_HINTS; +use strum::IntoEnumIterator; + +use crate::hints::enum_definition::{AllHints, SyscallHint}; +use crate::hints::types::HintEnum; + +#[test] +fn test_hint_strings_are_unique() { + let all_hints = AllHints::all_iter().map(|hint| hint.to_str()).collect::>(); + let all_hints_set: HashSet<&&str> = HashSet::from_iter(all_hints.iter()); + assert_eq!(all_hints.len(), all_hints_set.len(), "Duplicate hint strings."); +} + +#[test] +fn test_from_str_for_all_hints() { + for hint in AllHints::all_iter() { + let hint_str = hint.to_str(); + let parsed_hint = AllHints::from_str(hint_str).unwrap(); + assert_eq!(hint, parsed_hint, "Failed to parse hint: {hint_str}."); + } +} + +#[test] +fn test_syscall_compatibility_with_blockifier() { + let syscall_hint_strings = + SyscallHint::iter().map(|hint| hint.to_str()).collect::>(); + let blockifier_syscall_strings: HashSet<_> = SYSCALL_HINTS.iter().cloned().collect(); + assert_eq!( + blockifier_syscall_strings, syscall_hint_strings, + "The syscall hints in the 'blockifier' do not match the syscall hints in 'starknet_os'. + If this is intentional, please update the 'starknet_os' hints and add a todo to update + the implementation." + ); +} diff --git a/crates/starknet_os/src/hints/enum_generation.rs b/crates/starknet_os/src/hints/enum_generation.rs new file mode 100644 index 00000000000..5c40189abf2 --- /dev/null +++ b/crates/starknet_os/src/hints/enum_generation.rs @@ -0,0 +1,68 @@ +#[macro_export] +macro_rules! define_hint_enum_base { + ($enum_name:ident, $(($hint_name:ident, $hint_str:expr)),+ $(,)?) => { + #[cfg_attr(any(test, feature = "testing"), derive(Default, strum_macros::EnumIter))] + #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] + pub enum $enum_name { + // Make first variant the default variant for testing (iteration) purposes. + #[cfg_attr(any(test, feature = "testing"), default)] + $($hint_name),+ + } + + impl From<$enum_name> for AllHints { + fn from(hint: $enum_name) -> Self { + Self::$enum_name(hint) + } + } + + impl HintEnum for $enum_name { + fn from_str(hint_str: &str) -> Result { + match hint_str { + $($hint_str => Ok(Self::$hint_name),)+ + _ => Err(OsHintError::UnknownHint(hint_str.to_string())), + } + } + + fn to_str(&self) -> &'static str { + match self { + $(Self::$hint_name => $hint_str,)+ + } + } + } + } +} + +#[macro_export] +macro_rules! define_hint_enum { + ($enum_name:ident, $(($hint_name:ident, $implementation:ident, $hint_str:expr)),+ $(,)?) => { + + $crate::define_hint_enum_base!($enum_name, $(($hint_name, $hint_str)),+); + + impl HintImplementation for $enum_name { + fn execute_hint(&self, hint_args: HintArgs<'_, S>) -> OsHintResult { + match self { + $(Self::$hint_name => $implementation::(hint_args),)+ + } + } + } + }; +} + +#[macro_export] +macro_rules! define_hint_extension_enum { + ($enum_name:ident, $(($hint_name:ident, $implementation:ident, $hint_str:expr)),+ $(,)?) => { + + $crate::define_hint_enum_base!($enum_name, $(($hint_name, $hint_str)),+); + + impl HintExtensionImplementation for $enum_name { + fn execute_hint_extensive( + &self, + hint_extension_args: HintArgs<'_, S>, + ) -> OsHintExtensionResult { + match self { + $(Self::$hint_name => $implementation::(hint_extension_args),)+ + } + } + } + }; +} diff --git a/crates/starknet_os/src/hints/error.rs b/crates/starknet_os/src/hints/error.rs new file mode 100644 index 00000000000..cd3ab0a4a8c --- /dev/null +++ b/crates/starknet_os/src/hints/error.rs @@ -0,0 +1,103 @@ +use std::string::FromUtf8Error; + +use blockifier::execution::syscalls::hint_processor::SyscallExecutionError; +use blockifier::state::errors::StateError; +use cairo_vm::hint_processor::hint_processor_definition::HintExtension; +use cairo_vm::serde::deserialize_program::Identifier; +use cairo_vm::types::errors::math_errors::MathError; +use cairo_vm::vm::errors::exec_scope_errors::ExecScopeError; +use cairo_vm::vm::errors::hint_errors::HintError as VmHintError; +use cairo_vm::vm::errors::memory_errors::MemoryError; +use cairo_vm::vm::errors::vm_errors::VirtualMachineError; +use num_bigint::{BigUint, TryFromBigIntError}; +use starknet_api::block::BlockNumber; +use starknet_api::core::ClassHash; +use starknet_api::executable_transaction::Transaction; +use starknet_api::StarknetApiError; +use starknet_types_core::felt::Felt; + +use crate::hints::enum_definition::AllHints; +use crate::hints::hint_implementation::kzg::utils::FftError; +use crate::hints::vars::{Const, Ids}; + +#[derive(Debug, thiserror::Error)] +pub enum OsHintError { + #[error("Assertion failed: {message}")] + AssertionFailed { message: String }, + #[error("Unexpectedly assigned leaf bytecode segment.")] + AssignedLeafBytecodeSegment, + #[error("Block number is probably < {stored_block_hash_buffer}.")] + BlockNumberTooSmall { stored_block_hash_buffer: Felt }, + #[error("{id:?} value {felt} is not a boolean.")] + BooleanIdExpected { id: Ids, felt: Felt }, + #[error("Failed to convert {variant:?} felt value {felt:?} to type {ty}: {reason:?}.")] + ConstConversion { variant: Const, felt: Felt, ty: String, reason: String }, + #[error("Tried to iterate past the end of {item_type}.")] + EndOfIterator { item_type: String }, + #[error(transparent)] + ExecutionScopes(#[from] ExecScopeError), + #[error("{id:?} value {felt} is not a bit.")] + ExpectedBit { id: Ids, felt: Felt }, + #[error(transparent)] + Fft(#[from] FftError), + #[error(transparent)] + FromUtf8(#[from] FromUtf8Error), + #[error("The identifier {0:?} has no full name.")] + IdentifierHasNoFullName(Box), + #[error("The identifier {0:?} has no members.")] + IdentifierHasNoMembers(Box), + #[error("Failed to convert {variant:?} felt value {felt:?} to type {ty}: {reason:?}.")] + IdsConversion { variant: Ids, felt: Felt, ty: String, reason: String }, + #[error( + "Inconsistent block numbers: {actual}, {expected}. The constant STORED_BLOCK_HASH_BUFFER \ + is probably out of sync." + )] + InconsistentBlockNumber { actual: BlockNumber, expected: BlockNumber }, + #[error("Inconsistent storage value. Actual: {actual}, expected: {expected}.")] + InconsistentValue { actual: Felt, expected: Felt }, + #[error(transparent)] + Math(#[from] MathError), + #[error(transparent)] + Memory(#[from] MemoryError), + #[error("Hint {hint:?} has no nondet offset.")] + MissingOffsetForHint { hint: AllHints }, + #[error("No bytecode segment structure for class hash: {0:?}.")] + MissingBytecodeSegmentStructure(ClassHash), + #[error("No preimage found for value {0:?}.")] + MissingPreimage(Felt), + #[error("Failed to parse resource bounds: {0}.")] + ResourceBoundsParsing(SyscallExecutionError), + #[error("{error:?} for json value {value}.")] + SerdeJsonDeserialize { error: serde_json::Error, value: serde_json::value::Value }, + #[error(transparent)] + SerdeJson(#[from] serde_json::Error), + #[error(transparent)] + StarknetApi(#[from] StarknetApiError), + #[error(transparent)] + State(#[from] StateError), + #[error("Convert {n_bits} bits for {type_name}.")] + StatelessCompressionOverflow { n_bits: usize, type_name: String }, + #[error(transparent)] + TryFromBigUint(#[from] TryFromBigIntError), + #[error("Unexpected tx type: {0:?}.")] + UnexpectedTxType(Transaction), + #[error("Unknown hint string: {0}")] + UnknownHint(String), + #[error(transparent)] + Vm(#[from] VirtualMachineError), + #[error(transparent)] + VmHint(#[from] VmHintError), +} + +/// `OsHintError` and the VM's `HintError` must have conversions in both directions, as execution +/// can pass back and forth between the VM and the OS hint processor; errors should propagate. +// TODO(Dori): Consider replicating the blockifier's mechanism and keeping structured error data, +// instead of converting to string. +impl From for VmHintError { + fn from(error: OsHintError) -> Self { + Self::CustomHint(format!("{error}").into()) + } +} + +pub type OsHintResult = Result<(), OsHintError>; +pub type OsHintExtensionResult = Result; diff --git a/crates/starknet_os/src/hints/hint_implementation.rs b/crates/starknet_os/src/hints/hint_implementation.rs new file mode 100644 index 00000000000..dba3f1fee33 --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation.rs @@ -0,0 +1,23 @@ +pub(crate) mod aggregator; +pub(crate) mod block_context; +pub(crate) mod bls_field; +pub(crate) mod builtins; +pub(crate) mod cairo1_revert; +pub(crate) mod compiled_class; +pub(crate) mod deprecated_compiled_class; +pub(crate) mod execute_syscalls; +pub(crate) mod execute_transactions; +pub(crate) mod execution; +pub(crate) mod find_element; +pub(crate) mod kzg; +pub(crate) mod math; +pub(crate) mod os; +pub(crate) mod os_logger; +pub(crate) mod output; +pub(crate) mod patricia; +pub(crate) mod resources; +pub(crate) mod secp; +pub(crate) mod state; +pub(crate) mod stateful_compression; +pub(crate) mod stateless_compression; +pub(crate) mod syscalls; diff --git a/crates/starknet_os/src/hints/hint_implementation/aggregator.rs b/crates/starknet_os/src/hints/hint_implementation/aggregator.rs new file mode 100644 index 00000000000..e9450367b06 --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/aggregator.rs @@ -0,0 +1,62 @@ +use blockifier::state::state_api::StateReader; +use cairo_vm::hint_processor::builtin_hint_processor::hint_utils::insert_value_from_var_name; + +use crate::hints::error::OsHintResult; +use crate::hints::types::HintArgs; +use crate::hints::vars::Ids; + +pub(crate) fn allocate_segments_for_messages( + HintArgs { vm, ids_data, ap_tracking, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let segment1 = vm.add_temporary_segment(); + let segment2 = vm.add_temporary_segment(); + let initial_carried_outputs = vm.gen_arg(&[segment1, segment2])?; + insert_value_from_var_name( + Ids::InitialCarriedOutputs.into(), + initial_carried_outputs, + vm, + ids_data, + ap_tracking, + )?; + Ok(()) +} + +pub(crate) fn disable_da_page_creation( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn get_os_output_for_inner_blocks( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn get_aggregator_output( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn write_da_segment(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn get_full_output_from_input( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn get_use_kzg_da_from_input( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn set_state_update_pointers_to_none( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} diff --git a/crates/starknet_os/src/hints/hint_implementation/block_context.rs b/crates/starknet_os/src/hints/hint_implementation/block_context.rs new file mode 100644 index 00000000000..e49e031221f --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/block_context.rs @@ -0,0 +1,91 @@ +use blockifier::state::state_api::StateReader; +use cairo_vm::hint_processor::builtin_hint_processor::hint_utils::{ + get_ptr_from_var_name, + insert_value_from_var_name, + insert_value_into_ap, +}; +use starknet_api::core::ascii_as_felt; +use starknet_types_core::felt::Felt; + +use crate::hints::enum_definition::{AllHints, OsHint}; +use crate::hints::error::OsHintResult; +use crate::hints::nondet_offsets::insert_nondet_hint_value; +use crate::hints::types::HintArgs; +use crate::hints::vars::{Const, Ids}; + +// Hint implementations. + +pub(crate) fn block_number( + HintArgs { hint_processor, vm, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let block_number = hint_processor.execution_helper.os_input.block_info.block_number; + Ok(insert_value_into_ap(vm, Felt::from(block_number.0))?) +} + +pub(crate) fn block_timestamp( + HintArgs { hint_processor, vm, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let block_timestamp = hint_processor.execution_helper.os_input.block_info.block_timestamp; + Ok(insert_value_into_ap(vm, Felt::from(block_timestamp.0))?) +} + +pub(crate) fn chain_id( + HintArgs { vm, hint_processor, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let chain_id = &hint_processor.execution_helper.os_input.chain_info.chain_id; + let chain_id_as_felt = ascii_as_felt(&chain_id.to_string())?; + Ok(insert_value_into_ap(vm, chain_id_as_felt)?) +} + +pub(crate) fn fee_token_address( + HintArgs { hint_processor, vm, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let strk_fee_token_address = hint_processor + .execution_helper + .os_input + .chain_info + .fee_token_addresses + .strk_fee_token_address; + Ok(insert_value_into_ap(vm, strk_fee_token_address.0.key())?) +} + +pub(crate) fn sequencer_address( + HintArgs { hint_processor, vm, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let address = hint_processor.execution_helper.os_input.block_info.sequencer_address; + Ok(insert_value_into_ap(vm, address.0.key())?) +} + +pub(crate) fn get_block_mapping( + HintArgs { ids_data, constants, vm, ap_tracking, exec_scopes, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let block_hash_contract_address = Const::BlockHashContractAddress.fetch(constants)?; + let contract_state_changes_ptr = + get_ptr_from_var_name(Ids::ContractStateChanges.into(), vm, ids_data, ap_tracking)?; + let dict_manager = exec_scopes.get_dict_manager()?; + let mut dict_manager_borrowed = dict_manager.borrow_mut(); + let block_hash_state_entry = dict_manager_borrowed + .get_tracker_mut(contract_state_changes_ptr)? + .get_value(&block_hash_contract_address.into())?; + + Ok(insert_value_from_var_name( + Ids::StateEntry.into(), + block_hash_state_entry, + vm, + ids_data, + ap_tracking, + )?) +} + +pub(crate) fn write_use_kzg_da_to_memory( + HintArgs { hint_processor, vm, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let use_kzg_da = hint_processor.execution_helper.os_input.block_info.use_kzg_da + && !hint_processor.execution_helper.os_input.full_output; + + insert_nondet_hint_value( + vm, + AllHints::OsHint(OsHint::WriteUseKzgDaToMemory), + Felt::from(use_kzg_da), + ) +} diff --git a/crates/starknet_os/src/hints/hint_implementation/bls_field.rs b/crates/starknet_os/src/hints/hint_implementation/bls_field.rs new file mode 100644 index 00000000000..20a4368a886 --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/bls_field.rs @@ -0,0 +1,50 @@ +use blockifier::state::state_api::StateReader; +use cairo_vm::hint_processor::builtin_hint_processor::hint_utils::{ + get_constant_from_var_name, + insert_value_from_var_name, +}; +use num_bigint::BigUint; +use starknet_types_core::felt::Felt; + +use crate::hints::error::OsHintResult; +use crate::hints::types::HintArgs; +use crate::hints::vars::{CairoStruct, Const, Ids}; +use crate::vm_utils::get_address_of_nested_fields; + +/// From the Cairo code, we can make the current assumptions: +/// +/// * The limbs of value are in the range [0, BASE * 3). +/// * value is in the range [0, 2 ** 256). +pub(crate) fn compute_ids_low( + HintArgs { hint_processor, vm, ap_tracking, ids_data, constants, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let d0 = vm + .get_integer(get_address_of_nested_fields( + ids_data, + Ids::Value, + CairoStruct::BigInt3, + vm, + ap_tracking, + &["d0"], + &hint_processor.execution_helper.os_program, + )?)? + .into_owned(); + let d1 = vm + .get_integer(get_address_of_nested_fields( + ids_data, + Ids::Value, + CairoStruct::BigInt3, + vm, + ap_tracking, + &["d1"], + &hint_processor.execution_helper.os_program, + )?)? + .into_owned(); + let base = get_constant_from_var_name(Const::Base.into(), constants)?; + let mask = BigUint::from(u128::MAX); + + let low = (d0 + d1 * base).to_biguint() & mask; + + insert_value_from_var_name(Ids::Low.into(), Felt::from(low), vm, ids_data, ap_tracking)?; + Ok(()) +} diff --git a/crates/starknet_os/src/hints/hint_implementation/builtins.rs b/crates/starknet_os/src/hints/hint_implementation/builtins.rs new file mode 100644 index 00000000000..a126365fa7b --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/builtins.rs @@ -0,0 +1,18 @@ +use blockifier::state::state_api::StateReader; + +use crate::hints::error::OsHintResult; +use crate::hints::types::HintArgs; + +pub(crate) fn selected_builtins(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn select_builtin(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn update_builtin_ptrs( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} diff --git a/crates/starknet_os/src/hints/hint_implementation/cairo1_revert.rs b/crates/starknet_os/src/hints/hint_implementation/cairo1_revert.rs new file mode 100644 index 00000000000..1880a8dd262 --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/cairo1_revert.rs @@ -0,0 +1,28 @@ +use blockifier::state::state_api::StateReader; + +use crate::hints::error::OsHintResult; +use crate::hints::types::HintArgs; + +pub(crate) fn prepare_state_entry_for_revert( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn read_storage_key_for_revert( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn write_storage_key_for_revert( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn generate_dummy_os_output_segment( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} diff --git a/crates/starknet_os/src/hints/hint_implementation/compiled_class.rs b/crates/starknet_os/src/hints/hint_implementation/compiled_class.rs new file mode 100644 index 00000000000..7451a214e7f --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/compiled_class.rs @@ -0,0 +1,2 @@ +pub mod implementation; +mod utils; diff --git a/crates/starknet_os/src/hints/hint_implementation/compiled_class/implementation.rs b/crates/starknet_os/src/hints/hint_implementation/compiled_class/implementation.rs new file mode 100644 index 00000000000..bf8b8c5d913 --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/compiled_class/implementation.rs @@ -0,0 +1,214 @@ +use std::collections::HashMap; + +use blockifier::state::state_api::StateReader; +use cairo_vm::any_box; +use cairo_vm::hint_processor::builtin_hint_processor::hint_utils::{ + get_integer_from_var_name, + get_relocatable_from_var_name, + insert_value_from_var_name, + insert_value_into_ap, +}; +use cairo_vm::hint_processor::hint_processor_definition::HintExtension; +use cairo_vm::types::relocatable::Relocatable; +use starknet_api::core::ClassHash; +use starknet_types_core::felt::Felt; + +use crate::hints::error::{OsHintError, OsHintExtensionResult, OsHintResult}; +use crate::hints::hint_implementation::compiled_class::utils::{ + create_bytecode_segment_structure, + BytecodeSegmentNode, + CompiledClassFact, +}; +use crate::hints::types::HintArgs; +use crate::hints::vars::{CairoStruct, Ids, Scope}; +use crate::vm_utils::{ + get_address_of_nested_fields, + get_address_of_nested_fields_from_base_address, + CairoSized, + LoadCairoObject, +}; + +pub(crate) fn assign_bytecode_segments( + HintArgs { exec_scopes, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let bytecode_segment_structure: BytecodeSegmentNode = + exec_scopes.get(Scope::BytecodeSegmentStructure.into())?; + + match bytecode_segment_structure { + BytecodeSegmentNode::InnerNode(node) => { + exec_scopes.insert_value(Scope::BytecodeSegments.into(), node.segments.into_iter()); + Ok(()) + } + BytecodeSegmentNode::Leaf(_) => Err(OsHintError::AssignedLeafBytecodeSegment), + } +} + +pub(crate) fn assert_end_of_bytecode_segments( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn bytecode_segment_structure( + HintArgs { hint_processor, exec_scopes, ids_data, ap_tracking, vm, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let bytecode_segment_structures: &HashMap = + exec_scopes.get_ref(Scope::BytecodeSegmentStructures.into())?; + + let class_hash_address = get_address_of_nested_fields( + ids_data, + Ids::CompiledClassFact, + CairoStruct::CompiledClassFact, + vm, + ap_tracking, + &["hash"], + &hint_processor.execution_helper.os_program, + )?; + + let class_hash = ClassHash(*vm.get_integer(class_hash_address)?.as_ref()); + let bytecode_segment_structure = bytecode_segment_structures + .get(&class_hash) + .ok_or_else(|| OsHintError::MissingBytecodeSegmentStructure(class_hash))?; + + // TODO(Nimrod): See if we can avoid the clone here. + let new_scope = HashMap::from([( + Scope::BytecodeSegmentStructure.into(), + any_box!(bytecode_segment_structure.clone()), + )]); + // TODO(Nimrod): support is_segment_used_callback. + exec_scopes.enter_scope(new_scope); + + Ok(()) +} + +pub(crate) fn delete_memory_data(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + // TODO(Yoni): Assert that the address was not accessed before. + todo!() +} + +pub(crate) fn is_leaf( + HintArgs { vm, exec_scopes, ap_tracking, ids_data, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let bytecode_segment_structure: &BytecodeSegmentNode = + exec_scopes.get_ref(Scope::BytecodeSegmentStructure.into())?; + let is_leaf = bytecode_segment_structure.is_leaf(); + Ok(insert_value_from_var_name( + Ids::IsLeaf.into(), + Felt::from(is_leaf), + vm, + ids_data, + ap_tracking, + )?) +} + +pub(crate) fn iter_current_segment_info( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn load_class( + HintArgs { exec_scopes, ids_data, ap_tracking, vm, hint_processor, .. }: HintArgs<'_, S>, +) -> OsHintResult { + exec_scopes.exit_scope()?; + let expected_hash_address = get_address_of_nested_fields( + ids_data, + Ids::CompiledClassFact, + CairoStruct::CompiledClassFact, + vm, + ap_tracking, + &["hash"], + &hint_processor.execution_helper.os_program, + )?; + let expected_hash = vm.get_integer(expected_hash_address)?; + let computed_hash = get_integer_from_var_name(Ids::Hash.into(), vm, ids_data, ap_tracking)?; + if &computed_hash != expected_hash.as_ref() { + return Err(OsHintError::AssertionFailed { + message: format!( + "Computed compiled_class_hash is inconsistent with the hash in the os_input. \ + Computed hash = {computed_hash}, Expected hash = {expected_hash}." + ), + }); + } + + Ok(()) +} + +pub(crate) fn set_ap_to_segment_hash( + HintArgs { exec_scopes, vm, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let bytecode_segment_structure: &BytecodeSegmentNode = + exec_scopes.get_ref(Scope::BytecodeSegmentStructure.into())?; + + Ok(insert_value_into_ap(vm, bytecode_segment_structure.hash().0)?) +} + +pub(crate) fn validate_compiled_class_facts_post_execution( + HintArgs { hint_processor, exec_scopes, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let mut bytecode_segment_structures = HashMap::new(); + for (compiled_hash, compiled_class) in + hint_processor.execution_helper.os_input.compiled_classes.iter() + { + bytecode_segment_structures.insert( + *compiled_hash, + create_bytecode_segment_structure( + &compiled_class.bytecode.iter().map(|x| Felt::from(&x.value)).collect::>(), + compiled_class.get_bytecode_segment_lengths(), + )?, + ); + } + // No need for is_segment_used callback: use the VM's `MemoryCell::is_accessed`. + // TODO(Dori): upgrade the VM to a version including the `is_accessed` API, as added + // [here](https://github.com/lambdaclass/cairo-vm/pull/2024). + exec_scopes.enter_scope(HashMap::from([( + Scope::BytecodeSegmentStructures.into(), + any_box!(bytecode_segment_structures), + )])); + Ok(()) +} + +// Hint extensions. +pub(crate) fn load_class_inner( + HintArgs { hint_processor, constants, vm, ids_data, ap_tracking, .. }: HintArgs<'_, S>, +) -> OsHintExtensionResult { + let identifier_getter = &hint_processor.execution_helper.os_program; + let mut hint_extension = HintExtension::new(); + let mut compiled_class_facts_ptr = vm.add_memory_segment(); + // Iterate only over cairo 1 classes. + for (class_hash, class) in hint_processor.execution_helper.os_input.compiled_classes.iter() { + let compiled_class_fact = CompiledClassFact { class_hash, compiled_class: class }; + compiled_class_fact.load_into( + vm, + identifier_getter, + compiled_class_facts_ptr, + constants, + )?; + + // Compiled classes are expected to end with a `ret` opcode followed by a pointer to + // the builtin costs. + let bytecode_ptr_address = get_address_of_nested_fields_from_base_address( + compiled_class_facts_ptr, + CairoStruct::CompiledClassFact, + vm, + &["compiled_class", "bytecode_ptr"], + identifier_getter, + )?; + let bytecode_ptr = vm.get_relocatable(bytecode_ptr_address)?; + let builtin_costs = + get_relocatable_from_var_name(Ids::BuiltinCosts.into(), vm, ids_data, ap_tracking)?; + let encoded_ret_opcode = 0x208b7fff7fff7ffe; + let data = [encoded_ret_opcode.into(), builtin_costs.into()]; + vm.load_data((bytecode_ptr + class.bytecode.len())?, &data)?; + + // Extend hints. + for (rel_pc, hints) in class.hints.iter() { + let abs_pc = Relocatable::from((bytecode_ptr.segment_index, *rel_pc)); + hint_extension.insert(abs_pc, hints.iter().map(|h| any_box!(h.clone())).collect()); + } + + compiled_class_facts_ptr += CompiledClassFact::size(identifier_getter); + } + + Ok(hint_extension) +} diff --git a/crates/starknet_os/src/hints/hint_implementation/compiled_class/utils.rs b/crates/starknet_os/src/hints/hint_implementation/compiled_class/utils.rs new file mode 100644 index 00000000000..c2cdbfa6e8e --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/compiled_class/utils.rs @@ -0,0 +1,280 @@ +#![allow(dead_code)] +use std::collections::HashMap; + +use cairo_lang_starknet_classes::casm_contract_class::{CasmContractClass, CasmContractEntryPoint}; +use cairo_lang_starknet_classes::NestedIntList; +use cairo_vm::types::relocatable::{MaybeRelocatable, Relocatable}; +use cairo_vm::vm::vm_core::VirtualMachine; +use starknet_api::core::ClassHash; +use starknet_api::hash::PoseidonHash; +use starknet_types_core::felt::Felt; +use starknet_types_core::hash::{Poseidon, StarkHash}; + +use crate::hints::error::{OsHintError, OsHintResult}; +use crate::hints::vars::{CairoStruct, Const}; +use crate::vm_utils::{insert_values_to_fields, CairoSized, IdentifierGetter, LoadCairoObject}; + +#[cfg(test)] +#[path = "utils_test.rs"] +pub mod utils_test; + +impl LoadCairoObject for CasmContractEntryPoint { + fn load_into( + &self, + vm: &mut VirtualMachine, + identifier_getter: &IG, + address: Relocatable, + _constants: &HashMap, + ) -> OsHintResult { + // Allocate a segment for the builtin list. + let builtin_list_base = vm.add_memory_segment(); + let mut next_builtin_address = builtin_list_base; + // Insert the builtin list. + for builtin in self.builtins.iter() { + let builtin_as_felt = Felt::from_bytes_be_slice(builtin.as_bytes()); + vm.insert_value(next_builtin_address, builtin_as_felt)?; + next_builtin_address += 1; + } + // Insert the fields. + let nested_fields_and_value = [ + ("selector", Felt::from(&self.selector).into()), + ("offset", self.offset.into()), + ("n_builtins", self.builtins.len().into()), + ("builtin_list", builtin_list_base.into()), + ]; + insert_values_to_fields( + address, + CairoStruct::CompiledClassEntryPoint, + vm, + nested_fields_and_value.as_slice(), + identifier_getter, + )?; + + Ok(()) + } +} + +impl CairoSized for CasmContractEntryPoint { + fn size(_identifier_getter: &IG) -> usize { + // TODO(Nimrod): Fetch from IG after we upgrade the VM. + 4 + } +} + +impl LoadCairoObject for CasmContractClass { + fn load_into( + &self, + vm: &mut VirtualMachine, + identifier_getter: &IG, + address: Relocatable, + constants: &HashMap, + ) -> OsHintResult { + // Insert compiled class version field. + let compiled_class_version = Const::CompiledClassVersion.fetch(constants)?; + // Insert l1 handler entry points. + let l1_handlers_list_base = vm.add_memory_segment(); + self.entry_points_by_type.l1_handler.load_into( + vm, + identifier_getter, + l1_handlers_list_base, + constants, + )?; + + // Insert constructor entry points. + let constructor_list_base = vm.add_memory_segment(); + self.entry_points_by_type.constructor.load_into( + vm, + identifier_getter, + constructor_list_base, + constants, + )?; + + // Insert external entry points. + let externals_list_base = vm.add_memory_segment(); + self.entry_points_by_type.external.load_into( + vm, + identifier_getter, + externals_list_base, + constants, + )?; + + // Insert the bytecode entirely. + let bytecode_base = vm.add_memory_segment(); + // TODO(Nimrod): See if we can transfer ownership here instead of cloning. + + let bytecode: Vec<_> = + self.bytecode.iter().map(|x| MaybeRelocatable::from(Felt::from(&x.value))).collect(); + vm.load_data(bytecode_base, &bytecode)?; + + // Insert the fields. + let nested_fields_and_value = [ + ("compiled_class_version", compiled_class_version.into()), + ("external_functions", externals_list_base.into()), + ("n_external_functions", self.entry_points_by_type.external.len().into()), + ("l1_handlers", l1_handlers_list_base.into()), + ("n_l1_handlers", self.entry_points_by_type.l1_handler.len().into()), + ("constructors", constructor_list_base.into()), + ("n_constructors", self.entry_points_by_type.constructor.len().into()), + ("bytecode_ptr", bytecode_base.into()), + ("bytecode_length", bytecode.len().into()), + ]; + + insert_values_to_fields( + address, + CairoStruct::CompiledClass, + vm, + &nested_fields_and_value, + identifier_getter, + )?; + + Ok(()) + } +} + +pub(crate) struct CompiledClassFact<'a> { + pub(crate) class_hash: &'a ClassHash, + pub(crate) compiled_class: &'a CasmContractClass, +} + +impl LoadCairoObject for CompiledClassFact<'_> { + fn load_into( + &self, + vm: &mut VirtualMachine, + identifier_getter: &IG, + address: Relocatable, + constants: &HashMap, + ) -> OsHintResult { + let compiled_class_address = vm.add_memory_segment(); + self.compiled_class.load_into(vm, identifier_getter, compiled_class_address, constants)?; + let nested_fields_and_value = [ + ("class_hash", self.class_hash.0.into()), + ("compiled_class", compiled_class_address.into()), + ]; + insert_values_to_fields( + address, + CairoStruct::CompiledClassFact, + vm, + &nested_fields_and_value, + identifier_getter, + ) + } +} + +impl CairoSized for CompiledClassFact<'_> { + fn size(_identifier_getter: &IG) -> usize { + // TODO(Nimrod): Fetch from IG after we upgrade the VM. + 2 + } +} + +#[cfg_attr(test, derive(PartialEq))] +// TODO(Nimrod): When cloning is avoided in the `bytecode_segment_structure` hint, remove the Clone +// derives. +#[derive(Clone, Debug)] +pub(crate) struct BytecodeSegmentLeaf { + pub(crate) data: Vec, +} + +#[cfg_attr(test, derive(PartialEq))] +// TODO(Nimrod): When cloning is avoided in the `bytecode_segment_structure` hint, remove the Clone +// derives. +#[derive(Clone, Debug)] +pub(crate) struct BytecodeSegmentInnerNode { + pub(crate) segments: Vec, +} + +// TODO(Nimrod): When cloning is avoided in the `bytecode_segment_structure` hint, remove the Clone +// derives. +#[cfg_attr(test, derive(PartialEq))] +#[derive(Clone, Debug)] +pub(crate) enum BytecodeSegmentNode { + Leaf(BytecodeSegmentLeaf), + InnerNode(BytecodeSegmentInnerNode), +} + +impl BytecodeSegmentNode { + pub(crate) fn hash(&self) -> PoseidonHash { + match self { + BytecodeSegmentNode::Leaf(leaf) => PoseidonHash(Poseidon::hash_array(&leaf.data)), + BytecodeSegmentNode::InnerNode(inner_node) => { + let flatten_input: Vec<_> = inner_node + .segments + .iter() + .flat_map(|segment| [Felt::from(segment.length), segment.node.hash().0]) + .collect(); + PoseidonHash(Poseidon::hash_array(&flatten_input) + Felt::ONE) + } + } + } + + pub(crate) fn is_leaf(&self) -> bool { + match self { + BytecodeSegmentNode::Leaf(_) => true, + BytecodeSegmentNode::InnerNode(_) => false, + } + } +} + +#[cfg_attr(test, derive(PartialEq))] +// TODO(Nimrod): When cloning is avoided in the `bytecode_segment_structure` hint, remove the Clone +// derives. +#[derive(Clone, Debug)] +pub(crate) struct BytecodeSegment { + node: BytecodeSegmentNode, + length: usize, +} + +/// Creates the bytecode segment structure from the given bytecode and bytecode segment lengths. +pub(crate) fn create_bytecode_segment_structure( + bytecode: &[Felt], + bytecode_segment_lengths: NestedIntList, +) -> Result { + let (structure, total_len) = + create_bytecode_segment_structure_inner(bytecode, bytecode_segment_lengths, 0); + // Sanity checks. + if total_len != bytecode.len() { + return Err(OsHintError::AssertionFailed { + message: format!( + "Invalid length bytecode segment structure: {}. Bytecode length: {}.", + total_len, + bytecode.len() + ), + }); + } + + Ok(structure) +} + +/// Helper function for `create_bytecode_segment_structure`. +/// Returns the bytecode segment structure and the total length of the processed segment. +pub(crate) fn create_bytecode_segment_structure_inner( + bytecode: &[Felt], + bytecode_segment_lengths: NestedIntList, + bytecode_offset: usize, +) -> (BytecodeSegmentNode, usize) { + match bytecode_segment_lengths { + NestedIntList::Leaf(length) => { + let segment_end = bytecode_offset + length; + let bytecode_segment = bytecode[bytecode_offset..segment_end].to_vec(); + + (BytecodeSegmentNode::Leaf(BytecodeSegmentLeaf { data: bytecode_segment }), length) + } + NestedIntList::Node(lengths) => { + let mut segments = vec![]; + let mut total_len = 0; + let mut bytecode_offset = bytecode_offset; + + for item in lengths { + let (current_structure, item_len) = + create_bytecode_segment_structure_inner(bytecode, item, bytecode_offset); + + segments.push(BytecodeSegment { length: item_len, node: current_structure }); + + bytecode_offset += item_len; + total_len += item_len; + } + + (BytecodeSegmentNode::InnerNode(BytecodeSegmentInnerNode { segments }), total_len) + } + } +} diff --git a/crates/starknet_os/src/hints/hint_implementation/compiled_class/utils_test.rs b/crates/starknet_os/src/hints/hint_implementation/compiled_class/utils_test.rs new file mode 100644 index 00000000000..40cf9f97c87 --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/compiled_class/utils_test.rs @@ -0,0 +1,143 @@ +use cairo_lang_starknet_classes::NestedIntList; +use rstest::rstest; +use starknet_api::felt; +use starknet_types_core::felt::Felt; + +use super::{ + create_bytecode_segment_structure, + BytecodeSegment, + BytecodeSegmentInnerNode, + BytecodeSegmentNode, +}; +use crate::hints::hint_implementation::compiled_class::utils::BytecodeSegmentLeaf; + +fn dummy_bytecode(bytecode_len: u32) -> Vec { + (0..bytecode_len).map(|x| felt!(x)).collect() +} + +#[rstest] +#[case (3, NestedIntList::Node(vec![NestedIntList::Node(vec![NestedIntList::Leaf(3)])]), +BytecodeSegmentNode::InnerNode(BytecodeSegmentInnerNode { + segments: vec![BytecodeSegment { + node: BytecodeSegmentNode::InnerNode(BytecodeSegmentInnerNode { + segments: vec![BytecodeSegment { + node: BytecodeSegmentNode::Leaf(BytecodeSegmentLeaf { + data: vec![felt!(0_u8), felt!(1_u8), felt!(2_u8)], + }), + length: 3, + }], + }), + length: 3, + }], +}))] +#[case (3, NestedIntList::Leaf(3), BytecodeSegmentNode::Leaf(BytecodeSegmentLeaf { + data: vec![felt!(0_u8), felt!(1_u8), felt!(2_u8)], +}))] +#[case(4, NestedIntList::Node(vec![ + NestedIntList::Leaf(2), + NestedIntList::Leaf(2), +]), BytecodeSegmentNode::InnerNode(BytecodeSegmentInnerNode { + segments: vec![ + BytecodeSegment { + node: BytecodeSegmentNode::Leaf(BytecodeSegmentLeaf { + data: vec![felt!(0_u8), felt!(1_u8)], + }), + length: 2, + }, + BytecodeSegment { + node: BytecodeSegmentNode::Leaf(BytecodeSegmentLeaf { + data: vec![felt!(2_u8), felt!(3_u8)], + }), + length: 2, + }, + ], +}))] +#[case(4, NestedIntList::Node(vec![ + NestedIntList::Leaf(2), + NestedIntList::Node(vec![NestedIntList::Leaf(2)]), +]), BytecodeSegmentNode::InnerNode(BytecodeSegmentInnerNode { + segments: vec![ + BytecodeSegment { + node: BytecodeSegmentNode::Leaf(BytecodeSegmentLeaf { + data: vec![felt!(0_u8), felt!(1_u8)], + }), + length: 2, + }, + BytecodeSegment { + node: BytecodeSegmentNode::InnerNode(BytecodeSegmentInnerNode { + segments: vec![BytecodeSegment { + node: BytecodeSegmentNode::Leaf(BytecodeSegmentLeaf { + data: vec![felt!(2_u8), felt!(3_u8)], + }), + length: 2, + }], + }), + length: 2, + }, + ], +}))] +#[case(10, NestedIntList::Node(vec![ + NestedIntList::Leaf(3), + NestedIntList::Node(vec![ + NestedIntList::Leaf(1), + NestedIntList::Leaf(1), + NestedIntList::Node(vec![NestedIntList::Leaf(1)]), + ]), + NestedIntList::Leaf(4), +]), BytecodeSegmentNode::InnerNode(BytecodeSegmentInnerNode { + segments: vec![ + BytecodeSegment { + node: BytecodeSegmentNode::Leaf(BytecodeSegmentLeaf { + data: vec![felt!(0_u8), felt!(1_u8), felt!(2_u8)], + }), + length: 3, + }, + BytecodeSegment { + node: BytecodeSegmentNode::InnerNode(BytecodeSegmentInnerNode { + segments: vec![ + BytecodeSegment { + node: BytecodeSegmentNode::Leaf(BytecodeSegmentLeaf { + data: vec![felt!(3_u8)], + }), + length: 1, + }, + BytecodeSegment { + node: BytecodeSegmentNode::Leaf(BytecodeSegmentLeaf { + data: vec![felt!(4_u8)], + }), + length: 1, + }, + BytecodeSegment { + node: BytecodeSegmentNode::InnerNode(BytecodeSegmentInnerNode { + segments: vec![BytecodeSegment { + node: BytecodeSegmentNode::Leaf(BytecodeSegmentLeaf { + data: vec![felt!(5_u8)], + }), + length: 1, + }], + }), + length: 1, + }, + ], + }), + length: 3, + }, + BytecodeSegment { + node: BytecodeSegmentNode::Leaf(BytecodeSegmentLeaf { + data: vec![felt!(6_u8), felt!(7_u8), felt!(8_u8), felt!(9_u8)], + }), + length: 4, + }, + ], +}))] +fn create_bytecode_segment_structure_test( + #[case] bytecode_len: u32, + #[case] bytecode_segment_lengths: NestedIntList, + #[case] expected_structure: BytecodeSegmentNode, +) { + let bytecode = dummy_bytecode(bytecode_len); + let actual_structure = + create_bytecode_segment_structure(&bytecode, bytecode_segment_lengths).unwrap(); + + assert_eq!(actual_structure, expected_structure); +} diff --git a/crates/starknet_os/src/hints/hint_implementation/deprecated_compiled_class.rs b/crates/starknet_os/src/hints/hint_implementation/deprecated_compiled_class.rs new file mode 100644 index 00000000000..848a30b90f9 --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/deprecated_compiled_class.rs @@ -0,0 +1,3 @@ +pub mod implementation; +#[allow(dead_code)] +pub mod utils; diff --git a/crates/starknet_os/src/hints/hint_implementation/deprecated_compiled_class/implementation.rs b/crates/starknet_os/src/hints/hint_implementation/deprecated_compiled_class/implementation.rs new file mode 100644 index 00000000000..7bb990b8622 --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/deprecated_compiled_class/implementation.rs @@ -0,0 +1,154 @@ +use std::any::Any; +use std::collections::hash_map::IntoIter; +use std::collections::{HashMap, HashSet}; + +use blockifier::state::state_api::StateReader; +use cairo_vm::hint_processor::builtin_hint_processor::hint_utils::insert_value_from_var_name; +use cairo_vm::hint_processor::hint_processor_definition::{ + HintExtension, + HintProcessorLogic, + HintReference, +}; +use cairo_vm::serde::deserialize_program::{HintParams, ReferenceManager}; +use cairo_vm::types::relocatable::Relocatable; +use cairo_vm::vm::errors::hint_errors::HintError as VmHintError; +use starknet_api::core::ClassHash; +use starknet_api::deprecated_contract_class::ContractClass; +use starknet_types_core::felt::Felt; + +use crate::hints::error::{OsHintError, OsHintExtensionResult, OsHintResult}; +use crate::hints::types::HintArgs; +use crate::hints::vars::{CairoStruct, Ids, Scope}; +use crate::vm_utils::{get_address_of_nested_fields, LoadCairoObject}; + +pub(crate) fn load_deprecated_class_facts( + HintArgs { hint_processor, vm, exec_scopes, ids_data, ap_tracking, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let deprecated_compiled_classes = + &hint_processor.execution_helper.os_input.deprecated_compiled_classes; + // TODO(Rotem): see if we can avoid cloning here. + let deprecated_class_hashes: HashSet = + HashSet::from_iter(deprecated_compiled_classes.keys().cloned()); + exec_scopes.insert_value(Scope::DeprecatedClassHashes.into(), deprecated_class_hashes); + + insert_value_from_var_name( + Ids::NCompiledClassFacts.into(), + deprecated_compiled_classes.len(), + vm, + ids_data, + ap_tracking, + )?; + // TODO(Nimrod): See if we can avoid cloning here. + let scoped_classes: Box = Box::new(deprecated_compiled_classes.clone().into_iter()); + exec_scopes + .enter_scope(HashMap::from([(Scope::CompiledClassFacts.to_string(), scoped_classes)])); + + Ok(()) +} + +pub(crate) fn load_deprecated_class_inner( + HintArgs { hint_processor, vm, exec_scopes, ids_data, ap_tracking, constants }: HintArgs<'_, S>, +) -> OsHintResult { + let deprecated_class_iter = exec_scopes + .get_mut_ref::>(Scope::CompiledClassFacts.into())?; + + let (class_hash, deprecated_class) = deprecated_class_iter.next().ok_or_else(|| { + OsHintError::EndOfIterator { item_type: "deprecated_compiled_classes".to_string() } + })?; + + let dep_class_base = vm.add_memory_segment(); + deprecated_class.load_into( + vm, + &hint_processor.execution_helper.os_program, + dep_class_base, + constants, + )?; + + exec_scopes.insert_value(Scope::CompiledClassHash.into(), class_hash); + exec_scopes.insert_value(Scope::CompiledClass.into(), deprecated_class); + + Ok(insert_value_from_var_name( + Ids::CompiledClass.into(), + dep_class_base, + vm, + ids_data, + ap_tracking, + )?) +} + +pub(crate) fn load_deprecated_class( + HintArgs { hint_processor, vm, exec_scopes, ids_data, ap_tracking, .. }: HintArgs<'_, S>, +) -> OsHintExtensionResult { + let computed_hash_addr = get_address_of_nested_fields( + ids_data, + Ids::CompiledClassFact, + CairoStruct::DeprecatedCompiledClassFact, + vm, + ap_tracking, + &["hash"], + &hint_processor.execution_helper.os_program, + )?; + let computed_hash = vm.get_integer(computed_hash_addr)?; + let expected_hash = exec_scopes.get::(Scope::CompiledClassHash.into())?; + + if computed_hash.as_ref() != &expected_hash { + return Err(OsHintError::AssertionFailed { + message: format!( + "Computed compiled_class_hash is inconsistent with the hash in the os_input. \ + Computed hash = {computed_hash}, Expected hash = {expected_hash}." + ), + }); + } + + let dep_class = exec_scopes.get_ref::(Scope::CompiledClass.into())?; + + // TODO(Rotem): see if we can avoid cloning here. + let hints: HashMap> = + serde_json::from_value(dep_class.program.hints.clone()).map_err(|e| { + OsHintError::SerdeJsonDeserialize { error: e, value: dep_class.program.hints.clone() } + })?; + let ref_manager: ReferenceManager = + serde_json::from_value(dep_class.program.reference_manager.clone()).map_err(|e| { + OsHintError::SerdeJsonDeserialize { + error: e, + value: dep_class.program.reference_manager.clone(), + } + })?; + + let refs = ref_manager + .references + .iter() + .map(|r| HintReference::from(r.clone())) + .collect::>(); + + let byte_code_ptr_addr = get_address_of_nested_fields( + ids_data, + Ids::CompiledClass, + CairoStruct::DeprecatedCompiledClass, + vm, + ap_tracking, + &["bytecode_ptr"], + &hint_processor.execution_helper.os_program, + )?; + let byte_code_ptr = vm.get_relocatable(byte_code_ptr_addr)?; + + let mut hint_extension = HintExtension::new(); + + for (pc, hints_params) in hints.into_iter() { + let rel_pc = pc.parse().map_err(|_| VmHintError::WrongHintData)?; + let abs_pc = Relocatable::from((byte_code_ptr.segment_index, rel_pc)); + let mut compiled_hints = Vec::new(); + for params in hints_params.into_iter() { + let compiled_hint = hint_processor.compile_hint( + ¶ms.code, + ¶ms.flow_tracking_data.ap_tracking, + ¶ms.flow_tracking_data.reference_ids, + &refs, + )?; + compiled_hints.push(compiled_hint); + } + hint_extension.insert(abs_pc, compiled_hints); + } + + Ok(hint_extension) +} diff --git a/crates/starknet_os/src/hints/hint_implementation/deprecated_compiled_class/utils.rs b/crates/starknet_os/src/hints/hint_implementation/deprecated_compiled_class/utils.rs new file mode 100644 index 00000000000..251eebdbd19 --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/deprecated_compiled_class/utils.rs @@ -0,0 +1,151 @@ +use std::collections::HashMap; + +use cairo_vm::serde::deserialize_program::deserialize_array_of_bigint_hex; +use cairo_vm::types::relocatable::{MaybeRelocatable, Relocatable}; +use cairo_vm::vm::vm_core::VirtualMachine; +use starknet_api::contract_class::EntryPointType; +use starknet_api::deprecated_contract_class::{ContractClass, EntryPointV0}; +use starknet_types_core::felt::Felt; + +use crate::hints::class_hash::hinted_class_hash::{ + compute_cairo_hinted_class_hash, + CairoContractDefinition, +}; +use crate::hints::error::{OsHintError, OsHintResult}; +use crate::hints::vars::{CairoStruct, Const}; +use crate::vm_utils::{insert_values_to_fields, CairoSized, IdentifierGetter, LoadCairoObject}; + +impl LoadCairoObject for ContractClass { + fn load_into( + &self, + vm: &mut VirtualMachine, + identifier_getter: &IG, + address: Relocatable, + constants: &HashMap, + ) -> OsHintResult { + // Insert compiled class version field. + let compiled_class_version = Const::DeprecatedCompiledClassVersion.fetch(constants)?; + + // Insert external entry points. + let (externals_list_base, externals_len) = + insert_entry_points(self, vm, identifier_getter, constants, &EntryPointType::External)?; + + // Insert l1 handler entry points. + let (l1_handlers_list_base, l1_handlers_len) = insert_entry_points( + self, + vm, + identifier_getter, + constants, + &EntryPointType::L1Handler, + )?; + + // Insert constructor entry points. + let (constructors_list_base, constructors_len) = insert_entry_points( + self, + vm, + identifier_getter, + constants, + &EntryPointType::Constructor, + )?; + + // Insert builtins. + let builtins: Vec = + serde_json::from_value(self.program.builtins.clone()).map_err(|e| { + OsHintError::SerdeJsonDeserialize { error: e, value: self.program.builtins.clone() } + })?; + let builtins: Vec = builtins + .into_iter() + .map(|bi| (Felt::from_bytes_be_slice(bi.as_bytes())).into()) + .collect(); + + let builtin_list_base = vm.add_memory_segment(); + vm.load_data(builtin_list_base, &builtins)?; + + // Insert hinted class hash. + let contract_definition_vec = serde_json::to_vec(&self)?; + let contract_definition: CairoContractDefinition<'_> = + serde_json::from_slice(&contract_definition_vec).map_err(OsHintError::SerdeJson)?; + + let hinted_class_hash = compute_cairo_hinted_class_hash(&contract_definition)?; + + // Insert bytecode_ptr. + let bytecode_ptr = deserialize_array_of_bigint_hex(&self.program.data)?; + + let bytecode_ptr_base = vm.add_memory_segment(); + vm.load_data(bytecode_ptr_base, &bytecode_ptr)?; + + // Insert the fields. + let nested_fields_and_value = [ + ("compiled_class_version", compiled_class_version.into()), + ("n_external_functions", Felt::from(externals_len).into()), + ("external_functions", externals_list_base.into()), + ("n_l1_handlers", Felt::from(l1_handlers_len).into()), + ("l1_handlers", l1_handlers_list_base.into()), + ("n_constructors", Felt::from(constructors_len).into()), + ("constructors", constructors_list_base.into()), + ("n_builtins", Felt::from(builtins.len()).into()), + ("builtin_list", builtin_list_base.into()), + ("hinted_class_hash", hinted_class_hash.into()), + ("bytecode_length", Felt::from(bytecode_ptr.len()).into()), + ("bytecode_ptr", bytecode_ptr_base.into()), + ]; + insert_values_to_fields( + address, + CairoStruct::DeprecatedCompiledClass, + vm, + nested_fields_and_value.as_slice(), + identifier_getter, + )?; + + Ok(()) + } +} + +fn insert_entry_points( + dep_contract_class: &ContractClass, + vm: &mut VirtualMachine, + identifier_getter: &IG, + constants: &HashMap, + entry_point_type: &EntryPointType, +) -> Result<(Relocatable, usize), OsHintError> { + let list_base = vm.add_memory_segment(); + let n_entry_points = match dep_contract_class.entry_points_by_type.get(entry_point_type) { + Some(entry_points) => { + entry_points.load_into(vm, identifier_getter, list_base, constants)?; + entry_points.len() + } + None => 0, + }; + + Ok((list_base, n_entry_points)) +} + +impl LoadCairoObject for EntryPointV0 { + fn load_into( + &self, + vm: &mut VirtualMachine, + identifier_getter: &IG, + address: Relocatable, + _constants: &HashMap, + ) -> OsHintResult { + // Insert the fields. + let nested_fields_and_value = + [("selector", self.selector.0.into()), ("offset", self.offset.0.into())]; + insert_values_to_fields( + address, + CairoStruct::DeprecatedContractEntryPoint, + vm, + nested_fields_and_value.as_slice(), + identifier_getter, + )?; + + Ok(()) + } +} + +impl CairoSized for EntryPointV0 { + fn size(_identifier_getter: &IG) -> usize { + // TODO(Rotem): Fetch from IG after we upgrade the VM. + 2 + } +} diff --git a/crates/starknet_os/src/hints/hint_implementation/execute_syscalls.rs b/crates/starknet_os/src/hints/hint_implementation/execute_syscalls.rs new file mode 100644 index 00000000000..e4ab98d9c57 --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/execute_syscalls.rs @@ -0,0 +1,10 @@ +use blockifier::state::state_api::StateReader; + +use crate::hints::error::OsHintResult; +use crate::hints::types::HintArgs; + +pub(crate) fn is_block_number_in_block_hash_buffer( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} diff --git a/crates/starknet_os/src/hints/hint_implementation/execute_transactions.rs b/crates/starknet_os/src/hints/hint_implementation/execute_transactions.rs new file mode 100644 index 00000000000..52d8820b371 --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/execute_transactions.rs @@ -0,0 +1,92 @@ +use blockifier::state::state_api::StateReader; +use cairo_vm::hint_processor::builtin_hint_processor::hint_utils::{ + get_integer_from_var_name, + get_ptr_from_var_name, + insert_value_into_ap, +}; +use cairo_vm::types::relocatable::Relocatable; +use starknet_types_core::felt::Felt; + +use crate::hints::enum_definition::{AllHints, OsHint}; +use crate::hints::error::OsHintResult; +use crate::hints::nondet_offsets::insert_nondet_hint_value; +use crate::hints::types::HintArgs; +use crate::hints::vars::Ids; + +pub(crate) fn set_sha256_segment_in_syscall_handler( + HintArgs { hint_processor, vm, ids_data, ap_tracking, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let sha256_ptr = get_ptr_from_var_name(Ids::Sha256Ptr.into(), vm, ids_data, ap_tracking)?; + hint_processor.syscall_hint_processor.set_sha256_segment(sha256_ptr); + Ok(()) +} + +pub(crate) fn log_remaining_txs( + HintArgs { vm, ids_data, ap_tracking, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let n_txs = get_integer_from_var_name(Ids::NTxs.into(), vm, ids_data, ap_tracking)?; + log::debug!("execute_transactions_inner: {n_txs} transactions remaining."); + Ok(()) +} + +pub(crate) fn fill_holes_in_rc96_segment( + HintArgs { vm, ids_data, ap_tracking, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let rc96_ptr = get_ptr_from_var_name(Ids::RangeCheck96Ptr.into(), vm, ids_data, ap_tracking)?; + let segment_size = rc96_ptr.offset; + let base = Relocatable::from((rc96_ptr.segment_index, 0)); + + for i in 0..segment_size { + let address = (base + i)?; + if vm.get_maybe(&address).is_none() { + vm.insert_value(address, Felt::ZERO)?; + } + } + + Ok(()) +} + +pub(crate) fn set_component_hashes( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn sha2_finalize(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn segments_add_temp( + HintArgs { vm, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let temp_segment = vm.add_temporary_segment(); + insert_nondet_hint_value(vm, AllHints::OsHint(OsHint::SegmentsAddTemp), temp_segment) +} + +pub(crate) fn set_ap_to_actual_fee( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn skip_tx(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn start_tx(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + // TODO(lior): No longer equivalent to moonsong impl; PTAL at the new implementation of + // start_tx(). + todo!() +} + +pub(crate) fn os_input_transactions( + HintArgs { hint_processor, vm, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let num_txns = hint_processor.execution_helper.os_input.transactions.len(); + insert_nondet_hint_value(vm, AllHints::OsHint(OsHint::OsInputTransactions), num_txns) +} + +pub(crate) fn segments_add(HintArgs { vm, .. }: HintArgs<'_, S>) -> OsHintResult { + let segment = vm.add_memory_segment(); + Ok(insert_value_into_ap(vm, segment)?) +} diff --git a/crates/starknet_os/src/hints/hint_implementation/execution.rs b/crates/starknet_os/src/hints/hint_implementation/execution.rs new file mode 100644 index 00000000000..0ce75ce496f --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/execution.rs @@ -0,0 +1,4 @@ +#[cfg(test)] +pub mod execution_hints_test; +pub mod implementation; +pub mod utils; diff --git a/crates/starknet_os/src/hints/hint_implementation/execution/execution_hints_test.rs b/crates/starknet_os/src/hints/hint_implementation/execution/execution_hints_test.rs new file mode 100644 index 00000000000..633b757ab8c --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/execution/execution_hints_test.rs @@ -0,0 +1,14 @@ +use rstest::rstest; +use starknet_types_core::felt::Felt; + +use super::utils::tx_name_as_felt; + +#[rstest] +#[case::invoke("INVOKE_FUNCTION", Felt::from_hex_unchecked("0x494e564f4b455f46554e4354494f4e"))] +#[case::l1_handler("L1_HANDLER", Felt::from_hex_unchecked("0x4c315f48414e444c4552"))] +#[case::deploy("DEPLOY_ACCOUNT", Felt::from_hex_unchecked("0x4445504c4f595f4143434f554e54"))] +#[case::declare("DECLARE", Felt::from_hex_unchecked("0x4445434c415245"))] +fn tx_type_as_hex_regression(#[case] tx_name: &'static str, #[case] expected_hex: Felt) { + let tx_type = tx_name_as_felt(tx_name); + assert_eq!(tx_type, expected_hex); +} diff --git a/crates/starknet_os/src/hints/hint_implementation/execution/implementation.rs b/crates/starknet_os/src/hints/hint_implementation/execution/implementation.rs new file mode 100644 index 00000000000..67a5f46bba8 --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/execution/implementation.rs @@ -0,0 +1,588 @@ +use std::collections::{HashMap, HashSet}; +use std::vec::IntoIter; + +use blockifier::state::state_api::{State, StateReader}; +use cairo_vm::any_box; +use cairo_vm::hint_processor::builtin_hint_processor::hint_utils::{ + get_constant_from_var_name, + get_integer_from_var_name, + get_ptr_from_var_name, + insert_value_from_var_name, + insert_value_into_ap, +}; +use cairo_vm::types::relocatable::MaybeRelocatable; +use starknet_api::block::BlockNumber; +use starknet_api::core::{ClassHash, ContractAddress, PatriciaKey}; +use starknet_api::executable_transaction::Transaction; +use starknet_api::state::StorageKey; +use starknet_api::transaction::fields::ValidResourceBounds; +use starknet_types_core::felt::Felt; + +use crate::hints::error::{OsHintError, OsHintResult}; +use crate::hints::hint_implementation::execution::utils::tx_name_as_felt; +use crate::hints::types::HintArgs; +use crate::hints::vars::{CairoStruct, Const, Ids, Scope}; +use crate::syscall_handler_utils::SyscallHandlerType; +use crate::vm_utils::{get_address_of_nested_fields, LoadCairoObject}; + +pub(crate) fn load_next_tx( + HintArgs { exec_scopes, vm, ids_data, ap_tracking, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let mut txs_iter: IntoIter = exec_scopes.get(Scope::Transactions.into())?; + let tx = txs_iter.next().ok_or(OsHintError::EndOfIterator { item_type: "txs".to_string() })?; + let tx_type = tx_name_as_felt(tx.tx_type_name()); + insert_value_from_var_name(Ids::TxType.into(), tx_type, vm, ids_data, ap_tracking)?; + + // TODO(Yoav): add logger and log enter_tx. + exec_scopes.insert_value(Scope::Transactions.into(), txs_iter); + exec_scopes.insert_value(Scope::Tx.into(), tx); + Ok(()) +} + +pub(crate) fn load_resource_bounds( + HintArgs { exec_scopes, vm, ids_data, ap_tracking, hint_processor, constants }: HintArgs<'_, S>, +) -> OsHintResult { + // Guess the resource bounds. + let tx = exec_scopes.get::(Scope::Tx.into())?; + let resource_bounds = match tx { + Transaction::Account(account_tx) => account_tx.resource_bounds(), + Transaction::L1Handler(_) => return Err(OsHintError::UnexpectedTxType(tx)), + }; + if let ValidResourceBounds::L1Gas(_) = resource_bounds { + return Err(OsHintError::AssertionFailed { + message: "Only transactions with 3 resource bounds are supported. Got 1 resource \ + bounds." + .to_string(), + }); + } + + let resource_bound_address = vm.add_memory_segment(); + resource_bounds.load_into( + vm, + &hint_processor.execution_helper.os_program, + resource_bound_address, + constants, + )?; + + insert_value_from_var_name( + Ids::ResourceBounds.into(), + MaybeRelocatable::RelocatableValue(resource_bound_address), + vm, + ids_data, + ap_tracking, + )?; + Ok(()) +} + +pub(crate) fn exit_tx(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + // TODO(Aner): implement OsLogger + Ok(()) +} + +pub(crate) fn prepare_constructor_execution( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn assert_transaction_hash( + HintArgs { exec_scopes, vm, ids_data, ap_tracking, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let stored_transaction_hash = + get_integer_from_var_name(Ids::TransactionHash.into(), vm, ids_data, ap_tracking)?; + let tx = exec_scopes.get::(Scope::Tx.into())?; + let calculated_tx_hash = tx.tx_hash().0; + + if calculated_tx_hash == stored_transaction_hash { + Ok(()) + } else { + Err(OsHintError::AssertionFailed { + message: format!( + "Computed transaction_hash is inconsistent with the hash in the transaction. \ + Computed hash = {stored_transaction_hash:#x}, Expected hash = \ + {calculated_tx_hash:#x}." + ), + }) + } +} + +pub(crate) fn enter_scope_deprecated_syscall_handler( + HintArgs { exec_scopes, .. }: HintArgs<'_, S>, +) -> OsHintResult { + exec_scopes.insert_value( + Scope::SyscallHandlerType.into(), + SyscallHandlerType::DeprecatedSyscallHandler, + ); + Ok(()) +} + +pub(crate) fn enter_scope_syscall_handler( + HintArgs { exec_scopes, .. }: HintArgs<'_, S>, +) -> OsHintResult { + exec_scopes.insert_value(Scope::SyscallHandlerType.into(), SyscallHandlerType::SyscallHandler); + Ok(()) +} + +pub(crate) fn get_contract_address_state_entry( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn set_state_entry_to_account_contract_address( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn get_block_hash_contract_address_state_entry_and_set_new_state_entry< + S: StateReader, +>( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn get_contract_address_state_entry_and_set_new_state_entry( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn check_is_deprecated( + HintArgs { hint_processor, vm, ids_data, ap_tracking, exec_scopes, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let class_hash = ClassHash( + *vm.get_integer( + get_address_of_nested_fields( + ids_data, + Ids::ExecutionContext, + CairoStruct::ExecutionContext, + vm, + ap_tracking, + &["class_hash"], + &hint_processor.execution_helper.os_program, + )? + .to_owned(), + )?, + ); + + exec_scopes.insert_value( + Scope::IsDeprecated.into(), + Felt::from( + exec_scopes + .get::>(Scope::DeprecatedClassHashes.into())? + .contains(&class_hash), + ), + ); + + Ok(()) +} + +pub(crate) fn is_deprecated( + HintArgs { vm, exec_scopes, .. }: HintArgs<'_, S>, +) -> OsHintResult { + Ok(insert_value_into_ap(vm, exec_scopes.get::(Scope::IsDeprecated.into())?)?) +} + +pub(crate) fn enter_syscall_scopes( + HintArgs { exec_scopes, hint_processor, .. }: HintArgs<'_, S>, +) -> OsHintResult { + // The scope variables `syscall_handler`, `deprecated_syscall_handler` and `execution_helper` + // are accessible through the hint processor. + let deprecated_class_hashes: HashSet = + exec_scopes.get(Scope::DeprecatedClassHashes.into())?; + // TODO(Nimrod): See if we can avoid cloning here. + let component_hashes = + hint_processor.execution_helper.os_input.declared_class_hash_to_component_hashes.clone(); + let transactions_iter = + hint_processor.execution_helper.os_input.transactions.clone().into_iter(); + let dict_manager = exec_scopes.get_dict_manager()?; + + let new_scope = HashMap::from([ + (Scope::DictManager.into(), any_box!(dict_manager)), + (Scope::DeprecatedClassHashes.into(), any_box!(deprecated_class_hashes)), + (Scope::ComponentHashes.into(), any_box!(component_hashes)), + (Scope::Transactions.into(), any_box!(transactions_iter)), + ]); + exec_scopes.enter_scope(new_scope); + + Ok(()) +} + +pub(crate) fn end_tx(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + // TODO(lior): No longer equivalent to moonsong impl; PTAL the new implementation of + // end_tx(). + todo!() +} + +pub(crate) fn enter_call(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + // TODO(lior): No longer equivalent to moonsong impl; PTAL the new implementation of + // enter_call(). + todo!() +} + +pub(crate) fn exit_call(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + // TODO(lior): No longer equivalent to moonsong impl; PTAL the new implementation of + // exit_call(). + todo!() +} + +pub(crate) fn contract_address(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn tx_calldata_len(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn tx_calldata(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn tx_entry_point_selector( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn tx_version(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn tx_tip(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn tx_paymaster_data_len( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn tx_paymaster_data(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn tx_nonce_data_availability_mode( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn tx_fee_data_availability_mode( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn tx_account_deployment_data_len( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn tx_account_deployment_data( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn gen_signature_arg(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn is_reverted(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn check_execution(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn is_remaining_gas_lt_initial_budget( + HintArgs { vm, ids_data, ap_tracking, constants, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let remaining_gas = + get_integer_from_var_name(Ids::RemainingGas.into(), vm, ids_data, ap_tracking)?; + let initial_budget = + get_constant_from_var_name(Const::EntryPointInitialBudget.into(), constants)?; + let remaining_gas_lt_initial_budget: Felt = (&remaining_gas < initial_budget).into(); + Ok(insert_value_into_ap(vm, remaining_gas_lt_initial_budget)?) +} + +pub(crate) fn check_syscall_response( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn check_new_syscall_response( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn check_new_deploy_response( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn log_enter_syscall(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn initial_ge_required_gas( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn set_ap_to_tx_nonce(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn set_fp_plus_4_to_tx_nonce( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn enter_scope_node(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn enter_scope_new_node( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn enter_scope_next_node_bit_0( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn enter_scope_next_node_bit_1( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn enter_scope_left_child( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn enter_scope_right_child( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn enter_scope_descend_edge( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +fn write_syscall_result_helper( + HintArgs { hint_processor, vm, ids_data, ap_tracking, exec_scopes, .. }: HintArgs<'_, S>, + ids_type: Ids, + struct_type: CairoStruct, + key_name: &str, +) -> OsHintResult { + let key = StorageKey(PatriciaKey::try_from( + vm.get_integer(get_address_of_nested_fields( + ids_data, + ids_type.clone(), + struct_type, + vm, + ap_tracking, + &[key_name], + &hint_processor.execution_helper.os_program, + )?)? + .into_owned(), + )?); + + let contract_address = ContractAddress( + get_integer_from_var_name(Ids::ContractAddress.into(), vm, ids_data, ap_tracking)? + .try_into()?, + ); + + let prev_value = + hint_processor.execution_helper.cached_state.get_storage_at(contract_address, key)?; + + insert_value_from_var_name(Ids::PrevValue.into(), prev_value, vm, ids_data, ap_tracking)?; + + let request_value = vm + .get_integer(get_address_of_nested_fields( + ids_data, + ids_type, + struct_type, + vm, + ap_tracking, + &["value"], + &hint_processor.execution_helper.os_program, + )?)? + .into_owned(); + + hint_processor.execution_helper.cached_state.set_storage_at( + contract_address, + key, + request_value, + )?; + + // Fetch a state_entry in this hint and validate it in the update that comes next. + + let contract_state_changes_ptr = + get_ptr_from_var_name(Ids::ContractStateChanges.into(), vm, ids_data, ap_tracking)?; + let dict_manager = exec_scopes.get_dict_manager()?; + let mut dict_manager_borrowed = dict_manager.borrow_mut(); + let contract_address_state_entry = dict_manager_borrowed + .get_tracker_mut(contract_state_changes_ptr)? + .get_value(&contract_address.key().into())?; + + insert_value_from_var_name( + Ids::StateEntry.into(), + contract_address_state_entry, + vm, + ids_data, + ap_tracking, + )?; + + Ok(()) +} + +pub(crate) fn write_syscall_result_deprecated( + hint_args: HintArgs<'_, S>, +) -> OsHintResult { + write_syscall_result_helper(hint_args, Ids::SyscallPtr, CairoStruct::StorageWritePtr, "address") +} + +pub(crate) fn write_syscall_result(hint_args: HintArgs<'_, S>) -> OsHintResult { + write_syscall_result_helper(hint_args, Ids::Request, CairoStruct::StorageReadRequestPtr, "key") +} + +pub(crate) fn declare_tx_fields(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn write_old_block_to_storage( + HintArgs { hint_processor, vm, ids_data, ap_tracking, constants, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let execution_helper = &mut hint_processor.execution_helper; + + let block_hash_contract_address = + get_constant_from_var_name(Const::BlockHashContractAddress.into(), constants)?; + let old_block_number = + get_integer_from_var_name(Ids::OldBlockNumber.into(), vm, ids_data, ap_tracking)?; + let old_block_hash = + get_integer_from_var_name(Ids::OldBlockHash.into(), vm, ids_data, ap_tracking)?; + + log::debug!("writing block number: {} -> block hash: {}", old_block_number, old_block_hash); + + execution_helper.cached_state.set_storage_at( + ContractAddress(PatriciaKey::try_from(*block_hash_contract_address)?), + StorageKey(PatriciaKey::try_from(old_block_number)?), + old_block_hash, + )?; + Ok(()) +} + +fn assert_value_cached_by_reading( + HintArgs { hint_processor, vm, ids_data, ap_tracking, .. }: HintArgs<'_, S>, + id: Ids, + cairo_struct_type: CairoStruct, + nested_fields: &[&str], +) -> OsHintResult { + let key = StorageKey(PatriciaKey::try_from( + vm.get_integer(get_address_of_nested_fields( + ids_data, + id, + cairo_struct_type, + vm, + ap_tracking, + nested_fields, + &hint_processor.execution_helper.os_program, + )?)? + .into_owned(), + )?); + + let contract_address = ContractAddress( + get_integer_from_var_name(Ids::ContractAddress.into(), vm, ids_data, ap_tracking)? + .try_into()?, + ); + + let value = + hint_processor.execution_helper.cached_state.get_storage_at(contract_address, key)?; + + let ids_value = get_integer_from_var_name(Ids::Value.into(), vm, ids_data, ap_tracking)?; + + if value != ids_value { + return Err(OsHintError::InconsistentValue { expected: value, actual: ids_value }); + } + Ok(()) +} + +pub(crate) fn cache_contract_storage_request_key( + hint_args: HintArgs<'_, S>, +) -> OsHintResult { + assert_value_cached_by_reading( + hint_args, + Ids::Request, + CairoStruct::StorageReadRequestPtr, + &["key"], + ) +} + +pub(crate) fn cache_contract_storage_syscall_request_address( + hint_args: HintArgs<'_, S>, +) -> OsHintResult { + assert_value_cached_by_reading( + hint_args, + Ids::SyscallPtr, + CairoStruct::StorageReadPtr, + &["request", "key"], + ) +} + +pub(crate) fn get_old_block_number_and_hash( + HintArgs { hint_processor, vm, ids_data, ap_tracking, constants, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let os_input = &hint_processor.execution_helper.os_input; + let (old_block_number, old_block_hash) = + os_input.old_block_number_and_hash.ok_or(OsHintError::BlockNumberTooSmall { + stored_block_hash_buffer: *get_constant_from_var_name( + Const::StoredBlockHashBuffer.into(), + constants, + )?, + })?; + + let ids_old_block_number = BlockNumber( + get_integer_from_var_name(Ids::OldBlockNumber.into(), vm, ids_data, ap_tracking)? + .try_into() + .expect("Block number should fit in u64"), + ); + if old_block_number != ids_old_block_number { + return Err(OsHintError::InconsistentBlockNumber { + expected: old_block_number, + actual: ids_old_block_number, + }); + } + insert_value_from_var_name( + Ids::OldBlockHash.into(), + old_block_hash.0, + vm, + ids_data, + ap_tracking, + )?; + Ok(()) +} + +pub(crate) fn fetch_result(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} diff --git a/crates/starknet_os/src/hints/hint_implementation/execution/utils.rs b/crates/starknet_os/src/hints/hint_implementation/execution/utils.rs new file mode 100644 index 00000000000..cd3f9051ff7 --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/execution/utils.rs @@ -0,0 +1,61 @@ +use std::collections::HashMap; + +use blockifier::execution::syscalls::hint_processor::{ + valid_resource_bounds_as_felts, + ResourceAsFelts, +}; +use cairo_vm::types::relocatable::Relocatable; +use cairo_vm::vm::vm_core::VirtualMachine; +use starknet_api::transaction::fields::ValidResourceBounds; +use starknet_types_core::felt::Felt; + +use crate::hints::error::{OsHintError, OsHintResult}; +use crate::hints::vars::CairoStruct; +use crate::vm_utils::{insert_values_to_fields, CairoSized, IdentifierGetter, LoadCairoObject}; + +impl LoadCairoObject for ResourceAsFelts { + fn load_into( + &self, + vm: &mut VirtualMachine, + identifier_getter: &IG, + address: Relocatable, + _constants: &HashMap, + ) -> OsHintResult { + let resource_bounds_list = vec![ + ("resource_name", self.resource_name.into()), + ("max_amount", self.max_amount.into()), + ("max_price_per_unit", self.max_price_per_unit.into()), + ]; + insert_values_to_fields( + address, + CairoStruct::ResourceBounds, + vm, + &resource_bounds_list, + identifier_getter, + ) + } +} + +impl CairoSized for ResourceAsFelts { + fn size(_identifier_getter: &IG) -> usize { + 3 + } +} + +impl LoadCairoObject for ValidResourceBounds { + fn load_into( + &self, + vm: &mut VirtualMachine, + identifier_getter: &IG, + address: Relocatable, + constants: &HashMap, + ) -> OsHintResult { + valid_resource_bounds_as_felts(self, false) + .map_err(OsHintError::ResourceBoundsParsing)? + .load_into(vm, identifier_getter, address, constants) + } +} + +pub fn tx_name_as_felt(tx_type_name: &'static str) -> Felt { + Felt::from_bytes_be_slice(tx_type_name.as_bytes()) +} diff --git a/crates/starknet_os/src/hints/hint_implementation/find_element.rs b/crates/starknet_os/src/hints/hint_implementation/find_element.rs new file mode 100644 index 00000000000..55d4b0ec261 --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/find_element.rs @@ -0,0 +1,10 @@ +use blockifier::state::state_api::StateReader; + +use crate::hints::error::OsHintResult; +use crate::hints::types::HintArgs; + +pub(crate) fn search_sorted_optimistic( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} diff --git a/crates/starknet_os/src/hints/hint_implementation/kzg.rs b/crates/starknet_os/src/hints/hint_implementation/kzg.rs new file mode 100644 index 00000000000..b142310d0e7 --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/kzg.rs @@ -0,0 +1,4 @@ +pub(crate) mod implementation; +#[cfg(test)] +mod test; +pub(crate) mod utils; diff --git a/crates/starknet_os/src/hints/hint_implementation/kzg/blob_regression_input.json b/crates/starknet_os/src/hints/hint_implementation/kzg/blob_regression_input.json new file mode 100644 index 00000000000..1e6b6c1f9fc --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/kzg/blob_regression_input.json @@ -0,0 +1,4098 @@ +[ + "8063396892870388055806370369789704857755116044327394765020751373651916505604", + "8508483812464206518085049244372452833194835134520979270007832350261298667882", + "19117113120082819016668200647135001715837478318358716841264060050227396465881", + "37077981857546661241251130312207907184193238693974231148147352916768788994135", + "30184313526435205135692234381176229638581505933393057499629411046922039007164", + "5400072087579183248417097986155207708844723555046489096582298578632779472835", + "36200418421588775243309119949223232894801620146762327411501330245855064527084", + "42280241257371673815160097152767428025946064322242734718711257798115980928325", + "12835778768437414954554807192803990376950332714222309733373695821840423884746", + "5281042937224358728984373427998613507632789856857526327590127736191247052535", + "28327769318998424473532788120723840128251581309766749532608750538862301288657", + "19264938547969613489392752937264473211287691947968633170915134226785586853649", + "31682458506259988622192630565295757095527038643769309319969071968893578307182", + "18355758583510375527229065609964591240097367339368617206113154076390928028279", + "1908972521616433956609934641213364218294969156411721565915156761981419904370", + "39295432658001474208918713976717616486582724731695270383527141209542013924326", + "4646060149838860084656545214937492305268122861299979864954781272966624859320", + "48509082895212880922588102806120103933870676461542927621894095505499261676662", + "12459303475592427006440908860462157839889864313655746962312348448742974518257", + "15933617506542846606761410350525938171792076508786513142153149325668127950342", + "33989303027894377464128790036640672587141451889816337183433222825857542216282", + "15692026166397326803843140914154516885100162609673181658720720632988883310087", + "24671307205800365422241814735443776358671726753112605431028168009443029320530", + "12666123817642246610953242851909188858006331216227426940794701642485695753795", + "34863289447919745835223996864661456090162471367486813514803121220420420007345", + "48058703862441633327864008339270291570921096269694555395911427375369109051116", + "6718612685744939514438602529550307001146040834908172035568740609223459710751", + "41575921491965879624959110143670552736337045532413991744101593675326817369363", + "39331515792579927332821833657509250308707944404947586142921202265560605759482", + "4052972149635276880396637686341220622997466248637518786707248612348639122483", + "3534115976703630595461698371631482964268204042340603815738640727147083744377", + "22653344215783509727012660968466744095786981837468814379573294868904989839982", + "52239845781535186100948242198875771073738488767342081954145273525027178347310", + "44426433932801284048049816935605209612935345089311934984950534113472280634358", + "30654463277313049987259166826074498037488833264261265368281385214857023614251", + "764445356307967123027413444162238972284886997755340128916580659309166005167", + "8881992422822763548398950308247476900193888600170088982716089111980422130880", + "42786110366009063137854231548380555351684511425412490560454716608090344750839", + "27895882512795010858021889447473437790643471863512388611425186780684706038768", + "51640003201006269384133997978334384293281334081004236300987879464084211201115", + "43334371859868923586949967290419880999257736421305210400676904166452216286365", + "40445174580395882336472262939507832152530506145500448317117066416386913815580", + "41126453839615682460960731728547426766058033280700319779866738603969595791733", + "50467298482596985561368105862360868759919256533923882897509473178722764570448", + "9591925511631181273371679192773119781967254961488173021140530153328015514412", + "51234844824555622129594697798777114115124534342844368925010114745032132172259", + "2252745749070573980190878793504694982212140632879777747892017891336395780133", + "47632229432209145974529032479449822246459979717761858285107789724747107727439", + "852767511478416453169505353624999035667010115999240565272356364686824970949", + "827410582392053602209463844279378813864173047000826926965465922578799228820", + "35435966703677323598020559131402045868865449717685650123411597901655072476682", + "17508692843974048887755313720387387070029293045367212718876571010652447466773", + "46306678105088771524417339611844465820076741862649813911876124108884313760126", + "47316886719698745415696219533385129380958735125607912116953526080583505470740", + "49283414537087001345240652897998808597576271108041064534914447418456570182368", + "18220651295779370063929410099333606219221864014265152643018369535351864772994", + "49000891678807389022761048552101245836202262238281384306400748368577698856408", + "37293357891579984887734529208927390707246612291048096402410655689113988451497", + "10322188440967937402192179617980369708745553259012692612017487763994307986210", + "15711448365926475048115366267749639388645454251566208819911949694242718565753", + "45125156632991563268073399185533374813546591667159154108907135771310693171333", + "33779515537299172584679855725278905804206782089640898365159964180357490382322", + "6652048019700371916697052695561321009412930140298651475262939612226244227511", + "49619028180423324091952874326268613680034304285937897426664717952872045769262", + "17323973007254719967225951846047055270208805457008345278611565412248633908905", + "19515630004545582795980012349821015741349860294022556078979388454925505344000", + "6716407968667810474080223581393407321134522444842859279581279771708744652297", + "39780979373747884815453681155403207328694783888936663655678724924378103459148", + "46671072058228535396884297320816323783454501626749938080426723935174232859230", + "11465748944847715131290477704963370070971578928030556909294892726374513822807", + "32217678792868839012189433355603758097423260037846132208424918352667491136462", + "41361303018991334776877151746491556429689548285624454405134790177837161475494", + "6658763097131892283839768445719772464851492837957326472673966341657851555101", + "30442650098963666978204235331260035374760021726412007075429041608157338074764", + "14849158607587160189549764333869255184490701223381479814011489405098553824392", + "36093267557204431059728097263524618447484710211955664551779714171357581092749", + "47879252659420373308539832967202271038461442503114754614446113351957871033584", + "32647818103180216509860925076759998951454804395958573888244794465132136487284", + "39329846393817829412828532419012843592427514784941255890512721339063737090915", + "36767739675129603786435776576778041076924190411314243830325896051753354498564", + "561861659129157478464061156438667316865647695956774519929010830026279065093", + "18632388299314001730846894316937836657077334319969177342577398425756875926946", + "9026303639718645238787520094340247628158678670610459653008352644216705544877", + "27236116375462940816921948901244707646870540437491999809542788884665423046716", + "3841673966085906172644231454293544902005872942585562604356311929352561158525", + "25971534223446189654126016340708722563756948877100871569047825083605865958031", + "26674739350162993830307628236657362670504275097659695305052985888291728512261", + "1946349854106894931830953985651198131558044856593109819736074611723202858623", + "34745864327842653936883039727782428214423328456637171547575661602891570433673", + "16770408004710696959039978524472625938771283346882677748582245026928065219292", + "48950641315681965605962717720758443761881467557631654681652601870786411694832", + "50067152657641967110884710069436539169000355150678499861938698355527422942319", + "17510198106988474500458397900131817069752001672730646170591727993631028387873", + "15169199526847735301129592222053030221723063612936965762397312197934851387032", + "22213521258648216036484664426707715394344763507085826562961855499729155455448", + "42232307902238715539214874503759612056147374908434730211012313952580136874168", + "8157835238189372133400207150092491390098816362775369763449574374707327073848", + "40451758239305997375187440306699834561443653979628177506235617423923899572788", + "26995707246581498319802234697030705977177624983947622005351408611322176237159", + "1171125663730423465148979760652625582199967721143387243049341591534295689300", + "40531845198915898885924736204387834705668461525276256644232303014525113706521", + "45011916214659526478362322553331579561242960740589881969273776839747922341784", + "35567325887850450334333620852219827541879268750161881530279749799480622683941", + "41315595289803921511943851102488359880463402415101297399871164631757495418279", + "22443152175769585933324306273300024678893133782784392529944277472946817980564", + "2210726280984152539680098767657805758755666421340602687703259766703296125330", + "20643055207744801696382531515101059719298976655187953112133495890583991394629", + "2314723001264777018135667072618274020332681287509404957626556378649691456845", + "32957714373463787570990869754573184910545255802754079818187228333910544175346", + "51219822884939900117060589847744468572645982522154106302024382011882665494238", + "29359473460872155010882868467007007304438629803440148133272503386620241023207", + "24435402987726599820188105712715957161787482584303061510900721274093132375668", + "24036205615963970408773507187106700490423373387353718375133294332844513027830", + "24958192207115548168492656419214305856440180293117556526593835313138335546398", + "18787216095635319315697690865043681848106544720314862971558904024845847697608", + "40051045021693762319721072681373454824439367136064191304233344331337252245563", + "13344663894795640801701321433738306044448153407661155658135389909106699880663", + "187125948949796107152113282242971410063389659414358388721561773913538194526", + "43304899373832349049218421311015753694826736320293053218259753944105704303486", + "13481852619924376579959371750223120880486068942043834648097177282673955494147", + "40960321497980898061646342669467626119563098016391938801875722451917208743633", + "19395937166471808191406302273236800705763412631803415292911861755900077032398", + "32028353580131374998620282932832282719862718762857599553913049834637453348213", + "30871784920618693193607139309786704753447421684163832122999117085190887530296", + "7250668715078986538256919381725119562582293430460973257848308528843869817757", + "10649654527334653876508303991031389547074888739500049121743545852195691595226", + "34807577893532800129038635515027889114770391794446461535626729231712971317354", + "17333303496789437464376019222805724352037567041656449566663649403196217146741", + "17254648822998867276259036987740157896790137392277126149696339357123999677361", + "36882357054102232380439071839654763793327291886142535024232317541154615735517", + "6493547392407192426556028957834874208666896092723214798292339187409067185694", + "36562331705696596707940306472797472771670593592618611687215157578751389539020", + "48063777114988404621595293039059783305087096261779351223816030636161441878760", + "6626620314781029932985930697824533249790879115780425359144622875142888955641", + "24560027379103483606751991934807530075842934348965009722425536297644721518331", + "1251676965309971925506030197376371941088043943136383971898778321220664041370", + "23067440619281980344416014567892947604753048796375267435088245581842805084697", + "43222347046009078417616446453950423557602825633420580912065255950313700891996", + "11349413211523873762182123465904837804080230217657469450559935578192692833402", + "30895567049925796030712346825105252359170936759710249127085437259937913555157", + "44116818436114952599099521349978659897487696386098150460858079802286118473438", + "7782416608641073027346249329035238156135229495612851329120383896709704366468", + "16130683318242952351232798430926745437752117268773956614392208213291167957207", + "7138479108474424925341045076818627827804387727962013074822039041015297420108", + "32399388071671691182320093095184379549183323796227194977567365641460518006613", + "12621914215480896512517547663453096966512934786647273410862577533845371026259", + "51373200076767248739440216790102987446384414528795951939018168608077246019419", + "4711169473142499536978868853292467407847241217783402621574141126943041819430", + "20916585638213674602293662548044242117498481993087101859479278002709791318260", + "37075077739162198479789085501743807449882997747622016435706176765596550210020", + "33165768678659862130519082903461215912917419018176882281786537855179764440040", + "22239616586889242864268563791651371553935760823554369158673685695119198872827", + "8569731460635050209220208359992017590732713959074882859927852462628618291500", + "12092520094794312518223386827734761560684214042395904473429407201376566622377", + "24738412725289425974801793264223539062637529704113899092136506769707516262904", + "25432113392278530544551775907514826208797148854755635873255353588215528125938", + "1926736678550551819824749907540350447652543492087233394118420659240698256478", + "43026187200763140882600435283171857884297199542905516113485668142291006084967", + "5015514426935505748517019380698989244722462701841178979298123640147254233885", + "51119410672983265943971779418293774273144527694049599371957174538935513506142", + "38537323848964568700627415360145572095347815396947284033561138347785758891460", + "24930297626156479599218835584979276393118145079148037900729490095297097571358", + "19522213724390048292898904226913222707789362700146575889335353281742515064245", + "16778834842828383900239316692868676840669056640838167902498742249473937780910", + "12862561806980827890549828197360567876296777932744629275313552436221430836308", + "11165150051769232179902627647829312029811010242102119207476280617340195714400", + "18470584350449742736522584192892404006943213814031928154913610451704227673997", + "30221174221364922097359587369023136832738101236945136440584050297665741355327", + "20017396266500602514836361112136165285126663781729308325204365466938031910895", + "17445314184429459035824802825025646384703789166068808984340913627847854304796", + "50483944037375839807193551925037217416660796505173481854372423133696357200196", + "533133567371898783409741252235598308322911917327937044962475425454356766062", + "23860128686699795743558943727050964579511964115524077338055039280862558393328", + "13961306922385642675381777575738166174022886640361316764302554234366224548117", + "12358867566157698146900304130273564222580660555210277970310631255015590094291", + "51330883736455802450428622415896594594173252955099357099131379478316580717736", + "12740053620434000446695361440687679530189958020739387085375327031353817400807", + "45682162886175704643460861184805529206610941405019536910163247279765351164536", + "26752456247835343292380238291484358341458130122058302176218424448436253285628", + "35598636944835691835797458068785811082422386201301019741043856979239987453037", + "12625083838006312300032854043965818589082954417698684019479776912167719340521", + "31004727670064615494431444973983044743520847741148581625760673954766406597103", + "15775793225640769152818854619322127336830054496055998129778527780871976097595", + "41485367897109272705950415293200263251937166003827119828114127861500524970561", + "52197264324954942956131843607688156203641234001460353833988364488616355267986", + "21606625398404308456967868538729676656278289947715874850769792166619275431691", + "897316823535960264428973962122920574100152379394404271513262088171366524145", + "47011338442381273388738847316676835117511300436965122821841235926489587348540", + "28759129782449696672960295122705430351076899593896771037742701860863448621653", + "7649723612152825620167200100201178410997159929797621896236886558245716139934", + "7673583080257704217377429143735728248289771106002182759101425389361981081437", + "1506134239089954193284170854764596456714168074258655852733368138179010720342", + "46851599557836143036514421363603166467444778784403452730946690930462680333873", + "4560606986387916225544968619101255713640426662527334826362267245800699275831", + "18319503856526392074609177890282545538125539672889278310902143894647482102464", + "18246361877537016289522732389232017219806327982370260006160600979383230786857", + "38699608706708461402324831898547590502517680254835025164598760728387691040454", + "9398392607727620815304482803223297943138533616844414029705557978603020215820", + "36499855703124130978954843375285150600068220060102095397374966114746758993363", + "13979985526780798383427559673040385002792216222279307299987410962521269869318", + "47530154363078812739224758764580576078531147582600501127696258637489600902684", + "37578915610247492708702918884467691498026478386377009323438096589043272655526", + "557726654767741883727773955061915708882842835224417804628827738018023283136", + "7097792498610951190328250772333872946803820241430948129731593953799272141450", + "36002306878811242479916445729509046040137221087751424483781478579034775347896", + "4611270584582337878728824226625302017745670303521351658182684743822782311806", + "48536783846700705969044386284944724393027493466396269740224639439805442174066", + "50060674130595886426588967838186200592941247704006984470713352043129639029389", + "35602426220104598030625180800499570408605810403695995234258769232959374266113", + "21798881913933761202303885475954053624625462635873282890611490139373706064727", + "20747926182183043065182056626925866469958662543294959716942868249036925369184", + "9395645326729058055830751930593355150009940492071324621275103760518592112382", + "27148470444648218381819000740521911651147694302777419751588429832053407677888", + "20066123347332420102096417717501979182075846936034417483414191415546460044411", + "14700962628707384834162298519702008795854285633156089980425258012020345286575", + "22352027540626928072572661593873058418497952514630041396266019464165412107604", + "39014054053532584026100333341581967368342914534879019883569557554221880335122", + "50256566882131562729674147701433950611065994836343943641614633398824120841336", + "33865289605871458026416814226210414624580373389988179004040219786950136206940", + "16858784870916440808764416451307156851688406043217032274723276003034869328162", + "24953520861307942053864761075962184327175328938622587606522215260028356442998", + "25583617801014756764592614336840363099145001898050265707075191140856497891000", + "35444697122149102456994608566335900461772072925703166983565868755661834828904", + "48062077100228011001509794801336830898921776680444038141323774271432950423943", + "33561581847552266606163481158685273637152829157511070945394706762133198101191", + "22272535578858012413075225432172096128543629445425765787154002515895190846004", + "45073877981110760474519989224806744926881700096140305629844861313305042980469", + "30526572682621705120741803116646458064904802200443399066627812775871109412074", + "24993513871176442307518250808541830504795673338654240509259910776391407739495", + "45428100803808128414099715531730223288375212359851876244034108170677556127353", + "26871324155876919497216874769226397579473378951180226627590213074962274560258", + "46228660526089869660816406046235958891538183169177889697643119510487062266032", + "40532391098003189145054348122277931208582030216863078326457246503576912317638", + "14015455457912713459705840701413231906372015845977781353053639693734868858844", + "33182572175176093240437385720217851893425663149506391623381986729556088968965", + "51814601384523056900961045512657359030837299081467322789739682219095528040371", + "25502966126300991711873567120724450244265452967354825063206920773900499157886", + "15739198907351003052113492143911290735869482851562498879113585799876829929917", + "18976125160345780669078298095860848879365087799311866352623554732008334688420", + "11740606845749207402262005848257860797897983481355207134306531742658015230588", + "38968463814225179486108179099852313595830289070529236552302176395964405352202", + "20528957882920380216031430182758767826065417515501127868169814699342914038505", + "47590849513742075499716459497565193347097606691954600671971705450434562962407", + "4717487649187609370996850696124997862080245901282328052120226795542961232851", + "41528121749320948164844207497894957535294042141152744991951009476939945613103", + "48711702168219415680036059395120492220445267536688444511463583825338113595032", + "7252674426181757457702378532518587404305036440394639423562122798181266094901", + "8228877831832621079604151493650489239679018952573855101601859521955699090946", + "9431948612373862379486159662759007584959234645575469435893282139163770839405", + "41469415965376412086610122925474236445607403630808057526628597876088337141958", + "47676995055012764946657851615052235711550550810139161322941671701801254649215", + "10434105768911021616517519337292136786903383282952139721258824574146140241622", + "10098537836468783984494602318845008941831077465499579080273332630647096616612", + "41029347571268346169171858593252183820741715623496662560923942042444548561316", + "36621801804864769891844294591226548875199749035135786238141663372415889773952", + "18299793491712377015405049308221469155071887520269377831370540134675314344320", + "35368269547741864770375177147421330516777038971428376604125734402684505250181", + "4771591746407566385984713734191188067217115088218098948400850804023882394230", + "6020107861586597996053751633804087949631575894870288310826646478507788629698", + "21888493867698446276178932629937582691497675686599995290084811943725439642034", + "7880142872745882776350113958557943121680952921506484233913362005002348698489", + "19562462951397949524235095172596677199211131568509570546587265626452556500393", + "40460185120309566588627856178481560112381116643971509476770218255646393687512", + "45995442729743347936375604955332251980382246766773242715334853526064219448955", + "23634677191370233659060400271551988838798169268241992612394372314954905355241", + "14811440896986830669631568037341572681475630900587480160511772171927718944017", + "10459863017867673945153581928286102525154120908953135258491304585760648004328", + "3710716411978088520542313211506787957560194656949837620638374888747015288032", + "23376298834627813812971745124447730510432816048678291807961586925026725873993", + "45781629450327616311925200568203660934946607906302688617575710496640858264848", + "49673453677924708857074589982841451185758519891191095272256456874917172241679", + "4637035657743022459445419481561161032244338845944349404561261455875900593646", + "8931729717197548516604156180162723118540264752449847057882165925433420785740", + "42061885304346289605645751239682448289699388594473040859697896870938927834", + "9295688434113674855832209619464814782540666292401208359064807056872603288834", + "36802880880247101341570292515788734131865101815514200937419571950356880259076", + "9473028781668566115159126853018837133660762402536638483291512857154920211500", + "22377402991855031618065712511964090447773665542484212890774817759081761809107", + "39771113307688276585731528138607457134472066859316865234943940744710002212728", + "1457018074055924153084126197340344135323511772948054605507297652704038419661", + "45555451760491473467016497239600417332269419348763702453193822380306163147509", + "39741648455977619206431909187521942288566743172576675081733996212154473083277", + "12543922084892015411547375157167186926074027458998005866471804311555561649978", + "20297939857539303338120295166213124111568765521382797270265136183258718503724", + "22102353419186411890825396188350077329715785920064798829028863693411280951557", + "30487243710502956186919100656350530901204326151931394243681318679708796521113", + "50760448758708451101222876896215722856935213848637527802768621470386251239496", + "22624363481187116095564086744249109628862129979393003196819849318927157765978", + "8349028591773597380701273575765314534054364766753531625067456777858413789380", + "26747253867793730939073267129261476112508005724112298232410644668847206087752", + "21322098605570230843876944263703745256645862055057808582801005337946674191178", + "30031678568844860342325756409306833088739520865259182803931659143497791668033", + "41885268385230341258688864414228086346269137564539236698548258083204161918299", + "31925910024484481216760441454519949384665305201574588015168206478845311459625", + "12052498043146629563202099255344649663552039354795610968042697155030880092068", + "1807851395731414745520713155897515445729559210622017790966282055728543627700", + "40934565808087449598474053518126675446429396242634261835058877567157623476951", + "8007066619871599411528344196079152567335219154655394676747589510750536365082", + "7848162833207681921715211261629992829335452145371601976289615257548377742001", + "16676346894907458661673861247637887467002608217188068226180070225696837392304", + "9166083929743497633442776692827871506833325781041024120803732206629962629942", + "8370638974531408949554283798398052080165328684022032181696303962879083436530", + "13578733422834943811683277818774149663680788396454802899277427011597843549213", + "27284858183499733556231728031861418325375535220120966501557208845618233475589", + "5657183324093577599752799858847595865713323832360169365578634118358770168970", + "36709065963969807327270866519783427877936118655672367815044525676619221023471", + "45117362522077674319119357589026499677691631626338395923812732482740192508919", + "29726843971111514810255884991860955074366257806796390752209226951036384124648", + "4942991139542771151463308347523934190175914784363179955683368722244342029855", + "41827772002638109081973359512026241192071518676402797771251723244135714969252", + "40335043235787290519393377739847650263660536707427049730474922055863494473921", + "9208196930748448318170624933668901447936490470280385714239286039524866425324", + "29410733039310645365306848697993125025714530651391708842492972174898109085667", + "9657937744527233821832087368546633391481712186484019837723557101566116397266", + "25369203678088636646799344354303019366108331081761330774812732705402180848009", + "21713801853989477517359447457600241524344678893516085998705194228897359741379", + "13495310317054186632767802563202760911889797510304097702232931023796294559520", + "15556194631966443902991876888613034740811412429563052990040896342392789881654", + "15360223194040840664477127376214101525227940292267885732329153366060543113901", + "35250509401044202343218273142704030989176349061148128377584186589917522376804", + "27680788323889958371755554827082244687176022123633428499926804257042315083851", + "27922795314937653456233994012430955839107892840808755516258125423872192521206", + "5450839009700041421553618428031470586174915862008323236937739202210386559986", + "33955736267270823152063133839338754000684875593354320054538892047699670825872", + "40514921886446480831159322225408793255054256039921773455951803081882016978492", + "27382631637850731413069145375895291769367872493057000498743278928765258693884", + "39701573443811297472882417345186410969955558755323119807603470028774819390708", + "15889966029584644126231043439233514850802985543819136196850136425350934112475", + "42783192461064914492676784746652862499278267820619169109781269683941253799324", + "16668429688574912345222013251345680767989456538161625110334537783694956194864", + "45249772018452462619853389537513423375577200949046613525273373367758010884628", + "6916251385246201669924565025910971505243369791028872213180634281800637771464", + "41065691087940406779156741002715535394650725636180290543737083319186334453702", + "6095795290984591162259827030092868824662899199545551235545303946063048077753", + "13240646233919518257075907180652598345663713356544046451391390349405996981717", + "26734990621369278235260628115635117840925974254473083696473961644398257590325", + "12775073866689047061158472100595105198701831341748129374738601284009407544558", + "29985413135055806924461073262866633201972673750092741781469744899671341795068", + "44659056447115692262217833598160063603972906293727334599287732812295808840770", + "10338588710032789741122087245556605726013714223091742198207346497374098424610", + "47561925286615320725965871174559017798172725502968942209648636318102630401408", + "26984792893098216457501073694009784708752948955318340668130168373055662459978", + "24038665407714311265639727621947467800579708560539430237738942188872559023162", + "24051464590691095770275976692618535067297191277595894116611073351723366508792", + "20093907518315766387113910295573406745192545360169029511386251198998890011063", + "7779983314954489885189495007551484280427639511320877398167270236989028283223", + "5991507554080136750288802323056558645973328579327343843636740959656863403594", + "7868321813409128594300587198233114664344072712178164971764597605910760317427", + "24384202076070477998106841045233255646508136327647119103360381019822340713917", + "27478097590293552656595646891042692431006745894213366364549849204400996554182", + "31713989022607812520663435069022132383826910712940249832324775227368847594416", + "29262966183851039280755786904751036705166470941398005442139638479113663947521", + "20324328538837248123147344126222587332190923602758652148030156605775587930510", + "51413273656143047586665505660971222299614708243414460649338609309834061114626", + "12967759054236874198187461477004074678661302806622814489109310101081350055385", + "25526880894791524706605432403156985928903649732697667624119721141724297493634", + "8615410304717664225790402930493837408469320200954170447382017993448967428604", + "19847395082602033172213832347788973870944134256243199457693506913122527403160", + "52108500451169134970446634443156780957394305976815263328843511705846449187633", + "9698229582774307623468744338036225686099093623439445003635006477966868101204", + "19624661272230187192441437388995025908044517413488045839444600978983940627768", + "18992884086352705840393554670376090070747537256701263520032115277798712420106", + "33735698361294347387719701536521027239918829976831510465434615414070681431585", + "38396839432472795759108664437935891726365198817504559835307154145482888797103", + "28239257126456716873208604012612481654251579747097237711013406473196878415430", + "29781714779774311072124177927751981391519183312895687902735657014989082736", + "35315008642251958795352080090276565121775280208114595478703640916027362349508", + "29858255048778808186627413506991797976078812747123452781501650391961274151042", + "39544438116861600561135454959250822448775430056681489776743845894827184971349", + "48820138137152835127662641140479742135757486530438042746744748566402296772429", + "18383561305614151671548867209079573054308612097659164389790107270930976067418", + "6559435169411204472549674436290749151008432489119481263114929962631193375148", + "40976165106978486118982276772874200152309011706825719935662081579894935629112", + "23513791997234753066829690822937830515348327924216558851131542892688720559007", + "45779644104149061605855968851427458054030240339251880407893476549765809510796", + "38718770719440596377529302535075161561438010488027626499165501751116522681406", + "31490518346187818013039932793776714697839433787496176978276674361002356762225", + "43554438628150511704086890941429534399985061392036271474639633607772313359503", + "4846664731178844403761403978726766058601112677468909899447206927624011645839", + "50112399997597575705143850041913203147079516556069413233404431125564544895458", + "26965189626033996846520534648081875252391447104789646767913132322641261344662", + "13218043846091145574834100926310057489665921931348222290552262682894266467672", + "18268296412406331541017001878871486012754089527318405965751542598701567116746", + "30529398501703216150269880003459556406015908838640125752278023375856766779207", + "6750561167323823710562340761637209306813063609776463030559000169218249105163", + "8206235873550095286403097451290005576843322060150743333224994820026828256178", + "36435170252840416417477597995258898682776628347299485818198308098320730016584", + "35674212368285559710889163892250357969566652567201295976024167140857307294064", + "3450928321096379888294163680079649735370613779046122142117686117669658863265", + "47445922658391508597171115220196291470397232905055768974312188546148952703018", + "43875584792962951613249014500353429532521550826275048093953786821138320607237", + "12933491865718752852833620915275591932651198815139487113571596330112667171279", + "10258659441860227692682975603241565369663343591079572991309130199998357177367", + "40433563751392788544985385962590467827842662948325846521146166494388186073488", + "51792969517663426627307553730511106241511544549322453041833512181749741495496", + "26963921997991736062329930338080636398722039144551674200774505993207132292533", + "44938075775473964052946021444506797621595691088620067362194288635357895732430", + "50498537347707756464120897431167332705429399852150347316349830041671343262901", + "817500575051435508925705409286145819157711955947116385306749335036639932412", + "11660763473577438721162727966834688494727068439615249894110258311072302434200", + "29106027612257054689407792164851423589237019258684162796929926042097387896533", + "26803468898464297015730270096705608125980090610249594205782743226666772511013", + "39000583619997986205554999732457130935455085170824939099684172310191794566480", + "48960419153350885540296033788774874803130707365511295750794688068266785515873", + "14405272179585841941059137834823600571132552845083904260866134872732817400479", + "3247258893249361623356179707710043407912682696330824380012591926814700678022", + "41005822234143792223762039125101973541057678578548139112661399849872433105378", + "40886612272816085414786457296815385455498029330816883838983427053508659335356", + "5698213734200962556214281372138050008180382536270952314852539813287756619132", + "51731064304947938269996589044456495707088198064825700956919355878652234435269", + "28938360248529327550438870467931804120239304871984842076767409529847998788788", + "11721817599076331681485435747176949544709322127921828686780164816614049471343", + "10784891264972165132244055825081277861146726629781093090146344558382604399297", + "50033180304327238639470953666920333048645313336672572426165740397263700280505", + "9080652362263372407998395540428181974399864056342662656495868376980934423064", + "39439274555023217702567746663902750651964604530536724676265093219153544483682", + "46235943261917407784842123558693827266469034053515478507371292909064822067480", + "26683017781001939960960945058038678835925890407207160381303418479195516422229", + "22059331941314969973981199749534845033315446637675197540293071925509806112848", + "5965369340611470660325923282907789807985296061986003026279147867128768126632", + "51747909440657805720345411623670256949182584202684953545217152782477462607847", + "22919148685983530840618465967912004168342814581287388376571877885600343066045", + "38317763979817858406003619674848389581292404358617175335238454795189873299858", + "33928906322030132207587394592416558439086661391184608237090651553460447844664", + "3106714649247639126481153946696755324095295057859375532500365305450227280044", + "41114277786042774911390909587922932212006303013354157710441199420725677716516", + "50956379015940932931012908333537689394542004038449730212280252315562519568149", + "20725594465122308146494251940019215901865807163499658947242376918233649958157", + "14677119134707288082388889854800047289384850971469333963975639502347490912043", + "49525888079664435118284496041858042057392661382332814646158244305864746124303", + "8066203475504417168373512692012508880759544656621015747636800752506564606187", + "19214399603564607910293301364995503276727719883972420414160182181917288205205", + "23232003252745880179910141133691610758065123721380569335128563208582845701268", + "32694463707076432204612727301658269863278351312709132323532727743048512886553", + "9692406755222911490906563330841648987891837880003555233568610826138811513096", + "30785169670023021795414099546609738575234772507517481702497087504986251256293", + "30495285424912304614600676571293913083314602270939090603441412430090909426965", + "40027840139962499446451502896264506178836256381871773519721731434603555203795", + "51870685472226367346309738025925016076786306043870808477217847242010981662439", + "35281721672920391749786101106188490007056483580423747835799047162836016716990", + "1195609659179264933679423271280047247323788889750323560090604677471520461430", + "49688707892973465310838648854823556467905600998909703975764873913428155292862", + "1431989502380376652908430897558018052794651642374481007114824008265295121855", + "42748630675567206573983982925126842118508115845680231036468046254876523545037", + "46063520111111227208101978420462789342219211684777912035229982256745622784019", + "23603532236766558263712007197572398821764294132501155028898070849630803247788", + "159146234156883444983023215600248529307860125347478174563320657992587191239", + "37531069913427333953175953145552820607197966363749077284688941019613320006071", + "36644656056117014517645268517826975919313063239199877121546043795704415716504", + "3558440683863513616598056508903985601649593903056016580245079926260902597586", + "43249760150422321846139928094106866848666428437273208732581096933994810902428", + "15607305412865691833211858861636123058695920368628785736739608805314356200246", + "51993094986164825512600366906991589661976559518618005440541837248837822185506", + "25925354551398871951796491632150418544692800200225078746124326063528976878957", + "7318259507252728426268244372108047829007982107604706798183592051142852929119", + "33841743492196831124143979640814899696885047255360615373696627846357120396136", + "17033395605827572434463787393748737838374974750236063219298913486988386142921", + "15986508815433002841925369738306520450626239311898188554016233427523973342915", + "46421973855966527437131796027770063951538802528152521049342778956568145562413", + "27867265905027614206590500661387338730423383218345599855951860364725884055005", + "40695311577797569846882083441925553768329252811841863801300793416947189149504", + "12114065592321750091712640024735959055558876045061853775078759015418529890678", + "45275641697290077442193406517055081609292885470978164229878635815131090807917", + "23431749385124376582276307193690156394928227354126470237749424245600688188203", + "42999220271410168562489666098715117432297572658478463903288683754006488385795", + "52217993507383563479579697007396950080519160377471569772932519499002524890246", + "5169100530992316441535443184229005225700311595874887142675757145583841347726", + "39638257720743201852555451262288337881288829305422156332574219713672302353366", + "45052924612026449353782012863868742047778120892288767413976738737520135464414", + "8154629871856418042342285493686796202955598392389911993008016248788275838619", + "19121035535162117104361615141149226447106725886646105576100554367419342935252", + "26114796048053302344186964364065392697541936955818477282476350999407843308414", + "4682097759709896860884296813343977811067606340444750309244152442811910825891", + "31917084286637195677490509868060719017034307408712365208737181906041513079632", + "23135908703409349419851753826779951475234110961540948861434868004919353668323", + "8289176405401070390096030795385933741170692432741577696216978544784078135497", + "3943533298550918940813397642124784873944431314601577216654972444627979251374", + "50332345435143894637661086168953373058681899057158910541320305054076903385490", + "38771505311922563443855379565626732597921176327982513624117328160001021412175", + "29074034873401213780266246894527328667979747775901134246668488972421541219679", + "45882556002632999437284816390135119911260669988797907507250714727599243770139", + "21305187795089127898261903743536687815128270363749639048480775143678160637796", + "29400099649801875911195088608824899026338539128523029069028772590716979899753", + "21175869230048522155111083721121429523312547656858594468425833955668595648464", + "51078657802912399053656982004360025894473819274219564944312033541536665339388", + "37884321392482679648461115542113260844731508866167639995471276309256243833202", + "46478859347408120182949905244422849244790995565004052750713767350872899853530", + "44070774544055493782764934460383451387210172945785175250258261750369583544908", + "48233041424061218558680543548902412110912249284317141636107810946827147057350", + "12333524153110564653373896670101652040790767389834412096208473261689247173858", + "47815742009138084173785589084205182966854166393898085759449888551822525001836", + "18976077332556606328396098846639244533808171029985748254847207464323323891940", + "8342062238065696104147909128633251242024565671053629775509579759157620349398", + "13930837308663862929725474311188734172413912189411452424606716059084594656935", + "36126099464420179365130795750459486522670593533340030253699878227897165347900", + "14861959307861465989832627230558441981961360229800610791065346026584422053001", + "51740384495994265069820094383124876141998643179476109833965893919804641147868", + "20723175697793683526758479403911794680281567652612124614464115484862915426969", + "52380927739393927042191987554963683225937142561654016799900354080549687561114", + "48867149188190184608962307676781083143555789244170193283266491901976205690637", + "11405572561077233393464957617282106194691745748599205814688972990600986908248", + "14523482793780497764486700810931551606323259157673123805207962714757698049724", + "49124639917263375454345554393406075698555428748907654976750964834909798044842", + "3152585799624447022430167175654891411472562411637837641665580585570142816025", + "9246745827799915125767684894608100202660907413758513282997900298369725099462", + "31724521487995424656728794923381844498231691128258772629818234360326100221028", + "36367328452218310056301050170628335556945482755616330366222542108657663360013", + "29704639236035125547421615025387188327639890582481589019649635304258295034952", + "52171806027473706998753490162061332301674848966114368047589594802543624972123", + "41093689955973699399767749692401360879374813269651377685140746904760675260831", + "35381229449300507329378555233920733593696135634476796451393279124386080513508", + "9190764180963753157474359768576441829145609842506415293510564712458525467708", + "50712718671122859300648226105502251019901121496111764507522087199967711153363", + "35676152631451240229031008202018314409435965877876611315999799406047983216233", + "23561126509559871384518896737158296027516862427884668066767816476626057995134", + "20347488420866620232764035160105552702172573556465061933631148617865354823415", + "42918169876324885062781583543989064678047777760227706825308511750489994343958", + "40021003404657021176885562092445377736026187324921270489925952625166735805805", + "51773276086263632089545673208497886531937915094822243017545116331123932246609", + "24211978399662049006753874321423794368769553051676333342249123320202467464228", + "25624161081073124125917855011122095866125620715457106844093018147340086749169", + "40961017316163616067603111794242720075706459795096650923001934869220628091747", + "34079491977127683150459628641828381479144646119464673227208604758265769860970", + "10143431391532350495520137873797971723176747772715396845677800512366079815714", + "29926926760042227471126045537580952593953364372735544291182114999390416743309", + "8347479619147970619596222667884088174746544898385749606390416880694345016017", + "45812971097506654682039733003332064361561218332199858126872648961637344907431", + "21778611716615985276538565672701091037995254997612198499989528873172469412854", + "41797028198292058439807174946697468976847746371421453995590564918471246357395", + "32956278941641920915449970796776991687265223958625302034811716184777379479357", + "44082595684610701779319087060077938440797195103280387777656993220308100309722", + "27012256908066449412726118560072686450000464644842730414217640287204759907128", + "5508075311555477583030684171198357302963365743078433343163012963985687961220", + "12309833290429186391821669105819976158300701473852651675967578262403097818514", + "49748807668258774076960302266970167893568245583022319741384522071467176761666", + "30094056928325576640448394298152818248352384226270855148890219371671815581908", + "45661423059189531324997317298269915376556974344857131203279239929720496234278", + "40646234961259748995495530894139219594787001806368008150867406492466640352531", + "39491285358902894073867688737255066549280707646222392247035140940420156854788", + "5292198855958983596631926857485053214653751708999171396414919391944680948511", + "42728103209775016810478371927041250479419229479783104059538047467114254665550", + "38839880835695560290090724510138807580887573453047240080957699344936132701651", + "35974366789112249869314438315020271070248391060692412688605164656208293122429", + "50921079691712294558350315142913353209643927384708892879761630343032785156924", + "48898135068094386833657659840682793851022493524891629181347170447666470799514", + "18611726646143277076395115442191464896507349393354070130713296243605241036096", + "48681533122026557969113589255329245376005508101445243279591772668357043043908", + "37691798746875895465917757533303885469033367558373984102297807226793542679540", + "4463944917437126358355598473718507764299405661730401023850657451070567263158", + "34874458233882838733875116296364332071062567679314440387655106558836226187337", + "24860070594936593568180960826726689229048831303281804757766882694928141477256", + "25557867280135023335964931323567702913752035679469732824554931350439543621641", + "2218224452792534411444403053259674790389797279020971933539150463659009087585", + "37481132832399138179762804485147085914460800444058546741762709389473472530876", + "1743141427465380836996219297255876901435693116833296537646867366611647332319", + "47560685408081470643728623543951977115765490153377117220156574865709040876983", + "21790333887028852163362949189767432007344199054217180055912243773121317975892", + "39069010934657886237618358456449966253139126372709051276712018286684188162960", + "49109278351022864762306047623455382309465786026148219688531825325635347436136", + "6114166505031913922038573076129445444552139942751377601601212851977606747917", + "14935559989767484555651484783452737239311595413235484641103038837868364121864", + "47909362002217640625853864373628135624188189879138187073628265168600998650660", + "23609646783179023828625632863617598886500179824880288017469187406649832781110", + "12291248442941733374185558098717530571261688390884382467166132299715281612077", + "30273240775913762390991918024269380328763410123901788753683289354092038698015", + "14501843168396762967015623744819899468129974462699716716832982573031124046528", + "19215008596346640937514669752870243018714780950412836013419706492641699665437", + "11604291415408080056847957083203845353497687784575587152208768028956409071235", + "46365153253026296019866270982443024693238919346848054126163650555261138594377", + "8392493857755270423588429116382834746676534864287806442879986303108233062068", + "36563896773454372834223774116845706827832334332314086626305917850621506961035", + "27107319695281072003340210765489963475967707113907578904272019211466252496107", + "48485389328577065352222950349969514200956880827338164187274838304681738727695", + "11454132070237167378968078285934971138609326534712826881499834976102398100187", + "35239981306794245820197065180137009683104395790502718203329391541334096717903", + "12027822609235713271189357302526844489889022546510788340068938279745597353624", + "38069559893498226007099889201162509971513312714200364272320837438345012405081", + "11147214771111562870927172818972341598258139747673529634537230055152407078774", + "7174801556706451631845043808968476988608097702213255899769811312604052103941", + "10060377484606765296115763248257558373604639003887103898503284912973716233202", + "21110676829461593448942314485171388741038824988677359453640840825837561154222", + "7585444028250796613448511226837883540009782686468825816602540674860873818245", + "22362721752390742351788847418165576799899766771433776512338111689905772390292", + "24423844760656779911839841617586299147435727308816808491883424274116557058740", + "16127565926485596838742458139410066003951995014210643187877704175727132963817", + "49031212598288279808638713707580295943538503456654100455665408361887291838870", + "15141413300987295099362188832660755986889330025962796376445735394988765355710", + "274136558879841640667300433486886962303453581043513332121388468907888438063", + "29007101881237769288547387453379870285158878747606621342731865100581547633897", + "16713979148924315440177593510967536201795556887911333421249019386387506848102", + "9526836803571106553435449064046802547504681674669163247193338125648827295037", + "40196037730422505631634639311806918105017728985832575652567118803295808738205", + "21914414851546431820046880924951588716600987198934981578580121098829350401058", + "44494821926369940830542821401522256442929163415172457365176991879216847802348", + "37350613020156877784404835195057494342355297052761274942293954481738928734318", + "37041758360365850813664512000737884038484504407602420043581149474623713614489", + "13530644407819208899357633676884847664645154455750584040412060362990401466897", + "44194371282090226518083325275283634193231936594148713965279809100669354621957", + "19950213474010706107459870745087118398785920333235882908684368504594614764858", + "26763834485610957008103948533729564603224277224135325985181929316017874876706", + "26590771314210318880528657800654726465257404834802644636991718012924254811564", + "22502643447350376589920918142800413572836036151031860162975634571121329562836", + "28458472787695898883912047047829769905076457554697612218692136188438729137396", + "21290538119443845902297525113953844433927350315632194689980608207668532226955", + "7614773499167039136312387398168535865451558173037669388538727063567054182632", + "32071537375201686083732538801358780172871957086815839164501665197584283704195", + "31527511427373595217929050763828998225341563349555493371048374854756004962408", + "11445095304940085647823369957392065018120270446630882451462109693890173349002", + "46427609245996519586393319191322685195778148257851859131038460462155953958384", + "45251398849047484384488053650332843244118739078038447653582141612852342200115", + "28062556164215227459729984856983576449357546344351606772802520237606082317278", + "16704859381309279990341722794626607429674220463465440919165829811789321454689", + "44422885627041455774139877439846695226181964046578776061297267123766022638553", + "31707669368868050705854286778654629702424199840626860190054322142343235438099", + "44719369489314966385327718405519845905243431182207795946594720355888708910587", + "17968778368313258555787125506345599263069833356598144239920739754718561065431", + "1391650808277841003942493162750433271810312519174701185907286608222082425741", + "50789172236975172248997616074850311435536446599557932185816090015408561172725", + "13248651950523460405436391833766106239695188560075009777498116043247948280622", + "22976143915093447413090130052535539758780763243482196980836192843130586754081", + "9138821184581858941054096287056362645367705544248312484784107416453199624443", + "42438497480735589504683740501166265802037041616560860992547405808199105661463", + "33925573125642932031628823196193524327223402972399381263917096608562395171995", + "44304039282240924877917080480343076653245855876941777777838515440982555665678", + "26330028428110098438483604190523435819237615883060462523787125613068369591602", + "3939433613011450449533220223023568288971947921507005835661765059408104212852", + "409465334409432341287833436778782543815434472181320607149157795869456067793", + "9022169527597799496062095124536238021524552332359759044761581464903536492522", + "33898683464876188605096459360675028948101374965510020178906660404993288138521", + "5883631454540383569869837143003565085534997882981153207400557987010582025510", + "11681551591180968044679334426814823301134650626910890903243137789079195435716", + "27418420945049138645770769650227533146757569914358559320368498000334490795411", + "9729619795359800631584926226727311521191677368677071794472417719450051417872", + "24439889588818255603411498658699058780194529286449854841452786357857657554523", + "42288441523920025558234368170531276682844315487654818793645172148127230991750", + "21892815147094130811330755355749646051138561056031024308945183239290454950003", + "33108599517208070878419917316458173183163094024165188317641991629962038749522", + "5300155038754606533289175061929837178182664847550864057915394421909776939052", + "42564480328809780623865581179469568643183139132232210092342548627917692815418", + "71724269288297288595163479769121854257463402097858064157686790035248749059", + "52293282278015396489611420678227363589775060462831270825115401529174333306421", + "38595997103546996195112609059826029890225159035516104231287385552904042108157", + "2363743434857835199396431677499935629182433544497393957695015861433989883451", + "11585317797552850373540657705121748667061563662542595277928209275939122890383", + "36607102921280505251147241864606624758598733537631021932462657170648594362271", + "39970869950059915479958229107854843560414304921225532263043773694273490653788", + "15911979113051972715384485897995919205467298424237974219427734316319247602395", + "36924760565765852882977367069343210882760511577781241464420078864863987905451", + "31095174669851525231892016231773786152253775060820588533382421963404721684923", + "43104797525216096235351236031351863909132287343619805284596732685783640174861", + "24114284062717590272367579607874012185750016589298443638692792697086025988789", + "21380896208921059077552774249720539563369260084263039281133895692424578928144", + "28798818959495778630066965923723832728500003805792758781334172290382458015835", + "16509435888175746091581474752755786344439462634662533465752701721383849287348", + "46249026781973777263382135771766096810728577211184066886016835990481312858568", + "33756263102339480457103729737543528802145130344402235877770329766396519935494", + "31443287114866658502968693736447295348172639352045892611758444042747913649016", + "38108603866214708080509265267849610034472455504038281291345400417271037956630", + "20069465933674293239172519243110100564185277592117884592468771147980421696761", + "10771149112044952143429687899713785941398975444185599807999992611729972324067", + "49913864679391995654110289907916816827031592358289345665208701188774943152742", + "52220643473064951305855710482844248481790685639700854904129069594391346881057", + "9364600221207189366497127071174382141873221655525752936867433947844047626644", + "40588798813033144248934441303796413158243393014654641956789828051849732363757", + "23038633563626470040727362612733335940692893703809653420808227468346798724034", + "42165671332358309082382926031202487836298590866428729015041052234819115749760", + "14879805729127079865941422454470842944326280623834468855433964409170337843112", + "28944760938249309609865191244986971394213443068919508694978939097425003972163", + "15762353066127749943165821722908732694715855585948875894012813361424435906842", + "1248120192964111233126892871232449268407159204989085568005993940703605109467", + "46978344716416843977086416869533420552160439318247200831103871731397096667159", + "30889118248009240244354605720368898377039898662679216506951470090314393577697", + "42440565603298845971610945311147934628392653199727097143431357644132535545446", + "43697887815880827421699141075757182895970267692429082909280244605997225972625", + "12691090355801434590737282525344604327973123454804153967248984015879486684824", + "19750719661550256945841869789706655012185326883894873358883332440065762613408", + "2600794991062153289402553730029925261338222207432355969355155130294864898929", + "37641004430998075823882340305743420389163405950814361871477264301776732646729", + "8085714741099654138180312520717305491411833780968358774865804549748553735402", + "28347939648275083228987283111241492647038735023970362437131928555312098378261", + "27005831219255083866498205084223216144146432432221419453167336651612131883541", + "5977792183072430510994041086070961527347801026510736848658379924212244388451", + "17852178572890822970953380179997124050663797997661882648202839778704536472491", + "43679141030133593781058568459147032305178508640746050566098387129386341629754", + "49488979065710957919630838459828510319060621152364800364769299706443315610422", + "21813503510364779282971774283184333876611263362479292637628856484384182491185", + "44636889522067301368374356642512451371373029116782012751155605542506164033356", + "21009295349556885884425756849027548826509548894713047069819935809449453407480", + "26699707293937543692275881507508724462436207577489036371257876793644358788973", + "8936181598744289262475375370770680186115254422392293603234042881655987296338", + "10085112693149247129025961922932722920582440635254985367247185616679784570571", + "38352380362914574651182870257010969867097332845017391905302185485387010749287", + "18974928412335024560015376063093587167319845497634482747635349071452419461038", + "38116117593712176700159823571918382448130683078439589373907205881048802507924", + "9207432498581478170880051105041917051375723760827107559153839692897185391317", + "15030146458483013584727905490844656060712533341199555937414733966378361517514", + "22641390906073225072593935955327124994240042627804282249110781769469216686287", + "51647749054133185965567587016788842404731176981894206755520291294760322226333", + "49407805464715538439636938580886736240542941063797483580237255022066757445226", + "9963865578989339184512867561948103986533528547290890678088817014617682528221", + "10107581660221002721057404715385578967141971140503042331131993653773998467627", + "47284248819523796730034891864350214193624768370715257608648349250654235949010", + "52168937779595953008057768247712709300668390852088096859869353733130914517937", + "45663495502484861030620837682772730823304037557114220235113751024099502424861", + "10152462846513724034550328077196500303244606735745438819469365544248832542806", + "44270269195242386088334835596635712067470275009111736025861926590957584589353", + "18663394025505519854768442433547744109106835527569307878826173685004234796430", + "28750046865491269757080112985252343559098492544634796494163537234909553526235", + "52187472408953219614720407655222559043195367179599764070380407351622403961620", + "1055203909028841649335460587117744113509132000652869709069270038807775418988", + "28975948047441994766842833446726711246205459936686173689803499294874071173678", + "6350140504602115078537523980259371087250976214489143775961907541903898192228", + "32584014193675228642172846059977756151878642162070739390659401602120865911735", + "35212966258978027879934121245933133029918026449020158274852718033819799371355", + "8385228452097271378355695012501422765748761816589938579756608914484087056500", + "27896423080896914950017091451622044411016768133263973559895184377824974123788", + "49348866648446932539924880838722860038775736483230543450744205131908588140059", + "18053823667452248277330823279669366245707263717020158633192832498189826841473", + "13301839954809237726266351114931694304269710306102994980660518965244053202788", + "51873716320986048717172849428111916221801730092723387050618218841758419176087", + "12909016223002491877585042387044492680241332733659331425107982956275145216244", + "8885091688792387989418889073687094983467989849380236916758308976997958124955", + "44986702046355927562531353266697757342876856477877504144290786716723229796988", + "46835953186579595681928676099449878268641553431675284797378013483528208748292", + "19226226706273785839337025382155807043498752778570938915461109879257059255134", + "43753244332189965642679181914364188052285115063793015713960779453352673940636", + "41327742854764663087181807466537169594113281539209576571287224683670647531063", + "47908569153278889728695630253769595239671662844873310050950452404142509421056", + "10356985089548338018602338745377710215056392640383720678617151090944697538427", + "29309500488115788911815064094866021221112277312668957993616064216768870485605", + "27863188405687867449872142208813665829634720626322416342709835812301876219388", + "45710423665065041706531742146751101491466573847139661500526201720354080886665", + "8519034162573582958198269272032747172378981429221601036182164958707019207185", + "21807508082177981825926502621401253695694912440587500518109890486746709038749", + "35156447288902839335025492504860682594911605641238048790503777105619005255667", + "5526086606132477589354495316295273348393785772758269546588184050123923886953", + "10912719688792412414761275602826481416755710457214231406252794081246907821433", + "15957622257151011592169270435227711991231014338627202211455247109058658884658", + "19454937401544945941026619824571078010367238440006696865640243628514874444770", + "10919845692244438050739305416567448954053218343286103563819549705260882089924", + "24749932698026123378605148612868959468920378384869610064055062056400023522513", + "17191523242109694596941495328786921020266184429878114800684658492248272748239", + "9785543175169738249918864388532133897161134582906203205067299689288473056146", + "45844873887396860342287197567390021073711785747480075695678713327274013727236", + "32294915894944540129970440829915511854402192394035420909582635944479145069390", + "50367267359846894919678983620329239209922062247988368714645518582304638174868", + "27107971960130575277272155034362129198784875580872623530466764897825446365358", + "26379248015743570034419222662346887488892203934828565389778858757949306827776", + "17242932998238114740344536523493651455664926060423493630114501547550513972215", + "18795481170002032356844325983789778320863899027145058510165669595363944174896", + "10328753142512142326979769055647019027059112239579345293052059239370071833770", + "50057299540417142043185969879261459339931828368383634488726347030376995603304", + "30928083134743814710647243446736095469167650239680801679409037394133158923095", + "19660369532827020817358096914900460540301251557170014957101827782512748842169", + "9756737746264366763810278317585025474680119542745951440653649670431686888548", + "1604225615242610973134043026752149105994107642725906913139232307018853369627", + "14629108589430859485405788764529889066682032453095159743289312644363339017485", + "18036384602521789516208880911023159363678776942301739295989024841954184367536", + "43824822990084120674945816717002411315724805031540468822346096704222404872271", + "42247339105313985393331008788046796809519553411225833396263717523927431545329", + "12411326888682863471497381589116457803775256358742364462146054618542057223597", + "10251195719932424452963280472152811095982966838883961291307366891955097856647", + "6876721044466056320883383615011689587389766121205053331714441893790432189305", + "41148559833289457767975186073135519192205943921799349756765240108771738209964", + "38619802993754125018043481269673294020861530007994111981057459063040730748872", + "22598531649993815358282366522410610825648345808618226744110969284026732375718", + "3902001281564501665332252357777927114344064882785646258497164628518364398451", + "35188446872233805895108694433193808390335418661793514397149118773499693318475", + "44344250773302653666476302143880695091517256366379991412728681922769200147851", + "44936427330387080992552071267532986016562997320267948735354196211461127686446", + "37563162666453844628902032532005225581978717459834789315007862052523802791814", + "11537332147991648081192670591682731831773380801417187386799803440046519654241", + "8704295285065461025519209041703031741708731582381977984859882861966464591828", + "13095146348281837766238685363639839968544917875238861211166228696020527090427", + "19031664010911288319036993426457807768363719706636708600567427796802669995286", + "17391560751642079165365844685363741415958408036111907415652332070957322973683", + "37164162298766343092556518255674085332922115175309607665442722186577695995686", + "47524792977784830186791378164516074180825406023717873899796125875702158560006", + "39947858112466856973840566791354754072672306802529282569734859018474866291432", + "38723161012431202927570591067714590449500185046138030193775455301552631779282", + "10146626590921656872129641435371410224195536908899035032468079765030851177598", + "2367487524238903167009564050715422812845255414870858490385644180654157979332", + "1522691084986592444636692811476293371976251968746947642660244091271708047810", + "29751975762215780628740114723138020353078934071684246175194751599796111385781", + "28510709500986094610336596513284835516746620891625478777657060244440010084570", + "19585876268034885715375990705984250466855994907520354277738504097633349241051", + "11580915068742407537835146501116128329486601664629585618691803520676341311478", + "45986834352375568821783394092131411633679169030949944411460425712823481578683", + "45892009309303762496626374099129598690935880461447409999457073924630230676059", + "12851430748788265913205026357349418711636776133935313377959014139326565156603", + "51159958933284881171492406221388877634676249482876938150932769696155358949334", + "35712278822729564083825963311250149726684656967398637628325100914697347589150", + "33103010923151015824584839351315539614138978391767602760576147324810833809219", + "17561737625300158291835282816425344623811537138369366806331917559372505789686", + "764248685696788128079473535129122443000214339222334526201336703461594262923", + "41413081312061452238825688356895875064065383877793081002391105868609598732099", + "19524085552888101259259910026037726475378453930659070861070197656080782706458", + "48120466451839364534745158874914214044461014106605697961743944882935279667557", + "16481162343750487633079918418440046109950282748237924218832177934382495454354", + "11536316625364087731054509569945382365499497810284828238931023514709125747157", + "38489227566573894924235709345277188538582111311119844652630206485796315318445", + "50792046478131411397845899336305438729938545480842855426427478048473261807192", + "14702121773642993854090501622496414851157782776616429236257595037513240061570", + "52037905677690583778590599957180304139273841231725000370767109449337693093787", + "20432777978985958028255112635276370977663407440935638042043024130405058821153", + "46213870332584303142223648643975688978943191457750972792917173454223923322363", + "14305904302356639979945672042268989360074837300336404362389438431094799767741", + "13926652865977882824309366289895036332708485877274621147917907265770853809880", + "8131907010091773592492017269116551423646291320301967484770041261467405434323", + "35298761126525018044412231530325162752504192071883895349066374167282720387764", + "46315514638397357274941647291481585961104782642492990403002920860816198813851", + "50305628005256449758575662374244724627149991364932765775416797962134366147969", + "36297735559732973936602040721422269210489064764686930749309013563319571070615", + "1802273241058374943192808217779637073203589902986166781617269251344599612790", + "21292890350065778660984933369955843113182504110186256786294769248754918202260", + "6275485810047174278528685500782955736843475601379798845661857367803758273029", + "28102595515354452167907108899241354684914646652318861390822309166420314022964", + "34670376176310631690423430343870553975921679476990599243305397898998192364959", + "50215593741348556194011905148491299973507779216517189842227299588450793586880", + "51616522426277058289245418067410351581253009632425978111768032589653902250465", + "12087242225874115520724533745652264576305160458035539609350085693334703318418", + "19688197367388363892846050472804173451185761385773544797014261121409675987230", + "45317239954740140935869743201544955306262682970099507829265151105277190376570", + "46257420691815064842278996532781154190565772093142893109128474015271259725541", + "16269406153038024721014944119079352438972724176944845864145660403740753500201", + "42414687979844417939411020908599398544017824379384047701901821289555929217595", + "22799764253078485878377874359357615331641065479783965500402463438505158756218", + "34902365471216571592803841796726737727077858677962919163721750093033319183749", + "25131170502654350465573952878122712674989355032741838604242121582415144186785", + "32209185938408182820642902820934739878910403945653998776174416674409072050470", + "37299849674329269161752404530420552455578902565462921235024879885238190430681", + "15923146206133086315183424742684772334167017313013558150048952609520643852552", + "26221415914895565747683686963484408814619576960117376557935949136934525880051", + "39355950995628695689052816368207469318757166117110929365091396101838037589265", + "12993712753832555370522287929652436304335075587096105518021459596169332308490", + "21684440231010612356918797447739502778905105569808331103021061201209041951071", + "40449553295694172015495987115776837285480328940188491231399298771238607212095", + "44904305966774776200954668646462124168704711421816844557196347834619780177614", + "5686187573937379334197555052621557406499910073630429789291897361096329770291", + "48487250061759416581060422530046854251426746356467017524986524108355817127253", + "22896278285651984552749810229438279208366855929535612414093080539810446039769", + "51064884389742104667307426302568190887647395353239134353328983997552269043392", + "17339253076872575131200663118864459049454700559255675713496553528557147642593", + "2911715859670422712693450578160104473959533901286104747553560031881805560469", + "32230729533389499412835281357822125197998617737508824846370748061050912985520", + "40797513297902296912558249146250719027673096762362061869679644760516467395532", + "25860804805212576307169653437125988973986723402124834080464395892440011402023", + "4413780686135711965862933312776584799308901193104048530208340665228866797795", + "6277803075632326512994150724499608759240807199124460183575363837383463793644", + "6105502724535180475256683452724844239318129190274707992865089695509126462383", + "38555630731168325082578225654359114436859138436314688103346612148395593089213", + "43089899536825488495879880123972160711820358878922963746806638954377820478337", + "862405836490250634573695347392175301645584761583022570468899721256552694678", + "44835535395969944206443947674182099545944082690205218138671530630649306303858", + "26421642976176156032529767067344356454229233002781020994309692664030160639089", + "26304451581569433897864380295639159362544856631929641833953011868735924679339", + "49908031550715319960393825858557505772632487366671007659192392737335227664320", + "18481899103283638689566443600518394176217076682688994681377288258368282305277", + "36030988829870582614721409090899313475216800402504641687932021229098197721474", + "28434103805984674617162008738915542578305414424616828840970909890279573928255", + "6572135581845138950623568593967137103727143867222077737682487708821317207792", + "37434012992821400829203363502513690060204477410692264832805770943972428436394", + "734487935461219795718821642791707171896770191759449058457581915934728140634", + "5945522775118408734465801174992361262496314295692729454996309181712149970725", + "6061362597025391338317960105204071234280141805965826143111780902035264626765", + "44842101708268066811635992777701483486756386630558229543057556971287868233904", + "33833013305260561888764103874464248698794240800311253239678001509181520154672", + "13783924045989680466787159027866381441409620427867803740068120579166165150700", + "18451072401456646022088635420864560768443120376339059404828884303316576926769", + "6611089591059544314752113745247762285063445116848053067868215797927618689516", + "18118934366802262522547196235406256799547333332255474717922633345665588600248", + "28594230178986159429334883665813607405313354505803079510727116972754084185320", + "15872047783516798506535285714790319817212107454761968893188608896457987808090", + "39376189309286196328000618569110236618937662145021239150811068183674869548788", + "51790212845788769544979923141610226463829629011796262933538813408273630270437", + "9415568635090231878089368172064106509694234875138609445760721077054922335510", + "10808224570463925879863108253706767340955217221155750057882460537013441237836", + "32624780252627125235221598650999578078872672049996805201230658341224642940638", + "44882418089893714597821041978800765637755875397331154083202861592715138004898", + "39678045486996117440545240333075034136113029550039116045763695235590112285611", + "10739750268411002810363660708186335562834963703213829072932101589022130666850", + "6458321220014111430927565851113336422924729821579248905764815377173352054687", + "35690652536277013429095353459708644770122884910231460634616848854149728985804", + "22866503983008162398627065365410672184269654937708510812870906438200019774458", + "45798444487665292059738796606381335528698082861992411911046391601972778686422", + "21642905225093141418353378896253519456302491787855089858941184263692728424278", + "24716410610520984884080467997890572811890587253193011688305207021698868139761", + "21165290013769627615260150235753522212465360303019776973550198294898631557611", + "46818981960486811398003112702299922989410794324995318789139291905031631037079", + "36176618763578564377910283654239408072294157246495718915823498322616238901050", + "13274378899702688563645374333166470995780154801427842572766099561918811046243", + "34732451288935281938935107221024111469514541207098817353468389437290607925367", + "10192680507658068454245800159121380031830064510237610380278377993312629458979", + "26011336184269261146772332120650333030990406732729528773248280756536338757082", + "14792023544554355606692708570676583451408023659919161755005512470556280008334", + "27782503841762117975063137180268426737619708847085348418283465964621858151467", + "48257729197279843288778023759825971827372626792760193778359235456134831610563", + "899116846542040334564623286120433279580182565260960897190198302201061845499", + "49803105087343659836047081416698192646409997863031949375481477933316519110688", + "11552640137683163370281908439168506346356679615500990279924235031008378178779", + "38317657797507288711575584989314626843696331009657439648742557436681431503596", + "50610386390757221542909799910217567300902103833369617346809892852354153983920", + "1781992546377902685604243671771967845230715989100805860418659523776898964257", + "17928226804588064047283401442269322714181615505501562886671236247625814906932", + "41077073732200295738674155812720023358965971593387291399749165382921605617035", + "26400247415750435502200394006279640449224023774274437710058463892180368739616", + "30490831845323370691374166060289236917698023970791051789374546789408547974765", + "9441859741481038115034774598602884800203441538552918222379784983237017673606", + "12108455612904323656694564550016698029130048754242112153257525049962859243609", + "7323533313304928806054178275611035260596874190717028916541622628204706854651", + "3536346804596292025365154607046754546671822567895083689705183210870069256789", + "15085491980809959450054178064833472285774270929957121713195823671270630652739", + "49246908153706319543709932322242889714055707824341764849794552135480595908853", + "1718341916497826212699951411538121447104487523111441479876932559162603230773", + "51528704220535124286115007066292673370320978191312314471553808076309145530928", + "44482270729673408427055036724703731754051247159440227474768715099582327489839", + "2335081999532565696428759821127795134226854383941462623579826575097976952605", + "21570709675435589789060700114331333120220762558039710738267992558507961254251", + "48844771987065832599379001824152962228527990954049474626247958213654388144791", + "6433297665837627760376202668455854562813582067641282213753440475242415640783", + "32128702483187795723699418217198077935514306066620889292520026151388807673400", + "1891828252966943042231728551497441967657630753635616808507933368008158102952", + "37382198113676592897595793340482633827902287230568882254729885657583119779792", + "42009514344335512754509378997607484521097011501164560211001812259052072793129", + "42571984287382382454856429314607560184629477578619571159889892147203477231153", + "11520095192229994352188106996634898102106605358200680057558700000354685466928", + "41380061745400797513076609186066126797563621014913831147399329119128814553631", + "35662618981371215956933130628116507016135279196749967315423594174590434875113", + "14545153466258802287641035031481553753393176285477980316320429790271126556096", + "32779022778926037331320780593973456837718503738190943636639340019683896318584", + "45271785494862383726239581626551066063224443199670421800826405296304292628502", + "33032860402268481210041457230761958279223424753836701759300791339108778092416", + "13025744396415457390244058202466416525568954230466258342810879433990018522007", + "27076382984754257110571722988688931834274538287773562704073559896590100283302", + "12590985220946855034366116501445559296632806962678105944547602670811305209436", + "5906134477178202348690334220272861439635004056647854569382056713993438432521", + "45496664722965174119814906746937015387377152288405318670176643936942064226703", + "12389337635427364084397436576259371184923978242195419393890038653945628278617", + "9677518202218770239395922031345887338423081733219129692030238632122101483109", + "13571665913060827447663219603906391247347515053698677503629266810656306339448", + "428508274569122533800819602105572985055498252748462998968687774112678614538", + "22896172757999299502959977467231661447886546439347541644216825088431475015810", + "2023690697297695614715869158137937486935890263739890859934669709961098476047", + "36187697643761610890743585350761494714633205757672759507195000598140468003107", + "32178828903300216587376640477035642502072160785212710703753022844132234290677", + "46325026737195866982591918029651847954312986931157731770194512649169723288388", + "44285011588526501761198751865870546970024752334076625791325536315171207270601", + "50769781282307957292499033391375102553322396412881863819073114534049876834653", + "31302130283030923006102841561039384768484981652326671549473676986203432616704", + "5831023310460527637065277538972922928054987926451896850732375292642442846118", + "13394505294536674105057106455870624671784326008095365256762127436930656867963", + "2958143703707878800890242253771755646447640272851364146804130349352598806908", + "7530568452679413020908905466143937402755368896979778613229519341832750053961", + "13216865019901707449944013663140366381169227416836095232051214144964507285363", + "38940726430227737380996381513222518842961406087303450926464415578896024387755", + "2138333873265589195096717095468198022676556824881836512150597015907387162914", + "28555563877306727084473153658133451719158260298330789571046201746314014468604", + "22366377753174126465370208541830938190351979822398318420489989188497532568515", + "24365960722766790413824293045007637443717589034068086582373822990351903697625", + "3714523600066347366826256192350286405500909331787276832183645077908297599633", + "47788796252163126301462878218974224736769557269531860018262864137404106874868", + "15769177923042695345360889296893762570181244311997461015399145409291003087084", + "48681260130262750847845537855174145969285949088726109943820865516769648858459", + "5880767564096499858789793789599053503696580519651606239838457298960048628729", + "24221700485596540098387519095702483457328240826079167265557724307908176684209", + "25474338391824722945135004439096840089142011000462868224678514162533708012199", + "30342760824969680853897105785529057506345449896351693819029290122114106213023", + "1436515093371169517429683206352948858558022860018981776605348069501707179572", + "51822305427184055810285892857119994395389776537406915411708043251633255587650", + "27411296180882983321606199117803860195344459018399441300230476505738101205786", + "2051431114771221612682887784460689353939162621504386229586611615328446434514", + "52083592275025015885411157181164091890626931568972999221637557695715039693270", + "8514751956045058140925116940255843204588574341830808696847714313246992774481", + "1605761483653805937926667659033884618639331829287713477192166692214140355704", + "27023615179632139407748724312390540175164232301085232632342779034083224288523", + "9676592010717976475859731743000661269702440498332243439529696523616476031421", + "41709721800591956399706410874744857647645978340896157731235204194722915385477", + "49771952068254783259004593366897857568263624609520670487007345222047640200294", + "6368467672984198020756933066001602316556436121142867558031785844993840800450", + "44558508222101539675163571143760821004475317476684585444781215641448650402747", + "18626064886466522491139003438914468922291356036590147403395287567971232602983", + "39033815165243476880239781053512525529934873481456698937996789682422463321932", + "46332456168250268629503355772804666322981333168738816314858439198605052264353", + "44970557598959314600294783203620240929497784476147916167869426923343523130799", + "2152256087425654551272686482053659467807822606356239941016357421478120908324", + "41279604733365724498061244862887940839118988659978402257506899400895824164600", + "17410430964562301548218551704075438089352411973718856040996552931519533350627", + "1375798598321325469002265347609029952782441003600939719913799110226198052352", + "14922442358984451421532536157312323329126264512833701991831467067091892567159", + "30371977385787425243040096882597886049876380709093537937987642589148238217412", + "25530528532842794587977388401623810474835472620555157650196517897388051730490", + "9520789619312299982974148035645326646860458691346451067747644943421214704305", + "36273808860763367197290202778671846083249731970642769960817299885531584559483", + "46565569325382883518900489728121693893830886837423760605037509801208337638552", + "45752056923148961608141120053773040596261222788338211991881431063692836803645", + "8488350251687171939514874408300121615056616689225830194985461585036529085651", + "1967097432547675563167866278500873195358903574650298876854524212720844332740", + "36742854201329579079967291382924408902130006322765270601646614707305986261240", + "34474163792799129758506603660383102693434884221131887985350200176474143526893", + "2551874797207065229401534784934328141486798432597474938806984656103367912889", + "23642278937354704952040772849723541274218424998492852099635185522690019910525", + "16427764572060280681385011625464895776358400912250166506361829434330746603356", + "42295216441511773440017766440767816637989363687487926176653181998006784382982", + "48204459813297173342453617416365550829260573336122109602681081717501059154449", + "31870557294779992176113086417151641647919633633817787935401655668583400687978", + "21249356953567516477622939882132926030148833117444751871706470519077557018910", + "28971653764847256774028844858274749977307023148045567766247674932530101231948", + "38469877791789331188645080168223201758710769144363366070053990028039519039705", + "19071289800038823481204744992833127712778900842824666150588830087990084476112", + "33927149622966416324803917284477004182961006950805016660354616649824169824289", + "16267268296573745810418903341809532560366936130486256775317657950645959249150", + "8426811299492218658811965389358484873103219029932656440727539254231418667891", + "2577104285187822739733308085612128949162591625585897314685144753120063597179", + "39005894761203505660420298560250057016631429351279286577407900075801521871620", + "12961306404462143181416247469661702703780833580107062553279656436769271092227", + "26694203488134516903027565289843567786264512458075462882804810065135378374170", + "170063391350385569541400011798646629640439571528618168674351796403824522776", + "28675752788868253644853436846429865586961666941770559792157864339688647350401", + "30060483135958810964887735445150025512997603379059262694307796735657474484891", + "26331211230841189799745538385551911636566751701180022876164996606806521802822", + "19697981830342226986137630793025488921473865712842584709313498722188533837404", + "24309300188891442543880824107672154452984707007361358686565377506616051744177", + "48883770559864454597039800477520241395813461708088594457504720335919396142057", + "32087761783300150365091261337906189729974375899068187409182489463560473279892", + "12190412852206331481600872331281044308333157241984653005488774489514887223883", + "37392554312070964241408076014739117269267269253307693335453890579820890645224", + "14885497856786380473795096679595107806435630849634124141143808731790076349596", + "30427374155411972108700053250873082330912731437851652356922435143205750458844", + "32342253817581193843408963220715524045005109016904499618366085592296409731346", + "47802156822062478800596440547565715063302922607953473538011453266167493395420", + "2762887509453347334971244946129399735116906558410530532838515362156761895376", + "12151151224458267396535822060873945482135944098744227686565286369736784125481", + "2730824076388508269601312589407721736634115568901208713622844609515031573110", + "12673849970661500945286560329323406186222995867388097990290016200256059701127", + "28285847074167667464449240550459890812384214050987259675670203070747981711735", + "34509920766247273873184758108640412332661694691529438835905277816651654860425", + "23250013987589959770965286334994287012822813698619455913995279645539064748884", + "46315947549662738033474749146284221191782243284636148950373064351887014679675", + "18433951092158892178887789230615347910086231787076887734227107737522598486882", + "30926063536110726223572344347070588009665601187929954625514414748303202761359", + "32487655181637052078226970610503753455484674692588954717947909878471166648588", + "20478539027671448522682986820173125868241662118647861539355528652682470941556", + "14720799958970954005416144018844063139946126380123887854638888621637942302364", + "47459540333024009611037168110133867882053864276764422970630652988175837170812", + "32362238526925978159361640695233637979654304317024166456916648814287074487986", + "36494584342829990031783578212936781984656284118188344497465247569893098505279", + "16484744181123313138186704586805486701808187524934741508348590667726557383334", + "13538044153471140138393147000593598400750575242439670832952374604777794832723", + "42249636669171856604531186454141362512472968719831599845178242701173669507535", + "21439061077006987118167293187375468098047488102472334195240778397881935581399", + "3628162269412689623305812699362901269070336768869061825028936526632805446720", + "50237369819266336886898751454032109476025220924147589170989396786478791470371", + "4383879719770694793955720847416245353803183576888870754755482053057389024783", + "36899183209925393052201112441881934789907341112370264968014474595853841895107", + "40853389010897990413576353381592121242690020959155963007921876203747325292454", + "12460967106712208357321132295471236717633102283824522136129313051533720744482", + "5896190926589117443988759401590011774467845631441910890491767304646534419060", + "48078990469877294012970090259816797211791199909708936545183982629133949936576", + "51921272519634696223615101118421100466100645947983169640698963866393349238995", + "22524047447747535094167443971066500564187501781041206691783085463606754296391", + "41135566811226788953192181923627809209845332728222698963438429131676121296595", + "46313162662851686484378964086969421060288865357651286924330527817337490503055", + "46789713049931061507659135891921436653051104415149681312701822912150293559525", + "6005919104993769633139774744270918750273138093000247172309885762846352455929", + "9502987939548789525224979172494371516148962830833743750966453871571991883295", + "16740444815999110100928837766716267805423365125883620149261084487266897767942", + "39231358903627340313691389665597413394556924618513971205151538891487460235567", + "36457266623792817190969078983442304872499693836130006845525544353309534457802", + "8387989210196643945108327418955878915604291329967501915933537249560207052759", + "50534440801855344876204438213038067443858139389358479754182356213122765561511", + "955416652263986923860697375982649262291796506381524864684496757578325013662", + "21506548758640651341468174405825034603351906437339452137448427291190194261479", + "19630020048217112329104127933228489184862568122597266469494690928851953858565", + "38594065106571472082263704491745108702234181411746010133881783824319393373332", + "26381720559766613246818680935264734878820552074716711774034677729748565537167", + "21694850955218873429030108096732406460539939333332452138046751699532551854731", + "14328919002048183000839807049378982440710847120580024004154868309480046499809", + "23724449608615355571829069153170435306757173530022489967507055894606081338886", + "33148809323418325801456216678474229337665771471263568257664577293250757383239", + "12565184560765219266720868139713968064202544705197564378369398420123951509486", + "26205024274482445919019973288756098358307729149347121886956476474594496316719", + "27249267483333054456621101255419623223844674450300895686628227373939781408516", + "36645057471419945500869554868027658123524851326137636121672514740360919001011", + "37977830983048875443193658232455102158985663800596591349047078005617187646363", + "13048437260213802175215167179188063766531713986828870849222729641815515106167", + "1336374269153345786556635754770637496128437848834603250270483177716540807795", + "19382155765203304243529809543319663603197840051683903149010893878978017334372", + "31095323141308397866774081636808719919163471320433031872174493484109663461622", + "6129833815611279843813593034800414214623390690345087761784447421566910611616", + "15295281417542358324921995851415928575005008273887305526313393677139826612158", + "44484536442836880849966946753067702463472783002271725452303394262214526602090", + "15120001474375894781725326999141128995207615272920216566826734974717303510726", + "18337969836656578617952811372573956412294204765039739959985463433412039643685", + "24612400699737067063801367180223399473396030857082743662660473331341592583772", + "40299374313678590417653882265023908269938627013628037395804102409376838760426", + "36765385228165589474802115938891699652090721447083356295619434567855460620609", + "9257503850018980045098896227437682023390152036932212470993834687278602406365", + "18837836379304238581127866719382118725573987367418970390774663988334857331877", + "30149765696947625223335932101260095541509818507732726423788414579790550927224", + "3843252163132482025519930776110251088584074001276667298286761549114411714432", + "29808486945181271152661020714178136782259244137216494941849920899360592754388", + "39742042338702392091261665952409331997397235053207487499786409739248415725817", + "23357063590631063043826440160585321939202331961048005116984465191974350274886", + "24005645754849581891474130598448495466816603743833964899533262926811417035032", + "37767157297522157744909582459552743452287760735158066866994485710991098051197", + "45833076643034999177030058537075153004759658508389539052551619585041223298209", + "21125681848370680841796720286726841236552419934102782082408835983657358293006", + "48144759162618678660709800202443915237041451260135727210880085637439050097088", + "36104895734831303099135218683038407549576385912302392086531888699796081986654", + "31634242254099103217292461345815102408503291824087997460466818051449442504754", + "44832188042342994973420358581811743746222597375577710274421860760122253248261", + "35472224407372544656284560262214148363086670096446246454903192740702172969829", + "29808723386815788107899222377402343021172539264612744524703165526697575980223", + "39666104051530865381605361391965282925997124602218183118462859423917759906334", + "18453593126267841442575950530831164175490370326313257134068431902810377959038", + "29433768083961604386971611391019420809639516706924474124648080243757988621901", + "35302775942038285435144714490810223462670893755887478738399755574940379525125", + "11643587588092712825547799637421554348398745983233756229074014632634819272560", + "44381443659805392039221776935880502612228104215108874819992366546333628699266", + "18870856142279170074943161545502613823479389470114118800864724958188286268765", + "47987816176668097711139145752843643395351623517074551702270398999933286388945", + "28144509977418295720852550644988398924085879370007608115263222837920325872076", + "44419201984503657209759773352035266140304045741291074468217486395104735516018", + "5049652964544418515464913219660175728719833519598996360284595623299262897504", + "12883058445992035262741103165222822110244216237071524895762071865889204973232", + "33946114874782705612928032412528556711412854066969657801457813244728284592566", + "8647846776444094427223605964209870171683370460421016223916314152369579754990", + "14906646452934664129355517280513518427569525850712533612910005890463853116180", + "42893350793468225216237420703326232727408071594489784281505724853010835587274", + "42065468194495969530044270042910125489636841963912590228244391394829096592303", + "1197221470218056388211741556088774535293898678411514661835024893924384913418", + "6099089537046854855698328527975929305156435671058056263567497806798991492506", + "17744556457448830895792460817490611197255441542544469824877077025812499923046", + "51849264169028764809822388872983263824394530194073818482233689546975066281596", + "45657221887090042994796066737424448918209584886134765745491423711403037666063", + "19715888098220826962050263405326054326161791797610704684730091296719714026593", + "3630764012030029522879521043635585556731903841606828242785141908166942230282", + "37917298496209512766982727636777747134663495827878655436807168051546562394859", + "4075437477759695521913038340035468230073701757857396610536382724351003320157", + "26644355854379493001028786311261724953545376152483007126060234545749187070993", + "24752915719328633134580702558515282856858563228387424209758291658761972642800", + "42992259745264554127933623909154415418096156952185567693961404799177646750844", + "5159105563677508331653326626016898794405362957272741521337220285631136758449", + "17581511365775088359400264470379639175873648809596347526799822265950439270057", + "38898066195414932583249995805020471787124780862091212470420940576115522559747", + "33919800616722169685940332711531040668474127591242023667314849253243107352294", + "19690407556528306942270003619839984485021934516729510547872842372788331308202", + "19610670892160489841314332098812755101221606344132791061081048191443212203365", + "42881984633592181635229630149838358841069227843990644358209695011172450566544", + "9244097180389535650690436694054098459351979340813843937529932845426550928914", + "74617471640033348289148056859338404391417496188240392755294630133409751687", + "6490330112714368477331433497113320652107786298748679077576019583548347679690", + "1243811156079432591800275042299213134931611177556596166943378456496932999295", + "29717701754892122487916457225252031853636764536835936037074019617603387288393", + "11529269518506874033651628037800288782280570433072565928231332849871701239658", + "4940864386433853113038401657323701163053585859669545000027481324512644917145", + "18648214472917949048990493003121127815448674101937580250196203865479969453127", + "9620609100661976203196856267058164309706557123622297968927043972335242667648", + "43131875720369143272045838051091922127083228157244165344595515398356061863928", + "10543598568030299629203554592913442833798164005191511333449982449166235530153", + "24801441108284019797422908653895471941508674411778231550721765698006867287753", + "38540781935553843677270549468629620632883771994024308159994877730481075238050", + "27400191021397231890508944949162787128856653101407299500939489664957624873830", + "28465851410220197678406579819013456506627262015719846719871213132851613532198", + "49108293473916540905060237538051924692731410159444660361500926963474250244497", + "50368333702535539503410094280593551837732819781299376551935780159514415185966", + "13222269483217462755588961071167870728086157364549036803101146430252426509893", + "29319525082744317951206531245442622402922902671146059867463539409456521201056", + "12037036944145389971624136990160613355485330537229715998470037040260180744924", + "41171053038981199288436087386238570493569972564572278467642404962708739705943", + "41813465593182114045180756978480395250482020247561996017431905526762492418527", + "10816190028414327102785278384404439260536221276860491575399612903682986727445", + "5424448855468688131802362592018397620180101261796961077709481679306123441071", + "19756260667019205610868549651937197404485883292793450392145881894522900656460", + "43424210445007663139764843416051295535558705185836574178922666137918406430331", + "6285051341728395368066403035061202597558287119341171645492275025235035806069", + "14634524646443070923011729861744414579096799718290496460373691887021334489038", + "6447769451675615654868058563347533204454956897047330584244671490149472645293", + "7608989841932091225106093750061789265842068117521577373248361090639201852309", + "5949004464331009404565810857763568226142691285121503239919262126460251654845", + "37331742862370424648045333445704927896930234051942296510049432134160442215599", + "7601579509324906164121939124678398033805721306430107358696447537391398301569", + "11494175821571003906232823588310442572501848465973271267575638838254843087883", + "35779307358809724276727930795736418044020176951887652397856204492237464822339", + "11656624672669624938570638146176222713475614333576791713406537378303860146567", + "50239022941499887205161293992465852213116022792046743371536792716776226391647", + "17793583236098702156627504856448539430013165929505175028163783075106287995447", + "6678152127768085581911695575452336046409515917601734127204247259915250148048", + "5284642365566852104931059096562672518652500649146372352753564467538460654102", + "42246925127647996244167871080189431817416037629033987415109870274826425965846", + "46804164548853850643200120827310586676180406454088155248580204510384388709858", + "18115225701785997344878987151801859478332484021128133458946286854697451723453", + "30797907762882242281196109309690368406034064186641487987569677001552720193133", + "48475734420829228251720449087950936923960988364238418022402877628743640154918", + "20286887080042324798927972995471655950500800343931829524294954458211176345056", + "46667825020507806204031744678132903269810669966620022981149363580724413554752", + "12364092420662889406598268667411769563790387540426048385859615577795297133635", + "23271782388318071607022637122530617364295902300593011810043335991537785044036", + "10290558440425236433873285667953706549603686489325457123694176516051463282965", + "48553690926301795023671663855151059879457914612191598493714645521043199494275", + "29050877643768038210157066315782938780041720481980334223572738899968418586058", + "15273715702294297248955318419420106001395421735869052073446655273099834362414", + "46015558385135742537153233198496637017247144653900140040964059684179788894687", + "47069806653939385072114428827829327948915883288853441792124341513114908923766", + "40521309656339034134156528164417784864841643861696675120362518975984107238668", + "37673987548859465549697220945260025913493118602426796645886849211604234474327", + "35806918077497221208135627669187294769368897571693543109961099252611885360340", + "49171253614646435003959313187232477625784260454215426465220389978191922414109", + "32072199349538515727966252741857301156609017131696387457896680967498130050763", + "27944807270929367970899222976866896908076155686959159150861727146069563193373", + "17920416122907739495111303008701443599639246033930158339890295199313282358349", + "35944063532945094154157503949782238857633176916980317355374986381428081522389", + "2863617208666096459749645892807937277798915382923112672137634337133545700804", + "13126029878456352882638392241664400160592289416206274035283450295589593491277", + "24099796254252852636297867028645923675740727918195663008945831546310194517006", + "9154200888829668358778859232665785164218566254554413075924267306621114637839", + "6579218828501253900140692934801520358253039290757872918852153030208215401922", + "42380595503934680639803475806976075667180998741400657580668152979879823972805", + "15132530802806912634683088357805978127259479078347596223576875165769228576412", + "43276553938355893035614028219292922405306502126135767729126083557698293619292", + "11777184881525626267832614602899016843054925792474983290553463043717396626326", + "46594907189311016699159966788226229755999892845637992018104641898131678292723", + "43958392935691316994918705015939735079129359763690434291788493675949221200780", + "15596350860147354899303067047601182143030764014476767136316554768237262360527", + "41870298291496051938349749190431531855076924689316883368709357033348148669124", + "38332157506482169808542929449341337988583501457010231836448080913497032278619", + "37992861403220981809803453622876490387598094737315330033266306228996186236838", + "13816734688186441161957579161111886191178154496651704462292381771667529141880", + "46341867162094772488105534956856213655324699413608097939718024260317611796125", + "27617796636243311935193071281380656632872744823685392997513518404892063619691", + "26738224052368081763876845918690420789787030786822444385930826026568969227997", + "24921598563387133678883748710135709264881462774847658015732340147257441334843", + "26768685022344584286956726760213183780249456681080027716253905933004630426018", + "42172689784821246671973772256482013691950181465002322449835870419930483702648", + "43095743767863512705629964320305754950401393383913963612116127365547295964921", + "36007468637595412666290816663131167960088632689762825869262544798645822869097", + "51686878387622479448402741229362267249659908571509515285324574884619485074359", + "1293469627117039084598324953837192341436729018683612051274788631721424932675", + "42679693230679403244107026663054896212425736598066013325664460211760530309498", + "14400381054161402604549014380155693642159401200806879832765811334433382979736", + "18183450905249665938556606528567943283587441751490056988735759411371160729318", + "32960216449174338480099072862103644585387230925494274393633916499467396951709", + "6713808689179314832251290011002067100307832826275957711246829120103470582263", + "28964389494877807399233685030529943518517678340328258225262553161931896963045", + "44493756029966705490345902166749228623861222038888685973123760175232682868786", + "7894702484868800241200915060152293251034003156926126972198313517377897043905", + "13858996103973187123114106982317294602240699149834155484602224943855197801706", + "38672691709212498256624499351533708803360238631894557448361288794313416481593", + "27140586111885423816782874401021322945657025054529178510007922906976003409457", + "17488452605485532538451768416715190610699721035094877685772029853851774267805", + "24010369782931318521127307926552642389455024601695019041872562253340080240112", + "44330310106728570192223635566641687842549772636510600864027744994079618971700", + "3401847324029215004382194556965456508503320245115737636536131226526458495228", + "13781373945237593031543291726612041767214619637899250691903832121600774185530", + "27852821218497278335265542081178595699910765859543485346270982674897498527927", + "4944170042667256819176721822947062269100512141570679534121911229465504393523", + "28368800089081673849841246299674726476621257655886870616017412474041871325766", + "24968341908248022203486236264223104820618759683345935172654999243388355920788", + "30843754072318437546295312462416587346266730214513468355304800705319280537102", + "32404246548992535233219941985216396358079616933157111583015041717500202593155", + "18641145591383176581143294381482993031913792895563738899609126954586109198904", + "4761736524766459320719008808156753597241732523175290429976764293377406441324", + "7791404982396720520743977708192093740218817428711946439379521550648572010216", + "15304152902591942246052841390924701335343892992069811658035247558526513621366", + "12910204566150055171286738094615521091006195249970061881374676757079929042312", + "47673772213686473046983437137816731170762654830716833336400262593105007252177", + "19061965066245161673920686262828766811220464837673918755904852078753256855544", + "46938065241360942525250594497663283565754281724911294286800718292636943081289", + "43877511566543167215180429202545503486896362190653256544430397137119380389314", + "2679080038907252032123488436964437308366268089714675377960329704580711911383", + "29051277197159719980594018349335128893234065723051525142269802018114935313689", + "47487652362253584124774880255393526111523938094006118073482653399014287160113", + "18943780432463018150153786241019422666477959201807787771610029833246919422362", + "35434562083626993807962274381912030788279700258077432094601638935689617356587", + "47006641146615567233865258793503979298270400713342144763239297361312768802828", + "29120977454252952818383704052946314362017141742743765581472181159392958388138", + "2913175900096060979940593448959664911748950253257895494385834341938608941580", + "33926301042753470145950593723050985867899261552670834617331657887242200047223", + "2394342536950159556506397390253402916688867799425595888065237991259642624430", + "45985839512527047818667436250865258599515233745548058623293386756602485857758", + "2814766064585793597812227974740787570607101406152570049707454535138086556949", + "6230044079025692664245381887184815940091647010281905114343134103905193211129", + "24663448659684244721634101532480419379448212839317022607372857118909564877627", + "7101954040615383827910702694109013160179011844417407257211555709662575448223", + "50855992894980586381031482651938019248143629659650184865423974888891367351732", + "41378670573906426061620553154646659333882978665128764794259951678982156152929", + "11980370869151402133721461017147511727130226668499132478432171668874316424915", + "14794900343318836307966830241999212485474294572930273443883303123350331860455", + "50403405709635102475223398345571791097668174664448994305476647135857323634351", + "17781384099734871469203668205889774059186987876418701501289036743747410114290", + "7079493575169956865692904085448713280549461278457168661018495008355685779445", + "30043197933916320811461424310069768838756105344758823825713119393117864929903", + "17060891353151031337504412366341961698933533865506688202686275712833569343294", + "48306242788523629055064759524163936304588459139979816817094580414371221671787", + "45558309855447951743268285421697676157916520246182944157296265385139312512646", + "19641079302260207036603188656632913043688987685795320711673419679739551201736", + "41880578565933779922854999823716414019928706212281364119165641329967372513756", + "35556918013804893247258193949436869225804050605831891559305443936129595305122", + "35239102617271935300134431138067693648564725032823289283004159701705941399992", + "33156088285362925184598195408610247479593456697066978136277778499935147751810", + "48569508660738265257355226493812073118238455026864638384463244320773775987221", + "52286685199039501113304050809150551076505785481417572981819510331447695554269", + "9023457469782644206083950996394375795994102277208487452430912265257349982059", + "14933368320796257481836343006419880529827538822116213161108534974270762456416", + "51185494015152209883432316275046586636358344344831201545549515841450846108306", + "22699139659900188707008269479426459697664019750443390257623091736564445973469", + "37766809143021454817494169438716817915549553780023227647551962696881928805243", + "28975975703604982811486015952416332469773780885823850389612391626858105624039", + "41606000300492647612034029911166835958437681130488675669294747650879051748984", + "52137651377671515158900969784363873921891735631501204427961869112103333942869", + "35216038200662355240770286633461829079498239764565765477566059478697590427658", + "961654641882238832891980291257315859447038010850322986451232357461390670512", + "30675392985457429697788073539506114849663677650722993368266435348832133717276", + "3515414110292300296802859526059467701560659399520230770482873379220399831032", + "38042118888328714914953489988548273301187198384632485493303347578404921188039", + "48078492292018863377123225896965631123498548637280211819131058112702278213310", + "9921671008185638452326940798399091445605550718342429631218486247869477671015", + "23431154059152186253818721578295044484312063828870177238378210833694299605745", + "25192644419017234644178255528311953582064155728472624477079524589575858741337", + "30305166996348706719766191422458684197284538737419650376843924198039297298238", + "39104688515032169171071109898556844327649205583677408271451000955778031895878", + "42391313598755524617759595408099225260676357694935294350634487052941441860251", + "22149524277086716223783552436768951588242831899401057537216399286862299582802", + "5914018179280536027933099470694742281786738160413564494036032231327476073965", + "6385165498912036498915685826139147250530492290987231845280159361151413142106", + "41028655894108823522067295942638796848745009533929908287178180404024917137112", + "19831496858653926537337738762529850505639461513841764798267121793697191778265", + "36886585287815411927727726627867079689939488211543779211584029499462688622772", + "35257991443219288842300943321819931537060214006682815584657238251597102595591", + "51551409788092578183957044568116935389428704011936531106697160643352784559835", + "2735921654212942448738109727006589271815260562227186034068102890322028081562", + "6755710910796631069897035693282935535656229556377843617333317459775593136490", + "28403285567381959453413269062440773567039968726779412127874285078948125198910", + "33563928004104778222966666105223586012602496580359835036620276046710490068914", + "15756590323108071392845406625738680360740023355752632462268228012829349821244", + "49637936784627053821278595933905416796710085054524027584188632028678142582592", + "27384187765922816347071395419633029646188751736834429398823257480320119012387", + "15684062041424619682402812580755799445110960479959309018902226936720897531285", + "12576437607082662071076171965184768978549799787476137129826803476300979354877", + "42293296671423786845277875456868473438279516552194173345900029048336912670007", + "14092807202473190917350115847949450202551173023890906261062424373892242464877", + "2082222829580371513483493375751976805468816964503683912706790059590774857145", + "16543783454326793424087144362479693856673125785024232751428754384176095975868", + "47583919070220392755148107136126046508993184097250702970320811096561924326412", + "9466025209508893182984973583082992827116291445057250207376676738138310931004", + "25324248174211100408057084778352923078269015492217315494507632998212103680234", + "2042289104590783962256102308343177002194415848162014485531821460968699836546", + "34260166636798646189550045363903153645804593841775133735311491917876008856540", + "20465701639462406350480116069059693762023525224118125080004003540574536000961", + "27391211844833605356036233376244144412218201088550081231993653135935012668965", + "6160120705947128775895694074034046853059119101104900652227881772206987589117", + "3955125422566331997458674748693688796943027205849574652142486738213185643165", + "31335758938874354378882102255773791282173748318638101678564962649631401809463", + "48846255150186544219791351957194273090842705949035916028167175995263950175445", + "9110321174057979252971602075737357718645573462921050119704806341825127345447", + "26378015467757654449259049919391608037845342151779578985795971301127106340989", + "50373440707551131790457607022104255657411323169893121387968089690101131372430", + "10076224715863189958330817410568234785713466114499442117968042692598994750057", + "27338224142781029703211068669383102054772980340562719610415550496649617218238", + "23158712001201074932929907245109465603528658094997922079611264396613129699173", + "16708725188193554218665572717707958535852498838155119812652524001705207989946", + "1199969202727487717202919273938904279288479308554611362421067966783229397267", + "8269410756985070134414363125494411989837769565286701457470247465330569726773", + "49209289749501285434386239406606335615623174208706475342980254398714965847650", + "14728060944448849249783889463241996351922688998684877248955625935710101822960", + "29921563879803343642510418409092935826275674859480433159989319210506770285036", + "36393911388650740960901181005211911581940768874254363160084613312693829752178", + "10539132247772237271028673467475056257584082497425059910158919305477298095156", + "6141749906102722489317305634237280730554490257760065944915925328207012893409", + "39865612600225156699451384525617250369521811024315330896219975513181425091032", + "28148634323226592551986029089425641706987799209491360006269193774611778913883", + "11289328813059332732641060815821037432009517775177631952681479090486152860849", + "2874667499064644915704460748373754292211902657059098951173340748250828389206", + "20623496765275887710603465296571813809736228434136382460740968861016142362130", + "13926730378066519275993280135528851247845928721760020946452945766916519390637", + "30689407781842878170909479741757957877410956596427401687036051588389926061316", + "48106823275122039799452094372766993871590961247566121348793494501183810821465", + "51851130923392576662702586491146318976798742988639302696052515248066149193342", + "24149594421897839134606076241605109067953360151289495413328608404993486101079", + "40760977931098920533826770999128377727552234225022539057310508566759064329793", + "39631838295441041615477240035860928323845366074393036397410083325072710732004", + "45203146917745421259151362897351941009185585622153066961123919946672085414979", + "33252088711430132979027797701437978442573116434584324961126074197687303168959", + "30694226166540312551548215747306932890291711250294440779417014887490519938070", + "10674636748184779239144981730938996012295076971955268832011896271046229149178", + "29552891199679017452733198693384853724481980356501293744559073460896233563774", + "13538319852439936994756443172388388781168692481301387115654876008416896535291", + "35244414886525499351214528388933157702456514352540765789039162732883280311363", + "13257940485825402745272894183525226757361364013671024098558030917066047893968", + "30262062614088074581836190916478191808257638136112966075081372119493827709708", + "26504199314340686837334180329421092744663665638150907337618034809083048733800", + "51293755299458845690090437266819422645080579212337926510057824678972815994505", + "24999345588959953840691478007440934164580959849979662446485554189451582495165", + "47471818934212212056920662961837197737878342621577383690921683183454908286907", + "30965607183479376447603682973549822506289250687226705827561319651353759529504", + "6130581593113027845493179203839309839192261811776011899148989030960350848406", + "22485329967708425716598206489505220681489164307914453864435945361860520350942", + "44110358557697605678485692167455636460668214836605177215919905713644854699481", + "20438467033130929503908258640299622226840341668288906607303973072379185450546", + "50956755783191813337555340367000942932240806606401623329396610867487931944514", + "11522705299735902348669741303040828049319653112472092831986291130365603089930", + "16316521255171896582815224314409940955877666796965238521443947597871993418441", + "2412841082533844474586246263286976333122673223466490163728004537013436366816", + "37414557286813172161167589613291729600465466866412467781268228156675845451512", + "21391905679385449438259360406219339236862948987967180813170848908285343629079", + "10479594365311905463096373017880112280847379080857713415472507536040004885492", + "8333085713109106159155997848871654069410596141761002900470915227846861805502", + "48214049028538843508518306078704758371265652870330693100381687395235957692952", + "27645920058149299147099278460442974329355261917454564093753557276710512064709", + "26817229451543674906512117113315555779528067098926344095282964609943270342910", + "28072148237468858212913796007815042307577819916471330343927320860008268513580", + "35642534365283367734811619085134495494256557983620635535244117592649883298933", + "11445891272584789013424104040141502464728832906971185512210549435617988327661", + "19347288586302446717892927147851577742086726162208610071037518788257201150168", + "22665090428444192875956280970520816681433524110385751373398472257924251183683", + "11417316380754334831332830492597570808764406540636048363453859505773141965332", + "5301110673786948482997416850638853647631795186196055442009934071562115345556", + "4175705550000337763107256872160379256632157596494401478796514220878065427074", + "36661455264625042646712801277621892063359091201928994387767256803760104267775", + "42978754665578660750544369332494778828271964385384404451946611105540819034916", + "38166986562213712338003880848428327678516491418224299312181809861355134415797", + "38219126936293438460584909135726369564040877187367678917252919874341149473649", + "20316384044232050034600712839658388505507805729797447613057019955108937860535", + "15932894204526643964988396436918647148260636785041515887929268941901736388206", + "47392041392590525774546454854589628682575489822774629547850370260315991141129", + "15606079699186019506280954301469488805251338872712020346336398005298240117323", + "20299380207162822359422086934443477548953580695949316559706337300030385576474", + "10854972910630534469819183973296175566996120206961569840261888270405710067234", + "51513129918764361622039263720409984596265506329728547854317126777049190515999", + "18701610670569957483345452235975937173767190019788147533065822617887565338686", + "30469217678388964880245319564032031030666519000222216351800099308079349224751", + "50455808296680293972224794554040691705981162253936487640105156326454035184507", + "1416082007135839680442664653847139667925630318689714891095933294307791385670", + "15279001426269752502994974587798304995246034179678614988924243439331068736864", + "21243398332494814280756737337812594168100180784435938795943062263401863475707", + "40750806181179801282025363414662823471592696826966803566970471585533365767290", + "13754439623490587255475047284660167974073583587833928860417775734578019788221", + "43251061611216857746498968728560967792537941520705974357690500493261265807208", + "46944113325674658181508057472601314115636426543849317327996407324455140057748", + "19135576575837141802548195513163105830345030584720737695743249754810010539894", + "31021362925162252158568297988851577369348882735792006818805332600298886330222", + "48430961272096240705642389722760305662576333737357759258273159655194542656069", + "28241408726898285561012265228261291313236599242071212867933766988629402188228", + "15543796157338495799393278729602462159537664465827341368464987460234370014762", + "8892382779519222486377124088269159093381475873831021508122290689855805939082", + "13366108367210685231846175571300755594329934027012532918406984013542078094200", + "32804189201334093760050020921737157620639477746501453735126823495366696322336", + "22457072854339667006556600872166376570908126225885814617051477581338277738392", + "16900700339024785554274591135056324356562218968773675939720206908326471433672", + "43973268892601415963782765970413959172874524408554262260969477161041150574993", + "19556564224326182923374802547483935507806587914494475579193284459785830929677", + "5932171016473938955472056308338577712481964152088765201737097991410738864086", + "21323877223397655765356324684361133664748549189004228872733328427328575447413", + "28969209193088384105035868097832329328283203207472741250018227207018215088552", + "47160519201043534849803517392310230704914966402959168368773266879687754978478", + "13776067026764111855614134930431964518319203036655028082843461612064853869542", + "48958349032478080501086469042933087170812742880255494022076387654365657963189", + "37561124831952730515383663940986597268737003738918966269332482409873405636982", + "35632447402826828026544763717164471251084454220375670878083382369860283875303", + "13115554461471460905111224342870065738994101043165392666954102598096543303650", + "29414990444522701976386131701444018836010805039901454416772213582728046518682", + "27321516227256093530442310610112730791884784637612345219502110515834880470014", + "206130898316061106745713443346028086133872468024004111724539800872346456837", + "2345396547199144424899985406909939503451514119125862048937131184937202760756", + "47813181804839776840655565673638340296477661684543725383792495157820631626223", + "33090048249540114688706136052241766411168171501486163645666133844976261617749", + "50116232009834255216066490236313928781032979921754166857848063007231087793916", + "30533566357170545643915775608458953608706512990465569842995133732349792422413", + "42203129659730221560533100242103321743151318735888177086263787369205992900569", + "6022897161845206080263760135965012578497194777738703145049332895480685467459", + "16381092956853916077375462348804098240875621478477906414778220822455950768058", + "3276465384420952138554937872500474147977211160804950887460544163413011872711", + "14743377235047469406655645355725491911420068928168148075729501332767276142260", + "30220063216109332368021195710946139815892976853212165825496268772631888831667", + "27870859355758563296656561289683946296381008675832200423782081901546713901793", + "39188675974246629572087909174341062255581097730996158048225068120574483291967", + "3790081959676252060523331870350781440428634605088766464914544276731047039797", + "30368607887004257621354416640251560083956596274820249150303684368416522655890", + "15181263329227941855581666263934682372684851917506114493557529827290029763604", + "26723633402424058360013236061335988962167482384896461510859025265576881044720", + "35533769579746827006050699697490330203033134229881755534282795939699403989929", + "23405987031721014549758220021707750645456488011887214954338894313187234440933", + "30495118105929998608019567732232088950570647031863624206845795889645227369477", + "32578456638706007766200793756151495543388535467677498816605646419290269070598", + "26395751317424972875472246355980356628734062136427178158316515850181210289064", + "10216816565224037564516475397725672425335671230134256043507963800716869828028", + "36512375774227095444773204485688739570785599580554596789302096551961172632621", + "33291236309452026646789453288171302343952454640551503978322412206776562714832", + "12937628018686182296482563196394329083506027428512185132387542757857584089674", + "2589777786367956994162054167564143239470161072227924675478508904091488684847", + "45980382750587949549276837205768279793660728918306632086246915047558681620226", + "14536953698776086868495833998079251553700235257901674441912334938950895615835", + "43752317545680469728552433886352920514316913756112129905846800671809069891771", + "24496521022633264477190739682748820362265377947518870941723677572709509311838", + "4165997081162861656924125504508519872476570787567552373463863179716993862656", + "37342823627753205801212700283232972957565068889946333501210278546728578737253", + "23457191220877601864768823677000281947067539987705193541939328801572794711895", + "761194773736533055940557045309106443274536567732464279698175852222974460405", + "51782317364973859431407658454745804140209557623433468934759094741816752205355", + "17713987776105772734427648325078648614323236402318628800176237562424758503377", + "49564660684112918715601232894448914772799892629646407285271725786570867161685", + "9823197367236646101257611178875519396567528029705747252519278270939841054815", + "9945451425413930846838491802799528772228154696890320861945808672088111533738", + "48951391229365553269621259829968864275808392529179972655583670479300093603912", + "4608298350949371812245927404590656051916590246706515570940715787009838310766", + "40213570757461159286473499971968511232873340594505939237277273913466576934484", + "49464328658588766009742177487131191314631221891982550604690174771393311814162", + "20955222054384514791751280195465986172794033211785766089008034503372963416739", + "51160622941518684595781598187837663016844986154918331915815402814939571767715", + "46116627482198547326910718858491452012583160561539310819111537256067901414438", + "4418378521395367085888927324999657463429241686869740301423442701629323225481", + "45469504385244682835030295604850590616852978982481961894636819163657780649027", + "25328594363297337336476957773532358458201809117973394212586299093165674754368", + "26795966414551576503530887853033430289819596098103339435611767766540067296854", + "6582052756317751065090309506894088872677330663458229357161738149250529758399", + "22862971026037168339406506500191162299777415782451770674012207183556893861540", + "23792209878009644257188430442053511290566151487671367395559478472899824962241", + "1932046670949565917768490692075194725378622692844117068655316195904849878017", + "41257345196869997690508724315845990304232314012333413079461416763003434427826", + "10035057767738334566297286198069856277354290168611661194372030289174263208212", + "21375223486053129976370645536555873906194776843516312615694940867021862890220", + "17827559671376871652127140707459455087086419747889040245575619879605424443671", + "21582235186360824866647168991762686132057332598993130657424470393525957480685", + "11304533079624168487113280933242519108177487391526031264575238780232075122356", + "18093350715565747772491421735170178419554118034890882333737313680353336923572", + "51834785089037828931789718970344121100239390747498886195731541679821722985383", + "51856612830800184909394539401694296534423723848153826487758359329955958370603", + "14458449327463567065866784741152434174142323385524918970128961652210064392282", + "44749774152179152552579837577785689448942886014499023916671491996495571778840", + "21734289155553570540662099680184264883664222201278619062043661209425184923713", + "36482248125194216141722898518569965475608245219787666481964510963111021147099", + "3739228500323021573061154445747103742690426441889230104634017569447440841226", + "24090758472741765812291245938039399083950569365264818450013642264397985446779", + "34269758081173132526197341133714229432924221059711884541598370390969204439400", + "35012369293881871433416952184029552540246017816977236496666019635820996222895", + "29977567084985193911022405532759791281729861103876323533513042558719696465103", + "6750925537124693097481270203540553582778073524626561696377813566973006777231", + "33502463611986919650669997453432531640494215487182226999063692676281180568682", + "39142784897384736713365682668844462435111328038377646108964921378925875458362", + "36575741028691005127339501261660785092379628461180351269196109481523165156492", + "19036330933762013656182232810065780942792864674952026495562196066288063727672", + "32290859531463258430354304643890098463933293138193164734812396567948023957922", + "10961638348378394526720164016793890434309196024697663768120393402477875092295", + "37481723671888041227278793682924658494658185833714977190471504010133107644294", + "48890010654029134203327816820317409947666172685004218426560541957418389221280", + "21216020003003748067423267818064195237663760819863408629108574812197969185210", + "2451777332538879547335374613305801342741899303524477021550777020445838764641", + "29592328175766755181614234456428854890836466175415449915547618234697711944144", + "5827954886466818899078747199028579276668849886346166172539764410802532975490", + "30835075854910127707285137034940386895837810156241642846615678576570347121610", + "5423321984017589918115073237328399096789685418440150879078026262994033033280", + "51966820986139015765549600647649773115148110278730421637400629133527270136902", + "37733992939183833882058302612944400349917336515311862658169122569891972349233", + "31558522571668940621261801184763455884996380572172355171979646659268771023343", + "43557040331536555781914573163218969046613201833331732594750003786110561210095", + "5179930165954625889068887197506214244840704977659707683238889034606443062484", + "28809263087355800886649442196988570687178413422711169828928444699449009121412", + "5391496490732793598704541067334740002957989289459279955492265654767296420056", + "26927125703691961374455280469463071553764104897090441924586784636039141258144", + "39147742725053050296532211401434737507684832956699112068551438320434607121823", + "51006149871063183019239103252857424446445432793021988309300211609289430207190", + "13918090488051486718524486307059313768645834702081537101056620786686502431260", + "35529768530851218691499793340076398490372452029712138502731591311138870205100", + "51619175349984599618701634259831043573050615445740749100149283718516410993520", + "27716914265287039268153190124109441548147197813502101571849674215830406856093", + "2293393146179656030196083916774668921335621212091613295962439790630545603059", + "23218917234879230538093630702352048194549618954582672240745663962501820508812", + "38252297180727587193399512343958426343107152579434911039851902900434953557349", + "41162617524677571617292615494619733249881280266827839896116797700574171254422", + "49539990125027280258518152743225644805186998973883553644309798390985842981565", + "11467570514586924557054706022094853094611064374350533158738501841534919952884", + "51092377960338537220888967779739597669043999194642867163184689581473979552530", + "22284001093570225238450400534516134393917994444094546625248269445431038903661", + "10236823699897457062435093068199936176461918773204316764289496219255649202755", + "30340246239618587843707202735650875045657453070463935033028491237807153623667", + "42462821093059055960231633319147983886141924466580150744529628105889188574710", + "27864356429743198633757978036962441752443391795613860881205968196798425067932", + "20594707181601802330285793719176571666140177157177064926328768531580880899582", + "52362407133048063274584611972792634924917407246434384870452389526910832098313", + "14681105599312127700368894872573678134464665513298312866617531806051609151904", + "7831139964766002041536232492614317764244049048520792361886648935554407533777", + "38429815948693959244717960195785150369115980094650760095280476817705953038684", + "31902724695925546122943032209514806124874609512826514544136021427955495891878", + "5825472455264305158948991458117093215056275851781376856271170250888150298365", + "8766086543376028467003458770217664606982137381843920855523024926999629762084", + "45475899633985926541571273905099250005272158979206171178842169782668943754792", + "35551333962120392071903565777165683149356388697561119184181226501997931982882", + "16239486424390473959228081342912121967759350343136945740329632410951726106158", + "11950525756965426346270476807429865111854374732685314332788942250480781153701", + "50236942041913091267573098117096335245070889056554400337941748606508700013596", + "46360922016249166507092958086855301972464643717689385222892356370123272352380", + "41092525318955039680616246299841200911441158668726171846468566607410223722676", + "20661967302311884656277932915773712735374137092545668197004528720962993911529", + "52402313129682522309079053773798550722724945806370579608733310383295234257656", + "16827762038094966263092603171527826039051278381247020213124733777023979247396", + "48421038189015261590766670886697304210036766701556138273154918171295982205103", + "20503580898950921169490574286286567448743086730989055295751302587962348865199", + "32159384054320732396959505369612764934058307055216196186446019869642887981609", + "48628409232815840695539355840944094593258031740613297645802564888526274216281", + "13099648510184385465612278688951019553515228430634753421520041538331441864868", + "20402230257779854578758642513110683521707099169131976078982098624460379907200", + "4092049571094635598338041949900539066583921964848679957217060446926235975493", + "42469905011594552271720151507258695196657600715391058483900550310654676348109", + "8655755681604862207428381611195532962441107206702774840139814667299138812116", + "2647304623247942486871723402247280559009518475627403372195156649197046459348", + "31737393464961113471354808093295024686357270105710924994779915545494385992162", + "17849619282726284553632391516303485460963432802025858611162494767347780826808", + "10338578311874411347883870095305706665728280864891245888572052926908766448160", + "18344075222834662420949422105596781141946312741751497992342491389030562646372", + "913161742425198107114311324625350389342392686983231988501772849826338109791", + "45393666010372868059286681869601032565670390580803986746896630958288797242390", + "25615724541068622184083174220586231886092649578462232411616234564425893142963", + "9760564341613858811630074964499269465660074187601590875917549671808735339389", + "38588801668771106353393637010704284261366863104474918664381003405616992720971", + "37507277997257584970208057598168674143402816470493470489313633177595443008174", + "15486753599837263911880735487521659727169638009474219813079356306769005051433", + "12284756211809991331767888557803251708404354372738390779796096356846973807841", + "48382117849035441354070466469359812343976911559342993623344505006184188564062", + "21196053003647150001593251481773929342081802376481520060493561376453170164111", + "15724132954129249239256181255654998176740679872213365165795616156526059320524", + "14609364517336174183437836500612745644017909780297239569870784648623501810464", + "3663541885813977819188946858472367593784660784302813658611033140391524295952", + "24876206087753705447290837323230202517204722505376291683479592707551009291511", + "14688458211386376729699346479829602323761235504379603742104313381453293794092", + "50739213036602921134158533221082082940105572646293950884653754899805742012127", + "24257544634284070226622941757238957283906215022181657704549949474916599780744", + "49985806694954677888614084401782857559271431347941730168934942656412924723443", + "2044077336769536035548641136542534728124596742736828430565871038420595322978", + "721632064342632009855277553994385826434857087480620448372304155093508705423", + "48978423695058189619449109865849964667848229402918635559316132298622760066886", + "20068101419700776454790044965861361255596401059901365748448949053742782194665", + "423055067960553876164059799675910783455050081933801692769336724002987090376", + "43246261936097827232017440170290804998931018306930521842511323428740653372", + "41311615071398265227631797247697296582107041997739366031994011006232566972874", + "12906749578056142514839430057122637171193903063580572137539991979518176127529", + "24941456580266763298265078862955973091347754797812815147959593410350198268028", + "28366523335156466321031184909549515332567252704309501106673808311273890704111", + "15504459590248066869517322313145899466314113129075725878062672566745925019474", + "38039571682042186072107817115441103324802826357119268022703452488029751646776", + "21017269425752942954858801485157581446835058673930780679414886547195819633497", + "1973786970448241188773458714298782487740438980861317065471604185506620612041", + "16357835656137980752919050609079088442251581318976832591182010869724782789107", + "5206453305902156917697513273916074974388829392743349144823637419620006214650", + "44438765451384422882511397209419311638146373267473149572278526662866776000311", + "5420173856062589064879135899422560672264286563683086279556789783188544225281", + "18529602703450947465986326600746373685786201079149304165457649013167681751214", + "17891016115944406520924407273107069160990653992782779915889054505239045809280", + "9827398732518332622616196054594554859086018835916894277717759162736172421353", + "22574357580632800417892660455946122090106877671496344229691487026157909280765", + "41707195966835237957060334143049192440666432209382509664458816285687669488917", + "48681171704042119363823796305088365465582429814359843440236468237560167660784", + "25080528971939482733483535946932399614422650840905230711736442915132106973069", + "33365089521587482811974796841063442655092985173983579520915787752357017941337", + "8816868109327852090210380645657124038267096497965046044341221261521354271652", + "7048734207874884659736583984755950232474067735348357995916594859799406883580", + "10091209250818584271392864164551814622851037835248924991678162019136212255331", + "241770374426577334470523633825306929976742265188587856835996869410796045073", + "2662718971079154131507226985736198532282646217926191562456919250090467335818", + "46488501952703675183808708816358914869827593097427152248527230290984331174237", + "15178512463261888895153058344930917295417216623890221384528451666827690184597", + "5139045019023765029119005280941384046265752223626021641300567445054820746527", + "42419274746327589160285117747580105093857189016642408067011283615056852369610", + "46520895557204796217929646629716802803002772573592900059947873474033492662288", + "2194389461326783469597065914715733958144645944445337868259542547171338482076", + "21279720992298632313179921035939271853536005330579310972236375070025127053502", + "40960601108977739575185884574742182448058295447131431560228706324988125701380", + "39792751459265338500938317367903131126107649284390258036213372211660155849081", + "13880749868630038571517086877866736117455231569279766822895552353627793896891", + "50094841028258832863927132153749722083471658673288716966413087561174137840943", + "43118294959556937158015194293383223758760113313691693128568478209115082430832", + "22741999656883443850169952751287239356201544218343851831764014230122901661740", + "23303936332543414677647508062354158485890284990606645976790217734113299124244", + "1110651669671363098283155533410537529097485183332110170335528003713277591015", + "44254871389608557940276819620305686095864370836945211387419752593381134574072", + "2850365773098030107251647601215773227131429220355254464117621618784367691871", + "6393653295143442729069978460193248946214851856967562516864207245360781085", + "45996806199045225809724932154504883505331920854660613740711747355377154928480", + "19644407184101168787680508681092446204358194611957800527715993587176467427586", + "606444201171303575726752696708017784547897759829688320774935316117292673779", + "18937676268172040584045726121445050981391226598688793929015018266740804411462", + "23005838223474008998615579053326161962392891953698370921745515251370574041167", + "44349582300387085756018447304139556415931953954766347764094106774232162328157", + "2583836591759982626239885985043408687095125747642791229558307783975987651995", + "18673531539528412976538305952836168159418489209095384855586030347297768816476", + "22870065573307246509639798086099984729695379168892968922525974100055658188466", + "14383415181394923695292734914112713859357968855938025191075261726661252480271", + "34227516085058793262255098125504863152633079692099425051829529636818726711040", + "43618414156959118887271233476003031202426430877608922169880915643644417753392", + "18674109855923967390670350198100017456427309233282826898108969619440650213796", + "42793471850481057521058107300636418867808077593734173781163505556515563732117", + "21155265773024949360921259188050963433189387803169373612786336314662188295985", + "29851803333200263042129662706297306040124608170150776250570571381863685220585", + "49721938184345973344243640638352507329622030556195384158107877825453047290938", + "17072663912486098699733602009772355527541470359512154119309375499194482443565", + "33991280956705891754132589582082536070363083576367117199614434216860582856249", + "7521658563092951196487039531094520221138154570808472890954932540688619578837", + "45563582109420625393518926656075423180629474465621929061293437889854383822872", + "20252804164805785961002391167232560340275654378830426733175546196959635591400", + "14149101801214935819009918891070863283228566144336345947638590851984923556621", + "20215393961730649664744154205776170840490721400566421016832277532587829874509", + "34461005214710902910378966540934397753038878590873589188673004659711247027027", + "17361932629884449158102061542872974632076756315638256750543314208234918353435", + "13502682661951695068446714060626445390748209195233210361217873804126949363363", + "1553066739216037960769239724326295150743725181530701147451759061465179585826", + "51412567162726912605971087872220668662754034798502851225690265169676124137361", + "37160819931042257555453347132867674172292597181754228502308468336116797825568", + "33030169651646824595901976172035056228823193100117546873858444971408691100197", + "24679327291722489678378890911432918595212229115903729982413210032219635716281", + "15366612053626515850366064542210391516442146415182650289082351370022421013345", + "7984851479244851770462086394887458633808056772227823149565830943684262021224", + "11296147042440045673468768540664982120143970960990556864021380430899564652146", + "40794554359012775941281158025810746738916294793196111134468864729934675222360", + "1091356311334245034308165531946246328620153314286745661748662227200824820519", + "29373890864613058055154821900069105682801948652906154970903906576260678251397", + "38489610290302104556930947707048437179026513267448289529543555787311603297101", + "7089020647479342437705002669395767540363836036391030216431019283699768610001", + "20735186827523308062382844862822478744855810796496607225225248211204104651112", + "8733317012274834755366058675549661370660604488254222146048665545651161027628", + "8864868163864563904085116340060534677773645915571862689293580100402311724713", + "36623870597402476032264932118577094864567070461367940692953760263656072841314", + "21325547881363339371570992447573420282034360823123841028417085458749291602023", + "37224812340838640536005373824538872863186464411763032858399977300917764537334", + "25136753341639736606177644392495341242059656733409212592818916073448200157468", + "52059240783909640549684107225240594271681910547768622956879071253417578572758", + "48518740695478175380507899372934183395325576704834719757643855490237289837181", + "40235164217204830691441907206847482450957433133042841432246059359359117290163", + "52186300804309828148237216117827799681965559673801148699661084049537146083416", + "7028913982926463627774069826104110659796590246980249700150666474128179403149", + "33072214076807902171935367978455636758725136176593130571681773945249589849637", + "25620387376686467690630002087883455295136097879667423203317538261359983580538", + "30252577677991810127394928644037555774213542816851868481243831419546754595901", + "3757519658086668243833821110348094784577568574577940428852435353728373192459", + "4839388450980616049790123244406754737808512944832378369438033876788253807859", + "41308065893797923707263406390234704640554073635766425437314873219845952278998", + "2458664463182372465668129601266207602297674561545934204393734866668758289227", + "40234088807580756763375947077746868320846120283022571092107092274724732668952", + "15901686630224904116598565965589359833960853808382698236308395981601795556546", + "11340582570496942484871073039097758915000527737155770814534070288975051621250", + "1757520518650604960991831162233479057285505618911239961428865814203819905665", + "51937127567480959837778420381088605416453915645942116661752901946303748068224", + "45619178307130047051566535076533854053244838002683578790520790902713216507083", + "26603707309492658213395884811414889449569281935147915189008168657723829132346", + "12223809262366868773592739001902400457037613706161941820924006699813812760887", + "36647146382932633542738540297856916853247104769280540265906000437738093087523", + "21855169514972519231314063512328480551277223759444486323008895406659174077553", + "49044184623865866053472514247655449462506923483310713908481654545774336445333", + "1878926920319854553078123393730940655923859552582062924227360083573272619695", + "34591057941903220895490298811808418436768688415909875787562936571361421245136", + "12658616000984528787089537156425039352271914939696330363008811286762178619284", + "31224096061517804618851369787242913733230541220817097785343348917736545599709", + "33228830829602240333285830030214393706158825858138401753182308996553692425488", + "26812476124924791737337127186488829000030371407234782036902830299310971379785", + "24629441339811945371793178785024545157830877928120693603375641896977275921682", + "1399170687699019941394054990470644791312994406778283594463930542936098492934", + "45364581466491741599441887056761141479812917296551532400521117477628604755787", + "50621687444618510075385574141912522278083943240294149454131936791482678270319", + "12681582134819865307973034133266488170857292387311385444969820000132271831731", + "23031596019138964255493167182924008100197854523848233268696480741709941934219", + "17412386682221621925784989577785142074975170768661265689040262265971329014432", + "38330983077157754996883021064193672505477110799530129138641109069039757426930", + "23224866005512136954470825753142173262609554245935222040776946997668835720430", + "9390599214779547553083819901717511730159571410945822116439592251341936100102", + "44918170003431715616935428948742604022277005607154393947083680481700004902673", + "1177280309523241830704667678463341414749161239076441670927614156208534304068", + "40522155823782964105074501792572768940075484698015666747924235087098364496703", + "46680830202459003485037246695223305593694126793463530398206996270236964640564", + "12960161381681368949825302075129524046598133307521179406404730682669981959241", + "30552679583266627041689152121211676985692287494326192162406692721466134765135", + "47110989029871756053905953923689915084650228409982581020996248021364311963501", + "52416326326712662314070629436158883809294808911998108085767774734459361349523", + "46778548902259835324051583836250279253147545365711625404105786781853529104355", + "24644527062133875219992711391366293374802353999982628061678812716725345728478", + "2600582783177139334756678704026520173855951477050341150864632567698783426197", + "11108398195621494893420716429381410381492457765274598350162292674592994289158", + "33449726608159378590026654556894817289844645170426133051670099189836230381183", + "40720363717368914785338625391584274871176588053507352532235575510621206251035", + "27281411150079688525665554455990059858915213248665785547252752918760302925960", + "17165038720902784160859423803952099590042302399655697723302122987882353414306", + "12667523881415183921106255743455820833688098984263214122532592476888931095223", + "37080784979701581966195685985681975526517801784479360393340582661108736587516", + "51850024506203469642999445476383058545667919076156111530884580321291620348550", + "10665886572917058666145991975660727654333025102655332171186591227274169892625", + "17554557245228553378150842693702681479324200904338317878111118530931746227383", + "15936996769918674403075783880977940734717549693788000693683786932251004231621", + "35756017235757625450865964482987724997815546085671604164891960753154875929492", + "31879739955547551837957370952805752910082017638401508381948086367008966043216", + "43143458574808636775529925064630005408907707642610877603707348375130215679778", + "7441694310153858058473375656249950365520853202065990954483323998155652682803", + "41922530296376030510412708837832121873277743634454032952977065478857580048162", + "48491713577361238954084044160464671561692554536139920470988576911281864777469", + "48422319958113465606122112656668159396594927431015387058042127576945885128182", + "12093406660797902455603855462863544388196239414994997364205044808622913377504", + "42279082617999990508566527071946855139865967451754533932695267122102616945594", + "35062643888200194376590671693974753258605106108414953283501318740197790969540", + "19847141235093625946269552068427132736070355119773065101566404271661648693593", + "21248878941997053637872432124760202030599696445831005655237159894588112204696", + "40537875256259142431016417291376417839938355115769045102976138029858848053480", + "34422723410965207480235368296918487235783056694920006070130277360080911076684", + "46808796524249051580986462849224893711398007476258345912557816672119554140977", + "25915397494415622381058099933619545035744036067053547416365763824570901901860", + "17872775079787562821086636207641203489326808639339007347475905586962708539960", + "12298125971614572692868668604220252194670684724354071494569399699168825600668", + "8571411253307586187710386215566313875880515723533099489237584255689153998343", + "6400256027002166473744351599555107106392769724826788932292851732009712433863", + "44286802563489258460325812943087384871749957129751103043224951353117607068854", + "48266630745201966000050519782172605154867191892565974570894345350803648191004", + "1744032263303466979451206751534305831685870384856490651875590912902580263195", + "22447268779540564827369711490435619165002345870326231393682896273966256563659", + "15734921892731146393610413861264423071663208697234757302291500354614382901460", + "41110886301377620852713159068681772022910965426044409500441099542125354425734", + "32451185106329928692840832633131744541423313326107364630532796487835781943256", + "35834316942664780585237056989233184178138432332218890666314265477378808279753", + "40554108597312322624927383475770689681265239855769216131300026456279548621203", + "42950840047054647162179077782660999154271745995738659731128541691376098096648", + "42615532497275149289719268124177391496827833948106656053496459850320130198005", + "1710814868415433885753139383838652128597833518243874009983039400841828322272", + "24034093732487523929071531013590622601859604330556603875390192919088288154421", + "20182490138453002558017084540627544286758643760643843682235303769854935637148", + "36782932784395394383029609014975977604933461898853988216411513175834290294144", + "43014147722837878212750419914168141955542426415739323488041238707940697948388", + "29230479669142754563410268073521888300511142770854390092005046133814152036170", + "26677687034947416095948345381228362797083183054880534445708325332469465346151", + "9254296026126823713067751249723728022970366416753842196546732218312907725702", + "42211950002905303794413540375423357890942873774816726704866831884844869248076", + "26966259132932048936473246797600570975788718623565512720321183848797817059545", + "1594416984687614183718229702725435815684282469849370782899136040241249372445", + "44692845819426070153324944089224261898300005796580994307117834860386844625494", + "33097842347887731028159508660045875502737301260085757093771971269454877311909", + "2002825525188082695619305033897202713869351492425634759446260963680048780801", + "24035691011843844292007464407071597090103793898885012509568335421587047501715", + "50331501735995800226439789175904074980307966222923466350829621588738315516233", + "7901117102542932849571612337973908921420521109738143983226695946881445838879", + "30968398191988087908116242186542681038904172269373472260197002505442050019120", + "48836243607791822598589402188348576185291155602581473532538248722296141732148", + "18935920223327230292697980939973352228063185634817340264043300986572200305011", + "12973917133966106205974360619457870788746359520450078598604861684561583849311", + "5852950460836308112770524023465931211746773795701860272193537777557955966859", + "47737753373447091918179175753750436737393832924676105600373335839445450555714", + "48182857059865348486815559900189736216605242850309284403001552350297214953921", + "40134763981652032071303670174445512969855484274497090051336651949362876996794", + "15445184116781600693217348727281126729960140290235612177844721726863319756398", + "984789659549599753369214188818371135663758323177365797922426604524027899894", + "45681250652907940323118965236838783460413898181893961494791459348199758393524", + "28349154377723268931336434782757002455325372547729776278669685077011406811912", + "470195906255515855843909483561998375559421541823268848042287007393746296535", + "37504713976365720554594401392147519653816955998228523470581182996588270767910", + "9754795974763797261027334378448834158479876760102655721630598848212574583053", + "23901870492989516928513482065543434680044789484802986401082353142846736569480", + "47980194832608579987795499962263516338632441364741497406991178800829555787559", + "17794682190879202310566145369040523588726239019129262966902542067506854012372", + "23323249078165024789961418061893607952636602678512591193818071822693824989619", + "30312533724017623662742447216564539493460921638142351440197113489821072734820", + "35608856057585796955114324844553728808442861230598051158946450273623500030100", + "22818053155327072694723275494057663829085201284705094917283814303800742197565", + "22373375515268981419858446833025435674614917796202058173910286130108123907089", + "16679391198351351233791856714782298467225936954102562188457078216597446820733", + "34162488980983580320643858270298890169952461315049243417341295031776436673714", + "45227561589567494235664597910570715807239289652979424562985005070894361193880", + "1338301540819389583985940181453265990080306627516398444319287207966421719522", + "46241475054090395513051153475598803422894530893925089868079543394084681902468", + "44797383250550141935194021046754642358027690060281757225727085767980474196852", + "44232120251871682031847158741210769906366118536049400814484858478411639405358", + "44136112356926109891895026176791386756315721142203685801381059490077143155380", + "49038556335162934115499099615573149766476987644365198887698736314924888007544", + "39286839535661069906273373306811854217613863206815351371869598004584482252221", + "23625001205404071031377143220201404062070296955781368027096309820034994463055", + "9568441716717818078284631766342151030343488197680442237428521805603901597619", + "37408902803618952703850795055910291278882705023736193928428966803081848289320", + "13234313572588344202325744301892854322084618309449349077930740324977190068887", + "49215379497819073934405319954044551571377412728484073866431092602538840352873", + "42881638114838596494135354197122557154336712344720982177370151889929159585288", + "9801410522869728405285603344135386968748266847254332147524635130269310994890", + "40639781505240252854624088616787040181211292104012317340296712061103357749559", + "36646438660045344156562373807526051090078124774803519953313289610273447453621", + "48966925701900963792142305910435902143693283420110683099400521007455213573932", + "8780400984891078112812185098453465171735857834413895688562731307081100750798", + "28172596229791496268219417834760861357346026183545081655370568187494660347826", + "40688983934770990948815266259699217759635209470084041080140897736537473008501", + "14706021399407245492024324661075745785803340309040303422836685402628402132964", + "32476424728280408959457670061308058435458785562961412362517297764179559849139", + "48144770339849454146098753864900252807755549052436353888165667857918780931010", + "4436534687641875961520968176473100201132771210326143861696959254899552617820", + "46313614426887952165051364217798500272692288578115969563487778599155197968975", + "20040108823825616683154428771085664826660682310925992656449425753747926199431", + "43647253348327980441579172471167719903328244402019096983329756600329781932637", + "10905853776657162271345764862252579974164531349806143841448656664518822041853", + "10738800973800880326510064167396135524302980763924759056836481845035464539115", + "42988899647756081009546842890014584370553203675433733465340197326592562023122", + "32448490001357182278547413425601803679830517415475362833773737698385522281761", + "5673625043858783681977348916701527248596570558258979442454047194782395873396", + "51447731857341955105643801452947998725685333885614491387804156967660415577668", + "36174235959906698868625824610446689976993350443088805623182985077868789888058", + "43486230207118009197607869239772490249089108585233918309781861771160887306852", + "8028172759885787439499208845877204118520841716374771847851869867476275476526", + "37309361216592058199736850553157415637605900005676984232786693261358191245199", + "23466490552370404994340858812107789089406313281690232726015151261131916414931", + "12919433882988809433095553789087162438911404714701195713378891513974705023206", + "44028314666289304263187961884463732715403912883099939193142210246960524758689", + "27356260747435973874232369362467301003098280506324123705145293029198316912924", + "39860634445116086212874431936279248062886856282215980950212856400726993212796", + "20416224875376327332518909594755226759971139130487096900641696893926631286819", + "28824091311064468328038909906932999876669727793549112646379981728522168498314", + "27113679279569975992930132003629538744537371907835628087060577679825378314532", + "38746029596814181805661187977722388028774434201921089497249603417404846163780", + "49756034785120795509001613899526034050587728047202284481453300452089626727038", + "33239073709530412659337269066031662892287026024443037806759421783020395897635", + "20732579566391176954091629718630430577064453272617304752380799391604630795026", + "48571808734970807063397226334832184065930470309594657338829401154739477864210", + "19260488809435480599159433567891403890991004199984155098981596908120344883788", + "23020883110213236018529126216484789718107682336309516113105156923100204885628", + "32104750464765140560573167881042136042839786900575787053057438752664756951274", + "8886256188992543552747543522566863241178506319259914415340676380075042245908", + "39732262243501363471372630335900106766571858148547717158225386285220327400815", + "2780501664278902905230654716191116423981277710758270586439020585440944375896", + "20756039297016991017152564285982251029152264273806514610633944431743272148772", + "9933253247690267295914834610743269258823224675451044411180261845574989547180", + "33312558241894833342391179787247907043931777474749308889396566351510461262920", + "52393273943912027363864403350663199476961065555313291095118067325575839394615", + "43040837877043845560650942118147277791861275738687691030963818290807092491549", + "42887684244395728496015822245202929199392401294585769410805150900416189031527", + "31981030421151897376328952466088996315524781692072477185705736311941393990963", + "3927032478444916605947773404479846994975687149724641516411679917073629342812", + "11784290364194914777527554924276036925553965240529766335053994517540808790410", + "26598809491646695229136331531075113348111155526623276590666811237501309970228", + "50187779274542870827052304714904105749653457423270732384634731722333349730715", + "43650912532998123885662359602187030600627575432674920673083345864256986280369", + "38348774796306810974307570591601108965843632624932746077255960063272135842874", + "49782901952255851759890627822359101609138755201632016133461450626906417436456", + "41323767239087936477629729525838201559262027717906711358286156107010606932358", + "35524847025524687378887386435380395950846706351242714145601567634200844995662", + "15079290546427344335029581631932687566466013005326270823821105979180468924242", + "2007941871728484997068937305744494873805788851936118548532197658183797221045", + "46454817385417963666252882407685958973825553674352916265623684659271402055526", + "40694305211710389462830572466597997022173368138956982924809342229726162049302", + "42485191844988935552052617205468566242187905750961631163729636167925472910213", + "31856924832214890947502729954972405949038126503907554199520601886316224282069", + "7420586199845856515021703587558429192856642230086081187144124127145751501164", + "15561861588916693186747293191385994451400926217015742600880886809053264712916", + "23713469438289548582757218826220337449713190420158311915874504821568635702728", + "16482449582481651761004343362076223016647776236099159446689084278841379758490", + "21152664974124064251234597848963370487009025448690722862827637850787629684276", + "16783850002242418845060503671853174403816556574512689796674639334254886843629", + "35050187941954042373531332915452578207396904154932100116048404156205552359814", + "27459959270031186623508711116249517438718503653909647408437918360638548791795", + "28632464440885555011257864070402323056105045958726452813304993171608754622705", + "33639493897174558976473674618182792336423934409822058681564085145055590771867", + "4885440278089132337651676334370938946984598140010556638992577167038447656749", + "23525914554017507315374748068532833865494770518434948304100790259957857621498", + "13457528910935531694141768705863546262155171545646937500184942505224785965205", + "23690029512753496329288640704545639413385868681825060977907588289676166056245", + "3831642117764209490444275003399951134610013415173991918911491379638505546192", + "38359039351941298190957325292784386032251276459173493794944926112481132123228", + "24832549514284218353701756952005327360507749156367582364111843551983525815459", + "28185479236375877358805979015149995255373519694314497792097843326194269760934", + "25447773138076708025984583086319021723620683932571994550479373779510360179833", + "9861721333150293010272610653054714269011269522723627145381650180811046208374", + "51524633990694226354162922884980595405867216810595946092342364649785140173932", + "27428344669051668685329809277340312861841153682953801844245069211167319326409", + "36466823615444349556817131666134794695203770662489876686248361730543334002305", + "37343942990676309839993610344037872993796100055169522472765027688531943506812", + "35696097521472628962184610077419262675856646324561734083250085772599749376486", + "7875824568579607329914497804128980467344512356261438190821346887871009579077", + "4669016081375054057712324338480726222894509241016315035766343736469610390037", + "24830356724268527010115329596469670934581584464481438265743097563407668817458", + "24058585132560228981277322721245874466390023910295835177737743387054883655615", + "38431760804275116627834843959262225464619314119393669707422894197625230150272", + "39565950182181330134661881168765903878526949960247834711181279773343885880504", + "8303674887777076865676826570793573803542224720510410142099992706548937631719", + "17343099449381300670731207231559465364096203472709748641748322397580787722433", + "46624311801294183263339043191265029269655151497028289648376054867821775208339", + "4462192163817493198277800820011372857235631224231469626974207042693928551537", + "31501693007564138649398746443417750395312308990449485830729818424506423821616", + "8155826756227013240536087636298192208077588670684447076943438676868289469619", + "632320815097689301711618140272503429729250792849243845141019278627922507787", + "28646551105856976900928270631694241296887713783179437821251722123826022368464", + "7006139857159496452073890378475921514231132751765643462106818534540232780164", + "1648610018143580802197947870018056214617082678143831709454493278443044165361", + "5907335830301011514937426476327584559452536621866999336981617662652725986011", + "50087598735524645178224431386630649723805236863625073697396036837904519248528", + "47581125018089101288831772849805461106110591284119428654290677536196096105939", + "21616357208789057450536801732968094792483733863604279287374520668249034058392", + "36829675247356246059892899658678574459417559685994330081924280927123077683113", + "48484326101816562600305380885996324978144009492499505774027517154978969252642", + "3444495571956056793793812883019016799515226686584884312358122643543529905014", + "37256713742989222543321296274775949041732192452272071390536733765516117583682", + "7720832181326653109452107856181782771779209026437652560977529564435463729678", + "26496582312130779204654169823656934699716580559826277630969089008214600082231", + "36741677792872271111058798884247340711690342632923450633998858479263906362400", + "32300377315876473624775295788017200940751031169615775766245080001521370769590", + "15721780188047243125891679700931793810761564623180681709434322427803234237752", + "23511976900219242182866030204728353776903804968342309044785508664971587962936", + "27393782823911907744270781256679328616661555505344782478841766905482892186971", + "23137694070769032357993428956376864344612712398546438610377732743670572479506", + "17854157797978461706973834126293397742594905126945546629854988548307449644471", + "5964395438788200744652063364602982127799401146668877383021667566670462197564", + "12159717451567895123409935281769280581231701710557126051536953466785552531425", + "36788466332287228962415448994214714959363738279120193785486695927045201772927", + "3429164320954174381063838780559832987988688599749228236840272468082964166738", + "13441436824433284293456693001228750361624155161156102298199244595961260831870", + "36362380593759813368290779730981174418081335130075065247139554763700377305549", + "10808396064986580204813987623270159181369133241263853827094703998685087385274", + "26229362560331450863376826756455322184672819479574001401676333791041129771583", + "19014218469810245175603478999554936366646882054800270201327733725833464174595", + "14755530810496216648786288798677187275637429775673738433023388251938399228953", + "28681473873089664292826422673882522844075037526013951862698870421215607907264", + "50064213290146784871023067547637305227705463058349075129850465354038089724514", + "35318923658859191450561411654047534202193828838969935150046998345046009041987", + "4046648733983148841771884260197324786507727843454958121611719528761704491076", + "21674241769383770903783584426147199728284955236049899706492184067744698924313", + "39793035792715103513459306950751136623771608571611536416379429855867582565060", + "20195170620669059379840039021256213540931635177461368072045442119849346355050", + "4321684944587990667660627286305049684568526290946399514509707693633402517309", + "37540225316407523768240189063512452067287834765288892674352480683879720673748", + "22852145131827680740147546784932343867843921797340250815131695011260620296292", + "17670489879942451113396153284395230478441551400427810106069392038092346157151", + "915493698749566992979097321213008936858206754595484902681584765528946791581", + "26030524096410987959550774953401491136909672319342494800819277192873573224957", + "29001309423497180033846934016542813180551096850842387228883265380596110120418", + "15725666786458638169849565403288602355542116485709124608604561674452394390933", + "39003686452109571799174609813603195828546982501970982241316123133158291628792", + "37797406295003460704036245663175020392799162491899375360617076529770068146840", + "50854232439933556232583596285669698722589086959029239111421869911247262109571", + "31486325291931115897453234755589021528766070811942590488426228291991440769192", + "45749865384120946216507858868042916436068959515874163307946472994501864162660", + "15514445401329313948113639352537551321985494651390516443718924995182703098072", + "18938818699861426378311917370348864612907241739765639697934193200168748740464", + "8908576033246626651824218789062451142189176687664341449305955443602477082457", + "12542611472292536280117958126768313188784208367075503069742949067143025449273", + "18894820473905826667746029299527872670696615775625178972038937190525786881823", + "42166388093602138018029464424315158763102547575437962824182880622306946270723", + "18356359822205905796431915202311038787557753393734478659802378293083930419097", + "26440277672031529611459463711271637696691656704894608665230862618318230903431", + "43936207899030709849822195130624221035934306359119661743363594211023582166717", + "17720573641284252833204661334848180929095269262020126070694240711328848455070", + "36468747890097203355206550200538689278042421185140314772418908944572956238411", + "19495181063369994645397912761202762932569421139600815368199932700252142128872", + "34321594734880408097523727884105368445531818247395656249730906694117722526466", + "32408805171794506957896128185525988991901673722793140235755970873963573911878", + "31741282997448292304421964169259883353374271041953059908247402623724516352630", + "42077598011806863050128261951283931355636582619670842135492393310254798128661", + "13278543315703992591639339349318947394701272332553942787652021146529286188157", + "1719958543304033820592305522731575525566950070053706873705044924016870646944", + "46150393972923812422352916521314141993447086175533626595925453949574874875227", + "4361769779931624603370686463798012624193058416356992556634074353621507632314", + "44908902066251652747772614075548484282058382016762478707111457317451375285793", + "14184826188658774116422178227458852482711356204874646198284587334854728286015", + "11290077559292661273504651056669682572106362363699422959803976787627087739893", + "9140666748106183332717582211664519784828584147544256315192597464376984585188", + "26643033985152469944109339784207220223128930422319517298943254653983902079668", + "14509636648059013877434971879754946183523815930063529066940992198915113411367", + "13192447520690180316495756932660240053091486324623602126198855400805062925914", + "28553403212026811679770698418745568241743719747387268804461615245437909914149", + "25299284408788081509607589208192334401876781871273958126995757831826028649950", + "28530356329452348945644723750928393135241826904433041893244641057644015458544", + "1846997376603609268217580498665258023165504119308436419662877027055171171731", + "11653183421530463335868732155473197248100725614188615570171427750330794131094", + "46147037286332155392405210293641506288981449079035306988047896625700181842824", + "46358224854027770938623440286820083861533657066850480061674022450890991121716", + "25192903670805445599467182467261744888209095302907950091555035197561411230825", + "51684353815079277888563937669954224588335611310988585760041198126172291946824", + "40212331439739985558638525054360509540078769263361669790219771366021697673779", + "49796664108777150844232863107249949334102936992511526241235048676855724782189", + "10242345153206530342304883267767078633594489183632785138836766560422608537969", + "29004424620282598407757893831714199479622671405715280516381675902425138014942", + "10255486193246114372571104126579187184109630904061984833948998386574631086752", + "16685917015406855468818955637964332022681212804979215923930898988219456450543", + "24434021992532544122460160402671212730644681945493433593770849625382427794439", + "18292160261857345379460502558549406603577667034431997089869033113662570096725", + "35772862663366056149598060354812588653957774142430977776045747532926387483197", + "35370081528466736400287886517574631193501339737717508377193320181057425645950", + "18992571108223291133753026834739359238315380829900318312609273409612846810896", + "40362502531700390468819707277338962907385983765785714179599208492190921372025", + "23667117991216471932334148869369437155387682381717567756524943344220296458353", + "21238676533420937895707358721362073507024717338461698155664714157753820922607", + "37517524762432886814713390400879585522723538184443175420767248591887083030260", + "21945914533028823920819117938539359291695585427129232967208167753856350744027", + "8384495581233131759155259695328270034054460753977281701003701423762489603477", + "40617018205138397085412217268761615509716847602311557631111751863980053872873", + "29205082094912566997389748849425515812849789294082534360690339009391570855864", + "27230149176495637901175639106944004333840368200381446921849372681636130107002", + "27365759266060646481536654599152650624723857111906934036173877037399059649729", + "35406111523585512054034138221920166146042731387746679886922878489864383938714", + "32774883717399381687757482255404090979579486286057825405272837964830307189747", + "13170416247409001999396914414377108100761474942917629122386954055533375280602", + "47089401087784446858337787168403074309898471771828782350587065287935033442649", + "37489865966069420701116385680985576591946263271019950872954847120485859866182", + "8632410675954390876358086639615993296684221517501234428619901790711437545676", + "32885513335528965891460128903637689912707292965395965701230284253801939095288", + "3865622551208242304975184319838876537667895751870084131280275044394363356871", + "32642956263031664532698514128023439117352747373200998294309308872829736375854", + "40084300443726825474116139474586161768249842441105109985254077470761942925976", + "13575035647115287708378246174661399442735742506844869922741573471380610846253", + "46154962057875267543948087764385335777228979509028809095852537407717076987256", + "35086599876786323495402488467917205122834534608854496441019108702752108240985", + "46889898355485673792007394499032585866097162739455803970110008615737131347278", + "34441300416665498228606851438796612043569828927484901100307586180938535414605", + "46539119526978313274295303765842782099143120413561238646711646741911654671841", + "30175957079120113188074125074039839413301110804986571208327982605692725549132", + "8966760344895115939872117259956938057113187197867594647177818940543418414335", + "24843999425749485253385228797176224463723611999805244434265174981356612639146", + "9473328202759301877737137589842485194588027404257756455728538969687548450516", + "13573812071035688949493529454074175204289092809209822052056492726089543728108", + "46908934760591728558277188582482218769654379044959859361194832535727197214605", + "13930487528963939578570126810273646483591374780297266197346613985275608470586", + "40803858207257116823977243598481385428429858940423615937056292030910762136178", + "39162486428605606030181788649215653373551532060914475973456290331055500258775", + "35449178862900256506814668735709087039690105072094040109555532699902051796098", + "3195904309253823366898274166209405187129747041593163047743093848114234332268", + "22100622276110240522875971709633125545413316465373588685009818470536030395532", + "13287987855066954189309750913761626232970004781032511431642938463869940737777", + "12567168949307351662103354182150292498970124002251962277486555667288769328042", + "32779004608575656731569431255402737928720189660823475846982606916917898535767", + "4482199135958605427663553800295530336366129688136181786295675169982647835199", + "25746427563626230289661908855847413166800055617361501505936554303817926274945", + "3673867327210125191043312359112986293209766537418778586102884361685134399611", + "26702420945696319869216393496591518144980013524906896191405168870185967727854", + "24894712629093310812492638033956160014471415666571729992427926632928259668533", + "35084154604432695842176224702383681151077882630302483714918387510618510957648", + "36468488224516960030665577096769293206427170413589748869173486685788278698839", + "32558816960868760640276972658593008232425611329139091284007891283258193415951", + "36972007350342209468361945157882520344065366159482086470133075516198180749954", + "44453346959413275725546715337367414720283153251752797267742592512078066548117", + "9315998642762164550465143547300167078903418457425403391745676538370479218171", + "15294339943189168967585922476367552749833180626317990775718049011734138801820", + "19135545837730799481368362797651049436840471260922818267515070203298088377920", + "10541224659644463657071395972972658655022748181255236105583498458313866845335", + "20121616767939407515339703216234195803287798983222412787301309276027281591928", + "9186255242504224162001899231801416756248939936071485796980837799616824053999", + "22984104413990497791383559340857556601208897112969697436986303232004851942743", + "1097605926114561105481064922642891985429250708987010424265005206202058400479", + "24568950690225041115140415646317627700249701393251346295687622090955017648570", + "2496623376180515142183585387078159240643861407286756287425929471518980970198", + "36749584298928712271636221076233655787117180340545270846482787107095780688330", + "22009052941812978814202527253059634831658147004310631163378918280938698404480", + "5429974825297736436882133749619225985516554622013781139750177423571746307886", + "21844039850779764562596076140933788068005086283465043333864950350317661428360", + "7382098549143627245992371010759495009411304322851525271875160939196538290662", + "39325420019957119255601642066957694999516292283723915014413214517079996786670", + "10214862436229257463932478796990841631972995700995154661569613058340971097393", + "11841954594311801649003781972009983731063293296462085646952344913639398736104", + "49803786087962599783885640102405776531163183805028434757227838013568606473623", + "6470577111433312958130987278039865184296817767481810618881429410085478821813", + "4678381423387349776954415265415955877139795934075069883709082087866232563206", + "13167303739520288260642004911942188492384246241564282603804519154293465178034", + "41605450404075278045106946197403380094708484834509671447831651724975888268486", + "30898888341682553708372744026907567593827286487018590802769949135868396638743", + "35870205331609468665172804558808684713382697758942464309307496588877819535802", + "22337338512275203759606200777648725810675039681330339088043466914768783248381", + "49208166368750087662956273668587338477209577244012381074819493453794860615006", + "44792249472562972459061613888433234514174635002526579460827485029301277613597", + "13663460714525961788726496004970288062553159944787876138655660855881889221826", + "14061624235680471529213319576740633593133279648094414169119853800677722928342", + "44183479088810607229481067800621525686365317614522231996420583030037913451624", + "14987379549396346382639357739796493954636560654291390975672707230701595345957", + "30761472744732625422037875359130325793208473393506579840694386698791063949438", + "27064202254346432506847196952348941444475631786722969208616763527736925706827", + "27474828800999580230013344798000768971974599085004769050535846817186812572097", + "6553111582844895693759087141414192099864981132999925154210381350402755647570", + "36210739370437465463730383543941058078339947762840168774306761711901993197641", + "46797146780644435735958539906751687571875298894548487285061502807842853731246", + "45545957001844128159596883204740907705367429740427982939228003082907715541600", + "12425813554032361425229480812195852682279962903246107320546395735336466470101", + "41822482747106121574561387737820756611620639955419432033563467380014664933547", + "36416928723161115578448174235560774983094306625101268476566373830775675691632", + "45989469764156163628514923201303246060260001295057033142087824020663603768939", + "45934294102598282664979829832153612625530334024753870566098639614421671884295", + "51489583948396519592470708418279079213682515067094483126313633824081452504973", + "34083050828186743468338598731932341472678769054821450687800828349111961422082", + "26136345141385373420029701324103563246467906640289343413660351338216849775019", + "1453870995092002727716667041576504305496790852098619490246399225800268420925", + "29360939934550778054558547599665598751850044869530830540916411790821431920914", + "49257988709246321500540832688063626224740989657424656533680629569812946897717", + "49394094490056242544292416011047789952918804530867913967658951913037652216783", + "5447260155359438938135019295005821938328754524637330283630608897363351999658", + "24215836970412752562894632869533464509053586407295120961183099229588670474153", + "51506521030605148144814140601124451831069079838574903889883537192854407362805", + "9872735055238501890644956908243201635494917783827005461172440072528529374582", + "16678248878524040828746213983040323100005249685499128443224633896280988223130", + "39594222856440764478608913997647723260344813941449448240808165949823550510080", + "49133623392324077392240164767468427857994505499851418580041502565161313381733", + "8192508034785054819754809978768844877470554592953862231564471035898163011015", + "25713232287725851186900169506501884915493457436695103626655554189456838734824", + "28152117667891668016797783216051767700159359927467579277427916114355659259445", + "5323010978043226879236847548176982003826771995208965110053231719197097875239", + "16553741945237444412740487327462618159797410992080219994432790366781935598735", + "37377883329217946130789369211816223557965350856275560520006370554358920876572", + "18981514108437667061446986122382985407748056999893189077471099489315458101851", + "27725926785534214594109433131941162730768551407184096047366530655900074583730", + "6109319505914771388566939253976844699496557414166418517927539577420270664317", + "32543330178476084640625591248871985870684691133369529355615526358394663436895", + "23812202462203812914825900447860166948369376805586166292136310332258861626161", + "18851505661682934375333420208724156232744652042747784060238778871838129648910", + "17620647952813540745343045174626101129793012720110982408908917018908104635931", + "23105557911246646271518935827409242334127659580461627787190498766440670307259", + "48018877292231383414212121096563443869985540001440935221816579566459687134866", + "13800758800989982415720299176070354402784511702354054121121373788959980332285", + "21598620742451417964753713233833085356346314329282271974036798670030875838726", + "3769888792763025957714446092591937448931536267101221115753807457449686271689", + "12216062808319681877766341538184602560553649874038644985058462251587081145176", + "23592208179858071123479786697644283133585159183224809304342461518885174773377", + "89243960630161121881321076034383277162202470744223177002547262355759527947", + "39946356160646463674635315938241979336854171301366920217893025935782767372004", + "19283377026196874896179360370956592837590605067104491375294600592509242617545", + "31840996965954876534585181016450424052941284109619244367639868865093813070063", + "22904193798229538816377436901341063688973804085562822952630366418122197345149", + "13762672704723715915460033301343131995109727710374322076760700437332902828166", + "12305020288573672209463372257517900926484256401598952236259026450672871292154", + "7506827766069404450089316982653754961243673800811261275801952555062838338249", + "42825945890820325506407479653239869806600906991417629086566560575912518731204", + "32492058249590907809154469399704545319652648371613267394667261316578224003211", + "13148130782161993383754179033264293808277407881733654796366538392033970866231", + "7030992495893991485537789173824345038150826296983413868543811118415594806472", + "16166811679434837376391390489455184055518552806728123279093380669024884293715", + "8389679740997242212987629739784169942738081925655012759407958875613363948219", + "44618292933443506840040159509435046986221318816549731625369769355401404286820", + "17673355293313365693725047120125592030441264535038518345389166339516805437718", + "4804742518983114566705594031027019590989355015654016085597622311535627728207", + "683529238095899818801243467244219352335715129227253976114687382380665511578", + "20652391290895337831462080657415679428023245473157280558781542991720017597552", + "6828848521285234289024944846504474276579684242637165890530428213279929262234", + "41021066415255706456478315010118918742552975771400912467370140191632295540942", + "3332175631430231657903431867858538236140998812914163824437982604081209598844", + "42258359893785164335068695909247829688321170823517423501508910367086052257265", + "29987173266080400379405912478835742914006529895863932151517156417748493627066", + "6543195739466850183923388059754214317858034821611490348508327400616567616452", + "33711298165270720841570492624791005717832062516084579170323766407552720446676", + "12786943028853029532864486499398045201336568141345803607694048384169939428701", + "4147048494146279364011899300032812025948275204933833379895319326159539563031", + "13496435818163187894582837035244154181677700570668374199172253515464527151849", + "35841716328727069069001563960032654218661382248707235216811139920865293242135", + "36570076524893717512304843334784623467747827112962947358652390050025205492423", + "34167035431969545986361707451964992401596707960556604561400869897824561048851", + "49322901703931137081764999711876403363344801042357291309725463569222862848530", + "40420027560488992745352987550711357605154581267313747599686674503485672155270", + "9452910361572787444847277802828319388013674647071613298276345263507180387753", + "50233619820432542115200822579019203782527910279021796520684633898739596996838", + "35301977698126782484386727376733189676042582018240956798113258763470731542409", + "31576695523382631847513886958921540055277139781362783877881777474672315217882", + "14406679565757623899833604329279806408890698715038301042197857986498609598287", + "18043691118605959951167076871919262519309369223315617884538615188245978205325", + "19436891140197389768213215181759179078213905581607042868259293199050078178807", + "13166318973675012237199875352891497517028526828579418192106749762583724346401", + "41714120599390352402242216649283531885645954449615036554144572015209579895048", + "28503336515367362609387402101938939793667450055395076778877094216333082636149", + "34841225004125976730041466314664161963766032078646856400160767415818405114573", + "36181468768541006623413343709831136760923979238943729211279003520445698290479", + "27977157144418818250618847739152744443157300719564419784882822015847366756247", + "49421935977993287806327036582115808237419547607289847215557121662015160236988", + "31594230181297634430202494182459855349935694616703696998071852480074450786842", + "36724355529653808915342699066179157583916664011184296180770623708560237505768", + "36678267243468712577142537622462996035707722081336309467543162411449017409882", + "47976046898580066665880528866170225417644155453347276925876196038942457797961", + "1375681893045586601369566717695652300318584863174436538162397288514989445123", + "4645164562880717310297017984916730901505474472152564508499710898375604102704", + "24162621631566751587679116645378308023079689928585234048134785419321092629843", + "11600585631763378528448769557283533081172976875061805152398952678748289358359", + "43977040350747830564601957833508710574827431699259536360254229671286143305869", + "35570537602043402482941528445530406376041731340026556020234189514434202036000", + "46889001240750183267887759763151504339400790049476276641769577174759867102611", + "44081827650971190464649494017054670713992102069434984910134963983285688812513", + "36728486773765996715325931575050694258540071074654535613763015144784406908220", + "31616154836934549346909357919535198937649865594414320324804395402794138785052", + "46322941865263073090107958850850221366912017427480269394109313990510100240380", + "8110809774544050397450610496960757369587013442271874283363253413577667051946", + "26358027915867043994773710861281700676090704387354789619770725280151301029159", + "19238929699850091529202834454530731409435088443285980748272549009636694334579", + "51160775613706890989342179482215508972123218701371105770569451397502799017661", + "15258420503985870233372980150721695112117794797276907240969793468306046268936", + "19215443700379962136288916354568151635732290786821966079399322029810614221889", + "26996165224656953056593646212113634338961604174742483046658738989101880786829", + "52221035236759910837433309749776311655648061700759427111504142783667011891976", + "42277785797531953619496563961717389614905777166654008424897848379003789601927", + "3380824416223433472305058482119629947069358675033726305602070274224720128706", + "43083568289328945403375901366969762523958111820472201421115801083795914894552", + "51023890368139978952289176895766327124243536294530276268237971088494788639316", + "36261705930888378607562728167269562258119162112570602448603840683080665673248", + "13378336364412915813075051975067630504947410829123202899544058620511983012211", + "22122778721447787516062459027383979560885668521629318363917938488344895663772", + "27187396414927777454312049691512171879170118150841027031280541720114210162902", + "10674233864163723009194665325473716108944368352133788282642150860598161594149", + "40885156073557138865730452481104566922118301640445749745288708889302542937746", + "23591324748777110210317379830102368157444192920795764258520751714592359717057", + "48931275407992885780583431072868155940569260552660993402110500696132941805123", + "33932195917285524393802756508251840937638614380875948818736066802444366358733", + "32164626743420456575992638708475314585773186074502726194067491802517567965805", + "10150501646256959397704118219443897891628764972022266505424237541533116492464", + "36165156582519363510103057660722654502521108892556448048088453695974203065066", + "50991698813854384454376562661418950140632139146507304797550263143024135148863", + "51857353029433778233395228924474415800970705227914927371086534960806021729554", + "43555690014720450781333341520551000098761063847380411765568586323128316702228", + "13530316600787059687545920534154229782017707325696697729718563463790114541889", + "14059738073586070898476706698271087619552725954184765223154607877431854176623", + "52407514936929444680865631659294526279995452087685102189422632907375488691284", + "41027982473059748336701697997664091660980474388671203045393099752442688200570", + "37905209201153223866978084658230984570027493084453033736424326105278971852361", + "35181959696329527447604937634238659390455420868809045032104897742961615948595", + "449439688158152932202871332502728195073716157337252502623797881459432926847", + "47000247282135657765835576678191179751152030311674436519091017368335203044969", + "30931603416762260824076756053570219016507180616318865919029914184843102705701", + "23905261297341559721380073279483151203521821589127883024342749524702384610833", + "1122262247369623705292611451026085886330417442135158741589676992835634617494", + "11968299351190925981612011470995654474655210098964094817205313301927544091093", + "45976540638306806566318200948669755629350586481932728607830537688602614478208", + "45181940452178728664330684338441018168316009987530926581554109040819432487024", + "6593621332332855745887612823617716881098791168163034210986726452136184359820", + "39020931106802447501323359351950226229341237431283049229232071445859089663135", + "3846978054103138096677916519094045732254081525190915120531530167357090949380", + "48062487236593503337958984148696651000801374913559466170129045084888837092346", + "25146345914803332794975289420263202170320220260400997021275019526880813130847", + "11959561012651501573131979717228403494374101825030574114073403149075251761014", + "12172235660829384773896830428734663140626523697981054231477722402525860325360", + "48501111886303356844741910717229426182822355208283697520679002167629764163153", + "47668223199706158114328040432103646463483562639345773606949999059256519913303", + "48665416414466767056869357051217280013739691788759902702516554570353980156547", + "39554460272151083074672800826324120693374561515500028012725703658545390703795", + "50826141126353485099108130395278693886985548100065500383766595289239403636468", + "21767255398665955717978921133361880086935366598658560001033134067451884777213", + "41886513275448891050068379194154996712463794686118097367198637611226852495946", + "22970684559980607155751911547287120019924784160821342297932464733284577474126", + "24127792621879507552924125847380576821398682726636017389568289497827684771621", + "33249816753653179717430478327794562399909613994841603292183082707796311354779", + "33240819556999090580093475188231967525080776215872975838703690200281707365707", + "3578370662399440058336525178631988132044332508091661108516058247471886253845", + "45294135191078949397319403639143771161447401417309436437256358975204085640949", + "25554147495998515551667925365084194227219330498840298561055242549539238858049", + "11396043008409644695178716892917547641506900622271993586200235089185536114379", + "49397858964134917792263842370448350955985288141934937436977112444210944385315", + "34526297323627615239386207991929976018719588813423929293307808999246540953726", + "21988018982987349169854322225663468276632307943140793335599863325083633885513", + "48914122906380956876289855538966063465936495248723403624938191323524877605461", + "34655530900175267724855295465098518483142334195427685853191656298175722321088", + "10253192045246478144942291915780249977589914460399497708526244725793315598411", + "33012789512484582677420276557604731105735008109401063377440067816709317572484", + "22883474190834977599297490232121402802516568423216948828245968172136838831006", + "28268322103652819017971931228343521876523214499750479583406782035849582396480", + "35589447536990127914685854466841926406294466619393684707642602020802114064531", + "24909781321858818291390435085749039965760935846760352263897561569387582859309", + "18983680500678638837149774139044757060716774934181700198008407674386508508018", + "49545882537871890211889376033265174370226289341007061567643059107883736906010", + "42514143524525039879365494176339027482337568109028679112137083316819691389630", + "29338757454211805684510194256488959288415030675823964125830462478161154672260", + "29608683176599643802906109863908178443788836756161174672656170778284831611415", + "3203310072498808515944572253929420889964420914079035702115313963190997599945", + "22148546752018301342781032323346203115882355119835612984435899242009118768801", + "42397474956913686360672264915333885453356185150612475781054803685910205687346", + "15865030517996665474622928503891315979530261816609194213904080585391356315693", + "18112121186379747157803083154265587871062939091773036865612680158443065318045", + "22642839461881665740535923058608291096559000411752434293493026213535890652575", + "38522627402246395169285949187244799970338998994110621372220650994538272050248", + "46914643616733855227237340230100512666703292626010653713619122896392368315165", + "46726498696533570124406068294862844530790967006230450368615125923996444154605", + "42021751614348762713338236569386375004701836770710583722693645055695938503134", + "29150338021828118023130684325041284973294037127350885824164093671236233612760", + "7330127731605087829476364729395094104122495027578821695161561935400104382980", + "16664532871747017916489070252238417936611739460323888858188028071523280902433", + "41550133748080252244075570803601868911513956993858228280666219724166977498850", + "37392079807013347902095443431128204441282451787420974017339892225622828731195", + "52429220946936454588113724009777601385553986937514946986238993585320467561012", + "46886375015756241050214202288419522165104015989732925551100300835655676710439", + "13083536432151160634535347501261464453111878562340169264063103184214067068488", + "15119876105142350908101933291983249248737845284738376107246112220856567730153", + "16680631509664403239774325274853266492865688170313557221168602386763404479327", + "30847268855608055431108674396279926844685577470609072969995270189945047701379", + "32547652121414754561800534177985999436413852518686573857925046062507405960368", + "22241839894394188817124800757007871562724816406907328223462376840027914533743", + "42922713441026922975515945766080055172845051575358587538397931789147587805690", + "46495659235959896211788365966219568779845462504942749458871981418924746064646", + "34368263838106866388040106480312342899425614606947752896552139362730220043213", + "48683349399026507078043636359334309325656743806346332363979023787556639233166", + "13376000577330699020433535930218121397549263768637177558831067941544974612797", + "3370864084097032258615881375482039563024697308919166413950039161297066195259", + "21589403764135128419814784530404524031494601584096717730239062257312895929585", + "6191266762219018758428203376239940522925610429433434081392605731755430952181", + "39543347608038933792831465314933096707660815460675516691079121839685956966212", + "51476746943111254514490135289782781949790977704573830873803416590165587308188", + "18939254760333226205433824503086664200665650333936248721530234732637346073448", + "25562859754069998521842229441125052109302752766203225850868172254945198632031", + "20793637914665490108301323271380303933765394876761329714764525144963348382698", + "28303599773347646519449936449542034844159158274463372688190966026633060259931", + "11588213734024265342501441422932823968999413387363162716575030955471989396716", + "33305467834621428918641184002055179610941258759875780768983471984617825599181", + "13085206918781846006280020743993524796018017013211199757010496509958329640915", + "23626654186938902322893383502341673433747493647965840818780490971922119500348", + "182230699445124725350908449256863811149650831128012209319641485967685548809", + "30244531347903450869101357317493033761439554953543517568341516168992086224457", + "42683636487374982279154734156219177111842763047640879582662508462100355507898", + "45880919482560452867576981753200005885775906125683545438521312688749188262006", + "32323521489584954417912194802150132828144523318316317797887845451443205136618", + "18617901833199137155009183179504305521275073006888958106833975089711765725057", + "26417716412644762583973769757102857054887614344577627410087913531211209465498", + "43025791355003634080247570985711013791934947747030697155365891101986813509905", + "33815089880569250182330859222443843734256349099103607336694515729612991626092", + "25737315115933844588383479671643021130849596324557074965064723620076323265845", + "6045416637276345455050398862450333219705210433503028705045396218598675542502", + "51400668428204827930899328580774939886483990927897682519921741482038795422431", + "50745831751716258116765154781626553670677743464701168541379977169156348908369", + "41987567917952314223564633056927955599252177348356752034409062879518193782729", + "30405122503762067498177472478152349170640378893415571708498043924631209175448", + "37728908954675807242851589427520846408334682878592503287715022262173674774179", + "10606582730625087801333331686963010811689203560925441722301675541572499165496", + "16158936068853356687145844909098356374241416021724993241811564213122248567908", + "11308759238025940011454860390317772400357582865817375752515055097559222185503", + "37885634686518652113859733544073577332784327028443411082192402945702453957342", + "14451085348462570841355703350656163666959850350944619563731503229664281552222", + "25931610239249720264968989803887354355406237964042774927890778344110493459973", + "42711654032205916391316548439417079698832595699158426327821527391665284605329", + "27848394339990402667185486393585838154661922054642953826596505346616344062610", + "17025618499049513933450511824837007349784100192582793730598849751595591726441", + "34676026096064573812691793169333143671008497734334044526630397921956244859936", + "36786898476851583273276036827278611654596986061937222963758325490192271931916", + "1338420233569849501238349102684720312385559742025814347269623302341287481134", + "8344860413505851736033651459807092776544258196190140950374358392813150876734", + "21196236980683840767726445707456145757087104407602569108671911925997546120415", + "29763503452802270398861488464493559836634354282458090908778409782298541264901", + "4293943447942528361850198268759940380057278114964632617489767364268091736869", + "2376887610856001424048362806898559964233672405509468234536845728069654318917", + "36849235939335222151530272349263118757094730305579590082888789142477487744880", + "6071767548782731543412669033978411518858315800986132869669275317022798130857", + "1856619955166062310418651993037649801127760678120052414540324497554773168201", + "37249422493409692845433418688902214137536918514239902623351765706889679923409", + "36577064763903965555501767903238940197645566009555889420750024710997850836367", + "39242332057735193511578790762830889657699860351149006130346144563026167101482", + "32429456418585658834303298173300650294574892650487315662073167759071328705063", + "14605935834180671649342842297020152261537795568644047236901209811896518650066", + "43704893435437997385114250913252427401837340512660586168644471610223996759398", + "45511542278981008562353895934902111368813026242165667488796466289886546931830", + "19299209626990547853423505613312676807327506056008082115961538880799309409718", + "24411039939552476286023014022115179795032553041260539701276943758100615785574", + "30590349793772459466146762165469984423975743306265543155492490774458832700361", + "43513206914523178104679760240447608317912672580706658821619667820299569017406", + "8379028758652283342380058964617936857257596853003699898999828218574463908805", + "2436858262027795502580886483308353695782658644673618752154467749373203391497", + "20349694877890700617681544533628692601912844237090789956420562466142558428754", + "45593048272542953209185318371911130550060284381150193778194630175166582352029", + "13285235558555945884600299835592447112527152335405227547390864130468464302377", + "899699054405802614685071673059935147676971388637263446457351275227544983749", + "30430234903522558892784418094858641676494051958634663518057946611863319836884", + "25989035951997369032257118893902590511702506738256465342603209814793879706517", + "10936754012681042493481438712532644700178518708922252827018011928519614286194", + "35278512321967581019373674960413315536418522435513936741483521828079897342989", + "23841346057533464945698947877047643704884223993630940474436313998937886437110", + "27115812130908895710266560949767775655669045881122182295201757081241326435912", + "1824348604377973165688257592369840234418642329597275599023781203242189015633", + "29073922806635071671350637125127166314500817038425580464047931099385015748728", + "41794697547812316571474373167918605935703454138576804802725237958494758835250", + "40699869011241960179513335837630815527976440839437408013530320237865217390530", + "14460516451298063806954349488774157954989893560418856590613527365680438108356", + "185412739073897572244761124271350747990973623324307469436583326504775834385", + "7918202390410580349573852810557690273233149712755118164750121784051101288024", + "16277859609340072290241411790575690402783826234904230339391021460684548422056", + "17614434970142576753545624348475914496344996148137739754719847306335253278601", + "31637720094362347983291362831400767835694388011400313098297842852849293523401", + "13174963814459499933056411267169939635413362786381428234364529876442872647651", + "14617967833435275902393936167924182995811506654177995036916215241438763357912", + "4291022443681574749702169271450410167815331055596812283572315785447968848217", + "49287120096437701411773477002615051503897487691120820048587617866012588495096", + "16083343374505264058969343787675913600570294700328813386327766224231164175225", + "42591776479103779172932146037240408567236192563356286443727207850493163941860", + "48412704114263406928022831102343028192655670161769162982967265508777601822462", + "36825092550734736593512470368337710888573468694313111392617118145087987821139", + "47240185900743919640778751669336950807487933484528974829648945249185214307232", + "1859005917803427248417766162305878877884769584913596801219703296522700374483", + "12417547104438294229692210254450179641810350730253401195046729660889126226752", + "11090463467418272905362466094864909751681441810406981331793353804483462852460", + "43817248906910103996851984390536657850861956350746144364965942872331039715533", + "24826772656337886175869710751209390061427969633828570696644614649856432012318", + "4564347138822124821133900421933767926263207070595914854244492924078736100904", + "6058942347013616424244715589733090709570933494190296093768922918955565609812", + "41640694696057742718617163785008973580509709301708403047490484101377843477739", + "1300849502969625726732961806643355972972425450759144120037372395109979849610", + "13661485125681675404842822120183579702056295816235632596831943347751370307200", + "26799582804167308311409278111783327464204097091944453473922345699769626013187", + "9935336682889013152937970747365894514833112600257784602539057971627417412194", + "22928477759468177175231823021957847980559933096291447351582117891800332198717", + "26465780786177004849745619410454052532586679487769487165830029881908645585356", + "7131210378784259602184719276034085221838419363095636270422977483086593174099", + "11069972441069762784844565552965990928609460793735251377174400928339810780258", + "22488427770321238051027789466698805850661129048549314080495190998984163272041", + "37115425392858969905553833117163099133645589075250231526680063130630268237055", + "52066645347785791346669514512767461797042773806359945357487734664196619354898", + "20032067955925518966505799597418369042366938470887177415824306304217292224047", + "26562918608621715110360483378722325766865809361325040935357169736532619995336", + "18537867824425076815899750258019505299609950051771667195529228065557979559897", + "38440559267572472922666374660009133093881048547630256500707688785454602938345", + "7874921154713040851736797299576854801197623671677774023110372375340868156075", + "22474037454026532100090442144575863485938170232831863033914688662617225613391", + "45020049051155460809795803794675034986143429349493276211698399884858550760184", + "10015207074639751254468138822286941845075935024085581699422001218354710593111", + "8048671534976821994677888149393871850698660671129635866006017748421546620863", + "37317557179720190587679377652664520116278838590978169636322066032214849322909", + "13191919750195277221858274311855545442237380778911169031243371633849265549294", + "18694907433374407283888374082811464236345496282085550591093413044356594109333", + "11188423620461559384002920729375784654682359414917413921709906151179612911681", + "22209306015955671663936529772991765426296296760242705436437011356435832809087", + "23771706382747454835998241115235182916524786257560134943652839278536853438450", + "35560059520695396901863047916426319572301098918630919267218228560564788441666", + "39607718233816856743991419554778454017555934339815584415235481119478250501487", + "11879864052515875085903720499006069336699477783600451068851999127653237727419", + "24539382254461043786721112707671930229928489963591543352696379006385918878206", + "31367363609133772136626685575249916044318084316429777544819484910000779503807", + "958596981114710566538150672804392955581321227920497723557765012783677756696", + "39123586832511555181075451331024675801285131885358974547701353538236578004097", + "31184744013010098884867756711989217206754896780828044424398369541123014704141", + "18268470201095040088305681906516721816642602011529450521971193115316859592143", + "14245815100547004453818249354633564469927654967149983106529890047904904910305", + "36981085605299317834692841853458726970158264077791474062044506665946224386200", + "16833513194156444596681876395820682493305086626100228204478248068944909570680", + "2952071324809262725299734403037549863155688904680073473448149165615249548781", + "11841320116945599472922308196775674886536747906936118891415347492573489301658", + "17323467126162737074744519419020666803463545290775362482403743333483613788956", + "39259423117682034240913832535637279429320017365055767154589919077471504463437", + "28145586645422618325377846238154248078050317173340331351878832122959432387063", + "2332187288417775553497150073496227766339222547658814374255973075226789855445", + "14817499458581168566441594243923510364490856297716527108232542618038495278937", + "40216094600848260442094677449062892246124339487933940284628889554968173748836", + "20363546963343335629468151465416710953754138541126176499226921865000465363972", + "17427957164508313468447008845374531473754973522927800022884134560919158797205", + "9486489180470174082480367748553353492911587971041170077117173635509981181103", + "19280437817820333487003705241045887291796921726332965212695772112577945661460", + "44827045516547899679195020973645019637473353788809939300315809371412208972536", + "49352603532816148177602011524295603244782122384298057911716361613710349615790", + "32179182461865384935446165608961889028066502232116807325977686052805093241554", + "995807321691755204336244163400775715936158337067746311955241858961793981299", + "31467195445209314098545387354441141132547905905590794693586729639920312400447", + "35073635863123001580669139605710420361597282987898563458425205525536986435798", + "26290418456655867378501891392962611195977369433137657339781607418134814834857", + "13164925027129442692675069098750391612577373061015529455475158650422245633833", + "50916649310985588839017201188013974068554406183117072223958216205352439416178", + "6044828207565729504477313838427182916023088055017980441850854352061980039880", + "49982880123876874059987252707933038115282052372677207187304707536391575378753", + "29314888161778153141264156668271885022643033297494490586339796233712479512682", + "48164040782379118279536191882344393134699229095093120189444428101592573784033", + "25733252146977175298832124849977749266786227311602616129335900343604555575833", + "1929427108591945773978306921855180112692151045130004934540579586757425318004", + "23816912209118935413341162119786389688384625838568542116322513976093354174483", + "38720931563199292471988352103339846338805759015630027099270021469054845597572", + "2341037372860732977590795413336096566155634384964584388564951980205986228192", + "32036495189668197390543450983323155159102484735467936906599320630306153070681", + "42506130148435083977095754648678094225607300486711636922918643309634077711906", + "20413778529787255728581995472377596973889655842850291811686548410055644736721", + "20569716063668278601394811432291768569793253912519790733448622524773614059589", + "16872989594118266545555931614877567180412628702480502782355261956946299112319", + "33412762364115693786578999292527680092014977398505719847760490661729477462779", + "35644833363842791720353995722324676919281965257478186058938615250855562818176", + "24377437896827218798796941015588226824481742194728851635267746263928538239478", + "40077774804453397886367444400640832771938759279251542808082697608752783987260", + "33837547213755181740596845442273818045341208140065641337628228958385320287676", + "17585471645619381430886934918557459575536298693154359324001140629280597501887", + "31425325803251297569358225284768017087074344958655671199352915753710148610749", + "38523862228751453171870966764124879487414342534352969597525487033726476448501", + "14203693914115357695574547005316898917062635575795437434490468867043503476910", + "2096014101670160778697434414631809573635213044038056386932682451405153855898", + "31903289014035386879190702439523959945870332278379118307650349835394152545057", + "51485971440153582622823033718681342352858326833688964489516116250765217253862", + "50122892882759821781325737405551723793271309735944372517502181455724563707195", + "44750549906435290831893358961084502070697075062330144548003370368164207254839", + "20394141448527768584952361319854869258785693427537580309020625509889855679015", + "29179223030550613849683807291724810806167648025871421051032781390400155805925", + "35731360709800763337633476614696418388326698579926262009481357919655322592251", + "46368821756753064911870666781008327175653587360428992030984372123285825115223", + "20196750412930762990130994436470332643993452275763774248328536776133640947147", + "31860936946212779925955249890321852775218528412034168652849388570497065019305", + "52086547117819447843668702923269201583357451206847056974635480205486077810291", + "25280504142190448489746663356182401733035078170173694543935737146552535118363", + "9744640904443880363797501739735449265943379985737397404848127833512761636365", + "19248722588064383570574875984160861149918489674186209629462515232634115465665", + "11421402377744699466975505777611078258072998021477363844738794211665857447742", + "16192456139498720381326033463198390410824099358977823894689046979336451244086", + "14442723714560703155486570388118362590573089329688246453258947401680818439663", + "19416445241356128387223508400813009382794277647508063622822581988710037660696", + "12355820645189665288793334800293494967267098811512960941705482169223831558448", + "27349709423892167191889395856489486303043624734008060546947015830455409250002", + "48600083899303536047122576331880246512539560039748531054557937994286207484388", + "24238715003600176023065649696494093694663213536079186342060126377896454327187", + "21738391831365473027848187325397375210926003231217894642114722377124023010791", + "4658010348385803182207612853007800137574662451850686697633275138669695643155", + "11333478912952723685886990306799405870532331088193251759056693708752377325700", + "9406504258977879028616475081658271940213541347659857377044602309209601978621", + "20392275871252307344188957395772445993284700015535878179266848751975460620461", + "43800012837485599407816585679361907073436965939956654312733733322136962948382", + "4898708291786232802315014926851956752035320522123658381352612209259770811463", + "46794770380932067797315405643722441015799801659897683894017674494436696033308", + "5502033358724000082085539792820941686736271951731175995566011540614650713889", + "16717288628218166337269381989609756845551122832616048187911094571656565631972", + "45133715245530979468112154682210419675769425729370109340402907767513859727841", + "4551662058219335093299209487380176199505874930660581986557197817089355615839", + "2959697226888382913408175459865278062983094027791953959676689454193185899903", + "14310583724738040396443905882312348861444331048187625383401377498563318311610", + "2726491376174763865864419942841352102623270074954466117246577078597443790495", + "6840725396403587453776797204169255673886788864413644646993407511009168428440", + "24059685155549224953453813996736783847721707912617129413404448816237661245826", + "37108402615812415873055485521244019335727860597352795888042076693054378857411", + "7546342874744511868491995059033444177185229786451831311187271824449759127308", + "10805199913152897361749862934932738014229240500971738633021162460072685042802", + "6192572429150755176431379291681992901657019872584676053610479264823895582746", + "31747201078097618417928929938335012762359333735955588373604635380570714299781", + "20595228750820753774621121498063147813160439441650602456558744003701486053306", + "29378118586772873060176692160951044662855855816710089126517394900493407042729", + "41071515748201110410553969243898400182363843677496049963346856307243404258569", + "20304018697609974747771642252148679545165883461164698840902778873268093102370", + "48399104457492992252156329942255398797890449167449300116028426356504161494001", + "16963313834923195349236122051461516924971837138697953715450039344723885925121", + "17791216583191731078065544177887434104645412948925502191906237726982761700399", + "2746173922732350673367457342041413577255609882555762876766745770637571145667", + "21780992715604095596374127091962359075255326770539745735077401414797125238426", + "49493555628324592987140966107686094152088797515485937386411928482665680640260", + "36433976796402085019133741452499445095352943393272709241090696784001178321040", + "39410530246025559947106359439441980516509463103182544400993722767134205435715", + "4067625228911978447139282182438453034592186673792061783512943381122929813395", + "46763420823492349986767568820522345148303641400218300259646890932488256359506", + "32923355590358685099743237980649976717599019891597580530569966706367128333474", + "30494095685630575315393162181506297011660587731275328045858955882921226216207", + "32510439152849997469757108043374242664178841501344386740677492884306163407540", + "13842511663357652010680970690220201885072036284644951338760990016355756617167", + "1920216327487711255085140939846383057797822461404265653807009987136301155608", + "13528082276469701061394368375880411188607270696202785829512258817032438493543", + "35896671942076575067815829675356200354863028659901395580174434928416684604364", + "18213383076738225392856205312911129095013469953323182405467482898201144162080", + "25435916276629625916249411596736134184044864756330861658014138487949199950157", + "31857608288402685839433611866685748139783360707453799890424354620409260176167", + "32773885401668136750904471113570925341514962792410555762797489567304937015721", + "19987453264485244438254735495760095597592533305780828858296642324967982540214", + "41489562264909527625175992757798012070261161398949745646219204313119544158708", + "27382703087275011429405384084252279397772275555831162067253471715363804901111", + "34900336495239765418629205953973511289447035422383684659701562981754615594424", + "34569927035644028552931020757619378653188757056329713043435698098213829870431", + "31451941737449357374409284916385140493240201590971364774926034086631736175188", + "39955790415991653634725648168926412416792024482877993705740835067419409301904", + "20887850729845791651680750006425496106138753062536952133273073588889488985242", + "27295798684669871674152483697548338044749196552603166384643863096269544055364", + "14178711252230227265770766919442477330831968717356225650259211864045405191351", + "25457431478882678041762475378018906823758111773406483945767015997395928509816", + "51606335751977828745003375674467917423286173595167997734120264831789979498570", + "6015095979244217492322887325716371623382634655718544907796338772664536940750", + "36735425231927510894762726206800977934458183844636222324868784978853464983030", + "839079264845850871337087072162639867529112466224024471292185257204326483735", + "35518695161895409339369978249617250439597111627809104562000531260684278040080", + "50963220373134354668150292077369280694641867381252838504571954934530373242167", + "40298873152298694372444878693322530130467952795984142299274111884425357064069", + "37163183921430562852735529908610141206319571132064756107878828419623357066111", + "17108207013756953482521824902102939928908584523447849816384340439947745703723", + "7758246163045087955415949636288941085357489894708492308736381326613568759384", + "47773556914706422285558589840235475023134497477954289966061263618610303877979", + "24751617690890280750622160938382931400954531673664354155388892061296574891310", + "43901360708780128354874346660670881892063808972574775760157283993958214286131", + "6686735146600252363127419885356414450555593568480408327683285138110702125162", + "7893149842387772112647036164185540292357017153225117303747096812662699761553", + "19130460406526574494271245159944379920503893139961326394074542529364926647692", + "6242072539216123163690114183016546172280434442137350895368134568095785483333", + "16307812452192213891085522671486691599514085810491848464296505465827078886805", + "40075829046854379076412955746295070475763606321675641362452479347273329334263", + "32781182224195648779378959115516080507824913441525799168230035740341806847306", + "20392695807287377152642020465056665884546032269815277859386514826622449109639", + "45527362228780014339201805113332691982482899552173866964223704527290911233269", + "30112601627981356459246423174211533036624362166446078551184945389612991002646", + "50929780966111139396055465144020488728616771355171668455770149526230781928078", + "21177032328556672245601481525285342911833076053131088016187228135052225802607", + "1863459904155555154238583337032657121196425688146892281609070364712994861467", + "41267448493241672422522676563803809982953674737731899146807202293150211758114", + "43705775722817886033984379998869007868253263412520927908803007849038831977643", + "32489864064912712800029932571483153335198515304030118778484540637106341030554", + "1584998597786636616436316763885075595521151616216854329608920969160732228196", + "41030855037279676904314076248531916866549300943053932412471391428196172131896", + "16382623016160986451076393744542283548748978130333194370505664760988609868911", + "12402343595999670687173403953508189727602704801892409934157238933145366080291", + "38110366919883784924496467752480569033643809343493342802410377430084295082188", + "43791029171578494801789105115836862038818178533979649248532378230125579275312", + "18782970029862236292548168352397875805306226672619060114538865915791747083504", + "41337066990776152881746570857537304602763449648610645744638886802962738350386", + "34758096220116349946751622842802999072170148196400433005442911966884184543281", + "43552558583742177180281163726788138011083616713882426722485155617065734482227", + "31257006255086467553523990681310022953970675656856438730834936233098629834696", + "43664531371356155551805764661323636043898565296555874520579868581477507322132", + "24657662217953665859688361124981964939966923949806830353651365709105989383809", + "829123801047542449702836169076827941934231953722374441762407156080843705284", + "37506459047476927585832231166259088295159965588353363241488860185630391371657", + "43219869598983332071721794486315646824945702305483732213958831723506210074037", + "23718869689760117918268593911680514314365558629861468672793721021665694494606", + "20656278549852959494690704196521816977719869944088836933211817192121578211408", + "32946019795374956321339672368263948470556461322173644090736009859327405201189", + "19946686351988559490760924897359875984028371472718806891007917794444895106231", + "31897612074728467344880074297175667125198857364205188821538364354356700173003", + "28134529170206125039364326525637085385244852469217093397737370803781820735903", + "24416266549642056890176368914370053958745060574864741431830290558626319155995", + "19320147929049967072467742140419406057948689537091152680887997493365719860031", + "8697806773264283595206193659128338504908324178520417185651809251896167519509", + "11831128373783441259033625955421030186093070281567305617338709411790503253589", + "33218976060370081704579962727971791228705833512777457206479721274412390662465", + "29000030521073315831460731422450015298678928507677785945363830315268688031273", + "30447388515894606539765058876886317269453941144043914082051248868723611499187", + "8968300242769021285687232705549796305210796331798827939185698327636472212555", + "283272168769565192068347193417536436361790005305513982910283822597747491995", + "43479109329278911562977594595817143102448510703533057579503838738162311487923", + "28298826193109483541152360574448223132068370143499134648850367413388255836019", + "9073204935034337874677213092922918877253990585226232369471344272983268407149", + "24970281016000491734738094063166801839183591168720491050722097714374320616821", + "32708070039875736923033995916844572052548014734443199154689624244858157073091", + "6529052700033002004436367125039659896107254517802996378019252505474519815463", + "17132193367763622910774690527822911657277868532728373761248910934631741035497", + "46159162450962370473468804632575818740373849185058804160344348816112846332836", + "43307717671625140903127765724370660956983151127928043811047855780344162417787", + "46557146101178501320814094400136101613817637270623484126650878870851124764780", + "24342475514895490670367567667156674023666319706427991510762239466781043832481", + "26609085049228845447719616578913167829179309854699293621120406316921767746199", + "47565821610236794935444887983618874581058336722070137066592394964205082307466", + "51931869448852136972024384389580363993320045643787716054119284173019560952400", + "29602749628076272132681053705834860309544334430520745328161929061156761004294", + "6727876480945840224603405846577761650414266592595531031292253366438932033379", + "31451114680549771228062892045673914910659678622639423685667197987468230775240", + "28707375961647177676905937811648833066480630625854767352597062807927917343390", + "11441080812077103677815724968410312291732826237841695616975509016304759081284", + "11554863150076707282114169396563364252728371789504060893758910252730240716309", + "30515231913560069229817393244110897369991496101660280256068682669323121923051", + "9139072405433117140042461160763498845168752272081420948855734580566786737511", + "1747130835102284373230195438784185325947798646995683673302658625931342875250", + "2160224910407870271657366614091798515844530525185421737691611574750170047670", + "33655234234653133444012692484087077761637781831108205054125989054199486385028", + "40661196399245985609495347372696655892129765159600382683630122988523820236689", + "34484475137105504195314614053359592504557915725808170960310361905780936719193", + "48429974815224427175070262920030145333689471280284630993073835346184151079748", + "49461629845282193600874019032370526131150551018792093709182213531215260598220", + "40959773873463030899658757545049804932531147226993192435104239235441310073973", + "42042912382357904629210522854706618942500224530361450998746631938295097277702", + "27140421466619809729151582042274160977004827196910664008712005065447310161603", + "36238917823488222090845765107415472279423711166382877329133849015794788817285", + "37322704869101365553601339880403505767193777385879010758227991164125077735261", + "41484984458192379761263777727975663764679738307743732994312818884219386995779", + "36760178846420696585028461211833273230232430368993000724885069200947095525747", + "32772654285928458441560039830941208625222710701979536213130642196353490490689", + "31221830732131654708203248457463871914800459909342944431492821429253818224582", + "8406255509519011682970132436153700010006853147089386775820274225351838829518", + "51179073223451862944924104511709686723347211695321392345055592899882927199229", + "29194566426845723166325178983368617072860518456678303111084396073971106017477", + "8465624716024994911436608361130777091569924080806232987116377900592440838565", + "40021912172341016358996912093948703396719629235154662199335906261420780260014", + "20202172067322087104045859478604572595056358011639056774369606456496204442064", + "26579153690151885001736625806086546481994657900696123267542453435440201688660", + "38204829512088346378145655975926550544825159895416202533862116903776954821502", + "35306232751168934415156355058291948469432905130886173217389974391568044471075", + "38114022169106900443618944474486073080593843093448458099405009613118540305622", + "39107958727166332431329162067142846654021783284601375417229815850528531501857", + "27237568847549167783598262114918332103015135600211895082002920865030784081723", + "26043769770540756618526190882559298404384269615889057121671474305703612834264", + "38684507700259337230515149330941052300635545273801841099629750085387840489458", + "26122480510442885078231702794637455167034416020981282984531229957118201487949", + "7592684621369867208017906197640689837600013556562699561689808982215058801807", + "36185915921466468453221086526605077546553893049467884868747991833155479261912", + "13602568110208893562812265382315582551106201963855114542409618094880980286819", + "21973904270169881490189585462321533562753338188764232084484144187389274758804", + "16928461042545717132425183520105857525912583039568324206183620432569574575999", + "21261035356522891242615102799992100696233171703004170460656195467998444118683", + "49402248978609927685778740076886363474545706998481037119036382889107170793080", + "42492839165878108760709996027224877241979892092061521818395652723123804529222", + "44524731209484009724161419821554831327209305124594471608121054221987694484932", + "38719256183475653543603729530886426816549712289075259361048047039733616227148", + "34529594270763653757695176651797713465561994036054331308892157842979827355064", + "6010332967016885795696979957522313994172021113144069209372084571315005554153", + "23583565639132548129293069688597253368783975539674515564421426709121889960830", + "50745496448439144515780673385781649580945417418589057124175158424281541582947", + "51445088476922464149709587743557250722064598557454834339721351677075084731486", + "4035194064440100243190831374879379738755396194142977330911806915059534045083", + "23566821414003663151811430291468830714918914169700530146223015891300128751434", + "7184373785510665818722148100931831474427573602851151063919308846520028322994", + "41954674542087785747425435073360579844499481298381460041932461442184052819631", + "17705319614048350367884781313453785807312667271294614193441701890616489247597", + "16178148632315234353933090546414355790691269532556900581948399111064611890925", + "36673923261257647101657409803576127507342478256633512518950720578314035767929", + "17468920877906223022382905702977674611252967496253783900422217190359655764162", + "33972825184971851943863887870033341813086106220096748995244660981837813589629", + "49281634954842528552995430328561964201480372516980960817087802066800380856918", + "51867034062977776957524200500235611815381021403348797475184894587274039538813", + "23999531238313519073563141950854043492164337968201201151985868008907388363844", + "14008446785405705714016031200206461006443844040389366494593728855297537229993", + "23429177591701652274906740703454768924809405195528627356505816577176189514278", + "48235303332617554267850020641279063398632439572472321597671022354657806915534", + "39304191193921279569459284241778715566930388553493653908634653679921425281034", + "32289096699256568266517328169753508693336326329669711221451463438058210994459", + "48826185130999763666964777433111782694109811161476629424953434715672783978268", + "23454622902723055094242668593945481047721044588448606051038781834458124276426", + "25072331207790879342322684489395109275059065246100738839353333017854922564789", + "43427146325851678223202180687727928915077103012469941485793314710681890946264", + "44303399233296324501056223572940569338666869037267627730983043388803474640841", + "10985678495999198141622548926473628087964598203591284025685415323770481934697", + "14382067057127673846269509516196358927194277181778440880849470737923373902877", + "40501767894796393823266280430251163971173074203255762074537307547846664023464", + "40685412885555279008462823763338117726850192564085614409464045445332706092921", + "31497357930889744094983785431251631324923908570278408077075986398518259527064", + "49006215349473752911084622456566958524164250503714028000811364769015833414168", + "35127012535771505535395210150931572699178127230536909434368583306762650628065", + "14307511658568467815838011147329791313971657322719479130798712318524519178395", + "13879873612217224159547358972326234891338584971563645347812178390177513164446", + "1222172172738835527580348387906886091728589944636526905383626930686629167141", + "38380795811594619415479864202201870031336823414181149108855685379479455086456", + "21334535846656395985931342086251709920283491679334272109372030909707837943988", + "29594860206385928691253521317635177215596101823766252691899107441242454071375", + "1048403500266015156360218662539960404692901690800486622819683936656689333614", + "7678236622660273966961585938378296683044665084709787753806857857339067981061", + "1050154424762105223620418222180555386066060786650898259220979344142352272358", + "35159035084733904394691207988151137610950878410093865320392118623744523936945", + "44188067777872713180756738000558701565221270107785630503483701965005600986994", + "8669434515281052894122309908359241913799393689270117952856147296095274482190", + "29742483852927453524140850756702685743254371995992290411028619705021326880351", + "3405077783779583732221036748732186401859230803981166925896729485182473725493", + "8430709062514657337603968540429841004194853845472872906398740946514902596750", + "1112002095825855546713926619774492377273681113315105469342463228080291313046", + "49544623579222424700573807327421229605735586751439123090678395851144334969777", + "5058986452824930686161386274682363916005348677747688184961439621182097791152", + "5854279292080584108277355362129895518541236828620871662978174206066940631598", + "34350577919130027408059478063141817863396414397088879510970612376927967819367", + "8668652451091497834120300705059007818007630698523929756672492438136987653102", + "37106661455383327061051265767381946530369960148862591117328340655793260044692", + "39718352653019380377846343613072451228452250890993019948561941837374810200735", + "11043777881730973323922838331398315053168563288611032545854964272336257539613", + "3649379263807528288606201756097771589071682173012848406077605836891998480511", + "28544350990875141972437405372367446783141853541002708892891775410338884093457", + "35207967248911277453805743355999300235013863329266530760911003613832148393828", + "21453653942381211251446176538167953552014021161653889839561671247995429278967", + "50460415246516722865132517880352741912230326372272897665617421404334501369744", + "37612867232277623558476730914641045294123303120966768739857818016826567780944", + "27910405360666369235005162685806449220400851188378676708894100633973849305730", + "27568799258640720985418172987629904547183821749593800810330159076608233194872", + "13984802810619922705722368741317821802639213673798841817764549103119460636881", + "12032716097161752925817409213916441608640778926544740531924924271597322308515", + "52331330465655241334825956751736774623615354486755296718475196748190069649584", + "27416981087375984627640477702222067742674683502166544246063588801837456802232", + "34002662729862864573743201803516318051320249806079829095878720090672771024965", + "46287681912067277411345636010890736700823683703988872964534389994366831563334", + "1941670225497198682504278812809391051411619916915523587724111320200526024008", + "17106813830980181616569254185119989852061501904390330536773674954964621708737", + "36047062999811667438195238209707186815278723165858926486025237699063875744627", + "23294783303069515390471365345931937282196260474403258620119788559040734841415", + "32003535549397777697130599309642352262586982970171737891702556712674595244801", + "20106033385930041103538354263595707461871050751214705497277186780347716764672", + "14935876526695023713647753893164468784992383798015349948469828001927450283462", + "46037754952140271961961908569012719358009746962273506895193383572079587844030", + "3061555846760505353844992649293079483528895898398917681047476116392642332524", + "1819523585095301106173950593965174598811492044714066186719330287161127928168", + "7199083647662122229309219459722062421501721139959255724433818200771973306061", + "3872524553784893077928239233560160209372485290857702332614191888318531845597", + "44074306446493691264182009179519419056728039511415773918158075837675161157874", + "11752815548375412945916149515529552956881725605998538502949224213497407789596", + "51538294594543814630480312433433243853479564607788595129442659235284132851021", + "51674524023463966693737509172615877133682757148416768108620174427663886670850", + "25612707770859015997608138694753263999404086753408923222162547962428811777212", + "48786354379160731335366342086454150239952279910887021381709723966190911709756", + "49971422928634930025442770333164229480257757903565774205810452367773360911054", + "15629659170893290873319250413164203853534358481623928361580520012709943072505", + "44872247715879005691960951248479044464057121580708032796913561693944192038961", + "30853869274213056132149324631804771573973860122240850299612298894829754772764", + "12179609070801268747550486543583482968069283360839702141698786285812243310842", + "14191230536614351728112837550026946632299146591449345377804381860213089864895", + "5812892217967909569718814095737820958689836599762870144018400800685592372006", + "36627302133608831437808317434530595510969416054677354469702388404977386186893", + "49408446560032022844072375489447751021111285798741651028706282486559443482572", + "39788807737272898886316693625828450751571246533197814487031965059967197227198", + "48803110384118240543230282957219000753690391605137441365164212255670197730375", + "19917682470215580627726274335332789162391480390842563424369346031150025731108", + "5908491368466220150271369007519302341731203447951782323857366529142789136719", + "46403188761264005057677774057935665091704361757975191577689672384220386907620", + "7716309687244128363368445987141188584850998461310692614625202233079110510685", + "13454053195409965646482311873085774891916997741772889256514781199246633394303", + "3866897864798471480843272889361531942238736216162170558532288629433614293785", + "24164859392554102692904125210974454242821559574677326973510312572471219513630", + "49182637146315613389644986099346132814901583188757898736753871290108954980071", + "22366616862457956884582855994706857793530096665198207579265047795563736316380", + "8195739232178417996444704927630176181353543340185420911846953793303284891153", + "28114941043711754490569075530640649355456670055024220809575833547832261140479", + "37031940231747073303990649304853863521385569610100116940814884313801899736493", + "49196947457950931472978484984109555409662314432410297576722596095613700869935", + "31666699189598139642181270750029772622549583733882512810875767967395874762110", + "36822370362038798113723428135963537265365853855618809790071224426663950480495", + "51540679016143598803261072032107488804694936554073972655766724783421309102930", + "32977823436157941037814574677020985997625261295871480854891669943691359591116", + "43764213124907988601183411362248979794554938810693389842497676013955440233016", + "2476874386995762804112208894387397093969789016853876532691041701621240288860", + "40531773678536591506830757925108229795197075502005965805351573026908580834603", + "50842485297089163775439775984380940492066233196043046338035072062385799122037", + "49354071481299994125910734591572534324418545818472423953219696694139994942533", + "46995293829574580180920098934979681635665874281159875261951135836713276749563", + "10542504824992893011239217914626737925266090846556014721892951901040916960647", + "20734811939931171696713484133990167371060265301554150656877116728310884013298", + "15498277479465168252766341461589642375453285835526734741632048260030389829186", + "4813467491672280840409795034231162289848153478470934463908199514020770165914", + "22849084125283152212150908610769488533801881092943964098534085526425014517684", + "441691270422417896855091788135306076417271267632068805707814576673406095488", + "28088966757483492886097093864274698711494862541216621530063266456628735414495", + "36063116953197986974652570422842161786523041960470491918263560292133226492526", + "27157171394263663753808119152648161829850497463839106863519074356409162286322", + "49883854675966976671260007752161829239282587470787838732787737927631136106031", + "21589145834636557281325036639709737241473200972010635577765782839361836791890", + "9123649151761012660548219123609531972424374838101574124287561274462339931740", + "37188596439877780355496019291307973067383405231465587476071278072527960694919", + "41971686332596980987948696637883481426206146909562654471577019071301597817972", + "8305185506692638738985896260315778505685976868824898135599854635071680121123", + "160370875366285716207963502458964141729248047828698291083912187366773505239", + "2272049968800232476208516997951766591224452050716402873519776492411538068519", + "9911837957824978755782982179964851426426786063538301891063683727140912423349", + "31885876819999395384768456727984922108230282681120878575212265115604966086382", + "30312890097734770814477783947743040517452701142405342219014178204780288609087", + "21845688879097729588269148649591462131564326243358350888411544497877853101587", + "33649284550105161573691510409198858233350168814613477575633903824677755536220", + "33052005060074689833450833424461704898023398841942193265859916882421175618448", + "44293597414597886162674704574570885101202960307048507214912443384196764285097", + "45400699518258683183693165724723662106488870732899861372450734833886709159159", + "20756271217029088215554779556411651409160024748045343190939071071496020730709", + "31827383213496177537275722847178480937645145229998208351476143253897906198527", + "29408515403682384842937951577022817491288461125038940422095325461905399209967", + "46221074945103994338926005664785976904340060179079560953731326429097572941881", + "23622420830737728819930859870353982835141326149710011206309206758600647374938", + "29558294781409688393319151350025871582134391861009097899199031371882017219466", + "43091756296225708116300640289111026535528436770272393400672208521327269694014", + "12092438668558924168162597935604471384364701659596161857740111482976526856129", + "2502922794187861812002014014431876602215210908290366443166751774519674567642", + "6151663603441112319323072015097250696945900157560686078813629906177921520157", + "45144745626413736584133713049708352387069784645975224275251423542497898342757", + "6068416503492070234416132717032642181605064983673661587841366796970730444376", + "30277626486333810919624759981561727294935560450407454974071677977032415778152", + "22215368216920268397853065442319738448379178124613198028111895415618819670418", + "29679977111230731706508851506496416409262204422794964139637618465651874427572", + "34928950235461121418100777174348799313438314575403375787198526933029611623033", + "277605433742943303725519584658769777103667951647651604575978438112670539100", + "14477659935289158938226782071199120181189988779742404668520002388311551580771", + "10166958820817943761790811474905257284677093651611718654471798046195900543746", + "50236428281001225073258245745522344706905803776552387021998594310567488568868", + "4199533158036544697850617388810931909129539925130154289247309080719154210076", + "50012948111850866820545411148769710574817751601235126534100672372840157457714", + "44362618403221732812327020982848823882139743677416397054230316580658699955849", + "4694528200643766656019583014192432761403388904024421094863670248574961730356", + "853960336506216843643185678154076725505191626078220812178022368914291017646", + "35198257504287970471210282189700732928323333485362071114616587694299122548005", + "35038109255881669896536818042038205193485469712847846179072191805490697210712", + "32234297887986709744807122252278549393224399332093033304866202977777164406024", + "19730369567167296350508563908908141527330562362665269376891632408758401164338", + "11490355994239162082343276002223310362274265541766925228867810628265123882563", + "35453400741104035439560530238910449942130005791981473762709826718206881908219", + "11898910030687603307705230156581875084751884399333048310404905623086284622240", + "41284195087783030553282314642951700107621266769365977862513316021210750486452", + "49620191542799556329337751931291096080711342552782344080830254969288742912620", + "11626576868555700747483294135136036066796304807001854645027535870803331032343", + "42600038040676061344938712449684699479541273976071945692529252261249649447381", + "9443056304229652568188678666781136501408418172071561707590546818020913713804", + "5416640766100790532811040115999306281897559683390753747062398408449056656922", + "1720182457774701101184145223122786875098270378164088128026547074605202808955", + "4296078344226974303685192394095697120818694858805248246941267163426060995322", + "26435995103004378888865503609585845274121700987893070280032189742148322811077", + "10766763750947221531558758758567423716841260619097377379279021478525771321860", + "28572000406110390127059727557146094160605309235412551092302817436849288154683", + "31464058969871252218091738631247675027487350523418086952899945674998120129079", + "7236350323346015039861507313898760365824964960430554181634287001012990409550", + "34034693178909298017799649937242386412343293114763397442545345638124754032980", + "16262262486939550441930253600929386699746169389929227106523585469213860500496", + "29419994762528456949582129064627070328503385002762171224556796679405042219675", + "26265213176682701533698269821142983234262116762346047912631148316928891727929", + "19334016773676073246709425033934916495465592040158680438724956401710034007290", + "4809206637581217238766776799285974674545688902650211824502148233514002766619", + "6516862398778387349855398571796588622954599687607803921061054752582825609918", + "27429646418461227580903077064668903284856077907540851334851349672479652744390", + "28634140564574393286891076418174545204340947503721807828937397865932204591192", + "17296539079725328443822942315428313107304079550467002127018552304590690937953", + "17936705493671686680622546998524700291221503750266791110536215432670952100599", + "42155964151413043888709631683264570689239448311646238181757984223947770864072", + "51979741666493345169338686834043334647906082656410181350931554087413611767572", + "3638720888528281484068140460478506962704290430491551184838256385185864516437", + "17760375306266906879319604125234453521205676871982452816860341743941973470999", + "2974512794561126160496766719588235458274496219225886057303427994897171951150", + "33869486661765955931662549369902309198658941666902625380423321516069031168608", + "21728631683862585174479055801470738711155017339074401031400530379617861871169", + "16747617131054245239563150825452481120527700270658586642450279649753145839431", + "26447379086948049944937626013317073505442014213976063495405417588573492138129", + "8303219476413538459447112481375893857181925963114230080128892938948869550243", + "32459150211657699035472908388329828468014085322689011675133176376447296541533", + "3143429451916408290336860899803918726850545668943274957316048066875088082242", + "31817318700216712728486561935565604750722885797314027880618929353893593123615", + "8989978011612464436600808279292689575418828646972446035225471122695837495556", + "49382769386622322293024085432533326688560101516628722283482741608674137218638", + "17507223752598277908137023374902073035679642499764759157696090336380193654059", + "9335019745515132918337206973549041810368384195300576712099824143931293417789", + "13279584921531608302686041123286309765908123620330675744141498383186516729073", + "19880901132820066774536261857732161873941481048027789668064222162830733865299", + "24536014612721617599468827629100349745747075558757409843261806370442122989195", + "16886689430245357657574957164805924734051740506684019999815167175221493031911", + "13610346448530484824277207784530576586197945993572322871024939454304138773470", + "46848015846054646681120104878716238703036704913667612991969366082899678894553", + "10439699670905367635699748728658714525616897372265356886210148246289192187681", + "38239240791414963551818936439681244312169555239821435697961666575501282845334", + "30638735280725564990372596570298754291264841145108094265300544405308991561585", + "7832639767330634364502299252151626448588282852558033741356749646546318220830", + "21866636906068623297876171559120650280513608324112755837783082278610228998254", + "19764385525803409660654468245819149162034130013307574022156330234444438994234", + "27166209117796752939963297320504263816263366291360536467786019901217162967627", + "3978614119787596474128630966620471834960088883993443094680814537374232571902", + "16202780932084290602399454124765998471100961104128035853772119798438926444100", + "39174358281602172921728010264712736589641346885121859053138052866260307768305", + "36939029909196107960273832591752919731217837007965143705441707656302517531118", + "49449036514604483640895330245634083476367136911256666832227174492538095126750", + "32466026116786533239522906702846381636170007291194432059197709214032140821445", + "6207286991936842707239075660181248730075016028102375010857591401726290057947", + "17351708130138871069707976000882572702761215666133486604762333801250394871308", + "13972758894896662837225971002513671606363185920638796424373671555054441751709", + "42553284954956883726994348540427798384016290903297260667114671158441966849439", + "30718134670621488313987072073596141427428863195715841921854616205631166407883", + "26557147203811568620485535851466000312443153264769905631961014440885445815710", + "35319550019948640753959612980668545014871277350677086663066165359890988714987", + "7817375072690403510675150187494993917972165849497252295126605226856917397403", + "8611019202637911670054905230509164259326702929509504215294337717881276568270", + "40088226399295885499125223719539437424639577929658320754215604998329776375789", + "5776746797294322272625400991739437303430379175162245528177363905532343036378", + "19268563035943010098057251422533201694388809471553667530958400211208574458700", + "19321146964513897005812460692861838237849573372734595401575155016628470630216", + "52375208211615303264090592281458177832252364359741092083607250616362246328193", + "43908851516675563208389775713804611688357298288045582921179267309137507907993", + "41726680624378778245844148102490108491476864277061980692597412255119861646299", + "19050196954900786187170419593895068589673875749323218602428735725608803509282", + "33401884828225364941270651671991817946406205916760416255080575318365549806751", + "41738755998424217420281676032822070666054414798357624934426386032786143337379", + "27209223977480481115409989063271656391435462048663764656300525559818659929903", + "33896672011384464970078194654866806355903882214669605033759261580582792225027", + "3296382097627196776046426933182528510737262289244856484060041112451232821272", + "48334674951192306546021236746679157147548049509376602180378730837834528902688", + "34436919752364180836140466274488156128347003277875599929700886512607296986841", + "16301229277336026025264369124562478936262303548161925266450894632672197031093", + "35842238991073983890131457011391408122619361354659776659410337335114532659159", + "50099275576111085594837655282957650359610421982067238915553809636119911166514", + "9550484073909069854812254205677106583866835111658276197319778439102792845298", + "14284981048997587769107625796468219617776924162608202936724804426997499758544", + "35210152916158178588110139941418230842067787406030594749787204184286906629084", + "41265513108134531207444306053507677321820260918292937933688262845474254803436", + "26208661879820780560788855573387439583006642172064776640977551961981906894845", + "6647220531761293264419478906259051774840534115210874394734343974280316072688", + "5258539541572749177514521804713119043605471671493334302565809113416637529526", + "22159227425440535128714962890305823906815898185232452105846190843943350782607", + "2119948439260120646828582625398817435120581423663991535390767348544641974089", + "17506866451482693293968198369820037806676067632614459104708152193047592900492", + "22594792281357258562480955977750437016141976245059256533987065194497835923636", + "9743349299801857619655198703289437671061948176897836606606637750837854132331", + "6083252878761927218973843680315268811211791679314762076658192946272170961690", + "43936879756611685494636120684321963326110589920420379038453304643911786771132", + "4402859659401234262446365194030501200551644801717798686278492600138131702047", + "6445373350744503804573484401361743436622784333001802547791369244639240849776", + "9463873886123148284658821006743738773127028085374512774108336456817493296782", + "14730844731649280962393329501941853167489718083427255686026478033565246002978", + "1711192001928176113133304634124607168411255230651216703566669475675133080452", + "19838345036438650089059998594294751335596538220272904678245824257362197049472", + "30821694440665852190257240751126594957860216254231711146737179074070886983183", + "42258389181206334056404458041124054479135303513841608711828428753306981127714", + "40496096556677660952616565401161180184460457613220070234389291673863096224310", + "34587469517391196355440063701824540045727772904225585950913386445569660286514", + "18895268835767204933651027698965041092549602003052708354601723355676605440739", + "32381894309861350266105450176780402033988372325140520264693342755909134738739", + "15208881079101974305562635224081805971997504095836014508801629756391142914852", + "15513102929086851617353389668903185715257787898198724157476547008050222914078", + "28816963792783868833063794302568773510733861951404301040229784346137137539924", + "15769264121198406047637310976403408571865364757817656185105076439620779361038", + "17714098552162764086320527789297848447877580987100807842906492474351402142015", + "50937232709814611656274652259469877100181441434429604516506742920349288929160", + "40589765727153022380968695610461572044130374424034758822997901695515664279523", + "32292901581122427768098906494515022754248338945233156177683825583230742019187", + "7700100036222513573490014663804526809356970321224474359818180814999222208340", + "24847591563749228560844414040011786084050053269930990046148164771258601744394", + "45140343194686683502286851809522726130825060330894527410783720110985383035300", + "20614571292869733156884188710004093876785902422698640809120807293332663186154", + "28855451018281425911549978487644061966292894377113821908529817963189057873985", + "41448551411034364189671727864751122953233717588112887307093258893456223314666", + "31721870708700458311219430833188248122154485853669791926430894369977309936711", + "4053916345609124986406666527587071437914286675753335097553836438758511244021", + "36789050764301027938100186640411291521701554125415168358638485655275417063904", + "41551912700430820189108919090250858361799134812174662948103266781775141586562", + "36837776136876464007796550670968906150471887608026531374387703283819866946759", + "42122188590463985139775736571784700100777067584506178049114735359338484091371", + "51555358425197651748397946177919419918385976221265516485130767247762975454586", + "39701690773326793440523237448630320483629804558826151138438915631297706046323", + "42157353849203790964566302919452095728335823193067338402797628746523603086271", + "38982685188543391659014702858957855786215025404679306003575288580912433971706", + "21320800476985708002335168440450264847824915503013088552469017926695451026687", + "35014096573907398248591829622085895540673171805019580446977694563807626507635", + "43663090332591759593616315324406178001130548265813380421849998964479791113386", + "8344452228601064117700068362088121196477493268776147775273463480242801616379", + "45781494358706055015934223513888020657767216577896114680464584744444745131937", + "33467379900118205083610616758439408352532256623700844600965355761397907270467", + "49289464383311973416741926103976466115992406766645459444726337742895812105387", + "8297176132367979895050278556447543612756660519892341650127785151524304626473", + "18909511992160676560865615408378916473238641263040399011155255609493943265564", + "28403215554477564400240476108137973054438360942093556405963748704105168373206", + "32284697207236048871441726993636460003240836780410789774515456412167471685882", + "21455972727832022634133849529570849717683121600306317542207425736915222072822", + "37966613826606212243160555518209489224101796260779174519152543384839305452199", + "26373376705688307544237021352967014492862186743326327359901675375906008102856", + "888913040404219490791464346828018749944814933116579488554728817234771077201", + "38683985486134002304454174040573560869565733534645365628736465704389391888809", + "41398984614751470222472865515296010644258742413853037348800039512841789888050", + "3981283109230681091825307488121480947508708310726712832607203158576892067703", + "39185828438588558188915379131518464636273345750166958485211877653503757339480", + "33827707363482743900713449393479388310391886910364209704974646955339896390835", + "8716219983603629585160327242530225317920480744970476539462076885325870263412", + "43447062878818282814398271985080482177228519590181808678872821427604844358461", + "31027313717284757940734780448763784962721233825524493612243415116769063532034", + "14706144459479842951716152267457582689690315354132182612165416297105120833222", + "9731384481219233591079036512159467510375906330825763010057701072051363348016", + "30553634363293330339627522304483837193808591921825027360665778403994462685053", + "45609533956166743936587023779139608084992945000764251170879888124320204137873", + "47847704668499660137497648431623946320346245151162623677917809356020718716543", + "38056563283173661218572385039374263860331073810891654595083068058824842867148", + "26993670658973421752943907735592412479903698483910673701632708769585668590681", + "30785459823368323785248783806005618762910639678919458170995539383143282216886", + "51222266624873684770581761791726071711326320644231678529486523861409608009510", + "29345076648373789763814337336153070632182695833874664106738644185576798841024", + "49325830872149257668161983669020549256160626846833264392599822176663179111964", + "38534254846883451222661994922881712410063235334605277706180147242343430305270", + "12302845844865342023702318149069274564821080420651956671830318139963733697026", + "39710113487053850947537018880864678011586666017993492832654089356847160961156", + "44707211722938056531780377636883511072417166842595053797519190857660776172645", + "22828704955530534295913742448904253088936787911676137615919570307831721660316", + "19865304854082330510387975347748761488439621474499270777193578348391174978676", + "48187363407286985063315354576987650774005140586159763666757793228939637194509", + "29819911619328942513733092194389994796588217536658225052133395039573331038598", + "38212362290400985557333755808544147246118314415292211192028525047889200770579", + "27586761646017325199994622717423910439980235111116357191663070996314302438643", + "12813373917894102436834016490102233395533576428058867437361605310168038131811", + "302963330853095396046916617359697374324369296158793631319274636584358102932", + "15968464224529046804614476367667926160350753960150807749705468158253809054860", + "39067411645134214736822169808547655170787099937061044820996305147812026854541", + "11274138088895759649174086821837151634923706014204135445881261441226690451361", + "52302826852127139513889364116662617639424064477648131126743953971253161065139", + "44716323546185249745896526430554326575517177607981161634515835226199797028461", + "32213798095768240088008712291931875623871695349482523000173703218338859386372", + "34958861747241044060595212406666557723044439804410301660122231050845602374384", + "49331229594826243054522004195698564695327002993093424792317420865791564435689", + "10956839418024830498215278860521725249247148815954712487396442932185064206791", + "26528434904530467838934389414677535207935099924291611616175367029507285204808", + "30970602240016594005496941331936508575879373500463039867150475964754208968002", + "50852594035255214818355325437672146695514999379312932573169216851091892785957", + "10428959791499118681772548527498028479204728352607918590213953646409081243787", + "10784274958860527028106425747196996826612035922287947830662115261587608582702", + "15387770184893555625374258860094155186740384824043288116285938876188706352378", + "9934807223434379460742677991773631572095139254201330705385004741587605142614", + "49954421148716069470844192200858239981501709270868025840988796723256496433262", + "50754394996439847104529385291639399406114796115767766632917252734345933111049", + "15242398477171464313078939838709268518321535564802227485663197408480401954180", + "28551831758405423643714337640190482021597051318716106880804323886508434704174", + "52042314865952702323407653703476385524996234808675396968531651815714396823669", + "7061162115671611024647470449452253036512150846356323737980487311443239991867", + "21693705308091445892841286499909589648140116274663013658416616911085984173831", + "9378293057401229515729878153897135648651310963813003671352852523007478044052", + "44488997632429755934102186308410966840398300068819080703427061278002451546070", + "2432902403191483063810323981689359589532525575996641804763113438209944546840", + "22115398057252496460300159284552178027153609041882343616367478550096550065339", + "48828085752836840401760212721895326880952681231516051287793814404232914998619", + "6848656008988757778373176885637714055033065292918266965729257745955042129579", + "49717910085180296348076030858781580143543737524860475731554846514653033040951", + "50956999705289978725642818651095647208279752071767003628894783773997967937438", + "6614217010805172932554915027351078871977375510505400961073154721946204116151", + "6659338948184431444159350266381737925307641545539165190456646064114195756046", + "13134704971542180751368672699051662514111233349539970233298092521474003167535", + "25615171325614134762412001645178160560051723094942727283883188340627000320773", + "4554113075120259444258085197552041030110139406762293060906947707234287854778", + "21590607955121543410469036877002722340921152028079254533125667021638414133580", + "25721077475420671857627349266060304018614510431320722857999763624721033719365", + "39059855572342429852459389108866845060202318322907130870131694201140269974898", + "47248360139753810427898459660244634029998683304314464233755481196724507412079", + "45772698267448181210954719755985066202769404821688224431639053202836380806652", + "41328056318828522916564951469201562944342765077242232616399196395910629499579", + "49003177385121106174881890143436076625201397529362997480809350519371548551018", + "27703235310447790685590157307054771335073553012159754241645182681857822932840", + "24430754808049082397703889460607130235638313185161328805244468224427616997070", + "18948678448259787641529154740875024009762425283638648930898810776395977448185", + "45099866019867049982334288042709351091607368617318819427970594408031942010384", + "6330562388951735111853498714115540964600859545546301981483008927104108014560", + "26844446011257250563521162555350324035409773386687625177480935411004614165123", + "9630588912504002954226860034154573404045725442590576531521466047638360149202", + "4369428140436853617225620545240900988824887753255284727489100852571135967155", + "41767754458560876641693405397509092401869596018756994592242585110359913131594", + "316733539055969076194091054957476209325469420954119902025522521961012440673", + "46079723625082367050206125655860489404252296079831070260124873759270291006009", + "46068817035462023271132406554092250449653236885477390229983222152584883223116", + "17663932846432631391735648490661466851438312750871829091910181621225527927977", + "14129520372398044245610937754100852180392856305134514153118275949573378620460", + "48348957513052792669831200715713306353452813757036443090444851782068845912358", + "33316880798949276287333841030815974044088443604424895982409991596634596270821", + "48203666166292939874585478248422539751048503268251860475278526091331925953733", + "32629921904433181013677595962652716661720883152986500744875009298365036770180", + "47213304003116683761538146428144306663067319043318294565769545077500859898074", + "44975375145118684992707757392628032126030768059286135718718624022522058458402", + "14395912355171833934659280542253077194333211239141833906089772786071331719263", + "5018636237084983114549836238534248962324525959762743987863513628448018516350", + "7928474284387325566544628537637370233167453107715981649985849351275817752494", + "5157850316742851916248214785688491502812115862098042652694646351226147924670", + "10804028725491175039787813929870963395445311136480859250226843004088508818338", + "36346239476583770449756289736596007596690689254671873093849336766501494792159", + "30420563423615031829212347128178379355832458989964136582937738158165653902239", + "18602578447689344907803395808474510541759512440634505575465774163982161795673", + "29028845669019412765758633005243017469691604113123990515590489705970287872020", + "9291488642164628318907190676979355777272236177112902842040039863190358947287", + "32662131954434851794870937456857249478864557350764152132201866324807303990786", + "13560042454772309025826220430464943558557059680976546630717580757417638630499", + "3501131939484048932402796435878801356302820031248529368092381904974151266944", + "26900507867106915526700545403820288140013889281854915689003620610686569121696", + "17083188777299633822567430660580422580964992606171218493480720062703183887795", + "45276671089202857010215472449822312609541026169595687558347287674112561413397", + "47115740039584431904195929860045984429404973521642945411926692667749619469107", + "9093337590451886669781164897242921157729421802178706886945153778736712176134", + "19180614896970686262757377118356273611215530498544504515902806115502072616431", + "26913459933699783502030503282437394328256693391239950382209323091118551247469", + "5885691041273956332672155791025593191620955141474251857608756016805079598543", + "34178211659594567643604513524991139385140010380469154701429045352148045316883", + "2654121613098100515579677837985313196104996226639365987396365807817531989055", + "48871978233993187622862649667038294129395604771901545006571985469987941847352", + "11771016559088538356129180410139927237146457803085518277434509246616826176041", + "49565147082393122541729780511786948368942276615956713961816317475637439609617", + "41884528350579998816132743840130703132118815479359952840235687884244111904226", + "49478937862653693738159996589888850231908996681740256983768081228822222799726", + "33007174588326976662861646782202164538676263911465371669307958976610711242102", + "40632680609641467833636588192092800378447491928392176945583801221175394510721", + "50403221980610547277005168257735060817596900293494173496773806175288057128223", + "28987320252956915129426998707933316452219146957929290744298299240697010099155", + "4485563522807084127897476625654517595931676529646946015407577488107973245915", + "45330532839929708834865514577622682019984357569538370931202927292231475549811", + "25344455046284656467998354953812195881699560755983162642813442591486642177341", + "1953257645151277964469597913705873178318638549628048141814164895940037204566", + "9924473112270590868362901043152302314314384569597765240465411680942798370745", + "50342411168742289111222279051777639713729096027982032722257947342105006557240", + "45158611844065552336885945557823918493134793873768386281636795439939726980894", + "32201751252829989048749093013725407085575587700080516857124196180489818610413", + "30286468919691381082526852492693130494853798256044729842989556419991112469797", + "30412615178862998787452855155029150173708524117818234002344922833737604891915", + "12817032562826112635566635721446319230638904073114171675112278696276922060251", + "50419605966653129634088281506481255636028360526019755398636818434984365487367", + "26845423050771648797768493997135188293706088387817088191773070754980214789595", + "36566967377100441719861317333296366412930498200119863070381940590818698762641", + "40099744571531705562796674419332023719819276270734826042001342314734205134431", + "9376262748751892864819881017970065904850832910699844051203059175396962165048", + "9089806558460966685372758591122708030181767774805456567261777097029004328960", + "47172170252998141038119401924144471778994800839802961275539836185001654231800", + "28599768540285119808611743546926126675476597703984553286133006395402163413817", + "40774894912411714939834603045979206180915161180330799642689674774237777986147", + "14148563128625218566414311664928498262885510633801511476222988573542818647220", + "7242312810599341381667420728188676710875277296043383862736917175816432503590", + "36649773096128885983688929983694260014070584380802171121062454387724971207014", + "41559455354118775074121004512888780090451892994330018212618968764464391622367", + "2842920233702069137594365917850275844667590592950833694777334580366830520685", + "15253192942995019016845068887899025929490110521939859465480423414593951300522", + "4583039742823086977911822164420926880574895679281946300728403763343360094243", + "38268693590152746595418660172144537364737083556586880840089414199771422258150", + "47642728266106382142053929547628971259179925653944595376637103144340361838065", + "2742996853083557269631615817061251451692180925435462472982320798745587328967", + "23489987448687572382489748102287137621500191638138744163373449027182480588984", + "1319412377707824997170437464184432379846687904802027328665245667327626917125", + "23420019641144629600502962819905294237220431247858405514755265746867756259009", + "37527116632060272307597433469581283809913438480330159265835662782963732806584", + "18389406919119232657896017869553414774417547615919821185950932810507538515202", + "19087455107053847811943670004824938254947435780338104729579561436836184664622", + "370704884789462457695619775843633910949248673343615225951469339465897453094", + "21974713296965865293712153750854454116733065440769766576785574418631933001917", + "9676569976266481284990459265959415739075484632122168421923611973593891826207", + "38248378901187257089251117826175949457104766663396284514617789440971925017054", + "4294505792530815929487039346329065154542687968920747825019151120581240532332", + "44277786236353564021199735444993743897156067348513266414566116406031052010775", + "32506685969676892626087540538707038628692482017248188883606441140401178135306", + "28363651659057862096589622662253600507908345705433345033791291474623539667221", + "42544586412111771193463962824451537173692044846325439043333191123735968573138", + "30566295040450901786458123441101437747641886821439883199677258485713852686011", + "37994965875797159195192948523953908017536526654631269771030795352558620684205", + "28978214334335551356953845707530787286891464301149326236654768202382347223819", + "23490804608565344911241113138948535389871674464240729140286957263527735008294", + "42860771319786319205482081874103732261202558080537173717030649042097814066316", + "40682755775701110632725347347716307490389226988480745258093807569321371295941", + "39992823493377850683736582775095010536741647259785820066571129907433910266783", + "7006869582682547066152582635224869432905848434554834675521166545776539853076", + "45529590474087428579847662690663774097692890294072007508881882557575014629077", + "26061143788185383048864973911762473831042799411987487856748791100150105438344", + "42306621780643571066896182249901806204147625730745275084712501590996333665441", + "634816972988661852251695404769462434099334374869607737828228783002808288319", + "14442029056840311826166863629738778557649157738201192369618525531638365403504", + "35040643129258546949915370972911339955688239578677258484437332638533915123595", + "42686640552417679103983721570348048788141292464338704261606435155389600530695", + "42773640424885963455875097209601111244552380600862056357735197523936943496823", + "38023376986642564683895319054493883417154550263835473517998071097523373370914", + "37526556239320325720182171070313838601006219096199590630909657888678084252881", + "34264930313953252737993053543935781331352619711891342308269210936866934913125", + "24523283981847104502625540905088505628826146614135916423822725095482147948181", + "28507770717592142808998065725294707726919758993274998895842236823816968387084", + "34511800852075074313306724213740166496367218297164892277048636146946840398467", + "22672200004261697966740652558329084352525923895435423795979348853568444273159", + "2414372753299795409914937165347088383473578761221153008468941629211164378932", + "41654143715773350405949670860776992316602831200329934559114494589736966242849", + "38284440417103919833420175596157680832908140842965001789750079660241895996047", + "50060319945112249842249525179429732239272525625895904524667201372451409465830", + "35636620523995728970610688258163392330088489551591368294787787608911667751199", + "15774770974225863548645722429472643581980493074337274599598141574289286701555", + "670461736582310495685790586381892242077125146628354493935465949609299361513", + "25390643730204448339947880269181654041828611063484668231177217294215040120894", + "40726073153037777633847249938016415093714481951695351581414342363373874704639", + "12307192994180562327168774453205294609983215378812257171456029758133595561724", + "6444090097863890900669516287018475837461924085915315479191188876165906565965", + "6015501456890066872538960463933916273030706505669134464250759025373820323473", + "48229245656066482021335314004566865642449078508855975021315891580289052319625", + "9889893532191114218669595996428894430865852687724759046433715172794664675963", + "40947340679338039314981816655373361522558595013117330272703472134873510834510", + "16103444666584900355472947137987683800214537590618676189417170281117229729641", + "8713934352712854733047485025621592920716146702187998186568917620850059947729", + "46468307024428239689921816068546958119066014333551407306266392430045587134187", + "44273480918428452046665324990302563689970893314614970542615565747831637380018", + "9814752986754682011680947057420484586520024167465795345642459599133555627705", + "34927546482543143025569911905014480786345876508420264035236525018162587551555", + "18553355358852382882042144386787371293563719784783451771228814332766556544847", + "40396041884333897763495026075406059133702781568162590723317553252585282843759", + "30787860933726913731521498412905722996792347156801992143673567530883787941138", + "41464039446721017733751047738018810041394761259425878342228777528670172441016", + "22946184428291831831287929457403294198425992822563462991381117319217928778048", + "40379058745972628454720076253339600096492465061339563118028192502942113674231", + "22181687715073918336581471573501944363757348049076517338333782567717081888089", + "49958193022966222862792934221629064460279392136719151389427118205478925488531", + "5265518771693473869432456375045714267384938085701552146634630488366966938850", + "12548327158274391633956670652500530639817744745513288563514198228555228376227", + "26243078900522523013996051232784046820173323566845465820621585813673495119606", + "36055903876416047250009362494366926138796330646106353641650980229137305194406", + "43770495009787397835676426795170907077240123204476137584855574400312243148783", + "1990303509265015866945533434649736028686641666801026650160601017039842330702", + "1728221424292512726310862568327420830093007150451885761943778882997848732540", + "16397726427358405900498297206155819893890166397493988179961231835025820420840", + "9277150089057878239466722680563091158065704160984203413801016773658632304960", + "5498089806580474450508440851056880355228871353216655047868646631789400607503", + "51952977261294039380333439874218634003529698748058294562149562006477314369131", + "16721285610652631521064240694457184929378397444806026835623673962806176811713", + "46697457084405485372064794484653235337142223273249341093472059693512704781592", + "45136827772981360085269068338286000830973948538683096475568562011952146970579", + "11720636668999239894276999708532919896799810248129425127225878635445312796505", + "14791900176255928665926638219703013453738211461038617270180421548977258735317", + "23573632834585152880967743841706109771870765258100962557858304550141802902602", + "37290070179368539143024853497480579817175920421375306448120846702792654747943", + "16402434651329734528029901792982478124355498325569520023174011908174943763798", + "51785066438382728508733716484731089252023745259081516372531646760508451753536", + "13181576645528942746355160428329085767614218557734277105669781590642531193267", + "20307892450803973996652511985677168420651505571566517799222580833105844870130", + "34774513237087522146201024974327538657755267644952080136301584143042691979255", + "12065940904612820612969009588235738886283663138324142597110366316946238786904", + "48897257447250153082218599809301154601439812859878831315446732667891732190109", + "43901712082157616288746701131458187659742568646974586837029849663203224659812", + "33734678181093675568854833212882155665646540572380786206209490640284849987657", + "50241950194231657978152273801580152511499030465091957768328222586117607912123", + "28046943884082291720307022513323438507705272251785659846700137040684398378805", + "24445720464617178356322587423234276200368023770695080626597604226469167565724", + "30715849968807314021431047526436839754237029446612944024950632530249266808089", + "774820634699550112965043493161989778494600221501352786693912905729904766924", + "7091523579567881680553209981816443157365236096496912252629739006757567973577", + "15475628993346247390701026692343631501969962731567481866537941093022448796706", + "20622319905701822982563523398337511231462758939941986027606268636026276921087", + "27767531687227545546892693855917272770236424517997551920334974309105093738654", + "10608501310978868005495512924353388295848562740476105678991235610605640877160", + "19767935855126648613420171572562662663992446448540931240988822574201794275565", + "28520212276321126152525941104711282072931169023022696055747482958295119188980", + "11445863447602102926769518396836283612190659648719885480698307390029737776310", + "29102884192967225925363527470069305319325154472623645986254811146515048090364", + "36369278870479514280760752151659605313259539065385372664931252525556621244778", + "5741349802021902033976624129224136833640445229422637226022201971861607467628", + "27906878010973396860922259847343505035649156527379598154470635574424852907945", + "25099093090959328980302345996467008508626086131641514022813633964945681523342", + "15941652398398956444535415907906331153573002083422932920882653361624580872675", + "22640076898648488229073071510958264997712505032208982758776406784678208694535", + "29448042351872739281666313410745481440745254135703562941250221546782676287058", + "18232186157472603671964971195185090321437119831854684649156331641892276952866", + "31200812425031786052041360811446653268039088419834014338422902869700665679378", + "27296181458408517915557685658517002298878931985074753917307111151582913624416", + "42335061640246064116679707260943648213309646091844861313130252111652461277025", + "49501897270481435327972513077930476873836341510540489960474375283951500327671", + "18883258563374700325758566629141737064912847795454411394483227308933684526210", + "11345820604410340023500576946166582635264293974768401581223563433249544440757", + "38566478828835756154760201447792264539807632899338481092186514881940280869831", + "50750313880317758159599047455511499773666245498050785338425415271301276559851", + "3875449008036363736820038005048906330216542693639043365331166271194848508880", + "33823965227647359149881540872514025191430000741294877370232872996362032068658", + "33844965576392174677847923589259748179821011233588403583128183360459957907314", + "21312464330658589040447852541958132554971487966655831631600092894552022779318", + "28030144027113300689044514918285829546157675527687144318210579809912765373871", + "46900940940220576478562281244096702283852628361984336570311553287501265484774", + "4579085965976986978504059267253955478348033162571484194106879841242840984869", + "52372256092284915725572205018366001225874311115645225721465542324259278331828", + "18223669367473580782281750321744933319982690394917258988324461796672589034163", + "48196287850462323469482572139859419003716975015944574190053261376692121191342", + "28994161753363058950486454179612669649180606087803197919444435154241551834683", + "7953603554248873537111667022791137432927769413475849935989483915561714096595", + "28221524068852358424002038925194136995119996178749335456693026526598281676385", + "9157710532949756353312299546465118107863817175652421311915712594617289873752", + "19193350552561005723938751236098758254032813091525408637064701468121509642780", + "17830826557676368607369842288942913836171438398140993472735896791162180445406", + "22113556015928583856233513018729708287907754347273116428694353600712802121928", + "7133249248527678023771889238324395094421207740430761000761183349130820175883", + "33429182205163032545126075140482212600447894902418935178706860336206338286405", + "48700863449499074729857500640334620379177269149918774849239136585396667908952", + "46884618606129003615355644221451917763171795256215015898547319215773482753230", + "37195803785761515363993713206540874871347189009324850754787127696797028648713", + "16170477241984049609210677848516857583104036758284973133188274494033028192355", + "39962033866559366380020207771447350677925127875460518964847411704230416294369", + "17924840809801688778334325664041403006615815528533437570209725399728093806413", + "11011806239111604297614227859676006406223882328410285834108701782153567191972", + "31013409765776568866620154998179754722934941957366602408825669161621329561729", + "37424127786078687344106151840709770118731482710721888433992571640337878210825", + "20833011915153125211537996818972689653491565255825216850456573045842314407687", + "42868816990590527390734811103858051546424284552599591573381926317350220790991", + "50541066639005383569305062768349813624716959173310665974747067322676443138895", + "34084685810716379304636550615195591077750618000017666723372978248512146616849", + "11044069222757134032019545839027779921568175190745411663271382740434815404911", + "19173021666385497510020466195337882212218681002115677692974520794493152622563", + "40613468040327250771752069702867902785905236230045971152832061758862147363081", + "51958650042344138540788548059349525076850214599749791518079050598950132712268", + "13916640329827121494788933994701299766467251502101802148142895159421833944782", + "48963359113290271551624417294280581920550185130627995226401693291235889264887", + "50705270037059409695978396156054729366590684788756836164655921285729296462599", + "35098807597550919444640807289874202169267577288211927855605470142317606751443", + "21821030125369396575679610676103596980862322270568993580761261195642030821762", + "30947469554879771060822920245544278156201787216845066645643610360768059987570", + "51105610544844649859940806222580060227579922991540385180915262546788529867790", + "32533543759521788985226817082796094313815243757866258224488063531620119789315", + "18562795784189296230800227707093582003394259103036806502232874304178883910093", + "3586178812745338105170917322002694923182127895950946535079805860349669293155", + "34638648219540501030734909730657615316747717364691295622991926869783650386175", + "41789330772321093366842572361896284503344301694835929525031893258028142479881", + "4566331986931196657690857687325908275180847437458013806842959148715240862467", + "45560958145443692761661710685422224751868998306811774675250866708786798452550", + "33753417182540441680821447613003005323348987498381851132788898208889529313133", + "17215707231149073506591040296296127166417982802304036304469207641908289807938", + "38778578302570826753703718274241846305717398757985312528177992783739825605891", + "12761803192252542361951527806120041697164944431580288334644372488997070344622", + "31230683671394091795262676137454153565153364357744125277080519222913092971551", + "47670679720925155853611954257359487450991977646427913413959119900524876557896", + "33774037299038604829962891402742054413332899667328530236547500818049321991296", + "39748439611897027300849016430379805701022422394053957646079371356771780237268", + "24917262737867116871649394177512708693209002928055278032998542358331790935462", + "13229539485364693166968616345545824165036276506937360986481194633106197221000", + "9173852320867156064836619184635936409983838203461515778901557117755714251382", + "20183000608619758017133191024195379512463464781777330274187562472768048002319", + "24698860160316479830638146304314998386620104551895758056061898735594836479765", + "48858468776550587515414829698775726122732601019060864167844910719415200047011", + "23087734324578288200953475032077475942641325065919591779982858916954179300366", + "47184217186027066742347739804571346673895445991507075364034203348481185815088", + "19806288990889498548568903590067855897003614132764264044816463362191109951983", + "794279024485485991104489628590135991184596516612535232378261548453948719192", + "19377179395595214302788588382118501487582100003956951974238895111244662002576", + "51577740752122254975215940516753540311249966422952002018864616210460080665738", + "25713649611693818559634156043529845065918500302065391115879597243354769727402", + "49680875948250747525400525654651292305501503222856038495200288357161772998284", + "9314750894759680521306494983136112338204818698724274351553156263558066255124", + "50748598716589720802099083771725666148085003965157890084363898910071840540868", + "46895063712855426517452943182429901070471340431265640488521837762375775684792", + "13535270005134298174673384917501440950286409408231035744125281888779209917616", + "48375135743711048381911420266468987317999396443282999984699960119911762624448", + "43477010470471655850385478350455575975339165523336797040695041138085897434571", + "40122989391848742604551537313136157858857486425951402156845713258668071244959", + "48392913986810089486741853394373068120793689606245359492457376257507349213935", + "12614399911559742885236226899657430440717406302975466190704418405798129139846", + "39687557869679468662083934543555164851908353236768087857551429231550793303916", + "17970101105485026292690292013381977879173179317965466756983322603430730611328", + "5692264022966005812026252984123477168698998697719350409712612871172978346917", + "27660171459750615107037791061131903078953745504540657160239130018204097811303", + "31794444961769069592818857487933833793207567009510081489730921613162283512868", + "4466290113398948729465050909074034009002681120532612723463757655751637627941", + "30811795228269886003729328980034645527992020736886164913832626580606863020568", + "4563189083745189167563329554519198474032178839024441358869643524396093176492", + "199557363896635809257454574423983365573847878615012381227336157996191678988", + "27157360993085973503896672273326055248662936262877449226047702781836282128715", + "27331158959955041061945283935507791117553150792857620566713051489146891533689", + "4870785918957576033728131676168651787600924880934333001462071795683210396140", + "33082826037442134626858119836786712732175450431160390856462707047324089036240", + "22773169567417213381972613277016880943565568476089747405877210640627158818840", + "38521511308109400208347296439616753270371654434542916949384503355223031749119", + "31022819168392407991510347956315457560379328698297672940485701538487077631355", + "2913684410997023904333059298168439938052128830860921463813385174393930275786", + "8677650425616998151660633699192332162853108740216710669958646977602898177509", + "36692168657523797319051195300876685532265451600789712531884252284349661595440", + "17333039819700133758809678150712189425572701074381783667844777632000328029834", + "28130765243140029714277438359942480686256189498496025577174449153662494161106", + "11853574850250445388003011343388397814714984249802141779671500260926130459346", + "36639665096321952500497792307506698502978143436612777825548620705729608061832", + "20181336486407191435775096917310061377928628087326547083905934219512194328997", + "44507837164645945443045372169835121659969824351854940710021355014737541055758", + "27871939123111558736043561948429538019701434116371139704331241660599962340202", + "2625015074615560737752991177989641731348799957893750761693241454507641015908", + "19522137942620077793947693658651590426272659752265997742883076802200363429902", + "38803793365198370083820646297735085158091207815866114279674752098638214678389", + "20509520936449693583898013500124374501822922618123203351269249727395523321952", + "4687255859605213952046360129103526918521669687413395864174192865143168444704", + "38397953238719091523539228918870732618981549730455077943999454274848782830375", + "46379470617045330349564693157117273103496341548360085464544446600226611655539", + "2104803082865779941377653831234841880228453570595703020269173502010576813914", + "27844475355374331367089848657747560063223211593691628628527514381196019330698", + "11080261998809632367384856485044144592209154548510390881748373842610991025859", + "43734718206592741350422660563740775111407029163031188806321805454903496422087", + "48371955285873083607127480062219714289561828946279477916628501493725049591080", + "30950085156541560358946685253792509544579361183191076471680147696379319296804", + "42794302724951760110945816433574719492684366170715179945979919688329730137837", + "1649712978658167225066749343742187083965153264047033906883618203855062276828", + "35027545511962181176840932783726415960103377835995443142513611299295695243979", + "51886487886450181815120305127998381755734391294738633811249997490191350686322", + "12049724946634844207375879477807661448659419267655236551853344700082650531409", + "19708698087872506680146914819802747754876270240738114832886445834594210093533", + "45446354063887752079814940711894867763625533713549817929368505177876992660934", + "23597229221801681805989378386206482952093790075934438273703622195939849766053", + "43773114006003508199971538712731389505560851992605200136721552194569122626564", + "44432663722627365405441381643642120246968642744202324569741814309514658364228", + "43246396584590243782707231947604256177450543605432246755347421494579630334151", + "31683409126968504972575510464617671371406929768517804924569487603530449954708", + "47783145261028117925245716500299506257258278981773757855431818331371389946618", + "8762870505137626766336695610895085829016826196890899036036721159952383686486", + "26663493010137872460610913463363881948714953035250615535442563062907413022965", + "16745038085684033575521797235126293869011869775691613222277597476355909679852", + "44704026609676731476784191281428184700223860622603764373522225120310233811314", + "43237924727464833955511153086885334331763987665401247262879429639152428518388", + "30599439792260662385476912877369429274003538706932515425794180455142272635352", + "45340320334013484272963951061632697460592105559945311283587013787112810755492", + "23490574998928376752967050984798517292925056659195855849582621455308867322326", + "50493361415952534946362911549495858654318363402042751028247391869927943435216", + "28508365750342750815679971527172126253706541992490953953477431158755290656560", + "50009754865928023372479414104707319256531742728501134632125458401115892185030", + "50856842412882281128302740429099995706970535532203114811941426179795627990414", + "8412300813933699630430544013682808834320181868657511760122566496833655124750", + "15657217851770399300282428955815916397670800738532715409066852210435915453545", + "25624610454209761433358917744746039576715883677534410335235295756856149366728", + "12787753184840798756381099679595885533190584019762371782453406061392673665356", + "48618001642278349893355193739080008498066880024247150168609553521808785836218", + "50230861877774402642418805707727568308444844344036590658237181156951431835278", + "29738520113606033687523027883838468274960299960273735314443238121715681323297", + "31341010174460272824478668916418173365235869031180575905163023524296285200697", + "36115454211157757847346257836254771919115139903524505683532764759206121396266", + "11199519127983593041044127762557798027583068318313131997175515321296066793949", + "38613521641851862895228394220571127408754314517164632561152460949105759499178", + "41861599643711702101374598199112375223189693801113506009474907392528157327793", + "43742367895205096690833671945928988673232344118874250384263179428967663546233", + "21129932156028795045366166901583372257393769243604104410492841026805988026453", + "11965620859848783315060003935686250616135925205797734433288824643020201382951", + "28006159953080268647013753736227060222791898369198109821268187678004848322400", + "36076468151505924861123538491607218399162247482231063633400745256872367449944", + "7051394804164019211863990900864745116148057218009999279333708495621571592440", + "21298724739911482204934893296793006342387265135543951826187418468023760996707", + "38392446299718886910553174567886545452747235211428872987170940727849368847156", + "22792115625894447120174277222774677350993364020949518283045551670453506767971", + "25016360260592718974732911182211090959295993002202845909448395542025839936960", + "46911472675112716448870515428430247605456872113170436030133837953126175507442", + "5335707646854840965315582607056887964567825750039131439820576723288370988052", + "46093533203263240853261875077901743978051349529751861147985537357638588125588", + "7425857456576700514262802428901037740251453955601743640683344851039553695934", + "42013643593102068902430284695727077729078094535061834875472073790266038032607", + "34030091127296427281469669971238823782511764173503007226416435207242261696077", + "2060424307554320607325035441639720906206005887405337889386755844302515896876", + "20068915771994953638854399505007627991407086651366393881897799303799323558623", + "34096984682962797775451276911583765375325136590790978121176780008789636147967", + "18790622226263165691961600621468065481125622358825318077573716175537655658277", + "27182236699890064265356233158726323690690916031731480343198603869311616854649", + "9056857257027806390087260779918810584913438930765444708385433300365036091452", + "10488171238957013313679106396847713762360016742167740557905792717106396794512", + "7111050208297111358399877301637174906597148655885881826916579147702791631469", + "44537615127183928563133325256073888464605920603533886443209789499081449814296", + "31525540943097740274854422921433931177319572507515435866509796988034514055488", + "43979593893629513284994095253943278006319090761269704325048420133443885576805", + "23893477959894287278683011969858961625194076839677788605463068410677525201521", + "48142218270365100663336790580695397893931072833086822037977611433643843650622", + "52310254070590224411898619195728934191182835578470464640663619302487559910971", + "49596406516543886829879539200347577490681219355044011267541840758556922928917", + "13457396607833318646409527457607916839490932655861460978425143373957648218253", + "8846759173134379282687187683511994417007633783700806511786325574202958125281", + "4442919108909080910124736857731605230330643518480114755184170138580590468263", + "49518695896054079709226991789274820326817167262161716431370683516017740493245", + "38719319116057877100404193520085558063288254665006529576333205360130117587631", + "765180284660006767182717753108171246033605005948357493369149931013519972301", + "22207067369188969387097726048024244446819982866329414235521680002045736995519", + "42461240418257218352842172844707214509400545239465678117199018442851130091583", + "9675803914268175758758971643435757013573881664277711371519440167020463229527", + "9297886123193655541631288199407398948745644425117231745526413111863663527578", + "46546439935463194130628229845266394562497339253497718480519351875545462350040", + "15803807122647210533225841826092333170412554035847706962354643972171551302787", + "6571561130547451838202162779620510086432411786198630572668779780558701482939", + "44987560935964874083030357428076640862840468105606050344556639397755138400437", + "29996413814097160057764617692542484448742566414855968632593389502581100588297", + "12901800264776896196691527839497429379493728289431394150644796540167950793748", + "50038613064695481869084522198823403444807978606852240245542401713721086326781", + "52415793460958409276318021941933047606260573881416261353621067676622193253076", + "13534049232434025527601480426138344382285579433818270609857343243417668128288", + "46755299653520540123088094739305159296569975875138410266784634353584907793677", + "37532461643737446891754791338873097347157079259358340434400833911323146313318", + "19306781954827387836834515995146326883198173471292106605021506952630541432600", + "43701927093857401788909086015867617585374215780425279074631914981356477444767", + "46526989842505623821498323428832464787445971269314744971690282355801758181771", + "22660631379784138701548749017062779192576741659311502489022769447241849263656", + "35871080558600202679157337169640964283408925309648597157862671188140381317582", + "13179168763665762282572673789313480622837951474214637183128068353111791531717", + "11302505747571282190055015388380474978091819312161415561243807282456935481469", + "35318656164425501575140002636835661267375040169872480845175673909146555043842", + "24288204442285734519719525206853323044758153235352908875140155785676884013835", + "33431141088090872098220126362814257247736705857322983353421900523521431478780", + "31167951461393692499793217731528080785766392587504107069942572778405539032587", + "9591020246950406860559436039221575567418715176663815196404772460325015836867", + "30794520581990488030236973070066092220484200094489800846498261295523790469326", + "49106396106869099767545489663814860612132078111769755743238669602163804565203", + "50097682833572201211171329993704168708424982780608910217539106617667812530464", + "44317233581356484603608243083320433065412861800051471828148844904770357324585", + "17576616344228999418338688045883145037243302539786405240724125123164478943594", + "2704030951037814588964206166191917277788965882479787069686934970716392703324", + "25970070246941534068189255687183059768983011231033839156980494939780979995727", + "14199882874235758404688830277438191912772673730064331707983916303331485893520", + "42744803471214700550328620101143572367479553725524383461741144283899339724680", + "5283978513013862346468084992605715057353561096809787461734367326339391120492", + "20687106352026699185096153579031675599283381900125380540310638109328217262457", + "6906701669692187940310053540954236275856779219413465204290496179183330582772", + "36216348302029065339847635504157843059809564259506592611131531339410913007634", + "13200642770528984708098212590442516579171798293661049239881900610430939654165", + "33496393768316116081608011174542962423144648237916782561864760390541818962591", + "6361919146925640700908956486331100741064421809326352661336774258915740490332", + "11176633991868337359911530779967079961129108823046014426841328537470496429036", + "10513440875519036377030478739365043743564532093854673857606535967541144492983", + "51300511310787873870389124614056722345910288364219850819658381026323310025849", + "19753414999649416439344405787572714367263488632494906250890246216985323155493", + "38623477791292847281384922863520228459911904057568315983312905827239694640151", + "5600024611171694398412001072975956889497496425318593587598596318323364323940", + "51029328223204516187598675242923287933870430450175281958990715934637331520589", + "14378305800076491718569835398977485014928684197340644282344824915393746342873", + "11968145844083112790175554052396893563194463468528081479846848659127126404506", + "10306147130082519975698980873054656969456703974360277197005783059443665064759", + "35436942507828122018173125749649325292475048590920551474423353801753849468922", + "7488779675295757136419501293587352142231025809740084033730710208255061953155", + "14018951510521976315519792622055148558535512637601772790873341617897948706762", + "45329344219531887127940190972718403648951031706418377934952396192910304599858", + "51339304594849836202087303909012585228506538687893677074906656040070755153728", + "45883269526993892566134424370191915400373319780507108889237222553007926193996", + "18568186860989922809623001752137428298227187918844667675661074558349848145302", + "32085785357461843097593634739849961808485350477478081321039837059842472696828", + "45155133332356684488871353227240188524788031433536181188485333247320523008868", + "30152744322083656006184386590107071962163547129971413295036040527900437209242", + "21536284221466686206237193161875777198309466472149467808125753328165315696650", + "20594954780062227372462362015959853145984102070735636835812994552664847557176", + "48376893181428918179563395502050434923357929653107081230260863503235258448301", + "17296400116564770088522416008035686547263377090680407130892037649460150673515", + "38815715437667809164667085341925525076838819838497771803683106901702132079425", + "52237947303492322721632626019305687526695681038721139773632643801228008447902", + "2113459543480281952318754868603606352667161066180315231812310549325801123018", + "26412633547298951719855692526073946895152226023922524871113076384713962560124", + "31629077065479501487751665676558686356449200923395092168161866474258691282395", + "38856363900052515057078718982485564996986070788104717198468809923977195032408", + "42502968324777221766192216633591565705219033277593869089067378728342048179768", + "47883073399264201592317582289054942025724036869059886766560231793297547983058", + "6910706996708930329656107509253892901353349396754155271956900675122233238408", + "42907493238891357766708183881223545215246621432111317079856164831462609478846", + "23806667905845326320104581525336266746871848614806660146668803589015912260102", + "38542790713056639725105332025061092378256482420274106902693587695306643632028", + "43038324747323338638687824366735426692820718956896138052879869892646024276441", + "367198476338570572924784752191596906735031335239782984698712374082221978477", + "48405991031038543894631190245718907977275650880699247335379100370841257800795", + "9887828365769160756215303395555941099958650829117725510388841453976545513133", + "28504970218430880201022465241059546406142178570890633443944136680127635107340", + "18035447678661658840772215393977342721670798001326097943793894885608530791002", + "39881224203910566887976476754059184678215579118802614439981760789092865205574", + "29214828552460152099356502868405446495621043031599214277131181651235445439551", + "37586745829823785655450074398299105230454805920375201739241953831821950932269", + "25016560920730175651251198481234087079717377088935771569931881242164999359500", + "15585996963630833853070362257388751726572823567589771103917964382584748479729", + "10026232571347002013746799594536285942769878601175925908063646287173666765297", + "24421142005259869782857684564924773366082521611691395407916980655147879479406", + "45457350557529747749227482976119285978820182603615312320469126576892512649658", + "46412203541849006285181025346528037683223203131865504681901104652381050931822", + "50917096312348120920246713978074206402957867443505572723687198665613966000883", + "8925019176083329935663965946519181169597989393016347560353305860856989678366", + "4675385338838906191860374330033052905906135213872136280101018768408010742884", + "40675045214311564746492359544597164513530659368843047121550496344789916070041", + "48107177152931453119604475762434125779417473273843273469458880644475627661385", + "48794332949060874933018293131562774511826328539687180887632019545046364597885", + "16594870503367905266348736142793076337147478942380114515579728690355327057181", + "37046009503674838705235512169377328854935911759097968085723512007720489327080", + "32145346535149953350418033005751778876600896104993068895676830769824591999943", + "40834318035659358695758278698275060492390938744061377251187854583430740723771", + "26116310910891646024647596172427030768256162580734079273739214738170722023950", + "52356498637848161062469937659264026594141893018389753803888549728849304643092", + "12987789814055147624078935609101915877839432485530151136547377766583243701340", + "51777812367142537419833703551319461110102423252904678191886514423062941012459", + "6940439990227722264480683066903990130270272508800325313764252461864618121778", + "2918080361555132961406904148703716782924271874810733993220668899222164205997", + "9349104718667365431947186969650987699474248292323631689983865729035852753357", + "50056471811589616759120248035872870443897823243392811213679543543666886465705", + "28880602259876669208574458420014868263594912107310207827868188173553954911356", + "14860211398257027615789446768845969265307861017477766208591479514377645373317", + "44415613319031323933396315267318541920625976123010559879200534992807762793914", + "4833192663723614591570645314262509341208649707539760688933412616384058374840", + "48825253320793370134275379708553907202304779560072520808880684719521391594806", + "43449232685529597504548262233503423534662304416568660357713639471659395648609", + "31189729657305281106207890546335056390410558926257811471600895775124323964736", + "10657145415967046259486339579605797462806131801455217616856159620193687603989", + "20531156045132790166920091562897504262087064509822296769210507300642758871307", + "19836039903037751833534099476562945906880722992265228234645591713473034278357", + "9111479756400869858868768337220478775663777989403332842008909695265696921346", + "22905659957016264036008584978814284447152424513703007115744342253147407261935", + "44123441755042495198881177140309049532044521325657851133076599791688597832352", + "49348995783992048927733552465578191694984448561179738408861673348895103048724", + "12177182841690469593499268087554990394972695728621261382306580674975185003216", + "33051713726148424448504118957608548945810857155543779171724168396307735643443", + "31571127880917660053637634134589757038647933423660512013354204613215167567022", + "27078270311889637229024296968947977272026339213289780732610898817246855807459", + "1506358493833050999396512780115758944113632898683260818679691558544944318651", + "16004569126220897353922921093888884979252129224874990473381140855393280701469", + "17041219034398008716677281400757742124663278406538932701301147125667923912341", + "14077577600251534475892642126847901009158780019891707162772566592062721541444", + "38163929425677991505344078549881468986244920147013557934048568612254907136620", + "40553176377433096833731123976355141099244432288751404495867354107942667929046", + "1550862720069133374073556316991215666095691829551584602944580038700387589606", + "23312866937498467422575293948432079739688803097322014970274534411393241595896", + "2498690076529972629400870535880084972353143057135751366651137948598864446103", + "32933241980944932950378332471268934177320748139894258248683971243998743673633", + "44280260615638157404572329269718219635287037604702060413419997238347073075456", + "8228901037479515863086494016256566522096475499899108578092925323026762485467", + "32231671118293547991537899558472046371695809248554972968182174317930893757810", + "47680838668493468045726396625811153994782262829115289046356564519660184138128", + "21581054729778905489147036087141487743715812056892493031812139636700148128405", + "24131783997032270255344412857277205381011436126277679863814396501807503482764", + "17165147989593725209289783285743121275169694530458570383904419981567102289744", + "43117882246977220862499037731535290684059639931709119234143634526286012830980", + "7457605011946473949156010930092687535159311223610185639278542589459029697476", + "3766298798424776894698420420974883667189054255130974674724068766865995601361", + "43722812578485927976110581991165708952759114995548148874575930185935247875636", + "41851231304629398320993641146373782367489918516505223212092841500444310721967", + "14322310454736124012395478911371769805552598825732806271218133101961082864069", + "43864155882922989328337592006760167493550093977545311806244191120852516030729", + "3269882161174260590016848328197328386545937001529392175739620011095254070437", + "50468205663903231054577051106142842075427625015337723322699980695959130131849", + "42706280931142654268814798814516658508400512226736752827382423866091579840385", + "25627638741104321296814751158983428085107604387235407408158677194665200811695", + "7393325033658302589597757454403129738887923660121205707465046544508988832235", + "7614938186685334033207568330326349351462589130215986447130225239680336262940", + "593259180994765950828478367124399501817700899533517481351480468060451483329", + "7133450125980100099972282463220992826006947113553076482762677372983305158628", + "36881258553478482961538543988875592968214709276351747846335528744186338968289", + "42433029247931104112824844508544708806428474165300770449770522923957064860253", + "38891676748035831716367440290069516099341305630084804569515149231466047781969", + "49487503418641759625037027962044749104694580362709908928949653364203366387510", + "25021155270144004949332812255602644643437827983961204887189624606965774600073", + "35442323207493525041308924995511252847092542407928968270475442589366247745349", + "13592843280973422147204215088630488573439834681163353628088482352513898151001", + "41157312275904367562609424874266496620285249191315459542109301581983937949894", + "24382591778041633272817989220464564732787738715791828312137160594407444317984", + "29150428339432129442790099923255776911972642492019117667461913566823805791385", + "4750730489469721018897704733799266889671360336506666184349847974732343214621", + "10768649869250903452967538613679961218072948274265012133650682087886919674833", + "7957215528227142016180620342833369242153698748041311968934673450908337508975", + "33373800659692861993347060794542004538742984258551619280444578233008378999834", + "44448759107693854371297743562960014530160601354894872307292099333681656056574", + "21168424682902710266416183161067242434500622212889928356692906751791216979738", + "33044219036109635759088587213854083797653664299022533141617215190471829953613", + "3845460561900794626516390435067167226701899990723780502343474341297463978767", + "48596902255604407635296698074354099753057175800376635517634569019192353625584", + "10804997083085185195166485691748572845367446208714744038021105678444328520950", + "41783799266290833836179616049821302499819047058248974264920728862873517346228", + "51716479204759127431089310152011288428068146398080474158850454348532402358216", + "3355016366604581703644615068837873663942242548301679033003068623436844370493", + "13379930755059278033074012224580298139438902110913222302671909070453641687874", + "20879015821188738353188388249832779341291477011431937084841625633229604385469", + "47643384011863740124792889332852949628973087743965981153077805819137548120094", + "34864627484842196580262772531336369893767809348418942814441044693192229328023", + "26801087194826226356638584559698785255269281101839206744790488399027269024787", + "24802041627826917527939248318172491730197046114958602054418626160552124810104", + "17393808653114744947159916000979527506320327595220115426883473406584203907551", + "36595583074769680557592359588776168347044343881898751546641890200405993646361", + "50475948248358914101160077148622755584901385067996164730645195870163519109843", + "20643160275502206195313411024872493339086781228790116506647959958608414990476", + "9567769377744521062779511085675475199326636912690625585264714929818405363088", + "31763337287678847823712921476690378557942255529050446990532009088612817178165", + "27982758968592721672854853837638321180685554545172081299398563052239696555553", + "32915536331336510290685184590167239237049775499997832666488486930265172133629", + "16246866445708412139082289133822343881759735082180504899955667027526122030639", + "11030253755190873546736651425118680584466941572957447679956506578189366885424", + "5370224607105913069807194617164101417075777767006503134813486224106896878708", + "16274853568862658426722166099775571118787199077071937421394163927969291347491", + "46400487231913882150016400317786120288023123191264293976302650710383677228774", + "30485811285975744012871394954300445338635282492040615372456351282421362663906", + "29564470166569704067055455516719120972571841594241886461973003849644835393120", + "28717620535389808614530406968387335891585691881656128434147439695367925391836", + "32255161690207604830812059724823227692583875604742132125056805780405679533882", + "51290259986142124456823473197590203186111790043643203129055087556843277850035", + "33539109708328518433354449632782759004628387309059665966519049464766316278342", + "33188338966767477528212399628749994323771247240690020026043381850868826615853", + "26483723355441085613613052353424654293972496797066632002191085812994089020576", + "38870634465445886737359245024148558135290634611389981261809213003096418815518", + "12867302819539123444321463052731287575021371688738084271434625142048735140721", + "21454496781866034641331130042097877800321869880265488339203376506443078707148", + "41203976248790753917286103637147352157116152785965716011186470377100314075042", + "49633387786236662888743976036736800694176485598467480498820666940367106129474", + "26626738035066883647793157089368365710832867784886376945967056307433041642908", + "47668902276797823430061820014480553174240008184005680942232719989493193219525", + "30936173359381313071718184804587856620600981290071644104593303812498054105731", + "44969109059763613622356060204970467954156088599033828270619718949186179567273", + "38411949731060340075762680805742159102543211923660625796097996670097923148760", + "23462688508245683521433415910958992012327440646909745993746007988964885373177", + "9703646052829784359584834032278064964019743547840006558309582798580638819964", + "16381768848866172979520144800365113542640147475041846218721062160338501129584", + "16837333748082664235417915277835995986405662602125773008922838624025127681279", + "21653460814500213581851391513383757388138787345391792079852133357560999912049", + "18695529591490345909238351268507847581568311749618220060227622840156950624822", + "20953025488631365762097349562332353871507636134158523145364538770963738125203", + "12513738860726523254529232740164512849790659695220801041585806489751101032459", + "45448932529668409119622808483131733592128166089267541603543278360652582293961", + "21879071512084631648979685760674931200016877830346253322286404942424445231327", + "4251905105290877025397109135924356812440637103043841988127674164456871541100", + "23528679966007779913490501971985725552349859307317916379876513144114268779181", + "42786223808177766922224535621354854059322497249856859557898350572264146733501", + "49320644981396667310372095543753237139439470090367983353641582752887360028535", + "10396406911094025396661741814447257817108892899878508697933903904828001241902", + "24443788034003937447245145225389788386360415244475944386953996476414144380034", + "34420065813822849409034183670235500883024552413332606967047621322907363437970", + "10836289521051042247358164388806026441843866954674775337950770190079409077309", + "4548068872690315389666697910895112323321875219336998036966967740868360815962", + "8432438263303849518853241081566476091839897655888081598701442735935231584102", + "18127693798254031147524249193074919808689912801316041439171680364879045209848", + "9006831162029763679982905724367186688608289268332650292695702286475526430942", + "33096413533204898862805983985647035233109479557050564282625614923177830867587", + "51530097119854454914260690441711876656998030340759322189042125225316844495345", + "35979166429581069631410853437829925640381590470038405943223395809073248612791", + "1562274454954565026427654945345844979412108477502037859418970089008035718718", + "25892073619168920228211256673872223959228824956202069714640121494491398477950", + "31578052928819061880930885578490059175127292805516037675142940782415280229946", + "2245444860443928975548007495691595411171825087918960956579785986732116204040", + "46996695076163569264808889961393803751356393040074471601451290475836282981517", + "42365659433541203083109453373608722043521455340104342662600654478058014869233", + "19301036404110943933268798088639217179780089519217868643878469697825516879580", + "50235407507425568386120842400480692462968419857255991255901217940557907015083", + "11917994939816048448655036778444377217732607914566657638807380548630446165447", + "50368075720330677260314476079202799514567222773890240341078937612799806999390", + "7841236602688160178005276930692444532506436710940390570602763700422580305624", + "14996437544713444302485761880701198026218225640647771585587800471689307998211", + "14344855692649234268067477332274032408423963133696044477033488855056412325947", + "4268733642669424363695143840219917048935479598869975494137863218026560675516", + "7807123319119050137068120680106013259055740449412599032473342362350296690470", + "19307291827272186986320425334420914493183455604655841162485286473349618341982", + "34917641071958571448607169693815175870961647437330440288906514747775937814317", + "41620412117508933486290374321941425294504957626752984335445579053041657045303", + "14910183069686316233798452985001543271482606304344735079545084223767879002431", + "30294338488305182784898673983174803958003766401983755861315484719927208226362", + "15819464174709500651082582851744616618314228410979167911734713262418783733751", + "25669850548638449028168606220552427857338800047137217898034517507195897848430", + "28412763452381469545729181542328703701149869533220675045763896270285952935532", + "6578760723722483394474496521549780458780712610168408572663015091157477335534", + "10598052993705148018309112601039690811425019291036742265954888058175008774801", + "49742119802425274079711674493239954425638890157570688688555621101459613400187", + "32711628381108183102645277483221531673396016636621472095325274667411424699903", + "33209931504342177136711229956692542615437479645157419045907435509765106252813", + "43930905466548436617609603724134298448952739388613441958522937388353768583911", + "23489920137299230247172224978941001571642977282315531962932397843293601270008", + "45839459422299869903406038561860670815668124932372110063009195854726020375108", + "30963458406040697553973540083788127982460667451041762260149997274649284974950", + "40123692247211138500512584243722123187992420127478768160593099931943781220526", + "17545601125776521892841707603025355387195656026620639122769662982309239922289", + "18339211719922696614284356770157484279168392749460687939363517753979065420511", + "16871627938935914691643973642889705212662166208227536114447519099902285415836", + "39825230154955495867676537112349881980137346289525283889685915751180022931774", + "44933669444049781424315520435868214639729888731618909033250437042253585348591", + "27983823212609767644938778091724548644639934965773907815966224788454971625201", + "51411347353421840614524296462052597148594077019104315506188729562546374918398", + "20199163432055772485940092454395186549722290509585628316517844043503506132628", + "8543752659099747055969885934363384801918040456251774632825930204978009258698", + "230887599252333559130623841824378508862610354945379821369830620566424249562", + "33398997102174049975136517937126312937216256555588485017844789714171668396274", + "7035411936448646585757002281856435569407513652852510109230821524774501219443", + "42451001514825613300292879543753356556961041336350591473253864414975710247437", + "19596720502990445293075008475299430386053678886054275092494405044686878190246", + "37834401270729649338911194531909905291644919415187482530529236387280109754520", + "8177212100012556630747108412538768633142130324968406354283168302746308638146", + "46130710014886108792069579524096488417821579029425102199548289269333183335785", + "18472194880861107318098327387743070809818170212185714277032473419360099769580", + "41166297306010739218609810564111288607781713045212185923566948644674473845940", + "36511528672472626100689738591913689034195420769910540772129042986502967863765", + "155416905880692730872628527967848689842275976488925224290406119727450425665", + "2541483681988425249285248900056477530676396461385545458102921189534490106180", + "32440859413391179060197604037311742783980936735095841666347592483738729445896", + "34666596042133152912038038898674083317478161898218429125900332549809169564470", + "38266991926376750042771899719138943392558885990589008592751641059089034869725", + "38399329015857761432847134427932686126615423551906391058627572809948504790492", + "18639530440228491415074569711418632040235420335763115142345094925959344684881", + "46921684343960019672088235768915847130235817986739993667129586812140745411565", + "20559667457448568189289168103529920593138153088190424548604830928934068594350", + "15513334688571776631924659001049908011623830329094812775810557995659793014396", + "3420879078813003972233722520183724365174341143497933666100802349507960514065", + "3999016152861200699596999188588396049236739899208496747611321011597819313484", + "50265604847467256138064572957467157943822199682661504358468721226153491020903", + "11541717926941788276313912801317796347448694340424223060165408006276026063868", + "50343807465638816663592423797661994862812331742903093462623518630290057455964", + "24053403559075270305848194476832116258935483237588811267951213848716792538274", + "22145317296838181911158041025158936050840104141418610310679780359288409407203", + "3444384503547657151066511499364098373988225031418314496854767455271300068950", + "13237163632069364333963194128170594417244825676985204072241404030986675254309", + "4288813692511708486354526547436786551546699733752723774338852148261285520532", + "35554858313567382721832526767078180112210061844672727269884773325198182195954", + "40537780863573548650775734088430122027812334133209969989364155263600291375690", + "45697523332662310437384475180447541891085585505348507126195286963426379770228", + "5525651241159964477623520441421958662474279875604675307294706112262484007263", + "4458980750595658878084564211413382374579728886377602850660522811614672538203", + "51462940654848198487069801510329904696487623752628395109791099816203399680607", + "39575207275483620206514500353077909360755661223791844156001310420810497279154", + "25476351035513384824846211070695734383314830335546049074257907740750694758932", + "51211225523714514846625337565850376604779910843963574762357746614641122524857", + "40155149635333614744253705047754911999263470944038892447683702547970830154614", + "48390398201560618807362954011710595657049278694437347668304546576788818159665", + "35758227785580689049223104790275669396808832214846927586957702621873101604478", + "42200644356742031842813197670409564734714690977902486738283512959567602027086", + "48095958810698189710719919895994985170489288384180033752915646151224348767757", + "44809427803489176046787584251046031417136003690341335896931013699395443192513", + "2269612694250321282818273221663061682358366065395446799815793511851463817445", + "15498816175717581430204661224626084018031485163714494371379852229603041335359", + "10278122719274579889816764277786080874476129329153063551358616382593044512654", + "12016552282393354995143296699210937214034681361839166706455028169861385372264", + "50175039526680119049619013783184945940324861374943145476708801132061206366618", + "4545976067256395471272421180327782449381249055842484381127767174750360741727", + "28677244186806329978317921251809328256002465999628874618188062257714286991604", + "52294131766377577472738258905264501392377294290556565964911662488716940066022", + "26884787427943092889514462629090475864337279147972166088029760075313908060568", + "24149297717539229948758747528480512641753223255810862212087275533242974498500", + "26733531504691563426512329021066077180105305228131832981509380639698176741462", + "50044054173024499963989655067281048032808988461396727706521985969030009509583", + "25797496457556437934820179554457787510471044407841129171290042887002929352075", + "7442965822786938867040141488040803134065507904895362988659402741724990550813", + "16156964026237018702802162059604028443123887103120738860141925982993305823054", + "39004544877702372087755553766284134053447669374308096979163043418252297363403", + "39747133232340977492487232753857645440071111136458683127778226148872167312363", + "15620599721823910604021810941867670709065617260561926956383386940846831501102", + "18757590663203299258274135672321907891579924090706320638962576933319441136552", + "35309349969686299005016682283087205454250633816480330095228376624374168414521", + "16960892090698977276412769074690999508376223595175939030658039874792603258402", + "51723198662570306936397744570978263909707304583187749149498559241701996545003", + "48054040474358839996886718980020514182626551346173382453983890707227628656484", + "22912474307211796591300815578854539317426910304997196958737902553556432537091", + "45235368080393380174813393941470493952570880238229136484576525130124674458773", + "14093696594193786431590196220151395144806231091364298847175810263263615375415", + "34161751818016213590823620496616628240369009309977052837562206847768209922859", + "51722410813431954739272755463652135600331546740816228553966891796026559870103", + "8274821650247039283264657225272666099755331809997242797871355905047925532451", + "11095904039860369389256015603245413006420585481192628894043026929318400737444", + "30424312352494090474277119054302781059731730871464573796757584208038309259855", + "40579242649281647487587372687437882908474436987878292972980929935830996284102", + "19454288432980083029696232587977535397876315996879250953908512672179742985087", + "35978385434908421585197681194330180350578605670437054635617471471400494119032", + "43475552877318766506929753246062983829358842756218194235051166945609642788035", + "20706168555192738786549007461028356040495612119987764640884717536153104498324", + "51867280059467871836929026226672932130392316335495032250466190293027440419817", + "21032332937245098373923528172276210556536860628958821389952831587874149487958", + "36858278235691115548926638028624712333967109647196840198352761568530707601664", + "29373582800177882515591182668428757866064019312398138059956680241130754293111", + "41937691267416099330447682059576948514084993742438979481097591729098023405997", + "13412103422768016087444260616930759212657217975718650230350040343484730771062", + "50464690738311280209437035413479921184094355777258178809467382530918156263930", + "7349245009146581856013132078953803881838129280167326652020723925998281174508", + "14200402674977353908598260195137994587343563724723201026671057904602150138171", + "16621859006034084064512259332140044227366945871288344149550745923509347721710", + "47495383032506419922337630674002312756059379519424434835063320720471418685721", + "7381137877503447867958548162510897884986340468846145187102185391888101628009", + "9583899241008002985625400182147654951711233736560459479886559378437884741114", + "52257317753748733206895607549939362158629888037436058776552768145600173898645", + "6337260220097043912858165721775441845125384298734201691090476527656011793686", + "34188859555634569097921929210158249043626454183911891386781764901581803992943", + "45713526744313127091159418489683334647452585813064179824656444661743862218337", + "31928434682128921296275294130243624873420099986121331620272054437722990948477", + "1976463721892749021004337042177487272357663622315888153933420733160615973115", + "33321238092370859030956467961430579686079120755006092084912212182146703764446", + "23030921943050700662822029553404291714697166860610189908081845543962161048346", + "21160593174830788810466696662118839253938816917511055097838418468260350972437", + "1611358703613358409888950957067958726467315751688310539838901643464119486326", + "11442633024604306361052544983416719159386838363208092059432968465126355017128", + "7244847937825343105748229697848713329850686568522370291647192655432141206881", + "19464803406275110041339503572432715295474799451415005874776437117686136125332", + "41049818131347116186323221833011600662591746182566860044105303494066171377021", + "43121840400590738890074465599276841646864572054167726130663097023705807264515", + "536345624528368003744720032933779853381371252861469805643606866096908821212", + "35728835326761217844156279981898954041677836600537887121965520951012261641659", + "38754309322184582322044281482911862792953535642113419253962429405712448350002", + "17101098981040767580115030496739836553526098573223078228010253783828617784283", + "41368381625458356985481176823678110489035873682434054563702646812300330242633", + "25510851166362289164886279116945263389027835524268961762493917576685078715775", + "15566468304223544967907710088318423124266205091148112619245407877019312204463", + "41055452329758403555638253994796548001394410132451190584557231620492857015113", + "32689357105398883989003153040042832397811577732342162942111644617981437592539", + "1024768857001569898519792936684230802605516833546761955899128048776975939287", + "24676480703389179370787802748528807212626716708894684464172445040207875775149", + "29216050772327288092260808534804949373594503515354198725049552111307518224205", + "52410100857814433438817442328694036440730238022082510360171730887759093465481", + "40543780236182316882464625519600838616995610015014846211588517028056823476017", + "26545811755985805094640794491213532971022247850242406385576190901627386177200", + "40190277376375775680255634061091463939432889927032297976760076076204104076642", + "25610442271370585640686855705082082005978351602979365073160810256043819149", + "34868403157632270097105800928116524281163668958890221938944640362771737046369", + "10360715285361728247967793679491726871187159820401782886944308445173757237660", + "17226241832238524621308916898419210587796266425699244256232831096237030558657", + "48254770593568519219560424366692941237608771788618122012997240550036662932503", + "22393650022661618512721129495012401777980660217458695524271388049710294630887", + "44588712351821010051043480466782716847851039499194235967093254692762855484007", + "14038264746429210579848606034469806747367217995727553279035186846376706850321", + "10226451936276293085026911723993358027411020772551999686536991101205710129445", + "51833230104847001065910752898851363673106601368072185359763126470983607642979", + "17731568570209604805696733082425879879476587632820434548116182970573285266983", + "7293301549267145168646494936950794141888801470123323832840622688669896216180", + "43980624643572972086106579021374305586648663090131917351236676838506661928994", + "6880500665998738785726032676562268034667354632067005832699658798735544947954", + "9958623123796966423899360548471808019217080677018391989248364853979397629337", + "48301447831178128817063634255237911498604316082787728486039780142380825344151", + "16239346579868812175632184977493741977975015753773751460634794597983623247600", + "44346112848438880859609808158797680803257206420389682070071036855654584211547", + "33859132335333257150279672995392009322042669130394126860729209603681969652655", + "50405473453998633083896189380120004463097357565488678236424316493827517712854", + "33585745758199143506610722584372074825851725088059939000913058597283702938145", + "52255686860605204437569268128673452039170549728485774573168131770590952250060", + "2510654139473627451121203708815376438628328183023084239800159285587238310184", + "51062321801149753600521856768457506586989769922776681386710884583455833385331", + "3990315958315072276362273520687836085445455584751787977137300023765259734183", + "22824059279264376926623112117626094280952057854343176927798704656433291469008", + "29318449117766273889429817872532733195894000607234279610846974420945818281166", + "47405715912102735477706975890972266177839129761332879720618643464279573270248", + "10134577200313170573356672478335938704405832480102067053062428730997112659997", + "50469787687241980646240999261410003786908332095763311219292973158013769807319", + "13290158194560422732057552874953066062171368873517937767067284855744048261272", + "21239823421188808448119494118737819510970783685900569439956735302071768456980", + "23529839943833287587280296061950099018631270174318961537860546757130196908702", + "38499834190314454060181375975491474230078904599255317886313599123150870566025", + "36329028899277333424379893864637685661845881202302920018441383042153070668889", + "10549023210207369304684145902795777543052692491603755214747690610687944425161", + "48023327420612451276370142621683247121814792924279354590368337521558573261444", + "26200022564413195041863894746038554617753411768199090733563845868432708254894", + "27657167416713809935685365503583909336487250267861186244996315660249356849800", + "37475823163078615615361952414880958682089601832622733559049378958171676290905", + "3981093650031673935479702160050698785910816535056430608854737953941027218130", + "20226119683451061894120210521022674440323729882521001087747367235499447984574", + "35801988668140681317815257177243723970417077510119342425146453581516844988995", + "38890492302645470045975397431314712481435227821820869093176497683904062745943", + "12638290869002031315527391523934716300424967789802794444405630835061730177631", + "8783883334710323900557508788174169715612488067544611842401543295980655005456", + "13671216343655908244658735644988032764545223802661354325404127729029490052904", + "42506866900029791148301479350595582075333097986973091308276696116128623678856", + "624768951951161421834594320427719908172107631632225546772667123566627050865", + "29080649650974855757100354089091133401682994892704915965229442795908917485965", + "39482075302033149403104280831643183831481802780170896414133908684464644527290", + "41142028823108411088938990611528401832565360123183925701081576350637441921380", + "47751412775782974292012852259846971864271242595592615861653470770134420053368", + "32072960229493609371174099008652746264648030933148586234256934146892833532692", + "38592859091051974270611287758035515250993307478311123255299292854580140226138", + "42081202303706675790539787231771583734785854948882245682262025401436985374917", + "35523971741902264498676255180412672412066804435428232689227710162810321618381", + "28304001939473571844416220973626740230244582308371665732805683095447896042444", + "35396974103687644575020044699162886384085922090859662957854813410439180872612", + "43107629588932513752141145665603482822404828021280627615784654472139424437760", + "9340696434124726037195007010960789440991143615652360419099542286959524793603", + "41793899493035309412550330564750570162959747229864700927668614998874136340410", + "31485638044337798283919014801691358542241010025754675253135951597132647187011", + "44420491175871190847395176945534199329978214208144046857114084712253910863797", + "22042953513631038464691779675990026348021162820742350564631984820627811689748", + "2255673500796170875376530630338271294380225347422477965617289980728657223812", + "25513867004536544360431496236413705549655187234337937706930924865567922875163", + "44747936120205109296579764760686402772951946694045050919674657423791160459822", + "31842773453943229305651006473067128637650522563327575167151226969829397417962", + "33297275000203583612771024713050675183391734849999901119832117542619064578022", + "16568330647136135230389143454713451418317185225000606764073088866229645847394", + "51386042204967541420683591885478118210870993127040064355262215538735792376893", + "13187841681061407506212288917289844619045309655083272022538712923780881907594", + "35588224379263011321682693856697492756041550653532512940103620962529654387192", + "26507585734171571101257367118833500998157952008609900314086219161667029074648", + "47325907874104792559598814025481210270548050013425734364409660199164556876787", + "7173934586522281006984026073519548919424067071272287140375403387176812570913", + "6007058669949274206209938289794898972424247168475062734060431698031656993040", + "15118475409720402477154518795062468506145624952420693679036328397505896450685", + "40916033146954657806951963423277340121796712962560020463181231934534146151625", + "49302382047989881643500240571520707512768912193477208553423414945524285991802", + "5412890572437678828434073336657436662318106920628164233400173615548486163544", + "32064079730154641868570246950519079674675773786249602675502531428772865768744", + "5370175028979951356695467436197478761739351562998516962028369570050776517433", + "4169058070292755127117821732551383379507963862136873308253866907272418833248", + "50694400271083347250613297234586582149404137712433566832598176825829057600118", + "16313496090158590617233259688864727096538384664742091241496121033869508933298", + "32118843816862459819831610848021869962105847189656144459709177912938102673041", + "49164848317585513805910724097514770231202109076805768499675440986075602544247", + "42887611112813612923000433794070746915829746551739942133835164049773990099185", + "28750479706214633236439398163855354723520775341850263236790879413978873340996", + "37816054974060021148341976332274426910639823794527085299815047103724410140720", + "42242242429258941849761947914618024396716732904374415263430933246863556538102", + "15803497266553607762758192163127469233230089538874306780877620277867673932102", + "4845329557786019202026805527526179996533184141542641615563566860505399169976", + "37768449026863380100226657081342961983925934970314286022600671822715722524209", + "32832478456560071204852901267835794755934710427334288307614888168235392898116", + "6458648508515941059385460165267366689292746868104132757667377715377804998017", + "49138162401485943665607545656164820356658228292676119980566445664866955472301", + "9182796467869989924866315851094618695240807319564988124708696801887192474705", + "10550826078780335600164091538364070555221618757019509288469485393796023157252", + "18553384735423693760469146850114787477746958483364845081517998502999448005742", + "12493318082987884054210383942635172473866849615890229870168557187835210356819", + "25337922137847909546952935019320343743158955894614546588547054649334415472593", + "39783937831759855034221024361883822844460981250152596918165936297185455821808", + "12423078682227598320322571640719205707353746939426823709070583296149780154353", + "39159110647376449551416162888021289645383901048449346271890841091053707131260", + "29790207700388420130426446293658539359238992535689357962479599378933663866473", + "15532452907182623763067773333822167439198089786336602355297528603106398551922", + "38889785922272494502633675041842833372425514413939166538308554457302365522760", + "41894625001545769011333180040699858315002831034178807390726230059784511672628", + "5112469828748150229999123592653268487131020611743614172020457581995961408269", + "3044864441616193776937095576972319333910802411311614418870538053981835561162", + "9226994762580291138996403169594921256187963335099851729630071412504017785221", + "32951808503824262496267163465084293455993138887959432600024622399637179231630", + "40981559309486107744668727759163297562164269727713412246973414972709980860445", + "32191022876783159424925656117954595213113841457586092550955954886795427658699", + "27597847927440347903828447288148607970591128921756439592921824122623571081612", + "1427242296809904447990631280896243073785437052175182632051040475977115900637" +] diff --git a/crates/starknet_os/src/hints/hint_implementation/kzg/blob_regression_output.json b/crates/starknet_os/src/hints/hint_implementation/kzg/blob_regression_output.json new file mode 100644 index 00000000000..a33b3acd440 --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/kzg/blob_regression_output.json @@ -0,0 +1,131074 @@ +[ + 66, + 205, + 143, + 73, + 246, + 116, + 156, + 8, + 13, + 186, + 62, + 37, + 50, + 78, + 99, + 217, + 223, + 89, + 71, + 156, + 38, + 92, + 216, + 249, + 141, + 42, + 87, + 153, + 126, + 140, + 179, + 217, + 91, + 227, + 66, + 38, + 133, + 65, + 202, + 34, + 59, + 78, + 3, + 190, + 180, + 50, + 111, + 51, + 165, + 49, + 48, + 64, + 216, + 159, + 49, + 121, + 204, + 113, + 123, + 142, + 11, + 168, + 229, + 31, + 36, + 135, + 253, + 247, + 22, + 3, + 94, + 129, + 189, + 19, + 168, + 3, + 125, + 183, + 182, + 106, + 56, + 117, + 119, + 142, + 40, + 85, + 38, + 108, + 40, + 14, + 55, + 112, + 178, + 34, + 97, + 229, + 7, + 143, + 56, + 127, + 151, + 47, + 73, + 234, + 109, + 126, + 213, + 49, + 94, + 60, + 206, + 11, + 30, + 225, + 85, + 253, + 247, + 132, + 108, + 234, + 47, + 176, + 198, + 209, + 123, + 78, + 10, + 126, + 25, + 19, + 124, + 37, + 130, + 119, + 249, + 183, + 56, + 177, + 84, + 114, + 91, + 181, + 215, + 162, + 130, + 112, + 140, + 78, + 238, + 22, + 108, + 205, + 55, + 41, + 200, + 56, + 253, + 188, + 12, + 82, + 103, + 85, + 23, + 229, + 177, + 14, + 122, + 138, + 35, + 69, + 50, + 115, + 252, + 1, + 80, + 241, + 46, + 25, + 151, + 248, + 163, + 202, + 169, + 34, + 203, + 37, + 171, + 159, + 149, + 183, + 68, + 74, + 47, + 102, + 217, + 40, + 21, + 228, + 178, + 21, + 37, + 218, + 7, + 24, + 68, + 141, + 8, + 13, + 1, + 181, + 161, + 18, + 177, + 86, + 234, + 243, + 151, + 114, + 218, + 210, + 145, + 48, + 34, + 188, + 13, + 90, + 23, + 48, + 83, + 110, + 255, + 90, + 237, + 196, + 59, + 16, + 74, + 204, + 23, + 73, + 84, + 114, + 2, + 106, + 144, + 187, + 203, + 42, + 116, + 23, + 61, + 147, + 99, + 168, + 56, + 194, + 53, + 149, + 85, + 168, + 70, + 35, + 217, + 52, + 192, + 223, + 234, + 80, + 44, + 183, + 186, + 8, + 61, + 106, + 117, + 238, + 58, + 233, + 12, + 101, + 225, + 170, + 164, + 86, + 62, + 25, + 186, + 201, + 111, + 47, + 248, + 226, + 223, + 186, + 11, + 21, + 185, + 87, + 58, + 170, + 139, + 225, + 4, + 90, + 113, + 248, + 252, + 145, + 198, + 54, + 180, + 235, + 128, + 67, + 13, + 29, + 122, + 189, + 23, + 66, + 89, + 40, + 187, + 35, + 205, + 213, + 128, + 85, + 92, + 12, + 149, + 232, + 113, + 130, + 227, + 122, + 169, + 247, + 42, + 237, + 38, + 8, + 11, + 39, + 17, + 85, + 117, + 165, + 2, + 240, + 243, + 253, + 99, + 193, + 33, + 222, + 164, + 241, + 127, + 205, + 79, + 215, + 187, + 9, + 139, + 220, + 139, + 169, + 228, + 177, + 101, + 12, + 229, + 117, + 92, + 137, + 73, + 184, + 171, + 61, + 78, + 146, + 69, + 125, + 38, + 99, + 11, + 104, + 182, + 82, + 119, + 79, + 238, + 86, + 196, + 176, + 177, + 0, + 184, + 53, + 30, + 66, + 25, + 12, + 96, + 8, + 19, + 3, + 185, + 147, + 119, + 41, + 67, + 7, + 32, + 106, + 22, + 173, + 238, + 36, + 51, + 6, + 52, + 53, + 83, + 242, + 250, + 18, + 2, + 236, + 172, + 192, + 156, + 247, + 152, + 12, + 231, + 219, + 185, + 169, + 173, + 86, + 69, + 90, + 244, + 178, + 178, + 162, + 58, + 74, + 28, + 152, + 249, + 195, + 1, + 104, + 37, + 156, + 20, + 58, + 169, + 120, + 239, + 113, + 162, + 95, + 156, + 74, + 126, + 249, + 81, + 108, + 143, + 236, + 240, + 134, + 173, + 145, + 41, + 119, + 107, + 153, + 231, + 95, + 95, + 225, + 147, + 242, + 114, + 83, + 19, + 66, + 45, + 202, + 74, + 206, + 84, + 183, + 222, + 133, + 91, + 224, + 66, + 199, + 119, + 8, + 69, + 18, + 118, + 157, + 105, + 131, + 41, + 242, + 132, + 90, + 61, + 224, + 254, + 100, + 25, + 200, + 111, + 240, + 199, + 53, + 155, + 126, + 189, + 181, + 239, + 107, + 226, + 207, + 110, + 76, + 252, + 14, + 116, + 254, + 197, + 84, + 97, + 146, + 44, + 112, + 124, + 228, + 80, + 110, + 61, + 234, + 130, + 212, + 141, + 245, + 43, + 179, + 73, + 12, + 170, + 35, + 229, + 164, + 76, + 206, + 48, + 75, + 248, + 89, + 137, + 27, + 209, + 24, + 214, + 104, + 80, + 156, + 120, + 238, + 133, + 181, + 192, + 167, + 201, + 23, + 187, + 207, + 133, + 69, + 82, + 148, + 115, + 10, + 235, + 30, + 185, + 93, + 183, + 79, + 74, + 61, + 111, + 13, + 77, + 17, + 173, + 165, + 22, + 92, + 195, + 95, + 111, + 52, + 99, + 35, + 78, + 27, + 113, + 195, + 190, + 19, + 69, + 118, + 40, + 184, + 142, + 216, + 239, + 32, + 22, + 10, + 85, + 3, + 241, + 222, + 253, + 1, + 100, + 60, + 24, + 79, + 51, + 143, + 178, + 236, + 143, + 17, + 111, + 57, + 155, + 79, + 25, + 137, + 115, + 169, + 74, + 131, + 202, + 96, + 38, + 222, + 148, + 41, + 78, + 208, + 204, + 98, + 26, + 105, + 116, + 167, + 6, + 138, + 18, + 200, + 172, + 46, + 244, + 145, + 25, + 12, + 56, + 249, + 246, + 117, + 65, + 143, + 1, + 138, + 112, + 240, + 49, + 227, + 197, + 49, + 77, + 127, + 174, + 224, + 130, + 202, + 189, + 177, + 99, + 144, + 238, + 226, + 136, + 184, + 64, + 233, + 23, + 245, + 57, + 192, + 167, + 44, + 178, + 179, + 87, + 26, + 54, + 108, + 55, + 44, + 180, + 229, + 198, + 242, + 168, + 246, + 131, + 220, + 236, + 163, + 25, + 88, + 106, + 54, + 144, + 50, + 63, + 202, + 103, + 105, + 242, + 148, + 156, + 135, + 149, + 64, + 91, + 27, + 94, + 173, + 115, + 65, + 179, + 230, + 223, + 185, + 190, + 230, + 246, + 127, + 145, + 90, + 107, + 21, + 74, + 12, + 206, + 177, + 36, + 219, + 197, + 250, + 247, + 141, + 190, + 87, + 148, + 140, + 51, + 143, + 252, + 38, + 245, + 19, + 202, + 151, + 108, + 160, + 223, + 229, + 65, + 37, + 30, + 114, + 101, + 245, + 87, + 131, + 109, + 153, + 193, + 152, + 48, + 221, + 1, + 248, + 101, + 176, + 179, + 166, + 150, + 178, + 211, + 94, + 136, + 194, + 136, + 245, + 234, + 16, + 206, + 158, + 79, + 216, + 105, + 14, + 13, + 218, + 43, + 10, + 142, + 61, + 63, + 161, + 37, + 150, + 96, + 185, + 8, + 14, + 231, + 174, + 211, + 28, + 143, + 42, + 117, + 245, + 232, + 53, + 228, + 179, + 81, + 203, + 109, + 250, + 70, + 33, + 107, + 17, + 245, + 4, + 158, + 234, + 155, + 221, + 136, + 224, + 56, + 115, + 137, + 90, + 153, + 155, + 51, + 140, + 71, + 6, + 229, + 255, + 224, + 223, + 142, + 129, + 186, + 252, + 29, + 137, + 254, + 157, + 28, + 253, + 20, + 101, + 109, + 83, + 74, + 145, + 111, + 234, + 19, + 74, + 89, + 214, + 146, + 236, + 254, + 109, + 120, + 51, + 63, + 69, + 130, + 6, + 91, + 111, + 251, + 152, + 67, + 219, + 1, + 140, + 68, + 211, + 161, + 189, + 251, + 241, + 233, + 73, + 1, + 131, + 120, + 111, + 58, + 236, + 105, + 193, + 92, + 78, + 32, + 145, + 161, + 213, + 164, + 238, + 232, + 248, + 218, + 254, + 47, + 80, + 217, + 117, + 39, + 131, + 106, + 208, + 35, + 60, + 164, + 174, + 253, + 62, + 5, + 95, + 189, + 33, + 88, + 4, + 113, + 240, + 72, + 22, + 44, + 39, + 53, + 63, + 183, + 109, + 16, + 29, + 41, + 189, + 204, + 73, + 21, + 73, + 251, + 122, + 91, + 178, + 70, + 44, + 61, + 34, + 84, + 110, + 0, + 243, + 60, + 148, + 67, + 140, + 90, + 107, + 194, + 132, + 66, + 2, + 254, + 46, + 110, + 222, + 185, + 118, + 230, + 1, + 43, + 69, + 249, + 135, + 224, + 192, + 237, + 217, + 50, + 255, + 68, + 252, + 71, + 118, + 123, + 227, + 244, + 77, + 53, + 2, + 232, + 23, + 87, + 222, + 8, + 116, + 171, + 194, + 191, + 47, + 226, + 235, + 75, + 187, + 154, + 205, + 246, + 64, + 94, + 250, + 117, + 196, + 177, + 143, + 51, + 7, + 192, + 242, + 148, + 242, + 63, + 190, + 155, + 139, + 158, + 226, + 254, + 212, + 7, + 200, + 178, + 3, + 39, + 226, + 20, + 170, + 118, + 22, + 163, + 102, + 105, + 65, + 190, + 6, + 113, + 168, + 195, + 40, + 214, + 149, + 105, + 243, + 128, + 224, + 172, + 69, + 202, + 177, + 35, + 240, + 246, + 115, + 2, + 233, + 7, + 172, + 56, + 232, + 4, + 11, + 144, + 79, + 167, + 40, + 193, + 138, + 86, + 158, + 4, + 223, + 219, + 51, + 14, + 12, + 24, + 90, + 133, + 87, + 156, + 10, + 95, + 94, + 241, + 8, + 184, + 143, + 178, + 223, + 63, + 188, + 227, + 232, + 60, + 213, + 128, + 42, + 142, + 117, + 247, + 189, + 59, + 41, + 236, + 174, + 248, + 231, + 8, + 75, + 184, + 234, + 30, + 237, + 40, + 193, + 115, + 121, + 70, + 195, + 76, + 147, + 75, + 185, + 5, + 26, + 206, + 121, + 220, + 183, + 85, + 172, + 93, + 79, + 218, + 216, + 38, + 121, + 146, + 79, + 16, + 176, + 86, + 112, + 103, + 243, + 145, + 104, + 34, + 183, + 139, + 40, + 46, + 180, + 63, + 5, + 17, + 154, + 184, + 106, + 17, + 70, + 35, + 245, + 121, + 122, + 70, + 207, + 91, + 247, + 25, + 146, + 65, + 85, + 182, + 123, + 31, + 16, + 87, + 139, + 129, + 232, + 196, + 120, + 184, + 184, + 63, + 230, + 193, + 63, + 123, + 73, + 130, + 227, + 82, + 146, + 100, + 202, + 140, + 24, + 196, + 58, + 52, + 62, + 201, + 29, + 57, + 72, + 249, + 120, + 132, + 112, + 3, + 195, + 7, + 148, + 112, + 244, + 69, + 76, + 135, + 162, + 17, + 2, + 95, + 172, + 251, + 0, + 166, + 244, + 137, + 128, + 94, + 145, + 25, + 87, + 113, + 145, + 39, + 123, + 44, + 221, + 166, + 70, + 244, + 112, + 102, + 231, + 3, + 199, + 28, + 196, + 163, + 81, + 23, + 105, + 105, + 137, + 3, + 57, + 126, + 188, + 103, + 172, + 114, + 148, + 110, + 17, + 70, + 51, + 15, + 240, + 76, + 200, + 206, + 114, + 184, + 139, + 190, + 210, + 220, + 33, + 74, + 5, + 96, + 187, + 22, + 194, + 170, + 49, + 120, + 73, + 53, + 179, + 109, + 238, + 245, + 130, + 42, + 222, + 197, + 50, + 155, + 196, + 192, + 241, + 164, + 221, + 246, + 173, + 176, + 141, + 84, + 150, + 51, + 40, + 102, + 115, + 109, + 84, + 104, + 61, + 46, + 199, + 44, + 212, + 159, + 177, + 239, + 32, + 84, + 149, + 184, + 193, + 38, + 189, + 204, + 150, + 139, + 249, + 9, + 80, + 130, + 254, + 155, + 53, + 64, + 10, + 81, + 84, + 195, + 153, + 129, + 85, + 34, + 32, + 49, + 208, + 213, + 130, + 204, + 10, + 119, + 79, + 255, + 75, + 168, + 117, + 59, + 61, + 132, + 5, + 100, + 172, + 111, + 160, + 127, + 0, + 80, + 193, + 225, + 187, + 79, + 155, + 142, + 198, + 148, + 71, + 168, + 184, + 172, + 251, + 130, + 125, + 126, + 250, + 143, + 49, + 23, + 42, + 60, + 101, + 2, + 8, + 203, + 198, + 18, + 174, + 241, + 54, + 35, + 23, + 220, + 227, + 48, + 21, + 161, + 59, + 66, + 107, + 188, + 96, + 186, + 35, + 189, + 139, + 42, + 248, + 20, + 155, + 234, + 24, + 12, + 147, + 9, + 165, + 182, + 40, + 184, + 166, + 208, + 31, + 72, + 134, + 213, + 96, + 41, + 30, + 21, + 141, + 236, + 204, + 145, + 255, + 217, + 117, + 131, + 159, + 229, + 249, + 89, + 73, + 219, + 233, + 205, + 157, + 88, + 102, + 180, + 203, + 169, + 121, + 110, + 179, + 26, + 202, + 128, + 50, + 130, + 17, + 218, + 226, + 84, + 64, + 217, + 194, + 159, + 95, + 211, + 69, + 57, + 124, + 157, + 168, + 58, + 215, + 237, + 40, + 182, + 130, + 180, + 244, + 35, + 109, + 55, + 86, + 112, + 157, + 29, + 59, + 150, + 217, + 223, + 192, + 65, + 85, + 246, + 54, + 1, + 103, + 172, + 228, + 248, + 179, + 150, + 57, + 19, + 213, + 36, + 198, + 77, + 229, + 80, + 126, + 94, + 228, + 36, + 194, + 85, + 159, + 21, + 212, + 47, + 165, + 33, + 99, + 128, + 253, + 13, + 59, + 167, + 80, + 77, + 216, + 219, + 184, + 15, + 135, + 34, + 160, + 144, + 240, + 200, + 40, + 158, + 102, + 193, + 170, + 253, + 111, + 93, + 150, + 227, + 9, + 11, + 21, + 225, + 236, + 171, + 101, + 252, + 151, + 212, + 181, + 47, + 208, + 23, + 210, + 53, + 248, + 172, + 198, + 75, + 101, + 164, + 229, + 31, + 51, + 103, + 235, + 220, + 183, + 22, + 62, + 127, + 161, + 85, + 79, + 29, + 12, + 17, + 207, + 106, + 2, + 204, + 95, + 203, + 196, + 220, + 165, + 140, + 145, + 33, + 158, + 49, + 226, + 153, + 152, + 187, + 35, + 209, + 172, + 33, + 249, + 96, + 211, + 225, + 207, + 21, + 163, + 109, + 215, + 163, + 179, + 72, + 212, + 31, + 173, + 165, + 226, + 10, + 150, + 197, + 254, + 7, + 133, + 231, + 162, + 190, + 1, + 233, + 156, + 62, + 109, + 72, + 231, + 0, + 4, + 40, + 191, + 1, + 67, + 120, + 95, + 159, + 149, + 102, + 49, + 148, + 107, + 18, + 62, + 82, + 97, + 90, + 243, + 170, + 76, + 77, + 232, + 155, + 204, + 176, + 151, + 131, + 22, + 200, + 66, + 68, + 73, + 62, + 164, + 218, + 193, + 178, + 157, + 169, + 20, + 8, + 151, + 41, + 27, + 28, + 30, + 184, + 171, + 52, + 34, + 226, + 108, + 99, + 208, + 115, + 106, + 46, + 33, + 205, + 200, + 18, + 8, + 66, + 254, + 71, + 174, + 104, + 66, + 146, + 114, + 21, + 133, + 117, + 157, + 65, + 14, + 40, + 53, + 100, + 101, + 65, + 172, + 51, + 45, + 75, + 44, + 156, + 179, + 207, + 53, + 8, + 69, + 188, + 210, + 96, + 222, + 139, + 179, + 175, + 157, + 191, + 67, + 231, + 203, + 22, + 247, + 145, + 200, + 72, + 93, + 140, + 187, + 36, + 99, + 215, + 139, + 49, + 93, + 122, + 191, + 186, + 43, + 154, + 123, + 198, + 224, + 25, + 5, + 137, + 122, + 19, + 234, + 58, + 85, + 123, + 229, + 224, + 131, + 129, + 70, + 49, + 201, + 251, + 255, + 162, + 197, + 239, + 175, + 159, + 236, + 41, + 39, + 38, + 62, + 238, + 164, + 105, + 82, + 104, + 17, + 171, + 33, + 199, + 85, + 211, + 19, + 95, + 249, + 198, + 75, + 165, + 74, + 35, + 44, + 246, + 168, + 175, + 47, + 251, + 254, + 85, + 224, + 65, + 4, + 90, + 171, + 114, + 159, + 175, + 194, + 48, + 253, + 82, + 83, + 66, + 82, + 173, + 204, + 146, + 193, + 51, + 190, + 5, + 63, + 216, + 10, + 67, + 140, + 25, + 107, + 155, + 34, + 10, + 119, + 132, + 66, + 76, + 133, + 104, + 3, + 0, + 238, + 110, + 5, + 101, + 190, + 233, + 102, + 224, + 188, + 74, + 40, + 199, + 85, + 179, + 140, + 2, + 94, + 56, + 120, + 158, + 167, + 115, + 49, + 137, + 195, + 234, + 219, + 241, + 248, + 190, + 233, + 205, + 81, + 89, + 56, + 147, + 246, + 188, + 200, + 45, + 246, + 108, + 87, + 242, + 230, + 21, + 12, + 134, + 221, + 42, + 29, + 154, + 50, + 247, + 81, + 45, + 77, + 22, + 95, + 81, + 192, + 154, + 22, + 213, + 158, + 89, + 169, + 218, + 134, + 186, + 210, + 80, + 138, + 144, + 186, + 162, + 107, + 6, + 44, + 31, + 162, + 140, + 248, + 157, + 126, + 123, + 77, + 37, + 39, + 59, + 47, + 234, + 8, + 141, + 210, + 253, + 65, + 60, + 136, + 175, + 161, + 7, + 71, + 10, + 187, + 127, + 55, + 164, + 80, + 181, + 138, + 84, + 57, + 248, + 16, + 210, + 23, + 211, + 154, + 155, + 237, + 125, + 115, + 6, + 230, + 181, + 235, + 22, + 198, + 35, + 167, + 180, + 199, + 172, + 13, + 147, + 250, + 173, + 31, + 195, + 91, + 250, + 81, + 203, + 207, + 232, + 241, + 78, + 39, + 217, + 224, + 67, + 146, + 37, + 141, + 168, + 149, + 248, + 224, + 116, + 142, + 86, + 240, + 177, + 69, + 92, + 36, + 13, + 205, + 29, + 133, + 252, + 209, + 155, + 247, + 171, + 2, + 40, + 217, + 155, + 154, + 40, + 129, + 17, + 190, + 3, + 90, + 242, + 66, + 180, + 246, + 152, + 70, + 108, + 132, + 211, + 225, + 167, + 215, + 36, + 67, + 211, + 231, + 229, + 161, + 120, + 4, + 152, + 204, + 66, + 125, + 160, + 44, + 58, + 41, + 224, + 104, + 144, + 37, + 106, + 122, + 111, + 120, + 138, + 22, + 9, + 22, + 184, + 8, + 106, + 125, + 239, + 179, + 103, + 190, + 35, + 131, + 131, + 241, + 214, + 204, + 235, + 178, + 153, + 227, + 44, + 192, + 78, + 202, + 187, + 98, + 26, + 93, + 46, + 249, + 196, + 134, + 93, + 12, + 214, + 236, + 100, + 86, + 156, + 230, + 251, + 219, + 221, + 35, + 7, + 5, + 212, + 84, + 165, + 148, + 246, + 164, + 171, + 36, + 184, + 33, + 129, + 37, + 142, + 16, + 51, + 245, + 85, + 44, + 8, + 195, + 164, + 126, + 23, + 202, + 50, + 226, + 227, + 250, + 132, + 163, + 178, + 106, + 176, + 165, + 93, + 220, + 143, + 112, + 169, + 239, + 104, + 250, + 27, + 45, + 49, + 171, + 45, + 217, + 10, + 168, + 17, + 75, + 167, + 212, + 115, + 86, + 234, + 61, + 33, + 224, + 148, + 136, + 65, + 30, + 220, + 9, + 142, + 54, + 243, + 18, + 205, + 223, + 70, + 212, + 111, + 231, + 121, + 87, + 41, + 142, + 13, + 141, + 83, + 177, + 104, + 151, + 77, + 72, + 70, + 48, + 169, + 87, + 130, + 135, + 11, + 149, + 194, + 160, + 161, + 84, + 129, + 29, + 191, + 60, + 14, + 19, + 0, + 236, + 181, + 65, + 142, + 57, + 131, + 178, + 103, + 3, + 71, + 88, + 170, + 226, + 252, + 159, + 252, + 70, + 57, + 211, + 216, + 170, + 122, + 221, + 3, + 7, + 65, + 97, + 131, + 242, + 160, + 224, + 63, + 54, + 75, + 69, + 106, + 66, + 110, + 43, + 15, + 67, + 183, + 69, + 216, + 135, + 195, + 134, + 67, + 92, + 105, + 32, + 44, + 173, + 235, + 1, + 169, + 166, + 230, + 146, + 223, + 195, + 216, + 69, + 126, + 71, + 138, + 42, + 83, + 134, + 196, + 154, + 55, + 90, + 163, + 92, + 173, + 101, + 156, + 53, + 126, + 205, + 143, + 99, + 162, + 216, + 134, + 188, + 29, + 202, + 138, + 231, + 81, + 6, + 65, + 121, + 158, + 87, + 65, + 206, + 65, + 24, + 171, + 204, + 0, + 29, + 162, + 49, + 126, + 224, + 165, + 203, + 221, + 151, + 60, + 238, + 254, + 67, + 88, + 139, + 235, + 251, + 56, + 56, + 17, + 66, + 74, + 128, + 69, + 67, + 149, + 108, + 26, + 5, + 223, + 88, + 40, + 68, + 130, + 83, + 127, + 198, + 184, + 78, + 184, + 153, + 245, + 193, + 186, + 149, + 231, + 150, + 54, + 101, + 80, + 49, + 63, + 57, + 244, + 62, + 9, + 205, + 224, + 38, + 245, + 204, + 89, + 11, + 42, + 60, + 151, + 112, + 72, + 241, + 140, + 11, + 74, + 100, + 28, + 192, + 238, + 80, + 215, + 84, + 126, + 92, + 189, + 155, + 193, + 159, + 5, + 194, + 150, + 220, + 165, + 152, + 69, + 60, + 229, + 47, + 108, + 122, + 229, + 171, + 97, + 124, + 182, + 204, + 14, + 122, + 174, + 219, + 68, + 31, + 1, + 184, + 250, + 109, + 133, + 161, + 190, + 239, + 219, + 36, + 59, + 93, + 170, + 217, + 175, + 38, + 166, + 105, + 10, + 133, + 17, + 84, + 250, + 244, + 146, + 125, + 78, + 214, + 227, + 164, + 12, + 154, + 50, + 63, + 36, + 94, + 169, + 217, + 91, + 235, + 38, + 138, + 217, + 163, + 185, + 156, + 32, + 104, + 134, + 219, + 23, + 64, + 171, + 195, + 94, + 222, + 204, + 184, + 218, + 226, + 107, + 44, + 187, + 77, + 25, + 155, + 202, + 163, + 109, + 236, + 142, + 190, + 109, + 16, + 53, + 164, + 163, + 143, + 168, + 72, + 24, + 201, + 100, + 74, + 111, + 201, + 119, + 240, + 182, + 128, + 149, + 124, + 84, + 42, + 193, + 12, + 163, + 115, + 92, + 47, + 108, + 55, + 91, + 251, + 4, + 80, + 156, + 189, + 15, + 235, + 253, + 159, + 89, + 105, + 1, + 158, + 176, + 89, + 196, + 250, + 71, + 141, + 97, + 107, + 254, + 204, + 141, + 221, + 89, + 214, + 248, + 239, + 204, + 183, + 124, + 124, + 57, + 254, + 31, + 246, + 156, + 45, + 77, + 106, + 141, + 159, + 64, + 29, + 61, + 21, + 211, + 181, + 250, + 171, + 67, + 98, + 132, + 119, + 240, + 112, + 159, + 61, + 233, + 9, + 9, + 165, + 124, + 5, + 95, + 24, + 117, + 222, + 94, + 131, + 204, + 210, + 185, + 41, + 7, + 59, + 200, + 231, + 25, + 186, + 221, + 117, + 126, + 0, + 172, + 158, + 128, + 22, + 241, + 131, + 38, + 123, + 133, + 89, + 212, + 161, + 97, + 53, + 161, + 73, + 110, + 232, + 2, + 120, + 47, + 152, + 53, + 104, + 249, + 167, + 233, + 185, + 166, + 253, + 213, + 32, + 139, + 22, + 107, + 180, + 149, + 165, + 151, + 170, + 105, + 122, + 164, + 120, + 171, + 221, + 8, + 251, + 71, + 92, + 116, + 112, + 131, + 100, + 87, + 213, + 253, + 41, + 9, + 242, + 24, + 30, + 27, + 193, + 21, + 116, + 62, + 98, + 38, + 118, + 154, + 39, + 61, + 84, + 157, + 242, + 19, + 189, + 125, + 73, + 129, + 127, + 216, + 90, + 122, + 227, + 2, + 11, + 144, + 80, + 161, + 124, + 185, + 142, + 93, + 183, + 127, + 225, + 60, + 148, + 217, + 39, + 211, + 222, + 27, + 192, + 116, + 62, + 224, + 113, + 153, + 145, + 85, + 113, + 91, + 142, + 140, + 15, + 19, + 201, + 114, + 12, + 75, + 220, + 128, + 251, + 19, + 0, + 186, + 91, + 22, + 33, + 134, + 36, + 246, + 82, + 148, + 238, + 52, + 178, + 112, + 221, + 165, + 104, + 189, + 0, + 7, + 34, + 190, + 104, + 73, + 147, + 105, + 246, + 104, + 140, + 38, + 183, + 210, + 161, + 78, + 234, + 207, + 189, + 168, + 218, + 98, + 157, + 77, + 193, + 235, + 47, + 224, + 119, + 220, + 249, + 33, + 163, + 211, + 97, + 123, + 167, + 58, + 103, + 80, + 68, + 71, + 199, + 77, + 209, + 131, + 186, + 65, + 138, + 112, + 114, + 57, + 201, + 33, + 198, + 159, + 64, + 108, + 167, + 59, + 5, + 44, + 233, + 153, + 252, + 254, + 230, + 232, + 112, + 42, + 87, + 176, + 33, + 96, + 11, + 131, + 243, + 196, + 201, + 193, + 247, + 38, + 197, + 24, + 17, + 54, + 27, + 43, + 66, + 141, + 184, + 217, + 16, + 218, + 195, + 90, + 70, + 8, + 52, + 7, + 215, + 111, + 123, + 20, + 205, + 163, + 34, + 60, + 193, + 9, + 165, + 78, + 104, + 194, + 177, + 101, + 60, + 21, + 184, + 204, + 64, + 53, + 7, + 209, + 25, + 130, + 232, + 197, + 95, + 110, + 167, + 137, + 251, + 62, + 161, + 189, + 41, + 226, + 110, + 165, + 195, + 57, + 13, + 27, + 59, + 156, + 123, + 90, + 213, + 176, + 252, + 24, + 111, + 20, + 245, + 118, + 38, + 250, + 67, + 180, + 216, + 73, + 21, + 1, + 13, + 56, + 93, + 33, + 211, + 215, + 13, + 90, + 115, + 155, + 85, + 180, + 240, + 166, + 178, + 223, + 163, + 41, + 123, + 225, + 118, + 51, + 178, + 198, + 4, + 113, + 64, + 222, + 210, + 182, + 48, + 35, + 110, + 101, + 193, + 127, + 152, + 9, + 154, + 121, + 23, + 181, + 179, + 72, + 107, + 57, + 69, + 130, + 113, + 109, + 252, + 64, + 0, + 83, + 46, + 53, + 230, + 37, + 156, + 223, + 26, + 127, + 44, + 114, + 224, + 109, + 59, + 111, + 174, + 5, + 95, + 61, + 19, + 61, + 121, + 68, + 75, + 111, + 108, + 186, + 75, + 37, + 105, + 214, + 233, + 60, + 246, + 248, + 235, + 25, + 63, + 226, + 137, + 240, + 22, + 108, + 188, + 102, + 107, + 132, + 97, + 87, + 148, + 134, + 186, + 16, + 12, + 34, + 123, + 142, + 64, + 112, + 69, + 105, + 205, + 190, + 1, + 128, + 39, + 129, + 166, + 184, + 67, + 47, + 116, + 195, + 127, + 111, + 12, + 111, + 50, + 173, + 89, + 232, + 223, + 179, + 171, + 100, + 145, + 167, + 77, + 255, + 220, + 138, + 86, + 198, + 1, + 124, + 0, + 135, + 205, + 51, + 104, + 125, + 157, + 182, + 62, + 6, + 155, + 119, + 243, + 60, + 81, + 134, + 28, + 90, + 127, + 194, + 38, + 111, + 72, + 56, + 190, + 35, + 249, + 28, + 238, + 141, + 168, + 67, + 196, + 85, + 134, + 247, + 60, + 192, + 15, + 30, + 188, + 32, + 174, + 10, + 252, + 43, + 89, + 154, + 165, + 22, + 117, + 60, + 161, + 70, + 210, + 139, + 131, + 128, + 38, + 97, + 240, + 188, + 103, + 249, + 46, + 149, + 255, + 182, + 250, + 147, + 136, + 139, + 206, + 118, + 132, + 155, + 115, + 34, + 125, + 38, + 175, + 213, + 37, + 64, + 114, + 174, + 177, + 22, + 47, + 89, + 59, + 67, + 216, + 38, + 95, + 190, + 158, + 226, + 63, + 204, + 154, + 231, + 119, + 195, + 114, + 19, + 168, + 175, + 199, + 17, + 104, + 58, + 107, + 28, + 220, + 250, + 185, + 159, + 104, + 253, + 136, + 231, + 65, + 175, + 175, + 196, + 242, + 98, + 67, + 113, + 28, + 227, + 8, + 50, + 136, + 3, + 166, + 138, + 10, + 80, + 92, + 7, + 103, + 189, + 105, + 43, + 168, + 188, + 123, + 193, + 138, + 137, + 112, + 192, + 185, + 22, + 116, + 32, + 63, + 158, + 16, + 236, + 91, + 201, + 193, + 88, + 157, + 96, + 21, + 231, + 90, + 57, + 167, + 45, + 224, + 39, + 83, + 180, + 150, + 97, + 67, + 50, + 193, + 68, + 237, + 112, + 187, + 12, + 250, + 157, + 78, + 186, + 183, + 153, + 156, + 61, + 83, + 251, + 174, + 126, + 119, + 15, + 60, + 126, + 144, + 58, + 21, + 52, + 96, + 195, + 85, + 48, + 120, + 9, + 94, + 54, + 25, + 9, + 108, + 38, + 98, + 46, + 153, + 3, + 248, + 212, + 116, + 42, + 25, + 83, + 217, + 193, + 184, + 34, + 170, + 46, + 220, + 1, + 115, + 199, + 74, + 6, + 96, + 65, + 37, + 105, + 190, + 40, + 46, + 166, + 25, + 69, + 109, + 154, + 162, + 184, + 88, + 93, + 110, + 255, + 22, + 136, + 153, + 11, + 111, + 111, + 38, + 184, + 88, + 72, + 27, + 93, + 111, + 133, + 32, + 35, + 140, + 255, + 226, + 119, + 44, + 81, + 194, + 239, + 59, + 29, + 186, + 216, + 114, + 209, + 155, + 49, + 62, + 108, + 131, + 216, + 120, + 103, + 181, + 5, + 244, + 3, + 205, + 26, + 233, + 227, + 75, + 12, + 37, + 88, + 202, + 103, + 163, + 107, + 223, + 102, + 244, + 60, + 30, + 229, + 188, + 151, + 231, + 58, + 141, + 55, + 142, + 95, + 237, + 83, + 109, + 133, + 40, + 81, + 252, + 228, + 4, + 230, + 127, + 253, + 36, + 255, + 169, + 251, + 212, + 79, + 83, + 43, + 92, + 131, + 194, + 81, + 14, + 226, + 45, + 43, + 153, + 109, + 176, + 135, + 174, + 148, + 200, + 66, + 158, + 49, + 186, + 173, + 197, + 188, + 105, + 144, + 246, + 247, + 108, + 43, + 226, + 161, + 47, + 127, + 200, + 57, + 77, + 1, + 136, + 95, + 48, + 227, + 46, + 135, + 243, + 48, + 111, + 12, + 244, + 56, + 50, + 102, + 112, + 74, + 133, + 182, + 82, + 225, + 144, + 253, + 216, + 43, + 217, + 211, + 67, + 136, + 222, + 68, + 167, + 50, + 172, + 246, + 36, + 142, + 178, + 145, + 173, + 251, + 76, + 101, + 77, + 58, + 38, + 56, + 153, + 221, + 203, + 120, + 229, + 111, + 16, + 113, + 222, + 210, + 195, + 34, + 194, + 106, + 214, + 193, + 206, + 11, + 193, + 100, + 235, + 27, + 168, + 191, + 91, + 35, + 94, + 78, + 174, + 142, + 120, + 77, + 246, + 179, + 1, + 104, + 238, + 22, + 143, + 105, + 125, + 13, + 104, + 239, + 51, + 131, + 161, + 205, + 28, + 210, + 212, + 191, + 94, + 214, + 101, + 23, + 178, + 46, + 219, + 14, + 55, + 158, + 32, + 13, + 117, + 156, + 3, + 89, + 58, + 129, + 147, + 167, + 122, + 183, + 189, + 139, + 82, + 133, + 229, + 43, + 219, + 117, + 241, + 190, + 130, + 38, + 216, + 93, + 213, + 229, + 126, + 116, + 68, + 191, + 8, + 102, + 39, + 84, + 167, + 12, + 244, + 178, + 156, + 134, + 71, + 17, + 148, + 34, + 74, + 77, + 56, + 88, + 237, + 99, + 85, + 28, + 62, + 204, + 192, + 199, + 184, + 34, + 59, + 176, + 156, + 79, + 22, + 37, + 129, + 133, + 7, + 244, + 169, + 229, + 98, + 40, + 46, + 13, + 195, + 3, + 211, + 181, + 11, + 202, + 255, + 140, + 123, + 27, + 44, + 66, + 3, + 78, + 92, + 202, + 25, + 86, + 251, + 240, + 58, + 90, + 208, + 78, + 14, + 180, + 52, + 13, + 251, + 133, + 0, + 133, + 213, + 78, + 99, + 209, + 129, + 123, + 152, + 162, + 14, + 32, + 87, + 119, + 46, + 250, + 248, + 19, + 158, + 194, + 50, + 101, + 174, + 5, + 216, + 244, + 43, + 123, + 127, + 192, + 148, + 36, + 77, + 105, + 57, + 149, + 180, + 97, + 47, + 177, + 215, + 133, + 144, + 142, + 196, + 126, + 204, + 117, + 194, + 156, + 87, + 59, + 34, + 47, + 116, + 93, + 162, + 137, + 8, + 204, + 204, + 190, + 21, + 154, + 226, + 154, + 33, + 76, + 205, + 14, + 37, + 33, + 149, + 139, + 214, + 142, + 103, + 67, + 251, + 202, + 174, + 165, + 112, + 196, + 79, + 190, + 24, + 12, + 184, + 15, + 41, + 93, + 206, + 213, + 89, + 240, + 13, + 209, + 55, + 208, + 165, + 31, + 50, + 214, + 103, + 104, + 15, + 251, + 213, + 209, + 225, + 187, + 175, + 169, + 159, + 164, + 184, + 85, + 243, + 95, + 128, + 164, + 181, + 238, + 210, + 122, + 212, + 249, + 199, + 133, + 210, + 228, + 48, + 121, + 225, + 139, + 140, + 33, + 129, + 20, + 75, + 167, + 47, + 205, + 25, + 180, + 28, + 216, + 215, + 200, + 139, + 89, + 234, + 88, + 232, + 40, + 203, + 176, + 9, + 195, + 179, + 156, + 81, + 5, + 12, + 6, + 144, + 148, + 136, + 49, + 244, + 84, + 87, + 203, + 45, + 24, + 123, + 53, + 108, + 247, + 117, + 207, + 139, + 97, + 185, + 34, + 42, + 4, + 193, + 115, + 222, + 188, + 75, + 150, + 212, + 181, + 165, + 214, + 194, + 88, + 14, + 130, + 77, + 190, + 24, + 56, + 13, + 77, + 42, + 214, + 220, + 23, + 86, + 164, + 102, + 19, + 53, + 192, + 196, + 57, + 228, + 210, + 77, + 237, + 34, + 52, + 133, + 125, + 212, + 72, + 222, + 246, + 32, + 0, + 103, + 163, + 253, + 152, + 101, + 232, + 102, + 255, + 77, + 151, + 33, + 247, + 143, + 8, + 221, + 115, + 123, + 70, + 196, + 164, + 235, + 161, + 193, + 11, + 7, + 194, + 61, + 26, + 148, + 25, + 252, + 155, + 202, + 103, + 215, + 37, + 172, + 206, + 171, + 243, + 115, + 179, + 203, + 56, + 89, + 62, + 76, + 253, + 25, + 202, + 57, + 42, + 243, + 139, + 173, + 212, + 202, + 212, + 203, + 215, + 187, + 3, + 122, + 174, + 73, + 88, + 73, + 169, + 225, + 32, + 158, + 154, + 77, + 12, + 251, + 98, + 210, + 95, + 133, + 180, + 165, + 189, + 37, + 226, + 12, + 82, + 127, + 183, + 68, + 212, + 58, + 116, + 237, + 130, + 116, + 101, + 32, + 33, + 3, + 101, + 43, + 215, + 47, + 55, + 9, + 46, + 107, + 219, + 179, + 86, + 212, + 8, + 60, + 113, + 247, + 47, + 196, + 254, + 182, + 35, + 154, + 88, + 181, + 239, + 67, + 87, + 131, + 128, + 203, + 193, + 5, + 126, + 12, + 164, + 173, + 235, + 55, + 18, + 193, + 254, + 137, + 60, + 160, + 120, + 54, + 51, + 50, + 128, + 97, + 73, + 16, + 60, + 88, + 98, + 128, + 156, + 145, + 39, + 69, + 192, + 58, + 96, + 27, + 68, + 32, + 77, + 235, + 147, + 228, + 197, + 191, + 152, + 22, + 0, + 44, + 119, + 19, + 61, + 107, + 110, + 213, + 242, + 254, + 237, + 195, + 208, + 174, + 65, + 78, + 154, + 87, + 235, + 101, + 194, + 40, + 222, + 225, + 230, + 112, + 61, + 255, + 181, + 189, + 51, + 133, + 70, + 80, + 68, + 48, + 222, + 112, + 167, + 191, + 103, + 131, + 60, + 49, + 113, + 37, + 249, + 239, + 245, + 35, + 243, + 204, + 72, + 248, + 101, + 95, + 138, + 32, + 20, + 201, + 197, + 125, + 230, + 82, + 32, + 106, + 168, + 95, + 248, + 247, + 226, + 193, + 207, + 43, + 10, + 150, + 248, + 9, + 214, + 42, + 112, + 166, + 58, + 238, + 135, + 251, + 64, + 2, + 84, + 212, + 218, + 233, + 146, + 162, + 180, + 41, + 98, + 127, + 237, + 105, + 91, + 177, + 70, + 11, + 110, + 55, + 248, + 224, + 173, + 217, + 153, + 189, + 29, + 21, + 141, + 190, + 47, + 43, + 120, + 212, + 4, + 31, + 90, + 229, + 129, + 164, + 206, + 167, + 4, + 140, + 108, + 82, + 42, + 160, + 48, + 97, + 93, + 38, + 252, + 157, + 85, + 62, + 187, + 55, + 213, + 29, + 1, + 19, + 174, + 96, + 173, + 242, + 202, + 100, + 5, + 79, + 152, + 253, + 100, + 9, + 19, + 103, + 56, + 243, + 134, + 121, + 108, + 208, + 125, + 152, + 224, + 122, + 176, + 95, + 219, + 117, + 11, + 37, + 121, + 17, + 75, + 82, + 85, + 87, + 19, + 0, + 31, + 31, + 88, + 114, + 108, + 92, + 92, + 191, + 28, + 223, + 154, + 11, + 168, + 200, + 134, + 207, + 53, + 13, + 179, + 189, + 174, + 124, + 28, + 197, + 133, + 101, + 95, + 130, + 142, + 139, + 5, + 113, + 184, + 142, + 160, + 201, + 216, + 121, + 69, + 106, + 194, + 60, + 96, + 113, + 93, + 45, + 171, + 167, + 157, + 249, + 93, + 158, + 173, + 5, + 133, + 169, + 78, + 190, + 103, + 18, + 194, + 244, + 102, + 129, + 92, + 62, + 177, + 156, + 180, + 175, + 76, + 60, + 98, + 66, + 53, + 45, + 74, + 69, + 251, + 249, + 202, + 240, + 163, + 10, + 45, + 172, + 26, + 166, + 211, + 111, + 72, + 54, + 192, + 206, + 33, + 92, + 7, + 101, + 2, + 188, + 129, + 64, + 14, + 177, + 243, + 129, + 193, + 77, + 122, + 71, + 163, + 73, + 65, + 46, + 24, + 235, + 243, + 12, + 129, + 227, + 244, + 187, + 63, + 11, + 0, + 195, + 22, + 198, + 145, + 200, + 3, + 168, + 46, + 177, + 108, + 65, + 8, + 185, + 129, + 150, + 20, + 119, + 205, + 167, + 11, + 214, + 180, + 64, + 145, + 155, + 42, + 129, + 156, + 56, + 206, + 138, + 169, + 6, + 50, + 81, + 130, + 167, + 173, + 173, + 2, + 28, + 14, + 21, + 141, + 63, + 5, + 174, + 70, + 20, + 224, + 205, + 2, + 9, + 140, + 204, + 214, + 206, + 195, + 172, + 76, + 117, + 22, + 130, + 156, + 226, + 189, + 36, + 113, + 89, + 250, + 190, + 111, + 108, + 104, + 80, + 241, + 32, + 121, + 45, + 19, + 75, + 81, + 143, + 26, + 93, + 164, + 20, + 65, + 122, + 20, + 213, + 98, + 24, + 228, + 124, + 54, + 103, + 129, + 224, + 159, + 189, + 42, + 185, + 126, + 128, + 103, + 40, + 58, + 120, + 208, + 139, + 86, + 106, + 161, + 230, + 162, + 186, + 109, + 75, + 142, + 152, + 138, + 83, + 57, + 248, + 177, + 193, + 179, + 118, + 211, + 225, + 181, + 234, + 115, + 210, + 30, + 125, + 47, + 129, + 229, + 54, + 79, + 135, + 192, + 150, + 109, + 89, + 23, + 107, + 122, + 92, + 173, + 18, + 209, + 204, + 178, + 66, + 24, + 137, + 38, + 161, + 195, + 41, + 204, + 228, + 199, + 84, + 219, + 198, + 65, + 69, + 217, + 190, + 106, + 78, + 135, + 42, + 34, + 146, + 107, + 33, + 209, + 220, + 102, + 33, + 152, + 177, + 176, + 68, + 120, + 149, + 237, + 105, + 140, + 14, + 208, + 166, + 242, + 247, + 122, + 13, + 33, + 5, + 252, + 226, + 231, + 103, + 211, + 32, + 214, + 216, + 141, + 21, + 108, + 120, + 4, + 9, + 250, + 196, + 214, + 219, + 21, + 5, + 152, + 98, + 162, + 178, + 225, + 16, + 12, + 140, + 206, + 64, + 110, + 168, + 227, + 243, + 50, + 197, + 166, + 244, + 206, + 184, + 2, + 227, + 37, + 178, + 48, + 4, + 163, + 158, + 250, + 26, + 214, + 99, + 121, + 91, + 127, + 154, + 192, + 86, + 198, + 214, + 113, + 88, + 2, + 98, + 207, + 38, + 230, + 81, + 97, + 59, + 69, + 11, + 53, + 185, + 209, + 81, + 118, + 248, + 221, + 249, + 132, + 43, + 54, + 33, + 17, + 42, + 98, + 184, + 197, + 229, + 2, + 228, + 88, + 15, + 55, + 185, + 244, + 196, + 176, + 47, + 72, + 142, + 162, + 196, + 190, + 194, + 3, + 208, + 172, + 135, + 2, + 123, + 27, + 106, + 144, + 208, + 229, + 159, + 79, + 117, + 138, + 16, + 92, + 34, + 21, + 148, + 71, + 177, + 130, + 221, + 97, + 199, + 190, + 228, + 107, + 239, + 207, + 86, + 113, + 47, + 217, + 234, + 151, + 167, + 80, + 56, + 241, + 213, + 142, + 125, + 241, + 156, + 132, + 203, + 66, + 200, + 61, + 244, + 48, + 143, + 253, + 143, + 95, + 208, + 144, + 152, + 196, + 138, + 65, + 158, + 46, + 45, + 46, + 242, + 215, + 180, + 131, + 18, + 177, + 166, + 43, + 96, + 155, + 20, + 132, + 18, + 139, + 115, + 76, + 154, + 5, + 250, + 51, + 227, + 177, + 64, + 127, + 59, + 146, + 81, + 159, + 65, + 35, + 31, + 51, + 32, + 34, + 247, + 161, + 53, + 106, + 242, + 163, + 217, + 19, + 159, + 190, + 87, + 143, + 42, + 69, + 169, + 79, + 139, + 112, + 179, + 176, + 80, + 14, + 223, + 101, + 51, + 245, + 101, + 177, + 101, + 5, + 233, + 139, + 200, + 208, + 126, + 133, + 204, + 130, + 31, + 102, + 146, + 32, + 208, + 185, + 119, + 136, + 226, + 30, + 228, + 168, + 97, + 119, + 19, + 44, + 66, + 131, + 68, + 56, + 180, + 42, + 82, + 144, + 67, + 98, + 88, + 147, + 169, + 166, + 204, + 23, + 97, + 61, + 44, + 222, + 10, + 73, + 60, + 230, + 12, + 54, + 120, + 150, + 239, + 166, + 191, + 59, + 246, + 34, + 246, + 158, + 156, + 149, + 152, + 40, + 219, + 178, + 164, + 9, + 24, + 78, + 16, + 228, + 142, + 234, + 124, + 24, + 133, + 38, + 217, + 83, + 196, + 41, + 14, + 169, + 27, + 169, + 239, + 215, + 50, + 235, + 10, + 204, + 172, + 96, + 246, + 185, + 251, + 34, + 118, + 78, + 15, + 22, + 2, + 34, + 120, + 38, + 169, + 158, + 117, + 74, + 89, + 28, + 94, + 15, + 17, + 199, + 57, + 110, + 206, + 189, + 38, + 74, + 166, + 92, + 203, + 41, + 113, + 197, + 170, + 5, + 249, + 73, + 74, + 21, + 66, + 150, + 160, + 153, + 42, + 211, + 236, + 242, + 133, + 108, + 21, + 57, + 172, + 213, + 115, + 160, + 91, + 192, + 28, + 216, + 35, + 16, + 6, + 109, + 192, + 5, + 57, + 12, + 203, + 31, + 52, + 171, + 33, + 17, + 239, + 112, + 65, + 56, + 146, + 64, + 169, + 192, + 210, + 8, + 5, + 174, + 91, + 133, + 132, + 47, + 173, + 156, + 238, + 60, + 71, + 189, + 170, + 61, + 84, + 66, + 86, + 35, + 152, + 140, + 130, + 167, + 70, + 209, + 92, + 154, + 65, + 183, + 42, + 55, + 30, + 5, + 254, + 98, + 233, + 136, + 42, + 3, + 199, + 253, + 53, + 239, + 100, + 35, + 225, + 18, + 244, + 181, + 237, + 68, + 242, + 7, + 62, + 102, + 16, + 120, + 61, + 85, + 216, + 141, + 62, + 252, + 250, + 33, + 89, + 116, + 48, + 175, + 41, + 65, + 104, + 30, + 240, + 118, + 157, + 151, + 216, + 210, + 6, + 85, + 153, + 87, + 232, + 228, + 105, + 87, + 119, + 100, + 33, + 202, + 103, + 178, + 17, + 55, + 38, + 100, + 141, + 19, + 231, + 97, + 113, + 103, + 157, + 79, + 199, + 89, + 208, + 184, + 85, + 21, + 178, + 150, + 158, + 12, + 98, + 37, + 12, + 143, + 188, + 249, + 35, + 101, + 79, + 200, + 233, + 183, + 202, + 93, + 242, + 137, + 19, + 114, + 184, + 7, + 251, + 128, + 5, + 8, + 163, + 14, + 25, + 79, + 18, + 230, + 203, + 65, + 235, + 169, + 60, + 127, + 170, + 143, + 77, + 228, + 110, + 13, + 100, + 128, + 101, + 73, + 200, + 11, + 235, + 72, + 240, + 40, + 7, + 147, + 214, + 22, + 229, + 49, + 65, + 251, + 31, + 11, + 213, + 51, + 92, + 58, + 51, + 69, + 0, + 160, + 60, + 247, + 199, + 254, + 135, + 93, + 88, + 32, + 140, + 234, + 218, + 230, + 110, + 149, + 161, + 203, + 7, + 232, + 139, + 212, + 216, + 5, + 133, + 7, + 249, + 180, + 111, + 62, + 77, + 198, + 100, + 234, + 30, + 49, + 252, + 41, + 129, + 184, + 147, + 73, + 78, + 160, + 86, + 75, + 227, + 202, + 13, + 172, + 229, + 96, + 198, + 76, + 72, + 231, + 196, + 139, + 94, + 182, + 239, + 189, + 23, + 238, + 123, + 139, + 3, + 29, + 78, + 69, + 65, + 212, + 1, + 45, + 238, + 19, + 102, + 168, + 3, + 3, + 181, + 7, + 117, + 233, + 113, + 247, + 212, + 13, + 164, + 154, + 215, + 204, + 168, + 5, + 30, + 110, + 36, + 132, + 160, + 245, + 228, + 217, + 48, + 61, + 174, + 4, + 203, + 56, + 91, + 83, + 177, + 241, + 194, + 94, + 165, + 5, + 138, + 96, + 247, + 82, + 227, + 246, + 6, + 36, + 144, + 135, + 138, + 165, + 32, + 123, + 202, + 92, + 244, + 74, + 212, + 71, + 253, + 30, + 3, + 177, + 185, + 252, + 216, + 131, + 222, + 253, + 110, + 20, + 96, + 5, + 47, + 108, + 223, + 152, + 190, + 188, + 174, + 218, + 178, + 118, + 76, + 157, + 115, + 1, + 195, + 64, + 36, + 61, + 190, + 49, + 24, + 119, + 90, + 183, + 39, + 78, + 151, + 43, + 243, + 16, + 189, + 29, + 120, + 86, + 217, + 186, + 231, + 130, + 203, + 62, + 244, + 99, + 88, + 110, + 165, + 130, + 195, + 177, + 151, + 96, + 83, + 98, + 243, + 96, + 184, + 130, + 148, + 205, + 9, + 141, + 121, + 166, + 86, + 68, + 227, + 123, + 224, + 75, + 109, + 140, + 122, + 15, + 92, + 68, + 118, + 102, + 235, + 72, + 34, + 9, + 161, + 134, + 150, + 87, + 17, + 27, + 48, + 49, + 5, + 81, + 0, + 146, + 3, + 58, + 95, + 33, + 196, + 67, + 155, + 150, + 230, + 20, + 77, + 135, + 232, + 88, + 110, + 65, + 42, + 38, + 36, + 73, + 160, + 170, + 119, + 41, + 76, + 145, + 214, + 24, + 186, + 234, + 4, + 118, + 220, + 137, + 163, + 12, + 129, + 54, + 171, + 217, + 200, + 254, + 152, + 69, + 127, + 19, + 38, + 143, + 241, + 78, + 0, + 220, + 239, + 50, + 105, + 5, + 128, + 74, + 75, + 12, + 132, + 76, + 106, + 203, + 157, + 173, + 13, + 24, + 252, + 244, + 132, + 183, + 34, + 166, + 3, + 177, + 171, + 106, + 132, + 160, + 211, + 219, + 182, + 226, + 223, + 158, + 72, + 15, + 181, + 188, + 29, + 86, + 191, + 34, + 21, + 123, + 145, + 31, + 83, + 73, + 107, + 154, + 224, + 130, + 209, + 81, + 225, + 103, + 21, + 228, + 33, + 144, + 139, + 233, + 139, + 60, + 212, + 51, + 70, + 21, + 121, + 255, + 198, + 218, + 28, + 151, + 67, + 173, + 165, + 11, + 205, + 203, + 1, + 233, + 34, + 83, + 25, + 21, + 51, + 36, + 103, + 57, + 116, + 185, + 122, + 152, + 54, + 83, + 159, + 127, + 97, + 15, + 121, + 152, + 23, + 46, + 170, + 129, + 19, + 160, + 77, + 176, + 72, + 197, + 94, + 17, + 142, + 204, + 120, + 49, + 133, + 149, + 16, + 94, + 164, + 205, + 86, + 87, + 246, + 175, + 255, + 233, + 114, + 93, + 46, + 148, + 215, + 208, + 24, + 157, + 75, + 19, + 15, + 216, + 201, + 241, + 0, + 128, + 210, + 43, + 52, + 110, + 160, + 15, + 190, + 145, + 210, + 147, + 59, + 51, + 122, + 193, + 167, + 9, + 148, + 44, + 37, + 180, + 135, + 102, + 124, + 27, + 2, + 233, + 17, + 227, + 91, + 59, + 7, + 113, + 189, + 233, + 151, + 8, + 27, + 68, + 11, + 24, + 140, + 203, + 43, + 156, + 34, + 99, + 71, + 169, + 29, + 2, + 154, + 10, + 122, + 110, + 126, + 31, + 232, + 248, + 143, + 201, + 134, + 54, + 228, + 186, + 212, + 57, + 36, + 73, + 134, + 23, + 252, + 50, + 213, + 81, + 163, + 131, + 108, + 218, + 216, + 226, + 22, + 95, + 35, + 193, + 183, + 35, + 44, + 188, + 246, + 233, + 69, + 43, + 244, + 56, + 168, + 245, + 40, + 231, + 199, + 24, + 166, + 21, + 192, + 124, + 86, + 29, + 111, + 188, + 81, + 192, + 236, + 253, + 186, + 39, + 126, + 56, + 95, + 41, + 230, + 207, + 27, + 210, + 6, + 71, + 198, + 173, + 154, + 2, + 95, + 97, + 126, + 124, + 87, + 49, + 251, + 56, + 156, + 41, + 183, + 198, + 237, + 139, + 47, + 115, + 228, + 42, + 81, + 43, + 147, + 239, + 1, + 7, + 241, + 188, + 145, + 170, + 214, + 50, + 66, + 18, + 218, + 240, + 254, + 33, + 83, + 232, + 219, + 142, + 249, + 204, + 75, + 56, + 117, + 137, + 253, + 67, + 215, + 71, + 170, + 67, + 86, + 178, + 128, + 128, + 89, + 220, + 79, + 228, + 211, + 33, + 198, + 9, + 55, + 213, + 79, + 166, + 209, + 222, + 194, + 91, + 102, + 126, + 3, + 65, + 103, + 104, + 85, + 216, + 90, + 40, + 157, + 106, + 131, + 40, + 148, + 191, + 213, + 189, + 151, + 222, + 156, + 222, + 171, + 24, + 18, + 189, + 191, + 15, + 29, + 227, + 183, + 253, + 21, + 0, + 127, + 41, + 242, + 11, + 106, + 227, + 111, + 64, + 82, + 206, + 94, + 121, + 224, + 71, + 145, + 46, + 163, + 191, + 206, + 162, + 28, + 254, + 255, + 23, + 61, + 214, + 96, + 35, + 197, + 39, + 153, + 242, + 94, + 251, + 104, + 8, + 86, + 37, + 241, + 94, + 189, + 63, + 152, + 33, + 124, + 138, + 111, + 195, + 121, + 44, + 1, + 84, + 35, + 196, + 135, + 240, + 180, + 252, + 100, + 247, + 235, + 149, + 103, + 70, + 20, + 234, + 118, + 53, + 130, + 20, + 193, + 6, + 125, + 130, + 73, + 55, + 197, + 227, + 26, + 171, + 107, + 39, + 219, + 40, + 53, + 192, + 5, + 113, + 56, + 154, + 88, + 204, + 163, + 131, + 175, + 177, + 0, + 210, + 233, + 241, + 119, + 120, + 147, + 6, + 208, + 233, + 101, + 153, + 238, + 31, + 116, + 132, + 44, + 172, + 29, + 140, + 163, + 97, + 176, + 168, + 218, + 74, + 210, + 157, + 26, + 223, + 249, + 61, + 243, + 9, + 148, + 59, + 190, + 150, + 217, + 21, + 222, + 228, + 117, + 216, + 237, + 6, + 200, + 7, + 45, + 57, + 157, + 150, + 149, + 182, + 246, + 65, + 43, + 34, + 155, + 145, + 101, + 12, + 149, + 57, + 193, + 192, + 12, + 189, + 106, + 88, + 167, + 11, + 82, + 66, + 133, + 195, + 123, + 165, + 8, + 222, + 164, + 105, + 92, + 135, + 47, + 52, + 1, + 91, + 103, + 88, + 75, + 171, + 59, + 215, + 239, + 204, + 60, + 63, + 68, + 141, + 41, + 88, + 63, + 44, + 8, + 172, + 173, + 96, + 9, + 172, + 215, + 160, + 3, + 43, + 79, + 199, + 13, + 75, + 89, + 70, + 58, + 241, + 39, + 145, + 211, + 166, + 129, + 23, + 160, + 1, + 184, + 168, + 213, + 189, + 89, + 88, + 170, + 251, + 70, + 65, + 35, + 78, + 166, + 160, + 35, + 250, + 112, + 47, + 222, + 23, + 47, + 13, + 188, + 185, + 37, + 161, + 64, + 228, + 162, + 25, + 6, + 76, + 173, + 115, + 247, + 194, + 241, + 89, + 233, + 79, + 209, + 236, + 211, + 143, + 196, + 223, + 139, + 17, + 207, + 105, + 65, + 118, + 176, + 137, + 99, + 182, + 159, + 132, + 35, + 67, + 25, + 69, + 111, + 116, + 111, + 69, + 97, + 159, + 91, + 41, + 253, + 222, + 29, + 254, + 4, + 54, + 77, + 241, + 79, + 238, + 165, + 213, + 9, + 73, + 85, + 51, + 120, + 247, + 159, + 143, + 225, + 59, + 190, + 108, + 155, + 65, + 19, + 39, + 55, + 46, + 14, + 109, + 117, + 140, + 238, + 238, + 120, + 21, + 146, + 147, + 219, + 135, + 11, + 20, + 186, + 167, + 247, + 109, + 183, + 217, + 220, + 55, + 48, + 141, + 189, + 192, + 123, + 210, + 119, + 249, + 83, + 77, + 83, + 57, + 160, + 0, + 70, + 213, + 123, + 169, + 221, + 76, + 252, + 76, + 62, + 239, + 117, + 39, + 109, + 136, + 247, + 217, + 124, + 207, + 150, + 45, + 183, + 182, + 163, + 131, + 11, + 180, + 62, + 253, + 46, + 90, + 8, + 229, + 180, + 88, + 99, + 172, + 92, + 175, + 49, + 61, + 103, + 235, + 108, + 82, + 62, + 139, + 156, + 95, + 42, + 186, + 146, + 197, + 52, + 13, + 124, + 15, + 134, + 150, + 37, + 84, + 55, + 9, + 236, + 111, + 253, + 37, + 22, + 197, + 213, + 165, + 209, + 0, + 227, + 57, + 37, + 233, + 149, + 74, + 120, + 62, + 179, + 154, + 244, + 238, + 36, + 167, + 153, + 1, + 137, + 117, + 207, + 41, + 83, + 78, + 203, + 186, + 156, + 100, + 126, + 167, + 209, + 238, + 78, + 185, + 105, + 254, + 117, + 226, + 121, + 68, + 58, + 58, + 43, + 219, + 254, + 109, + 238, + 201, + 208, + 9, + 182, + 221, + 155, + 110, + 120, + 52, + 51, + 132, + 221, + 209, + 194, + 157, + 16, + 220, + 209, + 236, + 72, + 29, + 180, + 242, + 195, + 245, + 119, + 122, + 37, + 88, + 214, + 3, + 54, + 183, + 204, + 6, + 29, + 109, + 61, + 229, + 88, + 31, + 236, + 215, + 207, + 135, + 35, + 121, + 120, + 192, + 226, + 12, + 130, + 77, + 152, + 65, + 234, + 189, + 106, + 232, + 37, + 157, + 17, + 80, + 42, + 140, + 62, + 177, + 16, + 115, + 241, + 88, + 3, + 73, + 135, + 242, + 190, + 172, + 75, + 223, + 86, + 85, + 236, + 209, + 174, + 25, + 249, + 42, + 185, + 91, + 184, + 44, + 140, + 38, + 17, + 59, + 84, + 55, + 161, + 89, + 86, + 158, + 164, + 250, + 193, + 26, + 75, + 110, + 127, + 87, + 237, + 10, + 32, + 102, + 124, + 29, + 116, + 213, + 228, + 239, + 110, + 121, + 3, + 13, + 86, + 96, + 125, + 196, + 60, + 169, + 120, + 114, + 215, + 183, + 78, + 23, + 186, + 70, + 15, + 43, + 9, + 144, + 71, + 158, + 155, + 207, + 160, + 245, + 90, + 59, + 228, + 152, + 122, + 163, + 42, + 208, + 84, + 232, + 244, + 206, + 61, + 166, + 52, + 158, + 59, + 58, + 189, + 84, + 27, + 31, + 203, + 218, + 87, + 80, + 219, + 186, + 85, + 29, + 245, + 76, + 162, + 6, + 209, + 246, + 170, + 32, + 176, + 8, + 77, + 148, + 121, + 91, + 29, + 114, + 23, + 205, + 19, + 153, + 109, + 217, + 233, + 20, + 130, + 199, + 107, + 248, + 240, + 181, + 222, + 149, + 0, + 185, + 244, + 35, + 180, + 33, + 143, + 138, + 79, + 108, + 199, + 209, + 254, + 122, + 215, + 132, + 237, + 15, + 10, + 226, + 120, + 158, + 23, + 105, + 119, + 255, + 240, + 238, + 112, + 81, + 98, + 166, + 147, + 13, + 43, + 98, + 21, + 149, + 110, + 143, + 184, + 252, + 37, + 118, + 92, + 157, + 111, + 58, + 238, + 75, + 197, + 57, + 207, + 57, + 178, + 11, + 123, + 46, + 241, + 127, + 104, + 100, + 97, + 117, + 16, + 99, + 72, + 124, + 49, + 81, + 119, + 162, + 134, + 93, + 33, + 164, + 175, + 45, + 109, + 195, + 140, + 75, + 134, + 130, + 194, + 194, + 155, + 81, + 68, + 208, + 202, + 6, + 20, + 69, + 188, + 19, + 155, + 208, + 94, + 195, + 224, + 38, + 45, + 15, + 97, + 106, + 224, + 157, + 44, + 94, + 80, + 185, + 153, + 163, + 46, + 167, + 155, + 217, + 63, + 109, + 78, + 10, + 173, + 128, + 184, + 158, + 228, + 35, + 248, + 212, + 116, + 233, + 241, + 94, + 15, + 217, + 156, + 227, + 31, + 179, + 228, + 48, + 77, + 90, + 16, + 20, + 157, + 154, + 101, + 223, + 136, + 14, + 163, + 58, + 93, + 150, + 62, + 229, + 129, + 159, + 44, + 151, + 137, + 227, + 141, + 240, + 248, + 14, + 174, + 157, + 34, + 81, + 123, + 201, + 124, + 210, + 26, + 21, + 202, + 158, + 121, + 217, + 92, + 101, + 246, + 181, + 16, + 75, + 107, + 16, + 127, + 198, + 0, + 132, + 152, + 38, + 169, + 60, + 113, + 242, + 27, + 163, + 38, + 129, + 140, + 237, + 196, + 78, + 24, + 127, + 44, + 198, + 166, + 110, + 51, + 46, + 16, + 8, + 216, + 108, + 191, + 183, + 20, + 86, + 253, + 202, + 183, + 202, + 248, + 124, + 91, + 99, + 199, + 106, + 110, + 42, + 18, + 115, + 23, + 211, + 252, + 50, + 199, + 183, + 157, + 235, + 52, + 101, + 243, + 154, + 81, + 241, + 248, + 204, + 17, + 78, + 88, + 224, + 202, + 192, + 180, + 6, + 115, + 35, + 233, + 18, + 167, + 40, + 198, + 84, + 45, + 69, + 125, + 236, + 131, + 92, + 195, + 90, + 202, + 20, + 142, + 199, + 189, + 142, + 255, + 211, + 87, + 187, + 9, + 57, + 167, + 143, + 115, + 97, + 137, + 181, + 46, + 109, + 254, + 7, + 149, + 179, + 38, + 183, + 112, + 151, + 53, + 242, + 205, + 83, + 140, + 80, + 125, + 201, + 80, + 158, + 195, + 99, + 93, + 15, + 86, + 122, + 16, + 117, + 98, + 153, + 98, + 41, + 115, + 252, + 17, + 140, + 245, + 54, + 20, + 62, + 137, + 66, + 168, + 216, + 186, + 222, + 52, + 17, + 179, + 169, + 26, + 120, + 79, + 157, + 64, + 197, + 156, + 24, + 170, + 238, + 62, + 221, + 46, + 4, + 189, + 118, + 80, + 140, + 159, + 238, + 233, + 51, + 125, + 190, + 229, + 144, + 82, + 21, + 214, + 5, + 175, + 130, + 112, + 6, + 214, + 124, + 40, + 62, + 237, + 239, + 108, + 19, + 151, + 217, + 219, + 71, + 62, + 204, + 46, + 206, + 182, + 178, + 21, + 141, + 22, + 126, + 251, + 51, + 70, + 52, + 41, + 25, + 217, + 140, + 62, + 244, + 33, + 28, + 83, + 73, + 75, + 81, + 47, + 202, + 64, + 96, + 243, + 192, + 72, + 254, + 160, + 135, + 96, + 240, + 187, + 171, + 110, + 166, + 58, + 113, + 181, + 192, + 49, + 81, + 28, + 65, + 7, + 66, + 218, + 238, + 250, + 105, + 141, + 51, + 159, + 107, + 53, + 237, + 253, + 162, + 235, + 169, + 22, + 191, + 194, + 4, + 116, + 216, + 112, + 57, + 99, + 144, + 254, + 66, + 226, + 90, + 56, + 108, + 41, + 167, + 77, + 155, + 221, + 151, + 105, + 61, + 130, + 94, + 72, + 139, + 94, + 126, + 229, + 228, + 254, + 88, + 114, + 112, + 241, + 56, + 19, + 11, + 180, + 96, + 80, + 61, + 134, + 41, + 111, + 80, + 99, + 62, + 166, + 168, + 15, + 132, + 78, + 68, + 116, + 175, + 223, + 48, + 108, + 183, + 81, + 245, + 143, + 232, + 94, + 221, + 202, + 140, + 162, + 254, + 242, + 44, + 233, + 220, + 83, + 79, + 15, + 36, + 193, + 217, + 87, + 94, + 152, + 173, + 132, + 254, + 218, + 51, + 154, + 29, + 239, + 162, + 160, + 184, + 109, + 204, + 77, + 132, + 102, + 13, + 213, + 250, + 21, + 34, + 8, + 50, + 247, + 115, + 125, + 4, + 43, + 156, + 30, + 152, + 90, + 100, + 102, + 52, + 47, + 153, + 87, + 83, + 198, + 228, + 112, + 62, + 212, + 212, + 174, + 248, + 58, + 73, + 216, + 2, + 195, + 28, + 163, + 118, + 94, + 44, + 40, + 247, + 36, + 42, + 208, + 165, + 65, + 132, + 23, + 217, + 98, + 54, + 173, + 138, + 155, + 48, + 253, + 198, + 154, + 246, + 181, + 46, + 67, + 48, + 238, + 206, + 109, + 80, + 227, + 251, + 122, + 109, + 65, + 191, + 41, + 86, + 88, + 168, + 209, + 161, + 152, + 190, + 204, + 211, + 106, + 110, + 217, + 144, + 241, + 85, + 86, + 234, + 37, + 14, + 198, + 129, + 30, + 194, + 136, + 239, + 1, + 237, + 77, + 38, + 254, + 170, + 221, + 207, + 175, + 87, + 18, + 209, + 132, + 108, + 2, + 177, + 36, + 0, + 27, + 40, + 189, + 70, + 89, + 0, + 49, + 231, + 201, + 51, + 39, + 192, + 229, + 31, + 65, + 152, + 189, + 18, + 112, + 27, + 138, + 59, + 56, + 77, + 44, + 219, + 109, + 118, + 80, + 215, + 133, + 130, + 127, + 41, + 146, + 105, + 208, + 56, + 155, + 104, + 254, + 76, + 255, + 222, + 55, + 13, + 225, + 215, + 125, + 109, + 140, + 175, + 215, + 131, + 245, + 135, + 216, + 250, + 162, + 45, + 61, + 176, + 227, + 178, + 150, + 214, + 26, + 20, + 222, + 141, + 35, + 55, + 64, + 207, + 63, + 102, + 183, + 111, + 103, + 40, + 197, + 113, + 235, + 153, + 219, + 48, + 157, + 21, + 83, + 144, + 100, + 237, + 247, + 59, + 141, + 28, + 193, + 45, + 249, + 128, + 86, + 133, + 205, + 149, + 109, + 212, + 239, + 105, + 49, + 75, + 82, + 60, + 134, + 7, + 209, + 219, + 187, + 93, + 246, + 93, + 37, + 206, + 117, + 97, + 86, + 39, + 76, + 228, + 184, + 140, + 208, + 128, + 92, + 204, + 206, + 232, + 206, + 163, + 11, + 93, + 237, + 139, + 115, + 167, + 180, + 62, + 122, + 84, + 78, + 5, + 239, + 107, + 247, + 220, + 38, + 246, + 13, + 233, + 180, + 24, + 236, + 129, + 169, + 83, + 62, + 196, + 226, + 229, + 11, + 37, + 164, + 0, + 140, + 82, + 206, + 142, + 3, + 79, + 224, + 95, + 231, + 161, + 190, + 240, + 2, + 124, + 164, + 181, + 116, + 150, + 98, + 104, + 83, + 8, + 135, + 219, + 109, + 139, + 141, + 188, + 9, + 175, + 99, + 202, + 185, + 178, + 206, + 121, + 138, + 49, + 84, + 171, + 27, + 253, + 196, + 210, + 220, + 227, + 16, + 235, + 69, + 202, + 154, + 208, + 132, + 54, + 109, + 152, + 253, + 43, + 243, + 142, + 117, + 160, + 104, + 127, + 219, + 244, + 148, + 75, + 110, + 33, + 183, + 196, + 8, + 120, + 1, + 176, + 162, + 23, + 233, + 243, + 85, + 187, + 2, + 233, + 89, + 26, + 223, + 50, + 224, + 106, + 21, + 135, + 161, + 201, + 195, + 212, + 44, + 94, + 183, + 39, + 34, + 60, + 155, + 246, + 235, + 15, + 223, + 127, + 49, + 161, + 225, + 103, + 71, + 64, + 62, + 85, + 197, + 187, + 109, + 101, + 195, + 43, + 1, + 68, + 201, + 231, + 172, + 87, + 72, + 20, + 218, + 43, + 34, + 31, + 138, + 229, + 90, + 178, + 239, + 13, + 138, + 131, + 2, + 233, + 157, + 69, + 82, + 197, + 15, + 82, + 14, + 201, + 24, + 81, + 39, + 199, + 124, + 5, + 203, + 205, + 37, + 252, + 79, + 226, + 134, + 91, + 68, + 67, + 215, + 16, + 212, + 220, + 3, + 95, + 149, + 193, + 61, + 108, + 175, + 119, + 140, + 130, + 156, + 91, + 209, + 156, + 63, + 32, + 244, + 134, + 252, + 224, + 251, + 134, + 125, + 210, + 96, + 49, + 128, + 111, + 223, + 138, + 65, + 99, + 12, + 133, + 3, + 96, + 213, + 124, + 88, + 18, + 198, + 224, + 113, + 185, + 74, + 146, + 100, + 188, + 23, + 5, + 139, + 85, + 177, + 191, + 21, + 223, + 61, + 23, + 245, + 186, + 46, + 167, + 10, + 159, + 30, + 31, + 51, + 91, + 59, + 110, + 252, + 181, + 146, + 9, + 169, + 168, + 254, + 1, + 147, + 234, + 115, + 211, + 221, + 214, + 56, + 90, + 167, + 108, + 132, + 46, + 8, + 15, + 94, + 107, + 80, + 166, + 174, + 155, + 15, + 235, + 193, + 246, + 107, + 190, + 39, + 172, + 196, + 74, + 101, + 228, + 245, + 166, + 72, + 166, + 85, + 133, + 245, + 244, + 235, + 140, + 2, + 55, + 34, + 44, + 92, + 115, + 178, + 227, + 146, + 89, + 128, + 233, + 68, + 237, + 81, + 126, + 127, + 77, + 160, + 163, + 243, + 229, + 248, + 146, + 230, + 2, + 135, + 151, + 242, + 234, + 89, + 235, + 189, + 60, + 91, + 116, + 191, + 23, + 47, + 180, + 46, + 245, + 103, + 215, + 54, + 116, + 72, + 109, + 96, + 77, + 74, + 40, + 14, + 221, + 80, + 100, + 174, + 57, + 49, + 146, + 240, + 149, + 13, + 203, + 126, + 38, + 193, + 186, + 68, + 51, + 56, + 75, + 133, + 45, + 228, + 171, + 176, + 207, + 111, + 75, + 222, + 179, + 144, + 234, + 13, + 0, + 58, + 89, + 100, + 32, + 50, + 108, + 185, + 81, + 234, + 30, + 29, + 19, + 138, + 29, + 58, + 9, + 230, + 51, + 238, + 189, + 85, + 127, + 89, + 154, + 168, + 183, + 128, + 254, + 188, + 127, + 68, + 232, + 165, + 130, + 156, + 37, + 183, + 226, + 239, + 193, + 53, + 100, + 194, + 85, + 253, + 69, + 134, + 227, + 82, + 136, + 80, + 143, + 150, + 223, + 95, + 247, + 126, + 4, + 248, + 102, + 127, + 7, + 23, + 48, + 58, + 98, + 238, + 156, + 40, + 210, + 200, + 191, + 98, + 89, + 188, + 59, + 25, + 164, + 220, + 183, + 98, + 19, + 151, + 218, + 49, + 195, + 175, + 134, + 252, + 212, + 211, + 140, + 196, + 42, + 2, + 230, + 84, + 2, + 56, + 201, + 2, + 226, + 194, + 203, + 212, + 78, + 249, + 15, + 120, + 49, + 117, + 182, + 99, + 185, + 47, + 68, + 158, + 146, + 37, + 9, + 173, + 252, + 115, + 238, + 222, + 244, + 40, + 64, + 46, + 82, + 187, + 200, + 155, + 225, + 95, + 228, + 180, + 103, + 188, + 89, + 228, + 42, + 128, + 148, + 210, + 251, + 26, + 81, + 99, + 186, + 225, + 155, + 145, + 25, + 43, + 50, + 240, + 20, + 172, + 180, + 55, + 167, + 196, + 114, + 67, + 31, + 89, + 155, + 33, + 103, + 26, + 23, + 74, + 113, + 27, + 9, + 54, + 93, + 103, + 211, + 41, + 92, + 47, + 58, + 30, + 63, + 34, + 188, + 129, + 77, + 124, + 233, + 22, + 37, + 31, + 174, + 180, + 197, + 126, + 247, + 100, + 40, + 4, + 80, + 25, + 148, + 147, + 13, + 231, + 76, + 102, + 160, + 73, + 186, + 108, + 249, + 119, + 153, + 31, + 1, + 60, + 96, + 240, + 98, + 125, + 179, + 141, + 55, + 164, + 177, + 96, + 57, + 72, + 45, + 217, + 98, + 214, + 45, + 178, + 213, + 236, + 49, + 42, + 246, + 48, + 44, + 119, + 125, + 141, + 23, + 131, + 92, + 239, + 54, + 1, + 209, + 125, + 98, + 200, + 148, + 188, + 199, + 49, + 208, + 143, + 238, + 253, + 20, + 98, + 126, + 182, + 186, + 70, + 236, + 159, + 76, + 85, + 67, + 87, + 29, + 196, + 108, + 84, + 149, + 248, + 80, + 40, + 109, + 189, + 200, + 24, + 233, + 199, + 6, + 89, + 42, + 237, + 36, + 177, + 15, + 190, + 163, + 173, + 15, + 189, + 187, + 47, + 219, + 63, + 154, + 15, + 152, + 217, + 96, + 204, + 177, + 111, + 190, + 173, + 96, + 216, + 251, + 1, + 12, + 224, + 103, + 205, + 108, + 25, + 186, + 2, + 85, + 93, + 232, + 202, + 54, + 66, + 172, + 141, + 80, + 238, + 215, + 78, + 129, + 150, + 55, + 102, + 104, + 9, + 67, + 6, + 17, + 27, + 203, + 121, + 55, + 132, + 132, + 240, + 183, + 63, + 5, + 45, + 48, + 94, + 195, + 183, + 51, + 115, + 85, + 7, + 209, + 43, + 121, + 204, + 72, + 158, + 24, + 91, + 4, + 55, + 113, + 210, + 203, + 175, + 179, + 89, + 110, + 220, + 235, + 131, + 121, + 64, + 192, + 47, + 89, + 166, + 240, + 143, + 71, + 210, + 239, + 41, + 138, + 102, + 153, + 108, + 176, + 159, + 153, + 119, + 113, + 233, + 251, + 63, + 124, + 134, + 254, + 12, + 234, + 172, + 37, + 56, + 168, + 44, + 223, + 65, + 92, + 179, + 224, + 207, + 58, + 109, + 110, + 154, + 41, + 38, + 84, + 145, + 109, + 228, + 27, + 65, + 186, + 124, + 158, + 150, + 58, + 170, + 99, + 30, + 252, + 243, + 2, + 62, + 41, + 199, + 6, + 43, + 40, + 185, + 202, + 8, + 135, + 166, + 226, + 163, + 76, + 60, + 23, + 153, + 209, + 134, + 19, + 70, + 79, + 53, + 172, + 158, + 89, + 56, + 25, + 118, + 65, + 218, + 107, + 111, + 130, + 64, + 163, + 92, + 74, + 181, + 226, + 213, + 122, + 77, + 193, + 254, + 145, + 187, + 38, + 162, + 73, + 237, + 203, + 195, + 36, + 248, + 185, + 229, + 170, + 61, + 152, + 182, + 44, + 46, + 30, + 137, + 171, + 20, + 164, + 17, + 49, + 123, + 34, + 193, + 249, + 201, + 166, + 199, + 246, + 26, + 219, + 16, + 229, + 247, + 238, + 148, + 243, + 77, + 6, + 227, + 132, + 78, + 47, + 13, + 33, + 196, + 200, + 98, + 30, + 63, + 220, + 193, + 77, + 160, + 45, + 121, + 221, + 208, + 190, + 216, + 108, + 6, + 201, + 213, + 218, + 215, + 170, + 52, + 93, + 34, + 79, + 94, + 57, + 15, + 145, + 70, + 179, + 213, + 242, + 239, + 125, + 90, + 13, + 92, + 62, + 114, + 68, + 19, + 10, + 35, + 2, + 181, + 199, + 166, + 39, + 157, + 38, + 32, + 164, + 73, + 88, + 34, + 62, + 64, + 141, + 175, + 28, + 54, + 44, + 117, + 38, + 164, + 135, + 73, + 199, + 38, + 38, + 209, + 172, + 7, + 233, + 21, + 83, + 23, + 29, + 231, + 23, + 108, + 169, + 145, + 127, + 40, + 1, + 54, + 146, + 194, + 111, + 76, + 145, + 145, + 212, + 107, + 152, + 248, + 147, + 49, + 7, + 255, + 18, + 194, + 130, + 118, + 48, + 138, + 51, + 98, + 234, + 90, + 146, + 223, + 141, + 232, + 186, + 140, + 255, + 23, + 128, + 114, + 247, + 137, + 17, + 20, + 2, + 218, + 148, + 132, + 106, + 171, + 71, + 235, + 3, + 78, + 101, + 218, + 146, + 109, + 229, + 217, + 89, + 182, + 72, + 75, + 42, + 212, + 144, + 193, + 224, + 85, + 162, + 228, + 88, + 215, + 241, + 159, + 137, + 148, + 70, + 26, + 77, + 73, + 172, + 63, + 108, + 211, + 232, + 194, + 61, + 167, + 84, + 116, + 188, + 117, + 102, + 144, + 208, + 254, + 239, + 69, + 34, + 207, + 135, + 120, + 113, + 201, + 243, + 177, + 126, + 75, + 18, + 242, + 186, + 237, + 112, + 211, + 40, + 28, + 204, + 55, + 72, + 110, + 223, + 236, + 218, + 166, + 101, + 193, + 53, + 69, + 65, + 195, + 252, + 193, + 70, + 30, + 75, + 147, + 157, + 238, + 239, + 112, + 176, + 247, + 0, + 128, + 30, + 10, + 59, + 230, + 114, + 30, + 60, + 211, + 221, + 215, + 174, + 87, + 173, + 157, + 78, + 157, + 231, + 4, + 43, + 122, + 39, + 110, + 50, + 187, + 50, + 160, + 15, + 192, + 91, + 137, + 77, + 231, + 205, + 128, + 97, + 136, + 226, + 50, + 183, + 13, + 44, + 177, + 20, + 92, + 150, + 133, + 165, + 83, + 205, + 229, + 177, + 142, + 81, + 235, + 155, + 16, + 57, + 91, + 32, + 196, + 235, + 225, + 184, + 96, + 232, + 22, + 114, + 75, + 85, + 194, + 207, + 223, + 144, + 202, + 98, + 222, + 193, + 161, + 121, + 27, + 128, + 253, + 212, + 86, + 117, + 105, + 154, + 112, + 68, + 95, + 120, + 234, + 182, + 208, + 86, + 33, + 19, + 42, + 37, + 133, + 139, + 230, + 8, + 96, + 154, + 255, + 13, + 148, + 139, + 140, + 197, + 104, + 105, + 136, + 103, + 156, + 173, + 12, + 32, + 86, + 228, + 166, + 12, + 96, + 133, + 199, + 52, + 15, + 165, + 60, + 100, + 205, + 121, + 22, + 243, + 26, + 34, + 48, + 74, + 178, + 207, + 5, + 183, + 97, + 251, + 49, + 194, + 100, + 141, + 148, + 51, + 85, + 205, + 181, + 55, + 244, + 86, + 16, + 124, + 20, + 172, + 130, + 77, + 123, + 135, + 137, + 242, + 105, + 70, + 162, + 222, + 75, + 51, + 177, + 95, + 226, + 101, + 10, + 99, + 100, + 207, + 210, + 12, + 100, + 0, + 160, + 48, + 191, + 134, + 197, + 211, + 242, + 142, + 195, + 52, + 173, + 240, + 73, + 145, + 127, + 13, + 245, + 23, + 115, + 24, + 219, + 104, + 94, + 183, + 42, + 109, + 121, + 135, + 150, + 121, + 49, + 3, + 223, + 60, + 235, + 202, + 198, + 113, + 126, + 204, + 119, + 25, + 242, + 155, + 185, + 221, + 117, + 150, + 95, + 36, + 201, + 207, + 241, + 19, + 125, + 215, + 182, + 3, + 45, + 248, + 38, + 7, + 165, + 62, + 143, + 248, + 155, + 3, + 59, + 218, + 45, + 218, + 90, + 83, + 123, + 142, + 94, + 31, + 47, + 3, + 63, + 189, + 234, + 40, + 23, + 206, + 214, + 76, + 214, + 66, + 202, + 2, + 26, + 106, + 146, + 255, + 36, + 182, + 27, + 37, + 217, + 5, + 251, + 73, + 255, + 12, + 182, + 54, + 229, + 25, + 137, + 10, + 48, + 153, + 139, + 199, + 40, + 172, + 58, + 254, + 81, + 57, + 188, + 131, + 223, + 185, + 112, + 236, + 244, + 62, + 90, + 181, + 64, + 121, + 181, + 101, + 62, + 30, + 3, + 142, + 103, + 135, + 91, + 92, + 149, + 108, + 29, + 137, + 252, + 24, + 6, + 53, + 31, + 133, + 55, + 120, + 133, + 148, + 18, + 68, + 64, + 213, + 50, + 70, + 96, + 129, + 242, + 252, + 198, + 62, + 237, + 224, + 8, + 138, + 76, + 205, + 209, + 92, + 141, + 75, + 39, + 70, + 158, + 47, + 47, + 45, + 140, + 169, + 206, + 158, + 254, + 108, + 12, + 14, + 244, + 130, + 110, + 25, + 194, + 16, + 82, + 48, + 119, + 78, + 135, + 130, + 116, + 207, + 237, + 63, + 240, + 29, + 128, + 59, + 39, + 117, + 84, + 119, + 155, + 230, + 251, + 66, + 235, + 94, + 6, + 186, + 66, + 29, + 44, + 87, + 88, + 29, + 115, + 21, + 200, + 132, + 253, + 206, + 11, + 15, + 72, + 165, + 232, + 87, + 135, + 67, + 0, + 227, + 64, + 110, + 58, + 78, + 196, + 185, + 89, + 88, + 120, + 252, + 107, + 229, + 236, + 103, + 37, + 132, + 113, + 20, + 135, + 41, + 226, + 190, + 175, + 32, + 161, + 99, + 172, + 16, + 237, + 23, + 118, + 121, + 146, + 84, + 66, + 72, + 151, + 128, + 28, + 203, + 231, + 204, + 0, + 105, + 69, + 241, + 127, + 43, + 178, + 26, + 75, + 104, + 28, + 140, + 99, + 70, + 211, + 76, + 121, + 108, + 173, + 75, + 2, + 198, + 145, + 213, + 248, + 223, + 203, + 14, + 120, + 180, + 80, + 48, + 30, + 120, + 13, + 170, + 184, + 70, + 186, + 7, + 218, + 94, + 205, + 59, + 209, + 24, + 106, + 136, + 24, + 227, + 0, + 155, + 200, + 129, + 153, + 131, + 135, + 32, + 183, + 26, + 87, + 44, + 132, + 44, + 142, + 3, + 82, + 229, + 103, + 180, + 141, + 96, + 15, + 114, + 119, + 31, + 162, + 221, + 120, + 13, + 173, + 178, + 102, + 93, + 253, + 234, + 240, + 73, + 26, + 225, + 234, + 250, + 93, + 110, + 109, + 21, + 245, + 228, + 209, + 134, + 99, + 76, + 198, + 23, + 185, + 46, + 186, + 41, + 174, + 100, + 229, + 123, + 47, + 145, + 192, + 0, + 29, + 186, + 165, + 55, + 141, + 88, + 92, + 102, + 71, + 76, + 145, + 176, + 129, + 132, + 235, + 71, + 180, + 122, + 32, + 47, + 253, + 36, + 132, + 91, + 233, + 126, + 124, + 226, + 98, + 150, + 176, + 47, + 227, + 233, + 189, + 38, + 235, + 94, + 238, + 230, + 80, + 6, + 255, + 170, + 36, + 193, + 41, + 19, + 20, + 95, + 64, + 80, + 218, + 135, + 136, + 237, + 31, + 175, + 60, + 5, + 188, + 205, + 106, + 122, + 26, + 102, + 155, + 80, + 162, + 50, + 54, + 211, + 214, + 159, + 238, + 37, + 237, + 239, + 114, + 182, + 39, + 202, + 213, + 83, + 188, + 199, + 138, + 37, + 184, + 12, + 73, + 164, + 147, + 9, + 128, + 108, + 140, + 218, + 167, + 100, + 155, + 187, + 76, + 108, + 176, + 79, + 183, + 75, + 63, + 30, + 34, + 253, + 98, + 182, + 151, + 3, + 169, + 96, + 191, + 85, + 97, + 14, + 82, + 97, + 90, + 100, + 179, + 138, + 166, + 187, + 61, + 111, + 46, + 10, + 45, + 133, + 46, + 157, + 74, + 198, + 126, + 135, + 185, + 149, + 137, + 170, + 156, + 68, + 211, + 167, + 132, + 96, + 18, + 130, + 79, + 199, + 59, + 182, + 8, + 80, + 181, + 190, + 134, + 231, + 7, + 125, + 3, + 132, + 22, + 116, + 193, + 107, + 252, + 184, + 205, + 78, + 48, + 225, + 81, + 111, + 6, + 139, + 72, + 34, + 109, + 33, + 29, + 27, + 213, + 104, + 208, + 0, + 208, + 9, + 4, + 56, + 235, + 73, + 222, + 7, + 12, + 96, + 193, + 65, + 224, + 208, + 49, + 170, + 174, + 216, + 250, + 8, + 76, + 139, + 22, + 189, + 225, + 233, + 46, + 111, + 23, + 16, + 119, + 131, + 172, + 103, + 87, + 116, + 86, + 115, + 141, + 94, + 135, + 104, + 89, + 240, + 23, + 251, + 145, + 224, + 85, + 142, + 252, + 25, + 79, + 203, + 189, + 157, + 4, + 96, + 187, + 244, + 194, + 188, + 251, + 125, + 98, + 255, + 148, + 46, + 201, + 138, + 233, + 88, + 71, + 153, + 248, + 226, + 234, + 176, + 122, + 214, + 147, + 43, + 54, + 5, + 53, + 2, + 74, + 250, + 162, + 22, + 12, + 82, + 165, + 23, + 100, + 158, + 63, + 14, + 187, + 127, + 11, + 99, + 192, + 70, + 96, + 193, + 54, + 65, + 245, + 120, + 221, + 60, + 95, + 85, + 191, + 57, + 125, + 94, + 156, + 1, + 149, + 23, + 197, + 65, + 180, + 57, + 15, + 167, + 108, + 130, + 125, + 199, + 169, + 158, + 61, + 243, + 197, + 55, + 73, + 94, + 198, + 30, + 186, + 127, + 7, + 124, + 251, + 7, + 30, + 226, + 234, + 224, + 131, + 248, + 27, + 42, + 82, + 209, + 239, + 67, + 2, + 35, + 139, + 215, + 126, + 135, + 255, + 93, + 214, + 215, + 105, + 14, + 209, + 51, + 169, + 125, + 71, + 161, + 232, + 1, + 182, + 118, + 255, + 170, + 26, + 73, + 183, + 175, + 210, + 251, + 255, + 228, + 232, + 31, + 188, + 187, + 124, + 242, + 147, + 24, + 14, + 93, + 235, + 90, + 234, + 107, + 86, + 187, + 138, + 124, + 177, + 61, + 228, + 169, + 122, + 59, + 31, + 105, + 160, + 105, + 87, + 5, + 216, + 109, + 134, + 219, + 227, + 6, + 248, + 162, + 164, + 71, + 55, + 208, + 39, + 56, + 99, + 185, + 193, + 183, + 240, + 32, + 30, + 38, + 186, + 231, + 137, + 68, + 165, + 201, + 107, + 34, + 99, + 42, + 68, + 18, + 185, + 245, + 79, + 238, + 75, + 36, + 152, + 34, + 48, + 152, + 63, + 63, + 241, + 247, + 119, + 172, + 10, + 196, + 5, + 16, + 50, + 69, + 145, + 177, + 143, + 34, + 165, + 23, + 95, + 191, + 244, + 252, + 235, + 216, + 119, + 54, + 151, + 5, + 138, + 211, + 154, + 113, + 53, + 194, + 160, + 210, + 43, + 159, + 147, + 226, + 232, + 31, + 167, + 152, + 52, + 142, + 116, + 118, + 131, + 231, + 72, + 178, + 224, + 58, + 31, + 88, + 147, + 12, + 246, + 224, + 234, + 4, + 46, + 49, + 203, + 45, + 69, + 100, + 12, + 114, + 39, + 228, + 168, + 81, + 234, + 230, + 237, + 161, + 106, + 59, + 136, + 139, + 74, + 52, + 151, + 56, + 130, + 66, + 2, + 167, + 44, + 3, + 192, + 177, + 49, + 72, + 151, + 201, + 67, + 204, + 26, + 114, + 170, + 148, + 154, + 9, + 224, + 144, + 16, + 81, + 90, + 18, + 23, + 197, + 200, + 38, + 136, + 176, + 133, + 87, + 236, + 14, + 254, + 195, + 75, + 88, + 193, + 52, + 7, + 123, + 52, + 101, + 199, + 86, + 82, + 164, + 133, + 24, + 85, + 169, + 126, + 98, + 162, + 122, + 32, + 125, + 254, + 145, + 228, + 213, + 179, + 104, + 183, + 63, + 11, + 33, + 40, + 255, + 76, + 185, + 234, + 88, + 111, + 173, + 190, + 142, + 254, + 165, + 203, + 93, + 90, + 116, + 120, + 239, + 200, + 35, + 123, + 193, + 196, + 215, + 22, + 201, + 23, + 98, + 13, + 186, + 194, + 175, + 248, + 101, + 197, + 108, + 55, + 109, + 186, + 101, + 127, + 76, + 117, + 237, + 84, + 64, + 105, + 6, + 66, + 108, + 0, + 157, + 235, + 1, + 171, + 186, + 12, + 125, + 84, + 224, + 86, + 60, + 126, + 133, + 174, + 83, + 16, + 55, + 211, + 211, + 234, + 177, + 147, + 48, + 2, + 74, + 143, + 34, + 50, + 238, + 82, + 158, + 69, + 216, + 126, + 191, + 169, + 113, + 128, + 211, + 162, + 29, + 99, + 189, + 81, + 157, + 156, + 18, + 91, + 209, + 163, + 26, + 122, + 240, + 176, + 248, + 184, + 59, + 136, + 115, + 72, + 243, + 244, + 69, + 152, + 179, + 160, + 24, + 0, + 60, + 249, + 142, + 161, + 28, + 16, + 234, + 152, + 132, + 84, + 117, + 56, + 147, + 12, + 226, + 237, + 133, + 43, + 224, + 120, + 122, + 205, + 27, + 109, + 175, + 77, + 130, + 161, + 193, + 92, + 96, + 135, + 175, + 66, + 240, + 176, + 95, + 240, + 234, + 100, + 142, + 81, + 119, + 214, + 212, + 182, + 204, + 85, + 49, + 199, + 198, + 126, + 121, + 57, + 57, + 94, + 245, + 155, + 207, + 168, + 247, + 56, + 246, + 171, + 95, + 15, + 28, + 100, + 248, + 232, + 13, + 12, + 74, + 83, + 138, + 126, + 144, + 17, + 61, + 220, + 107, + 50, + 17, + 195, + 136, + 208, + 86, + 38, + 151, + 45, + 140, + 100, + 146, + 59, + 67, + 20, + 253, + 178, + 180, + 22, + 207, + 156, + 219, + 30, + 2, + 241, + 186, + 89, + 230, + 199, + 146, + 156, + 175, + 156, + 122, + 74, + 146, + 244, + 111, + 76, + 135, + 186, + 196, + 203, + 207, + 117, + 1, + 100, + 60, + 63, + 236, + 32, + 13, + 12, + 7, + 243, + 154, + 41, + 117, + 212, + 72, + 100, + 185, + 147, + 210, + 151, + 45, + 244, + 85, + 109, + 11, + 91, + 171, + 171, + 148, + 162, + 28, + 61, + 155, + 85, + 0, + 172, + 127, + 228, + 205, + 14, + 154, + 72, + 78, + 71, + 169, + 189, + 64, + 49, + 197, + 82, + 1, + 7, + 110, + 99, + 160, + 19, + 55, + 56, + 255, + 32, + 106, + 225, + 240, + 66, + 159, + 17, + 3, + 31, + 107, + 221, + 30, + 56, + 54, + 156, + 163, + 58, + 49, + 237, + 241, + 206, + 18, + 220, + 213, + 19, + 8, + 98, + 133, + 236, + 70, + 8, + 74, + 43, + 135, + 99, + 144, + 45, + 135, + 249, + 195, + 52, + 24, + 148, + 172, + 224, + 118, + 176, + 232, + 107, + 55, + 132, + 183, + 212, + 225, + 175, + 67, + 158, + 205, + 44, + 187, + 58, + 16, + 81, + 64, + 144, + 220, + 144, + 128, + 184, + 101, + 113, + 158, + 11, + 111, + 192, + 89, + 215, + 97, + 75, + 52, + 69, + 113, + 246, + 142, + 71, + 143, + 35, + 84, + 170, + 16, + 36, + 201, + 28, + 78, + 139, + 127, + 80, + 111, + 61, + 142, + 184, + 166, + 119, + 103, + 21, + 211, + 249, + 162, + 107, + 11, + 44, + 194, + 206, + 46, + 83, + 24, + 39, + 225, + 141, + 34, + 215, + 84, + 237, + 147, + 109, + 49, + 201, + 24, + 218, + 228, + 155, + 168, + 243, + 31, + 24, + 252, + 211, + 91, + 249, + 19, + 186, + 88, + 254, + 116, + 33, + 129, + 19, + 167, + 54, + 166, + 212, + 238, + 208, + 218, + 98, + 164, + 230, + 111, + 89, + 70, + 115, + 109, + 209, + 226, + 193, + 37, + 39, + 66, + 177, + 173, + 166, + 39, + 59, + 113, + 170, + 27, + 175, + 139, + 63, + 28, + 173, + 144, + 231, + 74, + 113, + 165, + 2, + 38, + 65, + 78, + 38, + 100, + 193, + 205, + 54, + 44, + 66, + 155, + 182, + 200, + 85, + 46, + 245, + 143, + 232, + 8, + 209, + 255, + 57, + 8, + 103, + 16, + 128, + 158, + 111, + 28, + 253, + 172, + 231, + 22, + 250, + 23, + 210, + 154, + 28, + 141, + 186, + 194, + 56, + 75, + 60, + 100, + 191, + 9, + 89, + 34, + 149, + 167, + 208, + 23, + 19, + 17, + 76, + 60, + 48, + 180, + 82, + 221, + 12, + 183, + 36, + 240, + 74, + 96, + 21, + 214, + 144, + 153, + 175, + 31, + 96, + 41, + 233, + 161, + 117, + 111, + 59, + 43, + 143, + 170, + 185, + 48, + 52, + 181, + 205, + 72, + 189, + 102, + 215, + 114, + 128, + 38, + 136, + 238, + 39, + 48, + 148, + 199, + 122, + 64, + 166, + 55, + 6, + 194, + 120, + 11, + 152, + 171, + 213, + 72, + 243, + 49, + 133, + 55, + 24, + 157, + 157, + 28, + 86, + 105, + 94, + 61, + 217, + 143, + 55, + 144, + 237, + 4, + 247, + 52, + 88, + 7, + 139, + 15, + 122, + 50, + 234, + 219, + 10, + 134, + 43, + 22, + 168, + 114, + 168, + 48, + 93, + 180, + 72, + 255, + 205, + 82, + 223, + 92, + 37, + 64, + 150, + 175, + 134, + 10, + 201, + 120, + 121, + 11, + 141, + 108, + 44, + 125, + 132, + 174, + 17, + 11, + 160, + 58, + 186, + 108, + 244, + 19, + 169, + 64, + 234, + 111, + 156, + 38, + 43, + 23, + 126, + 225, + 248, + 38, + 6, + 53, + 205, + 189, + 136, + 155, + 176, + 3, + 56, + 167, + 185, + 115, + 222, + 26, + 254, + 94, + 110, + 68, + 223, + 173, + 220, + 200, + 193, + 99, + 242, + 109, + 70, + 160, + 80, + 68, + 169, + 18, + 251, + 44, + 129, + 244, + 12, + 28, + 25, + 160, + 114, + 84, + 92, + 198, + 248, + 225, + 33, + 166, + 56, + 28, + 223, + 145, + 214, + 227, + 227, + 46, + 158, + 140, + 143, + 146, + 65, + 128, + 54, + 213, + 118, + 39, + 182, + 161, + 62, + 6, + 81, + 224, + 204, + 214, + 100, + 149, + 23, + 149, + 226, + 228, + 230, + 138, + 199, + 122, + 202, + 7, + 39, + 108, + 243, + 245, + 7, + 134, + 75, + 131, + 247, + 240, + 89, + 103, + 21, + 48, + 176, + 209, + 54, + 44, + 139, + 4, + 165, + 177, + 38, + 243, + 42, + 19, + 235, + 181, + 200, + 211, + 116, + 154, + 210, + 56, + 171, + 61, + 138, + 167, + 250, + 80, + 68, + 229, + 110, + 2, + 227, + 60, + 161, + 19, + 192, + 109, + 212, + 24, + 65, + 211, + 174, + 245, + 168, + 123, + 28, + 135, + 0, + 43, + 223, + 106, + 246, + 102, + 22, + 189, + 8, + 73, + 244, + 105, + 181, + 204, + 248, + 86, + 117, + 95, + 244, + 2, + 218, + 166, + 205, + 68, + 23, + 0, + 12, + 226, + 236, + 65, + 97, + 3, + 0, + 93, + 61, + 254, + 121, + 154, + 209, + 38, + 77, + 133, + 0, + 167, + 56, + 41, + 31, + 43, + 13, + 194, + 151, + 134, + 163, + 181, + 153, + 224, + 54, + 142, + 27, + 26, + 206, + 244, + 255, + 100, + 140, + 227, + 211, + 135, + 154, + 135, + 138, + 201, + 66, + 143, + 213, + 173, + 104, + 78, + 70, + 0, + 226, + 118, + 247, + 151, + 218, + 106, + 142, + 107, + 211, + 133, + 108, + 174, + 82, + 88, + 149, + 238, + 96, + 144, + 15, + 199, + 221, + 110, + 13, + 5, + 169, + 178, + 136, + 97, + 157, + 115, + 167, + 54, + 213, + 241, + 76, + 97, + 225, + 195, + 234, + 38, + 250, + 208, + 224, + 130, + 214, + 140, + 181, + 212, + 159, + 53, + 114, + 87, + 12, + 199, + 29, + 161, + 216, + 99, + 121, + 171, + 234, + 23, + 176, + 15, + 100, + 242, + 69, + 1, + 139, + 70, + 60, + 255, + 48, + 231, + 44, + 33, + 88, + 92, + 36, + 147, + 145, + 104, + 232, + 95, + 24, + 61, + 254, + 185, + 165, + 192, + 150, + 235, + 236, + 251, + 175, + 83, + 29, + 21, + 5, + 28, + 84, + 101, + 103, + 28, + 119, + 84, + 86, + 238, + 201, + 55, + 188, + 194, + 95, + 17, + 40, + 35, + 251, + 140, + 169, + 145, + 157, + 142, + 219, + 81, + 128, + 49, + 216, + 63, + 93, + 2, + 245, + 118, + 218, + 102, + 90, + 29, + 167, + 37, + 173, + 213, + 84, + 18, + 215, + 255, + 207, + 214, + 101, + 164, + 40, + 2, + 193, + 251, + 141, + 208, + 175, + 34, + 222, + 14, + 245, + 29, + 113, + 116, + 49, + 66, + 79, + 206, + 182, + 89, + 132, + 185, + 18, + 132, + 181, + 146, + 147, + 46, + 222, + 89, + 163, + 245, + 70, + 38, + 131, + 219, + 211, + 14, + 113, + 74, + 35, + 8, + 45, + 94, + 7, + 36, + 177, + 205, + 226, + 125, + 3, + 151, + 146, + 179, + 235, + 241, + 116, + 12, + 22, + 13, + 67, + 241, + 174, + 113, + 231, + 154, + 90, + 39, + 152, + 39, + 10, + 201, + 143, + 94, + 7, + 40, + 14, + 234, + 207, + 3, + 125, + 216, + 0, + 170, + 8, + 1, + 189, + 111, + 197, + 108, + 140, + 154, + 43, + 135, + 33, + 115, + 38, + 57, + 167, + 220, + 166, + 157, + 111, + 93, + 148, + 51, + 8, + 22, + 57, + 125, + 124, + 251, + 94, + 159, + 9, + 52, + 235, + 20, + 52, + 212, + 117, + 149, + 173, + 47, + 82, + 89, + 116, + 43, + 201, + 254, + 18, + 126, + 1, + 251, + 200, + 249, + 93, + 38, + 72, + 99, + 76, + 192, + 153, + 80, + 96, + 95, + 156, + 5, + 2, + 209, + 72, + 31, + 53, + 44, + 6, + 150, + 208, + 224, + 250, + 34, + 110, + 231, + 142, + 5, + 204, + 94, + 211, + 145, + 53, + 99, + 46, + 31, + 145, + 11, + 52, + 199, + 51, + 158, + 149, + 190, + 172, + 240, + 67, + 167, + 194, + 79, + 155, + 138, + 105, + 30, + 135, + 162, + 48, + 121, + 50, + 80, + 30, + 239, + 46, + 176, + 4, + 12, + 185, + 34, + 192, + 127, + 222, + 66, + 230, + 152, + 152, + 22, + 207, + 94, + 124, + 36, + 74, + 249, + 34, + 27, + 52, + 26, + 16, + 119, + 170, + 173, + 154, + 148, + 131, + 207, + 167, + 249, + 38, + 219, + 52, + 57, + 119, + 87, + 81, + 40, + 14, + 246, + 186, + 48, + 41, + 149, + 179, + 124, + 231, + 176, + 98, + 38, + 233, + 163, + 149, + 11, + 78, + 49, + 156, + 61, + 182, + 183, + 144, + 54, + 195, + 103, + 118, + 91, + 80, + 67, + 16, + 247, + 100, + 152, + 180, + 168, + 243, + 137, + 150, + 104, + 176, + 185, + 161, + 112, + 137, + 142, + 120, + 16, + 236, + 62, + 99, + 150, + 129, + 195, + 212, + 84, + 241, + 216, + 116, + 58, + 104, + 170, + 175, + 26, + 170, + 163, + 198, + 93, + 55, + 0, + 156, + 206, + 92, + 235, + 17, + 141, + 12, + 167, + 23, + 49, + 203, + 105, + 112, + 189, + 4, + 191, + 77, + 172, + 187, + 183, + 228, + 106, + 19, + 228, + 247, + 17, + 137, + 254, + 169, + 94, + 241, + 59, + 202, + 254, + 200, + 157, + 154, + 254, + 17, + 208, + 217, + 131, + 165, + 161, + 122, + 221, + 197, + 159, + 89, + 215, + 246, + 108, + 55, + 20, + 51, + 6, + 148, + 202, + 232, + 23, + 160, + 248, + 47, + 110, + 15, + 78, + 9, + 191, + 5, + 138, + 85, + 55, + 91, + 5, + 59, + 70, + 206, + 125, + 193, + 209, + 165, + 174, + 115, + 84, + 46, + 41, + 198, + 85, + 32, + 111, + 61, + 243, + 73, + 160, + 60, + 158, + 248, + 95, + 137, + 57, + 20, + 52, + 5, + 111, + 1, + 212, + 113, + 41, + 167, + 39, + 149, + 1, + 218, + 70, + 13, + 104, + 224, + 39, + 22, + 148, + 189, + 236, + 70, + 104, + 234, + 84, + 245, + 40, + 89, + 209, + 38, + 26, + 153, + 173, + 96, + 236, + 63, + 78, + 79, + 147, + 98, + 156, + 241, + 10, + 230, + 107, + 230, + 255, + 49, + 108, + 91, + 45, + 142, + 56, + 148, + 206, + 61, + 109, + 240, + 58, + 191, + 167, + 168, + 10, + 239, + 170, + 62, + 220, + 201, + 50, + 11, + 164, + 11, + 109, + 116, + 45, + 61, + 88, + 118, + 141, + 7, + 78, + 190, + 225, + 234, + 216, + 96, + 74, + 198, + 63, + 249, + 186, + 194, + 119, + 165, + 83, + 57, + 22, + 96, + 95, + 35, + 159, + 149, + 100, + 130, + 240, + 87, + 191, + 162, + 127, + 4, + 99, + 96, + 57, + 246, + 206, + 198, + 35, + 44, + 89, + 122, + 97, + 162, + 53, + 17, + 226, + 164, + 181, + 108, + 101, + 78, + 51, + 44, + 183, + 53, + 93, + 10, + 216, + 166, + 153, + 245, + 77, + 175, + 147, + 153, + 56, + 203, + 165, + 47, + 4, + 217, + 193, + 91, + 243, + 71, + 121, + 212, + 85, + 182, + 165, + 145, + 162, + 41, + 205, + 151, + 95, + 182, + 137, + 25, + 192, + 12, + 117, + 231, + 226, + 220, + 53, + 128, + 115, + 79, + 38, + 209, + 220, + 246, + 224, + 51, + 5, + 249, + 211, + 155, + 118, + 236, + 228, + 243, + 85, + 178, + 145, + 217, + 44, + 122, + 152, + 178, + 90, + 49, + 216, + 171, + 19, + 181, + 168, + 152, + 33, + 238, + 52, + 107, + 37, + 197, + 34, + 4, + 54, + 8, + 184, + 93, + 166, + 180, + 95, + 120, + 41, + 179, + 157, + 145, + 78, + 20, + 195, + 159, + 100, + 30, + 234, + 243, + 166, + 40, + 99, + 227, + 23, + 224, + 35, + 163, + 58, + 83, + 10, + 71, + 105, + 210, + 104, + 39, + 135, + 83, + 220, + 109, + 254, + 238, + 128, + 177, + 168, + 20, + 245, + 221, + 160, + 111, + 68, + 176, + 112, + 215, + 75, + 181, + 19, + 106, + 58, + 210, + 12, + 106, + 82, + 23, + 184, + 152, + 86, + 71, + 137, + 7, + 232, + 153, + 180, + 94, + 182, + 20, + 96, + 166, + 119, + 89, + 202, + 48, + 181, + 162, + 160, + 41, + 23, + 143, + 69, + 177, + 53, + 65, + 47, + 212, + 36, + 17, + 45, + 40, + 240, + 43, + 224, + 46, + 225, + 149, + 35, + 63, + 193, + 242, + 138, + 76, + 35, + 12, + 249, + 19, + 51, + 55, + 199, + 35, + 14, + 164, + 89, + 78, + 132, + 12, + 212, + 146, + 19, + 255, + 10, + 170, + 232, + 74, + 148, + 53, + 16, + 248, + 54, + 92, + 225, + 238, + 72, + 174, + 219, + 91, + 20, + 80, + 146, + 100, + 52, + 81, + 9, + 164, + 32, + 10, + 77, + 30, + 39, + 203, + 32, + 218, + 130, + 65, + 130, + 81, + 201, + 34, + 44, + 38, + 200, + 12, + 246, + 146, + 208, + 11, + 45, + 37, + 26, + 54, + 255, + 180, + 104, + 120, + 103, + 245, + 24, + 237, + 21, + 99, + 76, + 34, + 13, + 109, + 19, + 114, + 245, + 9, + 66, + 197, + 221, + 124, + 223, + 24, + 253, + 137, + 1, + 33, + 244, + 62, + 176, + 136, + 243, + 43, + 151, + 76, + 183, + 60, + 87, + 136, + 38, + 238, + 152, + 1, + 202, + 120, + 75, + 199, + 253, + 110, + 129, + 63, + 86, + 36, + 71, + 187, + 64, + 76, + 130, + 22, + 103, + 181, + 166, + 114, + 3, + 9, + 179, + 53, + 85, + 197, + 28, + 112, + 18, + 223, + 206, + 158, + 23, + 203, + 149, + 26, + 238, + 56, + 4, + 122, + 103, + 91, + 3, + 60, + 197, + 83, + 134, + 244, + 200, + 46, + 29, + 207, + 11, + 5, + 131, + 211, + 124, + 226, + 101, + 84, + 201, + 82, + 115, + 9, + 123, + 75, + 117, + 4, + 14, + 77, + 17, + 128, + 253, + 218, + 210, + 140, + 132, + 72, + 196, + 80, + 41, + 249, + 106, + 65, + 130, + 194, + 142, + 226, + 249, + 158, + 62, + 44, + 165, + 73, + 22, + 165, + 235, + 11, + 109, + 43, + 129, + 34, + 225, + 215, + 174, + 58, + 46, + 30, + 22, + 180, + 98, + 50, + 229, + 24, + 121, + 222, + 187, + 112, + 3, + 25, + 55, + 166, + 109, + 141, + 114, + 183, + 71, + 1, + 240, + 40, + 148, + 178, + 85, + 217, + 155, + 89, + 132, + 179, + 87, + 127, + 121, + 48, + 123, + 18, + 242, + 114, + 195, + 147, + 41, + 22, + 79, + 114, + 181, + 220, + 104, + 233, + 73, + 235, + 1, + 80, + 103, + 201, + 248, + 167, + 42, + 229, + 96, + 123, + 89, + 235, + 68, + 2, + 246, + 109, + 245, + 54, + 193, + 248, + 163, + 249, + 9, + 27, + 220, + 167, + 230, + 213, + 62, + 207, + 184, + 28, + 176, + 110, + 115, + 53, + 153, + 251, + 24, + 88, + 141, + 51, + 85, + 185, + 169, + 74, + 215, + 64, + 131, + 41, + 21, + 30, + 23, + 128, + 0, + 162, + 235, + 225, + 137, + 26, + 40, + 72, + 236, + 131, + 161, + 139, + 56, + 122, + 25, + 183, + 251, + 98, + 239, + 15, + 219, + 252, + 158, + 217, + 127, + 127, + 228, + 89, + 0, + 73, + 79, + 134, + 202, + 215, + 60, + 83, + 88, + 211, + 99, + 171, + 57, + 54, + 122, + 167, + 183, + 207, + 147, + 75, + 247, + 7, + 211, + 51, + 47, + 236, + 255, + 200, + 85, + 117, + 207, + 52, + 28, + 69, + 208, + 107, + 149, + 202, + 231, + 158, + 248, + 15, + 81, + 70, + 84, + 147, + 18, + 199, + 24, + 23, + 221, + 218, + 120, + 231, + 210, + 48, + 198, + 87, + 220, + 122, + 94, + 85, + 127, + 21, + 160, + 103, + 169, + 116, + 249, + 45, + 126, + 54, + 128, + 17, + 73, + 8, + 11, + 31, + 40, + 174, + 6, + 158, + 147, + 217, + 148, + 68, + 58, + 137, + 25, + 54, + 191, + 183, + 69, + 13, + 22, + 54, + 97, + 131, + 94, + 96, + 232, + 210, + 63, + 84, + 224, + 125, + 47, + 239, + 242, + 50, + 180, + 255, + 240, + 15, + 122, + 236, + 57, + 104, + 13, + 88, + 189, + 28, + 55, + 172, + 11, + 227, + 205, + 248, + 249, + 91, + 200, + 150, + 103, + 107, + 23, + 77, + 237, + 64, + 44, + 210, + 246, + 45, + 64, + 220, + 54, + 76, + 30, + 60, + 141, + 163, + 164, + 131, + 108, + 151, + 221, + 51, + 94, + 102, + 195, + 205, + 137, + 121, + 174, + 174, + 50, + 144, + 239, + 243, + 113, + 181, + 34, + 86, + 217, + 215, + 250, + 233, + 204, + 22, + 81, + 246, + 161, + 161, + 211, + 207, + 246, + 243, + 109, + 48, + 170, + 47, + 13, + 2, + 227, + 123, + 28, + 151, + 126, + 77, + 27, + 22, + 125, + 153, + 10, + 64, + 155, + 14, + 208, + 79, + 187, + 145, + 94, + 175, + 229, + 68, + 241, + 115, + 141, + 42, + 57, + 255, + 78, + 77, + 71, + 254, + 29, + 128, + 182, + 152, + 147, + 167, + 45, + 124, + 117, + 255, + 20, + 42, + 242, + 149, + 59, + 90, + 64, + 43, + 27, + 133, + 158, + 210, + 239, + 126, + 70, + 245, + 69, + 252, + 173, + 87, + 42, + 87, + 130, + 226, + 194, + 118, + 254, + 70, + 0, + 208, + 25, + 71, + 82, + 226, + 193, + 192, + 182, + 130, + 252, + 164, + 66, + 204, + 81, + 57, + 182, + 204, + 83, + 98, + 192, + 181, + 88, + 177, + 41, + 232, + 35, + 145, + 208, + 63, + 181, + 107, + 158, + 240, + 27, + 62, + 14, + 44, + 38, + 8, + 239, + 163, + 218, + 79, + 150, + 59, + 103, + 27, + 116, + 157, + 69, + 123, + 140, + 220, + 85, + 53, + 186, + 76, + 147, + 40, + 246, + 180, + 25, + 238, + 175, + 198, + 52, + 166, + 6, + 94, + 167, + 90, + 57, + 213, + 21, + 138, + 143, + 208, + 165, + 48, + 88, + 103, + 71, + 132, + 136, + 39, + 97, + 29, + 27, + 152, + 113, + 145, + 140, + 71, + 8, + 22, + 166, + 34, + 119, + 55, + 66, + 162, + 77, + 239, + 46, + 239, + 235, + 176, + 111, + 158, + 234, + 226, + 21, + 37, + 237, + 194, + 1, + 122, + 23, + 15, + 123, + 222, + 34, + 78, + 228, + 220, + 124, + 101, + 155, + 246, + 28, + 107, + 51, + 90, + 42, + 18, + 49, + 161, + 133, + 245, + 116, + 112, + 130, + 163, + 195, + 181, + 201, + 46, + 203, + 96, + 48, + 247, + 32, + 69, + 85, + 20, + 147, + 74, + 112, + 64, + 95, + 144, + 20, + 141, + 98, + 218, + 6, + 136, + 101, + 154, + 136, + 140, + 124, + 202, + 79, + 79, + 89, + 36, + 94, + 64, + 166, + 171, + 124, + 79, + 188, + 119, + 72, + 192, + 151, + 58, + 172, + 103, + 5, + 162, + 140, + 190, + 113, + 75, + 144, + 21, + 206, + 231, + 45, + 158, + 158, + 145, + 147, + 249, + 134, + 121, + 244, + 196, + 26, + 95, + 202, + 147, + 99, + 75, + 155, + 25, + 53, + 128, + 166, + 254, + 197, + 47, + 16, + 210, + 87, + 57, + 212, + 157, + 82, + 213, + 242, + 121, + 99, + 97, + 213, + 18, + 118, + 231, + 36, + 186, + 45, + 219, + 54, + 144, + 181, + 106, + 122, + 42, + 253, + 155, + 20, + 4, + 189, + 191, + 173, + 132, + 67, + 248, + 118, + 220, + 210, + 119, + 238, + 229, + 137, + 170, + 81, + 183, + 235, + 89, + 110, + 47, + 221, + 6, + 214, + 23, + 25, + 59, + 50, + 39, + 192, + 248, + 3, + 25, + 138, + 76, + 32, + 178, + 18, + 186, + 13, + 65, + 144, + 81, + 79, + 81, + 40, + 134, + 124, + 245, + 252, + 8, + 99, + 11, + 85, + 34, + 76, + 94, + 230, + 250, + 205, + 233, + 241, + 0, + 69, + 182, + 157, + 110, + 82, + 15, + 97, + 187, + 137, + 185, + 46, + 184, + 0, + 155, + 80, + 33, + 99, + 232, + 51, + 234, + 178, + 106, + 128, + 251, + 101, + 166, + 149, + 148, + 2, + 191, + 206, + 27, + 86, + 83, + 174, + 101, + 205, + 47, + 14, + 72, + 100, + 252, + 215, + 199, + 14, + 117, + 154, + 187, + 185, + 9, + 255, + 41, + 101, + 190, + 97, + 80, + 46, + 172, + 255, + 87, + 163, + 8, + 8, + 81, + 86, + 228, + 212, + 119, + 172, + 199, + 100, + 245, + 247, + 209, + 72, + 86, + 33, + 128, + 228, + 156, + 181, + 245, + 189, + 14, + 143, + 92, + 83, + 90, + 37, + 209, + 38, + 157, + 173, + 217, + 98, + 163, + 130, + 117, + 125, + 196, + 117, + 226, + 41, + 60, + 249, + 157, + 77, + 3, + 216, + 71, + 197, + 138, + 125, + 72, + 193, + 96, + 162, + 186, + 236, + 218, + 186, + 38, + 84, + 134, + 29, + 58, + 22, + 74, + 107, + 112, + 20, + 194, + 216, + 233, + 52, + 44, + 235, + 211, + 163, + 85, + 30, + 179, + 175, + 4, + 150, + 175, + 74, + 7, + 100, + 249, + 240, + 142, + 240, + 65, + 188, + 179, + 108, + 18, + 233, + 10, + 168, + 100, + 246, + 237, + 202, + 73, + 49, + 146, + 171, + 64, + 48, + 205, + 172, + 184, + 85, + 127, + 167, + 166, + 132, + 54, + 92, + 148, + 123, + 67, + 98, + 169, + 206, + 123, + 47, + 138, + 231, + 107, + 231, + 124, + 67, + 70, + 16, + 182, + 74, + 198, + 104, + 182, + 20, + 236, + 67, + 231, + 86, + 130, + 107, + 28, + 70, + 131, + 118, + 137, + 236, + 140, + 87, + 103, + 123, + 219, + 242, + 194, + 96, + 105, + 248, + 38, + 244, + 80, + 133, + 66, + 21, + 221, + 204, + 255, + 167, + 201, + 122, + 148, + 137, + 124, + 35, + 74, + 63, + 50, + 77, + 184, + 94, + 176, + 221, + 36, + 176, + 68, + 149, + 66, + 196, + 23, + 81, + 70, + 66, + 174, + 157, + 150, + 75, + 195, + 99, + 90, + 153, + 211, + 236, + 43, + 176, + 50, + 239, + 91, + 231, + 158, + 208, + 176, + 169, + 129, + 159, + 206, + 45, + 253, + 168, + 127, + 222, + 246, + 254, + 48, + 145, + 178, + 119, + 113, + 102, + 177, + 131, + 12, + 130, + 109, + 211, + 193, + 238, + 150, + 129, + 100, + 114, + 254, + 234, + 6, + 217, + 152, + 120, + 161, + 248, + 42, + 122, + 152, + 246, + 182, + 254, + 89, + 48, + 162, + 105, + 199, + 93, + 17, + 4, + 229, + 57, + 109, + 57, + 16, + 91, + 71, + 0, + 219, + 239, + 255, + 195, + 205, + 138, + 21, + 38, + 81, + 10, + 30, + 59, + 99, + 80, + 10, + 36, + 4, + 50, + 204, + 153, + 114, + 65, + 113, + 223, + 64, + 99, + 169, + 233, + 48, + 84, + 209, + 235, + 57, + 246, + 141, + 97, + 11, + 194, + 232, + 99, + 138, + 65, + 152, + 153, + 170, + 180, + 194, + 233, + 198, + 216, + 211, + 177, + 128, + 7, + 59, + 21, + 175, + 49, + 239, + 85, + 102, + 129, + 155, + 32, + 232, + 51, + 250, + 197, + 233, + 119, + 40, + 24, + 51, + 37, + 4, + 219, + 174, + 111, + 5, + 130, + 216, + 88, + 141, + 195, + 44, + 89, + 195, + 224, + 225, + 165, + 1, + 129, + 208, + 6, + 48, + 96, + 18, + 55, + 49, + 93, + 82, + 173, + 154, + 48, + 204, + 76, + 99, + 91, + 139, + 129, + 157, + 16, + 7, + 149, + 94, + 26, + 99, + 103, + 122, + 204, + 31, + 127, + 79, + 7, + 8, + 213, + 113, + 16, + 205, + 139, + 115, + 205, + 199, + 134, + 27, + 54, + 150, + 232, + 147, + 238, + 161, + 204, + 174, + 207, + 146, + 81, + 222, + 161, + 45, + 21, + 228, + 9, + 92, + 77, + 113, + 219, + 247, + 205, + 3, + 179, + 217, + 224, + 236, + 64, + 252, + 97, + 114, + 124, + 7, + 180, + 43, + 133, + 191, + 60, + 251, + 111, + 44, + 157, + 133, + 173, + 106, + 50, + 255, + 95, + 202, + 68, + 46, + 128, + 88, + 143, + 161, + 222, + 177, + 216, + 233, + 19, + 217, + 227, + 86, + 117, + 214, + 0, + 123, + 213, + 147, + 70, + 40, + 74, + 204, + 70, + 221, + 68, + 238, + 89, + 135, + 2, + 42, + 148, + 105, + 159, + 26, + 173, + 206, + 11, + 198, + 140, + 106, + 158, + 7, + 0, + 60, + 65, + 171, + 187, + 130, + 210, + 197, + 188, + 158, + 181, + 91, + 146, + 28, + 232, + 252, + 30, + 141, + 96, + 61, + 213, + 239, + 102, + 118, + 221, + 184, + 73, + 76, + 172, + 181, + 235, + 226, + 51, + 223, + 92, + 215, + 241, + 55, + 82, + 162, + 108, + 69, + 34, + 14, + 180, + 110, + 53, + 80, + 79, + 191, + 88, + 147, + 81, + 12, + 23, + 29, + 100, + 67, + 112, + 198, + 44, + 2, + 65, + 7, + 29, + 9, + 160, + 102, + 219, + 162, + 200, + 49, + 79, + 221, + 68, + 166, + 67, + 32, + 233, + 231, + 49, + 84, + 84, + 214, + 155, + 83, + 96, + 255, + 190, + 5, + 244, + 90, + 47, + 86, + 251, + 53, + 206, + 105, + 68, + 11, + 37, + 96, + 39, + 56, + 71, + 75, + 157, + 37, + 225, + 248, + 100, + 35, + 82, + 2, + 2, + 70, + 136, + 122, + 69, + 255, + 203, + 41, + 101, + 236, + 217, + 142, + 229, + 89, + 84, + 190, + 87, + 247, + 72, + 8, + 104, + 237, + 156, + 220, + 61, + 230, + 31, + 218, + 30, + 196, + 59, + 51, + 175, + 9, + 113, + 196, + 123, + 211, + 130, + 245, + 112, + 122, + 119, + 144, + 191, + 144, + 164, + 203, + 148, + 235, + 17, + 0, + 114, + 69, + 237, + 19, + 15, + 57, + 136, + 49, + 104, + 31, + 105, + 45, + 249, + 143, + 178, + 170, + 113, + 175, + 179, + 17, + 90, + 175, + 104, + 95, + 110, + 17, + 246, + 181, + 26, + 35, + 187, + 82, + 148, + 130, + 57, + 98, + 219, + 123, + 206, + 204, + 43, + 99, + 27, + 135, + 12, + 43, + 132, + 139, + 208, + 220, + 215, + 70, + 107, + 1, + 169, + 249, + 18, + 224, + 145, + 217, + 212, + 63, + 84, + 144, + 76, + 97, + 130, + 213, + 219, + 151, + 28, + 192, + 170, + 84, + 91, + 16, + 232, + 58, + 190, + 143, + 239, + 53, + 119, + 45, + 75, + 70, + 209, + 157, + 102, + 44, + 19, + 71, + 172, + 235, + 193, + 48, + 88, + 88, + 192, + 230, + 136, + 117, + 246, + 84, + 54, + 64, + 61, + 42, + 78, + 163, + 160, + 175, + 131, + 4, + 181, + 35, + 185, + 21, + 10, + 26, + 240, + 111, + 102, + 166, + 105, + 151, + 22, + 89, + 3, + 152, + 16, + 247, + 97, + 24, + 115, + 184, + 29, + 197, + 45, + 27, + 110, + 202, + 211, + 213, + 30, + 59, + 156, + 254, + 154, + 192, + 204, + 94, + 55, + 10, + 3, + 245, + 28, + 19, + 228, + 66, + 38, + 214, + 64, + 135, + 79, + 34, + 198, + 131, + 255, + 72, + 84, + 121, + 75, + 35, + 85, + 173, + 63, + 69, + 34, + 121, + 195, + 31, + 155, + 158, + 140, + 31, + 189, + 17, + 227, + 37, + 80, + 176, + 34, + 55, + 182, + 216, + 147, + 254, + 71, + 132, + 57, + 62, + 46, + 23, + 208, + 134, + 217, + 172, + 17, + 168, + 36, + 130, + 159, + 126, + 7, + 70, + 45, + 204, + 8, + 146, + 239, + 56, + 66, + 59, + 126, + 249, + 189, + 179, + 105, + 91, + 222, + 220, + 10, + 187, + 91, + 64, + 227, + 231, + 191, + 222, + 26, + 223, + 30, + 241, + 132, + 77, + 143, + 158, + 194, + 49, + 145, + 251, + 161, + 140, + 82, + 246, + 186, + 114, + 71, + 30, + 129, + 41, + 200, + 77, + 8, + 80, + 71, + 193, + 245, + 244, + 164, + 24, + 187, + 229, + 133, + 249, + 150, + 189, + 243, + 94, + 53, + 235, + 58, + 162, + 242, + 71, + 28, + 143, + 178, + 24, + 250, + 92, + 191, + 176, + 242, + 232, + 103, + 190, + 12, + 35, + 226, + 155, + 57, + 199, + 55, + 174, + 7, + 29, + 45, + 148, + 102, + 222, + 141, + 101, + 73, + 167, + 57, + 170, + 73, + 161, + 93, + 109, + 102, + 150, + 110, + 111, + 66, + 171, + 252, + 212, + 8, + 181, + 121, + 199, + 26, + 183, + 60, + 28, + 192, + 7, + 97, + 106, + 54, + 200, + 86, + 56, + 89, + 50, + 224, + 98, + 144, + 50, + 233, + 245, + 42, + 220, + 203, + 114, + 143, + 251, + 167, + 195, + 34, + 6, + 212, + 119, + 64, + 145, + 200, + 69, + 161, + 204, + 5, + 123, + 204, + 66, + 84, + 100, + 136, + 109, + 213, + 59, + 74, + 205, + 243, + 65, + 117, + 51, + 226, + 98, + 45, + 74, + 149, + 131, + 84, + 203, + 158, + 61, + 180, + 67, + 132, + 23, + 32, + 140, + 109, + 101, + 29, + 123, + 140, + 115, + 71, + 77, + 155, + 74, + 200, + 139, + 145, + 200, + 24, + 158, + 159, + 37, + 9, + 129, + 236, + 193, + 27, + 196, + 106, + 159, + 196, + 255, + 32, + 59, + 115, + 199, + 65, + 127, + 138, + 145, + 102, + 51, + 120, + 13, + 167, + 108, + 131, + 235, + 110, + 56, + 5, + 103, + 161, + 76, + 169, + 131, + 89, + 195, + 3, + 3, + 110, + 102, + 46, + 52, + 67, + 194, + 245, + 82, + 192, + 102, + 92, + 200, + 50, + 247, + 121, + 130, + 158, + 110, + 10, + 148, + 252, + 244, + 167, + 54, + 121, + 28, + 2, + 229, + 54, + 232, + 30, + 122, + 166, + 147, + 221, + 123, + 63, + 113, + 13, + 86, + 31, + 165, + 174, + 154, + 18, + 44, + 213, + 199, + 30, + 38, + 135, + 237, + 139, + 185, + 221, + 91, + 8, + 32, + 102, + 127, + 54, + 241, + 73, + 150, + 212, + 43, + 42, + 209, + 196, + 31, + 77, + 152, + 171, + 235, + 210, + 201, + 249, + 56, + 135, + 101, + 18, + 214, + 168, + 238, + 117, + 44, + 192, + 208, + 220, + 222, + 102, + 40, + 149, + 90, + 92, + 180, + 136, + 1, + 198, + 154, + 164, + 139, + 55, + 56, + 72, + 174, + 162, + 252, + 11, + 197, + 183, + 220, + 84, + 68, + 199, + 175, + 179, + 232, + 203, + 99, + 51, + 81, + 99, + 242, + 84, + 97, + 105, + 52, + 73, + 196, + 40, + 196, + 131, + 75, + 129, + 224, + 49, + 27, + 23, + 53, + 202, + 222, + 198, + 159, + 206, + 163, + 187, + 10, + 225, + 57, + 242, + 250, + 95, + 32, + 104, + 176, + 122, + 234, + 105, + 108, + 12, + 166, + 30, + 148, + 154, + 1, + 247, + 239, + 123, + 138, + 208, + 138, + 6, + 165, + 81, + 55, + 213, + 250, + 207, + 10, + 56, + 231, + 178, + 215, + 18, + 10, + 61, + 199, + 219, + 8, + 73, + 239, + 188, + 106, + 66, + 235, + 185, + 58, + 123, + 201, + 154, + 36, + 216, + 191, + 47, + 230, + 0, + 191, + 168, + 68, + 117, + 252, + 156, + 228, + 100, + 102, + 194, + 253, + 50, + 129, + 231, + 137, + 14, + 235, + 189, + 193, + 83, + 238, + 158, + 20, + 153, + 3, + 75, + 174, + 51, + 38, + 68, + 184, + 233, + 61, + 151, + 249, + 4, + 235, + 97, + 224, + 100, + 168, + 35, + 249, + 243, + 133, + 186, + 150, + 9, + 110, + 222, + 87, + 153, + 60, + 39, + 112, + 173, + 44, + 198, + 94, + 216, + 62, + 244, + 246, + 1, + 15, + 225, + 156, + 120, + 115, + 56, + 9, + 223, + 236, + 141, + 137, + 76, + 153, + 250, + 17, + 40, + 232, + 243, + 238, + 212, + 33, + 77, + 178, + 239, + 190, + 105, + 130, + 74, + 190, + 174, + 216, + 73, + 44, + 177, + 121, + 220, + 74, + 221, + 10, + 51, + 163, + 101, + 55, + 74, + 23, + 75, + 113, + 18, + 128, + 18, + 75, + 86, + 193, + 77, + 43, + 191, + 96, + 196, + 43, + 82, + 201, + 66, + 182, + 51, + 76, + 17, + 200, + 243, + 210, + 27, + 92, + 95, + 52, + 247, + 199, + 27, + 101, + 239, + 133, + 98, + 176, + 207, + 157, + 91, + 59, + 148, + 242, + 135, + 187, + 222, + 63, + 136, + 81, + 187, + 183, + 138, + 130, + 144, + 2, + 38, + 240, + 58, + 163, + 153, + 96, + 93, + 123, + 229, + 31, + 194, + 127, + 57, + 226, + 53, + 177, + 21, + 100, + 169, + 252, + 196, + 116, + 238, + 155, + 22, + 57, + 17, + 104, + 49, + 97, + 23, + 100, + 243, + 210, + 122, + 189, + 208, + 185, + 171, + 218, + 250, + 143, + 13, + 83, + 37, + 255, + 107, + 8, + 108, + 87, + 25, + 236, + 243, + 237, + 64, + 31, + 44, + 31, + 190, + 130, + 213, + 160, + 238, + 27, + 96, + 237, + 8, + 1, + 96, + 251, + 77, + 239, + 114, + 59, + 45, + 4, + 88, + 123, + 243, + 77, + 143, + 77, + 227, + 43, + 172, + 204, + 252, + 32, + 29, + 20, + 160, + 24, + 160, + 78, + 191, + 169, + 4, + 84, + 80, + 117, + 245, + 183, + 64, + 20, + 242, + 95, + 91, + 122, + 82, + 42, + 218, + 92, + 118, + 43, + 253, + 212, + 168, + 214, + 114, + 107, + 225, + 103, + 4, + 177, + 171, + 30, + 133, + 155, + 13, + 169, + 56, + 186, + 8, + 45, + 162, + 111, + 159, + 185, + 80, + 110, + 114, + 129, + 241, + 40, + 2, + 73, + 135, + 225, + 182, + 233, + 249, + 107, + 134, + 166, + 123, + 13, + 66, + 120, + 79, + 195, + 226, + 122, + 244, + 179, + 254, + 7, + 35, + 151, + 14, + 116, + 191, + 244, + 45, + 142, + 239, + 202, + 18, + 32, + 16, + 253, + 39, + 208, + 201, + 135, + 212, + 190, + 120, + 98, + 193, + 53, + 89, + 206, + 213, + 102, + 154, + 33, + 198, + 98, + 19, + 222, + 142, + 28, + 190, + 202, + 54, + 199, + 19, + 82, + 102, + 171, + 244, + 209, + 157, + 11, + 141, + 111, + 175, + 216, + 165, + 165, + 76, + 158, + 2, + 11, + 23, + 155, + 67, + 92, + 31, + 54, + 129, + 14, + 207, + 159, + 188, + 133, + 95, + 188, + 36, + 40, + 102, + 230, + 60, + 225, + 75, + 16, + 72, + 2, + 52, + 165, + 145, + 134, + 25, + 16, + 53, + 203, + 138, + 175, + 38, + 198, + 168, + 207, + 52, + 14, + 114, + 233, + 15, + 94, + 65, + 82, + 63, + 212, + 25, + 208, + 26, + 172, + 134, + 94, + 18, + 19, + 154, + 232, + 160, + 8, + 241, + 56, + 245, + 118, + 14, + 97, + 188, + 232, + 231, + 160, + 156, + 24, + 161, + 197, + 124, + 117, + 55, + 39, + 226, + 86, + 86, + 238, + 157, + 22, + 29, + 159, + 234, + 44, + 86, + 52, + 202, + 3, + 3, + 136, + 142, + 177, + 54, + 151, + 220, + 63, + 32, + 236, + 84, + 35, + 78, + 255, + 44, + 78, + 53, + 214, + 70, + 191, + 166, + 51, + 186, + 166, + 234, + 187, + 81, + 119, + 64, + 73, + 248, + 127, + 69, + 165, + 50, + 137, + 6, + 148, + 107, + 228, + 1, + 150, + 158, + 11, + 118, + 69, + 184, + 233, + 104, + 248, + 125, + 230, + 95, + 166, + 120, + 186, + 156, + 180, + 96, + 60, + 151, + 84, + 229, + 184, + 199, + 175, + 169, + 98, + 122, + 197, + 5, + 46, + 175, + 77, + 203, + 192, + 79, + 21, + 128, + 50, + 89, + 27, + 110, + 85, + 93, + 197, + 132, + 63, + 31, + 210, + 96, + 39, + 220, + 103, + 192, + 141, + 232, + 192, + 210, + 127, + 13, + 67, + 191, + 139, + 174, + 217, + 135, + 5, + 97, + 108, + 69, + 65, + 18, + 203, + 182, + 114, + 248, + 112, + 42, + 2, + 170, + 18, + 65, + 248, + 206, + 90, + 90, + 108, + 164, + 13, + 176, + 186, + 33, + 76, + 198, + 98, + 253, + 227, + 43, + 250, + 140, + 12, + 32, + 253, + 27, + 27, + 11, + 5, + 43, + 248, + 16, + 128, + 194, + 142, + 215, + 106, + 9, + 90, + 77, + 237, + 87, + 174, + 88, + 85, + 108, + 97, + 55, + 22, + 173, + 61, + 163, + 173, + 132, + 246, + 38, + 187, + 62, + 36, + 202, + 160, + 68, + 69, + 53, + 214, + 131, + 30, + 185, + 150, + 163, + 124, + 176, + 227, + 83, + 229, + 188, + 131, + 83, + 255, + 101, + 69, + 191, + 130, + 110, + 113, + 34, + 71, + 43, + 156, + 88, + 107, + 17, + 54, + 133, + 100, + 23, + 2, + 232, + 64, + 192, + 148, + 34, + 92, + 158, + 93, + 4, + 218, + 66, + 215, + 155, + 117, + 181, + 1, + 214, + 152, + 76, + 164, + 148, + 87, + 66, + 190, + 43, + 239, + 46, + 96, + 79, + 252, + 15, + 109, + 251, + 160, + 7, + 80, + 227, + 131, + 221, + 216, + 99, + 253, + 206, + 13, + 209, + 195, + 179, + 178, + 75, + 38, + 148, + 52, + 77, + 128, + 67, + 71, + 114, + 158, + 238, + 216, + 7, + 51, + 238, + 31, + 66, + 133, + 40, + 129, + 117, + 76, + 66, + 19, + 91, + 76, + 7, + 186, + 239, + 223, + 8, + 99, + 145, + 177, + 94, + 124, + 230, + 243, + 8, + 226, + 101, + 191, + 129, + 183, + 202, + 67, + 80, + 16, + 136, + 142, + 90, + 238, + 129, + 33, + 193, + 240, + 156, + 152, + 228, + 53, + 35, + 61, + 145, + 53, + 144, + 30, + 43, + 245, + 219, + 6, + 128, + 62, + 35, + 168, + 84, + 158, + 169, + 99, + 100, + 72, + 223, + 219, + 188, + 115, + 173, + 243, + 211, + 78, + 190, + 113, + 57, + 176, + 132, + 3, + 151, + 254, + 43, + 81, + 98, + 165, + 139, + 177, + 41, + 142, + 69, + 166, + 54, + 64, + 104, + 200, + 77, + 248, + 132, + 208, + 18, + 104, + 151, + 1, + 185, + 208, + 74, + 89, + 52, + 76, + 138, + 47, + 177, + 23, + 156, + 94, + 7, + 100, + 127, + 52, + 214, + 236, + 42, + 149, + 130, + 100, + 248, + 252, + 243, + 99, + 35, + 96, + 127, + 197, + 253, + 179, + 251, + 4, + 223, + 225, + 84, + 55, + 116, + 65, + 29, + 90, + 179, + 164, + 172, + 163, + 251, + 81, + 23, + 242, + 82, + 97, + 79, + 21, + 251, + 159, + 93, + 194, + 232, + 181, + 233, + 135, + 46, + 93, + 107, + 114, + 126, + 125, + 104, + 58, + 17, + 158, + 134, + 100, + 122, + 82, + 110, + 110, + 253, + 156, + 0, + 134, + 101, + 243, + 223, + 243, + 38, + 107, + 51, + 195, + 183, + 113, + 89, + 22, + 40, + 84, + 20, + 214, + 153, + 119, + 142, + 53, + 161, + 141, + 48, + 108, + 39, + 170, + 110, + 185, + 156, + 222, + 248, + 4, + 21, + 167, + 173, + 189, + 150, + 175, + 41, + 255, + 15, + 250, + 127, + 215, + 36, + 206, + 166, + 138, + 83, + 80, + 71, + 54, + 127, + 33, + 37, + 10, + 95, + 87, + 205, + 228, + 97, + 109, + 133, + 41, + 85, + 238, + 106, + 50, + 233, + 34, + 233, + 69, + 54, + 77, + 137, + 166, + 232, + 53, + 73, + 110, + 43, + 223, + 59, + 128, + 176, + 43, + 136, + 121, + 18, + 137, + 237, + 242, + 49, + 128, + 60, + 105, + 37, + 113, + 3, + 55, + 147, + 140, + 106, + 128, + 37, + 65, + 112, + 17, + 198, + 44, + 154, + 139, + 28, + 72, + 169, + 229, + 16, + 184, + 125, + 136, + 187, + 157, + 111, + 206, + 146, + 81, + 106, + 190, + 75, + 24, + 236, + 143, + 208, + 56, + 209, + 78, + 5, + 227, + 233, + 120, + 228, + 105, + 75, + 157, + 219, + 120, + 57, + 175, + 178, + 128, + 58, + 126, + 128, + 136, + 53, + 198, + 115, + 132, + 107, + 77, + 38, + 195, + 31, + 185, + 11, + 116, + 192, + 193, + 52, + 198, + 26, + 183, + 184, + 231, + 66, + 10, + 191, + 15, + 136, + 64, + 161, + 12, + 243, + 58, + 86, + 37, + 104, + 208, + 94, + 46, + 162, + 234, + 84, + 14, + 132, + 210, + 21, + 76, + 241, + 86, + 233, + 26, + 128, + 16, + 161, + 41, + 230, + 52, + 85, + 4, + 198, + 234, + 163, + 31, + 231, + 18, + 212, + 88, + 219, + 54, + 219, + 55, + 11, + 23, + 89, + 221, + 236, + 43, + 106, + 215, + 205, + 177, + 94, + 106, + 225, + 245, + 197, + 181, + 93, + 124, + 155, + 43, + 65, + 147, + 111, + 237, + 211, + 214, + 169, + 233, + 4, + 216, + 236, + 158, + 248, + 37, + 61, + 41, + 38, + 137, + 148, + 138, + 76, + 135, + 229, + 153, + 211, + 207, + 138, + 9, + 58, + 133, + 19, + 125, + 38, + 228, + 150, + 243, + 68, + 216, + 119, + 88, + 195, + 1, + 181, + 141, + 196, + 107, + 95, + 55, + 92, + 135, + 30, + 111, + 218, + 208, + 85, + 74, + 198, + 85, + 22, + 22, + 82, + 17, + 222, + 26, + 157, + 112, + 103, + 206, + 114, + 14, + 206, + 45, + 166, + 133, + 121, + 137, + 67, + 249, + 82, + 153, + 40, + 192, + 167, + 113, + 35, + 248, + 30, + 1, + 120, + 239, + 245, + 74, + 95, + 107, + 198, + 60, + 149, + 211, + 82, + 31, + 153, + 246, + 55, + 41, + 158, + 73, + 42, + 188, + 106, + 122, + 67, + 228, + 226, + 162, + 208, + 235, + 142, + 112, + 153, + 249, + 131, + 91, + 104, + 64, + 23, + 12, + 226, + 89, + 88, + 50, + 86, + 33, + 200, + 101, + 124, + 194, + 32, + 88, + 172, + 101, + 107, + 102, + 24, + 98, + 206, + 255, + 76, + 38, + 96, + 52, + 243, + 129, + 86, + 63, + 104, + 14, + 162, + 5, + 103, + 196, + 64, + 39, + 189, + 111, + 231, + 5, + 31, + 196, + 222, + 146, + 218, + 4, + 159, + 144, + 101, + 75, + 0, + 53, + 158, + 161, + 234, + 253, + 228, + 194, + 113, + 85, + 8, + 223, + 215, + 190, + 208, + 75, + 70, + 246, + 131, + 185, + 18, + 56, + 181, + 52, + 112, + 54, + 152, + 197, + 247, + 185, + 99, + 247, + 251, + 28, + 159, + 151, + 67, + 211, + 253, + 55, + 179, + 27, + 238, + 8, + 58, + 172, + 54, + 13, + 30, + 43, + 177, + 60, + 14, + 172, + 62, + 74, + 85, + 64, + 202, + 61, + 157, + 176, + 1, + 132, + 151, + 209, + 171, + 247, + 168, + 232, + 230, + 254, + 97, + 2, + 172, + 19, + 230, + 44, + 136, + 221, + 149, + 158, + 180, + 226, + 124, + 44, + 47, + 91, + 2, + 82, + 175, + 136, + 70, + 252, + 85, + 222, + 116, + 118, + 78, + 244, + 137, + 140, + 103, + 40, + 32, + 139, + 9, + 233, + 9, + 166, + 83, + 157, + 23, + 125, + 242, + 68, + 53, + 15, + 217, + 85, + 14, + 119, + 182, + 73, + 35, + 203, + 30, + 254, + 92, + 189, + 63, + 73, + 247, + 95, + 2, + 0, + 108, + 8, + 188, + 89, + 245, + 42, + 36, + 123, + 57, + 106, + 16, + 176, + 114, + 157, + 223, + 177, + 60, + 97, + 23, + 218, + 1, + 19, + 91, + 177, + 218, + 207, + 112, + 4, + 78, + 168, + 129, + 81, + 216, + 119, + 45, + 117, + 120, + 252, + 20, + 60, + 157, + 175, + 18, + 143, + 230, + 207, + 183, + 157, + 158, + 0, + 14, + 46, + 55, + 69, + 66, + 48, + 89, + 26, + 198, + 134, + 47, + 163, + 31, + 150, + 164, + 30, + 185, + 133, + 144, + 243, + 42, + 163, + 85, + 167, + 174, + 47, + 91, + 252, + 106, + 150, + 167, + 194, + 145, + 58, + 92, + 107, + 90, + 205, + 181, + 75, + 152, + 2, + 104, + 200, + 34, + 168, + 89, + 211, + 225, + 26, + 163, + 47, + 14, + 218, + 185, + 235, + 12, + 148, + 193, + 83, + 59, + 230, + 168, + 108, + 45, + 25, + 230, + 249, + 4, + 248, + 214, + 96, + 57, + 140, + 117, + 136, + 94, + 249, + 1, + 94, + 86, + 233, + 33, + 114, + 237, + 230, + 102, + 39, + 165, + 133, + 203, + 166, + 121, + 109, + 161, + 18, + 79, + 205, + 31, + 23, + 78, + 206, + 171, + 100, + 125, + 247, + 209, + 133, + 150, + 191, + 67, + 251, + 44, + 188, + 236, + 40, + 10, + 75, + 210, + 84, + 93, + 139, + 182, + 238, + 16, + 213, + 238, + 103, + 113, + 94, + 187, + 175, + 107, + 3, + 212, + 245, + 218, + 47, + 98, + 50, + 84, + 66, + 119, + 156, + 41, + 7, + 225, + 219, + 8, + 172, + 94, + 112, + 14, + 84, + 143, + 143, + 141, + 237, + 3, + 171, + 2, + 127, + 97, + 5, + 64, + 38, + 224, + 216, + 28, + 84, + 50, + 39, + 131, + 121, + 16, + 151, + 94, + 9, + 45, + 1, + 151, + 139, + 138, + 78, + 13, + 7, + 178, + 78, + 208, + 250, + 220, + 245, + 196, + 179, + 168, + 142, + 76, + 202, + 217, + 99, + 107, + 23, + 39, + 5, + 187, + 67, + 14, + 53, + 218, + 126, + 102, + 9, + 226, + 146, + 242, + 231, + 198, + 59, + 239, + 83, + 0, + 102, + 127, + 91, + 72, + 45, + 199, + 154, + 32, + 50, + 71, + 202, + 24, + 45, + 5, + 241, + 111, + 140, + 255, + 57, + 127, + 250, + 47, + 41, + 109, + 228, + 41, + 237, + 249, + 187, + 140, + 2, + 19, + 148, + 130, + 204, + 162, + 210, + 107, + 217, + 110, + 19, + 70, + 151, + 34, + 16, + 197, + 140, + 78, + 28, + 231, + 104, + 28, + 22, + 36, + 112, + 7, + 14, + 69, + 168, + 103, + 19, + 64, + 163, + 92, + 214, + 151, + 152, + 135, + 184, + 135, + 159, + 18, + 180, + 63, + 117, + 91, + 50, + 251, + 171, + 36, + 157, + 66, + 56, + 215, + 185, + 19, + 50, + 67, + 28, + 122, + 2, + 103, + 77, + 233, + 43, + 35, + 75, + 105, + 29, + 3, + 226, + 147, + 102, + 97, + 117, + 97, + 246, + 9, + 42, + 200, + 94, + 65, + 197, + 39, + 162, + 13, + 150, + 86, + 191, + 220, + 76, + 51, + 43, + 224, + 27, + 17, + 141, + 155, + 125, + 146, + 50, + 134, + 66, + 49, + 172, + 41, + 165, + 161, + 107, + 248, + 128, + 242, + 96, + 114, + 121, + 1, + 220, + 205, + 176, + 10, + 43, + 119, + 161, + 108, + 206, + 180, + 166, + 235, + 40, + 81, + 0, + 222, + 49, + 96, + 130, + 174, + 0, + 67, + 216, + 177, + 199, + 6, + 42, + 193, + 41, + 88, + 85, + 184, + 175, + 191, + 205, + 101, + 246, + 85, + 251, + 217, + 86, + 141, + 21, + 137, + 230, + 212, + 15, + 134, + 141, + 177, + 8, + 176, + 112, + 76, + 86, + 33, + 83, + 189, + 200, + 169, + 92, + 225, + 126, + 48, + 209, + 9, + 228, + 112, + 181, + 226, + 149, + 215, + 192, + 79, + 48, + 98, + 121, + 187, + 232, + 169, + 118, + 57, + 129, + 63, + 213, + 58, + 1, + 205, + 80, + 114, + 237, + 88, + 126, + 4, + 22, + 78, + 6, + 246, + 92, + 197, + 94, + 110, + 184, + 245, + 148, + 144, + 144, + 253, + 24, + 64, + 70, + 178, + 197, + 15, + 204, + 27, + 67, + 74, + 53, + 209, + 112, + 196, + 136, + 114, + 201, + 149, + 14, + 245, + 6, + 77, + 26, + 13, + 246, + 109, + 60, + 132, + 218, + 43, + 18, + 191, + 194, + 194, + 83, + 124, + 156, + 59, + 87, + 218, + 132, + 20, + 184, + 89, + 70, + 197, + 117, + 152, + 112, + 246, + 133, + 72, + 201, + 40, + 183, + 62, + 138, + 22, + 110, + 32, + 114, + 108, + 196, + 103, + 8, + 94, + 248, + 176, + 192, + 137, + 104, + 56, + 254, + 43, + 125, + 113, + 44, + 123, + 146, + 59, + 173, + 175, + 119, + 42, + 15, + 14, + 29, + 153, + 66, + 218, + 233, + 105, + 137, + 234, + 242, + 193, + 124, + 51, + 37, + 35, + 72, + 189, + 249, + 59, + 218, + 9, + 23, + 42, + 235, + 155, + 29, + 113, + 245, + 227, + 204, + 211, + 58, + 148, + 107, + 137, + 152, + 9, + 241, + 1, + 125, + 167, + 57, + 72, + 38, + 19, + 135, + 12, + 124, + 171, + 122, + 136, + 172, + 3, + 121, + 146, + 20, + 90, + 240, + 77, + 206, + 113, + 221, + 160, + 149, + 61, + 80, + 236, + 22, + 22, + 146, + 129, + 206, + 43, + 224, + 90, + 47, + 185, + 155, + 17, + 180, + 177, + 105, + 219, + 25, + 111, + 99, + 145, + 194, + 51, + 54, + 63, + 13, + 228, + 123, + 212, + 47, + 137, + 148, + 123, + 15, + 64, + 9, + 243, + 50, + 198, + 49, + 36, + 253, + 152, + 87, + 198, + 63, + 214, + 171, + 12, + 247, + 105, + 242, + 167, + 204, + 133, + 246, + 174, + 165, + 46, + 55, + 147, + 239, + 46, + 79, + 115, + 82, + 127, + 243, + 62, + 233, + 133, + 220, + 114, + 141, + 211, + 127, + 0, + 69, + 178, + 175, + 101, + 139, + 66, + 225, + 204, + 235, + 206, + 17, + 214, + 205, + 157, + 189, + 17, + 121, + 83, + 81, + 60, + 159, + 255, + 170, + 45, + 200, + 250, + 15, + 87, + 114, + 254, + 195, + 251, + 220, + 24, + 51, + 250, + 211, + 82, + 222, + 45, + 163, + 210, + 23, + 188, + 156, + 226, + 174, + 163, + 110, + 179, + 156, + 97, + 10, + 32, + 179, + 36, + 194, + 143, + 226, + 63, + 136, + 46, + 138, + 91, + 20, + 106, + 24, + 185, + 136, + 82, + 28, + 70, + 109, + 253, + 188, + 168, + 178, + 106, + 137, + 148, + 80, + 60, + 94, + 240, + 56, + 60, + 147, + 36, + 210, + 147, + 36, + 37, + 34, + 41, + 1, + 215, + 253, + 143, + 253, + 191, + 63, + 46, + 68, + 85, + 89, + 205, + 167, + 105, + 203, + 193, + 209, + 174, + 71, + 75, + 6, + 151, + 170, + 144, + 58, + 159, + 76, + 216, + 227, + 69, + 255, + 180, + 132, + 86, + 252, + 11, + 97, + 215, + 37, + 110, + 48, + 107, + 169, + 166, + 88, + 2, + 5, + 41, + 37, + 171, + 49, + 85, + 157, + 102, + 28, + 196, + 136, + 1, + 173, + 53, + 98, + 189, + 0, + 101, + 48, + 224, + 174, + 187, + 32, + 14, + 216, + 78, + 92, + 53, + 144, + 211, + 13, + 112, + 79, + 207, + 243, + 19, + 127, + 79, + 216, + 61, + 175, + 137, + 21, + 98, + 101, + 118, + 100, + 200, + 137, + 94, + 72, + 48, + 19, + 51, + 90, + 186, + 9, + 95, + 169, + 45, + 127, + 141, + 5, + 7, + 75, + 131, + 63, + 37, + 241, + 161, + 11, + 246, + 92, + 25, + 58, + 219, + 201, + 60, + 121, + 68, + 219, + 171, + 219, + 251, + 110, + 122, + 173, + 223, + 88, + 110, + 140, + 215, + 34, + 92, + 79, + 55, + 159, + 150, + 150, + 122, + 70, + 1, + 179, + 151, + 118, + 72, + 250, + 46, + 73, + 182, + 23, + 52, + 171, + 45, + 36, + 40, + 231, + 166, + 123, + 118, + 168, + 66, + 192, + 55, + 76, + 220, + 143, + 23, + 50, + 38, + 25, + 168, + 234, + 14, + 187, + 40, + 17, + 16, + 211, + 37, + 89, + 243, + 196, + 191, + 77, + 74, + 88, + 226, + 116, + 158, + 241, + 118, + 175, + 89, + 252, + 179, + 73, + 220, + 5, + 39, + 212, + 133, + 219, + 253, + 42, + 49, + 154, + 38, + 44, + 153, + 37, + 209, + 232, + 99, + 28, + 17, + 55, + 128, + 240, + 254, + 168, + 245, + 37, + 130, + 68, + 17, + 232, + 238, + 68, + 244, + 75, + 14, + 47, + 150, + 231, + 132, + 0, + 1, + 65, + 108, + 10, + 252, + 43, + 103, + 106, + 68, + 251, + 245, + 48, + 253, + 4, + 211, + 199, + 23, + 136, + 4, + 168, + 94, + 131, + 184, + 103, + 176, + 171, + 14, + 71, + 20, + 215, + 28, + 35, + 65, + 189, + 1, + 226, + 248, + 71, + 234, + 58, + 6, + 249, + 110, + 55, + 79, + 180, + 92, + 248, + 163, + 75, + 101, + 158, + 88, + 104, + 85, + 243, + 33, + 230, + 140, + 62, + 122, + 87, + 236, + 167, + 208, + 135, + 111, + 119, + 74, + 192, + 106, + 120, + 124, + 76, + 121, + 69, + 20, + 188, + 13, + 229, + 13, + 185, + 132, + 200, + 28, + 124, + 122, + 94, + 231, + 213, + 172, + 113, + 242, + 95, + 22, + 202, + 178, + 104, + 158, + 243, + 69, + 20, + 116, + 167, + 239, + 132, + 120, + 126, + 166, + 43, + 89, + 40, + 2, + 253, + 66, + 222, + 89, + 238, + 66, + 59, + 217, + 84, + 110, + 38, + 32, + 67, + 92, + 250, + 37, + 36, + 227, + 9, + 83, + 37, + 191, + 242, + 49, + 49, + 227, + 29, + 214, + 12, + 240, + 122, + 10, + 125, + 1, + 185, + 97, + 191, + 44, + 203, + 221, + 43, + 19, + 155, + 202, + 146, + 166, + 54, + 156, + 6, + 50, + 227, + 7, + 35, + 207, + 213, + 36, + 99, + 232, + 218, + 127, + 198, + 89, + 99, + 162, + 130, + 133, + 113, + 108, + 55, + 204, + 125, + 14, + 212, + 233, + 31, + 152, + 122, + 47, + 8, + 204, + 163, + 242, + 168, + 1, + 87, + 14, + 55, + 114, + 130, + 16, + 166, + 19, + 135, + 111, + 59, + 202, + 25, + 26, + 72, + 81, + 190, + 89, + 55, + 16, + 249, + 15, + 207, + 162, + 15, + 192, + 57, + 167, + 131, + 46, + 213, + 215, + 175, + 51, + 71, + 96, + 232, + 117, + 159, + 75, + 119, + 167, + 21, + 167, + 27, + 205, + 189, + 110, + 142, + 192, + 160, + 89, + 126, + 184, + 248, + 254, + 175, + 34, + 170, + 82, + 55, + 144, + 240, + 195, + 87, + 232, + 56, + 75, + 111, + 46, + 1, + 241, + 142, + 248, + 99, + 36, + 198, + 230, + 116, + 74, + 42, + 21, + 245, + 94, + 14, + 110, + 191, + 70, + 142, + 170, + 5, + 185, + 192, + 96, + 38, + 26, + 197, + 187, + 76, + 63, + 114, + 94, + 106, + 173, + 173, + 111, + 224, + 128, + 212, + 87, + 90, + 46, + 54, + 205, + 38, + 18, + 188, + 217, + 214, + 79, + 131, + 206, + 85, + 87, + 52, + 85, + 227, + 72, + 236, + 164, + 197, + 119, + 205, + 9, + 152, + 6, + 129, + 224, + 111, + 48, + 74, + 33, + 204, + 35, + 75, + 127, + 244, + 146, + 89, + 51, + 101, + 108, + 231, + 152, + 202, + 145, + 74, + 103, + 165, + 33, + 215, + 88, + 38, + 91, + 136, + 228, + 131, + 15, + 54, + 130, + 110, + 87, + 18, + 5, + 193, + 32, + 46, + 209, + 46, + 112, + 253, + 177, + 181, + 251, + 35, + 213, + 66, + 166, + 2, + 190, + 220, + 172, + 131, + 69, + 193, + 128, + 137, + 155, + 72, + 140, + 208, + 42, + 146, + 38, + 121, + 0, + 230, + 16, + 120, + 19, + 227, + 51, + 247, + 234, + 124, + 1, + 249, + 8, + 63, + 155, + 175, + 165, + 51, + 188, + 22, + 177, + 185, + 126, + 174, + 105, + 196, + 207, + 87, + 176, + 235, + 57, + 58, + 197, + 89, + 33, + 223, + 112, + 107, + 1, + 13, + 41, + 148, + 26, + 251, + 228, + 189, + 22, + 246, + 174, + 115, + 48, + 248, + 16, + 10, + 126, + 123, + 159, + 5, + 117, + 172, + 245, + 193, + 201, + 111, + 243, + 168, + 45, + 73, + 84, + 41, + 112, + 133, + 55, + 26, + 153, + 236, + 108, + 96, + 248, + 136, + 58, + 157, + 252, + 154, + 15, + 157, + 235, + 22, + 136, + 128, + 40, + 49, + 14, + 3, + 186, + 248, + 49, + 117, + 2, + 237, + 56, + 120, + 83, + 179, + 142, + 139, + 45, + 46, + 210, + 217, + 233, + 55, + 192, + 167, + 110, + 102, + 181, + 127, + 141, + 30, + 35, + 202, + 246, + 180, + 246, + 163, + 150, + 131, + 47, + 184, + 57, + 230, + 100, + 27, + 204, + 177, + 20, + 45, + 219, + 136, + 242, + 26, + 47, + 168, + 109, + 132, + 84, + 69, + 227, + 93, + 224, + 251, + 55, + 40, + 47, + 223, + 18, + 161, + 92, + 31, + 27, + 133, + 81, + 55, + 122, + 90, + 18, + 25, + 212, + 138, + 69, + 21, + 1, + 110, + 125, + 147, + 217, + 112, + 167, + 156, + 82, + 122, + 227, + 101, + 154, + 151, + 10, + 140, + 238, + 158, + 195, + 199, + 33, + 191, + 77, + 28, + 18, + 157, + 177, + 194, + 72, + 44, + 241, + 10, + 219, + 4, + 99, + 36, + 113, + 251, + 182, + 4, + 177, + 76, + 209, + 172, + 214, + 152, + 248, + 39, + 140, + 152, + 22, + 19, + 229, + 73, + 112, + 9, + 88, + 168, + 207, + 201, + 147, + 95, + 211, + 215, + 192, + 149, + 100, + 252, + 101, + 152, + 227, + 105, + 154, + 36, + 221, + 3, + 167, + 66, + 164, + 45, + 60, + 188, + 210, + 148, + 64, + 183, + 55, + 125, + 123, + 57, + 253, + 167, + 190, + 117, + 116, + 15, + 22, + 129, + 87, + 76, + 70, + 225, + 60, + 28, + 199, + 172, + 70, + 38, + 213, + 54, + 232, + 211, + 78, + 137, + 213, + 202, + 234, + 184, + 67, + 41, + 96, + 74, + 251, + 243, + 55, + 239, + 50, + 0, + 247, + 239, + 49, + 37, + 175, + 81, + 209, + 145, + 102, + 130, + 126, + 116, + 99, + 132, + 168, + 246, + 143, + 72, + 191, + 113, + 72, + 163, + 105, + 198, + 136, + 250, + 142, + 82, + 160, + 35, + 127, + 148, + 224, + 6, + 62, + 243, + 237, + 246, + 141, + 201, + 33, + 137, + 22, + 8, + 123, + 183, + 8, + 96, + 127, + 4, + 117, + 43, + 176, + 52, + 110, + 13, + 13, + 207, + 245, + 181, + 35, + 176, + 78, + 243, + 236, + 5, + 84, + 136, + 38, + 77, + 81, + 243, + 198, + 131, + 213, + 22, + 237, + 24, + 233, + 212, + 234, + 196, + 223, + 157, + 189, + 176, + 82, + 134, + 139, + 130, + 41, + 91, + 213, + 151, + 206, + 125, + 46, + 92, + 155, + 82, + 85, + 151, + 60, + 114, + 40, + 58, + 66, + 170, + 70, + 138, + 16, + 87, + 223, + 233, + 95, + 2, + 184, + 228, + 25, + 54, + 229, + 244, + 185, + 181, + 179, + 173, + 234, + 195, + 142, + 83, + 16, + 2, + 76, + 122, + 27, + 204, + 146, + 52, + 239, + 230, + 59, + 107, + 232, + 151, + 231, + 36, + 254, + 78, + 9, + 134, + 92, + 14, + 221, + 213, + 20, + 141, + 195, + 122, + 4, + 106, + 242, + 63, + 178, + 225, + 31, + 203, + 220, + 10, + 207, + 122, + 173, + 107, + 254, + 231, + 109, + 139, + 127, + 72, + 70, + 116, + 120, + 85, + 14, + 2, + 91, + 19, + 126, + 194, + 92, + 132, + 115, + 192, + 24, + 201, + 46, + 210, + 115, + 14, + 53, + 184, + 150, + 239, + 219, + 226, + 237, + 139, + 14, + 157, + 189, + 15, + 80, + 206, + 243, + 50, + 51, + 148, + 45, + 82, + 139, + 212, + 72, + 76, + 217, + 138, + 237, + 36, + 143, + 88, + 73, + 247, + 70, + 184, + 183, + 78, + 86, + 143, + 89, + 215, + 227, + 46, + 222, + 44, + 224, + 116, + 51, + 92, + 8, + 93, + 228, + 223, + 234, + 164, + 158, + 232, + 113, + 211, + 80, + 202, + 88, + 36, + 73, + 76, + 210, + 94, + 230, + 17, + 125, + 9, + 118, + 245, + 208, + 165, + 41, + 26, + 92, + 158, + 10, + 10, + 58, + 223, + 189, + 71, + 15, + 42, + 33, + 221, + 102, + 101, + 90, + 111, + 71, + 94, + 127, + 83, + 236, + 95, + 192, + 224, + 206, + 169, + 67, + 22, + 75, + 154, + 234, + 77, + 8, + 63, + 219, + 253, + 70, + 216, + 194, + 45, + 43, + 166, + 251, + 211, + 76, + 48, + 89, + 244, + 219, + 253, + 148, + 40, + 222, + 217, + 251, + 252, + 226, + 115, + 50, + 242, + 196, + 54, + 220, + 113, + 111, + 142, + 226, + 140, + 109, + 242, + 97, + 157, + 220, + 100, + 87, + 171, + 137, + 66, + 235, + 47, + 37, + 168, + 147, + 217, + 182, + 247, + 66, + 142, + 38, + 145, + 53, + 113, + 103, + 252, + 247, + 130, + 193, + 94, + 49, + 146, + 74, + 71, + 214, + 126, + 81, + 218, + 211, + 123, + 71, + 59, + 16, + 205, + 45, + 198, + 199, + 126, + 91, + 214, + 255, + 16, + 90, + 31, + 116, + 172, + 25, + 234, + 120, + 242, + 16, + 131, + 148, + 99, + 82, + 145, + 60, + 223, + 143, + 238, + 208, + 134, + 20, + 0, + 115, + 201, + 38, + 28, + 149, + 188, + 118, + 48, + 76, + 111, + 229, + 64, + 189, + 220, + 246, + 208, + 93, + 128, + 130, + 114, + 209, + 79, + 71, + 57, + 158, + 143, + 30, + 132, + 143, + 31, + 213, + 52, + 125, + 75, + 226, + 78, + 3, + 138, + 74, + 118, + 106, + 14, + 201, + 75, + 82, + 232, + 59, + 8, + 104, + 232, + 150, + 44, + 12, + 45, + 27, + 12, + 12, + 205, + 119, + 128, + 26, + 193, + 29, + 76, + 18, + 106, + 18, + 139, + 101, + 80, + 126, + 108, + 43, + 39, + 247, + 120, + 218, + 93, + 39, + 247, + 177, + 173, + 122, + 112, + 148, + 70, + 51, + 1, + 80, + 11, + 216, + 206, + 84, + 243, + 71, + 246, + 251, + 101, + 5, + 173, + 185, + 54, + 230, + 164, + 221, + 243, + 109, + 251, + 79, + 35, + 3, + 241, + 250, + 36, + 240, + 51, + 85, + 27, + 71, + 40, + 237, + 6, + 191, + 82, + 26, + 54, + 34, + 203, + 254, + 85, + 177, + 75, + 45, + 37, + 14, + 172, + 125, + 78, + 106, + 83, + 22, + 185, + 1, + 94, + 163, + 142, + 23, + 91, + 204, + 244, + 7, + 40, + 184, + 196, + 87, + 195, + 29, + 124, + 240, + 221, + 138, + 60, + 75, + 132, + 43, + 168, + 200, + 8, + 17, + 52, + 158, + 14, + 79, + 113, + 66, + 77, + 176, + 39, + 107, + 41, + 229, + 209, + 6, + 70, + 110, + 187, + 46, + 177, + 42, + 41, + 214, + 116, + 13, + 59, + 155, + 145, + 77, + 23, + 164, + 116, + 25, + 113, + 44, + 173, + 38, + 115, + 86, + 121, + 254, + 124, + 205, + 246, + 128, + 78, + 20, + 49, + 229, + 110, + 183, + 130, + 145, + 191, + 49, + 90, + 39, + 179, + 210, + 116, + 168, + 70, + 44, + 120, + 10, + 97, + 84, + 163, + 243, + 208, + 187, + 103, + 142, + 46, + 41, + 170, + 212, + 115, + 8, + 138, + 46, + 79, + 89, + 3, + 176, + 200, + 191, + 155, + 179, + 4, + 98, + 247, + 21, + 56, + 37, + 52, + 12, + 161, + 120, + 209, + 207, + 211, + 217, + 110, + 54, + 250, + 159, + 137, + 29, + 192, + 24, + 118, + 124, + 61, + 54, + 53, + 18, + 114, + 147, + 114, + 89, + 232, + 94, + 190, + 177, + 85, + 112, + 114, + 29, + 197, + 38, + 11, + 171, + 39, + 162, + 163, + 188, + 215, + 22, + 1, + 149, + 161, + 41, + 101, + 223, + 139, + 209, + 190, + 179, + 183, + 238, + 168, + 128, + 54, + 17, + 123, + 183, + 42, + 92, + 41, + 131, + 93, + 205, + 93, + 208, + 44, + 105, + 137, + 15, + 107, + 221, + 136, + 121, + 124, + 54, + 33, + 59, + 122, + 57, + 212, + 251, + 39, + 143, + 130, + 20, + 225, + 106, + 121, + 2, + 77, + 37, + 20, + 149, + 11, + 65, + 210, + 70, + 65, + 203, + 140, + 249, + 178, + 215, + 57, + 59, + 172, + 67, + 107, + 180, + 226, + 128, + 250, + 211, + 111, + 149, + 36, + 91, + 6, + 7, + 216, + 206, + 52, + 212, + 39, + 128, + 23, + 87, + 124, + 57, + 220, + 211, + 197, + 89, + 239, + 28, + 102, + 177, + 120, + 79, + 37, + 68, + 22, + 239, + 53, + 118, + 13, + 138, + 62, + 40, + 90, + 34, + 131, + 132, + 182, + 57, + 22, + 84, + 97, + 139, + 177, + 220, + 179, + 109, + 91, + 195, + 116, + 246, + 75, + 188, + 33, + 40, + 222, + 138, + 126, + 6, + 38, + 120, + 107, + 145, + 180, + 231, + 155, + 209, + 246, + 136, + 157, + 49, + 66, + 151, + 249, + 139, + 142, + 122, + 248, + 141, + 126, + 181, + 239, + 84, + 254, + 6, + 140, + 78, + 37, + 127, + 19, + 246, + 126, + 244, + 9, + 183, + 111, + 100, + 222, + 87, + 77, + 159, + 181, + 184, + 178, + 126, + 255, + 37, + 37, + 65, + 193, + 84, + 152, + 32, + 106, + 219, + 80, + 199, + 239, + 110, + 6, + 244, + 30, + 112, + 34, + 192, + 240, + 9, + 42, + 160, + 208, + 138, + 182, + 216, + 251, + 170, + 74, + 54, + 109, + 98, + 198, + 252, + 30, + 49, + 207, + 122, + 8, + 208, + 242, + 14, + 152, + 4, + 137, + 59, + 251, + 70, + 188, + 27, + 137, + 136, + 237, + 236, + 165, + 242, + 225, + 83, + 137, + 203, + 16, + 158, + 202, + 142, + 103, + 200, + 152, + 238, + 146, + 91, + 101, + 87, + 164, + 205, + 231, + 92, + 25, + 176, + 197, + 25, + 254, + 81, + 7, + 27, + 147, + 50, + 196, + 59, + 254, + 137, + 9, + 242, + 245, + 201, + 213, + 121, + 66, + 117, + 113, + 223, + 196, + 99, + 213, + 217, + 149, + 130, + 99, + 30, + 2, + 192, + 253, + 121, + 255, + 244, + 126, + 103, + 52, + 126, + 228, + 91, + 253, + 190, + 231, + 169, + 69, + 234, + 77, + 153, + 33, + 171, + 221, + 95, + 2, + 78, + 66, + 4, + 147, + 46, + 149, + 84, + 110, + 136, + 93, + 42, + 198, + 120, + 244, + 196, + 173, + 191, + 195, + 8, + 208, + 49, + 233, + 139, + 222, + 149, + 23, + 72, + 21, + 145, + 189, + 65, + 159, + 185, + 124, + 107, + 119, + 18, + 189, + 35, + 47, + 175, + 246, + 107, + 17, + 114, + 208, + 16, + 231, + 159, + 200, + 171, + 148, + 117, + 27, + 198, + 124, + 221, + 160, + 10, + 96, + 98, + 155, + 200, + 240, + 214, + 181, + 198, + 253, + 98, + 212, + 1, + 75, + 123, + 81, + 119, + 26, + 155, + 18, + 196, + 163, + 160, + 101, + 66, + 239, + 60, + 188, + 175, + 140, + 208, + 66, + 136, + 225, + 192, + 100, + 186, + 40, + 109, + 70, + 2, + 199, + 182, + 198, + 45, + 142, + 85, + 21, + 30, + 217, + 9, + 204, + 201, + 248, + 187, + 23, + 137, + 185, + 148, + 253, + 71, + 80, + 123, + 236, + 158, + 177, + 136, + 129, + 113, + 74, + 47, + 39, + 155, + 166, + 226, + 216, + 51, + 71, + 34, + 87, + 91, + 79, + 124, + 79, + 35, + 187, + 219, + 99, + 31, + 149, + 231, + 169, + 97, + 144, + 227, + 180, + 238, + 136, + 38, + 226, + 101, + 161, + 71, + 247, + 92, + 156, + 171, + 182, + 54, + 192, + 220, + 128, + 224, + 43, + 110, + 88, + 181, + 37, + 48, + 20, + 167, + 133, + 10, + 241, + 182, + 57, + 75, + 247, + 21, + 211, + 34, + 45, + 165, + 84, + 172, + 116, + 157, + 77, + 139, + 56, + 3, + 209, + 152, + 57, + 51, + 178, + 254, + 5, + 232, + 27, + 251, + 55, + 5, + 226, + 119, + 16, + 144, + 159, + 195, + 236, + 197, + 209, + 255, + 6, + 78, + 26, + 205, + 144, + 101, + 10, + 233, + 137, + 106, + 242, + 234, + 127, + 25, + 131, + 237, + 15, + 129, + 51, + 79, + 69, + 194, + 45, + 26, + 148, + 232, + 94, + 228, + 1, + 80, + 171, + 99, + 126, + 111, + 238, + 151, + 112, + 91, + 72, + 251, + 211, + 6, + 108, + 104, + 252, + 92, + 99, + 237, + 49, + 176, + 94, + 172, + 145, + 35, + 30, + 246, + 162, + 112, + 239, + 31, + 156, + 89, + 240, + 51, + 213, + 170, + 170, + 233, + 153, + 244, + 231, + 98, + 173, + 12, + 46, + 235, + 38, + 119, + 27, + 32, + 13, + 249, + 62, + 121, + 131, + 164, + 187, + 109, + 242, + 43, + 78, + 250, + 46, + 195, + 26, + 237, + 220, + 255, + 166, + 28, + 130, + 238, + 223, + 100, + 228, + 50, + 90, + 234, + 199, + 180, + 201, + 135, + 225, + 46, + 103, + 66, + 141, + 154, + 233, + 14, + 198, + 119, + 144, + 211, + 153, + 107, + 100, + 255, + 48, + 124, + 50, + 208, + 81, + 59, + 23, + 197, + 178, + 21, + 224, + 117, + 239, + 240, + 25, + 87, + 32, + 255, + 233, + 71, + 10, + 72, + 198, + 134, + 164, + 104, + 103, + 2, + 34, + 157, + 43, + 40, + 106, + 134, + 236, + 47, + 118, + 55, + 53, + 26, + 30, + 110, + 66, + 146, + 131, + 45, + 36, + 22, + 3, + 204, + 118, + 70, + 18, + 164, + 177, + 240, + 225, + 47, + 159, + 36, + 133, + 47, + 38, + 233, + 240, + 218, + 163, + 188, + 167, + 135, + 95, + 118, + 180, + 44, + 219, + 65, + 167, + 75, + 56, + 219, + 130, + 200, + 44, + 120, + 20, + 191, + 22, + 125, + 121, + 18, + 23, + 124, + 232, + 11, + 73, + 243, + 105, + 246, + 236, + 181, + 249, + 69, + 48, + 191, + 247, + 103, + 58, + 28, + 221, + 138, + 199, + 232, + 11, + 25, + 47, + 238, + 47, + 233, + 29, + 10, + 190, + 126, + 217, + 146, + 195, + 184, + 69, + 99, + 220, + 218, + 92, + 194, + 18, + 2, + 22, + 201, + 237, + 79, + 19, + 60, + 143, + 131, + 166, + 193, + 105, + 230, + 236, + 129, + 131, + 101, + 86, + 240, + 159, + 166, + 116, + 235, + 58, + 16, + 38, + 95, + 119, + 94, + 148, + 122, + 56, + 10, + 213, + 57, + 229, + 59, + 110, + 92, + 246, + 51, + 32, + 205, + 22, + 217, + 150, + 240, + 195, + 190, + 170, + 20, + 72, + 246, + 11, + 63, + 141, + 79, + 88, + 109, + 149, + 206, + 39, + 180, + 130, + 197, + 225, + 40, + 141, + 86, + 49, + 133, + 66, + 2, + 248, + 146, + 124, + 29, + 34, + 235, + 120, + 46, + 151, + 133, + 98, + 198, + 70, + 79, + 120, + 121, + 75, + 225, + 34, + 242, + 13, + 221, + 79, + 157, + 141, + 224, + 107, + 38, + 126, + 115, + 125, + 33, + 208, + 213, + 190, + 254, + 193, + 154, + 14, + 42, + 39, + 7, + 45, + 243, + 83, + 17, + 254, + 21, + 73, + 209, + 83, + 13, + 241, + 118, + 179, + 190, + 173, + 11, + 93, + 13, + 93, + 184, + 153, + 196, + 46, + 145, + 80, + 117, + 241, + 190, + 44, + 153, + 250, + 0, + 50, + 38, + 141, + 6, + 238, + 25, + 0, + 77, + 209, + 71, + 181, + 104, + 93, + 194, + 175, + 156, + 102, + 21, + 89, + 126, + 230, + 94, + 177, + 14, + 109, + 220, + 85, + 84, + 65, + 227, + 116, + 135, + 33, + 73, + 5, + 213, + 116, + 31, + 99, + 79, + 2, + 24, + 47, + 249, + 209, + 148, + 225, + 178, + 133, + 8, + 136, + 183, + 197, + 61, + 210, + 35, + 43, + 246, + 55, + 211, + 177, + 92, + 105, + 108, + 153, + 46, + 178, + 252, + 125, + 121, + 131, + 228, + 198, + 80, + 194, + 143, + 20, + 190, + 26, + 32, + 65, + 26, + 111, + 208, + 58, + 206, + 115, + 205, + 146, + 145, + 199, + 34, + 104, + 87, + 91, + 179, + 177, + 175, + 242, + 230, + 155, + 96, + 195, + 170, + 11, + 111, + 208, + 96, + 18, + 60, + 231, + 99, + 230, + 14, + 201, + 164, + 145, + 97, + 55, + 6, + 48, + 245, + 143, + 41, + 61, + 78, + 94, + 180, + 249, + 190, + 222, + 23, + 45, + 166, + 59, + 164, + 9, + 118, + 233, + 170, + 105, + 24, + 89, + 142, + 68, + 84, + 143, + 252, + 170, + 26, + 233, + 110, + 14, + 94, + 110, + 19, + 244, + 185, + 6, + 179, + 166, + 201, + 140, + 210, + 176, + 188, + 247, + 201, + 115, + 44, + 24, + 33, + 5, + 225, + 195, + 197, + 169, + 54, + 243, + 237, + 236, + 83, + 143, + 86, + 138, + 247, + 210, + 213, + 143, + 44, + 38, + 204, + 195, + 186, + 41, + 157, + 12, + 158, + 86, + 33, + 29, + 128, + 196, + 131, + 255, + 207, + 13, + 12, + 108, + 68, + 134, + 128, + 8, + 107, + 148, + 191, + 143, + 204, + 67, + 140, + 140, + 230, + 227, + 223, + 181, + 113, + 177, + 166, + 104, + 128, + 222, + 198, + 235, + 197, + 231, + 227, + 9, + 217, + 236, + 13, + 214, + 70, + 50, + 125, + 127, + 199, + 124, + 27, + 187, + 204, + 233, + 58, + 160, + 47, + 57, + 45, + 161, + 141, + 44, + 15, + 15, + 234, + 83, + 42, + 99, + 202, + 12, + 239, + 255, + 12, + 43, + 55, + 127, + 4, + 33, + 254, + 148, + 9, + 94, + 72, + 30, + 233, + 6, + 43, + 160, + 88, + 219, + 234, + 92, + 99, + 179, + 13, + 187, + 15, + 110, + 175, + 33, + 180, + 88, + 152, + 48, + 183, + 187, + 210, + 4, + 19, + 199, + 69, + 124, + 233, + 213, + 72, + 53, + 30, + 255, + 109, + 106, + 23, + 178, + 69, + 211, + 70, + 235, + 91, + 113, + 222, + 226, + 129, + 98, + 12, + 4, + 168, + 118, + 175, + 250, + 133, + 109, + 47, + 103, + 86, + 26, + 201, + 238, + 51, + 233, + 176, + 50, + 213, + 182, + 111, + 97, + 153, + 230, + 38, + 240, + 100, + 68, + 96, + 123, + 210, + 105, + 242, + 197, + 7, + 43, + 56, + 182, + 155, + 70, + 75, + 235, + 83, + 119, + 184, + 195, + 13, + 245, + 68, + 220, + 147, + 37, + 85, + 41, + 155, + 10, + 128, + 60, + 142, + 182, + 87, + 163, + 224, + 78, + 66, + 182, + 22, + 159, + 205, + 179, + 118, + 174, + 101, + 1, + 99, + 149, + 132, + 39, + 41, + 217, + 63, + 0, + 13, + 15, + 178, + 120, + 25, + 17, + 137, + 201, + 217, + 248, + 191, + 195, + 185, + 155, + 130, + 121, + 117, + 154, + 63, + 159, + 111, + 66, + 75, + 211, + 145, + 228, + 50, + 56, + 118, + 89, + 99, + 43, + 23, + 12, + 236, + 7, + 138, + 4, + 195, + 66, + 4, + 115, + 249, + 72, + 175, + 104, + 125, + 159, + 152, + 19, + 14, + 9, + 164, + 5, + 6, + 115, + 40, + 200, + 170, + 180, + 197, + 173, + 101, + 228, + 238, + 121, + 214, + 80, + 150, + 214, + 246, + 3, + 68, + 99, + 222, + 150, + 137, + 154, + 99, + 187, + 239, + 207, + 166, + 198, + 136, + 199, + 38, + 149, + 236, + 39, + 114, + 86, + 82, + 3, + 57, + 135, + 72, + 76, + 74, + 249, + 147, + 24, + 239, + 237, + 42, + 81, + 21, + 181, + 175, + 105, + 217, + 134, + 72, + 52, + 61, + 11, + 148, + 214, + 96, + 179, + 117, + 226, + 188, + 55, + 87, + 129, + 28, + 51, + 158, + 163, + 193, + 69, + 96, + 102, + 41, + 23, + 201, + 189, + 97, + 57, + 231, + 102, + 45, + 175, + 185, + 26, + 8, + 43, + 243, + 180, + 10, + 159, + 212, + 39, + 188, + 150, + 206, + 26, + 138, + 244, + 76, + 242, + 67, + 113, + 210, + 223, + 234, + 31, + 211, + 196, + 209, + 97, + 174, + 135, + 64, + 244, + 95, + 48, + 32, + 70, + 249, + 181, + 102, + 210, + 162, + 58, + 244, + 210, + 133, + 72, + 164, + 39, + 195, + 132, + 15, + 211, + 78, + 86, + 170, + 200, + 129, + 42, + 32, + 168, + 49, + 222, + 150, + 154, + 88, + 98, + 143, + 144, + 241, + 99, + 3, + 185, + 176, + 53, + 148, + 47, + 137, + 30, + 122, + 227, + 109, + 222, + 188, + 132, + 43, + 152, + 122, + 234, + 170, + 148, + 1, + 55, + 15, + 85, + 81, + 126, + 95, + 107, + 8, + 244, + 45, + 158, + 57, + 151, + 218, + 85, + 250, + 128, + 204, + 2, + 108, + 167, + 173, + 194, + 13, + 35, + 11, + 144, + 152, + 124, + 203, + 19, + 86, + 191, + 211, + 89, + 138, + 37, + 150, + 254, + 32, + 49, + 218, + 34, + 13, + 107, + 151, + 48, + 186, + 117, + 65, + 218, + 122, + 65, + 85, + 84, + 224, + 7, + 189, + 211, + 197, + 210, + 1, + 191, + 118, + 190, + 114, + 61, + 253, + 182, + 49, + 195, + 145, + 216, + 145, + 226, + 60, + 41, + 73, + 40, + 50, + 213, + 80, + 108, + 100, + 228, + 180, + 211, + 54, + 120, + 149, + 179, + 29, + 80, + 219, + 112, + 187, + 70, + 79, + 140, + 172, + 51, + 164, + 10, + 97, + 233, + 14, + 255, + 65, + 186, + 174, + 89, + 188, + 193, + 145, + 220, + 233, + 75, + 8, + 61, + 197, + 243, + 185, + 18, + 1, + 196, + 4, + 63, + 193, + 79, + 57, + 36, + 101, + 126, + 24, + 117, + 24, + 161, + 174, + 154, + 37, + 16, + 207, + 193, + 114, + 127, + 83, + 138, + 195, + 133, + 232, + 61, + 255, + 89, + 137, + 128, + 7, + 47, + 142, + 219, + 74, + 66, + 143, + 244, + 157, + 83, + 200, + 26, + 153, + 191, + 202, + 80, + 13, + 203, + 124, + 220, + 12, + 109, + 43, + 121, + 154, + 233, + 49, + 99, + 26, + 215, + 19, + 133, + 39, + 129, + 48, + 87, + 11, + 242, + 98, + 83, + 46, + 204, + 211, + 158, + 207, + 42, + 122, + 155, + 91, + 243, + 69, + 71, + 196, + 246, + 124, + 169, + 117, + 20, + 9, + 86, + 14, + 247, + 7, + 58, + 162, + 176, + 1, + 138, + 198, + 244, + 158, + 38, + 13, + 94, + 187, + 92, + 212, + 62, + 182, + 155, + 111, + 112, + 101, + 44, + 175, + 130, + 55, + 29, + 28, + 140, + 57, + 131, + 122, + 202, + 218, + 101, + 10, + 94, + 212, + 23, + 71, + 127, + 129, + 99, + 116, + 157, + 52, + 20, + 203, + 242, + 87, + 114, + 96, + 40, + 225, + 16, + 120, + 250, + 25, + 201, + 174, + 199, + 144, + 154, + 60, + 20, + 17, + 115, + 14, + 24, + 213, + 150, + 94, + 222, + 28, + 244, + 91, + 174, + 175, + 240, + 18, + 6, + 29, + 59, + 77, + 17, + 243, + 138, + 39, + 27, + 49, + 54, + 177, + 67, + 16, + 59, + 221, + 165, + 111, + 201, + 4, + 32, + 182, + 174, + 191, + 94, + 214, + 195, + 218, + 165, + 229, + 69, + 0, + 159, + 10, + 47, + 27, + 184, + 173, + 49, + 223, + 94, + 26, + 42, + 169, + 6, + 98, + 89, + 21, + 186, + 54, + 179, + 169, + 21, + 93, + 249, + 166, + 114, + 105, + 69, + 21, + 68, + 233, + 7, + 90, + 129, + 125, + 110, + 88, + 198, + 46, + 75, + 188, + 120, + 214, + 20, + 142, + 150, + 75, + 153, + 201, + 104, + 74, + 80, + 143, + 195, + 76, + 187, + 228, + 23, + 75, + 204, + 127, + 160, + 28, + 249, + 173, + 128, + 36, + 206, + 20, + 95, + 29, + 179, + 100, + 204, + 169, + 115, + 181, + 31, + 164, + 103, + 145, + 227, + 165, + 196, + 28, + 136, + 179, + 104, + 242, + 135, + 145, + 158, + 135, + 35, + 158, + 89, + 83, + 63, + 58, + 55, + 111, + 12, + 186, + 49, + 47, + 140, + 156, + 130, + 2, + 193, + 220, + 85, + 177, + 5, + 250, + 72, + 21, + 70, + 6, + 98, + 134, + 103, + 94, + 253, + 193, + 242, + 28, + 108, + 229, + 205, + 143, + 31, + 19, + 51, + 95, + 45, + 151, + 32, + 109, + 152, + 130, + 177, + 237, + 143, + 70, + 180, + 96, + 246, + 213, + 207, + 100, + 163, + 101, + 238, + 152, + 69, + 8, + 78, + 219, + 3, + 248, + 248, + 110, + 82, + 52, + 94, + 220, + 80, + 159, + 194, + 35, + 103, + 159, + 61, + 12, + 5, + 156, + 40, + 163, + 213, + 145, + 26, + 92, + 94, + 116, + 115, + 97, + 184, + 68, + 14, + 31, + 37, + 21, + 5, + 136, + 12, + 94, + 60, + 230, + 105, + 207, + 133, + 110, + 155, + 22, + 108, + 226, + 116, + 233, + 150, + 4, + 13, + 149, + 145, + 18, + 193, + 45, + 82, + 210, + 39, + 156, + 175, + 108, + 88, + 58, + 20, + 21, + 58, + 114, + 133, + 81, + 10, + 203, + 63, + 36, + 191, + 127, + 81, + 91, + 100, + 222, + 112, + 119, + 195, + 218, + 102, + 128, + 243, + 160, + 216, + 146, + 167, + 32, + 58, + 194, + 18, + 251, + 175, + 205, + 223, + 54, + 59, + 138, + 143, + 107, + 24, + 75, + 13, + 104, + 217, + 122, + 21, + 121, + 40, + 85, + 108, + 80, + 77, + 171, + 164, + 106, + 214, + 22, + 183, + 160, + 117, + 12, + 196, + 226, + 87, + 154, + 76, + 5, + 154, + 143, + 87, + 98, + 104, + 15, + 226, + 4, + 140, + 35, + 223, + 52, + 192, + 215, + 20, + 117, + 80, + 204, + 126, + 72, + 242, + 90, + 90, + 171, + 202, + 75, + 249, + 35, + 223, + 136, + 177, + 33, + 42, + 97, + 139, + 215, + 65, + 40, + 20, + 232, + 219, + 28, + 124, + 191, + 110, + 74, + 82, + 160, + 227, + 197, + 170, + 47, + 156, + 193, + 153, + 36, + 180, + 237, + 46, + 206, + 208, + 15, + 35, + 10, + 137, + 206, + 250, + 34, + 169, + 104, + 147, + 120, + 6, + 38, + 102, + 227, + 129, + 89, + 8, + 126, + 157, + 22, + 124, + 142, + 142, + 22, + 15, + 60, + 190, + 35, + 140, + 235, + 4, + 214, + 248, + 22, + 195, + 15, + 190, + 83, + 49, + 150, + 139, + 13, + 66, + 86, + 157, + 100, + 104, + 91, + 37, + 183, + 229, + 58, + 181, + 132, + 39, + 235, + 255, + 122, + 228, + 11, + 238, + 156, + 12, + 177, + 207, + 42, + 39, + 236, + 147, + 15, + 61, + 201, + 190, + 134, + 172, + 83, + 126, + 221, + 106, + 26, + 127, + 71, + 79, + 212, + 128, + 160, + 111, + 38, + 35, + 170, + 22, + 82, + 212, + 104, + 183, + 166, + 254, + 42, + 141, + 95, + 72, + 149, + 87, + 59, + 105, + 5, + 4, + 56, + 104, + 22, + 212, + 210, + 70, + 223, + 130, + 201, + 218, + 202, + 206, + 140, + 45, + 130, + 101, + 233, + 221, + 115, + 212, + 20, + 208, + 100, + 92, + 249, + 236, + 140, + 129, + 187, + 109, + 13, + 19, + 72, + 100, + 164, + 81, + 35, + 235, + 102, + 221, + 86, + 120, + 224, + 130, + 217, + 198, + 209, + 57, + 165, + 224, + 181, + 182, + 196, + 212, + 105, + 116, + 147, + 186, + 209, + 201, + 80, + 160, + 158, + 52, + 184, + 67, + 227, + 68, + 169, + 18, + 180, + 32, + 105, + 165, + 67, + 135, + 201, + 69, + 23, + 28, + 200, + 240, + 29, + 241, + 112, + 239, + 62, + 49, + 248, + 32, + 108, + 65, + 189, + 192, + 53, + 209, + 16, + 145, + 208, + 147, + 181, + 71, + 245, + 70, + 71, + 105, + 51, + 175, + 235, + 184, + 8, + 117, + 218, + 248, + 219, + 239, + 212, + 154, + 28, + 177, + 224, + 220, + 130, + 103, + 132, + 95, + 115, + 22, + 180, + 80, + 168, + 107, + 252, + 79, + 27, + 141, + 37, + 50, + 253, + 1, + 80, + 23, + 216, + 148, + 145, + 52, + 27, + 162, + 229, + 148, + 69, + 219, + 77, + 49, + 244, + 94, + 238, + 185, + 34, + 203, + 5, + 192, + 155, + 150, + 189, + 197, + 76, + 250, + 232, + 69, + 33, + 41, + 147, + 138, + 171, + 244, + 221, + 250, + 184, + 45, + 33, + 228, + 20, + 68, + 90, + 215, + 74, + 178, + 156, + 201, + 251, + 51, + 144, + 166, + 152, + 100, + 1, + 121, + 226, + 137, + 151, + 68, + 227, + 83, + 251, + 12, + 128, + 158, + 145, + 193, + 134, + 37, + 7, + 223, + 62, + 124, + 187, + 70, + 9, + 180, + 82, + 166, + 252, + 194, + 212, + 161, + 32, + 37, + 238, + 166, + 54, + 31, + 153, + 215, + 245, + 204, + 22, + 60, + 87, + 215, + 132, + 98, + 219, + 23, + 108, + 245, + 35, + 187, + 24, + 109, + 90, + 113, + 169, + 125, + 154, + 127, + 200, + 108, + 13, + 139, + 190, + 154, + 177, + 74, + 225, + 33, + 150, + 42, + 121, + 68, + 226, + 67, + 144, + 239, + 139, + 165, + 59, + 193, + 61, + 36, + 124, + 28, + 56, + 229, + 12, + 34, + 158, + 2, + 63, + 108, + 109, + 155, + 71, + 223, + 244, + 40, + 59, + 101, + 71, + 12, + 84, + 86, + 177, + 219, + 74, + 9, + 91, + 107, + 56, + 206, + 33, + 97, + 30, + 51, + 139, + 1, + 21, + 178, + 82, + 161, + 29, + 74, + 242, + 149, + 209, + 114, + 6, + 46, + 253, + 118, + 202, + 40, + 121, + 130, + 181, + 249, + 130, + 211, + 206, + 171, + 168, + 7, + 93, + 187, + 47, + 203, + 222, + 246, + 229, + 115, + 144, + 202, + 31, + 167, + 220, + 245, + 136, + 8, + 156, + 72, + 95, + 39, + 140, + 37, + 62, + 128, + 37, + 108, + 197, + 9, + 102, + 218, + 236, + 91, + 57, + 42, + 159, + 26, + 254, + 3, + 234, + 70, + 155, + 68, + 118, + 5, + 59, + 96, + 93, + 253, + 126, + 111, + 233, + 62, + 154, + 46, + 127, + 243, + 48, + 42, + 224, + 38, + 78, + 120, + 117, + 246, + 35, + 208, + 225, + 232, + 203, + 11, + 44, + 173, + 97, + 222, + 45, + 171, + 164, + 162, + 198, + 109, + 37, + 213, + 72, + 227, + 221, + 215, + 178, + 65, + 6, + 18, + 118, + 228, + 168, + 105, + 236, + 180, + 92, + 71, + 182, + 50, + 111, + 239, + 102, + 89, + 84, + 150, + 91, + 240, + 165, + 189, + 252, + 37, + 77, + 210, + 56, + 199, + 208, + 118, + 232, + 134, + 176, + 24, + 216, + 198, + 196, + 144, + 196, + 14, + 101, + 22, + 69, + 176, + 166, + 161, + 174, + 148, + 105, + 193, + 65, + 134, + 85, + 118, + 226, + 221, + 68, + 33, + 196, + 13, + 161, + 171, + 176, + 120, + 163, + 114, + 156, + 48, + 26, + 33, + 48, + 22, + 35, + 90, + 62, + 254, + 166, + 105, + 49, + 23, + 146, + 87, + 114, + 113, + 200, + 11, + 138, + 54, + 76, + 198, + 190, + 93, + 69, + 76, + 186, + 219, + 57, + 93, + 173, + 211, + 41, + 220, + 41, + 141, + 109, + 147, + 218, + 42, + 23, + 21, + 141, + 219, + 53, + 113, + 65, + 241, + 199, + 62, + 140, + 150, + 171, + 199, + 214, + 146, + 204, + 44, + 45, + 74, + 140, + 194, + 96, + 249, + 227, + 40, + 20, + 17, + 84, + 212, + 240, + 75, + 175, + 63, + 88, + 122, + 242, + 148, + 144, + 1, + 151, + 166, + 149, + 241, + 168, + 254, + 21, + 220, + 58, + 90, + 123, + 18, + 215, + 220, + 42, + 82, + 153, + 31, + 219, + 205, + 55, + 102, + 82, + 14, + 142, + 72, + 6, + 115, + 167, + 45, + 20, + 24, + 169, + 127, + 188, + 208, + 162, + 96, + 223, + 61, + 174, + 74, + 224, + 26, + 222, + 19, + 255, + 20, + 76, + 204, + 25, + 57, + 106, + 28, + 87, + 69, + 151, + 143, + 221, + 236, + 144, + 35, + 107, + 68, + 248, + 54, + 141, + 20, + 53, + 120, + 182, + 232, + 218, + 170, + 222, + 11, + 222, + 52, + 98, + 69, + 212, + 189, + 153, + 190, + 53, + 1, + 77, + 129, + 235, + 17, + 236, + 73, + 133, + 62, + 43, + 111, + 9, + 212, + 188, + 198, + 246, + 51, + 30, + 79, + 179, + 7, + 7, + 169, + 72, + 240, + 208, + 71, + 221, + 70, + 142, + 170, + 10, + 177, + 250, + 182, + 61, + 70, + 24, + 1, + 46, + 202, + 225, + 245, + 116, + 121, + 101, + 36, + 32, + 243, + 28, + 119, + 26, + 251, + 227, + 87, + 99, + 75, + 46, + 81, + 152, + 98, + 221, + 20, + 113, + 177, + 236, + 240, + 243, + 32, + 196, + 179, + 13, + 129, + 7, + 63, + 201, + 90, + 175, + 205, + 230, + 79, + 141, + 5, + 79, + 77, + 53, + 160, + 18, + 98, + 102, + 206, + 225, + 61, + 177, + 14, + 83, + 66, + 209, + 165, + 10, + 113, + 42, + 192, + 206, + 197, + 233, + 131, + 154, + 240, + 178, + 9, + 20, + 10, + 233, + 134, + 203, + 87, + 89, + 179, + 175, + 47, + 47, + 202, + 219, + 81, + 79, + 138, + 12, + 246, + 252, + 195, + 56, + 17, + 198, + 76, + 96, + 34, + 160, + 93, + 41, + 235, + 98, + 55, + 55, + 215, + 121, + 210, + 83, + 188, + 64, + 167, + 237, + 248, + 234, + 120, + 127, + 65, + 1, + 95, + 14, + 121, + 80, + 27, + 33, + 138, + 244, + 36, + 227, + 10, + 201, + 47, + 113, + 252, + 84, + 160, + 133, + 51, + 221, + 38, + 103, + 65, + 23, + 150, + 59, + 55, + 48, + 168, + 182, + 205, + 222, + 245, + 25, + 26, + 1, + 48, + 140, + 26, + 73, + 21, + 5, + 231, + 54, + 34, + 71, + 44, + 227, + 181, + 210, + 147, + 139, + 227, + 32, + 12, + 248, + 236, + 51, + 203, + 189, + 233, + 246, + 204, + 39, + 73, + 88, + 100, + 122, + 115, + 149, + 55, + 55, + 47, + 140, + 26, + 177, + 144, + 209, + 20, + 13, + 191, + 222, + 199, + 235, + 174, + 6, + 209, + 218, + 84, + 56, + 204, + 44, + 5, + 119, + 100, + 159, + 190, + 61, + 232, + 143, + 115, + 46, + 49, + 160, + 228, + 217, + 14, + 69, + 14, + 24, + 224, + 86, + 94, + 62, + 200, + 79, + 14, + 131, + 30, + 125, + 189, + 57, + 164, + 18, + 2, + 91, + 123, + 225, + 56, + 5, + 130, + 178, + 48, + 141, + 171, + 73, + 160, + 11, + 225, + 79, + 29, + 22, + 241, + 122, + 229, + 60, + 34, + 33, + 241, + 14, + 149, + 151, + 231, + 231, + 50, + 37, + 113, + 241, + 120, + 181, + 175, + 80, + 186, + 109, + 115, + 116, + 154, + 140, + 122, + 162, + 149, + 242, + 113, + 107, + 61, + 118, + 0, + 72, + 230, + 231, + 106, + 230, + 90, + 202, + 195, + 59, + 248, + 12, + 184, + 232, + 220, + 113, + 12, + 19, + 175, + 195, + 210, + 251, + 32, + 30, + 37, + 185, + 129, + 122, + 23, + 252, + 45, + 233, + 192, + 234, + 181, + 55, + 176, + 49, + 13, + 10, + 186, + 115, + 57, + 189, + 173, + 135, + 146, + 201, + 94, + 23, + 121, + 38, + 143, + 146, + 186, + 220, + 209, + 176, + 51, + 171, + 253, + 213, + 26, + 66, + 32, + 44, + 174, + 22, + 134, + 100, + 19, + 28, + 116, + 173, + 62, + 2, + 83, + 123, + 124, + 46, + 141, + 44, + 133, + 170, + 244, + 111, + 11, + 166, + 146, + 143, + 197, + 25, + 5, + 42, + 151, + 26, + 7, + 116, + 81, + 41, + 58, + 60, + 201, + 88, + 150, + 103, + 188, + 24, + 231, + 194, + 184, + 218, + 48, + 26, + 228, + 6, + 66, + 246, + 151, + 235, + 168, + 129, + 31, + 186, + 103, + 215, + 43, + 97, + 52, + 99, + 14, + 48, + 94, + 84, + 189, + 107, + 193, + 168, + 253, + 230, + 232, + 109, + 78, + 88, + 184, + 105, + 132, + 106, + 239, + 173, + 144, + 27, + 4, + 22, + 37, + 217, + 114, + 183, + 228, + 13, + 155, + 169, + 200, + 166, + 196, + 246, + 181, + 74, + 96, + 181, + 21, + 201, + 61, + 88, + 49, + 33, + 220, + 22, + 102, + 112, + 246, + 152, + 141, + 174, + 188, + 110, + 138, + 254, + 10, + 6, + 170, + 130, + 39, + 7, + 117, + 137, + 234, + 248, + 110, + 99, + 15, + 44, + 111, + 123, + 108, + 126, + 70, + 20, + 100, + 3, + 129, + 88, + 165, + 7, + 224, + 240, + 251, + 177, + 35, + 75, + 98, + 107, + 106, + 40, + 0, + 104, + 82, + 161, + 166, + 151, + 226, + 146, + 187, + 2, + 63, + 8, + 46, + 154, + 127, + 30, + 218, + 19, + 113, + 24, + 135, + 235, + 185, + 120, + 159, + 26, + 175, + 222, + 233, + 77, + 44, + 188, + 177, + 78, + 165, + 219, + 28, + 178, + 227, + 148, + 215, + 99, + 166, + 235, + 184, + 68, + 196, + 173, + 153, + 113, + 104, + 26, + 86, + 212, + 240, + 215, + 147, + 82, + 109, + 249, + 65, + 72, + 91, + 153, + 59, + 159, + 190, + 127, + 246, + 149, + 115, + 248, + 85, + 70, + 183, + 182, + 118, + 28, + 79, + 175, + 129, + 43, + 153, + 192, + 39, + 173, + 251, + 7, + 168, + 60, + 94, + 225, + 217, + 136, + 163, + 181, + 160, + 135, + 176, + 34, + 52, + 142, + 222, + 108, + 82, + 135, + 148, + 93, + 50, + 7, + 185, + 207, + 62, + 74, + 57, + 196, + 244, + 127, + 177, + 207, + 245, + 88, + 207, + 201, + 35, + 211, + 179, + 186, + 156, + 173, + 210, + 184, + 169, + 215, + 129, + 39, + 118, + 124, + 148, + 39, + 146, + 18, + 7, + 154, + 39, + 57, + 246, + 173, + 144, + 49, + 143, + 202, + 175, + 42, + 114, + 61, + 133, + 27, + 194, + 10, + 205, + 203, + 49, + 231, + 15, + 237, + 58, + 99, + 103, + 139, + 15, + 144, + 103, + 4, + 1, + 88, + 41, + 37, + 122, + 89, + 41, + 199, + 139, + 209, + 173, + 155, + 41, + 59, + 69, + 75, + 212, + 188, + 36, + 78, + 232, + 174, + 119, + 243, + 163, + 36, + 219, + 115, + 169, + 180, + 181, + 113, + 45, + 119, + 106, + 21, + 104, + 203, + 21, + 82, + 95, + 218, + 129, + 128, + 112, + 186, + 29, + 64, + 121, + 154, + 71, + 241, + 195, + 177, + 145, + 33, + 104, + 202, + 246, + 224, + 153, + 164, + 225, + 99, + 88, + 106, + 112, + 115, + 114, + 21, + 192, + 147, + 108, + 49, + 118, + 196, + 171, + 98, + 88, + 253, + 87, + 245, + 105, + 116, + 237, + 255, + 178, + 174, + 255, + 38, + 146, + 249, + 183, + 25, + 85, + 52, + 47, + 229, + 48, + 25, + 5, + 221, + 0, + 69, + 163, + 239, + 203, + 136, + 185, + 150, + 123, + 210, + 34, + 85, + 219, + 105, + 161, + 162, + 181, + 86, + 26, + 70, + 20, + 11, + 71, + 128, + 31, + 164, + 170, + 98, + 190, + 12, + 135, + 197, + 46, + 38, + 213, + 196, + 53, + 205, + 108, + 234, + 30, + 37, + 88, + 22, + 181, + 15, + 71, + 121, + 154, + 32, + 217, + 195, + 203, + 69, + 180, + 128, + 252, + 204, + 147, + 208, + 248, + 95, + 219, + 228, + 190, + 176, + 102, + 217, + 203, + 126, + 219, + 16, + 42, + 71, + 119, + 173, + 15, + 55, + 198, + 83, + 201, + 73, + 43, + 127, + 21, + 185, + 174, + 85, + 64, + 181, + 51, + 122, + 232, + 107, + 59, + 228, + 72, + 113, + 174, + 81, + 19, + 25, + 13, + 18, + 208, + 180, + 4, + 201, + 112, + 139, + 0, + 48, + 104, + 136, + 241, + 245, + 245, + 178, + 234, + 243, + 225, + 152, + 186, + 22, + 87, + 113, + 230, + 98, + 53, + 98, + 86, + 88, + 75, + 163, + 115, + 164, + 173, + 70, + 73, + 85, + 102, + 41, + 206, + 184, + 145, + 148, + 69, + 105, + 10, + 112, + 68, + 211, + 231, + 183, + 160, + 6, + 123, + 94, + 122, + 202, + 78, + 228, + 123, + 122, + 20, + 189, + 247, + 64, + 59, + 239, + 32, + 66, + 166, + 176, + 188, + 81, + 148, + 4, + 131, + 49, + 129, + 135, + 83, + 153, + 54, + 93, + 90, + 123, + 154, + 60, + 107, + 208, + 25, + 97, + 212, + 139, + 221, + 141, + 250, + 96, + 158, + 71, + 89, + 48, + 101, + 227, + 212, + 63, + 96, + 36, + 171, + 207, + 152, + 42, + 104, + 250, + 145, + 52, + 163, + 215, + 49, + 49, + 60, + 6, + 28, + 106, + 171, + 138, + 222, + 224, + 55, + 127, + 67, + 235, + 89, + 247, + 231, + 19, + 67, + 56, + 190, + 60, + 210, + 239, + 49, + 52, + 226, + 67, + 52, + 241, + 172, + 48, + 130, + 75, + 51, + 123, + 122, + 248, + 7, + 71, + 57, + 195, + 146, + 18, + 244, + 41, + 249, + 177, + 95, + 33, + 75, + 96, + 29, + 138, + 31, + 120, + 138, + 49, + 1, + 117, + 65, + 226, + 180, + 186, + 206, + 78, + 53, + 170, + 166, + 214, + 34, + 4, + 182, + 205, + 64, + 136, + 140, + 145, + 217, + 91, + 158, + 142, + 250, + 235, + 189, + 160, + 122, + 196, + 112, + 57, + 186, + 193, + 234, + 23, + 110, + 44, + 183, + 26, + 13, + 20, + 221, + 120, + 98, + 177, + 254, + 229, + 224, + 152, + 185, + 197, + 7, + 9, + 129, + 255, + 50, + 241, + 70, + 178, + 152, + 203, + 248, + 171, + 51, + 154, + 195, + 9, + 30, + 88, + 245, + 48, + 123, + 156, + 58, + 130, + 67, + 255, + 217, + 155, + 173, + 111, + 239, + 69, + 180, + 208, + 64, + 235, + 44, + 60, + 81, + 72, + 253, + 184, + 214, + 137, + 195, + 160, + 240, + 225, + 89, + 96, + 170, + 71, + 50, + 210, + 143, + 108, + 25, + 99, + 223, + 214, + 162, + 68, + 216, + 121, + 105, + 47, + 229, + 91, + 84, + 27, + 193, + 213, + 12, + 97, + 38, + 202, + 67, + 185, + 233, + 48, + 68, + 133, + 152, + 59, + 175, + 127, + 178, + 77, + 208, + 26, + 37, + 222, + 150, + 229, + 254, + 55, + 161, + 14, + 48, + 103, + 73, + 254, + 213, + 136, + 76, + 14, + 51, + 162, + 119, + 153, + 72, + 7, + 176, + 229, + 233, + 0, + 98, + 103, + 255, + 244, + 171, + 244, + 141, + 25, + 79, + 171, + 144, + 195, + 223, + 23, + 186, + 244, + 5, + 98, + 38, + 147, + 241, + 181, + 20, + 167, + 151, + 187, + 115, + 109, + 5, + 124, + 243, + 31, + 127, + 199, + 150, + 28, + 201, + 184, + 161, + 254, + 144, + 123, + 101, + 32, + 31, + 124, + 116, + 36, + 105, + 30, + 50, + 45, + 221, + 246, + 248, + 20, + 246, + 148, + 192, + 158, + 126, + 237, + 172, + 112, + 85, + 53, + 184, + 247, + 23, + 53, + 145, + 159, + 104, + 249, + 134, + 237, + 66, + 77, + 192, + 0, + 172, + 127, + 180, + 91, + 109, + 212, + 67, + 48, + 79, + 122, + 85, + 173, + 82, + 71, + 75, + 113, + 195, + 78, + 175, + 49, + 217, + 86, + 141, + 207, + 103, + 123, + 6, + 200, + 134, + 171, + 86, + 102, + 140, + 222, + 104, + 209, + 22, + 57, + 12, + 75, + 169, + 202, + 228, + 69, + 50, + 77, + 164, + 37, + 219, + 83, + 58, + 196, + 167, + 193, + 121, + 145, + 191, + 151, + 174, + 184, + 226, + 128, + 246, + 97, + 247, + 255, + 7, + 57, + 162, + 193, + 10, + 164, + 40, + 194, + 21, + 82, + 64, + 115, + 83, + 19, + 33, + 50, + 147, + 40, + 78, + 137, + 213, + 96, + 186, + 49, + 104, + 38, + 97, + 214, + 206, + 40, + 212, + 53, + 217, + 44, + 36, + 38, + 178, + 199, + 254, + 236, + 132, + 220, + 251, + 74, + 23, + 7, + 155, + 244, + 51, + 169, + 67, + 160, + 240, + 40, + 166, + 224, + 95, + 37, + 38, + 18, + 106, + 236, + 102, + 223, + 183, + 7, + 89, + 113, + 33, + 4, + 247, + 173, + 134, + 99, + 164, + 223, + 146, + 18, + 252, + 59, + 84, + 89, + 202, + 8, + 243, + 61, + 63, + 209, + 21, + 228, + 250, + 10, + 186, + 151, + 206, + 53, + 179, + 75, + 163, + 10, + 4, + 24, + 218, + 55, + 120, + 74, + 116, + 161, + 159, + 8, + 62, + 202, + 164, + 141, + 211, + 87, + 199, + 33, + 71, + 241, + 77, + 11, + 136, + 26, + 70, + 160, + 132, + 70, + 153, + 80, + 203, + 188, + 122, + 141, + 212, + 2, + 56, + 162, + 196, + 112, + 118, + 12, + 125, + 166, + 31, + 189, + 127, + 67, + 174, + 191, + 61, + 202, + 12, + 199, + 91, + 41, + 251, + 135, + 74, + 171, + 18, + 236, + 78, + 248, + 160, + 236, + 229, + 79, + 60, + 8, + 114, + 107, + 123, + 43, + 252, + 242, + 50, + 4, + 199, + 59, + 98, + 71, + 144, + 151, + 153, + 14, + 135, + 53, + 144, + 108, + 217, + 130, + 136, + 169, + 80, + 160, + 234, + 192, + 175, + 146, + 229, + 25, + 86, + 233, + 86, + 68, + 99, + 236, + 28, + 40, + 24, + 88, + 66, + 246, + 42, + 18, + 76, + 8, + 129, + 186, + 51, + 140, + 17, + 106, + 114, + 97, + 182, + 222, + 180, + 36, + 63, + 108, + 131, + 125, + 86, + 0, + 230, + 93, + 245, + 33, + 30, + 105, + 18, + 192, + 136, + 119, + 5, + 207, + 117, + 67, + 72, + 24, + 155, + 84, + 174, + 160, + 211, + 133, + 72, + 52, + 47, + 41, + 189, + 149, + 112, + 86, + 36, + 250, + 90, + 13, + 155, + 143, + 200, + 198, + 226, + 187, + 88, + 192, + 156, + 32, + 205, + 62, + 103, + 0, + 20, + 114, + 70, + 86, + 194, + 205, + 12, + 52, + 121, + 160, + 130, + 229, + 2, + 105, + 202, + 172, + 176, + 84, + 221, + 5, + 134, + 207, + 173, + 124, + 124, + 161, + 26, + 109, + 15, + 118, + 166, + 155, + 54, + 219, + 232, + 13, + 179, + 74, + 36, + 153, + 102, + 7, + 142, + 212, + 216, + 104, + 54, + 22, + 26, + 62, + 104, + 188, + 207, + 171, + 246, + 0, + 181, + 177, + 25, + 122, + 140, + 170, + 96, + 240, + 205, + 117, + 249, + 124, + 77, + 150, + 168, + 230, + 93, + 77, + 83, + 6, + 128, + 147, + 226, + 40, + 56, + 63, + 100, + 115, + 221, + 213, + 44, + 44, + 21, + 107, + 182, + 93, + 2, + 220, + 36, + 81, + 16, + 183, + 198, + 29, + 126, + 210, + 245, + 71, + 143, + 44, + 46, + 220, + 200, + 148, + 246, + 19, + 85, + 20, + 70, + 150, + 9, + 188, + 169, + 60, + 77, + 66, + 4, + 189, + 5, + 119, + 226, + 70, + 187, + 144, + 237, + 34, + 78, + 200, + 249, + 72, + 213, + 117, + 231, + 160, + 91, + 195, + 206, + 95, + 73, + 27, + 157, + 183, + 19, + 51, + 7, + 53, + 2, + 82, + 251, + 4, + 47, + 233, + 187, + 223, + 2, + 19, + 218, + 5, + 138, + 224, + 219, + 117, + 173, + 156, + 9, + 220, + 159, + 112, + 4, + 148, + 146, + 80, + 160, + 170, + 175, + 251, + 203, + 165, + 113, + 165, + 191, + 42, + 251, + 151, + 147, + 165, + 65, + 65, + 147, + 123, + 77, + 196, + 36, + 160, + 205, + 73, + 193, + 136, + 186, + 177, + 191, + 142, + 8, + 49, + 202, + 144, + 189, + 216, + 1, + 160, + 186, + 127, + 114, + 180, + 200, + 96, + 129, + 18, + 179, + 46, + 17, + 234, + 30, + 79, + 54, + 254, + 29, + 11, + 66, + 188, + 207, + 178, + 56, + 66, + 245, + 88, + 254, + 184, + 218, + 98, + 191, + 173, + 235, + 101, + 125, + 229, + 199, + 52, + 160, + 206, + 32, + 48, + 157, + 240, + 28, + 174, + 115, + 112, + 104, + 216, + 38, + 241, + 22, + 129, + 102, + 69, + 247, + 15, + 4, + 58, + 202, + 128, + 76, + 131, + 150, + 12, + 202, + 194, + 18, + 112, + 127, + 128, + 27, + 216, + 163, + 250, + 92, + 201, + 198, + 162, + 235, + 133, + 180, + 132, + 122, + 39, + 150, + 192, + 3, + 111, + 246, + 53, + 128, + 168, + 52, + 44, + 221, + 36, + 126, + 132, + 92, + 31, + 170, + 91, + 10, + 30, + 135, + 51, + 220, + 175, + 20, + 223, + 19, + 68, + 96, + 67, + 121, + 106, + 114, + 76, + 68, + 94, + 200, + 174, + 117, + 57, + 114, + 127, + 137, + 195, + 22, + 36, + 183, + 87, + 235, + 12, + 108, + 137, + 106, + 45, + 231, + 223, + 97, + 124, + 204, + 133, + 245, + 67, + 231, + 82, + 181, + 75, + 177, + 53, + 51, + 194, + 219, + 103, + 218, + 238, + 162, + 156, + 61, + 185, + 41, + 85, + 69, + 110, + 233, + 94, + 188, + 49, + 85, + 202, + 105, + 23, + 180, + 64, + 3, + 247, + 156, + 29, + 63, + 186, + 135, + 112, + 152, + 249, + 109, + 232, + 37, + 102, + 209, + 23, + 49, + 246, + 182, + 160, + 24, + 173, + 67, + 218, + 101, + 181, + 135, + 107, + 230, + 55, + 128, + 218, + 71, + 217, + 91, + 35, + 98, + 166, + 33, + 74, + 4, + 110, + 13, + 73, + 4, + 202, + 233, + 107, + 151, + 26, + 41, + 27, + 43, + 189, + 21, + 190, + 27, + 148, + 58, + 194, + 14, + 209, + 201, + 197, + 144, + 220, + 33, + 130, + 145, + 109, + 36, + 40, + 139, + 111, + 38, + 82, + 189, + 139, + 190, + 13, + 66, + 75, + 161, + 16, + 52, + 204, + 7, + 249, + 254, + 201, + 252, + 236, + 189, + 11, + 1, + 159, + 215, + 30, + 60, + 177, + 147, + 5, + 76, + 8, + 132, + 141, + 191, + 117, + 64, + 159, + 231, + 52, + 164, + 138, + 99, + 46, + 150, + 21, + 19, + 244, + 248, + 7, + 55, + 145, + 9, + 64, + 52, + 187, + 210, + 125, + 225, + 12, + 189, + 18, + 51, + 0, + 119, + 173, + 238, + 0, + 247, + 67, + 60, + 247, + 237, + 124, + 179, + 40, + 226, + 104, + 236, + 109, + 239, + 179, + 215, + 57, + 247, + 25, + 139, + 122, + 118, + 11, + 208, + 249, + 93, + 206, + 57, + 65, + 137, + 224, + 34, + 107, + 250, + 229, + 63, + 80, + 22, + 254, + 113, + 88, + 154, + 53, + 1, + 116, + 163, + 128, + 185, + 168, + 133, + 154, + 168, + 162, + 168, + 196, + 91, + 124, + 207, + 11, + 192, + 42, + 68, + 145, + 27, + 194, + 60, + 76, + 239, + 81, + 131, + 179, + 123, + 82, + 255, + 204, + 116, + 168, + 219, + 54, + 244, + 51, + 16, + 73, + 142, + 108, + 227, + 89, + 203, + 145, + 187, + 143, + 241, + 31, + 233, + 226, + 210, + 164, + 244, + 16, + 25, + 123, + 201, + 112, + 33, + 74, + 30, + 221, + 251, + 79, + 93, + 10, + 169, + 26, + 198, + 82, + 45, + 52, + 149, + 90, + 24, + 71, + 56, + 127, + 210, + 12, + 182, + 244, + 194, + 109, + 198, + 63, + 126, + 243, + 129, + 155, + 75, + 30, + 99, + 96, + 98, + 5, + 71, + 191, + 126, + 83, + 123, + 84, + 195, + 110, + 106, + 151, + 225, + 116, + 74, + 4, + 250, + 31, + 126, + 207, + 122, + 122, + 57, + 252, + 12, + 221, + 190, + 37, + 26, + 45, + 92, + 173, + 56, + 49, + 1, + 122, + 135, + 205, + 182, + 142, + 240, + 177, + 164, + 31, + 125, + 175, + 163, + 123, + 42, + 112, + 36, + 107, + 239, + 40, + 42, + 85, + 221, + 38, + 245, + 223, + 57, + 219, + 236, + 113, + 53, + 1, + 154, + 0, + 128, + 135, + 111, + 248, + 161, + 90, + 142, + 92, + 185, + 225, + 86, + 92, + 228, + 18, + 203, + 21, + 121, + 21, + 177, + 148, + 68, + 84, + 20, + 117, + 4, + 215, + 85, + 219, + 101, + 182, + 70, + 113, + 150, + 81, + 49, + 53, + 16, + 3, + 92, + 43, + 171, + 208, + 215, + 74, + 7, + 100, + 208, + 219, + 133, + 46, + 29, + 121, + 159, + 90, + 74, + 160, + 131, + 82, + 126, + 117, + 202, + 203, + 48, + 101, + 25, + 225, + 6, + 141, + 101, + 33, + 3, + 91, + 191, + 4, + 55, + 82, + 178, + 31, + 89, + 28, + 168, + 6, + 23, + 138, + 222, + 213, + 52, + 148, + 208, + 128, + 253, + 2, + 245, + 109, + 227, + 59, + 179, + 207, + 11, + 166, + 124, + 66, + 221, + 181, + 80, + 40, + 238, + 58, + 145, + 102, + 105, + 76, + 19, + 219, + 30, + 158, + 208, + 233, + 77, + 194, + 79, + 151, + 75, + 110, + 205, + 250, + 76, + 109, + 212, + 216, + 112, + 114, + 136, + 110, + 128, + 23, + 39, + 68, + 202, + 40, + 254, + 95, + 6, + 180, + 202, + 18, + 28, + 192, + 35, + 200, + 44, + 33, + 198, + 38, + 181, + 120, + 249, + 176, + 169, + 7, + 166, + 73, + 33, + 202, + 173, + 146, + 179, + 46, + 92, + 109, + 107, + 117, + 68, + 62, + 163, + 128, + 167, + 189, + 63, + 72, + 139, + 154, + 51, + 110, + 157, + 216, + 193, + 43, + 108, + 90, + 69, + 135, + 96, + 38, + 74, + 22, + 187, + 254, + 168, + 76, + 128, + 121, + 255, + 167, + 101, + 47, + 137, + 153, + 91, + 72, + 127, + 199, + 59, + 230, + 192, + 147, + 78, + 206, + 58, + 204, + 76, + 182, + 162, + 186, + 157, + 46, + 162, + 236, + 40, + 27, + 18, + 150, + 174, + 61, + 94, + 122, + 210, + 9, + 251, + 8, + 12, + 132, + 212, + 206, + 254, + 83, + 45, + 39, + 255, + 80, + 38, + 199, + 208, + 121, + 79, + 99, + 65, + 192, + 206, + 118, + 34, + 30, + 191, + 146, + 170, + 180, + 112, + 66, + 150, + 48, + 228, + 40, + 124, + 209, + 25, + 208, + 169, + 79, + 0, + 203, + 58, + 71, + 248, + 1, + 20, + 0, + 102, + 246, + 23, + 178, + 27, + 127, + 39, + 85, + 84, + 101, + 128, + 124, + 196, + 194, + 195, + 98, + 209, + 94, + 36, + 70, + 90, + 158, + 119, + 153, + 56, + 226, + 90, + 8, + 193, + 242, + 183, + 255, + 166, + 62, + 11, + 160, + 112, + 221, + 137, + 4, + 190, + 148, + 194, + 36, + 110, + 153, + 73, + 21, + 210, + 164, + 14, + 157, + 225, + 9, + 153, + 150, + 124, + 245, + 144, + 206, + 98, + 27, + 111, + 15, + 177, + 173, + 219, + 162, + 40, + 205, + 231, + 128, + 174, + 35, + 169, + 149, + 182, + 27, + 17, + 30, + 56, + 51, + 161, + 132, + 61, + 223, + 217, + 88, + 72, + 215, + 163, + 190, + 196, + 104, + 50, + 124, + 179, + 26, + 73, + 223, + 216, + 160, + 138, + 84, + 233, + 19, + 25, + 223, + 228, + 50, + 3, + 101, + 244, + 165, + 0, + 174, + 136, + 195, + 221, + 68, + 17, + 241, + 173, + 254, + 63, + 86, + 169, + 61, + 249, + 92, + 167, + 80, + 127, + 206, + 243, + 44, + 66, + 228, + 202, + 221, + 96, + 124, + 197, + 97, + 218, + 231, + 30, + 12, + 157, + 214, + 205, + 220, + 93, + 247, + 208, + 163, + 211, + 41, + 144, + 55, + 235, + 97, + 70, + 102, + 166, + 144, + 171, + 201, + 6, + 71, + 20, + 60, + 123, + 37, + 143, + 18, + 172, + 209, + 145, + 67, + 138, + 77, + 197, + 227, + 201, + 167, + 63, + 243, + 79, + 210, + 158, + 112, + 130, + 174, + 148, + 154, + 122, + 230, + 138, + 49, + 17, + 153, + 113, + 88, + 125, + 97, + 127, + 109, + 22, + 10, + 218, + 214, + 39, + 44, + 196, + 160, + 104, + 88, + 9, + 236, + 188, + 174, + 246, + 158, + 129, + 202, + 83, + 217, + 184, + 210, + 134, + 36, + 128, + 81, + 47, + 103, + 179, + 149, + 27, + 113, + 226, + 194, + 43, + 150, + 135, + 168, + 82, + 91, + 9, + 200, + 207, + 131, + 56, + 31, + 53, + 162, + 205, + 149, + 131, + 91, + 62, + 185, + 99, + 101, + 242, + 127, + 95, + 167, + 232, + 130, + 235, + 79, + 182, + 77, + 212, + 178, + 241, + 103, + 165, + 185, + 21, + 222, + 59, + 17, + 11, + 254, + 87, + 163, + 156, + 148, + 166, + 184, + 3, + 240, + 131, + 86, + 90, + 130, + 28, + 119, + 43, + 244, + 224, + 36, + 59, + 33, + 103, + 217, + 16, + 129, + 161, + 0, + 191, + 141, + 122, + 158, + 137, + 142, + 105, + 89, + 173, + 75, + 66, + 228, + 244, + 115, + 123, + 138, + 199, + 153, + 68, + 206, + 254, + 64, + 66, + 44, + 112, + 108, + 249, + 112, + 0, + 80, + 251, + 201, + 26, + 220, + 31, + 82, + 214, + 169, + 2, + 246, + 12, + 220, + 227, + 189, + 213, + 235, + 213, + 92, + 246, + 160, + 140, + 55, + 249, + 40, + 240, + 87, + 3, + 52, + 232, + 156, + 21, + 16, + 148, + 149, + 213, + 140, + 84, + 155, + 184, + 108, + 130, + 113, + 126, + 30, + 178, + 228, + 173, + 164, + 180, + 160, + 236, + 157, + 211, + 50, + 68, + 52, + 36, + 4, + 127, + 56, + 233, + 216, + 53, + 155, + 36, + 241, + 134, + 63, + 100, + 61, + 23, + 64, + 171, + 187, + 107, + 69, + 101, + 141, + 35, + 246, + 68, + 177, + 177, + 173, + 76, + 16, + 197, + 196, + 27, + 63, + 64, + 197, + 253, + 86, + 235, + 102, + 190, + 215, + 80, + 94, + 163, + 232, + 89, + 242, + 5, + 6, + 234, + 134, + 115, + 129, + 252, + 93, + 164, + 149, + 64, + 156, + 241, + 166, + 182, + 189, + 171, + 49, + 170, + 33, + 4, + 15, + 106, + 225, + 232, + 94, + 232, + 170, + 88, + 103, + 42, + 66, + 71, + 108, + 175, + 165, + 12, + 203, + 232, + 191, + 154, + 163, + 76, + 118, + 167, + 158, + 80, + 235, + 166, + 89, + 234, + 88, + 19, + 73, + 48, + 106, + 149, + 48, + 131, + 64, + 134, + 84, + 139, + 135, + 180, + 186, + 199, + 171, + 73, + 168, + 27, + 217, + 243, + 129, + 212, + 255, + 255, + 82, + 119, + 9, + 43, + 103, + 101, + 251, + 64, + 238, + 57, + 224, + 103, + 231, + 219, + 10, + 243, + 23, + 150, + 217, + 40, + 13, + 204, + 9, + 81, + 252, + 110, + 78, + 77, + 245, + 129, + 193, + 171, + 30, + 103, + 37, + 212, + 75, + 122, + 45, + 101, + 232, + 118, + 149, + 149, + 43, + 33, + 54, + 188, + 193, + 203, + 105, + 110, + 33, + 30, + 141, + 227, + 167, + 222, + 16, + 47, + 255, + 155, + 220, + 175, + 151, + 253, + 95, + 254, + 98, + 182, + 19, + 143, + 245, + 126, + 201, + 211, + 96, + 182, + 46, + 201, + 215, + 226, + 197, + 93, + 67, + 16, + 35, + 148, + 126, + 24, + 12, + 192, + 5, + 73, + 59, + 171, + 31, + 107, + 249, + 5, + 61, + 77, + 92, + 238, + 214, + 228, + 3, + 191, + 40, + 185, + 108, + 244, + 251, + 171, + 117, + 115, + 70, + 49, + 45, + 132, + 66, + 201, + 231, + 196, + 247, + 117, + 75, + 22, + 32, + 126, + 233, + 137, + 66, + 105, + 251, + 130, + 96, + 175, + 103, + 195, + 141, + 12, + 123, + 16, + 162, + 19, + 230, + 251, + 249, + 243, + 92, + 48, + 102, + 85, + 139, + 211, + 130, + 203, + 106, + 0, + 191, + 106, + 111, + 231, + 110, + 55, + 208, + 101, + 4, + 46, + 228, + 23, + 144, + 241, + 2, + 113, + 60, + 8, + 132, + 165, + 253, + 23, + 102, + 93, + 135, + 188, + 187, + 126, + 52, + 137, + 64, + 50, + 153, + 90, + 121, + 183, + 43, + 161, + 41, + 21, + 2, + 103, + 13, + 215, + 173, + 240, + 149, + 84, + 250, + 11, + 90, + 151, + 61, + 105, + 99, + 31, + 143, + 254, + 101, + 179, + 164, + 192, + 131, + 233, + 146, + 1, + 77, + 96, + 45, + 93, + 242, + 90, + 141, + 169, + 55, + 86, + 171, + 228, + 78, + 203, + 3, + 137, + 229, + 42, + 226, + 96, + 190, + 174, + 234, + 139, + 216, + 97, + 164, + 119, + 128, + 61, + 238, + 168, + 27, + 249, + 3, + 111, + 96, + 93, + 78, + 23, + 225, + 221, + 81, + 35, + 107, + 172, + 185, + 20, + 182, + 150, + 43, + 204, + 136, + 90, + 197, + 169, + 205, + 213, + 158, + 148, + 176, + 26, + 236, + 141, + 64, + 43, + 80, + 140, + 101, + 45, + 182, + 104, + 60, + 76, + 51, + 49, + 53, + 85, + 66, + 56, + 104, + 13, + 100, + 67, + 51, + 145, + 127, + 140, + 157, + 249, + 100, + 36, + 195, + 82, + 64, + 56, + 26, + 77, + 112, + 205, + 218, + 103, + 12, + 232, + 176, + 198, + 61, + 47, + 247, + 111, + 211, + 48, + 248, + 154, + 230, + 78, + 8, + 63, + 120, + 241, + 121, + 130, + 43, + 206, + 19, + 246, + 169, + 94, + 253, + 60, + 40, + 254, + 200, + 23, + 24, + 151, + 130, + 45, + 149, + 9, + 112, + 186, + 121, + 42, + 60, + 81, + 41, + 206, + 31, + 157, + 50, + 199, + 58, + 10, + 217, + 153, + 74, + 194, + 186, + 120, + 238, + 81, + 13, + 206, + 84, + 17, + 39, + 202, + 56, + 126, + 173, + 4, + 141, + 247, + 238, + 101, + 153, + 195, + 157, + 175, + 115, + 138, + 171, + 35, + 158, + 126, + 41, + 134, + 255, + 29, + 30, + 0, + 54, + 8, + 59, + 178, + 17, + 219, + 129, + 2, + 94, + 67, + 130, + 75, + 139, + 198, + 159, + 113, + 224, + 249, + 143, + 202, + 248, + 194, + 194, + 26, + 101, + 139, + 29, + 89, + 157, + 247, + 209, + 141, + 207, + 33, + 70, + 29, + 136, + 249, + 225, + 46, + 191, + 86, + 25, + 105, + 51, + 205, + 48, + 139, + 245, + 84, + 117, + 100, + 35, + 197, + 29, + 89, + 53, + 53, + 9, + 191, + 93, + 67, + 218, + 112, + 207, + 221, + 25, + 222, + 152, + 3, + 30, + 38, + 190, + 213, + 32, + 172, + 58, + 189, + 167, + 74, + 246, + 236, + 24, + 215, + 63, + 13, + 132, + 2, + 155, + 13, + 153, + 8, + 255, + 193, + 6, + 150, + 55, + 156, + 38, + 7, + 254, + 244, + 77, + 244, + 88, + 96, + 134, + 209, + 180, + 91, + 250, + 11, + 62, + 136, + 224, + 142, + 27, + 98, + 241, + 220, + 42, + 1, + 36, + 85, + 27, + 92, + 148, + 237, + 248, + 112, + 59, + 210, + 83, + 128, + 230, + 10, + 114, + 59, + 37, + 41, + 72, + 221, + 1, + 212, + 194, + 42, + 31, + 104, + 46, + 115, + 6, + 119, + 129, + 39, + 94, + 228, + 178, + 184, + 196, + 201, + 206, + 132, + 42, + 140, + 92, + 106, + 132, + 6, + 26, + 16, + 140, + 202, + 222, + 242, + 196, + 139, + 101, + 143, + 32, + 181, + 7, + 65, + 194, + 137, + 71, + 143, + 157, + 17, + 102, + 156, + 165, + 53, + 220, + 205, + 48, + 254, + 122, + 209, + 79, + 204, + 218, + 203, + 220, + 112, + 150, + 232, + 75, + 155, + 80, + 210, + 89, + 114, + 245, + 216, + 2, + 238, + 242, + 121, + 8, + 243, + 40, + 12, + 180, + 24, + 237, + 79, + 77, + 184, + 70, + 154, + 143, + 112, + 98, + 132, + 102, + 20, + 237, + 109, + 201, + 3, + 20, + 44, + 129, + 5, + 112, + 60, + 136, + 192, + 81, + 26, + 99, + 232, + 106, + 198, + 24, + 85, + 227, + 100, + 104, + 51, + 106, + 200, + 15, + 236, + 228, + 50, + 50, + 118, + 156, + 82, + 77, + 226, + 96, + 80, + 158, + 137, + 222, + 179, + 209, + 218, + 209, + 88, + 194, + 221, + 49, + 168, + 165, + 159, + 78, + 170, + 52, + 29, + 34, + 137, + 0, + 202, + 232, + 58, + 197, + 214, + 35, + 30, + 172, + 188, + 3, + 133, + 237, + 29, + 253, + 155, + 180, + 7, + 201, + 68, + 104, + 160, + 133, + 238, + 212, + 143, + 179, + 161, + 37, + 108, + 41, + 177, + 183, + 167, + 150, + 100, + 216, + 188, + 35, + 177, + 142, + 166, + 211, + 169, + 218, + 230, + 141, + 105, + 134, + 68, + 65, + 239, + 54, + 82, + 188, + 199, + 3, + 62, + 31, + 167, + 74, + 78, + 247, + 131, + 64, + 79, + 71, + 107, + 105, + 127, + 52, + 79, + 53, + 245, + 210, + 36, + 223, + 157, + 70, + 108, + 83, + 143, + 134, + 144, + 59, + 76, + 50, + 116, + 12, + 5, + 140, + 7, + 83, + 242, + 151, + 166, + 30, + 71, + 42, + 19, + 37, + 233, + 25, + 11, + 32, + 125, + 169, + 244, + 110, + 118, + 118, + 140, + 147, + 125, + 212, + 190, + 230, + 113, + 153, + 204, + 98, + 203, + 199, + 129, + 20, + 161, + 68, + 13, + 61, + 253, + 167, + 194, + 36, + 120, + 228, + 104, + 77, + 115, + 203, + 66, + 150, + 217, + 242, + 207, + 205, + 103, + 160, + 181, + 82, + 105, + 121, + 71, + 57, + 11, + 86, + 104, + 30, + 87, + 149, + 243, + 2, + 57, + 101, + 42, + 126, + 208, + 146, + 105, + 147, + 37, + 153, + 183, + 20, + 202, + 8, + 127, + 133, + 21, + 201, + 115, + 12, + 39, + 75, + 170, + 117, + 5, + 106, + 132, + 112, + 67, + 116, + 254, + 45, + 12, + 109, + 7, + 247, + 44, + 134, + 146, + 85, + 99, + 24, + 160, + 125, + 38, + 80, + 137, + 229, + 144, + 101, + 38, + 240, + 249, + 115, + 251, + 221, + 201, + 148, + 163, + 113, + 59, + 49, + 235, + 252, + 39, + 57, + 87, + 86, + 165, + 254, + 244, + 224, + 217, + 159, + 74, + 248, + 99, + 207, + 197, + 188, + 56, + 70, + 187, + 72, + 107, + 27, + 77, + 6, + 28, + 51, + 186, + 84, + 171, + 218, + 203, + 76, + 189, + 47, + 167, + 92, + 16, + 58, + 85, + 2, + 7, + 188, + 19, + 77, + 25, + 126, + 21, + 184, + 9, + 187, + 33, + 186, + 180, + 105, + 124, + 28, + 164, + 43, + 30, + 26, + 126, + 87, + 22, + 69, + 39, + 20, + 73, + 209, + 153, + 89, + 248, + 89, + 165, + 69, + 208, + 51, + 34, + 43, + 191, + 138, + 83, + 49, + 56, + 255, + 145, + 233, + 238, + 206, + 194, + 219, + 60, + 20, + 10, + 107, + 191, + 235, + 94, + 88, + 41, + 176, + 228, + 108, + 47, + 15, + 229, + 20, + 174, + 1, + 242, + 11, + 58, + 100, + 12, + 236, + 58, + 158, + 207, + 26, + 96, + 90, + 177, + 37, + 72, + 20, + 211, + 231, + 194, + 22, + 203, + 140, + 184, + 118, + 53, + 221, + 44, + 141, + 116, + 145, + 254, + 197, + 50, + 170, + 176, + 90, + 252, + 236, + 88, + 20, + 254, + 66, + 24, + 186, + 45, + 62, + 186, + 79, + 65, + 28, + 142, + 87, + 241, + 8, + 128, + 79, + 6, + 46, + 56, + 146, + 47, + 106, + 34, + 155, + 80, + 124, + 237, + 81, + 66, + 119, + 234, + 210, + 203, + 56, + 55, + 208, + 89, + 175, + 222, + 58, + 88, + 11, + 84, + 109, + 206, + 90, + 102, + 100, + 229, + 163, + 102, + 230, + 65, + 162, + 212, + 59, + 206, + 245, + 11, + 231, + 222, + 46, + 238, + 59, + 55, + 166, + 201, + 232, + 21, + 189, + 225, + 77, + 39, + 30, + 14, + 236, + 236, + 2, + 24, + 235, + 30, + 134, + 18, + 119, + 198, + 73, + 145, + 23, + 94, + 63, + 5, + 148, + 223, + 165, + 88, + 110, + 30, + 34, + 32, + 221, + 147, + 157, + 118, + 12, + 36, + 201, + 172, + 208, + 38, + 34, + 165, + 69, + 97, + 253, + 205, + 152, + 110, + 84, + 121, + 231, + 40, + 198, + 168, + 157, + 126, + 21, + 210, + 186, + 202, + 57, + 193, + 16, + 201, + 11, + 62, + 98, + 44, + 37, + 222, + 218, + 11, + 88, + 239, + 96, + 122, + 37, + 155, + 3, + 254, + 20, + 28, + 236, + 166, + 216, + 106, + 42, + 201, + 249, + 82, + 60, + 42, + 45, + 51, + 19, + 70, + 20, + 216, + 78, + 139, + 216, + 212, + 15, + 139, + 115, + 162, + 46, + 152, + 60, + 72, + 47, + 136, + 111, + 127, + 196, + 101, + 42, + 43, + 123, + 103, + 2, + 221, + 253, + 62, + 175, + 211, + 195, + 21, + 171, + 94, + 31, + 112, + 113, + 56, + 79, + 87, + 61, + 135, + 22, + 1, + 45, + 8, + 67, + 55, + 156, + 113, + 116, + 163, + 73, + 117, + 68, + 175, + 120, + 70, + 163, + 5, + 94, + 4, + 170, + 159, + 230, + 133, + 33, + 139, + 180, + 230, + 23, + 222, + 100, + 162, + 94, + 127, + 241, + 101, + 5, + 135, + 91, + 149, + 214, + 28, + 66, + 142, + 218, + 55, + 165, + 88, + 118, + 147, + 19, + 245, + 53, + 3, + 200, + 126, + 37, + 114, + 44, + 146, + 200, + 136, + 95, + 229, + 0, + 237, + 71, + 233, + 86, + 5, + 57, + 139, + 68, + 10, + 7, + 161, + 40, + 245, + 180, + 30, + 8, + 3, + 21, + 36, + 141, + 217, + 140, + 119, + 85, + 154, + 177, + 5, + 54, + 214, + 54, + 167, + 98, + 85, + 64, + 170, + 111, + 94, + 180, + 160, + 193, + 65, + 221, + 194, + 72, + 29, + 238, + 201, + 130, + 55, + 133, + 165, + 86, + 29, + 84, + 91, + 35, + 72, + 47, + 7, + 157, + 13, + 169, + 201, + 177, + 134, + 102, + 156, + 4, + 4, + 77, + 11, + 190, + 13, + 83, + 218, + 134, + 184, + 85, + 199, + 79, + 180, + 105, + 224, + 14, + 42, + 79, + 247, + 112, + 11, + 232, + 193, + 175, + 142, + 112, + 154, + 192, + 5, + 226, + 253, + 218, + 40, + 149, + 44, + 80, + 14, + 199, + 164, + 146, + 64, + 104, + 245, + 249, + 202, + 75, + 11, + 130, + 135, + 156, + 230, + 48, + 73, + 181, + 232, + 141, + 56, + 174, + 13, + 114, + 92, + 25, + 108, + 196, + 252, + 155, + 147, + 120, + 104, + 147, + 176, + 239, + 138, + 235, + 204, + 25, + 255, + 55, + 244, + 226, + 208, + 151, + 141, + 7, + 80, + 68, + 67, + 192, + 226, + 63, + 79, + 240, + 37, + 191, + 0, + 59, + 245, + 58, + 209, + 16, + 109, + 154, + 250, + 138, + 159, + 238, + 223, + 108, + 34, + 51, + 212, + 107, + 29, + 34, + 214, + 4, + 12, + 105, + 85, + 203, + 42, + 152, + 227, + 253, + 145, + 252, + 129, + 36, + 25, + 75, + 219, + 189, + 26, + 36, + 255, + 30, + 120, + 174, + 141, + 93, + 54, + 65, + 65, + 193, + 48, + 7, + 85, + 17, + 6, + 157, + 28, + 161, + 153, + 188, + 195, + 255, + 146, + 74, + 35, + 167, + 143, + 24, + 8, + 34, + 218, + 38, + 77, + 10, + 105, + 169, + 108, + 51, + 184, + 129, + 159, + 202, + 99, + 82, + 18, + 78, + 19, + 207, + 129, + 45, + 175, + 83, + 88, + 165, + 189, + 89, + 166, + 249, + 150, + 94, + 186, + 103, + 139, + 234, + 25, + 122, + 181, + 16, + 96, + 124, + 201, + 229, + 123, + 104, + 208, + 87, + 223, + 91, + 22, + 137, + 91, + 193, + 187, + 76, + 26, + 177, + 214, + 188, + 62, + 36, + 7, + 166, + 169, + 0, + 242, + 215, + 239, + 149, + 1, + 104, + 149, + 170, + 154, + 130, + 160, + 212, + 205, + 43, + 126, + 104, + 94, + 29, + 252, + 205, + 28, + 132, + 145, + 218, + 176, + 128, + 169, + 229, + 235, + 169, + 231, + 88, + 124, + 70, + 240, + 232, + 12, + 206, + 140, + 154, + 225, + 127, + 53, + 29, + 230, + 117, + 134, + 14, + 223, + 129, + 110, + 78, + 236, + 184, + 241, + 103, + 31, + 224, + 122, + 184, + 127, + 178, + 193, + 7, + 80, + 19, + 226, + 41, + 141, + 154, + 39, + 70, + 8, + 232, + 14, + 117, + 150, + 92, + 105, + 17, + 180, + 234, + 86, + 215, + 195, + 25, + 61, + 154, + 126, + 95, + 235, + 37, + 150, + 126, + 8, + 45, + 171, + 130, + 36, + 158, + 245, + 133, + 208, + 160, + 230, + 47, + 31, + 78, + 232, + 151, + 83, + 37, + 245, + 225, + 86, + 67, + 115, + 110, + 233, + 7, + 39, + 19, + 94, + 135, + 33, + 145, + 197, + 61, + 144, + 84, + 0, + 153, + 206, + 0, + 163, + 244, + 10, + 121, + 253, + 239, + 163, + 125, + 229, + 113, + 202, + 123, + 34, + 86, + 103, + 232, + 13, + 171, + 203, + 13, + 205, + 233, + 144, + 214, + 57, + 29, + 108, + 166, + 75, + 4, + 196, + 20, + 176, + 90, + 191, + 192, + 178, + 150, + 139, + 26, + 236, + 105, + 191, + 3, + 6, + 37, + 186, + 2, + 217, + 161, + 29, + 123, + 217, + 207, + 249, + 182, + 126, + 224, + 114, + 71, + 168, + 80, + 33, + 113, + 247, + 75, + 235, + 250, + 32, + 130, + 107, + 22, + 17, + 22, + 19, + 230, + 153, + 109, + 221, + 66, + 237, + 79, + 51, + 209, + 214, + 84, + 157, + 115, + 11, + 108, + 203, + 173, + 30, + 26, + 173, + 84, + 103, + 194, + 113, + 240, + 151, + 240, + 179, + 85, + 5, + 107, + 40, + 166, + 90, + 210, + 39, + 114, + 87, + 147, + 32, + 73, + 45, + 194, + 76, + 107, + 8, + 178, + 108, + 55, + 197, + 222, + 70, + 150, + 252, + 57, + 38, + 248, + 126, + 226, + 178, + 152, + 34, + 18, + 48, + 162, + 215, + 135, + 209, + 50, + 41, + 134, + 108, + 157, + 172, + 63, + 46, + 85, + 134, + 34, + 121, + 200, + 88, + 232, + 172, + 12, + 94, + 163, + 205, + 190, + 44, + 239, + 116, + 146, + 120, + 84, + 110, + 244, + 70, + 12, + 91, + 105, + 221, + 121, + 73, + 162, + 137, + 219, + 238, + 236, + 55, + 119, + 54, + 121, + 102, + 151, + 169, + 40, + 206, + 57, + 5, + 1, + 51, + 213, + 84, + 89, + 81, + 48, + 103, + 213, + 214, + 48, + 17, + 183, + 119, + 75, + 89, + 61, + 37, + 53, + 193, + 68, + 136, + 183, + 22, + 173, + 250, + 240, + 210, + 55, + 44, + 89, + 117, + 125, + 26, + 67, + 63, + 45, + 50, + 95, + 175, + 94, + 22, + 120, + 197, + 152, + 164, + 126, + 107, + 44, + 227, + 163, + 140, + 125, + 233, + 213, + 67, + 232, + 248, + 241, + 21, + 181, + 112, + 65, + 219, + 21, + 84, + 170, + 38, + 218, + 121, + 32, + 218, + 69, + 167, + 126, + 176, + 217, + 81, + 31, + 128, + 225, + 242, + 157, + 170, + 81, + 0, + 225, + 82, + 209, + 5, + 17, + 190, + 33, + 108, + 245, + 2, + 92, + 199, + 11, + 145, + 204, + 9, + 59, + 193, + 14, + 86, + 69, + 182, + 42, + 48, + 13, + 245, + 131, + 243, + 3, + 47, + 70, + 153, + 65, + 217, + 74, + 199, + 139, + 8, + 117, + 45, + 150, + 112, + 1, + 86, + 193, + 223, + 160, + 23, + 67, + 166, + 109, + 110, + 211, + 45, + 72, + 146, + 251, + 207, + 92, + 158, + 187, + 3, + 106, + 202, + 239, + 188, + 79, + 113, + 4, + 170, + 238, + 88, + 30, + 173, + 93, + 151, + 253, + 190, + 21, + 70, + 50, + 70, + 16, + 29, + 165, + 211, + 73, + 223, + 244, + 219, + 91, + 102, + 54, + 120, + 212, + 173, + 189, + 76, + 119, + 194, + 178, + 105, + 218, + 244, + 156, + 197, + 130, + 119, + 190, + 93, + 43, + 229, + 13, + 166, + 89, + 131, + 42, + 23, + 113, + 125, + 236, + 158, + 51, + 81, + 195, + 4, + 9, + 83, + 142, + 244, + 39, + 212, + 101, + 228, + 67, + 150, + 50, + 202, + 77, + 123, + 106, + 192, + 142, + 61, + 93, + 225, + 81, + 41, + 170, + 43, + 207, + 111, + 56, + 117, + 132, + 31, + 158, + 236, + 109, + 113, + 185, + 181, + 124, + 17, + 37, + 239, + 221, + 187, + 26, + 183, + 82, + 143, + 212, + 101, + 106, + 42, + 107, + 211, + 106, + 194, + 64, + 117, + 166, + 183, + 9, + 180, + 123, + 218, + 227, + 35, + 175, + 232, + 238, + 111, + 231, + 211, + 178, + 246, + 227, + 181, + 186, + 242, + 235, + 78, + 229, + 32, + 196, + 165, + 52, + 90, + 232, + 212, + 138, + 250, + 160, + 225, + 20, + 18, + 148, + 2, + 27, + 42, + 209, + 193, + 39, + 94, + 92, + 84, + 78, + 174, + 31, + 252, + 190, + 100, + 121, + 134, + 194, + 13, + 145, + 207, + 29, + 239, + 70, + 144, + 243, + 222, + 183, + 65, + 217, + 0, + 238, + 59, + 144, + 82, + 135, + 19, + 250, + 251, + 67, + 69, + 78, + 163, + 225, + 77, + 97, + 219, + 154, + 24, + 208, + 127, + 58, + 105, + 49, + 43, + 121, + 206, + 241, + 84, + 65, + 186, + 38, + 183, + 71, + 115, + 205, + 212, + 49, + 77, + 91, + 199, + 194, + 139, + 181, + 18, + 116, + 221, + 241, + 187, + 184, + 157, + 162, + 32, + 237, + 159, + 32, + 0, + 99, + 188, + 18, + 72, + 253, + 100, + 217, + 22, + 75, + 159, + 82, + 15, + 27, + 233, + 122, + 169, + 51, + 87, + 16, + 28, + 14, + 86, + 95, + 89, + 120, + 46, + 218, + 32, + 230, + 72, + 32, + 226, + 91, + 156, + 182, + 147, + 186, + 12, + 161, + 15, + 170, + 205, + 43, + 23, + 51, + 147, + 30, + 228, + 194, + 15, + 2, + 52, + 47, + 110, + 170, + 183, + 58, + 114, + 196, + 156, + 135, + 104, + 90, + 231, + 31, + 5, + 147, + 110, + 164, + 252, + 243, + 93, + 155, + 36, + 158, + 155, + 194, + 252, + 88, + 198, + 37, + 186, + 11, + 189, + 169, + 233, + 157, + 128, + 33, + 66, + 22, + 108, + 77, + 231, + 8, + 75, + 205, + 181, + 69, + 37, + 121, + 30, + 57, + 234, + 186, + 11, + 247, + 159, + 172, + 206, + 147, + 57, + 101, + 92, + 212, + 30, + 90, + 87, + 24, + 115, + 73, + 117, + 197, + 7, + 129, + 71, + 61, + 5, + 175, + 128, + 225, + 20, + 131, + 61, + 54, + 40, + 145, + 241, + 25, + 40, + 7, + 110, + 188, + 147, + 120, + 25, + 151, + 89, + 37, + 5, + 198, + 55, + 21, + 37, + 184, + 252, + 232, + 147, + 96, + 40, + 117, + 121, + 145, + 112, + 5, + 182, + 57, + 32, + 128, + 242, + 29, + 2, + 119, + 120, + 26, + 162, + 35, + 132, + 224, + 97, + 35, + 250, + 139, + 139, + 30, + 213, + 110, + 255, + 140, + 176, + 42, + 50, + 85, + 249, + 163, + 58, + 84, + 104, + 3, + 202, + 252, + 105, + 213, + 91, + 183, + 249, + 10, + 187, + 202, + 26, + 180, + 225, + 81, + 239, + 126, + 220, + 189, + 60, + 61, + 254, + 5, + 107, + 31, + 204, + 121, + 95, + 184, + 54, + 74, + 45, + 65, + 23, + 170, + 109, + 55, + 135, + 169, + 0, + 2, + 61, + 107, + 221, + 56, + 102, + 88, + 62, + 186, + 148, + 250, + 64, + 59, + 114, + 25, + 96, + 28, + 91, + 184, + 181, + 242, + 155, + 160, + 0, + 168, + 12, + 145, + 174, + 58, + 230, + 123, + 1, + 33, + 95, + 199, + 101, + 171, + 250, + 28, + 46, + 82, + 10, + 12, + 58, + 15, + 29, + 19, + 61, + 16, + 254, + 141, + 133, + 98, + 174, + 52, + 208, + 105, + 119, + 83, + 49, + 122, + 103, + 41, + 121, + 40, + 142, + 80, + 188, + 78, + 234, + 57, + 217, + 154, + 190, + 217, + 174, + 140, + 132, + 216, + 189, + 54, + 65, + 241, + 217, + 226, + 151, + 242, + 90, + 154, + 164, + 246, + 62, + 199, + 22, + 218, + 170, + 10, + 64, + 29, + 25, + 179, + 123, + 18, + 21, + 170, + 223, + 133, + 130, + 136, + 252, + 31, + 39, + 43, + 46, + 182, + 59, + 75, + 229, + 91, + 116, + 185, + 73, + 192, + 0, + 13, + 192, + 173, + 33, + 18, + 178, + 52, + 65, + 166, + 152, + 74, + 255, + 120, + 122, + 9, + 199, + 168, + 170, + 231, + 204, + 45, + 174, + 77, + 173, + 244, + 252, + 60, + 165, + 31, + 226, + 187, + 175, + 198, + 124, + 2, + 192, + 85, + 48, + 0, + 70, + 13, + 54, + 227, + 97, + 74, + 81, + 193, + 126, + 156, + 138, + 197, + 20, + 34, + 126, + 5, + 252, + 14, + 115, + 181, + 126, + 158, + 117, + 114, + 117, + 9, + 252, + 111, + 5, + 146, + 61, + 252, + 123, + 180, + 22, + 150, + 212, + 132, + 14, + 233, + 132, + 149, + 31, + 119, + 80, + 105, + 217, + 94, + 248, + 139, + 214, + 103, + 42, + 44, + 129, + 95, + 144, + 193, + 26, + 181, + 56, + 245, + 203, + 74, + 60, + 147, + 40, + 26, + 232, + 21, + 13, + 179, + 11, + 142, + 29, + 62, + 1, + 81, + 18, + 192, + 83, + 96, + 2, + 150, + 161, + 79, + 97, + 114, + 78, + 8, + 119, + 142, + 202, + 128, + 20, + 101, + 131, + 218, + 222, + 111, + 228, + 38, + 16, + 243, + 22, + 119, + 137, + 112, + 198, + 11, + 43, + 253, + 96, + 72, + 30, + 120, + 254, + 51, + 112, + 206, + 248, + 46, + 82, + 98, + 109, + 171, + 247, + 91, + 182, + 186, + 119, + 77, + 27, + 162, + 233, + 66, + 229, + 203, + 209, + 59, + 5, + 54, + 224, + 125, + 155, + 177, + 206, + 233, + 175, + 64, + 119, + 225, + 54, + 226, + 65, + 225, + 7, + 144, + 234, + 43, + 64, + 158, + 234, + 163, + 19, + 153, + 219, + 119, + 83, + 217, + 166, + 128, + 93, + 48, + 39, + 9, + 234, + 207, + 4, + 67, + 186, + 169, + 100, + 60, + 162, + 217, + 144, + 243, + 166, + 33, + 24, + 212, + 30, + 132, + 154, + 11, + 150, + 111, + 132, + 177, + 148, + 106, + 140, + 131, + 160, + 11, + 66, + 196, + 31, + 75, + 67, + 16, + 13, + 212, + 66, + 125, + 59, + 46, + 167, + 46, + 29, + 56, + 140, + 16, + 27, + 164, + 169, + 185, + 142, + 99, + 183, + 197, + 183, + 218, + 47, + 183, + 62, + 6, + 18, + 11, + 83, + 157, + 194, + 30, + 167, + 172, + 200, + 253, + 11, + 163, + 88, + 88, + 136, + 109, + 143, + 55, + 137, + 173, + 96, + 149, + 74, + 238, + 27, + 97, + 89, + 25, + 9, + 235, + 130, + 74, + 40, + 177, + 48, + 183, + 169, + 79, + 63, + 149, + 173, + 194, + 101, + 146, + 179, + 180, + 90, + 56, + 20, + 246, + 214, + 122, + 161, + 130, + 144, + 140, + 249, + 43, + 90, + 100, + 97, + 29, + 179, + 87, + 192, + 116, + 176, + 127, + 157, + 41, + 206, + 177, + 162, + 241, + 185, + 5, + 47, + 206, + 82, + 76, + 21, + 73, + 237, + 103, + 84, + 166, + 71, + 132, + 113, + 48, + 12, + 42, + 232, + 32, + 50, + 47, + 86, + 206, + 125, + 92, + 128, + 31, + 75, + 147, + 102, + 11, + 17, + 113, + 94, + 224, + 165, + 193, + 104, + 63, + 101, + 136, + 255, + 142, + 121, + 100, + 18, + 225, + 148, + 33, + 34, + 184, + 143, + 11, + 74, + 205, + 61, + 231, + 95, + 64, + 200, + 87, + 3, + 52, + 130, + 205, + 92, + 169, + 179, + 169, + 64, + 141, + 93, + 202, + 32, + 89, + 212, + 251, + 105, + 216, + 45, + 195, + 238, + 64, + 1, + 102, + 12, + 23, + 55, + 150, + 171, + 244, + 96, + 250, + 127, + 151, + 12, + 233, + 35, + 168, + 186, + 106, + 10, + 138, + 243, + 160, + 54, + 51, + 11, + 4, + 21, + 129, + 251, + 86, + 167, + 210, + 7, + 55, + 177, + 60, + 58, + 209, + 166, + 237, + 62, + 141, + 180, + 173, + 41, + 219, + 73, + 128, + 67, + 152, + 250, + 188, + 153, + 215, + 80, + 192, + 216, + 13, + 86, + 131, + 25, + 50, + 126, + 96, + 63, + 94, + 198, + 209, + 248, + 84, + 89, + 195, + 212, + 81, + 90, + 22, + 180, + 70, + 22, + 146, + 46, + 62, + 209, + 77, + 101, + 108, + 113, + 202, + 116, + 235, + 61, + 60, + 65, + 245, + 249, + 85, + 241, + 16, + 96, + 254, + 125, + 212, + 173, + 41, + 37, + 248, + 147, + 78, + 118, + 58, + 78, + 75, + 225, + 47, + 61, + 186, + 26, + 114, + 225, + 63, + 123, + 15, + 25, + 173, + 94, + 194, + 137, + 193, + 167, + 77, + 116, + 41, + 118, + 51, + 253, + 235, + 135, + 45, + 205, + 33, + 87, + 133, + 128, + 68, + 231, + 32, + 170, + 176, + 124, + 195, + 209, + 37, + 42, + 125, + 12, + 236, + 98, + 125, + 251, + 40, + 239, + 27, + 52, + 203, + 19, + 68, + 0, + 171, + 212, + 119, + 172, + 227, + 134, + 45, + 137, + 46, + 174, + 127, + 74, + 240, + 67, + 115, + 187, + 72, + 241, + 238, + 84, + 122, + 192, + 246, + 28, + 55, + 1, + 108, + 37, + 172, + 53, + 54, + 247, + 213, + 78, + 162, + 246, + 120, + 25, + 68, + 170, + 66, + 140, + 218, + 111, + 96, + 132, + 170, + 122, + 43, + 9, + 27, + 136, + 200, + 106, + 228, + 103, + 238, + 12, + 103, + 127, + 248, + 222, + 245, + 143, + 206, + 205, + 0, + 30, + 198, + 75, + 162, + 40, + 199, + 23, + 32, + 93, + 59, + 242, + 124, + 222, + 101, + 251, + 197, + 222, + 229, + 142, + 234, + 145, + 201, + 124, + 54, + 232, + 167, + 196, + 169, + 95, + 119, + 245, + 204, + 109, + 197, + 199, + 62, + 146, + 203, + 236, + 94, + 79, + 207, + 20, + 162, + 184, + 232, + 134, + 178, + 110, + 195, + 21, + 128, + 178, + 26, + 50, + 12, + 46, + 217, + 197, + 207, + 135, + 150, + 86, + 210, + 217, + 176, + 156, + 229, + 60, + 224, + 1, + 212, + 188, + 15, + 24, + 147, + 234, + 187, + 179, + 242, + 242, + 58, + 87, + 59, + 127, + 58, + 248, + 8, + 191, + 18, + 162, + 96, + 223, + 151, + 106, + 134, + 71, + 159, + 48, + 145, + 131, + 191, + 210, + 33, + 187, + 180, + 226, + 195, + 124, + 79, + 220, + 55, + 175, + 198, + 202, + 36, + 157, + 102, + 29, + 113, + 199, + 249, + 49, + 77, + 105, + 221, + 62, + 229, + 126, + 201, + 11, + 45, + 138, + 146, + 73, + 135, + 19, + 65, + 33, + 219, + 130, + 35, + 208, + 237, + 54, + 227, + 160, + 215, + 122, + 154, + 207, + 61, + 70, + 106, + 244, + 172, + 183, + 61, + 172, + 218, + 141, + 93, + 12, + 9, + 239, + 86, + 41, + 59, + 189, + 21, + 217, + 194, + 208, + 4, + 1, + 28, + 202, + 134, + 153, + 128, + 60, + 119, + 3, + 85, + 8, + 84, + 173, + 108, + 36, + 145, + 158, + 138, + 210, + 141, + 88, + 21, + 191, + 185, + 137, + 40, + 4, + 160, + 218, + 41, + 236, + 102, + 19, + 185, + 50, + 67, + 41, + 19, + 166, + 64, + 103, + 92, + 73, + 203, + 29, + 252, + 182, + 125, + 82, + 10, + 126, + 74, + 29, + 55, + 32, + 226, + 196, + 127, + 80, + 124, + 174, + 50, + 157, + 140, + 42, + 180, + 128, + 171, + 157, + 35, + 98, + 78, + 179, + 11, + 9, + 79, + 246, + 142, + 162, + 199, + 110, + 170, + 247, + 108, + 119, + 84, + 65, + 58, + 249, + 247, + 154, + 227, + 107, + 111, + 27, + 241, + 30, + 154, + 242, + 113, + 46, + 221, + 186, + 85, + 47, + 33, + 51, + 229, + 176, + 133, + 17, + 202, + 147, + 219, + 4, + 223, + 231, + 215, + 220, + 177, + 35, + 230, + 158, + 87, + 67, + 122, + 21, + 7, + 213, + 39, + 28, + 164, + 165, + 94, + 232, + 247, + 192, + 33, + 93, + 221, + 101, + 133, + 212, + 37, + 20, + 141, + 23, + 63, + 224, + 248, + 141, + 211, + 98, + 230, + 7, + 218, + 15, + 220, + 9, + 43, + 165, + 213, + 184, + 220, + 16, + 70, + 172, + 216, + 94, + 80, + 60, + 230, + 148, + 80, + 244, + 148, + 32, + 74, + 217, + 128, + 36, + 41, + 115, + 116, + 83, + 170, + 143, + 15, + 52, + 94, + 78, + 211, + 136, + 147, + 153, + 88, + 63, + 111, + 246, + 220, + 126, + 95, + 170, + 98, + 87, + 171, + 145, + 247, + 119, + 221, + 67, + 124, + 49, + 1, + 11, + 166, + 106, + 90, + 170, + 221, + 73, + 125, + 26, + 153, + 220, + 75, + 235, + 82, + 151, + 192, + 124, + 114, + 15, + 89, + 180, + 122, + 239, + 91, + 60, + 32, + 233, + 44, + 147, + 90, + 207, + 12, + 49, + 161, + 167, + 154, + 216, + 201, + 164, + 214, + 21, + 125, + 221, + 195, + 55, + 135, + 59, + 202, + 86, + 111, + 9, + 35, + 252, + 46, + 81, + 80, + 4, + 33, + 170, + 68, + 195, + 232, + 44, + 89, + 197, + 24, + 135, + 171, + 218, + 228, + 136, + 233, + 88, + 95, + 104, + 93, + 62, + 48, + 106, + 12, + 218, + 207, + 65, + 56, + 152, + 99, + 87, + 84, + 116, + 139, + 129, + 95, + 37, + 65, + 26, + 91, + 89, + 11, + 146, + 158, + 66, + 77, + 163, + 73, + 46, + 230, + 132, + 106, + 135, + 106, + 185, + 180, + 31, + 198, + 236, + 2, + 47, + 29, + 13, + 153, + 127, + 7, + 139, + 169, + 173, + 208, + 223, + 251, + 119, + 112, + 26, + 70, + 103, + 113, + 177, + 67, + 208, + 65, + 136, + 5, + 12, + 73, + 105, + 192, + 112, + 1, + 82, + 28, + 213, + 114, + 235, + 118, + 200, + 66, + 62, + 97, + 173, + 129, + 212, + 43, + 242, + 42, + 213, + 53, + 158, + 177, + 155, + 74, + 130, + 48, + 14, + 89, + 163, + 248, + 215, + 230, + 83, + 39, + 68, + 72, + 174, + 42, + 209, + 233, + 76, + 183, + 62, + 192, + 85, + 181, + 144, + 123, + 10, + 114, + 111, + 84, + 0, + 136, + 175, + 149, + 201, + 30, + 87, + 178, + 151, + 163, + 21, + 31, + 52, + 189, + 101, + 76, + 10, + 186, + 35, + 197, + 219, + 143, + 87, + 213, + 97, + 209, + 198, + 128, + 87, + 183, + 142, + 165, + 181, + 104, + 229, + 209, + 100, + 115, + 226, + 131, + 119, + 113, + 17, + 197, + 174, + 176, + 149, + 4, + 81, + 238, + 233, + 192, + 221, + 247, + 136, + 204, + 188, + 32, + 225, + 160, + 200, + 87, + 40, + 63, + 139, + 102, + 136, + 82, + 197, + 92, + 239, + 121, + 183, + 86, + 219, + 237, + 57, + 209, + 241, + 48, + 113, + 118, + 198, + 222, + 7, + 79, + 119, + 122, + 61, + 5, + 44, + 148, + 124, + 229, + 198, + 241, + 135, + 251, + 253, + 173, + 225, + 246, + 14, + 156, + 83, + 185, + 126, + 254, + 149, + 7, + 177, + 82, + 229, + 1, + 159, + 97, + 234, + 4, + 82, + 94, + 145, + 133, + 66, + 86, + 96, + 68, + 111, + 121, + 187, + 67, + 102, + 253, + 134, + 37, + 99, + 24, + 37, + 82, + 75, + 189, + 82, + 40, + 217, + 108, + 227, + 204, + 254, + 69, + 36, + 212, + 108, + 79, + 68, + 160, + 203, + 170, + 18, + 180, + 175, + 20, + 224, + 150, + 190, + 9, + 154, + 165, + 191, + 59, + 132, + 143, + 27, + 63, + 196, + 72, + 186, + 26, + 63, + 194, + 78, + 15, + 40, + 25, + 97, + 138, + 89, + 177, + 112, + 142, + 84, + 38, + 163, + 14, + 183, + 122, + 243, + 77, + 79, + 246, + 225, + 83, + 205, + 239, + 88, + 42, + 64, + 108, + 101, + 82, + 173, + 135, + 147, + 65, + 253, + 131, + 161, + 95, + 28, + 43, + 194, + 162, + 176, + 6, + 233, + 56, + 88, + 126, + 139, + 133, + 189, + 78, + 101, + 211, + 64, + 41, + 180, + 158, + 147, + 117, + 104, + 50, + 158, + 192, + 39, + 165, + 227, + 128, + 185, + 151, + 208, + 193, + 228, + 213, + 30, + 234, + 56, + 115, + 194, + 93, + 21, + 107, + 145, + 156, + 163, + 52, + 138, + 182, + 151, + 251, + 176, + 187, + 101, + 9, + 5, + 105, + 75, + 1, + 222, + 172, + 113, + 111, + 81, + 194, + 181, + 146, + 47, + 147, + 44, + 165, + 18, + 102, + 63, + 40, + 20, + 10, + 30, + 66, + 60, + 177, + 30, + 72, + 19, + 229, + 119, + 13, + 205, + 252, + 71, + 122, + 102, + 5, + 145, + 208, + 26, + 136, + 63, + 201, + 23, + 83, + 102, + 252, + 164, + 46, + 220, + 251, + 188, + 251, + 222, + 161, + 97, + 19, + 22, + 89, + 222, + 193, + 145, + 42, + 31, + 244, + 108, + 43, + 134, + 135, + 34, + 235, + 226, + 159, + 126, + 53, + 246, + 83, + 144, + 35, + 124, + 20, + 201, + 139, + 181, + 223, + 69, + 42, + 66, + 64, + 13, + 148, + 230, + 34, + 232, + 100, + 14, + 124, + 184, + 25, + 175, + 43, + 5, + 61, + 37, + 106, + 190, + 246, + 13, + 98, + 252, + 90, + 57, + 192, + 0, + 169, + 180, + 32, + 156, + 9, + 129, + 234, + 11, + 113, + 38, + 43, + 239, + 102, + 251, + 154, + 177, + 131, + 249, + 156, + 156, + 245, + 40, + 112, + 7, + 108, + 197, + 186, + 109, + 159, + 56, + 153, + 53, + 148, + 132, + 85, + 198, + 255, + 86, + 118, + 249, + 192, + 4, + 176, + 21, + 30, + 34, + 142, + 47, + 158, + 25, + 216, + 3, + 129, + 228, + 179, + 238, + 21, + 39, + 34, + 23, + 151, + 14, + 69, + 84, + 98, + 181, + 205, + 199, + 46, + 233, + 215, + 167, + 41, + 254, + 115, + 213, + 108, + 253, + 200, + 55, + 62, + 15, + 104, + 62, + 225, + 22, + 68, + 52, + 171, + 81, + 82, + 229, + 9, + 94, + 97, + 106, + 123, + 71, + 169, + 18, + 201, + 79, + 142, + 178, + 129, + 41, + 249, + 78, + 67, + 231, + 15, + 39, + 21, + 42, + 108, + 64, + 104, + 26, + 52, + 17, + 55, + 238, + 184, + 119, + 28, + 179, + 3, + 2, + 128, + 238, + 154, + 108, + 211, + 72, + 241, + 43, + 157, + 31, + 124, + 146, + 37, + 16, + 236, + 154, + 170, + 145, + 79, + 92, + 43, + 81, + 46, + 78, + 170, + 214, + 110, + 65, + 86, + 17, + 84, + 130, + 17, + 173, + 119, + 89, + 110, + 234, + 40, + 191, + 16, + 175, + 97, + 228, + 92, + 237, + 210, + 238, + 54, + 186, + 125, + 71, + 107, + 206, + 184, + 247, + 232, + 147, + 191, + 236, + 27, + 218, + 77, + 67, + 35, + 60, + 106, + 131, + 27, + 168, + 243, + 234, + 45, + 81, + 143, + 169, + 70, + 107, + 199, + 107, + 51, + 234, + 66, + 45, + 6, + 85, + 234, + 117, + 146, + 143, + 177, + 67, + 94, + 237, + 129, + 133, + 118, + 227, + 46, + 63, + 21, + 117, + 89, + 243, + 74, + 35, + 215, + 119, + 76, + 196, + 153, + 123, + 89, + 14, + 103, + 22, + 90, + 53, + 122, + 203, + 79, + 45, + 2, + 143, + 155, + 20, + 102, + 252, + 4, + 89, + 202, + 189, + 157, + 134, + 187, + 71, + 235, + 245, + 215, + 105, + 22, + 250, + 89, + 160, + 30, + 190, + 98, + 151, + 138, + 65, + 206, + 228, + 44, + 121, + 187, + 147, + 76, + 5, + 129, + 145, + 168, + 139, + 105, + 154, + 193, + 189, + 152, + 239, + 36, + 63, + 200, + 151, + 35, + 28, + 172, + 27, + 107, + 138, + 23, + 196, + 96, + 95, + 97, + 25, + 240, + 169, + 226, + 15, + 79, + 24, + 14, + 54, + 204, + 162, + 62, + 174, + 150, + 53, + 164, + 115, + 47, + 95, + 28, + 1, + 3, + 175, + 76, + 118, + 108, + 138, + 158, + 167, + 7, + 205, + 165, + 141, + 73, + 41, + 26, + 221, + 143, + 12, + 231, + 3, + 187, + 214, + 3, + 67, + 223, + 66, + 183, + 123, + 12, + 102, + 248, + 211, + 5, + 83, + 118, + 61, + 122, + 175, + 25, + 122, + 46, + 84, + 49, + 202, + 248, + 142, + 6, + 55, + 168, + 112, + 246, + 70, + 35, + 63, + 248, + 133, + 43, + 152, + 239, + 154, + 183, + 36, + 192, + 82, + 63, + 141, + 255, + 4, + 102, + 25, + 22, + 1, + 78, + 184, + 178, + 196, + 246, + 28, + 168, + 166, + 103, + 171, + 63, + 73, + 108, + 195, + 201, + 23, + 187, + 42, + 186, + 39, + 249, + 32, + 55, + 211, + 77, + 163, + 170, + 252, + 142, + 66, + 122, + 163, + 239, + 129, + 199, + 104, + 131, + 221, + 93, + 98, + 150, + 5, + 73, + 131, + 128, + 117, + 125, + 57, + 219, + 122, + 35, + 129, + 186, + 172, + 31, + 253, + 54, + 149, + 169, + 35, + 26, + 163, + 131, + 149, + 150, + 34, + 219, + 132, + 185, + 149, + 36, + 29, + 99, + 219, + 56, + 9, + 191, + 185, + 95, + 144, + 159, + 236, + 174, + 102, + 15, + 87, + 112, + 252, + 46, + 221, + 127, + 182, + 4, + 139, + 255, + 15, + 255, + 216, + 248, + 131, + 163, + 235, + 132, + 246, + 73, + 26, + 217, + 138, + 207, + 217, + 223, + 228, + 252, + 164, + 54, + 224, + 88, + 19, + 4, + 43, + 90, + 220, + 34, + 155, + 1, + 30, + 197, + 48, + 240, + 130, + 129, + 190, + 78, + 153, + 29, + 187, + 16, + 46, + 186, + 192, + 101, + 70, + 249, + 201, + 245, + 13, + 104, + 18, + 22, + 172, + 82, + 67, + 93, + 90, + 224, + 170, + 47, + 214, + 17, + 206, + 21, + 103, + 191, + 27, + 64, + 51, + 124, + 225, + 89, + 174, + 61, + 178, + 74, + 222, + 67, + 143, + 254, + 108, + 249, + 11, + 17, + 97, + 203, + 97, + 10, + 225, + 139, + 191, + 248, + 20, + 59, + 160, + 123, + 76, + 101, + 197, + 85, + 88, + 4, + 155, + 16, + 141, + 237, + 142, + 199, + 70, + 122, + 24, + 83, + 144, + 248, + 55, + 236, + 251, + 1, + 216, + 16, + 103, + 240, + 167, + 159, + 70, + 101, + 245, + 65, + 133, + 150, + 203, + 179, + 242, + 252, + 12, + 0, + 249, + 90, + 221, + 2, + 209, + 101, + 105, + 102, + 25, + 32, + 157, + 81, + 61, + 216, + 104, + 50, + 6, + 167, + 27, + 113, + 155, + 223, + 8, + 250, + 250, + 52, + 247, + 102, + 228, + 18, + 248, + 217, + 10, + 204, + 177, + 8, + 222, + 80, + 43, + 128, + 201, + 7, + 100, + 15, + 74, + 250, + 245, + 31, + 42, + 62, + 215, + 125, + 148, + 200, + 77, + 109, + 201, + 194, + 8, + 139, + 166, + 32, + 178, + 111, + 241, + 183, + 137, + 224, + 19, + 170, + 64, + 148, + 125, + 67, + 97, + 107, + 199, + 235, + 53, + 106, + 250, + 25, + 7, + 238, + 249, + 248, + 253, + 243, + 231, + 190, + 202, + 201, + 253, + 46, + 62, + 235, + 116, + 164, + 71, + 48, + 105, + 180, + 106, + 171, + 13, + 57, + 67, + 62, + 47, + 212, + 158, + 110, + 143, + 66, + 13, + 6, + 248, + 107, + 66, + 18, + 75, + 176, + 26, + 30, + 227, + 214, + 212, + 123, + 199, + 62, + 18, + 36, + 40, + 192, + 185, + 178, + 167, + 246, + 195, + 186, + 214, + 42, + 216, + 3, + 223, + 226, + 20, + 150, + 221, + 31, + 30, + 173, + 209, + 5, + 203, + 166, + 40, + 247, + 63, + 40, + 221, + 224, + 241, + 247, + 58, + 148, + 107, + 70, + 8, + 241, + 33, + 220, + 150, + 150, + 246, + 9, + 139, + 190, + 62, + 145, + 166, + 85, + 45, + 115, + 16, + 13, + 59, + 201, + 14, + 61, + 194, + 2, + 113, + 201, + 153, + 195, + 11, + 94, + 142, + 65, + 31, + 162, + 187, + 86, + 224, + 226, + 19, + 12, + 159, + 215, + 35, + 51, + 245, + 72, + 19, + 241, + 234, + 220, + 163, + 244, + 84, + 73, + 126, + 255, + 40, + 255, + 90, + 121, + 248, + 138, + 159, + 179, + 193, + 68, + 108, + 134, + 198, + 94, + 129, + 109, + 239, + 153, + 66, + 26, + 113, + 222, + 147, + 166, + 89, + 10, + 8, + 188, + 96, + 139, + 3, + 210, + 152, + 92, + 106, + 254, + 65, + 135, + 57, + 7, + 146, + 125, + 158, + 31, + 129, + 47, + 99, + 23, + 127, + 54, + 212, + 24, + 52, + 235, + 49, + 168, + 173, + 98, + 241, + 243, + 231, + 24, + 61, + 4, + 120, + 56, + 189, + 231, + 92, + 83, + 229, + 87, + 168, + 196, + 136, + 213, + 223, + 36, + 30, + 98, + 66, + 254, + 237, + 99, + 80, + 63, + 189, + 201, + 108, + 137, + 60, + 179, + 104, + 146, + 103, + 21, + 194, + 127, + 142, + 240, + 84, + 203, + 72, + 127, + 155, + 131, + 141, + 100, + 182, + 12, + 127, + 29, + 208, + 239, + 1, + 229, + 160, + 99, + 74, + 103, + 147, + 158, + 125, + 170, + 44, + 235, + 48, + 16, + 103, + 31, + 175, + 135, + 170, + 93, + 255, + 123, + 14, + 8, + 44, + 38, + 158, + 0, + 92, + 86, + 230, + 249, + 93, + 244, + 220, + 156, + 76, + 76, + 118, + 194, + 102, + 38, + 45, + 239, + 62, + 155, + 119, + 252, + 65, + 211, + 254, + 43, + 215, + 40, + 51, + 155, + 140, + 20, + 0, + 82, + 241, + 1, + 160, + 170, + 93, + 59, + 14, + 58, + 191, + 42, + 187, + 27, + 61, + 49, + 167, + 184, + 230, + 252, + 150, + 163, + 246, + 173, + 33, + 131, + 26, + 134, + 81, + 9, + 100, + 91, + 120, + 60, + 32, + 105, + 3, + 187, + 197, + 122, + 16, + 75, + 161, + 249, + 72, + 54, + 244, + 161, + 116, + 78, + 53, + 18, + 4, + 71, + 203, + 3, + 40, + 255, + 59, + 239, + 40, + 185, + 198, + 165, + 148, + 248, + 140, + 79, + 211, + 124, + 177, + 180, + 235, + 253, + 65, + 194, + 69, + 58, + 118, + 9, + 168, + 63, + 117, + 247, + 35, + 53, + 97, + 246, + 190, + 129, + 63, + 26, + 240, + 142, + 69, + 155, + 44, + 200, + 83, + 43, + 10, + 180, + 204, + 87, + 22, + 33, + 181, + 217, + 211, + 224, + 80, + 73, + 46, + 84, + 66, + 130, + 222, + 235, + 146, + 76, + 50, + 175, + 201, + 244, + 175, + 7, + 166, + 31, + 164, + 219, + 230, + 81, + 19, + 26, + 18, + 230, + 149, + 241, + 243, + 97, + 172, + 149, + 205, + 10, + 107, + 168, + 240, + 175, + 145, + 172, + 107, + 16, + 91, + 209, + 17, + 203, + 171, + 30, + 124, + 79, + 63, + 47, + 213, + 5, + 207, + 173, + 98, + 137, + 154, + 254, + 80, + 226, + 253, + 74, + 156, + 229, + 203, + 229, + 67, + 6, + 233, + 227, + 97, + 187, + 68, + 32, + 18, + 210, + 28, + 40, + 72, + 94, + 204, + 99, + 106, + 37, + 166, + 58, + 53, + 59, + 241, + 95, + 88, + 87, + 36, + 3, + 158, + 14, + 14, + 140, + 195, + 195, + 94, + 227, + 237, + 81, + 219, + 125, + 179, + 13, + 169, + 26, + 52, + 60, + 78, + 228, + 136, + 71, + 84, + 62, + 110, + 3, + 160, + 88, + 15, + 50, + 90, + 252, + 207, + 168, + 157, + 50, + 70, + 163, + 106, + 234, + 88, + 223, + 226, + 177, + 43, + 220, + 140, + 33, + 89, + 1, + 32, + 219, + 213, + 94, + 187, + 206, + 59, + 106, + 190, + 228, + 142, + 134, + 59, + 198, + 73, + 98, + 178, + 24, + 12, + 165, + 77, + 4, + 17, + 210, + 225, + 32, + 14, + 160, + 157, + 112, + 99, + 179, + 231, + 197, + 111, + 73, + 140, + 254, + 76, + 227, + 103, + 88, + 134, + 54, + 121, + 37, + 81, + 172, + 89, + 120, + 71, + 41, + 107, + 165, + 187, + 38, + 228, + 219, + 236, + 141, + 166, + 96, + 251, + 36, + 15, + 181, + 57, + 18, + 199, + 32, + 220, + 220, + 141, + 164, + 54, + 86, + 20, + 251, + 95, + 21, + 173, + 138, + 212, + 67, + 154, + 52, + 88, + 76, + 126, + 98, + 177, + 66, + 111, + 243, + 176, + 183, + 3, + 114, + 65, + 105, + 218, + 116, + 184, + 222, + 215, + 166, + 51, + 120, + 116, + 155, + 3, + 47, + 210, + 45, + 151, + 254, + 193, + 43, + 203, + 58, + 125, + 197, + 182, + 134, + 63, + 19, + 32, + 47, + 135, + 155, + 121, + 17, + 227, + 70, + 52, + 217, + 147, + 9, + 255, + 83, + 138, + 122, + 225, + 82, + 231, + 6, + 37, + 97, + 255, + 119, + 39, + 73, + 217, + 199, + 15, + 179, + 214, + 36, + 208, + 57, + 5, + 176, + 48, + 24, + 249, + 190, + 88, + 210, + 143, + 126, + 85, + 254, + 11, + 30, + 169, + 75, + 189, + 38, + 71, + 53, + 238, + 62, + 37, + 48, + 84, + 148, + 253, + 40, + 220, + 135, + 104, + 14, + 88, + 93, + 168, + 3, + 108, + 93, + 198, + 12, + 152, + 206, + 146, + 121, + 212, + 157, + 187, + 115, + 120, + 95, + 255, + 137, + 73, + 111, + 19, + 194, + 245, + 170, + 120, + 97, + 182, + 125, + 223, + 149, + 129, + 28, + 96, + 56, + 222, + 199, + 114, + 34, + 185, + 201, + 139, + 16, + 158, + 219, + 19, + 72, + 55, + 125, + 101, + 111, + 53, + 218, + 81, + 63, + 183, + 20, + 34, + 11, + 45, + 162, + 7, + 69, + 24, + 64, + 129, + 37, + 115, + 13, + 254, + 128, + 212, + 19, + 164, + 231, + 70, + 142, + 9, + 96, + 93, + 70, + 140, + 35, + 5, + 131, + 220, + 219, + 43, + 55, + 34, + 227, + 15, + 43, + 153, + 75, + 185, + 57, + 95, + 81, + 132, + 154, + 108, + 71, + 19, + 179, + 28, + 197, + 107, + 84, + 112, + 97, + 160, + 237, + 3, + 2, + 155, + 16, + 91, + 179, + 160, + 0, + 154, + 212, + 44, + 29, + 144, + 120, + 62, + 197, + 79, + 13, + 40, + 241, + 152, + 20, + 194, + 192, + 117, + 1, + 209, + 84, + 1, + 209, + 38, + 204, + 115, + 166, + 139, + 176, + 124, + 30, + 253, + 152, + 11, + 143, + 96, + 136, + 183, + 6, + 103, + 139, + 170, + 62, + 121, + 68, + 169, + 135, + 195, + 40, + 247, + 83, + 240, + 83, + 232, + 98, + 124, + 169, + 204, + 100, + 19, + 201, + 222, + 240, + 80, + 104, + 0, + 41, + 80, + 55, + 101, + 34, + 247, + 178, + 108, + 20, + 247, + 39, + 185, + 116, + 197, + 49, + 32, + 96, + 20, + 224, + 195, + 58, + 25, + 135, + 2, + 120, + 91, + 22, + 176, + 214, + 233, + 102, + 71, + 7, + 191, + 165, + 249, + 180, + 230, + 238, + 148, + 0, + 237, + 151, + 133, + 26, + 80, + 97, + 131, + 1, + 104, + 180, + 101, + 253, + 181, + 137, + 101, + 247, + 147, + 116, + 55, + 243, + 88, + 25, + 192, + 124, + 94, + 105, + 254, + 209, + 209, + 130, + 77, + 16, + 93, + 158, + 188, + 60, + 173, + 126, + 198, + 17, + 75, + 110, + 244, + 146, + 171, + 127, + 157, + 3, + 95, + 175, + 35, + 197, + 28, + 223, + 9, + 196, + 238, + 202, + 217, + 180, + 66, + 128, + 12, + 79, + 154, + 1, + 131, + 243, + 113, + 74, + 157, + 48, + 190, + 157, + 27, + 109, + 118, + 187, + 208, + 4, + 28, + 206, + 240, + 242, + 22, + 102, + 181, + 146, + 235, + 78, + 153, + 241, + 70, + 132, + 123, + 93, + 219, + 234, + 169, + 119, + 1, + 122, + 249, + 212, + 0, + 227, + 24, + 187, + 125, + 235, + 187, + 10, + 11, + 46, + 20, + 58, + 7, + 108, + 125, + 1, + 86, + 198, + 100, + 46, + 142, + 20, + 76, + 64, + 87, + 121, + 166, + 144, + 95, + 175, + 210, + 99, + 154, + 85, + 175, + 191, + 233, + 69, + 232, + 174, + 144, + 220, + 129, + 96, + 189, + 73, + 242, + 173, + 225, + 21, + 249, + 137, + 254, + 120, + 61, + 112, + 169, + 14, + 71, + 65, + 48, + 236, + 181, + 165, + 236, + 88, + 177, + 210, + 105, + 163, + 237, + 210, + 53, + 25, + 197, + 48, + 252, + 253, + 148, + 174, + 106, + 217, + 57, + 134, + 43, + 250, + 60, + 105, + 150, + 101, + 32, + 218, + 43, + 73, + 200, + 96, + 55, + 0, + 114, + 220, + 140, + 34, + 40, + 81, + 38, + 159, + 200, + 13, + 164, + 48, + 253, + 27, + 85, + 8, + 80, + 56, + 140, + 228, + 131, + 23, + 61, + 252, + 184, + 193, + 173, + 40, + 132, + 237, + 155, + 208, + 22, + 88, + 230, + 40, + 7, + 8, + 22, + 228, + 46, + 216, + 231, + 247, + 79, + 132, + 179, + 12, + 11, + 248, + 179, + 32, + 158, + 50, + 28, + 53, + 194, + 61, + 107, + 160, + 227, + 5, + 129, + 94, + 92, + 53, + 230, + 181, + 212, + 156, + 20, + 154, + 144, + 84, + 2, + 193, + 71, + 120, + 88, + 233, + 117, + 178, + 8, + 231, + 182, + 69, + 142, + 33, + 165, + 113, + 196, + 133, + 154, + 49, + 61, + 69, + 151, + 64, + 59, + 88, + 135, + 104, + 79, + 65, + 254, + 150, + 143, + 211, + 189, + 202, + 199, + 110, + 211, + 6, + 22, + 225, + 205, + 24, + 48, + 244, + 152, + 130, + 3, + 250, + 82, + 248, + 130, + 168, + 81, + 189, + 207, + 152, + 122, + 179, + 83, + 168, + 5, + 107, + 170, + 200, + 9, + 139, + 41, + 76, + 47, + 212, + 9, + 63, + 228, + 62, + 30, + 217, + 194, + 179, + 115, + 92, + 161, + 171, + 207, + 116, + 146, + 137, + 126, + 51, + 87, + 29, + 189, + 169, + 232, + 165, + 245, + 7, + 185, + 35, + 209, + 32, + 174, + 158, + 47, + 207, + 188, + 45, + 46, + 220, + 56, + 202, + 41, + 235, + 54, + 92, + 112, + 201, + 35, + 213, + 71, + 104, + 68, + 123, + 22, + 231, + 103, + 21, + 236, + 83, + 206, + 178, + 135, + 149, + 213, + 29, + 159, + 149, + 184, + 6, + 41, + 68, + 61, + 115, + 37, + 118, + 167, + 15, + 225, + 218, + 59, + 67, + 70, + 86, + 11, + 117, + 127, + 112, + 147, + 1, + 191, + 120, + 168, + 90, + 119, + 156, + 38, + 153, + 197, + 25, + 235, + 20, + 5, + 106, + 135, + 43, + 98, + 183, + 104, + 65, + 144, + 126, + 152, + 7, + 252, + 78, + 164, + 176, + 123, + 51, + 17, + 96, + 142, + 179, + 179, + 146, + 235, + 158, + 248, + 136, + 4, + 145, + 230, + 45, + 238, + 42, + 199, + 179, + 151, + 214, + 193, + 90, + 146, + 169, + 145, + 76, + 70, + 204, + 163, + 227, + 66, + 91, + 16, + 188, + 197, + 230, + 137, + 66, + 160, + 110, + 96, + 113, + 89, + 204, + 53, + 79, + 90, + 108, + 156, + 201, + 5, + 23, + 50, + 95, + 198, + 50, + 195, + 60, + 225, + 186, + 214, + 74, + 2, + 105, + 125, + 200, + 2, + 245, + 243, + 143, + 30, + 81, + 71, + 56, + 238, + 180, + 76, + 1, + 64, + 214, + 137, + 69, + 164, + 31, + 254, + 75, + 150, + 157, + 16, + 54, + 141, + 93, + 20, + 234, + 124, + 50, + 60, + 2, + 126, + 79, + 75, + 225, + 152, + 118, + 227, + 167, + 225, + 144, + 202, + 52, + 157, + 45, + 35, + 44, + 182, + 199, + 120, + 12, + 10, + 120, + 238, + 44, + 120, + 241, + 108, + 123, + 136, + 79, + 117, + 107, + 68, + 253, + 74, + 152, + 8, + 209, + 139, + 103, + 3, + 180, + 94, + 16, + 204, + 84, + 24, + 12, + 247, + 50, + 84, + 134, + 251, + 229, + 250, + 34, + 184, + 25, + 214, + 152, + 130, + 236, + 227, + 9, + 101, + 244, + 245, + 86, + 224, + 203, + 175, + 131, + 61, + 18, + 2, + 40, + 167, + 224, + 190, + 165, + 46, + 228, + 246, + 43, + 4, + 63, + 34, + 18, + 114, + 15, + 45, + 93, + 169, + 150, + 196, + 73, + 74, + 166, + 228, + 49, + 24, + 17, + 197, + 21, + 36, + 221, + 107, + 2, + 188, + 28, + 30, + 233, + 113, + 211, + 59, + 1, + 36, + 181, + 161, + 245, + 92, + 13, + 255, + 93, + 221, + 135, + 94, + 6, + 213, + 187, + 188, + 16, + 152, + 88, + 65, + 223, + 67, + 241, + 11, + 98, + 61, + 199, + 22, + 73, + 71, + 203, + 142, + 33, + 28, + 229, + 72, + 83, + 215, + 5, + 54, + 203, + 158, + 234, + 212, + 165, + 103, + 213, + 14, + 189, + 105, + 143, + 202, + 255, + 72, + 130, + 158, + 85, + 49, + 87, + 68, + 137, + 89, + 54, + 196, + 110, + 109, + 50, + 48, + 201, + 49, + 51, + 20, + 137, + 223, + 9, + 7, + 60, + 219, + 207, + 242, + 240, + 46, + 15, + 154, + 199, + 247, + 224, + 209, + 102, + 190, + 31, + 148, + 101, + 189, + 84, + 195, + 2, + 176, + 245, + 195, + 236, + 54, + 176, + 56, + 246, + 109, + 197, + 49, + 36, + 29, + 18, + 239, + 0, + 26, + 58, + 9, + 32, + 8, + 134, + 190, + 87, + 29, + 183, + 49, + 233, + 255, + 34, + 149, + 253, + 3, + 4, + 180, + 74, + 11, + 215, + 201, + 10, + 151, + 80, + 0, + 234, + 162, + 162, + 140, + 57, + 106, + 0, + 71, + 41, + 185, + 23, + 135, + 55, + 202, + 148, + 100, + 100, + 26, + 99, + 2, + 218, + 148, + 218, + 115, + 97, + 201, + 65, + 30, + 103, + 195, + 46, + 127, + 120, + 22, + 222, + 46, + 177, + 23, + 104, + 241, + 10, + 66, + 75, + 1, + 73, + 182, + 61, + 60, + 103, + 107, + 142, + 142, + 7, + 234, + 38, + 148, + 65, + 31, + 197, + 56, + 158, + 208, + 59, + 74, + 248, + 59, + 202, + 187, + 235, + 121, + 75, + 235, + 101, + 107, + 246, + 28, + 54, + 45, + 217, + 39, + 136, + 179, + 125, + 206, + 197, + 76, + 80, + 132, + 55, + 250, + 52, + 145, + 207, + 57, + 28, + 61, + 4, + 217, + 16, + 12, + 62, + 34, + 15, + 188, + 21, + 156, + 127, + 223, + 113, + 11, + 201, + 163, + 158, + 173, + 9, + 121, + 127, + 130, + 242, + 100, + 20, + 229, + 199, + 58, + 186, + 231, + 37, + 210, + 205, + 159, + 209, + 167, + 105, + 241, + 8, + 54, + 219, + 137, + 235, + 46, + 51, + 142, + 231, + 62, + 192, + 196, + 241, + 168, + 246, + 87, + 66, + 57, + 236, + 60, + 122, + 64, + 137, + 84, + 178, + 102, + 96, + 158, + 164, + 202, + 60, + 241, + 154, + 98, + 236, + 214, + 119, + 17, + 27, + 2, + 159, + 163, + 105, + 128, + 33, + 206, + 50, + 97, + 15, + 248, + 92, + 46, + 89, + 53, + 222, + 60, + 10, + 27, + 218, + 86, + 65, + 38, + 206, + 39, + 145, + 75, + 128, + 52, + 119, + 199, + 46, + 243, + 185, + 175, + 119, + 70, + 217, + 212, + 170, + 18, + 106, + 186, + 248, + 56, + 222, + 206, + 189, + 167, + 22, + 247, + 158, + 187, + 255, + 29, + 178, + 210, + 143, + 107, + 79, + 105, + 206, + 119, + 74, + 118, + 23, + 95, + 6, + 88, + 174, + 133, + 115, + 210, + 186, + 67, + 48, + 19, + 57, + 59, + 42, + 132, + 19, + 52, + 80, + 229, + 37, + 237, + 42, + 106, + 82, + 55, + 154, + 109, + 60, + 216, + 27, + 193, + 44, + 142, + 225, + 46, + 113, + 56, + 117, + 232, + 157, + 180, + 159, + 118, + 144, + 1, + 53, + 213, + 55, + 58, + 50, + 54, + 116, + 186, + 248, + 160, + 76, + 204, + 163, + 52, + 13, + 247, + 115, + 133, + 192, + 56, + 59, + 137, + 11, + 57, + 248, + 169, + 120, + 185, + 25, + 157, + 217, + 239, + 190, + 153, + 161, + 103, + 237, + 147, + 36, + 118, + 221, + 23, + 192, + 254, + 130, + 49, + 234, + 202, + 97, + 59, + 60, + 111, + 244, + 79, + 12, + 254, + 45, + 185, + 216, + 75, + 219, + 216, + 25, + 37, + 240, + 44, + 162, + 102, + 124, + 79, + 247, + 47, + 104, + 181, + 147, + 179, + 249, + 34, + 157, + 254, + 88, + 56, + 212, + 236, + 61, + 144, + 227, + 159, + 156, + 184, + 200, + 151, + 131, + 196, + 47, + 11, + 249, + 90, + 4, + 221, + 250, + 238, + 125, + 17, + 43, + 91, + 89, + 195, + 204, + 191, + 190, + 118, + 71, + 6, + 74, + 148, + 169, + 18, + 202, + 155, + 147, + 237, + 232, + 233, + 185, + 174, + 191, + 207, + 67, + 103, + 88, + 196, + 247, + 49, + 211, + 200, + 11, + 248, + 180, + 175, + 37, + 183, + 211, + 226, + 27, + 21, + 179, + 117, + 221, + 40, + 188, + 36, + 31, + 171, + 211, + 41, + 98, + 208, + 207, + 248, + 93, + 227, + 13, + 129, + 228, + 127, + 126, + 54, + 193, + 16, + 78, + 112, + 27, + 161, + 144, + 195, + 33, + 252, + 198, + 217, + 45, + 37, + 45, + 23, + 79, + 181, + 254, + 204, + 41, + 197, + 128, + 92, + 35, + 33, + 156, + 150, + 6, + 166, + 182, + 75, + 220, + 85, + 222, + 215, + 102, + 39, + 179, + 124, + 16, + 206, + 77, + 114, + 31, + 179, + 37, + 62, + 109, + 52, + 218, + 203, + 156, + 137, + 173, + 8, + 48, + 87, + 146, + 84, + 4, + 58, + 90, + 190, + 236, + 168, + 155, + 96, + 42, + 100, + 110, + 226, + 4, + 50, + 130, + 50, + 5, + 189, + 224, + 118, + 85, + 99, + 221, + 35, + 7, + 14, + 30, + 56, + 98, + 211, + 193, + 94, + 17, + 240, + 135, + 140, + 156, + 185, + 220, + 105, + 21, + 113, + 219, + 111, + 104, + 129, + 226, + 54, + 216, + 183, + 145, + 17, + 226, + 235, + 158, + 43, + 66, + 138, + 47, + 200, + 247, + 148, + 242, + 235, + 11, + 58, + 223, + 140, + 82, + 244, + 227, + 111, + 99, + 27, + 28, + 3, + 18, + 59, + 106, + 198, + 159, + 60, + 147, + 22, + 76, + 240, + 63, + 99, + 175, + 237, + 67, + 139, + 90, + 66, + 32, + 50, + 79, + 10, + 21, + 253, + 199, + 96, + 82, + 100, + 77, + 36, + 41, + 126, + 64, + 168, + 199, + 18, + 151, + 238, + 86, + 239, + 240, + 228, + 194, + 182, + 170, + 148, + 39, + 235, + 43, + 93, + 254, + 227, + 85, + 146, + 100, + 60, + 112, + 122, + 0, + 133, + 30, + 151, + 106, + 224, + 48, + 186, + 51, + 54, + 95, + 196, + 81, + 25, + 137, + 236, + 237, + 94, + 29, + 199, + 163, + 198, + 233, + 99, + 8, + 125, + 181, + 115, + 40, + 115, + 46, + 174, + 68, + 74, + 217, + 170, + 30, + 37, + 67, + 120, + 134, + 191, + 40, + 236, + 121, + 60, + 153, + 126, + 174, + 213, + 84, + 110, + 34, + 224, + 182, + 221, + 160, + 212, + 125, + 122, + 8, + 254, + 216, + 207, + 128, + 46, + 16, + 123, + 44, + 216, + 57, + 150, + 152, + 145, + 203, + 93, + 248, + 142, + 118, + 219, + 52, + 97, + 40, + 12, + 183, + 233, + 4, + 126, + 233, + 147, + 198, + 216, + 109, + 28, + 21, + 229, + 216, + 191, + 254, + 171, + 205, + 225, + 75, + 177, + 255, + 59, + 67, + 186, + 216, + 187, + 184, + 196, + 131, + 118, + 162, + 58, + 12, + 82, + 87, + 182, + 124, + 192, + 206, + 95, + 157, + 206, + 32, + 65, + 22, + 208, + 79, + 112, + 84, + 35, + 40, + 173, + 106, + 98, + 213, + 119, + 161, + 143, + 198, + 15, + 249, + 1, + 93, + 63, + 58, + 47, + 208, + 155, + 146, + 182, + 53, + 122, + 140, + 92, + 234, + 177, + 233, + 0, + 53, + 107, + 42, + 94, + 62, + 137, + 0, + 245, + 160, + 148, + 25, + 189, + 56, + 109, + 140, + 40, + 26, + 153, + 61, + 96, + 54, + 224, + 116, + 18, + 241, + 163, + 37, + 234, + 151, + 164, + 253, + 127, + 102, + 87, + 136, + 243, + 20, + 95, + 110, + 118, + 150, + 243, + 206, + 108, + 8, + 23, + 112, + 140, + 135, + 26, + 236, + 223, + 222, + 156, + 240, + 85, + 244, + 138, + 147, + 170, + 92, + 130, + 5, + 84, + 150, + 125, + 34, + 196, + 98, + 207, + 131, + 60, + 255, + 0, + 203, + 85, + 244, + 4, + 48, + 79, + 174, + 210, + 163, + 248, + 201, + 175, + 53, + 83, + 249, + 253, + 31, + 103, + 144, + 68, + 160, + 39, + 197, + 9, + 252, + 76, + 12, + 251, + 84, + 198, + 81, + 10, + 190, + 57, + 238, + 219, + 123, + 139, + 240, + 142, + 222, + 224, + 47, + 28, + 27, + 238, + 129, + 50, + 8, + 157, + 35, + 89, + 3, + 155, + 88, + 187, + 131, + 251, + 51, + 167, + 116, + 69, + 165, + 168, + 24, + 230, + 166, + 119, + 219, + 127, + 146, + 168, + 39, + 231, + 22, + 197, + 222, + 227, + 44, + 211, + 189, + 99, + 139, + 83, + 9, + 153, + 63, + 162, + 253, + 0, + 12, + 66, + 12, + 252, + 187, + 68, + 88, + 226, + 176, + 164, + 127, + 202, + 68, + 180, + 94, + 163, + 227, + 41, + 0, + 114, + 12, + 75, + 161, + 8, + 165, + 203, + 240, + 121, + 31, + 0, + 76, + 246, + 101, + 2, + 177, + 76, + 84, + 16, + 118, + 79, + 38, + 169, + 208, + 231, + 178, + 62, + 201, + 190, + 201, + 204, + 118, + 87, + 144, + 100, + 154, + 135, + 85, + 26, + 16, + 22, + 173, + 98, + 183, + 98, + 29, + 68, + 173, + 149, + 127, + 180, + 164, + 112, + 167, + 214, + 254, + 118, + 73, + 12, + 141, + 95, + 214, + 128, + 219, + 71, + 73, + 56, + 8, + 107, + 151, + 34, + 245, + 211, + 224, + 65, + 61, + 229, + 79, + 251, + 46, + 171, + 33, + 225, + 118, + 223, + 220, + 40, + 239, + 203, + 245, + 185, + 88, + 10, + 254, + 22, + 21, + 111, + 107, + 122, + 106, + 189, + 15, + 78, + 98, + 9, + 112, + 23, + 144, + 195, + 45, + 237, + 124, + 122, + 132, + 33, + 162, + 99, + 88, + 62, + 23, + 122, + 218, + 223, + 188, + 191, + 94, + 182, + 216, + 163, + 150, + 168, + 11, + 95, + 116, + 227, + 210, + 94, + 152, + 97, + 214, + 203, + 58, + 140, + 77, + 136, + 31, + 6, + 70, + 46, + 167, + 22, + 141, + 85, + 46, + 56, + 240, + 95, + 80, + 100, + 142, + 97, + 206, + 63, + 24, + 103, + 80, + 190, + 82, + 252, + 111, + 10, + 163, + 218, + 72, + 7, + 247, + 216, + 161, + 121, + 44, + 137, + 101, + 35, + 4, + 203, + 6, + 159, + 82, + 25, + 143, + 12, + 171, + 142, + 62, + 2, + 69, + 245, + 255, + 74, + 140, + 19, + 186, + 43, + 109, + 59, + 85, + 101, + 34, + 74, + 74, + 14, + 57, + 152, + 218, + 141, + 245, + 148, + 170, + 17, + 58, + 239, + 104, + 59, + 237, + 178, + 212, + 172, + 60, + 23, + 213, + 235, + 93, + 158, + 214, + 31, + 147, + 255, + 105, + 21, + 130, + 60, + 217, + 240, + 60, + 187, + 65, + 73, + 249, + 99, + 56, + 81, + 84, + 253, + 50, + 65, + 16, + 167, + 25, + 34, + 203, + 245, + 252, + 114, + 24, + 63, + 88, + 29, + 49, + 120, + 76, + 61, + 235, + 115, + 74, + 155, + 84, + 244, + 16, + 214, + 84, + 70, + 245, + 183, + 3, + 146, + 166, + 32, + 92, + 148, + 139, + 208, + 173, + 52, + 180, + 181, + 203, + 167, + 254, + 144, + 198, + 171, + 22, + 35, + 238, + 41, + 58, + 237, + 156, + 3, + 27, + 250, + 78, + 75, + 120, + 202, + 202, + 218, + 87, + 77, + 21, + 130, + 126, + 63, + 42, + 114, + 236, + 78, + 90, + 62, + 94, + 45, + 126, + 134, + 110, + 80, + 152, + 113, + 153, + 21, + 218, + 177, + 224, + 73, + 141, + 245, + 249, + 68, + 244, + 109, + 248, + 248, + 206, + 91, + 112, + 105, + 32, + 145, + 216, + 137, + 23, + 72, + 121, + 4, + 56, + 44, + 17, + 62, + 84, + 179, + 186, + 71, + 49, + 52, + 131, + 95, + 158, + 122, + 208, + 224, + 68, + 207, + 187, + 20, + 131, + 192, + 143, + 80, + 185, + 179, + 220, + 162, + 25, + 110, + 193, + 104, + 126, + 39, + 69, + 133, + 157, + 123, + 170, + 193, + 39, + 116, + 137, + 32, + 27, + 186, + 223, + 77, + 174, + 118, + 59, + 192, + 77, + 140, + 53, + 6, + 78, + 215, + 192, + 177, + 75, + 178, + 172, + 212, + 249, + 213, + 35, + 188, + 110, + 181, + 242, + 1, + 242, + 7, + 193, + 197, + 59, + 41, + 93, + 65, + 160, + 165, + 36, + 19, + 248, + 180, + 71, + 204, + 58, + 64, + 99, + 19, + 29, + 43, + 253, + 185, + 24, + 249, + 16, + 21, + 241, + 248, + 146, + 142, + 117, + 245, + 92, + 194, + 148, + 35, + 226, + 107, + 33, + 40, + 13, + 10, + 243, + 23, + 72, + 108, + 210, + 12, + 206, + 133, + 137, + 200, + 67, + 219, + 22, + 179, + 5, + 3, + 56, + 87, + 94, + 211, + 164, + 63, + 119, + 141, + 154, + 105, + 105, + 78, + 180, + 200, + 26, + 197, + 221, + 218, + 66, + 9, + 49, + 243, + 250, + 103, + 87, + 200, + 114, + 174, + 200, + 245, + 41, + 198, + 64, + 232, + 9, + 226, + 217, + 191, + 222, + 163, + 47, + 44, + 146, + 157, + 227, + 208, + 44, + 4, + 67, + 138, + 47, + 175, + 156, + 198, + 81, + 95, + 253, + 91, + 133, + 7, + 187, + 102, + 74, + 203, + 35, + 206, + 94, + 86, + 175, + 4, + 172, + 6, + 35, + 97, + 155, + 222, + 255, + 158, + 75, + 141, + 72, + 189, + 167, + 47, + 173, + 102, + 150, + 180, + 252, + 77, + 55, + 187, + 81, + 188, + 24, + 122, + 129, + 40, + 21, + 230, + 58, + 225, + 195, + 104, + 27, + 170, + 225, + 80, + 53, + 110, + 39, + 172, + 164, + 19, + 201, + 54, + 30, + 161, + 145, + 132, + 156, + 70, + 140, + 163, + 205, + 68, + 88, + 168, + 197, + 45, + 129, + 246, + 111, + 57, + 191, + 140, + 10, + 34, + 253, + 128, + 41, + 195, + 237, + 182, + 64, + 174, + 150, + 200, + 32, + 25, + 182, + 134, + 104, + 118, + 2, + 194, + 52, + 190, + 92, + 198, + 26, + 89, + 200, + 236, + 75, + 97, + 29, + 226, + 195, + 144, + 33, + 27, + 48, + 184, + 106, + 58, + 116, + 217, + 16, + 83, + 222, + 142, + 106, + 155, + 79, + 240, + 199, + 114, + 232, + 230, + 108, + 41, + 248, + 121, + 224, + 254, + 236, + 240, + 95, + 236, + 137, + 238, + 181, + 6, + 30, + 222, + 73, + 211, + 245, + 242, + 158, + 75, + 239, + 42, + 203, + 112, + 246, + 84, + 99, + 186, + 228, + 10, + 64, + 63, + 1, + 27, + 124, + 25, + 180, + 17, + 88, + 4, + 105, + 102, + 18, + 83, + 196, + 82, + 184, + 66, + 154, + 128, + 57, + 253, + 179, + 88, + 92, + 169, + 170, + 65, + 26, + 207, + 82, + 105, + 23, + 4, + 226, + 91, + 3, + 17, + 101, + 114, + 175, + 180, + 152, + 213, + 253, + 213, + 199, + 27, + 102, + 70, + 205, + 80, + 192, + 110, + 158, + 15, + 46, + 116, + 54, + 143, + 4, + 4, + 92, + 199, + 70, + 148, + 105, + 235, + 254, + 193, + 85, + 71, + 233, + 196, + 47, + 66, + 81, + 54, + 163, + 94, + 247, + 106, + 38, + 86, + 129, + 122, + 59, + 198, + 197, + 17, + 188, + 14, + 171, + 150, + 29, + 91, + 33, + 239, + 237, + 6, + 70, + 138, + 59, + 68, + 128, + 118, + 214, + 218, + 178, + 49, + 204, + 229, + 47, + 118, + 176, + 125, + 145, + 12, + 97, + 139, + 149, + 123, + 60, + 124, + 56, + 12, + 10, + 108, + 19, + 34, + 33, + 174, + 68, + 176, + 177, + 221, + 140, + 73, + 97, + 16, + 9, + 51, + 207, + 92, + 188, + 229, + 35, + 161, + 58, + 26, + 100, + 36, + 98, + 82, + 222, + 124, + 74, + 245, + 24, + 236, + 109, + 68, + 155, + 174, + 153, + 50, + 202, + 163, + 115, + 27, + 71, + 116, + 30, + 86, + 116, + 166, + 196, + 81, + 45, + 98, + 169, + 128, + 109, + 234, + 252, + 193, + 5, + 113, + 34, + 48, + 63, + 100, + 93, + 64, + 2, + 53, + 48, + 110, + 37, + 40, + 60, + 155, + 160, + 6, + 244, + 76, + 104, + 144, + 22, + 187, + 192, + 147, + 0, + 152, + 203, + 145, + 33, + 233, + 151, + 204, + 46, + 64, + 92, + 237, + 95, + 22, + 230, + 194, + 91, + 59, + 205, + 191, + 171, + 61, + 108, + 113, + 60, + 152, + 34, + 131, + 73, + 227, + 221, + 188, + 225, + 158, + 228, + 236, + 17, + 236, + 220, + 190, + 187, + 223, + 32, + 169, + 65, + 46, + 199, + 52, + 85, + 145, + 136, + 170, + 2, + 188, + 235, + 171, + 96, + 28, + 128, + 150, + 10, + 240, + 10, + 93, + 187, + 32, + 62, + 40, + 68, + 240, + 87, + 87, + 210, + 30, + 73, + 88, + 33, + 23, + 247, + 183, + 86, + 243, + 58, + 132, + 106, + 71, + 50, + 158, + 19, + 152, + 13, + 248, + 111, + 84, + 86, + 85, + 84, + 65, + 221, + 19, + 116, + 115, + 182, + 199, + 67, + 171, + 26, + 227, + 90, + 100, + 196, + 140, + 239, + 210, + 173, + 50, + 150, + 72, + 66, + 110, + 107, + 28, + 163, + 144, + 237, + 129, + 221, + 126, + 186, + 223, + 72, + 140, + 17, + 163, + 2, + 7, + 78, + 228, + 94, + 115, + 69, + 196, + 83, + 195, + 112, + 165, + 205, + 187, + 181, + 63, + 153, + 148, + 234, + 238, + 33, + 70, + 238, + 40, + 31, + 149, + 239, + 246, + 76, + 175, + 60, + 194, + 136, + 165, + 86, + 75, + 224, + 75, + 62, + 34, + 219, + 177, + 36, + 230, + 6, + 98, + 33, + 95, + 75, + 7, + 240, + 160, + 5, + 11, + 1, + 133, + 180, + 124, + 178, + 163, + 51, + 45, + 178, + 248, + 109, + 252, + 159, + 90, + 64, + 7, + 41, + 146, + 190, + 124, + 188, + 142, + 229, + 133, + 251, + 111, + 33, + 222, + 19, + 242, + 241, + 102, + 17, + 94, + 6, + 194, + 90, + 175, + 105, + 104, + 140, + 175, + 45, + 50, + 236, + 227, + 86, + 254, + 101, + 236, + 70, + 163, + 239, + 2, + 14, + 151, + 146, + 132, + 203, + 240, + 89, + 67, + 134, + 169, + 101, + 244, + 92, + 124, + 249, + 51, + 132, + 226, + 216, + 249, + 248, + 51, + 11, + 11, + 207, + 174, + 80, + 21, + 110, + 209, + 116, + 187, + 84, + 226, + 196, + 225, + 136, + 188, + 58, + 37, + 49, + 18, + 20, + 220, + 29, + 248, + 17, + 46, + 210, + 135, + 179, + 74, + 140, + 23, + 217, + 211, + 161, + 120, + 9, + 157, + 28, + 41, + 45, + 155, + 174, + 102, + 156, + 51, + 76, + 68, + 51, + 203, + 22, + 187, + 155, + 59, + 239, + 90, + 151, + 160, + 200, + 229, + 209, + 121, + 139, + 190, + 115, + 20, + 110, + 240, + 16, + 249, + 12, + 94, + 210, + 151, + 194, + 48, + 182, + 248, + 117, + 33, + 219, + 198, + 40, + 56, + 233, + 4, + 207, + 163, + 97, + 135, + 88, + 31, + 151, + 215, + 213, + 10, + 195, + 41, + 163, + 136, + 21, + 69, + 139, + 7, + 101, + 59, + 188, + 82, + 17, + 176, + 215, + 30, + 88, + 139, + 52, + 49, + 59, + 230, + 238, + 183, + 142, + 237, + 231, + 148, + 130, + 79, + 239, + 153, + 181, + 59, + 14, + 103, + 84, + 12, + 70, + 155, + 43, + 25, + 20, + 226, + 211, + 82, + 73, + 160, + 235, + 150, + 116, + 223, + 222, + 243, + 140, + 9, + 134, + 227, + 30, + 225, + 71, + 130, + 101, + 41, + 21, + 198, + 31, + 136, + 6, + 40, + 99, + 112, + 120, + 98, + 82, + 211, + 98, + 250, + 209, + 225, + 0, + 173, + 98, + 109, + 201, + 167, + 200, + 245, + 162, + 118, + 45, + 53, + 177, + 85, + 52, + 150, + 42, + 175, + 112, + 251, + 50, + 130, + 74, + 63, + 130, + 56, + 162, + 227, + 187, + 255, + 5, + 79, + 212, + 62, + 202, + 49, + 56, + 12, + 152, + 195, + 138, + 255, + 32, + 185, + 122, + 169, + 34, + 84, + 211, + 135, + 89, + 207, + 47, + 119, + 15, + 156, + 152, + 205, + 92, + 38, + 155, + 207, + 177, + 25, + 0, + 253, + 166, + 145, + 83, + 136, + 113, + 57, + 147, + 51, + 134, + 54, + 11, + 95, + 235, + 193, + 46, + 105, + 163, + 137, + 6, + 177, + 128, + 64, + 12, + 207, + 243, + 23, + 134, + 110, + 39, + 227, + 15, + 94, + 230, + 204, + 118, + 182, + 18, + 141, + 51, + 186, + 180, + 154, + 1, + 117, + 200, + 163, + 32, + 86, + 253, + 140, + 87, + 185, + 242, + 185, + 114, + 9, + 211, + 170, + 165, + 186, + 89, + 92, + 173, + 53, + 123, + 140, + 39, + 29, + 230, + 214, + 227, + 53, + 54, + 226, + 159, + 10, + 42, + 150, + 77, + 195, + 36, + 69, + 87, + 217, + 209, + 152, + 64, + 115, + 243, + 59, + 229, + 129, + 18, + 3, + 22, + 38, + 91, + 7, + 211, + 41, + 219, + 133, + 80, + 9, + 168, + 156, + 44, + 84, + 72, + 3, + 161, + 34, + 200, + 249, + 63, + 54, + 118, + 78, + 181, + 82, + 229, + 178, + 199, + 136, + 151, + 219, + 244, + 11, + 98, + 163, + 32, + 200, + 1, + 70, + 173, + 63, + 34, + 55, + 247, + 122, + 125, + 165, + 187, + 70, + 128, + 191, + 0, + 200, + 226, + 206, + 146, + 205, + 171, + 75, + 197, + 232, + 41, + 12, + 127, + 133, + 156, + 239, + 44, + 26, + 26, + 60, + 250, + 226, + 190, + 85, + 114, + 83, + 242, + 51, + 200, + 231, + 158, + 96, + 101, + 114, + 119, + 49, + 81, + 39, + 251, + 115, + 228, + 161, + 39, + 88, + 79, + 41, + 151, + 149, + 250, + 94, + 33, + 111, + 17, + 157, + 97, + 246, + 207, + 94, + 136, + 85, + 120, + 2, + 129, + 124, + 91, + 230, + 6, + 83, + 195, + 28, + 143, + 110, + 128, + 169, + 253, + 45, + 246, + 100, + 40, + 232, + 188, + 1, + 26, + 31, + 212, + 128, + 191, + 92, + 105, + 21, + 84, + 49, + 221, + 104, + 97, + 51, + 15, + 233, + 116, + 163, + 55, + 106, + 10, + 137, + 34, + 141, + 184, + 152, + 61, + 140, + 86, + 180, + 200, + 214, + 78, + 49, + 244, + 130, + 106, + 161, + 208, + 12, + 250, + 36, + 152, + 187, + 21, + 247, + 2, + 159, + 107, + 51, + 196, + 242, + 93, + 168, + 39, + 111, + 64, + 31, + 64, + 250, + 43, + 94, + 98, + 153, + 180, + 246, + 85, + 106, + 233, + 202, + 130, + 42, + 156, + 27, + 230, + 111, + 246, + 13, + 40, + 68, + 3, + 102, + 128, + 252, + 238, + 93, + 234, + 56, + 222, + 202, + 88, + 107, + 150, + 8, + 255, + 118, + 58, + 67, + 229, + 167, + 38, + 236, + 16, + 181, + 78, + 101, + 8, + 32, + 170, + 75, + 115, + 1, + 51, + 175, + 92, + 230, + 154, + 43, + 134, + 1, + 180, + 10, + 157, + 66, + 26, + 41, + 0, + 162, + 95, + 240, + 91, + 71, + 85, + 88, + 184, + 244, + 15, + 137, + 34, + 205, + 228, + 247, + 86, + 148, + 112, + 123, + 100, + 191, + 247, + 42, + 222, + 125, + 48, + 19, + 84, + 118, + 114, + 134, + 177, + 31, + 43, + 134, + 69, + 236, + 184, + 196, + 137, + 248, + 82, + 118, + 191, + 125, + 126, + 31, + 92, + 104, + 206, + 157, + 213, + 116, + 10, + 48, + 175, + 240, + 242, + 228, + 82, + 158, + 107, + 107, + 16, + 127, + 208, + 38, + 227, + 114, + 192, + 162, + 20, + 222, + 43, + 134, + 119, + 94, + 88, + 54, + 114, + 205, + 41, + 64, + 154, + 202, + 113, + 239, + 0, + 79, + 20, + 203, + 73, + 88, + 247, + 56, + 22, + 166, + 19, + 90, + 59, + 33, + 145, + 73, + 253, + 166, + 75, + 149, + 11, + 172, + 184, + 127, + 45, + 135, + 174, + 68, + 20, + 5, + 59, + 148, + 241, + 40, + 135, + 90, + 34, + 1, + 19, + 58, + 46, + 8, + 248, + 73, + 146, + 100, + 20, + 38, + 132, + 235, + 64, + 47, + 100, + 5, + 155, + 140, + 3, + 195, + 100, + 188, + 9, + 161, + 165, + 7, + 165, + 47, + 197, + 16, + 73, + 17, + 55, + 21, + 156, + 247, + 202, + 53, + 77, + 191, + 116, + 15, + 108, + 186, + 73, + 249, + 234, + 76, + 22, + 75, + 112, + 155, + 243, + 206, + 240, + 83, + 64, + 103, + 3, + 78, + 155, + 236, + 156, + 101, + 218, + 246, + 221, + 53, + 101, + 159, + 43, + 185, + 128, + 31, + 86, + 208, + 12, + 87, + 129, + 61, + 210, + 146, + 0, + 214, + 74, + 134, + 199, + 157, + 89, + 65, + 115, + 201, + 235, + 83, + 224, + 245, + 19, + 7, + 26, + 181, + 68, + 87, + 172, + 23, + 97, + 130, + 3, + 226, + 49, + 128, + 87, + 191, + 166, + 187, + 15, + 204, + 4, + 191, + 238, + 81, + 146, + 11, + 204, + 163, + 89, + 193, + 52, + 165, + 67, + 253, + 50, + 121, + 97, + 18, + 183, + 217, + 219, + 157, + 159, + 238, + 54, + 113, + 46, + 16, + 229, + 70, + 86, + 112, + 28, + 202, + 160, + 155, + 183, + 102, + 192, + 21, + 45, + 38, + 37, + 222, + 252, + 14, + 211, + 229, + 150, + 115, + 211, + 82, + 96, + 12, + 150, + 133, + 240, + 107, + 64, + 175, + 93, + 217, + 39, + 92, + 238, + 115, + 195, + 180, + 47, + 68, + 50, + 231, + 232, + 91, + 47, + 8, + 63, + 5, + 69, + 20, + 118, + 8, + 38, + 254, + 203, + 202, + 232, + 36, + 192, + 136, + 189, + 163, + 57, + 208, + 102, + 59, + 204, + 120, + 84, + 116, + 122, + 116, + 70, + 190, + 173, + 63, + 220, + 48, + 212, + 9, + 88, + 23, + 101, + 108, + 97, + 9, + 217, + 73, + 186, + 22, + 129, + 237, + 148, + 156, + 11, + 209, + 9, + 248, + 234, + 22, + 185, + 153, + 64, + 215, + 164, + 9, + 237, + 18, + 41, + 9, + 142, + 228, + 69, + 164, + 2, + 174, + 115, + 220, + 27, + 172, + 186, + 251, + 190, + 249, + 84, + 84, + 21, + 135, + 31, + 11, + 27, + 119, + 178, + 143, + 142, + 108, + 234, + 178, + 59, + 159, + 144, + 47, + 63, + 94, + 80, + 215, + 91, + 21, + 161, + 85, + 140, + 70, + 101, + 200, + 140, + 31, + 229, + 2, + 120, + 73, + 98, + 23, + 245, + 191, + 88, + 242, + 175, + 131, + 54, + 177, + 187, + 35, + 149, + 234, + 202, + 202, + 45, + 252, + 207, + 231, + 66, + 161, + 101, + 141, + 182, + 7, + 221, + 23, + 90, + 241, + 177, + 64, + 51, + 6, + 11, + 248, + 159, + 59, + 91, + 112, + 188, + 225, + 211, + 246, + 247, + 108, + 71, + 176, + 73, + 166, + 174, + 243, + 161, + 247, + 67, + 183, + 47, + 3, + 58, + 247, + 198, + 99, + 98, + 249, + 62, + 226, + 74, + 105, + 80, + 30, + 242, + 91, + 191, + 151, + 61, + 58, + 165, + 183, + 111, + 66, + 129, + 153, + 60, + 58, + 161, + 2, + 12, + 74, + 101, + 244, + 29, + 99, + 189, + 181, + 114, + 204, + 106, + 136, + 48, + 204, + 80, + 22, + 201, + 127, + 161, + 189, + 136, + 71, + 236, + 76, + 159, + 76, + 174, + 74, + 242, + 134, + 43, + 215, + 134, + 139, + 130, + 232, + 223, + 112, + 166, + 222, + 127, + 68, + 13, + 225, + 222, + 228, + 231, + 113, + 200, + 217, + 7, + 109, + 159, + 21, + 239, + 86, + 190, + 237, + 201, + 246, + 191, + 168, + 231, + 242, + 180, + 112, + 213, + 243, + 5, + 202, + 127, + 41, + 134, + 9, + 20, + 41, + 235, + 209, + 243, + 23, + 193, + 70, + 114, + 38, + 232, + 10, + 195, + 196, + 239, + 63, + 102, + 124, + 120, + 183, + 99, + 168, + 97, + 85, + 109, + 83, + 51, + 255, + 207, + 25, + 125, + 28, + 66, + 143, + 35, + 7, + 165, + 244, + 36, + 183, + 210, + 81, + 83, + 9, + 104, + 164, + 170, + 221, + 252, + 245, + 114, + 13, + 156, + 199, + 142, + 93, + 165, + 150, + 215, + 197, + 101, + 29, + 159, + 140, + 115, + 84, + 49, + 8, + 52, + 240, + 125, + 59, + 236, + 209, + 25, + 70, + 203, + 158, + 181, + 247, + 158, + 229, + 141, + 162, + 48, + 161, + 240, + 81, + 244, + 241, + 175, + 123, + 39, + 96, + 156, + 77, + 41, + 15, + 28, + 70, + 73, + 104, + 100, + 162, + 209, + 36, + 160, + 112, + 151, + 213, + 170, + 59, + 43, + 3, + 79, + 27, + 209, + 73, + 1, + 210, + 133, + 97, + 91, + 67, + 204, + 55, + 239, + 197, + 18, + 230, + 249, + 15, + 185, + 126, + 18, + 162, + 70, + 199, + 206, + 163, + 229, + 143, + 75, + 8, + 230, + 104, + 118, + 33, + 212, + 247, + 144, + 50, + 15, + 46, + 2, + 168, + 184, + 217, + 19, + 160, + 101, + 34, + 26, + 73, + 58, + 11, + 157, + 149, + 235, + 229, + 79, + 73, + 190, + 5, + 5, + 137, + 35, + 115, + 120, + 153, + 144, + 144, + 251, + 184, + 23, + 130, + 147, + 89, + 253, + 144, + 153, + 60, + 74, + 61, + 18, + 237, + 9, + 7, + 188, + 143, + 8, + 165, + 116, + 206, + 8, + 124, + 183, + 209, + 54, + 196, + 188, + 228, + 183, + 235, + 154, + 154, + 111, + 128, + 129, + 84, + 220, + 223, + 113, + 238, + 25, + 192, + 27, + 152, + 91, + 48, + 196, + 164, + 52, + 12, + 254, + 162, + 119, + 197, + 24, + 60, + 175, + 200, + 192, + 111, + 13, + 98, + 234, + 183, + 59, + 202, + 20, + 171, + 96, + 55, + 36, + 206, + 67, + 28, + 68, + 50, + 48, + 105, + 173, + 64, + 49, + 30, + 49, + 14, + 146, + 35, + 116, + 61, + 7, + 18, + 97, + 165, + 141, + 66, + 96, + 24, + 95, + 199, + 42, + 98, + 91, + 155, + 186, + 222, + 39, + 79, + 83, + 236, + 0, + 8, + 8, + 91, + 123, + 13, + 93, + 97, + 227, + 112, + 118, + 170, + 44, + 103, + 89, + 205, + 143, + 113, + 247, + 66, + 112, + 246, + 83, + 40, + 211, + 123, + 36, + 139, + 110, + 165, + 223, + 227, + 172, + 128, + 143, + 79, + 221, + 43, + 146, + 104, + 13, + 92, + 206, + 35, + 79, + 160, + 35, + 102, + 33, + 9, + 40, + 0, + 104, + 244, + 236, + 189, + 112, + 106, + 145, + 186, + 104, + 163, + 53, + 156, + 242, + 203, + 199, + 56, + 76, + 39, + 177, + 25, + 182, + 236, + 126, + 95, + 74, + 241, + 128, + 203, + 253, + 142, + 106, + 44, + 178, + 92, + 14, + 9, + 57, + 26, + 137, + 201, + 36, + 102, + 188, + 121, + 177, + 128, + 208, + 93, + 3, + 202, + 217, + 233, + 64, + 116, + 56, + 3, + 42, + 242, + 57, + 188, + 18, + 200, + 78, + 194, + 3, + 162, + 237, + 23, + 176, + 173, + 203, + 77, + 60, + 238, + 122, + 190, + 1, + 24, + 86, + 244, + 144, + 48, + 220, + 164, + 15, + 17, + 153, + 126, + 226, + 236, + 118, + 152, + 125, + 62, + 197, + 22, + 127, + 71, + 195, + 19, + 111, + 97, + 1, + 143, + 95, + 55, + 218, + 96, + 110, + 6, + 99, + 207, + 41, + 113, + 214, + 136, + 31, + 27, + 123, + 189, + 154, + 231, + 60, + 117, + 56, + 17, + 109, + 255, + 0, + 244, + 238, + 125, + 228, + 11, + 95, + 227, + 105, + 103, + 200, + 251, + 205, + 129, + 85, + 34, + 128, + 85, + 38, + 42, + 62, + 180, + 8, + 162, + 54, + 53, + 252, + 12, + 128, + 28, + 143, + 74, + 214, + 50, + 62, + 68, + 82, + 226, + 66, + 41, + 20, + 110, + 254, + 235, + 120, + 205, + 143, + 119, + 153, + 12, + 234, + 92, + 67, + 32, + 170, + 172, + 141, + 85, + 239, + 122, + 140, + 66, + 172, + 235, + 241, + 92, + 77, + 100, + 159, + 83, + 168, + 130, + 46, + 108, + 26, + 89, + 32, + 74, + 175, + 94, + 75, + 63, + 180, + 87, + 58, + 123, + 197, + 0, + 160, + 45, + 72, + 84, + 25, + 220, + 152, + 250, + 244, + 202, + 108, + 150, + 216, + 115, + 222, + 232, + 74, + 67, + 59, + 77, + 146, + 114, + 35, + 64, + 72, + 108, + 77, + 5, + 92, + 161, + 191, + 140, + 204, + 181, + 63, + 36, + 29, + 135, + 5, + 198, + 175, + 13, + 75, + 252, + 16, + 233, + 108, + 95, + 87, + 144, + 183, + 196, + 127, + 127, + 193, + 112, + 237, + 203, + 30, + 82, + 240, + 59, + 182, + 206, + 25, + 20, + 216, + 45, + 127, + 181, + 50, + 30, + 234, + 196, + 15, + 163, + 209, + 191, + 157, + 118, + 95, + 159, + 204, + 192, + 87, + 238, + 29, + 25, + 237, + 5, + 25, + 238, + 205, + 67, + 184, + 2, + 223, + 206, + 117, + 225, + 199, + 188, + 88, + 255, + 62, + 238, + 235, + 66, + 108, + 2, + 162, + 102, + 16, + 242, + 165, + 83, + 184, + 255, + 101, + 23, + 225, + 6, + 26, + 124, + 163, + 13, + 212, + 189, + 29, + 220, + 144, + 151, + 163, + 223, + 29, + 7, + 153, + 234, + 177, + 224, + 243, + 66, + 20, + 21, + 77, + 103, + 229, + 160, + 42, + 48, + 175, + 239, + 33, + 62, + 71, + 236, + 233, + 249, + 33, + 183, + 254, + 225, + 196, + 127, + 245, + 2, + 165, + 158, + 161, + 225, + 107, + 59, + 244, + 19, + 27, + 0, + 97, + 95, + 162, + 10, + 39, + 205, + 1, + 141, + 81, + 146, + 165, + 248, + 133, + 83, + 92, + 55, + 221, + 78, + 248, + 210, + 130, + 255, + 113, + 12, + 137, + 20, + 103, + 218, + 241, + 176, + 109, + 66, + 30, + 139, + 89, + 42, + 128, + 29, + 26, + 155, + 119, + 18, + 111, + 138, + 47, + 243, + 54, + 231, + 57, + 158, + 217, + 53, + 225, + 28, + 8, + 26, + 14, + 6, + 167, + 31, + 174, + 77, + 135, + 154, + 95, + 195, + 212, + 241, + 95, + 197, + 119, + 61, + 121, + 253, + 92, + 205, + 211, + 55, + 86, + 139, + 79, + 65, + 134, + 117, + 107, + 208, + 89, + 76, + 81, + 95, + 7, + 120, + 209, + 160, + 24, + 151, + 12, + 162, + 24, + 234, + 19, + 40, + 204, + 231, + 53, + 170, + 217, + 80, + 83, + 196, + 72, + 135, + 107, + 177, + 55, + 202, + 191, + 215, + 237, + 26, + 192, + 172, + 236, + 89, + 177, + 236, + 49, + 129, + 108, + 217, + 47, + 223, + 119, + 64, + 244, + 217, + 186, + 81, + 48, + 173, + 124, + 13, + 5, + 196, + 29, + 159, + 168, + 241, + 13, + 161, + 254, + 94, + 9, + 232, + 98, + 136, + 201, + 76, + 228, + 10, + 55, + 159, + 221, + 120, + 12, + 188, + 130, + 97, + 15, + 224, + 138, + 87, + 174, + 32, + 76, + 239, + 114, + 0, + 75, + 127, + 44, + 122, + 156, + 229, + 16, + 114, + 23, + 33, + 209, + 75, + 147, + 204, + 74, + 152, + 56, + 80, + 148, + 207, + 96, + 199, + 46, + 194, + 19, + 6, + 113, + 72, + 164, + 202, + 17, + 30, + 93, + 104, + 224, + 170, + 242, + 46, + 23, + 109, + 52, + 148, + 161, + 173, + 104, + 96, + 42, + 189, + 206, + 76, + 150, + 216, + 131, + 171, + 49, + 75, + 226, + 168, + 19, + 238, + 214, + 120, + 126, + 207, + 171, + 146, + 115, + 94, + 104, + 203, + 196, + 201, + 164, + 85, + 236, + 2, + 40, + 7, + 39, + 160, + 169, + 95, + 7, + 253, + 165, + 110, + 180, + 160, + 169, + 205, + 17, + 35, + 174, + 149, + 201, + 178, + 108, + 155, + 149, + 70, + 222, + 249, + 46, + 182, + 114, + 118, + 171, + 169, + 39, + 149, + 57, + 183, + 243, + 144, + 191, + 204, + 103, + 18, + 49, + 132, + 44, + 119, + 143, + 108, + 216, + 131, + 138, + 116, + 18, + 60, + 52, + 168, + 171, + 168, + 57, + 240, + 200, + 224, + 203, + 1, + 5, + 28, + 56, + 39, + 160, + 34, + 189, + 210, + 25, + 36, + 62, + 214, + 127, + 142, + 28, + 99, + 222, + 51, + 226, + 74, + 243, + 43, + 154, + 58, + 227, + 68, + 94, + 106, + 213, + 143, + 248, + 25, + 223, + 80, + 9, + 213, + 186, + 0, + 199, + 66, + 20, + 64, + 31, + 181, + 154, + 156, + 0, + 58, + 145, + 96, + 167, + 241, + 130, + 109, + 93, + 5, + 118, + 253, + 89, + 10, + 201, + 241, + 54, + 68, + 225, + 125, + 114, + 109, + 253, + 237, + 153, + 75, + 140, + 220, + 61, + 180, + 246, + 205, + 17, + 16, + 57, + 62, + 170, + 216, + 82, + 153, + 161, + 146, + 145, + 197, + 100, + 202, + 153, + 118, + 52, + 1, + 171, + 43, + 48, + 66, + 60, + 238, + 95, + 209, + 168, + 203, + 77, + 242, + 131, + 163, + 174, + 122, + 129, + 127, + 139, + 224, + 146, + 74, + 194, + 220, + 18, + 62, + 212, + 29, + 176, + 87, + 169, + 210, + 127, + 151, + 83, + 139, + 119, + 56, + 73, + 168, + 10, + 70, + 167, + 167, + 66, + 122, + 128, + 195, + 186, + 188, + 86, + 64, + 94, + 21, + 39, + 32, + 102, + 127, + 131, + 32, + 149, + 48, + 60, + 251, + 153, + 20, + 32, + 111, + 37, + 166, + 148, + 220, + 110, + 119, + 61, + 171, + 69, + 55, + 213, + 29, + 225, + 234, + 250, + 81, + 253, + 224, + 142, + 235, + 205, + 5, + 56, + 252, + 249, + 121, + 92, + 44, + 43, + 36, + 28, + 116, + 240, + 143, + 174, + 158, + 112, + 18, + 135, + 150, + 6, + 87, + 38, + 145, + 26, + 150, + 220, + 30, + 3, + 129, + 192, + 3, + 168, + 30, + 70, + 154, + 84, + 95, + 113, + 212, + 60, + 106, + 62, + 255, + 46, + 80, + 10, + 133, + 155, + 117, + 176, + 20, + 185, + 218, + 60, + 99, + 202, + 226, + 5, + 136, + 176, + 73, + 16, + 187, + 56, + 82, + 149, + 7, + 15, + 47, + 136, + 58, + 143, + 104, + 99, + 32, + 36, + 113, + 18, + 119, + 89, + 10, + 21, + 30, + 14, + 131, + 61, + 24, + 203, + 154, + 185, + 190, + 148, + 197, + 21, + 236, + 251, + 16, + 74, + 185, + 151, + 108, + 133, + 171, + 76, + 2, + 56, + 15, + 1, + 32, + 20, + 85, + 135, + 198, + 196, + 44, + 59, + 110, + 227, + 10, + 45, + 4, + 247, + 202, + 209, + 93, + 159, + 95, + 192, + 46, + 165, + 116, + 40, + 229, + 193, + 146, + 99, + 38, + 6, + 25, + 34, + 82, + 52, + 28, + 186, + 99, + 158, + 244, + 123, + 12, + 37, + 137, + 225, + 188, + 136, + 142, + 227, + 186, + 74, + 167, + 160, + 205, + 246, + 195, + 22, + 95, + 177, + 98, + 179, + 103, + 113, + 194, + 75, + 67, + 94, + 135, + 170, + 246, + 249, + 42, + 188, + 77, + 189, + 160, + 154, + 123, + 108, + 76, + 164, + 133, + 167, + 211, + 20, + 252, + 153, + 115, + 7, + 131, + 6, + 224, + 76, + 135, + 93, + 0, + 209, + 160, + 98, + 23, + 4, + 89, + 48, + 122, + 65, + 37, + 224, + 249, + 10, + 223, + 13, + 216, + 217, + 31, + 65, + 241, + 210, + 242, + 254, + 135, + 70, + 47, + 236, + 213, + 40, + 153, + 52, + 123, + 140, + 35, + 90, + 136, + 202, + 61, + 155, + 219, + 105, + 132, + 135, + 185, + 39, + 168, + 159, + 168, + 214, + 161, + 34, + 38, + 101, + 218, + 140, + 212, + 246, + 128, + 85, + 241, + 158, + 38, + 107, + 29, + 204, + 21, + 124, + 57, + 70, + 28, + 222, + 94, + 232, + 16, + 188, + 52, + 158, + 246, + 228, + 203, + 83, + 155, + 114, + 140, + 134, + 159, + 191, + 48, + 213, + 17, + 110, + 27, + 204, + 181, + 99, + 240, + 128, + 249, + 128, + 230, + 102, + 156, + 17, + 242, + 208, + 137, + 142, + 179, + 230, + 17, + 84, + 233, + 60, + 29, + 5, + 208, + 225, + 32, + 109, + 91, + 4, + 94, + 227, + 73, + 181, + 48, + 55, + 57, + 53, + 225, + 220, + 100, + 248, + 15, + 1, + 74, + 226, + 155, + 131, + 221, + 135, + 206, + 179, + 71, + 57, + 170, + 39, + 120, + 37, + 211, + 121, + 179, + 185, + 24, + 84, + 16, + 11, + 86, + 50, + 102, + 79, + 231, + 2, + 231, + 201, + 138, + 208, + 171, + 156, + 254, + 57, + 120, + 228, + 46, + 247, + 68, + 167, + 238, + 161, + 44, + 47, + 0, + 8, + 134, + 151, + 244, + 173, + 16, + 190, + 155, + 15, + 50, + 118, + 79, + 118, + 69, + 128, + 38, + 125, + 201, + 129, + 14, + 74, + 200, + 3, + 18, + 189, + 158, + 243, + 49, + 225, + 51, + 138, + 111, + 209, + 66, + 130, + 241, + 26, + 210, + 127, + 87, + 75, + 186, + 189, + 24, + 242, + 95, + 13, + 211, + 16, + 187, + 209, + 13, + 5, + 254, + 194, + 31, + 161, + 135, + 90, + 129, + 219, + 167, + 115, + 63, + 11, + 176, + 180, + 47, + 28, + 7, + 145, + 234, + 45, + 193, + 124, + 212, + 232, + 95, + 224, + 115, + 110, + 140, + 174, + 111, + 141, + 98, + 240, + 150, + 234, + 155, + 67, + 120, + 222, + 56, + 28, + 251, + 23, + 78, + 143, + 103, + 100, + 97, + 13, + 189, + 45, + 202, + 39, + 96, + 230, + 248, + 61, + 120, + 93, + 209, + 194, + 75, + 112, + 49, + 227, + 31, + 37, + 183, + 229, + 35, + 73, + 202, + 122, + 235, + 127, + 156, + 137, + 200, + 39, + 40, + 88, + 32, + 79, + 100, + 184, + 40, + 134, + 240, + 84, + 166, + 104, + 63, + 225, + 27, + 235, + 55, + 142, + 160, + 34, + 181, + 140, + 52, + 98, + 64, + 115, + 247, + 235, + 43, + 208, + 166, + 102, + 107, + 94, + 154, + 17, + 117, + 41, + 93, + 204, + 123, + 26, + 161, + 118, + 27, + 124, + 28, + 188, + 86, + 152, + 4, + 63, + 172, + 1, + 166, + 199, + 0, + 175, + 227, + 142, + 0, + 185, + 105, + 92, + 203, + 237, + 203, + 33, + 229, + 179, + 156, + 21, + 139, + 130, + 112, + 207, + 169, + 164, + 200, + 224, + 42, + 214, + 241, + 159, + 1, + 20, + 29, + 196, + 192, + 44, + 181, + 70, + 244, + 70, + 33, + 27, + 116, + 62, + 60, + 104, + 148, + 98, + 72, + 192, + 143, + 18, + 164, + 95, + 149, + 174, + 116, + 230, + 183, + 167, + 207, + 206, + 146, + 224, + 45, + 139, + 255, + 210, + 165, + 142, + 45, + 33, + 130, + 190, + 180, + 94, + 234, + 54, + 72, + 116, + 23, + 123, + 210, + 31, + 190, + 156, + 207, + 193, + 171, + 241, + 120, + 172, + 87, + 56, + 233, + 190, + 188, + 129, + 130, + 199, + 113, + 209, + 108, + 8, + 229, + 159, + 58, + 133, + 231, + 86, + 19, + 2, + 79, + 246, + 178, + 154, + 3, + 138, + 154, + 219, + 163, + 114, + 203, + 50, + 0, + 246, + 151, + 248, + 93, + 186, + 123, + 44, + 173, + 124, + 136, + 170, + 155, + 171, + 44, + 36, + 122, + 24, + 244, + 16, + 99, + 178, + 244, + 81, + 106, + 141, + 176, + 26, + 37, + 142, + 19, + 237, + 47, + 132, + 204, + 6, + 249, + 12, + 244, + 167, + 103, + 145, + 71, + 252, + 177, + 216, + 124, + 225, + 7, + 48, + 18, + 4, + 138, + 135, + 5, + 54, + 100, + 128, + 89, + 80, + 122, + 14, + 158, + 73, + 80, + 221, + 67, + 189, + 232, + 181, + 174, + 50, + 0, + 248, + 185, + 49, + 154, + 87, + 214, + 26, + 179, + 48, + 152, + 55, + 137, + 46, + 180, + 13, + 106, + 197, + 140, + 175, + 194, + 147, + 16, + 107, + 225, + 82, + 239, + 22, + 18, + 135, + 35, + 230, + 87, + 203, + 153, + 144, + 75, + 15, + 229, + 251, + 60, + 102, + 72, + 135, + 29, + 185, + 174, + 253, + 66, + 162, + 144, + 25, + 226, + 150, + 234, + 124, + 141, + 150, + 72, + 248, + 87, + 7, + 91, + 20, + 63, + 167, + 7, + 237, + 255, + 239, + 230, + 4, + 84, + 13, + 74, + 95, + 141, + 244, + 235, + 180, + 47, + 171, + 108, + 219, + 52, + 144, + 173, + 152, + 209, + 142, + 138, + 254, + 125, + 134, + 81, + 135, + 114, + 38, + 8, + 238, + 65, + 149, + 183, + 92, + 201, + 0, + 45, + 0, + 207, + 29, + 35, + 192, + 66, + 159, + 111, + 238, + 102, + 175, + 233, + 101, + 248, + 88, + 70, + 238, + 20, + 4, + 71, + 184, + 247, + 223, + 254, + 165, + 102, + 167, + 212, + 241, + 218, + 11, + 16, + 48, + 58, + 82, + 161, + 190, + 84, + 37, + 10, + 231, + 188, + 46, + 147, + 190, + 31, + 213, + 12, + 33, + 206, + 38, + 247, + 127, + 195, + 226, + 12, + 114, + 194, + 54, + 245, + 221, + 23, + 89, + 84, + 239, + 57, + 14, + 64, + 142, + 210, + 230, + 52, + 13, + 8, + 47, + 12, + 128, + 166, + 21, + 206, + 4, + 108, + 205, + 229, + 200, + 243, + 152, + 79, + 177, + 181, + 160, + 1, + 156, + 246, + 66, + 9, + 1, + 209, + 234, + 44, + 137, + 214, + 191, + 120, + 176, + 191, + 122, + 98, + 241, + 121, + 3, + 133, + 132, + 63, + 34, + 184, + 157, + 63, + 182, + 209, + 149, + 202, + 61, + 149, + 8, + 171, + 80, + 30, + 13, + 236, + 140, + 57, + 132, + 85, + 24, + 176, + 171, + 173, + 145, + 105, + 81, + 144, + 215, + 198, + 127, + 94, + 206, + 51, + 212, + 89, + 228, + 176, + 126, + 243, + 190, + 1, + 150, + 58, + 94, + 10, + 204, + 145, + 104, + 232, + 182, + 121, + 161, + 13, + 197, + 51, + 41, + 74, + 67, + 42, + 14, + 114, + 86, + 196, + 156, + 17, + 18, + 66, + 10, + 153, + 224, + 101, + 38, + 195, + 36, + 7, + 60, + 58, + 156, + 179, + 230, + 120, + 125, + 91, + 186, + 169, + 102, + 69, + 118, + 246, + 125, + 207, + 161, + 216, + 94, + 117, + 253, + 80, + 200, + 105, + 22, + 177, + 244, + 103, + 18, + 206, + 72, + 36, + 82, + 181, + 63, + 202, + 109, + 72, + 32, + 127, + 239, + 126, + 187, + 94, + 216, + 3, + 56, + 16, + 69, + 210, + 36, + 117, + 189, + 29, + 123, + 13, + 220, + 221, + 56, + 166, + 18, + 114, + 182, + 217, + 109, + 211, + 64, + 78, + 127, + 105, + 235, + 144, + 84, + 70, + 98, + 104, + 203, + 107, + 85, + 23, + 183, + 253, + 93, + 154, + 119, + 227, + 33, + 49, + 223, + 175, + 143, + 26, + 33, + 60, + 137, + 182, + 13, + 219, + 78, + 187, + 87, + 48, + 245, + 229, + 254, + 190, + 75, + 68, + 115, + 252, + 232, + 243, + 134, + 168, + 13, + 79, + 168, + 109, + 62, + 247, + 208, + 125, + 16, + 249, + 175, + 106, + 184, + 233, + 110, + 69, + 122, + 151, + 214, + 57, + 179, + 88, + 13, + 56, + 178, + 47, + 167, + 28, + 160, + 139, + 39, + 158, + 177, + 65, + 33, + 211, + 132, + 170, + 108, + 255, + 188, + 234, + 246, + 45, + 217, + 18, + 53, + 29, + 57, + 212, + 173, + 243, + 230, + 202, + 87, + 164, + 98, + 109, + 130, + 28, + 82, + 152, + 251, + 118, + 186, + 105, + 3, + 207, + 11, + 169, + 81, + 176, + 32, + 63, + 183, + 14, + 7, + 198, + 72, + 155, + 237, + 192, + 212, + 133, + 53, + 150, + 60, + 42, + 234, + 189, + 132, + 229, + 71, + 194, + 191, + 195, + 5, + 129, + 87, + 161, + 208, + 227, + 255, + 152, + 118, + 90, + 26, + 211, + 145, + 189, + 62, + 130, + 75, + 41, + 231, + 172, + 53, + 0, + 106, + 209, + 73, + 195, + 8, + 188, + 192, + 64, + 135, + 61, + 237, + 96, + 2, + 178, + 8, + 76, + 15, + 32, + 75, + 222, + 117, + 113, + 83, + 156, + 55, + 146, + 225, + 159, + 195, + 23, + 233, + 235, + 129, + 101, + 78, + 56, + 79, + 42, + 19, + 29, + 2, + 80, + 22, + 65, + 202, + 186, + 214, + 119, + 217, + 194, + 227, + 37, + 252, + 12, + 120, + 207, + 54, + 32, + 162, + 194, + 49, + 75, + 19, + 192, + 0, + 244, + 11, + 60, + 210, + 216, + 161, + 168, + 218, + 182, + 21, + 249, + 248, + 37, + 25, + 91, + 156, + 229, + 164, + 185, + 224, + 119, + 78, + 202, + 81, + 143, + 137, + 104, + 145, + 159, + 13, + 245, + 233, + 22, + 116, + 253, + 94, + 72, + 1, + 64, + 87, + 78, + 85, + 54, + 156, + 8, + 144, + 38, + 118, + 220, + 241, + 116, + 196, + 17, + 19, + 86, + 82, + 73, + 162, + 154, + 36, + 144, + 238, + 145, + 165, + 53, + 160, + 118, + 59, + 25, + 213, + 135, + 120, + 100, + 254, + 26, + 200, + 111, + 153, + 72, + 204, + 125, + 201, + 122, + 100, + 114, + 103, + 42, + 53, + 18, + 190, + 232, + 91, + 141, + 57, + 165, + 122, + 164, + 164, + 25, + 15, + 14, + 176, + 209, + 18, + 39, + 173, + 15, + 7, + 36, + 38, + 129, + 196, + 254, + 94, + 246, + 97, + 184, + 12, + 151, + 94, + 249, + 207, + 131, + 127, + 42, + 233, + 206, + 225, + 177, + 63, + 209, + 69, + 124, + 122, + 207, + 211, + 164, + 35, + 201, + 242, + 197, + 227, + 81, + 126, + 10, + 201, + 105, + 111, + 237, + 166, + 166, + 29, + 189, + 130, + 127, + 59, + 183, + 205, + 70, + 15, + 214, + 44, + 158, + 123, + 211, + 167, + 117, + 37, + 107, + 63, + 25, + 232, + 75, + 125, + 212, + 51, + 69, + 169, + 105, + 62, + 42, + 76, + 128, + 20, + 158, + 240, + 141, + 83, + 123, + 147, + 56, + 167, + 29, + 152, + 106, + 148, + 197, + 204, + 211, + 59, + 212, + 90, + 138, + 1, + 209, + 196, + 17, + 105, + 255, + 195, + 12, + 62, + 189, + 51, + 145, + 46, + 13, + 141, + 100, + 86, + 54, + 155, + 181, + 146, + 186, + 187, + 249, + 66, + 141, + 10, + 61, + 119, + 234, + 220, + 123, + 143, + 14, + 97, + 237, + 86, + 48, + 228, + 64, + 94, + 188, + 7, + 90, + 78, + 26, + 22, + 86, + 55, + 110, + 67, + 30, + 195, + 31, + 151, + 130, + 106, + 9, + 169, + 134, + 52, + 220, + 22, + 232, + 198, + 146, + 92, + 104, + 36, + 89, + 233, + 198, + 210, + 80, + 139, + 240, + 55, + 194, + 93, + 140, + 22, + 6, + 146, + 238, + 11, + 149, + 8, + 186, + 209, + 123, + 72, + 41, + 233, + 202, + 27, + 129, + 177, + 10, + 247, + 146, + 60, + 127, + 51, + 55, + 130, + 180, + 174, + 115, + 103, + 49, + 128, + 141, + 248, + 67, + 101, + 217, + 249, + 158, + 199, + 120, + 210, + 181, + 166, + 123, + 153, + 140, + 63, + 47, + 47, + 72, + 82, + 17, + 212, + 132, + 123, + 163, + 230, + 97, + 28, + 48, + 81, + 246, + 168, + 157, + 51, + 33, + 216, + 206, + 199, + 214, + 10, + 208, + 7, + 18, + 158, + 161, + 37, + 99, + 116, + 115, + 64, + 215, + 162, + 48, + 22, + 62, + 235, + 76, + 98, + 126, + 134, + 37, + 74, + 199, + 237, + 37, + 238, + 116, + 78, + 105, + 102, + 36, + 223, + 114, + 130, + 214, + 213, + 92, + 176, + 231, + 166, + 57, + 235, + 39, + 96, + 85, + 155, + 36, + 195, + 167, + 24, + 121, + 224, + 152, + 11, + 51, + 249, + 93, + 233, + 138, + 147, + 147, + 136, + 29, + 198, + 108, + 166, + 179, + 51, + 172, + 182, + 223, + 36, + 70, + 93, + 20, + 56, + 174, + 221, + 175, + 183, + 161, + 213, + 48, + 217, + 13, + 13, + 82, + 220, + 246, + 12, + 141, + 182, + 65, + 105, + 219, + 152, + 88, + 45, + 91, + 178, + 162, + 152, + 26, + 107, + 169, + 39, + 217, + 1, + 124, + 246, + 207, + 206, + 100, + 154, + 118, + 142, + 110, + 93, + 207, + 155, + 190, + 49, + 253, + 236, + 39, + 19, + 41, + 242, + 172, + 15, + 156, + 217, + 80, + 54, + 251, + 110, + 27, + 38, + 245, + 204, + 174, + 1, + 122, + 104, + 209, + 62, + 164, + 212, + 75, + 76, + 231, + 216, + 180, + 171, + 240, + 192, + 215, + 86, + 115, + 27, + 118, + 142, + 197, + 26, + 101, + 89, + 154, + 130, + 167, + 183, + 67, + 242, + 210, + 220, + 188, + 250, + 44, + 227, + 91, + 71, + 233, + 103, + 13, + 198, + 154, + 48, + 85, + 104, + 242, + 239, + 123, + 118, + 255, + 214, + 200, + 222, + 161, + 240, + 106, + 131, + 97, + 31, + 113, + 115, + 93, + 12, + 96, + 35, + 150, + 129, + 87, + 169, + 39, + 0, + 196, + 156, + 175, + 190, + 233, + 49, + 49, + 80, + 8, + 32, + 26, + 196, + 25, + 213, + 235, + 66, + 75, + 61, + 231, + 174, + 110, + 43, + 80, + 182, + 169, + 201, + 86, + 95, + 209, + 183, + 80, + 108, + 204, + 192, + 107, + 197, + 150, + 201, + 249, + 225, + 196, + 216, + 21, + 86, + 149, + 169, + 217, + 156, + 96, + 234, + 252, + 186, + 195, + 69, + 73, + 125, + 148, + 223, + 1, + 228, + 35, + 33, + 22, + 111, + 126, + 54, + 219, + 216, + 75, + 80, + 207, + 71, + 115, + 88, + 106, + 191, + 110, + 139, + 15, + 210, + 72, + 137, + 66, + 10, + 172, + 145, + 197, + 188, + 89, + 87, + 42, + 214, + 92, + 65, + 156, + 93, + 14, + 86, + 233, + 132, + 188, + 2, + 79, + 99, + 140, + 118, + 20, + 92, + 60, + 7, + 202, + 115, + 72, + 132, + 12, + 48, + 121, + 188, + 163, + 135, + 157, + 34, + 0, + 70, + 77, + 138, + 175, + 23, + 138, + 83, + 160, + 200, + 193, + 254, + 248, + 165, + 115, + 147, + 33, + 15, + 249, + 107, + 166, + 9, + 187, + 33, + 91, + 86, + 215, + 146, + 166, + 178, + 197, + 73, + 224, + 17, + 105, + 164, + 227, + 41, + 230, + 42, + 113, + 207, + 183, + 68, + 65, + 37, + 5, + 186, + 150, + 96, + 106, + 14, + 84, + 135, + 216, + 221, + 92, + 252, + 27, + 178, + 64, + 128, + 45, + 226, + 128, + 3, + 229, + 177, + 41, + 31, + 16, + 1, + 177, + 129, + 48, + 30, + 107, + 173, + 255, + 213, + 200, + 97, + 10, + 216, + 57, + 162, + 238, + 50, + 171, + 63, + 148, + 220, + 235, + 60, + 230, + 155, + 15, + 27, + 214, + 43, + 55, + 111, + 136, + 153, + 120, + 39, + 81, + 87, + 235, + 59, + 60, + 107, + 74, + 134, + 240, + 138, + 79, + 135, + 63, + 148, + 63, + 253, + 139, + 103, + 243, + 248, + 178, + 89, + 176, + 253, + 248, + 152, + 110, + 99, + 144, + 149, + 12, + 152, + 74, + 110, + 34, + 221, + 240, + 176, + 213, + 71, + 18, + 194, + 55, + 240, + 146, + 96, + 62, + 188, + 28, + 21, + 194, + 172, + 73, + 183, + 112, + 72, + 1, + 60, + 35, + 45, + 27, + 84, + 98, + 26, + 249, + 215, + 86, + 83, + 17, + 176, + 152, + 236, + 55, + 51, + 91, + 224, + 152, + 7, + 5, + 203, + 215, + 188, + 253, + 123, + 119, + 242, + 244, + 14, + 178, + 182, + 183, + 40, + 63, + 162, + 150, + 252, + 171, + 7, + 215, + 161, + 230, + 23, + 48, + 164, + 44, + 194, + 168, + 52, + 179, + 197, + 30, + 194, + 28, + 115, + 99, + 148, + 231, + 124, + 18, + 244, + 95, + 32, + 134, + 58, + 41, + 82, + 234, + 183, + 148, + 16, + 100, + 204, + 123, + 81, + 9, + 183, + 237, + 119, + 34, + 94, + 76, + 178, + 13, + 74, + 206, + 107, + 208, + 87, + 27, + 165, + 61, + 175, + 30, + 123, + 111, + 96, + 168, + 45, + 187, + 150, + 197, + 77, + 73, + 107, + 112, + 207, + 60, + 70, + 63, + 238, + 152, + 202, + 112, + 41, + 3, + 174, + 68, + 68, + 86, + 132, + 199, + 184, + 10, + 35, + 195, + 45, + 225, + 93, + 156, + 63, + 168, + 135, + 225, + 50, + 91, + 185, + 183, + 252, + 53, + 102, + 107, + 46, + 60, + 200, + 182, + 221, + 94, + 54, + 245, + 60, + 103, + 129, + 197, + 170, + 191, + 89, + 167, + 182, + 109, + 32, + 152, + 88, + 80, + 125, + 164, + 254, + 139, + 143, + 246, + 121, + 236, + 57, + 86, + 7, + 47, + 18, + 173, + 41, + 38, + 18, + 201, + 195, + 32, + 234, + 252, + 156, + 29, + 73, + 195, + 142, + 41, + 58, + 206, + 141, + 169, + 145, + 243, + 232, + 62, + 49, + 169, + 127, + 199, + 255, + 222, + 255, + 119, + 245, + 43, + 63, + 117, + 156, + 110, + 131, + 166, + 46, + 146, + 97, + 204, + 99, + 31, + 128, + 158, + 115, + 114, + 202, + 101, + 255, + 98, + 61, + 74, + 214, + 40, + 41, + 30, + 140, + 207, + 78, + 125, + 183, + 55, + 57, + 215, + 113, + 134, + 154, + 233, + 171, + 129, + 90, + 128, + 219, + 188, + 146, + 147, + 103, + 142, + 159, + 177, + 8, + 69, + 122, + 9, + 22, + 58, + 136, + 14, + 98, + 252, + 253, + 178, + 226, + 234, + 18, + 3, + 36, + 57, + 7, + 166, + 242, + 231, + 37, + 219, + 95, + 227, + 119, + 19, + 4, + 217, + 252, + 248, + 16, + 105, + 131, + 37, + 5, + 253, + 37, + 244, + 148, + 66, + 175, + 152, + 200, + 217, + 92, + 82, + 174, + 73, + 145, + 43, + 23, + 87, + 19, + 21, + 37, + 213, + 156, + 31, + 5, + 136, + 134, + 57, + 139, + 121, + 95, + 242, + 5, + 130, + 64, + 1, + 173, + 213, + 116, + 214, + 80, + 76, + 29, + 122, + 142, + 240, + 221, + 238, + 198, + 161, + 19, + 159, + 176, + 106, + 228, + 181, + 13, + 140, + 183, + 173, + 207, + 112, + 187, + 76, + 191, + 215, + 111, + 244, + 179, + 237, + 199, + 179, + 48, + 210, + 173, + 8, + 68, + 254, + 182, + 45, + 176, + 12, + 158, + 161, + 90, + 75, + 104, + 54, + 50, + 77, + 2, + 159, + 149, + 172, + 165, + 16, + 88, + 121, + 68, + 251, + 65, + 71, + 217, + 196, + 48, + 7, + 164, + 180, + 211, + 91, + 213, + 179, + 169, + 187, + 203, + 196, + 138, + 145, + 48, + 207, + 52, + 221, + 250, + 58, + 181, + 50, + 83, + 124, + 193, + 59, + 91, + 192, + 35, + 4, + 240, + 134, + 26, + 0, + 121, + 132, + 144, + 3, + 93, + 16, + 98, + 128, + 83, + 88, + 231, + 43, + 62, + 222, + 70, + 174, + 59, + 36, + 108, + 156, + 245, + 183, + 62, + 175, + 145, + 36, + 249, + 14, + 123, + 115, + 62, + 33, + 241, + 36, + 211, + 99, + 68, + 111, + 177, + 112, + 168, + 6, + 209, + 218, + 217, + 224, + 81, + 116, + 254, + 186, + 101, + 72, + 57, + 248, + 239, + 186, + 173, + 255, + 56, + 10, + 220, + 187, + 171, + 147, + 225, + 233, + 232, + 34, + 234, + 173, + 212, + 133, + 137, + 135, + 73, + 242, + 253, + 23, + 8, + 20, + 177, + 22, + 199, + 69, + 128, + 32, + 142, + 30, + 251, + 155, + 157, + 224, + 88, + 171, + 70, + 90, + 119, + 20, + 115, + 142, + 217, + 10, + 120, + 248, + 105, + 180, + 156, + 40, + 210, + 91, + 95, + 162, + 150, + 17, + 30, + 103, + 183, + 97, + 195, + 135, + 96, + 36, + 123, + 158, + 146, + 104, + 216, + 114, + 19, + 223, + 67, + 208, + 114, + 160, + 118, + 81, + 201, + 6, + 41, + 111, + 83, + 250, + 43, + 7, + 100, + 243, + 206, + 30, + 113, + 153, + 178, + 171, + 194, + 108, + 93, + 15, + 182, + 126, + 69, + 85, + 25, + 238, + 184, + 45, + 118, + 183, + 170, + 64, + 37, + 169, + 47, + 1, + 175, + 85, + 56, + 70, + 0, + 203, + 44, + 49, + 222, + 125, + 52, + 252, + 56, + 12, + 171, + 56, + 219, + 5, + 62, + 152, + 237, + 40, + 170, + 195, + 201, + 91, + 248, + 80, + 89, + 229, + 224, + 30, + 106, + 208, + 54, + 101, + 46, + 69, + 52, + 83, + 227, + 240, + 79, + 205, + 95, + 122, + 76, + 78, + 220, + 66, + 136, + 133, + 60, + 14, + 141, + 115, + 219, + 44, + 194, + 71, + 26, + 169, + 125, + 151, + 240, + 75, + 35, + 250, + 66, + 221, + 199, + 247, + 96, + 32, + 19, + 15, + 44, + 173, + 241, + 38, + 66, + 0, + 79, + 212, + 92, + 67, + 237, + 224, + 236, + 68, + 46, + 241, + 221, + 143, + 242, + 159, + 196, + 218, + 113, + 243, + 237, + 191, + 123, + 250, + 174, + 218, + 149, + 158, + 91, + 177, + 61, + 45, + 42, + 24, + 102, + 106, + 147, + 63, + 5, + 192, + 161, + 177, + 183, + 83, + 68, + 253, + 15, + 232, + 4, + 51, + 91, + 213, + 138, + 76, + 4, + 225, + 172, + 40, + 230, + 28, + 160, + 127, + 91, + 108, + 70, + 82, + 33, + 168, + 64, + 137, + 89, + 84, + 247, + 30, + 28, + 132, + 102, + 250, + 1, + 99, + 46, + 243, + 59, + 34, + 41, + 220, + 234, + 152, + 178, + 229, + 96, + 186, + 122, + 124, + 133, + 216, + 58, + 79, + 199, + 125, + 37, + 233, + 25, + 56, + 68, + 15, + 97, + 107, + 151, + 208, + 47, + 28, + 127, + 145, + 111, + 46, + 176, + 62, + 120, + 47, + 191, + 51, + 174, + 185, + 40, + 65, + 75, + 232, + 196, + 231, + 168, + 171, + 84, + 207, + 20, + 166, + 136, + 153, + 47, + 40, + 209, + 206, + 15, + 55, + 206, + 154, + 80, + 5, + 139, + 0, + 51, + 162, + 180, + 96, + 223, + 127, + 193, + 202, + 113, + 56, + 77, + 96, + 211, + 86, + 222, + 40, + 3, + 124, + 49, + 24, + 155, + 101, + 164, + 110, + 251, + 205, + 115, + 224, + 12, + 25, + 138, + 148, + 166, + 140, + 90, + 103, + 194, + 252, + 98, + 158, + 17, + 80, + 223, + 12, + 0, + 195, + 87, + 114, + 248, + 159, + 248, + 255, + 142, + 251, + 191, + 47, + 4, + 47, + 205, + 233, + 20, + 20, + 70, + 175, + 181, + 222, + 100, + 154, + 224, + 239, + 230, + 202, + 214, + 31, + 170, + 201, + 166, + 179, + 167, + 136, + 36, + 90, + 167, + 12, + 136, + 176, + 188, + 152, + 79, + 225, + 73, + 200, + 68, + 183, + 168, + 100, + 183, + 214, + 172, + 238, + 48, + 105, + 78, + 18, + 60, + 173, + 144, + 189, + 67, + 80, + 218, + 63, + 223, + 205, + 154, + 52, + 240, + 93, + 85, + 13, + 153, + 116, + 34, + 64, + 56, + 38, + 23, + 152, + 196, + 87, + 52, + 85, + 156, + 123, + 224, + 172, + 60, + 118, + 79, + 172, + 114, + 173, + 195, + 130, + 211, + 71, + 18, + 49, + 182, + 163, + 142, + 99, + 36, + 103, + 232, + 66, + 19, + 228, + 2, + 54, + 232, + 220, + 37, + 133, + 45, + 151, + 206, + 42, + 99, + 137, + 98, + 203, + 201, + 1, + 28, + 211, + 198, + 221, + 26, + 162, + 74, + 76, + 197, + 111, + 212, + 90, + 238, + 111, + 26, + 53, + 37, + 230, + 22, + 252, + 197, + 72, + 191, + 102, + 251, + 195, + 56, + 79, + 140, + 15, + 81, + 201, + 148, + 59, + 22, + 195, + 93, + 169, + 33, + 24, + 196, + 252, + 95, + 52, + 67, + 65, + 37, + 7, + 223, + 149, + 171, + 75, + 5, + 43, + 126, + 132, + 31, + 157, + 146, + 206, + 16, + 54, + 26, + 2, + 204, + 19, + 65, + 164, + 37, + 62, + 76, + 193, + 157, + 251, + 116, + 231, + 156, + 222, + 82, + 24, + 1, + 128, + 81, + 164, + 234, + 1, + 62, + 16, + 106, + 63, + 156, + 8, + 50, + 29, + 236, + 126, + 127, + 164, + 157, + 234, + 142, + 34, + 91, + 165, + 220, + 190, + 44, + 249, + 178, + 233, + 113, + 111, + 10, + 85, + 95, + 212, + 142, + 188, + 54, + 137, + 69, + 190, + 138, + 215, + 207, + 132, + 230, + 54, + 42, + 127, + 67, + 61, + 0, + 21, + 91, + 227, + 125, + 154, + 47, + 157, + 186, + 93, + 52, + 211, + 138, + 10, + 64, + 124, + 174, + 9, + 39, + 121, + 43, + 150, + 124, + 47, + 240, + 115, + 38, + 140, + 203, + 154, + 87, + 155, + 41, + 28, + 166, + 95, + 140, + 191, + 30, + 58, + 62, + 32, + 77, + 11, + 68, + 193, + 206, + 133, + 97, + 142, + 117, + 192, + 50, + 59, + 98, + 186, + 209, + 204, + 27, + 76, + 103, + 200, + 234, + 93, + 35, + 238, + 197, + 31, + 144, + 52, + 78, + 40, + 55, + 155, + 98, + 18, + 20, + 146, + 120, + 214, + 240, + 159, + 101, + 43, + 69, + 253, + 29, + 57, + 208, + 194, + 169, + 9, + 208, + 235, + 108, + 194, + 28, + 237, + 18, + 81, + 186, + 192, + 10, + 235, + 124, + 108, + 36, + 86, + 161, + 229, + 106, + 10, + 46, + 184, + 1, + 140, + 44, + 220, + 53, + 90, + 20, + 77, + 6, + 200, + 185, + 14, + 172, + 27, + 181, + 197, + 22, + 28, + 49, + 238, + 127, + 115, + 117, + 135, + 103, + 17, + 184, + 78, + 171, + 56, + 129, + 164, + 65, + 54, + 204, + 250, + 184, + 29, + 52, + 171, + 73, + 102, + 27, + 125, + 113, + 149, + 221, + 138, + 71, + 89, + 138, + 232, + 254, + 10, + 233, + 41, + 35, + 20, + 175, + 254, + 45, + 202, + 203, + 52, + 156, + 83, + 221, + 224, + 11, + 5, + 99, + 236, + 3, + 59, + 207, + 80, + 153, + 255, + 98, + 49, + 192, + 51, + 39, + 234, + 48, + 33, + 109, + 199, + 114, + 133, + 101, + 107, + 17, + 164, + 154, + 121, + 125, + 199, + 209, + 39, + 62, + 111, + 125, + 77, + 25, + 55, + 158, + 203, + 213, + 135, + 178, + 141, + 255, + 98, + 9, + 90, + 151, + 124, + 224, + 168, + 13, + 133, + 160, + 10, + 209, + 231, + 139, + 101, + 18, + 188, + 159, + 69, + 6, + 1, + 121, + 0, + 166, + 211, + 111, + 89, + 190, + 48, + 239, + 158, + 3, + 221, + 250, + 197, + 73, + 131, + 202, + 78, + 73, + 7, + 229, + 144, + 222, + 242, + 65, + 255, + 252, + 67, + 12, + 175, + 166, + 180, + 13, + 60, + 158, + 26, + 205, + 16, + 35, + 147, + 84, + 183, + 32, + 94, + 88, + 17, + 154, + 180, + 144, + 208, + 6, + 131, + 6, + 223, + 235, + 220, + 221, + 226, + 60, + 172, + 162, + 235, + 219, + 111, + 42, + 164, + 21, + 52, + 123, + 183, + 68, + 58, + 109, + 47, + 101, + 56, + 30, + 58, + 209, + 153, + 13, + 176, + 29, + 148, + 179, + 49, + 219, + 122, + 37, + 39, + 46, + 14, + 204, + 157, + 60, + 134, + 148, + 149, + 146, + 212, + 239, + 147, + 184, + 20, + 183, + 19, + 96, + 70, + 215, + 98, + 148, + 207, + 165, + 99, + 45, + 223, + 46, + 68, + 29, + 86, + 97, + 255, + 2, + 200, + 47, + 151, + 217, + 49, + 248, + 55, + 161, + 70, + 73, + 225, + 38, + 204, + 129, + 89, + 71, + 205, + 123, + 104, + 244, + 90, + 24, + 240, + 0, + 83, + 234, + 196, + 4, + 73, + 55, + 58, + 79, + 177, + 95, + 248, + 203, + 36, + 143, + 116, + 246, + 207, + 86, + 76, + 186, + 228, + 3, + 202, + 216, + 193, + 92, + 34, + 106, + 195, + 212, + 151, + 51, + 248, + 6, + 246, + 59, + 176, + 207, + 161, + 86, + 122, + 143, + 237, + 120, + 167, + 224, + 155, + 252, + 192, + 133, + 240, + 203, + 201, + 155, + 197, + 120, + 201, + 52, + 99, + 13, + 114, + 42, + 6, + 21, + 225, + 118, + 124, + 254, + 93, + 158, + 150, + 158, + 81, + 2, + 239, + 33, + 248, + 56, + 223, + 186, + 152, + 105, + 177, + 255, + 236, + 233, + 225, + 175, + 247, + 246, + 208, + 98, + 107, + 247, + 210, + 8, + 41, + 92, + 156, + 149, + 18, + 200, + 37, + 28, + 167, + 126, + 118, + 184, + 38, + 2, + 79, + 175, + 181, + 183, + 180, + 243, + 206, + 189, + 107, + 191, + 141, + 31, + 40, + 233, + 46, + 134, + 190, + 25, + 15, + 50, + 80, + 228, + 145, + 120, + 31, + 191, + 214, + 201, + 203, + 221, + 58, + 33, + 107, + 13, + 137, + 26, + 191, + 90, + 40, + 233, + 229, + 182, + 2, + 137, + 114, + 219, + 191, + 22, + 56, + 53, + 0, + 79, + 181, + 20, + 148, + 196, + 94, + 141, + 22, + 199, + 28, + 90, + 15, + 63, + 33, + 139, + 184, + 157, + 27, + 231, + 79, + 151, + 64, + 107, + 81, + 164, + 81, + 4, + 115, + 179, + 183, + 113, + 0, + 114, + 82, + 63, + 33, + 75, + 107, + 166, + 95, + 208, + 29, + 117, + 202, + 105, + 14, + 19, + 131, + 31, + 60, + 43, + 157, + 217, + 33, + 216, + 156, + 39, + 71, + 26, + 166, + 212, + 195, + 113, + 4, + 243, + 15, + 237, + 186, + 241, + 98, + 157, + 170, + 95, + 135, + 14, + 7, + 109, + 34, + 112, + 41, + 114, + 151, + 27, + 92, + 228, + 64, + 234, + 155, + 204, + 210, + 102, + 193, + 57, + 54, + 10, + 197, + 59, + 231, + 173, + 194, + 124, + 229, + 134, + 199, + 152, + 52, + 147, + 46, + 215, + 28, + 17, + 42, + 11, + 227, + 255, + 226, + 82, + 72, + 216, + 211, + 88, + 251, + 86, + 222, + 240, + 101, + 48, + 113, + 183, + 220, + 127, + 63, + 60, + 127, + 24, + 86, + 185, + 68, + 188, + 202, + 139, + 76, + 223, + 196, + 238, + 118, + 137, + 254, + 208, + 131, + 170, + 165, + 90, + 63, + 95, + 27, + 49, + 196, + 82, + 141, + 143, + 161, + 154, + 132, + 197, + 83, + 204, + 224, + 23, + 193, + 32, + 170, + 196, + 90, + 185, + 81, + 186, + 234, + 159, + 181, + 219, + 46, + 229, + 236, + 80, + 83, + 113, + 120, + 33, + 28, + 107, + 238, + 119, + 22, + 22, + 212, + 112, + 50, + 227, + 231, + 1, + 172, + 241, + 86, + 170, + 51, + 103, + 98, + 104, + 78, + 203, + 88, + 17, + 172, + 46, + 203, + 211, + 125, + 208, + 167, + 203, + 73, + 44, + 250, + 115, + 26, + 114, + 45, + 60, + 94, + 225, + 206, + 110, + 142, + 63, + 28, + 12, + 172, + 134, + 242, + 64, + 244, + 137, + 45, + 53, + 43, + 223, + 240, + 246, + 105, + 159, + 236, + 69, + 1, + 105, + 33, + 212, + 62, + 190, + 244, + 236, + 143, + 236, + 190, + 137, + 120, + 16, + 21, + 19, + 190, + 49, + 74, + 105, + 27, + 222, + 143, + 174, + 24, + 157, + 255, + 171, + 133, + 255, + 152, + 191, + 35, + 76, + 117, + 117, + 46, + 243, + 41, + 50, + 120, + 74, + 182, + 69, + 43, + 78, + 50, + 150, + 145, + 76, + 86, + 71, + 46, + 34, + 161, + 155, + 214, + 28, + 78, + 46, + 203, + 17, + 252, + 137, + 121, + 27, + 59, + 247, + 184, + 109, + 144, + 205, + 31, + 88, + 144, + 109, + 188, + 47, + 238, + 32, + 47, + 235, + 16, + 22, + 111, + 12, + 105, + 156, + 220, + 69, + 82, + 148, + 30, + 16, + 45, + 67, + 163, + 103, + 127, + 244, + 33, + 129, + 64, + 108, + 92, + 201, + 216, + 160, + 196, + 14, + 67, + 3, + 111, + 96, + 171, + 13, + 234, + 232, + 211, + 86, + 101, + 238, + 138, + 67, + 163, + 37, + 56, + 99, + 207, + 60, + 220, + 3, + 91, + 31, + 43, + 122, + 238, + 40, + 129, + 211, + 195, + 19, + 79, + 75, + 91, + 43, + 100, + 100, + 21, + 65, + 153, + 104, + 69, + 98, + 87, + 93, + 145, + 43, + 59, + 69, + 218, + 49, + 51, + 137, + 163, + 99, + 239, + 144, + 182, + 210, + 28, + 147, + 23, + 179, + 37, + 180, + 109, + 209, + 101, + 11, + 200, + 221, + 62, + 154, + 170, + 171, + 186, + 116, + 122, + 173, + 22, + 108, + 198, + 92, + 37, + 171, + 253, + 193, + 66, + 68, + 202, + 33, + 115, + 182, + 41, + 20, + 65, + 128, + 33, + 99, + 248, + 247, + 71, + 96, + 121, + 16, + 93, + 182, + 34, + 194, + 200, + 146, + 165, + 22, + 93, + 86, + 201, + 30, + 119, + 232, + 171, + 84, + 118, + 43, + 247, + 215, + 76, + 227, + 84, + 0, + 198, + 221, + 134, + 168, + 6, + 31, + 132, + 137, + 59, + 151, + 135, + 39, + 122, + 240, + 18, + 190, + 212, + 89, + 245, + 18, + 40, + 130, + 105, + 43, + 138, + 108, + 177, + 118, + 51, + 37, + 114, + 188, + 76, + 71, + 83, + 122, + 238, + 133, + 156, + 11, + 168, + 234, + 104, + 82, + 3, + 219, + 191, + 174, + 208, + 23, + 138, + 153, + 117, + 58, + 118, + 197, + 224, + 94, + 45, + 236, + 135, + 90, + 30, + 146, + 220, + 183, + 42, + 190, + 156, + 110, + 118, + 65, + 33, + 76, + 136, + 79, + 66, + 37, + 187, + 80, + 255, + 76, + 236, + 220, + 93, + 10, + 51, + 144, + 62, + 215, + 176, + 99, + 46, + 212, + 29, + 208, + 203, + 19, + 113, + 74, + 245, + 195, + 138, + 214, + 221, + 246, + 142, + 135, + 93, + 23, + 215, + 191, + 221, + 26, + 254, + 120, + 58, + 131, + 232, + 203, + 124, + 121, + 149, + 2, + 229, + 87, + 120, + 28, + 54, + 165, + 83, + 79, + 67, + 243, + 47, + 125, + 61, + 170, + 254, + 232, + 26, + 112, + 182, + 104, + 216, + 17, + 153, + 156, + 194, + 13, + 253, + 16, + 250, + 145, + 187, + 89, + 230, + 127, + 208, + 33, + 30, + 223, + 33, + 127, + 163, + 90, + 220, + 215, + 248, + 56, + 133, + 80, + 179, + 112, + 140, + 72, + 17, + 0, + 105, + 51, + 82, + 198, + 77, + 255, + 10, + 211, + 44, + 38, + 201, + 211, + 6, + 88, + 161, + 1, + 76, + 23, + 103, + 53, + 46, + 135, + 50, + 87, + 83, + 139, + 101, + 151, + 125, + 235, + 150, + 62, + 108, + 93, + 254, + 252, + 244, + 187, + 80, + 140, + 221, + 91, + 20, + 175, + 6, + 176, + 120, + 201, + 228, + 34, + 3, + 60, + 190, + 189, + 43, + 92, + 167, + 216, + 116, + 133, + 34, + 145, + 28, + 27, + 160, + 255, + 195, + 211, + 98, + 102, + 51, + 242, + 187, + 148, + 244, + 228, + 57, + 67, + 137, + 255, + 250, + 108, + 97, + 48, + 7, + 29, + 183, + 203, + 94, + 77, + 164, + 22, + 155, + 188, + 94, + 10, + 45, + 116, + 116, + 244, + 8, + 33, + 246, + 62, + 50, + 161, + 27, + 114, + 183, + 161, + 29, + 150, + 253, + 157, + 137, + 143, + 229, + 91, + 110, + 212, + 231, + 193, + 58, + 114, + 235, + 24, + 108, + 109, + 39, + 230, + 157, + 207, + 91, + 62, + 139, + 6, + 97, + 188, + 37, + 69, + 42, + 184, + 28, + 241, + 143, + 2, + 202, + 192, + 212, + 60, + 89, + 3, + 179, + 119, + 194, + 181, + 55, + 211, + 198, + 33, + 115, + 133, + 210, + 99, + 127, + 132, + 158, + 196, + 138, + 52, + 138, + 10, + 135, + 229, + 247, + 160, + 202, + 31, + 131, + 138, + 149, + 243, + 6, + 48, + 68, + 254, + 130, + 175, + 92, + 11, + 249, + 8, + 8, + 212, + 71, + 249, + 37, + 225, + 21, + 115, + 138, + 175, + 190, + 18, + 163, + 145, + 82, + 142, + 149, + 235, + 213, + 84, + 16, + 218, + 91, + 231, + 227, + 94, + 155, + 198, + 118, + 245, + 196, + 87, + 121, + 79, + 85, + 243, + 182, + 192, + 73, + 239, + 82, + 200, + 101, + 116, + 38, + 6, + 4, + 94, + 48, + 143, + 217, + 195, + 77, + 242, + 82, + 219, + 167, + 198, + 95, + 43, + 78, + 46, + 43, + 63, + 7, + 154, + 47, + 193, + 109, + 88, + 100, + 53, + 230, + 12, + 79, + 236, + 97, + 38, + 217, + 69, + 197, + 203, + 111, + 191, + 59, + 187, + 116, + 208, + 231, + 137, + 208, + 51, + 187, + 63, + 109, + 115, + 15, + 114, + 200, + 45, + 132, + 94, + 62, + 39, + 149, + 155, + 163, + 253, + 172, + 250, + 42, + 154, + 202, + 128, + 220, + 28, + 113, + 129, + 179, + 80, + 26, + 240, + 49, + 168, + 101, + 237, + 180, + 74, + 115, + 205, + 133, + 104, + 173, + 47, + 46, + 228, + 75, + 243, + 225, + 60, + 92, + 65, + 181, + 98, + 229, + 243, + 110, + 98, + 204, + 211, + 151, + 174, + 4, + 43, + 162, + 253, + 153, + 79, + 73, + 77, + 61, + 56, + 219, + 130, + 220, + 244, + 151, + 159, + 60, + 74, + 187, + 113, + 178, + 82, + 151, + 103, + 215, + 55, + 213, + 17, + 87, + 188, + 86, + 199, + 225, + 146, + 225, + 22, + 185, + 206, + 201, + 110, + 140, + 129, + 94, + 47, + 248, + 79, + 124, + 103, + 137, + 68, + 191, + 38, + 243, + 88, + 231, + 250, + 115, + 116, + 218, + 249, + 5, + 30, + 124, + 150, + 138, + 213, + 145, + 207, + 165, + 223, + 191, + 12, + 212, + 141, + 14, + 85, + 182, + 164, + 135, + 17, + 95, + 241, + 88, + 47, + 4, + 147, + 77, + 213, + 98, + 92, + 31, + 239, + 28, + 158, + 137, + 4, + 120, + 255, + 15, + 80, + 158, + 235, + 168, + 38, + 228, + 5, + 238, + 90, + 47, + 155, + 30, + 154, + 145, + 94, + 90, + 90, + 110, + 214, + 129, + 61, + 34, + 117, + 143, + 43, + 111, + 238, + 94, + 239, + 32, + 119, + 15, + 154, + 50, + 123, + 156, + 67, + 150, + 162, + 252, + 169, + 28, + 172, + 16, + 223, + 196, + 67, + 175, + 92, + 25, + 206, + 3, + 237, + 244, + 235, + 231, + 150, + 121, + 148, + 122, + 102, + 228, + 183, + 3, + 234, + 29, + 90, + 81, + 76, + 140, + 124, + 141, + 190, + 48, + 103, + 21, + 13, + 67, + 59, + 165, + 37, + 204, + 224, + 236, + 159, + 112, + 45, + 184, + 82, + 179, + 165, + 232, + 140, + 131, + 30, + 133, + 129, + 224, + 217, + 58, + 18, + 138, + 241, + 225, + 138, + 14, + 204, + 212, + 210, + 11, + 158, + 250, + 171, + 101, + 242, + 241, + 101, + 205, + 159, + 208, + 207, + 135, + 80, + 171, + 194, + 189, + 72, + 153, + 230, + 110, + 56, + 249, + 99, + 197, + 146, + 199, + 182, + 218, + 107, + 158, + 140, + 236, + 252, + 224, + 149, + 239, + 115, + 221, + 81, + 90, + 235, + 140, + 141, + 157, + 85, + 229, + 9, + 60, + 160, + 122, + 28, + 102, + 113, + 218, + 61, + 123, + 21, + 135, + 34, + 185, + 97, + 155, + 48, + 52, + 44, + 177, + 30, + 250, + 183, + 187, + 35, + 9, + 18, + 164, + 246, + 14, + 29, + 183, + 181, + 134, + 194, + 229, + 17, + 12, + 76, + 60, + 36, + 82, + 104, + 4, + 0, + 159, + 53, + 9, + 153, + 92, + 74, + 198, + 120, + 209, + 107, + 209, + 246, + 49, + 177, + 188, + 94, + 155, + 110, + 160, + 173, + 158, + 193, + 38, + 112, + 38, + 62, + 39, + 36, + 201, + 145, + 236, + 243, + 207, + 170, + 164, + 169, + 128, + 105, + 199, + 129, + 166, + 5, + 117, + 254, + 190, + 245, + 195, + 238, + 10, + 61, + 168, + 238, + 98, + 189, + 133, + 21, + 244, + 122, + 75, + 62, + 141, + 172, + 230, + 114, + 107, + 250, + 197, + 175, + 59, + 252, + 233, + 44, + 107, + 44, + 140, + 51, + 115, + 69, + 136, + 61, + 248, + 78, + 181, + 140, + 244, + 164, + 253, + 155, + 233, + 11, + 212, + 58, + 69, + 26, + 209, + 105, + 40, + 127, + 82, + 164, + 80, + 130, + 128, + 196, + 31, + 154, + 94, + 178, + 25, + 42, + 60, + 194, + 199, + 14, + 214, + 112, + 211, + 187, + 67, + 52, + 90, + 225, + 182, + 92, + 209, + 75, + 138, + 89, + 192, + 0, + 241, + 94, + 93, + 54, + 206, + 207, + 121, + 7, + 249, + 248, + 252, + 150, + 6, + 100, + 9, + 194, + 16, + 159, + 179, + 220, + 156, + 211, + 70, + 110, + 220, + 97, + 121, + 10, + 219, + 16, + 61, + 227, + 62, + 67, + 55, + 4, + 228, + 252, + 208, + 216, + 221, + 82, + 251, + 147, + 238, + 161, + 33, + 244, + 113, + 33, + 203, + 134, + 61, + 129, + 119, + 59, + 95, + 31, + 107, + 46, + 145, + 231, + 164, + 187, + 55, + 170, + 9, + 175, + 122, + 151, + 203, + 221, + 139, + 141, + 194, + 9, + 89, + 56, + 251, + 233, + 219, + 231, + 56, + 123, + 208, + 2, + 106, + 79, + 69, + 94, + 195, + 221, + 42, + 3, + 95, + 163, + 128, + 10, + 112, + 204, + 17, + 222, + 158, + 44, + 101, + 254, + 202, + 147, + 113, + 14, + 56, + 162, + 79, + 215, + 43, + 117, + 10, + 178, + 69, + 167, + 90, + 94, + 190, + 184, + 1, + 109, + 234, + 141, + 186, + 85, + 82, + 42, + 45, + 190, + 94, + 36, + 92, + 253, + 134, + 15, + 22, + 220, + 246, + 143, + 126, + 123, + 88, + 216, + 66, + 74, + 92, + 17, + 228, + 19, + 4, + 217, + 162, + 210, + 11, + 212, + 179, + 197, + 222, + 244, + 1, + 199, + 50, + 53, + 207, + 97, + 118, + 179, + 111, + 28, + 181, + 108, + 191, + 7, + 85, + 18, + 76, + 22, + 80, + 25, + 87, + 3, + 79, + 84, + 156, + 190, + 247, + 123, + 131, + 111, + 171, + 74, + 190, + 245, + 252, + 199, + 23, + 241, + 187, + 5, + 147, + 130, + 162, + 134, + 200, + 48, + 17, + 32, + 159, + 190, + 52, + 147, + 180, + 83, + 49, + 176, + 152, + 198, + 201, + 42, + 151, + 146, + 97, + 153, + 237, + 152, + 82, + 225, + 133, + 72, + 21, + 11, + 137, + 123, + 32, + 100, + 17, + 225, + 220, + 138, + 58, + 76, + 235, + 10, + 22, + 26, + 94, + 184, + 40, + 41, + 41, + 49, + 39, + 113, + 226, + 92, + 216, + 240, + 156, + 40, + 184, + 56, + 33, + 42, + 83, + 117, + 122, + 194, + 4, + 9, + 73, + 74, + 231, + 190, + 207, + 71, + 193, + 59, + 132, + 225, + 109, + 141, + 124, + 137, + 235, + 208, + 66, + 194, + 231, + 5, + 17, + 186, + 38, + 155, + 99, + 26, + 12, + 116, + 112, + 226, + 23, + 90, + 219, + 136, + 110, + 173, + 67, + 152, + 10, + 78, + 0, + 119, + 20, + 157, + 247, + 210, + 230, + 59, + 250, + 157, + 224, + 93, + 97, + 24, + 22, + 22, + 5, + 122, + 87, + 28, + 143, + 169, + 116, + 55, + 170, + 186, + 34, + 184, + 203, + 252, + 233, + 79, + 168, + 222, + 96, + 165, + 58, + 197, + 69, + 38, + 196, + 81, + 231, + 38, + 96, + 95, + 245, + 158, + 155, + 201, + 72, + 196, + 246, + 45, + 217, + 249, + 64, + 47, + 188, + 160, + 30, + 163, + 143, + 30, + 177, + 238, + 70, + 11, + 216, + 40, + 14, + 208, + 244, + 70, + 135, + 33, + 49, + 152, + 217, + 218, + 202, + 19, + 255, + 42, + 193, + 2, + 46, + 29, + 217, + 68, + 189, + 115, + 109, + 87, + 55, + 10, + 244, + 225, + 106, + 76, + 196, + 242, + 247, + 122, + 109, + 68, + 166, + 61, + 0, + 12, + 88, + 36, + 183, + 201, + 39, + 37, + 92, + 89, + 139, + 75, + 222, + 194, + 187, + 142, + 149, + 64, + 88, + 41, + 157, + 21, + 112, + 222, + 166, + 11, + 249, + 210, + 163, + 6, + 147, + 36, + 68, + 38, + 178, + 159, + 81, + 167, + 0, + 132, + 136, + 41, + 38, + 59, + 28, + 243, + 62, + 7, + 30, + 252, + 218, + 83, + 123, + 207, + 219, + 64, + 84, + 53, + 238, + 10, + 145, + 94, + 131, + 12, + 6, + 31, + 209, + 34, + 192, + 184, + 218, + 249, + 187, + 205, + 178, + 137, + 207, + 68, + 228, + 229, + 186, + 229, + 114, + 48, + 112, + 121, + 22, + 221, + 17, + 131, + 12, + 202, + 226, + 36, + 7, + 11, + 125, + 24, + 230, + 249, + 87, + 241, + 180, + 172, + 25, + 100, + 91, + 126, + 19, + 135, + 107, + 144, + 172, + 97, + 15, + 12, + 246, + 159, + 29, + 64, + 127, + 44, + 48, + 108, + 148, + 8, + 184, + 236, + 134, + 76, + 123, + 87, + 70, + 96, + 37, + 154, + 35, + 76, + 157, + 149, + 95, + 9, + 137, + 123, + 40, + 121, + 179, + 106, + 4, + 48, + 211, + 228, + 206, + 124, + 195, + 126, + 236, + 37, + 184, + 74, + 33, + 229, + 227, + 189, + 102, + 223, + 62, + 237, + 207, + 208, + 249, + 156, + 222, + 181, + 141, + 85, + 121, + 147, + 226, + 106, + 129, + 195, + 55, + 178, + 100, + 160, + 34, + 113, + 150, + 79, + 94, + 153, + 120, + 91, + 193, + 35, + 232, + 76, + 247, + 250, + 227, + 115, + 233, + 173, + 220, + 229, + 192, + 183, + 173, + 128, + 91, + 75, + 26, + 126, + 132, + 145, + 85, + 83, + 235, + 0, + 178, + 159, + 45, + 226, + 201, + 91, + 139, + 119, + 143, + 162, + 53, + 176, + 47, + 117, + 24, + 192, + 8, + 2, + 100, + 18, + 185, + 207, + 245, + 57, + 42, + 177, + 175, + 156, + 41, + 144, + 239, + 190, + 140, + 109, + 170, + 241, + 14, + 187, + 163, + 204, + 117, + 213, + 254, + 211, + 129, + 144, + 157, + 61, + 29, + 175, + 25, + 101, + 171, + 239, + 236, + 88, + 169, + 70, + 212, + 116, + 190, + 163, + 134, + 167, + 104, + 228, + 232, + 9, + 237, + 26, + 179, + 105, + 240, + 176, + 85, + 139, + 225, + 26, + 32, + 89, + 73, + 96, + 218, + 6, + 143, + 16, + 116, + 10, + 49, + 76, + 227, + 188, + 39, + 1, + 158, + 55, + 197, + 237, + 189, + 19, + 15, + 66, + 136, + 196, + 213, + 58, + 98, + 171, + 162, + 4, + 77, + 27, + 100, + 107, + 64, + 229, + 34, + 75, + 229, + 79, + 32, + 43, + 237, + 81, + 198, + 99, + 120, + 158, + 104, + 43, + 224, + 213, + 180, + 149, + 10, + 194, + 43, + 251, + 83, + 143, + 172, + 94, + 141, + 13, + 46, + 125, + 248, + 32, + 234, + 121, + 103, + 0, + 40, + 160, + 19, + 134, + 146, + 222, + 131, + 205, + 238, + 97, + 149, + 15, + 99, + 227, + 86, + 103, + 235, + 248, + 182, + 95, + 54, + 61, + 54, + 11, + 162, + 191, + 47, + 34, + 104, + 29, + 236, + 107, + 60, + 12, + 242, + 204, + 209, + 75, + 60, + 25, + 67, + 38, + 190, + 53, + 38, + 75, + 195, + 144, + 161, + 77, + 124, + 192, + 30, + 149, + 144, + 215, + 24, + 20, + 237, + 8, + 114, + 242, + 107, + 11, + 198, + 104, + 27, + 149, + 8, + 171, + 128, + 6, + 95, + 230, + 228, + 172, + 171, + 7, + 105, + 229, + 4, + 30, + 45, + 159, + 22, + 141, + 193, + 107, + 57, + 3, + 235, + 26, + 215, + 45, + 217, + 13, + 52, + 192, + 245, + 228, + 3, + 223, + 155, + 243, + 157, + 118, + 84, + 12, + 121, + 14, + 137, + 181, + 164, + 132, + 197, + 210, + 170, + 149, + 240, + 11, + 174, + 228, + 29, + 150, + 242, + 216, + 30, + 1, + 67, + 173, + 191, + 214, + 168, + 148, + 51, + 4, + 204, + 251, + 41, + 29, + 117, + 0, + 220, + 177, + 185, + 90, + 116, + 193, + 29, + 106, + 7, + 193, + 87, + 179, + 177, + 28, + 64, + 58, + 213, + 26, + 118, + 214, + 40, + 255, + 207, + 43, + 112, + 50, + 1, + 246, + 158, + 46, + 48, + 16, + 122, + 101, + 253, + 252, + 244, + 147, + 119, + 254, + 97, + 242, + 26, + 109, + 49, + 206, + 142, + 100, + 165, + 77, + 0, + 128, + 208, + 249, + 141, + 214, + 200, + 160, + 39, + 206, + 255, + 42, + 231, + 83, + 226, + 243, + 60, + 150, + 124, + 219, + 36, + 226, + 119, + 97, + 2, + 180, + 228, + 74, + 79, + 151, + 202, + 43, + 2, + 219, + 160, + 206, + 91, + 127, + 12, + 24, + 21, + 85, + 45, + 91, + 136, + 251, + 252, + 187, + 243, + 213, + 170, + 184, + 192, + 9, + 54, + 118, + 92, + 51, + 45, + 238, + 1, + 167, + 78, + 44, + 199, + 253, + 181, + 140, + 63, + 132, + 192, + 178, + 186, + 105, + 27, + 125, + 97, + 105, + 34, + 176, + 98, + 122, + 142, + 195, + 219, + 165, + 132, + 193, + 167, + 43, + 40, + 230, + 233, + 247, + 44, + 104, + 234, + 10, + 236, + 100, + 228, + 153, + 40, + 131, + 129, + 46, + 162, + 24, + 160, + 127, + 216, + 45, + 244, + 228, + 195, + 36, + 231, + 3, + 184, + 90, + 229, + 104, + 80, + 11, + 164, + 191, + 211, + 104, + 182, + 116, + 233, + 79, + 178, + 22, + 137, + 169, + 109, + 215, + 18, + 112, + 50, + 139, + 216, + 92, + 197, + 225, + 97, + 95, + 219, + 150, + 99, + 5, + 64, + 110, + 65, + 87, + 87, + 196, + 57, + 112, + 235, + 93, + 236, + 184, + 139, + 195, + 39, + 171, + 117, + 231, + 85, + 129, + 3, + 79, + 47, + 22, + 254, + 56, + 96, + 90, + 203, + 233, + 206, + 47, + 112, + 139, + 188, + 209, + 236, + 96, + 27, + 59, + 50, + 122, + 232, + 9, + 74, + 184, + 83, + 134, + 18, + 92, + 226, + 65, + 80, + 240, + 60, + 27, + 64, + 89, + 55, + 205, + 62, + 129, + 99, + 40, + 133, + 24, + 82, + 254, + 35, + 176, + 76, + 83, + 169, + 208, + 205, + 37, + 219, + 132, + 75, + 44, + 210, + 49, + 194, + 165, + 175, + 212, + 181, + 79, + 58, + 159, + 102, + 215, + 162, + 230, + 61, + 224, + 195, + 234, + 228, + 185, + 187, + 254, + 166, + 10, + 145, + 215, + 1, + 140, + 23, + 77, + 67, + 13, + 2, + 60, + 89, + 202, + 140, + 68, + 253, + 6, + 89, + 79, + 24, + 81, + 35, + 64, + 160, + 3, + 254, + 196, + 41, + 72, + 170, + 108, + 154, + 64, + 188, + 40, + 139, + 149, + 125, + 36, + 103, + 178, + 154, + 73, + 64, + 217, + 56, + 91, + 212, + 0, + 247, + 71, + 201, + 231, + 124, + 233, + 108, + 50, + 33, + 162, + 131, + 100, + 155, + 153, + 64, + 21, + 30, + 233, + 64, + 51, + 35, + 72, + 242, + 62, + 89, + 75, + 216, + 180, + 206, + 191, + 150, + 77, + 27, + 149, + 157, + 251, + 40, + 179, + 251, + 228, + 71, + 57, + 230, + 65, + 98, + 157, + 150, + 31, + 225, + 108, + 197, + 52, + 239, + 45, + 153, + 72, + 88, + 224, + 195, + 177, + 53, + 217, + 137, + 193, + 113, + 11, + 59, + 206, + 108, + 32, + 26, + 217, + 66, + 144, + 213, + 227, + 180, + 167, + 151, + 20, + 118, + 131, + 5, + 163, + 251, + 243, + 129, + 40, + 163, + 32, + 207, + 118, + 119, + 64, + 214, + 213, + 114, + 202, + 21, + 5, + 247, + 116, + 91, + 16, + 148, + 44, + 177, + 78, + 51, + 95, + 235, + 59, + 108, + 120, + 53, + 179, + 22, + 16, + 126, + 175, + 205, + 8, + 73, + 240, + 26, + 55, + 208, + 199, + 28, + 213, + 67, + 99, + 150, + 213, + 176, + 189, + 191, + 108, + 197, + 116, + 103, + 81, + 65, + 66, + 142, + 165, + 61, + 195, + 243, + 126, + 240, + 207, + 7, + 171, + 99, + 194, + 117, + 124, + 81, + 180, + 14, + 55, + 3, + 175, + 8, + 170, + 235, + 105, + 16, + 219, + 135, + 20, + 151, + 194, + 245, + 47, + 230, + 237, + 216, + 179, + 244, + 230, + 76, + 179, + 224, + 129, + 200, + 133, + 247, + 103, + 96, + 13, + 92, + 183, + 161, + 226, + 180, + 78, + 183, + 74, + 28, + 48, + 3, + 62, + 91, + 9, + 113, + 86, + 115, + 131, + 217, + 246, + 95, + 228, + 100, + 87, + 62, + 203, + 230, + 207, + 127, + 107, + 34, + 84, + 198, + 217, + 134, + 89, + 128, + 219, + 103, + 248, + 65, + 109, + 73, + 107, + 144, + 144, + 36, + 50, + 241, + 224, + 98, + 250, + 248, + 215, + 66, + 94, + 104, + 17, + 252, + 166, + 154, + 53, + 156, + 87, + 202, + 107, + 137, + 47, + 139, + 95, + 48, + 187, + 181, + 151, + 80, + 45, + 210, + 209, + 60, + 48, + 96, + 42, + 80, + 187, + 99, + 159, + 154, + 120, + 136, + 44, + 111, + 35, + 161, + 140, + 0, + 125, + 136, + 165, + 0, + 147, + 145, + 200, + 253, + 193, + 91, + 13, + 87, + 194, + 69, + 41, + 38, + 46, + 194, + 151, + 35, + 5, + 8, + 37, + 124, + 111, + 251, + 63, + 67, + 72, + 25, + 4, + 127, + 49, + 8, + 42, + 237, + 180, + 18, + 123, + 47, + 29, + 132, + 208, + 178, + 75, + 191, + 17, + 100, + 42, + 55, + 41, + 237, + 1, + 177, + 83, + 96, + 177, + 152, + 182, + 189, + 204, + 115, + 37, + 94, + 253, + 143, + 168, + 179, + 200, + 179, + 244, + 231, + 231, + 182, + 136, + 26, + 229, + 193, + 42, + 145, + 86, + 177, + 9, + 167, + 128, + 121, + 146, + 74, + 202, + 134, + 168, + 173, + 226, + 203, + 32, + 169, + 121, + 205, + 35, + 5, + 215, + 59, + 62, + 175, + 56, + 139, + 149, + 52, + 132, + 155, + 121, + 120, + 21, + 84, + 154, + 141, + 206, + 200, + 164, + 1, + 99, + 82, + 44, + 81, + 95, + 98, + 84, + 146, + 79, + 226, + 21, + 79, + 193, + 79, + 251, + 180, + 203, + 86, + 152, + 205, + 164, + 147, + 164, + 209, + 49, + 232, + 106, + 254, + 122, + 243, + 13, + 86, + 60, + 63, + 91, + 236, + 36, + 82, + 230, + 63, + 186, + 94, + 137, + 74, + 236, + 21, + 66, + 25, + 111, + 207, + 79, + 143, + 95, + 101, + 44, + 186, + 2, + 170, + 185, + 222, + 181, + 109, + 71, + 177, + 184, + 37, + 227, + 173, + 54, + 96, + 62, + 112, + 46, + 185, + 96, + 83, + 33, + 77, + 145, + 57, + 66, + 32, + 161, + 236, + 34, + 157, + 195, + 163, + 55, + 219, + 156, + 158, + 178, + 129, + 17, + 106, + 178, + 155, + 203, + 1, + 76, + 162, + 205, + 105, + 81, + 202, + 248, + 213, + 97, + 253, + 77, + 135, + 39, + 132, + 132, + 170, + 11, + 117, + 62, + 142, + 97, + 85, + 36, + 129, + 88, + 110, + 19, + 128, + 87, + 30, + 140, + 211, + 37, + 0, + 204, + 46, + 216, + 175, + 230, + 44, + 171, + 135, + 250, + 195, + 199, + 237, + 104, + 116, + 46, + 156, + 107, + 26, + 71, + 253, + 139, + 161, + 105, + 155, + 78, + 8, + 95, + 254, + 124, + 90, + 6, + 100, + 168, + 37, + 4, + 163, + 116, + 250, + 76, + 206, + 44, + 21, + 215, + 133, + 81, + 239, + 29, + 188, + 53, + 244, + 90, + 76, + 107, + 30, + 149, + 90, + 152, + 100, + 229, + 124, + 137, + 52, + 243, + 245, + 75, + 161, + 191, + 226, + 43, + 184, + 209, + 180, + 34, + 185, + 193, + 108, + 246, + 50, + 231, + 126, + 199, + 173, + 54, + 47, + 182, + 180, + 75, + 201, + 13, + 74, + 70, + 176, + 153, + 42, + 135, + 127, + 92, + 195, + 78, + 57, + 36, + 166, + 63, + 99, + 221, + 179, + 154, + 52, + 42, + 246, + 131, + 132, + 138, + 113, + 54, + 86, + 18, + 30, + 102, + 15, + 15, + 97, + 209, + 165, + 5, + 74, + 235, + 165, + 75, + 228, + 31, + 102, + 37, + 150, + 96, + 213, + 251, + 0, + 23, + 141, + 170, + 50, + 80, + 154, + 159, + 177, + 62, + 41, + 109, + 72, + 150, + 228, + 15, + 49, + 186, + 17, + 219, + 80, + 152, + 131, + 71, + 38, + 35, + 209, + 115, + 6, + 184, + 99, + 2, + 82, + 101, + 122, + 179, + 85, + 237, + 180, + 85, + 63, + 46, + 115, + 244, + 49, + 49, + 56, + 103, + 155, + 40, + 245, + 18, + 114, + 171, + 10, + 28, + 204, + 129, + 198, + 48, + 81, + 131, + 95, + 17, + 168, + 231, + 94, + 223, + 52, + 236, + 86, + 159, + 117, + 104, + 116, + 117, + 170, + 188, + 140, + 50, + 119, + 124, + 183, + 123, + 8, + 103, + 190, + 224, + 218, + 160, + 81, + 130, + 21, + 142, + 229, + 81, + 69, + 43, + 150, + 160, + 97, + 93, + 135, + 184, + 21, + 85, + 96, + 73, + 249, + 134, + 68, + 166, + 196, + 49, + 137, + 247, + 152, + 12, + 43, + 74, + 3, + 38, + 124, + 1, + 219, + 93, + 240, + 5, + 218, + 244, + 48, + 226, + 87, + 67, + 157, + 79, + 106, + 56, + 255, + 56, + 10, + 24, + 63, + 168, + 172, + 239, + 83, + 218, + 238, + 192, + 229, + 226, + 149, + 242, + 218, + 8, + 174, + 231, + 84, + 37, + 105, + 150, + 127, + 16, + 219, + 59, + 246, + 168, + 205, + 22, + 241, + 163, + 101, + 14, + 112, + 62, + 228, + 238, + 206, + 41, + 132, + 49, + 117, + 142, + 237, + 140, + 229, + 63, + 174, + 0, + 215, + 172, + 59, + 185, + 22, + 139, + 53, + 52, + 106, + 3, + 174, + 49, + 250, + 111, + 214, + 238, + 29, + 217, + 208, + 184, + 229, + 119, + 238, + 94, + 161, + 133, + 225, + 87, + 33, + 0, + 171, + 106, + 19, + 11, + 206, + 116, + 225, + 209, + 140, + 107, + 233, + 69, + 138, + 37, + 207, + 198, + 140, + 84, + 139, + 180, + 17, + 46, + 50, + 163, + 128, + 255, + 82, + 227, + 73, + 232, + 133, + 152, + 238, + 211, + 155, + 117, + 86, + 95, + 62, + 85, + 43, + 12, + 0, + 205, + 50, + 97, + 167, + 72, + 108, + 182, + 41, + 45, + 176, + 211, + 144, + 1, + 110, + 142, + 53, + 178, + 87, + 132, + 167, + 178, + 123, + 25, + 152, + 146, + 138, + 250, + 8, + 196, + 207, + 160, + 85, + 165, + 90, + 41, + 87, + 174, + 243, + 148, + 87, + 124, + 189, + 52, + 249, + 224, + 19, + 15, + 117, + 4, + 210, + 118, + 15, + 153, + 120, + 157, + 122, + 250, + 59, + 177, + 11, + 130, + 6, + 97, + 104, + 116, + 239, + 17, + 65, + 159, + 252, + 146, + 176, + 71, + 93, + 117, + 188, + 53, + 138, + 235, + 227, + 69, + 250, + 114, + 26, + 254, + 109, + 69, + 137, + 170, + 81, + 2, + 137, + 212, + 161, + 124, + 120, + 182, + 52, + 56, + 250, + 189, + 117, + 41, + 233, + 180, + 31, + 33, + 36, + 246, + 182, + 199, + 86, + 147, + 73, + 54, + 30, + 51, + 45, + 179, + 111, + 177, + 99, + 56, + 10, + 75, + 141, + 154, + 10, + 128, + 68, + 69, + 13, + 181, + 161, + 196, + 146, + 194, + 225, + 152, + 165, + 38, + 201, + 177, + 13, + 59, + 60, + 69, + 22, + 186, + 88, + 87, + 94, + 213, + 51, + 153, + 251, + 191, + 219, + 253, + 66, + 239, + 61, + 50, + 54, + 80, + 58, + 96, + 156, + 111, + 22, + 196, + 240, + 125, + 154, + 193, + 1, + 130, + 70, + 79, + 162, + 192, + 70, + 167, + 36, + 97, + 197, + 48, + 70, + 95, + 196, + 143, + 143, + 0, + 186, + 51, + 209, + 224, + 207, + 138, + 17, + 146, + 7, + 156, + 200, + 241, + 0, + 118, + 80, + 157, + 196, + 180, + 234, + 219, + 188, + 141, + 141, + 58, + 232, + 98, + 66, + 245, + 207, + 236, + 124, + 207, + 127, + 69, + 151, + 198, + 145, + 2, + 186, + 162, + 187, + 42, + 15, + 41, + 109, + 250, + 111, + 206, + 104, + 141, + 193, + 10, + 44, + 150, + 164, + 92, + 48, + 161, + 212, + 143, + 152, + 169, + 83, + 48, + 177, + 55, + 139, + 254, + 142, + 233, + 53, + 115, + 44, + 241, + 156, + 91, + 167, + 192, + 62, + 141, + 202, + 230, + 218, + 143, + 94, + 183, + 199, + 16, + 7, + 63, + 228, + 218, + 54, + 36, + 52, + 104, + 183, + 91, + 226, + 215, + 243, + 224, + 27, + 128, + 146, + 43, + 238, + 49, + 7, + 34, + 27, + 12, + 202, + 122, + 227, + 36, + 145, + 58, + 252, + 97, + 153, + 167, + 165, + 182, + 166, + 220, + 188, + 110, + 27, + 59, + 53, + 238, + 30, + 163, + 228, + 218, + 166, + 202, + 219, + 109, + 154, + 158, + 169, + 158, + 142, + 194, + 232, + 5, + 139, + 185, + 95, + 221, + 2, + 46, + 50, + 50, + 165, + 136, + 20, + 123, + 169, + 90, + 247, + 233, + 167, + 231, + 134, + 192, + 38, + 37, + 123, + 10, + 184, + 170, + 38, + 79, + 117, + 11, + 199, + 236, + 23, + 143, + 250, + 209, + 194, + 138, + 143, + 226, + 96, + 223, + 49, + 27, + 58, + 77, + 198, + 204, + 145, + 158, + 242, + 51, + 200, + 160, + 180, + 155, + 189, + 85, + 245, + 231, + 44, + 251, + 130, + 3, + 12, + 18, + 19, + 180, + 13, + 57, + 64, + 252, + 6, + 128, + 216, + 126, + 41, + 40, + 218, + 174, + 72, + 148, + 5, + 200, + 87, + 244, + 250, + 26, + 133, + 215, + 204, + 210, + 4, + 220, + 121, + 244, + 28, + 4, + 55, + 247, + 238, + 97, + 193, + 241, + 174, + 217, + 94, + 149, + 238, + 81, + 36, + 44, + 42, + 41, + 6, + 223, + 152, + 239, + 85, + 97, + 83, + 124, + 69, + 167, + 155, + 183, + 109, + 111, + 117, + 192, + 69, + 52, + 103, + 52, + 237, + 193, + 50, + 201, + 81, + 0, + 47, + 112, + 153, + 123, + 28, + 135, + 0, + 6, + 75, + 125, + 102, + 157, + 153, + 70, + 112, + 155, + 187, + 2, + 56, + 80, + 71, + 173, + 13, + 88, + 232, + 6, + 42, + 180, + 80, + 52, + 90, + 118, + 103, + 109, + 68, + 183, + 108, + 222, + 106, + 205, + 31, + 221, + 162, + 181, + 133, + 14, + 229, + 27, + 22, + 89, + 174, + 255, + 228, + 87, + 4, + 89, + 159, + 209, + 132, + 180, + 99, + 246, + 217, + 32, + 75, + 67, + 139, + 216, + 250, + 136, + 9, + 8, + 11, + 39, + 7, + 226, + 76, + 224, + 106, + 196, + 224, + 117, + 29, + 176, + 96, + 123, + 159, + 8, + 162, + 190, + 128, + 185, + 106, + 159, + 31, + 250, + 194, + 97, + 207, + 29, + 159, + 242, + 206, + 20, + 147, + 36, + 209, + 145, + 255, + 174, + 65, + 11, + 136, + 44, + 49, + 131, + 83, + 223, + 104, + 185, + 6, + 3, + 15, + 141, + 213, + 127, + 164, + 32, + 218, + 42, + 150, + 54, + 14, + 190, + 194, + 166, + 215, + 60, + 234, + 125, + 236, + 179, + 156, + 39, + 113, + 218, + 132, + 200, + 81, + 244, + 160, + 69, + 146, + 200, + 27, + 240, + 207, + 186, + 87, + 167, + 42, + 39, + 50, + 188, + 165, + 241, + 181, + 119, + 151, + 43, + 72, + 194, + 20, + 42, + 138, + 231, + 227, + 121, + 78, + 231, + 26, + 19, + 140, + 153, + 192, + 39, + 232, + 29, + 96, + 38, + 198, + 225, + 243, + 97, + 148, + 138, + 237, + 72, + 228, + 173, + 20, + 114, + 140, + 83, + 91, + 144, + 133, + 92, + 163, + 49, + 252, + 89, + 176, + 141, + 169, + 205, + 20, + 90, + 171, + 136, + 221, + 73, + 163, + 69, + 222, + 63, + 24, + 227, + 126, + 197, + 120, + 82, + 12, + 226, + 26, + 18, + 53, + 252, + 161, + 251, + 139, + 250, + 72, + 20, + 237, + 90, + 218, + 131, + 121, + 180, + 218, + 114, + 191, + 134, + 81, + 187, + 191, + 11, + 35, + 52, + 29, + 115, + 152, + 53, + 129, + 1, + 106, + 88, + 152, + 250, + 119, + 119, + 150, + 203, + 41, + 192, + 208, + 117, + 125, + 243, + 254, + 254, + 129, + 56, + 227, + 249, + 99, + 135, + 210, + 85, + 210, + 214, + 214, + 203, + 41, + 208, + 87, + 46, + 11, + 237, + 112, + 108, + 86, + 244, + 96, + 80, + 17, + 40, + 60, + 144, + 141, + 158, + 246, + 114, + 215, + 133, + 64, + 68, + 230, + 198, + 130, + 113, + 79, + 6, + 33, + 89, + 242, + 213, + 33, + 23, + 200, + 168, + 38, + 163, + 162, + 181, + 230, + 240, + 30, + 174, + 192, + 180, + 18, + 255, + 145, + 203, + 145, + 158, + 79, + 221, + 18, + 194, + 165, + 65, + 113, + 242, + 5, + 241, + 12, + 181, + 73, + 230, + 21, + 5, + 77, + 237, + 208, + 94, + 96, + 67, + 250, + 121, + 156, + 40, + 185, + 140, + 141, + 12, + 185, + 37, + 131, + 87, + 126, + 89, + 207, + 91, + 32, + 7, + 30, + 231, + 146, + 91, + 124, + 43, + 196, + 132, + 231, + 251, + 48, + 125, + 253, + 191, + 37, + 25, + 122, + 219, + 115, + 126, + 162, + 134, + 142, + 207, + 16, + 151, + 111, + 204, + 218, + 66, + 177, + 144, + 151, + 27, + 57, + 147, + 185, + 38, + 46, + 70, + 15, + 25, + 52, + 19, + 38, + 77, + 194, + 251, + 57, + 36, + 177, + 2, + 139, + 212, + 58, + 189, + 1, + 161, + 245, + 129, + 18, + 28, + 46, + 57, + 21, + 6, + 40, + 190, + 252, + 169, + 179, + 63, + 45, + 217, + 28, + 243, + 192, + 89, + 8, + 164, + 183, + 220, + 203, + 116, + 56, + 215, + 85, + 57, + 160, + 97, + 212, + 2, + 27, + 20, + 44, + 242, + 81, + 92, + 44, + 139, + 158, + 59, + 201, + 81, + 64, + 32, + 221, + 174, + 160, + 105, + 175, + 76, + 113, + 221, + 252, + 89, + 107, + 198, + 131, + 243, + 32, + 233, + 56, + 230, + 25, + 70, + 42, + 59, + 81, + 140, + 227, + 175, + 121, + 164, + 225, + 116, + 68, + 74, + 69, + 244, + 30, + 224, + 225, + 161, + 70, + 246, + 120, + 23, + 219, + 195, + 84, + 117, + 171, + 2, + 123, + 92, + 20, + 57, + 199, + 246, + 220, + 171, + 1, + 68, + 129, + 49, + 207, + 13, + 172, + 92, + 8, + 67, + 208, + 142, + 96, + 209, + 55, + 147, + 58, + 133, + 177, + 249, + 222, + 114, + 229, + 17, + 54, + 45, + 179, + 98, + 6, + 156, + 75, + 60, + 215, + 152, + 247, + 98, + 23, + 150, + 155, + 188, + 239, + 184, + 195, + 43, + 53, + 187, + 48, + 194, + 200, + 5, + 157, + 158, + 144, + 107, + 189, + 180, + 90, + 221, + 132, + 17, + 73, + 79, + 241, + 12, + 195, + 27, + 178, + 58, + 192, + 24, + 245, + 83, + 154, + 180, + 225, + 223, + 209, + 110, + 22, + 41, + 49, + 237, + 197, + 97, + 61, + 70, + 218, + 79, + 233, + 127, + 203, + 59, + 220, + 233, + 35, + 140, + 216, + 92, + 5, + 33, + 159, + 243, + 63, + 183, + 81, + 239, + 27, + 194, + 4, + 172, + 202, + 91, + 159, + 190, + 194, + 247, + 163, + 12, + 234, + 130, + 191, + 165, + 168, + 60, + 208, + 92, + 65, + 178, + 71, + 70, + 211, + 182, + 100, + 254, + 213, + 192, + 21, + 167, + 3, + 48, + 75, + 177, + 136, + 127, + 79, + 175, + 197, + 0, + 206, + 232, + 9, + 74, + 45, + 229, + 12, + 51, + 149, + 20, + 54, + 206, + 233, + 191, + 115, + 89, + 253, + 9, + 24, + 110, + 32, + 64, + 104, + 17, + 193, + 109, + 67, + 213, + 10, + 0, + 206, + 83, + 133, + 226, + 183, + 241, + 233, + 95, + 40, + 90, + 196, + 83, + 34, + 136, + 94, + 41, + 95, + 134, + 115, + 214, + 74, + 236, + 202, + 163, + 147, + 201, + 15, + 87, + 105, + 222, + 54, + 138, + 156, + 70, + 176, + 34, + 26, + 28, + 50, + 118, + 166, + 68, + 62, + 218, + 114, + 135, + 208, + 175, + 81, + 232, + 172, + 238, + 233, + 55, + 5, + 204, + 119, + 84, + 48, + 49, + 4, + 13, + 204, + 39, + 32, + 188, + 236, + 156, + 71, + 57, + 167, + 225, + 247, + 21, + 67, + 66, + 65, + 152, + 198, + 181, + 126, + 103, + 69, + 62, + 9, + 216, + 204, + 69, + 219, + 40, + 39, + 17, + 60, + 52, + 137, + 162, + 160, + 249, + 199, + 181, + 228, + 25, + 160, + 185, + 115, + 52, + 46, + 248, + 95, + 73, + 121, + 199, + 87, + 247, + 202, + 128, + 32, + 71, + 238, + 144, + 79, + 66, + 1, + 148, + 224, + 40, + 178, + 58, + 175, + 209, + 84, + 169, + 32, + 247, + 124, + 44, + 54, + 111, + 176, + 63, + 127, + 137, + 29, + 68, + 11, + 156, + 228, + 215, + 229, + 213, + 240, + 182, + 82, + 93, + 2, + 232, + 233, + 183, + 70, + 149, + 139, + 31, + 129, + 151, + 227, + 151, + 75, + 169, + 85, + 23, + 186, + 226, + 52, + 162, + 176, + 145, + 174, + 177, + 86, + 207, + 217, + 55, + 83, + 172, + 153, + 45, + 253, + 192, + 47, + 250, + 199, + 96, + 57, + 205, + 43, + 180, + 76, + 41, + 173, + 153, + 197, + 112, + 64, + 117, + 190, + 151, + 75, + 162, + 106, + 186, + 202, + 244, + 232, + 59, + 223, + 25, + 225, + 63, + 254, + 98, + 54, + 161, + 71, + 16, + 246, + 193, + 4, + 253, + 132, + 199, + 70, + 171, + 144, + 63, + 143, + 72, + 197, + 177, + 113, + 59, + 91, + 159, + 12, + 131, + 141, + 196, + 104, + 93, + 143, + 229, + 140, + 74, + 28, + 21, + 183, + 33, + 143, + 13, + 158, + 73, + 99, + 112, + 141, + 238, + 156, + 60, + 120, + 242, + 183, + 206, + 99, + 102, + 94, + 156, + 117, + 14, + 12, + 167, + 23, + 243, + 1, + 149, + 182, + 147, + 194, + 10, + 59, + 228, + 26, + 113, + 187, + 231, + 233, + 61, + 251, + 78, + 31, + 70, + 176, + 205, + 156, + 78, + 250, + 136, + 146, + 190, + 86, + 2, + 100, + 73, + 75, + 110, + 175, + 229, + 180, + 61, + 200, + 250, + 193, + 122, + 52, + 67, + 214, + 158, + 174, + 166, + 88, + 132, + 254, + 46, + 92, + 176, + 23, + 57, + 70, + 79, + 118, + 225, + 83, + 71, + 16, + 238, + 135, + 17, + 140, + 119, + 37, + 234, + 183, + 42, + 55, + 46, + 82, + 126, + 111, + 140, + 50, + 252, + 99, + 246, + 5, + 21, + 173, + 147, + 234, + 66, + 83, + 81, + 202, + 30, + 93, + 86, + 182, + 79, + 227, + 214, + 145, + 70, + 248, + 231, + 4, + 91, + 185, + 232, + 1, + 226, + 201, + 199, + 141, + 162, + 69, + 21, + 184, + 18, + 209, + 143, + 86, + 217, + 203, + 238, + 163, + 221, + 75, + 203, + 72, + 92, + 140, + 155, + 57, + 92, + 140, + 68, + 187, + 70, + 105, + 190, + 154, + 168, + 19, + 210, + 160, + 134, + 156, + 86, + 25, + 25, + 247, + 93, + 170, + 212, + 41, + 249, + 187, + 184, + 131, + 180, + 10, + 90, + 18, + 47, + 254, + 156, + 242, + 181, + 132, + 193, + 250, + 151, + 143, + 197, + 195, + 103, + 11, + 205, + 176, + 223, + 30, + 47, + 181, + 240, + 214, + 229, + 210, + 115, + 166, + 190, + 254, + 224, + 214, + 24, + 4, + 247, + 247, + 242, + 49, + 55, + 42, + 196, + 239, + 155, + 159, + 206, + 86, + 181, + 12, + 153, + 70, + 88, + 5, + 2, + 18, + 141, + 12, + 252, + 133, + 215, + 161, + 241, + 103, + 78, + 140, + 165, + 50, + 174, + 43, + 80, + 68, + 166, + 13, + 182, + 153, + 75, + 203, + 39, + 160, + 98, + 0, + 151, + 78, + 140, + 38, + 37, + 111, + 19, + 69, + 208, + 94, + 125, + 222, + 84, + 76, + 132, + 234, + 34, + 231, + 89, + 181, + 185, + 164, + 29, + 70, + 148, + 240, + 179, + 242, + 23, + 123, + 3, + 22, + 84, + 17, + 150, + 31, + 65, + 219, + 206, + 86, + 51, + 88, + 182, + 48, + 65, + 2, + 142, + 151, + 195, + 101, + 68, + 50, + 138, + 151, + 246, + 1, + 242, + 142, + 227, + 130, + 197, + 55, + 58, + 143, + 251, + 11, + 127, + 199, + 43, + 221, + 148, + 73, + 197, + 188, + 69, + 238, + 234, + 95, + 151, + 15, + 109, + 165, + 167, + 124, + 29, + 119, + 114, + 104, + 17, + 60, + 131, + 196, + 247, + 20, + 43, + 70, + 98, + 246, + 254, + 240, + 107, + 42, + 86, + 116, + 182, + 47, + 31, + 208, + 146, + 109, + 227, + 210, + 37, + 152, + 60, + 136, + 233, + 49, + 187, + 150, + 244, + 83, + 108, + 137, + 190, + 116, + 218, + 225, + 220, + 58, + 231, + 222, + 34, + 170, + 180, + 190, + 151, + 89, + 209, + 215, + 39, + 112, + 54, + 114, + 176, + 239, + 90, + 165, + 232, + 250, + 215, + 219, + 124, + 175, + 141, + 20, + 140, + 178, + 212, + 231, + 142, + 177, + 86, + 158, + 18, + 165, + 235, + 108, + 217, + 194, + 57, + 32, + 243, + 82, + 14, + 86, + 65, + 201, + 14, + 153, + 243, + 170, + 246, + 89, + 182, + 176, + 254, + 87, + 184, + 206, + 163, + 148, + 82, + 114, + 190, + 89, + 58, + 1, + 78, + 115, + 143, + 159, + 238, + 227, + 249, + 118, + 88, + 255, + 147, + 125, + 11, + 162, + 137, + 0, + 185, + 254, + 140, + 173, + 154, + 112, + 119, + 165, + 162, + 187, + 244, + 0, + 125, + 133, + 62, + 63, + 102, + 207, + 54, + 127, + 227, + 90, + 251, + 90, + 91, + 123, + 108, + 103, + 233, + 185, + 180, + 134, + 12, + 252, + 36, + 153, + 198, + 142, + 173, + 177, + 148, + 30, + 32, + 106, + 56, + 98, + 13, + 213, + 60, + 46, + 214, + 239, + 111, + 52, + 229, + 230, + 90, + 245, + 21, + 14, + 205, + 50, + 121, + 107, + 122, + 199, + 202, + 113, + 149, + 135, + 190, + 156, + 245, + 187, + 75, + 253, + 49, + 222, + 33, + 12, + 191, + 129, + 104, + 181, + 167, + 215, + 34, + 38, + 84, + 158, + 36, + 101, + 162, + 53, + 239, + 48, + 53, + 42, + 174, + 155, + 101, + 252, + 94, + 194, + 105, + 163, + 152, + 141, + 31, + 122, + 65, + 223, + 229, + 30, + 52, + 186, + 242, + 100, + 69, + 82, + 98, + 4, + 76, + 136, + 192, + 147, + 45, + 51, + 125, + 46, + 78, + 167, + 237, + 50, + 184, + 36, + 151, + 52, + 87, + 101, + 230, + 9, + 49, + 89, + 34, + 119, + 47, + 239, + 229, + 171, + 123, + 247, + 118, + 156, + 91, + 118, + 178, + 141, + 41, + 156, + 70, + 197, + 189, + 251, + 24, + 130, + 15, + 206, + 200, + 6, + 91, + 181, + 0, + 252, + 42, + 201, + 144, + 4, + 109, + 253, + 33, + 71, + 152, + 7, + 242, + 230, + 75, + 242, + 193, + 225, + 150, + 42, + 229, + 184, + 76, + 236, + 133, + 163, + 245, + 226, + 59, + 48, + 149, + 85, + 249, + 78, + 104, + 151, + 129, + 209, + 122, + 181, + 106, + 51, + 38, + 126, + 158, + 233, + 17, + 121, + 42, + 50, + 121, + 108, + 2, + 219, + 5, + 16, + 130, + 38, + 128, + 227, + 76, + 54, + 193, + 241, + 221, + 159, + 27, + 127, + 31, + 157, + 141, + 144, + 146, + 154, + 241, + 106, + 176, + 64, + 157, + 40, + 48, + 179, + 119, + 196, + 227, + 52, + 160, + 130, + 223, + 234, + 244, + 34, + 28, + 84, + 196, + 192, + 246, + 228, + 5, + 101, + 136, + 234, + 145, + 47, + 60, + 39, + 33, + 53, + 83, + 149, + 129, + 82, + 144, + 42, + 199, + 106, + 43, + 122, + 181, + 142, + 241, + 12, + 152, + 77, + 185, + 36, + 196, + 56, + 222, + 79, + 83, + 226, + 18, + 59, + 239, + 25, + 200, + 227, + 90, + 144, + 161, + 178, + 92, + 191, + 49, + 196, + 73, + 226, + 242, + 82, + 20, + 83, + 117, + 46, + 119, + 119, + 163, + 221, + 55, + 16, + 165, + 126, + 60, + 169, + 203, + 235, + 120, + 56, + 219, + 243, + 102, + 211, + 88, + 36, + 17, + 160, + 73, + 33, + 173, + 0, + 134, + 41, + 202, + 182, + 125, + 162, + 89, + 156, + 6, + 100, + 224, + 68, + 181, + 129, + 42, + 145, + 149, + 180, + 39, + 155, + 143, + 61, + 58, + 74, + 244, + 224, + 175, + 106, + 115, + 180, + 113, + 248, + 180, + 28, + 106, + 128, + 236, + 188, + 34, + 10, + 38, + 132, + 55, + 85, + 46, + 249, + 13, + 127, + 99, + 109, + 197, + 182, + 73, + 80, + 30, + 144, + 216, + 52, + 98, + 227, + 119, + 44, + 195, + 215, + 176, + 76, + 125, + 52, + 127, + 67, + 201, + 44, + 209, + 234, + 80, + 82, + 117, + 102, + 90, + 223, + 142, + 5, + 99, + 202, + 58, + 104, + 226, + 103, + 195, + 74, + 172, + 117, + 63, + 179, + 217, + 203, + 119, + 106, + 137, + 211, + 124, + 23, + 136, + 49, + 58, + 202, + 59, + 247, + 180, + 22, + 46, + 82, + 231, + 154, + 83, + 177, + 210, + 116, + 249, + 132, + 184, + 149, + 222, + 92, + 86, + 95, + 212, + 92, + 223, + 241, + 142, + 252, + 177, + 25, + 202, + 181, + 90, + 214, + 64, + 39, + 225, + 184, + 39, + 194, + 115, + 128, + 130, + 160, + 115, + 10, + 86, + 90, + 190, + 107, + 93, + 71, + 88, + 124, + 173, + 129, + 224, + 79, + 62, + 40, + 33, + 62, + 151, + 167, + 56, + 228, + 57, + 111, + 167, + 151, + 50, + 12, + 120, + 200, + 75, + 179, + 226, + 156, + 0, + 105, + 242, + 164, + 82, + 147, + 49, + 89, + 191, + 165, + 171, + 200, + 93, + 112, + 130, + 88, + 254, + 99, + 149, + 37, + 68, + 107, + 146, + 98, + 90, + 96, + 190, + 185, + 239, + 60, + 112, + 236, + 141, + 231, + 18, + 44, + 199, + 137, + 170, + 194, + 113, + 198, + 215, + 104, + 100, + 231, + 136, + 53, + 214, + 181, + 206, + 91, + 101, + 231, + 159, + 140, + 32, + 214, + 208, + 117, + 190, + 25, + 47, + 153, + 162, + 196, + 242, + 194, + 82, + 243, + 67, + 253, + 26, + 241, + 58, + 99, + 231, + 166, + 138, + 99, + 14, + 184, + 63, + 180, + 107, + 23, + 39, + 158, + 53, + 142, + 92, + 177, + 148, + 187, + 118, + 187, + 194, + 34, + 156, + 243, + 35, + 106, + 46, + 41, + 31, + 39, + 66, + 120, + 199, + 139, + 38, + 97, + 67, + 105, + 208, + 231, + 86, + 142, + 246, + 79, + 77, + 101, + 179, + 60, + 84, + 51, + 246, + 191, + 41, + 214, + 130, + 62, + 60, + 204, + 142, + 192, + 110, + 28, + 171, + 250, + 177, + 214, + 168, + 231, + 221, + 14, + 182, + 21, + 57, + 245, + 202, + 168, + 32, + 47, + 238, + 104, + 107, + 228, + 101, + 189, + 194, + 108, + 188, + 131, + 4, + 170, + 115, + 145, + 27, + 133, + 213, + 58, + 70, + 155, + 235, + 120, + 16, + 39, + 166, + 129, + 223, + 116, + 130, + 82, + 107, + 61, + 54, + 141, + 111, + 135, + 167, + 52, + 197, + 25, + 44, + 40, + 237, + 140, + 81, + 69, + 5, + 136, + 94, + 250, + 67, + 82, + 119, + 137, + 143, + 91, + 23, + 105, + 91, + 2, + 38, + 105, + 114, + 214, + 29, + 90, + 181, + 222, + 186, + 32, + 215, + 89, + 67, + 47, + 115, + 39, + 152, + 195, + 91, + 216, + 70, + 55, + 39, + 205, + 45, + 255, + 32, + 137, + 169, + 204, + 87, + 170, + 230, + 248, + 67, + 178, + 52, + 22, + 203, + 253, + 255, + 17, + 11, + 75, + 127, + 189, + 80, + 154, + 159, + 22, + 116, + 243, + 134, + 226, + 133, + 156, + 25, + 9, + 75, + 235, + 180, + 176, + 84, + 230, + 32, + 164, + 27, + 34, + 23, + 191, + 80, + 98, + 245, + 162, + 28, + 187, + 235, + 7, + 189, + 169, + 34, + 129, + 227, + 115, + 112, + 207, + 200, + 231, + 168, + 136, + 10, + 3, + 161, + 96, + 73, + 5, + 96, + 180, + 92, + 148, + 21, + 161, + 141, + 6, + 11, + 202, + 207, + 69, + 90, + 28, + 115, + 164, + 78, + 223, + 219, + 140, + 126, + 59, + 119, + 221, + 248, + 121, + 27, + 248, + 251, + 89, + 72, + 103, + 82, + 211, + 106, + 110, + 234, + 63, + 253, + 101, + 225, + 101, + 59, + 40, + 83, + 231, + 23, + 183, + 54, + 57, + 164, + 5, + 92, + 122, + 194, + 166, + 201, + 51, + 125, + 199, + 90, + 98, + 42, + 244, + 181, + 211, + 45, + 38, + 152, + 37, + 176, + 90, + 192, + 178, + 97, + 115, + 30, + 66, + 13, + 19, + 187, + 162, + 73, + 88, + 177, + 207, + 225, + 110, + 226, + 82, + 11, + 44, + 119, + 121, + 30, + 78, + 213, + 167, + 18, + 139, + 229, + 243, + 60, + 93, + 243, + 182, + 144, + 123, + 55, + 166, + 117, + 114, + 213, + 39, + 180, + 107, + 83, + 255, + 239, + 205, + 86, + 193, + 42, + 155, + 69, + 48, + 255, + 250, + 244, + 152, + 36, + 251, + 33, + 158, + 124, + 224, + 78, + 5, + 207, + 94, + 154, + 9, + 217, + 61, + 14, + 83, + 31, + 44, + 237, + 20, + 63, + 237, + 6, + 192, + 115, + 178, + 49, + 95, + 29, + 41, + 90, + 193, + 32, + 43, + 85, + 42, + 77, + 217, + 153, + 28, + 8, + 35, + 208, + 24, + 135, + 171, + 165, + 233, + 154, + 201, + 26, + 1, + 240, + 30, + 45, + 172, + 140, + 220, + 100, + 54, + 191, + 152, + 157, + 227, + 26, + 66, + 215, + 75, + 149, + 5, + 203, + 117, + 32, + 80, + 127, + 62, + 51, + 157, + 222, + 250, + 21, + 73, + 112, + 89, + 218, + 75, + 153, + 60, + 245, + 146, + 70, + 205, + 11, + 101, + 183, + 101, + 5, + 105, + 229, + 218, + 149, + 169, + 233, + 47, + 141, + 117, + 94, + 171, + 39, + 205, + 83, + 25, + 133, + 172, + 1, + 237, + 40, + 220, + 46, + 156, + 24, + 119, + 158, + 128, + 69, + 154, + 112, + 247, + 4, + 136, + 87, + 155, + 173, + 125, + 12, + 102, + 14, + 175, + 174, + 199, + 16, + 166, + 110, + 99, + 111, + 140, + 74, + 129, + 17, + 142, + 117, + 80, + 117, + 135, + 156, + 213, + 35, + 172, + 103, + 115, + 18, + 148, + 244, + 26, + 5, + 195, + 169, + 136, + 101, + 198, + 31, + 111, + 144, + 2, + 110, + 132, + 62, + 138, + 60, + 4, + 116, + 234, + 85, + 180, + 41, + 66, + 99, + 73, + 204, + 83, + 134, + 249, + 63, + 244, + 53, + 236, + 23, + 54, + 246, + 118, + 85, + 14, + 79, + 234, + 80, + 208, + 167, + 154, + 87, + 245, + 50, + 3, + 202, + 66, + 73, + 204, + 165, + 105, + 122, + 56, + 91, + 19, + 218, + 214, + 32, + 22, + 170, + 200, + 152, + 167, + 61, + 106, + 17, + 18, + 132, + 3, + 155, + 57, + 19, + 95, + 253, + 40, + 236, + 129, + 120, + 212, + 154, + 152, + 156, + 211, + 158, + 226, + 234, + 7, + 37, + 8, + 113, + 144, + 79, + 170, + 236, + 26, + 76, + 121, + 3, + 77, + 129, + 12, + 204, + 224, + 202, + 133, + 42, + 151, + 254, + 155, + 155, + 99, + 140, + 101, + 162, + 103, + 70, + 29, + 116, + 35, + 220, + 163, + 98, + 7, + 112, + 230, + 80, + 95, + 99, + 75, + 133, + 76, + 55, + 98, + 54, + 49, + 76, + 46, + 176, + 193, + 255, + 119, + 35, + 183, + 48, + 16, + 236, + 55, + 18, + 144, + 201, + 82, + 228, + 77, + 7, + 222, + 119, + 191, + 187, + 88, + 40, + 237, + 230, + 201, + 101, + 13, + 171, + 143, + 97, + 209, + 137, + 41, + 52, + 28, + 50, + 167, + 220, + 173, + 122, + 34, + 222, + 253, + 123, + 151, + 252, + 132, + 103, + 132, + 85, + 166, + 8, + 155, + 191, + 184, + 3, + 74, + 222, + 57, + 104, + 204, + 40, + 245, + 179, + 33, + 70, + 118, + 240, + 130, + 108, + 110, + 94, + 60, + 134, + 206, + 88, + 128, + 112, + 68, + 40, + 4, + 200, + 182, + 119, + 129, + 100, + 182, + 152, + 20, + 236, + 191, + 72, + 109, + 42, + 55, + 255, + 42, + 100, + 173, + 9, + 223, + 116, + 153, + 133, + 48, + 217, + 33, + 255, + 139, + 219, + 164, + 23, + 4, + 234, + 194, + 225, + 147, + 206, + 29, + 36, + 14, + 207, + 240, + 165, + 210, + 116, + 87, + 194, + 18, + 133, + 23, + 207, + 201, + 175, + 236, + 100, + 183, + 45, + 168, + 181, + 212, + 129, + 72, + 103, + 204, + 120, + 99, + 93, + 137, + 6, + 92, + 109, + 26, + 74, + 130, + 242, + 230, + 45, + 0, + 98, + 209, + 73, + 118, + 220, + 142, + 184, + 103, + 68, + 169, + 197, + 244, + 40, + 239, + 223, + 103, + 108, + 75, + 214, + 207, + 22, + 54, + 62, + 218, + 123, + 208, + 96, + 47, + 182, + 226, + 253, + 120, + 243, + 144, + 99, + 157, + 233, + 209, + 251, + 119, + 252, + 109, + 109, + 39, + 239, + 92, + 222, + 197, + 110, + 186, + 238, + 155, + 87, + 99, + 14, + 78, + 201, + 30, + 199, + 248, + 199, + 7, + 192, + 155, + 115, + 124, + 240, + 145, + 230, + 51, + 239, + 239, + 181, + 141, + 246, + 82, + 47, + 241, + 82, + 206, + 30, + 237, + 84, + 91, + 214, + 175, + 99, + 220, + 51, + 140, + 119, + 48, + 31, + 171, + 79, + 121, + 57, + 205, + 130, + 237, + 221, + 129, + 124, + 108, + 212, + 27, + 100, + 147, + 253, + 174, + 198, + 95, + 0, + 114, + 170, + 148, + 16, + 8, + 212, + 198, + 6, + 1, + 254, + 77, + 189, + 193, + 179, + 141, + 211, + 43, + 83, + 223, + 235, + 11, + 31, + 123, + 9, + 231, + 183, + 122, + 205, + 182, + 90, + 166, + 26, + 253, + 56, + 124, + 138, + 185, + 89, + 155, + 61, + 103, + 212, + 36, + 57, + 54, + 54, + 189, + 249, + 145, + 136, + 240, + 142, + 114, + 23, + 73, + 66, + 233, + 18, + 75, + 111, + 210, + 119, + 206, + 75, + 48, + 30, + 63, + 162, + 146, + 171, + 87, + 139, + 190, + 134, + 34, + 115, + 25, + 245, + 247, + 74, + 125, + 3, + 56, + 111, + 240, + 115, + 242, + 250, + 41, + 54, + 95, + 135, + 216, + 79, + 195, + 54, + 239, + 199, + 239, + 195, + 133, + 12, + 53, + 105, + 132, + 19, + 163, + 52, + 25, + 103, + 121, + 78, + 26, + 83, + 164, + 29, + 58, + 14, + 29, + 111, + 129, + 203, + 172, + 52, + 172, + 74, + 215, + 106, + 40, + 139, + 107, + 14, + 198, + 140, + 117, + 23, + 60, + 193, + 147, + 102, + 55, + 48, + 42, + 72, + 176, + 165, + 29, + 166, + 87, + 116, + 217, + 202, + 0, + 183, + 79, + 82, + 130, + 211, + 238, + 83, + 247, + 3, + 183, + 191, + 19, + 34, + 167, + 148, + 103, + 149, + 186, + 163, + 149, + 237, + 62, + 239, + 155, + 209, + 118, + 149, + 126, + 6, + 80, + 252, + 189, + 185, + 143, + 207, + 184, + 14, + 228, + 3, + 197, + 140, + 60, + 221, + 32, + 31, + 8, + 225, + 133, + 189, + 108, + 92, + 101, + 251, + 130, + 24, + 210, + 88, + 4, + 14, + 13, + 222, + 248, + 163, + 179, + 243, + 170, + 143, + 57, + 145, + 174, + 35, + 56, + 234, + 209, + 251, + 112, + 23, + 159, + 116, + 236, + 125, + 105, + 228, + 61, + 150, + 161, + 8, + 221, + 106, + 119, + 173, + 66, + 241, + 182, + 9, + 115, + 244, + 81, + 120, + 109, + 174, + 23, + 37, + 65, + 207, + 137, + 28, + 41, + 81, + 230, + 149, + 94, + 14, + 164, + 46, + 223, + 213, + 87, + 47, + 115, + 162, + 21, + 249, + 249, + 253, + 3, + 169, + 240, + 83, + 181, + 231, + 48, + 239, + 235, + 17, + 188, + 147, + 136, + 234, + 89, + 86, + 165, + 18, + 101, + 27, + 30, + 40, + 75, + 202, + 39, + 78, + 78, + 239, + 15, + 101, + 99, + 190, + 183, + 132, + 61, + 72, + 253, + 47, + 23, + 230, + 42, + 50, + 15, + 183, + 194, + 19, + 64, + 155, + 137, + 90, + 241, + 55, + 123, + 207, + 223, + 130, + 128, + 68, + 235, + 11, + 96, + 104, + 14, + 99, + 82, + 85, + 17, + 244, + 106, + 178, + 212, + 39, + 39, + 0, + 12, + 98, + 182, + 235, + 162, + 78, + 142, + 116, + 225, + 238, + 242, + 172, + 235, + 50, + 54, + 104, + 226, + 194, + 76, + 202, + 201, + 73, + 202, + 136, + 248, + 235, + 49, + 235, + 118, + 190, + 119, + 78, + 195, + 170, + 132, + 143, + 249, + 77, + 103, + 53, + 214, + 40, + 129, + 35, + 108, + 85, + 223, + 204, + 249, + 227, + 240, + 163, + 125, + 95, + 134, + 4, + 61, + 29, + 35, + 153, + 61, + 144, + 57, + 0, + 224, + 23, + 208, + 203, + 115, + 9, + 145, + 176, + 221, + 12, + 10, + 161, + 53, + 164, + 230, + 173, + 94, + 186, + 254, + 222, + 227, + 65, + 173, + 116, + 108, + 176, + 46, + 44, + 223, + 184, + 197, + 27, + 180, + 62, + 134, + 202, + 71, + 183, + 254, + 92, + 199, + 103, + 154, + 244, + 150, + 222, + 234, + 54, + 133, + 51, + 45, + 73, + 206, + 101, + 7, + 142, + 119, + 199, + 88, + 126, + 100, + 128, + 18, + 57, + 156, + 104, + 28, + 209, + 149, + 59, + 197, + 127, + 70, + 117, + 249, + 90, + 149, + 107, + 204, + 64, + 152, + 167, + 57, + 178, + 90, + 170, + 33, + 193, + 32, + 233, + 6, + 243, + 67, + 228, + 239, + 36, + 153, + 150, + 217, + 70, + 185, + 33, + 36, + 206, + 78, + 198, + 106, + 19, + 119, + 73, + 177, + 34, + 70, + 60, + 117, + 62, + 240, + 114, + 32, + 245, + 245, + 253, + 1, + 180, + 38, + 229, + 52, + 29, + 153, + 155, + 232, + 123, + 222, + 41, + 51, + 40, + 143, + 79, + 242, + 177, + 5, + 134, + 223, + 11, + 25, + 223, + 225, + 108, + 131, + 174, + 210, + 67, + 24, + 9, + 140, + 192, + 103, + 10, + 59, + 90, + 251, + 183, + 74, + 194, + 60, + 120, + 254, + 40, + 49, + 157, + 244, + 190, + 227, + 86, + 156, + 187, + 197, + 235, + 87, + 53, + 247, + 210, + 237, + 160, + 133, + 235, + 230, + 221, + 167, + 199, + 27, + 50, + 188, + 157, + 249, + 248, + 217, + 44, + 122, + 213, + 11, + 235, + 86, + 215, + 113, + 8, + 159, + 191, + 30, + 104, + 22, + 17, + 11, + 17, + 60, + 51, + 166, + 192, + 60, + 34, + 99, + 15, + 208, + 91, + 82, + 191, + 37, + 61, + 154, + 58, + 117, + 100, + 18, + 215, + 24, + 121, + 105, + 60, + 51, + 151, + 224, + 4, + 44, + 183, + 105, + 92, + 111, + 170, + 224, + 69, + 214, + 117, + 117, + 36, + 245, + 68, + 69, + 53, + 249, + 151, + 83, + 76, + 15, + 26, + 116, + 177, + 139, + 215, + 164, + 36, + 127, + 27, + 66, + 213, + 47, + 1, + 109, + 213, + 127, + 216, + 180, + 20, + 139, + 229, + 161, + 62, + 195, + 59, + 128, + 254, + 246, + 138, + 26, + 222, + 251, + 55, + 229, + 19, + 180, + 87, + 251, + 203, + 68, + 96, + 98, + 185, + 111, + 52, + 86, + 232, + 190, + 22, + 212, + 151, + 36, + 207, + 168, + 108, + 237, + 85, + 53, + 159, + 226, + 220, + 104, + 175, + 90, + 217, + 252, + 245, + 209, + 195, + 243, + 198, + 187, + 36, + 110, + 250, + 62, + 122, + 198, + 252, + 73, + 237, + 243, + 157, + 249, + 17, + 127, + 117, + 75, + 55, + 240, + 150, + 139, + 65, + 141, + 21, + 248, + 181, + 206, + 67, + 40, + 53, + 181, + 71, + 154, + 157, + 45, + 200, + 34, + 31, + 159, + 59, + 48, + 161, + 97, + 97, + 219, + 66, + 56, + 48, + 30, + 115, + 202, + 125, + 83, + 27, + 135, + 74, + 187, + 170, + 214, + 6, + 50, + 78, + 183, + 249, + 203, + 203, + 221, + 176, + 83, + 202, + 142, + 229, + 25, + 114, + 94, + 71, + 171, + 62, + 77, + 178, + 218, + 101, + 183, + 176, + 52, + 214, + 97, + 123, + 77, + 35, + 44, + 138, + 249, + 72, + 95, + 129, + 35, + 215, + 10, + 73, + 4, + 60, + 206, + 91, + 250, + 122, + 162, + 76, + 29, + 151, + 190, + 49, + 59, + 50, + 139, + 28, + 118, + 205, + 179, + 205, + 152, + 54, + 97, + 48, + 137, + 87, + 243, + 201, + 67, + 6, + 25, + 1, + 147, + 27, + 26, + 137, + 18, + 92, + 184, + 72, + 75, + 70, + 25, + 171, + 90, + 9, + 141, + 41, + 145, + 187, + 12, + 78, + 111, + 217, + 243, + 156, + 48, + 229, + 23, + 71, + 78, + 218, + 100, + 106, + 68, + 87, + 93, + 209, + 198, + 66, + 155, + 215, + 114, + 28, + 133, + 124, + 114, + 39, + 38, + 64, + 239, + 44, + 132, + 100, + 224, + 15, + 123, + 46, + 227, + 43, + 29, + 246, + 87, + 31, + 133, + 93, + 93, + 141, + 17, + 98, + 170, + 218, + 83, + 145, + 201, + 32, + 174, + 234, + 71, + 33, + 37, + 175, + 26, + 115, + 211, + 144, + 43, + 95, + 55, + 57, + 237, + 211, + 31, + 225, + 152, + 118, + 205, + 29, + 241, + 27, + 45, + 21, + 119, + 41, + 255, + 32, + 244, + 137, + 170, + 251, + 21, + 33, + 20, + 2, + 19, + 95, + 227, + 139, + 103, + 113, + 126, + 82, + 146, + 4, + 38, + 145, + 21, + 153, + 203, + 211, + 163, + 130, + 227, + 70, + 97, + 174, + 148, + 216, + 150, + 245, + 56, + 76, + 38, + 0, + 210, + 67, + 53, + 26, + 231, + 128, + 204, + 47, + 243, + 209, + 154, + 79, + 239, + 123, + 183, + 60, + 184, + 228, + 59, + 85, + 197, + 62, + 76, + 15, + 137, + 70, + 1, + 248, + 236, + 2, + 148, + 74, + 97, + 122, + 217, + 116, + 19, + 171, + 197, + 119, + 206, + 58, + 106, + 157, + 231, + 47, + 84, + 23, + 89, + 146, + 101, + 32, + 201, + 218, + 52, + 250, + 26, + 209, + 110, + 209, + 193, + 113, + 77, + 100, + 122, + 151, + 43, + 151, + 221, + 33, + 70, + 186, + 254, + 81, + 117, + 124, + 101, + 121, + 48, + 157, + 45, + 94, + 52, + 34, + 228, + 221, + 218, + 197, + 220, + 233, + 110, + 19, + 183, + 181, + 222, + 105, + 108, + 248, + 122, + 108, + 131, + 76, + 85, + 32, + 91, + 145, + 127, + 54, + 29, + 133, + 253, + 195, + 17, + 109, + 219, + 58, + 169, + 101, + 0, + 229, + 64, + 115, + 59, + 207, + 231, + 149, + 52, + 97, + 83, + 110, + 179, + 83, + 120, + 89, + 89, + 124, + 56, + 211, + 101, + 120, + 67, + 165, + 134, + 201, + 217, + 18, + 212, + 171, + 10, + 190, + 167, + 65, + 207, + 132, + 195, + 87, + 149, + 134, + 58, + 111, + 61, + 126, + 44, + 242, + 235, + 62, + 211, + 51, + 22, + 98, + 31, + 169, + 13, + 27, + 83, + 188, + 53, + 37, + 101, + 230, + 18, + 10, + 59, + 142, + 12, + 137, + 92, + 184, + 251, + 233, + 205, + 15, + 199, + 123, + 98, + 226, + 106, + 119, + 185, + 176, + 100, + 167, + 145, + 221, + 211, + 21, + 19, + 37, + 184, + 249, + 75, + 103, + 54, + 73, + 190, + 52, + 4, + 114, + 119, + 214, + 132, + 127, + 157, + 23, + 89, + 243, + 179, + 30, + 66, + 187, + 136, + 225, + 111, + 200, + 138, + 135, + 61, + 171, + 142, + 117, + 187, + 116, + 14, + 125, + 96, + 73, + 176, + 67, + 184, + 188, + 206, + 22, + 98, + 72, + 122, + 56, + 245, + 113, + 71, + 68, + 11, + 142, + 67, + 199, + 108, + 250, + 46, + 117, + 21, + 243, + 118, + 86, + 21, + 167, + 201, + 29, + 156, + 159, + 56, + 1, + 90, + 229, + 0, + 155, + 84, + 215, + 123, + 61, + 244, + 89, + 63, + 102, + 184, + 63, + 188, + 209, + 120, + 207, + 226, + 104, + 88, + 74, + 136, + 39, + 10, + 134, + 126, + 148, + 102, + 53, + 252, + 122, + 19, + 234, + 6, + 85, + 254, + 93, + 219, + 111, + 169, + 46, + 197, + 197, + 14, + 169, + 155, + 42, + 49, + 124, + 88, + 141, + 16, + 225, + 74, + 218, + 91, + 132, + 141, + 73, + 15, + 53, + 0, + 22, + 205, + 209, + 167, + 234, + 146, + 194, + 48, + 56, + 3, + 130, + 232, + 3, + 198, + 96, + 191, + 213, + 188, + 49, + 200, + 11, + 103, + 229, + 138, + 5, + 30, + 153, + 62, + 186, + 36, + 108, + 79, + 167, + 192, + 67, + 136, + 247, + 23, + 102, + 95, + 69, + 158, + 203, + 190, + 148, + 21, + 66, + 93, + 248, + 119, + 212, + 152, + 81, + 84, + 189, + 216, + 144, + 28, + 167, + 165, + 86, + 50, + 207, + 184, + 40, + 251, + 211, + 202, + 7, + 219, + 177, + 210, + 44, + 20, + 131, + 186, + 254, + 202, + 51, + 1, + 13, + 70, + 178, + 184, + 201, + 82, + 53, + 213, + 4, + 141, + 175, + 52, + 1, + 133, + 135, + 25, + 107, + 3, + 105, + 118, + 75, + 135, + 45, + 224, + 18, + 71, + 105, + 193, + 167, + 168, + 197, + 125, + 155, + 68, + 2, + 176, + 100, + 47, + 107, + 2, + 237, + 85, + 209, + 198, + 103, + 220, + 145, + 158, + 52, + 215, + 183, + 195, + 14, + 106, + 143, + 36, + 98, + 239, + 77, + 61, + 252, + 103, + 156, + 106, + 171, + 23, + 33, + 134, + 166, + 205, + 163, + 241, + 38, + 157, + 88, + 137, + 220, + 74, + 21, + 96, + 215, + 33, + 189, + 88, + 162, + 116, + 213, + 126, + 7, + 118, + 187, + 205, + 147, + 53, + 139, + 134, + 252, + 176, + 131, + 206, + 164, + 63, + 146, + 21, + 144, + 252, + 7, + 160, + 73, + 248, + 37, + 51, + 127, + 58, + 196, + 127, + 188, + 130, + 54, + 185, + 57, + 214, + 147, + 44, + 203, + 209, + 105, + 227, + 190, + 233, + 127, + 86, + 152, + 216, + 39, + 164, + 5, + 132, + 30, + 226, + 210, + 169, + 146, + 28, + 43, + 114, + 135, + 138, + 60, + 183, + 147, + 164, + 58, + 102, + 232, + 56, + 13, + 67, + 216, + 140, + 172, + 80, + 240, + 214, + 134, + 145, + 247, + 228, + 5, + 140, + 78, + 232, + 245, + 124, + 174, + 155, + 92, + 171, + 156, + 148, + 1, + 236, + 182, + 245, + 105, + 68, + 8, + 92, + 86, + 45, + 214, + 25, + 44, + 91, + 177, + 222, + 84, + 178, + 233, + 147, + 135, + 105, + 172, + 21, + 81, + 217, + 94, + 245, + 54, + 48, + 200, + 45, + 65, + 110, + 144, + 49, + 19, + 8, + 61, + 32, + 120, + 32, + 90, + 85, + 189, + 10, + 37, + 198, + 173, + 94, + 203, + 57, + 127, + 4, + 44, + 229, + 87, + 86, + 101, + 15, + 23, + 21, + 2, + 124, + 144, + 219, + 49, + 189, + 66, + 239, + 52, + 70, + 110, + 62, + 43, + 119, + 230, + 172, + 20, + 190, + 160, + 249, + 140, + 173, + 10, + 211, + 120, + 17, + 1, + 241, + 2, + 132, + 70, + 112, + 242, + 137, + 228, + 90, + 204, + 75, + 79, + 51, + 184, + 114, + 86, + 146, + 64, + 189, + 24, + 175, + 184, + 88, + 63, + 57, + 206, + 46, + 82, + 59, + 135, + 96, + 34, + 9, + 226, + 250, + 116, + 31, + 196, + 93, + 43, + 85, + 22, + 133, + 87, + 74, + 217, + 48, + 39, + 169, + 137, + 219, + 236, + 93, + 12, + 100, + 19, + 12, + 92, + 95, + 88, + 179, + 246, + 2, + 71, + 109, + 146, + 69, + 21, + 189, + 242, + 151, + 194, + 203, + 206, + 164, + 45, + 68, + 34, + 236, + 11, + 202, + 214, + 242, + 107, + 22, + 23, + 179, + 31, + 194, + 124, + 229, + 233, + 254, + 162, + 163, + 143, + 155, + 106, + 35, + 54, + 158, + 19, + 10, + 115, + 222, + 126, + 200, + 21, + 232, + 126, + 23, + 89, + 117, + 98, + 132, + 233, + 130, + 99, + 50, + 127, + 222, + 199, + 139, + 145, + 250, + 129, + 197, + 159, + 78, + 68, + 40, + 26, + 240, + 117, + 104, + 217, + 7, + 11, + 40, + 90, + 187, + 211, + 81, + 91, + 64, + 76, + 170, + 21, + 248, + 172, + 210, + 96, + 137, + 6, + 227, + 116, + 235, + 118, + 86, + 187, + 173, + 89, + 132, + 82, + 80, + 211, + 217, + 121, + 191, + 88, + 196, + 58, + 23, + 212, + 117, + 47, + 96, + 8, + 175, + 21, + 60, + 217, + 38, + 39, + 29, + 58, + 48, + 199, + 166, + 119, + 21, + 156, + 206, + 193, + 143, + 181, + 142, + 48, + 78, + 26, + 84, + 242, + 31, + 76, + 83, + 254, + 132, + 150, + 88, + 236, + 35, + 138, + 245, + 128, + 255, + 248, + 77, + 131, + 105, + 149, + 65, + 19, + 66, + 176, + 204, + 121, + 197, + 107, + 91, + 67, + 226, + 141, + 213, + 102, + 177, + 35, + 165, + 105, + 52, + 72, + 47, + 255, + 220, + 59, + 101, + 178, + 21, + 205, + 101, + 224, + 130, + 70, + 28, + 111, + 135, + 119, + 108, + 65, + 100, + 176, + 30, + 209, + 185, + 153, + 85, + 43, + 77, + 1, + 207, + 92, + 13, + 180, + 150, + 114, + 137, + 81, + 216, + 49, + 86, + 73, + 101, + 254, + 123, + 85, + 190, + 58, + 130, + 54, + 2, + 150, + 219, + 216, + 43, + 54, + 150, + 239, + 252, + 212, + 145, + 110, + 217, + 68, + 65, + 69, + 250, + 156, + 162, + 80, + 225, + 170, + 53, + 152, + 187, + 40, + 254, + 61, + 149, + 231, + 128, + 129, + 140, + 118, + 54, + 88, + 228, + 2, + 209, + 54, + 211, + 166, + 73, + 88, + 112, + 3, + 90, + 168, + 47, + 213, + 65, + 93, + 87, + 220, + 73, + 62, + 153, + 47, + 40, + 245, + 244, + 183, + 163, + 170, + 131, + 93, + 195, + 215, + 44, + 219, + 198, + 42, + 240, + 33, + 216, + 21, + 17, + 111, + 143, + 59, + 184, + 69, + 48, + 34, + 64, + 172, + 0, + 149, + 166, + 57, + 46, + 199, + 200, + 107, + 243, + 31, + 19, + 182, + 115, + 145, + 199, + 114, + 215, + 224, + 22, + 22, + 163, + 5, + 122, + 201, + 45, + 11, + 159, + 140, + 246, + 79, + 207, + 17, + 104, + 101, + 243, + 211, + 70, + 142, + 120, + 175, + 203, + 156, + 151, + 21, + 125, + 214, + 51, + 203, + 105, + 106, + 183, + 114, + 250, + 58, + 83, + 162, + 4, + 75, + 7, + 228, + 132, + 164, + 125, + 28, + 13, + 224, + 94, + 107, + 41, + 183, + 125, + 105, + 71, + 235, + 149, + 155, + 54, + 173, + 44, + 135, + 137, + 188, + 76, + 177, + 51, + 76, + 108, + 17, + 121, + 189, + 190, + 191, + 99, + 38, + 207, + 90, + 46, + 137, + 104, + 45, + 89, + 32, + 42, + 49, + 71, + 110, + 55, + 20, + 173, + 82, + 79, + 200, + 69, + 203, + 11, + 109, + 253, + 41, + 10, + 37, + 203, + 99, + 108, + 68, + 158, + 223, + 165, + 166, + 183, + 56, + 128, + 32, + 149, + 110, + 12, + 237, + 137, + 131, + 73, + 147, + 135, + 233, + 34, + 187, + 224, + 19, + 169, + 209, + 200, + 4, + 127, + 124, + 170, + 163, + 204, + 252, + 140, + 26, + 47, + 157, + 181, + 187, + 136, + 172, + 188, + 117, + 76, + 29, + 210, + 174, + 117, + 49, + 49, + 30, + 92, + 198, + 217, + 248, + 194, + 185, + 171, + 10, + 242, + 151, + 239, + 209, + 107, + 126, + 102, + 83, + 1, + 59, + 92, + 210, + 191, + 198, + 42, + 127, + 188, + 26, + 37, + 22, + 146, + 146, + 255, + 53, + 127, + 236, + 156, + 76, + 176, + 83, + 17, + 69, + 34, + 23, + 141, + 59, + 51, + 219, + 120, + 156, + 197, + 139, + 142, + 213, + 243, + 177, + 153, + 60, + 93, + 170, + 16, + 223, + 211, + 212, + 136, + 9, + 113, + 135, + 216, + 206, + 189, + 130, + 211, + 113, + 49, + 1, + 4, + 107, + 19, + 167, + 77, + 112, + 211, + 225, + 171, + 13, + 23, + 82, + 210, + 111, + 45, + 40, + 121, + 211, + 112, + 186, + 67, + 84, + 53, + 64, + 198, + 76, + 233, + 69, + 140, + 89, + 214, + 194, + 159, + 89, + 121, + 33, + 54, + 243, + 231, + 112, + 104, + 131, + 227, + 84, + 20, + 11, + 187, + 89, + 58, + 37, + 99, + 80, + 239, + 209, + 149, + 190, + 44, + 54, + 254, + 31, + 38, + 10, + 111, + 122, + 7, + 184, + 237, + 200, + 30, + 32, + 178, + 189, + 75, + 96, + 100, + 45, + 17, + 255, + 236, + 81, + 234, + 139, + 214, + 100, + 22, + 123, + 68, + 144, + 217, + 120, + 212, + 184, + 49, + 106, + 211, + 47, + 12, + 194, + 46, + 30, + 42, + 84, + 137, + 137, + 86, + 148, + 150, + 132, + 119, + 242, + 221, + 187, + 78, + 126, + 89, + 59, + 149, + 209, + 56, + 164, + 205, + 101, + 214, + 207, + 23, + 27, + 60, + 153, + 212, + 10, + 177, + 108, + 154, + 194, + 17, + 36, + 77, + 110, + 127, + 167, + 220, + 216, + 136, + 201, + 66, + 139, + 65, + 120, + 125, + 41, + 77, + 162, + 74, + 196, + 153, + 38, + 146, + 13, + 74, + 69, + 90, + 80, + 111, + 102, + 3, + 241, + 42, + 48, + 120, + 47, + 55, + 88, + 210, + 53, + 119, + 156, + 242, + 45, + 201, + 128, + 132, + 180, + 243, + 224, + 252, + 190, + 249, + 13, + 187, + 1, + 5, + 199, + 221, + 70, + 71, + 30, + 3, + 113, + 203, + 239, + 238, + 207, + 48, + 60, + 91, + 154, + 131, + 147, + 114, + 153, + 78, + 224, + 128, + 177, + 177, + 63, + 169, + 198, + 250, + 15, + 202, + 16, + 240, + 54, + 105, + 128, + 42, + 69, + 239, + 124, + 34, + 72, + 8, + 29, + 223, + 160, + 163, + 96, + 220, + 40, + 64, + 176, + 111, + 97, + 33, + 136, + 39, + 113, + 15, + 74, + 26, + 139, + 118, + 10, + 35, + 15, + 100, + 234, + 136, + 175, + 81, + 181, + 167, + 240, + 146, + 101, + 83, + 36, + 138, + 215, + 250, + 155, + 141, + 107, + 48, + 28, + 87, + 113, + 86, + 159, + 12, + 230, + 203, + 175, + 22, + 13, + 222, + 85, + 149, + 100, + 194, + 8, + 251, + 197, + 114, + 50, + 201, + 25, + 107, + 24, + 126, + 136, + 172, + 106, + 162, + 175, + 29, + 255, + 89, + 66, + 180, + 253, + 182, + 7, + 182, + 137, + 205, + 69, + 53, + 100, + 98, + 31, + 253, + 175, + 86, + 43, + 237, + 89, + 150, + 229, + 244, + 82, + 234, + 149, + 70, + 11, + 105, + 191, + 32, + 6, + 204, + 104, + 94, + 182, + 51, + 193, + 221, + 2, + 76, + 78, + 23, + 111, + 158, + 103, + 59, + 24, + 149, + 134, + 187, + 15, + 133, + 72, + 81, + 170, + 245, + 119, + 37, + 246, + 248, + 238, + 67, + 127, + 177, + 14, + 175, + 254, + 178, + 211, + 44, + 130, + 171, + 46, + 222, + 237, + 60, + 136, + 238, + 166, + 231, + 111, + 62, + 214, + 207, + 95, + 236, + 51, + 147, + 81, + 42, + 186, + 121, + 228, + 14, + 26, + 148, + 185, + 225, + 108, + 183, + 28, + 236, + 192, + 82, + 24, + 227, + 48, + 48, + 204, + 22, + 74, + 38, + 173, + 81, + 165, + 234, + 36, + 28, + 196, + 115, + 183, + 102, + 160, + 106, + 4, + 81, + 200, + 89, + 241, + 5, + 5, + 59, + 20, + 159, + 23, + 232, + 115, + 189, + 146, + 63, + 200, + 204, + 69, + 122, + 98, + 198, + 163, + 92, + 137, + 116, + 233, + 136, + 9, + 186, + 236, + 127, + 57, + 23, + 14, + 28, + 135, + 41, + 36, + 47, + 213, + 68, + 77, + 33, + 10, + 107, + 66, + 213, + 153, + 151, + 118, + 2, + 247, + 49, + 70, + 124, + 27, + 121, + 29, + 233, + 196, + 2, + 233, + 221, + 221, + 66, + 24, + 148, + 40, + 143, + 196, + 10, + 170, + 116, + 125, + 95, + 36, + 143, + 5, + 220, + 111, + 1, + 24, + 120, + 115, + 109, + 87, + 61, + 21, + 66, + 71, + 84, + 123, + 32, + 22, + 247, + 12, + 51, + 162, + 0, + 144, + 178, + 255, + 134, + 148, + 129, + 148, + 125, + 91, + 180, + 236, + 152, + 194, + 8, + 14, + 242, + 78, + 84, + 166, + 13, + 105, + 56, + 244, + 8, + 111, + 84, + 68, + 26, + 69, + 27, + 201, + 68, + 214, + 107, + 32, + 47, + 142, + 3, + 85, + 201, + 103, + 200, + 167, + 140, + 60, + 219, + 214, + 238, + 151, + 140, + 184, + 189, + 148, + 147, + 50, + 151, + 48, + 250, + 167, + 90, + 23, + 46, + 5, + 75, + 15, + 144, + 229, + 71, + 104, + 44, + 35, + 150, + 45, + 92, + 98, + 112, + 114, + 222, + 176, + 135, + 101, + 206, + 208, + 3, + 230, + 193, + 13, + 159, + 39, + 83, + 149, + 234, + 195, + 242, + 19, + 202, + 56, + 221, + 45, + 137, + 172, + 175, + 253, + 185, + 114, + 200, + 189, + 74, + 41, + 151, + 119, + 92, + 157, + 38, + 233, + 194, + 166, + 173, + 204, + 175, + 27, + 228, + 24, + 71, + 20, + 109, + 177, + 4, + 173, + 113, + 49, + 21, + 151, + 70, + 135, + 58, + 76, + 174, + 182, + 38, + 56, + 181, + 77, + 209, + 177, + 228, + 40, + 23, + 91, + 37, + 207, + 2, + 246, + 164, + 251, + 172, + 210, + 159, + 189, + 49, + 122, + 207, + 216, + 140, + 220, + 233, + 63, + 154, + 17, + 162, + 181, + 252, + 58, + 107, + 120, + 57, + 145, + 100, + 66, + 112, + 137, + 80, + 117, + 227, + 35, + 166, + 134, + 242, + 117, + 54, + 116, + 190, + 118, + 227, + 66, + 207, + 73, + 154, + 100, + 43, + 31, + 21, + 53, + 36, + 15, + 79, + 62, + 113, + 254, + 85, + 165, + 203, + 66, + 202, + 224, + 150, + 14, + 93, + 237, + 30, + 108, + 55, + 211, + 251, + 43, + 87, + 231, + 79, + 7, + 58, + 36, + 13, + 48, + 85, + 48, + 226, + 1, + 254, + 98, + 58, + 79, + 84, + 34, + 67, + 201, + 88, + 241, + 191, + 220, + 253, + 138, + 241, + 153, + 234, + 84, + 128, + 178, + 93, + 53, + 86, + 11, + 227, + 97, + 132, + 63, + 237, + 135, + 155, + 136, + 218, + 143, + 189, + 16, + 69, + 210, + 82, + 139, + 80, + 117, + 249, + 167, + 174, + 200, + 48, + 221, + 65, + 207, + 149, + 230, + 144, + 222, + 31, + 150, + 170, + 57, + 97, + 86, + 67, + 148, + 130, + 192, + 22, + 42, + 94, + 211, + 10, + 175, + 173, + 210, + 135, + 78, + 113, + 202, + 192, + 103, + 197, + 118, + 185, + 201, + 195, + 206, + 88, + 66, + 97, + 151, + 101, + 116, + 104, + 24, + 170, + 14, + 73, + 75, + 193, + 246, + 1, + 134, + 137, + 202, + 70, + 162, + 159, + 148, + 27, + 49, + 252, + 253, + 132, + 203, + 16, + 152, + 220, + 118, + 97, + 81, + 168, + 222, + 164, + 155, + 49, + 108, + 97, + 228, + 114, + 220, + 54, + 145, + 2, + 217, + 153, + 75, + 130, + 214, + 154, + 68, + 102, + 62, + 54, + 194, + 8, + 239, + 252, + 20, + 26, + 234, + 185, + 126, + 194, + 183, + 95, + 33, + 235, + 85, + 249, + 27, + 133, + 214, + 32, + 38, + 235, + 175, + 103, + 49, + 234, + 62, + 212, + 18, + 39, + 26, + 73, + 251, + 220, + 154, + 232, + 104, + 167, + 232, + 245, + 40, + 152, + 4, + 240, + 31, + 213, + 61, + 35, + 121, + 129, + 101, + 33, + 247, + 245, + 170, + 70, + 100, + 203, + 44, + 105, + 69, + 138, + 235, + 162, + 212, + 170, + 4, + 142, + 215, + 136, + 140, + 180, + 107, + 65, + 215, + 230, + 201, + 221, + 11, + 160, + 192, + 168, + 235, + 43, + 212, + 137, + 46, + 244, + 34, + 197, + 219, + 103, + 156, + 127, + 109, + 72, + 43, + 19, + 231, + 189, + 50, + 142, + 205, + 155, + 187, + 230, + 22, + 58, + 85, + 138, + 4, + 109, + 9, + 17, + 169, + 209, + 208, + 243, + 10, + 224, + 105, + 158, + 212, + 229, + 74, + 212, + 131, + 25, + 13, + 55, + 65, + 2, + 220, + 229, + 88, + 3, + 97, + 56, + 184, + 193, + 64, + 20, + 98, + 160, + 44, + 123, + 67, + 1, + 70, + 50, + 9, + 207, + 158, + 153, + 228, + 119, + 190, + 147, + 73, + 83, + 3, + 72, + 30, + 120, + 244, + 57, + 48, + 59, + 47, + 211, + 139, + 86, + 34, + 190, + 3, + 115, + 128, + 215, + 58, + 123, + 69, + 118, + 26, + 208, + 68, + 151, + 235, + 51, + 173, + 190, + 157, + 14, + 135, + 232, + 212, + 80, + 232, + 189, + 53, + 183, + 83, + 223, + 168, + 60, + 193, + 25, + 93, + 168, + 208, + 172, + 93, + 52, + 78, + 139, + 135, + 233, + 108, + 126, + 188, + 178, + 93, + 86, + 25, + 203, + 252, + 112, + 239, + 162, + 149, + 242, + 166, + 56, + 111, + 237, + 176, + 101, + 180, + 187, + 77, + 113, + 244, + 212, + 107, + 140, + 52, + 248, + 50, + 137, + 132, + 12, + 146, + 179, + 252, + 40, + 177, + 161, + 21, + 95, + 67, + 116, + 120, + 115, + 201, + 191, + 175, + 23, + 18, + 222, + 102, + 234, + 35, + 166, + 155, + 115, + 231, + 192, + 83, + 16, + 217, + 233, + 177, + 79, + 51, + 212, + 83, + 139, + 174, + 129, + 211, + 252, + 16, + 230, + 192, + 21, + 21, + 209, + 238, + 114, + 103, + 236, + 133, + 0, + 54, + 198, + 35, + 145, + 13, + 137, + 201, + 80, + 133, + 26, + 145, + 59, + 161, + 209, + 32, + 86, + 204, + 9, + 148, + 19, + 228, + 38, + 241, + 232, + 77, + 114, + 171, + 79, + 93, + 249, + 81, + 112, + 78, + 197, + 17, + 141, + 240, + 79, + 150, + 160, + 211, + 199, + 3, + 182, + 249, + 195, + 9, + 139, + 82, + 244, + 70, + 58, + 33, + 136, + 8, + 155, + 103, + 40, + 70, + 184, + 240, + 76, + 81, + 204, + 29, + 164, + 30, + 209, + 79, + 159, + 227, + 136, + 253, + 31, + 0, + 185, + 158, + 173, + 59, + 43, + 15, + 6, + 134, + 18, + 52, + 250, + 218, + 249, + 193, + 67, + 134, + 89, + 22, + 179, + 130, + 153, + 105, + 11, + 15, + 169, + 10, + 214, + 244, + 34, + 59, + 27, + 119, + 39, + 148, + 32, + 161, + 55, + 149, + 64, + 197, + 125, + 197, + 60, + 222, + 210, + 7, + 161, + 255, + 123, + 45, + 229, + 142, + 151, + 55, + 26, + 160, + 13, + 92, + 61, + 230, + 160, + 191, + 172, + 246, + 249, + 107, + 60, + 220, + 237, + 146, + 101, + 133, + 22, + 45, + 198, + 90, + 98, + 152, + 173, + 249, + 205, + 90, + 245, + 4, + 206, + 63, + 200, + 173, + 232, + 255, + 189, + 172, + 146, + 120, + 189, + 122, + 108, + 188, + 177, + 4, + 239, + 209, + 71, + 224, + 118, + 99, + 117, + 175, + 68, + 215, + 28, + 144, + 92, + 247, + 58, + 18, + 19, + 17, + 78, + 233, + 111, + 55, + 252, + 11, + 42, + 157, + 242, + 223, + 186, + 72, + 150, + 118, + 33, + 238, + 204, + 17, + 78, + 178, + 232, + 147, + 166, + 253, + 6, + 149, + 106, + 26, + 152, + 49, + 71, + 9, + 183, + 32, + 221, + 232, + 30, + 169, + 158, + 71, + 65, + 53, + 65, + 152, + 28, + 26, + 96, + 120, + 224, + 118, + 115, + 89, + 52, + 195, + 31, + 85, + 158, + 240, + 61, + 235, + 9, + 99, + 71, + 37, + 140, + 23, + 252, + 122, + 24, + 3, + 114, + 156, + 151, + 185, + 158, + 132, + 202, + 42, + 209, + 191, + 157, + 215, + 23, + 74, + 121, + 125, + 85, + 127, + 204, + 175, + 169, + 193, + 213, + 35, + 42, + 31, + 51, + 24, + 227, + 223, + 202, + 245, + 54, + 152, + 224, + 151, + 97, + 218, + 219, + 4, + 248, + 210, + 47, + 195, + 86, + 251, + 89, + 168, + 87, + 32, + 239, + 61, + 33, + 80, + 129, + 121, + 40, + 85, + 134, + 177, + 163, + 149, + 28, + 27, + 139, + 240, + 162, + 151, + 132, + 208, + 4, + 159, + 5, + 117, + 163, + 199, + 193, + 228, + 231, + 113, + 87, + 245, + 88, + 10, + 92, + 202, + 136, + 109, + 81, + 50, + 78, + 140, + 16, + 185, + 50, + 12, + 199, + 47, + 107, + 2, + 107, + 179, + 80, + 173, + 216, + 191, + 141, + 230, + 149, + 162, + 224, + 36, + 211, + 231, + 84, + 136, + 210, + 21, + 98, + 241, + 83, + 39, + 176, + 162, + 183, + 9, + 66, + 96, + 100, + 64, + 80, + 143, + 244, + 23, + 126, + 221, + 114, + 232, + 237, + 181, + 220, + 184, + 69, + 187, + 234, + 173, + 24, + 117, + 166, + 132, + 134, + 113, + 151, + 37, + 140, + 217, + 170, + 104, + 223, + 65, + 244, + 52, + 0, + 207, + 220, + 137, + 146, + 230, + 89, + 90, + 191, + 86, + 162, + 53, + 48, + 133, + 162, + 118, + 20, + 15, + 16, + 37, + 161, + 221, + 23, + 105, + 195, + 34, + 149, + 147, + 153, + 86, + 120, + 223, + 159, + 95, + 167, + 56, + 220, + 122, + 158, + 0, + 160, + 19, + 16, + 218, + 143, + 3, + 99, + 221, + 140, + 208, + 86, + 194, + 62, + 58, + 224, + 83, + 169, + 46, + 179, + 71, + 116, + 178, + 114, + 20, + 141, + 52, + 194, + 130, + 70, + 89, + 15, + 182, + 31, + 108, + 62, + 117, + 65, + 117, + 250, + 34, + 119, + 231, + 64, + 183, + 8, + 255, + 248, + 54, + 181, + 92, + 20, + 46, + 167, + 11, + 189, + 130, + 182, + 162, + 39, + 63, + 75, + 61, + 176, + 217, + 120, + 6, + 103, + 19, + 221, + 45, + 94, + 104, + 95, + 134, + 221, + 178, + 168, + 220, + 63, + 94, + 49, + 235, + 248, + 211, + 207, + 154, + 230, + 252, + 52, + 213, + 189, + 227, + 151, + 209, + 184, + 28, + 202, + 194, + 124, + 149, + 252, + 168, + 25, + 110, + 207, + 144, + 178, + 245, + 2, + 27, + 23, + 74, + 153, + 79, + 188, + 1, + 26, + 111, + 36, + 71, + 108, + 74, + 80, + 167, + 132, + 14, + 90, + 137, + 140, + 90, + 240, + 64, + 164, + 215, + 124, + 46, + 60, + 0, + 46, + 157, + 246, + 7, + 145, + 76, + 14, + 232, + 227, + 243, + 123, + 233, + 4, + 20, + 233, + 133, + 172, + 107, + 32, + 53, + 101, + 11, + 50, + 132, + 21, + 217, + 240, + 189, + 151, + 110, + 29, + 246, + 67, + 226, + 162, + 248, + 205, + 115, + 166, + 68, + 166, + 104, + 28, + 32, + 48, + 16, + 215, + 160, + 157, + 247, + 73, + 215, + 0, + 170, + 25, + 193, + 162, + 227, + 211, + 100, + 178, + 201, + 154, + 49, + 217, + 138, + 137, + 230, + 201, + 102, + 98, + 219, + 250, + 120, + 100, + 40, + 215, + 167, + 41, + 169, + 113, + 85, + 158, + 242, + 100, + 129, + 233, + 233, + 246, + 105, + 101, + 64, + 16, + 47, + 162, + 254, + 30, + 167, + 218, + 194, + 207, + 46, + 23, + 234, + 71, + 165, + 209, + 143, + 209, + 235, + 148, + 239, + 121, + 205, + 220, + 64, + 225, + 214, + 252, + 206, + 57, + 91, + 159, + 223, + 199, + 54, + 165, + 182, + 175, + 35, + 88, + 142, + 194, + 63, + 253, + 13, + 71, + 152, + 12, + 44, + 223, + 105, + 12, + 25, + 225, + 6, + 56, + 120, + 80, + 54, + 89, + 51, + 112, + 137, + 56, + 205, + 65, + 37, + 162, + 48, + 101, + 124, + 46, + 122, + 185, + 30, + 151, + 145, + 68, + 42, + 159, + 119, + 154, + 32, + 81, + 252, + 225, + 121, + 68, + 127, + 231, + 220, + 231, + 9, + 247, + 18, + 84, + 81, + 126, + 133, + 7, + 145, + 231, + 116, + 206, + 143, + 138, + 94, + 61, + 75, + 161, + 240, + 253, + 223, + 226, + 243, + 50, + 201, + 176, + 225, + 210, + 47, + 83, + 183, + 58, + 17, + 218, + 97, + 0, + 203, + 164, + 68, + 155, + 153, + 195, + 7, + 123, + 5, + 186, + 10, + 144, + 121, + 144, + 56, + 30, + 86, + 78, + 106, + 225, + 227, + 200, + 2, + 108, + 188, + 250, + 99, + 193, + 58, + 65, + 147, + 120, + 152, + 63, + 174, + 44, + 46, + 249, + 84, + 121, + 105, + 148, + 100, + 211, + 253, + 78, + 228, + 187, + 179, + 146, + 241, + 230, + 134, + 231, + 60, + 97, + 104, + 150, + 37, + 199, + 14, + 77, + 15, + 228, + 31, + 243, + 166, + 21, + 178, + 232, + 210, + 232, + 86, + 192, + 5, + 178, + 184, + 249, + 48, + 206, + 55, + 207, + 111, + 224, + 97, + 172, + 248, + 76, + 133, + 110, + 221, + 240, + 198, + 213, + 58, + 45, + 182, + 57, + 13, + 70, + 122, + 191, + 53, + 173, + 116, + 116, + 59, + 88, + 219, + 233, + 27, + 252, + 235, + 96, + 228, + 105, + 54, + 11, + 103, + 28, + 32, + 232, + 18, + 216, + 82, + 46, + 253, + 173, + 195, + 148, + 31, + 88, + 98, + 11, + 37, + 48, + 221, + 191, + 17, + 24, + 118, + 219, + 43, + 95, + 245, + 43, + 229, + 28, + 250, + 254, + 206, + 247, + 167, + 61, + 56, + 87, + 251, + 79, + 27, + 250, + 123, + 218, + 153, + 223, + 145, + 233, + 191, + 255, + 77, + 234, + 88, + 240, + 113, + 193, + 93, + 161, + 130, + 73, + 105, + 193, + 93, + 41, + 91, + 244, + 104, + 182, + 175, + 251, + 18, + 168, + 255, + 7, + 178, + 34, + 243, + 11, + 192, + 216, + 127, + 168, + 132, + 126, + 101, + 25, + 208, + 200, + 203, + 132, + 53, + 80, + 114, + 44, + 86, + 20, + 155, + 73, + 205, + 143, + 107, + 47, + 98, + 15, + 140, + 142, + 123, + 36, + 5, + 189, + 228, + 40, + 138, + 4, + 40, + 160, + 93, + 178, + 88, + 68, + 248, + 166, + 174, + 177, + 56, + 113, + 70, + 42, + 1, + 225, + 55, + 57, + 85, + 187, + 193, + 195, + 182, + 71, + 168, + 86, + 201, + 200, + 254, + 161, + 118, + 233, + 62, + 169, + 91, + 128, + 49, + 190, + 80, + 99, + 148, + 153, + 138, + 99, + 82, + 136, + 207, + 136, + 217, + 14, + 148, + 138, + 162, + 161, + 16, + 43, + 223, + 240, + 245, + 148, + 231, + 219, + 213, + 252, + 71, + 181, + 46, + 43, + 234, + 54, + 186, + 254, + 144, + 247, + 31, + 163, + 219, + 104, + 161, + 65, + 59, + 162, + 252, + 184, + 33, + 211, + 198, + 131, + 64, + 255, + 103, + 93, + 56, + 101, + 227, + 126, + 19, + 76, + 91, + 97, + 6, + 254, + 218, + 49, + 132, + 182, + 56, + 152, + 108, + 47, + 190, + 97, + 185, + 1, + 103, + 48, + 115, + 185, + 37, + 154, + 236, + 136, + 111, + 156, + 98, + 100, + 35, + 0, + 33, + 177, + 23, + 78, + 169, + 224, + 164, + 0, + 24, + 26, + 187, + 156, + 9, + 219, + 124, + 149, + 46, + 50, + 206, + 22, + 67, + 241, + 204, + 143, + 174, + 31, + 60, + 217, + 1, + 14, + 46, + 44, + 94, + 42, + 0, + 213, + 62, + 222, + 108, + 30, + 222, + 179, + 125, + 242, + 182, + 176, + 211, + 252, + 121, + 24, + 215, + 229, + 150, + 69, + 42, + 151, + 202, + 195, + 181, + 58, + 185, + 108, + 206, + 213, + 243, + 0, + 8, + 198, + 119, + 146, + 11, + 83, + 207, + 51, + 209, + 97, + 192, + 54, + 64, + 6, + 154, + 53, + 30, + 76, + 191, + 163, + 42, + 200, + 24, + 0, + 199, + 59, + 123, + 110, + 242, + 76, + 110, + 88, + 43, + 69, + 221, + 206, + 176, + 251, + 157, + 123, + 235, + 99, + 98, + 121, + 27, + 54, + 13, + 56, + 108, + 3, + 244, + 149, + 7, + 40, + 202, + 48, + 62, + 83, + 79, + 245, + 77, + 205, + 5, + 132, + 72, + 45, + 227, + 119, + 13, + 88, + 95, + 188, + 216, + 15, + 112, + 31, + 137, + 61, + 174, + 87, + 194, + 157, + 28, + 155, + 179, + 56, + 158, + 172, + 68, + 245, + 229, + 220, + 154, + 185, + 19, + 237, + 68, + 32, + 73, + 46, + 214, + 80, + 149, + 37, + 242, + 62, + 2, + 36, + 38, + 216, + 5, + 224, + 129, + 161, + 4, + 65, + 183, + 177, + 202, + 239, + 215, + 107, + 176, + 233, + 77, + 62, + 153, + 253, + 60, + 140, + 195, + 212, + 233, + 232, + 101, + 50, + 195, + 249, + 45, + 162, + 203, + 60, + 201, + 0, + 155, + 76, + 129, + 88, + 6, + 103, + 107, + 115, + 4, + 96, + 212, + 201, + 254, + 56, + 84, + 78, + 22, + 214, + 76, + 214, + 1, + 131, + 66, + 12, + 48, + 174, + 39, + 123, + 75, + 218, + 253, + 218, + 44, + 173, + 10, + 210, + 92, + 162, + 109, + 10, + 50, + 72, + 36, + 97, + 167, + 44, + 52, + 176, + 95, + 41, + 163, + 214, + 16, + 188, + 196, + 57, + 27, + 19, + 135, + 234, + 153, + 1, + 175, + 101, + 120, + 227, + 64, + 107, + 224, + 57, + 89, + 183, + 171, + 137, + 192, + 0, + 139, + 188, + 77, + 42, + 49, + 222, + 198, + 219, + 227, + 34, + 183, + 13, + 47, + 195, + 161, + 242, + 48, + 142, + 11, + 15, + 135, + 46, + 73, + 182, + 171, + 213, + 141, + 15, + 244, + 88, + 69, + 200, + 114, + 97, + 51, + 178, + 93, + 144, + 145, + 200, + 175, + 138, + 238, + 92, + 217, + 94, + 255, + 130, + 194, + 118, + 144, + 64, + 150, + 5, + 90, + 69, + 23, + 164, + 210, + 235, + 135, + 50, + 51, + 35, + 8, + 175, + 145, + 237, + 81, + 240, + 52, + 106, + 126, + 242, + 74, + 7, + 190, + 104, + 174, + 183, + 5, + 228, + 15, + 96, + 42, + 27, + 98, + 80, + 172, + 5, + 7, + 233, + 41, + 170, + 38, + 159, + 132, + 190, + 223, + 52, + 9, + 48, + 101, + 43, + 27, + 130, + 14, + 252, + 221, + 57, + 205, + 153, + 254, + 224, + 72, + 81, + 41, + 48, + 117, + 242, + 140, + 51, + 73, + 217, + 60, + 176, + 252, + 66, + 150, + 193, + 188, + 78, + 22, + 9, + 29, + 6, + 99, + 86, + 157, + 194, + 62, + 163, + 162, + 90, + 229, + 141, + 56, + 150, + 16, + 43, + 156, + 155, + 197, + 185, + 107, + 17, + 124, + 39, + 254, + 218, + 91, + 194, + 41, + 14, + 31, + 189, + 174, + 168, + 75, + 250, + 58, + 68, + 59, + 140, + 127, + 117, + 152, + 190, + 216, + 0, + 24, + 174, + 207, + 70, + 177, + 143, + 176, + 78, + 45, + 68, + 142, + 155, + 78, + 138, + 29, + 101, + 87, + 39, + 113, + 64, + 34, + 80, + 118, + 7, + 116, + 183, + 108, + 193, + 88, + 101, + 233, + 238, + 19, + 78, + 2, + 119, + 217, + 181, + 178, + 241, + 46, + 162, + 43, + 132, + 55, + 176, + 164, + 204, + 8, + 163, + 99, + 224, + 20, + 235, + 42, + 43, + 164, + 221, + 235, + 52, + 45, + 108, + 164, + 93, + 251, + 169, + 63, + 103, + 235, + 14, + 66, + 220, + 12, + 108, + 182, + 145, + 12, + 133, + 153, + 193, + 101, + 213, + 25, + 156, + 122, + 158, + 227, + 112, + 219, + 161, + 58, + 225, + 90, + 143, + 137, + 133, + 97, + 96, + 115, + 183, + 223, + 66, + 30, + 56, + 116, + 230, + 186, + 171, + 221, + 224, + 73, + 244, + 47, + 125, + 157, + 214, + 137, + 135, + 229, + 18, + 80, + 171, + 206, + 224, + 38, + 119, + 119, + 65, + 10, + 152, + 182, + 158, + 181, + 170, + 68, + 35, + 92, + 217, + 189, + 60, + 61, + 22, + 132, + 164, + 37, + 37, + 155, + 69, + 207, + 72, + 46, + 157, + 85, + 124, + 126, + 42, + 114, + 168, + 73, + 184, + 224, + 244, + 90, + 245, + 36, + 246, + 67, + 145, + 10, + 97, + 214, + 108, + 250, + 202, + 37, + 76, + 15, + 208, + 104, + 24, + 184, + 124, + 216, + 195, + 132, + 244, + 61, + 225, + 169, + 49, + 241, + 210, + 196, + 207, + 83, + 158, + 244, + 211, + 115, + 53, + 11, + 148, + 0, + 159, + 188, + 201, + 79, + 145, + 99, + 168, + 112, + 83, + 124, + 13, + 83, + 135, + 183, + 21, + 59, + 173, + 109, + 126, + 234, + 42, + 151, + 28, + 205, + 141, + 69, + 79, + 146, + 4, + 83, + 194, + 152, + 82, + 78, + 226, + 7, + 164, + 97, + 37, + 1, + 134, + 121, + 62, + 108, + 14, + 217, + 228, + 138, + 209, + 31, + 152, + 129, + 17, + 244, + 11, + 105, + 127, + 247, + 24, + 172, + 16, + 188, + 33, + 146, + 27, + 166, + 169, + 194, + 0, + 38, + 221, + 184, + 166, + 71, + 80, + 104, + 3, + 5, + 6, + 113, + 171, + 205, + 148, + 203, + 93, + 210, + 148, + 210, + 190, + 253, + 202, + 30, + 223, + 240, + 122, + 4, + 165, + 91, + 39, + 112, + 31, + 25, + 36, + 98, + 89, + 121, + 109, + 11, + 80, + 81, + 35, + 11, + 155, + 54, + 197, + 250, + 118, + 251, + 82, + 69, + 136, + 140, + 21, + 167, + 43, + 243, + 126, + 208, + 245, + 34, + 189, + 94, + 139, + 106, + 19, + 198, + 155, + 208, + 165, + 134, + 225, + 81, + 170, + 113, + 249, + 61, + 130, + 14, + 163, + 66, + 41, + 67, + 218, + 22, + 51, + 152, + 44, + 57, + 58, + 135, + 121, + 73, + 201, + 106, + 67, + 60, + 24, + 126, + 62, + 121, + 208, + 97, + 130, + 149, + 131, + 136, + 122, + 221, + 72, + 225, + 93, + 206, + 187, + 68, + 33, + 4, + 117, + 239, + 35, + 121, + 86, + 72, + 50, + 59, + 7, + 232, + 133, + 18, + 128, + 205, + 144, + 148, + 42, + 52, + 15, + 248, + 105, + 85, + 227, + 109, + 223, + 99, + 186, + 22, + 63, + 57, + 10, + 101, + 82, + 165, + 55, + 159, + 214, + 178, + 161, + 162, + 242, + 73, + 37, + 13, + 87, + 56, + 162, + 139, + 147, + 126, + 71, + 166, + 180, + 136, + 50, + 10, + 190, + 97, + 147, + 226, + 13, + 222, + 55, + 191, + 123, + 18, + 53, + 226, + 62, + 212, + 245, + 34, + 180, + 14, + 4, + 19, + 11, + 212, + 190, + 246, + 172, + 245, + 36, + 136, + 8, + 211, + 99, + 57, + 228, + 144, + 73, + 181, + 178, + 161, + 129, + 102, + 1, + 61, + 236, + 69, + 68, + 183, + 46, + 156, + 180, + 112, + 251, + 111, + 210, + 242, + 100, + 114, + 244, + 144, + 92, + 144, + 156, + 84, + 20, + 58, + 221, + 59, + 157, + 229, + 195, + 177, + 85, + 68, + 40, + 211, + 176, + 63, + 247, + 58, + 235, + 190, + 29, + 253, + 192, + 65, + 131, + 170, + 10, + 104, + 225, + 185, + 101, + 168, + 24, + 141, + 151, + 136, + 211, + 197, + 253, + 100, + 175, + 24, + 52, + 223, + 14, + 50, + 133, + 81, + 182, + 232, + 35, + 67, + 241, + 221, + 197, + 83, + 220, + 206, + 38, + 232, + 178, + 59, + 136, + 193, + 50, + 70, + 174, + 74, + 115, + 243, + 228, + 172, + 252, + 79, + 0, + 84, + 133, + 74, + 233, + 113, + 172, + 194, + 200, + 181, + 33, + 55, + 153, + 59, + 19, + 47, + 163, + 106, + 208, + 87, + 4, + 41, + 136, + 92, + 237, + 203, + 26, + 16, + 83, + 154, + 165, + 236, + 136, + 21, + 133, + 211, + 103, + 193, + 213, + 56, + 251, + 186, + 223, + 111, + 250, + 85, + 254, + 233, + 243, + 15, + 181, + 105, + 118, + 186, + 151, + 93, + 250, + 206, + 57, + 255, + 107, + 149, + 5, + 230, + 182, + 47, + 208, + 79, + 67, + 82, + 194, + 179, + 127, + 41, + 204, + 188, + 214, + 57, + 194, + 30, + 170, + 105, + 176, + 32, + 208, + 12, + 20, + 119, + 103, + 187, + 56, + 170, + 245, + 19, + 80, + 73, + 34, + 122, + 205, + 80, + 254, + 221, + 238, + 127, + 151, + 155, + 89, + 67, + 180, + 26, + 163, + 25, + 143, + 28, + 110, + 169, + 14, + 9, + 155, + 183, + 4, + 11, + 201, + 191, + 154, + 69, + 82, + 166, + 55, + 106, + 170, + 99, + 170, + 122, + 80, + 173, + 243, + 46, + 136, + 14, + 107, + 90, + 60, + 132, + 177, + 37, + 22, + 178, + 100, + 188, + 208, + 104, + 88, + 220, + 168, + 24, + 169, + 153, + 208, + 177, + 101, + 118, + 89, + 191, + 17, + 50, + 17, + 97, + 95, + 238, + 61, + 233, + 226, + 10, + 9, + 245, + 186, + 197, + 188, + 98, + 31, + 102, + 161, + 24, + 198, + 64, + 196, + 111, + 246, + 92, + 108, + 186, + 221, + 49, + 222, + 61, + 25, + 73, + 6, + 244, + 238, + 241, + 5, + 211, + 46, + 52, + 225, + 12, + 26, + 14, + 159, + 240, + 120, + 194, + 117, + 83, + 123, + 30, + 27, + 70, + 23, + 81, + 136, + 103, + 198, + 9, + 74, + 36, + 23, + 18, + 219, + 88, + 0, + 151, + 13, + 65, + 95, + 23, + 87, + 122, + 58, + 130, + 114, + 1, + 155, + 37, + 175, + 222, + 241, + 104, + 201, + 159, + 186, + 73, + 229, + 175, + 156, + 100, + 95, + 118, + 101, + 254, + 223, + 216, + 225, + 174, + 236, + 24, + 227, + 102, + 242, + 145, + 112, + 136, + 81, + 148, + 210, + 174, + 66, + 57, + 170, + 44, + 48, + 244, + 217, + 139, + 171, + 201, + 177, + 144, + 220, + 202, + 58, + 253, + 183, + 226, + 166, + 149, + 72, + 148, + 118, + 27, + 1, + 45, + 77, + 83, + 117, + 91, + 254, + 179, + 2, + 216, + 154, + 46, + 19, + 95, + 67, + 190, + 246, + 21, + 187, + 207, + 232, + 255, + 254, + 180, + 192, + 232, + 166, + 26, + 181, + 7, + 232, + 77, + 41, + 93, + 12, + 154, + 105, + 124, + 191, + 78, + 71, + 5, + 204, + 53, + 72, + 164, + 124, + 107, + 109, + 175, + 244, + 204, + 38, + 201, + 181, + 43, + 233, + 214, + 99, + 221, + 250, + 5, + 150, + 16, + 224, + 135, + 128, + 5, + 158, + 137, + 164, + 215, + 148, + 187, + 60, + 245, + 150, + 158, + 163, + 39, + 25, + 102, + 208, + 171, + 159, + 20, + 99, + 73, + 91, + 26, + 0, + 65, + 101, + 195, + 82, + 66, + 75, + 196, + 105, + 35, + 225, + 120, + 161, + 91, + 120, + 254, + 151, + 45, + 54, + 89, + 1, + 235, + 38, + 223, + 83, + 86, + 194, + 121, + 16, + 130, + 177, + 79, + 225, + 0, + 45, + 121, + 243, + 31, + 228, + 164, + 159, + 100, + 16, + 175, + 115, + 157, + 35, + 83, + 223, + 88, + 114, + 214, + 68, + 30, + 203, + 53, + 9, + 81, + 153, + 7, + 74, + 96, + 44, + 47, + 90, + 243, + 71, + 134, + 37, + 65, + 109, + 228, + 237, + 161, + 23, + 223, + 29, + 162, + 212, + 85, + 44, + 156, + 174, + 134, + 61, + 11, + 213, + 25, + 110, + 220, + 145, + 52, + 79, + 25, + 67, + 52, + 121, + 44, + 188, + 115, + 113, + 107, + 152, + 34, + 28, + 86, + 28, + 53, + 115, + 230, + 26, + 76, + 69, + 182, + 247, + 142, + 144, + 209, + 70, + 60, + 223, + 160, + 46, + 129, + 85, + 25, + 72, + 254, + 254, + 217, + 71, + 74, + 234, + 24, + 101, + 76, + 230, + 47, + 181, + 102, + 118, + 70, + 129, + 173, + 142, + 121, + 80, + 67, + 30, + 195, + 148, + 30, + 250, + 86, + 66, + 15, + 205, + 27, + 32, + 160, + 135, + 22, + 179, + 137, + 56, + 82, + 160, + 182, + 139, + 24, + 18, + 129, + 88, + 48, + 198, + 48, + 248, + 134, + 102, + 139, + 162, + 171, + 131, + 30, + 197, + 207, + 151, + 126, + 57, + 192, + 202, + 195, + 14, + 193, + 249, + 235, + 194, + 19, + 211, + 134, + 171, + 233, + 199, + 97, + 21, + 132, + 102, + 82, + 153, + 82, + 38, + 45, + 183, + 161, + 47, + 190, + 7, + 154, + 101, + 228, + 236, + 55, + 86, + 194, + 70, + 112, + 205, + 70, + 73, + 105, + 119, + 102, + 45, + 214, + 255, + 118, + 192, + 59, + 240, + 91, + 173, + 112, + 160, + 96, + 166, + 64, + 239, + 137, + 228, + 96, + 7, + 99, + 8, + 103, + 110, + 111, + 80, + 81, + 2, + 11, + 28, + 23, + 185, + 186, + 85, + 92, + 94, + 55, + 189, + 76, + 156, + 29, + 147, + 92, + 54, + 131, + 132, + 203, + 73, + 97, + 224, + 223, + 55, + 74, + 56, + 146, + 37, + 195, + 68, + 245, + 51, + 28, + 205, + 16, + 169, + 37, + 129, + 89, + 139, + 249, + 226, + 193, + 217, + 212, + 174, + 67, + 29, + 174, + 84, + 62, + 201, + 178, + 16, + 153, + 103, + 204, + 17, + 29, + 181, + 144, + 22, + 161, + 194, + 141, + 60, + 16, + 102, + 252, + 182, + 149, + 207, + 140, + 2, + 163, + 20, + 201, + 53, + 200, + 168, + 249, + 82, + 144, + 86, + 91, + 232, + 226, + 79, + 248, + 99, + 107, + 76, + 21, + 90, + 14, + 60, + 188, + 239, + 51, + 176, + 44, + 26, + 142, + 103, + 242, + 159, + 196, + 84, + 247, + 184, + 165, + 199, + 231, + 195, + 87, + 195, + 21, + 91, + 177, + 149, + 130, + 234, + 246, + 154, + 201, + 14, + 76, + 27, + 62, + 243, + 72, + 108, + 29, + 228, + 150, + 183, + 38, + 203, + 33, + 161, + 102, + 119, + 1, + 142, + 103, + 100, + 148, + 124, + 231, + 115, + 198, + 162, + 239, + 179, + 118, + 173, + 242, + 247, + 194, + 231, + 42, + 201, + 64, + 125, + 128, + 214, + 8, + 188, + 191, + 28, + 162, + 169, + 168, + 28, + 245, + 41, + 246, + 210, + 74, + 196, + 182, + 177, + 197, + 214, + 127, + 226, + 182, + 88, + 159, + 93, + 35, + 177, + 37, + 71, + 105, + 194, + 92, + 96, + 220, + 66, + 17, + 143, + 3, + 60, + 46, + 127, + 132, + 17, + 72, + 84, + 53, + 99, + 244, + 69, + 150, + 111, + 209, + 170, + 180, + 181, + 143, + 183, + 81, + 220, + 130, + 244, + 39, + 2, + 27, + 156, + 120, + 130, + 39, + 247, + 99, + 137, + 185, + 210, + 12, + 13, + 59, + 25, + 239, + 191, + 44, + 10, + 44, + 140, + 29, + 192, + 70, + 155, + 191, + 54, + 206, + 28, + 88, + 247, + 4, + 60, + 1, + 207, + 69, + 182, + 126, + 112, + 203, + 100, + 174, + 33, + 244, + 101, + 134, + 37, + 133, + 212, + 136, + 155, + 241, + 244, + 8, + 226, + 252, + 63, + 111, + 37, + 16, + 180, + 67, + 161, + 109, + 212, + 124, + 218, + 220, + 152, + 16, + 24, + 17, + 187, + 3, + 14, + 122, + 75, + 121, + 85, + 43, + 203, + 131, + 175, + 82, + 24, + 176, + 166, + 227, + 29, + 47, + 151, + 67, + 26, + 37, + 121, + 107, + 174, + 248, + 80, + 50, + 91, + 200, + 159, + 85, + 182, + 96, + 31, + 186, + 32, + 18, + 7, + 235, + 189, + 200, + 202, + 109, + 245, + 15, + 64, + 209, + 206, + 79, + 16, + 44, + 176, + 70, + 249, + 73, + 144, + 237, + 195, + 140, + 246, + 19, + 0, + 109, + 85, + 78, + 230, + 66, + 177, + 101, + 214, + 26, + 87, + 17, + 96, + 21, + 71, + 135, + 116, + 191, + 161, + 39, + 44, + 117, + 29, + 173, + 213, + 77, + 216, + 214, + 42, + 122, + 160, + 23, + 246, + 120, + 43, + 170, + 185, + 3, + 83, + 199, + 175, + 126, + 162, + 206, + 109, + 0, + 178, + 141, + 20, + 63, + 82, + 14, + 74, + 41, + 198, + 111, + 68, + 4, + 55, + 12, + 39, + 30, + 14, + 173, + 85, + 225, + 215, + 167, + 110, + 244, + 28, + 10, + 51, + 141, + 104, + 202, + 122, + 178, + 136, + 93, + 177, + 58, + 69, + 132, + 2, + 62, + 215, + 179, + 188, + 27, + 193, + 166, + 53, + 58, + 115, + 15, + 77, + 203, + 58, + 237, + 198, + 181, + 206, + 205, + 128, + 128, + 74, + 195, + 27, + 71, + 216, + 69, + 251, + 145, + 200, + 7, + 92, + 180, + 233, + 165, + 180, + 38, + 162, + 247, + 44, + 180, + 88, + 42, + 50, + 168, + 224, + 31, + 18, + 231, + 238, + 38, + 183, + 213, + 112, + 36, + 147, + 234, + 96, + 253, + 214, + 28, + 88, + 199, + 155, + 74, + 134, + 214, + 183, + 68, + 111, + 57, + 53, + 40, + 110, + 113, + 120, + 128, + 148, + 248, + 148, + 157, + 134, + 166, + 6, + 12, + 244, + 186, + 222, + 102, + 88, + 198, + 45, + 194, + 179, + 169, + 241, + 135, + 72, + 94, + 147, + 76, + 1, + 214, + 196, + 195, + 136, + 194, + 117, + 95, + 225, + 135, + 78, + 247, + 96, + 135, + 1, + 159, + 197, + 209, + 156, + 43, + 63, + 52, + 22, + 231, + 6, + 147, + 231, + 101, + 115, + 13, + 52, + 84, + 3, + 129, + 122, + 129, + 184, + 55, + 180, + 64, + 81, + 125, + 2, + 46, + 182, + 221, + 145, + 216, + 41, + 234, + 14, + 64, + 109, + 195, + 150, + 107, + 229, + 178, + 21, + 224, + 29, + 130, + 190, + 106, + 89, + 120, + 138, + 29, + 30, + 243, + 245, + 185, + 135, + 183, + 88, + 255, + 147, + 137, + 105, + 19, + 17, + 122, + 46, + 15, + 127, + 44, + 9, + 164, + 239, + 246, + 17, + 241, + 204, + 65, + 201, + 102, + 174, + 246, + 126, + 52, + 238, + 184, + 178, + 163, + 6, + 163, + 13, + 205, + 211, + 121, + 61, + 105, + 220, + 114, + 146, + 37, + 38, + 87, + 52, + 36, + 128, + 149, + 143, + 161, + 88, + 45, + 20, + 0, + 230, + 91, + 157, + 184, + 33, + 238, + 166, + 142, + 58, + 8, + 246, + 156, + 209, + 39, + 120, + 91, + 16, + 252, + 245, + 61, + 119, + 146, + 164, + 224, + 237, + 57, + 115, + 111, + 60, + 175, + 8, + 27, + 165, + 185, + 149, + 216, + 251, + 128, + 151, + 41, + 182, + 142, + 82, + 227, + 74, + 186, + 192, + 174, + 38, + 193, + 200, + 6, + 80, + 86, + 146, + 24, + 144, + 90, + 212, + 26, + 138, + 1, + 8, + 21, + 92, + 85, + 33, + 174, + 182, + 112, + 17, + 105, + 127, + 103, + 251, + 192, + 234, + 208, + 65, + 220, + 193, + 34, + 60, + 45, + 236, + 145, + 172, + 143, + 138, + 141, + 27, + 152, + 154, + 9, + 13, + 96, + 155, + 23, + 112, + 90, + 224, + 6, + 110, + 144, + 160, + 88, + 94, + 188, + 123, + 97, + 10, + 147, + 1, + 229, + 123, + 10, + 249, + 13, + 230, + 104, + 248, + 3, + 217, + 249, + 207, + 15, + 225, + 63, + 130, + 122, + 177, + 114, + 81, + 195, + 91, + 187, + 81, + 110, + 64, + 229, + 238, + 177, + 22, + 26, + 140, + 26, + 32, + 184, + 47, + 211, + 203, + 14, + 96, + 188, + 159, + 40, + 84, + 48, + 182, + 12, + 115, + 108, + 41, + 120, + 116, + 32, + 236, + 86, + 130, + 83, + 216, + 96, + 129, + 81, + 49, + 126, + 238, + 217, + 44, + 49, + 31, + 246, + 30, + 22, + 41, + 138, + 51, + 36, + 176, + 122, + 105, + 115, + 221, + 127, + 155, + 249, + 233, + 199, + 14, + 23, + 229, + 5, + 1, + 212, + 93, + 138, + 90, + 226, + 116, + 110, + 45, + 20, + 16, + 214, + 100, + 175, + 220, + 47, + 218, + 222, + 232, + 50, + 116, + 75, + 88, + 90, + 228, + 190, + 1, + 213, + 93, + 230, + 29, + 17, + 167, + 209, + 94, + 54, + 128, + 228, + 163, + 48, + 133, + 107, + 188, + 33, + 180, + 66, + 53, + 78, + 123, + 53, + 128, + 25, + 106, + 29, + 136, + 132, + 246, + 249, + 12, + 26, + 131, + 89, + 140, + 162, + 79, + 217, + 21, + 146, + 7, + 70, + 201, + 205, + 230, + 221, + 30, + 63, + 171, + 40, + 233, + 25, + 100, + 6, + 173, + 190, + 133, + 114, + 156, + 182, + 248, + 249, + 210, + 148, + 81, + 25, + 120, + 114, + 78, + 222, + 38, + 242, + 227, + 127, + 83, + 181, + 131, + 61, + 61, + 94, + 65, + 192, + 119, + 222, + 37, + 225, + 145, + 233, + 118, + 9, + 64, + 88, + 159, + 125, + 230, + 9, + 92, + 179, + 24, + 124, + 37, + 15, + 219, + 127, + 55, + 54, + 253, + 155, + 249, + 168, + 38, + 78, + 49, + 176, + 196, + 133, + 158, + 132, + 118, + 255, + 161, + 46, + 209, + 167, + 164, + 217, + 115, + 44, + 16, + 60, + 11, + 86, + 20, + 115, + 167, + 14, + 13, + 55, + 78, + 101, + 47, + 230, + 255, + 106, + 106, + 130, + 163, + 254, + 19, + 233, + 75, + 88, + 62, + 4, + 252, + 242, + 177, + 55, + 180, + 22, + 182, + 120, + 5, + 66, + 158, + 30, + 54, + 90, + 41, + 114, + 8, + 72, + 104, + 198, + 229, + 111, + 95, + 106, + 171, + 105, + 95, + 50, + 80, + 49, + 168, + 83, + 241, + 131, + 185, + 51, + 17, + 195, + 4, + 198, + 110, + 219, + 17, + 178, + 170, + 135, + 91, + 89, + 95, + 231, + 30, + 128, + 83, + 12, + 106, + 21, + 141, + 37, + 140, + 140, + 239, + 210, + 197, + 28, + 60, + 213, + 148, + 135, + 234, + 211, + 204, + 223, + 151, + 216, + 131, + 231, + 126, + 224, + 122, + 225, + 26, + 211, + 72, + 85, + 94, + 170, + 132, + 5, + 24, + 111, + 223, + 64, + 88, + 229, + 18, + 109, + 91, + 30, + 215, + 221, + 108, + 243, + 161, + 222, + 146, + 128, + 229, + 161, + 217, + 226, + 154, + 168, + 181, + 68, + 211, + 72, + 84, + 245, + 56, + 161, + 95, + 195, + 232, + 103, + 64, + 156, + 18, + 28, + 174, + 108, + 248, + 64, + 162, + 198, + 23, + 164, + 139, + 88, + 227, + 47, + 158, + 13, + 52, + 25, + 199, + 51, + 82, + 175, + 237, + 246, + 173, + 182, + 44, + 128, + 29, + 230, + 103, + 243, + 130, + 58, + 232, + 104, + 9, + 22, + 77, + 87, + 93, + 26, + 148, + 242, + 249, + 247, + 120, + 3, + 122, + 145, + 38, + 110, + 181, + 108, + 8, + 126, + 0, + 177, + 151, + 132, + 27, + 78, + 97, + 173, + 180, + 73, + 136, + 145, + 175, + 111, + 13, + 3, + 245, + 114, + 94, + 84, + 59, + 33, + 98, + 189, + 143, + 136, + 251, + 120, + 209, + 161, + 3, + 105, + 211, + 103, + 55, + 182, + 7, + 232, + 26, + 8, + 63, + 109, + 210, + 80, + 77, + 214, + 55, + 221, + 200, + 163, + 230, + 5, + 191, + 102, + 175, + 59, + 98, + 172, + 183, + 3, + 126, + 249, + 159, + 214, + 20, + 135, + 60, + 181, + 139, + 55, + 203, + 111, + 169, + 55, + 54, + 148, + 239, + 181, + 86, + 11, + 243, + 200, + 92, + 18, + 75, + 214, + 133, + 129, + 255, + 139, + 157, + 9, + 13, + 51, + 233, + 219, + 182, + 208, + 235, + 188, + 95, + 122, + 179, + 157, + 183, + 66, + 207, + 21, + 184, + 251, + 220, + 156, + 141, + 148, + 182, + 93, + 57, + 118, + 78, + 250, + 78, + 223, + 107, + 11, + 44, + 105, + 44, + 181, + 180, + 131, + 220, + 223, + 92, + 118, + 217, + 238, + 221, + 79, + 101, + 214, + 161, + 1, + 65, + 134, + 91, + 231, + 90, + 132, + 211, + 61, + 126, + 124, + 52, + 151, + 154, + 195, + 224, + 26, + 84, + 252, + 214, + 72, + 82, + 69, + 48, + 15, + 86, + 142, + 204, + 107, + 152, + 179, + 29, + 142, + 52, + 35, + 96, + 189, + 85, + 108, + 11, + 109, + 164, + 58, + 95, + 222, + 141, + 37, + 68, + 238, + 210, + 115, + 129, + 10, + 1, + 164, + 51, + 64, + 11, + 255, + 79, + 51, + 77, + 46, + 202, + 245, + 164, + 107, + 101, + 26, + 131, + 77, + 136, + 254, + 133, + 137, + 68, + 48, + 65, + 142, + 101, + 67, + 63, + 34, + 253, + 47, + 111, + 94, + 166, + 223, + 131, + 99, + 16, + 33, + 159, + 34, + 140, + 134, + 107, + 23, + 42, + 194, + 51, + 71, + 221, + 222, + 4, + 228, + 192, + 118, + 127, + 238, + 202, + 155, + 145, + 236, + 54, + 136, + 71, + 109, + 234, + 181, + 120, + 37, + 160, + 61, + 200, + 182, + 204, + 163, + 246, + 108, + 231, + 105, + 35, + 151, + 61, + 164, + 24, + 1, + 230, + 244, + 223, + 145, + 54, + 164, + 187, + 159, + 17, + 114, + 19, + 104, + 45, + 217, + 102, + 50, + 81, + 114, + 121, + 17, + 0, + 177, + 35, + 251, + 54, + 156, + 43, + 112, + 79, + 95, + 229, + 249, + 153, + 66, + 212, + 20, + 11, + 29, + 242, + 131, + 149, + 242, + 150, + 141, + 197, + 120, + 21, + 174, + 246, + 62, + 180, + 43, + 72, + 218, + 212, + 220, + 162, + 193, + 204, + 39, + 1, + 122, + 3, + 63, + 62, + 79, + 20, + 191, + 96, + 93, + 81, + 137, + 249, + 160, + 166, + 105, + 13, + 248, + 13, + 38, + 237, + 70, + 49, + 96, + 101, + 79, + 87, + 148, + 131, + 53, + 196, + 72, + 8, + 218, + 209, + 237, + 57, + 124, + 227, + 30, + 53, + 134, + 143, + 63, + 23, + 125, + 174, + 96, + 92, + 119, + 190, + 148, + 235, + 71, + 105, + 247, + 208, + 150, + 3, + 153, + 160, + 34, + 6, + 18, + 63, + 156, + 47, + 141, + 146, + 95, + 35, + 92, + 14, + 77, + 246, + 54, + 53, + 52, + 57, + 85, + 128, + 220, + 227, + 52, + 207, + 1, + 232, + 52, + 120, + 181, + 80, + 125, + 127, + 85, + 197, + 206, + 8, + 93, + 163, + 44, + 136, + 27, + 221, + 129, + 229, + 16, + 21, + 24, + 131, + 53, + 226, + 163, + 240, + 243, + 151, + 240, + 17, + 16, + 10, + 59, + 52, + 108, + 137, + 174, + 222, + 107, + 220, + 87, + 12, + 33, + 96, + 184, + 202, + 73, + 24, + 187, + 20, + 171, + 66, + 40, + 130, + 114, + 233, + 211, + 183, + 189, + 12, + 9, + 158, + 8, + 72, + 206, + 138, + 206, + 78, + 50, + 97, + 49, + 88, + 253, + 185, + 110, + 104, + 43, + 112, + 168, + 203, + 111, + 87, + 33, + 116, + 176, + 159, + 58, + 98, + 140, + 77, + 111, + 118, + 205, + 26, + 24, + 1, + 235, + 188, + 48, + 239, + 217, + 219, + 162, + 22, + 224, + 16, + 128, + 4, + 179, + 113, + 226, + 222, + 132, + 104, + 203, + 210, + 27, + 36, + 46, + 119, + 54, + 236, + 171, + 120, + 214, + 131, + 91, + 70, + 97, + 17, + 111, + 132, + 16, + 37, + 120, + 148, + 63, + 254, + 142, + 51, + 20, + 59, + 48, + 169, + 68, + 216, + 137, + 176, + 227, + 130, + 36, + 132, + 33, + 67, + 88, + 94, + 127, + 213, + 45, + 50, + 132, + 177, + 199, + 238, + 14, + 126, + 255, + 145, + 53, + 234, + 193, + 252, + 4, + 248, + 140, + 69, + 183, + 222, + 21, + 6, + 58, + 28, + 140, + 31, + 46, + 81, + 64, + 235, + 82, + 40, + 52, + 71, + 116, + 92, + 26, + 101, + 119, + 26, + 211, + 87, + 224, + 85, + 179, + 66, + 218, + 192, + 176, + 147, + 176, + 56, + 131, + 81, + 197, + 74, + 71, + 199, + 68, + 120, + 19, + 16, + 181, + 11, + 16, + 88, + 177, + 159, + 118, + 172, + 188, + 22, + 149, + 236, + 135, + 201, + 254, + 50, + 171, + 127, + 113, + 235, + 112, + 176, + 106, + 45, + 117, + 63, + 237, + 226, + 226, + 47, + 12, + 77, + 217, + 191, + 20, + 243, + 128, + 123, + 152, + 55, + 176, + 124, + 218, + 66, + 20, + 9, + 69, + 212, + 193, + 108, + 232, + 161, + 18, + 212, + 239, + 98, + 198, + 146, + 46, + 175, + 169, + 231, + 250, + 88, + 122, + 102, + 78, + 144, + 217, + 208, + 244, + 161, + 180, + 159, + 236, + 129, + 41, + 121, + 252, + 9, + 241, + 197, + 127, + 0, + 102, + 1, + 206, + 167, + 220, + 96, + 235, + 136, + 9, + 139, + 4, + 17, + 99, + 216, + 95, + 216, + 1, + 118, + 48, + 223, + 12, + 255, + 171, + 140, + 25, + 231, + 142, + 205, + 68, + 64, + 235, + 124, + 67, + 171, + 43, + 177, + 221, + 146, + 198, + 12, + 42, + 57, + 161, + 22, + 48, + 192, + 56, + 69, + 234, + 168, + 241, + 64, + 99, + 177, + 183, + 241, + 36, + 135, + 216, + 154, + 200, + 6, + 45, + 242, + 10, + 191, + 134, + 137, + 156, + 50, + 206, + 155, + 205, + 13, + 231, + 163, + 217, + 134, + 11, + 228, + 192, + 134, + 212, + 105, + 41, + 135, + 123, + 225, + 202, + 165, + 187, + 80, + 104, + 83, + 117, + 234, + 182, + 21, + 57, + 32, + 175, + 246, + 202, + 135, + 241, + 159, + 193, + 241, + 242, + 116, + 107, + 80, + 149, + 234, + 26, + 137, + 214, + 86, + 117, + 78, + 180, + 95, + 134, + 67, + 182, + 208, + 212, + 201, + 126, + 141, + 180, + 62, + 168, + 222, + 108, + 79, + 178, + 157, + 168, + 216, + 216, + 14, + 112, + 73, + 187, + 23, + 91, + 112, + 72, + 252, + 191, + 159, + 192, + 37, + 195, + 201, + 128, + 32, + 98, + 45, + 164, + 233, + 241, + 183, + 228, + 99, + 230, + 163, + 95, + 13, + 209, + 137, + 134, + 158, + 73, + 121, + 80, + 15, + 120, + 80, + 240, + 153, + 112, + 157, + 215, + 199, + 150, + 180, + 31, + 44, + 209, + 46, + 13, + 12, + 249, + 254, + 142, + 22, + 73, + 165, + 109, + 127, + 165, + 254, + 56, + 28, + 37, + 70, + 132, + 189, + 113, + 29, + 51, + 25, + 97, + 81, + 87, + 47, + 117, + 96, + 92, + 77, + 33, + 25, + 213, + 198, + 208, + 187, + 174, + 151, + 49, + 239, + 58, + 102, + 110, + 140, + 123, + 103, + 20, + 65, + 112, + 171, + 176, + 34, + 162, + 110, + 249, + 113, + 204, + 183, + 112, + 163, + 110, + 89, + 100, + 6, + 167, + 187, + 123, + 215, + 202, + 249, + 203, + 221, + 241, + 65, + 44, + 139, + 214, + 17, + 18, + 237, + 16, + 133, + 148, + 162, + 52, + 206, + 221, + 146, + 205, + 203, + 68, + 99, + 130, + 136, + 107, + 85, + 114, + 158, + 235, + 136, + 189, + 100, + 234, + 82, + 170, + 135, + 220, + 119, + 25, + 188, + 88, + 223, + 202, + 24, + 254, + 80, + 33, + 152, + 219, + 113, + 20, + 229, + 245, + 170, + 152, + 73, + 113, + 121, + 43, + 29, + 130, + 182, + 4, + 6, + 35, + 89, + 118, + 238, + 107, + 147, + 215, + 32, + 67, + 211, + 80, + 6, + 241, + 124, + 49, + 115, + 125, + 156, + 12, + 241, + 56, + 241, + 5, + 87, + 125, + 39, + 21, + 13, + 200, + 160, + 246, + 6, + 251, + 135, + 233, + 192, + 222, + 23, + 101, + 56, + 75, + 42, + 92, + 81, + 110, + 30, + 164, + 24, + 72, + 43, + 209, + 47, + 54, + 9, + 250, + 218, + 75, + 181, + 255, + 111, + 80, + 108, + 38, + 169, + 204, + 254, + 57, + 74, + 224, + 28, + 68, + 128, + 6, + 83, + 192, + 3, + 23, + 106, + 228, + 147, + 110, + 32, + 194, + 182, + 155, + 195, + 86, + 142, + 50, + 126, + 227, + 157, + 36, + 174, + 154, + 210, + 30, + 61, + 89, + 130, + 248, + 139, + 186, + 241, + 104, + 12, + 43, + 110, + 14, + 33, + 36, + 172, + 119, + 91, + 223, + 177, + 68, + 201, + 55, + 156, + 241, + 16, + 177, + 133, + 157, + 104, + 184, + 153, + 240, + 236, + 250, + 147, + 103, + 18, + 135, + 103, + 80, + 73, + 216, + 96, + 151, + 158, + 161, + 251, + 14, + 230, + 21, + 123, + 111, + 172, + 209, + 98, + 110, + 112, + 21, + 185, + 173, + 93, + 91, + 184, + 206, + 138, + 105, + 147, + 158, + 7, + 44, + 0, + 72, + 136, + 7, + 54, + 4, + 248, + 99, + 125, + 158, + 7, + 250, + 112, + 216, + 160, + 148, + 173, + 8, + 194, + 236, + 6, + 131, + 58, + 63, + 84, + 66, + 249, + 240, + 202, + 236, + 15, + 230, + 37, + 98, + 194, + 244, + 222, + 189, + 223, + 117, + 30, + 137, + 3, + 142, + 102, + 15, + 240, + 185, + 229, + 115, + 8, + 170, + 149, + 102, + 80, + 163, + 130, + 185, + 231, + 101, + 55, + 204, + 62, + 5, + 54, + 32, + 239, + 1, + 151, + 234, + 118, + 13, + 154, + 49, + 222, + 50, + 215, + 187, + 20, + 129, + 203, + 155, + 236, + 196, + 73, + 223, + 73, + 183, + 64, + 235, + 129, + 49, + 64, + 225, + 8, + 46, + 182, + 71, + 244, + 206, + 105, + 107, + 95, + 143, + 9, + 25, + 226, + 0, + 102, + 188, + 255, + 255, + 188, + 147, + 61, + 215, + 141, + 183, + 249, + 247, + 62, + 140, + 223, + 179, + 242, + 124, + 205, + 4, + 14, + 8, + 183, + 41, + 214, + 225, + 135, + 164, + 24, + 47, + 166, + 50, + 8, + 163, + 224, + 166, + 222, + 145, + 23, + 169, + 36, + 79, + 251, + 154, + 36, + 117, + 149, + 15, + 246, + 191, + 163, + 252, + 129, + 34, + 25, + 195, + 123, + 42, + 242, + 179, + 67, + 56, + 124, + 107, + 207, + 161, + 156, + 76, + 23, + 56, + 156, + 170, + 37, + 178, + 233, + 139, + 252, + 121, + 213, + 206, + 161, + 182, + 181, + 183, + 221, + 97, + 145, + 248, + 244, + 211, + 9, + 80, + 33, + 215, + 222, + 233, + 164, + 8, + 145, + 121, + 108, + 70, + 26, + 214, + 243, + 57, + 146, + 173, + 244, + 74, + 218, + 166, + 51, + 190, + 74, + 9, + 122, + 76, + 221, + 114, + 88, + 155, + 50, + 135, + 93, + 222, + 147, + 223, + 136, + 194, + 142, + 118, + 175, + 161, + 47, + 3, + 149, + 61, + 42, + 61, + 112, + 98, + 204, + 123, + 81, + 234, + 220, + 193, + 111, + 112, + 160, + 159, + 130, + 243, + 51, + 32, + 161, + 137, + 116, + 84, + 66, + 83, + 18, + 179, + 239, + 142, + 212, + 250, + 235, + 53, + 199, + 215, + 35, + 210, + 48, + 188, + 126, + 145, + 172, + 194, + 186, + 2, + 90, + 223, + 11, + 67, + 254, + 235, + 88, + 14, + 223, + 145, + 223, + 222, + 122, + 52, + 146, + 97, + 25, + 194, + 108, + 169, + 207, + 176, + 69, + 241, + 7, + 53, + 114, + 134, + 40, + 98, + 76, + 67, + 133, + 171, + 194, + 151, + 54, + 63, + 174, + 107, + 119, + 224, + 236, + 98, + 28, + 208, + 219, + 195, + 3, + 186, + 63, + 155, + 186, + 170, + 20, + 29, + 102, + 146, + 11, + 77, + 55, + 167, + 101, + 68, + 128, + 43, + 127, + 236, + 205, + 24, + 143, + 53, + 205, + 234, + 72, + 153, + 30, + 132, + 146, + 20, + 9, + 83, + 179, + 238, + 127, + 254, + 167, + 153, + 109, + 6, + 58, + 160, + 205, + 11, + 150, + 81, + 60, + 14, + 116, + 190, + 157, + 76, + 99, + 75, + 170, + 218, + 186, + 66, + 72, + 102, + 154, + 90, + 53, + 84, + 92, + 228, + 250, + 95, + 64, + 80, + 125, + 231, + 222, + 208, + 46, + 154, + 139, + 59, + 250, + 83, + 85, + 208, + 62, + 219, + 237, + 20, + 184, + 176, + 74, + 226, + 154, + 219, + 51, + 3, + 249, + 79, + 249, + 205, + 132, + 181, + 245, + 105, + 213, + 49, + 253, + 174, + 17, + 3, + 211, + 23, + 23, + 192, + 117, + 168, + 40, + 86, + 199, + 197, + 134, + 205, + 205, + 223, + 246, + 252, + 254, + 140, + 52, + 142, + 74, + 13, + 210, + 5, + 222, + 77, + 118, + 101, + 53, + 223, + 227, + 53, + 198, + 21, + 159, + 62, + 188, + 82, + 122, + 110, + 167, + 172, + 211, + 126, + 241, + 127, + 194, + 32, + 187, + 143, + 211, + 2, + 130, + 250, + 123, + 231, + 53, + 246, + 185, + 186, + 214, + 81, + 104, + 199, + 58, + 89, + 189, + 47, + 76, + 212, + 201, + 42, + 44, + 55, + 83, + 248, + 34, + 18, + 32, + 0, + 96, + 120, + 208, + 175, + 206, + 48, + 250, + 8, + 117, + 141, + 147, + 70, + 44, + 90, + 105, + 131, + 193, + 76, + 132, + 167, + 15, + 23, + 145, + 69, + 226, + 73, + 227, + 252, + 161, + 136, + 156, + 111, + 145, + 224, + 116, + 137, + 26, + 19, + 90, + 134, + 24, + 113, + 74, + 98, + 62, + 71, + 94, + 147, + 90, + 98, + 229, + 171, + 138, + 80, + 54, + 201, + 1, + 204, + 46, + 215, + 109, + 172, + 53, + 174, + 161, + 241, + 105, + 127, + 251, + 3, + 187, + 150, + 42, + 253, + 161, + 224, + 146, + 138, + 60, + 245, + 165, + 61, + 99, + 241, + 95, + 58, + 102, + 132, + 121, + 155, + 93, + 95, + 60, + 18, + 100, + 55, + 15, + 133, + 23, + 166, + 65, + 120, + 113, + 240, + 192, + 43, + 48, + 72, + 130, + 228, + 62, + 44, + 195, + 82, + 19, + 89, + 34, + 202, + 93, + 250, + 147, + 108, + 104, + 12, + 106, + 59, + 195, + 31, + 120, + 21, + 109, + 28, + 63, + 190, + 191, + 215, + 43, + 247, + 86, + 103, + 117, + 170, + 189, + 246, + 175, + 55, + 133, + 48, + 210, + 171, + 171, + 113, + 76, + 231, + 157, + 5, + 150, + 33, + 184, + 174, + 52, + 88, + 150, + 236, + 44, + 73, + 28, + 255, + 100, + 96, + 119, + 164, + 11, + 234, + 125, + 121, + 119, + 100, + 233, + 10, + 229, + 75, + 224, + 50, + 238, + 35, + 200, + 76, + 160, + 185, + 245, + 12, + 110, + 105, + 242, + 132, + 65, + 59, + 154, + 65, + 131, + 149, + 102, + 201, + 186, + 156, + 35, + 28, + 219, + 42, + 67, + 193, + 99, + 222, + 160, + 243, + 145, + 253, + 92, + 82, + 3, + 225, + 51, + 240, + 61, + 69, + 2, + 33, + 223, + 36, + 168, + 172, + 206, + 59, + 185, + 51, + 164, + 238, + 170, + 99, + 177, + 110, + 93, + 193, + 122, + 15, + 0, + 86, + 231, + 83, + 99, + 65, + 11, + 163, + 239, + 47, + 237, + 90, + 111, + 160, + 99, + 199, + 154, + 14, + 135, + 116, + 253, + 83, + 32, + 47, + 167, + 86, + 19, + 39, + 234, + 174, + 6, + 95, + 8, + 100, + 109, + 39, + 209, + 11, + 3, + 17, + 21, + 14, + 154, + 82, + 158, + 123, + 118, + 22, + 213, + 219, + 229, + 110, + 46, + 124, + 87, + 154, + 100, + 69, + 78, + 77, + 22, + 116, + 135, + 83, + 220, + 37, + 13, + 63, + 241, + 100, + 22, + 51, + 144, + 31, + 58, + 104, + 143, + 189, + 56, + 21, + 155, + 49, + 112, + 79, + 79, + 52, + 17, + 191, + 198, + 242, + 209, + 65, + 65, + 185, + 84, + 228, + 59, + 247, + 214, + 253, + 169, + 148, + 156, + 65, + 39, + 95, + 253, + 167, + 14, + 37, + 143, + 81, + 213, + 42, + 111, + 125, + 67, + 185, + 83, + 190, + 183, + 80, + 27, + 99, + 195, + 247, + 212, + 207, + 246, + 177, + 77, + 143, + 115, + 254, + 43, + 49, + 86, + 83, + 95, + 146, + 166, + 9, + 98, + 225, + 212, + 240, + 158, + 91, + 13, + 218, + 68, + 35, + 245, + 219, + 208, + 90, + 126, + 10, + 216, + 227, + 200, + 201, + 176, + 43, + 127, + 139, + 10, + 72, + 176, + 169, + 29, + 5, + 6, + 218, + 24, + 245, + 144, + 112, + 217, + 91, + 104, + 175, + 110, + 207, + 17, + 132, + 60, + 91, + 108, + 47, + 241, + 208, + 10, + 12, + 16, + 182, + 221, + 247, + 128, + 151, + 240, + 225, + 46, + 14, + 182, + 31, + 101, + 181, + 248, + 180, + 195, + 146, + 195, + 103, + 110, + 244, + 114, + 177, + 215, + 85, + 30, + 186, + 111, + 197, + 207, + 117, + 29, + 59, + 240, + 206, + 251, + 6, + 94, + 97, + 117, + 214, + 136, + 223, + 168, + 209, + 84, + 190, + 165, + 26, + 98, + 62, + 2, + 202, + 59, + 253, + 165, + 112, + 64, + 155, + 155, + 83, + 158, + 60, + 34, + 129, + 125, + 200, + 163, + 119, + 68, + 34, + 112, + 235, + 208, + 235, + 41, + 242, + 167, + 12, + 173, + 181, + 240, + 22, + 5, + 49, + 104, + 153, + 182, + 92, + 112, + 57, + 224, + 148, + 67, + 46, + 29, + 27, + 182, + 37, + 54, + 141, + 172, + 214, + 153, + 3, + 58, + 49, + 23, + 11, + 199, + 110, + 221, + 189, + 34, + 93, + 82, + 95, + 230, + 195, + 168, + 30, + 250, + 163, + 103, + 199, + 247, + 181, + 148, + 155, + 144, + 67, + 60, + 151, + 159, + 157, + 248, + 227, + 61, + 47, + 14, + 176, + 217, + 212, + 97, + 46, + 2, + 160, + 229, + 173, + 127, + 207, + 127, + 76, + 229, + 181, + 12, + 198, + 119, + 111, + 160, + 71, + 115, + 101, + 235, + 229, + 232, + 108, + 223, + 156, + 102, + 81, + 59, + 89, + 254, + 230, + 167, + 140, + 170, + 194, + 247, + 101, + 105, + 114, + 193, + 48, + 54, + 42, + 25, + 120, + 140, + 106, + 158, + 113, + 2, + 214, + 240, + 79, + 65, + 228, + 36, + 128, + 132, + 88, + 90, + 188, + 91, + 76, + 169, + 93, + 156, + 10, + 197, + 154, + 123, + 68, + 174, + 67, + 0, + 206, + 191, + 37, + 92, + 39, + 160, + 15, + 221, + 47, + 113, + 241, + 147, + 111, + 123, + 82, + 68, + 69, + 241, + 169, + 41, + 168, + 92, + 81, + 235, + 226, + 126, + 35, + 79, + 134, + 123, + 42, + 136, + 81, + 80, + 190, + 107, + 96, + 115, + 58, + 66, + 150, + 23, + 126, + 132, + 119, + 50, + 109, + 92, + 121, + 221, + 186, + 72, + 211, + 255, + 201, + 167, + 14, + 189, + 231, + 214, + 109, + 74, + 0, + 165, + 102, + 133, + 62, + 243, + 210, + 229, + 107, + 61, + 176, + 237, + 121, + 234, + 82, + 125, + 42, + 171, + 247, + 116, + 34, + 20, + 48, + 182, + 212, + 157, + 28, + 0, + 252, + 42, + 188, + 104, + 13, + 40, + 26, + 164, + 135, + 148, + 250, + 52, + 41, + 230, + 17, + 199, + 165, + 51, + 23, + 230, + 65, + 85, + 123, + 217, + 28, + 9, + 158, + 19, + 72, + 69, + 3, + 139, + 190, + 231, + 96, + 242, + 30, + 51, + 40, + 67, + 228, + 106, + 201, + 169, + 69, + 229, + 233, + 190, + 132, + 94, + 132, + 104, + 235, + 139, + 107, + 120, + 194, + 141, + 230, + 0, + 220, + 91, + 180, + 69, + 71, + 45, + 174, + 143, + 82, + 63, + 167, + 32, + 51, + 153, + 219, + 15, + 178, + 25, + 46, + 138, + 118, + 158, + 178, + 201, + 116, + 136, + 97, + 106, + 238, + 106, + 235, + 17, + 55, + 190, + 127, + 57, + 5, + 236, + 186, + 249, + 41, + 144, + 155, + 157, + 170, + 29, + 194, + 248, + 204, + 25, + 182, + 175, + 144, + 183, + 187, + 222, + 52, + 187, + 127, + 64, + 115, + 56, + 228, + 134, + 197, + 241, + 22, + 240, + 85, + 135, + 152, + 157, + 93, + 236, + 162, + 161, + 229, + 177, + 152, + 81, + 50, + 67, + 89, + 106, + 86, + 17, + 113, + 195, + 168, + 116, + 202, + 250, + 106, + 65, + 170, + 92, + 90, + 46, + 49, + 110, + 175, + 21, + 121, + 185, + 60, + 244, + 56, + 254, + 150, + 107, + 255, + 174, + 214, + 34, + 96, + 238, + 233, + 22, + 130, + 211, + 160, + 223, + 49, + 59, + 104, + 80, + 240, + 24, + 137, + 114, + 118, + 191, + 64, + 214, + 130, + 94, + 88, + 33, + 134, + 223, + 158, + 77, + 150, + 8, + 174, + 71, + 176, + 105, + 139, + 42, + 168, + 143, + 239, + 198, + 241, + 216, + 137, + 45, + 196, + 230, + 214, + 66, + 99, + 235, + 72, + 238, + 146, + 106, + 95, + 75, + 242, + 23, + 55, + 175, + 22, + 190, + 107, + 138, + 199, + 11, + 118, + 252, + 22, + 89, + 127, + 159, + 196, + 19, + 76, + 50, + 207, + 65, + 131, + 62, + 246, + 3, + 85, + 65, + 249, + 134, + 103, + 189, + 11, + 131, + 111, + 186, + 77, + 221, + 78, + 47, + 139, + 156, + 217, + 98, + 213, + 107, + 147, + 156, + 203, + 33, + 131, + 174, + 244, + 39, + 228, + 204, + 200, + 222, + 55, + 66, + 46, + 184, + 9, + 255, + 251, + 248, + 213, + 70, + 195, + 97, + 188, + 154, + 52, + 152, + 89, + 45, + 116, + 194, + 89, + 213, + 83, + 133, + 88, + 238, + 193, + 117, + 217, + 42, + 122, + 227, + 233, + 3, + 64, + 38, + 49, + 115, + 40, + 91, + 210, + 120, + 6, + 199, + 116, + 19, + 195, + 122, + 189, + 110, + 214, + 251, + 174, + 115, + 90, + 96, + 150, + 169, + 81, + 8, + 42, + 16, + 152, + 190, + 35, + 25, + 146, + 83, + 92, + 200, + 99, + 165, + 43, + 222, + 87, + 247, + 204, + 149, + 214, + 135, + 184, + 251, + 195, + 48, + 147, + 188, + 26, + 37, + 170, + 247, + 212, + 162, + 100, + 220, + 57, + 64, + 207, + 150, + 192, + 167, + 73, + 206, + 102, + 104, + 180, + 82, + 63, + 176, + 11, + 71, + 92, + 37, + 191, + 211, + 34, + 124, + 252, + 36, + 127, + 95, + 89, + 166, + 254, + 71, + 95, + 108, + 179, + 39, + 156, + 115, + 122, + 114, + 47, + 81, + 235, + 150, + 39, + 48, + 238, + 16, + 24, + 31, + 146, + 240, + 43, + 78, + 185, + 96, + 66, + 242, + 30, + 82, + 72, + 155, + 68, + 87, + 58, + 178, + 2, + 254, + 130, + 21, + 238, + 163, + 48, + 200, + 223, + 133, + 136, + 84, + 2, + 182, + 225, + 108, + 2, + 225, + 74, + 14, + 182, + 161, + 128, + 72, + 70, + 182, + 233, + 83, + 57, + 212, + 233, + 42, + 82, + 149, + 62, + 209, + 198, + 65, + 113, + 150, + 174, + 145, + 162, + 104, + 224, + 66, + 68, + 130, + 186, + 186, + 125, + 167, + 122, + 106, + 216, + 119, + 224, + 92, + 147, + 17, + 116, + 73, + 127, + 249, + 86, + 181, + 218, + 50, + 33, + 72, + 48, + 252, + 112, + 184, + 97, + 194, + 7, + 95, + 97, + 169, + 53, + 223, + 251, + 144, + 233, + 124, + 160, + 226, + 14, + 61, + 38, + 117, + 233, + 60, + 154, + 233, + 72, + 106, + 109, + 127, + 219, + 17, + 2, + 7, + 199, + 74, + 147, + 8, + 159, + 203, + 39, + 60, + 0, + 134, + 13, + 186, + 129, + 226, + 246, + 223, + 98, + 95, + 91, + 9, + 130, + 224, + 203, + 147, + 147, + 102, + 66, + 155, + 23, + 181, + 92, + 87, + 244, + 121, + 55, + 242, + 230, + 1, + 178, + 106, + 173, + 58, + 36, + 170, + 223, + 126, + 42, + 224, + 153, + 40, + 17, + 132, + 137, + 248, + 167, + 160, + 205, + 143, + 19, + 224, + 245, + 238, + 57, + 20, + 214, + 160, + 232, + 234, + 210, + 77, + 116, + 174, + 89, + 177, + 17, + 252, + 34, + 171, + 37, + 196, + 157, + 222, + 43, + 59, + 153, + 20, + 132, + 183, + 206, + 98, + 71, + 56, + 61, + 141, + 14, + 127, + 138, + 57, + 230, + 214, + 253, + 245, + 69, + 151, + 158, + 40, + 205, + 76, + 110, + 89, + 24, + 215, + 1, + 218, + 56, + 25, + 65, + 27, + 238, + 77, + 90, + 31, + 139, + 191, + 79, + 88, + 102, + 88, + 176, + 196, + 77, + 165, + 229, + 69, + 231, + 113, + 202, + 77, + 195, + 194, + 63, + 107, + 101, + 22, + 4, + 190, + 162, + 223, + 111, + 162, + 27, + 238, + 119, + 193, + 16, + 75, + 254, + 133, + 10, + 147, + 142, + 252, + 38, + 62, + 230, + 200, + 116, + 192, + 208, + 159, + 236, + 220, + 52, + 69, + 64, + 189, + 211, + 132, + 74, + 124, + 186, + 236, + 152, + 129, + 86, + 150, + 230, + 211, + 217, + 161, + 41, + 172, + 101, + 161, + 88, + 227, + 27, + 164, + 54, + 120, + 193, + 249, + 141, + 110, + 188, + 100, + 221, + 86, + 43, + 105, + 124, + 143, + 4, + 185, + 79, + 79, + 0, + 208, + 223, + 117, + 157, + 44, + 13, + 157, + 39, + 74, + 143, + 219, + 18, + 39, + 185, + 160, + 183, + 55, + 113, + 33, + 5, + 148, + 224, + 254, + 44, + 37, + 68, + 116, + 157, + 205, + 122, + 97, + 145, + 189, + 99, + 206, + 176, + 2, + 65, + 101, + 187, + 255, + 67, + 29, + 60, + 110, + 171, + 163, + 124, + 65, + 31, + 67, + 137, + 197, + 43, + 129, + 139, + 53, + 227, + 15, + 148, + 151, + 195, + 58, + 224, + 104, + 91, + 16, + 104, + 38, + 101, + 180, + 197, + 177, + 78, + 72, + 40, + 217, + 88, + 92, + 148, + 33, + 116, + 129, + 99, + 109, + 57, + 237, + 201, + 48, + 150, + 188, + 111, + 26, + 117, + 198, + 126, + 188, + 129, + 166, + 32, + 203, + 108, + 76, + 39, + 129, + 17, + 35, + 219, + 47, + 2, + 188, + 185, + 62, + 210, + 65, + 230, + 116, + 122, + 160, + 253, + 21, + 245, + 152, + 43, + 76, + 64, + 93, + 44, + 2, + 139, + 16, + 188, + 172, + 22, + 210, + 158, + 19, + 53, + 226, + 39, + 86, + 226, + 2, + 237, + 2, + 20, + 245, + 110, + 9, + 232, + 163, + 215, + 83, + 177, + 0, + 236, + 149, + 70, + 19, + 138, + 193, + 194, + 20, + 215, + 120, + 61, + 168, + 202, + 19, + 178, + 228, + 153, + 58, + 34, + 144, + 27, + 113, + 62, + 253, + 33, + 187, + 154, + 142, + 241, + 40, + 220, + 33, + 26, + 177, + 2, + 32, + 76, + 173, + 88, + 71, + 167, + 128, + 13, + 252, + 233, + 179, + 125, + 4, + 118, + 182, + 41, + 173, + 41, + 187, + 215, + 101, + 230, + 81, + 120, + 102, + 19, + 146, + 44, + 8, + 163, + 225, + 37, + 102, + 158, + 217, + 58, + 22, + 226, + 108, + 67, + 112, + 36, + 193, + 93, + 43, + 142, + 237, + 63, + 72, + 25, + 203, + 180, + 40, + 119, + 220, + 39, + 68, + 232, + 72, + 75, + 214, + 193, + 152, + 115, + 14, + 116, + 11, + 71, + 75, + 245, + 254, + 63, + 132, + 30, + 143, + 208, + 126, + 56, + 94, + 80, + 146, + 39, + 20, + 225, + 70, + 37, + 113, + 202, + 44, + 76, + 83, + 40, + 35, + 231, + 84, + 78, + 208, + 249, + 32, + 107, + 114, + 71, + 132, + 18, + 131, + 15, + 5, + 180, + 21, + 10, + 231, + 130, + 240, + 145, + 174, + 43, + 152, + 88, + 31, + 18, + 20, + 59, + 93, + 251, + 131, + 197, + 93, + 79, + 176, + 55, + 11, + 215, + 50, + 143, + 218, + 90, + 43, + 221, + 16, + 185, + 234, + 83, + 21, + 96, + 93, + 236, + 219, + 78, + 195, + 34, + 101, + 55, + 117, + 74, + 126, + 194, + 39, + 244, + 22, + 145, + 104, + 233, + 221, + 227, + 198, + 227, + 176, + 82, + 139, + 185, + 219, + 9, + 148, + 207, + 120, + 220, + 95, + 176, + 113, + 35, + 205, + 13, + 61, + 166, + 83, + 16, + 2, + 191, + 136, + 55, + 103, + 32, + 188, + 88, + 73, + 242, + 21, + 108, + 47, + 70, + 1, + 228, + 255, + 82, + 112, + 241, + 106, + 65, + 255, + 30, + 118, + 21, + 194, + 253, + 162, + 234, + 97, + 153, + 120, + 254, + 218, + 129, + 49, + 202, + 176, + 112, + 187, + 250, + 212, + 58, + 197, + 2, + 16, + 93, + 227, + 150, + 250, + 125, + 159, + 199, + 231, + 72, + 67, + 248, + 130, + 196, + 71, + 124, + 230, + 54, + 4, + 228, + 43, + 63, + 209, + 86, + 195, + 223, + 224, + 220, + 252, + 33, + 172, + 23, + 234, + 143, + 56, + 226, + 34, + 180, + 31, + 238, + 39, + 61, + 10, + 237, + 68, + 186, + 105, + 195, + 164, + 59, + 161, + 89, + 6, + 206, + 96, + 223, + 177, + 179, + 22, + 20, + 252, + 164, + 64, + 12, + 107, + 92, + 94, + 79, + 175, + 15, + 149, + 79, + 9, + 5, + 1, + 44, + 246, + 223, + 50, + 244, + 100, + 219, + 139, + 68, + 43, + 16, + 171, + 151, + 90, + 108, + 39, + 211, + 223, + 236, + 52, + 29, + 164, + 34, + 226, + 34, + 140, + 211, + 61, + 20, + 219, + 106, + 181, + 79, + 200, + 100, + 95, + 110, + 16, + 43, + 107, + 115, + 58, + 58, + 11, + 241, + 62, + 146, + 44, + 232, + 21, + 60, + 160, + 83, + 172, + 126, + 22, + 122, + 105, + 161, + 140, + 76, + 214, + 203, + 35, + 38, + 32, + 94, + 251, + 170, + 70, + 116, + 250, + 147, + 30, + 236, + 27, + 77, + 128, + 233, + 70, + 164, + 249, + 141, + 65, + 48, + 213, + 84, + 137, + 131, + 162, + 39, + 247, + 1, + 194, + 230, + 186, + 121, + 184, + 158, + 10, + 148, + 109, + 75, + 168, + 48, + 145, + 241, + 166, + 68, + 25, + 68, + 25, + 129, + 42, + 185, + 63, + 75, + 125, + 237, + 36, + 189, + 240, + 212, + 27, + 50, + 184, + 213, + 189, + 130, + 79, + 224, + 119, + 16, + 151, + 158, + 168, + 213, + 226, + 56, + 166, + 91, + 193, + 145, + 138, + 117, + 81, + 239, + 74, + 41, + 36, + 52, + 243, + 44, + 240, + 156, + 151, + 45, + 147, + 27, + 228, + 198, + 58, + 127, + 119, + 147, + 228, + 13, + 4, + 227, + 102, + 174, + 136, + 62, + 33, + 235, + 154, + 22, + 91, + 108, + 217, + 81, + 10, + 225, + 237, + 198, + 101, + 138, + 244, + 247, + 116, + 143, + 7, + 101, + 204, + 143, + 25, + 86, + 242, + 2, + 229, + 123, + 132, + 233, + 131, + 119, + 227, + 224, + 18, + 104, + 196, + 241, + 247, + 28, + 42, + 137, + 104, + 116, + 183, + 157, + 187, + 214, + 101, + 224, + 78, + 212, + 45, + 1, + 234, + 157, + 225, + 55, + 159, + 117, + 125, + 138, + 8, + 2, + 64, + 11, + 94, + 77, + 198, + 98, + 97, + 110, + 139, + 234, + 237, + 230, + 22, + 193, + 194, + 204, + 61, + 90, + 153, + 227, + 170, + 49, + 161, + 98, + 163, + 198, + 190, + 76, + 160, + 90, + 28, + 14, + 221, + 225, + 2, + 110, + 18, + 193, + 9, + 78, + 105, + 250, + 59, + 204, + 5, + 97, + 26, + 104, + 43, + 233, + 49, + 1, + 104, + 65, + 165, + 84, + 139, + 115, + 116, + 168, + 76, + 155, + 81, + 137, + 240, + 208, + 31, + 190, + 149, + 37, + 64, + 78, + 48, + 69, + 173, + 109, + 64, + 25, + 227, + 177, + 134, + 129, + 126, + 53, + 21, + 214, + 4, + 5, + 8, + 222, + 76, + 205, + 43, + 47, + 233, + 98, + 29, + 33, + 50, + 19, + 117, + 88, + 211, + 42, + 117, + 149, + 149, + 75, + 216, + 82, + 191, + 243, + 188, + 110, + 197, + 51, + 68, + 171, + 238, + 156, + 5, + 172, + 25, + 209, + 186, + 91, + 157, + 208, + 106, + 139, + 191, + 88, + 50, + 152, + 51, + 53, + 213, + 146, + 128, + 116, + 40, + 23, + 32, + 90, + 176, + 7, + 247, + 246, + 149, + 138, + 82, + 16, + 184, + 52, + 56, + 154, + 49, + 18, + 25, + 229, + 78, + 188, + 9, + 28, + 186, + 56, + 141, + 70, + 215, + 244, + 239, + 64, + 80, + 18, + 39, + 92, + 69, + 195, + 236, + 96, + 209, + 154, + 194, + 24, + 132, + 170, + 122, + 177, + 36, + 134, + 112, + 35, + 25, + 243, + 121, + 244, + 245, + 150, + 147, + 24, + 148, + 249, + 192, + 102, + 68, + 36, + 89, + 27, + 170, + 131, + 231, + 33, + 236, + 235, + 5, + 245, + 34, + 133, + 50, + 42, + 63, + 216, + 222, + 186, + 7, + 207, + 148, + 201, + 132, + 9, + 108, + 91, + 12, + 131, + 18, + 239, + 209, + 232, + 119, + 142, + 38, + 176, + 213, + 210, + 112, + 25, + 158, + 37, + 209, + 44, + 199, + 242, + 69, + 174, + 244, + 181, + 213, + 34, + 24, + 2, + 222, + 34, + 76, + 110, + 141, + 148, + 112, + 116, + 129, + 102, + 252, + 110, + 161, + 47, + 208, + 27, + 56, + 57, + 130, + 221, + 182, + 20, + 120, + 227, + 149, + 239, + 94, + 185, + 168, + 187, + 11, + 220, + 208, + 195, + 92, + 70, + 238, + 222, + 20, + 96, + 24, + 173, + 202, + 232, + 126, + 147, + 98, + 230, + 192, + 215, + 157, + 161, + 132, + 208, + 235, + 147, + 136, + 125, + 13, + 173, + 96, + 208, + 75, + 14, + 56, + 103, + 61, + 66, + 9, + 219, + 120, + 1, + 219, + 240, + 78, + 45, + 134, + 245, + 112, + 3, + 96, + 56, + 93, + 181, + 35, + 196, + 175, + 202, + 111, + 178, + 146, + 250, + 224, + 192, + 120, + 198, + 246, + 31, + 163, + 115, + 177, + 2, + 91, + 82, + 122, + 52, + 73, + 41, + 73, + 226, + 80, + 226, + 10, + 97, + 236, + 150, + 229, + 108, + 153, + 246, + 230, + 176, + 73, + 16, + 26, + 79, + 192, + 200, + 14, + 193, + 124, + 78, + 222, + 15, + 185, + 158, + 146, + 162, + 105, + 173, + 158, + 91, + 254, + 127, + 173, + 176, + 210, + 147, + 93, + 165, + 48, + 131, + 26, + 47, + 190, + 102, + 240, + 115, + 168, + 92, + 41, + 11, + 148, + 76, + 50, + 250, + 161, + 124, + 197, + 174, + 24, + 235, + 119, + 162, + 145, + 189, + 109, + 90, + 135, + 119, + 12, + 158, + 174, + 63, + 44, + 151, + 97, + 116, + 47, + 82, + 60, + 87, + 140, + 69, + 63, + 61, + 78, + 100, + 244, + 136, + 152, + 42, + 54, + 210, + 8, + 8, + 219, + 240, + 185, + 140, + 253, + 251, + 237, + 170, + 207, + 110, + 211, + 31, + 206, + 138, + 115, + 164, + 64, + 145, + 247, + 203, + 202, + 81, + 100, + 87, + 196, + 134, + 21, + 250, + 171, + 233, + 120, + 20, + 83, + 229, + 100, + 102, + 120, + 224, + 230, + 169, + 66, + 82, + 99, + 14, + 59, + 167, + 170, + 7, + 30, + 16, + 36, + 149, + 61, + 52, + 77, + 66, + 243, + 11, + 162, + 32, + 253, + 131, + 8, + 112, + 38, + 116, + 156, + 230, + 155, + 39, + 155, + 117, + 103, + 162, + 133, + 35, + 134, + 155, + 251, + 143, + 84, + 46, + 29, + 138, + 221, + 72, + 190, + 95, + 174, + 68, + 22, + 100, + 245, + 187, + 193, + 53, + 213, + 108, + 65, + 243, + 116, + 206, + 140, + 36, + 48, + 186, + 49, + 59, + 170, + 150, + 237, + 33, + 31, + 36, + 192, + 227, + 216, + 66, + 87, + 77, + 79, + 109, + 102, + 186, + 88, + 177, + 56, + 11, + 4, + 168, + 181, + 205, + 235, + 124, + 14, + 67, + 212, + 240, + 167, + 124, + 20, + 24, + 76, + 124, + 131, + 197, + 32, + 29, + 222, + 84, + 2, + 132, + 66, + 40, + 58, + 115, + 228, + 193, + 233, + 69, + 129, + 50, + 94, + 175, + 250, + 192, + 235, + 189, + 164, + 20, + 116, + 36, + 95, + 53, + 213, + 227, + 188, + 80, + 236, + 11, + 161, + 45, + 237, + 219, + 228, + 35, + 221, + 187, + 2, + 32, + 168, + 50, + 68, + 245, + 48, + 117, + 185, + 179, + 240, + 195, + 7, + 167, + 188, + 245, + 194, + 8, + 87, + 127, + 36, + 222, + 0, + 78, + 121, + 34, + 109, + 153, + 163, + 242, + 168, + 141, + 26, + 50, + 79, + 203, + 35, + 62, + 3, + 176, + 100, + 103, + 5, + 230, + 50, + 3, + 49, + 158, + 49, + 24, + 117, + 1, + 14, + 78, + 142, + 162, + 255, + 36, + 21, + 120, + 102, + 196, + 75, + 165, + 235, + 254, + 94, + 168, + 130, + 242, + 245, + 131, + 150, + 55, + 40, + 93, + 213, + 249, + 169, + 78, + 55, + 102, + 165, + 70, + 15, + 226, + 17, + 147, + 78, + 24, + 96, + 17, + 84, + 33, + 6, + 213, + 110, + 130, + 247, + 23, + 30, + 42, + 67, + 83, + 43, + 70, + 117, + 219, + 53, + 221, + 160, + 155, + 54, + 7, + 206, + 4, + 92, + 12, + 120, + 40, + 48, + 80, + 114, + 250, + 45, + 182, + 216, + 158, + 51, + 114, + 173, + 37, + 225, + 164, + 174, + 8, + 228, + 91, + 111, + 227, + 242, + 60, + 126, + 6, + 69, + 18, + 30, + 77, + 74, + 23, + 169, + 37, + 37, + 6, + 154, + 203, + 103, + 122, + 129, + 58, + 237, + 38, + 79, + 190, + 103, + 189, + 93, + 209, + 168, + 4, + 64, + 122, + 162, + 107, + 165, + 38, + 106, + 207, + 9, + 152, + 159, + 70, + 162, + 226, + 135, + 29, + 218, + 160, + 250, + 9, + 71, + 224, + 137, + 227, + 235, + 66, + 45, + 102, + 43, + 226, + 255, + 38, + 5, + 75, + 119, + 29, + 161, + 208, + 250, + 128, + 23, + 222, + 239, + 249, + 162, + 233, + 50, + 13, + 165, + 166, + 223, + 40, + 237, + 169, + 255, + 35, + 100, + 49, + 34, + 190, + 175, + 53, + 147, + 215, + 108, + 40, + 240, + 226, + 166, + 227, + 14, + 234, + 110, + 1, + 33, + 142, + 69, + 247, + 128, + 17, + 19, + 158, + 44, + 180, + 185, + 157, + 132, + 68, + 32, + 116, + 79, + 201, + 177, + 48, + 248, + 18, + 254, + 234, + 217, + 199, + 221, + 122, + 96, + 122, + 144, + 255, + 233, + 116, + 82, + 110, + 66, + 27, + 176, + 45, + 215, + 11, + 168, + 49, + 37, + 102, + 43, + 4, + 166, + 121, + 211, + 108, + 70, + 24, + 201, + 234, + 86, + 159, + 159, + 16, + 207, + 180, + 78, + 97, + 137, + 201, + 162, + 48, + 255, + 32, + 59, + 218, + 155, + 227, + 164, + 165, + 58, + 140, + 125, + 231, + 164, + 202, + 194, + 173, + 170, + 118, + 14, + 39, + 116, + 8, + 172, + 159, + 252, + 22, + 187, + 124, + 103, + 28, + 9, + 109, + 127, + 29, + 219, + 11, + 139, + 168, + 216, + 108, + 222, + 99, + 186, + 114, + 2, + 228, + 78, + 114, + 130, + 187, + 47, + 99, + 183, + 165, + 190, + 121, + 40, + 250, + 15, + 57, + 104, + 189, + 254, + 253, + 85, + 92, + 45, + 127, + 130, + 82, + 202, + 73, + 184, + 244, + 236, + 75, + 138, + 133, + 148, + 96, + 189, + 0, + 143, + 28, + 58, + 74, + 102, + 178, + 168, + 148, + 211, + 255, + 77, + 182, + 238, + 231, + 71, + 74, + 165, + 124, + 96, + 66, + 71, + 119, + 4, + 72, + 49, + 141, + 187, + 48, + 126, + 209, + 86, + 118, + 9, + 160, + 31, + 92, + 137, + 19, + 192, + 151, + 33, + 230, + 239, + 199, + 201, + 24, + 152, + 13, + 54, + 71, + 42, + 84, + 221, + 162, + 142, + 188, + 6, + 136, + 157, + 131, + 130, + 158, + 231, + 127, + 1, + 245, + 103, + 127, + 0, + 183, + 23, + 27, + 125, + 121, + 234, + 42, + 255, + 57, + 182, + 59, + 101, + 200, + 191, + 97, + 16, + 130, + 37, + 240, + 181, + 136, + 81, + 58, + 165, + 110, + 187, + 119, + 123, + 142, + 73, + 196, + 212, + 18, + 32, + 254, + 111, + 127, + 57, + 49, + 226, + 158, + 95, + 4, + 7, + 190, + 157, + 248, + 21, + 44, + 192, + 158, + 95, + 246, + 178, + 200, + 108, + 168, + 196, + 58, + 4, + 253, + 156, + 102, + 199, + 218, + 14, + 9, + 86, + 201, + 149, + 15, + 7, + 97, + 35, + 14, + 168, + 53, + 252, + 46, + 18, + 158, + 245, + 177, + 66, + 226, + 46, + 103, + 54, + 52, + 161, + 24, + 124, + 28, + 79, + 40, + 122, + 102, + 157, + 78, + 98, + 174, + 62, + 69, + 251, + 108, + 44, + 27, + 9, + 63, + 57, + 245, + 193, + 45, + 255, + 180, + 149, + 29, + 87, + 127, + 192, + 244, + 233, + 118, + 76, + 52, + 187, + 193, + 33, + 5, + 160, + 74, + 150, + 194, + 75, + 75, + 94, + 114, + 134, + 105, + 130, + 253, + 49, + 188, + 62, + 81, + 5, + 25, + 105, + 47, + 146, + 104, + 174, + 86, + 63, + 81, + 118, + 9, + 94, + 181, + 43, + 87, + 1, + 155, + 122, + 5, + 206, + 31, + 185, + 49, + 159, + 2, + 225, + 3, + 176, + 50, + 155, + 28, + 129, + 114, + 169, + 244, + 57, + 60, + 125, + 104, + 96, + 119, + 172, + 228, + 203, + 107, + 45, + 14, + 105, + 156, + 137, + 18, + 190, + 154, + 172, + 35, + 223, + 27, + 221, + 115, + 174, + 35, + 224, + 100, + 98, + 133, + 172, + 94, + 208, + 227, + 102, + 179, + 146, + 103, + 41, + 171, + 147, + 40, + 79, + 236, + 0, + 147, + 44, + 116, + 53, + 103, + 137, + 225, + 17, + 6, + 248, + 6, + 89, + 80, + 229, + 41, + 243, + 101, + 254, + 231, + 41, + 98, + 122, + 5, + 37, + 96, + 225, + 233, + 40, + 118, + 252, + 160, + 238, + 182, + 195, + 184, + 69, + 48, + 255, + 228, + 129, + 3, + 150, + 84, + 98, + 87, + 61, + 190, + 173, + 226, + 23, + 28, + 135, + 1, + 75, + 193, + 38, + 188, + 210, + 77, + 241, + 88, + 12, + 121, + 99, + 34, + 57, + 219, + 208, + 247, + 150, + 193, + 234, + 25, + 251, + 247, + 28, + 96, + 60, + 38, + 89, + 32, + 82, + 248, + 125, + 44, + 131, + 111, + 212, + 164, + 8, + 35, + 216, + 187, + 119, + 162, + 206, + 191, + 129, + 134, + 163, + 254, + 91, + 247, + 97, + 12, + 249, + 212, + 27, + 121, + 163, + 240, + 156, + 15, + 203, + 230, + 107, + 123, + 56, + 250, + 66, + 37, + 83, + 230, + 208, + 168, + 21, + 227, + 7, + 18, + 254, + 239, + 22, + 103, + 203, + 7, + 34, + 3, + 16, + 66, + 62, + 137, + 240, + 66, + 60, + 227, + 139, + 164, + 115, + 63, + 184, + 171, + 64, + 124, + 57, + 75, + 131, + 100, + 222, + 97, + 222, + 67, + 191, + 173, + 250, + 159, + 69, + 184, + 203, + 14, + 76, + 72, + 85, + 145, + 3, + 179, + 182, + 20, + 197, + 142, + 155, + 24, + 14, + 127, + 213, + 121, + 38, + 84, + 51, + 220, + 55, + 116, + 112, + 255, + 219, + 195, + 108, + 42, + 129, + 151, + 126, + 91, + 109, + 85, + 246, + 16, + 135, + 177, + 188, + 157, + 111, + 43, + 161, + 38, + 7, + 153, + 193, + 190, + 227, + 168, + 193, + 117, + 23, + 254, + 203, + 41, + 129, + 161, + 163, + 20, + 27, + 188, + 224, + 17, + 101, + 41, + 157, + 205, + 118, + 180, + 122, + 39, + 114, + 157, + 145, + 221, + 205, + 37, + 169, + 71, + 86, + 196, + 200, + 41, + 95, + 51, + 70, + 45, + 86, + 246, + 58, + 16, + 192, + 65, + 151, + 24, + 87, + 201, + 2, + 126, + 164, + 22, + 13, + 127, + 224, + 86, + 109, + 24, + 123, + 185, + 96, + 216, + 93, + 220, + 21, + 79, + 64, + 5, + 78, + 31, + 131, + 133, + 11, + 156, + 23, + 125, + 23, + 6, + 206, + 216, + 170, + 94, + 244, + 91, + 124, + 207, + 93, + 175, + 28, + 64, + 203, + 234, + 232, + 58, + 26, + 61, + 173, + 205, + 138, + 30, + 219, + 54, + 218, + 13, + 27, + 240, + 19, + 183, + 66, + 48, + 98, + 142, + 79, + 131, + 52, + 114, + 9, + 190, + 85, + 233, + 40, + 6, + 9, + 255, + 203, + 213, + 90, + 145, + 194, + 78, + 73, + 227, + 220, + 154, + 53, + 85, + 12, + 9, + 22, + 83, + 241, + 47, + 113, + 55, + 201, + 87, + 114, + 226, + 102, + 198, + 241, + 0, + 254, + 52, + 50, + 108, + 151, + 126, + 94, + 74, + 124, + 217, + 157, + 140, + 158, + 189, + 109, + 215, + 15, + 150, + 54, + 225, + 43, + 60, + 7, + 115, + 182, + 100, + 199, + 155, + 252, + 119, + 158, + 210, + 67, + 120, + 191, + 128, + 250, + 107, + 130, + 39, + 39, + 49, + 144, + 38, + 37, + 146, + 2, + 187, + 122, + 147, + 181, + 244, + 132, + 88, + 196, + 240, + 132, + 21, + 30, + 186, + 125, + 217, + 203, + 189, + 68, + 131, + 76, + 185, + 23, + 37, + 190, + 172, + 6, + 175, + 179, + 173, + 247, + 251, + 246, + 211, + 184, + 127, + 117, + 171, + 119, + 13, + 140, + 248, + 181, + 80, + 164, + 221, + 84, + 77, + 252, + 206, + 216, + 157, + 19, + 206, + 196, + 80, + 160, + 175, + 210, + 155, + 230, + 164, + 33, + 182, + 205, + 99, + 156, + 254, + 108, + 22, + 15, + 91, + 170, + 45, + 74, + 87, + 94, + 60, + 57, + 103, + 179, + 111, + 187, + 182, + 100, + 7, + 227, + 185, + 213, + 51, + 29, + 77, + 106, + 72, + 128, + 246, + 147, + 34, + 44, + 0, + 32, + 58, + 42, + 115, + 213, + 183, + 124, + 131, + 94, + 199, + 219, + 237, + 67, + 106, + 186, + 199, + 42, + 38, + 243, + 172, + 91, + 27, + 2, + 196, + 196, + 53, + 20, + 10, + 236, + 170, + 39, + 111, + 86, + 29, + 159, + 10, + 41, + 71, + 146, + 40, + 153, + 246, + 116, + 113, + 24, + 221, + 210, + 252, + 55, + 14, + 179, + 246, + 69, + 102, + 147, + 113, + 61, + 45, + 55, + 173, + 211, + 128, + 117, + 39, + 178, + 52, + 198, + 23, + 126, + 129, + 232, + 53, + 124, + 43, + 65, + 202, + 92, + 195, + 206, + 184, + 169, + 189, + 235, + 16, + 41, + 107, + 33, + 223, + 4, + 137, + 15, + 31, + 237, + 161, + 9, + 211, + 63, + 62, + 247, + 12, + 81, + 162, + 107, + 87, + 76, + 214, + 227, + 137, + 209, + 81, + 122, + 14, + 153, + 59, + 162, + 31, + 110, + 5, + 238, + 235, + 107, + 152, + 3, + 132, + 55, + 36, + 81, + 143, + 235, + 133, + 250, + 11, + 32, + 133, + 176, + 180, + 48, + 56, + 209, + 165, + 203, + 183, + 132, + 4, + 129, + 243, + 46, + 132, + 109, + 106, + 17, + 35, + 111, + 148, + 164, + 67, + 236, + 163, + 58, + 132, + 17, + 47, + 123, + 88, + 51, + 189, + 196, + 131, + 153, + 1, + 242, + 249, + 43, + 98, + 171, + 220, + 83, + 86, + 129, + 25, + 12, + 101, + 148, + 40, + 184, + 192, + 151, + 238, + 234, + 64, + 166, + 135, + 230, + 246, + 13, + 110, + 73, + 23, + 67, + 130, + 216, + 8, + 138, + 74, + 22, + 249, + 139, + 181, + 199, + 230, + 80, + 226, + 38, + 81, + 38, + 27, + 154, + 40, + 128, + 48, + 247, + 140, + 54, + 167, + 201, + 106, + 184, + 17, + 194, + 246, + 91, + 58, + 147, + 200, + 122, + 190, + 32, + 24, + 110, + 221, + 255, + 176, + 219, + 18, + 36, + 188, + 119, + 89, + 189, + 30, + 173, + 164, + 111, + 230, + 115, + 172, + 5, + 180, + 112, + 15, + 96, + 151, + 150, + 229, + 153, + 34, + 209, + 153, + 188, + 37, + 164, + 166, + 219, + 48, + 99, + 39, + 204, + 41, + 105, + 17, + 43, + 130, + 241, + 154, + 122, + 47, + 230, + 84, + 182, + 61, + 6, + 22, + 227, + 66, + 0, + 50, + 94, + 109, + 84, + 247, + 192, + 46, + 176, + 206, + 58, + 9, + 242, + 201, + 96, + 104, + 162, + 55, + 122, + 85, + 219, + 59, + 237, + 89, + 67, + 6, + 150, + 139, + 220, + 101, + 87, + 64, + 190, + 5, + 238, + 50, + 36, + 114, + 102, + 239, + 36, + 217, + 142, + 104, + 68, + 174, + 1, + 197, + 157, + 89, + 102, + 212, + 250, + 150, + 188, + 48, + 114, + 85, + 237, + 130, + 148, + 71, + 131, + 0, + 56, + 241, + 37, + 191, + 161, + 53, + 134, + 78, + 55, + 239, + 186, + 88, + 194, + 147, + 127, + 158, + 147, + 230, + 104, + 198, + 51, + 107, + 230, + 12, + 39, + 94, + 138, + 0, + 24, + 82, + 187, + 101, + 45, + 118, + 115, + 216, + 124, + 175, + 192, + 8, + 225, + 164, + 68, + 4, + 160, + 95, + 172, + 199, + 196, + 59, + 151, + 30, + 97, + 97, + 169, + 37, + 14, + 148, + 252, + 16, + 4, + 82, + 54, + 61, + 73, + 82, + 226, + 160, + 227, + 0, + 43, + 86, + 14, + 79, + 201, + 106, + 159, + 4, + 226, + 63, + 35, + 88, + 239, + 80, + 91, + 220, + 106, + 118, + 229, + 12, + 95, + 82, + 94, + 52, + 41, + 179, + 132, + 204, + 221, + 56, + 64, + 113, + 81, + 140, + 242, + 13, + 226, + 90, + 22, + 74, + 148, + 117, + 207, + 130, + 178, + 118, + 188, + 46, + 181, + 49, + 213, + 193, + 103, + 172, + 132, + 3, + 152, + 95, + 85, + 130, + 44, + 3, + 219, + 55, + 76, + 117, + 63, + 1, + 226, + 229, + 88, + 250, + 99, + 34, + 103, + 180, + 113, + 157, + 222, + 57, + 104, + 253, + 157, + 21, + 30, + 180, + 101, + 47, + 103, + 238, + 29, + 109, + 253, + 77, + 36, + 205, + 76, + 124, + 75, + 72, + 178, + 230, + 130, + 240, + 232, + 26, + 219, + 125, + 25, + 121, + 141, + 105, + 230, + 253, + 75, + 38, + 114, + 62, + 122, + 18, + 172, + 98, + 104, + 170, + 142, + 197, + 0, + 131, + 33, + 164, + 8, + 210, + 228, + 127, + 4, + 176, + 110, + 184, + 248, + 145, + 98, + 234, + 136, + 12, + 52, + 81, + 107, + 211, + 137, + 226, + 21, + 8, + 40, + 8, + 218, + 103, + 114, + 32, + 194, + 113, + 21, + 20, + 252, + 5, + 118, + 46, + 91, + 85, + 72, + 186, + 88, + 62, + 109, + 176, + 55, + 190, + 47, + 55, + 201, + 200, + 175, + 109, + 246, + 45, + 39, + 93, + 77, + 179, + 47, + 145, + 34, + 28, + 164, + 37, + 18, + 202, + 188, + 68, + 190, + 240, + 46, + 100, + 129, + 114, + 114, + 141, + 47, + 188, + 229, + 100, + 128, + 167, + 12, + 56, + 177, + 20, + 184, + 157, + 62, + 29, + 6, + 122, + 76, + 217, + 118, + 202, + 3, + 49, + 148, + 160, + 84, + 185, + 59, + 49, + 12, + 237, + 158, + 189, + 152, + 218, + 179, + 100, + 100, + 63, + 91, + 27, + 147, + 107, + 163, + 59, + 13, + 252, + 45, + 201, + 49, + 22, + 25, + 195, + 240, + 12, + 87, + 59, + 95, + 69, + 24, + 39, + 127, + 231, + 176, + 173, + 171, + 178, + 135, + 113, + 66, + 34, + 68, + 7, + 21, + 107, + 224, + 67, + 127, + 25, + 170, + 100, + 119, + 55, + 19, + 149, + 177, + 193, + 113, + 84, + 143, + 110, + 75, + 35, + 238, + 146, + 150, + 2, + 192, + 59, + 93, + 153, + 162, + 10, + 221, + 100, + 137, + 17, + 194, + 168, + 170, + 19, + 80, + 251, + 158, + 253, + 136, + 149, + 39, + 15, + 186, + 13, + 38, + 133, + 61, + 221, + 147, + 4, + 78, + 186, + 68, + 186, + 130, + 163, + 39, + 191, + 130, + 22, + 185, + 42, + 56, + 84, + 152, + 102, + 95, + 0, + 28, + 90, + 252, + 220, + 39, + 105, + 191, + 95, + 254, + 58, + 58, + 225, + 50, + 246, + 113, + 186, + 55, + 12, + 149, + 233, + 199, + 162, + 255, + 151, + 35, + 104, + 68, + 254, + 54, + 201, + 228, + 13, + 47, + 95, + 68, + 151, + 110, + 26, + 59, + 57, + 75, + 226, + 10, + 141, + 51, + 108, + 80, + 93, + 34, + 75, + 111, + 151, + 157, + 226, + 19, + 24, + 150, + 42, + 52, + 46, + 89, + 241, + 126, + 219, + 246, + 133, + 215, + 12, + 9, + 93, + 236, + 121, + 226, + 118, + 32, + 192, + 16, + 226, + 180, + 219, + 202, + 33, + 170, + 184, + 252, + 249, + 34, + 8, + 90, + 83, + 37, + 240, + 24, + 92, + 59, + 142, + 154, + 234, + 124, + 40, + 131, + 118, + 66, + 44, + 150, + 114, + 122, + 42, + 236, + 3, + 13, + 184, + 152, + 118, + 213, + 200, + 145, + 184, + 60, + 205, + 79, + 16, + 249, + 120, + 28, + 214, + 140, + 218, + 110, + 247, + 56, + 182, + 35, + 97, + 217, + 122, + 191, + 76, + 182, + 52, + 184, + 204, + 111, + 187, + 154, + 48, + 108, + 77, + 173, + 171, + 16, + 128, + 155, + 4, + 129, + 112, + 103, + 37, + 61, + 174, + 203, + 9, + 91, + 112, + 155, + 103, + 104, + 123, + 66, + 25, + 98, + 58, + 96, + 229, + 149, + 92, + 226, + 165, + 43, + 114, + 113, + 19, + 66, + 5, + 146, + 6, + 159, + 20, + 27, + 125, + 194, + 70, + 205, + 214, + 74, + 84, + 125, + 223, + 238, + 222, + 7, + 149, + 237, + 153, + 235, + 89, + 226, + 143, + 76, + 183, + 89, + 60, + 107, + 169, + 11, + 155, + 203, + 48, + 193, + 116, + 71, + 250, + 120, + 42, + 160, + 125, + 148, + 250, + 77, + 34, + 126, + 145, + 161, + 252, + 120, + 5, + 114, + 105, + 50, + 5, + 132, + 90, + 64, + 146, + 38, + 233, + 97, + 118, + 236, + 16, + 10, + 255, + 12, + 107, + 0, + 61, + 238, + 58, + 159, + 160, + 106, + 211, + 87, + 157, + 12, + 186, + 157, + 198, + 90, + 139, + 209, + 208, + 171, + 100, + 27, + 248, + 131, + 49, + 237, + 104, + 234, + 7, + 201, + 181, + 3, + 15, + 172, + 227, + 208, + 104, + 113, + 26, + 178, + 140, + 133, + 123, + 250, + 139, + 83, + 53, + 77, + 223, + 143, + 112, + 22, + 6, + 121, + 141, + 29, + 219, + 48, + 199, + 193, + 53, + 188, + 123, + 175, + 147, + 245, + 123, + 40, + 186, + 147, + 249, + 20, + 82, + 3, + 55, + 136, + 154, + 2, + 16, + 93, + 100, + 202, + 252, + 227, + 162, + 34, + 179, + 90, + 36, + 26, + 20, + 218, + 66, + 195, + 215, + 93, + 148, + 152, + 233, + 7, + 141, + 53, + 178, + 247, + 59, + 182, + 84, + 87, + 36, + 248, + 25, + 152, + 191, + 119, + 235, + 5, + 98, + 213, + 148, + 253, + 212, + 9, + 215, + 158, + 108, + 202, + 42, + 229, + 44, + 99, + 219, + 190, + 93, + 19, + 129, + 34, + 45, + 131, + 6, + 227, + 117, + 106, + 191, + 238, + 212, + 106, + 213, + 62, + 18, + 180, + 56, + 252, + 187, + 51, + 1, + 173, + 21, + 216, + 158, + 85, + 114, + 95, + 234, + 161, + 127, + 223, + 250, + 243, + 220, + 77, + 43, + 141, + 166, + 0, + 25, + 233, + 9, + 30, + 239, + 13, + 247, + 90, + 49, + 221, + 170, + 158, + 47, + 217, + 25, + 247, + 35, + 193, + 78, + 132, + 163, + 182, + 133, + 166, + 60, + 30, + 244, + 96, + 164, + 147, + 121, + 31, + 1, + 43, + 233, + 16, + 174, + 220, + 78, + 241, + 193, + 253, + 113, + 232, + 36, + 2, + 38, + 225, + 137, + 67, + 173, + 108, + 53, + 100, + 34, + 132, + 41, + 148, + 23, + 180, + 218, + 183, + 239, + 82, + 151, + 33, + 105, + 120, + 66, + 230, + 28, + 51, + 15, + 33, + 179, + 86, + 149, + 123, + 88, + 221, + 252, + 93, + 12, + 109, + 133, + 141, + 11, + 253, + 103, + 45, + 194, + 188, + 255, + 85, + 94, + 57, + 173, + 69, + 125, + 192, + 119, + 86, + 209, + 181, + 17, + 188, + 100, + 38, + 99, + 179, + 89, + 249, + 73, + 179, + 246, + 247, + 83, + 48, + 41, + 86, + 7, + 109, + 154, + 132, + 11, + 143, + 48, + 180, + 8, + 137, + 189, + 242, + 145, + 221, + 63, + 13, + 241, + 240, + 187, + 103, + 254, + 197, + 7, + 55, + 36, + 69, + 33, + 193, + 173, + 38, + 190, + 85, + 196, + 168, + 161, + 120, + 178, + 56, + 134, + 147, + 72, + 73, + 13, + 193, + 182, + 55, + 147, + 188, + 0, + 12, + 248, + 195, + 151, + 190, + 25, + 112, + 198, + 154, + 32, + 246, + 239, + 160, + 32, + 85, + 167, + 201, + 227, + 149, + 121, + 210, + 227, + 54, + 255, + 76, + 49, + 68, + 231, + 16, + 139, + 163, + 17, + 41, + 239, + 47, + 207, + 17, + 39, + 186, + 20, + 127, + 217, + 110, + 0, + 1, + 236, + 189, + 249, + 58, + 112, + 58, + 24, + 243, + 182, + 240, + 177, + 134, + 176, + 242, + 82, + 73, + 70, + 236, + 122, + 170, + 119, + 229, + 117, + 89, + 27, + 161, + 28, + 244, + 186, + 1, + 143, + 159, + 235, + 136, + 65, + 211, + 246, + 117, + 100, + 23, + 147, + 247, + 43, + 203, + 14, + 148, + 30, + 71, + 21, + 83, + 138, + 117, + 14, + 139, + 190, + 188, + 97, + 86, + 137, + 207, + 173, + 150, + 255, + 97, + 44, + 34, + 68, + 10, + 92, + 163, + 119, + 57, + 205, + 162, + 48, + 70, + 255, + 21, + 42, + 133, + 172, + 16, + 220, + 73, + 201, + 73, + 200, + 250, + 18, + 57, + 10, + 246, + 230, + 247, + 93, + 128, + 76, + 198, + 24, + 85, + 40, + 70, + 121, + 102, + 73, + 191, + 76, + 231, + 99, + 110, + 66, + 240, + 164, + 187, + 46, + 201, + 167, + 86, + 148, + 117, + 22, + 162, + 249, + 149, + 117, + 56, + 3, + 220, + 236, + 232, + 195, + 68, + 0, + 58, + 71, + 89, + 37, + 110, + 133, + 7, + 69, + 126, + 150, + 158, + 67, + 114, + 136, + 56, + 198, + 108, + 87, + 18, + 49, + 144, + 177, + 250, + 213, + 82, + 220, + 100, + 232, + 58, + 239, + 84, + 184, + 150, + 197, + 187, + 25, + 133, + 193, + 151, + 90, + 212, + 109, + 245, + 171, + 135, + 75, + 81, + 192, + 149, + 136, + 70, + 23, + 5, + 22, + 111, + 141, + 45, + 127, + 239, + 238, + 152, + 198, + 16, + 11, + 152, + 47, + 2, + 90, + 89, + 112, + 157, + 179, + 50, + 220, + 134, + 91, + 81, + 242, + 210, + 104, + 230, + 93, + 133, + 105, + 142, + 163, + 229, + 112, + 194, + 233, + 36, + 224, + 69, + 229, + 249, + 161, + 64, + 175, + 83, + 164, + 127, + 78, + 165, + 115, + 32, + 80, + 177, + 240, + 78, + 187, + 232, + 124, + 143, + 17, + 101, + 32, + 31, + 165, + 82, + 211, + 17, + 7, + 206, + 83, + 227, + 126, + 13, + 242, + 91, + 248, + 122, + 206, + 207, + 26, + 110, + 62, + 96, + 82, + 17, + 181, + 124, + 85, + 17, + 29, + 52, + 111, + 105, + 94, + 196, + 102, + 180, + 220, + 199, + 19, + 198, + 138, + 49, + 0, + 210, + 103, + 94, + 169, + 244, + 12, + 132, + 192, + 216, + 2, + 170, + 143, + 104, + 96, + 169, + 53, + 14, + 101, + 1, + 149, + 162, + 44, + 151, + 188, + 147, + 224, + 103, + 240, + 200, + 78, + 2, + 11, + 26, + 222, + 92, + 115, + 74, + 220, + 164, + 31, + 119, + 130, + 121, + 179, + 130, + 82, + 218, + 19, + 141, + 45, + 68, + 199, + 65, + 52, + 220, + 124, + 55, + 158, + 65, + 128, + 110, + 184, + 203, + 5, + 248, + 215, + 167, + 248, + 34, + 164, + 123, + 200, + 68, + 58, + 251, + 20, + 32, + 98, + 119, + 73, + 55, + 142, + 182, + 135, + 229, + 20, + 18, + 49, + 209, + 45, + 9, + 232, + 217, + 141, + 8, + 250, + 145, + 205, + 176, + 37, + 93, + 119, + 89, + 4, + 85, + 183, + 243, + 223, + 196, + 126, + 163, + 245, + 79, + 62, + 151, + 113, + 119, + 15, + 203, + 54, + 40, + 17, + 231, + 131, + 220, + 139, + 6, + 4, + 240, + 96, + 101, + 8, + 117, + 102, + 185, + 196, + 79, + 7, + 190, + 94, + 33, + 78, + 136, + 35, + 143, + 24, + 255, + 52, + 132, + 29, + 6, + 247, + 83, + 169, + 59, + 199, + 40, + 164, + 6, + 157, + 248, + 56, + 47, + 51, + 87, + 169, + 92, + 34, + 16, + 234, + 182, + 22, + 55, + 210, + 240, + 151, + 217, + 144, + 94, + 51, + 120, + 46, + 222, + 212, + 9, + 203, + 117, + 6, + 60, + 20, + 40, + 217, + 90, + 198, + 232, + 16, + 213, + 139, + 99, + 69, + 59, + 35, + 182, + 38, + 50, + 12, + 156, + 47, + 42, + 238, + 102, + 223, + 200, + 24, + 183, + 148, + 172, + 97, + 190, + 81, + 233, + 158, + 235, + 183, + 159, + 61, + 132, + 141, + 196, + 127, + 3, + 243, + 173, + 64, + 169, + 1, + 221, + 95, + 182, + 119, + 197, + 4, + 183, + 124, + 254, + 46, + 203, + 223, + 175, + 115, + 101, + 90, + 30, + 212, + 1, + 236, + 81, + 137, + 175, + 232, + 255, + 173, + 227, + 22, + 89, + 198, + 124, + 6, + 240, + 247, + 82, + 206, + 149, + 3, + 176, + 101, + 251, + 92, + 99, + 64, + 218, + 235, + 117, + 202, + 192, + 191, + 170, + 93, + 176, + 12, + 12, + 19, + 162, + 52, + 215, + 7, + 156, + 211, + 38, + 133, + 142, + 55, + 125, + 244, + 66, + 95, + 0, + 157, + 21, + 60, + 237, + 147, + 112, + 22, + 35, + 82, + 43, + 114, + 42, + 42, + 197, + 179, + 24, + 11, + 119, + 25, + 186, + 48, + 136, + 238, + 213, + 41, + 50, + 182, + 189, + 71, + 127, + 54, + 61, + 196, + 155, + 34, + 136, + 136, + 174, + 59, + 69, + 247, + 221, + 69, + 163, + 75, + 222, + 180, + 211, + 62, + 14, + 149, + 96, + 246, + 214, + 51, + 98, + 103, + 1, + 247, + 76, + 254, + 42, + 216, + 163, + 245, + 160, + 67, + 132, + 110, + 99, + 247, + 200, + 50, + 95, + 180, + 250, + 119, + 139, + 42, + 152, + 249, + 148, + 232, + 75, + 155, + 193, + 95, + 109, + 8, + 245, + 135, + 227, + 60, + 181, + 60, + 49, + 102, + 230, + 53, + 85, + 58, + 239, + 117, + 224, + 127, + 135, + 157, + 201, + 77, + 205, + 11, + 173, + 212, + 87, + 13, + 17, + 113, + 231, + 31, + 245, + 107, + 236, + 124, + 74, + 149, + 81, + 39, + 155, + 238, + 214, + 58, + 157, + 12, + 42, + 137, + 189, + 159, + 82, + 41, + 153, + 12, + 203, + 35, + 30, + 176, + 37, + 91, + 38, + 161, + 91, + 115, + 180, + 211, + 69, + 165, + 103, + 110, + 1, + 29, + 235, + 80, + 217, + 22, + 142, + 233, + 96, + 233, + 194, + 126, + 247, + 104, + 227, + 179, + 251, + 91, + 91, + 82, + 14, + 165, + 138, + 16, + 241, + 106, + 135, + 95, + 42, + 147, + 8, + 13, + 53, + 239, + 54, + 41, + 127, + 59, + 8, + 67, + 33, + 252, + 33, + 5, + 90, + 109, + 168, + 163, + 70, + 235, + 89, + 3, + 197, + 59, + 181, + 189, + 77, + 251, + 255, + 42, + 48, + 128, + 80, + 210, + 196, + 191, + 162, + 19, + 156, + 5, + 239, + 151, + 12, + 205, + 198, + 142, + 88, + 144, + 143, + 223, + 62, + 173, + 208, + 225, + 61, + 99, + 29, + 186, + 159, + 182, + 218, + 134, + 114, + 123, + 123, + 73, + 168, + 137, + 219, + 109, + 102, + 65, + 56, + 249, + 33, + 207, + 54, + 236, + 189, + 36, + 209, + 255, + 228, + 73, + 131, + 105, + 159, + 6, + 165, + 136, + 228, + 157, + 38, + 16, + 172, + 1, + 213, + 10, + 91, + 71, + 122, + 162, + 155, + 61, + 166, + 79, + 90, + 90, + 127, + 47, + 246, + 122, + 127, + 62, + 116, + 177, + 43, + 84, + 37, + 27, + 69, + 21, + 32, + 58, + 26, + 74, + 84, + 230, + 18, + 245, + 194, + 252, + 61, + 232, + 193, + 113, + 2, + 20, + 77, + 241, + 114, + 209, + 134, + 174, + 11, + 108, + 142, + 111, + 99, + 55, + 92, + 197, + 217, + 60, + 114, + 120, + 35, + 182, + 100, + 255, + 166, + 110, + 15, + 10, + 23, + 36, + 157, + 17, + 204, + 176, + 68, + 188, + 108, + 243, + 39, + 246, + 254, + 197, + 137, + 203, + 83, + 176, + 195, + 10, + 133, + 231, + 38, + 214, + 193, + 27, + 1, + 164, + 128, + 144, + 96, + 66, + 244, + 88, + 52, + 32, + 15, + 221, + 72, + 60, + 33, + 141, + 198, + 250, + 145, + 152, + 83, + 202, + 236, + 172, + 115, + 82, + 153, + 175, + 217, + 124, + 213, + 178, + 104, + 68, + 147, + 207, + 184, + 44, + 225, + 11, + 114, + 45, + 52, + 247, + 96, + 237, + 123, + 70, + 186, + 211, + 97, + 93, + 43, + 180, + 42, + 186, + 53, + 5, + 169, + 154, + 169, + 7, + 62, + 239, + 38, + 209, + 161, + 202, + 231, + 211, + 255, + 88, + 232, + 110, + 162, + 193, + 176, + 78, + 47, + 44, + 40, + 50, + 66, + 31, + 121, + 130, + 96, + 241, + 34, + 35, + 89, + 61, + 29, + 216, + 125, + 184, + 32, + 134, + 212, + 10, + 70, + 9, + 64, + 19, + 142, + 16, + 43, + 91, + 148, + 4, + 125, + 172, + 79, + 111, + 31, + 112, + 233, + 73, + 28, + 19, + 202, + 40, + 106, + 62, + 236, + 51, + 82, + 170, + 197, + 210, + 137, + 222, + 89, + 142, + 178, + 67, + 2, + 46, + 142, + 236, + 65, + 165, + 163, + 56, + 163, + 87, + 186, + 12, + 185, + 55, + 99, + 210, + 64, + 154, + 29, + 68, + 51, + 228, + 174, + 110, + 30, + 195, + 115, + 177, + 136, + 107, + 209, + 90, + 117, + 80, + 241, + 87, + 12, + 75, + 17, + 218, + 231, + 43, + 51, + 89, + 201, + 241, + 254, + 105, + 76, + 0, + 16, + 247, + 162, + 107, + 90, + 163, + 72, + 172, + 50, + 166, + 41, + 129, + 37, + 195, + 230, + 99, + 114, + 56, + 211, + 163, + 34, + 188, + 35, + 175, + 31, + 75, + 184, + 48, + 19, + 174, + 160, + 117, + 253, + 41, + 140, + 3, + 180, + 57, + 58, + 63, + 126, + 172, + 8, + 117, + 130, + 169, + 230, + 68, + 56, + 122, + 19, + 158, + 242, + 75, + 254, + 79, + 63, + 243, + 152, + 200, + 207, + 120, + 12, + 55, + 0, + 138, + 64, + 157, + 242, + 169, + 77, + 210, + 228, + 110, + 153, + 175, + 176, + 154, + 213, + 16, + 137, + 129, + 241, + 35, + 208, + 231, + 19, + 87, + 52, + 227, + 75, + 192, + 139, + 28, + 106, + 90, + 147, + 180, + 226, + 76, + 212, + 114, + 123, + 201, + 242, + 99, + 166, + 153, + 123, + 140, + 162, + 103, + 195, + 108, + 251, + 113, + 208, + 239, + 98, + 102, + 188, + 31, + 136, + 223, + 144, + 64, + 139, + 98, + 154, + 197, + 247, + 53, + 79, + 35, + 158, + 14, + 242, + 118, + 129, + 236, + 229, + 200, + 161, + 32, + 18, + 120, + 155, + 113, + 145, + 85, + 15, + 125, + 212, + 195, + 103, + 10, + 33, + 251, + 225, + 88, + 127, + 163, + 166, + 186, + 107, + 29, + 2, + 223, + 97, + 64, + 11, + 170, + 45, + 172, + 91, + 18, + 179, + 226, + 168, + 46, + 53, + 252, + 51, + 235, + 111, + 229, + 193, + 103, + 164, + 53, + 124, + 247, + 209, + 148, + 116, + 168, + 163, + 156, + 145, + 31, + 189, + 57, + 41, + 1, + 42, + 79, + 108, + 54, + 160, + 17, + 238, + 101, + 253, + 100, + 41, + 210, + 209, + 33, + 241, + 195, + 244, + 126, + 135, + 69, + 155, + 176, + 116, + 52, + 151, + 42, + 205, + 167, + 160, + 0, + 149, + 28, + 13, + 145, + 59, + 18, + 182, + 225, + 161, + 230, + 168, + 115, + 240, + 244, + 18, + 247, + 174, + 100, + 127, + 1, + 35, + 185, + 114, + 89, + 43, + 119, + 116, + 17, + 225, + 125, + 88, + 222, + 191, + 160, + 210, + 12, + 40, + 37, + 190, + 155, + 53, + 189, + 145, + 14, + 137, + 89, + 47, + 93, + 8, + 213, + 28, + 238, + 176, + 207, + 18, + 109, + 29, + 195, + 82, + 170, + 62, + 183, + 113, + 25, + 56, + 66, + 12, + 114, + 123, + 93, + 5, + 187, + 36, + 202, + 201, + 202, + 37, + 60, + 27, + 211, + 114, + 172, + 250, + 237, + 170, + 74, + 105, + 116, + 13, + 76, + 129, + 200, + 215, + 22, + 73, + 47, + 13, + 169, + 14, + 97, + 216, + 107, + 0, + 156, + 140, + 128, + 254, + 51, + 128, + 194, + 58, + 184, + 166, + 3, + 80, + 236, + 75, + 186, + 15, + 56, + 10, + 129, + 236, + 142, + 64, + 155, + 104, + 224, + 252, + 80, + 92, + 63, + 201, + 44, + 150, + 39, + 44, + 185, + 190, + 34, + 217, + 228, + 75, + 202, + 69, + 147, + 82, + 144, + 59, + 191, + 212, + 145, + 113, + 252, + 193, + 28, + 95, + 173, + 208, + 211, + 253, + 3, + 46, + 149, + 25, + 35, + 241, + 86, + 116, + 255, + 170, + 35, + 255, + 231, + 29, + 233, + 137, + 192, + 15, + 178, + 96, + 223, + 154, + 125, + 159, + 97, + 130, + 77, + 116, + 84, + 69, + 111, + 80, + 117, + 146, + 118, + 138, + 55, + 97, + 184, + 100, + 252, + 196, + 95, + 33, + 179, + 175, + 28, + 12, + 163, + 243, + 16, + 134, + 18, + 94, + 198, + 56, + 56, + 94, + 231, + 200, + 29, + 250, + 198, + 70, + 190, + 17, + 140, + 198, + 36, + 210, + 149, + 170, + 35, + 228, + 167, + 19, + 233, + 223, + 70, + 184, + 124, + 253, + 230, + 213, + 69, + 122, + 187, + 113, + 183, + 57, + 186, + 224, + 139, + 9, + 153, + 81, + 95, + 184, + 13, + 37, + 60, + 130, + 147, + 53, + 230, + 122, + 241, + 240, + 97, + 182, + 17, + 178, + 199, + 45, + 26, + 231, + 104, + 136, + 129, + 163, + 177, + 51, + 211, + 101, + 31, + 107, + 206, + 244, + 144, + 233, + 243, + 189, + 108, + 107, + 10, + 130, + 230, + 241, + 165, + 154, + 222, + 71, + 52, + 113, + 21, + 64, + 96, + 216, + 7, + 53, + 116, + 251, + 25, + 248, + 120, + 70, + 237, + 215, + 164, + 114, + 18, + 223, + 160, + 1, + 14, + 21, + 10, + 163, + 177, + 247, + 155, + 3, + 66, + 78, + 61, + 106, + 105, + 123, + 169, + 29, + 156, + 249, + 138, + 21, + 90, + 44, + 220, + 87, + 78, + 223, + 194, + 164, + 255, + 182, + 207, + 133, + 38, + 117, + 162, + 248, + 24, + 31, + 187, + 47, + 87, + 103, + 74, + 106, + 220, + 94, + 215, + 103, + 37, + 252, + 111, + 128, + 190, + 94, + 233, + 232, + 186, + 231, + 212, + 99, + 207, + 32, + 6, + 244, + 20, + 192, + 205, + 152, + 140, + 14, + 50, + 254, + 18, + 226, + 14, + 24, + 194, + 82, + 81, + 227, + 165, + 117, + 54, + 113, + 87, + 78, + 179, + 226, + 126, + 243, + 13, + 197, + 104, + 121, + 234, + 208, + 68, + 54, + 162, + 199, + 215, + 103, + 161, + 168, + 146, + 113, + 44, + 151, + 163, + 98, + 196, + 181, + 56, + 32, + 38, + 23, + 163, + 74, + 75, + 161, + 236, + 174, + 226, + 162, + 245, + 5, + 115, + 5, + 31, + 197, + 75, + 175, + 149, + 3, + 188, + 129, + 230, + 85, + 18, + 4, + 215, + 37, + 185, + 137, + 143, + 173, + 75, + 160, + 239, + 16, + 253, + 98, + 161, + 133, + 16, + 74, + 151, + 199, + 84, + 83, + 102, + 254, + 239, + 105, + 176, + 203, + 128, + 198, + 90, + 90, + 114, + 114, + 86, + 181, + 181, + 111, + 187, + 40, + 180, + 218, + 31, + 251, + 185, + 40, + 54, + 226, + 26, + 57, + 172, + 166, + 194, + 156, + 40, + 127, + 47, + 64, + 85, + 19, + 122, + 152, + 211, + 176, + 104, + 154, + 83, + 194, + 155, + 5, + 184, + 18, + 45, + 250, + 181, + 44, + 0, + 120, + 33, + 215, + 164, + 14, + 226, + 168, + 75, + 199, + 55, + 247, + 42, + 48, + 131, + 208, + 220, + 196, + 252, + 130, + 141, + 9, + 191, + 53, + 162, + 91, + 250, + 188, + 243, + 245, + 195, + 48, + 245, + 4, + 70, + 201, + 83, + 144, + 65, + 175, + 112, + 61, + 47, + 173, + 155, + 60, + 68, + 95, + 133, + 162, + 143, + 0, + 73, + 114, + 247, + 208, + 22, + 225, + 144, + 215, + 14, + 145, + 138, + 187, + 107, + 217, + 2, + 147, + 239, + 147, + 249, + 122, + 135, + 77, + 43, + 14, + 42, + 194, + 27, + 14, + 141, + 111, + 248, + 77, + 214, + 112, + 143, + 218, + 141, + 98, + 198, + 37, + 186, + 31, + 80, + 90, + 24, + 138, + 188, + 14, + 57, + 17, + 136, + 222, + 37, + 40, + 80, + 198, + 179, + 102, + 141, + 136, + 155, + 129, + 197, + 9, + 186, + 35, + 143, + 132, + 169, + 242, + 9, + 239, + 119, + 110, + 182, + 138, + 244, + 129, + 98, + 126, + 91, + 194, + 185, + 35, + 233, + 98, + 34, + 237, + 226, + 242, + 91, + 81, + 65, + 124, + 178, + 94, + 74, + 51, + 94, + 1, + 125, + 246, + 160, + 255, + 153, + 106, + 10, + 23, + 186, + 61, + 64, + 49, + 10, + 115, + 189, + 254, + 50, + 232, + 55, + 45, + 219, + 165, + 247, + 103, + 247, + 50, + 185, + 18, + 74, + 83, + 113, + 196, + 63, + 121, + 63, + 30, + 247, + 92, + 63, + 93, + 77, + 238, + 129, + 177, + 45, + 145, + 49, + 217, + 39, + 202, + 16, + 192, + 200, + 253, + 5, + 122, + 46, + 169, + 107, + 227, + 207, + 63, + 177, + 65, + 42, + 109, + 62, + 163, + 163, + 75, + 141, + 223, + 82, + 217, + 92, + 102, + 216, + 91, + 156, + 191, + 27, + 166, + 82, + 79, + 120, + 44, + 70, + 180, + 196, + 194, + 124, + 143, + 107, + 100, + 71, + 162, + 183, + 7, + 221, + 74, + 15, + 19, + 23, + 176, + 167, + 48, + 110, + 181, + 1, + 14, + 133, + 146, + 211, + 145, + 113, + 197, + 16, + 123, + 167, + 211, + 132, + 241, + 224, + 167, + 43, + 42, + 147, + 197, + 144, + 145, + 254, + 183, + 20, + 39, + 24, + 114, + 159, + 140, + 4, + 165, + 19, + 215, + 95, + 165, + 68, + 106, + 30, + 9, + 113, + 165, + 81, + 79, + 132, + 50, + 68, + 114, + 194, + 46, + 244, + 215, + 98, + 13, + 46, + 155, + 156, + 54, + 123, + 53, + 97, + 58, + 161, + 28, + 32, + 72, + 113, + 47, + 116, + 124, + 84, + 187, + 92, + 208, + 82, + 244, + 210, + 169, + 123, + 94, + 107, + 9, + 151, + 190, + 174, + 64, + 4, + 95, + 188, + 32, + 251, + 53, + 208, + 213, + 151, + 88, + 150, + 103, + 180, + 204, + 224, + 20, + 79, + 2, + 204, + 141, + 247, + 206, + 0, + 122, + 61, + 66, + 80, + 241, + 177, + 159, + 172, + 87, + 199, + 61, + 189, + 7, + 185, + 101, + 190, + 255, + 59, + 123, + 216, + 138, + 153, + 64, + 98, + 164, + 11, + 18, + 80, + 14, + 64, + 86, + 190, + 118, + 202, + 15, + 57, + 17, + 172, + 9, + 36, + 94, + 167, + 240, + 165, + 40, + 103, + 169, + 121, + 166, + 147, + 16, + 148, + 44, + 217, + 106, + 119, + 47, + 53, + 165, + 99, + 46, + 7, + 234, + 14, + 7, + 72, + 215, + 110, + 32, + 192, + 233, + 11, + 100, + 52, + 251, + 97, + 158, + 23, + 220, + 129, + 177, + 171, + 75, + 17, + 237, + 58, + 70, + 152, + 157, + 31, + 110, + 161, + 84, + 252, + 204, + 39, + 8, + 194, + 109, + 3, + 215, + 40, + 170, + 143, + 245, + 143, + 53, + 107, + 198, + 18, + 5, + 213, + 40, + 132, + 152, + 211, + 204, + 196, + 229, + 98, + 20, + 11, + 14, + 25, + 44, + 193, + 104, + 233, + 133, + 79, + 166, + 61, + 197, + 190, + 173, + 195, + 120, + 150, + 79, + 117, + 190, + 26, + 166, + 63, + 94, + 99, + 244, + 47, + 189, + 207, + 182, + 168, + 203, + 54, + 237, + 87, + 32, + 57, + 77, + 138, + 84, + 220, + 198, + 223, + 165, + 244, + 245, + 146, + 22, + 200, + 159, + 186, + 146, + 87, + 76, + 99, + 99, + 149, + 164, + 195, + 227, + 172, + 153, + 30, + 191, + 11, + 208, + 70, + 16, + 167, + 66, + 127, + 87, + 55, + 44, + 62, + 126, + 86, + 14, + 120, + 200, + 117, + 251, + 22, + 217, + 81, + 19, + 58, + 243, + 105, + 50, + 134, + 41, + 156, + 235, + 162, + 78, + 56, + 51, + 119, + 96, + 237, + 45, + 203, + 117, + 61, + 41, + 255, + 187, + 47, + 160, + 254, + 89, + 238, + 216, + 17, + 123, + 191, + 21, + 172, + 213, + 101, + 114, + 187, + 103, + 86, + 51, + 47, + 0, + 62, + 211, + 227, + 59, + 155, + 196, + 81, + 239, + 219, + 155, + 142, + 71, + 206, + 75, + 5, + 237, + 138, + 57, + 41, + 231, + 51, + 195, + 29, + 228, + 233, + 245, + 201, + 236, + 91, + 120, + 181, + 31, + 50, + 155, + 145, + 112, + 28, + 124, + 94, + 151, + 39, + 222, + 106, + 241, + 215, + 217, + 53, + 93, + 78, + 38, + 14, + 235, + 175, + 85, + 128, + 121, + 29, + 183, + 203, + 123, + 6, + 133, + 218, + 138, + 77, + 0, + 74, + 67, + 200, + 94, + 36, + 128, + 89, + 145, + 34, + 10, + 200, + 15, + 72, + 124, + 101, + 60, + 229, + 102, + 238, + 89, + 42, + 22, + 4, + 160, + 191, + 168, + 77, + 148, + 23, + 219, + 42, + 92, + 46, + 127, + 24, + 58, + 123, + 184, + 248, + 44, + 235, + 58, + 209, + 84, + 32, + 146, + 248, + 190, + 187, + 17, + 186, + 35, + 164, + 162, + 10, + 129, + 83, + 243, + 94, + 136, + 159, + 160, + 34, + 25, + 147, + 74, + 94, + 237, + 184, + 28, + 63, + 158, + 80, + 119, + 167, + 209, + 128, + 204, + 106, + 208, + 64, + 37, + 150, + 235, + 103, + 230, + 28, + 69, + 90, + 90, + 136, + 180, + 240, + 239, + 103, + 94, + 121, + 126, + 114, + 153, + 91, + 192, + 165, + 55, + 48, + 183, + 190, + 124, + 79, + 81, + 19, + 133, + 250, + 146, + 164, + 222, + 250, + 17, + 247, + 250, + 218, + 41, + 134, + 124, + 246, + 232, + 114, + 29, + 132, + 244, + 41, + 51, + 231, + 248, + 142, + 119, + 105, + 119, + 69, + 213, + 231, + 50, + 171, + 83, + 74, + 60, + 112, + 203, + 208, + 203, + 226, + 99, + 223, + 84, + 140, + 39, + 175, + 239, + 6, + 163, + 169, + 252, + 238, + 198, + 81, + 16, + 90, + 203, + 105, + 198, + 166, + 191, + 8, + 205, + 84, + 105, + 13, + 128, + 243, + 62, + 80, + 220, + 144, + 84, + 45, + 16, + 253, + 241, + 39, + 243, + 89, + 129, + 252, + 32, + 29, + 218, + 110, + 144, + 104, + 81, + 153, + 101, + 215, + 142, + 84, + 81, + 163, + 218, + 54, + 78, + 110, + 247, + 151, + 213, + 9, + 210, + 117, + 197, + 104, + 8, + 117, + 221, + 48, + 221, + 216, + 185, + 44, + 33, + 43, + 230, + 145, + 173, + 217, + 84, + 226, + 197, + 21, + 150, + 72, + 36, + 9, + 176, + 135, + 221, + 241, + 11, + 64, + 186, + 79, + 139, + 176, + 101, + 124, + 38, + 16, + 108, + 53, + 200, + 2, + 75, + 234, + 139, + 21, + 9, + 13, + 8, + 247, + 97, + 62, + 243, + 190, + 184, + 32, + 198, + 100, + 194, + 39, + 122, + 46, + 198, + 34, + 18, + 55, + 166, + 154, + 44, + 64, + 102, + 189, + 192, + 177, + 250, + 164, + 65, + 219, + 75, + 127, + 108, + 201, + 22, + 66, + 2, + 208, + 155, + 194, + 225, + 87, + 169, + 101, + 90, + 163, + 21, + 116, + 185, + 27, + 20, + 91, + 3, + 33, + 106, + 40, + 97, + 120, + 193, + 220, + 3, + 40, + 83, + 18, + 30, + 136, + 17, + 197, + 198, + 39, + 104, + 198, + 23, + 203, + 170, + 176, + 209, + 183, + 132, + 81, + 91, + 182, + 110, + 161, + 220, + 47, + 82, + 189, + 131, + 90, + 143, + 82, + 240, + 160, + 199, + 52, + 140, + 171, + 22, + 177, + 15, + 7, + 157, + 158, + 179, + 186, + 66, + 181, + 84, + 194, + 93, + 185, + 47, + 25, + 55, + 34, + 207, + 15, + 254, + 18, + 5, + 33, + 242, + 14, + 87, + 183, + 80, + 177, + 211, + 23, + 99, + 229, + 255, + 188, + 72, + 197, + 115, + 98, + 102, + 73, + 91, + 152, + 226, + 35, + 39, + 154, + 248, + 195, + 2, + 34, + 92, + 100, + 123, + 225, + 132, + 9, + 102, + 236, + 238, + 66, + 139, + 157, + 163, + 208, + 143, + 139, + 85, + 250, + 49, + 116, + 242, + 245, + 61, + 104, + 163, + 245, + 183, + 34, + 61, + 37, + 25, + 12, + 249, + 229, + 225, + 8, + 9, + 132, + 112, + 132, + 16, + 210, + 86, + 169, + 240, + 226, + 109, + 245, + 209, + 135, + 53, + 123, + 189, + 128, + 236, + 183, + 78, + 182, + 7, + 148, + 200, + 194, + 93, + 3, + 225, + 40, + 34, + 246, + 3, + 102, + 15, + 138, + 59, + 95, + 121, + 118, + 57, + 28, + 184, + 211, + 67, + 143, + 119, + 226, + 141, + 227, + 54, + 180, + 125, + 127, + 125, + 17, + 101, + 17, + 33, + 31, + 66, + 81, + 163, + 90, + 115, + 185, + 236, + 191, + 11, + 19, + 207, + 204, + 95, + 226, + 183, + 82, + 189, + 226, + 161, + 54, + 113, + 113, + 31, + 204, + 85, + 183, + 11, + 214, + 175, + 78, + 69, + 74, + 219, + 12, + 117, + 14, + 222, + 121, + 207, + 238, + 57, + 245, + 103, + 47, + 50, + 159, + 119, + 220, + 180, + 210, + 7, + 227, + 175, + 83, + 189, + 103, + 68, + 188, + 5, + 125, + 52, + 100, + 128, + 0, + 42, + 195, + 100, + 36, + 159, + 229, + 57, + 2, + 219, + 224, + 145, + 68, + 90, + 155, + 106, + 157, + 99, + 173, + 189, + 150, + 237, + 5, + 36, + 248, + 168, + 1, + 200, + 243, + 245, + 225, + 2, + 110, + 96, + 96, + 251, + 84, + 139, + 181, + 77, + 132, + 182, + 114, + 79, + 74, + 250, + 196, + 76, + 67, + 132, + 64, + 213, + 54, + 148, + 227, + 137, + 254, + 208, + 32, + 66, + 245, + 254, + 187, + 92, + 15, + 241, + 222, + 64, + 48, + 42, + 92, + 54, + 122, + 176, + 128, + 79, + 21, + 142, + 22, + 75, + 178, + 131, + 50, + 128, + 105, + 187, + 76, + 82, + 127, + 48, + 164, + 198, + 122, + 63, + 73, + 124, + 52, + 182, + 118, + 202, + 16, + 207, + 188, + 90, + 81, + 76, + 103, + 157, + 122, + 121, + 207, + 225, + 73, + 252, + 210, + 193, + 65, + 78, + 0, + 17, + 248, + 211, + 224, + 244, + 124, + 175, + 190, + 35, + 5, + 34, + 59, + 252, + 84, + 77, + 171, + 62, + 240, + 227, + 49, + 95, + 172, + 97, + 166, + 61, + 233, + 207, + 168, + 58, + 15, + 44, + 127, + 102, + 197, + 232, + 198, + 41, + 32, + 44, + 210, + 135, + 95, + 182, + 204, + 24, + 57, + 216, + 110, + 4, + 205, + 206, + 168, + 195, + 155, + 244, + 43, + 101, + 19, + 234, + 30, + 228, + 198, + 55, + 187, + 71, + 199, + 226, + 221, + 9, + 2, + 248, + 178, + 119, + 22, + 196, + 6, + 168, + 174, + 239, + 15, + 130, + 110, + 131, + 200, + 192, + 192, + 144, + 141, + 228, + 202, + 199, + 29, + 99, + 115, + 26, + 58, + 174, + 181, + 132, + 184, + 153, + 197, + 205, + 87, + 141, + 15, + 248, + 238, + 95, + 158, + 111, + 7, + 5, + 180, + 60, + 4, + 111, + 104, + 150, + 167, + 74, + 147, + 142, + 2, + 138, + 24, + 192, + 73, + 155, + 252, + 84, + 108, + 120, + 93, + 166, + 246, + 25, + 86, + 114, + 106, + 57, + 156, + 86, + 63, + 37, + 108, + 214, + 151, + 114, + 47, + 68, + 98, + 143, + 147, + 120, + 199, + 117, + 64, + 114, + 150, + 105, + 205, + 201, + 178, + 177, + 122, + 155, + 215, + 236, + 113, + 105, + 117, + 212, + 227, + 36, + 194, + 167, + 6, + 142, + 111, + 63, + 246, + 18, + 228, + 168, + 11, + 94, + 195, + 19, + 29, + 97, + 187, + 202, + 109, + 161, + 115, + 183, + 113, + 134, + 157, + 9, + 63, + 40, + 196, + 131, + 145, + 239, + 239, + 94, + 88, + 222, + 105, + 76, + 89, + 251, + 204, + 99, + 220, + 165, + 168, + 18, + 162, + 89, + 36, + 158, + 229, + 172, + 142, + 90, + 220, + 19, + 192, + 235, + 110, + 123, + 20, + 132, + 79, + 24, + 181, + 123, + 206, + 175, + 229, + 89, + 225, + 39, + 131, + 133, + 126, + 169, + 42, + 223, + 119, + 192, + 1, + 37, + 118, + 66, + 157, + 41, + 95, + 215, + 211, + 53, + 63, + 41, + 144, + 55, + 68, + 69, + 96, + 230, + 226, + 25, + 217, + 217, + 254, + 41, + 91, + 139, + 87, + 123, + 191, + 15, + 48, + 54, + 166, + 12, + 121, + 68, + 231, + 254, + 231, + 183, + 219, + 28, + 42, + 92, + 148, + 57, + 24, + 67, + 228, + 114, + 117, + 108, + 99, + 181, + 92, + 239, + 27, + 19, + 5, + 16, + 121, + 72, + 26, + 248, + 20, + 175, + 26, + 93, + 218, + 67, + 252, + 187, + 58, + 125, + 107, + 104, + 170, + 170, + 61, + 24, + 53, + 230, + 11, + 92, + 77, + 17, + 122, + 100, + 245, + 14, + 38, + 41, + 173, + 87, + 49, + 183, + 44, + 171, + 34, + 250, + 149, + 189, + 23, + 149, + 115, + 136, + 82, + 177, + 87, + 155, + 50, + 152, + 120, + 237, + 88, + 240, + 215, + 80, + 201, + 192, + 163, + 17, + 170, + 179, + 252, + 9, + 49, + 3, + 147, + 151, + 201, + 107, + 228, + 241, + 192, + 184, + 16, + 168, + 1, + 251, + 116, + 146, + 37, + 94, + 213, + 2, + 234, + 164, + 32, + 171, + 175, + 135, + 33, + 58, + 178, + 212, + 240, + 159, + 168, + 245, + 251, + 82, + 119, + 177, + 219, + 164, + 86, + 254, + 97, + 76, + 100, + 61, + 44, + 243, + 35, + 221, + 25, + 63, + 235, + 90, + 187, + 105, + 248, + 134, + 84, + 134, + 155, + 79, + 149, + 167, + 121, + 152, + 62, + 19, + 97, + 180, + 122, + 100, + 226, + 14, + 164, + 139, + 90, + 27, + 232, + 153, + 134, + 205, + 131, + 100, + 134, + 247, + 218, + 230, + 210, + 189, + 140, + 38, + 176, + 119, + 199, + 206, + 249, + 218, + 37, + 146, + 83, + 175, + 146, + 62, + 113, + 254, + 101, + 46, + 71, + 99, + 4, + 108, + 154, + 216, + 152, + 196, + 116, + 128, + 1, + 80, + 73, + 34, + 148, + 118, + 185, + 224, + 86, + 254, + 222, + 206, + 17, + 241, + 70, + 214, + 129, + 146, + 94, + 49, + 116, + 242, + 91, + 244, + 162, + 224, + 114, + 180, + 112, + 72, + 56, + 242, + 179, + 244, + 230, + 29, + 185, + 156, + 55, + 21, + 183, + 148, + 138, + 208, + 230, + 98, + 135, + 82, + 12, + 190, + 113, + 157, + 158, + 137, + 44, + 253, + 4, + 164, + 190, + 4, + 207, + 133, + 145, + 225, + 160, + 136, + 14, + 253, + 48, + 240, + 165, + 125, + 171, + 135, + 183, + 134, + 219, + 155, + 253, + 65, + 101, + 94, + 188, + 233, + 234, + 163, + 49, + 147, + 68, + 31, + 142, + 7, + 91, + 39, + 3, + 186, + 223, + 181, + 233, + 59, + 183, + 249, + 11, + 230, + 206, + 60, + 24, + 111, + 216, + 66, + 62, + 104, + 15, + 70, + 114, + 138, + 86, + 70, + 18, + 118, + 215, + 217, + 64, + 9, + 146, + 55, + 71, + 79, + 98, + 95, + 66, + 45, + 106, + 235, + 159, + 6, + 6, + 95, + 155, + 20, + 90, + 212, + 5, + 208, + 156, + 51, + 33, + 164, + 25, + 117, + 81, + 253, + 248, + 246, + 21, + 4, + 72, + 168, + 184, + 7, + 58, + 57, + 71, + 69, + 131, + 89, + 223, + 165, + 236, + 202, + 242, + 125, + 39, + 245, + 232, + 212, + 59, + 24, + 138, + 210, + 167, + 33, + 104, + 182, + 116, + 152, + 133, + 4, + 179, + 124, + 24, + 53, + 49, + 34, + 255, + 20, + 114, + 66, + 110, + 34, + 5, + 237, + 221, + 12, + 59, + 244, + 138, + 216, + 227, + 205, + 150, + 92, + 225, + 63, + 20, + 35, + 192, + 137, + 56, + 250, + 62, + 73, + 189, + 196, + 103, + 93, + 241, + 42, + 146, + 12, + 225, + 196, + 186, + 126, + 208, + 244, + 36, + 201, + 105, + 133, + 210, + 253, + 34, + 126, + 119, + 158, + 48, + 1, + 70, + 25, + 19, + 187, + 135, + 100, + 131, + 71, + 223, + 60, + 255, + 206, + 249, + 203, + 209, + 211, + 77, + 239, + 40, + 152, + 52, + 66, + 152, + 80, + 13, + 129, + 123, + 92, + 114, + 92, + 14, + 234, + 120, + 207, + 94, + 51, + 153, + 168, + 253, + 147, + 178, + 230, + 141, + 193, + 207, + 152, + 248, + 39, + 72, + 119, + 149, + 182, + 71, + 165, + 103, + 209, + 168, + 105, + 152, + 78, + 46, + 107, + 87, + 145, + 78, + 192, + 115, + 9, + 0, + 116, + 90, + 15, + 184, + 92, + 101, + 139, + 146, + 154, + 188, + 164, + 242, + 58, + 219, + 228, + 185, + 42, + 45, + 245, + 122, + 141, + 184, + 189, + 188, + 27, + 100, + 166, + 43, + 95, + 43, + 118, + 188, + 169, + 166, + 25, + 14, + 8, + 209, + 175, + 3, + 32, + 127, + 129, + 52, + 32, + 86, + 234, + 25, + 92, + 203, + 168, + 111, + 223, + 7, + 236, + 113, + 228, + 64, + 179, + 122, + 16, + 119, + 28, + 52, + 179, + 213, + 10, + 59, + 202, + 11, + 190, + 32, + 114, + 214, + 140, + 123, + 102, + 12, + 81, + 133, + 198, + 173, + 225, + 22, + 158, + 237, + 97, + 65, + 24, + 33, + 47, + 86, + 228, + 139, + 40, + 22, + 161, + 185, + 29, + 8, + 122, + 163, + 62, + 243, + 216, + 181, + 185, + 123, + 154, + 175, + 68, + 91, + 202, + 63, + 248, + 183, + 181, + 126, + 149, + 134, + 149, + 60, + 28, + 151, + 6, + 161, + 224, + 228, + 250, + 93, + 174, + 110, + 55, + 243, + 149, + 229, + 185, + 116, + 142, + 188, + 22, + 254, + 99, + 174, + 143, + 78, + 146, + 120, + 253, + 220, + 8, + 130, + 189, + 77, + 17, + 39, + 129, + 13, + 232, + 165, + 232, + 170, + 22, + 103, + 143, + 53, + 90, + 171, + 215, + 196, + 147, + 23, + 97, + 87, + 25, + 26, + 229, + 222, + 107, + 187, + 95, + 86, + 173, + 70, + 28, + 54, + 186, + 190, + 154, + 62, + 120, + 154, + 188, + 161, + 82, + 250, + 76, + 177, + 182, + 139, + 72, + 196, + 0, + 58, + 198, + 58, + 35, + 131, + 77, + 96, + 140, + 46, + 84, + 179, + 77, + 174, + 232, + 83, + 15, + 183, + 170, + 224, + 14, + 44, + 198, + 46, + 162, + 216, + 76, + 110, + 155, + 7, + 37, + 106, + 244, + 79, + 126, + 91, + 172, + 133, + 144, + 141, + 107, + 195, + 35, + 42, + 62, + 153, + 130, + 41, + 115, + 118, + 241, + 82, + 61, + 223, + 231, + 86, + 165, + 35, + 194, + 198, + 134, + 26, + 212, + 78, + 187, + 217, + 36, + 107, + 117, + 136, + 177, + 40, + 144, + 5, + 214, + 23, + 126, + 172, + 66, + 60, + 249, + 114, + 3, + 44, + 39, + 230, + 253, + 136, + 195, + 98, + 29, + 123, + 237, + 84, + 148, + 115, + 181, + 227, + 195, + 60, + 15, + 206, + 75, + 93, + 177, + 181, + 234, + 115, + 27, + 134, + 95, + 98, + 58, + 161, + 2, + 31, + 63, + 211, + 1, + 145, + 12, + 152, + 81, + 106, + 234, + 150, + 147, + 5, + 61, + 77, + 220, + 43, + 97, + 30, + 47, + 194, + 184, + 141, + 112, + 58, + 193, + 237, + 252, + 79, + 122, + 189, + 40, + 163, + 211, + 13, + 85, + 192, + 59, + 229, + 168, + 206, + 173, + 148, + 222, + 202, + 166, + 97, + 86, + 128, + 68, + 96, + 127, + 207, + 219, + 76, + 241, + 61, + 40, + 172, + 107, + 6, + 137, + 240, + 30, + 38, + 152, + 125, + 124, + 221, + 131, + 139, + 59, + 223, + 33, + 243, + 41, + 215, + 20, + 201, + 162, + 193, + 14, + 119, + 244, + 55, + 6, + 43, + 192, + 22, + 229, + 127, + 156, + 82, + 164, + 122, + 226, + 135, + 223, + 135, + 247, + 38, + 167, + 238, + 129, + 69, + 128, + 46, + 252, + 95, + 40, + 152, + 14, + 0, + 246, + 233, + 227, + 196, + 177, + 37, + 6, + 135, + 153, + 64, + 180, + 113, + 111, + 42, + 125, + 101, + 16, + 106, + 250, + 115, + 145, + 69, + 106, + 11, + 188, + 97, + 180, + 42, + 68, + 238, + 31, + 224, + 49, + 1, + 29, + 145, + 240, + 126, + 82, + 193, + 57, + 148, + 124, + 31, + 172, + 224, + 243, + 208, + 251, + 182, + 185, + 28, + 71, + 88, + 218, + 2, + 113, + 86, + 74, + 232, + 15, + 166, + 223, + 40, + 17, + 9, + 128, + 112, + 253, + 236, + 130, + 225, + 179, + 221, + 245, + 42, + 84, + 250, + 55, + 219, + 76, + 19, + 56, + 246, + 101, + 140, + 85, + 83, + 49, + 77, + 29, + 66, + 44, + 237, + 102, + 206, + 214, + 138, + 117, + 115, + 77, + 167, + 171, + 114, + 60, + 230, + 29, + 76, + 154, + 59, + 27, + 176, + 62, + 184, + 80, + 7, + 166, + 19, + 188, + 59, + 56, + 149, + 71, + 126, + 20, + 143, + 214, + 28, + 243, + 129, + 104, + 27, + 244, + 71, + 127, + 6, + 46, + 114, + 225, + 24, + 81, + 139, + 245, + 81, + 114, + 75, + 185, + 241, + 93, + 102, + 121, + 229, + 71, + 163, + 105, + 194, + 204, + 116, + 54, + 107, + 40, + 116, + 180, + 247, + 151, + 218, + 8, + 23, + 130, + 187, + 0, + 84, + 48, + 203, + 31, + 151, + 116, + 137, + 154, + 13, + 228, + 91, + 18, + 191, + 78, + 196, + 63, + 110, + 249, + 63, + 244, + 160, + 159, + 104, + 208, + 244, + 249, + 46, + 171, + 141, + 16, + 4, + 120, + 36, + 215, + 37, + 63, + 126, + 3, + 126, + 170, + 196, + 66, + 144, + 88, + 17, + 233, + 249, + 138, + 125, + 27, + 126, + 226, + 36, + 59, + 67, + 111, + 35, + 212, + 51, + 187, + 212, + 211, + 192, + 152, + 101, + 73, + 164, + 164, + 252, + 232, + 61, + 223, + 183, + 221, + 20, + 255, + 152, + 53, + 5, + 120, + 44, + 124, + 180, + 190, + 69, + 246, + 102, + 219, + 234, + 133, + 129, + 85, + 243, + 241, + 134, + 236, + 36, + 122, + 209, + 28, + 168, + 111, + 237, + 144, + 49, + 247, + 9, + 201, + 186, + 195, + 109, + 18, + 153, + 133, + 106, + 169, + 102, + 145, + 181, + 118, + 243, + 165, + 11, + 234, + 115, + 157, + 128, + 145, + 101, + 65, + 248, + 4, + 109, + 227, + 249, + 231, + 206, + 26, + 116, + 230, + 82, + 6, + 56, + 182, + 46, + 46, + 118, + 95, + 52, + 0, + 99, + 137, + 254, + 208, + 158, + 222, + 41, + 235, + 238, + 97, + 110, + 242, + 215, + 167, + 193, + 107, + 123, + 185, + 244, + 104, + 178, + 96, + 206, + 64, + 198, + 98, + 217, + 55, + 197, + 204, + 10, + 10, + 176, + 176, + 239, + 28, + 87, + 152, + 255, + 160, + 109, + 223, + 44, + 99, + 21, + 196, + 244, + 228, + 65, + 33, + 32, + 72, + 81, + 141, + 202, + 100, + 38, + 75, + 4, + 89, + 15, + 90, + 255, + 182, + 101, + 69, + 25, + 97, + 238, + 81, + 187, + 217, + 83, + 208, + 43, + 119, + 104, + 225, + 227, + 221, + 62, + 167, + 226, + 86, + 20, + 254, + 54, + 106, + 227, + 169, + 164, + 39, + 31, + 96, + 39, + 116, + 90, + 167, + 198, + 131, + 40, + 22, + 135, + 167, + 15, + 27, + 95, + 100, + 26, + 184, + 86, + 154, + 47, + 212, + 51, + 100, + 98, + 188, + 246, + 80, + 193, + 16, + 142, + 187, + 205, + 110, + 80, + 194, + 56, + 91, + 139, + 202, + 53, + 44, + 63, + 255, + 67, + 149, + 33, + 140, + 132, + 33, + 171, + 110, + 244, + 68, + 108, + 210, + 138, + 64, + 41, + 247, + 67, + 185, + 147, + 45, + 253, + 6, + 146, + 121, + 116, + 22, + 236, + 244, + 136, + 210, + 163, + 180, + 111, + 245, + 97, + 4, + 45, + 240, + 231, + 253, + 238, + 61, + 32, + 29, + 18, + 241, + 202, + 86, + 163, + 154, + 43, + 214, + 47, + 225, + 157, + 59, + 191, + 45, + 72, + 123, + 112, + 55, + 95, + 203, + 134, + 84, + 48, + 253, + 36, + 43, + 128, + 141, + 186, + 208, + 123, + 175, + 194, + 113, + 147, + 235, + 207, + 173, + 219, + 103, + 126, + 109, + 5, + 58, + 163, + 23, + 88, + 155, + 201, + 128, + 255, + 34, + 165, + 240, + 94, + 213, + 97, + 77, + 81, + 93, + 31, + 92, + 218, + 30, + 22, + 131, + 83, + 250, + 251, + 207, + 27, + 14, + 105, + 6, + 116, + 217, + 118, + 15, + 111, + 133, + 206, + 156, + 208, + 108, + 16, + 39, + 95, + 60, + 33, + 44, + 197, + 77, + 206, + 37, + 149, + 66, + 58, + 194, + 168, + 183, + 157, + 9, + 11, + 10, + 62, + 15, + 136, + 20, + 69, + 14, + 212, + 196, + 239, + 85, + 230, + 75, + 244, + 231, + 19, + 16, + 202, + 76, + 194, + 34, + 125, + 160, + 42, + 96, + 66, + 46, + 71, + 36, + 148, + 189, + 44, + 35, + 215, + 57, + 37, + 111, + 158, + 202, + 74, + 124, + 73, + 108, + 22, + 83, + 222, + 185, + 14, + 79, + 126, + 213, + 30, + 127, + 161, + 37, + 0, + 133, + 207, + 67, + 232, + 203, + 121, + 45, + 118, + 248, + 91, + 231, + 92, + 250, + 49, + 178, + 243, + 211, + 213, + 89, + 185, + 169, + 252, + 19, + 89, + 89, + 130, + 146, + 234, + 178, + 140, + 11, + 254, + 121, + 223, + 120, + 194, + 25, + 183, + 190, + 83, + 86, + 10, + 40, + 31, + 5, + 125, + 42, + 97, + 13, + 66, + 213, + 108, + 135, + 10, + 22, + 12, + 137, + 130, + 162, + 182, + 109, + 214, + 179, + 2, + 249, + 158, + 7, + 141, + 90, + 109, + 30, + 219, + 78, + 31, + 149, + 182, + 208, + 191, + 170, + 80, + 120, + 180, + 162, + 76, + 34, + 196, + 102, + 42, + 228, + 241, + 234, + 86, + 25, + 229, + 89, + 253, + 173, + 44, + 220, + 137, + 70, + 11, + 153, + 35, + 157, + 88, + 148, + 214, + 138, + 163, + 130, + 64, + 165, + 139, + 167, + 53, + 193, + 52, + 53, + 7, + 66, + 74, + 232, + 241, + 0, + 43, + 170, + 227, + 233, + 106, + 231, + 64, + 37, + 183, + 199, + 30, + 219, + 70, + 12, + 110, + 195, + 52, + 28, + 183, + 169, + 64, + 120, + 107, + 4, + 210, + 194, + 37, + 170, + 89, + 182, + 13, + 161, + 231, + 88, + 251, + 233, + 229, + 253, + 152, + 122, + 218, + 39, + 71, + 115, + 33, + 16, + 146, + 156, + 164, + 86, + 149, + 72, + 85, + 128, + 19, + 95, + 229, + 57, + 60, + 128, + 106, + 217, + 189, + 140, + 215, + 154, + 205, + 174, + 85, + 8, + 101, + 75, + 102, + 196, + 190, + 235, + 179, + 117, + 22, + 83, + 85, + 127, + 63, + 224, + 28, + 79, + 177, + 228, + 39, + 68, + 19, + 118, + 52, + 113, + 5, + 22, + 155, + 132, + 3, + 148, + 112, + 108, + 42, + 217, + 46, + 185, + 137, + 44, + 14, + 83, + 241, + 179, + 242, + 243, + 24, + 195, + 135, + 58, + 75, + 188, + 186, + 29, + 88, + 36, + 240, + 0, + 98, + 231, + 107, + 25, + 130, + 214, + 111, + 26, + 138, + 228, + 122, + 77, + 230, + 191, + 165, + 80, + 147, + 84, + 24, + 222, + 6, + 159, + 177, + 90, + 55, + 104, + 252, + 110, + 17, + 163, + 20, + 230, + 142, + 31, + 41, + 118, + 181, + 217, + 107, + 165, + 236, + 215, + 39, + 228, + 191, + 247, + 137, + 113, + 13, + 131, + 193, + 248, + 198, + 122, + 170, + 70, + 6, + 196, + 107, + 223, + 32, + 160, + 113, + 50, + 217, + 42, + 130, + 104, + 167, + 111, + 65, + 39, + 81, + 19, + 10, + 207, + 47, + 188, + 118, + 29, + 212, + 164, + 102, + 142, + 251, + 108, + 255, + 54, + 173, + 106, + 208, + 239, + 99, + 118, + 108, + 207, + 120, + 38, + 84, + 229, + 176, + 248, + 138, + 2, + 60, + 250, + 143, + 18, + 157, + 205, + 158, + 197, + 168, + 29, + 227, + 168, + 213, + 216, + 225, + 57, + 188, + 92, + 145, + 68, + 101, + 133, + 122, + 85, + 162, + 21, + 168, + 36, + 31, + 18, + 218, + 112, + 236, + 51, + 141, + 125, + 211, + 141, + 20, + 8, + 30, + 181, + 110, + 29, + 85, + 99, + 48, + 147, + 201, + 155, + 179, + 205, + 108, + 90, + 211, + 36, + 248, + 50, + 212, + 70, + 145, + 63, + 231, + 208, + 68, + 153, + 54, + 142, + 102, + 193, + 197, + 27, + 156, + 3, + 194, + 19, + 96, + 138, + 27, + 29, + 109, + 142, + 185, + 121, + 104, + 230, + 178, + 64, + 164, + 140, + 18, + 17, + 115, + 216, + 157, + 64, + 11, + 146, + 112, + 246, + 158, + 145, + 252, + 74, + 190, + 230, + 196, + 14, + 153, + 66, + 9, + 195, + 142, + 104, + 218, + 5, + 50, + 79, + 78, + 155, + 77, + 87, + 45, + 41, + 250, + 228, + 255, + 67, + 57, + 196, + 125, + 96, + 14, + 114, + 89, + 172, + 249, + 159, + 122, + 77, + 186, + 31, + 152, + 206, + 178, + 0, + 87, + 174, + 33, + 244, + 228, + 33, + 122, + 149, + 6, + 246, + 190, + 83, + 115, + 232, + 179, + 39, + 87, + 183, + 63, + 155, + 80, + 98, + 78, + 200, + 107, + 199, + 156, + 108, + 5, + 225, + 216, + 213, + 244, + 83, + 53, + 112, + 45, + 1, + 13, + 171, + 50, + 9, + 243, + 94, + 83, + 13, + 123, + 213, + 213, + 194, + 246, + 63, + 164, + 164, + 85, + 133, + 185, + 130, + 49, + 29, + 108, + 181, + 23, + 107, + 93, + 128, + 105, + 137, + 248, + 67, + 20, + 101, + 142, + 251, + 47, + 152, + 216, + 155, + 169, + 176, + 185, + 219, + 202, + 138, + 235, + 51, + 13, + 145, + 36, + 126, + 182, + 116, + 206, + 21, + 164, + 205, + 16, + 149, + 40, + 85, + 179, + 57, + 120, + 234, + 51, + 86, + 1, + 42, + 124, + 58, + 22, + 89, + 165, + 88, + 238, + 22, + 175, + 149, + 206, + 60, + 106, + 170, + 173, + 44, + 211, + 24, + 164, + 219, + 51, + 162, + 107, + 49, + 109, + 191, + 177, + 36, + 1, + 217, + 132, + 162, + 80, + 82, + 133, + 88, + 154, + 199, + 218, + 98, + 198, + 41, + 123, + 51, + 242, + 253, + 228, + 223, + 85, + 138, + 193, + 112, + 36, + 64, + 43, + 234, + 156, + 205, + 17, + 199, + 81, + 105, + 121, + 222, + 77, + 122, + 138, + 2, + 140, + 43, + 45, + 35, + 160, + 112, + 106, + 201, + 253, + 42, + 153, + 80, + 159, + 163, + 36, + 43, + 191, + 154, + 112, + 237, + 32, + 242, + 136, + 90, + 82, + 113, + 214, + 91, + 69, + 115, + 145, + 95, + 155, + 11, + 77, + 47, + 118, + 98, + 229, + 160, + 220, + 135, + 127, + 126, + 232, + 3, + 74, + 166, + 81, + 107, + 59, + 116, + 65, + 8, + 109, + 87, + 191, + 11, + 122, + 131, + 214, + 1, + 91, + 99, + 29, + 202, + 209, + 212, + 54, + 73, + 166, + 168, + 144, + 176, + 188, + 43, + 47, + 186, + 46, + 33, + 124, + 52, + 11, + 217, + 11, + 245, + 177, + 6, + 23, + 213, + 210, + 12, + 217, + 196, + 206, + 120, + 195, + 84, + 53, + 92, + 152, + 72, + 69, + 197, + 237, + 49, + 191, + 254, + 161, + 2, + 199, + 144, + 242, + 144, + 6, + 46, + 52, + 211, + 125, + 158, + 38, + 200, + 41, + 195, + 14, + 86, + 236, + 40, + 153, + 155, + 136, + 44, + 135, + 120, + 22, + 184, + 184, + 166, + 98, + 200, + 93, + 176, + 124, + 14, + 25, + 248, + 26, + 104, + 74, + 113, + 10, + 112, + 68, + 118, + 249, + 80, + 83, + 151, + 205, + 79, + 81, + 7, + 216, + 125, + 166, + 83, + 16, + 232, + 123, + 243, + 70, + 124, + 217, + 214, + 136, + 26, + 111, + 187, + 91, + 67, + 226, + 10, + 112, + 200, + 210, + 126, + 114, + 169, + 0, + 84, + 22, + 108, + 19, + 118, + 97, + 113, + 13, + 76, + 227, + 222, + 151, + 43, + 43, + 85, + 30, + 67, + 45, + 209, + 91, + 240, + 17, + 44, + 135, + 245, + 84, + 224, + 155, + 225, + 25, + 111, + 230, + 13, + 22, + 0, + 240, + 112, + 60, + 255, + 175, + 125, + 234, + 147, + 237, + 253, + 139, + 63, + 61, + 36, + 47, + 253, + 80, + 187, + 5, + 170, + 241, + 41, + 108, + 174, + 196, + 242, + 105, + 110, + 111, + 2, + 44, + 142, + 105, + 85, + 16, + 198, + 48, + 112, + 76, + 244, + 39, + 221, + 99, + 109, + 135, + 46, + 82, + 143, + 208, + 5, + 106, + 214, + 254, + 163, + 93, + 199, + 215, + 38, + 35, + 140, + 52, + 157, + 52, + 165, + 217, + 0, + 237, + 80, + 146, + 19, + 250, + 51, + 207, + 153, + 27, + 202, + 50, + 86, + 180, + 34, + 116, + 220, + 43, + 240, + 143, + 72, + 107, + 249, + 26, + 163, + 108, + 182, + 166, + 107, + 132, + 30, + 106, + 1, + 128, + 232, + 51, + 4, + 134, + 14, + 108, + 177, + 198, + 31, + 211, + 235, + 156, + 225, + 30, + 230, + 62, + 160, + 11, + 198, + 203, + 189, + 168, + 100, + 171, + 185, + 88, + 246, + 30, + 0, + 169, + 243, + 27, + 51, + 242, + 39, + 52, + 214, + 163, + 36, + 36, + 81, + 27, + 134, + 111, + 201, + 178, + 218, + 38, + 175, + 108, + 164, + 26, + 152, + 140, + 13, + 24, + 48, + 99, + 161, + 250, + 6, + 22, + 172, + 30, + 139, + 72, + 75, + 220, + 139, + 11, + 47, + 58, + 14, + 134, + 77, + 4, + 224, + 200, + 21, + 95, + 120, + 120, + 240, + 34, + 23, + 65, + 167, + 230, + 153, + 108, + 119, + 103, + 59, + 5, + 213, + 123, + 18, + 125, + 179, + 226, + 174, + 200, + 131, + 69, + 139, + 3, + 50, + 205, + 63, + 71, + 25, + 12, + 162, + 114, + 246, + 141, + 23, + 242, + 215, + 113, + 180, + 94, + 165, + 6, + 97, + 215, + 20, + 162, + 112, + 43, + 140, + 100, + 191, + 125, + 244, + 214, + 176, + 245, + 77, + 228, + 6, + 37, + 230, + 11, + 103, + 4, + 82, + 152, + 252, + 40, + 119, + 96, + 200, + 159, + 182, + 124, + 103, + 164, + 80, + 86, + 17, + 243, + 157, + 214, + 223, + 156, + 227, + 101, + 115, + 89, + 132, + 137, + 5, + 188, + 130, + 55, + 31, + 99, + 112, + 99, + 96, + 253, + 143, + 50, + 234, + 5, + 38, + 188, + 250, + 81, + 44, + 149, + 221, + 198, + 237, + 245, + 184, + 92, + 170, + 104, + 109, + 231, + 109, + 101, + 166, + 106, + 186, + 110, + 222, + 213, + 44, + 113, + 150, + 201, + 169, + 56, + 19, + 91, + 47, + 82, + 83, + 6, + 88, + 126, + 29, + 153, + 208, + 149, + 42, + 212, + 58, + 56, + 188, + 160, + 233, + 102, + 38, + 57, + 17, + 0, + 239, + 64, + 15, + 221, + 199, + 144, + 56, + 105, + 3, + 51, + 98, + 52, + 89, + 129, + 73, + 26, + 126, + 136, + 45, + 215, + 128, + 21, + 78, + 99, + 67, + 104, + 45, + 61, + 95, + 104, + 201, + 86, + 224, + 103, + 189, + 81, + 145, + 48, + 205, + 159, + 71, + 113, + 77, + 12, + 218, + 187, + 186, + 50, + 6, + 37, + 150, + 216, + 26, + 14, + 159, + 49, + 243, + 155, + 34, + 185, + 80, + 154, + 49, + 21, + 239, + 139, + 170, + 180, + 103, + 92, + 115, + 13, + 248, + 200, + 192, + 47, + 209, + 155, + 211, + 97, + 227, + 147, + 147, + 44, + 111, + 64, + 244, + 94, + 212, + 139, + 96, + 50, + 120, + 143, + 106, + 53, + 16, + 146, + 2, + 186, + 103, + 78, + 132, + 54, + 70, + 214, + 210, + 36, + 4, + 116, + 138, + 138, + 56, + 55, + 136, + 161, + 174, + 64, + 93, + 132, + 132, + 10, + 177, + 227, + 216, + 97, + 218, + 106, + 178, + 225, + 131, + 5, + 188, + 142, + 37, + 33, + 182, + 204, + 156, + 107, + 75, + 233, + 247, + 0, + 253, + 23, + 52, + 142, + 231, + 83, + 195, + 98, + 1, + 9, + 17, + 65, + 196, + 184, + 24, + 82, + 23, + 122, + 233, + 193, + 249, + 3, + 249, + 36, + 111, + 95, + 49, + 247, + 173, + 129, + 82, + 205, + 196, + 214, + 112, + 225, + 234, + 87, + 242, + 191, + 50, + 253, + 212, + 147, + 252, + 215, + 220, + 44, + 163, + 204, + 56, + 103, + 247, + 65, + 83, + 85, + 193, + 133, + 37, + 245, + 183, + 26, + 96, + 174, + 40, + 91, + 74, + 213, + 239, + 34, + 36, + 91, + 126, + 108, + 209, + 124, + 145, + 165, + 196, + 95, + 253, + 165, + 156, + 98, + 249, + 180, + 182, + 218, + 83, + 36, + 101, + 188, + 14, + 245, + 80, + 123, + 169, + 42, + 75, + 69, + 129, + 59, + 103, + 222, + 70, + 202, + 141, + 100, + 92, + 98, + 9, + 16, + 64, + 212, + 176, + 213, + 229, + 22, + 17, + 180, + 2, + 52, + 99, + 69, + 211, + 138, + 7, + 86, + 146, + 139, + 43, + 65, + 132, + 93, + 101, + 165, + 71, + 203, + 197, + 205, + 216, + 228, + 224, + 63, + 135, + 244, + 97, + 148, + 32, + 174, + 83, + 177, + 5, + 230, + 3, + 219, + 211, + 97, + 55, + 3, + 83, + 182, + 82, + 124, + 108, + 87, + 101, + 243, + 118, + 123, + 250, + 219, + 79, + 144, + 227, + 107, + 161, + 190, + 107, + 247, + 84, + 51, + 199, + 142, + 152, + 64, + 251, + 183, + 72, + 236, + 53, + 142, + 57, + 249, + 131, + 238, + 136, + 73, + 138, + 27, + 119, + 146, + 113, + 250, + 93, + 119, + 191, + 64, + 238, + 107, + 158, + 255, + 87, + 108, + 213, + 206, + 180, + 65, + 14, + 0, + 98, + 132, + 19, + 250, + 9, + 43, + 243, + 215, + 9, + 231, + 159, + 201, + 103, + 249, + 23, + 140, + 192, + 73, + 244, + 83, + 181, + 71, + 57, + 250, + 125, + 2, + 5, + 156, + 241, + 37, + 204, + 19, + 138, + 36, + 142, + 34, + 149, + 202, + 158, + 179, + 59, + 187, + 100, + 252, + 114, + 255, + 151, + 54, + 46, + 77, + 186, + 91, + 246, + 89, + 205, + 81, + 68, + 252, + 129, + 96, + 6, + 39, + 118, + 62, + 210, + 73, + 136, + 199, + 98, + 193, + 122, + 54, + 116, + 143, + 234, + 54, + 215, + 223, + 121, + 219, + 223, + 227, + 140, + 115, + 36, + 238, + 120, + 201, + 38, + 31, + 24, + 77, + 29, + 97, + 113, + 182, + 42, + 179, + 29, + 242, + 110, + 195, + 85, + 31, + 205, + 112, + 94, + 81, + 115, + 134, + 72, + 124, + 81, + 236, + 146, + 2, + 188, + 76, + 163, + 142, + 43, + 235, + 95, + 79, + 148, + 170, + 91, + 127, + 122, + 211, + 116, + 248, + 96, + 253, + 71, + 133, + 189, + 222, + 86, + 1, + 102, + 91, + 157, + 113, + 91, + 50, + 59, + 102, + 183, + 60, + 121, + 196, + 200, + 25, + 30, + 204, + 30, + 119, + 166, + 177, + 182, + 184, + 146, + 99, + 171, + 233, + 26, + 76, + 60, + 193, + 3, + 209, + 208, + 183, + 54, + 167, + 54, + 146, + 3, + 60, + 253, + 138, + 168, + 100, + 210, + 219, + 52, + 141, + 176, + 250, + 237, + 24, + 227, + 117, + 25, + 138, + 195, + 57, + 221, + 5, + 105, + 21, + 141, + 109, + 68, + 252, + 218, + 39, + 221, + 184, + 119, + 19, + 208, + 128, + 57, + 156, + 36, + 209, + 213, + 173, + 52, + 41, + 241, + 177, + 99, + 220, + 138, + 204, + 183, + 49, + 32, + 34, + 111, + 38, + 55, + 141, + 0, + 167, + 26, + 53, + 153, + 201, + 157, + 51, + 74, + 33, + 95, + 86, + 78, + 218, + 118, + 247, + 53, + 159, + 130, + 9, + 237, + 21, + 215, + 11, + 42, + 134, + 133, + 2, + 118, + 155, + 224, + 29, + 59, + 135, + 174, + 25, + 205, + 243, + 1, + 20, + 127, + 162, + 23, + 9, + 64, + 121, + 137, + 21, + 164, + 233, + 214, + 136, + 174, + 41, + 235, + 205, + 117, + 115, + 188, + 46, + 203, + 234, + 87, + 50, + 68, + 44, + 126, + 190, + 25, + 225, + 17, + 78, + 47, + 207, + 253, + 69, + 132, + 161, + 88, + 94, + 188, + 166, + 80, + 245, + 46, + 194, + 187, + 31, + 190, + 58, + 198, + 197, + 0, + 122, + 79, + 124, + 107, + 101, + 110, + 62, + 182, + 203, + 241, + 23, + 62, + 190, + 80, + 246, + 246, + 73, + 104, + 155, + 40, + 32, + 36, + 178, + 105, + 235, + 186, + 88, + 94, + 33, + 31, + 169, + 103, + 251, + 189, + 150, + 24, + 223, + 85, + 201, + 201, + 60, + 64, + 106, + 106, + 234, + 23, + 96, + 12, + 141, + 246, + 178, + 12, + 36, + 195, + 222, + 129, + 192, + 33, + 37, + 108, + 25, + 189, + 79, + 39, + 80, + 147, + 173, + 26, + 223, + 114, + 76, + 226, + 120, + 153, + 113, + 34, + 221, + 205, + 12, + 24, + 176, + 168, + 109, + 195, + 247, + 200, + 45, + 178, + 39, + 102, + 182, + 58, + 209, + 87, + 16, + 27, + 230, + 214, + 113, + 9, + 121, + 198, + 2, + 131, + 181, + 206, + 41, + 27, + 68, + 48, + 165, + 31, + 73, + 242, + 253, + 46, + 12, + 182, + 216, + 74, + 60, + 76, + 89, + 101, + 191, + 254, + 68, + 23, + 47, + 6, + 148, + 119, + 240, + 186, + 86, + 17, + 21, + 154, + 78, + 76, + 4, + 42, + 55, + 67, + 96, + 114, + 249, + 170, + 102, + 226, + 71, + 238, + 208, + 147, + 33, + 236, + 196, + 224, + 248, + 161, + 92, + 207, + 87, + 139, + 253, + 65, + 13, + 56, + 159, + 229, + 115, + 109, + 148, + 5, + 191, + 249, + 46, + 253, + 48, + 236, + 247, + 55, + 2, + 130, + 142, + 212, + 86, + 57, + 192, + 10, + 21, + 129, + 251, + 36, + 246, + 47, + 29, + 130, + 135, + 122, + 222, + 200, + 113, + 116, + 112, + 168, + 154, + 122, + 30, + 128, + 6, + 252, + 27, + 59, + 173, + 205, + 130, + 140, + 174, + 210, + 18, + 149, + 45, + 217, + 144, + 52, + 200, + 203, + 29, + 3, + 49, + 42, + 196, + 33, + 41, + 69, + 233, + 63, + 232, + 241, + 242, + 235, + 47, + 53, + 213, + 218, + 5, + 166, + 52, + 15, + 194, + 253, + 78, + 134, + 102, + 241, + 166, + 112, + 55, + 155, + 104, + 176, + 28, + 74, + 83, + 29, + 10, + 166, + 110, + 12, + 163, + 58, + 161, + 82, + 191, + 187, + 19, + 85, + 82, + 191, + 78, + 73, + 149, + 221, + 74, + 98, + 157, + 78, + 244, + 218, + 114, + 109, + 73, + 39, + 200, + 36, + 209, + 140, + 72, + 211, + 2, + 60, + 216, + 97, + 242, + 252, + 216, + 85, + 6, + 213, + 5, + 41, + 9, + 131, + 105, + 15, + 245, + 131, + 64, + 183, + 130, + 14, + 103, + 215, + 119, + 22, + 210, + 11, + 238, + 210, + 34, + 158, + 249, + 157, + 78, + 185, + 23, + 198, + 137, + 200, + 14, + 92, + 16, + 192, + 92, + 122, + 97, + 140, + 89, + 62, + 216, + 119, + 176, + 128, + 22, + 129, + 122, + 60, + 36, + 95, + 129, + 78, + 107, + 56, + 166, + 74, + 213, + 190, + 73, + 234, + 68, + 72, + 23, + 79, + 186, + 47, + 224, + 16, + 0, + 78, + 251, + 229, + 226, + 189, + 69, + 202, + 232, + 118, + 253, + 107, + 127, + 17, + 185, + 182, + 1, + 139, + 199, + 109, + 228, + 106, + 134, + 247, + 93, + 1, + 156, + 189, + 177, + 101, + 86, + 60, + 176, + 250, + 65, + 191, + 200, + 92, + 174, + 100, + 215, + 11, + 141, + 105, + 101, + 201, + 107, + 212, + 82, + 17, + 247, + 16, + 94, + 3, + 76, + 254, + 182, + 91, + 173, + 218, + 245, + 237, + 23, + 83, + 63, + 108, + 60, + 208, + 135, + 30, + 102, + 30, + 141, + 158, + 167, + 168, + 4, + 109, + 195, + 249, + 58, + 137, + 218, + 202, + 157, + 239, + 207, + 238, + 148, + 54, + 40, + 14, + 176, + 89, + 52, + 74, + 84, + 72, + 230, + 69, + 59, + 35, + 201, + 176, + 207, + 3, + 195, + 118, + 50, + 121, + 94, + 185, + 102, + 2, + 160, + 173, + 54, + 195, + 8, + 242, + 37, + 21, + 70, + 225, + 44, + 79, + 107, + 24, + 29, + 210, + 150, + 126, + 29, + 62, + 177, + 124, + 182, + 13, + 95, + 125, + 210, + 47, + 103, + 223, + 3, + 120, + 231, + 154, + 125, + 3, + 230, + 168, + 35, + 89, + 110, + 111, + 13, + 121, + 136, + 251, + 113, + 102, + 181, + 242, + 175, + 188, + 194, + 173, + 157, + 137, + 164, + 229, + 159, + 254, + 24, + 57, + 59, + 58, + 242, + 167, + 135, + 98, + 181, + 99, + 50, + 149, + 33, + 28, + 155, + 99, + 52, + 166, + 187, + 164, + 123, + 36, + 62, + 37, + 132, + 236, + 234, + 195, + 174, + 87, + 139, + 109, + 227, + 41, + 54, + 65, + 185, + 146, + 246, + 27, + 142, + 125, + 57, + 140, + 159, + 68, + 140, + 150, + 133, + 243, + 182, + 30, + 178, + 203, + 179, + 66, + 11, + 40, + 42, + 117, + 179, + 13, + 251, + 177, + 116, + 156, + 108, + 85, + 34, + 89, + 107, + 198, + 146, + 129, + 28, + 78, + 98, + 159, + 178, + 209, + 173, + 206, + 171, + 162, + 110, + 108, + 73, + 138, + 124, + 38, + 120, + 83, + 3, + 113, + 197, + 244, + 209, + 81, + 37, + 194, + 159, + 42, + 57, + 202, + 208, + 236, + 209, + 185, + 48, + 70, + 80, + 197, + 112, + 224, + 133, + 29, + 31, + 159, + 240, + 46, + 215, + 41, + 5, + 89, + 236, + 192, + 250, + 142, + 44, + 246, + 15, + 3, + 220, + 123, + 171, + 138, + 58, + 72, + 151, + 196, + 211, + 18, + 13, + 106, + 28, + 75, + 168, + 239, + 59, + 207, + 220, + 196, + 111, + 97, + 202, + 44, + 17, + 247, + 180, + 1, + 143, + 254, + 41, + 214, + 97, + 141, + 30, + 52, + 160, + 124, + 68, + 23, + 30, + 95, + 48, + 215, + 87, + 201, + 130, + 151, + 247, + 126, + 70, + 250, + 145, + 183, + 161, + 34, + 217, + 197, + 75, + 155, + 191, + 21, + 2, + 250, + 114, + 148, + 246, + 132, + 251, + 34, + 98, + 215, + 180, + 244, + 152, + 34, + 46, + 181, + 176, + 205, + 3, + 174, + 41, + 232, + 250, + 131, + 90, + 56, + 103, + 164, + 218, + 163, + 234, + 137, + 52, + 1, + 95, + 144, + 164, + 83, + 200, + 138, + 218, + 57, + 15, + 185, + 110, + 29, + 208, + 32, + 232, + 158, + 34, + 236, + 26, + 20, + 116, + 171, + 115, + 190, + 154, + 236, + 44, + 201, + 213, + 96, + 109, + 141, + 23, + 140, + 229, + 10, + 26, + 192, + 84, + 27, + 50, + 96, + 200, + 162, + 180, + 237, + 154, + 247, + 183, + 121, + 90, + 47, + 231, + 245, + 74, + 99, + 139, + 216, + 180, + 66, + 41, + 111, + 7, + 37, + 48, + 107, + 71, + 160, + 28, + 173, + 113, + 31, + 140, + 223, + 192, + 128, + 155, + 224, + 132, + 232, + 120, + 195, + 237, + 12, + 251, + 50, + 121, + 178, + 137, + 83, + 34, + 210, + 54, + 170, + 107, + 84, + 107, + 35, + 82, + 24, + 45, + 96, + 90, + 38, + 82, + 185, + 117, + 239, + 165, + 198, + 189, + 78, + 142, + 201, + 137, + 242, + 18, + 192, + 12, + 54, + 5, + 196, + 198, + 107, + 129, + 81, + 38, + 99, + 99, + 39, + 24, + 251, + 45, + 159, + 66, + 156, + 222, + 196, + 18, + 10, + 152, + 236, + 35, + 149, + 109, + 0, + 56, + 119, + 44, + 207, + 8, + 213, + 106, + 147, + 135, + 106, + 167, + 245, + 107, + 180, + 224, + 107, + 29, + 85, + 59, + 134, + 44, + 47, + 94, + 116, + 213, + 214, + 107, + 109, + 31, + 161, + 175, + 186, + 10, + 194, + 241, + 67, + 54, + 16, + 197, + 149, + 211, + 192, + 53, + 176, + 53, + 131, + 0, + 222, + 162, + 147, + 21, + 15, + 105, + 113, + 119, + 32, + 171, + 204, + 7, + 22, + 252, + 249, + 163, + 80, + 93, + 131, + 202, + 91, + 165, + 247, + 100, + 126, + 235, + 249, + 48, + 116, + 2, + 15, + 11, + 214, + 61, + 183, + 84, + 202, + 139, + 220, + 117, + 239, + 158, + 108, + 113, + 186, + 134, + 14, + 92, + 89, + 113, + 165, + 42, + 169, + 40, + 166, + 15, + 157, + 97, + 39, + 133, + 186, + 15, + 39, + 36, + 56, + 72, + 135, + 17, + 253, + 147, + 158, + 183, + 43, + 105, + 126, + 129, + 182, + 85, + 43, + 15, + 214, + 136, + 161, + 75, + 77, + 92, + 21, + 76, + 227, + 218, + 57, + 7, + 194, + 28, + 173, + 191, + 233, + 98, + 111, + 245, + 248, + 231, + 239, + 157, + 26, + 23, + 207, + 112, + 62, + 188, + 129, + 53, + 113, + 103, + 11, + 3, + 128, + 0, + 184, + 17, + 3, + 84, + 140, + 190, + 85, + 2, + 65, + 63, + 125, + 199, + 113, + 120, + 195, + 39, + 190, + 128, + 224, + 237, + 109, + 108, + 4, + 164, + 248, + 20, + 23, + 107, + 57, + 251, + 196, + 202, + 254, + 44, + 25, + 232, + 79, + 45, + 189, + 44, + 249, + 73, + 119, + 14, + 38, + 56, + 94, + 120, + 43, + 17, + 22, + 191, + 134, + 172, + 179, + 6, + 243, + 254, + 143, + 252, + 130, + 72, + 168, + 110, + 77, + 42, + 155, + 30, + 204, + 132, + 197, + 106, + 236, + 238, + 57, + 138, + 220, + 115, + 52, + 141, + 159, + 106, + 191, + 54, + 77, + 17, + 168, + 65, + 109, + 156, + 208, + 94, + 71, + 144, + 245, + 71, + 233, + 193, + 56, + 111, + 210, + 96, + 72, + 115, + 147, + 46, + 181, + 15, + 42, + 2, + 225, + 68, + 154, + 46, + 215, + 183, + 165, + 231, + 132, + 177, + 99, + 19, + 210, + 123, + 2, + 157, + 133, + 190, + 245, + 249, + 25, + 91, + 79, + 58, + 22, + 37, + 34, + 34, + 194, + 163, + 126, + 168, + 9, + 218, + 142, + 126, + 53, + 58, + 13, + 121, + 51, + 138, + 131, + 142, + 64, + 237, + 110, + 175, + 73, + 207, + 171, + 200, + 240, + 251, + 4, + 243, + 119, + 12, + 87, + 45, + 135, + 94, + 92, + 92, + 35, + 41, + 183, + 0, + 11, + 147, + 148, + 251, + 224, + 37, + 161, + 235, + 213, + 157, + 251, + 43, + 242, + 217, + 173, + 81, + 175, + 202, + 8, + 191, + 88, + 57, + 180, + 97, + 99, + 7, + 12, + 100, + 87, + 149, + 116, + 62, + 243, + 62, + 25, + 123, + 224, + 122, + 45, + 156, + 193, + 206, + 19, + 175, + 68, + 199, + 252, + 16, + 165, + 179, + 140, + 133, + 72, + 7, + 171, + 149, + 102, + 165, + 4, + 254, + 81, + 104, + 199, + 240, + 21, + 205, + 179, + 141, + 231, + 53, + 175, + 7, + 108, + 180, + 81, + 9, + 168, + 127, + 114, + 41, + 167, + 92, + 119, + 89, + 25, + 111, + 14, + 6, + 73, + 141, + 87, + 157, + 54, + 228, + 189, + 169, + 180, + 51, + 12, + 129, + 246, + 15, + 14, + 149, + 51, + 11, + 83, + 163, + 146, + 89, + 179, + 84, + 219, + 238, + 88, + 176, + 209, + 10, + 94, + 204, + 121, + 57, + 240, + 236, + 40, + 252, + 203, + 131, + 169, + 8, + 113, + 71, + 75, + 162, + 98, + 12, + 166, + 128, + 161, + 115, + 220, + 158, + 204, + 55, + 154, + 221, + 151, + 139, + 210, + 64, + 81, + 208, + 194, + 57, + 56, + 60, + 231, + 126, + 125, + 58, + 119, + 40, + 53, + 12, + 45, + 155, + 243, + 74, + 228, + 12, + 15, + 65, + 181, + 14, + 87, + 61, + 20, + 235, + 106, + 195, + 203, + 97, + 161, + 219, + 71, + 98, + 85, + 190, + 209, + 0, + 228, + 94, + 249, + 115, + 148, + 131, + 217, + 16, + 103, + 134, + 243, + 55, + 118, + 94, + 146, + 167, + 31, + 165, + 28, + 52, + 17, + 41, + 104, + 107, + 234, + 129, + 208, + 102, + 56, + 126, + 54, + 150, + 249, + 32, + 213, + 29, + 1, + 94, + 175, + 205, + 123, + 163, + 219, + 97, + 182, + 58, + 74, + 201, + 71, + 221, + 183, + 65, + 33, + 45, + 157, + 84, + 88, + 136, + 31, + 111, + 81, + 169, + 172, + 184, + 246, + 60, + 119, + 102, + 249, + 144, + 17, + 28, + 175, + 124, + 207, + 179, + 3, + 128, + 245, + 66, + 155, + 223, + 82, + 231, + 34, + 114, + 117, + 110, + 96, + 3, + 121, + 95, + 14, + 171, + 113, + 75, + 90, + 30, + 227, + 240, + 100, + 190, + 113, + 197, + 174, + 204, + 213, + 3, + 103, + 189, + 53, + 229, + 188, + 164, + 65, + 152, + 6, + 94, + 239, + 39, + 2, + 213, + 180, + 23, + 63, + 73, + 136, + 121, + 156, + 207, + 94, + 148, + 172, + 93, + 199, + 54, + 177, + 253, + 70, + 245, + 52, + 164, + 39, + 177, + 69, + 28, + 237, + 118, + 12, + 200, + 5, + 50, + 88, + 133, + 95, + 124, + 165, + 121, + 158, + 146, + 51, + 168, + 228, + 115, + 112, + 135, + 152, + 46, + 67, + 254, + 133, + 46, + 119, + 87, + 46, + 2, + 127, + 228, + 86, + 170, + 252, + 49, + 16, + 49, + 62, + 102, + 42, + 247, + 172, + 18, + 8, + 154, + 232, + 172, + 247, + 31, + 90, + 41, + 221, + 181, + 80, + 14, + 146, + 156, + 245, + 213, + 150, + 131, + 73, + 132, + 199, + 144, + 240, + 200, + 37, + 21, + 245, + 86, + 67, + 77, + 225, + 34, + 108, + 89, + 237, + 14, + 28, + 151, + 89, + 144, + 67, + 140, + 203, + 238, + 42, + 77, + 233, + 89, + 36, + 54, + 144, + 24, + 136, + 26, + 55, + 20, + 146, + 84, + 251, + 189, + 41, + 37, + 97, + 136, + 166, + 106, + 249, + 153, + 230, + 225, + 241, + 77, + 20, + 40, + 200, + 243, + 52, + 224, + 88, + 133, + 244, + 84, + 240, + 40, + 62, + 201, + 160, + 97, + 106, + 61, + 104, + 233, + 79, + 203, + 248, + 25, + 200, + 138, + 80, + 18, + 196, + 42, + 42, + 65, + 141, + 236, + 185, + 36, + 236, + 145, + 94, + 194, + 198, + 111, + 65, + 244, + 250, + 163, + 24, + 37, + 210, + 7, + 92, + 182, + 92, + 128, + 168, + 109, + 176, + 6, + 200, + 226, + 90, + 171, + 142, + 240, + 18, + 100, + 236, + 199, + 36, + 158, + 239, + 147, + 184, + 47, + 186, + 99, + 4, + 14, + 253, + 217, + 101, + 17, + 175, + 191, + 232, + 206, + 217, + 12, + 223, + 179, + 78, + 233, + 108, + 104, + 218, + 161, + 220, + 71, + 112, + 150, + 234, + 154, + 251, + 137, + 50, + 185, + 180, + 63, + 211, + 169, + 102, + 87, + 76, + 108, + 157, + 108, + 44, + 252, + 31, + 118, + 247, + 122, + 62, + 153, + 182, + 147, + 100, + 13, + 194, + 116, + 205, + 23, + 109, + 212, + 197, + 193, + 197, + 124, + 248, + 75, + 148, + 31, + 2, + 2, + 163, + 79, + 219, + 179, + 29, + 198, + 56, + 162, + 250, + 151, + 166, + 224, + 143, + 92, + 113, + 3, + 190, + 174, + 194, + 214, + 55, + 139, + 36, + 210, + 169, + 44, + 220, + 35, + 219, + 217, + 225, + 12, + 159, + 58, + 3, + 67, + 43, + 13, + 170, + 210, + 105, + 7, + 14, + 13, + 251, + 52, + 105, + 206, + 178, + 42, + 151, + 184, + 24, + 169, + 218, + 40, + 122, + 173, + 74, + 248, + 208, + 141, + 119, + 86, + 16, + 8, + 82, + 227, + 101, + 179, + 111, + 192, + 196, + 218, + 185, + 71, + 159, + 241, + 30, + 150, + 149, + 201, + 217, + 168, + 182, + 126, + 112, + 132, + 50, + 237, + 144, + 117, + 181, + 35, + 127, + 14, + 111, + 50, + 37, + 200, + 150, + 195, + 38, + 80, + 224, + 34, + 176, + 28, + 190, + 211, + 136, + 117, + 243, + 251, + 136, + 93, + 172, + 90, + 50, + 130, + 83, + 34, + 166, + 116, + 59, + 147, + 238, + 140, + 253, + 68, + 21, + 137, + 147, + 57, + 62, + 54, + 114, + 195, + 83, + 9, + 18, + 72, + 18, + 184, + 25, + 210, + 164, + 120, + 189, + 226, + 156, + 160, + 106, + 156, + 80, + 192, + 139, + 110, + 203, + 246, + 179, + 79, + 62, + 245, + 174, + 218, + 54, + 172, + 220, + 119, + 90, + 210, + 71, + 207, + 34, + 226, + 158, + 65, + 11, + 75, + 28, + 68, + 91, + 241, + 77, + 197, + 202, + 69, + 219, + 140, + 203, + 179, + 123, + 32, + 152, + 12, + 105, + 3, + 96, + 27, + 177, + 231, + 118, + 31, + 245, + 207, + 225, + 233, + 101, + 66, + 43, + 241, + 89, + 214, + 247, + 248, + 223, + 255, + 7, + 205, + 224, + 130, + 15, + 114, + 110, + 23, + 108, + 24, + 199, + 234, + 189, + 228, + 23, + 43, + 155, + 109, + 17, + 166, + 203, + 238, + 106, + 219, + 83, + 182, + 252, + 10, + 152, + 117, + 51, + 244, + 237, + 177, + 81, + 40, + 30, + 42, + 58, + 7, + 80, + 60, + 84, + 86, + 183, + 232, + 0, + 200, + 180, + 229, + 11, + 146, + 130, + 46, + 133, + 38, + 11, + 189, + 199, + 109, + 9, + 118, + 148, + 155, + 134, + 145, + 31, + 94, + 43, + 215, + 249, + 29, + 164, + 57, + 18, + 38, + 111, + 136, + 56, + 183, + 68, + 250, + 230, + 183, + 148, + 244, + 191, + 151, + 102, + 207, + 153, + 189, + 218, + 21, + 159, + 6, + 122, + 160, + 130, + 208, + 59, + 245, + 253, + 3, + 49, + 18, + 126, + 83, + 40, + 167, + 14, + 145, + 41, + 45, + 99, + 155, + 18, + 230, + 55, + 245, + 20, + 77, + 196, + 23, + 152, + 127, + 246, + 203, + 225, + 137, + 165, + 189, + 28, + 54, + 178, + 35, + 247, + 136, + 242, + 186, + 4, + 15, + 131, + 187, + 163, + 85, + 70, + 55, + 21, + 253, + 112, + 21, + 8, + 63, + 234, + 138, + 190, + 153, + 85, + 78, + 81, + 243, + 153, + 54, + 179, + 133, + 243, + 52, + 196, + 125, + 59, + 196, + 85, + 185, + 145, + 104, + 8, + 255, + 233, + 63, + 168, + 8, + 100, + 45, + 93, + 133, + 98, + 157, + 73, + 153, + 44, + 21, + 245, + 180, + 141, + 125, + 20, + 23, + 0, + 26, + 255, + 42, + 20, + 220, + 111, + 195, + 24, + 182, + 207, + 109, + 162, + 165, + 101, + 122, + 58, + 119, + 137, + 28, + 16, + 19, + 110, + 123, + 241, + 160, + 187, + 228, + 53, + 24, + 190, + 133, + 190, + 56, + 29, + 137, + 169, + 76, + 70, + 176, + 204, + 159, + 123, + 19, + 11, + 215, + 226, + 191, + 24, + 7, + 92, + 78, + 174, + 121, + 149, + 123, + 37, + 127, + 10, + 65, + 78, + 223, + 53, + 243, + 225, + 31, + 105, + 104, + 123, + 232, + 110, + 104, + 222, + 160, + 225, + 174, + 79, + 107, + 28, + 81, + 140, + 222, + 47, + 94, + 129, + 208, + 95, + 131, + 41, + 252, + 6, + 55, + 140, + 66, + 103, + 47, + 131, + 99, + 96, + 90, + 5, + 30, + 71, + 124, + 97, + 36, + 220, + 89, + 139, + 246, + 40, + 157, + 152, + 44, + 169, + 131, + 37, + 74, + 139, + 217, + 229, + 184, + 205, + 175, + 54, + 180, + 30, + 237, + 253, + 9, + 43, + 240, + 200, + 197, + 67, + 115, + 234, + 220, + 116, + 176, + 196, + 40, + 45, + 193, + 108, + 36, + 166, + 44, + 183, + 106, + 157, + 168, + 93, + 242, + 98, + 175, + 212, + 61, + 109, + 182, + 42, + 47, + 71, + 244, + 9, + 71, + 98, + 55, + 171, + 57, + 154, + 177, + 133, + 128, + 189, + 172, + 75, + 237, + 54, + 33, + 249, + 11, + 34, + 32, + 9, + 11, + 119, + 83, + 105, + 42, + 62, + 7, + 119, + 53, + 155, + 247, + 58, + 40, + 183, + 94, + 246, + 18, + 119, + 247, + 3, + 189, + 9, + 54, + 100, + 58, + 209, + 27, + 217, + 167, + 6, + 230, + 75, + 19, + 36, + 242, + 240, + 234, + 171, + 53, + 201, + 113, + 210, + 82, + 48, + 71, + 224, + 88, + 190, + 218, + 181, + 6, + 143, + 142, + 170, + 198, + 27, + 232, + 157, + 160, + 114, + 199, + 51, + 190, + 189, + 180, + 170, + 170, + 106, + 146, + 247, + 138, + 149, + 74, + 174, + 81, + 56, + 19, + 118, + 166, + 8, + 196, + 206, + 22, + 32, + 113, + 130, + 23, + 171, + 170, + 213, + 252, + 64, + 191, + 24, + 70, + 181, + 238, + 170, + 13, + 127, + 39, + 132, + 187, + 200, + 87, + 77, + 9, + 163, + 141, + 239, + 156, + 200, + 54, + 186, + 63, + 239, + 43, + 138, + 21, + 138, + 77, + 163, + 163, + 238, + 155, + 103, + 184, + 235, + 68, + 0, + 221, + 64, + 204, + 177, + 166, + 190, + 104, + 170, + 125, + 148, + 8, + 251, + 10, + 116, + 70, + 220, + 215, + 27, + 125, + 102, + 202, + 143, + 181, + 18, + 119, + 136, + 42, + 217, + 156, + 198, + 31, + 4, + 19, + 25, + 232, + 18, + 142, + 91, + 42, + 152, + 36, + 69, + 195, + 254, + 6, + 24, + 247, + 8, + 175, + 196, + 186, + 72, + 51, + 218, + 73, + 85, + 111, + 200, + 214, + 20, + 73, + 178, + 193, + 120, + 254, + 208, + 154, + 40, + 43, + 126, + 10, + 240, + 178, + 245, + 70, + 161, + 16, + 108, + 173, + 21, + 90, + 242, + 213, + 201, + 48, + 108, + 169, + 65, + 4, + 94, + 210, + 244, + 156, + 85, + 185, + 83, + 66, + 58, + 0, + 154, + 188, + 29, + 36, + 175, + 29, + 247, + 245, + 195, + 77, + 249, + 70, + 238, + 207, + 161, + 156, + 137, + 74, + 161, + 102, + 116, + 73, + 9, + 155, + 118, + 40, + 208, + 205, + 141, + 16, + 6, + 227, + 19, + 67, + 202, + 82, + 9, + 49, + 114, + 35, + 177, + 143, + 51, + 193, + 145, + 239, + 58, + 244, + 208, + 175, + 40, + 127, + 61, + 74, + 12, + 104, + 184, + 207, + 36, + 12, + 167, + 205, + 111, + 73, + 189, + 99, + 158, + 15, + 205, + 37, + 180, + 175, + 41, + 38, + 169, + 161, + 75, + 113, + 246, + 151, + 12, + 73, + 183, + 177, + 176, + 140, + 119, + 34, + 15, + 21, + 240, + 72, + 68, + 70, + 151, + 139, + 174, + 82, + 216, + 52, + 107, + 25, + 121, + 37, + 20, + 23, + 165, + 143, + 100, + 73, + 93, + 157, + 75, + 33, + 225, + 47, + 11, + 239, + 115, + 62, + 189, + 156, + 128, + 48, + 158, + 170, + 89, + 221, + 243, + 11, + 33, + 106, + 211, + 182, + 54, + 214, + 116, + 81, + 93, + 2, + 103, + 56, + 18, + 197, + 42, + 127, + 102, + 101, + 53, + 193, + 156, + 156, + 0, + 230, + 40, + 205, + 63, + 4, + 57, + 247, + 189, + 226, + 214, + 46, + 69, + 62, + 170, + 208, + 55, + 225, + 149, + 21, + 146, + 86, + 37, + 135, + 11, + 97, + 21, + 64, + 228, + 44, + 99, + 132, + 36, + 129, + 199, + 147, + 192, + 90, + 103, + 0, + 200, + 15, + 199, + 13, + 40, + 14, + 47, + 67, + 102, + 6, + 91, + 48, + 240, + 219, + 17, + 26, + 161, + 199, + 249, + 170, + 25, + 238, + 77, + 85, + 13, + 186, + 36, + 28, + 238, + 65, + 37, + 187, + 144, + 152, + 131, + 86, + 73, + 215, + 24, + 16, + 94, + 248, + 50, + 35, + 16, + 76, + 78, + 218, + 193, + 239, + 33, + 37, + 161, + 169, + 124, + 4, + 192, + 106, + 123, + 5, + 143, + 55, + 19, + 225, + 191, + 39, + 90, + 34, + 232, + 120, + 13, + 104, + 17, + 200, + 237, + 236, + 77, + 80, + 104, + 101, + 151, + 255, + 202, + 110, + 11, + 112, + 142, + 209, + 181, + 149, + 125, + 60, + 185, + 181, + 40, + 120, + 212, + 192, + 96, + 102, + 61, + 248, + 76, + 241, + 41, + 55, + 6, + 110, + 112, + 25, + 90, + 46, + 3, + 45, + 17, + 9, + 125, + 46, + 68, + 127, + 243, + 67, + 207, + 103, + 110, + 41, + 220, + 196, + 176, + 33, + 225, + 73, + 227, + 131, + 40, + 80, + 254, + 242, + 217, + 194, + 182, + 70, + 154, + 139, + 141, + 155, + 240, + 64, + 221, + 215, + 59, + 172, + 15, + 105, + 79, + 200, + 46, + 93, + 145, + 191, + 19, + 232, + 218, + 78, + 70, + 86, + 252, + 186, + 132, + 122, + 206, + 81, + 164, + 166, + 182, + 31, + 92, + 237, + 171, + 245, + 158, + 113, + 216, + 113, + 237, + 117, + 142, + 169, + 107, + 147, + 251, + 94, + 113, + 202, + 255, + 103, + 158, + 74, + 222, + 123, + 100, + 232, + 180, + 188, + 87, + 130, + 161, + 8, + 254, + 152, + 239, + 167, + 174, + 36, + 185, + 130, + 0, + 238, + 110, + 232, + 113, + 93, + 93, + 4, + 95, + 24, + 208, + 71, + 15, + 208, + 88, + 187, + 162, + 50, + 223, + 235, + 98, + 199, + 160, + 126, + 218, + 59, + 225, + 26, + 55, + 44, + 213, + 46, + 228, + 29, + 175, + 14, + 128, + 97, + 239, + 252, + 216, + 14, + 126, + 96, + 15, + 240, + 176, + 246, + 213, + 59, + 112, + 166, + 216, + 254, + 246, + 8, + 48, + 219, + 187, + 42, + 150, + 217, + 147, + 96, + 34, + 130, + 45, + 126, + 216, + 231, + 50, + 197, + 96, + 139, + 93, + 48, + 131, + 165, + 126, + 143, + 177, + 131, + 48, + 72, + 166, + 237, + 87, + 180, + 28, + 15, + 11, + 161, + 27, + 82, + 205, + 43, + 54, + 228, + 90, + 55, + 62, + 199, + 58, + 124, + 79, + 209, + 1, + 75, + 82, + 80, + 4, + 86, + 178, + 116, + 81, + 105, + 209, + 246, + 203, + 152, + 238, + 178, + 134, + 19, + 117, + 50, + 137, + 37, + 190, + 40, + 20, + 32, + 181, + 228, + 190, + 81, + 152, + 237, + 19, + 22, + 11, + 7, + 172, + 138, + 9, + 131, + 172, + 6, + 39, + 82, + 177, + 230, + 137, + 5, + 189, + 191, + 251, + 167, + 167, + 6, + 150, + 123, + 157, + 181, + 209, + 77, + 149, + 56, + 96, + 195, + 46, + 33, + 92, + 82, + 25, + 150, + 109, + 203, + 162, + 20, + 211, + 156, + 17, + 49, + 112, + 149, + 165, + 28, + 168, + 200, + 185, + 249, + 36, + 72, + 83, + 217, + 94, + 173, + 230, + 243, + 183, + 162, + 150, + 76, + 63, + 52, + 156, + 132, + 97, + 4, + 83, + 107, + 29, + 94, + 127, + 54, + 37, + 253, + 11, + 159, + 146, + 27, + 100, + 148, + 173, + 186, + 219, + 255, + 42, + 105, + 66, + 203, + 143, + 32, + 229, + 110, + 96, + 97, + 209, + 79, + 25, + 156, + 178, + 10, + 119, + 244, + 144, + 53, + 43, + 49, + 144, + 195, + 177, + 228, + 81, + 152, + 85, + 48, + 66, + 171, + 64, + 9, + 54, + 251, + 24, + 255, + 124, + 92, + 147, + 216, + 82, + 70, + 112, + 172, + 245, + 94, + 224, + 183, + 114, + 253, + 164, + 133, + 147, + 197, + 9, + 134, + 142, + 8, + 129, + 209, + 154, + 178, + 126, + 146, + 98, + 72, + 237, + 42, + 19, + 7, + 172, + 94, + 22, + 26, + 202, + 39, + 235, + 38, + 104, + 140, + 61, + 1, + 98, + 63, + 65, + 62, + 129, + 88, + 53, + 68, + 213, + 73, + 172, + 180, + 30, + 110, + 47, + 135, + 96, + 6, + 236, + 78, + 170, + 237, + 39, + 184, + 28, + 152, + 110, + 242, + 4, + 29, + 232, + 168, + 252, + 217, + 104, + 8, + 93, + 127, + 70, + 31, + 82, + 5, + 66, + 12, + 87, + 69, + 225, + 104, + 227, + 209, + 26, + 68, + 168, + 127, + 114, + 61, + 53, + 254, + 15, + 102, + 124, + 232, + 60, + 150, + 169, + 86, + 237, + 24, + 149, + 18, + 0, + 122, + 211, + 227, + 182, + 193, + 25, + 215, + 193, + 217, + 102, + 22, + 223, + 47, + 195, + 143, + 241, + 241, + 191, + 29, + 255, + 30, + 9, + 196, + 145, + 28, + 50, + 232, + 122, + 252, + 155, + 128, + 41, + 101, + 120, + 238, + 130, + 178, + 76, + 37, + 33, + 184, + 236, + 184, + 84, + 72, + 6, + 250, + 18, + 224, + 147, + 95, + 83, + 223, + 129, + 22, + 67, + 172, + 221, + 153, + 133, + 172, + 137, + 186, + 127, + 176, + 106, + 124, + 136, + 250, + 219, + 37, + 35, + 192, + 165, + 178, + 249, + 58, + 42, + 118, + 106, + 141, + 239, + 188, + 255, + 92, + 175, + 165, + 95, + 108, + 114, + 25, + 250, + 201, + 50, + 134, + 221, + 47, + 120, + 226, + 206, + 190, + 159, + 148, + 26, + 241, + 106, + 26, + 225, + 54, + 100, + 195, + 215, + 121, + 246, + 184, + 192, + 130, + 208, + 8, + 65, + 16, + 74, + 11, + 186, + 83, + 130, + 232, + 26, + 50, + 29, + 190, + 228, + 106, + 185, + 17, + 116, + 191, + 47, + 12, + 192, + 20, + 46, + 195, + 152, + 79, + 98, + 218, + 43, + 171, + 234, + 130, + 155, + 32, + 52, + 70, + 146, + 135, + 91, + 43, + 200, + 216, + 170, + 29, + 183, + 95, + 12, + 46, + 190, + 197, + 192, + 182, + 93, + 66, + 212, + 56, + 167, + 245, + 47, + 139, + 192, + 156, + 40, + 48, + 198, + 110, + 14, + 141, + 46, + 0, + 106, + 158, + 189, + 69, + 16, + 10, + 184, + 134, + 147, + 80, + 190, + 83, + 56, + 159, + 9, + 46, + 51, + 82, + 76, + 113, + 169, + 68, + 245, + 252, + 161, + 33, + 250, + 253, + 75, + 153, + 80, + 128, + 194, + 215, + 121, + 46, + 85, + 213, + 217, + 152, + 173, + 59, + 250, + 99, + 68, + 101, + 54, + 25, + 6, + 192, + 148, + 202, + 243, + 98, + 239, + 215, + 2, + 91, + 224, + 117, + 212, + 168, + 188, + 243, + 16, + 151, + 10, + 8, + 88, + 12, + 160, + 69, + 163, + 246, + 121, + 80, + 145, + 237, + 201, + 44, + 245, + 117, + 70, + 221, + 219, + 108, + 124, + 131, + 145, + 202, + 199, + 186, + 8, + 247, + 29, + 135, + 196, + 90, + 63, + 206, + 167, + 183, + 86, + 30, + 38, + 225, + 25, + 10, + 53, + 14, + 64, + 72, + 222, + 221, + 65, + 85, + 154, + 105, + 175, + 28, + 152, + 180, + 133, + 167, + 69, + 98, + 44, + 65, + 6, + 146, + 9, + 33, + 206, + 224, + 135, + 192, + 114, + 234, + 27, + 6, + 121, + 232, + 10, + 48, + 147, + 223, + 125, + 77, + 250, + 185, + 33, + 168, + 156, + 38, + 70, + 253, + 30, + 145, + 26, + 145, + 114, + 109, + 109, + 33, + 115, + 114, + 66, + 225, + 15, + 128, + 159, + 95, + 7, + 155, + 110, + 3, + 40, + 205, + 125, + 201, + 192, + 163, + 200, + 26, + 129, + 137, + 226, + 129, + 84, + 178, + 13, + 221, + 189, + 183, + 168, + 109, + 140, + 242, + 48, + 2, + 242, + 165, + 204, + 125, + 161, + 211, + 196, + 15, + 154, + 198, + 184, + 112, + 23, + 177, + 250, + 10, + 72, + 16, + 144, + 47, + 125, + 10, + 222, + 201, + 168, + 179, + 160, + 96, + 42, + 118, + 226, + 208, + 153, + 138, + 153, + 118, + 253, + 85, + 37, + 113, + 252, + 102, + 88, + 242, + 120, + 121, + 67, + 182, + 61, + 38, + 103, + 172, + 0, + 163, + 243, + 88, + 17, + 51, + 57, + 173, + 38, + 143, + 56, + 251, + 35, + 199, + 36, + 47, + 15, + 69, + 190, + 20, + 209, + 110, + 150, + 222, + 204, + 165, + 178, + 38, + 21, + 151, + 171, + 245, + 57, + 46, + 68, + 149, + 246, + 253, + 225, + 25, + 9, + 36, + 149, + 250, + 12, + 251, + 169, + 208, + 68, + 190, + 97, + 114, + 119, + 127, + 130, + 192, + 73, + 22, + 88, + 55, + 57, + 71, + 22, + 46, + 109, + 227, + 27, + 184, + 207, + 200, + 71, + 108, + 91, + 50, + 169, + 168, + 243, + 39, + 194, + 191, + 161, + 18, + 131, + 65, + 75, + 142, + 246, + 5, + 50, + 144, + 115, + 30, + 216, + 173, + 209, + 110, + 82, + 85, + 133, + 228, + 228, + 134, + 84, + 180, + 148, + 192, + 2, + 69, + 35, + 118, + 15, + 78, + 0, + 67, + 67, + 88, + 1, + 108, + 231, + 83, + 139, + 149, + 130, + 190, + 19, + 181, + 7, + 88, + 121, + 7, + 190, + 244, + 249, + 47, + 252, + 154, + 113, + 255, + 45, + 251, + 239, + 142, + 179, + 209, + 2, + 106, + 148, + 89, + 188, + 84, + 68, + 209, + 18, + 204, + 251, + 112, + 113, + 79, + 93, + 1, + 25, + 240, + 165, + 129, + 248, + 14, + 166, + 195, + 224, + 149, + 116, + 49, + 91, + 169, + 34, + 6, + 160, + 5, + 22, + 85, + 29, + 91, + 166, + 77, + 219, + 29, + 191, + 202, + 5, + 16, + 59, + 57, + 210, + 123, + 147, + 61, + 134, + 2, + 150, + 57, + 208, + 54, + 186, + 145, + 168, + 52, + 190, + 175, + 83, + 169, + 72, + 23, + 189, + 148, + 126, + 60, + 140, + 73, + 110, + 226, + 60, + 79, + 109, + 222, + 54, + 33, + 204, + 46, + 51, + 143, + 1, + 80, + 236, + 154, + 8, + 160, + 106, + 49, + 102, + 222, + 126, + 24, + 125, + 59, + 120, + 179, + 41, + 28, + 201, + 96, + 130, + 159, + 172, + 251, + 6, + 109, + 195, + 6, + 162, + 53, + 220, + 216, + 201, + 7, + 63, + 219, + 136, + 191, + 249, + 111, + 203, + 110, + 131, + 101, + 193, + 23, + 254, + 105, + 124, + 176, + 36, + 13, + 24, + 0, + 101, + 41, + 30, + 206, + 230, + 124, + 87, + 171, + 212, + 132, + 39, + 34, + 32, + 139, + 181, + 155, + 242, + 76, + 118, + 166, + 51, + 4, + 220, + 96, + 138, + 117, + 91, + 54, + 137, + 98, + 24, + 138, + 2, + 155, + 44, + 148, + 83, + 149, + 21, + 114, + 34, + 216, + 43, + 149, + 51, + 63, + 64, + 88, + 241, + 221, + 91, + 190, + 200, + 108, + 148, + 48, + 182, + 209, + 146, + 51, + 167, + 115, + 247, + 80, + 222, + 158, + 218, + 127, + 232, + 83, + 108, + 218, + 161, + 187, + 22, + 187, + 255, + 53, + 140, + 89, + 106, + 95, + 243, + 206, + 155, + 194, + 128, + 3, + 17, + 161, + 228, + 110, + 76, + 253, + 74, + 148, + 228, + 97, + 216, + 225, + 133, + 115, + 214, + 75, + 240, + 226, + 235, + 207, + 6, + 174, + 94, + 44, + 131, + 89, + 45, + 168, + 178, + 37, + 133, + 30, + 107, + 237, + 59, + 17, + 237, + 62, + 148, + 207, + 65, + 160, + 215, + 254, + 195, + 190, + 216, + 49, + 21, + 208, + 236, + 85, + 248, + 25, + 20, + 146, + 128, + 164, + 66, + 144, + 126, + 222, + 196, + 42, + 74, + 245, + 127, + 97, + 66, + 137, + 230, + 86, + 248, + 110, + 76, + 160, + 100, + 83, + 105, + 216, + 107, + 238, + 160, + 20, + 19, + 142, + 205, + 112, + 216, + 208, + 169, + 61, + 220, + 83, + 198, + 78, + 210, + 74, + 133, + 248, + 229, + 58, + 170, + 238, + 202, + 73, + 147, + 53, + 178, + 24, + 10, + 12, + 130, + 176, + 182, + 143, + 196, + 118, + 208, + 27, + 25, + 51, + 132, + 78, + 79, + 187, + 190, + 37, + 248, + 8, + 96, + 195, + 247, + 202, + 55, + 6, + 86, + 9, + 186, + 8, + 51, + 200, + 114, + 133, + 66, + 86, + 29, + 24, + 207, + 182, + 45, + 0, + 116, + 175, + 236, + 227, + 246, + 126, + 68, + 55, + 232, + 231, + 130, + 218, + 40, + 154, + 141, + 209, + 13, + 170, + 4, + 108, + 104, + 243, + 117, + 49, + 134, + 186, + 50, + 219, + 84, + 213, + 197, + 100, + 11, + 238, + 160, + 231, + 232, + 139, + 217, + 64, + 138, + 121, + 188, + 241, + 109, + 209, + 4, + 0, + 95, + 74, + 33, + 170, + 164, + 233, + 48, + 24, + 21, + 254, + 140, + 115, + 18, + 194, + 156, + 252, + 248, + 90, + 113, + 89, + 13, + 253, + 117, + 66, + 44, + 115, + 4, + 73, + 225, + 109, + 87, + 88, + 156, + 33, + 59, + 246, + 21, + 233, + 180, + 38, + 213, + 114, + 58, + 10, + 0, + 251, + 236, + 213, + 143, + 96, + 202, + 149, + 41, + 234, + 211, + 64, + 6, + 108, + 231, + 202, + 184, + 193, + 155, + 220, + 221, + 38, + 20, + 246, + 134, + 200, + 160, + 232, + 44, + 63, + 96, + 112, + 108, + 6, + 89, + 11, + 243, + 7, + 228, + 210, + 31, + 171, + 90, + 112, + 85, + 33, + 23, + 243, + 222, + 106, + 19, + 91, + 132, + 217, + 96, + 26, + 141, + 80, + 89, + 142, + 117, + 118, + 250, + 218, + 228, + 203, + 76, + 172, + 112, + 62, + 163, + 83, + 162, + 122, + 21, + 48, + 86, + 230, + 37, + 5, + 43, + 42, + 235, + 128, + 163, + 21, + 125, + 0, + 88, + 26, + 207, + 18, + 5, + 89, + 124, + 139, + 130, + 113, + 198, + 156, + 129, + 158, + 152, + 37, + 47, + 2, + 85, + 16, + 102, + 68, + 116, + 145, + 200, + 28, + 4, + 100, + 240, + 138, + 117, + 212, + 20, + 184, + 236, + 75, + 30, + 39, + 24, + 252, + 14, + 234, + 225, + 20, + 13, + 133, + 18, + 241, + 4, + 165, + 208, + 16, + 159, + 227, + 92, + 186, + 99, + 95, + 46, + 225, + 157, + 155, + 84, + 183, + 192, + 63, + 40, + 163, + 135, + 154, + 50, + 250, + 51, + 176, + 72, + 123, + 59, + 17, + 48, + 159, + 222, + 227, + 167, + 23, + 140, + 127, + 225, + 192, + 104, + 122, + 225, + 60, + 101, + 116, + 121, + 242, + 246, + 92, + 42, + 89, + 123, + 177, + 160, + 133, + 159, + 45, + 62, + 193, + 161, + 142, + 108, + 2, + 55, + 81, + 208, + 76, + 45, + 26, + 232, + 185, + 160, + 32, + 90, + 97, + 239, + 13, + 139, + 41, + 87, + 18, + 30, + 242, + 211, + 25, + 180, + 181, + 72, + 101, + 206, + 98, + 138, + 158, + 180, + 35, + 188, + 152, + 155, + 51, + 94, + 71, + 48, + 10, + 60, + 230, + 17, + 124, + 160, + 74, + 219, + 179, + 89, + 150, + 134, + 48, + 143, + 128, + 37, + 164, + 113, + 187, + 188, + 214, + 137, + 49, + 230, + 164, + 72, + 25, + 0, + 94, + 116, + 148, + 99, + 7, + 255, + 138, + 54, + 39, + 35, + 147, + 2, + 143, + 148, + 169, + 109, + 134, + 216, + 88, + 181, + 156, + 72, + 214, + 91, + 25, + 94, + 97, + 252, + 252, + 201, + 30, + 171, + 52, + 122, + 183, + 63, + 197, + 21, + 115, + 33, + 130, + 128, + 239, + 140, + 130, + 242, + 150, + 110, + 22, + 215, + 225, + 64, + 187, + 118, + 144, + 10, + 7, + 205, + 78, + 155, + 21, + 240, + 192, + 188, + 1, + 66, + 159, + 59, + 37, + 143, + 85, + 235, + 70, + 71, + 41, + 74, + 97, + 223, + 167, + 17, + 230, + 158, + 124, + 97, + 102, + 239, + 240, + 31, + 204, + 82, + 43, + 111, + 49, + 103, + 23, + 240, + 68, + 200, + 55, + 173, + 158, + 166, + 4, + 166, + 121, + 28, + 54, + 109, + 11, + 93, + 140, + 235, + 255, + 112, + 33, + 105, + 196, + 56, + 168, + 227, + 226, + 163, + 217, + 168, + 88, + 50, + 99, + 250, + 60, + 252, + 116, + 17, + 139, + 198, + 105, + 166, + 223, + 60, + 67, + 155, + 91, + 164, + 45, + 209, + 67, + 152, + 130, + 103, + 133, + 91, + 88, + 149, + 47, + 218, + 1, + 74, + 18, + 237, + 109, + 1, + 18, + 115, + 238, + 1, + 229, + 21, + 218, + 129, + 171, + 47, + 220, + 35, + 239, + 125, + 105, + 194, + 185, + 160, + 157, + 56, + 89, + 178, + 228, + 65, + 8, + 150, + 212, + 177, + 1, + 135, + 4, + 233, + 8, + 199, + 4, + 36, + 179, + 3, + 177, + 223, + 39, + 171, + 5, + 229, + 172, + 225, + 96, + 243, + 130, + 63, + 196, + 139, + 85, + 119, + 69, + 138, + 254, + 61, + 115, + 174, + 43, + 186, + 30, + 252, + 107, + 192, + 90, + 81, + 101, + 124, + 11, + 87, + 170, + 55, + 38, + 173, + 132, + 204, + 11, + 227, + 231, + 18, + 117, + 251, + 48, + 102, + 160, + 99, + 147, + 104, + 181, + 228, + 21, + 19, + 214, + 255, + 97, + 50, + 98, + 239, + 80, + 94, + 81, + 108, + 180, + 48, + 20, + 105, + 161, + 20, + 124, + 197, + 49, + 109, + 41, + 113, + 7, + 14, + 34, + 202, + 222, + 193, + 28, + 38, + 175, + 249, + 136, + 228, + 30, + 121, + 53, + 93, + 70, + 193, + 235, + 101, + 73, + 165, + 108, + 100, + 160, + 101, + 147, + 169, + 143, + 154, + 196, + 66, + 46, + 141, + 30, + 254, + 156, + 138, + 73, + 137, + 103, + 242, + 12, + 212, + 43, + 220, + 62, + 68, + 106, + 120, + 82, + 45, + 203, + 218, + 107, + 123, + 250, + 193, + 62, + 116, + 245, + 122, + 70, + 154, + 254, + 212, + 205, + 215, + 96, + 126, + 153, + 16, + 72, + 97, + 117, + 250, + 63, + 144, + 14, + 157, + 255, + 132, + 3, + 12, + 212, + 53, + 49, + 196, + 125, + 81, + 164, + 165, + 108, + 224, + 187, + 80, + 6, + 93, + 37, + 7, + 255, + 36, + 252, + 184, + 95, + 75, + 226, + 95, + 107, + 134, + 94, + 144, + 80, + 77, + 168, + 97, + 99, + 229, + 50, + 179, + 129, + 224, + 201, + 23, + 194, + 51, + 128, + 164, + 141, + 5, + 135, + 62, + 31, + 207, + 3, + 158, + 140, + 102, + 91, + 77, + 0, + 57, + 87, + 253, + 218, + 149, + 222, + 241, + 169, + 50, + 44, + 175, + 122, + 99, + 4, + 110, + 58, + 104, + 103, + 152, + 221, + 104, + 97, + 136, + 60, + 13, + 167, + 21, + 165, + 12, + 203, + 133, + 19, + 139, + 160, + 163, + 102, + 74, + 51, + 6, + 132, + 32, + 227, + 209, + 73, + 178, + 153, + 24, + 51, + 90, + 211, + 142, + 192, + 155, + 250, + 223, + 253, + 114, + 161, + 214, + 223, + 68, + 117, + 187, + 40, + 85, + 83, + 185, + 138, + 198, + 250, + 170, + 181, + 37, + 142, + 18, + 208, + 222, + 51, + 25, + 95, + 78, + 95, + 162, + 33, + 161, + 125, + 246, + 191, + 1, + 129, + 199, + 38, + 58, + 240, + 155, + 101, + 83, + 69, + 244, + 66, + 50, + 59, + 41, + 81, + 41, + 209, + 193, + 244, + 117, + 229, + 77, + 228, + 245, + 79, + 85, + 35, + 161, + 135, + 211, + 22, + 210, + 40, + 193, + 169, + 236, + 231, + 223, + 27, + 225, + 93, + 254, + 19, + 199, + 138, + 34, + 141, + 161, + 93, + 54, + 129, + 74, + 23, + 179, + 188, + 193, + 193, + 139, + 115, + 200, + 175, + 221, + 24, + 113, + 196, + 214, + 66, + 174, + 13, + 166, + 7, + 130, + 224, + 182, + 169, + 85, + 122, + 45, + 89, + 24, + 177, + 26, + 151, + 101, + 27, + 248, + 19, + 116, + 161, + 48, + 2, + 55, + 156, + 65, + 125, + 13, + 165, + 111, + 36, + 53, + 139, + 147, + 76, + 204, + 89, + 226, + 12, + 128, + 86, + 47, + 168, + 55, + 74, + 84, + 20, + 23, + 175, + 3, + 159, + 145, + 182, + 254, + 53, + 68, + 93, + 181, + 9, + 31, + 74, + 48, + 205, + 41, + 246, + 94, + 54, + 241, + 144, + 185, + 172, + 248, + 119, + 45, + 96, + 246, + 68, + 5, + 226, + 146, + 89, + 203, + 235, + 177, + 243, + 110, + 205, + 230, + 238, + 114, + 123, + 24, + 79, + 106, + 237, + 111, + 227, + 125, + 10, + 117, + 68, + 220, + 195, + 224, + 112, + 237, + 106, + 221, + 25, + 224, + 207, + 209, + 181, + 97, + 16, + 120, + 160, + 51, + 245, + 85, + 34, + 207, + 137, + 88, + 190, + 244, + 149, + 170, + 190, + 226, + 67, + 124, + 72, + 24, + 102, + 88, + 26, + 122, + 110, + 128, + 41, + 122, + 168, + 7, + 234, + 152, + 208, + 85, + 112, + 192, + 148, + 246, + 180, + 215, + 122, + 71, + 221, + 93, + 167, + 231, + 169, + 190, + 57, + 207, + 209, + 249, + 177, + 109, + 182, + 236, + 105, + 236, + 38, + 91, + 19, + 135, + 52, + 4, + 102, + 33, + 9, + 74, + 79, + 238, + 216, + 242, + 206, + 222, + 235, + 98, + 152, + 234, + 217, + 196, + 58, + 231, + 23, + 125, + 177, + 148, + 70, + 117, + 206, + 242, + 195, + 117, + 196, + 89, + 99, + 74, + 109, + 255, + 194, + 192, + 50, + 226, + 207, + 44, + 154, + 17, + 119, + 51, + 177, + 144, + 97, + 97, + 57, + 201, + 32, + 111, + 145, + 47, + 168, + 170, + 13, + 49, + 232, + 93, + 145, + 142, + 50, + 132, + 180, + 223, + 234, + 173, + 225, + 87, + 123, + 196, + 83, + 77, + 248, + 121, + 98, + 223, + 72, + 154, + 92, + 149, + 10, + 52, + 134, + 105, + 21, + 203, + 153, + 46, + 73, + 107, + 103, + 206, + 158, + 95, + 38, + 217, + 65, + 39, + 80, + 16, + 96, + 209, + 41, + 59, + 153, + 162, + 27, + 15, + 63, + 64, + 41, + 153, + 72, + 132, + 184, + 118, + 192, + 169, + 203, + 24, + 55, + 211, + 103, + 26, + 239, + 118, + 191, + 118, + 101, + 178, + 196, + 132, + 13, + 84, + 226, + 126, + 218, + 0, + 231, + 78, + 191, + 148, + 29, + 127, + 247, + 209, + 166, + 96, + 73, + 216, + 131, + 182, + 80, + 121, + 99, + 87, + 223, + 105, + 120, + 99, + 196, + 253, + 170, + 125, + 177, + 0, + 41, + 12, + 205, + 197, + 182, + 132, + 243, + 0, + 96, + 105, + 6, + 77, + 74, + 93, + 77, + 8, + 67, + 98, + 137, + 47, + 18, + 195, + 148, + 119, + 183, + 251, + 155, + 99, + 42, + 181, + 86, + 218, + 200, + 97, + 54, + 133, + 97, + 162, + 100, + 14, + 107, + 98, + 41, + 149, + 233, + 86, + 3, + 142, + 111, + 186, + 108, + 40, + 59, + 38, + 248, + 3, + 39, + 46, + 239, + 149, + 108, + 158, + 48, + 228, + 242, + 30, + 191, + 79, + 29, + 252, + 251, + 250, + 9, + 181, + 189, + 202, + 78, + 94, + 101, + 170, + 187, + 120, + 76, + 177, + 242, + 214, + 254, + 26, + 70, + 123, + 51, + 224, + 22, + 185, + 162, + 118, + 87, + 216, + 78, + 41, + 45, + 32, + 57, + 254, + 112, + 0, + 230, + 78, + 94, + 105, + 193, + 150, + 205, + 255, + 202, + 178, + 167, + 195, + 133, + 236, + 88, + 143, + 187, + 238, + 13, + 133, + 203, + 177, + 173, + 164, + 179, + 185, + 218, + 115, + 232, + 138, + 38, + 234, + 232, + 200, + 185, + 81, + 233, + 201, + 43, + 136, + 40, + 20, + 237, + 143, + 194, + 224, + 238, + 193, + 68, + 254, + 240, + 105, + 188, + 198, + 191, + 112, + 229, + 214, + 251, + 142, + 36, + 31, + 15, + 179, + 10, + 183, + 80, + 246, + 168, + 164, + 10, + 21, + 196, + 152, + 19, + 247, + 161, + 186, + 27, + 205, + 7, + 80, + 220, + 193, + 173, + 96, + 232, + 88, + 35, + 116, + 240, + 202, + 234, + 71, + 78, + 186, + 135, + 19, + 63, + 248, + 139, + 41, + 224, + 98, + 56, + 235, + 76, + 37, + 9, + 250, + 56, + 21, + 77, + 114, + 102, + 151, + 33, + 168, + 103, + 186, + 62, + 75, + 246, + 202, + 182, + 241, + 77, + 90, + 158, + 207, + 18, + 197, + 231, + 109, + 99, + 161, + 10, + 190, + 173, + 29, + 192, + 88, + 55, + 153, + 151, + 17, + 190, + 238, + 167, + 198, + 191, + 52, + 116, + 59, + 140, + 14, + 18, + 75, + 78, + 199, + 124, + 243, + 97, + 70, + 254, + 82, + 14, + 3, + 181, + 196, + 41, + 121, + 212, + 163, + 215, + 64, + 54, + 204, + 145, + 86, + 144, + 114, + 134, + 63, + 230, + 55, + 167, + 250, + 70, + 153, + 85, + 59, + 246, + 173, + 46, + 130, + 58, + 221, + 194, + 218, + 120, + 150, + 47, + 196, + 39, + 104, + 211, + 105, + 23, + 78, + 137, + 157, + 201, + 253, + 156, + 212, + 59, + 252, + 146, + 56, + 251, + 141, + 49, + 176, + 91, + 159, + 12, + 33, + 241, + 97, + 2, + 24, + 100, + 67, + 23, + 124, + 124, + 142, + 241, + 93, + 246, + 100, + 1, + 124, + 85, + 5, + 18, + 40, + 3, + 185, + 118, + 129, + 154, + 96, + 101, + 177, + 223, + 93, + 41, + 157, + 212, + 201, + 106, + 78, + 161, + 146, + 222, + 152, + 14, + 24, + 46, + 49, + 87, + 194, + 153, + 165, + 57, + 213, + 249, + 192, + 156, + 206, + 203, + 246, + 98, + 142, + 76, + 153, + 138, + 25, + 212, + 245, + 232, + 158, + 191, + 47, + 178, + 220, + 245, + 74, + 99, + 243, + 11, + 57, + 109, + 212, + 220, + 61, + 250, + 98, + 51, + 33, + 193, + 243, + 71, + 130, + 176, + 184, + 87, + 41, + 106, + 134, + 126, + 251, + 198, + 232, + 192, + 131, + 87, + 91, + 133, + 248, + 23, + 137, + 137, + 191, + 14, + 194, + 118, + 82, + 204, + 196, + 128, + 119, + 170, + 48, + 9, + 95, + 33, + 152, + 12, + 60, + 98, + 31, + 17, + 10, + 102, + 66, + 48, + 108, + 124, + 215, + 56, + 121, + 3, + 157, + 20, + 56, + 226, + 29, + 61, + 53, + 229, + 48, + 121, + 237, + 236, + 156, + 39, + 192, + 241, + 163, + 56, + 154, + 222, + 37, + 50, + 148, + 223, + 61, + 14, + 177, + 116, + 166, + 33, + 241, + 106, + 179, + 246, + 158, + 20, + 178, + 198, + 75, + 174, + 54, + 16, + 108, + 2, + 64, + 173, + 226, + 82, + 49, + 83, + 152, + 115, + 153, + 246, + 217, + 107, + 152, + 211, + 23, + 29, + 152, + 169, + 173, + 19, + 144, + 146, + 170, + 69, + 92, + 210, + 180, + 61, + 183, + 203, + 17, + 61, + 84, + 248, + 86, + 102, + 55, + 53, + 100, + 151, + 131, + 208, + 133, + 115, + 126, + 35, + 83, + 18, + 238, + 76, + 221, + 182, + 250, + 91, + 222, + 22, + 190, + 159, + 188, + 49, + 185, + 5, + 130, + 179, + 118, + 176, + 28, + 3, + 37, + 60, + 211, + 134, + 106, + 170, + 99, + 50, + 85, + 113, + 166, + 129, + 85, + 240, + 40, + 88, + 162, + 142, + 23, + 235, + 213, + 136, + 36, + 147, + 164, + 230, + 220, + 70, + 47, + 32, + 13, + 17, + 148, + 15, + 110, + 223, + 122, + 193, + 61, + 131, + 179, + 134, + 33, + 28, + 162, + 233, + 55, + 136, + 238, + 66, + 5, + 176, + 91, + 192, + 135, + 106, + 42, + 122, + 121, + 107, + 255, + 63, + 212, + 80, + 88, + 6, + 68, + 123, + 14, + 137, + 236, + 68, + 28, + 78, + 238, + 203, + 88, + 111, + 243, + 78, + 183, + 108, + 195, + 14, + 228, + 250, + 30, + 225, + 65, + 113, + 97, + 134, + 137, + 129, + 183, + 52, + 29, + 62, + 231, + 169, + 58, + 21, + 186, + 66, + 6, + 79, + 200, + 191, + 75, + 232, + 240, + 197, + 195, + 72, + 154, + 209, + 80, + 227, + 199, + 32, + 221, + 179, + 169, + 146, + 231, + 183, + 43, + 196, + 147, + 91, + 181, + 162, + 104, + 137, + 146, + 197, + 127, + 141, + 172, + 160, + 228, + 140, + 104, + 89, + 246, + 31, + 73, + 135, + 53, + 47, + 193, + 143, + 93, + 73, + 46, + 197, + 98, + 138, + 59, + 87, + 11, + 102, + 186, + 229, + 178, + 141, + 132, + 86, + 146, + 68, + 219, + 44, + 150, + 187, + 199, + 11, + 254, + 143, + 193, + 126, + 120, + 130, + 91, + 105, + 106, + 167, + 29, + 44, + 154, + 3, + 248, + 117, + 71, + 114, + 48, + 25, + 253, + 216, + 167, + 229, + 149, + 229, + 213, + 172, + 70, + 39, + 13, + 234, + 80, + 104, + 214, + 155, + 241, + 189, + 221, + 19, + 191, + 46, + 216, + 61, + 63, + 88, + 88, + 245, + 153, + 10, + 240, + 156, + 230, + 253, + 5, + 54, + 255, + 239, + 226, + 252, + 189, + 87, + 197, + 91, + 23, + 159, + 253, + 117, + 34, + 41, + 171, + 251, + 162, + 142, + 253, + 99, + 255, + 231, + 24, + 68, + 10, + 115, + 214, + 105, + 160, + 135, + 161, + 253, + 112, + 94, + 181, + 99, + 244, + 139, + 204, + 254, + 174, + 216, + 8, + 119, + 72, + 26, + 19, + 159, + 88, + 56, + 93, + 29, + 146, + 170, + 214, + 149, + 1, + 56, + 50, + 200, + 10, + 235, + 101, + 50, + 191, + 187, + 11, + 146, + 216, + 31, + 204, + 41, + 235, + 222, + 47, + 234, + 42, + 53, + 20, + 175, + 196, + 108, + 116, + 181, + 62, + 99, + 76, + 84, + 68, + 56, + 191, + 190, + 230, + 88, + 212, + 123, + 203, + 246, + 88, + 114, + 6, + 22, + 46, + 193, + 63, + 57, + 205, + 98, + 205, + 95, + 181, + 47, + 50, + 69, + 168, + 236, + 60, + 184, + 28, + 148, + 173, + 73, + 229, + 134, + 182, + 235, + 189, + 117, + 81, + 38, + 110, + 23, + 255, + 232, + 132, + 110, + 81, + 108, + 131, + 130, + 81, + 17, + 48, + 125, + 150, + 40, + 104, + 97, + 40, + 97, + 165, + 118, + 99, + 76, + 235, + 253, + 75, + 183, + 203, + 114, + 77, + 134, + 46, + 4, + 96, + 109, + 202, + 160, + 221, + 29, + 208, + 166, + 63, + 230, + 104, + 106, + 233, + 185, + 239, + 136, + 91, + 52, + 240, + 184, + 15, + 41, + 123, + 31, + 90, + 161, + 82, + 187, + 135, + 154, + 75, + 10, + 224, + 245, + 207, + 203, + 93, + 87, + 180, + 26, + 94, + 171, + 173, + 140, + 85, + 64, + 47, + 99, + 212, + 31, + 59, + 58, + 57, + 99, + 49, + 75, + 101, + 99, + 29, + 184, + 140, + 76, + 140, + 211, + 144, + 133, + 37, + 54, + 77, + 6, + 3, + 172, + 42, + 177, + 85, + 20, + 221, + 61, + 84, + 180, + 102, + 133, + 69, + 137, + 62, + 85, + 32, + 21, + 34, + 187, + 10, + 168, + 204, + 147, + 185, + 107, + 255, + 99, + 127, + 100, + 35, + 101, + 119, + 214, + 216, + 202, + 181, + 192, + 107, + 7, + 250, + 246, + 147, + 190, + 139, + 141, + 45, + 42, + 48, + 116, + 117, + 188, + 223, + 108, + 231, + 76, + 116, + 77, + 131, + 202, + 23, + 61, + 87, + 64, + 171, + 171, + 128, + 181, + 144, + 199, + 22, + 37, + 94, + 104, + 232, + 42, + 155, + 62, + 95, + 59, + 231, + 29, + 245, + 31, + 151, + 181, + 226, + 51, + 123, + 50, + 25, + 249, + 163, + 82, + 154, + 144, + 117, + 44, + 100, + 103, + 48, + 163, + 46, + 199, + 121, + 245, + 144, + 5, + 93, + 235, + 76, + 12, + 246, + 16, + 8, + 121, + 189, + 158, + 92, + 52, + 47, + 21, + 87, + 222, + 215, + 46, + 16, + 224, + 252, + 181, + 157, + 33, + 146, + 125, + 148, + 168, + 63, + 211, + 232, + 33, + 15, + 252, + 99, + 16, + 123, + 166, + 193, + 224, + 56, + 74, + 144, + 239, + 53, + 104, + 244, + 120, + 97, + 16, + 254, + 28, + 225, + 228, + 201, + 28, + 134, + 73, + 166, + 61, + 255, + 58, + 17, + 6, + 30, + 243, + 41, + 97, + 186, + 166, + 39, + 61, + 160, + 25, + 51, + 33, + 246, + 165, + 128, + 101, + 33, + 186, + 108, + 59, + 137, + 31, + 152, + 5, + 233, + 126, + 80, + 90, + 190, + 38, + 70, + 21, + 160, + 96, + 59, + 98, + 71, + 160, + 118, + 51, + 46, + 6, + 212, + 99, + 38, + 136, + 254, + 181, + 111, + 69, + 134, + 107, + 22, + 253, + 35, + 233, + 173, + 33, + 16, + 233, + 43, + 115, + 181, + 105, + 44, + 19, + 12, + 79, + 145, + 72, + 25, + 240, + 121, + 143, + 132, + 119, + 9, + 252, + 71, + 231, + 195, + 111, + 228, + 80, + 149, + 38, + 95, + 59, + 231, + 247, + 7, + 17, + 86, + 24, + 217, + 227, + 145, + 181, + 78, + 111, + 138, + 74, + 168, + 140, + 143, + 37, + 102, + 52, + 73, + 129, + 26, + 159, + 245, + 161, + 58, + 120, + 233, + 209, + 100, + 48, + 230, + 66, + 87, + 158, + 92, + 245, + 75, + 11, + 20, + 164, + 31, + 87, + 12, + 171, + 7, + 185, + 163, + 212, + 81, + 120, + 103, + 206, + 245, + 239, + 44, + 26, + 23, + 4, + 80, + 121, + 133, + 230, + 240, + 39, + 28, + 23, + 101, + 110, + 9, + 104, + 56, + 69, + 198, + 95, + 67, + 230, + 182, + 150, + 97, + 126, + 11, + 9, + 151, + 89, + 99, + 17, + 189, + 106, + 147, + 117, + 214, + 57, + 40, + 178, + 40, + 226, + 190, + 165, + 224, + 195, + 222, + 230, + 170, + 78, + 200, + 4, + 22, + 15, + 16, + 204, + 203, + 87, + 104, + 153, + 252, + 216, + 157, + 202, + 48, + 139, + 91, + 8, + 215, + 45, + 224, + 226, + 179, + 38, + 67, + 122, + 162, + 204, + 98, + 76, + 189, + 208, + 86, + 41, + 126, + 207, + 255, + 251, + 92, + 125, + 87, + 57, + 155, + 29, + 43, + 137, + 117, + 32, + 82, + 56, + 80, + 83, + 137, + 124, + 220, + 231, + 67, + 232, + 221, + 147, + 192, + 158, + 228, + 198, + 8, + 69, + 197, + 162, + 219, + 135, + 117, + 6, + 174, + 3, + 132, + 235, + 4, + 11, + 232, + 188, + 54, + 116, + 107, + 152, + 80, + 45, + 191, + 146, + 232, + 226, + 237, + 70, + 205, + 154, + 73, + 182, + 17, + 49, + 194, + 15, + 191, + 69, + 180, + 167, + 250, + 220, + 24, + 85, + 215, + 31, + 231, + 63, + 34, + 184, + 193, + 198, + 98, + 169, + 219, + 23, + 180, + 223, + 245, + 0, + 213, + 192, + 148, + 142, + 27, + 107, + 47, + 23, + 16, + 200, + 211, + 96, + 59, + 159, + 11, + 108, + 33, + 2, + 127, + 137, + 6, + 62, + 82, + 188, + 93, + 250, + 26, + 17, + 175, + 211, + 160, + 59, + 14, + 161, + 48, + 15, + 3, + 108, + 174, + 39, + 105, + 27, + 170, + 2, + 241, + 84, + 6, + 159, + 73, + 143, + 139, + 115, + 116, + 19, + 240, + 49, + 252, + 131, + 22, + 244, + 192, + 35, + 227, + 216, + 204, + 75, + 200, + 5, + 213, + 102, + 71, + 169, + 110, + 7, + 152, + 209, + 31, + 163, + 118, + 155, + 90, + 241, + 36, + 210, + 46, + 208, + 49, + 188, + 40, + 228, + 132, + 235, + 214, + 198, + 80, + 186, + 96, + 124, + 253, + 187, + 229, + 112, + 226, + 181, + 72, + 11, + 140, + 238, + 232, + 239, + 225, + 51, + 62, + 183, + 116, + 47, + 202, + 20, + 43, + 193, + 26, + 214, + 84, + 85, + 228, + 41, + 30, + 138, + 175, + 130, + 129, + 65, + 253, + 93, + 145, + 0, + 75, + 96, + 74, + 183, + 35, + 217, + 80, + 203, + 119, + 27, + 159, + 144, + 23, + 33, + 172, + 50, + 156, + 241, + 101, + 143, + 21, + 212, + 93, + 157, + 9, + 37, + 35, + 75, + 247, + 22, + 163, + 111, + 64, + 240, + 137, + 28, + 229, + 120, + 85, + 206, + 176, + 1, + 70, + 159, + 4, + 163, + 99, + 98, + 222, + 142, + 89, + 85, + 78, + 220, + 23, + 1, + 21, + 132, + 220, + 19, + 50, + 30, + 172, + 180, + 6, + 234, + 175, + 99, + 83, + 226, + 199, + 138, + 211, + 153, + 34, + 250, + 127, + 106, + 23, + 72, + 136, + 111, + 189, + 63, + 78, + 97, + 118, + 77, + 47, + 97, + 63, + 218, + 21, + 77, + 95, + 248, + 34, + 150, + 43, + 68, + 169, + 203, + 110, + 99, + 251, + 192, + 67, + 39, + 81, + 23, + 248, + 9, + 4, + 146, + 85, + 105, + 154, + 24, + 209, + 22, + 127, + 88, + 2, + 18, + 80, + 76, + 9, + 173, + 106, + 61, + 49, + 241, + 249, + 198, + 64, + 74, + 214, + 97, + 15, + 129, + 79, + 5, + 199, + 44, + 105, + 177, + 112, + 245, + 223, + 154, + 154, + 189, + 207, + 253, + 239, + 94, + 137, + 94, + 220, + 155, + 201, + 232, + 92, + 126, + 222, + 136, + 247, + 18, + 30, + 132, + 209, + 150, + 46, + 203, + 38, + 230, + 254, + 14, + 36, + 150, + 6, + 13, + 87, + 246, + 196, + 123, + 88, + 27, + 139, + 109, + 150, + 85, + 241, + 184, + 49, + 212, + 170, + 77, + 28, + 12, + 28, + 34, + 150, + 168, + 11, + 235, + 113, + 138, + 234, + 163, + 137, + 173, + 92, + 87, + 192, + 19, + 217, + 241, + 1, + 251, + 84, + 92, + 126, + 174, + 2, + 119, + 223, + 86, + 7, + 211, + 104, + 85, + 22, + 24, + 96, + 196, + 246, + 121, + 58, + 225, + 126, + 140, + 170, + 32, + 48, + 32, + 219, + 195, + 134, + 70, + 73, + 227, + 87, + 47, + 12, + 60, + 94, + 147, + 56, + 254, + 12, + 240, + 150, + 168, + 197, + 54, + 204, + 32, + 77, + 166, + 84, + 198, + 24, + 158, + 100, + 68, + 234, + 100, + 109, + 58, + 46, + 192, + 181, + 123, + 238, + 32, + 163, + 106, + 204, + 229, + 167, + 23, + 223, + 145, + 96, + 135, + 89, + 116, + 220, + 239, + 154, + 22, + 88, + 128, + 0, + 31, + 221, + 86, + 33, + 169, + 53, + 174, + 74, + 12, + 205, + 181, + 116, + 71, + 248, + 236, + 13, + 37, + 148, + 100, + 187, + 65, + 204, + 18, + 187, + 124, + 159, + 17, + 205, + 167, + 95, + 85, + 195, + 136, + 186, + 216, + 158, + 124, + 245, + 249, + 51, + 67, + 183, + 8, + 104, + 37, + 6, + 37, + 190, + 156, + 87, + 173, + 8, + 237, + 0, + 55, + 72, + 91, + 242, + 58, + 98, + 25, + 103, + 9, + 103, + 154, + 0, + 39, + 218, + 98, + 171, + 240, + 230, + 241, + 109, + 129, + 5, + 53, + 145, + 193, + 242, + 103, + 201, + 135, + 202, + 4, + 30, + 17, + 168, + 139, + 201, + 165, + 137, + 99, + 115, + 81, + 159, + 31, + 53, + 40, + 183, + 77, + 203, + 217, + 36, + 161, + 122, + 15, + 77, + 81, + 22, + 93, + 243, + 19, + 234, + 28, + 117, + 172, + 126, + 66, + 8, + 94, + 253, + 3, + 223, + 186, + 3, + 63, + 203, + 166, + 147, + 91, + 254, + 255, + 11, + 70, + 9, + 202, + 54, + 157, + 61, + 80, + 246, + 163, + 135, + 220, + 104, + 226, + 179, + 221, + 197, + 171, + 127, + 77, + 227, + 4, + 133, + 86, + 10, + 117, + 244, + 126, + 205, + 26, + 124, + 7, + 204, + 151, + 161, + 137, + 161, + 56, + 14, + 74, + 62, + 82, + 0, + 27, + 123, + 143, + 197, + 155, + 201, + 45, + 116, + 77, + 221, + 255, + 241, + 245, + 129, + 150, + 8, + 183, + 172, + 130, + 222, + 81, + 124, + 248, + 41, + 111, + 42, + 121, + 55, + 6, + 191, + 234, + 0, + 141, + 77, + 171, + 212, + 129, + 108, + 111, + 63, + 153, + 163, + 16, + 8, + 130, + 191, + 33, + 55, + 38, + 105, + 22, + 41, + 96, + 96, + 166, + 132, + 251, + 54, + 0, + 138, + 13, + 230, + 29, + 15, + 59, + 30, + 145, + 138, + 83, + 59, + 23, + 153, + 44, + 166, + 6, + 30, + 56, + 54, + 36, + 9, + 71, + 194, + 17, + 101, + 116, + 193, + 92, + 232, + 209, + 88, + 243, + 122, + 89, + 78, + 137, + 9, + 246, + 79, + 203, + 2, + 108, + 187, + 149, + 14, + 94, + 13, + 219, + 184, + 115, + 125, + 90, + 193, + 186, + 74, + 163, + 174, + 211, + 88, + 80, + 146, + 180, + 25, + 96, + 58, + 11, + 90, + 12, + 127, + 98, + 179, + 137, + 215, + 182, + 82, + 99, + 156, + 138, + 174, + 74, + 209, + 44, + 218, + 88, + 16, + 124, + 219, + 200, + 86, + 207, + 102, + 15, + 91, + 124, + 213, + 106, + 90, + 28, + 106, + 163, + 170, + 204, + 226, + 47, + 34, + 189, + 43, + 82, + 241, + 6, + 58, + 230, + 245, + 44, + 149, + 140, + 6, + 81, + 153, + 34, + 100, + 39, + 137, + 222, + 31, + 66, + 204, + 240, + 86, + 40, + 210, + 61, + 39, + 101, + 93, + 164, + 166, + 4, + 153, + 55, + 32, + 28, + 7, + 67, + 9, + 65, + 159, + 40, + 223, + 25, + 221, + 68, + 198, + 62, + 150, + 161, + 20, + 75, + 94, + 179, + 217, + 57, + 41, + 32, + 180, + 20, + 20, + 117, + 252, + 153, + 173, + 160, + 103, + 231, + 148, + 172, + 201, + 64, + 62, + 141, + 236, + 27, + 42, + 30, + 109, + 118, + 192, + 158, + 154, + 176, + 83, + 242, + 11, + 1, + 166, + 18, + 236, + 92, + 52, + 186, + 224, + 103, + 40, + 189, + 248, + 109, + 55, + 67, + 8, + 36, + 247, + 18, + 152, + 136, + 159, + 29, + 78, + 142, + 224, + 83, + 57, + 101, + 6, + 90, + 177, + 28, + 128, + 11, + 119, + 47, + 177, + 12, + 75, + 45, + 249, + 101, + 11, + 171, + 123, + 167, + 152, + 134, + 27, + 103, + 95, + 194, + 137, + 130, + 239, + 205, + 13, + 162, + 6, + 114, + 58, + 252, + 30, + 37, + 90, + 57, + 93, + 32, + 145, + 245, + 23, + 18, + 41, + 209, + 85, + 243, + 55, + 111, + 192, + 75, + 144, + 86, + 17, + 100, + 219, + 114, + 122, + 243, + 236, + 28, + 29, + 94, + 99, + 226, + 95, + 13, + 123, + 58, + 249, + 254, + 29, + 139, + 98, + 50, + 121, + 249, + 61, + 224, + 140, + 93, + 228, + 45, + 191, + 88, + 221, + 89, + 168, + 209, + 248, + 85, + 17, + 201, + 234, + 114, + 58, + 68, + 176, + 89, + 50, + 124, + 152, + 177, + 160, + 253, + 8, + 81, + 130, + 100, + 208, + 32, + 26, + 142, + 45, + 162, + 6, + 167, + 240, + 252, + 96, + 154, + 189, + 236, + 68, + 177, + 51, + 144, + 55, + 95, + 171, + 87, + 69, + 73, + 165, + 51, + 190, + 106, + 220, + 182, + 214, + 175, + 97, + 9, + 28, + 148, + 75, + 171, + 172, + 54, + 241, + 106, + 5, + 20, + 54, + 56, + 63, + 200, + 79, + 165, + 101, + 55, + 129, + 62, + 6, + 237, + 145, + 171, + 109, + 153, + 66, + 118, + 127, + 114, + 132, + 124, + 103, + 200, + 48, + 180, + 129, + 161, + 127, + 135, + 92, + 126, + 105, + 108, + 184, + 84, + 37, + 4, + 15, + 38, + 12, + 41, + 32, + 226, + 83, + 119, + 149, + 10, + 77, + 40, + 135, + 47, + 221, + 123, + 191, + 186, + 118, + 93, + 14, + 31, + 123, + 192, + 14, + 145, + 209, + 72, + 18, + 236, + 76, + 142, + 38, + 22, + 148, + 74, + 81, + 162, + 110, + 124, + 32, + 245, + 130, + 198, + 232, + 43, + 100, + 204, + 54, + 107, + 131, + 14, + 224, + 67, + 118, + 46, + 162, + 112, + 93, + 94, + 168, + 52, + 78, + 216, + 153, + 177, + 54, + 64, + 190, + 166, + 219, + 197, + 154, + 13, + 221, + 9, + 98, + 219, + 79, + 102, + 92, + 138, + 85, + 198, + 76, + 43, + 234, + 16, + 58, + 159, + 69, + 77, + 168, + 108, + 54, + 71, + 104, + 6, + 62, + 51, + 234, + 97, + 56, + 147, + 3, + 86, + 212, + 14, + 169, + 207, + 41, + 242, + 27, + 252, + 181, + 236, + 121, + 37, + 252, + 234, + 193, + 35, + 78, + 33, + 236, + 2, + 128, + 67, + 204, + 79, + 70, + 81, + 213, + 45, + 97, + 204, + 26, + 51, + 210, + 54, + 132, + 17, + 36, + 11, + 0, + 165, + 62, + 77, + 17, + 61, + 160, + 89, + 5, + 120, + 167, + 252, + 171, + 236, + 139, + 54, + 0, + 38, + 248, + 40, + 37, + 173, + 82, + 37, + 33, + 19, + 77, + 194, + 159, + 3, + 117, + 250, + 188, + 121, + 68, + 103, + 58, + 225, + 99, + 15, + 82, + 121, + 120, + 202, + 32, + 145, + 66, + 182, + 127, + 79, + 150, + 50, + 49, + 31, + 254, + 203, + 184, + 51, + 110, + 160, + 110, + 108, + 2, + 182, + 139, + 101, + 7, + 64, + 203, + 190, + 23, + 73, + 93, + 18, + 209, + 238, + 248, + 254, + 17, + 245, + 255, + 194, + 227, + 73, + 5, + 47, + 54, + 15, + 62, + 31, + 213, + 12, + 125, + 186, + 218, + 166, + 141, + 136, + 68, + 145, + 1, + 160, + 30, + 160, + 14, + 67, + 107, + 170, + 194, + 239, + 147, + 62, + 41, + 171, + 104, + 72, + 191, + 230, + 54, + 116, + 87, + 85, + 159, + 101, + 122, + 215, + 228, + 43, + 227, + 109, + 51, + 230, + 80, + 251, + 160, + 128, + 250, + 135, + 136, + 184, + 115, + 198, + 250, + 246, + 242, + 8, + 20, + 19, + 226, + 23, + 6, + 183, + 189, + 175, + 75, + 138, + 206, + 233, + 160, + 78, + 223, + 82, + 126, + 217, + 35, + 173, + 93, + 157, + 135, + 81, + 10, + 68, + 131, + 187, + 228, + 46, + 3, + 250, + 63, + 115, + 177, + 40, + 54, + 24, + 84, + 59, + 208, + 77, + 222, + 223, + 33, + 123, + 251, + 75, + 179, + 219, + 70, + 170, + 38, + 125, + 27, + 249, + 210, + 76, + 79, + 243, + 183, + 184, + 62, + 221, + 179, + 51, + 191, + 228, + 15, + 71, + 115, + 149, + 87, + 24, + 139, + 139, + 20, + 165, + 4, + 81, + 245, + 84, + 36, + 36, + 121, + 253, + 65, + 232, + 153, + 207, + 228, + 109, + 37, + 137, + 245, + 101, + 149, + 0, + 140, + 177, + 9, + 134, + 59, + 25, + 114, + 238, + 161, + 112, + 219, + 5, + 52, + 200, + 210, + 39, + 239, + 113, + 42, + 6, + 145, + 221, + 141, + 17, + 18, + 95, + 180, + 27, + 84, + 158, + 253, + 22, + 138, + 186, + 235, + 165, + 208, + 21, + 217, + 243, + 128, + 208, + 193, + 121, + 248, + 56, + 26, + 68, + 21, + 88, + 96, + 230, + 14, + 155, + 143, + 172, + 90, + 67, + 154, + 148, + 59, + 228, + 222, + 50, + 67, + 92, + 247, + 93, + 243, + 77, + 221, + 121, + 82, + 233, + 157, + 217, + 65, + 61, + 161, + 235, + 43, + 230, + 157, + 86, + 162, + 23, + 203, + 205, + 12, + 3, + 165, + 225, + 115, + 226, + 52, + 99, + 189, + 203, + 12, + 184, + 245, + 242, + 82, + 26, + 72, + 84, + 108, + 167, + 98, + 14, + 63, + 78, + 74, + 20, + 255, + 9, + 220, + 223, + 152, + 42, + 84, + 221, + 213, + 17, + 172, + 79, + 110, + 50, + 231, + 192, + 65, + 200, + 213, + 57, + 60, + 42, + 46, + 96, + 4, + 75, + 16, + 119, + 68, + 200, + 129, + 167, + 150, + 79, + 24, + 78, + 161, + 84, + 243, + 244, + 220, + 163, + 122, + 216, + 15, + 11, + 137, + 110, + 191, + 100, + 158, + 84, + 117, + 194, + 185, + 149, + 36, + 128, + 220, + 239, + 138, + 157, + 234, + 167, + 38, + 111, + 208, + 127, + 190, + 57, + 221, + 212, + 20, + 143, + 123, + 83, + 146, + 83, + 224, + 44, + 195, + 202, + 83, + 8, + 123, + 146, + 26, + 156, + 60, + 237, + 87, + 54, + 68, + 21, + 176, + 17, + 189, + 172, + 251, + 126, + 84, + 46, + 149, + 154, + 187, + 215, + 103, + 104, + 18, + 66, + 74, + 23, + 116, + 130, + 247, + 250, + 71, + 180, + 194, + 112, + 156, + 243, + 193, + 199, + 96, + 168, + 31, + 82, + 73, + 132, + 31, + 140, + 172, + 183, + 251, + 207, + 93, + 107, + 203, + 160, + 170, + 15, + 114, + 142, + 86, + 224, + 77, + 243, + 242, + 236, + 30, + 30, + 125, + 21, + 106, + 109, + 75, + 252, + 29, + 119, + 135, + 31, + 123, + 106, + 44, + 120, + 67, + 7, + 122, + 48, + 215, + 237, + 81, + 75, + 191, + 195, + 111, + 11, + 50, + 217, + 173, + 219, + 123, + 116, + 211, + 85, + 254, + 191, + 44, + 145, + 155, + 188, + 190, + 50, + 213, + 99, + 108, + 74, + 131, + 7, + 23, + 10, + 51, + 212, + 116, + 8, + 187, + 70, + 112, + 13, + 105, + 203, + 51, + 61, + 205, + 224, + 228, + 168, + 91, + 164, + 31, + 177, + 231, + 168, + 228, + 169, + 168, + 110, + 11, + 24, + 0, + 64, + 40, + 232, + 234, + 24, + 196, + 101, + 124, + 19, + 83, + 194, + 228, + 7, + 51, + 211, + 208, + 241, + 39, + 156, + 243, + 198, + 17, + 235, + 209, + 253, + 91, + 172, + 120, + 54, + 93, + 6, + 129, + 154, + 166, + 250, + 247, + 229, + 245, + 45, + 86, + 200, + 124, + 166, + 110, + 93, + 55, + 164, + 35, + 105, + 190, + 48, + 49, + 52, + 197, + 20, + 152, + 142, + 176, + 189, + 160, + 99, + 49, + 192, + 3, + 115, + 203, + 42, + 244, + 209, + 140, + 2, + 0, + 111, + 110, + 99, + 167, + 143, + 249, + 4, + 93, + 204, + 220, + 178, + 243, + 201, + 57, + 43, + 173, + 115, + 119, + 236, + 225, + 61, + 209, + 86, + 33, + 142, + 68, + 52, + 95, + 183, + 252, + 101, + 79, + 52, + 3, + 32, + 204, + 122, + 102, + 118, + 3, + 149, + 254, + 55, + 197, + 145, + 199, + 254, + 174, + 253, + 185, + 110, + 183, + 102, + 125, + 82, + 92, + 249, + 39, + 176, + 62, + 164, + 37, + 15, + 30, + 116, + 155, + 129, + 245, + 185, + 222, + 204, + 144, + 83, + 194, + 208, + 163, + 11, + 91, + 100, + 10, + 135, + 31, + 251, + 105, + 45, + 107, + 5, + 157, + 14, + 61, + 8, + 193, + 153, + 207, + 36, + 217, + 84, + 18, + 214, + 220, + 8, + 238, + 196, + 105, + 27, + 221, + 154, + 110, + 234, + 198, + 9, + 157, + 8, + 243, + 34, + 59, + 235, + 200, + 147, + 22, + 159, + 6, + 88, + 133, + 12, + 141, + 57, + 12, + 221, + 28, + 29, + 78, + 159, + 59, + 58, + 238, + 230, + 47, + 33, + 32, + 228, + 90, + 131, + 122, + 182, + 223, + 158, + 212, + 57, + 154, + 45, + 127, + 67, + 112, + 66, + 230, + 28, + 6, + 51, + 107, + 126, + 147, + 251, + 106, + 24, + 157, + 138, + 80, + 45, + 208, + 30, + 228, + 215, + 158, + 192, + 81, + 172, + 200, + 83, + 217, + 114, + 146, + 14, + 221, + 108, + 108, + 96, + 166, + 43, + 136, + 53, + 98, + 250, + 98, + 183, + 242, + 105, + 128, + 234, + 216, + 122, + 24, + 218, + 232, + 153, + 157, + 213, + 223, + 231, + 186, + 7, + 95, + 163, + 46, + 33, + 14, + 202, + 100, + 4, + 14, + 98, + 8, + 47, + 71, + 173, + 10, + 223, + 54, + 22, + 198, + 219, + 50, + 67, + 123, + 68, + 151, + 126, + 8, + 72, + 143, + 212, + 177, + 85, + 221, + 38, + 186, + 237, + 201, + 52, + 200, + 224, + 99, + 254, + 109, + 68, + 239, + 95, + 5, + 221, + 23, + 40, + 106, + 230, + 63, + 213, + 135, + 55, + 141, + 190, + 45, + 165, + 237, + 248, + 211, + 132, + 27, + 154, + 62, + 79, + 254, + 158, + 204, + 220, + 24, + 145, + 39, + 94, + 7, + 107, + 238, + 51, + 189, + 83, + 41, + 118, + 248, + 251, + 212, + 11, + 46, + 2, + 158, + 77, + 2, + 218, + 150, + 29, + 92, + 232, + 245, + 181, + 152, + 179, + 83, + 26, + 111, + 10, + 129, + 44, + 89, + 17, + 201, + 190, + 1, + 93, + 170, + 159, + 179, + 66, + 9, + 96, + 178, + 133, + 65, + 169, + 53, + 237, + 217, + 22, + 85, + 29, + 40, + 74, + 160, + 27, + 222, + 109, + 188, + 245, + 102, + 66, + 94, + 157, + 4, + 255, + 181, + 236, + 48, + 44, + 223, + 60, + 247, + 114, + 38, + 194, + 80, + 245, + 128, + 7, + 191, + 187, + 22, + 3, + 231, + 228, + 120, + 190, + 150, + 253, + 118, + 230, + 214, + 36, + 135, + 143, + 34, + 167, + 152, + 219, + 246, + 71, + 221, + 124, + 167, + 34, + 51, + 136, + 24, + 226, + 180, + 128, + 92, + 146, + 108, + 231, + 133, + 107, + 21, + 147, + 254, + 6, + 110, + 8, + 96, + 42, + 115, + 141, + 41, + 231, + 101, + 1, + 89, + 83, + 165, + 48, + 104, + 243, + 172, + 114, + 174, + 81, + 73, + 76, + 160, + 37, + 66, + 85, + 20, + 103, + 11, + 98, + 132, + 112, + 67, + 156, + 181, + 113, + 223, + 11, + 191, + 248, + 30, + 6, + 113, + 163, + 182, + 198, + 100, + 55, + 219, + 115, + 228, + 158, + 141, + 33, + 111, + 129, + 165, + 192, + 174, + 207, + 18, + 99, + 95, + 19, + 215, + 8, + 158, + 49, + 61, + 48, + 89, + 69, + 236, + 52, + 132, + 227, + 248, + 55, + 247, + 1, + 163, + 76, + 7, + 64, + 121, + 255, + 104, + 165, + 137, + 177, + 111, + 64, + 240, + 82, + 96, + 126, + 205, + 110, + 8, + 40, + 96, + 42, + 57, + 235, + 50, + 8, + 126, + 157, + 82, + 232, + 199, + 108, + 138, + 170, + 185, + 231, + 190, + 202, + 190, + 144, + 10, + 169, + 213, + 50, + 18, + 227, + 135, + 96, + 0, + 244, + 152, + 58, + 201, + 174, + 231, + 17, + 177, + 84, + 9, + 165, + 237, + 34, + 141, + 178, + 70, + 113, + 235, + 192, + 89, + 145, + 113, + 150, + 79, + 167, + 237, + 20, + 181, + 169, + 15, + 7, + 213, + 135, + 99, + 65, + 137, + 97, + 169, + 75, + 140, + 101, + 187, + 3, + 151, + 134, + 59, + 12, + 106, + 111, + 206, + 235, + 144, + 17, + 6, + 101, + 218, + 111, + 204, + 241, + 172, + 37, + 100, + 36, + 109, + 118, + 118, + 20, + 45, + 209, + 76, + 88, + 47, + 1, + 124, + 0, + 152, + 224, + 29, + 101, + 71, + 169, + 216, + 214, + 64, + 71, + 70, + 220, + 82, + 97, + 108, + 208, + 149, + 139, + 98, + 170, + 180, + 57, + 61, + 65, + 241, + 57, + 203, + 160, + 13, + 39, + 197, + 21, + 112, + 248, + 165, + 86, + 134, + 220, + 23, + 231, + 29, + 175, + 102, + 154, + 180, + 7, + 27, + 225, + 87, + 45, + 205, + 85, + 242, + 71, + 14, + 4, + 36, + 168, + 16, + 32, + 239, + 81, + 161, + 7, + 195, + 255, + 152, + 176, + 205, + 245, + 44, + 202, + 228, + 112, + 226, + 178, + 34, + 6, + 181, + 209, + 86, + 31, + 90, + 106, + 61, + 198, + 57, + 63, + 28, + 189, + 16, + 90, + 251, + 106, + 182, + 251, + 32, + 39, + 93, + 51, + 180, + 20, + 132, + 197, + 73, + 74, + 174, + 212, + 218, + 232, + 232, + 47, + 242, + 21, + 31, + 180, + 147, + 183, + 134, + 94, + 76, + 214, + 171, + 68, + 230, + 45, + 172, + 33, + 108, + 235, + 133, + 181, + 29, + 167, + 145, + 182, + 249, + 166, + 231, + 214, + 76, + 27, + 99, + 202, + 231, + 233, + 6, + 47, + 109, + 142, + 248, + 34, + 171, + 23, + 51, + 56, + 219, + 2, + 235, + 74, + 94, + 181, + 108, + 128, + 163, + 76, + 86, + 28, + 89, + 30, + 249, + 90, + 99, + 20, + 38, + 191, + 152, + 229, + 29, + 248, + 237, + 194, + 59, + 63, + 239, + 121, + 16, + 185, + 32, + 5, + 137, + 90, + 175, + 7, + 249, + 165, + 35, + 13, + 192, + 86, + 190, + 21, + 146, + 179, + 140, + 28, + 206, + 17, + 81, + 255, + 155, + 201, + 159, + 245, + 211, + 70, + 40, + 3, + 138, + 29, + 129, + 142, + 240, + 49, + 113, + 188, + 165, + 86, + 214, + 154, + 186, + 175, + 77, + 41, + 126, + 211, + 250, + 111, + 134, + 125, + 187, + 5, + 75, + 227, + 69, + 13, + 235, + 40, + 251, + 120, + 24, + 208, + 124, + 76, + 143, + 82, + 207, + 223, + 53, + 52, + 0, + 37, + 163, + 184, + 183, + 75, + 100, + 229, + 189, + 62, + 161, + 57, + 208, + 61, + 34, + 28, + 103, + 185, + 53, + 30, + 185, + 143, + 201, + 119, + 225, + 181, + 172, + 15, + 99, + 243, + 239, + 62, + 18, + 101, + 138, + 231, + 157, + 55, + 208, + 114, + 15, + 129, + 76, + 64, + 47, + 47, + 77, + 30, + 35, + 213, + 134, + 59, + 216, + 175, + 17, + 48, + 211, + 171, + 121, + 232, + 177, + 192, + 41, + 136, + 111, + 5, + 60, + 60, + 130, + 44, + 202, + 34, + 134, + 243, + 155, + 189, + 114, + 236, + 246, + 3, + 209, + 254, + 192, + 36, + 101, + 87, + 177, + 108, + 20, + 133, + 239, + 104, + 202, + 253, + 192, + 103, + 196, + 9, + 67, + 24, + 202, + 248, + 234, + 39, + 116, + 146, + 76, + 220, + 135, + 70, + 41, + 225, + 87, + 98, + 19, + 3, + 130, + 209, + 201, + 169, + 134, + 2, + 87, + 249, + 108, + 235, + 28, + 176, + 188, + 173, + 241, + 253, + 86, + 140, + 203, + 207, + 198, + 83, + 159, + 102, + 82, + 26, + 37, + 251, + 24, + 155, + 119, + 33, + 195, + 35, + 63, + 182, + 34, + 140, + 155, + 138, + 14, + 106, + 173, + 84, + 107, + 189, + 193, + 5, + 82, + 185, + 81, + 184, + 244, + 1, + 64, + 37, + 243, + 231, + 77, + 243, + 86, + 209, + 111, + 20, + 47, + 92, + 129, + 68, + 70, + 72, + 194, + 69, + 189, + 137, + 228, + 46, + 155, + 112, + 158, + 54, + 25, + 128, + 122, + 87, + 76, + 221, + 114, + 88, + 88, + 4, + 62, + 199, + 7, + 98, + 136, + 61, + 160, + 7, + 119, + 171, + 70, + 4, + 218, + 30, + 238, + 185, + 211, + 222, + 67, + 80, + 221, + 215, + 80, + 108, + 28, + 15, + 119, + 214, + 204, + 13, + 1, + 84, + 106, + 177, + 64, + 106, + 50, + 9, + 22, + 104, + 71, + 42, + 209, + 79, + 170, + 249, + 159, + 242, + 23, + 179, + 207, + 32, + 165, + 151, + 122, + 53, + 213, + 148, + 100, + 135, + 99, + 27, + 30, + 247, + 105, + 138, + 219, + 207, + 86, + 10, + 147, + 234, + 13, + 93, + 139, + 254, + 244, + 181, + 71, + 141, + 139, + 142, + 250, + 48, + 179, + 184, + 189, + 200, + 174, + 190, + 176, + 45, + 14, + 155, + 241, + 221, + 112, + 172, + 203, + 234, + 57, + 18, + 63, + 10, + 6, + 213, + 201, + 44, + 91, + 221, + 62, + 222, + 225, + 92, + 87, + 40, + 198, + 188, + 40, + 250, + 107, + 99, + 194, + 125, + 99, + 196, + 194, + 255, + 135, + 80, + 18, + 122, + 40, + 48, + 72, + 180, + 126, + 209, + 81, + 154, + 209, + 45, + 111, + 167, + 238, + 185, + 72, + 119, + 116, + 83, + 62, + 153, + 213, + 181, + 150, + 167, + 22, + 179, + 179, + 154, + 44, + 139, + 151, + 41, + 153, + 6, + 171, + 18, + 17, + 108, + 174, + 1, + 197, + 232, + 13, + 166, + 133, + 30, + 44, + 246, + 181, + 49, + 40, + 253, + 86, + 204, + 6, + 242, + 241, + 27, + 168, + 118, + 148, + 225, + 55, + 110, + 195, + 42, + 178, + 76, + 247, + 80, + 2, + 221, + 15, + 99, + 145, + 29, + 116, + 254, + 118, + 152, + 250, + 168, + 78, + 165, + 14, + 255, + 2, + 134, + 210, + 172, + 71, + 252, + 78, + 184, + 204, + 82, + 63, + 108, + 186, + 4, + 174, + 176, + 104, + 54, + 28, + 188, + 176, + 205, + 83, + 234, + 228, + 148, + 179, + 132, + 189, + 245, + 213, + 46, + 249, + 120, + 216, + 158, + 150, + 8, + 30, + 201, + 22, + 160, + 247, + 92, + 85, + 5, + 207, + 124, + 4, + 253, + 20, + 62, + 112, + 72, + 174, + 123, + 244, + 115, + 80, + 72, + 69, + 252, + 58, + 78, + 41, + 223, + 15, + 42, + 173, + 220, + 254, + 251, + 16, + 133, + 206, + 28, + 150, + 63, + 164, + 14, + 14, + 150, + 57, + 54, + 76, + 56, + 3, + 241, + 91, + 131, + 70, + 134, + 142, + 227, + 105, + 81, + 210, + 77, + 62, + 66, + 182, + 250, + 151, + 26, + 22, + 147, + 130, + 68, + 23, + 7, + 191, + 56, + 178, + 134, + 22, + 144, + 165, + 202, + 59, + 107, + 199, + 207, + 94, + 38, + 50, + 37, + 216, + 174, + 121, + 20, + 120, + 249, + 194, + 249, + 115, + 144, + 62, + 1, + 35, + 91, + 252, + 151, + 164, + 159, + 245, + 181, + 132, + 93, + 75, + 1, + 5, + 66, + 200, + 129, + 22, + 3, + 153, + 125, + 39, + 96, + 97, + 151, + 41, + 197, + 108, + 170, + 1, + 13, + 86, + 72, + 54, + 15, + 206, + 2, + 249, + 239, + 43, + 115, + 120, + 229, + 81, + 62, + 232, + 82, + 46, + 65, + 45, + 100, + 90, + 32, + 45, + 207, + 19, + 227, + 228, + 111, + 245, + 147, + 146, + 232, + 152, + 30, + 57, + 3, + 52, + 178, + 249, + 64, + 243, + 177, + 15, + 35, + 6, + 196, + 149, + 36, + 239, + 24, + 161, + 108, + 175, + 167, + 206, + 44, + 0, + 43, + 136, + 255, + 195, + 11, + 146, + 86, + 227, + 89, + 73, + 85, + 178, + 250, + 15, + 199, + 203, + 90, + 199, + 179, + 208, + 223, + 0, + 19, + 215, + 248, + 165, + 201, + 53, + 242, + 71, + 9, + 167, + 41, + 211, + 235, + 192, + 213, + 58, + 55, + 196, + 56, + 74, + 55, + 9, + 120, + 91, + 176, + 148, + 205, + 175, + 61, + 179, + 210, + 66, + 137, + 109, + 123, + 91, + 245, + 200, + 226, + 150, + 21, + 205, + 167, + 164, + 75, + 14, + 201, + 186, + 5, + 248, + 21, + 55, + 93, + 125, + 203, + 5, + 123, + 30, + 68, + 69, + 124, + 12, + 196, + 165, + 77, + 227, + 188, + 159, + 213, + 164, + 59, + 171, + 187, + 243, + 214, + 247, + 35, + 147, + 223, + 122, + 106, + 64, + 174, + 123, + 50, + 59, + 190, + 91, + 215, + 131, + 149, + 141, + 132, + 203, + 128, + 144, + 92, + 102, + 205, + 244, + 181, + 108, + 168, + 64, + 197, + 83, + 231, + 219, + 165, + 89, + 128, + 109, + 51, + 132, + 25, + 64, + 96, + 116, + 153, + 234, + 224, + 111, + 67, + 199, + 164, + 218, + 252, + 211, + 74, + 141, + 199, + 59, + 149, + 138, + 223, + 187, + 113, + 127, + 26, + 219, + 28, + 211, + 250, + 107, + 77, + 11, + 155, + 250, + 74, + 43, + 181, + 233, + 152, + 153, + 153, + 69, + 244, + 250, + 72, + 220, + 122, + 217, + 212, + 101, + 81, + 225, + 27, + 113, + 73, + 200, + 99, + 78, + 227, + 186, + 109, + 98, + 154, + 62, + 180, + 76, + 33, + 20, + 138, + 234, + 80, + 226, + 234, + 34, + 103, + 198, + 149, + 139, + 235, + 122, + 184, + 113, + 165, + 46, + 13, + 65, + 105, + 188, + 155, + 249, + 105, + 244, + 61, + 184, + 26, + 92, + 58, + 133, + 94, + 30, + 249, + 115, + 64, + 245, + 109, + 203, + 239, + 239, + 60, + 142, + 217, + 7, + 198, + 106, + 95, + 196, + 113, + 32, + 11, + 48, + 176, + 177, + 190, + 25, + 153, + 14, + 42, + 75, + 75, + 45, + 92, + 10, + 20, + 205, + 125, + 163, + 54, + 75, + 198, + 43, + 48, + 195, + 103, + 152, + 81, + 137, + 31, + 217, + 40, + 234, + 181, + 98, + 205, + 117, + 15, + 182, + 252, + 234, + 20, + 232, + 56, + 143, + 7, + 16, + 96, + 26, + 10, + 246, + 150, + 99, + 104, + 132, + 14, + 178, + 201, + 198, + 135, + 104, + 108, + 12, + 219, + 167, + 127, + 243, + 131, + 211, + 134, + 62, + 178, + 41, + 200, + 139, + 212, + 207, + 14, + 141, + 184, + 34, + 119, + 214, + 127, + 174, + 1, + 53, + 141, + 157, + 22, + 238, + 127, + 66, + 5, + 237, + 119, + 148, + 185, + 235, + 184, + 215, + 32, + 238, + 59, + 164, + 52, + 205, + 99, + 133, + 2, + 190, + 32, + 77, + 100, + 136, + 74, + 113, + 17, + 29, + 222, + 64, + 113, + 125, + 232, + 58, + 167, + 98, + 110, + 166, + 208, + 127, + 21, + 113, + 194, + 207, + 7, + 36, + 218, + 226, + 183, + 66, + 45, + 149, + 50, + 131, + 199, + 118, + 36, + 34, + 255, + 249, + 27, + 248, + 37, + 38, + 98, + 6, + 135, + 182, + 243, + 44, + 98, + 176, + 171, + 228, + 224, + 215, + 106, + 20, + 103, + 201, + 64, + 239, + 86, + 61, + 217, + 39, + 141, + 236, + 165, + 11, + 73, + 27, + 164, + 87, + 39, + 80, + 124, + 23, + 194, + 91, + 10, + 65, + 87, + 185, + 169, + 168, + 147, + 89, + 253, + 130, + 75, + 104, + 251, + 168, + 85, + 208, + 241, + 67, + 129, + 111, + 177, + 222, + 170, + 205, + 85, + 162, + 25, + 157, + 169, + 61, + 135, + 78, + 6, + 218, + 31, + 19, + 118, + 109, + 24, + 190, + 13, + 206, + 42, + 150, + 179, + 54, + 9, + 130, + 75, + 10, + 185, + 130, + 166, + 159, + 81, + 5, + 241, + 78, + 214, + 96, + 26, + 174, + 74, + 54, + 110, + 170, + 220, + 156, + 8, + 241, + 188, + 38, + 190, + 158, + 10, + 166, + 193, + 161, + 5, + 118, + 102, + 190, + 111, + 246, + 174, + 94, + 235, + 212, + 44, + 96, + 155, + 97, + 29, + 243, + 133, + 244, + 131, + 145, + 219, + 102, + 170, + 51, + 39, + 186, + 97, + 121, + 110, + 79, + 181, + 138, + 30, + 246, + 27, + 189, + 88, + 63, + 202, + 84, + 25, + 215, + 186, + 148, + 228, + 231, + 151, + 84, + 98, + 11, + 177, + 89, + 216, + 180, + 90, + 213, + 177, + 175, + 122, + 106, + 30, + 119, + 255, + 255, + 76, + 147, + 46, + 61, + 109, + 43, + 2, + 249, + 175, + 173, + 66, + 96, + 208, + 233, + 105, + 191, + 59, + 202, + 65, + 231, + 17, + 65, + 240, + 10, + 162, + 106, + 91, + 226, + 111, + 212, + 7, + 59, + 63, + 77, + 130, + 73, + 202, + 68, + 31, + 27, + 228, + 1, + 232, + 203, + 2, + 117, + 65, + 99, + 239, + 142, + 216, + 149, + 104, + 202, + 243, + 251, + 214, + 215, + 2, + 224, + 16, + 14, + 114, + 65, + 43, + 79, + 249, + 179, + 108, + 106, + 42, + 74, + 126, + 95, + 68, + 144, + 74, + 4, + 109, + 83, + 0, + 63, + 201, + 250, + 127, + 69, + 145, + 193, + 63, + 190, + 180, + 142, + 66, + 10, + 116, + 31, + 28, + 166, + 102, + 233, + 53, + 106, + 2, + 16, + 161, + 232, + 217, + 155, + 59, + 139, + 39, + 57, + 211, + 24, + 51, + 152, + 166, + 167, + 165, + 218, + 4, + 177, + 67, + 43, + 214, + 211, + 252, + 104, + 114, + 52, + 235, + 202, + 18, + 158, + 10, + 164, + 216, + 218, + 92, + 231, + 155, + 157, + 148, + 250, + 243, + 83, + 191, + 119, + 8, + 65, + 94, + 44, + 227, + 155, + 0, + 133, + 147, + 1, + 129, + 148, + 36, + 189, + 55, + 205, + 116, + 240, + 225, + 24, + 109, + 121, + 185, + 253, + 241, + 247, + 248, + 20, + 253, + 104, + 32, + 79, + 109, + 85, + 48, + 66, + 241, + 112, + 63, + 120, + 255, + 119, + 13, + 160, + 11, + 109, + 176, + 188, + 53, + 116, + 90, + 148, + 226, + 2, + 135, + 159, + 102, + 78, + 124, + 74, + 87, + 246, + 104, + 79, + 111, + 45, + 101, + 145, + 67, + 179, + 126, + 108, + 62, + 54, + 49, + 101, + 37, + 210, + 241, + 20, + 118, + 37, + 20, + 113, + 177, + 102, + 59, + 254, + 29, + 128, + 157, + 70, + 44, + 191, + 206, + 205, + 156, + 117, + 0, + 202, + 42, + 129, + 233, + 245, + 226, + 50, + 64, + 254, + 82, + 219, + 246, + 202, + 126, + 215, + 50, + 226, + 41, + 131, + 225, + 150, + 11, + 200, + 34, + 231, + 193, + 33, + 198, + 182, + 61, + 10, + 156, + 92, + 211, + 198, + 108, + 197, + 218, + 5, + 50, + 188, + 111, + 240, + 21, + 252, + 84, + 75, + 92, + 232, + 146, + 41, + 100, + 215, + 235, + 165, + 167, + 144, + 74, + 239, + 178, + 155, + 150, + 128, + 202, + 146, + 157, + 148, + 190, + 227, + 56, + 42, + 116, + 77, + 99, + 234, + 60, + 79, + 173, + 234, + 9, + 242, + 204, + 98, + 76, + 163, + 120, + 60, + 140, + 85, + 201, + 62, + 180, + 115, + 244, + 180, + 225, + 191, + 61, + 197, + 122, + 242, + 246, + 182, + 143, + 193, + 65, + 103, + 48, + 234, + 156, + 103, + 246, + 255, + 7, + 230, + 154, + 254, + 189, + 67, + 175, + 238, + 65, + 111, + 17, + 248, + 158, + 43, + 196, + 167, + 58, + 95, + 19, + 232, + 13, + 220, + 81, + 231, + 31, + 240, + 129, + 230, + 221, + 116, + 196, + 197, + 84, + 187, + 177, + 177, + 192, + 123, + 176, + 232, + 124, + 177, + 0, + 156, + 149, + 153, + 152, + 176, + 21, + 177, + 122, + 132, + 200, + 222, + 38, + 105, + 32, + 9, + 164, + 129, + 241, + 210, + 176, + 31, + 44, + 4, + 50, + 232, + 139, + 13, + 76, + 204, + 220, + 182, + 246, + 97, + 16, + 217, + 182, + 248, + 40, + 143, + 196, + 118, + 105, + 63, + 177, + 101, + 97, + 64, + 36, + 207, + 118, + 85, + 115, + 246, + 212, + 76, + 115, + 201, + 42, + 153, + 92, + 200, + 221, + 135, + 148, + 82, + 13, + 1, + 155, + 140, + 64, + 194, + 230, + 44, + 178, + 125, + 255, + 201, + 78, + 205, + 237, + 160, + 213, + 148, + 62, + 10, + 110, + 230, + 220, + 42, + 220, + 40, + 124, + 249, + 18, + 116, + 225, + 31, + 180, + 143, + 144, + 128, + 26, + 112, + 220, + 121, + 140, + 59, + 251, + 63, + 12, + 214, + 80, + 196, + 209, + 113, + 114, + 219, + 197, + 77, + 36, + 25, + 3, + 182, + 20, + 189, + 40, + 201, + 3, + 61, + 63, + 174, + 168, + 84, + 100, + 120, + 157, + 237, + 248, + 6, + 148, + 15, + 60, + 37, + 233, + 26, + 66, + 143, + 115, + 137, + 142, + 193, + 233, + 107, + 78, + 36, + 11, + 42, + 251, + 3, + 118, + 198, + 84, + 35, + 196, + 38, + 132, + 178, + 9, + 40, + 152, + 132, + 148, + 199, + 100, + 122, + 154, + 48, + 141, + 205, + 17, + 253, + 132, + 171, + 127, + 46, + 33, + 220, + 215, + 59, + 229, + 58, + 30, + 166, + 74, + 236, + 140, + 127, + 0, + 127, + 53, + 50, + 149, + 87, + 92, + 195, + 65, + 210, + 135, + 21, + 232, + 232, + 224, + 48, + 63, + 37, + 220, + 100, + 214, + 136, + 203, + 228, + 203, + 176, + 193, + 98, + 225, + 115, + 231, + 61, + 121, + 147, + 215, + 58, + 104, + 201, + 3, + 24, + 8, + 66, + 169, + 52, + 91, + 216, + 185, + 48, + 162, + 128, + 234, + 229, + 65, + 93, + 76, + 161, + 169, + 175, + 92, + 152, + 59, + 151, + 69, + 178, + 149, + 18, + 10, + 29, + 56, + 21, + 3, + 121, + 109, + 63, + 56, + 175, + 142, + 112, + 22, + 69, + 153, + 162, + 44, + 144, + 104, + 126, + 151, + 205, + 86, + 62, + 47, + 189, + 136, + 153, + 44, + 21, + 118, + 223, + 120, + 208, + 84, + 172, + 176, + 236, + 27, + 52, + 88, + 202, + 113, + 26, + 235, + 112, + 98, + 202, + 125, + 138, + 28, + 28, + 116, + 133, + 156, + 32, + 253, + 122, + 107, + 109, + 83, + 205, + 130, + 112, + 145, + 226, + 6, + 218, + 159, + 120, + 85, + 152, + 221, + 151, + 156, + 159, + 185, + 132, + 125, + 54, + 149, + 28, + 83, + 198, + 6, + 174, + 92, + 206, + 163, + 156, + 31, + 232, + 136, + 168, + 165, + 184, + 155, + 52, + 11, + 1, + 172, + 139, + 22, + 54, + 9, + 188, + 138, + 203, + 137, + 161, + 30, + 16, + 250, + 47, + 40, + 58, + 57, + 25, + 53, + 57, + 92, + 81, + 174, + 113, + 80, + 180, + 145, + 66, + 145, + 154, + 11, + 242, + 95, + 226, + 35, + 42, + 68, + 101, + 19, + 31, + 129, + 50, + 114, + 112, + 51, + 151, + 143, + 71, + 23, + 85, + 95, + 21, + 78, + 29, + 51, + 142, + 122, + 116, + 158, + 131, + 49, + 39, + 241, + 131, + 90, + 85, + 95, + 133, + 152, + 168, + 248, + 95, + 189, + 42, + 47, + 211, + 186, + 34, + 146, + 104, + 66, + 135, + 32, + 86, + 201, + 136, + 184, + 38, + 70, + 64, + 122, + 100, + 65, + 112, + 145, + 182, + 85, + 165, + 47, + 38, + 159, + 145, + 10, + 232, + 229, + 204, + 145, + 249, + 18, + 20, + 120, + 49, + 25, + 85, + 112, + 220, + 108, + 231, + 167, + 107, + 142, + 177, + 65, + 227, + 180, + 172, + 75, + 231, + 125, + 253, + 2, + 82, + 87, + 45, + 124, + 107, + 79, + 100, + 17, + 222, + 66, + 112, + 115, + 139, + 25, + 118, + 128, + 164, + 164, + 163, + 141, + 124, + 164, + 164, + 45, + 22, + 172, + 63, + 72, + 147, + 175, + 71, + 54, + 84, + 113, + 208, + 158, + 131, + 240, + 70, + 17, + 162, + 164, + 252, + 129, + 63, + 226, + 58, + 118, + 226, + 76, + 2, + 22, + 38, + 197, + 22, + 237, + 116, + 82, + 32, + 103, + 0, + 212, + 64, + 5, + 68, + 249, + 40, + 188, + 225, + 91, + 239, + 119, + 97, + 177, + 118, + 146, + 217, + 25, + 245, + 11, + 227, + 8, + 140, + 55, + 222, + 248, + 132, + 169, + 126, + 153, + 111, + 227, + 19, + 23, + 163, + 30, + 47, + 70, + 229, + 213, + 120, + 11, + 100, + 68, + 254, + 179, + 110, + 51, + 20, + 243, + 6, + 177, + 45, + 1, + 117, + 122, + 41, + 67, + 136, + 81, + 68, + 100, + 239, + 182, + 194, + 242, + 123, + 27, + 146, + 254, + 27, + 78, + 181, + 11, + 98, + 26, + 127, + 235, + 245, + 38, + 89, + 64, + 178, + 198, + 235, + 84, + 122, + 30, + 162, + 31, + 67, + 244, + 167, + 214, + 126, + 86, + 109, + 91, + 151, + 75, + 61, + 133, + 11, + 121, + 182, + 43, + 108, + 52, + 34, + 172, + 71, + 49, + 254, + 160, + 255, + 224, + 77, + 11, + 98, + 227, + 27, + 12, + 221, + 204, + 6, + 51, + 51, + 150, + 219, + 93, + 87, + 26, + 79, + 8, + 157, + 189, + 210, + 188, + 56, + 32, + 68, + 172, + 138, + 196, + 245, + 138, + 249, + 228, + 214, + 192, + 109, + 1, + 237, + 80, + 221, + 250, + 134, + 236, + 67, + 46, + 209, + 113, + 219, + 1, + 161, + 28, + 71, + 80, + 109, + 192, + 157, + 218, + 98, + 143, + 8, + 219, + 244, + 65, + 21, + 78, + 234, + 19, + 97, + 112, + 232, + 194, + 237, + 121, + 61, + 183, + 103, + 147, + 192, + 216, + 234, + 39, + 96, + 36, + 91, + 4, + 203, + 186, + 102, + 37, + 251, + 96, + 209, + 20, + 81, + 175, + 38, + 113, + 188, + 168, + 62, + 186, + 29, + 29, + 96, + 4, + 82, + 150, + 97, + 155, + 105, + 148, + 2, + 68, + 170, + 202, + 60, + 96, + 20, + 100, + 126, + 42, + 197, + 31, + 221, + 186, + 125, + 146, + 198, + 222, + 85, + 0, + 123, + 83, + 58, + 129, + 140, + 220, + 21, + 204, + 118, + 128, + 39, + 186, + 97, + 43, + 9, + 163, + 188, + 245, + 91, + 113, + 9, + 224, + 35, + 196, + 200, + 215, + 165, + 133, + 145, + 138, + 212, + 102, + 195, + 226, + 191, + 168, + 118, + 177, + 39, + 18, + 223, + 254, + 233, + 68, + 245, + 43, + 203, + 244, + 96, + 31, + 41, + 243, + 55, + 220, + 227, + 128, + 22, + 211, + 202, + 109, + 206, + 135, + 194, + 70, + 47, + 90, + 144, + 164, + 147, + 37, + 18, + 185, + 180, + 0, + 114, + 90, + 253, + 56, + 82, + 2, + 173, + 173, + 182, + 128, + 125, + 161, + 98, + 66, + 198, + 123, + 3, + 239, + 24, + 4, + 146, + 14, + 118, + 56, + 204, + 221, + 228, + 251, + 224, + 74, + 220, + 200, + 157, + 78, + 160, + 107, + 41, + 67, + 167, + 16, + 250, + 106, + 185, + 166, + 165, + 145, + 36, + 127, + 191, + 194, + 238, + 3, + 195, + 48, + 98, + 33, + 23, + 219, + 41, + 122, + 184, + 1, + 229, + 11, + 50, + 13, + 39, + 32, + 234, + 173, + 179, + 178, + 250, + 151, + 26, + 115, + 31, + 243, + 104, + 221, + 102, + 73, + 48, + 141, + 158, + 149, + 46, + 68, + 38, + 190, + 103, + 44, + 26, + 19, + 192, + 193, + 144, + 230, + 77, + 103, + 120, + 229, + 3, + 54, + 57, + 87, + 80, + 12, + 201, + 30, + 89, + 2, + 53, + 179, + 169, + 242, + 122, + 73, + 251, + 244, + 93, + 207, + 183, + 141, + 124, + 54, + 225, + 126, + 157, + 222, + 237, + 86, + 1, + 60, + 9, + 182, + 157, + 191, + 114, + 68, + 154, + 121, + 237, + 201, + 254, + 213, + 7, + 17, + 141, + 45, + 92, + 180, + 190, + 212, + 249, + 47, + 86, + 241, + 54, + 31, + 34, + 84, + 255, + 49, + 193, + 0, + 98, + 115, + 94, + 17, + 98, + 197, + 186, + 123, + 86, + 33, + 19, + 196, + 244, + 191, + 16, + 48, + 230, + 110, + 155, + 133, + 33, + 54, + 102, + 38, + 173, + 160, + 164, + 105, + 145, + 47, + 34, + 243, + 153, + 131, + 212, + 77, + 246, + 44, + 85, + 84, + 6, + 173, + 79, + 87, + 198, + 226, + 218, + 189, + 29, + 240, + 116, + 131, + 236, + 237, + 118, + 145, + 235, + 119, + 126, + 167, + 133, + 13, + 1, + 82, + 131, + 99, + 233, + 69, + 86, + 131, + 39, + 119, + 1, + 109, + 81, + 11, + 64, + 89, + 224, + 185, + 240, + 20, + 245, + 16, + 163, + 202, + 182, + 13, + 243, + 50, + 211, + 115, + 192, + 1, + 166, + 225, + 244, + 3, + 102, + 139, + 194, + 80, + 113, + 183, + 40, + 69, + 84, + 112, + 104, + 53, + 140, + 7, + 225, + 232, + 99, + 163, + 192, + 80, + 149, + 228, + 177, + 185, + 19, + 109, + 74, + 69, + 135, + 182, + 77, + 74, + 93, + 99, + 124, + 79, + 101, + 153, + 185, + 245, + 167, + 215, + 99, + 21, + 109, + 241, + 147, + 153, + 186, + 19, + 243, + 4, + 242, + 154, + 162, + 34, + 144, + 202, + 139, + 37, + 181, + 154, + 123, + 4, + 55, + 129, + 249, + 139, + 84, + 231, + 239, + 6, + 74, + 141, + 141, + 143, + 185, + 17, + 13, + 15, + 109, + 154, + 53, + 36, + 90, + 165, + 20, + 8, + 178, + 62, + 240, + 93, + 230, + 255, + 107, + 119, + 46, + 173, + 159, + 150, + 147, + 155, + 104, + 185, + 62, + 67, + 182, + 180, + 225, + 194, + 184, + 57, + 95, + 220, + 12, + 19, + 234, + 54, + 53, + 203, + 109, + 246, + 122, + 80, + 118, + 219, + 54, + 253, + 5, + 163, + 197, + 154, + 104, + 95, + 211, + 18, + 159, + 23, + 249, + 178, + 122, + 57, + 4, + 93, + 28, + 92, + 245, + 69, + 155, + 139, + 176, + 4, + 6, + 67, + 235, + 111, + 145, + 23, + 176, + 6, + 77, + 60, + 120, + 45, + 25, + 233, + 114, + 6, + 153, + 171, + 46, + 55, + 138, + 103, + 169, + 214, + 160, + 90, + 217, + 40, + 193, + 9, + 192, + 38, + 131, + 28, + 230, + 26, + 52, + 215, + 217, + 196, + 216, + 42, + 181, + 0, + 114, + 202, + 149, + 252, + 165, + 70, + 22, + 38, + 138, + 85, + 155, + 227, + 144, + 233, + 156, + 36, + 57, + 136, + 244, + 46, + 108, + 95, + 182, + 99, + 2, + 13, + 161, + 154, + 218, + 45, + 255, + 255, + 100, + 191, + 154, + 90, + 118, + 159, + 153, + 90, + 89, + 191, + 213, + 152, + 94, + 11, + 140, + 158, + 66, + 61, + 89, + 51, + 187, + 44, + 90, + 96, + 220, + 166, + 206, + 221, + 133, + 61, + 66, + 18, + 180, + 201, + 57, + 19, + 70, + 196, + 48, + 52, + 38, + 227, + 39, + 8, + 18, + 102, + 67, + 41, + 231, + 138, + 177, + 191, + 183, + 102, + 161, + 62, + 60, + 254, + 243, + 84, + 40, + 84, + 80, + 18, + 51, + 9, + 154, + 44, + 99, + 146, + 64, + 34, + 34, + 12, + 105, + 73, + 150, + 196, + 10, + 15, + 209, + 166, + 77, + 144, + 102, + 235, + 220, + 49, + 54, + 124, + 47, + 56, + 117, + 9, + 100, + 63, + 196, + 137, + 19, + 135, + 61, + 78, + 59, + 146, + 115, + 88, + 133, + 48, + 179, + 64, + 79, + 154, + 154, + 47, + 21, + 238, + 70, + 254, + 249, + 78, + 66, + 106, + 216, + 159, + 155, + 249, + 87, + 31, + 150, + 231, + 248, + 6, + 43, + 28, + 137, + 103, + 137, + 74, + 104, + 51, + 55, + 102, + 181, + 107, + 254, + 8, + 253, + 247, + 41, + 107, + 236, + 92, + 209, + 101, + 238, + 207, + 4, + 46, + 114, + 98, + 255, + 8, + 240, + 214, + 112, + 75, + 77, + 115, + 93, + 121, + 179, + 147, + 7, + 114, + 238, + 125, + 150, + 200, + 234, + 67, + 38, + 181, + 156, + 77, + 243, + 204, + 93, + 174, + 253, + 159, + 122, + 106, + 17, + 202, + 175, + 74, + 167, + 150, + 207, + 157, + 76, + 20, + 197, + 166, + 22, + 184, + 84, + 7, + 128, + 99, + 177, + 65, + 250, + 145, + 212, + 49, + 237, + 75, + 246, + 71, + 43, + 200, + 66, + 38, + 11, + 137, + 153, + 135, + 221, + 75, + 117, + 242, + 220, + 129, + 0, + 242, + 223, + 18, + 83, + 196, + 125, + 191, + 220, + 171, + 82, + 18, + 204, + 78, + 161, + 169, + 151, + 160, + 197, + 180, + 240, + 59, + 47, + 76, + 86, + 176, + 160, + 225, + 181, + 188, + 98, + 28, + 74, + 221, + 218, + 46, + 36, + 231, + 225, + 191, + 179, + 8, + 147, + 214, + 169, + 8, + 162, + 98, + 159, + 218, + 31, + 233, + 23, + 73, + 51, + 180, + 79, + 4, + 76, + 188, + 85, + 18, + 221, + 208, + 103, + 138, + 147, + 184, + 34, + 226, + 137, + 180, + 237, + 180, + 55, + 58, + 203, + 56, + 249, + 87, + 189, + 8, + 106, + 164, + 211, + 24, + 113, + 35, + 202, + 167, + 160, + 162, + 70, + 52, + 255, + 93, + 83, + 244, + 152, + 97, + 142, + 240, + 85, + 18, + 188, + 253, + 239, + 38, + 113, + 27, + 189, + 142, + 82, + 215, + 85, + 33, + 141, + 113, + 200, + 10, + 65, + 115, + 29, + 194, + 65, + 54, + 255, + 166, + 136, + 151, + 23, + 131, + 161, + 207, + 166, + 7, + 68, + 90, + 236, + 223, + 21, + 83, + 132, + 104, + 93, + 23, + 75, + 111, + 232, + 197, + 160, + 47, + 229, + 72, + 31, + 90, + 199, + 70, + 124, + 137, + 59, + 31, + 144, + 63, + 250, + 137, + 199, + 124, + 69, + 194, + 39, + 201, + 59, + 72, + 79, + 204, + 238, + 138, + 192, + 208, + 124, + 189, + 83, + 4, + 75, + 84, + 170, + 0, + 235, + 182, + 44, + 27, + 76, + 19, + 217, + 48, + 6, + 187, + 130, + 240, + 53, + 250, + 99, + 71, + 154, + 38, + 191, + 162, + 149, + 176, + 4, + 54, + 20, + 250, + 183, + 159, + 106, + 234, + 17, + 146, + 221, + 187, + 85, + 1, + 180, + 46, + 152, + 137, + 109, + 201, + 161, + 50, + 222, + 221, + 219, + 189, + 30, + 89, + 71, + 61, + 112, + 176, + 228, + 8, + 26, + 98, + 71, + 122, + 144, + 54, + 245, + 109, + 186, + 68, + 131, + 115, + 111, + 70, + 66, + 221, + 245, + 186, + 207, + 63, + 114, + 72, + 55, + 5, + 255, + 10, + 133, + 46, + 38, + 253, + 216, + 36, + 247, + 101, + 234, + 218, + 61, + 109, + 247, + 130, + 3, + 168, + 22, + 75, + 154, + 127, + 199, + 86, + 96, + 31, + 38, + 150, + 57, + 199, + 9, + 252, + 129, + 82, + 113, + 219, + 129, + 128, + 158, + 208, + 2, + 15, + 110, + 31, + 191, + 209, + 26, + 123, + 218, + 66, + 214, + 109, + 130, + 23, + 152, + 250, + 20, + 179, + 90, + 21, + 102, + 11, + 50, + 87, + 54, + 101, + 95, + 5, + 180, + 201, + 217, + 210, + 33, + 58, + 133, + 1, + 99, + 198, + 5, + 210, + 152, + 172, + 101, + 36, + 214, + 154, + 227, + 170, + 188, + 28, + 195, + 20, + 72, + 128, + 176, + 38, + 35, + 14, + 207, + 146, + 115, + 230, + 150, + 95, + 227, + 94, + 159, + 76, + 132, + 255, + 49, + 250, + 58, + 115, + 158, + 75, + 53, + 27, + 252, + 245, + 19, + 181, + 216, + 139, + 33, + 55, + 172, + 40, + 59, + 115, + 80, + 43, + 249, + 2, + 58, + 115, + 123, + 93, + 174, + 189, + 65, + 28, + 134, + 94, + 23, + 173, + 206, + 143, + 235, + 150, + 177, + 51, + 68, + 104, + 51, + 135, + 242, + 109, + 87, + 205, + 255, + 71, + 161, + 38, + 154, + 76, + 141, + 247, + 82, + 236, + 100, + 107, + 246, + 202, + 25, + 192, + 64, + 185, + 76, + 45, + 222, + 20, + 48, + 139, + 5, + 21, + 245, + 151, + 244, + 18, + 34, + 111, + 244, + 65, + 46, + 62, + 164, + 224, + 166, + 129, + 89, + 240, + 20, + 191, + 230, + 104, + 221, + 111, + 177, + 150, + 254, + 54, + 35, + 143, + 145, + 128, + 247, + 127, + 117, + 165, + 108, + 170, + 3, + 156, + 192, + 36, + 54, + 25, + 71, + 175, + 118, + 136, + 167, + 8, + 234, + 13, + 201, + 78, + 229, + 207, + 132, + 171, + 96, + 161, + 12, + 29, + 77, + 234, + 212, + 156, + 6, + 100, + 218, + 252, + 165, + 29, + 147, + 1, + 210, + 151, + 150, + 34, + 96, + 199, + 81, + 121, + 83, + 30, + 18, + 7, + 212, + 155, + 210, + 255, + 121, + 13, + 116, + 36, + 156, + 131, + 39, + 157, + 62, + 97, + 122, + 246, + 13, + 38, + 0, + 87, + 30, + 255, + 192, + 242, + 125, + 54, + 130, + 120, + 223, + 91, + 152, + 229, + 154, + 114, + 50, + 152, + 137, + 54, + 225, + 159, + 65, + 11, + 119, + 143, + 32, + 76, + 87, + 17, + 199, + 131, + 179, + 67, + 212, + 221, + 78, + 10, + 84, + 42, + 94, + 46, + 43, + 68, + 192, + 38, + 120, + 65, + 197, + 202, + 17, + 220, + 182, + 166, + 250, + 113, + 250, + 21, + 23, + 79, + 68, + 97, + 58, + 230, + 200, + 100, + 113, + 65, + 190, + 149, + 184, + 130, + 94, + 172, + 191, + 186, + 234, + 187, + 65, + 92, + 217, + 158, + 60, + 109, + 197, + 39, + 95, + 154, + 17, + 208, + 73, + 109, + 181, + 130, + 121, + 92, + 112, + 99, + 202, + 155, + 107, + 100, + 34, + 249, + 197, + 204, + 145, + 41, + 136, + 15, + 99, + 189, + 46, + 178, + 105, + 230, + 120, + 57, + 94, + 19, + 148, + 255, + 72, + 186, + 73, + 131, + 125, + 158, + 126, + 80, + 214, + 97, + 79, + 76, + 235, + 12, + 192, + 142, + 245, + 31, + 191, + 71, + 67, + 185, + 65, + 112, + 232, + 182, + 139, + 225, + 87, + 202, + 80, + 138, + 72, + 159, + 112, + 187, + 140, + 180, + 63, + 13, + 20, + 37, + 253, + 108, + 234, + 95, + 82, + 174, + 75, + 246, + 196, + 205, + 112, + 191, + 160, + 78, + 2, + 32, + 33, + 137, + 241, + 2, + 28, + 175, + 220, + 145, + 207, + 120, + 59, + 29, + 147, + 0, + 144, + 217, + 186, + 35, + 190, + 170, + 113, + 130, + 244, + 183, + 254, + 174, + 174, + 163, + 233, + 250, + 93, + 162, + 116, + 206, + 148, + 130, + 5, + 155, + 66, + 31, + 55, + 119, + 223, + 82, + 95, + 99, + 92, + 154, + 96, + 106, + 51, + 54, + 203, + 45, + 191, + 2, + 198, + 78, + 49, + 185, + 73, + 189, + 154, + 86, + 73, + 184, + 94, + 226, + 242, + 254, + 91, + 201, + 186, + 58, + 53, + 2, + 164, + 53, + 230, + 197, + 220, + 125, + 122, + 171, + 136, + 219, + 90, + 58, + 12, + 182, + 245, + 194, + 198, + 141, + 0, + 118, + 196, + 247, + 118, + 223, + 234, + 33, + 245, + 136, + 102, + 89, + 246, + 19, + 153, + 15, + 14, + 192, + 161, + 236, + 147, + 157, + 196, + 226, + 95, + 24, + 11, + 134, + 140, + 231, + 245, + 11, + 127, + 9, + 156, + 22, + 145, + 77, + 196, + 87, + 254, + 180, + 226, + 11, + 23, + 195, + 176, + 21, + 244, + 47, + 194, + 62, + 49, + 179, + 9, + 56, + 194, + 171, + 126, + 117, + 183, + 53, + 85, + 184, + 54, + 107, + 12, + 108, + 85, + 1, + 29, + 171, + 124, + 158, + 52, + 151, + 87, + 197, + 143, + 43, + 68, + 71, + 118, + 51, + 110, + 175, + 136, + 242, + 6, + 145, + 52, + 218, + 118, + 250, + 202, + 48, + 240, + 120, + 167, + 22, + 86, + 114, + 1, + 11, + 244, + 128, + 200, + 218, + 133, + 66, + 238, + 113, + 108, + 123, + 145, + 130, + 229, + 243, + 122, + 55, + 12, + 210, + 0, + 77, + 143, + 172, + 101, + 1, + 1, + 177, + 5, + 205, + 192, + 18, + 131, + 30, + 80, + 134, + 234, + 169, + 198, + 54, + 44, + 29, + 239, + 102, + 164, + 140, + 104, + 192, + 97, + 184, + 246, + 210, + 94, + 43, + 120, + 49, + 178, + 230, + 37, + 240, + 187, + 88, + 43, + 198, + 129, + 15, + 12, + 235, + 122, + 41, + 123, + 223, + 222, + 90, + 75, + 220, + 158, + 255, + 74, + 194, + 94, + 78, + 238, + 183, + 61, + 37, + 234, + 235, + 230, + 152, + 171, + 62, + 249, + 166, + 1, + 224, + 176, + 226, + 38, + 166, + 220, + 186, + 33, + 122, + 124, + 107, + 158, + 165, + 114, + 48, + 204, + 212, + 89, + 205, + 168, + 159, + 248, + 239, + 102, + 159, + 222, + 6, + 116, + 62, + 51, + 245, + 9, + 155, + 208, + 53, + 254, + 163, + 150, + 96, + 14, + 118, + 124, + 87, + 205, + 209, + 123, + 76, + 70, + 229, + 109, + 118, + 46, + 159, + 78, + 169, + 60, + 17, + 33, + 89, + 34, + 138, + 52, + 200, + 205, + 99, + 122, + 209, + 33, + 113, + 52, + 131, + 145, + 163, + 246, + 36, + 163, + 107, + 66, + 6, + 42, + 200, + 90, + 178, + 38, + 250, + 122, + 235, + 95, + 143, + 196, + 215, + 20, + 164, + 233, + 153, + 234, + 16, + 5, + 129, + 56, + 183, + 40, + 152, + 130, + 41, + 146, + 86, + 181, + 127, + 155, + 90, + 34, + 226, + 102, + 188, + 135, + 229, + 25, + 158, + 84, + 63, + 96, + 232, + 199, + 45, + 45, + 0, + 224, + 208, + 187, + 8, + 163, + 55, + 46, + 112, + 2, + 195, + 69, + 52, + 208, + 147, + 132, + 81, + 243, + 86, + 181, + 238, + 229, + 247, + 244, + 238, + 52, + 155, + 97, + 108, + 186, + 180, + 42, + 83, + 125, + 166, + 208, + 93, + 244, + 0, + 237, + 15, + 106, + 85, + 209, + 32, + 151, + 68, + 2, + 222, + 36, + 222, + 47, + 170, + 192, + 140, + 118, + 32, + 174, + 127, + 31, + 167, + 146, + 111, + 37, + 178, + 196, + 158, + 155, + 222, + 215, + 51, + 8, + 141, + 30, + 120, + 185, + 9, + 0, + 173, + 90, + 213, + 199, + 151, + 85, + 239, + 79, + 172, + 30, + 171, + 47, + 7, + 28, + 191, + 9, + 0, + 26, + 13, + 93, + 178, + 68, + 208, + 129, + 68, + 84, + 3, + 61, + 115, + 198, + 40, + 200, + 34, + 94, + 137, + 49, + 40, + 241, + 190, + 6, + 174, + 171, + 124, + 125, + 250, + 1, + 148, + 21, + 185, + 70, + 209, + 34, + 168, + 69, + 242, + 188, + 31, + 132, + 206, + 134, + 14, + 173, + 63, + 4, + 125, + 10, + 24, + 215, + 242, + 85, + 40, + 123, + 226, + 3, + 175, + 225, + 253, + 234, + 58, + 16, + 65, + 67, + 184, + 127, + 192, + 48, + 36, + 117, + 186, + 211, + 56, + 226, + 10, + 106, + 45, + 201, + 158, + 204, + 160, + 39, + 93, + 77, + 118, + 93, + 27, + 143, + 193, + 149, + 239, + 171, + 11, + 219, + 207, + 122, + 127, + 222, + 40, + 218, + 19, + 191, + 180, + 23, + 231, + 123, + 221, + 151, + 108, + 221, + 7, + 237, + 70, + 211, + 6, + 250, + 86, + 173, + 112, + 179, + 81, + 34, + 32, + 141, + 243, + 39, + 27, + 189, + 1, + 173, + 106, + 232, + 158, + 184, + 50, + 9, + 65, + 129, + 142, + 228, + 73, + 173, + 177, + 36, + 212, + 149, + 97, + 217, + 81, + 176, + 105, + 145, + 2, + 84, + 220, + 232, + 165, + 115, + 114, + 67, + 255, + 81, + 16, + 150, + 121, + 215, + 225, + 86, + 82, + 10, + 41, + 46, + 57, + 20, + 74, + 11, + 8, + 47, + 2, + 219, + 123, + 151, + 28, + 114, + 62, + 113, + 21, + 169, + 93, + 218, + 167, + 138, + 58, + 179, + 41, + 48, + 233, + 69, + 61, + 148, + 130, + 192, + 79, + 27, + 115, + 37, + 36, + 233, + 96, + 111, + 236, + 37, + 38, + 80, + 28, + 249, + 189, + 135, + 22, + 175, + 28, + 104, + 162, + 127, + 217, + 192, + 210, + 41, + 7, + 51, + 78, + 230, + 206, + 167, + 210, + 206, + 85, + 134, + 178, + 58, + 122, + 147, + 30, + 86, + 9, + 154, + 53, + 18, + 138, + 189, + 55, + 226, + 163, + 0, + 244, + 236, + 49, + 9, + 83, + 155, + 33, + 116, + 171, + 127, + 113, + 158, + 244, + 251, + 41, + 40, + 26, + 180, + 66, + 205, + 46, + 138, + 220, + 13, + 18, + 32, + 138, + 93, + 59, + 160, + 102, + 36, + 100, + 145, + 143, + 54, + 128, + 174, + 115, + 181, + 65, + 157, + 198, + 207, + 112, + 176, + 34, + 180, + 108, + 199, + 144, + 113, + 242, + 149, + 46, + 0, + 74, + 118, + 243, + 167, + 16, + 18, + 93, + 128, + 111, + 255, + 174, + 44, + 252, + 141, + 43, + 197, + 252, + 104, + 21, + 145, + 116, + 72, + 4, + 216, + 153, + 43, + 117, + 27, + 209, + 119, + 210, + 40, + 127, + 216, + 232, + 4, + 142, + 229, + 103, + 7, + 22, + 20, + 147, + 80, + 40, + 122, + 244, + 94, + 38, + 1, + 15, + 68, + 177, + 92, + 9, + 39, + 136, + 158, + 106, + 155, + 178, + 213, + 30, + 88, + 10, + 60, + 62, + 117, + 149, + 156, + 213, + 172, + 240, + 8, + 18, + 172, + 16, + 175, + 16, + 225, + 81, + 95, + 254, + 88, + 230, + 200, + 77, + 230, + 30, + 249, + 163, + 65, + 70, + 63, + 152, + 97, + 130, + 90, + 15, + 144, + 161, + 81, + 187, + 59, + 171, + 220, + 68, + 149, + 203, + 47, + 166, + 178, + 102, + 11, + 214, + 130, + 143, + 228, + 55, + 197, + 73, + 204, + 4, + 183, + 104, + 63, + 92, + 176, + 136, + 40, + 243, + 39, + 113, + 171, + 6, + 144, + 101, + 185, + 32, + 204, + 180, + 58, + 120, + 208, + 174, + 31, + 157, + 250, + 207, + 242, + 18, + 139, + 138, + 104, + 218, + 105, + 74, + 73, + 152, + 255, + 235, + 87, + 36, + 149, + 249, + 34, + 229, + 92, + 160, + 189, + 168, + 36, + 119, + 45, + 209, + 150, + 222, + 82, + 229, + 147, + 148, + 78, + 66, + 218, + 8, + 239, + 161, + 223, + 187, + 196, + 247, + 254, + 203, + 204, + 152, + 199, + 80, + 192, + 93, + 140, + 142, + 150, + 109, + 200, + 224, + 1, + 88, + 205, + 55, + 210, + 107, + 36, + 47, + 64, + 30, + 175, + 13, + 104, + 79, + 102, + 12, + 84, + 11, + 210, + 213, + 227, + 7, + 126, + 107, + 116, + 107, + 79, + 80, + 155, + 218, + 243, + 236, + 208, + 248, + 18, + 247, + 75, + 129, + 54, + 118, + 234, + 67, + 1, + 20, + 148, + 194, + 56, + 232, + 13, + 99, + 142, + 126, + 118, + 97, + 60, + 37, + 81, + 227, + 166, + 117, + 221, + 199, + 157, + 30, + 2, + 231, + 231, + 122, + 246, + 211, + 153, + 127, + 227, + 29, + 155, + 82, + 72, + 211, + 167, + 36, + 194, + 102, + 219, + 170, + 14, + 123, + 213, + 47, + 82, + 92, + 223, + 182, + 53, + 236, + 250, + 121, + 33, + 96, + 115, + 33, + 204, + 6, + 74, + 191, + 63, + 21, + 13, + 161, + 69, + 89, + 217, + 20, + 200, + 63, + 136, + 40, + 140, + 205, + 100, + 58, + 36, + 48, + 223, + 92, + 94, + 208, + 230, + 11, + 195, + 182, + 161, + 111, + 207, + 59, + 3, + 31, + 179, + 12, + 54, + 164, + 98, + 221, + 241, + 186, + 75, + 212, + 85, + 2, + 126, + 104, + 163, + 115, + 214, + 72, + 116, + 161, + 11, + 235, + 141, + 182, + 126, + 146, + 203, + 49, + 51, + 115, + 36, + 66, + 198, + 35, + 80, + 240, + 58, + 116, + 3, + 237, + 116, + 124, + 217, + 137, + 218, + 103, + 11, + 242, + 177, + 39, + 243, + 12, + 161, + 128, + 185, + 36, + 94, + 154, + 175, + 176, + 91, + 148, + 93, + 207, + 254, + 79, + 219, + 39, + 84, + 180, + 54, + 12, + 176, + 160, + 107, + 250, + 78, + 54, + 213, + 82, + 69, + 161, + 176, + 119, + 129, + 182, + 113, + 191, + 238, + 203, + 43, + 203, + 48, + 8, + 156, + 36, + 47, + 50, + 41, + 78, + 90, + 67, + 72, + 132, + 169, + 249, + 234, + 21, + 59, + 243, + 73, + 154, + 187, + 161, + 90, + 140, + 180, + 137, + 153, + 190, + 163, + 46, + 249, + 89, + 84, + 116, + 220, + 204, + 160, + 69, + 43, + 244, + 73, + 113, + 97, + 201, + 45, + 77, + 132, + 135, + 59, + 79, + 70, + 76, + 175, + 180, + 123, + 15, + 44, + 183, + 5, + 129, + 107, + 108, + 63, + 88, + 222, + 223, + 100, + 198, + 104, + 93, + 12, + 79, + 26, + 144, + 149, + 23, + 108, + 168, + 120, + 21, + 71, + 182, + 112, + 196, + 96, + 78, + 227, + 126, + 86, + 194, + 60, + 145, + 29, + 214, + 137, + 239, + 65, + 11, + 209, + 223, + 46, + 37, + 171, + 81, + 123, + 34, + 43, + 21, + 231, + 53, + 52, + 216, + 213, + 99, + 182, + 89, + 234, + 177, + 82, + 8, + 51, + 225, + 91, + 75, + 240, + 77, + 246, + 114, + 130, + 210, + 247, + 50, + 102, + 26, + 181, + 160, + 93, + 228, + 144, + 152, + 172, + 179, + 248, + 164, + 187, + 105, + 218, + 162, + 3, + 44, + 134, + 40, + 120, + 82, + 80, + 195, + 6, + 150, + 51, + 239, + 46, + 71, + 6, + 114, + 59, + 25, + 76, + 173, + 75, + 136, + 76, + 196, + 22, + 19, + 143, + 59, + 254, + 71, + 52, + 155, + 243, + 96, + 170, + 213, + 72, + 109, + 253, + 99, + 28, + 169, + 156, + 14, + 182, + 175, + 53, + 34, + 75, + 8, + 34, + 15, + 34, + 172, + 97, + 153, + 26, + 74, + 211, + 233, + 252, + 6, + 243, + 56, + 203, + 79, + 32, + 68, + 219, + 170, + 201, + 104, + 187, + 80, + 84, + 222, + 48, + 250, + 81, + 131, + 126, + 71, + 150, + 17, + 20, + 255, + 214, + 26, + 209, + 52, + 74, + 251, + 0, + 147, + 19, + 129, + 109, + 139, + 159, + 158, + 132, + 49, + 92, + 196, + 157, + 40, + 255, + 48, + 156, + 61, + 210, + 2, + 209, + 80, + 148, + 183, + 235, + 141, + 157, + 96, + 164, + 15, + 195, + 65, + 67, + 226, + 226, + 85, + 36, + 90, + 139, + 123, + 226, + 102, + 234, + 175, + 101, + 34, + 54, + 200, + 254, + 234, + 82, + 28, + 166, + 39, + 219, + 137, + 53, + 38, + 111, + 230, + 69, + 244, + 29, + 43, + 224, + 58, + 192, + 221, + 236, + 29, + 227, + 110, + 77, + 126, + 176, + 55, + 1, + 110, + 123, + 139, + 170, + 17, + 236, + 109, + 237, + 53, + 88, + 28, + 157, + 5, + 112, + 93, + 114, + 43, + 38, + 130, + 71, + 91, + 192, + 169, + 37, + 94, + 129, + 56, + 9, + 115, + 42, + 100, + 38, + 119, + 222, + 211, + 207, + 104, + 13, + 240, + 76, + 112, + 18, + 138, + 111, + 21, + 205, + 168, + 208, + 148, + 35, + 245, + 227, + 123, + 187, + 3, + 49, + 86, + 79, + 190, + 41, + 5, + 191, + 161, + 140, + 245, + 1, + 112, + 91, + 142, + 196, + 240, + 59, + 33, + 142, + 248, + 232, + 206, + 26, + 19, + 143, + 14, + 4, + 238, + 82, + 196, + 229, + 22, + 30, + 187, + 204, + 254, + 59, + 243, + 66, + 61, + 247, + 21, + 239, + 95, + 156, + 149, + 60, + 68, + 180, + 41, + 93, + 56, + 23, + 218, + 98, + 173, + 102, + 226, + 128, + 239, + 151, + 125, + 43, + 158, + 239, + 9, + 254, + 202, + 238, + 7, + 19, + 238, + 186, + 237, + 196, + 14, + 57, + 176, + 49, + 46, + 161, + 16, + 205, + 97, + 159, + 39, + 117, + 224, + 234, + 39, + 246, + 61, + 187, + 9, + 48, + 30, + 187, + 74, + 103, + 28, + 56, + 32, + 239, + 232, + 71, + 217, + 227, + 213, + 52, + 236, + 234, + 65, + 26, + 26, + 242, + 106, + 49, + 195, + 255, + 240, + 11, + 212, + 221, + 30, + 219, + 1, + 48, + 214, + 149, + 227, + 203, + 204, + 33, + 237, + 39, + 89, + 61, + 142, + 180, + 24, + 242, + 242, + 52, + 160, + 199, + 99, + 206, + 84, + 82, + 44, + 43, + 115, + 221, + 173, + 12, + 28, + 84, + 156, + 119, + 13, + 54, + 31, + 219, + 84, + 6, + 195, + 101, + 151, + 230, + 185, + 110, + 114, + 140, + 120, + 18, + 31, + 238, + 93, + 40, + 28, + 201, + 191, + 76, + 233, + 189, + 31, + 238, + 66, + 200, + 227, + 230, + 117, + 207, + 150, + 154, + 75, + 13, + 0, + 186, + 205, + 245, + 96, + 198, + 249, + 98, + 99, + 7, + 16, + 192, + 55, + 255, + 79, + 182, + 144, + 4, + 32, + 181, + 70, + 56, + 99, + 141, + 58, + 229, + 223, + 124, + 134, + 128, + 78, + 197, + 64, + 59, + 199, + 124, + 167, + 126, + 138, + 4, + 91, + 122, + 135, + 236, + 58, + 182, + 81, + 18, + 201, + 182, + 60, + 218, + 124, + 167, + 206, + 114, + 109, + 146, + 184, + 123, + 163, + 183, + 116, + 41, + 170, + 238, + 13, + 254, + 60, + 51, + 214, + 202, + 74, + 53, + 178, + 74, + 92, + 111, + 190, + 137, + 144, + 200, + 136, + 226, + 208, + 178, + 23, + 25, + 17, + 91, + 159, + 233, + 231, + 222, + 87, + 211, + 220, + 195, + 34, + 23, + 192, + 249, + 171, + 188, + 195, + 206, + 55, + 46, + 16, + 220, + 80, + 182, + 238, + 170, + 202, + 183, + 245, + 52, + 93, + 57, + 178, + 245, + 29, + 136, + 142, + 239, + 73, + 129, + 1, + 30, + 116, + 156, + 97, + 41, + 254, + 63, + 109, + 71, + 126, + 190, + 84, + 15, + 223, + 115, + 114, + 83, + 139, + 44, + 246, + 58, + 43, + 125, + 112, + 91, + 237, + 254, + 46, + 18, + 158, + 120, + 164, + 15, + 1, + 64, + 111, + 188, + 132, + 151, + 142, + 66, + 140, + 187, + 4, + 126, + 123, + 95, + 192, + 242, + 160, + 89, + 202, + 28, + 194, + 94, + 86, + 222, + 9, + 46, + 113, + 216, + 136, + 239, + 12, + 17, + 209, + 46, + 248, + 236, + 132, + 125, + 247, + 219, + 204, + 217, + 98, + 198, + 125, + 157, + 82, + 127, + 182, + 48, + 60, + 140, + 222, + 113, + 207, + 147, + 27, + 47, + 212, + 68, + 186, + 117, + 175, + 22, + 121, + 160, + 33, + 164, + 207, + 22, + 170, + 100, + 192, + 147, + 47, + 1, + 155, + 32, + 231, + 240, + 245, + 233, + 223, + 219, + 49, + 90, + 146, + 20, + 30, + 209, + 111, + 116, + 166, + 255, + 238, + 37, + 111, + 59, + 4, + 137, + 157, + 118, + 242, + 105, + 243, + 157, + 82, + 20, + 176, + 142, + 28, + 113, + 246, + 111, + 159, + 225, + 159, + 51, + 48, + 172, + 182, + 16, + 232, + 179, + 228, + 120, + 65, + 83, + 242, + 1, + 23, + 117, + 236, + 122, + 51, + 30, + 215, + 80, + 110, + 82, + 190, + 197, + 121, + 6, + 195, + 94, + 131, + 117, + 49, + 56, + 155, + 14, + 22, + 102, + 187, + 76, + 85, + 74, + 15, + 96, + 247, + 150, + 168, + 62, + 144, + 71, + 188, + 190, + 187, + 158, + 5, + 154, + 181, + 38, + 147, + 76, + 102, + 64, + 146, + 45, + 122, + 215, + 138, + 131, + 178, + 231, + 28, + 215, + 239, + 144, + 86, + 176, + 156, + 94, + 225, + 235, + 219, + 104, + 41, + 144, + 11, + 225, + 2, + 181, + 126, + 194, + 160, + 145, + 45, + 141, + 175, + 232, + 226, + 221, + 195, + 129, + 127, + 104, + 180, + 223, + 177, + 49, + 113, + 140, + 210, + 40, + 198, + 140, + 84, + 101, + 229, + 183, + 121, + 94, + 16, + 225, + 40, + 18, + 1, + 83, + 189, + 41, + 16, + 153, + 76, + 202, + 91, + 94, + 55, + 245, + 147, + 158, + 217, + 231, + 100, + 40, + 53, + 100, + 115, + 34, + 89, + 223, + 118, + 134, + 120, + 236, + 69, + 175, + 113, + 179, + 130, + 66, + 127, + 196, + 24, + 58, + 72, + 57, + 46, + 210, + 157, + 185, + 120, + 67, + 238, + 112, + 134, + 51, + 64, + 244, + 13, + 110, + 163, + 184, + 38, + 77, + 101, + 253, + 85, + 253, + 254, + 147, + 204, + 53, + 220, + 180, + 146, + 204, + 102, + 64, + 15, + 246, + 65, + 108, + 172, + 171, + 126, + 43, + 74, + 68, + 77, + 53, + 200, + 66, + 95, + 185, + 47, + 212, + 149, + 222, + 35, + 219, + 143, + 151, + 162, + 187, + 142, + 108, + 41, + 165, + 228, + 21, + 205, + 56, + 160, + 141, + 134, + 45, + 205, + 51, + 187, + 193, + 161, + 121, + 6, + 44, + 242, + 163, + 51, + 207, + 173, + 120, + 81, + 159, + 116, + 29, + 31, + 98, + 46, + 168, + 166, + 171, + 216, + 18, + 88, + 36, + 194, + 240, + 60, + 163, + 242, + 96, + 247, + 115, + 15, + 252, + 56, + 40, + 233, + 0, + 156, + 51, + 143, + 36, + 66, + 84, + 51, + 112, + 121, + 77, + 87, + 230, + 138, + 141, + 178, + 151, + 130, + 158, + 214, + 10, + 234, + 244, + 104, + 134, + 157, + 115, + 115, + 199, + 203, + 171, + 85, + 252, + 110, + 195, + 60, + 234, + 20, + 67, + 24, + 119, + 132, + 146, + 73, + 79, + 213, + 19, + 167, + 199, + 102, + 252, + 69, + 92, + 126, + 221, + 143, + 253, + 71, + 233, + 77, + 223, + 93, + 0, + 104, + 255, + 235, + 58, + 77, + 66, + 95, + 131, + 221, + 62, + 82, + 27, + 212, + 41, + 135, + 30, + 136, + 254, + 19, + 248, + 211, + 255, + 32, + 12, + 76, + 78, + 89, + 183, + 238, + 183, + 40, + 55, + 108, + 2, + 118, + 117, + 77, + 178, + 88, + 25, + 108, + 47, + 226, + 112, + 96, + 149, + 102, + 76, + 226, + 26, + 155, + 50, + 104, + 29, + 167, + 202, + 167, + 61, + 115, + 82, + 49, + 33, + 176, + 28, + 250, + 117, + 236, + 92, + 194, + 117, + 55, + 60, + 43, + 91, + 164, + 41, + 255, + 7, + 94, + 31, + 112, + 42, + 59, + 243, + 163, + 176, + 151, + 113, + 137, + 171, + 243, + 200, + 241, + 255, + 35, + 16, + 56, + 107, + 73, + 54, + 190, + 120, + 84, + 215, + 6, + 204, + 200, + 216, + 4, + 34, + 68, + 71, + 3, + 116, + 29, + 210, + 222, + 170, + 123, + 173, + 5, + 182, + 219, + 132, + 56, + 211, + 254, + 189, + 6, + 122, + 222, + 96, + 244, + 6, + 90, + 114, + 81, + 46, + 206, + 135, + 7, + 114, + 115, + 166, + 179, + 94, + 66, + 210, + 206, + 116, + 174, + 118, + 125, + 221, + 78, + 220, + 166, + 193, + 167, + 68, + 65, + 216, + 183, + 146, + 86, + 116, + 56, + 14, + 209, + 234, + 75, + 32, + 202, + 160, + 230, + 223, + 128, + 150, + 81, + 196, + 253, + 248, + 249, + 104, + 158, + 52, + 41, + 132, + 238, + 81, + 11, + 216, + 154, + 255, + 223, + 128, + 185, + 5, + 93, + 118, + 109, + 229, + 112, + 123, + 28, + 128, + 54, + 50, + 49, + 106, + 182, + 44, + 85, + 68, + 68, + 245, + 94, + 37, + 114, + 103, + 201, + 130, + 231, + 95, + 211, + 93, + 78, + 254, + 67, + 89, + 14, + 139, + 221, + 188, + 187, + 226, + 124, + 100, + 215, + 238, + 249, + 233, + 88, + 253, + 200, + 121, + 80, + 224, + 183, + 227, + 89, + 237, + 190, + 172, + 112, + 103, + 3, + 134, + 246, + 71, + 124, + 190, + 8, + 0, + 25, + 164, + 5, + 19, + 144, + 59, + 124, + 91, + 181, + 125, + 231, + 51, + 116, + 182, + 113, + 235, + 65, + 25, + 143, + 249, + 151, + 29, + 217, + 135, + 128, + 111, + 203, + 154, + 159, + 94, + 57, + 232, + 232, + 67, + 36, + 193, + 209, + 241, + 28, + 159, + 30, + 44, + 3, + 40, + 134, + 8, + 32, + 187, + 254, + 235, + 191, + 34, + 106, + 35, + 90, + 108, + 224, + 162, + 83, + 162, + 176, + 120, + 42, + 243, + 95, + 187, + 67, + 138, + 6, + 64, + 251, + 130, + 205, + 127, + 188, + 53, + 31, + 34, + 18, + 199, + 4, + 176, + 188, + 134, + 129, + 237, + 76, + 68, + 167, + 199, + 131, + 17, + 188, + 37, + 39, + 181, + 155, + 60, + 250, + 144, + 17, + 168, + 71, + 125, + 77, + 171, + 81, + 201, + 119, + 147, + 163, + 96, + 142, + 150, + 122, + 56, + 91, + 199, + 63, + 168, + 185, + 228, + 189, + 48, + 118, + 85, + 93, + 144, + 214, + 249, + 93, + 255, + 128, + 7, + 177, + 235, + 26, + 49, + 191, + 161, + 58, + 132, + 215, + 238, + 133, + 3, + 232, + 190, + 250, + 240, + 148, + 169, + 17, + 61, + 206, + 14, + 39, + 216, + 7, + 54, + 207, + 163, + 43, + 115, + 181, + 87, + 181, + 43, + 254, + 99, + 242, + 253, + 108, + 48, + 189, + 1, + 58, + 90, + 52, + 185, + 87, + 62, + 134, + 127, + 69, + 125, + 113, + 119, + 119, + 74, + 87, + 249, + 112, + 112, + 83, + 188, + 161, + 75, + 166, + 116, + 22, + 236, + 212, + 240, + 158, + 84, + 31, + 33, + 205, + 124, + 233, + 215, + 40, + 206, + 40, + 81, + 240, + 54, + 133, + 157, + 130, + 11, + 3, + 32, + 24, + 85, + 54, + 236, + 63, + 24, + 157, + 255, + 211, + 97, + 119, + 32, + 75, + 122, + 110, + 96, + 231, + 227, + 193, + 20, + 240, + 179, + 78, + 234, + 69, + 35, + 131, + 211, + 142, + 237, + 79, + 194, + 86, + 243, + 150, + 11, + 141, + 132, + 62, + 122, + 212, + 83, + 221, + 96, + 149, + 187, + 111, + 78, + 44, + 35, + 140, + 119, + 176, + 81, + 101, + 194, + 116, + 191, + 180, + 186, + 171, + 151, + 96, + 83, + 172, + 32, + 183, + 21, + 181, + 135, + 237, + 228, + 99, + 195, + 73, + 96, + 118, + 163, + 53, + 195, + 122, + 217, + 91, + 196, + 151, + 48, + 234, + 15, + 142, + 218, + 73, + 44, + 66, + 227, + 30, + 18, + 70, + 20, + 50, + 189, + 75, + 45, + 94, + 127, + 21, + 212, + 66, + 159, + 170, + 153, + 10, + 173, + 178, + 88, + 155, + 2, + 33, + 142, + 164, + 188, + 57, + 33, + 120, + 173, + 225, + 51, + 82, + 100, + 155, + 85, + 244, + 180, + 32, + 47, + 0, + 99, + 54, + 171, + 113, + 163, + 35, + 161, + 40, + 230, + 64, + 16, + 113, + 229, + 86, + 131, + 159, + 124, + 59, + 121, + 254, + 180, + 25, + 120, + 20, + 253, + 112, + 46, + 173, + 179, + 107, + 179, + 213, + 223, + 10, + 211, + 224, + 70, + 247, + 148, + 114, + 54, + 39, + 92, + 229, + 238, + 128, + 71, + 192, + 63, + 249, + 35, + 29, + 84, + 5, + 151, + 96, + 37, + 170, + 240, + 152, + 52, + 185, + 139, + 135, + 222, + 216, + 18, + 50, + 113, + 155, + 59, + 104, + 38, + 15, + 252, + 164, + 74, + 17, + 40, + 138, + 188, + 114, + 124, + 142, + 225, + 112, + 250, + 15, + 224, + 90, + 223, + 167, + 34, + 224, + 32, + 7, + 180, + 191, + 118, + 3, + 212, + 152, + 8, + 57, + 179, + 127, + 195, + 182, + 151, + 124, + 45, + 183, + 76, + 50, + 229, + 1, + 13, + 55, + 168, + 19, + 194, + 197, + 199, + 245, + 153, + 255, + 19, + 32, + 154, + 118, + 31, + 168, + 97, + 212, + 149, + 128, + 83, + 63, + 53, + 49, + 250, + 125, + 249, + 167, + 52, + 102, + 190, + 188, + 215, + 61, + 249, + 5, + 147, + 12, + 34, + 207, + 120, + 119, + 164, + 171, + 220, + 197, + 218, + 21, + 194, + 115, + 175, + 45, + 212, + 198, + 69, + 8, + 181, + 179, + 53, + 80, + 114, + 151, + 99, + 253, + 239, + 42, + 0, + 103, + 186, + 72, + 207, + 171, + 123, + 12, + 203, + 122, + 149, + 134, + 184, + 120, + 235, + 53, + 71, + 115, + 85, + 152, + 254, + 251, + 109, + 229, + 145, + 25, + 99, + 94, + 15, + 177, + 147, + 90, + 76, + 112, + 143, + 16, + 76, + 72, + 232, + 169, + 32, + 30, + 79, + 76, + 64, + 134, + 191, + 38, + 249, + 163, + 3, + 161, + 101, + 214, + 175, + 123, + 187, + 9, + 114, + 192, + 156, + 33, + 31, + 0, + 23, + 106, + 207, + 54, + 34, + 233, + 41, + 2, + 69, + 40, + 73, + 18, + 189, + 216, + 124, + 89, + 179, + 77, + 150, + 127, + 48, + 180, + 185, + 11, + 57, + 243, + 90, + 80, + 135, + 194, + 51, + 90, + 114, + 71, + 76, + 20, + 119, + 187, + 111, + 97, + 237, + 78, + 228, + 159, + 69, + 237, + 56, + 17, + 195, + 140, + 147, + 24, + 198, + 149, + 181, + 173, + 183, + 214, + 29, + 33, + 255, + 144, + 187, + 89, + 65, + 57, + 245, + 160, + 172, + 153, + 155, + 229, + 173, + 58, + 1, + 74, + 155, + 82, + 85, + 191, + 11, + 148, + 103, + 100, + 6, + 19, + 113, + 36, + 158, + 79, + 162, + 213, + 231, + 253, + 180, + 159, + 197, + 33, + 150, + 121, + 104, + 26, + 88, + 31, + 120, + 238, + 174, + 87, + 15, + 116, + 126, + 63, + 73, + 125, + 204, + 81, + 9, + 94, + 29, + 246, + 160, + 78, + 128, + 99, + 148, + 136, + 157, + 108, + 214, + 30, + 214, + 238, + 251, + 168, + 198, + 214, + 87, + 170, + 127, + 230, + 81, + 185, + 112, + 88, + 140, + 58, + 3, + 163, + 157, + 3, + 75, + 134, + 201, + 100, + 4, + 16, + 118, + 132, + 129, + 168, + 141, + 61, + 182, + 65, + 142, + 40, + 42, + 114, + 65, + 143, + 235, + 40, + 93, + 53, + 91, + 48, + 184, + 172, + 97, + 186, + 118, + 90, + 217, + 91, + 26, + 7, + 177, + 13, + 181, + 124, + 9, + 60, + 93, + 46, + 85, + 222, + 109, + 116, + 48, + 103, + 246, + 169, + 193, + 222, + 6, + 56, + 18, + 43, + 128, + 131, + 168, + 190, + 219, + 232, + 64, + 115, + 11, + 47, + 145, + 55, + 58, + 71, + 196, + 46, + 50, + 17, + 71, + 7, + 224, + 124, + 75, + 24, + 17, + 188, + 40, + 196, + 62, + 176, + 214, + 69, + 159, + 162, + 237, + 166, + 195, + 66, + 28, + 166, + 38, + 169, + 191, + 210, + 225, + 80, + 79, + 21, + 201, + 17, + 174, + 165, + 35, + 252, + 104, + 180, + 50, + 187, + 8, + 56, + 84, + 188, + 92, + 129, + 31, + 168, + 205, + 250, + 241, + 101, + 226, + 160, + 23, + 207, + 206, + 242, + 211, + 189, + 63, + 104, + 6, + 48, + 49, + 188, + 32, + 146, + 227, + 0, + 119, + 135, + 203, + 22, + 119, + 105, + 1, + 60, + 110, + 218, + 154, + 167, + 24, + 102, + 124, + 99, + 178, + 37, + 154, + 80, + 166, + 87, + 159, + 87, + 178, + 93, + 198, + 178, + 197, + 118, + 253, + 139, + 47, + 126, + 25, + 43, + 140, + 192, + 102, + 89, + 210, + 237, + 103, + 132, + 145, + 59, + 21, + 44, + 224, + 30, + 146, + 231, + 250, + 73, + 26, + 154, + 25, + 107, + 215, + 253, + 15, + 17, + 183, + 14, + 219, + 151, + 46, + 72, + 243, + 25, + 65, + 102, + 109, + 209, + 179, + 5, + 18, + 209, + 41, + 31, + 176, + 235, + 132, + 100, + 83, + 157, + 113, + 192, + 212, + 70, + 235, + 194, + 148, + 200, + 91, + 211, + 75, + 84, + 43, + 107, + 168, + 114, + 221, + 189, + 218, + 180, + 160, + 113, + 40, + 31, + 182, + 185, + 72, + 96, + 51, + 8, + 210, + 137, + 220, + 148, + 103, + 97, + 214, + 75, + 96, + 169, + 64, + 6, + 57, + 71, + 9, + 230, + 18, + 18, + 175, + 19, + 132, + 109, + 77, + 44, + 120, + 193, + 115, + 229, + 240, + 229, + 189, + 226, + 32, + 199, + 110, + 30, + 52, + 37, + 120, + 70, + 243, + 194, + 52, + 32, + 6, + 131, + 173, + 127, + 191, + 251, + 46, + 30, + 182, + 241, + 138, + 39, + 62, + 36, + 19, + 80, + 172, + 104, + 44, + 109, + 89, + 73, + 47, + 8, + 231, + 67, + 152, + 103, + 56, + 196, + 172, + 236, + 103, + 104, + 145, + 222, + 246, + 181, + 3, + 14, + 168, + 109, + 119, + 217, + 134, + 241, + 97, + 21, + 22, + 241, + 1, + 137, + 79, + 124, + 134, + 179, + 231, + 44, + 216, + 213, + 122, + 145, + 4, + 86, + 47, + 190, + 251, + 239, + 166, + 48, + 207, + 5, + 11, + 238, + 225, + 194, + 15, + 224, + 91, + 47, + 10, + 36, + 216, + 45, + 138, + 139, + 178, + 165, + 50, + 54, + 54, + 191, + 164, + 17, + 107, + 94, + 73, + 53, + 20, + 67, + 196, + 140, + 176, + 231, + 189, + 155, + 100, + 84, + 37, + 118, + 127, + 216, + 168, + 185, + 131, + 1, + 95, + 25, + 81, + 22, + 216, + 25, + 22, + 150, + 87, + 196, + 235, + 204, + 154, + 218, + 86, + 168, + 212, + 41, + 13, + 144, + 57, + 130, + 50, + 2, + 12, + 68, + 62, + 118, + 56, + 17, + 123, + 128, + 185, + 103, + 147, + 70, + 185, + 43, + 23, + 168, + 132, + 14, + 8, + 3, + 231, + 183, + 118, + 216, + 24, + 63, + 94, + 131, + 163, + 137, + 104, + 25, + 167, + 249, + 96, + 255, + 32, + 91, + 196, + 216, + 124, + 35, + 28, + 7, + 152, + 60, + 200, + 18, + 25, + 80, + 204, + 242, + 73, + 94, + 124, + 127, + 196, + 209, + 138, + 9, + 13, + 240, + 107, + 145, + 10, + 126, + 112, + 183, + 163, + 249, + 200, + 243, + 18, + 227, + 37, + 186, + 245, + 56, + 195, + 217, + 89, + 4, + 35, + 134, + 252, + 145, + 54, + 39, + 194, + 221, + 39, + 142, + 146, + 238, + 186, + 5, + 223, + 179, + 104, + 145, + 214, + 107, + 171, + 226, + 246, + 175, + 167, + 72, + 3, + 72, + 178, + 205, + 242, + 23, + 79, + 52, + 41, + 31, + 221, + 169, + 71, + 153, + 154, + 245, + 85, + 102, + 101, + 181, + 113, + 57, + 49, + 101, + 44, + 180, + 15, + 235, + 122, + 60, + 173, + 15, + 46, + 101, + 73, + 63, + 194, + 241, + 158, + 214, + 164, + 106, + 160, + 5, + 37, + 103, + 105, + 198, + 249, + 192, + 21, + 245, + 253, + 28, + 108, + 123, + 143, + 28, + 249, + 130, + 220, + 177, + 47, + 116, + 47, + 30, + 42, + 192, + 169, + 210, + 180, + 6, + 62, + 121, + 186, + 134, + 21, + 187, + 129, + 202, + 81, + 240, + 172, + 115, + 131, + 71, + 34, + 140, + 65, + 122, + 200, + 238, + 121, + 197, + 60, + 230, + 83, + 12, + 63, + 171, + 190, + 137, + 55, + 184, + 15, + 132, + 23, + 10, + 161, + 96, + 163, + 102, + 147, + 173, + 58, + 161, + 224, + 233, + 70, + 93, + 245, + 80, + 164, + 54, + 108, + 196, + 73, + 253, + 66, + 31, + 52, + 167, + 196, + 253, + 170, + 12, + 99, + 216, + 38, + 120, + 108, + 33, + 70, + 144, + 53, + 72, + 245, + 140, + 209, + 220, + 76, + 227, + 172, + 176, + 118, + 238, + 88, + 104, + 235, + 46, + 137, + 60, + 96, + 182, + 132, + 161, + 94, + 2, + 169, + 126, + 254, + 100, + 31, + 93, + 249, + 253, + 90, + 234, + 193, + 58, + 54, + 230, + 154, + 173, + 0, + 14, + 216, + 129, + 117, + 91, + 30, + 173, + 201, + 38, + 35, + 172, + 202, + 116, + 68, + 0, + 187, + 35, + 49, + 153, + 191, + 93, + 53, + 200, + 69, + 11, + 20, + 13, + 73, + 73, + 68, + 112, + 73, + 102, + 138, + 84, + 119, + 89, + 39, + 166, + 26, + 104, + 120, + 158, + 229, + 165, + 204, + 59, + 220, + 96, + 8, + 90, + 34, + 171, + 225, + 21, + 19, + 150, + 50, + 156, + 196, + 254, + 224, + 50, + 0, + 39, + 133, + 232, + 9, + 64, + 177, + 218, + 223, + 3, + 95, + 141, + 210, + 199, + 132, + 243, + 48, + 27, + 18, + 167, + 164, + 214, + 37, + 143, + 91, + 43, + 250, + 83, + 236, + 15, + 20, + 7, + 230, + 183, + 142, + 247, + 214, + 182, + 176, + 177, + 150, + 10, + 49, + 99, + 94, + 146, + 239, + 46, + 134, + 93, + 63, + 51, + 173, + 189, + 254, + 143, + 70, + 140, + 90, + 166, + 145, + 248, + 220, + 54, + 174, + 197, + 119, + 146, + 61, + 142, + 135, + 253, + 230, + 82, + 97, + 40, + 198, + 209, + 22, + 174, + 131, + 36, + 230, + 25, + 31, + 232, + 165, + 134, + 7, + 43, + 221, + 109, + 97, + 94, + 128, + 174, + 249, + 189, + 171, + 238, + 49, + 211, + 102, + 235, + 183, + 7, + 145, + 194, + 70, + 111, + 137, + 43, + 28, + 214, + 173, + 145, + 24, + 106, + 151, + 170, + 59, + 36, + 117, + 217, + 74, + 255, + 16, + 42, + 19, + 143, + 169, + 186, + 125, + 166, + 54, + 209, + 92, + 63, + 191, + 82, + 200, + 192, + 87, + 63, + 200, + 124, + 188, + 54, + 192, + 64, + 94, + 118, + 137, + 61, + 153, + 107, + 42, + 163, + 115, + 190, + 23, + 242, + 155, + 199, + 5, + 19, + 140, + 119, + 182, + 104, + 131, + 196, + 1, + 167, + 126, + 54, + 6, + 50, + 68, + 173, + 33, + 35, + 203, + 62, + 57, + 185, + 32, + 69, + 19, + 239, + 188, + 146, + 71, + 3, + 222, + 13, + 92, + 149, + 61, + 139, + 102, + 84, + 213, + 153, + 110, + 160, + 15, + 82, + 179, + 21, + 234, + 65, + 92, + 31, + 105, + 146, + 76, + 191, + 210, + 213, + 248, + 199, + 121, + 57, + 229, + 178, + 247, + 160, + 129, + 169, + 127, + 152, + 142, + 100, + 182, + 26, + 21, + 231, + 129, + 45, + 208, + 69, + 149, + 42, + 208, + 203, + 66, + 178, + 79, + 106, + 119, + 52, + 77, + 108, + 95, + 78, + 9, + 191, + 39, + 230, + 112, + 242, + 155, + 45, + 177, + 64, + 29, + 139, + 183, + 184, + 35, + 192, + 117, + 244, + 135, + 138, + 161, + 33, + 129, + 39, + 5, + 189, + 221, + 103, + 233, + 41, + 251, + 194, + 115, + 193, + 5, + 222, + 93, + 97, + 154, + 163, + 3, + 28, + 191, + 187, + 205, + 21, + 121, + 87, + 156, + 205, + 174, + 170, + 119, + 207, + 214, + 209, + 54, + 43, + 176, + 243, + 41, + 90, + 62, + 47, + 121, + 235, + 152, + 189, + 223, + 40, + 7, + 20, + 160, + 30, + 147, + 238, + 192, + 199, + 242, + 223, + 190, + 99, + 254, + 29, + 26, + 112, + 211, + 238, + 224, + 22, + 105, + 63, + 8, + 90, + 101, + 245, + 60, + 219, + 15, + 138, + 75, + 23, + 111, + 39, + 53, + 11, + 176, + 132, + 187, + 209, + 198, + 195, + 232, + 101, + 29, + 219, + 100, + 195, + 31, + 66, + 83, + 8, + 149, + 214, + 229, + 192, + 91, + 106, + 194, + 242, + 2, + 128, + 235, + 105, + 16, + 172, + 126, + 42, + 49, + 11, + 113, + 4, + 99, + 250, + 236, + 70, + 29, + 23, + 166, + 16, + 238, + 104, + 196, + 244, + 227, + 28, + 146, + 48, + 241, + 179, + 87, + 222, + 246, + 130, + 41, + 60, + 109, + 152, + 46, + 86, + 191, + 93, + 154, + 37, + 231, + 43, + 89, + 172, + 193, + 37, + 127, + 170, + 164, + 30, + 102, + 249, + 58, + 117, + 145, + 120, + 116, + 250, + 188, + 207, + 73, + 244, + 242, + 235, + 91, + 148, + 237, + 98, + 126, + 198, + 75, + 37, + 241, + 162, + 135, + 63, + 178, + 141, + 214, + 144, + 66, + 178, + 239, + 104, + 206, + 144, + 231, + 99, + 184, + 40, + 127, + 200, + 173, + 77, + 75, + 56, + 48, + 96, + 146, + 57, + 124, + 118, + 70, + 32, + 0, + 64, + 154, + 174, + 172, + 157, + 51, + 150, + 49, + 248, + 236, + 191, + 109, + 226, + 81, + 191, + 48, + 248, + 185, + 217, + 236, + 211, + 220, + 67, + 210, + 99, + 125, + 7, + 118, + 182, + 251, + 68, + 61, + 125, + 31, + 210, + 9, + 181, + 100, + 238, + 206, + 31, + 18, + 245, + 166, + 172, + 139, + 90, + 193, + 162, + 73, + 207, + 7, + 67, + 97, + 143, + 235, + 222, + 78, + 17, + 109, + 96, + 197, + 15, + 39, + 202, + 184, + 213, + 98, + 204, + 2, + 188, + 18, + 198, + 135, + 106, + 92, + 172, + 208, + 145, + 207, + 173, + 120, + 49, + 107, + 33, + 187, + 77, + 76, + 185, + 84, + 17, + 34, + 139, + 85, + 41, + 91, + 120, + 226, + 210, + 133, + 161, + 131, + 95, + 49, + 244, + 171, + 97, + 125, + 22, + 80, + 168, + 63, + 131, + 48, + 187, + 134, + 93, + 89, + 103, + 206, + 141, + 117, + 7, + 178, + 136, + 106, + 240, + 190, + 82, + 104, + 166, + 175, + 45, + 31, + 24, + 79, + 222, + 114, + 152, + 7, + 220, + 138, + 231, + 218, + 4, + 34, + 176, + 13, + 43, + 136, + 87, + 28, + 63, + 34, + 65, + 76, + 120, + 71, + 155, + 255, + 22, + 144, + 236, + 18, + 110, + 180, + 185, + 136, + 39, + 108, + 103, + 130, + 150, + 169, + 161, + 92, + 65, + 53, + 96, + 125, + 71, + 186, + 203, + 67, + 185, + 214, + 67, + 175, + 113, + 49, + 230, + 67, + 151, + 158, + 95, + 173, + 188, + 157, + 250, + 29, + 97, + 54, + 214, + 124, + 141, + 246, + 233, + 73, + 159, + 68, + 140, + 80, + 45, + 212, + 249, + 219, + 233, + 44, + 30, + 83, + 178, + 52, + 49, + 154, + 139, + 97, + 19, + 235, + 217, + 97, + 66, + 239, + 21, + 192, + 156, + 143, + 6, + 199, + 162, + 195, + 120, + 141, + 133, + 12, + 101, + 65, + 100, + 191, + 165, + 106, + 37, + 164, + 77, + 225, + 244, + 192, + 68, + 7, + 124, + 81, + 42, + 85, + 109, + 44, + 100, + 221, + 36, + 49, + 205, + 46, + 132, + 249, + 201, + 251, + 146, + 139, + 65, + 165, + 21, + 80, + 118, + 215, + 30, + 61, + 198, + 190, + 6, + 194, + 103, + 42, + 241, + 74, + 182, + 3, + 130, + 255, + 21, + 17, + 53, + 203, + 145, + 33, + 137, + 251, + 234, + 154, + 4, + 81, + 186, + 148, + 83, + 19, + 193, + 21, + 7, + 57, + 129, + 76, + 176, + 57, + 160, + 187, + 168, + 41, + 220, + 234, + 128, + 149, + 18, + 96, + 43, + 80, + 2, + 51, + 189, + 30, + 183, + 72, + 188, + 117, + 118, + 195, + 148, + 212, + 103, + 244, + 89, + 196, + 135, + 162, + 79, + 162, + 132, + 133, + 209, + 126, + 142, + 87, + 24, + 203, + 116, + 50, + 143, + 22, + 165, + 168, + 54, + 110, + 175, + 234, + 24, + 51, + 19, + 211, + 135, + 144, + 251, + 125, + 81, + 170, + 216, + 43, + 84, + 110, + 67, + 94, + 182, + 120, + 14, + 200, + 79, + 48, + 228, + 160, + 226, + 118, + 19, + 112, + 208, + 151, + 13, + 60, + 159, + 30, + 5, + 188, + 52, + 215, + 207, + 164, + 73, + 30, + 100, + 71, + 228, + 177, + 247, + 226, + 82, + 82, + 201, + 188, + 99, + 239, + 174, + 184, + 203, + 232, + 44, + 163, + 211, + 122, + 114, + 213, + 83, + 177, + 221, + 173, + 221, + 224, + 44, + 232, + 87, + 176, + 234, + 134, + 157, + 119, + 43, + 180, + 103, + 35, + 148, + 30, + 224, + 8, + 236, + 68, + 235, + 146, + 196, + 33, + 7, + 80, + 66, + 183, + 36, + 119, + 235, + 220, + 222, + 173, + 123, + 89, + 103, + 99, + 192, + 70, + 122, + 25, + 78, + 83, + 232, + 196, + 122, + 52, + 64, + 51, + 221, + 234, + 37, + 13, + 12, + 89, + 109, + 240, + 75, + 147, + 164, + 4, + 235, + 232, + 193, + 106, + 61, + 69, + 56, + 20, + 41, + 221, + 186, + 53, + 231, + 59, + 170, + 191, + 169, + 17, + 121, + 164, + 8, + 156, + 16, + 5, + 137, + 144, + 58, + 68, + 178, + 69, + 140, + 173, + 21, + 125, + 232, + 190, + 80, + 215, + 111, + 74, + 221, + 254, + 175, + 112, + 67, + 74, + 38, + 100, + 112, + 248, + 227, + 53, + 169, + 225, + 197, + 184, + 123, + 95, + 249, + 1, + 6, + 116, + 1, + 138, + 27, + 221, + 208, + 245, + 81, + 17, + 24, + 249, + 29, + 52, + 1, + 42, + 155, + 43, + 107, + 167, + 169, + 174, + 129, + 84, + 146, + 158, + 128, + 131, + 157, + 25, + 96, + 150, + 94, + 129, + 206, + 243, + 95, + 80, + 153, + 5, + 52, + 31, + 34, + 129, + 100, + 99, + 244, + 150, + 253, + 226, + 203, + 33, + 192, + 147, + 154, + 25, + 142, + 153, + 38, + 117, + 172, + 188, + 138, + 44, + 107, + 133, + 218, + 189, + 252, + 200, + 21, + 79, + 40, + 147, + 63, + 179, + 125, + 254, + 60, + 60, + 102, + 31, + 146, + 244, + 102, + 240, + 66, + 88, + 76, + 157, + 137, + 11, + 41, + 27, + 9, + 231, + 29, + 25, + 114, + 58, + 222, + 139, + 60, + 2, + 45, + 86, + 72, + 145, + 205, + 164, + 241, + 162, + 223, + 86, + 136, + 219, + 66, + 82, + 160, + 212, + 123, + 9, + 177, + 235, + 120, + 147, + 202, + 26, + 37, + 212, + 98, + 23, + 138, + 165, + 12, + 147, + 39, + 41, + 26, + 215, + 59, + 161, + 100, + 27, + 12, + 104, + 53, + 164, + 94, + 227, + 106, + 83, + 249, + 187, + 81, + 14, + 9, + 253, + 17, + 193, + 225, + 25, + 91, + 100, + 233, + 211, + 184, + 7, + 87, + 162, + 94, + 248, + 127, + 243, + 171, + 170, + 213, + 208, + 20, + 10, + 26, + 24, + 189, + 23, + 58, + 62, + 58, + 181, + 153, + 8, + 118, + 162, + 179, + 76, + 149, + 198, + 32, + 24, + 153, + 37, + 10, + 214, + 96, + 6, + 1, + 42, + 71, + 157, + 100, + 53, + 192, + 108, + 109, + 130, + 48, + 85, + 220, + 4, + 76, + 224, + 89, + 220, + 152, + 94, + 103, + 125, + 53, + 213, + 167, + 225, + 182, + 241, + 176, + 185, + 108, + 7, + 208, + 204, + 171, + 115, + 92, + 57, + 87, + 74, + 64, + 228, + 222, + 104, + 117, + 223, + 209, + 139, + 218, + 168, + 26, + 249, + 153, + 35, + 80, + 80, + 49, + 197, + 187, + 75, + 102, + 87, + 105, + 122, + 91, + 44, + 114, + 204, + 183, + 4, + 149, + 156, + 176, + 65, + 130, + 135, + 215, + 93, + 247, + 150, + 119, + 63, + 87, + 236, + 85, + 167, + 245, + 31, + 76, + 122, + 148, + 183, + 75, + 23, + 45, + 120, + 112, + 212, + 42, + 37, + 193, + 44, + 66, + 33, + 6, + 85, + 243, + 32, + 230, + 83, + 145, + 201, + 47, + 170, + 191, + 34, + 8, + 3, + 64, + 107, + 188, + 207, + 85, + 30, + 218, + 60, + 69, + 93, + 247, + 186, + 53, + 145, + 72, + 101, + 185, + 160, + 139, + 109, + 44, + 121, + 112, + 102, + 48, + 78, + 44, + 82, + 86, + 196, + 22, + 118, + 16, + 194, + 80, + 200, + 13, + 232, + 155, + 106, + 48, + 73, + 97, + 197, + 98, + 111, + 204, + 31, + 150, + 30, + 148, + 213, + 49, + 50, + 223, + 253, + 212, + 26, + 186, + 96, + 141, + 123, + 69, + 8, + 168, + 88, + 193, + 229, + 164, + 48, + 40, + 79, + 106, + 236, + 156, + 206, + 99, + 96, + 116, + 7, + 30, + 30, + 60, + 16, + 117, + 63, + 52, + 102, + 132, + 195, + 9, + 83, + 56, + 141, + 235, + 18, + 172, + 162, + 147, + 54, + 218, + 125, + 150, + 109, + 89, + 11, + 151, + 252, + 102, + 47, + 168, + 159, + 238, + 50, + 75, + 226, + 169, + 59, + 28, + 238, + 148, + 226, + 241, + 249, + 85, + 4, + 237, + 107, + 121, + 118, + 242, + 227, + 177, + 26, + 153, + 202, + 31, + 87, + 19, + 159, + 90, + 70, + 228, + 28, + 19, + 170, + 27, + 189, + 244, + 193, + 106, + 75, + 39, + 34, + 165, + 106, + 148, + 129, + 159, + 125, + 63, + 80, + 23, + 246, + 173, + 0, + 139, + 118, + 21, + 227, + 229, + 4, + 139, + 0, + 180, + 139, + 14, + 123, + 211, + 151, + 225, + 193, + 112, + 10, + 89, + 208, + 96, + 162, + 98, + 71, + 76, + 210, + 229, + 84, + 199, + 73, + 82, + 186, + 221, + 161, + 11, + 123, + 53, + 105, + 25, + 184, + 249, + 215, + 201, + 127, + 125, + 16, + 9, + 214, + 104, + 198, + 42, + 25, + 87, + 172, + 181, + 182, + 121, + 147, + 23, + 64, + 191, + 35, + 252, + 110, + 195, + 177, + 66, + 152, + 216, + 43, + 231, + 53, + 143, + 184, + 189, + 109, + 67, + 85, + 29, + 229, + 17, + 206, + 221, + 212, + 167, + 159, + 40, + 57, + 66, + 161, + 101, + 64, + 151, + 217, + 72, + 221, + 35, + 221, + 30, + 238, + 162, + 247, + 177, + 155, + 166, + 33, + 129, + 101, + 147, + 221, + 229, + 60, + 56, + 88, + 210, + 126, + 127, + 209, + 143, + 67, + 147, + 122, + 16, + 224, + 242, + 37, + 69, + 162, + 229, + 131, + 10, + 166, + 31, + 137, + 52, + 34, + 183, + 2, + 69, + 114, + 250, + 125, + 130, + 229, + 133, + 246, + 169, + 196, + 185, + 121, + 65, + 213, + 230, + 1, + 66, + 94, + 205, + 122, + 82, + 100, + 230, + 34, + 104, + 172, + 57, + 239, + 116, + 53, + 165, + 178, + 21, + 254, + 50, + 26, + 214, + 242, + 130, + 141, + 64, + 187, + 95, + 237, + 215, + 202, + 101, + 201, + 12, + 251, + 216, + 133, + 63, + 34, + 45, + 52, + 60, + 141, + 22, + 1, + 113, + 9, + 61, + 59, + 250, + 131, + 168, + 181, + 199, + 35, + 101, + 176, + 46, + 22, + 4, + 0, + 18, + 105, + 65, + 164, + 67, + 33, + 98, + 64, + 98, + 33, + 238, + 119, + 61, + 8, + 84, + 163, + 79, + 106, + 117, + 95, + 70, + 147, + 236, + 120, + 240, + 250, + 22, + 61, + 182, + 206, + 139, + 70, + 225, + 35, + 119, + 47, + 232, + 11, + 94, + 250, + 158, + 92, + 158, + 155, + 16, + 95, + 120, + 25, + 42, + 108, + 42, + 85, + 56, + 128, + 136, + 87, + 97, + 72, + 172, + 40, + 90, + 160, + 87, + 37, + 235, + 175, + 230, + 111, + 248, + 52, + 21, + 139, + 237, + 208, + 234, + 183, + 31, + 157, + 49, + 101, + 220, + 189, + 177, + 139, + 10, + 233, + 64, + 20, + 197, + 141, + 33, + 62, + 158, + 1, + 254, + 45, + 88, + 177, + 50, + 33, + 35, + 88, + 82, + 182, + 86, + 228, + 50, + 66, + 23, + 155, + 15, + 79, + 189, + 86, + 83, + 140, + 71, + 156, + 168, + 193, + 15, + 177, + 58, + 27, + 169, + 233, + 44, + 2, + 127, + 10, + 150, + 29, + 193, + 136, + 164, + 90, + 52, + 131, + 220, + 47, + 99, + 219, + 40, + 35, + 151, + 40, + 164, + 116, + 255, + 9, + 73, + 2, + 151, + 149, + 240, + 5, + 168, + 111, + 44, + 81, + 225, + 226, + 133, + 233, + 184, + 50, + 44, + 170, + 52, + 12, + 57, + 100, + 60, + 123, + 248, + 174, + 143, + 61, + 205, + 48, + 23, + 131, + 249, + 69, + 162, + 96, + 65, + 241, + 219, + 231, + 81, + 23, + 83, + 186, + 166, + 85, + 8, + 119, + 1, + 15, + 35, + 54, + 84, + 231, + 23, + 198, + 212, + 101, + 250, + 24, + 29, + 29, + 120, + 181, + 222, + 217, + 134, + 81, + 106, + 252, + 143, + 149, + 240, + 181, + 100, + 135, + 191, + 188, + 114, + 201, + 136, + 128, + 43, + 235, + 245, + 94, + 28, + 203, + 59, + 134, + 141, + 72, + 255, + 142, + 24, + 74, + 48, + 175, + 66, + 5, + 128, + 190, + 188, + 59, + 38, + 112, + 192, + 95, + 42, + 175, + 95, + 239, + 121, + 111, + 244, + 143, + 255, + 133, + 35, + 197, + 32, + 76, + 25, + 199, + 185, + 242, + 141, + 162, + 209, + 62, + 121, + 246, + 254, + 65, + 193, + 207, + 206, + 159, + 55, + 225, + 57, + 54, + 146, + 59, + 78, + 4, + 196, + 44, + 219, + 5, + 57, + 66, + 240, + 66, + 252, + 188, + 233, + 55, + 156, + 243, + 219, + 3, + 52, + 228, + 27, + 140, + 124, + 142, + 135, + 207, + 170, + 176, + 233, + 22, + 204, + 245, + 199, + 54, + 221, + 65, + 235, + 91, + 21, + 164, + 238, + 88, + 134, + 210, + 33, + 70, + 226, + 120, + 141, + 88, + 23, + 19, + 241, + 163, + 220, + 79, + 132, + 153, + 229, + 113, + 3, + 24, + 219, + 225, + 82, + 87, + 133, + 128, + 62, + 53, + 26, + 214, + 195, + 46, + 145, + 10, + 192, + 151, + 86, + 4, + 194, + 169, + 122, + 204, + 18, + 127, + 110, + 242, + 57, + 177, + 77, + 202, + 12, + 1, + 171, + 67, + 165, + 227, + 151, + 62, + 165, + 95, + 36, + 27, + 190, + 146, + 82, + 124, + 161, + 8, + 66, + 7, + 100, + 35, + 177, + 201, + 80, + 80, + 151, + 97, + 150, + 65, + 112, + 255, + 192, + 103, + 58, + 160, + 168, + 59, + 47, + 207, + 144, + 153, + 63, + 109, + 219, + 106, + 39, + 40, + 197, + 47, + 231, + 153, + 71, + 181, + 214, + 174, + 86, + 202, + 84, + 239, + 170, + 156, + 143, + 55, + 229, + 152, + 194, + 89, + 49, + 237, + 5, + 97, + 181, + 69, + 51, + 24, + 165, + 16, + 242, + 255, + 1, + 198, + 207, + 70, + 174, + 76, + 109, + 0, + 157, + 149, + 221, + 158, + 115, + 23, + 185, + 225, + 56, + 169, + 182, + 227, + 242, + 142, + 237, + 7, + 16, + 141, + 93, + 116, + 236, + 74, + 144, + 233, + 46, + 205, + 227, + 140, + 118, + 211, + 83, + 55, + 107, + 249, + 197, + 73, + 241, + 130, + 45, + 213, + 222, + 195, + 148, + 23, + 54, + 117, + 223, + 54, + 75, + 144, + 29, + 181, + 179, + 146, + 66, + 249, + 56, + 211, + 4, + 152, + 152, + 223, + 66, + 104, + 110, + 106, + 214, + 13, + 107, + 57, + 82, + 67, + 55, + 136, + 159, + 146, + 236, + 110, + 10, + 240, + 208, + 81, + 47, + 218, + 251, + 180, + 172, + 196, + 152, + 126, + 192, + 1, + 99, + 209, + 133, + 170, + 162, + 199, + 172, + 21, + 255, + 244, + 101, + 21, + 128, + 20, + 211, + 203, + 59, + 206, + 132, + 122, + 23, + 60, + 55, + 245, + 154, + 205, + 194, + 40, + 94, + 203, + 3, + 198, + 206, + 199, + 86, + 167, + 69, + 70, + 134, + 27, + 151, + 97, + 36, + 116, + 107, + 189, + 245, + 194, + 135, + 122, + 147, + 88, + 12, + 0, + 97, + 4, + 194, + 86, + 107, + 98, + 237, + 19, + 88, + 150, + 113, + 214, + 24, + 51, + 28, + 49, + 193, + 191, + 108, + 133, + 136, + 170, + 192, + 200, + 137, + 185, + 206, + 100, + 90, + 116, + 82, + 221, + 84, + 173, + 55, + 31, + 74, + 137, + 81, + 93, + 180, + 202, + 56, + 202, + 21, + 220, + 201, + 233, + 96, + 76, + 241, + 228, + 65, + 76, + 161, + 110, + 190, + 70, + 1, + 166, + 214, + 160, + 167, + 71, + 70, + 214, + 118, + 170, + 16, + 230, + 54, + 239, + 20, + 171, + 73, + 43, + 98, + 238, + 189, + 220, + 140, + 218, + 176, + 140, + 235, + 214, + 126, + 197, + 205, + 121, + 169, + 36, + 219, + 33, + 183, + 212, + 87, + 92, + 185, + 45, + 70, + 180, + 86, + 21, + 46, + 53, + 23, + 125, + 49, + 38, + 228, + 169, + 3, + 190, + 48, + 18, + 94, + 177, + 222, + 240, + 89, + 188, + 18, + 30, + 8, + 178, + 82, + 204, + 114, + 47, + 200, + 46, + 146, + 134, + 66, + 162, + 35, + 240, + 136, + 107, + 171, + 233, + 27, + 187, + 251, + 138, + 46, + 152, + 203, + 16, + 171, + 94, + 200, + 13, + 219, + 203, + 186, + 215, + 35, + 33, + 70, + 188, + 19, + 184, + 242, + 47, + 77, + 74, + 191, + 148, + 245, + 60, + 6, + 247, + 94, + 182, + 158, + 61, + 118, + 152, + 186, + 211, + 140, + 118, + 69, + 67, + 252, + 95, + 119, + 176, + 219, + 145, + 85, + 135, + 218, + 137, + 228, + 23, + 195, + 118, + 241, + 49, + 209, + 1, + 20, + 89, + 12, + 173, + 39, + 89, + 76, + 129, + 246, + 41, + 29, + 56, + 100, + 232, + 255, + 20, + 208, + 117, + 166, + 195, + 72, + 179, + 135, + 205, + 79, + 98, + 106, + 114, + 250, + 230, + 175, + 112, + 236, + 87, + 98, + 93, + 241, + 66, + 87, + 77, + 98, + 142, + 225, + 101, + 166, + 11, + 65, + 0, + 46, + 155, + 250, + 192, + 100, + 187, + 213, + 185, + 132, + 193, + 205, + 97, + 151, + 245, + 106, + 94, + 210, + 64, + 126, + 96, + 118, + 104, + 212, + 102, + 185, + 219, + 51, + 110, + 117, + 224, + 87, + 216, + 225, + 51, + 234, + 130, + 21, + 178, + 37, + 8, + 82, + 211, + 71, + 45, + 76, + 174, + 61, + 245, + 4, + 194, + 134, + 92, + 71, + 202, + 42, + 245, + 146, + 201, + 135, + 244, + 1, + 205, + 198, + 12, + 123, + 193, + 66, + 150, + 69, + 220, + 64, + 151, + 219, + 223, + 68, + 161, + 215, + 191, + 203, + 76, + 216, + 160, + 195, + 150, + 121, + 174, + 118, + 70, + 110, + 148, + 198, + 226, + 209, + 25, + 242, + 201, + 37, + 146, + 111, + 62, + 73, + 243, + 186, + 21, + 71, + 175, + 252, + 222, + 9, + 23, + 174, + 177, + 56, + 212, + 93, + 100, + 58, + 13, + 105, + 192, + 114, + 39, + 182, + 108, + 206, + 99, + 69, + 36, + 111, + 6, + 54, + 44, + 75, + 229, + 67, + 91, + 32, + 251, + 227, + 64, + 98, + 52, + 236, + 2, + 22, + 124, + 162, + 253, + 67, + 156, + 146, + 23, + 160, + 48, + 226, + 100, + 231, + 193, + 126, + 89, + 110, + 186, + 29, + 204, + 42, + 34, + 195, + 81, + 195, + 210, + 179, + 161, + 142, + 32, + 71, + 190, + 27, + 68, + 180, + 201, + 157, + 95, + 138, + 224, + 166, + 4, + 47, + 202, + 94, + 24, + 252, + 134, + 182, + 203, + 70, + 217, + 111, + 253, + 71, + 35, + 125, + 22, + 164, + 201, + 227, + 141, + 22, + 40, + 162, + 125, + 60, + 239, + 160, + 226, + 75, + 60, + 187, + 176, + 163, + 123, + 156, + 96, + 84, + 200, + 6, + 244, + 120, + 206, + 51, + 239, + 16, + 27, + 167, + 180, + 174, + 218, + 68, + 237, + 8, + 166, + 226, + 251, + 111, + 113, + 147, + 25, + 87, + 162, + 119, + 33, + 212, + 246, + 190, + 125, + 111, + 168, + 122, + 226, + 107, + 89, + 72, + 117, + 114, + 221, + 177, + 166, + 34, + 185, + 205, + 31, + 132, + 246, + 44, + 220, + 77, + 204, + 64, + 112, + 156, + 252, + 255, + 22, + 210, + 217, + 107, + 234, + 76, + 239, + 107, + 232, + 61, + 216, + 70, + 32, + 93, + 154, + 221, + 15, + 25, + 230, + 82, + 188, + 51, + 175, + 152, + 239, + 114, + 162, + 57, + 74, + 111, + 52, + 217, + 144, + 68, + 58, + 11, + 164, + 37, + 64, + 5, + 250, + 98, + 163, + 2, + 190, + 126, + 251, + 79, + 197, + 19, + 165, + 139, + 233, + 225, + 37, + 34, + 32, + 211, + 45, + 230, + 41, + 164, + 51, + 102, + 19, + 0, + 147, + 208, + 69, + 26, + 56, + 81, + 78, + 148, + 238, + 5, + 241, + 145, + 178, + 23, + 230, + 69, + 171, + 93, + 224, + 13, + 253, + 31, + 238, + 61, + 219, + 200, + 4, + 220, + 163, + 226, + 228, + 107, + 195, + 114, + 12, + 145, + 71, + 37, + 198, + 3, + 197, + 108, + 43, + 220, + 159, + 201, + 114, + 138, + 183, + 24, + 103, + 74, + 72, + 160, + 22, + 72, + 60, + 243, + 230, + 223, + 249, + 163, + 26, + 213, + 32, + 237, + 2, + 44, + 235, + 116, + 3, + 57, + 196, + 61, + 248, + 209, + 173, + 60, + 217, + 156, + 51, + 36, + 202, + 214, + 48, + 122, + 152, + 82, + 204, + 8, + 207, + 116, + 3, + 35, + 220, + 62, + 54, + 46, + 4, + 181, + 133, + 162, + 4, + 206, + 84, + 80, + 197, + 26, + 233, + 243, + 236, + 249, + 80, + 154, + 57, + 95, + 51, + 80, + 55, + 243, + 7, + 119, + 5, + 51, + 32, + 172, + 109, + 220, + 3, + 138, + 180, + 30, + 64, + 48, + 232, + 226, + 103, + 89, + 231, + 246, + 156, + 155, + 143, + 142, + 129, + 115, + 183, + 13, + 103, + 22, + 167, + 10, + 255, + 5, + 166, + 168, + 31, + 242, + 221, + 41, + 165, + 101, + 152, + 43, + 25, + 72, + 128, + 173, + 57, + 80, + 171, + 91, + 3, + 164, + 142, + 111, + 44, + 242, + 5, + 207, + 103, + 23, + 123, + 136, + 247, + 116, + 228, + 68, + 80, + 238, + 64, + 154, + 38, + 174, + 45, + 253, + 65, + 125, + 134, + 215, + 37, + 80, + 220, + 7, + 240, + 127, + 200, + 142, + 82, + 103, + 166, + 11, + 30, + 155, + 70, + 83, + 167, + 34, + 97, + 15, + 91, + 134, + 22, + 139, + 10, + 159, + 117, + 10, + 15, + 83, + 237, + 177, + 22, + 51, + 79, + 9, + 46, + 38, + 111, + 70, + 213, + 32, + 179, + 203, + 17, + 253, + 82, + 21, + 107, + 236, + 108, + 188, + 5, + 113, + 169, + 178, + 220, + 77, + 38, + 33, + 133, + 172, + 100, + 89, + 192, + 68, + 196, + 146, + 4, + 172, + 137, + 77, + 59, + 144, + 165, + 91, + 29, + 2, + 147, + 31, + 205, + 100, + 110, + 104, + 161, + 208, + 153, + 19, + 45, + 226, + 75, + 158, + 35, + 255, + 177, + 39, + 86, + 101, + 72, + 54, + 24, + 177, + 66, + 20, + 75, + 11, + 182, + 176, + 208, + 236, + 17, + 254, + 28, + 37, + 11, + 57, + 98, + 26, + 95, + 148, + 223, + 202, + 168, + 205, + 232, + 88, + 244, + 125, + 33, + 82, + 107, + 22, + 123, + 54, + 53, + 34, + 186, + 93, + 19, + 170, + 170, + 130, + 63, + 250, + 139, + 115, + 98, + 254, + 16, + 140, + 31, + 147, + 104, + 106, + 20, + 254, + 73, + 24, + 137, + 222, + 186, + 110, + 66, + 106, + 233, + 160, + 129, + 181, + 67, + 40, + 188, + 6, + 184, + 60, + 157, + 231, + 106, + 155, + 41, + 118, + 241, + 166, + 16, + 105, + 235, + 4, + 209, + 234, + 214, + 187, + 100, + 156, + 238, + 24, + 85, + 75, + 113, + 66, + 33, + 21, + 188, + 94, + 124, + 88, + 2, + 144, + 143, + 128, + 127, + 123, + 151, + 152, + 248, + 37, + 224, + 106, + 18, + 149, + 215, + 250, + 161, + 12, + 156, + 231, + 150, + 92, + 141, + 227, + 221, + 71, + 188, + 135, + 41, + 25, + 23, + 112, + 181, + 24, + 66, + 114, + 140, + 105, + 166, + 195, + 140, + 91, + 133, + 73, + 89, + 1, + 70, + 55, + 225, + 54, + 3, + 28, + 243, + 70, + 93, + 154, + 34, + 240, + 29, + 161, + 184, + 85, + 192, + 122, + 145, + 43, + 183, + 103, + 11, + 202, + 153, + 47, + 229, + 144, + 58, + 71, + 146, + 38, + 133, + 150, + 85, + 223, + 21, + 72, + 85, + 21, + 211, + 132, + 182, + 147, + 58, + 53, + 163, + 119, + 126, + 35, + 223, + 148, + 123, + 73, + 242, + 192, + 7, + 229, + 211, + 10, + 7, + 134, + 169, + 77, + 183, + 56, + 13, + 59, + 12, + 115, + 203, + 66, + 208, + 115, + 253, + 242, + 177, + 150, + 210, + 206, + 72, + 124, + 65, + 33, + 209, + 193, + 91, + 2, + 55, + 81, + 152, + 180, + 115, + 182, + 17, + 155, + 179, + 126, + 221, + 244, + 172, + 167, + 140, + 62, + 74, + 61, + 172, + 87, + 106, + 195, + 16, + 133, + 127, + 146, + 9, + 247, + 171, + 181, + 131, + 60, + 224, + 198, + 32, + 163, + 124, + 177, + 212, + 149, + 222, + 20, + 160, + 135, + 33, + 149, + 55, + 114, + 143, + 21, + 38, + 71, + 11, + 111, + 146, + 68, + 99, + 65, + 107, + 100, + 18, + 192, + 0, + 17, + 32, + 75, + 159, + 85, + 112, + 229, + 61, + 113, + 201, + 193, + 16, + 163, + 167, + 210, + 237, + 0, + 223, + 76, + 100, + 76, + 202, + 125, + 117, + 204, + 162, + 14, + 69, + 87, + 251, + 26, + 11, + 2, + 89, + 176, + 103, + 199, + 64, + 173, + 0, + 238, + 169, + 156, + 66, + 178, + 112, + 96, + 116, + 68, + 125, + 126, + 52, + 178, + 49, + 210, + 134, + 236, + 254, + 54, + 95, + 45, + 180, + 45, + 76, + 253, + 101, + 62, + 201, + 138, + 40, + 87, + 209, + 135, + 176, + 67, + 95, + 13, + 105, + 174, + 226, + 98, + 102, + 213, + 89, + 144, + 210, + 34, + 176, + 106, + 28, + 176, + 109, + 223, + 93, + 20, + 217, + 198, + 193, + 144, + 163, + 155, + 193, + 237, + 21, + 142, + 201, + 114, + 192, + 207, + 96, + 214, + 159, + 79, + 146, + 94, + 62, + 176, + 185, + 215, + 115, + 15, + 67, + 164, + 246, + 18, + 42, + 27, + 216, + 215, + 72, + 219, + 231, + 35, + 121, + 56, + 90, + 40, + 52, + 176, + 249, + 151, + 230, + 234, + 229, + 99, + 51, + 224, + 212, + 92, + 132, + 174, + 11, + 133, + 96, + 220, + 200, + 34, + 174, + 109, + 41, + 249, + 147, + 4, + 119, + 224, + 225, + 180, + 3, + 29, + 46, + 52, + 45, + 133, + 166, + 249, + 221, + 13, + 57, + 59, + 150, + 235, + 1, + 47, + 79, + 167, + 29, + 164, + 53, + 128, + 180, + 143, + 1, + 40, + 251, + 204, + 90, + 244, + 210, + 250, + 8, + 58, + 105, + 215, + 72, + 90, + 30, + 86, + 221, + 3, + 167, + 243, + 204, + 139, + 118, + 146, + 12, + 233, + 15, + 192, + 174, + 99, + 156, + 116, + 189, + 131, + 7, + 10, + 9, + 68, + 232, + 190, + 158, + 13, + 44, + 240, + 55, + 26, + 163, + 164, + 90, + 17, + 36, + 194, + 164, + 183, + 38, + 19, + 221, + 235, + 67, + 81, + 255, + 239, + 225, + 210, + 154, + 96, + 182, + 221, + 231, + 174, + 201, + 136, + 182, + 206, + 9, + 120, + 193, + 100, + 229, + 5, + 183, + 68, + 89, + 92, + 102, + 14, + 116, + 14, + 129, + 232, + 85, + 27, + 129, + 102, + 248, + 150, + 51, + 111, + 40, + 242, + 164, + 14, + 114, + 31, + 164, + 18, + 45, + 240, + 62, + 154, + 103, + 245, + 222, + 55, + 124, + 70, + 74, + 87, + 207, + 246, + 174, + 230, + 190, + 12, + 41, + 47, + 112, + 6, + 120, + 36, + 81, + 248, + 23, + 144, + 168, + 73, + 116, + 255, + 180, + 16, + 138, + 32, + 165, + 48, + 33, + 3, + 248, + 24, + 117, + 103, + 52, + 138, + 122, + 227, + 36, + 165, + 73, + 255, + 163, + 71, + 91, + 52, + 31, + 50, + 236, + 103, + 231, + 248, + 51, + 116, + 51, + 238, + 60, + 118, + 223, + 143, + 43, + 0, + 65, + 90, + 54, + 135, + 84, + 246, + 243, + 187, + 253, + 70, + 79, + 198, + 13, + 25, + 26, + 88, + 121, + 232, + 31, + 155, + 62, + 49, + 239, + 161, + 215, + 217, + 122, + 229, + 111, + 3, + 58, + 22, + 16, + 62, + 232, + 28, + 197, + 32, + 236, + 43, + 46, + 38, + 94, + 239, + 181, + 110, + 80, + 99, + 55, + 251, + 32, + 41, + 80, + 10, + 176, + 210, + 70, + 146, + 219, + 95, + 252, + 56, + 130, + 87, + 140, + 101, + 80, + 144, + 40, + 124, + 172, + 15, + 45, + 188, + 78, + 72, + 224, + 229, + 173, + 250, + 114, + 193, + 163, + 118, + 83, + 36, + 155, + 95, + 173, + 197, + 73, + 192, + 103, + 182, + 188, + 107, + 81, + 158, + 61, + 3, + 117, + 65, + 58, + 79, + 35, + 178, + 42, + 34, + 208, + 118, + 203, + 81, + 29, + 179, + 22, + 201, + 180, + 75, + 19, + 86, + 201, + 47, + 245, + 117, + 243, + 14, + 156, + 40, + 215, + 106, + 242, + 186, + 16, + 120, + 47, + 28, + 175, + 141, + 229, + 130, + 90, + 246, + 114, + 110, + 250, + 110, + 246, + 47, + 9, + 89, + 164, + 142, + 170, + 93, + 174, + 21, + 171, + 190, + 105, + 29, + 68, + 196, + 31, + 39, + 46, + 209, + 128, + 237, + 74, + 72, + 97, + 253, + 68, + 60, + 102, + 11, + 163, + 116, + 254, + 139, + 244, + 225, + 241, + 115, + 93, + 106, + 63, + 65, + 169, + 99, + 245, + 80, + 206, + 160, + 74, + 174, + 237, + 80, + 146, + 40, + 76, + 2, + 133, + 160, + 169, + 149, + 1, + 146, + 242, + 48, + 87, + 147, + 215, + 218, + 205, + 88, + 140, + 43, + 167, + 68, + 186, + 70, + 104, + 22, + 231, + 255, + 73, + 91, + 82, + 5, + 4, + 18, + 139, + 36, + 80, + 152, + 54, + 243, + 70, + 183, + 191, + 174, + 60, + 215, + 126, + 131, + 99, + 40, + 8, + 127, + 9, + 27, + 95, + 219, + 50, + 96, + 54, + 230, + 118, + 55, + 111, + 201, + 99, + 157, + 216, + 29, + 115, + 1, + 148, + 187, + 235, + 148, + 118, + 225, + 111, + 108, + 125, + 70, + 67, + 15, + 58, + 41, + 2, + 249, + 209, + 173, + 252, + 54, + 59, + 182, + 247, + 38, + 184, + 169, + 254, + 104, + 161, + 204, + 141, + 123, + 131, + 199, + 22, + 217, + 84, + 120, + 232, + 183, + 77, + 80, + 161, + 32, + 159, + 228, + 139, + 232, + 209, + 130, + 111, + 48, + 246, + 47, + 105, + 240, + 120, + 233, + 210, + 141, + 193, + 98, + 111, + 211, + 207, + 137, + 161, + 77, + 200, + 100, + 48, + 48, + 110, + 155, + 169, + 254, + 229, + 8, + 53, + 182, + 147, + 89, + 19, + 103, + 196, + 178, + 42, + 80, + 250, + 138, + 70, + 16, + 111, + 153, + 57, + 74, + 188, + 11, + 139, + 209, + 153, + 81, + 171, + 195, + 93, + 63, + 239, + 211, + 75, + 215, + 106, + 236, + 5, + 162, + 230, + 64, + 32, + 102, + 52, + 0, + 160, + 245, + 104, + 49, + 171, + 4, + 175, + 219, + 56, + 115, + 89, + 181, + 177, + 123, + 146, + 222, + 142, + 164, + 162, + 185, + 1, + 130, + 110, + 164, + 237, + 206, + 233, + 106, + 60, + 59, + 125, + 21, + 112, + 154, + 159, + 73, + 11, + 210, + 26, + 217, + 162, + 93, + 29, + 193, + 251, + 192, + 139, + 216, + 202, + 133, + 147, + 170, + 44, + 119, + 70, + 218, + 230, + 179, + 21, + 114, + 70, + 196, + 137, + 72, + 134, + 117, + 218, + 107, + 185, + 29, + 122, + 251, + 19, + 125, + 49, + 171, + 183, + 15, + 47, + 93, + 122, + 47, + 35, + 121, + 94, + 72, + 94, + 140, + 94, + 46, + 136, + 57, + 69, + 22, + 90, + 45, + 146, + 85, + 239, + 137, + 195, + 120, + 166, + 2, + 58, + 123, + 103, + 103, + 229, + 70, + 245, + 151, + 152, + 32, + 239, + 93, + 28, + 19, + 0, + 50, + 173, + 46, + 120, + 44, + 229, + 153, + 34, + 153, + 180, + 105, + 128, + 52, + 87, + 103, + 112, + 2, + 179, + 100, + 241, + 244, + 80, + 231, + 220, + 199, + 150, + 117, + 133, + 128, + 61, + 197, + 9, + 15, + 151, + 81, + 161, + 12, + 98, + 23, + 164, + 7, + 12, + 186, + 194, + 43, + 77, + 77, + 103, + 188, + 168, + 46, + 118, + 207, + 96, + 93, + 84, + 46, + 24, + 35, + 230, + 219, + 113, + 167, + 242, + 124, + 178, + 119, + 43, + 45, + 12, + 169, + 51, + 1, + 241, + 36, + 91, + 76, + 176, + 218, + 122, + 229, + 182, + 132, + 128, + 212, + 200, + 186, + 47, + 61, + 12, + 150, + 79, + 169, + 97, + 154, + 144, + 225, + 26, + 173, + 1, + 85, + 185, + 179, + 72, + 114, + 94, + 215, + 20, + 53, + 190, + 28, + 138, + 187, + 165, + 28, + 42, + 219, + 68, + 175, + 116, + 93, + 90, + 184, + 141, + 97, + 154, + 179, + 178, + 109, + 1, + 83, + 172, + 11, + 113, + 178, + 24, + 27, + 187, + 177, + 95, + 6, + 181, + 190, + 156, + 46, + 243, + 184, + 20, + 13, + 118, + 252, + 48, + 103, + 26, + 203, + 219, + 181, + 92, + 50, + 14, + 3, + 175, + 108, + 212, + 81, + 173, + 68, + 232, + 216, + 94, + 155, + 145, + 116, + 143, + 47, + 170, + 142, + 93, + 61, + 176, + 0, + 192, + 17, + 151, + 182, + 81, + 132, + 148, + 241, + 227, + 13, + 97, + 66, + 93, + 9, + 235, + 1, + 139, + 21, + 1, + 184, + 14, + 21, + 197, + 30, + 223, + 159, + 143, + 206, + 221, + 6, + 6, + 35, + 111, + 105, + 147, + 68, + 240, + 31, + 5, + 44, + 135, + 140, + 82, + 246, + 152, + 171, + 230, + 62, + 43, + 12, + 60, + 14, + 231, + 51, + 0, + 134, + 100, + 8, + 255, + 121, + 124, + 135, + 59, + 201, + 84, + 129, + 246, + 189, + 33, + 97, + 210, + 28, + 97, + 162, + 160, + 133, + 237, + 42, + 38, + 101, + 45, + 137, + 112, + 215, + 118, + 204, + 50, + 233, + 108, + 168, + 142, + 156, + 125, + 145, + 57, + 109, + 187, + 29, + 228, + 255, + 193, + 2, + 6, + 83, + 254, + 155, + 35, + 7, + 74, + 161, + 50, + 2, + 124, + 164, + 39, + 97, + 165, + 207, + 133, + 96, + 238, + 75, + 184, + 39, + 159, + 24, + 95, + 106, + 81, + 239, + 247, + 159, + 127, + 148, + 173, + 194, + 17, + 124, + 38, + 249, + 114, + 45, + 110, + 19, + 189, + 69, + 242, + 51, + 206, + 90, + 17, + 99, + 243, + 122, + 46, + 214, + 144, + 56, + 7, + 152, + 33, + 253, + 137, + 241, + 213, + 66, + 72, + 33, + 197, + 28, + 133, + 41, + 152, + 250, + 40, + 9, + 96, + 58, + 164, + 181, + 108, + 124, + 189, + 17, + 250, + 193, + 131, + 122, + 220, + 89, + 69, + 115, + 158, + 178, + 215, + 115, + 193, + 219, + 18, + 246, + 87, + 11, + 208, + 24, + 48, + 189, + 70, + 22, + 236, + 187, + 205, + 199, + 35, + 254, + 191, + 151, + 122, + 123, + 134, + 127, + 163, + 121, + 168, + 190, + 248, + 9, + 104, + 159, + 20, + 250, + 180, + 210, + 120, + 38, + 165, + 193, + 123, + 194, + 39, + 52, + 152, + 76, + 82, + 110, + 177, + 67, + 24, + 249, + 166, + 31, + 182, + 141, + 122, + 180, + 241, + 126, + 9, + 32, + 158, + 43, + 191, + 31, + 30, + 106, + 250, + 58, + 255, + 1, + 99, + 142, + 173, + 102, + 86, + 33, + 148, + 131, + 202, + 148, + 224, + 196, + 121, + 93, + 94, + 142, + 206, + 199, + 229, + 131, + 154, + 199, + 191, + 112, + 106, + 30, + 78, + 208, + 212, + 64, + 240, + 224, + 95, + 139, + 91, + 27, + 115, + 57, + 216, + 214, + 128, + 22, + 144, + 202, + 201, + 148, + 128, + 143, + 25, + 179, + 109, + 110, + 213, + 238, + 235, + 87, + 176, + 81, + 232, + 27, + 230, + 152, + 168, + 109, + 200, + 125, + 194, + 50, + 29, + 155, + 42, + 84, + 125, + 251, + 54, + 5, + 170, + 19, + 174, + 86, + 24, + 189, + 122, + 80, + 93, + 168, + 149, + 135, + 241, + 73, + 84, + 79, + 235, + 115, + 170, + 233, + 112, + 226, + 244, + 111, + 103, + 82, + 92, + 3, + 78, + 61, + 214, + 61, + 188, + 234, + 100, + 175, + 236, + 247, + 56, + 165, + 71, + 83, + 160, + 252, + 119, + 247, + 75, + 53, + 59, + 57, + 111, + 168, + 36, + 119, + 166, + 39, + 25, + 98, + 242, + 42, + 165, + 9, + 221, + 104, + 206, + 202, + 28, + 104, + 191, + 186, + 131, + 46, + 41, + 168, + 136, + 33, + 24, + 23, + 45, + 205, + 93, + 81, + 21, + 247, + 100, + 222, + 122, + 74, + 237, + 220, + 141, + 153, + 48, + 228, + 17, + 58, + 123, + 240, + 224, + 240, + 42, + 182, + 138, + 146, + 81, + 212, + 28, + 244, + 114, + 80, + 82, + 199, + 189, + 168, + 95, + 253, + 133, + 9, + 24, + 66, + 198, + 188, + 65, + 163, + 159, + 122, + 251, + 66, + 158, + 182, + 87, + 70, + 220, + 62, + 28, + 132, + 230, + 200, + 99, + 188, + 30, + 42, + 52, + 232, + 229, + 51, + 28, + 102, + 143, + 9, + 227, + 90, + 230, + 83, + 24, + 26, + 57, + 198, + 63, + 46, + 224, + 220, + 39, + 192, + 32, + 5, + 133, + 110, + 14, + 217, + 156, + 212, + 39, + 167, + 6, + 151, + 240, + 43, + 207, + 23, + 27, + 236, + 86, + 61, + 171, + 222, + 195, + 210, + 251, + 7, + 132, + 120, + 195, + 17, + 115, + 34, + 154, + 83, + 136, + 229, + 208, + 131, + 40, + 157, + 148, + 58, + 248, + 13, + 47, + 40, + 82, + 37, + 42, + 231, + 2, + 40, + 239, + 191, + 76, + 236, + 8, + 206, + 168, + 198, + 227, + 131, + 193, + 197, + 35, + 194, + 205, + 225, + 83, + 211, + 137, + 185, + 85, + 19, + 227, + 152, + 44, + 84, + 44, + 246, + 194, + 177, + 161, + 48, + 211, + 15, + 135, + 201, + 192, + 12, + 216, + 140, + 188, + 54, + 110, + 114, + 64, + 97, + 125, + 116, + 235, + 198, + 95, + 161, + 242, + 174, + 209, + 16, + 33, + 22, + 184, + 22, + 250, + 81, + 180, + 110, + 0, + 87, + 14, + 156, + 39, + 38, + 174, + 95, + 60, + 207, + 178, + 11, + 231, + 184, + 146, + 161, + 239, + 165, + 207, + 228, + 138, + 173, + 89, + 144, + 99, + 57, + 216, + 32, + 249, + 117, + 80, + 16, + 130, + 45, + 225, + 245, + 32, + 174, + 194, + 40, + 45, + 245, + 215, + 32, + 3, + 153, + 190, + 85, + 82, + 204, + 90, + 190, + 7, + 171, + 160, + 198, + 81, + 251, + 50, + 247, + 6, + 57, + 68, + 18, + 244, + 117, + 171, + 81, + 71, + 103, + 75, + 189, + 198, + 7, + 197, + 144, + 116, + 200, + 231, + 56, + 36, + 18, + 147, + 15, + 175, + 135, + 146, + 224, + 131, + 196, + 193, + 94, + 36, + 100, + 40, + 43, + 26, + 53, + 131, + 167, + 229, + 158, + 118, + 193, + 170, + 134, + 187, + 134, + 209, + 196, + 55, + 186, + 230, + 255, + 33, + 223, + 71, + 239, + 205, + 204, + 224, + 250, + 70, + 176, + 171, + 230, + 251, + 81, + 221, + 83, + 204, + 193, + 5, + 30, + 65, + 18, + 164, + 29, + 23, + 78, + 231, + 252, + 214, + 204, + 237, + 123, + 187, + 111, + 212, + 17, + 182, + 20, + 155, + 6, + 29, + 203, + 163, + 225, + 240, + 71, + 16, + 71, + 130, + 103, + 188, + 184, + 70, + 5, + 238, + 207, + 36, + 239, + 134, + 91, + 82, + 173, + 42, + 198, + 153, + 153, + 85, + 151, + 34, + 44, + 220, + 114, + 94, + 99, + 243, + 176, + 151, + 84, + 7, + 187, + 52, + 139, + 87, + 109, + 27, + 21, + 54, + 75, + 164, + 139, + 202, + 251, + 89, + 184, + 224, + 6, + 154, + 154, + 106, + 236, + 143, + 153, + 196, + 134, + 28, + 6, + 71, + 70, + 237, + 95, + 217, + 188, + 237, + 120, + 21, + 165, + 41, + 14, + 108, + 0, + 15, + 118, + 24, + 165, + 101, + 127, + 53, + 19, + 126, + 242, + 237, + 253, + 146, + 224, + 115, + 220, + 97, + 67, + 176, + 29, + 89, + 61, + 81, + 167, + 228, + 72, + 46, + 18, + 49, + 233, + 229, + 221, + 5, + 201, + 184, + 185, + 179, + 88, + 85, + 233, + 113, + 188, + 18, + 86, + 206, + 200, + 110, + 65, + 166, + 102, + 145, + 216, + 110, + 111, + 36, + 153, + 143, + 187, + 104, + 145, + 162, + 114, + 193, + 88, + 89, + 36, + 43, + 179, + 134, + 192, + 209, + 140, + 21, + 255, + 115, + 87, + 166, + 67, + 84, + 2, + 67, + 35, + 41, + 104, + 167, + 47, + 234, + 169, + 198, + 202, + 250, + 19, + 221, + 98, + 78, + 40, + 107, + 183, + 64, + 242, + 8, + 156, + 90, + 152, + 191, + 136, + 42, + 113, + 86, + 138, + 49, + 188, + 145, + 35, + 157, + 109, + 118, + 96, + 241, + 203, + 212, + 181, + 221, + 26, + 223, + 143, + 73, + 99, + 66, + 174, + 16, + 81, + 178, + 124, + 89, + 148, + 166, + 245, + 218, + 18, + 92, + 26, + 106, + 69, + 154, + 135, + 114, + 203, + 156, + 98, + 133, + 208, + 102, + 22, + 220, + 196, + 9, + 77, + 234, + 177, + 101, + 46, + 167, + 216, + 158, + 82, + 151, + 196, + 128, + 71, + 145, + 214, + 0, + 62, + 240, + 216, + 32, + 68, + 103, + 77, + 241, + 52, + 116, + 180, + 40, + 147, + 234, + 228, + 115, + 43, + 57, + 220, + 17, + 42, + 170, + 243, + 221, + 178, + 43, + 14, + 227, + 154, + 193, + 90, + 182, + 123, + 59, + 111, + 102, + 215, + 55, + 117, + 8, + 60, + 42, + 128, + 122, + 213, + 37, + 12, + 119, + 244, + 45, + 68, + 78, + 116, + 244, + 39, + 246, + 147, + 148, + 160, + 139, + 18, + 146, + 160, + 20, + 124, + 134, + 100, + 147, + 140, + 223, + 54, + 180, + 99, + 69, + 135, + 234, + 10, + 43, + 119, + 87, + 32, + 97, + 210, + 186, + 33, + 20, + 209, + 151, + 139, + 199, + 14, + 224, + 238, + 13, + 111, + 98, + 239, + 145, + 5, + 250, + 171, + 242, + 87, + 38, + 41, + 58, + 43, + 164, + 34, + 232, + 87, + 82, + 167, + 171, + 186, + 232, + 56, + 251, + 23, + 29, + 167, + 200, + 195, + 192, + 26, + 247, + 230, + 225, + 219, + 106, + 1, + 229, + 57, + 91, + 203, + 109, + 98, + 245, + 84, + 179, + 209, + 10, + 35, + 96, + 150, + 102, + 97, + 161, + 246, + 55, + 156, + 92, + 113, + 247, + 175, + 141, + 177, + 241, + 29, + 222, + 38, + 254, + 213, + 32, + 243, + 93, + 33, + 207, + 46, + 247, + 235, + 201, + 205, + 189, + 82, + 160, + 105, + 75, + 212, + 80, + 188, + 85, + 81, + 88, + 250, + 91, + 58, + 172, + 15, + 139, + 117, + 116, + 68, + 56, + 23, + 214, + 35, + 66, + 153, + 12, + 99, + 57, + 17, + 170, + 200, + 1, + 146, + 230, + 58, + 76, + 13, + 137, + 72, + 22, + 131, + 25, + 48, + 136, + 22, + 10, + 92, + 244, + 129, + 72, + 162, + 254, + 172, + 233, + 94, + 204, + 202, + 0, + 67, + 108, + 192, + 26, + 143, + 103, + 243, + 35, + 193, + 123, + 43, + 71, + 160, + 224, + 207, + 53, + 124, + 157, + 98, + 69, + 218, + 64, + 53, + 45, + 48, + 50, + 230, + 139, + 190, + 143, + 208, + 27, + 36, + 133, + 230, + 93, + 60, + 133, + 89, + 191, + 135, + 251, + 172, + 127, + 36, + 138, + 151, + 151, + 28, + 192, + 143, + 178, + 98, + 35, + 1, + 170, + 240, + 173, + 18, + 206, + 58, + 49, + 164, + 120, + 0, + 241, + 218, + 26, + 181, + 244, + 175, + 128, + 14, + 10, + 50, + 199, + 109, + 210, + 201, + 254, + 130, + 247, + 8, + 128, + 51, + 24, + 117, + 132, + 17, + 121, + 157, + 206, + 250, + 49, + 212, + 24, + 111, + 186, + 190, + 71, + 154, + 118, + 63, + 119, + 106, + 214, + 237, + 130, + 165, + 6, + 184, + 85, + 235, + 132, + 141, + 67, + 8, + 96, + 213, + 53, + 77, + 176, + 20, + 45, + 92, + 115, + 238, + 228, + 92, + 247, + 67, + 247, + 235, + 8, + 58, + 186, + 198, + 243, + 211, + 167, + 53, + 117, + 87, + 242, + 133, + 247, + 9, + 100, + 144, + 190, + 162, + 158, + 176, + 194, + 105, + 136, + 41, + 132, + 200, + 248, + 49, + 65, + 174, + 136, + 20, + 154, + 7, + 242, + 67, + 222, + 150, + 233, + 92, + 126, + 158, + 37, + 205, + 227, + 66, + 3, + 23, + 213, + 116, + 134, + 166, + 8, + 165, + 82, + 115, + 42, + 61, + 18, + 87, + 62, + 89, + 252, + 170, + 189, + 124, + 252, + 243, + 94, + 129, + 130, + 176, + 95, + 1, + 115, + 255, + 156, + 231, + 9, + 134, + 194, + 199, + 161, + 38, + 16, + 154, + 50, + 171, + 174, + 60, + 141, + 10, + 189, + 159, + 213, + 79, + 184, + 233, + 191, + 91, + 173, + 195, + 37, + 107, + 153, + 164, + 170, + 213, + 30, + 181, + 254, + 35, + 227, + 120, + 186, + 225, + 119, + 174, + 112, + 118, + 104, + 215, + 163, + 60, + 73, + 37, + 134, + 19, + 208, + 235, + 64, + 137, + 159, + 92, + 140, + 33, + 6, + 27, + 176, + 59, + 237, + 145, + 249, + 213, + 225, + 227, + 221, + 106, + 42, + 154, + 226, + 222, + 192, + 139, + 194, + 67, + 67, + 140, + 106, + 184, + 211, + 174, + 5, + 230, + 21, + 80, + 175, + 11, + 129, + 132, + 46, + 203, + 191, + 216, + 252, + 207, + 103, + 118, + 21, + 2, + 110, + 103, + 96, + 188, + 87, + 143, + 48, + 77, + 102, + 123, + 109, + 141, + 51, + 185, + 175, + 216, + 76, + 68, + 114, + 140, + 104, + 153, + 130, + 10, + 190, + 84, + 121, + 255, + 169, + 158, + 181, + 152, + 236, + 130, + 92, + 234, + 109, + 147, + 236, + 53, + 100, + 116, + 176, + 176, + 2, + 239, + 236, + 66, + 235, + 134, + 65, + 205, + 64, + 234, + 101, + 170, + 151, + 176, + 120, + 149, + 248, + 1, + 188, + 146, + 159, + 232, + 73, + 234, + 130, + 199, + 141, + 76, + 44, + 156, + 233, + 64, + 126, + 108, + 213, + 162, + 217, + 100, + 246, + 155, + 185, + 52, + 86, + 213, + 99, + 128, + 12, + 150, + 87, + 198, + 106, + 104, + 22, + 172, + 15, + 108, + 101, + 182, + 11, + 7, + 199, + 121, + 13, + 138, + 68, + 95, + 231, + 10, + 240, + 238, + 17, + 253, + 165, + 12, + 115, + 214, + 231, + 182, + 248, + 226, + 166, + 183, + 98, + 86, + 212, + 125, + 63, + 244, + 239, + 134, + 12, + 77, + 122, + 50, + 161, + 39, + 162, + 184, + 246, + 150, + 93, + 236, + 136, + 50, + 106, + 24, + 94, + 94, + 194, + 163, + 202, + 45, + 175, + 16, + 63, + 198, + 171, + 2, + 163, + 155, + 142, + 180, + 152, + 42, + 216, + 223, + 254, + 107, + 164, + 240, + 107, + 132, + 209, + 228, + 245, + 54, + 157, + 33, + 142, + 90, + 129, + 168, + 151, + 174, + 254, + 46, + 70, + 172, + 198, + 128, + 178, + 140, + 91, + 0, + 153, + 1, + 167, + 103, + 34, + 211, + 113, + 100, + 178, + 5, + 59, + 31, + 159, + 219, + 227, + 148, + 163, + 233, + 125, + 195, + 47, + 224, + 123, + 72, + 199, + 180, + 2, + 162, + 138, + 223, + 120, + 95, + 169, + 29, + 245, + 73, + 241, + 252, + 7, + 25, + 85, + 237, + 0, + 199, + 154, + 109, + 116, + 114, + 151, + 126, + 28, + 97, + 187, + 229, + 52, + 156, + 102, + 79, + 211, + 204, + 155, + 222, + 119, + 54, + 57, + 52, + 220, + 16, + 41, + 142, + 54, + 95, + 54, + 18, + 110, + 237, + 146, + 177, + 184, + 92, + 111, + 125, + 239, + 198, + 33, + 238, + 240, + 42, + 116, + 207, + 147, + 98, + 79, + 92, + 161, + 204, + 88, + 77, + 86, + 68, + 122, + 34, + 33, + 144, + 188, + 219, + 57, + 87, + 137, + 6, + 203, + 31, + 136, + 248, + 173, + 8, + 245, + 143, + 29, + 103, + 221, + 46, + 106, + 212, + 9, + 219, + 45, + 134, + 76, + 14, + 54, + 59, + 61, + 171, + 160, + 119, + 22, + 120, + 253, + 12, + 90, + 65, + 147, + 64, + 5, + 105, + 151, + 62, + 65, + 137, + 210, + 26, + 39, + 211, + 30, + 115, + 239, + 55, + 6, + 177, + 8, + 3, + 74, + 0, + 107, + 63, + 27, + 89, + 83, + 208, + 200, + 215, + 31, + 66, + 71, + 149, + 80, + 42, + 195, + 34, + 21, + 62, + 226, + 149, + 211, + 169, + 198, + 157, + 168, + 130, + 35, + 201, + 120, + 41, + 77, + 22, + 35, + 0, + 69, + 101, + 221, + 172, + 132, + 180, + 130, + 185, + 138, + 199, + 226, + 115, + 66, + 7, + 195, + 60, + 85, + 226, + 97, + 107, + 58, + 2, + 152, + 78, + 209, + 131, + 38, + 50, + 78, + 175, + 214, + 205, + 233, + 133, + 237, + 240, + 11, + 50, + 171, + 168, + 61, + 191, + 75, + 218, + 192, + 4, + 198, + 243, + 236, + 20, + 28, + 1, + 85, + 37, + 30, + 70, + 123, + 0, + 58, + 99, + 49, + 216, + 44, + 112, + 81, + 34, + 169, + 209, + 233, + 96, + 218, + 128, + 250, + 249, + 139, + 216, + 191, + 59, + 98, + 226, + 191, + 215, + 231, + 194, + 188, + 126, + 59, + 142, + 196, + 106, + 182, + 87, + 223, + 25, + 179, + 5, + 139, + 72, + 88, + 32, + 81, + 111, + 98, + 199, + 238, + 61, + 31, + 17, + 211, + 25, + 39, + 181, + 44, + 66, + 252, + 9, + 152, + 131, + 194, + 80, + 25, + 127, + 81, + 44, + 121, + 169, + 61, + 41, + 139, + 173, + 104, + 224, + 42, + 177, + 193, + 22, + 131, + 2, + 94, + 39, + 225, + 45, + 0, + 138, + 239, + 106, + 69, + 119, + 179, + 31, + 105, + 194, + 60, + 221, + 61, + 27, + 96, + 115, + 33, + 109, + 206, + 22, + 20, + 244, + 233, + 133, + 128, + 227, + 102, + 32, + 208, + 212, + 222, + 58, + 104, + 4, + 7, + 68, + 232, + 14, + 90, + 103, + 175, + 92, + 157, + 24, + 41, + 50, + 94, + 16, + 6, + 237, + 181, + 20, + 126, + 18, + 169, + 92, + 224, + 174, + 139, + 173, + 155, + 152, + 47, + 225, + 34, + 253, + 253, + 47, + 173, + 68, + 28, + 0, + 57, + 78, + 160, + 147, + 140, + 25, + 44, + 132, + 163, + 152, + 60, + 134, + 103, + 10, + 252, + 98, + 163, + 185, + 88, + 75, + 238, + 47, + 134, + 67, + 174, + 249, + 49, + 167, + 5, + 148, + 56, + 171, + 155, + 249, + 222, + 33, + 55, + 37, + 196, + 179, + 144, + 170, + 194, + 171, + 174, + 18, + 133, + 86, + 126, + 153, + 110, + 140, + 223, + 44, + 66, + 189, + 136, + 29, + 216, + 32, + 82, + 114, + 5, + 223, + 19, + 43, + 4, + 154, + 237, + 19, + 123, + 64, + 128, + 132, + 229, + 5, + 30, + 160, + 121, + 155, + 72, + 221, + 89, + 167, + 210, + 179, + 25, + 53, + 234, + 81, + 191, + 125, + 196, + 66, + 215, + 152, + 148, + 159, + 143, + 41, + 165, + 4, + 64, + 184, + 74, + 214, + 12, + 177, + 85, + 230, + 66, + 253, + 18, + 138, + 225, + 223, + 40, + 248, + 86, + 147, + 161, + 221, + 188, + 194, + 1, + 40, + 140, + 17, + 137, + 135, + 138, + 51, + 247, + 69, + 198, + 224, + 80, + 16, + 2, + 2, + 212, + 73, + 241, + 127, + 239, + 143, + 36, + 234, + 180, + 184, + 159, + 2, + 123, + 0, + 16, + 59, + 186, + 155, + 209, + 15, + 215, + 213, + 248, + 223, + 86, + 0, + 230, + 67, + 222, + 131, + 73, + 255, + 197, + 199, + 129, + 186, + 218, + 4, + 166, + 225, + 214, + 241, + 48, + 46, + 204, + 248, + 94, + 193, + 247, + 144, + 207, + 169, + 185, + 42, + 62, + 100, + 152, + 70, + 143, + 61, + 228, + 46, + 97, + 39, + 59, + 172, + 18, + 220, + 97, + 217, + 116, + 246, + 6, + 214, + 183, + 42, + 141, + 2, + 84, + 159, + 177, + 72, + 29, + 232, + 95, + 156, + 151, + 45, + 191, + 32, + 74, + 145, + 211, + 2, + 245, + 147, + 6, + 228, + 10, + 132, + 36, + 211, + 125, + 208, + 143, + 18, + 31, + 8, + 64, + 193, + 26, + 245, + 53, + 137, + 99, + 189, + 190, + 241, + 244, + 193, + 197, + 3, + 144, + 28, + 97, + 14, + 163, + 72, + 121, + 45, + 159, + 87, + 26, + 250, + 201, + 44, + 69, + 72, + 45, + 16, + 211, + 185, + 53, + 18, + 185, + 107, + 2, + 14, + 45, + 61, + 240, + 183, + 109, + 103, + 223, + 177, + 183, + 251, + 99, + 136, + 17, + 179, + 242, + 74, + 168, + 9, + 34, + 29, + 173, + 115, + 194, + 29, + 174, + 83, + 228, + 60, + 128, + 206, + 153, + 74, + 254, + 87, + 103, + 198, + 226, + 108, + 209, + 235, + 55, + 139, + 196, + 69, + 133, + 49, + 138, + 163, + 36, + 90, + 184, + 157, + 218, + 243, + 238, + 161, + 63, + 100, + 68, + 31, + 188, + 80, + 221, + 235, + 77, + 31, + 134, + 245, + 13, + 4, + 204, + 4, + 38, + 188, + 132, + 93, + 164, + 74, + 156, + 117, + 173, + 206, + 114, + 30, + 55, + 127, + 163, + 105, + 35, + 40, + 193, + 198, + 105, + 48, + 118, + 32, + 156, + 70, + 72, + 103, + 132, + 1, + 94, + 168, + 222, + 36, + 253, + 70, + 6, + 155, + 237, + 121, + 147, + 176, + 22, + 154, + 193, + 249, + 198, + 57, + 144, + 29, + 108, + 234, + 199, + 247, + 137, + 183, + 241, + 123, + 95, + 32, + 152, + 18, + 126, + 253, + 115, + 110, + 55, + 98, + 192, + 105, + 79, + 82, + 219, + 154, + 75, + 109, + 234, + 146, + 147, + 245, + 43, + 47, + 149, + 177, + 187, + 98, + 59, + 125, + 132, + 9, + 237, + 89, + 68, + 3, + 86, + 192, + 5, + 168, + 228, + 58, + 0, + 183, + 13, + 215, + 92, + 107, + 226, + 27, + 118, + 97, + 105, + 197, + 19, + 136, + 74, + 108, + 100, + 123, + 78, + 123, + 169, + 95, + 195, + 113, + 233, + 97, + 240, + 9, + 26, + 239, + 221, + 17, + 35, + 105, + 131, + 183, + 254, + 233, + 212, + 205, + 50, + 208, + 151, + 42, + 143, + 227, + 72, + 161, + 36, + 212, + 223, + 67, + 7, + 208, + 24, + 130, + 142, + 69, + 168, + 144, + 81, + 224, + 198, + 180, + 147, + 93, + 1, + 175, + 108, + 19, + 146, + 246, + 69, + 251, + 56, + 154, + 159, + 183, + 49, + 49, + 58, + 133, + 31, + 46, + 193, + 35, + 163, + 47, + 194, + 110, + 214, + 16, + 216, + 51, + 35, + 134, + 192, + 249, + 59, + 236, + 0, + 151, + 171, + 93, + 87, + 158, + 44, + 15, + 152, + 172, + 141, + 58, + 184, + 99, + 148, + 225, + 170, + 68, + 28, + 14, + 117, + 97, + 102, + 15, + 223, + 122, + 182, + 11, + 63, + 106, + 250, + 76, + 117, + 205, + 77, + 133, + 248, + 198, + 2, + 124, + 244, + 148, + 67, + 44, + 39, + 15, + 183, + 74, + 239, + 8, + 72, + 145, + 14, + 5, + 9, + 223, + 62, + 222, + 61, + 95, + 29, + 133, + 36, + 92, + 255, + 195, + 106, + 132, + 21, + 174, + 139, + 50, + 204, + 148, + 216, + 66, + 193, + 221, + 97, + 116, + 111, + 46, + 75, + 8, + 55, + 38, + 214, + 144, + 241, + 44, + 140, + 232, + 15, + 196, + 133, + 225, + 180, + 193, + 166, + 145, + 244, + 115, + 69, + 138, + 10, + 151, + 27, + 155, + 165, + 203, + 179, + 40, + 244, + 19, + 25, + 59, + 94, + 21, + 15, + 118, + 169, + 89, + 228, + 53, + 122, + 225, + 154, + 33, + 111, + 74, + 145, + 135, + 18, + 58, + 153, + 150, + 118, + 65, + 142, + 44, + 3, + 169, + 15, + 167, + 144, + 13, + 38, + 232, + 238, + 55, + 126, + 55, + 6, + 128, + 104, + 87, + 122, + 216, + 181, + 181, + 109, + 218, + 47, + 240, + 111, + 139, + 82, + 142, + 74, + 219, + 8, + 105, + 3, + 112, + 224, + 46, + 143, + 159, + 159, + 204, + 164, + 4, + 65, + 184, + 186, + 174, + 170, + 190, + 123, + 207, + 205, + 102, + 130, + 72, + 139, + 60, + 97, + 20, + 165, + 226, + 210, + 146, + 211, + 155, + 196, + 122, + 124, + 57, + 62, + 245, + 73, + 52, + 26, + 30, + 198, + 32, + 122, + 33, + 89, + 72, + 85, + 235, + 179, + 37, + 188, + 244, + 24, + 233, + 96, + 203, + 64, + 253, + 116, + 113, + 200, + 1, + 28, + 174, + 114, + 218, + 196, + 176, + 180, + 212, + 0, + 108, + 190, + 118, + 245, + 192, + 214, + 172, + 22, + 225, + 55, + 172, + 167, + 94, + 162, + 192, + 63, + 55, + 55, + 200, + 96, + 226, + 41, + 156, + 38, + 231, + 161, + 32, + 124, + 99, + 163, + 195, + 145, + 115, + 66, + 110, + 130, + 252, + 73, + 16, + 45, + 131, + 114, + 107, + 143, + 24, + 164, + 94, + 62, + 248, + 157, + 11, + 87, + 250, + 58, + 139, + 233, + 172, + 45, + 57, + 244, + 198, + 226, + 54, + 254, + 36, + 113, + 195, + 30, + 191, + 128, + 236, + 104, + 194, + 101, + 165, + 27, + 245, + 94, + 151, + 219, + 198, + 214, + 177, + 114, + 251, + 37, + 59, + 175, + 180, + 116, + 44, + 105, + 87, + 137, + 4, + 214, + 42, + 101, + 241, + 234, + 48, + 100, + 84, + 237, + 2, + 220, + 81, + 126, + 245, + 50, + 152, + 59, + 252, + 81, + 185, + 249, + 71, + 100, + 140, + 150, + 189, + 130, + 132, + 101, + 146, + 71, + 225, + 192, + 114, + 233, + 211, + 39, + 172, + 53, + 221, + 20, + 144, + 249, + 72, + 231, + 252, + 37, + 214, + 197, + 206, + 253, + 65, + 170, + 16, + 0, + 155, + 71, + 66, + 230, + 31, + 94, + 25, + 87, + 32, + 126, + 110, + 192, + 51, + 4, + 1, + 2, + 155, + 63, + 41, + 48, + 18, + 6, + 142, + 79, + 206, + 212, + 223, + 99, + 166, + 94, + 255, + 124, + 38, + 28, + 121, + 58, + 112, + 146, + 86, + 133, + 17, + 185, + 111, + 72, + 97, + 196, + 153, + 12, + 168, + 190, + 207, + 102, + 182, + 223, + 199, + 118, + 9, + 35, + 144, + 172, + 103, + 60, + 15, + 140, + 233, + 24, + 39, + 81, + 197, + 38, + 0, + 173, + 254, + 52, + 114, + 152, + 184, + 82, + 226, + 117, + 99, + 91, + 229, + 120, + 41, + 58, + 5, + 177, + 7, + 114, + 141, + 150, + 78, + 91, + 95, + 53, + 105, + 32, + 227, + 65, + 153, + 200, + 196, + 184, + 85, + 50, + 111, + 102, + 37, + 132, + 97, + 133, + 246, + 63, + 146, + 22, + 123, + 6, + 80, + 38, + 26, + 66, + 130, + 117, + 166, + 125, + 46, + 42, + 219, + 208, + 17, + 245, + 97, + 35, + 8, + 5, + 34, + 219, + 1, + 158, + 113, + 218, + 12, + 237, + 71, + 35, + 220, + 189, + 130, + 74, + 166, + 142, + 71, + 212, + 133, + 183, + 28, + 129, + 104, + 158, + 154, + 158, + 45, + 138, + 125, + 9, + 49, + 104, + 31, + 221, + 52, + 54, + 160, + 138, + 139, + 19, + 13, + 93, + 147, + 89, + 73, + 117, + 223, + 154, + 224, + 126, + 40, + 137, + 226, + 24, + 244, + 79, + 45, + 159, + 183, + 237, + 42, + 63, + 131, + 172, + 19, + 58, + 114, + 199, + 214, + 112, + 167, + 17, + 151, + 26, + 53, + 12, + 204, + 93, + 94, + 144, + 179, + 75, + 109, + 141, + 165, + 171, + 24, + 0, + 238, + 80, + 128, + 71, + 30, + 87, + 97, + 137, + 169, + 22, + 94, + 132, + 149, + 189, + 154, + 162, + 147, + 102, + 110, + 179, + 153, + 82, + 201, + 181, + 137, + 240, + 31, + 234, + 141, + 172, + 59, + 53, + 130, + 146, + 251, + 123, + 108, + 214, + 134, + 245, + 117, + 109, + 26, + 36, + 221, + 198, + 233, + 71, + 221, + 173, + 107, + 238, + 242, + 111, + 198, + 136, + 152, + 60, + 134, + 197, + 23, + 17, + 252, + 63, + 189, + 211, + 30, + 110, + 220, + 82, + 186, + 217, + 181, + 63, + 10, + 191, + 14, + 184, + 1, + 11, + 143, + 73, + 65, + 136, + 177, + 128, + 81, + 60, + 104, + 131, + 223, + 68, + 125, + 105, + 12, + 104, + 250, + 28, + 186, + 156, + 133, + 232, + 152, + 108, + 190, + 3, + 48, + 134, + 110, + 235, + 139, + 20, + 154, + 56, + 95, + 123, + 98, + 164, + 209, + 91, + 234, + 189, + 143, + 248, + 76, + 66, + 212, + 186, + 24, + 24, + 199, + 109, + 64, + 153, + 19, + 49, + 6, + 22, + 54, + 245, + 146, + 118, + 9, + 96, + 139, + 129, + 4, + 6, + 152, + 15, + 156, + 108, + 52, + 2, + 193, + 212, + 122, + 104, + 84, + 202, + 11, + 187, + 188, + 239, + 202, + 40, + 11, + 201, + 220, + 73, + 33, + 40, + 136, + 42, + 78, + 254, + 189, + 16, + 139, + 80, + 9, + 248, + 216, + 201, + 67, + 127, + 46, + 61, + 244, + 226, + 28, + 7, + 14, + 251, + 192, + 183, + 167, + 236, + 169, + 217, + 140, + 219, + 64, + 243, + 217, + 8, + 166, + 139, + 69, + 107, + 8, + 187, + 215, + 227, + 14, + 105, + 140, + 76, + 63, + 186, + 221, + 148, + 189, + 67, + 134, + 117, + 209, + 43, + 29, + 79, + 253, + 50, + 232, + 122, + 99, + 209, + 202, + 240, + 48, + 49, + 0, + 4, + 243, + 207, + 188, + 46, + 56, + 178, + 88, + 176, + 26, + 241, + 112, + 0, + 10, + 66, + 60, + 225, + 29, + 148, + 239, + 47, + 56, + 183, + 212, + 34, + 93, + 109, + 83, + 0, + 238, + 230, + 167, + 58, + 238, + 167, + 142, + 206, + 2, + 92, + 199, + 239, + 216, + 163, + 9, + 153, + 23, + 254, + 44, + 106, + 45, + 127, + 10, + 98, + 165, + 204, + 176, + 219, + 77, + 183, + 80, + 199, + 187, + 91, + 245, + 123, + 43, + 182, + 111, + 239, + 165, + 208, + 42, + 41, + 51, + 240, + 140, + 235, + 219, + 0, + 230, + 166, + 57, + 82, + 100, + 13, + 158, + 77, + 165, + 147, + 47, + 56, + 59, + 166, + 93, + 72, + 159, + 226, + 70, + 127, + 107, + 201, + 56, + 202, + 151, + 152, + 83, + 75, + 166, + 248, + 165, + 203, + 104, + 244, + 129, + 77, + 85, + 73, + 121, + 119, + 3, + 237, + 46, + 5, + 55, + 245, + 34, + 39, + 85, + 32, + 18, + 5, + 161, + 130, + 42, + 166, + 72, + 245, + 237, + 111, + 29, + 193, + 234, + 111, + 98, + 14, + 208, + 22, + 222, + 10, + 90, + 207, + 71, + 185, + 31, + 169, + 47, + 194, + 86, + 222, + 212, + 91, + 253, + 131, + 1, + 162, + 5, + 13, + 11, + 96, + 141, + 233, + 46, + 4, + 1, + 85, + 150, + 183, + 97, + 197, + 156, + 126, + 12, + 127, + 43, + 109, + 36, + 151, + 9, + 107, + 25, + 46, + 4, + 77, + 13, + 217, + 36, + 151, + 158, + 225, + 1, + 139, + 52, + 239, + 216, + 156, + 242, + 30, + 95, + 236, + 47, + 213, + 168, + 171, + 3, + 238, + 224, + 68, + 75, + 27, + 114, + 228, + 216, + 79, + 144, + 173, + 208, + 211, + 220, + 213, + 182, + 71, + 136, + 84, + 225, + 145, + 49, + 86, + 229, + 183, + 49, + 128, + 218, + 26, + 230, + 2, + 195, + 240, + 188, + 100, + 54, + 65, + 139, + 136, + 104, + 110, + 187, + 36, + 50, + 254, + 105, + 4, + 219, + 19, + 39, + 30, + 119, + 255, + 223, + 34, + 127, + 204, + 120, + 178, + 128, + 160, + 167, + 136, + 221, + 177, + 251, + 158, + 6, + 180, + 150, + 253, + 82, + 1, + 203, + 24, + 212, + 248, + 72, + 206, + 150, + 16, + 83, + 225, + 145, + 89, + 125, + 27, + 201, + 49, + 86, + 87, + 108, + 58, + 16, + 61, + 111, + 217, + 100, + 130, + 9, + 122, + 58, + 118, + 16, + 230, + 54, + 54, + 31, + 131, + 142, + 3, + 182, + 196, + 233, + 160, + 211, + 21, + 138, + 213, + 63, + 180, + 105, + 202, + 172, + 182, + 143, + 47, + 71, + 78, + 93, + 72, + 66, + 101, + 240, + 110, + 223, + 175, + 91, + 47, + 41, + 218, + 113, + 148, + 7, + 7, + 41, + 85, + 6, + 75, + 118, + 23, + 149, + 81, + 37, + 18, + 62, + 113, + 33, + 240, + 241, + 106, + 153, + 19, + 104, + 123, + 18, + 107, + 53, + 91, + 187, + 161, + 85, + 110, + 103, + 242, + 253, + 196, + 173, + 27, + 212, + 3, + 251, + 130, + 156, + 76, + 27, + 73, + 132, + 20, + 97, + 76, + 87, + 112, + 21, + 25, + 95, + 71, + 206, + 10, + 237, + 233, + 72, + 172, + 203, + 193, + 101, + 182, + 68, + 128, + 130, + 139, + 189, + 53, + 183, + 124, + 101, + 177, + 220, + 61, + 249, + 100, + 141, + 176, + 80, + 223, + 70, + 17, + 21, + 64, + 248, + 159, + 193, + 144, + 160, + 4, + 122, + 99, + 111, + 210, + 21, + 11, + 244, + 255, + 172, + 96, + 228, + 191, + 54, + 249, + 122, + 138, + 48, + 211, + 92, + 115, + 71, + 17, + 38, + 4, + 7, + 201, + 147, + 172, + 67, + 36, + 218, + 181, + 117, + 194, + 127, + 17, + 248, + 12, + 210, + 6, + 195, + 122, + 2, + 86, + 240, + 105, + 151, + 242, + 205, + 173, + 109, + 137, + 185, + 160, + 138, + 192, + 96, + 118, + 92, + 220, + 79, + 105, + 4, + 133, + 255, + 62, + 136, + 3, + 189, + 96, + 21, + 17, + 10, + 22, + 34, + 42, + 142, + 69, + 200, + 156, + 85, + 8, + 81, + 83, + 101, + 191, + 237, + 163, + 23, + 33, + 170, + 80, + 188, + 132, + 204, + 63, + 167, + 109, + 134, + 242, + 251, + 134, + 208, + 200, + 140, + 33, + 180, + 191, + 236, + 178, + 172, + 238, + 35, + 155, + 88, + 101, + 122, + 44, + 154, + 140, + 50, + 230, + 225, + 178, + 242, + 39, + 234, + 80, + 1, + 101, + 17, + 148, + 78, + 217, + 39, + 44, + 188, + 133, + 101, + 138, + 32, + 61, + 131, + 113, + 130, + 153, + 69, + 79, + 124, + 26, + 13, + 196, + 56, + 20, + 53, + 111, + 245, + 221, + 253, + 213, + 200, + 236, + 26, + 251, + 170, + 70, + 151, + 58, + 190, + 163, + 64, + 95, + 138, + 13, + 63, + 152, + 223, + 252, + 132, + 215, + 5, + 250, + 219, + 16, + 110, + 63, + 153, + 78, + 228, + 211, + 13, + 3, + 137, + 4, + 49, + 132, + 24, + 44, + 11, + 106, + 119, + 131, + 95, + 188, + 136, + 19, + 71, + 161, + 22, + 247, + 62, + 251, + 73, + 232, + 170, + 5, + 3, + 230, + 103, + 246, + 164, + 28, + 102, + 252, + 216, + 179, + 164, + 33, + 116, + 131, + 116, + 15, + 181, + 185, + 35, + 12, + 82, + 47, + 147, + 249, + 9, + 35, + 235, + 47, + 91, + 168, + 1, + 109, + 29, + 217, + 83, + 170, + 97, + 148, + 237, + 219, + 223, + 165, + 250, + 44, + 213, + 45, + 12, + 195, + 213, + 136, + 163, + 11, + 104, + 235, + 158, + 178, + 132, + 60, + 57, + 239, + 76, + 132, + 194, + 57, + 7, + 139, + 91, + 213, + 51, + 1, + 86, + 115, + 247, + 174, + 42, + 251, + 230, + 165, + 4, + 54, + 155, + 52, + 255, + 232, + 109, + 35, + 134, + 85, + 199, + 120, + 77, + 197, + 185, + 107, + 131, + 142, + 79, + 171, + 217, + 66, + 49, + 117, + 130, + 204, + 83, + 125, + 183, + 21, + 37, + 157, + 209, + 34, + 87, + 214, + 89, + 18, + 89, + 152, + 70, + 185, + 75, + 174, + 62, + 112, + 179, + 65, + 236, + 239, + 51, + 171, + 175, + 236, + 166, + 250, + 255, + 89, + 112, + 70, + 245, + 191, + 67, + 214, + 202, + 151, + 149, + 246, + 225, + 5, + 193, + 251, + 80, + 224, + 189, + 107, + 242, + 113, + 233, + 142, + 176, + 236, + 17, + 27, + 82, + 177, + 101, + 31, + 33, + 16, + 250, + 218, + 164, + 1, + 32, + 157, + 38, + 139, + 32, + 193, + 159, + 5, + 251, + 126, + 99, + 72, + 211, + 80, + 226, + 153, + 114, + 86, + 129, + 122, + 67, + 179, + 235, + 79, + 116, + 27, + 127, + 165, + 52, + 45, + 40, + 209, + 217, + 215, + 121, + 95, + 213, + 217, + 166, + 225, + 13, + 45, + 49, + 159, + 157, + 167, + 149, + 134, + 245, + 89, + 64, + 98, + 84, + 229, + 134, + 71, + 225, + 35, + 250, + 191, + 15, + 162, + 107, + 63, + 19, + 137, + 21, + 10, + 189, + 188, + 58, + 44, + 230, + 66, + 60, + 114, + 149, + 89, + 244, + 179, + 198, + 11, + 17, + 76, + 93, + 191, + 232, + 57, + 11, + 123, + 132, + 76, + 135, + 21, + 227, + 209, + 140, + 230, + 85, + 252, + 238, + 195, + 126, + 135, + 213, + 176, + 200, + 170, + 240, + 30, + 150, + 253, + 128, + 221, + 11, + 149, + 21, + 187, + 114, + 90, + 84, + 160, + 236, + 12, + 250, + 9, + 113, + 147, + 199, + 208, + 54, + 27, + 87, + 206, + 164, + 77, + 241, + 29, + 174, + 7, + 221, + 62, + 116, + 25, + 244, + 26, + 119, + 164, + 32, + 77, + 68, + 244, + 108, + 42, + 61, + 93, + 68, + 128, + 129, + 149, + 20, + 172, + 166, + 94, + 188, + 230, + 26, + 224, + 43, + 50, + 138, + 207, + 67, + 90, + 234, + 60, + 129, + 48, + 54, + 179, + 59, + 185, + 114, + 244, + 37, + 210, + 13, + 93, + 144, + 37, + 97, + 70, + 48, + 11, + 187, + 60, + 193, + 174, + 60, + 219, + 54, + 149, + 52, + 166, + 134, + 55, + 172, + 208, + 58, + 150, + 53, + 125, + 104, + 40, + 214, + 217, + 24, + 50, + 56, + 249, + 122, + 33, + 202, + 209, + 16, + 16, + 67, + 50, + 152, + 154, + 168, + 62, + 145, + 52, + 188, + 20, + 41, + 253, + 46, + 100, + 198, + 148, + 114, + 9, + 59, + 41, + 159, + 9, + 145, + 222, + 228, + 65, + 235, + 105, + 254, + 146, + 151, + 237, + 98, + 238, + 18, + 11, + 99, + 84, + 117, + 41, + 38, + 74, + 77, + 80, + 102, + 34, + 95, + 127, + 92, + 193, + 86, + 131, + 163, + 70, + 61, + 21, + 126, + 113, + 60, + 122, + 102, + 83, + 38, + 171, + 106, + 9, + 214, + 192, + 247, + 231, + 127, + 133, + 44, + 252, + 169, + 32, + 80, + 159, + 7, + 35, + 126, + 71, + 109, + 0, + 49, + 164, + 208, + 211, + 129, + 166, + 159, + 54, + 98, + 196, + 232, + 232, + 4, + 203, + 97, + 222, + 111, + 213, + 189, + 131, + 90, + 227, + 92, + 221, + 40, + 241, + 231, + 97, + 70, + 153, + 78, + 86, + 105, + 29, + 36, + 160, + 175, + 254, + 185, + 45, + 127, + 199, + 170, + 34, + 107, + 131, + 174, + 229, + 186, + 232, + 30, + 69, + 222, + 99, + 242, + 207, + 118, + 171, + 245, + 238, + 182, + 160, + 68, + 130, + 56, + 76, + 136, + 253, + 60, + 28, + 76, + 151, + 90, + 121, + 60, + 202, + 236, + 217, + 185, + 173, + 226, + 173, + 252, + 152, + 227, + 168, + 145, + 188, + 181, + 58, + 31, + 104, + 140, + 49, + 113, + 77, + 184, + 32, + 45, + 158, + 156, + 238, + 219, + 88, + 8, + 104, + 114, + 189, + 230, + 192, + 190, + 202, + 29, + 170, + 6, + 239, + 58, + 216, + 56, + 52, + 195, + 196, + 199, + 213, + 99, + 16, + 57, + 207, + 19, + 242, + 179, + 97, + 151, + 249, + 38, + 150, + 140, + 164, + 62, + 126, + 82, + 208, + 30, + 197, + 41, + 248, + 239, + 110, + 99, + 115, + 170, + 148, + 202, + 232, + 160, + 132, + 141, + 195, + 56, + 25, + 30, + 1, + 142, + 20, + 138, + 176, + 57, + 165, + 72, + 151, + 35, + 243, + 207, + 250, + 142, + 195, + 11, + 30, + 239, + 195, + 85, + 15, + 60, + 55, + 101, + 20, + 121, + 164, + 202, + 124, + 11, + 111, + 20, + 222, + 159, + 198, + 133, + 198, + 85, + 238, + 149, + 123, + 119, + 50, + 24, + 173, + 86, + 92, + 147, + 244, + 53, + 197, + 60, + 203, + 167, + 64, + 11, + 142, + 67, + 147, + 49, + 124, + 112, + 196, + 159, + 97, + 71, + 188, + 216, + 84, + 103, + 240, + 217, + 225, + 0, + 70, + 149, + 71, + 241, + 96, + 83, + 126, + 121, + 210, + 25, + 157, + 221, + 88, + 108, + 178, + 124, + 145, + 231, + 145, + 105, + 198, + 183, + 33, + 71, + 154, + 18, + 24, + 6, + 205, + 231, + 135, + 192, + 223, + 81, + 122, + 205, + 82, + 146, + 58, + 218, + 180, + 136, + 163, + 180, + 210, + 53, + 161, + 82, + 155, + 154, + 47, + 43, + 111, + 4, + 0, + 229, + 32, + 0, + 194, + 170, + 15, + 147, + 128, + 208, + 159, + 237, + 162, + 217, + 129, + 148, + 186, + 119, + 187, + 143, + 10, + 166, + 90, + 171, + 248, + 35, + 9, + 86, + 212, + 104, + 122, + 165, + 103, + 198, + 191, + 213, + 161, + 218, + 94, + 157, + 168, + 106, + 247, + 218, + 186, + 136, + 161, + 221, + 116, + 251, + 155, + 154, + 73, + 38, + 95, + 32, + 244, + 19, + 33, + 160, + 187, + 73, + 49, + 231, + 196, + 238, + 248, + 107, + 160, + 222, + 187, + 224, + 193, + 101, + 101, + 252, + 16, + 90, + 119, + 57, + 37, + 137, + 16, + 29, + 223, + 3, + 142, + 245, + 22, + 56, + 73, + 52, + 187, + 100, + 145, + 47, + 227, + 178, + 48, + 241, + 102, + 226, + 75, + 203, + 153, + 92, + 236, + 150, + 54, + 15, + 144, + 77, + 157, + 114, + 54, + 3, + 62, + 40, + 115, + 45, + 67, + 159, + 128, + 114, + 239, + 86, + 21, + 51, + 137, + 160, + 73, + 37, + 30, + 214, + 231, + 67, + 208, + 8, + 255, + 102, + 29, + 139, + 215, + 113, + 176, + 121, + 24, + 193, + 115, + 16, + 199, + 219, + 250, + 59, + 0, + 217, + 111, + 46, + 188, + 174, + 92, + 149, + 165, + 37, + 215, + 173, + 148, + 169, + 104, + 89, + 11, + 13, + 12, + 45, + 80, + 71, + 112, + 77, + 188, + 243, + 186, + 143, + 66, + 253, + 148, + 106, + 245, + 133, + 158, + 34, + 84, + 38, + 236, + 204, + 72, + 48, + 35, + 71, + 65, + 4, + 0, + 65, + 175, + 4, + 201, + 206, + 123, + 157, + 73, + 178, + 149, + 20, + 27, + 15, + 155, + 154, + 211, + 31, + 63, + 62, + 223, + 44, + 165, + 226, + 231, + 230, + 204, + 33, + 81, + 238, + 230, + 17, + 243, + 45, + 35, + 17, + 115, + 183, + 158, + 183, + 210, + 202, + 250, + 154, + 73, + 146, + 89, + 176, + 163, + 184, + 155, + 200, + 80, + 96, + 71, + 107, + 72, + 107, + 70, + 180, + 41, + 247, + 101, + 10, + 33, + 80, + 213, + 27, + 52, + 14, + 85, + 33, + 236, + 172, + 194, + 144, + 0, + 21, + 147, + 141, + 89, + 222, + 47, + 22, + 125, + 57, + 26, + 2, + 147, + 43, + 244, + 46, + 211, + 149, + 139, + 27, + 38, + 159, + 59, + 21, + 108, + 250, + 145, + 172, + 216, + 35, + 235, + 4, + 207, + 148, + 15, + 207, + 241, + 58, + 0, + 172, + 251, + 16, + 48, + 57, + 90, + 108, + 183, + 218, + 255, + 16, + 36, + 9, + 165, + 72, + 250, + 171, + 137, + 77, + 160, + 37, + 148, + 172, + 3, + 208, + 83, + 12, + 152, + 207, + 37, + 201, + 158, + 141, + 158, + 10, + 110, + 140, + 58, + 35, + 228, + 225, + 60, + 172, + 211, + 0, + 53, + 117, + 216, + 78, + 219, + 16, + 59, + 142, + 250, + 76, + 222, + 181, + 122, + 44, + 74, + 22, + 139, + 228, + 94, + 67, + 151, + 29, + 22, + 107, + 43, + 73, + 109, + 255, + 244, + 159, + 139, + 198, + 161, + 122, + 50, + 37, + 203, + 27, + 104, + 244, + 94, + 23, + 189, + 8, + 14, + 70, + 19, + 89, + 133, + 240, + 18, + 234, + 73, + 7, + 8, + 106, + 10, + 79, + 235, + 54, + 213, + 69, + 72, + 97, + 151, + 89, + 74, + 217, + 104, + 87, + 38, + 152, + 218, + 102, + 117, + 248, + 88, + 7, + 238, + 135, + 32, + 109, + 28, + 181, + 117, + 95, + 93, + 148, + 118, + 178, + 138, + 61, + 18, + 163, + 56, + 83, + 195, + 223, + 53, + 156, + 98, + 20, + 226, + 255, + 34, + 136, + 80, + 32, + 78, + 173, + 241, + 213, + 64, + 86, + 43, + 50, + 139, + 10, + 82, + 215, + 110, + 12, + 101, + 4, + 109, + 112, + 247, + 240, + 234, + 131, + 209, + 219, + 237, + 158, + 35, + 69, + 223, + 201, + 222, + 20, + 51, + 117, + 240, + 226, + 54, + 138, + 179, + 24, + 128, + 18, + 52, + 250, + 131, + 35, + 63, + 80, + 197, + 122, + 191, + 81, + 100, + 122, + 104, + 210, + 91, + 222, + 85, + 109, + 105, + 5, + 9, + 55, + 172, + 114, + 136, + 169, + 133, + 191, + 227, + 194, + 87, + 36, + 54, + 145, + 89, + 197, + 198, + 137, + 97, + 128, + 19, + 90, + 182, + 237, + 197, + 8, + 20, + 224, + 250, + 180, + 153, + 201, + 99, + 147, + 90, + 70, + 57, + 225, + 15, + 205, + 151, + 26, + 2, + 50, + 197, + 2, + 13, + 161, + 63, + 192, + 59, + 167, + 42, + 187, + 105, + 225, + 118, + 123, + 59, + 60, + 194, + 183, + 4, + 44, + 136, + 112, + 98, + 172, + 60, + 172, + 64, + 41, + 41, + 212, + 14, + 1, + 211, + 108, + 175, + 168, + 159, + 117, + 229, + 143, + 142, + 7, + 93, + 117, + 95, + 55, + 68, + 159, + 58, + 210, + 201, + 197, + 33, + 212, + 151, + 224, + 59, + 87, + 33, + 109, + 238, + 150, + 113, + 109, + 27, + 132, + 92, + 94, + 13, + 24, + 117, + 98, + 245, + 210, + 220, + 182, + 200, + 187, + 103, + 64, + 238, + 87, + 218, + 158, + 160, + 238, + 217, + 73, + 210, + 2, + 144, + 92, + 81, + 130, + 160, + 35, + 122, + 206, + 167, + 149, + 252, + 175, + 53, + 86, + 120, + 69, + 82, + 104, + 110, + 111, + 3, + 254, + 184, + 34, + 60, + 130, + 203, + 159, + 243, + 183, + 3, + 153, + 172, + 201, + 63, + 29, + 15, + 43, + 80, + 55, + 230, + 14, + 136, + 210, + 109, + 167, + 60, + 25, + 169, + 21, + 146, + 123, + 79, + 178, + 197, + 42, + 77, + 69, + 155, + 4, + 145, + 168, + 137, + 209, + 215, + 204, + 187, + 221, + 38, + 25, + 135, + 151, + 22, + 252, + 28, + 6, + 38, + 131, + 197, + 205, + 8, + 86, + 209, + 200, + 87, + 192, + 113, + 94, + 140, + 38, + 214, + 82, + 96, + 51, + 191, + 19, + 91, + 38, + 22, + 212, + 148, + 49, + 250, + 56, + 211, + 52, + 189, + 68, + 204, + 254, + 109, + 46, + 109, + 133, + 32, + 89, + 96, + 200, + 54, + 192, + 106, + 253, + 16, + 153, + 200, + 164, + 2, + 183, + 121, + 30, + 228, + 160, + 42, + 19, + 227, + 232, + 43, + 81, + 37, + 202, + 204, + 51, + 187, + 189, + 135, + 20, + 194, + 21, + 104, + 136, + 186, + 202, + 250, + 219, + 148, + 106, + 60, + 214, + 250, + 155, + 115, + 171, + 76, + 242, + 228, + 103, + 231, + 86, + 50, + 59, + 198, + 60, + 177, + 8, + 229, + 136, + 194, + 184, + 121, + 60, + 9, + 150, + 254, + 83, + 77, + 138, + 72, + 0, + 68, + 194, + 54, + 98, + 226, + 25, + 63, + 160, + 237, + 81, + 30, + 23, + 203, + 198, + 232, + 226, + 166, + 37, + 135, + 116, + 204, + 102, + 121, + 209, + 117, + 252, + 216, + 20, + 172, + 207, + 117, + 73, + 167, + 232, + 185, + 201, + 252, + 199, + 204, + 85, + 35, + 6, + 39, + 13, + 249, + 248, + 119, + 173, + 223, + 206, + 117, + 193, + 212, + 249, + 38, + 68, + 163, + 61, + 77, + 77, + 103, + 214, + 15, + 35, + 60, + 27, + 125, + 174, + 64, + 43, + 229, + 9, + 171, + 86, + 249, + 53, + 164, + 34, + 26, + 103, + 76, + 221, + 46, + 86, + 254, + 109, + 125, + 63, + 221, + 81, + 15, + 162, + 252, + 253, + 74, + 30, + 123, + 248, + 2, + 92, + 124, + 115, + 117, + 196, + 2, + 92, + 186, + 56, + 241, + 131, + 94, + 108, + 185, + 94, + 96, + 32, + 70, + 168, + 194, + 55, + 100, + 101, + 24, + 212, + 236, + 186, + 187, + 240, + 238, + 166, + 48, + 85, + 248, + 0, + 238, + 151, + 184, + 30, + 232, + 65, + 18, + 137, + 141, + 59, + 158, + 219, + 147, + 141, + 158, + 11, + 71, + 44, + 96, + 106, + 117, + 130, + 144, + 132, + 94, + 215, + 41, + 218, + 178, + 100, + 177, + 76, + 89, + 146, + 239, + 66, + 95, + 80, + 118, + 209, + 5, + 230, + 185, + 95, + 180, + 195, + 229, + 167, + 164, + 29, + 89, + 154, + 191, + 122, + 201, + 200, + 187, + 67, + 43, + 25, + 201, + 222, + 55, + 43, + 163, + 171, + 22, + 7, + 180, + 165, + 31, + 101, + 44, + 187, + 209, + 97, + 22, + 22, + 42, + 64, + 210, + 254, + 235, + 203, + 72, + 26, + 88, + 34, + 139, + 13, + 72, + 92, + 166, + 208, + 62, + 94, + 17, + 79, + 16, + 55, + 142, + 18, + 140, + 253, + 150, + 9, + 243, + 212, + 91, + 74, + 132, + 76, + 50, + 124, + 116, + 248, + 119, + 134, + 31, + 173, + 87, + 58, + 144, + 214, + 189, + 124, + 222, + 85, + 69, + 211, + 144, + 92, + 225, + 41, + 99, + 220, + 236, + 239, + 215, + 255, + 8, + 167, + 115, + 143, + 143, + 197, + 37, + 27, + 39, + 5, + 156, + 174, + 127, + 85, + 26, + 128, + 97, + 72, + 108, + 93, + 25, + 136, + 113, + 54, + 42, + 137, + 207, + 100, + 85, + 95, + 191, + 57, + 174, + 25, + 26, + 98, + 81, + 214, + 109, + 243, + 109, + 140, + 132, + 100, + 245, + 146, + 144, + 79, + 117, + 83, + 168, + 9, + 95, + 58, + 11, + 59, + 103, + 204, + 55, + 153, + 204, + 36, + 32, + 29, + 169, + 255, + 90, + 65, + 207, + 143, + 168, + 61, + 6, + 43, + 25, + 221, + 143, + 44, + 141, + 6, + 158, + 91, + 9, + 60, + 208, + 228, + 39, + 36, + 205, + 200, + 253, + 199, + 168, + 17, + 250, + 122, + 153, + 17, + 42, + 91, + 243, + 160, + 79, + 38, + 171, + 28, + 92, + 244, + 128, + 227, + 108, + 28, + 106, + 206, + 35, + 19, + 180, + 24, + 122, + 65, + 132, + 101, + 107, + 70, + 131, + 255, + 162, + 92, + 243, + 13, + 143, + 84, + 58, + 17, + 32, + 200, + 127, + 244, + 124, + 72, + 114, + 125, + 40, + 59, + 173, + 13, + 44, + 184, + 9, + 103, + 123, + 5, + 138, + 97, + 172, + 26, + 5, + 32, + 211, + 196, + 249, + 62, + 245, + 92, + 246, + 212, + 118, + 96, + 222, + 199, + 89, + 113, + 7, + 106, + 128, + 98, + 69, + 219, + 158, + 6, + 156, + 129, + 247, + 111, + 58, + 144, + 213, + 96, + 153, + 239, + 73, + 121, + 193, + 181, + 242, + 213, + 59, + 181, + 69, + 216, + 64, + 103, + 145, + 174, + 206, + 141, + 40, + 106, + 172, + 49, + 88, + 78, + 152, + 185, + 159, + 34, + 242, + 158, + 141, + 238, + 191, + 0, + 14, + 105, + 0, + 118, + 2, + 84, + 72, + 152, + 15, + 135, + 50, + 22, + 152, + 249, + 87, + 133, + 19, + 20, + 243, + 113, + 214, + 161, + 119, + 85, + 135, + 104, + 12, + 30, + 186, + 208, + 157, + 14, + 123, + 1, + 68, + 24, + 25, + 35, + 171, + 213, + 70, + 97, + 97, + 159, + 70, + 237, + 128, + 28, + 130, + 208, + 158, + 97, + 78, + 226, + 73, + 108, + 231, + 18, + 24, + 152, + 148, + 122, + 167, + 113, + 188, + 228, + 21, + 213, + 186, + 145, + 59, + 180, + 185, + 0, + 18, + 209, + 66, + 182, + 159, + 59, + 13, + 22, + 247, + 169, + 212, + 168, + 240, + 92, + 115, + 83, + 80, + 205, + 85, + 58, + 72, + 181, + 202, + 87, + 52, + 239, + 106, + 41, + 94, + 106, + 172, + 82, + 135, + 95, + 134, + 77, + 32, + 214, + 210, + 91, + 177, + 134, + 240, + 120, + 30, + 157, + 143, + 40, + 59, + 71, + 12, + 205, + 230, + 54, + 114, + 234, + 147, + 48, + 103, + 80, + 192, + 83, + 136, + 164, + 93, + 211, + 138, + 115, + 116, + 210, + 156, + 197, + 173, + 90, + 48, + 27, + 47, + 180, + 130, + 19, + 39, + 63, + 165, + 139, + 117, + 73, + 137, + 165, + 182, + 181, + 7, + 168, + 158, + 95, + 107, + 100, + 195, + 31, + 115, + 89, + 91, + 242, + 181, + 54, + 251, + 180, + 16, + 211, + 116, + 251, + 225, + 32, + 140, + 90, + 25, + 196, + 23, + 171, + 161, + 245, + 180, + 36, + 108, + 79, + 194, + 22, + 160, + 116, + 201, + 224, + 64, + 249, + 184, + 225, + 22, + 114, + 46, + 164, + 38, + 117, + 246, + 44, + 82, + 22, + 88, + 244, + 160, + 34, + 88, + 102, + 53, + 75, + 224, + 96, + 204, + 255, + 84, + 38, + 158, + 234, + 233, + 222, + 79, + 40, + 82, + 245, + 171, + 199, + 169, + 69, + 30, + 206, + 180, + 108, + 107, + 24, + 78, + 133, + 75, + 37, + 12, + 149, + 213, + 216, + 207, + 9, + 42, + 13, + 234, + 89, + 47, + 174, + 64, + 206, + 13, + 223, + 73, + 171, + 193, + 107, + 66, + 119, + 63, + 169, + 136, + 177, + 40, + 15, + 181, + 187, + 101, + 9, + 232, + 155, + 208, + 230, + 5, + 211, + 62, + 64, + 197, + 198, + 49, + 24, + 40, + 17, + 89, + 116, + 87, + 208, + 108, + 195, + 198, + 151, + 56, + 12, + 143, + 5, + 219, + 34, + 104, + 138, + 219, + 178, + 129, + 111, + 89, + 76, + 162, + 135, + 132, + 182, + 225, + 70, + 173, + 33, + 67, + 210, + 250, + 224, + 134, + 205, + 59, + 146, + 15, + 21, + 177, + 197, + 228, + 52, + 47, + 113, + 5, + 238, + 134, + 27, + 139, + 110, + 67, + 10, + 13, + 167, + 16, + 102, + 243, + 20, + 179, + 139, + 155, + 74, + 210, + 215, + 78, + 245, + 14, + 250, + 44, + 79, + 63, + 200, + 181, + 217, + 225, + 100, + 232, + 105, + 173, + 250, + 161, + 89, + 14, + 21, + 250, + 31, + 120, + 89, + 230, + 124, + 111, + 174, + 69, + 139, + 182, + 94, + 66, + 131, + 103, + 175, + 216, + 109, + 102, + 11, + 179, + 126, + 180, + 29, + 219, + 173, + 140, + 106, + 121, + 149, + 82, + 94, + 10, + 123, + 66, + 35, + 153, + 177, + 85, + 145, + 98, + 240, + 53, + 20, + 92, + 252, + 211, + 98, + 103, + 203, + 15, + 99, + 228, + 234, + 209, + 13, + 131, + 223, + 10, + 56, + 83, + 147, + 255, + 12, + 94, + 208, + 189, + 134, + 209, + 53, + 178, + 172, + 186, + 196, + 249, + 159, + 171, + 65, + 166, + 178, + 236, + 247, + 244, + 44, + 23, + 56, + 74, + 17, + 213, + 246, + 190, + 91, + 80, + 232, + 166, + 225, + 222, + 98, + 61, + 9, + 7, + 60, + 165, + 199, + 165, + 30, + 66, + 213, + 1, + 214, + 86, + 152, + 183, + 20, + 184, + 153, + 187, + 84, + 191, + 83, + 124, + 198, + 202, + 184, + 194, + 239, + 219, + 187, + 230, + 100, + 72, + 216, + 95, + 254, + 97, + 80, + 168, + 212, + 195, + 1, + 68, + 91, + 227, + 55, + 181, + 203, + 196, + 151, + 6, + 122, + 24, + 37, + 87, + 5, + 225, + 213, + 217, + 228, + 10, + 235, + 162, + 167, + 172, + 97, + 93, + 176, + 81, + 94, + 229, + 154, + 201, + 226, + 160, + 154, + 40, + 21, + 118, + 31, + 118, + 207, + 193, + 111, + 150, + 43, + 180, + 104, + 1, + 118, + 44, + 180, + 163, + 144, + 164, + 90, + 150, + 15, + 22, + 249, + 91, + 209, + 101, + 99, + 187, + 236, + 81, + 22, + 167, + 158, + 0, + 75, + 170, + 45, + 244, + 31, + 83, + 106, + 243, + 176, + 148, + 130, + 15, + 58, + 53, + 205, + 12, + 48, + 137, + 255, + 180, + 25, + 206, + 3, + 236, + 239, + 176, + 61, + 56, + 173, + 104, + 131, + 165, + 144, + 218, + 128, + 36, + 127, + 252, + 34, + 140, + 98, + 146, + 113, + 173, + 93, + 224, + 110, + 16, + 236, + 113, + 32, + 79, + 82, + 2, + 81, + 48, + 243, + 167, + 226, + 255, + 219, + 92, + 97, + 125, + 126, + 205, + 171, + 110, + 64, + 37, + 49, + 112, + 2, + 186, + 223, + 54, + 108, + 233, + 189, + 26, + 31, + 45, + 236, + 198, + 147, + 47, + 126, + 92, + 97, + 182, + 36, + 40, + 192, + 146, + 12, + 120, + 162, + 185, + 60, + 223, + 183, + 88, + 9, + 155, + 182, + 103, + 157, + 113, + 109, + 116, + 22, + 233, + 11, + 163, + 250, + 14, + 168, + 78, + 239, + 88, + 149, + 116, + 57, + 173, + 58, + 63, + 87, + 58, + 102, + 86, + 126, + 123, + 19, + 68, + 112, + 220, + 73, + 61, + 132, + 75, + 173, + 194, + 199, + 217, + 175, + 2, + 6, + 219, + 111, + 165, + 191, + 109, + 204, + 228, + 155, + 138, + 216, + 15, + 75, + 27, + 140, + 214, + 46, + 79, + 164, + 200, + 98, + 74, + 161, + 202, + 87, + 161, + 79, + 21, + 247, + 202, + 87, + 203, + 130, + 177, + 38, + 176, + 112, + 160, + 235, + 72, + 110, + 144, + 120, + 205, + 143, + 85, + 130, + 36, + 124, + 169, + 153, + 66, + 57, + 130, + 93, + 59, + 45, + 193, + 54, + 226, + 68, + 240, + 169, + 24, + 169, + 89, + 157, + 198, + 204, + 141, + 141, + 210, + 145, + 178, + 3, + 178, + 174, + 130, + 245, + 213, + 210, + 185, + 99, + 125, + 53, + 65, + 229, + 135, + 201, + 131, + 224, + 82, + 29, + 100, + 51, + 72, + 51, + 163, + 149, + 248, + 78, + 125, + 249, + 152, + 120, + 132, + 211, + 177, + 75, + 32, + 115, + 107, + 5, + 196, + 3, + 208, + 102, + 241, + 68, + 105, + 144, + 102, + 25, + 19, + 78, + 242, + 211, + 91, + 33, + 42, + 147, + 9, + 144, + 243, + 74, + 20, + 26, + 13, + 26, + 204, + 53, + 30, + 49, + 203, + 189, + 227, + 73, + 99, + 27, + 160, + 73, + 222, + 48, + 92, + 13, + 171, + 254, + 3, + 10, + 107, + 216, + 218, + 135, + 217, + 209, + 167, + 236, + 150, + 27, + 106, + 230, + 185, + 53, + 79, + 167, + 241, + 215, + 55, + 198, + 147, + 76, + 176, + 85, + 94, + 201, + 138, + 28, + 202, + 233, + 53, + 54, + 145, + 49, + 154, + 203, + 153, + 75, + 34, + 141, + 227, + 183, + 215, + 90, + 190, + 127, + 220, + 117, + 121, + 17, + 49, + 250, + 66, + 65, + 219, + 206, + 7, + 54, + 235, + 137, + 146, + 63, + 3, + 138, + 150, + 227, + 204, + 40, + 161, + 124, + 229, + 249, + 228, + 40, + 104, + 170, + 177, + 65, + 82, + 240, + 188, + 209, + 76, + 62, + 187, + 21, + 122, + 216, + 178, + 49, + 27, + 99, + 225, + 50, + 126, + 36, + 154, + 8, + 227, + 67, + 170, + 115, + 28, + 211, + 145, + 112, + 133, + 114, + 145, + 47, + 212, + 49, + 142, + 207, + 178, + 130, + 20, + 20, + 97, + 241, + 212, + 227, + 58, + 203, + 84, + 219, + 83, + 202, + 56, + 186, + 254, + 91, + 73, + 114, + 206, + 152, + 240, + 176, + 102, + 254, + 106, + 15, + 228, + 131, + 164, + 50, + 249, + 98, + 85, + 21, + 60, + 52, + 81, + 126, + 67, + 219, + 246, + 133, + 169, + 64, + 96, + 58, + 153, + 184, + 58, + 227, + 132, + 98, + 168, + 170, + 190, + 63, + 85, + 230, + 30, + 195, + 155, + 224, + 124, + 229, + 81, + 30, + 18, + 128, + 56, + 203, + 239, + 171, + 5, + 185, + 14, + 104, + 228, + 75, + 27, + 212, + 37, + 8, + 211, + 119, + 152, + 239, + 241, + 26, + 94, + 31, + 9, + 191, + 170, + 76, + 178, + 140, + 227, + 97, + 136, + 182, + 117, + 193, + 8, + 80, + 55, + 108, + 243, + 247, + 127, + 204, + 126, + 126, + 227, + 68, + 153, + 123, + 82, + 68, + 70, + 198, + 26, + 83, + 239, + 146, + 12, + 128, + 240, + 197, + 43, + 108, + 171, + 113, + 134, + 247, + 156, + 9, + 228, + 93, + 255, + 5, + 226, + 203, + 31, + 42, + 116, + 31, + 178, + 224, + 49, + 43, + 18, + 27, + 234, + 50, + 166, + 3, + 173, + 253, + 227, + 236, + 111, + 43, + 152, + 134, + 30, + 218, + 50, + 105, + 98, + 220, + 14, + 156, + 56, + 166, + 173, + 147, + 253, + 92, + 101, + 48, + 234, + 224, + 96, + 237, + 223, + 150, + 88, + 12, + 103, + 201, + 127, + 206, + 86, + 39, + 237, + 216, + 126, + 160, + 112, + 166, + 175, + 105, + 218, + 48, + 73, + 198, + 92, + 17, + 211, + 63, + 132, + 244, + 226, + 71, + 27, + 243, + 74, + 15, + 40, + 238, + 56, + 63, + 192, + 165, + 106, + 76, + 34, + 240, + 7, + 5, + 196, + 5, + 78, + 198, + 152, + 102, + 125, + 61, + 139, + 113, + 58, + 137, + 23, + 11, + 171, + 54, + 75, + 65, + 45, + 108, + 35, + 186, + 218, + 68, + 222, + 195, + 223, + 8, + 253, + 190, + 148, + 13, + 139, + 149, + 19, + 125, + 40, + 66, + 24, + 75, + 218, + 129, + 22, + 160, + 47, + 2, + 44, + 31, + 212, + 33, + 219, + 182, + 183, + 251, + 173, + 174, + 87, + 123, + 131, + 1, + 216, + 89, + 243, + 134, + 179, + 169, + 62, + 146, + 155, + 144, + 51, + 62, + 193, + 101, + 226, + 37, + 34, + 162, + 39, + 59, + 39, + 175, + 220, + 58, + 177, + 94, + 190, + 177, + 184, + 120, + 18, + 70, + 196, + 140, + 33, + 250, + 201, + 97, + 46, + 229, + 53, + 235, + 160, + 90, + 217, + 206, + 111, + 120, + 180, + 210, + 241, + 178, + 110, + 232, + 19, + 172, + 175, + 137, + 88, + 232, + 5, + 135, + 46, + 4, + 107, + 242, + 35, + 131, + 116, + 80, + 38, + 41, + 40, + 82, + 155, + 149, + 81, + 210, + 186, + 73, + 102, + 46, + 134, + 10, + 215, + 201, + 99, + 223, + 44, + 143, + 146, + 88, + 159, + 164, + 188, + 80, + 8, + 62, + 12, + 121, + 113, + 185, + 242, + 233, + 31, + 44, + 135, + 82, + 227, + 213, + 131, + 176, + 125, + 20, + 75, + 93, + 160, + 89, + 242, + 15, + 9, + 154, + 6, + 248, + 98, + 159, + 62, + 20, + 14, + 213, + 151, + 159, + 207, + 227, + 12, + 64, + 172, + 21, + 158, + 70, + 124, + 226, + 63, + 170, + 78, + 94, + 206, + 34, + 116, + 217, + 170, + 127, + 106, + 23, + 72, + 135, + 136, + 249, + 224, + 70, + 90, + 23, + 75, + 59, + 111, + 140, + 169, + 43, + 130, + 205, + 117, + 218, + 198, + 141, + 146, + 132, + 207, + 197, + 112, + 246, + 161, + 181, + 193, + 121, + 66, + 80, + 157, + 236, + 37, + 65, + 81, + 101, + 6, + 107, + 103, + 220, + 140, + 84, + 24, + 197, + 199, + 19, + 216, + 143, + 161, + 172, + 0, + 178, + 230, + 54, + 104, + 115, + 24, + 129, + 183, + 169, + 240, + 194, + 95, + 75, + 197, + 29, + 244, + 99, + 132, + 127, + 4, + 200, + 179, + 39, + 170, + 16, + 100, + 171, + 153, + 101, + 188, + 228, + 138, + 180, + 73, + 206, + 130, + 215, + 136, + 148, + 29, + 242, + 121, + 188, + 159, + 166, + 41, + 149, + 129, + 101, + 155, + 124, + 244, + 195, + 32, + 144, + 29, + 18, + 191, + 211, + 250, + 211, + 85, + 112, + 77, + 192, + 96, + 60, + 42, + 146, + 177, + 88, + 168, + 47, + 202, + 31, + 230, + 223, + 237, + 187, + 39, + 89, + 235, + 185, + 253, + 150, + 97, + 29, + 139, + 92, + 133, + 84, + 232, + 71, + 68, + 63, + 30, + 67, + 212, + 150, + 188, + 164, + 186, + 110, + 151, + 44, + 181, + 58, + 197, + 192, + 102, + 158, + 241, + 91, + 152, + 229, + 3, + 35, + 229, + 173, + 107, + 90, + 165, + 108, + 183, + 153, + 246, + 125, + 181, + 124, + 222, + 3, + 255, + 94, + 57, + 239, + 108, + 22, + 180, + 178, + 126, + 39, + 4, + 113, + 126, + 3, + 249, + 36, + 182, + 9, + 92, + 0, + 167, + 155, + 54, + 105, + 24, + 149, + 203, + 211, + 171, + 95, + 115, + 206, + 180, + 137, + 182, + 23, + 71, + 224, + 184, + 71, + 157, + 66, + 137, + 14, + 95, + 3, + 70, + 217, + 68, + 193, + 192, + 208, + 46, + 46, + 116, + 173, + 164, + 139, + 219, + 82, + 248, + 90, + 36, + 216, + 190, + 102, + 209, + 73, + 226, + 166, + 66, + 107, + 163, + 55, + 44, + 246, + 48, + 17, + 180, + 4, + 214, + 0, + 104, + 44, + 84, + 163, + 208, + 69, + 246, + 170, + 124, + 89, + 164, + 80, + 53, + 51, + 31, + 6, + 89, + 14, + 7, + 100, + 150, + 80, + 116, + 148, + 91, + 149, + 107, + 91, + 253, + 98, + 192, + 124, + 106, + 47, + 10, + 168, + 2, + 218, + 27, + 37, + 32, + 151, + 118, + 26, + 77, + 230, + 250, + 241, + 28, + 142, + 99, + 118, + 126, + 0, + 156, + 240, + 146, + 75, + 14, + 104, + 182, + 145, + 102, + 168, + 228, + 73, + 35, + 160, + 9, + 17, + 121, + 46, + 29, + 48, + 123, + 47, + 114, + 222, + 126, + 239, + 191, + 13, + 53, + 126, + 37, + 84, + 251, + 200, + 116, + 1, + 239, + 35, + 27, + 72, + 185, + 181, + 69, + 161, + 130, + 254, + 91, + 11, + 237, + 161, + 17, + 39, + 10, + 119, + 30, + 157, + 75, + 42, + 156, + 214, + 213, + 190, + 225, + 183, + 193, + 31, + 117, + 92, + 110, + 100, + 116, + 128, + 105, + 190, + 216, + 135, + 138, + 194, + 107, + 103, + 73, + 148, + 113, + 213, + 168, + 66, + 215, + 132, + 56, + 83, + 245, + 137, + 62, + 178, + 112, + 67, + 43, + 42, + 73, + 185, + 192, + 92, + 51, + 249, + 231, + 68, + 123, + 41, + 61, + 248, + 21, + 62, + 218, + 47, + 200, + 136, + 41, + 108, + 139, + 101, + 9, + 54, + 241, + 1, + 103, + 111, + 194, + 5, + 47, + 153, + 90, + 142, + 217, + 85, + 150, + 35, + 35, + 229, + 248, + 41, + 41, + 166, + 188, + 13, + 69, + 252, + 19, + 107, + 242, + 250, + 36, + 173, + 134, + 224, + 152, + 234, + 155, + 99, + 178, + 114, + 178, + 29, + 255, + 157, + 91, + 112, + 195, + 45, + 120, + 30, + 87, + 168, + 136, + 175, + 126, + 206, + 227, + 153, + 57, + 196, + 54, + 88, + 36, + 53, + 13, + 159, + 237, + 121, + 83, + 202, + 199, + 97, + 75, + 105, + 62, + 34, + 137, + 1, + 16, + 37, + 98, + 52, + 177, + 46, + 91, + 0, + 226, + 37, + 83, + 123, + 202, + 49, + 251, + 11, + 50, + 96, + 24, + 165, + 189, + 233, + 23, + 2, + 155, + 22, + 128, + 132, + 10, + 135, + 179, + 114, + 109, + 158, + 205, + 161, + 159, + 48, + 162, + 39, + 122, + 127, + 56, + 107, + 215, + 211, + 161, + 77, + 242, + 92, + 131, + 137, + 225, + 129, + 34, + 156, + 21, + 90, + 2, + 237, + 18, + 21, + 166, + 4, + 252, + 4, + 14, + 42, + 185, + 189, + 64, + 59, + 196, + 247, + 48, + 107, + 31, + 122, + 22, + 155, + 178, + 227, + 109, + 44, + 144, + 63, + 175, + 145, + 162, + 2, + 10, + 236, + 68, + 90, + 243, + 19, + 88, + 65, + 231, + 8, + 46, + 18, + 189, + 239, + 117, + 7, + 149, + 141, + 191, + 31, + 2, + 255, + 182, + 37, + 13, + 160, + 253, + 196, + 105, + 143, + 147, + 74, + 109, + 0, + 100, + 230, + 211, + 9, + 35, + 59, + 2, + 18, + 21, + 40, + 190, + 223, + 159, + 240, + 111, + 223, + 177, + 111, + 247, + 249, + 224, + 254, + 155, + 64, + 86, + 227, + 64, + 159, + 129, + 26, + 219, + 171, + 144, + 30, + 99, + 86, + 222, + 250, + 24, + 143, + 24, + 59, + 195, + 104, + 157, + 110, + 143, + 200, + 6, + 48, + 225, + 67, + 22, + 84, + 123, + 185, + 100, + 122, + 135, + 79, + 106, + 176, + 87, + 229, + 99, + 190, + 57, + 32, + 62, + 87, + 232, + 111, + 111, + 226, + 189, + 39, + 106, + 25, + 24, + 142, + 255, + 70, + 240, + 15, + 190, + 233, + 221, + 50, + 244, + 89, + 32, + 206, + 172, + 74, + 67, + 194, + 16, + 248, + 24, + 46, + 77, + 227, + 177, + 100, + 230, + 184, + 22, + 32, + 177, + 51, + 147, + 200, + 170, + 89, + 229, + 23, + 255, + 120, + 38, + 60, + 130, + 50, + 10, + 30, + 223, + 37, + 249, + 130, + 179, + 241, + 128, + 70, + 139, + 48, + 59, + 251, + 134, + 228, + 20, + 29, + 248, + 154, + 241, + 5, + 86, + 118, + 129, + 56, + 243, + 9, + 130, + 26, + 41, + 239, + 84, + 142, + 84, + 104, + 193, + 74, + 253, + 252, + 147, + 99, + 208, + 52, + 75, + 242, + 161, + 196, + 46, + 149, + 212, + 146, + 239, + 198, + 213, + 2, + 40, + 5, + 45, + 70, + 154, + 203, + 251, + 0, + 223, + 103, + 175, + 55, + 221, + 27, + 228, + 145, + 224, + 38, + 215, + 19, + 193, + 201, + 62, + 58, + 194, + 18, + 117, + 24, + 115, + 45, + 52, + 70, + 71, + 17, + 136, + 244, + 54, + 208, + 46, + 203, + 122, + 175, + 238, + 177, + 93, + 27, + 121, + 204, + 157, + 8, + 29, + 102, + 158, + 96, + 122, + 69, + 60, + 124, + 67, + 126, + 74, + 55, + 60, + 86, + 209, + 159, + 23, + 248, + 88, + 74, + 131, + 100, + 82, + 176, + 134, + 189, + 27, + 174, + 26, + 111, + 218, + 82, + 4, + 80, + 215, + 253, + 56, + 5, + 31, + 136, + 67, + 17, + 238, + 93, + 43, + 115, + 56, + 62, + 242, + 192, + 39, + 33, + 157, + 228, + 92, + 233, + 64, + 251, + 1, + 32, + 186, + 140, + 182, + 112, + 157, + 47, + 77, + 119, + 85, + 107, + 197, + 74, + 32, + 65, + 240, + 226, + 201, + 60, + 130, + 12, + 168, + 221, + 84, + 194, + 62, + 111, + 190, + 141, + 75, + 57, + 239, + 135, + 215, + 126, + 86, + 40, + 37, + 228, + 89, + 174, + 179, + 67, + 165, + 180, + 180, + 88, + 161, + 142, + 46, + 29, + 189, + 104, + 39, + 124, + 3, + 151, + 220, + 250, + 96, + 94, + 8, + 206, + 231, + 240, + 110, + 167, + 44, + 24, + 234, + 29, + 91, + 93, + 228, + 140, + 237, + 126, + 126, + 145, + 193, + 177, + 135, + 90, + 248, + 247, + 6, + 244, + 203, + 178, + 146, + 53, + 162, + 201, + 171, + 213, + 95, + 186, + 7, + 232, + 215, + 109, + 33, + 187, + 218, + 85, + 227, + 69, + 3, + 246, + 101, + 201, + 109, + 159, + 186, + 104, + 166, + 181, + 161, + 6, + 162, + 81, + 12, + 235, + 67, + 17, + 158, + 99, + 81, + 226, + 198, + 219, + 61, + 63, + 26, + 135, + 112, + 56, + 41, + 99, + 31, + 15, + 245, + 3, + 226, + 108, + 144, + 185, + 204, + 209, + 8, + 244, + 68, + 133, + 101, + 13, + 84, + 93, + 52, + 199, + 120, + 206, + 48, + 117, + 115, + 52, + 85, + 22, + 163, + 238, + 124, + 14, + 210, + 15, + 87, + 208, + 183, + 75, + 251, + 102, + 170, + 96, + 73, + 72, + 183, + 197, + 243, + 112, + 36, + 175, + 63, + 113, + 167, + 244, + 0, + 65, + 248, + 88, + 19, + 146, + 86, + 136, + 131, + 110, + 198, + 125, + 181, + 97, + 205, + 1, + 53, + 199, + 35, + 184, + 182, + 224, + 232, + 79, + 102, + 233, + 113, + 156, + 156, + 101, + 17, + 2, + 168, + 190, + 191, + 69, + 176, + 103, + 200, + 116, + 101, + 177, + 1, + 29, + 190, + 182, + 39, + 112, + 237, + 58, + 114, + 112, + 217, + 41, + 139, + 8, + 221, + 214, + 248, + 187, + 154, + 197, + 227, + 192, + 78, + 122, + 234, + 64, + 95, + 44, + 113, + 245, + 167, + 64, + 138, + 130, + 137, + 236, + 150, + 41, + 150, + 222, + 35, + 164, + 76, + 18, + 88, + 9, + 200, + 11, + 185, + 116, + 37, + 182, + 113, + 2, + 70, + 238, + 45, + 106, + 95, + 58, + 212, + 174, + 174, + 164, + 118, + 112, + 202, + 202, + 11, + 121, + 19, + 217, + 144, + 158, + 244, + 164, + 239, + 42, + 126, + 8, + 148, + 250, + 82, + 224, + 252, + 231, + 248, + 123, + 182, + 60, + 22, + 243, + 212, + 75, + 200, + 226, + 73, + 56, + 125, + 210, + 12, + 34, + 39, + 18, + 17, + 47, + 95, + 117, + 231, + 110, + 226, + 44, + 249, + 80, + 176, + 30, + 32, + 70, + 124, + 243, + 3, + 38, + 14, + 122, + 196, + 129, + 69, + 151, + 43, + 248, + 182, + 214, + 195, + 114, + 96, + 150, + 207, + 243, + 152, + 160, + 65, + 248, + 223, + 208, + 255, + 29, + 127, + 248, + 219, + 162, + 7, + 124, + 126, + 88, + 222, + 81, + 66, + 163, + 141, + 41, + 63, + 105, + 115, + 33, + 25, + 115, + 108, + 124, + 58, + 150, + 102, + 50, + 182, + 214, + 18, + 245, + 95, + 27, + 103, + 254, + 213, + 250, + 199, + 64, + 167, + 79, + 163, + 23, + 8, + 31, + 135, + 162, + 41, + 161, + 85, + 251, + 29, + 212, + 94, + 54, + 197, + 107, + 186, + 232, + 111, + 213, + 85, + 24, + 137, + 146, + 190, + 125, + 13, + 46, + 62, + 219, + 59, + 54, + 54, + 34, + 206, + 8, + 214, + 255, + 246, + 101, + 158, + 182, + 207, + 51, + 173, + 186, + 254, + 117, + 35, + 220, + 213, + 55, + 93, + 172, + 165, + 170, + 83, + 33, + 138, + 168, + 48, + 118, + 247, + 69, + 166, + 198, + 164, + 250, + 145, + 143, + 38, + 155, + 170, + 127, + 191, + 58, + 111, + 115, + 176, + 10, + 103, + 138, + 104, + 162, + 123, + 61, + 130, + 99, + 230, + 9, + 77, + 55, + 90, + 1, + 202, + 79, + 124, + 15, + 59, + 243, + 93, + 111, + 207, + 222, + 3, + 58, + 156, + 252, + 7, + 215, + 189, + 66, + 150, + 64, + 14, + 31, + 136, + 115, + 240, + 183, + 253, + 155, + 165, + 196, + 131, + 214, + 201, + 59, + 232, + 159, + 38, + 4, + 42, + 244, + 227, + 93, + 59, + 16, + 160, + 32, + 42, + 9, + 110, + 204, + 206, + 62, + 236, + 160, + 1, + 41, + 240, + 111, + 222, + 191, + 86, + 199, + 54, + 225, + 3, + 29, + 253, + 89, + 93, + 20, + 17, + 217, + 63, + 157, + 237, + 177, + 245, + 127, + 43, + 129, + 89, + 57, + 251, + 124, + 228, + 204, + 137, + 196, + 184, + 47, + 173, + 156, + 227, + 122, + 103, + 89, + 150, + 53, + 190, + 101, + 54, + 217, + 152, + 173, + 143, + 250, + 19, + 52, + 188, + 62, + 15, + 66, + 99, + 162, + 81, + 43, + 45, + 141, + 85, + 249, + 151, + 38, + 8, + 9, + 170, + 228, + 152, + 180, + 189, + 38, + 109, + 179, + 85, + 188, + 123, + 105, + 190, + 84, + 176, + 196, + 9, + 201, + 28, + 153, + 251, + 63, + 237, + 133, + 239, + 149, + 187, + 1, + 232, + 209, + 185, + 18, + 245, + 51, + 82, + 142, + 189, + 107, + 114, + 78, + 81, + 33, + 171, + 23, + 177, + 177, + 168, + 70, + 33, + 218, + 75, + 8, + 174, + 97, + 58, + 222, + 93, + 162, + 103, + 8, + 62, + 32, + 73, + 66, + 99, + 206, + 168, + 103, + 171, + 102, + 251, + 98, + 188, + 51, + 238, + 67, + 66, + 95, + 89, + 117, + 48, + 111, + 136, + 172, + 72, + 131, + 10, + 164, + 112, + 155, + 250, + 61, + 46, + 115, + 102, + 80, + 166, + 226, + 23, + 161, + 187, + 4, + 38, + 84, + 8, + 30, + 91, + 183, + 224, + 126, + 17, + 157, + 53, + 122, + 215, + 11, + 75, + 61, + 118, + 232, + 161, + 25, + 211, + 229, + 150, + 24, + 28, + 22, + 76, + 88, + 120, + 172, + 140, + 24, + 152, + 213, + 5, + 3, + 1, + 110, + 243, + 150, + 164, + 22, + 126, + 48, + 45, + 42, + 39, + 239, + 85, + 160, + 225, + 232, + 143, + 238, + 199, + 209, + 90, + 221, + 186, + 225, + 139, + 69, + 132, + 47, + 36, + 51, + 163, + 195, + 253, + 156, + 7, + 144, + 226, + 221, + 70, + 96, + 8, + 165, + 105, + 91, + 7, + 8, + 74, + 27, + 124, + 89, + 241, + 235, + 163, + 155, + 11, + 172, + 124, + 56, + 145, + 27, + 204, + 110, + 43, + 243, + 116, + 81, + 160, + 69, + 168, + 74, + 5, + 234, + 241, + 202, + 166, + 154, + 133, + 33, + 193, + 246, + 74, + 194, + 193, + 10, + 147, + 54, + 147, + 53, + 86, + 236, + 194, + 69, + 116, + 82, + 162, + 11, + 227, + 172, + 217, + 200, + 2, + 28, + 249, + 213, + 8, + 69, + 233, + 116, + 156, + 77, + 118, + 218, + 224, + 85, + 170, + 63, + 251, + 19, + 199, + 176, + 35, + 157, + 132, + 110, + 193, + 9, + 98, + 139, + 109, + 182, + 145, + 50, + 64, + 253, + 57, + 45, + 31, + 16, + 175, + 144, + 124, + 53, + 91, + 106, + 165, + 195, + 242, + 243, + 75, + 7, + 20, + 198, + 123, + 123, + 124, + 103, + 252, + 162, + 67, + 136, + 41, + 241, + 201, + 96, + 227, + 126, + 110, + 116, + 38, + 154, + 249, + 106, + 182, + 174, + 153, + 40, + 73, + 106, + 18, + 5, + 21, + 215, + 123, + 249, + 58, + 171, + 56, + 21, + 138, + 25, + 106, + 56, + 212, + 120, + 210, + 40, + 50, + 155, + 147, + 167, + 201, + 213, + 208, + 146, + 76, + 0, + 118, + 216, + 196, + 90, + 136, + 3, + 15, + 124, + 64, + 222, + 37, + 199, + 139, + 21, + 46, + 109, + 169, + 163, + 219, + 240, + 6, + 129, + 182, + 27, + 15, + 26, + 156, + 32, + 184, + 155, + 246, + 237, + 29, + 129, + 154, + 239, + 96, + 46, + 84, + 147, + 217, + 141, + 222, + 133, + 10, + 72, + 81, + 111, + 75, + 69, + 80, + 93, + 11, + 44, + 45, + 228, + 79, + 74, + 115, + 132, + 79, + 54, + 214, + 118, + 133, + 241, + 141, + 100, + 23, + 39, + 106, + 164, + 125, + 213, + 148, + 204, + 206, + 63, + 6, + 60, + 93, + 18, + 141, + 235, + 32, + 55, + 214, + 185, + 64, + 143, + 182, + 131, + 85, + 11, + 112, + 243, + 69, + 227, + 77, + 43, + 8, + 161, + 47, + 13, + 182, + 202, + 174, + 139, + 76, + 51, + 51, + 137, + 74, + 172, + 188, + 207, + 49, + 32, + 25, + 110, + 8, + 31, + 43, + 15, + 226, + 70, + 147, + 1, + 75, + 160, + 168, + 127, + 179, + 129, + 21, + 159, + 60, + 107, + 108, + 254, + 85, + 111, + 233, + 69, + 158, + 99, + 44, + 118, + 69, + 144, + 240, + 32, + 205, + 207, + 246, + 253, + 8, + 33, + 66, + 118, + 163, + 31, + 174, + 166, + 164, + 239, + 2, + 184, + 89, + 161, + 243, + 47, + 110, + 43, + 184, + 97, + 77, + 16, + 133, + 253, + 217, + 210, + 125, + 124, + 192, + 129, + 105, + 31, + 71, + 40, + 63, + 71, + 164, + 197, + 183, + 38, + 58, + 245, + 234, + 105, + 183, + 176, + 182, + 109, + 204, + 84, + 12, + 119, + 165, + 247, + 33, + 209, + 199, + 221, + 223, + 239, + 97, + 113, + 29, + 8, + 169, + 31, + 245, + 58, + 158, + 136, + 145, + 95, + 86, + 59, + 246, + 158, + 191, + 253, + 171, + 187, + 226, + 64, + 130, + 132, + 137, + 102, + 228, + 192, + 197, + 116, + 77, + 222, + 231, + 3, + 78, + 160, + 252, + 173, + 67, + 16, + 15, + 236, + 108, + 173, + 64, + 33, + 107, + 217, + 200, + 10, + 233, + 96, + 27, + 80, + 30, + 253, + 241, + 32, + 245, + 190, + 19, + 188, + 24, + 239, + 231, + 4, + 190, + 232, + 194, + 173, + 72, + 155, + 228, + 190, + 101, + 92, + 86, + 156, + 206, + 62, + 125, + 201, + 85, + 114, + 124, + 3, + 34, + 212, + 131, + 204, + 68, + 150, + 25, + 145, + 2, + 131, + 250, + 147, + 170, + 142, + 109, + 139, + 48, + 229, + 65, + 246, + 30, + 185, + 120, + 101, + 121, + 52, + 151, + 194, + 120, + 142, + 32, + 67, + 88, + 63, + 209, + 125, + 92, + 81, + 142, + 51, + 156, + 88, + 133, + 157, + 174, + 93, + 118, + 151, + 17, + 188, + 168, + 247, + 4, + 107, + 122, + 49, + 98, + 177, + 47, + 244, + 16, + 7, + 255, + 9, + 63, + 127, + 102, + 93, + 148, + 209, + 150, + 38, + 121, + 170, + 6, + 31, + 47, + 56, + 2, + 5, + 212, + 54, + 46, + 16, + 248, + 80, + 54, + 189, + 3, + 28, + 51, + 253, + 3, + 23, + 45, + 76, + 20, + 58, + 187, + 1, + 189, + 204, + 205, + 123, + 238, + 144, + 110, + 58, + 53, + 20, + 244, + 121, + 7, + 178, + 11, + 228, + 152, + 132, + 11, + 85, + 99, + 139, + 1, + 117, + 17, + 146, + 142, + 108, + 230, + 64, + 249, + 250, + 1, + 160, + 123, + 187, + 232, + 75, + 59, + 11, + 58, + 226, + 251, + 105, + 186, + 170, + 209, + 128, + 102, + 92, + 239, + 222, + 113, + 84, + 63, + 32, + 194, + 9, + 71, + 22, + 174, + 253, + 87, + 92, + 221, + 250, + 161, + 54, + 108, + 212, + 195, + 175, + 179, + 180, + 106, + 235, + 157, + 252, + 226, + 167, + 87, + 76, + 62, + 153, + 174, + 84, + 173, + 245, + 95, + 135, + 39, + 8, + 94, + 210, + 7, + 53, + 195, + 145, + 131, + 213, + 131, + 81, + 140, + 121, + 200, + 224, + 196, + 194, + 41, + 84, + 228, + 57, + 74, + 220, + 228, + 249, + 61, + 217, + 217, + 5, + 88, + 109, + 86, + 8, + 73, + 225, + 79, + 219, + 96, + 118, + 226, + 32, + 207, + 168, + 123, + 134, + 204, + 28, + 149, + 126, + 213, + 134, + 65, + 192, + 92, + 73, + 109, + 229, + 154, + 169, + 86, + 154, + 29, + 48, + 143, + 97, + 123, + 243, + 107, + 252, + 66, + 12, + 85, + 45, + 90, + 51, + 236, + 205, + 98, + 198, + 141, + 172, + 214, + 147, + 118, + 209, + 129, + 216, + 0, + 112, + 125, + 46, + 194, + 229, + 96, + 151, + 15, + 30, + 251, + 140, + 129, + 204, + 175, + 250, + 77, + 247, + 51, + 108, + 90, + 228, + 218, + 65, + 149, + 241, + 142, + 160, + 49, + 13, + 11, + 236, + 217, + 147, + 72, + 42, + 138, + 61, + 168, + 58, + 193, + 56, + 135, + 117, + 157, + 103, + 8, + 172, + 224, + 75, + 98, + 109, + 64, + 67, + 224, + 230, + 84, + 195, + 37, + 116, + 225, + 222, + 236, + 251, + 156, + 88, + 120, + 147, + 136, + 83, + 104, + 199, + 154, + 14, + 194, + 12, + 67, + 73, + 191, + 198, + 233, + 245, + 91, + 244, + 203, + 181, + 197, + 130, + 28, + 48, + 242, + 245, + 134, + 23, + 158, + 224, + 56, + 190, + 145, + 151, + 206, + 36, + 90, + 86, + 21, + 14, + 223, + 5, + 177, + 223, + 98, + 136, + 138, + 156, + 232, + 98, + 154, + 104, + 65, + 249, + 170, + 33, + 152, + 39, + 76, + 22, + 79, + 30, + 176, + 162, + 88, + 249, + 168, + 239, + 144, + 48, + 135, + 44, + 102, + 60, + 200, + 160, + 119, + 123, + 150, + 232, + 119, + 70, + 62, + 113, + 238, + 28, + 95, + 73, + 68, + 232, + 83, + 0, + 167, + 135, + 89, + 175, + 52, + 42, + 173, + 99, + 231, + 151, + 178, + 55, + 39, + 39, + 5, + 250, + 12, + 19, + 131, + 118, + 185, + 144, + 223, + 250, + 216, + 70, + 47, + 179, + 59, + 41, + 86, + 138, + 195, + 160, + 88, + 21, + 251, + 150, + 104, + 114, + 81, + 53, + 187, + 73, + 202, + 15, + 237, + 90, + 45, + 96, + 182, + 61, + 52, + 49, + 219, + 239, + 31, + 96, + 150, + 110, + 82, + 96, + 183, + 15, + 227, + 189, + 107, + 4, + 132, + 117, + 80, + 4, + 197, + 22, + 97, + 22, + 72, + 211, + 59, + 162, + 66, + 200, + 154, + 44, + 236, + 77, + 43, + 135, + 223, + 216, + 249, + 106, + 180, + 172, + 13, + 77, + 154, + 253, + 74, + 213, + 227, + 178, + 147, + 224, + 73, + 194, + 59, + 65, + 20, + 45, + 176, + 104, + 91, + 212, + 112, + 17, + 50, + 41, + 29, + 16, + 168, + 50, + 255, + 244, + 140, + 54, + 182, + 227, + 142, + 141, + 33, + 234, + 34, + 103, + 239, + 250, + 80, + 2, + 83, + 70, + 120, + 177, + 218, + 170, + 164, + 142, + 228, + 241, + 109, + 223, + 208, + 165, + 48, + 20, + 230, + 198, + 190, + 95, + 62, + 84, + 108, + 34, + 64, + 225, + 157, + 164, + 121, + 28, + 40, + 232, + 99, + 20, + 76, + 251, + 225, + 215, + 107, + 244, + 126, + 54, + 163, + 122, + 26, + 46, + 6, + 68, + 169, + 10, + 143, + 157, + 173, + 44, + 186, + 27, + 38, + 20, + 167, + 184, + 28, + 21, + 103, + 13, + 208, + 19, + 47, + 252, + 220, + 128, + 162, + 47, + 32, + 60, + 146, + 12, + 247, + 54, + 53, + 127, + 181, + 211, + 104, + 32, + 129, + 12, + 93, + 135, + 180, + 100, + 164, + 80, + 161, + 76, + 140, + 253, + 141, + 115, + 146, + 179, + 158, + 225, + 6, + 122, + 221, + 71, + 18, + 148, + 171, + 209, + 223, + 61, + 79, + 127, + 255, + 12, + 36, + 189, + 55, + 210, + 223, + 12, + 62, + 103, + 165, + 45, + 254, + 98, + 88, + 77, + 205, + 121, + 58, + 34, + 55, + 216, + 145, + 40, + 51, + 191, + 159, + 31, + 116, + 34, + 158, + 28, + 239, + 207, + 85, + 75, + 95, + 12, + 18, + 74, + 117, + 144, + 11, + 58, + 239, + 219, + 137, + 28, + 46, + 74, + 209, + 207, + 196, + 45, + 156, + 13, + 227, + 224, + 188, + 146, + 11, + 45, + 122, + 84, + 77, + 186, + 235, + 32, + 162, + 123, + 95, + 125, + 44, + 143, + 1, + 255, + 103, + 47, + 75, + 92, + 168, + 63, + 19, + 74, + 198, + 192, + 156, + 133, + 224, + 34, + 56, + 93, + 10, + 14, + 129, + 161, + 225, + 0, + 178, + 72, + 96, + 71, + 244, + 158, + 139, + 64, + 146, + 226, + 136, + 124, + 219, + 7, + 23, + 120, + 211, + 49, + 234, + 143, + 64, + 23, + 19, + 38, + 197, + 203, + 231, + 148, + 44, + 154, + 110, + 81, + 191, + 13, + 190, + 70, + 35, + 131, + 136, + 241, + 78, + 155, + 156, + 136, + 177, + 90, + 92, + 189, + 174, + 193, + 69, + 213, + 162, + 148, + 226, + 131, + 66, + 211, + 194, + 193, + 77, + 199, + 23, + 176, + 101, + 230, + 48, + 158, + 56, + 166, + 49, + 55, + 19, + 90, + 90, + 232, + 203, + 43, + 188, + 188, + 67, + 216, + 229, + 181, + 113, + 177, + 226, + 221, + 57, + 124, + 207, + 87, + 7, + 55, + 136, + 79, + 57, + 229, + 174, + 225, + 27, + 87, + 63, + 107, + 168, + 14, + 80, + 146, + 107, + 37, + 203, + 185, + 234, + 11, + 50, + 35, + 13, + 86, + 41, + 99, + 133, + 19, + 20, + 20, + 142, + 64, + 42, + 55, + 120, + 34, + 171, + 119, + 129, + 130, + 113, + 253, + 248, + 61, + 0, + 196, + 52, + 67, + 7, + 176, + 220, + 106, + 149, + 101, + 23, + 134, + 85, + 42, + 178, + 60, + 81, + 183, + 107, + 10, + 63, + 94, + 111, + 187, + 126, + 26, + 106, + 198, + 131, + 55, + 162, + 27, + 250, + 49, + 82, + 48, + 157, + 210, + 131, + 11, + 1, + 179, + 113, + 196, + 89, + 20, + 229, + 103, + 62, + 48, + 23, + 164, + 75, + 192, + 116, + 149, + 117, + 135, + 106, + 226, + 160, + 123, + 48, + 176, + 193, + 41, + 1, + 24, + 134, + 68, + 87, + 213, + 228, + 117, + 177, + 20, + 184, + 16, + 58, + 180, + 253, + 46, + 45, + 6, + 147, + 136, + 99, + 166, + 84, + 36, + 197, + 24, + 167, + 71, + 83, + 53, + 44, + 174, + 176, + 84, + 243, + 60, + 217, + 254, + 52, + 255, + 30, + 10, + 6, + 34, + 62, + 152, + 200, + 101, + 105, + 57, + 97, + 28, + 209, + 29, + 94, + 66, + 192, + 147, + 209, + 14, + 0, + 13, + 69, + 11, + 96, + 73, + 235, + 164, + 116, + 198, + 45, + 9, + 251, + 198, + 131, + 231, + 210, + 181, + 215, + 202, + 139, + 54, + 78, + 29, + 160, + 158, + 175, + 73, + 250, + 177, + 226, + 77, + 38, + 94, + 138, + 151, + 206, + 104, + 191, + 176, + 174, + 167, + 250, + 93, + 240, + 82, + 179, + 56, + 251, + 26, + 170, + 155, + 229, + 40, + 151, + 71, + 239, + 151, + 66, + 158, + 236, + 7, + 59, + 26, + 83, + 80, + 27, + 94, + 145, + 115, + 195, + 113, + 201, + 182, + 204, + 222, + 241, + 210, + 151, + 67, + 222, + 31, + 120, + 1, + 51, + 16, + 166, + 230, + 210, + 100, + 132, + 105, + 152, + 124, + 176, + 51, + 165, + 183, + 190, + 255, + 171, + 30, + 178, + 219, + 109, + 240, + 82, + 145, + 199, + 153, + 189, + 176, + 82, + 88, + 251, + 49, + 111, + 174, + 148, + 96, + 216, + 156, + 145, + 150, + 64, + 66, + 142, + 45, + 92, + 162, + 163, + 131, + 250, + 51, + 136, + 82, + 201, + 253, + 123, + 33, + 210, + 249, + 124, + 185, + 181, + 49, + 26, + 228, + 202, + 14, + 225, + 132, + 136, + 165, + 213, + 188, + 2, + 182, + 29, + 171, + 196, + 17, + 84, + 150, + 221, + 89, + 212, + 31, + 127, + 203, + 105, + 145, + 70, + 2, + 45, + 181, + 132, + 78, + 170, + 96, + 128, + 86, + 102, + 227, + 62, + 16, + 165, + 90, + 48, + 52, + 80, + 161, + 225, + 77, + 17, + 129, + 254, + 87, + 55, + 168, + 93, + 28, + 151, + 252, + 157, + 229, + 106, + 210, + 111, + 122, + 112, + 89, + 29, + 197, + 104, + 246, + 247, + 101, + 26, + 59, + 107, + 8, + 207, + 43, + 190, + 155, + 59, + 114, + 12, + 20, + 26, + 151, + 249, + 39, + 109, + 121, + 147, + 116, + 10, + 83, + 151, + 110, + 30, + 121, + 36, + 36, + 242, + 239, + 19, + 149, + 61, + 227, + 26, + 247, + 53, + 170, + 67, + 4, + 185, + 131, + 235, + 106, + 234, + 48, + 238, + 8, + 15, + 78, + 50, + 251, + 156, + 47, + 137, + 70, + 230, + 69, + 160, + 140, + 222, + 149, + 220, + 242, + 173, + 88, + 233, + 30, + 20, + 221, + 218, + 96, + 97, + 125, + 1, + 59, + 227, + 17, + 103, + 224, + 24, + 196, + 55, + 178, + 156, + 155, + 25, + 228, + 29, + 147, + 212, + 92, + 204, + 71, + 41, + 165, + 205, + 168, + 16, + 248, + 90, + 193, + 53, + 69, + 75, + 12, + 101, + 37, + 59, + 51, + 188, + 3, + 46, + 129, + 150, + 205, + 145, + 72, + 39, + 83, + 147, + 109, + 171, + 130, + 201, + 177, + 218, + 26, + 253, + 188, + 127, + 116, + 90, + 182, + 168, + 95, + 136, + 212, + 146, + 101, + 76, + 43, + 43, + 194, + 250, + 115, + 251, + 98, + 120, + 244, + 195, + 230, + 109, + 135, + 131, + 125, + 141, + 65, + 71, + 135, + 65, + 230, + 102, + 175, + 196, + 246, + 174, + 211, + 47, + 233, + 229, + 87, + 122, + 108, + 15, + 220, + 51, + 5, + 222, + 197, + 149, + 126, + 49, + 92, + 250, + 7, + 243, + 96, + 45, + 49, + 212, + 86, + 74, + 30, + 235, + 210, + 249, + 252, + 92, + 155, + 77, + 40, + 222, + 45, + 216, + 212, + 98, + 8, + 27, + 214, + 97, + 147, + 157, + 198, + 16, + 150, + 77, + 112, + 2, + 214, + 255, + 89, + 123, + 74, + 87, + 253, + 145, + 36, + 80, + 122, + 206, + 195, + 170, + 221, + 50, + 8, + 168, + 194, + 49, + 53, + 40, + 76, + 36, + 199, + 71, + 33, + 149, + 107, + 156, + 171, + 215, + 95, + 225, + 244, + 209, + 124, + 87, + 211, + 235, + 77, + 88, + 143, + 211, + 203, + 6, + 60, + 104, + 42, + 212, + 182, + 252, + 90, + 221, + 141, + 226, + 196, + 39, + 137, + 83, + 139, + 188, + 100, + 112, + 2, + 95, + 147, + 21, + 174, + 26, + 63, + 50, + 195, + 7, + 210, + 32, + 138, + 55, + 80, + 22, + 48, + 226, + 85, + 164, + 64, + 90, + 253, + 102, + 90, + 156, + 208, + 0, + 170, + 199, + 6, + 153, + 199, + 240, + 1, + 3, + 242, + 145, + 32, + 130, + 207, + 195, + 121, + 124, + 206, + 147, + 12, + 95, + 33, + 30, + 148, + 171, + 209, + 167, + 237, + 56, + 11, + 37, + 242, + 122, + 90, + 154, + 234, + 106, + 217, + 84, + 38, + 87, + 179, + 156, + 212, + 103, + 62, + 231, + 54, + 9, + 194, + 138, + 67, + 69, + 13, + 197, + 173, + 158, + 255, + 178, + 59, + 231, + 199, + 133, + 155, + 55, + 130, + 9, + 7, + 177, + 149, + 21, + 144, + 70, + 85, + 122, + 43, + 245, + 201, + 181, + 96, + 120, + 240, + 11, + 11, + 173, + 9, + 91, + 106, + 204, + 122, + 78, + 230, + 171, + 124, + 36, + 153, + 80, + 239, + 180, + 136, + 28, + 105, + 74, + 207, + 131, + 213, + 255, + 23, + 145, + 208, + 73, + 19, + 74, + 121, + 44, + 130, + 76, + 63, + 69, + 120, + 143, + 76, + 177, + 239, + 110, + 45, + 253, + 195, + 87, + 22, + 227, + 181, + 73, + 71, + 157, + 67, + 170, + 18, + 61, + 9, + 69, + 66, + 56, + 241, + 201, + 130, + 234, + 215, + 101, + 112, + 132, + 71, + 247, + 51, + 135, + 240, + 139, + 68, + 76, + 214, + 149, + 132, + 153, + 177, + 192, + 187, + 43, + 253, + 46, + 131, + 188, + 103, + 114, + 150, + 135, + 217, + 16, + 141, + 185, + 28, + 40, + 43, + 107, + 145, + 199, + 63, + 105, + 243, + 237, + 213, + 239, + 125, + 68, + 78, + 188, + 208, + 43, + 27, + 102, + 154, + 89, + 82, + 186, + 33, + 133, + 131, + 179, + 94, + 204, + 62, + 26, + 72, + 219, + 14, + 209, + 79, + 237, + 217, + 248, + 41, + 201, + 46, + 4, + 216, + 13, + 15, + 96, + 169, + 37, + 67, + 235, + 16, + 135, + 150, + 97, + 201, + 31, + 158, + 55, + 178, + 91, + 225, + 176, + 28, + 84, + 40, + 212, + 102, + 242, + 49, + 221, + 71, + 136, + 150, + 250, + 125, + 110, + 64, + 40, + 47, + 9, + 188, + 130, + 209, + 78, + 170, + 47, + 88, + 71, + 34, + 161, + 127, + 47, + 7, + 165, + 4, + 84, + 16, + 212, + 22, + 150, + 123, + 29, + 160, + 21, + 42, + 82, + 207, + 9, + 114, + 72, + 157, + 215, + 97, + 24, + 183, + 251, + 204, + 194, + 85, + 57, + 211, + 139, + 236, + 173, + 41, + 1, + 179, + 2, + 62, + 115, + 110, + 47, + 77, + 135, + 49, + 142, + 184, + 215, + 99, + 181, + 22, + 211, + 98, + 120, + 105, + 31, + 184, + 160, + 178, + 59, + 44, + 178, + 156, + 103, + 176, + 133, + 80, + 1, + 125, + 142, + 2, + 66, + 38, + 60, + 195, + 120, + 63, + 243, + 216, + 139, + 140, + 120, + 153, + 129, + 247, + 118, + 0, + 162, + 101, + 231, + 38, + 44, + 162, + 67, + 212, + 22, + 180, + 173, + 59, + 214, + 225, + 207, + 38, + 83, + 98, + 222, + 35, + 52, + 78, + 60, + 143, + 48, + 216, + 251, + 255, + 86, + 157, + 43, + 104, + 145, + 202, + 133, + 115, + 5, + 172, + 108, + 2, + 105, + 131, + 199, + 195, + 15, + 115, + 141, + 34, + 218, + 236, + 188, + 21, + 4, + 188, + 143, + 89, + 187, + 128, + 109, + 11, + 60, + 126, + 136, + 191, + 247, + 105, + 39, + 207, + 253, + 248, + 10, + 122, + 206, + 36, + 205, + 211, + 171, + 34, + 163, + 85, + 152, + 137, + 46, + 96, + 132, + 214, + 117, + 145, + 250, + 180, + 38, + 127, + 58, + 234, + 148, + 147, + 127, + 12, + 249, + 48, + 24, + 225, + 124, + 237, + 15, + 208, + 103, + 79, + 244, + 14, + 38, + 87, + 89, + 71, + 159, + 54, + 43, + 171, + 11, + 213, + 69, + 143, + 65, + 19, + 78, + 245, + 38, + 102, + 149, + 203, + 104, + 164, + 139, + 66, + 218, + 32, + 90, + 67, + 40, + 152, + 167, + 108, + 224, + 4, + 162, + 166, + 9, + 181, + 70, + 128, + 30, + 187, + 90, + 249, + 9, + 235, + 251, + 180, + 80, + 70, + 16, + 199, + 185, + 83, + 236, + 120, + 131, + 84, + 137, + 246, + 197, + 228, + 218, + 31, + 47, + 71, + 202, + 207, + 2, + 142, + 130, + 100, + 128, + 179, + 90, + 21, + 133, + 232, + 174, + 229, + 221, + 182, + 105, + 213, + 153, + 202, + 66, + 117, + 133, + 2, + 176, + 94, + 49, + 254, + 203, + 120, + 241, + 91, + 43, + 17, + 18, + 187, + 129, + 9, + 3, + 221, + 203, + 202, + 163, + 42, + 156, + 246, + 217, + 10, + 12, + 19, + 244, + 10, + 211, + 73, + 111, + 22, + 128, + 132, + 1, + 23, + 58, + 137, + 158, + 85, + 87, + 10, + 85, + 139, + 74, + 215, + 174, + 237, + 194, + 181, + 252, + 171, + 224, + 169, + 152, + 226, + 229, + 53, + 76, + 143, + 106, + 19, + 131, + 39, + 129, + 21, + 58, + 33, + 118, + 122, + 13, + 23, + 177, + 97, + 51, + 26, + 237, + 228, + 165, + 163, + 212, + 146, + 249, + 213, + 69, + 156, + 105, + 208, + 246, + 98, + 221, + 154, + 244, + 154, + 33, + 249, + 217, + 25, + 79, + 8, + 93, + 171, + 232, + 37, + 143, + 95, + 225, + 25, + 116, + 84, + 7, + 253, + 18, + 97, + 80, + 248, + 243, + 42, + 48, + 93, + 118, + 72, + 3, + 99, + 169, + 236, + 216, + 17, + 64, + 62, + 71, + 229, + 209, + 249, + 250, + 43, + 113, + 189, + 98, + 8, + 227, + 47, + 179, + 168, + 213, + 204, + 99, + 178, + 23, + 216, + 141, + 4, + 157, + 89, + 15, + 48, + 83, + 230, + 172, + 170, + 234, + 140, + 153, + 252, + 16, + 18, + 28, + 91, + 183, + 76, + 111, + 40, + 132, + 112, + 159, + 14, + 136, + 197, + 53, + 197, + 240, + 56, + 244, + 102, + 167, + 164, + 197, + 57, + 98, + 117, + 72, + 65, + 56, + 142, + 28, + 179, + 139, + 216, + 0, + 105, + 28, + 235, + 35, + 107, + 131, + 13, + 49, + 198, + 174, + 206, + 86, + 5, + 210, + 217, + 95, + 169, + 71, + 44, + 37, + 135, + 117, + 33, + 147, + 146, + 57, + 255, + 149, + 125, + 79, + 47, + 61, + 27, + 186, + 161, + 134, + 73, + 144, + 86, + 45, + 255, + 99, + 169, + 180, + 218, + 81, + 184, + 110, + 62, + 67, + 47, + 163, + 216, + 66, + 22, + 234, + 102, + 140, + 53, + 220, + 237, + 188, + 177, + 171, + 38, + 218, + 47, + 99, + 101, + 253, + 174, + 52, + 166, + 241, + 176, + 190, + 163, + 153, + 51, + 65, + 34, + 60, + 73, + 223, + 215, + 177, + 208, + 118, + 139, + 185, + 70, + 250, + 86, + 233, + 67, + 57, + 33, + 124, + 34, + 68, + 49, + 119, + 81, + 118, + 75, + 187, + 186, + 33, + 60, + 52, + 121, + 83, + 188, + 26, + 160, + 63, + 214, + 105, + 139, + 124, + 227, + 40, + 75, + 58, + 186, + 103, + 129, + 189, + 69, + 74, + 197, + 77, + 17, + 209, + 97, + 236, + 94, + 174, + 112, + 212, + 186, + 9, + 243, + 224, + 226, + 69, + 54, + 235, + 90, + 189, + 8, + 62, + 247, + 140, + 170, + 43, + 69, + 97, + 46, + 104, + 110, + 147, + 224, + 47, + 110, + 91, + 116, + 54, + 6, + 98, + 79, + 180, + 198, + 120, + 30, + 227, + 123, + 24, + 247, + 218, + 226, + 158, + 97, + 42, + 197, + 245, + 34, + 197, + 58, + 87, + 198, + 73, + 110, + 37, + 56, + 99, + 114, + 170, + 254, + 171, + 66, + 27, + 184, + 73, + 162, + 73, + 28, + 93, + 105, + 88, + 216, + 10, + 88, + 92, + 227, + 208, + 47, + 206, + 229, + 176, + 201, + 94, + 149, + 21, + 26, + 25, + 70, + 191, + 76, + 238, + 211, + 49, + 121, + 211, + 172, + 247, + 224, + 26, + 0, + 64, + 91, + 95, + 70, + 138, + 145, + 251, + 154, + 134, + 140, + 5, + 23, + 113, + 151, + 189, + 214, + 59, + 95, + 69, + 125, + 131, + 253, + 35, + 253, + 193, + 156, + 220, + 157, + 244, + 123, + 189, + 34, + 166, + 215, + 179, + 159, + 176, + 95, + 244, + 54, + 48, + 182, + 185, + 0, + 199, + 116, + 188, + 22, + 183, + 108, + 182, + 228, + 79, + 179, + 206, + 254, + 246, + 17, + 235, + 67, + 42, + 235, + 245, + 14, + 87, + 179, + 170, + 90, + 192, + 0, + 0, + 124, + 203, + 111, + 17, + 93, + 42, + 133, + 158, + 252, + 32, + 102, + 9, + 223, + 147, + 232, + 189, + 39, + 4, + 2, + 73, + 178, + 110, + 137, + 169, + 254, + 114, + 217, + 181, + 0, + 58, + 217, + 199, + 205, + 64, + 14, + 67, + 57, + 17, + 190, + 168, + 194, + 191, + 17, + 27, + 49, + 43, + 97, + 240, + 95, + 201, + 223, + 194, + 215, + 221, + 238, + 98, + 193, + 200, + 214, + 67, + 96, + 171, + 120, + 7, + 99, + 8, + 182, + 58, + 65, + 66, + 210, + 171, + 210, + 155, + 78, + 180, + 84, + 146, + 185, + 130, + 196, + 1, + 255, + 154, + 230, + 218, + 165, + 123, + 43, + 115, + 41, + 93, + 87, + 45, + 249, + 188, + 66, + 89, + 208, + 138, + 1, + 129, + 22, + 31, + 81, + 245, + 65, + 218, + 10, + 25, + 191, + 22, + 244, + 124, + 212, + 188, + 96, + 103, + 105, + 54, + 189, + 170, + 254, + 17, + 153, + 13, + 43, + 107, + 50, + 34, + 239, + 220, + 77, + 76, + 177, + 82, + 35, + 253, + 57, + 208, + 139, + 109, + 202, + 8, + 159, + 6, + 217, + 131, + 136, + 40, + 235, + 157, + 133, + 63, + 71, + 41, + 182, + 10, + 165, + 38, + 133, + 248, + 130, + 139, + 200, + 203, + 51, + 12, + 222, + 129, + 20, + 8, + 231, + 232, + 227, + 219, + 90, + 99, + 108, + 5, + 89, + 96, + 94, + 68, + 169, + 171, + 101, + 10, + 98, + 201, + 99, + 243, + 106, + 158, + 161, + 153, + 15, + 171, + 44, + 88, + 154, + 79, + 93, + 5, + 142, + 154, + 171, + 32, + 5, + 45, + 142, + 32, + 66, + 144, + 36, + 67, + 155, + 196, + 220, + 11, + 11, + 54, + 1, + 182, + 220, + 247, + 6, + 63, + 49, + 204, + 70, + 65, + 95, + 238, + 95, + 103, + 246, + 66, + 15, + 66, + 63, + 107, + 80, + 166, + 148, + 5, + 37, + 189, + 178, + 182, + 110, + 240, + 203, + 239, + 72, + 180, + 15, + 205, + 189, + 216, + 159, + 122, + 163, + 32, + 221, + 213, + 66, + 164, + 180, + 219, + 165, + 228, + 42, + 142, + 190, + 215, + 61, + 184, + 24, + 65, + 62, + 127, + 236, + 151, + 234, + 33, + 145, + 3, + 245, + 24, + 73, + 103, + 141, + 31, + 32, + 20, + 228, + 213, + 69, + 249, + 14, + 164, + 133, + 101, + 137, + 19, + 61, + 147, + 204, + 99, + 8, + 162, + 252, + 231, + 112, + 71, + 159, + 6, + 122, + 163, + 159, + 30, + 218, + 36, + 63, + 4, + 182, + 107, + 164, + 133, + 36, + 248, + 234, + 40, + 73, + 77, + 196, + 11, + 137, + 161, + 239, + 232, + 123, + 197, + 88, + 123, + 28, + 101, + 247, + 230, + 239, + 218, + 252, + 190, + 153, + 207, + 112, + 118, + 173, + 228, + 61, + 213, + 103, + 245, + 27, + 209, + 99, + 104, + 124, + 121, + 52, + 14, + 181, + 97, + 138, + 234, + 125, + 11, + 205, + 82, + 71, + 115, + 47, + 24, + 8, + 136, + 153, + 28, + 206, + 97, + 255, + 69, + 4, + 193, + 33, + 210, + 47, + 115, + 206, + 45, + 198, + 109, + 17, + 235, + 171, + 222, + 183, + 149, + 65, + 193, + 33, + 154, + 150, + 40, + 132, + 116, + 243, + 63, + 23, + 3, + 21, + 169, + 240, + 47, + 72, + 234, + 96, + 67, + 214, + 202, + 47, + 40, + 54, + 215, + 98, + 244, + 12, + 131, + 133, + 249, + 110, + 11, + 42, + 36, + 85, + 34, + 8, + 155, + 19, + 98, + 52, + 25, + 206, + 86, + 198, + 65, + 182, + 144, + 49, + 69, + 204, + 126, + 97, + 102, + 111, + 177, + 238, + 126, + 79, + 127, + 63, + 11, + 4, + 61, + 11, + 26, + 24, + 98, + 157, + 27, + 62, + 101, + 78, + 22, + 42, + 23, + 56, + 137, + 37, + 134, + 80, + 56, + 134, + 67, + 27, + 197, + 121, + 232, + 55, + 53, + 115, + 37, + 122, + 23, + 93, + 83, + 104, + 109, + 243, + 228, + 18, + 181, + 100, + 91, + 236, + 22, + 26, + 204, + 254, + 164, + 131, + 197, + 92, + 116, + 58, + 182, + 126, + 213, + 67, + 225, + 77, + 146, + 18, + 189, + 6, + 150, + 144, + 49, + 128, + 164, + 112, + 188, + 244, + 77, + 170, + 4, + 162, + 232, + 71, + 14, + 156, + 83, + 155, + 31, + 34, + 65, + 192, + 63, + 255, + 12, + 68, + 163, + 255, + 53, + 71, + 95, + 119, + 69, + 9, + 78, + 49, + 80, + 65, + 195, + 220, + 129, + 236, + 73, + 9, + 90, + 82, + 198, + 19, + 109, + 110, + 51, + 8, + 149, + 106, + 23, + 47, + 27, + 231, + 128, + 248, + 59, + 182, + 78, + 116, + 247, + 4, + 242, + 65, + 34, + 88, + 95, + 3, + 197, + 101, + 107, + 242, + 254, + 157, + 216, + 255, + 198, + 232, + 164, + 57, + 43, + 140, + 241, + 194, + 249, + 239, + 141, + 27, + 216, + 220, + 191, + 232, + 129, + 11, + 126, + 47, + 41, + 210, + 107, + 183, + 16, + 31, + 81, + 191, + 180, + 80, + 173, + 128, + 43, + 13, + 173, + 71, + 229, + 57, + 249, + 126, + 110, + 144, + 1, + 62, + 1, + 46, + 190, + 137, + 131, + 1, + 12, + 189, + 230, + 30, + 181, + 160, + 141, + 10, + 111, + 88, + 181, + 73, + 223, + 103, + 199, + 46, + 21, + 76, + 129, + 91, + 23, + 54, + 242, + 182, + 25, + 227, + 80, + 1, + 206, + 134, + 145, + 94, + 76, + 57, + 162, + 39, + 90, + 84, + 68, + 163, + 50, + 80, + 150, + 69, + 45, + 65, + 219, + 139, + 117, + 48, + 12, + 10, + 35, + 97, + 70, + 116, + 65, + 182, + 190, + 148, + 5, + 76, + 92, + 230, + 191, + 243, + 219, + 229, + 203, + 166, + 165, + 179, + 242, + 130, + 232, + 68, + 135, + 48, + 126, + 135, + 105, + 30, + 182, + 56, + 209, + 164, + 193, + 87, + 252, + 141, + 144, + 163, + 201, + 142, + 126, + 131, + 196, + 126, + 28, + 198, + 221, + 209, + 158, + 242, + 100, + 3, + 19, + 3, + 29, + 50, + 150, + 79, + 151, + 51, + 223, + 25, + 51, + 37, + 8, + 162, + 70, + 146, + 27, + 86, + 232, + 211, + 171, + 33, + 28, + 49, + 183, + 224, + 47, + 124, + 126, + 31, + 31, + 114, + 132, + 158, + 13, + 47, + 241, + 26, + 39, + 39, + 3, + 24, + 120, + 1, + 224, + 83, + 144, + 131, + 54, + 47, + 244, + 100, + 64, + 251, + 231, + 157, + 126, + 185, + 191, + 169, + 136, + 149, + 104, + 55, + 152, + 95, + 28, + 60, + 30, + 77, + 8, + 31, + 143, + 170, + 54, + 78, + 219, + 57, + 111, + 60, + 106, + 38, + 210, + 155, + 93, + 93, + 246, + 52, + 113, + 130, + 114, + 209, + 52, + 33, + 255, + 55, + 71, + 17, + 153, + 212, + 243, + 138, + 233, + 54, + 12, + 248, + 29, + 245, + 123, + 212, + 48, + 121, + 79, + 7, + 60, + 155, + 234, + 143, + 133, + 215, + 209, + 159, + 20, + 123, + 35, + 16, + 74, + 226, + 14, + 26, + 193, + 143, + 240, + 57, + 31, + 1, + 153, + 231, + 91, + 187, + 31, + 153, + 25, + 207, + 254, + 134, + 27, + 190, + 222, + 217, + 178, + 74, + 234, + 24, + 42, + 249, + 77, + 185, + 113, + 159, + 200, + 54, + 142, + 112, + 209, + 18, + 112, + 12, + 151, + 5, + 181, + 226, + 56, + 137, + 70, + 200, + 129, + 61, + 164, + 249, + 53, + 211, + 169, + 14, + 30, + 219, + 169, + 108, + 97, + 218, + 52, + 64, + 70, + 115, + 56, + 145, + 79, + 92, + 107, + 48, + 33, + 249, + 253, + 64, + 255, + 215, + 51, + 89, + 172, + 124, + 215, + 11, + 243, + 169, + 67, + 170, + 137, + 209, + 121, + 251, + 201, + 59, + 21, + 199, + 240, + 147, + 205, + 201, + 141, + 199, + 44, + 26, + 117, + 201, + 130, + 37, + 110, + 20, + 27, + 68, + 193, + 212, + 164, + 167, + 133, + 248, + 148, + 225, + 236, + 161, + 232, + 233, + 243, + 155, + 219, + 103, + 12, + 252, + 119, + 149, + 247, + 88, + 203, + 18, + 206, + 188, + 66, + 34, + 105, + 187, + 238, + 1, + 23, + 250, + 65, + 174, + 5, + 191, + 59, + 92, + 229, + 57, + 132, + 164, + 168, + 39, + 81, + 84, + 118, + 162, + 169, + 36, + 3, + 237, + 91, + 49, + 159, + 149, + 14, + 160, + 227, + 103, + 75, + 236, + 47, + 198, + 201, + 141, + 134, + 21, + 28, + 41, + 3, + 90, + 77, + 53, + 6, + 233, + 124, + 130, + 5, + 218, + 185, + 9, + 222, + 231, + 109, + 106, + 241, + 123, + 1, + 247, + 0, + 231, + 17, + 134, + 103, + 170, + 115, + 74, + 149, + 73, + 161, + 17, + 25, + 168, + 146, + 12, + 69, + 158, + 28, + 232, + 114, + 100, + 88, + 162, + 239, + 63, + 158, + 60, + 111, + 98, + 165, + 94, + 62, + 142, + 210, + 147, + 191, + 121, + 82, + 73, + 231, + 59, + 81, + 205, + 58, + 47, + 85, + 128, + 169, + 16, + 224, + 209, + 161, + 170, + 247, + 206, + 37, + 151, + 129, + 47, + 126, + 201, + 24, + 44, + 249, + 239, + 217, + 160, + 172, + 127, + 86, + 147, + 154, + 105, + 105, + 234, + 24, + 133, + 67, + 131, + 105, + 233, + 184, + 197, + 194, + 84, + 11, + 160, + 249, + 227, + 115, + 31, + 8, + 167, + 91, + 34, + 245, + 143, + 252, + 99, + 96, + 152, + 106, + 253, + 38, + 185, + 41, + 97, + 246, + 164, + 128, + 77, + 192, + 213, + 64, + 6, + 232, + 234, + 228, + 52, + 55, + 253, + 164, + 97, + 72, + 213, + 26, + 45, + 144, + 214, + 30, + 221, + 117, + 227, + 115, + 45, + 200, + 5, + 54, + 148, + 31, + 68, + 111, + 241, + 157, + 112, + 173, + 42, + 47, + 47, + 29, + 43, + 90, + 182, + 45, + 115, + 85, + 168, + 225, + 81, + 5, + 25, + 42, + 230, + 135, + 234, + 200, + 249, + 75, + 143, + 195, + 190, + 20, + 86, + 25, + 50, + 71, + 144, + 24, + 194, + 2, + 76, + 236, + 226, + 42, + 226, + 192, + 90, + 234, + 233, + 13, + 33, + 73, + 147, + 155, + 252, + 147, + 135, + 66, + 30, + 249, + 169, + 167, + 76, + 88, + 251, + 224, + 138, + 251, + 29, + 77, + 126, + 174, + 164, + 174, + 213, + 94, + 158, + 122, + 80, + 61, + 190, + 214, + 187, + 250, + 111, + 228, + 46, + 199, + 28, + 218, + 77, + 105, + 4, + 148, + 28, + 28, + 51, + 180, + 157, + 179, + 174, + 158, + 240, + 121, + 31, + 42, + 48, + 217, + 76, + 43, + 114, + 82, + 108, + 85, + 2, + 113, + 181, + 249, + 244, + 226, + 112, + 211, + 245, + 225, + 205, + 210, + 131, + 107, + 234, + 13, + 232, + 79, + 34, + 253, + 108, + 60, + 228, + 183, + 86, + 125, + 24, + 136, + 48, + 72, + 75, + 115, + 93, + 192, + 188, + 168, + 220, + 180, + 255, + 108, + 14, + 15, + 4, + 166, + 135, + 211, + 180, + 187, + 131, + 250, + 246, + 107, + 84, + 249, + 133, + 28, + 185, + 131, + 220, + 51, + 115, + 89, + 161, + 4, + 161, + 215, + 117, + 18, + 197, + 193, + 109, + 245, + 168, + 234, + 149, + 1, + 0, + 177, + 159, + 128, + 156, + 16, + 160, + 3, + 245, + 68, + 185, + 109, + 83, + 191, + 203, + 156, + 30, + 174, + 160, + 91, + 210, + 167, + 40, + 248, + 242, + 138, + 77, + 151, + 246, + 15, + 210, + 142, + 51, + 213, + 215, + 134, + 113, + 177, + 79, + 84, + 52, + 88, + 240, + 216, + 228, + 120, + 154, + 58, + 75, + 233, + 205, + 8, + 87, + 109, + 147, + 140, + 149, + 115, + 115, + 146, + 45, + 109, + 102, + 119, + 64, + 40, + 27, + 69, + 218, + 131, + 27, + 186, + 168, + 108, + 237, + 249, + 190, + 42, + 16, + 188, + 49, + 179, + 155, + 26, + 194, + 149, + 105, + 74, + 140, + 229, + 5, + 141, + 121, + 224, + 204, + 35, + 143, + 244, + 130, + 223, + 186, + 169, + 47, + 142, + 46, + 77, + 164, + 140, + 140, + 30, + 21, + 33, + 50, + 3, + 126, + 79, + 87, + 24, + 57, + 47, + 203, + 107, + 150, + 221, + 221, + 227, + 132, + 90, + 167, + 129, + 150, + 5, + 7, + 222, + 96, + 193, + 107, + 20, + 166, + 18, + 55, + 149, + 29, + 233, + 99, + 62, + 173, + 117, + 187, + 106, + 59, + 250, + 200, + 145, + 233, + 122, + 39, + 32, + 127, + 163, + 255, + 191, + 149, + 158, + 60, + 80, + 203, + 242, + 53, + 216, + 53, + 19, + 128, + 187, + 56, + 38, + 46, + 138, + 5, + 103, + 238, + 71, + 125, + 163, + 251, + 222, + 189, + 73, + 98, + 12, + 232, + 172, + 234, + 65, + 204, + 14, + 252, + 77, + 158, + 138, + 248, + 195, + 136, + 72, + 30, + 62, + 61, + 5, + 35, + 242, + 47, + 218, + 52, + 117, + 52, + 56, + 28, + 132, + 45, + 25, + 136, + 166, + 138, + 233, + 222, + 253, + 93, + 89, + 29, + 65, + 98, + 90, + 4, + 80, + 2, + 153, + 135, + 194, + 140, + 154, + 96, + 226, + 197, + 168, + 191, + 137, + 230, + 53, + 35, + 211, + 0, + 191, + 185, + 90, + 114, + 206, + 246, + 95, + 182, + 17, + 41, + 120, + 137, + 93, + 226, + 114, + 232, + 161, + 24, + 228, + 234, + 48, + 101, + 206, + 241, + 198, + 85, + 234, + 249, + 102, + 196, + 144, + 112, + 98, + 50, + 195, + 105, + 18, + 17, + 98, + 66, + 217, + 165, + 250, + 137, + 106, + 94, + 93, + 118, + 212, + 53, + 103, + 221, + 169, + 3, + 248, + 165, + 165, + 108, + 109, + 37, + 162, + 157, + 53, + 7, + 79, + 109, + 55, + 232, + 149, + 25, + 192, + 33, + 241, + 148, + 86, + 208, + 49, + 180, + 202, + 24, + 201, + 205, + 234, + 135, + 149, + 48, + 123, + 8, + 115, + 24, + 249, + 50, + 106, + 128, + 81, + 90, + 156, + 216, + 184, + 190, + 94, + 202, + 76, + 32, + 217, + 141, + 89, + 42, + 217, + 137, + 249, + 80, + 163, + 246, + 156, + 179, + 47, + 70, + 188, + 90, + 14, + 45, + 105, + 9, + 52, + 65, + 81, + 43, + 223, + 30, + 88, + 8, + 220, + 185, + 163, + 158, + 46, + 51, + 55, + 137, + 140, + 190, + 6, + 166, + 253, + 102, + 20, + 183, + 238, + 4, + 39, + 217, + 179, + 173, + 3, + 1, + 156, + 152, + 189, + 10, + 126, + 141, + 91, + 174, + 184, + 62, + 27, + 91, + 125, + 178, + 93, + 72, + 173, + 14, + 2, + 188, + 74, + 100, + 83, + 170, + 255, + 39, + 145, + 227, + 75, + 39, + 220, + 69, + 120, + 152, + 16, + 240, + 217, + 34, + 38, + 187, + 201, + 212, + 160, + 125, + 21, + 13, + 69, + 83, + 218, + 8, + 96, + 75, + 10, + 75, + 33, + 224, + 211, + 25, + 223, + 169, + 113, + 84, + 30, + 17, + 113, + 100, + 168, + 41, + 234, + 79, + 124, + 45, + 100, + 196, + 111, + 197, + 177, + 173, + 113, + 119, + 217, + 25, + 210, + 32, + 163, + 117, + 211, + 167, + 20, + 88, + 173, + 128, + 38, + 87, + 132, + 250, + 117, + 198, + 7, + 150, + 34, + 212, + 170, + 31, + 107, + 133, + 202, + 230, + 15, + 21, + 184, + 35, + 19, + 66, + 131, + 164, + 183, + 180, + 207, + 144, + 175, + 55, + 152, + 233, + 122, + 28, + 8, + 224, + 42, + 184, + 74, + 217, + 36, + 173, + 123, + 173, + 89, + 156, + 115, + 104, + 101, + 187, + 200, + 179, + 242, + 95, + 3, + 125, + 163, + 23, + 238, + 61, + 109, + 8, + 15, + 132, + 100, + 139, + 44, + 54, + 222, + 93, + 125, + 177, + 183, + 228, + 52, + 87, + 238, + 152, + 73, + 148, + 72, + 120, + 60, + 87, + 103, + 106, + 128, + 236, + 16, + 198, + 185, + 133, + 255, + 4, + 162, + 36, + 71, + 35, + 33, + 175, + 223, + 248, + 185, + 250, + 125, + 26, + 201, + 146, + 146, + 35, + 66, + 160, + 164, + 233, + 173, + 126, + 51, + 196, + 226, + 14, + 72, + 235, + 236, + 35, + 197, + 42, + 10, + 43, + 13, + 112, + 111, + 206, + 157, + 175, + 115, + 215, + 205, + 155, + 227, + 203, + 14, + 193, + 40, + 5, + 123, + 229, + 189, + 17, + 94, + 103, + 196, + 141, + 239, + 31, + 51, + 247, + 182, + 76, + 128, + 158, + 203, + 60, + 130, + 20, + 141, + 67, + 168, + 174, + 170, + 43, + 87, + 194, + 4, + 84, + 241, + 118, + 186, + 34, + 231, + 206, + 5, + 113, + 54, + 181, + 41, + 210, + 242, + 3, + 13, + 28, + 147, + 216, + 170, + 145, + 246, + 25, + 96, + 83, + 232, + 36, + 113, + 165, + 40, + 65, + 192, + 203, + 39, + 42, + 132, + 142, + 142, + 68, + 189, + 120, + 149, + 26, + 100, + 179, + 67, + 22, + 102, + 8, + 241, + 34, + 190, + 50, + 220, + 253, + 6, + 60, + 93, + 7, + 209, + 106, + 43, + 180, + 176, + 57, + 8, + 203, + 141, + 199, + 191, + 232, + 236, + 169, + 176, + 171, + 59, + 119, + 106, + 82, + 32, + 115, + 32, + 109, + 86, + 233, + 41, + 185, + 27, + 71, + 104, + 84, + 145, + 29, + 156, + 29, + 164, + 223, + 15, + 3, + 183, + 10, + 31, + 78, + 243, + 17, + 100, + 1, + 102, + 74, + 141, + 52, + 38, + 28, + 193, + 241, + 13, + 4, + 143, + 250, + 188, + 159, + 6, + 242, + 88, + 79, + 31, + 235, + 166, + 245, + 155, + 242, + 65, + 106, + 154, + 225, + 253, + 151, + 230, + 79, + 70, + 117, + 203, + 1, + 223, + 52, + 222, + 231, + 36, + 252, + 77, + 95, + 153, + 16, + 239, + 157, + 104, + 159, + 123, + 89, + 129, + 236, + 251, + 60, + 152, + 84, + 155, + 36, + 6, + 235, + 6, + 154, + 202, + 152, + 205, + 202, + 241, + 13, + 113, + 52, + 125, + 186, + 237, + 187, + 165, + 47, + 170, + 5, + 228, + 8, + 110, + 91, + 87, + 51, + 192, + 127, + 164, + 147, + 67, + 205, + 147, + 12, + 56, + 35, + 162, + 189, + 53, + 76, + 213, + 20, + 247, + 56, + 115, + 19, + 64, + 70, + 71, + 178, + 13, + 7, + 168, + 100, + 89, + 245, + 165, + 232, + 100, + 15, + 236, + 243, + 150, + 69, + 43, + 49, + 163, + 238, + 107, + 210, + 251, + 62, + 75, + 17, + 231, + 197, + 16, + 140, + 100, + 175, + 4, + 143, + 228, + 153, + 159, + 241, + 22, + 81, + 45, + 199, + 203, + 128, + 147, + 93, + 197, + 143, + 208, + 21, + 108, + 53, + 146, + 158, + 214, + 246, + 76, + 85, + 87, + 239, + 172, + 28, + 24, + 37, + 234, + 180, + 2, + 160, + 188, + 48, + 42, + 202, + 78, + 125, + 141, + 63, + 142, + 87, + 188, + 51, + 45, + 131, + 218, + 210, + 39, + 25, + 110, + 119, + 165, + 95, + 82, + 166, + 204, + 65, + 44, + 98, + 211, + 113, + 241, + 236, + 237, + 134, + 173, + 99, + 79, + 101, + 197, + 196, + 9, + 214, + 155, + 243, + 68, + 207, + 170, + 10, + 163, + 186, + 122, + 233, + 205, + 32, + 7, + 158, + 60, + 101, + 79, + 7, + 135, + 29, + 66, + 178, + 37, + 54, + 4, + 43, + 47, + 38, + 110, + 114, + 113, + 118, + 161, + 13, + 254, + 18, + 129, + 6, + 239, + 61, + 245, + 203, + 208, + 1, + 208, + 105, + 224, + 239, + 222, + 62, + 219, + 83, + 160, + 7, + 40, + 115, + 247, + 99, + 138, + 32, + 56, + 73, + 88, + 8, + 49, + 179, + 42, + 142, + 130, + 6, + 138, + 219, + 78, + 209, + 187, + 111, + 48, + 250, + 181, + 237, + 15, + 19, + 179, + 139, + 47, + 174, + 23, + 129, + 133, + 241, + 96, + 162, + 125, + 82, + 213, + 135, + 63, + 227, + 170, + 34, + 161, + 73, + 83, + 35, + 34, + 156, + 87, + 87, + 89, + 134, + 25, + 104, + 9, + 64, + 54, + 188, + 142, + 209, + 223, + 31, + 176, + 1, + 11, + 71, + 9, + 163, + 225, + 41, + 61, + 88, + 248, + 112, + 139, + 243, + 186, + 207, + 96, + 243, + 2, + 104, + 186, + 92, + 149, + 205, + 144, + 8, + 249, + 93, + 4, + 176, + 155, + 205, + 34, + 222, + 217, + 56, + 228, + 73, + 41, + 192, + 84, + 188, + 222, + 149, + 231, + 120, + 202, + 196, + 22, + 164, + 64, + 99, + 14, + 93, + 223, + 81, + 16, + 233, + 174, + 179, + 152, + 252, + 167, + 24, + 49, + 214, + 229, + 195, + 2, + 136, + 143, + 229, + 41, + 209, + 139, + 241, + 205, + 210, + 199, + 23, + 38, + 18, + 11, + 0, + 224, + 181, + 239, + 122, + 237, + 153, + 4, + 99, + 11, + 121, + 231, + 208, + 85, + 168, + 233, + 113, + 38, + 43, + 174, + 212, + 48, + 86, + 44, + 153, + 51, + 102, + 205, + 54, + 36, + 224, + 14, + 93, + 120, + 132, + 92, + 166, + 219, + 1, + 240, + 156, + 143, + 196, + 48, + 213, + 71, + 5, + 124, + 153, + 127, + 175, + 9, + 16, + 146, + 119, + 98, + 184, + 178, + 147, + 145, + 177, + 31, + 16, + 146, + 88, + 49, + 89, + 251, + 72, + 62, + 229, + 137, + 71, + 107, + 172, + 73, + 162, + 92, + 47, + 7, + 214, + 105, + 142, + 231, + 120, + 231, + 178, + 182, + 78, + 164, + 239, + 217, + 189, + 20, + 192, + 103, + 81, + 154, + 47, + 245, + 98, + 32, + 153, + 106, + 161, + 230, + 18, + 63, + 175, + 90, + 94, + 43, + 156, + 4, + 8, + 195, + 223, + 231, + 71, + 93, + 181, + 67, + 150, + 121, + 222, + 170, + 84, + 113, + 47, + 71, + 160, + 200, + 130, + 203, + 32, + 131, + 196, + 84, + 81, + 137, + 102, + 121, + 225, + 44, + 213, + 195, + 109, + 191, + 53, + 153, + 90, + 123, + 230, + 101, + 223, + 218, + 74, + 75, + 187, + 201, + 15, + 241, + 245, + 213, + 170, + 219, + 132, + 234, + 254, + 67, + 136, + 34, + 138, + 24, + 182, + 18, + 190, + 203, + 167, + 198, + 28, + 112, + 61, + 23, + 92, + 23, + 137, + 120, + 90, + 26, + 182, + 183, + 114, + 245, + 1, + 106, + 161, + 121, + 51, + 85, + 41, + 180, + 129, + 171, + 42, + 120, + 135, + 66, + 69, + 15, + 116, + 10, + 227, + 57, + 141, + 9, + 176, + 79, + 209, + 187, + 201, + 161, + 176, + 88, + 83, + 200, + 194, + 160, + 59, + 38, + 107, + 149, + 73, + 32, + 139, + 47, + 111, + 213, + 176, + 245, + 56, + 16, + 160, + 149, + 136, + 103, + 32, + 87, + 196, + 210, + 55, + 89, + 183, + 248, + 148, + 54, + 75, + 53, + 82, + 140, + 189, + 144, + 227, + 210, + 255, + 172, + 212, + 60, + 50, + 86, + 187, + 26, + 235, + 198, + 81, + 1, + 109, + 83, + 192, + 45, + 150, + 14, + 249, + 209, + 197, + 79, + 212, + 170, + 13, + 182, + 148, + 49, + 110, + 79, + 39, + 132, + 115, + 215, + 195, + 245, + 47, + 82, + 20, + 59, + 233, + 137, + 96, + 237, + 252, + 204, + 144, + 168, + 32, + 206, + 206, + 15, + 213, + 108, + 91, + 179, + 110, + 171, + 130, + 96, + 88, + 10, + 170, + 13, + 168, + 56, + 248, + 31, + 106, + 36, + 204, + 85, + 176, + 117, + 207, + 239, + 73, + 132, + 90, + 95, + 96, + 185, + 1, + 52, + 92, + 166, + 24, + 221, + 82, + 61, + 172, + 32, + 51, + 254, + 159, + 244, + 219, + 127, + 183, + 39, + 148, + 123, + 167, + 41, + 210, + 180, + 193, + 125, + 251, + 95, + 87, + 84, + 178, + 28, + 136, + 119, + 226, + 40, + 145, + 79, + 6, + 40, + 118, + 37, + 19, + 178, + 180, + 241, + 8, + 134, + 5, + 69, + 38, + 248, + 180, + 19, + 191, + 129, + 162, + 248, + 11, + 219, + 110, + 76, + 169, + 38, + 145, + 165, + 25, + 192, + 210, + 225, + 79, + 155, + 206, + 12, + 190, + 238, + 225, + 202, + 91, + 214, + 23, + 10, + 53, + 244, + 195, + 28, + 225, + 46, + 105, + 133, + 126, + 211, + 119, + 198, + 223, + 191, + 195, + 244, + 125, + 167, + 62, + 216, + 88, + 159, + 58, + 20, + 117, + 124, + 217, + 6, + 162, + 188, + 144, + 151, + 116, + 116, + 215, + 26, + 24, + 230, + 215, + 24, + 128, + 126, + 195, + 216, + 218, + 223, + 32, + 212, + 105, + 216, + 199, + 60, + 114, + 215, + 32, + 229, + 161, + 49, + 168, + 200, + 162, + 248, + 98, + 77, + 240, + 123, + 80, + 23, + 91, + 94, + 98, + 223, + 214, + 85, + 58, + 5, + 201, + 245, + 244, + 155, + 197, + 213, + 236, + 184, + 39, + 232, + 223, + 70, + 127, + 3, + 63, + 193, + 240, + 112, + 127, + 198, + 154, + 183, + 64, + 113, + 203, + 138, + 230, + 177, + 60, + 253, + 13, + 254, + 126, + 106, + 40, + 251, + 188, + 119, + 10, + 115, + 111, + 129, + 133, + 90, + 53, + 176, + 15, + 66, + 11, + 60, + 250, + 111, + 25, + 182, + 216, + 50, + 31, + 179, + 87, + 189, + 158, + 41, + 220, + 101, + 75, + 71, + 157, + 147, + 122, + 76, + 164, + 18, + 9, + 206, + 43, + 10, + 14, + 242, + 177, + 176, + 127, + 59, + 226, + 181, + 55, + 7, + 167, + 178, + 93, + 103, + 113, + 95, + 150, + 254, + 209, + 68, + 6, + 15, + 207, + 156, + 164, + 189, + 43, + 143, + 13, + 143, + 0, + 151, + 38, + 73, + 182, + 43, + 3, + 9, + 122, + 0, + 113, + 167, + 23, + 137, + 14, + 234, + 186, + 158, + 197, + 255, + 45, + 100, + 80, + 133, + 72, + 70, + 6, + 29, + 220, + 191, + 21, + 137, + 254, + 64, + 226, + 175, + 134, + 28, + 218, + 42, + 92, + 98, + 227, + 26, + 233, + 252, + 174, + 179, + 165, + 19, + 148, + 250, + 176, + 158, + 13, + 236, + 74, + 57, + 16, + 60, + 184, + 178, + 8, + 62, + 237, + 51, + 92, + 80, + 33, + 241, + 115, + 100, + 224, + 5, + 185, + 223, + 79, + 241, + 69, + 180, + 193, + 29, + 240, + 95, + 26, + 27, + 205, + 239, + 172, + 206, + 255, + 97, + 139, + 93, + 18, + 131, + 202, + 41, + 85, + 25, + 166, + 250, + 224, + 149, + 76, + 227, + 79, + 58, + 32, + 251, + 206, + 124, + 20, + 197, + 33, + 231, + 42, + 8, + 251, + 206, + 169, + 253, + 102, + 189, + 32, + 248, + 42, + 79, + 219, + 156, + 59, + 121, + 183, + 183, + 67, + 205, + 186, + 231, + 196, + 3, + 208, + 60, + 114, + 242, + 194, + 115, + 219, + 19, + 226, + 14, + 23, + 186, + 10, + 49, + 73, + 240, + 83, + 106, + 20, + 149, + 8, + 115, + 47, + 101, + 252, + 78, + 14, + 199, + 152, + 14, + 28, + 74, + 79, + 163, + 182, + 166, + 222, + 21, + 212, + 29, + 225, + 232, + 199, + 245, + 66, + 213, + 34, + 97, + 248, + 109, + 28, + 201, + 251, + 125, + 5, + 56, + 93, + 185, + 50, + 10, + 127, + 206, + 245, + 141, + 8, + 76, + 136, + 47, + 121, + 36, + 16, + 143, + 237, + 250, + 180, + 187, + 174, + 102, + 20, + 76, + 246, + 131, + 24, + 4, + 121, + 36, + 210, + 180, + 80, + 96, + 203, + 0, + 179, + 227, + 112, + 129, + 254, + 20, + 199, + 62, + 164, + 246, + 43, + 152, + 240, + 156, + 30, + 150, + 104, + 124, + 57, + 183, + 34, + 248, + 0, + 2, + 171, + 137, + 95, + 148, + 202, + 110, + 77, + 180, + 199, + 7, + 99, + 156, + 70, + 166, + 254, + 226, + 137, + 114, + 11, + 178, + 150, + 215, + 201, + 201, + 130, + 224, + 253, + 53, + 115, + 91, + 89, + 248, + 30, + 15, + 223, + 58, + 92, + 19, + 185, + 70, + 117, + 31, + 223, + 239, + 138, + 18, + 218, + 62, + 19, + 103, + 55, + 252, + 154, + 230, + 253, + 209, + 137, + 182, + 104, + 19, + 103, + 216, + 74, + 90, + 242, + 18, + 184, + 205, + 212, + 131, + 31, + 117, + 17, + 18, + 125, + 229, + 15, + 99, + 108, + 98, + 184, + 17, + 13, + 191, + 64, + 197, + 146, + 169, + 157, + 188, + 144, + 230, + 175, + 198, + 112, + 241, + 67, + 238, + 252, + 87, + 102, + 222, + 206, + 17, + 136, + 45, + 108, + 222, + 114, + 23, + 175, + 196, + 18, + 150, + 32, + 24, + 166, + 102, + 249, + 176, + 116, + 135, + 19, + 225, + 118, + 177, + 22, + 202, + 143, + 148, + 85, + 156, + 19, + 228, + 253, + 188, + 18, + 219, + 47, + 76, + 170, + 169, + 114, + 157, + 161, + 96, + 209, + 219, + 192, + 169, + 152, + 158, + 23, + 91, + 59, + 51, + 222, + 102, + 11, + 180, + 63, + 8, + 75, + 0, + 159, + 221, + 91, + 141, + 227, + 205, + 186, + 224, + 16, + 21, + 128, + 193, + 132, + 131, + 196, + 85, + 117, + 214, + 246, + 25, + 234, + 201, + 56, + 102, + 82, + 76, + 38, + 84, + 23, + 117, + 186, + 70, + 209, + 146, + 69, + 40, + 4, + 95, + 23, + 18, + 191, + 233, + 144, + 200, + 131, + 34, + 146, + 132, + 145, + 164, + 235, + 111, + 67, + 85, + 36, + 139, + 162, + 176, + 109, + 52, + 234, + 10, + 78, + 25, + 168, + 75, + 38, + 116, + 73, + 123, + 226, + 198, + 119, + 83, + 36, + 210, + 66, + 255, + 225, + 196, + 112, + 4, + 174, + 46, + 160, + 175, + 104, + 31, + 157, + 5, + 97, + 70, + 132, + 240, + 210, + 113, + 109, + 53, + 61, + 96, + 83, + 7, + 84, + 20, + 186, + 169, + 76, + 163, + 173, + 43, + 149, + 120, + 46, + 136, + 123, + 24, + 249, + 155, + 21, + 182, + 248, + 147, + 4, + 87, + 56, + 156, + 67, + 73, + 163, + 222, + 159, + 178, + 124, + 11, + 189, + 49, + 49, + 16, + 122, + 70, + 10, + 187, + 229, + 137, + 107, + 175, + 218, + 20, + 27, + 6, + 14, + 251, + 213, + 150, + 82, + 44, + 167, + 163, + 107, + 164, + 142, + 59, + 173, + 139, + 54, + 72, + 11, + 31, + 167, + 209, + 43, + 115, + 76, + 164, + 234, + 155, + 220, + 19, + 86, + 90, + 176, + 45, + 150, + 136, + 74, + 93, + 109, + 131, + 62, + 44, + 233, + 92, + 182, + 82, + 137, + 59, + 25, + 39, + 84, + 230, + 15, + 33, + 244, + 138, + 111, + 224, + 20, + 28, + 179, + 36, + 94, + 217, + 69, + 36, + 110, + 146, + 215, + 62, + 43, + 252, + 131, + 150, + 174, + 68, + 157, + 75, + 182, + 221, + 18, + 156, + 92, + 203, + 104, + 171, + 39, + 38, + 78, + 157, + 96, + 153, + 23, + 211, + 43, + 130, + 245, + 77, + 6, + 75, + 148, + 184, + 77, + 223, + 188, + 96, + 168, + 35, + 112, + 166, + 231, + 37, + 73, + 67, + 123, + 105, + 180, + 163, + 252, + 23, + 150, + 137, + 83, + 141, + 161, + 21, + 28, + 143, + 78, + 113, + 54, + 170, + 100, + 200, + 99, + 56, + 165, + 144, + 138, + 193, + 234, + 15, + 55, + 46, + 177, + 216, + 250, + 51, + 228, + 224, + 196, + 138, + 69, + 98, + 149, + 199, + 186, + 164, + 50, + 65, + 145, + 88, + 247, + 202, + 7, + 112, + 113, + 48, + 37, + 7, + 121, + 116, + 157, + 129, + 239, + 39, + 155, + 71, + 42, + 230, + 30, + 137, + 115, + 144, + 24, + 19, + 102, + 132, + 219, + 72, + 234, + 128, + 62, + 200, + 27, + 196, + 104, + 8, + 80, + 230, + 18, + 113, + 17, + 176, + 16, + 76, + 118, + 230, + 236, + 4, + 55, + 171, + 118, + 227, + 206, + 186, + 178, + 245, + 43, + 250, + 28, + 108, + 107, + 30, + 58, + 250, + 85, + 118, + 24, + 99, + 30, + 156, + 9, + 126, + 120, + 87, + 150, + 253, + 209, + 112, + 204, + 87, + 14, + 229, + 44, + 244, + 98, + 180, + 184, + 217, + 183, + 27, + 184, + 191, + 241, + 197, + 81, + 3, + 207, + 126, + 239, + 81, + 98, + 130, + 7, + 52, + 20, + 91, + 6, + 22, + 251, + 249, + 11, + 231, + 88, + 42, + 147, + 139, + 227, + 95, + 5, + 252, + 247, + 195, + 40, + 21, + 188, + 173, + 48, + 58, + 76, + 155, + 101, + 86, + 58, + 14, + 4, + 128, + 83, + 229, + 95, + 119, + 156, + 171, + 110, + 238, + 52, + 214, + 14, + 243, + 192, + 58, + 1, + 174, + 207, + 111, + 156, + 127, + 254, + 45, + 123, + 190, + 239, + 66, + 131, + 228, + 31, + 213, + 122, + 147, + 134, + 37, + 89, + 118, + 110, + 97, + 15, + 226, + 138, + 64, + 117, + 217, + 247, + 210, + 63, + 92, + 26, + 125, + 250, + 195, + 199, + 208, + 143, + 97, + 130, + 39, + 63, + 5, + 11, + 102, + 112, + 209, + 62, + 103, + 105, + 69, + 117, + 4, + 13, + 51, + 97, + 99, + 207, + 196, + 123, + 193, + 161, + 129, + 206, + 236, + 80, + 185, + 237, + 126, + 190, + 5, + 138, + 117, + 213, + 163, + 92, + 24, + 38, + 229, + 233, + 16, + 35, + 92, + 102, + 255, + 74, + 194, + 87, + 9, + 4, + 200, + 57, + 239, + 59, + 114, + 131, + 131, + 71, + 17, + 192, + 186, + 89, + 50, + 155, + 100, + 133, + 85, + 13, + 68, + 169, + 118, + 194, + 73, + 126, + 86, + 227, + 112, + 28, + 30, + 206, + 52, + 169, + 143, + 6, + 146, + 188, + 210, + 48, + 195, + 118, + 58, + 77, + 111, + 92, + 46, + 217, + 54, + 144, + 6, + 55, + 240, + 128, + 253, + 192, + 233, + 104, + 85, + 13, + 70, + 139, + 99, + 222, + 163, + 238, + 95, + 47, + 122, + 20, + 95, + 211, + 218, + 212, + 94, + 79, + 143, + 34, + 196, + 101, + 131, + 79, + 228, + 44, + 230, + 96, + 35, + 252, + 51, + 117, + 95, + 58, + 178, + 72, + 104, + 155, + 115, + 47, + 143, + 16, + 75, + 150, + 117, + 40, + 230, + 44, + 226, + 14, + 246, + 122, + 74, + 201, + 76, + 3, + 97, + 3, + 39, + 138, + 91, + 220, + 111, + 147, + 82, + 106, + 87, + 164, + 162, + 76, + 90, + 16, + 185, + 25, + 29, + 169, + 9, + 67, + 117, + 255, + 213, + 224, + 23, + 163, + 16, + 14, + 105, + 0, + 21, + 88, + 1, + 30, + 99, + 217, + 79, + 149, + 229, + 181, + 38, + 87, + 80, + 116, + 6, + 248, + 86, + 2, + 247, + 201, + 49, + 54, + 13, + 160, + 2, + 32, + 154, + 37, + 83, + 109, + 243, + 121, + 84, + 67, + 248, + 23, + 241, + 139, + 58, + 53, + 16, + 154, + 199, + 213, + 179, + 141, + 61, + 156, + 138, + 236, + 21, + 63, + 39, + 221, + 138, + 79, + 169, + 53, + 9, + 161, + 253, + 126, + 159, + 181, + 15, + 90, + 132, + 145, + 72, + 95, + 109, + 248, + 123, + 232, + 246, + 108, + 57, + 64, + 19, + 131, + 152, + 219, + 55, + 220, + 153, + 108, + 234, + 68, + 158, + 152, + 127, + 69, + 61, + 42, + 44, + 116, + 241, + 78, + 69, + 14, + 118, + 93, + 139, + 159, + 71, + 65, + 71, + 173, + 172, + 245, + 9, + 185, + 110, + 38, + 173, + 59, + 185, + 194, + 106, + 37, + 132, + 0, + 136, + 255, + 184, + 9, + 201, + 120, + 253, + 95, + 191, + 231, + 73, + 57, + 241, + 171, + 11, + 138, + 53, + 131, + 86, + 20, + 165, + 235, + 217, + 139, + 187, + 61, + 154, + 65, + 98, + 109, + 90, + 134, + 134, + 1, + 211, + 40, + 90, + 0, + 140, + 35, + 249, + 93, + 233, + 98, + 2, + 27, + 101, + 72, + 13, + 187, + 220, + 183, + 41, + 79, + 121, + 218, + 120, + 39, + 197, + 205, + 10, + 211, + 184, + 179, + 24, + 92, + 82, + 130, + 254, + 224, + 249, + 62, + 61, + 149, + 150, + 86, + 31, + 29, + 244, + 250, + 164, + 195, + 73, + 96, + 177, + 254, + 97, + 190, + 128, + 108, + 63, + 84, + 36, + 235, + 148, + 62, + 55, + 204, + 66, + 39, + 25, + 127, + 117, + 31, + 121, + 149, + 83, + 239, + 45, + 196, + 164, + 58, + 169, + 131, + 145, + 104, + 145, + 244, + 194, + 244, + 96, + 58, + 56, + 31, + 84, + 163, + 205, + 100, + 185, + 242, + 44, + 19, + 10, + 240, + 171, + 58, + 225, + 11, + 242, + 157, + 55, + 218, + 235, + 186, + 255, + 137, + 0, + 215, + 204, + 214, + 228, + 197, + 172, + 211, + 36, + 224, + 37, + 251, + 74, + 138, + 220, + 86, + 250, + 184, + 36, + 201, + 99, + 8, + 234, + 91, + 69, + 12, + 141, + 253, + 54, + 145, + 92, + 97, + 131, + 0, + 106, + 198, + 206, + 42, + 238, + 108, + 115, + 24, + 169, + 131, + 134, + 12, + 126, + 176, + 235, + 8, + 128, + 207, + 42, + 43, + 4, + 187, + 221, + 44, + 122, + 145, + 243, + 138, + 8, + 189, + 247, + 166, + 28, + 46, + 183, + 192, + 143, + 252, + 251, + 78, + 109, + 137, + 102, + 161, + 4, + 13, + 84, + 30, + 7, + 165, + 104, + 52, + 136, + 211, + 12, + 132, + 234, + 204, + 164, + 81, + 141, + 18, + 54, + 242, + 75, + 141, + 94, + 86, + 61, + 167, + 63, + 167, + 255, + 90, + 11, + 143, + 36, + 107, + 110, + 159, + 81, + 28, + 69, + 60, + 217, + 13, + 58, + 62, + 2, + 37, + 9, + 232, + 138, + 53, + 165, + 20, + 25, + 2, + 112, + 236, + 34, + 21, + 211, + 74, + 122, + 7, + 156, + 34, + 29, + 98, + 114, + 177, + 91, + 26, + 207, + 83, + 36, + 16, + 36, + 91, + 196, + 179, + 182, + 128, + 41, + 27, + 188, + 250, + 199, + 70, + 124, + 176, + 37, + 70, + 80, + 138, + 95, + 200, + 67, + 249, + 241, + 27, + 204, + 109, + 151, + 145, + 224, + 105, + 134, + 214, + 10, + 53, + 236, + 94, + 3, + 160, + 108, + 222, + 126, + 115, + 106, + 89, + 123, + 130, + 189, + 81, + 100, + 216, + 145, + 180, + 226, + 247, + 131, + 72, + 168, + 16, + 159, + 65, + 188, + 98, + 98, + 142, + 22, + 253, + 173, + 70, + 27, + 207, + 219, + 58, + 216, + 21, + 117, + 150, + 59, + 188, + 20, + 245, + 94, + 162, + 59, + 108, + 131, + 72, + 195, + 13, + 141, + 28, + 215, + 165, + 123, + 51, + 172, + 123, + 169, + 77, + 212, + 114, + 113, + 93, + 136, + 24, + 15, + 229, + 212, + 126, + 22, + 29, + 150, + 165, + 158, + 213, + 112, + 63, + 224, + 194, + 39, + 34, + 223, + 41, + 204, + 61, + 70, + 95, + 187, + 33, + 100, + 177, + 28, + 101, + 179, + 231, + 131, + 114, + 23, + 255, + 163, + 216, + 5, + 45, + 181, + 199, + 144, + 46, + 2, + 134, + 223, + 59, + 12, + 13, + 165, + 129, + 177, + 166, + 15, + 64, + 83, + 23, + 129, + 231, + 87, + 228, + 182, + 176, + 177, + 253, + 20, + 76, + 58, + 42, + 77, + 245, + 181, + 247, + 240, + 89, + 177, + 183, + 41, + 106, + 123, + 45, + 16, + 62, + 123, + 130, + 240, + 89, + 100, + 149, + 116, + 138, + 239, + 157, + 244, + 126, + 41, + 97, + 246, + 6, + 113, + 86, + 150, + 209, + 106, + 119, + 179, + 150, + 110, + 138, + 61, + 172, + 33, + 196, + 170, + 240, + 248, + 248, + 242, + 36, + 172, + 173, + 202, + 110, + 227, + 58, + 138, + 146, + 118, + 23, + 77, + 229, + 221, + 137, + 130, + 213, + 14, + 193, + 158, + 49, + 193, + 154, + 247, + 49, + 189, + 232, + 43, + 156, + 104, + 112, + 211, + 83, + 103, + 41, + 16, + 255, + 188, + 83, + 192, + 248, + 200, + 211, + 60, + 12, + 157, + 183, + 237, + 88, + 184, + 175, + 224, + 41, + 61, + 137, + 53, + 173, + 10, + 15, + 33, + 149, + 104, + 131, + 128, + 62, + 228, + 191, + 189, + 128, + 175, + 190, + 150, + 74, + 160, + 41, + 80, + 147, + 243, + 116, + 99, + 166, + 144, + 15, + 132, + 161, + 169, + 55, + 95, + 119, + 22, + 67, + 232, + 85, + 239, + 124, + 41, + 53, + 142, + 207, + 22, + 159, + 195, + 155, + 34, + 22, + 151, + 150, + 215, + 66, + 64, + 17, + 112, + 176, + 158, + 21, + 213, + 72, + 152, + 83, + 26, + 35, + 76, + 90, + 38, + 182, + 31, + 44, + 25, + 69, + 247, + 107, + 29, + 67, + 20, + 31, + 26, + 5, + 1, + 141, + 105, + 41, + 185, + 25, + 151, + 208, + 128, + 33, + 195, + 4, + 3, + 37, + 167, + 28, + 31, + 137, + 38, + 243, + 232, + 134, + 24, + 93, + 47, + 113, + 207, + 161, + 126, + 205, + 141, + 188, + 23, + 145, + 77, + 117, + 37, + 206, + 144, + 151, + 118, + 72, + 167, + 63, + 250, + 205, + 78, + 255, + 154, + 12, + 130, + 204, + 174, + 162, + 111, + 75, + 139, + 216, + 35, + 43, + 65, + 18, + 246, + 48, + 26, + 202, + 233, + 245, + 241, + 58, + 5, + 120, + 209, + 251, + 52, + 108, + 191, + 160, + 202, + 211, + 142, + 167, + 85, + 131, + 185, + 228, + 167, + 42, + 18, + 203, + 4, + 115, + 154, + 54, + 208, + 51, + 74, + 143, + 242, + 179, + 252, + 207, + 210, + 23, + 3, + 23, + 118, + 63, + 207, + 157, + 136, + 0, + 138, + 231, + 82, + 214, + 20, + 233, + 9, + 57, + 81, + 171, + 227, + 209, + 96, + 27, + 32, + 36, + 100, + 8, + 241, + 46, + 48, + 19, + 60, + 0, + 179, + 112, + 75, + 156, + 183, + 153, + 247, + 182, + 209, + 73, + 5, + 32, + 48, + 169, + 63, + 47, + 68, + 179, + 204, + 168, + 222, + 120, + 115, + 198, + 94, + 88, + 248, + 50, + 142, + 68, + 122, + 228, + 121, + 131, + 147, + 81, + 250, + 102, + 104, + 140, + 185, + 58, + 193, + 122, + 137, + 149, + 15, + 59, + 128, + 17, + 132, + 234, + 118, + 54, + 127, + 100, + 29, + 11, + 13, + 81, + 171, + 37, + 212, + 6, + 105, + 240, + 176, + 250, + 129, + 48, + 29, + 223, + 41, + 35, + 94, + 165, + 85, + 2, + 111, + 78, + 81, + 31, + 73, + 9, + 148, + 179, + 117, + 217, + 25, + 30, + 174, + 146, + 167, + 193, + 246, + 227, + 245, + 242, + 147, + 194, + 125, + 201, + 203, + 97, + 58, + 4, + 131, + 243, + 67, + 181, + 76, + 59, + 10, + 229, + 64, + 157, + 20, + 247, + 226, + 168, + 93, + 208, + 153, + 172, + 164, + 133, + 229, + 43, + 154, + 212, + 122, + 91, + 23, + 216, + 50, + 81, + 55, + 236, + 103, + 122, + 158, + 34, + 191, + 108, + 4, + 157, + 95, + 73, + 121, + 195, + 86, + 247, + 4, + 129, + 185, + 132, + 136, + 89, + 202, + 214, + 64, + 143, + 25, + 150, + 71, + 116, + 75, + 77, + 143, + 6, + 32, + 193, + 66, + 25, + 130, + 100, + 176, + 167, + 173, + 14, + 213, + 5, + 13, + 145, + 164, + 153, + 29, + 146, + 4, + 166, + 178, + 68, + 233, + 244, + 84, + 148, + 244, + 3, + 132, + 193, + 48, + 224, + 154, + 117, + 105, + 248, + 70, + 58, + 38, + 178, + 200, + 253, + 59, + 50, + 244, + 22, + 88, + 155, + 255, + 113, + 159, + 95, + 191, + 219, + 44, + 138, + 51, + 225, + 88, + 179, + 127, + 8, + 5, + 78, + 9, + 151, + 132, + 220, + 235, + 111, + 55, + 252, + 219, + 18, + 13, + 230, + 164, + 119, + 246, + 98, + 68, + 88, + 158, + 151, + 133, + 33, + 250, + 82, + 118, + 51, + 199, + 227, + 114, + 88, + 225, + 105, + 93, + 145, + 106, + 136, + 86, + 102, + 117, + 73, + 227, + 247, + 224, + 35, + 229, + 165, + 193, + 31, + 55, + 152, + 73, + 193, + 198, + 252, + 232, + 219, + 95, + 139, + 245, + 112, + 226, + 252, + 169, + 220, + 40, + 140, + 234, + 17, + 165, + 0, + 93, + 26, + 87, + 181, + 16, + 241, + 6, + 243, + 121, + 18, + 173, + 124, + 233, + 11, + 4, + 163, + 89, + 208, + 49, + 26, + 164, + 52, + 249, + 57, + 42, + 110, + 132, + 209, + 229, + 155, + 167, + 48, + 217, + 61, + 9, + 150, + 36, + 185, + 7, + 9, + 1, + 64, + 7, + 118, + 188, + 249, + 77, + 54, + 254, + 189, + 82, + 151, + 211, + 38, + 10, + 48, + 69, + 95, + 116, + 29, + 115, + 244, + 135, + 27, + 250, + 243, + 156, + 154, + 181, + 249, + 1, + 112, + 6, + 202, + 24, + 90, + 121, + 8, + 221, + 13, + 137, + 13, + 242, + 222, + 22, + 146, + 14, + 19, + 184, + 95, + 134, + 37, + 46, + 238, + 250, + 86, + 202, + 106, + 158, + 88, + 243, + 161, + 152, + 51, + 26, + 28, + 37, + 20, + 96, + 221, + 81, + 143, + 177, + 166, + 142, + 207, + 217, + 19, + 99, + 131, + 156, + 240, + 73, + 179, + 139, + 189, + 37, + 21, + 139, + 1, + 95, + 90, + 181, + 115, + 39, + 191, + 155, + 30, + 148, + 188, + 71, + 172, + 210, + 178, + 209, + 43, + 83, + 0, + 72, + 118, + 115, + 47, + 209, + 187, + 167, + 212, + 100, + 125, + 229, + 14, + 232, + 54, + 179, + 20, + 210, + 238, + 169, + 143, + 21, + 56, + 38, + 120, + 22, + 20, + 31, + 66, + 94, + 240, + 65, + 176, + 76, + 92, + 9, + 188, + 167, + 53, + 21, + 181, + 34, + 180, + 10, + 77, + 150, + 54, + 130, + 197, + 189, + 101, + 192, + 13, + 25, + 94, + 239, + 50, + 176, + 168, + 60, + 239, + 169, + 179, + 179, + 231, + 244, + 83, + 152, + 95, + 121, + 14, + 109, + 231, + 196, + 72, + 195, + 70, + 95, + 16, + 3, + 11, + 60, + 171, + 111, + 5, + 86, + 85, + 217, + 23, + 117, + 146, + 20, + 110, + 156, + 160, + 241, + 43, + 159, + 8, + 126, + 147, + 56, + 121, + 56, + 182, + 36, + 14, + 236, + 55, + 197, + 168, + 204, + 150, + 212, + 14, + 135, + 7, + 32, + 109, + 126, + 125, + 113, + 23, + 57, + 24, + 115, + 116, + 223, + 5, + 160, + 209, + 162, + 65, + 203, + 202, + 191, + 24, + 168, + 25, + 126, + 107, + 172, + 140, + 31, + 14, + 143, + 150, + 19, + 12, + 161, + 155, + 231, + 196, + 29, + 190, + 206, + 98, + 113, + 23, + 88, + 49, + 41, + 42, + 250, + 199, + 232, + 153, + 12, + 193, + 66, + 0, + 179, + 67, + 87, + 237, + 212, + 215, + 226, + 102, + 76, + 243, + 247, + 81, + 4, + 12, + 147, + 13, + 27, + 181, + 50, + 13, + 26, + 234, + 234, + 178, + 241, + 151, + 237, + 27, + 107, + 151, + 113, + 171, + 184, + 53, + 22, + 64, + 173, + 89, + 5, + 7, + 67, + 43, + 161, + 51, + 85, + 220, + 160, + 135, + 10, + 248, + 243, + 171, + 122, + 239, + 109, + 109, + 27, + 224, + 131, + 223, + 181, + 115, + 4, + 61, + 186, + 52, + 90, + 164, + 64, + 109, + 157, + 16, + 237, + 216, + 215, + 255, + 40, + 110, + 114, + 10, + 67, + 229, + 105, + 230, + 135, + 156, + 189, + 94, + 72, + 214, + 163, + 142, + 27, + 133, + 170, + 58, + 47, + 77, + 186, + 0, + 238, + 5, + 228, + 155, + 165, + 3, + 105, + 133, + 45, + 148, + 21, + 205, + 115, + 223, + 85, + 18, + 100, + 158, + 163, + 112, + 177, + 87, + 193, + 226, + 184, + 122, + 195, + 64, + 23, + 84, + 7, + 147, + 231, + 233, + 83, + 150, + 127, + 185, + 54, + 127, + 235, + 176, + 65, + 127, + 210, + 199, + 45, + 39, + 18, + 77, + 19, + 107, + 12, + 173, + 66, + 126, + 152, + 23, + 9, + 28, + 68, + 29, + 75, + 212, + 161, + 82, + 49, + 176, + 219, + 37, + 81, + 19, + 208, + 5, + 108, + 127, + 32, + 145, + 47, + 97, + 160, + 3, + 97, + 29, + 13, + 180, + 242, + 74, + 132, + 117, + 124, + 106, + 54, + 84, + 205, + 65, + 208, + 140, + 16, + 108, + 149, + 180, + 105, + 213, + 99, + 1, + 228, + 55, + 77, + 48, + 67, + 44, + 145, + 198, + 28, + 212, + 161, + 169, + 191, + 202, + 130, + 92, + 195, + 196, + 158, + 67, + 212, + 97, + 214, + 59, + 93, + 160, + 58, + 210, + 6, + 100, + 242, + 36, + 26, + 246, + 160, + 210, + 193, + 32, + 86, + 220, + 38, + 162, + 131, + 186, + 43, + 241, + 232, + 198, + 44, + 20, + 67, + 82, + 52, + 41, + 88, + 107, + 28, + 40, + 63, + 51, + 176, + 7, + 133, + 48, + 111, + 185, + 250, + 253, + 122, + 60, + 125, + 138, + 193, + 133, + 168, + 214, + 110, + 186, + 76, + 218, + 173, + 112, + 138, + 0, + 113, + 221, + 207, + 120, + 137, + 26, + 13, + 57, + 76, + 4, + 33, + 246, + 57, + 104, + 35, + 39, + 140, + 50, + 204, + 127, + 252, + 116, + 252, + 117, + 121, + 34, + 232, + 221, + 231, + 252, + 38, + 45, + 185, + 24, + 135, + 202, + 55, + 81, + 243, + 139, + 230, + 109, + 55, + 211, + 22, + 55, + 205, + 234, + 105, + 182, + 218, + 157, + 55, + 114, + 106, + 130, + 196, + 111, + 173, + 86, + 80, + 39, + 95, + 73, + 70, + 234, + 150, + 226, + 6, + 95, + 201, + 93, + 10, + 100, + 30, + 75, + 82, + 240, + 199, + 184, + 177, + 111, + 57, + 132, + 104, + 142, + 224, + 38, + 12, + 185, + 175, + 203, + 35, + 82, + 124, + 4, + 92, + 154, + 200, + 163, + 36, + 242, + 38, + 113, + 15, + 135, + 155, + 234, + 168, + 24, + 75, + 137, + 24, + 72, + 159, + 248, + 9, + 195, + 244, + 122, + 153, + 96, + 188, + 154, + 255, + 205, + 25, + 82, + 216, + 59, + 158, + 13, + 23, + 40, + 229, + 18, + 213, + 82, + 23, + 209, + 22, + 13, + 41, + 206, + 174, + 87, + 238, + 22, + 210, + 68, + 144, + 74, + 18, + 62, + 126, + 29, + 182, + 111, + 17, + 105, + 186, + 213, + 55, + 252, + 175, + 175, + 161, + 196, + 175, + 10, + 92, + 153, + 56, + 59, + 193, + 186, + 100, + 77, + 173, + 207, + 214, + 67, + 108, + 93, + 231, + 22, + 78, + 188, + 140, + 96, + 59, + 57, + 183, + 188, + 79, + 205, + 187, + 167, + 126, + 160, + 156, + 245, + 93, + 6, + 184, + 135, + 124, + 70, + 123, + 82, + 153, + 151, + 255, + 33, + 83, + 38, + 149, + 13, + 62, + 94, + 109, + 12, + 4, + 24, + 186, + 127, + 89, + 200, + 244, + 119, + 10, + 75, + 239, + 175, + 161, + 222, + 127, + 223, + 190, + 141, + 132, + 225, + 126, + 252, + 222, + 163, + 72, + 234, + 205, + 42, + 200, + 71, + 95, + 49, + 79, + 14, + 243, + 216, + 175, + 35, + 31, + 194, + 126, + 55, + 151, + 35, + 9, + 144, + 189, + 65, + 204, + 188, + 242, + 109, + 227, + 52, + 170, + 60, + 28, + 21, + 128, + 9, + 34, + 164, + 213, + 171, + 115, + 3, + 185, + 136, + 98, + 243, + 73, + 109, + 113, + 214, + 150, + 105, + 128, + 126, + 108, + 124, + 31, + 160, + 51, + 66, + 77, + 78, + 116, + 156, + 54, + 188, + 134, + 219, + 129, + 33, + 19, + 115, + 147, + 16, + 114, + 250, + 34, + 237, + 185, + 115, + 202, + 128, + 65, + 116, + 45, + 136, + 209, + 73, + 38, + 146, + 168, + 99, + 155, + 41, + 230, + 154, + 234, + 178, + 134, + 154, + 31, + 113, + 92, + 148, + 121, + 109, + 40, + 158, + 6, + 182, + 25, + 192, + 5, + 93, + 104, + 146, + 207, + 15, + 86, + 167, + 42, + 147, + 159, + 27, + 152, + 218, + 206, + 109, + 70, + 10, + 77, + 199, + 120, + 108, + 136, + 70, + 128, + 107, + 85, + 210, + 236, + 22, + 5, + 159, + 217, + 3, + 219, + 77, + 220, + 232, + 103, + 53, + 102, + 125, + 234, + 242, + 181, + 135, + 112, + 135, + 86, + 123, + 221, + 181, + 243, + 18, + 58, + 209, + 86, + 88, + 38, + 52, + 145, + 33, + 58, + 4, + 123, + 136, + 167, + 209, + 42, + 0, + 207, + 190, + 117, + 157, + 129, + 255, + 118, + 121, + 192, + 127, + 154, + 115, + 19, + 25, + 152, + 215, + 19, + 47, + 32, + 81, + 51, + 90, + 235, + 98, + 175, + 4, + 37, + 78, + 21, + 106, + 150, + 95, + 83, + 100, + 222, + 61, + 228, + 248, + 204, + 225, + 44, + 158, + 7, + 191, + 187, + 200, + 159, + 113, + 254, + 151, + 125, + 3, + 109, + 167, + 82, + 235, + 216, + 97, + 175, + 150, + 132, + 236, + 251, + 15, + 23, + 18, + 71, + 119, + 230, + 255, + 170, + 232, + 186, + 232, + 151, + 105, + 68, + 49, + 41, + 170, + 215, + 168, + 171, + 48, + 246, + 28, + 165, + 229, + 27, + 23, + 233, + 194, + 244, + 65, + 230, + 53, + 5, + 180, + 38, + 16, + 113, + 226, + 112, + 122, + 247, + 201, + 43, + 209, + 70, + 227, + 70, + 124, + 193, + 35, + 226, + 19, + 194, + 130, + 172, + 79, + 129, + 27, + 11, + 24, + 104, + 26, + 210, + 87, + 139, + 169, + 126, + 161, + 45, + 128, + 27, + 130, + 178, + 4, + 254, + 249, + 197, + 53, + 133, + 89, + 132, + 150, + 105, + 0, + 184, + 161, + 152, + 21, + 99, + 251, + 37, + 192, + 13, + 231, + 119, + 37, + 83, + 13, + 223, + 185, + 67, + 156, + 26, + 76, + 108, + 243, + 77, + 133, + 68, + 200, + 99, + 20, + 54, + 125, + 27, + 80, + 88, + 25, + 169, + 171, + 69, + 149, + 96, + 28, + 1, + 224, + 13, + 37, + 32, + 203, + 125, + 90, + 73, + 162, + 122, + 197, + 51, + 175, + 182, + 166, + 238, + 145, + 199, + 216, + 122, + 233, + 230, + 86, + 11, + 153, + 250, + 85, + 148, + 67, + 133, + 170, + 149, + 225, + 42, + 191, + 161, + 222, + 199, + 54, + 185, + 126, + 231, + 133, + 87, + 28, + 140, + 90, + 1, + 177, + 250, + 156, + 229, + 154, + 184, + 67, + 219, + 172, + 233, + 105, + 207, + 6, + 200, + 62, + 94, + 96, + 6, + 65, + 174, + 112, + 252, + 223, + 199, + 254, + 124, + 226, + 206, + 1, + 55, + 94, + 45, + 202, + 145, + 34, + 37, + 65, + 167, + 58, + 175, + 174, + 39, + 101, + 230, + 31, + 114, + 1, + 212, + 134, + 17, + 164, + 43, + 196, + 191, + 14, + 245, + 61, + 130, + 239, + 150, + 39, + 136, + 28, + 28, + 253, + 249, + 246, + 231, + 94, + 3, + 27, + 47, + 46, + 105, + 157, + 125, + 120, + 164, + 220, + 179, + 201, + 31, + 138, + 11, + 97, + 88, + 122, + 16, + 156, + 118, + 8, + 18, + 173, + 240, + 69, + 130, + 246, + 200, + 71, + 119, + 237, + 243, + 30, + 192, + 11, + 41, + 153, + 11, + 165, + 9, + 130, + 212, + 152, + 177, + 211, + 222, + 124, + 147, + 207, + 50, + 70, + 120, + 105, + 203, + 54, + 151, + 3, + 172, + 246, + 221, + 81, + 81, + 37, + 250, + 10, + 215, + 185, + 59, + 213, + 197, + 81, + 137, + 7, + 170, + 116, + 119, + 110, + 56, + 130, + 70, + 112, + 124, + 80, + 189, + 159, + 185, + 162, + 218, + 101, + 41, + 83, + 163, + 155, + 100, + 127, + 249, + 72, + 18, + 69, + 57, + 68, + 52, + 170, + 128, + 250, + 87, + 52, + 162, + 7, + 252, + 166, + 16, + 216, + 210, + 239, + 12, + 141, + 238, + 37, + 176, + 227, + 241, + 108, + 158, + 204, + 135, + 30, + 250, + 25, + 51, + 142, + 216, + 38, + 253, + 252, + 97, + 235, + 49, + 41, + 27, + 48, + 187, + 234, + 175, + 25, + 161, + 168, + 120, + 38, + 106, + 173, + 206, + 171, + 137, + 201, + 70, + 58, + 77, + 228, + 155, + 114, + 6, + 143, + 31, + 84, + 47, + 179, + 233, + 105, + 156, + 42, + 8, + 183, + 213, + 103, + 23, + 221, + 66, + 186, + 138, + 191, + 46, + 104, + 60, + 216, + 178, + 60, + 153, + 37, + 7, + 105, + 193, + 96, + 189, + 63, + 19, + 162, + 210, + 145, + 4, + 51, + 240, + 67, + 108, + 190, + 137, + 25, + 80, + 78, + 138, + 246, + 169, + 178, + 128, + 92, + 131, + 66, + 82, + 35, + 70, + 40, + 33, + 101, + 109, + 15, + 154, + 15, + 8, + 196, + 66, + 178, + 157, + 79, + 57, + 140, + 84, + 4, + 157, + 8, + 233, + 105, + 151, + 125, + 57, + 207, + 35, + 127, + 20, + 11, + 25, + 249, + 184, + 220, + 172, + 70, + 81, + 70, + 27, + 22, + 124, + 113, + 124, + 21, + 106, + 130, + 188, + 137, + 109, + 231, + 111, + 131, + 69, + 107, + 55, + 86, + 119, + 20, + 35, + 0, + 42, + 238, + 62, + 122, + 102, + 12, + 150, + 249, + 223, + 110, + 84, + 162, + 24, + 26, + 97, + 121, + 135, + 112, + 76, + 72, + 178, + 32, + 159, + 53, + 177, + 32, + 234, + 205, + 53, + 125, + 37, + 221, + 17, + 195, + 31, + 177, + 121, + 185, + 249, + 31, + 239, + 83, + 82, + 14, + 133, + 94, + 193, + 78, + 116, + 71, + 46, + 242, + 44, + 194, + 149, + 115, + 105, + 123, + 29, + 225, + 2, + 205, + 153, + 195, + 129, + 244, + 79, + 253, + 12, + 209, + 94, + 56, + 37, + 77, + 19, + 213, + 33, + 116, + 107, + 129, + 219, + 237, + 19, + 204, + 222, + 169, + 77, + 117, + 84, + 135, + 109, + 166, + 25, + 20, + 150, + 173, + 252, + 157, + 90, + 113, + 141, + 187, + 83, + 32, + 208, + 111, + 49, + 164, + 114, + 170, + 131, + 226, + 183, + 253, + 239, + 172, + 231, + 41, + 152, + 39, + 49, + 223, + 98, + 148, + 90, + 192, + 247, + 168, + 247, + 64, + 89, + 153, + 103, + 2, + 128, + 144, + 78, + 109, + 106, + 46, + 201, + 200, + 36, + 172, + 99, + 215, + 142, + 91, + 208, + 88, + 203, + 150, + 59, + 229, + 179, + 193, + 220, + 206, + 146, + 60, + 250, + 58, + 235, + 30, + 251, + 194, + 239, + 11, + 237, + 78, + 158, + 13, + 134, + 2, + 206, + 195, + 125, + 134, + 111, + 99, + 125, + 7, + 237, + 187, + 190, + 189, + 169, + 119, + 177, + 217, + 29, + 93, + 65, + 2, + 84, + 78, + 21, + 251, + 108, + 79, + 158, + 39, + 223, + 11, + 251, + 187, + 62, + 207, + 92, + 106, + 93, + 69, + 145, + 128, + 9, + 98, + 218, + 22, + 73, + 97, + 78, + 176, + 221, + 141, + 99, + 111, + 196, + 235, + 193, + 250, + 85, + 166, + 172, + 8, + 213, + 89, + 15, + 15, + 95, + 173, + 233, + 230, + 159, + 189, + 24, + 239, + 1, + 247, + 195, + 140, + 185, + 229, + 238, + 195, + 244, + 89, + 117, + 24, + 16, + 168, + 14, + 225, + 32, + 77, + 145, + 82, + 107, + 100, + 140, + 215, + 127, + 56, + 230, + 71, + 69, + 153, + 35, + 5, + 57, + 43, + 137, + 169, + 69, + 81, + 12, + 81, + 80, + 237, + 205, + 152, + 105, + 29, + 95, + 2, + 186, + 30, + 134, + 9, + 166, + 107, + 148, + 179, + 131, + 222, + 160, + 162, + 167, + 94, + 182, + 33, + 215, + 168, + 220, + 174, + 75, + 175, + 16, + 134, + 59, + 66, + 45, + 229, + 200, + 226, + 61, + 212, + 187, + 62, + 168, + 104, + 139, + 247, + 96, + 218, + 217, + 132, + 164, + 43, + 110, + 52, + 153, + 72, + 136, + 213, + 39, + 176, + 44, + 236, + 144, + 98, + 30, + 153, + 174, + 137, + 180, + 90, + 91, + 166, + 118, + 57, + 14, + 55, + 113, + 58, + 106, + 79, + 39, + 239, + 185, + 127, + 107, + 154, + 191, + 248, + 86, + 132, + 31, + 219, + 11, + 189, + 194, + 110, + 198, + 65, + 66, + 57, + 24, + 30, + 116, + 190, + 58, + 186, + 40, + 64, + 243, + 187, + 100, + 58, + 232, + 98, + 31, + 109, + 74, + 169, + 24, + 45, + 178, + 252, + 63, + 198, + 207, + 197, + 38, + 112, + 24, + 140, + 216, + 0, + 231, + 22, + 81, + 222, + 103, + 193, + 23, + 4, + 67, + 230, + 35, + 243, + 13, + 138, + 108, + 136, + 89, + 12, + 60, + 176, + 175, + 3, + 136, + 175, + 3, + 30, + 162, + 33, + 18, + 21, + 36, + 37, + 182, + 16, + 238, + 135, + 0, + 243, + 144, + 50, + 3, + 57, + 19, + 126, + 22, + 24, + 140, + 67, + 11, + 207, + 168, + 128, + 225, + 56, + 6, + 252, + 43, + 186, + 26, + 165, + 0, + 230, + 55, + 211, + 171, + 17, + 223, + 132, + 56, + 92, + 10, + 33, + 253, + 25, + 108, + 74, + 221, + 172, + 123, + 155, + 61, + 105, + 73, + 118, + 64, + 17, + 218, + 38, + 16, + 157, + 16, + 226, + 167, + 154, + 122, + 79, + 189, + 185, + 124, + 90, + 165, + 233, + 39, + 50, + 37, + 143, + 56, + 166, + 20, + 255, + 86, + 8, + 131, + 41, + 129, + 87, + 55, + 213, + 49, + 216, + 33, + 46, + 233, + 246, + 46, + 198, + 128, + 242, + 161, + 148, + 130, + 179, + 251, + 53, + 9, + 44, + 243, + 51, + 20, + 3, + 50, + 31, + 245, + 246, + 170, + 159, + 160, + 241, + 50, + 110, + 188, + 72, + 62, + 64, + 238, + 74, + 191, + 187, + 116, + 218, + 147, + 250, + 134, + 86, + 112, + 187, + 242, + 27, + 125, + 9, + 177, + 61, + 143, + 127, + 157, + 213, + 28, + 114, + 130, + 81, + 128, + 38, + 51, + 20, + 47, + 9, + 47, + 121, + 155, + 220, + 229, + 106, + 144, + 201, + 92, + 161, + 141, + 213, + 97, + 52, + 40, + 158, + 108, + 218, + 209, + 255, + 248, + 47, + 94, + 88, + 210, + 83, + 63, + 86, + 181, + 99, + 164, + 238, + 186, + 209, + 208, + 182, + 238, + 119, + 193, + 197, + 55, + 80, + 198, + 4, + 39, + 80, + 168, + 87, + 230, + 130, + 35, + 110, + 6, + 56, + 78, + 236, + 122, + 254, + 72, + 50, + 102, + 144, + 177, + 101, + 170, + 138, + 235, + 251, + 148, + 194, + 143, + 174, + 236, + 183, + 253, + 168, + 6, + 0, + 56, + 125, + 63, + 101, + 17, + 44, + 209, + 83, + 249, + 239, + 114, + 154, + 229, + 30, + 128, + 174, + 117, + 26, + 19, + 87, + 65, + 253, + 9, + 45, + 213, + 62, + 119, + 86, + 0, + 251, + 147, + 99, + 100, + 12, + 217, + 69, + 246, + 175, + 88, + 207, + 209, + 22, + 221, + 61, + 255, + 44, + 239, + 104, + 133, + 190, + 101, + 162, + 39, + 230, + 105, + 100, + 196, + 202, + 234, + 52, + 140, + 219, + 241, + 30, + 46, + 183, + 176, + 3, + 217, + 142, + 135, + 130, + 141, + 161, + 201, + 29, + 170, + 232, + 8, + 12, + 165, + 219, + 179, + 242, + 164, + 205, + 74, + 100, + 115, + 217, + 31, + 13, + 77, + 43, + 87, + 85, + 114, + 248, + 36, + 65, + 20, + 205, + 120, + 186, + 222, + 225, + 129, + 163, + 91, + 242, + 5, + 53, + 128, + 62, + 44, + 19, + 50, + 43, + 175, + 209, + 66, + 7, + 79, + 114, + 151, + 9, + 8, + 42, + 237, + 157, + 181, + 85, + 184, + 40, + 65, + 168, + 236, + 98, + 76, + 246, + 133, + 10, + 52, + 4, + 25, + 139, + 126, + 137, + 120, + 248, + 234, + 80, + 12, + 45, + 151, + 250, + 3, + 137, + 37, + 42, + 110, + 223, + 42, + 197, + 4, + 179, + 14, + 65, + 155, + 91, + 18, + 218, + 27, + 40, + 209, + 179, + 195, + 80, + 63, + 159, + 65, + 159, + 134, + 229, + 14, + 11, + 104, + 83, + 169, + 128, + 71, + 114, + 116, + 221, + 99, + 81, + 247, + 180, + 112, + 235, + 203, + 206, + 210, + 57, + 193, + 242, + 142, + 170, + 63, + 134, + 233, + 62, + 246, + 178, + 115, + 110, + 45, + 3, + 76, + 144, + 130, + 187, + 209, + 74, + 68, + 222, + 229, + 130, + 209, + 206, + 166, + 150, + 173, + 119, + 232, + 80, + 106, + 154, + 70, + 204, + 55, + 64, + 58, + 182, + 246, + 156, + 129, + 84, + 106, + 209, + 171, + 60, + 185, + 242, + 242, + 52, + 81, + 251, + 115, + 51, + 237, + 237, + 86, + 89, + 219, + 193, + 50, + 91, + 229, + 50, + 54, + 66, + 108, + 143, + 216, + 251, + 108, + 48, + 161, + 79, + 93, + 38, + 49, + 130, + 154, + 144, + 239, + 111, + 205, + 4, + 57, + 110, + 5, + 233, + 167, + 197, + 198, + 225, + 111, + 117, + 209, + 49, + 84, + 70, + 141, + 107, + 206, + 127, + 214, + 227, + 94, + 86, + 191, + 89, + 1, + 141, + 108, + 223, + 159, + 70, + 207, + 238, + 64, + 179, + 175, + 142, + 144, + 75, + 19, + 211, + 244, + 196, + 118, + 119, + 249, + 219, + 78, + 127, + 238, + 186, + 13, + 201, + 139, + 96, + 136, + 25, + 124, + 195, + 59, + 24, + 236, + 113, + 201, + 33, + 127, + 109, + 38, + 187, + 95, + 132, + 115, + 0, + 232, + 64, + 33, + 216, + 147, + 90, + 155, + 210, + 118, + 232, + 110, + 232, + 98, + 166, + 193, + 155, + 85, + 193, + 33, + 92, + 48, + 55, + 124, + 12, + 131, + 57, + 173, + 192, + 188, + 75, + 233, + 182, + 126, + 54, + 81, + 115, + 80, + 63, + 37, + 116, + 239, + 14, + 14, + 23, + 32, + 138, + 92, + 143, + 11, + 190, + 22, + 254, + 217, + 91, + 227, + 32, + 48, + 74, + 54, + 68, + 169, + 210, + 203, + 177, + 186, + 141, + 74, + 126, + 88, + 35, + 187, + 249, + 215, + 73, + 141, + 182, + 33, + 193, + 154, + 1, + 27, + 104, + 14, + 91, + 253, + 62, + 160, + 29, + 10, + 232, + 152, + 16, + 51, + 185, + 243, + 63, + 6, + 41, + 99, + 98, + 69, + 190, + 226, + 218, + 46, + 164, + 60, + 39, + 149, + 103, + 22, + 16, + 85, + 35, + 119, + 112, + 168, + 28, + 34, + 216, + 144, + 5, + 179, + 20, + 195, + 66, + 238, + 82, + 218, + 160, + 155, + 156, + 41, + 96, + 130, + 35, + 147, + 162, + 76, + 192, + 88, + 6, + 113, + 3, + 195, + 158, + 85, + 140, + 37, + 2, + 40, + 174, + 25, + 200, + 208, + 237, + 24, + 252, + 243, + 183, + 26, + 106, + 222, + 212, + 9, + 147, + 48, + 56, + 214, + 191, + 143, + 132, + 119, + 135, + 233, + 100, + 145, + 194, + 85, + 191, + 154, + 13, + 130, + 29, + 9, + 107, + 243, + 80, + 171, + 201, + 208, + 76, + 180, + 112, + 224, + 126, + 216, + 213, + 148, + 149, + 7, + 48, + 208, + 114, + 1, + 125, + 124, + 179, + 45, + 203, + 122, + 167, + 48, + 1, + 190, + 145, + 211, + 121, + 113, + 7, + 244, + 97, + 253, + 255, + 31, + 133, + 156, + 112, + 166, + 245, + 190, + 128, + 148, + 146, + 12, + 238, + 27, + 228, + 84, + 204, + 140, + 247, + 241, + 198, + 32, + 41, + 103, + 127, + 59, + 154, + 147, + 35, + 244, + 148, + 26, + 19, + 235, + 213, + 61, + 73, + 63, + 204, + 86, + 146, + 116, + 129, + 119, + 105, + 21, + 134, + 157, + 162, + 127, + 196, + 250, + 112, + 100, + 73, + 234, + 157, + 121, + 56, + 85, + 245, + 51, + 226, + 38, + 1, + 99, + 138, + 144, + 72, + 248, + 192, + 81, + 13, + 71, + 184, + 155, + 35, + 185, + 170, + 127, + 49, + 118, + 225, + 80, + 145, + 140, + 21, + 186, + 208, + 195, + 252, + 6, + 212, + 147, + 14, + 143, + 210, + 189, + 8, + 170, + 157, + 24, + 87, + 199, + 100, + 144, + 135, + 19, + 115, + 19, + 187, + 239, + 251, + 170, + 114, + 224, + 28, + 121, + 113, + 181, + 192, + 121, + 80, + 214, + 27, + 108, + 30, + 94, + 176, + 1, + 184, + 124, + 159, + 4, + 168, + 158, + 147, + 127, + 82, + 151, + 253, + 35, + 202, + 145, + 18, + 104, + 72, + 161, + 40, + 191, + 100, + 170, + 179, + 251, + 173, + 84, + 241, + 30, + 52, + 69, + 21, + 41, + 65, + 128, + 136, + 146, + 89, + 6, + 63, + 162, + 169, + 51, + 106, + 173, + 142, + 231, + 41, + 198, + 77, + 225, + 0, + 79, + 98, + 236, + 61, + 115, + 157, + 162, + 228, + 195, + 227, + 117, + 1, + 81, + 141, + 232, + 204, + 156, + 46, + 227, + 135, + 57, + 80, + 205, + 119, + 6, + 221, + 173, + 121, + 182, + 50, + 74, + 43, + 3, + 60, + 46, + 90, + 194, + 68, + 119, + 89, + 238, + 126, + 76, + 35, + 96, + 186, + 230, + 40, + 124, + 23, + 39, + 57, + 131, + 152, + 64, + 26, + 142, + 228, + 191, + 93, + 69, + 116, + 120, + 49, + 6, + 12, + 230, + 167, + 166, + 112, + 3, + 98, + 22, + 89, + 79, + 252, + 196, + 240, + 186, + 159, + 61, + 226, + 124, + 196, + 189, + 128, + 200, + 100, + 69, + 88, + 2, + 54, + 240, + 24, + 248, + 30, + 240, + 30, + 69, + 123, + 230, + 8, + 132, + 64, + 14, + 7, + 7, + 141, + 243, + 255, + 84, + 144, + 84, + 152, + 179, + 173, + 20, + 78, + 168, + 194, + 45, + 117, + 65, + 37, + 56, + 37, + 98, + 111, + 224, + 80, + 133, + 131, + 1, + 5, + 170, + 226, + 47, + 151, + 168, + 115, + 66, + 36, + 173, + 19, + 94, + 182, + 194, + 127, + 193, + 4, + 101, + 235, + 110, + 174, + 23, + 47, + 37, + 48, + 218, + 91, + 150, + 4, + 207, + 52, + 30, + 254, + 81, + 103, + 118, + 249, + 188, + 191, + 98, + 79, + 116, + 218, + 37, + 33, + 99, + 16, + 52, + 73, + 36, + 213, + 124, + 198, + 99, + 45, + 211, + 42, + 46, + 38, + 127, + 9, + 251, + 62, + 148, + 206, + 51, + 164, + 116, + 26, + 124, + 91, + 148, + 21, + 126, + 49, + 232, + 33, + 33, + 228, + 187, + 130, + 85, + 30, + 177, + 159, + 111, + 164, + 15, + 230, + 95, + 110, + 56, + 18, + 86, + 166, + 32, + 139, + 110, + 159, + 73, + 134, + 117, + 212, + 93, + 136, + 125, + 173, + 213, + 23, + 14, + 75, + 160, + 135, + 129, + 145, + 85, + 118, + 82, + 195, + 16, + 105, + 32, + 219, + 255, + 101, + 155, + 143, + 51, + 132, + 131, + 56, + 1, + 140, + 11, + 150, + 30, + 5, + 135, + 141, + 200, + 196, + 19, + 159, + 248, + 20, + 191, + 174, + 189, + 83, + 223, + 22, + 62, + 249, + 88, + 86, + 135, + 75, + 230, + 114, + 78, + 92, + 214, + 9, + 245, + 178, + 81, + 224, + 121, + 96, + 18, + 104, + 114, + 24, + 149, + 238, + 215, + 43, + 152, + 18, + 134, + 232, + 55, + 35, + 13, + 48, + 39, + 189, + 139, + 112, + 226, + 79, + 241, + 230, + 230, + 63, + 113, + 153, + 36, + 221, + 178, + 79, + 183, + 73, + 5, + 82, + 215, + 162, + 111, + 238, + 240, + 103, + 5, + 63, + 87, + 174, + 175, + 74, + 188, + 153, + 198, + 102, + 250, + 207, + 69, + 52, + 33, + 67, + 225, + 50, + 221, + 134, + 130, + 78, + 223, + 42, + 86, + 191, + 58, + 11, + 185, + 113, + 36, + 178, + 19, + 96, + 40, + 55, + 103, + 3, + 142, + 66, + 183, + 93, + 14, + 67, + 48, + 6, + 252, + 15, + 51, + 229, + 145, + 139, + 153, + 218, + 230, + 47, + 0, + 25, + 120, + 60, + 188, + 21, + 225, + 242, + 10, + 13, + 152, + 88, + 204, + 57, + 70, + 251, + 185, + 39, + 16, + 80, + 13, + 79, + 193, + 182, + 86, + 184, + 167, + 203, + 116, + 182, + 47, + 17, + 248, + 163, + 193, + 172, + 56, + 63, + 101, + 164, + 255, + 29, + 129, + 153, + 209, + 29, + 175, + 49, + 71, + 90, + 35, + 67, + 198, + 254, + 135, + 158, + 121, + 7, + 122, + 204, + 117, + 102, + 14, + 102, + 99, + 94, + 239, + 70, + 144, + 96, + 163, + 2, + 97, + 52, + 76, + 158, + 47, + 232, + 92, + 143, + 8, + 24, + 70, + 216, + 36, + 122, + 35, + 46, + 117, + 110, + 205, + 133, + 88, + 183, + 159, + 230, + 117, + 36, + 150, + 185, + 121, + 102, + 209, + 149, + 204, + 194, + 77, + 157, + 69, + 87, + 171, + 3, + 95, + 96, + 134, + 104, + 121, + 231, + 192, + 140, + 240, + 170, + 68, + 225, + 44, + 198, + 73, + 251, + 128, + 132, + 200, + 27, + 98, + 220, + 34, + 151, + 110, + 238, + 83, + 104, + 156, + 48, + 228, + 22, + 82, + 97, + 49, + 218, + 47, + 192, + 201, + 9, + 119, + 210, + 211, + 9, + 158, + 110, + 75, + 133, + 96, + 251, + 107, + 237, + 205, + 65, + 198, + 23, + 211, + 10, + 73, + 204, + 237, + 113, + 233, + 9, + 216, + 73, + 241, + 97, + 22, + 76, + 127, + 98, + 183, + 184, + 82, + 165, + 10, + 56, + 144, + 109, + 251, + 66, + 149, + 140, + 241, + 156, + 42, + 92, + 79, + 211, + 12, + 107, + 226, + 52, + 152, + 138, + 162, + 15, + 237, + 209, + 19, + 13, + 22, + 86, + 38, + 2, + 57, + 162, + 72, + 205, + 136, + 145, + 119, + 231, + 52, + 161, + 129, + 227, + 164, + 166, + 11, + 91, + 79, + 97, + 177, + 20, + 69, + 109, + 242, + 46, + 222, + 24, + 164, + 135, + 198, + 96, + 90, + 46, + 226, + 23, + 8, + 135, + 162, + 203, + 9, + 11, + 46, + 148, + 248, + 144, + 205, + 239, + 206, + 48, + 12, + 221, + 92, + 175, + 12, + 154, + 41, + 56, + 175, + 56, + 71, + 200, + 217, + 54, + 137, + 227, + 59, + 32, + 188, + 196, + 97, + 1, + 106, + 211, + 35, + 196, + 141, + 150, + 48, + 11, + 104, + 13, + 14, + 11, + 139, + 98, + 28, + 95, + 112, + 17, + 125, + 55, + 194, + 76, + 175, + 78, + 128, + 158, + 183, + 211, + 105, + 236, + 13, + 253, + 161, + 26, + 47, + 254, + 220, + 136, + 182, + 173, + 138, + 26, + 189, + 192, + 12, + 127, + 123, + 42, + 134, + 51, + 219, + 33, + 16, + 36, + 152, + 155, + 209, + 185, + 219, + 137, + 111, + 213, + 85, + 176, + 85, + 226, + 201, + 140, + 125, + 243, + 34, + 97, + 189, + 228, + 220, + 34, + 155, + 255, + 8, + 239, + 72, + 85, + 211, + 86, + 113, + 127, + 253, + 135, + 193, + 169, + 117, + 135, + 152, + 171, + 10, + 130, + 73, + 45, + 110, + 178, + 85, + 244, + 139, + 162, + 202, + 212, + 142, + 149, + 255, + 179, + 87, + 204, + 124, + 68, + 15, + 68, + 83, + 141, + 238, + 255, + 193, + 10, + 57, + 175, + 233, + 47, + 199, + 204, + 81, + 45, + 220, + 156, + 108, + 112, + 99, + 53, + 16, + 104, + 245, + 209, + 122, + 45, + 199, + 154, + 95, + 68, + 94, + 216, + 83, + 16, + 159, + 132, + 8, + 67, + 152, + 43, + 25, + 152, + 49, + 216, + 182, + 125, + 141, + 245, + 73, + 251, + 136, + 179, + 36, + 97, + 130, + 112, + 21, + 232, + 142, + 95, + 55, + 26, + 247, + 224, + 8, + 200, + 188, + 69, + 186, + 217, + 74, + 62, + 54, + 39, + 18, + 187, + 90, + 250, + 45, + 87, + 89, + 100, + 32, + 117, + 100, + 75, + 108, + 173, + 6, + 54, + 156, + 129, + 88, + 113, + 232, + 244, + 139, + 241, + 59, + 11, + 13, + 221, + 79, + 17, + 111, + 125, + 155, + 212, + 51, + 51, + 150, + 228, + 138, + 73, + 143, + 248, + 101, + 205, + 42, + 167, + 50, + 152, + 26, + 169, + 110, + 23, + 255, + 186, + 24, + 222, + 70, + 40, + 72, + 101, + 110, + 100, + 223, + 195, + 83, + 109, + 33, + 211, + 85, + 130, + 214, + 145, + 111, + 225, + 124, + 199, + 161, + 113, + 103, + 251, + 221, + 187, + 143, + 99, + 105, + 164, + 251, + 217, + 158, + 81, + 26, + 38, + 159, + 24, + 222, + 119, + 244, + 50, + 248, + 212, + 5, + 218, + 120, + 64, + 21, + 83, + 195, + 192, + 119, + 115, + 189, + 153, + 215, + 198, + 34, + 104, + 227, + 127, + 14, + 37, + 89, + 69, + 187, + 72, + 200, + 104, + 171, + 144, + 140, + 76, + 122, + 76, + 233, + 62, + 79, + 70, + 145, + 165, + 166, + 98, + 152, + 244, + 4, + 42, + 104, + 162, + 81, + 40, + 237, + 60, + 239, + 91, + 181, + 130, + 118, + 114, + 200, + 127, + 11, + 136, + 75, + 79, + 235, + 236, + 212, + 48, + 50, + 129, + 149, + 72, + 121, + 180, + 153, + 77, + 240, + 21, + 192, + 174, + 148, + 104, + 48, + 96, + 154, + 255, + 236, + 197, + 147, + 129, + 74, + 118, + 93, + 13, + 92, + 215, + 207, + 23, + 73, + 15, + 27, + 26, + 42, + 232, + 254, + 201, + 125, + 101, + 65, + 48, + 238, + 184, + 135, + 45, + 169, + 205, + 140, + 240, + 139, + 126, + 248, + 109, + 174, + 227, + 51, + 6, + 171, + 243, + 128, + 210, + 187, + 125, + 68, + 170, + 197, + 99, + 110, + 127, + 182, + 56, + 12, + 145, + 215, + 204, + 81, + 88, + 183, + 77, + 66, + 170, + 20, + 16, + 222, + 167, + 72, + 39, + 24, + 162, + 251, + 108, + 135, + 162, + 37, + 99, + 212, + 253, + 239, + 205, + 114, + 209, + 30, + 203, + 251, + 179, + 175, + 115, + 10, + 106, + 2, + 9, + 252, + 135, + 230, + 21, + 49, + 24, + 99, + 177, + 187, + 192, + 27, + 152, + 190, + 126, + 207, + 75, + 163, + 81, + 3, + 149, + 93, + 102, + 71, + 12, + 147, + 162, + 133, + 126, + 237, + 75, + 227, + 196, + 14, + 145, + 230, + 154, + 24, + 60, + 201, + 9, + 138, + 145, + 20, + 177, + 189, + 189, + 196, + 34, + 23, + 109, + 205, + 205, + 171, + 156, + 14, + 90, + 209, + 223, + 51, + 226, + 214, + 28, + 110, + 238, + 78, + 152, + 21, + 210, + 31, + 190, + 16, + 41, + 206, + 144, + 39, + 58, + 245, + 44, + 139, + 232, + 226, + 74, + 238, + 132, + 20, + 182, + 238, + 34, + 179, + 205, + 61, + 170, + 121, + 54, + 30, + 79, + 181, + 89, + 148, + 202, + 120, + 184, + 243, + 170, + 167, + 150, + 104, + 50, + 88, + 54, + 91, + 82, + 135, + 156, + 58, + 146, + 198, + 90, + 123, + 77, + 10, + 226, + 117, + 216, + 112, + 93, + 134, + 159, + 154, + 139, + 237, + 207, + 226, + 210, + 172, + 13, + 102, + 73, + 71, + 200, + 92, + 122, + 33, + 16, + 107, + 29, + 207, + 250, + 23, + 54, + 118, + 76, + 26, + 138, + 41, + 249, + 114, + 76, + 194, + 110, + 46, + 47, + 255, + 168, + 106, + 115, + 80, + 224, + 220, + 227, + 197, + 121, + 146, + 242, + 46, + 197, + 248, + 167, + 218, + 252, + 241, + 100, + 92, + 83, + 81, + 149, + 23, + 152, + 89, + 88, + 110, + 57, + 103, + 141, + 225, + 231, + 221, + 199, + 39, + 63, + 186, + 186, + 247, + 201, + 174, + 23, + 191, + 187, + 61, + 57, + 124, + 1, + 78, + 20, + 60, + 171, + 128, + 254, + 166, + 59, + 108, + 51, + 195, + 197, + 215, + 180, + 39, + 248, + 114, + 209, + 155, + 185, + 57, + 108, + 78, + 3, + 214, + 196, + 229, + 110, + 70, + 208, + 159, + 205, + 171, + 93, + 167, + 67, + 35, + 115, + 196, + 114, + 67, + 64, + 191, + 64, + 44, + 139, + 112, + 178, + 26, + 133, + 183, + 42, + 118, + 161, + 16, + 75, + 230, + 47, + 115, + 83, + 249, + 26, + 216, + 79, + 92, + 23, + 61, + 119, + 228, + 45, + 76, + 78, + 120, + 23, + 170, + 94, + 61, + 27, + 63, + 189, + 38, + 168, + 182, + 170, + 66, + 102, + 245, + 144, + 202, + 70, + 188, + 83, + 241, + 158, + 253, + 210, + 71, + 143, + 181, + 163, + 68, + 135, + 105, + 106, + 194, + 21, + 183, + 240, + 234, + 45, + 221, + 22, + 45, + 246, + 243, + 185, + 217, + 56, + 248, + 163, + 213, + 106, + 228, + 213, + 38, + 226, + 212, + 67, + 51, + 31, + 238, + 209, + 137, + 162, + 71, + 8, + 90, + 93, + 193, + 241, + 211, + 160, + 165, + 130, + 30, + 182, + 109, + 86, + 80, + 55, + 23, + 65, + 193, + 234, + 81, + 104, + 232, + 44, + 209, + 178, + 201, + 147, + 193, + 254, + 1, + 211, + 96, + 209, + 24, + 7, + 251, + 195, + 75, + 245, + 76, + 228, + 72, + 158, + 89, + 0, + 38, + 125, + 133, + 150, + 30, + 113, + 105, + 59, + 46, + 245, + 169, + 111, + 134, + 158, + 253, + 90, + 18, + 100, + 35, + 109, + 196, + 67, + 244, + 221, + 19, + 179, + 109, + 2, + 6, + 120, + 62, + 200, + 55, + 32, + 219, + 94, + 107, + 15, + 70, + 148, + 22, + 222, + 201, + 157, + 128, + 17, + 138, + 154, + 77, + 95, + 193, + 89, + 17, + 105, + 86, + 186, + 240, + 208, + 33, + 88, + 153, + 58, + 116, + 105, + 109, + 175, + 132, + 220, + 147, + 85, + 13, + 137, + 32, + 66, + 225, + 243, + 120, + 158, + 106, + 214, + 157, + 243, + 47, + 195, + 31, + 59, + 192, + 97, + 39, + 254, + 214, + 204, + 44, + 67, + 91, + 111, + 80, + 167, + 82, + 179, + 137, + 137, + 101, + 95, + 135, + 165, + 6, + 112, + 86, + 76, + 37, + 186, + 134, + 120, + 108, + 211, + 53, + 41, + 46, + 93, + 119, + 141, + 139, + 216, + 58, + 215, + 57, + 70, + 155, + 242, + 202, + 51, + 153, + 90, + 171, + 213, + 51, + 162, + 163, + 219, + 211, + 148, + 101, + 17, + 32, + 153, + 212, + 201, + 80, + 105, + 88, + 202, + 121, + 43, + 207, + 51, + 3, + 168, + 178, + 130, + 28, + 188, + 74, + 45, + 186, + 110, + 216, + 32, + 230, + 54, + 241, + 45, + 39, + 157, + 185, + 18, + 33, + 246, + 185, + 242, + 163, + 46, + 56, + 235, + 194, + 73, + 73, + 39, + 240, + 244, + 181, + 124, + 149, + 192, + 178, + 33, + 204, + 8, + 92, + 154, + 33, + 48, + 14, + 249, + 27, + 213, + 225, + 53, + 46, + 242, + 198, + 12, + 96, + 104, + 47, + 239, + 193, + 238, + 152, + 36, + 248, + 95, + 229, + 239, + 64, + 89, + 192, + 162, + 235, + 8, + 107, + 136, + 223, + 212, + 146, + 217, + 53, + 32, + 173, + 79, + 181, + 215, + 79, + 55, + 20, + 52, + 218, + 15, + 141, + 206, + 129, + 249, + 149, + 253, + 241, + 176, + 87, + 98, + 141, + 103, + 127, + 85, + 218, + 134, + 108, + 208, + 224, + 245, + 226, + 184, + 253, + 74, + 144, + 148, + 140, + 218, + 102, + 66, + 23, + 47, + 175, + 166, + 238, + 143, + 80, + 39, + 219, + 9, + 200, + 23, + 236, + 218, + 68, + 107, + 27, + 92, + 146, + 183, + 10, + 179, + 189, + 163, + 224, + 125, + 82, + 78, + 140, + 214, + 253, + 61, + 203, + 86, + 130, + 100, + 133, + 199, + 151, + 220, + 82, + 192, + 163, + 27, + 68, + 0, + 155, + 105, + 95, + 215, + 218, + 106, + 138, + 239, + 31, + 173, + 127, + 238, + 134, + 116, + 96, + 8, + 210, + 78, + 142, + 239, + 220, + 217, + 82, + 195, + 108, + 145, + 126, + 174, + 191, + 64, + 64, + 147, + 55, + 34, + 45, + 162, + 204, + 41, + 114, + 169, + 207, + 133, + 68, + 255, + 24, + 106, + 135, + 97, + 16, + 81, + 19, + 38, + 34, + 115, + 93, + 190, + 108, + 104, + 81, + 213, + 150, + 221, + 26, + 193, + 234, + 3, + 247, + 49, + 110, + 203, + 162, + 12, + 4, + 144, + 10, + 224, + 82, + 163, + 247, + 207, + 85, + 95, + 146, + 34, + 149, + 13, + 224, + 239, + 34, + 238, + 212, + 135, + 218, + 81, + 54, + 62, + 55, + 97, + 187, + 52, + 243, + 108, + 177, + 142, + 99, + 144, + 152, + 8, + 130, + 79, + 18, + 56, + 167, + 26, + 181, + 197, + 109, + 204, + 5, + 36, + 22, + 178, + 121, + 248, + 200, + 9, + 86, + 16, + 65, + 217, + 212, + 219, + 122, + 208, + 187, + 219, + 78, + 154, + 92, + 236, + 68, + 138, + 11, + 185, + 154, + 70, + 126, + 238, + 147, + 13, + 219, + 148, + 117, + 13, + 101, + 128, + 121, + 253, + 88, + 223, + 249, + 0, + 153, + 55, + 237, + 122, + 11, + 10, + 68, + 83, + 181, + 197, + 61, + 15, + 3, + 253, + 156, + 63, + 11, + 83, + 19, + 127, + 0, + 79, + 89, + 218, + 172, + 83, + 168, + 157, + 238, + 136, + 108, + 32, + 51, + 40, + 160, + 137, + 119, + 123, + 20, + 120, + 1, + 37, + 224, + 16, + 192, + 22, + 31, + 78, + 171, + 6, + 99, + 17, + 167, + 241, + 201, + 254, + 147, + 72, + 252, + 252, + 237, + 79, + 72, + 155, + 208, + 140, + 128, + 198, + 231, + 238, + 139, + 159, + 64, + 159, + 91, + 70, + 39, + 226, + 124, + 100, + 224, + 37, + 199, + 190, + 45, + 247, + 2, + 127, + 166, + 164, + 123, + 173, + 84, + 114, + 192, + 178, + 25, + 75, + 140, + 82, + 117, + 226, + 169, + 51, + 24, + 122, + 206, + 230, + 110, + 88, + 192, + 113, + 47, + 146, + 162, + 131, + 3, + 105, + 199, + 196, + 28, + 6, + 71, + 13, + 202, + 114, + 104, + 141, + 217, + 199, + 165, + 127, + 58, + 131, + 90, + 111, + 101, + 200, + 111, + 253, + 48, + 219, + 86, + 107, + 225, + 252, + 28, + 15, + 85, + 137, + 64, + 76, + 112, + 25, + 223, + 90, + 200, + 200, + 166, + 236, + 193, + 201, + 153, + 238, + 187, + 157, + 202, + 14, + 171, + 63, + 16, + 224, + 35, + 251, + 170, + 82, + 180, + 190, + 191, + 11, + 97, + 14, + 248, + 68, + 87, + 150, + 231, + 127, + 254, + 31, + 171, + 69, + 34, + 189, + 77, + 122, + 223, + 70, + 33, + 227, + 15, + 49, + 200, + 72, + 183, + 150, + 153, + 36, + 19, + 159, + 234, + 15, + 185, + 113, + 109, + 187, + 234, + 65, + 207, + 107, + 241, + 230, + 89, + 34, + 252, + 129, + 116, + 156, + 21, + 50, + 52, + 96, + 252, + 109, + 89, + 81, + 42, + 49, + 162, + 39, + 237, + 51, + 123, + 204, + 2, + 104, + 186, + 89, + 0, + 237, + 62, + 62, + 101, + 104, + 124, + 154, + 188, + 179, + 11, + 68, + 34, + 250, + 106, + 201, + 0, + 155, + 126, + 254, + 130, + 174, + 227, + 93, + 27, + 246, + 135, + 21, + 73, + 239, + 54, + 112, + 205, + 163, + 146, + 86, + 242, + 106, + 224, + 52, + 91, + 238, + 42, + 121, + 218, + 167, + 157, + 192, + 10, + 199, + 237, + 114, + 239, + 213, + 87, + 90, + 101, + 69, + 89, + 175, + 52, + 29, + 200, + 36, + 185, + 73, + 38, + 252, + 35, + 115, + 49, + 134, + 159, + 180, + 34, + 175, + 159, + 242, + 125, + 37, + 37, + 103, + 139, + 91, + 108, + 225, + 21, + 40, + 154, + 126, + 9, + 192, + 247, + 66, + 40, + 105, + 19, + 4, + 117, + 166, + 45, + 112, + 199, + 230, + 98, + 134, + 23, + 24, + 189, + 187, + 235, + 37, + 42, + 145, + 248, + 85, + 59, + 105, + 112, + 84, + 154, + 193, + 124, + 160, + 168, + 75, + 248, + 210, + 129, + 121, + 182, + 248, + 249, + 123, + 64, + 17, + 57, + 160, + 77, + 32, + 53, + 218, + 12, + 104, + 188, + 58, + 42, + 152, + 191, + 244, + 99, + 17, + 232, + 96, + 58, + 184, + 198, + 102, + 230, + 206, + 221, + 138, + 222, + 8, + 156, + 51, + 140, + 117, + 18, + 8, + 127, + 164, + 192, + 138, + 192, + 116, + 147, + 50, + 64, + 224, + 248, + 12, + 81, + 39, + 31, + 73, + 70, + 145, + 45, + 119, + 199, + 32, + 143, + 24, + 229, + 14, + 207, + 161, + 136, + 0, + 123, + 173, + 81, + 81, + 13, + 203, + 255, + 154, + 168, + 153, + 73, + 65, + 174, + 167, + 165, + 54, + 176, + 234, + 240, + 230, + 139, + 86, + 209, + 194, + 151, + 133, + 2, + 141, + 188, + 253, + 140, + 198, + 239, + 161, + 85, + 197, + 252, + 112, + 230, + 210, + 25, + 182, + 181, + 11, + 56, + 93, + 40, + 36, + 67, + 0, + 46, + 128, + 85, + 27, + 143, + 229, + 187, + 212, + 50, + 3, + 14, + 206, + 55, + 28, + 218, + 205, + 40, + 59, + 39, + 243, + 194, + 121, + 225, + 114, + 167, + 80, + 48, + 226, + 31, + 5, + 158, + 80, + 203, + 25, + 251, + 212, + 55, + 178, + 27, + 121, + 10, + 225, + 22, + 84, + 156, + 239, + 16, + 37, + 37, + 175, + 45, + 77, + 29, + 162, + 228, + 100, + 254, + 236, + 112, + 163, + 21, + 11, + 179, + 84, + 27, + 64, + 159, + 222, + 35, + 102, + 17, + 130, + 135, + 52, + 217, + 147, + 112, + 113, + 117, + 10, + 45, + 244, + 31, + 13, + 134, + 67, + 111, + 215, + 231, + 154, + 19, + 96, + 183, + 61, + 238, + 150, + 8, + 72, + 72, + 118, + 11, + 228, + 100, + 84, + 244, + 191, + 225, + 176, + 208, + 226, + 83, + 53, + 72, + 69, + 225, + 98, + 4, + 220, + 203, + 228, + 213, + 36, + 131, + 62, + 192, + 4, + 87, + 193, + 142, + 211, + 88, + 37, + 245, + 84, + 188, + 200, + 117, + 157, + 176, + 221, + 174, + 101, + 131, + 157, + 28, + 19, + 23, + 30, + 166, + 74, + 84, + 225, + 149, + 234, + 205, + 169, + 127, + 6, + 34, + 233, + 234, + 88, + 204, + 156, + 97, + 45, + 20, + 14, + 12, + 141, + 125, + 60, + 81, + 87, + 218, + 58, + 255, + 116, + 205, + 62, + 101, + 105, + 241, + 235, + 141, + 163, + 126, + 51, + 183, + 97, + 223, + 53, + 178, + 105, + 4, + 45, + 189, + 132, + 179, + 9, + 93, + 68, + 157, + 164, + 34, + 41, + 72, + 150, + 235, + 45, + 212, + 83, + 212, + 65, + 218, + 222, + 47, + 218, + 40, + 28, + 184, + 39, + 206, + 139, + 234, + 252, + 188, + 239, + 75, + 193, + 162, + 38, + 129, + 75, + 54, + 205, + 215, + 27, + 192, + 7, + 105, + 16, + 116, + 185, + 111, + 62, + 54, + 148, + 25, + 49, + 50, + 153, + 149, + 74, + 179, + 78, + 30, + 218, + 204, + 1, + 157, + 114, + 249, + 147, + 76, + 81, + 100, + 27, + 197, + 142, + 22, + 71, + 14, + 196, + 224, + 197, + 178, + 183, + 91, + 114, + 242, + 85, + 153, + 133, + 148, + 64, + 210, + 218, + 137, + 87, + 133, + 10, + 155, + 156, + 158, + 98, + 84, + 216, + 40, + 157, + 160, + 78, + 42, + 156, + 50, + 247, + 48, + 149, + 14, + 202, + 62, + 233, + 37, + 137, + 39, + 103, + 21, + 24, + 241, + 48, + 245, + 147, + 242, + 92, + 85, + 24, + 24, + 58, + 171, + 146, + 246, + 103, + 190, + 57, + 208, + 107, + 6, + 147, + 207, + 8, + 3, + 161, + 226, + 240, + 133, + 235, + 224, + 11, + 17, + 91, + 224, + 65, + 201, + 90, + 119, + 57, + 250, + 206, + 1, + 70, + 81, + 225, + 173, + 71, + 96, + 140, + 13, + 224, + 74, + 156, + 35, + 31, + 203, + 147, + 227, + 5, + 109, + 150, + 47, + 212, + 16, + 73, + 201, + 10, + 186, + 119, + 111, + 57, + 26, + 139, + 171, + 177, + 169, + 227, + 182, + 77, + 243, + 195, + 115, + 87, + 204, + 22, + 163, + 49, + 105, + 3, + 80, + 90, + 199, + 228, + 215, + 22, + 4, + 79, + 213, + 83, + 208, + 136, + 234, + 37, + 95, + 169, + 219, + 201, + 123, + 64, + 163, + 8, + 111, + 56, + 97, + 85, + 212, + 146, + 236, + 108, + 16, + 69, + 51, + 240, + 238, + 57, + 199, + 44, + 37, + 67, + 221, + 20, + 237, + 104, + 33, + 30, + 250, + 74, + 159, + 137, + 116, + 192, + 40, + 137, + 216, + 149, + 106, + 238, + 29, + 34, + 168, + 200, + 141, + 171, + 136, + 204, + 197, + 77, + 83, + 53, + 32, + 70, + 45, + 44, + 253, + 172, + 187, + 92, + 202, + 10, + 28, + 234, + 187, + 27, + 78, + 115, + 92, + 121, + 210, + 128, + 111, + 247, + 122, + 218, + 74, + 238, + 110, + 179, + 240, + 224, + 238, + 14, + 197, + 5, + 20, + 141, + 89, + 66, + 54, + 36, + 168, + 142, + 147, + 24, + 211, + 110, + 132, + 4, + 207, + 59, + 195, + 154, + 5, + 139, + 204, + 10, + 107, + 180, + 154, + 165, + 191, + 18, + 64, + 248, + 98, + 77, + 185, + 62, + 74, + 197, + 46, + 129, + 28, + 3, + 148, + 144, + 53, + 119, + 211, + 42, + 29, + 242, + 174, + 20, + 241, + 220, + 99, + 226, + 238, + 152, + 183, + 17, + 198, + 182, + 175, + 55, + 33, + 22, + 108, + 195, + 184, + 176, + 239, + 38, + 62, + 32, + 146, + 37, + 200, + 9, + 218, + 111, + 77, + 241, + 100, + 197, + 148, + 127, + 50, + 164, + 150, + 114, + 64, + 115, + 97, + 144, + 98, + 19, + 176, + 27, + 251, + 64, + 169, + 10, + 73, + 124, + 154, + 20, + 135, + 231, + 230, + 178, + 204, + 30, + 37, + 54, + 204, + 100, + 209, + 109, + 163, + 15, + 34, + 43, + 223, + 122, + 121, + 200, + 111, + 91, + 90, + 110, + 236, + 133, + 92, + 217, + 49, + 229, + 5, + 124, + 240, + 122, + 178, + 92, + 85, + 23, + 215, + 246, + 78, + 67, + 113, + 29, + 59, + 196, + 22, + 173, + 67, + 141, + 156, + 18, + 63, + 67, + 65, + 14, + 1, + 61, + 235, + 104, + 143, + 70, + 109, + 121, + 154, + 149, + 215, + 66, + 176, + 137, + 186, + 105, + 102, + 176, + 56, + 179, + 210, + 195, + 139, + 140, + 104, + 164, + 99, + 160, + 19, + 230, + 196, + 56, + 191, + 58, + 225, + 38, + 41, + 237, + 47, + 32, + 113, + 72, + 189, + 61, + 167, + 35, + 99, + 26, + 201, + 88, + 133, + 63, + 86, + 10, + 239, + 47, + 128, + 53, + 64, + 162, + 62, + 172, + 239, + 104, + 181, + 146, + 36, + 151, + 174, + 72, + 135, + 4, + 86, + 150, + 92, + 102, + 130, + 126, + 175, + 165, + 175, + 150, + 67, + 147, + 59, + 107, + 200, + 41, + 177, + 155, + 191, + 189, + 209, + 211, + 68, + 44, + 154, + 37, + 249, + 3, + 182, + 177, + 9, + 104, + 13, + 9, + 92, + 212, + 230, + 138, + 13, + 147, + 130, + 136, + 170, + 199, + 23, + 102, + 12, + 250, + 128, + 10, + 173, + 131, + 202, + 128, + 170, + 9, + 59, + 209, + 194, + 130, + 244, + 15, + 70, + 229, + 107, + 53, + 226, + 20, + 230, + 42, + 24, + 80, + 254, + 199, + 41, + 17, + 145, + 255, + 103, + 86, + 76, + 239, + 99, + 15, + 221, + 3, + 45, + 26, + 220, + 239, + 223, + 202, + 211, + 246, + 55, + 156, + 187, + 66, + 31, + 218, + 36, + 95, + 55, + 224, + 54, + 89, + 138, + 207, + 136, + 80, + 181, + 9, + 136, + 48, + 171, + 14, + 232, + 120, + 73, + 93, + 252, + 2, + 157, + 181, + 213, + 231, + 55, + 217, + 217, + 55, + 128, + 206, + 154, + 119, + 189, + 253, + 36, + 31, + 51, + 248, + 110, + 66, + 173, + 191, + 122, + 76, + 125, + 209, + 250, + 245, + 253, + 96, + 210, + 108, + 142, + 32, + 90, + 146, + 27, + 106, + 243, + 11, + 114, + 109, + 109, + 181, + 101, + 49, + 191, + 79, + 109, + 100, + 8, + 247, + 117, + 147, + 159, + 61, + 39, + 109, + 114, + 235, + 125, + 60, + 163, + 245, + 217, + 206, + 43, + 81, + 172, + 21, + 133, + 191, + 138, + 78, + 161, + 54, + 90, + 154, + 211, + 34, + 0, + 17, + 218, + 162, + 166, + 187, + 30, + 188, + 246, + 217, + 47, + 96, + 91, + 46, + 45, + 0, + 248, + 88, + 60, + 56, + 143, + 192, + 107, + 115, + 40, + 134, + 35, + 216, + 86, + 220, + 104, + 162, + 30, + 179, + 139, + 98, + 41, + 192, + 68, + 213, + 14, + 38, + 214, + 1, + 116, + 14, + 212, + 228, + 41, + 105, + 252, + 0, + 98, + 118, + 121, + 193, + 92, + 217, + 196, + 103, + 56, + 69, + 123, + 33, + 7, + 208, + 194, + 0, + 216, + 123, + 230, + 251, + 176, + 12, + 24, + 226, + 48, + 36, + 165, + 48, + 19, + 207, + 89, + 30, + 145, + 75, + 145, + 164, + 197, + 180, + 209, + 91, + 194, + 112, + 73, + 42, + 62, + 71, + 37, + 49, + 237, + 192, + 205, + 169, + 57, + 38, + 215, + 185, + 145, + 29, + 119, + 216, + 113, + 136, + 225, + 227, + 81, + 175, + 96, + 232, + 216, + 100, + 88, + 46, + 98, + 229, + 32, + 190, + 226, + 114, + 227, + 33, + 203, + 60, + 225, + 51, + 143, + 84, + 206, + 30, + 213, + 47, + 168, + 175, + 164, + 94, + 199, + 21, + 136, + 242, + 70, + 36, + 241, + 42, + 135, + 218, + 113, + 86, + 172, + 112, + 166, + 84, + 108, + 123, + 133, + 187, + 68, + 231, + 237, + 115, + 226, + 204, + 187, + 18, + 133, + 25, + 153, + 230, + 122, + 92, + 35, + 12, + 249, + 248, + 180, + 0, + 66, + 249, + 201, + 9, + 79, + 115, + 52, + 112, + 111, + 205, + 122, + 188, + 38, + 94, + 146, + 90, + 201, + 27, + 233, + 84, + 149, + 178, + 14, + 164, + 232, + 127, + 178, + 222, + 149, + 210, + 73, + 253, + 97, + 174, + 253, + 175, + 48, + 226, + 231, + 144, + 180, + 59, + 167, + 209, + 190, + 166, + 41, + 224, + 114, + 169, + 202, + 37, + 54, + 128, + 33, + 219, + 65, + 52, + 95, + 73, + 145, + 27, + 58, + 231, + 168, + 168, + 98, + 250, + 217, + 31, + 78, + 231, + 137, + 104, + 158, + 131, + 224, + 132, + 150, + 6, + 253, + 150, + 78, + 12, + 251, + 135, + 123, + 208, + 103, + 142, + 108, + 86, + 151, + 215, + 196, + 70, + 43, + 201, + 53, + 126, + 111, + 1, + 231, + 125, + 243, + 78, + 99, + 59, + 89, + 114, + 39, + 15, + 102, + 208, + 212, + 27, + 22, + 134, + 176, + 146, + 16, + 225, + 195, + 56, + 35, + 75, + 105, + 40, + 115, + 131, + 79, + 132, + 34, + 159, + 47, + 46, + 238, + 55, + 13, + 117, + 20, + 76, + 11, + 75, + 154, + 103, + 146, + 97, + 102, + 228, + 99, + 99, + 181, + 218, + 81, + 53, + 194, + 11, + 211, + 96, + 127, + 199, + 223, + 18, + 39, + 196, + 182, + 172, + 209, + 27, + 108, + 185, + 83, + 80, + 38, + 239, + 147, + 238, + 143, + 36, + 217, + 196, + 33, + 177, + 31, + 90, + 167, + 176, + 98, + 34, + 122, + 92, + 203, + 77, + 106, + 228, + 87, + 245, + 242, + 197, + 174, + 195, + 54, + 128, + 77, + 10, + 113, + 47, + 171, + 246, + 138, + 38, + 176, + 44, + 59, + 246, + 4, + 11, + 127, + 163, + 228, + 205, + 48, + 234, + 223, + 138, + 10, + 42, + 225, + 44, + 13, + 130, + 79, + 224, + 140, + 97, + 82, + 86, + 142, + 122, + 212, + 188, + 150, + 74, + 163, + 198, + 219, + 128, + 30, + 91, + 74, + 236, + 139, + 63, + 180, + 157, + 157, + 77, + 143, + 84, + 34, + 13, + 73, + 40, + 186, + 61, + 91, + 56, + 148, + 250, + 184, + 224, + 138, + 33, + 114, + 10, + 69, + 96, + 230, + 117, + 246, + 214, + 179, + 17, + 227, + 145, + 81, + 213, + 10, + 249, + 40, + 158, + 184, + 54, + 103, + 227, + 31, + 206, + 224, + 209, + 83, + 165, + 53, + 218, + 56, + 2, + 224, + 74, + 75, + 192, + 135, + 221, + 179, + 141, + 32, + 92, + 94, + 244, + 157, + 6, + 115, + 28, + 28, + 225, + 26, + 150, + 201, + 129, + 158, + 57, + 44, + 112, + 14, + 138, + 227, + 12, + 239, + 249, + 209, + 9, + 130, + 50, + 88, + 196, + 166, + 1, + 164, + 142, + 246, + 165, + 75, + 111, + 246, + 106, + 29, + 136, + 229, + 249, + 123, + 211, + 133, + 114, + 5, + 68, + 47, + 168, + 155, + 131, + 78, + 96, + 117, + 14, + 99, + 78, + 251, + 245, + 9, + 55, + 44, + 172, + 190, + 194, + 233, + 14, + 221, + 114, + 68, + 68, + 139, + 54, + 29, + 190, + 144, + 10, + 121, + 54, + 149, + 9, + 200, + 132, + 213, + 11, + 179, + 45, + 99, + 10, + 119, + 188, + 171, + 44, + 182, + 108, + 5, + 107, + 147, + 112, + 235, + 204, + 90, + 164, + 53, + 15, + 29, + 35, + 182, + 217, + 83, + 129, + 8, + 1, + 131, + 177, + 168, + 73, + 142, + 47, + 80, + 70, + 199, + 209, + 52, + 111, + 196, + 188, + 1, + 84, + 52, + 99, + 139, + 144, + 184, + 201, + 102, + 184, + 59, + 178, + 180, + 0, + 246, + 79, + 161, + 36, + 72, + 139, + 194, + 109, + 41, + 21, + 41, + 29, + 103, + 47, + 222, + 227, + 215, + 229, + 192, + 113, + 139, + 156, + 12, + 0, + 240, + 21, + 227, + 38, + 50, + 67, + 158, + 213, + 119, + 136, + 173, + 92, + 44, + 219, + 210, + 18, + 233, + 70, + 175, + 7, + 224, + 131, + 116, + 66, + 158, + 197, + 112, + 25, + 63, + 157, + 74, + 202, + 231, + 87, + 131, + 93, + 241, + 159, + 238, + 100, + 241, + 188, + 70, + 204, + 167, + 186, + 152, + 228, + 169, + 54, + 130, + 7, + 52, + 181, + 67, + 86, + 163, + 43, + 240, + 35, + 62, + 137, + 49, + 251, + 10, + 232, + 152, + 222, + 73, + 44, + 78, + 143, + 180, + 227, + 102, + 23, + 102, + 120, + 138, + 230, + 148, + 69, + 170, + 239, + 61, + 151, + 176, + 94, + 192, + 200, + 159, + 78, + 210, + 252, + 20, + 232, + 120, + 144, + 31, + 238, + 36, + 142, + 193, + 128, + 86, + 143, + 2, + 205, + 100, + 167, + 132, + 40, + 129, + 108, + 79, + 95, + 227, + 202, + 150, + 39, + 157, + 204, + 173, + 149, + 253, + 113, + 200, + 205, + 58, + 178, + 6, + 152, + 184, + 68, + 42, + 91, + 1, + 111, + 52, + 69, + 131, + 3, + 166, + 27, + 212, + 97, + 8, + 135, + 238, + 27, + 68, + 2, + 196, + 159, + 125, + 180, + 12, + 1, + 91, + 252, + 2, + 177, + 165, + 43, + 220, + 176, + 47, + 101, + 160, + 231, + 175, + 204, + 1, + 60, + 198, + 122, + 30, + 27, + 186, + 128, + 211, + 239, + 68, + 151, + 139, + 17, + 135, + 79, + 149, + 130, + 107, + 131, + 255, + 44, + 16, + 133, + 232, + 104, + 29, + 230, + 157, + 155, + 12, + 250, + 30, + 203, + 54, + 227, + 7, + 54, + 1, + 164, + 90, + 30, + 128, + 18, + 152, + 209, + 91, + 148, + 164, + 237, + 25, + 131, + 246, + 203, + 87, + 95, + 156, + 119, + 142, + 62, + 185, + 120, + 137, + 34, + 127, + 101, + 7, + 157, + 101, + 59, + 110, + 199, + 152, + 191, + 247, + 40, + 159, + 222, + 31, + 28, + 181, + 243, + 158, + 218, + 169, + 30, + 243, + 165, + 127, + 64, + 203, + 26, + 104, + 117, + 149, + 128, + 58, + 53, + 178, + 63, + 214, + 63, + 149, + 128, + 6, + 201, + 138, + 138, + 197, + 127, + 142, + 115, + 6, + 147, + 22, + 253, + 41, + 48, + 67, + 134, + 24, + 252, + 53, + 223, + 15, + 4, + 208, + 207, + 8, + 161, + 19, + 46, + 150, + 56, + 20, + 24, + 69, + 171, + 160, + 90, + 228, + 212, + 238, + 29, + 60, + 106, + 11, + 77, + 232, + 92, + 126, + 9, + 171, + 109, + 253, + 213, + 214, + 13, + 226, + 190, + 251, + 24, + 246, + 196, + 114, + 60, + 0, + 106, + 70, + 105, + 126, + 68, + 200, + 189, + 245, + 155, + 92, + 151, + 75, + 166, + 101, + 190, + 6, + 101, + 229, + 37, + 171, + 71, + 218, + 104, + 66, + 64, + 175, + 138, + 142, + 227, + 160, + 105, + 79, + 59, + 92, + 78, + 233, + 20, + 63, + 245, + 29, + 97, + 125, + 171, + 188, + 23, + 121, + 12, + 199, + 125, + 69, + 10, + 57, + 41, + 19, + 127, + 24, + 50, + 85, + 118, + 209, + 19, + 79, + 102, + 178, + 220, + 190, + 141, + 95, + 145, + 211, + 56, + 99, + 186, + 205, + 220, + 240, + 21, + 22, + 62, + 225, + 117, + 174, + 200, + 221, + 157, + 201, + 160, + 255, + 235, + 121, + 105, + 14, + 140, + 9, + 90, + 28, + 51, + 65, + 245, + 167, + 34, + 88, + 144, + 168, + 216, + 140, + 70, + 145, + 254, + 179, + 160, + 225, + 188, + 127, + 181, + 196, + 50, + 162, + 77, + 6, + 167, + 119, + 158, + 54, + 15, + 191, + 104, + 14, + 73, + 116, + 47, + 6, + 134, + 12, + 139, + 225, + 73, + 239, + 96, + 74, + 42, + 67, + 157, + 178, + 251, + 218, + 103, + 120, + 42, + 176, + 154, + 157, + 130, + 122, + 215, + 196, + 56, + 81, + 70, + 170, + 235, + 251, + 205, + 109, + 224, + 131, + 67, + 169, + 72, + 150, + 244, + 175, + 223, + 89, + 142, + 125, + 37, + 89, + 20, + 221, + 202, + 77, + 51, + 20, + 207, + 229, + 243, + 199, + 49, + 193, + 12, + 59, + 57, + 152, + 128, + 203, + 205, + 73, + 226, + 200, + 192, + 208, + 108, + 195, + 87, + 220, + 96, + 196, + 68, + 110, + 159, + 164, + 119, + 79, + 32, + 134, + 121, + 201, + 40, + 243, + 237, + 65, + 63, + 210, + 69, + 34, + 61, + 51, + 212, + 245, + 26, + 61, + 182, + 155, + 82, + 243, + 128, + 98, + 192, + 205, + 181, + 193, + 125, + 175, + 137, + 211, + 109, + 242, + 4, + 73, + 10, + 158, + 48, + 52, + 100, + 220, + 171, + 19, + 67, + 219, + 95, + 28, + 40, + 212, + 237, + 144, + 40, + 136, + 229, + 78, + 231, + 178, + 176, + 224, + 182, + 101, + 107, + 117, + 195, + 140, + 195, + 168, + 184, + 49, + 140, + 28, + 9, + 93, + 195, + 107, + 153, + 166, + 148, + 203, + 115, + 57, + 155, + 152, + 125, + 26, + 147, + 180, + 36, + 228, + 138, + 226, + 252, + 141, + 87, + 125, + 44, + 253, + 193, + 32, + 139, + 24, + 201, + 236, + 10, + 96, + 151, + 106, + 108, + 89, + 103, + 140, + 40, + 149, + 242, + 109, + 82, + 150, + 73, + 142, + 120, + 159, + 98, + 161, + 98, + 239, + 55, + 209, + 141, + 33, + 105, + 204, + 99, + 157, + 48, + 64, + 50, + 185, + 189, + 101, + 14, + 203, + 140, + 75, + 202, + 90, + 167, + 153, + 83, + 96, + 140, + 77, + 107, + 183, + 21, + 125, + 119, + 33, + 182, + 249, + 203, + 136, + 151, + 77, + 46, + 132, + 22, + 197, + 76, + 68, + 33, + 179, + 196, + 111, + 60, + 169, + 49, + 204, + 254, + 162, + 29, + 133, + 11, + 172, + 116, + 33, + 114, + 77, + 88, + 72, + 188, + 229, + 123, + 148, + 69, + 159, + 55, + 164, + 226, + 208, + 91, + 178, + 166, + 97, + 52, + 50, + 33, + 84, + 158, + 36, + 25, + 6, + 41, + 173, + 150, + 147, + 140, + 227, + 150, + 16, + 130, + 168, + 5, + 190, + 14, + 84, + 250, + 58, + 254, + 135, + 190, + 111, + 109, + 60, + 76, + 132, + 241, + 53, + 234, + 101, + 217, + 96, + 73, + 155, + 75, + 68, + 135, + 58, + 2, + 158, + 87, + 212, + 205, + 245, + 183, + 149, + 120, + 130, + 202, + 136, + 184, + 29, + 209, + 85, + 62, + 229, + 165, + 79, + 53, + 210, + 7, + 62, + 200, + 27, + 228, + 41, + 64, + 249, + 66, + 190, + 147, + 162, + 63, + 204, + 139, + 165, + 111, + 114, + 182, + 150, + 109, + 66, + 129, + 36, + 16, + 67, + 102, + 236, + 129, + 210, + 143, + 111, + 224, + 184, + 233, + 255, + 39, + 82, + 17, + 69, + 229, + 30, + 36, + 179, + 155, + 153, + 88, + 53, + 47, + 68, + 12, + 132, + 47, + 22, + 248, + 238, + 2, + 113, + 62, + 123, + 101, + 16, + 211, + 194, + 70, + 22, + 247, + 100, + 51, + 160, + 184, + 123, + 9, + 38, + 103, + 246, + 105, + 192, + 109, + 75, + 136, + 34, + 107, + 92, + 191, + 94, + 171, + 81, + 148, + 233, + 94, + 84, + 212, + 213, + 41, + 18, + 208, + 126, + 163, + 243, + 190, + 33, + 162, + 160, + 200, + 217, + 249, + 39, + 49, + 141, + 139, + 48, + 222, + 198, + 136, + 153, + 61, + 43, + 32, + 177, + 192, + 241, + 20, + 53, + 222, + 22, + 102, + 71, + 38, + 8, + 77, + 98, + 233, + 44, + 19, + 46, + 110, + 70, + 81, + 195, + 85, + 5, + 146, + 248, + 222, + 203, + 15, + 19, + 21, + 155, + 121, + 168, + 12, + 157, + 76, + 74, + 30, + 90, + 150, + 203, + 5, + 88, + 225, + 240, + 152, + 249, + 131, + 27, + 167, + 86, + 204, + 68, + 98, + 226, + 153, + 104, + 60, + 198, + 135, + 195, + 15, + 179, + 232, + 218, + 211, + 190, + 43, + 25, + 77, + 89, + 247, + 63, + 214, + 87, + 172, + 139, + 91, + 173, + 131, + 88, + 10, + 113, + 104, + 56, + 15, + 165, + 233, + 190, + 5, + 231, + 253, + 47, + 238, + 63, + 102, + 201, + 252, + 240, + 84, + 206, + 253, + 53, + 145, + 221, + 187, + 255, + 76, + 255, + 192, + 41, + 180, + 141, + 40, + 87, + 190, + 12, + 139, + 110, + 46, + 72, + 141, + 145, + 34, + 106, + 67, + 21, + 97, + 190, + 132, + 163, + 115, + 48, + 162, + 51, + 239, + 37, + 174, + 18, + 113, + 214, + 89, + 188, + 93, + 75, + 252, + 24, + 51, + 106, + 62, + 87, + 20, + 166, + 228, + 237, + 56, + 126, + 215, + 142, + 195, + 59, + 250, + 67, + 115, + 38, + 197, + 119, + 26, + 110, + 206, + 95, + 101, + 58, + 216, + 108, + 72, + 173, + 68, + 181, + 26, + 134, + 15, + 52, + 222, + 194, + 3, + 4, + 176, + 2, + 121, + 148, + 170, + 132, + 77, + 185, + 108, + 126, + 116, + 102, + 135, + 176, + 78, + 59, + 2, + 143, + 91, + 36, + 253, + 124, + 132, + 156, + 160, + 130, + 114, + 167, + 228, + 224, + 157, + 51, + 221, + 196, + 143, + 162, + 223, + 18, + 96, + 153, + 29, + 106, + 140, + 100, + 148, + 199, + 21, + 215, + 34, + 234, + 137, + 214, + 70, + 189, + 84, + 176, + 52, + 62, + 210, + 40, + 57, + 80, + 68, + 72, + 80, + 42, + 245, + 161, + 171, + 190, + 169, + 221, + 16, + 167, + 54, + 4, + 99, + 147, + 12, + 112, + 227, + 61, + 175, + 118, + 8, + 110, + 188, + 16, + 236, + 49, + 205, + 231, + 182, + 49, + 1, + 162, + 243, + 189, + 217, + 69, + 83, + 146, + 86, + 24, + 104, + 80, + 223, + 204, + 222, + 238, + 162, + 143, + 193, + 69, + 137, + 34, + 133, + 222, + 15, + 153, + 51, + 136, + 242, + 165, + 138, + 237, + 68, + 65, + 126, + 77, + 203, + 229, + 28, + 249, + 194, + 142, + 43, + 140, + 16, + 1, + 35, + 192, + 12, + 162, + 66, + 157, + 55, + 123, + 206, + 213, + 139, + 108, + 47, + 82, + 5, + 195, + 242, + 158, + 72, + 202, + 243, + 58, + 46, + 12, + 32, + 76, + 140, + 187, + 42, + 46, + 239, + 148, + 12, + 25, + 10, + 199, + 190, + 229, + 3, + 143, + 31, + 245, + 77, + 247, + 213, + 123, + 240, + 69, + 229, + 146, + 125, + 147, + 69, + 213, + 183, + 198, + 48, + 113, + 41, + 92, + 38, + 161, + 159, + 187, + 175, + 76, + 40, + 82, + 134, + 214, + 237, + 162, + 36, + 192, + 120, + 140, + 25, + 245, + 227, + 52, + 225, + 69, + 86, + 129, + 198, + 181, + 179, + 143, + 81, + 145, + 201, + 77, + 70, + 149, + 187, + 184, + 35, + 115, + 63, + 83, + 156, + 4, + 8, + 250, + 57, + 101, + 250, + 127, + 0, + 200, + 178, + 161, + 29, + 26, + 29, + 136, + 79, + 7, + 50, + 23, + 8, + 214, + 91, + 132, + 32, + 229, + 129, + 143, + 114, + 75, + 163, + 104, + 199, + 226, + 229, + 125, + 21, + 230, + 217, + 252, + 213, + 195, + 233, + 251, + 238, + 74, + 223, + 241, + 18, + 232, + 237, + 180, + 116, + 134, + 77, + 76, + 49, + 83, + 250, + 223, + 68, + 10, + 12, + 140, + 180, + 4, + 161, + 25, + 16, + 59, + 75, + 56, + 125, + 57, + 129, + 63, + 45, + 134, + 141, + 175, + 237, + 226, + 108, + 54, + 186, + 194, + 201, + 215, + 79, + 120, + 104, + 146, + 84, + 119, + 118, + 135, + 68, + 172, + 235, + 177, + 132, + 48, + 30, + 182, + 243, + 165, + 37, + 37, + 78, + 245, + 100, + 59, + 53, + 128, + 234, + 177, + 98, + 223, + 156, + 246, + 91, + 226, + 15, + 71, + 13, + 107, + 61, + 75, + 41, + 181, + 73, + 107, + 131, + 147, + 25, + 195, + 118, + 48, + 31, + 35, + 183, + 44, + 53, + 175, + 75, + 180, + 6, + 88, + 111, + 25, + 76, + 23, + 35, + 99, + 114, + 252, + 17, + 58, + 46, + 176, + 140, + 18, + 249, + 94, + 128, + 35, + 144, + 167, + 95, + 14, + 142, + 168, + 50, + 43, + 211, + 221, + 179, + 116, + 88, + 79, + 137, + 120, + 156, + 189, + 8, + 214, + 112, + 13, + 3, + 170, + 7, + 10, + 69, + 208, + 0, + 81, + 209, + 144, + 35, + 216, + 226, + 225, + 52, + 16, + 163, + 43, + 128, + 114, + 238, + 24, + 64, + 88, + 68, + 7, + 140, + 253, + 23, + 0, + 44, + 86, + 37, + 0, + 170, + 67, + 207, + 52, + 187, + 172, + 243, + 11, + 189, + 225, + 27, + 152, + 192, + 99, + 122, + 223, + 100, + 123, + 19, + 44, + 27, + 142, + 233, + 100, + 241, + 0, + 101, + 13, + 248, + 22, + 211, + 219, + 82, + 144, + 62, + 221, + 189, + 9, + 235, + 40, + 144, + 84, + 204, + 243, + 30, + 144, + 18, + 69, + 141, + 223, + 42, + 213, + 223, + 166, + 144, + 233, + 89, + 168, + 30, + 140, + 100, + 115, + 239, + 253, + 107, + 41, + 197, + 33, + 209, + 134, + 92, + 154, + 169, + 135, + 93, + 202, + 186, + 83, + 213, + 237, + 127, + 1, + 33, + 85, + 80, + 247, + 124, + 89, + 98, + 46, + 29, + 6, + 7, + 155, + 82, + 12, + 127, + 21, + 54, + 113, + 31, + 220, + 44, + 18, + 32, + 10, + 151, + 190, + 59, + 59, + 75, + 7, + 31, + 166, + 225, + 96, + 73, + 155, + 117, + 109, + 181, + 44, + 29, + 112, + 6, + 4, + 9, + 110, + 213, + 85, + 74, + 110, + 147, + 98, + 57, + 78, + 74, + 25, + 197, + 163, + 71, + 107, + 52, + 143, + 243, + 185, + 233, + 137, + 157, + 103, + 69, + 94, + 160, + 99, + 93, + 62, + 251, + 113, + 29, + 201, + 69, + 236, + 202, + 149, + 236, + 24, + 7, + 182, + 156, + 145, + 202, + 119, + 143, + 123, + 113, + 166, + 9, + 229, + 21, + 110, + 252, + 152, + 235, + 148, + 154, + 196, + 85, + 0, + 157, + 154, + 16, + 45, + 204, + 184, + 167, + 228, + 88, + 29, + 139, + 29, + 136, + 212, + 22, + 198, + 228, + 204, + 139, + 118, + 130, + 126, + 246, + 139, + 247, + 34, + 16, + 91, + 247, + 29, + 90, + 77, + 15, + 146, + 116, + 12, + 81, + 229, + 196, + 27, + 124, + 23, + 59, + 23, + 152, + 51, + 217, + 43, + 39, + 246, + 109, + 180, + 201, + 226, + 27, + 80, + 27, + 174, + 193, + 18, + 138, + 222, + 36, + 205, + 182, + 236, + 46, + 231, + 75, + 117, + 117, + 3, + 134, + 189, + 242, + 113, + 50, + 27, + 245, + 224, + 122, + 7, + 39, + 38, + 6, + 12, + 168, + 19, + 213, + 214, + 160, + 253, + 83, + 176, + 97, + 196, + 156, + 116, + 80, + 160, + 147, + 149, + 89, + 27, + 48, + 103, + 56, + 10, + 252, + 53, + 231, + 118, + 254, + 203, + 248, + 255, + 88, + 214, + 245, + 6, + 242, + 141, + 241, + 72, + 191, + 105, + 101, + 217, + 221, + 24, + 150, + 180, + 205, + 69, + 11, + 208, + 233, + 125, + 227, + 83, + 121, + 83, + 87, + 138, + 177, + 16, + 125, + 108, + 193, + 78, + 62, + 148, + 226, + 188, + 62, + 75, + 174, + 149, + 79, + 44, + 213, + 71, + 121, + 157, + 69, + 215, + 192, + 58, + 202, + 231, + 63, + 104, + 188, + 45, + 164, + 255, + 30, + 250, + 136, + 6, + 232, + 199, + 32, + 45, + 125, + 245, + 23, + 140, + 180, + 176, + 114, + 116, + 87, + 146, + 162, + 121, + 18, + 225, + 142, + 151, + 6, + 76, + 154, + 27, + 232, + 5, + 196, + 51, + 92, + 174, + 85, + 151, + 255, + 149, + 110, + 189, + 19, + 217, + 186, + 165, + 175, + 94, + 65, + 250, + 165, + 86, + 158, + 162, + 253, + 168, + 233, + 18, + 27, + 182, + 109, + 226, + 81, + 40, + 204, + 92, + 97, + 116, + 0, + 42, + 193, + 46, + 66, + 194, + 141, + 139, + 46, + 38, + 110, + 172, + 67, + 247, + 242, + 229, + 48, + 252, + 176, + 0, + 131, + 86, + 107, + 57, + 191, + 128, + 59, + 48, + 56, + 252, + 236, + 160, + 62, + 94, + 7, + 100, + 39, + 245, + 96, + 4, + 90, + 175, + 101, + 253, + 11, + 166, + 233, + 44, + 127, + 83, + 121, + 34, + 17, + 184, + 26, + 228, + 194, + 178, + 100, + 137, + 91, + 30, + 213, + 48, + 29, + 144, + 11, + 33, + 192, + 110, + 233, + 8, + 221, + 182, + 208, + 196, + 94, + 51, + 215, + 34, + 180, + 96, + 44, + 5, + 143, + 160, + 103, + 60, + 151, + 168, + 157, + 32, + 192, + 250, + 13, + 5, + 116, + 134, + 243, + 14, + 149, + 210, + 128, + 118, + 27, + 182, + 253, + 4, + 79, + 66, + 89, + 159, + 226, + 9, + 99, + 148, + 126, + 95, + 4, + 177, + 105, + 250, + 198, + 139, + 231, + 31, + 186, + 229, + 108, + 140, + 131, + 161, + 108, + 4, + 46, + 193, + 95, + 20, + 163, + 240, + 74, + 18, + 121, + 11, + 206, + 193, + 102, + 29, + 50, + 113, + 209, + 115, + 1, + 110, + 211, + 114, + 206, + 212, + 18, + 188, + 3, + 146, + 170, + 38, + 137, + 111, + 251, + 70, + 12, + 239, + 238, + 187, + 43, + 136, + 84, + 5, + 221, + 115, + 203, + 181, + 77, + 181, + 252, + 168, + 148, + 207, + 64, + 124, + 101, + 242, + 190, + 234, + 218, + 63, + 241, + 6, + 117, + 44, + 75, + 115, + 165, + 1, + 101, + 165, + 29, + 107, + 193, + 26, + 131, + 103, + 92, + 183, + 178, + 204, + 128, + 70, + 192, + 108, + 87, + 173, + 182, + 174, + 158, + 173, + 206, + 217, + 123, + 221, + 86, + 109, + 100, + 56, + 19, + 71, + 183, + 68, + 84, + 82, + 183, + 21, + 206, + 50, + 247, + 250, + 109, + 107, + 89, + 141, + 152, + 115, + 123, + 71, + 250, + 242, + 100, + 213, + 74, + 219, + 65, + 91, + 158, + 130, + 71, + 236, + 222, + 235, + 240, + 234, + 9, + 228, + 35, + 185, + 15, + 75, + 89, + 220, + 169, + 179, + 7, + 215, + 92, + 129, + 112, + 205, + 131, + 141, + 100, + 202, + 141, + 188, + 112, + 137, + 221, + 163, + 209, + 135, + 219, + 246, + 245, + 52, + 110, + 161, + 84, + 161, + 189, + 228, + 155, + 191, + 63, + 18, + 142, + 34, + 77, + 251, + 167, + 151, + 242, + 166, + 81, + 187, + 115, + 79, + 204, + 232, + 178, + 2, + 5, + 142, + 176, + 197, + 163, + 254, + 20, + 72, + 74, + 29, + 15, + 238, + 170, + 49, + 130, + 77, + 108, + 98, + 106, + 163, + 207, + 112, + 89, + 31, + 159, + 234, + 153, + 103, + 161, + 107, + 242, + 213, + 64, + 134, + 213, + 157, + 110, + 54, + 49, + 222, + 125, + 177, + 148, + 68, + 53, + 126, + 134, + 52, + 186, + 155, + 243, + 239, + 255, + 161, + 45, + 236, + 161, + 114, + 255, + 59, + 150, + 210, + 220, + 37, + 88, + 235, + 23, + 13, + 4, + 254, + 98, + 109, + 233, + 23, + 100, + 29, + 173, + 241, + 76, + 224, + 85, + 112, + 99, + 136, + 91, + 49, + 222, + 37, + 244, + 102, + 184, + 107, + 181, + 2, + 195, + 231, + 148, + 72, + 58, + 230, + 85, + 210, + 22, + 52, + 66, + 98, + 142, + 53, + 60, + 29, + 180, + 34, + 237, + 148, + 188, + 71, + 167, + 23, + 53, + 81, + 16, + 91, + 125, + 112, + 57, + 55, + 185, + 57, + 20, + 60, + 251, + 45, + 243, + 164, + 89, + 174, + 132, + 157, + 111, + 124, + 225, + 209, + 20, + 249, + 157, + 179, + 13, + 39, + 26, + 229, + 98, + 221, + 177, + 111, + 52, + 88, + 247, + 166, + 115, + 226, + 155, + 251, + 152, + 119, + 87, + 237, + 106, + 35, + 147, + 8, + 139, + 201, + 91, + 171, + 126, + 157, + 243, + 58, + 223, + 124, + 17, + 156, + 238, + 211, + 182, + 204, + 63, + 187, + 215, + 156, + 247, + 88, + 10, + 63, + 209, + 146, + 128, + 43, + 63, + 47, + 88, + 161, + 108, + 62, + 189, + 88, + 27, + 167, + 3, + 98, + 102, + 220, + 155, + 192, + 10, + 11, + 116, + 195, + 143, + 50, + 117, + 239, + 129, + 252, + 237, + 124, + 163, + 23, + 91, + 131, + 54, + 101, + 228, + 38, + 181, + 140, + 52, + 49, + 141, + 151, + 33, + 45, + 62, + 230, + 160, + 225, + 208, + 72, + 195, + 113, + 238, + 12, + 71, + 192, + 153, + 185, + 221, + 202, + 64, + 81, + 60, + 168, + 97, + 197, + 169, + 129, + 48, + 87, + 135, + 62, + 64, + 33, + 243, + 103, + 78, + 251, + 206, + 1, + 147, + 116, + 130, + 221, + 219, + 226, + 51, + 201, + 90, + 187, + 176, + 126, + 120, + 210, + 17, + 77, + 39, + 175, + 242, + 112, + 137, + 135, + 96, + 57, + 30, + 145, + 213, + 231, + 154, + 193, + 20, + 244, + 247, + 203, + 128, + 227, + 182, + 139, + 244, + 253, + 122, + 8, + 176, + 201, + 197, + 45, + 42, + 35, + 53, + 108, + 40, + 86, + 38, + 124, + 190, + 172, + 246, + 37, + 131, + 53, + 35, + 240, + 107, + 38, + 175, + 115, + 124, + 126, + 152, + 135, + 48, + 114, + 70, + 133, + 179, + 22, + 202, + 68, + 56, + 63, + 24, + 155, + 92, + 141, + 13, + 53, + 92, + 16, + 116, + 223, + 202, + 232, + 139, + 40, + 74, + 190, + 46, + 251, + 246, + 199, + 30, + 234, + 89, + 58, + 90, + 183, + 130, + 99, + 175, + 227, + 110, + 88, + 96, + 211, + 173, + 61, + 35, + 132, + 172, + 119, + 6, + 184, + 56, + 88, + 123, + 203, + 144, + 65, + 243, + 207, + 178, + 34, + 245, + 14, + 181, + 3, + 61, + 165, + 50, + 210, + 203, + 45, + 21, + 14, + 47, + 125, + 117, + 10, + 56, + 208, + 122, + 111, + 211, + 155, + 10, + 32, + 82, + 80, + 211, + 127, + 2, + 157, + 90, + 200, + 206, + 237, + 52, + 124, + 47, + 54, + 20, + 239, + 163, + 169, + 241, + 9, + 49, + 129, + 179, + 121, + 158, + 76, + 198, + 249, + 153, + 189, + 62, + 53, + 106, + 236, + 101, + 142, + 203, + 24, + 201, + 214, + 70, + 27, + 189, + 180, + 128, + 42, + 153, + 58, + 245, + 107, + 91, + 114, + 111, + 116, + 109, + 66, + 200, + 67, + 103, + 88, + 19, + 178, + 146, + 29, + 219, + 2, + 47, + 244, + 211, + 43, + 28, + 76, + 84, + 231, + 34, + 188, + 87, + 248, + 144, + 1, + 81, + 34, + 62, + 123, + 107, + 138, + 21, + 185, + 97, + 82, + 243, + 233, + 199, + 238, + 120, + 144, + 163, + 181, + 181, + 170, + 75, + 41, + 222, + 254, + 134, + 67, + 148, + 173, + 252, + 108, + 105, + 36, + 152, + 162, + 249, + 177, + 25, + 187, + 118, + 6, + 5, + 218, + 211, + 126, + 78, + 48, + 236, + 102, + 30, + 14, + 243, + 69, + 15, + 213, + 253, + 189, + 31, + 68, + 148, + 137, + 138, + 36, + 193, + 10, + 230, + 111, + 111, + 245, + 35, + 159, + 156, + 37, + 215, + 71, + 223, + 177, + 118, + 244, + 19, + 254, + 225, + 158, + 93, + 149, + 125, + 142, + 253, + 143, + 0, + 50, + 195, + 68, + 45, + 169, + 248, + 213, + 111, + 125, + 132, + 249, + 52, + 172, + 110, + 14, + 84, + 204, + 190, + 208, + 26, + 104, + 41, + 141, + 169, + 41, + 120, + 114, + 14, + 64, + 113, + 3, + 116, + 244, + 155, + 23, + 164, + 156, + 222, + 125, + 152, + 91, + 169, + 155, + 34, + 191, + 223, + 160, + 237, + 21, + 23, + 253, + 73, + 67, + 70, + 64, + 200, + 31, + 194, + 106, + 181, + 240, + 71, + 98, + 109, + 228, + 54, + 109, + 173, + 34, + 68, + 148, + 57, + 26, + 168, + 189, + 106, + 166, + 71, + 6, + 112, + 210, + 199, + 213, + 30, + 11, + 251, + 158, + 145, + 19, + 163, + 223, + 103, + 127, + 251, + 209, + 147, + 121, + 244, + 90, + 28, + 234, + 182, + 12, + 109, + 98, + 86, + 47, + 44, + 162, + 54, + 104, + 244, + 238, + 194, + 13, + 125, + 103, + 253, + 18, + 1, + 211, + 66, + 14, + 114, + 246, + 54, + 232, + 168, + 251, + 134, + 94, + 106, + 125, + 248, + 165, + 125, + 87, + 16, + 189, + 58, + 101, + 209, + 221, + 124, + 248, + 2, + 165, + 58, + 188, + 219, + 118, + 177, + 56, + 1, + 97, + 204, + 12, + 77, + 21, + 105, + 162, + 212, + 218, + 96, + 30, + 168, + 65, + 127, + 236, + 164, + 66, + 2, + 235, + 163, + 21, + 154, + 131, + 140, + 216, + 5, + 230, + 245, + 242, + 50, + 41, + 93, + 91, + 15, + 55, + 128, + 204, + 221, + 26, + 241, + 170, + 105, + 62, + 200, + 91, + 58, + 86, + 159, + 141, + 36, + 50, + 114, + 143, + 209, + 162, + 94, + 153, + 212, + 104, + 97, + 187, + 173, + 34, + 151, + 183, + 164, + 34, + 70, + 189, + 53, + 54, + 206, + 238, + 170, + 156, + 180, + 122, + 73, + 111, + 193, + 210, + 74, + 166, + 29, + 244, + 221, + 106, + 128, + 117, + 187, + 253, + 222, + 101, + 180, + 244, + 248, + 58, + 97, + 67, + 203, + 166, + 159, + 23, + 205, + 222, + 150, + 178, + 196, + 71, + 64, + 41, + 121, + 127, + 39, + 244, + 98, + 156, + 131, + 92, + 119, + 49, + 136, + 250, + 13, + 131, + 179, + 219, + 141, + 163, + 172, + 41, + 231, + 74, + 211, + 83, + 6, + 220, + 175, + 235, + 191, + 85, + 223, + 215, + 5, + 152, + 58, + 93, + 106, + 19, + 52, + 162, + 120, + 104, + 172, + 73, + 206, + 53, + 159, + 48, + 13, + 168, + 168, + 115, + 207, + 234, + 189, + 169, + 106, + 193, + 226, + 188, + 165, + 103, + 93, + 120, + 101, + 216, + 13, + 130, + 204, + 190, + 64, + 171, + 234, + 153, + 94, + 129, + 142, + 167, + 173, + 202, + 129, + 42, + 181, + 250, + 29, + 220, + 28, + 223, + 248, + 75, + 232, + 172, + 95, + 113, + 247, + 223, + 240, + 41, + 104, + 209, + 195, + 90, + 89, + 62, + 8, + 74, + 228, + 200, + 10, + 42, + 37, + 188, + 96, + 207, + 107, + 73, + 103, + 64, + 130, + 83, + 47, + 74, + 48, + 123, + 227, + 102, + 246, + 0, + 217, + 139, + 38, + 137, + 184, + 201, + 170, + 236, + 84, + 101, + 197, + 177, + 219, + 29, + 195, + 91, + 116, + 152, + 81, + 68, + 90, + 24, + 77, + 201, + 17, + 222, + 140, + 174, + 6, + 246, + 115, + 62, + 22, + 199, + 115, + 118, + 134, + 158, + 74, + 135, + 241, + 174, + 159, + 97, + 68, + 127, + 219, + 172, + 115, + 217, + 247, + 116, + 224, + 224, + 208, + 225, + 189, + 65, + 101, + 159, + 149, + 66, + 133, + 180, + 15, + 67, + 61, + 239, + 44, + 47, + 71, + 121, + 136, + 172, + 17, + 149, + 136, + 140, + 161, + 85, + 199, + 195, + 158, + 229, + 172, + 234, + 164, + 244, + 107, + 252, + 46, + 13, + 160, + 145, + 224, + 184, + 212, + 197, + 19, + 77, + 205, + 102, + 141, + 153, + 49, + 114, + 69, + 41, + 108, + 123, + 44, + 236, + 55, + 136, + 90, + 4, + 81, + 229, + 72, + 98, + 207, + 33, + 232, + 150, + 109, + 11, + 84, + 240, + 37, + 47, + 78, + 125, + 171, + 15, + 223, + 153, + 185, + 155, + 174, + 161, + 168, + 57, + 122, + 75, + 74, + 182, + 236, + 8, + 76, + 109, + 204, + 229, + 70, + 38, + 23, + 203, + 213, + 160, + 25, + 133, + 35, + 23, + 30, + 248, + 95, + 67, + 50, + 170, + 86, + 83, + 54, + 211, + 34, + 21, + 33, + 81, + 80, + 153, + 12, + 149, + 5, + 235, + 252, + 237, + 171, + 95, + 184, + 40, + 158, + 244, + 225, + 96, + 76, + 53, + 66, + 223, + 250, + 193, + 210, + 56, + 250, + 74, + 16, + 115, + 4, + 249, + 42, + 240, + 219, + 232, + 71, + 163, + 71, + 51, + 32, + 43, + 210, + 106, + 209, + 62, + 62, + 188, + 221, + 105, + 113, + 166, + 10, + 65, + 79, + 157, + 13, + 106, + 115, + 12, + 64, + 77, + 146, + 42, + 149, + 159, + 218, + 212, + 53, + 164, + 52, + 30, + 162, + 208, + 210, + 112, + 159, + 214, + 8, + 73, + 99, + 249, + 238, + 204, + 90, + 19, + 122, + 251, + 94, + 184, + 157, + 57, + 152, + 17, + 67, + 164, + 98, + 192, + 27, + 116, + 223, + 168, + 32, + 88, + 222, + 230, + 213, + 153, + 100, + 173, + 44, + 194, + 69, + 121, + 183, + 131, + 106, + 153, + 220, + 184, + 216, + 223, + 77, + 205, + 162, + 42, + 105, + 6, + 77, + 98, + 241, + 132, + 85, + 44, + 166, + 190, + 72, + 188, + 91, + 217, + 163, + 39, + 157, + 111, + 122, + 121, + 89, + 208, + 9, + 214, + 196, + 187, + 42, + 220, + 148, + 230, + 90, + 115, + 248, + 107, + 177, + 118, + 20, + 125, + 30, + 163, + 68, + 131, + 16, + 91, + 42, + 162, + 203, + 98, + 75, + 196, + 136, + 140, + 1, + 251, + 112, + 129, + 94, + 79, + 55, + 138, + 171, + 75, + 60, + 233, + 77, + 149, + 218, + 116, + 87, + 116, + 70, + 24, + 27, + 223, + 54, + 45, + 7, + 101, + 232, + 65, + 217, + 167, + 44, + 201, + 71, + 130, + 26, + 166, + 69, + 203, + 122, + 122, + 114, + 239, + 241, + 180, + 172, + 2, + 128, + 9, + 27, + 184, + 166, + 137, + 0, + 119, + 78, + 29, + 205, + 226, + 101, + 171, + 243, + 106, + 101, + 21, + 183, + 253, + 68, + 14, + 19, + 84, + 71, + 152, + 121, + 190, + 78, + 48, + 77, + 149, + 22, + 111, + 193, + 59, + 25, + 217, + 171, + 99, + 99, + 49, + 91, + 1, + 86, + 78, + 219, + 161, + 232, + 81, + 242, + 132, + 69, + 166, + 254, + 219, + 20, + 142, + 145, + 245, + 46, + 158, + 160, + 149, + 159, + 13, + 55, + 250, + 58, + 108, + 254, + 247, + 36, + 40, + 23, + 184, + 126, + 243, + 149, + 55, + 223, + 122, + 177, + 119, + 47, + 128, + 228, + 112, + 156, + 232, + 117, + 216, + 33, + 71, + 197, + 134, + 11, + 35, + 235, + 87, + 219, + 59, + 48, + 234, + 50, + 150, + 146, + 167, + 179, + 209, + 206, + 13, + 126, + 82, + 135, + 46, + 58, + 172, + 219, + 172, + 226, + 54, + 51, + 98, + 143, + 45, + 149, + 210, + 165, + 226, + 220, + 207, + 141, + 54, + 129, + 206, + 139, + 96, + 139, + 56, + 48, + 250, + 9, + 137, + 4, + 223, + 207, + 52, + 75, + 44, + 34, + 97, + 190, + 182, + 23, + 56, + 6, + 102, + 7, + 229, + 113, + 153, + 27, + 67, + 146, + 84, + 80, + 187, + 199, + 50, + 12, + 66, + 119, + 44, + 222, + 204, + 133, + 222, + 128, + 199, + 68, + 175, + 159, + 206, + 187, + 205, + 215, + 8, + 129, + 150, + 169, + 8, + 11, + 20, + 244, + 246, + 250, + 173, + 108, + 86, + 179, + 144, + 128, + 8, + 166, + 201, + 189, + 78, + 247, + 219, + 91, + 97, + 90, + 82, + 141, + 104, + 8, + 82, + 114, + 182, + 121, + 100, + 162, + 107, + 77, + 18, + 146, + 227, + 93, + 201, + 224, + 215, + 177, + 72, + 3, + 105, + 88, + 212, + 9, + 139, + 134, + 171, + 141, + 192, + 49, + 183, + 4, + 210, + 39, + 236, + 35, + 107, + 59, + 223, + 91, + 195, + 41, + 168, + 133, + 3, + 64, + 201, + 150, + 194, + 118, + 247, + 248, + 197, + 197, + 182, + 35, + 65, + 205, + 54, + 171, + 200, + 33, + 227, + 164, + 159, + 214, + 139, + 6, + 254, + 27, + 53, + 8, + 110, + 56, + 23, + 207, + 4, + 43, + 223, + 152, + 146, + 11, + 91, + 169, + 156, + 213, + 166, + 254, + 154, + 62, + 62, + 245, + 254, + 21, + 14, + 221, + 40, + 239, + 77, + 44, + 246, + 152, + 29, + 160, + 46, + 62, + 179, + 204, + 248, + 228, + 164, + 14, + 35, + 73, + 103, + 126, + 245, + 206, + 109, + 42, + 175, + 31, + 54, + 123, + 83, + 75, + 72, + 57, + 41, + 153, + 186, + 123, + 215, + 88, + 110, + 251, + 92, + 98, + 123, + 220, + 239, + 246, + 125, + 87, + 233, + 202, + 120, + 19, + 49, + 16, + 213, + 188, + 77, + 200, + 14, + 162, + 104, + 73, + 32, + 213, + 61, + 210, + 15, + 135, + 28, + 186, + 48, + 97, + 73, + 247, + 211, + 157, + 40, + 129, + 141, + 178, + 152, + 57, + 225, + 120, + 125, + 92, + 203, + 203, + 156, + 10, + 34, + 167, + 53, + 59, + 199, + 97, + 108, + 50, + 139, + 173, + 246, + 142, + 58, + 203, + 193, + 70, + 104, + 28, + 231, + 233, + 158, + 162, + 24, + 55, + 254, + 180, + 99, + 58, + 41, + 183, + 59, + 227, + 253, + 82, + 237, + 6, + 126, + 123, + 38, + 136, + 215, + 5, + 23, + 30, + 10, + 253, + 69, + 218, + 161, + 183, + 80, + 244, + 9, + 68, + 140, + 31, + 17, + 0, + 170, + 54, + 61, + 76, + 23, + 183, + 247, + 140, + 197, + 6, + 245, + 51, + 213, + 106, + 191, + 146, + 150, + 111, + 230, + 50, + 118, + 42, + 230, + 138, + 111, + 121, + 159, + 208, + 22, + 212, + 26, + 227, + 171, + 137, + 10, + 198, + 57, + 202, + 250, + 254, + 220, + 6, + 177, + 176, + 126, + 0, + 190, + 35, + 69, + 214, + 72, + 221, + 43, + 58, + 236, + 90, + 29, + 119, + 103, + 157, + 8, + 65, + 182, + 70, + 129, + 68, + 194, + 230, + 155, + 172, + 234, + 104, + 18, + 8, + 70, + 253, + 13, + 224, + 63, + 137, + 188, + 103, + 206, + 50, + 98, + 152, + 26, + 196, + 131, + 252, + 10, + 106, + 167, + 71, + 164, + 174, + 167, + 23, + 7, + 9, + 168, + 227, + 140, + 117, + 86, + 56, + 39, + 43, + 252, + 213, + 236, + 178, + 124, + 103, + 34, + 187, + 54, + 218, + 109, + 235, + 21, + 252, + 124, + 56, + 167, + 227, + 33, + 166, + 230, + 69, + 233, + 176, + 219, + 245, + 203, + 57, + 164, + 90, + 64, + 63, + 113, + 184, + 27, + 22, + 197, + 114, + 206, + 71, + 24, + 159, + 151, + 143, + 96, + 108, + 93, + 124, + 57, + 62, + 179, + 218, + 46, + 179, + 39, + 77, + 136, + 99, + 114, + 165, + 229, + 95, + 121, + 185, + 129, + 67, + 92, + 121, + 155, + 98, + 112, + 54, + 139, + 50, + 134, + 138, + 14, + 39, + 53, + 7, + 89, + 220, + 57, + 175, + 57, + 225, + 51, + 125, + 166, + 204, + 188, + 162, + 20, + 9, + 5, + 12, + 113, + 170, + 132, + 193, + 21, + 3, + 4, + 38, + 233, + 209, + 22, + 126, + 68, + 105, + 67, + 71, + 51, + 43, + 47, + 131, + 194, + 202, + 180, + 157, + 149, + 169, + 76, + 146, + 95, + 78, + 141, + 232, + 137, + 185, + 201, + 30, + 89, + 200, + 10, + 169, + 160, + 177, + 216, + 247, + 137, + 240, + 6, + 85, + 63, + 4, + 90, + 25, + 124, + 178, + 13, + 179, + 116, + 65, + 204, + 169, + 89, + 113, + 234, + 162, + 109, + 166, + 33, + 220, + 190, + 34, + 168, + 91, + 164, + 53, + 81, + 187, + 48, + 247, + 20, + 249, + 190, + 253, + 72, + 239, + 191, + 212, + 141, + 97, + 50, + 81, + 164, + 95, + 132, + 74, + 74, + 201, + 134, + 45, + 53, + 184, + 236, + 193, + 6, + 197, + 176, + 106, + 184, + 45, + 244, + 91, + 103, + 29, + 56, + 76, + 22, + 131, + 194, + 24, + 143, + 250, + 11, + 28, + 15, + 59, + 58, + 104, + 107, + 224, + 94, + 81, + 125, + 50, + 217, + 153, + 183, + 48, + 27, + 214, + 239, + 61, + 114, + 124, + 98, + 241, + 10, + 114, + 34, + 24, + 113, + 168, + 65, + 96, + 189, + 70, + 107, + 33, + 139, + 24, + 243, + 183, + 158, + 9, + 181, + 20, + 75, + 92, + 10, + 72, + 102, + 122, + 60, + 158, + 161, + 112, + 201, + 122, + 174, + 113, + 160, + 206, + 158, + 176, + 87, + 170, + 31, + 74, + 105, + 178, + 161, + 65, + 251, + 58, + 18, + 163, + 5, + 41, + 112, + 190, + 94, + 195, + 230, + 211, + 101, + 194, + 245, + 40, + 151, + 88, + 58, + 107, + 10, + 22, + 135, + 115, + 155, + 178, + 43, + 93, + 152, + 70, + 139, + 58, + 193, + 52, + 11, + 12, + 125, + 212, + 18, + 95, + 112, + 3, + 128, + 15, + 227, + 188, + 173, + 245, + 127, + 167, + 203, + 224, + 242, + 214, + 223, + 160, + 192, + 229, + 74, + 155, + 33, + 211, + 105, + 109, + 128, + 1, + 59, + 145, + 56, + 119, + 33, + 73, + 171, + 221, + 101, + 25, + 253, + 7, + 196, + 103, + 125, + 112, + 198, + 192, + 26, + 70, + 92, + 187, + 131, + 157, + 148, + 193, + 205, + 10, + 114, + 24, + 148, + 62, + 182, + 50, + 219, + 232, + 223, + 243, + 188, + 231, + 87, + 29, + 1, + 89, + 102, + 183, + 119, + 217, + 70, + 29, + 69, + 182, + 244, + 8, + 238, + 110, + 55, + 227, + 205, + 194, + 208, + 96, + 12, + 169, + 110, + 63, + 140, + 60, + 80, + 255, + 38, + 200, + 190, + 165, + 208, + 88, + 159, + 206, + 146, + 94, + 144, + 222, + 75, + 141, + 33, + 198, + 16, + 185, + 244, + 190, + 127, + 237, + 247, + 94, + 203, + 35, + 66, + 248, + 18, + 150, + 86, + 201, + 164, + 60, + 227, + 241, + 51, + 29, + 94, + 175, + 215, + 223, + 227, + 199, + 134, + 57, + 44, + 55, + 225, + 231, + 127, + 64, + 54, + 121, + 44, + 62, + 221, + 192, + 232, + 147, + 23, + 107, + 39, + 46, + 50, + 159, + 138, + 110, + 233, + 94, + 187, + 13, + 129, + 145, + 95, + 68, + 126, + 183, + 100, + 119, + 78, + 250, + 64, + 61, + 139, + 51, + 163, + 97, + 240, + 224, + 151, + 46, + 187, + 11, + 200, + 61, + 166, + 197, + 168, + 83, + 217, + 156, + 7, + 87, + 149, + 109, + 86, + 168, + 155, + 242, + 24, + 59, + 218, + 56, + 19, + 115, + 43, + 57, + 172, + 5, + 130, + 251, + 225, + 249, + 155, + 232, + 173, + 185, + 234, + 52, + 49, + 133, + 78, + 205, + 85, + 77, + 222, + 114, + 217, + 71, + 219, + 124, + 232, + 38, + 136, + 8, + 15, + 193, + 158, + 164, + 98, + 85, + 102, + 71, + 179, + 58, + 218, + 180, + 63, + 183, + 107, + 104, + 9, + 6, + 124, + 201, + 14, + 3, + 251, + 241, + 15, + 39, + 22, + 51, + 215, + 217, + 180, + 161, + 172, + 177, + 171, + 127, + 243, + 96, + 62, + 4, + 135, + 95, + 39, + 101, + 148, + 36, + 178, + 134, + 133, + 92, + 124, + 228, + 152, + 165, + 160, + 85, + 2, + 243, + 204, + 39, + 166, + 170, + 68, + 185, + 71, + 173, + 43, + 234, + 16, + 13, + 18, + 54, + 154, + 86, + 100, + 208, + 26, + 205, + 119, + 97, + 101, + 127, + 219, + 111, + 153, + 55, + 153, + 250, + 215, + 87, + 69, + 96, + 216, + 193, + 110, + 106, + 244, + 179, + 156, + 125, + 199, + 95, + 3, + 146, + 212, + 135, + 30, + 26, + 45, + 135, + 142, + 114, + 64, + 113, + 59, + 44, + 218, + 196, + 38, + 31, + 32, + 127, + 29, + 172, + 196, + 207, + 110, + 90, + 235, + 177, + 84, + 146, + 20, + 33, + 35, + 212, + 5, + 181, + 126, + 168, + 253, + 209, + 246, + 142, + 210, + 153, + 93, + 205, + 162, + 209, + 234, + 10, + 225, + 86, + 53, + 145, + 92, + 231, + 57, + 6, + 234, + 103, + 195, + 207, + 93, + 23, + 183, + 49, + 163, + 105, + 225, + 35, + 135, + 17, + 206, + 54, + 101, + 24, + 153, + 200, + 53, + 63, + 195, + 75, + 13, + 56, + 17, + 186, + 248, + 34, + 140, + 197, + 76, + 142, + 68, + 45, + 81, + 83, + 78, + 219, + 83, + 174, + 214, + 129, + 196, + 47, + 69, + 82, + 156, + 179, + 130, + 76, + 10, + 252, + 222, + 97, + 231, + 61, + 143, + 80, + 188, + 198, + 95, + 70, + 48, + 190, + 157, + 68, + 202, + 76, + 35, + 251, + 112, + 150, + 68, + 71, + 236, + 47, + 186, + 166, + 188, + 232, + 78, + 164, + 41, + 132, + 76, + 79, + 9, + 17, + 237, + 82, + 155, + 16, + 149, + 198, + 31, + 220, + 218, + 21, + 37, + 0, + 40, + 109, + 121, + 19, + 105, + 36, + 43, + 192, + 120, + 164, + 186, + 74, + 151, + 214, + 116, + 3, + 76, + 188, + 46, + 163, + 71, + 192, + 27, + 227, + 20, + 61, + 139, + 240, + 229, + 119, + 123, + 98, + 255, + 39, + 24, + 33, + 6, + 240, + 161, + 27, + 64, + 109, + 76, + 158, + 95, + 101, + 137, + 79, + 32, + 39, + 91, + 155, + 51, + 68, + 35, + 153, + 150, + 141, + 134, + 206, + 255, + 21, + 74, + 60, + 28, + 87, + 126, + 236, + 55, + 174, + 135, + 28, + 92, + 101, + 181, + 91, + 192, + 134, + 253, + 124, + 149, + 198, + 204, + 147, + 248, + 26, + 92, + 160, + 186, + 168, + 52, + 249, + 33, + 170, + 220, + 47, + 245, + 44, + 167, + 35, + 242, + 20, + 221, + 8, + 240, + 89, + 27, + 16, + 122, + 98, + 97, + 3, + 63, + 202, + 148, + 121, + 34, + 175, + 245, + 242, + 47, + 75, + 36, + 235, + 224, + 175, + 64, + 53, + 87, + 216, + 238, + 1, + 145, + 212, + 248, + 3, + 161, + 102, + 193, + 49, + 58, + 60, + 155, + 23, + 65, + 152, + 231, + 184, + 146, + 16, + 231, + 24, + 204, + 40, + 178, + 78, + 23, + 86, + 190, + 62, + 53, + 140, + 47, + 223, + 107, + 130, + 101, + 235, + 253, + 144, + 56, + 45, + 164, + 43, + 111, + 168, + 189, + 55, + 252, + 24, + 125, + 21, + 78, + 70, + 152, + 70, + 163, + 39, + 108, + 195, + 158, + 1, + 143, + 91, + 217, + 168, + 36, + 42, + 0, + 150, + 17, + 91, + 140, + 140, + 212, + 245, + 152, + 89, + 255, + 82, + 224, + 119, + 105, + 98, + 109, + 83, + 10, + 251, + 12, + 135, + 188, + 54, + 30, + 0, + 250, + 56, + 49, + 212, + 64, + 170, + 218, + 140, + 188, + 51, + 226, + 216, + 187, + 43, + 48, + 93, + 3, + 87, + 4, + 67, + 71, + 181, + 85, + 223, + 128, + 85, + 57, + 31, + 199, + 40, + 167, + 91, + 230, + 173, + 247, + 198, + 76, + 44, + 54, + 152, + 17, + 57, + 96, + 113, + 69, + 245, + 13, + 216, + 124, + 63, + 7, + 68, + 137, + 52, + 209, + 185, + 249, + 229, + 201, + 101, + 47, + 108, + 101, + 46, + 51, + 211, + 47, + 167, + 97, + 130, + 7, + 211, + 166, + 92, + 255, + 51, + 45, + 146, + 177, + 225, + 53, + 203, + 215, + 32, + 14, + 15, + 169, + 59, + 220, + 175, + 89, + 75, + 216, + 178, + 18, + 97, + 24, + 58, + 218, + 98, + 66, + 51, + 156, + 185, + 204, + 102, + 24, + 144, + 12, + 64, + 175, + 76, + 68, + 151, + 219, + 81, + 18, + 220, + 91, + 185, + 77, + 120, + 102, + 39, + 169, + 61, + 128, + 97, + 92, + 36, + 245, + 177, + 216, + 33, + 243, + 147, + 59, + 84, + 8, + 186, + 131, + 116, + 124, + 123, + 3, + 46, + 192, + 223, + 22, + 243, + 3, + 207, + 95, + 253, + 247, + 224, + 64, + 82, + 183, + 95, + 163, + 11, + 178, + 86, + 113, + 65, + 18, + 90, + 201, + 190, + 164, + 157, + 175, + 229, + 166, + 10, + 15, + 14, + 226, + 237, + 181, + 242, + 141, + 144, + 193, + 209, + 159, + 98, + 46, + 5, + 29, + 68, + 73, + 44, + 46, + 131, + 138, + 20, + 105, + 19, + 155, + 3, + 135, + 135, + 115, + 167, + 92, + 158, + 204, + 95, + 182, + 213, + 6, + 98, + 15, + 193, + 199, + 253, + 14, + 139, + 193, + 140, + 189, + 86, + 203, + 193, + 168, + 232, + 45, + 173, + 231, + 206, + 124, + 153, + 26, + 228, + 59, + 14, + 206, + 208, + 186, + 242, + 221, + 181, + 188, + 93, + 40, + 225, + 139, + 101, + 4, + 106, + 14, + 125, + 49, + 54, + 161, + 128, + 70, + 130, + 33, + 248, + 209, + 179, + 224, + 106, + 197, + 111, + 180, + 255, + 104, + 191, + 137, + 72, + 196, + 63, + 149, + 206, + 109, + 111, + 62, + 113, + 229, + 61, + 206, + 61, + 48, + 35, + 180, + 136, + 168, + 65, + 158, + 36, + 224, + 43, + 136, + 240, + 139, + 148, + 28, + 46, + 149, + 220, + 194, + 230, + 28, + 159, + 203, + 147, + 171, + 242, + 218, + 214, + 42, + 220, + 127, + 227, + 95, + 18, + 138, + 220, + 69, + 78, + 154, + 171, + 185, + 24, + 58, + 10, + 145, + 1, + 180, + 117, + 255, + 219, + 250, + 123, + 57, + 100, + 98, + 15, + 127, + 219, + 82, + 5, + 154, + 62, + 156, + 99, + 124, + 21, + 142, + 254, + 239, + 5, + 111, + 179, + 92, + 221, + 81, + 99, + 144, + 185, + 193, + 242, + 173, + 182, + 228, + 69, + 137, + 109, + 202, + 162, + 59, + 80, + 226, + 28, + 215, + 3, + 134, + 139, + 178, + 38, + 63, + 93, + 44, + 162, + 250, + 184, + 56, + 204, + 250, + 227, + 109, + 49, + 79, + 167, + 199, + 34, + 181, + 184, + 167, + 75, + 4, + 147, + 224, + 168, + 166, + 93, + 66, + 152, + 96, + 141, + 25, + 115, + 203, + 202, + 124, + 27, + 247, + 49, + 171, + 243, + 27, + 174, + 91, + 71, + 39, + 140, + 247, + 180, + 90, + 43, + 121, + 223, + 168, + 59, + 107, + 92, + 164, + 159, + 176, + 168, + 47, + 131, + 43, + 37, + 180, + 199, + 92, + 170, + 207, + 119, + 245, + 69, + 82, + 213, + 183, + 24, + 195, + 49, + 95, + 15, + 205, + 220, + 228, + 159, + 93, + 220, + 208, + 13, + 187, + 126, + 132, + 234, + 190, + 236, + 54, + 87, + 190, + 71, + 3, + 239, + 250, + 247, + 53, + 32, + 187, + 194, + 246, + 249, + 121, + 228, + 16, + 228, + 43, + 37, + 109, + 62, + 51, + 107, + 180, + 26, + 241, + 219, + 253, + 33, + 174, + 220, + 223, + 39, + 155, + 80, + 49, + 45, + 107, + 204, + 83, + 75, + 27, + 239, + 91, + 20, + 178, + 138, + 196, + 74, + 192, + 11, + 95, + 106, + 84, + 152, + 5, + 96, + 106, + 88, + 244, + 183, + 73, + 72, + 226, + 21, + 94, + 132, + 115, + 12, + 107, + 197, + 134, + 74, + 49, + 74, + 207, + 224, + 151, + 42, + 170, + 188, + 53, + 15, + 182, + 50, + 154, + 110, + 96, + 208, + 81, + 165, + 115, + 184, + 202, + 69, + 93, + 18, + 234, + 55, + 233, + 165, + 69, + 226, + 95, + 252, + 216, + 152, + 146, + 62, + 186, + 187, + 108, + 28, + 98, + 98, + 25, + 32, + 67, + 157, + 147, + 117, + 182, + 58, + 32, + 31, + 145, + 83, + 59, + 68, + 60, + 167, + 140, + 24, + 182, + 226, + 32, + 102, + 173, + 228, + 135, + 4, + 33, + 224, + 52, + 199, + 246, + 128, + 203, + 35, + 63, + 149, + 192, + 37, + 223, + 65, + 28, + 39, + 11, + 65, + 69, + 98, + 71, + 71, + 86, + 183, + 6, + 43, + 35, + 163, + 227, + 45, + 144, + 86, + 223, + 172, + 241, + 173, + 151, + 83, + 237, + 221, + 2, + 146, + 32, + 153, + 227, + 78, + 87, + 78, + 100, + 113, + 49, + 109, + 45, + 57, + 166, + 236, + 116, + 246, + 188, + 251, + 61, + 150, + 204, + 130, + 113, + 20, + 115, + 99, + 236, + 14, + 16, + 35, + 218, + 168, + 113, + 232, + 172, + 95, + 155, + 113, + 6, + 72, + 218, + 106, + 212, + 2, + 194, + 192, + 61, + 160, + 90, + 168, + 51, + 15, + 219, + 36, + 148, + 101, + 111, + 232, + 96, + 82, + 233, + 152, + 103, + 176, + 106, + 248, + 135, + 215, + 128, + 252, + 169, + 143, + 16, + 35, + 101, + 205, + 180, + 203, + 175, + 91, + 213, + 135, + 43, + 120, + 97, + 3, + 141, + 89, + 171, + 148, + 235, + 187, + 149, + 50, + 44, + 207, + 65, + 203, + 27, + 235, + 241, + 58, + 180, + 239, + 139, + 63, + 155, + 49, + 104, + 65, + 229, + 107, + 108, + 248, + 178, + 137, + 87, + 195, + 97, + 124, + 207, + 201, + 192, + 25, + 226, + 126, + 2, + 115, + 219, + 5, + 199, + 135, + 161, + 205, + 179, + 113, + 187, + 77, + 172, + 13, + 5, + 66, + 232, + 21, + 2, + 73, + 182, + 56, + 81, + 244, + 4, + 252, + 159, + 86, + 156, + 138, + 2, + 105, + 204, + 32, + 100, + 255, + 134, + 198, + 32, + 187, + 143, + 116, + 139, + 37, + 197, + 120, + 112, + 2, + 153, + 59, + 17, + 96, + 18, + 249, + 50, + 208, + 218, + 83, + 225, + 209, + 131, + 192, + 45, + 13, + 148, + 92, + 35, + 252, + 142, + 14, + 238, + 69, + 195, + 123, + 75, + 18, + 128, + 199, + 31, + 95, + 80, + 142, + 74, + 114, + 71, + 68, + 102, + 181, + 100, + 202, + 7, + 70, + 179, + 21, + 16, + 118, + 46, + 134, + 202, + 220, + 153, + 166, + 7, + 24, + 108, + 151, + 240, + 84, + 223, + 39, + 235, + 76, + 6, + 192, + 182, + 244, + 83, + 49, + 53, + 121, + 134, + 10, + 86, + 173, + 163, + 139, + 80, + 155, + 192, + 228, + 244, + 207, + 204, + 120, + 122, + 99, + 62, + 165, + 162, + 22, + 67, + 25, + 21, + 15, + 160, + 176, + 112, + 84, + 25, + 36, + 7, + 104, + 40, + 70, + 180, + 204, + 222, + 197, + 113, + 233, + 10, + 70, + 160, + 105, + 216, + 163, + 189, + 4, + 169, + 207, + 94, + 72, + 109, + 212, + 182, + 251, + 46, + 199, + 50, + 197, + 9, + 143, + 28, + 126, + 82, + 125, + 70, + 22, + 7, + 230, + 112, + 83, + 46, + 150, + 188, + 78, + 178, + 29, + 139, + 111, + 187, + 59, + 155, + 47, + 121, + 60, + 180, + 95, + 232, + 109, + 82, + 81, + 166, + 83, + 47, + 167, + 4, + 43, + 132, + 161, + 201, + 2, + 59, + 19, + 55, + 201, + 170, + 116, + 30, + 105, + 197, + 176, + 158, + 6, + 147, + 83, + 2, + 196, + 9, + 4, + 234, + 5, + 54, + 149, + 28, + 231, + 83, + 65, + 254, + 164, + 188, + 227, + 194, + 233, + 18, + 84, + 21, + 24, + 184, + 230, + 201, + 190, + 195, + 224, + 236, + 206, + 229, + 56, + 174, + 178, + 3, + 177, + 181, + 212, + 152, + 239, + 33, + 138, + 8, + 176, + 197, + 214, + 107, + 160, + 97, + 175, + 3, + 179, + 130, + 159, + 158, + 89, + 106, + 236, + 176, + 137, + 13, + 83, + 237, + 4, + 36, + 241, + 11, + 153, + 230, + 163, + 117, + 122, + 145, + 206, + 15, + 85, + 24, + 167, + 163, + 237, + 101, + 17, + 170, + 224, + 160, + 90, + 33, + 67, + 55, + 48, + 67, + 77, + 111, + 169, + 246, + 18, + 185, + 62, + 192, + 163, + 82, + 38, + 138, + 62, + 182, + 123, + 78, + 228, + 244, + 173, + 144, + 80, + 53, + 222, + 28, + 38, + 189, + 30, + 178, + 134, + 19, + 62, + 149, + 153, + 217, + 81, + 154, + 1, + 191, + 34, + 36, + 230, + 208, + 162, + 167, + 119, + 206, + 110, + 8, + 29, + 203, + 8, + 113, + 35, + 240, + 199, + 200, + 177, + 245, + 142, + 183, + 234, + 124, + 170, + 251, + 215, + 88, + 16, + 110, + 113, + 132, + 39, + 17, + 35, + 61, + 154, + 229, + 208, + 26, + 92, + 157, + 43, + 119, + 189, + 22, + 128, + 156, + 196, + 15, + 220, + 33, + 52, + 40, + 251, + 23, + 255, + 174, + 208, + 119, + 187, + 74, + 64, + 189, + 128, + 173, + 104, + 58, + 199, + 176, + 89, + 6, + 106, + 105, + 171, + 211, + 185, + 212, + 129, + 94, + 80, + 239, + 0, + 53, + 182, + 95, + 199, + 137, + 89, + 246, + 121, + 194, + 191, + 149, + 96, + 191, + 158, + 142, + 231, + 226, + 247, + 216, + 67, + 86, + 7, + 96, + 181, + 112, + 81, + 68, + 10, + 4, + 70, + 122, + 95, + 26, + 77, + 204, + 45, + 66, + 144, + 11, + 170, + 33, + 104, + 35, + 107, + 164, + 204, + 90, + 80, + 141, + 221, + 36, + 202, + 165, + 30, + 176, + 78, + 228, + 72, + 42, + 182, + 240, + 47, + 65, + 226, + 158, + 70, + 63, + 137, + 42, + 150, + 237, + 84, + 222, + 47, + 205, + 89, + 115, + 105, + 120, + 129, + 84, + 235, + 141, + 71, + 226, + 65, + 55, + 150, + 249, + 204, + 185, + 201, + 63, + 125, + 228, + 61, + 65, + 73, + 165, + 77, + 57, + 47, + 114, + 215, + 10, + 65, + 228, + 30, + 165, + 154, + 53, + 174, + 226, + 40, + 91, + 220, + 56, + 156, + 228, + 203, + 182, + 160, + 138, + 62, + 172, + 113, + 27, + 43, + 13, + 149, + 165, + 157, + 84, + 21, + 157, + 73, + 110, + 78, + 110, + 59, + 179, + 244, + 95, + 160, + 189, + 25, + 128, + 11, + 241, + 28, + 117, + 32, + 188, + 128, + 21, + 74, + 217, + 174, + 153, + 99, + 63, + 183, + 226, + 61, + 233, + 138, + 18, + 99, + 201, + 171, + 172, + 80, + 104, + 68, + 43, + 7, + 160, + 221, + 182, + 85, + 28, + 195, + 248, + 236, + 196, + 144, + 48, + 176, + 149, + 152, + 221, + 155, + 237, + 253, + 252, + 186, + 49, + 162, + 14, + 110, + 50, + 45, + 70, + 61, + 52, + 169, + 84, + 124, + 149, + 76, + 26, + 15, + 11, + 149, + 178, + 4, + 159, + 101, + 16, + 172, + 4, + 180, + 194, + 254, + 194, + 202, + 4, + 10, + 162, + 193, + 131, + 236, + 209, + 177, + 70, + 38, + 37, + 153, + 66, + 252, + 111, + 116, + 176, + 48, + 23, + 151, + 38, + 25, + 166, + 145, + 77, + 149, + 119, + 227, + 73, + 70, + 111, + 31, + 147, + 124, + 8, + 218, + 227, + 64, + 184, + 97, + 152, + 95, + 153, + 64, + 246, + 100, + 42, + 53, + 215, + 136, + 250, + 237, + 10, + 195, + 158, + 162, + 111, + 134, + 11, + 139, + 197, + 61, + 111, + 55, + 18, + 120, + 109, + 32, + 111, + 63, + 29, + 41, + 246, + 82, + 75, + 198, + 61, + 255, + 72, + 133, + 166, + 82, + 242, + 55, + 74, + 232, + 174, + 40, + 24, + 21, + 12, + 138, + 114, + 14, + 9, + 76, + 171, + 248, + 3, + 47, + 132, + 223, + 108, + 42, + 25, + 2, + 208, + 124, + 84, + 1, + 253, + 55, + 79, + 163, + 201, + 136, + 75, + 210, + 154, + 153, + 207, + 57, + 30, + 68, + 157, + 21, + 191, + 152, + 182, + 122, + 114, + 145, + 47, + 125, + 60, + 133, + 168, + 80, + 142, + 126, + 153, + 36, + 114, + 233, + 211, + 33, + 241, + 21, + 24, + 53, + 72, + 143, + 40, + 145, + 72, + 206, + 247, + 103, + 200, + 31, + 17, + 116, + 96, + 166, + 83, + 37, + 6, + 207, + 190, + 29, + 190, + 102, + 16, + 23, + 78, + 38, + 133, + 51, + 158, + 155, + 5, + 82, + 169, + 110, + 64, + 144, + 147, + 128, + 114, + 116, + 151, + 166, + 125, + 237, + 52, + 59, + 13, + 181, + 27, + 49, + 166, + 56, + 232, + 199, + 63, + 49, + 190, + 218, + 116, + 184, + 23, + 204, + 144, + 109, + 35, + 158, + 4, + 76, + 11, + 74, + 105, + 250, + 28, + 82, + 129, + 206, + 218, + 169, + 246, + 191, + 183, + 6, + 145, + 87, + 234, + 153, + 28, + 154, + 142, + 98, + 149, + 237, + 2, + 134, + 107, + 115, + 14, + 120, + 242, + 236, + 171, + 147, + 173, + 53, + 27, + 198, + 181, + 133, + 10, + 82, + 43, + 202, + 129, + 140, + 16, + 15, + 160, + 157, + 124, + 19, + 117, + 97, + 125, + 11, + 213, + 106, + 124, + 42, + 139, + 141, + 204, + 134, + 233, + 151, + 4, + 226, + 173, + 36, + 99, + 72, + 245, + 124, + 155, + 166, + 51, + 228, + 104, + 70, + 176, + 73, + 9, + 155, + 117, + 22, + 41, + 36, + 193, + 151, + 156, + 158, + 119, + 219, + 232, + 202, + 32, + 150, + 60, + 255, + 65, + 177, + 157, + 226, + 85, + 136, + 214, + 192, + 215, + 240, + 158, + 35, + 108, + 38, + 61, + 74, + 86, + 92, + 74, + 210, + 229, + 230, + 218, + 20, + 104, + 46, + 7, + 194, + 205, + 237, + 138, + 123, + 236, + 104, + 138, + 51, + 60, + 97, + 81, + 125, + 9, + 207, + 222, + 113, + 0, + 51, + 52, + 145, + 78, + 87, + 25, + 255, + 236, + 141, + 166, + 233, + 64, + 69, + 205, + 149, + 125, + 205, + 156, + 80, + 44, + 39, + 133, + 18, + 67, + 26, + 255, + 229, + 195, + 232, + 180, + 34, + 239, + 88, + 199, + 133, + 96, + 172, + 109, + 44, + 26, + 106, + 219, + 139, + 130, + 86, + 41, + 57, + 53, + 215, + 210, + 13, + 84, + 246, + 176, + 122, + 130, + 185, + 102, + 40, + 191, + 66, + 131, + 70, + 8, + 245, + 78, + 229, + 22, + 201, + 147, + 105, + 71, + 53, + 232, + 127, + 74, + 35, + 142, + 103, + 132, + 85, + 183, + 139, + 53, + 113, + 215, + 70, + 19, + 119, + 155, + 235, + 255, + 145, + 80, + 113, + 118, + 133, + 123, + 206, + 198, + 119, + 199, + 67, + 41, + 142, + 60, + 229, + 235, + 11, + 61, + 124, + 142, + 187, + 4, + 53, + 176, + 248, + 159, + 117, + 155, + 116, + 143, + 117, + 182, + 2, + 52, + 112, + 17, + 110, + 35, + 169, + 232, + 38, + 245, + 78, + 24, + 53, + 167, + 165, + 238, + 129, + 99, + 199, + 163, + 221, + 29, + 74, + 239, + 156, + 23, + 33, + 172, + 6, + 236, + 241, + 6, + 172, + 193, + 34, + 43, + 87, + 89, + 86, + 54, + 53, + 23, + 59, + 223, + 155, + 73, + 128, + 177, + 70, + 124, + 55, + 0, + 249, + 192, + 47, + 245, + 216, + 53, + 127, + 14, + 231, + 49, + 245, + 70, + 65, + 197, + 81, + 84, + 25, + 194, + 218, + 40, + 90, + 180, + 174, + 213, + 122, + 41, + 100, + 220, + 111, + 212, + 30, + 226, + 75, + 60, + 1, + 158, + 63, + 16, + 159, + 187, + 152, + 154, + 189, + 193, + 41, + 33, + 21, + 66, + 203, + 234, + 216, + 13, + 215, + 68, + 128, + 34, + 215, + 60, + 70, + 103, + 123, + 92, + 38, + 215, + 87, + 180, + 185, + 53, + 71, + 62, + 168, + 174, + 116, + 84, + 105, + 172, + 0, + 33, + 82, + 173, + 39, + 141, + 23, + 251, + 227, + 211, + 18, + 24, + 68, + 134, + 40, + 246, + 85, + 222, + 124, + 107, + 165, + 50, + 92, + 221, + 24, + 25, + 92, + 117, + 186, + 202, + 19, + 164, + 207, + 134, + 86, + 31, + 83, + 162, + 133, + 109, + 108, + 133, + 253, + 15, + 201, + 26, + 41, + 129, + 215, + 249, + 153, + 177, + 132, + 34, + 161, + 116, + 35, + 166, + 137, + 167, + 241, + 220, + 8, + 96, + 213, + 70, + 102, + 141, + 194, + 213, + 74, + 142, + 238, + 233, + 240, + 223, + 21, + 20, + 102, + 70, + 58, + 21, + 190, + 170, + 20, + 194, + 203, + 91, + 214, + 45, + 180, + 210, + 92, + 192, + 58, + 35, + 109, + 17, + 23, + 67, + 45, + 146, + 141, + 138, + 113, + 195, + 104, + 8, + 148, + 107, + 19, + 108, + 244, + 78, + 209, + 182, + 58, + 103, + 161, + 74, + 214, + 191, + 201, + 253, + 49, + 128, + 152, + 32, + 12, + 74, + 14, + 55, + 70, + 77, + 233, + 171, + 176, + 149, + 124, + 65, + 210, + 198, + 87, + 174, + 145, + 138, + 52, + 244, + 99, + 139, + 104, + 146, + 45, + 6, + 224, + 200, + 184, + 138, + 143, + 129, + 159, + 135, + 68, + 32, + 174, + 84, + 53, + 226, + 2, + 132, + 72, + 151, + 122, + 180, + 210, + 132, + 23, + 21, + 79, + 18, + 166, + 69, + 119, + 234, + 167, + 222, + 18, + 3, + 239, + 253, + 115, + 18, + 33, + 71, + 23, + 128, + 207, + 62, + 44, + 7, + 101, + 16, + 133, + 66, + 230, + 27, + 227, + 203, + 80, + 136, + 244, + 178, + 73, + 35, + 199, + 230, + 136, + 106, + 116, + 122, + 61, + 114, + 54, + 206, + 9, + 117, + 95, + 177, + 83, + 229, + 161, + 113, + 187, + 9, + 169, + 214, + 13, + 91, + 189, + 216, + 179, + 69, + 123, + 155, + 137, + 165, + 31, + 84, + 78, + 97, + 233, + 251, + 147, + 226, + 233, + 108, + 49, + 133, + 75, + 88, + 240, + 13, + 151, + 25, + 237, + 179, + 140, + 180, + 185, + 86, + 209, + 29, + 215, + 200, + 191, + 16, + 111, + 179, + 50, + 133, + 214, + 86, + 102, + 19, + 247, + 13, + 94, + 143, + 219, + 113, + 101, + 14, + 205, + 39, + 151, + 48, + 46, + 148, + 219, + 149, + 196, + 33, + 22, + 15, + 129, + 61, + 239, + 96, + 161, + 231, + 55, + 211, + 121, + 4, + 79, + 191, + 48, + 109, + 64, + 0, + 123, + 161, + 104, + 144, + 191, + 218, + 243, + 250, + 124, + 72, + 242, + 198, + 50, + 189, + 88, + 143, + 126, + 223, + 23, + 163, + 161, + 131, + 223, + 227, + 40, + 30, + 207, + 123, + 173, + 163, + 60, + 58, + 244, + 98, + 11, + 97, + 223, + 250, + 174, + 146, + 119, + 115, + 176, + 18, + 73, + 61, + 249, + 41, + 89, + 12, + 18, + 240, + 212, + 14, + 10, + 55, + 130, + 214, + 148, + 36, + 37, + 57, + 190, + 224, + 72, + 49, + 18, + 85, + 255, + 205, + 228, + 187, + 50, + 236, + 215, + 13, + 16, + 115, + 234, + 143, + 220, + 60, + 3, + 237, + 190, + 205, + 215, + 50, + 4, + 68, + 51, + 208, + 80, + 76, + 255, + 149, + 88, + 8, + 36, + 117, + 36, + 112, + 14, + 223, + 232, + 72, + 58, + 232, + 87, + 145, + 175, + 76, + 180, + 165, + 164, + 16, + 149, + 152, + 6, + 213, + 181, + 139, + 70, + 111, + 247, + 162, + 0, + 205, + 65, + 1, + 75, + 84, + 169, + 212, + 179, + 224, + 46, + 97, + 99, + 126, + 231, + 165, + 200, + 214, + 12, + 21, + 113, + 222, + 112, + 192, + 98, + 143, + 14, + 153, + 251, + 64, + 61, + 227, + 219, + 162, + 178, + 150, + 96, + 47, + 54, + 12, + 45, + 114, + 206, + 223, + 189, + 97, + 148, + 105, + 42, + 125, + 88, + 144, + 40, + 79, + 166, + 19, + 158, + 61, + 32, + 157, + 80, + 114, + 20, + 37, + 80, + 99, + 135, + 134, + 112, + 194, + 99, + 169, + 190, + 96, + 31, + 143, + 32, + 51, + 168, + 242, + 193, + 36, + 88, + 182, + 145, + 251, + 36, + 30, + 26, + 60, + 186, + 193, + 21, + 10, + 4, + 212, + 197, + 128, + 152, + 222, + 30, + 12, + 27, + 169, + 80, + 34, + 181, + 41, + 71, + 41, + 206, + 232, + 238, + 141, + 82, + 3, + 231, + 149, + 208, + 127, + 123, + 11, + 158, + 192, + 86, + 0, + 111, + 162, + 19, + 88, + 250, + 19, + 4, + 124, + 169, + 142, + 178, + 4, + 104, + 193, + 6, + 88, + 99, + 182, + 96, + 35, + 159, + 201, + 147, + 11, + 17, + 139, + 116, + 153, + 210, + 242, + 106, + 132, + 242, + 20, + 83, + 15, + 221, + 224, + 2, + 70, + 112, + 250, + 199, + 4, + 18, + 44, + 253, + 247, + 203, + 188, + 232, + 172, + 238, + 162, + 15, + 110, + 176, + 118, + 190, + 34, + 183, + 184, + 76, + 115, + 43, + 212, + 181, + 89, + 152, + 117, + 3, + 207, + 56, + 163, + 52, + 193, + 101, + 34, + 223, + 126, + 80, + 147, + 104, + 157, + 78, + 46, + 252, + 59, + 102, + 56, + 115, + 24, + 207, + 81, + 87, + 24, + 52, + 234, + 184, + 3, + 216, + 237, + 83, + 82, + 57, + 59, + 77, + 174, + 185, + 32, + 85, + 219, + 30, + 33, + 54, + 82, + 218, + 237, + 228, + 176, + 117, + 159, + 12, + 177, + 47, + 143, + 195, + 4, + 149, + 132, + 213, + 224, + 30, + 155, + 99, + 30, + 177, + 60, + 38, + 19, + 175, + 231, + 43, + 129, + 138, + 59, + 78, + 200, + 73, + 29, + 74, + 211, + 194, + 26, + 40, + 52, + 245, + 143, + 17, + 74, + 172, + 142, + 70, + 222, + 192, + 93, + 94, + 174, + 27, + 93, + 231, + 39, + 21, + 174, + 157, + 229, + 167, + 98, + 16, + 82, + 174, + 21, + 249, + 111, + 121, + 165, + 250, + 85, + 5, + 11, + 195, + 182, + 71, + 242, + 197, + 213, + 240, + 200, + 6, + 232, + 118, + 50, + 218, + 108, + 229, + 113, + 156, + 16, + 219, + 170, + 87, + 116, + 106, + 85, + 147, + 25, + 162, + 162, + 72, + 132, + 199, + 245, + 50, + 133, + 138, + 70, + 168, + 140, + 184, + 133, + 49, + 217, + 216, + 60, + 26, + 140, + 206, + 189, + 4, + 124, + 95, + 150, + 232, + 14, + 7, + 77, + 16, + 57, + 33, + 146, + 214, + 204, + 217, + 67, + 2, + 152, + 123, + 203, + 150, + 151, + 143, + 25, + 8, + 101, + 91, + 48, + 248, + 50, + 207, + 152, + 115, + 74, + 6, + 27, + 61, + 189, + 98, + 203, + 188, + 182, + 203, + 169, + 249, + 145, + 93, + 247, + 73, + 21, + 0, + 216, + 239, + 22, + 191, + 63, + 55, + 107, + 32, + 181, + 208, + 186, + 147, + 235, + 128, + 141, + 163, + 208, + 253, + 221, + 101, + 133, + 104, + 23, + 218, + 178, + 209, + 91, + 84, + 234, + 70, + 102, + 164, + 111, + 74, + 74, + 80, + 237, + 96, + 128, + 235, + 99, + 95, + 73, + 111, + 6, + 61, + 74, + 241, + 21, + 70, + 70, + 241, + 93, + 174, + 52, + 155, + 56, + 254, + 206, + 110, + 108, + 247, + 129, + 233, + 116, + 140, + 4, + 107, + 93, + 75, + 186, + 84, + 54, + 34, + 165, + 134, + 225, + 124, + 251, + 164, + 82, + 52, + 200, + 52, + 110, + 82, + 170, + 213, + 13, + 84, + 30, + 234, + 179, + 169, + 201, + 248, + 62, + 56, + 150, + 194, + 54, + 42, + 33, + 216, + 107, + 135, + 10, + 151, + 195, + 114, + 249, + 55, + 163, + 45, + 214, + 185, + 5, + 216, + 43, + 100, + 237, + 238, + 181, + 115, + 131, + 75, + 230, + 176, + 131, + 194, + 197, + 74, + 187, + 17, + 208, + 153, + 134, + 40, + 118, + 81, + 237, + 172, + 151, + 217, + 81, + 155, + 72, + 140, + 221, + 101, + 46, + 71, + 248, + 32, + 55, + 132, + 93, + 17, + 13, + 11, + 115, + 152, + 54, + 111, + 53, + 105, + 197, + 238, + 181, + 214, + 143, + 146, + 178, + 251, + 66, + 132, + 206, + 111, + 92, + 137, + 95, + 70, + 99, + 123, + 185, + 221, + 16, + 254, + 217, + 15, + 215, + 103, + 214, + 42, + 146, + 152, + 180, + 16, + 88, + 224, + 64, + 165, + 135, + 36, + 21, + 13, + 9, + 68, + 11, + 212, + 250, + 64, + 24, + 174, + 5, + 22, + 124, + 83, + 67, + 193, + 94, + 209, + 1, + 219, + 53, + 221, + 69, + 94, + 241, + 16, + 235, + 249, + 53, + 84, + 160, + 120, + 214, + 1, + 168, + 121, + 86, + 233, + 135, + 222, + 193, + 151, + 128, + 74, + 19, + 99, + 192, + 59, + 117, + 69, + 134, + 156, + 93, + 135, + 26, + 107, + 159, + 78, + 40, + 73, + 170, + 174, + 59, + 165, + 63, + 178, + 19, + 209, + 180, + 15, + 206, + 111, + 219, + 19, + 236, + 71, + 152, + 154, + 199, + 154, + 195, + 176, + 28, + 247, + 18, + 226, + 131, + 155, + 167, + 107, + 107, + 102, + 131, + 3, + 111, + 189, + 200, + 118, + 106, + 63, + 184, + 131, + 160, + 137, + 72, + 60, + 40, + 122, + 54, + 219, + 205, + 77, + 164, + 192, + 26, + 100, + 70, + 235, + 6, + 30, + 62, + 13, + 57, + 85, + 245, + 54, + 233, + 245, + 129, + 62, + 170, + 245, + 177, + 18, + 81, + 196, + 118, + 118, + 47, + 242, + 214, + 38, + 12, + 51, + 209, + 15, + 220, + 133, + 141, + 194, + 33, + 165, + 124, + 111, + 163, + 20, + 114, + 120, + 167, + 243, + 87, + 15, + 171, + 97, + 108, + 83, + 77, + 132, + 240, + 226, + 222, + 190, + 184, + 68, + 72, + 3, + 164, + 222, + 128, + 82, + 195, + 119, + 106, + 110, + 78, + 49, + 11, + 224, + 109, + 224, + 17, + 108, + 79, + 19, + 240, + 225, + 157, + 52, + 218, + 106, + 152, + 1, + 253, + 15, + 7, + 177, + 26, + 98, + 27, + 128, + 176, + 132, + 226, + 53, + 70, + 252, + 45, + 69, + 248, + 81, + 244, + 253, + 134, + 180, + 94, + 111, + 30, + 234, + 12, + 1, + 156, + 28, + 98, + 145, + 58, + 244, + 243, + 185, + 189, + 57, + 96, + 5, + 185, + 98, + 68, + 220, + 105, + 114, + 68, + 88, + 181, + 148, + 191, + 213, + 195, + 65, + 45, + 172, + 13, + 198, + 162, + 107, + 163, + 24, + 142, + 254, + 241, + 210, + 236, + 109, + 166, + 4, + 229, + 63, + 60, + 22, + 25, + 140, + 178, + 36, + 37, + 19, + 132, + 21, + 191, + 68, + 120, + 253, + 34, + 161, + 205, + 232, + 238, + 111, + 159, + 37, + 107, + 118, + 15, + 83, + 29, + 165, + 147, + 156, + 49, + 252, + 33, + 173, + 127, + 157, + 100, + 101, + 132, + 87, + 90, + 152, + 35, + 117, + 98, + 26, + 165, + 227, + 107, + 91, + 29, + 12, + 201, + 202, + 185, + 40, + 74, + 160, + 187, + 174, + 90, + 171, + 143, + 92, + 190, + 143, + 221, + 143, + 208, + 199, + 254, + 26, + 155, + 12, + 102, + 169, + 200, + 121, + 193, + 228, + 38, + 90, + 51, + 224, + 181, + 59, + 145, + 115, + 253, + 251, + 111, + 244, + 98, + 132, + 64, + 225, + 139, + 234, + 186, + 167, + 171, + 26, + 221, + 21, + 143, + 3, + 162, + 121, + 140, + 155, + 228, + 171, + 149, + 188, + 125, + 131, + 196, + 208, + 29, + 221, + 20, + 168, + 92, + 152, + 194, + 228, + 202, + 220, + 211, + 204, + 10, + 37, + 177, + 82, + 106, + 108, + 205, + 70, + 220, + 159, + 43, + 235, + 192, + 229, + 159, + 139, + 80, + 6, + 79, + 38, + 25, + 117, + 171, + 77, + 79, + 114, + 133, + 238, + 128, + 164, + 30, + 235, + 41, + 1, + 222, + 53, + 134, + 71, + 225, + 194, + 219, + 125, + 38, + 22, + 176, + 26, + 66, + 220, + 100, + 105, + 46, + 217, + 60, + 245, + 121, + 204, + 215, + 79, + 65, + 221, + 25, + 132, + 109, + 117, + 59, + 32, + 6, + 48, + 107, + 7, + 126, + 221, + 131, + 177, + 238, + 55, + 96, + 110, + 197, + 154, + 165, + 102, + 238, + 6, + 108, + 51, + 60, + 12, + 42, + 55, + 117, + 234, + 206, + 218, + 82, + 168, + 40, + 140, + 182, + 173, + 134, + 73, + 182, + 123, + 237, + 219, + 12, + 2, + 134, + 243, + 204, + 152, + 70, + 61, + 239, + 87, + 116, + 118, + 142, + 183, + 237, + 16, + 10, + 196, + 224, + 238, + 248, + 96, + 83, + 49, + 150, + 207, + 117, + 70, + 10, + 66, + 223, + 59, + 12, + 209, + 245, + 79, + 130, + 168, + 233, + 226, + 28, + 235, + 27, + 107, + 194, + 105, + 35, + 252, + 52, + 36, + 152, + 81, + 125, + 155, + 246, + 18, + 155, + 204, + 251, + 56, + 145, + 217, + 115, + 171, + 209, + 9, + 91, + 231, + 123, + 235, + 0, + 2, + 238, + 109, + 159, + 54, + 40, + 34, + 18, + 157, + 227, + 95, + 191, + 33, + 149, + 109, + 49, + 116, + 43, + 211, + 83, + 47, + 16, + 211, + 246, + 105, + 133, + 184, + 71, + 235, + 12, + 7, + 30, + 115, + 152, + 203, + 119, + 96, + 0, + 233, + 180, + 179, + 36, + 73, + 111, + 166, + 230, + 119, + 233, + 252, + 172, + 30, + 227, + 28, + 132, + 114, + 243, + 56, + 7, + 95, + 134, + 233, + 210, + 226, + 119, + 190, + 44, + 57, + 230, + 205, + 127, + 61, + 210, + 176, + 70, + 20, + 115, + 127, + 132, + 84, + 98, + 78, + 231, + 17, + 111, + 1, + 26, + 38, + 40, + 72, + 162, + 0, + 200, + 232, + 81, + 166, + 213, + 224, + 184, + 15, + 88, + 247, + 37, + 14, + 7, + 94, + 170, + 236, + 63, + 56, + 228, + 232, + 233, + 108, + 229, + 172, + 21, + 48, + 63, + 170, + 153, + 7, + 119, + 103, + 63, + 173, + 219, + 228, + 193, + 209, + 110, + 158, + 101, + 42, + 190, + 146, + 128, + 86, + 95, + 19, + 140, + 155, + 203, + 56, + 112, + 203, + 118, + 127, + 43, + 73, + 122, + 12, + 15, + 212, + 83, + 214, + 217, + 22, + 246, + 71, + 134, + 30, + 103, + 44, + 126, + 89, + 75, + 36, + 16, + 196, + 232, + 22, + 220, + 222, + 193, + 101, + 100, + 221, + 49, + 58, + 146, + 5, + 163, + 233, + 190, + 54, + 198, + 91, + 121, + 102, + 120, + 222, + 27, + 58, + 13, + 53, + 25, + 130, + 62, + 136, + 223, + 60, + 193, + 51, + 199, + 15, + 3, + 69, + 15, + 166, + 62, + 235, + 6, + 12, + 7, + 158, + 130, + 95, + 255, + 196, + 254, + 108, + 140, + 180, + 228, + 220, + 24, + 141, + 124, + 199, + 15, + 89, + 99, + 84, + 35, + 204, + 235, + 69, + 50, + 31, + 119, + 119, + 165, + 95, + 148, + 101, + 237, + 73, + 19, + 157, + 66, + 67, + 225, + 162, + 25, + 62, + 85, + 165, + 48, + 211, + 59, + 68, + 84, + 122, + 122, + 212, + 126, + 27, + 240, + 232, + 91, + 169, + 172, + 181, + 41, + 92, + 134, + 5, + 241, + 180, + 10, + 37, + 20, + 160, + 44, + 193, + 44, + 26, + 93, + 104, + 62, + 114, + 49, + 243, + 35, + 189, + 226, + 165, + 119, + 77, + 206, + 196, + 217, + 5, + 235, + 7, + 24, + 98, + 162, + 15, + 234, + 246, + 147, + 117, + 247, + 119, + 113, + 219, + 100, + 6, + 32, + 29, + 213, + 144, + 166, + 37, + 212, + 190, + 188, + 128, + 212, + 129, + 27, + 36, + 27, + 154, + 38, + 82, + 230, + 200, + 175, + 80, + 218, + 173, + 46, + 139, + 178, + 218, + 24, + 153, + 190, + 251, + 55, + 37, + 138, + 95, + 96, + 107, + 71, + 42, + 180, + 4, + 53, + 38, + 107, + 140, + 39, + 112, + 173, + 187, + 165, + 203, + 22, + 43, + 252, + 183, + 56, + 149, + 106, + 162, + 197, + 134, + 176, + 218, + 51, + 243, + 10, + 184, + 203, + 208, + 11, + 1, + 123, + 199, + 59, + 173, + 237, + 61, + 66, + 46, + 32, + 4, + 152, + 122, + 170, + 81, + 139, + 70, + 221, + 107, + 25, + 223, + 68, + 199, + 25, + 90, + 117, + 14, + 35, + 254, + 165, + 181, + 164, + 133, + 125, + 190, + 251, + 5, + 76, + 46, + 4, + 253, + 35, + 255, + 153, + 109, + 181, + 50, + 155, + 250, + 220, + 141, + 215, + 217, + 45, + 58, + 169, + 65, + 84, + 106, + 79, + 192, + 165, + 71, + 122, + 150, + 220, + 211, + 75, + 142, + 65, + 41, + 190, + 245, + 89, + 134, + 153, + 193, + 87, + 48, + 87, + 133, + 235, + 80, + 225, + 0, + 137, + 68, + 151, + 97, + 37, + 216, + 243, + 253, + 110, + 134, + 129, + 154, + 225, + 250, + 127, + 184, + 106, + 100, + 221, + 98, + 2, + 197, + 218, + 231, + 37, + 88, + 115, + 182, + 154, + 127, + 206, + 229, + 119, + 197, + 58, + 225, + 232, + 52, + 117, + 114, + 176, + 109, + 90, + 27, + 8, + 222, + 163, + 113, + 103, + 139, + 58, + 143, + 255, + 28, + 23, + 205, + 109, + 64, + 246, + 244, + 191, + 119, + 179, + 183, + 32, + 160, + 190, + 95, + 32, + 176, + 171, + 120, + 108, + 162, + 168, + 249, + 151, + 118, + 249, + 229, + 6, + 50, + 214, + 213, + 68, + 42, + 165, + 104, + 173, + 74, + 221, + 1, + 46, + 247, + 206, + 204, + 90, + 160, + 124, + 110, + 234, + 224, + 68, + 239, + 27, + 154, + 40, + 34, + 28, + 3, + 138, + 243, + 212, + 155, + 205, + 174, + 36, + 212, + 205, + 156, + 172, + 30, + 176, + 126, + 221, + 117, + 202, + 58, + 191, + 131, + 105, + 124, + 50, + 227, + 25, + 25, + 200, + 58, + 127, + 141, + 201, + 181, + 69, + 41, + 123, + 201, + 60, + 154, + 175, + 128, + 10, + 179, + 228, + 111, + 102, + 99, + 145, + 99, + 60, + 204, + 255, + 187, + 216, + 108, + 158, + 113, + 117, + 22, + 168, + 41, + 247, + 238, + 31, + 37, + 236, + 164, + 202, + 185, + 170, + 30, + 224, + 100, + 54, + 231, + 224, + 18, + 228, + 0, + 210, + 55, + 196, + 120, + 126, + 209, + 166, + 144, + 228, + 65, + 162, + 41, + 52, + 192, + 73, + 153, + 208, + 31, + 201, + 104, + 107, + 103, + 148, + 176, + 52, + 3, + 241, + 174, + 217, + 72, + 228, + 133, + 48, + 64, + 68, + 55, + 85, + 51, + 62, + 73, + 190, + 252, + 4, + 169, + 116, + 79, + 140, + 134, + 230, + 79, + 90, + 185, + 57, + 159, + 28, + 146, + 92, + 178, + 44, + 200, + 48, + 12, + 183, + 177, + 37, + 135, + 213, + 250, + 49, + 184, + 13, + 23, + 7, + 9, + 241, + 185, + 63, + 154, + 153, + 163, + 36, + 72, + 6, + 212, + 29, + 69, + 181, + 34, + 123, + 80, + 184, + 177, + 5, + 49, + 49, + 113, + 209, + 93, + 46, + 14, + 149, + 132, + 121, + 103, + 47, + 119, + 139, + 231, + 41, + 224, + 44, + 38, + 238, + 92, + 235, + 116, + 97, + 109, + 29, + 237, + 232, + 213, + 55, + 2, + 175, + 78, + 21, + 65, + 206, + 205, + 125, + 34, + 81, + 92, + 70, + 253, + 206, + 125, + 105, + 240, + 179, + 58, + 97, + 191, + 33, + 96, + 232, + 107, + 77, + 174, + 183, + 37, + 91, + 173, + 196, + 164, + 41, + 16, + 173, + 206, + 29, + 170, + 10, + 37, + 33, + 200, + 38, + 107, + 119, + 105, + 118, + 86, + 164, + 188, + 203, + 87, + 135, + 148, + 204, + 255, + 211, + 83, + 182, + 92, + 51, + 252, + 34, + 42, + 210, + 104, + 90, + 132, + 103, + 176, + 129, + 155, + 84, + 69, + 102, + 181, + 45, + 80, + 83, + 177, + 144, + 169, + 247, + 85, + 235, + 47, + 40, + 246, + 73, + 50, + 36, + 193, + 42, + 172, + 104, + 30, + 171, + 94, + 76, + 43, + 142, + 202, + 64, + 145, + 56, + 234, + 224, + 102, + 45, + 166, + 118, + 215, + 45, + 144, + 106, + 203, + 197, + 186, + 175, + 5, + 5, + 75, + 126, + 179, + 240, + 213, + 202, + 146, + 77, + 61, + 66, + 110, + 218, + 76, + 159, + 155, + 16, + 140, + 218, + 49, + 161, + 48, + 88, + 161, + 22, + 219, + 187, + 106, + 246, + 207, + 211, + 115, + 71, + 197, + 221, + 81, + 119, + 191, + 105, + 241, + 110, + 52, + 14, + 113, + 109, + 37, + 0, + 251, + 190, + 69, + 203, + 223, + 181, + 131, + 173, + 129, + 129, + 151, + 218, + 151, + 216, + 254, + 169, + 6, + 50, + 160, + 116, + 209, + 80, + 75, + 129, + 244, + 215, + 70, + 125, + 122, + 203, + 168, + 228, + 7, + 221, + 16, + 71, + 151, + 19, + 13, + 139, + 78, + 237, + 54, + 22, + 42, + 232, + 245, + 114, + 239, + 202, + 244, + 203, + 7, + 52, + 65, + 148, + 117, + 91, + 62, + 221, + 253, + 58, + 211, + 73, + 254, + 46, + 128, + 95, + 86, + 114, + 199, + 55, + 55, + 101, + 222, + 150, + 66, + 11, + 65, + 30, + 133, + 163, + 110, + 187, + 222, + 244, + 28, + 203, + 222, + 242, + 98, + 229, + 5, + 155, + 175, + 69, + 184, + 129, + 229, + 216, + 122, + 46, + 19, + 17, + 39, + 3, + 132, + 115, + 112, + 74, + 91, + 97, + 11, + 93, + 30, + 158, + 60, + 16, + 113, + 12, + 50, + 245, + 40, + 12, + 75, + 227, + 167, + 170, + 18, + 31, + 158, + 202, + 138, + 17, + 127, + 146, + 49, + 121, + 234, + 181, + 164, + 162, + 102, + 247, + 42, + 11, + 177, + 43, + 95, + 251, + 217, + 161, + 90, + 214, + 114, + 220, + 3, + 86, + 36, + 36, + 187, + 231, + 223, + 29, + 41, + 122, + 225, + 226, + 10, + 0, + 79, + 179, + 39, + 249, + 197, + 138, + 125, + 157, + 116, + 118, + 107, + 116, + 248, + 112, + 84, + 98, + 31, + 93, + 92, + 77, + 19, + 202, + 193, + 121, + 209, + 73, + 225, + 5, + 206, + 134, + 193, + 115, + 131, + 192, + 55, + 176, + 114, + 203, + 218, + 15, + 184, + 58, + 82, + 217, + 102, + 181, + 31, + 248, + 57, + 241, + 244, + 94, + 10, + 205, + 86, + 101, + 30, + 253, + 168, + 245, + 114, + 17, + 134, + 71, + 133, + 241, + 83, + 254, + 158, + 99, + 177, + 60, + 221, + 66, + 173, + 107, + 152, + 40, + 129, + 61, + 103, + 50, + 151, + 43, + 234, + 141, + 164, + 12, + 253, + 55, + 172, + 217, + 131, + 47, + 135, + 213, + 9, + 217, + 208, + 102, + 123, + 6, + 234, + 68, + 113, + 146, + 160, + 236, + 14, + 192, + 80, + 89, + 103, + 208, + 138, + 209, + 158, + 233, + 252, + 251, + 192, + 45, + 56, + 86, + 103, + 168, + 19, + 13, + 120, + 111, + 119, + 149, + 3, + 224, + 7, + 127, + 208, + 221, + 131, + 85, + 7, + 176, + 231, + 136, + 79, + 25, + 161, + 250, + 212, + 1, + 120, + 165, + 144, + 43, + 131, + 2, + 72, + 215, + 217, + 148, + 108, + 14, + 86, + 57, + 226, + 26, + 141, + 81, + 60, + 1, + 84, + 159, + 0, + 38, + 78, + 224, + 100, + 136, + 112, + 27, + 37, + 191, + 180, + 80, + 108, + 35, + 179, + 175, + 189, + 186, + 127, + 49, + 100, + 59, + 144, + 217, + 112, + 16, + 54, + 176, + 89, + 132, + 213, + 164, + 246, + 144, + 199, + 217, + 34, + 179, + 43, + 241, + 184, + 55, + 4, + 195, + 30, + 182, + 122, + 195, + 85, + 184, + 242, + 226, + 91, + 173, + 22, + 7, + 189, + 165, + 148, + 11, + 182, + 137, + 76, + 47, + 16, + 17, + 8, + 12, + 44, + 252, + 206, + 208, + 190, + 224, + 144, + 13, + 220, + 176, + 124, + 160, + 20, + 110, + 46, + 142, + 76, + 70, + 160, + 79, + 132, + 140, + 114, + 185, + 36, + 200, + 137, + 177, + 221, + 104, + 166, + 43, + 5, + 128, + 61, + 71, + 217, + 208, + 200, + 126, + 133, + 42, + 177, + 70, + 247, + 253, + 107, + 199, + 251, + 92, + 141, + 154, + 2, + 131, + 100, + 198, + 213, + 70, + 66, + 117, + 34, + 149, + 106, + 208, + 71, + 7, + 129, + 76, + 29, + 14, + 144, + 209, + 40, + 39, + 237, + 47, + 117, + 199, + 107, + 107, + 28, + 146, + 35, + 51, + 70, + 56, + 91, + 48, + 5, + 52, + 125, + 177, + 85, + 187, + 112, + 84, + 10, + 40, + 86, + 58, + 96, + 26, + 207, + 207, + 78, + 89, + 15, + 107, + 248, + 241, + 64, + 120, + 164, + 143, + 138, + 151, + 97, + 251, + 149, + 176, + 237, + 232, + 110, + 240, + 40, + 23, + 218, + 196, + 7, + 208, + 93, + 89, + 21, + 165, + 226, + 157, + 242, + 15, + 103, + 140, + 22, + 221, + 60, + 34, + 145, + 192, + 61, + 240, + 250, + 204, + 40, + 159, + 218, + 122, + 231, + 208, + 168, + 90, + 224, + 159, + 87, + 164, + 241, + 41, + 188, + 83, + 57, + 203, + 141, + 99, + 113, + 120, + 152, + 244, + 27, + 54, + 1, + 83, + 104, + 93, + 121, + 158, + 73, + 171, + 12, + 247, + 113, + 89, + 137, + 235, + 99, + 232, + 40, + 198, + 175, + 184, + 195, + 121, + 33, + 134, + 132, + 142, + 163, + 148, + 27, + 59, + 96, + 84, + 98, + 36, + 68, + 196, + 69, + 216, + 193, + 6, + 245, + 223, + 165, + 72, + 21, + 120, + 217, + 106, + 7, + 228, + 34, + 118, + 54, + 193, + 63, + 19, + 200, + 170, + 61, + 57, + 20, + 60, + 199, + 154, + 130, + 220, + 58, + 12, + 91, + 124, + 6, + 35, + 102, + 2, + 179, + 84, + 184, + 255, + 253, + 48, + 2, + 238, + 187, + 9, + 178, + 197, + 106, + 23, + 179, + 50, + 150, + 74, + 3, + 12, + 125, + 6, + 155, + 3, + 153, + 48, + 83, + 66, + 23, + 243, + 41, + 164, + 15, + 141, + 18, + 16, + 251, + 217, + 15, + 71, + 227, + 213, + 196, + 31, + 64, + 255, + 115, + 215, + 19, + 164, + 126, + 213, + 47, + 94, + 78, + 39, + 165, + 137, + 192, + 34, + 214, + 133, + 241, + 68, + 247, + 39, + 136, + 128, + 66, + 12, + 20, + 15, + 146, + 239, + 134, + 237, + 70, + 23, + 218, + 238, + 222, + 64, + 46, + 245, + 105, + 130, + 222, + 39, + 7, + 248, + 201, + 134, + 25, + 117, + 105, + 63, + 112, + 163, + 165, + 86, + 215, + 222, + 46, + 148, + 53, + 111, + 77, + 8, + 152, + 121, + 225, + 6, + 197, + 218, + 48, + 166, + 170, + 158, + 250, + 247, + 123, + 100, + 157, + 200, + 104, + 236, + 210, + 135, + 6, + 131, + 147, + 113, + 240, + 192, + 8, + 216, + 84, + 110, + 186, + 17, + 204, + 218, + 185, + 1, + 14, + 43, + 37, + 83, + 43, + 121, + 227, + 102, + 124, + 69, + 176, + 240, + 129, + 196, + 146, + 74, + 95, + 138, + 219, + 35, + 10, + 41, + 19, + 201, + 0, + 50, + 105, + 144, + 132, + 38, + 82, + 240, + 179, + 83, + 3, + 148, + 232, + 45, + 190, + 190, + 60, + 72, + 76, + 181, + 111, + 5, + 60, + 6, + 172, + 106, + 172, + 57, + 149, + 156, + 74, + 254, + 211, + 245, + 51, + 44, + 245, + 40, + 177, + 134, + 17, + 122, + 243, + 0, + 138, + 4, + 217, + 117, + 35, + 64, + 177, + 237, + 81, + 164, + 169, + 118, + 54, + 77, + 130, + 171, + 187, + 180, + 104, + 87, + 215, + 102, + 178, + 41, + 168, + 103, + 209, + 151, + 221, + 201, + 109, + 178, + 84, + 136, + 161, + 5, + 190, + 140, + 21, + 65, + 150, + 132, + 31, + 50, + 198, + 139, + 78, + 62, + 173, + 74, + 28, + 240, + 112, + 136, + 119, + 239, + 175, + 79, + 109, + 227, + 138, + 19, + 24, + 203, + 23, + 33, + 212, + 203, + 116, + 103, + 101, + 109, + 150, + 83, + 73, + 38, + 100, + 59, + 113, + 109, + 188, + 54, + 57, + 200, + 30, + 10, + 64, + 106, + 152, + 200, + 225, + 215, + 171, + 44, + 18, + 43, + 49, + 130, + 117, + 222, + 248, + 153, + 75, + 84, + 24, + 167, + 31, + 254, + 197, + 185, + 180, + 139, + 9, + 242, + 71, + 198, + 71, + 69, + 255, + 124, + 42, + 29, + 236, + 230, + 164, + 251, + 234, + 51, + 11, + 73, + 69, + 32, + 213, + 127, + 219, + 25, + 166, + 60, + 201, + 58, + 25, + 43, + 76, + 37, + 47, + 246, + 61, + 47, + 139, + 197, + 155, + 3, + 37, + 135, + 19, + 41, + 62, + 237, + 81, + 17, + 187, + 31, + 181, + 227, + 190, + 86, + 105, + 219, + 64, + 111, + 121, + 234, + 196, + 179, + 114, + 232, + 130, + 76, + 60, + 183, + 171, + 15, + 176, + 136, + 136, + 157, + 180, + 89, + 56, + 16, + 20, + 179, + 125, + 65, + 103, + 228, + 70, + 239, + 212, + 237, + 110, + 45, + 174, + 65, + 11, + 111, + 108, + 54, + 211, + 75, + 22, + 9, + 68, + 50, + 115, + 133, + 160, + 39, + 191, + 196, + 184, + 167, + 57, + 158, + 12, + 119, + 161, + 67, + 132, + 11, + 21, + 80, + 130, + 100, + 70, + 132, + 192, + 251, + 235, + 176, + 160, + 47, + 87, + 43, + 43, + 181, + 157, + 170, + 119, + 59, + 40, + 4, + 4, + 252, + 155, + 239, + 234, + 146, + 247, + 164, + 181, + 5, + 4, + 24, + 194, + 168, + 51, + 173, + 46, + 60, + 9, + 24, + 218, + 100, + 40, + 253, + 147, + 128, + 28, + 94, + 212, + 61, + 145, + 195, + 118, + 155, + 158, + 135, + 185, + 77, + 224, + 21, + 44, + 10, + 151, + 147, + 236, + 164, + 183, + 81, + 51, + 0, + 190, + 171, + 208, + 42, + 91, + 250, + 206, + 245, + 84, + 114, + 174, + 39, + 156, + 248, + 129, + 6, + 30, + 126, + 100, + 202, + 25, + 110, + 38, + 122, + 37, + 27, + 140, + 23, + 144, + 79, + 131, + 200, + 80, + 199, + 105, + 152, + 24, + 38, + 10, + 158, + 42, + 193, + 143, + 98, + 47, + 47, + 48, + 231, + 250, + 255, + 175, + 169, + 185, + 43, + 150, + 22, + 189, + 70, + 24, + 55, + 216, + 145, + 219, + 173, + 193, + 70, + 205, + 180, + 107, + 159, + 58, + 137, + 50, + 119, + 143, + 35, + 12, + 11, + 133, + 193, + 174, + 148, + 213, + 179, + 85, + 219, + 246, + 177, + 216, + 54, + 153, + 150, + 218, + 103, + 237, + 37, + 213, + 204, + 127, + 10, + 20, + 109, + 209, + 207, + 51, + 238, + 125, + 82, + 66, + 44, + 146, + 133, + 55, + 223, + 137, + 53, + 254, + 93, + 0, + 136, + 35, + 217, + 208, + 14, + 139, + 56, + 36, + 122, + 42, + 189, + 213, + 213, + 23, + 184, + 53, + 7, + 59, + 196, + 116, + 40, + 16, + 171, + 239, + 20, + 228, + 76, + 203, + 133, + 91, + 111, + 88, + 222, + 21, + 20, + 167, + 207, + 55, + 119, + 78, + 42, + 245, + 238, + 156, + 211, + 57, + 217, + 98, + 173, + 227, + 141, + 75, + 194, + 52, + 117, + 57, + 18, + 198, + 193, + 130, + 166, + 158, + 43, + 233, + 193, + 47, + 180, + 126, + 60, + 148, + 223, + 119, + 219, + 36, + 93, + 42, + 2, + 16, + 23, + 18, + 52, + 221, + 215, + 28, + 182, + 229, + 182, + 158, + 16, + 111, + 176, + 93, + 66, + 7, + 192, + 193, + 109, + 39, + 163, + 251, + 142, + 5, + 75, + 40, + 26, + 25, + 113, + 132, + 83, + 79, + 242, + 5, + 109, + 199, + 160, + 150, + 88, + 226, + 71, + 52, + 8, + 112, + 136, + 46, + 44, + 245, + 123, + 243, + 227, + 138, + 133, + 169, + 173, + 184, + 97, + 152, + 197, + 192, + 181, + 128, + 21, + 101, + 97, + 190, + 174, + 127, + 198, + 18, + 138, + 97, + 161, + 143, + 134, + 45, + 89, + 57, + 138, + 72, + 146, + 2, + 116, + 89, + 41, + 84, + 225, + 226, + 13, + 32, + 117, + 105, + 158, + 231, + 227, + 93, + 103, + 144, + 58, + 123, + 133, + 63, + 186, + 227, + 57, + 224, + 249, + 180, + 173, + 113, + 238, + 10, + 50, + 93, + 5, + 25, + 172, + 30, + 189, + 210, + 157, + 176, + 38, + 20, + 181, + 70, + 117, + 26, + 84, + 247, + 17, + 144, + 104, + 159, + 2, + 126, + 163, + 164, + 161, + 215, + 105, + 70, + 238, + 221, + 85, + 134, + 92, + 155, + 186, + 248, + 101, + 154, + 48, + 201, + 164, + 0, + 101, + 69, + 208, + 78, + 229, + 40, + 238, + 5, + 244, + 229, + 87, + 98, + 46, + 77, + 98, + 150, + 122, + 111, + 190, + 231, + 123, + 153, + 71, + 182, + 125, + 10, + 244, + 162, + 104, + 215, + 216, + 83, + 184, + 92, + 122, + 115, + 140, + 63, + 183, + 248, + 50, + 171, + 186, + 53, + 196, + 253, + 16, + 73, + 67, + 124, + 194, + 249, + 49, + 217, + 75, + 211, + 12, + 104, + 26, + 218, + 115, + 8, + 250, + 185, + 127, + 253, + 118, + 28, + 116, + 147, + 128, + 90, + 230, + 51, + 90, + 204, + 23, + 155, + 208, + 91, + 73, + 201, + 229, + 103, + 234, + 193, + 120, + 140, + 235, + 206, + 95, + 176, + 41, + 14, + 206, + 187, + 21, + 231, + 176, + 14, + 55, + 204, + 144, + 181, + 239, + 194, + 229, + 209, + 8, + 224, + 182, + 134, + 141, + 212, + 122, + 196, + 115, + 155, + 56, + 60, + 53, + 198, + 120, + 133, + 152, + 126, + 142, + 137, + 247, + 171, + 149, + 115, + 149, + 136, + 2, + 149, + 156, + 23, + 30, + 251, + 16, + 234, + 137, + 144, + 206, + 167, + 248, + 113, + 145, + 126, + 18, + 39, + 44, + 134, + 240, + 130, + 92, + 216, + 156, + 237, + 107, + 161, + 240, + 103, + 39, + 35, + 65, + 34, + 62, + 226, + 43, + 106, + 117, + 113, + 239, + 108, + 191, + 65, + 143, + 202, + 112, + 68, + 174, + 78, + 63, + 112, + 119, + 195, + 244, + 120, + 240, + 157, + 197, + 134, + 70, + 67, + 218, + 181, + 152, + 163, + 178, + 149, + 51, + 159, + 219, + 1, + 168, + 114, + 20, + 232, + 38, + 226, + 14, + 151, + 7, + 84, + 211, + 39, + 71, + 220, + 63, + 164, + 118, + 119, + 186, + 157, + 159, + 4, + 155, + 148, + 34, + 206, + 89, + 219, + 88, + 67, + 33, + 24, + 205, + 63, + 162, + 121, + 24, + 37, + 165, + 172, + 235, + 159, + 209, + 95, + 23, + 239, + 85, + 51, + 143, + 231, + 213, + 251, + 77, + 78, + 207, + 148, + 25, + 132, + 63, + 67, + 67, + 155, + 227, + 226, + 243, + 50, + 128, + 146, + 143, + 74, + 229, + 203, + 123, + 2, + 78, + 153, + 166, + 126, + 70, + 210, + 79, + 39, + 115, + 124, + 131, + 108, + 167, + 189, + 239, + 190, + 93, + 118, + 193, + 129, + 96, + 41, + 241, + 244, + 19, + 199, + 6, + 82, + 197, + 59, + 220, + 38, + 236, + 187, + 101, + 49, + 233, + 189, + 84, + 54, + 216, + 77, + 23, + 49, + 242, + 22, + 239, + 251, + 62, + 3, + 201, + 144, + 151, + 170, + 86, + 46, + 250, + 3, + 89, + 29, + 34, + 27, + 104, + 117, + 49, + 48, + 214, + 143, + 85, + 235, + 22, + 112, + 112, + 67, + 174, + 79, + 5, + 47, + 189, + 204, + 72, + 122, + 206, + 151, + 157, + 188, + 36, + 11, + 231, + 84, + 226, + 54, + 214, + 18, + 50, + 80, + 53, + 78, + 59, + 186, + 101, + 149, + 188, + 36, + 225, + 145, + 216, + 95, + 30, + 169, + 107, + 122, + 112, + 162, + 227, + 118, + 83, + 183, + 124, + 207, + 10, + 132, + 75, + 166, + 30, + 177, + 85, + 77, + 93, + 23, + 206, + 99, + 53, + 38, + 213, + 101, + 138, + 81, + 40, + 18, + 253, + 227, + 110, + 145, + 132, + 162, + 119, + 50, + 77, + 230, + 250, + 184, + 174, + 98, + 122, + 228, + 34, + 9, + 24, + 48, + 251, + 215, + 237, + 87, + 167, + 233, + 168, + 171, + 184, + 46, + 215, + 111, + 86, + 10, + 46, + 79, + 213, + 167, + 188, + 181, + 19, + 227, + 72, + 140, + 197, + 163, + 22, + 106, + 233, + 70, + 139, + 4, + 99, + 170, + 176, + 166, + 106, + 84, + 250, + 159, + 104, + 49, + 103, + 82, + 132, + 254, + 116, + 139, + 134, + 164, + 207, + 202, + 108, + 225, + 198, + 244, + 122, + 247, + 186, + 150, + 120, + 75, + 144, + 236, + 181, + 213, + 187, + 49, + 206, + 250, + 235, + 235, + 222, + 107, + 227, + 91, + 153, + 158, + 173, + 123, + 100, + 35, + 134, + 176, + 227, + 130, + 73, + 46, + 7, + 144, + 3, + 7, + 72, + 203, + 63, + 112, + 1, + 164, + 89, + 252, + 88, + 128, + 253, + 155, + 126, + 223, + 214, + 89, + 32, + 21, + 120, + 190, + 82, + 144, + 11, + 89, + 38, + 86, + 36, + 200, + 166, + 169, + 166, + 18, + 68, + 102, + 74, + 5, + 189, + 55, + 48, + 114, + 73, + 31, + 51, + 49, + 157, + 164, + 162, + 31, + 243, + 183, + 28, + 37, + 157, + 242, + 210, + 83, + 92, + 246, + 41, + 110, + 130, + 213, + 29, + 194, + 103, + 125, + 71, + 156, + 115, + 217, + 167, + 143, + 212, + 83, + 51, + 99, + 2, + 155, + 146, + 71, + 29, + 173, + 241, + 254, + 35, + 4, + 69, + 42, + 188, + 106, + 134, + 224, + 159, + 53, + 28, + 6, + 16, + 56, + 137, + 18, + 82, + 170, + 171, + 249, + 234, + 193, + 109, + 233, + 171, + 100, + 3, + 60, + 14, + 60, + 36, + 47, + 152, + 142, + 114, + 197, + 215, + 12, + 254, + 205, + 178, + 220, + 129, + 103, + 35, + 212, + 172, + 72, + 69, + 105, + 112, + 212, + 78, + 37, + 19, + 149, + 59, + 69, + 175, + 23, + 85, + 70, + 110, + 230, + 153, + 38, + 162, + 0, + 172, + 11, + 113, + 75, + 177, + 204, + 60, + 103, + 47, + 205, + 94, + 43, + 95, + 247, + 157, + 5, + 168, + 233, + 158, + 238, + 69, + 121, + 29, + 91, + 128, + 175, + 229, + 183, + 195, + 11, + 78, + 187, + 36, + 38, + 192, + 126, + 184, + 38, + 95, + 20, + 223, + 136, + 71, + 241, + 165, + 174, + 52, + 254, + 165, + 187, + 176, + 84, + 224, + 50, + 49, + 88, + 151, + 51, + 202, + 222, + 179, + 108, + 178, + 239, + 205, + 22, + 5, + 118, + 241, + 121, + 174, + 245, + 54, + 27, + 11, + 87, + 248, + 15, + 42, + 224, + 220, + 194, + 19, + 122, + 192, + 144, + 102, + 73, + 162, + 170, + 85, + 221, + 70, + 147, + 206, + 239, + 136, + 97, + 35, + 62, + 91, + 63, + 177, + 165, + 60, + 178, + 37, + 76, + 1, + 214, + 152, + 198, + 193, + 7, + 137, + 218, + 230, + 247, + 6, + 104, + 134, + 232, + 168, + 65, + 144, + 192, + 189, + 78, + 131, + 137, + 113, + 158, + 77, + 31, + 165, + 64, + 62, + 79, + 185, + 189, + 102, + 46, + 76, + 151, + 209, + 90, + 10, + 138, + 93, + 57, + 147, + 70, + 84, + 92, + 107, + 63, + 42, + 255, + 243, + 182, + 3, + 18, + 222, + 61, + 157, + 142, + 27, + 61, + 131, + 41, + 238, + 83, + 58, + 27, + 197, + 201, + 182, + 185, + 55, + 162, + 194, + 57, + 78, + 31, + 222, + 90, + 207, + 221, + 41, + 11, + 107, + 147, + 1, + 91, + 71, + 2, + 241, + 179, + 249, + 234, + 2, + 2, + 182, + 44, + 79, + 184, + 102, + 173, + 225, + 171, + 29, + 192, + 79, + 83, + 16, + 100, + 137, + 140, + 144, + 141, + 253, + 150, + 165, + 232, + 131, + 139, + 16, + 176, + 181, + 128, + 82, + 143, + 156, + 188, + 192, + 239, + 161, + 216, + 148, + 58, + 82, + 54, + 109, + 176, + 20, + 35, + 114, + 99, + 141, + 253, + 141, + 179, + 220, + 137, + 174, + 36, + 80, + 91, + 151, + 108, + 255, + 1, + 120, + 112, + 236, + 240, + 103, + 112, + 91, + 78, + 144, + 148, + 53, + 91, + 0, + 230, + 251, + 28, + 228, + 31, + 179, + 208, + 81, + 87, + 150, + 46, + 123, + 198, + 199, + 245, + 112, + 150, + 63, + 194, + 117, + 172, + 211, + 205, + 115, + 109, + 123, + 22, + 32, + 208, + 252, + 172, + 4, + 10, + 144, + 87, + 53, + 19, + 126, + 121, + 96, + 1, + 49, + 126, + 213, + 26, + 198, + 34, + 132, + 243, + 148, + 245, + 252, + 230, + 206, + 183, + 157, + 228, + 154, + 135, + 91, + 0, + 46, + 127, + 128, + 183, + 178, + 144, + 220, + 85, + 80, + 210, + 168, + 93, + 159, + 104, + 168, + 54, + 60, + 102, + 180, + 175, + 101, + 126, + 73, + 25, + 81, + 88, + 64, + 199, + 207, + 222, + 233, + 241, + 253, + 88, + 163, + 142, + 74, + 74, + 254, + 75, + 109, + 35, + 35, + 29, + 116, + 114, + 129, + 0, + 181, + 116, + 121, + 120, + 37, + 13, + 119, + 42, + 105, + 45, + 149, + 232, + 28, + 60, + 235, + 233, + 26, + 211, + 127, + 13, + 254, + 220, + 237, + 14, + 24, + 40, + 95, + 39, + 65, + 129, + 156, + 174, + 198, + 140, + 127, + 191, + 6, + 125, + 84, + 36, + 138, + 79, + 183, + 5, + 141, + 161, + 1, + 191, + 20, + 2, + 19, + 168, + 98, + 49, + 97, + 16, + 12, + 120, + 171, + 171, + 77, + 133, + 26, + 51, + 117, + 20, + 137, + 158, + 233, + 90, + 129, + 180, + 55, + 49, + 54, + 132, + 194, + 11, + 255, + 73, + 245, + 184, + 5, + 83, + 192, + 70, + 34, + 88, + 161, + 55, + 170, + 59, + 8, + 126, + 199, + 190, + 47, + 15, + 47, + 94, + 52, + 167, + 42, + 46, + 134, + 152, + 40, + 116, + 23, + 167, + 101, + 13, + 68, + 134, + 2, + 103, + 120, + 134, + 88, + 62, + 92, + 65, + 203, + 118, + 59, + 38, + 97, + 112, + 69, + 236, + 26, + 212, + 70, + 25, + 204, + 212, + 77, + 11, + 42, + 58, + 69, + 137, + 155, + 154, + 96, + 28, + 84, + 9, + 107, + 70, + 131, + 19, + 251, + 47, + 52, + 231, + 97, + 160, + 178, + 202, + 215, + 44, + 221, + 41, + 150, + 167, + 199, + 33, + 231, + 28, + 81, + 15, + 208, + 94, + 29, + 1, + 44, + 208, + 53, + 58, + 193, + 65, + 119, + 19, + 101, + 35, + 46, + 25, + 63, + 234, + 186, + 88, + 61, + 9, + 244, + 173, + 50, + 13, + 152, + 160, + 233, + 21, + 33, + 189, + 177, + 60, + 55, + 251, + 141, + 103, + 132, + 75, + 124, + 155, + 124, + 0, + 101, + 215, + 146, + 61, + 188, + 17, + 129, + 67, + 151, + 212, + 236, + 61, + 117, + 191, + 238, + 87, + 34, + 98, + 155, + 77, + 76, + 103, + 145, + 121, + 239, + 50, + 22, + 221, + 106, + 116, + 184, + 59, + 84, + 49, + 148, + 15, + 250, + 211, + 147, + 26, + 147, + 124, + 137, + 11, + 176, + 206, + 150, + 116, + 27, + 100, + 158, + 151, + 196, + 108, + 212, + 101, + 255, + 153, + 175, + 48, + 99, + 212, + 5, + 20, + 141, + 192, + 227, + 78, + 47, + 170, + 47, + 72, + 124, + 178, + 44, + 77, + 20, + 76, + 190, + 144, + 54, + 213, + 236, + 209, + 239, + 223, + 128, + 118, + 116, + 176, + 247, + 218, + 15, + 35, + 224, + 34, + 123, + 62, + 12, + 41, + 96, + 198, + 158, + 180, + 238, + 171, + 123, + 43, + 222, + 118, + 198, + 111, + 84, + 159, + 145, + 167, + 190, + 249, + 3, + 15, + 159, + 197, + 40, + 123, + 124, + 47, + 162, + 66, + 82, + 62, + 126, + 104, + 22, + 54, + 237, + 26, + 132, + 120, + 22, + 219, + 181, + 32, + 160, + 119, + 192, + 188, + 205, + 151, + 43, + 143, + 20, + 76, + 244, + 206, + 115, + 63, + 161, + 228, + 64, + 32, + 250, + 75, + 68, + 174, + 189, + 159, + 93, + 86, + 59, + 138, + 245, + 56, + 116, + 21, + 252, + 153, + 77, + 144, + 146, + 156, + 4, + 76, + 120, + 239, + 118, + 227, + 228, + 228, + 89, + 170, + 135, + 51, + 143, + 94, + 188, + 20, + 40, + 175, + 241, + 113, + 88, + 184, + 176, + 59, + 135, + 77, + 111, + 61, + 2, + 115, + 13, + 212, + 226, + 142, + 40, + 131, + 47, + 70, + 152, + 134, + 43, + 41, + 46, + 55, + 184, + 189, + 57, + 90, + 145, + 98, + 126, + 66, + 39, + 174, + 46, + 164, + 253, + 24, + 37, + 97, + 220, + 180, + 67, + 31, + 255, + 187, + 60, + 245, + 194, + 46, + 105, + 226, + 132, + 251, + 165, + 51, + 103, + 149, + 160, + 153, + 239, + 243, + 223, + 178, + 13, + 166, + 1, + 11, + 232, + 135, + 178, + 213, + 214, + 84, + 252, + 91, + 124, + 164, + 216, + 182, + 75, + 85, + 181, + 112, + 108, + 145, + 25, + 49, + 180, + 31, + 165, + 20, + 175, + 182, + 208, + 239, + 144, + 26, + 180, + 174, + 252, + 238, + 162, + 155, + 5, + 235, + 23, + 78, + 72, + 250, + 225, + 82, + 20, + 14, + 72, + 225, + 35, + 108, + 0, + 74, + 103, + 136, + 147, + 251, + 87, + 53, + 227, + 211, + 242, + 167, + 53, + 9, + 171, + 214, + 58, + 7, + 237, + 78, + 83, + 32, + 138, + 208, + 208, + 206, + 51, + 70, + 143, + 79, + 60, + 98, + 248, + 8, + 150, + 19, + 134, + 228, + 14, + 46, + 190, + 131, + 115, + 206, + 237, + 67, + 232, + 147, + 235, + 141, + 65, + 212, + 135, + 156, + 36, + 16, + 196, + 13, + 40, + 160, + 9, + 106, + 88, + 85, + 178, + 98, + 121, + 13, + 166, + 25, + 95, + 149, + 220, + 135, + 1, + 93, + 95, + 118, + 131, + 72, + 85, + 120, + 202, + 171, + 22, + 130, + 243, + 63, + 40, + 40, + 155, + 79, + 19, + 63, + 239, + 169, + 144, + 1, + 34, + 158, + 94, + 134, + 190, + 232, + 105, + 148, + 179, + 190, + 40, + 229, + 232, + 238, + 207, + 177, + 180, + 225, + 20, + 12, + 112, + 177, + 235, + 191, + 48, + 188, + 34, + 155, + 152, + 180, + 126, + 92, + 14, + 66, + 99, + 236, + 206, + 71, + 118, + 28, + 223, + 56, + 1, + 44, + 37, + 231, + 187, + 243, + 132, + 251, + 161, + 43, + 14, + 119, + 118, + 28, + 149, + 254, + 214, + 49, + 100, + 26, + 12, + 110, + 43, + 246, + 202, + 5, + 201, + 68, + 56, + 112, + 0, + 238, + 31, + 40, + 141, + 205, + 36, + 93, + 88, + 112, + 144, + 49, + 140, + 153, + 149, + 194, + 197, + 181, + 139, + 66, + 89, + 230, + 73, + 87, + 122, + 53, + 171, + 22, + 139, + 9, + 102, + 32, + 206, + 46, + 87, + 233, + 92, + 244, + 26, + 217, + 33, + 3, + 157, + 202, + 237, + 80, + 174, + 195, + 238, + 208, + 113, + 14, + 95, + 91, + 206, + 80, + 128, + 213, + 211, + 139, + 12, + 173, + 134, + 40, + 54, + 40, + 73, + 187, + 246, + 13, + 39, + 100, + 131, + 5, + 45, + 96, + 222, + 104, + 56, + 20, + 73, + 224, + 144, + 247, + 5, + 98, + 219, + 107, + 108, + 26, + 232, + 23, + 233, + 109, + 129, + 142, + 92, + 175, + 6, + 136, + 186, + 208, + 85, + 162, + 234, + 92, + 249, + 201, + 146, + 30, + 201, + 27, + 70, + 121, + 222, + 106, + 254, + 239, + 43, + 69, + 15, + 68, + 129, + 47, + 50, + 27, + 200, + 180, + 88, + 141, + 234, + 157, + 95, + 209, + 97, + 154, + 188, + 59, + 186, + 169, + 19, + 73, + 78, + 88, + 26, + 138, + 193, + 95, + 207, + 106, + 38, + 68, + 41, + 208, + 34, + 170, + 75, + 147, + 101, + 251, + 44, + 154, + 156, + 222, + 5, + 1, + 91, + 134, + 101, + 250, + 196, + 231, + 234, + 143, + 195, + 157, + 212, + 251, + 221, + 100, + 74, + 197, + 138, + 34, + 178, + 79, + 42, + 186, + 29, + 23, + 227, + 73, + 226, + 136, + 183, + 26, + 68, + 30, + 8, + 123, + 144, + 107, + 118, + 243, + 244, + 75, + 217, + 96, + 77, + 218, + 195, + 165, + 216, + 105, + 69, + 47, + 98, + 207, + 200, + 40, + 48, + 102, + 38, + 166, + 247, + 146, + 178, + 253, + 252, + 79, + 135, + 0, + 83, + 46, + 166, + 80, + 69, + 140, + 34, + 20, + 203, + 60, + 120, + 128, + 45, + 193, + 28, + 58, + 37, + 176, + 73, + 46, + 255, + 239, + 212, + 80, + 152, + 113, + 206, + 164, + 229, + 15, + 76, + 19, + 116, + 75, + 91, + 40, + 12, + 80, + 188, + 121, + 24, + 76, + 135, + 220, + 111, + 81, + 76, + 91, + 139, + 64, + 69, + 29, + 44, + 123, + 99, + 31, + 108, + 81, + 170, + 209, + 255, + 41, + 50, + 66, + 74, + 225, + 188, + 130, + 211, + 100, + 2, + 48, + 228, + 50, + 17, + 213, + 225, + 221, + 77 +] diff --git a/crates/starknet_os/src/hints/hint_implementation/kzg/fft_regression_input.json b/crates/starknet_os/src/hints/hint_implementation/kzg/fft_regression_input.json new file mode 100644 index 00000000000..67e2cbaba42 --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/kzg/fft_regression_input.json @@ -0,0 +1,4098 @@ +[ + "2256525055050173099272789413975329458913202604230993824449084317739004391404078172318204527939442950312323945436147", + "793891092371137599743482856389234316555960755636037312244477165258244497727357161221704139503210153176653801218276", + "741987744536604650459016266721817468285648864186188547948528192907409701497442725444219826063100669530912141842739", + "506956872661188542383611846939011553823536132523077742187666122072146347691215837428597169956849638907407045929868", + "580684662924492657191795986352618519255430534723807899888961026187293606050548060019622581157724419305164990441878", + "1688436051064325412268720444012346085780483400887266808746775859985366953106892563707921546529713936408166281984931", + "1488945660326926210883249729992880759851671789039006401781760644017330158090278713518140617025526369493266090841382", + "2300929327527533527073141436707786086106029114961988687941294892269515216740979805421647772941467410385498810478048", + "2067551807146361234919049533283195445700957586617107580167891801457794482283738583134474685186285828618855688254877", + "517209428603728421964956093657781645211783341532662039996191506090341501556764952917918786617033959604691638296641", + "611781230944814706977904867305655553625506804526272947601691327050599640457380036671043340198537579784934142007873", + "967058099240758803458134112186216175925511528372692619548842006158389370872531745216042378521631171113735446878476", + "2069765843482112102592693502103160589706403303864226775728970084686770823677117318608833730813468709069309818805127", + "2460925929169538985418513713439370220625101222537689857778956864523408785327513549123287204252928400080361230795005", + "1169471839444202221399356039308951092968995044229266698450892020731224098742764918414332801082607865484812156282668", + "930643203517671151540118987411892084419282286253753499171579223295312977359903585023976031078660891097723524900248", + "389878528188739822418063509227797842735981058882034581056169693120760395065376203998024332537185255898234958914392", + "1477714910384168711633099330534149556635617343623135844491131277650294555658849576658794156260787073802235666061353", + "1012299206962560979057018335252150005134984064868328767866641001076358989032194109440178038699748361049958569083861", + "1168060416937942158471684888584142166487960075405134465079261675233833085940343577311916653844661469942076237241227", + "2392376498815372814011641539090593608092183912655170759908654979646891145842447564610749540877093236409331879573082", + "1804615009105594895843121271689762147502209580709037212819550137949930934756770999119359028297340344029209297348634", + "821999135147643212080516701898177007160416131506030655281986873708758521762963391791312879564038635819275183449747", + "2420127196714869412524759991630645564841004426139442496508642595741480550967634166917298165345762352517359473173560", + "916715939289487157954275991934159940753570453489597208825571255688206523309079413780923697709100341715131578455455", + "1549265550591586889241997942256719369595415317080677086599583307979662390691824505924115656674119429901414676628882", + "167486462833484566855356066561965584593545181451099334347138794601210681558625864504363294434439575957019135635370", + "611581895289873449674324191810488617592891293463582576836839704423838573578503043381659518391229984166773317952937", + "1058072418623224674547215147270867869896959361112155765487984293153697724650756748499687269595673664878043343718951", + "1054923259596603751271478470197725971544480740217417725537667320723683310178985083571332165604078164395535034651832", + "1130272117742396759381079531482857609098583428788654058478554523321225239765927502290705716578820785785056477252995", + "630849725664241025253553410377241021552144702408787959468130468611801076585300593839773419993367059434629734956230", + "1793987701539738304463598226552466856192069236324601326913653686967183921388867649204832678139360587986517332147032", + "1871059491973015039603934828067746404430834232756126830803656194584544571627170027135400080514049100768460179265975", + "48535958046360257501999545339276150066610122169888048449484672364982775458063254462022702649599736957629020246206", + "2067631272487494100903893181798753261905149111704806449854143723434939315898124619017322858260569875390192021068566", + "1140146470140320959313174885687914703407059273437938609764604155429836610593456809208728607046219691018893646498487", + "1214666898300761951168149007297760504855367777392615139935929365841246206281725674715222409846405099732835857484495", + "658164890925737596108131801713144806040830182418664378155769397939528318165416714755405595177593895398738427885227", + "146356085915579380441028666938711396249372121890724587001148790282055478379879731361751910312207340346021277609219", + "184739359860541404358850914138566356466687995023942862536276662626054226920601789731153747221929508316349390375741", + "999320566532284855344655637094334157723612430644718451298362178004787197152534703246987642112026822733991603219911", + "233252086095926445405955405460685556519707094087308533335362973642845975432145805422371477478094512516395264188554", + "840328390616584948373459684306211122964963976976553969503449922375932508289331548387262300156822358169339034096883", + "798246198336369789262806028813736924217965944297451080378085906762216846326142763173851613881791717810869190924542", + "1710065643939904096969938063219853018035475005109220432388266513160974034022837145565016240578208976492574825875437", + "2113324112561408026440768671846993615884736990661657843552106073022984614990948314028019322874707393469492200501587", + "1395151906628962119608156054519961591256621747377885679153316568181942100076184705424269301310300726841551503521113", + "1545107173165854632398063802943320008144593059939653224046208543815663460913074847943426070161150814520694713300004", + "201804964153222377512074077947766976921588019156407454656370278665961797252478717563416106127018827746794083706215", + "1846700614186526275790057641739620196214763814563296318422493027840301367009138063753108143715868393236976424436200", + "1472005099275199152635110240622270769229633322820391530273283286561491270305791710766758909791083867321298021088749", + "1895986026361704392415539017664634028489512890415653575477157174197416159516712946552752776700057329591259271047779", + "1696778866661034293494957111815315688671968530553943546260256130867926998592199148938207915137240359398697931464968", + "2109316339165444809599657033308949170221463083441683746521488072666009032250689093364537634584007202380053688403567", + "2229094621580217905312061166303721702668324438656840445824100038945016672133077122386009806201504755253192524707074", + "293726970330669360211422120642728678564475817141144253297732283064467528689306083670436733747474762988873479499563", + "862672512427442206830496905106850812267791614190578139580436879233417876732188306858911346828770817176572435482683", + "301411876574887168077919132314237340735617199442899106199175891621438467563423593462311414460658098598601516795021", + "491865928638065363475501068398617000051766166405662458196999522424744305576696314033756196671186577581257762880013", + "270375907309216538342444834570215844899962912971650016436671436032540238533557501977561935197796478266157911680906", + "1559336038744525131011303885664072951501912313040128636237046131676642843366538204920654983793227183503826532720117", + "1032650643636717782363861168915070183698596625679856974658237824280449436112630097566072917358179709367769645474488", + "2347657799646563226264706898910078625565965133188829522081636182433496248368764024520327593164264749907944901908921", + "1382194388953398158866192193712320469453932434715764318160784227274536281055785798162527076272573761646655517510686", + "1827030775275331780920504926849247100416238405878378141951309633050119336999904139346221322890446879190828780561949", + "542593979414357208483318956267730529941183369389875800544095998214799079016812108163980127027994004202904703857165", + "1171759496987466993429858026183644622937403682554357179411177944612587639017578021068301965809346850846984235426758", + "2012974796566630363350270909149480906170279370516240267784444299827432231212968309225836198754636444062396861056211", + "524653536919278623964032256314117777250150038388038958965218274799558747004326389970891335004073556605229156303545", + "659104056595441588708063316603541479638030056997086064219117249244312815400795952043095880965971676043063437124069", + "356606443591083130891882697807110035958781119560533051818310939268560808320086379863060941701839955218118644992704", + "629654680194540314230514370070806476249381937775301073305325678034021981942607422761247748773276880897742384344792", + "1537966517987546409175927684329235996410071618903507462527807648462139483465953672141171529969654372176176756864311", + "288746464812282427372677066027979281584814931539614298072667064477172542273731394751538960685837520412915525246027", + "895549714629158853890571778905812436330156143557538732780607730588329423473809984517397102678103349302078171101492", + "1453910366288928069288606692011011270030292445264176083377785407373177446585515791340242410945762718949716459967194", + "1008974698482182340822926015678291925405720266445063924871532691546114366049253705246127862643958736978679986447497", + "1210956925367356606850618646519864996287606920115061119986477924986200241461211398381510768734033574055374346127859", + "2238077669757232120033758901058314638320300430282101091073026797977618435365623296242685938231610052683413471985752", + "1450983103417065967214531087226647862418560543572581302420271484348228476983019624147601857714098845029497139260685", + "1196477759011692134113575569840210119170156543203753148950760796407838369926304782325479088033652564261042284482563", + "1718503602738781772380774413984449021225834675040380536344741745366040418040776675985983931191784133332213201310722", + "208505760253097887065048018159640368946417228239614934459952624662676327165709838956465618105717757069528956938160", + "2074317093927337367776309891126610820983089453869191044064697369976640639882056037083146105142091297612942319860693", + "1189267900880475399165122746818478575521004680741057496734527153184397567635709173719881022725870103610421239577727", + "170039104495036613278147679517809731090660197971963415929714662671764210699316221031136497864123687490865220429759", + "1485557025692983757612994175990347241750028038772612397606040308135592407449267736172571531175188857600287083693980", + "842490818907447769903246981037558018956695837759654038356595587212473931966766342766589568469734822976399197982964", + "735197033707176439260762062670228548343695173635665608807327086410706657188079409744283617728913025962796240917325", + "415141134714092090456228746359144298241577407361627195524449157923004207188011137827624174100350837820474223948522", + "344215791210191079685276846168534725631085190270162510240025765349839440597356679902936948749571806400995993148054", + "818311640495073458269763270669724196097357738457381499108438114999892326544832759363383732914295782071269523068689", + "1626418255031132707795582044575703611421143126790379423901461870908842127296751687589867677479993746071038956246960", + "1277285608543081374135186741715158739113640210596731561552713122186544550631115699226705268507377500955152881981512", + "250253682998833962302751060452937621831698708006856203729017427954095414874054471366272662206303874268103509005304", + "978716446689336695604485724513384696336761161477659259445483402236948190516279019512769765542898419454276302193545", + "2425430802925807479442124103815221008352247353973942399398684997129614062305847627941304141621635457442427002517045", + "1882932224839151476101213247082906055819971368737450537654839282337719308078891349732609682251766049129657095993274", + "1429717189181431985976022095136776404248932452896107322593490435595518515421452404803991808186079558796880158582904", + "2459798920591820557469487384996971054187988792279563510512158631609664765885160996260725085424154280166500471758670", + "2257194413435117838608876433433344327989793389418669425693027596314667127792973854926598664541044887123065399360927", + "309846417444392987047869469816803496726005752727348085208107922161665650013963815308812317171280090233373277052025", + "1195022819782571262875081595280514746368840653556019945548066240094186286857070933515190698762458771301031421672806", + "304753678670594208253933321109834838869399306294545809129768201785879655804798409544311190248631318105375411959006", + "1550059060711139396963574131470036134482946952131460777778745867514549722226996498391611546420292688216444216834874", + "1978017800822739709235011511936688133964918886332661467451989792756156986530224478029057379271135497299070813316539", + "2392432125244260827787131487686043388376707900182050267897086351628795204263200076521602679331910671551037389276764", + "1611476715117306191691634647882850041516606849832153287479480466060166561940154222879372198548652450046728711715011", + "2196027099792415160809289774461307856865549354296126949395194943913771738786865427174875807272921047122769232652162", + "40751044282113928963598008968625031558576084058846996711490453142332035106793897408467071415496596439682007114146", + "1518711545604797514119624123910893990166385717367141365891821600795151808960062688414913274506917395420040314576213", + "366947369337874543273944237011602669042759715573172596985417008062823738123397037154943931676244188858498414752413", + "917156639193504508964222810114755380787674216692929168727054773718403213681692972856781987450237670096080080552748", + "1520033673629372876258315192956815561669100384903954412763011037848619304281222504967906130715421148437539213184461", + "669596074073045151156074618100343954888484299702267556055820254669138759406120374413755573926428103515501132424621", + "832131339600356692955886665961730380181098240753310691992429281630028688493665157812252560825358328779027609552091", + "2185108865388215091919159889413470420289626641989400591221039816537352495418780677306198700594535362221701182020141", + "1746009327978766911784445974388462186331030853632491812543881204207300596403122205717078757163372834278667055518930", + "1028920589993433280518717964993947491700594422178209620249319487540608796034676950411571862468777353720279413866224", + "383142164556862891384663980161303329180305313269003918355415608723222716532298690343805045086706678275038436314359", + "250516259263502658430488057469438427145719981317067381293838156105779970539972662916478100587113360843446699340075", + "1156028086898184221179793813946908925000750666802471262853689853064049047189816800909538092704080867580814523541673", + "1872051367951502092774130629034646465130288041163651969320001648969169452821813690559924809927207062087966012022396", + "1180868160803148899464911687081469436741492065083687793736404339631527336873879181500334289941783231484532695655316", + "2016654891273446283139433911504492303190544773964350209705099890946424572454463020243727711188262725184939636587268", + "2256441473429573483161586088903910669282013519603275865673161731264530745503392735683746254575511848037980046522548", + "193130685691579161963011158474474345517505636728560398486057067409388317361896904873234179711826404077230027370611", + "1202591175945649174012717464791136744225155240454196146209860829062538961192710228566189901697679108431138864942551", + "2428410054031088295510082884464425291085047999220615719647114677969990891261543707082268167855833935368108547858783", + "774754737891148013741805428942170617571436316633707808782702820975764370848898180896833153399170666752762453281518", + "784806303010652871385492038543760449113995568713617604865761302849103147216274208930603023071370883086832364734222", + "1436580074503659666356215258667571820984266690637851181816851653933331947475937810512059927850887427545940674999773", + "1564786121936863633006896860745281471938087236141060102832542010247263122143784349016052733719606900730844925152162", + "1754084779610969992827914941279256794242132269617550683259739157880387879735866498774466583995718870283309200893996", + "2455794730273694655928451842157431835075238892878640646279947990435246672127951772559932219248154115548630234185367", + "1465644584369210924157780377006561563040473377382201103881267236742871330708548830875313224286998943610545432501165", + "868007332846370988064108785570094220881644715063304274003170467541229668979968053643115286586144311599022343651549", + "987602835633352648965961927605449321297491363303701134269998001752979730157144654766641672321334087893649774552194", + "1809932911100667686012193102729959575189176165774033868746292170494155968663749581904936012797465300304976902182954", + "2036509461934684026032005044275216296934648827936776362720682973640480484714756096079130263359235442760423217215322", + "269746681827713932710593488939980893515395880255248089581655677510305222363071890358162041043654231606979254017200", + "1941659598169372544277251910679097143468624024352223253196533189440458998733386083467230024085752424807169668090272", + "617634941292405105465200597390415695974686514733248209075311997651424642919814775645595251396127200793228292235849", + "617492859674921531215290379638843731701392195133415898935527794806807861618587725018336081385885647945793779112270", + "1142791796085758833530642859563775692176775013773024701825259964328677128860334790201717246967628587633113363544821", + "1388177963099349993794082115965822191737046406065671159118004250105648662331268371147114397544115532837372429115096", + "1860337696584269794530457911077821478778706133191788806712256737083070995776648833188076724842096934418666023542615", + "2065429167319198551004776610751637380655624717500310930626236951175050560783282958416758151920984309634422029727323", + "2409652743437309069708252322292088923652075856857484289783740939391946265533707300036083065599956381005130855316269", + "2350179111922549116070399226145771583475448773344409816268894516331696934697852635632239866544568814376328095902791", + "1375414984285748889220973498966879128464776779771986853554735548549552547921559125199367660824452867114754353594272", + "1492372280300683892301993986635340106041320470469220871352980944266315837586937811249613540689642535826743936418960", + "2149438859935635545211765892412657137846263721237311244015870404409233268171758040572002531166156349881471528768922", + "929806894532875047585821383137381612063191876532032491157314195664237554691671930676715895747789005675431769734505", + "714629976032156375289936000494604822534776589831235862152304769140689780250841562436090693643731929572845020298770", + "822184512935726933747261594427195751162809853414625330714073175907386439005915337977773339796976292044233642149323", + "792214965925629130939878592264768691005150490707115752696850606276328925481751911464191825164326557771002784975415", + "919099664206500520566925028053823740056253452335640741294436690408774503610049403738885331430217392990600198815557", + "2187221592289175885215450947490600136144860760137495163595917732321495953134297255357783483701161214443266309670049", + "801317100961689379072145924952583162240077232022461386814130278690199431792958750635167127096132154476844440385331", + "543550956961650874362449865847771899560894328957349349382930871234654750411418970971871202645461508933069152776328", + "1578228756102408692659425027120646192450655207630632485192281160804690745133792199584553079171565693435150373348442", + "1846845813615674273812286600883959523949903606617391396116294277156239814834228401893391630731554417384641770998017", + "178129648572516731275878040369713830605619555610325902435031673889665906216477587058123951858406356590009460982767", + "1294911959005287654775268327798253779132867018175336388039402593837126635270821857067733923399108703043693333167961", + "810342424660838924007421885371587862978804006828889531236213449248493009351751038831980974695590694046525115109777", + "353431987415376157715169219653421074568436939666743440012876635872096445481326624655268592944342117963120050139443", + "1289588629961081612609919597462138312860937471813476311828388871977371744166234993374421401243694205688802467310806", + "98115630569649763847721661924363153565071923471938340637352014500757235154420574089110200070105727335052516249563", + "1150072500046715364144940528001346580616799475184388876126993766230728217214445490511915606045078156857546996623082", + "1609111244883505154542020035412390208563726411839559248439976003671702717604208325385178380257415794277191279088798", + "542782096920762079486077353165463854306006047462423892365183423695974339225820608564693868355178158468535895663655", + "1026064538637544904506725425710633047441474874777684107581998214245201720260684804112273835282886421709998860059763", + "1034149156348830377720799877564369108205969264875970250834874875091667148492883061345440862995741985109838653413682", + "331684891068539700607983252276191982005304328213205559083116780452098522872811179032528559500100843465790871754532", + "183753377889139554044622508046708914086140636756835724558122580033387384069782932942885977814772116635297813127950", + "2400467067171295463156078670456696727424373634364413069712832675843640561031195845857148260199094099052432844310185", + "169359648322409336628003856109665893831554670826954736117370408562217620649498785929173666207965794499265462772968", + "934560338921000351688684002674090231463947339216489806878805536244390344034908050722961563021699955028102753273279", + "996006071707128719065882872393333489923790157971656220380953348926629034146069026527754550904741522343232266372459", + "1176550409866878967349473462880985159715597412773641039660356475108155947899323449336631614228787855232512413193036", + "13480637718682649471532595349234786412369963138860949875847405630853729757187168745949685996208844784740465639467", + "1929618927095398965372507139584879863896304332078221999094739333553537590968071755521713574374278942231410148413181", + "2069272363495100282885394487971920026280646747184197672650130841349540877086149015661302509714598446735141869159385", + "2129242696010728750792481541684375020275999453572564929089790031585560158508374506610491258327222869181900675127451", + "1004689808381853375686255598723413318309133805792617086046664396024198056035634496575228566781835992684408822981501", + "903429298256444997989824560294847616618344095535747531753563134528676604344795125210670513279224605714386973177097", + "1495756191686868750600905865576780002428483465551009168185352352095329952519621171894195634753521079991759833256480", + "2122972388406105265336852013637252488342385781582535140646112634858276791650377173711720231441605783911518622324244", + "1442630761980723137830447193758609532425105042794414781647685113880395251794296167779708133597316725063082532988230", + "2202471077856640557491198592824261772394543687870032987991227927340020269437909804769666176290430010691381637405046", + "805657620915710467321292191809385108362625710331407794891632425120234303262535878329325676209349174485780789483005", + "263001792296252677758238570387730845155868181563982765231954451139818481163766053656006581640246294959483723357699", + "1577314410679388539866058752815179711934891816259687050225960853009557326712008599447836059616878684108179813468389", + "1121571029175846518160845883433094204731348567110666192308394155252275886605201885792892527072668856390076710766821", + "1490513309047695842891333287570316219559245062126420435359897900620011523125108113552263707126524044533791784174495", + "1618257001803142136472124553894169670662414735697676480569554413075124932981442444143267940477754842788153199293131", + "1778870275252418872362121556854789248158537609998491774689328869586092697112130498838942549237221119367710102656811", + "943126269738149029000715085759830376534363100248031368911905928453969230697400970906109887807850043528828460348416", + "1850640834128398916092322520242534004853835875743767700452421881082305729409921584208623598786550621574293082469295", + "665024810680847055282376003602779714445166236654718962182820067663311406562844425363003817728080915321321036275482", + "263898065477155079310171000259782439657097710189096594853316444417298147601221597016483321615489220110336922093142", + "1672775793423945249412525992427982032195967184484708710733240181625519726835625410193635750104783965733234380734", + "1815471794928592384717127242596646414015035608252065803874656390628007534897608598960700688544380724094651128359932", + "2121485118194398107376256605567385708899797334015684543432976943315594229780545974112868284005893966518325285772263", + "1365813307940393801691188126021015469721922611443307258480105328939843127159058027751750818894114351258543805756630", + "1763078656924125358593908784284448540545144916171273366440789570755080133553035131536463259441153642887403029426548", + "1042198312612418220424391021738773111637876689204420956874389322471254040342045979366377359110178382388171903978823", + "842518493273080893781055808000517574174930077937872655943160583194307793280153612888337671954766718704369813540631", + "2435162219630329992297580750443302961532275829840661525610576570690996940730605823444346062183773203442647718599172", + "852153857965049654209979170051810840974446847505893946323492964226723938318404121804497631698721694625759074349168", + "2073786302160242852770049659337860891357239976010186952411820817676029925044784232803792193370262241439822500743996", + "725994757547756783636525585879262301870829493548767690140737307202028563677001918449774836717361134773802129580242", + "1790450278180293242326774691846290446960745840566876769305756942076034985583842109727753216945581245927440950419190", + "1802479881359145014442812397047171318074500197978395721209657958746142263185262374037518682269782093804214224935806", + "2403774960190431789072982690807173090515643745091471769643231863370750525571140248112540933384491943287622283393024", + "1616632278391821389778468884474900353813019182205074971880379653664520099890076792993041934590104286443993061542412", + "634972037956517694664946491679073256363537913173871924154135359715213321428229687125403795424362641696209412328656", + "1053657134676695515494596191696289874360920661169491115797722821197729105658063186332482258099255206191870534303041", + "1816617975196216494352291158507106394450573837226243922565983571514198007671191772850413592823130934314922223719672", + "2424761308498860954687688307968192973227085238897252995125334370323452428592085112131336894476374704772965957767726", + "1835379699772956259301368992088683568671378377482374628495118492122405118899122725488816178151393210244613186141950", + "98411155683251341770756904825475186259487400082630947940497388321681904545037958529727879613590184972248173165096", + "179059033366903902927210638836493064307682354960874017074728248635681580355180201089177321848319604124282137440821", + "1968365319601400557548398689909196228850170569634313541233443838036752963464613718170924864223679526003765616501274", + "1319262285877206481936202465204253721153258512149284520432938994213920762911778552270662491750098739630362204880336", + "1485501595098281894298166542974401542041578327560432718768116562476073144636184944197920240017053719218390521395321", + "1939467784571172979784517468671994710720604268582464323750104163503438223237472868316134274678900579395709245239277", + "422250063072728287517812736275968548618804890833574360502810740953809689895957039308453062648251090568828807202859", + "1835264799716214399622342887878473990325962516003228095039938854591411581142176889613287323519944079411409332215140", + "2298149151619026484746466481312539806559199895749070605084731795933310585719815896197698717534742608316245452874539", + "1629303176566052928042440444661772470043729115621382640718998055650536337616278838280959395366624144515939729240865", + "1845096212777955123778508216278326137903773890368626988336219049698196326629107268660535419992216051664979507191023", + "433404477747214940611633505745289289391572506099877942857409478031470697611755236447306225395149636496359611277280", + "1964952835544566945674138245076532584740223970522793546157326374109407680910686568634032920046138107424379385058856", + "169333538811067195723238800765978253614078403272044699249962269184469347007863601171688116522763510855319776441844", + "794580180530945680788837145617309353811092250245600455099499531253041768317121106695531747032725314303484084542764", + "1000374219358848863391047003167260884459001483570426350650649088977015622212606970180095371000616076816905562417635", + "1131170878687076908004155729640406733729606528339907493226270730281866547550539596873515198662886905658615251673457", + "1836612714215784188802528121310505439452013619167206618065906611353436617382954653742945742868377569053262376682872", + "2364036018007031650881309548817115764326275904594947913975264401914306100057896477327117331229487798514146258214821", + "1232431838282489444770256882306104685529818523448819258810399218899295957810583725719338241643141416235231001972225", + "1973389566361038218848503500899539271416290611302032119471294251639279446951583532729293044412483299328238159858524", + "1361981903293840624570004137770303451039095015991645153742622707691517212005895783542898045813459476037405730000355", + "1081676919432626788099095062883844482043780783921358137272989395744707969033140910121564372725187852899581517090849", + "1417141433651045279603687027438374529200438155029194327347990132320545711293454471127214920392269274609828826401488", + "830175846028952040563366167307488553041755579593754938245436209589286382409844946339836023573672215856782276289209", + "1213544790184564904297799100850707745860611717255503793606473844611685033635041640019278345209477181572794918867626", + "921047268462809472247985557338907440922895662883038341118284229550202613274567689671521872760897204037122200864247", + "2354910441105563121019474259368436491010467123732677876697590092743087375150439162131800606127215090107192645423768", + "2199518203690332335542626711974941490012929002898446953043775794354472164781899827386395238738023201038371233758571", + "838886246906979323124550516916685295578215553739273330207818852800034539510993977192790408076997047493681395084578", + "1575674014671474177835942539214629542325058064964245063947326504736196045845828745202864142414869016234627746830229", + "156427703806933493827200682572823462968699375170381102065091326759962896529361286490783874748652845623934695095570", + "390626289961345896807436339252369782678670137312893722510175560898571689255764162614672962639471948106983946805454", + "1327525804147083278965533877952541416715974727644563975838479308672121645074071940891916515915114913460328268068567", + "2124929825279122655042187780962607395554921484005881623481988222334172270720918048049656844498219319477061448032838", + "827640065018769101417324986117262165026257674527120242870658739482335150278428904218230399474307551073083127781731", + "1556074355566281117360078628199808107234331554915818119846994802189131119692417550153771663442427269352675823987347", + "1928039556096291605559538422338509501336038146861996146216314079353272196630853114810418363525467217292444117023821", + "2190039131857329211278276136531191830125692767168250820403625195608675255017068186193725461251485045793002296646584", + "1935781415130894730708554577415111829592876173175198778707445829870001820885241708208550693009376507341525309780967", + "62543603200596396703566380167150695793927437027267051491563137071611494381177211747682502769379632813298491717693", + "164267907939214606895246998501818615493633206807337502162992742266444263006210663243742488669567943995954180891567", + "918724760169782829677508999486182308100270711908292757017651903241613862450833451696008771342511762289385295317725", + "1160286845908639419884871555954633220112176113208388206013531012780129035878054501368656954618160036166042800106314", + "118385692341060257192486518197047533788390856107920587021270973974877521436338702752323241580892927171941683143091", + "1066271302004663193141632165087535831971178029722237041859954070511363901668174098681293607722543062582876573537922", + "1764459461824760521049345069847475354467533775014772838366437035355840887860903939633254589288365314889316788161451", + "1330767031767467141126049545641144650966840092612970380784671019907043345262834154506740580114465372480680570129076", + "2446733102184596552778844269006373964281786154664374757401625338678819090919359739687337802419048652384074787382088", + "1124199181855407781404044468469976371165502670681531500122730027862129956487973148276738627804329351518559648859851", + "1140078713086769480698501305056787754675045506735717483323591939971096493551354134945826482682170123976847932237049", + "1109105467760424700207238652480832426593986014523232936522797990684997700873422106469053685626412511989461145629847", + "1425521822103793851586020960337709407514777152962842955993733537481210077153080373323081759242938052852765076617687", + "286947533038247729823447065255405945631634303673287882410915688470468557811937713235968949829578562511460926176516", + "1216780133512009993116935491628461276513564840056782390486501674815949250061706718366373222647526650476560626833744", + "1795830086521868995038070991445466151317885856841338501035896640938179149755918152954143161807372394057691242686281", + "1668660406137266598290317918014092867881106520248620370179058505283929161612844746137639546523641354893908705024882", + "2296872000562610413686151376361282062926006461594729178762204034419971556714761280910741629157182767204838939505812", + "996943622872264335913180404243427036741177430269234145537916126155033627607455346053759973483656684484457393921130", + "1193136484827228884124554800033243117996423173709164305444069455895440155706094908716546958907106890277129464566778", + "1456057851983422166715563851218519986338098742430444709119829749169571996675911474278257919106930343083715920663290", + "2399783196112796796346760218132973953396941847546930939012942787874485262752102118767432103614367111266783986475417", + "216938272554457015989869842079533154317839416996122485606531901216713117622542881094888655596710720005875088539398", + "1803976605116206598768011071628319670374378685046699166208083581304176587075608837587070992458496998299692853216289", + "1441967932719532092756572596314308772836120282823592604586206068517728878101988631123748872555730857562637746418641", + "910035375703994134326675518786588501194230663194830792894463950484274115188584935548594516916082764983754353692837", + "244902652919033475755235869498241163025124951465846773637738741185818512115389186510291192486309287834756375369590", + "80177267118747750563816024643704578957795251114851667545038592238176675525828749360598079276338555858657984288846", + "2442614658019783536514046806252040059338871550227807128627298261054933357791868768749476214700949065275928543733359", + "434845779844440912980297428307203213077144018306818423613103987378885308785937441238888815357005241619180703229000", + "1265647454071521128396129533692972402611188004627821223595211743911835420525622482048509724558403831181847371692288", + "227391806904219548382170725100884243521437033416623941530856941717992621218359950065625034042914125013550969411434", + "1212523060554889874964877048872544600781005125085149429742763860729484179125649082868354166843036333432067478057043", + "548496714389812456390089126635379183704698689881523137728741704036735953133899816967551685462772862300115930610113", + "1928369418745795245928002935177475740994605817514525612110267864778856255158807324889816328271807432929694740942145", + "2283497701108127155722916878436262220485411411408619422857828537071811259064426848740485275871583486407015461528960", + "243303677452171416553881641767355624990096545050541679372869553600404438187735767961025515809829619318194676858010", + "1245520069002734958118205327871662714342780539495642904147333920457012468685652647206235780726120698378174350476816", + "2372786169568443120840893984843856124902755248984792427545145757222543367378970167273053109422100416773131855978419", + "1289891995452256792857711849310056776860027674818190597887370266921277887096180174844586148880173365352610021054842", + "1790242999096286096077506611114938228307062073746739122815993314706776597060117115080546826977713190330501693516084", + "2387014921866008268694614773298936210287985015763663042793199674581487870200161418045541727982188196018507008932064", + "1562225947429590496130473408835595683258311918702806388526511219211651853157987789427245615356766802844930481105359", + "1559338149718913759020051083230770475736858272788695538891539976900217711014640084656574939941546806632346214374755", + "1115131199006803598372661537140263487042900129443576613809227949879984338838305437011782247184260245236226076565160", + "1109178623146026423826253198021737108798444236632302167181082963295633647345346630146318080192101776652019238625135", + "1979189638104526855979796526834456846835499091532071322392864286391226825438785395551213402710416077321680982442557", + "22519206084032432216412512258323144176204666928402343013115910938290594452381090934712761250429602075065771701525", + "2458315085582390022520852205162963055640841374024968432923497082948118039492597627984182013697778050152824386850866", + "437826141149518581137391009117607946206693671414838700182335391050930811243979101374368102665967498019496262387921", + "2125440819268093221220617597626535528945936089820225089057652503421215356132656620037241642408444739141509576890996", + "1302282375002063813513758739831136075749180742535041433072171109744513310964356373484008625925084125945182226458505", + "907675910113462030853006291901364697639551011392525725981238101521493244988903101336508741990115965802840301172927", + "1741776402280013445584605379987856898444001212907911574841448605023457021593960242089161398303440360219060673487935", + "539456425396048076671431517459365660822577550519534271839583918520349198865071988157830926938120215416136144475896", + "1799738798987063575140892880209736325086229716700302925998219861632791231467853015201366867806522045200445908168137", + "805833925863235334871291976817223346150127021389264358686791846789810574049091825580571255157778195324197927723911", + "1035314307543163373643902695088329809285706194806900031036391448440473933944168208981562755228860580052365179838570", + "802363193675359024438832331946401571658260002601247571414135512866955600715510992740049004992741336181621291170290", + "2371349436019328902398377429206573990499071524532116516671000282694478208678632762981514275177623794294115642081239", + "1810793578498858004500527286219893067451937833254153183389819054964915117362071272991215126026609829459712908851660", + "1531661270681355313209948050747136426998223675996234901169357299806984797219402568797794087363898304894171510891892", + "1977668710230164848664657695523446803362021786545462201158455754293165324781015257257647068030847456612785086818023", + "1825299254994208529382030145258107519565217737392559690140265324399590516767058947389333495082170729441255350836062", + "774621229067669009561055451019610340103045485828996178900061557555109701528982359555291044667246854391467503120791", + "54708485578327040172919597830971126247232716987226048057789471593484609809206517741325377777073201067821182005063", + "692889928722497112423314798161158802537010214047487949450995895924971655447210685050993001195905808263933482446306", + "615039773631428651618675499135115704721286246857479521602088307071661445500595889696742487458985137529315697559143", + "1754761528842891516383657183133052892620389134162585619256355157313419149906311476978504742702151853313108264794196", + "704583961631920990551563728401821827969390771611053740844958071264217859897321111916960388010613858934328284048836", + "1345845994444171087805615452356880951854605544714506070425281798623863446117071034570598915263696361924604077270528", + "2257814686657096335026212751082391499725794644985748123651716754633551733834452583316737310433833936828621146868642", + "1676503232496414974712084895160955328871337611722238193265969905416473427410251363252634086944426506129479381712793", + "1896612183479002674282779692741120155138379755030853706145571599760176713169639840767172209570473917348934161883707", + "2378613048867179120828008501971996602631529849743804440861939813290228001661620502726907326826347745716896563228334", + "385236824494316173557160704164900917790547058824028462437180800344774148077165423379898797686370846174271692356023", + "1889593547168901233094521403695529295500740470424963930768393624326171737453777061360357509678140793348642667703799", + "391919179410405048692865174919202216188880773603967143576683384897971168548472740356761123026091195811350607949096", + "384253545850281738624716466941877587651646875016804447466681495583484747509457233379160333156694212874736392536912", + "491453226115891184379382687523342743866272856763506146359836132339405828879813374588467237914485866981699495248848", + "782996037956647918588776211986801743979457800729130298855824153378451315295651686713017913030139114142432448646728", + "2368474315451316074282270176414489955062361226628097366956613877372711796028473118487526800177892350098171714708314", + "1108580614235209561295235845929389247728035161599346628027724536612497753850161864782041685733289760002278537564037", + "592275975100746097808676485141999801074979994493399555141834847334470487557493622512905550753600072766845360531962", + "926990711084100880666413016946623865994110825453555286949600116380583400986198839389726625143054580294710895793798", + "542880768261218398117084077607802463065586558574393152936349288595893933293616722701452151876461407888780989322932", + "1986982389173242283328874518568683748152628371503736867521035726640763013786146366956454121342300817371203039679227", + "2135558414016211721140077019977024336201646560881972080755025534095780419448472787959464223403798049639657928922845", + "1653963172740756075831372137749897878252779347180998999470777353176270232305294305273052165166341477446504414079482", + "2100816755053645996365181713697953575996053704955215078979564757286265411710229565252389162283845787985060686664178", + "1183567930412223749473271439782701501586012932688022419682578740604076593823473277665496063372731892964337966111638", + "1920409333715903974318809980828230185410787966437091380487259606930530178148292064092131867225685248303512624774663", + "2159053549848402856999338133381631019150747699890583742623830827385321658087478330609667395102928670001334583719422", + "101853852410641575203411526127523515928088886652783837854195580402852534147914331012144776367865383714666527328185", + "1720820965985399233626627294317617561662966163242699252722191305171036085395667098413748462519605875421022611900434", + "2124163443603202256260957621037495530021984097407237339597013645879953777049336405756125639112198395348230241532342", + "1028816280208571383154930605605232977091779513791477127921886784699233694362702307287395635633380949901704302258980", + "457435210749206308944849809122073819031891628700445567354628980685739442158032037362365028498765038809861062490691", + "1058014078837626674897885708090454055801616513324075478126086016104051473771141797037946529760268968037468748623016", + "1610334374381287937454405390715688969626837253958926735333814137252791380229527450990883407375231446556927988896254", + "1355139038141383956661588281064656137896076307178115342638358675236519828335042106218562691440941730153129650949728", + "769757892322104974712636639651088096083690353657280029840448364378317674785845965938485563225220151993061886876100", + "1378757399273982484687144186190903676466892709064460037272585486904385619514884323007939702731817472872264826957119", + "1620033908969102739323502146561627232162357019324389343946532685396528831016464467314740669091772246147694050201438", + "552608011695610515909083744232281763310187810751853463131020913093053924139191575369375434335837031172086524536634", + "330874147019746184136170526659189527948022804586695978743978480562836337543957958362258317532818161055966296359079", + "1529768097217958695727510716678095630116433254801797412309335503853121775288579360136623356262226426757266000678112", + "201326842879471914092963361566136840949721428829279436136761531221809909053698542654956224717968868915993289174415", + "1970223418188971011071175032372888784680303492380011856460875733537385481107667988313890657756604392542166971464787", + "1508067260552368437062783024264159767382387622546623749174928730897366577499498902145260642438455038982037063632612", + "1874926585793570155528767494118485663441965708266594775935798663441188831190375184226977080181011200154194489964225", + "2178903667654986305645612493998186314101934067647019098848838317640594993412624237991897148400632038145361170419207", + "2292280396959164502285587506272189805107490242694878103429764127946680225031009377070968622925285236625383936978746", + "1678436065207822785186555140522424081774065284683290494233477343913889227530384110273854835652984875124479654564426", + "972701618882359087904730410601284278774606904712450620047337282867879742842773982355171323542774542613449429731704", + "20672084413973960538653665924246155736365179656238291659345209819533459263615955701577227376156676933263460213191", + "929942362505494741311631248501071709717869975624842524731643023193592419496364118879401898240343935632746764482982", + "1084422340649216812405853080528763213192501881347480727953497259733377582850852477220730033596480703222575347383750", + "1492288182053458245268072868342497069129616704416880396636128640549721784884199947731756205334695447081293207972847", + "1108835168655645784038471860195392372159456745925701310389637626368365088791632434601585154255398049245267848719726", + "1619920149321182765805713548057215159360065613946104355915735699156459653176304386028233782427911958236840553727102", + "684163797518720735843914083399400315945891855772056338143023592425421531119188136695093641148629737618795216551029", + "1693534954104330965330925169550173389423251329709901876089358741872058916610561599521543953365380789194465286343766", + "155523790423137460743096368170361559396925525536673477801048542019949591418685967060966632558432235390852507431002", + "2042579545143151998590958588085440513451320986347744759995140710311235817304438579829998435060400135476220985446206", + "2057114357792258858105014954147804756336801459913187940516084805945205308695788827467838257878635274871351285202993", + "844055827368781389862213895499232569445193531736860181312881129424682538701704306392897425945644878821872728946144", + "96452877129990100273870907736115588361805788501651409620528068307121041331149088160580735374586188751408146739977", + "204876102287768501667574541251211732892992823957658620010219448157997015733471910450157107068681808688265407427807", + "1751389191632396450228694523189066247004165386567768731555055017148716211920778645136157245012139704499620248193270", + "2142949480051635330556941389888393908641818976943188486863598782114205182412725836864087196850822646988245102291618", + "1813712439211293292194709163492489592544204495758046082019074605817151627954783419281993933656261159434554671029593", + "1591912787330108303947657675370308927974595808351474187490848704061199269068373345472523880900326745669765113677504", + "1382373370372893467495260686108707656154547601219463637869227725797426833979634267025549413165072879734869616130356", + "566792378445875177455543885586648497704529875993151597596316645360520274550524938701306684702337507610488967763890", + "1101123753972484399004078869598263116765927644082959175865647397667009062318582637229403222968724420444033995598267", + "213162198061359003480717454582174975772863223792195264886832624230417746262507949562260282021685208306425949598288", + "2448865052199962967609285007521201543830595261990082034374386458898920856942872718131827484435967448015880373643743", + "1858127086722709304893069306040209022168964513198028101746884368601791337996676346062801564945291343878717095473843", + "1523501676936745892319572661490343800381106737716071319677109565505495299341918554434304362829964662075079318655476", + "35800495648226381980895223887826178567039864637770828865561807614067055893965151570196948838987458952778662330051", + "2069201963414217745698423239097303882426827592639711109618603775766850789983125443376583750795082390153943082067283", + "946360877431633762080551821558773676899079791528237998957391312924771154344531098521874621918801287316743188505189", + "1397266655784734998038019349647876216477722267608128367546529625700994604736038185438585777059666170504392057308135", + "2344363291702055979857977160768676340564323868965423198360680979993696554088168227791162435174703089594783018274604", + "1253671828901028063610580905210525850966771024422779698694875144289594788690567261693608043914374703123525975222240", + "1522039818302615156250311614205578464355050365330819157781471874676138160645010146569307932502162167313713383049904", + "858980304587180871887858737316570565797118280536788919869678773389595581870272429115443806710509942432481228749663", + "351370456086097725552386131707728216316930023643953054501495924450152345923017025355361457826347992940062281639249", + "1104796023647172664320759420135400003804236462745408301927011131609059731255910166569599609105857746259640637475228", + "783976632435892439089876791228876870755404408228918794861220587305813363543418155010215108907295112807431517588881", + "2340779151860753446873764301091576469709867494430548198063943616453339175153135732724568855554600692279055507456141", + "638990692083623527553045261212487990533745921864201870590359066051282190059900511012998278137377455531040884157421", + "1384993626397374227266241656531643151698492562288477881345199729607292606938881136228073464889906023719980430429100", + "39010464245521638026364713798105595097688950756549003992624816871564952728006574287113071918758760257741515527164", + "910525911657699156691938597092272733504409734770001347154454393479407394229174137801326625641060918254992216957680", + "523162370331461998470127410797569186602932210213875519406102486709076720541847936020004259859385436389052393152083", + "2135368061398805890838839460999330114439555454506655972640420912182655243221098251461940037293695455397425291964123", + "791472255670768438861422454093882013732098906278064843759152134015559663234690702386275654196732036020267544242777", + "2326727411931213442707857186339829559066428445446987680422105009531674883039038603485722664899719521903773454034451", + "2436589610985330480168699769170951296438760950237685365646861541126085037160891547357132578146689348535913304862969", + "758815420779361055880252583186706690393589977566566554276019550713077772962350799725769887151391536605313549658748", + "2319795366194108089784979960418657428775514606259753765958251161589072611925977597877460365569519682384261080185278", + "2256910692656264818141958252753175922969626015674556654401880172663578958668144971761152046505319988493099250568401", + "411973707939249563177537838344861269399281300092526346073382247247118829199892309188575299664367972546377565899257", + "214457326947078706782005993600112719104082761192836371392543417369409704098287660217173103273060701110039640306022", + "1159845307939117081691010517027241268850534611639545558385213213114869230325331405337648888045758272638580348547875", + "2243254785735019914880285827212758266197407098787068402228804692569557949682101466853707402823466230935672651522407", + "1280553908839247150397784441329400126065609836444300144574987283806776710862739710539377401421571849581039881395395", + "232740004006566346620737868185265605616727023184856391197555922868103645484870150549721694658965757894272200550100", + "2126258172802096398468802935403560482166377154232208678415078791528313535874033157912732748858514878434213625501801", + "1100461512932842813878852475284801961457433999116365277078598656277029323279858896746982300827835134482842702866826", + "1940600477750519850070299657408549729570766158026918262505503550346820170719238652218474777343777470598239565964704", + "151720534551593228069762030186923960299446988241758751067060140968327653535898553678988333844280709593973432002452", + "781016282840306365725743765427180970135305277219619989925308164886216669353114997502765991906012741250784588567796", + "2388297253326511895517561066570287689176219578714844977340798114999194170528586174535540202751045354394863469991387", + "2061939259583908137632595697423624265854679367618008836561181834953876610951181583083194170090455781215743295825464", + "1550644043499134565862822487908455428709954882751473874481871889384651972103281847192347583344929507057519014775360", + "1269461840801775723163010892224972664083956643932962898670665082548136462727365030301445133659208716643181949281272", + "1678580437626505724627797979884031302406412854060843123583812149448948192758945844874583912909426477019054473344007", + "803521364214245019719580559195734521612687027077584590695962500962008646730299819903782784748114498368491838420116", + "2080461599488097034557217831333467556149115844567812001284487539401650430024982736842069104139800293863004505074184", + "2383862231466065736084393819803819189845221611418242443432391321503178838353618325564428209790186304234304904312378", + "1328181288284255777760836138371971019927606843891390777840702566489145059576457384698598379270181722233620189621954", + "880185014718497370146882982187594697997672462216568537066897070078965879011536750536772469497069275656720058889594", + "777559362860694541598410388002425571211982266891793950387744330815022786858454445635708614196229367939302336771492", + "101486763821142141113643064357186897077055075196836099069237250068002622416360929289559854598910171927621766203620", + "1116097234342419589663972997684059018223796731826054778828130357185584778376125108512949427503610570119199478220086", + "1011507143708474670367332028830225596613038523379018227059658534763631810974041125930559951379125108550449860725544", + "898683883223219483745003847408896071285138559197894560752886514336731613123230020901301581031687613156028919970620", + "1763233887501183944763935380899540061783729117902051718091353743392672313572609990864839034842070740189636894532401", + "877594348933463537759795158711535211085643257253095616440042550371525979387863056383720466868654073618081925750343", + "2411059719711554142236677331694886678066094458268594931605722609746394636333348970109896667700370364410963119206765", + "2231997296063909227730087308359802341012279362943693589083173052362460844321248265847996956529035800820174518498544", + "256094287486497954683020536154187969617418373378896442323975928415403865842358194362437343216739796539227712538803", + "1313954932437517902338528105695604264840272737861973416483161993788340393085774282421566973659746469285481521278882", + "2439582112418435650653407631039917863764915325701284946449958867828257318388012200357520534104297330871375828070415", + "2281529656656461877125347455547774275745623816559309508608609449538772042075097960129408275947620927617020148033578", + "910724404075110608363971365338187298105141418977142320933847509705833612503818582992268495192061761350524407582784", + "1931060761553757067864419935918802895947430504631277787052792379526518562736032079567200843997545824172743484440627", + "1686428979256567674346868781054166770068885733994481116029896476044735172552459111469668692950798798829713267693766", + "1921702681490827375029268585382470523533107759651163305725971938793045474436221475486159072701252363660048809683203", + "2440748821507159050380825563768635701233862915046648940132297309714982793259712326366231116099059207130284795473471", + "550513245825430275967456976531577342642769860942442558250804824399201109328237195818997740397676304558624021936034", + "394129783413614762591714314048761426216206572045173095145392100015690570694471534880836188628370568221951770282045", + "1093465027671745791869422839585889997672584631092660058223610333750652650901038565641206583620235914963344698866521", + "1240449471620059059504044206950444334974076470572061517816046973630878762133516745573690486855993496625537491269294", + "1666462634700996475177950950590253093652865548862234781814312153886393849588567632909085550083072902312547913517883", + "662860907730691022474630790742829004373389562556686558696934546970545052163452479265779619783414963167399363092774", + "2259366518250431759169194664773699388289521108502689956629362852282697578504608285767000128007808070904997471752113", + "1313199201134960691257844275369216043225510727212944898006097232244397005614210346784291187301058840679200973581909", + "609051577358587407831322772851681187527448180200046238988229163428802097114566302972513889516623294950269295570759", + "29431383716807958348656369326127101675452778738206519905476111310541519063195210052225957336271138436304282101855", + "1851942298485407404368108385650569221100477032326705447733962232459498653135909560682237803870132641857636571600415", + "365521572610213705362452093974966134374823888005617096667634599378563223178773956687618522745976604992417963652597", + "625383855199097097226111236231677580153711162965160902212148012650883621496364999343910954539860163829399100437178", + "565819038319258862947707600088308239566814649206636686432653943630898341174519837460652203676611177970323566954665", + "1861214438254981738663887072612285936170594219156486405342376445129836253436601265230953184665932970614526679264829", + "476699180394322543839211537942548961504084590396395531438965151059141709757878505888312031231338191861908411731326", + "1453041017451277696590269700888090770858448004893069071120338612805023659028702133738293316746576710092142321358814", + "1121982277744541678536298540901300517933009617463876066985490729903311431057661527471156073880715854877199652469112", + "544814372162797467519317256974396264076100693566128871510184580302228600727610234787100157159013282758491922368216", + "271712201114290690080692339009173163630182114970058050568554984999350230759369533838199526880197004903212609140451", + "400819560052112042623856076043665648331592111620143338245766403708145009348992921435382387748516218857235874588071", + "2074755489142049876228617184549623596178344258655096643313819558664654655063739450993741121773877275754554946346534", + "1094473981777721362052999270312603588786181439827558394542521762709193859678185250476840878610190582687570614641960", + "641046164823331533469793704683415285354546507219623014133851291842581510789486758219781465768397301082971687390063", + "1437772238527959730507320095550970612871919597997413014343640989474778503887863600042194035042250846005610914014627", + "73338977329444822174583569434010210762903984739178329511302655351820148864314981005580683074879381409321991623422", + "1020053376744027877066069204860816807650786280976270100063595397647177868266425733986175299127922287448701842741136", + "1438878278822659185911344212005938893651168374879398508298697637288851992370437079423417075915219778350704459477720", + "149299542312983338543920304097085194596749374581688663384456990199011162888687060776041083463651449632331531486920", + "2458910489443722904956762770236980164561780418644954348231235860744300203764547656023977740694171429166959753372602", + "1538961188242542640563541842024068091612336715820004157828834813914104510836976711397468630144754926240814938163947", + "226413059965071030033246532245314916358862175772265762582448899075142313280556170595939640975339206180582991760908", + "2208519604414309560719353183289870933391648834418346690534160014784249456494837787299101223212397233967940129595581", + "2411974768596830962306247845399849525041983885870935771558113839218057489321214418316927746783349009215647250697201", + "1783077957089810315608093320848021797026121167685324534951373299133427606284181952005234205565247133156602111328308", + "518502110540039264428694389069558672068743401977970587581163782422656362726299814511372431517726488249099674906170", + "273310175686321618579954575977954385409767948270807917031227815481365965231679245654233418386297813018950561910744", + "1439189925407179787692590771740041234426118397491919454571165271345030617200070354160549946598271172493199816792971", + "1172353516176787854207992325127658575953183813459520168940239109815596472076404404988233592801272534807975932191688", + "330285854371009524182368799353433236292325885504230178723745942498739120307354476376970933305548333469237158962003", + "170332020083912371275685422443042978241799214742090879660097640759498310296279031094152372525327205752625178193000", + "413263617465982677828823749418035640143220267629834120425094479726335095285820833608625209987140546109321743906544", + "2038414109354057544158221081941726940369132907892902852662303028582286041723536320118502654171167538564404447661381", + "169267184498677799565946827166850062786208420878523124957385746941446460542706951891230840078038064695932723447343", + "709681101278233995086105758367761368879829908043756530505376225143460984211226013447868314230030897454956602462685", + "1948257532557044309551693217084997095981903080269354287660077789112885300572476497175642310541156344227617018809666", + "57832059694508418938808227546134726154742262407617489449543926789602437665977356621575956713008235624392717085074", + "733189593695119004170030106886466990335979754401498603583468424386144732358453249484138517006196696640168394127390", + "2119794870053976040632742868659497303353012541650759614510164806622592553491396697261100279753363202934121614197640", + "1829816433104485326910892998744163289552522564700803298080663127949011656893801900533788454586492496289514023356480", + "767634564488059511277048049782977101679985675611732933306953839987816015906220597813018216820760662372253270486774", + "861382505194110276887771324376603250787803357650180261801131511161706204552991705340276531547128227521576322276585", + "2365582714427066793763201375917328514331388316933536064337851187971242244289393685639716866864388965403797029902007", + "2270731934874816510919125282861851089995686749518676022167641881315235094027493702519889830098540708044871142424355", + "2055613816975728207133642727644287303838497408462242304207375624693627519561343160850955065346597619450161957231873", + "2160084458726114263662430910581240775385272491710262735807495481014471197537126947243644935295618818605606779945180", + "783996704384979502224473842161161648861739839371072026592045839657035716846709325538228755225797131737704753913429", + "2072016214899815608942820393680386763004729762439401667378395201692565582787888418487029723589372279225511598014482", + "843231393665325496944140726798567397724434660644928515140601312190101140036614987219729658779619005199167062663842", + "1229203438748715651930019975376167604563593071077371514929575472581997453653549283324431899112141813093774578658586", + "52369338025525286189175058279467260242591493133669867007338940036665608655555422569573060882658566636386854732503", + "1556002981273682319473582153242732700481343570587445903674376511647859548976097221007683600033321098175648018668122", + "443326624184639573132772607725892959459274980535489394741174712736700271740378337412680614385840200898079481573656", + "846544909566422444564149358145868632918556669082351268493257246703128793172723440146073448847572546379022955487138", + "678949182872475801438347614394522105245212984724603056163616193882008210429298053349374935857413189825580147164280", + "1984962359471832996894186327257754764055190662499523646167452865039806761975877625991656128782241456310754661143198", + "1434871496203895080949673944412985022039025044207351538378658604587552262523468984227395723039126698397978935250318", + "964291484452041997871653183582695624018835464811995282806496293287134683480856463101871282211153099247001209021958", + "2273831178885801296997614516361963892657712395242914957517148696223009157158942083230371471591161600544258162664525", + "1485528743775021135808408233649693528842369036644017728707595055720327469024676992985928970338887887633534969800957", + "224522811541540801847577190815193300282649737110202398851675676806429405372430681669482158756004093327121020137796", + "696784111127363613386969633181363611474882911392024109478446492067922437911034326593015972927786586191275400796910", + "2005347791550288730178449188947900487615411349823446212652968316679437657516250302478518761241784729906754178037562", + "67676054605708671121081269066016868048621747266767866063962903907603998154419028469482741793276223274439287713247", + "85749288899745283479059000169371001258664018829480179267261599807100869390638011981707875609564610738911617241333", + "574167644867666886132534790367111239127365513515593860835432158200413639483133349570910402921952088296846287636216", + "181026536632644435117147077075094879712250685779674116558112960256357595571147424401363341452005845653939834487844", + "942137008769564862670545406119826202763447923262702726772138359306324549198721548568786134431151386854423021521466", + "1745165421168373835270995773405695262673943367872292994079929468912504928860346466529542706645761589010186140457728", + "1587610206194185379060664177821086698335760705572805162916203056761657701702985876477206254715382902677648089959673", + "1240155566515148065458994206371909654489115440335333821085653034103024696020783466723605671221582787821980331765454", + "1953587972118689382373532968171559125888745177385781538129581971151971211101782764760294612347941550888632409337801", + "1642109598145112632130103903558232532353608044689484015701763226887559106638040737838465059602555480382877788174247", + "1256936566773976580752174156683392859347148514714632145975327515031736546624277390316987447499425773274038704349725", + "1134380783150029412556887765477178820754939995112909314641909197681466232043399033215031444275400729977068098856454", + "269122936961694423296052304942114544652001047894100827274002120832832746822262862613639206456067630773524522458499", + "2401720554303226454939024151781273352596758885586976840933461220202191312520053091367843821942382651346139858154290", + "1285587140000600320593489863291723004957669976658132388697656893365610941851863595407603733117128792764263096042043", + "972498343600884098952992087973124900175164735815744053617576231787559777667380926145588667054328270691097441090777", + "1577107565509449455196548753073618573588073592873433556775967710705154088336038234990746977576766920765156953946893", + "1434590707863606866372998180511810340799262199071865219445071920991615507878913836941352465825553191592224412469935", + "771912490210954451171488162306717157766920097974467736129525456596122747716000448354469045872754044316637217397962", + "1215630386688507274297290578884320008451360766379759132763897802284223675955383510167366211095202014800215188479935", + "657984995181916153182305889194661573742215294286985318727097916389064100468153992142961077545101638296112259129428", + "1446663787586815591679897122044634543253767805835814233847307996315784634059629009444185161854340293080348632203168", + "1544919755906959778276442515628209424895359243390057512046259104149407174397997053744799503059954135787298826856903", + "118921609291482318342175270349125967463205953235281821838675712222558390370620670488272290276205108290302899306593", + "868862375916904056570372084699416946335270117631245543054312044241176875281888709793259233303944600834629411062989", + "2132409856634225233455810923227390096070297954823477956924485177945688753956789558760429518937878910129571300980887", + "813588420996945909542943520012556166710314847296922531714154333277152749321296122672014771332596539092733094930544", + "750589876417861689320005834949090350598785023780461583509655649014180223045902667841793037238601317137642238074297", + "720526411228425883470172923220615299865994697894936445914675412961495175017532395191321700255761556924448556511604", + "1788409943227416320741677597606796151949151195006656869825293764140623627738405271666516980750982072409181267909408", + "844749377611620000414453972478432160425385576962654047482916831304594285600182702868386590068887654565685436417766", + "1796728341551602884205296024425090263511400987632924050962956772512606844120917497939588310088236469478496830051065", + "887007773648821050380852756584416205477891310433525638370981333667621310136173675114668869629727937198323505020685", + "2214836953044065231413744697899294807221949190685863142252217440783896145485972232901813860555242822141106658810904", + "1788233201365297074484051304631345732319486181016136462928926117910620289587749132736752143020488423186551695429089", + "2396662207557491102549395865744375938722100606024529860879351189776769404306654944569725266707116481413070459716102", + "1285457869546944042025637786743146003000915599321722353659773955229314090092742418686949383816155092746008675302780", + "1249142973227688133527782343363304976840797063823677127952194483761712436663831603322912312744323789169508544402907", + "980914967436444745395534305045672728217500247422127860584737195180929167205684260006232215476571577520673486592774", + "1654346057237018333576303740976267933029844177852920982802002812407874920631978594957759137926945107185281224137232", + "670355654074247780541778452547341672253708687607728137923024104638715453057154192693286944471479379558365862812486", + "2148529781336613196124578010379413727314976715833455205594683620507227584394105909012785429065053076384027103084902", + "1571747078526053495805982359703666920211757986876799467024615291600960598744859037815300107274752684447536030674894", + "1803607497215220110075007171991908959129362811144563231259779786871026289834039559810324297660719322094632872269948", + "1918721830659902090749082003118118204045265063970129609276941294712486989466791558869997266228239062849141421735515", + "712508727386965451147659687948217568121628783703070727297252715822009406402490822947429842578336613301840158231509", + "2413806052930550728567088898867517467471345326451389677092022159370768424655500724382754479795070633315256756761549", + "522923670515851835624871183896738579036135090491021603788166096867547575339930424346758586928289987514029908976097", + "2262746498132539482914353030525523143436606591011683434059125228728937976361858745081094139036838384881695654229504", + "50432506163415158237660367072778445318326430993784354726794031488117453079572064146865048901257635317191880355125", + "353998030467887459325545794182106128954532003067721919555029668434552325556411257037783351541671310462738378302589", + "762858396748962099937465913064628514113360493249454487446133424042782803960602977632862325265358502569490673018239", + "182368044466983020381551175101107214588554562696378844471901288885393471351966974019651930098606197756484296883066", + "740148385223713204858598473558311738336228099331017444757817738862489150372725095844069482952423643683785811064564", + "966330783585663711146129923828672818171501317350552679333893537230719331761210653754162783579232134545862206522174", + "1811198316686741709375171855013173792516704864594544903725359592378645986722585936562187348888861489872657784636188", + "521316125541910150788706770845107247373983342085095056903770360139546553639757292279106256320918264454733655198048", + "998715798177557737692216669149627934239973459393967483391111750541792871408816736361720980285245030988977669220818", + "1142208108941960804117457925250662035255492434524464311262739680444810183004980339963981410342479975345006961603849", + "543467012540458945411847519936699440545816492767705413586229974605360462403074528365977164950310976064870814615849", + "2437538607226810630833309561003305707757945873893636034158297620144838194273082388826082311442207463983016268729388", + "1495002582714509000905901086218907828223121114064908112311147216692907155720517955941095804032607359472885574673082", + "1266642126557892065577304476092789778170198415924511304301129210236409860450918040869198239984055487899413005462244", + "557892952206383388547012111841424055913845163304534664564783153678267469021055344257483159382712889591878961028418", + "2365065803374286038164619748725715116704411444607703834768676607424676643161212443304179542825081769437472224103286", + "423530240081823204632308718741498665610346909534174390233604808970212171741447820061160722828256343200810557846335", + "1234618628619053599587097746845001760036670340692040096260661546480316550019584422158146183247089750823495256893881", + "2268448781885373370867802209757378812984103930706535854424126289282609299191374908916885122829020782893929799077308", + "1193345515899378136740487399828792889946260327541368723913644825871010343149849607205659388849943697013945825465723", + "701458754318827911829181237924205109431103241056646586998712150995120272406153177205567135342969676443556961583122", + "499865163519112124329310596952647131983942862633132048960990913650086925238092212547470545128507077081276130799010", + "719156159361399997587899312455395406525750367774726633010315264750667227545913683292662435735523725910115816267448", + "697267858871643658827733199774820667086695784878570146419192633458816358757423214514138439818073297632718424904471", + "1021208078003909463443779668587846662657410270829740886017591700605600087524507915386005046416846374696334910396718", + "2317919560873668284230275817534673508456918929015927563354850700579495349060480878564949272824161832307553391830058", + "839819056410791262443199949024012569882822296062240029375411174928193515401612657766214822521353557381683659244566", + "1526940419871370665246646802090075148522245874116901709710817226977470391544482395428563333444232566736301196268209", + "1575899641418041746358399291743373311960568093472548726136182212570667206935685436800652238753222262030379386764430", + "1640489847940999232103192113763632573804187902984352671764657271627249221339530251480750659606574264617984808001594", + "1128966641910712154518107290956073111794189989027665507925037022417130096797863064284942478148091985570470371800416", + "1772482334403724805874903433747524254553657923684477154011438113015392320098633937267791148852150379780394770980193", + "1781812828527269715957817839793749465179260741926531419921384189671129112409850887631178543666973456826997180903988", + "671677808915244481126808901003050542557137774470561414591375256546359776277829478196955134688780111789900816581499", + "217532755968312522588025976534566060038025341348458856254293444962938662675014031593768286279962916941926487957661", + "1417300844211097792594694116455113426715945667807847518079676501611631121224082702465580526216542908219697136105804", + "511480200546533558282088375073158138799922440949597511716831859527833100751572490094496824265786211529145943963266", + "1419189568940152446936908696543671621026782819775005661221099054590936072358529903393799211435466066450599330338377", + "1713217052131101678974864190829481833000060155809057821392774323996412419436515100038761925660758791119738127757399", + "65462093927972410544466513948273081778016729362503274867577930923714263454481210568191439372527674344380454560704", + "1117317349052263648800530043149928412679505126948259198447365031224070126831458005917290431129346404631112577057238", + "1105967636341720972095827663105397074911653523977733443535046583050544674581316600449108685228399760767092721775122", + "1926583341528763819329709833096788413294437273422336092212467238496889343603729103673718852427501847484259958914819", + "1583358016563782445632496416786667670392139682804497227783155667690891680918027092064189270764903916040793140730258", + "72632342457928389059124699680361914217879584321552268817519245203099976074259492934597391659302431471870949829007", + "2056223383514754957309121024742813814918480143546892641716354984634755907705525838962418560432062509231522540566187", + "1384451588518326999364027809351657685009683064130205731654028775795716267376215081766684248372673792480503116672616", + "1713696864474986121431840083646963758271809860639883760054762754586422769351728450574356986618445490158000796509766", + "810534440135519749715768195953903937199100232262548224171154052988846401647443989294789764658293020776924318134744", + "1723657437698286782429244568426189012590923071128773298442721058625199391845024260784175182126098924117122962690699", + "1577504110649715460871172083697112733264742340371945869157783345604936089781693552415242041821996744578945235076422", + "623116700544069259432826085344844518616222429345530584479465090898915389340388388457799407627775092834771076822180", + "842924530094029303153246634556806691033272691984932280851784730028213089579161970398357319884348196686683542277723", + "1689086233177356075891101971917756605030996195434293563772860072484610520624788741610651315184837173348573741408843", + "1490461455465748496750568313470517466561344188483907951247099769757064326025678226765743802602117014612182524535879", + "104459510719431953378597705254171949571033481604082204082322816847780251443030957488223588683783686225266318873284", + "1823088526487328695358817860339062416028207231003149760924786135031938815068125814142289584131698949633831474743528", + "1634554052531474313630062444277290778025598900974687886840635593871073518089043644657991128732050867832437580145288", + "1479210833512762757345735042364445489185636832793474386271174925009841369709345510339728919726321069928008882746500", + "952573867976357606128854639970964733161654612519405116268414781150766484043909247319085564873824802295834393958976", + "1672447897361579655553936939222429762928684480962036920883995495569506464258342924117009666316501422311571849710752", + "982509928437920236027869328430400795237781129299844449397729707357406758508788630635871558339066207722030588687420", + "965011903074202400195621942995465493720761747881853483287113779203687513907592783564289706201423377785003197386892", + "2012296585537709542913437362844121055776463559898470607572305199580679762180547479878683600197357309723318291856285", + "556706808182551599147908661008521278617582104120168371996092593287396195209272804365614231955209008764677145212294", + "2074156708853844664862727686750842400278880274679783435250200617510264320652030575292492061234753131376215257475956", + "2414166836665473019145765585346633775660602813203863158207331675097380287307838819721148846133972934363226891786882", + "1541028502105347162271191420244101850844431096896513559893391333025831759524822351001572059614744584105097422770355", + "1475019326404096698462780651273702826729708399424679785708710797223023934236410932923640639762474929465750855398370", + "553229590986885810864154601827815695558707840989206398214049264667363601855384848547897482342737570346684573070894", + "248548742807857195347745993692609507542929611140201904835418098957313563030854026374529903202410519659379655267090", + "897064166845323145105057853735486288194219388690723480806812173311224345038928110462927548880756365037987760975717", + "1812512766882623787984512903027936783895331000318547813166895290294137620069143155688170027143933521188619623309400", + "2023147403243633911638099437226361556149777164816020224829158471862030372637594798640704674170692489772458270471669", + "1944089216826930175896515749888782667049229194032562150305507124741819431114462073557449865326062186923680132461572", + "292977880540780137495718374835817119023084294623006834623234651975437021473478088852455459893194919435678738841969", + "494150362686590973824526907751641420710243603045346903695536626340636734706904705338619168552699224211246103482870", + "847711890307509447551191872251417747946154611412557120992572072242192628654981516117818179787439899415982606172554", + "2143261661403484502029622360132620164022571105640805669779664963030157694261601622528438373285506792600302521365165", + "315594537340528132064803031473193700818502061755461519991667470345630757062071041597833383718129538280146204942477", + "411487265614567639082463958958628920150047872073064175934582632598872057188359643761209681349028804607172600198538", + "108870342012019372224520723995124769683020271800118955336850803806043649281757596122819184819927874232656100696331", + "1718972355492333455280296199212545704182674254966376652000396149436696716000547634649386899057583739214585492458567", + "1788196976064669642833849959445325145709365918709718826978123719319629956333473839021437981011165004970899940704106", + "1576415091711522868556976647913816421906006710232069708618461361800482794972953149622990388901559502553533574597449", + "191648163044997688477308977771732759635443018772773488761899433451847666164205208866890174763294522757704354753615", + "1272652213054192227578337703084283994372242963094495234640719903921639194169110217152697699660930973973355957000225", + "251259976285480504909102151532277995932286312750712730460042441642927309663334791261547301497899033490929113056209", + "1519596266371229633020079711573645628721769025846946674911793759623540328325108651154289103775959165220035682083542", + "1678665583040525743795441525970919668769725416244719046709489833949963571318537994084870128659368846593920161720359", + "617125724396476199384826838358871045497660517134323971144889261030848000090166547509264492584338731905957244712105", + "1570956522162948301557587779166195790250610419807859258160217813520598860244723914635086676503790928950412999517610", + "511121594978844829871566972901110968612852247771781233358449899875418398865920215131050137312565182396628191243657", + "483899684582488854329220694794988188357517593768390212450346375326100715888552367172688284580208238167234107036649", + "163715165178989544166590844287623853385844765217998991889220313591971277651678878299281117337632024343933729491665", + "636694175276553612068135240842333039325173897236665189035985441583318554590347868513488773134500035511227779404147", + "104453133983500580597261427143005673691458209135351696505472026890547068853066384664258238618750860102902678148246", + "1022776745232923171562067159763467522242367333193386751748037687378372453607130558874415830699382856793269238056104", + "710831103224620569980480271464099012786108938835977913970449363513358554668435829165395566348289928532403744909264", + "1765491752363017901889208337697671604495367562893966493594568351111836340737985414442787918104180542124988433554779", + "1949649949794359904242619742424378736631469503335907547161738777539724937931262327156485782455589745242174327915717", + "825886513876720456860230427594166387817340735562602817346273139323197601056242518995693854786290304403712556002474", + "1205549091750307652934566637119669608133303237671281175099021030635140720815990849513202118722783990530784580342222", + "791157096030491873584141820902019059144377425635549163308528134593593432309029876335186615479660866295831133970892", + "1318110072567800409477593150764829426526693959786203595011462146782785736229230237156700011135442191185519840440455", + "2186557964695111239231877551464367415773988370606060737430005615911070346914780775947878390556782194574091994475121", + "1713797694271873828771581005341152007627749288559727057857300656033974900468924676987091294605704651816012242629815", + "324957631290195945519613420324677388861033517519613334911965936935238820713511227214627015777300272596814745605175", + "1479983719596072727744628896187507695517876500460851338916761627240702168028433580565263977224995939844056523161610", + "389123040020438264060425480399024512687335010344011298550576113487042711480910835522549373947188569806431630066976", + "1478082106370117124409621182869621020527648403453294082562696403524677050086669596204506073799534519113566060583052", + "1822859209426061131804749505152857896156138020275801533265635420814907317749009697601498310705486415014067032894316", + "1848290217126726127637231625598187014418918022106091280699207509329996222441274271912627211091695844754424077230710", + "729509739460601564244822682705762584042957343630798993281351917914198662133909107489715788191851229897167990649757", + "1231456464443005501986489006049104700317815163866950394566747437174551295414192561207442864366223738378036259799586", + "2295007586277860036980040011245074330242405891081014934203334115776904969284783331773711704149646939729401911399211", + "790996319158022663262991373854074643072785695244977122752307724822533204693416124240487464465456305940777266497234", + "1928225583084740252576520074794865303662651588170581810755925260017591466693650672369869849734159373033101150880447", + "772565000274852602488993652794513297183156037824287705478831347706242922807328960397399170697691683025265744177573", + "912058298074195179521344514717714863854614824695777644124772859807244358621041496799948031959415677103056107696018", + "2013499157494458148480590260806706749745643367477013725071056377970047363630510411924868700584193024084600047450209", + "1792861087469227473618099254097659899051802950189804225721389950856743285092309839120016799033173555692629681888080", + "1876290235503079845487956655487098923910271964227473084446522300329657304311423159907044815864999370689120601065886", + "970822019548386372423705148581257074731602778394631576054926706260732244580489056454197693176102854916330290606059", + "1043700110492138297309335133971330172142716113626804198015285097418901508636081522446520553166652178366362373671283", + "230507782633271251016927242132238007318322303525825693269196506714220886385997156355851800235697406226112712245127", + "313617644824242962844834414781965721485475867338410394186489095625717672493238809305642088233392219115985224316886", + "805949741404374312749329514244198477964520649532356124770256158771846914890434745777810392464057110057110333558146", + "1737958430608248034998004687305588753337760154840004425970774162389781239177305337453437494190088413836940419969322", + "892490924139945069681697653901500309980274612621057669474456227626596000049972681912561331758491463706342202029866", + "1568136830945352301274696125553309314523798035909670606162782535458879942409866415736864409813476474432524638654677", + "833019039195840012376714376399030804466774521021300010250828857882471092628182092350812444760235972199178631636756", + "1582651091258290523388620373669070720771793468341710240977236433328109619228548272090958483437432906177376881830651", + "2198476113249768078971749852252764798567996258881611263763912868822038794893309071510283260803795055892505691142778", + "2390732078051529825247713777162063392262874691311729964600996760699098717410871494502533009155371276315075473577434", + "2456655074477051502836239035092918823004156003218392926059365996812742214109909754378076827365712468387009750237684", + "109269672208331079592001283548203553578963166670514881317659022632645545663963827751754181907289041047432686196505", + "1857094021419238992302453976953911256504660734660175181819145185016674681747655087007075885397777982472000117690420", + "2087897364016527085385048980056655884873145825370768509819377486096713004302550047659449802228126041967473473539617", + "73221416446164069265867390274360746723926664031402334262412825085933673550057374272472216505396641138774464029352", + "356175788892213421033409124896650309963524361463840456619636891485656570827030396435559729632659849039824261607506", + "1239859240125046351519826589546254543563612242791198918393772410378855763168958622403313682890624638607389783864988", + "1764296400680532362911119309633261705534596754497319021871819267030938601680747130258035085299596648208113551791972", + "846364669297413147852782183836291479510745687479273909029004402065976147038150359660923003689567390692265182165178", + "1949357404128745083662189168375033362898783399014381471246121174132876368229996613250172547227962720108322521188029", + "85354701408306419505762620277856969507801903060561516401628037396994798106668236437829967637174711008504004874911", + "250050483732699494909532104426631728036855580024144510093094692767609673366003156088238271902830736163269600584508", + "1667664376061167486602244053976915689201651929052901889219522717914518705008212933193106446050194336551143074236301", + "1720459008757123955437824167506347329961059423072479836863077887899024753466161230697018468257944320076215007062446", + "1812145815424503367264204228275725264570589647224732643026994009143079895386923948500829735034682979608988854895450", + "1701705275796457503335703272764351489871034209112359256834747169103675012469862409221399696842140991987221780492323", + "877026642060021298461869224963673594700251673871502110347021451634129793708991018540362787485626633877064964929045", + "2159847151147189593400399394947506056352495595272166450559863577094864772042745720924940970228789037264938177604306", + "2116069098429753369617174354537698935441111352290235816686912094647487211469996946021358506059495918975096726163036", + "1699487946808866457607043691951242794818371485748499187797759260379035425230298205753395129197232359368823177192519", + "2352624216485200679806091557205636338664293152067945419982195502492470276545418634945142567611747303699788167686798", + "421248458466870446111303434116913420171458467314128181078591615619367127385454761226888985652637914028283431254801", + "594559567858425179557644372212631279443913185576495775281980001592977274324073651946991665668751993842114493732391", + "155674299993344988770799537715043002234558432209278256791795457442623025366167165468350034694591157451472913250798", + "2437073068943988180725441219995381424531331450791750532831430043929191149430930490285891740990621027512278751522521", + "187169259832738188347247797181102595020642768828071381072433156926933545931456222474242776363599789847292611510945", + "1305983678541085059742770905302402984344152936695570274299433903809221855900021919251708049818553261000853163124805", + "606360862071421718736558169960913206000590713668298737285543795048858409629245720835578126310453182908730323188638", + "491403273421553406305463449672864268498452439941712644662026249615208992619353835340005394275359527620406480097341", + "2303496163171090788585882706085860388659087562766978098146514970958416294564838094045648231073603476697779299324323", + "1808055337364799467842361228973185373927019433642714524859221551766793853685357704136618895907132166449945929829111", + "1511932136983381909365900349792511074461830296678807381240163682816095223193399486412459350113647595061299370213273", + "2064531852762825844097321256783650642075155659897868976119518407698151907705879837673808052081161692003902163856366", + "1900070332063219024837340141680712411893478242617953717487387703006649916241247373596125420987259375808965839194274", + "381783408591064925320118830118888882197143183315762004570668301513580309190751732933109210798005038668218522901114", + "194597083113804637882470580079125778375176570391928588495040518493117449219265539754694698872460470706178304008774", + "2443471663201288964676474947908913352575686582921317735927647731545576987349054461795271442138033764797728295905705", + "908750388216540865729253692091508564300126842641233026453533601826309571255260032361366795584884884314694446283248", + "313942695605040554581634331705945250298463439198880292724404727186337289681729723255153074648780378116198209272583", + "1954718818253025207354591022622495229671163981484733234231653483606460079918320758578348056839539120175613859674125", + "1612917580122053197025170663102565510819471214602662051686853673353513181359994326435672950109873375086630978476031", + "1427714082814377670694458179958011155271866486659281256647508081751720047019376775993624629880494111640953150798058", + "544196981032125460308843813041580433685969522643397064183456935870458363671330814499314372961783281810516909116443", + "1393755753293818649407290458508547695206230591394375784365763211827311774227493906759403964194296884835758904061344", + "743926140663503058244837007326198838635454974708443650287462625027289444066441087257110827287166987561978623995678", + "953650225600801925221508043704835966294452574725285516276385264188771825084559308362408455382339651161051513377178", + "2222390134431428809309759086321406268036229919990141534862586085272926321334360385525336164514599678996801561632407", + "2423024272534840344131964487852483856447462544167340022989108928725982902451657781446028301893116103331245076420469", + "1483826891047241507267559939846204962570797089287705466522679287170189944082385366582508747509905985337245213430645", + "813504116166701491427912001884314754029215483390096066694523515389506657529997490378842061555979946812311807664208", + "218712385841410913291407669001059513172683561824895693834270121451486232877130744168349866221286090006951580836869", + "952898182900036214500471763739385537649586962951874597128371965583478726653475597151284911015980228205149857664945", + "205979655790610517531482817833490329902619895734652434052597615377612979729209747874337615583791232041231290975146", + "1604639541040146399327851490986967750821651835978809085513920410440915530145671484674341649451609704873401230515450", + "2341229056214725794073642132617300700577423437815718584680962543874000489777579418659668059432387619609739770152557", + "1474098541429981467922271811954041286179412086656797872259788010186595533520934552749201029122052569276508822826429", + "949259043013481697451869265416270304662153397049034354748653144368745306234632283504746517270682315305182882153065", + "573377174674605408516396069721420418346096107262906342699069999164382559481473850353987824633809454557433662230850", + "2052938007932841028516280637088058586549959617988578008240445057527260788654658096943286666262938700743827721638764", + "131965689228306545572656782808579587606962452529692527374468619747290794574140623295897052435251336228961381415239", + "312451745515031994962902251213157775020590717507188695022139538788921601041677345299694141105054064820111091101063", + "667851046666380429860013655086832522654140374705469158022672194603248961513751916781306443867687402693253106978082", + "86242989607533420845732627254200208688153658496194202162756412618257961375319133138871427929003058629781058533020", + "1579303546771030192547630365509485699766070057664808341397796636050996542131447277299371063335595146564449022169012", + "1910742057235669383913056708259327425793648927230598288432284582258325068037782693481849695632965362146532472535946", + "659758593819438305794177825094858058948874250203207719565982489874164177692739874239160202654956191466768036297452", + "1993092717102857436600423104473501109074773752521280342043150960803795347523449484796083887147448013426725510369422", + "361939988342595866866433316588219182344617541287275943074845159804601819838897381044389021453766646969522487354933", + "317421055308037795816918223717498862907118684653855171866669108772592200622343141890494510863872306295883797879840", + "743888729178869651874372711014488799465581194674796698656047910198219655030516675213301741131785257514506029565529", + "753903080906353109438974865527252182719553003092508872273910478435054386953304361602049432177629072293265999922391", + "876182366554320809266017904570361940966390804721844108695216059893955732612849349302835779364527142090610760775599", + "989803961516065312503565456574881723944345927986233601601162401504859253783511098131665516005626662465167237263332", + "567293244578518631297337740720601379739979699939142123445662941059440666986804225914374800216413520354968059032367", + "1844128226618017726480568400690956658685118585363305647431849688678428015748996276893676393915087906665257048320719", + "1407476928072464119475056729727610753011168865097728974983766641160000519536257752893466430730455801920011658548045", + "1605754731778168508693631359254059855344573301505842250918981398984560613630206140144207414323004856332387782909053", + "385509383703200858396191430829914409384033214673166476204341576075285248010285548560755982818797241273424994270731", + "2455299516805080346402828199257522954318929561737476624670452853982837228126515690171697354711713370072896648407488", + "286621743116944291847581922124954205358796021236014853430370527690901798957994941893777618013862049266077608825021", + "1955470360070229070635458226563609706452473425685577367505208557616614403172510957138385855316911107528207299583284", + "478720866111863864217003568495502497551886571759591123700759935404903191926818023424261432413768854601061886988454", + "1440836280217584428611178784901615811737590412940214351621139171050607803939339383908316323310358480092948395710406", + "1854549062102071357094095839246941491488527384477078792135586219124068812098329371973925924843853623792901213411342", + "2081928627151215719808917264249109568997423848455695882135749506510707541799772755792222386012911999180308294699226", + "2279462890554225410604821795408267210206412907047491142120622210036235954500067784040274588638889641399053653419556", + "623326541740293512531407993829881517057941498875710396303280375956776179421494533730001369681339880124127527541830", + "177105416104816236199637493432080032772108414965540075886658217589877611358930128309594590020902861482976952778288", + "1771606754144912850410547707309432286663635792725701473615887261622497109633816137147755136354283439726929436300925", + "1857576418044936943912853874664041724252006172136337763999102197721975714466680964965979415022600160449369333597982", + "2401675506852833894315993430226063090756854539713811093207266228612722116327761583639975088868073830686985526777113", + "988629187394995254725649194643786881571905711571642379203075093059207817813479930350469724958526995528918554287064", + "1689672894716956438661938305717309574403393639284037714146325023060386711234732553291444654911041973376662482439388", + "1804869388046320857159275607281819490495852325160841260212982931026195003273409561744731438127935440964094337736660", + "1846486566504708203424543860101940547264335658447278423345406873795830207629662442492454010278866122786402898265030", + "995929319474162240087839610021816821936777149829818685840515573304410206725387355332623889684090489348431357053109", + "790300880159823099111402697000559683162503135063044725793955627745274062615762379061124236003121840134520040019796", + "1475868325123536963820889824147992621110185106596285600358211533860299015960857031965313439597170842274703814957553", + "2214310936741762991659885702627379216249085336950608171049788002654513245303075291094499272970665972721021001713027", + "1832672539883106612708800915275587306576107396990526161977312331169514849195041013911417172287469398961177661552643", + "1370451304070705079795209104010896744877411993388891848529560972721441056585488891475342805172766142022811917498283", + "1024692997084185897047767820720390528851059707889398927192350780197896593765838083888551190266723359080225897522459", + "2075269776768922115079338074432895547946457904115428365004621860257956936021820369228565371487937576010125744174370", + "2235611475486384249212261205006572734992864915498107097202393200602318753932195745802847146359131311867286235769113", + "1648606530350536363607286643664028336926872477401656849843991909085113965679440431910728452640579222062480749994900", + "745816389050193911908139015938490097270905260458597202142734787743856137939811834323776654381684899485828881594367", + "737866043297585350620926747173666179372639550409813260173669575614625339354089595743188593909401612391613553421786", + "2401075927771436705489841586272461310579723502777183658847764631748631013104237823533187679472375528527611122152225", + "473526969837840606067513434463578318283321192116979900145195526628949367664480212814270096084238830366594991652933", + "1424744775416233819641875874995315797863274571224341522281605408696435796638567982235744167392526977308796306878897", + "1406858356965022710650925556314018437179884585426577210222339014915143068608558563251188602361170736298585266523510", + "1012621985460388125969451407555552312756998915404746020876596777774725138759779264446880101759483766685606716733695", + "383773211338232050722284508537412471392517503346826019299439163542303487177802875339780170044233366291270388331052", + "932420264901439346571460974069331862231981352683865422088945462881676117621512837089989112057821624524653857391275", + "1525479269065278888653404937228412507844582561455462174122031448454036655514802870997946303597441455521771247133753", + "1329751345494373913374700035562982772218328182506362180444877255963560725655133718816724416395325928511625844031149", + "730793739423982063037744640789486180599056618161222816375706244851706033194543184420287377371072767116695073502123", + "2071211231879266408947423162808857798085979809847422257228703695942917913541417190796823445657490865867000070774082", + "1514468909025164694410444531164385392878349399095729288575042388920815582150951670245013869744384823474913303863331", + "250103479186519529902859957461602241367864736107329066923566228154440920315055092917232486988716700057935616632666", + "593260921843038713604411113454900286689674076574420155718990214920690981573919332460441033243783653366408227194914", + "1002120539712130183700880585309784617926046652343363658760101479576055287840484965800311006026622215391817343388128", + "189000399754787750966391537172075986057574175713755315840051542016996894378834529992211342796320805278830534128066", + "1252566450205471658661526624616231353333175728213735587951655111727921952484266394345192856365784324562037018974853", + "2295454188891625490841460032066130291317963327765825396225812312937708289201585876848013145850761062556839173183922", + "1894079686441429426389739439491471136092175181702476089883237631111655933528924724234473660451444759060818964635000", + "1494819374670551815715070069375109748871801508372899742703197884259135130976151246082870288711718119163649196942273", + "169155691436610941589059810996546011336662541890788718409648535476275394894208339667468491558454541077376914087421", + "1457608022361498897463655937950591070519260567764403291068623436429276093969910771154012875685606968802225056635584", + "128680154519660676689299265333944961992398725049301908587084971887125874292431051303018144467161736959041371407976", + "640440499337485965554779188217714441504094840380965060683208192425853593632013509019856604046395473225380436546943", + "1380331876281998140060588795240658368375136391083998632086619280036552053055249523527373165588347577596529531524284", + "1992965133712792259364825542643417907452235839306056400765729702854674673706885560411089188026493388475067083448801", + "940007957016255668516907519073016221939959511788832291112300632218262955705140189608153732101453975789648290485174", + "549278026467760062996993949063038208871530786384105865972882545100620956797360542496196580518642510911436861252268", + "333051392250055556312504448901242183560701342082835670411660886307507688877904858869001602969122218549809035935211", + "1660215407912999302209626376126653283948254795826205223641714315828138044946005190892753044645669171339863013605324", + "1433999428441458273406621087791939185313440625096688800146595594535477237353889824464136548405926891846495410926579", + "1558756940694863968936254033313954409067221196638765716867448064304029682719937935706120093721179417179592490840653", + "834476778987139024115254709477826056024495611582878713148444286832523158072280342060956477936853819181953404619335", + "1845010677403799752297301220284812888814132597244576168519840071250898956285626685381680240975073810963312580666369", + "167195766083932237988391971547747033235425128142506446346504377682528158024410827854925626996763935048952669194685", + "1903957683695911612236542289134261336104738577928918715010921999351208963050280009705267429933513099389326094094598", + "378035994802834132676687821589600826061678181349555165102788369237321844919602721805465345320804841675416797902512", + "1070176044201789637083370424551595052714105570385662019304907835703417166123844825070272982654414532326065585813360", + "1265113945827246437898602272803399624893558269393611220450967764203058550119466817317170043416557480653042472424297", + "108356878927624042121138147657899957454748893462821034090106558909982243576297151332991864643632656503675729499407", + "973229907285376151200066181139313711725226233037340004224290065662528115981057387281230348128748659427669618926939", + "1821838462338186812862398153805484028707940013669075624473642090429386348318098323556467566924079968552487857795481", + "407447450209191773949622871033575368360585114287417537663447930143044292825085784241564938422433950026778853061897", + "1481381085069279480301771943422997447519549735872181601985060355561204277945274280593926611416543400036128931091051", + "1096759536909332866131336524294733510834267036361513959628499250204996387244521847715688824021910214517178849248473", + "1039551296920971030197865621474608891119245023135688205920276236774567798971822551882172231090645379529783733148891", + "2248761274327865778344732153991262888333690597834346546176335284988140645142107543950842196877435549735628105627590", + "517820448230766968412453567976702251276444910655520675609231398089073153570469483025921991513157828575825481186541", + "1979600444411234870345513530026809714594114869751202749059311545028835503782272805620043146279665386993371357086868", + "839254133943106690307739767129728566251357337106231408161769496541692671671110340147012615275517767974849379407156", + "1427428890030329881665475991818296333696393455020210517887283459816846576144880184420297329426223951780855488389311", + "1675565494331099822909906498181432373201934320975588182682593762277524055099757962011752165685788069552872854282927", + "1279082180138756795308283470234428560932083922849165137177885088057717407880155206377865552577932795495726757646195", + "1265213654306937344166594644901698520025051687317983986569158701708612719058436921786103633507683197661173820360729", + "682863903175831309945028292787998898105743462117614383221633854754256079658985976703124853188991557331053776471920", + "2282876135475756022256584625372982510063097600734312800093697770626471887893737439764313729864438221862335238079329", + "2375994584952123238647846711297382558474035389579706433734178666966832662549628694539811976125790102406668843624427", + "493117776084830841621916389379968110370921982489719048034044029843267537270398039899623108640580669640878366366238", + "1713643282337164755901505409368350260969900598555183240382670225340182022584747083934628769118045488867737670779025", + "2451545381460937568251155402628720957592652088017571647734720906595080711723508260278698977401675899634655473628719", + "554365660158795474545802648213543440956349413191515759677248837562457065998361606834383348210868099981653306206190", + "91933943413734241893229800796023571891414093238126467979199999924431653973733881754600083482577957043859557598629", + "1845361111223564361080815970295628609871204782305753772334657658388703425486476707045766966842638159622980794743040", + "2155761040127484172976932713839136440868588348878985744795407538742636630894152355787941168286992928563832424328734", + "1693101754044333218237973192719705805944607512555178479323564574483815078400861846378717869597981287396634145579591", + "165810956056529036982001016256974232612534186218265827410699835222264310882398559689383559870132293224519150177735", + "771892052818735851818997827871307935772651340919268194036026581270688399538665799142289820309877717029359431464564", + "94496741561331057728131056836181757472072767182504727040636603079786991759050025960715405250052005776211669221898", + "1651129897384600697198947952391206679587638614190570931959803385616870917101778461417270282745014001092921118019633", + "1997752781818888227188644377610211654018679806917750716685225725347940540166051956595568217741778752830291450254593", + "2125361273693635592602887279387645750052462987397230376119327169905915214736833980815437129970501631789046077765075", + "1620701195945015720926050026661634654429749314794541512185969799508079451983314769722523564768063646801967461288351", + "65661457845534366751870447698291217024837303993275479768527179063204510889130152101405768033126645665277873511390", + "418246695508098668197622415719413777704658530359840715834110131476876938081733708477355070418738040217752520230829", + "2266747630578337260692265893746329470687060344793670355661962236461240914042799748533968177134053257312650133281718", + "1111433104611871268883224451931800641096917315385165253362093635368291038264241464485385971358874841209107065782168", + "2355846810277045646787384877494934486170213322651391000306879992386818830373460510252529733872100490960400412547213", + "1837576357143086974690103471676008177405983637518417150012856807858877408151474251979150341015074073683009853028022", + "1471198762860306587876239769543785465716378609280544863361426785679637702036071432893323437806215532068189682946563", + "1339478405286023631488551180550241195578813033162814091133358382439422196573023960802941954097691783930959824349548", + "1426257964239956432467895161060093798769692172695201171794405901165941121500111754433753464283608153865264384551046", + "1191785281180582176253832546873144821442724554819410444144762698765984227963879102373771500398787237597733406077814", + "952833896434624687963055148670233146340577904449365403071025119777522373185018251030290869695002300482629762694208", + "178352284632075701181337423075009646229550513344118380421466116912775517247131078998718743855463540415414175720276", + "1576277979611523357233820711002475650407279782880266753029027029537362890579108089996449813137472886817840023449959", + "2277667477050352068367139378455081177257902439896958925891469502047975540344163615762130631242859744427784351471595", + "1973526722823241510234687363613905789719366674418910840354574317913240056585585522934277918692677717861982908676967", + "2312284108758076078141304118849176793965948406110058778048915764461676240090361286228239949337936902404961243628954", + "992317079638603217695576827525741196651141692498865914715374585714272248509336137672094734787249944404958142398710", + "1172347283463150166565389196712355171127599279136909342800175904003128173797100275937911757716722527234390756345440", + "484747533927274802627716140298638443172453104390242553257221621463737670063380039917526484001224218548774860028612", + "775821097639535118518873362194951703586239510207712713986198828991430702972571332739556418469635597199563921318220", + "1713966063914229724695233746699239958492591242382414899730563694184874445720632945603978909034727847757499782372401", + "522654053643054591883519629937669186059925530626490813935190206690946106898817835903395042131561090331697314955121", + "2381117768136063235336344541659904893145083233306354580245692518805519623890106014931550394116314389961768059868903", + "393670864237451206408633313844203747678536628585277685149553148101128607402728882534692929891732238737089673059084", + "2166619543238085588472780159158572481161450486631043390018175642205002602289164543430083427590183369531133229085713", + "86962970618869633061139666610468727965324638975751229385593683163273728848187736998224403183808996943360001559943", + "2271758307366026576664439741884722389276360225377482883061363588617770454913760511777443367547247844001546944935797", + "1965671613474570794836192379644957988186517753392226824807177316297874022994177932629796242284243874798984905146002", + "557998752886928190896066591044607951549570197626281180697658526809702707208330512082543865254025240636602842486348", + "771081189033324520842049900846927723223165097362339780811192823466275836918906869703796437421408690438693397585566", + "589622965689278327151642650851838958742608360633258611510956104492708721458981069642368481019082329146435901572841", + "339523550025905842963153835030360851778497826719002589667906521531167297473166818269270170162630509306919836735639", + "86358575023711200182039847081777592798671968634300809677616511527752344803852453742389507601640572431488341166454", + "873166895727684371018360789991912964808241967436448052280966429601688861544478046825032742472922980946041890556920", + "1272967923608612163226632890351064377217334511837472647076794219234767351613588285833376791223436756043747427423176", + "1345615315032874997470710829675662020235297223556854605353778907617219071339724935925239681885959652447885160181139", + "939156005297993513729623674901042296776830805174503483463888112684694976091538269892993487545269090990252568439632", + "967222335831690786946253204866336323285080210188699389257771354564118647177168914610311652580832221117742435564977", + "1869647032771280502043476631717806151181533170707706474580781109749612295954096292510361822630272873056076500857738", + "1189202809022645279750751045586627391479757923147095174167993592993582137016701476549627381830096030685817910501597", + "1330793215382791952708553531801475394870906431571164539254312831289040742429117989951076651716880001047913759205119", + "367723388060240504649302154625819492172594767493790010341585122476734544073753407681451578404874589154673511338727", + "1711701076828600627461535531841350600326245952495942166213093189380106735862181719021925250409608693573711958870734", + "1580371532316923465471377631607076854638223088693303619312733621119465386422153145612408476992692270799001063351795", + "602411376720215697878981793955418803766926994310215734835888732648736195100857664266516287664537166435460772412496", + "196655376713914452836872006025656498976436690203381069134808502560725827907414096689511126316712079272268886203320", + "1269983437880555898754595430617152151610289527158309230418139958740377301165613795533410894895684504402144333193255", + "2292998461401712795895743617350866777671721468933778218846353060660947141102241382808521358819170231134749672479500", + "1797715537064344931566257983472389990950384547175022371535613192890252462805709298896088027157686017957186354794445", + "1059008646222741558700726390156875583497242891714714856906326582910773244302738700870988063219672734227139356574741", + "1152068494239873608599726698644286234930682301764648474914092235367529086338393345443605102031123928766110178290589", + "1310856988705615833324213408621596015047395899729904942822469493078965763913353997396007191169122737767104052447251", + "2188498798044747250097059972771081279475858646493457854294732035031655498445278004766347508004521099041606535366975", + "577060123999258575877110028647298249451250267646237398866059090211354859161437260005621824878557151960407205921446", + "1797143477298422034258984656372427307677394334525651654245452052315807740900439608193577849100222499594141393884464", + "619194473339515364769095606129243069364393007199578052284765920548624278777186087817364984179641335114984540653221", + "83270353762903983045808236382872881833999660604287882762597615729084954599094829105327756929967696952265265946342", + "951718226253490689206408747494414526938851097031485054565607757842950437184319634100087167661801195347687187201294", + "862637195788940320407185958082081170740465946678782182606004567688515399297786837707659980128149973270677931301503", + "2148250010359989557089796251062947451216869341400573903144290280033181973955223721092489943870197174345675540753212", + "518838968855762160105511934209010116427263657754016440360829171646155443908188133831831461043022890202235985883158", + "2093536976205898297049330797558529105777881415013191121962420209776720113477038791982824414919992550989824738080644", + "1360506846834577928072358532689592779584877789340642514459844224430747462265866542150016154558598262450144641217864", + "2104650173245359303910161552994670483812673238425634548380349660562669322071382450731109833968877106819453692032206", + "412071841280073117948221883648946593021201005806126299908839448896619847295305522407173643984667333520108148878113", + "1858953570881717862009398572436215661578884221851516235094664166795008067189366074859102048918474389157756069779528", + "2238891016574760550724086705592536279625810298438248988587570041467301464556808541876487109745576738406575549017678", + "2147440961989933209724899382334915230047658749908756793694415413645857695083024453688802052584527633723764388177633", + "1572662840598407256774231074940899409975682490727839204051841815535755873552859748298903528934160277642614467460983", + "2011238959970777028544988056243028545166764711735723301509794833460216393158467356529219655936624703741095716860901", + "115023714188993404016248797461332313879860865069868744310036082796859781713682966263657753637274776390125244084039", + "485725679145879694078522363125596012551152114560826792484215430927623006732121139067342423725573356837603428264281", + "191851680845532056288377089494491977477283195284480693096168537148166985156935237920820695345173970792631063589315", + "2088512924893527288745655317802050594697878154457404815311635850148798040207997862820386769899365216362937096084673", + "630989609514400349796856887564466035242020537129845938177200367018774325540173590080810694278176691019054801778829", + "1007697273907764028966108976105988738761265557270675034882249773259568650683066321582341075856041659201297730025902", + "1766769873736696862969596525690054712975633378825111299991403525769101163611610917248738248635051743600057741693691", + "1361150100909866252744754361789206658998134823794792718605986510293457927762445091308005725557619562095442872936607", + "593214309445554423036869293990035841362317189694343655567490981876431612189951257211212833153034286188990106014743", + "1915533840795004680632864085162223064863449893170964399248518000436277586449920406919925846710092972509332306770895", + "1458726591411151297343497807760690399576416737166384686881587915935882235541587730508921500836953444916368888459331", + "712256484225913754396184957090616475360609284500580320515157542395235519253564107061487691713131127027052167748346", + "1575067299216214800544570238033299712531544408726766161045602880114060027445551621662761529024817221700506337919919", + "1052370363739353304391320042391912091240995804726463224925080250021403463273584527982703018784781459490627217988198", + "615491809851323192050493480029854029451411442247336348500143600136456883174841186198837337853864388064505184621487", + "2392278327371048922806187590557973523658177831475639039399453006195755902229313487223526150154260049292785730588245", + "1744806423335950921219208930652711224394344184174921625002270208258621282233312124801494487177832375169852060510707", + "1341179874063245045125392936946418579215003451774260995427652110500669935697365112390924485012274750750326661967760", + "2039009697042104164309950949201402337415550739017154058986153327974270344209417327196233462828024429858926718609879", + "2371634919588920932516173950294181337566750332091154576314640188063105074237417898024759301724768768477089939112819", + "1166041556144764783290451620846554975339634324116528432896160622256989203060822275992515249734053240709205636158063", + "633144565277043831722244381284790759110746931186270194079677561231051637547783917714654389907331449455271478860528", + "94030391260711213394853846782846977362865255760686147780135356415022777815316094457285609036645879923001381557577", + "32944143210256663298984106669963326919324628875236335633812018266842565683626115697854867482479177530004081068995", + "11479658036586910125038581618213719707042750095015364404187562885435336308847804686655222537132800608844628330925", + "576792817042666045893538991748888333618089997312699473887341957425979210027425774334281974479175081623395354641978", + "1192409393955298121365669965472877017870269123316089734811680525521300717325236926745375656113086996608841511961595", + "1685798030362262262882464915985062676301234252817414171404521632458845907100303699420591353647886244745260089075671", + "1905800470147793882663553386726162020249113747057742343933145881224937484147802759546061265525767474931159149137764", + "995856679712906626397678228854256984547865121142405916243512346640118869324809349890647344321301777521216850785409", + "2391968868194794484556637833998677639895996959631045886741880007627147407244904294096495103006506821018188999378709", + "1232939887983608775455069363911022846757362619783555719850903459234816857023539769304222136258730872864626317892779", + "849720348495430483506127187855837913943167043753158189256119417438055224945346325967032231341135614609487484071567", + "146990867885312735976174772804854364825337972160215430835864009406519669016696515379232276447020917798343318881780", + "1887302743598756997682560964800158549719122640392824340206472742409215587797557869931767667683992021562127718853691", + "85868041280888760176524583427325419301299983926073704589924810156328213560490923946099414400843725269817892402980", + "470400570901535924689358764353934056116466638093553271557239627942770042893607319642071288232075811154445694715559", + "1177860296917325819999289846848696807096283734889235561783633985431515081436215667978557369567653894771786042497258", + "1673698783941016898056434691527078419849004402190443291461114420091644582070703300068560359531196032585072564666681", + "1407251994565592673740287261326931941905609746283278456842146995944642328055760335075921644652857982486834543897979", + "1614942868406431409259484258079180518205674219660632433025904009276372440262318605963727585282477370383401068631333", + "1072693961755082797460889045615644239614123282770691234062737412455853020139505258637306573998136122365459219005327", + "1519635511679962787962946703697973861592266139400295212796255558074665096240189212727237825884994921968963988708639", + "2416118057873151419322658485936713497798096619684096393423856332743919308984335236463824189773603331854602812000664", + "1436757078713220425392388347912255104385110698791389958828248630288227298670565888177337834314594837734642424297323", + "361604577495853393735417007685323308039898391688660206287873588035692633351592441507789386287808603847072814400957", + "1671996172909437749053702976595637553429905764847733092158448131727871458823133608830563607317796198513284226590547", + "1211482279059307543829662841012726327447168075133222038155026198268305013516144852952076984628496885056896575943950", + "353955522135372165031798418109096005881485629921036487992487475327701145965630517305749713968952044580459018957385", + "1069311660732735872264662256219522406509054956873708259317757106371560076199316440854767688628988751159970245156759", + "964519572365873660428771138123362645930505922914377747776189792030377169529634617966034008809689839149146230850908", + "981333911737299083498578812271194652735954605625808115689787743907007345468629987639598402552732766710844780714456", + "924396205476402796843435309135307051882932735648482925288728410075575374596651850459826654541993562316686264700625", + "2314271642034398294351322826831744796958770989321662540003173575884518505302409909121064962270874109146730069841697", + "2364042369546798831473954781362956947547298798332851647774377945854702652152310151873288777432613278834518204725633", + "1147057081469939304080182594780695282493998125978975154603470224521496412503881108064911123836875888673628812913296", + "773990109852578118422861721501678288811256239252932096199493493811999209326696442649224743275919197312282072977244", + "945372112212452193740293384580875634646603494830169040655961710929374657633840117721231548190693462939550966362267", + "1630141151395463128541433749371494972558996805474253440945755904807115063713277419785284087737917791355681133157621", + "956003428557934320836712530146272854795642221678838898754354586587868132190796795613466615108577819474326147251898", + "702318718040673535636013910883384629227551379526371359247377430449867411951163548273599866612852302889438519015740", + "897155277292709098053228146791532860058054296250468135125959843753887320504283418104360970344869671373921273061802", + "2457033157234587969470373963119947461250216740542892003542365213943547802129359466456455144738110844967789238491651", + "1328374849146788610675835804466381545357091747441623406725613564583029281384279527898902115622788823487483479836937", + "1023208852196606182613176465011744427711948800232666190711027137425382810615694465495022325067267192200203532143324", + "1490311297351804779739324283979527701849765799989187205158612844010745214934987306820370471731138570623857914535744", + "2254002370397793123538508599203455839978516429129678357394596532057375017717269636425568865765486194389942709498187", + "560209324765989248685633090337251080220769775773900096868181938658076908401684535353707959817415470869614436683133", + "1574410873175219625833974810533815727445596130799444945942901656237842348210516528455710889609796547295485537951790", + "2045007327588126174967874389276457951732055021008872749493904959401722842573137454977044665060190210027044668722328", + "908637947537115743207993868401246558849465151926263405054453307859773342988233302174260085869011208025937205580468", + "647696044027254108399092338358271800704885292098100971334622664445060311884226592356063929242363606706024824340401", + "1276057842071531768758613247226759086690392618010874942131912684976569999240403161758191289081458269750622731219001", + "2073454174640408785322218192993124350772967800868999657505971749523920899017713886215870487941340795209385699393689", + "2147112209598443985936733433381604841237487358129836698857889294426241340300121221694653497444084745986729873977279", + "1091252509512128327096765629913363067223034713000097725360754922238321822336485403959950056131064854197057040664246", + "2175678136896214986196759835458195651665866765577591666703399895223748699012319218857486209319085426253308448021305", + "1870224625620363403781600077510774575448926072273283665036804981354504144974770490343212802518042898648969800688172", + "1066931753292142982098197455914981912570569890394407560786010879990391593607385196979417704301375565628516637388366", + "1424283342368143462097113291150104389475857282455547283783857815349149299622587054504310143826464319491983431766309", + "396377505030177781943272526680252939818005466718575243139836146485360628457162515645449646243307331693713603305630", + "1747789287022605072493075344616560781265738810683488302973008762495617361569366432362202116142040854503530755268879", + "2158525746276214947091456414926509797387167776727132818056911748257503350408016192133189224581313279294353064871007", + "2347393288197482422436685561241821668211051174299947841114870568736336581429830954050008144722825526034216988947737", + "615154244671765718368543997829733192437247851899670023489425315257868746817802422124742627267857782082692438087989", + "819998163067338211502570962139569368571041712726221310759087732576379555016868917317568775732618438256834617442506", + "605615220653217306491443456083691496157606084382004368508901468761633515780519560441156225521516915262247484278897", + "1284653364651835247812204157640418505107164757566030529473647190513041599935395930916126748930081459317430838640908", + "690510364450001955608698520875092874589956904696914472174049468513589066318533299954960787197501237444496586671113", + "2214149150615148807700771523809092834018910805188261379488244222045994053765723294720086438465257776565085041797329", + "2033187715399863270741829034163103707045560604093792365538129046488181810996192571544062564832474680027662969474949", + "1226699915651450595815050419857548256869442831803204820012567361481193955568938101840148867827318777223630683725215", + "1293237936976628322425824190889570072692981142985398366989921551074764873330494374255732649831077889278145835478791", + "1203738768399645456428415882365888488562726117207143000684192261088739070772780095565548134533827834055727033396426", + "1748928850663936690538494879390318487031411809347002944044420118238202565911647661983076262939803698008029176920685", + "901358430451855448744466509025324869260596079179746759269074480622485519891532036650795206157304714770990530685194", + "1896525354379684115678002428693185359316162802571280518805684087832706282779296556322414892361248459887103647828965", + "2257628231674234537739500374178438619131265738351798707063108565122480323571169338916996478304624550056140323129831", + "840367460731606574229994237619514886394106064805862554307435456681848582370390633953864383546361548858525703329776", + "108133767124707273911084351873225845376927497092861841455544803036799038506765147838348498701325307800565916884720", + "1414265283483349230655251979939023142503981660018070145756613655931015296320748350269600379289452879143478075172025", + "409086558507575914097386359858432687727406865045759406966443658509356821075447267165572548442270645685957533279767", + "1415919604957440129112993790419801894302671293794284399567522363378809443020680598338057590991549312533432204282129", + "764092117847588985188328141177959499920107821847112674504111115107638245937133639053184758676304249246780922179405", + "1245115394407594869435192751083057876379909284007418981741115596856898037025773106195606340575064810004635538127423", + "1633691667903554238794669991241272213914196714815571208952291868081596385192487401279901838217772251526509659825532", + "833807604883190100423126611089097304523393461012773338745959089914008206752220227641759419283239397463192235631002", + "227041116772795790664954390611413539016276873905704646023770685389662499525515535685362274967056489187843622993414", + "47756955886919641057510649256346304744764168499051997977728115393171902801608703495872398902018419673223533240286", + "1108800923486866119694246187763916932226989065777499236028614158701046099571988154533708723296601848531793179294378", + "327196472299181769222602802602051101807240481440577437118889837222450104159977740341530032125609785034496403152492", + "2434831887033848969138084043894234282866461347460018214638076529513815844607804691832488980432738594881691775359033", + "2032910976831279349347667581975282631164030251336762181772810204501528618519352054172220658270855102389369903920733", + "2191645879473524644069479340827500226636007294019656752781326759815983693722879116577578848770174040069142353257872", + "1633650045948464641678230412910226036358337555628132123824108142215680942790629667410022745048248776645865165967315", + "1294604530226667664913577477001356318997525878018033770715139727640409672299240469130703894697747200293162795886059", + "1227708762606215617310201020243525073270217697768353772707866983490400557877098430517661407410033410045755719501712", + "2387573922456428197194222996041262098229184071577545451148138526093037171239927037231580786197494762618990154759209", + "1695622864488362999139037622534086079594230475875567712256884965591605723444211154206449090428254723079254428723571", + "2390940703242279700931821978332627582274476724548549056104370992090356660287831723045668239002448931305563923112101", + "754300932375550271671796741713713724536587931866611300885557965843158376283905964748590774561317783661499808329457", + "1691127263541457096970888442073714109911181667442497294593081814662679378153057161456546609427827866562764706357899", + "440373418007465522588923000700349786295916429860516614830229956597543325041559928482757508887770479207150416237860", + "1721510623785751307071917667810929590832669440587783845567449927420458419108926050762103586291700218450216950379308", + "1273454250658264994924940446660068648060354830110636621973575476228495530345128170556787473703703827651112551136475", + "1526675881834439857873193001802098138432539186712541222437287975726847230057632613105842232890387182181406897923673", + "1844690586055669044821943702637801336958437698080193714892902558593695057614261062666385279546680081720774596528986", + "980240801179011815496607306768723969395071187050561380242192851231839690887598592852079785936646175181207273041609", + "72122092261301981733153800385487299738224404287772545714888027008113062752424051501102004184028288702189338330972", + "1244863549588704502632377981685953452509055770679460875638162701367348306094269776873718714962737927244147410129454", + "2345519472967422305216510954792204029709911182768525750079083221393458502012456157968519148133267844184468569560990", + "441199455845736190349809267841941410052715144160803049774933450816627885632094089619506946673307965904401362609654", + "972225854731510223782217322640531460821985152144304991461074152686176551867735497102380512491128221350427571404713", + "2203747156890139676799658597158567884811096171037608460748502338681871907199011825843060977208875054367468334607382", + "978912045356613251794111887545002625819142186224777293323479552090185079356847369103417834758096729526471558194238", + "97986620619657430348494356389013151468436203597318466058589388997010910048073319482421521612038152476049572933159", + "1340917216662064692621488485670698685986095912490849223176700626699832395545412837572689736039598244613406239253166", + "238854976036322715989019602525352385643885353965739091955746899074444961196745365922984789215986078501776658177013", + "1617486694471246199450438225324054047681069620336861639198041708532867308659658467784344447572194807396800574781661", + "2089844792302483483654937086179752123868236888650062403348985892274370808146723370587400592010563401497982585931212", + "947375174683555662921531444240603294974518870073248326159288919405020656456503180031204432672464218329806762518326", + "2307352185889279244554355373242684955370154950420645622655641234443876663109217522308776006071963369645175728472074", + "1219312061537256837437858200771617900788919262989161318269344954372722021298473804629624468627573563898107032391462", + "290999032966972854668874615608962712166150680347980244752858964616263995785307169158625420396429024302850505942666", + "1830022001240071150863588693602897322040606236490253034424330025014536462778443831651831706171867263908908624290797", + "154255120077722031281648903596600916257882459216379813312610136693576859456172470036208738902150281891085778828285", + "381711286972779176498711996672730041425315291257698121073643765655417660639171555015646741435451293888309642784756", + "1315234961670259332385061988251017398626087535209472238675666319708750141692244234260651595268845075707849591569205", + "2021600539894760060701112142051774440803722924985037689384444128735231276050324393001855367177583450364757349476889", + "2273934447112642151117574064574823491730565821852531403278486166300560992732315771374545868293907760417293117939085", + "1629729915380024633766661710380884267946686267413097553976080564054295850622905615621282351759623268299472963110211", + "1503783431182050705788804148408541415286768860937472690010064389218431532417113230284214835020610426787513104752132", + "701194796825408993378499125013475920990241290599918851124649850715510456528471335334061967063631071805128430896693", + "1163087613739592540280092739051420865212300393973798798882434780134797163578412939244314192313949592575016487185282", + "2044463598697898751376120498235314655564746916387604110148065059423302782219669631761163114181642897733964999178202", + "260445213511978055412638034370132606098227853017952186266536856850876502877813922222909660529713063092961939496948", + "1756277915905959040601418693422043334593391931238628538762135394189117056395568025746495371556018494048242179940153", + "2355790062881195234700101950095062196837798841792503918521688180636060181982291267434128240398006834984083314736643", + "866450085202644967840487544945518953627695459567526907494650437341325236072786260335727584244060275872077541827717", + "946038317614008480480536204659976865047321127939893498845673529922111591658014958704239445438981102468700588330337", + "2401198158648863316078511433942878375607590208782204986577783447099806345495104882235829159340372456328893634675269", + "1167385117861520612188465848465181961494249597402250731389377660262676261279523046987462073769659240874915224736848", + "752347328312969844622779877140298556227659992077330062834416515827933588474441573415758346150708424758132071328623", + "993700465608940726479060587610135660556649975332645040507086295866584299437904691770821052946741069204413017805724", + "1551094923337471925760453363734693450385723461697996884369840374110128766805455760975151972963083206282130848832124", + "1372376583335390555763315070032189323590360149507528720746387358592162565661412466825168019076823376377930003095632", + "799587985836793134050369744767425710209063597607461329437893142106319542484155098675459766376590283527832097096865", + "2172893165975873053019148468512447915802802211541412143984375207903835982015443359506263049295187570075441265027808", + "2155727452878051073169337831267343102199367954008590441356584039053456199793916051751660922174701223139605992160572", + "1086773660184582010219201895567606648040279265110250440783840857619338536933203939451829417545285184596399507354628", + "1889855363374611549837416774554919829424979980482204959566749572445907991162792191098547448453606900910353246243891", + "2067961403315495155248922115620517625586763367361564669110091543483413041447331831300811233680978724710251401039754", + "2154224938654905710924243680355366361156846952115085759827872149620156347188435762731088404993514669747473399251962", + "1506643414870504872390881216599577255904702696239937301948967472672786265281616783252545956748254501568809651089160", + "342424297265705930424787208673598716204024240226244937265698095594852276255865092912492895494261722465284742279275", + "2001272444825784353703206193559431407333686343699098784917000441947228069063182716432145061227124634103922226733478", + "2169313118396225571565913842336970512021680046806353937509594320263876391072200837336074154075965160721382948383461", + "2091090789231057461506537728326583634634936287362723998479491112123053006967283648707694979427958511734321481421199", + "2021127036649649011904386476470131139887725020373825902362225498189503978734078375597591161385350047182509159457173", + "1664892786527134993917755184540257007789851778653134250818863708175303611162842624777134169870273310104635902103160", + "1025247325873956542816148494315016805101187693652861006759325022338598203742599711463376974447834630295369832453606", + "279692796119886645450031180438027553740092997527378057046625855566519145464510208238055481105209061574965949190977", + "1296538044690725953340321815166358767146321658638966665165360971877023795198668191186280515693261944274745138965035", + "1428586645246292816939400755130264010168693731059139276942489766612718693567862894244060888823161144133447702958615", + "2106625316269631805256706343091331742345657962893726907376591100027970315772182012483375591584490789595099763573724", + "846296296088678564591718785868046808197038894414640874987724760177051826630531950436371323083245579131291832787360", + "2205347350270992559919702337446576652732952599909750441893616451292730295820138956695527989926628764014425953804814", + "2165374070355342865825969841897807407993202437007603609174776901577816396533244060140238943112590679646024476144330", + "787837374189678245946509780046767279724803298383177392524129818069049017853880625499367002495957056272373310015231", + "1165542131404415807092402377665124129707356548312153408323278744238689673815962019692433338154991439195249052647572", + "369572102365795652319475688993043680247031296717764350435118268234301833103965634353695432201739651675227395543948", + "998487741478170700227959334141949676816697068129344606588698993188621104323486501275880934579735961085741678681532", + "1654672957263677496124133271433539199685357367397821399182998060168926440053772264699496789616597668855364020889743", + "747090952801134934503715640876851228419804414795479775042505792069343576979935078564756723695242093864031385624564", + "1659632281412805022905962734534342364955943353028610504197678528731945386639277515752867840582069508773533187253432", + "533264838046474384368344318422285806669834387354395162596815796114210760593163915892782317915492941576690380993724", + "540638045196401642627854818247207875953893920420719573752957716535715610905375180742185293134815169473070756383528", + "366400661612397308015967652110763630888216929515068037779314920971946852163386230827063584921448087743262826857923", + "732031776217950742387332513341234642587951922605382511224734923647717983168547877764298792646507916049840175685445", + "2146747825917347349095303286406522469471268305175048815244529472842525024932368824193960190859804047455081965613752", + "1195216904610419846229184835550040605240763427804931435381150951298755423003636373914266583946053666548962221582198", + "1770934497299863574163711535787095751638561958310210985931495637631535290867183943121339723739038645866566955767840", + "1597476432516351205562670496073355799284133923493525372889177422597252831051890788019858800879198318659823208166592", + "172697732981253084414547263943778384987622017054881698135226023736804898961928034187273992233020279217318831625507", + "2120355051267865477046911059035099071990488823392336343828689160606789381431133090555376084974368527451686266329851", + "778304503853674329129584231690037408832424357832126050748917783657518086600307070329004963049714094576862217474140", + "1865321830392012017657418872831620251580967393806036931004770729359285826874606550043807542157459361460751021171158", + "1100655831423393649648158810378447109045090218574506501636131881328904519069384445290138630159713107735562077480656", + "1229932254246054378493037509319446487175144548021452994895930936709538664375563469940639145820028326538975415093029", + "1246477193354447517874682544700342382038016837432027092212696173732275064460025476863824120279144692324544490277282", + "2433183898910040427027837478611413086686330271627835565657251836991226647956221392962748478395379598674306488168859", + "595437960893928345051357009275611246713157063998779974230073753984401740127022255285509606901721535216972502378678", + "491802772608720280158317765599340518612922654597879296673270247895171331154812011149162859327932807776122758776845", + "2059062872686351141191937183905005026507581248831148368288722534985651837487446508708833653987579335324679286633515", + "407628172887109244495093146239523892871271383459350726153724075205699563367323452705145532071085945625838133434416", + "446359956931366044029907935876035152801328755491402120857223924071894425058527762379854223802386090247370604587043", + "2192464262177279042012302514896620337682511879134685698811576528068407004919362900484583981360830811814824771554520", + "469511820156039660981528989380990079731889453880720470918737877769908547262441631717428041521843954158584971412491", + "31965297279534616960719923355507282498839877169501255168600527704876843007906399846045859250809408910687315163415", + "2163255338521296903712611781008347691465752809909387339988197144538089234376083784242027190567077108265683575063498", + "2154468212829677088571190929261804119514261169442796904561388120052981845651573869138341916596875113183421022830192", + "1462531317527469734898311629775944449845784729981953777590925686800440446072934947746778535521190358085357264855929", + "2375805535321308407553628829247658860294270351864248947694425215555602093190440680953372817719220874536661458858248", + "985788287974963711637621620290725102355299318530720197496054344845632390738576241212465139734602326048850543049445", + "1194642605188185498356370958150145539772466491762688575067745928261377603808479860068633693520338961822992093562689", + "1277672549616450790733408840206858284163437247741164173906915637488077098321581921046450850682490202350983353708147", + "2281988098247341662717087958457645854428994962081212871130895878240233622425320299575143099450940196350506658639611", + "1413998842593537051006013508069613345147176305930617595912633883414545550468874905080809750549812686763558164463272", + "1734260864074199854741562161254809473777777324763830751390783090619487498417394047216017572216750244072579526889716", + "299406475390617959969814964241915428140102591635266990308927671007343378119774252185771491924558958781827872793944", + "703999616651181966677173419148734349701035078987953880289257568359737676007122112744119648777036330212134224362427", + "2172889134279228325044264151839365079975190149968886449677188918021894098459879910258646855947760238960290743046640", + "564668675517962643354343096145213261653186767077240221485189660699745766686333949202366414554274029454821520151442", + "2373812562518808824078018443998077948623923158588039939873606519933742306807417150321431212792653528542002707664546", + "1051091653988998037387267770411346666046066172622993096068508357523469616883051874123756619103176170775005388123095", + "519313629877430076792983221838918695230586897008685087134699447816608261896363045804814633777103054810626501672054", + "2179979180295347243466233178268379363421211097581010100657469789877491029308465066730237745810889187931337839447417", + "894819752764220934778307809511418768150193465134551039047014576593356935212456158287163058679806073850089238646144", + "1396054453132732101841892160565329723925217190822190005736843905095744180548497602609619837678907233299663194089903", + "746857673872972409943364536191045981314968311982381778825730347169889288406875652235980380277797869026670259642110", + "2317113923582203130620952104632162236218102868897731091917226413097272861496800581045770918281203157112859337296520", + "925667252133102060630810915152371639662216366102625999964026391085208199542632622958465931199225368071573291865933", + "1383765820263074614192656221248801180489467976817130189025956072574810280929399375185005911652489446214394755698507", + "1997027458902472184308408372596413299983915606853312231162701119691013611821177578052101556304633130583675621891231", + "1800808141388321821772431650295907513969524528943628408035326131765614629111108788535701174319581250516319700797643", + "993819358541914329723208573013492175732057943357710026519068453037650831364914499276505187745635466217015939981761", + "23946932257803572272117752979485305531398685053116534298253292992202326605563026132029247208553819874488745416236", + "1351839354853410552220356534534520071396168161818484241135653419317786287645268897094091905836972809880038234855332", + "2162012398293821587485543322658171857687019918363905175097478165991474431553973900500778088976320346209136868336981", + "944804316001625537890203089575859431886607979872413223586913213420207119515709603047045637722060140498799653654697", + "841623536430032541034826224091661647205778004052115836667884883655140384510555182756827151547938974195037682078744", + "2184854390487771439105073227801638505680418234668496464947841810260149140731906986417178800855696069850799147808973", + "2002949084210162463413190784806204777010822830599820150432652927599331606936425655515159763324738145404187726111687", + "1234454743902448473772839239612693394279627485211519814032622067230419590519767701845404996724416873083496353744132", + "850854912351927251953350155091937606459103778811532560877548589521710201209393228016531033220479751067809123806787", + "1087781180751501001386754964955249524685103656793441285868898470184951964909879518819862590293809530925027222458295", + "2262846521371109091290257373819737132937883446859473466519142593594278509092871505360276600791313807598228891111689", + "885435143320503740605496495053399843580120182271878943958284799673104337102873687190303364169486306335023922673944", + "1993327062803310618317496429194204774933109358081615387192707384963386461179695632632785906871147899736333494604226", + "2244588236886872893043581903365712638141975121899803438549970053104495064175228983111086913109392673894625416677017", + "501749523206879155266589894602285560904962768374230704008913421846558592894951486557058112810933501203516373119736", + "2311710239559917202767196153732725331602180837814084970871891616560956594681120816210917797411244798215424272968737", + "2432356815748649972264173397719800610401255063933642631712019595666704441970559461746544784461717868450034288524370", + "1017560119838464921091028257753866350709741460607951534848453579028036182390900031440342070618126549881866334798317", + "1732175740389738740822739575503657008664973864984786715713491319454759430182163144234502760414769760619136557906127", + "2453183367422452960236713494166194806918784177012402050638274703886985749230318919542958154876647035947442909748851", + "1206901727472095444042607079648114678568526472957852735367714898262925883779531136330771458387655762304261532617783", + "127647361278007903844479047320782976560007791879629271151915281784507536949650832970822841175654591174555501996388", + "1541412705766916150068161850283545794956481522410066018190435275608567730140820107997755158322615846088994715677870", + "2310886883725835730021566677011321809219240421220101373675917939441575103388355732220475544345453784749378824839944", + "781973775269495720115407482931352465943461288905735369717821393547557779107573892900895926882710283702927374956773", + "164093523149922726633712074666922162544116313022014380801111725037063079712312227259822640114930473560582804854035", + "2407514888317628452518561986078534407692266675765590566955802893056895635190177980748355511180123170205909008554408", + "1336779456215350059113065301136836456647844973868668891678626144094136179093720543470684977236246944372922435324082", + "371412895126057963964771370916510316173405139956752652525274741543830450969065266012250087002918797531856220667167", + "2219814809302226496181101275602077554484320633842662388841725111963385742270253357870377835554365808280682213492588", + "2285084396332217677092085089000481211580010922847047878242464480562657426802555253728024830198170856696184064721833", + "825723937406264003653401795698379863294921612070460596031988070692068322058862000836895001902362004159341100123062", + "2262783462431279672914864131148619454799550235424819471455935775735676689351064548193816480634414556350972990423414", + "2364321450048025616717394433208664360116024124767997190249151628026240676981631475463006941810866573009541881945752", + "2043584678679908203386382879006341974947037192453488537307838804130174867897414364183760199139680427861255745124598", + "308401770295990313720522563225229561408210120353191464962204938623285507795444894214552918220197902222601858589696", + "591148127149302790153385861495362036593362814512719187521070699214332593527801544654922536562017987860849178904159", + "604906741541226200439273113149523927319895386763644431555681455174824446492949082459890768372206488753276422873800", + "1735593019959034660858849016308970231563152138905106650505358450813891005116629737267464210991994282861038646720009", + "2196548717936206348339854024951866019585584281874916445642932860664473026175174070859612722604458673338747950203466", + "360872019867569843735623022506554354723772186638721342480933044661608709062374309242941870037845362868030375282527", + "1592584666941731430052931890459026708823336755871769987656117069251718621888519943136407266793999135178754149207434", + "175633958407069228304178121129686334241560714453718376989643402721852622991014476231590788320278878382493603864097", + "2006936079164664275923793096344019062246093902759605081793390748703824806043010228174635819806118335166352452310724", + "1279502389033701178089354800819056241393612281634362333866254800257349489612922291750965089071600843409817037569032", + "2333299656502301173513134789405275182403315797030300754938498424869588829154822046154987072662332248736855905002079", + "438927888778151820509820772585186872551612795063761061679116215464541187381042931268433120895925532485104508755870", + "536331529281022239428803960020049282545782047617887214608653445421674214519187832351920522534063302374357300609049", + "2159094162208927566847825131642035773160853472670406984913951629833668035530242427851529225122819770676309162508221", + "1649705829157960126789715149386620152913298170900060844884755694050790409307841722884398195773034892427276333409002", + "1326703243873407016662835529138508708625973914486970926508039610385736558369874565860379288584540059591435080610907", + "378502149215799199182794368461371310398388024068923794324446317979302178940931455630344396779119613651432010512863", + "1728453232851205968342562152726367944799500284063802647390689932010690136685454409457990196265611443532127293854926", + "2057151224226541383221500493554370699888919490975021983594630243535169580884081249123749231697353961041997313619558", + "878582365985898131090761897374068221613410210649075567514742864822684023296806336999302676246939315938736166786083", + "1065256734780105881068063485085014758213858691285494878932569742365109340217288064598674682174752630958030690868451", + "867474452006850684595186072210161941565277858246337070367693848890265941557938050982732343878885610063677152487410", + "70302099692477945264173429824544756749606201547660599623359659524732570714588140169421484312827131954060458052390", + "930112429968348627350574067872713709419220879081293159596393704795845728914984515551892391561717351639800693417787", + "175366485671566988872818352019013715007265584027443646831716090404989830316947322954627583534006758634488304693437", + "807454316713170100732006074702521830467377924087365403881942954845726380551710538231030577179041110971843393444122", + "1269823967455722307282842465867028289975902976705290305875296461769737610456670324358397610707673402511430039879423", + "328300376881263116684894288776490339778095606149037138677261645648675535748980929627783587083070601991703128756954", + "248171170938359937187800962211940676402790566965100647354488249215014846451415011139371933238577663892343013940922", + "307299758506408710623243075496033357895654824673564217894731260875499127581921402533078596534517221634625645027430", + "1960332720413162824193288417378759616080127216620493917641344885518864545713983171542541361220891864037608150719286", + "2436744208829504988358915791994130217597633423508830835151345162128257119601928925478054360247235958311177203100794", + "1480579175289984544602048144477183667529587724180767176816534034335751162333416519877865857586845925969502128002592", + "1217731527874310749819027886997006410279152926438873605034042628136820758713471663585338349936989821527252241262111", + "318814804546027666541907829310965694877533776940690175133466770298942751932637503686886868286613015579221540672917", + "449160460966999094385525671990422600146963247548124091399432705408066376784346255053018789411522418321109154150949", + "1665562948762853597770734728408851084445755440915484627827484821962530956365737386803708011371419880492534178550799", + "2060960826225511428193151909025944210056593578544768878805709857157422424856753410492278417416023366804631883823653", + "707399103148472401256256327632264148188202528110486159370319119822607548363414165852455380983943713915828552049646", + "135683470797231172367230399579978731692998143100121673948993608954453935410899704509267873540499484010141578099435", + "1765587333519681116462457714557566310495113801973058029109337240179917578431839718464602707656356969134697365101057", + "2204351810031166832770518225356549519519508736926146383191353238921250035820329886880898487138455638244817387933570", + "2063448847536780272602069371146882074783160115180200040779729681948171687092268099587156492308502501751092699047180", + "859854773453162630095114951794001031523065263999038124489278329435232788863721822230461877877873638272785906330889", + "421126236558277561306246538141868158509879740917423268325154940500759742505523985093467317722803532132424472205995", + "162906947385536995785313779290266111561811492983976369671566175204794249584079035840512539728567387192131866409255", + "940427387197752218731245864959568783895086152864880222187440830370430653183591617521829924892975527807038856265481", + "75909669749433921766874209248776452784631170870697112800036176284637819346370058500479958005110106745713830164564", + "765804916561493731124152110354881256221551323406187586229068953525742411682870885630360227303482796820347941490704", + "49923066487130621038913469393829313575345510441939465903347826725508996622600245761953042196441330923067285431404", + "2091263052793666282650302792219827461934807201011375716650853433911166506657203125110127522406735197933902211395998", + "1740154881710131881135769763483932610772344790698735072609272255705943797359638635268577367693994014216930307820869", + "183155424122227851797562276875817919687046224989699523893357907906695428843649541550062426850403812850402235117503", + "565618235719388136194870538460184958925041597681910640951199927502773810779753894544291008614085568959638695216579", + "73777085249451358552247229879927200179158157368567878786618775126817545371018028723358290521339286374736501831292", + "289714451873267826546857787819615364549708235365936611351446995055900981115540066095907768406678472492169609935669", + "1482979801937891818093234710921477028505000103807662409032532377481269448806866932907930167660183102787211575316377", + "1995912086103026066780206731343620041735666158540639706188407722739676604540764733058279315231557702615046758629906", + "863350210874506773240156757414341173100202243798053510908113108240456242993520843920087882340801620894125517881949", + "1531375411621451329635862726862505972315919492762511661856688166858318189964749327308381233923849633596196994821108", + "479167064207064335964200021925759592985653560008302801697455960375205776066188633731952499130228765842426691568144", + "1318524180745347911628320156266618440859237827857513819149413325779224774690827754448769117483292225160689545435926", + "1297849902080619619683842545467951440956216724238219372523584335845532042349159530106760472503449633998807383669068", + "69376705520658418827446661649720544565303455282293898307521109314587104807667255417954698691406625504755631873287", + "2063096547396162095774336339064634880230932010198360072098605988409805295852315931370085756164706511403025877458166", + "1116938311027197532312844703643746846271391910531948730656691909392810543802891988265540964438540592031081732116210", + "2160879434376353469048849784298757231061905812451735962489472238954481419090751211888244329054849372892714156414113", + "1288672053258700031007177510085679509293196946610896554454809278359849746232876846834871600808007747502134303799200", + "1287321286200012831974624330716826452852560283278161231785997587904295640966122761873907739946076618227169178093227", + "1158974276646555653462022691607878465307867401025851740774382291411118001309950379285731398043610720974046725721223", + "235156589686368167891028665591365891124652104569377718824146619744683591487524775795699984615962643251602059746527", + "584250098225724154601295282364181951759229500837622207112051175228896233617447141783744374498829036536121461683301", + "2025681911389884040094946627141897142140678275771884266116501233713032473717568602679792051828156817323578154573442", + "126978525029295265113493716421502110043484368100901552901698537055489672572325209710900960637311777558725989075948", + "2345087703582471855136988483435248823511214246879009457187029169480864912498177633895225692151794840320625533253495", + "964687987729617526098890354207251750208243476589036142716331832183119250817007729949044999183173035180344780484918", + "1164533671419290359878975266949956611401907081476093914960267034410078196030930801941417836105856712871234547516180", + "428839921715232363033805822066489122498734204651382085026075091343883899869841438465846613446418929995208768419467", + "741518836156457644772016827741292248353905540625636718420224995141051403907509010921469660835867383353288950442022", + "615098528306611081616936082216436006449400922475241422070039030357855146343930853292634282847872034799260201081935", + "1502609003991250534328299529078480290948150374200097500646987440068607464283126553032047781902088802922465514537108", + "1363795645992268376343436515683524051157157535797430065029930917474154348764606959665931586234403563451158799772695", + "2059431879325694851294079008836048811350569210238343299022176411326293763843943440947732134556714430943287440685792", + "169846174779629737246634064858068026717264382411606567699745707464476772862145069089393207224709735674993453199252", + "1023075936231676046866055368966265316590725485698827113236837763085753781073676784915182138418960824375536051789855", + "641053717746669733234575701984928489380053433503422959968410363616245723572453578852555928016526683333566873276515", + "1643795357697562264369619933204491498873181216672657513486808977952649103962221103855995835282471612031617215543532", + "639042058116929460055607148814980808009789849075829152843212507504298040311649127111883515267048774389140315738320", + "535666776473090493038904844094903517581725536486572282356034627618230901126978501574661228801617462242690216840062", + "184434357348512051164294717060429901040445431017576741285908325828946938272025722732719187253266608886810126860357", + "2223791324333616564019689701940525516736896510447130147242623791213821823694721766473016515448255303644440040315937", + "1284309816963094735317925230412261867598886728516316232354068284451459744016296478149140679443077906204663150668240", + "596147066167196808458606060076348680571375408021333833425751187627427968339474579096435078669614512393885208732483", + "731777509443305067864049825109458152272043449616338468903737644073228220450688868210656206527009019799427648686804", + "1153131985303923839175242359615704240829688385343489027215608704135137909989617025726008656621234663461101855442879", + "1052347679806288607236400665266396813028552537481067185831915415365133093115280202285784614148258923368248917245687", + "1331628246266841428576732597370368491268849535528368849127150221295435363252402250651033169820900749803816167637028", + "975103513767448326776015137275708231589907969187702098618998053059832654612348564480430333671777218387172522284243", + "2303734976436026498675754831981074434959849957787188245879491634677875672234860440126198939178584876032284465379072", + "965802488063223949861401737967275696181536404954645269965174314613108183188452224448041298138662424145685712407062", + "1304726697570937502683874367707774661664739372822792639123665947867171945536120015658258829435314919323779849657485", + "816691838570410355789161441502416457336375122070423046102955887537147962063894871680004479690688328110294525667246", + "1872474158909611431043059864262060420467749284371911979820640540046295770047944149580415867081421098554672942456149", + "2338692152946861602960047352610179083252366726133808371882556594103702900106159222078788288725986903409257608122938", + "1327725231067784425699861162803170166755731545868770378593622745387754844175522487903477572695182983124556025589271", + "2128804667028931489996583134718436025121894888825717750244186745411950162907810251419256908638794061689139576906733", + "2373323707905378589648690343936751547278860770126219763127371371795870861179069168821425316896690706590842855054529", + "691368994166999660621978030536924727414988043664497907483702550214318562265972849103734325177612179190453868142484", + "4632714946299537134606287633651787889358789613747394700417421206948610840066053633560730493567563650659277635256", + "1507277151470470373948630846968093538604946549632966839310845952379075871903785922333462887356789569264271138252024", + "1522695156518601958656217467382961683667499549234663536755585188520144905222659865848625403668610082603096607699324", + "2042080070218588593313744257430777641094916878339396531978101620914140296434508442670751100164870502153972947831705", + "393686951978461411655594975793661124200690802151738453752485263875567569791282904022998020912407142651576908575797", + "1432540318393628451828361757574770029975779964699567236266620710332867368765510669370437691972961716426133421625566", + "1068172952826516684113402042644035979789518499360198625967343153678782135034315314991733918906261910939700644808177", + "225890462008738907259270487885001468191160154260263996379014169524574145707761361273843240572552486705082842051201", + "1243578481893905760507376272931516173915267210042563512302810874500963146616879535211150696476520433122609990684423", + "788653757159917045038500810497009743192378362371910815534628271963476139235239850278195414291391753704279597726292", + "1094232470780801928296826953132289836823024613810930254454663110260209186150282041307489973174583863464835998889583", + "954264419011693781078132104373633774373067011880173824690009878106365773352015607853224904344960032343050101231186", + "1099844340241022327407133032303051058615229620010594658430747303550679400550989659387007720458899169148199768249988", + "1863087404558385652952385760055339353121953183650055784360498750647458149734953024874888365656823492846733685573669", + "2033658601575621816267614687699663705185120167515863425644279273168845601091423623863726373302045419812484579738952", + "1357919290448625499461622529550866225496508502180014583216780418196373018629672384350291545624651101983447554582268", + "1002204876094741512207706077848745221940838400165278563932294365951305280258754440607739100618054049705808703244169", + "907410251076452623072528222800799783562418296126946784584490710974237997791866216573573847343843068788613936335434", + "2160758349963124929401901316932839104910215807674324577755408645575445910488332471061248597708449951607496982787833", + "1882586173353582472155899307581521911839506728364532372576482514882886010855136153932837826082878229447426392073769", + "1106501178364106797575962420372546055803256157079686737502958759606507636756080881067647477706967089444455169052444", + "458908607107230045631792232731921780529948429221498558889294699705395696647494907323540685318294937499573570204358", + "141701313868103171950316098228506077253096040103482574293998763414002229870084281763890068991943800398220649345439", + "2197895250577959249226094330338844889184340871330631995382355080299656895799910288045277579287715008029770841520312", + "1561917538654129163031556261924467776041266756763148951080605293501953535018298365525611170462044129765435224223475", + "606486325185039281068962938365581005809038072056245406201384070253684735253720126182199322000488570425569462525326", + "1027080541310922529162018332143000308046284281269528406119425686965151485821278029364768538072280175644919936973905", + "2174741193812691792019845623323372795450732363575053439737448156174035264706187432181918166382669734977948439745155", + "184847957263140754725234402133718804526631327618627119631473436864120464768368429465284096506843774771917885810817", + "1585563719639784321188398907012485611629324873357867163338446267356252319340646174475040813802151249988607282236427", + "1135494920998094343112232331299903712168082031398081059596348091596723837323928874568449763919976016082124324151423", + "1376887112924267074346729350435742863361126212034425487003722108393147139276686297047404011187943721292391492474404", + "850606876339879560118165273639339343426039976017378478940094114087006706197624858340847275370053768374520444453537", + "1101185959031564148883926891946892825273437829599742922508463585013550507093155257261854848916158598983325627422819", + "174236079944829251562627813405596335326914287315945124188976082827002594142869182735279873155350030495355452743077", + "1421752736711189407547341878168703758179207224550195075736636821253097428637042932962012113465207140366037353855189", + "508716436543006450339694236250796144189687002544568268200826958581399600881531256495144799588379183146644175003810", + "1975059570095283350403802193722598473943475681707192237193983327076273418752955829488521199158307265959102540250788", + "204798886284749944245992791762209791048704368775219165466582488380024381249221340083247318990318259178040636011755", + "2155558447961941751890066090498466658325763896572298773957994837388157389981761544470303590659638779396674991764525", + "2061513607476573889266710778643512536949045419249502692187001637610904660782897417930464853743532539435498516920652", + "1500783641728096401607548500865635670099660956109936375555115941706581141216245049214103083214916127654393504988973", + "1817898804849142441498530833778710991535769859412328396978372312181773125037943784887539563206090001750999976149897", + "113982096160318594690280419870169517301003615301100980448533428407032495887295336745973688821415444743723791756587", + "1452791699781168416029553689630456056878965592491709190743083936492564469360584810491819578772298754597178429369614", + "1395482242531594511442217446335795915235726670576715452666392291366451458980774513875997959598404852294026808070797", + "2275104702896022946995519039622451226858978534504073867960202333881941078678424014661731256697491132201022697026473", + "240435144612054021520344769125239999653246961506295465140107032374909952313888273091782568374492621769792981201590", + "1930152837297407541566764542175925488357413042185650319630858316235007471345309680586264625655071331885813288052866", + "1159822760038180961250592985030105058723569948445564539291340121042466331222094834470300835160929440246596932047091", + "225881163268537551813241431069435797386764099328640626505115664430177934872761535615816215092499437051692309468939", + "875015615634261716456830034826137926164656314343924385757153752618667830764595406252176343439778154216363387139786", + "1254444706930214007432395266935322072820666648788505105281084635493696505022843826117814166341185232378830616121403", + "962276283339302069275827749363412431028692145098868089016494595862059627891392931247553179160672716170746438397331", + "128189456482636002644606964541820936789810264348891595550804409291934589986684474270214497172154976511871744603854", + "435784634943592305816738003544145521988774890609526437316931746084369830689119758661175168594749192822865244753489", + "1672768544252793678334136410194883248625820624467369779609416884161308125582248060072298156573977734489708603088076", + "195889822040706337331259288366797318026100560660628028789519002976459034523882980387919370385267697932160558383483", + "1128297067229960264217347390238813193527470584038622160436779801276068978337206964305548203645012016781223267986214", + "1333312989109142766635120864569303455235332543310656834369781778227030614786852298991273172293955933727475108234058", + "1479255633589167996995415156071720080461421942876628922897593505623052853314878264234906293470124586057996007296696", + "1450200497288798865904034436865090247118466641396847158913596384329727113712678129981144394658799319531002666894194", + "1960339811416910991251330032631509654533984157732290981989123580273407836604309208211924825592841753794530331168355", + "490494365019504769870305544324903839963089978705882114094603505122378696509858376147620525792276490908644260928803", + "1859387410311462172461265258197645421907565703311489165630444895136494847060508628161564187299836990902755644748538", + "491259308944578775647146959519318334365955776762733217603732977699727780588602305035407624674309426770953237296485", + "1713204090872962378957862413636831782008879027393152910532833955372246323810743161272656670668184230972253004914060", + "770001562936129489857796100887806223858568925637578986641500676312861643743248471614342160714487153781966094053270", + "1228614921434231608419709638216644838409641460610523658489844247751871289644371343234044724758573201221839217265957", + "299894676347558735197234573545738853849165546490192402561870961271096433425502675898638056272041210526922476769528", + "112002942938218707618494035375856032961760066164782850110423088037224875520419965569022763353191505611055879063152", + "1718647732426238263528213109081946256176341481358786339901746020983924305541433442625520705413707841731348427794778", + "586429327912759428672978018939493564302783490135569170447563390063028604464658200762843300021193008011038087853272", + "754709714618034853695046765563679125446383315935230387476689532293248682260660097770147145158486328641626565525148", + "574641945571701348331096956358662396816048684783222045732011206829605953582176471519651233734453998169310189361566", + "2297037464508078557662021558623552284970728173794676611481316081394823400400432215704368961978153887085805416435942", + "640093941933666184971638798828792332618973107471339065077562435565780162192753901448702986422600252423733796526577", + "2167157165089857502181084036339650713287276336584888696156914124030658800769474286026149244000125716274265784771168", + "741076794937565357721833697345259241766241223986934517830373830201280634065522620190326143104661208015084119807838", + "1813879869405422554190118751636944064550827818073916936031598786650961530250376329780033904342192738026175036686385", + "1316595265509051479686019493381568465042286303504923918531565185606191796642043918457208525527317264008178341257040", + "161845511185144409504209980435485964350437942479782317982773551175502315899426197170708278293946098645833290043829", + "1059699623875535682303565899046344741783650459932903632689995116326071589573210489795334457963618855939657403855477", + "1336490281523019201431361544409727251296260012362173826280575819357155735966713827892654841114682069143383963706407", + "2136324688671166512197610406185484137027696719009226357692201032431030177217877479512923391641257503064282504263819", + "333949775952119005170696694064096471361699189648061574765680460705448404799204583761355124658242347620853062079340", + "1450931222423646239690500003366674675242485691788125946388272993865790830380451919014852257039741379567023888313594", + "1781769335752275339151436583900118961375565164399225642248599388105431106541765920089939089986979219150217201482525", + "2448446690195887169863655602997053511996440787563837215300407387398110801584529720797233391056671006479454577772847", + "869979526569830506790651453039160232880707929339621983307684153647797246276730605947790256075963849714324023894760", + "559394776020448403184834167681017141251771929505920112822920359838781270728465828634235632151657034264886627429250", + "610432474040067013372606125625811493148813051825974216615961378183155643410119803530433914949906882420425886941872", + "369951494642952293332299906395512693756088699170153180499094826272947544523243100195062497226771896205739632773487", + "90806649616642510813358445442320942106310809216950879507655423015965117637052709930481309811583879875487677939741", + "229461594715726727705047458307970453396937213348839676532855264770451298491291841437545842654288651212328493530040", + "2258947396638388232197808203549172452244508975024538920210994262217095664093161245543067950448979628899692534735775", + "748760675415464516936025092598636445460913696234758158611573004900272188889694362639913166762956673920778519732079", + "129238177854481307743807828830921863763350405355582576106110989105321888386228274858192541363941756155155144423758", + "731894566888761463165762214707563481486599137065777189799249046805229942652264681962375910659564644379176231441183", + "450684332680465175174278789591072412003885910874063119075827993413885677232269687116044331171936284016776023857302", + "1148064092358884098918796091417382027312421128053787898436195397401924782358427191470207117562721458322472112846920", + "447164608595994735342513542721401047663518171771978965643761750795477685992896161453938499138186538752836228865695", + "885414644019935922212389779349683439500744552855266505069577010520452518067896840540647214016570254976270675300121", + "70557079942644810326877457962043400726746108460909304378308210394665097356436840338875437709454239045373369623812", + "1332725690652030904915916651450220793133940114681090258083551583410725877784301319110099253723187160533003460610968", + "915483169479378613042551012027352034986161553460178653290433583511707369193920858614802673809992477130778990150968", + "1995122622381788842990833037205767881092363548874385653822325443830266687738004976250042323029745675121826865580845", + "102755641150900516625490428222756294552024031771820057723619657874339382930791257519941108015226978800973650691235", + "1193513796544759845923335793582160040281836803246454997820742372202164950278422354215854298486073358772148793742736", + "1615856428570711950231702188493554825401360956446397024880792516863951645722824990990835014270284789211403620719563", + "885282744142796833319556630394333730562225376843727153965947054817820790967579516239284901981950465212828753976903", + "1859397297574031857281768770528891609962988709303988852140855199596686640554207734330573304941869307978035541643266", + "261840685947991434128799147370227019264925846817739632641858591121529882583091652989085571433984170457613573697288", + "607246117514334090567154461566856451054383178603400890800230209888064818114413314574133906519748085395727808751455", + "407587811618643995627566346936903858709228091648472771838930575852274316087091346613582608063526543568403406159587", + "1191164852142534634260822748456357207282231449525036296879062655004396864379241645188640026265592602880577653496174", + "1975529666893695962804475736746445309127034615481043185549676134403985226414981437952707852908735533210144502739909", + "1452862875734610232527715540683701677776976982588244008026986229976560291904110729140649368053631598694707160887495", + "272510571354402505808155177313884097477081407902147327265083580296842248969673599646433469494946410901302256648692", + "1248882233385377607544451351422638276263850480165217116048923216013415570449081391946388085184957788300610011360101", + "469030941063443121068017404204593260328302099444737299476063483046073688657956841926984524049170045149360301155165", + "690843730178906290147556100261081057504670165307631634453044428949275131090792266670765387450530423117604871019730", + "779461494868743197891032441851384628482651823520497336506679858066003923160673149707559958858829987410694470189133", + "954895371964858255658838557974780126709186615034248740109483169655326610791792402707703758721024034789712764354058", + "850493267432728518016182800957623206458600438051971147888230096718105304697337772501651416233905716351301570766649", + "1990619233414195709676020318462083894272860259134409694517081545020626208404458683877058176376396003808378702927637", + "770568823502294654850947100877346634546620367626145130454150104562532851219187136978241427681816143649500023452633", + "654448865970335915305090087212671539990624026150181256633596220987880909391026527797552664927355837575535208513568", + "357206071555114281366231992045017289654187009740905347081072833014692780382532219690226717399423661154961051742774", + "2236314307778602301563386138390695950933598760263714906764950958682006119222282906261223605201910374746429598999010", + "1379731593452189240312970273483695259895268031920411217340943325851682149190935839092081285190367138019715631241683", + "2317841450441863854283670192593691302998625543893930379309801508387250600230223818093248163266758421593556962489790", + "296406856175677219155074378989099713478684774515084054048495564920967817224540910084299321378495528626140616296125", + "2332951461781185592474224451801307358384680053571970574488576159888203642096197937948703761337614528313961242578068", + "2399748055370665602960558127589522739056013999720816755036378939417757657660599772180310388697888610906756977874925", + "2462307746513758033175434367155036916989218114993166469081515573979261279248950111836848207891315287811941426204959", + "1969890810058836822910303660162768088523440851283363388252571218127039631893086202777524635146025620555299694986661", + "627699081609714882295622764050401387147498856765273153057826836701054924397015489289538477876654833873032479380443", + "2035316847415021982388274441146774941433913931103944730550254750747967990227377745485308242909682891729271047825997", + "628517494366157353987572870444093527966475266963141079437223436656547308581261782068217393963634033342560887194006", + "1666509684504575157733539364596825934102843706967124527282899036217883867715765707417094328087780369865454838888377", + "835362134678985264548725089087534601703125070970036409846485195193414648747199250882395305634564709562106354571315", + "431651856520708675416409896543214423633709396701221662881641649593074110845550741279910734949831359521984656263485", + "580537105466790608228106184786320567119411637749411330605129924065044670163465479058786891920434241941397454513957", + "1577555328466819988089095251742320714857718371447097930978200064785740280523206382254379959078487445459388246985304", + "615442252860081752905193723468011632314223980600412549390587680292492119867967757373486056968324788032057496614550", + "151912967132760886775985631595258439800258091638300904584253186301951431067108694290667995093734043436914136656298", + "1459406040012978067253494773350119470019784868578298434303749691790314297413173143089879088794119109025844832991177", + "789242497114559640901270049861829578799525924081697690067879410115912571703495765732368792222415912118686286697030", + "2097574006633074110791049209393138276505110003471365734329515115197743744624160094049434778884051763701543894560484", + "836883734753361701486544864862624645239360024949821479356858243446701145826216508568680133726549372228991519010617", + "2392850146175240651298086640036565626388795867607942289950233321102327989702015535836674378996205129641479916728705", + "461116648552582642111428829064168055623096033344588659328891604222324455106467801430246115807562702841006723989589", + "1891294821239034936010986209272454320967318911149694939377139243596002362549653720870126878120975543444789878951902", + "314126508139241364871752402702299455850872668341432350677823895177369518620366979934365464747075947844724092979904", + "149030433277060786219467575526604424880996005416406746060851104454827951692518457157358745272373585766108983772302", + "1234013291091446289814935614323555083376685341162323216571630906698062232962328015688073819460646604747752502495273", + "986957563394552783580832716029744180868131238358954277525383857089270712100310331335698753820734138383491877355542", + "719956652862903071046052285705044454441681886734585822179131706245322762170950518226697103750290642291599047637871", + "1796985696330078873676063776689948724170103350217728721392390134058918559590858107512840401830501322209732868688034", + "1409538837475086404761117438317811973434471402083697599225823897685181261092572189512536232178053587551342872186579", + "635171595603781482149566459814526047276783004941774780764911321635170649738017961487390414674938394959856387238362", + "1606721009500659911431335022216954277558220182037255552770033429537269801463527845258956202206619996345897091629453", + "756998962502312635247814779706198168282617106074674602436863740835089792375463788226745491515983048228411616650467", + "446791207746485395868789335649931781569193208849709764989336671021277866991607259020179550788889413427693087372976", + "1459958154343395318851105545886646801471784896894566424362716164309181288354331466586770943124127561262707725934321", + "2455035944014666013066924643838344199274801192542495615540228975401877025619917315855769326155808370789449604952529", + "800809091107280527798948701427671120735137107064537936086241213292621468113192495784581851747597473150944068648689", + "937871994052267315660158686109223434663980198902000011153707380388563828805361982011014008056115187574905617122015", + "1349216579995491159705727877103799075485508921749189050145554392183182813603301809775113953407663994156588808645615", + "229849434652767706742843708475591525226544367937754226356404248945291476903057554825045778316148287475430332999900", + "1816978464880175772219870283333546803465390885657245385484794033002915265021373990824370040142017431893874377781596", + "497315146332799015531110971425737011179522554354771140834650937029872460092398007649419010911883820296882618082998", + "1206856371446484023516130252958490639050218161149553611068364080826301115034329453829306839442421746668118030318149", + "271048740163751483768362101232483117000653845202011950687534780710845408525529703277200361052695824503159818545878", + "294894087818771246616457658042829581683313893575978246461822139162513999499571892679058794093177455166481716304222", + "949716720660101145505977850506642424251946069233203667107078188816492984043058361064702779364353734205683551263718", + "1332160450146181719493839964909767814932605268168445205085028669715125986224004609088078334106234900010485194976624", + "2388739457394139309388375889485357734494802851810982522042256544211393303095155881194186844478980432398784086254921", + "1237070841290547360602869979719808762599494127228637630226020198227148600815844907850421016414414652056758952197853", + "1904730985756466972941070089283136260584115729410595131240853208815203872553229359449426401247941715280626627112864", + "647428159500667186860280856678018521528509293349203110037874248743518237012189048782696394046033504153164200735796", + "1979568079396487322995497865720279180347274758763112970304375266814298844207832687101246835805903475055904404437762", + "2459718621989039438483246254910065515019438299693453566031345849335582794059504237353422169440832666115290435425023", + "2204451110600984037016402787329457822023840661995791455861914110230815127452059898289327948085167375506905153282846", + "827052331246439123261543245657909945688189014150994030093076221026146313377637750973529647064795573460847553127609", + "1546256702543748416115601287314127284179758456694543898864524878552893563384776258190386546787390600406382844115115", + "483168004286966535639466731653569703865685159439562365842821544743096106920989995446632638167783137738897809543736", + "2311842507807649627994182191821592029504493204961396647203086208369926581707879666710562118134977843341063314564915", + "1084166765620998479701566150695459805070307982169092181398709280492495203420301283111307420481838234856558004773061", + "2355354839457181773990629162528284586851222954482956547522678565250346516548553471982889112444812773108119116360998", + "1767390602609781034080493115066852906658543420505517523311117946778485783719064979136091915679920395382662185212368", + "873021318710151904325698563403257539586102280803773888788155301147733910430309807468089068978041865550064571714295", + "993790576418490374475999413380410753541502045574370467494235552403694117987325140907791938302052468835350315269346", + "704486510034029123253430234531971422797478533743295162739218527608100485542392723457788156489424821690736483754347", + "1125050726349129182372732128517004111969784129823318304033844156298623835306552530481312815618432549691851517590585", + "1320450516761946392300286198003082191567536932388694240458723479352568704561319422425288910348183962852603753171801", + "397492427468386540486753939716435474033839097731063584193145970502537706804617737855749841964426423299180395498352", + "1886795920752745464781797264495080615431467093115107718128261853293927677989052357230325401831267365112263896442791", + "2338769026365558409678866053024153267784051115073772447880537270334344948747146963589374558685018961206902624047453", + "490517529519444219808616149366036941318295251577331054262471456903211278091350567346179786048989889147049661410001", + "2018849583027043696582743146284492613769994206122394098658409417705161062559450256991577648983152172889024439463096", + "1856955208275728995151071886141785636530695439252806245406568803403407146593112701386171579774667858592094546068903", + "134351055074216232944418873680928893052797683968502588515317610946647508792574444791825269392035869853675045712451", + "2229140227627035788058953995244919933042420740875671012262979040334957501359765780400182404546359198778218080876643", + "452738445323474721688594592840287455082965578112507491167774708531538984920186775315765892788228459967953514378103", + "1720991127145322743019818028966895070426333209266347694225637725037626561769575279577324633271824623861899384723670", + "380941609943710378596148143072458225340501649123346886996395828259204172143714332184066282745011610999611526233977", + "1138326397868656002226605783247197864606399223542029935144619202614349588589096289877174917737068281315308428730690", + "1119585204257290584764339556230092268018050680519569607236391173588870227444479386423385744750066795760925107730405", + "1841859063417334551685749658675259314506116387768231508816532690448340617334991235270011322248579788652852878864617", + "2360396999731516619802289445617363851229136957858656088924392024239194132522504174504273991718808591974042835901260", + "2308028606786306727725133082232371122128023856128996077041896724681652081321653946922149654753505623227770603874839", + "456931727126867282367494900893911125721870331832729622373567077298133939530414899378614133485700336514099136722415", + "2388982360472195758237853926000125325160083222996864879496120838595273104865495966247045436258604186383008724547493", + "1811274281120717805203654943857618617293273917287898018659288793498048279317735873019464091428344740130503405259634", + "2034715069180824239009821027052529503153925877690006168919204928058577348242009793403272180316201766596136213291153", + "1635982475443248954392317300006082168351091852665908005502832723593971745895396222209301978009579563008207683220966", + "2335955111372509285238252816982001346123146892475960540944868641951998866858180106147197673534571561570046910221244", + "1277919220895551113026406769060727536427280755300168196383004078149602390603431904169009927354257228057510823348160", + "179615288857828751067002764940362740479857156370141279871729536726264470923959680803331168449927147582487251134234", + "1581285826047674280766774657661150564121327209740146991903151229974019377120255189953821791691120823098208671431611", + "1280129801148537843363402334366528876674526720550517530969622493762747674858199223667147375676372826351408030689277", + "2249524641464426734299541021051054551582135921832390139584290455617897530834594745143075631694768237364548295095234", + "1666620007767482146000044510499286155181710278937627210713568155237527979690549286742779782075554466655733432417075", + "236674310923540441712359030423612635693149073199581419097943967032752277169478104208467109479109219221238884956071", + "650350690361599192136866345527368930450859679551027790918518656516713566232221528594661107082753675063750492966573", + "1405670914283528022352118044734066178160221681903849377663991701769555315604790774300799557382437566697742068009041", + "675542564651966879472073407760670361322655662703233376718637481824630037469291888837507787738285014670967096615304", + "1412484837296202610777315847020450270742338388827563687311468076027865253498215769527046760785803234367446699179601", + "947109288726941762866861163408639872414236384631056395387739176097121675955929172232779031497431539713493816309675", + "136162483537051403471412143770618517827250490027358380335045678414723506957899661430316374197490669987640412045971", + "2316598895548566235035745862377107443522317330714478466399011929505988953887637139700779633556920460862154473706802", + "955754247609397563347277843717647902233777328709317616162487948205832014036972979662114390758927753442219911977112", + "1496521036630953368581284445660063182051965482189565303013229836256465983540572910535732776940301731743095748434904", + "1334077622984473465160719688648994360952619688044511844390595693255130790093521317580238718916863418053886367655697", + "164735856906885361129660224307020374242602330806449274590789193559560108986019777605763485130960991784239543910683", + "1311757056378306454557528416712653317681123754054699331240177464858736699475717502539714311078880445148572854545833", + "426166015553445846904049339673077173493970413601051883398367919112832371018839055893811487850571554945201602684155", + "918882018911066647557611358781825405003301279498552998490049700462516225134948751029395664449306295789974326620382", + "600874436551520090008554541356237604690751692999612483099254912670241699080086551214719300730359651183425493703226", + "2052395957472202674778180633979812747362889775435859836711170222807140635776789122175594153350308513489467751773111", + "2268696461523532225816382375926795969760756288828702777446408112029549408314534212309459994299368160273445857641386", + "1751837895286615686803329476205046105366298975761737990040061888113567384561997396958785342219816422354650797615141", + "1039099223567058903410790022111913522383911915188990873321036436626018572201862344170162443098047041721745916372105", + "149739978577144555253324434757064764478510229979227547823091407419818197468531959390980619619462201611414929433700", + "2207748898563692532343893488007550218930355536912102327857348831481592882589571817031809402893829714378520059902852", + "1781302523019593027267196553521564407710145678072103948923055005930178553315420978194035891803903838114187822906389", + "715346154477999168117512398038946716490952188626685083156865385342872526675853892520406629212552123242210510713022", + "932553469676135078049423074347435644937349287165005358604472923627409781540214736008228649451461853159750217499270", + "405936413578177550040609140846280764393503116203365947318814603299742983793786407565224346798762509380492351012407", + "248080228514284937200647355322461758840640977654970434291437641280915178044266019220183370840603897731601644415778", + "1027596182301212568838828191502099162265099570389854207875836662471625955305794731409188966267733191075187144769127", + "2385695302774318057076205030718122873831309625735827207776181834325614178620762906846094005000732524748256419811893", + "1797881291678528628222500209895251112521396788499498430488310295051928966485604620869222596654082793202692121758870", + "726593649680485611437537166122758020359539623948661230470723492623883609007505253362859390681394498606845859971640", + "1449429822267903613369984358470645585153451251642198072788957607200521580197868979595922154547005075785322529279336", + "1758774813972479135859007145938524059563599325550366554066549193857772928340051466391445574097378325277612156232261", + "1536291732360682520056632227125399667716824050308879330538404097310418098549749113298423783915433339411385533631989", + "559937981540310282824228908673176545894156610357423368625561276553970016667177894589251884254528081263936656245903", + "1666032812150609299554412906357435191947420497504420876388345031249309667543101628465417215795879289798289814539236", + "1423583981481500933477156246610063321312679173984699719544125906517337257586236289680638866171028977194014332386410", + "686336603970494859913401312699157075184638170187047043138798091081770423146548609389866951938562843995029249290992", + "1269230813880706693832515529178616974689451699651182509995866869402030089608498614286774427017407045110786037506582", + "473432643361864438772639294995626031050401364943193528511985814532653148176688640929913441546605776248968458638684", + "59047554486611502150632754720549271741422187935423936478470131168475864338282075816922936779661978649959467375109", + "157718561807654772974756448330685088143608243464853272527676842545485567203730341522006053821475630319151724389595", + "1962856897659624356305850799641276900374460827943426146685495858030040289209619592335491805136866613775916314236555", + "207714873588629960764364294579199312328447975196705006287766631409182222077756761441153243325132877185764361777756", + "702385559408847164028893060327798369192593685802718488230964951095158298430233352295008567193978758223964637245638", + "2415900259371637369706858331700722816314395932781741537649897042314010653930589449228002517736249785542565382658558", + "812598498835368358358846868902830738523908048295971449743573845164981155571852470229452051135179546708940871736648", + "2229065714775487110157667959703818806631720325235073654553029576784019621698591943579875332393413974997953155791154", + "2242031468457352105870534483371400050710778430099444245013991986065932377672515838214615704288420810122546040700056", + "2288757364655883039177316016861980539844976812642268210691451135694110291643898377011492012728764424171301953535181", + "2318590782809425321831368561551040424335283548888286786918664834794519828735080109069775475158186497117855560228194", + "2074286267458774276752609471958319235423211732141673072784656931269868436812916734602614742599553033644299801151908", + "2003275569451386893475768013586337095624242063345834207479854628348284107070402565257952656138012396523450057991711", + "2128222530701230933706993606127392287589382001705329221360718178608715163975244366869732702289524294157854294309298", + "1017047459834641203458556242435359206250924062856318684513121613024248216198537774034522991584595643582350994112525", + "1835800859279987083518096982766845737686413537214044725866844270042772406931271595421170871544227365544333119510919", + "1650651323306655355233779077904058596271212230297319056355972680740601156495858835788090488479862003195756020896616", + "2174878882411374699486010187716843049103023361588547903823404416598200192464117057459002939044986291322829974552681", + "1381340081893903145813548108533269185047300087563515422246140993192198147796251820462710942910387260256756985310861", + "894863310836798885508191007576176266556062352362737429389805700381559514114055015006246913354697148149831572051514", + "456380322909780010960388598115909217861633230380448765713885548257183518516624123745148730020639899558852782265596", + "990941327915136369127918465270545667708399151707437846074524275603909642390326997869465355311953554167380774919671", + "353204389698065084090191028162262113568141484782225734021958070431403837177911684799862502338911675322022192109155", + "1057995694066897981262334185693520351853909790900823338243017643258727400857267609206876444996138439963587793407667", + "1818837158142730257642053596726581444391678586435333491842115222426355391026395752071680762462906466279065277551392", + "1008709530371374724513985799036006511264314583206574992177727699753998690588811828510497596885964154174226289143541", + "1493176058435682381672851546518726856768594880833556938023576244687314022008765248389538259700026850969472980529793", + "1085842053505890093838533187378837956570994482908398949202062185892533200897274816851193785147088985109947545158571", + "1966388422348247916446306217140268689553293329195902478171504421937042808544740196000690039227718452726421647415533", + "735838276494941919697175670424424701658014381419094997406034049899954988310545896181359060016358662970997631976789", + "1276415110806674801430139675652658932885649333329272993370549059043512401044297707388510891679688060888316694444245", + "130126953244925154787228999303299696350772145453280200394071383973895093498136426985391690808506847807036382960316", + "150304451781598920314596986795690797411546841131760567411130193318271268665746404806009049139181337584098263785873", + "1094995745053912241431952170453395123876414435261981641329288902669710291471172197720729403594267954485234274225799", + "701221899771096187036042769564193607424813050132777476177430998092815074543864293285222229007187809967285729041368", + "271856892337766111632232551619752205963437001368415000325784862996426718661581825250226759047576991909615204216006", + "1840841767921696185722113366552609946285281357137847939299597649060892113854519644351239061714862036128304232090536", + "1388771519587340279543038496811895654490828173443263583627254326382263401555387447092820843500608669042422163773781", + "1828641973265248133436480806965749500565111908190005713529841277421483155723300818815460243884186220108354721565619", + "533877372106259181273846339092792539030364678629051340475675903336986193767514807045285517016849128547026770829358", + "1494984117945347599811962187129089361038487272520590010936077732443354475769104059386503214852759381370583624187370", + "2331064752715415556471476233797748813010891164125263663521858558215775800223333920216301774673170031410253925502826", + "2155830436842857640703338834145358323510381940721374415244385456359695239623511971633086668955933033720209031999752", + "689494143654386351619891383738599477455435728448150471552392979381466242304454550001758390638118014559344746321661", + "462634887401074036069667245974243065323731353354621027286889002392348266445148697388350206488979428155239744358538", + "609298429394370042981486367688521801568562209874161503557389061456227805247124287515336118574208769993867437070107", + "263705603003169235717809521485792400456549098445238795683626764417522955662056620777406963612856543728958942777", + "833274322958852107626240244464889638369076021797865156920521258450271112643640330173524338987195262606872520257552", + "2104988675972377028109701580866008701915393111550507320186446259277379680135136495035044371599906799830959575467483", + "1780079550413941809535283531095162785652583436409283732932843737144952687419203222866368245798127511910718704790341", + "1878458521566045401933092905972693947104938595269925997058911203297545185513213150903086214837864511723349565481280", + "633530727772823632301750490183629317233103171072450173798489847651490099098167009152912695147557646302427658631865", + "128894356854035725103845726922831205228090087601915918159483827803996837231346145222839138470350086166529685244630", + "1848370021314710779798814067346948184816636587552727752896041084319781608814236649828418643112253760435142037181756", + "1484496773863923809397820691659850812457038135021869281557617529414561904906261881630093297586776667973696928317191", + "324333087125242016719109162158918498767660727908905773193056980913526667956458820191131444675073981723958562615369", + "1312015045572705530343091579561507665629854737475357991530565804471620019332590286314028106763363194336696366093504", + "1204190501302993793765278647640574477509055443816413364268032511106705524094147369476492240488696001453783425894322", + "206645804733568553291449657505368502743406599454881703829429118358475773627015401154770620133769817637369275674062", + "722546194741368284153474576739179753936558084721647064298375735622679654609164298033229788192451802063508682391458", + "197045886620611862984506849934036713197585327169722245043677290350929302119685419871399422963247617182695886947216", + "1741910592641326416985692039608512459951161663813179570169894392890584573487178288372947546445360967745263158599098", + "994861549166009666901185465607185470513412378927651060543240580594748323610036323201950953910497519339420755742616", + "1056264163182297301478761504386976445696308728484684487375352388413898177662647336521593522045341821142003955917767", + "970950224513728553360343656664080466850044764053228760960458289610441004485130955735295032962713997091863425275423", + "1363925968967500590815322397049448504457119224946462846738274074536936162294284502265077372825683560020622308897614", + "966879518905715361580860295808109360980113690078288501423279836662645964825861897731835946999031150824427089020054", + "2127732752201176042820832986104920449857454699368940452190775598821177175901789890339233469534861087654574890606721", + "1016742976244978519302196813924850676585454986268508390466840998048233192630326134839651158060462625897183641542890", + "792365935204386973293014440186566135958600796302263589321392064404968717613116159578676891829071834953717577848009", + "2026547649068054203230911363532698026891457755087222889796555902680768499460203903563552711048913461426654739637628", + "822434717147867598658505463628133615766667714994684314098492995611609810305403189795731727607329383794185163181881", + "1308270695553121536674513047594775175898576394347121708621676390641295171159870163022057614748464602834055504027884", + "1041361446860315002991558829821792156097136435294692723509640211953003637239654744885692627223448698118449900383706", + "735807255195790523063534092463177609605452524581170937063912793382881918108596175627488914316442788631356341825856", + "1565135547486021666502482080111136144471093904928259246387469861537148613179586162652445954754543608472206701525824", + "2353091069763282455220539193305360602693094857978708263568901155898593336487276773538434286582413869753545138679043", + "581330953729483006313692415849129377499543611348751325687102803964637683240601853390828162105548910179240158375232", + "375943589599180332624272837386042655934831575746889708428261462057404350060195522782761524499559577937191889696184", + "1305520890124244491708404729401563039400672163671921316914037722929271043945520008949996039362506093284362735650359", + "226486395153288272228564875591423747067110269708156558801018841288577560030267681778180715845009512860471397697851", + "1119838324134634598884511101904005523242087788815404719136325191490388153427072759657514223707293086561024659457485", + "1815134168312579255506540493476793962275935026952600596512348690550960508150389332819281626953400840349327788744528", + "671248376438702998189224855575350083390213537398673373374549908836602362415198500252367738602870952791529332013618", + "1618892389922827867847806345347397785159295285564675635174723551675662517288436301085864773273755418489167985872708", + "936886757845597533895439749602294846329814626472653965554206945750241131151745145001281367104425671966643995663524", + "1712085206168498991581114539392855538657293471870543314795253544733168214521283774373289509970561753861641630728825", + "1228520583648003491664985362738924580680062566028276090301332483998206706602875081238016716054814076391169893261333", + "2191389260083101349906594392588037452942069959278090477789305648217146058157476253506120218970224083459993046951411", + "2400468295930898419299478456580643557439511160518133194571304417247338490255956574962426548222211748398772319178550", + "1502700682759081821824921417867425689358709128582173957336473321536037742043154767538500861528472436470192372119175", + "1274230611812098424955612754090089608595684865954177679429936441044062394355563541617394834634062337037055092595222", + "1481366010182421659091598678190727283748233837082311179397401699978794981943460754216363623974394197952877560050879", + "1467711504975404886432982336770162625874321046251668787749820696712690376391766946233918822514963649550377948036148", + "1631438890197905789832011497134439256420196065984154050301994776613699938749855029362990380801772275816736557547234", + "199646244019409680327876624167747406659857223294714907268287082732326286875288490442744207149534861708929425685156", + "1481695895409244507997217889452792107590394146748562510620022806891926383085047373624331175141551088226934022045895", + "2159094820259449846611134945516347900887260519252271891427552105799021124020445203721047945009524971238313027471688", + "107086101178086556644327042115883572967992729140922044887354054337513321884972073053780248556375253831160334861321", + "1980383623304061291213718942461879341694732332329678923078408738008948610705579173844288071726925285606760703645538", + "34632033449724028061051546213223569843614612251407630767095986093273440880191534763978233029001603503341905045579", + "251947443939296626001393286102307645372080782883095506645428229268339105929760959376386411592713395995302168645121", + "124200255347797739814220755776163953458354862775732419964770680970110929502400561104950184549761856274389991045409", + "245437926500718860774796271555214197103864462882142184287364874633841718887408973029304560152747297551936779618146", + "1508287478257432033891621208279090754264698071401211892148643956597946197772216947629109087736353534890552476857181", + "1581496679452763882099049360225046761070281427230819339324226618868881794230190485766931923918106107345287958203287", + "1586577654713129377522172053125911954310150426116042260352939882263835357053363548726961398039069549082375607601221", + "848225800685717612099039419528710497301700060404444591388492282212432984219450714024803346808004224496419186477741", + "2274439194663876173499969264780402658391435915136339903893643030191846421145444712611344062734262997842873462690428", + "2393029254489975584765779565725036404427876569705882659259961411748798167318297573238641314193229910310963668915485", + "258809004300040937706969105070885887254749657955574374404860427664400876743750693703433591711381482415500879167386", + "1555398273574848966460965804840750765050954155300243937048606572518394096424018926277910935024192796650422709373372", + "41932202012559959745282911026452124539887794569867204617242173472381708807625815125935359585750725580599587870141", + "249170591567650022568118356608259229741954228192193224667111552707634676914608380670373470117648007048724683900607", + "1589593671787493251167414691235355620997333629625338893808712219086215619471707445401285912602696237843786207159899", + "1063430676060244899128469783341664521892497462444230241674773807964093058356907888459048840847416752003347722051881", + "918031234796764700460527957494426823209436481621439851413882647434904295742329119389043089230437915532983787370713", + "2410610142756389781703194066732587984055253030555264790829403057173691843116803668519665018413561008803730365751507", + "1178984222533072872787392113593450784000079718780988465319468430759205111909942721918160131025978435565285858419065", + "2246651165480590257085395394578476875581561960454094409837086468082539709942102284336922117618427693439835032912559", + "1034905308769618279396433448649536866838978694281096356414773124378109287235658085958883035529498283221399819578223", + "1338985351060717586161603089458851202165386273661589514377456264524999389127421045553222250511533424772422268303731", + "62062577305605244520761772720202928386067983404799811020047084060961618616477513551893364168935014006668149588554", + "1407612281933631329185053609136813499705079691102559691472765226374243189112682253103778805520511488746971695161181", + "631229574906513617579122680168392007359653164353443555222874474463277584397618575786660117304818652797278939096560", + "1398427158365262966039264108273490797647197664541621157368941362735763564828500656900430791208412467055124632775065", + "2448408653543046356600905085756864827433152194137745244750633382548989935399461880999030248917328869568674080805320", + "984555363142658787685895202347759349569929802424155054011261728814343893046073990181788121833677407652615629116402", + "1733995881926096483679349623379026017040647833240975830240770536807727117974438628069532717936606351346569952268924", + "1023508469378572015666707949139757201905600864556551816575309476586993825446542587491792613294457718197665415087923", + "1564067865856768234896334146082944948721497222491125860054002242101055551626749509268020232251512401211631228853066", + "273006212099001867813251350318960548319168354611849423413209534723134679751156809936639399634567990027316125808684", + "2252015681687898335828211177241623278836376930044959308850631712856213269255431661325030876969763491383893812969753", + "548665817953383652127421571692284971423759941866012694200742995585814460000232670163569783120635359353059701059770", + "1245159273374947797909957803166654007457634972238590660336119489370519908928393455228651438556665938479048744810242", + "1992942539134535226768575020715887905153691461448997010220568439064429985935361799112625699088150518372539282826006", + "330412604081563873326637462607042390245089535406753734892340491286766497000190873817284174293498146838926679893079", + "1700704698229639311342665897767585750348344336743292875941259755284396711075312568650979220766427595061872787111117", + "1831788302278214118886451522435647831005656964423488251682375228165207650343291950720004537675915359136920758982044", + "1001398407530212085368235584598892786437488917718279784675049892639692927883571766397649187380149066479835130784523", + "5862572322643915586809986035289818193009860484031554639844092979773918300454262279612899457939429002408443918536", + "634675714836292285148751260302743012033849325723114286612371767105401592508493335666532397205140848638890803078995", + "227376535103684850927902219031654804266468672311464884877223335180224307376564242495388207849119569708365391016944", + "1714890625074310832086426288740884577127767957370284603439616832437974657021710481570649654567253718683019594274639", + "1472765968348845391475156648035993015192927375750603627221463940582195197414674193508865246527004254516458479591487", + "1338341339608400063740275362604811898132094960637170906772706327962224750521806721968842232206200021536386790482233", + "1966210351639446134049779615443760038045286261832650136591673246023578476675861064766255170784068060956771335665940", + "2128948031352087523730055554834475853223482780939365235056008704937101479947549757020104006578910975093017577980375", + "1617180170434421326809302641484690268472679706552518583462205038820484827736082012193515419228164031720523563569925", + "722567584015779760860192652593878679788315652050316913991789707415384357861350950992639076756679990097244672554667", + "632924046523217455495896348383151331557668990565508859385114161107224621193696229041387240116891087091138738305057", + "1159731206556668489483905771284305030816124428568222791951611623976899443915194402054357729259785103942926526767452", + "885375733694229973053039335492410298984974986385499570089645969233197868186452462769774405290909544368595630677151", + "336164144223411021365518634858139648130836106734271795954598159146676417895530500771692862453558219067840601098109", + "672077307513575899600758590066213999930960531139446010880677167540144918071564779497197074034165009215315603020309", + "1527807999573521199582479456909501697231145588476752541814587138373622841196085056713190445290966701912059016211351", + "2088587377822948200156245462310801026499013603264418571401662985593066099143653247528594881781854381452504717566740", + "1584739475134676182578310615257330166339420474729566417225120036249875551912237258746975844893096529377425003500817", + "2363231994129264344128676649270573892020013927302863956810586422108549063122810781532217269884219703956308886882954", + "1883093812809156680651970581734467506388401258959815635687798162740797298289805305013184203067614567798632603650260", + "2438292459514997712267523068977161224974654619340538731256034421067234319255217369485195120556354455221063228428901", + "110498986863977137857945232431001417159080883968411665866066293696467301238740773621776208635269807248666832569745", + "1380171280350074947277687899121555246753970431379493693006148536635386396942025151748255890895025839648108795401830", + "1724902935324265678110674602224291031936070239556612537414309964435751529901667653482554378644431513165494922519993", + "421181147561582010378654502868590379673423037516771765578507913453051752955518832776702632470396992789577546747977", + "203159037962135067103286152847449607490954306928371739070127474503276350838935873804316901103010353010824919362925", + "1129386743672814607246886567298657331333902106637653960549353212810177039050074437401692509298913865637001554521668", + "1214837692722579963969256926616075306071407706725136382132933641493835123269244616365342213381950671738411906348049", + "608415482651107281365825606521667408923228014843526078833279168675954150583861702387308875560359897684850035859490", + "2418155629937099871966253358948526899584129947705333129653882287847023099402055247691088901734380361810872895483264", + "2313954950409015962034446222429411725474302962778725563595728442030906336322205511909793147898680302176125370445078", + "1919397933732818120589944677082332116440974393132027988543204490935322131682504517281151374728072772695156807210817", + "315512858331692044901404417316050693628575263310399122558074575667676011939173970884380491390371100207699190916054", + "11119124329715680456290955493177367758537826946022969918292449779836767016660903063181715035722886584763053629158", + "906468141375887959009856367851656144432627207857816155493679650353381071645420569895161107764311140607361633010844", + "2205787788533023726225532097791479343101682528349142780657392634617847720573048671176914047418610799694193390144864", + "2381320101384490918234404859458087345312245079227085683746472163665665745330119019679852835793491952294982358929495", + "335212473613674918058056474250998580888910081470545504585613952328308388181818576876942852283880261248287211476716", + "352699532325929024739548605212270346141857130833476592324041186669124714572951107438276518370477273339055099315112", + "1451751976693943379375109592089909976041077670972254890842568873681966939329212043473735099793680755196215448224091", + "1204074921061474280486352958735491933549709672702695833479398508143824209831826491463018172720882789507708956451995", + "1809743299456314111865002849233125362562851639324761648080445960184846254411257160525591258975665761950810162100952", + "2231847704945250462070808035797964352931361760548907489589751180061414831756962682057398583514524261892189876144796", + "2176119981186884914481685479471016862196794773990996516083301791563256279906156112411900419103705030002276362093358", + "1336494251288644188781857671254982341123028357998061666323412542910355116235660564613822988656489000128468417688710", + "528721967641630170664026408008460101506587071529195593238140918092941100153396363423938162355306037275821076111359", + "1170447342053375853241720223765081611877024233281006401544052676602814117043858057741239511015984141314300198115363", + "2184899260240143472261622873682116036187356178251473855595720222741595324310028759007638101043957060084200029652924", + "2359181878923652699771361212996793248901242603685601631902679144434707607573644722635945151703455038392898185685941", + "1525950840956044794356324523833222164143856282469538819523019071927463483573083572521677001576485012013446727805018", + "1477803814601515058458998298663897572046864836775174326880674557399031086174307699220725625520150135193417545066263", + "2093829460790583459977194290255782384828588279224806714149743822068085798224044406972849593348359733777214013776971", + "206902943503136111768184246210269797714133686201329872765085433616635060570903012168679584773663037122331296179436", + "1815627194493458399597015318938928801351428984367615797009991885776493384760218734254786805372283929048216960097543", + "1050740010212137690761972280185938169333829176677102549511942033762641588467988772146846439642678273174763697828226", + "1624515772560404097051599309028732615382725806913811948523269824345627713363535294228957614994602898174335326862706", + "416836039212459839053261591742669025515103053696390584040224161731523081417625683864858118778688307358604819829547", + "1923246141404138577481239204316600315307402186774061478048765454992003947208704455630405008943101338808916423912818", + "768487650882735185729425356614253215912539757697461790054472332139945895106101011215823813483637594046937015119496", + "2134356925292327767834167794830276355134146509816961092492928319705910732796948700971102260046957132366208197485871", + "1999093780523473173127812848614235603574888970474119525788588339045676202237851830029768664213313630196990596096557", + "113384509992304754713820971703041825170600336846544716375514738805395703805789551705870804976502225550087082312042", + "215298119918587408157749180842698891224872130648397703023005431730802571065402769579291568884860638295392416505319", + "2043627446204918209136436608497221695627722137987350501349206978243015403964781022219319854729249191001337194414094", + "1005660836497803720447332288452054964668885959254140397237460694908072566551090574079661007998509383079918577838419", + "1672333395191028408824809846284627078504823039383371003780683984618992691183765726501565083676200288573694371805733", + "2153822943071931725155205740231780235462350731664361282329943143179297396974596718799749436729986004107603186029680", + "2407833627203201362705234852622751971781973068379467885620722887605069346398470371301714356182829093048416209951275", + "503192994878430859858744952099636605662467784433635837295108562122939261941567306369765494526217724536659723981574", + "1766008052532101763171597950036071891324104445805917001852309199160374942942802189094347650370446094458803239137946", + "1074251523305174151486753089855168593271645072931593991967497258172398154343502251459746555486506871451100594472920", + "1994685554892771372426871839603807652376446168343351092764000077436931574739787668250871035703870917921438036256866", + "688832816879251557901284053068418632875417342351855668584137287329605886431627473073075149416826040746707396332008", + "902739441052259253861812938704444347161638763056353908789593313833652265881758389372600877659023948900629188331914", + "1935001756427258323301418669488351407698176185745120274736959158307346024723344865785788345368604666177184829999689", + "1726509047948884209326735827438153105831325470099951931897214694530186928198930261616252179721134790542661456118031", + "2028125898401202049925136061231128332190584941873460641344891477759824950228989063669871948129015505744211959487513", + "1562389633580202643925900710519200353840143012099564888105011803465957784236501895174661121150908357573636726597972", + "1430815941075466980972703019550781625276337199313857209089842652739188285079993866681161008539275959187200033504458", + "2276601433836432982341845867910402604353615751317583410686163736735429125219392801683162112200447106915907592454187", + "1202793227514929369507088753854403790920737109655845519997836346698782135955353747146363036712139218246133051991428", + "649234012814609812027874751499364316198398405323180181999470787200336789063352018371536664738232966049601631961621", + "1533274157603955792492265563140368588658524367643162861183017249554605945137164901874933164423518529803197941750737", + "805579305966331331217578532203655308482524732654720285396370303758199063986265792323168784960137634027161774006625", + "2403759130054783045536791885762733650149040097413856665391497176042362390336848167820789239987588523461755690826814", + "437543320294951279872023421276425606942521668500051951554075701520901540103167037878458420840046857515935455029713", + "1826887724560261040415101892793802130113106941664550553415616819271728294771745681350671121724238195012665723623824", + "33642717193817239686920625969722667689454406391059645210933722723760180882669335170505381989835558853676211623452", + "371840035736120047660270186813314946258582089082799677261214349174160631913368104249969255269365968358570362979571", + "1693093762319304591515057774637429073069001239388243903378154579738043074794087316710043931172330358567790132685", + "675121206190664847188992968777974182625617785202182191394827422440053855250075220874979874248635706919725839043221", + "1894104042048006930357747311428250159292835813125254424193566381259968916561995814614422162931070759202348973264071", + "1643595612344672105814999721870250345094971934966252292842066426922933863965940494690800791230265217500413452899997", + "1290951547642078544619099049940559836797172223967424150365723529659299016284733451861098293361744077499152160462762", + "274772890886122959697359950822869602517129781395489814003733012647786098104013799853158358182520443450433740010854", + "824631226589913852516449046620000589019617554503274372678161504825677311846023640466349675266781823708535399289654", + "973284123657540871956807009962757570542093069702490459152529942441774925470080068191245394233858500453151204817963", + "489490727435539441129142952517339973543488419782254762363131334031671410031180855667321139915152620324340122344733", + "1928419674272737121535390359829623854867730559756972382378123140697292124730263038693534301581757189792509487177693", + "560954840859189711971846583924417736286299020128236531644151082675220263983766828534351645157445037968889074557565", + "861664197528491490896902349063627839402773228847117009662123241060751599583765660089950327377009854457737046111815", + "920594587911217057911569721783752451965435066153388463232411712046710582554911134812621603810104263856891807335250", + "223396784536688595278677477754544624390641624069795031637583779008111312049418755073153307718545358382856635226153", + "628891195515329714315935603399966248960486348165372777813806508385923167519005250676918826318837666350595349124762", + "2333516523425093274727906822604133821012986688134231693310155318944736911319782322438715402701416759687747415395373", + "1958838359068950098210860016445724303365235487726859418435343421326509023067109609988470534012439360449831844939711", + "1973543329289725148359046445356305418072679143867035679209870385812924017589343485114821040692526763194848772169828", + "539975654195976903165368080980453333586209422796732810483754553047184998404021081729036684221323332153456980356596", + "1178706127500211468915826537531411291222613868052077434626195967220248274587350188039053763043242459214820681453160", + "2383711806626563036331957911222152381559333951234855263575119195566034522156942669714031915866998192601159623536037", + "752700611470571177835822241519517323326080437301725055128756754661769301594469437532310749513656306555351273849272", + "2125371131461497658929593042407505926808355103329160419803824910556451072393678213635717670643739697853462715519892", + "1676352239589379608141122820380195100116005290835272747046011769775920487597635537959797835834427312554067166092503", + "1369031180583580096209343824676146479463586787769059375506539233019633086226636266015069402669695726367385470776070", + "971036088227834061959016798859884302340338723369101366785608739198756149450255640344883627543955635068882057416845", + "1620694445195382558379628321982482695566099989895023900295119038367350893890743252093013814723110870474367583658556", + "2419638487422238417876314490908325767811643523029910558785330240540503292840940377484113011688037814786277618354936", + "1262972594889378823120607890721003068631098801558315136923292374121497250279589299438165638545204514043827420406120", + "2397534345873949605320388201654701997514519113653212431950945835780759054780304515653838725217640583615981696870258", + "240819674346611585353409613415168894224709684794030610965462833609741204157607555188216037247352962276902344810107", + "1667255941536438610720991891036359912302724360100908577398705448729397524964848872616982418395544818028599670236750", + "731213880719293997542535926123542159704958680633680651945696998790711204396199773739019110980533903373480347129053", + "1319520020148012817175790671360115254446607817171934872053033446803695052959751709452651684300839834462880325719623", + "1289968941312336151599677497828314199460953092489323665597248251780500598588876170807752255581319330320682179332610", + "751858265099252538490690994168877793774833898608522930653043505450606099594829136977534513707267495211404595723923", + "2357275882487289573353882649226974682396564969269880914712761648711193841605501318727482525943512551655123399963249", + "1919355635926196023519211240067919352999051827438631932645958404648188827063391580208985381905153292309039111261073", + "252239499374732391089057153071048879735776373351466634079727971742188658679796789182877076214413842733913947557356", + "2411901929898190373098691165100598422811997245017433236760611294804680318822175317281432902603419664472063742282703", + "1908228080678919572136130747343840728761009109151065187684671077706549994792136781323667704653799402240985024507225", + "1929970027060086939537976899772195687171685880716775563938569213331532940347907112586911921112681014997238719534340", + "2421905922109231809436826825477194100994654876985064619062468199823880008498030110098411753913925473478239649024507", + "189378599124638390983542283432932662595801924830552173757706769869991209881135024809517097507202398021148833301620", + "1127961823756648927497130786529692734260574823804792161628662016762778659127805020451685354395079983261131164961051", + "830268686763930655029652863080381837539007180066755296868643686548355608844595013692476373261376785144864582837583", + "1120507501690185283637161890498761104727636169214402542180701942065338896148510631673251366197645167698343211555818", + "2008636251003028060982990195352865972253386028662750988794327677307215563171417971396904759220421690716132527919576", + "370502641715696303399475799137926338872980140632263195141212198069069074086923098049766074616451044407071686693032", + "1170917040011845125972878418249199921697011915334960621002250872728276790644752568827086212168597289562957380897299", + "2164259242501228948178519199289082604228755823447858652691738261297893819604454052962924708269072296878168109625650", + "499789953143504104407078976972497925298037567734398092704048026745652786607075633542506632762680990652625861749710", + "357231257916621671172390754159518482996335642237411832362500255659014041455361145509045359211680624800423628189170", + "441782097715818387098850599948260040096712107438922767559067669512569766322741433380833344813392206141275046081860", + "1095253819945611635630811893971379476071826172140313904088260108962187113501509800096751336812275824218752729609261", + "1241223790091286818474974508888071201297683680464319079356146317544856956742571104217875237483283457764425001538338", + "999572207792387404876894976670114186964796241837520982498000819897543233760379925504188853917694736275850117667765", + "454354020488290705012896970479514399762492929856021020379878566166400693166758412959723864628097500913965417737984", + "1837505186788367421400405063280923171901602986188609525710949774579495392007912560449479091071349385254775194708368", + "674779983143999688881174037262232445051071113941125162785992084983573020569742994901614893051064570260020475142715", + "660203335119958482985005497414684744940191245596910460415429804520366909892262016161446382020971860784649067312870", + "71893599932500866946249117263591076694054340441003105476829981607483140871298464053922044375169162479588774430712", + "2426082459124377365339717406178721994752884999372855199224823433902625965050708167726790819582622321579530361220766", + "2428853273655366762791146285155806926863871846014163395744852940603378994173532149964757309902118767420454555580080", + "1102941953124423155405409663932748066355183205108135112906631971431555438005416705228708849166701022095537220382282", + "846922029449978569030406109842472529555535544680376237017303967370814961532725918885040186961442937305877587734045", + "2168728598303084875703338396061065710700464869149488322444632490652416396557167653514492088240585439286850460953188", + "573846016667636747947227286719768280527059545274834773695935176538171790172977100222081821568195947047470106601038", + "2115665923283028359182445500154206782462375679144267020239849008956098935059121375947518136429383311570469381642241", + "1726459385122332688015786038013522802209622243111441846893443355740170935120342809093318039102828765116325280867861", + "253583640955828657059516077427814144628083705516009110520813707099985694501282462608098352181816610651303841521300", + "1261002971157442262640203741576671445454175726266077832304627619365745773185625959479497614164448489661442899463076", + "1249990933960536097877475930052786749315078502297471561137133888168444265422699065099687468681183304170723364133697", + "628184324801236798523761760690933170325409433262642162954876831555609508211726639991984406345347826979894612962734", + "1261781119949153012433956987962830747324310137389856101241248851478850514691194439208664197017060052790121552168497", + "2086768923136937657230476020374548578551770851192444372179078137055545370050752180527285871706511588720387453019210", + "1005280910982949934362574772858288886820145972816338682875873847346347759022387760752543774816287771320220750048104", + "2419373125390840221665783915748636973370849244589554595720567037343054587772580356452540368815437251008842905096609", + "1793147565260783882075274653041360399733484948198313690305925959873892551182838606139837786913432375636979644351886", + "2277194864765915759220738079010205996537773899835741184557999432121345569032990437634439369831642483035160334824362", + "189980709528448618002198156122772472326274777383630273203632355733010718575190571386903141895984798609356327820088", + "1220775738451542137308990852690607063330616245123995560662077626426397525907034342390041218460773444813368508072361", + "947965071915418668375652097730177449121141257503625262512509963063126641275981552814678752159297251329233302080987", + "322362751331706476231252744485216121920559767422439010650951204110106225228231213696076236110981104862493908507425", + "1775754940337198307308919193649690232051726927954976204177405750905010192540505669413552226263584653942428462462810", + "810348610680961991236597958338520161072012161007412641641825126836620150937537007500792161575475300614171275557587", + "297759437444177389689714974154013538066513746810883163565439754112487557708422459879880627399516747937993010545190", + "235129789362052722357424451421960352575367872774045993195523468505602624101429569220639429210955950408293728364805", + "851660350790446630533176017754800301287682415991532520969635686308195862852480969052492663623216564173943023191469", + "544570955406381653697157613684955951861977394138178036196429458854537933338628968049010572601104681756253347770097", + "339890509957777595350993543520809237939200533494304325358290130162461528786482336145062415423468270857002971680787", + "1484069551882036552578190179533218778160495863806487872062289808992277826429801403886748243758947905756491477784293", + "2271894572053135238261069309502094942135951254794452676183051559598773625407254611995190369411224530628498938607435", + "327988978764114273788427476059424732965962040495949174522708646860635950938585239361753989562526617266710772372982", + "1341341285377330580473327767806853629368653663056975466764886357729921190679417065895700778834709515638520680751362", + "1861460235353181486245723680187394300620279663055792912058946394611112014030794806468176242855916125556006885621253", + "300219604931377269751344496332536027977390847359608377925863990693843012400379090924399610862021671125144485826961", + "1920098584880799326787233368350904594402779067749924269036327664330267940184799910583059823290323964935208712096627", + "939052986566885582065734339828701066404768835972237336577521779479416767254436990415341062348840827913220241927509", + "999020054837514367337639379939876187424185803768662540183342876282939336184530305590434057661680055989900912169385", + "2002898114336857310386082683973313418842208688192445315199536810349510848511760382088903071206002425147263150102872", + "1073509713992802373863900275253978397482296838876581319745953043033382686757111260077165119022801247666417888509592", + "2447470606028510519158208984755917197031713831502338926193613789501260599895693154764318968703636348290201142691602", + "1383923273139672628071551609336988575055454998141277540904102378453345549668106208446368518424291768803007571960940", + "206916461628250624804729256863748962610374989888186398620437646535207007292030437928037614896967834948915661371272", + "351929580032161529483907356698412441048229215265996040908293513271441074989962286132132889495082759976857414700911", + "1921227126633376329663183640101642044551081141048479114652701003292972546984552393887131888124159551864223672130379", + "1759375981147029838065462898595592111241239862893188283393530677746069539842310012813640417310701947843977152135120", + "265308808124660273754688197793117891991456889487127807867419898218092095620975394641395970813593012634223176921847", + "1454012412630567976322211710949575661431202301464381434381338420522983125434371189370084973316819979846035383637269", + "1494795959706744274262381940132805023719225272129316333506097220927290780205496172043932368567151781077889462660637", + "357543665724295576876080995057518254626802472272288741308771228809103651066965277109573941010277512514339630733760", + "1089473576094585791947450277308918670396129296405098815947514711726440285633712667757442971381789943588359579809607", + "358924681860258042545951461330720665192360508266174411800369509078669691353348259224859774477976037196558518555897", + "1371320694561914544618561283784447524300407624947606215382367546204585371154505175404121566733476742054959571052511", + "923371065369933366633078987636660563541675054185812869361588475118598423971063258919669661744144730667620962652647", + "2054425850877124048626450159922653798368662335265223112129059736110284155966975996983028280306334735172743498160509", + "29514109798729675502616144142465608767968434133916868536389905847990637549082684426616298192445402576899701308408", + "2367586904517360078695013730307584743702508235230779833572795691365806223610675585588210481991955580760774042816038", + "1530678304463719167237472104081293738315211499377900830427696904169966302612959390724837054138436056124901800846894", + "1170193351585868300132488291537589525385248853288943198878597421201986048915115732539020667903245734433301538785447", + "484749350642654612718608908942388899384526201236425378130472878139100762493924633233194482053393161410593623315954", + "1027229413924682108346908068227594622119913991607664227196253391460104271906799419706188013566371415032879458283495", + "1016916120876036276384374047638853146873492070818124148205135654916378513489969166470122299140444301320113679423348", + "1819405565614776767498986743597472533339729250079242178499685004721970017115401537540821710665335330336877383625891", + "2086576553454140823735210299050475864570732377023033819977499994541767563042842886394371053683822762133730132663370", + "1454702899381034330792628419052438243698941856934084180248109006299448821935999535695798399010939087160531483271060", + "2125757789338025693102471323945844759271962467793493950695403468005820356932015189686046535894167957561727298106316", + "2043533276092597018314869736920355468903332497576628679647827385996465829520773145240042108709690165228177308867153", + "316107500084757911510368486967702442244984591208071589392852568363781516617431305364267541874834013508173119804745", + "131542850142655502842704487370862980564217694216670152345628174682599863364819110012262521020503477890206827442534", + "1255035312796174514278031811443112262425912037344014580714584260373893791572358852288737758349146351473496553751454", + "1878895351830318100463081966434895206403422071094215481516790255205239687572902163155345413794033908090319369171209", + "553489950770845048144126607146352878820668742276298552786230069952986648361395325964996910247791765526979045178883", + "410574860440685649026916860718136820910075482033916743301605360001445924082057466948271312406308841505169692281033", + "863201751540753687597910207103157241101050483912987519178736432244985570674642356292297129035839019658081233037894", + "224010814529109057153616499358416355947035873606689541766953623141771475142643080908588384270929067973424580679350", + "650175906600829895319376363315561457911525479950415916913046497802493117016856711642169664038061415087886189927460", + "1343731319490509354411638416057403100288213394828842605326143151560271030214380458491075222649637511825637287610089", + "2458463782108209385525197886048890851110998970029196403590388574056705776132340222625722390721495115412605961770770", + "685678949381912326173953644018349846755063079821231838054900752453130070238838242370181327655293631106060522414237", + "2049312903233530823574191302207290784207625253629365767614429894976287224996193805353970925264969644378976721962016", + "569332427600262632203975443464091036352888333385132326993156282363188907150195240483215123183655233966729415907666", + "2105231350511953932910614464205257682503735381336067670547590720007420762120486082014366686842051626678128773486211", + "806902282564919221975061760046047942160711488180922726216772316457139634811169690642499144894397400879839562963087", + "6561708444590710339138428687034975726831537700214160685640183076342301814652241134515449102865162320849235593299", + "795566817448184265651098667472797594328807592217040983812707953156252727894720604995656660601405242310926343720385", + "1452934065667724519112890014061769264774925060189448133367479028335929757041154847246902989138974259115540989913872", + "2319639915929409783692431115409361052877801680835265769439704501737444292398484094251674390763742611949486790446350", + "972402003575569652374813518049268508672856977872911507245503174482214700113147228009345379808713538983670420591883", + "16032292658048318291588826716213835933424180613425176092197282147404380218766899140760727615397401830350616816069", + "1093057193276297215085394066026206849316471165362900904977424043070282598118744402643154308698654957442177583158770", + "1318586855318788899518055438670635479380027728323696619795647964973290186121239027434677486695258914999541679086496", + "1507272062745034914244429764580001585290455194678099377445541599339618730797963000509110524087090611596141560602413", + "489900680023525957356874700598089595832577860504782202585972802451751034598021949975994036946070423146931540363495", + "1439711011000598706353324355444321247893700125758145351473902007902354662682878021670515615613394194687996114436837", + "769524047150711914579631269031051018008766694304459046698897853902245180911888598055313877365706196949172497015395", + "1616852176546905743850557915955848704785277734473775478694791316043444581768329140710941542009984925844184623836246", + "601104684165432949258988735016696747149743970283066475136194726036478481116677929882755803728372102254675686176706", + "639125306223768620155462341711512774075006974714388942287411264398677576018621511323404613036422285245974228563929", + "975556583226104796619630089932450276314261299352451378760867542344021138218002045053055261616512254773678683141608", + "295894327575049067605928056937501814002943030523468056595422466679615119041919369874930809474765209655874263389699", + "1199896243855495804677016528098623622064284752404147063297554497351102931228010732473758544024399066205020883887993", + "1996262482331613090463889357152778894791390541232146027919680454228375535577880580034667879816040215083647116223511", + "733265638721168089825974526897593343117662690578623763366674290088287337498685319839944656631275047860778953830839", + "1121814830513158306992754914011826877243562160931690567018123341796722519882900881072558367868561618074463521398127", + "651129285297568500791433580236052801459018287848281384184002854019389121335936786808657834822622522555131084139684", + "960374490821968008230506781675176237941703489174371295827792978325221628149226411473551665593855695163695386468042", + "950898189509519036245562408574280922608013121468540878224951687057047755907380177093329221185949165407437703935582", + "823064357042875114434478149088977122743195585774410067894463361656252636056920569037043725255250204389751450702337", + "2223100813428676378103404232984692108922032210996133175998693619126827034354539769762022857165742359258910513445080", + "1097221918265313684103500974395346110962424250706774930417516963953032605176450336006627758020475648066318984707297", + "2445788719882050847647462539323777431823443009675505424531183057378796916814549371295410652375979139755236376319008", + "1930382777239700839697692511346162381734586790458000124825676034769872801539365949336626713916841529448078033912390", + "1864766843912354994146516435080630319164180097865553750543400736646116386366093555016298273026371076985094390407842", + "1138778423557993495538325818585950419623607881551447648136214987465008755159119542390284316966209979259279933834075", + "29855787922061646730303706860926332023349365310994299031382579577344369937720595287421316191670766194662190193667", + "2171751381197968057725285258302836994967465832176877948799051975854867591405676119336032644925277401717096817523378", + "1020955470020271213797379908924447344267317417459627408669573357881057512756899317446260112806851542953778460125579", + "1642649208982797342688390824502115708134538428808567062555892958033976262696022319278841384152275838456779044842533", + "1354407220080062464773540561414059213314300028203018178954485802511272014504050319644312957173139651980209245833327", + "2258361462077462199799239315789075615505847030338536492080796972840216061013708020576584519328038016050541146767083", + "342603217172607403522130872981902002223120604760060879265263740586657260891693688754220027170505305026612493819017", + "2291237150352038764863181316812242090880417118835229173482690031516935364572530877458214299494787587571923139110159", + "399931965007710033991556879523704420707123208424168657428658928212065855721749824148597993013575590766733065370583", + "125587148491889835654882769910494954905180225131549434044524552357242386501888539025769653238189444606817365218012", + "1939861343971476973447558624683362976645851333264701753484594356146644929126936206024845006407023390661595588027614", + "2008465252772679944441413732269727958557766383252418506029421018325827827167448603831548753377422164995026200230046", + "2334250292669942828435346115992306565762102903421025129997237014400568484183088570891488318021858885404291609549565", + "1807426040869180047829152549897940271573684396081872321131820860510482917679943962712644420929623595040449650750290", + "368605312293415718784513203720126369138368008110248321606104753759491034182694461915333289672548048968721056893464", + "1937817102614222826666263127440810596355233985545622215080659005497038985702590095152295342900914371431783826385019", + "1705238691004479045244512995158658739407366758038285463414456776904510649975943639659874495527091871690689132520378", + "112122842765710511401252625029170798936884009202931976754685963104032876533732668297071554787833581038853260773387", + "385752886150286213792767618792969714664647730451887419016416399117974423405299480050266661785586923577188305700504", + "819694622988788229313770291319897282283664401987822594883852644263999518787366405666414931437926596680674692277769", + "346998172770746308801933276615083070403083625708154705356401417595599535103971712831105628308423002381884836715231", + "1036036813655328774950326879286855663626789003512134574201720126026034709427843401910697884624690214701269043715517", + "408525819554721399578524261363598148842889289130635183674224285882329032231210650899970464902795319101763111881898", + "1014546133417555575623225921745066362920998968760964233902682461125676904812280014912086186875369467380766550145275", + "1359221153942686185331087360871398808949557625688972963489512460642841027288884004334459131518385484657688212830778", + "942199226615333638029974655822020621387281021441840896320190129967473754156585162626951594427341778797417022728015", + "71957144648603482222151529721767032641938175141744926511779053770435400382272661335903158794602046106360944256757", + "1050217910922940642300245863943732747885881717761211922504829874715693885854880781109094454959265813461575373585141", + "1702075435984048547252087937041118045841525516856449711878584435609433679525047262753338018077271181510985835386399", + "1643847170070654559540992808741443881080254349991503582373829025608404221864381347590794342734300067164767501360259", + "135707527602848390311211215788027279165861576630060824869750139782609308568783533495939659328199588525423422861554", + "1733191384117077209564933634877135596691968545938430776488614803737230738279297014673013983879143807874658857358432", + "971076749535603528713513625272568241088473793728464021587114114328537572340623525184880662494028954984771117381296", + "1675992496871216698796637064546308432381745939617214905382088722359933907310665683802052744665257360391255289383623", + "1150812806136576234873026425894409132543659532185885443599249671891807202908888256377486589632357418773587498350735", + "2025165674222189930047636809193184723632232920574307800050443002240804074000026134151527154096074512507973074668858", + "1323912425260396843618470998043740728419049882013258787007571040558712939764879086272017560660212131590598799032923", + "487681874835589457282949164069473026008946239937169991706222094408972080561068853912543894312669103788120715706706", + "716208706275508729700222355690888714780073833579687680016412642330872023717956676927993180965134997858699168263979", + "604129702314122692245287686548769131300101522945189684340677150694545212173154671013153951030412160345129018971160", + "234252485519602211260955754756455668034355526947000816102177783827585586922727485010599812012356335520563993824363", + "317605512037550230993733101289836258256662650920100307509439029372204539496205744882327109626526778088593550654046", + "249899590865478084100545149021869408252819824139949181529459341873704273164247423081161498352435672419018550541352", + "2082607882774906231860821152615438040451806106232053913930134404219591648860106114559685772631569419576332596931145", + "352139350376815562033222214816318012102024202528298111896820355182221088057614477681760729691806177807242203840936", + "533321640596295135650173491089075635398311599208844147126500972776708611343271721058913616411533606960727000694901", + "387724027519266975326695010124860519711149117640723575909155709337744447975190893387663910625408188713757514847626", + "1177582848033030469947922777717995465952829608150157749474834465268803327724625311202004636234610508547474921869096", + "1210755952183619342240631944557873270557451631757104511651916940472873761218338048961843864799051417706759354626428", + "982403714775048121862850183437420739099017593108754093100062350097549023476541430909227007471512956210953935609205", + "977878617060124768751770852343179383279428981549934585672057385790863473473399548689657357627029851857337980646646", + "1140954934652580107626308417710086102269342520774180966876037008118872853174210920221030462760398093412484464835371", + "332944425867253818867209165481612234531546233547484051391164822779321077267894361551254793564614503870558895985745", + "654615463717340421925962931137967199282044375780755795113718479561328931537839018581614497405623063861066673906943", + "1421477767889667857689580855210127049926161778520668642830590295598022533455530137527888661504674366069921633154578", + "1062134966229016428466813123295344654155587913475497533115253245872442482870703524001011621114419605128555783401489", + "830678324511180096812416996865341567152681197279633961139812602161196086550858101567722844169431915861212874404420", + "1864243123338266761560923357736329606566423402119338200012832179314596692330426201791076847250798540104331489617194", + "1211772423913807137294277606470319003769532759462638921277802798046063833217673624985802789428002786285460671828366", + "1918852210613390338590134661536902066452008159165408480682683722613072831382878836805443760482245597735952943242864", + "555599420154555501970078883263794186774725568078379049002452104901978234520497019571202719888723578613492062135732", + "617249424008059310164323703154226470882944444763781930812563863196464902293221244089573911731989822201990010241133", + "249216515232769672766954347684038874897508464209587280380105970337839991048331170490309345187040722533156361598518", + "2227696115091970022800445136818127081589524187585452160208230134931994760814123561814148395552081192411646395560334", + "1785575935740269666051855308374264654487277741860902885198249859193003546313186047292977330092990996440711278120971", + "1384296655581663355731666803391650158911095000614364799797217805943571952672443168096557435212116165601287772679590", + "2052491234130582441049454126504024594632622297337235140399822203655216960246331288884622312016787952226714425703064", + "1366285951757840217160443807783054510339908287605525597654698181525559852859090686338943046840212945112473432619644", + "361314916408516694217033961176921327475106526624633639686605820545317568852616938878170413788535975372432274925430", + "245341282507493694808363414378377123052602941724260733292904918767464886093465049173072936182869254296214390292063", + "420335189217495248886096173809542343369716467495640180241903546489715001046725369068707578512895501686692356629822", + "735970799561515184418797478106754492621346191291185204734644186357245576232084458826410975671351254851243215805807", + "1599930549321044666071797678198790152522061996005736513696149221281172828444612272388017971004283017517625119258181", + "1632641778209093771946726051688327743928084908504069887729040861257004301631982978141779425232686006429413518530478", + "2292387345500631944467658182940806701136064930454775802159944481282796446507133563763166833399563538724201659475904", + "2215302318473729329616345221746528050107397608957730801767992074137242683162844402973837513620368048392034695532308", + "2315881445424519346573977782383393523333095301048169772100790421988191453933497446503530419776942067561134868662436", + "809885166633017463003416477100297149054502395659081611037029867827173874998747058393298205847465906454424350275133", + "1875449608158084824700011330581726709688288407376398326629058428037881790112246187502548794682144557681603406323278", + "1544203295429589947047708303828741789987686316071679065894912038561711409251116951566214049796759928270024236422643", + "1187399190006739475703137747059635743933043161916425462116947811072707605025829101354189786672241584210764179193514", + "1161677527916444932825332661613402661952710503743495954761696992568375352287477113815028454580576540011280117145015", + "1109966584290006563306536495376692752234260648203052187052498415174423988785183505071598815951427376159477292226469", + "1178522324160650107493643213430464062492312622739853806102584226748062858878137308034066755514054420174836533913167", + "783809182122958797807875478082863708838931007383487107083271446160652626950229806327350039127430854042823454842559", + "845511700803720716924139476133737436912176384226348153599301605489423661399245056628083105301854730415069043294398", + "2218354384976775401986775635305993305637560846004739485214796298581380531192861694079185011846200599779016010312910", + "1631858359889757418580190138171798175580223941138677717556603415905022487892866363737638650133129958241148862916015", + "117646587282770650841367409225135872302758777415864367829700838425944648737293483853886635337407741162093256312152", + "623607652992534748995048051661418584061208639754899303294988638873784335470252267673768093188812993163407137852431", + "2351329225105794428739905195425569351402176500314158846503759587778083787365680138631429147267338505402293303489894", + "930573863637322034478101289277819432105138806280824201162659017709000486042449443492991685075039222783358740355781", + "1697026148074926754579100562946357046191780265831523580749901456922522016714263173941879907601170406358648417112637", + "1332929643236227081775795838542537972824759324159349373004566715483307346163587024685799084814823751189808637327415", + "2202126961999260882499529804267903810243560344485233248896954319882496245509299996097322122385657878221985470861177", + "2182213797179082180052479635299316946707392339806411592155441076535611579513910058218341916565355425267610541494308", + "1811313464698762639222307187538310875131291413885520124839650697319901316355849865453187424867086450515524646523820", + "1337424050537958469396572696672292581517861297985204112894553070112086274893216535712682714009969027030566148552774", + "813826590581380897238221792511377441472423879726557873050568937049801689843221055146720349470796646862987364779446", + "2334570323614829270204761159680760943321063849768238578562482315285893466371073769674829258566242266206224883277648", + "53770484129669886977901665536330974030610970835006283397230404305007180918408316255458294705708564219267970992443", + "141706107514102902233054682989390303006547073665999513300976650214888894948701927368567778253675667731071093336918", + "793834539393565271202216576375001312549333051570861363078840412626820551493343798448902484311381618693630788978785", + "1561284852386860316061131432352723031709440812242800946918320401942559029536098710544980357198093530568178112319209", + "1720743791958035468433023221769048231770052495178748277964787948046232578107288173176068164947162357739129519373493", + "1502995323439702464816081651803005498149197401477691149888192986797747826310437336458291226194986523920691380538432", + "963682346029095987871413529710581868065059048763406563047065077756780793356338278685105822882964663263553278154387", + "953822404805689288842096803615518490861069572214905582525038975526476619057244970890808019959936319697108346735432", + "1603342408435151237763355953722883620013979911546605444408793408017418632804907990504777189984342872515076220430869", + "581847320816156949965681072842594776419744392862257121236006013478011595674185474229666338097723683749523723482027", + "2114041977242734292361656655833923879469660777043791787798213460236080758896962846088983466925571457317878562755110", + "342512389616829331177727878003557422250141528304133419533413723114157354948797590423561619846616362477088101527085", + "1117034416976971887840968848802197790268735686352610626801714060814830834129106563613183987858895578139609304881276", + "2261692660079804955455638546916996346485849536513490200276568776869907851429295693953975185712580763395120816305854", + "76318401291933054612780334837474147345669774028419219746509466354319251824477505894470194397737757058562410899698", + "2102353358404230106229879660121254629263479763849114999071222678718721824682303371151958441396468548425113080530125", + "2257095751458150385650594201930578791078411415329274238480034412041940906480295707252272216960729166267487409041338", + "1349473983170129280905413008163691385838503167659065225782580649672690022441609971443681288539451862015587290411939", + "366945195444548048119767624411404140866591902851780566859289172197412973487075690407267056492480423355229124727179", + "2412102796207578768729891604669567664424222831411115195989361775512434831182954921069987285039536742712568412409166", + "881125649070528760009786044137666524387146633628867096562540459291666691686099055031845386759189992064646348970802", + "2257538066527488629089203838218779309919263061105710040763717282512500231587308633492662572297136485462194696722177", + "1825157904895425254740972142668321576279986977253958413790586871439471653222680683086316973552188204629157719261139", + "2242532615139300085589056685921943290818976472841539279097912173423697044983481772068967782057340735437041411238887", + "1211889476577270008910856940961799554326807240053026985774188385385911901848482642370260482766893336029347104199354", + "1213268444252310279298455564750311310368800562871269685317220907919584024244094320242222191409972726982532750617079", + "1228751977219501775565136722745561434670362142123077233312336866139220495704661245062892227140711969293323900809538", + "273903777384507351075694578897916255074583067728234733425304140172573538583142656234272310360468518543081318146278", + "1958141638975461967254299247437731763918897612057096798747532759361946913598723406974530756078741533354091257254672", + "1157138726603026866578975411994925047483110829650066007791350270548085923303232231561603817200551810821216429845346", + "592602565272015767631233514849622564141830611089126182021765465355963139099810862822809860411309450223810356030356", + "2398102632873258377588228201209943850372027418544823641209836788962357466358904757806858714278497965988853927352540", + "944964300560223114949472177664625833008071518448317119574413436497483378863501998939821881908890807293163400502335", + "394576182886225670699473081903136906042542338274626204432172619339976766652859919847014322984956580124899162463509", + "485290723034181329392088169998486936528691442696310755594261914475856461727169252078616625450338331416171643922632", + "650536253500711659037007134862354666353624875816231279507207372758378232199813016082594190999125417152920708646287", + "1164409259202226824245724370457711242499383942778386986296660522209494900004838154575516851220077106359430000945964", + "857047778305144492805025767694204978048634720951045599441712568390317807824384412130682785624561684678384263766261", + "1800654697374632004356267641990049887153421580935374519606945385342185077255176953178867932749756082595426116075419", + "2138987652783739000992156870186987319097722793709373094347863884069412371551771069602068716978062798640390222722097", + "1789572238003194864075615589452256007731659824584779097297485399525573367189981170581609881465148409340500143990626", + "1983652187904057353684492435554876132383482093138238435125408278248312860088331045215345064419980839365471533447700", + "152520884469881587708709140651015839402663321017394669912881562273152342315348487405174450112177126642411695521430", + "442507691725985779958125385691843014647369752819986969774267249651614423758582903209499785697958799255413655650547", + "2219452590376543233360412606768868571484333998583517166254064671167264428583626418065963407148906817578289163037279", + "2214960596985455872704882928496866693790183898581061376197022715593693431170831817978636044288313911713986111075071", + "43032905399244269537243363583507222222682115990298166813800955124944917873567565918280651522899913740590023566234", + "612982287756702769776110012439321632245255199423516645455425178706144129791709271782210980211767247474778596658137", + "1317895634414207758467326910932396034452182113558337992593290236430837602792239479588440368357690499909977320931262", + "2422241634321772287318748556149349210369707357870089085029411026189829520555983735265033469175108830130010981437705", + "805467636743349002175022630152055189693448712509673478578175846302403760102109047356937432489825944661206492946907", + "2253822172794489089634991967269725001623964165384784888437746800527575442651090329900067299063088057832587281661315", + "1221333352101881517188529058034166553812077387822038757761061873743466010969260093225909308469251667666620294248982", + "957806284226854502815679413385753331023784951011207453470864772646148120070958219071052891728496602659411776253655", + "687317791660528555040909583302432002196582137950151104904533564931899752343782954780201729991133986058895174751743", + "2085260908942044306601100230339590693083931022780974716046049442768340281238677778180641353107261224830386361132641", + "257695409270174298281281334344936398163192765590405248645488030450097732712770494565415115885523072645713154296168", + "1463330018299945661578718635861625930676122656955359425623011811710198628541946044068899477483602426558366532778566", + "1860015868272849419830447898905054763819081317002328871237584708845447541302947969479749537009298667893653076661169", + "637162497270380695982549578159039297321753183466685713912804423877528623442157703380289123809268261309837973908823", + "1023447100460512981619533848798959021602037768142001194334705371202007592505374856916317633620565537850073029608920", + "578613052045810655741632009585258329323850869009723365069137953329768022020586842404358087920064087149597738721171", + "898796262917499458954284529797529426881376297117082420190206719663251573714708734649261255937947007338549997663808", + "1742697783448218811428005760293152140523705774808603364191088193626924439874241846941848255587479199440161928584991", + "1343682285849752731025676356159983477465597382612866078757647933221723552828728900247951006162381175459173750332626", + "2001308667518198544475910704072043580823229503570860812300906134198108809663766461279078942415827618053371557151722", + "499893347240266147093926271479587729919133487551475352385687503989313655498538575916403998550130950408101711382974", + "2310976186521184241564491859981779756915062050942172824860302034626260754599256347577553800742731932388130687542378", + "1288571739439265552877928826487380770994919348870665250875532779563258624453457938431808481461537355828192674760440", + "5282328997172398575552448443591107235337725108798977712932597957832745489875867899194449786306086819265868768097", + "958127441853976494188967421047353342082288996122854477052650105230544290349013882217492012073906060145315887299516", + "1278004323533319401411252385352581311089029869370451137436237687106729838883946799606882886384097245567415644149527", + "1033311435029124198690271415622259050815670342655035275400623545537488090522716613501752059632122232402228203630153", + "1898347977268631809657060848155711849769233513926059791913812506365957006789549931144139199616353384924821796764050", + "718740087904531263497341601903140113065607095460653172854867158276480791045102861727349803813450091518214013633934", + "1226644195136086315605148733861686663952101112006593412683477216901113436648492959208357244144535722548198280920054", + "208756064156992880730784197270850344228209920873151385821781242741636621627126480757054529721539632414739772138669", + "1878551453005349762732942717833000975027195677563151002453462736035727224033837563343634698171684798635475400555632", + "1354395401562592855039782496037814053145825250861117690007535531465137060643824018694068529057710044117367040312067", + "1588709651016660545211979177534184955044609843907010274497327245806055208859624759471859534428720255652878886740168", + "1871535552626902179855248663945702358417202070047311918573721146541901983592061036610125489870037239966023755281412", + "776987293721826669758744681297930981084943248296000364082449780073604822487599248092780190537127971333621199525258", + "1359481181964669011285679589401409682526937205509964827719633376967015992381375499052806501393238469653929086362837", + "1533174491193324260906770997163077744967417785236186872977889928945627295244940275310350083378600661113066972453576", + "105024996996534154027994073567359680997602443755566011938449606476100649086732307290671549404646739155230136737958", + "526349652970090370238414061330598174748959129668090234104163100780033278402511674043169389763842905103018027906992", + "2153163475591963485414529915405820271943579053712888129544105955177508321979560974243344763596002027655143730828966", + "1316781913635189227303765482024331893510204353421117420086765976260351068817985283365551177302655851826779531369156", + "340722684011143292882934203593621690011483744881833425271476475566932837511519249900622888039877361838191939508300", + "2459385827650691611577439368848963867726658926321382617758494525680285123834863833083873103104895463992093069022027", + "930392906776128548427547632896483925115810939547573203091501371870084624328311806298919505562687995324610938819619", + "678359937471536213277354023718460193586347678162558991257241335052962366857221036445196397333844297565578915308873", + "814041096035743347842261770313675763103552430371893733896540741000179539993789519751064749749971877830213670053221", + "2012312215270452305749922438978641421988701031759096708205851839440492468414620165038540600710483811966822831690579", + "1658338103374792248936288609808578182802334280535645982847394791253167065374255711242442973736034292716921226597476", + "2067824726136422424207145552800641155857966837729513861588204652368915764030680357158241671895341501811039094527725", + "2301975804912122236377174133099444453947684468135061984907132951686343625158079290070091800593433397521218056703709", + "1642068025254804818762757940650106199601126324898127364556125484149025367240060913236912631159438618718977699144482", + "1444104799340955643698687997700334466508014626698652946675415971553509035930081340549427993025271443372952850110894", + "750245042974230657822075396070285655910856429262000349203267632781884828242568172227407290438675939220059260017840", + "972926764223427415861872246449813804922491663770700917459876471190436978090650611830839360558637874939392110375938", + "2440844156173970599438914746176426845264522090741275396085733805001906625100640139291356591569469649491866854326992", + "822012214062659410381543209491338810833207734982047674511796583057400416101815493794280095168087611310942011586016", + "1803473073685451564293243560141317056356645011482899528537049546455712597155032140566642899840311417527957527910315", + "2194433091848025497358083266635690319043699929401317631503381903528928388648868120645118383203000669955171367086438", + "1938163834360181972890282239016946169316158554475698570983471596027783998167730968865530951211845315014150854948448", + "1040827130383559005045638826489522593354740403121262395034802987261629977962701145331104618244636066216745118251827", + "2314570357298274990949498294788340345527082608455733153855851933789415615234413504294872339322534235148850694731586", + "2122541603233171231014415122332962737572492731875532368523576078374625263018698414984582628057075397776527133502599", + "1391593361544240470229239699914256554068943608183528295024376490033215578375984090519451854138039463469352035481798", + "580790271994930390947309705100629907393133552057872181385376052971157065619950618007278183478631593727792632880406", + "2390014953061795295167387124930559398666794180139433959185696734879002643652009065108493385957080014776289098431930", + "123000486980331973802520184801616263885554353800992193276824950372401165595583885000622751485089094856939413216535", + "924475766910547764513229265146816520781565711732836336483725851876365494395581080100329878022975506915878955717827", + "1967913490656406024384031168971071765636571602071141258545975581241637032374610115166910658498472105582703762596945", + "1015317242263143987858953219994030568590823457105356270830010327315759559424080882634787727236831298661631742402963", + "110254363645975614861248110848421615757070786472545347290050507004357947207759864958109237352217160993520323013496", + "127175818803272592122016952331301576786016831823963929334622430151783064100584636449291368730008917691770355558789", + "1668522978885316278710106836866070858399999233011926708143478822975625178984465846359641164898258358655422441388371", + "1049921684816342684526344367994633599103551497163052811944531614237063491388283301711688052909115861162008455702326", + "760298233708504993642841653183434151778381435253536114850535045407992611298239264824981171075047960337304453066900", + "1221793346313788709974128336988758189013509364595860740064453002468153601122484598096857943869692997406100892718343", + "1467870550544712612567832750961664664215804207145234169132339459565851208125583816602475568095491367913654312339982", + "1704557742691587020155425612957168994737589833764564994361214169794724176685488597038249215192397068398895159220303", + "1677546932008035628881641793933870495124332093385745562641711680015071915647890963149421867347404989318612455401545", + "1313296267482866161533817084863748721529228311538604746437390563278432540160936434416203107143377759586677994570560", + "2023700381975763008246043440558033923003458970683530225406565359516461878037239274521356639195335115400926063483157", + "655024620057782589768422158793908365492139339889583541474222689530634723703875780444405753960942296493190827420240", + "1998519003855397548312788391317765149259992318807287943032147916427465029251724219038711883113349887097885172450332", + "181957974548022360096123861145287750447553748984918823386087989094356419682833111381256478278646202553357746878413", + "2249374141117551597743433554042623373006187188645976308126456944332700947216618175342123142606445761204826938445122", + "1359270748942229680512510177329662138099627696736092333008955428052978450114229207907510133798000069720464390874639", + "1553709467133736279852601837872739595147350046955170440821062402176095354106461995319898718793056839889073086423018", + "1094499707922649299951254616843041351480459989368044855775857104403465647830640690456341328513594903181976143302030", + "824793495507392030797947623279274999906862896371286895109401752879075472661840880021708612280032076975307518216833", + "1710943098736233659450824708929643858225771154552596762541407885293022318930674447669217757073999103249952454249815", + "1344114426479874908038893380832348347243593309684380214967986817591789118536739135831315448667277049718340181661226", + "1406075685800722633723417121710993387410699546261404033837134884331208633099660900120362199121707569832454197515471", + "983267853800826817059465588862870882433490585248590530906693564782421601567301905426813729431125940262809552618410", + "1189086447619797586572542512627153056875473554000177674957344659037707036641231669415267140206466396344205583853311", + "440511129156357298306610429877819595075068374264929094833833437661110322107865512005161762488772646607148835865060", + "851781731801332424022899328118668465886703715853897380850679733710732879254651213200174530741677453743406987936316", + "1120174577591446647329521984932443957636254647725669935392009384999799850896569381145037126530214608643747208482175", + "2002666721919799719120298871805162912683594917185400605395318617657890082477881390177515574627439939198901062312691", + "1630174025009232630608562485840813702685301608111705219493479075138220911285988523441199362089217921964211322977205", + "703342821122425447990251580370427804735826043969844727058746621746477264799474259355273601224779831734950484985276", + "555057179636033317183981721667829936751177983496038133132206096175438012510088148778278693546586835957478850335081", + "257985453088906276658309610797929714819312226684610640547011503065891002835712730145243988524879397507514266130522", + "2453922615451323952015480732928889279585224839377387972702207365458926539833306682164271372172056109671306609653788", + "441863772998765971976834819025382332738473798674648048792175214233332814494198365704638761135541510922762731155133", + "2072632890560780060884660100416960656646876801001212211888252993347713184412169180701833938114933351491237958433720", + "476821613801378549251134441821880536509089678632056472568486032072104686775168901773215827850863968156443897952596", + "1452548891764958849194392120260070210150770583043478990647554005306379708921497991115152590761165730753923851691680", + "893634667206669122172435719423941548241632252236428396809597391959649587278635751888401764073065225646874932536236", + "1049875655174797900977456602579268376182290824940249732988365349751912796832340708806936246121802491507867714622491", + "900821339470351924759585204071145620275637151642154740071875249011187969109727487367128904218352292101348366692737", + "2272195877927078623473417321520821174614107810078164579689299051388287010932159832314866490666203137043396571022366", + "187017127857843675200109027209658046476927329215273322079541495131049168656384156168815048434657072511536409050491", + "649442436381613612009178624768506208270438567415773763120548078080620561137861592266012776380196437730296117759905", + "777087973022978827446918922216455345744861733028036167057802056326000135798712130239309060343789983116164175741476", + "2399178295444661578596339129800471475104358391462755703066269313157478941946836418295934325391572683364418063080010", + "1415569011644980865450007256778093983353337083041388618428645357513455517605222901796195234624851170810199286477422", + "611719656190910200950007960819393148810503175879945104805184344306972962084516804141133921628039893087430182891073", + "2094774398283063457060966004433896544465312528675786528324878330553867711650874749224453268626816189449895089860182", + "755783497868247388941307656765298286799419063254874442378563808001706635361992272197904556225804298525660401366786", + "1576104363935697702508221013411867051551804820813460552984357329018998535891773960855439714799178660815860562963775", + "2372828226585318517194164432977238901954731366427363154753323451787543561868767656145308595932974058541286469923146", + "1526825736174294919736389018779462885499588850063468737249649970888931526055890394397328928473041741223927691374768", + "971583594846500241585129751766540900300207586405208804426844965476696844683040035155944426722737634552696195400769", + "112841234344186349817935231308889065894177450020653855258443286855222728827501148734867388499282069497583058340785", + "1380908052960902624684482123532455803818716749870225472653548252398388363454636836171270921156802153804167370919044", + "1930952024863374179334544405876674944403343870797164027249377105131760072125214436054289976107451368581287958181335", + "1550103114580924512453780178097677115811353040800695872931783841521295072143732850189527488557971674724978962777010", + "134047389411876792299128305157828330405711240744514725673216621950503964571942705843762419628047107014964534149044", + "2034168721680338433071972385237125419094603811403982842566549920823436445546101960540310906941390820186283821512208", + "2210949680638322626701098703249628537622677174542329240420924560882522542221658745543949518814730560662628100263352", + "2132300485862469456297288689252457729498345462677806900202706207922393115850457129211821115170477002103420257944968", + "1623612483045348234885507767559630102444959906738860144888307381348749159314639400758535927012205893763214922887187", + "2225315042994777585082087292583088809127100902039515749636704504074861524729735631845596829763650569876519336540735", + "2038790171051998706954816332948817379081630098867785474713496773070318151663450539169414623904151618488751899146590", + "191321704424091547090135270036882233666903590299625324732663671361389040336144688308600376386927825960253641943607", + "630836799551398897729078840470917258117456849922572508557635301995677565338134603984128345927909978550987466305103", + "740129892057966053844030479496069885757204595052044279276700217153803183737543735505290809352198829598628153402200", + "2100523980217611531642012865712473868031771295274125020651137005201318679131330294223893538033570885023215969433475", + "2310544671947183147004668865357290890158406154637890874571300060125356114415771570631041161503238528332614740793660", + "211300959742704400755680203129843735543999257477515589068541904412137910979147569858436189881769773412718557122875", + "1204220353790738722914083792135362748035159765787692557419132674570779260528813655383033099537444542456305266769433", + "467773203653620200363030246502682528655992524152005647916581351427019987296789559173353646592561779476558893246047", + "550908530414523064524210174296778403214222114026573274934218570461608395666104567675317084385414062543480737603284", + "1095981027022875078043834350770329156652097295519005444881609808543959775649488686035917160767128221754396159704455", + "1316758622882133370823387863387723472834695409300335175743347348974604644068946218403893554437799917946828842174890", + "53926337151038012360415290302261928860299221530712803837758947306343631315402906165715266204061939493709654455801", + "2405072505107228661208976333615386216734371319269731448223630132576288899225683454907295280487761333138615900734927", + "2358357592818336360146026440179189649755945597552229822253468927940477635063422178762344069571306154253232820637898", + "224341006429951264597644478580009179215413691076880329537112022991661392677997787745453204393546452664407665846501", + "296066499693129972854957280240246476196560720335931699320322570207125592380389167625303265845540490083798312112004", + "1930018820723046513509661496890649520416544564870044992480536841367699119963041573231610892948468842064612193833101", + "1586513242381858432840221243151704452246909996513413539108657134635707969256308554824429882374688504096358153712416", + "249076159890301398728184356586073039114740242080701880859856849079877716703163355441346046057712422984212199612928", + "2377720193421427157349100140266835113049647668592854331203916407562823013294193185443072027546353527498690779324553", + "1102831742837865724689216145540448164428714323983977923825267562449907221287966132722694313663462407043175033351238", + "1726309908887245704733967501625088519066478170895360416593235087189173446060242721613094865055122998426172219698054", + "143357436013782470008106977541272688671010164355982288833778025675288633773044313652096651339291714864993256186333", + "2304711390855856772627679415451171268422446936823086664073910305819162064510130396020405343514682103750675121563836", + "1269485132519675704118860547812932440740823799525241666269008552457183873406212526247461425853751887649635764839312", + "1628507904241576074656515366121157316718363285591105898026005082873240423340374878958005413935085616158732549793867", + "840135200704405488286566961578553618677471569114968872303440157244035926462530083524368461842020786560788525998688", + "1966746302376143199532488691608312774123286938954875712666526264980315825068612123287058406161268933373857319994628", + "803470655046650865368880990043590508974601560175989183852999623920775950329504200176026817157388772716355843949484", + "1025284438640851205817209487715180803863679940795280160957399092471389919439518222174420184381758805702122396714389", + "1687569688561811506725110618634412749966087309556419985589627212887119192811767744297757930609459922539009309772487", + "1597360032214680564156732902357671944650643986882854263269435361544076344791929607610676513803409446749099604691139", + "770335444494418847254870745715676668630259713428794500878133471041468715338496498850474268546496520369703205983340", + "2397447458717465125417831534253336169045972531543707459414950690363055104693201066588201863776191540931059135181439", + "968609008997612063667564644631211312277267472447706169765583484255041023936506485844362542750389267647913766204797", + "2432831457055358990159626495399016515890553853405083724069854387631438913609575457494431690111108871166555173018607", + "1126631882163765675237481667024275285139965536388481335861359122266935622157409981008527649224906975438351420416548", + "2180682012126298377906079251030739364474747224395392260209383030705455955023933453417664585559418124835106688780771", + "416141599561560430945009384848364017878342056243872840795719690437379561602503229904517435763506221614235641295148", + "1213034987780431217443277809371041961564586182250262683191927622148963789867094274071546598906858331371719551486470", + "1292113176044674418410518153458261344833357070847063949969708088712321243556428135766882604823836353726206054332326", + "1037205295630549989798207616256865142799362629464378734448817204493641703540802311609453375052170796685454325836269", + "1482666796634788663834731780216079460587786724617360033872527620961189955323175638306874334184338625729161354451080", + "326568562017584140054205302907768852357016964028236019042149977723974396538120527700147743689699262734340381430414", + "638361202077077026100800406518393675886868536619906770094546474892606399814461810470896065062378177950169793517777", + "2130010502720066034153292734313914993985729913972650275141826926712516622153334939227712700633345264211249065829560", + "1635743505158818649007584268275253108513829894741311886155445624975532735908714228141151240365523455355893867967937", + "194491661293563919557189937457921652795758541990998082192972073545373986523384940083092385073698803442521866905693", + "213392788118853560192495032686501956294953583926328141207810033322285522046314088212148756011768991900124516655924", + "1318113623727105100328779897774828482200147418685906532710087254855214541282749594416311449856816107279688662062713", + "1796284641217216378495515985419646042659889000801811234802707205901348699768929331665715758238115181906923546432219", + "1277313753574516675957529654651729226217712694649903654464409668452644175166862392144599132996943249267916662715729", + "2058525705949607109175666512679740973888651853774344087237309772303189868907119499810911938291923134002675765468420", + "902243435726949761733562222594485149328637169808257820485137748929617274242626430428342574956614547564011109419910", + "1137907651844961211025748439088864425370643583954128273229163941132790254662694341300261324110502606536460599981176", + "1733142458574208547454980972680895294560734871670096068750547977964373329529358276586551559956106678295155667817049", + "1374224387369294561204759546290267505498765050602461759129052116309279277082163142234613304289567543217533411786454", + "1781275880363112763267608299404732548108406115578597011999783876306470163533479605589934959607170613962632724944281", + "74581095951250197140684573927308100088990101682800074225531445202837943999287811469719327334270107916497141542346", + "1630249206417732055300045581266831845761731373369353902849922582218983996620379732093728718691704239541361721367961", + "703575641726140692228636878623149883101808908719800279716698498691884439812631200618371045709372900232678705768274", + "126818378549785577712541937879708214706405982281817439489743163338576133330546069526718661780874428348977583770047", + "2173691627319030035789389984288781638295198214420937291034950749123986377185975342057579011881714873816349200812794", + "1490958175099792036173472814715955514117598762778398058902183011181932796851695167671121414517594680793976868242053", + "1643744902149821062015253741311184694233763008086435755575860718513237921518301776462146868530294885308706053463093", + "354827495465832489972755065764474850180183757127807626600399661498277303010470251448546910710106503223586624338270", + "379463898130020777122431734177117213257199805313532815623421672760966281447259524068302965811005370151451433208230", + "866726528770534334173627812979720637172330782975442903922410838534353250088182107707188182167939710936311122678440", + "2112272742411791846853825937419869683483223223792139429224681985211807486217915870203978854287862906041908555717350", + "254303718564210291314189454537256587231549665479121627133458136742868930692699013488670306299712654628412232238878", + "1198617877072278823632407502299983724279746863221811010444621066634909610796615234389038574536535140244604393795128", + "620887646169904086053266114569451559848034894482411247423424572416196209039137259938203230584806658720447713898608", + "573789102112286232539449175689604414974703203722927959048189460838552318212902487310773598230794123658529435104908", + "115782388317760091792361795930734732786977546341138424711987313131961839770147801116742345916508114765623734760046", + "1520396608967541633868891347848152647113328974622191270914701955530762119709481312757137620609748826649236951053098", + "264923103276616748621869743456330348000108786696472255144276791071068092031585708713652417075840230515825048964950", + "1915966445164799826045434127809732993682453583407919499182630908563646116756402880314935040681571024052274557733149", + "279693459462288575350563230418894000427246836611573965953958031175095839229271970444886750472495317692627726651465", + "1510762567380265948082486592555901107923988127279430051648709814667048957433115161235366554864645987212620956412615", + "2400090807096960768468071247752215031824303029358573071379834235970648946465332011156632173129408654920009512434053", + "1370785852690643997760153701826016322949008720992271777151491313757528261634416738580098648698687790329198528650815", + "1080213403480674113970930124779430902332743094744727052892433900942106985888803328486387587544402020097237607666962", + "1561793673169929501498412501698271453682103436805490122853076765442008799446407594695449188376062361438996526733539", + "24917829508603836070622233752414343578267130087426182999319476185873635315053736965654987932087133367722742051176", + "1890357530584146942882709534225456368098287401543074743562131021776201049160860425521036136791338572886962542548109", + "2106387818494854920561721219822085314161605846487211540948652096212742830703311914561224751081139496190792009099472", + "808262538577389462981675240547199823860932510576149851336490806395817532810025800172916667175069128724253590560945", + "2262902263685550143954817482568253274380443013596367069847533357409082070432818029319692561433537944804147938809114", + "110202500695964277248065384824703536522397568706980558748445608112276046477655745160123077796075336370376937240246", + "163017594514936582795036358739748326651913620523612426566454827589309965120803457939937151999791953288296118516612", + "1281009290330198775193528623910349705489913887544830540595834046177437846690997456045495417780093126274562596404112", + "1392348725963406262125739431355033140050586123216172572454537912191514674656745882791494534393350614209697596769733", + "422358409663741138618680139916169046729199505630432842958840020717419562754594832600147624079657449265894044195086", + "1350705499278967084506662269947985458750731200824258503101320875992460061012896920081602574857176683504563360174730", + "972455722728591680887916807490413563655542904997887966497639289793280265132629148313043029687250205658713310152644", + "2239322912002536160176380072936581454486942444625931207970669425294082066499792874192577024366053091312861366457643", + "773181959950179391287443695880263885414558414823182277927225535739470712659798237136823431346815703198868250096019", + "565089485225524323977839636438759106333625179892300005057792904111938920107860196368060391532141014217925142764129", + "2296433915461777291662509194177746820454395817714254863386628308969404528162889054961315221818013365004418214709966", + "429390263365636986844705246633708202658896242710268524487486230419766340311624148468977078608667182015292070869815", + "1709423872832492410572677373393973094478850613406696744098434880208830015671104064558525381793751901485845465585085", + "2413076896610732768936271740440107643303460055194844838963472505444203989663282310356449084664706995209794271946648", + "64571252134271450523081386551939650534346269945971494913607081738674356079151492099286784190875475729570275514781", + "271940492306677391624003660599984774650515920029198875601605903483649039070498769171102871732068060315270656538870", + "670372149330959132739163557101469749756355442047541779333272352289000722467739968254446505481466258561556234828356", + "2429249861872594575476339823890513359021484404612992984275072815616159221675010730523051452313962750156469043053607", + "2169531029496328647320078434533765896963520865301871318967989720689070368680719570313179930039068484391780054836600", + "296962853081236740657857922086464741585974810981508816235047510199252664484915592505861684683244278648249948904559", + "244574280923190222673030633978062351184490871104850450647456034546012081892554335862995712293593285718577037995579", + "598896799642750923214442735427630829573009284810673450162168071800854625154628720670167029771071588134725398383680", + "1431755562858492546627010574432928332945701017187819039349166230398884721900686147558881677784384335525597019342298", + "1303579799222841066144353191715819988173046334113945620620151362746103071587680100927123600018528910949996281750129", + "1451737018920720102085265912867006105813218520125551204373850945141904736509942796366895943961215868328094132407330", + "1077390158643691604484068179581105674709395980096212005894526354258772102862594568227554261757110184850068110094090", + "374255178917837225928715486546035214364715422608461399513539878916360872837114269314666295962381254545775063206040", + "2013199535415033789461852435927615247306119291700926545754251252772002173332005480764463616107149994036855883586001", + "2018770495400077823691590887362950146663018003033025606146686186014327094244321931963039548023458443780422727976074", + "729780205158926609290506521606892343912530884296819832446088592103680198501648907896017969810749653927557123236644", + "1704664917426575357740422827442431636232320700028886434197608301873300837333339141467708951405761357629128544539985", + "2345055784341051835368805247999441731505323395655324216541367488357118342888425243610413284429248366655797608712601", + "1535205215203112627655812424495300572894888485185335308341890040383777769456366743259017867125623785392803415077275", + "398540909085657841245990515784060186728811071155852814072532941621393857541906897756908540967337680186619533730450", + "264883592119350977377672083348893432559096490455747875457395397570868003796552793700710112706262335501528333377750", + "1312222078272659358913435016851247236994958327854819336465353985964983751421218277019201076709803280887028870288383", + "1315973320147899910210915936361930538540482533325929839831067978223962638638889252900004046330809171468380390355452", + "1406831542742396687965279512311491154843685427302387045557803197802553818907969104048121133740330632688994300231904", + "2278833699078295727001740174356111696414075535218491040334038404918987304245518024658273084620380047958518696359246", + "2351157871219599995880834002170319299539798953559082646785271007077563717869108641200500978101850553064874009550864", + "1134291246226788056920037917483982229028933882466984838323086480317836121419884485960134979838535241091453245159986", + "1007431619642158857690747945301723532043766127954996668052399258049012592125228458650172989359571966807565985477021", + "1950231018942702905318116646149695343507772914242145963205025568783829341193686926929102063254942891433539440913494", + "475172783691731477626612290450441666463219428591335907603254521532651613049931638228300594747436352457823048611157", + "686329274989088656871189584488628644135626530856362699340565476569136076422502448351090742054489607009302961045928", + "1192064925141807921019187574635488404729986021902700930384082364186859047032016533171751357940968024150444836237309", + "1460383253760357891180226502720525390043432550163019871514271414977108159337735695052777617579943730310682692317000", + "2073071731796741164426399877893639247007728269311383205262063342630213899394864083946905908096049124097578468117519", + "1676028276631092190548900767626361636652473393680409183965956788812738388042984798060205662889915638406418492966210", + "1774387708669034577773165220051281062280635831321676118593149339203546061694952114806760877439538913198139083716401", + "26352304478597612786328543460868115696653942590260389699124910046556618644142470004093482923878903510174667296210", + "582338078233823452901507569181130300214255004128424861494806515010693845716098739334789727047278961537673157766835", + "1384262708151976513708592596301359799691693156695033454329657769369203025295519889474805768751155398248584825568691", + "1319158438107922975449918552803437676650879637339059311454222015534369813681467688498110163778254346904829031301609", + "1058673113980762230322981719429735787097863960459996637533700396641172071664405818944787525762319902624422897654960", + "2337199351959673257251580471652611748873789176979221783572166566339982713581277556748165957508108619626899352942012", + "688949745735524561521855720393249429099870961005416408693245203482656215386912028581036293296808028803133964872975", + "2039436401357192453853956934493613184452082091654526573416474334021570024432743606889808939213880205143055384499883", + "2128511223623250566597423267093100389600725807195546138894222432725512600162384267005467634680178317871246250339232", + "1789864238136100562269856546335914056117103461018656262755145564907017176520107403993992250575860762831718749083518", + "742170081886278838199427596547853309410299635097151692079499446716509955787310504335877048390639313407972121914274", + "1319004589834996581040511397685908210785830918791735468125216921864393138213087584173443667948416588539346347727527", + "2270327899084574818324768199485671680892875289032288763583668238589783952556918786459671866713823798928432736471644", + "1264331509879580642780996731884187545955985725342978781393373632379987079065335788676223843125198339470158334781432", + "1332451976550059579205944241570754083228821208509455796481808565873271862106945106387099466437303031968134832167869", + "196025876343226372519033681539270141114971491115715513422045820650212427666229767223429282381171434750215502413803", + "346405785137031474459016193622590721092630941429631318418928335937876172175902664897765106653341339843474979897677", + "809743000076198921698625219530434905499327310577122757485875575774386177206661548583966701809182400313972583759843", + "49298019713421491587580667026126336590193801601880719530953064006578222628710726297854029148141088429607875012715", + "40669272509610836677559911144054023432354197001958484065860940738827267064744387193244517707374164370651803674641", + "2366555060979525427690886691890997878692366453009661333739496259801576141596931642047623230442056159824814220322115", + "1750899184024479633305981484191093585568846179526769929108017173523521485634632644223596751679273867468838448509128", + "1583117874009390221343799694826474307799040913097770201290441025315840052025003864407572769419402526742629669584391", + "1701659092706956459226882097736678303066579202896491305161482571131253875213820985106461550277402433120204297928509", + "73449217201925538088576081947995908927779704790269053873227715055790588545438169565447386239752484414573076738027", + "243318349809306919285132652166566711504055921645740409747739838932091144202388284761835164834239002035526753901028", + "91481063019644506822601243072523517617555331876381635505582164528707138988294724504147961821218183337875754680335", + "1337406868353828784618121912971339388105961826378985701939442614521365218956819087948850751594744196624111441367808", + "1898076975488377682137688071167941042433751438762381381251447168906538994302184598215485275153441352891157406970302", + "506303616404572488134572985639638430997643164482737314723845670943513250756916944221910294788802041286534272460772", + "901048510681986750773968794138087566972333289361409844613797192901829190224645510406716438291637273028961662471724", + "1973491574711576409575032913773718280583623289003830971646727695802521026417831734412879304364753051287841428252307", + "1516975824933240079177093157556726282373904787111102612661954439958873395598421119594530853295746694214406946116399", + "1530506796404503211152282003048383139362368852375627534119340133439689904566757630699519061534499377109375919108717", + "2059436136977111521223034935506402451840991792118576479595958844543830017477739243942032696992242398856128070122175", + "2076721250663068946878004516869301171088035376326647856757705513029798674769309008442572766325519711683956903836642", + "421173964035699633554550331835366023057533426110878525907141220128819171864897540562195809923823227822490680625612", + "539813296591129957761456271832122952508467329185039934105775767677777864978878447721410605509749266430389267082790", + "388998602774572820100635555708442272021214399821782947136858649665375988225556512742911437816153684268929547213209", + "567234787609815370236746037645805481146441551748442271833874175190419954564161797866016212815447437031473788466815", + "680359711387887089076175159074668664508989031315733648606008297051382257936980217744504465470865973249210812449687", + "2438363223403654939096330818894778916452222178560734881550752227384688379356149273831902160535403001877901921984497", + "14442068528946529205108556582669483983811901225623878457581015415357842867104547939492744871760561202055972618291", + "527821398568851442803375464628018992244819131282062899521852971517481872752537551380403435405846171177100901613491", + "1697278191727737544186951993999372334974794689881836129614431728690081804696746557701358064211561428580134846255817", + "7480991571323204753042989647680770960366493562004104092018684330354340772269238222463380436389276733008184704656", + "47384310308604150128049692873197721730947122136486621300350451200181847067468852753211162024403890674170196977921", + "1004693654524848055799558646980407908564358026113416153801799241345928593351728914326681936996978299211675549115032", + "81169368051000947071716300193352717950148921825890147270410786937206224286413896695525469569107248658685100481435", + "1272507944493762077456055913387796094208734580405818479210855549133308916221312170576089524059531123660072080970414", + "1147741065386149930037340824068093798460294422660602892204721105053550910265555704804522167203512221526643331376984", + "1456007546372550589711271268592271063416612563027572369442921025797529308340584081110654928681451034777502901123537", + "1020533444457311775765562922049720971755878961670385917375672794189123356082316831258351793613489501592469189307484", + "1872570440295030367523406744780869903783295909730814428839925080343063487509866000923440476216668179783985995738913", + "778873716957051042824343953948878824360645865062943914901401420318809967259622824247568348333523033014173940086760", + "140221439885807609335950657020193230946570924100836694364860262788616544635035290431025243866925527145449366018446", + "208969853952501117347430876395543373569972046961774283170693976151464490402897127083104209892632417252638842000608", + "700778779545530188474632927979415096258376754370386880648342249007396262815807959879157035598165408339146764366918", + "1523489254070271368805203704874822889892659212133256686456331785425569443457400334931829899680276963321674068142401", + "1821747934662965430427177485209222157123426566753066078918980256305936790802416060401711718445819380625699133590341", + "2324579319090072638980960427117639480277748059146024936902257008228047592949559632500054314596448929230873231354520", + "2113070182234290823967772230629343178009448504749941946238944582270371176108245162974734033256368977811358557114227", + "1254592930736207271715357802902779152971083707809315717517034474814483787390757795324144012110756911855137654893583", + "1160747310480030058055276292929691079636622361388756732029888523911910791337405788621589707066699708851916513076968", + "39522902602204742274269373890319048322101517723071424967485971662106859099922869491474236964938639208322033774152", + "1286999607282312260479362744239795744154848328211687893236481166781960535592782319301400004684895151108703938776960", + "2338451584411700795995043408391938581601372002910838543422818884619703825436903024513910480087902571317830354668358", + "1747774284303202043044889438241646486977059773157671662094484214283139947020529388487124604086424181796800814933847", + "137457905019783238752826241291811582285120800789277601671650750305690545685063294993309616611993817162697529243045", + "77916428951885330875018578977144717038138996804943489913332677053620235237877436841713856012159618171701617981361", + "1290772766090665876314384063690659758473759513482078993879872123464156255559092103028694353740424861310454808010771", + "1143462266903377502315054194386236947796482970718118397276675007907934775456748789308341764552117815957363645947234", + "365493933849057456072735420404997787715090019844466759937694646010404086771965811494016599955351652223237014841070", + "570040069777832739776223195117678305974828193292582292460648823742081775243238289207522769879401748033071726548695", + "634185284967152459345290591169532719020937590547274348353794220428502131413434098869148187481798063547012117715354", + "29137179924754696393474774141232718181843942548862829522067824716951665431181959324356517140927213787309655428084", + "2030234502637028857813838389562327571193330948450086356034733969752890121997887237362713910727145068978006531790399", + "227126986363606182903135302648059730464432378109140790192863795317831294596089468525905268106462683236933874353789", + "904371380182740409071259849899139106440452402158020681264973377067600870348936116953581490781557594514959115428399", + "908880579066177610944948186611630974936361276267212705661937730242166909370324935103602722213055625601116775486294", + "866704273169095561143015605457479375199335938752568786102388012758999582558637891141898247500465161838285344897226", + "1829783842696636843545618207822505043817273246413306043647487159987136728037548262499247280184619200282293576912205", + "855096276112382736559104799314971275893247518587904896086960841160532020820682340108512871274203714918941322557228", + "1221415827972653240359012265609840043569518018561804234135591083124438277009009969287280547723426583280981680918780", + "879776922465089526293546211200868684883320288587504186006787287972960916605237969209323113380357868390508407975394", + "574188854924662242922083494333154795739402740837394214609239556160464013482511711432298818799043699275991756881807", + "2280285198337001672619680655275426414459839352484246413290966928999269688836613928789604965423022502722472953024958", + "26095166427271548497998731243851198612120946753479726342771002472830288602240130912329678915771297988263932376288", + "850115970709923507717728438376325605619846257294064719036858023088245962941669626873924124119106700406722164899051", + "1925125429084821897805898190502905229355581443536260025917033689632223026928852877292768861574059584315587997879175", + "15121968325492862739654529571793503066611133361369841772921965687619406148484396433485104667611140054912075415785", + "400133060442525877660985244358975451795954682918163529192225493509520674395456940682746344913271441013323291594122", + "116920079834686910694922107397628320287214423287167439605057083531206136754679864299404088814520446693606529186800", + "585486653168829229864067285160197943490540621273574258525482934352851925357241181967763137939865976581097176870149", + "1930488239695922635092968672511379359213555079248826825199715541674265357928878073220583024783544305139099343199137", + "1068687630685711270395825329557806420406939310042097316376265508849621816613092177470592396777047357245888839910279", + "611509028475536409941239873712202455252285803202958732558955373349765837039289409180477299114864891800674662954350", + "460937910618160667278397996760216398680913937225054594560514172899679722062966007103407765443899889089612726061224", + "1588178294983942329486444578280503461764166845057696356646903233795775740633361784793291426687237448877713193122086", + "1205206883928187809211206843601100341166997473553210707334400545457875696245584770824123244882969779462985253416779", + "1354096024169832869844477727787974069017866536891854954686916809672764904207413547763596041758068199338951190222545", + "2369406001876778694657505882969249243819874286409380435289140694229123194864785012919102573895198384238602105284326", + "1420816308619336103189043092897799687599086806082965481189730314301512500340449198945035007576569059286182447624715", + "83345948985971596121340647777287580872653260059588360878845870971267307666436828850615875882656691139512025054417", + "173496425000935513484877358494087667122018784470696627501264669593566850168041651678380321029598310113963445438623", + "424694533411926370436398883799220007731444048364285071974252043692146375229360334626797575485936791946119051898735", + "2414195586857063145253041706810879510095639842128219577308629004670566147429121490863782688358785910951933575100048", + "71401978971226798713591393385596102424343159131066143155427262004579924797658648836794215023436639089628119865872", + "158847137779854995339910023468319480218713155432337914067344469687409916464201831109925074920552780786706836621555", + "728539111397792259899370463522615710420622176411392290652619805416319991231143468638850151820409946376663124442596", + "213257092736121694792649603882940995676567896473919848294692311521385106376668717851119173647265122254447259359196", + "2426868403082272346966855367210131831049950920560364392741561606970589332909877582257675220224859972818544906810297", + "2184977311133897427255449935855187887858938348264862313166807740072217629383371929932520152782504111530302940000613", + "218460693430277425531482970799001089613516741966922716645392425466912762507884832876655839153099963444706056051619", + "1791127720523813066270812291105436245793960245343780925884592671085728709819030196488265790892225501591187825098678", + "2188996971796425084090055536030790275118531888903129156968395849948824705185050940694907101741002378985608485265689", + "1975701060904312898435516648516009792347786590814157661422268696634812509722512031206774062463526767600808547536815", + "2187072376663973819828400017669010998186067122608979635599401075850705645468491991349407371113739387180722642410524", + "864777115712877475986641333222396968553405325860040099653616892749000612062581596194751005586359121558340051424560", + "2350035444965924357725778632878880186694958273500284836758000162780235613163869096757799001819520763498271935824212", + "333036782310838750682859498437401267936162210582911011375096651687126689042837518095942153501300899389245707084942", + "224396571237344197595824789918684395919931171223185781255409135729726046744027842042343464850131314911090775617668", + "878334054469383833085689875335618512056710246047556150587364448659648582788828001224690912320274927216899018321693", + "2336726445291520317489485354169722938374318798479879154910928420387927409832985449859311819415237475935055346582662", + "1477165933040295972663493688953409951677440891616241509248372126746819804255929945283714018932502963449664285132805", + "1361469645809124206124222471306684873850184644403589214975992021513795447259288575992780891940154465277285938946659", + "2038548092773497491258253053607563761738942469342824551179596311703543011944074643797891373959359211418050208877266", + "1940496127948398810328224555163097282922846488325049937427875866951576047799638093920431458289383283859493713048936", + "1124045941840723260017743242825664654787765369933330975627178275441692154084758393850514373217684947627205672482695", + "1639748849973659838954006976263803980085912902658791489166508336252517558408016942228746153795745321486575057938313", + "2433051916859958500367633647749172324687523635535740970032867905471779634990858099238756374252470498518279052439884", + "731625044371303348931624848926616927697377785243741553451155065793028197338802322633870980819523896483027624865704", + "2301487899558897082605848821793747484178423443104312248661177895276657029002181160378227514055146212274483310672862", + "1624608499932493388399323091364188673201563670699203554744089881529773828940629212897330491499926492454944670213389", + "984899449541777351285312830792006550420509481419565221585930486491337910950993809060094935463678257448909788323056", + "905729860959080930412596260608424604309469861982686392556102619474166139282375225760853262285194235120255934733167", + "1797399906507719680191524910067822079134278219727173385921466325840932192977147423323480095260378274457878478248464", + "1512691769264119158038230577044042536163391131991738732568173148162180750909913661904780194174098646882756770894900", + "1665851009936169388035135594858427622037618659276570737351413877276429875527895189842920718426146990773262784280092", + "1132258517398631781993315945407098501611688586619548699161104891244505298377807743031133331481181576467158017290673", + "1711749417589759469402356670864348864619591082165432492433045201679756415670476533927687131827920579499756195551592", + "1257922614075899226445914916425761561900410036635592529579395094291002621922526349484052884036869274037765828435557", + "1655179370943286197178817417376411628986699216393762594205974666673952505698926248139550976077497747105200028791412", + "2027038747063797339662268287153013939159829028375013176755870171661751114271424198875417203880657761540639391681738", + "1516573433159492860359505003203119958053598256777938072646427009700474503681767381739364019449120119556728856074550", + "656164094113543594303556555200767533347106056314982877413147695288161729462773339338339386147797743550206881671566", + "1747538866765607822817716856277530009527354510041813070148216919846224080426800617683274624795118059085498825066289", + "2225112932412366248105251402270058642891463281968009900799965838889841055341075954857867238409734885648065627377260", + "906323479370233025856404499495002970810430344494850533607678641112206100248243408978850973554180958030242327319353", + "100934230540156510190003580137659306645097805313511933638301992064677292491845395882038981412420943530467818950398", + "14465026448867904266565757431465370966340437687006835959258959264902299561565059105860934743772779461246804729557", + "643915699063508568637164732579134246918514342472598802563628355133235120741282236475284994175371658334179650063139", + "1820145683331374071999492558663514494067553949553814411015852365778985637087880329033961173796836195638531983217131", + "1653599001856633915356691815082713548254103321630764472307341005334326632061203461009867791756917198286877135534818", + "879197621447331164416745351536074485221167309817368996980357905636547991800203067853033387918426630985801173257054", + "2053265746835281123507353199635605780705600500959249323352305218170143644908341505026649732299098202475632784858351", + "146607842270674395295284978082882854521204823024750514376451934198526051763165164439589202342905115767708714806023", + "1123552803405198774930351774992033207997035329563801383186316482441063855618611332208209803746870767886956553824938", + "2221751929635314918196130389162784616638972085698257956991328275359827339807121591004323198033614676445694952686675", + "1771414089326438962987626037564864798407289770005722284792859000935822326755419524541413539196591257020673715101214", + "1140839858053537289108049690423981667418439060991208893247540425778030648096518172110959328246046471420289971662079", + "54990356077626012378060894142842245868013697209379779174712474559259620503250988711528224774634006701177864493922", + "1662515672132832010250639103093205342462517972974466518922081986978418283281050698167708603175596153510574118230081", + "2042454148784419663141880129209426038794308155070408508140666426434023364715396494171633382635142942460709945689599", + "1994098798791800632905134444364992767094517684809647777070359932540207211747194648166882420650964110496593823188074", + "327801906400326512626086077210857144481770341784600460066272751923360010370765515290712025623532296014676784933728", + "1218819938655996865906878228342772734093593341643034101154997566796055001421749115028187141343349506628746624484591", + "2269016558192301428111609926861123950598934009638230851204628076346097460900056643944769280670391886141411047002459", + "1138798253392487837740405326939046231197535532512016416476293018271286660296671686048238929774450952377997108903133", + "569313226648778749908000908817377168036697513863613299794100334018653080314182335913970476348155709452292618138860", + "1038879715916403887247253837539860147837993118359664923727784127498311735519241149572082708113793827128820051157544", + "519071390884241020105148510194474164241141737644053283212949281425591050228256653676876170838497953265832916778376", + "643011285066860752617041783343096985640836124973187107771632694970719933859456415375316583409479202497253611593618", + "100266530130224047629218112552283911522993557877774990671700768594429367022804697144335795671487192912817502632474", + "1163139634352916938467040278287229653623897574313926090127818699149995223158868854597383909183464254424252210761427", + "1340748446922321032175992685517299741304925614097923740397257186716803795893681959404377925604744572643125559257553", + "407178383859282663610234854563432535885123918135448187095092127847230229380510425066567175969894922249332904241249", + "1896098673735290091052090598853986025705418220013070440280843580843575748281710214977781958052206657584739607976416", + "783654949683059350478480931317296878315986947709147782639378906892004576086188131769007238517523702020067132282837", + "1614158562467057832291167280408770673326766356848484775571805327253749683970682991772078231439584560729062895812676", + "973698211785609536815453309687569755978694151379994184632471724047551655334205691014629068461468015981160924534070", + "235517449917375332419069521292972545320155292644309946619412623506084180375883052543876471910401581241266191018956", + "935361809825703375713109430196323539858265130227291395562153238986644740620784427037457915588133617343707817873075", + "118001665173900618625586605138866238584373461641162740933433425280546152852571026799988259732444651946996407667956", + "326302339520643766704928284223910329189827188733077434192860763211609337709069118041608340545816419824237354346305", + "803181726842071785292338223691913065541309395956474523497177245600419042594789369553390052575015222365394843969570", + "1909785627228330554007630580742346455158928090101574636779610045727554457534687056700730876856447407272808121012150", + "1266862698431367657501178234961004617267131859246039348246444742137336507761784934994763678204267207883748837119541", + "62272540605437758034184556301363652855538848340235109805855825805543027407187393082568769130200920763377403162025", + "407204976198027741372182983934223152276019324367187100020807922772004355181544376901152819014699571395156971342122", + "1236436602947867537691554517529353898110871288528941992368190514415254716939427719907449025138102708736039695462609", + "2340160751295829910866917568050771348411044345381137256481831243760351198347137187412459062466043901234716587638414", + "295708660037840258472460302631621785941923075220234509023736323915592046005063189587500426270345724619351382499914", + "1636618316058497745241970088955572756172462749776727233036573198625197494705467674161492243895693125669305778800660", + "648653877831301015147477446127728249603472370866730948499269527014405743347868265929396734354872859290773067917001", + "1596759860068880622205493053472730138838722617037603748268198091729617740059448332203403680668374376598338141834280", + "753954837645620435732588479582224943289845465002852211094563231390934079577082985090147328015948468199544163760333", + "969733542537287345664882136720739811914981448561795601652694951982827043278794054435470804304033782185725525221082", + "2230893321234386474189228182259370059881987871334106396670586121242356730582715506234707908847652899324090710772212", + "337636234545910638283236727486788939736369959774696271430853776272602861910866306235607769251174997648792933431888", + "1191146113588670822065818344083081688538930035987091849755414834502849064756655696137610093374369295091732917232733", + "624850543956587705704870442716186052769251800152156965737975242686824434462538375677942087823795688901123045060842", + "266207017772915475772567738608658393953065969407930443150918542291428198776991923296995515646437963719110612191428", + "2016576538103974366869095468458510086811345797480283475049403499136425587576840057757720120895866129773840074367828", + "1658903365550996279705992971846067728780332093280283314834452873313064395041318488036773909416584473459033244105750", + "2263030598712119942377714124571116211878372829488775657546833345154013797641638187023976489572608772537367059856351", + "2250397979655305276373475148516589147166332578378633345698419421843907495160788687985756319797875660460069203025027", + "271246193510562694636604414174344559490845231843696289697845393980714060289664083426005059514600668986052373244093", + "55244125136675925372833175204988794379424232091477107875489909581117214368270037027398928260476523262567565280435", + "1560457187518978533718269470122895268779267122595256057851853786963549897612301862629392027523345418087024535386006", + "1374891416456003465520773422607370845932689266278755593558646032058984326267826508042351455265596449577513444289484", + "2456777357868874199575142602988888790313150547663385876474901433330677779932103213851920042198905673811491600082698", + "919043875744160626648482290197033436010404320388166747757255787078461253857923107510564429983230036330130003341892", + "1387369649466978629010830519238879681571288766110162201754735210982612704737052677794943452866818619987408585161010", + "1243502536391565001390299790017283985777859764194514329717569374921599823894027444854247079974430436387930639461099", + "236481221717377057028160444951144642966178719985728415557765704527029965624570233897234260332928922709225631853688", + "1202668346848819190119923317820528187336270018532763672183883712641548672458871145661601766214328098750186420012578", + "1493989008793874055583094877221227018734934736429990204439211473392521304283519582882741316397279488092635778791558", + "2375114564211015622166452943099620810993322356968174472607294394443897431613714978221788178805160694156068524682800", + "1312064512665453079546871460081928261033410960553143426744065345630635779922186785040656414062522208160824592938011", + "2301000459682333814780856427802669262123950211475470205073140730330735720999284273092780782246542987098053123540880", + "980224524076055385461922048376521717913786795915668072395588628634824649576465600365601505552824938880056398127316", + "1396985038567271052712669874674230631241557679079259976223679345298319838400470613731207045931455036864830854434361", + "1975856198699299454991073745570915776614573646164552454273626800708675289548535421193283634606172466852100693673430", + "670090598236471171212654340363354350344622007631130963106097492937503276356311954635685497644406422353693016676087", + "2253747115456302942665310717085405133831640936700766668235844245868751037735373116793690913604900305604627699593501", + "1441957124011315592160275850468231789133956974475976783633315367016157098524581161996592199333684660838325401560403", + "196677144455466899977222580761184799988807885433142530305273390190334506329138806196435023493943321010885452660651", + "1850634042589750723079627647269959244513476399488286035891454650056496657005549544836002601614146356284973881457220", + "118514277308084371936972528563674137144141727484351010590231001837667858721805512249606954288768556822000916292435", + "892554851178328230760053651009301233179513899706807217176334682341062457143693539128461192702542626153394289970103", + "92568737781756476313145116379954817495526834238102694730381933088777249185450933927528743491395098476684178693377", + "622241686948287706751476079812259193088674219441035352592108739164783089195719684212192269359938724862104616497504", + "260849586309963665035767282401589400097815301787313049667186095023594934350223004684243999533175465926051137780488", + "2159698717092703822991314238029918784406332640841241613592616201155026029854452892440968775304064128744715052347548", + "1745081254112538115567384436561930178134833149778321747290059938261062978640964183246523213484015312835496787687554", + "1450800842934358844759550819473002473742027671026904543398294623748043156541245943322324391477600335253123556493168", + "127593637496950499908966721423710176933525840993673819422716440153622244911436106165741802018688358549586506336728", + "1082289537207413056960441715272597855486988505000976744583832428170714264165776035596039027223767011111778200902773", + "1322806247493794628689391146126056530884341301631270428831761773916408845807012116028207258133358256002922840825723", + "2413750777210650035996830420872374002304722506144922541613631061158354279295803134924285575095582870725376618471704", + "883303622298980931461463901190173830489899434709672114525693745685993885488666749525438132327279545628197345179589", + "805135483549044341757286624296194481585668223323486063454742234827574738321417331021651370010576927178403362436897", + "474786668546900937234104315590568619539838521702414223300009423017935944789093211615531455017148466817375596926891", + "1159597766963181392870235289773712673995158465827322430416504778469851316553561049966696833029352173541527436650683", + "1786164952030621813365725608508899543518624053339596718134691184409562465367710321143284132629444193635705550226681", + "952092123213137618008637035415294009921465652885605163547883550913868728480700305617400301786257741515085653542218", + "2284829892254900230850401979816301157684380381450318931958688242115859673586192577127046867077815197915059778027339", + "1443769659531548622487632236100442779232092511650933682192019691930134246203085195369705128562351050523490948565531", + "201768829220454419559200156587323158005137656833281393502050653194290258283751057429529988274719005990230979149732", + "243241128737099390291742143242111326382455926108660840817515117892993451385920230275192535566734296135167423750951", + "68090863099367925605777401048977943066891681686443474822304835619784127436989846164231678636740669217562768280240", + "1566911743067702283173128675617245539008285108850652686203527444340729248976712710888902168032910336461896497576264", + "949435244523081011284618048385708996905961534823172486735416622119853830417960178567845935399069425280530150006597", + "2073848097143296647049295431658824932096110677264995065099022943699277148460586183535205567942910793338931549929501", + "1787276595549263173801153728670783648143216591285712942028335206598667430543232078806204159354929737625371220637827", + "2025145555380367938464115928933382826555964352482782391166155840994230404306324758486257436131817384390964518453660", + "1348715307818945669301476898093321531510937379197442422359146313477446241979117996758244243622872514064353683594132", + "1083920033409981193730455376248008994004267339810639434391825573904848080524987633919315480589111156123130714446758", + "9226973815476615028826038029381888935969961227258438655341213198376555173017712409589072148298536645184736332690", + "476313036564909965846578034412636265442147364112110199284716287491615775111262239394093853287090700473281632792796", + "1702955792185616861347594452970943499161384746094677183574107913283566794893334398689431058073159773451199607310971", + "1245484876993777452361835660530927080172553270207315385122711479788000491074676532180317277248462727706368680565719", + "1526121414124879526728870209596248559611392347359657704430604981576944900561020288350471289280053412432709354882905", + "2126738157287064803135972549058602019758095600975897422289459754625851066635563789259520339534972670694341494929731", + "842346017849416916536767959905630564138578992167690048348611644526638694621339429172725907898976051973918544976493", + "2280433963154164679765762456128734361576855106642766347001007705147319056260489129182776229711727095067599561378509", + "76448558236914430858704492072525354275678071278633030401559406627442406793921633563071935186712803055282717687655", + "1041307630223227265568091861669800302727682363628331034819895691304563143354395488318338358121774034625493321474386", + "2447880322562052441908404708998020700593415897907647230177552753605566120147220227673103627731336928440900540265565", + "1625324762719248273250379347709524770451312904150756361926129737812939662808459540303056590190664518651091104340537", + "1993299216807041646388723589077487223594536541633217486311644011363880705544558006466758798315261845039070428323433", + "944358750081097305062504680948839763319312537739508667729689636758262794712379881735804303248687471402976466561224", + "1913894063440416183095440928421549404164139852638100186108629334312709600930141074595518263420020157530811449301472", + "1555156078830160113400653849592249708755093085882053036798066004537669579302315447952163641125541740185840743854175", + "74249193750056512131190543562143494076630302484066143379709689735240475962103157604003363592143146442750280913380", + "337257862384107745372951173724473787679839182102785566674779198173242276879937098711221582528356436077224912467300", + "2166059273425489260150262270640487099633381004435894173954908458487405274891927126370969104262210557511022042003172", + "1676782279148116329480348004077077078591422304764718378097874545382297175787425967995205676375317936181312026526048", + "1458214773239495230621771745256368461601776439382590153582397566847583243029744532116338254078254108817367809196381", + "2135375567512301053906602896400359224452165165308999628470353841286624420158382901386186214765487079356370417111023", + "1987373462347625477512316249950767007314817917762602508082851662771606192172940634127340504349779855465390025316621", + "1897402940606124361088710194888956679510324895005680636058709485494110093445172664870272441322114953263448240670926", + "2295031739927104001305526417946428404440030845652197232410259459111611345561742267082575205870626081144631449243588", + "320615713843034307772768039912922505502191577577180067012296945642051263332945563641912927917642917854565419308945", + "1237952191610816268742608109646301933010313291463294654568783904209512727601598728741446107187322329821753558080257", + "615527378175517786012034087335203189857115574871161684876118547313565731666818608038076582262828349595362907016186", + "1548223333961084210913640207466471141270555868282918566430583952005135748852796283796625053245836102653313466443169", + "482957959935305047148157682592476497016316794478371708088342385613779645962465974453233081028664304894712844159603", + "741964373672240218565719572877455983180805579432543677647645403938881544760968659058367082430664867986722578619436", + "1962914749534668985597664225179811258484400509161000945198115406506367243651871385925034735371315608473127672743533", + "1023744357844574199171696957848325240932174112871633134992806723167499771746479947506210926703795732333756014077172", + "1973069520309581663888827192930000240241576286730583224396386182251370248215268218061755053717940293784606279779770", + "880238877830723887031241933619082137485413589707587673118756459259675757073971294617423580197675936497840198133854", + "152441107948653765091551548038230552645463086322277714502534327376388687098737415315981376041895501802966447286029", + "718788108109263022508863099290785239214065920553813564368737201677964460983605475421671794610206574515618565302429", + "230410386671411676451852163374966016304317913432202381871910290116457808680742870632440804881331669950671020458854", + "706249245263693147454949867421443023068505066108304531765835341404956793251683998669901687501164417909648796149158", + "887070891038947634631437023117027485809859382862458999024272350619760441344972232397556497171491738072282614779506", + "1117193229448093825529308881051062235775628650435449174519785510303175859710185085784345302876341417034157231063472", + "1920910386820445931532425706310430596472603765449439483532670123766630001050382217841740325002637990576410018043195", + "1243814949553747777811186265782391059460503126919490283271783633415472057800564722865220997018759055324579359955783", + "2153597912870092420211668631744647558186344105395786133820846533117066377067687942512426750301831076049506857010874", + "160371224568147029881361458204520082704676459283944053087549371375681480202486376439167071109563417624056664371959", + "979922965537234852400750872161129576931903342597078058214248528660959357061787796006164624101113607561501969529332", + "1436168310438915283068351307734603182785118462480518612512383400227959583078148591421663162479321891824985602922360", + "1858627243514714545752171631971958725368357816263693560193953239142997747632715281630176861675163231834039340961235", + "1393907710701147980367589620409893238574725850250507581346538621290453619482951501596141267697110952396903139649387", + "511426735069299948241617458359438610298398008098410329250746221163698321586947658509651602600156458625368469121660", + "908335770663284355274943822320579388340852543475558011146437408292309064194675840685453416013242398841925512971147", + "2188689799332456852892581732423034433546404185777815935063678841007576869580594386827341436713239148888817767727463", + "1512102338997553338349541273236378090991743125267947448928824460114809094619733703512921110940431049385733022428236", + "1102068183783990167833137983200097552127226987751125192070100947911933288412994089876181355978454347235075964255817", + "367212051047650550118605191229866541676260398369633174623533520398176014119945766348124251924933091060999218654307", + "1511069457165295688435454338678438324009688357863340063866371379796135974840704559628078564375474781150041815950044", + "892902890394725766852357407689660739881379661773885018114536148662301010037859292871267648169078815969244134287045", + "441520787968625326017661545330697054618932091441453675022709086823215751638881541630663610607568171865594389383949", + "798368660078418604143005959852191918864455828307145084025663079404330158274395159425892066062501677139835096975946", + "1813089339903769713186426694115774084558977178297377211004360828179418276972300326822831677037599089483587991085857", + "1502882846621712845234033286887906406431054342022000903290051862442407270806712711821982526383303202295485516075015", + "1406603884742901385874199161422237975565435272846975576269330901195752857275233131553152737180962924785291853902736", + "1168565298688059666903604749136089806501314233825397851008401544393547255071065618035201877257732342711202187127888", + "304617017025030356321240324914151831991726992029512091656330884601173045041607548537802857525781948715995743317933", + "1611642516592937263224093748587257656855141703906074801263615223715586208516536949770200175322499150078725728684994", + "1215081234401189215020054731900872783880599288421066308235469002342434218166180778547201080292279750648661864524636", + "1786359238860772344093456255822564606393242913967773982023406218757389234944719833920615382138759816147775946784271", + "1726044324651766770054448250106277360774968693224886577398786270991909551959925760438971421140798510391519585630295", + "2079922168800710299941821066879214144944285701716208006768281457019751753559870955928846231637034716871250236450882", + "2443388179442549451716324360179861628385294901156946928130144518803278035932260900061916465242704666951488441631644", + "1911460474228864535592358946377917209180895741194546971671291132040378880643177193997306110788712051172644537904810", + "1786947436464061717815445850593017739664828505496703189890053771261912537254578149172532016419020692825177151314721", + "1735400266292922375017275418351318502455666918855476480967941184852797168210224105014180319808533802197773093522939", + "2319339067311423005944613503509297163943906568214008838197374991073978107064158566702770883120705404225331195669841", + "1896193703223692886368915577212986238873638350924341185996511400746994645511519843303140851022382641958144584340634", + "143020738545236804835848702195142155779042282916822504434055944624111837702656726474428348782108168954995406399114", + "558656881824293566357744086445520959132147590307101317934145210340867532552167178004275435852706599240113075661425", + "8674800613925828596713905560315200033260671113488647351922915792377994074621547883976900603906296216434626692456", + "1804882034603715942868422671022777815514123304002787355153317636832257828322095220316254913973995226116233874368590", + "2208468786829652885556733446116672042298831507529659982528665462370310191040373097074657794259611214319312562140237", + "236185775897824150006399653306804942227787815659686077741852943669452708120229000064314541433786754077244762430883", + "1936629624329730886523091669254530922762361328691179508967408884744996995292156910728932574179006761541062334480092", + "1031515274522449152328654043224723609176616231093761533579004180246206678666123316784215317627315946259297827736339", + "1715333162141536294366429585882068060296323902362216872059197788766672171345410227454766817716563016171609624924885", + "384476188719625503608026785944257924005769884406106261044226551335593356340060877329333289245036724799310248729126", + "1073464321235111000116699737033336680773487901834069445475653766334954976951487126155143697156453018764998009917554", + "89305678303935369528846175473375893487815759485496918933057936418167010172765772291562752935870919766251986472794", + "1277940720998610577192250089417270742653816949714010804651264306272572580486392036191413419046743440408330386002697", + "2114091455848735511747508639153508319276328873137814886304073556154633826798843277693087558942043294211654548722440", + "603963475933146981830327962130419617129813185534966936044119087700053342320631217798328633331086654912117275286908", + "2226425585357877643534966373323690840610875253664473448204041664247552259483477490367675399406534709435897156944495", + "1316896271036505402579409216532544328138569599043539888657035097092931674069066228295954739546333624709087464531604", + "229584558406837074312123407421293920726487895979086107652894709745138974765037181508957031999379286190130048516822", + "1789706628761761769737718094922478668586923807793627469544190358810388663214387845203105988658247231884625751201071", + "1247352636301710449525895508761052621993396662071459579631550450651135845602005602938232805842355401833840326397576", + "1005031482187867527924278639871598062750067925351587954623491938148801944141967304817157810655142042106746160868361", + "2374196835009103263404961952403248225766365035462698359793604091378528387614502008494180806596761161536058676153971", + "1059006114284379034466480940606285648869582056120556328236100117862867886650401424651945071855644992229479111505616", + "1722497384537425552856128061692313989974637715487185979018218821405289283497958539966320745495692415864178094448913", + "184563543595382259345299327531225297533113843309152722969844533084670839929427994978310384426830373569779121052669", + "1586189435245239648996003722149490263369497542631407092689790163972164497635794634851680527026698260694649020051548", + "2392408639721167637162257300579978832027353755347020196835425581229747050811006386368364404396280923523639635595205", + "276037568040160221582007317819328257004468167845805665919867545596423241674791862039133585313586831428544125513161", + "2194694043317579847724556429018411557687797431749778554254959738857055125343044805494665150365940788041583224297549", + "1079331714351213417399642728701580786676262188535759973715123455860227247332721349627015538146592701374864645980433", + "2256434276983175107138089606311998594138626014456359451823261768334772213284498271572031791388351478061906916401822", + "2208731985541453041850038336204534361197528520401979548292021815043834586806259718909929345952684187082610688734729", + "1936106564067781068044865640485102876155359674569417431215184765462173253320066002316201246909220480528285831936440", + "145370640267440561318804544696727467579014013724143661150065061148711912905102602794143875975008517047195286038664", + "372023355526438342895083750163765505178960157907629155692802146229736272310771311530658109153058509622006004377573", + "1756349154295061982718172783504384160123720852302689826546764471108013418029183436571595366671523896710267564899456", + "1844580328578012899095908282603950199580182946215921165800125636690583357994053407713912067912546080335170932698679", + "1677980815134722677670834643064054507657726309713165976432424957218030319514003151021806174655269984887916491458138", + "116714438707543629600665072582745700655908101483738340968835394802917793951416345590735385912945997736993304160264", + "198114109373704334429537694207563034175174236950616452871229556355749919744617660818400612145974204796005624102555", + "840801165508071632570116367661403182577332047544348337064476930284956013497218688957193571907818695548375470430904", + "191335393021893619894727851535598775521507460333636266532092366941173106900785334529791723693438333210607290364371", + "866035484295169603004768365782184588445932304351178224248890824955121812639337123067505814058241245974973089051258", + "869930975333475905643657284836206779245219661532256220740751220307173265974525701906286976368978143271540953721175", + "1803910481071299974068189962677961690270786047575653511914024573303502680960695305001009939330668116231612057550655", + "1926676403918011269139381196054443758195758597959587852321455962709867270014347150371261450691587962898709509672563", + "228010465655721024189267569981702115124684296038686404326835433802352468916635245038771998832834105571296738437010", + "605474780975566251143162188163519973556403370994592905596230538989901733055743055142323880483393027538308349115877", + "295133181687959982979478799895330180205977405536914458114390587228608715180741649192486848790996956746425995413209", + "2450686623010828538187843382477704126450629682631599744897050194530736488737461912726399246805741604888137831289882", + "1455886111159443623400449428614610889142308068186822922569072048414154506059345036840717003615699585334170214695007", + "850965261405784349457454663959278566439760374531741415442749376855469793768622611981172427881064447235830446151811", + "94152904543905713614809935284125471698461858298753270780276004100706507640980298304014572466871113531135865758523", + "2452234810908434195117466952484599014186908067111953297790297290010396078154141669753458728366652093726430678685027", + "1049551312802224643215949045270915872635032256371752473902078977818546177308159579971757480262089244769110173166678", + "1878527836820725194475803759374637144458726798813032591067738688254266911997156308189194885290667710436844871276574", + "141202264631440743168058150729637612047386657208086450161562799635355932398641270034459963826117810246855693283540", + "577054005287977857042966981293357392901062699879106651204099635444518733555181174982175023076348554942056856201247", + "1220828459591598968748778249326929812980904370263769956054604081874995149026032854046366382167826847062611645932637", + "1232552708042990756764398285450623726586114570043848294312467889439810866633125107035057416421226291271616365901318", + "2024211930945930836646520741124483874216683056309488265303476265825479679113789248295251142062709023368658284345478", + "204598562864363088719293408603905161043565871434193522765852101052802171282259555456951311467131878998443024282208", + "780403452803500258363463405431031450166279154902618848270198378662452186310300760656573157816151156688478616171358", + "2173475818088067261929342554882191536039913911992731444676651747110098963474459287887547767794732207267563929978890", + "876163076818601678717385062262888192603368623491777575098146244343205889853570140888433898915981937047064909071541", + "1754314697088239627824295188941048387104326311394483559254261237141086082182196918018029358360563144672302133026437", + "190367425110906219848044520877494359731872941549863406488613492712448963744634242928446861040303274204849929429883", + "1833513579965086277523371163240877616231443396972472721212225692490961078444620406320171301521831481766702044375955", + "617777816952246595022069315374566505085327211824711263557488698951318467644730382086060766419763694587917467199823", + "30711438703195751551891032769400112321746470611364232964374075486652023788917502699146107043940200894206003487417", + "561585904509745740985077424727983669089617562069853056218261990474900177984367670427045344227629029845500780086986", + "1586541276016611562345471994774286747740487735639561897630689441655976773363829991845458573544544252353513197753916", + "1109570645125865245000042279066941983606612055589875614195967726751164822590387613090767376221239733483318320849980", + "2000871892287547888470064766693212666284710932667915215216964086140561999557964388554910698415388110690756669254046", + "2267872334762924098870633898811465033633926003832144524226902520423722247556756938654201033700770439961346897541750", + "426603267498989820112396343156389373967162817836586387569156941136301181700861393897116769008222061626925643549501", + "84906471824031269312272287988840055994213782105510348257113977824818488207674158517970686588241407375576009531391", + "1640552681720710356285585808794298954901556193985766491624608992367627434300516137333647676881873882034454699194079", + "1694032854014793619497013677280745520482217128288999322407942857514584792765483962690367905373074807740772153242780", + "550847099589527186391453497908560887971423250145666618595250921345739535891670235930545976028659324979098562287199", + "626004080769243943657208372327037401558099866792193120027341284015628292794283986004665171402729700410927122986009", + "2203326480839813437725449054579186630534814530799744884359379683872055937055580098036428311437154459269415848454481", + "1564261624129667192087482524648128626379958440068599605517239632773310066526471885209872976586875465037929978229383", + "696071211524255870793926748644377129874516626098575042395192550409933861268781549288995694200336108644099881956567", + "1285235572505658342835913243457454387830111611440317226755847883527274614568720304713847957317783738600383916117737", + "1858392744466846147704004749198125637045787249717399380012086021072610305553566879790249265333779195774275620093447", + "1939914641065762621069052747131183505244488805905582577740888563136081737027871603708180627742147113040410641377115", + "1342500727337007106141659811396033530348588569656009034324961527944781537746259409243615506578685350730784252432257", + "796051183580510802113753720891001054948694659254668736359520893587150664004000868149429044568146339326891627661213", + "2302198515530003918281419782714712341222416816119485365839048232694768447087938822388900193036214999598280001893696", + "1408895945427337884028189553475424318483024918673016492598735087913032209359687111498161121956408704925105856480129", + "2418353912337660591472055772659695416115632336117923167318801480747328552761721221192688218360835990463036239842091", + "2199688468859410548922700477165693202907341860750481327291303915833241444779926225954664282383639212430081796898229", + "1182090301702006147759400485520086479457030958091854606319701641840416780613757496015230782385083497090499937458102", + "1720761252440552342643931363694850483743257696814828846504575807325131831354468087680933283511976466748213290283256", + "1877729711323516045767561717252070942143331776900378262200262033266889956975295501973112717954418570436591033867761", + "341716924421719842667626521881747857958116299154816670732427854353030253172305285097781566530233527905056855772392", + "2153004294321302925700899220094558866033952612173254235381891091730360747986558369353150051416124989468462142925707", + "2458993678352596262546077334785456884844199634373111105699356880920189219314870195608084449035934698570358821688380", + "1986226109825979594747405456165704142591754789851133756783867434507223726381497939782474958403172414456705311408727", + "1203841109076744752061939755107772967874829936853723298807559216230329766207288458252626004908912781234488374020638", + "940915299701132381003125672928302939056261743446750740487260538965527054012601214486040452481479871442587064908646", + "1477014072360582719427430316729115938108502700367041739457682276729736495269151810818859687094039083680422009195292", + "1175782981425218292434123074185990143850524508090498452791356141182008867885306269296607133535187039339141201360345", + "625196436518479388014477753958354165258146745624113075835128701619567565851168648199851376101381371142101258714518", + "1709339754219907575796237986960642619806103747651003411225983504820025582313982331874120929381891736753595611280858", + "469507508184108219899048822791397080206613541246488650398566537203375320567423437741864386089737004440780519952546", + "377737302779498056267372791999276155840430247787273062214595117303236262824500203320920376960730926550042331763051", + "865249836763503574218511159493258644782536357557896239549076408942870472684959069827974076898913430880807177414429", + "351124827409813139669278379619790411736089393833440802025753774938922940705453332059632280208359765911804957311497", + "1990349313799815937739187093785718020165430239647344766976221890242115252368617476228868179381088598952887100188906", + "299214893195484473687023088920396937205261160322031902026061633011954607560185060184094246726021503201168519751323", + "1818366332253053556842216672330829385340681960259320169583890010538589809663858297948443342745157792936486680536483", + "815016369095486733740402522367982541791035002836068143840562536751606393115785114624278110054371165515045487595714", + "2309652086017421242605623255980456766830289459351147847195027347872351744267452052399884977735255453750154633747906", + "2009875403291597418682297324851461113929889458576027339825630377180227343085401750885799966988234439774905552638132", + "1666785993069345049054460270677128720104525579330122017860703141575061829571620752331494155192853763462075680275795", + "851375140560911273782463055506919043335204402206177103997899735774069171730742497528041321554904386578492050030159", + "2060861211380615602822949037354372361279551377180150193104422713576289619648591860831866630053438230898936191866183", + "724024833588802745600756411622952188717925846111047951572491741317364101277974052883963178841351429214429131581373", + "1728015821354714677663655803281502218014410792886166807101309535639614766730096399122247067498321171915895163264932", + "2075385529516883203122101510897865777126532285840561927754696404658521285298582417388094770371803457370976210206692", + "35274763026359980683668038234134222719965245315157115433199443903515422882014440978640278398161965455449613118373", + "1552843861893432314598680918723296779220408613873277674996040531046441955790412159947828695841505612493151849451355", + "823074226438417162864209359107871483117400399915318600033689956601416621829280173441482613330064136212278620150588", + "2170453414398091445118124365600213731614029797415059967195945863174058557702558320842161795637503507320084924969508", + "992799508607299781098651598951318570318323714687766915047709669242257570202123958786658835991136407646229536377619", + "2059160055961318691611796859262561691070431647387809744930827589382419817442548081345384981224861007784341151603937", + "180207425250590930679210032615561799648393807417949235151279568505516284636270573282266255284221713335034109931016", + "2104336916861185729018442784395015467067334162877861176130133713445168242639421206958744305847669148099624145047096", + "1447600914220354916892671016987027091534997424967961269248365996026396919062573914260666883254376391233262994637339", + "158913033105072163464429962348120877931258205807196184100360477975288510950957991501865760644107040856392191094546", + "1409906118600206047084899894041039346028020188564360081497180086888178840024983496748779776545503441409522563215898", + "1281527924802863264004977813272253852540130474374793018366475598429157370238365844059851568764730167459147106008927", + "1406110384179228666143875807673686637312379976203286005515417568428424991832337081290566342254881150043309487016826", + "1086184997166968452663033734558395666139488897918726547071731982067802656863142530482800799013626210752692564742126", + "1339366778360004636343334760797246888789530472836752542000717387712141550702793253639668357914409631141836998334488", + "833060510842460154308247818640603623851731567291787712654128280149692403973160072120332770566338751273504753675212", + "679766199337500380677389878159425891249204169585514126143373145757405453292117731418354815612575028018078329515151", + "1727445464479800577621445295254939054149519434661809833318426651688834799473682109926801897004246796290896438866948", + "1678650033627228194266205495271626558057977472555847430549739632850761717879245499387442751908131781373641081853477", + "2178928326220784677864863464061025267436016578644094601928627804309239748913447817868678125613131875687409488357144", + "1499908580048095876558526548940838607979288547482490893957646651167058335285730604715181198015448320162185185470215", + "2118146144977503455515255561526534516993933414414511087820030928628374721703886036592184282243578239200025564419987", + "1405958643137135685372289593671266771084688566435725357050434125406415057125566892932398722514977608111747822185770", + "1185151907830499956013916390339169229538645362553823560266622144341185775051311505675122253347066523061620336349441", + "1498391714394884995498003640939656499636546089630637467072399144807947122702858387980624521527047379593225150370746", + "38995466538330503975987395440905461664913945971202567569513430379032831564721276204895454475131128561100308350697", + "28784680125606112679133718649974456224360180565219313257729660554862238746101189589244737937399648919766389661054", + "2002481497413460031772137148977376108698320762321445976312694375102042541890915126134084720646433373490322141424863", + "2264217160763766384091092867400688249496476780038762035942218213706940462862664161923704716977799239967173395593793", + "320967705749641016809359846363574501969236264853484930094003247458460925022425079869890939943104457421848678784946", + "450600329016574622075906023909971238222278223091941661874189724894618521973768544788353015139045070540736489399850", + "1924627845431271860649447763317119608395744332591472013818125550088039592854044568720735799184556456196928604023207", + "2426194782410136140840419405777359894833240237736714439712413703134316934468304989352507177278019883620795628899578", + "2345068992970794760050423920351953105523897366433887074383741060051622180053194582018544284356920714207345629518190", + "1672045168520143447860786984547998515215587995574007102073983669300819847979568669947567796760875165756815717091896", + "1431696496187110307290967537939098924677031748699401340531999498194227339381056459167346375093439636358827890910243", + "384792717713698114103704421474526323610536465524756702789262948380542512925240192764798574778987578126254577272616", + "2064376421279985704989370307800863074609690142371435783207452920310580650372156134233854435147152614933473132327769", + "1214272480453516618234266574049043265760345687562394664218754996026813615932443842014181082368792542287765276693949", + "124849867353712080629816619167970072930938793828613970254740605124042634870062463002936985224595316556598099555771", + "1273173644586274579201211478434762269951639245894477182609235098955107620081252651208994490757777656189024378909032", + "136487525557996287029680388008223192600622044047095354694963446923001745140092430945715379123783992225467186495140", + "36278253766169035871072854383481854162912803785517344608524676822741663198441500393331847176830748163336174902533", + "385857460891108428895922073943160823804170389015746011547066617315002138956121105343446745752379855293541538599236", + "582647669961619151146673961874644257549455672247926123188936106151986526783412365033880426389907008096657772000701", + "2099463038430111994240563061422774704506829951763463759056232812894036643366990135531071360804916922235336571101850", + "1760177306807532530692807665374534157096660184796647326992231298375479536252498201005465280972020163114942791589334", + "2004061944904801531120961382766492965529522727648756987885333577135964590512715541546304438766923895693614945948107", + "828186780322308763971929424020041044972507134648277516460410151128441018908486531085152441159144989364104431345414", + "1918146861660850358392223302587315582501441140237589828561264208904997707282252544980587312193413184605891821081799", + "433056783391169619252199815344496087340687110016131513223479994692105327136798398372234810222706551135842347481381", + "664600260975867035969767527213707045180123927239920101237317075325204225341541707230532202229070328387150757085520", + "555493395382797481061642897913807434034363316135665973293395229562686127105430149145095890378863755614641900345081", + "1772924540133635454632512574394528387394691701359391804544091025944126772811596214267327506697270587300114939906832", + "1283000732324802867542343391206614642107973837847200024394559361609202460108000392476306808015518892052788893177899", + "2159570312232286607952476167206479403266045417381189689153524557958701690579282314569745920843091049842362831250478", + "1931128757679483539309153583786350684890203045328780039934244958318871476719336600616535095935776266783536035875855", + "313633251227720448104046030841436860726795397137801079676516392611710993759942114437632362799384314736084780326060", + "926736268731963229329221320332475051959073291159160686568157131793010772319472399287785822587744041178766895167853", + "824835448547604928158455986765816641851132173813853688272989031822277661697820075041272379002243512262112488455761", + "1085903783693801440864722709104236213063003110628772875974737258460725369068691214977351982432825562027918321399594", + "1736011406526500920300618439188675670861216057827874202073323118535161978587135237187904282751540164875198178773219", + "201399348510402797614816376861316347083665893668238811439423403178635394093779719290064503222579990718932846612095", + "1850106577105400843388364320448453112937145667285661113019180394818316503248085394921738039492079882093000589357238", + "646930147838539482294534255736019979549226932279228686472406036723101066918564037143459258592909643389220128594167", + "1841767095548738703669966443763083477704886511724442381248988344239715355804302328037528630378801786536858617637176", + "1660925445991346319284217920745876614986360631912880267126004021384991176507745784985733788675051478082936693466058", + "1300381254350891366645535706902057249962290282727443416100061486078417672675681096876532242853247449722551198991902", + "1131453428075313411126132265798249448307182576497405011853148057244733363295878930154084633694132646848381774758321", + "1586044731736091638985688539655219087511127241561503334629652124923323765009444224164101098332796851887320007682626", + "1779800940526257618951982176859945340314479137906450739958098359296338548422142789911272999283073471976692425617196", + "277459125718979424813724034662392685491429032864957482402957021666821273986523555823022419271921356414472858442669", + "806303133219770000414447192195883440315077067498669379161958840116308490938000197314477763534243330270125880073399", + "1458588998378470343967874528477063178028848558669121612161546724050309241382221415014378099163929230865600887350007", + "280307259903874066165514285592253185112168485929293510045256208531673760741306839290322562954560677138141924396117", + "338042384423071618421938655924162862930537606390562943518653454553917955469515305536712240250354719511540860259964", + "1732932147882224780757901148257742616293151695181594767555024442469971090500072276801730951568226067942880124014224", + "2257770164930941404091708817838816802904031481868489072487236411938267942428938812173893846405753455593898372788714", + "85670851978791100912758179103954614820382898072457169460059257180427167404886087753108487854723776526745545699486", + "1826214837352169208649971155865316378894785403535495162382623790388213458680746475165842967548352869737626308054505", + "1304173556781566648966158246582940874648892251787831745735640190315196592596933396554737833086619008356080152717629", + "534529576841182532846391899353917256795049442359589091186047395909686121609017452603728091935273554397384423517012", + "202799704785078580886075934401140201691103165828890205073180686467259991703638952602350264047146009880958816828159", + "2164020382887497795039058999343985803285240271580858479264276407353710790250010048986706791347721242898661504740854", + "1886154750268827312372121497786637328426887940533163212854282063568481300479720986075319976639429892056550299087635", + "2407975655501760925087539502990629760676949807448320510324579288386541672227369824434460402850577180486453774809633", + "765575231917491389295142593077404974221877532681767420298151116049853093021727823647166503452914915841156135839747", + "2306462068843320379293130181585098897955889589151753132611716610837119339200615845720223553891757839542332108781835", + "909993407346299721178200241415149694218465978048598144142688699027095249252847579546669942622325508750588950437494", + "425075231347388832863577896930558737951227321431799154358752634393881102811413249862754120614874658034607800681178", + "1907426827399994100590690632522811530218367871602188309732141542998241144664847861514558920464060373036086068964704", + "1766194758084919143238483203114779011362006872599566984294649032395095320682482356582521325476010902221821807716771", + "527530021010385076672264383393620128279400331302397649277300617348656229169883063020633000231832556979448999684182", + "2446594286365008033392641318209081334365850711708895593152922510866906076436304042914918701988622894091150863351384", + "1854967435395153168422149352838255118136193913276477493213421819482385160605085243994787128025276036073452541051843", + "442369105016014181701974239340090302733917799077020490916473240696917831431595143941361929044624377333174503956028", + "1852441957994017083063004399699433423707964941099817894266346184855063454741757737535242679462685446538256498499582", + "1111459503010819238828725775811159017724479587832786324996453322219475911197929499452021086164484132611131454187413", + "806112737040108555888489294107576250662516202664886323074323134107891610397078781207764477394674466373602413789128", + "444229549399748874704746394784818983474787572960225187957896377183174484163274755787591651846721150902220728611092", + "1943559766697636649598549879028091039992298543566551584701096250558827733209089225615031423990305846874167849406717", + "834585430982623586825093587109449415149697984815297163527789827605675252163914634692588072794257043984920034172747", + "1233283624147380150405312894189514091907783547039205594786407869324835071778044292917208846125012610741824487877096", + "2070965136484281660241370018654983173624372038028752478651597413962852962300413251146246859046589286181029668352305", + "826100924199236772453494384033119965441163251819563745390512360507958130128315001756529752651922759813012106189184", + "451146742948729672818077883862693934430831789933755724087919034752848646792626669209344028607079444526287988731950", + "2108159896154512940685422694464100403185014129619794658102486773003339543227713772413373680119150326297776256113336", + "2169649329087523633797371201598513536189705184243713972473156412012445661674482780280869182265425962802102514918893", + "1568386532160896072677872164729075143241127641070500068305054848409644629713765392897617229200315475459524652872095", + "2094776247605375594129033895316658310297361731647103801761315977457971307310858753017560947069587757565086043861089", + "657452391158647910877197749557013563302867643526359438025371346671438199978121631811634810801211870719127501069743", + "1490914819545948616007916647543992306512256334502426392573404658951309482846100278834464592866348215580531493862738", + "2303489204311745941909379223184837872771491964409536788525890930055908667189822992734376193213336680176803868798485", + "2012685017433348483128858805766753920060497422694567093664459092453791737894994012151842672399758159351473044546657", + "196998584313607676786725602907794966808147824519682479589742109911842299648216625817515513126240865185351224381778", + "2301914520181426858095300905153173984597403708659637264872417492514258456750434761111551191232551778735222013137463", + "167119644694415693464968055689463570351540607149765709780056134790279552445761654625182283402110793494164514645506", + "2232645436995525385935784545126355667912987052238726236166577109179381175467049771798081807763886234028543331130015", + "1200524336293823699598579809332530316443374907382465627638221246752903444433727675127140421884651412050993641776964", + "1829217379486498540814541394513992772543868229268745232013433190031662340701507076634543527823580373772803551159580", + "463757115343965145535471188399740223277615154909961258897167779835105602948974292344822964599008364654242484619574", + "375713784188331520343678658483527488108493114228651630990197686826341252071908228997639694595792021598460164525115", + "2350206942783867830344168417246545345156037367849735360600273910524128048577749706375333955263592002363791271999350", + "670973392409929246903660110747975508237801107144364888203010900945847202059879487876736310625441043519993956976484", + "1549930606904534632226916897348740829895374836696777835584361191686035520643781726802454145659068325070143897087616", + "1634434211692239410208916383865688779480989171405692521024513748689545578905138264923238910985462842538750428025464", + "2070472878051702129589239710430999344064838310756749124335976206937513370298929699177961190718585476117836206377322", + "2093132703087385620956344027481537529953676391745083978522478200301170067244699852813152809676379713853721817372600", + "1080106123714770216655644912625994889784749642856540219524152838012842555893282970660535370062915701466950706427249", + "1054081241105735760357910776295148996778707565566950059144261810063855559812859532524699051145034710394285386290493", + "963959807676835240504484727057810732697216647458622620133815636333477268213593942185372361102852479220712388663056", + "861633448316795279794998700048936571675045650560158762419807253713953627834441920255529143845846179007096804736503", + "2052070891455908739379326647408992169720834350602796886432009290655296541914332725538818390255525591192967902044804", + "1907463443011844846738818719256154914533977505172268426227263630384858393471908563904938494017854166048328840573900", + "134670233387252500624677666319322634704525777564766414947891637430331280076567569863690670183387326207844990127975", + "1362934378864924730999719565537137855893726828186123715620423491701011834991120235934774777968556071811768415322109", + "41077822760839758204402014785983314753623926031364002114341977021996246664260618062096865819144075373479424223367", + "2212535751129289613161806905498936710900993756749820938299603137195159743703262781180971288609164361919594014957504", + "453894197267781449333766570596977339850997103748403689988056977417114192278951244978238747412731497111681638802182", + "2405389052357337484309763423569127203353300171280194120645819081064487494510267231992300736552822246014733522741896", + "472507450430143035541272975247847992816303930265273187889863486254519088831698958334912764290283633240225173570685", + "2028580327982757258286311790403784448936971185579687874803269275623481935542343144352385153387381887279014481786505", + "1405665320109581108013268713756741396831054076664812815681676743946137581998720273148888036898974491044283615314899", + "389036232887361590371484986309511040456222852134432005841007852160513113074462308318629648071798544477623102938565", + "1706532566358441261652373836767114235429542953813638817055230409715315109249214230931380969557227778381827758657812", + "1505128355881972026479442251969126260177688356384010801741457435406342758647719854827230114035065631228907824728727", + "1085218778575813535340771669753554252702045309029116947984068449887944862025194972217096999552125692411658240520011", + "823326627446312503558975607364424812675761801922728333351489998044146484768578559047282503885566372107089797241770", + "1236541809824641166856976719529685360801435503174463774360580535349830683201896583481538516133417517706554351648688", + "1907719944626690160046637407504120882676265329527221119869839725663210733244197899681572843999722228176269894108354", + "152590090155973761025179418744420906101883765191997641758265352301422231192780034703487332097421145852820899181231", + "948570747636500380620527932143803966796185522427945235184091169876908280447214530034405298488342800713166888847084", + "1476129820418470492244883076451187786161652421638544993375512588132272114181886569237310698570124284077788586142914", + "2169481348484395183101284346371014757807007628661818728290234304618273507140233443681695203538648846285848702074294", + "1359985383234020646450838763129261981914862347037201431720185403740181320314619274459147028547674827226086688651142", + "716669454375615598548122804133900896037289988547162121406502295922540227990531477417148070259742056704134315486054", + "862949943141768618103490596508669813844878754653305591940747357621365137690112745856179491591325002515251734745498", + "1022417580281519912141643710048749431720899274612295835062289205666362110548014202631450485820878676197431986899115", + "468648194373522281733369798079510270052928831756170980312131725622502335298349459327045710397553281254540595590159", + "844292093227333364999249444608457372214402672255222096367166859802692850661061016816616637756100923766426168718427", + "2188858154801665573387591804492832109589465501862511193181403847650291843064403936109943041420566880173211534105852", + "2042883581008264305037758339608252285537867056877427800731916605489166743619172476724938104513594315476666016976457", + "1483120895980450624180229130241403202843932285665551252742900048065654567232261695026704289638314896513982098727846", + "68820412072820087660656880049157354980741412663605646148989546525340912550682769615638547456339041924674411650530", + "1127693905200922153288647040368513842662718572462854294422276661393369326091205770381132592146201362813202846988702", + "798496738206903574011549775827484104970890387512399960674134862637753336921619033259229276493438231618712693390292", + "1084800156171773079084149651566705469736612181058038943846922592316592050061003994551141620799519396009951310939413", + "1881807536051067545012403167467228643418689616345205644960760188566492363671199832546438074380183377249629841554312", + "769393566883808586843046072907987535940892739778718924131152024265518112273199613329630619746645316681543745250295", + "1323598523885621998174778424161582962415981892030092623650457154954920278064166296627647252773108181810325470542723", + "1124429161618723710173912411093821458779479693131704743795721583899871419125208882299628045190152816997314963331623", + "2166081516451049156838843788330482572451574407890760385248787990950703131070667672021361975556270283845566924798624", + "43935441686494302565349535242990063064142824663701405452692153539087061503184781611942628015173049623563772376718", + "1023732919401032095707406776829528214394830028598298857774642666566723345605717964993543801601386432250377246247418", + "616371285168913641612962159200582684418089562859811951627372384679457185897671412876740085078545665643427231629305", + "1428247252638468835424833802545286937066010692948800957787302341281955502608185295918639995022501006909419486567377", + "1957343653009198272422872969422755750281205537068514832613164245358599701929485869950583681093648324062002046706808", + "2229422658315184590458808189025364546390486343001978917218493467729637715124327490612012845767211608791361558822673", + "928375908900227033708851297373680213384833658038645808665444130730469653877188029535673115968965838069021287985760", + "706351122773417637243441302082067286044501883442766514782092302424154070180402946154364569926194162105894559664579", + "912037848825640867233017627020903508183745451725999045521053057751837507418902377868163668294789330273343898930385", + "1970977307123351923913861900001000065688365669616842267123644299672549547533852587091435836115929517971571487889717", + "965193865330735366953588352046370356345949276338248835698256127312382352897800922118755695727989832024874560254588", + "1085565610327834979697088053326022412157271645627995967584870722665578091907184752364185310485846461602533131386000", + "2048492922625110257930912590416969685822409637179123164536176204256852050762748398776387499194179155887249772598380", + "232903261479787479711404619745847909445608784221555822443603762562091448259314767511268001094459787358743367899237", + "1174857497748086743766950296448304238379956116565284063506278885186224400192477416296053523899821219783804674375504", + "2167909066418129282065075991991315198717682378718189696335735888434244553104976731133557751045934332299190979154900", + "2417711982025759845268388544683542883317886150301078096895262353100938239097177790017450538700965836500693934320698", + "352671930627422338016298792178242977252139822526674257940732872190160703973467406959713113199199257364558857736636", + "1530266312265565298044793802055590637768754577723666421202827350853749424696455393051754897994806656891694686066108", + "1709018653591264569665340011759433127711689409715408299890145188638556207069876373098313491965184873868848759592145", + "1900123489998416026334911031015025513834105367975429048722682430053181460266925691657404528187976044205598636322768", + "1647309500182173993814685226552123363071767059061209734447807556537985080241005609602372239059138487286482662977703", + "7573004696882017596278994747889656454358274048302309367694557065229839727496438786073753781849883753429767994943", + "1043559911194419545344735644468015021004855623199261377417945887221619885393480339686333159082341957244008710507856", + "422489400133347158881440010714723748172717969023029446096138374978630138851555928358088805660230444515391670979444", + "367673539821795166651893252985917679681466448291949791668308353143106859796729594953520427375057267842123326948431", + "1528828719968235754031213482488812547950030324395557511384353038789481014238156587373379045864401684617614115525647", + "1595635287874998802186360493011891769699224929970044308428729212485403734988199931734895954327745896670737851121179", + "766902624761922478316806695755216617228739466135865918015839807590233301469430507796199227660711374842050609564656", + "10468631171329773021104242904477166152388669849973732171412860918060658341567898096558074557095700201677068442733", + "1412548690595280641521356755040859155557125652573661819629948645005342657799405370738411000144253276432659636982567", + "1992408381654152697371397115361984956119544260051269723760448369344078990832576393654222852305519231727237335410389", + "404324508764374521695705406882525141376132514817206556841646377473156683289798265617357698469173158860561027559861", + "2184393896417367943134972647678721466092357885446808031914386341137399518100136306877782933374208539305039489911432", + "221317024228695130400573792983215040069779928574640173296311456469556657101696384472620320868071440338860898614955", + "155866739734380785457684976484888507543311664420224854209664520135253341258316206334709466618336274876350723813025", + "43262999433669875411391400797048750733881874020492117604461643636380693345927598663140724170335603086235143677788", + "2318077029060079953638338804536068959451482282541923294098441546834706802108364281776498510064553034443584187113490", + "974427623422932254947422371137827772359026123676284392902785122679117950424794353373080957601573029279541298281018", + "966223246869454619533530891783553744158533136225343978794181427239462146006675352549006334856474866543270386064943", + "1711567525662327663556522991126913632243924150199843642411909212151843146284997188564252021424731638759444696092916", + "166864634503670280331415377886927185210568757645748405384706941960640165700373793830620688692606410203855837930411", + "202344026172900598573644154202799233031714733215148077176325918053401772542253570820956153193264504322065725672062", + "1146999061592542046235249392386830566060552984384071300718614836599257581595767479422158003316181507171551303982138", + "122413363692688442703741629070046975939250488519958730915081925420540237778191417258183954934381261688499287082515", + "1626536533884049684520313697717963693090418628087775187438970216126524568036524594393206682891584115253094854230164", + "2166772986081025512773610397404528621857499370138129306922255170018651375665851542440871299529351332628441229042388", + "724892302452399908273805403637968424854265989161852218671309719213637503276216058269725257375345332017499754694836", + "756646540124206175084829457116695102748087784465685767141856673138642008439510792285983312872529156397362884758452", + "2393692311665788491432130726242365648909304759760756781554144555024344230601507657987625227916921147304446882674102", + "2026631743989187853458699193218203279484861583006278542004292732827990417466224592675735800844496187297971274259267", + "2249292151585845519742040915540600210803047923869115177829186931236442936383465895227148001456443268358601446243855", + "2383414298333896981833421271338458022748036223253856552023675198894842842842852776181328796430324844787403075642184", + "1773134728340561143673956616497432191531818187613423674990499328793840421678960567347313636244939201446319916052631", + "751816619997261815950216922964930020119422681669725862486328840293205478987776049078020021610484519571290668327435", + "2033512017160686187273355799368065544990882419420882512762278161392180954353327088780125481529103231058066188064740", + "1370706019266069724753791489849106290864801543023627318349396333672927110748702298818692622081650101383097199858486", + "1243799082884019090628900021733823292883655242527922116449936915441664023543041952306645673081964016277595449044125", + "1484725721855143347683180565775297967046557848819965067340713639203153105938493732050507365594008830896382041080900", + "1500133284287384984970751774243780588940381045595127596314400492676913170790488135846890185183668776772607210198740", + "144741201557269819382400723859162023705834672012281626621484657042053433843344199103670838638881085955924257118185", + "845146889147362185111969598430907372229493206968045986633063797215810491127146969061275134659836249232921843980435", + "1630518844399086238910282431669342283109633450424676805703418073671483451296158611324677981441817023009596075672276", + "1973102025777694378049774832117939534896304334005978159183314045478559128240344147383628766936308285649690795552080", + "1345098486791380442617380170221645962074940040636898707182381184373844950194698508427364922739955372791448189716561", + "2180270898998625793583399014760154702368205586268432711401921380688349376790228630748878375604662696221803340626154", + "1101939169256090630548488578200617114575779892345887322351326674385428133519135369358085528031860142578055134276287", + "677109471130079088738588544681148500825555661216740690458942624029686428613294881110639199526925275135951277272799", + "598940486175857459835156879555890357877266264006929945632330129159811287461154899479316906744110624104560711909561", + "1553304970225409594233103820789826243226429853867193421787038912400950826872369440320555380904547506779656044691546", + "1291487088303046719006043433626450116654569538207136301123991373419523656054176312199956686234870660226271491608223", + "1529615360681438544898952232448530715281009482644451911782300555548776412858116631158393414621463213023548482954614", + "1671450413297839745306832423425493199725004641606746982401112638493466153418565163239804388181460770610916062796301", + "1640204438232311366278646968435748689706455632468833969391174429129153137534709652693478987946289413570527635782890", + "2243774139828831890038333627084641644013890397825143465590692691128658507695645126794447975388968446487101422819337", + "1204714158557018354748053416749380921307577831042195952402853068926022841909063855152406296187693367333763202572360", + "640097321535030030343357133053667609440011429995542896420229427555357278376110038199500452687481390609738936754296", + "2417704607654844968231095881005379604571034494429531589776592728449028882989051671272464027084612351441860386056478", + "2378585208724575274234014880203970126754875822823442568458022888878746903483243210990872687923715998686596808444493", + "2235108409276050890461504185097517112987543140143713789116373466588011894499910389334719975592204062115242010845319", + "559431015474498247363252652126910043691326073961409479659660300363041784238703670692942032101240099428995506284069", + "486948982879865592787122279356673509390547615448359409525808791232050399521506412562600531663389072465928882337013", + "2005270079725961664359135305787373085036256322041216875548283740607063292664178043718463249917874151851184782954334", + "541371017395940818553472047414882593714122045026723617095925365699896224181580264787688353951434864298296154403085", + "431849931913888304683842865784744898514512366287811741324232080562674640608216863158362717871079220812010673653500", + "1853934583045750764487027656405813041217045387982237358584086451269834634541466951552537383206979616158026697369324", + "766406015689949306105291684142671532580847195801577419773193103722346632601730430353873335261900819377363023176053", + "1796820250739603251836252702773438057223460214701273541910162238772703706711918255612927580648724489425951021356835", + "1406553091458438850589471819372477631484003565846247541184955413320466383862633071669585288580741377305566265896736", + "715357534800221885453766555631009467794850624376476450514390045213966595497929174559901710817606622906861966520095", + "228535841357837216132920709239009259021702547648106067926389999865015122072055243832197461496070404459630606292395", + "956371584587957538895108639459495479398235388118351682722223214939207750541900871228562766202987922053476866382153", + "2091650566248956152623386206534944282011878943153826852905538278216813290223602431859350307982659573366141727156886", + "2353168529439851690433049497144343663620966313552745266068308090448802827530633406752438070634223654699790277094827", + "1284741456618648867858814563476755090973174741556874550318251707326006970799929148509306909193357786952290727121802", + "1525374264821077088521056506715511915627414289169390309486701884904513431258248118482270944315272284871227519188689", + "1242292512121115774769475700371636220888704342079058609881973140774502282489050886196630718571865596230879355858276", + "139813540015160218631990836626951650022844778146934766773759625432308865774642551619312525209972280473700115646792", + "85119726711289200166943212807910229816223222366939337523183919095618599407806216001950876288034107475186866005119", + "46584412173013408542896704426335695605622782424243246302877085305257202251484171537505385697529422797064666629598", + "825132190016541220313128048208542080630910368222736079049967094651235172191484838316394553406444969567635791180051", + "444527195823840794284330424882350745216468158143908317926842285277931357461988681889894779502365850392775372143369", + "1413900404933941420349665795686362710452077559482756332028597948335439216142657945057842688048836844046397343298874", + "165099707184794516112755302661751902241269598911352079191115652132459380760042091321089674751470900959944264910775", + "1069881205986057211773167407171721774225260038151355082609524344064502509351812938946216583605430369260044067189723", + "1703915986586012506580699723979825180691466951794862675851912317730854668842779777856732259327089454721610343702879", + "2298891669951482008420605244726476158035228054996457444864948199734799301782415973916693957069043600330055042926822", + "791948814998089441047012579992163402627736327737623201076436580701095183051563384539484128896408507882751186150803", + "3923069283608861232544034641668288235432219702510200885322534852824275554610678876519481653658822790186699817838", + "141557541190268786385521217053253025192956973012051228578196342560394691248682867436568091488560642503922821451479", + "1926339707933434984904164605974145801438598353248227356027960092311980130733075688105684779131618507495291465603183", + "1575476138122699989883963334331691458216156671834060646253653854784679404065938464930765446281871660398393784284085", + "14251654079090190155242908074091319535643199927776553259262650680229708062221045750233669710966080154382404871347", + "2085967179149200046614006987643499924636592119743929137735129781262763295222179377959022759590677615687008650505334", + "520034940520266687610782839826150059837693900201442649768280518887248488044775348198434634261036604704441098533055", + "1978078088075500254594159486425970634682274317965672147298513517044131929876804717225999165709517060304516045627503", + "2451312505102671904582895341531909204396003906366642346753858593129721135589541232575979989081895619017144436124930", + "68574842057027398946766986204068846081174910404315400344084135194433231283636718208100975549787511171745857768288", + "255783776272691962546491708409725363171016286043577663369771814098422452059429633502062150863662235602689693398195", + "616574579503134923421346695955725301920475484973092719901809277736405010533614902096556540522809302629657366661034", + "869902327873984925097993469324761630514822756391467387552827325250632898997131954109180875568588071855605844001847", + "1782324354785748113957269930761923385226860510176141074435251551431485961267904037604702252131071615371296963554209", + "1115343135928341053875841702540274970499428887710729920178509449882345322633110816216764757941719650140418384874178", + "2357283313691325319844434699227819315594420076444370705075859009590932871729692814097286782823040590699778767268725", + "1729596299446646249098543600922099361939257811020663475888802804047277632026846510125874744321023106253396474549324", + "2451152047720971890813059769280138194626081773345328022430170069525658496282709290852584836740642899569743929761758", + "754945622525258260597358367747986868404997474391923228699508886967636810791017511226979133741836208959651114603960", + "684431189328820682686598974025678898967829036974973007785608692683901742401743741407178101722791313498187529544494", + "1680156183095991412627048323471263776167711419194219438631899726512552369282062204607695920648126116252022748080122", + "772042383272290653022836854636520305119137379245290723180936782635725161860816158255687798570115504328825895453430", + "1969907413846951455262252932564712113454808746306459168808836861283130172685868804552135903845332310950947098150450", + "1254652827756973029743628836729777870740634700800465754362963241722576916617953005836760306696238111488334094831260", + "200907081249080100264005717258801760708289712097376308408885019049817826244119954554474500545039641595656062484175", + "1158068204413655985262445325472291733501580473160930427734431410457436477339331679239781328277090602937880571472627", + "856431905198773875825750956956816859973341693457580661338396184042358597237757703388703037865433963899054992976327", + "1538574174568904003314935652483351369392865786955168891465740221476162451209762679251209169498470523102151184996589", + "738404796100853357548517749958063534688344185804950912652360493775005913473834315670916608865828267199339284241718", + "1904096370505322456964068091898636182209257737619783433481517109822701640334375435887571403202304530559689559282180", + "857768048476630016755295851396330058049432444565769288771806837288219625984885375486808672068747668599503840094507", + "1705541811455104685026937318827591519710940450095567851198086658344782705127486933483835504092084396724721143333467", + "1317933114349393597207966034308992235848572089661059549773919283151174388485578747629132354043847794053948416880013", + "2378637459134351818370337616917609926042935260543986515135559851156070233492199739825194145114762105619055117956283", + "509798466768409982027994550677882782739337856523879031493368953118882500471508367813218926529471178372117326396461", + "528221536928289893839341073323203204866345061551542777806962487701299718232946794990736419640123553319131438263526", + "1228399275281316010313205717789420455493930534680521540814850231366360866572053289918438484462561166759693935851601", + "2160175783315888997280083875312371973633329036572813769742476715600321566091506986795347596068995590637383245483142", + "2353080360729315469236709861777948249967807912676090383712165846429824375076001806777299036943733074768323229226518", + "1609536635384856240212791707847886641743302549912482035038174413989557521280131208280655728504325516981286602595078", + "1956526293861725824509216856457222186247409422579398052690000316431922468374331848982909864035212344415571453484225", + "869153325133605795837309286881877580915167667768837672847350164128102498849360288460636350828364720160813196429068", + "833400262691429508496052360730021971199909403965953965550130733661605598827674693561609748268150520691769255767991", + "240069907767263682816006702922897836483358981284601910811606531999678718688415469738715837324222663853357585887469", + "1509881022466018645294365175687738084709609106237259442984297141607477946213723162131554249745814453362414906610329", + "300092487121106907641549082071836060979252238667072589589759308734527555901187716731332358989468699888582842396369", + "1772854974314768412011882319623400591965995036064260240910713664814396729734520426439627877673310440747474744408401", + "110382789495817781715652220955981398365896376814385900405560730153745980616602338665301897449956547710614318724995", + "944124995459248751925010012870672386990773456483695948663752478334129902608588826649054291720815862456852851152578", + "599325580139304735535487804127569567376184415987004514064220971518195165515937795368778557801128045221861235988218", + "1325844853250533269319009421877482180419167794932478761777716781593576610619438038577756504605008137730049171543441", + "1094790548036433521847343123005596313074264399026121810580014429822927217416623707885932644639239209908670087329251", + "2395778006062505184506680694990489164257726985147983723914622997450889073139625966012709064634400590861792350119450", + "1402401069626545580731626172712353213348539333650398214343555362953212205416313271019974942459303126809756681905173", + "158590021343499024237443080988295127341373991218387320385952336553775590364302635424027181497392553754985660494595", + "252988138942257093806952270532733393452953455642110398577361012860479375745541932649666201724260012024363245450151", + "323963409660973828226497241405612939743957675802697678836511971920082484657026057082299161704997564743085052276481", + "549073277006988866923454292545970583457718695224094481641544273003487338687336945014303751314924646841290505191741", + "988978711324737316487841945084454662302995179214237378654119589977193885998822266968397220861690241469881510119239", + "1108714061073466255056808747935487825064460840420788526430575337861393301363183619276872714641857198005912952658776", + "1057013286173395002875978625286561851950935715248310879295301845347971835154548728370244995808114269545045068547764", + "1763558435634587067450054822370828033020918894113883985944441984105713171190639039936464385881508607376647116909117", + "2135045090725360265732038244998441922722899099430680103770143174246255717526268576974880750106431050231764412809681", + "594139282694463679071411069016781698402028103301228828506663616744112547642017664493859389069112726185315936350513", + "971147661447798660368800021996625220267827031552296107195687313736305172286269495615008415043907076612437885312817", + "258456584180306012140333250970453759041422591956897309691034372598831624913119378864683275848795432023379156201907", + "1746872448388640575698773309686824788300765749012196306731991437178217690021400902609265053855129444670214017124889", + "555902805026405891013581466451072609596156026291210215196352713613211519607108171249444833374397900567281952294894", + "1425994875535526628431151989917792752997328215198821350571392550704440017667113060580067214013260450117854412199917", + "466912342802598301615910700474029353176186763456442458019322197718688394063383085703809346270716698961459064391618", + "1372067102267806306257972712308519943285402257256914809958110205261584634054267285557906913120395971912319384590504", + "1390809318629809566288109119594706283132814685782457466582022496919607963113491399462892910489805230049193527520594", + "420719140494803945598965754402744147708893524937966867024016784423175534701313215137780233872476169035955254708762", + "709953567369598005456852621187986583039581766422993298812258321262330154769758880561190831372232248780064283096688", + "644983137759903488580273360672708139098708760397304590859505096672881700943649551064332590654944952333333143649802", + "1076759566985940606766774382186985334760242154826431205320535081544337082871690602724889221454936937525925311635044", + "2166816038193587602551393516258784619975399717793190726920890126712378679755999418768537872332917354108095908303090", + "1043541511168265198419841583047746721407260747275028341441989921312615862327977063303590607449124255657787697880752", + "1036131545500129470490857698718593298422224616982421295644511607618318836929059662803976739828458676813834126060174", + "1133596629788220865644348282580161396702777750048258738417568450901220694595533892781579134920215638715242624368402", + "1081882570004791372405795420006190435541402291432390161889463644542026932553975055814718959111852246492666307299929", + "296723161432353786429784792796498712327949440351991693862911244594415177707953816186514112545689318394323504722024", + "1788858038080469648019727538444040590652239070205354865566001800176776982642470408442087919563752909181413717192182", + "322889132817987396179295088430519030898864668627724723380993026487855369527726583826423332044952896437695493190471", + "1314742763519399697497246852282248442861912147203135839265462034729875031092043933590031601702441058404055014532983", + "2237819955683239189001370348157033800984280112000627714000663279743221371848592214237780375199883830911150296840985", + "1245577882079832359228919890491591417251082073637508998056897813172304176034725802644529769763260663415435079753432", + "1413145375692576009136207228417219715526850560729877188429841015044269745845011852710339548951155759956072450044448", + "2176788812644678449462549258699222008658159515346001867096744012550338158288145583288660026312936239902590627035194", + "2462582419835144672864136531813196956724819112706041464971779357235505671381824687258491183215194600642391759134113", + "577824903149667940860352357871081439775691958150036823226044584262300729231143346011463553203879264976682539353681", + "1214972626523579654023660346490209699653689561816784532401148049743838314579139087529480758443448496701456417114328", + "296116841068841646273505481655280771904873811560687854219146739619913860556204811997471598470550175559832217313726", + "2435492307618335682853178958848323709075091747449727165770163945808267791539735342276017437801819598279121677895280", + "1172478448597185288887478352209423577478823023546784180051516127167403166179184239278486397226682746087905988388639", + "2279748714210214789170112951861324413673339214865644424594300815839595930681441488770157511153469365066080047272485", + "824911176790684569321498816751068302875390843278383166972592595094012487874117287887695447381027111700123974203583", + "1012431480569606407014911175756896234618699144065924473141189212767295615773137956655967650556201536151458067307578", + "2260939853449185896724946576907779006595019586698343442088061633171818115492910327569721610254694668716993220930427", + "1676824972047588725235020526517711100356277463014419935992790475184030153424710500784276845771113975529728629142932", + "700398174219732770366831936939931722663452342414264360433843668300295403150452104579343911218017981462835958663409", + "1402091938465450354498920784714683500011428902643266025725037323602442483116049829062291194955730381645105610806333", + "1197941223403789591848960777257393806186803853481165862770913327457823771414492598973873730360327652439278466680247", + "1426364081922590431509784838141253953241636956553829586882586882729190552645438494814325197495966603579692005039872", + "2391549658155617126349228627723361317720907175248997630589662778889276307468172707154815855819896919881478770605748", + "2035665803362139803552614785964383012704992940912943015687585635788846818268395136539164568144236088275223131716461", + "850336841718613765488503527803075291683855413045992443963942748930661190754714768701696230803411160811412379129792", + "313570347176007618531394573446267511768927020625954513993386497758466278077550004268352634378592679664887173060048", + "2212778325296190981723068635314185894706539010737634763934600346257883691894591419348025261968284874504330631167154", + "1952718620305557821542530301407981077661108804939873278825631225456836012744749699679209545252885193731980642508967", + "1295758854688208196489603497107811687840233630649176331892172837518974171984519765043863528327806009971378514329958", + "2404010730746250636971354767284228507735372474863207953990970627684809193864700698516709394246729381085359114645374", + "2447396356077109389249302804403594078988135013873421231883272317900793434270855170951984503262504568192349398245462", + "1879282562484389688991498121758906070545972699038179936338486900386785781338455823976058211445808910973299605843214", + "1517269755890611246628339124621098243255698083599972192920746987441267699037686450948027210566934152354090035940722", + "887162756363052776897619230335905218389448795850500575409721092517863820338564643490336944940433017553677371972174", + "160361522080809521955094057847654250283900920962938152293038389175740521087485689199079330881642622013006213609999", + "1743921054449102465647440985208334268272221946305168706251751000923740368117347813857885364532327769318427199930193", + "2298184452256535373678048435084997185027301500035272831353253637529271442136289862378327359538716653134565659586053", + "296512167110737323076431645009199794516645188216526517160610600608239072161999713381916760613979954959663682084418", + "1742347091350648954813724299035600757575466864062424142401675420876385972797373175116167801645671498509774634041336", + "417841604278275445668065081675247820212427854654712084777275997488535887279911051074934509360032275559906736655260", + "2294154469414300827722552576504495684799406021846091107798761916889901388756537905154572071613888516186218203406795", + "1758887873643719396214126715282072510246843511943037984382104231357431357485684339803660819821386519491772506124869", + "2045984268381468112950088898491852781641969936803217731080218136250457427760282427846412780855056814169385307084883", + "1248961902111779567637137101429062743706646234485662039380817412812092762090912792804030526858004105570625652752272", + "1757379439214156667609970669433187659601212687779406722346349835188015494370743690281419220897848359049170800702363", + "1136566616424651833604311592171820968786387292806301000835339966565264362264717975446622433329038557883824467415241", + "864028551291926539607337256126144041699115830644997828212835946112659495446252653533553483940448771739774876802563", + "297506989830792800986764666785175735371032572705675766375388295752256185386222177382728247773486674196593729964950", + "1669878642959320994834639598730531245283111354751009844114980823410204221049404336411950214127463965031500227932789", + "1212264695967015566925647508684185986489297667180595536042040361227431003351731537383845106908967832279898479638890", + "1596405870889372243651980183953083736843849935986725666071121821880203134110953089359954863890907822644335245196535", + "1867835898034064931030652856428510556496719567493366999025392647519269377986558091629699109359861649975459238179849", + "2045764399745397765559241855818234478552776062631928837486209146148165301656114694880117649464007909324828254988629", + "718136359102965861891615294474727681634903537256837026931016647121150149119339543311353760385289131501649334820612", + "1475325793462386927130372113608003759519973776127254064217932879413530260283909958138850200218333604676798563407777", + "2276069848471509613884264290741538112930447478901550643391105846116789410613514923443586525808929636462705721909836", + "1908017132294857945886626833580125376899532973325466812721483941581673700121779255016588038029837679103492551611183", + "1663398607144712045659292169403913843097956951760272525919023247580916643835501476698624309568279473789702990356370", + "761559276551661486079897420130163699790324313770008355900752695391925369356295994287109716633931400477140451860892", + "458174544657637728872759544557431464770805086785936030507538422656542074653245064468413854658829091044598840424845", + "2056998177634906224586178763657668909068336487444023028409357663271160986585694439835229335370317453852100376453608", + "1523983747623126749811084938574516902351571916294277988065639869769296076177424386805877606029682593136657751992095", + "1107172971717522103474193142079513853006299203642895560630671101335803073403422630242338731285426886410775162583666", + "2138216838563997191069431091712560044726241313444720493469730930499381752676355552771830755784014253756410422839683", + "1525241712334847460321459672750361929105691131422019312588308337112624542531909533371639297371991371531129536543650", + "650117971624653300788425878309689912469867867661289026708644966452408652730988757732145234937356230491480487468824", + "1754021662901794526219137177510816797153364367565158985989369710762576159294795325094662295995023234257272110188722", + "1839414055759316751326731233546670924281213646976251467509896909064852166999125973674374052336890790768979509005338", + "1847223034023147053545555136991154980087208413192795249423378339033040416730181391009088585687369824464122274904662", + "865563238519787170124083486792137951944326127285192617578298094110396412490384427220240890311505283386183814724635", + "1565830729214284691882805666956303975215365990277552195221193375638909386605125372485368056264133556619290967428811", + "353268443964723289281985880257793018876914840517760985238823216364106144040394879048832766409444827551033166545457", + "1020487300190605391642440364858923170223136869361626333036196960974366115180394271369669414633516921980029854140651", + "1576918899298114023185788492274856960671289459137360992330121961177480498137995768023807855900838379305958818656406", + "1726869161530569308153274689318305303695731206526573722596572035518314875511361657240270786436787541544614403986619", + "2436403450099887952661660994180357551293855608439003253723430196624893240262350015092962822014404973519531565124232", + "364369038786044512404861424688841947436138443875586452605609828335299356037927792143259831757730717118976101756016", + "1203928691808975789723434234275156756596044535260674695205035501161591415188659527490149652242095136718468393097247", + "1559490641264589456197415866817181848620469357418944525350084268353234852387992409791639025445510180061803392952035", + "813268487920746535500144206542462600290015325119689752807646149652746008413965859914277514489708229009141922789808", + "1883934508733876557483082597761341790810265106686620189179929849684107706837193924130661214471020732534447358241807", + "443097176868987506796979960514121167198479615943115068966417259396661816488996203096468598452574812431318686736633", + "718277305198282434854702290118772635190311685705025893905826401081772948493175261397548249287880435002995085871260", + "1069288675964029818431174854862870016680189218458218878480776736644135008635035053087664371678868203775911569080759", + "15363049710456734576928162598674384082823727670626241609859144161555909116651647007734127553870411569815327181773", + "1563100411226232091120989589363715630534667870787057432291441717739885689665571323887754742868422236153892010888540", + "60256787557626577990074141352385917361635566910773193304618800640940994121910523459853947698093652021294509627003", + "858269958829127599840715001488090162323070382084938536791213014740017869524121364239975027849595116859209129479217", + "2102461639648097668196764593871764402162771754569538332378279797642332086123322860807431096118091326918610993856793", + "1555492189635123302164904008310441970473588341124031329994650741281954113812556031611663872493830873141070566150854", + "1855945220096799433770925193167350622896168736129612360889680114458832140916417846230972025381153203842663755964789", + "187972111462944892184379161396497858599591062765588219937411278954153208198869664641540040325391660416787726980527", + "277336803244098641293887590892195601817921669864755720765639829021466163170114166710595768918687901677233675132429", + "1771689957706101181089809673555515722545411084954219558299745180989278038288252417863827068820042953591236556619578", + "1538380354766285826939119879999033245900112493880090943379184383153444917802100834342553906537181882013025275748356", + "2379240764241710276222500500155778382866688540821963772265543453094528033795664876994180878091699185763118955407388", + "2413222207642092640677495101419924554646342662543031736273313374678941279410445301498375435659187984644673727562156", + "1472566217260097614329027498757570051605021804616345200139543925107905925659224596438541176795136484246842604958311", + "508001392327747880636838165639429050000148878154034379304083572887235236028113323425957485339185314455603641104180", + "1232539653258952021206287203914591692142729748095407623328402418691860941074598319117921968689964633847453956375536", + "1763435970613841327040579188295936911266952283045405539631892600015328433379791427382229411719929027617115084126648", + "1743333570295370025731783575463327513598053163638371326327013421247040979457052565188179499397362827414896027931000", + "399263552769498951233298852556265310157323002389468705688182293732973398916796784961299054246545417339294661454374", + "2081381253718764964474766303513973059310536326155271010339093851556324516147081787454887926727456038036734773114678", + "2454525206026252006332467168543432993713158209745369415521875924073028222800941864535693639095282219428277832643427", + "436422070110329636745439388322379710907129262630225908328394136631180326858524169567708918969611157144956975265791", + "1204551703235757481840712735893652587387800732906490121526129605064708860639563317478810035961325045838607711799728", + "1529958267918866449962767071578302356499119460907924782585809213155372593965551854842602201883097530069720913811163", + "337808457884661313691358021714590203412515206034165138774797492535154932218139011456880831616613740829667724312557", + "1477198795500389420274575601061960041864954744404580754816699342367259960587846790757909641568016197872191990857020", + "1993940663141965929062843936051888851493760167900622143291110348735444674677656039972675857437921216498265882622369", + "283395262326738590319944807755997975973040028558499850684605073611525111569111402773903572781284289296817546213222", + "2027669255906096514600137324203518482865692873078740952093663164456102873070372957440393820072461539579842474519115", + "2412948616560527679713802193605166006356656118512134748829400081724680919414270994826543791154283742811077017975422", + "2374665204591751292051285183021547159665983944002447209110052352321383625798424768787578180480495522049468453515099", + "756438860148593618488226338146321759412473456659706384752727570191586426635836300771637871751400746007319679569574", + "2120420211267086756584637291870260070909333231575606860076869389524071838627507572031163218127729208691396559251276", + "2248441515245209136548552578559272256965333070875611686832627898345052879518317110947849050268067849633944759500275", + "1259651399008092835878704226832821846929211390495433966252515752645901974686753282547596665090631963658725241170086", + "163889311886977720312788906480150329307925989892070661973303483583820006071804032921262478135905120632203878473920", + "2400451258289539522075409622220354540974453679286120036358915812020853994703117923556514940957251071409773160766056", + "1575439130381911663283898335141592951692055106624930525157680229993905204737178876940961535617992780848951594115112", + "201507872555191339001001151500591377295546537305759569629077492300341280382464578857425277921336343321864016454862", + "901448351303148550318116145845444359217989292324661414746474397591754921722668230986215861851178912915568491041259", + "2152130192984275869476544524559734858487771760070102316289776661175569057247731239116470049578245727932163074330630", + "4461228804685760565326815573635357708554036545639481050321451017385673860843378838705321769556746057630156320457", + "693355307450215410875494884942412309590208558058379005263679037764748949926151361287938785477966055565090307924358", + "390841283260237755752694182911874457347967532623753112251701220500347989692525109088424429005791919579519328179738", + "1473904929236955395646041617284470949609138471612555677404557045815188220551222308532741425970807975220850942355601", + "1302848308096210992895850305448504786328805044976253681740959822406657827922410269567689304638595613611598813748968", + "1180467997031123746601536274651531460619337342697683181319785839138091096546516966803601308974258157680174609661187", + "1662761757635929939033840594100316386857167559707375341628748574463643340213535739504885543933059811361452167779347", + "1602445913910714699649558184009857248715250494591939123299786055784707451001515927283722912723099271371477124645013", + "1488772882030063302123008670662222401011031911225416565276310944907624808177979091233526614841362920586964400229030", + "1490201335587340168804222778668509954047887621762054468866361593092497365828079179621655286458703507325002820540247", + "1427460643365694488694723297374112229818524838334580906948244955536356771784548457523461502880566466937853872828358", + "1989928787489739617217231239334290391284482280687576358989488734449146128637521854414285088222806378392054840317499", + "614584688480024065793985140375482298181951695369169766601149448369651966435699192837987544545286705264481460683233", + "1984751217427711203163168176570968715741264438787904260341470457964369412067193717578164009751322727801766162032933", + "389542587002132062260103423713065173539568376036406201077705838034613286694658487599236262227169766297376140143411", + "2414068640544491971250371603322608854727261955471899475790831353262038541641987029096189223801346730271099733186647", + "1975944514538277975776685593195419603705188988203833623859159980133608332178897606374553026628440103098776085862813", + "297512033237005081032754576643100589707817820417287664442260212363228195822496811598628058884305650749330579435765", + "2415296726598138674015718844219045146902806022672299534962633021028534240810309973302359644391685267143537847492712", + "981566514843930838859923433470208744848748758745128971845455599144543854177948628948885494368339930895637045623582", + "1137375878726416364035995490365404316567148653968112494177329690394730718242164976574291258697206326862236459857973", + "829193069516398565068586700237381271214847068876905891400126015088222856394932951698808762743725757939800005744290", + "828694505079613023046133232213545797930450766457378928186288785335882542140857703658353110693176921502433461129263", + "2236280270900283858310769719917999559780842575030065692528979415413034190752720276179123463960858699528546577770475", + "421306778887192610742058374653472198550321727457496389194315933467214599715648553726581327179473005435696016488787", + "345033739978233081895098751717172973795893301437491198210843825052531810272983486627583604934381135384356519942194", + "1797621390707274333764080066804939805972332232666875625136057937681046451941598571280224503894764416006774511534297", + "458699090550796692168691352580549926724721435458497651409936448619775719663155782593692670507299377678400589127326", + "287830475828737540986146466340485090882393283807974582008476391773141610505748732551214099250233493975197772885234", + "1980238862806864517699459649181304291607388425503880242180520015365388017791040904761283954134605973669101616660114", + "61606733673505187018986196815670172768713177287216042499709581739640956171615924618419790161709618487621951535570", + "1534774758659844343813103875875021211486590707289490870563706275693282916415639953389346795315315681724599431335974", + "937783709794679642827512860562017018803872293364984210311534118084941529137434522170928083709188488148075945755082", + "653345777647891814626352215612412125606950091682888198601142754873425909414628807048586063428306624930914119234442", + "1359977570860183286728987657794249354571933533757880849198995466170517853072697213428685616762674210855887478267014", + "1750068298651896444583650969859992421108806666456103334933775349245360745432297403598917941966211278442351869258642", + "2116875668470441748909460942469914318637014615143986490034809685443213942460332400711558448045461035869560784319405", + "1658992204218112162864245980953344206238881927647190460987737843629718915177511644459270979484267754663506821293132", + "394510234460855552842146887525982674748135193768047831325651160587945406332524671357981777434843099465046176930712", + "1520204732498650127781787018286392862291156757877467911457358839143782804718178394394608221290935500451187620431224", + "1160225715765452577568449376533920083129941863186394041992753407125294070868995012123094061101629780801010094814423", + "487997474290586742742465048073137705922723586747155513816193540403025498623433945541141710999530552105202655951236", + "1497766477543023366807988092945325941185926594865792908509268053035403295789780728641959196584213355941259335566096", + "904836310211775481862592447622394863301811937605205963718635715498381939139667053543846238344373964390727367730384", + "1409693792820779741170807189471891159672379766815367068403836450726695737279181261379682471695358872754731424832410", + "99531776776395506800879456381945378451707210725532322144707033415648560849240872571225680469156165180058169650898", + "2177438357716490686607464338509673897890585678642829172135007245889857965199122302946517711318754572905356823355443", + "1533708125200482729194525865988896276587764655313889635685199394720185075268542869472232705491169798695700110724812", + "1855553916102032017930782680442993143091126825995673026402336144315737531940619756213918064916310440065522821418739", + "571039714265247640624038772896127100080499550538817340866874752905791276714498578326352898940562348268882733460774", + "413798807435117036468058737608035614677716747426405484399995895972246745918553973553229798097329144531048595207323", + "1149077290692475227960582333646765173937295221076944279484416072024225364279765739832103969852897673814393586058368", + "549667366727858588582108638728665495164986818422329944508898045284707542796412158998965848573459888696697452742968", + "2209333231911017644286426383606554022642713587394338984034430210660627152397106491125950547228643684262258610832066", + "1127004747348547400991599357990677346676827156655186618514068507054084277205321640812972284992513324079035924773365", + "269838693477902397756030793771979174412532182735357576124858870294979184424547041158674009058331225738865917459159", + "1439765848667242797355270738358972417618981337880174200759193269963484670358511047693328684650924930925197338470934", + "1301572948765482445548468264656664293294131507725571437696334027410136800512125278252605998823010030252273264891022", + "1368970591738726400460240914475545934630699302091788489318004987629658589915619159533989541315642415954923848575083", + "2344350587775184870504731749117160675681255931326384202390962669491987137926614964620731801313256550255877866837936", + "575959751593105341190112648366852958551716405978788113189465229384504027877213081184810363678730409830958458639369", + "91631274357333162289650541546464863351510119652777218651534566808858410271711026030007432645503789129235474090255", + "1831793320253045391095799712934398635712945828162323939434433421591674478379566205523316764293518438131954254965104", + "1007103400494995793768880489198287171611283513239988020338759903523643018799071732542712245244198085419905492661674", + "1140100433518423726497135740645880337712049166181552239892921878409893672185651826566359487651468542734267407149812", + "606862311485406732732735193950459674060719007964323446516257827357408067627087235614422249861342455502531169854848", + "2180913039577337067790865450453880976988993610980420623719243521202467768697322819008819886208371712111274282967672", + "2103439746300119163689896473551892018732067353461637662918625072606870322065733375647126814672271608983115237189880", + "1972159391885892603362713182723025248220362416149035447186442526547137365467285126743677366864535293028275106496858", + "796179843587454457493040214715612741590518184201946657545580235740618522598497808250891927166373245332195744236125", + "2025144720532564304481792359249336482811872628969759327169271793060887671656616878715184785379047574218224779201501", + "2234717915368478318683019576038631726701163855541756388729290956355295192935645288654574453419769788544824794941251", + "1565271296692779991331330667459301771359392538964188667435185867353578224899474025520621758024713541798368817064836", + "2074207796505674833428149913166785897087383005594410319008025767431183736342023417305072386263516089472084253312718", + "902093287420660629391163597675221068863519533558488635876620149378909071508575834934636798909782129909816980212665", + "211753923437507878812435615203368388346733856905372376157921279738468057588508429311445322876256659133996220685150", + "1102968720727547935610854466459261515175960235924353162981325005077906556266232183738954149071337534322364173020953", + "708603656798808899074132784593461890418526247154093597715530333799660381971292076348393044915236995474609724445742", + "966136515669473091288512235137687192617402460845225892243723110845041753339115276128308860711917301102703216173521", + "914984263843574622762907960111971923793167974356091114410428697810812483465852434158911334350639576831210813321441", + "795227761471672151357663934835509834523295524084893701308640159798552812022311467861544022545975840562937016243544", + "2254243708012485909715385017062567634976460453650420958062514563744750981810123281132920539212682483038583139500041", + "1790920311144708599914514720232955408761306453789224398455663215739855257343286135335466910257520706804965815739828", + "48409983317930111115110750673390003981555585031198055122027556561620177600161773226170929950325447415382847545159", + "940025866104254076111288138084137280996524018680640894985769708823696311411117616852291076961885988034481264201357", + "552400034903226020759909235812178311976842934333807647830971086467914891526701052481350520709274105129641119993184", + "759783561779919433289928900881709950480592977789230914296427307239314866532742375318639047636119938263022355476591", + "1954481466937575354702592705496459239538703603175603813348876799517314513793206370899761497242634810176227086635340", + "1568612436999518175787024019276381186318126757080943496636629338974231436494742078030797879338532810243655556173165", + "1847907154101965392117327739123380912727811292426390583308235941366405810017431548253152430576495079444732771095655", + "1409502220387971918890571721512623177822919607051211369409485375188804563318918822172793130993143913675704841845132", + "1058413060040407188134817502832813766761024500974963497449673312810513982002739431020946589020072388219924383669912", + "813514391591396029718397113249234111879788579919297368009121090203056318700557940832196332650286433754925627225673", + "690854274894256955116988347059458776532972399898863999250116572632652075111085563040516971739501423138510399321640", + "1476974858030588395846307985816734547215512830743620266207333462268334563444391193825004863345047754919871412307555", + "248907098239808552880927712264688390189425192069140395270397392858868614305575405942877908712554357620283138943731", + "1488501489622344806592250156356558270775445566120136767037515088672220502830095512812535332432625427983191530405761", + "2302960057580278090922388964225874742240648300384272897972265773098406631217792507955503010040346722395474580866344", + "2388399348129263386022671749800724332617194691363491447062020843837201279255662952714305684251849610193664366430886", + "2226291486317834120009299387450092188586912170735688302517051975700588875978962984034734591347412108624905245367828", + "1125819746959991605460721778800148922037326356972031066953759275249350844038146541921162874134621554593913276724700", + "397280208762034250420418432585849863061331019368803183449683937264881850129231991185753845859355762671767773951047", + "1460370652019203879023478398643756327000741253827390179788817467507350312381803923738750555805716842088675623165409", + "353086864649421425463552364843726688736125759817445855814215009277670201665830913473136133550478988578933854331856", + "452319051864500611678447107493758399041386535254647652690727404805202920627846501409709995448661867308451873748397", + "1918919422355812245341701739779584569416493890713146305210764175615938782513844783835997246246644900951310214441561", + "27023418764081838153117795289978917547514528230119082124036306191311520942166746336556801219127247192207817513238", + "2391962568267856414156427013094214273798408986531057637443045835289679673310736646135459334867574684391550408303788", + "1963228670763441433286644043539685426343967204503303336078199536276617468458201778555758515361747229482882762969047", + "613329244488444114635272949356917482297565740543522171065403911778795267537883900684436541665022408537872073838517", + "1683161800518427347826378559057521426881154525553861495199912729895508048580757861809399226811309077471439146981264", + "73273355248428291261613955355809657904472982114806127698123968724832605089559281130384676317112465691767492441434", + "363482894554056184446116522652735968005422567266738760652713206647527424549791908047387541691913000992934788865697", + "2447684844381826975787825581443942308158038734056864640309400439086999939659927140870013310681457496847921211864327", + "1294751673171835701904247504266102588192605964736555599788126472605430972039891949268980982725980339629036091701600", + "836760045990955729560040382689276184029002400865377103021835373872894143616409222385240430808067799801714234807979", + "1265153819906981315052862039544117121494595315664361562621440905486743747196274893206352103082468403291747216562191", + "11571149352886094650330023669278467567847729442439415896456214299082003042875905895881371184526534472264335563329", + "2147136610895627205149896747808640888405150232770541541839676758277129213770552691673193342192248100062330829733314", + "662566541083721858886358473102580299074326636626422319926718499655071784355860151367972297765428183225109350291670", + "2244965774402124337773711210347956398301711153520720321133352928806420569234705921628086239787915913740143671884406", + "1616451213058019060293857882185408864429436376582189041562775927725026900338405806246451656717322276088192201795640", + "2441733546533891692601719047554081280800581967905304528760437728104356670388176282403261070763186735689519281471565", + "360713176540259206940816039210319321385177291897119108630382265796717905094478717138773778560206295778813344742586", + "2240504363752073891368545147571876626596356173550141818460715788270515768436924868659255086400485037760199191676282", + "1832120794046180333663166973272962288187511766828168022883401616892379239077933734147252680717378681385727579930653", + "1362369538372493569835595998162256574839874000471984953545141968400461911636925929798814668216288371453453319755011", + "240371212298747976235696277327855574678034002516410850409156813588412943360235034477512969839073685201635514309306", + "2063350789645775782505655652366251461240695064927654021616475232366186825659571026861333757103654621818877098597103", + "929716229859883195949430353033336184325481722842749218096708211327304268662657122661329708480087238320869870591004", + "244040642509486067261923095868802916762277321612712924139473081645682194004860722277600040514043966545134203572583", + "1831862130817260625779314285240723051259221893242932670362781724776351716198276635757024179969621346877942647240448", + "1367697922208143868994352159456681117768999527640855612594828861403674896683187399688111020168945335598034973581182", + "119997975334749651846459321931563779716658780247987170198967717216225306210981909516138994040858131918338997526972", + "1878772011020181712201525243893229078423219875112902567853658997515625661263391897024054429551384626138891480413902", + "2059803648261962721685966035780630218503033481848288514613846178307116004811806632862610339071318099635945296462667", + "237731260758693363930123799638528642272602043014457936774988106793733174526023807739805038779897871148908873275860", + "1862610540478310923739729474965583242417536523933070518507523300222327391296205149663724528661445038882277406263275", + "1982247998146530925719958441654911144972503122696086803874718566638194498996419805900529068220731233876687687962886", + "2330215576972237496222001129135571201735210718794942588079229659899083107820932470160714691429998819750920083598578", + "944360504140706610165639087930137014207387281919190565070332894585637161976812379966980454673278120077219208127016", + "2135409456198657093396845406401935998913512325189668884572536394808376149647264387544590066598362367073750743567897", + "1704892698431868687482440981033704855102503001168769721009570766675359076155576409732212387051337179532015708851746", + "1620507022311846376739446263347877039454661916200530222864674946664068446836044570909120325313203768806708650005630", + "1211034764026827499846058110466465412707489554432293322552253796394507588218584229432045683219189684208245939399890", + "2129161380898060022240194568573743023534083539230965576178134907247967968641912751602534942986276920028372757129745", + "2254489922077376651056922647969248563192710264456427547208675107415780782458325439538357527985190924135525481704405", + "496255348809985583194483575801531506680470557321945274783970676208747992563097822724385648978724058762784806045014", + "164316364545462098217487852865524225255731611944670872734248012893246875802135642048511683837083581281063861056719", + "569590129147878613710817634755003432532813074046501438089056502888772106305053141736838963956684454618863308352388", + "1432106744302255470060727712218906857919578803918990675267502395590188094966075920843541625720894481978592966097907", + "358993583529453433844091144560803397858668080104148583000884602727559309906089551986427322595043913401801331876534", + "2185166026681848311329451808064997841926168660893678041276324349368289665158318275179128766941639653283592604987131", + "1084689812303630053886391419883610501859144282098574749740203343836671668646980633280798346888072807255316488735120", + "2055149488229355488745302213395199433680582892087088704489234874604561457647342339212452769083271163158717471227665", + "1871806200211929858381935888557173159230983866350099711289331394298199435533509338722655935112390075138384773092723", + "1255377754546913724361185777144043110542603165841416424211153041035829029267733920358844584032908792506718667254088", + "1375794791867874769090305847672112477072030332736993403984020477979980624377037843124351953821144725983625852188565", + "1966623373384761399172244643119000212224106354984743346241878119058365025493588956142085872921373237017961910956766", + "1915114415046059367510205070077212685712425868104249467225645039330218828619319687697311011610977674832793332959456", + "1519361678628608322448170886139525319877339023501899847128892766523460776275723409182503979826422072447268767589178", + "450005679830631400070246702725712962748540727449674693199902328033848002536880947048331231727115147414018917261082", + "2257837235952532496115113038857758517240402985424864988893387141854431336227752812066394886956900376290943122000546", + "1504726812652450004784708903316348557971297013261823930943570619695476517256538290108970289336377102244060006435860", + "743052349327289154316924745496727927203382169060751388614142955061348517352869456391555446535971970604691521780635", + "1386512837396309407934398991682824971587487608541649214401875283535341859582384663272603740490422085055664369730636", + "2055770507115824272536843764418263333966497069252558091414251225130369230785729780784012803971669858513068441578761", + "439336623307300826247865329636753315474223911014527998103994000018006590457984266843086201850227005909305238277607", + "1862822056548264139321407976212826744460051004264840773890059740851965594248385772057080159765384482948887837104625", + "2055119219249601403566138918138231570523724143441559152632235085205220762008030359389424121419193454235829025921771", + "1125613381565078123870134770662226393220873748302083057381567187438972524410953608487501714652237085030924286929704", + "1271733740351808534817112083424261461398111110815180149125134039431213995472057847705755057287122901405821895488004", + "693876312628056236691484796882429752437757849960475312852160978606957789647513469905446224415327566746758891685701", + "565848888697057705367652468440987210184132585040045847329868018150255820531216840752033916730622076841930888629284", + "169189557320589485555041822129465641386303214418839433883584983485706005140187106192952451425616673456459320001349", + "670194769701026676819615085103979198979417709368148401982089875173555777608899636616663397799782951938715214788135", + "991984592164665552063950157088938966066680148052747470145217263574902870016399541946241579224445399702430425557239", + "246284588475400427351657482143645294335503443371689696727270807932120548840175051003301694637613673016310039287187", + "2271062781178300917480669722722412084551241569923445181182613971704330047476959152631360969661584680900903822221441", + "69604890486369811633181257006808168386204446873782388094480284646100264941504438651323483231816507020142863712975", + "1043362499283738653891798388663499244998328765625976360571209019192845877527208809501524127508729072076514323995639", + "1234689148645310606306996103922887764988100834856963582760063121584612192514336488435577414185479668380122019910700", + "2297177040801232820472555722878730636147117858266733897279328811276104953289727147758108608087964520915499792447870", + "8334933221015230863863719906010955630191043576732935419289442688468248512971558488410332554054498037273788374011", + "1208877439670013441720315953010020470612409447177038830870024721874404403725352751036209783805722947926610857083707", + "1987406241730405192181171938228929584660088417319121642919302890792388222922670811767496219515074677305966192688919", + "1142111829561733687503631798735837340406810039954926862175163013760773925966402162190981937306129329494698286130689", + "488485365108138451997764962873353132469553452650334091820460762056243410193104411234901516123255214785654448588090", + "1837439375633352025034496126963062500013752162659146462603895165758543562074751597647184595593979118908446213157896", + "1919507316773039321331712121757717301223969027201623878864520567224253825065075743203713369262745988101195045676776", + "1691072130468840030186975437223395562829523230352672925790148569814394432639715676590268534817474378087006806163427", + "830012509919474200687859494410835502273290787165596556674443674253026046774422767663911858425454134324184880481633", + "1006850151337603782417220858141330642437724375080663880801429867945778876216897008757145347956665962728185611252802", + "1881925765115184237496774916820519703982490431642274094912159356882579551460870750469938118054215319474225023502155", + "620401079935511129977766174595456099333689717025718277000127216365411380960939521626760324611318559094760283527429", + "1706487754426049839937255073565526260394703289083248218834360339477651783374341263475515575983225820289486277420713", + "1077430975654369875967515896203421628305850740915487764560558744632366747289930833608416232492114236465211531450148", + "1048736363402604108314053001180021582453445569626021417502775568136130340235611491386869397750379963938513561486061", + "23847278040933154793926775407898535613790529569543094359713983439655930177164030856927338521785893100046416615367", + "747079984005080526819577136945223761453340053540844758463534510510625773106843099837387329213543104316156909913689", + "2192090524568397021286887190539602907272397597559909893195892814391207642997114811047436513066594881788322611292274", + "435295362541293838524929071030747459701205276952990296185213345759054550313833292648230662944022972710374310238801", + "1993499910696843915720135675750677959093757427710889516110499604569026257718226724019900847054366447372449036779789", + "1076597182584968851506581012146896573877618556167479326843873669019739840553535532528075377775620922191913062778453", + "2035511068348517606164114214087356867838607314327543728152973367576532585267662958392907583299655499062871921490011", + "118102538088456932287490770551033710480085969219940659140389614906673517943198401465165904971816746350226415871499", + "1339944830827655882641804634295073072928877383312565807608029607190307715308675406438446315164093778354864520985827", + "789190032814949701760799140206380271756409470200933146089907532297767543244760232059615489048928519807948978824283", + "1643263521436568297771872902594174554268946192839759757818219976933468189098595557874698686267940805465469430632488", + "270957816219784097683861735797317267877096848846735547728488169809032530275562724810879584159702123982578034700894", + "398443253325497602226189118287274122715593126884667694109172803872290605163524096077674277873378655186661872233796", + "398851258626822087188590878343564849452122299937563065262095738359388765683876650335718077777902362236681813545837", + "1506885298224202445944896066715545817911001229187788848106346533019861398378148410576808082069248334289961291475293", + "1280102669748721290152231598428765731576865355199068766709147826948539679200649311663036252292810351371343264142907", + "1470804671031198537321299653766712101783603955797950379722070392196104271682748717563517462112473910108864981465462", + "2152151514431136211694558622740101898797349114207819679096696022147354693496693315528850848481818119440720516922266", + "1646894741776546859864244744946583306737635192660099247541079331482833325893482600897598962556572236989665864269077", + "137744343873479232966707982309309206099662906341063157892182396895520118948964543863486249022490126118835232371953", + "2202715775608892963859842938315956708909226046963417334662992228582207123373476465272620464628678820140993918740822", + "1344322152372155813429811719060357423976923096474623654936155620248653628382273883908462481387026906096142629852516", + "1695719879528856558754327237078443330200310566708247900386886508264650179920993104175268874569813545566602959414608", + "2429172559665524745500004935502112171974235959303013079401309751217078051026895472793839584180322073505954389831253", + "2422556039736704364570111803483168309574833006207407692378275329867118982048365619214075576419253382779765264776200", + "2262641886611335268861301693165028729264860097127182718788101465339996930556608679871397195438079761588594402166043", + "457100964095862291424042143188854700414658588106799956242245471370946544229852583442532255076936579582608671950033", + "2384159860450649732345875260024279405143980147359262389311164003928030836267317533205570554050591162740178044771665", + "1049988828762336220952332085752239506261899125932250704314521068664308112275220172318358997025714212065257472223959", + "2215134143358314185046157401794660959950182576362262647452242719561796029818512835940760477746544952246686812559713", + "1527616035748154862512413719739104646954075255532224297288271304336432209054560486538938070769832210494369376631943", + "1786060450153623041332274091317110322379698670293747358192730240277919006048254823742581235867306254838543350736321", + "1847277434397765602239938853900577482501598402267892014621633808100072216898588792813879700392831864861991935685164", + "2251980066928240542790839295928790097588565659367518346462967948756500669628700238636486961240384099158575387684713", + "946798315991306118910546375335529880692165355897073618437358076720072015895448270719346023840160330848315436158738", + "1785663992935695824129993549584318920763210672500792283787174475905163188117897002318614993721105887874942062317079", + "553662740035737984732478485745331793841730442111476762101838839926279507177959792214744852250721211940924582094740", + "2164968554747421723661422019222674866928661444663276031936050529784371881620675488322367982471251580884644488754263", + "1429148396740192116911781603141006585787975384333290267172666927763169234590290283461644035269330281221255240903132", + "1190061940919513419245150697073993822877548388296713338887420958439711760116123331315746544897890227441203381162701", + "1613605828403545667384492176024108961448257738145822600791109234830790366372681289672540632383753489463237604742267", + "982795167054168941497890315506123506340700810123906202134381752779232690598885348863346384305687654511446585336375", + "2408875829527665140469296416857629543084979778520674321693121885473724191202183017566027697415017623769986630468495", + "820330242275388575735908710629042629612534077282003250523656714201515770747259051853325243803550623466900058949934", + "2344778880978706964440079826653901438565398009851166330579717356841088992131245875474206217719734659437979426553818", + "570689049917288430402875576596722619559059071843482525394943104589918142172014455536437610246391455019211449512146", + "1539387258389787617498671289374392000557353969837151168465456594150837110499709993055646706643354440936496354377073", + "449785990176487187028256801930193276538514509198240398375934337487303225115352391610468104100043011537536253513024", + "657701216879924988349119880782213569409513450117532799684757155932667810236225171004522040192637904819205583278519", + "1939696700459184011978870421356165882409235174178199010338237795550056067522427983978799485514519448989163461234128", + "653657207180430635856610692300916527138313756947440525448408745461107417045499566979397836198638625725679735333807", + "261864010011121495752860358574890662317158639403170662920293610124644647033343616877238889473654467456052759356641", + "1616361625270377372332490843444548967077690960516192538914929462907699070563493736843729298848606374492400096379412", + "1679019702619688322083488460580967212003767642956451192466235231841426036966973533419652637915166786513687278992981", + "24318597806544141758547206662142559458820956947937598658656715520871072058667560371660824059894030338521242183289", + "1734806208979120756408719824621084134941847482380057376447663948762801923834423284504904546697412612547047209497920", + "2377412145188797190976021813172775459688175906085688188001738363291071560908634878495146501389969389112892534112686", + "287869022437905880683706677027132461859069094925490033941253552876170740085393648653023641230275961228405686549062", + "403379945702303400139022908461674519047782922103518041799098125731994674337400405544564874635600121341325409765960", + "209964251668948469956627041995799788081120453693923762353005792762199831556470435446167875672388210193172544238924", + "2148840887195599428778038841893987413889613773995286495244698483563246797984089843916022343934953495551140760985809", + "2092460942684730048602747587689515195399515944688630084341874003226474290976270625272308486967054411836891591908274", + "1301393926570539985166361303563113021367184281621727155282406737248979504768116949559652415929794987174987569967414", + "1659957160577587911309635835273147400294201170302462077057878107330430906128070743148708027981062600928871504267958", + "695078653607477290018968355666436371643653891468223016275840239472267843210280069434874253930708359588916988228053", + "2194188769204467022420417668853338230224614390024331392938949863429643186598671601489404418436572609864676797789218", + "2303844806537082485279891309992978668066019659668611708582589050665654844415960689095196169611207200177443189014598", + "770011383730878384738436199092688185282258879679293703980580498556985723244848269857824000783685494279037732032417", + "991144366109844682959799733720733688621650425958313066127448172861801620362292823393577794033153675362299002749554", + "1081460774444796367700124522121952532847535457886400191488741585246390319058354447031964746835452252440373419138802", + "72617030119979702208450507017548034866320108876016247303684320941441365758137163211194308517035170775650728229345", + "122811031391877323303407006732840925196479042929720050565825366083005172093518142666594930867891776802925806394225", + "2406622536565791946374960950443547924746628737064868206929106558631019260754757548255283788226387085577653612608310", + "1635910492988494901786276027086926297514122097057366465659162079910006089915703750518533976967226399784958818225154", + "977681738293818074095867075748564015209427178091767364460748618467232427568487925987287641794775204417407158733136", + "2285033562862782582517069315790728812256321335627385048327072384568512808276342627572390442932533945224599378897661", + "2124882702596420750671485977226780739157887757566570475703888175543584967244228379489624101495699356586783820316933", + "1263213098354454090017157600460720133273634873660426146486414714519613194346460867866352957386415679005050261757698", + "2030073829524529074659707308361911817519505015768160391156340951573129868745146970622834578326424453445800304849266", + "1235700487482771789402606357755644058922241261761655129680576645159748901594069204446251837853192069968827242608827", + "69309182538672990450102818381341744461895750331594335943363908898808894253957465844920833253493305532386724459816", + "1224860672537239156636593141330938196072215990889599211584649805975522378913481289096359145835787180728703075843290", + "658539806690757796066308778362651869774780578517910310445302515850931931478469032553441237389077995599915202413205", + "1813878556010366973921962087193278769160053634433629650468540163610076544477112600277789712976682083138835477599180", + "541050992738005317753505072294856072620103717711769815131256404111373649003986581376063284534079811185958110545148", + "651799042987107029196182409645253583032837975912394560526556206759807994628789593924057467196339753577309053439946", + "1696311353804736977655594380362525678446327619691929106355429436789325093264115975485393256708232679922941423144368", + "1230332050975373804195730597778936727476117287790645020855775513696596990656408886235715371890965547550939172878467", + "972748422951246837122864890664807397139403431758680539721615027237080544289753376631398546391630907267905455614053", + "458668008467285516212054166148862010744030995264581237507577099496445837303093941294626690586736758267493254158866", + "2001310653479944078910289847909964472466324293399474712419938304157758890209098957883722666210778166418644767021139", + "2216401505658753122606120668442411311453915364408073952290130825440897988522286075859634958445584954094367972106540", + "1442935743735750786660841386636598268933286462058692630368754900479961905444424712475905401759143556492247667202357", + "1434412073624704143672772070529092394699463034602325421778036793447039733153867293266796933207136370453662060964828", + "2315884809304012445812949344842491410910276125915057622112985441951780333824437323487813139157503305102641025838670", + "165896069942361968477895258899489460358934954016943146697461221653619713559513014028757572374301320584622805769520", + "1906592618166749295191643599050539923647639314919345107849455515922662919960222519862360038221233001930327681983553", + "769483892317483029565278770321285837030221266015421461233070896316475458039120068411972944538258897734281276927471", + "1662046512518689406967937463714397270588688494250893268516940441365988896944068013098199431197655619271064271044090", + "1939867756885004065970655006850723129202382676060273090812695042811315234033686093858394288310799094131079038854064", + "184533322757068788787664814858302679934319199845393222897280389414655345439751653472068421318782187807455333915353", + "1075264264670879820720208108233645656149772067641894417056345556530154126551324336034762150819602468041310309475908", + "1103930564272489301560615522777302878467727193874757376310052546786697716287052644948971909464415584922724576971161", + "273385962307389260557900299575288471174160557514361377747700473663440960812096694205263189561232380086477296250914", + "784692362523882968216824812484768017510046882470501406178969602261641424985527780283491098654167205478494918657182", + "1979165360476097534459251236507161947756438467189470147167662335053118156295314065453696339709497925245262415596469", + "1980763520952227910931572077329831689507149080058691024351307357595822107824083489750689743919889336977386017810115", + "694234690511017563144132697887907513700863629574423544647570978867675758352829021393891995432753258217619522282141", + "667714546273802035076903733798644083968429164998240888535991508500503325392394976596482432752942552119924799967648", + "2202257471573908274325364768887341181284311490397725289173333873343039668065335848508669368732478825138186239230949", + "1938798484075554306652154855938784310914373048412192307037858325336409225122077425353377351987908289634883688473108", + "969765731585740930714738171936750649034390372202493199944786661446405671247164260301087953575856329852978577222762", + "209753676492015439763496254691745603730089501530767365887104756026087760819580979018544018772368539563212525822642", + "722699813080228210092584800819450835722985608791433760944176739574040121044614478168699471687944805559918494692186", + "1527073801599839651978054542150875248031209969647571850288728413971727298603301494140381627542003788699164876490544", + "636835958338556765036308860417522829860941298720325525373262314063162567491932289475170247094029501574459325553515", + "2459090729777472078681219679700342266608379322849292023807191563037476963054541275899385386234326198699772773316808", + "201350461697227956881939367452356660853502697560783290028599260377181035501748122736945465578413823835553361068746", + "692503186698797720742512900526174400762543066146613017547575397726089815173183924646828790561763418565946914394794", + "1241899613373249118004960143171878562620997390160610413236943964001070784295958903544066100664187157152710701659170", + "2218424569459770293799535844744592712128559089631415218646764353895297169671481204743385618498347979853864747718592", + "30233875383633423830613594404882422786828952039472630002386268358098842686152388775111208358403443455091641642888", + "1940883368813386776931713931274108167084932709376423616587304609326996335404680522126934896007708129681552929336080", + "352848385966829006998226052011021928612787673095755256951833340668230284499954796434118160307540575784724350285165", + "2255674756759394202142126792996016299999422945576427888727746882236784424209667711525989194080874968676182328741784", + "1921265542171930457759649316452588745358414208141340736696218270074653597428300624429185061954336255427253957810602", + "1449923153713633958593393161883037825741016349205150924499582121153031975597151565457358416691362357499048754063485", + "1449307427843418876612270299849065525866435872864767534968516621037179125166926549085631767938328064107839082815943", + "1930021288865882115656579497402259726628408525784557196585294885229440670845042502020020988027588220819949486215618", + "2024570738303069660629175995469371337918012966732899591634908308261779258776893038041174046317924388140831268235121", + "2411300745333751855540404415612036135760982184101848799297065833802193356254672028819700082180087156905483299875958", + "2086079397069237153860815444620561849396075733595085814076049629191854095909003910741938676191272460897489057927740", + "2318377706996733302144471888642795003175657816011798024935683440500716634648882292462856982327069100519189874637639", + "2118961825395188305600307667276628477108160756226045895369150254942222082603314031280943697226129127162029942806199", + "759286605982743162909269321722548288630716805488716723852551846727051337896768585558791818234472867510026020266725", + "36174686394751539504746388793829840033182825173386229044364845450366056937206121428927419269578436089998963188838", + "348661109835412669343452389103760323035114314981109479781700982286309569325401135688893897106554983881053601641138", + "1191633275852386857873843397485101172036751636195994356611072931497956656986728402737732402912206270375573839959271", + "2430558152888731123750175323598525940427324778147347875331845758979787366163839843102290564805368739352928879078691", + "1697386270981359069910793013476756780337806056398968266125464307837495810451947439704409123506499908169531222702583", + "1835324755745505747448679155699941311753671013363765958651001602254061313452107446129151024214843960313607560447593", + "415963641955041491435567554277060603646271154262787015458877479238326539517878403345950600933008228560845689967901", + "310239612779116177064841966930411335546664238899487920601916914745880355082290338791068627031058334735342219876376", + "227900368404627511550801346779607058659943810981686850901760838732913113027348151157346930390676432899230377929552", + "586349990434360271066490653195945030836699070917992323384814428815451449859328046094021689519602904459136034184012", + "1623576373063510759838776413667906081601167518930913206924915892177742225041165235993036806098568358212641393183688", + "15369500929500219516465933045573648783406816188171295387057263975969921619106370850099617757868031211257058167395", + "739088982052200689510855965775791942175361599399229056660133225083018706956185965339504748467431558873018028703475", + "47222863173990940423641201121209982506236861627501258040651724653895116512885169841180248876407614069394597279939", + "547363492181703813740430605750735197380841885397280702297414413065444597895413002508733261729324612845434304424482", + "2361105558494903889766760455304162460386208367498352056928096559620790848262982001717761365495079229981411994103585", + "400467498082789418732699638618292700612257612406227604262313331415590054096290060564121856295914334520133967942597", + "2039126310424759710611496641881076817300352554457173706165444019802743220413013278110163262961408420328701509898034", + "867625534147740256292048401718851976249020831048815492738866167285426258769328579590519885136987260926435311251908", + "991080771937550834026011202857466820662361070684833774723736868233184129234363141177571364267700727020280711455467", + "2453915323885264389757285217001617247646362887487791862393457451403302274541816719794625326365092376290164571091568", + "501883160956337761240131284082452852877658448909893372924008197722276050034323706519827601909051869196384203183269", + "702969058932063865055272885907616485609564803157666248773192800233889407654025973300314831891778514016495593120837", + "1747899875504345299397690503830302017847220753094715545889455016204687491069141658975654494017587824601288534416204", + "1210751366778310034434858697460499574903940848393663641569594662946642184660551958002638837184606409906443926456144", + "1469631594342934523626992096002584806537653932141327218953932662627580378026425704106208471757807626025518450931948", + "2121656570271112715190095981862268271138672811937037620444537834048862714840644845574645439386531830169316982233740", + "2117986375584155090378039914422424738938517975079392912971055440576823120938149016730216726951057062322268601685921", + "2087524833811800371445823371810577773924152575316700374747029390125344708921344816031267668248937205500504675516282", + "2417839746717232664830373166288465299535145030506959399325987411777911624948303390746479297889829081521636141906632", + "1113536128989181862089927127158249747803681720555077309266662675968918021962778106262799383482372490090730889880288", + "2390164577104856351196745049143687253222348838966373302105616432133043600595418940814069506531742629809173042478510", + "2058317177517621290900245425162659851227449016747506427822806466122948063318699857120007450111634002404999704235275", + "2228598043124431523561701808506988674128484236475799310611924279929393358497859437693906469618089279356205573012105", + "1316647190348231741861069364464732890274805997577372343233638896467236452722036383059834153324271974087205329112369", + "1079967333461625010157915146515978725610008650025198684570739858139391548898606626198491910569455947925975038415345", + "2123831600507106050803067812807325539815299158637651244955400296045580695068456235052128663004172284375670570514303", + "1772685467119258574273229289086621063191333317856729306314287799395636247449257479984137563123164413673890661402873", + "1112000040203102591105244559231613907288019963097166519433462625214302025707975036533457511413136607331892846979106", + "1607242937775770652608306605863133268399728772274168254932722605318983879650465408578820819924632730916391521584632", + "895026855587132756450939839989501923353433289533342983567478071114032135447338716096923040694313368512100852111721", + "415771647569595225042633678593850471609702204938166214130367312273403783526072641550222462892625241529620719428092", + "1654232002810522436425908418950927462729186416958085789866764030706703752730163994177327722760164810250166410653876", + "1835106452818865136634011177164472333806154897035231159265119291054516829594892739330837211361505242444278385959492", + "2176806038750273492832861431666869465298456478109575935091455111731534043289195731105464616906071620255102052104428", + "679453091453567414617315440699864477048557984547979533575428017746582036110991368953726823649643338597904176279704", + "290211113145091600678589461798751144641041798424159376418503744780463504452680864584675917241499501279208698590836", + "924844547305053984704818274259169547143547536612444845930267165949850053583420181752093441287798416160718392983383", + "2175643848159568047451382226871526632508232278390156534824175381971168569198144944729252477706479057091563436129232", + "1418152829904359823177942370663793021656939994263248602171159706630037744197622234574922369533608045082977229246034", + "1808632871313697687863433819564113243323206500245915096874588116976592449965699929624501394636119581121310744175823", + "2263012606692935214538610399456124051422326974210614537284922189379969521922395117904213754743260730150003468732597", + "1687099485323541740758659736261637508589624920437750300294723884881550486526722070924362156528896674099163080838288", + "106585498496562846366062600939677495833104474589817293612309675756951011817489570783734102096925183551706215042177", + "753867768943149359701405023666599578066855258791201610472659137788124709383757155705379051201037845294682995867102", + "1667965386201452594922057460525617295396037200422161055371263907629613576364197280061098266913505953411601157945960", + "2371162651192408884377627646207060025757809129153528727780644745955141265130321469108167615722069378930681964616543", + "2219484174772264831523302472941300667707847592928313577403978273721429338944550495856353550822214721822083250033532", + "1532792549426299474914118709926513996478196001946608982132255470692812097212849593826870977103875293951945054478708", + "2376970248787748169263389303858571439620975596116905465933611284982242081628451461558747287873243570844911163114045", + "2266545578364030618681134600423863488785118399332876198347687222135375835380847231486281428281995524616430195320343", + "193253443641754188122467815454886558330277453972190416989292198539919698280857387555288426797176729427084844283136", + "1293897451506650346573669200008102665827027109716085071974270896519126869775516420114747962111361846184190345596441", + "620447464382414461779350010064475821331089466604438558450525229128261044255833560057760887800503310435427234929168", + "1474813887260296229811274002019206900334213321112954236302667984099660111441308213472414795597717389794502370768546", + "1133535171898813573284044575707459606322014190422692141724661850442911462771379987907920855186159557317837602551770", + "809373783502648399749227592103003560098927717194690828124404794118926777050325327294091211848989588234270888081714", + "195919917687027600378777223979200914587250264845145770264478347090793843766848826534716278322326004427238370613523", + "1985021447125391290726579001024063274284578698075369774411176932171614768700104052320034372365149399862778430680827", + "2386580703839381479642161269070613464946906812683962607861451520884779791596921181590830689365703306705706996183052", + "1889435593930365211046324468432826804850104493005717429526537499105901275433605086781660158104679421705519319395545", + "1227659662452530695951472034017457631218326154769012007235615254304343254503951340866799692280171440331036220828890", + "2085725922834308457002344591405200516951135673202506405552299096628974333800468953842912302875554196984011982312836", + "17639664852289099350816274317118493246676546974973833275085426379221973792163740133995084777522465926925672168169", + "2258071627130527337085364790910375122333172150415293511502843473622538993002304414933803802272337574851903370898440", + "1180939799580705764347422534042130754973837102029503144049388487089550440670651529142820731167352385052565025128216", + "1775145540477242525195389249930951770081246014294029928962930948566417172889008470172306203409327009451776891516408", + "355391569922251217314763287874007067524257398130537703270313659084853472063294988620143244517219903795124108675533", + "1241411192438493454678662124275276801336827420371324991117595168798775373730517001244340762619428145929678435392245", + "46720651530162914411406976751461153590986582561500772790203596247340997224203124064255033888378675344080215359248", + "805373430296484071574733779355324581174259460672285546901689767991433250128395979274179885258578487971516665409798", + "293438462679899495754844231026091647195672700922956771434149307597709630563390543333776048250945854589310247856294", + "33595445278284688311537095711189697409388983941028023776511764229896182638485987996669232173391331728083231306397", + "955317339356810099718021939476296715776133591275455026355302884104521248006865044517629197874187750602568597216836", + "251853172398045160655866570335801214175282051662887028597208879667187800168067400865191624713745456707739062956928", + "1046118189895571397249053088946138592140908090013988454074859993552078271842708539670461719499405514052428264413353", + "1294184757095924033656075282346435685877820853532410777151858062204317187820169711288064724585083895518098048523277", + "2193847030906163482074838007022923775452912697274919864123657335458459231224802680926871768021860620979374453911520", + "2261717920194074247226862859528489050417208688368893996589143622139761066177544290524049372548681535373633694192107", + "892988408056829705181143437029218444122107476683624955767188809316629654171438965926258728531194280714205024137373", + "1733609975270967520012693418650382933433951840198345622444784291707849407177874836757993969505211318130872545646230", + "351787988429977157896380773492702790417349051953829614065517451220395363145832753953005331922270371767135435881625", + "1174001785205828375710228289377562389066904815921527329148892559097056946490083893030552102562653254549004616092558", + "2116385830672530709300689279719022508416887008114731565336770230667923590108275085553710743188452432889462538476538", + "2201892790640967201285915120081160580362073768901112618058428382671573188123433989568212774834566568865462970285266", + "863732263661194402420600445241500433360381801262424135963010521295297645344510311617995600486307068960276822468817", + "2151117287838541693721175131823492146680152158346057217847709882912693119492854121357146138132910055275634818288288", + "768977476364293375650195554377513072266348452860612386710529808429206886822730571762770301788745052317026763934459", + "862374333417340402665816413740422360496094962834764091732763031361789733225546826696921573164249572307850171179337", + "994449351060858599993293583287949314297430710085536383443830651422709899530717854380745027785088604769186144052123", + "1176231109484444083724849598195110182454490640843563051238757602063822106690454671085329064088621490814325971297629", + "2073048274548527255099742695171843819593367848178323100783194881969485484412315674651578289836870139054720962031240", + "1211668920032280495276276620506110518275737325466799715915767557217806989160410076301602427452472794873185971992321", + "617530721690044432948790265226022252875812417736230796022179041531187783807882333641220349846886995654772885348696", + "1461051820915593519884222265241558590706865879823837664901913368826394345861919137654849124989610492063533106593497", + "1498238288414772375776200869634317592158853476901339430720909839420053795132975561246143842514651339252193338616092", + "343323832239020298261743208784530753867414665682912241006156543881925260204692565044233192870012970768034441495920", + "1709997709623037881668054982500666833152624905539554927268118011907088430607406398765554141470799141556561498325968", + "684405736452008080329847762685258908419661588219750492161263987540584570942057786423577749097249280615638162041138", + "1576892236040454291100880585795770763275152240139820131735337431333337145528688845124645659352346436216265328469309", + "1389544484501526032020459017782210421741932899534607906045269552039009793916245815740662120901806060723582865624511", + "2421094893518703889237610435538251959280920435893695363223596754085245293274274930198312217995453592713314565305142", + "2215818752989824527931382331482289941646818727909149820676473502044129324137061043872996976431585428252631525184258", + "281285756630982584614379116978459819046185677281463217424551933376760377351134802107652598920701881504313109130872", + "1125574365774221270824840794986952861373733176278912657739878604201059331840635762102675402871362312046759826079300", + "816994219637975323652700541521847932602159208534713856052521476083273790539857821158541391703770872698625296667207", + "1487039334940643386866192190486986494488631824992044063515890124017494119246483623579230397781831514707348389895551", + "1182766527323284195653723162447634944214972938575552555507960422048590118959659411189926186557396975422036801349367", + "1716922371473403845526663729244930614492328410427736514340184229265642457880021314577869700677612455280755925235698", + "2262947939687354933085073557742703658527563936950904645744173083869666473382120990452574647112857467036989586572250", + "2006930739245393941836467463882832509912485224651781944893582421033874553031489048793434024121062364444425156838139", + "1501756882207728606149084651169799757700300099125705686195854849198051079375543412971804360131900952284268152733618", + "1602223092274672442277531031319690366606885259222864085109088585148739373823540736680250521387293416519648093590359", + "807746979094457611451603487950481261707212336432184955855312758236636960203129059647404832338094949608842219955107", + "1017833809017406714883965274623622720967244456402005551510418652497192755268354291464769549533622271408327436973449", + "2296565236519189612566965499773842393226989390320650374300586249886033942071094509645029637806120637003360384183786", + "1084646489800349099857456078546283741786119969781667144382292901407968958239162690333678893768174008676342602145848", + "711310873812482795296608154492764347758929135702864424935067114465771610929710935827166326937840268484667600657095", + "697466888857750410978358926358835255025492005525918365617781365993141981778395232602872703438075215920440539096803", + "1866830047623369972418905805508653835983724423221749845780278200183696440721311610777899420152807502051311340077698", + "80629805802126646904937553420060203891076931785964030618296350083407320683839340995324906609698438946768199380845", + "2200633594524507591240060958836336389218532830865099608757929911807555727478113387437757599547318769962498066718809", + "1756261278164512115707746477853233209040317046610997127364761804390005344869025016710851804805521579236956874598262", + "1037819419816852876357331807417298305237309803042136486423109782013605265907282488757300696529801219638625764803320", + "1038101503097038415794450119618353937712066650150099328881276901884998217177824508324979753655379522940934114544962", + "150853724272051469605098780717964253324898445007300270075516323284620236505193079484055142521343730983391925671960", + "1621930379137146411613847734632223126810462283054038250668606108817536007031106296893470283517688469694402777002407", + "690205851903425128219888755473929687674198008363927942040965415313836934682729847409061195333258828818098655421706", + "795565834057304696100661308635481310502167689475871214143475263066973786978101447387369687010463903773729812328556", + "1449537045036168934397042469847728199996263874167614724677713959149274748904265972128063247365052773199151245180167", + "1380039381300987565245003675897012608564883904107368660672836817400061902590938304993707733670953950651268811888921", + "2363544673530334590570134086992698885071481712894749060750513000322947871321096041826711186249243921271036028867434", + "333451822308319582980843538276162044412562643024419819228520291021932837577611475919002794414525669324366891280293", + "1211681417212157758248464224769642099644881302323683717573597304634139093353566771739940398955232236169952201218532", + "990695458383068982699523939765904523010746103099719447475958537856027606749369405432714329960978763771412852767637", + "1800250838645388258483744743178566304308491042039013269326144008799350452235205798281005355764141190796630173345643", + "13135273613730633435505717596266791417044500675862500133614075418415710628366552964838530491498136587826407804307", + "1510082229037831006782944211649317770815580145121721242212489093310435462716490528547667947578390774906708120172182", + "2407239950453237455559535032493884415565983426062166301392635043197606615385936831819916452300566005719137362525060", + "1086990776818073953107814064107314732186805640636383144958245871542914657654573430935984491902003897532867166261683", + "776640031820138728943662735659902076246180569820249580922208892775192965432853527954825022869027282904986969581509", + "765455161673383549859047068585988656473381653274156341376326963006527771399889675546184153192375416279922356983675", + "1386352648128094704810056479181211076306097938549455076631124818625678670430773635919666722871857594551652730816915", + "1784648961487712628192268780229472136975131488078093448328776610890352661235771211432063504106037814061201881527052", + "1881778749135374926426110029487731952393325829610722842206716742954472426882315542921148685706369087223249396326847", + "1398527191282230036246828894301693654742129346971744406248551019671912606054640061698031995136879358710168636797534", + "183602459157708302359927217452268392414296871957549199767320259898310024497050833162674862715871538528258440526470", + "8604205462089070136568652163742127383123185546062817105491791754132562447502760750970595913616299508613576968081", + "169858437234628878957045863118689192494589000355129892594026045470046204235858004506422369262858977348261041839459", + "1426436886088444638703384186994322972422036428225753735722342896695535529620581494712501620780724943223198850908387", + "696141619524582764532083975345629050133893374252651653027898062654298868371675570072944281810062544470261525258786", + "994854680623574178441378332646603636632914226060010317919904475457806847634907270006058552066661583375824758157309", + "1752257848194740427451730963067958777512199104205575229341701926311578215387543730502030982399871486081944573697515", + "966392122778757478680417062060681200907448440130742696273735603614311572442211318343949272201989044739198649883866", + "372684344172013940849086166535585993226629652606171678880096851954471402452225078544234994705513554940093611517048", + "2334975813385423451245969373683206455226695953958325130049360054264388482754539594461576261009340744271440023076127", + "473817006497588420224960399051526878233061128299849082885508163883625373146392084992186213075594600614053880169830", + "690436120002054066727091400670649131225404702478810180956316646315750678089645736551401111246863636044062970328180", + "2395794895277468017015599003164565378424703092197395128945093491834572940803244355983040761885545391376554579414134", + "376612719782298395738070552870128004143371845117992700762128866436318563370127622545371006172936000621196506396529", + "1239125395074228036644885426660517897345375070823092321704093355811351965299510659478408909695538733726984593482313", + "1806076001795979228834211351173188659002264195546259915001118422793366888939528805108360253689603110284780270895822", + "1278848065385060554548663121596631650780992616679885926592792508616616917974427707612579741366472207566702917737694", + "1978741816331380305585464806017097380306190645767485631588949562697957356415268373089895902278579368184413858814803", + "584362893794223646219421283365409990526049089974407542480360337886427108656458410580111811788323429446155648207176", + "822902305774956116240783018539596233390637585712200343653261677355949021406883227067996058195101811357573852426183", + "1776963897209930129551498335245032985551612694762054691806576494890565744151142625894635352657418496689059300835646", + "2293811044494320743489397183132256799878664403383999304630532148178510334850073007168075447912046992678117477131893", + "1766850279847777482270361239004428105626114488766112320627615540128548224754239061798392056659724918575752420398523", + "2135340888849239159024001173166655115400100616835963473191551743196184133236332814789587485738741512202592011919642", + "855947332352289071356305314252239110086732322330591336794898521476565086667908155269815987706186082329080469656171", + "1847070405737634228212886363048788851852574786511473026326960138405633998656402834744225642859569303677492741069849", + "1415100679652884745853547075171993619070323485699165895083936627556088123077576125577554155678657824677693941843505", + "346366345391889929133280412056650155378898730241000423051147504005913331114876370467769307400675638141810990020869", + "604689666666372136792946282618231880963667020422624397886165775364510692619107723466038717317183321380184186019296", + "2069394094967179267694471114890300879170590047239248374127608555895738529298054715739985356101386006582780946939123", + "278911208732584157694581168904659157361122777560760504846082459799436393598601961086553142029554810894659858461702", + "93152710295243137177118458368021386668227093826505348686432416022678035904685347164176243633009984928996346210905", + "267489000338008975813701187050754930949127506594306680617555886691638297858029034484145762033631287179408964960872", + "2265231552110479976960262921658261477708630343087767640514920158728747726375504091414769270570936980529331827281616", + "1182445648231866978772243286695361475923849882221068643889851433018014366121224155600926484100788842004397758984256", + "241517724447489858758438200268271722510825826494965285421040612903752719726406747427184502087874570639671734534470", + "1823354261416136556481042795452796393821461374034869686685263031880944994946901993133799246912363787989721408746527", + "1080147205969486842693292663417601181074237004890452461696406785790263647863433774832221984308751494235473031589447", + "2069568987890620255705374217082049381961184672487785989587242842400502209366249997628999423671952628669654629473059", + "155138048341822114750980824961013633118869235085251893610796591651353459624445485342141550504772303858066574482827", + "2148165898434703155750349790516354510073975643256024272333274856552676831433760439334344878894378272517287195097639", + "1970546152569814847135463697694380715746135839620506999284425565282949625960182877140484228779170618890954050940570", + "131661849466333323220886258672692172437380864203495975499824460656473887635146092389581610546110545644212501475784", + "77077394525536480771036378143971453870855524816668957448465046342491619359980209815006213509952518887975334851470", + "248128116332717035361428040378649497802837255124184755553021879675636806318284128612916350768157816728940487577560", + "2106742636456992564821001096469510733670037670655192841289781249032421236970546375712919882887811347646547678776195", + "1063089846377109369342584790118892407491935660698329982582455896151644133189093592090268247032624981252751880483822", + "1548749922485243068826662467126348754662312284077754013571589073468235608336263001184330254748101379369517266746661", + "14527893927155943457341245877221480556234603212674974810684168480274703744572806733964183344106576014061529044132", + "558689056620828992730312628647587884920209315610092119263204474707444611476066197230906021035448572001738648908848", + "47604929964087777885475706468150080660529557957304561230446648757368020777001814845515301290428329161017980371505", + "2058924117174741605575038832771681653954506071189452452137869686295022561252861799849008610871911577462930041050393", + "2340370180681278104472574322283973699033046802389089572511973902391756142855971721580329298269538612949070801319326", + "1121717712923375686032202441139073349339307389937004792148443610255184272617278075112049649450012078957153280304756", + "1253752782973324838694230762573477036868714525167484111836598866865510630616007871533763496465963992247882644984", + "1027428252699948843893234851121303686923884071671839905572018921643706319991038169359562847858896348344462096684772", + "644174498003767012120510687034673267770682112417569879656718825072269936801668227310184852318782473734465836906208", + "2036687305572712062763541389945193548113834392665979568094146358374021197252098198588858359819410655042476299673588", + "1064958217728050155142626637560657845656126063229702651025958456644505899091439925482636250109554989438104463568587", + "1787475482907321558906550377317745819261669979788151651667653334959390530952951509706674027699207159584554293282356", + "876269539628357658687327642433029984654263872456998817566148739210825853472619553066307864982214719651246440571892", + "832019980205501930696215485440550001177192356409601960314097129250728735290316579283122046187308992496209626903638", + "675827987137226969450735355789067165147419853900361562144681246612503906129508088166399716784564732269498814944264", + "2262820138506544514860780129105334839212817826519443163497394557289051633520492100976407133186961313396174473018205", + "1563300816692109459047625218476920172021443640994045374776730215056753874227103955369407985298672031316875851568690", + "1586292536104325333949969020078926966566158757087217126465431183083804882058908996293826642889635539333030497377083", + "648485514715763086587829512815402556060149775011198437155443170410400231151320491843297280314516725336746945530611", + "333623788586654893657729126587918863412137216311472513245813013552578806018401282769993621412537067389206721935267", + "1071224777902633223996803655034600523768935054362066094735573136344651922850685637895711988405149514608204190277623", + "484821447804610513938496656480682000752217467037319991250486386855158302586744630410758237717709022418852861916812", + "1164943779139844649101135196765263354000329118445862276460308540322014530860600213364411275468378598462309570196919", + "1584865339447510705910948331075869513747496013193782590586049574850376495736657072496276953462052093398896292427167", + "1743411636229744029722739421789532317656281200471799974707521096343286326329917342048049817681370318758221536869934", + "2352482865717172831803098543240141982292371376315274805615193800803331443501930647661163392067896707565785594934451", + "1453872973042690732705488997274647473267380686846313995777254435946090683871567543945571859128530566769155145658735", + "344657909303291642381524855411687024365640851081134858318562300217619161529844639017343388417167279249904703958177", + "2201938651583566753024097581425617687832324437502376837419101836396308093613446330564882761111441190231471799286431", + "2025454563861431612335830997066165969355877753617620688992211946161416497565124463482798173660813691782196128354475", + "2400898880067315837152063853009687655071216459119660534468932500230957994695887534742704001764286369757871934470798", + "2317259053017007638893282657872394507087243840831203067751864083987909919877828870137623561830332662875674613725507", + "1743152519255918353750708857944067418101989042309369904985275868490562212219726793554348257532866482578841717426492", + "273746521369049231779311543878411628782302100087044803154921462785556268847613066777726155438673129775316417879203", + "1881156759457181384282400180415269775253373706404235332720294751446110404931147637252852793974343411004902075915348", + "882016276062104291561430369947216723101963833034444085295381585084111286709493822862758939240578049280008404604749", + "2027346038866823508665422570001986154327376572395580376601658304713196843325185655575559286750668516257423815462606", + "2242228735749675907316916113370362949060613241574833581728388122299557507189922385758677426459982649248994719821227", + "610028358561951028895460634488007280394339848673368173342383913983490178591108672955683272528438430855004338411780", + "317872378565780134652512741939355261219046730301387080947361674884484629141180464954032065975363587326323866906352", + "1070953246307015846463360275404180429308161458264481777681262974201589419972654947931261009080666921907861181157736", + "1730472103561523323949618747870315403549252577342266157944170910982050493664109819720383580287878937828458699656209", + "78659914914903077127909000209761099386408192320205472646798886111731751743216046198131435578810239095806475702136", + "351878083128513092620608142529447412543759672919152619521962169107842917349255749146234445534736718211785232485097", + "634883913936703009190422786365141627415092988852705328076589132287608136973768132092304760379045644116312599193976", + "2349801556971700008962996878386305235004386275717370728223226252103290875944711970167622349551299765691708056016390", + "1584069654928791795710677753434663873178064607157000624733775054999034461462246712172304073243099112756175912426537", + "842564944353360115012211283170373158178763433380814981494038288105762744347678040681023534764834238047291952978276", + "610005588013170081165830150276333508219596112391554088512137145939626675336834544503295091317805229403904339003055", + "1231069911656214992807565999685859453514503830059215983378880865458103912025715504583856394388143304157628514411173", + "939406602646902141536660594617271354933584412540151968037585013785196282251928160975765139962281611348849515346787", + "1653819827235865495182495604568939885929184625441139075898117891570961720190576005999180834403068293754856907326351", + "1409794473414102067420906023846295295028748656996008530726536130207180358411846309497550025155039673803127284433044", + "533215967153803211515961165496175305481877647432351210801269348482801547150018442604810954580652046914158195120778", + "1640196500156028820577840999678353953653691423587420785206924529734134223985085402939140714483955423449710875613408", + "242802713163475910076232296290776460784844418712851489676531884764598109565835623862334255036143477691285649980597", + "2428981837605749727147767102254395200349407788659254349303440186410234096472166308019577350419701074853221888979459", + "2339932982686348992707538273153948290546684447234895483829748344143215068265234115137797887647278717891406680410740", + "1117649778333779157979910163367916000477615155845151130845028912391870475339023405562928531017803855889185309048698", + "1219533810907940675666955873453159346009210193081453030550823375204267031074648147461028092311770536856941898324818", + "2397011654181784176432131756972869111773240264495758766828947830572295032467131596485800584484460992978936748903771", + "705444832540304056398678476941459345984352569533352411066334824762812353501908730754668291808959304092438364189989", + "1338956735250040819284523433551636212917381788056327824786095249767520222778139502698693995378661410503022781906094", + "2392655674088565137085849219086943918479530135668316363826305836597079056421257050981660363986653782362896473319328", + "1562034967301112018312659071531399421162219667466330175171725956187922717534530845780360034466564934035015148264373", + "1304847415038653973210711589843627478556059583368627476559583342934233283302372068870267431336093156653099276376350", + "2113397640534038730538189108463458630703816330005742980411234700606835099212983903826927482194672204054031029604881", + "1194722944585600670167404192387105972481158260216652561242378968333262143843853976395597317346905018419438193106330", + "1968289494203364899804944733714957618784880430460862935239199765839114362558108862085548364207433028840190329630796", + "1811503617088334877569836989811811931871193625774694383321844215565723897698645554907268202601314122437964755690127", + "618788811186837954645037089913358068051081864066222345686458870005244867899373708499774800415176453493739570759643", + "347810955750499712464417492337096722226842361443261101951318068242956385661380481547651664720444814018101875302983", + "792068870329630070409844943672110437200413931523622135704364356156150005265762477635514940737214015645834504512526", + "268697860228351388326474361640066159027672322621436827933113696551585503549028441511659978884545918948573679834477", + "2401100949048023334171089337510966902496877357924774047202153890334875922284141249607680407648800865694541024795866", + "1727325413666684343096937586298597684193386173558167496484811973327048932933067984677678863246361663531061983340362", + "1312981349988465224790022780583759162851043899906498835745769586823973204502111274695133057172913799654928176901598", + "2202072868394536857080302875907094688576860504124472928369634250064598557510349390813186307986739573440999724990800", + "1910610173802201602514357838343878957722613664915840974116833330870227911792448971105109817825543696120724878689355", + "1798427630803987071657268621347172425858154120023299888529638482639946420495734270820985847094604783345778235875737", + "698890109325018567416833528098574007322567886634711739959666976658900572665792705443136320964464859820673581808519", + "1104048112786868298780763519795819218334458207208765909152497042054554531667510008548941728465988872671173922431055", + "652174092516077422147784630111140200001955513638014597215204651668427178943011147706277795492123618301511761459934", + "1847430502501045801229035173829311048964200872296432630195257315553827393599134296678825702035000020883128205148515", + "1242881230538622577210862462276010604272112967644191858982596387194272535705197365839565034063839220177200179793231", + "1556257781745219039924674947204783125694034171685147603383296036312110609319892637435073822395885060227529590305287", + "2119276108019259399073998842914336223497207920252032457771585474113149815741041775736302285971125270339896526111825", + "1146009107594103402970893283847446678710732141452153362735363165381133962148096691563580194231798981244900123393453", + "705434281251516954976240639574973802166447319786364375174523609844106175590541759089853132054428864301764913765957", + "1163862779692313920612296041414974663450770155151035190159637149669190721660619155363656121316383671673706777899213", + "657682479372172303561107671657325586070821812655640240360325681747114573229661974551803276027137542178822614724154", + "832612747652310828954938065449710638763038121256004012934598408226690288465077762584775819338212727193746462043354", + "628233959066818537665285070218377151404202700653537423058650266770611470261804869104684377556131493187936438395491", + "421959335396060025556783255633369526036848716316626969849598348084188540646001778910725243575254868569334618138398", + "1561354833290947660102324224941460468835819563431275161394052106141960763312672886439035660066510972634161177062850", + "1715526213107979326187114178224196526144199023426207366424891233996408707989240891842812124128864751061935059833145", + "705110587799951639096652815561105533410413390914429023750319634980119548181088411090717419304446075585870332109571", + "2338025162700378920116224357787904612720848224658721253719049647474353713158417762868475915262612926487051833064537", + "1842313233168178235924035050992206652888427262808079338629226528231078716758915108896198111622154572335478837749836", + "195313822731934240486686444063426014513177916246803479261353759047110293831139858951467814452013889532523764043651", + "80714538962072828468315714627577617998805188292745223294131865237693873083111371664671188994654717119203485974105", + "961020536366174706473870962569101196405758454955481472141986166230737477377864781966386493486386657900818486097240", + "1048128144192012822146528470234408539156631885065073390771761552735787414060213256995424547479756898890434346880442", + "434393525190292161311681906124569678897336805344574141760119547888348712248656561493313250744899881850784419047348", + "993947253574711171749622245683564579178984029741859756491919453171157046825415310208481812463897297861299995218590", + "2366011803309643008089677867637702758596145214829119336385384195061872061965796223471441356202451570428750623387486", + "983422567826048374063298662751673202597931063465557383061650131140290669499475239940455312853782912328782817691278", + "10631799561581289216973291155594565075911674583370714248506175992829514315750290390152594077031849516701068619287", + "1661580660398586983037926714921085237372791608447766235419963204175618238868176709560031056011306848300202353838134", + "251033741802310041276564164970141695539950106071020874534124082526860696174511226011120221334743932392212945829077", + "888263469175740984496539727650188183004438850240677220259472767016521159421285911139384190726382930159952611818326", + "1510021329419084356380141097667059184400782750405890390815035596331775161778238729723562827331222651506929919447406", + "1501606516495061872187982354950932698580672505726004130569879262186806370369486944486967220889350981690704779201340", + "1447784663721610844781044318388508439004216734795754791441775053021893188166472336622642520600525120052575992117909", + "2137694275934741273868421006259975433573088359797425634080025237821358263017004737453528451691691074580544223143470", + "1406632806854402781036292948966267454619540907708736811412471408890325527158998644556283998611844100718659248255319", + "1616154538199183401017986184920384132718606015634121350993343962021673196695963704788598936998989985592292795385764", + "550023783033232106898947158946931359927585390549141494253660406627559375157411832485033029784162759884130606546736", + "2156002001865688169798473436651112991898960946178268151872471954420359431184166567259976857192675238549609983640275", + "1768377957234289316346737658256211888040227869634020706160550857276945967216958094620843031778084094546712804567562", + "1931898092115218464371575019673547468370451812433941148140781306266805418340307220803267444868443462785085245355472", + "1726167515761403355867668373852698864161197086002332775789667185584049960980522620439122828738916843296696523496372", + "249748683292772703955645279963248624841972996290423533769536282363461313681667603623657082843835264577719253402171", + "1328668094411214094648060163010717018942670172762747084807172160237927730579031335223791391881893525718540209811256", + "2119035492559961859857490964862504142457511086455311671235406447558596750578483882698168789193170144755311185477907", + "922633588065484960957796967186591956889888487696152879984730715942799648506780062717638927793404147067819769939234", + "2421865890128782279394917730141694119755065331817839893828696061305567328774779471037411871499454783318819514185224", + "2420065057560672260578615993933867488301594085819160752940295466850966397335939438007740292667088898006075399127415", + "1724918112777882241084503742715776808461348679280669047202272869154199292786463242669685316164757749484441653556361", + "2323939989117340289363832525790452607755210154547265715718847489356122589957388097818529523286477913069559710055976", + "1380072070836925890276877010401342904950092033937211017430637589562279085693303653586692057015010637088510766137726", + "639389597841341736153782606949097693914470469939260050994202020048793388756781793188504263106969720246395972286250", + "601028814306176416559220932192351806173232161821489904141902575241179106780572419475246491197225991632548954063341", + "1771853412888741691174486757655349591385789139856991420006178748886607253153375154451868825446982232728726118114698", + "91240689950830421481369887771253983032312310508508194304618003454273253585785168002606497108304266488973873081813", + "2141645193124179202512343072364642413597852766593988570819183396594374549177021260871722325522433182415291760900214", + "1530577712463500888718586949594577299223727421739878122751840924497879375414256751890681412810851157186115988469775", + "1973164996792276160719502691955880210418599427771502303971229761596635702486333352154169899691172118593992912755721", + "405469075053354543169935174731389914486036903929485180242025239778394595574807049249287305546843654342556115608593", + "2056843363104816161279290481088457418374924167715822684296079452450783133797752487562002629251883438762935057887695", + "1724772351157238583132087736315926752532803274779542292879096577893250285247472541098688009111554930127757031022669", + "1790492182120673024919589325337334821592988094279096989144533772301687190002745820599907324803310557981344719478478", + "40621608757715256042361136960088125359190700590288285797910876111451704253285294655891686673451064197880162575208", + "1523474103099716601858276691292018346244810253557630930368212125056033093158729874464745248159949979457664330287762", + "669422138247486901819080052960585670195294115804762258448756758815812902180199810768307850893102717659377848617167", + "446635376046873228020977978302205752806916122249353636449278318761609563184288043672242374367299494707002338846972", + "2011080479237748087797435358956982229037024468945037402404222325048797266771585739212203061020878583902854851901237", + "1211579989533767915079964009949062488161089483330691925468999223653547036719428941408352928580065350243220387411332", + "2324177544232566836995998950193465201770849032245688674912061507317151738619815311708854926695621467087215326211517", + "1451937417580251947246615256108850062548733591066098497242419831565750879902421178620702789244260586893756429117775", + "971209559120389112118814391665201484617489967346182610545301525477271528961633971923014495150228815441889494942831", + "2026907840435218316232199782942929784631037745919304731092365803263487188067128563439564774924371448233574736775372", + "525689830887298117375269481459359533674328256521973901139448103695999455689511881893608138719739866877311323266170", + "604116079430227068314285525702930191680370607683629704471171729703537689195520584424326230351326641877501919626847", + "955389254517151701426487001393253636437112176504226865131720826725566606205624126411666018970089872300359363093746", + "739712763308614444070889610111670817737838280788698755459778289319820860574504256803898995969352957095267948331282", + "1659981059789176358358369591913341984456706675665231789301507787708176502284178030889990074720120718655371466093185", + "1571736256925557626228665164296715262119338319580608623330297061077106597890543282951615303719763268448339888169601", + "1845422981258891232620052459965493761449368465033535881435082308167525619152321959786827464663608237317915473776887", + "617718217920920138352410062496835054519476904371526190121320253648702450047454801614425777964828201678030743352136", + "1575079397235456000687455873553578019993599281386019324186731792154493496272914459302313230895138313282611175155733", + "1707719263813160044645977618391900754293295892968966887979941440554341280890996773451110203483229553433045554691146", + "460872079526182431217288499340380286202851096842635274258340632791921003322680505123158048427424802318531483003045", + "926661324341151218788231950029319707251549791376882958165531147548947894729682404642647437829991709234362499248389", + "271245084618838055029858316698797604603425295319330018413748658998495298304490926817149390264395450353685236001983", + "12470864519308632096400987136212996663495410373401102011334882834121666004480582613606495911563025798154590287385", + "1062301172984531855280334630190989871860769168748031115470830879096069614027028877437312637748784544445003144800984" +] diff --git a/crates/starknet_os/src/hints/hint_implementation/kzg/fft_regression_output.json b/crates/starknet_os/src/hints/hint_implementation/kzg/fft_regression_output.json new file mode 100644 index 00000000000..fa43f76811c --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/kzg/fft_regression_output.json @@ -0,0 +1,131074 @@ +[ + 26, + 111, + 235, + 154, + 146, + 193, + 78, + 248, + 11, + 32, + 122, + 244, + 97, + 230, + 101, + 38, + 167, + 158, + 187, + 19, + 81, + 193, + 52, + 251, + 150, + 225, + 8, + 44, + 239, + 115, + 37, + 226, + 36, + 240, + 245, + 15, + 143, + 171, + 126, + 151, + 52, + 40, + 124, + 82, + 175, + 66, + 78, + 239, + 156, + 96, + 96, + 107, + 38, + 2, + 92, + 17, + 175, + 64, + 187, + 201, + 197, + 136, + 123, + 198, + 65, + 191, + 53, + 215, + 212, + 204, + 197, + 138, + 189, + 138, + 233, + 70, + 193, + 13, + 72, + 170, + 129, + 17, + 240, + 127, + 232, + 84, + 47, + 105, + 50, + 52, + 87, + 162, + 188, + 192, + 83, + 11, + 69, + 97, + 113, + 146, + 88, + 237, + 202, + 77, + 208, + 64, + 82, + 70, + 22, + 244, + 86, + 144, + 250, + 45, + 109, + 23, + 117, + 86, + 23, + 224, + 159, + 106, + 5, + 21, + 248, + 20, + 8, + 142, + 56, + 209, + 243, + 26, + 17, + 213, + 191, + 210, + 0, + 186, + 108, + 184, + 152, + 77, + 89, + 128, + 238, + 15, + 237, + 61, + 129, + 171, + 244, + 123, + 221, + 89, + 185, + 117, + 157, + 112, + 212, + 86, + 66, + 78, + 146, + 91, + 170, + 68, + 177, + 2, + 185, + 35, + 248, + 237, + 203, + 185, + 44, + 33, + 226, + 176, + 18, + 138, + 126, + 93, + 219, + 184, + 31, + 188, + 224, + 148, + 65, + 252, + 237, + 101, + 70, + 108, + 44, + 8, + 172, + 203, + 50, + 39, + 244, + 137, + 117, + 245, + 130, + 224, + 82, + 125, + 86, + 113, + 41, + 206, + 24, + 13, + 167, + 196, + 38, + 64, + 92, + 213, + 55, + 222, + 211, + 240, + 112, + 14, + 10, + 132, + 96, + 33, + 206, + 32, + 43, + 202, + 174, + 206, + 100, + 200, + 158, + 185, + 179, + 77, + 34, + 217, + 218, + 80, + 65, + 28, + 37, + 114, + 246, + 13, + 136, + 59, + 73, + 17, + 86, + 163, + 75, + 124, + 253, + 160, + 114, + 77, + 195, + 62, + 233, + 203, + 126, + 120, + 146, + 54, + 127, + 140, + 231, + 232, + 25, + 111, + 113, + 57, + 36, + 220, + 175, + 7, + 50, + 64, + 203, + 154, + 21, + 189, + 209, + 162, + 181, + 126, + 165, + 213, + 155, + 74, + 42, + 41, + 181, + 32, + 212, + 197, + 95, + 61, + 125, + 93, + 81, + 140, + 15, + 68, + 0, + 15, + 126, + 64, + 18, + 250, + 241, + 181, + 114, + 129, + 20, + 71, + 253, + 235, + 202, + 27, + 200, + 100, + 176, + 165, + 43, + 116, + 187, + 8, + 207, + 107, + 229, + 214, + 172, + 91, + 26, + 185, + 67, + 69, + 17, + 81, + 72, + 139, + 167, + 233, + 0, + 222, + 65, + 99, + 176, + 159, + 24, + 120, + 145, + 119, + 51, + 144, + 149, + 10, + 23, + 171, + 182, + 131, + 76, + 95, + 4, + 177, + 244, + 218, + 216, + 179, + 165, + 245, + 45, + 241, + 118, + 1, + 53, + 166, + 239, + 46, + 136, + 229, + 173, + 172, + 27, + 118, + 139, + 128, + 49, + 205, + 78, + 220, + 5, + 36, + 73, + 102, + 174, + 144, + 142, + 67, + 38, + 207, + 71, + 226, + 114, + 139, + 18, + 150, + 6, + 15, + 113, + 31, + 92, + 227, + 70, + 70, + 174, + 165, + 35, + 121, + 61, + 245, + 136, + 74, + 112, + 137, + 170, + 57, + 182, + 198, + 117, + 71, + 129, + 94, + 153, + 144, + 179, + 57, + 19, + 139, + 51, + 171, + 220, + 86, + 156, + 139, + 95, + 249, + 54, + 196, + 140, + 230, + 188, + 34, + 250, + 92, + 38, + 202, + 126, + 41, + 184, + 225, + 63, + 143, + 241, + 145, + 205, + 54, + 128, + 246, + 56, + 217, + 76, + 0, + 33, + 105, + 86, + 108, + 249, + 30, + 241, + 210, + 27, + 222, + 202, + 135, + 238, + 41, + 20, + 128, + 5, + 148, + 253, + 79, + 4, + 126, + 163, + 199, + 159, + 120, + 120, + 226, + 87, + 230, + 74, + 1, + 98, + 157, + 75, + 235, + 190, + 148, + 188, + 74, + 63, + 57, + 198, + 212, + 50, + 117, + 131, + 229, + 126, + 153, + 187, + 147, + 66, + 235, + 219, + 128, + 133, + 29, + 26, + 84, + 71, + 120, + 22, + 124, + 206, + 70, + 120, + 228, + 226, + 174, + 58, + 66, + 19, + 2, + 245, + 170, + 216, + 39, + 40, + 197, + 139, + 35, + 181, + 101, + 68, + 147, + 160, + 14, + 146, + 66, + 98, + 163, + 236, + 214, + 88, + 233, + 122, + 218, + 172, + 9, + 210, + 31, + 159, + 129, + 134, + 45, + 31, + 71, + 156, + 11, + 116, + 60, + 71, + 164, + 152, + 114, + 151, + 62, + 55, + 156, + 100, + 139, + 144, + 151, + 110, + 48, + 6, + 163, + 0, + 90, + 99, + 190, + 155, + 98, + 242, + 108, + 195, + 201, + 79, + 197, + 32, + 162, + 152, + 0, + 48, + 48, + 241, + 195, + 3, + 151, + 154, + 53, + 44, + 112, + 81, + 219, + 1, + 229, + 3, + 149, + 206, + 113, + 12, + 119, + 204, + 192, + 43, + 239, + 220, + 156, + 120, + 212, + 187, + 228, + 154, + 109, + 15, + 77, + 152, + 217, + 175, + 137, + 165, + 210, + 28, + 196, + 245, + 249, + 149, + 44, + 1, + 209, + 31, + 48, + 149, + 28, + 84, + 202, + 245, + 169, + 98, + 204, + 192, + 137, + 203, + 92, + 25, + 183, + 152, + 124, + 161, + 243, + 237, + 222, + 195, + 144, + 187, + 30, + 0, + 110, + 172, + 15, + 29, + 115, + 86, + 194, + 31, + 232, + 93, + 55, + 5, + 47, + 222, + 49, + 158, + 236, + 147, + 158, + 235, + 159, + 138, + 52, + 127, + 85, + 250, + 147, + 47, + 46, + 207, + 236, + 87, + 20, + 205, + 126, + 39, + 117, + 203, + 55, + 144, + 170, + 129, + 189, + 252, + 215, + 44, + 155, + 117, + 6, + 137, + 245, + 156, + 67, + 92, + 218, + 91, + 212, + 226, + 152, + 3, + 22, + 180, + 103, + 93, + 24, + 46, + 73, + 81, + 198, + 252, + 45, + 70, + 155, + 87, + 171, + 1, + 76, + 202, + 155, + 21, + 162, + 78, + 113, + 91, + 110, + 0, + 110, + 132, + 170, + 9, + 49, + 15, + 195, + 18, + 247, + 237, + 71, + 48, + 10, + 34, + 183, + 119, + 254, + 110, + 91, + 44, + 168, + 200, + 144, + 192, + 10, + 145, + 141, + 226, + 218, + 88, + 168, + 155, + 203, + 12, + 8, + 227, + 187, + 131, + 80, + 137, + 249, + 40, + 116, + 157, + 245, + 56, + 169, + 14, + 86, + 49, + 52, + 76, + 12, + 18, + 177, + 68, + 223, + 127, + 230, + 216, + 22, + 255, + 50, + 240, + 186, + 201, + 153, + 220, + 110, + 36, + 4, + 118, + 115, + 210, + 49, + 165, + 146, + 9, + 124, + 103, + 102, + 35, + 27, + 45, + 168, + 13, + 165, + 175, + 236, + 33, + 190, + 143, + 48, + 134, + 49, + 67, + 118, + 126, + 78, + 198, + 254, + 37, + 101, + 9, + 199, + 0, + 98, + 174, + 155, + 93, + 128, + 184, + 107, + 223, + 154, + 199, + 194, + 130, + 47, + 7, + 75, + 135, + 42, + 174, + 134, + 166, + 116, + 148, + 206, + 41, + 177, + 180, + 141, + 128, + 179, + 80, + 237, + 137, + 32, + 180, + 83, + 51, + 124, + 226, + 206, + 14, + 57, + 101, + 182, + 165, + 246, + 130, + 250, + 196, + 241, + 180, + 91, + 142, + 248, + 129, + 194, + 123, + 6, + 175, + 108, + 187, + 203, + 255, + 191, + 145, + 135, + 145, + 19, + 61, + 195, + 252, + 113, + 46, + 181, + 73, + 148, + 254, + 90, + 22, + 233, + 198, + 218, + 134, + 218, + 191, + 98, + 83, + 229, + 54, + 48, + 78, + 13, + 48, + 17, + 135, + 170, + 162, + 9, + 163, + 115, + 0, + 164, + 147, + 228, + 72, + 122, + 182, + 177, + 73, + 50, + 206, + 213, + 62, + 222, + 179, + 45, + 147, + 106, + 163, + 183, + 239, + 141, + 203, + 29, + 113, + 199, + 48, + 60, + 221, + 59, + 75, + 253, + 31, + 67, + 243, + 103, + 157, + 90, + 95, + 235, + 69, + 32, + 251, + 126, + 75, + 255, + 24, + 123, + 156, + 128, + 65, + 172, + 165, + 77, + 235, + 170, + 105, + 69, + 216, + 203, + 152, + 180, + 119, + 101, + 57, + 218, + 68, + 18, + 203, + 253, + 183, + 102, + 199, + 1, + 16, + 181, + 90, + 236, + 76, + 215, + 57, + 150, + 246, + 239, + 138, + 0, + 189, + 244, + 59, + 85, + 21, + 255, + 121, + 201, + 52, + 21, + 90, + 223, + 180, + 152, + 245, + 203, + 34, + 246, + 224, + 21, + 211, + 227, + 164, + 143, + 34, + 182, + 144, + 16, + 49, + 169, + 49, + 166, + 165, + 35, + 48, + 124, + 229, + 191, + 77, + 124, + 86, + 42, + 70, + 169, + 38, + 169, + 213, + 86, + 147, + 2, + 24, + 221, + 76, + 71, + 123, + 117, + 201, + 175, + 231, + 169, + 15, + 179, + 109, + 55, + 192, + 187, + 104, + 66, + 92, + 193, + 45, + 124, + 193, + 191, + 37, + 163, + 186, + 64, + 238, + 182, + 25, + 76, + 35, + 165, + 222, + 33, + 182, + 251, + 82, + 246, + 127, + 84, + 48, + 93, + 180, + 251, + 43, + 150, + 171, + 69, + 32, + 197, + 140, + 161, + 27, + 189, + 79, + 183, + 242, + 81, + 39, + 96, + 74, + 225, + 156, + 233, + 247, + 184, + 37, + 14, + 72, + 236, + 116, + 117, + 193, + 234, + 156, + 0, + 214, + 71, + 83, + 51, + 175, + 207, + 157, + 97, + 136, + 48, + 47, + 240, + 238, + 156, + 252, + 205, + 6, + 31, + 167, + 171, + 223, + 182, + 173, + 110, + 240, + 255, + 27, + 213, + 80, + 20, + 249, + 181, + 57, + 62, + 168, + 156, + 98, + 155, + 132, + 180, + 179, + 189, + 98, + 78, + 0, + 161, + 139, + 202, + 90, + 235, + 180, + 178, + 181, + 159, + 37, + 255, + 217, + 84, + 158, + 218, + 57, + 182, + 149, + 26, + 118, + 140, + 2, + 221, + 88, + 18, + 100, + 5, + 57, + 134, + 96, + 9, + 164, + 144, + 61, + 99, + 36, + 63, + 195, + 181, + 157, + 5, + 214, + 110, + 169, + 248, + 67, + 62, + 221, + 160, + 44, + 220, + 83, + 14, + 72, + 238, + 188, + 183, + 1, + 3, + 245, + 176, + 5, + 153, + 175, + 237, + 44, + 47, + 125, + 225, + 223, + 122, + 241, + 242, + 199, + 183, + 203, + 220, + 121, + 81, + 31, + 171, + 134, + 72, + 237, + 215, + 15, + 130, + 30, + 4, + 75, + 26, + 199, + 162, + 17, + 181, + 185, + 253, + 229, + 79, + 177, + 128, + 137, + 194, + 134, + 192, + 32, + 131, + 174, + 137, + 62, + 200, + 136, + 86, + 174, + 89, + 26, + 5, + 175, + 160, + 68, + 148, + 91, + 32, + 176, + 184, + 79, + 47, + 64, + 29, + 62, + 233, + 9, + 28, + 94, + 137, + 86, + 78, + 93, + 190, + 81, + 41, + 42, + 75, + 251, + 119, + 6, + 146, + 228, + 144, + 169, + 128, + 62, + 58, + 121, + 248, + 40, + 180, + 44, + 68, + 88, + 244, + 80, + 26, + 200, + 244, + 68, + 136, + 161, + 22, + 221, + 182, + 14, + 200, + 95, + 106, + 160, + 28, + 210, + 36, + 68, + 210, + 87, + 232, + 142, + 32, + 77, + 199, + 181, + 209, + 76, + 9, + 67, + 10, + 182, + 72, + 187, + 211, + 29, + 169, + 108, + 215, + 65, + 109, + 17, + 2, + 233, + 48, + 175, + 179, + 191, + 224, + 77, + 207, + 222, + 192, + 76, + 91, + 95, + 135, + 236, + 246, + 50, + 110, + 149, + 122, + 41, + 94, + 145, + 2, + 69, + 82, + 61, + 84, + 210, + 139, + 189, + 62, + 181, + 249, + 12, + 226, + 249, + 194, + 105, + 50, + 99, + 46, + 158, + 199, + 25, + 124, + 75, + 194, + 61, + 232, + 90, + 136, + 121, + 141, + 123, + 29, + 243, + 242, + 38, + 54, + 194, + 147, + 142, + 98, + 1, + 37, + 190, + 232, + 63, + 142, + 57, + 104, + 50, + 195, + 155, + 28, + 158, + 188, + 230, + 21, + 40, + 114, + 254, + 53, + 110, + 205, + 233, + 70, + 13, + 218, + 145, + 12, + 229, + 255, + 186, + 106, + 212, + 1, + 118, + 250, + 7, + 57, + 75, + 122, + 38, + 53, + 169, + 206, + 134, + 33, + 228, + 130, + 75, + 155, + 65, + 83, + 232, + 70, + 192, + 4, + 21, + 49, + 204, + 251, + 67, + 186, + 87, + 29, + 186, + 105, + 206, + 208, + 124, + 170, + 72, + 121, + 63, + 188, + 213, + 191, + 246, + 33, + 165, + 191, + 101, + 63, + 44, + 11, + 252, + 248, + 10, + 164, + 16, + 97, + 236, + 108, + 247, + 118, + 113, + 137, + 11, + 149, + 133, + 1, + 147, + 163, + 238, + 210, + 144, + 196, + 63, + 221, + 156, + 75, + 83, + 105, + 100, + 198, + 234, + 32, + 88, + 187, + 92, + 197, + 227, + 6, + 131, + 40, + 141, + 137, + 213, + 36, + 220, + 235, + 45, + 94, + 141, + 4, + 58, + 149, + 69, + 77, + 102, + 72, + 250, + 231, + 182, + 34, + 57, + 23, + 232, + 9, + 7, + 21, + 184, + 179, + 112, + 118, + 42, + 38, + 168, + 113, + 164, + 138, + 120, + 204, + 245, + 93, + 215, + 94, + 90, + 71, + 36, + 48, + 248, + 226, + 187, + 70, + 99, + 126, + 37, + 206, + 143, + 210, + 81, + 75, + 210, + 64, + 84, + 226, + 195, + 121, + 100, + 185, + 242, + 211, + 31, + 5, + 13, + 45, + 18, + 11, + 142, + 74, + 1, + 73, + 240, + 216, + 27, + 121, + 1, + 0, + 23, + 43, + 75, + 195, + 64, + 240, + 241, + 240, + 119, + 17, + 232, + 142, + 219, + 188, + 172, + 115, + 143, + 29, + 121, + 145, + 10, + 128, + 89, + 98, + 8, + 242, + 98, + 0, + 35, + 207, + 232, + 194, + 69, + 186, + 128, + 43, + 117, + 152, + 68, + 15, + 223, + 243, + 141, + 98, + 147, + 89, + 113, + 1, + 126, + 172, + 230, + 140, + 121, + 46, + 244, + 198, + 72, + 118, + 232, + 113, + 184, + 93, + 103, + 96, + 95, + 159, + 204, + 208, + 27, + 132, + 120, + 205, + 146, + 13, + 40, + 79, + 232, + 156, + 73, + 234, + 33, + 197, + 92, + 44, + 118, + 124, + 72, + 231, + 66, + 51, + 99, + 246, + 148, + 194, + 177, + 240, + 85, + 165, + 113, + 240, + 176, + 159, + 108, + 16, + 63, + 117, + 219, + 185, + 107, + 63, + 198, + 166, + 180, + 69, + 94, + 153, + 179, + 194, + 111, + 145, + 196, + 108, + 21, + 9, + 249, + 142, + 226, + 180, + 75, + 46, + 166, + 55, + 148, + 233, + 89, + 190, + 90, + 204, + 153, + 109, + 200, + 168, + 41, + 199, + 145, + 143, + 141, + 218, + 21, + 145, + 176, + 4, + 64, + 48, + 40, + 7, + 92, + 58, + 69, + 82, + 79, + 85, + 166, + 238, + 93, + 51, + 237, + 63, + 228, + 91, + 217, + 140, + 58, + 182, + 179, + 54, + 50, + 139, + 221, + 26, + 170, + 151, + 211, + 212, + 100, + 196, + 136, + 56, + 8, + 39, + 193, + 98, + 61, + 67, + 29, + 19, + 193, + 252, + 250, + 27, + 76, + 252, + 197, + 49, + 64, + 23, + 113, + 32, + 44, + 64, + 167, + 174, + 194, + 204, + 95, + 135, + 183, + 151, + 211, + 201, + 15, + 146, + 164, + 197, + 76, + 42, + 206, + 177, + 38, + 221, + 109, + 169, + 138, + 169, + 147, + 169, + 42, + 175, + 118, + 30, + 148, + 73, + 243, + 172, + 29, + 216, + 47, + 48, + 185, + 169, + 205, + 49, + 112, + 255, + 9, + 167, + 32, + 139, + 182, + 201, + 63, + 228, + 151, + 109, + 104, + 198, + 243, + 248, + 211, + 142, + 61, + 210, + 160, + 246, + 30, + 108, + 28, + 49, + 116, + 8, + 29, + 2, + 160, + 212, + 146, + 123, + 147, + 71, + 69, + 173, + 237, + 97, + 30, + 209, + 163, + 130, + 82, + 239, + 18, + 178, + 178, + 22, + 145, + 54, + 50, + 175, + 134, + 174, + 203, + 51, + 55, + 46, + 99, + 87, + 52, + 50, + 66, + 87, + 45, + 254, + 52, + 168, + 214, + 226, + 174, + 121, + 232, + 230, + 169, + 245, + 38, + 25, + 55, + 3, + 39, + 158, + 54, + 95, + 115, + 43, + 8, + 207, + 104, + 201, + 38, + 44, + 239, + 101, + 169, + 51, + 91, + 57, + 110, + 239, + 238, + 242, + 64, + 168, + 42, + 227, + 249, + 68, + 22, + 137, + 111, + 178, + 39, + 83, + 66, + 101, + 205, + 149, + 131, + 167, + 117, + 200, + 153, + 248, + 181, + 228, + 199, + 117, + 227, + 248, + 37, + 229, + 77, + 82, + 238, + 167, + 149, + 106, + 105, + 133, + 225, + 126, + 83, + 210, + 113, + 5, + 187, + 98, + 249, + 167, + 140, + 140, + 145, + 49, + 199, + 118, + 29, + 129, + 216, + 210, + 44, + 130, + 81, + 99, + 194, + 46, + 218, + 254, + 23, + 148, + 254, + 99, + 160, + 79, + 87, + 92, + 78, + 212, + 89, + 71, + 219, + 18, + 19, + 37, + 226, + 219, + 141, + 240, + 181, + 109, + 1, + 192, + 180, + 108, + 71, + 209, + 73, + 241, + 119, + 223, + 71, + 65, + 30, + 248, + 35, + 21, + 154, + 16, + 121, + 103, + 85, + 86, + 25, + 155, + 232, + 40, + 105, + 241, + 82, + 255, + 121, + 202, + 127, + 112, + 187, + 72, + 75, + 87, + 223, + 59, + 67, + 132, + 232, + 190, + 36, + 27, + 113, + 106, + 39, + 192, + 130, + 0, + 91, + 119, + 72, + 77, + 135, + 159, + 53, + 108, + 200, + 133, + 72, + 74, + 222, + 217, + 177, + 112, + 72, + 60, + 3, + 216, + 236, + 167, + 112, + 102, + 85, + 134, + 217, + 220, + 162, + 237, + 133, + 175, + 228, + 204, + 25, + 154, + 88, + 129, + 160, + 105, + 231, + 101, + 229, + 130, + 170, + 26, + 87, + 237, + 47, + 229, + 11, + 132, + 95, + 165, + 135, + 115, + 23, + 255, + 137, + 233, + 65, + 167, + 0, + 90, + 100, + 74, + 197, + 177, + 116, + 49, + 253, + 98, + 191, + 239, + 253, + 25, + 185, + 239, + 220, + 125, + 38, + 245, + 14, + 8, + 185, + 82, + 183, + 133, + 161, + 120, + 104, + 0, + 71, + 239, + 34, + 225, + 174, + 138, + 109, + 45, + 54, + 113, + 69, + 8, + 129, + 182, + 93, + 158, + 83, + 71, + 36, + 94, + 67, + 74, + 89, + 202, + 156, + 115, + 56, + 251, + 251, + 195, + 77, + 148, + 91, + 118, + 31, + 40, + 187, + 81, + 107, + 190, + 70, + 107, + 10, + 171, + 148, + 108, + 62, + 225, + 148, + 222, + 221, + 1, + 58, + 167, + 42, + 47, + 22, + 132, + 79, + 211, + 104, + 191, + 250, + 147, + 216, + 82, + 19, + 128, + 167, + 7, + 53, + 170, + 7, + 193, + 25, + 113, + 75, + 133, + 119, + 83, + 43, + 161, + 248, + 213, + 34, + 41, + 11, + 138, + 95, + 148, + 234, + 168, + 60, + 158, + 115, + 4, + 134, + 47, + 247, + 72, + 137, + 7, + 137, + 246, + 223, + 35, + 126, + 249, + 61, + 45, + 82, + 200, + 229, + 251, + 98, + 15, + 46, + 77, + 120, + 225, + 9, + 136, + 149, + 46, + 130, + 93, + 122, + 175, + 100, + 172, + 96, + 117, + 194, + 211, + 95, + 154, + 108, + 230, + 115, + 221, + 166, + 20, + 23, + 171, + 92, + 106, + 145, + 154, + 96, + 204, + 183, + 224, + 137, + 85, + 54, + 30, + 254, + 108, + 95, + 106, + 173, + 221, + 218, + 166, + 163, + 16, + 30, + 17, + 95, + 82, + 68, + 72, + 224, + 127, + 224, + 3, + 246, + 244, + 250, + 7, + 0, + 186, + 111, + 233, + 251, + 36, + 165, + 149, + 119, + 166, + 229, + 221, + 175, + 101, + 101, + 254, + 208, + 10, + 16, + 233, + 73, + 202, + 127, + 0, + 126, + 75, + 170, + 2, + 62, + 181, + 132, + 163, + 85, + 173, + 128, + 157, + 119, + 202, + 216, + 46, + 101, + 1, + 40, + 184, + 58, + 47, + 20, + 199, + 92, + 212, + 103, + 150, + 52, + 241, + 234, + 129, + 98, + 134, + 150, + 170, + 46, + 36, + 24, + 21, + 76, + 221, + 44, + 127, + 35, + 129, + 205, + 221, + 3, + 14, + 2, + 147, + 98, + 146, + 174, + 41, + 92, + 191, + 172, + 162, + 96, + 155, + 194, + 109, + 80, + 207, + 69, + 253, + 61, + 49, + 55, + 221, + 115, + 89, + 89, + 45, + 77, + 101, + 197, + 215, + 139, + 130, + 132, + 249, + 207, + 237, + 46, + 198, + 240, + 129, + 66, + 71, + 209, + 222, + 244, + 158, + 119, + 197, + 13, + 58, + 245, + 95, + 46, + 47, + 104, + 55, + 221, + 152, + 22, + 246, + 53, + 70, + 116, + 144, + 239, + 29, + 144, + 109, + 68, + 78, + 164, + 26, + 225, + 57, + 224, + 253, + 131, + 125, + 253, + 193, + 166, + 120, + 103, + 4, + 150, + 183, + 56, + 21, + 229, + 92, + 47, + 39, + 20, + 184, + 221, + 200, + 15, + 182, + 9, + 208, + 191, + 9, + 138, + 31, + 236, + 57, + 197, + 34, + 217, + 189, + 39, + 192, + 239, + 31, + 176, + 138, + 99, + 153, + 109, + 30, + 185, + 53, + 201, + 14, + 211, + 137, + 207, + 122, + 248, + 46, + 62, + 82, + 114, + 192, + 142, + 106, + 209, + 105, + 64, + 147, + 160, + 200, + 38, + 22, + 30, + 92, + 64, + 177, + 164, + 230, + 69, + 4, + 155, + 154, + 239, + 19, + 252, + 91, + 50, + 77, + 205, + 193, + 193, + 168, + 123, + 203, + 159, + 210, + 179, + 12, + 94, + 84, + 29, + 195, + 72, + 240, + 182, + 20, + 116, + 29, + 148, + 30, + 74, + 159, + 232, + 164, + 36, + 130, + 216, + 31, + 14, + 217, + 227, + 206, + 201, + 44, + 163, + 74, + 1, + 8, + 89, + 229, + 164, + 55, + 68, + 140, + 217, + 96, + 216, + 100, + 80, + 9, + 128, + 95, + 104, + 87, + 229, + 149, + 235, + 56, + 38, + 1, + 47, + 255, + 70, + 140, + 39, + 143, + 150, + 241, + 114, + 145, + 0, + 168, + 181, + 64, + 2, + 179, + 238, + 79, + 227, + 27, + 209, + 166, + 51, + 248, + 9, + 22, + 205, + 105, + 112, + 83, + 203, + 85, + 206, + 253, + 230, + 83, + 14, + 185, + 157, + 84, + 176, + 135, + 85, + 121, + 247, + 213, + 247, + 79, + 177, + 244, + 127, + 209, + 144, + 160, + 20, + 83, + 43, + 123, + 129, + 2, + 64, + 86, + 98, + 218, + 254, + 211, + 63, + 203, + 135, + 165, + 83, + 160, + 174, + 110, + 22, + 100, + 132, + 165, + 110, + 207, + 125, + 2, + 228, + 43, + 121, + 61, + 182, + 187, + 47, + 54, + 90, + 105, + 172, + 69, + 255, + 172, + 109, + 0, + 132, + 24, + 163, + 234, + 147, + 61, + 72, + 68, + 110, + 174, + 229, + 3, + 70, + 100, + 66, + 72, + 144, + 84, + 31, + 195, + 17, + 7, + 83, + 59, + 28, + 217, + 161, + 85, + 171, + 113, + 189, + 14, + 107, + 222, + 54, + 94, + 5, + 141, + 106, + 19, + 186, + 186, + 255, + 162, + 74, + 154, + 32, + 163, + 67, + 26, + 141, + 143, + 153, + 195, + 16, + 154, + 216, + 59, + 248, + 79, + 161, + 48, + 206, + 239, + 145, + 246, + 70, + 136, + 65, + 192, + 174, + 248, + 105, + 11, + 141, + 75, + 34, + 112, + 70, + 135, + 157, + 202, + 98, + 133, + 116, + 241, + 83, + 59, + 71, + 14, + 131, + 49, + 114, + 106, + 198, + 181, + 113, + 68, + 86, + 222, + 38, + 155, + 191, + 45, + 195, + 36, + 118, + 208, + 33, + 191, + 84, + 183, + 6, + 75, + 170, + 132, + 111, + 208, + 40, + 75, + 165, + 199, + 160, + 22, + 237, + 8, + 209, + 251, + 209, + 231, + 93, + 255, + 173, + 67, + 97, + 169, + 212, + 9, + 131, + 249, + 18, + 133, + 119, + 24, + 157, + 155, + 29, + 84, + 160, + 16, + 105, + 14, + 98, + 181, + 96, + 118, + 143, + 154, + 171, + 233, + 63, + 31, + 82, + 84, + 7, + 163, + 44, + 12, + 255, + 16, + 251, + 42, + 40, + 51, + 41, + 220, + 163, + 230, + 240, + 44, + 130, + 124, + 86, + 197, + 3, + 125, + 236, + 224, + 26, + 113, + 54, + 59, + 208, + 142, + 209, + 175, + 100, + 174, + 176, + 121, + 178, + 92, + 255, + 174, + 174, + 41, + 215, + 115, + 131, + 191, + 64, + 164, + 156, + 109, + 58, + 109, + 148, + 38, + 77, + 95, + 242, + 255, + 103, + 115, + 82, + 8, + 92, + 25, + 43, + 166, + 57, + 88, + 14, + 150, + 175, + 203, + 153, + 125, + 153, + 86, + 38, + 239, + 32, + 10, + 200, + 208, + 104, + 241, + 181, + 142, + 125, + 62, + 73, + 65, + 38, + 238, + 71, + 173, + 168, + 153, + 228, + 232, + 29, + 83, + 244, + 181, + 126, + 116, + 40, + 161, + 155, + 73, + 206, + 39, + 204, + 57, + 129, + 4, + 95, + 231, + 0, + 218, + 81, + 249, + 118, + 198, + 79, + 78, + 144, + 170, + 93, + 255, + 45, + 150, + 43, + 193, + 60, + 69, + 177, + 0, + 218, + 3, + 149, + 34, + 110, + 241, + 147, + 99, + 148, + 166, + 37, + 7, + 172, + 162, + 5, + 38, + 42, + 174, + 206, + 164, + 83, + 23, + 155, + 92, + 76, + 72, + 6, + 21, + 164, + 98, + 240, + 215, + 195, + 119, + 54, + 139, + 187, + 226, + 197, + 133, + 221, + 117, + 59, + 108, + 171, + 149, + 140, + 161, + 116, + 146, + 78, + 54, + 63, + 86, + 242, + 168, + 94, + 136, + 196, + 112, + 84, + 213, + 237, + 246, + 180, + 186, + 137, + 10, + 190, + 90, + 189, + 19, + 84, + 242, + 60, + 134, + 230, + 34, + 242, + 226, + 90, + 247, + 99, + 236, + 17, + 95, + 131, + 235, + 24, + 5, + 107, + 134, + 237, + 172, + 80, + 52, + 226, + 163, + 245, + 43, + 85, + 55, + 54, + 66, + 39, + 216, + 46, + 71, + 247, + 59, + 169, + 106, + 173, + 221, + 213, + 125, + 148, + 157, + 55, + 148, + 102, + 162, + 248, + 231, + 114, + 15, + 196, + 172, + 121, + 169, + 132, + 163, + 4, + 180, + 107, + 69, + 48, + 170, + 38, + 226, + 64, + 189, + 223, + 105, + 117, + 150, + 82, + 96, + 7, + 70, + 16, + 95, + 108, + 251, + 192, + 16, + 223, + 130, + 58, + 29, + 201, + 94, + 14, + 40, + 149, + 239, + 88, + 91, + 216, + 18, + 56, + 222, + 96, + 59, + 72, + 252, + 155, + 196, + 235, + 233, + 111, + 50, + 98, + 124, + 78, + 21, + 190, + 181, + 4, + 124, + 167, + 129, + 195, + 97, + 178, + 18, + 228, + 179, + 107, + 97, + 5, + 167, + 38, + 154, + 139, + 228, + 223, + 48, + 72, + 98, + 149, + 29, + 210, + 237, + 254, + 211, + 173, + 58, + 205, + 7, + 49, + 212, + 15, + 130, + 77, + 17, + 158, + 39, + 234, + 246, + 197, + 79, + 56, + 54, + 6, + 14, + 39, + 1, + 38, + 228, + 131, + 169, + 241, + 16, + 203, + 79, + 9, + 20, + 198, + 41, + 153, + 175, + 0, + 11, + 31, + 17, + 112, + 197, + 57, + 29, + 35, + 249, + 123, + 50, + 159, + 219, + 105, + 148, + 1, + 42, + 65, + 70, + 216, + 9, + 137, + 61, + 138, + 48, + 222, + 87, + 46, + 103, + 190, + 76, + 58, + 181, + 27, + 195, + 36, + 252, + 240, + 126, + 103, + 128, + 184, + 63, + 217, + 61, + 28, + 209, + 246, + 51, + 19, + 7, + 38, + 23, + 198, + 135, + 115, + 172, + 122, + 41, + 88, + 82, + 42, + 54, + 157, + 87, + 166, + 10, + 121, + 45, + 72, + 165, + 39, + 233, + 48, + 89, + 56, + 164, + 44, + 5, + 87, + 191, + 84, + 180, + 133, + 220, + 69, + 253, + 114, + 221, + 231, + 183, + 66, + 29, + 7, + 129, + 105, + 182, + 68, + 226, + 47, + 161, + 175, + 53, + 199, + 185, + 219, + 16, + 17, + 111, + 50, + 61, + 18, + 193, + 252, + 216, + 103, + 151, + 79, + 226, + 29, + 148, + 241, + 5, + 244, + 110, + 113, + 72, + 7, + 239, + 9, + 23, + 117, + 131, + 102, + 227, + 79, + 179, + 138, + 220, + 73, + 63, + 2, + 117, + 80, + 192, + 215, + 52, + 181, + 212, + 147, + 134, + 146, + 82, + 163, + 100, + 51, + 71, + 130, + 206, + 137, + 139, + 114, + 124, + 54, + 191, + 91, + 146, + 41, + 214, + 148, + 41, + 184, + 84, + 68, + 82, + 207, + 215, + 120, + 189, + 41, + 212, + 205, + 139, + 190, + 171, + 67, + 9, + 5, + 28, + 111, + 242, + 101, + 166, + 246, + 185, + 0, + 105, + 76, + 110, + 43, + 44, + 200, + 19, + 247, + 158, + 61, + 116, + 63, + 92, + 81, + 56, + 54, + 234, + 26, + 43, + 143, + 134, + 95, + 11, + 238, + 16, + 82, + 27, + 193, + 183, + 145, + 2, + 181, + 149, + 130, + 205, + 167, + 161, + 71, + 89, + 131, + 123, + 77, + 205, + 195, + 203, + 80, + 136, + 197, + 214, + 16, + 225, + 92, + 45, + 134, + 158, + 119, + 100, + 25, + 68, + 56, + 77, + 177, + 175, + 36, + 54, + 234, + 172, + 94, + 57, + 125, + 81, + 84, + 233, + 19, + 77, + 101, + 16, + 248, + 160, + 239, + 95, + 120, + 29, + 185, + 172, + 124, + 42, + 191, + 22, + 155, + 169, + 82, + 43, + 40, + 82, + 207, + 82, + 227, + 249, + 248, + 27, + 227, + 219, + 245, + 217, + 60, + 77, + 211, + 226, + 161, + 138, + 193, + 164, + 176, + 17, + 245, + 201, + 192, + 140, + 229, + 112, + 91, + 248, + 165, + 242, + 133, + 239, + 76, + 172, + 219, + 106, + 253, + 52, + 38, + 247, + 166, + 153, + 44, + 7, + 230, + 43, + 246, + 84, + 100, + 4, + 224, + 152, + 41, + 216, + 24, + 182, + 0, + 213, + 15, + 66, + 189, + 54, + 199, + 252, + 26, + 46, + 211, + 34, + 221, + 232, + 182, + 12, + 227, + 145, + 47, + 90, + 149, + 212, + 135, + 223, + 111, + 223, + 31, + 158, + 71, + 197, + 173, + 76, + 60, + 43, + 175, + 17, + 33, + 67, + 80, + 81, + 29, + 159, + 128, + 210, + 14, + 253, + 255, + 190, + 102, + 218, + 107, + 96, + 178, + 199, + 136, + 149, + 150, + 32, + 16, + 173, + 216, + 158, + 1, + 164, + 141, + 189, + 108, + 6, + 100, + 45, + 84, + 122, + 69, + 192, + 19, + 7, + 136, + 233, + 210, + 152, + 115, + 65, + 85, + 79, + 185, + 255, + 240, + 226, + 219, + 219, + 147, + 72, + 7, + 141, + 230, + 174, + 90, + 115, + 94, + 83, + 184, + 59, + 1, + 169, + 174, + 249, + 58, + 164, + 71, + 240, + 108, + 115, + 88, + 8, + 88, + 175, + 148, + 179, + 231, + 179, + 137, + 67, + 31, + 105, + 197, + 225, + 89, + 131, + 61, + 130, + 61, + 125, + 75, + 196, + 56, + 9, + 219, + 14, + 196, + 193, + 27, + 57, + 157, + 174, + 208, + 231, + 93, + 176, + 69, + 115, + 73, + 117, + 199, + 41, + 172, + 145, + 1, + 111, + 229, + 52, + 200, + 236, + 216, + 251, + 201, + 133, + 253, + 241, + 252, + 16, + 10, + 53, + 28, + 26, + 57, + 158, + 100, + 126, + 6, + 71, + 104, + 163, + 240, + 153, + 154, + 232, + 226, + 161, + 56, + 252, + 115, + 160, + 45, + 204, + 219, + 180, + 146, + 134, + 225, + 130, + 86, + 29, + 171, + 198, + 215, + 12, + 19, + 245, + 223, + 208, + 39, + 66, + 220, + 194, + 61, + 4, + 122, + 25, + 55, + 73, + 13, + 96, + 44, + 181, + 197, + 101, + 53, + 62, + 98, + 80, + 173, + 218, + 219, + 249, + 193, + 1, + 21, + 36, + 161, + 203, + 116, + 113, + 99, + 247, + 242, + 229, + 141, + 230, + 209, + 20, + 27, + 114, + 190, + 209, + 138, + 136, + 134, + 251, + 124, + 208, + 144, + 53, + 203, + 222, + 11, + 61, + 226, + 47, + 136, + 69, + 231, + 111, + 118, + 134, + 109, + 171, + 193, + 132, + 50, + 187, + 43, + 250, + 226, + 53, + 216, + 191, + 242, + 58, + 161, + 10, + 155, + 173, + 135, + 246, + 171, + 207, + 69, + 170, + 97, + 63, + 217, + 153, + 80, + 156, + 20, + 62, + 41, + 110, + 58, + 179, + 61, + 11, + 89, + 40, + 48, + 54, + 17, + 108, + 11, + 4, + 190, + 120, + 1, + 136, + 40, + 193, + 104, + 235, + 75, + 129, + 240, + 177, + 208, + 81, + 119, + 210, + 73, + 43, + 18, + 113, + 145, + 74, + 221, + 83, + 54, + 54, + 66, + 70, + 197, + 29, + 188, + 206, + 32, + 132, + 113, + 74, + 22, + 108, + 200, + 194, + 123, + 87, + 99, + 181, + 110, + 17, + 17, + 243, + 54, + 122, + 84, + 9, + 189, + 188, + 125, + 165, + 200, + 178, + 28, + 218, + 241, + 158, + 253, + 213, + 223, + 246, + 37, + 76, + 152, + 110, + 144, + 211, + 184, + 153, + 173, + 239, + 100, + 222, + 97, + 94, + 155, + 28, + 9, + 51, + 28, + 222, + 191, + 157, + 187, + 29, + 100, + 20, + 199, + 237, + 43, + 245, + 61, + 190, + 59, + 129, + 0, + 192, + 210, + 165, + 80, + 123, + 114, + 163, + 123, + 214, + 54, + 105, + 248, + 23, + 7, + 236, + 121, + 231, + 197, + 137, + 157, + 70, + 109, + 57, + 214, + 91, + 177, + 3, + 101, + 167, + 230, + 80, + 152, + 234, + 94, + 18, + 69, + 65, + 252, + 23, + 228, + 117, + 133, + 61, + 254, + 40, + 1, + 199, + 114, + 55, + 100, + 252, + 136, + 32, + 177, + 176, + 49, + 236, + 76, + 152, + 249, + 233, + 89, + 238, + 125, + 90, + 106, + 51, + 44, + 211, + 189, + 254, + 129, + 168, + 65, + 206, + 43, + 86, + 64, + 46, + 44, + 173, + 214, + 223, + 91, + 88, + 72, + 207, + 170, + 200, + 176, + 202, + 35, + 121, + 17, + 63, + 87, + 246, + 72, + 196, + 112, + 153, + 117, + 206, + 74, + 204, + 239, + 209, + 227, + 137, + 8, + 200, + 222, + 34, + 154, + 142, + 143, + 161, + 67, + 117, + 255, + 251, + 197, + 95, + 196, + 48, + 169, + 109, + 138, + 98, + 209, + 164, + 66, + 148, + 222, + 125, + 232, + 11, + 19, + 164, + 189, + 249, + 52, + 16, + 195, + 121, + 242, + 6, + 26, + 9, + 21, + 225, + 254, + 136, + 253, + 139, + 145, + 207, + 30, + 23, + 234, + 111, + 20, + 205, + 215, + 141, + 176, + 239, + 45, + 93, + 7, + 50, + 177, + 255, + 78, + 109, + 0, + 103, + 201, + 6, + 37, + 66, + 233, + 72, + 4, + 188, + 14, + 44, + 90, + 89, + 110, + 115, + 202, + 155, + 219, + 229, + 142, + 98, + 119, + 97, + 145, + 159, + 33, + 21, + 3, + 166, + 9, + 21, + 81, + 130, + 173, + 148, + 199, + 99, + 73, + 210, + 232, + 73, + 190, + 25, + 109, + 38, + 84, + 211, + 239, + 137, + 244, + 61, + 242, + 145, + 246, + 62, + 65, + 38, + 196, + 223, + 222, + 195, + 48, + 193, + 76, + 138, + 228, + 87, + 26, + 53, + 175, + 206, + 178, + 179, + 112, + 14, + 175, + 133, + 133, + 151, + 84, + 66, + 130, + 55, + 239, + 20, + 248, + 114, + 125, + 37, + 219, + 10, + 85, + 98, + 38, + 26, + 136, + 226, + 64, + 209, + 5, + 174, + 132, + 190, + 253, + 22, + 111, + 192, + 11, + 195, + 88, + 36, + 115, + 122, + 83, + 11, + 184, + 106, + 52, + 212, + 22, + 228, + 113, + 140, + 197, + 242, + 15, + 88, + 162, + 72, + 174, + 72, + 183, + 7, + 201, + 128, + 87, + 98, + 97, + 54, + 168, + 243, + 176, + 79, + 201, + 1, + 220, + 105, + 0, + 133, + 92, + 55, + 252, + 204, + 85, + 121, + 50, + 0, + 95, + 58, + 150, + 71, + 105, + 209, + 172, + 183, + 247, + 96, + 180, + 108, + 133, + 141, + 57, + 111, + 152, + 216, + 92, + 213, + 14, + 59, + 149, + 243, + 241, + 6, + 190, + 13, + 148, + 93, + 240, + 29, + 67, + 198, + 157, + 114, + 138, + 150, + 75, + 180, + 9, + 4, + 206, + 5, + 52, + 131, + 69, + 240, + 127, + 133, + 145, + 219, + 249, + 52, + 58, + 66, + 249, + 236, + 173, + 201, + 105, + 73, + 205, + 60, + 27, + 26, + 6, + 201, + 129, + 140, + 33, + 157, + 147, + 182, + 101, + 125, + 13, + 177, + 63, + 189, + 80, + 98, + 173, + 115, + 72, + 30, + 101, + 82, + 170, + 122, + 249, + 110, + 255, + 193, + 148, + 177, + 8, + 105, + 169, + 45, + 168, + 21, + 79, + 32, + 250, + 8, + 100, + 179, + 195, + 102, + 190, + 255, + 196, + 14, + 92, + 155, + 195, + 125, + 75, + 108, + 70, + 121, + 92, + 203, + 248, + 54, + 55, + 191, + 31, + 9, + 247, + 206, + 52, + 58, + 167, + 84, + 233, + 53, + 50, + 91, + 199, + 128, + 119, + 112, + 162, + 57, + 243, + 136, + 46, + 16, + 192, + 245, + 165, + 98, + 254, + 46, + 123, + 243, + 159, + 118, + 25, + 50, + 200, + 63, + 239, + 232, + 104, + 151, + 235, + 243, + 238, + 197, + 0, + 137, + 57, + 4, + 141, + 98, + 92, + 121, + 17, + 116, + 42, + 215, + 232, + 216, + 186, + 13, + 187, + 98, + 86, + 203, + 61, + 22, + 129, + 132, + 194, + 170, + 77, + 4, + 241, + 160, + 79, + 25, + 147, + 59, + 160, + 55, + 201, + 235, + 21, + 76, + 124, + 113, + 45, + 223, + 20, + 193, + 33, + 241, + 138, + 62, + 195, + 55, + 40, + 31, + 154, + 244, + 177, + 141, + 127, + 101, + 196, + 252, + 244, + 21, + 88, + 2, + 192, + 172, + 124, + 147, + 49, + 128, + 81, + 64, + 131, + 125, + 214, + 136, + 56, + 84, + 228, + 47, + 232, + 12, + 97, + 125, + 27, + 162, + 185, + 209, + 242, + 30, + 11, + 132, + 174, + 116, + 27, + 113, + 121, + 228, + 150, + 142, + 204, + 12, + 119, + 0, + 64, + 230, + 253, + 37, + 2, + 233, + 63, + 208, + 250, + 202, + 11, + 1, + 10, + 89, + 122, + 16, + 11, + 79, + 88, + 99, + 92, + 173, + 143, + 204, + 84, + 101, + 217, + 168, + 211, + 9, + 31, + 183, + 93, + 238, + 167, + 104, + 239, + 176, + 245, + 230, + 105, + 241, + 32, + 7, + 58, + 207, + 229, + 68, + 207, + 139, + 115, + 110, + 101, + 216, + 133, + 216, + 12, + 32, + 202, + 119, + 135, + 36, + 104, + 75, + 182, + 141, + 121, + 171, + 70, + 237, + 249, + 236, + 202, + 157, + 38, + 71, + 241, + 253, + 192, + 101, + 248, + 9, + 23, + 115, + 28, + 99, + 86, + 148, + 127, + 37, + 225, + 235, + 71, + 95, + 14, + 67, + 15, + 152, + 32, + 222, + 200, + 11, + 149, + 22, + 108, + 169, + 42, + 55, + 209, + 146, + 204, + 194, + 112, + 62, + 218, + 23, + 71, + 225, + 94, + 174, + 101, + 155, + 0, + 224, + 251, + 226, + 6, + 196, + 202, + 30, + 114, + 70, + 245, + 218, + 67, + 252, + 74, + 205, + 106, + 12, + 239, + 10, + 140, + 140, + 145, + 227, + 122, + 25, + 59, + 178, + 88, + 189, + 171, + 251, + 242, + 151, + 187, + 14, + 168, + 197, + 196, + 131, + 226, + 51, + 138, + 84, + 144, + 188, + 174, + 222, + 44, + 86, + 163, + 12, + 141, + 71, + 182, + 174, + 75, + 21, + 16, + 4, + 160, + 222, + 146, + 36, + 175, + 228, + 37, + 229, + 6, + 234, + 20, + 99, + 118, + 216, + 149, + 22, + 163, + 164, + 35, + 166, + 52, + 31, + 246, + 71, + 128, + 104, + 102, + 175, + 72, + 124, + 5, + 177, + 80, + 55, + 192, + 148, + 243, + 52, + 49, + 163, + 130, + 217, + 118, + 47, + 136, + 24, + 166, + 90, + 3, + 228, + 156, + 163, + 55, + 197, + 233, + 123, + 50, + 166, + 104, + 98, + 168, + 97, + 200, + 176, + 3, + 65, + 192, + 65, + 168, + 211, + 33, + 192, + 86, + 89, + 141, + 12, + 172, + 83, + 212, + 201, + 107, + 177, + 77, + 57, + 77, + 123, + 13, + 195, + 222, + 124, + 161, + 121, + 46, + 132, + 150, + 186, + 251, + 127, + 196, + 249, + 61, + 253, + 115, + 0, + 115, + 233, + 93, + 222, + 31, + 142, + 135, + 220, + 158, + 44, + 89, + 222, + 2, + 133, + 218, + 180, + 71, + 40, + 108, + 101, + 99, + 92, + 216, + 191, + 68, + 241, + 72, + 10, + 124, + 246, + 191, + 47, + 166, + 167, + 233, + 80, + 146, + 234, + 112, + 113, + 251, + 84, + 119, + 30, + 81, + 164, + 116, + 41, + 182, + 214, + 8, + 236, + 188, + 46, + 27, + 41, + 210, + 78, + 99, + 162, + 13, + 221, + 18, + 186, + 120, + 143, + 183, + 90, + 122, + 4, + 164, + 245, + 240, + 22, + 198, + 137, + 53, + 48, + 202, + 250, + 180, + 142, + 201, + 56, + 96, + 166, + 165, + 185, + 230, + 7, + 204, + 226, + 47, + 111, + 217, + 129, + 108, + 207, + 107, + 237, + 71, + 251, + 85, + 234, + 73, + 184, + 156, + 23, + 75, + 41, + 143, + 149, + 231, + 182, + 197, + 243, + 140, + 42, + 3, + 151, + 100, + 67, + 121, + 235, + 24, + 225, + 105, + 156, + 32, + 97, + 141, + 37, + 252, + 208, + 110, + 117, + 217, + 169, + 150, + 225, + 62, + 133, + 158, + 218, + 23, + 178, + 164, + 43, + 149, + 104, + 14, + 25, + 231, + 201, + 207, + 60, + 114, + 54, + 138, + 50, + 89, + 42, + 0, + 129, + 108, + 28, + 239, + 116, + 47, + 137, + 202, + 144, + 5, + 42, + 226, + 46, + 93, + 23, + 181, + 98, + 99, + 80, + 31, + 4, + 214, + 230, + 177, + 250, + 2, + 37, + 255, + 214, + 40, + 142, + 104, + 83, + 226, + 157, + 184, + 2, + 92, + 17, + 19, + 200, + 20, + 110, + 120, + 53, + 221, + 206, + 196, + 85, + 47, + 241, + 209, + 71, + 36, + 218, + 180, + 219, + 72, + 75, + 89, + 210, + 193, + 117, + 75, + 50, + 104, + 36, + 133, + 80, + 22, + 246, + 3, + 85, + 37, + 111, + 53, + 75, + 215, + 80, + 51, + 102, + 192, + 14, + 77, + 85, + 186, + 169, + 84, + 46, + 72, + 176, + 107, + 75, + 137, + 57, + 100, + 61, + 200, + 72, + 76, + 105, + 201, + 120, + 171, + 133, + 13, + 127, + 0, + 136, + 64, + 180, + 185, + 167, + 116, + 129, + 223, + 142, + 16, + 142, + 65, + 48, + 80, + 66, + 111, + 169, + 70, + 99, + 245, + 20, + 85, + 190, + 210, + 165, + 30, + 106, + 36, + 74, + 28, + 82, + 22, + 29, + 116, + 79, + 235, + 133, + 182, + 222, + 94, + 134, + 243, + 39, + 194, + 228, + 143, + 83, + 10, + 27, + 232, + 114, + 11, + 252, + 91, + 90, + 148, + 26, + 83, + 40, + 91, + 29, + 78, + 86, + 249, + 13, + 114, + 51, + 104, + 86, + 148, + 18, + 187, + 149, + 27, + 163, + 251, + 32, + 196, + 124, + 125, + 44, + 114, + 207, + 42, + 82, + 13, + 1, + 134, + 140, + 93, + 154, + 91, + 192, + 83, + 172, + 156, + 175, + 223, + 33, + 79, + 143, + 245, + 183, + 172, + 209, + 131, + 152, + 139, + 198, + 241, + 240, + 0, + 238, + 249, + 218, + 83, + 148, + 228, + 109, + 197, + 81, + 42, + 213, + 99, + 175, + 95, + 249, + 116, + 71, + 105, + 2, + 234, + 104, + 112, + 253, + 137, + 140, + 10, + 86, + 179, + 185, + 5, + 52, + 183, + 127, + 144, + 88, + 97, + 173, + 139, + 222, + 60, + 58, + 251, + 225, + 99, + 70, + 1, + 241, + 92, + 230, + 106, + 249, + 144, + 45, + 239, + 210, + 129, + 124, + 120, + 83, + 183, + 102, + 206, + 114, + 54, + 182, + 68, + 234, + 26, + 248, + 20, + 169, + 142, + 39, + 207, + 109, + 1, + 226, + 76, + 181, + 235, + 148, + 86, + 67, + 183, + 211, + 250, + 25, + 224, + 179, + 114, + 249, + 145, + 60, + 38, + 108, + 212, + 176, + 167, + 147, + 243, + 210, + 176, + 101, + 113, + 89, + 90, + 44, + 237, + 98, + 110, + 106, + 205, + 9, + 188, + 81, + 84, + 1, + 67, + 170, + 207, + 224, + 238, + 2, + 52, + 133, + 125, + 232, + 39, + 95, + 127, + 163, + 102, + 112, + 166, + 227, + 212, + 241, + 65, + 1, + 33, + 245, + 74, + 170, + 205, + 18, + 163, + 41, + 103, + 99, + 173, + 207, + 69, + 252, + 50, + 53, + 117, + 242, + 19, + 86, + 8, + 175, + 203, + 78, + 165, + 51, + 69, + 37, + 7, + 219, + 145, + 4, + 201, + 224, + 10, + 96, + 203, + 164, + 165, + 100, + 11, + 11, + 231, + 181, + 69, + 61, + 129, + 51, + 246, + 61, + 58, + 44, + 255, + 65, + 150, + 123, + 68, + 131, + 130, + 115, + 151, + 96, + 18, + 196, + 213, + 49, + 62, + 75, + 238, + 111, + 101, + 64, + 132, + 233, + 92, + 50, + 204, + 237, + 162, + 184, + 86, + 56, + 69, + 81, + 196, + 232, + 96, + 37, + 13, + 51, + 50, + 117, + 147, + 198, + 36, + 116, + 153, + 150, + 30, + 172, + 116, + 178, + 215, + 48, + 211, + 29, + 211, + 170, + 169, + 119, + 68, + 185, + 63, + 159, + 160, + 66, + 111, + 27, + 218, + 179, + 19, + 176, + 27, + 57, + 177, + 52, + 47, + 64, + 107, + 197, + 113, + 30, + 195, + 224, + 222, + 32, + 11, + 38, + 85, + 139, + 198, + 133, + 160, + 188, + 53, + 189, + 8, + 45, + 241, + 175, + 93, + 65, + 18, + 27, + 192, + 242, + 120, + 124, + 17, + 207, + 200, + 3, + 54, + 216, + 79, + 147, + 20, + 237, + 8, + 29, + 91, + 35, + 40, + 210, + 233, + 216, + 192, + 14, + 56, + 88, + 141, + 55, + 225, + 68, + 136, + 72, + 36, + 82, + 68, + 188, + 111, + 199, + 219, + 194, + 58, + 194, + 137, + 164, + 62, + 114, + 47, + 182, + 128, + 242, + 255, + 187, + 56, + 186, + 116, + 245, + 152, + 174, + 105, + 141, + 91, + 12, + 26, + 34, + 209, + 25, + 66, + 58, + 37, + 22, + 74, + 129, + 33, + 180, + 153, + 162, + 23, + 111, + 218, + 224, + 3, + 28, + 8, + 210, + 209, + 164, + 147, + 20, + 64, + 176, + 56, + 183, + 55, + 236, + 130, + 189, + 241, + 204, + 254, + 76, + 112, + 117, + 172, + 83, + 0, + 132, + 82, + 177, + 150, + 132, + 95, + 16, + 122, + 252, + 100, + 255, + 182, + 29, + 17, + 187, + 101, + 111, + 106, + 234, + 30, + 225, + 68, + 148, + 14, + 49, + 244, + 123, + 58, + 53, + 86, + 229, + 73, + 74, + 58, + 119, + 243, + 162, + 110, + 24, + 175, + 236, + 149, + 193, + 41, + 128, + 222, + 135, + 218, + 126, + 62, + 177, + 141, + 126, + 71, + 30, + 204, + 154, + 39, + 51, + 59, + 77, + 102, + 208, + 108, + 224, + 249, + 113, + 90, + 178, + 208, + 207, + 211, + 178, + 201, + 225, + 254, + 200, + 101, + 164, + 130, + 107, + 219, + 232, + 207, + 252, + 92, + 240, + 109, + 240, + 191, + 14, + 40, + 196, + 155, + 154, + 54, + 178, + 152, + 250, + 240, + 182, + 79, + 163, + 250, + 235, + 238, + 71, + 236, + 242, + 229, + 91, + 162, + 48, + 191, + 122, + 174, + 41, + 104, + 11, + 210, + 126, + 51, + 111, + 245, + 241, + 196, + 110, + 23, + 32, + 33, + 2, + 98, + 180, + 86, + 222, + 93, + 97, + 177, + 129, + 175, + 106, + 159, + 62, + 223, + 230, + 175, + 179, + 1, + 86, + 129, + 227, + 210, + 147, + 160, + 28, + 217, + 213, + 247, + 241, + 70, + 83, + 0, + 112, + 158, + 46, + 61, + 138, + 34, + 174, + 127, + 93, + 123, + 148, + 87, + 26, + 185, + 185, + 234, + 202, + 87, + 176, + 77, + 169, + 196, + 133, + 137, + 231, + 207, + 67, + 104, + 221, + 40, + 67, + 194, + 43, + 159, + 248, + 89, + 172, + 215, + 236, + 127, + 143, + 251, + 36, + 90, + 114, + 2, + 150, + 7, + 131, + 41, + 112, + 14, + 158, + 41, + 100, + 85, + 130, + 217, + 237, + 228, + 229, + 103, + 5, + 8, + 197, + 144, + 150, + 155, + 65, + 122, + 153, + 189, + 6, + 198, + 81, + 54, + 8, + 195, + 160, + 127, + 200, + 175, + 139, + 18, + 231, + 113, + 218, + 204, + 202, + 254, + 190, + 77, + 228, + 31, + 152, + 230, + 139, + 148, + 237, + 78, + 124, + 139, + 227, + 190, + 192, + 10, + 70, + 211, + 87, + 222, + 241, + 100, + 97, + 17, + 237, + 123, + 200, + 80, + 223, + 176, + 44, + 144, + 69, + 181, + 171, + 29, + 14, + 90, + 126, + 63, + 33, + 220, + 135, + 198, + 80, + 209, + 145, + 237, + 228, + 209, + 237, + 24, + 195, + 38, + 244, + 71, + 74, + 11, + 42, + 211, + 216, + 48, + 75, + 10, + 213, + 117, + 14, + 54, + 12, + 199, + 35, + 4, + 121, + 248, + 100, + 126, + 89, + 255, + 1, + 172, + 110, + 72, + 168, + 54, + 240, + 234, + 71, + 225, + 27, + 110, + 58, + 214, + 251, + 218, + 230, + 24, + 96, + 60, + 227, + 26, + 201, + 155, + 252, + 198, + 35, + 0, + 177, + 4, + 113, + 76, + 241, + 206, + 94, + 111, + 83, + 101, + 3, + 13, + 171, + 20, + 249, + 80, + 169, + 180, + 200, + 199, + 234, + 114, + 162, + 245, + 114, + 62, + 173, + 176, + 249, + 201, + 102, + 129, + 68, + 28, + 251, + 121, + 74, + 2, + 67, + 184, + 5, + 25, + 183, + 43, + 95, + 96, + 132, + 137, + 189, + 231, + 207, + 245, + 124, + 211, + 254, + 166, + 48, + 45, + 84, + 49, + 171, + 138, + 234, + 224, + 71, + 183, + 11, + 94, + 32, + 180, + 172, + 44, + 244, + 235, + 27, + 5, + 68, + 198, + 179, + 215, + 117, + 192, + 47, + 197, + 225, + 39, + 176, + 185, + 253, + 59, + 36, + 192, + 105, + 192, + 31, + 73, + 242, + 221, + 125, + 93, + 225, + 252, + 54, + 112, + 55, + 168, + 250, + 31, + 140, + 88, + 161, + 201, + 188, + 24, + 27, + 193, + 187, + 200, + 185, + 145, + 252, + 82, + 42, + 15, + 94, + 119, + 225, + 43, + 4, + 235, + 195, + 31, + 33, + 124, + 173, + 93, + 69, + 101, + 107, + 93, + 224, + 163, + 233, + 33, + 140, + 5, + 241, + 140, + 102, + 220, + 148, + 189, + 15, + 17, + 109, + 206, + 179, + 52, + 45, + 149, + 187, + 174, + 35, + 8, + 134, + 32, + 235, + 191, + 203, + 251, + 107, + 199, + 185, + 242, + 128, + 230, + 101, + 122, + 11, + 119, + 59, + 124, + 190, + 214, + 184, + 62, + 32, + 223, + 72, + 145, + 220, + 94, + 117, + 33, + 46, + 49, + 113, + 169, + 121, + 104, + 8, + 156, + 241, + 64, + 167, + 167, + 145, + 78, + 241, + 96, + 36, + 222, + 223, + 111, + 137, + 75, + 210, + 45, + 252, + 30, + 28, + 248, + 145, + 238, + 94, + 173, + 73, + 51, + 130, + 28, + 225, + 61, + 17, + 48, + 47, + 10, + 6, + 99, + 55, + 182, + 199, + 138, + 158, + 189, + 92, + 10, + 56, + 66, + 152, + 89, + 199, + 45, + 172, + 125, + 162, + 212, + 197, + 206, + 106, + 22, + 4, + 125, + 255, + 157, + 37, + 151, + 192, + 35, + 68, + 157, + 102, + 25, + 250, + 208, + 91, + 86, + 81, + 249, + 219, + 160, + 43, + 64, + 25, + 125, + 171, + 63, + 79, + 37, + 255, + 104, + 32, + 63, + 196, + 248, + 28, + 7, + 100, + 3, + 79, + 60, + 4, + 119, + 135, + 26, + 73, + 220, + 207, + 99, + 249, + 199, + 188, + 127, + 73, + 109, + 82, + 54, + 64, + 59, + 255, + 246, + 67, + 233, + 126, + 185, + 41, + 199, + 59, + 127, + 118, + 95, + 98, + 39, + 61, + 169, + 97, + 111, + 72, + 60, + 65, + 101, + 159, + 250, + 135, + 139, + 116, + 103, + 166, + 55, + 18, + 156, + 113, + 66, + 78, + 140, + 34, + 82, + 84, + 11, + 86, + 98, + 249, + 114, + 223, + 239, + 156, + 164, + 117, + 143, + 29, + 235, + 163, + 198, + 18, + 230, + 131, + 253, + 15, + 112, + 43, + 129, + 222, + 194, + 59, + 89, + 175, + 66, + 47, + 203, + 144, + 80, + 182, + 231, + 53, + 26, + 14, + 198, + 76, + 248, + 51, + 126, + 121, + 102, + 136, + 79, + 41, + 12, + 89, + 59, + 135, + 109, + 155, + 202, + 189, + 31, + 42, + 97, + 197, + 72, + 174, + 30, + 121, + 152, + 245, + 126, + 233, + 199, + 200, + 192, + 126, + 27, + 139, + 2, + 243, + 239, + 83, + 146, + 202, + 0, + 15, + 169, + 195, + 56, + 92, + 65, + 160, + 83, + 172, + 162, + 82, + 199, + 28, + 133, + 240, + 131, + 208, + 12, + 217, + 208, + 55, + 74, + 179, + 14, + 36, + 182, + 189, + 33, + 44, + 251, + 192, + 23, + 87, + 163, + 80, + 95, + 137, + 160, + 102, + 192, + 158, + 75, + 39, + 101, + 238, + 157, + 1, + 246, + 122, + 245, + 152, + 111, + 159, + 204, + 121, + 170, + 36, + 38, + 95, + 141, + 21, + 152, + 31, + 157, + 155, + 253, + 21, + 101, + 155, + 148, + 102, + 179, + 116, + 224, + 252, + 67, + 13, + 39, + 60, + 152, + 177, + 241, + 30, + 144, + 252, + 198, + 188, + 6, + 66, + 193, + 32, + 51, + 151, + 78, + 195, + 35, + 134, + 204, + 26, + 98, + 246, + 107, + 202, + 178, + 76, + 5, + 17, + 153, + 208, + 227, + 175, + 203, + 120, + 214, + 70, + 254, + 77, + 76, + 159, + 125, + 226, + 104, + 83, + 84, + 45, + 101, + 206, + 176, + 35, + 9, + 133, + 87, + 151, + 247, + 133, + 200, + 123, + 162, + 213, + 209, + 244, + 235, + 111, + 200, + 244, + 181, + 92, + 93, + 78, + 35, + 89, + 17, + 182, + 186, + 162, + 164, + 216, + 74, + 46, + 110, + 214, + 204, + 208, + 63, + 131, + 80, + 106, + 14, + 74, + 36, + 106, + 178, + 235, + 163, + 14, + 175, + 57, + 184, + 234, + 167, + 213, + 235, + 71, + 169, + 143, + 100, + 96, + 128, + 162, + 30, + 144, + 222, + 39, + 24, + 225, + 19, + 7, + 53, + 78, + 156, + 27, + 167, + 76, + 182, + 34, + 5, + 66, + 41, + 249, + 29, + 251, + 216, + 9, + 15, + 176, + 54, + 189, + 99, + 143, + 143, + 9, + 65, + 192, + 65, + 227, + 117, + 129, + 81, + 239, + 116, + 240, + 166, + 210, + 55, + 156, + 179, + 18, + 3, + 29, + 133, + 193, + 94, + 255, + 41, + 220, + 108, + 77, + 36, + 28, + 218, + 203, + 81, + 42, + 231, + 65, + 82, + 101, + 61, + 222, + 96, + 131, + 9, + 196, + 40, + 245, + 138, + 71, + 99, + 28, + 48, + 144, + 230, + 140, + 172, + 170, + 30, + 131, + 51, + 174, + 142, + 172, + 58, + 147, + 170, + 205, + 92, + 181, + 194, + 225, + 121, + 9, + 87, + 76, + 179, + 80, + 86, + 27, + 243, + 62, + 153, + 44, + 51, + 173, + 207, + 242, + 78, + 9, + 102, + 237, + 18, + 10, + 234, + 156, + 245, + 96, + 170, + 94, + 187, + 9, + 141, + 80, + 62, + 169, + 2, + 163, + 122, + 173, + 185, + 32, + 44, + 65, + 166, + 67, + 221, + 53, + 15, + 166, + 81, + 135, + 119, + 26, + 254, + 53, + 166, + 138, + 97, + 65, + 197, + 51, + 250, + 245, + 14, + 95, + 82, + 110, + 10, + 58, + 147, + 54, + 161, + 123, + 250, + 64, + 73, + 212, + 81, + 229, + 89, + 36, + 38, + 67, + 132, + 86, + 41, + 102, + 200, + 3, + 136, + 255, + 16, + 136, + 214, + 155, + 19, + 173, + 166, + 143, + 51, + 188, + 54, + 190, + 70, + 98, + 186, + 99, + 130, + 171, + 232, + 137, + 118, + 164, + 112, + 242, + 244, + 83, + 7, + 186, + 5, + 117, + 232, + 62, + 34, + 229, + 10, + 96, + 154, + 147, + 187, + 37, + 54, + 151, + 243, + 211, + 252, + 237, + 203, + 70, + 116, + 21, + 68, + 143, + 112, + 153, + 176, + 154, + 19, + 10, + 193, + 112, + 167, + 176, + 76, + 113, + 192, + 84, + 190, + 6, + 53, + 184, + 22, + 99, + 30, + 196, + 143, + 72, + 203, + 136, + 219, + 50, + 175, + 55, + 30, + 77, + 71, + 18, + 90, + 143, + 53, + 71, + 74, + 155, + 147, + 60, + 15, + 252, + 231, + 131, + 176, + 114, + 228, + 188, + 145, + 195, + 92, + 23, + 143, + 0, + 103, + 197, + 144, + 255, + 11, + 139, + 109, + 6, + 98, + 22, + 54, + 194, + 75, + 16, + 109, + 46, + 90, + 210, + 49, + 130, + 248, + 216, + 44, + 135, + 108, + 153, + 235, + 22, + 25, + 177, + 184, + 193, + 107, + 167, + 254, + 179, + 40, + 172, + 8, + 176, + 161, + 120, + 31, + 39, + 16, + 214, + 225, + 64, + 225, + 246, + 242, + 206, + 135, + 181, + 112, + 107, + 201, + 178, + 198, + 77, + 97, + 95, + 160, + 69, + 33, + 253, + 254, + 238, + 227, + 47, + 118, + 80, + 136, + 205, + 10, + 182, + 39, + 150, + 22, + 200, + 34, + 38, + 245, + 234, + 253, + 29, + 11, + 79, + 89, + 139, + 4, + 198, + 94, + 189, + 76, + 113, + 112, + 217, + 134, + 222, + 213, + 0, + 111, + 169, + 230, + 27, + 30, + 82, + 180, + 187, + 45, + 0, + 116, + 241, + 207, + 179, + 25, + 172, + 173, + 118, + 233, + 20, + 78, + 239, + 58, + 73, + 159, + 218, + 242, + 197, + 204, + 213, + 33, + 167, + 59, + 77, + 39, + 61, + 250, + 207, + 55, + 249, + 59, + 224, + 46, + 119, + 57, + 116, + 229, + 152, + 10, + 141, + 208, + 171, + 217, + 23, + 91, + 218, + 99, + 99, + 36, + 137, + 228, + 99, + 129, + 196, + 104, + 71, + 10, + 138, + 117, + 12, + 98, + 132, + 251, + 215, + 74, + 153, + 213, + 232, + 13, + 167, + 128, + 44, + 19, + 57, + 250, + 113, + 113, + 51, + 234, + 41, + 235, + 220, + 69, + 11, + 131, + 248, + 90, + 251, + 214, + 218, + 128, + 211, + 221, + 253, + 23, + 1, + 4, + 241, + 120, + 6, + 156, + 175, + 108, + 91, + 124, + 154, + 99, + 214, + 50, + 129, + 61, + 202, + 136, + 111, + 14, + 7, + 159, + 34, + 183, + 6, + 186, + 247, + 196, + 152, + 0, + 124, + 230, + 201, + 108, + 143, + 85, + 119, + 170, + 135, + 117, + 164, + 178, + 16, + 33, + 116, + 53, + 143, + 210, + 23, + 0, + 250, + 95, + 232, + 26, + 238, + 164, + 105, + 239, + 7, + 234, + 211, + 16, + 241, + 249, + 52, + 134, + 143, + 138, + 37, + 141, + 73, + 175, + 172, + 188, + 109, + 110, + 169, + 97, + 217, + 153, + 147, + 96, + 88, + 195, + 111, + 58, + 82, + 49, + 234, + 129, + 60, + 212, + 5, + 245, + 71, + 65, + 215, + 48, + 175, + 104, + 79, + 217, + 110, + 178, + 39, + 26, + 71, + 224, + 164, + 36, + 40, + 1, + 54, + 219, + 173, + 80, + 146, + 182, + 115, + 247, + 232, + 97, + 47, + 161, + 16, + 15, + 116, + 103, + 93, + 40, + 99, + 45, + 193, + 84, + 94, + 189, + 243, + 201, + 171, + 119, + 35, + 108, + 234, + 8, + 120, + 166, + 122, + 58, + 82, + 187, + 183, + 33, + 233, + 237, + 184, + 125, + 98, + 35, + 181, + 176, + 222, + 138, + 137, + 91, + 239, + 157, + 47, + 180, + 124, + 164, + 120, + 89, + 243, + 6, + 70, + 147, + 123, + 219, + 75, + 50, + 152, + 242, + 110, + 221, + 47, + 251, + 192, + 201, + 19, + 131, + 245, + 54, + 230, + 95, + 235, + 243, + 71, + 106, + 151, + 156, + 172, + 224, + 82, + 43, + 89, + 49, + 24, + 27, + 172, + 251, + 138, + 169, + 131, + 108, + 139, + 111, + 185, + 22, + 62, + 77, + 133, + 171, + 159, + 244, + 201, + 24, + 50, + 134, + 154, + 78, + 100, + 175, + 197, + 65, + 124, + 111, + 226, + 15, + 194, + 53, + 33, + 230, + 10, + 202, + 133, + 132, + 151, + 50, + 5, + 77, + 62, + 86, + 147, + 137, + 188, + 178, + 161, + 67, + 255, + 10, + 209, + 246, + 62, + 64, + 107, + 137, + 50, + 67, + 17, + 89, + 113, + 39, + 218, + 41, + 211, + 232, + 72, + 200, + 186, + 25, + 152, + 36, + 54, + 213, + 217, + 108, + 163, + 163, + 141, + 86, + 226, + 106, + 43, + 215, + 32, + 127, + 248, + 55, + 61, + 211, + 209, + 96, + 164, + 33, + 56, + 198, + 37, + 89, + 124, + 155, + 136, + 233, + 104, + 210, + 129, + 140, + 134, + 181, + 135, + 206, + 1, + 145, + 50, + 198, + 230, + 120, + 203, + 209, + 193, + 49, + 147, + 106, + 162, + 56, + 88, + 128, + 22, + 39, + 126, + 252, + 116, + 94, + 53, + 16, + 1, + 42, + 56, + 239, + 100, + 164, + 53, + 192, + 19, + 152, + 90, + 246, + 171, + 106, + 44, + 186, + 92, + 95, + 13, + 223, + 101, + 80, + 91, + 195, + 40, + 236, + 49, + 64, + 48, + 211, + 236, + 59, + 199, + 3, + 5, + 89, + 136, + 188, + 42, + 225, + 99, + 179, + 95, + 101, + 236, + 115, + 168, + 176, + 10, + 0, + 192, + 199, + 33, + 40, + 235, + 26, + 9, + 204, + 18, + 161, + 39, + 234, + 173, + 210, + 19, + 96, + 208, + 115, + 48, + 237, + 208, + 114, + 221, + 96, + 98, + 149, + 212, + 127, + 89, + 210, + 28, + 177, + 209, + 67, + 125, + 2, + 157, + 158, + 244, + 162, + 209, + 19, + 221, + 160, + 199, + 27, + 99, + 145, + 190, + 225, + 180, + 149, + 232, + 245, + 32, + 69, + 0, + 130, + 205, + 65, + 225, + 211, + 237, + 142, + 72, + 238, + 122, + 30, + 201, + 7, + 181, + 124, + 69, + 3, + 174, + 250, + 135, + 80, + 51, + 66, + 84, + 113, + 208, + 182, + 195, + 157, + 143, + 74, + 51, + 243, + 72, + 110, + 46, + 90, + 58, + 5, + 122, + 243, + 108, + 109, + 33, + 199, + 127, + 67, + 131, + 233, + 57, + 5, + 165, + 84, + 125, + 68, + 184, + 195, + 145, + 176, + 211, + 215, + 145, + 247, + 244, + 152, + 118, + 17, + 71, + 83, + 36, + 0, + 134, + 117, + 217, + 9, + 65, + 238, + 84, + 13, + 152, + 190, + 246, + 197, + 142, + 180, + 177, + 53, + 252, + 118, + 162, + 1, + 104, + 32, + 76, + 174, + 197, + 178, + 237, + 191, + 59, + 167, + 154, + 105, + 226, + 219, + 232, + 81, + 152, + 93, + 164, + 124, + 175, + 125, + 87, + 98, + 84, + 177, + 154, + 88, + 140, + 179, + 83, + 197, + 70, + 56, + 118, + 130, + 127, + 194, + 180, + 49, + 249, + 39, + 141, + 139, + 122, + 50, + 87, + 102, + 44, + 154, + 146, + 129, + 225, + 245, + 55, + 238, + 97, + 11, + 55, + 26, + 70, + 138, + 179, + 135, + 77, + 44, + 69, + 163, + 245, + 134, + 172, + 28, + 251, + 207, + 213, + 51, + 76, + 171, + 127, + 92, + 152, + 102, + 253, + 114, + 105, + 221, + 34, + 11, + 153, + 118, + 3, + 220, + 243, + 249, + 239, + 44, + 101, + 35, + 71, + 7, + 50, + 113, + 26, + 63, + 130, + 123, + 75, + 85, + 189, + 186, + 91, + 21, + 195, + 169, + 122, + 48, + 35, + 152, + 112, + 61, + 83, + 106, + 211, + 175, + 15, + 114, + 10, + 204, + 188, + 115, + 38, + 131, + 140, + 92, + 144, + 194, + 236, + 239, + 42, + 47, + 181, + 188, + 215, + 62, + 221, + 100, + 23, + 55, + 180, + 160, + 112, + 170, + 19, + 2, + 138, + 209, + 29, + 50, + 133, + 198, + 47, + 245, + 149, + 223, + 27, + 151, + 14, + 186, + 207, + 49, + 179, + 53, + 169, + 34, + 14, + 78, + 119, + 244, + 212, + 134, + 128, + 201, + 42, + 242, + 10, + 110, + 33, + 223, + 112, + 199, + 27, + 95, + 16, + 77, + 8, + 0, + 22, + 207, + 211, + 156, + 152, + 20, + 201, + 237, + 176, + 198, + 62, + 10, + 127, + 5, + 146, + 141, + 91, + 82, + 174, + 203, + 154, + 118, + 0, + 152, + 131, + 29, + 115, + 134, + 220, + 226, + 217, + 156, + 218, + 110, + 210, + 242, + 236, + 241, + 201, + 125, + 5, + 131, + 17, + 111, + 35, + 152, + 208, + 157, + 57, + 100, + 97, + 39, + 88, + 65, + 62, + 53, + 116, + 55, + 151, + 239, + 166, + 197, + 230, + 164, + 206, + 144, + 54, + 201, + 43, + 96, + 218, + 18, + 247, + 189, + 105, + 40, + 244, + 144, + 44, + 189, + 243, + 23, + 35, + 50, + 252, + 29, + 43, + 221, + 194, + 242, + 19, + 3, + 15, + 214, + 139, + 26, + 167, + 122, + 66, + 202, + 190, + 31, + 144, + 52, + 103, + 249, + 24, + 91, + 11, + 195, + 195, + 184, + 58, + 56, + 79, + 40, + 198, + 89, + 21, + 107, + 111, + 100, + 69, + 156, + 141, + 40, + 36, + 55, + 86, + 77, + 188, + 65, + 32, + 154, + 181, + 123, + 209, + 111, + 136, + 23, + 153, + 114, + 195, + 211, + 225, + 24, + 253, + 76, + 253, + 151, + 69, + 76, + 158, + 182, + 249, + 99, + 159, + 78, + 159, + 60, + 220, + 155, + 141, + 232, + 113, + 152, + 91, + 106, + 219, + 48, + 69, + 55, + 112, + 195, + 115, + 234, + 19, + 32, + 64, + 18, + 166, + 104, + 11, + 202, + 116, + 234, + 13, + 64, + 95, + 120, + 141, + 63, + 132, + 163, + 20, + 253, + 56, + 177, + 112, + 100, + 83, + 122, + 133, + 66, + 111, + 117, + 126, + 39, + 63, + 202, + 249, + 83, + 198, + 127, + 49, + 230, + 48, + 46, + 117, + 57, + 15, + 19, + 160, + 218, + 132, + 36, + 66, + 2, + 88, + 30, + 125, + 128, + 42, + 56, + 125, + 51, + 201, + 152, + 159, + 100, + 184, + 92, + 124, + 247, + 30, + 18, + 74, + 99, + 86, + 12, + 208, + 240, + 82, + 19, + 21, + 101, + 98, + 162, + 15, + 29, + 56, + 40, + 121, + 159, + 214, + 170, + 228, + 78, + 110, + 191, + 150, + 69, + 157, + 100, + 51, + 208, + 22, + 105, + 179, + 157, + 1, + 197, + 176, + 39, + 70, + 1, + 75, + 53, + 62, + 172, + 131, + 29, + 22, + 249, + 236, + 77, + 145, + 52, + 2, + 69, + 23, + 228, + 102, + 199, + 88, + 57, + 77, + 47, + 23, + 178, + 159, + 45, + 240, + 79, + 44, + 145, + 181, + 237, + 166, + 21, + 62, + 151, + 144, + 238, + 192, + 173, + 60, + 44, + 217, + 107, + 43, + 70, + 129, + 66, + 156, + 88, + 106, + 4, + 26, + 62, + 47, + 136, + 160, + 238, + 13, + 136, + 138, + 132, + 126, + 15, + 35, + 112, + 185, + 198, + 102, + 49, + 163, + 58, + 120, + 220, + 87, + 72, + 3, + 66, + 113, + 156, + 54, + 123, + 107, + 6, + 205, + 30, + 124, + 139, + 124, + 195, + 205, + 69, + 251, + 38, + 170, + 129, + 37, + 177, + 232, + 28, + 8, + 177, + 129, + 53, + 53, + 235, + 167, + 219, + 35, + 16, + 22, + 183, + 161, + 231, + 185, + 161, + 194, + 218, + 232, + 68, + 129, + 193, + 244, + 97, + 134, + 216, + 218, + 131, + 183, + 40, + 23, + 155, + 115, + 234, + 79, + 12, + 110, + 197, + 246, + 92, + 68, + 16, + 165, + 181, + 32, + 32, + 149, + 21, + 172, + 96, + 43, + 176, + 25, + 85, + 25, + 135, + 251, + 211, + 125, + 200, + 65, + 128, + 209, + 150, + 247, + 54, + 220, + 76, + 213, + 226, + 121, + 159, + 0, + 101, + 20, + 42, + 88, + 242, + 46, + 54, + 219, + 166, + 12, + 118, + 109, + 134, + 122, + 159, + 74, + 80, + 76, + 78, + 33, + 206, + 24, + 101, + 187, + 58, + 62, + 147, + 85, + 192, + 89, + 9, + 110, + 11, + 15, + 56, + 219, + 172, + 167, + 50, + 25, + 122, + 243, + 214, + 69, + 51, + 96, + 17, + 164, + 132, + 22, + 75, + 238, + 11, + 72, + 1, + 49, + 40, + 173, + 168, + 128, + 127, + 193, + 73, + 230, + 94, + 226, + 29, + 151, + 164, + 137, + 4, + 120, + 200, + 166, + 169, + 185, + 85, + 4, + 214, + 18, + 6, + 203, + 120, + 32, + 158, + 253, + 101, + 191, + 145, + 32, + 157, + 111, + 25, + 173, + 149, + 117, + 5, + 129, + 91, + 11, + 109, + 170, + 184, + 136, + 88, + 53, + 98, + 216, + 163, + 235, + 204, + 179, + 251, + 117, + 74, + 33, + 82, + 170, + 168, + 221, + 3, + 122, + 29, + 114, + 97, + 160, + 55, + 83, + 8, + 6, + 186, + 157, + 197, + 17, + 143, + 183, + 84, + 18, + 156, + 236, + 196, + 177, + 138, + 197, + 16, + 3, + 212, + 178, + 90, + 140, + 103, + 56, + 46, + 207, + 38, + 113, + 33, + 143, + 71, + 98, + 11, + 222, + 95, + 206, + 1, + 241, + 208, + 50, + 141, + 96, + 36, + 153, + 33, + 94, + 131, + 29, + 56, + 90, + 46, + 216, + 24, + 167, + 61, + 193, + 226, + 129, + 67, + 29, + 180, + 238, + 119, + 108, + 84, + 143, + 3, + 3, + 223, + 155, + 39, + 186, + 244, + 221, + 121, + 3, + 134, + 229, + 6, + 251, + 29, + 141, + 184, + 242, + 25, + 219, + 9, + 85, + 216, + 149, + 169, + 72, + 254, + 250, + 143, + 230, + 88, + 196, + 225, + 140, + 141, + 184, + 131, + 48, + 126, + 37, + 0, + 93, + 48, + 198, + 245, + 101, + 231, + 199, + 100, + 150, + 210, + 219, + 238, + 167, + 10, + 235, + 44, + 27, + 167, + 175, + 150, + 51, + 52, + 19, + 131, + 99, + 208, + 98, + 240, + 134, + 177, + 231, + 242, + 225, + 73, + 82, + 3, + 114, + 138, + 148, + 171, + 237, + 32, + 9, + 77, + 139, + 160, + 99, + 107, + 176, + 26, + 159, + 56, + 146, + 103, + 51, + 76, + 202, + 88, + 229, + 137, + 56, + 180, + 130, + 154, + 43, + 80, + 14, + 115, + 81, + 14, + 107, + 157, + 200, + 5, + 1, + 113, + 29, + 9, + 134, + 105, + 68, + 2, + 101, + 15, + 243, + 48, + 4, + 78, + 114, + 118, + 240, + 205, + 84, + 46, + 134, + 210, + 185, + 184, + 219, + 155, + 71, + 35, + 107, + 19, + 97, + 179, + 98, + 122, + 170, + 32, + 45, + 172, + 130, + 17, + 97, + 15, + 29, + 43, + 12, + 237, + 211, + 22, + 77, + 51, + 56, + 0, + 92, + 163, + 97, + 112, + 121, + 221, + 6, + 244, + 125, + 113, + 225, + 124, + 46, + 179, + 80, + 88, + 23, + 149, + 92, + 41, + 36, + 174, + 95, + 110, + 116, + 7, + 240, + 199, + 7, + 31, + 100, + 112, + 115, + 197, + 189, + 21, + 92, + 177, + 29, + 50, + 193, + 62, + 248, + 45, + 38, + 127, + 137, + 246, + 240, + 138, + 49, + 53, + 119, + 116, + 121, + 83, + 0, + 216, + 70, + 142, + 76, + 92, + 59, + 58, + 202, + 115, + 61, + 2, + 104, + 50, + 172, + 210, + 182, + 4, + 73, + 16, + 146, + 235, + 197, + 41, + 235, + 232, + 63, + 243, + 23, + 107, + 157, + 14, + 113, + 76, + 138, + 96, + 69, + 51, + 244, + 115, + 83, + 7, + 82, + 169, + 129, + 149, + 161, + 80, + 97, + 46, + 187, + 78, + 246, + 174, + 2, + 206, + 155, + 217, + 190, + 51, + 241, + 158, + 103, + 108, + 254, + 181, + 189, + 157, + 231, + 215, + 34, + 159, + 120, + 64, + 113, + 79, + 41, + 161, + 73, + 200, + 203, + 126, + 163, + 156, + 45, + 78, + 244, + 90, + 203, + 143, + 238, + 206, + 81, + 61, + 214, + 12, + 189, + 199, + 129, + 55, + 80, + 197, + 192, + 30, + 10, + 41, + 32, + 221, + 106, + 143, + 216, + 238, + 77, + 115, + 116, + 175, + 6, + 230, + 119, + 21, + 70, + 111, + 192, + 230, + 9, + 19, + 31, + 89, + 108, + 239, + 5, + 233, + 89, + 128, + 79, + 3, + 111, + 73, + 241, + 45, + 34, + 45, + 123, + 164, + 12, + 88, + 252, + 129, + 200, + 56, + 177, + 187, + 152, + 117, + 237, + 78, + 112, + 179, + 175, + 48, + 140, + 143, + 193, + 41, + 67, + 147, + 240, + 199, + 137, + 136, + 225, + 3, + 19, + 75, + 213, + 101, + 185, + 193, + 231, + 142, + 96, + 147, + 247, + 94, + 215, + 197, + 163, + 139, + 45, + 36, + 49, + 102, + 209, + 187, + 191, + 160, + 247, + 176, + 212, + 202, + 116, + 29, + 162, + 106, + 173, + 92, + 36, + 215, + 51, + 147, + 5, + 122, + 185, + 132, + 44, + 176, + 122, + 68, + 128, + 45, + 40, + 86, + 32, + 83, + 136, + 169, + 75, + 158, + 80, + 240, + 20, + 17, + 236, + 125, + 139, + 126, + 169, + 197, + 166, + 112, + 156, + 231, + 151, + 250, + 192, + 32, + 239, + 122, + 62, + 107, + 215, + 212, + 142, + 107, + 193, + 47, + 62, + 136, + 161, + 202, + 135, + 16, + 124, + 214, + 53, + 54, + 110, + 72, + 67, + 107, + 124, + 133, + 31, + 252, + 14, + 83, + 137, + 79, + 230, + 245, + 4, + 17, + 90, + 43, + 151, + 5, + 95, + 108, + 34, + 83, + 216, + 64, + 79, + 187, + 201, + 175, + 186, + 162, + 25, + 255, + 179, + 250, + 144, + 202, + 182, + 139, + 244, + 144, + 61, + 214, + 169, + 54, + 55, + 76, + 156, + 58, + 50, + 113, + 52, + 55, + 168, + 161, + 141, + 116, + 206, + 136, + 64, + 125, + 115, + 122, + 82, + 55, + 184, + 160, + 57, + 95, + 151, + 175, + 222, + 48, + 101, + 255, + 39, + 98, + 200, + 113, + 115, + 178, + 86, + 38, + 2, + 12, + 5, + 15, + 238, + 164, + 78, + 234, + 83, + 95, + 199, + 0, + 106, + 51, + 248, + 222, + 91, + 122, + 173, + 252, + 190, + 239, + 254, + 77, + 133, + 109, + 239, + 112, + 235, + 69, + 47, + 73, + 125, + 22, + 52, + 226, + 116, + 110, + 225, + 28, + 59, + 68, + 30, + 88, + 161, + 147, + 233, + 43, + 120, + 152, + 70, + 3, + 50, + 101, + 134, + 99, + 153, + 210, + 194, + 103, + 82, + 252, + 29, + 227, + 94, + 27, + 167, + 141, + 160, + 152, + 191, + 118, + 185, + 250, + 170, + 5, + 199, + 223, + 118, + 192, + 194, + 132, + 76, + 184, + 250, + 247, + 187, + 152, + 189, + 194, + 54, + 45, + 131, + 239, + 14, + 254, + 6, + 16, + 212, + 92, + 196, + 202, + 53, + 187, + 159, + 38, + 180, + 1, + 242, + 47, + 144, + 171, + 229, + 82, + 202, + 182, + 146, + 249, + 146, + 8, + 184, + 84, + 86, + 250, + 19, + 229, + 97, + 200, + 144, + 3, + 18, + 113, + 0, + 208, + 59, + 84, + 120, + 16, + 100, + 217, + 155, + 98, + 88, + 109, + 142, + 26, + 96, + 145, + 60, + 97, + 43, + 21, + 51, + 143, + 79, + 131, + 219, + 136, + 89, + 94, + 11, + 14, + 16, + 255, + 2, + 140, + 124, + 232, + 180, + 12, + 128, + 37, + 133, + 251, + 60, + 52, + 123, + 105, + 164, + 23, + 168, + 9, + 171, + 213, + 123, + 147, + 1, + 165, + 245, + 32, + 24, + 183, + 74, + 12, + 208, + 203, + 21, + 158, + 150, + 3, + 148, + 223, + 95, + 220, + 37, + 213, + 51, + 147, + 111, + 165, + 140, + 244, + 255, + 245, + 79, + 53, + 61, + 105, + 124, + 161, + 59, + 135, + 69, + 6, + 216, + 59, + 111, + 38, + 188, + 116, + 69, + 150, + 56, + 126, + 38, + 231, + 132, + 75, + 251, + 173, + 69, + 16, + 105, + 18, + 68, + 52, + 117, + 180, + 130, + 172, + 228, + 69, + 36, + 223, + 11, + 138, + 72, + 87, + 216, + 172, + 237, + 227, + 97, + 164, + 195, + 202, + 145, + 233, + 236, + 189, + 74, + 181, + 17, + 227, + 42, + 54, + 128, + 252, + 111, + 224, + 228, + 84, + 165, + 175, + 7, + 9, + 79, + 14, + 202, + 26, + 117, + 108, + 27, + 175, + 77, + 166, + 255, + 209, + 41, + 46, + 195, + 21, + 238, + 3, + 246, + 242, + 229, + 134, + 122, + 207, + 92, + 250, + 23, + 151, + 236, + 53, + 130, + 150, + 183, + 182, + 123, + 109, + 252, + 30, + 11, + 119, + 84, + 200, + 1, + 115, + 27, + 179, + 165, + 22, + 110, + 116, + 177, + 112, + 29, + 158, + 183, + 3, + 126, + 62, + 70, + 233, + 25, + 9, + 180, + 96, + 223, + 39, + 40, + 40, + 215, + 74, + 131, + 255, + 171, + 176, + 214, + 127, + 220, + 92, + 207, + 106, + 6, + 217, + 183, + 129, + 243, + 26, + 161, + 55, + 158, + 214, + 111, + 149, + 136, + 177, + 154, + 37, + 252, + 165, + 220, + 56, + 118, + 211, + 21, + 91, + 145, + 226, + 18, + 169, + 65, + 30, + 67, + 74, + 224, + 93, + 87, + 245, + 57, + 241, + 144, + 186, + 213, + 162, + 191, + 103, + 124, + 142, + 137, + 93, + 29, + 161, + 33, + 93, + 143, + 104, + 240, + 137, + 222, + 74, + 56, + 247, + 202, + 205, + 182, + 142, + 146, + 214, + 195, + 9, + 151, + 92, + 218, + 252, + 87, + 185, + 214, + 139, + 43, + 52, + 244, + 17, + 253, + 71, + 233, + 47, + 72, + 35, + 175, + 227, + 92, + 49, + 241, + 247, + 143, + 238, + 155, + 197, + 239, + 49, + 7, + 32, + 139, + 174, + 68, + 38, + 160, + 252, + 140, + 43, + 81, + 207, + 146, + 175, + 168, + 162, + 90, + 15, + 30, + 226, + 176, + 220, + 68, + 90, + 86, + 174, + 233, + 137, + 244, + 96, + 173, + 237, + 67, + 43, + 135, + 143, + 130, + 34, + 98, + 23, + 223, + 133, + 164, + 241, + 112, + 102, + 247, + 78, + 130, + 114, + 80, + 155, + 222, + 147, + 60, + 93, + 181, + 68, + 222, + 177, + 26, + 244, + 195, + 194, + 54, + 254, + 82, + 248, + 225, + 121, + 183, + 169, + 217, + 99, + 73, + 6, + 158, + 248, + 251, + 70, + 91, + 93, + 215, + 156, + 41, + 47, + 194, + 142, + 176, + 223, + 217, + 135, + 157, + 186, + 166, + 252, + 228, + 219, + 118, + 109, + 218, + 238, + 69, + 248, + 84, + 245, + 119, + 144, + 252, + 234, + 144, + 40, + 30, + 113, + 239, + 221, + 35, + 248, + 177, + 143, + 111, + 89, + 139, + 67, + 92, + 255, + 80, + 144, + 27, + 38, + 109, + 123, + 21, + 101, + 200, + 111, + 222, + 62, + 17, + 248, + 15, + 113, + 202, + 139, + 127, + 37, + 47, + 138, + 25, + 78, + 111, + 184, + 92, + 118, + 144, + 104, + 218, + 23, + 153, + 13, + 246, + 28, + 188, + 205, + 226, + 97, + 227, + 180, + 112, + 90, + 147, + 156, + 57, + 179, + 49, + 242, + 185, + 31, + 86, + 124, + 22, + 72, + 214, + 245, + 175, + 212, + 95, + 153, + 86, + 148, + 134, + 165, + 177, + 145, + 34, + 0, + 188, + 100, + 64, + 194, + 121, + 105, + 158, + 231, + 76, + 46, + 5, + 44, + 80, + 73, + 150, + 111, + 75, + 5, + 181, + 220, + 219, + 114, + 145, + 37, + 154, + 143, + 205, + 210, + 126, + 146, + 58, + 196, + 97, + 125, + 216, + 249, + 78, + 70, + 241, + 31, + 98, + 12, + 118, + 153, + 130, + 21, + 235, + 150, + 166, + 130, + 148, + 84, + 92, + 1, + 67, + 242, + 146, + 41, + 46, + 229, + 7, + 84, + 85, + 107, + 242, + 87, + 175, + 167, + 187, + 64, + 21, + 43, + 5, + 103, + 118, + 120, + 153, + 16, + 150, + 228, + 254, + 85, + 102, + 72, + 116, + 122, + 46, + 171, + 240, + 250, + 90, + 101, + 143, + 67, + 188, + 77, + 197, + 146, + 54, + 113, + 254, + 204, + 247, + 236, + 128, + 209, + 28, + 176, + 246, + 80, + 243, + 73, + 142, + 98, + 0, + 224, + 122, + 163, + 174, + 29, + 132, + 246, + 249, + 131, + 184, + 159, + 111, + 227, + 173, + 253, + 141, + 107, + 174, + 151, + 209, + 57, + 25, + 45, + 211, + 112, + 51, + 38, + 143, + 232, + 64, + 210, + 224, + 253, + 250, + 106, + 138, + 35, + 39, + 110, + 31, + 148, + 138, + 58, + 92, + 41, + 170, + 127, + 39, + 35, + 94, + 88, + 254, + 97, + 59, + 54, + 122, + 249, + 1, + 97, + 147, + 211, + 124, + 176, + 79, + 217, + 91, + 161, + 178, + 171, + 208, + 175, + 50, + 216, + 125, + 51, + 61, + 175, + 172, + 215, + 74, + 253, + 10, + 125, + 57, + 131, + 222, + 203, + 119, + 240, + 227, + 1, + 242, + 110, + 74, + 197, + 58, + 150, + 35, + 218, + 132, + 150, + 141, + 123, + 156, + 171, + 21, + 231, + 22, + 234, + 31, + 247, + 213, + 236, + 17, + 9, + 25, + 7, + 74, + 190, + 63, + 104, + 236, + 49, + 1, + 201, + 165, + 126, + 44, + 180, + 184, + 89, + 180, + 14, + 27, + 114, + 173, + 161, + 69, + 239, + 199, + 128, + 65, + 97, + 72, + 195, + 53, + 197, + 215, + 242, + 120, + 67, + 217, + 164, + 138, + 54, + 165, + 251, + 59, + 191, + 225, + 209, + 14, + 180, + 171, + 37, + 233, + 12, + 224, + 238, + 164, + 103, + 19, + 156, + 60, + 119, + 9, + 5, + 4, + 16, + 53, + 40, + 152, + 94, + 234, + 96, + 62, + 72, + 43, + 22, + 230, + 14, + 238, + 195, + 58, + 71, + 38, + 142, + 255, + 72, + 151, + 162, + 45, + 121, + 112, + 91, + 237, + 255, + 33, + 154, + 72, + 114, + 137, + 111, + 221, + 176, + 8, + 78, + 201, + 1, + 41, + 124, + 95, + 64, + 68, + 55, + 157, + 211, + 157, + 236, + 203, + 233, + 32, + 7, + 197, + 44, + 56, + 28, + 213, + 90, + 248, + 140, + 235, + 190, + 116, + 202, + 1, + 164, + 199, + 231, + 131, + 46, + 115, + 164, + 91, + 235, + 161, + 73, + 68, + 212, + 27, + 43, + 206, + 127, + 128, + 209, + 25, + 130, + 66, + 32, + 52, + 90, + 59, + 80, + 43, + 60, + 186, + 75, + 42, + 96, + 238, + 123, + 148, + 65, + 186, + 234, + 13, + 170, + 236, + 221, + 79, + 130, + 241, + 217, + 79, + 161, + 85, + 155, + 57, + 102, + 60, + 214, + 66, + 69, + 0, + 236, + 44, + 7, + 237, + 105, + 221, + 58, + 221, + 210, + 91, + 29, + 35, + 132, + 15, + 179, + 110, + 74, + 109, + 119, + 167, + 3, + 116, + 82, + 238, + 133, + 133, + 251, + 181, + 216, + 17, + 194, + 243, + 210, + 59, + 29, + 30, + 162, + 54, + 126, + 120, + 39, + 164, + 65, + 198, + 205, + 147, + 87, + 175, + 45, + 114, + 200, + 164, + 81, + 96, + 136, + 209, + 17, + 35, + 116, + 132, + 193, + 215, + 87, + 23, + 21, + 242, + 29, + 182, + 253, + 185, + 54, + 88, + 97, + 232, + 38, + 65, + 124, + 120, + 206, + 99, + 163, + 230, + 118, + 164, + 126, + 107, + 140, + 141, + 30, + 189, + 123, + 106, + 82, + 169, + 47, + 113, + 37, + 54, + 223, + 106, + 92, + 186, + 145, + 134, + 43, + 177, + 85, + 55, + 80, + 208, + 38, + 0, + 196, + 205, + 212, + 188, + 172, + 110, + 179, + 145, + 3, + 123, + 87, + 125, + 111, + 170, + 236, + 235, + 160, + 51, + 159, + 11, + 159, + 203, + 53, + 16, + 53, + 252, + 65, + 202, + 171, + 246, + 226, + 198, + 223, + 219, + 24, + 146, + 64, + 174, + 42, + 78, + 169, + 155, + 26, + 96, + 118, + 12, + 167, + 248, + 28, + 204, + 45, + 131, + 97, + 163, + 10, + 51, + 249, + 103, + 46, + 140, + 50, + 90, + 251, + 190, + 182, + 65, + 197, + 47, + 203, + 119, + 106, + 193, + 62, + 91, + 111, + 81, + 232, + 206, + 18, + 31, + 145, + 92, + 54, + 98, + 16, + 117, + 231, + 139, + 162, + 19, + 31, + 110, + 248, + 197, + 45, + 63, + 58, + 111, + 234, + 242, + 102, + 243, + 46, + 76, + 5, + 94, + 26, + 24, + 156, + 7, + 255, + 8, + 2, + 136, + 108, + 234, + 253, + 73, + 70, + 166, + 209, + 85, + 8, + 155, + 102, + 22, + 224, + 0, + 4, + 55, + 176, + 185, + 92, + 109, + 176, + 157, + 110, + 16, + 199, + 49, + 205, + 168, + 86, + 65, + 235, + 141, + 35, + 213, + 45, + 106, + 115, + 110, + 134, + 63, + 52, + 222, + 2, + 58, + 210, + 201, + 161, + 134, + 133, + 164, + 222, + 91, + 193, + 3, + 118, + 250, + 237, + 161, + 223, + 219, + 152, + 108, + 158, + 226, + 221, + 18, + 80, + 112, + 114, + 30, + 51, + 253, + 33, + 204, + 143, + 3, + 182, + 167, + 163, + 246, + 121, + 91, + 65, + 61, + 141, + 89, + 12, + 74, + 45, + 134, + 78, + 216, + 183, + 194, + 229, + 103, + 54, + 211, + 227, + 69, + 139, + 192, + 42, + 137, + 71, + 3, + 55, + 97, + 154, + 170, + 190, + 118, + 252, + 186, + 227, + 50, + 54, + 146, + 52, + 25, + 137, + 230, + 18, + 243, + 195, + 216, + 89, + 2, + 79, + 15, + 105, + 191, + 204, + 201, + 44, + 150, + 103, + 85, + 71, + 40, + 189, + 202, + 13, + 214, + 107, + 48, + 102, + 155, + 250, + 58, + 253, + 178, + 123, + 129, + 38, + 232, + 202, + 52, + 68, + 113, + 131, + 167, + 67, + 74, + 21, + 46, + 56, + 101, + 93, + 134, + 26, + 160, + 113, + 241, + 105, + 188, + 232, + 140, + 188, + 174, + 37, + 234, + 221, + 190, + 126, + 147, + 2, + 198, + 215, + 163, + 199, + 238, + 122, + 145, + 121, + 91, + 189, + 115, + 89, + 16, + 4, + 43, + 166, + 119, + 195, + 47, + 8, + 33, + 156, + 46, + 184, + 10, + 210, + 117, + 213, + 130, + 96, + 30, + 88, + 228, + 6, + 84, + 113, + 6, + 228, + 130, + 69, + 91, + 111, + 126, + 102, + 209, + 111, + 207, + 83, + 172, + 138, + 123, + 229, + 207, + 96, + 219, + 230, + 86, + 174, + 61, + 119, + 55, + 0, + 224, + 220, + 84, + 74, + 185, + 10, + 94, + 255, + 55, + 83, + 85, + 239, + 25, + 57, + 188, + 77, + 106, + 24, + 29, + 68, + 131, + 243, + 190, + 223, + 56, + 22, + 59, + 149, + 14, + 110, + 207, + 168, + 94, + 20, + 2, + 209, + 223, + 92, + 72, + 137, + 176, + 58, + 180, + 35, + 178, + 5, + 179, + 11, + 1, + 134, + 245, + 28, + 226, + 130, + 136, + 120, + 177, + 35, + 53, + 113, + 33, + 180, + 148, + 137, + 128, + 177, + 148, + 237, + 112, + 140, + 80, + 24, + 40, + 8, + 47, + 106, + 176, + 225, + 91, + 71, + 197, + 83, + 99, + 122, + 48, + 59, + 106, + 247, + 163, + 123, + 241, + 154, + 238, + 102, + 237, + 64, + 238, + 203, + 18, + 137, + 21, + 110, + 49, + 8, + 84, + 134, + 134, + 210, + 246, + 101, + 125, + 88, + 189, + 97, + 38, + 163, + 83, + 227, + 120, + 111, + 65, + 64, + 150, + 139, + 143, + 95, + 103, + 248, + 21, + 218, + 141, + 39, + 112, + 48, + 27, + 8, + 249, + 33, + 99, + 28, + 140, + 96, + 137, + 75, + 29, + 196, + 168, + 139, + 253, + 235, + 74, + 20, + 59, + 151, + 165, + 1, + 183, + 162, + 249, + 38, + 129, + 119, + 189, + 183, + 148, + 89, + 248, + 251, + 120, + 27, + 15, + 69, + 140, + 105, + 86, + 11, + 197, + 183, + 103, + 135, + 41, + 57, + 49, + 62, + 243, + 33, + 132, + 192, + 95, + 204, + 18, + 193, + 121, + 9, + 107, + 208, + 196, + 224, + 199, + 37, + 204, + 126, + 225, + 189, + 191, + 165, + 115, + 53, + 250, + 29, + 133, + 4, + 107, + 190, + 99, + 13, + 20, + 151, + 54, + 51, + 133, + 139, + 29, + 209, + 63, + 177, + 199, + 21, + 106, + 106, + 16, + 119, + 72, + 186, + 207, + 141, + 227, + 48, + 150, + 86, + 10, + 182, + 16, + 130, + 65, + 199, + 106, + 79, + 245, + 122, + 145, + 5, + 160, + 211, + 25, + 72, + 196, + 12, + 18, + 219, + 58, + 144, + 129, + 129, + 65, + 98, + 80, + 121, + 211, + 217, + 241, + 44, + 171, + 224, + 15, + 51, + 232, + 73, + 196, + 105, + 139, + 6, + 132, + 167, + 180, + 90, + 139, + 112, + 187, + 234, + 118, + 238, + 145, + 152, + 233, + 139, + 78, + 111, + 215, + 188, + 208, + 131, + 44, + 101, + 229, + 149, + 221, + 127, + 102, + 215, + 124, + 183, + 227, + 173, + 31, + 83, + 34, + 143, + 190, + 177, + 114, + 194, + 24, + 53, + 182, + 13, + 196, + 103, + 33, + 95, + 37, + 147, + 55, + 206, + 13, + 71, + 182, + 9, + 250, + 185, + 156, + 235, + 144, + 207, + 212, + 136, + 22, + 216, + 77, + 117, + 165, + 65, + 75, + 216, + 83, + 4, + 108, + 122, + 226, + 121, + 250, + 4, + 164, + 160, + 200, + 249, + 108, + 71, + 187, + 83, + 208, + 153, + 144, + 71, + 81, + 126, + 252, + 227, + 161, + 162, + 7, + 83, + 75, + 87, + 231, + 251, + 29, + 208, + 59, + 175, + 18, + 48, + 186, + 33, + 166, + 32, + 172, + 60, + 57, + 34, + 197, + 127, + 100, + 255, + 14, + 116, + 124, + 184, + 9, + 210, + 74, + 240, + 47, + 49, + 179, + 215, + 199, + 38, + 4, + 92, + 212, + 30, + 0, + 181, + 182, + 70, + 218, + 221, + 100, + 97, + 141, + 115, + 167, + 227, + 84, + 114, + 78, + 175, + 198, + 4, + 173, + 142, + 239, + 144, + 146, + 229, + 53, + 67, + 17, + 169, + 221, + 255, + 172, + 190, + 123, + 156, + 212, + 178, + 87, + 62, + 88, + 169, + 208, + 83, + 218, + 132, + 183, + 20, + 114, + 239, + 76, + 43, + 124, + 247, + 222, + 50, + 153, + 206, + 77, + 108, + 90, + 28, + 27, + 193, + 20, + 137, + 70, + 33, + 235, + 11, + 115, + 28, + 0, + 2, + 216, + 113, + 125, + 34, + 118, + 22, + 30, + 157, + 176, + 135, + 90, + 105, + 22, + 114, + 225, + 164, + 183, + 127, + 242, + 9, + 6, + 89, + 92, + 214, + 189, + 227, + 211, + 31, + 26, + 165, + 241, + 103, + 30, + 3, + 20, + 205, + 121, + 187, + 54, + 21, + 50, + 193, + 204, + 43, + 43, + 114, + 248, + 135, + 54, + 188, + 93, + 151, + 124, + 60, + 37, + 15, + 52, + 128, + 79, + 249, + 231, + 94, + 121, + 176, + 128, + 21, + 58, + 201, + 209, + 152, + 182, + 64, + 19, + 89, + 239, + 62, + 234, + 252, + 214, + 12, + 229, + 37, + 160, + 239, + 11, + 112, + 110, + 182, + 43, + 52, + 20, + 249, + 67, + 106, + 229, + 73, + 123, + 72, + 67, + 139, + 82, + 193, + 135, + 225, + 0, + 22, + 252, + 120, + 245, + 5, + 239, + 44, + 52, + 109, + 186, + 134, + 254, + 100, + 220, + 182, + 255, + 114, + 146, + 209, + 71, + 206, + 218, + 13, + 237, + 43, + 20, + 246, + 85, + 110, + 207, + 98, + 136, + 18, + 76, + 159, + 53, + 2, + 162, + 89, + 124, + 140, + 73, + 46, + 186, + 213, + 124, + 244, + 176, + 162, + 51, + 143, + 183, + 62, + 206, + 31, + 75, + 96, + 234, + 48, + 140, + 248, + 80, + 60, + 3, + 55, + 233, + 55, + 158, + 224, + 213, + 6, + 60, + 22, + 14, + 114, + 40, + 38, + 166, + 20, + 101, + 10, + 131, + 25, + 125, + 182, + 26, + 194, + 130, + 53, + 109, + 99, + 234, + 27, + 40, + 19, + 124, + 130, + 116, + 128, + 76, + 20, + 24, + 15, + 55, + 5, + 4, + 227, + 177, + 82, + 126, + 6, + 39, + 201, + 131, + 9, + 62, + 170, + 70, + 110, + 1, + 31, + 202, + 228, + 139, + 173, + 90, + 72, + 16, + 144, + 70, + 59, + 108, + 175, + 31, + 86, + 143, + 228, + 64, + 239, + 225, + 108, + 114, + 68, + 118, + 51, + 240, + 248, + 13, + 93, + 209, + 78, + 127, + 94, + 220, + 216, + 173, + 78, + 2, + 101, + 127, + 8, + 221, + 61, + 90, + 21, + 24, + 142, + 61, + 162, + 30, + 126, + 175, + 205, + 21, + 63, + 212, + 53, + 54, + 63, + 21, + 142, + 75, + 1, + 178, + 25, + 39, + 111, + 52, + 171, + 169, + 250, + 243, + 94, + 158, + 71, + 73, + 253, + 186, + 115, + 56, + 25, + 237, + 83, + 233, + 250, + 56, + 230, + 2, + 180, + 24, + 53, + 141, + 23, + 129, + 2, + 143, + 68, + 13, + 148, + 49, + 222, + 166, + 140, + 85, + 165, + 4, + 237, + 160, + 238, + 166, + 74, + 62, + 84, + 164, + 174, + 41, + 67, + 201, + 97, + 243, + 51, + 103, + 64, + 211, + 230, + 9, + 60, + 154, + 114, + 212, + 164, + 104, + 150, + 49, + 132, + 49, + 73, + 251, + 60, + 122, + 243, + 207, + 250, + 146, + 87, + 63, + 102, + 250, + 187, + 121, + 48, + 120, + 19, + 130, + 216, + 137, + 7, + 131, + 231, + 230, + 26, + 51, + 110, + 101, + 44, + 134, + 186, + 101, + 221, + 239, + 216, + 50, + 164, + 134, + 96, + 24, + 200, + 195, + 198, + 188, + 226, + 177, + 127, + 115, + 12, + 227, + 169, + 107, + 216, + 18, + 213, + 30, + 87, + 32, + 139, + 27, + 163, + 38, + 55, + 146, + 209, + 11, + 255, + 110, + 30, + 136, + 139, + 165, + 13, + 224, + 58, + 71, + 99, + 104, + 233, + 191, + 53, + 249, + 29, + 144, + 252, + 71, + 75, + 81, + 101, + 152, + 2, + 206, + 66, + 217, + 90, + 201, + 61, + 189, + 113, + 73, + 180, + 73, + 113, + 148, + 216, + 142, + 166, + 51, + 169, + 134, + 47, + 5, + 172, + 70, + 175, + 113, + 248, + 223, + 7, + 192, + 40, + 91, + 239, + 195, + 250, + 189, + 243, + 226, + 119, + 151, + 126, + 249, + 142, + 45, + 231, + 15, + 27, + 97, + 144, + 13, + 201, + 248, + 41, + 100, + 168, + 163, + 246, + 230, + 3, + 130, + 221, + 60, + 99, + 39, + 73, + 255, + 121, + 106, + 6, + 52, + 252, + 105, + 130, + 161, + 187, + 7, + 26, + 59, + 71, + 148, + 104, + 147, + 182, + 68, + 79, + 188, + 201, + 229, + 144, + 124, + 245, + 33, + 9, + 157, + 87, + 100, + 104, + 163, + 144, + 225, + 19, + 0, + 130, + 63, + 224, + 229, + 221, + 133, + 142, + 78, + 181, + 209, + 172, + 58, + 21, + 197, + 170, + 221, + 186, + 123, + 145, + 37, + 216, + 237, + 249, + 3, + 100, + 65, + 226, + 143, + 84, + 28, + 218, + 95, + 151, + 247, + 163, + 241, + 40, + 36, + 144, + 58, + 121, + 207, + 161, + 40, + 78, + 31, + 106, + 203, + 23, + 71, + 123, + 86, + 111, + 69, + 106, + 113, + 54, + 37, + 253, + 94, + 45, + 94, + 11, + 87, + 68, + 221, + 42, + 88, + 31, + 210, + 44, + 107, + 154, + 209, + 209, + 69, + 140, + 55, + 33, + 124, + 91, + 133, + 202, + 245, + 51, + 112, + 112, + 233, + 79, + 116, + 201, + 183, + 19, + 72, + 29, + 230, + 217, + 20, + 13, + 86, + 42, + 243, + 147, + 199, + 200, + 169, + 184, + 53, + 174, + 140, + 224, + 41, + 123, + 148, + 178, + 172, + 55, + 14, + 191, + 234, + 94, + 131, + 133, + 220, + 186, + 134, + 163, + 188, + 116, + 51, + 110, + 160, + 131, + 188, + 217, + 181, + 116, + 125, + 169, + 138, + 161, + 99, + 244, + 232, + 57, + 133, + 123, + 223, + 231, + 105, + 139, + 115, + 24, + 233, + 97, + 57, + 137, + 24, + 254, + 96, + 173, + 170, + 179, + 213, + 6, + 3, + 104, + 31, + 177, + 205, + 82, + 94, + 52, + 48, + 55, + 51, + 85, + 70, + 187, + 184, + 43, + 192, + 243, + 227, + 98, + 229, + 204, + 177, + 3, + 106, + 213, + 129, + 131, + 164, + 183, + 63, + 178, + 178, + 137, + 76, + 114, + 209, + 97, + 201, + 8, + 54, + 95, + 238, + 53, + 200, + 226, + 207, + 46, + 247, + 185, + 197, + 60, + 22, + 198, + 167, + 238, + 152, + 212, + 225, + 104, + 255, + 141, + 195, + 89, + 182, + 81, + 174, + 237, + 165, + 238, + 87, + 124, + 175, + 159, + 44, + 175, + 232, + 238, + 149, + 133, + 94, + 44, + 126, + 50, + 187, + 49, + 43, + 117, + 166, + 185, + 221, + 76, + 206, + 154, + 191, + 153, + 40, + 162, + 180, + 92, + 138, + 231, + 184, + 250, + 18, + 146, + 202, + 188, + 72, + 226, + 197, + 54, + 4, + 199, + 23, + 87, + 155, + 9, + 152, + 0, + 121, + 68, + 33, + 122, + 122, + 248, + 216, + 36, + 160, + 125, + 159, + 74, + 16, + 165, + 243, + 13, + 215, + 0, + 52, + 147, + 8, + 52, + 19, + 86, + 176, + 123, + 164, + 81, + 79, + 160, + 124, + 241, + 114, + 11, + 8, + 77, + 249, + 78, + 10, + 137, + 214, + 254, + 138, + 183, + 35, + 97, + 152, + 21, + 32, + 43, + 171, + 68, + 108, + 84, + 175, + 31, + 68, + 169, + 206, + 105, + 125, + 203, + 250, + 170, + 183, + 103, + 229, + 175, + 236, + 223, + 31, + 190, + 224, + 183, + 3, + 99, + 149, + 13, + 165, + 116, + 28, + 128, + 125, + 129, + 226, + 141, + 216, + 15, + 96, + 144, + 111, + 76, + 199, + 208, + 243, + 190, + 87, + 120, + 148, + 165, + 168, + 228, + 235, + 195, + 245, + 17, + 2, + 224, + 48, + 73, + 67, + 11, + 86, + 86, + 200, + 30, + 162, + 27, + 77, + 249, + 34, + 137, + 82, + 114, + 41, + 167, + 48, + 217, + 172, + 228, + 136, + 38, + 164, + 147, + 177, + 13, + 64, + 41, + 52, + 1, + 139, + 178, + 179, + 77, + 73, + 169, + 213, + 218, + 227, + 55, + 200, + 95, + 165, + 77, + 22, + 20, + 223, + 252, + 172, + 142, + 156, + 28, + 223, + 160, + 229, + 150, + 18, + 235, + 177, + 45, + 135, + 126, + 143, + 243, + 158, + 63, + 200, + 252, + 232, + 231, + 6, + 77, + 3, + 179, + 216, + 217, + 77, + 90, + 103, + 6, + 174, + 188, + 100, + 62, + 198, + 207, + 217, + 49, + 200, + 95, + 132, + 103, + 132, + 160, + 37, + 158, + 141, + 204, + 190, + 234, + 31, + 65, + 128, + 154, + 6, + 124, + 166, + 79, + 97, + 46, + 155, + 23, + 188, + 58, + 87, + 93, + 54, + 229, + 112, + 101, + 197, + 201, + 34, + 44, + 182, + 92, + 121, + 3, + 209, + 190, + 172, + 196, + 224, + 70, + 118, + 3, + 137, + 238, + 237, + 115, + 99, + 29, + 160, + 89, + 112, + 77, + 99, + 88, + 210, + 70, + 252, + 164, + 227, + 112, + 58, + 159, + 33, + 102, + 138, + 29, + 147, + 113, + 172, + 224, + 176, + 245, + 76, + 227, + 193, + 218, + 201, + 58, + 134, + 107, + 144, + 253, + 247, + 1, + 24, + 185, + 117, + 57, + 149, + 166, + 179, + 68, + 140, + 92, + 62, + 63, + 240, + 47, + 194, + 220, + 228, + 225, + 161, + 1, + 24, + 10, + 136, + 144, + 44, + 185, + 131, + 87, + 168, + 49, + 19, + 200, + 151, + 230, + 41, + 59, + 15, + 47, + 133, + 234, + 105, + 61, + 187, + 29, + 104, + 34, + 226, + 109, + 61, + 153, + 69, + 120, + 32, + 226, + 104, + 225, + 16, + 7, + 246, + 62, + 185, + 40, + 65, + 69, + 2, + 247, + 195, + 187, + 222, + 114, + 150, + 77, + 184, + 201, + 18, + 49, + 9, + 255, + 114, + 97, + 11, + 43, + 0, + 91, + 248, + 166, + 123, + 254, + 233, + 7, + 97, + 50, + 158, + 138, + 206, + 215, + 197, + 82, + 45, + 41, + 53, + 237, + 194, + 141, + 127, + 230, + 254, + 163, + 243, + 29, + 170, + 98, + 126, + 98, + 162, + 57, + 43, + 181, + 190, + 218, + 155, + 139, + 165, + 0, + 208, + 76, + 81, + 62, + 234, + 54, + 66, + 113, + 37, + 215, + 115, + 161, + 124, + 236, + 224, + 13, + 134, + 193, + 53, + 55, + 193, + 151, + 122, + 185, + 104, + 115, + 243, + 193, + 188, + 109, + 202, + 27, + 200, + 219, + 113, + 15, + 93, + 62, + 233, + 195, + 110, + 27, + 239, + 167, + 92, + 103, + 215, + 147, + 11, + 103, + 117, + 29, + 177, + 237, + 93, + 239, + 1, + 195, + 167, + 46, + 153, + 105, + 151, + 24, + 143, + 47, + 162, + 45, + 227, + 221, + 20, + 115, + 170, + 201, + 204, + 226, + 80, + 228, + 227, + 13, + 218, + 110, + 126, + 199, + 132, + 129, + 175, + 24, + 80, + 194, + 224, + 155, + 37, + 200, + 57, + 79, + 14, + 193, + 217, + 99, + 186, + 21, + 54, + 116, + 240, + 218, + 138, + 232, + 118, + 50, + 83, + 100, + 195, + 198, + 105, + 154, + 7, + 78, + 252, + 58, + 207, + 14, + 17, + 130, + 193, + 182, + 144, + 69, + 63, + 156, + 147, + 10, + 125, + 233, + 123, + 43, + 238, + 169, + 88, + 64, + 172, + 9, + 184, + 133, + 182, + 60, + 198, + 143, + 171, + 108, + 115, + 74, + 161, + 78, + 45, + 141, + 65, + 58, + 167, + 8, + 147, + 57, + 58, + 199, + 170, + 176, + 126, + 18, + 221, + 106, + 143, + 167, + 242, + 246, + 239, + 203, + 87, + 76, + 155, + 239, + 145, + 195, + 175, + 250, + 241, + 113, + 92, + 227, + 241, + 17, + 164, + 25, + 178, + 204, + 139, + 218, + 119, + 250, + 70, + 170, + 174, + 24, + 134, + 23, + 11, + 164, + 78, + 8, + 118, + 59, + 130, + 208, + 52, + 125, + 142, + 134, + 238, + 216, + 171, + 79, + 202, + 54, + 29, + 9, + 164, + 19, + 235, + 175, + 223, + 152, + 71, + 27, + 181, + 249, + 223, + 219, + 172, + 111, + 21, + 201, + 22, + 113, + 57, + 1, + 111, + 118, + 203, + 36, + 9, + 137, + 38, + 141, + 61, + 64, + 167, + 93, + 59, + 229, + 203, + 82, + 18, + 111, + 203, + 67, + 75, + 128, + 181, + 45, + 114, + 43, + 139, + 14, + 39, + 58, + 153, + 109, + 77, + 200, + 73, + 69, + 188, + 127, + 179, + 142, + 239, + 12, + 23, + 23, + 163, + 178, + 71, + 69, + 16, + 162, + 118, + 76, + 51, + 241, + 244, + 181, + 176, + 157, + 38, + 164, + 106, + 253, + 124, + 9, + 208, + 136, + 69, + 17, + 68, + 132, + 35, + 134, + 148, + 76, + 4, + 82, + 124, + 99, + 162, + 13, + 56, + 77, + 130, + 238, + 156, + 173, + 165, + 170, + 41, + 194, + 149, + 45, + 67, + 132, + 95, + 123, + 60, + 187, + 12, + 242, + 187, + 212, + 188, + 24, + 13, + 168, + 170, + 35, + 105, + 42, + 236, + 93, + 119, + 243, + 66, + 193, + 66, + 245, + 188, + 225, + 12, + 205, + 239, + 252, + 36, + 165, + 1, + 219, + 23, + 73, + 6, + 22, + 37, + 161, + 94, + 42, + 168, + 37, + 214, + 66, + 213, + 95, + 69, + 95, + 55, + 47, + 9, + 202, + 0, + 179, + 153, + 93, + 163, + 4, + 253, + 219, + 7, + 197, + 88, + 229, + 138, + 87, + 127, + 74, + 200, + 229, + 118, + 42, + 137, + 116, + 169, + 81, + 198, + 58, + 92, + 28, + 210, + 241, + 22, + 152, + 184, + 139, + 160, + 73, + 88, + 73, + 64, + 243, + 136, + 230, + 34, + 208, + 198, + 48, + 6, + 63, + 101, + 109, + 7, + 62, + 65, + 98, + 77, + 29, + 149, + 195, + 193, + 151, + 52, + 109, + 11, + 61, + 153, + 16, + 207, + 33, + 213, + 8, + 37, + 124, + 212, + 64, + 154, + 73, + 121, + 208, + 202, + 161, + 20, + 190, + 178, + 188, + 166, + 10, + 199, + 57, + 21, + 81, + 23, + 218, + 42, + 95, + 36, + 194, + 236, + 175, + 227, + 88, + 104, + 46, + 57, + 14, + 214, + 178, + 6, + 231, + 142, + 122, + 46, + 98, + 115, + 101, + 160, + 162, + 97, + 152, + 115, + 67, + 143, + 34, + 173, + 188, + 17, + 75, + 230, + 150, + 215, + 87, + 43, + 236, + 58, + 76, + 233, + 223, + 33, + 239, + 14, + 104, + 60, + 213, + 89, + 87, + 198, + 223, + 131, + 181, + 168, + 87, + 105, + 43, + 154, + 1, + 3, + 38, + 167, + 156, + 90, + 167, + 231, + 16, + 80, + 200, + 187, + 13, + 99, + 216, + 190, + 100, + 227, + 62, + 26, + 165, + 144, + 130, + 159, + 222, + 185, + 173, + 69, + 172, + 21, + 21, + 240, + 207, + 20, + 223, + 177, + 112, + 64, + 210, + 235, + 127, + 143, + 138, + 71, + 205, + 201, + 208, + 64, + 3, + 25, + 91, + 216, + 94, + 65, + 97, + 122, + 240, + 9, + 64, + 93, + 103, + 58, + 67, + 212, + 70, + 8, + 173, + 46, + 200, + 44, + 108, + 186, + 10, + 61, + 29, + 20, + 62, + 94, + 135, + 80, + 160, + 172, + 61, + 14, + 82, + 230, + 165, + 226, + 195, + 13, + 192, + 40, + 70, + 166, + 99, + 68, + 49, + 228, + 20, + 211, + 110, + 252, + 233, + 71, + 51, + 138, + 124, + 15, + 183, + 146, + 202, + 204, + 224, + 9, + 96, + 188, + 182, + 63, + 63, + 244, + 18, + 254, + 39, + 160, + 224, + 50, + 115, + 193, + 114, + 23, + 144, + 193, + 132, + 77, + 242, + 109, + 36, + 124, + 31, + 63, + 226, + 44, + 229, + 187, + 123, + 184, + 68, + 38, + 248, + 128, + 197, + 26, + 143, + 163, + 97, + 1, + 70, + 214, + 4, + 30, + 55, + 208, + 49, + 100, + 231, + 252, + 76, + 240, + 13, + 208, + 47, + 104, + 106, + 249, + 216, + 189, + 94, + 86, + 202, + 152, + 72, + 170, + 102, + 20, + 61, + 183, + 57, + 8, + 70, + 202, + 95, + 152, + 34, + 153, + 78, + 125, + 105, + 63, + 192, + 134, + 220, + 71, + 172, + 89, + 67, + 76, + 79, + 82, + 62, + 222, + 249, + 232, + 147, + 214, + 77, + 34, + 44, + 86, + 168, + 88, + 40, + 22, + 80, + 142, + 153, + 97, + 6, + 153, + 14, + 140, + 224, + 117, + 205, + 109, + 123, + 5, + 57, + 187, + 34, + 45, + 43, + 75, + 203, + 248, + 108, + 23, + 99, + 64, + 114, + 208, + 135, + 66, + 121, + 76, + 94, + 89, + 88, + 39, + 117, + 157, + 184, + 187, + 91, + 113, + 167, + 76, + 11, + 151, + 2, + 161, + 75, + 150, + 232, + 171, + 193, + 197, + 69, + 208, + 13, + 152, + 174, + 241, + 190, + 210, + 218, + 118, + 29, + 74, + 235, + 203, + 86, + 228, + 65, + 138, + 99, + 203, + 136, + 164, + 143, + 105, + 25, + 172, + 9, + 13, + 65, + 198, + 222, + 41, + 129, + 50, + 95, + 196, + 98, + 134, + 237, + 74, + 106, + 224, + 60, + 174, + 80, + 163, + 180, + 157, + 220, + 169, + 75, + 251, + 107, + 64, + 140, + 194, + 44, + 161, + 141, + 225, + 156, + 59, + 188, + 138, + 19, + 56, + 111, + 239, + 122, + 92, + 252, + 245, + 101, + 9, + 8, + 218, + 125, + 242, + 216, + 13, + 154, + 127, + 194, + 23, + 135, + 155, + 173, + 216, + 219, + 204, + 145, + 208, + 230, + 12, + 36, + 50, + 44, + 96, + 48, + 152, + 226, + 92, + 225, + 224, + 0, + 93, + 66, + 73, + 179, + 228, + 175, + 29, + 234, + 124, + 88, + 146, + 232, + 67, + 205, + 98, + 185, + 241, + 255, + 109, + 36, + 176, + 108, + 40, + 93, + 238, + 83, + 181, + 41, + 12, + 142, + 189, + 57, + 29, + 27, + 226, + 35, + 8, + 60, + 213, + 158, + 249, + 128, + 45, + 166, + 99, + 163, + 146, + 219, + 194, + 166, + 25, + 168, + 158, + 115, + 105, + 147, + 229, + 179, + 109, + 246, + 216, + 234, + 125, + 197, + 91, + 57, + 124, + 196, + 167, + 15, + 236, + 142, + 110, + 245, + 236, + 157, + 36, + 127, + 68, + 201, + 100, + 214, + 206, + 54, + 22, + 250, + 227, + 60, + 32, + 128, + 154, + 35, + 96, + 240, + 0, + 114, + 48, + 88, + 185, + 164, + 34, + 80, + 52, + 53, + 114, + 215, + 12, + 232, + 254, + 28, + 62, + 137, + 192, + 103, + 67, + 246, + 93, + 87, + 131, + 162, + 101, + 127, + 63, + 75, + 213, + 194, + 177, + 114, + 21, + 56, + 126, + 9, + 107, + 42, + 151, + 140, + 205, + 183, + 236, + 72, + 95, + 196, + 136, + 194, + 194, + 132, + 236, + 50, + 102, + 137, + 13, + 222, + 137, + 99, + 219, + 90, + 68, + 103, + 69, + 226, + 189, + 104, + 4, + 185, + 87, + 82, + 169, + 156, + 75, + 156, + 169, + 12, + 118, + 175, + 64, + 125, + 64, + 16, + 196, + 177, + 80, + 72, + 88, + 251, + 139, + 99, + 216, + 179, + 56, + 180, + 42, + 220, + 5, + 32, + 199, + 188, + 138, + 10, + 74, + 184, + 91, + 97, + 162, + 72, + 246, + 76, + 69, + 228, + 37, + 31, + 73, + 151, + 194, + 92, + 39, + 164, + 104, + 222, + 119, + 248, + 149, + 3, + 228, + 241, + 161, + 51, + 109, + 86, + 169, + 58, + 44, + 59, + 189, + 250, + 208, + 190, + 0, + 27, + 50, + 181, + 20, + 55, + 244, + 182, + 24, + 126, + 59, + 183, + 119, + 164, + 77, + 148, + 123, + 139, + 215, + 179, + 26, + 113, + 178, + 14, + 232, + 240, + 127, + 115, + 127, + 163, + 83, + 127, + 193, + 152, + 208, + 200, + 130, + 249, + 7, + 133, + 253, + 222, + 192, + 162, + 80, + 196, + 101, + 153, + 60, + 236, + 17, + 72, + 153, + 10, + 136, + 177, + 164, + 197, + 174, + 144, + 9, + 46, + 181, + 95, + 27, + 208, + 59, + 248, + 170, + 149, + 140, + 47, + 226, + 88, + 162, + 155, + 2, + 156, + 213, + 200, + 12, + 66, + 180, + 60, + 167, + 41, + 65, + 53, + 217, + 48, + 162, + 46, + 73, + 81, + 174, + 156, + 22, + 40, + 112, + 64, + 209, + 184, + 180, + 184, + 191, + 120, + 65, + 143, + 225, + 120, + 148, + 88, + 23, + 163, + 111, + 163, + 62, + 69, + 167, + 187, + 117, + 225, + 68, + 15, + 50, + 117, + 189, + 81, + 161, + 238, + 86, + 231, + 8, + 3, + 169, + 84, + 35, + 12, + 220, + 45, + 16, + 235, + 91, + 93, + 245, + 201, + 122, + 98, + 37, + 53, + 201, + 181, + 194, + 0, + 247, + 139, + 33, + 221, + 179, + 176, + 162, + 209, + 59, + 98, + 125, + 48, + 144, + 168, + 110, + 69, + 7, + 228, + 71, + 135, + 97, + 155, + 97, + 213, + 99, + 143, + 203, + 20, + 65, + 204, + 241, + 172, + 245, + 44, + 147, + 51, + 200, + 150, + 205, + 50, + 13, + 79, + 209, + 206, + 196, + 246, + 10, + 100, + 70, + 42, + 96, + 143, + 222, + 170, + 111, + 34, + 138, + 2, + 61, + 28, + 110, + 220, + 127, + 4, + 151, + 112, + 238, + 226, + 91, + 222, + 159, + 84, + 229, + 184, + 75, + 56, + 100, + 254, + 200, + 195, + 32, + 57, + 128, + 34, + 82, + 37, + 82, + 192, + 108, + 203, + 91, + 1, + 30, + 136, + 183, + 86, + 222, + 250, + 126, + 113, + 83, + 199, + 249, + 104, + 122, + 44, + 71, + 168, + 74, + 82, + 197, + 210, + 75, + 19, + 151, + 146, + 246, + 38, + 98, + 54, + 216, + 4, + 62, + 13, + 136, + 175, + 56, + 40, + 250, + 176, + 151, + 229, + 15, + 173, + 66, + 101, + 88, + 162, + 111, + 184, + 145, + 181, + 118, + 136, + 160, + 211, + 77, + 62, + 20, + 97, + 168, + 27, + 101, + 97, + 92, + 34, + 22, + 197, + 222, + 112, + 249, + 60, + 79, + 75, + 36, + 28, + 199, + 24, + 90, + 66, + 4, + 109, + 151, + 120, + 120, + 197, + 118, + 129, + 92, + 14, + 58, + 201, + 82, + 255, + 68, + 70, + 16, + 61, + 2, + 240, + 220, + 145, + 86, + 64, + 116, + 196, + 67, + 45, + 196, + 146, + 233, + 221, + 100, + 202, + 69, + 62, + 142, + 187, + 220, + 220, + 251, + 95, + 215, + 187, + 84, + 221, + 166, + 149, + 228, + 24, + 129, + 163, + 78, + 52, + 160, + 21, + 192, + 19, + 116, + 250, + 173, + 133, + 88, + 251, + 150, + 159, + 139, + 34, + 164, + 233, + 23, + 251, + 198, + 54, + 103, + 232, + 137, + 192, + 18, + 8, + 52, + 108, + 9, + 127, + 147, + 207, + 217, + 42, + 57, + 240, + 23, + 150, + 102, + 117, + 1, + 83, + 67, + 141, + 128, + 187, + 18, + 44, + 166, + 166, + 91, + 23, + 146, + 139, + 15, + 78, + 167, + 166, + 243, + 30, + 24, + 225, + 229, + 63, + 88, + 92, + 107, + 46, + 188, + 180, + 9, + 134, + 21, + 113, + 78, + 234, + 126, + 41, + 2, + 26, + 252, + 53, + 75, + 206, + 123, + 12, + 215, + 163, + 127, + 34, + 102, + 107, + 132, + 143, + 7, + 67, + 169, + 18, + 200, + 251, + 33, + 184, + 100, + 186, + 141, + 26, + 110, + 163, + 234, + 11, + 213, + 46, + 248, + 213, + 227, + 237, + 82, + 114, + 78, + 96, + 15, + 171, + 63, + 33, + 249, + 204, + 244, + 234, + 236, + 36, + 249, + 91, + 225, + 171, + 107, + 48, + 121, + 175, + 170, + 141, + 19, + 33, + 23, + 98, + 31, + 98, + 180, + 225, + 59, + 35, + 212, + 117, + 14, + 88, + 229, + 106, + 143, + 103, + 165, + 194, + 41, + 116, + 171, + 158, + 225, + 253, + 18, + 122, + 241, + 67, + 175, + 126, + 147, + 203, + 60, + 46, + 193, + 183, + 245, + 37, + 152, + 70, + 131, + 250, + 233, + 94, + 125, + 25, + 165, + 136, + 52, + 49, + 247, + 201, + 250, + 2, + 183, + 175, + 95, + 63, + 119, + 62, + 99, + 205, + 245, + 242, + 154, + 31, + 145, + 150, + 177, + 235, + 47, + 115, + 206, + 246, + 84, + 120, + 238, + 103, + 12, + 154, + 243, + 107, + 117, + 110, + 207, + 173, + 246, + 67, + 251, + 63, + 33, + 235, + 123, + 169, + 185, + 61, + 148, + 155, + 232, + 163, + 8, + 136, + 179, + 210, + 131, + 222, + 197, + 214, + 201, + 20, + 80, + 174, + 68, + 175, + 53, + 32, + 249, + 54, + 122, + 27, + 69, + 215, + 137, + 93, + 44, + 250, + 69, + 245, + 96, + 157, + 13, + 121, + 222, + 178, + 155, + 155, + 85, + 173, + 227, + 251, + 44, + 81, + 134, + 191, + 33, + 75, + 1, + 173, + 36, + 167, + 199, + 121, + 145, + 171, + 192, + 163, + 243, + 166, + 116, + 102, + 246, + 144, + 48, + 117, + 81, + 139, + 178, + 30, + 12, + 155, + 121, + 31, + 230, + 59, + 14, + 174, + 99, + 179, + 205, + 33, + 196, + 228, + 156, + 16, + 237, + 252, + 70, + 131, + 55, + 224, + 160, + 117, + 128, + 98, + 102, + 88, + 25, + 233, + 111, + 141, + 253, + 213, + 68, + 9, + 238, + 18, + 82, + 255, + 155, + 230, + 84, + 212, + 118, + 150, + 151, + 36, + 244, + 171, + 147, + 124, + 79, + 173, + 46, + 10, + 29, + 144, + 121, + 38, + 125, + 155, + 54, + 235, + 120, + 181, + 230, + 88, + 254, + 87, + 45, + 123, + 94, + 58, + 125, + 88, + 75, + 80, + 83, + 172, + 252, + 162, + 206, + 214, + 18, + 182, + 121, + 157, + 120, + 152, + 51, + 24, + 185, + 215, + 146, + 115, + 247, + 91, + 31, + 242, + 55, + 9, + 218, + 188, + 42, + 86, + 191, + 31, + 189, + 66, + 250, + 133, + 124, + 191, + 152, + 52, + 194, + 60, + 90, + 178, + 206, + 32, + 211, + 30, + 216, + 32, + 207, + 242, + 43, + 139, + 70, + 247, + 86, + 111, + 58, + 30, + 130, + 189, + 190, + 241, + 214, + 237, + 67, + 19, + 59, + 180, + 239, + 218, + 80, + 28, + 18, + 28, + 178, + 208, + 172, + 210, + 176, + 23, + 138, + 217, + 144, + 104, + 164, + 67, + 203, + 103, + 144, + 22, + 62, + 153, + 195, + 184, + 106, + 137, + 168, + 127, + 35, + 23, + 172, + 69, + 180, + 62, + 220, + 125, + 252, + 28, + 161, + 130, + 93, + 129, + 249, + 191, + 183, + 193, + 39, + 169, + 31, + 13, + 211, + 203, + 17, + 80, + 221, + 15, + 61, + 175, + 0, + 135, + 67, + 183, + 122, + 163, + 52, + 125, + 192, + 235, + 193, + 104, + 156, + 222, + 42, + 156, + 139, + 13, + 15, + 120, + 118, + 216, + 51, + 113, + 145, + 5, + 117, + 124, + 97, + 212, + 254, + 15, + 225, + 10, + 49, + 99, + 185, + 122, + 191, + 70, + 233, + 48, + 117, + 225, + 159, + 148, + 11, + 115, + 196, + 202, + 248, + 247, + 32, + 124, + 101, + 29, + 66, + 249, + 154, + 128, + 213, + 35, + 91, + 200, + 239, + 220, + 123, + 254, + 56, + 121, + 231, + 226, + 22, + 105, + 66, + 41, + 211, + 144, + 217, + 228, + 106, + 212, + 27, + 135, + 205, + 181, + 28, + 44, + 68, + 191, + 235, + 246, + 14, + 75, + 150, + 64, + 251, + 120, + 146, + 190, + 172, + 184, + 102, + 44, + 237, + 148, + 158, + 114, + 66, + 193, + 124, + 34, + 90, + 108, + 220, + 8, + 145, + 49, + 219, + 27, + 250, + 78, + 54, + 219, + 91, + 39, + 202, + 194, + 156, + 125, + 190, + 24, + 196, + 121, + 98, + 231, + 167, + 163, + 73, + 218, + 232, + 247, + 190, + 108, + 110, + 157, + 12, + 179, + 246, + 203, + 135, + 49, + 16, + 144, + 198, + 195, + 104, + 251, + 177, + 181, + 7, + 155, + 140, + 181, + 82, + 176, + 96, + 80, + 232, + 159, + 19, + 206, + 115, + 146, + 117, + 214, + 143, + 90, + 63, + 183, + 192, + 27, + 1, + 3, + 68, + 19, + 72, + 53, + 186, + 188, + 254, + 234, + 51, + 56, + 103, + 35, + 40, + 74, + 101, + 123, + 164, + 103, + 234, + 52, + 247, + 232, + 84, + 164, + 197, + 68, + 12, + 135, + 217, + 47, + 255, + 3, + 255, + 51, + 21, + 22, + 31, + 121, + 122, + 15, + 182, + 235, + 8, + 53, + 226, + 241, + 4, + 148, + 224, + 184, + 192, + 53, + 30, + 112, + 83, + 163, + 43, + 47, + 168, + 153, + 8, + 133, + 120, + 11, + 12, + 76, + 246, + 114, + 5, + 8, + 88, + 204, + 24, + 131, + 231, + 247, + 111, + 15, + 81, + 242, + 124, + 185, + 154, + 104, + 203, + 225, + 35, + 76, + 207, + 191, + 244, + 188, + 132, + 186, + 72, + 86, + 241, + 64, + 207, + 214, + 70, + 135, + 63, + 100, + 63, + 79, + 163, + 88, + 108, + 82, + 96, + 168, + 86, + 75, + 200, + 31, + 67, + 116, + 57, + 136, + 241, + 19, + 193, + 193, + 179, + 154, + 241, + 36, + 149, + 29, + 226, + 104, + 43, + 214, + 28, + 148, + 114, + 243, + 85, + 66, + 204, + 107, + 26, + 183, + 219, + 253, + 109, + 241, + 66, + 98, + 62, + 157, + 115, + 156, + 103, + 191, + 170, + 4, + 211, + 110, + 56, + 231, + 44, + 118, + 118, + 105, + 148, + 132, + 8, + 211, + 112, + 131, + 68, + 117, + 117, + 181, + 8, + 255, + 125, + 226, + 232, + 82, + 84, + 117, + 132, + 44, + 148, + 62, + 15, + 168, + 83, + 38, + 149, + 8, + 209, + 141, + 195, + 251, + 225, + 100, + 150, + 235, + 6, + 223, + 56, + 28, + 151, + 209, + 228, + 137, + 43, + 170, + 95, + 106, + 243, + 104, + 113, + 110, + 245, + 95, + 201, + 178, + 243, + 6, + 21, + 135, + 136, + 42, + 253, + 60, + 232, + 112, + 147, + 33, + 117, + 217, + 155, + 179, + 153, + 28, + 121, + 201, + 196, + 163, + 221, + 210, + 112, + 127, + 190, + 1, + 21, + 52, + 171, + 232, + 194, + 72, + 241, + 50, + 147, + 19, + 238, + 36, + 159, + 51, + 181, + 9, + 147, + 245, + 123, + 236, + 127, + 42, + 113, + 61, + 152, + 145, + 89, + 27, + 175, + 80, + 6, + 193, + 109, + 97, + 49, + 73, + 157, + 106, + 23, + 132, + 157, + 154, + 122, + 21, + 1, + 101, + 155, + 235, + 21, + 163, + 209, + 12, + 110, + 255, + 123, + 5, + 106, + 196, + 120, + 203, + 47, + 74, + 93, + 21, + 208, + 104, + 250, + 4, + 143, + 63, + 21, + 176, + 155, + 13, + 228, + 22, + 133, + 219, + 51, + 110, + 64, + 113, + 21, + 235, + 106, + 232, + 254, + 180, + 40, + 197, + 186, + 116, + 87, + 109, + 121, + 110, + 55, + 27, + 186, + 188, + 232, + 43, + 106, + 14, + 237, + 2, + 40, + 100, + 110, + 183, + 187, + 124, + 14, + 191, + 148, + 112, + 69, + 225, + 107, + 54, + 228, + 31, + 121, + 182, + 143, + 251, + 7, + 108, + 88, + 94, + 211, + 58, + 150, + 75, + 251, + 183, + 92, + 34, + 94, + 25, + 84, + 45, + 93, + 45, + 102, + 10, + 53, + 166, + 137, + 222, + 128, + 185, + 213, + 70, + 82, + 33, + 170, + 72, + 230, + 19, + 243, + 120, + 236, + 18, + 69, + 36, + 220, + 128, + 64, + 141, + 209, + 59, + 169, + 197, + 228, + 62, + 229, + 254, + 72, + 111, + 199, + 217, + 148, + 188, + 217, + 248, + 205, + 110, + 208, + 212, + 106, + 83, + 177, + 134, + 82, + 144, + 207, + 83, + 93, + 80, + 90, + 47, + 170, + 15, + 104, + 25, + 210, + 36, + 131, + 121, + 2, + 138, + 195, + 138, + 195, + 45, + 233, + 97, + 5, + 0, + 62, + 161, + 15, + 178, + 163, + 28, + 95, + 217, + 147, + 79, + 13, + 158, + 59, + 59, + 72, + 232, + 105, + 90, + 7, + 190, + 84, + 7, + 160, + 187, + 71, + 25, + 231, + 184, + 132, + 19, + 167, + 200, + 110, + 31, + 68, + 138, + 196, + 36, + 221, + 236, + 163, + 64, + 66, + 253, + 125, + 152, + 102, + 53, + 231, + 13, + 192, + 3, + 140, + 132, + 65, + 196, + 75, + 254, + 74, + 197, + 158, + 153, + 60, + 73, + 3, + 128, + 142, + 114, + 213, + 6, + 225, + 208, + 94, + 38, + 185, + 192, + 134, + 93, + 199, + 218, + 129, + 30, + 145, + 148, + 224, + 162, + 4, + 218, + 124, + 32, + 77, + 154, + 60, + 88, + 164, + 145, + 38, + 11, + 193, + 42, + 173, + 228, + 49, + 227, + 182, + 67, + 103, + 7, + 66, + 221, + 185, + 80, + 211, + 63, + 178, + 51, + 85, + 129, + 36, + 48, + 223, + 121, + 171, + 181, + 117, + 185, + 128, + 130, + 27, + 78, + 106, + 215, + 159, + 152, + 18, + 43, + 18, + 48, + 173, + 44, + 48, + 39, + 181, + 222, + 218, + 80, + 193, + 28, + 29, + 74, + 243, + 200, + 144, + 175, + 98, + 106, + 172, + 30, + 161, + 24, + 129, + 55, + 158, + 225, + 73, + 232, + 111, + 212, + 180, + 110, + 145, + 243, + 145, + 245, + 187, + 209, + 167, + 15, + 193, + 43, + 14, + 29, + 153, + 182, + 117, + 237, + 104, + 229, + 118, + 190, + 181, + 141, + 22, + 25, + 101, + 128, + 13, + 215, + 38, + 23, + 128, + 39, + 182, + 37, + 255, + 40, + 201, + 79, + 63, + 134, + 234, + 11, + 89, + 143, + 209, + 55, + 153, + 90, + 140, + 174, + 190, + 65, + 55, + 55, + 165, + 123, + 60, + 131, + 146, + 101, + 111, + 112, + 244, + 78, + 190, + 251, + 173, + 255, + 224, + 229, + 38, + 214, + 89, + 125, + 239, + 118, + 66, + 88, + 247, + 107, + 151, + 187, + 0, + 175, + 146, + 152, + 27, + 247, + 47, + 227, + 7, + 215, + 96, + 29, + 51, + 13, + 206, + 147, + 160, + 194, + 65, + 244, + 161, + 105, + 139, + 224, + 183, + 150, + 183, + 231, + 0, + 248, + 249, + 181, + 120, + 122, + 240, + 143, + 243, + 161, + 139, + 43, + 224, + 144, + 217, + 136, + 206, + 29, + 11, + 166, + 242, + 239, + 113, + 246, + 158, + 175, + 79, + 187, + 55, + 25, + 85, + 66, + 193, + 141, + 127, + 163, + 56, + 188, + 14, + 206, + 211, + 139, + 8, + 41, + 131, + 117, + 103, + 64, + 95, + 51, + 245, + 182, + 14, + 249, + 252, + 147, + 82, + 20, + 214, + 51, + 156, + 108, + 225, + 140, + 84, + 94, + 179, + 59, + 31, + 169, + 43, + 113, + 175, + 78, + 102, + 206, + 101, + 172, + 181, + 159, + 77, + 110, + 182, + 227, + 135, + 98, + 95, + 17, + 212, + 245, + 110, + 195, + 9, + 83, + 138, + 226, + 220, + 83, + 197, + 250, + 187, + 158, + 203, + 67, + 23, + 88, + 214, + 107, + 247, + 82, + 120, + 200, + 175, + 81, + 217, + 24, + 188, + 197, + 148, + 129, + 69, + 84, + 61, + 192, + 104, + 214, + 66, + 246, + 68, + 253, + 162, + 228, + 104, + 74, + 99, + 83, + 60, + 177, + 8, + 205, + 37, + 223, + 25, + 245, + 206, + 88, + 100, + 91, + 140, + 212, + 162, + 71, + 239, + 246, + 12, + 222, + 70, + 14, + 51, + 3, + 154, + 158, + 27, + 77, + 121, + 154, + 79, + 52, + 81, + 221, + 161, + 10, + 24, + 70, + 90, + 239, + 200, + 82, + 244, + 145, + 147, + 196, + 74, + 13, + 255, + 195, + 194, + 99, + 199, + 116, + 122, + 111, + 57, + 19, + 220, + 151, + 39, + 181, + 215, + 118, + 103, + 171, + 128, + 144, + 27, + 186, + 214, + 109, + 113, + 23, + 44, + 78, + 175, + 43, + 209, + 78, + 255, + 154, + 121, + 161, + 239, + 205, + 91, + 208, + 181, + 124, + 132, + 221, + 232, + 229, + 170, + 102, + 218, + 8, + 107, + 97, + 202, + 180, + 254, + 73, + 236, + 93, + 149, + 192, + 63, + 91, + 47, + 17, + 22, + 91, + 80, + 6, + 26, + 254, + 205, + 60, + 2, + 163, + 127, + 227, + 137, + 234, + 6, + 5, + 133, + 130, + 185, + 77, + 84, + 89, + 180, + 137, + 31, + 50, + 110, + 69, + 211, + 217, + 253, + 58, + 48, + 141, + 48, + 180, + 138, + 214, + 37, + 121, + 135, + 245, + 125, + 85, + 86, + 46, + 93, + 254, + 47, + 191, + 159, + 199, + 180, + 41, + 58, + 24, + 2, + 75, + 62, + 201, + 57, + 204, + 167, + 196, + 50, + 63, + 232, + 200, + 97, + 211, + 91, + 156, + 155, + 128, + 157, + 152, + 20, + 85, + 104, + 79, + 174, + 42, + 117, + 118, + 42, + 249, + 74, + 197, + 71, + 96, + 5, + 237, + 69, + 222, + 151, + 209, + 22, + 81, + 161, + 224, + 101, + 171, + 163, + 26, + 232, + 215, + 144, + 192, + 222, + 62, + 160, + 213, + 175, + 179, + 234, + 166, + 216, + 28, + 194, + 115, + 26, + 6, + 77, + 159, + 223, + 52, + 179, + 148, + 229, + 239, + 49, + 46, + 209, + 237, + 65, + 246, + 208, + 146, + 237, + 173, + 54, + 184, + 91, + 235, + 96, + 192, + 141, + 73, + 189, + 241, + 23, + 141, + 123, + 29, + 12, + 179, + 244, + 80, + 5, + 27, + 120, + 238, + 94, + 141, + 238, + 37, + 34, + 193, + 81, + 13, + 194, + 126, + 212, + 197, + 168, + 221, + 195, + 97, + 138, + 31, + 65, + 116, + 86, + 184, + 48, + 93, + 230, + 231, + 65, + 70, + 77, + 166, + 54, + 109, + 199, + 198, + 140, + 81, + 71, + 143, + 88, + 186, + 35, + 91, + 230, + 146, + 58, + 34, + 55, + 87, + 181, + 178, + 51, + 84, + 248, + 205, + 127, + 63, + 62, + 64, + 1, + 2, + 2, + 5, + 90, + 187, + 49, + 233, + 143, + 8, + 198, + 70, + 65, + 157, + 194, + 155, + 30, + 87, + 70, + 177, + 50, + 16, + 69, + 113, + 84, + 69, + 217, + 215, + 140, + 58, + 117, + 114, + 126, + 172, + 193, + 99, + 14, + 235, + 197, + 57, + 174, + 213, + 124, + 199, + 181, + 212, + 55, + 114, + 242, + 72, + 147, + 222, + 143, + 67, + 28, + 36, + 38, + 224, + 83, + 181, + 60, + 77, + 19, + 43, + 147, + 13, + 82, + 236, + 75, + 244, + 56, + 29, + 234, + 193, + 172, + 132, + 140, + 87, + 28, + 74, + 17, + 35, + 212, + 175, + 79, + 167, + 205, + 249, + 159, + 100, + 131, + 35, + 190, + 8, + 248, + 140, + 20, + 251, + 48, + 240, + 196, + 203, + 243, + 207, + 167, + 119, + 189, + 233, + 13, + 103, + 163, + 195, + 80, + 232, + 80, + 104, + 221, + 54, + 111, + 139, + 59, + 174, + 72, + 240, + 21, + 0, + 31, + 236, + 247, + 90, + 25, + 183, + 37, + 247, + 221, + 96, + 138, + 199, + 227, + 76, + 151, + 109, + 85, + 44, + 108, + 164, + 62, + 170, + 29, + 148, + 65, + 156, + 164, + 201, + 220, + 202, + 126, + 110, + 43, + 101, + 151, + 13, + 5, + 12, + 61, + 183, + 147, + 51, + 63, + 38, + 225, + 13, + 87, + 155, + 38, + 101, + 183, + 8, + 136, + 41, + 141, + 167, + 244, + 86, + 202, + 166, + 61, + 186, + 89, + 38, + 196, + 232, + 179, + 122, + 216, + 8, + 56, + 107, + 239, + 175, + 171, + 118, + 56, + 77, + 221, + 67, + 80, + 40, + 164, + 204, + 227, + 162, + 140, + 110, + 187, + 42, + 91, + 128, + 37, + 193, + 136, + 55, + 3, + 230, + 18, + 131, + 135, + 35, + 222, + 157, + 233, + 163, + 61, + 181, + 84, + 210, + 100, + 20, + 58, + 114, + 96, + 95, + 225, + 183, + 119, + 189, + 22, + 167, + 63, + 7, + 28, + 204, + 44, + 103, + 35, + 79, + 34, + 39, + 155, + 78, + 219, + 219, + 122, + 32, + 97, + 134, + 13, + 84, + 85, + 31, + 164, + 84, + 147, + 91, + 180, + 3, + 56, + 147, + 39, + 88, + 205, + 76, + 182, + 123, + 184, + 96, + 103, + 226, + 156, + 214, + 220, + 229, + 233, + 114, + 95, + 194, + 180, + 102, + 189, + 101, + 98, + 184, + 203, + 115, + 3, + 150, + 13, + 106, + 181, + 148, + 122, + 98, + 77, + 69, + 113, + 202, + 229, + 72, + 58, + 139, + 240, + 28, + 144, + 68, + 78, + 204, + 239, + 221, + 213, + 190, + 161, + 116, + 11, + 37, + 128, + 57, + 140, + 59, + 166, + 39, + 108, + 231, + 60, + 104, + 159, + 46, + 195, + 249, + 36, + 98, + 42, + 232, + 46, + 177, + 142, + 106, + 45, + 88, + 160, + 217, + 189, + 162, + 246, + 88, + 81, + 229, + 33, + 54, + 135, + 172, + 196, + 32, + 94, + 47, + 186, + 109, + 210, + 147, + 134, + 16, + 57, + 45, + 138, + 44, + 85, + 80, + 90, + 118, + 123, + 217, + 188, + 238, + 223, + 252, + 227, + 136, + 147, + 135, + 239, + 200, + 54, + 5, + 160, + 129, + 102, + 131, + 92, + 213, + 159, + 215, + 70, + 146, + 194, + 3, + 47, + 213, + 201, + 76, + 154, + 31, + 92, + 148, + 63, + 57, + 245, + 87, + 9, + 180, + 209, + 21, + 40, + 219, + 188, + 101, + 116, + 30, + 45, + 74, + 163, + 108, + 177, + 213, + 184, + 172, + 226, + 80, + 33, + 222, + 187, + 221, + 31, + 164, + 182, + 122, + 223, + 91, + 209, + 158, + 251, + 143, + 172, + 140, + 113, + 216, + 179, + 217, + 199, + 4, + 99, + 188, + 213, + 209, + 155, + 18, + 2, + 51, + 214, + 9, + 201, + 37, + 92, + 66, + 9, + 140, + 220, + 104, + 215, + 100, + 14, + 67, + 137, + 74, + 180, + 158, + 74, + 134, + 180, + 58, + 151, + 221, + 137, + 34, + 138, + 145, + 235, + 217, + 67, + 239, + 167, + 0, + 239, + 55, + 217, + 109, + 91, + 238, + 117, + 130, + 77, + 136, + 183, + 196, + 212, + 105, + 239, + 25, + 54, + 92, + 138, + 197, + 228, + 30, + 222, + 88, + 223, + 172, + 211, + 252, + 22, + 13, + 13, + 91, + 176, + 183, + 98, + 122, + 186, + 24, + 223, + 162, + 178, + 200, + 175, + 230, + 123, + 217, + 108, + 7, + 148, + 105, + 74, + 203, + 145, + 50, + 2, + 96, + 137, + 233, + 97, + 208, + 183, + 204, + 125, + 5, + 85, + 229, + 110, + 174, + 93, + 179, + 36, + 248, + 19, + 149, + 83, + 114, + 8, + 232, + 73, + 126, + 224, + 165, + 91, + 64, + 129, + 152, + 229, + 120, + 152, + 141, + 182, + 127, + 158, + 249, + 36, + 85, + 108, + 44, + 110, + 122, + 33, + 243, + 54, + 172, + 229, + 242, + 138, + 158, + 74, + 47, + 100, + 9, + 36, + 148, + 138, + 39, + 70, + 219, + 24, + 134, + 174, + 149, + 51, + 37, + 160, + 126, + 190, + 73, + 236, + 141, + 143, + 101, + 222, + 103, + 49, + 113, + 227, + 66, + 123, + 228, + 176, + 124, + 176, + 161, + 83, + 87, + 204, + 46, + 69, + 137, + 34, + 212, + 203, + 174, + 101, + 205, + 117, + 172, + 103, + 91, + 65, + 11, + 180, + 148, + 77, + 23, + 237, + 18, + 179, + 1, + 79, + 223, + 74, + 72, + 32, + 78, + 145, + 140, + 184, + 60, + 240, + 7, + 161, + 228, + 206, + 235, + 74, + 184, + 67, + 217, + 201, + 29, + 36, + 47, + 121, + 4, + 19, + 123, + 61, + 212, + 75, + 195, + 23, + 158, + 180, + 175, + 93, + 245, + 7, + 61, + 156, + 23, + 62, + 202, + 249, + 235, + 125, + 246, + 123, + 210, + 217, + 189, + 164, + 17, + 222, + 136, + 27, + 132, + 5, + 53, + 5, + 196, + 236, + 234, + 42, + 145, + 63, + 103, + 83, + 123, + 134, + 212, + 6, + 133, + 185, + 129, + 72, + 99, + 217, + 63, + 85, + 1, + 103, + 210, + 231, + 89, + 246, + 30, + 124, + 16, + 216, + 69, + 161, + 62, + 88, + 190, + 19, + 139, + 214, + 229, + 239, + 93, + 200, + 128, + 229, + 196, + 37, + 210, + 178, + 33, + 70, + 255, + 204, + 45, + 24, + 115, + 169, + 48, + 177, + 226, + 163, + 142, + 225, + 253, + 103, + 166, + 33, + 93, + 96, + 86, + 41, + 52, + 152, + 245, + 136, + 59, + 128, + 131, + 98, + 50, + 190, + 215, + 232, + 31, + 240, + 168, + 143, + 198, + 255, + 47, + 217, + 249, + 82, + 188, + 61, + 209, + 95, + 109, + 60, + 153, + 188, + 63, + 181, + 238, + 145, + 78, + 123, + 99, + 230, + 39, + 247, + 45, + 87, + 22, + 21, + 122, + 179, + 172, + 49, + 6, + 149, + 113, + 182, + 177, + 3, + 97, + 196, + 57, + 81, + 96, + 205, + 51, + 130, + 80, + 148, + 64, + 128, + 220, + 240, + 43, + 153, + 59, + 189, + 42, + 177, + 92, + 46, + 168, + 253, + 94, + 90, + 181, + 147, + 0, + 103, + 181, + 202, + 142, + 17, + 242, + 236, + 83, + 12, + 169, + 254, + 36, + 191, + 123, + 20, + 201, + 221, + 87, + 232, + 95, + 223, + 228, + 98, + 181, + 161, + 42, + 31, + 127, + 44, + 110, + 209, + 51, + 77, + 186, + 118, + 173, + 18, + 146, + 120, + 150, + 65, + 71, + 226, + 186, + 247, + 83, + 50, + 170, + 98, + 149, + 183, + 83, + 245, + 185, + 76, + 213, + 46, + 116, + 14, + 244, + 148, + 189, + 64, + 33, + 166, + 66, + 186, + 217, + 192, + 42, + 41, + 96, + 194, + 232, + 86, + 106, + 102, + 26, + 197, + 101, + 68, + 137, + 79, + 205, + 213, + 36, + 8, + 62, + 227, + 253, + 156, + 213, + 157, + 232, + 215, + 17, + 172, + 87, + 250, + 17, + 141, + 138, + 41, + 203, + 96, + 98, + 42, + 0, + 148, + 83, + 51, + 3, + 72, + 136, + 67, + 152, + 2, + 230, + 144, + 155, + 22, + 34, + 139, + 201, + 211, + 243, + 33, + 112, + 174, + 199, + 170, + 244, + 252, + 62, + 248, + 83, + 213, + 167, + 119, + 45, + 44, + 121, + 14, + 137, + 0, + 136, + 108, + 169, + 95, + 254, + 76, + 231, + 208, + 155, + 22, + 64, + 55, + 43, + 1, + 64, + 211, + 26, + 19, + 90, + 23, + 117, + 185, + 118, + 146, + 158, + 32, + 228, + 112, + 69, + 178, + 190, + 31, + 21, + 124, + 55, + 221, + 52, + 169, + 141, + 114, + 135, + 190, + 149, + 144, + 173, + 248, + 11, + 99, + 155, + 164, + 237, + 136, + 153, + 239, + 203, + 99, + 61, + 178, + 75, + 10, + 119, + 23, + 21, + 82, + 229, + 173, + 20, + 100, + 243, + 125, + 57, + 98, + 50, + 86, + 107, + 87, + 231, + 55, + 40, + 162, + 17, + 26, + 25, + 214, + 165, + 225, + 73, + 228, + 127, + 231, + 134, + 233, + 41, + 254, + 53, + 110, + 24, + 5, + 38, + 202, + 188, + 181, + 9, + 138, + 154, + 139, + 243, + 214, + 165, + 205, + 67, + 33, + 89, + 83, + 43, + 13, + 159, + 20, + 226, + 109, + 66, + 192, + 89, + 161, + 210, + 89, + 91, + 102, + 81, + 170, + 187, + 149, + 159, + 164, + 169, + 197, + 24, + 83, + 231, + 114, + 35, + 210, + 88, + 184, + 101, + 110, + 177, + 206, + 54, + 65, + 207, + 222, + 100, + 116, + 21, + 47, + 7, + 115, + 246, + 231, + 104, + 12, + 19, + 160, + 31, + 155, + 195, + 183, + 154, + 181, + 210, + 40, + 67, + 2, + 106, + 187, + 215, + 187, + 99, + 244, + 179, + 36, + 208, + 184, + 77, + 102, + 190, + 5, + 177, + 255, + 128, + 24, + 202, + 107, + 131, + 244, + 113, + 179, + 211, + 210, + 172, + 85, + 43, + 219, + 189, + 60, + 39, + 224, + 25, + 163, + 4, + 20, + 122, + 229, + 97, + 82, + 130, + 131, + 28, + 159, + 136, + 252, + 192, + 45, + 181, + 165, + 68, + 240, + 14, + 198, + 31, + 170, + 93, + 18, + 42, + 15, + 193, + 205, + 113, + 9, + 222, + 134, + 82, + 242, + 91, + 87, + 231, + 165, + 252, + 43, + 222, + 228, + 70, + 173, + 67, + 217, + 100, + 94, + 235, + 109, + 169, + 242, + 70, + 162, + 59, + 138, + 218, + 57, + 139, + 9, + 7, + 29, + 87, + 156, + 70, + 18, + 1, + 172, + 113, + 118, + 106, + 227, + 88, + 102, + 12, + 88, + 28, + 125, + 99, + 35, + 179, + 47, + 84, + 34, + 244, + 136, + 109, + 94, + 240, + 165, + 212, + 194, + 84, + 105, + 47, + 250, + 25, + 122, + 157, + 189, + 203, + 102, + 198, + 143, + 130, + 217, + 83, + 233, + 82, + 151, + 154, + 131, + 87, + 185, + 187, + 200, + 131, + 73, + 136, + 124, + 44, + 212, + 161, + 196, + 91, + 153, + 247, + 75, + 238, + 181, + 179, + 52, + 57, + 200, + 172, + 70, + 214, + 76, + 8, + 123, + 34, + 74, + 181, + 234, + 5, + 156, + 196, + 130, + 4, + 223, + 58, + 145, + 114, + 185, + 140, + 86, + 114, + 155, + 78, + 19, + 97, + 130, + 249, + 197, + 237, + 249, + 19, + 171, + 206, + 106, + 204, + 61, + 132, + 11, + 249, + 254, + 241, + 54, + 175, + 80, + 130, + 34, + 214, + 28, + 225, + 125, + 97, + 26, + 33, + 44, + 222, + 165, + 110, + 230, + 180, + 161, + 214, + 37, + 65, + 59, + 157, + 26, + 157, + 80, + 197, + 118, + 122, + 48, + 104, + 27, + 124, + 77, + 235, + 46, + 63, + 14, + 198, + 8, + 22, + 85, + 114, + 134, + 226, + 162, + 161, + 203, + 1, + 154, + 230, + 217, + 121, + 14, + 86, + 72, + 144, + 146, + 185, + 244, + 5, + 144, + 146, + 133, + 84, + 177, + 36, + 101, + 80, + 22, + 85, + 204, + 159, + 37, + 66, + 123, + 226, + 233, + 96, + 28, + 156, + 155, + 204, + 18, + 196, + 233, + 107, + 71, + 41, + 72, + 35, + 184, + 104, + 74, + 8, + 112, + 116, + 81, + 161, + 105, + 203, + 247, + 181, + 21, + 247, + 66, + 16, + 93, + 121, + 15, + 178, + 202, + 194, + 210, + 97, + 161, + 18, + 84, + 199, + 217, + 173, + 30, + 76, + 227, + 120, + 92, + 80, + 147, + 125, + 89, + 155, + 210, + 35, + 153, + 222, + 104, + 13, + 230, + 100, + 132, + 160, + 36, + 41, + 116, + 174, + 112, + 186, + 164, + 42, + 195, + 219, + 193, + 214, + 98, + 172, + 181, + 208, + 59, + 16, + 59, + 28, + 66, + 146, + 55, + 22, + 38, + 149, + 49, + 4, + 148, + 28, + 101, + 157, + 113, + 119, + 74, + 30, + 52, + 181, + 12, + 208, + 188, + 214, + 199, + 42, + 137, + 220, + 92, + 157, + 139, + 243, + 102, + 242, + 139, + 23, + 166, + 243, + 67, + 71, + 32, + 142, + 174, + 55, + 54, + 210, + 102, + 242, + 143, + 163, + 175, + 186, + 50, + 15, + 4, + 62, + 102, + 168, + 71, + 115, + 149, + 161, + 85, + 23, + 76, + 81, + 241, + 69, + 63, + 165, + 66, + 54, + 203, + 47, + 216, + 93, + 22, + 173, + 122, + 108, + 72, + 56, + 225, + 49, + 53, + 199, + 75, + 242, + 0, + 116, + 47, + 79, + 244, + 236, + 231, + 63, + 176, + 182, + 128, + 175, + 8, + 181, + 107, + 241, + 169, + 140, + 195, + 1, + 12, + 121, + 28, + 247, + 218, + 112, + 153, + 208, + 204, + 184, + 214, + 178, + 165, + 246, + 143, + 103, + 101, + 36, + 108, + 8, + 73, + 132, + 29, + 36, + 100, + 125, + 7, + 153, + 92, + 3, + 177, + 105, + 132, + 90, + 73, + 148, + 157, + 104, + 92, + 166, + 68, + 54, + 243, + 183, + 181, + 209, + 212, + 148, + 117, + 106, + 173, + 103, + 104, + 106, + 7, + 126, + 228, + 198, + 183, + 214, + 108, + 63, + 243, + 25, + 153, + 51, + 236, + 184, + 94, + 34, + 37, + 108, + 121, + 216, + 37, + 138, + 89, + 167, + 231, + 82, + 218, + 149, + 151, + 162, + 188, + 214, + 241, + 41, + 211, + 160, + 47, + 182, + 147, + 60, + 171, + 17, + 58, + 148, + 192, + 145, + 197, + 171, + 25, + 91, + 224, + 112, + 0, + 32, + 110, + 142, + 122, + 145, + 20, + 61, + 111, + 58, + 85, + 35, + 70, + 96, + 218, + 105, + 116, + 127, + 53, + 150, + 155, + 16, + 84, + 150, + 44, + 167, + 41, + 10, + 124, + 188, + 114, + 86, + 210, + 188, + 112, + 240, + 245, + 203, + 200, + 195, + 17, + 115, + 109, + 68, + 23, + 250, + 189, + 119, + 101, + 207, + 180, + 146, + 57, + 31, + 138, + 133, + 167, + 103, + 245, + 181, + 246, + 111, + 248, + 160, + 76, + 177, + 2, + 192, + 18, + 206, + 169, + 179, + 148, + 147, + 240, + 245, + 198, + 156, + 130, + 143, + 107, + 128, + 0, + 153, + 63, + 73, + 116, + 146, + 90, + 159, + 100, + 216, + 13, + 115, + 12, + 108, + 161, + 225, + 255, + 70, + 89, + 156, + 232, + 154, + 173, + 1, + 247, + 184, + 52, + 93, + 200, + 43, + 21, + 254, + 200, + 254, + 79, + 100, + 184, + 196, + 169, + 105, + 103, + 214, + 90, + 170, + 40, + 183, + 216, + 114, + 165, + 175, + 95, + 58, + 220, + 35, + 222, + 130, + 165, + 159, + 40, + 171, + 193, + 31, + 146, + 67, + 94, + 181, + 203, + 81, + 143, + 72, + 172, + 31, + 17, + 236, + 13, + 1, + 112, + 125, + 123, + 43, + 165, + 2, + 138, + 237, + 40, + 239, + 242, + 160, + 114, + 65, + 58, + 59, + 16, + 61, + 150, + 222, + 246, + 50, + 138, + 34, + 76, + 38, + 133, + 22, + 231, + 7, + 63, + 211, + 191, + 192, + 195, + 186, + 72, + 186, + 26, + 232, + 14, + 200, + 178, + 64, + 145, + 34, + 192, + 148, + 161, + 117, + 63, + 136, + 144, + 232, + 251, + 51, + 212, + 233, + 228, + 87, + 84, + 128, + 131, + 66, + 43, + 143, + 16, + 190, + 108, + 222, + 10, + 165, + 191, + 197, + 94, + 77, + 135, + 66, + 236, + 255, + 163, + 250, + 33, + 231, + 216, + 98, + 90, + 79, + 10, + 193, + 122, + 13, + 191, + 250, + 8, + 167, + 24, + 94, + 54, + 60, + 249, + 127, + 10, + 44, + 252, + 53, + 83, + 178, + 32, + 157, + 104, + 49, + 152, + 43, + 24, + 146, + 6, + 219, + 57, + 80, + 0, + 205, + 150, + 14, + 101, + 59, + 81, + 65, + 138, + 179, + 155, + 223, + 81, + 108, + 251, + 99, + 173, + 177, + 136, + 138, + 122, + 232, + 165, + 100, + 241, + 108, + 215, + 117, + 144, + 208, + 176, + 47, + 77, + 30, + 210, + 236, + 158, + 249, + 253, + 246, + 153, + 141, + 90, + 73, + 198, + 127, + 123, + 28, + 227, + 216, + 8, + 181, + 140, + 123, + 130, + 6, + 122, + 203, + 21, + 2, + 154, + 41, + 13, + 59, + 70, + 90, + 118, + 15, + 204, + 4, + 115, + 53, + 13, + 202, + 10, + 144, + 10, + 164, + 91, + 42, + 38, + 82, + 84, + 127, + 43, + 101, + 167, + 175, + 60, + 50, + 227, + 1, + 83, + 41, + 239, + 61, + 138, + 149, + 232, + 188, + 232, + 224, + 188, + 46, + 126, + 207, + 75, + 130, + 112, + 131, + 92, + 234, + 58, + 67, + 62, + 189, + 207, + 116, + 170, + 201, + 196, + 131, + 210, + 43, + 255, + 59, + 190, + 55, + 231, + 138, + 62, + 235, + 110, + 87, + 170, + 90, + 212, + 217, + 79, + 81, + 45, + 226, + 95, + 128, + 47, + 204, + 161, + 109, + 133, + 200, + 95, + 16, + 178, + 39, + 234, + 109, + 179, + 156, + 94, + 9, + 212, + 107, + 70, + 63, + 110, + 194, + 182, + 145, + 70, + 86, + 109, + 180, + 97, + 6, + 108, + 31, + 161, + 86, + 145, + 169, + 173, + 214, + 113, + 21, + 30, + 223, + 77, + 113, + 97, + 190, + 144, + 0, + 0, + 91, + 122, + 60, + 246, + 127, + 146, + 175, + 203, + 30, + 63, + 228, + 83, + 230, + 12, + 12, + 214, + 88, + 183, + 91, + 77, + 206, + 206, + 115, + 112, + 223, + 174, + 120, + 248, + 17, + 29, + 96, + 73, + 102, + 90, + 28, + 254, + 16, + 76, + 98, + 81, + 67, + 113, + 73, + 92, + 141, + 181, + 83, + 118, + 123, + 133, + 141, + 30, + 101, + 211, + 77, + 114, + 122, + 74, + 219, + 235, + 191, + 53, + 103, + 191, + 124, + 122, + 55, + 183, + 248, + 211, + 218, + 64, + 151, + 146, + 167, + 43, + 73, + 227, + 197, + 4, + 195, + 24, + 33, + 121, + 254, + 27, + 47, + 132, + 120, + 67, + 173, + 210, + 191, + 205, + 72, + 89, + 89, + 87, + 97, + 84, + 82, + 251, + 90, + 204, + 176, + 224, + 43, + 240, + 20, + 42, + 123, + 84, + 182, + 37, + 160, + 120, + 203, + 154, + 50, + 241, + 255, + 174, + 112, + 59, + 0, + 186, + 99, + 58, + 150, + 192, + 137, + 114, + 6, + 237, + 250, + 65, + 0, + 83, + 250, + 64, + 252, + 2, + 64, + 241, + 210, + 58, + 112, + 226, + 22, + 20, + 24, + 34, + 253, + 130, + 14, + 9, + 229, + 160, + 90, + 3, + 76, + 157, + 243, + 25, + 71, + 19, + 0, + 208, + 13, + 117, + 117, + 32, + 156, + 14, + 167, + 200, + 231, + 55, + 130, + 176, + 148, + 22, + 216, + 98, + 23, + 244, + 14, + 183, + 179, + 195, + 113, + 143, + 125, + 46, + 116, + 98, + 73, + 92, + 238, + 200, + 228, + 168, + 100, + 82, + 232, + 166, + 210, + 70, + 254, + 86, + 64, + 187, + 91, + 73, + 213, + 227, + 161, + 100, + 244, + 58, + 169, + 81, + 4, + 195, + 124, + 49, + 71, + 33, + 184, + 231, + 37, + 220, + 148, + 175, + 145, + 145, + 135, + 65, + 233, + 68, + 133, + 139, + 208, + 147, + 52, + 40, + 185, + 254, + 59, + 55, + 208, + 154, + 187, + 249, + 58, + 116, + 126, + 80, + 13, + 65, + 251, + 190, + 85, + 1, + 30, + 114, + 129, + 133, + 153, + 73, + 18, + 32, + 175, + 50, + 236, + 99, + 220, + 24, + 236, + 90, + 148, + 146, + 44, + 123, + 69, + 229, + 53, + 186, + 96, + 41, + 179, + 235, + 152, + 115, + 26, + 173, + 12, + 238, + 83, + 141, + 194, + 15, + 24, + 200, + 12, + 36, + 21, + 35, + 37, + 171, + 196, + 0, + 39, + 102, + 218, + 201, + 60, + 126, + 14, + 22, + 154, + 42, + 82, + 232, + 95, + 50, + 66, + 128, + 127, + 173, + 52, + 141, + 249, + 235, + 222, + 34, + 83, + 17, + 238, + 122, + 235, + 31, + 20, + 116, + 152, + 2, + 55, + 155, + 125, + 42, + 115, + 231, + 183, + 141, + 170, + 69, + 171, + 254, + 61, + 157, + 211, + 236, + 191, + 127, + 23, + 1, + 157, + 40, + 194, + 153, + 112, + 227, + 245, + 140, + 125, + 37, + 80, + 77, + 8, + 38, + 146, + 120, + 64, + 113, + 126, + 171, + 112, + 123, + 179, + 253, + 111, + 67, + 247, + 93, + 151, + 137, + 152, + 4, + 17, + 83, + 248, + 227, + 56, + 180, + 131, + 94, + 212, + 28, + 103, + 197, + 182, + 10, + 92, + 87, + 106, + 154, + 84, + 167, + 79, + 166, + 108, + 184, + 172, + 215, + 172, + 178, + 175, + 253, + 186, + 111, + 46, + 3, + 75, + 140, + 109, + 182, + 176, + 158, + 54, + 77, + 221, + 168, + 221, + 121, + 97, + 211, + 10, + 0, + 238, + 126, + 12, + 190, + 44, + 55, + 207, + 192, + 229, + 241, + 162, + 63, + 219, + 52, + 132, + 156, + 183, + 93, + 225, + 37, + 95, + 167, + 195, + 165, + 147, + 16, + 137, + 217, + 238, + 213, + 12, + 100, + 83, + 84, + 98, + 58, + 67, + 69, + 53, + 41, + 247, + 20, + 18, + 162, + 181, + 194, + 126, + 99, + 244, + 49, + 42, + 4, + 164, + 122, + 117, + 150, + 110, + 125, + 101, + 75, + 248, + 67, + 69, + 6, + 122, + 169, + 25, + 152, + 246, + 209, + 44, + 207, + 2, + 116, + 214, + 41, + 13, + 85, + 183, + 222, + 187, + 178, + 218, + 234, + 57, + 118, + 146, + 143, + 70, + 28, + 243, + 195, + 230, + 120, + 87, + 140, + 129, + 50, + 56, + 254, + 216, + 21, + 214, + 193, + 26, + 34, + 242, + 175, + 110, + 74, + 44, + 25, + 22, + 55, + 34, + 215, + 19, + 78, + 109, + 219, + 241, + 80, + 38, + 197, + 24, + 225, + 15, + 176, + 208, + 94, + 240, + 160, + 129, + 116, + 134, + 244, + 190, + 94, + 233, + 248, + 170, + 153, + 133, + 153, + 123, + 173, + 167, + 83, + 170, + 183, + 106, + 27, + 228, + 163, + 250, + 238, + 13, + 72, + 45, + 49, + 225, + 227, + 124, + 27, + 48, + 44, + 63, + 91, + 191, + 80, + 36, + 213, + 209, + 255, + 4, + 127, + 93, + 170, + 134, + 155, + 230, + 134, + 249, + 48, + 182, + 3, + 64, + 126, + 53, + 200, + 82, + 208, + 152, + 6, + 13, + 212, + 124, + 222, + 140, + 110, + 215, + 44, + 9, + 123, + 84, + 154, + 186, + 246, + 220, + 124, + 83, + 238, + 249, + 194, + 202, + 220, + 72, + 145, + 132, + 62, + 75, + 43, + 101, + 79, + 233, + 95, + 80, + 73, + 64, + 210, + 167, + 170, + 198, + 25, + 11, + 161, + 0, + 87, + 157, + 23, + 114, + 59, + 76, + 63, + 182, + 14, + 12, + 249, + 217, + 18, + 126, + 101, + 19, + 70, + 94, + 211, + 211, + 120, + 44, + 211, + 11, + 247, + 232, + 5, + 198, + 241, + 184, + 140, + 233, + 165, + 229, + 56, + 105, + 67, + 64, + 73, + 162, + 0, + 123, + 118, + 12, + 241, + 175, + 100, + 175, + 114, + 31, + 218, + 165, + 196, + 142, + 186, + 45, + 78, + 119, + 67, + 215, + 98, + 70, + 85, + 59, + 152, + 84, + 17, + 155, + 17, + 149, + 24, + 80, + 76, + 132, + 25, + 107, + 123, + 33, + 194, + 27, + 81, + 36, + 235, + 66, + 41, + 175, + 55, + 203, + 100, + 106, + 172, + 135, + 204, + 137, + 250, + 201, + 151, + 212, + 64, + 54, + 5, + 104, + 5, + 45, + 1, + 128, + 58, + 174, + 151, + 9, + 208, + 206, + 49, + 72, + 192, + 115, + 141, + 148, + 94, + 9, + 51, + 201, + 58, + 141, + 163, + 156, + 149, + 41, + 56, + 107, + 237, + 151, + 170, + 76, + 110, + 79, + 233, + 150, + 16, + 143, + 233, + 180, + 155, + 253, + 240, + 24, + 115, + 207, + 109, + 4, + 225, + 54, + 134, + 190, + 238, + 207, + 83, + 124, + 214, + 187, + 107, + 51, + 145, + 242, + 10, + 232, + 6, + 159, + 192, + 205, + 98, + 203, + 247, + 240, + 213, + 132, + 108, + 41, + 107, + 59, + 182, + 0, + 182, + 110, + 76, + 35, + 13, + 118, + 51, + 95, + 11, + 183, + 249, + 253, + 84, + 10, + 193, + 18, + 6, + 204, + 12, + 108, + 197, + 80, + 149, + 231, + 54, + 8, + 178, + 12, + 166, + 245, + 201, + 127, + 113, + 192, + 120, + 49, + 255, + 40, + 160, + 211, + 143, + 65, + 47, + 212, + 219, + 51, + 121, + 168, + 236, + 166, + 142, + 109, + 0, + 69, + 56, + 215, + 26, + 217, + 215, + 6, + 17, + 54, + 252, + 65, + 198, + 104, + 112, + 233, + 173, + 242, + 139, + 174, + 168, + 49, + 254, + 232, + 24, + 211, + 165, + 203, + 147, + 200, + 132, + 246, + 209, + 158, + 18, + 186, + 1, + 229, + 239, + 2, + 165, + 84, + 228, + 113, + 249, + 212, + 182, + 160, + 214, + 135, + 30, + 25, + 235, + 40, + 9, + 40, + 12, + 124, + 73, + 57, + 196, + 133, + 54, + 179, + 105, + 119, + 169, + 228, + 208, + 217, + 66, + 35, + 114, + 59, + 177, + 114, + 109, + 172, + 112, + 118, + 71, + 4, + 73, + 234, + 77, + 184, + 10, + 214, + 146, + 204, + 153, + 103, + 132, + 75, + 12, + 211, + 109, + 235, + 214, + 91, + 4, + 231, + 164, + 56, + 170, + 246, + 97, + 44, + 99, + 210, + 164, + 174, + 34, + 250, + 107, + 193, + 162, + 156, + 191, + 5, + 45, + 225, + 241, + 88, + 139, + 225, + 73, + 51, + 103, + 240, + 9, + 135, + 244, + 36, + 53, + 65, + 196, + 76, + 255, + 247, + 116, + 233, + 183, + 134, + 240, + 237, + 66, + 208, + 194, + 226, + 59, + 222, + 10, + 89, + 219, + 201, + 179, + 124, + 109, + 49, + 37, + 243, + 96, + 94, + 101, + 52, + 168, + 48, + 222, + 7, + 226, + 49, + 110, + 79, + 89, + 246, + 38, + 186, + 243, + 30, + 76, + 230, + 226, + 100, + 100, + 191, + 115, + 33, + 172, + 246, + 178, + 103, + 113, + 122, + 61, + 215, + 45, + 150, + 19, + 43, + 175, + 140, + 167, + 3, + 95, + 23, + 3, + 11, + 61, + 97, + 181, + 190, + 74, + 227, + 77, + 175, + 29, + 153, + 201, + 32, + 245, + 86, + 222, + 108, + 243, + 43, + 223, + 97, + 252, + 113, + 113, + 23, + 52, + 203, + 238, + 111, + 216, + 224, + 201, + 104, + 47, + 71, + 47, + 239, + 87, + 188, + 214, + 104, + 108, + 44, + 79, + 121, + 99, + 186, + 135, + 229, + 97, + 89, + 126, + 128, + 168, + 193, + 158, + 30, + 48, + 189, + 106, + 255, + 38, + 118, + 98, + 148, + 35, + 253, + 159, + 38, + 226, + 44, + 217, + 170, + 105, + 161, + 212, + 92, + 214, + 97, + 2, + 180, + 202, + 49, + 39, + 250, + 160, + 232, + 164, + 41, + 99, + 213, + 59, + 205, + 151, + 193, + 177, + 47, + 253, + 243, + 156, + 158, + 10, + 88, + 177, + 136, + 162, + 238, + 251, + 54, + 100, + 233, + 115, + 235, + 30, + 138, + 162, + 27, + 86, + 166, + 138, + 63, + 230, + 138, + 85, + 113, + 185, + 254, + 187, + 212, + 224, + 133, + 123, + 53, + 176, + 72, + 41, + 242, + 145, + 233, + 55, + 203, + 47, + 248, + 226, + 65, + 215, + 221, + 140, + 12, + 98, + 74, + 191, + 49, + 217, + 61, + 136, + 16, + 36, + 78, + 34, + 58, + 232, + 228, + 213, + 113, + 47, + 77, + 65, + 187, + 96, + 24, + 134, + 147, + 45, + 77, + 75, + 89, + 211, + 243, + 117, + 40, + 22, + 45, + 163, + 58, + 101, + 126, + 6, + 57, + 85, + 173, + 0, + 61, + 247, + 4, + 228, + 179, + 243, + 239, + 209, + 237, + 124, + 157, + 108, + 34, + 253, + 26, + 35, + 215, + 65, + 203, + 104, + 127, + 54, + 176, + 53, + 54, + 89, + 166, + 11, + 152, + 155, + 5, + 124, + 244, + 183, + 145, + 251, + 102, + 208, + 245, + 230, + 182, + 83, + 140, + 145, + 69, + 114, + 151, + 38, + 32, + 127, + 238, + 93, + 221, + 252, + 18, + 36, + 111, + 23, + 152, + 132, + 229, + 127, + 64, + 165, + 7, + 86, + 131, + 214, + 212, + 59, + 25, + 128, + 154, + 102, + 159, + 88, + 227, + 122, + 112, + 61, + 86, + 247, + 173, + 34, + 184, + 157, + 209, + 165, + 51, + 185, + 125, + 136, + 163, + 41, + 83, + 27, + 135, + 80, + 134, + 59, + 235, + 168, + 126, + 30, + 57, + 150, + 210, + 251, + 83, + 98, + 32, + 183, + 63, + 189, + 177, + 165, + 20, + 254, + 189, + 102, + 104, + 80, + 41, + 90, + 154, + 108, + 180, + 15, + 40, + 252, + 222, + 88, + 190, + 79, + 251, + 189, + 64, + 24, + 195, + 32, + 229, + 114, + 227, + 182, + 207, + 221, + 224, + 102, + 208, + 110, + 89, + 136, + 78, + 20, + 1, + 6, + 77, + 67, + 206, + 154, + 175, + 232, + 79, + 85, + 135, + 0, + 122, + 39, + 12, + 106, + 172, + 240, + 162, + 194, + 212, + 153, + 144, + 106, + 216, + 46, + 36, + 40, + 154, + 199, + 81, + 17, + 187, + 61, + 160, + 223, + 255, + 104, + 228, + 82, + 137, + 249, + 63, + 232, + 65, + 17, + 90, + 215, + 42, + 134, + 163, + 26, + 108, + 35, + 212, + 248, + 15, + 255, + 175, + 23, + 104, + 114, + 27, + 219, + 174, + 133, + 34, + 11, + 144, + 23, + 213, + 235, + 22, + 15, + 138, + 62, + 135, + 145, + 39, + 137, + 42, + 197, + 95, + 140, + 102, + 189, + 79, + 196, + 73, + 83, + 143, + 114, + 205, + 115, + 12, + 2, + 3, + 158, + 54, + 52, + 53, + 248, + 144, + 28, + 143, + 224, + 188, + 150, + 244, + 139, + 169, + 127, + 11, + 28, + 143, + 181, + 52, + 166, + 74, + 243, + 154, + 109, + 96, + 185, + 169, + 213, + 3, + 129, + 198, + 226, + 252, + 248, + 61, + 89, + 40, + 69, + 60, + 70, + 91, + 241, + 213, + 35, + 177, + 40, + 177, + 255, + 25, + 11, + 158, + 193, + 249, + 182, + 33, + 123, + 150, + 34, + 245, + 127, + 60, + 177, + 8, + 1, + 168, + 66, + 219, + 17, + 128, + 197, + 27, + 223, + 211, + 224, + 215, + 134, + 109, + 237, + 160, + 107, + 232, + 149, + 157, + 168, + 65, + 104, + 243, + 59, + 40, + 154, + 27, + 240, + 46, + 139, + 64, + 196, + 124, + 55, + 11, + 224, + 126, + 211, + 92, + 251, + 4, + 201, + 32, + 181, + 74, + 250, + 177, + 51, + 157, + 162, + 62, + 129, + 162, + 17, + 101, + 151, + 22, + 31, + 183, + 161, + 47, + 111, + 69, + 240, + 204, + 52, + 212, + 35, + 153, + 174, + 42, + 176, + 239, + 86, + 169, + 46, + 98, + 138, + 9, + 234, + 194, + 61, + 219, + 158, + 82, + 27, + 131, + 189, + 104, + 255, + 240, + 233, + 38, + 148, + 216, + 114, + 192, + 218, + 3, + 77, + 126, + 194, + 191, + 159, + 16, + 234, + 106, + 32, + 152, + 230, + 149, + 94, + 237, + 218, + 2, + 172, + 143, + 254, + 236, + 169, + 207, + 198, + 168, + 228, + 29, + 69, + 182, + 61, + 178, + 158, + 97, + 191, + 80, + 195, + 71, + 32, + 127, + 109, + 244, + 108, + 104, + 213, + 18, + 239, + 192, + 219, + 18, + 131, + 132, + 130, + 229, + 19, + 27, + 170, + 146, + 120, + 84, + 122, + 185, + 136, + 180, + 178, + 96, + 50, + 180, + 31, + 188, + 55, + 129, + 43, + 172, + 227, + 186, + 64, + 143, + 157, + 76, + 176, + 128, + 170, + 45, + 155, + 168, + 57, + 193, + 40, + 165, + 204, + 51, + 249, + 71, + 40, + 133, + 187, + 244, + 140, + 76, + 31, + 239, + 227, + 123, + 122, + 97, + 19, + 172, + 56, + 136, + 228, + 153, + 52, + 37, + 126, + 44, + 169, + 174, + 65, + 91, + 6, + 220, + 179, + 56, + 250, + 51, + 190, + 49, + 156, + 252, + 150, + 220, + 177, + 30, + 174, + 183, + 5, + 215, + 46, + 62, + 132, + 116, + 188, + 35, + 218, + 128, + 123, + 178, + 3, + 115, + 53, + 229, + 250, + 131, + 117, + 82, + 47, + 200, + 117, + 159, + 107, + 201, + 134, + 1, + 125, + 73, + 71, + 92, + 111, + 250, + 241, + 97, + 221, + 134, + 82, + 149, + 88, + 147, + 218, + 56, + 3, + 44, + 32, + 188, + 51, + 208, + 234, + 19, + 250, + 106, + 32, + 119, + 145, + 247, + 120, + 96, + 207, + 79, + 142, + 172, + 2, + 8, + 254, + 136, + 87, + 36, + 62, + 87, + 151, + 193, + 76, + 18, + 181, + 46, + 202, + 111, + 119, + 106, + 254, + 64, + 129, + 119, + 57, + 229, + 54, + 45, + 90, + 244, + 189, + 160, + 88, + 153, + 158, + 44, + 182, + 190, + 207, + 51, + 101, + 55, + 165, + 65, + 26, + 211, + 11, + 114, + 44, + 4, + 177, + 145, + 149, + 74, + 176, + 7, + 176, + 214, + 119, + 226, + 63, + 161, + 137, + 63, + 208, + 24, + 36, + 148, + 16, + 142, + 21, + 104, + 142, + 29, + 17, + 93, + 213, + 245, + 9, + 97, + 117, + 22, + 201, + 121, + 102, + 96, + 135, + 5, + 188, + 164, + 49, + 85, + 0, + 73, + 51, + 17, + 105, + 200, + 114, + 240, + 102, + 42, + 212, + 201, + 54, + 129, + 8, + 157, + 86, + 52, + 93, + 162, + 95, + 62, + 176, + 123, + 120, + 113, + 147, + 35, + 72, + 221, + 173, + 103, + 177, + 230, + 77, + 138, + 200, + 176, + 175, + 3, + 98, + 73, + 32, + 3, + 192, + 230, + 169, + 182, + 110, + 9, + 33, + 225, + 244, + 220, + 128, + 118, + 146, + 78, + 16, + 127, + 123, + 87, + 33, + 59, + 51, + 24, + 177, + 3, + 32, + 192, + 145, + 33, + 1, + 124, + 106, + 30, + 36, + 182, + 160, + 143, + 77, + 138, + 16, + 93, + 10, + 27, + 238, + 127, + 6, + 110, + 214, + 159, + 188, + 72, + 154, + 180, + 140, + 91, + 198, + 165, + 4, + 249, + 251, + 222, + 121, + 74, + 77, + 149, + 249, + 117, + 84, + 44, + 11, + 100, + 164, + 92, + 215, + 4, + 49, + 49, + 86, + 3, + 30, + 62, + 201, + 60, + 218, + 26, + 162, + 57, + 136, + 226, + 240, + 3, + 18, + 124, + 187, + 130, + 195, + 79, + 103, + 106, + 184, + 60, + 129, + 14, + 23, + 135, + 192, + 242, + 146, + 44, + 43, + 23, + 116, + 66, + 46, + 30, + 191, + 211, + 51, + 220, + 85, + 161, + 172, + 54, + 72, + 30, + 129, + 211, + 75, + 150, + 43, + 127, + 102, + 55, + 114, + 167, + 78, + 34, + 113, + 68, + 98, + 75, + 149, + 10, + 164, + 231, + 125, + 72, + 172, + 132, + 225, + 100, + 120, + 160, + 245, + 170, + 49, + 97, + 178, + 42, + 167, + 0, + 202, + 149, + 22, + 75, + 105, + 20, + 136, + 253, + 143, + 120, + 41, + 172, + 19, + 3, + 85, + 184, + 138, + 150, + 57, + 124, + 13, + 61, + 215, + 49, + 222, + 221, + 2, + 143, + 241, + 155, + 230, + 118, + 196, + 30, + 178, + 161, + 214, + 146, + 1, + 105, + 69, + 67, + 46, + 68, + 48, + 99, + 16, + 237, + 245, + 45, + 82, + 119, + 185, + 94, + 191, + 39, + 112, + 40, + 62, + 203, + 4, + 131, + 17, + 139, + 105, + 45, + 231, + 12, + 215, + 96, + 129, + 72, + 171, + 210, + 232, + 12, + 146, + 36, + 120, + 63, + 173, + 141, + 129, + 135, + 65, + 222, + 222, + 135, + 213, + 31, + 230, + 6, + 232, + 109, + 165, + 32, + 239, + 157, + 117, + 166, + 240, + 72, + 172, + 5, + 8, + 236, + 159, + 197, + 138, + 40, + 153, + 209, + 162, + 236, + 28, + 227, + 139, + 121, + 111, + 37, + 45, + 43, + 236, + 103, + 0, + 63, + 56, + 54, + 88, + 58, + 83, + 96, + 109, + 85, + 203, + 36, + 251, + 65, + 57, + 192, + 151, + 102, + 101, + 23, + 170, + 89, + 221, + 89, + 78, + 145, + 177, + 122, + 140, + 50, + 175, + 62, + 119, + 220, + 109, + 208, + 8, + 198, + 26, + 43, + 149, + 188, + 206, + 3, + 109, + 91, + 88, + 0, + 184, + 16, + 78, + 246, + 96, + 204, + 102, + 13, + 84, + 227, + 250, + 43, + 164, + 73, + 25, + 80, + 178, + 75, + 91, + 132, + 206, + 22, + 247, + 131, + 15, + 184, + 15, + 106, + 18, + 89, + 88, + 202, + 92, + 115, + 171, + 70, + 11, + 152, + 217, + 121, + 20, + 2, + 104, + 219, + 88, + 203, + 206, + 91, + 60, + 115, + 121, + 4, + 251, + 76, + 250, + 190, + 92, + 144, + 169, + 209, + 131, + 60, + 122, + 100, + 254, + 95, + 169, + 45, + 132, + 74, + 115, + 148, + 59, + 207, + 236, + 37, + 146, + 170, + 223, + 204, + 230, + 254, + 0, + 37, + 13, + 41, + 153, + 106, + 32, + 91, + 249, + 207, + 105, + 69, + 109, + 125, + 63, + 16, + 20, + 46, + 50, + 248, + 194, + 136, + 139, + 196, + 42, + 24, + 114, + 164, + 151, + 118, + 102, + 142, + 215, + 199, + 179, + 215, + 209, + 177, + 25, + 210, + 176, + 164, + 223, + 107, + 21, + 107, + 240, + 106, + 15, + 248, + 131, + 58, + 180, + 193, + 20, + 46, + 26, + 193, + 71, + 125, + 240, + 24, + 69, + 145, + 54, + 142, + 125, + 194, + 91, + 106, + 172, + 251, + 111, + 244, + 186, + 174, + 198, + 3, + 64, + 5, + 91, + 147, + 98, + 189, + 109, + 86, + 88, + 18, + 77, + 218, + 124, + 189, + 128, + 195, + 176, + 86, + 182, + 232, + 36, + 92, + 243, + 136, + 22, + 42, + 126, + 75, + 170, + 111, + 108, + 70, + 245, + 69, + 40, + 3, + 124, + 44, + 145, + 67, + 30, + 202, + 58, + 91, + 239, + 111, + 138, + 182, + 203, + 253, + 139, + 201, + 183, + 210, + 158, + 32, + 133, + 71, + 70, + 173, + 132, + 169, + 199, + 20, + 0, + 101, + 61, + 252, + 239, + 48, + 250, + 115, + 109, + 225, + 144, + 41, + 62, + 37, + 1, + 43, + 237, + 86, + 190, + 117, + 237, + 167, + 74, + 247, + 33, + 241, + 70, + 42, + 188, + 211, + 32, + 33, + 173, + 47, + 67, + 163, + 242, + 133, + 148, + 151, + 176, + 231, + 138, + 208, + 221, + 210, + 146, + 110, + 137, + 64, + 171, + 177, + 55, + 65, + 172, + 32, + 205, + 239, + 253, + 174, + 41, + 226, + 74, + 5, + 240, + 56, + 138, + 219, + 47, + 199, + 42, + 231, + 218, + 227, + 90, + 12, + 173, + 129, + 6, + 80, + 165, + 143, + 169, + 62, + 99, + 224, + 140, + 255, + 205, + 72, + 154, + 95, + 109, + 13, + 87, + 143, + 163, + 3, + 56, + 40, + 62, + 172, + 132, + 11, + 192, + 183, + 174, + 125, + 217, + 239, + 199, + 85, + 3, + 78, + 23, + 159, + 64, + 91, + 195, + 133, + 227, + 18, + 137, + 102, + 248, + 165, + 12, + 72, + 170, + 72, + 223, + 79, + 179, + 174, + 70, + 197, + 75, + 228, + 64, + 55, + 247, + 10, + 211, + 187, + 139, + 240, + 196, + 46, + 28, + 239, + 70, + 21, + 165, + 90, + 28, + 5, + 43, + 217, + 182, + 108, + 125, + 48, + 168, + 137, + 249, + 224, + 8, + 213, + 3, + 127, + 137, + 185, + 58, + 80, + 73, + 77, + 141, + 148, + 221, + 127, + 223, + 239, + 104, + 245, + 226, + 173, + 9, + 189, + 32, + 77, + 190, + 23, + 77, + 108, + 172, + 193, + 129, + 254, + 235, + 33, + 224, + 232, + 50, + 57, + 4, + 129, + 218, + 85, + 237, + 143, + 133, + 155, + 51, + 207, + 20, + 152, + 164, + 99, + 230, + 68, + 46, + 175, + 45, + 32, + 90, + 61, + 182, + 238, + 155, + 126, + 28, + 40, + 164, + 37, + 37, + 163, + 97, + 98, + 7, + 103, + 189, + 55, + 102, + 76, + 170, + 155, + 40, + 190, + 2, + 90, + 33, + 122, + 226, + 177, + 32, + 184, + 234, + 102, + 225, + 177, + 70, + 21, + 62, + 118, + 64, + 196, + 245, + 21, + 191, + 15, + 241, + 147, + 169, + 211, + 143, + 79, + 178, + 16, + 43, + 219, + 170, + 38, + 250, + 161, + 41, + 62, + 20, + 224, + 66, + 55, + 246, + 250, + 34, + 94, + 17, + 144, + 245, + 255, + 58, + 104, + 234, + 179, + 176, + 146, + 143, + 53, + 114, + 253, + 92, + 80, + 237, + 149, + 81, + 141, + 115, + 154, + 182, + 68, + 29, + 45, + 167, + 15, + 44, + 80, + 160, + 219, + 104, + 172, + 50, + 189, + 98, + 14, + 180, + 251, + 152, + 89, + 130, + 9, + 109, + 160, + 81, + 205, + 169, + 40, + 6, + 123, + 251, + 221, + 241, + 154, + 198, + 80, + 205, + 94, + 235, + 231, + 40, + 39, + 135, + 20, + 89, + 51, + 134, + 85, + 95, + 18, + 122, + 128, + 181, + 241, + 255, + 57, + 41, + 127, + 199, + 2, + 39, + 150, + 122, + 109, + 200, + 246, + 0, + 51, + 170, + 4, + 18, + 185, + 45, + 138, + 57, + 145, + 64, + 55, + 174, + 69, + 177, + 134, + 196, + 239, + 223, + 140, + 173, + 100, + 15, + 53, + 222, + 89, + 111, + 236, + 148, + 150, + 129, + 208, + 210, + 12, + 61, + 47, + 210, + 86, + 251, + 162, + 150, + 103, + 169, + 205, + 130, + 104, + 85, + 100, + 121, + 60, + 87, + 9, + 214, + 27, + 55, + 142, + 11, + 180, + 68, + 131, + 150, + 146, + 251, + 85, + 240, + 56, + 144, + 25, + 56, + 249, + 81, + 25, + 221, + 52, + 7, + 235, + 234, + 189, + 81, + 34, + 14, + 154, + 55, + 105, + 47, + 212, + 131, + 94, + 55, + 184, + 113, + 139, + 2, + 195, + 100, + 178, + 231, + 124, + 139, + 30, + 149, + 36, + 7, + 65, + 192, + 145, + 42, + 253, + 204, + 217, + 187, + 201, + 6, + 44, + 115, + 96, + 180, + 221, + 136, + 130, + 129, + 200, + 127, + 12, + 253, + 32, + 54, + 80, + 35, + 116, + 173, + 52, + 26, + 15, + 198, + 181, + 159, + 4, + 26, + 140, + 151, + 245, + 187, + 128, + 163, + 246, + 185, + 236, + 158, + 212, + 188, + 126, + 109, + 51, + 83, + 96, + 182, + 151, + 196, + 213, + 131, + 7, + 212, + 102, + 155, + 92, + 205, + 183, + 163, + 169, + 142, + 246, + 104, + 69, + 165, + 51, + 213, + 243, + 181, + 85, + 156, + 199, + 210, + 44, + 24, + 31, + 39, + 126, + 189, + 157, + 95, + 89, + 11, + 59, + 67, + 6, + 21, + 93, + 178, + 254, + 2, + 113, + 196, + 7, + 152, + 144, + 48, + 145, + 24, + 250, + 70, + 245, + 201, + 243, + 156, + 128, + 172, + 211, + 77, + 252, + 41, + 6, + 135, + 80, + 40, + 255, + 137, + 17, + 161, + 207, + 22, + 40, + 160, + 113, + 43, + 34, + 86, + 170, + 179, + 66, + 224, + 238, + 206, + 45, + 215, + 152, + 84, + 101, + 139, + 35, + 36, + 185, + 143, + 61, + 221, + 199, + 232, + 146, + 15, + 87, + 185, + 202, + 122, + 160, + 247, + 57, + 61, + 195, + 131, + 25, + 224, + 142, + 112, + 39, + 100, + 135, + 87, + 216, + 232, + 90, + 247, + 63, + 137, + 36, + 101, + 246, + 202, + 10, + 57, + 152, + 205, + 51, + 129, + 239, + 241, + 117, + 178, + 88, + 202, + 181, + 173, + 94, + 204, + 54, + 7, + 121, + 158, + 97, + 118, + 215, + 38, + 98, + 63, + 21, + 208, + 185, + 78, + 89, + 90, + 219, + 98, + 161, + 80, + 69, + 197, + 216, + 40, + 36, + 167, + 142, + 213, + 95, + 67, + 99, + 202, + 110, + 0, + 179, + 79, + 33, + 16, + 181, + 167, + 20, + 226, + 3, + 38, + 116, + 182, + 21, + 89, + 44, + 214, + 42, + 83, + 104, + 216, + 14, + 191, + 218, + 66, + 17, + 6, + 18, + 73, + 245, + 203, + 70, + 209, + 234, + 195, + 116, + 199, + 1, + 77, + 127, + 193, + 208, + 122, + 138, + 10, + 76, + 26, + 158, + 126, + 37, + 6, + 56, + 59, + 10, + 73, + 92, + 192, + 119, + 13, + 72, + 69, + 129, + 163, + 93, + 20, + 63, + 188, + 133, + 120, + 220, + 197, + 172, + 186, + 125, + 78, + 109, + 171, + 131, + 161, + 16, + 93, + 9, + 118, + 80, + 135, + 163, + 105, + 93, + 148, + 226, + 146, + 23, + 110, + 200, + 70, + 37, + 12, + 6, + 45, + 109, + 121, + 0, + 33, + 172, + 151, + 56, + 254, + 46, + 229, + 6, + 112, + 175, + 189, + 3, + 54, + 33, + 19, + 119, + 101, + 197, + 72, + 53, + 40, + 168, + 158, + 180, + 63, + 233, + 154, + 235, + 143, + 48, + 205, + 170, + 138, + 215, + 255, + 228, + 172, + 47, + 117, + 103, + 86, + 144, + 245, + 12, + 39, + 61, + 204, + 132, + 53, + 52, + 57, + 171, + 43, + 14, + 54, + 212, + 88, + 37, + 154, + 127, + 41, + 25, + 90, + 101, + 188, + 225, + 215, + 113, + 155, + 191, + 79, + 147, + 155, + 62, + 85, + 141, + 245, + 85, + 52, + 19, + 50, + 237, + 49, + 31, + 150, + 80, + 204, + 176, + 163, + 120, + 35, + 230, + 77, + 240, + 118, + 254, + 32, + 6, + 205, + 232, + 22, + 127, + 95, + 158, + 89, + 181, + 236, + 249, + 111, + 37, + 137, + 99, + 29, + 157, + 249, + 212, + 238, + 242, + 230, + 138, + 216, + 106, + 212, + 120, + 225, + 140, + 16, + 122, + 32, + 138, + 45, + 237, + 119, + 38, + 128, + 254, + 122, + 19, + 90, + 253, + 76, + 88, + 44, + 11, + 49, + 182, + 119, + 103, + 206, + 65, + 255, + 85, + 249, + 68, + 212, + 215, + 133, + 16, + 189, + 222, + 128, + 27, + 188, + 241, + 59, + 207, + 198, + 171, + 40, + 125, + 2, + 162, + 23, + 110, + 0, + 131, + 7, + 94, + 67, + 27, + 171, + 49, + 41, + 138, + 71, + 17, + 218, + 45, + 94, + 13, + 20, + 150, + 140, + 110, + 73, + 196, + 248, + 45, + 224, + 41, + 102, + 214, + 138, + 13, + 136, + 19, + 60, + 31, + 55, + 122, + 74, + 199, + 75, + 107, + 229, + 78, + 226, + 32, + 198, + 92, + 172, + 121, + 3, + 19, + 64, + 202, + 145, + 172, + 193, + 236, + 162, + 204, + 184, + 3, + 163, + 172, + 38, + 24, + 59, + 32, + 24, + 247, + 123, + 237, + 15, + 18, + 34, + 250, + 22, + 102, + 71, + 215, + 231, + 209, + 202, + 104, + 49, + 127, + 182, + 251, + 42, + 223, + 201, + 100, + 5, + 210, + 244, + 8, + 214, + 14, + 224, + 210, + 65, + 111, + 183, + 97, + 45, + 162, + 246, + 46, + 149, + 245, + 126, + 52, + 90, + 32, + 38, + 56, + 135, + 38, + 98, + 89, + 175, + 225, + 198, + 40, + 206, + 241, + 52, + 0, + 243, + 13, + 246, + 89, + 234, + 234, + 133, + 124, + 59, + 168, + 203, + 108, + 80, + 143, + 230, + 49, + 7, + 133, + 255, + 56, + 111, + 236, + 225, + 141, + 216, + 103, + 108, + 209, + 170, + 249, + 134, + 246, + 112, + 61, + 29, + 115, + 80, + 124, + 113, + 111, + 115, + 97, + 205, + 190, + 175, + 8, + 151, + 212, + 110, + 205, + 129, + 1, + 59, + 160, + 212, + 33, + 169, + 180, + 46, + 1, + 164, + 204, + 83, + 246, + 110, + 69, + 160, + 232, + 97, + 127, + 128, + 138, + 99, + 102, + 111, + 219, + 75, + 33, + 242, + 192, + 47, + 52, + 213, + 169, + 27, + 122, + 31, + 198, + 99, + 253, + 255, + 11, + 191, + 219, + 4, + 1, + 232, + 89, + 46, + 150, + 112, + 123, + 28, + 90, + 239, + 105, + 62, + 44, + 160, + 29, + 73, + 140, + 58, + 28, + 168, + 251, + 124, + 182, + 68, + 84, + 188, + 126, + 137, + 139, + 105, + 85, + 242, + 29, + 0, + 85, + 69, + 121, + 179, + 88, + 92, + 59, + 44, + 248, + 81, + 185, + 220, + 179, + 155, + 130, + 157, + 92, + 83, + 179, + 194, + 154, + 136, + 172, + 167, + 221, + 115, + 207, + 147, + 169, + 70, + 232, + 28, + 21, + 89, + 168, + 46, + 88, + 128, + 45, + 94, + 200, + 196, + 244, + 218, + 175, + 60, + 108, + 72, + 179, + 171, + 86, + 2, + 153, + 210, + 202, + 8, + 61, + 6, + 62, + 251, + 119, + 47, + 28, + 9, + 89, + 139, + 222, + 140, + 198, + 51, + 149, + 64, + 31, + 5, + 111, + 212, + 91, + 78, + 25, + 16, + 220, + 80, + 146, + 7, + 151, + 111, + 15, + 227, + 97, + 210, + 151, + 83, + 33, + 236, + 87, + 40, + 31, + 139, + 105, + 142, + 28, + 159, + 2, + 246, + 187, + 229, + 69, + 19, + 54, + 119, + 189, + 60, + 174, + 99, + 177, + 131, + 44, + 74, + 32, + 143, + 190, + 85, + 101, + 244, + 20, + 173, + 70, + 25, + 59, + 207, + 24, + 67, + 52, + 195, + 199, + 193, + 37, + 204, + 97, + 14, + 22, + 115, + 245, + 179, + 18, + 101, + 35, + 244, + 174, + 219, + 132, + 80, + 80, + 233, + 250, + 17, + 192, + 144, + 135, + 50, + 38, + 48, + 172, + 2, + 93, + 250, + 178, + 173, + 233, + 201, + 52, + 237, + 88, + 247, + 122, + 178, + 58, + 213, + 216, + 171, + 147, + 86, + 150, + 60, + 205, + 249, + 125, + 69, + 178, + 75, + 183, + 142, + 13, + 177, + 22, + 63, + 38, + 127, + 135, + 215, + 33, + 202, + 147, + 59, + 24, + 4, + 141, + 215, + 15, + 103, + 213, + 35, + 37, + 138, + 79, + 72, + 50, + 178, + 2, + 118, + 136, + 221, + 69, + 161, + 16, + 191, + 203, + 30, + 93, + 177, + 42, + 93, + 95, + 199, + 94, + 158, + 33, + 178, + 44, + 225, + 12, + 81, + 89, + 187, + 180, + 224, + 70, + 227, + 159, + 209, + 28, + 119, + 149, + 126, + 56, + 245, + 105, + 234, + 205, + 52, + 150, + 179, + 154, + 214, + 24, + 212, + 25, + 121, + 118, + 247, + 140, + 2, + 59, + 147, + 227, + 11, + 236, + 124, + 101, + 58, + 157, + 45, + 98, + 127, + 154, + 118, + 251, + 180, + 20, + 67, + 220, + 229, + 94, + 194, + 108, + 220, + 186, + 120, + 74, + 217, + 40, + 53, + 9, + 216, + 60, + 242, + 110, + 26, + 189, + 240, + 200, + 32, + 103, + 227, + 89, + 164, + 131, + 50, + 110, + 168, + 42, + 239, + 145, + 188, + 111, + 25, + 174, + 199, + 35, + 242, + 179, + 225, + 22, + 94, + 79, + 56, + 27, + 80, + 1, + 176, + 38, + 88, + 44, + 110, + 6, + 103, + 180, + 199, + 70, + 211, + 198, + 248, + 38, + 198, + 44, + 56, + 67, + 210, + 181, + 218, + 18, + 114, + 94, + 19, + 149, + 194, + 180, + 89, + 50, + 248, + 220, + 200, + 36, + 226, + 72, + 166, + 110, + 253, + 142, + 138, + 59, + 134, + 72, + 80, + 85, + 72, + 78, + 123, + 139, + 193, + 43, + 240, + 88, + 233, + 3, + 137, + 6, + 238, + 97, + 158, + 42, + 158, + 229, + 204, + 146, + 185, + 210, + 45, + 181, + 48, + 173, + 142, + 203, + 67, + 131, + 16, + 35, + 204, + 117, + 199, + 141, + 187, + 110, + 75, + 73, + 36, + 208, + 178, + 75, + 65, + 200, + 236, + 42, + 127, + 87, + 255, + 79, + 173, + 244, + 171, + 41, + 123, + 31, + 99, + 77, + 214, + 132, + 68, + 70, + 194, + 236, + 22, + 213, + 170, + 26, + 126, + 200, + 103, + 79, + 115, + 26, + 227, + 121, + 116, + 198, + 124, + 172, + 130, + 110, + 144, + 181, + 59, + 65, + 254, + 168, + 207, + 35, + 86, + 47, + 178, + 30, + 31, + 172, + 107, + 183, + 210, + 217, + 137, + 133, + 58, + 33, + 182, + 181, + 136, + 146, + 213, + 31, + 238, + 108, + 74, + 157, + 64, + 125, + 55, + 193, + 58, + 88, + 114, + 141, + 45, + 142, + 144, + 42, + 208, + 207, + 150, + 16, + 62, + 41, + 214, + 200, + 205, + 6, + 188, + 41, + 198, + 208, + 153, + 25, + 172, + 180, + 173, + 189, + 78, + 191, + 178, + 1, + 82, + 153, + 152, + 61, + 100, + 69, + 33, + 71, + 154, + 24, + 119, + 251, + 85, + 21, + 13, + 216, + 45, + 202, + 231, + 222, + 47, + 84, + 23, + 149, + 129, + 185, + 217, + 215, + 49, + 222, + 205, + 191, + 173, + 182, + 234, + 23, + 106, + 163, + 42, + 39, + 94, + 206, + 82, + 99, + 49, + 232, + 245, + 119, + 187, + 234, + 47, + 126, + 207, + 9, + 85, + 234, + 213, + 71, + 221, + 224, + 113, + 175, + 189, + 74, + 173, + 15, + 131, + 23, + 254, + 13, + 56, + 95, + 18, + 37, + 166, + 80, + 55, + 77, + 254, + 59, + 214, + 197, + 42, + 136, + 46, + 151, + 169, + 52, + 109, + 110, + 112, + 16, + 192, + 59, + 245, + 227, + 16, + 16, + 168, + 173, + 33, + 214, + 196, + 26, + 175, + 17, + 65, + 164, + 176, + 198, + 204, + 147, + 238, + 46, + 57, + 168, + 201, + 45, + 246, + 159, + 190, + 246, + 176, + 21, + 235, + 16, + 249, + 93, + 224, + 197, + 33, + 36, + 241, + 196, + 30, + 50, + 142, + 48, + 235, + 183, + 124, + 157, + 183, + 64, + 196, + 70, + 229, + 134, + 188, + 100, + 239, + 26, + 205, + 248, + 195, + 60, + 253, + 76, + 22, + 59, + 202, + 95, + 206, + 145, + 51, + 144, + 202, + 77, + 69, + 169, + 149, + 146, + 60, + 25, + 231, + 63, + 206, + 165, + 200, + 110, + 149, + 39, + 108, + 87, + 246, + 72, + 51, + 249, + 42, + 0, + 113, + 85, + 50, + 71, + 154, + 10, + 71, + 1, + 88, + 111, + 107, + 91, + 61, + 17, + 173, + 119, + 158, + 216, + 101, + 16, + 153, + 120, + 205, + 182, + 13, + 0, + 230, + 5, + 42, + 67, + 118, + 84, + 241, + 44, + 116, + 246, + 23, + 168, + 98, + 157, + 235, + 6, + 161, + 127, + 235, + 226, + 244, + 87, + 161, + 2, + 84, + 45, + 71, + 181, + 81, + 149, + 119, + 24, + 96, + 215, + 134, + 57, + 140, + 83, + 87, + 177, + 55, + 122, + 75, + 66, + 70, + 0, + 231, + 47, + 22, + 114, + 11, + 36, + 97, + 108, + 96, + 161, + 85, + 112, + 224, + 86, + 83, + 89, + 67, + 80, + 252, + 108, + 88, + 178, + 142, + 64, + 18, + 119, + 159, + 11, + 10, + 132, + 21, + 4, + 124, + 33, + 26, + 246, + 13, + 193, + 3, + 186, + 186, + 109, + 92, + 114, + 178, + 253, + 67, + 217, + 202, + 172, + 38, + 1, + 95, + 192, + 12, + 214, + 198, + 77, + 98, + 221, + 167, + 143, + 131, + 108, + 82, + 7, + 12, + 241, + 6, + 235, + 18, + 102, + 233, + 198, + 227, + 211, + 208, + 193, + 180, + 80, + 142, + 90, + 125, + 212, + 104, + 168, + 75, + 122, + 139, + 83, + 171, + 224, + 158, + 252, + 164, + 41, + 201, + 40, + 234, + 233, + 70, + 45, + 50, + 116, + 28, + 135, + 204, + 211, + 68, + 185, + 181, + 134, + 17, + 79, + 206, + 70, + 211, + 145, + 196, + 46, + 1, + 203, + 106, + 101, + 31, + 105, + 143, + 206, + 64, + 93, + 144, + 130, + 178, + 106, + 155, + 132, + 186, + 238, + 244, + 13, + 241, + 206, + 211, + 224, + 138, + 129, + 27, + 29, + 126, + 95, + 55, + 159, + 71, + 245, + 228, + 43, + 146, + 190, + 147, + 137, + 55, + 0, + 149, + 81, + 57, + 188, + 92, + 26, + 170, + 34, + 22, + 135, + 163, + 138, + 155, + 252, + 51, + 80, + 144, + 134, + 90, + 8, + 254, + 120, + 214, + 198, + 56, + 255, + 75, + 18, + 224, + 3, + 199, + 100, + 188, + 46, + 137, + 244, + 56, + 13, + 103, + 250, + 44, + 41, + 241, + 4, + 82, + 173, + 59, + 252, + 163, + 75, + 195, + 198, + 130, + 153, + 147, + 52, + 104, + 121, + 135, + 196, + 52, + 227, + 250, + 60, + 111, + 123, + 191, + 36, + 238, + 205, + 111, + 121, + 140, + 232, + 111, + 186, + 88, + 157, + 75, + 212, + 78, + 83, + 115, + 180, + 165, + 35, + 101, + 110, + 160, + 212, + 72, + 180, + 24, + 124, + 173, + 89, + 142, + 166, + 192, + 210, + 7, + 31, + 34, + 107, + 176, + 188, + 134, + 163, + 36, + 40, + 237, + 114, + 95, + 79, + 27, + 147, + 85, + 15, + 215, + 22, + 26, + 101, + 126, + 53, + 26, + 242, + 153, + 72, + 207, + 236, + 90, + 253, + 249, + 215, + 233, + 76, + 116, + 25, + 204, + 183, + 222, + 158, + 154, + 114, + 96, + 200, + 148, + 82, + 4, + 31, + 89, + 195, + 196, + 27, + 187, + 200, + 247, + 229, + 32, + 12, + 106, + 14, + 156, + 197, + 243, + 145, + 50, + 203, + 138, + 99, + 38, + 60, + 59, + 178, + 30, + 110, + 105, + 68, + 109, + 6, + 143, + 143, + 108, + 111, + 100, + 66, + 250, + 214, + 18, + 29, + 212, + 91, + 201, + 143, + 12, + 20, + 226, + 213, + 134, + 50, + 38, + 96, + 159, + 168, + 76, + 213, + 126, + 38, + 125, + 80, + 76, + 83, + 98, + 52, + 92, + 184, + 30, + 158, + 81, + 35, + 124, + 155, + 21, + 75, + 25, + 203, + 201, + 170, + 126, + 126, + 221, + 91, + 5, + 173, + 254, + 76, + 145, + 91, + 151, + 211, + 172, + 77, + 181, + 156, + 104, + 81, + 90, + 19, + 28, + 76, + 52, + 5, + 207, + 138, + 182, + 5, + 230, + 73, + 1, + 131, + 15, + 166, + 55, + 67, + 228, + 4, + 28, + 133, + 156, + 240, + 9, + 233, + 108, + 98, + 92, + 126, + 246, + 123, + 91, + 75, + 191, + 208, + 125, + 134, + 152, + 143, + 74, + 59, + 66, + 218, + 181, + 61, + 3, + 86, + 103, + 112, + 29, + 140, + 166, + 223, + 200, + 110, + 195, + 216, + 248, + 90, + 89, + 123, + 244, + 115, + 230, + 81, + 89, + 40, + 59, + 122, + 85, + 9, + 213, + 80, + 235, + 68, + 180, + 107, + 180, + 15, + 186, + 141, + 252, + 14, + 107, + 54, + 26, + 21, + 97, + 111, + 43, + 46, + 172, + 96, + 123, + 100, + 64, + 139, + 101, + 159, + 45, + 238, + 79, + 155, + 76, + 102, + 110, + 79, + 198, + 155, + 59, + 12, + 55, + 160, + 224, + 238, + 58, + 45, + 133, + 198, + 73, + 76, + 246, + 10, + 101, + 130, + 161, + 38, + 179, + 43, + 21, + 86, + 163, + 247, + 111, + 206, + 169, + 4, + 18, + 2, + 205, + 103, + 187, + 15, + 73, + 13, + 103, + 23, + 77, + 193, + 126, + 226, + 73, + 163, + 204, + 120, + 122, + 23, + 163, + 151, + 28, + 122, + 206, + 9, + 42, + 53, + 151, + 136, + 243, + 39, + 71, + 202, + 180, + 103, + 20, + 162, + 202, + 169, + 172, + 76, + 215, + 128, + 184, + 158, + 112, + 145, + 242, + 1, + 143, + 186, + 80, + 106, + 12, + 146, + 57, + 120, + 129, + 16, + 254, + 147, + 93, + 35, + 36, + 228, + 154, + 188, + 60, + 10, + 220, + 67, + 239, + 51, + 47, + 194, + 33, + 238, + 68, + 91, + 101, + 208, + 37, + 48, + 149, + 140, + 195, + 2, + 138, + 46, + 190, + 218, + 136, + 231, + 66, + 43, + 107, + 128, + 72, + 140, + 155, + 16, + 130, + 129, + 245, + 118, + 217, + 41, + 56, + 58, + 130, + 98, + 208, + 201, + 216, + 144, + 44, + 131, + 85, + 46, + 64, + 69, + 74, + 89, + 39, + 251, + 208, + 9, + 122, + 46, + 29, + 66, + 22, + 85, + 145, + 189, + 56, + 218, + 25, + 142, + 22, + 44, + 81, + 208, + 149, + 3, + 216, + 2, + 144, + 154, + 134, + 39, + 138, + 83, + 22, + 165, + 144, + 69, + 1, + 110, + 178, + 137, + 232, + 41, + 44, + 117, + 128, + 55, + 133, + 130, + 216, + 176, + 150, + 133, + 137, + 139, + 121, + 172, + 2, + 199, + 132, + 245, + 13, + 84, + 255, + 41, + 17, + 241, + 91, + 64, + 195, + 61, + 18, + 134, + 132, + 183, + 187, + 177, + 20, + 128, + 35, + 29, + 204, + 181, + 222, + 205, + 170, + 67, + 157, + 110, + 243, + 114, + 160, + 145, + 162, + 1, + 24, + 71, + 89, + 255, + 231, + 81, + 174, + 52, + 221, + 24, + 36, + 190, + 73, + 232, + 60, + 240, + 180, + 29, + 14, + 39, + 57, + 165, + 239, + 206, + 137, + 7, + 162, + 226, + 28, + 230, + 232, + 153, + 148, + 46, + 55, + 40, + 240, + 149, + 104, + 74, + 102, + 97, + 242, + 205, + 167, + 137, + 77, + 254, + 72, + 147, + 70, + 180, + 142, + 92, + 83, + 158, + 57, + 122, + 35, + 203, + 212, + 77, + 215, + 183, + 177, + 179, + 124, + 250, + 34, + 119, + 190, + 71, + 251, + 94, + 114, + 134, + 189, + 255, + 24, + 45, + 159, + 253, + 124, + 208, + 207, + 235, + 6, + 124, + 8, + 68, + 183, + 183, + 36, + 222, + 251, + 152, + 140, + 195, + 126, + 104, + 66, + 140, + 198, + 1, + 143, + 232, + 231, + 96, + 59, + 181, + 21, + 24, + 153, + 95, + 214, + 12, + 75, + 196, + 112, + 212, + 75, + 244, + 117, + 181, + 10, + 183, + 179, + 88, + 3, + 224, + 136, + 157, + 74, + 246, + 102, + 114, + 61, + 52, + 88, + 194, + 51, + 48, + 161, + 29, + 215, + 163, + 235, + 176, + 155, + 49, + 107, + 181, + 113, + 42, + 96, + 130, + 4, + 49, + 215, + 216, + 112, + 102, + 232, + 104, + 143, + 127, + 230, + 23, + 58, + 140, + 47, + 131, + 139, + 179, + 2, + 118, + 68, + 17, + 63, + 9, + 97, + 184, + 25, + 85, + 148, + 239, + 2, + 40, + 221, + 148, + 170, + 38, + 129, + 103, + 26, + 37, + 37, + 174, + 153, + 15, + 90, + 194, + 241, + 29, + 101, + 220, + 138, + 99, + 70, + 254, + 175, + 150, + 97, + 117, + 43, + 175, + 198, + 74, + 172, + 13, + 215, + 220, + 19, + 103, + 156, + 206, + 3, + 208, + 64, + 163, + 239, + 76, + 124, + 90, + 6, + 242, + 204, + 216, + 92, + 1, + 15, + 125, + 224, + 81, + 200, + 184, + 166, + 238, + 138, + 29, + 204, + 56, + 176, + 49, + 56, + 126, + 187, + 7, + 143, + 224, + 229, + 71, + 231, + 25, + 161, + 64, + 240, + 173, + 171, + 57, + 219, + 187, + 114, + 88, + 239, + 10, + 121, + 253, + 95, + 150, + 160, + 41, + 144, + 161, + 217, + 196, + 205, + 146, + 90, + 222, + 201, + 241, + 54, + 219, + 249, + 81, + 240, + 83, + 69, + 193, + 170, + 16, + 179, + 59, + 249, + 210, + 184, + 173, + 194, + 152, + 91, + 45, + 75, + 69, + 162, + 98, + 76, + 108, + 14, + 37, + 195, + 109, + 108, + 171, + 94, + 107, + 159, + 113, + 244, + 97, + 8, + 160, + 235, + 45, + 55, + 3, + 129, + 194, + 224, + 75, + 50, + 255, + 173, + 181, + 27, + 252, + 47, + 92, + 200, + 195, + 165, + 29, + 226, + 72, + 178, + 56, + 96, + 114, + 180, + 108, + 116, + 2, + 182, + 133, + 92, + 195, + 235, + 67, + 19, + 196, + 71, + 100, + 23, + 110, + 69, + 189, + 72, + 198, + 68, + 140, + 94, + 167, + 235, + 110, + 32, + 225, + 69, + 197, + 251, + 50, + 235, + 43, + 15, + 48, + 55, + 207, + 153, + 158, + 74, + 124, + 43, + 23, + 246, + 250, + 149, + 89, + 141, + 218, + 105, + 174, + 31, + 24, + 88, + 184, + 171, + 195, + 164, + 162, + 55, + 50, + 127, + 4, + 215, + 82, + 169, + 140, + 49, + 64, + 212, + 149, + 80, + 123, + 216, + 250, + 172, + 216, + 147, + 195, + 65, + 22, + 176, + 92, + 22, + 95, + 24, + 29, + 38, + 2, + 102, + 186, + 32, + 7, + 221, + 93, + 113, + 66, + 197, + 12, + 203, + 220, + 247, + 168, + 173, + 57, + 60, + 199, + 133, + 148, + 70, + 20, + 70, + 79, + 254, + 229, + 41, + 41, + 234, + 6, + 51, + 108, + 22, + 146, + 187, + 134, + 209, + 203, + 134, + 108, + 85, + 196, + 14, + 69, + 99, + 95, + 93, + 119, + 21, + 83, + 170, + 143, + 84, + 77, + 127, + 146, + 54, + 240, + 192, + 229, + 4, + 24, + 47, + 226, + 121, + 193, + 212, + 0, + 179, + 11, + 69, + 53, + 21, + 67, + 41, + 145, + 233, + 54, + 18, + 171, + 179, + 59, + 163, + 161, + 54, + 76, + 69, + 120, + 233, + 178, + 197, + 137, + 133, + 26, + 37, + 9, + 109, + 31, + 115, + 188, + 61, + 181, + 216, + 31, + 97, + 172, + 7, + 238, + 4, + 134, + 194, + 219, + 126, + 122, + 195, + 152, + 147, + 69, + 136, + 79, + 132, + 135, + 71, + 247, + 139, + 254, + 196, + 149, + 167, + 9, + 90, + 226, + 181, + 230, + 58, + 83, + 56, + 123, + 104, + 169, + 93, + 12, + 105, + 55, + 193, + 25, + 9, + 156, + 228, + 122, + 140, + 56, + 49, + 192, + 83, + 58, + 157, + 115, + 104, + 115, + 165, + 188, + 117, + 74, + 220, + 149, + 186, + 29, + 211, + 53, + 87, + 204, + 90, + 55, + 234, + 233, + 112, + 15, + 121, + 39, + 9, + 232, + 28, + 216, + 22, + 153, + 177, + 144, + 46, + 100, + 175, + 57, + 101, + 170, + 166, + 136, + 147, + 10, + 130, + 37, + 27, + 146, + 238, + 173, + 225, + 109, + 119, + 139, + 160, + 234, + 147, + 72, + 88, + 83, + 199, + 15, + 115, + 32, + 56, + 245, + 124, + 15, + 103, + 156, + 61, + 71, + 130, + 27, + 34, + 33, + 191, + 59, + 50, + 230, + 90, + 227, + 73, + 97, + 209, + 105, + 202, + 217, + 110, + 203, + 253, + 70, + 204, + 168, + 23, + 86, + 32, + 4, + 111, + 225, + 224, + 12, + 184, + 162, + 47, + 115, + 38, + 185, + 211, + 96, + 126, + 249, + 48, + 225, + 255, + 229, + 31, + 231, + 28, + 28, + 96, + 96, + 138, + 124, + 51, + 32, + 47, + 115, + 69, + 100, + 206, + 34, + 59, + 113, + 111, + 8, + 164, + 48, + 119, + 95, + 57, + 25, + 187, + 160, + 24, + 77, + 33, + 157, + 198, + 168, + 169, + 185, + 174, + 195, + 218, + 58, + 31, + 63, + 129, + 39, + 108, + 105, + 47, + 206, + 165, + 231, + 115, + 161, + 254, + 23, + 125, + 34, + 54, + 95, + 176, + 88, + 100, + 212, + 150, + 193, + 153, + 234, + 200, + 61, + 244, + 62, + 50, + 209, + 247, + 82, + 249, + 37, + 159, + 170, + 248, + 231, + 184, + 1, + 172, + 90, + 158, + 112, + 25, + 132, + 97, + 62, + 26, + 117, + 223, + 219, + 37, + 49, + 179, + 178, + 123, + 250, + 112, + 202, + 216, + 21, + 207, + 84, + 238, + 187, + 61, + 108, + 141, + 215, + 199, + 135, + 154, + 240, + 30, + 110, + 57, + 126, + 11, + 80, + 12, + 199, + 101, + 21, + 174, + 173, + 136, + 237, + 237, + 134, + 149, + 248, + 194, + 224, + 133, + 82, + 224, + 188, + 209, + 216, + 135, + 197, + 5, + 148, + 192, + 107, + 118, + 57, + 25, + 61, + 93, + 106, + 44, + 86, + 30, + 13, + 127, + 83, + 252, + 68, + 221, + 6, + 115, + 133, + 208, + 89, + 35, + 74, + 106, + 121, + 117, + 114, + 242, + 2, + 187, + 186, + 216, + 87, + 145, + 144, + 148, + 5, + 253, + 110, + 59, + 89, + 3, + 198, + 58, + 154, + 65, + 86, + 134, + 164, + 249, + 99, + 58, + 111, + 228, + 51, + 191, + 101, + 58, + 223, + 45, + 117, + 17, + 124, + 13, + 140, + 255, + 64, + 168, + 230, + 36, + 14, + 200, + 103, + 170, + 151, + 162, + 199, + 173, + 163, + 226, + 4, + 148, + 72, + 21, + 220, + 26, + 80, + 123, + 88, + 72, + 194, + 57, + 48, + 140, + 75, + 189, + 253, + 55, + 147, + 46, + 39, + 58, + 10, + 121, + 67, + 112, + 199, + 14, + 35, + 243, + 180, + 144, + 26, + 77, + 30, + 120, + 194, + 101, + 131, + 190, + 250, + 210, + 24, + 61, + 7, + 73, + 50, + 228, + 173, + 5, + 20, + 178, + 205, + 240, + 52, + 7, + 141, + 144, + 88, + 37, + 187, + 50, + 110, + 132, + 187, + 47, + 141, + 218, + 193, + 209, + 63, + 237, + 54, + 150, + 164, + 103, + 220, + 23, + 243, + 40, + 87, + 1, + 98, + 14, + 155, + 198, + 2, + 239, + 230, + 35, + 193, + 0, + 130, + 51, + 43, + 168, + 130, + 106, + 73, + 182, + 143, + 37, + 99, + 106, + 136, + 247, + 50, + 78, + 196, + 79, + 243, + 102, + 159, + 124, + 172, + 191, + 114, + 62, + 28, + 20, + 216, + 133, + 110, + 152, + 112, + 183, + 48, + 206, + 52, + 132, + 231, + 237, + 107, + 245, + 101, + 208, + 192, + 11, + 188, + 62, + 211, + 219, + 14, + 69, + 251, + 39, + 148, + 181, + 151, + 186, + 110, + 244, + 172, + 74, + 6, + 17, + 167, + 26, + 5, + 110, + 242, + 156, + 123, + 6, + 162, + 7, + 136, + 22, + 39, + 4, + 22, + 204, + 124, + 173, + 4, + 81, + 20, + 137, + 180, + 9, + 134, + 43, + 109, + 162, + 169, + 232, + 73, + 94, + 100, + 18, + 137, + 82, + 147, + 191, + 63, + 248, + 209, + 18, + 76, + 114, + 189, + 200, + 111, + 160, + 159, + 127, + 156, + 172, + 57, + 7, + 233, + 121, + 119, + 164, + 67, + 91, + 142, + 248, + 121, + 222, + 122, + 120, + 112, + 85, + 47, + 141, + 255, + 28, + 189, + 240, + 247, + 230, + 200, + 176, + 23, + 27, + 119, + 219, + 128, + 189, + 189, + 43, + 232, + 87, + 219, + 60, + 8, + 101, + 6, + 185, + 41, + 86, + 119, + 161, + 213, + 180, + 208, + 182, + 89, + 8, + 238, + 209, + 58, + 165, + 74, + 51, + 125, + 138, + 132, + 152, + 140, + 218, + 19, + 23, + 165, + 119, + 73, + 252, + 83, + 150, + 128, + 65, + 249, + 109, + 234, + 246, + 248, + 213, + 71, + 47, + 143, + 39, + 56, + 137, + 180, + 162, + 103, + 193, + 131, + 16, + 43, + 250, + 81, + 51, + 224, + 209, + 152, + 149, + 204, + 215, + 20, + 143, + 31, + 140, + 26, + 143, + 32, + 67, + 237, + 52, + 132, + 74, + 36, + 84, + 52, + 33, + 173, + 210, + 53, + 174, + 36, + 9, + 66, + 148, + 132, + 139, + 118, + 140, + 173, + 251, + 71, + 204, + 103, + 143, + 239, + 211, + 117, + 225, + 32, + 57, + 192, + 94, + 116, + 21, + 53, + 12, + 95, + 254, + 5, + 3, + 77, + 71, + 76, + 161, + 39, + 46, + 158, + 214, + 131, + 13, + 158, + 192, + 118, + 125, + 47, + 50, + 105, + 171, + 214, + 241, + 15, + 143, + 13, + 198, + 155, + 245, + 73, + 91, + 95, + 214, + 3, + 166, + 245, + 52, + 90, + 93, + 27, + 166, + 113, + 163, + 133, + 21, + 66, + 195, + 251, + 207, + 29, + 154, + 96, + 228, + 122, + 118, + 115, + 149, + 10, + 193, + 253, + 130, + 10, + 168, + 89, + 44, + 178, + 109, + 230, + 96, + 239, + 152, + 229, + 231, + 16, + 210, + 96, + 233, + 128, + 26, + 245, + 54, + 113, + 122, + 105, + 3, + 183, + 10, + 82, + 204, + 125, + 137, + 155, + 242, + 88, + 219, + 123, + 193, + 56, + 18, + 80, + 89, + 25, + 229, + 109, + 113, + 199, + 115, + 210, + 79, + 53, + 151, + 137, + 15, + 51, + 211, + 226, + 246, + 32, + 95, + 7, + 243, + 200, + 122, + 12, + 153, + 56, + 124, + 201, + 16, + 169, + 74, + 199, + 8, + 110, + 15, + 208, + 252, + 228, + 226, + 27, + 156, + 24, + 141, + 178, + 29, + 37, + 242, + 19, + 104, + 185, + 118, + 96, + 99, + 159, + 148, + 222, + 197, + 58, + 192, + 159, + 110, + 131, + 96, + 203, + 187, + 210, + 58, + 79, + 79, + 17, + 131, + 252, + 255, + 162, + 217, + 35, + 9, + 90, + 222, + 2, + 151, + 153, + 181, + 77, + 193, + 130, + 184, + 181, + 48, + 32, + 230, + 184, + 58, + 0, + 52, + 214, + 93, + 230, + 174, + 173, + 128, + 191, + 14, + 42, + 34, + 152, + 78, + 148, + 101, + 83, + 58, + 246, + 94, + 2, + 107, + 80, + 35, + 166, + 220, + 24, + 239, + 52, + 98, + 106, + 1, + 72, + 227, + 209, + 142, + 82, + 145, + 31, + 253, + 14, + 75, + 116, + 242, + 102, + 115, + 169, + 144, + 42, + 4, + 194, + 213, + 1, + 6, + 154, + 181, + 140, + 236, + 33, + 213, + 34, + 60, + 32, + 145, + 95, + 222, + 22, + 2, + 84, + 45, + 219, + 215, + 240, + 227, + 62, + 164, + 254, + 214, + 206, + 164, + 77, + 171, + 209, + 68, + 162, + 202, + 0, + 220, + 52, + 64, + 54, + 125, + 194, + 8, + 122, + 144, + 202, + 157, + 172, + 32, + 114, + 33, + 8, + 141, + 86, + 54, + 69, + 2, + 62, + 42, + 185, + 153, + 21, + 67, + 69, + 49, + 232, + 100, + 131, + 74, + 37, + 218, + 38, + 63, + 45, + 107, + 132, + 251, + 47, + 38, + 53, + 156, + 146, + 248, + 179, + 63, + 126, + 64, + 116, + 128, + 231, + 188, + 42, + 136, + 2, + 59, + 167, + 13, + 98, + 216, + 56, + 119, + 255, + 73, + 212, + 91, + 97, + 43, + 245, + 233, + 186, + 170, + 108, + 94, + 127, + 210, + 201, + 119, + 5, + 197, + 61, + 38, + 125, + 244, + 229, + 132, + 35, + 39, + 188, + 42, + 188, + 178, + 202, + 101, + 8, + 111, + 69, + 158, + 233, + 56, + 175, + 10, + 193, + 142, + 63, + 192, + 103, + 212, + 77, + 36, + 111, + 216, + 2, + 41, + 40, + 75, + 177, + 224, + 99, + 248, + 210, + 31, + 77, + 185, + 195, + 175, + 156, + 133, + 242, + 95, + 243, + 162, + 109, + 96, + 37, + 247, + 92, + 144, + 122, + 88, + 166, + 170, + 200, + 243, + 138, + 103, + 250, + 168, + 238, + 128, + 53, + 213, + 136, + 115, + 53, + 11, + 184, + 5, + 189, + 179, + 65, + 194, + 235, + 233, + 3, + 14, + 149, + 176, + 187, + 97, + 110, + 203, + 201, + 133, + 202, + 240, + 176, + 245, + 32, + 208, + 48, + 227, + 52, + 50, + 150, + 125, + 192, + 38, + 142, + 102, + 11, + 117, + 58, + 208, + 115, + 113, + 253, + 61, + 21, + 203, + 159, + 112, + 220, + 128, + 45, + 191, + 210, + 211, + 174, + 190, + 173, + 211, + 234, + 187, + 29, + 46, + 82, + 96, + 222, + 83, + 225, + 69, + 4, + 180, + 76, + 157, + 6, + 198, + 222, + 64, + 37, + 32, + 135, + 242, + 102, + 63, + 145, + 85, + 161, + 93, + 72, + 42, + 63, + 214, + 162, + 85, + 17, + 148, + 50, + 223, + 197, + 122, + 152, + 146, + 23, + 241, + 14, + 181, + 231, + 104, + 148, + 57, + 122, + 246, + 179, + 150, + 86, + 211, + 173, + 194, + 13, + 76, + 84, + 145, + 172, + 94, + 206, + 9, + 20, + 90, + 86, + 59, + 15, + 250, + 102, + 168, + 55, + 62, + 41, + 150, + 57, + 19, + 68, + 164, + 202, + 73, + 126, + 243, + 247, + 143, + 85, + 148, + 205, + 236, + 22, + 150, + 4, + 59, + 165, + 2, + 52, + 140, + 23, + 65, + 137, + 198, + 41, + 119, + 191, + 161, + 35, + 215, + 15, + 221, + 146, + 137, + 157, + 138, + 208, + 164, + 57, + 97, + 93, + 201, + 149, + 108, + 59, + 174, + 191, + 208, + 172, + 164, + 95, + 133, + 74, + 134, + 85, + 46, + 113, + 128, + 179, + 224, + 46, + 176, + 17, + 225, + 186, + 59, + 57, + 213, + 176, + 212, + 142, + 98, + 139, + 205, + 180, + 138, + 68, + 172, + 39, + 162, + 17, + 42, + 19, + 100, + 99, + 68, + 12, + 58, + 236, + 23, + 140, + 67, + 10, + 92, + 235, + 120, + 173, + 129, + 134, + 115, + 29, + 114, + 115, + 85, + 220, + 60, + 169, + 248, + 0, + 167, + 210, + 111, + 198, + 161, + 16, + 6, + 131, + 1, + 79, + 239, + 138, + 133, + 244, + 67, + 186, + 197, + 108, + 197, + 94, + 170, + 156, + 233, + 50, + 172, + 109, + 147, + 205, + 71, + 191, + 215, + 197, + 35, + 115, + 32, + 219, + 30, + 7, + 87, + 93, + 36, + 139, + 4, + 135, + 66, + 56, + 160, + 47, + 233, + 193, + 13, + 247, + 47, + 182, + 154, + 143, + 239, + 13, + 133, + 84, + 103, + 212, + 127, + 72, + 87, + 202, + 236, + 80, + 98, + 12, + 89, + 192, + 232, + 242, + 105, + 69, + 135, + 153, + 197, + 228, + 132, + 101, + 209, + 253, + 224, + 132, + 173, + 247, + 199, + 101, + 119, + 7, + 133, + 97, + 59, + 91, + 172, + 31, + 158, + 45, + 55, + 105, + 48, + 209, + 222, + 144, + 106, + 187, + 7, + 52, + 250, + 201, + 174, + 172, + 250, + 31, + 53, + 60, + 248, + 242, + 171, + 3, + 151, + 235, + 124, + 180, + 171, + 188, + 59, + 178, + 247, + 93, + 58, + 42, + 154, + 71, + 4, + 61, + 96, + 8, + 103, + 88, + 2, + 106, + 233, + 114, + 230, + 80, + 26, + 26, + 29, + 205, + 178, + 44, + 94, + 188, + 195, + 173, + 246, + 185, + 80, + 211, + 151, + 55, + 188, + 25, + 126, + 199, + 250, + 120, + 78, + 7, + 3, + 96, + 151, + 74, + 119, + 122, + 224, + 249, + 139, + 183, + 144, + 49, + 210, + 115, + 144, + 69, + 238, + 80, + 125, + 226, + 253, + 25, + 198, + 244, + 121, + 20, + 63, + 131, + 197, + 218, + 118, + 92, + 27, + 32, + 228, + 140, + 127, + 39, + 250, + 10, + 196, + 39, + 184, + 0, + 82, + 81, + 7, + 166, + 129, + 64, + 72, + 248, + 29, + 207, + 199, + 103, + 138, + 104, + 107, + 63, + 179, + 43, + 139, + 130, + 222, + 80, + 6, + 138, + 24, + 245, + 132, + 54, + 128, + 212, + 72, + 84, + 33, + 102, + 240, + 129, + 120, + 174, + 184, + 6, + 104, + 183, + 236, + 65, + 53, + 43, + 166, + 6, + 224, + 210, + 229, + 79, + 207, + 251, + 20, + 78, + 113, + 114, + 105, + 187, + 22, + 182, + 7, + 33, + 111, + 189, + 203, + 50, + 158, + 186, + 65, + 248, + 174, + 168, + 80, + 220, + 74, + 21, + 198, + 29, + 42, + 75, + 250, + 75, + 52, + 248, + 249, + 249, + 136, + 90, + 62, + 88, + 40, + 28, + 55, + 71, + 203, + 75, + 197, + 211, + 16, + 187, + 198, + 69, + 218, + 40, + 173, + 120, + 207, + 34, + 130, + 146, + 166, + 61, + 206, + 131, + 24, + 78, + 176, + 227, + 66, + 115, + 113, + 133, + 115, + 106, + 195, + 47, + 161, + 251, + 131, + 43, + 191, + 32, + 220, + 155, + 44, + 230, + 167, + 239, + 251, + 84, + 43, + 106, + 243, + 29, + 98, + 58, + 248, + 127, + 210, + 192, + 25, + 157, + 211, + 13, + 221, + 198, + 119, + 183, + 224, + 64, + 238, + 2, + 99, + 93, + 132, + 176, + 121, + 111, + 185, + 128, + 92, + 106, + 183, + 164, + 17, + 23, + 206, + 176, + 109, + 26, + 81, + 198, + 46, + 12, + 180, + 81, + 148, + 81, + 143, + 193, + 94, + 138, + 174, + 123, + 57, + 124, + 237, + 236, + 197, + 64, + 139, + 134, + 20, + 101, + 83, + 234, + 132, + 253, + 119, + 112, + 1, + 169, + 153, + 249, + 183, + 252, + 13, + 229, + 66, + 194, + 76, + 17, + 119, + 212, + 142, + 37, + 44, + 14, + 45, + 196, + 232, + 139, + 169, + 149, + 115, + 73, + 52, + 247, + 18, + 120, + 166, + 132, + 224, + 207, + 12, + 116, + 7, + 44, + 230, + 51, + 41, + 80, + 76, + 28, + 244, + 122, + 114, + 150, + 137, + 61, + 154, + 78, + 108, + 159, + 20, + 135, + 98, + 78, + 227, + 6, + 246, + 227, + 216, + 189, + 158, + 233, + 78, + 168, + 27, + 94, + 209, + 96, + 192, + 36, + 99, + 86, + 141, + 142, + 235, + 117, + 193, + 251, + 145, + 153, + 37, + 18, + 170, + 86, + 163, + 32, + 155, + 94, + 2, + 54, + 254, + 223, + 132, + 154, + 63, + 247, + 140, + 8, + 57, + 161, + 68, + 12, + 228, + 83, + 137, + 149, + 44, + 248, + 32, + 133, + 145, + 212, + 161, + 7, + 94, + 235, + 239, + 99, + 29, + 160, + 181, + 210, + 166, + 57, + 14, + 139, + 96, + 97, + 134, + 67, + 243, + 100, + 2, + 245, + 235, + 9, + 250, + 118, + 113, + 140, + 56, + 11, + 184, + 193, + 214, + 144, + 169, + 156, + 95, + 74, + 70, + 187, + 6, + 181, + 67, + 14, + 235, + 146, + 118, + 237, + 217, + 39, + 40, + 191, + 116, + 225, + 4, + 109, + 243, + 234, + 233, + 184, + 80, + 74, + 86, + 211, + 141, + 5, + 6, + 142, + 247, + 80, + 216, + 208, + 91, + 150, + 78, + 171, + 18, + 62, + 163, + 48, + 228, + 95, + 221, + 117, + 199, + 137, + 45, + 247, + 211, + 195, + 211, + 129, + 76, + 100, + 26, + 139, + 121, + 111, + 203, + 201, + 83, + 50, + 119, + 231, + 162, + 165, + 20, + 81, + 170, + 184, + 136, + 116, + 226, + 6, + 235, + 229, + 193, + 89, + 210, + 67, + 92, + 246, + 40, + 201, + 172, + 39, + 218, + 35, + 91, + 107, + 29, + 61, + 86, + 27, + 127, + 22, + 65, + 135, + 182, + 0, + 121, + 176, + 111, + 89, + 33, + 105, + 196, + 58, + 57, + 195, + 152, + 49, + 17, + 73, + 128, + 84, + 163, + 103, + 48, + 245, + 180, + 87, + 121, + 102, + 220, + 24, + 64, + 115, + 229, + 88, + 163, + 43, + 10, + 189, + 74, + 232, + 139, + 180, + 55, + 80, + 129, + 45, + 100, + 252, + 241, + 204, + 7, + 39, + 247, + 237, + 21, + 119, + 52, + 146, + 123, + 229, + 11, + 98, + 215, + 31, + 50, + 60, + 170, + 250, + 23, + 226, + 112, + 101, + 0, + 126, + 247, + 11, + 29, + 207, + 12, + 27, + 219, + 255, + 232, + 89, + 160, + 139, + 174, + 173, + 207, + 21, + 251, + 14, + 201, + 20, + 1, + 5, + 196, + 188, + 224, + 159, + 103, + 24, + 249, + 235, + 46, + 87, + 56, + 207, + 203, + 54, + 20, + 214, + 24, + 140, + 98, + 180, + 151, + 42, + 21, + 90, + 8, + 213, + 230, + 34, + 123, + 2, + 166, + 239, + 253, + 61, + 255, + 26, + 62, + 241, + 66, + 170, + 239, + 15, + 218, + 168, + 187, + 9, + 7, + 24, + 85, + 194, + 44, + 45, + 244, + 117, + 180, + 172, + 19, + 50, + 138, + 210, + 69, + 44, + 135, + 149, + 220, + 243, + 126, + 11, + 145, + 48, + 245, + 116, + 223, + 76, + 50, + 209, + 110, + 5, + 77, + 78, + 2, + 119, + 243, + 53, + 11, + 203, + 152, + 170, + 43, + 117, + 31, + 209, + 82, + 29, + 129, + 208, + 67, + 214, + 180, + 234, + 144, + 80, + 206, + 151, + 110, + 53, + 150, + 231, + 139, + 177, + 170, + 12, + 42, + 100, + 245, + 154, + 69, + 85, + 98, + 115, + 48, + 160, + 53, + 212, + 246, + 56, + 57, + 95, + 6, + 42, + 26, + 150, + 244, + 77, + 163, + 195, + 99, + 10, + 133, + 146, + 139, + 15, + 109, + 32, + 199, + 72, + 236, + 184, + 114, + 74, + 155, + 167, + 133, + 96, + 15, + 3, + 96, + 99, + 228, + 150, + 138, + 11, + 76, + 162, + 210, + 162, + 74, + 122, + 117, + 10, + 164, + 1, + 174, + 110, + 105, + 209, + 171, + 183, + 226, + 26, + 150, + 173, + 166, + 205, + 182, + 128, + 166, + 78, + 170, + 38, + 236, + 233, + 131, + 245, + 228, + 127, + 225, + 111, + 10, + 178, + 253, + 216, + 236, + 16, + 234, + 231, + 197, + 1, + 190, + 159, + 216, + 238, + 164, + 159, + 230, + 131, + 64, + 129, + 90, + 176, + 57, + 14, + 131, + 28, + 204, + 120, + 113, + 73, + 98, + 91, + 209, + 1, + 57, + 186, + 53, + 56, + 205, + 225, + 232, + 144, + 216, + 8, + 23, + 233, + 71, + 99, + 167, + 163, + 112, + 221, + 45, + 97, + 3, + 75, + 122, + 93, + 85, + 245, + 56, + 214, + 67, + 15, + 30, + 234, + 204, + 180, + 201, + 60, + 253, + 173, + 250, + 121, + 252, + 173, + 79, + 178, + 46, + 19, + 238, + 207, + 90, + 166, + 252, + 76, + 42, + 111, + 170, + 196, + 203, + 34, + 24, + 49, + 53, + 53, + 163, + 44, + 128, + 108, + 97, + 5, + 118, + 159, + 111, + 154, + 160, + 230, + 60, + 193, + 231, + 184, + 148, + 124, + 162, + 116, + 162, + 174, + 27, + 1, + 92, + 199, + 134, + 90, + 24, + 4, + 115, + 220, + 131, + 249, + 48, + 3, + 206, + 216, + 133, + 186, + 48, + 85, + 13, + 17, + 190, + 219, + 30, + 13, + 96, + 18, + 213, + 33, + 204, + 215, + 38, + 109, + 142, + 99, + 247, + 142, + 149, + 137, + 203, + 30, + 185, + 227, + 166, + 215, + 203, + 230, + 169, + 121, + 198, + 22, + 56, + 39, + 204, + 30, + 244, + 234, + 67, + 34, + 38, + 75, + 95, + 147, + 102, + 66, + 130, + 175, + 144, + 88, + 180, + 91, + 146, + 255, + 60, + 231, + 203, + 65, + 27, + 162, + 70, + 154, + 196, + 167, + 17, + 213, + 44, + 55, + 122, + 236, + 65, + 214, + 200, + 108, + 55, + 134, + 118, + 43, + 127, + 55, + 170, + 147, + 208, + 183, + 152, + 53, + 174, + 64, + 175, + 13, + 168, + 136, + 18, + 186, + 211, + 3, + 78, + 100, + 169, + 173, + 29, + 72, + 31, + 111, + 187, + 44, + 68, + 127, + 116, + 25, + 204, + 97, + 203, + 197, + 238, + 112, + 252, + 235, + 164, + 99, + 246, + 141, + 76, + 161, + 138, + 44, + 143, + 137, + 155, + 53, + 152, + 252, + 213, + 245, + 149, + 73, + 227, + 19, + 87, + 173, + 159, + 13, + 141, + 111, + 9, + 81, + 124, + 57, + 34, + 105, + 250, + 136, + 75, + 30, + 237, + 226, + 109, + 253, + 128, + 212, + 249, + 66, + 94, + 107, + 40, + 183, + 178, + 204, + 219, + 178, + 197, + 238, + 211, + 26, + 143, + 235, + 93, + 233, + 6, + 63, + 236, + 212, + 6, + 165, + 236, + 108, + 62, + 139, + 76, + 91, + 253, + 106, + 92, + 204, + 178, + 237, + 70, + 92, + 235, + 68, + 112, + 197, + 251, + 56, + 234, + 76, + 136, + 204, + 159, + 103, + 234, + 28, + 103, + 253, + 222, + 73, + 227, + 35, + 6, + 141, + 195, + 98, + 175, + 249, + 54, + 93, + 242, + 35, + 85, + 123, + 99, + 132, + 31, + 85, + 239, + 39, + 22, + 41, + 235, + 82, + 35, + 36, + 235, + 153, + 56, + 173, + 215, + 117, + 20, + 179, + 44, + 255, + 142, + 103, + 73, + 80, + 6, + 13, + 243, + 211, + 7, + 172, + 22, + 59, + 107, + 234, + 172, + 251, + 243, + 46, + 127, + 140, + 199, + 173, + 159, + 149, + 144, + 44, + 30, + 93, + 192, + 6, + 5, + 104, + 17, + 25, + 243, + 154, + 147, + 152, + 140, + 163, + 46, + 26, + 122, + 146, + 141, + 121, + 41, + 151, + 184, + 50, + 130, + 19, + 131, + 205, + 219, + 124, + 115, + 225, + 14, + 51, + 49, + 250, + 117, + 226, + 213, + 235, + 29, + 248, + 131, + 179, + 238, + 251, + 38, + 75, + 249, + 130, + 211, + 235, + 239, + 40, + 119, + 37, + 126, + 27, + 145, + 127, + 154, + 37, + 97, + 245, + 87, + 212, + 26, + 128, + 172, + 176, + 49, + 108, + 216, + 85, + 237, + 203, + 56, + 35, + 154, + 133, + 108, + 122, + 232, + 14, + 232, + 137, + 20, + 67, + 189, + 166, + 5, + 76, + 109, + 205, + 169, + 19, + 72, + 79, + 40, + 183, + 177, + 241, + 92, + 108, + 88, + 90, + 147, + 185, + 22, + 190, + 251, + 230, + 106, + 11, + 224, + 169, + 84, + 191, + 174, + 17, + 31, + 233, + 205, + 206, + 216, + 4, + 231, + 226, + 56, + 150, + 140, + 27, + 152, + 51, + 68, + 49, + 126, + 111, + 84, + 116, + 203, + 95, + 114, + 59, + 40, + 209, + 83, + 137, + 62, + 208, + 145, + 1, + 220, + 171, + 142, + 36, + 115, + 252, + 235, + 10, + 38, + 205, + 1, + 65, + 170, + 54, + 5, + 89, + 80, + 240, + 244, + 115, + 57, + 93, + 16, + 225, + 31, + 240, + 7, + 65, + 131, + 224, + 133, + 21, + 192, + 95, + 197, + 15, + 225, + 64, + 100, + 54, + 169, + 201, + 139, + 88, + 255, + 24, + 40, + 145, + 29, + 141, + 104, + 133, + 32, + 172, + 24, + 136, + 187, + 80, + 128, + 31, + 28, + 107, + 244, + 10, + 152, + 155, + 159, + 91, + 229, + 86, + 132, + 175, + 241, + 123, + 13, + 163, + 205, + 250, + 76, + 106, + 117, + 152, + 182, + 72, + 233, + 91, + 166, + 231, + 44, + 176, + 6, + 0, + 218, + 168, + 159, + 6, + 76, + 246, + 58, + 36, + 33, + 66, + 146, + 92, + 6, + 104, + 166, + 52, + 226, + 46, + 159, + 211, + 71, + 187, + 122, + 110, + 189, + 231, + 158, + 45, + 130, + 60, + 7, + 131, + 238, + 252, + 104, + 91, + 198, + 118, + 216, + 99, + 142, + 157, + 92, + 48, + 48, + 15, + 217, + 255, + 61, + 214, + 72, + 225, + 153, + 101, + 148, + 206, + 203, + 12, + 172, + 208, + 201, + 74, + 62, + 201, + 218, + 30, + 177, + 54, + 84, + 207, + 243, + 155, + 37, + 53, + 9, + 136, + 142, + 76, + 11, + 225, + 23, + 57, + 236, + 104, + 42, + 20, + 13, + 7, + 206, + 51, + 82, + 129, + 19, + 214, + 65, + 218, + 243, + 159, + 186, + 8, + 169, + 188, + 2, + 62, + 188, + 187, + 74, + 162, + 33, + 25, + 180, + 99, + 82, + 30, + 200, + 111, + 4, + 242, + 74, + 93, + 211, + 79, + 139, + 10, + 195, + 14, + 187, + 85, + 8, + 214, + 3, + 93, + 124, + 110, + 109, + 59, + 143, + 178, + 75, + 10, + 181, + 173, + 113, + 77, + 208, + 150, + 242, + 44, + 161, + 136, + 111, + 232, + 13, + 239, + 149, + 12, + 236, + 38, + 73, + 14, + 193, + 177, + 6, + 28, + 112, + 227, + 137, + 18, + 22, + 244, + 183, + 101, + 72, + 185, + 189, + 141, + 38, + 176, + 96, + 81, + 253, + 100, + 239, + 73, + 189, + 95, + 103, + 173, + 211, + 169, + 74, + 235, + 144, + 159, + 7, + 18, + 110, + 96, + 65, + 172, + 254, + 89, + 57, + 239, + 113, + 236, + 135, + 66, + 23, + 153, + 208, + 163, + 141, + 139, + 22, + 120, + 245, + 219, + 221, + 87, + 15, + 231, + 137, + 87, + 77, + 72, + 198, + 77, + 137, + 207, + 136, + 170, + 102, + 29, + 51, + 53, + 134, + 24, + 45, + 248, + 168, + 158, + 232, + 156, + 209, + 172, + 125, + 215, + 49, + 97, + 6, + 116, + 121, + 6, + 194, + 142, + 194, + 115, + 57, + 54, + 9, + 243, + 162, + 112, + 142, + 246, + 229, + 15, + 245, + 139, + 175, + 79, + 114, + 94, + 55, + 71, + 100, + 43, + 1, + 156, + 47, + 208, + 11, + 148, + 222, + 112, + 10, + 124, + 153, + 169, + 78, + 11, + 246, + 79, + 250, + 78, + 191, + 159, + 162, + 93, + 21, + 148, + 133, + 182, + 33, + 229, + 9, + 131, + 38, + 1, + 37, + 63, + 156, + 100, + 206, + 162, + 109, + 70, + 27, + 240, + 192, + 72, + 18, + 9, + 87, + 89, + 35, + 25, + 43, + 117, + 97, + 132, + 86, + 7, + 156, + 248, + 60, + 109, + 16, + 246, + 186, + 22, + 199, + 252, + 146, + 111, + 0, + 17, + 173, + 213, + 13, + 107, + 193, + 250, + 49, + 99, + 107, + 203, + 3, + 87, + 141, + 51, + 76, + 228, + 99, + 181, + 33, + 82, + 75, + 145, + 118, + 213, + 32, + 17, + 122, + 243, + 231, + 142, + 120, + 66, + 219, + 204, + 68, + 185, + 3, + 212, + 160, + 0, + 177, + 6, + 50, + 19, + 4, + 199, + 22, + 206, + 215, + 175, + 28, + 7, + 32, + 27, + 14, + 186, + 4, + 135, + 8, + 204, + 143, + 214, + 82, + 89, + 170, + 212, + 62, + 95, + 20, + 254, + 32, + 6, + 165, + 189, + 209, + 214, + 90, + 38, + 120, + 98, + 234, + 106, + 29, + 16, + 175, + 186, + 211, + 185, + 241, + 52, + 233, + 46, + 152, + 116, + 211, + 53, + 32, + 197, + 249, + 217, + 122, + 100, + 53, + 52, + 214, + 215, + 37, + 137, + 119, + 203, + 113, + 73, + 243, + 68, + 245, + 234, + 129, + 156, + 71, + 245, + 218, + 110, + 215, + 136, + 99, + 43, + 207, + 89, + 28, + 245, + 224, + 221, + 104, + 101, + 71, + 37, + 163, + 61, + 141, + 144, + 76, + 37, + 69, + 241, + 215, + 16, + 250, + 246, + 117, + 215, + 140, + 180, + 154, + 167, + 246, + 151, + 221, + 110, + 148, + 143, + 193, + 243, + 195, + 12, + 131, + 66, + 56, + 114, + 253, + 34, + 202, + 11, + 9, + 3, + 249, + 98, + 121, + 202, + 152, + 9, + 36, + 10, + 35, + 117, + 56, + 227, + 110, + 233, + 173, + 208, + 46, + 126, + 204, + 178, + 27, + 28, + 6, + 173, + 193, + 57, + 105, + 213, + 85, + 205, + 189, + 124, + 78, + 252, + 113, + 25, + 133, + 223, + 81, + 202, + 172, + 74, + 63, + 86, + 128, + 228, + 137, + 131, + 41, + 220, + 24, + 232, + 223, + 92, + 236, + 239, + 199, + 110, + 28, + 208, + 119, + 60, + 118, + 218, + 81, + 191, + 104, + 245, + 235, + 127, + 143, + 65, + 11, + 69, + 158, + 177, + 51, + 230, + 10, + 12, + 75, + 166, + 20, + 14, + 5, + 229, + 255, + 172, + 152, + 80, + 239, + 135, + 18, + 238, + 136, + 159, + 213, + 64, + 209, + 245, + 211, + 26, + 103, + 119, + 213, + 237, + 127, + 32, + 6, + 250, + 159, + 220, + 249, + 218, + 151, + 210, + 69, + 25, + 46, + 97, + 251, + 83, + 227, + 234, + 196, + 205, + 140, + 247, + 254, + 155, + 73, + 41, + 94, + 18, + 19, + 134, + 200, + 84, + 11, + 247, + 9, + 35, + 130, + 34, + 205, + 214, + 33, + 174, + 56, + 121, + 200, + 94, + 1, + 96, + 239, + 62, + 80, + 119, + 21, + 51, + 4, + 129, + 92, + 101, + 116, + 131, + 118, + 104, + 112, + 149, + 90, + 99, + 97, + 34, + 5, + 114, + 251, + 91, + 192, + 0, + 177, + 148, + 44, + 124, + 32, + 69, + 129, + 58, + 9, + 156, + 144, + 80, + 58, + 148, + 157, + 214, + 4, + 143, + 131, + 241, + 153, + 57, + 218, + 4, + 119, + 15, + 163, + 81, + 139, + 246, + 10, + 88, + 0, + 49, + 63, + 213, + 97, + 13, + 128, + 31, + 188, + 205, + 159, + 199, + 250, + 147, + 49, + 33, + 97, + 81, + 55, + 49, + 17, + 99, + 28, + 9, + 88, + 97, + 144, + 214, + 118, + 65, + 228, + 214, + 54, + 147, + 220, + 52, + 143, + 8, + 61, + 103, + 54, + 219, + 181, + 70, + 113, + 129, + 29, + 137, + 188, + 218, + 199, + 14, + 249, + 90, + 172, + 232, + 112, + 119, + 81, + 229, + 21, + 55, + 255, + 253, + 53, + 136, + 59, + 157, + 174, + 35, + 228, + 81, + 93, + 2, + 41, + 88, + 205, + 11, + 157, + 85, + 10, + 26, + 92, + 197, + 53, + 129, + 125, + 1, + 141, + 201, + 95, + 59, + 49, + 152, + 121, + 61, + 130, + 61, + 136, + 100, + 86, + 75, + 3, + 255, + 233, + 145, + 241, + 78, + 55, + 78, + 160, + 188, + 228, + 50, + 206, + 190, + 159, + 86, + 181, + 31, + 17, + 87, + 232, + 65, + 209, + 107, + 7, + 115, + 138, + 148, + 102, + 47, + 78, + 106, + 61, + 132, + 42, + 102, + 161, + 56, + 177, + 170, + 255, + 139, + 113, + 115, + 167, + 143, + 142, + 36, + 146, + 10, + 61, + 184, + 65, + 141, + 108, + 155, + 143, + 80, + 73, + 113, + 250, + 96, + 212, + 4, + 208, + 98, + 222, + 171, + 227, + 148, + 111, + 128, + 35, + 217, + 219, + 162, + 83, + 187, + 108, + 25, + 18, + 120, + 242, + 46, + 171, + 55, + 77, + 225, + 200, + 60, + 153, + 232, + 30, + 135, + 87, + 31, + 160, + 2, + 81, + 164, + 115, + 149, + 170, + 177, + 2, + 248, + 80, + 134, + 5, + 247, + 250, + 126, + 0, + 50, + 193, + 239, + 109, + 228, + 140, + 107, + 209, + 160, + 152, + 172, + 20, + 80, + 184, + 1, + 98, + 157, + 18, + 184, + 127, + 22, + 211, + 137, + 168, + 196, + 226, + 244, + 174, + 220, + 17, + 205, + 218, + 209, + 158, + 34, + 148, + 107, + 232, + 239, + 11, + 76, + 165, + 94, + 19, + 175, + 81, + 16, + 180, + 59, + 197, + 2, + 95, + 120, + 38, + 185, + 225, + 198, + 169, + 249, + 217, + 83, + 233, + 170, + 193, + 77, + 73, + 157, + 45, + 9, + 144, + 242, + 125, + 34, + 64, + 70, + 46, + 211, + 251, + 86, + 152, + 130, + 35, + 198, + 187, + 204, + 175, + 72, + 186, + 238, + 36, + 143, + 0, + 182, + 95, + 240, + 12, + 174, + 218, + 104, + 230, + 63, + 118, + 168, + 2, + 81, + 100, + 50, + 63, + 64, + 153, + 58, + 154, + 132, + 24, + 144, + 155, + 29, + 37, + 8, + 221, + 195, + 212, + 72, + 191, + 76, + 126, + 111, + 128, + 158, + 23, + 61, + 177, + 75, + 95, + 111, + 29, + 119, + 212, + 179, + 173, + 246, + 28, + 76, + 192, + 38, + 242, + 220, + 232, + 206, + 200, + 160, + 133, + 138, + 182, + 100, + 55, + 100, + 86, + 208, + 2, + 235, + 84, + 221, + 36, + 226, + 177, + 211, + 196, + 22, + 51, + 141, + 252, + 15, + 6, + 78, + 139, + 14, + 76, + 143, + 67, + 91, + 164, + 119, + 136, + 165, + 132, + 14, + 233, + 70, + 189, + 35, + 170, + 83, + 35, + 115, + 247, + 123, + 68, + 41, + 206, + 150, + 105, + 94, + 106, + 2, + 78, + 74, + 61, + 128, + 251, + 94, + 128, + 136, + 4, + 19, + 169, + 243, + 193, + 33, + 14, + 28, + 122, + 214, + 247, + 179, + 150, + 156, + 125, + 134, + 236, + 89, + 82, + 115, + 69, + 2, + 77, + 253, + 240, + 18, + 38, + 246, + 68, + 22, + 227, + 118, + 40, + 130, + 34, + 147, + 58, + 180, + 175, + 91, + 62, + 215, + 226, + 30, + 105, + 163, + 119, + 63, + 81, + 154, + 34, + 125, + 7, + 216, + 18, + 192, + 75, + 20, + 120, + 239, + 194, + 52, + 172, + 19, + 111, + 140, + 83, + 32, + 69, + 240, + 54, + 191, + 65, + 28, + 109, + 171, + 107, + 220, + 237, + 84, + 85, + 118, + 146, + 46, + 37, + 30, + 105, + 11, + 199, + 90, + 65, + 45, + 155, + 225, + 90, + 3, + 115, + 253, + 53, + 215, + 201, + 97, + 27, + 54, + 13, + 112, + 236, + 102, + 44, + 39, + 92, + 190, + 188, + 241, + 224, + 251, + 8, + 146, + 149, + 229, + 36, + 13, + 147, + 91, + 212, + 81, + 235, + 9, + 92, + 97, + 243, + 135, + 35, + 50, + 177, + 94, + 54, + 134, + 151, + 222, + 78, + 43, + 210, + 60, + 2, + 109, + 91, + 165, + 17, + 70, + 145, + 212, + 201, + 22, + 242, + 38, + 73, + 197, + 243, + 5, + 79, + 78, + 238, + 218, + 236, + 1, + 34, + 162, + 172, + 25, + 203, + 67, + 122, + 36, + 101, + 167, + 221, + 194, + 187, + 20, + 86, + 244, + 137, + 221, + 212, + 103, + 8, + 247, + 236, + 59, + 97, + 24, + 170, + 59, + 94, + 144, + 16, + 248, + 4, + 211, + 182, + 149, + 185, + 124, + 19, + 152, + 89, + 225, + 41, + 248, + 151, + 104, + 62, + 215, + 160, + 128, + 133, + 63, + 147, + 18, + 185, + 212, + 102, + 106, + 17, + 56, + 51, + 149, + 185, + 137, + 185, + 255, + 168, + 96, + 250, + 108, + 138, + 23, + 144, + 233, + 165, + 214, + 64, + 159, + 147, + 147, + 60, + 125, + 164, + 106, + 86, + 153, + 188, + 70, + 26, + 103, + 196, + 193, + 17, + 40, + 91, + 53, + 84, + 83, + 92, + 65, + 20, + 163, + 243, + 138, + 150, + 59, + 221, + 211, + 207, + 93, + 187, + 95, + 102, + 220, + 137, + 108, + 168, + 85, + 44, + 185, + 133, + 208, + 87, + 29, + 35, + 14, + 25, + 38, + 65, + 53, + 136, + 97, + 17, + 44, + 252, + 97, + 157, + 152, + 124, + 115, + 98, + 162, + 176, + 57, + 38, + 221, + 104, + 104, + 34, + 170, + 193, + 120, + 125, + 68, + 133, + 32, + 112, + 240, + 103, + 248, + 60, + 27, + 62, + 135, + 200, + 16, + 183, + 143, + 195, + 28, + 16, + 144, + 131, + 140, + 194, + 144, + 198, + 233, + 19, + 108, + 16, + 109, + 62, + 48, + 123, + 66, + 113, + 188, + 30, + 241, + 232, + 115, + 56, + 147, + 125, + 218, + 155, + 231, + 148, + 67, + 136, + 213, + 35, + 157, + 79, + 85, + 93, + 140, + 158, + 27, + 36, + 2, + 230, + 115, + 178, + 114, + 239, + 193, + 223, + 238, + 173, + 96, + 120, + 163, + 88, + 203, + 190, + 187, + 26, + 99, + 248, + 237, + 66, + 2, + 218, + 71, + 112, + 90, + 189, + 179, + 76, + 154, + 250, + 104, + 73, + 167, + 208, + 116, + 61, + 127, + 110, + 230, + 21, + 216, + 77, + 167, + 236, + 102, + 162, + 134, + 4, + 67, + 195, + 167, + 59, + 157, + 126, + 229, + 27, + 108, + 240, + 176, + 250, + 253, + 41, + 0, + 62, + 147, + 25, + 176, + 14, + 6, + 28, + 109, + 24, + 211, + 227, + 158, + 2, + 22, + 76, + 52, + 21, + 178, + 149, + 251, + 251, + 9, + 97, + 135, + 242, + 62, + 224, + 92, + 46, + 155, + 128, + 16, + 242, + 112, + 212, + 193, + 121, + 226, + 140, + 186, + 219, + 101, + 158, + 82, + 118, + 153, + 247, + 228, + 203, + 6, + 254, + 215, + 151, + 154, + 124, + 83, + 19, + 86, + 227, + 237, + 229, + 194, + 7, + 30, + 141, + 31, + 94, + 191, + 48, + 243, + 173, + 78, + 196, + 174, + 207, + 250, + 24, + 122, + 141, + 245, + 182, + 15, + 63, + 245, + 23, + 19, + 210, + 174, + 3, + 165, + 22, + 230, + 150, + 84, + 107, + 35, + 249, + 143, + 213, + 130, + 52, + 92, + 78, + 82, + 92, + 33, + 109, + 157, + 235, + 133, + 164, + 179, + 188, + 196, + 63, + 68, + 218, + 250, + 198, + 226, + 59, + 183, + 44, + 179, + 119, + 109, + 228, + 2, + 145, + 43, + 67, + 185, + 159, + 208, + 152, + 128, + 240, + 135, + 5, + 16, + 150, + 144, + 116, + 91, + 20, + 58, + 67, + 250, + 178, + 15, + 63, + 208, + 207, + 89, + 173, + 238, + 1, + 219, + 84, + 35, + 64, + 113, + 98, + 14, + 151, + 104, + 245, + 104, + 72, + 57, + 205, + 110, + 159, + 69, + 162, + 101, + 252, + 38, + 161, + 153, + 222, + 133, + 202, + 158, + 207, + 213, + 5, + 209, + 106, + 115, + 96, + 44, + 93, + 189, + 99, + 227, + 41, + 70, + 193, + 140, + 129, + 121, + 93, + 3, + 22, + 108, + 238, + 151, + 10, + 14, + 35, + 73, + 94, + 76, + 123, + 186, + 136, + 134, + 150, + 22, + 126, + 227, + 9, + 10, + 74, + 95, + 74, + 0, + 0, + 26, + 194, + 249, + 230, + 115, + 162, + 252, + 74, + 107, + 57, + 22, + 237, + 184, + 123, + 84, + 166, + 50, + 157, + 39, + 23, + 97, + 31, + 187, + 97, + 148, + 146, + 54, + 54, + 15, + 75, + 24, + 149, + 204, + 161, + 213, + 56, + 186, + 154, + 228, + 253, + 172, + 193, + 44, + 66, + 53, + 171, + 135, + 128, + 111, + 99, + 68, + 93, + 110, + 221, + 106, + 140, + 152, + 132, + 29, + 68, + 224, + 85, + 187, + 49, + 239, + 80, + 76, + 67, + 10, + 145, + 135, + 82, + 203, + 9, + 74, + 140, + 77, + 188, + 224, + 172, + 254, + 131, + 56, + 14, + 88, + 136, + 240, + 96, + 195, + 59, + 82, + 95, + 5, + 148, + 153, + 135, + 165, + 77, + 84, + 126, + 163, + 119, + 21, + 174, + 131, + 178, + 213, + 63, + 107, + 11, + 152, + 250, + 229, + 94, + 228, + 32, + 26, + 152, + 228, + 114, + 154, + 29, + 89, + 27, + 20, + 44, + 17, + 255, + 176, + 212, + 157, + 116, + 8, + 52, + 66, + 84, + 181, + 146, + 157, + 143, + 138, + 188, + 141, + 11, + 231, + 44, + 82, + 81, + 71, + 41, + 231, + 82, + 25, + 157, + 75, + 231, + 16, + 101, + 113, + 233, + 194, + 2, + 207, + 169, + 143, + 76, + 61, + 201, + 75, + 167, + 141, + 43, + 36, + 46, + 234, + 113, + 210, + 149, + 106, + 61, + 161, + 25, + 145, + 171, + 54, + 186, + 109, + 240, + 88, + 102, + 156, + 241, + 182, + 95, + 7, + 110, + 189, + 203, + 176, + 152, + 56, + 116, + 125, + 125, + 219, + 130, + 28, + 123, + 214, + 130, + 146, + 254, + 21, + 77, + 204, + 153, + 122, + 21, + 43, + 99, + 254, + 179, + 104, + 84, + 2, + 51, + 17, + 242, + 244, + 111, + 18, + 214, + 116, + 24, + 127, + 62, + 40, + 116, + 207, + 59, + 251, + 173, + 179, + 189, + 172, + 143, + 44, + 194, + 188, + 173, + 7, + 241, + 84, + 136, + 57, + 140, + 175, + 101, + 249, + 5, + 60, + 39, + 249, + 16, + 25, + 42, + 195, + 20, + 210, + 198, + 20, + 81, + 152, + 176, + 154, + 195, + 96, + 65, + 171, + 81, + 118, + 251, + 77, + 178, + 200, + 50, + 0, + 158, + 210, + 247, + 87, + 24, + 252, + 244, + 102, + 72, + 31, + 128, + 228, + 130, + 133, + 2, + 44, + 141, + 191, + 5, + 219, + 240, + 16, + 0, + 34, + 71, + 99, + 235, + 15, + 70, + 54, + 184, + 140, + 10, + 203, + 155, + 156, + 253, + 39, + 7, + 107, + 132, + 42, + 221, + 170, + 154, + 132, + 66, + 145, + 85, + 45, + 121, + 156, + 53, + 7, + 139, + 11, + 123, + 204, + 32, + 56, + 35, + 202, + 133, + 114, + 120, + 66, + 109, + 35, + 112, + 43, + 121, + 205, + 151, + 184, + 235, + 160, + 181, + 9, + 198, + 24, + 134, + 86, + 242, + 164, + 102, + 40, + 202, + 221, + 7, + 114, + 236, + 30, + 251, + 188, + 116, + 13, + 65, + 95, + 72, + 178, + 61, + 251, + 246, + 39, + 137, + 19, + 50, + 41, + 116, + 143, + 240, + 154, + 94, + 80, + 173, + 89, + 38, + 78, + 3, + 202, + 171, + 97, + 128, + 78, + 205, + 232, + 201, + 6, + 39, + 214, + 122, + 2, + 223, + 122, + 80, + 113, + 27, + 215, + 191, + 144, + 193, + 205, + 23, + 243, + 223, + 185, + 238, + 211, + 87, + 175, + 106, + 230, + 21, + 232, + 182, + 51, + 51, + 255, + 2, + 23, + 74, + 79, + 115, + 8, + 134, + 233, + 150, + 67, + 1, + 179, + 77, + 141, + 62, + 203, + 216, + 178, + 7, + 77, + 41, + 113, + 120, + 14, + 45, + 113, + 116, + 69, + 164, + 8, + 85, + 33, + 19, + 108, + 161, + 93, + 119, + 223, + 208, + 153, + 133, + 13, + 36, + 9, + 255, + 52, + 228, + 117, + 71, + 78, + 246, + 204, + 59, + 125, + 228, + 174, + 253, + 42, + 202, + 245, + 171, + 36, + 208, + 52, + 204, + 197, + 168, + 155, + 108, + 228, + 52, + 126, + 87, + 24, + 53, + 239, + 34, + 248, + 142, + 113, + 53, + 132, + 117, + 235, + 46, + 60, + 7, + 4, + 12, + 86, + 145, + 59, + 79, + 71, + 97, + 144, + 146, + 10, + 67, + 174, + 223, + 189, + 88, + 161, + 2, + 136, + 238, + 168, + 79, + 20, + 172, + 75, + 167, + 218, + 231, + 241, + 9, + 216, + 27, + 107, + 201, + 27, + 213, + 111, + 183, + 115, + 214, + 216, + 32, + 136, + 132, + 167, + 69, + 204, + 94, + 131, + 106, + 163, + 52, + 145, + 243, + 253, + 154, + 142, + 230, + 66, + 169, + 199, + 98, + 57, + 246, + 255, + 210, + 177, + 190, + 14, + 142, + 94, + 85, + 140, + 207, + 240, + 18, + 54, + 87, + 158, + 17, + 64, + 145, + 78, + 16, + 148, + 89, + 15, + 158, + 163, + 52, + 99, + 13, + 142, + 46, + 240, + 243, + 134, + 124, + 177, + 160, + 140, + 140, + 107, + 33, + 79, + 86, + 137, + 73, + 68, + 79, + 241, + 74, + 206, + 162, + 67, + 177, + 188, + 41, + 115, + 215, + 106, + 77, + 31, + 19, + 75, + 67, + 138, + 241, + 54, + 87, + 154, + 0, + 206, + 199, + 47, + 134, + 199, + 161, + 162, + 225, + 174, + 237, + 192, + 69, + 42, + 170, + 64, + 188, + 127, + 232, + 71, + 93, + 81, + 112, + 214, + 246, + 119, + 133, + 12, + 153, + 193, + 104, + 33, + 135, + 180, + 200, + 100, + 169, + 85, + 221, + 88, + 171, + 145, + 173, + 101, + 124, + 208, + 114, + 141, + 20, + 129, + 123, + 252, + 56, + 158, + 0, + 42, + 147, + 94, + 128, + 73, + 75, + 117, + 77, + 25, + 54, + 32, + 85, + 87, + 27, + 108, + 141, + 187, + 3, + 159, + 241, + 135, + 184, + 158, + 128, + 38, + 226, + 122, + 32, + 41, + 108, + 189, + 47, + 168, + 36, + 12, + 231, + 40, + 8, + 179, + 114, + 154, + 20, + 153, + 109, + 10, + 253, + 54, + 99, + 38, + 141, + 171, + 63, + 194, + 56, + 143, + 247, + 221, + 122, + 112, + 8, + 158, + 117, + 148, + 61, + 230, + 175, + 148, + 196, + 114, + 95, + 73, + 156, + 196, + 71, + 127, + 220, + 92, + 186, + 22, + 53, + 148, + 177, + 155, + 10, + 42, + 6, + 54, + 211, + 101, + 9, + 148, + 29, + 219, + 134, + 94, + 77, + 230, + 124, + 65, + 163, + 115, + 99, + 74, + 55, + 205, + 76, + 37, + 55, + 1, + 245, + 148, + 36, + 18, + 185, + 216, + 162, + 242, + 182, + 128, + 172, + 180, + 180, + 227, + 231, + 74, + 94, + 158, + 231, + 248, + 137, + 167, + 18, + 121, + 225, + 11, + 250, + 145, + 243, + 29, + 128, + 33, + 51, + 149, + 24, + 212, + 61, + 8, + 108, + 115, + 212, + 50, + 116, + 180, + 216, + 178, + 187, + 253, + 134, + 145, + 107, + 132, + 33, + 15, + 37, + 32, + 38, + 167, + 173, + 251, + 197, + 102, + 155, + 103, + 189, + 133, + 184, + 225, + 15, + 194, + 201, + 170, + 209, + 131, + 222, + 128, + 178, + 215, + 224, + 169, + 25, + 88, + 188, + 18, + 35, + 191, + 126, + 224, + 32, + 224, + 254, + 7, + 71, + 8, + 0, + 16, + 1, + 141, + 123, + 139, + 231, + 190, + 28, + 105, + 37, + 152, + 226, + 247, + 228, + 186, + 207, + 64, + 53, + 40, + 184, + 104, + 116, + 8, + 174, + 102, + 165, + 76, + 106, + 161, + 10, + 57, + 36, + 45, + 143, + 16, + 194, + 35, + 82, + 24, + 76, + 111, + 207, + 124, + 157, + 56, + 14, + 133, + 160, + 24, + 147, + 223, + 110, + 47, + 231, + 229, + 156, + 225, + 69, + 112, + 46, + 222, + 125, + 120, + 185, + 95, + 121, + 9, + 26, + 211, + 92, + 57, + 190, + 27, + 38, + 246, + 231, + 172, + 142, + 22, + 6, + 47, + 46, + 245, + 4, + 107, + 30, + 126, + 251, + 30, + 26, + 35, + 223, + 140, + 215, + 100, + 126, + 102, + 28, + 225, + 56, + 185, + 192, + 233, + 70, + 206, + 188, + 141, + 30, + 74, + 9, + 161, + 38, + 96, + 25, + 85, + 163, + 157, + 228, + 192, + 29, + 47, + 220, + 3, + 57, + 8, + 174, + 111, + 65, + 27, + 202, + 70, + 153, + 19, + 217, + 36, + 220, + 169, + 175, + 167, + 12, + 239, + 26, + 122, + 112, + 188, + 33, + 192, + 54, + 160, + 72, + 156, + 83, + 152, + 16, + 26, + 88, + 133, + 146, + 146, + 218, + 66, + 29, + 35, + 179, + 206, + 68, + 138, + 156, + 235, + 41, + 87, + 161, + 2, + 156, + 32, + 180, + 84, + 72, + 233, + 247, + 71, + 137, + 80, + 236, + 102, + 58, + 70, + 182, + 29, + 100, + 96, + 252, + 84, + 32, + 64, + 235, + 233, + 36, + 173, + 119, + 251, + 82, + 19, + 74, + 202, + 10, + 220, + 3, + 173, + 129, + 239, + 245, + 12, + 159, + 168, + 41, + 87, + 126, + 196, + 219, + 90, + 14, + 135, + 104, + 45, + 94, + 55, + 188, + 3, + 132, + 145, + 242, + 125, + 40, + 165, + 30, + 190, + 47, + 59, + 22, + 9, + 133, + 151, + 220, + 192, + 221, + 121, + 20, + 167, + 38, + 80, + 74, + 131, + 37, + 152, + 99, + 105, + 38, + 29, + 232, + 108, + 158, + 7, + 6, + 155, + 123, + 135, + 6, + 206, + 181, + 29, + 146, + 86, + 132, + 109, + 26, + 252, + 92, + 120, + 240, + 48, + 141, + 226, + 126, + 4, + 242, + 247, + 52, + 88, + 40, + 91, + 217, + 135, + 50, + 52, + 204, + 48, + 88, + 223, + 164, + 246, + 252, + 89, + 164, + 232, + 5, + 80, + 1, + 148, + 214, + 250, + 201, + 40, + 66, + 204, + 73, + 35, + 41, + 149, + 215, + 33, + 241, + 14, + 222, + 16, + 175, + 247, + 165, + 184, + 38, + 133, + 199, + 232, + 156, + 238, + 2, + 51, + 233, + 161, + 189, + 108, + 184, + 99, + 44, + 145, + 88, + 127, + 127, + 225, + 251, + 54, + 210, + 66, + 39, + 164, + 97, + 232, + 184, + 121, + 5, + 160, + 64, + 36, + 21, + 103, + 36, + 108, + 129, + 204, + 138, + 183, + 186, + 163, + 49, + 44, + 123, + 88, + 200, + 93, + 221, + 137, + 9, + 216, + 51, + 115, + 105, + 199, + 52, + 197, + 129, + 56, + 17, + 203, + 0, + 241, + 237, + 195, + 127, + 107, + 45, + 123, + 56, + 231, + 23, + 145, + 41, + 183, + 237, + 137, + 58, + 3, + 245, + 58, + 24, + 167, + 41, + 66, + 142, + 106, + 165, + 247, + 45, + 172, + 223, + 118, + 37, + 64, + 149, + 176, + 126, + 240, + 100, + 44, + 81, + 190, + 20, + 238, + 107, + 57, + 116, + 213, + 147, + 176, + 12, + 83, + 38, + 129, + 131, + 70, + 112, + 191, + 102, + 46, + 76, + 65, + 189, + 250, + 73, + 140, + 136, + 243, + 143, + 52, + 120, + 175, + 181, + 9, + 107, + 193, + 83, + 246, + 75, + 226, + 141, + 184, + 21, + 248, + 45, + 82, + 140, + 65, + 87, + 253, + 73, + 230, + 241, + 2, + 142, + 141, + 211, + 30, + 41, + 41, + 14, + 110, + 215, + 93, + 92, + 211, + 152, + 55, + 185, + 9, + 105, + 58, + 76, + 255, + 251, + 49, + 7, + 156, + 85, + 78, + 204, + 65, + 33, + 46, + 112, + 4, + 45, + 121, + 80, + 178, + 73, + 147, + 230, + 36, + 193, + 92, + 186, + 174, + 13, + 221, + 159, + 227, + 146, + 20, + 60, + 185, + 194, + 161, + 80, + 158, + 119, + 16, + 63, + 88, + 216, + 248, + 189, + 72, + 31, + 11, + 73, + 156, + 62, + 71, + 204, + 213, + 215, + 149, + 177, + 156, + 82, + 5, + 78, + 1, + 228, + 150, + 88, + 23, + 254, + 87, + 203, + 94, + 19, + 93, + 32, + 133, + 212, + 109, + 188, + 204, + 79, + 167, + 185, + 148, + 243, + 28, + 142, + 137, + 185, + 120, + 169, + 112, + 72, + 27, + 177, + 118, + 121, + 91, + 48, + 103, + 222, + 246, + 166, + 26, + 101, + 107, + 120, + 221, + 180, + 51, + 162, + 26, + 127, + 74, + 23, + 63, + 34, + 11, + 97, + 101, + 140, + 141, + 43, + 134, + 29, + 141, + 39, + 250, + 227, + 136, + 244, + 124, + 189, + 18, + 111, + 164, + 48, + 54, + 202, + 113, + 151, + 13, + 217, + 233, + 50, + 87, + 251, + 2, + 252, + 178, + 106, + 22, + 235, + 183, + 250, + 76, + 3, + 201, + 11, + 126, + 61, + 146, + 38, + 12, + 179, + 140, + 48, + 165, + 209, + 26, + 105, + 131, + 63, + 121, + 111, + 203, + 136, + 240, + 44, + 123, + 233, + 142, + 28, + 132, + 57, + 186, + 13, + 148, + 200, + 191, + 197, + 61, + 174, + 15, + 205, + 10, + 128, + 140, + 33, + 211, + 47, + 27, + 107, + 99, + 179, + 112, + 83, + 204, + 93, + 142, + 251, + 233, + 6, + 253, + 68, + 10, + 162, + 185, + 106, + 183, + 20, + 74, + 33, + 237, + 85, + 103, + 194, + 215, + 171, + 215, + 125, + 206, + 68, + 32, + 135, + 241, + 124, + 57, + 189, + 24, + 131, + 113, + 156, + 158, + 153, + 142, + 242, + 92, + 224, + 86, + 197, + 35, + 173, + 48, + 183, + 209, + 59, + 252, + 181, + 1, + 98, + 36, + 97, + 193, + 201, + 71, + 87, + 166, + 254, + 47, + 184, + 19, + 212, + 13, + 173, + 108, + 80, + 120, + 109, + 99, + 168, + 101, + 136, + 27, + 114, + 68, + 9, + 107, + 228, + 123, + 120, + 196, + 162, + 82, + 28, + 41, + 171, + 82, + 193, + 204, + 147, + 131, + 68, + 122, + 97, + 99, + 111, + 70, + 31, + 94, + 6, + 214, + 164, + 8, + 125, + 67, + 184, + 105, + 147, + 144, + 53, + 234, + 105, + 7, + 76, + 150, + 52, + 220, + 117, + 106, + 157, + 81, + 214, + 212, + 74, + 144, + 174, + 73, + 238, + 9, + 137, + 111, + 163, + 222, + 129, + 233, + 33, + 170, + 246, + 207, + 189, + 177, + 86, + 57, + 12, + 80, + 37, + 218, + 213, + 250, + 198, + 79, + 199, + 160, + 81, + 160, + 182, + 182, + 98, + 39, + 153, + 116, + 198, + 193, + 45, + 162, + 110, + 39, + 120, + 213, + 199, + 143, + 175, + 151, + 24, + 220, + 210, + 13, + 231, + 178, + 252, + 172, + 92, + 14, + 36, + 128, + 159, + 47, + 194, + 46, + 197, + 70, + 39, + 41, + 234, + 109, + 213, + 127, + 4, + 10, + 75, + 136, + 232, + 227, + 203, + 96, + 136, + 89, + 218, + 130, + 207, + 58, + 105, + 139, + 98, + 11, + 102, + 17, + 244, + 116, + 224, + 171, + 49, + 167, + 176, + 72, + 51, + 77, + 143, + 142, + 54, + 87, + 17, + 77, + 129, + 181, + 67, + 104, + 172, + 23, + 59, + 136, + 132, + 138, + 206, + 22, + 61, + 28, + 174, + 236, + 188, + 97, + 149, + 11, + 246, + 236, + 210, + 241, + 141, + 181, + 88, + 69, + 89, + 86, + 146, + 52, + 30, + 74, + 79, + 166, + 182, + 87, + 96, + 255, + 122, + 62, + 233, + 57, + 208, + 46, + 5, + 80, + 198, + 189, + 44, + 240, + 156, + 222, + 10, + 91, + 195, + 204, + 254, + 233, + 59, + 228, + 224, + 39, + 73, + 89, + 196, + 166, + 30, + 47, + 109, + 245, + 245, + 96, + 45, + 224, + 145, + 39, + 17, + 159, + 52, + 195, + 112, + 4, + 35, + 250, + 157, + 99, + 191, + 151, + 80, + 13, + 103, + 164, + 177, + 7, + 246, + 49, + 85, + 120, + 239, + 217, + 247, + 35, + 208, + 203, + 122, + 24, + 229, + 101, + 96, + 218, + 173, + 109, + 27, + 217, + 137, + 17, + 239, + 162, + 44, + 112, + 235, + 73, + 222, + 147, + 61, + 120, + 147, + 18, + 232, + 101, + 167, + 131, + 26, + 113, + 179, + 193, + 60, + 145, + 36, + 88, + 177, + 108, + 20, + 141, + 254, + 32, + 80, + 238, + 25, + 98, + 230, + 214, + 196, + 80, + 95, + 135, + 26, + 248, + 36, + 214, + 72, + 253, + 93, + 65, + 108, + 140, + 150, + 167, + 173, + 242, + 151, + 34, + 218, + 111, + 221, + 77, + 39, + 62, + 86, + 180, + 237, + 95, + 250, + 172, + 102, + 133, + 241, + 11, + 140, + 161, + 29, + 204, + 216, + 38, + 168, + 77, + 192, + 136, + 14, + 160, + 198, + 6, + 157, + 64, + 183, + 184, + 88, + 235, + 155, + 106, + 106, + 108, + 66, + 50, + 184, + 46, + 64, + 37, + 193, + 27, + 244, + 99, + 73, + 246, + 52, + 135, + 198, + 72, + 20, + 120, + 8, + 71, + 19, + 185, + 104, + 44, + 191, + 97, + 113, + 213, + 153, + 245, + 157, + 171, + 171, + 247, + 34, + 104, + 141, + 191, + 7, + 127, + 7, + 60, + 30, + 200, + 218, + 224, + 62, + 214, + 95, + 33, + 11, + 211, + 94, + 253, + 63, + 9, + 233, + 151, + 126, + 26, + 213, + 209, + 173, + 151, + 59, + 94, + 218, + 165, + 110, + 148, + 211, + 90, + 64, + 221, + 136, + 123, + 38, + 188, + 30, + 153, + 17, + 20, + 114, + 149, + 192, + 69, + 47, + 40, + 210, + 27, + 93, + 97, + 147, + 67, + 219, + 77, + 91, + 61, + 54, + 212, + 85, + 227, + 214, + 209, + 178, + 222, + 114, + 150, + 27, + 88, + 34, + 83, + 204, + 154, + 253, + 101, + 100, + 141, + 132, + 62, + 178, + 52, + 226, + 111, + 101, + 160, + 143, + 167, + 69, + 68, + 152, + 150, + 209, + 184, + 163, + 0, + 120, + 184, + 83, + 114, + 5, + 31, + 199, + 196, + 110, + 128, + 49, + 174, + 75, + 104, + 74, + 49, + 30, + 171, + 143, + 104, + 9, + 216, + 207, + 24, + 244, + 152, + 202, + 237, + 157, + 124, + 252, + 181, + 94, + 76, + 215, + 1, + 145, + 234, + 228, + 160, + 91, + 89, + 71, + 64, + 248, + 77, + 110, + 29, + 112, + 216, + 222, + 140, + 212, + 101, + 228, + 194, + 111, + 34, + 129, + 159, + 117, + 139, + 221, + 238, + 253, + 187, + 253, + 19, + 217, + 221, + 208, + 5, + 99, + 23, + 44, + 75, + 73, + 42, + 7, + 42, + 183, + 168, + 15, + 152, + 174, + 101, + 185, + 168, + 232, + 77, + 9, + 97, + 121, + 40, + 12, + 99, + 136, + 154, + 223, + 83, + 132, + 50, + 237, + 253, + 162, + 25, + 84, + 225, + 32, + 145, + 201, + 52, + 70, + 141, + 199, + 153, + 248, + 145, + 60, + 27, + 132, + 72, + 66, + 231, + 228, + 220, + 30, + 153, + 111, + 177, + 163, + 215, + 137, + 39, + 140, + 188, + 107, + 118, + 21, + 150, + 237, + 29, + 239, + 5, + 0, + 177, + 248, + 230, + 184, + 138, + 63, + 29, + 180, + 2, + 238, + 86, + 91, + 204, + 37, + 125, + 228, + 101, + 196, + 176, + 86, + 1, + 53, + 33, + 64, + 198, + 188, + 171, + 129, + 53, + 48, + 40, + 156, + 96, + 40, + 164, + 225, + 110, + 202, + 208, + 217, + 186, + 180, + 3, + 61, + 150, + 135, + 98, + 67, + 89, + 115, + 148, + 16, + 174, + 111, + 221, + 185, + 40, + 90, + 52, + 226, + 142, + 164, + 100, + 200, + 24, + 245, + 197, + 96, + 241, + 217, + 63, + 23, + 233, + 111, + 132, + 60, + 87, + 159, + 159, + 29, + 184, + 233, + 116, + 142, + 100, + 127, + 177, + 26, + 218, + 196, + 20, + 102, + 3, + 108, + 102, + 161, + 17, + 42, + 139, + 236, + 174, + 105, + 121, + 119, + 89, + 146, + 18, + 12, + 78, + 101, + 208, + 197, + 114, + 233, + 57, + 3, + 47, + 159, + 125, + 79, + 173, + 86, + 167, + 45, + 27, + 217, + 96, + 163, + 48, + 15, + 250, + 85, + 201, + 106, + 58, + 245, + 196, + 156, + 254, + 134, + 152, + 72, + 33, + 211, + 40, + 11, + 65, + 146, + 53, + 124, + 58, + 59, + 119, + 46, + 133, + 230, + 19, + 20, + 35, + 184, + 51, + 244, + 125, + 173, + 13, + 89, + 221, + 245, + 239, + 231, + 113, + 92, + 66, + 196, + 3, + 10, + 54, + 0, + 101, + 160, + 229, + 17, + 41, + 216, + 144, + 153, + 124, + 222, + 67, + 119, + 23, + 130, + 207, + 227, + 211, + 111, + 89, + 226, + 120, + 249, + 64, + 247, + 155, + 236, + 140, + 97, + 103, + 129, + 86, + 244, + 36, + 98, + 107, + 80, + 8, + 34, + 185, + 201, + 254, + 250, + 98, + 136, + 115, + 83, + 5, + 157, + 134, + 105, + 131, + 125, + 66, + 147, + 149, + 169, + 51, + 102, + 158, + 101, + 169, + 201, + 86, + 133, + 211, + 127, + 141, + 12, + 9, + 48, + 116, + 60, + 118, + 120, + 136, + 171, + 82, + 11, + 24, + 123, + 33, + 142, + 117, + 151, + 77, + 90, + 243, + 66, + 36, + 29, + 204, + 235, + 67, + 72, + 33, + 224, + 172, + 99, + 242, + 153, + 209, + 245, + 165, + 113, + 46, + 219, + 130, + 2, + 43, + 7, + 143, + 190, + 155, + 24, + 142, + 41, + 42, + 107, + 170, + 247, + 238, + 33, + 183, + 190, + 65, + 54, + 243, + 84, + 0, + 29, + 112, + 195, + 62, + 231, + 165, + 116, + 233, + 180, + 197, + 148, + 8, + 216, + 121, + 91, + 107, + 248, + 155, + 192, + 49, + 37, + 214, + 232, + 120, + 172, + 32, + 183, + 99, + 41, + 243, + 67, + 90, + 195, + 202, + 42, + 93, + 82, + 203, + 53, + 66, + 95, + 211, + 4, + 17, + 210, + 40, + 69, + 0, + 21, + 40, + 171, + 130, + 42, + 43, + 133, + 167, + 158, + 40, + 73, + 33, + 242, + 206, + 105, + 90, + 103, + 29, + 236, + 111, + 140, + 14, + 65, + 133, + 11, + 103, + 217, + 109, + 68, + 126, + 119, + 110, + 233, + 237, + 14, + 44, + 157, + 61, + 9, + 166, + 45, + 114, + 215, + 213, + 66, + 52, + 75, + 14, + 21, + 152, + 190, + 47, + 68, + 67, + 239, + 171, + 237, + 161, + 217, + 68, + 37, + 89, + 61, + 84, + 165, + 196, + 8, + 178, + 102, + 174, + 60, + 207, + 168, + 11, + 237, + 196, + 179, + 208, + 249, + 51, + 201, + 82, + 153, + 112, + 59, + 182, + 8, + 114, + 97, + 83, + 202, + 75, + 173, + 208, + 92, + 151, + 86, + 37, + 15, + 142, + 172, + 201, + 154, + 231, + 247, + 158, + 27, + 84, + 181, + 72, + 239, + 9, + 119, + 231, + 0, + 166, + 209, + 121, + 100, + 50, + 196, + 170, + 95, + 3, + 148, + 127, + 166, + 155, + 157, + 155, + 157, + 245, + 191, + 219, + 11, + 185, + 153, + 254, + 240, + 184, + 10, + 87, + 192, + 89, + 102, + 38, + 249, + 103, + 161, + 125, + 179, + 179, + 142, + 238, + 230, + 96, + 1, + 79, + 240, + 122, + 126, + 253, + 112, + 101, + 233, + 171, + 218, + 102, + 207, + 199, + 156, + 199, + 40, + 174, + 172, + 90, + 255, + 28, + 108, + 48, + 192, + 11, + 69, + 58, + 217, + 71, + 0, + 99, + 50, + 11, + 121, + 104, + 202, + 76, + 132, + 226, + 254, + 241, + 75, + 74, + 149, + 227, + 153, + 96, + 39, + 160, + 116, + 216, + 223, + 162, + 77, + 31, + 91, + 132, + 170, + 226, + 115, + 155, + 145, + 5, + 153, + 29, + 167, + 67, + 156, + 28, + 165, + 48, + 165, + 52, + 220, + 77, + 131, + 31, + 177, + 219, + 48, + 88, + 203, + 211, + 147, + 73, + 52, + 65, + 112, + 219, + 194, + 219, + 32, + 135, + 131, + 49, + 97, + 244, + 139, + 103, + 218, + 124, + 250, + 34, + 255, + 65, + 187, + 128, + 112, + 20, + 245, + 93, + 163, + 183, + 51, + 197, + 145, + 149, + 75, + 82, + 145, + 50, + 184, + 19, + 23, + 33, + 142, + 4, + 191, + 6, + 31, + 159, + 132, + 43, + 192, + 136, + 79, + 106, + 49, + 76, + 88, + 122, + 172, + 204, + 253, + 63, + 23, + 101, + 141, + 73, + 216, + 43, + 29, + 212, + 197, + 150, + 178, + 37, + 15, + 107, + 12, + 7, + 227, + 240, + 123, + 144, + 167, + 225, + 17, + 246, + 72, + 5, + 8, + 52, + 114, + 23, + 50, + 183, + 225, + 168, + 168, + 198, + 67, + 66, + 104, + 30, + 82, + 65, + 183, + 223, + 65, + 94, + 134, + 128, + 13, + 19, + 183, + 71, + 105, + 121, + 19, + 164, + 220, + 120, + 24, + 6, + 160, + 124, + 189, + 209, + 208, + 84, + 209, + 69, + 74, + 133, + 199, + 250, + 163, + 211, + 254, + 166, + 74, + 4, + 28, + 47, + 194, + 56, + 194, + 132, + 55, + 235, + 92, + 218, + 176, + 142, + 215, + 155, + 225, + 85, + 84, + 249, + 119, + 43, + 78, + 117, + 94, + 188, + 97, + 18, + 54, + 16, + 12, + 222, + 21, + 10, + 14, + 202, + 44, + 170, + 227, + 196, + 183, + 156, + 247, + 228, + 38, + 30, + 207, + 182, + 218, + 5, + 131, + 175, + 85, + 180, + 201, + 189, + 90, + 104, + 177, + 47, + 47, + 177, + 86, + 124, + 107, + 44, + 184, + 139, + 148, + 106, + 39, + 59, + 224, + 113, + 33, + 14, + 163, + 227, + 215, + 101, + 183, + 144, + 184, + 225, + 246, + 99, + 163, + 97, + 211, + 217, + 12, + 219, + 235, + 252, + 223, + 92, + 252, + 8, + 154, + 143, + 35, + 213, + 253, + 223, + 161, + 88, + 13, + 208, + 218, + 50, + 243, + 214, + 82, + 52, + 22, + 7, + 5, + 185, + 156, + 163, + 89, + 165, + 207, + 207, + 175, + 93, + 20, + 25, + 57, + 33, + 193, + 190, + 243, + 34, + 36, + 68, + 234, + 224, + 172, + 34, + 36, + 31, + 236, + 228, + 31, + 66, + 192, + 161, + 133, + 53, + 30, + 34, + 2, + 3, + 199, + 200, + 60, + 127, + 78, + 112, + 25, + 20, + 249, + 60, + 25, + 211, + 78, + 42, + 223, + 90, + 129, + 201, + 240, + 244, + 151, + 252, + 113, + 208, + 39, + 234, + 144, + 91, + 157, + 190, + 71, + 119, + 217, + 33, + 101, + 230, + 152, + 243, + 1, + 102, + 95, + 162, + 62, + 28, + 203, + 175, + 112, + 42, + 217, + 228, + 131, + 120, + 99, + 213, + 15, + 14, + 226, + 144, + 103, + 19, + 15, + 127, + 128, + 190, + 108, + 145, + 166, + 104, + 239, + 73, + 6, + 29, + 26, + 202, + 224, + 34, + 172, + 158, + 187, + 78, + 238, + 223, + 74, + 41, + 68, + 56, + 179, + 145, + 252, + 182, + 2, + 27, + 113, + 141, + 210, + 176, + 184, + 18, + 47, + 181, + 250, + 15, + 166, + 109, + 164, + 142, + 53, + 72, + 3, + 185, + 222, + 96, + 183, + 255, + 177, + 233, + 94, + 228, + 141, + 150, + 213, + 239, + 80, + 252, + 97, + 221, + 29, + 59, + 240, + 51, + 197, + 223, + 22, + 157, + 53, + 50, + 89, + 93, + 221, + 61, + 49, + 112, + 144, + 248, + 182, + 226, + 124, + 119, + 36, + 38, + 99, + 79, + 226, + 75, + 86, + 64, + 223, + 148, + 127, + 228, + 107, + 193, + 168, + 72, + 19, + 164, + 36, + 1, + 186, + 44, + 103, + 150, + 155, + 192, + 1, + 75, + 18, + 174, + 255, + 90, + 159, + 116, + 139, + 197, + 84, + 146, + 97, + 109, + 117, + 96, + 29, + 79, + 195, + 20, + 225, + 12, + 225, + 163, + 69, + 67, + 50, + 157, + 211, + 15, + 92, + 79, + 230, + 2, + 254, + 24, + 233, + 150, + 195, + 110, + 229, + 169, + 76, + 125, + 193, + 21, + 88, + 2, + 120, + 207, + 74, + 71, + 135, + 93, + 117, + 119, + 50, + 17, + 81, + 185, + 151, + 157, + 243, + 6, + 125, + 104, + 32, + 125, + 199, + 45, + 226, + 2, + 144, + 251, + 72, + 0, + 143, + 59, + 132, + 69, + 216, + 169, + 211, + 72, + 102, + 164, + 108, + 75, + 133, + 73, + 212, + 51, + 164, + 203, + 234, + 204, + 242, + 74, + 120, + 92, + 154, + 82, + 104, + 161, + 153, + 21, + 221, + 95, + 246, + 238, + 17, + 41, + 225, + 178, + 160, + 149, + 5, + 237, + 2, + 144, + 187, + 7, + 17, + 187, + 124, + 67, + 175, + 178, + 162, + 129, + 178, + 113, + 204, + 23, + 54, + 213, + 181, + 183, + 224, + 90, + 27, + 206, + 77, + 139, + 209, + 114, + 32, + 10, + 81, + 42, + 52, + 159, + 178, + 60, + 63, + 178, + 0, + 99, + 216, + 123, + 31, + 154, + 81, + 65, + 184, + 156, + 230, + 77, + 151, + 180, + 55, + 64, + 71, + 226, + 116, + 198, + 109, + 179, + 61, + 202, + 110, + 236, + 239, + 159, + 52, + 26, + 78, + 48, + 96, + 20, + 55, + 39, + 107, + 5, + 247, + 244, + 105, + 166, + 62, + 157, + 252, + 10, + 183, + 18, + 191, + 210, + 222, + 117, + 126, + 36, + 200, + 160, + 226, + 216, + 155, + 106, + 178, + 102, + 114, + 36, + 147, + 219, + 243, + 15, + 120, + 94, + 161, + 109, + 60, + 169, + 176, + 244, + 50, + 60, + 63, + 227, + 52, + 180, + 186, + 14, + 232, + 244, + 99, + 73, + 20, + 39, + 245, + 146, + 117, + 25, + 61, + 184, + 255, + 46, + 124, + 151, + 159, + 240, + 69, + 215, + 175, + 26, + 208, + 84, + 28, + 148, + 27, + 164, + 39, + 240, + 180, + 109, + 96, + 71, + 152, + 252, + 197, + 168, + 48, + 5, + 51, + 50, + 147, + 169, + 206, + 37, + 41, + 192, + 83, + 48, + 233, + 246, + 143, + 80, + 247, + 53, + 97, + 230, + 126, + 219, + 49, + 247, + 130, + 186, + 9, + 112, + 41, + 140, + 122, + 74, + 162, + 248, + 149, + 110, + 99, + 195, + 72, + 48, + 141, + 208, + 179, + 34, + 179, + 3, + 5, + 13, + 212, + 139, + 161, + 120, + 95, + 64, + 85, + 60, + 117, + 212, + 88, + 201, + 153, + 10, + 163, + 130, + 221, + 200, + 227, + 74, + 82, + 207, + 224, + 126, + 126, + 27, + 57, + 234, + 150, + 181, + 112, + 109, + 247, + 161, + 56, + 68, + 55, + 119, + 64, + 25, + 182, + 183, + 243, + 129, + 185, + 148, + 243, + 248, + 169, + 228, + 135, + 106, + 51, + 75, + 13, + 133, + 37, + 199, + 133, + 160, + 50, + 38, + 181, + 63, + 115, + 114, + 65, + 9, + 135, + 160, + 250, + 101, + 255, + 125, + 13, + 251, + 199, + 120, + 104, + 97, + 30, + 11, + 228, + 87, + 82, + 81, + 117, + 154, + 197, + 106, + 136, + 157, + 193, + 21, + 193, + 50, + 62, + 114, + 123, + 195, + 169, + 123, + 251, + 196, + 255, + 33, + 198, + 246, + 172, + 101, + 82, + 164, + 68, + 107, + 130, + 112, + 196, + 95, + 67, + 193, + 168, + 208, + 14, + 0, + 176, + 109, + 236, + 213, + 193, + 227, + 121, + 255, + 198, + 187, + 192, + 24, + 4, + 80, + 16, + 132, + 55, + 178, + 68, + 198, + 129, + 31, + 25, + 102, + 250, + 175, + 87, + 133, + 115, + 186, + 88, + 108, + 228, + 209, + 102, + 61, + 232, + 185, + 70, + 182, + 217, + 238, + 95, + 208, + 229, + 74, + 198, + 162, + 148, + 70, + 91, + 89, + 193, + 119, + 160, + 41, + 31, + 167, + 90, + 64, + 185, + 235, + 42, + 5, + 38, + 182, + 103, + 239, + 234, + 37, + 122, + 45, + 164, + 204, + 121, + 222, + 132, + 13, + 90, + 247, + 212, + 73, + 217, + 227, + 103, + 178, + 89, + 103, + 226, + 138, + 55, + 216, + 27, + 13, + 27, + 215, + 151, + 33, + 225, + 23, + 11, + 248, + 243, + 125, + 181, + 218, + 114, + 100, + 196, + 236, + 200, + 175, + 91, + 59, + 100, + 89, + 5, + 118, + 51, + 14, + 73, + 107, + 226, + 65, + 49, + 63, + 163, + 198, + 227, + 222, + 10, + 183, + 151, + 191, + 87, + 150, + 214, + 137, + 158, + 46, + 11, + 60, + 209, + 101, + 16, + 211, + 144, + 30, + 122, + 70, + 113, + 55, + 144, + 162, + 166, + 191, + 225, + 240, + 172, + 203, + 173, + 156, + 119, + 123, + 189, + 141, + 1, + 239, + 78, + 255, + 150, + 19, + 170, + 123, + 158, + 157, + 165, + 186, + 246, + 253, + 106, + 69, + 124, + 99, + 225, + 88, + 195, + 40, + 118, + 63, + 195, + 198, + 135, + 71, + 136, + 12, + 187, + 230, + 236, + 178, + 15, + 212, + 102, + 31, + 194, + 61, + 173, + 190, + 223, + 156, + 163, + 26, + 48, + 173, + 28, + 111, + 231, + 33, + 175, + 151, + 76, + 120, + 191, + 40, + 122, + 252, + 159, + 52, + 192, + 223, + 246, + 105, + 89, + 45, + 163, + 246, + 157, + 40, + 39, + 35, + 60, + 221, + 91, + 166, + 76, + 132, + 13, + 42, + 177, + 63, + 144, + 71, + 57, + 248, + 29, + 98, + 221, + 69, + 130, + 155, + 138, + 5, + 146, + 20, + 195, + 252, + 10, + 19, + 175, + 245, + 253, + 59, + 79, + 227, + 227, + 80, + 64, + 166, + 83, + 72, + 194, + 7, + 29, + 182, + 139, + 243, + 166, + 229, + 135, + 134, + 188, + 179, + 103, + 1, + 19, + 111, + 79, + 255, + 21, + 176, + 164, + 200, + 179, + 119, + 6, + 67, + 231, + 29, + 116, + 90, + 175, + 77, + 181, + 22, + 191, + 126, + 199, + 172, + 255, + 114, + 72, + 55, + 186, + 87, + 152, + 192, + 169, + 235, + 201, + 29, + 40, + 45, + 80, + 179, + 106, + 207, + 137, + 245, + 25, + 0, + 34, + 212, + 117, + 30, + 164, + 119, + 99, + 174, + 222, + 134, + 66, + 12, + 222, + 125, + 53, + 195, + 87, + 119, + 226, + 108, + 214, + 228, + 153, + 81, + 11, + 201, + 136, + 119, + 159, + 97, + 66, + 125, + 205, + 150, + 50, + 34, + 138, + 20, + 38, + 138, + 16, + 38, + 6, + 179, + 146, + 234, + 127, + 173, + 100, + 38, + 84, + 123, + 79, + 122, + 199, + 187, + 111, + 94, + 245, + 118, + 164, + 79, + 117, + 107, + 202, + 141, + 231, + 16, + 40, + 107, + 30, + 0, + 95, + 189, + 252, + 86, + 156, + 104, + 38, + 216, + 51, + 121, + 66, + 210, + 89, + 253, + 158, + 44, + 157, + 47, + 105, + 12, + 124, + 28, + 234, + 175, + 57, + 221, + 39, + 0, + 172, + 68, + 85, + 90, + 113, + 176, + 103, + 251, + 6, + 121, + 142, + 82, + 59, + 163, + 223, + 70, + 114, + 246, + 139, + 67, + 138, + 83, + 64, + 61, + 103, + 106, + 25, + 240, + 247, + 252, + 73, + 2, + 56, + 72, + 102, + 106, + 87, + 158, + 242, + 40, + 83, + 246, + 177, + 81, + 205, + 184, + 148, + 145, + 169, + 245, + 153, + 164, + 36, + 127, + 192, + 130, + 60, + 154, + 83, + 232, + 72, + 102, + 54, + 80, + 231, + 58, + 171, + 58, + 52, + 192, + 165, + 109, + 226, + 7, + 119, + 245, + 103, + 127, + 105, + 157, + 101, + 61, + 41, + 15, + 55, + 157, + 136, + 128, + 55, + 183, + 100, + 217, + 43, + 232, + 24, + 26, + 93, + 113, + 237, + 171, + 163, + 17, + 93, + 85, + 15, + 71, + 15, + 161, + 170, + 183, + 165, + 248, + 8, + 17, + 21, + 9, + 138, + 31, + 253, + 91, + 198, + 31, + 78, + 224, + 50, + 155, + 215, + 66, + 124, + 241, + 229, + 77, + 53, + 107, + 164, + 211, + 102, + 88, + 130, + 88, + 233, + 182, + 240, + 251, + 46, + 121, + 72, + 135, + 163, + 151, + 129, + 6, + 183, + 84, + 135, + 70, + 145, + 82, + 225, + 7, + 107, + 255, + 84, + 202, + 63, + 24, + 189, + 158, + 68, + 103, + 132, + 31, + 201, + 225, + 99, + 95, + 96, + 10, + 140, + 63, + 167, + 55, + 152, + 194, + 104, + 77, + 117, + 53, + 209, + 79, + 222, + 86, + 225, + 115, + 200, + 28, + 65, + 245, + 38, + 121, + 236, + 7, + 50, + 61, + 75, + 104, + 64, + 180, + 241, + 253, + 38, + 80, + 232, + 66, + 51, + 214, + 109, + 13, + 40, + 81, + 173, + 155, + 6, + 45, + 238, + 69, + 138, + 115, + 97, + 143, + 188, + 156, + 163, + 244, + 35, + 210, + 238, + 14, + 230, + 49, + 155, + 207, + 232, + 223, + 193, + 247, + 232, + 97, + 40, + 66, + 65, + 80, + 128, + 168, + 92, + 102, + 208, + 153, + 103, + 123, + 45, + 163, + 59, + 3, + 15, + 230, + 203, + 53, + 59, + 154, + 253, + 82, + 162, + 58, + 26, + 68, + 236, + 65, + 57, + 12, + 225, + 156, + 25, + 178, + 35, + 56, + 107, + 1, + 189, + 9, + 36, + 192, + 6, + 18, + 166, + 35, + 42, + 232, + 183, + 106, + 155, + 91, + 43, + 117, + 119, + 90, + 156, + 83, + 77, + 207, + 129, + 50, + 196, + 114, + 87, + 150, + 239, + 50, + 193, + 100, + 108, + 199, + 39, + 204, + 9, + 130, + 235, + 228, + 175, + 188, + 99, + 130, + 180, + 2, + 247, + 140, + 12, + 148, + 134, + 224, + 39, + 227, + 156, + 183, + 85, + 254, + 126, + 232, + 154, + 110, + 218, + 43, + 248, + 9, + 98, + 78, + 183, + 80, + 230, + 113, + 96, + 32, + 12, + 173, + 205, + 66, + 2, + 93, + 117, + 249, + 73, + 220, + 148, + 52, + 170, + 74, + 119, + 1, + 133, + 66, + 164, + 64, + 23, + 69, + 251, + 158, + 86, + 201, + 34, + 108, + 54, + 213, + 34, + 59, + 221, + 216, + 221, + 225, + 97, + 58, + 47, + 136, + 122, + 245, + 199, + 187, + 54, + 145, + 2, + 151, + 63, + 101, + 27, + 211, + 181, + 10, + 98, + 87, + 100, + 213, + 208, + 245, + 42, + 162, + 34, + 206, + 90, + 68, + 239, + 74, + 108, + 174, + 228, + 188, + 220, + 126, + 198, + 255, + 132, + 202, + 1, + 124, + 7, + 12, + 25, + 244, + 118, + 21, + 115, + 96, + 76, + 229, + 210, + 46, + 237, + 251, + 227, + 169, + 75, + 154, + 147, + 226, + 246, + 209, + 195, + 74, + 213, + 152, + 183, + 17, + 247, + 188, + 78, + 255, + 61, + 232, + 66, + 185, + 212, + 108, + 53, + 179, + 40, + 0, + 105, + 254, + 11, + 128, + 116, + 145, + 188, + 3, + 82, + 9, + 66, + 192, + 232, + 217, + 222, + 123, + 56, + 93, + 49, + 23, + 39, + 162, + 40, + 208, + 79, + 206, + 223, + 81, + 253, + 242, + 39, + 81, + 23, + 46, + 187, + 147, + 92, + 142, + 117, + 216, + 226, + 236, + 211, + 230, + 83, + 193, + 13, + 29, + 1, + 200, + 188, + 49, + 248, + 248, + 74, + 213, + 185, + 192, + 72, + 76, + 254, + 83, + 224, + 234, + 115, + 250, + 87, + 50, + 230, + 9, + 47, + 146, + 97, + 36, + 180, + 72, + 54, + 126, + 21, + 87, + 201, + 1, + 83, + 182, + 1, + 151, + 235, + 104, + 242, + 15, + 67, + 26, + 27, + 185, + 225, + 28, + 163, + 221, + 121, + 237, + 104, + 221, + 179, + 22, + 41, + 22, + 99, + 174, + 245, + 187, + 14, + 89, + 71, + 149, + 6, + 218, + 212, + 190, + 66, + 19, + 71, + 255, + 168, + 100, + 128, + 199, + 110, + 242, + 117, + 82, + 227, + 248, + 252, + 71, + 238, + 222, + 148, + 245, + 125, + 195, + 241, + 161, + 210, + 69, + 91, + 60, + 77, + 102, + 152, + 64, + 4, + 195, + 150, + 239, + 61, + 5, + 213, + 87, + 67, + 194, + 173, + 38, + 59, + 171, + 198, + 247, + 65, + 61, + 27, + 233, + 9, + 56, + 142, + 229, + 72, + 127, + 171, + 5, + 15, + 227, + 128, + 179, + 165, + 205, + 239, + 73, + 78, + 66, + 40, + 107, + 175, + 12, + 148, + 97, + 191, + 137, + 163, + 139, + 238, + 245, + 15, + 105, + 98, + 190, + 192, + 215, + 30, + 45, + 248, + 176, + 158, + 116, + 123, + 143, + 101, + 250, + 172, + 111, + 15, + 55, + 96, + 236, + 63, + 99, + 248, + 154, + 146, + 132, + 248, + 89, + 238, + 188, + 65, + 0, + 249, + 229, + 173, + 189, + 232, + 235, + 157, + 71, + 184, + 44, + 45, + 127, + 240, + 216, + 119, + 166, + 194, + 10, + 77, + 94, + 164, + 215, + 123, + 227, + 144, + 169, + 117, + 152, + 34, + 43, + 80, + 42, + 140, + 56, + 82, + 233, + 96, + 52, + 166, + 199, + 145, + 103, + 54, + 44, + 250, + 80, + 17, + 95, + 181, + 3, + 219, + 169, + 202, + 8, + 121, + 160, + 111, + 245, + 74, + 125, + 71, + 37, + 32, + 1, + 214, + 71, + 155, + 50, + 56, + 4, + 176, + 160, + 158, + 102, + 182, + 80, + 0, + 220, + 152, + 187, + 50, + 82, + 121, + 183, + 5, + 246, + 133, + 55, + 12, + 184, + 147, + 213, + 245, + 250, + 40, + 153, + 60, + 214, + 121, + 250, + 26, + 72, + 34, + 56, + 101, + 71, + 88, + 165, + 140, + 151, + 124, + 242, + 101, + 30, + 72, + 76, + 10, + 30, + 47, + 111, + 40, + 239, + 207, + 248, + 240, + 141, + 174, + 241, + 55, + 102, + 84, + 167, + 54, + 29, + 39, + 254, + 191, + 205, + 150, + 95, + 138, + 220, + 141, + 31, + 146, + 0, + 89, + 223, + 169, + 58, + 223, + 137, + 2, + 13, + 201, + 234, + 74, + 158, + 247, + 210, + 23, + 92, + 203, + 112, + 97, + 120, + 149, + 129, + 254, + 138, + 2, + 57, + 85, + 195, + 45, + 244, + 145, + 26, + 116, + 3, + 57, + 173, + 229, + 205, + 63, + 79, + 42, + 202, + 182, + 239, + 208, + 181, + 237, + 148, + 213, + 118, + 235, + 65, + 248, + 214, + 90, + 242, + 16, + 5, + 85, + 42, + 193, + 10, + 80, + 67, + 254, + 182, + 97, + 219, + 166, + 115, + 139, + 153, + 71, + 133, + 14, + 151, + 81, + 140, + 177, + 106, + 51, + 48, + 221, + 8, + 101, + 81, + 90, + 139, + 169, + 225, + 147, + 227, + 101, + 63, + 36, + 68, + 7, + 109, + 36, + 20, + 145, + 175, + 43, + 101, + 14, + 193, + 32, + 128, + 90, + 251, + 46, + 168, + 83, + 130, + 33, + 227, + 105, + 223, + 85, + 126, + 182, + 108, + 198, + 147, + 54, + 243, + 31, + 94, + 24, + 28, + 3, + 4, + 169, + 67, + 55, + 48, + 18, + 92, + 138, + 127, + 151, + 150, + 221, + 11, + 77, + 79, + 115, + 124, + 145, + 169, + 121, + 53, + 3, + 30, + 150, + 151, + 161, + 254, + 119, + 53, + 9, + 90, + 234, + 153, + 169, + 192, + 53, + 153, + 123, + 148, + 66, + 13, + 66, + 253, + 47, + 202, + 187, + 143, + 2, + 99, + 71, + 197, + 201, + 49, + 46, + 146, + 146, + 233, + 252, + 175, + 61, + 76, + 254, + 5, + 179, + 135, + 216, + 122, + 63, + 245, + 214, + 31, + 237, + 246, + 213, + 252, + 61, + 131, + 239, + 153, + 222, + 143, + 85, + 10, + 153, + 25, + 102, + 237, + 122, + 101, + 237, + 74, + 247, + 46, + 27, + 116, + 65, + 49, + 48, + 148, + 44, + 79, + 231, + 189, + 84, + 177, + 227, + 168, + 119, + 103, + 41, + 165, + 92, + 45, + 178, + 205, + 175, + 44, + 168, + 41, + 132, + 163, + 180, + 165, + 79, + 67, + 235, + 132, + 175, + 217, + 130, + 133, + 224, + 206, + 155, + 114, + 87, + 70, + 168, + 111, + 251, + 192, + 133, + 249, + 64, + 34, + 99, + 117, + 204, + 74, + 7, + 199, + 253, + 151, + 212, + 129, + 31, + 100, + 225, + 22, + 246, + 18, + 155, + 220, + 125, + 250, + 132, + 94, + 68, + 156, + 106, + 64, + 18, + 152, + 134, + 53, + 155, + 94, + 49, + 79, + 74, + 156, + 7, + 237, + 78, + 186, + 53, + 155, + 20, + 101, + 202, + 60, + 157, + 238, + 11, + 196, + 38, + 163, + 118, + 33, + 86, + 210, + 133, + 135, + 254, + 63, + 2, + 218, + 150, + 189, + 99, + 195, + 149, + 53, + 2, + 241, + 1, + 234, + 11, + 136, + 140, + 115, + 219, + 158, + 200, + 218, + 81, + 135, + 248, + 61, + 241, + 169, + 1, + 59, + 168, + 66, + 132, + 101, + 104, + 204, + 9, + 179, + 245, + 102, + 67, + 33, + 174, + 247, + 235, + 156, + 18, + 76, + 127, + 96, + 243, + 208, + 177, + 214, + 81, + 101, + 135, + 196, + 239, + 189, + 93, + 140, + 205, + 77, + 166, + 64, + 190, + 35, + 64, + 17, + 62, + 147, + 59, + 170, + 43, + 248, + 155, + 15, + 200, + 44, + 196, + 4, + 233, + 149, + 53, + 60, + 154, + 116, + 11, + 85, + 231, + 57, + 92, + 71, + 234, + 37, + 249, + 19, + 99, + 106, + 73, + 169, + 120, + 11, + 252, + 185, + 112, + 117, + 195, + 13, + 12, + 31, + 188, + 60, + 16, + 0, + 173, + 19, + 45, + 78, + 127, + 9, + 194, + 96, + 244, + 236, + 58, + 163, + 30, + 154, + 122, + 24, + 34, + 151, + 175, + 93, + 2, + 197, + 70, + 164, + 69, + 75, + 157, + 223, + 47, + 20, + 25, + 219, + 245, + 115, + 90, + 81, + 252, + 137, + 216, + 207, + 42, + 100, + 108, + 52, + 83, + 77, + 189, + 186, + 218, + 234, + 250, + 42, + 25, + 156, + 150, + 196, + 45, + 248, + 199, + 189, + 207, + 95, + 1, + 138, + 152, + 5, + 20, + 173, + 33, + 217, + 188, + 102, + 175, + 23, + 99, + 165, + 231, + 104, + 156, + 248, + 127, + 156, + 137, + 31, + 85, + 83, + 253, + 217, + 209, + 150, + 171, + 208, + 167, + 73, + 147, + 57, + 10, + 241, + 41, + 176, + 201, + 123, + 116, + 73, + 13, + 206, + 139, + 167, + 65, + 52, + 131, + 44, + 34, + 139, + 36, + 16, + 35, + 160, + 30, + 115, + 108, + 133, + 203, + 100, + 39, + 18, + 10, + 164, + 5, + 165, + 249, + 14, + 7, + 45, + 222, + 122, + 173, + 166, + 49, + 130, + 71, + 25, + 254, + 28, + 78, + 154, + 175, + 58, + 229, + 124, + 63, + 248, + 44, + 86, + 164, + 118, + 229, + 30, + 35, + 49, + 35, + 67, + 223, + 127, + 131, + 7, + 108, + 16, + 75, + 181, + 177, + 60, + 68, + 12, + 124, + 253, + 45, + 53, + 127, + 140, + 123, + 17, + 67, + 250, + 198, + 18, + 74, + 23, + 208, + 103, + 47, + 82, + 77, + 118, + 247, + 50, + 226, + 151, + 133, + 117, + 138, + 183, + 142, + 145, + 175, + 16, + 91, + 199, + 176, + 146, + 14, + 253, + 236, + 199, + 145, + 60, + 225, + 236, + 248, + 227, + 156, + 8, + 154, + 168, + 88, + 246, + 126, + 196, + 56, + 26, + 243, + 85, + 173, + 82, + 220, + 26, + 4, + 172, + 79, + 199, + 83, + 195, + 75, + 238, + 24, + 24, + 179, + 231, + 160, + 128, + 232, + 43, + 190, + 22, + 51, + 85, + 219, + 233, + 209, + 25, + 250, + 227, + 91, + 17, + 36, + 14, + 75, + 181, + 123, + 233, + 255, + 98, + 158, + 15, + 199, + 246, + 13, + 190, + 100, + 14, + 142, + 75, + 39, + 17, + 117, + 41, + 20, + 232, + 7, + 151, + 116, + 99, + 177, + 172, + 153, + 13, + 101, + 4, + 150, + 108, + 16, + 239, + 1, + 2, + 134, + 250, + 156, + 186, + 219, + 67, + 254, + 112, + 44, + 118, + 66, + 215, + 84, + 20, + 175, + 234, + 101, + 248, + 158, + 215, + 16, + 39, + 131, + 236, + 78, + 79, + 167, + 24, + 99, + 189, + 233, + 12, + 17, + 80, + 34, + 101, + 18, + 94, + 132, + 147, + 190, + 234, + 155, + 219, + 241, + 60, + 83, + 148, + 47, + 244, + 214, + 205, + 173, + 189, + 22, + 52, + 190, + 78, + 91, + 186, + 133, + 159, + 105, + 153, + 12, + 184, + 158, + 139, + 96, + 118, + 204, + 87, + 139, + 241, + 52, + 103, + 62, + 63, + 21, + 235, + 234, + 181, + 199, + 72, + 198, + 144, + 65, + 29, + 222, + 192, + 247, + 14, + 41, + 215, + 28, + 78, + 116, + 246, + 235, + 90, + 36, + 94, + 230, + 202, + 189, + 13, + 199, + 208, + 52, + 34, + 27, + 100, + 79, + 220, + 98, + 236, + 136, + 213, + 220, + 217, + 21, + 153, + 237, + 197, + 198, + 90, + 126, + 132, + 67, + 96, + 97, + 114, + 48, + 172, + 16, + 44, + 142, + 105, + 136, + 142, + 222, + 101, + 177, + 175, + 222, + 184, + 167, + 14, + 71, + 34, + 159, + 93, + 110, + 28, + 208, + 123, + 253, + 78, + 240, + 102, + 59, + 134, + 128, + 32, + 110, + 188, + 28, + 182, + 253, + 64, + 213, + 229, + 239, + 59, + 166, + 232, + 89, + 159, + 177, + 24, + 162, + 88, + 207, + 68, + 252, + 23, + 104, + 0, + 122, + 36, + 129, + 35, + 128, + 231, + 57, + 51, + 132, + 175, + 59, + 65, + 20, + 65, + 218, + 209, + 35, + 5, + 248, + 135, + 217, + 17, + 96, + 116, + 14, + 105, + 81, + 132, + 104, + 87, + 195, + 166, + 129, + 66, + 50, + 214, + 21, + 108, + 72, + 30, + 91, + 216, + 186, + 176, + 18, + 181, + 35, + 221, + 31, + 48, + 108, + 172, + 161, + 117, + 43, + 204, + 87, + 51, + 151, + 142, + 168, + 54, + 160, + 110, + 96, + 31, + 81, + 109, + 249, + 110, + 6, + 212, + 108, + 193, + 226, + 90, + 136, + 112, + 91, + 47, + 145, + 8, + 210, + 16, + 217, + 100, + 247, + 199, + 120, + 207, + 215, + 166, + 33, + 182, + 144, + 180, + 191, + 113, + 154, + 24, + 100, + 226, + 30, + 214, + 249, + 243, + 63, + 33, + 145, + 167, + 20, + 206, + 242, + 79, + 27, + 64, + 24, + 157, + 136, + 245, + 226, + 201, + 142, + 229, + 28, + 125, + 240, + 55, + 204, + 226, + 245, + 184, + 31, + 45, + 73, + 25, + 242, + 240, + 108, + 57, + 34, + 104, + 217, + 150, + 190, + 50, + 246, + 206, + 7, + 201, + 51, + 88, + 155, + 150, + 201, + 1, + 140, + 179, + 200, + 225, + 159, + 129, + 125, + 78, + 66, + 240, + 71, + 36, + 185, + 220, + 40, + 61, + 79, + 5, + 129, + 208, + 42, + 44, + 90, + 56, + 99, + 142, + 126, + 113, + 196, + 84, + 75, + 78, + 218, + 242, + 11, + 67, + 218, + 229, + 59, + 224, + 109, + 209, + 1, + 223, + 166, + 243, + 255, + 248, + 251, + 45, + 65, + 243, + 255, + 30, + 245, + 180, + 69, + 95, + 4, + 169, + 161, + 172, + 140, + 63, + 127, + 155, + 91, + 112, + 100, + 116, + 161, + 31, + 208, + 31, + 237, + 168, + 142, + 173, + 62, + 58, + 28, + 203, + 235, + 84, + 101, + 58, + 40, + 191, + 157, + 65, + 210, + 30, + 237, + 239, + 110, + 46, + 108, + 185, + 68, + 234, + 191, + 155, + 26, + 217, + 167, + 116, + 50, + 87, + 115, + 177, + 124, + 29, + 44, + 59, + 230, + 226, + 168, + 83, + 243, + 103, + 217, + 227, + 205, + 153, + 2, + 131, + 7, + 212, + 104, + 140, + 224, + 208, + 192, + 246, + 72, + 198, + 72, + 168, + 1, + 76, + 102, + 116, + 209, + 211, + 1, + 66, + 223, + 98, + 244, + 43, + 143, + 60, + 167, + 111, + 231, + 193, + 74, + 36, + 253, + 55, + 111, + 55, + 105, + 131, + 171, + 140, + 241, + 166, + 8, + 168, + 54, + 102, + 98, + 80, + 244, + 84, + 183, + 2, + 20, + 168, + 237, + 17, + 235, + 145, + 220, + 96, + 249, + 109, + 217, + 117, + 72, + 102, + 94, + 239, + 17, + 183, + 160, + 165, + 28, + 114, + 2, + 110, + 193, + 186, + 80, + 109, + 115, + 36, + 69, + 91, + 38, + 195, + 223, + 12, + 153, + 28, + 124, + 164, + 206, + 185, + 92, + 42, + 169, + 90, + 224, + 0, + 186, + 127, + 33, + 171, + 50, + 92, + 31, + 43, + 151, + 220, + 75, + 223, + 11, + 216, + 102, + 192, + 158, + 182, + 94, + 52, + 11, + 9, + 168, + 236, + 125, + 140, + 231, + 46, + 110, + 119, + 179, + 219, + 252, + 71, + 25, + 14, + 254, + 44, + 233, + 241, + 86, + 16, + 60, + 23, + 245, + 41, + 179, + 252, + 17, + 224, + 98, + 27, + 31, + 96, + 25, + 58, + 165, + 94, + 83, + 74, + 187, + 4, + 100, + 105, + 42, + 119, + 239, + 240, + 99, + 134, + 211, + 150, + 208, + 33, + 234, + 35, + 181, + 26, + 245, + 150, + 90, + 238, + 236, + 24, + 193, + 64, + 57, + 197, + 194, + 235, + 190, + 200, + 164, + 184, + 174, + 130, + 64, + 237, + 229, + 81, + 61, + 124, + 161, + 243, + 54, + 175, + 13, + 81, + 111, + 56, + 195, + 221, + 192, + 29, + 7, + 54, + 64, + 241, + 172, + 235, + 223, + 115, + 41, + 47, + 39, + 175, + 70, + 11, + 121, + 224, + 53, + 160, + 40, + 31, + 239, + 55, + 227, + 13, + 0, + 207, + 227, + 63, + 134, + 184, + 33, + 124, + 176, + 77, + 3, + 153, + 11, + 232, + 190, + 90, + 219, + 54, + 234, + 56, + 218, + 110, + 182, + 218, + 120, + 32, + 65, + 124, + 111, + 34, + 75, + 124, + 189, + 137, + 70, + 22, + 181, + 3, + 207, + 173, + 126, + 25, + 163, + 58, + 92, + 217, + 46, + 220, + 222, + 195, + 127, + 199, + 41, + 42, + 203, + 153, + 113, + 185, + 104, + 102, + 93, + 95, + 162, + 47, + 123, + 254, + 81, + 196, + 195, + 47, + 25, + 199, + 195, + 73, + 43, + 241, + 42, + 140, + 80, + 0, + 177, + 223, + 151, + 66, + 202, + 82, + 223, + 181, + 44, + 114, + 33, + 25, + 33, + 105, + 45, + 9, + 22, + 153, + 88, + 219, + 170, + 79, + 76, + 254, + 138, + 97, + 75, + 192, + 118, + 131, + 57, + 146, + 206, + 121, + 219, + 229, + 113, + 196, + 170, + 30, + 249, + 217, + 104, + 210, + 250, + 145, + 51, + 213, + 175, + 89, + 175, + 141, + 203, + 76, + 172, + 32, + 243, + 24, + 119, + 145, + 235, + 156, + 150, + 107, + 252, + 204, + 62, + 98, + 106, + 118, + 40, + 214, + 34, + 82, + 233, + 205, + 90, + 87, + 20, + 59, + 94, + 66, + 92, + 19, + 157, + 221, + 134, + 224, + 255, + 108, + 13, + 105, + 91, + 164, + 253, + 168, + 31, + 31, + 76, + 177, + 215, + 24, + 101, + 109, + 22, + 44, + 169, + 168, + 245, + 252, + 227, + 196, + 131, + 232, + 138, + 112, + 249, + 17, + 37, + 109, + 209, + 20, + 107, + 223, + 103, + 180, + 66, + 13, + 69, + 61, + 94, + 65, + 92, + 155, + 210, + 215, + 193, + 124, + 181, + 240, + 163, + 124, + 180, + 144, + 140, + 188, + 83, + 20, + 172, + 16, + 133, + 211, + 10, + 50, + 113, + 137, + 2, + 230, + 35, + 200, + 228, + 87, + 200, + 149, + 189, + 138, + 194, + 68, + 212, + 117, + 59, + 149, + 8, + 211, + 109, + 211, + 168, + 100, + 254, + 252, + 142, + 23, + 43, + 114, + 16, + 13, + 184, + 32, + 248, + 178, + 144, + 7, + 13, + 64, + 204, + 234, + 248, + 121, + 188, + 190, + 199, + 26, + 149, + 243, + 209, + 70, + 219, + 39, + 179, + 18, + 232, + 38, + 204, + 149, + 154, + 247, + 242, + 77, + 76, + 221, + 141, + 45, + 94, + 122, + 175, + 187, + 189, + 181, + 65, + 149, + 249, + 124, + 86, + 13, + 241, + 17, + 81, + 244, + 44, + 82, + 97, + 3, + 18, + 189, + 248, + 29, + 244, + 201, + 61, + 104, + 30, + 121, + 80, + 232, + 167, + 136, + 217, + 162, + 197, + 42, + 246, + 135, + 205, + 229, + 114, + 72, + 200, + 223, + 58, + 146, + 14, + 237, + 69, + 46, + 51, + 141, + 187, + 102, + 19, + 138, + 147, + 84, + 222, + 109, + 176, + 82, + 215, + 90, + 112, + 32, + 170, + 54, + 35, + 62, + 204, + 166, + 24, + 46, + 40, + 170, + 251, + 202, + 207, + 96, + 80, + 180, + 187, + 28, + 150, + 82, + 110, + 250, + 105, + 58, + 92, + 179, + 115, + 251, + 74, + 97, + 139, + 83, + 230, + 184, + 194, + 55, + 80, + 226, + 76, + 134, + 159, + 204, + 134, + 200, + 1, + 191, + 50, + 165, + 186, + 234, + 72, + 243, + 0, + 73, + 152, + 107, + 231, + 18, + 190, + 72, + 38, + 27, + 4, + 202, + 169, + 195, + 115, + 248, + 192, + 50, + 104, + 207, + 98, + 71, + 118, + 79, + 200, + 134, + 91, + 88, + 206, + 195, + 32, + 160, + 80, + 15, + 187, + 101, + 181, + 237, + 209, + 18, + 19, + 228, + 188, + 236, + 235, + 48, + 120, + 249, + 137, + 63, + 70, + 47, + 112, + 253, + 249, + 30, + 199, + 100, + 38, + 234, + 97, + 250, + 173, + 83, + 157, + 41, + 151, + 62, + 50, + 69, + 99, + 26, + 90, + 180, + 220, + 43, + 172, + 178, + 75, + 22, + 17, + 35, + 172, + 64, + 67, + 187, + 126, + 89, + 113, + 190, + 201, + 132, + 174, + 27, + 44, + 155, + 138, + 235, + 243, + 21, + 59, + 141, + 187, + 206, + 72, + 174, + 162, + 122, + 118, + 127, + 137, + 39, + 110, + 186, + 46, + 208, + 208, + 113, + 34, + 144, + 182, + 219, + 166, + 52, + 212, + 79, + 162, + 77, + 196, + 70, + 8, + 30, + 52, + 9, + 136, + 238, + 184, + 145, + 21, + 11, + 233, + 190, + 117, + 11, + 53, + 220, + 5, + 132, + 95, + 248, + 181, + 27, + 114, + 175, + 123, + 6, + 5, + 160, + 138, + 219, + 45, + 110, + 144, + 72, + 46, + 162, + 209, + 217, + 170, + 127, + 223, + 255, + 252, + 240, + 100, + 198, + 93, + 80, + 99, + 248, + 59, + 132, + 228, + 107, + 163, + 4, + 110, + 99, + 143, + 188, + 147, + 200, + 70, + 125, + 79, + 20, + 243, + 232, + 125, + 39, + 140, + 10, + 214, + 209, + 43, + 58, + 228, + 133, + 97, + 76, + 182, + 199, + 34, + 136, + 204, + 196, + 52, + 161, + 174, + 56, + 56, + 255, + 154, + 97, + 161, + 239, + 232, + 103, + 195, + 42, + 166, + 130, + 73, + 150, + 140, + 178, + 71, + 146, + 131, + 77, + 173, + 81, + 105, + 105, + 79, + 136, + 33, + 69, + 114, + 78, + 99, + 87, + 250, + 144, + 173, + 95, + 255, + 130, + 68, + 85, + 62, + 251, + 60, + 175, + 245, + 200, + 240, + 71, + 234, + 127, + 183, + 5, + 195, + 80, + 105, + 145, + 154, + 212, + 227, + 153, + 159, + 16, + 179, + 204, + 12, + 30, + 253, + 192, + 166, + 57, + 228, + 90, + 113, + 248, + 172, + 3, + 252, + 202, + 161, + 169, + 222, + 222, + 116, + 169, + 131, + 207, + 211, + 118, + 206, + 200, + 65, + 213, + 8, + 185, + 68, + 163, + 163, + 99, + 176, + 141, + 247, + 241, + 230, + 12, + 150, + 185, + 221, + 253, + 217, + 184, + 7, + 96, + 19, + 136, + 181, + 2, + 12, + 81, + 61, + 193, + 221, + 208, + 189, + 183, + 38, + 231, + 129, + 35, + 126, + 132, + 145, + 103, + 7, + 128, + 14, + 28, + 132, + 185, + 140, + 14, + 192, + 104, + 245, + 251, + 153, + 150, + 45, + 172, + 58, + 4, + 124, + 56, + 249, + 168, + 229, + 150, + 148, + 40, + 200, + 40, + 250, + 115, + 247, + 111, + 152, + 254, + 69, + 17, + 143, + 34, + 212, + 216, + 147, + 98, + 110, + 121, + 229, + 174, + 116, + 156, + 103, + 27, + 135, + 61, + 2, + 41, + 8, + 152, + 54, + 4, + 30, + 155, + 159, + 219, + 162, + 211, + 108, + 247, + 103, + 73, + 173, + 52, + 170, + 225, + 148, + 16, + 81, + 146, + 67, + 24, + 162, + 165, + 51, + 28, + 60, + 173, + 143, + 247, + 206, + 101, + 133, + 138, + 150, + 47, + 132, + 77, + 10, + 145, + 191, + 125, + 74, + 17, + 3, + 33, + 151, + 37, + 82, + 210, + 37, + 115, + 168, + 51, + 126, + 85, + 178, + 26, + 50, + 118, + 167, + 242, + 154, + 150, + 179, + 59, + 208, + 236, + 3, + 202, + 249, + 22, + 219, + 44, + 32, + 71, + 128, + 75, + 72, + 117, + 63, + 29, + 71, + 125, + 58, + 156, + 159, + 5, + 43, + 97, + 235, + 20, + 115, + 234, + 34, + 196, + 137, + 111, + 28, + 15, + 36, + 84, + 209, + 103, + 52, + 112, + 202, + 75, + 202, + 105, + 49, + 135, + 253, + 220, + 225, + 53, + 130, + 59, + 197, + 239, + 219, + 216, + 230, + 145, + 35, + 213, + 153, + 105, + 18, + 142, + 48, + 47, + 247, + 141, + 137, + 251, + 201, + 81, + 130, + 26, + 211, + 18, + 179, + 212, + 204, + 244, + 230, + 221, + 172, + 236, + 73, + 55, + 103, + 168, + 240, + 121, + 162, + 111, + 225, + 122, + 143, + 109, + 120, + 217, + 172, + 19, + 198, + 235, + 185, + 125, + 239, + 89, + 181, + 128, + 90, + 14, + 201, + 67, + 181, + 170, + 89, + 204, + 142, + 188, + 223, + 56, + 195, + 81, + 214, + 197, + 53, + 49, + 130, + 233, + 128, + 165, + 5, + 188, + 248, + 88, + 119, + 104, + 41, + 96, + 255, + 19, + 84, + 104, + 173, + 13, + 109, + 223, + 83, + 246, + 237, + 226, + 249, + 220, + 46, + 125, + 161, + 118, + 173, + 91, + 193, + 123, + 203, + 138, + 155, + 103, + 198, + 169, + 218, + 227, + 62, + 101, + 197, + 175, + 240, + 4, + 41, + 52, + 27, + 175, + 183, + 182, + 152, + 143, + 153, + 205, + 167, + 87, + 37, + 200, + 105, + 109, + 23, + 74, + 131, + 93, + 189, + 39, + 241, + 70, + 89, + 139, + 77, + 3, + 5, + 49, + 180, + 225, + 194, + 54, + 135, + 71, + 91, + 25, + 3, + 30, + 4, + 48, + 222, + 42, + 67, + 194, + 161, + 226, + 123, + 0, + 56, + 57, + 223, + 198, + 114, + 80, + 75, + 56, + 203, + 101, + 44, + 119, + 245, + 54, + 170, + 231, + 189, + 105, + 62, + 236, + 218, + 220, + 96, + 230, + 172, + 126, + 53, + 31, + 250, + 61, + 233, + 138, + 66, + 181, + 161, + 184, + 77, + 147, + 241, + 31, + 141, + 6, + 112, + 13, + 224, + 90, + 33, + 28, + 96, + 154, + 109, + 239, + 129, + 239, + 211, + 112, + 38, + 48, + 167, + 177, + 20, + 168, + 7, + 11, + 78, + 217, + 191, + 28, + 253, + 148, + 113, + 128, + 51, + 101, + 218, + 51, + 34, + 246, + 10, + 180, + 185, + 238, + 27, + 181, + 27, + 150, + 255, + 179, + 242, + 56, + 1, + 11, + 85, + 136, + 50, + 84, + 225, + 231, + 194, + 112, + 154, + 22, + 11, + 208, + 114, + 44, + 33, + 13, + 215, + 48, + 59, + 2, + 252, + 172, + 110, + 133, + 87, + 229, + 196, + 148, + 75, + 194, + 42, + 195, + 128, + 219, + 117, + 85, + 132, + 156, + 99, + 4, + 158, + 8, + 161, + 221, + 21, + 53, + 123, + 92, + 189, + 196, + 233, + 221, + 78, + 100, + 96, + 65, + 4, + 53, + 71, + 220, + 246, + 132, + 125, + 49, + 19, + 64, + 191, + 70, + 232, + 87, + 196, + 79, + 244, + 68, + 106, + 138, + 123, + 60, + 200, + 30, + 183, + 96, + 130, + 235, + 219, + 141, + 173, + 115, + 124, + 94, + 55, + 89, + 81, + 167, + 100, + 72, + 103, + 115, + 11, + 138, + 178, + 238, + 68, + 11, + 194, + 53, + 114, + 224, + 36, + 61, + 7, + 3, + 115, + 72, + 114, + 107, + 4, + 147, + 3, + 8, + 79, + 138, + 234, + 23, + 200, + 54, + 57, + 115, + 120, + 155, + 24, + 208, + 242, + 84, + 170, + 46, + 229, + 143, + 59, + 87, + 42, + 32, + 223, + 236, + 147, + 37, + 4, + 154, + 16, + 233, + 149, + 101, + 24, + 77, + 24, + 215, + 84, + 235, + 92, + 160, + 48, + 17, + 138, + 218, + 109, + 171, + 88, + 47, + 231, + 57, + 248, + 39, + 72, + 50, + 20, + 217, + 94, + 24, + 216, + 67, + 234, + 22, + 122, + 229, + 103, + 127, + 131, + 251, + 189, + 175, + 77, + 43, + 34, + 4, + 17, + 235, + 160, + 189, + 146, + 233, + 12, + 107, + 61, + 63, + 245, + 8, + 215, + 126, + 22, + 161, + 118, + 136, + 149, + 234, + 205, + 17, + 228, + 20, + 101, + 39, + 29, + 74, + 173, + 215, + 90, + 102, + 32, + 106, + 57, + 22, + 101, + 152, + 179, + 112, + 102, + 126, + 251, + 75, + 43, + 72, + 166, + 88, + 87, + 217, + 137, + 23, + 145, + 10, + 251, + 186, + 109, + 232, + 125, + 177, + 10, + 138, + 84, + 92, + 182, + 82, + 6, + 55, + 3, + 107, + 246, + 179, + 109, + 183, + 242, + 32, + 85, + 195, + 28, + 180, + 94, + 60, + 132, + 57, + 225, + 192, + 8, + 12, + 205, + 32, + 96, + 246, + 219, + 107, + 101, + 67, + 219, + 59, + 141, + 227, + 138, + 241, + 236, + 56, + 84, + 136, + 253, + 84, + 230, + 20, + 93, + 106, + 155, + 91, + 120, + 250, + 210, + 109, + 15, + 188, + 35, + 6, + 230, + 29, + 162, + 160, + 18, + 191, + 236, + 33, + 118, + 79, + 230, + 88, + 42, + 73, + 31, + 90, + 161, + 100, + 7, + 213, + 242, + 137, + 214, + 81, + 29, + 46, + 171, + 28, + 27, + 108, + 15, + 3, + 116, + 230, + 121, + 49, + 23, + 199, + 84, + 235, + 107, + 224, + 71, + 46, + 35, + 170, + 9, + 181, + 15, + 55, + 44, + 47, + 31, + 153, + 47, + 239, + 99, + 36, + 138, + 188, + 224, + 5, + 144, + 160, + 42, + 124, + 253, + 1, + 81, + 163, + 251, + 214, + 229, + 167, + 7, + 190, + 150, + 24, + 72, + 169, + 117, + 52, + 70, + 63, + 88, + 58, + 88, + 59, + 247, + 234, + 66, + 134, + 119, + 139, + 143, + 172, + 176, + 244, + 244, + 72, + 101, + 199, + 21, + 230, + 117, + 170, + 70, + 207, + 116, + 38, + 123, + 84, + 86, + 57, + 60, + 63, + 105, + 17, + 113, + 163, + 26, + 12, + 194, + 62, + 72, + 34, + 140, + 74, + 209, + 33, + 213, + 210, + 244, + 129, + 11, + 30, + 96, + 85, + 142, + 96, + 129, + 115, + 249, + 196, + 88, + 70, + 138, + 216, + 97, + 74, + 170, + 208, + 254, + 148, + 121, + 88, + 103, + 54, + 124, + 105, + 230, + 202, + 98, + 58, + 127, + 82, + 122, + 241, + 72, + 137, + 98, + 136, + 219, + 136, + 182, + 99, + 88, + 19, + 11, + 122, + 210, + 230, + 106, + 218, + 253, + 178, + 138, + 230, + 12, + 148, + 102, + 24, + 55, + 149, + 168, + 68, + 90, + 44, + 86, + 52, + 75, + 64, + 165, + 151, + 255, + 45, + 225, + 219, + 80, + 23, + 241, + 239, + 155, + 121, + 116, + 124, + 57, + 202, + 151, + 213, + 145, + 9, + 180, + 62, + 204, + 187, + 37, + 179, + 110, + 199, + 240, + 135, + 193, + 234, + 165, + 89, + 126, + 62, + 72, + 140, + 0, + 96, + 174, + 106, + 238, + 138, + 58, + 160, + 63, + 57, + 114, + 94, + 208, + 195, + 31, + 3, + 17, + 215, + 248, + 24, + 47, + 79, + 140, + 222, + 119, + 255, + 29, + 172, + 202, + 89, + 21, + 136, + 73, + 95, + 150, + 167, + 189, + 32, + 93, + 123, + 34, + 67, + 189, + 7, + 48, + 34, + 128, + 113, + 107, + 64, + 115, + 217, + 202, + 104, + 1, + 107, + 36, + 131, + 220, + 73, + 184, + 218, + 138, + 183, + 121, + 39, + 85, + 37, + 236, + 141, + 167, + 128, + 38, + 2, + 64, + 128, + 133, + 44, + 26, + 247, + 51, + 61, + 145, + 67, + 182, + 213, + 235, + 76, + 47, + 236, + 176, + 21, + 220, + 46, + 110, + 242, + 23, + 105, + 113, + 69, + 97, + 37, + 45, + 89, + 244, + 100, + 222, + 69, + 245, + 143, + 47, + 181, + 71, + 93, + 245, + 115, + 176, + 40, + 250, + 41, + 156, + 232, + 230, + 59, + 36, + 87, + 64, + 245, + 254, + 26, + 49, + 127, + 12, + 209, + 32, + 150, + 109, + 163, + 48, + 105, + 25, + 80, + 19, + 2, + 200, + 174, + 90, + 42, + 93, + 72, + 54, + 88, + 82, + 142, + 127, + 102, + 173, + 101, + 9, + 213, + 185, + 18, + 31, + 13, + 229, + 176, + 148, + 54, + 219, + 208, + 166, + 14, + 179, + 189, + 219, + 71, + 150, + 57, + 242, + 35, + 7, + 176, + 222, + 115, + 233, + 184, + 159, + 84, + 165, + 116, + 181, + 103, + 199, + 58, + 35, + 114, + 236, + 184, + 60, + 52, + 248, + 2, + 235, + 100, + 10, + 163, + 79, + 169, + 226, + 65, + 19, + 21, + 153, + 244, + 86, + 117, + 180, + 186, + 187, + 32, + 114, + 33, + 222, + 200, + 73, + 46, + 166, + 87, + 230, + 117, + 160, + 9, + 83, + 124, + 205, + 135, + 205, + 67, + 235, + 70, + 13, + 166, + 241, + 185, + 69, + 129, + 168, + 176, + 89, + 150, + 95, + 176, + 75, + 198, + 225, + 253, + 118, + 106, + 128, + 58, + 207, + 93, + 207, + 147, + 236, + 14, + 158, + 140, + 242, + 20, + 89, + 217, + 133, + 214, + 200, + 197, + 78, + 5, + 254, + 90, + 56, + 187, + 136, + 158, + 21, + 80, + 7, + 150, + 129, + 44, + 2, + 114, + 61, + 121, + 75, + 5, + 0, + 57, + 65, + 221, + 165, + 57, + 146, + 80, + 114, + 63, + 196, + 99, + 120, + 218, + 157, + 148, + 253, + 140, + 184, + 22, + 178, + 74, + 92, + 25, + 101, + 7, + 96, + 27, + 66, + 101, + 197, + 106, + 30, + 39, + 163, + 132, + 250, + 247, + 194, + 36, + 5, + 33, + 150, + 232, + 224, + 50, + 107, + 39, + 223, + 57, + 177, + 106, + 175, + 47, + 224, + 243, + 228, + 115, + 37, + 250, + 48, + 1, + 35, + 51, + 44, + 173, + 199, + 159, + 174, + 229, + 68, + 199, + 12, + 203, + 80, + 17, + 246, + 151, + 42, + 65, + 186, + 39, + 223, + 95, + 208, + 126, + 98, + 188, + 150, + 41, + 245, + 214, + 11, + 119, + 92, + 34, + 203, + 242, + 95, + 47, + 100, + 112, + 252, + 230, + 154, + 74, + 206, + 44, + 250, + 61, + 213, + 8, + 14, + 198, + 185, + 71, + 179, + 170, + 87, + 251, + 5, + 39, + 9, + 82, + 123, + 151, + 92, + 190, + 47, + 112, + 232, + 214, + 196, + 109, + 249, + 131, + 239, + 45, + 227, + 243, + 91, + 83, + 87, + 161, + 215, + 57, + 235, + 163, + 58, + 138, + 79, + 67, + 4, + 45, + 147, + 34, + 190, + 251, + 161, + 0, + 10, + 111, + 19, + 80, + 25, + 222, + 251, + 223, + 199, + 89, + 170, + 184, + 63, + 162, + 50, + 131, + 6, + 227, + 243, + 26, + 237, + 60, + 163, + 95, + 239, + 6, + 251, + 39, + 12, + 185, + 250, + 234, + 208, + 67, + 49, + 3, + 249, + 192, + 119, + 166, + 127, + 230, + 80, + 72, + 191, + 22, + 152, + 218, + 8, + 195, + 34, + 204, + 199, + 40, + 225, + 47, + 14, + 37, + 135, + 108, + 137, + 166, + 74, + 223, + 131, + 111, + 152, + 134, + 216, + 9, + 176, + 223, + 72, + 223, + 90, + 169, + 155, + 229, + 91, + 229, + 192, + 8, + 155, + 113, + 188, + 71, + 79, + 160, + 244, + 96, + 203, + 115, + 32, + 130, + 203, + 99, + 62, + 217, + 216, + 111, + 23, + 164, + 19, + 248, + 71, + 177, + 50, + 78, + 154, + 102, + 87, + 98, + 101, + 110, + 176, + 99, + 161, + 138, + 124, + 173, + 25, + 97, + 119, + 123, + 172, + 145, + 1, + 108, + 80, + 29, + 202, + 214, + 31, + 101, + 229, + 180, + 174, + 50, + 184, + 165, + 16, + 161, + 51, + 193, + 199, + 15, + 243, + 232, + 241, + 141, + 164, + 81, + 19, + 28, + 228, + 147, + 98, + 25, + 224, + 77, + 232, + 119, + 254, + 241, + 159, + 108, + 243, + 187, + 162, + 40, + 136, + 244, + 167, + 69, + 186, + 62, + 74, + 54, + 52, + 79, + 66, + 110, + 143, + 228, + 51, + 58, + 51, + 158, + 2, + 18, + 129, + 93, + 63, + 244, + 36, + 253, + 234, + 57, + 176, + 100, + 129, + 111, + 67, + 2, + 158, + 220, + 97, + 201, + 123, + 184, + 3, + 238, + 2, + 109, + 38, + 37, + 106, + 9, + 243, + 229, + 172, + 162, + 9, + 38, + 33, + 231, + 49, + 41, + 226, + 209, + 185, + 12, + 13, + 183, + 164, + 30, + 66, + 7, + 168, + 90, + 39, + 29, + 30, + 111, + 221, + 184, + 209, + 223, + 136, + 66, + 234, + 154, + 140, + 140, + 130, + 164, + 198, + 38, + 71, + 42, + 88, + 26, + 15, + 144, + 210, + 2, + 91, + 12, + 169, + 84, + 60, + 115, + 57, + 198, + 61, + 62, + 250, + 18, + 193, + 7, + 207, + 82, + 63, + 52, + 50, + 87, + 211, + 189, + 48, + 216, + 252, + 19, + 203, + 81, + 80, + 227, + 25, + 98, + 207, + 18, + 163, + 166, + 139, + 116, + 4, + 173, + 168, + 224, + 93, + 240, + 89, + 244, + 239, + 1, + 231, + 143, + 87, + 244, + 222, + 193, + 251, + 32, + 43, + 223, + 38, + 75, + 158, + 198, + 216, + 159, + 60, + 152, + 197, + 34, + 5, + 145, + 205, + 153, + 186, + 223, + 209, + 140, + 112, + 43, + 134, + 37, + 154, + 109, + 98, + 247, + 50, + 155, + 172, + 72, + 124, + 27, + 10, + 219, + 143, + 86, + 26, + 167, + 122, + 200, + 8, + 159, + 148, + 147, + 91, + 210, + 27, + 152, + 102, + 106, + 212, + 144, + 87, + 76, + 49, + 215, + 16, + 189, + 200, + 191, + 82, + 194, + 244, + 255, + 135, + 216, + 49, + 118, + 22, + 44, + 9, + 67, + 30, + 37, + 240, + 221, + 174, + 99, + 162, + 10, + 119, + 216, + 116, + 40, + 158, + 27, + 36, + 135, + 203, + 101, + 187, + 215, + 93, + 102, + 202, + 32, + 207, + 227, + 173, + 110, + 87, + 236, + 105, + 30, + 174, + 62, + 98, + 206, + 200, + 134, + 43, + 181, + 147, + 142, + 197, + 148, + 94, + 88, + 150, + 93, + 207, + 216, + 211, + 114, + 222, + 1, + 60, + 1, + 188, + 64, + 243, + 122, + 183, + 33, + 1, + 24, + 54, + 229, + 228, + 163, + 99, + 159, + 107, + 193, + 178, + 39, + 153, + 130, + 199, + 10, + 135, + 214, + 128, + 37, + 222, + 91, + 253, + 118, + 89, + 14, + 159, + 89, + 175, + 254, + 240, + 3, + 186, + 122, + 207, + 248, + 99, + 133, + 35, + 176, + 210, + 65, + 65, + 76, + 198, + 185, + 254, + 106, + 113, + 128, + 131, + 242, + 166, + 41, + 88, + 152, + 131, + 160, + 68, + 214, + 200, + 83, + 196, + 194, + 139, + 240, + 105, + 31, + 213, + 80, + 232, + 222, + 200, + 74, + 76, + 29, + 23, + 231, + 110, + 49, + 195, + 40, + 160, + 183, + 8, + 16, + 57, + 123, + 176, + 52, + 18, + 61, + 45, + 200, + 231, + 108, + 238, + 168, + 231, + 17, + 145, + 128, + 189, + 92, + 215, + 5, + 56, + 166, + 32, + 13, + 130, + 36, + 109, + 174, + 203, + 124, + 102, + 145, + 101, + 42, + 116, + 190, + 254, + 185, + 23, + 69, + 80, + 193, + 93, + 57, + 67, + 237, + 130, + 110, + 0, + 207, + 202, + 219, + 35, + 208, + 60, + 59, + 154, + 7, + 1, + 8, + 32, + 178, + 185, + 206, + 36, + 232, + 37, + 132, + 67, + 208, + 90, + 173, + 60, + 82, + 111, + 204, + 241, + 186, + 55, + 32, + 207, + 63, + 6, + 222, + 238, + 199, + 22, + 225, + 165, + 106, + 217, + 155, + 114, + 124, + 219, + 120, + 226, + 173, + 49, + 100, + 6, + 215, + 59, + 117, + 218, + 222, + 195, + 116, + 153, + 252, + 122, + 50, + 2, + 166, + 31, + 247, + 45, + 39, + 139, + 230, + 50, + 89, + 56, + 232, + 155, + 187, + 3, + 146, + 86, + 30, + 148, + 76, + 92, + 144, + 197, + 31, + 85, + 75, + 36, + 177, + 112, + 79, + 169, + 21, + 52, + 76, + 49, + 221, + 114, + 60, + 25, + 12, + 63, + 19, + 244, + 207, + 148, + 53, + 6, + 142, + 146, + 172, + 79, + 241, + 121, + 51, + 232, + 179, + 78, + 214, + 225, + 249, + 61, + 32, + 137, + 244, + 12, + 181, + 157, + 25, + 198, + 58, + 229, + 155, + 83, + 85, + 160, + 229, + 231, + 241, + 134, + 162, + 157, + 247, + 103, + 162, + 47, + 167, + 210, + 144, + 185, + 119, + 29, + 89, + 97, + 22, + 239, + 40, + 80, + 86, + 107, + 58, + 61, + 200, + 247, + 232, + 103, + 40, + 178, + 28, + 35, + 243, + 57, + 33, + 186, + 210, + 131, + 249, + 62, + 38, + 5, + 145, + 192, + 77, + 226, + 123, + 144, + 75, + 93, + 254, + 251, + 63, + 40, + 50, + 29, + 63, + 46, + 56, + 208, + 67, + 196, + 134, + 178, + 71, + 212, + 53, + 106, + 153, + 119, + 91, + 69, + 58, + 43, + 214, + 184, + 104, + 48, + 144, + 207, + 198, + 68, + 75, + 57, + 208, + 192, + 115, + 70, + 20, + 232, + 177, + 155, + 113, + 204, + 55, + 194, + 141, + 209, + 99, + 178, + 203, + 247, + 236, + 133, + 89, + 218, + 169, + 205, + 48, + 153, + 180, + 101, + 98, + 23, + 114, + 107, + 249, + 231, + 68, + 160, + 32, + 103, + 106, + 226, + 109, + 169, + 206, + 209, + 3, + 83, + 97, + 152, + 195, + 187, + 207, + 36, + 15, + 47, + 254, + 253, + 11, + 135, + 109, + 246, + 242, + 22, + 13, + 135, + 28, + 171, + 244, + 40, + 89, + 27, + 232, + 51, + 93, + 175, + 251, + 182, + 218, + 25, + 151, + 111, + 52, + 123, + 243, + 35, + 139, + 63, + 89, + 50, + 234, + 219, + 1, + 126, + 12, + 92, + 25, + 152, + 241, + 81, + 169, + 150, + 100, + 230, + 46, + 62, + 80, + 230, + 222, + 90, + 118, + 134, + 37, + 90, + 180, + 67, + 145, + 89, + 187, + 113, + 162, + 33, + 243, + 8, + 189, + 25, + 216, + 171, + 209, + 205, + 167, + 26, + 35, + 41, + 45, + 36, + 58, + 219, + 98, + 130, + 10, + 192, + 233, + 235, + 62, + 169, + 73, + 153, + 141, + 123, + 222, + 72, + 201, + 236, + 141, + 160, + 84, + 196, + 59, + 183, + 148, + 254, + 143, + 31, + 240, + 93, + 21, + 44, + 165, + 6, + 100, + 38, + 151, + 135, + 225, + 161, + 118, + 205, + 250, + 182, + 91, + 88, + 152, + 120, + 10, + 242, + 123, + 226, + 50, + 149, + 196, + 192, + 84, + 99, + 177, + 217, + 68, + 11, + 156, + 104, + 133, + 119, + 80, + 129, + 208, + 144, + 211, + 83, + 5, + 27, + 236, + 123, + 210, + 224, + 150, + 166, + 15, + 77, + 232, + 54, + 89, + 134, + 194, + 36, + 73, + 101, + 150, + 247, + 37, + 106, + 142, + 108, + 88, + 223, + 38, + 135, + 145, + 31, + 95, + 72, + 20, + 211, + 110, + 119, + 73, + 96, + 149, + 6, + 126, + 252, + 154, + 255, + 175, + 203, + 9, + 132, + 156, + 144, + 57, + 82, + 127, + 49, + 85, + 62, + 216, + 19, + 87, + 181, + 228, + 1, + 243, + 36, + 47, + 180, + 99, + 55, + 44, + 153, + 233, + 34, + 125, + 97, + 119, + 108, + 138, + 162, + 133, + 178, + 173, + 115, + 185, + 145, + 103, + 233, + 220, + 156, + 227, + 141, + 107, + 129, + 138, + 49, + 187, + 24, + 154, + 116, + 227, + 62, + 20, + 187, + 209, + 116, + 26, + 207, + 23, + 112, + 219, + 236, + 138, + 20, + 87, + 150, + 150, + 55, + 164, + 66, + 65, + 40, + 76, + 105, + 94, + 56, + 254, + 149, + 85, + 223, + 254, + 49, + 224, + 247, + 22, + 250, + 244, + 57, + 176, + 248, + 204, + 82, + 105, + 32, + 77, + 11, + 110, + 251, + 197, + 211, + 224, + 56, + 178, + 193, + 235, + 113, + 113, + 55, + 253, + 242, + 249, + 108, + 90, + 139, + 206, + 164, + 8, + 224, + 213, + 197, + 121, + 44, + 131, + 175, + 222, + 60, + 245, + 76, + 16, + 213, + 87, + 164, + 139, + 245, + 157, + 127, + 197, + 95, + 20, + 45, + 83, + 111, + 86, + 64, + 93, + 41, + 237, + 56, + 183, + 158, + 3, + 10, + 224, + 17, + 240, + 213, + 122, + 40, + 213, + 170, + 190, + 183, + 62, + 2, + 246, + 25, + 137, + 213, + 80, + 68, + 56, + 214, + 100, + 210, + 253, + 53, + 189, + 188, + 132, + 209, + 202, + 190, + 204, + 224, + 183, + 140, + 24, + 213, + 79, + 124, + 125, + 167, + 193, + 224, + 86, + 57, + 113, + 155, + 213, + 68, + 93, + 120, + 99, + 92, + 206, + 68, + 145, + 202, + 94, + 107, + 58, + 164, + 37, + 34, + 4, + 47, + 130, + 254, + 208, + 174, + 22, + 40, + 216, + 49, + 140, + 118, + 170, + 77, + 182, + 212, + 117, + 137, + 1, + 223, + 53, + 62, + 112, + 243, + 78, + 251, + 128, + 82, + 196, + 168, + 158, + 200, + 120, + 185, + 228, + 37, + 182, + 49, + 137, + 153, + 78, + 96, + 165, + 212, + 104, + 153, + 14, + 127, + 207, + 84, + 172, + 145, + 24, + 136, + 240, + 19, + 70, + 73, + 169, + 80, + 221, + 240, + 138, + 7, + 164, + 239, + 145, + 70, + 127, + 52, + 15, + 185, + 249, + 178, + 62, + 49, + 4, + 127, + 17, + 191, + 119, + 54, + 148, + 3, + 89, + 72, + 44, + 150, + 253, + 184, + 209, + 50, + 206, + 104, + 55, + 1, + 45, + 175, + 60, + 123, + 150, + 208, + 202, + 122, + 224, + 107, + 206, + 211, + 218, + 153, + 133, + 99, + 250, + 151, + 185, + 177, + 111, + 61, + 130, + 66, + 153, + 225, + 210, + 189, + 56, + 251, + 170, + 193, + 60, + 150, + 251, + 223, + 23, + 44, + 25, + 132, + 9, + 11, + 25, + 126, + 81, + 71, + 28, + 162, + 17, + 43, + 49, + 33, + 50, + 212, + 169, + 176, + 93, + 199, + 98, + 194, + 134, + 119, + 95, + 80, + 52, + 2, + 128, + 46, + 1, + 130, + 114, + 62, + 183, + 2, + 106, + 80, + 121, + 94, + 185, + 250, + 87, + 200, + 253, + 157, + 30, + 251, + 207, + 36, + 43, + 4, + 174, + 39, + 105, + 184, + 151, + 65, + 129, + 7, + 183, + 224, + 32, + 194, + 177, + 198, + 15, + 104, + 117, + 29, + 233, + 238, + 57, + 140, + 251, + 38, + 226, + 215, + 46, + 88, + 188, + 14, + 229, + 106, + 170, + 102, + 118, + 147, + 149, + 227, + 191, + 142, + 40, + 31, + 89, + 128, + 217, + 6, + 235, + 145, + 218, + 230, + 117, + 53, + 173, + 174, + 252, + 32, + 20, + 124, + 78, + 33, + 63, + 40, + 129, + 41, + 25, + 32, + 9, + 212, + 184, + 203, + 234, + 202, + 115, + 87, + 112, + 153, + 57, + 207, + 159, + 106, + 190, + 61, + 58, + 27, + 23, + 64, + 148, + 1, + 184, + 89, + 100, + 171, + 150, + 32, + 98, + 100, + 37, + 101, + 22, + 33, + 13, + 70, + 42, + 170, + 109, + 32, + 44, + 106, + 118, + 93, + 118, + 145, + 215, + 186, + 171, + 171, + 100, + 151, + 20, + 205, + 74, + 226, + 100, + 180, + 158, + 175, + 67, + 202, + 102, + 59, + 34, + 111, + 57, + 199, + 13, + 5, + 190, + 8, + 252, + 144, + 89, + 254, + 45, + 50, + 195, + 3, + 41, + 212, + 218, + 156, + 16, + 229, + 143, + 70, + 13, + 52, + 86, + 29, + 166, + 223, + 143, + 19, + 241, + 155, + 122, + 204, + 140, + 218, + 1, + 139, + 45, + 194, + 63, + 63, + 48, + 32, + 111, + 168, + 241, + 6, + 255, + 126, + 77, + 138, + 132, + 151, + 40, + 211, + 250, + 204, + 106, + 157, + 197, + 220, + 79, + 26, + 209, + 144, + 114, + 233, + 171, + 152, + 40, + 251, + 232, + 35, + 25, + 205, + 85, + 242, + 236, + 156, + 94, + 35, + 42, + 1, + 145, + 161, + 101, + 133, + 2, + 66, + 181, + 183, + 6, + 186, + 231, + 139, + 250, + 163, + 7, + 193, + 69, + 146, + 162, + 134, + 242, + 0, + 190, + 225, + 48, + 40, + 170, + 9, + 118, + 104, + 27, + 27, + 52, + 48, + 68, + 39, + 182, + 177, + 109, + 215, + 60, + 122, + 149, + 148, + 244, + 3, + 150, + 154, + 92, + 105, + 208, + 187, + 164, + 159, + 137, + 64, + 191, + 58, + 170, + 145, + 62, + 107, + 101, + 255, + 153, + 212, + 26, + 52, + 28, + 143, + 86, + 210, + 234, + 184, + 120, + 26, + 126, + 239, + 43, + 199, + 36, + 22, + 52, + 53, + 255, + 246, + 134, + 216, + 171, + 207, + 95, + 83, + 167, + 40, + 130, + 74, + 122, + 141, + 39, + 118, + 184, + 32, + 191, + 83, + 153, + 174, + 110, + 96, + 95, + 21, + 16, + 250, + 6, + 208, + 250, + 233, + 214, + 253, + 223, + 94, + 153, + 46, + 46, + 113, + 206, + 245, + 98, + 49, + 49, + 122, + 22, + 40, + 184, + 56, + 5, + 245, + 118, + 84, + 188, + 105, + 218, + 141, + 172, + 194, + 186, + 53, + 5, + 231, + 113, + 88, + 193, + 232, + 157, + 15, + 135, + 211, + 43, + 9, + 246, + 95, + 90, + 56, + 65, + 73, + 3, + 90, + 88, + 105, + 178, + 149, + 201, + 77, + 32, + 230, + 122, + 157, + 77, + 163, + 136, + 180, + 120, + 123, + 71, + 241, + 205, + 106, + 197, + 8, + 2, + 232, + 64, + 1, + 19, + 24, + 104, + 163, + 161, + 69, + 79, + 228, + 151, + 80, + 123, + 98, + 47, + 189, + 216, + 140, + 189, + 233, + 36, + 117, + 94, + 61, + 175, + 207, + 150, + 60, + 207, + 14, + 206, + 38, + 139, + 210, + 72, + 253, + 113, + 49, + 135, + 8, + 41, + 180, + 240, + 201, + 210, + 5, + 47, + 240, + 117, + 197, + 53, + 31, + 49, + 5, + 88, + 68, + 106, + 109, + 0, + 108, + 85, + 190, + 140, + 105, + 221, + 198, + 217, + 190, + 58, + 37, + 137, + 175, + 189, + 189, + 40, + 75, + 208, + 250, + 211, + 243, + 138, + 246, + 117, + 229, + 5, + 154, + 55, + 164, + 31, + 180, + 52, + 252, + 42, + 138, + 110, + 10, + 212, + 193, + 182, + 204, + 29, + 107, + 2, + 84, + 255, + 30, + 254, + 7, + 242, + 43, + 35, + 121, + 71, + 41, + 140, + 37, + 175, + 91, + 161, + 77, + 120, + 40, + 77, + 43, + 174, + 213, + 80, + 47, + 101, + 188, + 221, + 86, + 6, + 128, + 187, + 127, + 158, + 169, + 219, + 132, + 157, + 241, + 29, + 212, + 205, + 185, + 27, + 63, + 78, + 99, + 164, + 249, + 29, + 39, + 212, + 107, + 169, + 204, + 1, + 10, + 19, + 231, + 216, + 245, + 101, + 118, + 120, + 23, + 154, + 47, + 62, + 114, + 198, + 234, + 8, + 222, + 134, + 42, + 44, + 247, + 97, + 243, + 209, + 9, + 98, + 133, + 63, + 244, + 212, + 187, + 180, + 155, + 153, + 44, + 57, + 222, + 96, + 2, + 107, + 125, + 131, + 156, + 241, + 219, + 63, + 82, + 116, + 136, + 86, + 16, + 132, + 58, + 114, + 22, + 66, + 9, + 13, + 109, + 219, + 94, + 159, + 33, + 160, + 251, + 235, + 163, + 118, + 194, + 103, + 21, + 241, + 60, + 32, + 30, + 46, + 190, + 239, + 2, + 78, + 12, + 24, + 86, + 218, + 41, + 232, + 9, + 180, + 58, + 176, + 33, + 223, + 242, + 73, + 86, + 41, + 245, + 185, + 237, + 46, + 111, + 64, + 179, + 27, + 1, + 226, + 96, + 6, + 133, + 130, + 162, + 114, + 222, + 91, + 249, + 38, + 157, + 140, + 178, + 121, + 246, + 200, + 10, + 101, + 69, + 175, + 153, + 35, + 46, + 44, + 89, + 137, + 84, + 1, + 226, + 90, + 228, + 64, + 73, + 101, + 154, + 250, + 42, + 88, + 32, + 209, + 216, + 182, + 219, + 111, + 144, + 145, + 19, + 142, + 123, + 17, + 245, + 137, + 57, + 247, + 5, + 73, + 251, + 178, + 212, + 72, + 136, + 194, + 152, + 15, + 207, + 14, + 250, + 59, + 42, + 96, + 61, + 20, + 15, + 51, + 232, + 187, + 192, + 208, + 195, + 47, + 156, + 196, + 245, + 136, + 114, + 99, + 198, + 37, + 168, + 60, + 69, + 38, + 13, + 64, + 149, + 48, + 135, + 137, + 196, + 222, + 161, + 2, + 123, + 119, + 255, + 79, + 88, + 153, + 71, + 154, + 124, + 171, + 224, + 187, + 221, + 138, + 15, + 157, + 154, + 12, + 59, + 238, + 97, + 106, + 18, + 147, + 90, + 138, + 7, + 233, + 248, + 32, + 227, + 62, + 67, + 235, + 40, + 74, + 242, + 112, + 151, + 128, + 227, + 24, + 204, + 194, + 83, + 182, + 113, + 205, + 27, + 62, + 15, + 68, + 226, + 23, + 1, + 151, + 146, + 6, + 178, + 225, + 82, + 159, + 141, + 106, + 7, + 218, + 176, + 148, + 150, + 208, + 195, + 84, + 213, + 209, + 111, + 222, + 180, + 36, + 100, + 242, + 172, + 114, + 147, + 38, + 27, + 11, + 11, + 112, + 218, + 194, + 31, + 166, + 6, + 82, + 75, + 42, + 214, + 93, + 99, + 47, + 247, + 204, + 125, + 159, + 170, + 72, + 9, + 67, + 172, + 12, + 245, + 161, + 163, + 54, + 230, + 14, + 83, + 66, + 193, + 25, + 217, + 131, + 205, + 146, + 217, + 7, + 2, + 50, + 88, + 65, + 17, + 151, + 165, + 120, + 101, + 149, + 128, + 72, + 214, + 2, + 37, + 172, + 21, + 132, + 138, + 112, + 158, + 216, + 138, + 57, + 151, + 227, + 75, + 2, + 124, + 7, + 130, + 239, + 25, + 134, + 147, + 251, + 0, + 135, + 26, + 90, + 168, + 22, + 74, + 63, + 253, + 64, + 46, + 36, + 229, + 176, + 193, + 27, + 2, + 122, + 70, + 90, + 90, + 140, + 134, + 113, + 81, + 83, + 90, + 12, + 39, + 85, + 247, + 59, + 239, + 215, + 13, + 170, + 253, + 151, + 64, + 25, + 133, + 205, + 62, + 223, + 245, + 75, + 210, + 203, + 175, + 7, + 158, + 13, + 39, + 115, + 234, + 2, + 174, + 0, + 231, + 5, + 205, + 77, + 209, + 241, + 1, + 105, + 90, + 251, + 55, + 117, + 243, + 189, + 134, + 247, + 126, + 153, + 164, + 235, + 21, + 198, + 116, + 178, + 203, + 1, + 39, + 21, + 111, + 157, + 189, + 52, + 243, + 108, + 105, + 97, + 225, + 67, + 116, + 34, + 129, + 108, + 46, + 55, + 201, + 248, + 165, + 150, + 100, + 247, + 51, + 255, + 254, + 12, + 133, + 235, + 136, + 68, + 107, + 102, + 194, + 194, + 158, + 191, + 36, + 10, + 81, + 176, + 10, + 170, + 43, + 122, + 162, + 15, + 245, + 14, + 250, + 176, + 206, + 22, + 67, + 139, + 141, + 28, + 50, + 71, + 158, + 107, + 17, + 8, + 26, + 223, + 90, + 153, + 216, + 174, + 10, + 46, + 0, + 228, + 183, + 175, + 7, + 126, + 12, + 198, + 174, + 45, + 107, + 29, + 214, + 132, + 154, + 11, + 54, + 231, + 167, + 224, + 201, + 230, + 94, + 3, + 52, + 204, + 238, + 28, + 128, + 55, + 255, + 179, + 243, + 106, + 140, + 156, + 217, + 79, + 243, + 60, + 170, + 41, + 200, + 230, + 0, + 65, + 236, + 174, + 131, + 152, + 131, + 66, + 71, + 103, + 87, + 21, + 191, + 222, + 64, + 173, + 157, + 80, + 140, + 61, + 150, + 121, + 214, + 73, + 22, + 253, + 106, + 142, + 180, + 214, + 98, + 92, + 19, + 150, + 232, + 245, + 92, + 229, + 233, + 115, + 102, + 68, + 210, + 1, + 188, + 15, + 208, + 180, + 21, + 187, + 174, + 83, + 198, + 79, + 51, + 96, + 67, + 40, + 243, + 224, + 35, + 129, + 116, + 242, + 243, + 27, + 48, + 141, + 187, + 19, + 252, + 240, + 198, + 253, + 203, + 46, + 69, + 186, + 26, + 3, + 25, + 235, + 213, + 77, + 254, + 237, + 103, + 16, + 35, + 49, + 4, + 194, + 45, + 204, + 6, + 208, + 53, + 104, + 86, + 57, + 216, + 67, + 47, + 235, + 44, + 189, + 186, + 55, + 168, + 69, + 77, + 214, + 56, + 104, + 27, + 85, + 198, + 176, + 194, + 164, + 207, + 61, + 219, + 174, + 73, + 168, + 163, + 61, + 33, + 137, + 47, + 10, + 169, + 24, + 80, + 119, + 139, + 10, + 162, + 104, + 231, + 69, + 78, + 94, + 208, + 185, + 15, + 131, + 207, + 197, + 210, + 133, + 38, + 47, + 99, + 136, + 43, + 113, + 101, + 221, + 21, + 248, + 104, + 136, + 230, + 96, + 184, + 118, + 101, + 182, + 219, + 93, + 57, + 71, + 2, + 23, + 225, + 60, + 51, + 39, + 104, + 12, + 236, + 42, + 108, + 112, + 196, + 9, + 111, + 138, + 228, + 223, + 24, + 236, + 125, + 173, + 203, + 45, + 214, + 68, + 7, + 36, + 243, + 9, + 45, + 126, + 251, + 238, + 158, + 18, + 94, + 162, + 90, + 89, + 7, + 154, + 156, + 38, + 222, + 36, + 188, + 206, + 38, + 86, + 74, + 255, + 141, + 255, + 160, + 135, + 112, + 96, + 10, + 132, + 210, + 63, + 251, + 185, + 135, + 255, + 107, + 10, + 252, + 187, + 107, + 245, + 51, + 104, + 193, + 176, + 174, + 56, + 83, + 220, + 0, + 61, + 101, + 118, + 125, + 51, + 94, + 188, + 26, + 22, + 144, + 253, + 118, + 25, + 28, + 177, + 84, + 3, + 217, + 10, + 154, + 243, + 32, + 213, + 255, + 253, + 237, + 200, + 120, + 193, + 235, + 121, + 247, + 18, + 126, + 69, + 58, + 249, + 202, + 79, + 243, + 150, + 252, + 131, + 199, + 55, + 116, + 158, + 247, + 192, + 124, + 153, + 49, + 0, + 109, + 117, + 141, + 125, + 151, + 50, + 93, + 155, + 23, + 155, + 113, + 84, + 53, + 134, + 233, + 186, + 24, + 184, + 137, + 45, + 114, + 121, + 222, + 18, + 225, + 139, + 184, + 206, + 203, + 9, + 143, + 92, + 185, + 235, + 255, + 100, + 154, + 58, + 111, + 202, + 140, + 243, + 115, + 24, + 74, + 73, + 17, + 223, + 99, + 177, + 5, + 130, + 193, + 237, + 110, + 72, + 156, + 206, + 57, + 85, + 235, + 38, + 171, + 177, + 109, + 1, + 178, + 217, + 148, + 155, + 99, + 244, + 155, + 141, + 243, + 94, + 238, + 206, + 243, + 143, + 226, + 9, + 161, + 23, + 243, + 217, + 54, + 78, + 104, + 71, + 116, + 183, + 139, + 140, + 83, + 71, + 117, + 15, + 245, + 72, + 24, + 32, + 97, + 121, + 59, + 5, + 222, + 48, + 141, + 137, + 197, + 200, + 187, + 146, + 140, + 171, + 110, + 252, + 222, + 82, + 252, + 172, + 73, + 23, + 194, + 221, + 35, + 232, + 157, + 188, + 19, + 37, + 227, + 59, + 159, + 30, + 82, + 212, + 167, + 89, + 71, + 15, + 123, + 135, + 92, + 56, + 78, + 216, + 56, + 252, + 135, + 10, + 193, + 12, + 225, + 22, + 42, + 90, + 235, + 65, + 191, + 244, + 185, + 193, + 18, + 188, + 99, + 203, + 221, + 223, + 164, + 5, + 109, + 83, + 121, + 193, + 224, + 214, + 44, + 71, + 241, + 181, + 74, + 22, + 123, + 58, + 215, + 87, + 238, + 24, + 34, + 158, + 23, + 184, + 120, + 1, + 52, + 92, + 39, + 192, + 17, + 247, + 224, + 161, + 209, + 27, + 116, + 102, + 170, + 244, + 57, + 11, + 101, + 212, + 179, + 11, + 242, + 99, + 215, + 86, + 96, + 251, + 240, + 129, + 228, + 91, + 230, + 220, + 3, + 13, + 39, + 169, + 166, + 76, + 252, + 83, + 78, + 63, + 171, + 58, + 71, + 162, + 179, + 147, + 151, + 178, + 133, + 72, + 125, + 86, + 66, + 253, + 214, + 107, + 250, + 66, + 5, + 17, + 233, + 54, + 94, + 190, + 127, + 5, + 222, + 12, + 126, + 53, + 184, + 150, + 244, + 102, + 28, + 20, + 247, + 163, + 124, + 56, + 149, + 110, + 16, + 28, + 151, + 14, + 117, + 4, + 86, + 217, + 54, + 46, + 216, + 163, + 60, + 247, + 241, + 30, + 199, + 90, + 15, + 192, + 226, + 247, + 187, + 16, + 234, + 112, + 210, + 38, + 178, + 221, + 184, + 48, + 8, + 116, + 125, + 153, + 185, + 16, + 79, + 222, + 105, + 210, + 127, + 141, + 75, + 247, + 186, + 75, + 106, + 28, + 200, + 96, + 112, + 187, + 176, + 116, + 30, + 94, + 169, + 13, + 194, + 113, + 216, + 81, + 173, + 226, + 148, + 67, + 194, + 91, + 24, + 19, + 85, + 98, + 112, + 140, + 249, + 77, + 91, + 107, + 60, + 214, + 106, + 119, + 73, + 75, + 74, + 231, + 218, + 126, + 112, + 27, + 207, + 136, + 180, + 32, + 34, + 33, + 178, + 6, + 74, + 212, + 143, + 26, + 3, + 86, + 228, + 133, + 89, + 129, + 245, + 165, + 154, + 107, + 88, + 7, + 146, + 150, + 147, + 127, + 91, + 253, + 26, + 92, + 184, + 141, + 244, + 97, + 100, + 252, + 217, + 6, + 161, + 184, + 56, + 40, + 119, + 48, + 238, + 79, + 47, + 184, + 201, + 159, + 138, + 143, + 249, + 16, + 57, + 190, + 178, + 134, + 104, + 221, + 13, + 70, + 185, + 236, + 1, + 76, + 103, + 100, + 42, + 149, + 255, + 243, + 215, + 17, + 254, + 129, + 140, + 157, + 68, + 44, + 233, + 33, + 216, + 150, + 209, + 73, + 160, + 151, + 107, + 75, + 100, + 43, + 236, + 108, + 225, + 59, + 83, + 11, + 19, + 84, + 3, + 218, + 129, + 231, + 136, + 252, + 198, + 253, + 80, + 123, + 30, + 105, + 121, + 155, + 138, + 101, + 246, + 178, + 156, + 70, + 196, + 184, + 208, + 59, + 39, + 202, + 146, + 8, + 177, + 16, + 39, + 65, + 82, + 146, + 60, + 114, + 236, + 76, + 22, + 75, + 45, + 253, + 255, + 69, + 211, + 136, + 238, + 197, + 72, + 84, + 233, + 24, + 221, + 229, + 86, + 9, + 178, + 153, + 60, + 116, + 227, + 60, + 212, + 225, + 146, + 60, + 174, + 127, + 182, + 73, + 15, + 153, + 89, + 18, + 133, + 39, + 216, + 100, + 104, + 29, + 165, + 217, + 185, + 47, + 22, + 8, + 249, + 113, + 242, + 84, + 13, + 237, + 176, + 93, + 119, + 62, + 224, + 222, + 187, + 113, + 78, + 49, + 178, + 32, + 10, + 102, + 252, + 72, + 225, + 46, + 15, + 208, + 49, + 77, + 85, + 82, + 186, + 116, + 192, + 42, + 213, + 99, + 39, + 61, + 40, + 43, + 102, + 62, + 31, + 224, + 30, + 26, + 79, + 210, + 144, + 82, + 218, + 120, + 226, + 210, + 101, + 42, + 148, + 49, + 83, + 142, + 70, + 167, + 125, + 225, + 196, + 52, + 99, + 102, + 160, + 94, + 137, + 45, + 33, + 43, + 233, + 118, + 153, + 244, + 82, + 103, + 97, + 57, + 161, + 224, + 4, + 5, + 230, + 51, + 69, + 206, + 172, + 187, + 230, + 125, + 116, + 89, + 63, + 218, + 238, + 143, + 250, + 56, + 168, + 46, + 189, + 16, + 90, + 138, + 146, + 47, + 202, + 67, + 3, + 171, + 216, + 13, + 91, + 174, + 150, + 46, + 43, + 184, + 127, + 100, + 56, + 251, + 39, + 16, + 112, + 97, + 87, + 81, + 35, + 223, + 41, + 70, + 23, + 247, + 68, + 195, + 254, + 117, + 185, + 210, + 179, + 175, + 26, + 1, + 81, + 205, + 161, + 238, + 200, + 185, + 185, + 114, + 207, + 107, + 0, + 63, + 205, + 107, + 208, + 137, + 12, + 193, + 47, + 60, + 8, + 83, + 166, + 234, + 205, + 149, + 7, + 125, + 99, + 62, + 99, + 37, + 193, + 193, + 72, + 112, + 85, + 242, + 135, + 222, + 213, + 219, + 107, + 233, + 45, + 34, + 106, + 237, + 161, + 219, + 239, + 37, + 199, + 220, + 118, + 97, + 46, + 71, + 98, + 79, + 64, + 252, + 194, + 12, + 68, + 173, + 220, + 64, + 86, + 208, + 211, + 223, + 18, + 71, + 129, + 70, + 127, + 118, + 135, + 190, + 24, + 141, + 239, + 46, + 157, + 107, + 2, + 160, + 112, + 204, + 224, + 0, + 65, + 170, + 47, + 48, + 7, + 42, + 136, + 52, + 150, + 80, + 30, + 246, + 199, + 13, + 199, + 173, + 73, + 215, + 72, + 80, + 24, + 141, + 223, + 92, + 157, + 181, + 168, + 171, + 30, + 207, + 44, + 173, + 224, + 202, + 53, + 101, + 234, + 230, + 96, + 35, + 26, + 8, + 111, + 33, + 3, + 12, + 60, + 163, + 161, + 81, + 127, + 126, + 106, + 40, + 200, + 68, + 12, + 166, + 207, + 96, + 228, + 78, + 120, + 30, + 13, + 145, + 88, + 123, + 243, + 160, + 175, + 183, + 41, + 52, + 145, + 230, + 245, + 71, + 184, + 172, + 62, + 152, + 142, + 123, + 7, + 237, + 185, + 114, + 87, + 79, + 198, + 196, + 139, + 92, + 128, + 7, + 201, + 116, + 144, + 98, + 185, + 149, + 91, + 77, + 5, + 71, + 245, + 104, + 169, + 42, + 4, + 221, + 14, + 49, + 237, + 65, + 10, + 44, + 175, + 51, + 17, + 14, + 223, + 120, + 103, + 35, + 34, + 251, + 72, + 126, + 216, + 176, + 145, + 223, + 22, + 42, + 244, + 74, + 16, + 56, + 242, + 10, + 5, + 201, + 25, + 232, + 234, + 191, + 91, + 13, + 89, + 72, + 85, + 65, + 238, + 165, + 1, + 184, + 208, + 59, + 123, + 85, + 94, + 143, + 79, + 252, + 111, + 130, + 72, + 106, + 212, + 135, + 190, + 102, + 19, + 245, + 37, + 64, + 65, + 193, + 166, + 184, + 195, + 57, + 130, + 222, + 95, + 121, + 253, + 90, + 214, + 14, + 189, + 130, + 191, + 34, + 82, + 253, + 55, + 101, + 238, + 180, + 77, + 113, + 180, + 236, + 139, + 160, + 31, + 222, + 6, + 153, + 208, + 57, + 10, + 65, + 148, + 112, + 65, + 108, + 234, + 29, + 91, + 75, + 55, + 230, + 179, + 215, + 181, + 150, + 245, + 250, + 18, + 3, + 175, + 19, + 47, + 55, + 65, + 129, + 82, + 53, + 199, + 43, + 235, + 204, + 29, + 55, + 9, + 112, + 254, + 113, + 234, + 189, + 65, + 208, + 215, + 100, + 31, + 72, + 85, + 126, + 252, + 4, + 200, + 128, + 127, + 135, + 54, + 250, + 196, + 49, + 59, + 71, + 225, + 31, + 30, + 158, + 51, + 115, + 9, + 10, + 179, + 50, + 81, + 10, + 235, + 94, + 228, + 135, + 139, + 36, + 96, + 157, + 212, + 181, + 203, + 43, + 141, + 239, + 187, + 107, + 43, + 177, + 255, + 201, + 150, + 107, + 10, + 254, + 44, + 83, + 25, + 218, + 7, + 26, + 24, + 236, + 126, + 191, + 63, + 177, + 66, + 16, + 61, + 15, + 228, + 83, + 14, + 224, + 242, + 150, + 204, + 40, + 210, + 120, + 64, + 5, + 196, + 229, + 70, + 52, + 73, + 43, + 14, + 213, + 109, + 121, + 136, + 122, + 170, + 175, + 44, + 150, + 14, + 197, + 59, + 17, + 182, + 199, + 28, + 86, + 2, + 96, + 255, + 97, + 80, + 172, + 170, + 240, + 166, + 169, + 35, + 13, + 184, + 68, + 207, + 95, + 233, + 162, + 201, + 80, + 52, + 119, + 193, + 19, + 155, + 115, + 29, + 221, + 185, + 202, + 140, + 6, + 149, + 13, + 88, + 194, + 141, + 58, + 255, + 1, + 79, + 59, + 40, + 90, + 63, + 79, + 100, + 234, + 44, + 115, + 195, + 250, + 17, + 95, + 228, + 61, + 66, + 117, + 31, + 214, + 147, + 46, + 74, + 69, + 39, + 15, + 144, + 46, + 227, + 244, + 159, + 104, + 145, + 133, + 204, + 81, + 132, + 109, + 1, + 143, + 230, + 28, + 121, + 198, + 252, + 200, + 88, + 110, + 159, + 234, + 25, + 239, + 183, + 139, + 97, + 98, + 70, + 233, + 140, + 102, + 30, + 152, + 226, + 33, + 194, + 3, + 71, + 214, + 66, + 21, + 43, + 151, + 229, + 96, + 234, + 244, + 17, + 131, + 174, + 220, + 216, + 242, + 183, + 96, + 118, + 134, + 60, + 158, + 43, + 236, + 214, + 120, + 249, + 82, + 233, + 46, + 82, + 76, + 193, + 41, + 192, + 60, + 149, + 166, + 56, + 109, + 218, + 237, + 39, + 26, + 245, + 100, + 221, + 246, + 172, + 173, + 74, + 43, + 165, + 197, + 2, + 169, + 113, + 43, + 198, + 198, + 61, + 92, + 74, + 232, + 244, + 229, + 110, + 115, + 109, + 243, + 106, + 1, + 34, + 166, + 113, + 84, + 30, + 62, + 156, + 178, + 50, + 209, + 22, + 94, + 99, + 129, + 144, + 104, + 179, + 4, + 146, + 47, + 198, + 255, + 132, + 97, + 248, + 60, + 211, + 13, + 219, + 146, + 11, + 14, + 65, + 235, + 61, + 246, + 162, + 133, + 183, + 21, + 235, + 142, + 255, + 147, + 65, + 158, + 57, + 12, + 169, + 86, + 207, + 192, + 153, + 147, + 30, + 224, + 75, + 54, + 180, + 114, + 101, + 99, + 221, + 201, + 136, + 107, + 128, + 255, + 18, + 104, + 91, + 193, + 148, + 216, + 118, + 150, + 107, + 170, + 28, + 179, + 213, + 68, + 27, + 231, + 216, + 68, + 111, + 64, + 127, + 77, + 210, + 44, + 149, + 150, + 144, + 19, + 187, + 87, + 120, + 140, + 44, + 133, + 103, + 224, + 77, + 87, + 181, + 221, + 103, + 171, + 61, + 201, + 191, + 64, + 90, + 135, + 139, + 181, + 135, + 38, + 207, + 95, + 39, + 57, + 141, + 24, + 62, + 7, + 251, + 134, + 13, + 95, + 80, + 61, + 10, + 194, + 65, + 182, + 0, + 44, + 134, + 19, + 226, + 75, + 53, + 176, + 164, + 131, + 231, + 110, + 177, + 185, + 158, + 186, + 28, + 58, + 110, + 86, + 246, + 228, + 18, + 220, + 223, + 253, + 24, + 212, + 73, + 213, + 253, + 235, + 82, + 185, + 137, + 61, + 119, + 176, + 249, + 222, + 245, + 235, + 120, + 117, + 75, + 48, + 153, + 198, + 171, + 72, + 54, + 3, + 15, + 189, + 104, + 229, + 141, + 78, + 192, + 115, + 252, + 113, + 121, + 84, + 226, + 202, + 221, + 121, + 63, + 105, + 232, + 92, + 45, + 216, + 119, + 76, + 109, + 162, + 11, + 226, + 42, + 95, + 100, + 55, + 150, + 94, + 7, + 152, + 250, + 27, + 22, + 144, + 89, + 190, + 90, + 149, + 174, + 67, + 202, + 214, + 255, + 20, + 32, + 163, + 62, + 142, + 95, + 171, + 191, + 196, + 85, + 34, + 139, + 80, + 38, + 85, + 189, + 140, + 246, + 115, + 75, + 9, + 28, + 224, + 57, + 163, + 26, + 24, + 180, + 31, + 33, + 200, + 24, + 29, + 192, + 162, + 54, + 246, + 169, + 247, + 250, + 76, + 183, + 186, + 212, + 0, + 249, + 91, + 242, + 187, + 35, + 224, + 7, + 242, + 153, + 51, + 1, + 104, + 142, + 37, + 203, + 8, + 192, + 239, + 206, + 94, + 190, + 73, + 19, + 235, + 50, + 246, + 106, + 34, + 67, + 200, + 17, + 86, + 86, + 20, + 84, + 63, + 242, + 195, + 208, + 208, + 128, + 20, + 225, + 12, + 183, + 187, + 0, + 50, + 212, + 187, + 77, + 64, + 76, + 221, + 140, + 4, + 199, + 18, + 250, + 139, + 252, + 21, + 17, + 5, + 34, + 247, + 184, + 64, + 16, + 119, + 164, + 210, + 0, + 110, + 35, + 74, + 211, + 147, + 97, + 177, + 225, + 207, + 185, + 3, + 17, + 222, + 121, + 93, + 194, + 28, + 12, + 195, + 242, + 54, + 65, + 22, + 186, + 63, + 93, + 134, + 44, + 79, + 49, + 205, + 75, + 94, + 52, + 79, + 21, + 24, + 1, + 99, + 210, + 47, + 113, + 230, + 65, + 181, + 163, + 167, + 139, + 152, + 18, + 202, + 96, + 58, + 101, + 113, + 13, + 186, + 178, + 129, + 140, + 177, + 159, + 58, + 237, + 44, + 54, + 15, + 81, + 51, + 238, + 183, + 226, + 113, + 22, + 155, + 75, + 82, + 213, + 59, + 52, + 145, + 228, + 36, + 91, + 40, + 240, + 77, + 38, + 68, + 7, + 226, + 110, + 171, + 129, + 178, + 160, + 58, + 228, + 17, + 131, + 87, + 203, + 96, + 30, + 252, + 199, + 37, + 76, + 46, + 114, + 8, + 158, + 212, + 207, + 53, + 234, + 47, + 8, + 50, + 68, + 196, + 187, + 50, + 36, + 146, + 154, + 92, + 4, + 127, + 160, + 142, + 13, + 176, + 169, + 188, + 98, + 165, + 231, + 88, + 150, + 0, + 244, + 16, + 227, + 6, + 54, + 210, + 226, + 147, + 160, + 55, + 102, + 243, + 64, + 181, + 82, + 108, + 172, + 223, + 95, + 91, + 13, + 164, + 152, + 31, + 88, + 235, + 30, + 63, + 104, + 192, + 177, + 106, + 149, + 152, + 34, + 11, + 148, + 127, + 103, + 115, + 56, + 39, + 149, + 45, + 246, + 60, + 70, + 255, + 62, + 66, + 225, + 243, + 154, + 184, + 159, + 195, + 45, + 89, + 205, + 12, + 164, + 185, + 31, + 146, + 194, + 185, + 203, + 81, + 21, + 140, + 31, + 154, + 183, + 35, + 243, + 57, + 169, + 3, + 230, + 76, + 198, + 149, + 27, + 136, + 254, + 130, + 85, + 130, + 91, + 135, + 94, + 26, + 214, + 6, + 189, + 86, + 194, + 119, + 197, + 107, + 96, + 10, + 29, + 253, + 61, + 91, + 100, + 40, + 202, + 161, + 27, + 238, + 184, + 62, + 120, + 127, + 67, + 122, + 166, + 74, + 80, + 111, + 124, + 23, + 34, + 10, + 82, + 117, + 169, + 64, + 63, + 199, + 115, + 77, + 182, + 243, + 179, + 45, + 167, + 97, + 67, + 202, + 166, + 240, + 50, + 8, + 255, + 129, + 156, + 32, + 52, + 65, + 133, + 68, + 67, + 16, + 89, + 239, + 18, + 61, + 10, + 172, + 0, + 161, + 83, + 193, + 50, + 137, + 33, + 94, + 43, + 208, + 213, + 238, + 162, + 158, + 152, + 45, + 185, + 108, + 36, + 179, + 167, + 133, + 233, + 31, + 74, + 144, + 185, + 0, + 174, + 100, + 200, + 61, + 222, + 176, + 89, + 197, + 84, + 6, + 241, + 27, + 176, + 52, + 28, + 175, + 80, + 141, + 78, + 219, + 101, + 46, + 216, + 75, + 199, + 84, + 192, + 62, + 105, + 119, + 74, + 196, + 158, + 171, + 175, + 42, + 224, + 20, + 139, + 162, + 157, + 141, + 0, + 63, + 232, + 162, + 50, + 129, + 17, + 60, + 152, + 84, + 187, + 228, + 47, + 16, + 116, + 112, + 26, + 102, + 112, + 178, + 132, + 169, + 73, + 4, + 234, + 26, + 36, + 210, + 18, + 32, + 172, + 220, + 228, + 58, + 59, + 179, + 66, + 50, + 186, + 34, + 7, + 169, + 155, + 139, + 107, + 134, + 87, + 74, + 182, + 235, + 246, + 180, + 105, + 255, + 74, + 68, + 165, + 117, + 21, + 100, + 10, + 189, + 172, + 176, + 61, + 12, + 170, + 156, + 35, + 216, + 74, + 112, + 238, + 209, + 58, + 206, + 13, + 70, + 46, + 156, + 198, + 47, + 81, + 249, + 26, + 78, + 89, + 206, + 161, + 140, + 21, + 62, + 129, + 115, + 227, + 196, + 43, + 76, + 154, + 177, + 69, + 66, + 212, + 229, + 97, + 238, + 11, + 61, + 0, + 172, + 35, + 49, + 191, + 142, + 215, + 166, + 96, + 40, + 106, + 253, + 1, + 235, + 3, + 243, + 30, + 108, + 233, + 75, + 20, + 64, + 11, + 0, + 40, + 138, + 251, + 108, + 41, + 71, + 36, + 43, + 35, + 154, + 63, + 217, + 187, + 245, + 6, + 102, + 251, + 234, + 93, + 33, + 81, + 172, + 234, + 141, + 237, + 38, + 170, + 229, + 101, + 48, + 206, + 19, + 179, + 139, + 241, + 135, + 142, + 56, + 51, + 51, + 108, + 215, + 128, + 140, + 238, + 227, + 73, + 205, + 242, + 124, + 114, + 77, + 45, + 234, + 153, + 152, + 22, + 194, + 62, + 13, + 104, + 52, + 186, + 206, + 0, + 131, + 48, + 254, + 54, + 75, + 87, + 26, + 61, + 126, + 192, + 127, + 38, + 65, + 250, + 241, + 190, + 238, + 5, + 98, + 241, + 221, + 253, + 51, + 192, + 212, + 32, + 168, + 231, + 22, + 87, + 26, + 236, + 239, + 75, + 79, + 107, + 160, + 194, + 247, + 120, + 215, + 103, + 105, + 6, + 168, + 198, + 202, + 140, + 247, + 13, + 66, + 238, + 177, + 146, + 173, + 174, + 23, + 87, + 177, + 87, + 96, + 9, + 235, + 144, + 39, + 73, + 59, + 87, + 0, + 12, + 210, + 2, + 226, + 237, + 110, + 86, + 155, + 81, + 46, + 178, + 219, + 133, + 187, + 236, + 251, + 225, + 208, + 139, + 253, + 15, + 204, + 231, + 24, + 161, + 117, + 109, + 123, + 43, + 233, + 95, + 115, + 142, + 35, + 71, + 117, + 207, + 177, + 244, + 119, + 31, + 187, + 111, + 95, + 158, + 193, + 13, + 158, + 44, + 182, + 67, + 226, + 91, + 114, + 125, + 96, + 166, + 98, + 123, + 211, + 182, + 42, + 239, + 220, + 253, + 147, + 117, + 69, + 219, + 240, + 204, + 81, + 73, + 243, + 46, + 169, + 121, + 42, + 180, + 96, + 122, + 87, + 90, + 229, + 120, + 117, + 127, + 2, + 70, + 168, + 157, + 46, + 21, + 103, + 78, + 184, + 10, + 42, + 115, + 150, + 3, + 33, + 121, + 70, + 242, + 115, + 112, + 153, + 222, + 210, + 247, + 250, + 78, + 101, + 107, + 29, + 53, + 34, + 222, + 89, + 158, + 96, + 52, + 78, + 135, + 162, + 86, + 233, + 60, + 122, + 124, + 179, + 126, + 78, + 23, + 222, + 9, + 198, + 160, + 248, + 152, + 37, + 95, + 47, + 88, + 98, + 155, + 214, + 156, + 181, + 250, + 4, + 86, + 124, + 223, + 137, + 99, + 178, + 19, + 226, + 114, + 8, + 160, + 122, + 44, + 138, + 53, + 34, + 177, + 29, + 228, + 171, + 230, + 109, + 21, + 179, + 30, + 186, + 108, + 255, + 101, + 217, + 139, + 47, + 254, + 235, + 243, + 133, + 69, + 177, + 235, + 113, + 205, + 141, + 108, + 206, + 98, + 243, + 79, + 176, + 21, + 133, + 128, + 190, + 58, + 190, + 216, + 74, + 156, + 135, + 106, + 22, + 125, + 183, + 94, + 41, + 197, + 184, + 138, + 129, + 113, + 95, + 202, + 170, + 190, + 67, + 219, + 71, + 106, + 229, + 83, + 81, + 181, + 165, + 161, + 195, + 222, + 113, + 13, + 149, + 40, + 254, + 56, + 202, + 52, + 7, + 230, + 46, + 71, + 111, + 75, + 179, + 126, + 86, + 48, + 47, + 73, + 30, + 128, + 22, + 58, + 201, + 120, + 189, + 185, + 231, + 101, + 229, + 56, + 185, + 126, + 228, + 226, + 122, + 235, + 130, + 114, + 23, + 242, + 111, + 221, + 19, + 27, + 41, + 242, + 195, + 41, + 105, + 181, + 139, + 204, + 134, + 250, + 141, + 83, + 75, + 174, + 185, + 26, + 67, + 203, + 95, + 186, + 228, + 136, + 20, + 178, + 93, + 126, + 251, + 92, + 6, + 235, + 224, + 120, + 68, + 176, + 51, + 174, + 95, + 192, + 172, + 230, + 12, + 194, + 77, + 4, + 8, + 167, + 169, + 168, + 87, + 142, + 6, + 229, + 221, + 116, + 47, + 165, + 13, + 229, + 29, + 21, + 47, + 26, + 16, + 253, + 92, + 53, + 30, + 144, + 122, + 27, + 32, + 146, + 180, + 210, + 225, + 177, + 171, + 116, + 75, + 55, + 109, + 187, + 115, + 93, + 87, + 144, + 111, + 241, + 150, + 48, + 249, + 83, + 28, + 132, + 82, + 79, + 245, + 98, + 107, + 57, + 56, + 242, + 236, + 217, + 220, + 54, + 71, + 34, + 69, + 10, + 208, + 194, + 223, + 121, + 125, + 223, + 67, + 41, + 220, + 248, + 188, + 128, + 231, + 132, + 115, + 132, + 140, + 20, + 241, + 234, + 2, + 142, + 10, + 169, + 80, + 226, + 148, + 15, + 6, + 22, + 158, + 50, + 8, + 239, + 6, + 76, + 51, + 52, + 10, + 49, + 101, + 134, + 40, + 30, + 94, + 159, + 74, + 166, + 12, + 155, + 143, + 21, + 8, + 103, + 250, + 161, + 111, + 196, + 71, + 199, + 66, + 200, + 198, + 199, + 236, + 137, + 5, + 1, + 111, + 171, + 250, + 247, + 15, + 130, + 175, + 97, + 19, + 137, + 62, + 51, + 55, + 45, + 99, + 70, + 130, + 72, + 127, + 12, + 102, + 29, + 238, + 188, + 90, + 78, + 129, + 45, + 230, + 171, + 187, + 87, + 141, + 163, + 54, + 34, + 244, + 45, + 221, + 168, + 1, + 168, + 105, + 163, + 101, + 253, + 82, + 177, + 71, + 238, + 102, + 20, + 5, + 40, + 13, + 20, + 113, + 57, + 226, + 56, + 56, + 35, + 30, + 163, + 158, + 206, + 212, + 250, + 13, + 185, + 163, + 169, + 132, + 132, + 86, + 176, + 0, + 13, + 46, + 102, + 129, + 39, + 30, + 160, + 92, + 100, + 241, + 171, + 52, + 213, + 1, + 67, + 234, + 131, + 237, + 141, + 180, + 173, + 136, + 63, + 41, + 171, + 223, + 27, + 94, + 87, + 28, + 124, + 204, + 180, + 29, + 174, + 153, + 164, + 167, + 99, + 30, + 61, + 98, + 250, + 239, + 24, + 234, + 172, + 46, + 184, + 62, + 29, + 248, + 243, + 5, + 76, + 137, + 106, + 133, + 233, + 81, + 230, + 8, + 167, + 172, + 26, + 236, + 178, + 80, + 227, + 95, + 92, + 4, + 60, + 54, + 16, + 54, + 107, + 174, + 94, + 93, + 106, + 139, + 158, + 190, + 226, + 233, + 90, + 209, + 164, + 49, + 130, + 216, + 196, + 65, + 32, + 195, + 5, + 56, + 89, + 208, + 161, + 64, + 175, + 169, + 81, + 143, + 140, + 118, + 142, + 93, + 166, + 204, + 86, + 178, + 6, + 29, + 250, + 190, + 107, + 11, + 55, + 137, + 82, + 33, + 232, + 115, + 157, + 209, + 87, + 177, + 79, + 150, + 112, + 88, + 97, + 78, + 59, + 79, + 120, + 87, + 54, + 130, + 132, + 200, + 3, + 199, + 194, + 240, + 158, + 124, + 241, + 158, + 150, + 160, + 41, + 61, + 200, + 44, + 48, + 194, + 44, + 90, + 141, + 97, + 232, + 74, + 104, + 8, + 7, + 67, + 185, + 189, + 255, + 66, + 210, + 244, + 75, + 242, + 242, + 36, + 199, + 13, + 47, + 192, + 158, + 219, + 4, + 78, + 185, + 113, + 133, + 15, + 219, + 50, + 45, + 28, + 250, + 171, + 226, + 221, + 150, + 237, + 164, + 78, + 9, + 20, + 219, + 129, + 24, + 211, + 216, + 224, + 133, + 142, + 193, + 184, + 101, + 87, + 123, + 1, + 253, + 23, + 220, + 1, + 63, + 66, + 60, + 250, + 78, + 247, + 50, + 250, + 27, + 154, + 179, + 106, + 240, + 183, + 160, + 245, + 166, + 195, + 238, + 211, + 148, + 37, + 10, + 33, + 112, + 165, + 176, + 126, + 250, + 49, + 5, + 4, + 29, + 118, + 174, + 127, + 75, + 29, + 199, + 228, + 223, + 185, + 232, + 13, + 73, + 39, + 58, + 94, + 167, + 93, + 13, + 33, + 137, + 97, + 87, + 145, + 98, + 223, + 186, + 177, + 146, + 34, + 7, + 182, + 153, + 38, + 77, + 224, + 233, + 37, + 43, + 20, + 69, + 201, + 230, + 58, + 190, + 186, + 176, + 166, + 158, + 216, + 43, + 117, + 36, + 5, + 24, + 138, + 76, + 59, + 93, + 59, + 68, + 48, + 220, + 82, + 130, + 145, + 210, + 55, + 155, + 38, + 88, + 229, + 117, + 105, + 94, + 202, + 122, + 26, + 85, + 67, + 211, + 11, + 7, + 7, + 46, + 94, + 67, + 157, + 186, + 12, + 139, + 134, + 205, + 68, + 244, + 46, + 186, + 139, + 57, + 91, + 133, + 33, + 14, + 201, + 105, + 235, + 186, + 222, + 85, + 138, + 183, + 75, + 103, + 76, + 249, + 92, + 235, + 114, + 89, + 109, + 234, + 41, + 24, + 120, + 68, + 98, + 23, + 175, + 101, + 187, + 253, + 163, + 145, + 10, + 90, + 11, + 75, + 80, + 110, + 92, + 69, + 219, + 235, + 43, + 235, + 4, + 225, + 53, + 22, + 231, + 20, + 230, + 209, + 132, + 134, + 234, + 1, + 23, + 92, + 160, + 211, + 254, + 143, + 36, + 204, + 79, + 255, + 5, + 92, + 99, + 48, + 203, + 232, + 234, + 122, + 88, + 191, + 247, + 65, + 216, + 145, + 130, + 84, + 106, + 193, + 196, + 200, + 167, + 110, + 114, + 49, + 179, + 154, + 76, + 36, + 251, + 188, + 100, + 83, + 136, + 94, + 0, + 168, + 164, + 240, + 253, + 253, + 95, + 17, + 245, + 62, + 235, + 20, + 68, + 9, + 101, + 89, + 198, + 163, + 23, + 35, + 14, + 97, + 90, + 196, + 144, + 132, + 139, + 76, + 10, + 82, + 35, + 80, + 129, + 72, + 94, + 218, + 4, + 24, + 246, + 33, + 41, + 11, + 57, + 202, + 79, + 163, + 146, + 86, + 185, + 112, + 12, + 174, + 5, + 218, + 243, + 45, + 3, + 61, + 250, + 55, + 233, + 30, + 5, + 213, + 166, + 247, + 27, + 76, + 40, + 96, + 124, + 26, + 53, + 36, + 56, + 14, + 118, + 109, + 209, + 159, + 96, + 136, + 241, + 121, + 91, + 50, + 109, + 165, + 95, + 62, + 228, + 12, + 240, + 96, + 153, + 181, + 58, + 94, + 175, + 65, + 174, + 64, + 78, + 50, + 124, + 153, + 61, + 176, + 91, + 56, + 107, + 63, + 232, + 14, + 65, + 192, + 91, + 102, + 121, + 179, + 11, + 186, + 230, + 242, + 130, + 123, + 98, + 19, + 204, + 127, + 56, + 47, + 168, + 173, + 62, + 62, + 3, + 15, + 182, + 87, + 196, + 97, + 205, + 174, + 98, + 253, + 16, + 39, + 90, + 76, + 229, + 194, + 157, + 255, + 209, + 165, + 26, + 208, + 53, + 129, + 196, + 120, + 184, + 160, + 122, + 191, + 249, + 108, + 140, + 223, + 61, + 153, + 216, + 253, + 172, + 189, + 168, + 148, + 2, + 103, + 81, + 67, + 235, + 21, + 16, + 9, + 186, + 253, + 143, + 179, + 218, + 83, + 71, + 120, + 123, + 131, + 6, + 154, + 53, + 151, + 59, + 179, + 251, + 72, + 121, + 201, + 152, + 79, + 84, + 190, + 178, + 107, + 91, + 49, + 15, + 239, + 80, + 138, + 189, + 67, + 176, + 254, + 129, + 51, + 132, + 57, + 250, + 116, + 206, + 25, + 115, + 71, + 199, + 34, + 81, + 196, + 66, + 98, + 199, + 247, + 235, + 93, + 216, + 199, + 6, + 65, + 199, + 191, + 90, + 72, + 19, + 192, + 120, + 197, + 133, + 141, + 140, + 71, + 242, + 206, + 183, + 178, + 57, + 194, + 216, + 67, + 53, + 98, + 123, + 194, + 191, + 219, + 252, + 165, + 81, + 121, + 33, + 214, + 202, + 232, + 85, + 44, + 0, + 223, + 246, + 232, + 14, + 44, + 127, + 8, + 190, + 240, + 3, + 71, + 29, + 242, + 135, + 154, + 109, + 22, + 184, + 103, + 184, + 141, + 191, + 48, + 105, + 35, + 10, + 118, + 10, + 110, + 72, + 115, + 245, + 225, + 44, + 7, + 29, + 73, + 96, + 145, + 171, + 152, + 2, + 235, + 162, + 154, + 136, + 81, + 86, + 57, + 109, + 20, + 183, + 143, + 181, + 11, + 122, + 93, + 22, + 20, + 117, + 64, + 158, + 167, + 222, + 194, + 114, + 51, + 147, + 170, + 64, + 26, + 90, + 137, + 225, + 220, + 195, + 146, + 34, + 200, + 244, + 15, + 247, + 204, + 233, + 32, + 143, + 22, + 110, + 115, + 98, + 175, + 59, + 157, + 2, + 176, + 149, + 56, + 82, + 48, + 128, + 239, + 61, + 175, + 204, + 97, + 26, + 161, + 135, + 48, + 220, + 22, + 103, + 166, + 56, + 138, + 67, + 175, + 104, + 158, + 217, + 86, + 12, + 246, + 153, + 183, + 165, + 79, + 107, + 37, + 214, + 78, + 203, + 137, + 118, + 190, + 214, + 9, + 76, + 28, + 8, + 196, + 134, + 215, + 119, + 27, + 156, + 164, + 61, + 114, + 151, + 72, + 242, + 229, + 101, + 253, + 255, + 218, + 105, + 148, + 80, + 141, + 33, + 148, + 34, + 25, + 99, + 243, + 6, + 0, + 241, + 216, + 123, + 41, + 38, + 109, + 254, + 200, + 41, + 145, + 197, + 74, + 195, + 32, + 244, + 137, + 9, + 90, + 169, + 7, + 221, + 205, + 177, + 238, + 159, + 203, + 32, + 33, + 111, + 81, + 234, + 94, + 6, + 174, + 66, + 141, + 43, + 21, + 178, + 225, + 90, + 36, + 254, + 8, + 27, + 162, + 79, + 196, + 6, + 120, + 104, + 117, + 240, + 92, + 205, + 228, + 2, + 70, + 221, + 232, + 156, + 101, + 76, + 141, + 200, + 97, + 199, + 253, + 22, + 175, + 84, + 79, + 247, + 130, + 246, + 13, + 169, + 242, + 70, + 226, + 1, + 90, + 58, + 4, + 43, + 69, + 81, + 100, + 48, + 199, + 142, + 253, + 165, + 10, + 92, + 120, + 124, + 145, + 82, + 187, + 123, + 109, + 56, + 124, + 67, + 200, + 113, + 161, + 52, + 133, + 171, + 13, + 98, + 126, + 130, + 155, + 171, + 167, + 186, + 245, + 220, + 239, + 102, + 197, + 82, + 209, + 155, + 177, + 164, + 89, + 107, + 124, + 59, + 80, + 188, + 189, + 113, + 105, + 50, + 212, + 159, + 223, + 229, + 152, + 29, + 148, + 189, + 117, + 113, + 129, + 0, + 221, + 181, + 77, + 241, + 106, + 56, + 250, + 153, + 45, + 172, + 61, + 134, + 23, + 20, + 249, + 108, + 146, + 153, + 159, + 40, + 62, + 65, + 255, + 118, + 96, + 76, + 99, + 186, + 215, + 165, + 15, + 145, + 126, + 145, + 69, + 35, + 110, + 125, + 1, + 93, + 175, + 154, + 62, + 24, + 200, + 94, + 233, + 249, + 30, + 109, + 163, + 41, + 176, + 76, + 161, + 84, + 182, + 14, + 155, + 12, + 249, + 14, + 115, + 82, + 61, + 146, + 57, + 208, + 15, + 44, + 45, + 101, + 230, + 81, + 80, + 8, + 53, + 97, + 193, + 84, + 14, + 38, + 141, + 224, + 151, + 233, + 58, + 144, + 156, + 56, + 209, + 181, + 78, + 193, + 163, + 35, + 11, + 244, + 160, + 237, + 110, + 249, + 149, + 16, + 69, + 13, + 253, + 4, + 9, + 79, + 55, + 94, + 113, + 249, + 183, + 48, + 199, + 201, + 249, + 115, + 242, + 2, + 67, + 86, + 190, + 11, + 172, + 45, + 219, + 94, + 146, + 213, + 58, + 245, + 102, + 160, + 175, + 182, + 98, + 20, + 127, + 17, + 27, + 138, + 69, + 6, + 244, + 178, + 40, + 42, + 245, + 192, + 183, + 26, + 154, + 154, + 19, + 20, + 123, + 36, + 163, + 155, + 51, + 231, + 221, + 152, + 177, + 228, + 249, + 59, + 72, + 109, + 83, + 242, + 92, + 6, + 146, + 119, + 135, + 72, + 115, + 175, + 220, + 120, + 131, + 26, + 22, + 249, + 40, + 21, + 79, + 231, + 49, + 229, + 156, + 234, + 93, + 208, + 67, + 134, + 28, + 120, + 138, + 240, + 237, + 181, + 169, + 185, + 161, + 200, + 164, + 130, + 30, + 127, + 66, + 7, + 31, + 42, + 77, + 191, + 128, + 33, + 247, + 0, + 88, + 212, + 173, + 239, + 49, + 128, + 96, + 155, + 124, + 169, + 40, + 87, + 107, + 170, + 238, + 137, + 27, + 7, + 56, + 223, + 84, + 82, + 211, + 215, + 68, + 81, + 160, + 101, + 39, + 169, + 3, + 8, + 244, + 118, + 2, + 213, + 114, + 189, + 146, + 228, + 51, + 174, + 0, + 124, + 98, + 14, + 208, + 93, + 10, + 62, + 116, + 212, + 231, + 112, + 6, + 159, + 83, + 90, + 48, + 152, + 107, + 142, + 182, + 75, + 53, + 84, + 192, + 80, + 240, + 108, + 200, + 28, + 238, + 98, + 124, + 88, + 52, + 183, + 102, + 19, + 213, + 240, + 249, + 135, + 8, + 52, + 252, + 24, + 9, + 35, + 13, + 159, + 100, + 115, + 167, + 198, + 62, + 44, + 170, + 109, + 101, + 61, + 177, + 113, + 20, + 171, + 49, + 155, + 125, + 194, + 112, + 223, + 153, + 64, + 137, + 171, + 102, + 112, + 153, + 31, + 168, + 97, + 0, + 22, + 171, + 6, + 170, + 134, + 225, + 136, + 183, + 49, + 215, + 106, + 35, + 127, + 179, + 117, + 122, + 16, + 239, + 210, + 145, + 222, + 52, + 237, + 214, + 65, + 12, + 146, + 188, + 149, + 43, + 107, + 151, + 94, + 144, + 221, + 53, + 78, + 189, + 11, + 53, + 190, + 213, + 64, + 62, + 166, + 10, + 138, + 24, + 243, + 209, + 239, + 76, + 127, + 0, + 86, + 228, + 242, + 212, + 218, + 134, + 174, + 192, + 40, + 89, + 246, + 124, + 19, + 141, + 142, + 68, + 63, + 218, + 30, + 177, + 117, + 122, + 134, + 131, + 21, + 57, + 100, + 67, + 0, + 32, + 217, + 6, + 110, + 5, + 73, + 162, + 227, + 186, + 153, + 50, + 105, + 183, + 60, + 19, + 175, + 224, + 10, + 193, + 169, + 168, + 134, + 138, + 8, + 237, + 33, + 129, + 44, + 36, + 166, + 127, + 106, + 189, + 167, + 176, + 88, + 116, + 148, + 14, + 13, + 210, + 128, + 121, + 111, + 140, + 247, + 206, + 192, + 239, + 252, + 186, + 219, + 90, + 85, + 145, + 9, + 59, + 255, + 145, + 44, + 41, + 175, + 11, + 30, + 111, + 26, + 182, + 164, + 182, + 78, + 56, + 137, + 96, + 139, + 245, + 113, + 167, + 64, + 1, + 227, + 191, + 193, + 211, + 148, + 13, + 183, + 223, + 184, + 63, + 121, + 25, + 77, + 161, + 65, + 134, + 138, + 8, + 239, + 89, + 235, + 198, + 43, + 84, + 183, + 246, + 67, + 136, + 17, + 254, + 24, + 183, + 70, + 229, + 186, + 139, + 179, + 58, + 154, + 66, + 123, + 158, + 88, + 0, + 19, + 171, + 47, + 66, + 13, + 105, + 104, + 180, + 34, + 167, + 173, + 17, + 246, + 239, + 19, + 113, + 49, + 60, + 166, + 16, + 231, + 18, + 14, + 224, + 8, + 224, + 188, + 67, + 217, + 53, + 116, + 174, + 124, + 12, + 32, + 142, + 8, + 81, + 14, + 142, + 153, + 67, + 180, + 122, + 191, + 17, + 63, + 111, + 67, + 52, + 168, + 208, + 8, + 109, + 226, + 24, + 68, + 24, + 84, + 67, + 227, + 209, + 140, + 25, + 83, + 161, + 50, + 29, + 165, + 214, + 83, + 41, + 9, + 74, + 206, + 11, + 16, + 141, + 73, + 16, + 37, + 154, + 35, + 255, + 239, + 23, + 2, + 133, + 161, + 192, + 185, + 236, + 123, + 94, + 195, + 114, + 189, + 3, + 15, + 113, + 122, + 170, + 105, + 226, + 159, + 156, + 21, + 68, + 87, + 21, + 69, + 221, + 3, + 70, + 120, + 233, + 148, + 97, + 64, + 5, + 144, + 27, + 53, + 59, + 127, + 77, + 209, + 228, + 0, + 244, + 51, + 45, + 152, + 53, + 106, + 64, + 30, + 102, + 47, + 55, + 209, + 117, + 40, + 18, + 69, + 136, + 64, + 124, + 235, + 10, + 72, + 205, + 223, + 126, + 184, + 94, + 246, + 22, + 82, + 48, + 206, + 51, + 198, + 35, + 163, + 81, + 158, + 238, + 150, + 250, + 91, + 215, + 117, + 137, + 139, + 65, + 56, + 102, + 170, + 214, + 51, + 164, + 140, + 236, + 237, + 157, + 5, + 176, + 22, + 59, + 65, + 89, + 239, + 12, + 18, + 15, + 202, + 255, + 197, + 92, + 191, + 62, + 243, + 123, + 177, + 23, + 199, + 184, + 41, + 199, + 32, + 91, + 243, + 129, + 219, + 86, + 118, + 241, + 116, + 240, + 130, + 149, + 57, + 50, + 174, + 152, + 189, + 215, + 118, + 175, + 251, + 204, + 156, + 131, + 106, + 49, + 105, + 88, + 56, + 59, + 33, + 246, + 73, + 10, + 149, + 204, + 192, + 97, + 133, + 138, + 241, + 34, + 189, + 62, + 222, + 208, + 199, + 242, + 156, + 113, + 65, + 55, + 4, + 154, + 28, + 184, + 64, + 164, + 150, + 224, + 197, + 146, + 50, + 124, + 20, + 167, + 227, + 239, + 189, + 1, + 248, + 54, + 79, + 44, + 199, + 215, + 225, + 134, + 22, + 84, + 197, + 168, + 30, + 79, + 18, + 70, + 216, + 79, + 37, + 114, + 219, + 77, + 211, + 208, + 8, + 193, + 139, + 56, + 124, + 131, + 108, + 245, + 14, + 203, + 101, + 189, + 182, + 194, + 79, + 216, + 230, + 79, + 190, + 107, + 124, + 118, + 222, + 234, + 51, + 91, + 1, + 76, + 180, + 230, + 65, + 144, + 107, + 150, + 168, + 248, + 180, + 72, + 108, + 111, + 208, + 166, + 159, + 32, + 111, + 125, + 222, + 114, + 127, + 100, + 250, + 247, + 178, + 4, + 163, + 85, + 2, + 179, + 239, + 95, + 10, + 39, + 242, + 75, + 41, + 28, + 180, + 159, + 205, + 175, + 84, + 42, + 169, + 240, + 57, + 146, + 130, + 205, + 245, + 161, + 23, + 139, + 153, + 16, + 52, + 216, + 188, + 216, + 36, + 106, + 111, + 123, + 153, + 123, + 8, + 103, + 23, + 194, + 188, + 50, + 133, + 177, + 83, + 6, + 47, + 230, + 128, + 136, + 124, + 121, + 133, + 175, + 32, + 228, + 58, + 201, + 149, + 19, + 98, + 33, + 89, + 210, + 188, + 162, + 158, + 128, + 129, + 80, + 57, + 104, + 64, + 133, + 91, + 131, + 108, + 116, + 80, + 4, + 119, + 60, + 236, + 71, + 248, + 141, + 148, + 49, + 235, + 31, + 194, + 172, + 128, + 252, + 163, + 155, + 160, + 193, + 12, + 250, + 20, + 3, + 18, + 148, + 51, + 172, + 59, + 144, + 230, + 231, + 35, + 14, + 239, + 16, + 101, + 22, + 94, + 244, + 124, + 238, + 22, + 11, + 89, + 140, + 136, + 85, + 251, + 242, + 110, + 98, + 189, + 132, + 69, + 209, + 88, + 224, + 33, + 72, + 164, + 39, + 71, + 207, + 101, + 98, + 102, + 102, + 246, + 3, + 34, + 212, + 102, + 244, + 84, + 28, + 49, + 83, + 216, + 194, + 159, + 131, + 171, + 235, + 232, + 140, + 116, + 46, + 86, + 27, + 215, + 67, + 57, + 55, + 156, + 136, + 144, + 166, + 192, + 63, + 226, + 102, + 191, + 45, + 44, + 160, + 57, + 20, + 101, + 81, + 121, + 13, + 170, + 150, + 216, + 73, + 183, + 101, + 252, + 174, + 73, + 189, + 138, + 142, + 8, + 0, + 102, + 143, + 59, + 43, + 13, + 205, + 106, + 12, + 106, + 203, + 241, + 146, + 47, + 140, + 14, + 8, + 39, + 74, + 68, + 108, + 40, + 62, + 166, + 150, + 43, + 165, + 110, + 108, + 11, + 220, + 72, + 119, + 181, + 36, + 62, + 27, + 18, + 151, + 154, + 136, + 170, + 237, + 12, + 80, + 183, + 131, + 47, + 145, + 0, + 225, + 53, + 15, + 100, + 55, + 189, + 200, + 187, + 171, + 63, + 101, + 100, + 88, + 225, + 249, + 160, + 183, + 229, + 27, + 128, + 130, + 77, + 132, + 237, + 173, + 197, + 65, + 70, + 132, + 230, + 166, + 154, + 199, + 37, + 179, + 77, + 198, + 67, + 183, + 162, + 246, + 28, + 250, + 196, + 235, + 102, + 1, + 107, + 121, + 69, + 155, + 146, + 90, + 180, + 126, + 59, + 206, + 96, + 159, + 165, + 168, + 74, + 178, + 54, + 15, + 24, + 129, + 100, + 158, + 23, + 4, + 109, + 152, + 64, + 164, + 173, + 114, + 29, + 154, + 123, + 48, + 5, + 136, + 146, + 50, + 127, + 95, + 146, + 94, + 105, + 129, + 203, + 101, + 152, + 94, + 187, + 48, + 132, + 4, + 102, + 195, + 9, + 85, + 238, + 143, + 113, + 190, + 126, + 217, + 43, + 216, + 207, + 107, + 133, + 97, + 48, + 110, + 13, + 235, + 208, + 143, + 105, + 56, + 98, + 204, + 112, + 13, + 18, + 59, + 216, + 157, + 46, + 39, + 227, + 219, + 51, + 36, + 44, + 255, + 7, + 105, + 152, + 33, + 173, + 177, + 161, + 106, + 172, + 206, + 1, + 232, + 252, + 184, + 14, + 160, + 134, + 196, + 125, + 199, + 165, + 168, + 211, + 231, + 53, + 178, + 15, + 60, + 42, + 113, + 80, + 166, + 238, + 218, + 97, + 90, + 41, + 185, + 131, + 113, + 245, + 100, + 109, + 134, + 223, + 210, + 145, + 185, + 2, + 112, + 78, + 49, + 78, + 112, + 75, + 79, + 86, + 217, + 222, + 28, + 2, + 123, + 54, + 213, + 233, + 35, + 121, + 231, + 211, + 68, + 171, + 76, + 117, + 61, + 150, + 217, + 143, + 225, + 86, + 231, + 41, + 8, + 131, + 25, + 118, + 144, + 178, + 103, + 62, + 49, + 40, + 187, + 247, + 221, + 9, + 195, + 241, + 45, + 9, + 153, + 247, + 140, + 130, + 138, + 120, + 253, + 94, + 255, + 82, + 161, + 146, + 255, + 100, + 75, + 101, + 55, + 27, + 228, + 4, + 206, + 114, + 23, + 48, + 199, + 88, + 54, + 87, + 191, + 152, + 20, + 85, + 182, + 144, + 87, + 109, + 2, + 68, + 152, + 30, + 198, + 103, + 182, + 120, + 206, + 100, + 173, + 112, + 158, + 109, + 76, + 39, + 158, + 114, + 65, + 173, + 84, + 28, + 116, + 8, + 214, + 104, + 233, + 251, + 193, + 193, + 2, + 252, + 239, + 123, + 217, + 149, + 1, + 39, + 214, + 179, + 20, + 168, + 21, + 122, + 217, + 235, + 196, + 123, + 90, + 172, + 221, + 139, + 104, + 11, + 120, + 72, + 84, + 177, + 149, + 180, + 202, + 17, + 3, + 118, + 243, + 156, + 255, + 50, + 91, + 26, + 23, + 251, + 83, + 77, + 7, + 52, + 131, + 150, + 94, + 79, + 255, + 9, + 174, + 164, + 4, + 194, + 39, + 65, + 180, + 174, + 29, + 96, + 226, + 90, + 196, + 232, + 211, + 10, + 58, + 112, + 65, + 221, + 26, + 6, + 149, + 45, + 130, + 221, + 134, + 230, + 142, + 115, + 135, + 255, + 225, + 110, + 173, + 51, + 180, + 87, + 0, + 34, + 164, + 214, + 97, + 46, + 176, + 153, + 175, + 178, + 86, + 238, + 20, + 6, + 108, + 10, + 107, + 150, + 118, + 210, + 34, + 113, + 231, + 162, + 236, + 200, + 98, + 200, + 146, + 158, + 126, + 75, + 248, + 255, + 25, + 195, + 144, + 119, + 126, + 69, + 104, + 30, + 73, + 19, + 113, + 14, + 170, + 212, + 47, + 37, + 127, + 77, + 85, + 52, + 31, + 33, + 6, + 161, + 93, + 244, + 164, + 184, + 82, + 115, + 153, + 225, + 110, + 29, + 193, + 212, + 139, + 5, + 191, + 184, + 246, + 217, + 76, + 175, + 172, + 1, + 94, + 228, + 70, + 158, + 203, + 95, + 167, + 184, + 7, + 67, + 137, + 93, + 205, + 240, + 194, + 73, + 96, + 2, + 174, + 104, + 148, + 181, + 233, + 133, + 51, + 71, + 100, + 244, + 30, + 131, + 141, + 201, + 8, + 129, + 39, + 0, + 252, + 116, + 46, + 77, + 3, + 34, + 192, + 233, + 147, + 181, + 162, + 44, + 254, + 183, + 117, + 7, + 206, + 161, + 132, + 243, + 150, + 60, + 216, + 12, + 131, + 23, + 116, + 78, + 170, + 35, + 105, + 215, + 186, + 255, + 124, + 88, + 126, + 65, + 144, + 125, + 217, + 64, + 105, + 48, + 50, + 139, + 11, + 166, + 55, + 255, + 3, + 17, + 232, + 47, + 83, + 220, + 251, + 126, + 223, + 137, + 131, + 27, + 31, + 242, + 166, + 225, + 56, + 94, + 252, + 27, + 123, + 156, + 3, + 131, + 55, + 26, + 24, + 173, + 225, + 170, + 160, + 243, + 92, + 93, + 22, + 244, + 117, + 174, + 34, + 152, + 248, + 72, + 176, + 3, + 60, + 92, + 21, + 218, + 59, + 98, + 104, + 80, + 5, + 90, + 20, + 65, + 200, + 1, + 74, + 136, + 178, + 192, + 69, + 132, + 153, + 82, + 194, + 241, + 250, + 192, + 149, + 54, + 24, + 64, + 153, + 7, + 135, + 73, + 30, + 227, + 143, + 104, + 186, + 144, + 72, + 6, + 187, + 232, + 21, + 104, + 37, + 45, + 197, + 227, + 29, + 215, + 25, + 87, + 104, + 245, + 209, + 127, + 194, + 37, + 219, + 160, + 37, + 14, + 150, + 204, + 118, + 225, + 53, + 61, + 70, + 12, + 174, + 255, + 81, + 100, + 144, + 73, + 170, + 57, + 117, + 220, + 169, + 40, + 19, + 136, + 114, + 204, + 214, + 161, + 125, + 206, + 66, + 68, + 126, + 123, + 192, + 192, + 6, + 34, + 50, + 24, + 178, + 232, + 153, + 59, + 69, + 42, + 202, + 64, + 110, + 96, + 65, + 55, + 102, + 232, + 57, + 154, + 45, + 140, + 210, + 124, + 218, + 168, + 23, + 169, + 181, + 213, + 41, + 131, + 18, + 219, + 132, + 237, + 84, + 222, + 160, + 2, + 107, + 133, + 127, + 57, + 150, + 186, + 143, + 118, + 121, + 86, + 205, + 34, + 244, + 195, + 189, + 211, + 163, + 146, + 120, + 196, + 51, + 53, + 135, + 182, + 6, + 23, + 230, + 65, + 208, + 173, + 206, + 41, + 71, + 18, + 95, + 108, + 222, + 151, + 224, + 178, + 233, + 11, + 143, + 211, + 22, + 88, + 71, + 54, + 254, + 11, + 193, + 11, + 59, + 253, + 236, + 175, + 145, + 180, + 181, + 100, + 47, + 82, + 250, + 162, + 190, + 37, + 105, + 52, + 69, + 29, + 105, + 7, + 250, + 174, + 136, + 90, + 12, + 198, + 19, + 188, + 191, + 187, + 227, + 76, + 112, + 91, + 117, + 179, + 41, + 48, + 130, + 157, + 3, + 198, + 158, + 201, + 239, + 215, + 155, + 77, + 213, + 190, + 91, + 81, + 76, + 195, + 95, + 98, + 69, + 150, + 247, + 227, + 16, + 47, + 122, + 236, + 94, + 204, + 127, + 91, + 62, + 250, + 218, + 0, + 20, + 52, + 119, + 138, + 110, + 126, + 57, + 42, + 243, + 254, + 2, + 102, + 144, + 90, + 91, + 227, + 177, + 223, + 15, + 219, + 88, + 43, + 155, + 31, + 103, + 127, + 173, + 62, + 27, + 165, + 46, + 163, + 204, + 181, + 30, + 155, + 89, + 69, + 219, + 89, + 158, + 201, + 102, + 145, + 134, + 147, + 23, + 34, + 239, + 136, + 80, + 27, + 138, + 240, + 237, + 93, + 45, + 68, + 22, + 227, + 60, + 170, + 189, + 127, + 87, + 88, + 124, + 232, + 71, + 128, + 167, + 82, + 36, + 250, + 47, + 62, + 126, + 198, + 182, + 216, + 201, + 99, + 16, + 215, + 92, + 82, + 81, + 204, + 190, + 183, + 95, + 157, + 154, + 252, + 42, + 96, + 84, + 247, + 32, + 59, + 108, + 65, + 54, + 60, + 173, + 104, + 93, + 0, + 124, + 242, + 106, + 132, + 220, + 237, + 164, + 186, + 84, + 139, + 115, + 158, + 236, + 91, + 11, + 203, + 30, + 219, + 16, + 236, + 238, + 147, + 97, + 64, + 10, + 73, + 144, + 107, + 82, + 21, + 232, + 63, + 5, + 30, + 159, + 94, + 230, + 159, + 184, + 86, + 171, + 140, + 22, + 85, + 134, + 189, + 120, + 76, + 38, + 150, + 62, + 59, + 216, + 78, + 141, + 35, + 69, + 63, + 148, + 10, + 184, + 154, + 59, + 125, + 154, + 91, + 16, + 198, + 21, + 0, + 48, + 28, + 146, + 80, + 161, + 206, + 42, + 82, + 93, + 106, + 206, + 232, + 40, + 65, + 163, + 61, + 250, + 13, + 197, + 219, + 138, + 110, + 152, + 180, + 14, + 231, + 232, + 226, + 214, + 123, + 154, + 59, + 10, + 120, + 130, + 196, + 159, + 92, + 165, + 105, + 107, + 183, + 69, + 89, + 129, + 138, + 63, + 238, + 117, + 59, + 53, + 166, + 92, + 100, + 66, + 54, + 216, + 110, + 39, + 39, + 82, + 38, + 58, + 9, + 59, + 31, + 116, + 28, + 69, + 77, + 137, + 222, + 88, + 199, + 12, + 234, + 143, + 244, + 115, + 128, + 42, + 113, + 112, + 81, + 133, + 54, + 183, + 27, + 14, + 64, + 181, + 194, + 101, + 118, + 214, + 210, + 116, + 207, + 147, + 180, + 60, + 142, + 65, + 183, + 110, + 242, + 194, + 197, + 212, + 165, + 246, + 187, + 23, + 21, + 37, + 148, + 29, + 2, + 127, + 224, + 60, + 159, + 7, + 125, + 125, + 66, + 180, + 91, + 183, + 191, + 219, + 3, + 221, + 159, + 163, + 234, + 60, + 247, + 14, + 72, + 9, + 145, + 3, + 64, + 54, + 148, + 253, + 221, + 53, + 53, + 196, + 247, + 143, + 181, + 137, + 158, + 180, + 134, + 111, + 59, + 204, + 233, + 93, + 83, + 109, + 237, + 134, + 57, + 21, + 239, + 129, + 139, + 96, + 150, + 25, + 72, + 33, + 82, + 45, + 127, + 49, + 45, + 207, + 129, + 108, + 229, + 42, + 243, + 27, + 209, + 106, + 206, + 126, + 210, + 28, + 103, + 87, + 124, + 59, + 8, + 38, + 255, + 41, + 174, + 222, + 112, + 190, + 130, + 13, + 240, + 197, + 236, + 58, + 44, + 176, + 77, + 21, + 104, + 73, + 57, + 46, + 193, + 103, + 182, + 198, + 209, + 171, + 90, + 27, + 87, + 106, + 10, + 107, + 128, + 71, + 117, + 171, + 142, + 13, + 200, + 225, + 49, + 98, + 19, + 194, + 109, + 54, + 22, + 194, + 120, + 192, + 45, + 37, + 241, + 103, + 29, + 16, + 51, + 106, + 57, + 10, + 212, + 138, + 210, + 147, + 95, + 108, + 106, + 94, + 167, + 35, + 248, + 211, + 142, + 89, + 242, + 199, + 18, + 180, + 19, + 63, + 76, + 4, + 10, + 153, + 50, + 138, + 198, + 16, + 204, + 27, + 41, + 73, + 166, + 154, + 44, + 2, + 1, + 200, + 37, + 76, + 112, + 45, + 4, + 42, + 94, + 229, + 149, + 181, + 72, + 164, + 166, + 157, + 126, + 173, + 135, + 249, + 98, + 32, + 252, + 167, + 82, + 234, + 208, + 216, + 30, + 177, + 14, + 155, + 7, + 115, + 179, + 122, + 78, + 230, + 98, + 205, + 187, + 82, + 27, + 81, + 34, + 134, + 186, + 168, + 242, + 143, + 192, + 129, + 200, + 23, + 144, + 253, + 58, + 121, + 253, + 134, + 63, + 196, + 151, + 121, + 135, + 162, + 255, + 207, + 164, + 182, + 195, + 231, + 158, + 197, + 137, + 211, + 110, + 95, + 172, + 147, + 71, + 137, + 23, + 244, + 109, + 112, + 146, + 102, + 189, + 9, + 5, + 91, + 66, + 210, + 206, + 212, + 116, + 146, + 5, + 0, + 145, + 128, + 167, + 95, + 11, + 208, + 38, + 11, + 47, + 55, + 88, + 245, + 125, + 142, + 33, + 11, + 73, + 236, + 170, + 152, + 228, + 16, + 229, + 9, + 105, + 200, + 61, + 9, + 169, + 84, + 134, + 186, + 206, + 26, + 103, + 28, + 237, + 133, + 149, + 197, + 111, + 87, + 60, + 224, + 76, + 136, + 140, + 6, + 42, + 124, + 31, + 111, + 64, + 75, + 148, + 165, + 223, + 59, + 172, + 230, + 187, + 112, + 45, + 84, + 123, + 140, + 57, + 140, + 103, + 173, + 114, + 252, + 52, + 243, + 138, + 1, + 51, + 191, + 38, + 229, + 62, + 238, + 23, + 35, + 228, + 215, + 17, + 155, + 162, + 171, + 69, + 36, + 115, + 169, + 60, + 218, + 141, + 211, + 213, + 223, + 111, + 106, + 127, + 158, + 98, + 173, + 21, + 97, + 148, + 55, + 174, + 34, + 254, + 128, + 208, + 112, + 233, + 88, + 9, + 105, + 142, + 5, + 33, + 243, + 187, + 232, + 124, + 226, + 151, + 73, + 204, + 136, + 79, + 184, + 27, + 90, + 52, + 251, + 207, + 92, + 215, + 37, + 29, + 76, + 134, + 193, + 232, + 106, + 208, + 162, + 8, + 66, + 250, + 237, + 148, + 14, + 137, + 86, + 103, + 87, + 242, + 77, + 239, + 1, + 2, + 110, + 193, + 192, + 75, + 188, + 14, + 110, + 97, + 122, + 47, + 97, + 200, + 106, + 153, + 94, + 190, + 137, + 102, + 5, + 152, + 130, + 174, + 28, + 20, + 62, + 41, + 233, + 80, + 54, + 18, + 5, + 88, + 209, + 174, + 235, + 49, + 26, + 77, + 32, + 93, + 235, + 101, + 63, + 13, + 65, + 172, + 37, + 221, + 194, + 84, + 107, + 197, + 143, + 226, + 249, + 159, + 33, + 77, + 77, + 200, + 74, + 218, + 244, + 219, + 90, + 1, + 153, + 12, + 52, + 110, + 67, + 26, + 225, + 215, + 66, + 177, + 247, + 152, + 7, + 218, + 132, + 197, + 44, + 229, + 40, + 149, + 151, + 136, + 9, + 45, + 18, + 213, + 165, + 35, + 233, + 109, + 39, + 115, + 176, + 109, + 227, + 237, + 166, + 41, + 23, + 47, + 90, + 173, + 185, + 75, + 208, + 170, + 141, + 12, + 24, + 192, + 62, + 0, + 88, + 116, + 126, + 241, + 238, + 94, + 52, + 179, + 211, + 4, + 220, + 167, + 93, + 55, + 37, + 182, + 115, + 108, + 145, + 110, + 71, + 30, + 126, + 182, + 208, + 162, + 11, + 167, + 65, + 25, + 182, + 138, + 249, + 230, + 158, + 96, + 132, + 72, + 18, + 62, + 199, + 103, + 9, + 55, + 210, + 55, + 16, + 185, + 169, + 192, + 171, + 223, + 115, + 134, + 130, + 29, + 252, + 88, + 0, + 87, + 240, + 185, + 216, + 234, + 8, + 199, + 87, + 247, + 173, + 225, + 211, + 172, + 142, + 136, + 52, + 236, + 7, + 30, + 192, + 1, + 36, + 80, + 59, + 235, + 120, + 47, + 54, + 223, + 224, + 117, + 246, + 225, + 214, + 71, + 69, + 70, + 171, + 143, + 99, + 36, + 158, + 234, + 114, + 238, + 119, + 225, + 177, + 118, + 96, + 0, + 198, + 4, + 72, + 167, + 42, + 229, + 51, + 50, + 105, + 138, + 140, + 102, + 150, + 233, + 17, + 229, + 143, + 28, + 68, + 239, + 182, + 121, + 163, + 52, + 212, + 188, + 211, + 72, + 210, + 159, + 202, + 0, + 79, + 29, + 131, + 254, + 15, + 71, + 32, + 65, + 162, + 136, + 76, + 59, + 47, + 195, + 250, + 130, + 250, + 236, + 170, + 246, + 3, + 130, + 27, + 121, + 204, + 6, + 230, + 149, + 146, + 77, + 101, + 17, + 57, + 212, + 154, + 66, + 181, + 176, + 201, + 227, + 203, + 56, + 242, + 107, + 144, + 201, + 89, + 118, + 255, + 43, + 107, + 184, + 27, + 132, + 190, + 10, + 25, + 167, + 189, + 87, + 171, + 128, + 173, + 87, + 65, + 148, + 54, + 201, + 38, + 137, + 24, + 28, + 52, + 59, + 225, + 174, + 207, + 140, + 149, + 65, + 210, + 151, + 24, + 48, + 198, + 254, + 252, + 61, + 48, + 110, + 12, + 96, + 210, + 188, + 56, + 101, + 82, + 236, + 233, + 49, + 77, + 43, + 24, + 0, + 249, + 29, + 86, + 207, + 19, + 123, + 167, + 0, + 248, + 6, + 247, + 38, + 116, + 1, + 135, + 178, + 203, + 60, + 39, + 65, + 114, + 146, + 46, + 36, + 103, + 241, + 16, + 254, + 89, + 75, + 200, + 150, + 190, + 201, + 109, + 232, + 74, + 8, + 160, + 206, + 251, + 12, + 61, + 225, + 69, + 86, + 238, + 105, + 46, + 60, + 91, + 55, + 163, + 58, + 82, + 40, + 249, + 147, + 115, + 93, + 26, + 172, + 113, + 216, + 7, + 107, + 246, + 153, + 222, + 120, + 2, + 112, + 140, + 113, + 157, + 123, + 128, + 13, + 86, + 223, + 231, + 211, + 121, + 191, + 82, + 12, + 74, + 7, + 236, + 138, + 178, + 152, + 250, + 1, + 248, + 126, + 170, + 25, + 245, + 163, + 143, + 146, + 40, + 142, + 58, + 118, + 253, + 197, + 56, + 29, + 100, + 109, + 183, + 18, + 166, + 161, + 231, + 105, + 43, + 10, + 234, + 46, + 71, + 83, + 50, + 62, + 109, + 82, + 22, + 17, + 39, + 204, + 154, + 81, + 159, + 177, + 158, + 158, + 137, + 126, + 253, + 58, + 206, + 159, + 225, + 147, + 176, + 63, + 178, + 165, + 209, + 30, + 70, + 121, + 216, + 152, + 48, + 215, + 211, + 185, + 23, + 27, + 160, + 113, + 150, + 21, + 54, + 69, + 31, + 178, + 88, + 250, + 124, + 75, + 1, + 181, + 196, + 234, + 210, + 41, + 75, + 32, + 156, + 93, + 182, + 192, + 128, + 123, + 107, + 91, + 247, + 146, + 173, + 209, + 220, + 201, + 215, + 160, + 253, + 21, + 243, + 215, + 116, + 179, + 32, + 140, + 241, + 238, + 174, + 193, + 189, + 142, + 84, + 132, + 58, + 75, + 60, + 47, + 178, + 253, + 212, + 219, + 81, + 34, + 192, + 27, + 46, + 119, + 118, + 119, + 41, + 102, + 104, + 97, + 210, + 232, + 144, + 73, + 65, + 173, + 102, + 146, + 116, + 157, + 224, + 235, + 43, + 43, + 244, + 3, + 150, + 112, + 252, + 118, + 24, + 84, + 35, + 246, + 51, + 251, + 25, + 102, + 95, + 79, + 190, + 220, + 90, + 128, + 246, + 182, + 46, + 65, + 152, + 13, + 208, + 159, + 204, + 112, + 197, + 4, + 36, + 125, + 17, + 134, + 233, + 101, + 18, + 236, + 212, + 223, + 96, + 192, + 207, + 164, + 149, + 239, + 240, + 77, + 96, + 32, + 71, + 230, + 120, + 163, + 73, + 119, + 9, + 128, + 117, + 176, + 255, + 93, + 93, + 83, + 201, + 113, + 213, + 168, + 172, + 100, + 184, + 75, + 132, + 149, + 223, + 248, + 109, + 64, + 57, + 148, + 170, + 15, + 151, + 220, + 210, + 205, + 198, + 147, + 6, + 44, + 107, + 227, + 202, + 1, + 53, + 161, + 209, + 139, + 76, + 86, + 92, + 162, + 206, + 33, + 56, + 199, + 230, + 165, + 74, + 169, + 119, + 189, + 74, + 71, + 47, + 237, + 154, + 102, + 3, + 94, + 43, + 249, + 31, + 120, + 147, + 74, + 125, + 217, + 128, + 214, + 166, + 237, + 187, + 190, + 63, + 125, + 121, + 180, + 249, + 62, + 254, + 225, + 77, + 190, + 101, + 159, + 244, + 247, + 148, + 212, + 200, + 174, + 120, + 28, + 60, + 188, + 252, + 13, + 2, + 106, + 219, + 146, + 96, + 101, + 99, + 124, + 209, + 13, + 93, + 66, + 136, + 162, + 16, + 254, + 136, + 149, + 167, + 127, + 211, + 124, + 23, + 80, + 161, + 227, + 179, + 81, + 23, + 36, + 153, + 4, + 248, + 217, + 139, + 81, + 96, + 56, + 53, + 60, + 237, + 5, + 166, + 171, + 83, + 249, + 234, + 96, + 223, + 28, + 157, + 162, + 70, + 23, + 194, + 60, + 96, + 209, + 124, + 22, + 155, + 35, + 17, + 51, + 176, + 33, + 43, + 68, + 248, + 47, + 53, + 195, + 34, + 98, + 127, + 250, + 159, + 183, + 13, + 41, + 227, + 231, + 78, + 28, + 24, + 3, + 195, + 223, + 71, + 210, + 186, + 107, + 211, + 194, + 81, + 59, + 198, + 163, + 18, + 112, + 29, + 163, + 182, + 107, + 82, + 98, + 177, + 150, + 49, + 255, + 68, + 112, + 247, + 38, + 165, + 139, + 191, + 4, + 40, + 96, + 136, + 90, + 153, + 42, + 176, + 138, + 116, + 53, + 8, + 61, + 183, + 4, + 46, + 30, + 48, + 38, + 179, + 51, + 194, + 152, + 129, + 108, + 63, + 172, + 137, + 111, + 129, + 60, + 179, + 193, + 247, + 90, + 12, + 201, + 162, + 16, + 142, + 199, + 138, + 29, + 129, + 116, + 184, + 222, + 62, + 139, + 110, + 30, + 126, + 141, + 102, + 146, + 119, + 208, + 19, + 133, + 145, + 169, + 125, + 48, + 41, + 234, + 68, + 186, + 64, + 60, + 220, + 180, + 17, + 173, + 87, + 15, + 172, + 103, + 188, + 70, + 83, + 21, + 239, + 113, + 29, + 236, + 82, + 120, + 157, + 18, + 245, + 58, + 235, + 93, + 79, + 194, + 198, + 171, + 208, + 10, + 194, + 92, + 217, + 225, + 53, + 151, + 27, + 115, + 80, + 175, + 198, + 125, + 47, + 92, + 253, + 174, + 24, + 124, + 23, + 7, + 73, + 111, + 35, + 114, + 154, + 255, + 119, + 7, + 223, + 255, + 132, + 9, + 108, + 58, + 123, + 84, + 228, + 103, + 198, + 67, + 28, + 82, + 129, + 89, + 146, + 22, + 250, + 26, + 113, + 111, + 6, + 77, + 150, + 129, + 43, + 29, + 192, + 117, + 99, + 118, + 104, + 169, + 64, + 209, + 37, + 122, + 199, + 238, + 133, + 179, + 117, + 78, + 230, + 235, + 7, + 98, + 110, + 55, + 21, + 221, + 186, + 107, + 209, + 225, + 199, + 191, + 5, + 19, + 47, + 66, + 103, + 171, + 131, + 12, + 254, + 107, + 82, + 166, + 204, + 8, + 33, + 85, + 86, + 105, + 129, + 133, + 122, + 129, + 236, + 221, + 142, + 80, + 134, + 223, + 66, + 242, + 229, + 113, + 15, + 100, + 111, + 100, + 133, + 18, + 57, + 191, + 135, + 122, + 118, + 165, + 42, + 34, + 26, + 11, + 228, + 85, + 95, + 146, + 29, + 81, + 167, + 111, + 174, + 28, + 116, + 170, + 140, + 137, + 195, + 231, + 216, + 111, + 214, + 37, + 129, + 249, + 73, + 11, + 97, + 249, + 221, + 222, + 47, + 183, + 210, + 17, + 103, + 110, + 191, + 183, + 104, + 171, + 14, + 242, + 79, + 90, + 192, + 249, + 11, + 36, + 71, + 218, + 40, + 120, + 218, + 42, + 5, + 64, + 230, + 234, + 206, + 235, + 145, + 228, + 84, + 91, + 165, + 12, + 44, + 71, + 246, + 51, + 96, + 141, + 165, + 84, + 159, + 200, + 155, + 114, + 17, + 51, + 237, + 113, + 236, + 224, + 67, + 166, + 235, + 231, + 28, + 208, + 56, + 28, + 245, + 134, + 149, + 30, + 94, + 160, + 116, + 66, + 69, + 228, + 70, + 214, + 196, + 197, + 211, + 119, + 59, + 63, + 26, + 39, + 55, + 15, + 159, + 55, + 212, + 232, + 107, + 77, + 251, + 132, + 218, + 73, + 104, + 216, + 53, + 199, + 239, + 101, + 240, + 27, + 119, + 199, + 19, + 108, + 166, + 95, + 39, + 76, + 3, + 67, + 201, + 147, + 208, + 115, + 247, + 6, + 102, + 246, + 236, + 17, + 113, + 201, + 47, + 99, + 207, + 123, + 252, + 23, + 236, + 196, + 159, + 57, + 254, + 132, + 106, + 119, + 197, + 135, + 4, + 218, + 81, + 182, + 116, + 186, + 125, + 208, + 64, + 244, + 79, + 217, + 1, + 188, + 229, + 135, + 168, + 63, + 8, + 124, + 237, + 94, + 20, + 150, + 205, + 60, + 237, + 99, + 90, + 170, + 142, + 171, + 249, + 181, + 6, + 28, + 31, + 235, + 246, + 209, + 177, + 30, + 248, + 57, + 29, + 67, + 230, + 225, + 3, + 206, + 245, + 188, + 251, + 125, + 212, + 217, + 250, + 46, + 247, + 132, + 21, + 168, + 60, + 222, + 115, + 57, + 92, + 29, + 179, + 87, + 160, + 191, + 40, + 189, + 132, + 158, + 98, + 188, + 102, + 162, + 141, + 244, + 110, + 255, + 1, + 198, + 97, + 9, + 158, + 59, + 49, + 80, + 229, + 249, + 149, + 87, + 139, + 144, + 119, + 186, + 165, + 239, + 176, + 253, + 229, + 221, + 30, + 3, + 237, + 97, + 18, + 150, + 37, + 36, + 245, + 50, + 71, + 155, + 206, + 34, + 38, + 78, + 89, + 10, + 51, + 75, + 237, + 244, + 252, + 20, + 8, + 63, + 54, + 44, + 79, + 168, + 57, + 84, + 255, + 40, + 140, + 68, + 174, + 25, + 194, + 166, + 189, + 101, + 134, + 163, + 191, + 1, + 23, + 26, + 121, + 62, + 110, + 121, + 55, + 108, + 39, + 146, + 152, + 29, + 47, + 19, + 227, + 85, + 53, + 39, + 91, + 93, + 88, + 250, + 89, + 37, + 208, + 16, + 116, + 124, + 208, + 215, + 71, + 35, + 144, + 92, + 130, + 54, + 144, + 214, + 233, + 30, + 168, + 25, + 116, + 53, + 136, + 27, + 75, + 118, + 28, + 181, + 253, + 175, + 51, + 224, + 101, + 60, + 43, + 243, + 182, + 53, + 254, + 191, + 109, + 26, + 62, + 47, + 37, + 11, + 190, + 143, + 197, + 9, + 217, + 132, + 116, + 85, + 72, + 108, + 236, + 50, + 148, + 62, + 5, + 127, + 184, + 92, + 42, + 38, + 187, + 84, + 14, + 42, + 171, + 242, + 99, + 204, + 30, + 60, + 23, + 128, + 32, + 80, + 132, + 178, + 175, + 238, + 226, + 54, + 161, + 90, + 61, + 93, + 169, + 132, + 109, + 175, + 81, + 48, + 38, + 166, + 101, + 218, + 221, + 175, + 231, + 218, + 34, + 166, + 230, + 88, + 88, + 75, + 167, + 167, + 0, + 112, + 159, + 159, + 2, + 231, + 70, + 169, + 143, + 232, + 36, + 212, + 17, + 89, + 128, + 135, + 95, + 173, + 30, + 250, + 174, + 217, + 185, + 227, + 74, + 255, + 100, + 71, + 51, + 186, + 193, + 123, + 247, + 225, + 217, + 35, + 169, + 220, + 254, + 185, + 67, + 124, + 72, + 120, + 95, + 81, + 131, + 156, + 0, + 85, + 133, + 33, + 237, + 108, + 202, + 77, + 125, + 54, + 187, + 34, + 108, + 24, + 198, + 45, + 10, + 179, + 173, + 45, + 114, + 92, + 154, + 47, + 162, + 223, + 61, + 75, + 192, + 86, + 62, + 106, + 92, + 8, + 100, + 135, + 179, + 239, + 194, + 56, + 149, + 223, + 238, + 12, + 149, + 211, + 251, + 194, + 130, + 127, + 84, + 231, + 103, + 42, + 91, + 141, + 179, + 16, + 52, + 121, + 86, + 41, + 52, + 97, + 213, + 80, + 107, + 161, + 141, + 161, + 235, + 91, + 241, + 54, + 223, + 14, + 234, + 167, + 102, + 114, + 227, + 185, + 82, + 252, + 240, + 148, + 185, + 240, + 163, + 70, + 234, + 63, + 178, + 171, + 22, + 141, + 34, + 128, + 83, + 37, + 201, + 168, + 42, + 220, + 185, + 76, + 54, + 7, + 97, + 150, + 204, + 191, + 113, + 251, + 172, + 10, + 55, + 87, + 236, + 90, + 230, + 189, + 218, + 154, + 159, + 11, + 130, + 209, + 118, + 98, + 54, + 104, + 28, + 33, + 121, + 199, + 215, + 92, + 32, + 54, + 102, + 218, + 88, + 149, + 23, + 199, + 85, + 173, + 218, + 72, + 244, + 184, + 76, + 89, + 54, + 250, + 216, + 84, + 153, + 8, + 24, + 127, + 119, + 173, + 7, + 239, + 96, + 62, + 10, + 245, + 189, + 89, + 247, + 67, + 174, + 115, + 41, + 140, + 41, + 55, + 104, + 111, + 109, + 46, + 131, + 206, + 39, + 139, + 210, + 247, + 236, + 210, + 18, + 120, + 73, + 233, + 134, + 215, + 18, + 200, + 128, + 81, + 24, + 41, + 130, + 111, + 49, + 12, + 219, + 176, + 198, + 108, + 84, + 123, + 177, + 136, + 249, + 242, + 186, + 184, + 31, + 136, + 196, + 14, + 61, + 56, + 19, + 194, + 253, + 150, + 133, + 181, + 14, + 79, + 204, + 114, + 223, + 23, + 89, + 24, + 56, + 179, + 93, + 35, + 7, + 113, + 10, + 84, + 216, + 37, + 171, + 105, + 79, + 29, + 203, + 111, + 253, + 162, + 74, + 228, + 229, + 134, + 6, + 129, + 82, + 52, + 234, + 76, + 187, + 159, + 26, + 213, + 168, + 75, + 36, + 76, + 121, + 42, + 90, + 107, + 0, + 68, + 46, + 223, + 45, + 91, + 236, + 28, + 203, + 182, + 197, + 23, + 169, + 67, + 244, + 249, + 164, + 172, + 126, + 58, + 45, + 56, + 109, + 42, + 38, + 37, + 224, + 115, + 231, + 178, + 160, + 63, + 160, + 190, + 130, + 234, + 126, + 53, + 2, + 131, + 75, + 77, + 89, + 11, + 236, + 66, + 65, + 129, + 68, + 43, + 212, + 47, + 219, + 7, + 145, + 89, + 136, + 227, + 242, + 113, + 161, + 182, + 174, + 72, + 6, + 217, + 56, + 225, + 244, + 216, + 96, + 208, + 253, + 3, + 206, + 198, + 170, + 32, + 179, + 56, + 223, + 114, + 167, + 55, + 11, + 212, + 226, + 43, + 86, + 47, + 46, + 18, + 125, + 56, + 206, + 251, + 48, + 32, + 208, + 97, + 229, + 40, + 99, + 155, + 49, + 126, + 53, + 143, + 40, + 81, + 181, + 99, + 106, + 103, + 228, + 1, + 110, + 201, + 90, + 84, + 84, + 235, + 176, + 222, + 36, + 139, + 214, + 143, + 17, + 37, + 97, + 90, + 44, + 218, + 160, + 56, + 221, + 196, + 81, + 185, + 187, + 195, + 85, + 7, + 105, + 221, + 233, + 47, + 216, + 125, + 90, + 193, + 206, + 62, + 234, + 56, + 207, + 130, + 52, + 232, + 119, + 228, + 52, + 254, + 51, + 155, + 211, + 237, + 210, + 93, + 148, + 69, + 234, + 201, + 213, + 166, + 246, + 146, + 6, + 21, + 179, + 35, + 108, + 91, + 69, + 35, + 135, + 147, + 205, + 146, + 148, + 204, + 169, + 117, + 236, + 174, + 198, + 29, + 249, + 44, + 241, + 230, + 47, + 234, + 168, + 41, + 128, + 134, + 92, + 212, + 134, + 6, + 36, + 18, + 252, + 197, + 248, + 222, + 241, + 81, + 38, + 29, + 215, + 34, + 24, + 63, + 71, + 102, + 41, + 224, + 180, + 112, + 66, + 171, + 174, + 213, + 122, + 150, + 117, + 217, + 58, + 249, + 246, + 9, + 157, + 253, + 237, + 251, + 193, + 81, + 112, + 234, + 12, + 118, + 30, + 172, + 87, + 106, + 218, + 249, + 168, + 77, + 176, + 83, + 5, + 191, + 206, + 4, + 132, + 49, + 50, + 196, + 147, + 18, + 131, + 76, + 244, + 72, + 80, + 137, + 181, + 160, + 62, + 34, + 91, + 20, + 200, + 244, + 207, + 225, + 46, + 117, + 102, + 111, + 234, + 201, + 253, + 90, + 168, + 31, + 198, + 174, + 64, + 16, + 50, + 109, + 120, + 28, + 207, + 20, + 246, + 10, + 17, + 203, + 36, + 92, + 224, + 194, + 202, + 231, + 112, + 234, + 24, + 29, + 77, + 146, + 110, + 98, + 157, + 139, + 154, + 72, + 215, + 219, + 231, + 225, + 66, + 30, + 233, + 32, + 194, + 105, + 75, + 4, + 185, + 178, + 230, + 93, + 233, + 164, + 214, + 254, + 169, + 251, + 28, + 201, + 134, + 27, + 30, + 31, + 165, + 67, + 89, + 254, + 86, + 169, + 207, + 200, + 44, + 107, + 80, + 95, + 67, + 130, + 178, + 165, + 222, + 151, + 233, + 127, + 117, + 154, + 203, + 46, + 146, + 183, + 6, + 245, + 8, + 188, + 244, + 212, + 33, + 184, + 215, + 21, + 139, + 188, + 247, + 2, + 149, + 20, + 144, + 53, + 107, + 219, + 196, + 181, + 104, + 132, + 105, + 182, + 133, + 21, + 184, + 46, + 110, + 85, + 104, + 199, + 69, + 23, + 196, + 165, + 232, + 219, + 53, + 178, + 83, + 68, + 208, + 180, + 26, + 78, + 182, + 84, + 26, + 100, + 2, + 120, + 82, + 106, + 215, + 55, + 64, + 130, + 106, + 108, + 8, + 0, + 98, + 209, + 35, + 64, + 169, + 130, + 211, + 222, + 153, + 195, + 221, + 37, + 37, + 208, + 147, + 158, + 4, + 82, + 135, + 172, + 209, + 143, + 36, + 25, + 189, + 242, + 102, + 223, + 186, + 192, + 189, + 128, + 198, + 165, + 65, + 154, + 66, + 87, + 139, + 249, + 162, + 5, + 0, + 219, + 236, + 239, + 209, + 37, + 144, + 114, + 60, + 221, + 233, + 38, + 18, + 100, + 221, + 18, + 220, + 4, + 35, + 76, + 0, + 175, + 60, + 250, + 210, + 90, + 203, + 210, + 96, + 75, + 7, + 214, + 109, + 240, + 56, + 135, + 20, + 179, + 118, + 23, + 65, + 46, + 14, + 14, + 45, + 96, + 184, + 231, + 172, + 144, + 201, + 71, + 161, + 64, + 201, + 176, + 111, + 98, + 249, + 179, + 85, + 196, + 134, + 104, + 50, + 182, + 251, + 129, + 153, + 236, + 60, + 41, + 23, + 1, + 122, + 46, + 255, + 81, + 73, + 55, + 153, + 200, + 207, + 76, + 97, + 103, + 125, + 52, + 108, + 89, + 34, + 196, + 19, + 137, + 5, + 91, + 47, + 170, + 156, + 146, + 153, + 7, + 200, + 107, + 25, + 191, + 174, + 223, + 56, + 64, + 93, + 201, + 209, + 184, + 50, + 61, + 71, + 133, + 199, + 202, + 161, + 71, + 208, + 22, + 50, + 72, + 57, + 74, + 46, + 146, + 142, + 19, + 109, + 150, + 159, + 42, + 145, + 127, + 124, + 121, + 174, + 211, + 28, + 45, + 62, + 107, + 105, + 127, + 67, + 186, + 80, + 67, + 20, + 34, + 137, + 43, + 47, + 222, + 52, + 101, + 21, + 8, + 190, + 134, + 233, + 72, + 191, + 19, + 220, + 99, + 137, + 116, + 90, + 172, + 79, + 47, + 192, + 5, + 53, + 54, + 11, + 202, + 211, + 237, + 255, + 121, + 27, + 10, + 156, + 237, + 128, + 249, + 44, + 173, + 247, + 108, + 226, + 177, + 50, + 55, + 121, + 63, + 193, + 114, + 154, + 15, + 19, + 135, + 57, + 89, + 62, + 34, + 255, + 8, + 72, + 101, + 219, + 130, + 125, + 166, + 255, + 251, + 214, + 152, + 152, + 124, + 24, + 12, + 20, + 61, + 98, + 29, + 136, + 36, + 88, + 22, + 184, + 3, + 171, + 150, + 61, + 28, + 50, + 19, + 171, + 11, + 191, + 98, + 106, + 145, + 76, + 106, + 54, + 37, + 61, + 198, + 168, + 159, + 233, + 101, + 6, + 33, + 240, + 9, + 81, + 29, + 58, + 56, + 124, + 75, + 135, + 115, + 151, + 246, + 159, + 26, + 50, + 226, + 71, + 61, + 232, + 104, + 86, + 162, + 195, + 75, + 118, + 17, + 21, + 134, + 227, + 96, + 206, + 50, + 151, + 22, + 183, + 168, + 159, + 30, + 254, + 61, + 177, + 65, + 94, + 233, + 64, + 215, + 46, + 1, + 178, + 5, + 110, + 149, + 102, + 185, + 1, + 221, + 148, + 175, + 15, + 41, + 252, + 160, + 249, + 239, + 19, + 61, + 230, + 220, + 124, + 84, + 91, + 133, + 120, + 130, + 221, + 252, + 102, + 140, + 65, + 168, + 44, + 96, + 101, + 171, + 26, + 139, + 182, + 113, + 198, + 15, + 65, + 53, + 119, + 99, + 98, + 22, + 186, + 70, + 24, + 238, + 53, + 208, + 122, + 79, + 132, + 65, + 197, + 247, + 97, + 107, + 62, + 173, + 144, + 241, + 139, + 50, + 208, + 36, + 248, + 103, + 235, + 118, + 136, + 122, + 125, + 49, + 226, + 65, + 107, + 90, + 75, + 150, + 153, + 214, + 13, + 108, + 148, + 251, + 219, + 230, + 100, + 146, + 53, + 115, + 175, + 161, + 219, + 87, + 140, + 239, + 91, + 35, + 79, + 42, + 164, + 227, + 150, + 249, + 136, + 218, + 216, + 22, + 104, + 30, + 253, + 172, + 153, + 212, + 255, + 35, + 172, + 123, + 221, + 20, + 37, + 217, + 161, + 114, + 103, + 39, + 8, + 255, + 223, + 57, + 160, + 179, + 147, + 106, + 125, + 9, + 22, + 53, + 251, + 52, + 139, + 178, + 26, + 197, + 58, + 80, + 35, + 34, + 33, + 151, + 225, + 218, + 12, + 18, + 249, + 202, + 38, + 255, + 236, + 62, + 201, + 17, + 18, + 245, + 207, + 114, + 85, + 87, + 175, + 59, + 241, + 75, + 166, + 94, + 227, + 68, + 143, + 56, + 242, + 45, + 147, + 233, + 140, + 213, + 160, + 163, + 22, + 66, + 1, + 134, + 157, + 162, + 131, + 229, + 171, + 167, + 151, + 225, + 178, + 102, + 9, + 60, + 218, + 54, + 142, + 255, + 164, + 91, + 32, + 247, + 55, + 50, + 177, + 173, + 215, + 160, + 77, + 107, + 118, + 131, + 106, + 83, + 203, + 157, + 178, + 165, + 57, + 29, + 16, + 139, + 34, + 185, + 98, + 28, + 84, + 62, + 189, + 31, + 196, + 1, + 216, + 172, + 215, + 152, + 140, + 101, + 200, + 185, + 116, + 214, + 29, + 65, + 56, + 139, + 240, + 176, + 57, + 135, + 92, + 141, + 246, + 196, + 94, + 49, + 52, + 58, + 206, + 19, + 219, + 118, + 203, + 1, + 139, + 236, + 51, + 62, + 106, + 115, + 209, + 174, + 47, + 202, + 157, + 228, + 239, + 95, + 187, + 216, + 204, + 146, + 151, + 202, + 238, + 113, + 88, + 94, + 18, + 125, + 88, + 102, + 94, + 85, + 53, + 187, + 123, + 21, + 78, + 250, + 76, + 28, + 148, + 64, + 28, + 34, + 236, + 184, + 196, + 35, + 101, + 246, + 33, + 93, + 5, + 225, + 153, + 163, + 199, + 39, + 222, + 45, + 142, + 42, + 164, + 126, + 112, + 20, + 85, + 249, + 49, + 48, + 1, + 100, + 82, + 184, + 158, + 122, + 139, + 198, + 90, + 150, + 224, + 56, + 62, + 149, + 178, + 71, + 74, + 0, + 27, + 182, + 191, + 81, + 235, + 1, + 62, + 232, + 165, + 62, + 52, + 88, + 152, + 112, + 2, + 90, + 129, + 198, + 200, + 173, + 132, + 233, + 185, + 29, + 60, + 185, + 94, + 18, + 55, + 119, + 22, + 241, + 13, + 1, + 46, + 187, + 16, + 107, + 108, + 71, + 169, + 13, + 76, + 152, + 177, + 157, + 11, + 222, + 104, + 194, + 140, + 115, + 159, + 190, + 11, + 30, + 95, + 237, + 100, + 110, + 13, + 54, + 238, + 105, + 196, + 79, + 3, + 28, + 74, + 36, + 195, + 54, + 208, + 113, + 65, + 44, + 155, + 10, + 88, + 4, + 222, + 135, + 191, + 208, + 77, + 144, + 147, + 195, + 59, + 150, + 102, + 192, + 104, + 209, + 171, + 109, + 138, + 0, + 168, + 81, + 135, + 48, + 144, + 33, + 112, + 4, + 23, + 12, + 157, + 86, + 72, + 251, + 244, + 196, + 68, + 243, + 167, + 230, + 88, + 251, + 187, + 164, + 168, + 156, + 91, + 16, + 18, + 144, + 122, + 170, + 30, + 124, + 136, + 99, + 238, + 83, + 197, + 153, + 164, + 82, + 215, + 151, + 66, + 188, + 235, + 132, + 81, + 20, + 185, + 230, + 133, + 98, + 216, + 231, + 6, + 219, + 50, + 253, + 186, + 100, + 112, + 168, + 232, + 156, + 36, + 101, + 160, + 174, + 27, + 254, + 117, + 92, + 202, + 173, + 130, + 129, + 174, + 212, + 77, + 4, + 41, + 137, + 89, + 210, + 235, + 191, + 114, + 22, + 188, + 29, + 96, + 81, + 28, + 70, + 37, + 210, + 126, + 75, + 31, + 234, + 105, + 160, + 251, + 36, + 247, + 253, + 235, + 120, + 161, + 237, + 64, + 252, + 74, + 194, + 34, + 194, + 47, + 129, + 90, + 83, + 253, + 244, + 151, + 89, + 67, + 52, + 138, + 205, + 113, + 71, + 26, + 72, + 174, + 252, + 134, + 52, + 164, + 150, + 90, + 160, + 207, + 83, + 202, + 235, + 211, + 193, + 207, + 238, + 27, + 60, + 1, + 241, + 217, + 110, + 67, + 79, + 11, + 90, + 62, + 178, + 106, + 29, + 4, + 178, + 121, + 26, + 57, + 118, + 17, + 238, + 144, + 29, + 85, + 102, + 195, + 91, + 61, + 251, + 70, + 191, + 204, + 113, + 119, + 214, + 254, + 57, + 253, + 211, + 226, + 128, + 191, + 239, + 134, + 66, + 90, + 14, + 150, + 22, + 195, + 15, + 81, + 195, + 87, + 240, + 251, + 62, + 90, + 180, + 161, + 154, + 12, + 96, + 10, + 37, + 196, + 15, + 8, + 217, + 213, + 7, + 208, + 27, + 65, + 68, + 80, + 32, + 142, + 81, + 59, + 224, + 39, + 244, + 144, + 201, + 87, + 115, + 220, + 56, + 56, + 52, + 171, + 251, + 25, + 178, + 130, + 159, + 94, + 56, + 24, + 223, + 61, + 204, + 53, + 191, + 23, + 143, + 253, + 84, + 89, + 89, + 221, + 18, + 123, + 213, + 123, + 133, + 16, + 43, + 213, + 241, + 196, + 217, + 173, + 175, + 72, + 140, + 165, + 63, + 241, + 130, + 26, + 97, + 70, + 230, + 62, + 194, + 69, + 135, + 81, + 114, + 47, + 48, + 37, + 51, + 57, + 63, + 53, + 205, + 58, + 84, + 185, + 200, + 132, + 178, + 224, + 11, + 67, + 150, + 0, + 250, + 143, + 59, + 207, + 62, + 148, + 42, + 235, + 59, + 8, + 9, + 125, + 101, + 206, + 14, + 102, + 50, + 249, + 43, + 222, + 150, + 164, + 155, + 176, + 36, + 133, + 75, + 27, + 60, + 183, + 218, + 164, + 159, + 0, + 227, + 186, + 250, + 77, + 10, + 129, + 205, + 103, + 75, + 4, + 76, + 199, + 123, + 233, + 130, + 95, + 84, + 16, + 29, + 60, + 16, + 101, + 182, + 72, + 67, + 128, + 96, + 10, + 251, + 170, + 17, + 65, + 105, + 174, + 130, + 246, + 90, + 205, + 70, + 33, + 218, + 47, + 51, + 190, + 211, + 31, + 34, + 172, + 8, + 178, + 192, + 150, + 128, + 221, + 211, + 130, + 61, + 71, + 251, + 14, + 128, + 234, + 182, + 145, + 147, + 240, + 104, + 210, + 194, + 175, + 98, + 132, + 102, + 59, + 2, + 164, + 83, + 121, + 61, + 62, + 186, + 14, + 235, + 143, + 131, + 236, + 85, + 199, + 152, + 175, + 25, + 33, + 164, + 231, + 224, + 133, + 35, + 218, + 20, + 158, + 165, + 39, + 130, + 85, + 188, + 98, + 45, + 150, + 99, + 28, + 150, + 6, + 235, + 181, + 35, + 146, + 255, + 234, + 153, + 205, + 83, + 201, + 8, + 245, + 12, + 234, + 217, + 177, + 126, + 207, + 69, + 121, + 140, + 195, + 239, + 39, + 149, + 253, + 97, + 121, + 139, + 89, + 114, + 222, + 80, + 57, + 67, + 255, + 138, + 230, + 133, + 168, + 243, + 20, + 244, + 214, + 83, + 163, + 194, + 52, + 132, + 248, + 144, + 173, + 160, + 134, + 233, + 234, + 237, + 98, + 75, + 63, + 190, + 150, + 207, + 241, + 132, + 65, + 211, + 211, + 179, + 31, + 181, + 30, + 139, + 15, + 252, + 148, + 228, + 149, + 145, + 17, + 209, + 74, + 253, + 114, + 189, + 162, + 55, + 48, + 207, + 4, + 43, + 21, + 36, + 134, + 26, + 174, + 132, + 7, + 38, + 202, + 121, + 183, + 142, + 40, + 129, + 189, + 66, + 136, + 7, + 1, + 128, + 208, + 238, + 14, + 128, + 239, + 36, + 26, + 148, + 118, + 98, + 111, + 17, + 37, + 243, + 86, + 246, + 123, + 253, + 161, + 12, + 246, + 152, + 53, + 209, + 123, + 158, + 220, + 145, + 107, + 127, + 122, + 79, + 230, + 75, + 180, + 200, + 118, + 6, + 107, + 129, + 105, + 144, + 187, + 21, + 1, + 116, + 30, + 28, + 91, + 136, + 113, + 14, + 92, + 178, + 60, + 107, + 86, + 160, + 151, + 136, + 79, + 232, + 210, + 178, + 85, + 204, + 140, + 252, + 235, + 194, + 82, + 58, + 191, + 3, + 249, + 102, + 202, + 172, + 59, + 165, + 81, + 87, + 76, + 141, + 159, + 96, + 162, + 209, + 62, + 133, + 125, + 197, + 11, + 68, + 207, + 200, + 190, + 121, + 188, + 253, + 190, + 111, + 197, + 63, + 249, + 124, + 53, + 19, + 231, + 16, + 71, + 120, + 73, + 188, + 15, + 20, + 119, + 231, + 78, + 252, + 77, + 212, + 151, + 191, + 160, + 250, + 69, + 76, + 219, + 148, + 158, + 75, + 226, + 149, + 185, + 140, + 212, + 241, + 168, + 39, + 191, + 8, + 48, + 243, + 101, + 25, + 183, + 28, + 137, + 175, + 144, + 165, + 205, + 150, + 34, + 207, + 72, + 76, + 228, + 103, + 18, + 146, + 104, + 188, + 7, + 177, + 95, + 27, + 11, + 42, + 214, + 110, + 36, + 167, + 41, + 22, + 5, + 65, + 51, + 231, + 178, + 38, + 251, + 223, + 82, + 155, + 90, + 29, + 84, + 236, + 197, + 34, + 197, + 58, + 221, + 16, + 168, + 213, + 228, + 220, + 189, + 24, + 163, + 112, + 169, + 159, + 66, + 20, + 4, + 145, + 68, + 146, + 42, + 4, + 105, + 237, + 113, + 84, + 75, + 25, + 91, + 160, + 111, + 154, + 153, + 159, + 109, + 191, + 38, + 179, + 129, + 0, + 0, + 155, + 179, + 60, + 174, + 140, + 10, + 36, + 152, + 139, + 197, + 80, + 87, + 2, + 14, + 155, + 139, + 12, + 224, + 93, + 247, + 235, + 158, + 125, + 245, + 19, + 215, + 175, + 145, + 180, + 218, + 72, + 170, + 36, + 147, + 20, + 162, + 205, + 209, + 137, + 63, + 47, + 69, + 154, + 158, + 193, + 231, + 27, + 94, + 199, + 227, + 134, + 247, + 142, + 88, + 4, + 35, + 106, + 177, + 205, + 69, + 85, + 222, + 115, + 207, + 196, + 165, + 107, + 169, + 247, + 191, + 171, + 193, + 57, + 203, + 204, + 15, + 215, + 145, + 220, + 188, + 190, + 20, + 180, + 211, + 224, + 7, + 208, + 49, + 66, + 4, + 43, + 83, + 207, + 176, + 23, + 149, + 242, + 128, + 15, + 133, + 74, + 94, + 73, + 91, + 137, + 181, + 177, + 110, + 221, + 40, + 29, + 102, + 74, + 178, + 95, + 117, + 97, + 229, + 161, + 220, + 147, + 128, + 47, + 122, + 187, + 21, + 18, + 243, + 10, + 1, + 103, + 58, + 196, + 241, + 27, + 235, + 111, + 151, + 79, + 202, + 255, + 50, + 17, + 202, + 160, + 249, + 74, + 92, + 253, + 254, + 4, + 199, + 103, + 175, + 224, + 232, + 218, + 229, + 125, + 161, + 74, + 127, + 40, + 49, + 118, + 64, + 188, + 95, + 151, + 194, + 182, + 139, + 252, + 228, + 36, + 8, + 71, + 187, + 91, + 95, + 200, + 50, + 155, + 139, + 156, + 62, + 192, + 39, + 121, + 144, + 90, + 62, + 18, + 73, + 9, + 0, + 159, + 79, + 180, + 106, + 84, + 154, + 7, + 149, + 128, + 63, + 132, + 204, + 41, + 209, + 56, + 140, + 26, + 142, + 2, + 144, + 246, + 208, + 234, + 65, + 112, + 187, + 78, + 35, + 2, + 117, + 23, + 37, + 28, + 15, + 197, + 84, + 109, + 98, + 124, + 192, + 37, + 50, + 37, + 102, + 225, + 162, + 69, + 159, + 155, + 6, + 190, + 110, + 66, + 215, + 53, + 214, + 11, + 63, + 95, + 83, + 98, + 113, + 52, + 67, + 134, + 89, + 78, + 196, + 44, + 45, + 124, + 91, + 249, + 163, + 94, + 142, + 73, + 11, + 47, + 190, + 243, + 103, + 58, + 212, + 121, + 37, + 90, + 241, + 241, + 232, + 124, + 65, + 156, + 57, + 19, + 15, + 75, + 200, + 60, + 157, + 228, + 198, + 56, + 78, + 107, + 123, + 71, + 197, + 231, + 232, + 178, + 66, + 105, + 39, + 165, + 144, + 98, + 197, + 115, + 17, + 130, + 149, + 67, + 140, + 26, + 191, + 79, + 73, + 54, + 134, + 71, + 176, + 59, + 94, + 73, + 165, + 22, + 3, + 253, + 194, + 57, + 187, + 22, + 220, + 34, + 136, + 211, + 142, + 187, + 48, + 235, + 138, + 104, + 50, + 209, + 22, + 34, + 180, + 28, + 32, + 241, + 200, + 220, + 66, + 19, + 57, + 140, + 126, + 87, + 2, + 29, + 51, + 157, + 94, + 187, + 159, + 143, + 128, + 224, + 37, + 108, + 74, + 14, + 177, + 6, + 63, + 148, + 162, + 136, + 192, + 47, + 32, + 63, + 153, + 225, + 228, + 147, + 79, + 129, + 238, + 190, + 192, + 50, + 108, + 126, + 190, + 93, + 246, + 119, + 41, + 16, + 37, + 52, + 129, + 226, + 196, + 242, + 147, + 248, + 115, + 97, + 152, + 45, + 217, + 244, + 148, + 132, + 81, + 84, + 246, + 253, + 215, + 102, + 165, + 92, + 180, + 13, + 158, + 87, + 58, + 68, + 76, + 71, + 100, + 154, + 193, + 161, + 32, + 97, + 238, + 75, + 129, + 235, + 194, + 114, + 132, + 148, + 208, + 18, + 43, + 79, + 112, + 233, + 177, + 125, + 149, + 91, + 168, + 85, + 165, + 137, + 207, + 84, + 116, + 145, + 145, + 54, + 140, + 43, + 84, + 193, + 7, + 165, + 15, + 140, + 216, + 34, + 26, + 217, + 88, + 49, + 106, + 77, + 95, + 158, + 195, + 12, + 84, + 68, + 210, + 185, + 81, + 241, + 23, + 124, + 23, + 41, + 160, + 190, + 15, + 221, + 160, + 255, + 28, + 128, + 30, + 118, + 214, + 22, + 62, + 72, + 63, + 220, + 242, + 54, + 167, + 171, + 247, + 13, + 85, + 228, + 95, + 82, + 17, + 206, + 2, + 6, + 136, + 150, + 211, + 21, + 9, + 101, + 148, + 109, + 74, + 178, + 42, + 119, + 41, + 19, + 224, + 124, + 46, + 251, + 189, + 28, + 112, + 154, + 112, + 222, + 72, + 213, + 26, + 10, + 82, + 183, + 14, + 57, + 97, + 94, + 241, + 212, + 219, + 220, + 87, + 254, + 16, + 38, + 215, + 118, + 30, + 106, + 151, + 137, + 89, + 103, + 188, + 211, + 209, + 254, + 45, + 14, + 234, + 196, + 85, + 124, + 205, + 174, + 23, + 116, + 169, + 214, + 175, + 20, + 195, + 117, + 145, + 92, + 187, + 198, + 232, + 7, + 65, + 27, + 186, + 6, + 193, + 117, + 36, + 89, + 201, + 219, + 73, + 122, + 23, + 233, + 47, + 238, + 117, + 241, + 177, + 233, + 88, + 50, + 95, + 226, + 188, + 5, + 102, + 211, + 187, + 253, + 36, + 32, + 154, + 36, + 63, + 2, + 215, + 166, + 4, + 191, + 196, + 119, + 238, + 87, + 104, + 68, + 129, + 34, + 56, + 105, + 98, + 8, + 152, + 19, + 73, + 33, + 140, + 76, + 103, + 189, + 163, + 230, + 231, + 92, + 134, + 15, + 225, + 202, + 19, + 146, + 149, + 140, + 125, + 58, + 213, + 21, + 87, + 50, + 162, + 53, + 41, + 155, + 16, + 116, + 252, + 211, + 76, + 143, + 255, + 49, + 105, + 172, + 144, + 216, + 215, + 84, + 72, + 81, + 126, + 99, + 160, + 151, + 150, + 39, + 113, + 193, + 213, + 120, + 228, + 211, + 200, + 194, + 182, + 117, + 56, + 77, + 252, + 139, + 129, + 192, + 32, + 125, + 227, + 48, + 134, + 44, + 234, + 38, + 241, + 58, + 72, + 71, + 198, + 69, + 162, + 134, + 24, + 150, + 67, + 193, + 64, + 61, + 78, + 99, + 50, + 118, + 152, + 209, + 85, + 165, + 255, + 20, + 110, + 168, + 129, + 32, + 251, + 219, + 92, + 235, + 241, + 86, + 117, + 129, + 159, + 201, + 222, + 136, + 157, + 137, + 205, + 115, + 192, + 208, + 44, + 243, + 48, + 216, + 245, + 161, + 57, + 97, + 113, + 203, + 167, + 35, + 180, + 183, + 180, + 161, + 48, + 19, + 193, + 80, + 213, + 90, + 199, + 153, + 166, + 44, + 58, + 253, + 59, + 189, + 202, + 55, + 10, + 85, + 174, + 29, + 107, + 213, + 183, + 108, + 208, + 103, + 23, + 227, + 131, + 74, + 223, + 84, + 182, + 172, + 126, + 50, + 162, + 80, + 121, + 215, + 27, + 106, + 209, + 35, + 215, + 3, + 35, + 32, + 132, + 182, + 111, + 166, + 252, + 100, + 129, + 180, + 35, + 25, + 102, + 207, + 226, + 121, + 70, + 47, + 47, + 133, + 1, + 115, + 25, + 42, + 50, + 169, + 2, + 14, + 122, + 67, + 52, + 60, + 227, + 247, + 192, + 100, + 157, + 133, + 215, + 211, + 196, + 55, + 123, + 53, + 138, + 22, + 11, + 26, + 61, + 50, + 38, + 138, + 20, + 84, + 170, + 117, + 57, + 166, + 9, + 90, + 39, + 243, + 241, + 81, + 72, + 29, + 236, + 98, + 40, + 1, + 109, + 58, + 225, + 88, + 201, + 42, + 70, + 144, + 246, + 207, + 221, + 158, + 8, + 113, + 198, + 0, + 81, + 102, + 199, + 186, + 145, + 5, + 30, + 58, + 198, + 192, + 93, + 160, + 111, + 65, + 2, + 99, + 228, + 250, + 75, + 21, + 212, + 70, + 49, + 216, + 33, + 239, + 89, + 176, + 191, + 208, + 163, + 94, + 158, + 120, + 174, + 17, + 53, + 112, + 216, + 174, + 52, + 213, + 91, + 52, + 36, + 34, + 192, + 171, + 230, + 15, + 151, + 0, + 153, + 105, + 113, + 125, + 186, + 76, + 179, + 218, + 116, + 107, + 252, + 99, + 63, + 134, + 125, + 19, + 151, + 194, + 83, + 21, + 123, + 178, + 200, + 98, + 226, + 51, + 29, + 127, + 120, + 106, + 236, + 98, + 233, + 23, + 26, + 53, + 103, + 198, + 176, + 47, + 238, + 248, + 98, + 37, + 34, + 174, + 65, + 78, + 54, + 48, + 177, + 188, + 186, + 33, + 37, + 60, + 20, + 202, + 82, + 112, + 76, + 145, + 254, + 138, + 43, + 20, + 94, + 92, + 124, + 45, + 225, + 36, + 146, + 101, + 179, + 49, + 95, + 50, + 198, + 112, + 39, + 165, + 20, + 71, + 132, + 139, + 181, + 92, + 103, + 197, + 31, + 131, + 182, + 17, + 174, + 197, + 204, + 213, + 161, + 146, + 123, + 207, + 32, + 85, + 42, + 205, + 188, + 53, + 167, + 177, + 4, + 49, + 73, + 29, + 45, + 29, + 79, + 247, + 190, + 152, + 38, + 222, + 179, + 104, + 161, + 179, + 148, + 113, + 137, + 57, + 108, + 19, + 207, + 59, + 193, + 190, + 94, + 107, + 174, + 15, + 176, + 154, + 91, + 88, + 77, + 223, + 248, + 175, + 154, + 162, + 10, + 124, + 56, + 218, + 145, + 57, + 98, + 158, + 195, + 234, + 13, + 186, + 114, + 22, + 199, + 188, + 71, + 217, + 134, + 125, + 88, + 37, + 60, + 28, + 13, + 56, + 107, + 196, + 148, + 82, + 28, + 154, + 102, + 22, + 220, + 214, + 240, + 179, + 91, + 51, + 85, + 210, + 94, + 94, + 255, + 148, + 209, + 18, + 217, + 231, + 153, + 186, + 238, + 33, + 172, + 0, + 39, + 25, + 12, + 123, + 101, + 17, + 17, + 33, + 248, + 165, + 72, + 181, + 124, + 138, + 167, + 132, + 134, + 73, + 144, + 254, + 107, + 191, + 215, + 90, + 46, + 107, + 82, + 211, + 137, + 85, + 120, + 66, + 251, + 152, + 123, + 29, + 88, + 116, + 240, + 229, + 9, + 24, + 145, + 185, + 125, + 84, + 95, + 154, + 9, + 147, + 151, + 25, + 255, + 79, + 144, + 126, + 178, + 18, + 135, + 141, + 190, + 31, + 211, + 35, + 92, + 236, + 101, + 137, + 133, + 96, + 46, + 192, + 241, + 231, + 72, + 94, + 45, + 90, + 195, + 14, + 173, + 106, + 205, + 105, + 30, + 189, + 6, + 14, + 244, + 230, + 16, + 153, + 44, + 98, + 224, + 188, + 68, + 43, + 16, + 76, + 205, + 237, + 1, + 108, + 118, + 14, + 43, + 30, + 102, + 197, + 84, + 51, + 80, + 246, + 5, + 68, + 244, + 192, + 102, + 223, + 177, + 80, + 182, + 101, + 86, + 106, + 125, + 84, + 255, + 252, + 35, + 168, + 252, + 193, + 79, + 116, + 212, + 102, + 163, + 60, + 175, + 190, + 90, + 77, + 113, + 17, + 139, + 87, + 100, + 80, + 240, + 144, + 195, + 25, + 210, + 115, + 84, + 110, + 140, + 252, + 23, + 155, + 25, + 234, + 148, + 226, + 210, + 19, + 160, + 148, + 116, + 179, + 123, + 39, + 113, + 60, + 131, + 119, + 153, + 182, + 152, + 24, + 46, + 33, + 143, + 33, + 165, + 60, + 65, + 46, + 199, + 138, + 229, + 93, + 11, + 134, + 10, + 127, + 179, + 63, + 82, + 27, + 32, + 132, + 180, + 64, + 101, + 247, + 34, + 61, + 98, + 104, + 144, + 164, + 107, + 196, + 109, + 90, + 171, + 111, + 245, + 52, + 155, + 16, + 134, + 254, + 18, + 100, + 114, + 23, + 174, + 140, + 67, + 194, + 87, + 241, + 218, + 172, + 191, + 180, + 123, + 66, + 35, + 166, + 164, + 157, + 161, + 246, + 232, + 13, + 1, + 219, + 244, + 19, + 249, + 4, + 9, + 225, + 78, + 250, + 246, + 48, + 194, + 183, + 205, + 114, + 10, + 142, + 226, + 137, + 212, + 110, + 190, + 107, + 233, + 162, + 28, + 209, + 206, + 202, + 112, + 242, + 122, + 237, + 149, + 58, + 186, + 238, + 89, + 77, + 3, + 77, + 212, + 191, + 206, + 119, + 193, + 222, + 80, + 184, + 159, + 151, + 4, + 250, + 155, + 192, + 83, + 37, + 162, + 90, + 51, + 249, + 225, + 31, + 139, + 165, + 86, + 28, + 110, + 207, + 17, + 201, + 114, + 89, + 58, + 137, + 209, + 16, + 136, + 38, + 17, + 248, + 254, + 39, + 53, + 177, + 191, + 203, + 213, + 96, + 149, + 132, + 98, + 183, + 146, + 195, + 16, + 216, + 187, + 34, + 87, + 152, + 244, + 203, + 251, + 168, + 58, + 28, + 24, + 74, + 13, + 200, + 119, + 15, + 48, + 221, + 132, + 116, + 98, + 235, + 98, + 241, + 148, + 158, + 153, + 136, + 207, + 119, + 9, + 113, + 31, + 68, + 81, + 203, + 155, + 106, + 43, + 133, + 58, + 182, + 5, + 13, + 226, + 98, + 43, + 111, + 76, + 7, + 155, + 84, + 206, + 130, + 230, + 1, + 102, + 172, + 250, + 11, + 94, + 105, + 170, + 87, + 240, + 104, + 53, + 1, + 142, + 161, + 144, + 191, + 230, + 219, + 39, + 43, + 58, + 71, + 239, + 120, + 92, + 45, + 128, + 185, + 89, + 30, + 39, + 89, + 94, + 18, + 213, + 184, + 42, + 21, + 25, + 173, + 206, + 27, + 250, + 219, + 246, + 238, + 12, + 225, + 24, + 194, + 102, + 241, + 105, + 116, + 242, + 42, + 231, + 80, + 249, + 71, + 140, + 7, + 58, + 162, + 196, + 101, + 9, + 95, + 47, + 40, + 26, + 61, + 154, + 36, + 153, + 204, + 157, + 196, + 224, + 215, + 238, + 49, + 250, + 72, + 195, + 95, + 208, + 38, + 123, + 232, + 164, + 28, + 131, + 41, + 131, + 242, + 97, + 171, + 183, + 128, + 200, + 119, + 239, + 182, + 250, + 115, + 132, + 25, + 134, + 154, + 17, + 48, + 159, + 71, + 139, + 71, + 68, + 36, + 223, + 51, + 175, + 222, + 244, + 226, + 235, + 22, + 189, + 188, + 153, + 169, + 221, + 148, + 95, + 145, + 71, + 166, + 129, + 62, + 149, + 50, + 206, + 102, + 155, + 165, + 99, + 133, + 209, + 162, + 244, + 145, + 59, + 127, + 35, + 216, + 88, + 13, + 213, + 215, + 181, + 224, + 33, + 93, + 102, + 109, + 191, + 156, + 76, + 120, + 197, + 64, + 254, + 0, + 12, + 221, + 227, + 76, + 191, + 12, + 181, + 60, + 78, + 229, + 160, + 130, + 20, + 133, + 249, + 13, + 102, + 221, + 248, + 91, + 223, + 40, + 27, + 90, + 180, + 105, + 39, + 49, + 175, + 77, + 72, + 27, + 119, + 240, + 92, + 102, + 13, + 96, + 43, + 79, + 165, + 54, + 20, + 31, + 138, + 154, + 230, + 164, + 99, + 76, + 177, + 206, + 40, + 9, + 172, + 123, + 118, + 133, + 128, + 61, + 171, + 88, + 97, + 250, + 150, + 166, + 169, + 250, + 11, + 96, + 53, + 165, + 49, + 16, + 250, + 94, + 104, + 11, + 250, + 71, + 123, + 38, + 37, + 60, + 218, + 200, + 135, + 249, + 157, + 53, + 190, + 12, + 59, + 48, + 145, + 182, + 83, + 102, + 187, + 207, + 25, + 196, + 47, + 103, + 162, + 193, + 178, + 6, + 100, + 216, + 10, + 164, + 137, + 16, + 202, + 254, + 3, + 137, + 33, + 188, + 222, + 178, + 168, + 250, + 206, + 71, + 247, + 46, + 245, + 64, + 14, + 204, + 141, + 145, + 190, + 22, + 53, + 151, + 5, + 102, + 84, + 8, + 190, + 212, + 5, + 41, + 35, + 23, + 115, + 151, + 4, + 150, + 223, + 215, + 60, + 159, + 104, + 27, + 232, + 125, + 199, + 242, + 112, + 77, + 194, + 0, + 221, + 9, + 64, + 91, + 75, + 49, + 229, + 127, + 243, + 128, + 125, + 214, + 47, + 164, + 236, + 47, + 41, + 135, + 47, + 111, + 162, + 49, + 94, + 52, + 33, + 202, + 154, + 184, + 148, + 224, + 231, + 114, + 252, + 91, + 174, + 64, + 180, + 113, + 165, + 193, + 191, + 244, + 1, + 107, + 55, + 235, + 30, + 245, + 233, + 98, + 214, + 90, + 14, + 197, + 2, + 57, + 191, + 113, + 250, + 252, + 175, + 213, + 237, + 228, + 109, + 64, + 70, + 117, + 119, + 53, + 22, + 187, + 138, + 76, + 53, + 64, + 161, + 54, + 233, + 184, + 188, + 120, + 124, + 11, + 180, + 36, + 214, + 74, + 206, + 253, + 236, + 185, + 218, + 62, + 6, + 205, + 85, + 5, + 183, + 252, + 52, + 23, + 72, + 64, + 31, + 202, + 88, + 195, + 105, + 234, + 24, + 160, + 158, + 105, + 218, + 209, + 80, + 41, + 48, + 24, + 136, + 199, + 213, + 107, + 99, + 176, + 106, + 86, + 122, + 78, + 217, + 67, + 154, + 57, + 170, + 19, + 95, + 181, + 86, + 142, + 95, + 140, + 48, + 168, + 208, + 63, + 67, + 203, + 165, + 108, + 199, + 11, + 28, + 35, + 225, + 123, + 11, + 206, + 197, + 102, + 245, + 21, + 163, + 87, + 234, + 140, + 183, + 123, + 117, + 70, + 215, + 37, + 201, + 192, + 65, + 143, + 244, + 26, + 62, + 93, + 99, + 188, + 182, + 17, + 74, + 175, + 201, + 17, + 79, + 234, + 169, + 118, + 189, + 58, + 128, + 170, + 89, + 123, + 118, + 252, + 125, + 210, + 94, + 2, + 228, + 158, + 19, + 109, + 178, + 164, + 184, + 46, + 217, + 4, + 54, + 60, + 221, + 6, + 42, + 172, + 120, + 109, + 198, + 116, + 84, + 28, + 208, + 245, + 123, + 100, + 178, + 177, + 215, + 74, + 98, + 106, + 28, + 220, + 199, + 15, + 192, + 31, + 147, + 160, + 221, + 13, + 28, + 26, + 91, + 128, + 123, + 243, + 136, + 241, + 215, + 19, + 241, + 89, + 176, + 219, + 71, + 75, + 12, + 164, + 26, + 91, + 117, + 83, + 221, + 224, + 176, + 101, + 182, + 140, + 197, + 39, + 128, + 125, + 180, + 107, + 111, + 118, + 89, + 158, + 78, + 147, + 80, + 251, + 27, + 201, + 160, + 121, + 73, + 53, + 63, + 93, + 149, + 11, + 222, + 132, + 178, + 68, + 110, + 148, + 172, + 47, + 232, + 90, + 78, + 74, + 92, + 111, + 111, + 14, + 227, + 173, + 178, + 223, + 249, + 33, + 50, + 180, + 203, + 68, + 197, + 105, + 208, + 64, + 38, + 66, + 130, + 38, + 254, + 80, + 172, + 30, + 91, + 16, + 174, + 178, + 115, + 93, + 42, + 72, + 108, + 170, + 116, + 219, + 43, + 51, + 4, + 244, + 27, + 166, + 110, + 12, + 241, + 240, + 244, + 227, + 49, + 127, + 133, + 112, + 117, + 59, + 143, + 224, + 232, + 28, + 29, + 32, + 245, + 148, + 233, + 45, + 22, + 108, + 110, + 115, + 161, + 71, + 167, + 95, + 1, + 162, + 24, + 140, + 21, + 56, + 50, + 243, + 163, + 0, + 108, + 89, + 59, + 196, + 193, + 183, + 206, + 202, + 92, + 213, + 27, + 137, + 235, + 27, + 252, + 171, + 169, + 222, + 52, + 11, + 47, + 10, + 116, + 56, + 157, + 15, + 28, + 92, + 102, + 59, + 1, + 18, + 90, + 10, + 110, + 67, + 78, + 111, + 0, + 138, + 104, + 143, + 241, + 39, + 241, + 113, + 158, + 244, + 142, + 53, + 129, + 147, + 3, + 120, + 233, + 118, + 123, + 217, + 41, + 143, + 245, + 78, + 251, + 105, + 60, + 128, + 67, + 53, + 244, + 242, + 144, + 185, + 127, + 119, + 62, + 104, + 249, + 93, + 98, + 97, + 193, + 229, + 88, + 181, + 32, + 203, + 155, + 120, + 98, + 128, + 22, + 21, + 223, + 232, + 213, + 216, + 139, + 38, + 67, + 196, + 149, + 220, + 37, + 242, + 43, + 79, + 219, + 173, + 143, + 74, + 53, + 225, + 183, + 111, + 19, + 23, + 119, + 13, + 207, + 41, + 186, + 177, + 176, + 218, + 120, + 124, + 210, + 64, + 85, + 137, + 46, + 113, + 202, + 231, + 82, + 253, + 167, + 128, + 105, + 180, + 84, + 14, + 5, + 204, + 114, + 13, + 59, + 143, + 127, + 125, + 172, + 174, + 108, + 163, + 140, + 170, + 113, + 87, + 223, + 177, + 155, + 122, + 59, + 226, + 43, + 88, + 177, + 17, + 120, + 200, + 196, + 210, + 192, + 91, + 124, + 159, + 109, + 95, + 153, + 72, + 244, + 70, + 230, + 121, + 234, + 42, + 145, + 32, + 82, + 218, + 145, + 204, + 104, + 152, + 157, + 153, + 72, + 173, + 224, + 136, + 105, + 96, + 174, + 191, + 249, + 69, + 83, + 66, + 240, + 153, + 163, + 203, + 224, + 218, + 187, + 196, + 216, + 213, + 182, + 142, + 197, + 194, + 64, + 44, + 183, + 67, + 192, + 157, + 25, + 174, + 230, + 89, + 38, + 155, + 194, + 135, + 115, + 85, + 95, + 154, + 119, + 151, + 78, + 49, + 208, + 148, + 32, + 201, + 29, + 254, + 193, + 195, + 233, + 250, + 85, + 246, + 239, + 195, + 210, + 168, + 52, + 158, + 105, + 46, + 134, + 64, + 229, + 105, + 140, + 114, + 172, + 133, + 85, + 154, + 202, + 82, + 80, + 129, + 60, + 181, + 252, + 225, + 3, + 179, + 119, + 125, + 214, + 94, + 218, + 110, + 114, + 54, + 189, + 128, + 68, + 171, + 229, + 2, + 189, + 96, + 103, + 63, + 109, + 74, + 120, + 75, + 199, + 76, + 18, + 25, + 240, + 14, + 153, + 64, + 172, + 200, + 199, + 90, + 129, + 169, + 223, + 62, + 129, + 58, + 171, + 157, + 47, + 31, + 174, + 107, + 68, + 150, + 154, + 6, + 150, + 217, + 124, + 222, + 161, + 60, + 193, + 196, + 34, + 100, + 91, + 166, + 5, + 238, + 204, + 7, + 170, + 13, + 25, + 240, + 202, + 239, + 160, + 185, + 238, + 51, + 46, + 217, + 251, + 66, + 182, + 27, + 183, + 222, + 144, + 233, + 167, + 251, + 149, + 68, + 26, + 238, + 104, + 193, + 24, + 48, + 211, + 229, + 153, + 145, + 161, + 230, + 65, + 96, + 143, + 33, + 10, + 192, + 166, + 154, + 255, + 87, + 52, + 100, + 24, + 187, + 215, + 210, + 29, + 186, + 143, + 64, + 172, + 204, + 197, + 203, + 142, + 103, + 155, + 199, + 250, + 156, + 59, + 18, + 254, + 62, + 144, + 192, + 224, + 11, + 220, + 11, + 129, + 254, + 57, + 106, + 242, + 30, + 244, + 103, + 43, + 64, + 185, + 150, + 120, + 231, + 21, + 211, + 152, + 108, + 15, + 10, + 89, + 246, + 36, + 73, + 246, + 105, + 127, + 145, + 246, + 124, + 127, + 238, + 8, + 52, + 27, + 13, + 105, + 112, + 174, + 245, + 220, + 236, + 145, + 221, + 131, + 244, + 220, + 117, + 131, + 11, + 237, + 49, + 191, + 193, + 223, + 174, + 58, + 21, + 137, + 48, + 90, + 74, + 232, + 197, + 153, + 145, + 221, + 1, + 177, + 0, + 102, + 250, + 75, + 124, + 246, + 232, + 101, + 114, + 63, + 65, + 202, + 25, + 9, + 45, + 42, + 199, + 38, + 6, + 185, + 143, + 4, + 61, + 1, + 208, + 24, + 149, + 84, + 196, + 192, + 30, + 78, + 168, + 203, + 200, + 201, + 27, + 20, + 125, + 206, + 207, + 17, + 214, + 18, + 203, + 131, + 190, + 69, + 78, + 118, + 203, + 193, + 128, + 166, + 201, + 248, + 148, + 176, + 230, + 130, + 238, + 176, + 10, + 129, + 121, + 236, + 50, + 20, + 242, + 105, + 117, + 16, + 224, + 114, + 132, + 183, + 208, + 148, + 136, + 55, + 60, + 27, + 239, + 32, + 246, + 250, + 40, + 28, + 108, + 188, + 33, + 136, + 142, + 51, + 105, + 67, + 138, + 200, + 151, + 2, + 46, + 176, + 225, + 50, + 180, + 11, + 192, + 52, + 98, + 140, + 128, + 225, + 227, + 96, + 51, + 27, + 22, + 201, + 6, + 73, + 87, + 188, + 213, + 59, + 136, + 149, + 61, + 20, + 175, + 195, + 170, + 106, + 92, + 51, + 215, + 43, + 181, + 179, + 63, + 254, + 24, + 12, + 122, + 141, + 157, + 185, + 76, + 54, + 231, + 161, + 199, + 78, + 80, + 139, + 194, + 223, + 92, + 234, + 0, + 167, + 191, + 167, + 61, + 106, + 44, + 221, + 62, + 241, + 67, + 144, + 179, + 220, + 207, + 201, + 121, + 162, + 171, + 12, + 178, + 215, + 58, + 42, + 168, + 152, + 156, + 35, + 164, + 180, + 164, + 201, + 107, + 207, + 251, + 149, + 1, + 148, + 179, + 86, + 74, + 52, + 202, + 95, + 11, + 31, + 255, + 103, + 34, + 161, + 232, + 216, + 54, + 213, + 183, + 104, + 9, + 218, + 33, + 28, + 123, + 10, + 233, + 138, + 13, + 205, + 12, + 134, + 83, + 223, + 141, + 108, + 24, + 168, + 170, + 118, + 237, + 146, + 251, + 137, + 58, + 64, + 6, + 0, + 201, + 240, + 209, + 208, + 141, + 192, + 10, + 55, + 64, + 193, + 210, + 244, + 107, + 155, + 118, + 32, + 228, + 147, + 51, + 97, + 177, + 16, + 235, + 108, + 90, + 109, + 244, + 179, + 228, + 156, + 4, + 161, + 202, + 254, + 27, + 12, + 231, + 127, + 171, + 185, + 40, + 164, + 8, + 43, + 74, + 103, + 205, + 11, + 190, + 136, + 143, + 23, + 145, + 100, + 203, + 206, + 141, + 217, + 36, + 253, + 220, + 222, + 0, + 225, + 28, + 170, + 116, + 84, + 11, + 12, + 82, + 67, + 217, + 39, + 63, + 230, + 100, + 71, + 187, + 156, + 7, + 187, + 91, + 19, + 36, + 254, + 78, + 186, + 175, + 10, + 33, + 148, + 73, + 238, + 131, + 123, + 114, + 79, + 145, + 99, + 40, + 50, + 42, + 157, + 164, + 118, + 61, + 146, + 115, + 144, + 41, + 179, + 228, + 52, + 251, + 130, + 253, + 34, + 217, + 66, + 55, + 8, + 7, + 111, + 63, + 174, + 27, + 21, + 163, + 44, + 14, + 10, + 130, + 126, + 119, + 188, + 127, + 159, + 18, + 57, + 73, + 52, + 222, + 51, + 119, + 93, + 65, + 134, + 52, + 107, + 155, + 196, + 211, + 62, + 248, + 119, + 81, + 154, + 200, + 72, + 159, + 102, + 101, + 152, + 131, + 130, + 213, + 166, + 77, + 146, + 74, + 114, + 41, + 121, + 200, + 140, + 217, + 119, + 195, + 189, + 239, + 56, + 56, + 173, + 98, + 194, + 201, + 43, + 173, + 113, + 78, + 196, + 212, + 117, + 71, + 1, + 197, + 235, + 32, + 16, + 132, + 131, + 113, + 156, + 104, + 116, + 81, + 251, + 83, + 251, + 212, + 223, + 54, + 109, + 116, + 120, + 173, + 11, + 170, + 48, + 148, + 20, + 102, + 225, + 105, + 76, + 178, + 122, + 163, + 189, + 170, + 208, + 22, + 205, + 78, + 52, + 86, + 198, + 154, + 238, + 52, + 150, + 21, + 128, + 147, + 242, + 182, + 27, + 153, + 85, + 99, + 183, + 19, + 228, + 105, + 130, + 235, + 213, + 55, + 64, + 20, + 33, + 40, + 23, + 129, + 41, + 102, + 241, + 115, + 47, + 2, + 115, + 216, + 91, + 244, + 132, + 29, + 196, + 161, + 112, + 100, + 74, + 56, + 117, + 174, + 240, + 25, + 189, + 203, + 197, + 103, + 5, + 89, + 240, + 32, + 214, + 248, + 85, + 65, + 226, + 38, + 232, + 64, + 23, + 9, + 248, + 114, + 57, + 193, + 213, + 121, + 79, + 199, + 176, + 227, + 216, + 122, + 223, + 90, + 234, + 95, + 21, + 225, + 156, + 67, + 230, + 112, + 38, + 158, + 222, + 169, + 181, + 113, + 237, + 235, + 49, + 75, + 216, + 255, + 53, + 75, + 215, + 228, + 208, + 82, + 155, + 178, + 94, + 43, + 20, + 193, + 175, + 185, + 86, + 141, + 40, + 90, + 201, + 162, + 44, + 204, + 194, + 213, + 21, + 37, + 252, + 241, + 8, + 229, + 156, + 5, + 249, + 176, + 91, + 249, + 3, + 160, + 70, + 47, + 107, + 186, + 19, + 159, + 211, + 196, + 203, + 101, + 165, + 34, + 174, + 203, + 64, + 41, + 138, + 80, + 64, + 89, + 219, + 128, + 20, + 27, + 133, + 4, + 203, + 219, + 63, + 107, + 251, + 164, + 125, + 191, + 39, + 128, + 207, + 20, + 46, + 222, + 173, + 101, + 248, + 141, + 121, + 249, + 217, + 145, + 183, + 245, + 51, + 70, + 60, + 216, + 36, + 30, + 246, + 135, + 169, + 19, + 159, + 74, + 82, + 66, + 158, + 207, + 227, + 207, + 71, + 11, + 3, + 217, + 116, + 116, + 74, + 116, + 90, + 233, + 148, + 235, + 80, + 128, + 170, + 43, + 189, + 50, + 116, + 245, + 103, + 95, + 247, + 219, + 130, + 188, + 66, + 85, + 31, + 209, + 64, + 24, + 98, + 149, + 244, + 107, + 188, + 53, + 72, + 243, + 144, + 89, + 199, + 97, + 247, + 174, + 218, + 109, + 215, + 83, + 103, + 84, + 26, + 77, + 60, + 48, + 233, + 175, + 24, + 15, + 72, + 134, + 153, + 2, + 81, + 223, + 133, + 66, + 54, + 186, + 117, + 165, + 39, + 233, + 211, + 179, + 232, + 105, + 48, + 60, + 31, + 211, + 28, + 223, + 177, + 33, + 134, + 28, + 10, + 232, + 139, + 79, + 76, + 149, + 63, + 126, + 141, + 105, + 247, + 232, + 28, + 188, + 25, + 72, + 7, + 233, + 79, + 93, + 101, + 184, + 90, + 0, + 25, + 207, + 228, + 22, + 207, + 21, + 85, + 15, + 204, + 75, + 186, + 246, + 239, + 141, + 5, + 146, + 180, + 27, + 95, + 104, + 121, + 98, + 32, + 44, + 120, + 141, + 161, + 157, + 141, + 30, + 231, + 1, + 230, + 113, + 101, + 125, + 191, + 55, + 82, + 42, + 209, + 199, + 170, + 132, + 237, + 213, + 10, + 81, + 143, + 80, + 130, + 131, + 112, + 34, + 72, + 120, + 87, + 13, + 64, + 133, + 114, + 88, + 229, + 4, + 129, + 81, + 14, + 150, + 178, + 196, + 26, + 74, + 136, + 34, + 135, + 170, + 195, + 204, + 44, + 142, + 62, + 153, + 192, + 211, + 231, + 111, + 248, + 121, + 67, + 26, + 66, + 135, + 99, + 228, + 149, + 79, + 70, + 171, + 152, + 101, + 188, + 141, + 62, + 146, + 110, + 167, + 143, + 193, + 142, + 66, + 127, + 184, + 132, + 224, + 25, + 42, + 28, + 101, + 243, + 217, + 122, + 162, + 72, + 85, + 167, + 213, + 77, + 40, + 147, + 180, + 43, + 235, + 67, + 2, + 40, + 215, + 170, + 91, + 242, + 222, + 251, + 248, + 67, + 75, + 160, + 16, + 98, + 58, + 26, + 80, + 48, + 196, + 34, + 203, + 63, + 53, + 239, + 176, + 101, + 89, + 172, + 81, + 38, + 14, + 83, + 83, + 101, + 139, + 132, + 205, + 113, + 158, + 221, + 153, + 29, + 202, + 183, + 221, + 38, + 145, + 56, + 136, + 133, + 112, + 40, + 21, + 115, + 139, + 73, + 120, + 206, + 84, + 227, + 102, + 199, + 119, + 146, + 15, + 36, + 56, + 212, + 13, + 49, + 99, + 93, + 67, + 4, + 63, + 13, + 165, + 243, + 233, + 86, + 54, + 209, + 235, + 210, + 0, + 131, + 194, + 5, + 90, + 37, + 81, + 197, + 104, + 117, + 32, + 181, + 91, + 136, + 168, + 89, + 196, + 196, + 98, + 48, + 73, + 224, + 196, + 242, + 180, + 46, + 97, + 188, + 202, + 199, + 255, + 155, + 149, + 213, + 103, + 124, + 243, + 249, + 14, + 181, + 22, + 103, + 109, + 235, + 41, + 42, + 123, + 17, + 18, + 176, + 29, + 6, + 157, + 188, + 40, + 234, + 210, + 171, + 182, + 130, + 158, + 211, + 64, + 194, + 27, + 245, + 240, + 142, + 195, + 17, + 16, + 12, + 190, + 36, + 239, + 60, + 167, + 82, + 218, + 44, + 110, + 245, + 26, + 173, + 114, + 149, + 74, + 141, + 94, + 131, + 92, + 14, + 174, + 20, + 56, + 28, + 146, + 44, + 202, + 190, + 183, + 250, + 5, + 28, + 238, + 148, + 22, + 177, + 38, + 5, + 15, + 195, + 123, + 34, + 168, + 109, + 9, + 122, + 244, + 246, + 118, + 179, + 234, + 134, + 207, + 165, + 193, + 71, + 97, + 173, + 64, + 202, + 161, + 118, + 78, + 65, + 83, + 226, + 18, + 218, + 28, + 199, + 84, + 99, + 230, + 30, + 125, + 95, + 214, + 228, + 61, + 177, + 206, + 231, + 85, + 250, + 157, + 12, + 189, + 210, + 22, + 232, + 60, + 189, + 94, + 151, + 32, + 13, + 215, + 62, + 161, + 90, + 57, + 82, + 113, + 93, + 121, + 221, + 72, + 214, + 118, + 53, + 158, + 62, + 164, + 2, + 206, + 133, + 186, + 107, + 248, + 222, + 244, + 41, + 31, + 135, + 104, + 151, + 45, + 106, + 45, + 216, + 132, + 51, + 87, + 237, + 3, + 106, + 178, + 249, + 232, + 128, + 10, + 167, + 232, + 130, + 64, + 76, + 219, + 189, + 254, + 156, + 173, + 65, + 236, + 114, + 120, + 28, + 18, + 177, + 74, + 29, + 232, + 233, + 77, + 193, + 246, + 37, + 221, + 214, + 42, + 3, + 101, + 246, + 83, + 73, + 216, + 160, + 252, + 21, + 112, + 181, + 21, + 169, + 70, + 251, + 246, + 251, + 58, + 113, + 204, + 63, + 12, + 133, + 93, + 183, + 57, + 231, + 214, + 245, + 23, + 85, + 94, + 62, + 148, + 235, + 142, + 123, + 54, + 46, + 186, + 120, + 48, + 134, + 34, + 231, + 202, + 228, + 88, + 169, + 144, + 20, + 5, + 6, + 90, + 115, + 19, + 1, + 174, + 193, + 4, + 140, + 120, + 159, + 75, + 75, + 101, + 246, + 0, + 209, + 26, + 226, + 152, + 114, + 15, + 110, + 202, + 47, + 91, + 50, + 179, + 47, + 118, + 45, + 96, + 133, + 93, + 175, + 61, + 130, + 174, + 13, + 177, + 175, + 255, + 36, + 210, + 201, + 11, + 21, + 93, + 96, + 240, + 170, + 50, + 138, + 201, + 157, + 177, + 25, + 222, + 72, + 153, + 19, + 59, + 178, + 219, + 31, + 91, + 72, + 162, + 196, + 34, + 132, + 62, + 239, + 227, + 82, + 139, + 153, + 119, + 112, + 206, + 85, + 157, + 111, + 129, + 180, + 86, + 248, + 48, + 110, + 0, + 243, + 101, + 39, + 166, + 88, + 35, + 146, + 9, + 120, + 181, + 170, + 195, + 93, + 65, + 77, + 224, + 26, + 6, + 147, + 74, + 21, + 67, + 79, + 245, + 149, + 27, + 92, + 153, + 11, + 68, + 54, + 44, + 158, + 206, + 181, + 254, + 214, + 70, + 177, + 105, + 77, + 206, + 182, + 20, + 159, + 200, + 248, + 96, + 63, + 43, + 32, + 224, + 80, + 145, + 231, + 179, + 238, + 78, + 193, + 55, + 74, + 87, + 107, + 31, + 108, + 25, + 25, + 136, + 110, + 10, + 4, + 39, + 160, + 88, + 53, + 215, + 193, + 251, + 186, + 107, + 115, + 149, + 107, + 56, + 231, + 2, + 62, + 244, + 141, + 41, + 223, + 173, + 220, + 43, + 146, + 255, + 0, + 127, + 186, + 61, + 24, + 218, + 146, + 26, + 229, + 214, + 160, + 197, + 27, + 171, + 61, + 196, + 65, + 229, + 136, + 139, + 33, + 105, + 140, + 158, + 197, + 211, + 52, + 14, + 218, + 60, + 214, + 144, + 234, + 234, + 65, + 131, + 165, + 164, + 216, + 79, + 179, + 189, + 239, + 100, + 47, + 39, + 241, + 167, + 10, + 212, + 225, + 143, + 126, + 208, + 211, + 15, + 219, + 108, + 66, + 228, + 95, + 72, + 13, + 7, + 53, + 55, + 106, + 52, + 80, + 196, + 81, + 68, + 88, + 67, + 242, + 232, + 190, + 243, + 255, + 112, + 146, + 254, + 148, + 195, + 146, + 232, + 41, + 248, + 169, + 8, + 179, + 190, + 110, + 140, + 19, + 29, + 200, + 255, + 165, + 20, + 97, + 216, + 86, + 17, + 192, + 243, + 125, + 219, + 166, + 50, + 17, + 165, + 33, + 9, + 126, + 225, + 160, + 10, + 72, + 185, + 136, + 70, + 167, + 243, + 55, + 248, + 213, + 34, + 219, + 99, + 64, + 190, + 43, + 40, + 64, + 30, + 167, + 240, + 24, + 18, + 114, + 70, + 196, + 247, + 48, + 84, + 253, + 249, + 154, + 228, + 53, + 56, + 178, + 50, + 55, + 226, + 40, + 117, + 65, + 31, + 164, + 134, + 30, + 131, + 217, + 172, + 50, + 61, + 99, + 65, + 126, + 143, + 118, + 195, + 195, + 232, + 251, + 142, + 156, + 176, + 141, + 139, + 33, + 184, + 195, + 160, + 204, + 21, + 73, + 97, + 208, + 165, + 241, + 167, + 192, + 141, + 134, + 107, + 37, + 65, + 217, + 22, + 83, + 76, + 108, + 180, + 217, + 59, + 214, + 253, + 253, + 58, + 187, + 117, + 226, + 29, + 49, + 210, + 121, + 85, + 101, + 76, + 50, + 94, + 174, + 167, + 188, + 182, + 110, + 193, + 34, + 88, + 255, + 67, + 217, + 82, + 70, + 200, + 133, + 232, + 24, + 164, + 118, + 160, + 24, + 162, + 136, + 205, + 233, + 110, + 121, + 117, + 198, + 89, + 5, + 123, + 31, + 239, + 38, + 103, + 50, + 27, + 238, + 97, + 113, + 183, + 122, + 129, + 194, + 16, + 196, + 217, + 116, + 228, + 47, + 26, + 60, + 38, + 131, + 195, + 168, + 53, + 249, + 212, + 98, + 183, + 205, + 27, + 18, + 81, + 46, + 137, + 1, + 0, + 150, + 9, + 78, + 99, + 68, + 96, + 251, + 43, + 210, + 100, + 17, + 56, + 25, + 178, + 154, + 191, + 24, + 36, + 69, + 160, + 100, + 56, + 30, + 224, + 45, + 201, + 47, + 144, + 205, + 214, + 89, + 53, + 19, + 6, + 234, + 30, + 159, + 209, + 172, + 129, + 242, + 173, + 244, + 19, + 146, + 82, + 179, + 200, + 168, + 215, + 193, + 254, + 16, + 155, + 196, + 194, + 219, + 107, + 72, + 198, + 76, + 70, + 42, + 154, + 165, + 19, + 109, + 53, + 56, + 69, + 91, + 134, + 98, + 253, + 15, + 167, + 250, + 19, + 130, + 253, + 41, + 200, + 40, + 179, + 54, + 148, + 49, + 236, + 253, + 171, + 137, + 243, + 87, + 72, + 254, + 169, + 137, + 78, + 147, + 72, + 66, + 85, + 238, + 245, + 115, + 3, + 213, + 85, + 24, + 247, + 88, + 97, + 43, + 255, + 47, + 225, + 234, + 213, + 7, + 130, + 135, + 109, + 171, + 24, + 246, + 159, + 94, + 68, + 24, + 115, + 133, + 192, + 158, + 49, + 101, + 217, + 109, + 122, + 85, + 174, + 113, + 196, + 26, + 55, + 131, + 219, + 204, + 85, + 26, + 8, + 187, + 198, + 4, + 161, + 7, + 149, + 39, + 176, + 235, + 169, + 50, + 57, + 79, + 246, + 98, + 55, + 42, + 143, + 161, + 14, + 179, + 161, + 108, + 144, + 138, + 58, + 67, + 39, + 8, + 48, + 46, + 253, + 65, + 188, + 137, + 165, + 10, + 111, + 214, + 84, + 204, + 143, + 180, + 22, + 56, + 14, + 110, + 6, + 122, + 131, + 16, + 160, + 75, + 50, + 118, + 179, + 158, + 190, + 233, + 114, + 11, + 178, + 206, + 220, + 147, + 154, + 20, + 157, + 221, + 38, + 65, + 199, + 37, + 159, + 21, + 42, + 168, + 132, + 230, + 104, + 21, + 254, + 188, + 178, + 119, + 48, + 111, + 174, + 174, + 107, + 247, + 135, + 90, + 24, + 30, + 123, + 155, + 37, + 178, + 39, + 119, + 239, + 255, + 197, + 190, + 19, + 52, + 58, + 28, + 22, + 21, + 135, + 184, + 126, + 19, + 149, + 21, + 70, + 145, + 43, + 32, + 177, + 91, + 163, + 195, + 67, + 167, + 63, + 5, + 236, + 134, + 4, + 137, + 198, + 115, + 86, + 10, + 8, + 157, + 32, + 139, + 159, + 188, + 194, + 154, + 171, + 38, + 182, + 139, + 110, + 246, + 128, + 185, + 130, + 85, + 109, + 218, + 194, + 213, + 49, + 144, + 127, + 144, + 143, + 243, + 48, + 189, + 149, + 138, + 61, + 242, + 34, + 231, + 90, + 67, + 195, + 134, + 104, + 204, + 90, + 195, + 33, + 116, + 105, + 39, + 156, + 111, + 1, + 233, + 173, + 242, + 41, + 228, + 246, + 21, + 5, + 43, + 241, + 84, + 232, + 200, + 159, + 62, + 88, + 119, + 56, + 122, + 160, + 59, + 103, + 245, + 235, + 251, + 180, + 23, + 8, + 239, + 36, + 127, + 193, + 162, + 69, + 85, + 235, + 123, + 36, + 183, + 34, + 7, + 198, + 165, + 36, + 239, + 187, + 188, + 76, + 199, + 102, + 186, + 115, + 101, + 114, + 104, + 66, + 149, + 248, + 106, + 43, + 88, + 57, + 47, + 167, + 175, + 247, + 151, + 196, + 85, + 216, + 106, + 53, + 153, + 118, + 78, + 86, + 114, + 110, + 43, + 61, + 247, + 202, + 192, + 88, + 26, + 73, + 47, + 53, + 173, + 211, + 176, + 146, + 96, + 157, + 123, + 100, + 148, + 225, + 235, + 174, + 26, + 111, + 161, + 163, + 250, + 155, + 141, + 204, + 179, + 23, + 26, + 35, + 145, + 228, + 143, + 186, + 213, + 11, + 48, + 147, + 177, + 208, + 61, + 123, + 114, + 124, + 188, + 248, + 228, + 48, + 118, + 40, + 85, + 209, + 185, + 69, + 207, + 52, + 68, + 136, + 101, + 14, + 191, + 66, + 104, + 110, + 50, + 15, + 116, + 64, + 134, + 127, + 173, + 174, + 23, + 65, + 29, + 210, + 0, + 46, + 92, + 153, + 247, + 96, + 1, + 41, + 216, + 69, + 35, + 149, + 34, + 6, + 165, + 45, + 108, + 96, + 22, + 177, + 168, + 33, + 103, + 7, + 48, + 173, + 111, + 57, + 245, + 100, + 235, + 116, + 153, + 61, + 204, + 211, + 252, + 187, + 105, + 16, + 167, + 138, + 138, + 238, + 186, + 182, + 66, + 79, + 36, + 36, + 133, + 17, + 135, + 40, + 184, + 126, + 26, + 102, + 240, + 182, + 206, + 249, + 236, + 73, + 244, + 78, + 52, + 1, + 154, + 113, + 159, + 163, + 19, + 36, + 230, + 49, + 108, + 253, + 189, + 146, + 148, + 47, + 131, + 142, + 203, + 23, + 51, + 8, + 243, + 250, + 191, + 131, + 21, + 2, + 203, + 242, + 23, + 152, + 157, + 132, + 126, + 73, + 194, + 7, + 54, + 208, + 234, + 117, + 42, + 126, + 222, + 0, + 39, + 54, + 10, + 135, + 72, + 199, + 148, + 185, + 62, + 6, + 160, + 191, + 242, + 186, + 245, + 99, + 120, + 149, + 155, + 185, + 203, + 106, + 136, + 168, + 232, + 140, + 146, + 136, + 233, + 168, + 137, + 32, + 175, + 21, + 221, + 230, + 80, + 130, + 80, + 12, + 210, + 152, + 84, + 108, + 164, + 155, + 57, + 187, + 208, + 114, + 223, + 159, + 243, + 171, + 230, + 197, + 162, + 126, + 17, + 245, + 72, + 182, + 113, + 1, + 208, + 47, + 201, + 136, + 111, + 6, + 66, + 28, + 238, + 101, + 74, + 205, + 89, + 116, + 123, + 145, + 91, + 225, + 29, + 29, + 37, + 250, + 155, + 153, + 161, + 9, + 241, + 148, + 60, + 115, + 251, + 216, + 209, + 85, + 18, + 213, + 125, + 121, + 173, + 201, + 17, + 250, + 138, + 47, + 223, + 155, + 191, + 221, + 208, + 118, + 217, + 154, + 128, + 25, + 132, + 98, + 14, + 0, + 171, + 46, + 251, + 112, + 144, + 226, + 139, + 76, + 85, + 235, + 54, + 26, + 240, + 153, + 164, + 37, + 102, + 25, + 161, + 244, + 236, + 104, + 69, + 81, + 160, + 245, + 158, + 111, + 32, + 164, + 28, + 19, + 130, + 224, + 62, + 135, + 154, + 218, + 36, + 49, + 249, + 163, + 177, + 147, + 160, + 91, + 124, + 63, + 153, + 221, + 119, + 16, + 54, + 16, + 225, + 181, + 187, + 121, + 96, + 115, + 111, + 240, + 237, + 130, + 144, + 90, + 57, + 206, + 185, + 137, + 114, + 11, + 128, + 8, + 174, + 73, + 124, + 30, + 114, + 120, + 97, + 137, + 108, + 111, + 67, + 92, + 13, + 212, + 229, + 37, + 58, + 31, + 220, + 1, + 214, + 216, + 63, + 178, + 153, + 128, + 106, + 53, + 218, + 76, + 5, + 92, + 22, + 46, + 10, + 34, + 3, + 21, + 203, + 97, + 64, + 102, + 66, + 62, + 233, + 95, + 67, + 88, + 167, + 123, + 17, + 181, + 185, + 200, + 186, + 235, + 184, + 210, + 149, + 188, + 187, + 45, + 114, + 57, + 14, + 95, + 130, + 254, + 247, + 236, + 116, + 252, + 35, + 56, + 111, + 108, + 245, + 90, + 241, + 236, + 245, + 3, + 16, + 40, + 189, + 219, + 141, + 30, + 187, + 187, + 16, + 251, + 146, + 69, + 3, + 228, + 95, + 17, + 195, + 152, + 167, + 178, + 14, + 224, + 84, + 180, + 241, + 182, + 222, + 42, + 110, + 63, + 167, + 86, + 44, + 216, + 178, + 194, + 127, + 47, + 93, + 147, + 105, + 72, + 202, + 33, + 191, + 73, + 174, + 40, + 114, + 147, + 151, + 238, + 201, + 44, + 52, + 91, + 50, + 198, + 118, + 111, + 5, + 8, + 190, + 200, + 146, + 25, + 126, + 176, + 178, + 195, + 63, + 90, + 14, + 105, + 72, + 80, + 159, + 198, + 87, + 40, + 135, + 24, + 128, + 60, + 11, + 57, + 153, + 36, + 39, + 179, + 186, + 210, + 99, + 110, + 83, + 29, + 68, + 192, + 61, + 224, + 92, + 28, + 43, + 219, + 116, + 223, + 222, + 7, + 90, + 106, + 56, + 213, + 165, + 180, + 70, + 196, + 31, + 11, + 39, + 166, + 155, + 240, + 38, + 6, + 172, + 159, + 234, + 165, + 243, + 45, + 79, + 215, + 8, + 85, + 139, + 56, + 14, + 75, + 230, + 97, + 85, + 223, + 242, + 87, + 122, + 139, + 33, + 188, + 203, + 175, + 227, + 41, + 88, + 169, + 112, + 16, + 26, + 86, + 240, + 209, + 9, + 16, + 99, + 143, + 156, + 222, + 190, + 219, + 31, + 23, + 66, + 89, + 175, + 62, + 24, + 88, + 9, + 253, + 150, + 231, + 130, + 187, + 87, + 228, + 23, + 177, + 198, + 30, + 248, + 118, + 122, + 219, + 40, + 39, + 212, + 102, + 244, + 113, + 28, + 93, + 198, + 107, + 186, + 9, + 180, + 31, + 214, + 228, + 135, + 158, + 199, + 94, + 174, + 252, + 48, + 33, + 81, + 242, + 160, + 186, + 81, + 180, + 102, + 119, + 200, + 113, + 55, + 219, + 30, + 126, + 249, + 88, + 144, + 77, + 206, + 22, + 162, + 40, + 181, + 87, + 180, + 24, + 86, + 238, + 29, + 171, + 16, + 70, + 158, + 141, + 93, + 253, + 178, + 248, + 61, + 63, + 236, + 43, + 179, + 215, + 220, + 77, + 239, + 172, + 238, + 6, + 242, + 57, + 254, + 61, + 193, + 192, + 155, + 215, + 208, + 3, + 37, + 191, + 225, + 234, + 76, + 255, + 139, + 13, + 114, + 152, + 137, + 208, + 11, + 43, + 146, + 36, + 222, + 157, + 68, + 26, + 8, + 43, + 195, + 41, + 247, + 199, + 132, + 67, + 178, + 222, + 43, + 110, + 27, + 130, + 109, + 230, + 57, + 168, + 83, + 197, + 143, + 167, + 132, + 82, + 149, + 8, + 94, + 190, + 224, + 97, + 6, + 102, + 30, + 107, + 83, + 29, + 205, + 161, + 215, + 185, + 188, + 255, + 117, + 15, + 172, + 105, + 91, + 62, + 25, + 130, + 129, + 205, + 163, + 249, + 180, + 127, + 62, + 73, + 43, + 137, + 149, + 109, + 105, + 92, + 127, + 3, + 120, + 64, + 30, + 221, + 12, + 18, + 159, + 254, + 195, + 194, + 179, + 25, + 121, + 231, + 180, + 117, + 199, + 95, + 224, + 7, + 133, + 121, + 43, + 190, + 49, + 174, + 245, + 233, + 192, + 8, + 193, + 143, + 166, + 71, + 183, + 153, + 93, + 239, + 106, + 249, + 246, + 122, + 1, + 52, + 159, + 55, + 220, + 1, + 137, + 193, + 47, + 121, + 38, + 106, + 31, + 138, + 210, + 3, + 136, + 146, + 207, + 40, + 214, + 212, + 247, + 15, + 182, + 56, + 237, + 92, + 51, + 41, + 246, + 61, + 192, + 125, + 24, + 35, + 91, + 106, + 88, + 187, + 251, + 227, + 250, + 120, + 111, + 231, + 186, + 19, + 180, + 192, + 0, + 151, + 82, + 214, + 5, + 53, + 133, + 55, + 156, + 119, + 194, + 241, + 149, + 157, + 128, + 129, + 1, + 96, + 238, + 130, + 231, + 48, + 158, + 190, + 163, + 21, + 18, + 110, + 134, + 78, + 25, + 51, + 163, + 80, + 158, + 235, + 214, + 98, + 56, + 87, + 64, + 122, + 172, + 228, + 214, + 228, + 95, + 63, + 154, + 147, + 21, + 151, + 4, + 31, + 198, + 72, + 194, + 38, + 156, + 224, + 18, + 44, + 213, + 99, + 248, + 26, + 67, + 147, + 224, + 38, + 161, + 144, + 216, + 74, + 164, + 102, + 51, + 179, + 6, + 111, + 210, + 196, + 12, + 144, + 231, + 133, + 13, + 136, + 212, + 66, + 85, + 196, + 121, + 101, + 237, + 198, + 110, + 234, + 186, + 49, + 186, + 83, + 16, + 216, + 212, + 111, + 136, + 129, + 202, + 121, + 185, + 160, + 154, + 86, + 101, + 98, + 144, + 223, + 140, + 72, + 23, + 200, + 135, + 2, + 152, + 10, + 253, + 36, + 208, + 108, + 191, + 244, + 144, + 73, + 1, + 216, + 84, + 125, + 90, + 139, + 239, + 151, + 57, + 2, + 134, + 51, + 225, + 106, + 70, + 65, + 114, + 41, + 117, + 153, + 249, + 236, + 215, + 240, + 91, + 250, + 224, + 85, + 2, + 221, + 251, + 10, + 121, + 107, + 218, + 42, + 121, + 121, + 118, + 231, + 237, + 233, + 209, + 59, + 76, + 227, + 128, + 129, + 130, + 242, + 115, + 36, + 44, + 216, + 127, + 176, + 182, + 186, + 87, + 193, + 190, + 109, + 8, + 4, + 37, + 218, + 138, + 194, + 243, + 178, + 153, + 47, + 21, + 59, + 61, + 3, + 76, + 218, + 213, + 253, + 186, + 15, + 211, + 28, + 62, + 20, + 56, + 49, + 255, + 69, + 8, + 145, + 243, + 125, + 145, + 8, + 62, + 163, + 18, + 26, + 239, + 95, + 77, + 177, + 4, + 62, + 182, + 50, + 169, + 234, + 50, + 48, + 65, + 199, + 106, + 214, + 17, + 75, + 104, + 81, + 96, + 251, + 122, + 90, + 56, + 140, + 21, + 5, + 11, + 245, + 239, + 160, + 28, + 175, + 212, + 213, + 7, + 142, + 150, + 253, + 11, + 7, + 253, + 52, + 27, + 56, + 44, + 183, + 215, + 231, + 192, + 73, + 95, + 48, + 118, + 216, + 105, + 191, + 14, + 17, + 155, + 216, + 80, + 52, + 133, + 7, + 5, + 134, + 174, + 45, + 51, + 177, + 141, + 54, + 70, + 151, + 145, + 52, + 116, + 191, + 66, + 180, + 141, + 220, + 199, + 8, + 74, + 140, + 117, + 252, + 104, + 17, + 69, + 129, + 249, + 43, + 42, + 126, + 124, + 4, + 164, + 101, + 52, + 192, + 206, + 2, + 219, + 74, + 209, + 25, + 155, + 16, + 164, + 162, + 68, + 81, + 4, + 227, + 120, + 127, + 54, + 49, + 236, + 63, + 216, + 16, + 76, + 23, + 162, + 117, + 52, + 237, + 137, + 231, + 13, + 110, + 247, + 47, + 65, + 201, + 101, + 206, + 21, + 241, + 234, + 93, + 134, + 210, + 104, + 37, + 209, + 185, + 88, + 42, + 108, + 67, + 140, + 144, + 5, + 51, + 142, + 10, + 90, + 64, + 11, + 45, + 30, + 82, + 80, + 59, + 204, + 111, + 2, + 18, + 114, + 83, + 159, + 38, + 89, + 20, + 180, + 50, + 62, + 252, + 83, + 67, + 156, + 20, + 58, + 81, + 231, + 8, + 113, + 214, + 31, + 34, + 10, + 215, + 143, + 235, + 47, + 139, + 168, + 46, + 2, + 229, + 134, + 78, + 136, + 200, + 77, + 31, + 197, + 249, + 101, + 218, + 210, + 27, + 162, + 85, + 254, + 59, + 46, + 24, + 115, + 62, + 44, + 214, + 14, + 8, + 64, + 209, + 124, + 57, + 109, + 193, + 117, + 91, + 29, + 236, + 107, + 91, + 88, + 131, + 89, + 191, + 246, + 46, + 85, + 145, + 14, + 60, + 141, + 41, + 185, + 110, + 17, + 90, + 239, + 47, + 138, + 141, + 17, + 11, + 53, + 124, + 231, + 49, + 66, + 169, + 88, + 55, + 136, + 203, + 4, + 227, + 14, + 53, + 82, + 106, + 119, + 141, + 56, + 99, + 5, + 137, + 140, + 236, + 29, + 78, + 178, + 164, + 194, + 186, + 44, + 227, + 138, + 213, + 248, + 3, + 96, + 154, + 23, + 50, + 102, + 37, + 77, + 176, + 74, + 20, + 111, + 111, + 235, + 141, + 165, + 83, + 111, + 95, + 146, + 163, + 57, + 198, + 80, + 209, + 103, + 228, + 188, + 238, + 177, + 60, + 199, + 82, + 143, + 61, + 169, + 47, + 117, + 121, + 248, + 34, + 92, + 110, + 233, + 171, + 160, + 78, + 241, + 28, + 123, + 43, + 139, + 245, + 141, + 123, + 112, + 157, + 174, + 255, + 179, + 210, + 157, + 155, + 212, + 104, + 145, + 245, + 241, + 92, + 13, + 129, + 15, + 71, + 131, + 122, + 37, + 139, + 61, + 174, + 73, + 52, + 208, + 75, + 3, + 203, + 243, + 161, + 124, + 201, + 245, + 12, + 236, + 147, + 182, + 69, + 126, + 129, + 86, + 188, + 66, + 86, + 88, + 93, + 10, + 61, + 138, + 63, + 35, + 225, + 243, + 19, + 70, + 56, + 198, + 93, + 37, + 115, + 108, + 147, + 247, + 85, + 210, + 46, + 65, + 225, + 90, + 132, + 168, + 182, + 98, + 105, + 224, + 71, + 35, + 89, + 88, + 80, + 114, + 63, + 90, + 79, + 74, + 241, + 232, + 65, + 129, + 141, + 70, + 183, + 171, + 7, + 4, + 46, + 101, + 30, + 232, + 152, + 157, + 226, + 229, + 154, + 197, + 165, + 199, + 195, + 32, + 212, + 155, + 212, + 98, + 132, + 223, + 108, + 29, + 238, + 206, + 71, + 67, + 56, + 85, + 250, + 109, + 54, + 149, + 130, + 180, + 129, + 148, + 253, + 69, + 223, + 92, + 45, + 54, + 165, + 130, + 191, + 197, + 89, + 204, + 217, + 188, + 132, + 55, + 118, + 168, + 62, + 150, + 84, + 118, + 111, + 23, + 88, + 87, + 187, + 4, + 110, + 18, + 246, + 217, + 116, + 183, + 197, + 215, + 44, + 36, + 82, + 115, + 139, + 42, + 234, + 67, + 224, + 135, + 68, + 198, + 158, + 167, + 229, + 235, + 99, + 209, + 23, + 114, + 193, + 86, + 142, + 240, + 29, + 156, + 108, + 208, + 61, + 32, + 138, + 221, + 90, + 251, + 35, + 50, + 35, + 74, + 133, + 4, + 112, + 206, + 19, + 21, + 198, + 205, + 191, + 246, + 72, + 202, + 137, + 129, + 176, + 232, + 97, + 148, + 204, + 223, + 205, + 199, + 123, + 243, + 77, + 195, + 213, + 135, + 26, + 17, + 210, + 9, + 83, + 158, + 140, + 40, + 172, + 8, + 140, + 123, + 242, + 185, + 109, + 4, + 159, + 103, + 204, + 5, + 223, + 195, + 217, + 30, + 64, + 175, + 234, + 247, + 197, + 1, + 117, + 64, + 27, + 20, + 45, + 205, + 200, + 81, + 119, + 210, + 31, + 122, + 38, + 232, + 140, + 158, + 78, + 39, + 8, + 144, + 22, + 250, + 123, + 252, + 232, + 119, + 28, + 191, + 205, + 116, + 22, + 171, + 217, + 149, + 125, + 109, + 62, + 84, + 231, + 43, + 203, + 224, + 136, + 120, + 147, + 185, + 12, + 228, + 35, + 112, + 49, + 199, + 187, + 249, + 235, + 186, + 201, + 57, + 46, + 62, + 202, + 144, + 94, + 130, + 95, + 132, + 228, + 112, + 91, + 238, + 63, + 78, + 124, + 224, + 116, + 157, + 121, + 109, + 105, + 196, + 13, + 136, + 81, + 198, + 149, + 62, + 85, + 246, + 46, + 39, + 9, + 68, + 208, + 186, + 52, + 70, + 139, + 96, + 124, + 136, + 82, + 75, + 101, + 58, + 61, + 135, + 43, + 108, + 70, + 201, + 12, + 86, + 74, + 12, + 59, + 100, + 231, + 73, + 140, + 120, + 129, + 12, + 197, + 21, + 11, + 244, + 105, + 180, + 88, + 41, + 9, + 140, + 132, + 4, + 138, + 17, + 171, + 70, + 102, + 208, + 67, + 51, + 52, + 77, + 106, + 174, + 251, + 164, + 152, + 227, + 160, + 244, + 48, + 138, + 36, + 200, + 183, + 15, + 246, + 157, + 57, + 214, + 228, + 4, + 48, + 54, + 37, + 239, + 190, + 145, + 231, + 5, + 1, + 128, + 188, + 172, + 16, + 96, + 16, + 3, + 133, + 91, + 94, + 248, + 45, + 67, + 7, + 192, + 141, + 78, + 198, + 3, + 38, + 193, + 118, + 190, + 231, + 29, + 150, + 95, + 31, + 216, + 4, + 147, + 224, + 61, + 98, + 127, + 11, + 183, + 62, + 123, + 205, + 152, + 198, + 35, + 52, + 90, + 243, + 166, + 79, + 156, + 173, + 82, + 191, + 5, + 31, + 67, + 240, + 66, + 6, + 137, + 63, + 189, + 94, + 12, + 117, + 91, + 233, + 99, + 33, + 16, + 64, + 33, + 211, + 112, + 57, + 209, + 54, + 6, + 31, + 244, + 163, + 46, + 69, + 223, + 39, + 106, + 117, + 240, + 77, + 189, + 206, + 167, + 54, + 151, + 158, + 88, + 93, + 28, + 212, + 162, + 32, + 24, + 45, + 170, + 109, + 51, + 72, + 173, + 216, + 156, + 9, + 29, + 236, + 173, + 34, + 1, + 132, + 145, + 75, + 54, + 248, + 150, + 142, + 55, + 237, + 39, + 220, + 91, + 92, + 153, + 56, + 105, + 40, + 218, + 175, + 154, + 80, + 19, + 207, + 39, + 228, + 114, + 36, + 126, + 121, + 137, + 183, + 69, + 187, + 181, + 214, + 50, + 151, + 194, + 89, + 211, + 25, + 47, + 65, + 39, + 223, + 131, + 140, + 107, + 73, + 41, + 107, + 222, + 175, + 177, + 75, + 246, + 192, + 83, + 19, + 154, + 114, + 80, + 193, + 48, + 48, + 174, + 225, + 220, + 221, + 54, + 67, + 213, + 165, + 60, + 163, + 135, + 135, + 26, + 109, + 113, + 111, + 141, + 73, + 115, + 80, + 152, + 144, + 145, + 47, + 250, + 215, + 139, + 41, + 255, + 159, + 75, + 202, + 126, + 109, + 175, + 34, + 101, + 130, + 74, + 50, + 42, + 26, + 144, + 124, + 207, + 143, + 198, + 3, + 1, + 70, + 155, + 157, + 14, + 125, + 89, + 53, + 195, + 253, + 59, + 79, + 5, + 181, + 149, + 135, + 207, + 176, + 35, + 177, + 195, + 151, + 157, + 55, + 75, + 32, + 65, + 248, + 210, + 222, + 4, + 74, + 241, + 122, + 194, + 5, + 41, + 47, + 198, + 46, + 163, + 18, + 44, + 92, + 67, + 194, + 38, + 187, + 179, + 137, + 36, + 113, + 61, + 104, + 184, + 78, + 232, + 252, + 238, + 166, + 239, + 13, + 174, + 107, + 217, + 118, + 187, + 252, + 169, + 145, + 186, + 99, + 113, + 226, + 7, + 229, + 228, + 170, + 21, + 141, + 42, + 24, + 57, + 181, + 227, + 102, + 253, + 181, + 230, + 14, + 112, + 105, + 152, + 64, + 230, + 54, + 214, + 190, + 18, + 42, + 60, + 39, + 145, + 56, + 169, + 2, + 193, + 43, + 211, + 174, + 133, + 59, + 247, + 153, + 22, + 54, + 36, + 246, + 118, + 128, + 21, + 50, + 20, + 23, + 116, + 84, + 58, + 48, + 1, + 86, + 200, + 139, + 182, + 128, + 234, + 77, + 111, + 32, + 77, + 202, + 155, + 6, + 241, + 7, + 170, + 1, + 182, + 89, + 213, + 60, + 42, + 223, + 142, + 67, + 199, + 249, + 80, + 72, + 45, + 44, + 175, + 31, + 244, + 61, + 127, + 110, + 84, + 184, + 251, + 227, + 14, + 128, + 197, + 105, + 104, + 150, + 124, + 33, + 13, + 145, + 93, + 143, + 210, + 98, + 54, + 252, + 121, + 105, + 25, + 44, + 20, + 53, + 194, + 71, + 119, + 9, + 232, + 218, + 204, + 189, + 69, + 27, + 13, + 241, + 113, + 89, + 137, + 137, + 52, + 15, + 187, + 152, + 145, + 175, + 72, + 61, + 208, + 195, + 51, + 67, + 82, + 109, + 72, + 92, + 45, + 210, + 177, + 236, + 51, + 50, + 38, + 118, + 20, + 77, + 30, + 41, + 238, + 220, + 195, + 189, + 146, + 167, + 248, + 118, + 208, + 66, + 43, + 93, + 187, + 236, + 18, + 204, + 58, + 27, + 39, + 17, + 191, + 227, + 68, + 200, + 60, + 30, + 177, + 247, + 233, + 111, + 199, + 66, + 41, + 134, + 115, + 38, + 150, + 192, + 239, + 140, + 194, + 127, + 251, + 170, + 91, + 22, + 92, + 88, + 67, + 162, + 175, + 73, + 117, + 89, + 204, + 186, + 122, + 75, + 194, + 55, + 80, + 89, + 231, + 76, + 65, + 228, + 250, + 46, + 170, + 216, + 187, + 241, + 61, + 40, + 218, + 115, + 217, + 46, + 146, + 32, + 190, + 88, + 5, + 60, + 139, + 124, + 194, + 216, + 5, + 110, + 117, + 171, + 17, + 222, + 112, + 182, + 36, + 1, + 171, + 175, + 183, + 35, + 168, + 184, + 47, + 50, + 238, + 42, + 100, + 133, + 103, + 61, + 65, + 105, + 246, + 18, + 158, + 166, + 70, + 34, + 244, + 73, + 210, + 165, + 169, + 231, + 209, + 178, + 60, + 137, + 179, + 139, + 97, + 94, + 220, + 206, + 157, + 63, + 11, + 45, + 63, + 182, + 122, + 77, + 202, + 153, + 162, + 76, + 106, + 167, + 211, + 147, + 192, + 42, + 79, + 200, + 19, + 110, + 83, + 86, + 233, + 81, + 250, + 123, + 80, + 50, + 97, + 177, + 23, + 193, + 61, + 110, + 121, + 110, + 58, + 24, + 196, + 24, + 213, + 17, + 110, + 185, + 171, + 193, + 252, + 123, + 248, + 177, + 82, + 149, + 70, + 12, + 98, + 31, + 162, + 245, + 30, + 176, + 112, + 161, + 141, + 205, + 37, + 141, + 119, + 231, + 218, + 216, + 163, + 82, + 192, + 62, + 138, + 23, + 98, + 106, + 21, + 195, + 77, + 193, + 84, + 195, + 132, + 124, + 69, + 95, + 76, + 194, + 141, + 169, + 56, + 100, + 35, + 198, + 79, + 6, + 151, + 90, + 17, + 112, + 79, + 63, + 199, + 11, + 16, + 79, + 216, + 34, + 255, + 160, + 10, + 224, + 38, + 67, + 111, + 43, + 39, + 166, + 130, + 74, + 255, + 147, + 164, + 75, + 157, + 4, + 41, + 135, + 171, + 189, + 4, + 71, + 103, + 131, + 199, + 74, + 106, + 46, + 41, + 155, + 151, + 80, + 156, + 61, + 13, + 214, + 249, + 116, + 246, + 117, + 6, + 79, + 31, + 253, + 241, + 132, + 150, + 154, + 97, + 250, + 117, + 222, + 194, + 210, + 90, + 129, + 24, + 74, + 150, + 39, + 219, + 42, + 128, + 1, + 218, + 246, + 17, + 160, + 219, + 79, + 180, + 57, + 9, + 242, + 229, + 231, + 102, + 164, + 221, + 240, + 65, + 200, + 73, + 90, + 164, + 96, + 122, + 119, + 191, + 67, + 74, + 73, + 143, + 127, + 244, + 88, + 204, + 116, + 187, + 253, + 179, + 93, + 181, + 147, + 158, + 210, + 74, + 253, + 54, + 174, + 149, + 239, + 66, + 176, + 21, + 62, + 119, + 149, + 81, + 173, + 235, + 21, + 186, + 182, + 255, + 159, + 1, + 167, + 188, + 122, + 11, + 141, + 170, + 53, + 14, + 69, + 238, + 209, + 123, + 236, + 193, + 76, + 112, + 216, + 6, + 219, + 123, + 230, + 87, + 142, + 74, + 88, + 30, + 6, + 249, + 131, + 72, + 72, + 113, + 242, + 9, + 206, + 127, + 71, + 240, + 172, + 38, + 93, + 191, + 139, + 33, + 127, + 164, + 126, + 240, + 139, + 200, + 88, + 124, + 55, + 243, + 189, + 172, + 154, + 101, + 93, + 47, + 89, + 156, + 161, + 104, + 68, + 164, + 73, + 194, + 48, + 65, + 56, + 92, + 65, + 33, + 202, + 195, + 100, + 199, + 125, + 178, + 204, + 120, + 195, + 248, + 6, + 89, + 40, + 152, + 132, + 78, + 84, + 67, + 102, + 64, + 107, + 31, + 15, + 119, + 58, + 152, + 124, + 24, + 24, + 71, + 97, + 247, + 135, + 46, + 11, + 100, + 164, + 69, + 216, + 211, + 172, + 108, + 206, + 50, + 236, + 206, + 143, + 42, + 93, + 31, + 141, + 172, + 17, + 47, + 55, + 165, + 86, + 206, + 178, + 158, + 108, + 181, + 108, + 56, + 231, + 193, + 29, + 18, + 230, + 133, + 86, + 44, + 241, + 180, + 223, + 212, + 72, + 219, + 202, + 239, + 58, + 201, + 143, + 54, + 231, + 186, + 173, + 167, + 195, + 193, + 15, + 100, + 47, + 136, + 192, + 36, + 212, + 2, + 211, + 83, + 49, + 219, + 68, + 41, + 155, + 212, + 242, + 6, + 232, + 10, + 123, + 83, + 11, + 203, + 185, + 76, + 105, + 31, + 123, + 182, + 228, + 85, + 97, + 82, + 74, + 191, + 150, + 25, + 132, + 72, + 220, + 226, + 224, + 243, + 251, + 148, + 18, + 255, + 10, + 78, + 40, + 109, + 13, + 182, + 31, + 132, + 245, + 181, + 123, + 33, + 135, + 195, + 217, + 203, + 233, + 35, + 253, + 158, + 87, + 85, + 203, + 4, + 233, + 122, + 153, + 210, + 213, + 251, + 127, + 36, + 251, + 94, + 152, + 240, + 69, + 247, + 14, + 38, + 210, + 171, + 166, + 140, + 120, + 18, + 144, + 243, + 154, + 220, + 38, + 255, + 199, + 26, + 140, + 147, + 189, + 28, + 36, + 194, + 70, + 125, + 124, + 99, + 25, + 220, + 140, + 255, + 200, + 0, + 98, + 130, + 241, + 62, + 14, + 45, + 138, + 187, + 181, + 21, + 218, + 77, + 146, + 62, + 255, + 233, + 91, + 128, + 107, + 177, + 160, + 19, + 67, + 24, + 206, + 197, + 188, + 122, + 29, + 144, + 123, + 90, + 31, + 86, + 220, + 182, + 30, + 199, + 49, + 140, + 148, + 24, + 103, + 170, + 122, + 0, + 49, + 64, + 82, + 123, + 222, + 56, + 61, + 77, + 128, + 109, + 151, + 119, + 61, + 253, + 9, + 199, + 89, + 102, + 74, + 69, + 128, + 230, + 196, + 5, + 128, + 158, + 24, + 222, + 143, + 121, + 164, + 112, + 96, + 66, + 50, + 163, + 138, + 194, + 24, + 50, + 222, + 125, + 74, + 35, + 121, + 61, + 121, + 66, + 231, + 140, + 22, + 236, + 55, + 145, + 254, + 200, + 162, + 236, + 3, + 222, + 112, + 29, + 209, + 192, + 129, + 14, + 79, + 197, + 154, + 192, + 92, + 197, + 117, + 22, + 19, + 145, + 11, + 77, + 89, + 176, + 219, + 186, + 47, + 21, + 115, + 250, + 249, + 65, + 156, + 154, + 112, + 158, + 18, + 127, + 229, + 243, + 117, + 202, + 185, + 158, + 231, + 187, + 194, + 52, + 37, + 109, + 78, + 250, + 231, + 227, + 166, + 55, + 125, + 25, + 31, + 178, + 207, + 60, + 135, + 128, + 234, + 148, + 36, + 80, + 208, + 248, + 221, + 168, + 44, + 34, + 129, + 15, + 6, + 237, + 61, + 132, + 148, + 8, + 84, + 38, + 47, + 94, + 143, + 240, + 243, + 123, + 32, + 253, + 74, + 236, + 0, + 139, + 6, + 40, + 91, + 178, + 28, + 219, + 74, + 137, + 49, + 141, + 137, + 5, + 249, + 96, + 181, + 43, + 156, + 46, + 41, + 56, + 206, + 237, + 52, + 225, + 97, + 160, + 1, + 147, + 200, + 200, + 7, + 113, + 85, + 243, + 40, + 152, + 238, + 12, + 163, + 184, + 237, + 41, + 190, + 36, + 100, + 112, + 238, + 49, + 172, + 143, + 10, + 249, + 234, + 81, + 218, + 181, + 54, + 61, + 109, + 18, + 1, + 105, + 150, + 59, + 68, + 223, + 125, + 170, + 179, + 176, + 213, + 126, + 131, + 109, + 39, + 4, + 8, + 23, + 145, + 174, + 163, + 253, + 197, + 84, + 109, + 113, + 11, + 127, + 166, + 111, + 89, + 189, + 129, + 252, + 122, + 56, + 85, + 162, + 156, + 13, + 25, + 82, + 40, + 1, + 99, + 152, + 210, + 254, + 180, + 77, + 115, + 100, + 128, + 10, + 198, + 53, + 26, + 106, + 101, + 242, + 38, + 124, + 76, + 47, + 234, + 154, + 177, + 254, + 109, + 199, + 33, + 74, + 162, + 27, + 117, + 184, + 192, + 2, + 223, + 64, + 97, + 144, + 61, + 64, + 11, + 235, + 254, + 137, + 47, + 96, + 21, + 158, + 49, + 93, + 4, + 156, + 235, + 97, + 229, + 191, + 37, + 63, + 16, + 114, + 59, + 224, + 35, + 212, + 24, + 248, + 51, + 178, + 169, + 215, + 111, + 158, + 203, + 51, + 98, + 175, + 253, + 74, + 89, + 231, + 157, + 44, + 13, + 118, + 121, + 46, + 58, + 76, + 45, + 219, + 205, + 22, + 36, + 128, + 193, + 82, + 95, + 227, + 235, + 203, + 248, + 168, + 21, + 75, + 94, + 198, + 8, + 135, + 202, + 45, + 52, + 109, + 159, + 149, + 98, + 50, + 182, + 110, + 140, + 47, + 234, + 166, + 18, + 154, + 104, + 31, + 228, + 199, + 26, + 224, + 149, + 149, + 40, + 122, + 235, + 78, + 202, + 104, + 223, + 34, + 94, + 239, + 71, + 79, + 67, + 63, + 40, + 129, + 163, + 25, + 16, + 30, + 184, + 20, + 203, + 62, + 231, + 246, + 166, + 169, + 143, + 228, + 180, + 251, + 61, + 52, + 151, + 238, + 43, + 10, + 20, + 76, + 192, + 171, + 76, + 68, + 184, + 248, + 82, + 244, + 203, + 152, + 226, + 101, + 254, + 168, + 251, + 42, + 115, + 8, + 229, + 124, + 230, + 79, + 73, + 9, + 131, + 160, + 74, + 238, + 190, + 94, + 25, + 253, + 91, + 58, + 233, + 63, + 216, + 25, + 84, + 197, + 108, + 162, + 182, + 150, + 153, + 51, + 93, + 253, + 93, + 246, + 38, + 203, + 145, + 214, + 246, + 32, + 254, + 204, + 8, + 135, + 20, + 0, + 145, + 144, + 20, + 25, + 196, + 14, + 103, + 123, + 115, + 122, + 145, + 126, + 53, + 73, + 203, + 28, + 84, + 169, + 91, + 109, + 169, + 159, + 191, + 127, + 100, + 201, + 239, + 3, + 74, + 253, + 215, + 181, + 203, + 66, + 155, + 116, + 173, + 150, + 235, + 209, + 80, + 144, + 95, + 21, + 21, + 237, + 23, + 108, + 62, + 155, + 60, + 236, + 32, + 38, + 60, + 38, + 55, + 50, + 207, + 186, + 98, + 112, + 101, + 41, + 68, + 72, + 52, + 99, + 214, + 53, + 29, + 79, + 46, + 194, + 104, + 231, + 163, + 194, + 168, + 41, + 61, + 23, + 226, + 213, + 66, + 133, + 129, + 130, + 75, + 69, + 56, + 66, + 51, + 135, + 178, + 141, + 169, + 133, + 21, + 18, + 233, + 81, + 126, + 187, + 40, + 44, + 18, + 222, + 29, + 102, + 198, + 252, + 6, + 126, + 253, + 54, + 190, + 9, + 233, + 204, + 150, + 204, + 175, + 75, + 105, + 201, + 104, + 118, + 251, + 47, + 44, + 209, + 145, + 231, + 20, + 62, + 7, + 249, + 241, + 138, + 57, + 127, + 175, + 83, + 164, + 232, + 22, + 61, + 67, + 219, + 151, + 204, + 188, + 217, + 62, + 42, + 49, + 41, + 67, + 246, + 121, + 218, + 176, + 166, + 229, + 83, + 64, + 81, + 6, + 174, + 190, + 120, + 115, + 196, + 11, + 63, + 90, + 182, + 111, + 227, + 125, + 15, + 127, + 229, + 149, + 234, + 134, + 146, + 130, + 139, + 5, + 83, + 117, + 124, + 62, + 183, + 81, + 142, + 227, + 119, + 20, + 240, + 63, + 140, + 104, + 141, + 131, + 92, + 30, + 19, + 61, + 95, + 45, + 205, + 99, + 7, + 110, + 101, + 93, + 39, + 6, + 34, + 154, + 22, + 139, + 22, + 35, + 135, + 204, + 109, + 59, + 149, + 29, + 101, + 100, + 66, + 80, + 200, + 157, + 133, + 169, + 79, + 40, + 69, + 134, + 94, + 173, + 41, + 32, + 210, + 120, + 209, + 227, + 14, + 48, + 117, + 65, + 240, + 140, + 44, + 10, + 99, + 128, + 193, + 93, + 204, + 44, + 219, + 203, + 148, + 155, + 183, + 242, + 134, + 226, + 44, + 123, + 165, + 43, + 73, + 140, + 197, + 204, + 71, + 22, + 138, + 198, + 80, + 247, + 241, + 254, + 174, + 200, + 21, + 57, + 189, + 46, + 98, + 20, + 165, + 107, + 196, + 110, + 169, + 58, + 98, + 26, + 89, + 45, + 32, + 4, + 86, + 187, + 71, + 134, + 194, + 138, + 81, + 103, + 129, + 38, + 46, + 79, + 154, + 118, + 102, + 26, + 247, + 1, + 178, + 223, + 254, + 177, + 225, + 243, + 55, + 183, + 43, + 221, + 114, + 144, + 177, + 2, + 17, + 216, + 156, + 111, + 225, + 166, + 244, + 98, + 241, + 200, + 176, + 239, + 206, + 178, + 85, + 109, + 163, + 45, + 236, + 126, + 86, + 27, + 68, + 187, + 185, + 173, + 71, + 72, + 83, + 120, + 210, + 55, + 214, + 231, + 182, + 49, + 12, + 101, + 170, + 23, + 250, + 237, + 59, + 185, + 41, + 113, + 47, + 114, + 28, + 108, + 28, + 224, + 226, + 217, + 191, + 40, + 69, + 196, + 224, + 118, + 23, + 75, + 209, + 3, + 136, + 51, + 137, + 25, + 119, + 33, + 103, + 220, + 249, + 160, + 107, + 180, + 98, + 33, + 162, + 235, + 76, + 92, + 119, + 199, + 72, + 34, + 46, + 32, + 253, + 78, + 172, + 149, + 109, + 105, + 52, + 150, + 142, + 196, + 48, + 184, + 59, + 12, + 25, + 157, + 138, + 65, + 253, + 119, + 83, + 80, + 247, + 242, + 28, + 1, + 224, + 170, + 43, + 74, + 188, + 213, + 178, + 110, + 91, + 215, + 177, + 37, + 41, + 19, + 7, + 139, + 241, + 1, + 42, + 109, + 208, + 214, + 153, + 238, + 19, + 12, + 42, + 71, + 210, + 38, + 131, + 95, + 133, + 233, + 126, + 143, + 217, + 227, + 16, + 63, + 200, + 110, + 246, + 167, + 12, + 237, + 229, + 224, + 233, + 82, + 50, + 41, + 198, + 249, + 193, + 84, + 105, + 29, + 157, + 149, + 76, + 139, + 158, + 14, + 143, + 50, + 155, + 198, + 40, + 70, + 236, + 69, + 68, + 42, + 219, + 229, + 25, + 16, + 4, + 102, + 192, + 183, + 28, + 127, + 59, + 202, + 131, + 104, + 109, + 216, + 180, + 90, + 57, + 84, + 202, + 46, + 180, + 123, + 216, + 168, + 118, + 205, + 27, + 170, + 217, + 134, + 184, + 62, + 214, + 147, + 30, + 142, + 208, + 55, + 75, + 208, + 70, + 240, + 67, + 39, + 139, + 4, + 49, + 119, + 77, + 206, + 216, + 61, + 220, + 22, + 108, + 159, + 209, + 82, + 127, + 148, + 136, + 114, + 83, + 125, + 224, + 236, + 244, + 117, + 140, + 152, + 165, + 153, + 206, + 168, + 117, + 28, + 38, + 1, + 106, + 246, + 168, + 105, + 190, + 26, + 63, + 223, + 137, + 18, + 132, + 52, + 169, + 8, + 0, + 203, + 109, + 46, + 54, + 122, + 34, + 240, + 62, + 161, + 126, + 92, + 92, + 23, + 8, + 139, + 157, + 240, + 84, + 221, + 160, + 173, + 43, + 69, + 88, + 171, + 30, + 89, + 110, + 110, + 135, + 140, + 212, + 214, + 142, + 216, + 9, + 239, + 231, + 110, + 253, + 54, + 201, + 113, + 131, + 250, + 63, + 17, + 190, + 92, + 118, + 212, + 79, + 159, + 128, + 102, + 18, + 131, + 87, + 249, + 229, + 84, + 71, + 192, + 55, + 48, + 81, + 225, + 169, + 233, + 139, + 39, + 105, + 31, + 50, + 252, + 221, + 40, + 238, + 121, + 10, + 8, + 221, + 24, + 47, + 158, + 244, + 101, + 34, + 226, + 32, + 126, + 89, + 78, + 183, + 249, + 28, + 19, + 197, + 210, + 165, + 86, + 98, + 81, + 26, + 49, + 102, + 21, + 64, + 89, + 170, + 78, + 109, + 125, + 52, + 113, + 142, + 18, + 87, + 35, + 202, + 213, + 23, + 242, + 190, + 168, + 70, + 106, + 217, + 250, + 201, + 86, + 72, + 235, + 25, + 176, + 139, + 50, + 87, + 245, + 188, + 130, + 203, + 108, + 101, + 196, + 8, + 218, + 142, + 247, + 237, + 77, + 208, + 164, + 99, + 164, + 183, + 174, + 32, + 221, + 218, + 88, + 228, + 111, + 74, + 17, + 167, + 51, + 27, + 57, + 219, + 101, + 192, + 187, + 49, + 37, + 166, + 11, + 49, + 185, + 21, + 69, + 134, + 70, + 40, + 170, + 143, + 239, + 133, + 21, + 139, + 23, + 168, + 94, + 207, + 1, + 179, + 93, + 228, + 114, + 85, + 227, + 65, + 249, + 111, + 160, + 87, + 45, + 14, + 83, + 215, + 56, + 189, + 128, + 84, + 24, + 135, + 74, + 24, + 243, + 150, + 116, + 251, + 131, + 54, + 66, + 16, + 36, + 2, + 76, + 4, + 51, + 226, + 99, + 108, + 63, + 5, + 42, + 87, + 254, + 78, + 221, + 1, + 196, + 160, + 24, + 42, + 36, + 149, + 226, + 128, + 106, + 192, + 112, + 199, + 47, + 70, + 103, + 112, + 12, + 193, + 228, + 97, + 24, + 58, + 94, + 180, + 57, + 75, + 202, + 120, + 251, + 0, + 195, + 183, + 143, + 161, + 68, + 104, + 55, + 138, + 94, + 213, + 70, + 208, + 95, + 145, + 29, + 23, + 232, + 84, + 152, + 123, + 85, + 118, + 170, + 129, + 106, + 197, + 148, + 94, + 197, + 15, + 198, + 80, + 34, + 154, + 156, + 149, + 189, + 209, + 34, + 85, + 12, + 116, + 38, + 73, + 241, + 33, + 0, + 152, + 26, + 220, + 39, + 13, + 149, + 87, + 178, + 123, + 162, + 19, + 61, + 26, + 176, + 137, + 32, + 170, + 43, + 48, + 4, + 47, + 138, + 40, + 13, + 203, + 194, + 160, + 173, + 120, + 36, + 186, + 64, + 2, + 59, + 27, + 220, + 245, + 243, + 88, + 93, + 240, + 135, + 22, + 63, + 37, + 193, + 139, + 229, + 178, + 152, + 24, + 250, + 211, + 72, + 52, + 36, + 72, + 130, + 165, + 243, + 147, + 219, + 80, + 238, + 143, + 44, + 150, + 106, + 200, + 246, + 227, + 233, + 97, + 38, + 68, + 193, + 218, + 39, + 69, + 17, + 150, + 54, + 250, + 110, + 194, + 236, + 210, + 54, + 254, + 140, + 35, + 178, + 27, + 141, + 160, + 85, + 57, + 13, + 14, + 71, + 45, + 43, + 250, + 246, + 233, + 44, + 72, + 212, + 44, + 46, + 166, + 189, + 182, + 208, + 178, + 67, + 132, + 10, + 77, + 104, + 61, + 233, + 15, + 129, + 213, + 214, + 159, + 157, + 42, + 53, + 248, + 250, + 31, + 16, + 5, + 141, + 217, + 6, + 194, + 106, + 236, + 126, + 252, + 199, + 89, + 79, + 167, + 103, + 224, + 56, + 38, + 0, + 24, + 114, + 9, + 1, + 83, + 22, + 46, + 221, + 42, + 3, + 13, + 146, + 254, + 81, + 17, + 68, + 78, + 137, + 137, + 61, + 221, + 175, + 161, + 3, + 163, + 224, + 253, + 250, + 99, + 12, + 172, + 52, + 69, + 203, + 59, + 70, + 192, + 154, + 29, + 124, + 149, + 73, + 135, + 216, + 134, + 172, + 73, + 168, + 14, + 34, + 220, + 15, + 73, + 46, + 185, + 84, + 240, + 166, + 82, + 93, + 41, + 52, + 38, + 50, + 155, + 171, + 187, + 178, + 88, + 133, + 173, + 60, + 153, + 69, + 171, + 43, + 142, + 222, + 189, + 253, + 146, + 150, + 89, + 210, + 49, + 63, + 101, + 98, + 75, + 10, + 62, + 169, + 126, + 68, + 160, + 65, + 196, + 38, + 180, + 132, + 69, + 211, + 38, + 165, + 66, + 10, + 102, + 196, + 233, + 170, + 215, + 181, + 14, + 226, + 242, + 122, + 200, + 190, + 70, + 140, + 254, + 103, + 89, + 206, + 121, + 27, + 249, + 89, + 119, + 215, + 177, + 51, + 13, + 35, + 109, + 178, + 101, + 39, + 112, + 215, + 91, + 183, + 100, + 81, + 205, + 181, + 240, + 163, + 254, + 245, + 190, + 40, + 117, + 138, + 37, + 99, + 244, + 71, + 152, + 12, + 144, + 54, + 104, + 226, + 200, + 21, + 84, + 171, + 120, + 197, + 44, + 121, + 96, + 225, + 143, + 220, + 62, + 111, + 29, + 4, + 110, + 81, + 132, + 254, + 78, + 215, + 37, + 1, + 16, + 77, + 20, + 46, + 173, + 8, + 201, + 173, + 204, + 15, + 170, + 141, + 62, + 77, + 233, + 153, + 96, + 57, + 164, + 228, + 131, + 185, + 166, + 130, + 148, + 44, + 3, + 227, + 159, + 36, + 54, + 178, + 179, + 106, + 162, + 97, + 85, + 34, + 220, + 89, + 139, + 199, + 204, + 173, + 223, + 219, + 171, + 83, + 222, + 138, + 6, + 67, + 205, + 119, + 134, + 93, + 32, + 17, + 124, + 69, + 52, + 231, + 45, + 255, + 190, + 112, + 147, + 19, + 235, + 75, + 25, + 200, + 178, + 9, + 122, + 155, + 128, + 242, + 115, + 33, + 152, + 241, + 252, + 131, + 191, + 118, + 0, + 73, + 71, + 133, + 202, + 221, + 31, + 63, + 77, + 85, + 245, + 239, + 179, + 40, + 252, + 231, + 121, + 186, + 166, + 143, + 71, + 125, + 70, + 23, + 122, + 3, + 51, + 126, + 91, + 170, + 213, + 1, + 189, + 157, + 183, + 195, + 174, + 65, + 230, + 78, + 191, + 23, + 239, + 30, + 115, + 66, + 82, + 196, + 157, + 152, + 2, + 55, + 192, + 75, + 110, + 93, + 147, + 133, + 82, + 254, + 34, + 84, + 137, + 27, + 96, + 253, + 55, + 130, + 251, + 122, + 211, + 15, + 20, + 82, + 166, + 113, + 17, + 52, + 161, + 129, + 156, + 12, + 242, + 207, + 232, + 110, + 102, + 25, + 60, + 158, + 175, + 21, + 204, + 226, + 100, + 102, + 5, + 171, + 49, + 240, + 36, + 69, + 240, + 183, + 45, + 180, + 133, + 55, + 222, + 60, + 34, + 13, + 192, + 68, + 19, + 86, + 16, + 19, + 156, + 48, + 195, + 57, + 166, + 163, + 205, + 38, + 32, + 225, + 86, + 47, + 4, + 175, + 136, + 18, + 17, + 36, + 250, + 103, + 95, + 78, + 33, + 94, + 199, + 48, + 156, + 198, + 47, + 33, + 147, + 122, + 78, + 112, + 71, + 96, + 149, + 156, + 94, + 141, + 232, + 15, + 71, + 11, + 119, + 5, + 173, + 143, + 119, + 239, + 244, + 192, + 245, + 166, + 50, + 41, + 178, + 84, + 140, + 226, + 209, + 110, + 190, + 171, + 94, + 117, + 14, + 32, + 64, + 64, + 172, + 62, + 85, + 234, + 37, + 217, + 131, + 233, + 12, + 82, + 56, + 74, + 72, + 199, + 163, + 241, + 167, + 12, + 128, + 5, + 116, + 54, + 123, + 205, + 128, + 242, + 10, + 253, + 115, + 136, + 29, + 230, + 18, + 157, + 78, + 86, + 155, + 16, + 49, + 112, + 177, + 220, + 4, + 78, + 57, + 168, + 105, + 57, + 187, + 46, + 34, + 110, + 205, + 0, + 210, + 109, + 191, + 24, + 160, + 26, + 24, + 217, + 141, + 154, + 207, + 247, + 170, + 120, + 196, + 189, + 134, + 47, + 97, + 224, + 83, + 36, + 90, + 245, + 104, + 255, + 62, + 115, + 96, + 23, + 134, + 59, + 170, + 97, + 54, + 44, + 23, + 140, + 181, + 102, + 87, + 209, + 148, + 32, + 89, + 198, + 161, + 218, + 68, + 192, + 250, + 47, + 129, + 113, + 129, + 145, + 97, + 153, + 66, + 34, + 134, + 12, + 247, + 244, + 105, + 81, + 174, + 169, + 254, + 140, + 91, + 88, + 9, + 241, + 64, + 222, + 84, + 119, + 190, + 173, + 216, + 197, + 56, + 77, + 126, + 48, + 254, + 164, + 48, + 99, + 187, + 0, + 198, + 164, + 18, + 77, + 83, + 226, + 225, + 235, + 225, + 31, + 174, + 224, + 29, + 167, + 73, + 162, + 24, + 190, + 61, + 225, + 48, + 39, + 228, + 11, + 215, + 11, + 134, + 10, + 152, + 72, + 231, + 39, + 176, + 166, + 16, + 150, + 204, + 2, + 4, + 235, + 109, + 133, + 66, + 219, + 56, + 237, + 142, + 12, + 73, + 1, + 218, + 235, + 13, + 134, + 76, + 183, + 51, + 31, + 197, + 181, + 182, + 208, + 83, + 22, + 210, + 7, + 69, + 196, + 28, + 83, + 237, + 225, + 32, + 66, + 211, + 88, + 206, + 239, + 150, + 204, + 86, + 40, + 45, + 214, + 99, + 142, + 149, + 53, + 190, + 14, + 65, + 39, + 81, + 10, + 241, + 24, + 202, + 199, + 188, + 58, + 108, + 102, + 208, + 12, + 44, + 109, + 57, + 86, + 248, + 229, + 212, + 46, + 237, + 183, + 168, + 163, + 61, + 182, + 74, + 21, + 138, + 133, + 177, + 55, + 191, + 35, + 41, + 78, + 64, + 122, + 82, + 131, + 204, + 242, + 207, + 226, + 77, + 216, + 90, + 28, + 16, + 177, + 219, + 123, + 207, + 2, + 105, + 37, + 62, + 217, + 4, + 77, + 235, + 10, + 12, + 152, + 73, + 132, + 61, + 25, + 108, + 193, + 43, + 62, + 76, + 197, + 80, + 105, + 138, + 204, + 228, + 144, + 8, + 21, + 221, + 1, + 132, + 246, + 172, + 159, + 131, + 27, + 199, + 152, + 109, + 162, + 31, + 134, + 101, + 105, + 47, + 44, + 90, + 162, + 228, + 19, + 20, + 142, + 154, + 216, + 62, + 91, + 113, + 13, + 75, + 199, + 49, + 42, + 160, + 210, + 66, + 46, + 165, + 21, + 150, + 9, + 221, + 221, + 199, + 17, + 17, + 148, + 54, + 71, + 192, + 200, + 92, + 228, + 219, + 90, + 10, + 128, + 35, + 19, + 149, + 31, + 154, + 161, + 119, + 83, + 211, + 65, + 253, + 215, + 242, + 133, + 79, + 48, + 207, + 118, + 145, + 180, + 26, + 108, + 165, + 42, + 20, + 15, + 151, + 46, + 59, + 90, + 197, + 15, + 210, + 6, + 99, + 73, + 19, + 240, + 179, + 194, + 96, + 165, + 82, + 3, + 1, + 176, + 67, + 125, + 161, + 81, + 169, + 61, + 44, + 151, + 79, + 47, + 172, + 26, + 113, + 219, + 36, + 171, + 213, + 149, + 42, + 252, + 26, + 184, + 138, + 105, + 23, + 187, + 167, + 126, + 26, + 238, + 75, + 91, + 129, + 197, + 128, + 152, + 242, + 138, + 13, + 108, + 105, + 13, + 13, + 123, + 95, + 175, + 240, + 104, + 184, + 49, + 156, + 133, + 103, + 162, + 127, + 151, + 41, + 245, + 108, + 237, + 182, + 167, + 242, + 64, + 81, + 96, + 128, + 176, + 241, + 202, + 42, + 221, + 72, + 3, + 233, + 193, + 4, + 106, + 106, + 212, + 188, + 10, + 179, + 203, + 58, + 23, + 206, + 114, + 204, + 29, + 136, + 142, + 102, + 115, + 164, + 24, + 128, + 177, + 18, + 105, + 194, + 47, + 87, + 213, + 164, + 5, + 247, + 253, + 230, + 57, + 112, + 88, + 193, + 87, + 167, + 42, + 197, + 44, + 250, + 4, + 136, + 183, + 217, + 148, + 138, + 108, + 8, + 209, + 44, + 151, + 55, + 186, + 243, + 52, + 0, + 255, + 34, + 35, + 23, + 155, + 28, + 16, + 211, + 70, + 106, + 128, + 112, + 213, + 215, + 241, + 104, + 56, + 223, + 104, + 234, + 57, + 90, + 237, + 207, + 80, + 86, + 88, + 33, + 73, + 114, + 40, + 136, + 1, + 246, + 12, + 60, + 36, + 177, + 126, + 231, + 37, + 220, + 73, + 131, + 196, + 144, + 151, + 42, + 86, + 234, + 143, + 160, + 90, + 64, + 140, + 218, + 202, + 126, + 90, + 114, + 158, + 85, + 150, + 225, + 237, + 145, + 99, + 72, + 210, + 16, + 234, + 184, + 97, + 64, + 81, + 41, + 40, + 120, + 196, + 205, + 62, + 119, + 168, + 202, + 47, + 50, + 231, + 34, + 170, + 95, + 15, + 174, + 103, + 170, + 59, + 254, + 209, + 0, + 29, + 96, + 146, + 193, + 76, + 131, + 153, + 213, + 251, + 252, + 16, + 117, + 213, + 143, + 223, + 142, + 186, + 125, + 162, + 25, + 31, + 69, + 195, + 169, + 237, + 166, + 211, + 130, + 170, + 52, + 233, + 170, + 25, + 32, + 40, + 82, + 153, + 55, + 125, + 13, + 37, + 67, + 41, + 106, + 209, + 164, + 166, + 118, + 52, + 71, + 181, + 117, + 1, + 86, + 58, + 183, + 187, + 157, + 3, + 255, + 225, + 198, + 50, + 93, + 88, + 221, + 163, + 245, + 199, + 142, + 14, + 42, + 165, + 20, + 104, + 60, + 113, + 180, + 4, + 1, + 191, + 250, + 108, + 230, + 108, + 162, + 142, + 158, + 111, + 99, + 168, + 60, + 91, + 11, + 48, + 144, + 48, + 78, + 193, + 131, + 192, + 181, + 142, + 23, + 84, + 193, + 147, + 13, + 155, + 29, + 218, + 231, + 187, + 30, + 48, + 132, + 250, + 235, + 100, + 185, + 245, + 203, + 105, + 62, + 53, + 140, + 72, + 229, + 17, + 255, + 34, + 24, + 24, + 243, + 154, + 95, + 43, + 221, + 216, + 101, + 104, + 174, + 185, + 231, + 30, + 19, + 14, + 218, + 102, + 236, + 151, + 129, + 93, + 94, + 88, + 67, + 235, + 150, + 29, + 174, + 37, + 185, + 32, + 163, + 248, + 118, + 26, + 202, + 81, + 39, + 202, + 123, + 160, + 193, + 61, + 154, + 190, + 15, + 224, + 47, + 147, + 213, + 219, + 80, + 156, + 18, + 148, + 36, + 155, + 43, + 140, + 177, + 81, + 219, + 19, + 70, + 31, + 11, + 221, + 169, + 235, + 31, + 244, + 214, + 82, + 44, + 151, + 213, + 242, + 219, + 190, + 117, + 183, + 67, + 208, + 220, + 184, + 67, + 134, + 8, + 4, + 89, + 105, + 79, + 101, + 8, + 241, + 144, + 223, + 37, + 138, + 112, + 61, + 73, + 48, + 31, + 137, + 161, + 154, + 112, + 171, + 94, + 207, + 28, + 147, + 111, + 181, + 229, + 60, + 58, + 251, + 100, + 136, + 12, + 253, + 180, + 47, + 46, + 109, + 99, + 91, + 205, + 35, + 252, + 175, + 108, + 64, + 37, + 192, + 97, + 65, + 141, + 182, + 221, + 150, + 12, + 0, + 208, + 96, + 14, + 222, + 148, + 133, + 70, + 39, + 141, + 97, + 185, + 81, + 131, + 157, + 1, + 241, + 217, + 123, + 222, + 177, + 129, + 254, + 102, + 60, + 134, + 225, + 130, + 24, + 52, + 158, + 85, + 153, + 154, + 3, + 130, + 144, + 32, + 49, + 119, + 126, + 71, + 226, + 114, + 59, + 107, + 40, + 113, + 156, + 113, + 119, + 159, + 147, + 132, + 88, + 234, + 80, + 4, + 232, + 116, + 247, + 63, + 219, + 212, + 82, + 129, + 78, + 75, + 48, + 138, + 2, + 33, + 174, + 76, + 96, + 164, + 89, + 72, + 128, + 87, + 79, + 229, + 135, + 171, + 81, + 115, + 221, + 162, + 126, + 113, + 240, + 243, + 66, + 248, + 124, + 253, + 165, + 172, + 114, + 197, + 122, + 8, + 174, + 158, + 196, + 76, + 100, + 51, + 22, + 156, + 235, + 2, + 157, + 222, + 86, + 83, + 253, + 201, + 217, + 103, + 159, + 220, + 81, + 68, + 12, + 168, + 7, + 21, + 49, + 9, + 219, + 72, + 80, + 106, + 148, + 20, + 52, + 54, + 217, + 194, + 56, + 8, + 84, + 113, + 169, + 121, + 92, + 213, + 253, + 88, + 185, + 117, + 52, + 9, + 40, + 219, + 221, + 124, + 7, + 103, + 59, + 103, + 70, + 1, + 18, + 220, + 242, + 76, + 224, + 206, + 146, + 105, + 34, + 210, + 150, + 248, + 187, + 6, + 135, + 198, + 215, + 71, + 132, + 157, + 172, + 68, + 44, + 99, + 181, + 151, + 218, + 131, + 119, + 96, + 232, + 229, + 250, + 165, + 56, + 47, + 216, + 124, + 38, + 189, + 72, + 90, + 58, + 144, + 80, + 240, + 74, + 6, + 12, + 36, + 48, + 189, + 109, + 83, + 9, + 110, + 134, + 19, + 23, + 158, + 103, + 246, + 105, + 30, + 23, + 130, + 58, + 139, + 112, + 164, + 222, + 216, + 103, + 206, + 49, + 164, + 150, + 174, + 105, + 194, + 92, + 9, + 217, + 234, + 64, + 109, + 245, + 247, + 204, + 184, + 69, + 171, + 2, + 131, + 64, + 32, + 21, + 70, + 77, + 90, + 112, + 19, + 110, + 21, + 58, + 187, + 213, + 191, + 204, + 229, + 67, + 62, + 177, + 94, + 2, + 13, + 223, + 13, + 91, + 2, + 29, + 46, + 209, + 8, + 151, + 55, + 170, + 235, + 108, + 167, + 198, + 167, + 201, + 62, + 188, + 19, + 103, + 255, + 242, + 70, + 20, + 94, + 152, + 215, + 65, + 87, + 65, + 223, + 98, + 147, + 173, + 147, + 161, + 135, + 25, + 144, + 130, + 114, + 198, + 204, + 183, + 104, + 163, + 158, + 116, + 219, + 173, + 85, + 114, + 140, + 16, + 172, + 209, + 100, + 87, + 70, + 221, + 47, + 167, + 193, + 227, + 20, + 9, + 210, + 177, + 52, + 201, + 249, + 163, + 28, + 213, + 117, + 196, + 129, + 217, + 109, + 68, + 113, + 131, + 189, + 71, + 159, + 49, + 219, + 6, + 65, + 126, + 94, + 63, + 187, + 206, + 188, + 100, + 102, + 175, + 164, + 81, + 190, + 184, + 36, + 67, + 47, + 60, + 197, + 144, + 139, + 68, + 81, + 70, + 145, + 174, + 64, + 79, + 24, + 14, + 56, + 246, + 7, + 109, + 163, + 14, + 23, + 41, + 87, + 52, + 58, + 157, + 172, + 27, + 227, + 204, + 19, + 2, + 121, + 222, + 194, + 105, + 95, + 164, + 4, + 128, + 14, + 134, + 13, + 98, + 49, + 88, + 194, + 246, + 124, + 209, + 178, + 16, + 7, + 107, + 238, + 79, + 187, + 77, + 206, + 48, + 213, + 160, + 155, + 69, + 180, + 171, + 174, + 81, + 113, + 48, + 9, + 205, + 202, + 248, + 130, + 55, + 122, + 136, + 109, + 161, + 64, + 44, + 195, + 217, + 44, + 22, + 224, + 176, + 243, + 173, + 57, + 214, + 245, + 196, + 120, + 26, + 90, + 122, + 232, + 43, + 224, + 218, + 203, + 46, + 9, + 152, + 234, + 107, + 149, + 51, + 80, + 38, + 79, + 210, + 6, + 194, + 30, + 126, + 137, + 21, + 105, + 232, + 227, + 216, + 126, + 253, + 114, + 197, + 163, + 94, + 243, + 130, + 233, + 37, + 220, + 211, + 227, + 214, + 207, + 53, + 179, + 92, + 110, + 57, + 242, + 20, + 27, + 144, + 247, + 230, + 255, + 195, + 182, + 47, + 3, + 80, + 115, + 99, + 96, + 157, + 187, + 152, + 4, + 126, + 123, + 161, + 155, + 213, + 158, + 145, + 94, + 105, + 230, + 66, + 171, + 7, + 74, + 120, + 5, + 190, + 190, + 155, + 0, + 47, + 173, + 143, + 0, + 214, + 252, + 104, + 99, + 48, + 23, + 171, + 102, + 53, + 164, + 200, + 37, + 86, + 169, + 73, + 33, + 74, + 188, + 49, + 52, + 20, + 38, + 202, + 123, + 177, + 216, + 89, + 3, + 194, + 63, + 206, + 103, + 41, + 173, + 177, + 36, + 66, + 166, + 74, + 52, + 166, + 13, + 59, + 166, + 197, + 131, + 13, + 240, + 20, + 133, + 115, + 69, + 23, + 159, + 116, + 185, + 69, + 84, + 153, + 215, + 112, + 102, + 22, + 70, + 37, + 146, + 221, + 82, + 192, + 88, + 57, + 206, + 51, + 14, + 8, + 68, + 217, + 120, + 14, + 19, + 20, + 96, + 47, + 218, + 95, + 183, + 184, + 115, + 249, + 252, + 131, + 141, + 85, + 128, + 247, + 212, + 33, + 5, + 200, + 67, + 72, + 174, + 3, + 38, + 24, + 186, + 69, + 117, + 101, + 137, + 15, + 231, + 16, + 107, + 134, + 87, + 129, + 167, + 146, + 39, + 177, + 75, + 83, + 8, + 78, + 116, + 173, + 133, + 157, + 76, + 219, + 150, + 163, + 88, + 64, + 245, + 166, + 103, + 151, + 250, + 139, + 112, + 91, + 196, + 47, + 25, + 212, + 130, + 35, + 147, + 146, + 144, + 149, + 87, + 162, + 85, + 227, + 194, + 233, + 126, + 2, + 60, + 246, + 81, + 191, + 98, + 45, + 35, + 243, + 82, + 223, + 248, + 156, + 187, + 83, + 189, + 95, + 43, + 215, + 179, + 135, + 213, + 127, + 47, + 199, + 29, + 181, + 246, + 180, + 205, + 77, + 194, + 170, + 178, + 228, + 130, + 91, + 83, + 228, + 251, + 13, + 143, + 9, + 172, + 168, + 237, + 92, + 2, + 10, + 250, + 224, + 229, + 195, + 217, + 9, + 70, + 222, + 140, + 124, + 101, + 93, + 47, + 39, + 170, + 62, + 106, + 110, + 203, + 254, + 0, + 110, + 247, + 15, + 46, + 156, + 114, + 91, + 164, + 35, + 237, + 65, + 55, + 125, + 139, + 168, + 160, + 118, + 95, + 170, + 253, + 88, + 6, + 78, + 152, + 32, + 158, + 251, + 55, + 198, + 13, + 170, + 174, + 116, + 135, + 179, + 250, + 154, + 150, + 97, + 142, + 205, + 209, + 72, + 10, + 237, + 167, + 132, + 39, + 197, + 239, + 219, + 196, + 169, + 204, + 157, + 104, + 185, + 101, + 51, + 28, + 76, + 229, + 76, + 124, + 158, + 17, + 151, + 203, + 1, + 243, + 79, + 199, + 41, + 87, + 82, + 226, + 153, + 47, + 8, + 211, + 231, + 8, + 191, + 156, + 213, + 72, + 19, + 187, + 254, + 249, + 150, + 99, + 20, + 215, + 234, + 55, + 223, + 195, + 140, + 54, + 190, + 228, + 108, + 75, + 199, + 55, + 83, + 108, + 192, + 210, + 229, + 4, + 171, + 155, + 135, + 84, + 43, + 133, + 199, + 125, + 25, + 126, + 0, + 241, + 68, + 138, + 103, + 24, + 148, + 62, + 46, + 113, + 220, + 186, + 244, + 30, + 211, + 71, + 11, + 67, + 233, + 78, + 32, + 250, + 16, + 74, + 38, + 49, + 49, + 175, + 137, + 10, + 75, + 142, + 138, + 151, + 198, + 86, + 27, + 248, + 66, + 187, + 218, + 99, + 22, + 0, + 87, + 95, + 72, + 87, + 54, + 219, + 245, + 31, + 138, + 104, + 11, + 2, + 59, + 56, + 13, + 181, + 198, + 186, + 198, + 60, + 231, + 212, + 34, + 234, + 187, + 50, + 91, + 31, + 67, + 211, + 87, + 95, + 196, + 54, + 179, + 85, + 102, + 3, + 120, + 205, + 189, + 206, + 54, + 181, + 61, + 200, + 54, + 248, + 111, + 189, + 0, + 76, + 56, + 132, + 147, + 149, + 57, + 13, + 215, + 254, + 80, + 18, + 99, + 224, + 189, + 134, + 83, + 9, + 63, + 186, + 97, + 115, + 99, + 37, + 66, + 165, + 105, + 25, + 45, + 250, + 202, + 86, + 242, + 61, + 33, + 21, + 8, + 55, + 219, + 241, + 59, + 117, + 50, + 237, + 169, + 201, + 140, + 147, + 244, + 213, + 60, + 188, + 215, + 33, + 73, + 22, + 119, + 113, + 185, + 235, + 178, + 66, + 86, + 144, + 130, + 63, + 211, + 213, + 197, + 86, + 153, + 193, + 246, + 254, + 227, + 222, + 78, + 182, + 107, + 221, + 125, + 156, + 41, + 216, + 108, + 209, + 115, + 232, + 33, + 104, + 98, + 175, + 73, + 10, + 90, + 56, + 70, + 58, + 254, + 248, + 81, + 216, + 79, + 135, + 242, + 96, + 21, + 200, + 248, + 212, + 102, + 7, + 207, + 192, + 50, + 223, + 124, + 12, + 162, + 126, + 46, + 159, + 49, + 120, + 216, + 4, + 242, + 144, + 41, + 170, + 225, + 54, + 49, + 148, + 37, + 134, + 230, + 87, + 252, + 147, + 236, + 166, + 74, + 68, + 48, + 165, + 72, + 139, + 192, + 255, + 53, + 107, + 187, + 49, + 175, + 84, + 9, + 141, + 26, + 131, + 252, + 110, + 24, + 210, + 224, + 205, + 255, + 92, + 161, + 73, + 170, + 6, + 32, + 153, + 206, + 34, + 191, + 24, + 79, + 161, + 245, + 131, + 97, + 65, + 46, + 8, + 165, + 38, + 204, + 80, + 94, + 11, + 207, + 176, + 45, + 71, + 175, + 252, + 118, + 108, + 208, + 209, + 130, + 52, + 189, + 101, + 187, + 70, + 168, + 25, + 50, + 47, + 9, + 21, + 190, + 236, + 78, + 192, + 129, + 51, + 228, + 92, + 174, + 183, + 91, + 130, + 81, + 59, + 221, + 134, + 253, + 73, + 26, + 78, + 196, + 43, + 183, + 44, + 110, + 127, + 203, + 242, + 64, + 231, + 131, + 199, + 246, + 158, + 228, + 146, + 228, + 37, + 60, + 12, + 252, + 168, + 202, + 33, + 235, + 87, + 84, + 139, + 214, + 69, + 72, + 199, + 233, + 104, + 30, + 98, + 53, + 252, + 54, + 123, + 93, + 139, + 251, + 151, + 104, + 130, + 118, + 249, + 176, + 92, + 83, + 122, + 82, + 102, + 141, + 92, + 233, + 79, + 192, + 109, + 159, + 211, + 152, + 164, + 147, + 163, + 49, + 169, + 156, + 181, + 198, + 78, + 0, + 247, + 18, + 26, + 104, + 155, + 59, + 52, + 221, + 166, + 54, + 136, + 179, + 215, + 58, + 185, + 156, + 184, + 23, + 108, + 39, + 47, + 114, + 92, + 160, + 237, + 221, + 119, + 233, + 232, + 94, + 67, + 30, + 117, + 183, + 226, + 169, + 166, + 110, + 161, + 109, + 239, + 252, + 76, + 43, + 182, + 205, + 141, + 105, + 222, + 40, + 26, + 197, + 191, + 9, + 132, + 49, + 204, + 160, + 93, + 14, + 41, + 253, + 166, + 0, + 180, + 161, + 31, + 159, + 22, + 221, + 170, + 215, + 21, + 94, + 153, + 122, + 178, + 74, + 24, + 210, + 21, + 35, + 90, + 206, + 228, + 189, + 202, + 26, + 103, + 230, + 209, + 72, + 89, + 118, + 155, + 17, + 93, + 1, + 100, + 20, + 248, + 75, + 8, + 179, + 170, + 48, + 208, + 244, + 227, + 67, + 255, + 224, + 162, + 213, + 15, + 82, + 92, + 30, + 3, + 109, + 155, + 18, + 68, + 213, + 203, + 159, + 127, + 107, + 108, + 248, + 166, + 19, + 157, + 72, + 115, + 207, + 31, + 175, + 144, + 95, + 217, + 38, + 4, + 78, + 41, + 167, + 68, + 46, + 0, + 91, + 180, + 61, + 106, + 39, + 13, + 61, + 230, + 217, + 244, + 49, + 55, + 174, + 31, + 202, + 186, + 150, + 17, + 28, + 61, + 193, + 58, + 130, + 224, + 1, + 150, + 140, + 47, + 219, + 63, + 117, + 84, + 58, + 181, + 198, + 41, + 48, + 108, + 60, + 45, + 102, + 136, + 8, + 62, + 34, + 6, + 44, + 179, + 51, + 19, + 134, + 114, + 80, + 8, + 120, + 54, + 220, + 181, + 204, + 118, + 182, + 107, + 238, + 56, + 153, + 78, + 253, + 100, + 178, + 15, + 253, + 155, + 84, + 191, + 57, + 131, + 15, + 26, + 41, + 131, + 157, + 35, + 105, + 165, + 61, + 250, + 28, + 124, + 156, + 145, + 14, + 158, + 176, + 114, + 171, + 136, + 29, + 203, + 34, + 189, + 181, + 189, + 77, + 199, + 205, + 189, + 65, + 175, + 78, + 212, + 209, + 10, + 106, + 172, + 31, + 78, + 110, + 12, + 217, + 113, + 127, + 253, + 139, + 253, + 195, + 112, + 121, + 82, + 177, + 240, + 90, + 199, + 192, + 175, + 162, + 46, + 174, + 141, + 101, + 250, + 156, + 171, + 42, + 98, + 71, + 115, + 219, + 110, + 110, + 6, + 212, + 193, + 96, + 89, + 203, + 219, + 213, + 24, + 172, + 180, + 20, + 249, + 96, + 216, + 204, + 120, + 152, + 61, + 123, + 37, + 36, + 85, + 153, + 57, + 30, + 29, + 58, + 77, + 237, + 197, + 73, + 160, + 9, + 100, + 253, + 217, + 36, + 103, + 82, + 71, + 19, + 0, + 235, + 199, + 153, + 123, + 128, + 18, + 234, + 214, + 154, + 251, + 36, + 238, + 228, + 224, + 121, + 86, + 239, + 114, + 100, + 63, + 115, + 76, + 225, + 77, + 65, + 89, + 103, + 62, + 157, + 197, + 138, + 41, + 152, + 183, + 241, + 162, + 166, + 216, + 4, + 38, + 237, + 20, + 44, + 145, + 251, + 202, + 239, + 173, + 206, + 144, + 57, + 157, + 249, + 226, + 45, + 227, + 196, + 104, + 217, + 119, + 207, + 228, + 86, + 148, + 69, + 64, + 19, + 191, + 75, + 56, + 30, + 119, + 16, + 174, + 19, + 114, + 160, + 250, + 215, + 147, + 92, + 154, + 44, + 149, + 65, + 151, + 161, + 118, + 70, + 252, + 67, + 155, + 221, + 191, + 168, + 113, + 202, + 20, + 249, + 90, + 224, + 13, + 94, + 87, + 196, + 128, + 12, + 44, + 28, + 178, + 157, + 208, + 237, + 69, + 18, + 170, + 90, + 253, + 178, + 123, + 54, + 255, + 113, + 104, + 67, + 208, + 192, + 248, + 29, + 138, + 80, + 179, + 47, + 24, + 229, + 132, + 65, + 68, + 99, + 194, + 13, + 53, + 9, + 98, + 146, + 162, + 164, + 221, + 70, + 210, + 46, + 72, + 74, + 153, + 130, + 146, + 183, + 20, + 14, + 52, + 19, + 15, + 198, + 235, + 107, + 46, + 248, + 29, + 51, + 10, + 31, + 50, + 67, + 168, + 119, + 110, + 175, + 44, + 215, + 77, + 218, + 173, + 170, + 141, + 119, + 95, + 114, + 43, + 152, + 154, + 40, + 203, + 190, + 53, + 200, + 151, + 217, + 118, + 91, + 99, + 215, + 151, + 34, + 203, + 207, + 191, + 1, + 89, + 157, + 139, + 167, + 87, + 91, + 12, + 11, + 8, + 56, + 245, + 112, + 17, + 39, + 212, + 222, + 250, + 36, + 57, + 24, + 215, + 177, + 20, + 114, + 0, + 150, + 225, + 34, + 73, + 145, + 162, + 7, + 151, + 57, + 121, + 147, + 103, + 14, + 104, + 109, + 31, + 139, + 48, + 144, + 17, + 167, + 142, + 242, + 194, + 123, + 213, + 178, + 209, + 195, + 210, + 243, + 79, + 156, + 167, + 1, + 184, + 72, + 140, + 204, + 41, + 8, + 207, + 218, + 201, + 8, + 113, + 82, + 20, + 150, + 19, + 218, + 58, + 15, + 140, + 113, + 205, + 4, + 62, + 147, + 217, + 98, + 133, + 181, + 172, + 28, + 212, + 60, + 109, + 170, + 193, + 237, + 166, + 143, + 188, + 39, + 52, + 55, + 135, + 54, + 199, + 251, + 147, + 203, + 49, + 139, + 162, + 231, + 89, + 32, + 19, + 239, + 191, + 182, + 181, + 100, + 216, + 168, + 55, + 53, + 20, + 235, + 237, + 211, + 158, + 236, + 32, + 39, + 41, + 92, + 249, + 211, + 213, + 79, + 182, + 200, + 47, + 223, + 133, + 101, + 158, + 236, + 125, + 107, + 180, + 217, + 192, + 223, + 39, + 51, + 79, + 42, + 157, + 219, + 86, + 137, + 166, + 129, + 46, + 154, + 32, + 112, + 244, + 86, + 182, + 7, + 202, + 115, + 108, + 131, + 253, + 136, + 138, + 236, + 217, + 193, + 92, + 119, + 114, + 16, + 120, + 43, + 102, + 31, + 232, + 27, + 47, + 179, + 75, + 177, + 194, + 30, + 106, + 95, + 198, + 25, + 32, + 144, + 19, + 39, + 18, + 213, + 86, + 246, + 193, + 229, + 129, + 18, + 254, + 165, + 8, + 215, + 27, + 147, + 39, + 46, + 169, + 254, + 129, + 34, + 109, + 42, + 145, + 114, + 229, + 212, + 152, + 206, + 108, + 176, + 169, + 37, + 78, + 103, + 254, + 217, + 15, + 84, + 129, + 83, + 233, + 247, + 175, + 92, + 228, + 108, + 33, + 23, + 17, + 58, + 163, + 244, + 254, + 161, + 146, + 150, + 64, + 12, + 248, + 47, + 241, + 160, + 184, + 89, + 78, + 80, + 9, + 110, + 225, + 203, + 169, + 231, + 150, + 181, + 226, + 214, + 109, + 87, + 73, + 42, + 226, + 34, + 209, + 186, + 121, + 29, + 76, + 131, + 71, + 43, + 238, + 252, + 55, + 104, + 114, + 72, + 230, + 75, + 177, + 233, + 54, + 128, + 129, + 221, + 218, + 172, + 170, + 42, + 219, + 45, + 70, + 45, + 166, + 253, + 169, + 222, + 131, + 4, + 203, + 152, + 40, + 154, + 110, + 134, + 245, + 186, + 139, + 165, + 241, + 98, + 214, + 161, + 128, + 163, + 105, + 38, + 247, + 15, + 127, + 1, + 50, + 183, + 112, + 9, + 213, + 194, + 69, + 56, + 150, + 42, + 244, + 125, + 105, + 157, + 72, + 67, + 64, + 126, + 178, + 53, + 142, + 200, + 213, + 228, + 130, + 177, + 248, + 193, + 155, + 58, + 52, + 95, + 115, + 65, + 20, + 108, + 184, + 191, + 97, + 182, + 169, + 143, + 42, + 11, + 39, + 90, + 9, + 241, + 146, + 88, + 219, + 60, + 118, + 36, + 156, + 10, + 3, + 78, + 139, + 129, + 62, + 228, + 102, + 196, + 19, + 15, + 122, + 104, + 184, + 203, + 0, + 241, + 45, + 135, + 92, + 180, + 131, + 73, + 169, + 114, + 233, + 13, + 164, + 70, + 230, + 93, + 121, + 233, + 195, + 112, + 146, + 178, + 61, + 203, + 200, + 226, + 89, + 240, + 251, + 81, + 255, + 96, + 112, + 222, + 163, + 81, + 165, + 91, + 206, + 69, + 103, + 69, + 207, + 150, + 192, + 119, + 40, + 155, + 124, + 15, + 251, + 149, + 122, + 214, + 113, + 203, + 114, + 0, + 90, + 157, + 93, + 88, + 183, + 244, + 58, + 244, + 167, + 230, + 5, + 185, + 184, + 152, + 159, + 220, + 174, + 12, + 160, + 62, + 212, + 25, + 172, + 114, + 139, + 9, + 107, + 120, + 229, + 218, + 83, + 62, + 82, + 3, + 194, + 97, + 55, + 240, + 154, + 130, + 40, + 101, + 165, + 52, + 96, + 4, + 226, + 128, + 90, + 84, + 15, + 192, + 205, + 43, + 247, + 10, + 200, + 205, + 246, + 246, + 31, + 107, + 249, + 241, + 84, + 203, + 101, + 86, + 217, + 42, + 97, + 229, + 91, + 189, + 158, + 157, + 105, + 249, + 22, + 3, + 158, + 124, + 80, + 78, + 164, + 222, + 93, + 254, + 77, + 146, + 36, + 176, + 217, + 62, + 104, + 33, + 116, + 146, + 97, + 64, + 74, + 42, + 3, + 108, + 85, + 234, + 7, + 211, + 84, + 105, + 220, + 136, + 213, + 12, + 46, + 130, + 27, + 111, + 76, + 69, + 0, + 226, + 175, + 50, + 189, + 16, + 79, + 203, + 233, + 42, + 203, + 4, + 248, + 255, + 50, + 168, + 52, + 14, + 212, + 124, + 153, + 106, + 3, + 43, + 27, + 46, + 0, + 106, + 57, + 169, + 178, + 119, + 61, + 55, + 2, + 108, + 173, + 218, + 25, + 3, + 133, + 35, + 201, + 91, + 175, + 11, + 79, + 173, + 246, + 197, + 46, + 186, + 100, + 151, + 248, + 75, + 169, + 72, + 135, + 232, + 24, + 21, + 16, + 89, + 7, + 231, + 112, + 120, + 141, + 22, + 238, + 151, + 103, + 213, + 155, + 65, + 74, + 112, + 131, + 246, + 138, + 160, + 70, + 120, + 188, + 129, + 233, + 55, + 212, + 251, + 176, + 15, + 117, + 217, + 104, + 29, + 64, + 22, + 88, + 92, + 123, + 57, + 206, + 120, + 52, + 8, + 3, + 89, + 180, + 29, + 214, + 8, + 173, + 85, + 188, + 164, + 222, + 207, + 178, + 249, + 159, + 167, + 180, + 22, + 212, + 247, + 95, + 45, + 148, + 73, + 115, + 17, + 237, + 176, + 24, + 241, + 121, + 23, + 150, + 3, + 82, + 165, + 0, + 169, + 185, + 208, + 152, + 66, + 138, + 19, + 222, + 190, + 219, + 185, + 210, + 189, + 159, + 207, + 4, + 79, + 160, + 82, + 68, + 166, + 162, + 102, + 181, + 184, + 192, + 114, + 189, + 91, + 39, + 243, + 47, + 92, + 202, + 182, + 33, + 195, + 13, + 209, + 103, + 182, + 2, + 211, + 3, + 120, + 196, + 111, + 176, + 199, + 56, + 209, + 65, + 85, + 98, + 148, + 127, + 250, + 128, + 75, + 230, + 114, + 220, + 163, + 255, + 178, + 114, + 11, + 6, + 186, + 12, + 120, + 174, + 94, + 191, + 48, + 87, + 32, + 123, + 84, + 113, + 30, + 227, + 125, + 119, + 45, + 166, + 0, + 51, + 130, + 105, + 245, + 193, + 21, + 152, + 222, + 15, + 87, + 236, + 160, + 11, + 197, + 173, + 145, + 130, + 187, + 182, + 44, + 32, + 243, + 140, + 246, + 236, + 211, + 132, + 84, + 224, + 230, + 73, + 74, + 87, + 151, + 92, + 204, + 107, + 38, + 222, + 174, + 77, + 104, + 42, + 20, + 249, + 36, + 61, + 198, + 3, + 5, + 63, + 38, + 13, + 85, + 50, + 81, + 241, + 104, + 108, + 41, + 106, + 4, + 138, + 160, + 33, + 245, + 77, + 231, + 215, + 12, + 246, + 96, + 127, + 118, + 150, + 197, + 51, + 28, + 84, + 123, + 14, + 170, + 28, + 193, + 84, + 69, + 40, + 53, + 48, + 87, + 75, + 249, + 41, + 175, + 43, + 56, + 243, + 221, + 11, + 241, + 150, + 54, + 83, + 68, + 93, + 196, + 102, + 184, + 87, + 253, + 16, + 111, + 8, + 206, + 242, + 127, + 194, + 181, + 55, + 51, + 240, + 64, + 126, + 232, + 202, + 235, + 70, + 103, + 43, + 201, + 88, + 141, + 189, + 68, + 97, + 113, + 108, + 24, + 185, + 65, + 160, + 211, + 4, + 114, + 80, + 58, + 242, + 3, + 131, + 135, + 3, + 165, + 231, + 213, + 193, + 131, + 31, + 93, + 13, + 34, + 5, + 40, + 23, + 163, + 49, + 22, + 123, + 192, + 64, + 116, + 137, + 254, + 215, + 7, + 161, + 191, + 204, + 143, + 245, + 207, + 226, + 149, + 92, + 56, + 22, + 140, + 228, + 181, + 72, + 221, + 176, + 34, + 251, + 202, + 125, + 138, + 23, + 35, + 128, + 103, + 141, + 113, + 182, + 193, + 238, + 231, + 116, + 38, + 121, + 177, + 199, + 115, + 174, + 99, + 236, + 12, + 186, + 237, + 214, + 117, + 60, + 110, + 125, + 208, + 22, + 250, + 58, + 225, + 90, + 77, + 158, + 30, + 137, + 176, + 103, + 245, + 0, + 93, + 144, + 161, + 211, + 189, + 179, + 134, + 96, + 44, + 20, + 111, + 92, + 70, + 60, + 23, + 242, + 91, + 11, + 185, + 106, + 230, + 251, + 90, + 72, + 84, + 17, + 66, + 96, + 47, + 241, + 253, + 97, + 23, + 191, + 111, + 28, + 76, + 98, + 137, + 38, + 193, + 182, + 251, + 199, + 97, + 78, + 208, + 56, + 99, + 90, + 158, + 192, + 129, + 101, + 246, + 83, + 10, + 8, + 66, + 25, + 212, + 137, + 166, + 46, + 20, + 24, + 227, + 210, + 81, + 250, + 179, + 52, + 155, + 212, + 88, + 46, + 37, + 72, + 9, + 132, + 22, + 134, + 140, + 146, + 77, + 15, + 210, + 8, + 72, + 91, + 150, + 246, + 43, + 175, + 25, + 226, + 239, + 106, + 180, + 186, + 250, + 172, + 58, + 205, + 247, + 31, + 152, + 198, + 217, + 75, + 3, + 18, + 178, + 187, + 216, + 75, + 86, + 162, + 123, + 232, + 44, + 46, + 231, + 87, + 222, + 28, + 193, + 186, + 111, + 41, + 84, + 134, + 201, + 211, + 180, + 227, + 219, + 31, + 66, + 216, + 217, + 75, + 229, + 136, + 245, + 33, + 52, + 173, + 8, + 25, + 196, + 162, + 33, + 119, + 4, + 240, + 125, + 106, + 114, + 106, + 43, + 14, + 252, + 33, + 64, + 226, + 64, + 49, + 140, + 179, + 37, + 173, + 136, + 75, + 49, + 184, + 236, + 195, + 100, + 236, + 86, + 244, + 241, + 172, + 80, + 38, + 8, + 26, + 200, + 8, + 104, + 9, + 175, + 154, + 121, + 130, + 76, + 95, + 34, + 162, + 66, + 217, + 66, + 249, + 138, + 5, + 17, + 71, + 125, + 17, + 154, + 119, + 88, + 66, + 66, + 200, + 53, + 16, + 124, + 35, + 110, + 217, + 252, + 162, + 144, + 237, + 125, + 130, + 83, + 83, + 61, + 61, + 0, + 66, + 143, + 74, + 136, + 100, + 196, + 76, + 245, + 51, + 27, + 56, + 48, + 146, + 188, + 215, + 79, + 216, + 54, + 27, + 163, + 156, + 167, + 197, + 226, + 144, + 187, + 20, + 116, + 23, + 32, + 30, + 245, + 79, + 15, + 98, + 64, + 47, + 38, + 79, + 75, + 152, + 181, + 25, + 155, + 179, + 177, + 253, + 47, + 54, + 232, + 230, + 243, + 228, + 15, + 66, + 95, + 53, + 150, + 23, + 186, + 176, + 160, + 67, + 39, + 126, + 193, + 238, + 71, + 42, + 60, + 88, + 229, + 8, + 84, + 5, + 114, + 211, + 184, + 226, + 36, + 223, + 86, + 133, + 157, + 59, + 165, + 171, + 232, + 140, + 65, + 142, + 210, + 173, + 254, + 229, + 180, + 224, + 123, + 89, + 164, + 206, + 245, + 79, + 46, + 70, + 28, + 200, + 23, + 86, + 200, + 77, + 48, + 105, + 134, + 47, + 179, + 66, + 107, + 208, + 148, + 97, + 199, + 66, + 253, + 15, + 239, + 5, + 237, + 183, + 186, + 93, + 27, + 231, + 134, + 86, + 67, + 93, + 91, + 11, + 127, + 12, + 69, + 75, + 79, + 165, + 208, + 7, + 189, + 94, + 115, + 29, + 220, + 115, + 170, + 160, + 199, + 238, + 97, + 86, + 252, + 86, + 100, + 110, + 153, + 21, + 129, + 36, + 234, + 227, + 180, + 108, + 9, + 247, + 228, + 128, + 100, + 150, + 163, + 136, + 4, + 85, + 64, + 12, + 136, + 142, + 115, + 226, + 142, + 244, + 108, + 70, + 54, + 88, + 54, + 5, + 234, + 21, + 120, + 94, + 55, + 179, + 165, + 45, + 89, + 184, + 21, + 56, + 21, + 228, + 27, + 109, + 57, + 252, + 189, + 26, + 116, + 152, + 246, + 196, + 209, + 205, + 130, + 89, + 92, + 45, + 155, + 9, + 176, + 56, + 8, + 184, + 140, + 24, + 190, + 37, + 154, + 220, + 242, + 190, + 112, + 193, + 162, + 200, + 32, + 175, + 17, + 252, + 201, + 90, + 0, + 173, + 239, + 34, + 51, + 23, + 171, + 233, + 126, + 197, + 160, + 230, + 153, + 54, + 69, + 255, + 241, + 138, + 141, + 96, + 3, + 37, + 57, + 235, + 183, + 70, + 115, + 67, + 208, + 254, + 128, + 114, + 164, + 84, + 211, + 233, + 194, + 143, + 53, + 131, + 189, + 207, + 4, + 41, + 87, + 155, + 38, + 39, + 135, + 144, + 207, + 18, + 134, + 47, + 105, + 75, + 222, + 79, + 203, + 127, + 155, + 29, + 57, + 144, + 129, + 188, + 191, + 5, + 177, + 170, + 83, + 132, + 54, + 237, + 33, + 237, + 239, + 89, + 238, + 60, + 127, + 160, + 86, + 213, + 83, + 231, + 5, + 149, + 185, + 221, + 32, + 6, + 210, + 109, + 142, + 157, + 131, + 39, + 107, + 125, + 28, + 207, + 138, + 122, + 150, + 43, + 79, + 252, + 240, + 125, + 99, + 186, + 200, + 162, + 83, + 184, + 82, + 191, + 31, + 214, + 23, + 17, + 227, + 229, + 52, + 191, + 74, + 195, + 117, + 53, + 112, + 39, + 96, + 123, + 55, + 140, + 65, + 53, + 156, + 69, + 195, + 148, + 212, + 144, + 247, + 129, + 242, + 238, + 61, + 211, + 44, + 184, + 117, + 109, + 163, + 168, + 219, + 113, + 32, + 38, + 83, + 153, + 43, + 33, + 215, + 241, + 37, + 8, + 227, + 38, + 160, + 222, + 47, + 167, + 57, + 182, + 51, + 94, + 169, + 159, + 29, + 239, + 42, + 206, + 77, + 20, + 154, + 207, + 142, + 28, + 251, + 151, + 93, + 241, + 1, + 159, + 129, + 162, + 165, + 50, + 82, + 101, + 121, + 29, + 140, + 47, + 97, + 208, + 251, + 149, + 214, + 141, + 196, + 190, + 13, + 28, + 181, + 3, + 48, + 150, + 209, + 71, + 28, + 199, + 130, + 62, + 201, + 214, + 159, + 61, + 15, + 209, + 17, + 141, + 165, + 21, + 33, + 202, + 198, + 173, + 157, + 221, + 28, + 255, + 254, + 51, + 57, + 13, + 24, + 3, + 184, + 236, + 236, + 198, + 184, + 96, + 221, + 17, + 104, + 55, + 75, + 149, + 123, + 206, + 117, + 228, + 156, + 80, + 65, + 127, + 112, + 230, + 206, + 241, + 147, + 158, + 86, + 109, + 18, + 16, + 255, + 81, + 169, + 112, + 87, + 114, + 8, + 16, + 242, + 245, + 87, + 189, + 187, + 150, + 150, + 78, + 83, + 51, + 0, + 37, + 182, + 183, + 87, + 188, + 24, + 170, + 16, + 246, + 130, + 152, + 90, + 12, + 72, + 149, + 197, + 119, + 55, + 225, + 109, + 170, + 215, + 217, + 77, + 104, + 9, + 73, + 169, + 176, + 181, + 34, + 221, + 74, + 246, + 105, + 124, + 85, + 63, + 36, + 235, + 83, + 89, + 39, + 94, + 38, + 187, + 57, + 139, + 228, + 168, + 121, + 34, + 209, + 229, + 219, + 19, + 200, + 54, + 179, + 159, + 92, + 113, + 107, + 14, + 190, + 208, + 238, + 251, + 254, + 80, + 80, + 46, + 72, + 133, + 213, + 90, + 49, + 189, + 191, + 126, + 182, + 197, + 25, + 181, + 110, + 36, + 237, + 111, + 36, + 236, + 6, + 240, + 27, + 145, + 254, + 239, + 102, + 171, + 149, + 198, + 235, + 68, + 227, + 121, + 6, + 130, + 123, + 97, + 27, + 248, + 168, + 138, + 39, + 13, + 23, + 161, + 88, + 1, + 20, + 89, + 74, + 179, + 83, + 59, + 198, + 247, + 73, + 125, + 4, + 76, + 7, + 132, + 196, + 104, + 144, + 91, + 47, + 74, + 43, + 12, + 111, + 231, + 8, + 170, + 74, + 64, + 145, + 225, + 212, + 122, + 112, + 95, + 249, + 51, + 25, + 110, + 56, + 60, + 188, + 233, + 30, + 39, + 191, + 168, + 117, + 109, + 122, + 146, + 132, + 231, + 129, + 1, + 54, + 5, + 143, + 151, + 249, + 167, + 238, + 15, + 56, + 178, + 139, + 144, + 143, + 169, + 130, + 112, + 80, + 51, + 155, + 130, + 40, + 29, + 144, + 254, + 202, + 229, + 62, + 73, + 42, + 109, + 0, + 53, + 141, + 89, + 90, + 207, + 80, + 17, + 50, + 67, + 43, + 228, + 136, + 230, + 215, + 140, + 100, + 157, + 237, + 213, + 22, + 90, + 242, + 123, + 244, + 156, + 185, + 152, + 35, + 33, + 243, + 48, + 227, + 41, + 52, + 9, + 114, + 8, + 186, + 160, + 172, + 171, + 237, + 23, + 81, + 226, + 212, + 52, + 187, + 239, + 214, + 84, + 169, + 14, + 118, + 124, + 0, + 80, + 192, + 232, + 197, + 127, + 131, + 144, + 121, + 87, + 218, + 31, + 47, + 232, + 23, + 52, + 222, + 76, + 229, + 46, + 13, + 189, + 96, + 93, + 212, + 205, + 230, + 228, + 7, + 136, + 118, + 213, + 160, + 19, + 222, + 66, + 162, + 148, + 137, + 242, + 32, + 92, + 135, + 53, + 227, + 134, + 246, + 112, + 55, + 205, + 134, + 137, + 170, + 224, + 237, + 169, + 164, + 57, + 96, + 139, + 83, + 17, + 228, + 246, + 128, + 156, + 46, + 105, + 47, + 85, + 32, + 62, + 126, + 78, + 193, + 1, + 100, + 51, + 188, + 28, + 184, + 237, + 229, + 174, + 65, + 102, + 200, + 246, + 160, + 253, + 247, + 143, + 224, + 131, + 181, + 127, + 46, + 99, + 158, + 110, + 100, + 254, + 117, + 122, + 132, + 106, + 54, + 119, + 138, + 55, + 149, + 4, + 165, + 69, + 120, + 228, + 215, + 178, + 255, + 6, + 9, + 75, + 212, + 121, + 76, + 192, + 82, + 55, + 216, + 126, + 49, + 182, + 159, + 28, + 233, + 169, + 230, + 63, + 203, + 57, + 182, + 122, + 119, + 165, + 166, + 95, + 32, + 160, + 146, + 144, + 46, + 240, + 157, + 155, + 118, + 166, + 251, + 104, + 170, + 2, + 104, + 159, + 160, + 231, + 16, + 100, + 38, + 37, + 62, + 53, + 159, + 204, + 243, + 116, + 173, + 211, + 12, + 201, + 111, + 223, + 40, + 105, + 47, + 32, + 233, + 183, + 68, + 152, + 12, + 252, + 164, + 58, + 237, + 40, + 70, + 203, + 132, + 160, + 205, + 175, + 227, + 67, + 155, + 114, + 166, + 180, + 25, + 179, + 141, + 123, + 122, + 158, + 35, + 143, + 212, + 12, + 1, + 129, + 92, + 71, + 8, + 74, + 164, + 211, + 217, + 48, + 102, + 67, + 254, + 97, + 99, + 144, + 159, + 34, + 108, + 170, + 144, + 12, + 50, + 248, + 209, + 247, + 160, + 36, + 199, + 64, + 122, + 25, + 114, + 133, + 25, + 14, + 169, + 1, + 92, + 152, + 153, + 14, + 222, + 170, + 12, + 28, + 91, + 102, + 102, + 78, + 59, + 93, + 50, + 18, + 164, + 166, + 38, + 181, + 228, + 195, + 254, + 237, + 117, + 180, + 23, + 145, + 108, + 133, + 165, + 88, + 84, + 66, + 92, + 77, + 207, + 1, + 149, + 207, + 200, + 171, + 39, + 55, + 175, + 215, + 235, + 248, + 141, + 249, + 234, + 181, + 164, + 67, + 211, + 138, + 128, + 110, + 151, + 75, + 214, + 201, + 57, + 208, + 145, + 69, + 200, + 45, + 70, + 245, + 125, + 11, + 125, + 163, + 63, + 84, + 54, + 7, + 36, + 97, + 206, + 15, + 197, + 107, + 144, + 62, + 134, + 143, + 5, + 221, + 154, + 164, + 162, + 67, + 108, + 158, + 99, + 19, + 97, + 57, + 6, + 148, + 20, + 33, + 185, + 14, + 88, + 83, + 21, + 157, + 157, + 173, + 235, + 103, + 80, + 179, + 12, + 55, + 134, + 72, + 243, + 88, + 158, + 159, + 228, + 49, + 137, + 233, + 42, + 152, + 72, + 59, + 21, + 139, + 233, + 108, + 63, + 242, + 23, + 91, + 191, + 56, + 174, + 29, + 231, + 176, + 55, + 27, + 229, + 151, + 113, + 120, + 15, + 95, + 66, + 3, + 2, + 183, + 48, + 29, + 16, + 115, + 0, + 81, + 71, + 70, + 172, + 89, + 172, + 234, + 0, + 20, + 172, + 75, + 126, + 39, + 73, + 4, + 211, + 190, + 250, + 239, + 225, + 96, + 239, + 35, + 42, + 90, + 174, + 72, + 142, + 76, + 233, + 119, + 103, + 106, + 104, + 245, + 136, + 139, + 248, + 96, + 123, + 5, + 8, + 219, + 105, + 44, + 11, + 89, + 119, + 40, + 38, + 149, + 195, + 90, + 240, + 206, + 38, + 15, + 98, + 143, + 28, + 60, + 187, + 134, + 136, + 6, + 209, + 246, + 73, + 118, + 134, + 47, + 161, + 24, + 253, + 18, + 227, + 59, + 55, + 106, + 179, + 244, + 196, + 234, + 152, + 250, + 155, + 115, + 49, + 228, + 208, + 166, + 177, + 117, + 254, + 122, + 177, + 230, + 34, + 247, + 56, + 148, + 240, + 197, + 237, + 32, + 151, + 175, + 168, + 71, + 195, + 97, + 20, + 105, + 186, + 137, + 219, + 181, + 158, + 172, + 0, + 166, + 121, + 170, + 25, + 3, + 114, + 140, + 253, + 146, + 210, + 200, + 33, + 248, + 96, + 167, + 0, + 75, + 160, + 21, + 53, + 67, + 142, + 165, + 56, + 207, + 110, + 148, + 223, + 99, + 68, + 133, + 254, + 217, + 195, + 247, + 248, + 161, + 42, + 212, + 210, + 75, + 236, + 84, + 137, + 123, + 131, + 254, + 6, + 115, + 68, + 208, + 147, + 54, + 119, + 253, + 254, + 124, + 114, + 176, + 63, + 231, + 76, + 9, + 15, + 45, + 146, + 73, + 185, + 165, + 252, + 105, + 67, + 192, + 10, + 201, + 83, + 137, + 91, + 30, + 217, + 44, + 41, + 82, + 29, + 0, + 186, + 245, + 39, + 1, + 97, + 11, + 17, + 201, + 213, + 255, + 94, + 59, + 133, + 135, + 226, + 6, + 109, + 10, + 197, + 64, + 8, + 159, + 239, + 104, + 251, + 224, + 220, + 60, + 216, + 235, + 26, + 15, + 43, + 203, + 175, + 105, + 222, + 113, + 114, + 123, + 0, + 178, + 203, + 4, + 229, + 42, + 12, + 227, + 218, + 22, + 131, + 211, + 8, + 201, + 226, + 87, + 131, + 123, + 184, + 16, + 181, + 86, + 169, + 229, + 153, + 116, + 133, + 38, + 111, + 42, + 13, + 92, + 78, + 150, + 196, + 74, + 223, + 243, + 43, + 241, + 112, + 164, + 213, + 95, + 35, + 41, + 161, + 25, + 240, + 253, + 13, + 5, + 103, + 126, + 19, + 130, + 38, + 163, + 185, + 144, + 234, + 250, + 154, + 43, + 97, + 30, + 108, + 182, + 55, + 112, + 89, + 155, + 190, + 242, + 109, + 8, + 98, + 208, + 247, + 21, + 44, + 126, + 76, + 30, + 131, + 131, + 25, + 140, + 82, + 155, + 165, + 16, + 27, + 15, + 36, + 43, + 126, + 151, + 63, + 166, + 94, + 214, + 91, + 107, + 83, + 5, + 220, + 129, + 123, + 173, + 245, + 170, + 89, + 105, + 122, + 69, + 145, + 192, + 119, + 180, + 202, + 143, + 165, + 47, + 33, + 31, + 63, + 41, + 19, + 88, + 12, + 67, + 135, + 31, + 10, + 107, + 72, + 163, + 48, + 17, + 173, + 194, + 252, + 90, + 67, + 47, + 170, + 16, + 204, + 85, + 72, + 27, + 87, + 120, + 247, + 65, + 58, + 235, + 212, + 73, + 6, + 73, + 140, + 202, + 45, + 34, + 152, + 115, + 241, + 245, + 190, + 56, + 148, + 248, + 224, + 235, + 254, + 12, + 117, + 68, + 254, + 75, + 83, + 156, + 206, + 189, + 123, + 182, + 112, + 122, + 43, + 106, + 25, + 141, + 152, + 149, + 65, + 228, + 57, + 217, + 7, + 27, + 46, + 181, + 62, + 251, + 117, + 194, + 105, + 8, + 239, + 70, + 26, + 124, + 214, + 115, + 97, + 122, + 60, + 177, + 76, + 64, + 18, + 187, + 30, + 91, + 212, + 17, + 75, + 180, + 209, + 83, + 113, + 107, + 108, + 131, + 96, + 116, + 153, + 84, + 55, + 139, + 232, + 68, + 195, + 206, + 83, + 216, + 100, + 162, + 183, + 7, + 200, + 108, + 47, + 102, + 21, + 241, + 172, + 73, + 167, + 153, + 252, + 51, + 227, + 31, + 192, + 189, + 252, + 152, + 166, + 68, + 171, + 190, + 175, + 18, + 190, + 18, + 58, + 60, + 131, + 237, + 102, + 196, + 123, + 144, + 191, + 75, + 4, + 32, + 100, + 169, + 72, + 233, + 197, + 227, + 68, + 243, + 130, + 211, + 48, + 218, + 70, + 47, + 26, + 56, + 106, + 1, + 170, + 57, + 144, + 172, + 213, + 248, + 44, + 41, + 112, + 200, + 255, + 234, + 18, + 116, + 87, + 241, + 96, + 167, + 115, + 52, + 188, + 170, + 70, + 65, + 49, + 103, + 108, + 201, + 125, + 109, + 40, + 2, + 216, + 150, + 212, + 101, + 171, + 95, + 50, + 116, + 60, + 253, + 0, + 149, + 50, + 217, + 38, + 128, + 192, + 201, + 11, + 185, + 161, + 127, + 167, + 151, + 158, + 196, + 26, + 38, + 174, + 143, + 185, + 26, + 240, + 185, + 69, + 130, + 59, + 164, + 80, + 163, + 86, + 136, + 225, + 189, + 237, + 244, + 219, + 22, + 84, + 34, + 22, + 183, + 135, + 138, + 108, + 29, + 51, + 181, + 2, + 47, + 215, + 41, + 179, + 43, + 175, + 241, + 157, + 217, + 52, + 128, + 80, + 177, + 180, + 15, + 15, + 138, + 115, + 26, + 170, + 76, + 201, + 219, + 146, + 242, + 247, + 192, + 67, + 123, + 179, + 252, + 199, + 202, + 100, + 186, + 177, + 45, + 225, + 41, + 203, + 250, + 31, + 25, + 56, + 201, + 174, + 246, + 217, + 69, + 219, + 146, + 232, + 157, + 140, + 112, + 218, + 48, + 110, + 104, + 31, + 79, + 2, + 43, + 144, + 141, + 13, + 129, + 204, + 48, + 58, + 223, + 70, + 233, + 103, + 187, + 5, + 226, + 228, + 97, + 228, + 238, + 236, + 249, + 242, + 141, + 76, + 184, + 40, + 131, + 241, + 198, + 150, + 143, + 129, + 38, + 118, + 51, + 98, + 56, + 26, + 112, + 197, + 177, + 69, + 28, + 42, + 143, + 202, + 10, + 25, + 26, + 196, + 161, + 162, + 65, + 133, + 4, + 33, + 191, + 138, + 186, + 153, + 159, + 233, + 242, + 230, + 52, + 140, + 199, + 18, + 97, + 14, + 49, + 11, + 186, + 124, + 100, + 101, + 13, + 198, + 2, + 209, + 52, + 20, + 213, + 36, + 95, + 147, + 126, + 118, + 128, + 250, + 125, + 63, + 63, + 13, + 113, + 158, + 33, + 29, + 12, + 16, + 20, + 12, + 75, + 218, + 23, + 125, + 236, + 161, + 52, + 198, + 191, + 213, + 171, + 30, + 221, + 127, + 66, + 29, + 191, + 172, + 252, + 159, + 37, + 112, + 196, + 37, + 143, + 125, + 116, + 96, + 149, + 143, + 84, + 241, + 43, + 126, + 66, + 111, + 248, + 138, + 187, + 162, + 255, + 5, + 195, + 86, + 174, + 213, + 75, + 26, + 223, + 156, + 45, + 131, + 36, + 36, + 245, + 34, + 41, + 249, + 72, + 5, + 14, + 80, + 186, + 254, + 18, + 8, + 144, + 191, + 206, + 188, + 56, + 87, + 183, + 137, + 186, + 23, + 190, + 181, + 212, + 162, + 211, + 62, + 57, + 98, + 216, + 141, + 54, + 74, + 192, + 189, + 209, + 246, + 37, + 44, + 98, + 127, + 79, + 139, + 10, + 154, + 235, + 53, + 236, + 116, + 253, + 95, + 86, + 152, + 29, + 13, + 212, + 3, + 122, + 58, + 120, + 169, + 253, + 28, + 38, + 40, + 163, + 246, + 6, + 124, + 233, + 42, + 61, + 55, + 96, + 90, + 89, + 124, + 62, + 163, + 215, + 54, + 27, + 171, + 37, + 63, + 177, + 97, + 28, + 87, + 13, + 49, + 253, + 193, + 4, + 184, + 59, + 0, + 242, + 229, + 151, + 206, + 102, + 185, + 48, + 78, + 42, + 245, + 179, + 175, + 215, + 119, + 230, + 117, + 34, + 104, + 63, + 217, + 218, + 149, + 111, + 25, + 155, + 94, + 244, + 214, + 140, + 131, + 112, + 246, + 250, + 98, + 14, + 112, + 158, + 87, + 51, + 176, + 50, + 102, + 212, + 133, + 77, + 228, + 140, + 234, + 3, + 161, + 243, + 252, + 217, + 68, + 148, + 75, + 70, + 40, + 33, + 59, + 103, + 208, + 140, + 31, + 109, + 50, + 168, + 110, + 85, + 236, + 124, + 30, + 55, + 247, + 72, + 235, + 189, + 109, + 7, + 48, + 116, + 227, + 14, + 116, + 69, + 205, + 177, + 169, + 124, + 46, + 215, + 186, + 165, + 148, + 132, + 163, + 35, + 199, + 144, + 78, + 115, + 103, + 72, + 96, + 13, + 116, + 7, + 217, + 181, + 93, + 40, + 46, + 20, + 81, + 137, + 143, + 63, + 134, + 26, + 191, + 83, + 161, + 27, + 67, + 179, + 44, + 155, + 156, + 183, + 196, + 243, + 50, + 26, + 45, + 87, + 29, + 19, + 141, + 33, + 19, + 184, + 22, + 47, + 143, + 67, + 188, + 95, + 155, + 128, + 133, + 181, + 214, + 52, + 22, + 124, + 30, + 186, + 171, + 77, + 240, + 222, + 193, + 184, + 211, + 217, + 159, + 183, + 233, + 63, + 245, + 161, + 132, + 174, + 122, + 220, + 39, + 3, + 3, + 11, + 229, + 90, + 16, + 227, + 119, + 1, + 93, + 254, + 53, + 159, + 52, + 236, + 207, + 123, + 147, + 39, + 151, + 179, + 84, + 237, + 242, + 2, + 120, + 236, + 48, + 160, + 127, + 9, + 39, + 86, + 112, + 210, + 192, + 103, + 207, + 28, + 44, + 18, + 237, + 48, + 39, + 61, + 0, + 60, + 29, + 165, + 239, + 122, + 73, + 112, + 222, + 198, + 231, + 66, + 110, + 79, + 11, + 31, + 225, + 225, + 51, + 229, + 228, + 233, + 59, + 115, + 122, + 16, + 134, + 111, + 64, + 183, + 217, + 112, + 196, + 242, + 2, + 99, + 223, + 199, + 241, + 131, + 175, + 4, + 195, + 37, + 67, + 50, + 48, + 23, + 129, + 162, + 12, + 159, + 183, + 43, + 136, + 11, + 106, + 191, + 228, + 229, + 68, + 235, + 221, + 232, + 62, + 95, + 98, + 126, + 115, + 191, + 197, + 95, + 241, + 1, + 231, + 95, + 251, + 48, + 36, + 156, + 138, + 52, + 238, + 4, + 167, + 166, + 68, + 37, + 231, + 178, + 242, + 77, + 193, + 188, + 167, + 19, + 31, + 157, + 97, + 151, + 30, + 31, + 219, + 249, + 162, + 237, + 38, + 37, + 165, + 142, + 83, + 186, + 134, + 21, + 246, + 32, + 218, + 1, + 138, + 142, + 240, + 90, + 233, + 237, + 77, + 3, + 49, + 150, + 44, + 97, + 242, + 223, + 112, + 97, + 253, + 184, + 67, + 13, + 137, + 16, + 245, + 252, + 11, + 200, + 183, + 13, + 98, + 253, + 201, + 29, + 199, + 96, + 246, + 42, + 225, + 248, + 165, + 12, + 240, + 182, + 192, + 25, + 112, + 184, + 231, + 208, + 113, + 169, + 28, + 218, + 38, + 91, + 49, + 169, + 18, + 194, + 5, + 2, + 166, + 103, + 24, + 130, + 6, + 121, + 65, + 244, + 110, + 165, + 46, + 235, + 211, + 26, + 166, + 122, + 120, + 206, + 171, + 203, + 72, + 68, + 213, + 212, + 14, + 23, + 25, + 127, + 92, + 16, + 241, + 241, + 11, + 224, + 200, + 221, + 161, + 158, + 146, + 3, + 149, + 187, + 65, + 47, + 180, + 212, + 8, + 212, + 119, + 23, + 53, + 227, + 172, + 155, + 115, + 238, + 18, + 79, + 163, + 134, + 116, + 87, + 184, + 34, + 172, + 73, + 47, + 72, + 211, + 17, + 52, + 188, + 130, + 64, + 157, + 22, + 122, + 94, + 86, + 183, + 109, + 196, + 136, + 219, + 194, + 54, + 150, + 82, + 14, + 55, + 133, + 75, + 151, + 80, + 72, + 139, + 156, + 52, + 157, + 218, + 9, + 113, + 203, + 113, + 159, + 180, + 50, + 10, + 38, + 213, + 208, + 15, + 236, + 72, + 121, + 54, + 190, + 118, + 198, + 189, + 187, + 56, + 110, + 30, + 247, + 219, + 224, + 79, + 21, + 91, + 209, + 79, + 111, + 64, + 35, + 68, + 57, + 60, + 228, + 179, + 151, + 193, + 197, + 149, + 134, + 176, + 110, + 234, + 203, + 148, + 41, + 195, + 154, + 100, + 71, + 249, + 90, + 123, + 120, + 31, + 109, + 178, + 99, + 68, + 27, + 209, + 3, + 111, + 12, + 172, + 113, + 242, + 194, + 3, + 108, + 245, + 219, + 46, + 16, + 188, + 29, + 86, + 244, + 242, + 141, + 75, + 172, + 237, + 49, + 205, + 128, + 18, + 78, + 84, + 144, + 135, + 251, + 87, + 198, + 194, + 207, + 174, + 191, + 8, + 128, + 221, + 26, + 190, + 118, + 55, + 113, + 135, + 130, + 89, + 169, + 249, + 206, + 100, + 200, + 189, + 183, + 216, + 4, + 103, + 251, + 146, + 121, + 172, + 71, + 150, + 13, + 131, + 28, + 211, + 221, + 126, + 98, + 243, + 21, + 129, + 191, + 14, + 90, + 26, + 127, + 166, + 233, + 217, + 186, + 50, + 26, + 18, + 33, + 106, + 20, + 255, + 138, + 116, + 16, + 91, + 163, + 128, + 238, + 3, + 223, + 227, + 174, + 185, + 176, + 57, + 45, + 60, + 42, + 168, + 81, + 4, + 29, + 65, + 211, + 67, + 129, + 85, + 132, + 35, + 123, + 101, + 52, + 123, + 123, + 118, + 71, + 169, + 235, + 99, + 13, + 44, + 11, + 243, + 215, + 223, + 72, + 179, + 220, + 133, + 203, + 69, + 246, + 200, + 67, + 75, + 144, + 126, + 36, + 29, + 220, + 87, + 143, + 169, + 20, + 7, + 186, + 228, + 171, + 11, + 32, + 128, + 171, + 129, + 161, + 224, + 212, + 187, + 38, + 3, + 141, + 72, + 83, + 199, + 120, + 180, + 206, + 253, + 135, + 65, + 162, + 98, + 87, + 239, + 123, + 146, + 6, + 52, + 41, + 219, + 54, + 244, + 226, + 106, + 91, + 234, + 145, + 167, + 70, + 81, + 133, + 71, + 204, + 202, + 47, + 32, + 128, + 226, + 202, + 59, + 148, + 228, + 36, + 41, + 175, + 76, + 187, + 215, + 72, + 121, + 139, + 133, + 176, + 88, + 27, + 189, + 191, + 61, + 93, + 57, + 231, + 94, + 185, + 254, + 146, + 246, + 89, + 10, + 227, + 155, + 192, + 74, + 182, + 134, + 225, + 50, + 129, + 154, + 252, + 188, + 104, + 82, + 228, + 133, + 75, + 99, + 117, + 116, + 38, + 140, + 230, + 35, + 142, + 236, + 250, + 97, + 42, + 37, + 238, + 88, + 240, + 66, + 84, + 37, + 16, + 114, + 127, + 31, + 26, + 133, + 142, + 60, + 55, + 0, + 246, + 240, + 120, + 110, + 150, + 108, + 134, + 83, + 245, + 153, + 120, + 69, + 17, + 80, + 18, + 206, + 219, + 177, + 57, + 233, + 48, + 95, + 29, + 143, + 62, + 77, + 69, + 94, + 68, + 199, + 38, + 129, + 58, + 158, + 78, + 118, + 218, + 65, + 22, + 160, + 26, + 84, + 9, + 113, + 189, + 163, + 66, + 230, + 62, + 77, + 198, + 50, + 248, + 220, + 11, + 50, + 141, + 32, + 91, + 214, + 58, + 48, + 193, + 248, + 29, + 82, + 193, + 203, + 237, + 0, + 29, + 113, + 65, + 1, + 180, + 15, + 106, + 137, + 69, + 139, + 218, + 97, + 240, + 135, + 105, + 87, + 145, + 69, + 202, + 7, + 61, + 76, + 38, + 49, + 249, + 146, + 29, + 170, + 115, + 67, + 236, + 166, + 39, + 23, + 35, + 234, + 81, + 251, + 117, + 145, + 200, + 131, + 122, + 197, + 105, + 114, + 57, + 60, + 208, + 238, + 89, + 107, + 87, + 37, + 49, + 210, + 241, + 128, + 101, + 20, + 145, + 65, + 197, + 216, + 32, + 119, + 161, + 253, + 150, + 157, + 176, + 169, + 39, + 56, + 95, + 202, + 192, + 151, + 252, + 9, + 37, + 100, + 37, + 33, + 181, + 15, + 244, + 119, + 176, + 13, + 204, + 148, + 59, + 51, + 199, + 226, + 81, + 181, + 33, + 189, + 130, + 247, + 87, + 192, + 94, + 253, + 136, + 34, + 132, + 65, + 12, + 27, + 42, + 49, + 211, + 28, + 196, + 14, + 20, + 210, + 253, + 112, + 21, + 197, + 64, + 86, + 233, + 187, + 240, + 171, + 78, + 184, + 8, + 143, + 100, + 100, + 31, + 45, + 11, + 56, + 115, + 214, + 24, + 167, + 114, + 143, + 88, + 42, + 166, + 240, + 5, + 175, + 123, + 192, + 171, + 186, + 84, + 68, + 55, + 224, + 42, + 90, + 66, + 189, + 84, + 223, + 32, + 228, + 145, + 2, + 43, + 255, + 222, + 224, + 13, + 147, + 133, + 250, + 129, + 107, + 151, + 123, + 135, + 225, + 136, + 133, + 203, + 1, + 106, + 71, + 249, + 40, + 87, + 33, + 223, + 1, + 59, + 102, + 183, + 111, + 30, + 59, + 238, + 118, + 144, + 19, + 72, + 60, + 126, + 182, + 239, + 92, + 160, + 7, + 71, + 166, + 101, + 106, + 222, + 87, + 43, + 6, + 188, + 108, + 52, + 250, + 192, + 52, + 188, + 178, + 194, + 232, + 48, + 107, + 190, + 240, + 12, + 252, + 203, + 78, + 91, + 223, + 246, + 89, + 187, + 232, + 175, + 115, + 56, + 214, + 201, + 19, + 113, + 190, + 17, + 139, + 52, + 190, + 123, + 35, + 27, + 211, + 194, + 220, + 152, + 44, + 77, + 194, + 212, + 8, + 110, + 7, + 76, + 228, + 41, + 100, + 173, + 250, + 166, + 51, + 3, + 228, + 160, + 240, + 223, + 110, + 96, + 120, + 126, + 133, + 190, + 113, + 92, + 115, + 112, + 37, + 140, + 211, + 205, + 90, + 247, + 187, + 19, + 195, + 197, + 23, + 251, + 93, + 13, + 17, + 125, + 113, + 72, + 215, + 75, + 69, + 67, + 108, + 35, + 129, + 237, + 173, + 97, + 7, + 211, + 101, + 218, + 198, + 16, + 4, + 149, + 200, + 244, + 63, + 13, + 162, + 46, + 15, + 139, + 5, + 150, + 143, + 244, + 102, + 192, + 62, + 131, + 77, + 105, + 168, + 59, + 211, + 87, + 125, + 152, + 62, + 175, + 160, + 192, + 129, + 225, + 218, + 63, + 173, + 28, + 103, + 197, + 136, + 248, + 72, + 70, + 71, + 16, + 63, + 243, + 198, + 120, + 8, + 6, + 11, + 9, + 98, + 88, + 73, + 165, + 71, + 69, + 54, + 253, + 165, + 38, + 245, + 186, + 14, + 244, + 131, + 128, + 219, + 9, + 125, + 121, + 152, + 252, + 27, + 116, + 113, + 17, + 114, + 34, + 27, + 75, + 195, + 45, + 215, + 178, + 69, + 39, + 150, + 52, + 107, + 101, + 180, + 176, + 184, + 127, + 12, + 49, + 83, + 210, + 184, + 178, + 11, + 37, + 25, + 56, + 21, + 43, + 53, + 103, + 90, + 6, + 214, + 187, + 115, + 172, + 166, + 68, + 101, + 214, + 106, + 55, + 95, + 81, + 223, + 112, + 248, + 219, + 255, + 53, + 212, + 218, + 252, + 226, + 75, + 232, + 132, + 46, + 39, + 227, + 43, + 189, + 64, + 71, + 66, + 96, + 75, + 224, + 29, + 245, + 124, + 49, + 184, + 123, + 167, + 119, + 103, + 30, + 78, + 255, + 16, + 133, + 18, + 75, + 181, + 240, + 41, + 247, + 172, + 4, + 19, + 189, + 117, + 163, + 239, + 80, + 135, + 209, + 21, + 86, + 226, + 219, + 38, + 121, + 64, + 244, + 149, + 45, + 22, + 214, + 80, + 215, + 29, + 26, + 162, + 174, + 120, + 69, + 49, + 68, + 99, + 48, + 42, + 164, + 112, + 55, + 173, + 94, + 227, + 122, + 39, + 87, + 109, + 25, + 14, + 99, + 207, + 181, + 189, + 104, + 68, + 145, + 15, + 74, + 78, + 159, + 217, + 252, + 79, + 102, + 121, + 134, + 206, + 70, + 20, + 214, + 192, + 98, + 63, + 78, + 56, + 40, + 240, + 131, + 186, + 235, + 150, + 16, + 128, + 155, + 189, + 53, + 93, + 255, + 241, + 8, + 58, + 178, + 95, + 141, + 21, + 163, + 205, + 6, + 210, + 43, + 55, + 206, + 132, + 30, + 83, + 131, + 156, + 79, + 3, + 102, + 92, + 37, + 116, + 165, + 137, + 105, + 252, + 93, + 10, + 201, + 212, + 159, + 127, + 244, + 200, + 164, + 7, + 21, + 62, + 162, + 106, + 168, + 3, + 98, + 52, + 95, + 199, + 101, + 131, + 127, + 193, + 84, + 15, + 107, + 152, + 133, + 25, + 51, + 175, + 152, + 20, + 178, + 4, + 230, + 151, + 199, + 157, + 131, + 203, + 90, + 116, + 36, + 107, + 241, + 56, + 30, + 105, + 18, + 100, + 122, + 162, + 194, + 151, + 109, + 79, + 148, + 110, + 152, + 176, + 211, + 8, + 124, + 216, + 38, + 116, + 179, + 17, + 189, + 30, + 194, + 39, + 37, + 150, + 54, + 101, + 148, + 114, + 106, + 204, + 3, + 4, + 171, + 55, + 19, + 98, + 159, + 103, + 95, + 173, + 173, + 113, + 65, + 225, + 128, + 91, + 210, + 148, + 179, + 164, + 129, + 221, + 173, + 247, + 29, + 218, + 14, + 38, + 50, + 21, + 3, + 196, + 221, + 90, + 9, + 62, + 158, + 182, + 50, + 89, + 22, + 97, + 112, + 91, + 130, + 217, + 236, + 213, + 46, + 33, + 157, + 24, + 202, + 4, + 18, + 202, + 241, + 46, + 178, + 148, + 61, + 76, + 198, + 166, + 201, + 216, + 200, + 142, + 74, + 209, + 59, + 5, + 132, + 227, + 58, + 192, + 253, + 139, + 167, + 125, + 169, + 113, + 239, + 66, + 101, + 110, + 119, + 35, + 177, + 148, + 124, + 195, + 184, + 114, + 184, + 15, + 48, + 140, + 15, + 56, + 5, + 192, + 91, + 185, + 188, + 150, + 6, + 42, + 84, + 141, + 247, + 4, + 22, + 137, + 139, + 206, + 12, + 31, + 97, + 41, + 58, + 86, + 232, + 184, + 103, + 21, + 28, + 157, + 31, + 228, + 43, + 117, + 35, + 201, + 178, + 2, + 78, + 59, + 135, + 63, + 171, + 167, + 210, + 221, + 56, + 90, + 144, + 250, + 185, + 216, + 233, + 103, + 93, + 238, + 50, + 224, + 27, + 44, + 234, + 112, + 34, + 224, + 250, + 247, + 253, + 186, + 88, + 24, + 156, + 35, + 234, + 79, + 26, + 97, + 234, + 172, + 35, + 28, + 149, + 10, + 235, + 117, + 251, + 121, + 58, + 0, + 10, + 88, + 123, + 95, + 247, + 211, + 28, + 167, + 200, + 159, + 248, + 130, + 132, + 137, + 188, + 95, + 160, + 45, + 6, + 204, + 208, + 177, + 120, + 30, + 246, + 241, + 240, + 184, + 23, + 86, + 11, + 166, + 42, + 138, + 65, + 18, + 187, + 151, + 79, + 107, + 132, + 14, + 135, + 148, + 13, + 27, + 218, + 108, + 82, + 167, + 150, + 240, + 98, + 50, + 240, + 201, + 227, + 121, + 253, + 231, + 207, + 121, + 114, + 238, + 103, + 131, + 10, + 72, + 50, + 194, + 17, + 233, + 14, + 218, + 151, + 114, + 185, + 219, + 30, + 39, + 188, + 206, + 253, + 198, + 172, + 155, + 41, + 181, + 103, + 28, + 44, + 204, + 196, + 135, + 87, + 156, + 45, + 132, + 255, + 43, + 18, + 202, + 118, + 203, + 138, + 51, + 145, + 40, + 99, + 121, + 223, + 134, + 74, + 105, + 169, + 45, + 51, + 92, + 172, + 122, + 9, + 143, + 237, + 175, + 163, + 190, + 144, + 132, + 55, + 54, + 224, + 59, + 37, + 248, + 131, + 193, + 44, + 122, + 223, + 135, + 190, + 85, + 47, + 218, + 17, + 101, + 252, + 198, + 135, + 109, + 35, + 118, + 177, + 154, + 30, + 71, + 78, + 127, + 205, + 160, + 103, + 14, + 152, + 106, + 50, + 245, + 185, + 5, + 189, + 154, + 92, + 98, + 107, + 217, + 30, + 59, + 63, + 188, + 34, + 198, + 212, + 189, + 93, + 255, + 158, + 223, + 219, + 82, + 219, + 156, + 198, + 174, + 164, + 17, + 166, + 23, + 25, + 108, + 135, + 107, + 221, + 116, + 202, + 179, + 202, + 134, + 219, + 199, + 170, + 193, + 92, + 90, + 208, + 25, + 212, + 223, + 143, + 136, + 214, + 66, + 225, + 24, + 183, + 141, + 84, + 118, + 218, + 110, + 132, + 46, + 146, + 216, + 128, + 217, + 156, + 163, + 219, + 68, + 25, + 96, + 178, + 46, + 255, + 198, + 15, + 217, + 227, + 212, + 216, + 227, + 11, + 129, + 217, + 78, + 88, + 115, + 107, + 231, + 199, + 76, + 10, + 251, + 96, + 18, + 36, + 196, + 236, + 174, + 105, + 58, + 3, + 45, + 225, + 45, + 245, + 69, + 70, + 163, + 241, + 68, + 28, + 249, + 174, + 56, + 117, + 239, + 23, + 68, + 125, + 76, + 208, + 71, + 112, + 168, + 150, + 102, + 253, + 64, + 227, + 64, + 61, + 155, + 140, + 151, + 219, + 50, + 237, + 218, + 49, + 94, + 78, + 198, + 178, + 97, + 152, + 141, + 145, + 152, + 66, + 37, + 120, + 79, + 100, + 27, + 86, + 131, + 185, + 80, + 253, + 103, + 85, + 204, + 54, + 24, + 149, + 65, + 253, + 70, + 117, + 137, + 213, + 20, + 64, + 101, + 30, + 224, + 148, + 23, + 119, + 250, + 183, + 72, + 151, + 161, + 190, + 5, + 7, + 70, + 43, + 48, + 5, + 111, + 189, + 27, + 131, + 96, + 232, + 64, + 118, + 146, + 161, + 22, + 81, + 175, + 123, + 206, + 134, + 5, + 108, + 111, + 182, + 161, + 46, + 242, + 197, + 89, + 143, + 10, + 62, + 222, + 134, + 152, + 107, + 195, + 158, + 146, + 146, + 252, + 182, + 169, + 60, + 9, + 237, + 148, + 94, + 15, + 127, + 173, + 174, + 0, + 77, + 12, + 81, + 103, + 176, + 245, + 153, + 249, + 114, + 108, + 62, + 191, + 96, + 160, + 203, + 209, + 246, + 249, + 181, + 84, + 171, + 251, + 181, + 181, + 179, + 198, + 175, + 86, + 28, + 251, + 221, + 95, + 250, + 29, + 249, + 41, + 139, + 38, + 222, + 84, + 7, + 77, + 195, + 79, + 33, + 94, + 197, + 27, + 82, + 4, + 133, + 122, + 32, + 208, + 206, + 204, + 215, + 173, + 20, + 121, + 240, + 21, + 179, + 212, + 6, + 176, + 67, + 132, + 11, + 104, + 191, + 132, + 215, + 100, + 81, + 27, + 75, + 41, + 246, + 61, + 114, + 178, + 14, + 228, + 84, + 66, + 58, + 108, + 87, + 249, + 22, + 142, + 88, + 244, + 117, + 69, + 26, + 243, + 213, + 169, + 91, + 9, + 89, + 33, + 159, + 45, + 241, + 203, + 53, + 121, + 125, + 104, + 207, + 118, + 137, + 247, + 92, + 41, + 81, + 206, + 223, + 63, + 99, + 178, + 14, + 55, + 55, + 178, + 177, + 162, + 61, + 185, + 75, + 10, + 197, + 143, + 55, + 51, + 78, + 38, + 180, + 15, + 44, + 12, + 118, + 240, + 136, + 235, + 28, + 37, + 4, + 210, + 183, + 150, + 222, + 191, + 102, + 36, + 152, + 189, + 239, + 208, + 104, + 229, + 13, + 163, + 23, + 115, + 9, + 40, + 151, + 136, + 48, + 1, + 80, + 75, + 213, + 183, + 4, + 58, + 139, + 13, + 123, + 243, + 250, + 158, + 76, + 118, + 22, + 101, + 82, + 172, + 63, + 81, + 199, + 27, + 209, + 242, + 202, + 232, + 111, + 12, + 136, + 63, + 243, + 81, + 197, + 185, + 210, + 252, + 58, + 188, + 146, + 211, + 7, + 206, + 181, + 153, + 218, + 44, + 70, + 199, + 117, + 54, + 204, + 0, + 216, + 65, + 106, + 62, + 64, + 128, + 41, + 75, + 27, + 137, + 216, + 48, + 121, + 12, + 146, + 253, + 60, + 248, + 74, + 83, + 76, + 16, + 18, + 127, + 124, + 158, + 35, + 211, + 130, + 141, + 128, + 95, + 183, + 128, + 108, + 90, + 53, + 121, + 160, + 74, + 233, + 193, + 215, + 0, + 192, + 175, + 133, + 238, + 252, + 158, + 214, + 196, + 54, + 155, + 177, + 68, + 85, + 64, + 222, + 218, + 124, + 0, + 132, + 28, + 132, + 54, + 125, + 115, + 8, + 120, + 19, + 10, + 24, + 103, + 188, + 23, + 226, + 58, + 65, + 72, + 201, + 17, + 24, + 175, + 214, + 65, + 28, + 40, + 66, + 118, + 1, + 20, + 163, + 202, + 197, + 36, + 42, + 56, + 245, + 24, + 129, + 251, + 87, + 30, + 145, + 13, + 203, + 65, + 210, + 95, + 189, + 46, + 243, + 27, + 80, + 200, + 1, + 227, + 253, + 94, + 79, + 190, + 173, + 204, + 213, + 217, + 143, + 0, + 115, + 116, + 46, + 108, + 27, + 240, + 142, + 115, + 12, + 141, + 122, + 41, + 114, + 134, + 116, + 183, + 140, + 73, + 246, + 240, + 205, + 8, + 247, + 67, + 12, + 123, + 3, + 193, + 119, + 39, + 243, + 214, + 223, + 59, + 113, + 101, + 242, + 56, + 142, + 59, + 156, + 34, + 219, + 80, + 61, + 63, + 188, + 8, + 194, + 235, + 139, + 241, + 226, + 139, + 92, + 237, + 209, + 36, + 224, + 14, + 157, + 58, + 194, + 161, + 50, + 11, + 148, + 94, + 200, + 250, + 58, + 80, + 42, + 170, + 105, + 239, + 247, + 31, + 8, + 146, + 208, + 238, + 137, + 136, + 172, + 124, + 204, + 180, + 235, + 130, + 194, + 250, + 165, + 141, + 119, + 230, + 169, + 28, + 192, + 116, + 155, + 88, + 185, + 59, + 38, + 132, + 190, + 205, + 85, + 76, + 161, + 170, + 21, + 76, + 221, + 139, + 193, + 45, + 252, + 202, + 237, + 146, + 31, + 4, + 37, + 167, + 167, + 93, + 148, + 217, + 215, + 11, + 182, + 122, + 6, + 111, + 107, + 121, + 235, + 20, + 87, + 208, + 145, + 11, + 110, + 59, + 114, + 199, + 169, + 171, + 173, + 147, + 41, + 166, + 98, + 215, + 159, + 30, + 178, + 179, + 255, + 134, + 193, + 140, + 165, + 136, + 49, + 3, + 65, + 42, + 44, + 137, + 130, + 199, + 66, + 98, + 202, + 33, + 148, + 30, + 26, + 195, + 57, + 171, + 253, + 0, + 252, + 65, + 38, + 180, + 4, + 14, + 44, + 8, + 56, + 116, + 182, + 8, + 36, + 90, + 98, + 16, + 73, + 24, + 197, + 191, + 109, + 1, + 133, + 93, + 25, + 64, + 224, + 229, + 98, + 254, + 103, + 40, + 11, + 53, + 25, + 253, + 113, + 10, + 86, + 4, + 50, + 146, + 87, + 180, + 214, + 97, + 224, + 221, + 121, + 204, + 144, + 216, + 177, + 24, + 153, + 42, + 145, + 5, + 13, + 145, + 171, + 219, + 234, + 220, + 20, + 104, + 106, + 67, + 216, + 114, + 78, + 45, + 199, + 49, + 11, + 16, + 236, + 99, + 97, + 70, + 186, + 49, + 103, + 141, + 161, + 105, + 163, + 3, + 142, + 212, + 9, + 5, + 173, + 241, + 115, + 107, + 124, + 36, + 253, + 139, + 253, + 82, + 220, + 105, + 60, + 7, + 230, + 34, + 29, + 50, + 204, + 85, + 75, + 141, + 168, + 123, + 206, + 68, + 118, + 213, + 224, + 128, + 67, + 237, + 26, + 187, + 68, + 225, + 119, + 62, + 168, + 169, + 98, + 171, + 130, + 241, + 4, + 90, + 124, + 78, + 192, + 10, + 78, + 238, + 37, + 98, + 53, + 37, + 193, + 231, + 163, + 91, + 19, + 111, + 100, + 41, + 82, + 152, + 208, + 68, + 37, + 186, + 121, + 41, + 104, + 97, + 2, + 247, + 90, + 67, + 108, + 142, + 204, + 113, + 246, + 48, + 77, + 18, + 99, + 194, + 69, + 48, + 197, + 121, + 57, + 93, + 106, + 28, + 247, + 100, + 224, + 168, + 210, + 209, + 165, + 39, + 119, + 193, + 80, + 22, + 147, + 20, + 117, + 124, + 34, + 113, + 134, + 117, + 165, + 148, + 5, + 10, + 251, + 166, + 215, + 194, + 240, + 242, + 70, + 86, + 79, + 72, + 246, + 87, + 148, + 35, + 115, + 137, + 73, + 3, + 155, + 133, + 123, + 70, + 69, + 20, + 79, + 72, + 198, + 232, + 222, + 205, + 1, + 74, + 85, + 162, + 113, + 220, + 163, + 97, + 56, + 36, + 91, + 51, + 184, + 91, + 39, + 168, + 99, + 55, + 53, + 75, + 235, + 223, + 48, + 142, + 192, + 244, + 108, + 106, + 105, + 12, + 8, + 85, + 162, + 189, + 208, + 26, + 63, + 9, + 5, + 204, + 197, + 1, + 172, + 247, + 179, + 126, + 130, + 113, + 25, + 35, + 252, + 245, + 11, + 254, + 160, + 196, + 65, + 23, + 35, + 24, + 203, + 151, + 86, + 39, + 212, + 200, + 189, + 121, + 181, + 42, + 128, + 130, + 201, + 119, + 17, + 97, + 203, + 97, + 245, + 126, + 25, + 174, + 122, + 154, + 212, + 179, + 165, + 126, + 47, + 36, + 142, + 88, + 178, + 174, + 97, + 93, + 63, + 231, + 145, + 247, + 112, + 121, + 202, + 41, + 187, + 11, + 210, + 126, + 56, + 53, + 172, + 75, + 160, + 218, + 78, + 138, + 102, + 49, + 244, + 248, + 65, + 31, + 21, + 55, + 22, + 145, + 167, + 194, + 23, + 153, + 201, + 169, + 77, + 254, + 137, + 128, + 239, + 167, + 158, + 167, + 247, + 103, + 142, + 234, + 92, + 150, + 67, + 11, + 47, + 64, + 4, + 0, + 40, + 154, + 92, + 97, + 82, + 114, + 130, + 190, + 205, + 254, + 112, + 233, + 183, + 114, + 59, + 123, + 234, + 253, + 253, + 150, + 182, + 21, + 228, + 26, + 76, + 192, + 3, + 65, + 199, + 190, + 172, + 73, + 54, + 73, + 90, + 30, + 145, + 13, + 244, + 101, + 133, + 237, + 60, + 206, + 21, + 93, + 97, + 63, + 119, + 157, + 99, + 8, + 174, + 116, + 75, + 174, + 119, + 123, + 133, + 182, + 121, + 162, + 169, + 169, + 84, + 10, + 44, + 29, + 159, + 4, + 67, + 224, + 0, + 153, + 112, + 109, + 23, + 106, + 79, + 54, + 206, + 84, + 47, + 59, + 224, + 151, + 86, + 103, + 79, + 152, + 166, + 177, + 22, + 151, + 57, + 26, + 95, + 251, + 182, + 115, + 60, + 250, + 139, + 107, + 160, + 143, + 184, + 48, + 219, + 109, + 245, + 98, + 101, + 168, + 193, + 128, + 138, + 5, + 60, + 65, + 109, + 247, + 155, + 190, + 161, + 111, + 85, + 64, + 115, + 2, + 142, + 64, + 197, + 108, + 116, + 251, + 219, + 133, + 77, + 94, + 16, + 183, + 19, + 130, + 169, + 163, + 38, + 213, + 146, + 144, + 150, + 167, + 185, + 219, + 146, + 36, + 26, + 159, + 174, + 244, + 14, + 1, + 240, + 10, + 251, + 146, + 229, + 207, + 85, + 108, + 85, + 155, + 6, + 232, + 32, + 113, + 192, + 171, + 111, + 139, + 47, + 35, + 186, + 50, + 76, + 59, + 202, + 8, + 168, + 136, + 229, + 156, + 16, + 193, + 20, + 49, + 3, + 23, + 3, + 112, + 77, + 107, + 23, + 19, + 156, + 4, + 97, + 0, + 161, + 133, + 141, + 110, + 176, + 105, + 135, + 23, + 101, + 79, + 92, + 80, + 233, + 253, + 50, + 178, + 14, + 200, + 84, + 98, + 206, + 133, + 140, + 73, + 247, + 170, + 129, + 163, + 217, + 24, + 142, + 148, + 226, + 240, + 128, + 234, + 92, + 56, + 103, + 66, + 144, + 203, + 92, + 191, + 118, + 171, + 89, + 202, + 97, + 198, + 217, + 17, + 28, + 249, + 76, + 212, + 79, + 46, + 255, + 145, + 103, + 146, + 173, + 215, + 135, + 170, + 136, + 241, + 113, + 148, + 160, + 168, + 82, + 236, + 129, + 149, + 31, + 202, + 227, + 123, + 96, + 63, + 169, + 87, + 82, + 239, + 113, + 124, + 85, + 107, + 183, + 190, + 51, + 150, + 239, + 154, + 25, + 77, + 239, + 222, + 36, + 117, + 225, + 226, + 233, + 229, + 158, + 2, + 243, + 151, + 231, + 51, + 227, + 199, + 244, + 32, + 8, + 44, + 177, + 114, + 170, + 2, + 144, + 193, + 234, + 200, + 178, + 215, + 192, + 234, + 206, + 244, + 158, + 87, + 201, + 224, + 184, + 39, + 78, + 20, + 9, + 23, + 75, + 93, + 76, + 73, + 138, + 20, + 249, + 225, + 168, + 113, + 75, + 245, + 93, + 30, + 113, + 206, + 137, + 106, + 112, + 177, + 192, + 95, + 37, + 151, + 83, + 75, + 63, + 14, + 105, + 114, + 30, + 156, + 76, + 170, + 7, + 180, + 153, + 45, + 7, + 246, + 150, + 245, + 108, + 104, + 200, + 243, + 199, + 57, + 65, + 233, + 127, + 132, + 239, + 107, + 117, + 7, + 44, + 197, + 145, + 134, + 149, + 97, + 140, + 102, + 208, + 225, + 215, + 223, + 119, + 25, + 138, + 221, + 185, + 18, + 208, + 74, + 69, + 177, + 186, + 179, + 198, + 65, + 199, + 137, + 80, + 57, + 126, + 50, + 253, + 180, + 223, + 77, + 13, + 222, + 193, + 111, + 157, + 129, + 123, + 199, + 159, + 102, + 179, + 208, + 233, + 224, + 51, + 94, + 231, + 209, + 16, + 146, + 86, + 27, + 154, + 163, + 53, + 27, + 144, + 24, + 0, + 217, + 158, + 249, + 34, + 155, + 20, + 221, + 231, + 187, + 214, + 53, + 234, + 50, + 155, + 173, + 255, + 83, + 217, + 11, + 161, + 126, + 140, + 152, + 131, + 174, + 116, + 84, + 93, + 114, + 44, + 142, + 103, + 241, + 21, + 196, + 236, + 197, + 106, + 136, + 19, + 55, + 236, + 152, + 198, + 88, + 56, + 187, + 103, + 9, + 229, + 207, + 188, + 89, + 187, + 140, + 0, + 85, + 51, + 168, + 61, + 141, + 131, + 30, + 95, + 88, + 225, + 120, + 148, + 137, + 160, + 11, + 44, + 78, + 142, + 119, + 39, + 81, + 94, + 224, + 200, + 227, + 140, + 10, + 34, + 236, + 212, + 178, + 122, + 235, + 118, + 13, + 145, + 250, + 169, + 77, + 39, + 115, + 229, + 251, + 92, + 240, + 64, + 133, + 65, + 14, + 165, + 230, + 32, + 38, + 7, + 236, + 38, + 89, + 251, + 113, + 171, + 179, + 229, + 125, + 69, + 217, + 255, + 81, + 121, + 150, + 243, + 152, + 186, + 155, + 251, + 173, + 37, + 227, + 237, + 116, + 22, + 10, + 219, + 145, + 97, + 50, + 203, + 162, + 113, + 49, + 107, + 77, + 38, + 83, + 109, + 50, + 167, + 19, + 37, + 135, + 69, + 250, + 104, + 123, + 150, + 191, + 111, + 231, + 171, + 128, + 38, + 215, + 148, + 103, + 141, + 103, + 229, + 27, + 228, + 175, + 110, + 202, + 134, + 16, + 192, + 120, + 205, + 84, + 125, + 244, + 85, + 130, + 64, + 47, + 179, + 230, + 77, + 69, + 15, + 161, + 123, + 205, + 121, + 198, + 22, + 142, + 208, + 133, + 229, + 65, + 252, + 164, + 8, + 39, + 214, + 250, + 178, + 17, + 111, + 109, + 119, + 186, + 131, + 38, + 238, + 203, + 145, + 29, + 162, + 151, + 3, + 161, + 241, + 193, + 130, + 93, + 59, + 187, + 161, + 64, + 101, + 97, + 219, + 96, + 12, + 250, + 134, + 14, + 14, + 147, + 59, + 48, + 69, + 8, + 44, + 4, + 88, + 173, + 100, + 73, + 56, + 140, + 44, + 36, + 97, + 65, + 106, + 180, + 103, + 71, + 248, + 98, + 64, + 22, + 173, + 163, + 196, + 21, + 95, + 226, + 108, + 128, + 149, + 26, + 162, + 55, + 200, + 248, + 160, + 55, + 207, + 39, + 244, + 76, + 2, + 249, + 80, + 110, + 156, + 151, + 186, + 189, + 192, + 201, + 220, + 77, + 136, + 124, + 112, + 166, + 202, + 187, + 51, + 94, + 79, + 63, + 92, + 198, + 241, + 39, + 100, + 37, + 124, + 111, + 68, + 171, + 242, + 45, + 48, + 98, + 206, + 58, + 64, + 222, + 248, + 13, + 222, + 16, + 168, + 69, + 169, + 16, + 132, + 117, + 120, + 70, + 93, + 84, + 221, + 178, + 199, + 62, + 124, + 76, + 26, + 141, + 177, + 57, + 84, + 223, + 119, + 166, + 132, + 126, + 203, + 185, + 85, + 69, + 164, + 82, + 124, + 81, + 59, + 42, + 153, + 61, + 184, + 14, + 61, + 9, + 9, + 255, + 154, + 84, + 190, + 23, + 236, + 14, + 203, + 31, + 214, + 118, + 7, + 8, + 253, + 221, + 198, + 47, + 187, + 154, + 58, + 35, + 63, + 240, + 2, + 82, + 198, + 185, + 78, + 62, + 34, + 44, + 226, + 2, + 55, + 156, + 61, + 89, + 202, + 188, + 20, + 192, + 230, + 58, + 204, + 7, + 253, + 39, + 39, + 70, + 27, + 99, + 14, + 46, + 165, + 222, + 188, + 221, + 187, + 68, + 83, + 44, + 21, + 40, + 24, + 144, + 120, + 117, + 219, + 148, + 25, + 55, + 212, + 21, + 248, + 37, + 118, + 30, + 191, + 221, + 116, + 143, + 31, + 210, + 7, + 104, + 62, + 104, + 94, + 149, + 44, + 28, + 192, + 101, + 30, + 204, + 4, + 22, + 64, + 48, + 231, + 1, + 50, + 235, + 170, + 177, + 25, + 25, + 90, + 141, + 245, + 232, + 39, + 51, + 40, + 230, + 232, + 41, + 22, + 195, + 218, + 46, + 164, + 22, + 250, + 113, + 183, + 239, + 98, + 134, + 211, + 40, + 91, + 243, + 246, + 178, + 32, + 252, + 107, + 28, + 171, + 209, + 112, + 31, + 226, + 162, + 40, + 140, + 27, + 51, + 236, + 77, + 11, + 220, + 116, + 63, + 75, + 81, + 233, + 30, + 29, + 158, + 85, + 85, + 193, + 98, + 34, + 45, + 136, + 8, + 226, + 113, + 42, + 242, + 3, + 230, + 207, + 53, + 101, + 30, + 222, + 96, + 151, + 226, + 137, + 41, + 207, + 240, + 0, + 151, + 164, + 21, + 124, + 102, + 242, + 143, + 36, + 121, + 140, + 232, + 152, + 191, + 106, + 241, + 9, + 124, + 65, + 233, + 213, + 246, + 45, + 5, + 182, + 2, + 98, + 184, + 192, + 125, + 154, + 155, + 75, + 106, + 153, + 95, + 251, + 214, + 81, + 7, + 213, + 199, + 69, + 99, + 252, + 253, + 251, + 212, + 128, + 222, + 96, + 117, + 33, + 27, + 241, + 57, + 180, + 101, + 93, + 81, + 55, + 80, + 140, + 229, + 79, + 34, + 196, + 73, + 96, + 57, + 170, + 95, + 81, + 229, + 206, + 105, + 214, + 184, + 185, + 182, + 40, + 174, + 192, + 111, + 164, + 159, + 64, + 51, + 235, + 102, + 217, + 195, + 112, + 233, + 200, + 61, + 232, + 132, + 61, + 137, + 203, + 155, + 6, + 53, + 103, + 29, + 163, + 146, + 164, + 78, + 244, + 14, + 23, + 230, + 169, + 35, + 196, + 255, + 158, + 104, + 146, + 54, + 94, + 131, + 244, + 45, + 31, + 29, + 32, + 172, + 22, + 108, + 215, + 10, + 203, + 13, + 189, + 115, + 152, + 35, + 199, + 57, + 68, + 185, + 162, + 219, + 160, + 128, + 239, + 28, + 29, + 168, + 243, + 69, + 252, + 224, + 118, + 109, + 99, + 180, + 189, + 251, + 250, + 64, + 157, + 197, + 115, + 154, + 58, + 235, + 56, + 247, + 87, + 172, + 207, + 27, + 228, + 126, + 245, + 26, + 94, + 223, + 55, + 34, + 64, + 32, + 5, + 25, + 88, + 206, + 250, + 149, + 145, + 190, + 251, + 123, + 55, + 101, + 163, + 215, + 60, + 195, + 203, + 16, + 135, + 221, + 186, + 0, + 223, + 0, + 115, + 34, + 82, + 202, + 113, + 133, + 45, + 103, + 200, + 51, + 69, + 208, + 179, + 87, + 4, + 127, + 140, + 109, + 113, + 16, + 169, + 248, + 56, + 71, + 7, + 158, + 123, + 116, + 192, + 85, + 240, + 43, + 173, + 133, + 232, + 244, + 95, + 171, + 108, + 76, + 62, + 77, + 250, + 98, + 151, + 160, + 62, + 221, + 209, + 78, + 7, + 29, + 173, + 49, + 195, + 214, + 94, + 237, + 35, + 42, + 214, + 132, + 154, + 220, + 104, + 183, + 71, + 188, + 11, + 203, + 76, + 55, + 219, + 39, + 48, + 94, + 95, + 245, + 196, + 142, + 18, + 79, + 127, + 147, + 65, + 147, + 204, + 76, + 7, + 220, + 114, + 190, + 241, + 16, + 87, + 177, + 140, + 206, + 61, + 62, + 171, + 159, + 200, + 90, + 105, + 75, + 76, + 192, + 86, + 189, + 175, + 1, + 106, + 131, + 121, + 113, + 100, + 194, + 185, + 75, + 3, + 223, + 14, + 8, + 96, + 177, + 63, + 193, + 188, + 109, + 8, + 154, + 46, + 64, + 172, + 77, + 241, + 86, + 3, + 213, + 208, + 142, + 223, + 48, + 88, + 11, + 136, + 214, + 115, + 55, + 113, + 237, + 227, + 126, + 156, + 118, + 13, + 192, + 250, + 62, + 13, + 43, + 110, + 251, + 162, + 32, + 28, + 111, + 142, + 181, + 91, + 198, + 89, + 147, + 148, + 238, + 204, + 246, + 109, + 111, + 43, + 203, + 241, + 191, + 88, + 184, + 13, + 80, + 51, + 241, + 9, + 164, + 196, + 116, + 214, + 255, + 246, + 65, + 0, + 95, + 119, + 55, + 12, + 241, + 88, + 168, + 199, + 64, + 163, + 200, + 173, + 253, + 60, + 154, + 34, + 41, + 104, + 111, + 19, + 241, + 43, + 185, + 83, + 8, + 120, + 91, + 209, + 85, + 0, + 242, + 150, + 38, + 92, + 16, + 134, + 220, + 28, + 199, + 213, + 31, + 159, + 238, + 62, + 253, + 118, + 31, + 91, + 99, + 58, + 154, + 2, + 124, + 92, + 128, + 15, + 254, + 230, + 255, + 92, + 47, + 192, + 184, + 197, + 91, + 40, + 194, + 74, + 124, + 94, + 7, + 234, + 134, + 67, + 120, + 90, + 9, + 126, + 147, + 229, + 186, + 35, + 64, + 66, + 124, + 206, + 92, + 44, + 68, + 212, + 49, + 37, + 198, + 240, + 252, + 212, + 50, + 18, + 101, + 31, + 20, + 105, + 145, + 163, + 115, + 250, + 62, + 2, + 226, + 88, + 87, + 158, + 53, + 28, + 30, + 229, + 169, + 240, + 54, + 246, + 193, + 112, + 5, + 64, + 62, + 94, + 177, + 235, + 80, + 36, + 101, + 83, + 122, + 186, + 209, + 119, + 141, + 166, + 60, + 132, + 181, + 230, + 179, + 199, + 107, + 165, + 221, + 132, + 237, + 1, + 201, + 215, + 57, + 27, + 64, + 180, + 34, + 6, + 134, + 80, + 36, + 86, + 152, + 249, + 180, + 42, + 167, + 194, + 215, + 125, + 245, + 219, + 26, + 71, + 240, + 97, + 171, + 245, + 95, + 251, + 219, + 123, + 47, + 104, + 100, + 152, + 57, + 116, + 56, + 226, + 116, + 146, + 62, + 23, + 70, + 150, + 182, + 31, + 54, + 208, + 249, + 60, + 45, + 121, + 14, + 183, + 110, + 203, + 234, + 153, + 95, + 2, + 82, + 65, + 204, + 31, + 110, + 3, + 128, + 73, + 166, + 160, + 158, + 70, + 85, + 19, + 101, + 73, + 8, + 80, + 9, + 30, + 129, + 115, + 117, + 238, + 104, + 5, + 138, + 94, + 28, + 86, + 229, + 247, + 40, + 186, + 19, + 250, + 189, + 76, + 218, + 51, + 215, + 117, + 93, + 236, + 31, + 155, + 0, + 242, + 56, + 188, + 216, + 90, + 82, + 104, + 203, + 99, + 104, + 236, + 161, + 183, + 254, + 218, + 218, + 162, + 36, + 102, + 170, + 132, + 125, + 15, + 177, + 0, + 180, + 151, + 44, + 5, + 76, + 190, + 87, + 178, + 150, + 124, + 231, + 220, + 14, + 234, + 144, + 185, + 9, + 63, + 104, + 184, + 88, + 215, + 202, + 124, + 81, + 227, + 213, + 153, + 109, + 34, + 233, + 69, + 168, + 19, + 15, + 166, + 75, + 188, + 183, + 121, + 214, + 53, + 126, + 85, + 10, + 171, + 187, + 59, + 118, + 2, + 116, + 79, + 99, + 163, + 242, + 178, + 152, + 78, + 53, + 171, + 157, + 18, + 68, + 70, + 48, + 81, + 237, + 126, + 5, + 30, + 234, + 29, + 72, + 9, + 222, + 204, + 29, + 7, + 55, + 255, + 207, + 17, + 216, + 9, + 114, + 168, + 66, + 246, + 48, + 210, + 151, + 7, + 127, + 196, + 35, + 18, + 178, + 255, + 0, + 166, + 0, + 237, + 184, + 31, + 195, + 153, + 145, + 190, + 247, + 198, + 231, + 207, + 121, + 183, + 150, + 18, + 29, + 103, + 103, + 72, + 200, + 254, + 91, + 37, + 69, + 85, + 233, + 148, + 53, + 231, + 144, + 172, + 34, + 30, + 6, + 52, + 212, + 105, + 158, + 192, + 118, + 160, + 128, + 42, + 232, + 140, + 255, + 93, + 223, + 156, + 75, + 203, + 17, + 184, + 240, + 140, + 150, + 76, + 123, + 124, + 235, + 110, + 182, + 92, + 64, + 206, + 68, + 22, + 110, + 181, + 18, + 48, + 95, + 109, + 228, + 194, + 5, + 137, + 79, + 203, + 106, + 186, + 61, + 215, + 29, + 69, + 112, + 201, + 70, + 155, + 184, + 169, + 31, + 171, + 249, + 133, + 16, + 232, + 119, + 214, + 39, + 29, + 176, + 151, + 212, + 84, + 29, + 185, + 86, + 175, + 139, + 43, + 95, + 109, + 111, + 218, + 239, + 70, + 142, + 177, + 99, + 39, + 228, + 252, + 255, + 252, + 12, + 241, + 49, + 231, + 242, + 223, + 210, + 21, + 102, + 106, + 78, + 165, + 230, + 215, + 196, + 182, + 136, + 121, + 174, + 122, + 121, + 217, + 121, + 77, + 197, + 29, + 122, + 82, + 240, + 91, + 203, + 20, + 158, + 213, + 77, + 103, + 167, + 148, + 120, + 34, + 119, + 159, + 142, + 115, + 154, + 237, + 157, + 111, + 42, + 108, + 85, + 142, + 21, + 231, + 5, + 115, + 72, + 138, + 33, + 37, + 147, + 135, + 247, + 22, + 152, + 27, + 80, + 228, + 3, + 67, + 93, + 88, + 83, + 97, + 4, + 101, + 247, + 119, + 142, + 183, + 7, + 88, + 95, + 46, + 78, + 56, + 193, + 10, + 235, + 242, + 194, + 35, + 55, + 98, + 114, + 159, + 140, + 220, + 31, + 170, + 134, + 191, + 137, + 163, + 30, + 153, + 178, + 195, + 121, + 226, + 234, + 234, + 152, + 118, + 129, + 59, + 214, + 205, + 17, + 151, + 15, + 190, + 77, + 162, + 12, + 51, + 226, + 59, + 133, + 210, + 108, + 103, + 38, + 39, + 122, + 217, + 229, + 47, + 118, + 81, + 139, + 39, + 211, + 161, + 101, + 248, + 6, + 226, + 89, + 151, + 95, + 83, + 151, + 139, + 13, + 169, + 95, + 219, + 65, + 241, + 182, + 178, + 28, + 158, + 7, + 143, + 247, + 18, + 206, + 30, + 76, + 138, + 63, + 128, + 12, + 4, + 253, + 13, + 125, + 142, + 55, + 54, + 123, + 35, + 148, + 152, + 202, + 15, + 214, + 163, + 27, + 227, + 127, + 16, + 102, + 159, + 66, + 156, + 65, + 179, + 51, + 211, + 5, + 32, + 147, + 231, + 102, + 56, + 169, + 197, + 88, + 148, + 207, + 5, + 95, + 76, + 152, + 119, + 136, + 44, + 241, + 181, + 202, + 37, + 165, + 185, + 57, + 75, + 141, + 197, + 194, + 6, + 131, + 191, + 101, + 41, + 93, + 174, + 15, + 115, + 124, + 194, + 161, + 183, + 35, + 184, + 207, + 85, + 99, + 35, + 155, + 47, + 53, + 193, + 145, + 141, + 8, + 116, + 54, + 0, + 254, + 115, + 175, + 83, + 114, + 129, + 90, + 123, + 198, + 131, + 26, + 51, + 142, + 97, + 55, + 117, + 47, + 154, + 230, + 97, + 112, + 238, + 152, + 136, + 251, + 72, + 89, + 217, + 148, + 248, + 43, + 23, + 57, + 155, + 218, + 189, + 27, + 19, + 77, + 37, + 136, + 244, + 249, + 101, + 249, + 213, + 186, + 234, + 232, + 111, + 226, + 242, + 51, + 209, + 240, + 180, + 70, + 70, + 165, + 22, + 25, + 178, + 83, + 71, + 43, + 253, + 29, + 245, + 64, + 150, + 35, + 233, + 4, + 41, + 179, + 156, + 249, + 216, + 74, + 98, + 83, + 121, + 171, + 234, + 13, + 95, + 202, + 34, + 219, + 201, + 169, + 10, + 102, + 228, + 71, + 55, + 250, + 22, + 84, + 21, + 223, + 109, + 80, + 176, + 224, + 182, + 200, + 6, + 187, + 218, + 218, + 53, + 120, + 200, + 188, + 191, + 16, + 230, + 232, + 84, + 57, + 78, + 55, + 208, + 57, + 159, + 75, + 140, + 34, + 103, + 95, + 127, + 98, + 189, + 50, + 219, + 116, + 13, + 27, + 28, + 136, + 173, + 167, + 162, + 182, + 153, + 104, + 153, + 167, + 164, + 2, + 190, + 99, + 84, + 193, + 244, + 70, + 172, + 87, + 111, + 150, + 72, + 167, + 72, + 93, + 0, + 128, + 52, + 117, + 233, + 55, + 122, + 199, + 129, + 7, + 213, + 179, + 206, + 95, + 21, + 205, + 159, + 227, + 9, + 197, + 31, + 243, + 117, + 244, + 137, + 87, + 59, + 223, + 7, + 197, + 246, + 123, + 192, + 249, + 250, + 23, + 167, + 129, + 145, + 111, + 251, + 137, + 28, + 24, + 128, + 97, + 182, + 27, + 38, + 174, + 173, + 94, + 47, + 110, + 212, + 196, + 153, + 97, + 150, + 88, + 195, + 254, + 84, + 221, + 127, + 200, + 7, + 139, + 140, + 12, + 52, + 240, + 92, + 66, + 218, + 164, + 199, + 233, + 161, + 32, + 204, + 55, + 225, + 93, + 167, + 1, + 87, + 229, + 144, + 26, + 84, + 31, + 143, + 7, + 53, + 44, + 200, + 122, + 147, + 46, + 36, + 120, + 48, + 238, + 125, + 107, + 133, + 229, + 214, + 146, + 252, + 43, + 40, + 92, + 80, + 212, + 187, + 200, + 250, + 195, + 40, + 72, + 199, + 192, + 95, + 23, + 251, + 71, + 58, + 191, + 113, + 197, + 194, + 140, + 228, + 168, + 88, + 19, + 229, + 220, + 144, + 20, + 236, + 142, + 57, + 197, + 252, + 100, + 156, + 160, + 93, + 208, + 197, + 107, + 217, + 216, + 245, + 97, + 90, + 251, + 28, + 34, + 154, + 183, + 252, + 112, + 100, + 16, + 119, + 198, + 119, + 31, + 87, + 14, + 129, + 75, + 188, + 15, + 91, + 242, + 50, + 187, + 11, + 125, + 247, + 105, + 23, + 215, + 126, + 21, + 42, + 75, + 132, + 183, + 144, + 148, + 81, + 200, + 45, + 235, + 82, + 81, + 68, + 13, + 136, + 227, + 8, + 223, + 147, + 23, + 15, + 213, + 193, + 137, + 166, + 56, + 155, + 26, + 24, + 255, + 24, + 220, + 123, + 4, + 72, + 141, + 210, + 211, + 112, + 246, + 121, + 195, + 200, + 206, + 134, + 152, + 111, + 174, + 72, + 244, + 199, + 1, + 176, + 52, + 61, + 174, + 218, + 230, + 60, + 89, + 178, + 122, + 248, + 7, + 243, + 136, + 77, + 100, + 19, + 22, + 92, + 192, + 64, + 248, + 213, + 72, + 66, + 198, + 191, + 16, + 116, + 52, + 85, + 77, + 160, + 189, + 161, + 240, + 106, + 187, + 48, + 43, + 80, + 200, + 66, + 240, + 163, + 2, + 175, + 42, + 175, + 163, + 198, + 60, + 207, + 23, + 161, + 8, + 203, + 108, + 86, + 200, + 19, + 213, + 229, + 102, + 132, + 11, + 208, + 230, + 77, + 180, + 96, + 99, + 169, + 236, + 130, + 71, + 126, + 87, + 147, + 53, + 187, + 58, + 7, + 8, + 72, + 203, + 19, + 54, + 24, + 230, + 159, + 153, + 140, + 164, + 55, + 89, + 10, + 158, + 244, + 37, + 118, + 115, + 153, + 4, + 137, + 228, + 199, + 61, + 11, + 247, + 191, + 250, + 24, + 32, + 205, + 167, + 246, + 87, + 9, + 255, + 214, + 108, + 161, + 125, + 212, + 225, + 124, + 49, + 135, + 51, + 28, + 159, + 21, + 104, + 209, + 115, + 199, + 248, + 195, + 18, + 95, + 125, + 253, + 53, + 206, + 88, + 86, + 223, + 169, + 107, + 162, + 115, + 38, + 168, + 116, + 54, + 59, + 168, + 58, + 209, + 14, + 203, + 211, + 89, + 84, + 248, + 56, + 91, + 159, + 225, + 154, + 252, + 200, + 19, + 65, + 180, + 103, + 90, + 229, + 210, + 42, + 215, + 19, + 167, + 49, + 5, + 28, + 26, + 201, + 41, + 55, + 211, + 119, + 63, + 136, + 110, + 224, + 57, + 84, + 84, + 55, + 185, + 147, + 10, + 80, + 108, + 28, + 68, + 218, + 206, + 75, + 218, + 22, + 168, + 30, + 255, + 46, + 96, + 206, + 99, + 235, + 49, + 48, + 191, + 102, + 146, + 118, + 221, + 242, + 71, + 155, + 104, + 206, + 215, + 112, + 248, + 232, + 155, + 82, + 123, + 18, + 14, + 211, + 12, + 169, + 60, + 224, + 42, + 205, + 238, + 199, + 164, + 218, + 76, + 171, + 224, + 216, + 197, + 242, + 225, + 220, + 53, + 69, + 69, + 252, + 81, + 128, + 44, + 30, + 107, + 27, + 38, + 99, + 106, + 147, + 16, + 167, + 255, + 58, + 122, + 179, + 82, + 141, + 85, + 32, + 175, + 1, + 220, + 117, + 14, + 254, + 19, + 37, + 113, + 13, + 13, + 100, + 102, + 187, + 130, + 170, + 98, + 35, + 174, + 84, + 116, + 134, + 14, + 201, + 31, + 64, + 153, + 58, + 110, + 166, + 254, + 11, + 71, + 152, + 175, + 165, + 179, + 53, + 237, + 78, + 221, + 152, + 40, + 221, + 58, + 99, + 80, + 213, + 221, + 79, + 35, + 103, + 1, + 171, + 160, + 138, + 241, + 88, + 89, + 135, + 165, + 162, + 130, + 197, + 93, + 71, + 84, + 120, + 15, + 189, + 202, + 37, + 252, + 81, + 97, + 183, + 42, + 57, + 206, + 145, + 63, + 186, + 110, + 76, + 189, + 243, + 98, + 1, + 137, + 154, + 79, + 123, + 9, + 184, + 43, + 176, + 62, + 56, + 22, + 125, + 144, + 101, + 83, + 176, + 2, + 218, + 18, + 9, + 91, + 236, + 38, + 163, + 145, + 74, + 10, + 249, + 55, + 160, + 210, + 238, + 96, + 246, + 98, + 177, + 32, + 74, + 249, + 121, + 207, + 29, + 199, + 88, + 120, + 120, + 96, + 220, + 146, + 196, + 12, + 107, + 103, + 138, + 3, + 81, + 49, + 24, + 248, + 118, + 138, + 163, + 104, + 174, + 154, + 241, + 34, + 20, + 16, + 164, + 53, + 148, + 180, + 8, + 39, + 88, + 251, + 64, + 132, + 6, + 211, + 33, + 95, + 122, + 73, + 86, + 199, + 213, + 86, + 99, + 151, + 200, + 22, + 179, + 43, + 172, + 193, + 198, + 186, + 13, + 23, + 54, + 151, + 224, + 205, + 176, + 69, + 220, + 146, + 230, + 137, + 120, + 181, + 250, + 0, + 187, + 54, + 210, + 41, + 150, + 180, + 47, + 84, + 234, + 25, + 55, + 7, + 222, + 234, + 142, + 156, + 25, + 34, + 66, + 77, + 84, + 195, + 164, + 209, + 199, + 119, + 253, + 174, + 190, + 213, + 112, + 54, + 117, + 121, + 15, + 29, + 248, + 15, + 77, + 58, + 45, + 69, + 155, + 45, + 76, + 250, + 0, + 46, + 126, + 3, + 203, + 79, + 4, + 121, + 55, + 70, + 18, + 11, + 101, + 240, + 27, + 191, + 109, + 96, + 90, + 34, + 220, + 18, + 141, + 175, + 220, + 202, + 237, + 34, + 19, + 88, + 123, + 180, + 69, + 167, + 254, + 156, + 110, + 154, + 143, + 159, + 246, + 2, + 209, + 127, + 191, + 27, + 147, + 205, + 74, + 34, + 98, + 243, + 203, + 195, + 112, + 217, + 2, + 193, + 71, + 53, + 152, + 206, + 53, + 43, + 10, + 174, + 93, + 241, + 162, + 110, + 118, + 103, + 160, + 205, + 212, + 45, + 120, + 157, + 5, + 72, + 128, + 4, + 200, + 104, + 225, + 181, + 31, + 102, + 98, + 0, + 26, + 210, + 184, + 119, + 222, + 143, + 221, + 83, + 234, + 188, + 127, + 190, + 237, + 238, + 134, + 138, + 69, + 17, + 128, + 229, + 70, + 36, + 26, + 0, + 145, + 61, + 142, + 136, + 78, + 93, + 80, + 174, + 198, + 60, + 70, + 88, + 229, + 128, + 136, + 136, + 193, + 78, + 36, + 65, + 225, + 181, + 191, + 85, + 165, + 92, + 250, + 206, + 190, + 100, + 119, + 72, + 126, + 131, + 232, + 228, + 99, + 167, + 35, + 194, + 120, + 58, + 108, + 92, + 129, + 143, + 150, + 50, + 205, + 33, + 13, + 13, + 178, + 35, + 110, + 28, + 153, + 83, + 190, + 216, + 6, + 200, + 179, + 80, + 60, + 16, + 26, + 190, + 215, + 199, + 162, + 67, + 33, + 172, + 101, + 242, + 122, + 127, + 236, + 68, + 62, + 173, + 171, + 82, + 77, + 55, + 91, + 57, + 149, + 192, + 235, + 90, + 29, + 72, + 225, + 43, + 129, + 236, + 188, + 177, + 110, + 82, + 71, + 38, + 190, + 192, + 238, + 87, + 186, + 14, + 10, + 90, + 178, + 25, + 36, + 15, + 6, + 233, + 166, + 181, + 181, + 181, + 133, + 48, + 13, + 236, + 93, + 22, + 114, + 79, + 223, + 39, + 180, + 232, + 180, + 183, + 215, + 79, + 86, + 162, + 12, + 134, + 30, + 165, + 172, + 249, + 54, + 201, + 180, + 238, + 208, + 167, + 101, + 110, + 42, + 23, + 223, + 223, + 159, + 49, + 74, + 70, + 119, + 221, + 80, + 164, + 87, + 58, + 183, + 204, + 163, + 144, + 92, + 223, + 97, + 26, + 185, + 207, + 147, + 141, + 255, + 249, + 235, + 16, + 254, + 249, + 30, + 56, + 248, + 179, + 140, + 15, + 57, + 96, + 110, + 87, + 64, + 234, + 57, + 36, + 134, + 89, + 242, + 187, + 95, + 37, + 164, + 138, + 193, + 185, + 168, + 252, + 70, + 247, + 2, + 33, + 128, + 202, + 177, + 73, + 123, + 97, + 88, + 60, + 187, + 131, + 106, + 87, + 147, + 152, + 152, + 12, + 163, + 58, + 105, + 181, + 94, + 233, + 234, + 236, + 99, + 236, + 255, + 202, + 139, + 157, + 168, + 149, + 130, + 214, + 81, + 69, + 78, + 120, + 174, + 13, + 43, + 49, + 138, + 2, + 5, + 155, + 78, + 101, + 59, + 67, + 185, + 89, + 211, + 1, + 245, + 248, + 81, + 189, + 7, + 117, + 140, + 113, + 162, + 206, + 73, + 59, + 150, + 200, + 124, + 174, + 36, + 110, + 93, + 226, + 87, + 42, + 60, + 50, + 64, + 213, + 29, + 91, + 31, + 43, + 218, + 84, + 219, + 65, + 28, + 107, + 247, + 96, + 202, + 84, + 220, + 19, + 233, + 81, + 58, + 173, + 201, + 234, + 78, + 88, + 182, + 197, + 113, + 207, + 108, + 193, + 230, + 247, + 104, + 38, + 237, + 97, + 180, + 253, + 210, + 13, + 112, + 36, + 78, + 152, + 30, + 217, + 146, + 108, + 201, + 2, + 151, + 128, + 107, + 211, + 181, + 49, + 157, + 127, + 247, + 117, + 62, + 225, + 5, + 1, + 20, + 122, + 148, + 177, + 131, + 223, + 250, + 42, + 235, + 10, + 35, + 5, + 135, + 252, + 32, + 239, + 63, + 197, + 206, + 154, + 76, + 100, + 39, + 20, + 210, + 207, + 146, + 117, + 102, + 230, + 170, + 30, + 132, + 86, + 61, + 6, + 29, + 109, + 68, + 160, + 84, + 192, + 225, + 179, + 80, + 185, + 94, + 134, + 61, + 211, + 234, + 107, + 16, + 76, + 125, + 72, + 251, + 12, + 154, + 250, + 147, + 65, + 91, + 135, + 11, + 68, + 106, + 184, + 204, + 45, + 130, + 207, + 17, + 213, + 244, + 185, + 207, + 110, + 55, + 62, + 147, + 250, + 237, + 122, + 48, + 219, + 181, + 114, + 13, + 106, + 1, + 154, + 170, + 40, + 215, + 167, + 8, + 183, + 143, + 144, + 85, + 239, + 69, + 206, + 226, + 41, + 58, + 122, + 70, + 234, + 102, + 113, + 138, + 239, + 142, + 112, + 49, + 98, + 153, + 31, + 40, + 24, + 8, + 188, + 52, + 190, + 5, + 144, + 129, + 107, + 31, + 28, + 49, + 18, + 100, + 28, + 195, + 189, + 57, + 241, + 243, + 118, + 8, + 58, + 148, + 211, + 206, + 152, + 237, + 42, + 54, + 77, + 201, + 39, + 11, + 32, + 60, + 201, + 91, + 238, + 55, + 126, + 86, + 54, + 255, + 66, + 80, + 242, + 243, + 159, + 123, + 62, + 212, + 240, + 238, + 123, + 122, + 110, + 42, + 126, + 195, + 149, + 37, + 99, + 171, + 125, + 230, + 113, + 57, + 252, + 243, + 93, + 139, + 104, + 41, + 30, + 245, + 131, + 161, + 242, + 23, + 146, + 46, + 139, + 112, + 81, + 203, + 220, + 249, + 247, + 2, + 215, + 202, + 164, + 18, + 18, + 235, + 140, + 130, + 77, + 131, + 70, + 245, + 129, + 222, + 43, + 116, + 123, + 254, + 149, + 248, + 232, + 181, + 58, + 47, + 105, + 83, + 35, + 123, + 104, + 231, + 204, + 161, + 93, + 211, + 29, + 192, + 96, + 155, + 24, + 137, + 132, + 190, + 151, + 4, + 148, + 189, + 121, + 158, + 91, + 129, + 99, + 117, + 52, + 163, + 61, + 144, + 179, + 122, + 136, + 146, + 148, + 43, + 40, + 253, + 56, + 129, + 161, + 107, + 27, + 143, + 249, + 91, + 21, + 243, + 120, + 219, + 121, + 209, + 18, + 182, + 166, + 255, + 109, + 134, + 135, + 83, + 170, + 56, + 52, + 230, + 51, + 129, + 47, + 5, + 70, + 15, + 141, + 14, + 193, + 94, + 69, + 85, + 106, + 228, + 7, + 64, + 136, + 192, + 185, + 235, + 22, + 78, + 221, + 231, + 127, + 18, + 255, + 0, + 201, + 187, + 39, + 110, + 58, + 177, + 235, + 30, + 13, + 199, + 91, + 70, + 251, + 239, + 75, + 204, + 150, + 216, + 241, + 130, + 95, + 24, + 165, + 44, + 184, + 9, + 154, + 243, + 4, + 144, + 181, + 76, + 160, + 156, + 0, + 197, + 15, + 145, + 250, + 6, + 189, + 52, + 131, + 161, + 134, + 151, + 95, + 55, + 198, + 94, + 248, + 69, + 241, + 215, + 170, + 110, + 160, + 101, + 183, + 18, + 214, + 34, + 216, + 141, + 114, + 226, + 235, + 57, + 24, + 187, + 24, + 180, + 138, + 12, + 181, + 26, + 114, + 104, + 111, + 26, + 74, + 2, + 212, + 105, + 154, + 198, + 169, + 227, + 212, + 158, + 91, + 131, + 239, + 155, + 2, + 147, + 218, + 46, + 142, + 165, + 153, + 17, + 108, + 33, + 198, + 36, + 149, + 68, + 202, + 55, + 96, + 103, + 195, + 248, + 101, + 24, + 206, + 9, + 129, + 28, + 53, + 218, + 12, + 127, + 79, + 189, + 129, + 250, + 81, + 126, + 27, + 153, + 37, + 48, + 91, + 3, + 21, + 138, + 151, + 211, + 93, + 80, + 81, + 192, + 197, + 20, + 0, + 73, + 2, + 144, + 239, + 165, + 43, + 129, + 22, + 93, + 168, + 101, + 76, + 27, + 229, + 121, + 97, + 190, + 97, + 165, + 112, + 114, + 248, + 49, + 162, + 124, + 170, + 18, + 39, + 11, + 42, + 116, + 175, + 17, + 207, + 41, + 201, + 251, + 142, + 218, + 48, + 22, + 243, + 202, + 166, + 202, + 46, + 182, + 253, + 116, + 232, + 59, + 187, + 157, + 138, + 14, + 167, + 138, + 41, + 251, + 66, + 64, + 138, + 243, + 102, + 153, + 31, + 52, + 164, + 33, + 119, + 254, + 171, + 117, + 102, + 66, + 185, + 77, + 179, + 207, + 168, + 164, + 227, + 42, + 161, + 150, + 207, + 92, + 160, + 112, + 85, + 130, + 1, + 25, + 130, + 174, + 199, + 87, + 56, + 230, + 33, + 101, + 73, + 203, + 158, + 167, + 80, + 172, + 165, + 159, + 8, + 212, + 63, + 142, + 85, + 158, + 2, + 88, + 93, + 86, + 55, + 204, + 0, + 137, + 45, + 206, + 79, + 71, + 15, + 99, + 208, + 140, + 72, + 123, + 57, + 43, + 166, + 68, + 243, + 253, + 35, + 111, + 46, + 219, + 144, + 55, + 255, + 239, + 29, + 141, + 117, + 49, + 206, + 67, + 232, + 168, + 30, + 157, + 229, + 112, + 30, + 186, + 246, + 150, + 232, + 62, + 154, + 106, + 221, + 96, + 35, + 23, + 212, + 171, + 34, + 208, + 178, + 80, + 0, + 16, + 255, + 43, + 93, + 73, + 101, + 125, + 214, + 100, + 7, + 206, + 233, + 126, + 210, + 74, + 167, + 90, + 222, + 192, + 249, + 94, + 215, + 174, + 35, + 120, + 45, + 84, + 78, + 79, + 20, + 208, + 191, + 10, + 203, + 162, + 89, + 188, + 248, + 4, + 29, + 73, + 110, + 124, + 87, + 57, + 249, + 243, + 209, + 70, + 248, + 191, + 72, + 186, + 163, + 104, + 85, + 60, + 13, + 61, + 248, + 44, + 45, + 71, + 107, + 36, + 61, + 200, + 102, + 28, + 222, + 52, + 28, + 168, + 55, + 246, + 95, + 142, + 153, + 10, + 17, + 145, + 149, + 133, + 232, + 146, + 86, + 19, + 58, + 112, + 220, + 226, + 92, + 224, + 14, + 107, + 203, + 126, + 98, + 166, + 67, + 97, + 220, + 202, + 103, + 48, + 79, + 134, + 192, + 127, + 82, + 252, + 92, + 171, + 156, + 180, + 91, + 130, + 23, + 212, + 244, + 172, + 138, + 172, + 98, + 150, + 139, + 29, + 140, + 248, + 38, + 174, + 185, + 139, + 166, + 123, + 71, + 146, + 74, + 156, + 91, + 40, + 81, + 48, + 62, + 6, + 151, + 84, + 252, + 199, + 142, + 148, + 145, + 51, + 103, + 217, + 158, + 199, + 19, + 225, + 218, + 143, + 217, + 86, + 55, + 26, + 128, + 141, + 57, + 60, + 35, + 153, + 19, + 191, + 26, + 119, + 244, + 219, + 102, + 168, + 63, + 195, + 22, + 45, + 84, + 219, + 35, + 247, + 117, + 90, + 76, + 112, + 0, + 225, + 253, + 146, + 10, + 194, + 127, + 241, + 162, + 154, + 58, + 124, + 194, + 6, + 24, + 151, + 136, + 185, + 248, + 242, + 48, + 208, + 159, + 107, + 181, + 110, + 236, + 141, + 79, + 68, + 12, + 117, + 93, + 121, + 72, + 25, + 220, + 34, + 97, + 120, + 158, + 130, + 19, + 211, + 82, + 248, + 15, + 106, + 164, + 29, + 68, + 74, + 243, + 70, + 47, + 112, + 49, + 99, + 41, + 159, + 235, + 213, + 236, + 135, + 214, + 232, + 23, + 66, + 203, + 80, + 111, + 77, + 55, + 192, + 73, + 93, + 75, + 187, + 238, + 51, + 197, + 97, + 167, + 226, + 81, + 30, + 31, + 33, + 57, + 218, + 42, + 109, + 233, + 160, + 51, + 201, + 99, + 107, + 128, + 132, + 81, + 49, + 136, + 221, + 159, + 140, + 110, + 205, + 26, + 182, + 27, + 233, + 157, + 238, + 120, + 246, + 167, + 12, + 240, + 86, + 198, + 254, + 145, + 144, + 138, + 67, + 24, + 154, + 89, + 46, + 218, + 64, + 159, + 73, + 126, + 202, + 251, + 224, + 31, + 15, + 60, + 208, + 159, + 66, + 54, + 49, + 213, + 128, + 241, + 190, + 93, + 127, + 242, + 197, + 111, + 251, + 185, + 176, + 0, + 228, + 235, + 124, + 239, + 213, + 148, + 16, + 69, + 93, + 108, + 207, + 104, + 53, + 11, + 214, + 253, + 129, + 248, + 64, + 246, + 26, + 139, + 58, + 248, + 187, + 149, + 241, + 38, + 153, + 205, + 127, + 64, + 150, + 173, + 35, + 98, + 145, + 34, + 128, + 217, + 122, + 33, + 125, + 49, + 25, + 93, + 39, + 234, + 137, + 7, + 15, + 194, + 219, + 31, + 234, + 68, + 36, + 232, + 194, + 208, + 133, + 223, + 156, + 208, + 62, + 102, + 132, + 134, + 3, + 251, + 221, + 35, + 129, + 102, + 170, + 27, + 11, + 150, + 88, + 203, + 94, + 172, + 163, + 54, + 98, + 17, + 170, + 17, + 174, + 44, + 212, + 86, + 181, + 150, + 80, + 201, + 233, + 191, + 4, + 80, + 15, + 74, + 96, + 173, + 20, + 48, + 213, + 66, + 79, + 130, + 221, + 148, + 99, + 39, + 231, + 193, + 98, + 62, + 9, + 19, + 123, + 52, + 189, + 86, + 100, + 51, + 213, + 49, + 150, + 162, + 43, + 96, + 56, + 183, + 88, + 11, + 170, + 63, + 232, + 81, + 17, + 176, + 169, + 156, + 241, + 73, + 174, + 48, + 147, + 210, + 151, + 64, + 102, + 136, + 83, + 90, + 13, + 132, + 51, + 35, + 137, + 34, + 208, + 228, + 39, + 171, + 43, + 171, + 93, + 169, + 40, + 68, + 235, + 250, + 117, + 42, + 246, + 134, + 133, + 97, + 81, + 211, + 147, + 164, + 94, + 78, + 132, + 237, + 204, + 20, + 215, + 111, + 209, + 159, + 185, + 76, + 84, + 29, + 71, + 189, + 20, + 135, + 4, + 88, + 206, + 131, + 236, + 36, + 90, + 140, + 177, + 200, + 30, + 36, + 144, + 66, + 86, + 48, + 70, + 111, + 221, + 18, + 13, + 210, + 8, + 98, + 74, + 29, + 213, + 232, + 131, + 120, + 51, + 112, + 75, + 3, + 109, + 235, + 114, + 219, + 29, + 173, + 16, + 73, + 203, + 160, + 67, + 59, + 214, + 102, + 224, + 238, + 69, + 251, + 51, + 68, + 143, + 35, + 158, + 202, + 170, + 167, + 55, + 159, + 189, + 67, + 23, + 95, + 176, + 182, + 168, + 193, + 62, + 189, + 119, + 48, + 18, + 241, + 220, + 227, + 108, + 175, + 152, + 215, + 209, + 253, + 11, + 28, + 232, + 61, + 168, + 113, + 235, + 78, + 226, + 253, + 159, + 117, + 25, + 26, + 130, + 168, + 227, + 26, + 140, + 252, + 183, + 99, + 84, + 192, + 2, + 130, + 232, + 119, + 254, + 89, + 153, + 60, + 39, + 187, + 243, + 53, + 44, + 57, + 95, + 168, + 137, + 219, + 142, + 163, + 186, + 48, + 89, + 207, + 231, + 199, + 52, + 126, + 154, + 198, + 84, + 115, + 38, + 165, + 183, + 13, + 119, + 206, + 193, + 128, + 247, + 206, + 38, + 129, + 16, + 243, + 46, + 139, + 127, + 64, + 144, + 73, + 236, + 65, + 164, + 211, + 247, + 219, + 131, + 190, + 220, + 131, + 199, + 187, + 125, + 189, + 225, + 201, + 230, + 10, + 60, + 209, + 153, + 225, + 116, + 154, + 232, + 180, + 12, + 61, + 55, + 213, + 90, + 139, + 181, + 36, + 245, + 230, + 22, + 207, + 56, + 82, + 33, + 30, + 53, + 77, + 112, + 142, + 96, + 117, + 250, + 242, + 11, + 166, + 177, + 12, + 216, + 45, + 19, + 22, + 8, + 242, + 52, + 233, + 88, + 77, + 244, + 60, + 108, + 196, + 27, + 41, + 76, + 112, + 119, + 108, + 41, + 255, + 126, + 194, + 118, + 220, + 97, + 121, + 237, + 197, + 116, + 159, + 97, + 40, + 134, + 102, + 65, + 144, + 114, + 12, + 139, + 250, + 32, + 43, + 36, + 197, + 222, + 112, + 3, + 62, + 145, + 186, + 205, + 137, + 213, + 91, + 94, + 146, + 221, + 98, + 4, + 116, + 234, + 217, + 238, + 192, + 152, + 182, + 83, + 64, + 104, + 46, + 92, + 98, + 117, + 48, + 17, + 87, + 177, + 7, + 73, + 172, + 41, + 175, + 72, + 51, + 62, + 15, + 170, + 210, + 42, + 123, + 217, + 247, + 39, + 170, + 69, + 44, + 54, + 176, + 4, + 77, + 92, + 134, + 185, + 242, + 155, + 65, + 166, + 75, + 135, + 165, + 107, + 57, + 226, + 166, + 152, + 165, + 41, + 243, + 213, + 241, + 225, + 42, + 137, + 21, + 205, + 171, + 7, + 162, + 207, + 148, + 187, + 5, + 151, + 206, + 120, + 220, + 217, + 42, + 209, + 135, + 104, + 59, + 226, + 177, + 64, + 135, + 72, + 186, + 30, + 30, + 18, + 129, + 193, + 88, + 99, + 27, + 250, + 154, + 240, + 30, + 43, + 161, + 62, + 117, + 4, + 242, + 51, + 92, + 234, + 72, + 224, + 30, + 53, + 50, + 191, + 54, + 228, + 60, + 20, + 194, + 6, + 21, + 213, + 52, + 72, + 249, + 166, + 34, + 204, + 6, + 189, + 153, + 214, + 20, + 209, + 243, + 181, + 139, + 47, + 12, + 183, + 93, + 92, + 103, + 144, + 61, + 226, + 50, + 36, + 208, + 230, + 250, + 151, + 165, + 142, + 133, + 217, + 41, + 36, + 66, + 222, + 135, + 179, + 187, + 228, + 45, + 251, + 250, + 50, + 171, + 175, + 197, + 192, + 96, + 205, + 183, + 119, + 190, + 80, + 48, + 216, + 124, + 253, + 249, + 67, + 164, + 203, + 196, + 230, + 168, + 5, + 255, + 13, + 105, + 73, + 11, + 124, + 35, + 68, + 239, + 96, + 59, + 238, + 101, + 50, + 91, + 72, + 183, + 177, + 170, + 250, + 126, + 217, + 251, + 74, + 93, + 48, + 178, + 28, + 61, + 163, + 111, + 31, + 215, + 162, + 233, + 255, + 95, + 168, + 86, + 57, + 9, + 181, + 18, + 129, + 154, + 229, + 5, + 25, + 211, + 160, + 191, + 92, + 77, + 231, + 117, + 202, + 146, + 7, + 253, + 121, + 55, + 254, + 247, + 46, + 195, + 226, + 42, + 115, + 177, + 226, + 160, + 177, + 252, + 96, + 95, + 198, + 88, + 125, + 95, + 132, + 192, + 178, + 223, + 53, + 31, + 168, + 132, + 206, + 197, + 19, + 45, + 111, + 69, + 242, + 138, + 56, + 185, + 4, + 230, + 124, + 211, + 20, + 222, + 1, + 199, + 213, + 141, + 83, + 247, + 12, + 87, + 162, + 21, + 13, + 243, + 185, + 130, + 132, + 80, + 226, + 144, + 20, + 222, + 179, + 118, + 247, + 32, + 202, + 205, + 157, + 80, + 178, + 170, + 41, + 83, + 185, + 84, + 252, + 6, + 215, + 186, + 144, + 100, + 143, + 255, + 96, + 15, + 59, + 244, + 108, + 230, + 235, + 216, + 16, + 170, + 27, + 8, + 103, + 47, + 62, + 201, + 1, + 171, + 121, + 166, + 138, + 165, + 187, + 123, + 220, + 165, + 225, + 105, + 174, + 30, + 26, + 250, + 50, + 7, + 121, + 243, + 100, + 42, + 202, + 190, + 246, + 42, + 239, + 72, + 231, + 130, + 34, + 18, + 128, + 249, + 181, + 244, + 2, + 227, + 147, + 144, + 65, + 156, + 199, + 210, + 222, + 9, + 204, + 131, + 137, + 248, + 228, + 237, + 53, + 155, + 37, + 84, + 180, + 199, + 137, + 128, + 130, + 154, + 85, + 57, + 89, + 9, + 150, + 143, + 36, + 189, + 56, + 53, + 85, + 16, + 232, + 87, + 113, + 98, + 233, + 145, + 14, + 121, + 220, + 101, + 57, + 75, + 35, + 234, + 167, + 186, + 18, + 67, + 17, + 21, + 210, + 35, + 212, + 248, + 145, + 1, + 38, + 180, + 47, + 164, + 204, + 162, + 249, + 205, + 31, + 77, + 139, + 149, + 23, + 118, + 171, + 127, + 47, + 185, + 135, + 215, + 56, + 87, + 220, + 45, + 166, + 165, + 112, + 67, + 87, + 108, + 41, + 20, + 90, + 181, + 22, + 58, + 8, + 70, + 89, + 91, + 31, + 75, + 177, + 169, + 165, + 17, + 66, + 92, + 94, + 221, + 241, + 229, + 189, + 232, + 123, + 184, + 252, + 30, + 173, + 198, + 61, + 96, + 250, + 62, + 212, + 68, + 180, + 54, + 159, + 142, + 2, + 56, + 83, + 50, + 196, + 89, + 126, + 151, + 231, + 75, + 44, + 93, + 55, + 18, + 39, + 56, + 110, + 254, + 165, + 192, + 63, + 98, + 80, + 118, + 126, + 47, + 240, + 141, + 87, + 5, + 212, + 141, + 60, + 224, + 148, + 25, + 223, + 219, + 189, + 171, + 38, + 194, + 113, + 24, + 16, + 10, + 220, + 169, + 20, + 178, + 194, + 224, + 64, + 117, + 165, + 209, + 19, + 178, + 216, + 79, + 232, + 151, + 21, + 135, + 125, + 3, + 126, + 5, + 57, + 157, + 251, + 96, + 58, + 90, + 168, + 255, + 60, + 225, + 85, + 209, + 135, + 59, + 123, + 110, + 116, + 126, + 93, + 97, + 185, + 31, + 233, + 161, + 184, + 40, + 63, + 172, + 143, + 252, + 64, + 53, + 174, + 251, + 19, + 229, + 255, + 196, + 178, + 164, + 3, + 31, + 68, + 232, + 138, + 48, + 131, + 112, + 212, + 250, + 119, + 68, + 192, + 225, + 224, + 144, + 169, + 245, + 159, + 252, + 141, + 151, + 141, + 65, + 208, + 68, + 60, + 133, + 165, + 31, + 141, + 62, + 33, + 49, + 233, + 167, + 212, + 151, + 228, + 138, + 139, + 20, + 245, + 46, + 144, + 219, + 122, + 96, + 216, + 230, + 155, + 210, + 27, + 0, + 189, + 73, + 189, + 225, + 23, + 67, + 222, + 128, + 66, + 120, + 253, + 241, + 10, + 22, + 87, + 176, + 142, + 43, + 161, + 83, + 19, + 169, + 76, + 231, + 43, + 128, + 105, + 166, + 6, + 14, + 216, + 198, + 172, + 96, + 242, + 28, + 160, + 67, + 71, + 237, + 91, + 111, + 205, + 204, + 153, + 159, + 11, + 50, + 16, + 201, + 170, + 246, + 46, + 19, + 8, + 252, + 134, + 124, + 110, + 58, + 116, + 219, + 194, + 91, + 10, + 22, + 227, + 157, + 169, + 221, + 254, + 229, + 198, + 12, + 213, + 108, + 156, + 197, + 134, + 23, + 34, + 127, + 152, + 158, + 200, + 220, + 118, + 66, + 31, + 82, + 90, + 222, + 5, + 188, + 46, + 1, + 88, + 103, + 15, + 132, + 192, + 255, + 78, + 25, + 33, + 212, + 82, + 161, + 13, + 176, + 76, + 103, + 214, + 214, + 213, + 49, + 254, + 149, + 77, + 221, + 179, + 164, + 53, + 76, + 153, + 24, + 170, + 41, + 5, + 65, + 204, + 36, + 241, + 77, + 16, + 188, + 48, + 231, + 141, + 76, + 81, + 27, + 207, + 192, + 24, + 102, + 177, + 135, + 129, + 24, + 156, + 164, + 64, + 73, + 190, + 41, + 129, + 142, + 104, + 251, + 113, + 45, + 98, + 65, + 157, + 69, + 141, + 170, + 193, + 71, + 11, + 143, + 234, + 164, + 254, + 212, + 74, + 35, + 139, + 61, + 112, + 72, + 86, + 127, + 239, + 80, + 254, + 43, + 235, + 255, + 34, + 88, + 37, + 106, + 11, + 227, + 82, + 156, + 57, + 4, + 78, + 101, + 250, + 190, + 236, + 21, + 175, + 212, + 155, + 150, + 183, + 150, + 35, + 184, + 167, + 252, + 157, + 230, + 222, + 22, + 18, + 146, + 124, + 171, + 9, + 96, + 30, + 17, + 62, + 144, + 131, + 147, + 88, + 140, + 180, + 174, + 175, + 139, + 89, + 116, + 211, + 242, + 139, + 53, + 0, + 224, + 108, + 160, + 229, + 248, + 59, + 107, + 162, + 80, + 232, + 52, + 51, + 32, + 85, + 220, + 160, + 130, + 2, + 242, + 80, + 175, + 177, + 50, + 239, + 30, + 131, + 124, + 45, + 249, + 77, + 211, + 239, + 31, + 205, + 34, + 143, + 85, + 193, + 159, + 103, + 222, + 250, + 71, + 217, + 1, + 222, + 101, + 165, + 74, + 9, + 143, + 30, + 49, + 176, + 43, + 42, + 185, + 158, + 93, + 145, + 7, + 160, + 181, + 126, + 75, + 25, + 199, + 101, + 144, + 111, + 123, + 137, + 94, + 204, + 191, + 70, + 12, + 9, + 125, + 12, + 4, + 179, + 8, + 145, + 223, + 189, + 105, + 59, + 229, + 234, + 232, + 203, + 99, + 54, + 117, + 98, + 195, + 91, + 98, + 230, + 147, + 174, + 58, + 172, + 165, + 173, + 45, + 181, + 115, + 66, + 80, + 140, + 234, + 107, + 25, + 69, + 175, + 64, + 181, + 36, + 187, + 255, + 48, + 70, + 184, + 122, + 107, + 204, + 181, + 220, + 44, + 127, + 155, + 198, + 41, + 208, + 120, + 148, + 107, + 208, + 99, + 134, + 220, + 99, + 230, + 250, + 125, + 12, + 80, + 190, + 127, + 32, + 70, + 102, + 50, + 203, + 212, + 120, + 44, + 236, + 6, + 53, + 120, + 90, + 89, + 101, + 226, + 201, + 213, + 218, + 171, + 85, + 97, + 78, + 43, + 118, + 215, + 148, + 30, + 140, + 156, + 220, + 199, + 216, + 237, + 126, + 212, + 100, + 26, + 11, + 19, + 152, + 248, + 77, + 181, + 229, + 222, + 138, + 67, + 74, + 63, + 237, + 36, + 243, + 53, + 4, + 36, + 166, + 133, + 83, + 36, + 227, + 169, + 45, + 133, + 59, + 44, + 85, + 119, + 255, + 86, + 46, + 180, + 75, + 58, + 121, + 141, + 158, + 29, + 188, + 229, + 138, + 185, + 79, + 212, + 169, + 38, + 127, + 84, + 137, + 120, + 21, + 109, + 110, + 97, + 61, + 184, + 197, + 88, + 208, + 244, + 62, + 85, + 107, + 63, + 45, + 61, + 154, + 57, + 64, + 105, + 124, + 227, + 128, + 50, + 189, + 117, + 246, + 68, + 145, + 113, + 170, + 40, + 115, + 59, + 37, + 190, + 189, + 24, + 123, + 246, + 157, + 64, + 197, + 164, + 54, + 136, + 49, + 229, + 190, + 71, + 143, + 255, + 72, + 246, + 154, + 62, + 168, + 188, + 160, + 13, + 60, + 183, + 53, + 28, + 130, + 26, + 174, + 100, + 120, + 172, + 144, + 17, + 236, + 240, + 45, + 229, + 57, + 242, + 35, + 61, + 145, + 65, + 100, + 179, + 2, + 160, + 92, + 24, + 54, + 182, + 117, + 2, + 114, + 53, + 19, + 152, + 51, + 34, + 116, + 186, + 28, + 73, + 19, + 41, + 10, + 181, + 238, + 105, + 167, + 27, + 252, + 235, + 114, + 148, + 181, + 110, + 14, + 158, + 105, + 98, + 177, + 157, + 74, + 51, + 1, + 28, + 111, + 88, + 47, + 173, + 92, + 164, + 124, + 233, + 231, + 71, + 134, + 75, + 81, + 173, + 29, + 30, + 102, + 25, + 96, + 39, + 232, + 125, + 159, + 101, + 128, + 115, + 34, + 224, + 132, + 13, + 76, + 223, + 138, + 41, + 70, + 146, + 195, + 139, + 200, + 123, + 229, + 90, + 23, + 109, + 214, + 235, + 76, + 137, + 167, + 160, + 208, + 115, + 195, + 18, + 181, + 5, + 89, + 25, + 94, + 64, + 236, + 105, + 160, + 9, + 43, + 25, + 251, + 139, + 232, + 36, + 111, + 8, + 204, + 131, + 90, + 126, + 0, + 80, + 118, + 4, + 81, + 2, + 32, + 110, + 140, + 158, + 143, + 194, + 50, + 93, + 76, + 171, + 65, + 25, + 112, + 46, + 64, + 202, + 239, + 57, + 156, + 135, + 88, + 73, + 220, + 110, + 159, + 213, + 83, + 155, + 238, + 200, + 181, + 1, + 186, + 140, + 234, + 37, + 92, + 189, + 59, + 102, + 181, + 208, + 80, + 8, + 62, + 124, + 126, + 113, + 231, + 97, + 184, + 17, + 254, + 32, + 150, + 205, + 62, + 2, + 151, + 54, + 53, + 174, + 94, + 73, + 96, + 181, + 163, + 155, + 59, + 176, + 245, + 239, + 111, + 57, + 219, + 85, + 90, + 28, + 219, + 219, + 196, + 207, + 78, + 206, + 230, + 179, + 32, + 88, + 217, + 13, + 247, + 177, + 26, + 239, + 69, + 239, + 244, + 253, + 210, + 171, + 221, + 136, + 31, + 236, + 240, + 16, + 131, + 44, + 28, + 144, + 124, + 78, + 180, + 156, + 158, + 168, + 79, + 213, + 111, + 181, + 111, + 9, + 197, + 235, + 96, + 246, + 208, + 235, + 123, + 38, + 72, + 234, + 74, + 17, + 86, + 139, + 68, + 93, + 70, + 30, + 31, + 46, + 28, + 7, + 3, + 72, + 174, + 213, + 250, + 130, + 164, + 51, + 38, + 155, + 120, + 151, + 105, + 123, + 121, + 207, + 177, + 126, + 52, + 15, + 161, + 225, + 46, + 99, + 66, + 19, + 234, + 4, + 133, + 150, + 108, + 161, + 49, + 64, + 106, + 99, + 214, + 242, + 76, + 118, + 55, + 50, + 11, + 84, + 63, + 102, + 63, + 168, + 63, + 54, + 128, + 153, + 130, + 69, + 233, + 46, + 103, + 222, + 106, + 4, + 107, + 107, + 252, + 242, + 44, + 143, + 62, + 143, + 199, + 180, + 192, + 146, + 206, + 200, + 237, + 253, + 249, + 178, + 216, + 247, + 167, + 119, + 91, + 117, + 146, + 246, + 152, + 85, + 24, + 76, + 62, + 101, + 200, + 20, + 191, + 225, + 75, + 134, + 132, + 31, + 103, + 80, + 176, + 153, + 41, + 133, + 93, + 176, + 165, + 154, + 63, + 56, + 8, + 194, + 71, + 110, + 144, + 150, + 225, + 102, + 26, + 95, + 40, + 1, + 17, + 62, + 169, + 98, + 198, + 169, + 139, + 209, + 12, + 80, + 32, + 29, + 245, + 207, + 43, + 51, + 119, + 167, + 153, + 31, + 227, + 173, + 64, + 119, + 56, + 4, + 162, + 254, + 237, + 40, + 167, + 9, + 207, + 213, + 144, + 21, + 74, + 115, + 205, + 161, + 167, + 214, + 200, + 179, + 207, + 188, + 201, + 115, + 187, + 14, + 4, + 105, + 139, + 185, + 234, + 44, + 61, + 216, + 245, + 237, + 105, + 45, + 133, + 33, + 196, + 129, + 34, + 191, + 33, + 85, + 48, + 52, + 70, + 73, + 197, + 251, + 55, + 234, + 64, + 50, + 101, + 131, + 239, + 203, + 147, + 222, + 88, + 199, + 104, + 34, + 130, + 7, + 66, + 55, + 120, + 68, + 168, + 112, + 172, + 111, + 70, + 73, + 95, + 233, + 224, + 253, + 136, + 55, + 158, + 71, + 5, + 108, + 15, + 72, + 41, + 250, + 59, + 197, + 161, + 26, + 64, + 249, + 144, + 112, + 230, + 99, + 145, + 27, + 61, + 190, + 179, + 176, + 16, + 127, + 159, + 41, + 92, + 159, + 144, + 26, + 183, + 150, + 64, + 152, + 28, + 38, + 169, + 187, + 183, + 149, + 65, + 188, + 14, + 152, + 238, + 176, + 189, + 59, + 1, + 55, + 0, + 99, + 50, + 176, + 0, + 123, + 46, + 170, + 69, + 163, + 253, + 146, + 103, + 230, + 219, + 233, + 120, + 33, + 131, + 61, + 215, + 178, + 204, + 79, + 10, + 216, + 29, + 172, + 118, + 150, + 218, + 42, + 116, + 55, + 247, + 130, + 160, + 85, + 73, + 23, + 228, + 6, + 24, + 132, + 104, + 213, + 254, + 183, + 65, + 1, + 148, + 76, + 117, + 245, + 118, + 78, + 133, + 85, + 246, + 160, + 205, + 12, + 136, + 114, + 211, + 220, + 189, + 172, + 49, + 140, + 236, + 203, + 175, + 207, + 193, + 60, + 99, + 170, + 248, + 90, + 98, + 102, + 168, + 198, + 73, + 66, + 100, + 230, + 195, + 37, + 64, + 219, + 206, + 135, + 61, + 112, + 114, + 113, + 111, + 11, + 226, + 91, + 234, + 89, + 172, + 88, + 174, + 100, + 109, + 17, + 246, + 2, + 72, + 45, + 37, + 38, + 217, + 241, + 160, + 180, + 138, + 155, + 205, + 187, + 251, + 239, + 114, + 96, + 78, + 119, + 244, + 215, + 70, + 153, + 84, + 30, + 166, + 14, + 68, + 94, + 10, + 166, + 238, + 239, + 0, + 92, + 194, + 237, + 117, + 211, + 139, + 248, + 112, + 160, + 246, + 212, + 251, + 197, + 53, + 44, + 17, + 4, + 120, + 183, + 192, + 131, + 115, + 36, + 211, + 182, + 46, + 108, + 154, + 194, + 116, + 205, + 175, + 0, + 52, + 32, + 229, + 249, + 12, + 159, + 62, + 51, + 138, + 178, + 168, + 150, + 185, + 114, + 183, + 202, + 16, + 128, + 211, + 243, + 254, + 48, + 209, + 136, + 115, + 235, + 183, + 112, + 237, + 26, + 150, + 235, + 139, + 111, + 239, + 255, + 19, + 66, + 249, + 16, + 136, + 21, + 217, + 10, + 6, + 78, + 226, + 224, + 88, + 164, + 14, + 164, + 74, + 134, + 88, + 172, + 5, + 211, + 54, + 159, + 253, + 161, + 214, + 251, + 234, + 63, + 166, + 46, + 181, + 238, + 59, + 43, + 95, + 217, + 116, + 237, + 180, + 11, + 135, + 115, + 34, + 187, + 95, + 77, + 26, + 226, + 19, + 13, + 85, + 241, + 188, + 219, + 43, + 5, + 105, + 184, + 150, + 251, + 186, + 236, + 33, + 252, + 117, + 26, + 84, + 47, + 203, + 75, + 53, + 45, + 177, + 122, + 106, + 251, + 107, + 130, + 97, + 7, + 125, + 63, + 55, + 235, + 1, + 140, + 115, + 127, + 141, + 10, + 158, + 147, + 18, + 76, + 162, + 49, + 191, + 121, + 115, + 47, + 8, + 123, + 251, + 32, + 167, + 203, + 42, + 109, + 16, + 140, + 3, + 157, + 195, + 106, + 50, + 246, + 58, + 84, + 19, + 189, + 181, + 15, + 235, + 41, + 158, + 195, + 3, + 132, + 139, + 140, + 124, + 213, + 186, + 168, + 37, + 90, + 2, + 245, + 135, + 66, + 49, + 10, + 198, + 234, + 62, + 206, + 105, + 103, + 96, + 64, + 201, + 49, + 91, + 213, + 235, + 201, + 7, + 98, + 103, + 2, + 70, + 125, + 96, + 219, + 178, + 102, + 71, + 12, + 160, + 101, + 76, + 105, + 33, + 243, + 82, + 149, + 192, + 110, + 125, + 34, + 227, + 242, + 50, + 244, + 157, + 176, + 236, + 13, + 23, + 253, + 182, + 145, + 125, + 31, + 26, + 238, + 34, + 69, + 142, + 40, + 100, + 247, + 48, + 65, + 180, + 119, + 64, + 151, + 14, + 145, + 4, + 175, + 21, + 181, + 75, + 41, + 205, + 110, + 33, + 116, + 146, + 251, + 58, + 62, + 222, + 118, + 78, + 106, + 103, + 207, + 185, + 64, + 167, + 109, + 157, + 220, + 115, + 51, + 219, + 151, + 89, + 15, + 43, + 160, + 170, + 11, + 240, + 177, + 224, + 147, + 170, + 193, + 56, + 87, + 1, + 24, + 111, + 151, + 96, + 218, + 147, + 32, + 235, + 83, + 173, + 111, + 96, + 55, + 230, + 133, + 131, + 90, + 161, + 154, + 130, + 166, + 243, + 6, + 61, + 66, + 156, + 72, + 114, + 210, + 212, + 79, + 250, + 230, + 192, + 200, + 20, + 170, + 67, + 222, + 157, + 75, + 84, + 7, + 43, + 223, + 213, + 222, + 175, + 177, + 225, + 54, + 108, + 148, + 232, + 205, + 210, + 87, + 158, + 154, + 198, + 133, + 212, + 84, + 217, + 41, + 70, + 91, + 202, + 235, + 215, + 42, + 208, + 59, + 63, + 130, + 18, + 124, + 31, + 180, + 74, + 105, + 196, + 177, + 212, + 12, + 165, + 222, + 172, + 196, + 127, + 210, + 33, + 109, + 248, + 16, + 71, + 41, + 158, + 33, + 122, + 117, + 212, + 22, + 32, + 15, + 130, + 218, + 119, + 224, + 204, + 254, + 197, + 93, + 1, + 226, + 107, + 27, + 74, + 129, + 191, + 211, + 164, + 153, + 139, + 221, + 46, + 238, + 233, + 127, + 109, + 101, + 147, + 146, + 181, + 151, + 217, + 71, + 211, + 51, + 69, + 27, + 17, + 207, + 182, + 136, + 18, + 103, + 62, + 120, + 137, + 219, + 144, + 73, + 147, + 50, + 17, + 253, + 210, + 110, + 224, + 73, + 5, + 125, + 208, + 214, + 121, + 105, + 5, + 13, + 173, + 16, + 181, + 238, + 137, + 158, + 210, + 236, + 23, + 101, + 24, + 200, + 35, + 229, + 205, + 186, + 14, + 98, + 247, + 35, + 169, + 131, + 6, + 87, + 206, + 111, + 169, + 82, + 23, + 179, + 21, + 12, + 243, + 20, + 61, + 115, + 103, + 33, + 76, + 67, + 158, + 163, + 27, + 115, + 231, + 155, + 166, + 113, + 166, + 66, + 126, + 77, + 65, + 58, + 166, + 186, + 225, + 198, + 134, + 145, + 119, + 32, + 222, + 80, + 28, + 64, + 37, + 85, + 14, + 90, + 102, + 244, + 219, + 45, + 156, + 6, + 49, + 246, + 189, + 177, + 119, + 252, + 205, + 238, + 37, + 110, + 121, + 112, + 60, + 65, + 151, + 252, + 211, + 140, + 183, + 47, + 163, + 83, + 187, + 148, + 55, + 99, + 64, + 26, + 129, + 171, + 177, + 6, + 30, + 89, + 107, + 247, + 201, + 73, + 16, + 56, + 7, + 33, + 48, + 126, + 189, + 157, + 137, + 64, + 76, + 47, + 41, + 38, + 149, + 206, + 8, + 239, + 156, + 161, + 196, + 193, + 225, + 29, + 138, + 166, + 57, + 199, + 45, + 14, + 187, + 216, + 35, + 160, + 11, + 56, + 170, + 235, + 231, + 232, + 168, + 94, + 109, + 176, + 76, + 37, + 242, + 47, + 215, + 42, + 84, + 37, + 173, + 204, + 185, + 127, + 70, + 68, + 139, + 130, + 135, + 41, + 214, + 169, + 250, + 106, + 11, + 200, + 184, + 192, + 65, + 122, + 38, + 146, + 169, + 247, + 146, + 92, + 227, + 6, + 69, + 81, + 251, + 162, + 132, + 176, + 237, + 169, + 80, + 14, + 97, + 174, + 67, + 251, + 125, + 196, + 243, + 69, + 124, + 108, + 50, + 248, + 231, + 184, + 55, + 114, + 183, + 9, + 150, + 75, + 21, + 174, + 27, + 171, + 144, + 169, + 115, + 233, + 203, + 105, + 201, + 1, + 62, + 22, + 199, + 162, + 62, + 121, + 52, + 244, + 20, + 206, + 73, + 17, + 202, + 154, + 187, + 71, + 247, + 146, + 220, + 24, + 174, + 162, + 141, + 5, + 40, + 104, + 148, + 42, + 167, + 18, + 229, + 141, + 115, + 133, + 121, + 196, + 220, + 71, + 40, + 189, + 72, + 79, + 206, + 201, + 137, + 118, + 148, + 187, + 243, + 9, + 196, + 69, + 181, + 190, + 79, + 80, + 169, + 71, + 29, + 20, + 175, + 45, + 130, + 216, + 168, + 43, + 48, + 58, + 60, + 253, + 223, + 237, + 124, + 155, + 197, + 29, + 120, + 181, + 178, + 205, + 54, + 105, + 224, + 43, + 37, + 141, + 211, + 118, + 52, + 253, + 15, + 197, + 243, + 15, + 19, + 98, + 194, + 236, + 159, + 201, + 229, + 203, + 137, + 109, + 110, + 128, + 91, + 185, + 123, + 71, + 184, + 86, + 227, + 83, + 4, + 2, + 233, + 87, + 169, + 200, + 122, + 90, + 152, + 254, + 186, + 202, + 142, + 100, + 211, + 182, + 3, + 175, + 106, + 24, + 149, + 242, + 88, + 104, + 7, + 211, + 92, + 84, + 151, + 117, + 54, + 254, + 15, + 96, + 148, + 52, + 252, + 138, + 63, + 97, + 127, + 253, + 117, + 123, + 35, + 245, + 183, + 17, + 154, + 88, + 183, + 252, + 164, + 209, + 53, + 113, + 91, + 226, + 27, + 213, + 73, + 38, + 152, + 217, + 200, + 57, + 159, + 203, + 212, + 45, + 209, + 81, + 212, + 103, + 3, + 174, + 191, + 164, + 140, + 54, + 105, + 210, + 23, + 50, + 171, + 161, + 144, + 2, + 59, + 142, + 221, + 194, + 253, + 36, + 98, + 114, + 143, + 49, + 172, + 224, + 10, + 100, + 152, + 218, + 112, + 220, + 27, + 116, + 125, + 20, + 120, + 190, + 50, + 116, + 35, + 180, + 77, + 125, + 238, + 170, + 205, + 243, + 85, + 135, + 164, + 173, + 50, + 196, + 54, + 107, + 128, + 151, + 117, + 69, + 230, + 138, + 60, + 106, + 133, + 114, + 146, + 97, + 179, + 174, + 37, + 179, + 113, + 55, + 144, + 178, + 90, + 147, + 136, + 174, + 2, + 233, + 75, + 169, + 249, + 141, + 166, + 20, + 4, + 207, + 137, + 237, + 9, + 166, + 161, + 233, + 75, + 75, + 247, + 107, + 78, + 254, + 224, + 220, + 164, + 74, + 139, + 190, + 200, + 9, + 150, + 226, + 88, + 89, + 172, + 242, + 8, + 222, + 255, + 73, + 149, + 232, + 252, + 62, + 172, + 199, + 124, + 251, + 128, + 194, + 154, + 74, + 152, + 170, + 165, + 142, + 40, + 99, + 203, + 156, + 184, + 135, + 234, + 71, + 27, + 177, + 163, + 4, + 145, + 110, + 133, + 69, + 177, + 195, + 122, + 217, + 10, + 103, + 236, + 199, + 219, + 172, + 6, + 43, + 203, + 89, + 32, + 252, + 245, + 64, + 114, + 229, + 29, + 5, + 245, + 179, + 181, + 116, + 204, + 194, + 133, + 211, + 250, + 63, + 221, + 214, + 113, + 137, + 252, + 14, + 190, + 83, + 107, + 185, + 98, + 113, + 215, + 79, + 147, + 206, + 118, + 44, + 56, + 119, + 205, + 136, + 141, + 237, + 73, + 49, + 160, + 34, + 185, + 198, + 231, + 28, + 71, + 255, + 97, + 179, + 9, + 3, + 73, + 151, + 245, + 27, + 114, + 41, + 110, + 170, + 82, + 128, + 249, + 26, + 227, + 130, + 66, + 217, + 27, + 191, + 224, + 101, + 36, + 217, + 30, + 177, + 157, + 115, + 197, + 32, + 45, + 124, + 15, + 255, + 87, + 174, + 160, + 134, + 144, + 254, + 12, + 228, + 138, + 44, + 132, + 59, + 87, + 11, + 255, + 109, + 25, + 62, + 20, + 240, + 74, + 6, + 106, + 206, + 59, + 0, + 150, + 141, + 21, + 106, + 246, + 209, + 7, + 171, + 85, + 210, + 55, + 135, + 22, + 242, + 223, + 166, + 221, + 63, + 45, + 154, + 235, + 63, + 254, + 134, + 21, + 252, + 182, + 64, + 141, + 101, + 155, + 43, + 209, + 131, + 222, + 220, + 76, + 187, + 34, + 58, + 229, + 200, + 245, + 65, + 106, + 226, + 71, + 206, + 167, + 140, + 113, + 144, + 102, + 251, + 53, + 195, + 79, + 223, + 187, + 152, + 199, + 2, + 105, + 77, + 146, + 208, + 76, + 77, + 57, + 169, + 70, + 146, + 246, + 214, + 163, + 39, + 78, + 11, + 233, + 16, + 225, + 235, + 92, + 48, + 83, + 26, + 134, + 189, + 217, + 9, + 199, + 142, + 86, + 222, + 122, + 55, + 208, + 36, + 126, + 78, + 85, + 45, + 215, + 234, + 50, + 202, + 130, + 102, + 239, + 116, + 218, + 17, + 57, + 17, + 5, + 35, + 189, + 37, + 10, + 200, + 10, + 23, + 166, + 142, + 129, + 236, + 161, + 44, + 67, + 20, + 70, + 209, + 121, + 105, + 21, + 168, + 224, + 189, + 242, + 209, + 139, + 56, + 10, + 12, + 199, + 58, + 18, + 11, + 16, + 66, + 30, + 72, + 77, + 26, + 190, + 20, + 228, + 134, + 36, + 91, + 123, + 53, + 135, + 245, + 187, + 233, + 251, + 129, + 178, + 229, + 114, + 252, + 14, + 142, + 33, + 164, + 190, + 136, + 253, + 196, + 173, + 56, + 112, + 201, + 174, + 14, + 193, + 196, + 70, + 152, + 254, + 73, + 117, + 5, + 31, + 183, + 171, + 138, + 100, + 26, + 21, + 66, + 2, + 52, + 183, + 204, + 200, + 240, + 192, + 26, + 147, + 143, + 198, + 173, + 149, + 57, + 196, + 228, + 121, + 105, + 119, + 4, + 81, + 74, + 61, + 249, + 151, + 26, + 137, + 16, + 94, + 250, + 171, + 52, + 69, + 162, + 143, + 251, + 31, + 134, + 81, + 209, + 211, + 99, + 152, + 223, + 200, + 63, + 222, + 73, + 145, + 150, + 52, + 181, + 8, + 11, + 178, + 110, + 163, + 239, + 111, + 41, + 242, + 217, + 85, + 7, + 110, + 236, + 142, + 155, + 189, + 107, + 16, + 51, + 247, + 139, + 162, + 68, + 91, + 144, + 80, + 46, + 156, + 60, + 167, + 75, + 16, + 1, + 125, + 40, + 250, + 191, + 219, + 209, + 26, + 132, + 0, + 77, + 193, + 6, + 144, + 27, + 253, + 75, + 117, + 44, + 120, + 60, + 124, + 80, + 230, + 89, + 128, + 47, + 149, + 74, + 255, + 175, + 242, + 2, + 78, + 113, + 52, + 170, + 218, + 255, + 138, + 126, + 55, + 186, + 200, + 62, + 141, + 115, + 253, + 231, + 87, + 109, + 85, + 102, + 48, + 94, + 88, + 168, + 233, + 172, + 6, + 199, + 65, + 81, + 85, + 41, + 238, + 167, + 56, + 127, + 42, + 138, + 5, + 16, + 251, + 160, + 90, + 153, + 147, + 132, + 12, + 145, + 225, + 200, + 156, + 190, + 189, + 120, + 174, + 153, + 117, + 179, + 56, + 76, + 151, + 119, + 190, + 100, + 231, + 85, + 44, + 136, + 103, + 80, + 102, + 74, + 254, + 70, + 109, + 118, + 164, + 228, + 120, + 70, + 143, + 238, + 136, + 61, + 112, + 214, + 218, + 176, + 205, + 161, + 40, + 1, + 55, + 242, + 47, + 32, + 154, + 67, + 246, + 11, + 149, + 22, + 114, + 53, + 141, + 114, + 124, + 54, + 229, + 81, + 162, + 165, + 175, + 119, + 133, + 135, + 38, + 39, + 74, + 108, + 141, + 240, + 118, + 11, + 247, + 65, + 135, + 62, + 2, + 84, + 46, + 145, + 184, + 69, + 68, + 252, + 29, + 247, + 173, + 51, + 214, + 79, + 249, + 83, + 247, + 19, + 86, + 96, + 205, + 123, + 27, + 170, + 111, + 146, + 122, + 156, + 185, + 105, + 195, + 100, + 54, + 141, + 196, + 27, + 37, + 70, + 67, + 183, + 175, + 49, + 63, + 36, + 53, + 30, + 162, + 35, + 25, + 73, + 213, + 146, + 58, + 187, + 248, + 196, + 29, + 54, + 232, + 203, + 144, + 198, + 203, + 79, + 245, + 153, + 144, + 239, + 12, + 173, + 182, + 103, + 231, + 88, + 247, + 183, + 173, + 247, + 215, + 239, + 114, + 243, + 35, + 193, + 236, + 72, + 95, + 187, + 72, + 0, + 201, + 5, + 87, + 86, + 164, + 72, + 176, + 132, + 187, + 207, + 26, + 211, + 62, + 38, + 182, + 240, + 71, + 178, + 145, + 219, + 116, + 52, + 49, + 105, + 152, + 112, + 168, + 100, + 255, + 241, + 165, + 9, + 57, + 84, + 202, + 209, + 192, + 41, + 138, + 161, + 92, + 136, + 170, + 6, + 0, + 224, + 88, + 99, + 16, + 207, + 168, + 172, + 54, + 65, + 42, + 96, + 68, + 200, + 53, + 0, + 206, + 169, + 89, + 189, + 230, + 154, + 94, + 160, + 86, + 33, + 122, + 47, + 175, + 169, + 99, + 172, + 220, + 56, + 36, + 42, + 1, + 158, + 69, + 203, + 76, + 81, + 197, + 246, + 42, + 246, + 91, + 26, + 18, + 127, + 109, + 185, + 172, + 86, + 37, + 84, + 220, + 94, + 188, + 196, + 134, + 241, + 144, + 94, + 37, + 134, + 119, + 121, + 155, + 60, + 113, + 108, + 106, + 202, + 135, + 49, + 150, + 194, + 19, + 169, + 226, + 194, + 153, + 56, + 69, + 2, + 66, + 57, + 72, + 76, + 79, + 63, + 147, + 116, + 178, + 143, + 93, + 133, + 20, + 126, + 228, + 243, + 47, + 118, + 241, + 181, + 207, + 32, + 6, + 135, + 122, + 240, + 154, + 108, + 132, + 230, + 190, + 100, + 140, + 83, + 107, + 27, + 35, + 55, + 38, + 229, + 209, + 212, + 74, + 243, + 37, + 255, + 216, + 99, + 49, + 126, + 7, + 240, + 86, + 27, + 63, + 35, + 116, + 209, + 8, + 35, + 24, + 37, + 74, + 204, + 211, + 90, + 47, + 44, + 15, + 86, + 85, + 55, + 120, + 250, + 80, + 76, + 4, + 5, + 172, + 142, + 121, + 103, + 168, + 48, + 20, + 43, + 18, + 17, + 221, + 73, + 175, + 164, + 54, + 182, + 204, + 164, + 148, + 177, + 114, + 102, + 237, + 75, + 62, + 52, + 4, + 139, + 116, + 2, + 66, + 225, + 191, + 77, + 97, + 125, + 63, + 93, + 253, + 97, + 126, + 255, + 212, + 9, + 249, + 112, + 89, + 28, + 203, + 59, + 12, + 20, + 144, + 43, + 120, + 116, + 132, + 178, + 156, + 187, + 132, + 179, + 141, + 7, + 75, + 128, + 133, + 183, + 148, + 170, + 161, + 67, + 103, + 60, + 186, + 113, + 246, + 93, + 205, + 221, + 55, + 17, + 133, + 246, + 176, + 39, + 93, + 98, + 196, + 163, + 190, + 17, + 182, + 218, + 160, + 220, + 173, + 240, + 61, + 8, + 199, + 18, + 17, + 194, + 22, + 79, + 243, + 224, + 219, + 196, + 169, + 191, + 218, + 176, + 70, + 155, + 213, + 103, + 187, + 9, + 165, + 93, + 23, + 38, + 112, + 18, + 212, + 47, + 175, + 215, + 26, + 192, + 96, + 106, + 20, + 166, + 19, + 127, + 19, + 109, + 64, + 90, + 218, + 60, + 16, + 110, + 130, + 88, + 103, + 109, + 109, + 210, + 53, + 46, + 146, + 204, + 181, + 14, + 253, + 2, + 170, + 63, + 154, + 229, + 16, + 164, + 140, + 145, + 42, + 215, + 211, + 179, + 39, + 72, + 108, + 66, + 17, + 96, + 153, + 12, + 169, + 84, + 225, + 12, + 20, + 244, + 85, + 199, + 46, + 223, + 68, + 135, + 157, + 134, + 47, + 143, + 120, + 0, + 229, + 146, + 128, + 134, + 127, + 253, + 18, + 192, + 249, + 167, + 74, + 103, + 102, + 97, + 180, + 115, + 37, + 96, + 8, + 69, + 91, + 43, + 110, + 223, + 47, + 64, + 46, + 128, + 74, + 34, + 113, + 191, + 203, + 251, + 83, + 175, + 216, + 79, + 94, + 124, + 146, + 170, + 46, + 77, + 105, + 63, + 181, + 51, + 62, + 14, + 197, + 138, + 174, + 181, + 122, + 82, + 201, + 24, + 126, + 215, + 232, + 249, + 173, + 220, + 149, + 126, + 140, + 94, + 37, + 101, + 214, + 28, + 49, + 141, + 90, + 27, + 228, + 226, + 137, + 8, + 2, + 186, + 181, + 156, + 143, + 245, + 74, + 63, + 201, + 252, + 29, + 212, + 229, + 128, + 210, + 217, + 232, + 89, + 123, + 203, + 148, + 71, + 84, + 128, + 62, + 52, + 121, + 196, + 179, + 149, + 3, + 88, + 111, + 208, + 92, + 248, + 172, + 178, + 112, + 195, + 9, + 63, + 196, + 67, + 175, + 97, + 223, + 214, + 185, + 23, + 71, + 6, + 11, + 49, + 15, + 121, + 191, + 143, + 181, + 130, + 93, + 188, + 93, + 47, + 162, + 223, + 31, + 104, + 24, + 101, + 111, + 185, + 124, + 11, + 125, + 160, + 195, + 121, + 160, + 159, + 108, + 138, + 157, + 166, + 139, + 76, + 94, + 200, + 174, + 100, + 55, + 27, + 62, + 155, + 82, + 17, + 191, + 7, + 117, + 120, + 52, + 61, + 57, + 194, + 166, + 13, + 137, + 21, + 143, + 248, + 44, + 139, + 233, + 10, + 229, + 173, + 87, + 231, + 193, + 179, + 4, + 196, + 77, + 52, + 221, + 226, + 235, + 101, + 122, + 17, + 247, + 55, + 139, + 70, + 70, + 65, + 25, + 239, + 161, + 243, + 226, + 219, + 231, + 37, + 60, + 22, + 185, + 16, + 41, + 82, + 92, + 124, + 122, + 51, + 151, + 22, + 78, + 2, + 109, + 111, + 215, + 49, + 64, + 208, + 212, + 26, + 97, + 52, + 67, + 173, + 68, + 34, + 174, + 96, + 147, + 145, + 139, + 111, + 48, + 160, + 210, + 37, + 108, + 26, + 92, + 202, + 216, + 88, + 212, + 242, + 221, + 70, + 121, + 165, + 155, + 202, + 142, + 119, + 121, + 138, + 101, + 48, + 66, + 211, + 112, + 230, + 252, + 95, + 164, + 202, + 85, + 240, + 112, + 80, + 123, + 110, + 229, + 31, + 75, + 42, + 35, + 34, + 125, + 88, + 196, + 240, + 159, + 195, + 54, + 234, + 221, + 132, + 206, + 191, + 153, + 58, + 216, + 133, + 10, + 129, + 211, + 171, + 60, + 43, + 23, + 213, + 21, + 150, + 181, + 78, + 160, + 196, + 194, + 200, + 16, + 86, + 114, + 208, + 188, + 193, + 135, + 6, + 141, + 46, + 198, + 58, + 188, + 82, + 28, + 234, + 168, + 35, + 253, + 185, + 0, + 228, + 215, + 239, + 241, + 205, + 111, + 248, + 139, + 234, + 143, + 191, + 205, + 16, + 97, + 97, + 95, + 135, + 11, + 149, + 208, + 52, + 133, + 109, + 136, + 184, + 99, + 225, + 82, + 111, + 77, + 11, + 74, + 13, + 125, + 228, + 254, + 245, + 189, + 12, + 41, + 164, + 51, + 60, + 143, + 109, + 161, + 51, + 98, + 223, + 217, + 102, + 88, + 139, + 214, + 29, + 106, + 100, + 9, + 168, + 71, + 242, + 40, + 241, + 14, + 64, + 40, + 176, + 216, + 252, + 88, + 206, + 189, + 192, + 29, + 162, + 123, + 114, + 68, + 136, + 59, + 172, + 208, + 226, + 54, + 56, + 52, + 253, + 109, + 105, + 252, + 247, + 44, + 136, + 185, + 7, + 63, + 171, + 197, + 249, + 58, + 110, + 236, + 172, + 51, + 221, + 125, + 162, + 177, + 44, + 147, + 4, + 48, + 239, + 78, + 246, + 189, + 163, + 121, + 248, + 212, + 122, + 190, + 112, + 55, + 147, + 80, + 75, + 14, + 175, + 10, + 48, + 223, + 166, + 234, + 78, + 229, + 13, + 243, + 21, + 68, + 54, + 72, + 44, + 91, + 252, + 244, + 212, + 67, + 32, + 15, + 208, + 108, + 189, + 29, + 129, + 7, + 115, + 157, + 181, + 53, + 190, + 22, + 212, + 97, + 52, + 97, + 231, + 236, + 113, + 250, + 21, + 60, + 40, + 219, + 229, + 175, + 185, + 237, + 9, + 67, + 225, + 205, + 19, + 143, + 91, + 145, + 159, + 139, + 34, + 92, + 216, + 14, + 205, + 46, + 210, + 148, + 226, + 136, + 64, + 221, + 194, + 97, + 44, + 68, + 53, + 155, + 136, + 250, + 124, + 22, + 1, + 255, + 191, + 240, + 40, + 245, + 228, + 68, + 49, + 25, + 204, + 44, + 213, + 86, + 88, + 157, + 142, + 34, + 165, + 208, + 75, + 252, + 146, + 129, + 80, + 209, + 72, + 56, + 119, + 125, + 176, + 41, + 101, + 49, + 11, + 253, + 191, + 6, + 108, + 248, + 25, + 237, + 227, + 160, + 24, + 94, + 178, + 42, + 245, + 83, + 149, + 101, + 63, + 119, + 83, + 13, + 23, + 140, + 68, + 216, + 222, + 130, + 11, + 87, + 149, + 182, + 153, + 195, + 104, + 120, + 217, + 62, + 137, + 202, + 0, + 10, + 101, + 39, + 116, + 185, + 138, + 60, + 149, + 158, + 90, + 222, + 241, + 255, + 69, + 48, + 1, + 248, + 57, + 235, + 191, + 150, + 94, + 34, + 29, + 7, + 92, + 216, + 116, + 232, + 188, + 30, + 217, + 111, + 60, + 136, + 220, + 136, + 85, + 166, + 34, + 184, + 58, + 244, + 188, + 119, + 42, + 9, + 27, + 203, + 92, + 5, + 124, + 58, + 191, + 29, + 71, + 48, + 194, + 102, + 104, + 35, + 99, + 75, + 188, + 185, + 38, + 26, + 236, + 71, + 139, + 198, + 137, + 105, + 239, + 182, + 197, + 146, + 36, + 183, + 86, + 77, + 98, + 215, + 230, + 131, + 249, + 135, + 55, + 106, + 80, + 165, + 209, + 18, + 209, + 91, + 6, + 178, + 253, + 182, + 172, + 14, + 57, + 251, + 33, + 249, + 16, + 3, + 25, + 24, + 99, + 171, + 10, + 98, + 152, + 60, + 7, + 3, + 8, + 9, + 2, + 241, + 165, + 226, + 22, + 108, + 20, + 199, + 190, + 173, + 238, + 211, + 27, + 88, + 193, + 250, + 130, + 34, + 202, + 101, + 245, + 27, + 29, + 59, + 22, + 84, + 205, + 190, + 229, + 56, + 212, + 49, + 69, + 196, + 141, + 106, + 117, + 147, + 31, + 234, + 111, + 164, + 42, + 27, + 101, + 240, + 13, + 95, + 68, + 219, + 81, + 30, + 156, + 232, + 83, + 12, + 47, + 6, + 27, + 161, + 19, + 83, + 120, + 24, + 44, + 63, + 240, + 113, + 216, + 174, + 58, + 138, + 23, + 207, + 163, + 233, + 167, + 46, + 112, + 125, + 28, + 47, + 4, + 254, + 229, + 234, + 82, + 136, + 113, + 189, + 76, + 109, + 113, + 192, + 162, + 29, + 234, + 205, + 181, + 11, + 197, + 131, + 244, + 191, + 13, + 29, + 240, + 122, + 133, + 37, + 111, + 78, + 194, + 212, + 95, + 186, + 21, + 158, + 238, + 178, + 25, + 2, + 74, + 70, + 80, + 239, + 110, + 189, + 19, + 65, + 148, + 52, + 46, + 82, + 71, + 36, + 103, + 223, + 107, + 217, + 236, + 139, + 148, + 241, + 38, + 201, + 233, + 158, + 106, + 223, + 205, + 16, + 113, + 93, + 78, + 198, + 253, + 95, + 27, + 180, + 7, + 203, + 184, + 104, + 72, + 221, + 223, + 253, + 112, + 197, + 252, + 111, + 184, + 49, + 157, + 125, + 79, + 113, + 229, + 180, + 192, + 23, + 18, + 4, + 24, + 86, + 35, + 192, + 158, + 153, + 19, + 34, + 63, + 183, + 143, + 198, + 13, + 128, + 132, + 229, + 123, + 170, + 136, + 151, + 79, + 207, + 249, + 144, + 221, + 52, + 157, + 138, + 218, + 192, + 71, + 174, + 100, + 111, + 119, + 116, + 147, + 24, + 250, + 179, + 2, + 190, + 132, + 158, + 154, + 240, + 156, + 13, + 43, + 156, + 180, + 191, + 202, + 78, + 240, + 10, + 184, + 40, + 120, + 98, + 84, + 115, + 4, + 32, + 17, + 61, + 17, + 88, + 109, + 98, + 73, + 133, + 139, + 150, + 228, + 250, + 155, + 129, + 47, + 32, + 148, + 88, + 224, + 134, + 25, + 161, + 80, + 84, + 129, + 57, + 201, + 102, + 168, + 213, + 239, + 188, + 83, + 38, + 0, + 238, + 219, + 223, + 244, + 126, + 233, + 207, + 147, + 7, + 56, + 155, + 21, + 153, + 172, + 33, + 98, + 121, + 250, + 57, + 36, + 53, + 32, + 178, + 177, + 189, + 156, + 214, + 192, + 149, + 84, + 126, + 49, + 110, + 229, + 47, + 232, + 112, + 200, + 18, + 80, + 138, + 17, + 24, + 97, + 195, + 246, + 17, + 246, + 17, + 162, + 228, + 229, + 4, + 159, + 238, + 42, + 120, + 170, + 39, + 174, + 249, + 77, + 103, + 163, + 41, + 66, + 238, + 235, + 0, + 125, + 242, + 80, + 41, + 185, + 174, + 140, + 210, + 63, + 127, + 90, + 191, + 37, + 240, + 232, + 242, + 184, + 144, + 221, + 118, + 102, + 151, + 49, + 26, + 42, + 168, + 22, + 156, + 128, + 156, + 18, + 247, + 187, + 29, + 63, + 39, + 113, + 190, + 241, + 71, + 141, + 250, + 213, + 219, + 93, + 223, + 201, + 62, + 234, + 79, + 208, + 117, + 31, + 185, + 116, + 157, + 87, + 73, + 77, + 226, + 167, + 188, + 183, + 146, + 254, + 118, + 249, + 13, + 243, + 113, + 64, + 50, + 6, + 2, + 75, + 245, + 145, + 79, + 8, + 155, + 58, + 97, + 74, + 196, + 34, + 128, + 57, + 60, + 86, + 217, + 31, + 11, + 201, + 89, + 100, + 206, + 200, + 96, + 242, + 26, + 197, + 207, + 72, + 23, + 2, + 185, + 100, + 228, + 107, + 123, + 35, + 144, + 60, + 3, + 77, + 87, + 125, + 55, + 175, + 195, + 73, + 172, + 61, + 250, + 160, + 41, + 82, + 72, + 30, + 80, + 76, + 61, + 73, + 189, + 190, + 198, + 168, + 45, + 30, + 175, + 6, + 206, + 30, + 91, + 46, + 5, + 81, + 226, + 131, + 218, + 101, + 34, + 17, + 78, + 229, + 42, + 111, + 170, + 113, + 102, + 163, + 0, + 187, + 53, + 75, + 24, + 114, + 180, + 74, + 154, + 254, + 60, + 11, + 27, + 223, + 210, + 115, + 242, + 31, + 0, + 142, + 204, + 29, + 186, + 9, + 104, + 250, + 160, + 95, + 95, + 215, + 59, + 207, + 172, + 23, + 63, + 48, + 28, + 102, + 155, + 248, + 76, + 9, + 241, + 56, + 197, + 113, + 16, + 125, + 138, + 87, + 137, + 174, + 28, + 98, + 168, + 2, + 15, + 151, + 210, + 110, + 215, + 2, + 18, + 74, + 132, + 177, + 163, + 85, + 66, + 23, + 238, + 250, + 214, + 233, + 123, + 200, + 151, + 156, + 235, + 218, + 134, + 160, + 137, + 81, + 171, + 0, + 63, + 8, + 149, + 59, + 191, + 130, + 172, + 172, + 114, + 132, + 161, + 196, + 131, + 191, + 207, + 155, + 142, + 155, + 25, + 158, + 47, + 54, + 190, + 91, + 175, + 219, + 162, + 56, + 147, + 80, + 236, + 164, + 170, + 30, + 207, + 112, + 30, + 208, + 138, + 72, + 161, + 207, + 240, + 244, + 158, + 166, + 86, + 5, + 55, + 237, + 180, + 203, + 158, + 246, + 108, + 151, + 21, + 198, + 246, + 3, + 27, + 7, + 29, + 101, + 144, + 80, + 216, + 47, + 118, + 89, + 135, + 141, + 50, + 148, + 164, + 116, + 100, + 227, + 100, + 174, + 4, + 133, + 205, + 146, + 185, + 204, + 189, + 208, + 182, + 2, + 137, + 188, + 81, + 217, + 249, + 53, + 252, + 112, + 85, + 82, + 37, + 83, + 5, + 155, + 44, + 218, + 164, + 18, + 3, + 126, + 99, + 248, + 222, + 113, + 228, + 252, + 21, + 220, + 147, + 37, + 111, + 219, + 37, + 39, + 12, + 57, + 19, + 76, + 72, + 42, + 97, + 109, + 159, + 26, + 89, + 31, + 19, + 73, + 49, + 132, + 43, + 241, + 99, + 84, + 78, + 47, + 178, + 81, + 126, + 114, + 98, + 175, + 55, + 183, + 159, + 126, + 123, + 39, + 121, + 107, + 254, + 12, + 55, + 85, + 106, + 25, + 107, + 200, + 138, + 195, + 189, + 107, + 145, + 195, + 253, + 208, + 95, + 57, + 68, + 176, + 33, + 238, + 5, + 239, + 199, + 177, + 214, + 119, + 105, + 64, + 80, + 54, + 88, + 89, + 25, + 9, + 249, + 174, + 75, + 244, + 67, + 164, + 47, + 170, + 85, + 108, + 27, + 105, + 207, + 73, + 60, + 19, + 148, + 157, + 38, + 170, + 56, + 97, + 232, + 75, + 170, + 160, + 254, + 30, + 156, + 75, + 67, + 211, + 157, + 80, + 198, + 18, + 246, + 139, + 24, + 53, + 142, + 52, + 49, + 187, + 101, + 191, + 5, + 13, + 114, + 24, + 252, + 100, + 166, + 109, + 103, + 179, + 251, + 186, + 185, + 22, + 43, + 50, + 128, + 147, + 108, + 33, + 113, + 247, + 232, + 122, + 11, + 9, + 104, + 115, + 149, + 20, + 155, + 108, + 181, + 83, + 92, + 69, + 94, + 51, + 23, + 29, + 185, + 64, + 60, + 98, + 130, + 212, + 74, + 99, + 185, + 68, + 134, + 40, + 11, + 71, + 9, + 76, + 199, + 249, + 12, + 221, + 112, + 150, + 135, + 122, + 87, + 52, + 110, + 116, + 44, + 61, + 12, + 195, + 119, + 152, + 106, + 90, + 222, + 236, + 94, + 24, + 254, + 51, + 177, + 18, + 94, + 109, + 6, + 190, + 28, + 50, + 27, + 76, + 24, + 95, + 57, + 48, + 212, + 130, + 227, + 224, + 19, + 236, + 143, + 219, + 60, + 210, + 78, + 65, + 235, + 202, + 251, + 114, + 227, + 163, + 11, + 8, + 48, + 63, + 153, + 197, + 146, + 144, + 192, + 241, + 100, + 65, + 149, + 132, + 227, + 205, + 93, + 41, + 10, + 109, + 83, + 74, + 118, + 97, + 242, + 200, + 58, + 200, + 121, + 76, + 222, + 110, + 38, + 203, + 243, + 22, + 134, + 194, + 179, + 162, + 24, + 41, + 223, + 112, + 152, + 105, + 117, + 44, + 56, + 21, + 88, + 245, + 61, + 17, + 73, + 52, + 36, + 218, + 145, + 3, + 11, + 7, + 111, + 4, + 219, + 126, + 233, + 194, + 240, + 31, + 78, + 49, + 66, + 36, + 119, + 60, + 206, + 138, + 72, + 236, + 7, + 233, + 139, + 54, + 55, + 5, + 23, + 90, + 18, + 128, + 156, + 146, + 8, + 12, + 78, + 137, + 147, + 188, + 251, + 232, + 75, + 73, + 70, + 8, + 104, + 149, + 219, + 234, + 1, + 177, + 156, + 135, + 107, + 28, + 158, + 73, + 161, + 14, + 146, + 196, + 63, + 218, + 76, + 184, + 159, + 102, + 24, + 198, + 146, + 206, + 216, + 66, + 213, + 17, + 200, + 122, + 235, + 108, + 253, + 113, + 200, + 45, + 130, + 33, + 57, + 24, + 128, + 84, + 3, + 79, + 244, + 146, + 189, + 215, + 163, + 65, + 50, + 70, + 75, + 53, + 3, + 250, + 151, + 36, + 59, + 222, + 74, + 77, + 28, + 161, + 204, + 45, + 251, + 249, + 29, + 106, + 62, + 55, + 191, + 126, + 228, + 220, + 62, + 31, + 137, + 209, + 24, + 138, + 96, + 76, + 63, + 42, + 66, + 89, + 138, + 110, + 112, + 84, + 125, + 134, + 78, + 131, + 231, + 250, + 127, + 170, + 66, + 44, + 89, + 15, + 43, + 155, + 68, + 59, + 7, + 116, + 26, + 88, + 142, + 237, + 143, + 42, + 146, + 150, + 92, + 127, + 196, + 211, + 85, + 53, + 99, + 229, + 123, + 91, + 60, + 233, + 43, + 251, + 78, + 111, + 67, + 90, + 129, + 168, + 212, + 28, + 165, + 55, + 176, + 107, + 16, + 24, + 194, + 73, + 51, + 115, + 242, + 97, + 103, + 155, + 160, + 188, + 179, + 13, + 202, + 168, + 127, + 93, + 233, + 144, + 44, + 157, + 49, + 209, + 214, + 222, + 90, + 165, + 219, + 91, + 91, + 251, + 253, + 234, + 162, + 37, + 55, + 90, + 182, + 63, + 22, + 58, + 127, + 121, + 105, + 55, + 178, + 17, + 8, + 189, + 66, + 124, + 190, + 106, + 158, + 255, + 16, + 247, + 253, + 39, + 70, + 3, + 130, + 171, + 24, + 218, + 122, + 40, + 11, + 21, + 87, + 115, + 50, + 6, + 6, + 97, + 197, + 52, + 87, + 73, + 237, + 134, + 42, + 253, + 253, + 196, + 167, + 134, + 203, + 162, + 133, + 86, + 243, + 173, + 84, + 144, + 93, + 32, + 249, + 70, + 228, + 60, + 155, + 146, + 91, + 177, + 40, + 173, + 103, + 85, + 74, + 236, + 102, + 54, + 159, + 229, + 250, + 253, + 96, + 50, + 39, + 30, + 89, + 102, + 15, + 137, + 13, + 219, + 78, + 25, + 147, + 112, + 188, + 255, + 121, + 213, + 125, + 3, + 173, + 138, + 39, + 43, + 50, + 226, + 154, + 92, + 188, + 185, + 79, + 235, + 222, + 172, + 1, + 240, + 24, + 212, + 151, + 252, + 40, + 227, + 213, + 104, + 206, + 105, + 92, + 41, + 204, + 255, + 204, + 210, + 227, + 220, + 141, + 64, + 91, + 230, + 100, + 65, + 218, + 213, + 238, + 139, + 136, + 23, + 244, + 248, + 244, + 103, + 214, + 7, + 121, + 80, + 166, + 246, + 82, + 11, + 101, + 120, + 239, + 134, + 245, + 185, + 90, + 87, + 85, + 30, + 167, + 219, + 218, + 20, + 100, + 227, + 85, + 234, + 76, + 98, + 59, + 56, + 46, + 132, + 246, + 5, + 170, + 13, + 97, + 159, + 14, + 68, + 163, + 65, + 216, + 56, + 142, + 61, + 179, + 204, + 37, + 73, + 144, + 134, + 3, + 222, + 38, + 222, + 4, + 64, + 136, + 143, + 222, + 180, + 13, + 10, + 63, + 213, + 45, + 78, + 231, + 133, + 228, + 114, + 93, + 108, + 156, + 227, + 94, + 169, + 193, + 133, + 124, + 75, + 255, + 173, + 126, + 91, + 15, + 27, + 134, + 49, + 189, + 151, + 104, + 141, + 17, + 61, + 243, + 72, + 1, + 177, + 44, + 199, + 250, + 74, + 211, + 242, + 220, + 223, + 241, + 168, + 6, + 13, + 45, + 99, + 113, + 165, + 60, + 150, + 178, + 165, + 162, + 176, + 133, + 106, + 76, + 80, + 179, + 154, + 184, + 113, + 160, + 28, + 153, + 209, + 104, + 100, + 37, + 116, + 70, + 138, + 124, + 102, + 215, + 162, + 37, + 42, + 52, + 245, + 187, + 102, + 54, + 44, + 123, + 39, + 142, + 236, + 94, + 194, + 60, + 94, + 17, + 184, + 54, + 16, + 36, + 124, + 100, + 5, + 188, + 43, + 17, + 117, + 252, + 205, + 237, + 247, + 218, + 128, + 106, + 218, + 110, + 39, + 209, + 249, + 175, + 11, + 95, + 74, + 190, + 195, + 208, + 195, + 238, + 157, + 221, + 161, + 53, + 44, + 216, + 51, + 16, + 255, + 77, + 77, + 111, + 15, + 140, + 253, + 151, + 38, + 61, + 108, + 134, + 150, + 42, + 225, + 63, + 253, + 134, + 0, + 250, + 99, + 130, + 228, + 216, + 234, + 32, + 209, + 187, + 214, + 169, + 82, + 157, + 203, + 226, + 226, + 137, + 147, + 158, + 12, + 140, + 149, + 183, + 122, + 224, + 188, + 140, + 193, + 27, + 231, + 204, + 29, + 214, + 210, + 88, + 182, + 23, + 95, + 89, + 11, + 43, + 169, + 226, + 54, + 90, + 9, + 160, + 54, + 83, + 204, + 45, + 70, + 177, + 225, + 125, + 11, + 250, + 0, + 174, + 90, + 9, + 145, + 176, + 2, + 252, + 11, + 43, + 13, + 24, + 232, + 52, + 136, + 107, + 159, + 84, + 12, + 27, + 167, + 28, + 58, + 64, + 107, + 5, + 5, + 81, + 139, + 153, + 229, + 150, + 243, + 184, + 128, + 46, + 40, + 254, + 209, + 228, + 212, + 147, + 39, + 163, + 143, + 6, + 115, + 209, + 160, + 232, + 92, + 129, + 247, + 88, + 216, + 41, + 146, + 210, + 123, + 201, + 241, + 158, + 230, + 81, + 196, + 196, + 234, + 254, + 203, + 239, + 50, + 244, + 22, + 60, + 232, + 194, + 236, + 122, + 148, + 106, + 87, + 163, + 82, + 57, + 168, + 222, + 68, + 159, + 68, + 211, + 21, + 229, + 236, + 24, + 202, + 5, + 129, + 170, + 205, + 17, + 20, + 139, + 106, + 226, + 32, + 117, + 113, + 244, + 35, + 254, + 69, + 16, + 105, + 82, + 88, + 107, + 200, + 188, + 87, + 217, + 4, + 185, + 221, + 195, + 89, + 90, + 236, + 217, + 234, + 102, + 8, + 190, + 234, + 91, + 80, + 46, + 206, + 237, + 92, + 201, + 147, + 44, + 6, + 60, + 115, + 0, + 87, + 18, + 107, + 252, + 56, + 81, + 181, + 66, + 212, + 112, + 158, + 96, + 89, + 105, + 156, + 46, + 191, + 82, + 173, + 181, + 245, + 155, + 239, + 61, + 144, + 251, + 168, + 102, + 229, + 19, + 54, + 225, + 6, + 233, + 169, + 49, + 4, + 130, + 106, + 13, + 187, + 117, + 232, + 247, + 14, + 190, + 176, + 100, + 189, + 80, + 16, + 24, + 95, + 42, + 235, + 114, + 103, + 164, + 189, + 225, + 216, + 201, + 176, + 65, + 19, + 222, + 229, + 134, + 253, + 228, + 63, + 7, + 166, + 130, + 135, + 230, + 152, + 244, + 203, + 141, + 221, + 161, + 87, + 60, + 186, + 177, + 95, + 85, + 72, + 74, + 1, + 87, + 180, + 42, + 72, + 6, + 71, + 67, + 115, + 83, + 175, + 105, + 189, + 234, + 249, + 198, + 48, + 105, + 133, + 192, + 198, + 193, + 153, + 20, + 254, + 29, + 249, + 98, + 0, + 123, + 131, + 239, + 235, + 111, + 27, + 102, + 6, + 219, + 4, + 186, + 218, + 182, + 246, + 76, + 68, + 36, + 229, + 104, + 228, + 79, + 146, + 20, + 79, + 176, + 167, + 5, + 224, + 187, + 222, + 121, + 67, + 21, + 245, + 209, + 60, + 186, + 204, + 53, + 133, + 142, + 48, + 28, + 158, + 218, + 124, + 53, + 125, + 248, + 49, + 11, + 5, + 181, + 134, + 152, + 154, + 221, + 175, + 230, + 131, + 2, + 80, + 4, + 127, + 167, + 150, + 30, + 35, + 145, + 104, + 166, + 46, + 80, + 75, + 206, + 221, + 116, + 229, + 35, + 200, + 112, + 90, + 57, + 15, + 115, + 156, + 238, + 221, + 214, + 130, + 121, + 90, + 168, + 227, + 218, + 111, + 240, + 75, + 199, + 86, + 28, + 101, + 201, + 199, + 69, + 113, + 28, + 241, + 2, + 29, + 21, + 101, + 75, + 147, + 116, + 215, + 85, + 206, + 205, + 138, + 210, + 99, + 76, + 89, + 78, + 196, + 167, + 110, + 40, + 110, + 33, + 106, + 87, + 236, + 81, + 166, + 13, + 22, + 189, + 50, + 197, + 120, + 133, + 111, + 132, + 130, + 183, + 94, + 218, + 129, + 199, + 119, + 94, + 240, + 186, + 196, + 103, + 2, + 102, + 140, + 195, + 19, + 115, + 20, + 82, + 233, + 1, + 206, + 33, + 38, + 143, + 187, + 163, + 248, + 76, + 167, + 40, + 137, + 141, + 217, + 97, + 10, + 5, + 104, + 64, + 169, + 13, + 9, + 178, + 137, + 110, + 23, + 46, + 44, + 94, + 72, + 87, + 227, + 27, + 95, + 10, + 108, + 165, + 178, + 118, + 192, + 152, + 51, + 53, + 195, + 217, + 196, + 89, + 18, + 169, + 209, + 127, + 38, + 79, + 108, + 45, + 105, + 56, + 20, + 166, + 31, + 250, + 129, + 74, + 105, + 234, + 68, + 144, + 41, + 234, + 190, + 253, + 96, + 85, + 203, + 143, + 236, + 24, + 128, + 142, + 253, + 100, + 200, + 33, + 13, + 48, + 75, + 129, + 197, + 14, + 76, + 120, + 178, + 79, + 227, + 17, + 59, + 239, + 141, + 186, + 43, + 209, + 240, + 239, + 158, + 85, + 214, + 139, + 30, + 205, + 96, + 103, + 194, + 82, + 230, + 251, + 100, + 130, + 41, + 40, + 217, + 172, + 34, + 222, + 213, + 107, + 1, + 254, + 121, + 245, + 136, + 21, + 63, + 241, + 144, + 176, + 61, + 247, + 61, + 161, + 114, + 116, + 97, + 120, + 9, + 161, + 157, + 134, + 10, + 141, + 207, + 206, + 107, + 39, + 211, + 3, + 249, + 110, + 181, + 213, + 226, + 8, + 86, + 220, + 109, + 2, + 238, + 178, + 14, + 73, + 220, + 71, + 154, + 117, + 39, + 91, + 206, + 255, + 13, + 33, + 33, + 108, + 205, + 67, + 123, + 158, + 112, + 34, + 128, + 17, + 89, + 100, + 138, + 245, + 42, + 115, + 77, + 118, + 178, + 127, + 20, + 117, + 126, + 228, + 149, + 235, + 45, + 74, + 124, + 220, + 204, + 172, + 16, + 205, + 124, + 120, + 235, + 143, + 17, + 130, + 165, + 255, + 153, + 178, + 83, + 9, + 13, + 239, + 101, + 164, + 251, + 62, + 194, + 198, + 54, + 187, + 152, + 6, + 137, + 105, + 51, + 91, + 66, + 114, + 119, + 122, + 146, + 199, + 94, + 43, + 195, + 197, + 127, + 249, + 46, + 230, + 131, + 61, + 200, + 38, + 11, + 87, + 61, + 3, + 16, + 27, + 68, + 176, + 152, + 114, + 94, + 58, + 54, + 123, + 139, + 137, + 126, + 56, + 20, + 111, + 156, + 150, + 147, + 193, + 137, + 198, + 243, + 41, + 194, + 11, + 108, + 126, + 2, + 64, + 172, + 250, + 0, + 28, + 193, + 252, + 107, + 98, + 15, + 40, + 194, + 186, + 194, + 71, + 198, + 45, + 76, + 63, + 88, + 35, + 23, + 242, + 166, + 216, + 37, + 83, + 59, + 66, + 51, + 249, + 47, + 212, + 95, + 229, + 199, + 58, + 167, + 147, + 92, + 211, + 159, + 74, + 197, + 86, + 64, + 25, + 197, + 71, + 2, + 30, + 141, + 176, + 107, + 189, + 30, + 109, + 133, + 79, + 66, + 224, + 3, + 198, + 49, + 59, + 100, + 39, + 109, + 171, + 122, + 252, + 36, + 72, + 218, + 159, + 42, + 225, + 241, + 194, + 132, + 156, + 130, + 187, + 57, + 13, + 244, + 139, + 33, + 53, + 228, + 105, + 175, + 193, + 31, + 204, + 113, + 3, + 119, + 19, + 21, + 59, + 195, + 26, + 59, + 72, + 68, + 249, + 86, + 160, + 85, + 136, + 225, + 57, + 5, + 129, + 168, + 196, + 163, + 53, + 127, + 118, + 128, + 247, + 71, + 67, + 9, + 31, + 106, + 54, + 175, + 201, + 122, + 151, + 139, + 225, + 107, + 136, + 125, + 210, + 228, + 212, + 28, + 214, + 191, + 81, + 23, + 253, + 62, + 173, + 122, + 92, + 249, + 134, + 126, + 81, + 114, + 13, + 254, + 207, + 96, + 35, + 20, + 177, + 251, + 59, + 47, + 220, + 176, + 54, + 153, + 178, + 182, + 74, + 74, + 250, + 185, + 147, + 6, + 230, + 84, + 36, + 146, + 170, + 102, + 45, + 30, + 105, + 118, + 88, + 6, + 7, + 61, + 57, + 112, + 15, + 87, + 245, + 62, + 101, + 168, + 9, + 52, + 92, + 107, + 216, + 240, + 185, + 139, + 82, + 54, + 17, + 209, + 215, + 57, + 136, + 54, + 223, + 235, + 105, + 7, + 38, + 79, + 83, + 72, + 96, + 119, + 28, + 0, + 86, + 139, + 222, + 197, + 87, + 90, + 18, + 189, + 219, + 85, + 227, + 255, + 48, + 78, + 73, + 157, + 88, + 56, + 64, + 140, + 21, + 151, + 209, + 176, + 81, + 65, + 82, + 24, + 204, + 95, + 183, + 195, + 79, + 117, + 189, + 196, + 218, + 26, + 207, + 203, + 76, + 201, + 122, + 140, + 14, + 105, + 26, + 60, + 40, + 213, + 28, + 12, + 7, + 102, + 106, + 208, + 60, + 159, + 123, + 17, + 207, + 172, + 29, + 169, + 22, + 177, + 111, + 0, + 51, + 179, + 181, + 208, + 0, + 82, + 139, + 194, + 68, + 24, + 83, + 126, + 160, + 14, + 103, + 75, + 32, + 116, + 24, + 76, + 220, + 104, + 22, + 49, + 196, + 88, + 28, + 163, + 105, + 150, + 64, + 64, + 125, + 102, + 92, + 17, + 156, + 36, + 153, + 219, + 38, + 160, + 212, + 190, + 238, + 8, + 254, + 189, + 71, + 122, + 15, + 149, + 199, + 195, + 145, + 104, + 248, + 180, + 200, + 189, + 73, + 230, + 162, + 209, + 15, + 51, + 81, + 221, + 48, + 8, + 126, + 74, + 54, + 38, + 175, + 197, + 22, + 213, + 75, + 248, + 52, + 154, + 151, + 102, + 203, + 109, + 58, + 115, + 87, + 127, + 170, + 254, + 8, + 224, + 235, + 45, + 18, + 104, + 76, + 50, + 238, + 241, + 237, + 2, + 97, + 214, + 91, + 2, + 203, + 162, + 216, + 115, + 41, + 199, + 203, + 8, + 160, + 222, + 98, + 36, + 200, + 227, + 92, + 23, + 236, + 33, + 229, + 209, + 20, + 235, + 119, + 19, + 91, + 222, + 216, + 152, + 151, + 139, + 229, + 125, + 185, + 141, + 5, + 40, + 57, + 56, + 199, + 248, + 60, + 4, + 11, + 64, + 103, + 255, + 149, + 74, + 128, + 11, + 27, + 201, + 135, + 62, + 107, + 235, + 157, + 5, + 164, + 113, + 89, + 123, + 66, + 175, + 180, + 150, + 51, + 149, + 15, + 18, + 52, + 191, + 111, + 247, + 219, + 46, + 19, + 108, + 78, + 195, + 248, + 252, + 167, + 195, + 196, + 100, + 73, + 62, + 18, + 254, + 115, + 165, + 115, + 254, + 66, + 240, + 41, + 59, + 4, + 12, + 109, + 47, + 247, + 27, + 141, + 183, + 202, + 56, + 161, + 14, + 151, + 169, + 251, + 7, + 121, + 208, + 87, + 217, + 235, + 200, + 50, + 212, + 99, + 104, + 189, + 226, + 111, + 64, + 131, + 83, + 143, + 198, + 208, + 42, + 238, + 244, + 7, + 50, + 170, + 36, + 253, + 101, + 48, + 224, + 111, + 175, + 78, + 132, + 46, + 103, + 31, + 217, + 76, + 53, + 241, + 66, + 255, + 67, + 24, + 170, + 238, + 202, + 207, + 185, + 50, + 44, + 94, + 30, + 179, + 37, + 214, + 112, + 181, + 219, + 44, + 35, + 234, + 52, + 133, + 170, + 108, + 184, + 100, + 150, + 140, + 62, + 94, + 39, + 91, + 186, + 88, + 195, + 112, + 3, + 127, + 73, + 101, + 136, + 20, + 212, + 28, + 55, + 205, + 33, + 84, + 173, + 80, + 80, + 178, + 134, + 133, + 193, + 67, + 184, + 71, + 156, + 251, + 22, + 72, + 96, + 244, + 29, + 4, + 231, + 51, + 60, + 221, + 197, + 224, + 3, + 77, + 152, + 127, + 44, + 242, + 23, + 201, + 150, + 32, + 170, + 139, + 91, + 208, + 226, + 233, + 99, + 81, + 118, + 238, + 42, + 128, + 209, + 224, + 251, + 150, + 48, + 20, + 103, + 179, + 60, + 218, + 96, + 176, + 4, + 233, + 208, + 8, + 73, + 180, + 33, + 65, + 254, + 121, + 155, + 242, + 146, + 129, + 71, + 21, + 56, + 63, + 223, + 17, + 127, + 8, + 202, + 68, + 19, + 142, + 141, + 183, + 77, + 10, + 72, + 103, + 49, + 3, + 80, + 11, + 75, + 140, + 252, + 23, + 89, + 250, + 1, + 252, + 120, + 157, + 162, + 114, + 78, + 30, + 143, + 65, + 152, + 84, + 197, + 215, + 111, + 193, + 33, + 81, + 102, + 121, + 72, + 38, + 14, + 47, + 115, + 226, + 83, + 53, + 220, + 11, + 114, + 82, + 78, + 253, + 239, + 194, + 229, + 152, + 84, + 173, + 192, + 62, + 134, + 119, + 69, + 238, + 17, + 121, + 85, + 224, + 173, + 166, + 76, + 48, + 148, + 22, + 9, + 250, + 31, + 53, + 179, + 228, + 44, + 124, + 167, + 137, + 242, + 56, + 220, + 218, + 25, + 138, + 108, + 237, + 82, + 129, + 95, + 140, + 93, + 192, + 207, + 144, + 252, + 134, + 89, + 101, + 134, + 169, + 109, + 93, + 10, + 218, + 225, + 92, + 83, + 194, + 109, + 141, + 219, + 151, + 60, + 208, + 129, + 142, + 69, + 153, + 27, + 130, + 81, + 215, + 34, + 116, + 127, + 15, + 150, + 224, + 41, + 208, + 234, + 92, + 39, + 82, + 88, + 57, + 201, + 91, + 228, + 60, + 47, + 235, + 98, + 221, + 26, + 116, + 141, + 252, + 242, + 116, + 240, + 203, + 133, + 26, + 196, + 83, + 43, + 195, + 243, + 184, + 239, + 228, + 149, + 183, + 207, + 234, + 9, + 251, + 70, + 126, + 34, + 207, + 43, + 191, + 160, + 138, + 162, + 125, + 214, + 4, + 39, + 49, + 194, + 43, + 142, + 84, + 79, + 101, + 93, + 3, + 61, + 45, + 144, + 43, + 174, + 211, + 40, + 136, + 10, + 74, + 67, + 200, + 77, + 4, + 57, + 128, + 212, + 150, + 230, + 17, + 69, + 150, + 226, + 111, + 69, + 74, + 78, + 27, + 246, + 15, + 162, + 229, + 128, + 226, + 250, + 180, + 97, + 101, + 152, + 178, + 78, + 150, + 158, + 211, + 158, + 117, + 114, + 69, + 32, + 151, + 28, + 173, + 129, + 220, + 75, + 64, + 180, + 145, + 79, + 122, + 163, + 105, + 165, + 147, + 195, + 50, + 144, + 103, + 83, + 59, + 81, + 8, + 23, + 119, + 46, + 48, + 245, + 82, + 214, + 121, + 200, + 86, + 21, + 84, + 58, + 212, + 151, + 252, + 50, + 124, + 241, + 106, + 31, + 80, + 135, + 53, + 87, + 85, + 164, + 12, + 80, + 5, + 83, + 226, + 24, + 218, + 231, + 137, + 100, + 129, + 125, + 192, + 229, + 45, + 205, + 190, + 124, + 105, + 51, + 244, + 54, + 211, + 189, + 255, + 94, + 147, + 180, + 70, + 148, + 46, + 142, + 198, + 128, + 180, + 64, + 24, + 105, + 90, + 241, + 130, + 156, + 46, + 132, + 66, + 97, + 167, + 55, + 209, + 173, + 180, + 203, + 122, + 55, + 56, + 17, + 85, + 198, + 11, + 67, + 195, + 46, + 49, + 188, + 6, + 48, + 211, + 156, + 34, + 19, + 1, + 31, + 136, + 154, + 240, + 16, + 122, + 210, + 70, + 133, + 161, + 151, + 166, + 5, + 37, + 109, + 56, + 197, + 74, + 155, + 203, + 224, + 175, + 46, + 247, + 223, + 177, + 52, + 161, + 226, + 44, + 52, + 95, + 6, + 238, + 255, + 145, + 5, + 8, + 32, + 133, + 85, + 173, + 32, + 74, + 124, + 17, + 212, + 132, + 142, + 3, + 184, + 112, + 121, + 116, + 61, + 164, + 26, + 177, + 243, + 6, + 16, + 11, + 109, + 223, + 211, + 240, + 24, + 251, + 153, + 190, + 112, + 56, + 33, + 121, + 6, + 96, + 22, + 45, + 128, + 60, + 232, + 114, + 108, + 30, + 56, + 211, + 94, + 219, + 174, + 198, + 139, + 226, + 144, + 22, + 25, + 56, + 99, + 255, + 237, + 98, + 240, + 95, + 184, + 239, + 109, + 38, + 158, + 8, + 165, + 228, + 49, + 115, + 118, + 52, + 130, + 212, + 162, + 141, + 205, + 200, + 141, + 220, + 0, + 44, + 16, + 102, + 65, + 40, + 1, + 237, + 8, + 233, + 74, + 197, + 54, + 14, + 7, + 137, + 8, + 34, + 141, + 59, + 23, + 185, + 72, + 21, + 58, + 60, + 118, + 222, + 7, + 86, + 168, + 157, + 39, + 185, + 100, + 242, + 15, + 121, + 44, + 158, + 168, + 250, + 3, + 189, + 199, + 158, + 29, + 183, + 13, + 197, + 158, + 213, + 177, + 142, + 215, + 222, + 61, + 204, + 104, + 17, + 179, + 207, + 150, + 139, + 121, + 175, + 65, + 71, + 95, + 5, + 199, + 69, + 251, + 43, + 252, + 171, + 241, + 101, + 228, + 15, + 249, + 34, + 197, + 44, + 36, + 2, + 187, + 247, + 49, + 61, + 133, + 114, + 157, + 96, + 25, + 154, + 168, + 73, + 244, + 241, + 111, + 149, + 11, + 227, + 224, + 142, + 114, + 128, + 156, + 166, + 158, + 170, + 69, + 150, + 130, + 158, + 188, + 109, + 134, + 59, + 4, + 218, + 111, + 23, + 61, + 17, + 208, + 214, + 174, + 72, + 63, + 211, + 14, + 19, + 210, + 254, + 100, + 18, + 105, + 45, + 111, + 4, + 82, + 226, + 203, + 177, + 197, + 107, + 164, + 56, + 66, + 26, + 108, + 65, + 219, + 71, + 87, + 49, + 193, + 83, + 213, + 248, + 81, + 122, + 90, + 140, + 234, + 78, + 134, + 208, + 9, + 204, + 50, + 148, + 109, + 108, + 229, + 232, + 36, + 110, + 129, + 124, + 65, + 121, + 202, + 57, + 162, + 98, + 104, + 236, + 207, + 61, + 29, + 162, + 108, + 200, + 101, + 87, + 88, + 180, + 165, + 175, + 152, + 29, + 181, + 203, + 50, + 69, + 34, + 245, + 110, + 170, + 163, + 255, + 35, + 18, + 5, + 7, + 41, + 58, + 77, + 195, + 49, + 90, + 152, + 159, + 141, + 205, + 89, + 66, + 21, + 218, + 115, + 50, + 161, + 39, + 22, + 126, + 189, + 89, + 62, + 224, + 41, + 106, + 132, + 141, + 199, + 169, + 166, + 247, + 86, + 142, + 209, + 218, + 194, + 153, + 15, + 164, + 37, + 200, + 52, + 252, + 161, + 136, + 2, + 24, + 254, + 11, + 70, + 181, + 252, + 112, + 147, + 81, + 161, + 134, + 36, + 62, + 159, + 216, + 35, + 246, + 171, + 149, + 129, + 148, + 1, + 64, + 109, + 51, + 136, + 122, + 45, + 167, + 238, + 149, + 198, + 56, + 116, + 238, + 172, + 113, + 227, + 43, + 213, + 161, + 72, + 171, + 27, + 55, + 13, + 46, + 188, + 249, + 27, + 175, + 239, + 139, + 92, + 1, + 244, + 231, + 221, + 194, + 80, + 148, + 19, + 79, + 87, + 113, + 170, + 87, + 20, + 66, + 50, + 30, + 168, + 119, + 93, + 124, + 118, + 212, + 2, + 94, + 148, + 170, + 232, + 97, + 99, + 79, + 15, + 88, + 2, + 239, + 66, + 211, + 0, + 28, + 2, + 170, + 7, + 171, + 195, + 193, + 149, + 242, + 22, + 29, + 28, + 111, + 82, + 156, + 62, + 102, + 1, + 41, + 160, + 60, + 180, + 135, + 189, + 13, + 105, + 188, + 205, + 108, + 248, + 227, + 107, + 138, + 44, + 103, + 112, + 222, + 251, + 221, + 162, + 19, + 251, + 238, + 163, + 135, + 76, + 170, + 54, + 168, + 196, + 40, + 152, + 39, + 185, + 241, + 246, + 44, + 48, + 17, + 65, + 113, + 143, + 56, + 52, + 51, + 113, + 242, + 184, + 100, + 85, + 47, + 225, + 98, + 222, + 128, + 25, + 244, + 23, + 60, + 176, + 153, + 74, + 107, + 160, + 9, + 104, + 254, + 194, + 138, + 146, + 48, + 222, + 190, + 218, + 24, + 18, + 206, + 101, + 18, + 98, + 88, + 112, + 145, + 227, + 132, + 245, + 25, + 31, + 220, + 133, + 27, + 63, + 108, + 135, + 128, + 197, + 61, + 44, + 24, + 220, + 255, + 183, + 132, + 73, + 41, + 97, + 61, + 34, + 49, + 14, + 168, + 87, + 143, + 20, + 225, + 130, + 189, + 21, + 217, + 82, + 93, + 35, + 110, + 100, + 162, + 5, + 163, + 21, + 189, + 219, + 249, + 231, + 18, + 166, + 254, + 33, + 86, + 195, + 65, + 48, + 217, + 118, + 223, + 255, + 156, + 226, + 240, + 10, + 150, + 179, + 98, + 135, + 22, + 106, + 238, + 101, + 12, + 194, + 44, + 71, + 188, + 23, + 178, + 68, + 99, + 197, + 92, + 103, + 6, + 219, + 195, + 110, + 83, + 3, + 132, + 151, + 169, + 93, + 63, + 53, + 216, + 35, + 85, + 214, + 81, + 211, + 77, + 198, + 3, + 104, + 95, + 50, + 16, + 124, + 216, + 136, + 203, + 144, + 234, + 124, + 46, + 154, + 123, + 17, + 72, + 124, + 146, + 223, + 170, + 109, + 35, + 6, + 126, + 53, + 25, + 15, + 167, + 67, + 19, + 199, + 104, + 37, + 140, + 210, + 143, + 73, + 136, + 195, + 248, + 255, + 165, + 219, + 77, + 60, + 214, + 53, + 250, + 152, + 1, + 202, + 117, + 82, + 115, + 106, + 250, + 47, + 133, + 114, + 222, + 114, + 170, + 114, + 181, + 69, + 63, + 251, + 40, + 115, + 24, + 42, + 18, + 8, + 98, + 57, + 246, + 211, + 2, + 34, + 30, + 100, + 186, + 25, + 221, + 255, + 204, + 60, + 54, + 34, + 23, + 60, + 202, + 172, + 71, + 109, + 116, + 57, + 218, + 168, + 13, + 31, + 11, + 62, + 192, + 86, + 86, + 11, + 120, + 96, + 138, + 112, + 165, + 1, + 37, + 61, + 68, + 6, + 15, + 219, + 5, + 149, + 195, + 239, + 212, + 237, + 4, + 119, + 220, + 196, + 124, + 123, + 2, + 171, + 68, + 97, + 14, + 138, + 138, + 49, + 5, + 138, + 76, + 109, + 8, + 162, + 101, + 123, + 126, + 1, + 227, + 244, + 21, + 100, + 237, + 13, + 88, + 208, + 251, + 245, + 236, + 111, + 131, + 115, + 185, + 13, + 190, + 136, + 191, + 65, + 96, + 109, + 28, + 21, + 55, + 47, + 128, + 159, + 88, + 47, + 6, + 153, + 186, + 125, + 6, + 69, + 52, + 124, + 153, + 192, + 131, + 250, + 188, + 67, + 157, + 145, + 198, + 144, + 210, + 71, + 252, + 83, + 219, + 131, + 12, + 246, + 162, + 32, + 224, + 83, + 148, + 255, + 62, + 238, + 167, + 155, + 78, + 70, + 99, + 94, + 177, + 126, + 226, + 167, + 62, + 183, + 145, + 15, + 112, + 75, + 243, + 147, + 216, + 162, + 185, + 84, + 219, + 6, + 48, + 74, + 75, + 223, + 16, + 220, + 44, + 6, + 212, + 119, + 159, + 76, + 82, + 250, + 211, + 175, + 20, + 65, + 194, + 8, + 130, + 25, + 14, + 250, + 97, + 125, + 4, + 148, + 17, + 122, + 209, + 223, + 230, + 94, + 216, + 241, + 209, + 93, + 180, + 57, + 251, + 122, + 36, + 233, + 27, + 244, + 138, + 148, + 97, + 39, + 20, + 0, + 95, + 169, + 44, + 116, + 251, + 166, + 162, + 138, + 20, + 178, + 113, + 177, + 46, + 110, + 46, + 57, + 82, + 228, + 87, + 83, + 231, + 117, + 153, + 27, + 66, + 70, + 85, + 254, + 78, + 25, + 217, + 17, + 157, + 205, + 41, + 224, + 62, + 61, + 141, + 203, + 244, + 123, + 136, + 143, + 226, + 7, + 120, + 26, + 142, + 181, + 161, + 214, + 50, + 173, + 84, + 214, + 108, + 234, + 114, + 117, + 122, + 94, + 220, + 43, + 101, + 172, + 193, + 14, + 252, + 164, + 184, + 157, + 253, + 60, + 11, + 187, + 31, + 60, + 164, + 98, + 9, + 166, + 209, + 84, + 133, + 210, + 92, + 253, + 222, + 216, + 129, + 208, + 165, + 225, + 254, + 183, + 111, + 184, + 143, + 150, + 75, + 254, + 167, + 55, + 24, + 134, + 51, + 7, + 142, + 88, + 173, + 254, + 126, + 170, + 84, + 159, + 136, + 187, + 140, + 138, + 165, + 105, + 40, + 163, + 224, + 58, + 184, + 177, + 39, + 97, + 99, + 181, + 31, + 196, + 162, + 34, + 41, + 217, + 242, + 29, + 182, + 11, + 134, + 147, + 216, + 163, + 213, + 162, + 104, + 251, + 31, + 68, + 230, + 110, + 73, + 218, + 171, + 230, + 130, + 189, + 53, + 73, + 132, + 247, + 240, + 32, + 7, + 26, + 31, + 134, + 106, + 207, + 96, + 37, + 243, + 160, + 199, + 205, + 233, + 64, + 48, + 153, + 77, + 62, + 22, + 83, + 245, + 241, + 215, + 55, + 1, + 197, + 18, + 157, + 17, + 58, + 253, + 19, + 142, + 174, + 16, + 184, + 39, + 208, + 0, + 109, + 98, + 232, + 162, + 174, + 91, + 9, + 50, + 137, + 193, + 226, + 220, + 247, + 185, + 46, + 151, + 100, + 134, + 67, + 1, + 95, + 210, + 162, + 132, + 90, + 91, + 162, + 147, + 73, + 212, + 22, + 45, + 109, + 94, + 109, + 129, + 89, + 102, + 103, + 181, + 55, + 45, + 32, + 12, + 8, + 71, + 195, + 143, + 199, + 123, + 220, + 23, + 160, + 15, + 230, + 91, + 3, + 61, + 231, + 142, + 132, + 189, + 17, + 40, + 101, + 170, + 176, + 0, + 67, + 89, + 210, + 129, + 114, + 24, + 202, + 187, + 4, + 247, + 172, + 14, + 53, + 201, + 162, + 246, + 68, + 70, + 65, + 233, + 140, + 160, + 79, + 95, + 11, + 188, + 25, + 197, + 19, + 121, + 22, + 90, + 16, + 4, + 213, + 253, + 143, + 198, + 100, + 196, + 160, + 13, + 193, + 218, + 211, + 142, + 66, + 221, + 132, + 169, + 162, + 188, + 36, + 251, + 237, + 68, + 223, + 104, + 253, + 116, + 107, + 43, + 241, + 180, + 226, + 29, + 93, + 11, + 120, + 92, + 57, + 90, + 245, + 45, + 68, + 31, + 172, + 15, + 152, + 105, + 149, + 47, + 123, + 222, + 92, + 154, + 24, + 228, + 197, + 242, + 129, + 68, + 26, + 194, + 175, + 246, + 249, + 55, + 57, + 35, + 114, + 179, + 75, + 173, + 159, + 63, + 15, + 55, + 92, + 71, + 212, + 250, + 177, + 255, + 211, + 201, + 99, + 11, + 194, + 183, + 127, + 114, + 145, + 59, + 23, + 1, + 155, + 148, + 244, + 196, + 105, + 95, + 173, + 252, + 149, + 168, + 62, + 196, + 163, + 97, + 244, + 243, + 213, + 75, + 182, + 188, + 189, + 188, + 105, + 104, + 227, + 66, + 200, + 183, + 220, + 246, + 5, + 6, + 238, + 225, + 39, + 175, + 235, + 155, + 189, + 136, + 87, + 36, + 65, + 6, + 116, + 244, + 148, + 172, + 240, + 239, + 206, + 46, + 209, + 23, + 173, + 220, + 17, + 244, + 120, + 134, + 5, + 82, + 16, + 182, + 151, + 30, + 243, + 164, + 115, + 59, + 164, + 85, + 156, + 75, + 83, + 110, + 226, + 69, + 168, + 191, + 133, + 203, + 20, + 162, + 51, + 196, + 148, + 249, + 169, + 129, + 233, + 215, + 76, + 172, + 1, + 28, + 126, + 87, + 134, + 246, + 192, + 198, + 31, + 62, + 226, + 61, + 88, + 154, + 14, + 85, + 227, + 59, + 175, + 155, + 170, + 4, + 134, + 38, + 233, + 217, + 179, + 42, + 226, + 199, + 195, + 57, + 93, + 138, + 147, + 147, + 180, + 165, + 4, + 31, + 11, + 158, + 195, + 80, + 143, + 63, + 136, + 15, + 42, + 174, + 10, + 129, + 137, + 225, + 72, + 125, + 176, + 166, + 231, + 255, + 74, + 38, + 252, + 104, + 15, + 84, + 247, + 83, + 18, + 36, + 62, + 13, + 212, + 226, + 27, + 142, + 37, + 38, + 152, + 96, + 140, + 143, + 81, + 247, + 6, + 66, + 72, + 60, + 255, + 11, + 242, + 21, + 206, + 102, + 122, + 250, + 113, + 176, + 185, + 129, + 64, + 200, + 120, + 129, + 229, + 175, + 99, + 165, + 170, + 251, + 108, + 9, + 182, + 159, + 129, + 65, + 123, + 37, + 10, + 243, + 224, + 231, + 74, + 201, + 214, + 85, + 163, + 230, + 34, + 141, + 130, + 243, + 50, + 189, + 2, + 23, + 129, + 95, + 227, + 89, + 17, + 70, + 246, + 247, + 26, + 99, + 80, + 202, + 254, + 74, + 168, + 245, + 162, + 56, + 230, + 208, + 10, + 251, + 80, + 195, + 20, + 190, + 217, + 113, + 175, + 18, + 139, + 186, + 179, + 78, + 172, + 73, + 70, + 113, + 66, + 245, + 132, + 94, + 213, + 220, + 176, + 192, + 245, + 77, + 66, + 198, + 90, + 232, + 211, + 171, + 106, + 173, + 45, + 86, + 76, + 133, + 144, + 241, + 104, + 224, + 81, + 212, + 67, + 30, + 178, + 5, + 64, + 70, + 158, + 12, + 239, + 132, + 178, + 215, + 230, + 49, + 147, + 221, + 87, + 189, + 193, + 100, + 234, + 64, + 10, + 43, + 110, + 71, + 217, + 63, + 218, + 197, + 5, + 66, + 30, + 28, + 208, + 191, + 124, + 19, + 167, + 213, + 17, + 180, + 203, + 157, + 197, + 110, + 138, + 229, + 188, + 156, + 100, + 4, + 152, + 208, + 40, + 252, + 178, + 230, + 11, + 121, + 173, + 191, + 53, + 195, + 204, + 155, + 234, + 2, + 247, + 198, + 75, + 151, + 75, + 211, + 222, + 72, + 103, + 251, + 62, + 173, + 236, + 118, + 15, + 227, + 211, + 202, + 20, + 217, + 150, + 121, + 239, + 102, + 14, + 67, + 28, + 56, + 10, + 165, + 43, + 214, + 173, + 184, + 249, + 217, + 159, + 163, + 189, + 140, + 165, + 144, + 141, + 140, + 253, + 20, + 54, + 242, + 86, + 106, + 79, + 226, + 145, + 54, + 191, + 155, + 110, + 154, + 231, + 58, + 14, + 39, + 179, + 184, + 140, + 83, + 40, + 87, + 157, + 147, + 19, + 73, + 8, + 165, + 135, + 128, + 171, + 209, + 87, + 182, + 186, + 240, + 48, + 157, + 231, + 151, + 0, + 79, + 48, + 96, + 237, + 3, + 102, + 193, + 102, + 107, + 79, + 198, + 60, + 101, + 192, + 238, + 98, + 49, + 214, + 239, + 64, + 69, + 205, + 141, + 128, + 32, + 201, + 173, + 28, + 22, + 255, + 55, + 181, + 189, + 30, + 113, + 189, + 70, + 63, + 175, + 195, + 118, + 161, + 19, + 34, + 86, + 37, + 66, + 153, + 160, + 210, + 174, + 180, + 7, + 30, + 130, + 204, + 164, + 12, + 176, + 51, + 143, + 213, + 204, + 190, + 170, + 10, + 70, + 4, + 169, + 100, + 78, + 90, + 238, + 195, + 159, + 104, + 144, + 141, + 26, + 226, + 118, + 42, + 124, + 146, + 232, + 93, + 56, + 144, + 211, + 150, + 116, + 51, + 29, + 170, + 82, + 11, + 65, + 147, + 177, + 174, + 143, + 122, + 202, + 2, + 135, + 44, + 194, + 195, + 198, + 243, + 78, + 11, + 52, + 205, + 40, + 102, + 220, + 81, + 201, + 121, + 21, + 237, + 235, + 74, + 3, + 254, + 156, + 71, + 175, + 221, + 228, + 52, + 113, + 35, + 228, + 203, + 146, + 106, + 73, + 168, + 135, + 31, + 139, + 142, + 112, + 10, + 178, + 195, + 239, + 123, + 21, + 148, + 55, + 248, + 32, + 32, + 144, + 223, + 195, + 28, + 83, + 169, + 98, + 247, + 55, + 107, + 115, + 248, + 122, + 242, + 216, + 139, + 190, + 71, + 170, + 135, + 235, + 65, + 9, + 250, + 6, + 107, + 45, + 40, + 165, + 172, + 136, + 32, + 204, + 204, + 34, + 86, + 211, + 112, + 13, + 160, + 131, + 114, + 57, + 22, + 6, + 43, + 126, + 164, + 197, + 178, + 189, + 68, + 108, + 20, + 143, + 147, + 170, + 224, + 92, + 165, + 220, + 10, + 20, + 48, + 93, + 50, + 44, + 132, + 50, + 31, + 104, + 9, + 111, + 224, + 191, + 215, + 213, + 165, + 150, + 137, + 39, + 97, + 104, + 131, + 128, + 88, + 149, + 157, + 158, + 109, + 223, + 240, + 161, + 105, + 122, + 81, + 36, + 155, + 105, + 121, + 238, + 240, + 32, + 15, + 211, + 253, + 223, + 210, + 0, + 223, + 108, + 85, + 125, + 67, + 78, + 8, + 67, + 140, + 160, + 228, + 249, + 191, + 137, + 241, + 193, + 15, + 80, + 89, + 124, + 110, + 215, + 133, + 21, + 21, + 11, + 92, + 4, + 3, + 148, + 66, + 33, + 181, + 201, + 181, + 99, + 182, + 177, + 210, + 23, + 72, + 7, + 97, + 139, + 23, + 32, + 235, + 197, + 68, + 203, + 62, + 205, + 220, + 203, + 193, + 139, + 194, + 249, + 35, + 57, + 218, + 240, + 143, + 99, + 136, + 148, + 115, + 170, + 90, + 225, + 15, + 100, + 212, + 39, + 187, + 82, + 27, + 193, + 254, + 157, + 50, + 50, + 103, + 120, + 100, + 57, + 9, + 163, + 60, + 253, + 224, + 86, + 16, + 98, + 154, + 156, + 159, + 82, + 61, + 237, + 149, + 217, + 106, + 201, + 45, + 50, + 108, + 255, + 4, + 49, + 115, + 3, + 162, + 181, + 49, + 221, + 69, + 161, + 41, + 204, + 123, + 44, + 104, + 43, + 115, + 30, + 205, + 242, + 205, + 7, + 251, + 119, + 248, + 10, + 19, + 85, + 30, + 109, + 30, + 150, + 140, + 214, + 61, + 175, + 38, + 22, + 101, + 45, + 197, + 251, + 80, + 246, + 130, + 22, + 235, + 122, + 167, + 84, + 0, + 5, + 91, + 242, + 123, + 89, + 113, + 64, + 48, + 191, + 216, + 195, + 172, + 42, + 65, + 233, + 234, + 60, + 58, + 234, + 23, + 230, + 167, + 208, + 192, + 245, + 246, + 39, + 10, + 218, + 111, + 14, + 252, + 60, + 87, + 248, + 80, + 53, + 204, + 139, + 135, + 135, + 198, + 63, + 39, + 150, + 251, + 246, + 161, + 92, + 179, + 45, + 85, + 253, + 128, + 113, + 147, + 237, + 101, + 33, + 157, + 2, + 134, + 76, + 79, + 61, + 36, + 166, + 79, + 165, + 59, + 214, + 254, + 145, + 163, + 3, + 234, + 62, + 172, + 49, + 106, + 218, + 253, + 70, + 20, + 106, + 177, + 72, + 97, + 108, + 74, + 152, + 20, + 93, + 148, + 149, + 244, + 46, + 243, + 183, + 147, + 4, + 179, + 233, + 76, + 220, + 126, + 255, + 90, + 29, + 121, + 4, + 21, + 99, + 222, + 247, + 75, + 130, + 142, + 238, + 137, + 171, + 178, + 111, + 7, + 162, + 168, + 185, + 124, + 98, + 76, + 6, + 178, + 52, + 76, + 200, + 147, + 246, + 101, + 50, + 147, + 79, + 80, + 123, + 83, + 22, + 25, + 129, + 82, + 190, + 158, + 22, + 34, + 242, + 48, + 230, + 135, + 130, + 141, + 241, + 117, + 158, + 35, + 14, + 101, + 76, + 191, + 143, + 121, + 120, + 165, + 236, + 201, + 60, + 213, + 206, + 133, + 237, + 147, + 190, + 19, + 48, + 196, + 175, + 73, + 208, + 63, + 114, + 160, + 191, + 231, + 17, + 46, + 161, + 159, + 192, + 213, + 166, + 198, + 129, + 248, + 154, + 195, + 160, + 58, + 124, + 210, + 162, + 160, + 24, + 156, + 63, + 61, + 239, + 132, + 147, + 108, + 45, + 79, + 29, + 83, + 61, + 108, + 100, + 16, + 219, + 22, + 138, + 53, + 141, + 43, + 253, + 126, + 25, + 216, + 44, + 239, + 116, + 220, + 218, + 60, + 145, + 140, + 177, + 18, + 203, + 24, + 250, + 225, + 21, + 194, + 240, + 11, + 192, + 162, + 194, + 99, + 40, + 67, + 201, + 91, + 131, + 69, + 86, + 128, + 255, + 47, + 160, + 93, + 230, + 50, + 245, + 209, + 236, + 149, + 88, + 66, + 78, + 43, + 120, + 240, + 183, + 100, + 160, + 109, + 172, + 54, + 40, + 202, + 39, + 221, + 158, + 77, + 93, + 162, + 82, + 157, + 156, + 165, + 172, + 37, + 200, + 10, + 140, + 247, + 117, + 241, + 252, + 99, + 238, + 47, + 109, + 144, + 39, + 35, + 5, + 174, + 200, + 208, + 200, + 75, + 188, + 219, + 132, + 230, + 247, + 20, + 201, + 206, + 194, + 23, + 90, + 235, + 148, + 109, + 144, + 44, + 250, + 219, + 45, + 11, + 239, + 188, + 196, + 89, + 12, + 255, + 190, + 159, + 176, + 136, + 52, + 130, + 170, + 0, + 56, + 216, + 48, + 205, + 39, + 112, + 31, + 58, + 199, + 111, + 119, + 170, + 215, + 183, + 83, + 45, + 214, + 45, + 62, + 203, + 225, + 216, + 245, + 128, + 166, + 253, + 227, + 155, + 92, + 11, + 52, + 42, + 176, + 34, + 233, + 170, + 132, + 0, + 79, + 154, + 23, + 113, + 179, + 196, + 111, + 36, + 80, + 52, + 15, + 32, + 251, + 163, + 21, + 32, + 172, + 243, + 98, + 63, + 75, + 247, + 26, + 184, + 235, + 197, + 72, + 83, + 34, + 156, + 204, + 40, + 130, + 3, + 231, + 99, + 106, + 213, + 65, + 93, + 128, + 232, + 107, + 45, + 71, + 160, + 41, + 53, + 163, + 133, + 4, + 44, + 194, + 49, + 65, + 118, + 246, + 109, + 220, + 234, + 245, + 110, + 136, + 162, + 222, + 235, + 109, + 78, + 31, + 88, + 177, + 178, + 69, + 235, + 244, + 102, + 227, + 143, + 20, + 16, + 27, + 115, + 78, + 22, + 163, + 78, + 147, + 86, + 193, + 147, + 79, + 251, + 84, + 104, + 177, + 88, + 57, + 111, + 97, + 39, + 220, + 218, + 0, + 28, + 91, + 43, + 111, + 30, + 237, + 101, + 217, + 58, + 28, + 137, + 219, + 224, + 239, + 119, + 111, + 170, + 239, + 127, + 138, + 66, + 168, + 137, + 49, + 119, + 73, + 37, + 196, + 103, + 161, + 151, + 70, + 123, + 158, + 224, + 172, + 109, + 242, + 82, + 68, + 87, + 132, + 179, + 95, + 128, + 131, + 15, + 153, + 229, + 206, + 75, + 6, + 114, + 132, + 20, + 147, + 153, + 63, + 71, + 142, + 209, + 121, + 26, + 78, + 182, + 195, + 79, + 133, + 58, + 251, + 171, + 182, + 39, + 148, + 68, + 73, + 252, + 179, + 142, + 44, + 190, + 187, + 162, + 210, + 247, + 198, + 64, + 249, + 54, + 188, + 60, + 49, + 48, + 147, + 216, + 63, + 176, + 187, + 172, + 41, + 82, + 105, + 52, + 225, + 106, + 72, + 154, + 55, + 9, + 174, + 34, + 47, + 131, + 48, + 79, + 149, + 200, + 208, + 165, + 213, + 217, + 14, + 160, + 184, + 79, + 197, + 53, + 97, + 6, + 23, + 211, + 4, + 97, + 236, + 229, + 55, + 101, + 16, + 126, + 41, + 200, + 69, + 74, + 128, + 138, + 16, + 162, + 64, + 219, + 131, + 31, + 84, + 51, + 246, + 169, + 176, + 157, + 60, + 79, + 51, + 249, + 203, + 84, + 246, + 89, + 109, + 63, + 135, + 161, + 104, + 67, + 112, + 78, + 255, + 56, + 178, + 1, + 59, + 16, + 157, + 217, + 46, + 9, + 250, + 63, + 229, + 191, + 29, + 179, + 213, + 190, + 197, + 206, + 156, + 164, + 232, + 80, + 169, + 90, + 110, + 128, + 160, + 251, + 226, + 234, + 171, + 182, + 52, + 172, + 112, + 72, + 14, + 136, + 211, + 40, + 239, + 91, + 15, + 138, + 33, + 15, + 128, + 132, + 250, + 113, + 205, + 220, + 27, + 34, + 109, + 249, + 73, + 173, + 83, + 30, + 36, + 115, + 127, + 25, + 129, + 35, + 165, + 229, + 136, + 170, + 211, + 204, + 165, + 180, + 180, + 241, + 197, + 82, + 61, + 158, + 157, + 167, + 101, + 17, + 179, + 3, + 141, + 17, + 107, + 213, + 144, + 131, + 108, + 115, + 175, + 103, + 60, + 51, + 22, + 19, + 38, + 63, + 231, + 43, + 182, + 33, + 197, + 167, + 23, + 101, + 169, + 62, + 114, + 253, + 98, + 146, + 228, + 5, + 229, + 71, + 117, + 98, + 246, + 58, + 219, + 123, + 241, + 198, + 79, + 120, + 98, + 235, + 182, + 124, + 82, + 249, + 164, + 21, + 188, + 185, + 46, + 63, + 182, + 115, + 133, + 121, + 139, + 142, + 13, + 7, + 148, + 97, + 116, + 0, + 116, + 126, + 225, + 109, + 149, + 20, + 116, + 104, + 1, + 245, + 135, + 126, + 164, + 45, + 85, + 171, + 38, + 183, + 243, + 155, + 120, + 197, + 84, + 11, + 161, + 149, + 90, + 108, + 236, + 102, + 220, + 128, + 253, + 158, + 73, + 61, + 13, + 22, + 92, + 46, + 72, + 219, + 125, + 95, + 242, + 139, + 59, + 235, + 47, + 145, + 29, + 98, + 37, + 27, + 130, + 101, + 177, + 33, + 7, + 30, + 100, + 16, + 26, + 17, + 152, + 191, + 130, + 198, + 101, + 184, + 84, + 164, + 209, + 36, + 38, + 159, + 214, + 18, + 57, + 63, + 139, + 85, + 139, + 150, + 6, + 237, + 144, + 2, + 112, + 127, + 109, + 45, + 235, + 184, + 227, + 109, + 18, + 5, + 25, + 180, + 136, + 139, + 162, + 241, + 80, + 216, + 49, + 198, + 22, + 68, + 130, + 116, + 135, + 129, + 103, + 48, + 247, + 251, + 177, + 154, + 248, + 146, + 227, + 106, + 214, + 237, + 7, + 110, + 173, + 25, + 86, + 168, + 54, + 68, + 231, + 175, + 210, + 120, + 73, + 229, + 170, + 94, + 148, + 90, + 149, + 160, + 199, + 126, + 234, + 208, + 147, + 76, + 99, + 25, + 67, + 60, + 7, + 195, + 110, + 31, + 187, + 228, + 160, + 181, + 200, + 38, + 112, + 238, + 97, + 183, + 88, + 73, + 166, + 133, + 105, + 187, + 58, + 8, + 98, + 82, + 174, + 225, + 35, + 169, + 39, + 48, + 110, + 42, + 214, + 30, + 201, + 133, + 121, + 248, + 74, + 154, + 56, + 119, + 30, + 102, + 172, + 221, + 218, + 211, + 96, + 62, + 145, + 156, + 231, + 107, + 38, + 104, + 188, + 31, + 206, + 126, + 217, + 117, + 239, + 96, + 143, + 179, + 43, + 63, + 58, + 210, + 125, + 5, + 127, + 179, + 102, + 191, + 237, + 172, + 223, + 65, + 69, + 192, + 76, + 146, + 180, + 44, + 226, + 28, + 137, + 35, + 193, + 185, + 201, + 147, + 103, + 68, + 242, + 211, + 136, + 58, + 166, + 41, + 221, + 222, + 144, + 202, + 227, + 249, + 97, + 197, + 196, + 201, + 131, + 13, + 158, + 175, + 211, + 63, + 161, + 170, + 157, + 222, + 145, + 142, + 233, + 111, + 76, + 40, + 96, + 231, + 231, + 153, + 164, + 211, + 230, + 70, + 169, + 110, + 140, + 231, + 207, + 21, + 216, + 134, + 45, + 198, + 127, + 84, + 22, + 29, + 224, + 252, + 179, + 138, + 92, + 55, + 139, + 123, + 88, + 80, + 85, + 27, + 115, + 226, + 108, + 18, + 76, + 9, + 162, + 224, + 214, + 223, + 186, + 111, + 111, + 123, + 129, + 24, + 130, + 78, + 30, + 144, + 47, + 42, + 3, + 238, + 1, + 177, + 32, + 136, + 53, + 80, + 178, + 245, + 124, + 243, + 202, + 75, + 244, + 7, + 136, + 251, + 53, + 32, + 206, + 217, + 23, + 48, + 112, + 40, + 132, + 112, + 197, + 223, + 135, + 199, + 103, + 210, + 27, + 125, + 46, + 225, + 13, + 34, + 236, + 239, + 184, + 97, + 44, + 9, + 233, + 198, + 107, + 111, + 190, + 239, + 7, + 60, + 79, + 57, + 252, + 142, + 37, + 27, + 227, + 114, + 182, + 78, + 122, + 164, + 189, + 50, + 128, + 208, + 31, + 24, + 192, + 210, + 168, + 159, + 255, + 7, + 206, + 213, + 11, + 126, + 49, + 30, + 247, + 220, + 242, + 93, + 197, + 159, + 170, + 39, + 164, + 174, + 254, + 90, + 178, + 8, + 58, + 141, + 215, + 228, + 88, + 68, + 234, + 213, + 27, + 4, + 154, + 18, + 223, + 27, + 241, + 252, + 83, + 72, + 34, + 109, + 158, + 214, + 27, + 58, + 187, + 13, + 162, + 212, + 175, + 154, + 221, + 35, + 144, + 110, + 246, + 245, + 202, + 85, + 240, + 87, + 195, + 115, + 1, + 126, + 105, + 242, + 93, + 127, + 247, + 186, + 72, + 35, + 167, + 151, + 191, + 27, + 33, + 95, + 16, + 214, + 22, + 179, + 20, + 247, + 20, + 129, + 225, + 61, + 87, + 13, + 144, + 203, + 193, + 20, + 98, + 105, + 11, + 88, + 109, + 128, + 32, + 244, + 161, + 217, + 132, + 84, + 110, + 212, + 215, + 49, + 142, + 153, + 13, + 35, + 126, + 127, + 82, + 220, + 19, + 228, + 136, + 93, + 170, + 153, + 29, + 61, + 112, + 90, + 150, + 177, + 174, + 162, + 144, + 8, + 174, + 4, + 139, + 130, + 86, + 183, + 162, + 170, + 60, + 101, + 212, + 41, + 14, + 43, + 237, + 85, + 68, + 99, + 240, + 74, + 47, + 242, + 190, + 13, + 54, + 83, + 64, + 130, + 232, + 35, + 12, + 124, + 206, + 64, + 151, + 230, + 246, + 112, + 135, + 228, + 45, + 197, + 88, + 133, + 175, + 145, + 190, + 204, + 153, + 215, + 112, + 59, + 116, + 186, + 234, + 91, + 79, + 203, + 150, + 180, + 194, + 47, + 101, + 245, + 65, + 182, + 203, + 185, + 189, + 104, + 173, + 157, + 139, + 142, + 151, + 253, + 109, + 141, + 98, + 69, + 156, + 194, + 99, + 64, + 94, + 16, + 226, + 3, + 129, + 159, + 150, + 225, + 125, + 128, + 77, + 62, + 69, + 126, + 178, + 29, + 30, + 89, + 17, + 4, + 112, + 73, + 227, + 224, + 17, + 135, + 253, + 40, + 146, + 105, + 235, + 3, + 33, + 204, + 14, + 26, + 79, + 103, + 161, + 114, + 161, + 135, + 45, + 233, + 206, + 53, + 36, + 120, + 155, + 115, + 18, + 85, + 210, + 88, + 150, + 176, + 170, + 208, + 149, + 106, + 19, + 57, + 75, + 92, + 204, + 9, + 255, + 248, + 101, + 124, + 93, + 224, + 204, + 92, + 217, + 237, + 3, + 48, + 10, + 90, + 92, + 134, + 227, + 31, + 47, + 47, + 213, + 162, + 46, + 139, + 90, + 226, + 186, + 24, + 222, + 114, + 41, + 133, + 233, + 235, + 48, + 77, + 252, + 63, + 15, + 66, + 102, + 47, + 84, + 25, + 75, + 204, + 97, + 11, + 240, + 192, + 169, + 154, + 81, + 150, + 68, + 98, + 69, + 208, + 89, + 113, + 30, + 5, + 135, + 196, + 55, + 183, + 191, + 68, + 45, + 252, + 43, + 1, + 34, + 145, + 225, + 29, + 188, + 255, + 146, + 2, + 87, + 247, + 189, + 215, + 71, + 63, + 186, + 168, + 153, + 121, + 24, + 144, + 202, + 51, + 228, + 10, + 117, + 248, + 167, + 19, + 120, + 147, + 227, + 78, + 114, + 194, + 45, + 159, + 34, + 138, + 207, + 225, + 97, + 71, + 232, + 246, + 175, + 210, + 0, + 116, + 16, + 173, + 195, + 190, + 89, + 103, + 210, + 243, + 139, + 165, + 88, + 89, + 103, + 239, + 52, + 19, + 124, + 92, + 181, + 158, + 163, + 32, + 128, + 218, + 86, + 97, + 254, + 122, + 114, + 84, + 201, + 73, + 45, + 164, + 79, + 128, + 211, + 112, + 54, + 181, + 122, + 239, + 136, + 210, + 136, + 234, + 198, + 214, + 192, + 13, + 81, + 61, + 16, + 193, + 60, + 108, + 163, + 242, + 245, + 160, + 239, + 157, + 227, + 160, + 196, + 87, + 37, + 69, + 255, + 64, + 107, + 209, + 138, + 240, + 201, + 62, + 4, + 206, + 56, + 46, + 69, + 214, + 100, + 198, + 206, + 228, + 157, + 250, + 154, + 86, + 243, + 213, + 182, + 61, + 207, + 96, + 178, + 249, + 236, + 150, + 203, + 24, + 137, + 69, + 127, + 117, + 13, + 119, + 104, + 221, + 178, + 12, + 25, + 210, + 164, + 68, + 48, + 224, + 73, + 72, + 16, + 33, + 157, + 200, + 6, + 33, + 86, + 57, + 238, + 122, + 204, + 199, + 151, + 67, + 176, + 136, + 136, + 75, + 158, + 250, + 90, + 182, + 24, + 160, + 124, + 233, + 214, + 118, + 61, + 41, + 97, + 215, + 197, + 161, + 144, + 95, + 147, + 45, + 109, + 183, + 187, + 194, + 6, + 132, + 77, + 22, + 80, + 3, + 8, + 249, + 89, + 56, + 111, + 156, + 167, + 43, + 103, + 18, + 119, + 44, + 209, + 231, + 26, + 231, + 58, + 220, + 124, + 96, + 182, + 62, + 77, + 85, + 86, + 230, + 162, + 90, + 23, + 56, + 139, + 157, + 207, + 77, + 238, + 217, + 248, + 121, + 107, + 27, + 49, + 64, + 141, + 115, + 141, + 218, + 199, + 29, + 106, + 78, + 134, + 252, + 41, + 198, + 111, + 47, + 72, + 113, + 95, + 238, + 49, + 37, + 157, + 225, + 124, + 201, + 98, + 189, + 213, + 158, + 77, + 126, + 13, + 31, + 17, + 132, + 1, + 120, + 86, + 105, + 119, + 39, + 140, + 106, + 226, + 234, + 135, + 166, + 61, + 250, + 218, + 94, + 246, + 78, + 71, + 2, + 12, + 173, + 68, + 70, + 108, + 185, + 246, + 87, + 144, + 124, + 173, + 55, + 173, + 41, + 73, + 230, + 161, + 190, + 114, + 82, + 248, + 212, + 198, + 103, + 20, + 2, + 60, + 250, + 19, + 41, + 46, + 239, + 215, + 160, + 111, + 90, + 0, + 118, + 198, + 70, + 254, + 9, + 218, + 239, + 163, + 37, + 71, + 19, + 220, + 180, + 85, + 29, + 53, + 22, + 46, + 167, + 227, + 216, + 33, + 171, + 216, + 40, + 70, + 213, + 143, + 154, + 242, + 123, + 249, + 105, + 51, + 125, + 157, + 70, + 12, + 83, + 146, + 43, + 219, + 162, + 253, + 134, + 51, + 31, + 218, + 91, + 14, + 254, + 14, + 208, + 73, + 177, + 52, + 31, + 31, + 69, + 184, + 167, + 26, + 112, + 209, + 246, + 111, + 68, + 111, + 105, + 75, + 78, + 167, + 43, + 17, + 108, + 215, + 241, + 152, + 205, + 68, + 109, + 231, + 227, + 186, + 208, + 70, + 216, + 102, + 14, + 185, + 181, + 220, + 121, + 34, + 70, + 115, + 41, + 216, + 192, + 9, + 229, + 236, + 157, + 190, + 195, + 15, + 188, + 204, + 116, + 109, + 194, + 75, + 156, + 173, + 105, + 105, + 22, + 224, + 63, + 173, + 31, + 246, + 239, + 21, + 1, + 168, + 27, + 42, + 30, + 89, + 134, + 19, + 8, + 29, + 14, + 79, + 62, + 160, + 208, + 51, + 144, + 182, + 26, + 145, + 106, + 135, + 213, + 139, + 58, + 21, + 65, + 75, + 40, + 176, + 221, + 192, + 45, + 174, + 215, + 114, + 235, + 173, + 53, + 162, + 22, + 14, + 237, + 74, + 59, + 128, + 91, + 40, + 125, + 133, + 173, + 71, + 0, + 160, + 8, + 47, + 154, + 12, + 130, + 68, + 107, + 12, + 126, + 229, + 164, + 140, + 155, + 80, + 241, + 5, + 223, + 16, + 52, + 22, + 230, + 8, + 120, + 80, + 113, + 173, + 64, + 29, + 145, + 36, + 126, + 11, + 85, + 26, + 11, + 204, + 112, + 164, + 47, + 185, + 113, + 19, + 170, + 194, + 255, + 252, + 43, + 159, + 24, + 12, + 183, + 231, + 86, + 214, + 164, + 0, + 90, + 33, + 98, + 190, + 86, + 217, + 57, + 183, + 217, + 202, + 253, + 168, + 160, + 42, + 104, + 245, + 198, + 42, + 187, + 113, + 2, + 152, + 8, + 183, + 239, + 71, + 214, + 110, + 86, + 253, + 128, + 209, + 7, + 82, + 55, + 67, + 79, + 210, + 245, + 163, + 55, + 229, + 75, + 215, + 205, + 217, + 105, + 70, + 45, + 46, + 65, + 60, + 181, + 188, + 112, + 79, + 92, + 86, + 132, + 209, + 19, + 51, + 157, + 37, + 13, + 125, + 40, + 143, + 66, + 210, + 118, + 187, + 67, + 207, + 227, + 84, + 56, + 45, + 49, + 105, + 213, + 162, + 160, + 16, + 47, + 109, + 107, + 43, + 17, + 14, + 231, + 9, + 192, + 20, + 79, + 30, + 108, + 254, + 154, + 85, + 5, + 155, + 150, + 152, + 165, + 210, + 92, + 196, + 240, + 124, + 98, + 254, + 169, + 218, + 224, + 50, + 118, + 0, + 120, + 169, + 32, + 128, + 141, + 86, + 21, + 180, + 84, + 223, + 65, + 74, + 111, + 116, + 85, + 172, + 110, + 204, + 117, + 174, + 161, + 45, + 102, + 10, + 44, + 232, + 220, + 31, + 211, + 238, + 114, + 42, + 173, + 251, + 170, + 150, + 54, + 244, + 213, + 167, + 99, + 169, + 44, + 177, + 188, + 126, + 177, + 108, + 208, + 75, + 233, + 44, + 0, + 182, + 196, + 53, + 33, + 142, + 108, + 95, + 107, + 62, + 19, + 12, + 121, + 108, + 98, + 6, + 157, + 241, + 72, + 87, + 162, + 184, + 250, + 86, + 195, + 218, + 124, + 71, + 129, + 39, + 189, + 229, + 161, + 40, + 118, + 253, + 114, + 18, + 251, + 51, + 78, + 117, + 51, + 237, + 108, + 38, + 223, + 243, + 246, + 73, + 218, + 47, + 46, + 161, + 187, + 201, + 75, + 212, + 114, + 160, + 57, + 113, + 95, + 47, + 0, + 15, + 26, + 92, + 57, + 128, + 206, + 85, + 178, + 126, + 37, + 213, + 222, + 229, + 240, + 99, + 194, + 102, + 84, + 187, + 153, + 180, + 13, + 45, + 17, + 194, + 177, + 237, + 73, + 12, + 11, + 157, + 34, + 234, + 182, + 154, + 1, + 48, + 153, + 75, + 184, + 132, + 133, + 60, + 232, + 198, + 192, + 100, + 9, + 127, + 167, + 86, + 172, + 129, + 201, + 81, + 121, + 80, + 194, + 72, + 21, + 170, + 225, + 63, + 46, + 235, + 38, + 251, + 89, + 55, + 141, + 46, + 253, + 47, + 247, + 39, + 83, + 62, + 28, + 254, + 37, + 228, + 134, + 81, + 224, + 206, + 230, + 207, + 161, + 23, + 208, + 129, + 45, + 166, + 241, + 88, + 114, + 190, + 236, + 50, + 9, + 42, + 156, + 91, + 174, + 201, + 186, + 207, + 73, + 173, + 124, + 130, + 148, + 211, + 36, + 61, + 37, + 207, + 251, + 165, + 12, + 220, + 215, + 126, + 250, + 187, + 189, + 143, + 181, + 177, + 205, + 60, + 7, + 216, + 11, + 152, + 173, + 44, + 151, + 41, + 172, + 99, + 171, + 59, + 225, + 155, + 177, + 27, + 39, + 144, + 178, + 227, + 175, + 169, + 150, + 242, + 87, + 224, + 19, + 167, + 138, + 131, + 223, + 53, + 67, + 165, + 194, + 138, + 83, + 134, + 14, + 100, + 204, + 101, + 17, + 43, + 55, + 7, + 44, + 142, + 244, + 8, + 133, + 209, + 222, + 14, + 136, + 203, + 252, + 121, + 159, + 246, + 88, + 196, + 63, + 108, + 11, + 196, + 157, + 11, + 16, + 236, + 78, + 76, + 205, + 200, + 142, + 216, + 151, + 49, + 85, + 241, + 89, + 10, + 101, + 94, + 33, + 14, + 116, + 213, + 178, + 38, + 124, + 45, + 54, + 137, + 152, + 26, + 45, + 10, + 254, + 25, + 81, + 58, + 192, + 99, + 189, + 205, + 42, + 2, + 244, + 12, + 2, + 40, + 103, + 105, + 160, + 230, + 80, + 91, + 230, + 78, + 63, + 19, + 150, + 82, + 71, + 77, + 157, + 165, + 111, + 41, + 24, + 44, + 133, + 224, + 136, + 162, + 17, + 162, + 189, + 84, + 216, + 38, + 165, + 192, + 72, + 80, + 226, + 93, + 5, + 155, + 94, + 57, + 178, + 223, + 70, + 124, + 158, + 233, + 247, + 40, + 27, + 92, + 202, + 203, + 106, + 176, + 18, + 73, + 202, + 226, + 248, + 116, + 183, + 127, + 150, + 90, + 177, + 180, + 142, + 69, + 250, + 137, + 18, + 68, + 222, + 156, + 89, + 227, + 24, + 239, + 100, + 115, + 98, + 44, + 198, + 142, + 245, + 134, + 249, + 214, + 90, + 35, + 132, + 255, + 142, + 18, + 208, + 134, + 107, + 10, + 72, + 193, + 240, + 81, + 95, + 195, + 26, + 196, + 22, + 71, + 47, + 44, + 14, + 160, + 43, + 41, + 95, + 63, + 9, + 234, + 101, + 119, + 64, + 70, + 152, + 53, + 225, + 119, + 132, + 148, + 236, + 185, + 140, + 53, + 10, + 114, + 51, + 78, + 171, + 32, + 188, + 22, + 162, + 56, + 49, + 65, + 78, + 204, + 23, + 237, + 186, + 214, + 190, + 245, + 81, + 67, + 51, + 100, + 93, + 33, + 148, + 166, + 244, + 50, + 161, + 210, + 177, + 98, + 18, + 139, + 123, + 235, + 221, + 117, + 77, + 7, + 25, + 84, + 87, + 20, + 177, + 209, + 111, + 241, + 180, + 222, + 198, + 103, + 193, + 143, + 208, + 142, + 183, + 150, + 15, + 62, + 233, + 156, + 221, + 216, + 146, + 62, + 65, + 38, + 253, + 81, + 140, + 142, + 141, + 183, + 36, + 161, + 176, + 211, + 185, + 184, + 41, + 51, + 49, + 41, + 92, + 144, + 254, + 121, + 62, + 63, + 109, + 10, + 188, + 11, + 103, + 154, + 11, + 171, + 79, + 184, + 86, + 248, + 22, + 0, + 191, + 86, + 115, + 10, + 241, + 248, + 218, + 190, + 182, + 100, + 230, + 87, + 15, + 51, + 100, + 120, + 171, + 155, + 54, + 160, + 188, + 234, + 106, + 245, + 83, + 109, + 164, + 161, + 218, + 54, + 242, + 169, + 85, + 239, + 6, + 15, + 224, + 121, + 117, + 161, + 29, + 222, + 226, + 142, + 48, + 12, + 119, + 140, + 8, + 1, + 73, + 77, + 244, + 117, + 252, + 210, + 186, + 193, + 82, + 85, + 184, + 106, + 142, + 172, + 194, + 247, + 6, + 23, + 237, + 115, + 134, + 3, + 5, + 94, + 131, + 232, + 9, + 80, + 114, + 182, + 11, + 242, + 59, + 10, + 126, + 63, + 154, + 196, + 189, + 159, + 105, + 138, + 64, + 158, + 173, + 239, + 222, + 105, + 57, + 188, + 216, + 193, + 92, + 63, + 129, + 20, + 180, + 69, + 180, + 136, + 113, + 205, + 41, + 0, + 238, + 66, + 75, + 191, + 239, + 169, + 6, + 172, + 226, + 150, + 108, + 112, + 91, + 92, + 147, + 144, + 108, + 156, + 233, + 14, + 126, + 216, + 153, + 51, + 215, + 137, + 247, + 237, + 169, + 227, + 212, + 108, + 85, + 104, + 38, + 166, + 134, + 27, + 180, + 15, + 185, + 214, + 237, + 22, + 252, + 128, + 184, + 189, + 79, + 96, + 219, + 17, + 17, + 157, + 27, + 176, + 212, + 182, + 103, + 207, + 161, + 193, + 44, + 167, + 19, + 29, + 96, + 70, + 100, + 57, + 148, + 176, + 211, + 49, + 108, + 188, + 0, + 24, + 135, + 87, + 113, + 217, + 134, + 102, + 185, + 60, + 105, + 192, + 216, + 209, + 249, + 197, + 245, + 111, + 201, + 92, + 26, + 182, + 10, + 51, + 19, + 194, + 178, + 206, + 96, + 133, + 28, + 6, + 109, + 74, + 174, + 68, + 113, + 130, + 94, + 229, + 128, + 47, + 171, + 216, + 241, + 155, + 0, + 28, + 52, + 95, + 49, + 104, + 80, + 31, + 232, + 22, + 112, + 80, + 51, + 132, + 220, + 253, + 216, + 187, + 90, + 169, + 117, + 246, + 21, + 103, + 95, + 138, + 252, + 19, + 108, + 89, + 248, + 212, + 37, + 117, + 249, + 171, + 128, + 193, + 73, + 153, + 91, + 70, + 46, + 232, + 134, + 48, + 232, + 137, + 238, + 201, + 222, + 83, + 110, + 238, + 108, + 91, + 129, + 53, + 55, + 33, + 97, + 83, + 235, + 35, + 231, + 199, + 213, + 170, + 66, + 3, + 147, + 85, + 20, + 202, + 56, + 63, + 245, + 138, + 111, + 96, + 108, + 241, + 242, + 203, + 232, + 175, + 20, + 163, + 81, + 209, + 238, + 55, + 43, + 44, + 252, + 16, + 164, + 198, + 188, + 127, + 95, + 244, + 216, + 72, + 15, + 5, + 94, + 166, + 38, + 219, + 46, + 227, + 217, + 64, + 167, + 63, + 135, + 214, + 99, + 35, + 175, + 43, + 124, + 89, + 72, + 86, + 251, + 21, + 133, + 240, + 167, + 37, + 25, + 138, + 219, + 148, + 61, + 253, + 78, + 119, + 138, + 87, + 86, + 55, + 216, + 192, + 62, + 117, + 71, + 227, + 26, + 3, + 223, + 45, + 118, + 34, + 134, + 106, + 82, + 215, + 4, + 139, + 180, + 52, + 224, + 220, + 5, + 109, + 234, + 41, + 175, + 82, + 212, + 103, + 2, + 234, + 161, + 111, + 163, + 220, + 60, + 150, + 81, + 94, + 151, + 93, + 174, + 137, + 134, + 217, + 71, + 71, + 2, + 43, + 187, + 231, + 54, + 45, + 63, + 189, + 186, + 193, + 64, + 211, + 58, + 171, + 226, + 228, + 165, + 140, + 23, + 224, + 97, + 82, + 84, + 97, + 143, + 252, + 223, + 197, + 115, + 92, + 89, + 252, + 174, + 84, + 111, + 245, + 12, + 28, + 64, + 2, + 178, + 108, + 148, + 4, + 47, + 0, + 158, + 43, + 74, + 150, + 189, + 114, + 129, + 205, + 41, + 17, + 170, + 189, + 57, + 55, + 212, + 90, + 210, + 120, + 11, + 133, + 211, + 106, + 68, + 14, + 209, + 166, + 145, + 122, + 206, + 247, + 24, + 213, + 152, + 35, + 80, + 176, + 118, + 211, + 155, + 245, + 82, + 214, + 178, + 185, + 155, + 222, + 38, + 37, + 223, + 153, + 178, + 57, + 204, + 163, + 148, + 42, + 189, + 45, + 42, + 108, + 68, + 133, + 153, + 210, + 47, + 228, + 177, + 26, + 138, + 0, + 74, + 158, + 33, + 18, + 155, + 145, + 207, + 236, + 160, + 220, + 167, + 183, + 95, + 58, + 173, + 97, + 194, + 96, + 218, + 177, + 246, + 169, + 96, + 211, + 127, + 189, + 75, + 113, + 178, + 129, + 82, + 23, + 69, + 245, + 11, + 206, + 145, + 129, + 227, + 172, + 51, + 214, + 61, + 110, + 214, + 109, + 84, + 232, + 201, + 234, + 172, + 167, + 66, + 40, + 22, + 153, + 0, + 167, + 173, + 22, + 74, + 123, + 84, + 205, + 113, + 36, + 32, + 73, + 162, + 80, + 10, + 209, + 187, + 19, + 74, + 68, + 4, + 254, + 126, + 125, + 232, + 74, + 95, + 236, + 160, + 3, + 216, + 103, + 125, + 153, + 67, + 187, + 115, + 56, + 35, + 184, + 61, + 2, + 55, + 200, + 15, + 53, + 3, + 71, + 32, + 32, + 140, + 146, + 111, + 228, + 225, + 163, + 94, + 55, + 244, + 92, + 241, + 137, + 106, + 181, + 125, + 131, + 241, + 141, + 90, + 201, + 221, + 167, + 219, + 8, + 30, + 5, + 213, + 233, + 90, + 105, + 152, + 186, + 203, + 99, + 12, + 81, + 29, + 130, + 183, + 168, + 16, + 37, + 123, + 241, + 165, + 179, + 8, + 81, + 167, + 90, + 239, + 167, + 172, + 165, + 75, + 94, + 48, + 42, + 124, + 118, + 230, + 226, + 198, + 237, + 165, + 108, + 246, + 240, + 157, + 52, + 56, + 134, + 238, + 57, + 192, + 159, + 240, + 15, + 36, + 35, + 63, + 208, + 181, + 130, + 134, + 45, + 224, + 132, + 115, + 54, + 155, + 54, + 161, + 16, + 6, + 3, + 38, + 67, + 41, + 60, + 120, + 46, + 206, + 18, + 56, + 218, + 196, + 115, + 232, + 113, + 57, + 200, + 12, + 223, + 164, + 128, + 143, + 253, + 98, + 240, + 25, + 208, + 26, + 101, + 22, + 23, + 226, + 219, + 40, + 42, + 225, + 12, + 182, + 60, + 78, + 87, + 124, + 47, + 237, + 109, + 153, + 204, + 118, + 171, + 110, + 191, + 155, + 102, + 23, + 203, + 67, + 98, + 64, + 47, + 251, + 30, + 250, + 189, + 22, + 124, + 36, + 45, + 62, + 162, + 113, + 184, + 201, + 201, + 83, + 143, + 216, + 211, + 88, + 199, + 74, + 39, + 53, + 70, + 96, + 212, + 186, + 245, + 41, + 96, + 53, + 110, + 242, + 138, + 189, + 61, + 88, + 4, + 179, + 208, + 122, + 94, + 115, + 53, + 164, + 177, + 241, + 133, + 189, + 197, + 79, + 191, + 50, + 204, + 187, + 163, + 40, + 3, + 209, + 2, + 20, + 218, + 52, + 194, + 164, + 141, + 55, + 164, + 251, + 231, + 43, + 208, + 224, + 214, + 13, + 48, + 99, + 188, + 247, + 36, + 52, + 23, + 184, + 189, + 76, + 147, + 216, + 140, + 53, + 23, + 68, + 196, + 245, + 6, + 77, + 123, + 165, + 112, + 223, + 178, + 108, + 181, + 85, + 75, + 215, + 163, + 101, + 251, + 176, + 25, + 248, + 229, + 162, + 247, + 138, + 33, + 71, + 238, + 70, + 2, + 181, + 189, + 106, + 21, + 186, + 229, + 73, + 123, + 165, + 2, + 119, + 147, + 138, + 106, + 13, + 161, + 171, + 164, + 127, + 121, + 241, + 105, + 39, + 252, + 204, + 108, + 19, + 153, + 243, + 117, + 226, + 246, + 183, + 116, + 140, + 118, + 75, + 171, + 103, + 58, + 193, + 110, + 21, + 125, + 42, + 95, + 201, + 149, + 48, + 145, + 227, + 241, + 231, + 40, + 195, + 76, + 152, + 31, + 187, + 79, + 144, + 137, + 81, + 157, + 173, + 98, + 245, + 136, + 236, + 29, + 88, + 92, + 102, + 136, + 32, + 58, + 160, + 194, + 253, + 49, + 171, + 83, + 216, + 23, + 66, + 6, + 14, + 114, + 80, + 233, + 236, + 19, + 240, + 146, + 180, + 253, + 118, + 243, + 48, + 220, + 171, + 145, + 79, + 105, + 219, + 0, + 54, + 182, + 168, + 45, + 221, + 235, + 113, + 241, + 113, + 144, + 228, + 196, + 204, + 202, + 101, + 222, + 254, + 176, + 78, + 124, + 11, + 25, + 237, + 97, + 184, + 208, + 83, + 74, + 95, + 51, + 238, + 1, + 161, + 110, + 48, + 200, + 175, + 244, + 240, + 248, + 148, + 92, + 130, + 35, + 217, + 228, + 82, + 129, + 210, + 133, + 119, + 89, + 43, + 23, + 24, + 45, + 107, + 85, + 96, + 45, + 45, + 159, + 81, + 182, + 62, + 198, + 31, + 135, + 69, + 198, + 251, + 137, + 154, + 65, + 254, + 249, + 186, + 185, + 171, + 120, + 247, + 98, + 7, + 128, + 153, + 123, + 189, + 106, + 92, + 189, + 115, + 35, + 47, + 191, + 34, + 147, + 230, + 191, + 68, + 31, + 176, + 251, + 204, + 147, + 3, + 59, + 122, + 25, + 210, + 17, + 102, + 65, + 119, + 87, + 181, + 97, + 60, + 96, + 254, + 70, + 189, + 36, + 164, + 200, + 72, + 149, + 0, + 245, + 15, + 192, + 102, + 130, + 78, + 109, + 17, + 91, + 60, + 155, + 142, + 191, + 215, + 227, + 177, + 131, + 161, + 68, + 152, + 30, + 89, + 115, + 28, + 244, + 5, + 125, + 18, + 9, + 66, + 226, + 77, + 30, + 214, + 232, + 33, + 209, + 223, + 85, + 243, + 235, + 50, + 99, + 249, + 202, + 206, + 183, + 41, + 0, + 188, + 162, + 147, + 18, + 93, + 201, + 154, + 27, + 145, + 242, + 223, + 102, + 105, + 197, + 140, + 22, + 67, + 249, + 190, + 57, + 96, + 32, + 47, + 153, + 211, + 46, + 94, + 108, + 33, + 211, + 18, + 61, + 45, + 117, + 208, + 75, + 18, + 117, + 252, + 193, + 118, + 75, + 252, + 160, + 11, + 249, + 6, + 191, + 83, + 6, + 158, + 206, + 191, + 36, + 184, + 47, + 2, + 235, + 68, + 56, + 4, + 194, + 1, + 57, + 113, + 180, + 78, + 105, + 69, + 84, + 153, + 38, + 126, + 249, + 150, + 156, + 103, + 98, + 56, + 143, + 32, + 233, + 56, + 169, + 91, + 105, + 175, + 180, + 115, + 87, + 105, + 21, + 205, + 115, + 67, + 227, + 192, + 146, + 73, + 120, + 74, + 21, + 227, + 18, + 232, + 229, + 162, + 196, + 71, + 24, + 162, + 204, + 183, + 29, + 57, + 118, + 91, + 227, + 20, + 57, + 218, + 72, + 146, + 84, + 56, + 5, + 160, + 177, + 129, + 27, + 141, + 234, + 16, + 169, + 121, + 25, + 137, + 72, + 221, + 38, + 56, + 122, + 126, + 135, + 181, + 219, + 27, + 200, + 27, + 220, + 45, + 220, + 47, + 22, + 34, + 232, + 106, + 246, + 180, + 148, + 58, + 177, + 248, + 25, + 238, + 53, + 237, + 26, + 53, + 29, + 252, + 171, + 67, + 161, + 125, + 24, + 101, + 213, + 0, + 97, + 237, + 250, + 225, + 114, + 38, + 18, + 192, + 123, + 125, + 77, + 163, + 45, + 17, + 161, + 140, + 3, + 248, + 208, + 98, + 17, + 125, + 247, + 132, + 250, + 74, + 142, + 76, + 184, + 112, + 183, + 196, + 140, + 159, + 135, + 55, + 91, + 107, + 8, + 205, + 152, + 157, + 10, + 206, + 33, + 187, + 194, + 208, + 89, + 122, + 55, + 138, + 80, + 215, + 2, + 165, + 59, + 21, + 108, + 202, + 212, + 231, + 139, + 195, + 139, + 15, + 62, + 56, + 49, + 92, + 89, + 54, + 38, + 219, + 190, + 228, + 193, + 8, + 234, + 148, + 191, + 108, + 207, + 151, + 170, + 22, + 142, + 246, + 125, + 47, + 147, + 160, + 158, + 144, + 223, + 19, + 69, + 201, + 7, + 202, + 51, + 146, + 192, + 244, + 40, + 4, + 162, + 138, + 150, + 168, + 140, + 94, + 144, + 63, + 211, + 48, + 109, + 113, + 163, + 78, + 189, + 38, + 160, + 207, + 37, + 128, + 56, + 222, + 36, + 155, + 184, + 241, + 113, + 217, + 233, + 115, + 63, + 244, + 169, + 82, + 171, + 180, + 68, + 181, + 112, + 146, + 61, + 224, + 33, + 140, + 230, + 70, + 46, + 84, + 219, + 218, + 119, + 152, + 178, + 172, + 149, + 208, + 19, + 132, + 225, + 9, + 46, + 21, + 155, + 156, + 3, + 127, + 53, + 90, + 108, + 79, + 41, + 30, + 58, + 197, + 252, + 204, + 219, + 120, + 58, + 12, + 19, + 194, + 69, + 199, + 123, + 44, + 254, + 206, + 37, + 57, + 137, + 189, + 183, + 179, + 107, + 106, + 146, + 169, + 21, + 221, + 245, + 167, + 186, + 109, + 241, + 137, + 63, + 121, + 134, + 56, + 201, + 100, + 232, + 234, + 89, + 47, + 176, + 82, + 52, + 191, + 22, + 21, + 38, + 95, + 160, + 138, + 112, + 63, + 161, + 127, + 168, + 15, + 228, + 230, + 196, + 77, + 110, + 211, + 139, + 227, + 191, + 73, + 132, + 73, + 3, + 219, + 128, + 103, + 16, + 54, + 200, + 136, + 134, + 55, + 66, + 29, + 12, + 133, + 70, + 61, + 81, + 135, + 13, + 183, + 44, + 100, + 200, + 223, + 214, + 228, + 172, + 76, + 55, + 18, + 201, + 67, + 215, + 166, + 254, + 53, + 85, + 126, + 185, + 255, + 106, + 148, + 6, + 173, + 184, + 18, + 254, + 80, + 141, + 200, + 158, + 121, + 45, + 139, + 201, + 63, + 232, + 12, + 242, + 100, + 225, + 148, + 86, + 99, + 198, + 243, + 255, + 254, + 249, + 175, + 232, + 222, + 229, + 197, + 40, + 135, + 189, + 69, + 244, + 61, + 180, + 125, + 43, + 117, + 254, + 89, + 90, + 23, + 28, + 217, + 74, + 164, + 9, + 97, + 185, + 18, + 255, + 74, + 9, + 52, + 170, + 137, + 160, + 51, + 240, + 12, + 31, + 105, + 226, + 1, + 73, + 136, + 76, + 134, + 247, + 138, + 116, + 46, + 21, + 75, + 82, + 210, + 74, + 234, + 241, + 77, + 171, + 97, + 103, + 9, + 9, + 56, + 107, + 32, + 52, + 238, + 238, + 185, + 146, + 224, + 213, + 176, + 54, + 53, + 106, + 198, + 81, + 111, + 100, + 149, + 142, + 254, + 42, + 231, + 11, + 163, + 248, + 195, + 187, + 13, + 27, + 198, + 195, + 128, + 79, + 191, + 227, + 176, + 76, + 97, + 184, + 124, + 89, + 124, + 158, + 24, + 110, + 49, + 209, + 19, + 128, + 107, + 217, + 194, + 45, + 255, + 114, + 5, + 62, + 123, + 43, + 32, + 200, + 90, + 53, + 75, + 185, + 113, + 61, + 247, + 255, + 117, + 241, + 12, + 22, + 83, + 133, + 247, + 117, + 158, + 187, + 177, + 174, + 2, + 120, + 191, + 107, + 206, + 227, + 28, + 100, + 87, + 158, + 89, + 64, + 121, + 196, + 160, + 104, + 97, + 67, + 149, + 235, + 217, + 42, + 50, + 183, + 95, + 186, + 57, + 16, + 97, + 79, + 90, + 163, + 230, + 13, + 104, + 103, + 48, + 48, + 95, + 192, + 185, + 47, + 105, + 107, + 27, + 220, + 179, + 239, + 142, + 114, + 43, + 210, + 177, + 249, + 55, + 208, + 228, + 148, + 249, + 202, + 107, + 19, + 113, + 165, + 176, + 228, + 139, + 27, + 246, + 82, + 108, + 32, + 247, + 122, + 107, + 217, + 53, + 243, + 28, + 157, + 97, + 211, + 255, + 220, + 245, + 179, + 73, + 105, + 145, + 229, + 175, + 112, + 105, + 71, + 236, + 135, + 135, + 229, + 89, + 238, + 112, + 170, + 80, + 139, + 41, + 122, + 78, + 106, + 253, + 82, + 182, + 243, + 212, + 138, + 23, + 191, + 194, + 123, + 68, + 226, + 108, + 61, + 234, + 12, + 145, + 227, + 55, + 128, + 148, + 38, + 218, + 187, + 202, + 221, + 240, + 96, + 68, + 10, + 1, + 235, + 156, + 95, + 213, + 195, + 110, + 113, + 29, + 5, + 191, + 246, + 65, + 69, + 216, + 169, + 233, + 180, + 140, + 200, + 2, + 117, + 82, + 25, + 153, + 184, + 172, + 100, + 34, + 152, + 37, + 152, + 40, + 84, + 7, + 210, + 137, + 100, + 86, + 73, + 170, + 214, + 77, + 60, + 154, + 163, + 233, + 147, + 223, + 242, + 125, + 89, + 72, + 248, + 236, + 100, + 213, + 245, + 141, + 82, + 218, + 95, + 80, + 88, + 86, + 51, + 11, + 178, + 6, + 72, + 79, + 196, + 95, + 5, + 194, + 27, + 118, + 249, + 227, + 83, + 23, + 213, + 105, + 221, + 67, + 8, + 76, + 51, + 113, + 169, + 138, + 41, + 147, + 138, + 138, + 218, + 77, + 84, + 187, + 41, + 124, + 174, + 218, + 152, + 15, + 96, + 207, + 84, + 87, + 70, + 69, + 247, + 184, + 168, + 140, + 122, + 11, + 105, + 172, + 38, + 46, + 140, + 6, + 83, + 51, + 192, + 206, + 57, + 21, + 208, + 39, + 248, + 224, + 76, + 77, + 248, + 70, + 26, + 192, + 209, + 62, + 192, + 91, + 218, + 236, + 82, + 168, + 28, + 6, + 124, + 143, + 70, + 45, + 168, + 205, + 21, + 147, + 11, + 167, + 204, + 114, + 241, + 7, + 107, + 16, + 56, + 135, + 42, + 74, + 99, + 227, + 125, + 30, + 194, + 187, + 34, + 198, + 220, + 57, + 246, + 250, + 111, + 113, + 35, + 255, + 30, + 42, + 127, + 211, + 195, + 68, + 6, + 110, + 139, + 222, + 67, + 215, + 175, + 172, + 151, + 221, + 20, + 16, + 162, + 11, + 113, + 53, + 116, + 93, + 84, + 130, + 183, + 112, + 44, + 34, + 137, + 1, + 195, + 226, + 226, + 57, + 67, + 14, + 11, + 85, + 225, + 166, + 118, + 27, + 72, + 16, + 103, + 49, + 5, + 137, + 58, + 144, + 30, + 195, + 145, + 155, + 49, + 219, + 141, + 130, + 13, + 201, + 54, + 36, + 164, + 181, + 249, + 185, + 58, + 157, + 32, + 108, + 174, + 113, + 98, + 133, + 101, + 111, + 128, + 249, + 195, + 69, + 168, + 112, + 184, + 81, + 104, + 229, + 228, + 117, + 164, + 186, + 21, + 133, + 104, + 86, + 127, + 72, + 96, + 23, + 87, + 191, + 136, + 113, + 63, + 54, + 98, + 195, + 234, + 42, + 119, + 96, + 56, + 163, + 207, + 63, + 84, + 189, + 233, + 236, + 78, + 81, + 114, + 254, + 247, + 215, + 216, + 129, + 78, + 129, + 215, + 154, + 177, + 120, + 109, + 52, + 129, + 178, + 22, + 5, + 240, + 7, + 235, + 89, + 183, + 82, + 49, + 142, + 166, + 65, + 22, + 174, + 231, + 26, + 78, + 84, + 241, + 104, + 136, + 59, + 220, + 167, + 25, + 41, + 233, + 226, + 236, + 74, + 145, + 130, + 115, + 14, + 152, + 97, + 206, + 46, + 81, + 158, + 67, + 19, + 240, + 82, + 96, + 119, + 141, + 113, + 184, + 111, + 67, + 234, + 140, + 33, + 128, + 9, + 97, + 182, + 152, + 155, + 114, + 48, + 87, + 237, + 179, + 156, + 227, + 132, + 36, + 100, + 239, + 209, + 11, + 72, + 246, + 117, + 251, + 129, + 14, + 137, + 224, + 98, + 9, + 45, + 216, + 89, + 135, + 152, + 148, + 107, + 201, + 95, + 31, + 114, + 113, + 77, + 236, + 94, + 17, + 188, + 149, + 146, + 154, + 108, + 113, + 83, + 191, + 244, + 229, + 187, + 152, + 91, + 153, + 123, + 42, + 82, + 155, + 219, + 97, + 98, + 117, + 209, + 199, + 164, + 251, + 79, + 170, + 237, + 208, + 8, + 179, + 11, + 96, + 167, + 199, + 34, + 62, + 204, + 102, + 140, + 193, + 191, + 86, + 3, + 203, + 216, + 61, + 19, + 153, + 161, + 98, + 233, + 91, + 229, + 181, + 31, + 251, + 11, + 157, + 31, + 16, + 109, + 43, + 27, + 146, + 207, + 184, + 254, + 89, + 227, + 150, + 68, + 198, + 243, + 191, + 20, + 84, + 125, + 118, + 78, + 14, + 103, + 206, + 194, + 149, + 154, + 135, + 40, + 63, + 25, + 182, + 39, + 213, + 149, + 15, + 47, + 191, + 97, + 255, + 194, + 158, + 87, + 252, + 30, + 0, + 68, + 44, + 230, + 154, + 126, + 109, + 1, + 156, + 28, + 68, + 90, + 139, + 16, + 240, + 118, + 7, + 0, + 137, + 32, + 53, + 0, + 188, + 251, + 76, + 247, + 206, + 17, + 213, + 216, + 84, + 83, + 227, + 95, + 152, + 200, + 168, + 211, + 108, + 73, + 248, + 190, + 116, + 135, + 178, + 236, + 238, + 166, + 44, + 54, + 204, + 215, + 111, + 181, + 169, + 236, + 21, + 96, + 227, + 242, + 223, + 118, + 56, + 64, + 151, + 249, + 52, + 253, + 92, + 172, + 151, + 109, + 216, + 221, + 107, + 234, + 112, + 185, + 184, + 26, + 152, + 49, + 245, + 59, + 52, + 224, + 65, + 86, + 126, + 59, + 255, + 39, + 47, + 43, + 174, + 123, + 160, + 169, + 37, + 161, + 39, + 208, + 100, + 114, + 252, + 71, + 71, + 2, + 8, + 227, + 82, + 98, + 21, + 7, + 122, + 133, + 237, + 110, + 228, + 154, + 218, + 191, + 160, + 8, + 95, + 97, + 158, + 129, + 149, + 72, + 67, + 161, + 142, + 200, + 120, + 241, + 186, + 64, + 252, + 200, + 145, + 103, + 105, + 102, + 189, + 19, + 223, + 234, + 131, + 234, + 233, + 123, + 137, + 169, + 58, + 3, + 10, + 31, + 52, + 14, + 122, + 34, + 199, + 245, + 31, + 42, + 123, + 138, + 136, + 210, + 148, + 232, + 143, + 73, + 70, + 153, + 160, + 107, + 186, + 92, + 170, + 250, + 121, + 223, + 28, + 85, + 236, + 240, + 56, + 226, + 119, + 106, + 187, + 151, + 61, + 195, + 186, + 210, + 61, + 97, + 21, + 5, + 81, + 125, + 145, + 250, + 133, + 228, + 137, + 26, + 163, + 231, + 47, + 114, + 202, + 244, + 208, + 174, + 121, + 124, + 71, + 169, + 109, + 30, + 152, + 116, + 167, + 69, + 186, + 40, + 219, + 105, + 60, + 211, + 152, + 131, + 251, + 143, + 35, + 148, + 131, + 37, + 25, + 97, + 123, + 76, + 19, + 230, + 197, + 142, + 165, + 206, + 7, + 28, + 67, + 14, + 136, + 69, + 9, + 147, + 219, + 10, + 134, + 251, + 136, + 15, + 249, + 12, + 85, + 55, + 162, + 136, + 158, + 69, + 106, + 154, + 29, + 229, + 126, + 221, + 57, + 153, + 141, + 206, + 207, + 148, + 179, + 100, + 26, + 198, + 53, + 25, + 63, + 239, + 110, + 88, + 234, + 246, + 20, + 168, + 47, + 182, + 237, + 39, + 254, + 93, + 222, + 67, + 155, + 6, + 180, + 53, + 118, + 207, + 41, + 222, + 11, + 176, + 30, + 19, + 42, + 139, + 84, + 180, + 239, + 77, + 196, + 52, + 101, + 128, + 253, + 129, + 61, + 99, + 228, + 6, + 252, + 87, + 141, + 6, + 203, + 36, + 132, + 193, + 78, + 11, + 250, + 245, + 162, + 72, + 113, + 138, + 231, + 87, + 7, + 114, + 244, + 20, + 184, + 208, + 210, + 1, + 132, + 234, + 178, + 74, + 73, + 167, + 140, + 83, + 57, + 116, + 86, + 21, + 77, + 199, + 147, + 46, + 24, + 225, + 35, + 37, + 119, + 29, + 137, + 250, + 156, + 239, + 26, + 240, + 197, + 52, + 153, + 74, + 191, + 110, + 59, + 65, + 118, + 138, + 168, + 46, + 57, + 71, + 172, + 24, + 205, + 6, + 104, + 138, + 57, + 124, + 2, + 92, + 216, + 108, + 227, + 236, + 225, + 60, + 97, + 100, + 57, + 3, + 71, + 104, + 196, + 139, + 193, + 167, + 63, + 66, + 237, + 6, + 91, + 51, + 97, + 243, + 151, + 211, + 253, + 187, + 171, + 235, + 199, + 162, + 187, + 204, + 240, + 125, + 157, + 34, + 75, + 140, + 232, + 44, + 77, + 24, + 84, + 148, + 142, + 217, + 104, + 157, + 16, + 17, + 91, + 55, + 143, + 15, + 57, + 42, + 33, + 42, + 115, + 207, + 220, + 34, + 202, + 49, + 7, + 147, + 183, + 160, + 60, + 181, + 77, + 93, + 253, + 178, + 92, + 252, + 109, + 71, + 227, + 74, + 117, + 110, + 59, + 107, + 138, + 155, + 176, + 33, + 63, + 46, + 225, + 212, + 41, + 112, + 39, + 82, + 7, + 57, + 146, + 128, + 49, + 19, + 123, + 111, + 252, + 77, + 149, + 38, + 126, + 171, + 42, + 243, + 70, + 34, + 239, + 178, + 163, + 159, + 123, + 25, + 31, + 249, + 62, + 205, + 223, + 216, + 72, + 230, + 56, + 127, + 19, + 48, + 133, + 158, + 139, + 218, + 141, + 47, + 28, + 43, + 208, + 97, + 231, + 70, + 140, + 58, + 16, + 137, + 27, + 53, + 97, + 11, + 171, + 209, + 82, + 243, + 88, + 46, + 95, + 249, + 22, + 242, + 229, + 2, + 70, + 174, + 227, + 118, + 201, + 232, + 116, + 54, + 159, + 66, + 77, + 92, + 108, + 10, + 220, + 142, + 76, + 131, + 191, + 249, + 95, + 87, + 171, + 121, + 221, + 93, + 86, + 15, + 44, + 194, + 6, + 134, + 106, + 107, + 192, + 71, + 113, + 97, + 243, + 75, + 183, + 180, + 51, + 8, + 110, + 15, + 99, + 115, + 111, + 31, + 245, + 66, + 33, + 86, + 128, + 97, + 89, + 155, + 181, + 90, + 10, + 111, + 243, + 191, + 111, + 159, + 98, + 253, + 71, + 72, + 236, + 23, + 9, + 228, + 191, + 186, + 85, + 103, + 11, + 47, + 135, + 180, + 156, + 184, + 227, + 39, + 30, + 123, + 233, + 232, + 60, + 242, + 51, + 22, + 221, + 223, + 46, + 201, + 170, + 214, + 11, + 252, + 121, + 4, + 219, + 23, + 100, + 156, + 2, + 85, + 43, + 249, + 35, + 173, + 227, + 243, + 127, + 164, + 169, + 146, + 31, + 196, + 150, + 76, + 117, + 63, + 230, + 95, + 245, + 153, + 70, + 107, + 64, + 132, + 98, + 74, + 73, + 69, + 9, + 132, + 162, + 26, + 67, + 14, + 93, + 168, + 21, + 151, + 242, + 46, + 75, + 37, + 49, + 74, + 226, + 79, + 239, + 23, + 234, + 13, + 213, + 16, + 116, + 80, + 60, + 131, + 211, + 132, + 28, + 151, + 165, + 100, + 14, + 76, + 3, + 87, + 26, + 48, + 137, + 225, + 164, + 227, + 250, + 76, + 22, + 148, + 194, + 201, + 50, + 80, + 195, + 212, + 79, + 0, + 207, + 5, + 238, + 96, + 194, + 235, + 214, + 14, + 254, + 15, + 253, + 20, + 184, + 101, + 185, + 59, + 138, + 134, + 164, + 91, + 72, + 246, + 198, + 210, + 62, + 179, + 55, + 101, + 47, + 247, + 141, + 193, + 56, + 218, + 214, + 137, + 240, + 21, + 20, + 68, + 44, + 81, + 77, + 115, + 56, + 79, + 148, + 132, + 42, + 137, + 12, + 249, + 30, + 41, + 218, + 137, + 85, + 118, + 213, + 210, + 117, + 137, + 115, + 186, + 123, + 101, + 185, + 236, + 240, + 203, + 95, + 51, + 241, + 2, + 126, + 28, + 195, + 209, + 219, + 203, + 27, + 70, + 136, + 11, + 102, + 140, + 155, + 38, + 255, + 203, + 113, + 231, + 67, + 183, + 19, + 145, + 217, + 14, + 152, + 120, + 21, + 108, + 34, + 114, + 244, + 82, + 229, + 68, + 222, + 166, + 244, + 169, + 86, + 240, + 170, + 249, + 14, + 112, + 175, + 88, + 61, + 136, + 23, + 216, + 73, + 200, + 72, + 56, + 190, + 87, + 86, + 194, + 106, + 161, + 96, + 48, + 200, + 19, + 118, + 41, + 133, + 78, + 88, + 242, + 65, + 126, + 153, + 112, + 206, + 213, + 79, + 244, + 131, + 243, + 44, + 93, + 1, + 219, + 81, + 65, + 251, + 132, + 254, + 63, + 238, + 95, + 72, + 56, + 78, + 47, + 57, + 40, + 51, + 197, + 100, + 7, + 107, + 22, + 10, + 163, + 76, + 50, + 243, + 8, + 84, + 112, + 211, + 123, + 15, + 20, + 243, + 193, + 66, + 58, + 32, + 77, + 189, + 236, + 16, + 133, + 110, + 58, + 232, + 56, + 99, + 172, + 200, + 103, + 134, + 48, + 62, + 178, + 54, + 147, + 150, + 237, + 231, + 127, + 177, + 143, + 247, + 17, + 183, + 46, + 58, + 87, + 190, + 205, + 88, + 25, + 163, + 219, + 146, + 224, + 186, + 115, + 58, + 252, + 12, + 191, + 253, + 20, + 166, + 51, + 211, + 121, + 17, + 59, + 43, + 103, + 61, + 230, + 205, + 12, + 196, + 146, + 167, + 187, + 133, + 210, + 9, + 30, + 79, + 90, + 219, + 116, + 159, + 16, + 142, + 185, + 108, + 125, + 73, + 207, + 217, + 215, + 149, + 67, + 70, + 95, + 76, + 157, + 142, + 2, + 154, + 192, + 31, + 58, + 52, + 51, + 140, + 9, + 247, + 124, + 67, + 184, + 66, + 176, + 170, + 14, + 52, + 116, + 68, + 254, + 178, + 228, + 234, + 58, + 106, + 128, + 240, + 68, + 36, + 21, + 197, + 187, + 13, + 80, + 208, + 154, + 194, + 68, + 252, + 13, + 212, + 47, + 144, + 141, + 41, + 252, + 225, + 110, + 96, + 88, + 25, + 222, + 88, + 108, + 145, + 71, + 43, + 21, + 241, + 1, + 182, + 2, + 184, + 20, + 63, + 114, + 75, + 204, + 233, + 249, + 77, + 64, + 89, + 61, + 209, + 73, + 43, + 52, + 159, + 102, + 255, + 153, + 65, + 241, + 123, + 158, + 252, + 157, + 79, + 124, + 55, + 3, + 120, + 76, + 89, + 214, + 190, + 224, + 228, + 237, + 23, + 252, + 37, + 58, + 241, + 118, + 211, + 80, + 194, + 241, + 43, + 79, + 47, + 139, + 111, + 180, + 136, + 189, + 244, + 237, + 161, + 255, + 216, + 51, + 101, + 35, + 75, + 6, + 202, + 122, + 46, + 7, + 229, + 143, + 231, + 181, + 9, + 122, + 15, + 213, + 190, + 80, + 22, + 28, + 235, + 35, + 127, + 26, + 255, + 128, + 220, + 170, + 208, + 2, + 120, + 243, + 9, + 50, + 156, + 203, + 235, + 116, + 52, + 111, + 169, + 232, + 140, + 57, + 82, + 221, + 118, + 81, + 49, + 84, + 173, + 15, + 27, + 3, + 92, + 1, + 73, + 98, + 106, + 23, + 192, + 227, + 112, + 155, + 238, + 255, + 0, + 16, + 204, + 204, + 174, + 241, + 159, + 201, + 137, + 224, + 113, + 24, + 13, + 232, + 202, + 187, + 42, + 4, + 153, + 188, + 139, + 77, + 134, + 149, + 205, + 244, + 187, + 166, + 236, + 114, + 239, + 244, + 246, + 111, + 131, + 61, + 10, + 162, + 19, + 78, + 226, + 134, + 172, + 62, + 84, + 125, + 235, + 248, + 249, + 30, + 41, + 7, + 166, + 38, + 121, + 199, + 171, + 217, + 229, + 95, + 75, + 34, + 132, + 235, + 198, + 210, + 189, + 13, + 32, + 146, + 34, + 51, + 137, + 15, + 57, + 59, + 183, + 175, + 201, + 66, + 215, + 100, + 85, + 23, + 188, + 239, + 232, + 65, + 201, + 58, + 51, + 119, + 176, + 217, + 42, + 191, + 195, + 54, + 218, + 80, + 144, + 240, + 145, + 53, + 93, + 236, + 116, + 84, + 13, + 216, + 182, + 243, + 162, + 17, + 15, + 24, + 192, + 227, + 106, + 33, + 68, + 137, + 243, + 171, + 162, + 34, + 89, + 159, + 61, + 72, + 24, + 217, + 88, + 20, + 172, + 127, + 10, + 80, + 113, + 165, + 239, + 108, + 138, + 99, + 130, + 9, + 20, + 251, + 60, + 100, + 9, + 1, + 210, + 144, + 67, + 68, + 13, + 223, + 197, + 98, + 2, + 53, + 198, + 20, + 81, + 194, + 141, + 119, + 55, + 45, + 253, + 96, + 206, + 62, + 126, + 100, + 218, + 48, + 42, + 32, + 211, + 13, + 40, + 227, + 57, + 197, + 216, + 229, + 27, + 206, + 26, + 170, + 184, + 115, + 79, + 82, + 121, + 35, + 186, + 133, + 72, + 179, + 73, + 15, + 118, + 222, + 208, + 15, + 245, + 0, + 234, + 12, + 132, + 161, + 169, + 178, + 13, + 15, + 46, + 14, + 156, + 102, + 12, + 21, + 17, + 233, + 100, + 1, + 61, + 83, + 215, + 93, + 128, + 237, + 62, + 184, + 201, + 133, + 37, + 143, + 164, + 79, + 224, + 115, + 163, + 65, + 66, + 5, + 119, + 0, + 146, + 98, + 149, + 11, + 155, + 163, + 193, + 145, + 56, + 219, + 136, + 158, + 141, + 62, + 77, + 151, + 211, + 123, + 28, + 171, + 88, + 41, + 70, + 67, + 11, + 20, + 64, + 58, + 178, + 181, + 102, + 249, + 222, + 80, + 242, + 162, + 108, + 67, + 52, + 173, + 0, + 182, + 210, + 172, + 108, + 78, + 114, + 208, + 117, + 60, + 237, + 114, + 109, + 111, + 244, + 84, + 65, + 77, + 66, + 150, + 225, + 254, + 13, + 130, + 191, + 63, + 50, + 128, + 23, + 93, + 135, + 180, + 32, + 92, + 183, + 79, + 10, + 104, + 108, + 67, + 114, + 145, + 100, + 16, + 151, + 200, + 22, + 46, + 134, + 163, + 241, + 181, + 68, + 65, + 230, + 126, + 62, + 79, + 82, + 77, + 128, + 138, + 104, + 114, + 83, + 45, + 64, + 43, + 106, + 57, + 172, + 113, + 154, + 114, + 142, + 5, + 126, + 197, + 182, + 94, + 154, + 23, + 46, + 145, + 218, + 185, + 14, + 151, + 51, + 119, + 73, + 135, + 87, + 21, + 114, + 205, + 103, + 74, + 85, + 22, + 251, + 116, + 151, + 100, + 14, + 58, + 89, + 112, + 116, + 234, + 79, + 94, + 155, + 192, + 214, + 150, + 47, + 202, + 124, + 139, + 150, + 176, + 218, + 149, + 130, + 108, + 14, + 242, + 37, + 20, + 110, + 139, + 7, + 192, + 82, + 15, + 45, + 236, + 21, + 154, + 214, + 221, + 91, + 34, + 248, + 31, + 242, + 232, + 184, + 35, + 130, + 146, + 35, + 104, + 89, + 172, + 116, + 185, + 81, + 57, + 178, + 7, + 246, + 43, + 243, + 137, + 196, + 171, + 226, + 224, + 193, + 123, + 221, + 171, + 122, + 26, + 121, + 84, + 57, + 173, + 194, + 246, + 118, + 232, + 25, + 183, + 70, + 32, + 92, + 55, + 196, + 115, + 163, + 139, + 232, + 103, + 127, + 34, + 115, + 57, + 164, + 88, + 37, + 30, + 179, + 126, + 107, + 54, + 233, + 27, + 43, + 27, + 98, + 32, + 74, + 100, + 167, + 178, + 132, + 252, + 154, + 6, + 84, + 202, + 162, + 209, + 29, + 234, + 33, + 237, + 45, + 221, + 243, + 190, + 121, + 132, + 152, + 173, + 39, + 34, + 150, + 194, + 239, + 185, + 45, + 21, + 62, + 216, + 115, + 180, + 66, + 164, + 205, + 193, + 4, + 225, + 99, + 106, + 183, + 58, + 150, + 56, + 100, + 90, + 49, + 240, + 242, + 80, + 238, + 87, + 163, + 72, + 87, + 113, + 108, + 158, + 142, + 43, + 198, + 151, + 118, + 116, + 96, + 156, + 122, + 6, + 184, + 242, + 96, + 224, + 246, + 10, + 113, + 96, + 131, + 20, + 78, + 110, + 202, + 159, + 153, + 229, + 246, + 36, + 134, + 164, + 219, + 225, + 50, + 73, + 18, + 62, + 249, + 228, + 203, + 38, + 27, + 107, + 17, + 88, + 55, + 251, + 169, + 152, + 50, + 205, + 23, + 2, + 178, + 220, + 99, + 54, + 28, + 56, + 254, + 22, + 148, + 68, + 203, + 58, + 98, + 247, + 220, + 76, + 65, + 63, + 152, + 205, + 133, + 244, + 224, + 141, + 33, + 230, + 102, + 161, + 239, + 143, + 193, + 190, + 87, + 161, + 239, + 68, + 179, + 127, + 126, + 28, + 80, + 227, + 15, + 106, + 28, + 182, + 201, + 113, + 122, + 49, + 186, + 95, + 210, + 65, + 218, + 45, + 93, + 252, + 166, + 49, + 160, + 176, + 226, + 184, + 47, + 209, + 163, + 207, + 61, + 19, + 210, + 52, + 36, + 4, + 181, + 138, + 191, + 173, + 91, + 248, + 177, + 107, + 196, + 41, + 180, + 33, + 119, + 214, + 154, + 67, + 3, + 247, + 196, + 57, + 93, + 244, + 68, + 97, + 229, + 140, + 67, + 64, + 250, + 3, + 20, + 99, + 61, + 70, + 77, + 200, + 250, + 195, + 61, + 84, + 21, + 204, + 151, + 175, + 81, + 25, + 74, + 205, + 92, + 141, + 25, + 31, + 99, + 60, + 84, + 48, + 27, + 126, + 187, + 83, + 245, + 78, + 162, + 168, + 100, + 196, + 80, + 113, + 104, + 46, + 35, + 150, + 168, + 232, + 124, + 157, + 75, + 202, + 222, + 13, + 81, + 66, + 161, + 105, + 60, + 21, + 152, + 114, + 129, + 28, + 254, + 66, + 147, + 32, + 124, + 238, + 233, + 39, + 63, + 39, + 32, + 99, + 126, + 210, + 96, + 212, + 43, + 195, + 240, + 79, + 148, + 207, + 61, + 3, + 71, + 89, + 46, + 179, + 97, + 187, + 102, + 130, + 234, + 78, + 150, + 25, + 102, + 72, + 232, + 145, + 188, + 151, + 28, + 138, + 103, + 106, + 64, + 51, + 41, + 166, + 184, + 184, + 92, + 123, + 133, + 85, + 36, + 68, + 201, + 101, + 229, + 220, + 109, + 3, + 202, + 148, + 186, + 83, + 45, + 169, + 5, + 73, + 138, + 171, + 39, + 107, + 50, + 221, + 123, + 137, + 51, + 107, + 100, + 48, + 246, + 232, + 181, + 102, + 57, + 241, + 118, + 91, + 243, + 27, + 147, + 76, + 79, + 115, + 186, + 21, + 99, + 177, + 243, + 125, + 2, + 246, + 128, + 113, + 250, + 76, + 155, + 4, + 122, + 7, + 188, + 162, + 39, + 111, + 249, + 217, + 20, + 139, + 131, + 167, + 203, + 60, + 139, + 132, + 33, + 11, + 63, + 31, + 14, + 208, + 95, + 254, + 3, + 121, + 194, + 56, + 119, + 139, + 145, + 180, + 214, + 177, + 72, + 30, + 159, + 50, + 213, + 192, + 139, + 249, + 232, + 140, + 113, + 188, + 174, + 20, + 132, + 203, + 197, + 25, + 16, + 238, + 102, + 150, + 6, + 4, + 209, + 41, + 145, + 58, + 96, + 207, + 130, + 77, + 78, + 99, + 79, + 89, + 25, + 222, + 177, + 191, + 145, + 21, + 215, + 99, + 184, + 126, + 208, + 33, + 110, + 27, + 90, + 219, + 199, + 176, + 191, + 42, + 49, + 160, + 197, + 39, + 175, + 98, + 110, + 43, + 167, + 165, + 23, + 185, + 232, + 151, + 150, + 150, + 163, + 1, + 238, + 106, + 224, + 184, + 182, + 111, + 187, + 15, + 54, + 228, + 182, + 104, + 195, + 239, + 214, + 191, + 88, + 251, + 170, + 93, + 80, + 125, + 67, + 134, + 135, + 111, + 172, + 43, + 67, + 107, + 119, + 180, + 79, + 3, + 196, + 23, + 167, + 136, + 153, + 57, + 213, + 196, + 196, + 45, + 124, + 153, + 3, + 41, + 40, + 176, + 120, + 248, + 158, + 194, + 78, + 83, + 181, + 185, + 39, + 7, + 225, + 250, + 86, + 62, + 151, + 38, + 72, + 213, + 116, + 104, + 171, + 113, + 163, + 248, + 122, + 1, + 138, + 194, + 164, + 219, + 85, + 209, + 219, + 187, + 50, + 42, + 224, + 68, + 176, + 15, + 36, + 247, + 114, + 77, + 141, + 211, + 244, + 90, + 112, + 230, + 179, + 120, + 247, + 81, + 111, + 197, + 39, + 82, + 9, + 75, + 235, + 110, + 14, + 70, + 156, + 98, + 89, + 189, + 50, + 233, + 80, + 161, + 190, + 114, + 86, + 100, + 138, + 94, + 67, + 239, + 194, + 223, + 96, + 5, + 224, + 44, + 71, + 159, + 121, + 236, + 221, + 202, + 73, + 32, + 154, + 241, + 116, + 101, + 167, + 167, + 79, + 18, + 181, + 17, + 93, + 253, + 149, + 89, + 217, + 153, + 171, + 72, + 190, + 27, + 37, + 146, + 14, + 64, + 194, + 120, + 213, + 202, + 42, + 206, + 107, + 101, + 108, + 134, + 97, + 43, + 146, + 116, + 205, + 68, + 213, + 174, + 224, + 44, + 172, + 5, + 196, + 130, + 94, + 228, + 195, + 207, + 147, + 235, + 239, + 46, + 175, + 92, + 201, + 161, + 82, + 51, + 252, + 82, + 116, + 133, + 223, + 20, + 14, + 216, + 98, + 222, + 196, + 39, + 13, + 27, + 161, + 67, + 10, + 149, + 141, + 146, + 115, + 119, + 78, + 69, + 15, + 84, + 1, + 2, + 23, + 71, + 128, + 53, + 62, + 223, + 220, + 224, + 197, + 124, + 50, + 145, + 254, + 19, + 14, + 44, + 1, + 115, + 147, + 42, + 124, + 41, + 33, + 170, + 115, + 249, + 3, + 93, + 119, + 101, + 41, + 106, + 240, + 95, + 57, + 46, + 4, + 98, + 146, + 125, + 233, + 222, + 250, + 234, + 223, + 97, + 123, + 145, + 254, + 64, + 113, + 36, + 50, + 26, + 159, + 225, + 18, + 109, + 88, + 158, + 143, + 3, + 57, + 252, + 158, + 191, + 231, + 83, + 251, + 209, + 107, + 178, + 194, + 143, + 126, + 117, + 255, + 224, + 241, + 200, + 152, + 201, + 185, + 81, + 29, + 21, + 219, + 67, + 129, + 25, + 205, + 21, + 146, + 67, + 175, + 234, + 89, + 220, + 8, + 172, + 22, + 57, + 40, + 169, + 23, + 64, + 52, + 231, + 154, + 141, + 29, + 204, + 201, + 58, + 151, + 249, + 77, + 140, + 111, + 198, + 175, + 48, + 31, + 224, + 170, + 32, + 5, + 68, + 238, + 118, + 42, + 33, + 89, + 47, + 198, + 40, + 31, + 50, + 60, + 13, + 229, + 203, + 67, + 120, + 108, + 87, + 32, + 228, + 175, + 13, + 55, + 136, + 191, + 214, + 158, + 83, + 218, + 106, + 118, + 21, + 233, + 74, + 248, + 100, + 8, + 157, + 92, + 103, + 252, + 151, + 66, + 174, + 151, + 22, + 117, + 205, + 70, + 229, + 21, + 29, + 170, + 14, + 233, + 155, + 143, + 49, + 105, + 247, + 24, + 17, + 16, + 196, + 56, + 72, + 95, + 121, + 163, + 157, + 52, + 46, + 173, + 253, + 93, + 138, + 221, + 117, + 5, + 99, + 92, + 14, + 39, + 38, + 67, + 239, + 115, + 204, + 61, + 47, + 200, + 203, + 127, + 10, + 38, + 164, + 13, + 18, + 62, + 63, + 203, + 120, + 23, + 194, + 161, + 178, + 252, + 241, + 138, + 250, + 8, + 72, + 78, + 223, + 42, + 29, + 219, + 88, + 221, + 13, + 134, + 89, + 78, + 222, + 137, + 19, + 174, + 228, + 248, + 248, + 43, + 31, + 45, + 240, + 6, + 158, + 89, + 9, + 195, + 29, + 1, + 212, + 173, + 33, + 41, + 33, + 83, + 214, + 223, + 110, + 177, + 140, + 177, + 154, + 108, + 232, + 43, + 92, + 141, + 51, + 62, + 42, + 167, + 118, + 185, + 138, + 28, + 2, + 246, + 24, + 78, + 149, + 17, + 42, + 49, + 106, + 147, + 168, + 115, + 118, + 145, + 55, + 55, + 204, + 71, + 119, + 145, + 141, + 232, + 26, + 111, + 199, + 120, + 255, + 118, + 148, + 79, + 87, + 156, + 89, + 111, + 216, + 116, + 188, + 162, + 64, + 73, + 23, + 111, + 155, + 27, + 228, + 47, + 233, + 167, + 86, + 9, + 2, + 8, + 7, + 22, + 22, + 14, + 227, + 113, + 63, + 120, + 48, + 205, + 182, + 51, + 128, + 166, + 226, + 174, + 166, + 117, + 161, + 154, + 97, + 80, + 183, + 179, + 191, + 32, + 243, + 185, + 139, + 38, + 170, + 246, + 242, + 7, + 86, + 146, + 211, + 118, + 45, + 98, + 86, + 162, + 142, + 45, + 141, + 65, + 240, + 14, + 201, + 50, + 136, + 47, + 22, + 213, + 217, + 155, + 161, + 165, + 119, + 26, + 230, + 234, + 63, + 236, + 61, + 152, + 65, + 39, + 73, + 5, + 88, + 191, + 126, + 22, + 183, + 134, + 113, + 115, + 125, + 118, + 56, + 58, + 60, + 81, + 167, + 42, + 161, + 112, + 95, + 134, + 170, + 64, + 14, + 28, + 55, + 48, + 198, + 194, + 15, + 68, + 79, + 15, + 228, + 4, + 81, + 69, + 39, + 186, + 12, + 123, + 61, + 112, + 164, + 2, + 7, + 109, + 13, + 47, + 149, + 29, + 238, + 193, + 120, + 196, + 121, + 130, + 170, + 26, + 75, + 31, + 25, + 221, + 197, + 127, + 189, + 11, + 181, + 23, + 251, + 15, + 104, + 194, + 169, + 254, + 93, + 92, + 48, + 247, + 48, + 44, + 107, + 101, + 168, + 41, + 149, + 56, + 88, + 144, + 116, + 113, + 80, + 201, + 40, + 228, + 28, + 148, + 209, + 89, + 124, + 154, + 2, + 97, + 24, + 203, + 22, + 105, + 12, + 161, + 104, + 5, + 159, + 215, + 147, + 252, + 209, + 73, + 30, + 79, + 143, + 159, + 237, + 198, + 226, + 244, + 10, + 146, + 156, + 71, + 118, + 200, + 251, + 185, + 121, + 12, + 4, + 149, + 114, + 35, + 127, + 205, + 140, + 35, + 177, + 57, + 11, + 53, + 204, + 131, + 79, + 213, + 130, + 108, + 209, + 139, + 166, + 16, + 88, + 106, + 217, + 55, + 57, + 146, + 44, + 168, + 16, + 116, + 113, + 140, + 66, + 12, + 115, + 203, + 224, + 113, + 19, + 213, + 55, + 32, + 148, + 213, + 136, + 167, + 197, + 251, + 161, + 82, + 115, + 220, + 55, + 203, + 127, + 238, + 218, + 145, + 79, + 52, + 203, + 123, + 67, + 228, + 19, + 20, + 228, + 119, + 36, + 210, + 227, + 223, + 150, + 106, + 145, + 117, + 72, + 243, + 93, + 12, + 55, + 234, + 181, + 75, + 18, + 97, + 172, + 23, + 43, + 232, + 253, + 172, + 124, + 179, + 120, + 0, + 144, + 174, + 241, + 125, + 62, + 0, + 117, + 180, + 216, + 70, + 37, + 108, + 220, + 251, + 157, + 225, + 87, + 141, + 65, + 57, + 69, + 206, + 190, + 80, + 121, + 239, + 88, + 52, + 171, + 107, + 153, + 36, + 161, + 180, + 50, + 94, + 237, + 82, + 222, + 210, + 207, + 85, + 4, + 65, + 171, + 149, + 23, + 214, + 163, + 34, + 100, + 169, + 0, + 18, + 82, + 108, + 48, + 240, + 254, + 81, + 245, + 146, + 167, + 246, + 115, + 66, + 16, + 19, + 31, + 61, + 205, + 178, + 194, + 201, + 151, + 239, + 148, + 227, + 98, + 175, + 69, + 39, + 5, + 148, + 19, + 171, + 153, + 67, + 32, + 242, + 239, + 120, + 75, + 25, + 252, + 85, + 27, + 145, + 158, + 146, + 228, + 114, + 44, + 184, + 58, + 42, + 145, + 82, + 222, + 227, + 0, + 85, + 232, + 188, + 134, + 89, + 13, + 239, + 190, + 103, + 252, + 122, + 57, + 58, + 48, + 238, + 35, + 55, + 124, + 43, + 197, + 33, + 163, + 216, + 7, + 51, + 10, + 248, + 83, + 114, + 117, + 91, + 175, + 55, + 122, + 129, + 175, + 22, + 50, + 176, + 204, + 76, + 124, + 180, + 162, + 121, + 83, + 237, + 148, + 38, + 255, + 134, + 204, + 105, + 160, + 252, + 181, + 4, + 215, + 224, + 53, + 13, + 64, + 31, + 176, + 187, + 226, + 55, + 2, + 89, + 90, + 229, + 88, + 150, + 151, + 154, + 134, + 44, + 197, + 222, + 27, + 135, + 114, + 29, + 213, + 13, + 123, + 172, + 4, + 244, + 105, + 81, + 43, + 108, + 24, + 171, + 61, + 124, + 50, + 147, + 145, + 154, + 68, + 24, + 160, + 206, + 187, + 215, + 88, + 169, + 67, + 13, + 105, + 187, + 170, + 28, + 168, + 144, + 202, + 146, + 162, + 168, + 233, + 210, + 157, + 235, + 238, + 125, + 54, + 161, + 242, + 182, + 30, + 6, + 76, + 254, + 239, + 39, + 201, + 71, + 209, + 186, + 139, + 188, + 236, + 16, + 92, + 89, + 248, + 77, + 200, + 126, + 29, + 18, + 24, + 130, + 174, + 231, + 197, + 185, + 142, + 255, + 182, + 137, + 201, + 136, + 102, + 133, + 187, + 227, + 4, + 189, + 71, + 238, + 179, + 205, + 93, + 113, + 49, + 219, + 21, + 180, + 207, + 1, + 92, + 88, + 244, + 11, + 95, + 207, + 98, + 101, + 255, + 79, + 103, + 182, + 102, + 184, + 113, + 202, + 60, + 234, + 36, + 81, + 168, + 42, + 129, + 136, + 12, + 129, + 232, + 188, + 57, + 187, + 228, + 69, + 139, + 113, + 240, + 121, + 174, + 54, + 138, + 102, + 20, + 109, + 192, + 62, + 35, + 160, + 60, + 212, + 85, + 249, + 223, + 234, + 128, + 91, + 71, + 231, + 191, + 232, + 73, + 55, + 192, + 38, + 151, + 62, + 159, + 173, + 130, + 5, + 116, + 32, + 58, + 72, + 95, + 147, + 51, + 94, + 32, + 9, + 16, + 192, + 94, + 132, + 113, + 140, + 201, + 161, + 123, + 130, + 179, + 127, + 4, + 201, + 147, + 77, + 6, + 235, + 216, + 5, + 171, + 141, + 146, + 163, + 11, + 241, + 228, + 108, + 127, + 167, + 206, + 19, + 4, + 218, + 207, + 244, + 163, + 41, + 53, + 103, + 31, + 130, + 13, + 117, + 33, + 136, + 56, + 142, + 162, + 240, + 211, + 195, + 226, + 81, + 155, + 152, + 13, + 30, + 61, + 55, + 20, + 195, + 122, + 241, + 80, + 252, + 141, + 136, + 119, + 119, + 25, + 199, + 44, + 211, + 224, + 207, + 200, + 206, + 244, + 9, + 69, + 189, + 248, + 108, + 222, + 14, + 137, + 179, + 227, + 220, + 221, + 181, + 156, + 143, + 112, + 242, + 88, + 64, + 183, + 226, + 120, + 85, + 150, + 156, + 63, + 241, + 7, + 160, + 177, + 196, + 107, + 144, + 151, + 164, + 166, + 8, + 76, + 88, + 164, + 35, + 245, + 88, + 161, + 126, + 9, + 81, + 173, + 27, + 99, + 60, + 31, + 209, + 215, + 167, + 178, + 250, + 174, + 63, + 249, + 58, + 150, + 117, + 98, + 52, + 45, + 121, + 25, + 131, + 156, + 171, + 170, + 78, + 183, + 135, + 197, + 248, + 70, + 88, + 207, + 164, + 32, + 96, + 105, + 108, + 209, + 253, + 80, + 148, + 25, + 93, + 190, + 72, + 105, + 192, + 18, + 198, + 167, + 120, + 50, + 119, + 163, + 7, + 185, + 74, + 70, + 125, + 15, + 128, + 190, + 244, + 9, + 181, + 45, + 25, + 236, + 164, + 191, + 117, + 239, + 128, + 109, + 184, + 46, + 139, + 149, + 252, + 50, + 137, + 179, + 132, + 69, + 119, + 254, + 250, + 104, + 166, + 160, + 218, + 66, + 109, + 49, + 63, + 151, + 132, + 37, + 116, + 10, + 236, + 70, + 64, + 28, + 47, + 253, + 245, + 134, + 240, + 181, + 87, + 126, + 192, + 59, + 66, + 212, + 2, + 6, + 178, + 225, + 87, + 11, + 133, + 55, + 123, + 192, + 249, + 144, + 25, + 81, + 30, + 72, + 53, + 91, + 160, + 139, + 244, + 92, + 119, + 120, + 221, + 211, + 178, + 103, + 161, + 125, + 187, + 67, + 81, + 54, + 111, + 19, + 232, + 108, + 40, + 164, + 247, + 28, + 54, + 157, + 189, + 79, + 51, + 42, + 154, + 114, + 80, + 124, + 121, + 170, + 67, + 194, + 39, + 15, + 4, + 110, + 17, + 192, + 9, + 17, + 229, + 131, + 34, + 38, + 157, + 12, + 73, + 115, + 238, + 222, + 125, + 206, + 129, + 49, + 156, + 59, + 120, + 221, + 250, + 4, + 41, + 70, + 51, + 52, + 166, + 186, + 215, + 117, + 64, + 4, + 144, + 249, + 236, + 67, + 25, + 77, + 58, + 144, + 133, + 8, + 116, + 69, + 66, + 242, + 214, + 39, + 180, + 69, + 164, + 144, + 181, + 182, + 42, + 22, + 35, + 81, + 2, + 220, + 154, + 156, + 38, + 217, + 38, + 237, + 99, + 16, + 159, + 93, + 135, + 64, + 177, + 18, + 187, + 203, + 0, + 175, + 81, + 2, + 49, + 37, + 124, + 25, + 114, + 4, + 214, + 64, + 228, + 122, + 133, + 238, + 221, + 212, + 216, + 42, + 3, + 94, + 79, + 175, + 228, + 59, + 100, + 225, + 165, + 85, + 69, + 32, + 70, + 41, + 109, + 93, + 215, + 128, + 140, + 135, + 147, + 255, + 9, + 9, + 8, + 7, + 141, + 213, + 92, + 79, + 9, + 225, + 126, + 73, + 236, + 17, + 96, + 148, + 208, + 48, + 184, + 151, + 182, + 56, + 57, + 130, + 202, + 45, + 209, + 93, + 206, + 207, + 44, + 105, + 229, + 69, + 207, + 12, + 134, + 198, + 221, + 174, + 195, + 2, + 100, + 88, + 144, + 66, + 91, + 3, + 158, + 98, + 115, + 241, + 119, + 191, + 192, + 127, + 130, + 26, + 27, + 129, + 168, + 214, + 246, + 26, + 206, + 127, + 189, + 208, + 84, + 215, + 223, + 147, + 8, + 246, + 108, + 130, + 119, + 204, + 63, + 108, + 93, + 244, + 29, + 185, + 137, + 101, + 6, + 147, + 117, + 27, + 159, + 130, + 17, + 171, + 158, + 64, + 14, + 72, + 154, + 121, + 227, + 157, + 110, + 11, + 115, + 60, + 85, + 177, + 230, + 158, + 85, + 175, + 195, + 8, + 49, + 100, + 27, + 142, + 16, + 232, + 123, + 48, + 212, + 140, + 233, + 22, + 171, + 7, + 251, + 5, + 18, + 64, + 48, + 140, + 52, + 232, + 165, + 248, + 60, + 44, + 145, + 5, + 166, + 145, + 162, + 159, + 217, + 178, + 129, + 234, + 244, + 180, + 90, + 56, + 6, + 165, + 212, + 35, + 223, + 144, + 214, + 240, + 128, + 131, + 193, + 142, + 54, + 239, + 243, + 40, + 216, + 89, + 88, + 16, + 112, + 66, + 9, + 182, + 215, + 229, + 65, + 128, + 25, + 117, + 38, + 87, + 245, + 154, + 76, + 50, + 67, + 225, + 89, + 87, + 166, + 183, + 228, + 3, + 100, + 88, + 116, + 5, + 193, + 125, + 238, + 80, + 6, + 144, + 227, + 183, + 134, + 78, + 153, + 51, + 160, + 60, + 6, + 75, + 167, + 100, + 156, + 212, + 193, + 126, + 190, + 29, + 251, + 68, + 90, + 220, + 123, + 75, + 26, + 79, + 22, + 243, + 240, + 85, + 81, + 193, + 35, + 186, + 39, + 138, + 61, + 131, + 151, + 187, + 107, + 103, + 5, + 195, + 153, + 246, + 10, + 196, + 175, + 87, + 222, + 203, + 196, + 169, + 101, + 155, + 130, + 198, + 6, + 131, + 45, + 30, + 82, + 38, + 202, + 192, + 20, + 137, + 164, + 78, + 8, + 88, + 75, + 71, + 158, + 124, + 100, + 142, + 228, + 126, + 161, + 197, + 218, + 116, + 38, + 156, + 185, + 198, + 224, + 117, + 85, + 187, + 218, + 245, + 31, + 62, + 52, + 238, + 165, + 150, + 3, + 171, + 38, + 81, + 34, + 26, + 139, + 145, + 70, + 134, + 183, + 226, + 162, + 96, + 245, + 218, + 165, + 226, + 215, + 202, + 156, + 173, + 128, + 46, + 247, + 32, + 153, + 176, + 142, + 59, + 148, + 150, + 69, + 48, + 50, + 147, + 201, + 113, + 48, + 247, + 132, + 170, + 81, + 7, + 26, + 234, + 225, + 120, + 27, + 8, + 220, + 237, + 210, + 193, + 27, + 102, + 112, + 72, + 144, + 3, + 204, + 147, + 206, + 65, + 129, + 21, + 183, + 241, + 216, + 8, + 185, + 61, + 45, + 42, + 236, + 166, + 185, + 25, + 196, + 120, + 121, + 145, + 124, + 77, + 177, + 237, + 123, + 232, + 220, + 196, + 142, + 27, + 114, + 179, + 123, + 49, + 41, + 64, + 6, + 245, + 161, + 74, + 89, + 251, + 39, + 179, + 163, + 16, + 124, + 126, + 241, + 120, + 255, + 246, + 237, + 202, + 24, + 107, + 92, + 169, + 166, + 88, + 199, + 204, + 65, + 253, + 2, + 237, + 252, + 38, + 66, + 90, + 57, + 72, + 220, + 202, + 140, + 194, + 132, + 245, + 208, + 82, + 215, + 212, + 81, + 112, + 229, + 224, + 178, + 106, + 77, + 231, + 174, + 175, + 82, + 49, + 205, + 19, + 241, + 249, + 46, + 228, + 169, + 72, + 23, + 28, + 70, + 144, + 24, + 60, + 163, + 124, + 2, + 47, + 80, + 3, + 129, + 3, + 69, + 142, + 9, + 74, + 28, + 142, + 150, + 203, + 175, + 26, + 37, + 215, + 140, + 27, + 113, + 80, + 10, + 119, + 103, + 51, + 156, + 17, + 69, + 147, + 185, + 77, + 239, + 202, + 9, + 148, + 247, + 154, + 125, + 149, + 95, + 20, + 176, + 10, + 0, + 217, + 38, + 17, + 154, + 46, + 8, + 209, + 216, + 41, + 6, + 191, + 3, + 38, + 191, + 110, + 205, + 32, + 96, + 21, + 77, + 177, + 42, + 245, + 200, + 125, + 6, + 249, + 4, + 176, + 242, + 204, + 189, + 11, + 164, + 65, + 198, + 235, + 120, + 217, + 243, + 158, + 84, + 85, + 48, + 13, + 125, + 27, + 225, + 11, + 35, + 132, + 80, + 223, + 34, + 82, + 255, + 1, + 167, + 51, + 97, + 175, + 250, + 164, + 198, + 209, + 144, + 113, + 109, + 56, + 254, + 223, + 50, + 101, + 33, + 118, + 239, + 81, + 107, + 145, + 204, + 9, + 93, + 160, + 33, + 10, + 168, + 76, + 104, + 95, + 62, + 83, + 22, + 104, + 121, + 172, + 100, + 119, + 165, + 112, + 194, + 171, + 90, + 129, + 208, + 74, + 49, + 122, + 183, + 12, + 51, + 126, + 240, + 39, + 230, + 162, + 6, + 73, + 44, + 25, + 250, + 138, + 49, + 35, + 187, + 30, + 43, + 170, + 142, + 9, + 67, + 243, + 40, + 83, + 24, + 240, + 152, + 164, + 85, + 162, + 67, + 104, + 232, + 94, + 244, + 85, + 173, + 72, + 46, + 177, + 43, + 148, + 40, + 100, + 200, + 168, + 223, + 145, + 144, + 200, + 85, + 86, + 113, + 76, + 188, + 23, + 176, + 57, + 151, + 38, + 98, + 56, + 95, + 16, + 239, + 240, + 49, + 219, + 199, + 115, + 96, + 120, + 147, + 121, + 243, + 36, + 253, + 87, + 98, + 19, + 174, + 99, + 185, + 201, + 193, + 79, + 48, + 178, + 144, + 214, + 248, + 16, + 108, + 20, + 242, + 79, + 157, + 5, + 211, + 11, + 134, + 117, + 243, + 121, + 202, + 235, + 24, + 234, + 170, + 168, + 149, + 154, + 191, + 158, + 99, + 132, + 142, + 38, + 166, + 135, + 133, + 143, + 136, + 82, + 97, + 147, + 71, + 114, + 25, + 132, + 227, + 93, + 213, + 116, + 57, + 13, + 10, + 131, + 10, + 251, + 154, + 19, + 21, + 96, + 124, + 12, + 247, + 21, + 194, + 10, + 189, + 89, + 1, + 67, + 123, + 203, + 210, + 245, + 68, + 15, + 156, + 146, + 209, + 239, + 232, + 185, + 226, + 180, + 107, + 223, + 194, + 186, + 223, + 137, + 22, + 23, + 13, + 63, + 142, + 130, + 55, + 216, + 209, + 242, + 35, + 109, + 159, + 41, + 205, + 13, + 74, + 85, + 223, + 60, + 229, + 50, + 178, + 202, + 234, + 244, + 6, + 1, + 46, + 51, + 202, + 169, + 63, + 178, + 205, + 154, + 11, + 145, + 194, + 165, + 71, + 209, + 133, + 210, + 173, + 245, + 254, + 63, + 160, + 57, + 148, + 122, + 95, + 162, + 153, + 251, + 115, + 168, + 73, + 195, + 160, + 95, + 48, + 115, + 37, + 71, + 249, + 215, + 122, + 248, + 206, + 126, + 160, + 166, + 51, + 88, + 78, + 161, + 111, + 44, + 237, + 26, + 211, + 1, + 192, + 192, + 135, + 57, + 46, + 24, + 10, + 167, + 254, + 231, + 235, + 212, + 208, + 27, + 153, + 180, + 118, + 117, + 220, + 231, + 236, + 103, + 150, + 29, + 71, + 170, + 192, + 93, + 242, + 7, + 45, + 244, + 0, + 145, + 171, + 90, + 136, + 214, + 177, + 122, + 151, + 196, + 46, + 69, + 49, + 220, + 140, + 189, + 44, + 144, + 126, + 35, + 36, + 43, + 247, + 21, + 80, + 88, + 52, + 195, + 200, + 79, + 90, + 64, + 116, + 184, + 129, + 55, + 34, + 213, + 218, + 62, + 93, + 86, + 87, + 212, + 132, + 240, + 143, + 29, + 242, + 179, + 35, + 199, + 164, + 71, + 50, + 181, + 179, + 162, + 246, + 196, + 133, + 54, + 163, + 99, + 17, + 250, + 246, + 87, + 39, + 172, + 230, + 33, + 14, + 119, + 142, + 196, + 63, + 7, + 114, + 251, + 142, + 196, + 107, + 67, + 236, + 82, + 175, + 86, + 185, + 211, + 47, + 33, + 149, + 101, + 140, + 102, + 39, + 8, + 224, + 70, + 195, + 239, + 64, + 162, + 212, + 6, + 53, + 224, + 185, + 152, + 20, + 239, + 30, + 29, + 60, + 248, + 177, + 66, + 88, + 12, + 145, + 123, + 29, + 159, + 136, + 26, + 116, + 96, + 198, + 71, + 249, + 42, + 146, + 62, + 87, + 122, + 54, + 52, + 10, + 194, + 238, + 217, + 244, + 10, + 60, + 81, + 66, + 52, + 2, + 23, + 217, + 134, + 221, + 22, + 30, + 39, + 84, + 12, + 119, + 103, + 138, + 238, + 213, + 224, + 32, + 116, + 7, + 104, + 198, + 116, + 229, + 143, + 251, + 199, + 152, + 128, + 156, + 216, + 176, + 180, + 164, + 100, + 146, + 8, + 119, + 128, + 223, + 61, + 75, + 65, + 121, + 66, + 156, + 184, + 198, + 51, + 249, + 19, + 52, + 226, + 132, + 21, + 155, + 221, + 191, + 12, + 210, + 193, + 4, + 15, + 115, + 193, + 129, + 192, + 167, + 140, + 74, + 182, + 114, + 102, + 49, + 13, + 156, + 161, + 255, + 187, + 227, + 66, + 229, + 52, + 212, + 89, + 118, + 70, + 48, + 115, + 77, + 43, + 66, + 84, + 52, + 114, + 208, + 24, + 5, + 146, + 11, + 227, + 171, + 126, + 150, + 85, + 232, + 46, + 56, + 161, + 122, + 183, + 162, + 84, + 179, + 223, + 49, + 53, + 196, + 191, + 226, + 137, + 239, + 209, + 37, + 191, + 113, + 7, + 157, + 33, + 250, + 74, + 53, + 185, + 92, + 188, + 103, + 69, + 57, + 93, + 63, + 25, + 90, + 217, + 181, + 197, + 239, + 197, + 149, + 254, + 38, + 222, + 32, + 225, + 248, + 104, + 220, + 193, + 212, + 225, + 233, + 235, + 124, + 135, + 166, + 104, + 19, + 147, + 3, + 30, + 20, + 99, + 111, + 175, + 229, + 81, + 105, + 91, + 1, + 86, + 116, + 34, + 202, + 165, + 92, + 12, + 152, + 0, + 176, + 55, + 238, + 92, + 35, + 90, + 119, + 162, + 206, + 49, + 53, + 53, + 28, + 194, + 30, + 106, + 2, + 88, + 82, + 39, + 254, + 42, + 30, + 253, + 57, + 132, + 244, + 22, + 43, + 195, + 58, + 50, + 202, + 53, + 72, + 243, + 250, + 246, + 37, + 41, + 116, + 132, + 50, + 55, + 212, + 72, + 144, + 103, + 193, + 150, + 110, + 9, + 64, + 57, + 88, + 100, + 55, + 131, + 157, + 95, + 220, + 217, + 82, + 1, + 160, + 154, + 224, + 118, + 164, + 122, + 193, + 231, + 78, + 208, + 181, + 59, + 225, + 36, + 122, + 30, + 45, + 77, + 237, + 241, + 112, + 70, + 191, + 17, + 214, + 174, + 0, + 83, + 152, + 23, + 58, + 123, + 248, + 69, + 204, + 174, + 78, + 127, + 243, + 152, + 72, + 26, + 193, + 101, + 240, + 181, + 249, + 95, + 205, + 29, + 212, + 162, + 72, + 146, + 111, + 123, + 213, + 165, + 59, + 238, + 54, + 49, + 126, + 118, + 103, + 65, + 255, + 94, + 140, + 135, + 120, + 229, + 255, + 34, + 77, + 64, + 189, + 61, + 231, + 33, + 152, + 6, + 60, + 162, + 23, + 48, + 167, + 168, + 91, + 207, + 93, + 126, + 16, + 193, + 192, + 239, + 179, + 32, + 53, + 144, + 233, + 74, + 210, + 90, + 66, + 13, + 114, + 34, + 125, + 36, + 6, + 105, + 188, + 95, + 228, + 172, + 188, + 204, + 35, + 136, + 4, + 22, + 249, + 193, + 179, + 184, + 203, + 171, + 61, + 247, + 216, + 149, + 59, + 181, + 201, + 136, + 239, + 38, + 253, + 150, + 140, + 92, + 114, + 63, + 0, + 240, + 94, + 143, + 64, + 187, + 117, + 221, + 37, + 194, + 29, + 80, + 152, + 46, + 235, + 30, + 237, + 14, + 243, + 126, + 133, + 186, + 41, + 209, + 61, + 103, + 165, + 61, + 247, + 71, + 140, + 113, + 149, + 33, + 45, + 183, + 161, + 115, + 202, + 211, + 44, + 86, + 51, + 62, + 11, + 208, + 210, + 169, + 73, + 108, + 238, + 43, + 68, + 13, + 235, + 208, + 41, + 14, + 133, + 17, + 187, + 161, + 175, + 29, + 119, + 127, + 187, + 180, + 242, + 190, + 17, + 29, + 235, + 21, + 163, + 62, + 165, + 10, + 173, + 120, + 139, + 147, + 86, + 170, + 187, + 235, + 249, + 247, + 138, + 18, + 193, + 11, + 140, + 57, + 171, + 101, + 228, + 33, + 205, + 104, + 115, + 91, + 62, + 69, + 26, + 141, + 255, + 12, + 80, + 108, + 86, + 25, + 215, + 87, + 120, + 250, + 228, + 195, + 2, + 57, + 181, + 60, + 46, + 49, + 7, + 125, + 41, + 111, + 60, + 104, + 95, + 197, + 209, + 229, + 174, + 159, + 245, + 16, + 27, + 84, + 178, + 218, + 116, + 145, + 234, + 169, + 103, + 251, + 239, + 224, + 221, + 76, + 209, + 128, + 47, + 101, + 248, + 184, + 146, + 28, + 132, + 73, + 189, + 67, + 141, + 98, + 101, + 60, + 51, + 13, + 153, + 175, + 25, + 55, + 65, + 82, + 239, + 219, + 9, + 105, + 16, + 228, + 109, + 133, + 141, + 239, + 193, + 34, + 100, + 103, + 3, + 3, + 120, + 198, + 61, + 100, + 254, + 109, + 144, + 124, + 171, + 185, + 199, + 24, + 46, + 87, + 169, + 80, + 124, + 150, + 121, + 2, + 112, + 85, + 81, + 200, + 203, + 89, + 31, + 131, + 197, + 167, + 215, + 41, + 191, + 116, + 17, + 108, + 33, + 156, + 198, + 84, + 183, + 4, + 151, + 131, + 0, + 18, + 2, + 181, + 212, + 6, + 159, + 113, + 232, + 199, + 232, + 226, + 182, + 214, + 86, + 196, + 102, + 74, + 204, + 15, + 93, + 121, + 245, + 30, + 89, + 134, + 144, + 112, + 209, + 117, + 133, + 243, + 57, + 35, + 234, + 234, + 51, + 146, + 241, + 65, + 210, + 111, + 218, + 221, + 40, + 217, + 16, + 2, + 64, + 154, + 184, + 74, + 206, + 27, + 231, + 25, + 238, + 146, + 46, + 127, + 102, + 152, + 179, + 232, + 45, + 247, + 22, + 8, + 68, + 220, + 64, + 132, + 51, + 44, + 183, + 122, + 91, + 57, + 85, + 42, + 151, + 187, + 252, + 15, + 8, + 183, + 51, + 86, + 192, + 34, + 110, + 72, + 119, + 124, + 153, + 237, + 23, + 166, + 108, + 96, + 87, + 40, + 131, + 140, + 246, + 42, + 86, + 10, + 109, + 225, + 110, + 26, + 24, + 117, + 11, + 110, + 33, + 152, + 68, + 159, + 102, + 37, + 132, + 138, + 184, + 255, + 76, + 248, + 31, + 102, + 228, + 77, + 122, + 151, + 102, + 139, + 227, + 106, + 189, + 227, + 233, + 139, + 39, + 202, + 199, + 29, + 211, + 47, + 244, + 234, + 184, + 237, + 246, + 49, + 176, + 217, + 186, + 101, + 94, + 98, + 4, + 118, + 183, + 19, + 22, + 198, + 138, + 208, + 132, + 234, + 39, + 126, + 153, + 47, + 7, + 1, + 84, + 17, + 252, + 69, + 23, + 228, + 28, + 122, + 45, + 132, + 125, + 75, + 41, + 112, + 212, + 113, + 174, + 177, + 177, + 22, + 188, + 79, + 132, + 229, + 66, + 41, + 34, + 210, + 232, + 111, + 173, + 85, + 90, + 190, + 92, + 51, + 26, + 138, + 241, + 38, + 240, + 155, + 63, + 49, + 121, + 249, + 30, + 101, + 195, + 58, + 211, + 153, + 157, + 155, + 88, + 197, + 195, + 243, + 129, + 66, + 25, + 215, + 239, + 142, + 80, + 59, + 41, + 41, + 242, + 120, + 152, + 251, + 245, + 168, + 93, + 29, + 98, + 146, + 214, + 145, + 1, + 20, + 181, + 145, + 145, + 2, + 184, + 184, + 46, + 132, + 138, + 49, + 34, + 198, + 199, + 248, + 170, + 134, + 220, + 29, + 164, + 45, + 180, + 238, + 104, + 170, + 154, + 201, + 126, + 162, + 136, + 6, + 91, + 175, + 202, + 70, + 11, + 240, + 69, + 42, + 34, + 120, + 170, + 244, + 215, + 241, + 116, + 238, + 98, + 172, + 246, + 67, + 71, + 22, + 123, + 117, + 4, + 105, + 73, + 86, + 240, + 103, + 157, + 216, + 14, + 103, + 170, + 234, + 8, + 113, + 85, + 207, + 62, + 74, + 163, + 199, + 50, + 64, + 44, + 139, + 30, + 44, + 46, + 95, + 158, + 52, + 214, + 105, + 170, + 191, + 238, + 231, + 167, + 136, + 169, + 226, + 153, + 154, + 63, + 173, + 235, + 78, + 252, + 136, + 97, + 225, + 59, + 166, + 33, + 94, + 231, + 105, + 65, + 240, + 179, + 109, + 107, + 18, + 199, + 63, + 92, + 223, + 133, + 11, + 107, + 51, + 230, + 117, + 242, + 35, + 171, + 163, + 52, + 48, + 42, + 198, + 4, + 51, + 57, + 39, + 159, + 170, + 117, + 247, + 169, + 23, + 129, + 73, + 52, + 154, + 207, + 93, + 24, + 202, + 191, + 216, + 188, + 32, + 25, + 206, + 91, + 9, + 212, + 213, + 18, + 226, + 23, + 239, + 232, + 16, + 157, + 48, + 54, + 63, + 22, + 212, + 245, + 62, + 197, + 100, + 221, + 196, + 158, + 22, + 7, + 218, + 140, + 121, + 147, + 140, + 197, + 80, + 85, + 150, + 193, + 162, + 200, + 75, + 83, + 244, + 226, + 125, + 144, + 133, + 170, + 116, + 179, + 116, + 37, + 216, + 188, + 27, + 217, + 86, + 226, + 24, + 184, + 183, + 147, + 106, + 115, + 164, + 25, + 177, + 19, + 222, + 204, + 164, + 239, + 86, + 181, + 219, + 17, + 173, + 34, + 186, + 63, + 30, + 97, + 216, + 152, + 21, + 228, + 115, + 209, + 201, + 142, + 5, + 186, + 124, + 161, + 100, + 239, + 147, + 200, + 102, + 183, + 60, + 105, + 171, + 128, + 149, + 80, + 59, + 50, + 171, + 173, + 222, + 165, + 22, + 150, + 164, + 198, + 187, + 115, + 28, + 139, + 99, + 30, + 145, + 161, + 74, + 154, + 254, + 62, + 49, + 182, + 39, + 68, + 172, + 133, + 96, + 250, + 210, + 136, + 7, + 88, + 4, + 254, + 216, + 5, + 206, + 90, + 213, + 125, + 43, + 20, + 38, + 15, + 215, + 83, + 145, + 209, + 236, + 9, + 48, + 174, + 252, + 117, + 4, + 163, + 98, + 222, + 196, + 165, + 63, + 175, + 160, + 189, + 77, + 111, + 212, + 173, + 223, + 250, + 164, + 0, + 124, + 0, + 4, + 7, + 200, + 25, + 202, + 250, + 236, + 55, + 227, + 151, + 136, + 49, + 71, + 114, + 91, + 67, + 11, + 232, + 17, + 35, + 129, + 95, + 110, + 245, + 147, + 185, + 25, + 107, + 169, + 148, + 209, + 164, + 101, + 93, + 22, + 192, + 39, + 45, + 245, + 173, + 132, + 51, + 135, + 11, + 88, + 192, + 218, + 111, + 138, + 176, + 7, + 118, + 15, + 203, + 172, + 126, + 153, + 49, + 23, + 216, + 200, + 86, + 170, + 50, + 20, + 49, + 171, + 57, + 18, + 138, + 162, + 68, + 152, + 223, + 159, + 202, + 140, + 65, + 154, + 211, + 167, + 204, + 15, + 213, + 251, + 90, + 222, + 186, + 8, + 187, + 202, + 117, + 3, + 36, + 10, + 78, + 104, + 56, + 235, + 120, + 153, + 220, + 93, + 184, + 123, + 230, + 228, + 18, + 177, + 168, + 197, + 67, + 123, + 110, + 202, + 27, + 250, + 168, + 25, + 150, + 84, + 5, + 252, + 83, + 211, + 186, + 204, + 119, + 3, + 142, + 115, + 162, + 185, + 136, + 191, + 173, + 227, + 67, + 239, + 232, + 147, + 241, + 34, + 236, + 223, + 128, + 98, + 38, + 188, + 156, + 65, + 133, + 67, + 47, + 231, + 171, + 241, + 149, + 131, + 53, + 106, + 249, + 114, + 147, + 2, + 74, + 190, + 202, + 42, + 28, + 189, + 228, + 72, + 177, + 219, + 148, + 125, + 135, + 255, + 18, + 50, + 208, + 242, + 223, + 43, + 53, + 200, + 191, + 67, + 92, + 178, + 136, + 27, + 36, + 236, + 20, + 111, + 48, + 91, + 245, + 136, + 199, + 203, + 249, + 253, + 159, + 182, + 129, + 164, + 141, + 175, + 229, + 30, + 65, + 8, + 99, + 50, + 43, + 98, + 59, + 164, + 57, + 255, + 202, + 34, + 226, + 215, + 157, + 112, + 234, + 176, + 221, + 0, + 248, + 107, + 95, + 111, + 221, + 149, + 95, + 254, + 177, + 131, + 4, + 67, + 130, + 157, + 65, + 99, + 132, + 235, + 88, + 223, + 131, + 37, + 23, + 28, + 242, + 234, + 201, + 99, + 13, + 56, + 16, + 23, + 24, + 86, + 44, + 49, + 43, + 212, + 142, + 103, + 148, + 68, + 173, + 134, + 166, + 245, + 54, + 96, + 43, + 213, + 160, + 136, + 135, + 68, + 236, + 78, + 187, + 131, + 242, + 134, + 77, + 215, + 177, + 113, + 198, + 159, + 115, + 66, + 171, + 108, + 172, + 35, + 254, + 60, + 77, + 220, + 211, + 98, + 245, + 123, + 227, + 108, + 138, + 47, + 200, + 184, + 192, + 18, + 211, + 128, + 230, + 76, + 215, + 175, + 65, + 149, + 123, + 157, + 4, + 63, + 140, + 212, + 66, + 145, + 48, + 16, + 4, + 206, + 44, + 121, + 154, + 85, + 53, + 215, + 231, + 107, + 253, + 150, + 0, + 84, + 241, + 129, + 161, + 134, + 69, + 20, + 70, + 74, + 214, + 77, + 210, + 149, + 249, + 192, + 117, + 205, + 71, + 120, + 58, + 102, + 22, + 63, + 229, + 17, + 43, + 192, + 149, + 185, + 139, + 220, + 28, + 96, + 155, + 165, + 159, + 122, + 101, + 106, + 112, + 171, + 50, + 197, + 220, + 38, + 165, + 4, + 84, + 95, + 93, + 147, + 176, + 244, + 37, + 101, + 68, + 118, + 159, + 206, + 174, + 234, + 234, + 203, + 242, + 103, + 159, + 140, + 25, + 225, + 128, + 124, + 104, + 191, + 145, + 140, + 73, + 178, + 197, + 23, + 36, + 32, + 3, + 58, + 94, + 145, + 217, + 55, + 190, + 208, + 235, + 178, + 211, + 23, + 155, + 10, + 14, + 21, + 18, + 50, + 212, + 117, + 99, + 87, + 30, + 199, + 109, + 155, + 121, + 3, + 204, + 81, + 35, + 31, + 159, + 20, + 204, + 160, + 222, + 91, + 166, + 157, + 194, + 112, + 91, + 227, + 87, + 185, + 11, + 89, + 4, + 163, + 228, + 24, + 176, + 69, + 65, + 119, + 107, + 172, + 251, + 245, + 12, + 122, + 36, + 31, + 182, + 160, + 8, + 126, + 89, + 57, + 202, + 122, + 217, + 218, + 187, + 106, + 66, + 222, + 174, + 74, + 229, + 108, + 107, + 27, + 145, + 113, + 118, + 149, + 114, + 177, + 184, + 78, + 205, + 253, + 223, + 110, + 97, + 219, + 73, + 205, + 149, + 14, + 62, + 143, + 59, + 168, + 119, + 209, + 9, + 165, + 218, + 49, + 160, + 225, + 159, + 244, + 162, + 57, + 187, + 152, + 156, + 94, + 126, + 121, + 140, + 226, + 243, + 100, + 55, + 252, + 18, + 227, + 124, + 28, + 41, + 84, + 40, + 35, + 6, + 129, + 197, + 131, + 177, + 105, + 233, + 143, + 59, + 33, + 253, + 4, + 16, + 239, + 90, + 174, + 186, + 213, + 114, + 174, + 147, + 33, + 229, + 76, + 203, + 254, + 37, + 50, + 162, + 253, + 155, + 112, + 230, + 223, + 243, + 229, + 63, + 98, + 243, + 126, + 22, + 112, + 192, + 34, + 87, + 230, + 161, + 158, + 75, + 185, + 221, + 81, + 229, + 231, + 232, + 117, + 216, + 16, + 230, + 187, + 51, + 239, + 71, + 6, + 69, + 173, + 186, + 163, + 7, + 6, + 56, + 186, + 77, + 72, + 178, + 43, + 22, + 48, + 120, + 193, + 0, + 86, + 250, + 192, + 225, + 181, + 48, + 42, + 241, + 109, + 137, + 39, + 70, + 248, + 188, + 90, + 18, + 227, + 110, + 176, + 234, + 37, + 99, + 16, + 38, + 132, + 177, + 125, + 195, + 206, + 221, + 136, + 50, + 190, + 31, + 119, + 83, + 136, + 205, + 96, + 57, + 96, + 226, + 30, + 170, + 189, + 23, + 133, + 70, + 228, + 166, + 76, + 188, + 55, + 44, + 106, + 245, + 27, + 37, + 208, + 13, + 25, + 199, + 181, + 229, + 163, + 250, + 215, + 3, + 208, + 253, + 31, + 198, + 142, + 186, + 149, + 1, + 238, + 72, + 203, + 91, + 41, + 45, + 243, + 84, + 102, + 70, + 72, + 55, + 205, + 182, + 80, + 254, + 191, + 200, + 27, + 91, + 145, + 172, + 15, + 71, + 202, + 29, + 146, + 141, + 243, + 158, + 246, + 167, + 186, + 85, + 124, + 202, + 100, + 1, + 104, + 60, + 99, + 148, + 26, + 189, + 249, + 200, + 121, + 127, + 139, + 80, + 8, + 239, + 194, + 2, + 119, + 87, + 176, + 2, + 232, + 236, + 5, + 166, + 22, + 39, + 184, + 90, + 192, + 36, + 30, + 108, + 181, + 21, + 75, + 181, + 5, + 126, + 69, + 35, + 177, + 213, + 7, + 70, + 104, + 253, + 30, + 116, + 25, + 254, + 47, + 242, + 199, + 126, + 101, + 93, + 219, + 108, + 129, + 161, + 137, + 39, + 173, + 43, + 173, + 211, + 86, + 91, + 20, + 87, + 172, + 227, + 154, + 4, + 65, + 17, + 83, + 254, + 36, + 69, + 165, + 14, + 72, + 173, + 146, + 30, + 173, + 43, + 74, + 13, + 201, + 192, + 116, + 63, + 23, + 151, + 196, + 136, + 70, + 142, + 90, + 114, + 157, + 206, + 180, + 225, + 204, + 128, + 132, + 220, + 165, + 161, + 198, + 191, + 24, + 5, + 47, + 67, + 219, + 216, + 159, + 81, + 253, + 230, + 35, + 202, + 67, + 15, + 141, + 107, + 98, + 172, + 187, + 131, + 164, + 229, + 61, + 226, + 55, + 32, + 51, + 76, + 194, + 89, + 70, + 206, + 211, + 241, + 103, + 39, + 194, + 71, + 122, + 9, + 254, + 121, + 14, + 206, + 165, + 179, + 201, + 213, + 69, + 206, + 121, + 244, + 136, + 23, + 177, + 237, + 23, + 137, + 238, + 224, + 125, + 215, + 30, + 158, + 232, + 5, + 118, + 42, + 37, + 69, + 122, + 113, + 120, + 19, + 231, + 132, + 107, + 58, + 60, + 73, + 110, + 227, + 186, + 233, + 148, + 102, + 199, + 139, + 30, + 36, + 197, + 25, + 164, + 160, + 33, + 127, + 180, + 222, + 201, + 123, + 140, + 69, + 104, + 36, + 38, + 123, + 55, + 22, + 64, + 113, + 204, + 57, + 9, + 228, + 133, + 136, + 188, + 178, + 156, + 251, + 46, + 38, + 235, + 143, + 161, + 60, + 18, + 104, + 68, + 221, + 130, + 175, + 94, + 147, + 200, + 187, + 113, + 105, + 207, + 241, + 100, + 78, + 58, + 206, + 82, + 145, + 248, + 64, + 76, + 184, + 40, + 129, + 220, + 130, + 15, + 35, + 4, + 7, + 161, + 56, + 235, + 239, + 44, + 87, + 248, + 82, + 243, + 32, + 157, + 228, + 41, + 164, + 84, + 160, + 130, + 109, + 79, + 106, + 68, + 192, + 168, + 181, + 205, + 239, + 126, + 222, + 31, + 146, + 130, + 151, + 80, + 203, + 194, + 67, + 147, + 85, + 89, + 84, + 122, + 167, + 94, + 87, + 213, + 181, + 11, + 53, + 109, + 37, + 10, + 250, + 67, + 232, + 34, + 196, + 255, + 152, + 25, + 162, + 1, + 47, + 45, + 1, + 131, + 13, + 126, + 137, + 22, + 4, + 202, + 22, + 81, + 48, + 236, + 37, + 253, + 89, + 26, + 125, + 79, + 172, + 90, + 86, + 33, + 27, + 240, + 72, + 167, + 224, + 179, + 246, + 241, + 4, + 65, + 53, + 46, + 221, + 9, + 8, + 135, + 243, + 207, + 59, + 129, + 221, + 41, + 79, + 253, + 15, + 238, + 185, + 2, + 103, + 73, + 198, + 75, + 66, + 191, + 6, + 15, + 223, + 197, + 86, + 207, + 28, + 246, + 29, + 252, + 29, + 183, + 37, + 37, + 74, + 197, + 255, + 62, + 250, + 50, + 74, + 97, + 141, + 83, + 237, + 89, + 87, + 11, + 38, + 70, + 91, + 136, + 123, + 97, + 249, + 124, + 85, + 164, + 10, + 151, + 28, + 36, + 35, + 41, + 134, + 165, + 124, + 198, + 120, + 65, + 80, + 227, + 234, + 110, + 28, + 29, + 152, + 132, + 236, + 33, + 232, + 145, + 236, + 197, + 36, + 205, + 211, + 192, + 48, + 54, + 227, + 26, + 167, + 229, + 180, + 160, + 186, + 173, + 28, + 97, + 245, + 44, + 21, + 209, + 198, + 168, + 228, + 54, + 78, + 199, + 207, + 88, + 7, + 13, + 236, + 125, + 141, + 113, + 53, + 199, + 64, + 126, + 54, + 57, + 15, + 96, + 196, + 233, + 218, + 255, + 193, + 252, + 182, + 122, + 243, + 14, + 36, + 174, + 50, + 213, + 22, + 94, + 104, + 47, + 152, + 104, + 41, + 108, + 10, + 57, + 58, + 114, + 76, + 193, + 74, + 255, + 105, + 81, + 221, + 225, + 157, + 31, + 211, + 121, + 34, + 24, + 114, + 137, + 50, + 195, + 188, + 130, + 68, + 72, + 145, + 49, + 72, + 32, + 27, + 219, + 24, + 54, + 66, + 193, + 64, + 114, + 0, + 158, + 201, + 187, + 55, + 222, + 218, + 164, + 35, + 189, + 144, + 120, + 45, + 140, + 133, + 8, + 165, + 196, + 57, + 6, + 91, + 49, + 194, + 98, + 0, + 137, + 172, + 115, + 138, + 20, + 230, + 22, + 122, + 73, + 194, + 78, + 0, + 45, + 6, + 36, + 100, + 112, + 240, + 151, + 226, + 253, + 33, + 3, + 28, + 68, + 106, + 31, + 188, + 30, + 145, + 56, + 107, + 27, + 201, + 122, + 158, + 117, + 194, + 225, + 213, + 199, + 207, + 228, + 234, + 116, + 27, + 218, + 93, + 180, + 141, + 85, + 91, + 19, + 53, + 41, + 2, + 50, + 81, + 128, + 158, + 24, + 79, + 111, + 98, + 119, + 211, + 113, + 110, + 22, + 109, + 116, + 194, + 53, + 89, + 90, + 19, + 156, + 72, + 208, + 29, + 221, + 138, + 171, + 165, + 124, + 73, + 30, + 195, + 37, + 180, + 221, + 38, + 29, + 138, + 47, + 74, + 156, + 116, + 17, + 231, + 39, + 6, + 78, + 205, + 47, + 99, + 215, + 225, + 21, + 114, + 101, + 164, + 32, + 251, + 157, + 4, + 116, + 104, + 109, + 158, + 3, + 47, + 105, + 0, + 93, + 227, + 85, + 180, + 214, + 148, + 108, + 71, + 209, + 1, + 226, + 79, + 107, + 240, + 159, + 110, + 200, + 109, + 42, + 194, + 191, + 204, + 90, + 33, + 232, + 213, + 169, + 1, + 248, + 139, + 80, + 48, + 69, + 147, + 96, + 247, + 194, + 207, + 52, + 223, + 106, + 199, + 204, + 79, + 208, + 236, + 126, + 71, + 70, + 195, + 175, + 198, + 247, + 194, + 193, + 254, + 192, + 248, + 132, + 187, + 117, + 46, + 134, + 58, + 27, + 244, + 159, + 210, + 106, + 175, + 153, + 84, + 58, + 87, + 248, + 183, + 146, + 71, + 205, + 7, + 41, + 228, + 96, + 182, + 222, + 81, + 230, + 169, + 95, + 154, + 2, + 207, + 247, + 51, + 250, + 95, + 100, + 161, + 229, + 95, + 28, + 135, + 241, + 224, + 204, + 217, + 21, + 92, + 88, + 15, + 71, + 66, + 71, + 80, + 143, + 189, + 71, + 255, + 184, + 127, + 254, + 226, + 73, + 101, + 35, + 229, + 243, + 112, + 27, + 5, + 226, + 28, + 224, + 111, + 22, + 141, + 82, + 82, + 72, + 240, + 133, + 133, + 71, + 193, + 86, + 105, + 120, + 197, + 89, + 19, + 222, + 139, + 236, + 23, + 212, + 144, + 67, + 135, + 56, + 166, + 28, + 198, + 31, + 103, + 129, + 102, + 72, + 25, + 158, + 243, + 245, + 158, + 254, + 162, + 26, + 155, + 17, + 41, + 110, + 95, + 42, + 51, + 246, + 83, + 240, + 73, + 65, + 106, + 18, + 165, + 112, + 155, + 104, + 123, + 122, + 225, + 85, + 53, + 17, + 2, + 120, + 49, + 229, + 50, + 202, + 172, + 240, + 125, + 82, + 130, + 53, + 231, + 217, + 159, + 19, + 47, + 186, + 144, + 82, + 46, + 248, + 41, + 30, + 0, + 29, + 82, + 53, + 12, + 109, + 126, + 139, + 113, + 148, + 220, + 17, + 138, + 29, + 24, + 17, + 233, + 219, + 112, + 1, + 30, + 138, + 205, + 184, + 110, + 72, + 236, + 12, + 202, + 168, + 95, + 33, + 246, + 11, + 238, + 216, + 211, + 79, + 25, + 169, + 253, + 255, + 167, + 61, + 3, + 242, + 5, + 34, + 244, + 23, + 86, + 163, + 123, + 164, + 159, + 95, + 152, + 203, + 192, + 189, + 142, + 131, + 244, + 211, + 20, + 25, + 184, + 176, + 233, + 70, + 185, + 76, + 84, + 121, + 97, + 60, + 169, + 213, + 130, + 255, + 100, + 90, + 102, + 248, + 73, + 38, + 154, + 239, + 200, + 216, + 60, + 10, + 113, + 30, + 170, + 62, + 76, + 93, + 140, + 175, + 235, + 142, + 112, + 64, + 35, + 29, + 84, + 143, + 254, + 206, + 160, + 6, + 45, + 136, + 28, + 177, + 98, + 99, + 2, + 70, + 122, + 247, + 225, + 157, + 56, + 25, + 38, + 95, + 14, + 40, + 12, + 133, + 203, + 195, + 191, + 228, + 95, + 228, + 67, + 95, + 190, + 6, + 28, + 33, + 91, + 191, + 31, + 72, + 48, + 85, + 36, + 206, + 90, + 91, + 224, + 96, + 49, + 152, + 217, + 37, + 159, + 73, + 43, + 116, + 224, + 188, + 8, + 184, + 208, + 247, + 48, + 17, + 160, + 47, + 31, + 211, + 81, + 237, + 12, + 204, + 95, + 233, + 208, + 210, + 235, + 26, + 122, + 127, + 246, + 96, + 192, + 109, + 182, + 74, + 9, + 250, + 246, + 141, + 211, + 234, + 175, + 34, + 96, + 175, + 145, + 17, + 49, + 20, + 159, + 222, + 222, + 60, + 142, + 216, + 111, + 215, + 14, + 37, + 58, + 49, + 221, + 19, + 6, + 40, + 200, + 78, + 136, + 121, + 90, + 115, + 244, + 152, + 98, + 189, + 67, + 148, + 112, + 212, + 155, + 119, + 21, + 44, + 15, + 141, + 225, + 86, + 97, + 154, + 151, + 22, + 48, + 227, + 130, + 67, + 34, + 232, + 174, + 81, + 101, + 110, + 50, + 127, + 239, + 209, + 238, + 115, + 74, + 238, + 89, + 73, + 11, + 89, + 219, + 251, + 122, + 252, + 227, + 237, + 232, + 93, + 174, + 3, + 42, + 73, + 142, + 169, + 110, + 138, + 191, + 102, + 149, + 175, + 4, + 29, + 176, + 144, + 214, + 38, + 91, + 196, + 154, + 209, + 125, + 88, + 138, + 190, + 22, + 148, + 134, + 135, + 121, + 87, + 18, + 217, + 83, + 126, + 162, + 43, + 35, + 155, + 145, + 97, + 125, + 219, + 208, + 156, + 45, + 6, + 89, + 189, + 201, + 134, + 169, + 172, + 30, + 121, + 33, + 8, + 221, + 110, + 252, + 38, + 159, + 235, + 104, + 182, + 48, + 58, + 76, + 208, + 248, + 134, + 123, + 78, + 154, + 58, + 176, + 103, + 98, + 144, + 128, + 171, + 185, + 132, + 97, + 247, + 151, + 198, + 148, + 207, + 91, + 27, + 247, + 117, + 163, + 191, + 87, + 89, + 53, + 221, + 230, + 77, + 103, + 17, + 131, + 28, + 205, + 100, + 163, + 7, + 67, + 157, + 203, + 236, + 199, + 39, + 47, + 167, + 92, + 140, + 34, + 157, + 253, + 129, + 17, + 105, + 134, + 33, + 12, + 232, + 5, + 233, + 117, + 179, + 54, + 105, + 176, + 35, + 172, + 47, + 147, + 214, + 250, + 4, + 157, + 108, + 216, + 204, + 122, + 230, + 164, + 132, + 1, + 121, + 40, + 79, + 70, + 243, + 213, + 52, + 236, + 15, + 138, + 136, + 251, + 146, + 50, + 191, + 144, + 25, + 45, + 48, + 109, + 205, + 103, + 146, + 55, + 218, + 47, + 131, + 222, + 118, + 165, + 254, + 254, + 130, + 1, + 212, + 105, + 90, + 13, + 68, + 1, + 207, + 179, + 199, + 158, + 47, + 232, + 3, + 175, + 98, + 33, + 45, + 51, + 41, + 117, + 4, + 205, + 190, + 150, + 194, + 111, + 100, + 83, + 58, + 144, + 176, + 26, + 46, + 223, + 201, + 222, + 73, + 120, + 145, + 231, + 108, + 0, + 179, + 58, + 193, + 99, + 46, + 69, + 190, + 155, + 28, + 80, + 92, + 235, + 12, + 58, + 12, + 215, + 87, + 120, + 112, + 237, + 203, + 184, + 106, + 135, + 51, + 101, + 210, + 23, + 238, + 136, + 249, + 45, + 82, + 74, + 2, + 155, + 92, + 46, + 27, + 207, + 55, + 158, + 48, + 224, + 137, + 109, + 154, + 237, + 219, + 136, + 179, + 63, + 80, + 246, + 147, + 171, + 28, + 101, + 71, + 50, + 198, + 82, + 207, + 111, + 207, + 169, + 57, + 253, + 101, + 190, + 106, + 75, + 82, + 204, + 75, + 110, + 197, + 164, + 141, + 114, + 129, + 194, + 87, + 124, + 187, + 150, + 229, + 47, + 99, + 171, + 135, + 176, + 57, + 142, + 21, + 55, + 84, + 113, + 124, + 151, + 24, + 15, + 207, + 1, + 47, + 162, + 141, + 245, + 234, + 140, + 249, + 163, + 136, + 134, + 192, + 85, + 76, + 212, + 121, + 106, + 212, + 164, + 47, + 100, + 239, + 224, + 247, + 132, + 98, + 123, + 228, + 69, + 24, + 33, + 25, + 130, + 160, + 184, + 51, + 64, + 21, + 4, + 150, + 120, + 181, + 173, + 143, + 154, + 59, + 229, + 126, + 213, + 23, + 254, + 4, + 10, + 89, + 245, + 99, + 207, + 163, + 73, + 230, + 65, + 90, + 183, + 60, + 110, + 222, + 125, + 141, + 12, + 2, + 93, + 222, + 138, + 106, + 111, + 114, + 49, + 236, + 228, + 234, + 113, + 15, + 194, + 105, + 212, + 41, + 152, + 200, + 39, + 245, + 72, + 178, + 33, + 23, + 106, + 126, + 74, + 156, + 34, + 188, + 206, + 247, + 237, + 148, + 153, + 254, + 249, + 69, + 174, + 190, + 239, + 164, + 53, + 107, + 69, + 244, + 38, + 106, + 155, + 27, + 150, + 214, + 110, + 255, + 44, + 2, + 150, + 164, + 190, + 231, + 185, + 100, + 206, + 208, + 205, + 74, + 90, + 214, + 131, + 229, + 190, + 223, + 76, + 86, + 208, + 206, + 171, + 24, + 38, + 193, + 180, + 127, + 74, + 109, + 183, + 62, + 207, + 97, + 132, + 125, + 150, + 202, + 191, + 223, + 118, + 96, + 251, + 16, + 75, + 91, + 56, + 10, + 35, + 79, + 26, + 217, + 253, + 153, + 82, + 241, + 76, + 190, + 145, + 84, + 250, + 192, + 232, + 46, + 83, + 63, + 252, + 140, + 87, + 15, + 115, + 232, + 166, + 2, + 184, + 218, + 230, + 111, + 226, + 251, + 50, + 143, + 51, + 68, + 86, + 239, + 165, + 55, + 154, + 43, + 49, + 70, + 95, + 72, + 104, + 25, + 226, + 1, + 37, + 14, + 32, + 246, + 28, + 182, + 3, + 120, + 37, + 34, + 2, + 37, + 177, + 10, + 234, + 136, + 15, + 162, + 218, + 230, + 233, + 230, + 204, + 108, + 159, + 3, + 82, + 17, + 183, + 205, + 66, + 114, + 12, + 73, + 166, + 89, + 202, + 45, + 81, + 63, + 41, + 118, + 122, + 101, + 18, + 162, + 152, + 135, + 251, + 243, + 186, + 80, + 223, + 84, + 149, + 6, + 165, + 67, + 199, + 117, + 140, + 191, + 207, + 62, + 134, + 216, + 21, + 85, + 9, + 191, + 180, + 192, + 84, + 112, + 144, + 58, + 202, + 163, + 25, + 162, + 202, + 176, + 52, + 87, + 160, + 160, + 56, + 110, + 54, + 66, + 119, + 112, + 101, + 17, + 64, + 109, + 242, + 83, + 230, + 106, + 142, + 231, + 5, + 84, + 23, + 210, + 213, + 153, + 23, + 150, + 236, + 53, + 162, + 42, + 228, + 236, + 105, + 248, + 14, + 10, + 52, + 7, + 200, + 106, + 19, + 244, + 141, + 8, + 30, + 206, + 215, + 127, + 133, + 103, + 5, + 164, + 46, + 253, + 228, + 157, + 45, + 90, + 97, + 127, + 160, + 243, + 221, + 173, + 124, + 109, + 46, + 124, + 230, + 4, + 133, + 240, + 67, + 224, + 205, + 9, + 91, + 12, + 6, + 45, + 197, + 150, + 48, + 86, + 67, + 109, + 222, + 52, + 159, + 177, + 117, + 162, + 44, + 111, + 244, + 101, + 228, + 50, + 228, + 31, + 230, + 88, + 123, + 152, + 4, + 87, + 116, + 106, + 161, + 20, + 252, + 190, + 14, + 101, + 184, + 208, + 81, + 168, + 130, + 116, + 146, + 150, + 1, + 183, + 2, + 113, + 57, + 85, + 242, + 240, + 135, + 86, + 15, + 123, + 79, + 60, + 249, + 96, + 53, + 104, + 144, + 42, + 141, + 76, + 194, + 174, + 68, + 39, + 65, + 11, + 47, + 120, + 240, + 6, + 123, + 22, + 139, + 140, + 9, + 41, + 236, + 140, + 157, + 107, + 114, + 234, + 207, + 92, + 223, + 230, + 143, + 69, + 159, + 76, + 55, + 14, + 138, + 215, + 229, + 0, + 192, + 129, + 142, + 216, + 129, + 224, + 124, + 44, + 134, + 132, + 28, + 86, + 54, + 2, + 218, + 175, + 254, + 183, + 197, + 228, + 22, + 200, + 117, + 51, + 53, + 24, + 237, + 106, + 170, + 46, + 21, + 167, + 0, + 164, + 40, + 85, + 234, + 73, + 142, + 18, + 31, + 172, + 236, + 91, + 115, + 91, + 19, + 162, + 72, + 17, + 25, + 80, + 234, + 166, + 226, + 27, + 54, + 70, + 123, + 109, + 144, + 71, + 225, + 239, + 65, + 63, + 231, + 74, + 92, + 114, + 116, + 117, + 112, + 13, + 155, + 74, + 34, + 179, + 133, + 65, + 64, + 191, + 229, + 117, + 185, + 225, + 184, + 28, + 120, + 123, + 170, + 37, + 74, + 44, + 19, + 92, + 149, + 15, + 115, + 83, + 189, + 98, + 253, + 40, + 104, + 152, + 255, + 249, + 192, + 136, + 80, + 199, + 111, + 62, + 168, + 83, + 185, + 179, + 162, + 83, + 202, + 123, + 196, + 47, + 56, + 59, + 26, + 58, + 106, + 11, + 40, + 180, + 30, + 27, + 39, + 34, + 149, + 236, + 236, + 245, + 202, + 157, + 6, + 112, + 90, + 47, + 211, + 56, + 188, + 228, + 78, + 108, + 62, + 8, + 205, + 124, + 163, + 218, + 110, + 87, + 68, + 162, + 130, + 66, + 22, + 74, + 2, + 146, + 29, + 124, + 79, + 243, + 132, + 163, + 68, + 46, + 140, + 152, + 195, + 100, + 238, + 253, + 93, + 27, + 247, + 82, + 222, + 39, + 133, + 119, + 49, + 27, + 224, + 44, + 253, + 99, + 222, + 68, + 231, + 71, + 26, + 178, + 210, + 85, + 85, + 206, + 11, + 98, + 166, + 117, + 0, + 65, + 240, + 64, + 226, + 90, + 234, + 8, + 228, + 232, + 24, + 182, + 56, + 158, + 5, + 26, + 252, + 72, + 198, + 65, + 98, + 210, + 175, + 0, + 60, + 218, + 0, + 209, + 68, + 86, + 204, + 57, + 158, + 19, + 146, + 40, + 62, + 69, + 210, + 52, + 123, + 205, + 31, + 80, + 95, + 18, + 117, + 149, + 107, + 173, + 6, + 5, + 29, + 144, + 111, + 244, + 63, + 199, + 111, + 84, + 22, + 37, + 82, + 77, + 110, + 190, + 53, + 117, + 227, + 43, + 21, + 206, + 46, + 58, + 188, + 60, + 169, + 157, + 223, + 70, + 200, + 43, + 123, + 115, + 4, + 58, + 243, + 85, + 104, + 136, + 30, + 104, + 41, + 163, + 196, + 195, + 103, + 94, + 142, + 119, + 183, + 71, + 249, + 103, + 196, + 227, + 112, + 137, + 212, + 92, + 49, + 118, + 46, + 0, + 193, + 31, + 105, + 118, + 178, + 14, + 113, + 51, + 109, + 59, + 237, + 247, + 29, + 227, + 123, + 58, + 235, + 51, + 103, + 23, + 177, + 58, + 49, + 207, + 210, + 155, + 16, + 179, + 156, + 130, + 120, + 125, + 24, + 203, + 222, + 91, + 149, + 157, + 12, + 99, + 189, + 49, + 203, + 151, + 195, + 89, + 221, + 147, + 243, + 20, + 146, + 84, + 139, + 245, + 132, + 232, + 179, + 25, + 121, + 205, + 28, + 156, + 22, + 225, + 174, + 82, + 186, + 106, + 247, + 6, + 120, + 34, + 112, + 53, + 168, + 150, + 186, + 179, + 41, + 228, + 206, + 86, + 64, + 76, + 41, + 127, + 172, + 128, + 187, + 245, + 192, + 234, + 229, + 114, + 16, + 47, + 198, + 90, + 51, + 244, + 32, + 139, + 178, + 155, + 132, + 119, + 210, + 88, + 59, + 190, + 181, + 89, + 217, + 106, + 48, + 28, + 186, + 140, + 105, + 147, + 43, + 72, + 239, + 246, + 125, + 82, + 12, + 250, + 123, + 21, + 207, + 168, + 57, + 169, + 11, + 119, + 118, + 96, + 8, + 204, + 200, + 202, + 217, + 150, + 122, + 170, + 96, + 65, + 119, + 183, + 122, + 95, + 99, + 224, + 108, + 7, + 198, + 224, + 215, + 109, + 230, + 90, + 93, + 132, + 207, + 46, + 116, + 77, + 80, + 136, + 115, + 198, + 94, + 124, + 26, + 1, + 47, + 134, + 12, + 95, + 10, + 37, + 178, + 129, + 162, + 206, + 22, + 162, + 49, + 160, + 136, + 229, + 66, + 103, + 40, + 218, + 123, + 131, + 207, + 110, + 252, + 173, + 164, + 49, + 26, + 88, + 122, + 33, + 107, + 38, + 208, + 53, + 22, + 167, + 124, + 26, + 251, + 10, + 61, + 132, + 115, + 74, + 39, + 237, + 254, + 54, + 38, + 16, + 57, + 171, + 204, + 98, + 121, + 228, + 192, + 203, + 216, + 177, + 111, + 148, + 115, + 28, + 208, + 77, + 72, + 8, + 159, + 147, + 71, + 32, + 43, + 248, + 23, + 169, + 127, + 9, + 165, + 214, + 92, + 172, + 209, + 31, + 204, + 229, + 125, + 28, + 59, + 192, + 201, + 245, + 104, + 23, + 188, + 237, + 234, + 101, + 146, + 51, + 206, + 30, + 11, + 11, + 237, + 236, + 90, + 155, + 249, + 8, + 22, + 87, + 148, + 247, + 213, + 83, + 126, + 137, + 33, + 170, + 229, + 18, + 40, + 59, + 25, + 249, + 29, + 182, + 190, + 107, + 142, + 14, + 36, + 57, + 91, + 151, + 96, + 216, + 156, + 218, + 207, + 188, + 221, + 202, + 133, + 176, + 33, + 141, + 227, + 46, + 54, + 15, + 151, + 115, + 175, + 148, + 182, + 206, + 47, + 63, + 38, + 67, + 102, + 67, + 52, + 238, + 188, + 241, + 77, + 75, + 178, + 119, + 245, + 224, + 135, + 70, + 66, + 129, + 137, + 113, + 226, + 208, + 120, + 15, + 139, + 0, + 215, + 185, + 80, + 48, + 122, + 133, + 203, + 63, + 73, + 126, + 77, + 63, + 94, + 78, + 240, + 146, + 123, + 24, + 249, + 246, + 93, + 149, + 245, + 143, + 145, + 167, + 63, + 102, + 19, + 170, + 215, + 96, + 155, + 187, + 164, + 97, + 22, + 216, + 202, + 12, + 191, + 143, + 157, + 1, + 77, + 78, + 89, + 164, + 186, + 224, + 133, + 36, + 139, + 99, + 16, + 198, + 12, + 89, + 216, + 20, + 79, + 201, + 250, + 61, + 36, + 238, + 99, + 40, + 105, + 86, + 207, + 19, + 179, + 99, + 98, + 35, + 108, + 177, + 45, + 41, + 114, + 20, + 67, + 150, + 114, + 173, + 237, + 204, + 132, + 202, + 253, + 209, + 84, + 126, + 16, + 18, + 154, + 147, + 173, + 166, + 36, + 165, + 86, + 51, + 186, + 223, + 239, + 60, + 22, + 245, + 117, + 70, + 154, + 96, + 247, + 222, + 38, + 55, + 197, + 73, + 8, + 249, + 232, + 149, + 126, + 19, + 37, + 4, + 103, + 46, + 204, + 170, + 110, + 115, + 255, + 83, + 120, + 107, + 188, + 124, + 29, + 98, + 206, + 62, + 192, + 255, + 9, + 88, + 163, + 37, + 82, + 27, + 173, + 123, + 224, + 71, + 16, + 4, + 41, + 202, + 188, + 96, + 132, + 127, + 151, + 167, + 137, + 57, + 48, + 241, + 64, + 84, + 127, + 68, + 179, + 33, + 194, + 88, + 22, + 100, + 105, + 6, + 74, + 72, + 25, + 0, + 136, + 23, + 99, + 7, + 161, + 231, + 219, + 83, + 50, + 136, + 107, + 7, + 129, + 83, + 24, + 228, + 201, + 75, + 56, + 99, + 255, + 111, + 20, + 153, + 173, + 39, + 87, + 42, + 76, + 118, + 24, + 129, + 46, + 71, + 127, + 240, + 142, + 146, + 23, + 187, + 94, + 37, + 184, + 245, + 222, + 101, + 206, + 36, + 173, + 205, + 3, + 20, + 62, + 159, + 59, + 40, + 74, + 10, + 38, + 182, + 140, + 24, + 5, + 84, + 1, + 54, + 67, + 124, + 18, + 202, + 57, + 194, + 196, + 238, + 73, + 208, + 205, + 37, + 234, + 207, + 114, + 151, + 205, + 155, + 8, + 13, + 16, + 12, + 78, + 153, + 2, + 146, + 128, + 5, + 31, + 182, + 95, + 101, + 207, + 163, + 107, + 156, + 155, + 252, + 195, + 64, + 97, + 179, + 141, + 104, + 80, + 204, + 185, + 172, + 164, + 48, + 253, + 159, + 37, + 31, + 51, + 138, + 51, + 245, + 20, + 28, + 225, + 145, + 4, + 88, + 110, + 145, + 52, + 94, + 67, + 138, + 25, + 37, + 161, + 11, + 71, + 8, + 25, + 139, + 107, + 183, + 81, + 52, + 120, + 218, + 198, + 28, + 207, + 68, + 63, + 59, + 213, + 236, + 94, + 105, + 132, + 231, + 82, + 152, + 179, + 111, + 75, + 221, + 211, + 28, + 184, + 254, + 15, + 66, + 45, + 63, + 29, + 136, + 197, + 180, + 214, + 104, + 185, + 170, + 173, + 225, + 167, + 121, + 212, + 159, + 14, + 104, + 73, + 166, + 135, + 148, + 35, + 121, + 38, + 231, + 55, + 206, + 79, + 240, + 90, + 66, + 90, + 42, + 26, + 31, + 199, + 184, + 254, + 70, + 197, + 43, + 105, + 158, + 116, + 5, + 92, + 37, + 103, + 49, + 167, + 113, + 126, + 88, + 228, + 79, + 63, + 99, + 81, + 155, + 123, + 21, + 97, + 68, + 181, + 43, + 13, + 239, + 220, + 16, + 60, + 221, + 195, + 178, + 62, + 192, + 2, + 184, + 2, + 26, + 99, + 244, + 168, + 209, + 5, + 128, + 153, + 120, + 54, + 106, + 204, + 183, + 84, + 200, + 115, + 55, + 71, + 254, + 247, + 83, + 116, + 252, + 237, + 25, + 42, + 92, + 4, + 56, + 148, + 3, + 114, + 137, + 201, + 111, + 49, + 89, + 213, + 208, + 173, + 192, + 146, + 122, + 11, + 126, + 178, + 98, + 244, + 92, + 99, + 129, + 36, + 153, + 74, + 155, + 212, + 147, + 204, + 195, + 83, + 248, + 167, + 85, + 111, + 165, + 35, + 187, + 240, + 188, + 250, + 113, + 208, + 185, + 106, + 99, + 239, + 33, + 250, + 39, + 50, + 115, + 143, + 205, + 204, + 96, + 64, + 9, + 57, + 8, + 57, + 234, + 119, + 174, + 112, + 191, + 23, + 91, + 65, + 212, + 15, + 63, + 175, + 173, + 39, + 152, + 11, + 141, + 78, + 24, + 113, + 179, + 216, + 88, + 144, + 86, + 8, + 135, + 58, + 90, + 182, + 11, + 217, + 50, + 242, + 129, + 6, + 220, + 237, + 139, + 26, + 204, + 233, + 80, + 191, + 13, + 231, + 202, + 27, + 145, + 53, + 33, + 187, + 164, + 244, + 21, + 64, + 105, + 104, + 151, + 230, + 3, + 133, + 187, + 177, + 131, + 214, + 1, + 146, + 171, + 242, + 3, + 9, + 239, + 217, + 32, + 4, + 233, + 161, + 172, + 161, + 223, + 244, + 15, + 127, + 105, + 196, + 81, + 9, + 208, + 146, + 55, + 101, + 148, + 228, + 215, + 173, + 36, + 106, + 80, + 31, + 139, + 23, + 138, + 173, + 142, + 45, + 26, + 44, + 68, + 123, + 97, + 227, + 133, + 71, + 107, + 53, + 86, + 115, + 49, + 4, + 176, + 217, + 145, + 87, + 137, + 255, + 163, + 140, + 194, + 151, + 230, + 85, + 24, + 52, + 55, + 245, + 173, + 102, + 147, + 254, + 110, + 58, + 98, + 116, + 62, + 59, + 243, + 96, + 150, + 88, + 64, + 1, + 247, + 104, + 191, + 169, + 7, + 155, + 145, + 12, + 118, + 146, + 21, + 185, + 215, + 0, + 148, + 190, + 255, + 167, + 77, + 58, + 229, + 49, + 189, + 17, + 124, + 107, + 70, + 249, + 65, + 40, + 15, + 156, + 196, + 254, + 224, + 95, + 100, + 72, + 37, + 107, + 176, + 89, + 30, + 69, + 172, + 7, + 71, + 250, + 15, + 237, + 232, + 218, + 47, + 54, + 213, + 156, + 17, + 129, + 183, + 247, + 249, + 65, + 114, + 17, + 76, + 236, + 209, + 168, + 190, + 51, + 66, + 136, + 156, + 183, + 83, + 228, + 149, + 114, + 233, + 209, + 222, + 230, + 27, + 38, + 48, + 226, + 217, + 75, + 145, + 162, + 15, + 103, + 220, + 61, + 43, + 174, + 242, + 106, + 108, + 185, + 73, + 17, + 19, + 182, + 44, + 174, + 73, + 219, + 123, + 100, + 210, + 224, + 24, + 192, + 10, + 165, + 4, + 179, + 59, + 108, + 243, + 239, + 25, + 224, + 188, + 171, + 104, + 162, + 192, + 250, + 160, + 25, + 71, + 219, + 50, + 75, + 123, + 80, + 193, + 133, + 99, + 229, + 127, + 218, + 184, + 70, + 230, + 242, + 77, + 43, + 253, + 26, + 47, + 58, + 195, + 109, + 238, + 164, + 65, + 33, + 152, + 118, + 28, + 175, + 107, + 72, + 131, + 146, + 122, + 56, + 51, + 240, + 81, + 12, + 127, + 224, + 158, + 215, + 172, + 56, + 177, + 213, + 242, + 197, + 116, + 161, + 112, + 216, + 33, + 70, + 91, + 7, + 6, + 234, + 247, + 135, + 181, + 235, + 139, + 106, + 56, + 127, + 179, + 210, + 58, + 81, + 221, + 109, + 17, + 131, + 250, + 26, + 156, + 121, + 117, + 206, + 228, + 3, + 133, + 245, + 237, + 175, + 15, + 89, + 224, + 55, + 76, + 81, + 254, + 237, + 213, + 116, + 49, + 98, + 178, + 244, + 56, + 162, + 76, + 40, + 111, + 158, + 23, + 210, + 230, + 193, + 205, + 199, + 6, + 103, + 203, + 202, + 168, + 200, + 16, + 0, + 167, + 172, + 205, + 123, + 144, + 128, + 195, + 141, + 114, + 219, + 90, + 163, + 161, + 104, + 137, + 24, + 149, + 245, + 17, + 169, + 104, + 141, + 4, + 147, + 194, + 118, + 153, + 72, + 26, + 219, + 78, + 248, + 194, + 161, + 188, + 142, + 61, + 151, + 183, + 152, + 22, + 40, + 181, + 89, + 6, + 115, + 115, + 182, + 11, + 215, + 69, + 92, + 4, + 101, + 169, + 238, + 247, + 204, + 43, + 61, + 99, + 215, + 96, + 75, + 98, + 224, + 54, + 42, + 242, + 239, + 97, + 228, + 24, + 164, + 186, + 96, + 70, + 111, + 120, + 9, + 24, + 103, + 100, + 87, + 240, + 180, + 220, + 49, + 50, + 215, + 161, + 246, + 30, + 209, + 85, + 94, + 163, + 54, + 105, + 123, + 135, + 26, + 45, + 31, + 247, + 18, + 169, + 89, + 244, + 215, + 70, + 210, + 120, + 239, + 219, + 145, + 9, + 211, + 97, + 195, + 242, + 42, + 233, + 200, + 215, + 201, + 8, + 205, + 26, + 175, + 64, + 233, + 47, + 74, + 186, + 73, + 231, + 209, + 218, + 8, + 103, + 208, + 188, + 96, + 35, + 57, + 181, + 164, + 246, + 150, + 19, + 140, + 135, + 206, + 74, + 10, + 62, + 84, + 107, + 105, + 140, + 64, + 28, + 148, + 200, + 165, + 37, + 68, + 22, + 213, + 102, + 136, + 72, + 179, + 32, + 59, + 87, + 0, + 119, + 182, + 255, + 203, + 162, + 165, + 98, + 51, + 161, + 161, + 46, + 81, + 86, + 57, + 23, + 181, + 159, + 93, + 168, + 157, + 50, + 49, + 162, + 213, + 106, + 33, + 12, + 248, + 8, + 90, + 230, + 53, + 152, + 198, + 1, + 181, + 127, + 85, + 103, + 188, + 155, + 103, + 47, + 236, + 101, + 226, + 246, + 170, + 201, + 66, + 143, + 48, + 141, + 131, + 154, + 220, + 47, + 110, + 221, + 205, + 72, + 89, + 225, + 255, + 140, + 147, + 86, + 19, + 18, + 236, + 52, + 206, + 186, + 129, + 80, + 59, + 24, + 41, + 26, + 110, + 205, + 93, + 218, + 147, + 3, + 151, + 57, + 9, + 78, + 57, + 153, + 89, + 198, + 99, + 95, + 7, + 168, + 152, + 161, + 90, + 217, + 127, + 83, + 152, + 166, + 232, + 99, + 233, + 92, + 226, + 71, + 95, + 199, + 82, + 233, + 83, + 218, + 45, + 137, + 113, + 74, + 164, + 16, + 109, + 255, + 39, + 225, + 123, + 211, + 140, + 241, + 99, + 14, + 146, + 84, + 97, + 165, + 242, + 9, + 174, + 111, + 24, + 21, + 43, + 66, + 101, + 224, + 59, + 39, + 109, + 147, + 171, + 74, + 216, + 1, + 51, + 83, + 164, + 197, + 116, + 129, + 17, + 33, + 122, + 137, + 171, + 21, + 86, + 185, + 167, + 193, + 120, + 101, + 150, + 165, + 216, + 89, + 11, + 211, + 178, + 33, + 238, + 32, + 197, + 179, + 185, + 39, + 100, + 41, + 251, + 198, + 208, + 12, + 63, + 241, + 4, + 155, + 140, + 128, + 122, + 211, + 77, + 145, + 94, + 112, + 103, + 63, + 8, + 71, + 79, + 67, + 196, + 50, + 23, + 228, + 187, + 180, + 183, + 158, + 133, + 252, + 80, + 20, + 140, + 173, + 251, + 165, + 212, + 27, + 127, + 84, + 23, + 33, + 212, + 148, + 1, + 108, + 195, + 218, + 232, + 103, + 26, + 45, + 23, + 148, + 51, + 50, + 82, + 89, + 159, + 212, + 135, + 173, + 209, + 191, + 96, + 35, + 168, + 29, + 209, + 50, + 226, + 45, + 125, + 218, + 74, + 2, + 80, + 100, + 9, + 151, + 108, + 204, + 136, + 119, + 177, + 23, + 39, + 95, + 196, + 31, + 147, + 249, + 213, + 169, + 186, + 79, + 147, + 50, + 43, + 221, + 155, + 205, + 152, + 16, + 196, + 57, + 224, + 193, + 28, + 61, + 39, + 89, + 3, + 252, + 226, + 132, + 239, + 110, + 25, + 95, + 170, + 149, + 90, + 201, + 223, + 171, + 57, + 78, + 35, + 7, + 39, + 101, + 241, + 34, + 128, + 190, + 224, + 107, + 59, + 53, + 51, + 20, + 203, + 168, + 91, + 136, + 76, + 238, + 172, + 12, + 107, + 95, + 109, + 63, + 220, + 113, + 94, + 106, + 225, + 181, + 143, + 38, + 173, + 200, + 96, + 67, + 142, + 156, + 115, + 91, + 78, + 239, + 88, + 65, + 36, + 118, + 49, + 252, + 59, + 102, + 236, + 251, + 105, + 206, + 19, + 89, + 212, + 100, + 5, + 7, + 4, + 174, + 235, + 112, + 255, + 107, + 59, + 111, + 51, + 183, + 223, + 219, + 2, + 249, + 158, + 104, + 50, + 104, + 124, + 184, + 213, + 114, + 7, + 125, + 113, + 72, + 157, + 223, + 55, + 84, + 142, + 10, + 26, + 37, + 210, + 77, + 150, + 202, + 10, + 72, + 52, + 144, + 214, + 163, + 224, + 33, + 9, + 12, + 14, + 79, + 116, + 242, + 210, + 42, + 224, + 174, + 11, + 106, + 14, + 46, + 250, + 198, + 178, + 66, + 62, + 29, + 27, + 59, + 121, + 133, + 159, + 181, + 124, + 42, + 186, + 237, + 107, + 164, + 25, + 34, + 17, + 99, + 54, + 240, + 60, + 117, + 57, + 153, + 239, + 5, + 90, + 20, + 115, + 193, + 81, + 193, + 121, + 91, + 128, + 62, + 66, + 34, + 197, + 146, + 186, + 245, + 69, + 58, + 236, + 12, + 18, + 32, + 170, + 31, + 205, + 57, + 52, + 26, + 155, + 63, + 97, + 245, + 216, + 233, + 130, + 10, + 66, + 93, + 87, + 67, + 15, + 106, + 240, + 74, + 69, + 24, + 108, + 130, + 100, + 29, + 171, + 159, + 37, + 45, + 248, + 209, + 31, + 107, + 233, + 241, + 34, + 89, + 209, + 238, + 51, + 187, + 239, + 29, + 243, + 216, + 137, + 138, + 32, + 189, + 35, + 25, + 236, + 110, + 48, + 4, + 121, + 167, + 198, + 208, + 122, + 29, + 157, + 154, + 166, + 199, + 201, + 219, + 92, + 228, + 86, + 180, + 141, + 42, + 198, + 64, + 125, + 87, + 68, + 211, + 87, + 107, + 18, + 94, + 78, + 99, + 126, + 223, + 52, + 90, + 177, + 169, + 176, + 51, + 8, + 10, + 78, + 70, + 160, + 204, + 184, + 239, + 193, + 202, + 29, + 209, + 196, + 80, + 75, + 228, + 147, + 34, + 14, + 131, + 190, + 105, + 218, + 73, + 47, + 13, + 185, + 73, + 5, + 13, + 24, + 91, + 67, + 11, + 155, + 199, + 173, + 5, + 136, + 21, + 44, + 20, + 191, + 24, + 115, + 103, + 147, + 185, + 62, + 106, + 201, + 31, + 93, + 206, + 206, + 197, + 84, + 220, + 6, + 2, + 89, + 106, + 95, + 46, + 54, + 19, + 111, + 165, + 137, + 148, + 254, + 152, + 148, + 138, + 17, + 182, + 147, + 47, + 187, + 91, + 126, + 101, + 253, + 249, + 118, + 96, + 26, + 239, + 115, + 226, + 237, + 11, + 72, + 242, + 84, + 43, + 188, + 18, + 59, + 100, + 10, + 67, + 226, + 113, + 16, + 182, + 228, + 63, + 203, + 243, + 27, + 181, + 121, + 66, + 16, + 153, + 149, + 123, + 39, + 120, + 132, + 194, + 15, + 141, + 28, + 132, + 154, + 100, + 31, + 55, + 232, + 239, + 236, + 126, + 51, + 48, + 144, + 244, + 165, + 85, + 174, + 67, + 52, + 202, + 251, + 143, + 187, + 101, + 27, + 233, + 75, + 175, + 7, + 64, + 223, + 205, + 108, + 208, + 159, + 20, + 6, + 187, + 84, + 184, + 126, + 140, + 125, + 86, + 208, + 44, + 10, + 103, + 90, + 197, + 65, + 194, + 114, + 114, + 28, + 180, + 26, + 31, + 88, + 66, + 233, + 229, + 59, + 32, + 172, + 246, + 231, + 89, + 226, + 133, + 247, + 87, + 120, + 180, + 194, + 167, + 166, + 243, + 40, + 105, + 202, + 213, + 11, + 203, + 67, + 247, + 252, + 108, + 62, + 1, + 183, + 16, + 5, + 185, + 52, + 191, + 46, + 157, + 238, + 109, + 76, + 74, + 26, + 118, + 218, + 28, + 45, + 61, + 42, + 45, + 208, + 136, + 137, + 0, + 104, + 65, + 124, + 24, + 90, + 207, + 173, + 224, + 201, + 115, + 64, + 119, + 246, + 3, + 50, + 12, + 55, + 64, + 178, + 228, + 255, + 15, + 54, + 141, + 5, + 69, + 37, + 250, + 145, + 199, + 152, + 125, + 16, + 106, + 2, + 221, + 32, + 248, + 98, + 85, + 112, + 114, + 190, + 234, + 141, + 36, + 110, + 128, + 196, + 43, + 1, + 138, + 130, + 32, + 183, + 106, + 117, + 151, + 143, + 142, + 248, + 161, + 116, + 91, + 46, + 235, + 237, + 55, + 139, + 225, + 255, + 23, + 21, + 23, + 187, + 93, + 234, + 167, + 231, + 252, + 122, + 102, + 252, + 11, + 70, + 93, + 243, + 53, + 72, + 249, + 239, + 186, + 71, + 160, + 218, + 252, + 10, + 7, + 242, + 137, + 55, + 112, + 38, + 215, + 238, + 174, + 98, + 196, + 164, + 100, + 244, + 164, + 82, + 79, + 97, + 233, + 3, + 166, + 30, + 217, + 139, + 150, + 141, + 84, + 66, + 68, + 165, + 142, + 40, + 255, + 228, + 124, + 85, + 211, + 173, + 164, + 253, + 192, + 129, + 131, + 92, + 230, + 202, + 182, + 206, + 90, + 125, + 150, + 177, + 194, + 217, + 190, + 229, + 214, + 117, + 68, + 198, + 153, + 142, + 52, + 215, + 197, + 253, + 38, + 14, + 72, + 22, + 108, + 248, + 1, + 48, + 157, + 46, + 128, + 160, + 111, + 188, + 45, + 177, + 88, + 205, + 60, + 101, + 83, + 191, + 108, + 244, + 39, + 92, + 20, + 198, + 11, + 227, + 105, + 178, + 61, + 174, + 188, + 43, + 250, + 2, + 137, + 9, + 201, + 56, + 183, + 73, + 20, + 121, + 33, + 191, + 2, + 252, + 0, + 48, + 24, + 231, + 54, + 240, + 209, + 221, + 19, + 122, + 119, + 208, + 230, + 245, + 30, + 217, + 237, + 188, + 167, + 54, + 73, + 30, + 187, + 86, + 61, + 185, + 42, + 84, + 79, + 115, + 181, + 18, + 43, + 54, + 227, + 64, + 19, + 185, + 63, + 219, + 66, + 17, + 21, + 85, + 84, + 67, + 123, + 83, + 121, + 158, + 4, + 12, + 99, + 45, + 1, + 142, + 56, + 246, + 140, + 108, + 91, + 252, + 95, + 126, + 189, + 115, + 121, + 172, + 83, + 94, + 185, + 235, + 236, + 178, + 187, + 49, + 252, + 151, + 224, + 142, + 119, + 87, + 37, + 135, + 90, + 189, + 193, + 18, + 149, + 188, + 229, + 157, + 56, + 91, + 124, + 15, + 79, + 255, + 249, + 50, + 113, + 162, + 77, + 188, + 32, + 151, + 101, + 229, + 102, + 151, + 77, + 147, + 238, + 118, + 247, + 225, + 194, + 73, + 140, + 130, + 129, + 87, + 34, + 55, + 47, + 64, + 173, + 209, + 7, + 41, + 203, + 192, + 109, + 30, + 8, + 128, + 172, + 142, + 216, + 103, + 165, + 85, + 121, + 115, + 199, + 230, + 112, + 239, + 161, + 107, + 13, + 70, + 221, + 92, + 85, + 70, + 58, + 237, + 72, + 48, + 26, + 190, + 144, + 145, + 32, + 54, + 247, + 215, + 41, + 135, + 89, + 123, + 202, + 65, + 135, + 128, + 155, + 104, + 178, + 46, + 107, + 219, + 34, + 75, + 206, + 108, + 90, + 39, + 31, + 219, + 22, + 5, + 54, + 69, + 225, + 5, + 47, + 89, + 204, + 102, + 51, + 52, + 128, + 153, + 172, + 92, + 62, + 192, + 112, + 239, + 45, + 228, + 71, + 69, + 185, + 199, + 107, + 88, + 79, + 138, + 48, + 80, + 125, + 142, + 51, + 67, + 201, + 1, + 105, + 172, + 85, + 74, + 120, + 87, + 35, + 200, + 155, + 112, + 6, + 231, + 132, + 178, + 162, + 8, + 54, + 216, + 127, + 134, + 76, + 155, + 34, + 81, + 72, + 22, + 137, + 239, + 106, + 225, + 122, + 12, + 115, + 199, + 123, + 144, + 127, + 227, + 213, + 190, + 107, + 155, + 11, + 155, + 148, + 79, + 239, + 165, + 149, + 107, + 29, + 239, + 194, + 57, + 144, + 15, + 41, + 254, + 46, + 59, + 219, + 132, + 52, + 89, + 20, + 163, + 93, + 254, + 74, + 117, + 189, + 217, + 35, + 127, + 110, + 124, + 223, + 153, + 56, + 230, + 99, + 26, + 120, + 235, + 102, + 79, + 225, + 166, + 59, + 92, + 226, + 139, + 210, + 176, + 71, + 132, + 193, + 221, + 240, + 77, + 179, + 26, + 234, + 39, + 36, + 145, + 138, + 3, + 182, + 211, + 136, + 101, + 95, + 238, + 206, + 92, + 81, + 93, + 11, + 66, + 73, + 215, + 27, + 147, + 234, + 201, + 239, + 14, + 65, + 101, + 92, + 219, + 174, + 154, + 13, + 105, + 186, + 145, + 184, + 181, + 198, + 70, + 158, + 84, + 128, + 182, + 217, + 11, + 48, + 182, + 129, + 111, + 15, + 95, + 84, + 69, + 190, + 198, + 146, + 229, + 54, + 125, + 193, + 153, + 37, + 39, + 76, + 36, + 8, + 95, + 175, + 179, + 176, + 149, + 3, + 193, + 138, + 18, + 154, + 185, + 53, + 62, + 19, + 247, + 38, + 162, + 241, + 91, + 173, + 96, + 40, + 60, + 142, + 120, + 22, + 97, + 103, + 154, + 68, + 79, + 51, + 70, + 133, + 71, + 201, + 159, + 212, + 118, + 50, + 184, + 21, + 5, + 142, + 78, + 224, + 149, + 47, + 65, + 31, + 53, + 246, + 13, + 217, + 53, + 159, + 160, + 142, + 10, + 125, + 59, + 55, + 134, + 219, + 89, + 171, + 5, + 244, + 123, + 245, + 77, + 182, + 117, + 20, + 33, + 13, + 205, + 224, + 14, + 33, + 102, + 245, + 223, + 150, + 254, + 211, + 168, + 77, + 18, + 165, + 183, + 72, + 196, + 62, + 231, + 155, + 223, + 101, + 102, + 205, + 109, + 8, + 126, + 47, + 144, + 166, + 97, + 50, + 102, + 188, + 87, + 49, + 61, + 88, + 20, + 178, + 190, + 155, + 136, + 191, + 193, + 23, + 107, + 110, + 98, + 137, + 15, + 19, + 108, + 133, + 215, + 190, + 15, + 6, + 106, + 134, + 173, + 165, + 208, + 139, + 9, + 174, + 179, + 6, + 127, + 156, + 235, + 44, + 141, + 132, + 84, + 209, + 156, + 209, + 164, + 254, + 89, + 120, + 57, + 80, + 0, + 109, + 196, + 101, + 201, + 168, + 150, + 151, + 85, + 25, + 162, + 178, + 148, + 5, + 149, + 8, + 211, + 104, + 15, + 242, + 98, + 7, + 60, + 194, + 197, + 40, + 100, + 44, + 52, + 244, + 72, + 152, + 44, + 13, + 155, + 42, + 250, + 209, + 45, + 147, + 115, + 2, + 188, + 177, + 217, + 14, + 113, + 13, + 1, + 135, + 147, + 27, + 159, + 21, + 160, + 9, + 20, + 19, + 185, + 122, + 14, + 56, + 42, + 248, + 11, + 202, + 79, + 41, + 235, + 83, + 46, + 184, + 72, + 235, + 166, + 140, + 112, + 169, + 115, + 81, + 241, + 241, + 174, + 18, + 101, + 105, + 250, + 214, + 242, + 29, + 202, + 207, + 217, + 181, + 218, + 86, + 81, + 115, + 143, + 84, + 117, + 20, + 113, + 214, + 149, + 224, + 21, + 39, + 165, + 180, + 226, + 81, + 211, + 117, + 60, + 182, + 79, + 251, + 124, + 248, + 129, + 67, + 143, + 104, + 50, + 127, + 17, + 162, + 11, + 57, + 16, + 246, + 215, + 109, + 63, + 217, + 60, + 64, + 175, + 218, + 191, + 120, + 38, + 15, + 159, + 245, + 243, + 185, + 224, + 254, + 201, + 169, + 207, + 155, + 198, + 98, + 250, + 157, + 231, + 29, + 134, + 70, + 37, + 214, + 8, + 193, + 2, + 9, + 67, + 6, + 159, + 104, + 37, + 18, + 253, + 97, + 53, + 197, + 201, + 122, + 228, + 77, + 190, + 3, + 49, + 31, + 253, + 244, + 235, + 209, + 129, + 237, + 106, + 124, + 226, + 94, + 227, + 199, + 163, + 39, + 178, + 176, + 253, + 60, + 170, + 207, + 222, + 104, + 45, + 58, + 57, + 254, + 251, + 217, + 241, + 37, + 83, + 55, + 160, + 189, + 144, + 164, + 72, + 167, + 14, + 146, + 162, + 153, + 137, + 33, + 46, + 247, + 252, + 192, + 232, + 199, + 48, + 174, + 44, + 36, + 158, + 5, + 18, + 38, + 122, + 57, + 137, + 216, + 82, + 37, + 222, + 253, + 135, + 242, + 175, + 70, + 139, + 243, + 100, + 8, + 54, + 48, + 113, + 112, + 19, + 141, + 206, + 173, + 95, + 231, + 9, + 97, + 251, + 98, + 246, + 61, + 254, + 156, + 199, + 181, + 180, + 126, + 56, + 25, + 130, + 225, + 151, + 251, + 233, + 88, + 83, + 164, + 128, + 64, + 134, + 199, + 166, + 73, + 78, + 29, + 242, + 218, + 61, + 37, + 93, + 213, + 154, + 176, + 222, + 148, + 34, + 70, + 47, + 57, + 9, + 32, + 182, + 81, + 106, + 121, + 110, + 108, + 47, + 34, + 203, + 232, + 31, + 202, + 129, + 72, + 37, + 52, + 127, + 85, + 192, + 25, + 0, + 22, + 235, + 187, + 242, + 214, + 189, + 243, + 64, + 251, + 59, + 108, + 84, + 161, + 235, + 138, + 161, + 170, + 192, + 206, + 48, + 218, + 182, + 160, + 97, + 204, + 61, + 27, + 5, + 226, + 79, + 7, + 207, + 128, + 240, + 237, + 68, + 213, + 9, + 99, + 167, + 214, + 85, + 132, + 30, + 158, + 147, + 237, + 79, + 221, + 16, + 161, + 132, + 191, + 105, + 246, + 254, + 233, + 156, + 217, + 240, + 53, + 29, + 83, + 163, + 228, + 209, + 111, + 76, + 112, + 97, + 142, + 187, + 138, + 228, + 129, + 176, + 84, + 7, + 189, + 242, + 109, + 192, + 181, + 217, + 144, + 122, + 214, + 36, + 182, + 76, + 80, + 157, + 163, + 30, + 104, + 97, + 191, + 57, + 249, + 244, + 129, + 39, + 197, + 204, + 234, + 48, + 103, + 150, + 21, + 220, + 84, + 2, + 108, + 200, + 240, + 159, + 75, + 29, + 96, + 124, + 74, + 71, + 169, + 154, + 223, + 176, + 112, + 183, + 62, + 102, + 245, + 28, + 128, + 216, + 136, + 116, + 75, + 238, + 4, + 217, + 102, + 194, + 166, + 162, + 238, + 200, + 142, + 12, + 98, + 46, + 122, + 34, + 19, + 84, + 135, + 246, + 165, + 38, + 0, + 6, + 30, + 45, + 14, + 2, + 244, + 215, + 143, + 112, + 166, + 215, + 59, + 180, + 219, + 35, + 17, + 212, + 139, + 133, + 115, + 247, + 227, + 1, + 128, + 179, + 156, + 203, + 124, + 108, + 208, + 238, + 89, + 118, + 54, + 126, + 106, + 152, + 196, + 126, + 201, + 125, + 120, + 110, + 97, + 86, + 175, + 199, + 51, + 151, + 239, + 152, + 102, + 81, + 55, + 96, + 246, + 148, + 20, + 41, + 55, + 162, + 206, + 141, + 66, + 233, + 31, + 72, + 34, + 193, + 197, + 31, + 161, + 31, + 49, + 246, + 198, + 245, + 127, + 190, + 70, + 36, + 60, + 174, + 165, + 30, + 24, + 238, + 103, + 226, + 35, + 170, + 201, + 45, + 190, + 36, + 16, + 185, + 172, + 253, + 93, + 230, + 102, + 243, + 155, + 233, + 149, + 237, + 23, + 172, + 1, + 89, + 243, + 247, + 243, + 140, + 118, + 177, + 1, + 156, + 187, + 222, + 46, + 159, + 238, + 178, + 94, + 8, + 29, + 80, + 87, + 168, + 169, + 143, + 64, + 37, + 65, + 180, + 127, + 190, + 106, + 86, + 45, + 157, + 237, + 67, + 48, + 157, + 255, + 24, + 10, + 252, + 231, + 211, + 163, + 91, + 109, + 44, + 109, + 110, + 42, + 122, + 91, + 157, + 68, + 58, + 202, + 138, + 18, + 88, + 235, + 151, + 173, + 63, + 78, + 102, + 184, + 74, + 96, + 10, + 114, + 92, + 12, + 199, + 196, + 39, + 15, + 102, + 193, + 114, + 92, + 57, + 32, + 166, + 141, + 51, + 35, + 95, + 39, + 36, + 56, + 146, + 220, + 157, + 56, + 233, + 85, + 134, + 127, + 83, + 56, + 178, + 175, + 65, + 101, + 106, + 89, + 102, + 163, + 247, + 161, + 4, + 173, + 229, + 68, + 240, + 80, + 255, + 91, + 64, + 211, + 112, + 241, + 181, + 155, + 81, + 0, + 51, + 209, + 120, + 166, + 197, + 241, + 212, + 60, + 165, + 66, + 23, + 47, + 79, + 184, + 103, + 170, + 52, + 107, + 84, + 95, + 120, + 65, + 9, + 234, + 7, + 192, + 109, + 193, + 150, + 142, + 130, + 237, + 19, + 3, + 18, + 210, + 19, + 228, + 135, + 33, + 248, + 38, + 5, + 70, + 248, + 153, + 13, + 241, + 185, + 205, + 36, + 5, + 175, + 183, + 141, + 183, + 207, + 186, + 28, + 120, + 145, + 78, + 26, + 172, + 81, + 22, + 150, + 131, + 140, + 171, + 84, + 226, + 170, + 83, + 196, + 19, + 184, + 163, + 188, + 174, + 105, + 11, + 133, + 111, + 127, + 201, + 28, + 235, + 86, + 179, + 211, + 100, + 0, + 32, + 62, + 191, + 245, + 155, + 89, + 234, + 203, + 2, + 192, + 184, + 177, + 62, + 22, + 21, + 79, + 114, + 2, + 215, + 146, + 40, + 88, + 1, + 197, + 212, + 249, + 70, + 162, + 152, + 34, + 96, + 239, + 222, + 180, + 152, + 192, + 238, + 15, + 110, + 204, + 6, + 126, + 24, + 141, + 200, + 149, + 188, + 200, + 198, + 82, + 138, + 200, + 205, + 0, + 38, + 36, + 122, + 19, + 164, + 25, + 107, + 164, + 249, + 208, + 17, + 167, + 90, + 254, + 40, + 185, + 122, + 102, + 0, + 122, + 21, + 152, + 150, + 41, + 236, + 89, + 219, + 45, + 151, + 68, + 18, + 239, + 29, + 88, + 91, + 32, + 188, + 83, + 129, + 66, + 10, + 43, + 31, + 70, + 85, + 27, + 237, + 131, + 160, + 74, + 54, + 47, + 244, + 130, + 178, + 17, + 107, + 134, + 199, + 50, + 51, + 98, + 106, + 182, + 34, + 10, + 163, + 183, + 234, + 178, + 55, + 171, + 196, + 212, + 85, + 204, + 172, + 205, + 170, + 46, + 253, + 134, + 134, + 12, + 86, + 103, + 31, + 231, + 222, + 55, + 231, + 109, + 179, + 180, + 72, + 82, + 115, + 89, + 228, + 175, + 120, + 148, + 136, + 130, + 30, + 240, + 70, + 248, + 126, + 96, + 163, + 182, + 210, + 175, + 166, + 186, + 11, + 182, + 26, + 64, + 239, + 205, + 8, + 114, + 5, + 54, + 21, + 200, + 65, + 119, + 44, + 149, + 136, + 125, + 177, + 28, + 70, + 9, + 30, + 86, + 176, + 37, + 160, + 219, + 164, + 44, + 150, + 115, + 18, + 56, + 122, + 85, + 214, + 35, + 2, + 51, + 77, + 0, + 53, + 77, + 60, + 76, + 156, + 205, + 143, + 177, + 176, + 145, + 160, + 135, + 214, + 59, + 250, + 58, + 162, + 24, + 32, + 239, + 143, + 120, + 170, + 190, + 172, + 81, + 246, + 44, + 113, + 187, + 67, + 166, + 97, + 164, + 40, + 176, + 158, + 42, + 44, + 212, + 156, + 211, + 75, + 106, + 7, + 184, + 0, + 207, + 19, + 80, + 174, + 23, + 207, + 110, + 143, + 235, + 151, + 226, + 66, + 49, + 18, + 41, + 51, + 250, + 17, + 130, + 105, + 228, + 177, + 172, + 42, + 86, + 165, + 235, + 164, + 229, + 213, + 246, + 57, + 173, + 153, + 169, + 158, + 76, + 138, + 7, + 23, + 4, + 155, + 122, + 122, + 126, + 44, + 122, + 129, + 185, + 65, + 59, + 83, + 171, + 244, + 180, + 205, + 246, + 51, + 239, + 236, + 180, + 51, + 211, + 124, + 114, + 98, + 245, + 175, + 166, + 83, + 130, + 82, + 90, + 88, + 95, + 56, + 39, + 86, + 59, + 58, + 226, + 42, + 183, + 111, + 186, + 29, + 175, + 192, + 104, + 141, + 84, + 128, + 55, + 12, + 12, + 132, + 192, + 102, + 163, + 200, + 71, + 221, + 237, + 48, + 229, + 109, + 187, + 211, + 224, + 243, + 194, + 128, + 41, + 235, + 196, + 38, + 133, + 196, + 71, + 77, + 69, + 111, + 133, + 166, + 95, + 143, + 171, + 14, + 171, + 232, + 144, + 203, + 25, + 26, + 184, + 159, + 245, + 128, + 56, + 56, + 238, + 60, + 43, + 41, + 190, + 2, + 88, + 20, + 84, + 74, + 95, + 101, + 71, + 7, + 61, + 64, + 125, + 81, + 252, + 86, + 52, + 252, + 163, + 113, + 77, + 133, + 31, + 37, + 226, + 83, + 94, + 167, + 63, + 128, + 9, + 51, + 170, + 104, + 99, + 59, + 43, + 241, + 105, + 59, + 141, + 18, + 155, + 52, + 235, + 113, + 113, + 221, + 230, + 152, + 177, + 3, + 250, + 81, + 65, + 8, + 113, + 143, + 155, + 48, + 54, + 66, + 74, + 169, + 155, + 134, + 253, + 65, + 69, + 136, + 153, + 223, + 20, + 90, + 184, + 32, + 222, + 44, + 23, + 131, + 221, + 237, + 217, + 3, + 81, + 80, + 112, + 58, + 105, + 25, + 173, + 93, + 66, + 130, + 60, + 121, + 156, + 234, + 208, + 101, + 25, + 89, + 11, + 226, + 29, + 141, + 77, + 29, + 120, + 29, + 201, + 20, + 117, + 101, + 63, + 155, + 90, + 231, + 27, + 75, + 154, + 127, + 152, + 54, + 130, + 85, + 24, + 13, + 235, + 150, + 185, + 78, + 71, + 200, + 179, + 43, + 175, + 77, + 29, + 95, + 94, + 53, + 152, + 205, + 178, + 93, + 12, + 145, + 0, + 152, + 234, + 184, + 158, + 137, + 166, + 11, + 40, + 215, + 130, + 87, + 71, + 105, + 49, + 15, + 225, + 28, + 46, + 122, + 103, + 177, + 16, + 217, + 242, + 206, + 40, + 135, + 3, + 230, + 200, + 225, + 45, + 241, + 11, + 62, + 199, + 76, + 221, + 237, + 25, + 97, + 75, + 162, + 141, + 170, + 150, + 67, + 98, + 8, + 168, + 226, + 18, + 116, + 32, + 208, + 89, + 249, + 68, + 193, + 179, + 185, + 226, + 140, + 158, + 11, + 166, + 217, + 125, + 103, + 66, + 27, + 107, + 76, + 149, + 33, + 214, + 249, + 134, + 92, + 148, + 196, + 115, + 203, + 171, + 221, + 7, + 231, + 77, + 87, + 190, + 35, + 60, + 248, + 210, + 153, + 209, + 105, + 174, + 97, + 196, + 58, + 65, + 153, + 114, + 238, + 199, + 246, + 3, + 117, + 177, + 86, + 181, + 27, + 211, + 148, + 39, + 75, + 39, + 198, + 211, + 157, + 22, + 201, + 32, + 230, + 236, + 177, + 134, + 216, + 6, + 20, + 200, + 161, + 108, + 180, + 197, + 192, + 239, + 149, + 66, + 94, + 108, + 43, + 179, + 14, + 68, + 50, + 11, + 92, + 201, + 100, + 184, + 213, + 2, + 186, + 207, + 219, + 193, + 17, + 201, + 8, + 162, + 207, + 142, + 111, + 27, + 194, + 101, + 205, + 2, + 98, + 20, + 59, + 215, + 106, + 143, + 127, + 211, + 133, + 215, + 29, + 66, + 44, + 138, + 103, + 172, + 230, + 106, + 55, + 194, + 194, + 72, + 87, + 137, + 191, + 32, + 52, + 163, + 250, + 131, + 117, + 139, + 240, + 20, + 110, + 8, + 0, + 168, + 15, + 66, + 87, + 197, + 43, + 0, + 232, + 221, + 172, + 167, + 203, + 61, + 18, + 21, + 194, + 193, + 62, + 64, + 197, + 41, + 171, + 175, + 118, + 5, + 66, + 13, + 174, + 128, + 36, + 252, + 92, + 24, + 255, + 233, + 44, + 100, + 31, + 197, + 9, + 119, + 149, + 172, + 61, + 157, + 197, + 61, + 3, + 23, + 234, + 103, + 9, + 1, + 66, + 255, + 8, + 110, + 23, + 137, + 209, + 123, + 140, + 205, + 111, + 226, + 142, + 96, + 78, + 79, + 210, + 75, + 111, + 82, + 118, + 33, + 59, + 81, + 167, + 119, + 144, + 172, + 159, + 146, + 98, + 216, + 79, + 170, + 63, + 140, + 167, + 61, + 214, + 58, + 249, + 181, + 73, + 50, + 145, + 243, + 69, + 52, + 138, + 203, + 88, + 56, + 124, + 130, + 243, + 32, + 193, + 91, + 39, + 9, + 157, + 24, + 72, + 26, + 183, + 29, + 46, + 249, + 66, + 118, + 38, + 85, + 219, + 82, + 35, + 30, + 81, + 230, + 231, + 194, + 78, + 66, + 135, + 111, + 199, + 115, + 134, + 208, + 29, + 155, + 248, + 51, + 29, + 64, + 26, + 220, + 60, + 193, + 187, + 182, + 59, + 215, + 191, + 180, + 44, + 4, + 80, + 15, + 15, + 107, + 191, + 113, + 229, + 132, + 124, + 156, + 207, + 222, + 194, + 174, + 129, + 107, + 60, + 10, + 91, + 128, + 226, + 103, + 63, + 155, + 160, + 92, + 142, + 18, + 151, + 67, + 138, + 45, + 36, + 122, + 214, + 7, + 198, + 173, + 128, + 1, + 251, + 164, + 2, + 32, + 181, + 219, + 120, + 146, + 164, + 229, + 247, + 164, + 197, + 91, + 101, + 87, + 41, + 59, + 76, + 170, + 235, + 66, + 81, + 172, + 45, + 60, + 194, + 244, + 159, + 194, + 35, + 235, + 222, + 44, + 8, + 56, + 255, + 3, + 61, + 66, + 111, + 40, + 61, + 235, + 157, + 90, + 112, + 244, + 160, + 124, + 201, + 54, + 60, + 148, + 117, + 7, + 20, + 44, + 150, + 110, + 154, + 214, + 212, + 25, + 133, + 142, + 216, + 125, + 128, + 157, + 233, + 55, + 130, + 224, + 254, + 30, + 208, + 187, + 238, + 81, + 197, + 119, + 7, + 81, + 32, + 252, + 77, + 42, + 112, + 15, + 128, + 182, + 113, + 201, + 191, + 89, + 255, + 124, + 255, + 171, + 86, + 248, + 215, + 104, + 238, + 52, + 236, + 220, + 60, + 129, + 157, + 63, + 251, + 4, + 177, + 89, + 97, + 46, + 20, + 253, + 99, + 1, + 175, + 7, + 177, + 133, + 76, + 244, + 111, + 156, + 23, + 16, + 126, + 150, + 30, + 198, + 40, + 95, + 226, + 182, + 58, + 44, + 10, + 239, + 70, + 4, + 228, + 217, + 31, + 84, + 43, + 190, + 15, + 81, + 172, + 208, + 59, + 77, + 106, + 215, + 76, + 212, + 226, + 39, + 204, + 87, + 69, + 214, + 22, + 13, + 210, + 1, + 191, + 244, + 73, + 43, + 126, + 61, + 93, + 188, + 95, + 188, + 86, + 85, + 21, + 143, + 38, + 128, + 235, + 245, + 30, + 98, + 23, + 26, + 64, + 23, + 117, + 222, + 189, + 139, + 100, + 10, + 14, + 79, + 217, + 71, + 53, + 174, + 76, + 216, + 157, + 98, + 186, + 103, + 156, + 238, + 62, + 244, + 229, + 241, + 246, + 237, + 125, + 157, + 216, + 111, + 161, + 47, + 168, + 147, + 255, + 254, + 136, + 81, + 119, + 124, + 40, + 144, + 46, + 154, + 4, + 19, + 196, + 215, + 185, + 154, + 187, + 88, + 112, + 111, + 158, + 135, + 71, + 137, + 1, + 119, + 187, + 131, + 245, + 84, + 50, + 76, + 151, + 251, + 110, + 94, + 232, + 242, + 142, + 196, + 56, + 31, + 153, + 79, + 225, + 97, + 163, + 168, + 243, + 220, + 7, + 160, + 178, + 14, + 69, + 187, + 104, + 211, + 8, + 226, + 18, + 10, + 23, + 219, + 54, + 62, + 80, + 92, + 240, + 60, + 148, + 58, + 47, + 106, + 249, + 171, + 57, + 113, + 181, + 103, + 161, + 169, + 57, + 17, + 195, + 30, + 76, + 223, + 162, + 223, + 180, + 132, + 103, + 90, + 158, + 2, + 239, + 68, + 74, + 168, + 173, + 73, + 75, + 4, + 217, + 197, + 255, + 46, + 14, + 150, + 157, + 1, + 112, + 230, + 76, + 111, + 135, + 206, + 42, + 71, + 99, + 251, + 236, + 134, + 88, + 123, + 140, + 149, + 74, + 26, + 178, + 103, + 201, + 90, + 169, + 136, + 22, + 100, + 31, + 237, + 208, + 18, + 155, + 85, + 200, + 143, + 64, + 61, + 100, + 81, + 194, + 27, + 75, + 163, + 35, + 203, + 177, + 216, + 74, + 78, + 250, + 52, + 137, + 98, + 139, + 239, + 186, + 232, + 3, + 105, + 146, + 107, + 239, + 239, + 74, + 174, + 128, + 128, + 110, + 75, + 216, + 69, + 133, + 234, + 36, + 198, + 172, + 111, + 185, + 106, + 93, + 102, + 241, + 83, + 141, + 29, + 117, + 43, + 55, + 126, + 73, + 162, + 142, + 246, + 116, + 123, + 198, + 41, + 106, + 101, + 50, + 78, + 17, + 123, + 124, + 55, + 201, + 172, + 98, + 41, + 223, + 37, + 96, + 112, + 114, + 140, + 161, + 198, + 122, + 19, + 134, + 109, + 112, + 6, + 241, + 175, + 246, + 67, + 245, + 212, + 83, + 11, + 47, + 125, + 252, + 15, + 125, + 118, + 208, + 58, + 254, + 0, + 119, + 156, + 32, + 49, + 60, + 152, + 251, + 116, + 92, + 10, + 53, + 178, + 221, + 64, + 244, + 245, + 209, + 235, + 127, + 230, + 45, + 78, + 81, + 24, + 5, + 46, + 80, + 252, + 194, + 244, + 106, + 205, + 82, + 185, + 226, + 157, + 19, + 106, + 208, + 145, + 2, + 147, + 34, + 51, + 76, + 43, + 162, + 176, + 79, + 2, + 43, + 217, + 30, + 23, + 5, + 77, + 52, + 230, + 250, + 213, + 42, + 135, + 110, + 62, + 193, + 123, + 174, + 188, + 249, + 39, + 21, + 223, + 12, + 243, + 89, + 149, + 114, + 202, + 130, + 218, + 226, + 137, + 139, + 199, + 72, + 13, + 79, + 172, + 55, + 107, + 40, + 176, + 88, + 67, + 124, + 12, + 171, + 108, + 147, + 80, + 143, + 226, + 45, + 195, + 63, + 107, + 93, + 222, + 27, + 55, + 0, + 0, + 48, + 111, + 249, + 54, + 152, + 93, + 109, + 121, + 224, + 15, + 81, + 253, + 253, + 121, + 1, + 224, + 146, + 235, + 240, + 247, + 130, + 58, + 173, + 108, + 101, + 105, + 158, + 71, + 97, + 204, + 103, + 134, + 84, + 194, + 181, + 162, + 190, + 57, + 38, + 123, + 154, + 247, + 222, + 128, + 21, + 254, + 94, + 54, + 7, + 101, + 149, + 35, + 219, + 171, + 41, + 14, + 102, + 130, + 115, + 163, + 216, + 157, + 197, + 186, + 62, + 244, + 25, + 164, + 226, + 204, + 74, + 67, + 192, + 145, + 149, + 131, + 54, + 19, + 136, + 72, + 59, + 111, + 207, + 43, + 18, + 154, + 254, + 104, + 109, + 97, + 139, + 69, + 249, + 89, + 44, + 26, + 67, + 150, + 222, + 39, + 212, + 18, + 108, + 205, + 220, + 162, + 195, + 198, + 96, + 83, + 101, + 224, + 8, + 216, + 46, + 160, + 20, + 23, + 249, + 59, + 44, + 95, + 150, + 41, + 46, + 178, + 152, + 233, + 4, + 148, + 38, + 132, + 196, + 87, + 100, + 224, + 3, + 63, + 230, + 178, + 241, + 108, + 93, + 179, + 163, + 50, + 105, + 158, + 111, + 145, + 187, + 234, + 196, + 235, + 84, + 44, + 12, + 205, + 187, + 243, + 52, + 229, + 135, + 191, + 92, + 134, + 6, + 193, + 65, + 146, + 115, + 79, + 131, + 164, + 204, + 11, + 184, + 217, + 165, + 120, + 34, + 143, + 118, + 124, + 21, + 240, + 93, + 28, + 23, + 89, + 170, + 250, + 45, + 116, + 46, + 19, + 55, + 218, + 83, + 151, + 160, + 29, + 32, + 19, + 99, + 186, + 251, + 61, + 24, + 194, + 62, + 56, + 44, + 32, + 97, + 102, + 66, + 91, + 208, + 197, + 132, + 148, + 230, + 150, + 241, + 74, + 191, + 131, + 182, + 195, + 82, + 96, + 110, + 237, + 171, + 117, + 207, + 136, + 229, + 136, + 204, + 3, + 234, + 252, + 227, + 203, + 109, + 103, + 180, + 177, + 5, + 176, + 216, + 175, + 215, + 252, + 148, + 118, + 182, + 161, + 70, + 214, + 16, + 179, + 151, + 179, + 248, + 147, + 110, + 0, + 132, + 235, + 153, + 154, + 127, + 143, + 8, + 255, + 119, + 82, + 139, + 26, + 201, + 27, + 244, + 195, + 203, + 3, + 240, + 100, + 255, + 151, + 70, + 116, + 87, + 0, + 104, + 63, + 66, + 157, + 4, + 63, + 117, + 19, + 76, + 187, + 81, + 209, + 242, + 218, + 144, + 224, + 236, + 247, + 106, + 54, + 51, + 64, + 125, + 138, + 64, + 131, + 92, + 252, + 83, + 14, + 25, + 68, + 71, + 213, + 84, + 161, + 167, + 130, + 207, + 44, + 50, + 55, + 150, + 252, + 147, + 158, + 46, + 226, + 97, + 236, + 243, + 193, + 52, + 165, + 252, + 86, + 202, + 80, + 172, + 152, + 204, + 116, + 56, + 67, + 62, + 20, + 27, + 161, + 245, + 215, + 50, + 51, + 95, + 37, + 156, + 87, + 242, + 103, + 198, + 76, + 79, + 40, + 232, + 80, + 85, + 89, + 131, + 238, + 107, + 32, + 132, + 163, + 208, + 236, + 18, + 154, + 170, + 81, + 239, + 211, + 136, + 208, + 7, + 121, + 113, + 99, + 200, + 228, + 81, + 20, + 75, + 17, + 210, + 255, + 212, + 85, + 228, + 150, + 162, + 31, + 102, + 143, + 71, + 73, + 1, + 247, + 22, + 18, + 46, + 157, + 161, + 129, + 118, + 237, + 203, + 165, + 55, + 183, + 86, + 19, + 148, + 88, + 88, + 10, + 111, + 116, + 30, + 23, + 72, + 70, + 41, + 71, + 142, + 125, + 138, + 174, + 29, + 235, + 99, + 202, + 158, + 82, + 4, + 33, + 5, + 77, + 62, + 201, + 127, + 213, + 155, + 159, + 36, + 156, + 68, + 122, + 222, + 213, + 106, + 114, + 31, + 181, + 131, + 237, + 162, + 65, + 194, + 64, + 201, + 123, + 28, + 127, + 157, + 154, + 169, + 246, + 80, + 31, + 148, + 188, + 189, + 142, + 219, + 23, + 75, + 243, + 12, + 122, + 56, + 44, + 32, + 83, + 108, + 7, + 206, + 32, + 213, + 30, + 110, + 235, + 68, + 38, + 7, + 82, + 104, + 44, + 189, + 182, + 33, + 66, + 194, + 218, + 238, + 88, + 49, + 223, + 252, + 59, + 18, + 160, + 193, + 145, + 170, + 218, + 30, + 239, + 142, + 83, + 155, + 154, + 12, + 247, + 116, + 242, + 34, + 190, + 128, + 27, + 100, + 217, + 98, + 154, + 227, + 122, + 237, + 138, + 213, + 136, + 105, + 228, + 106, + 159, + 60, + 187, + 248, + 131, + 164, + 33, + 19, + 119, + 11, + 10, + 30, + 38, + 108, + 19, + 48, + 51, + 240, + 167, + 57, + 132, + 204, + 39, + 120, + 77, + 94, + 86, + 195, + 83, + 170, + 245, + 10, + 11, + 230, + 175, + 248, + 5, + 148, + 200, + 146, + 178, + 53, + 171, + 55, + 46, + 21, + 233, + 89, + 192, + 208, + 173, + 109, + 16, + 130, + 75, + 30, + 49, + 52, + 185, + 39, + 142, + 134, + 204, + 43, + 146, + 92, + 46, + 149, + 201, + 129, + 49, + 204, + 159, + 180, + 224, + 26, + 112, + 74, + 63, + 59, + 155, + 75, + 153, + 95, + 241, + 46, + 240, + 23, + 152, + 71, + 62, + 185, + 158, + 141, + 95, + 108, + 9, + 246, + 84, + 171, + 159, + 200, + 172, + 165, + 236, + 120, + 19, + 223, + 65, + 188, + 182, + 84, + 28, + 227, + 248, + 202, + 146, + 36, + 141, + 68, + 212, + 68, + 173, + 192, + 140, + 150, + 223, + 147, + 135, + 111, + 1, + 47, + 163, + 122, + 22, + 21, + 69, + 53, + 175, + 149, + 66, + 95, + 195, + 59, + 23, + 4, + 100, + 32, + 106, + 171, + 34, + 51, + 175, + 10, + 141, + 103, + 212, + 116, + 231, + 46, + 113, + 8, + 156, + 44, + 144, + 241, + 122, + 253, + 157, + 25, + 89, + 148, + 68, + 48, + 48, + 67, + 183, + 13, + 164, + 51, + 226, + 145, + 54, + 125, + 28, + 89, + 202, + 96, + 136, + 103, + 199, + 170, + 28, + 95, + 120, + 82, + 215, + 184, + 172, + 81, + 198, + 107, + 165, + 15, + 48, + 13, + 54, + 71, + 127, + 231, + 2, + 156, + 155, + 135, + 148, + 215, + 97, + 191, + 198, + 232, + 216, + 159, + 206, + 88, + 124, + 251, + 6, + 134, + 226, + 87, + 126, + 80, + 64, + 13, + 224, + 252, + 120, + 80, + 243, + 86, + 227, + 184, + 246, + 97, + 110, + 116, + 242, + 80, + 226, + 50, + 158, + 237, + 26, + 191, + 39, + 110, + 43, + 75, + 31, + 129, + 133, + 195, + 146, + 144, + 33, + 1, + 25, + 72, + 6, + 237, + 72, + 71, + 181, + 63, + 227, + 185, + 53, + 172, + 166, + 250, + 240, + 230, + 149, + 204, + 135, + 198, + 151, + 190, + 60, + 116, + 5, + 85, + 169, + 78, + 104, + 29, + 55, + 140, + 176, + 180, + 192, + 17, + 71, + 102, + 30, + 163, + 60, + 253, + 133, + 123, + 191, + 101, + 78, + 255, + 19, + 59, + 26, + 17, + 177, + 115, + 200, + 237, + 119, + 2, + 55, + 76, + 72, + 42, + 52, + 229, + 133, + 178, + 154, + 137, + 183, + 99, + 108, + 151, + 217, + 54, + 195, + 135, + 184, + 115, + 106, + 229, + 180, + 104, + 37, + 179, + 29, + 178, + 254, + 52, + 128, + 232, + 110, + 76, + 234, + 113, + 35, + 56, + 119, + 15, + 204, + 117, + 197, + 94, + 253, + 107, + 102, + 178, + 131, + 37, + 125, + 71, + 228, + 64, + 103, + 28, + 10, + 235, + 245, + 72, + 197, + 215, + 124, + 173, + 246, + 187, + 114, + 68, + 60, + 193, + 202, + 121, + 188, + 194, + 117, + 5, + 10, + 136, + 250, + 13, + 18, + 147, + 90, + 60, + 241, + 172, + 4, + 6, + 223, + 218, + 28, + 68, + 236, + 62, + 59, + 179, + 137, + 208, + 31, + 48, + 61, + 39, + 31, + 29, + 26, + 108, + 105, + 85, + 215, + 44, + 197, + 50, + 239, + 222, + 226, + 100, + 158, + 91, + 185, + 249, + 148, + 28, + 114, + 146, + 16, + 19, + 74, + 87, + 238, + 169, + 123, + 75, + 212, + 164, + 172, + 37, + 118, + 97, + 148, + 2, + 215, + 56, + 10, + 148, + 248, + 184, + 93, + 57, + 131, + 42, + 152, + 128, + 23, + 190, + 7, + 93, + 85, + 106, + 46, + 235, + 239, + 224, + 25, + 93, + 231, + 147, + 144, + 41, + 123, + 216, + 150, + 73, + 184, + 9, + 213, + 50, + 46, + 119, + 34, + 46, + 157, + 51, + 68, + 3, + 187, + 209, + 186, + 50, + 158, + 216, + 223, + 243, + 8, + 101, + 105, + 94, + 113, + 142, + 213, + 92, + 171, + 107, + 39, + 88, + 236, + 125, + 22, + 2, + 238, + 200, + 144, + 121, + 249, + 46, + 236, + 158, + 109, + 18, + 240, + 31, + 50, + 111, + 2, + 92, + 132, + 40, + 133, + 112, + 58, + 39, + 169, + 246, + 197, + 189, + 204, + 45, + 134, + 89, + 17, + 47, + 147, + 89, + 165, + 48, + 40, + 130, + 115, + 111, + 76, + 187, + 38, + 242, + 224, + 217, + 110, + 99, + 70, + 180, + 26, + 8, + 249, + 106, + 242, + 121, + 95, + 57, + 86, + 68, + 159, + 45, + 166, + 32, + 41, + 228, + 120, + 16, + 149, + 152, + 232, + 63, + 247, + 151, + 239, + 175, + 76, + 32, + 243, + 176, + 67, + 98, + 251, + 12, + 26, + 162, + 184, + 27, + 70, + 241, + 96, + 4, + 90, + 131, + 241, + 88, + 232, + 250, + 107, + 240, + 123, + 47, + 223, + 124, + 169, + 169, + 73, + 26, + 56, + 38, + 169, + 176, + 213, + 212, + 10, + 30, + 125, + 255, + 0, + 23, + 21, + 219, + 116, + 95, + 140, + 3, + 160, + 246, + 111, + 53, + 167, + 253, + 102, + 205, + 237, + 155, + 47, + 85, + 203, + 81, + 229, + 145, + 215, + 24, + 3, + 241, + 106, + 83, + 197, + 248, + 178, + 195, + 71, + 155, + 247, + 97, + 57, + 192, + 225, + 122, + 18, + 93, + 147, + 190, + 123, + 69, + 226, + 172, + 119, + 178, + 26, + 118, + 66, + 229, + 116, + 150, + 91, + 31, + 214, + 238, + 38, + 14, + 199, + 143, + 216, + 137, + 66, + 0, + 78, + 244, + 206, + 145, + 238, + 4, + 131, + 234, + 7, + 229, + 216, + 38, + 138, + 174, + 30, + 85, + 177, + 184, + 68, + 209, + 145, + 231, + 221, + 8, + 28, + 73, + 2, + 65, + 60, + 222, + 24, + 60, + 166, + 24, + 189, + 95, + 156, + 59, + 146, + 77, + 163, + 81, + 29, + 60, + 231, + 85, + 249, + 212, + 39, + 43, + 130, + 166, + 189, + 16, + 170, + 156, + 119, + 110, + 44, + 188, + 24, + 144, + 19, + 47, + 65, + 199, + 190, + 140, + 86, + 233, + 174, + 151, + 60, + 159, + 104, + 142, + 61, + 133, + 74, + 123, + 80, + 195, + 198, + 119, + 117, + 29, + 139, + 7, + 31, + 106, + 176, + 222, + 216, + 212, + 237, + 86, + 248, + 139, + 125, + 8, + 199, + 62, + 173, + 124, + 142, + 55, + 47, + 46, + 202, + 211, + 110, + 70, + 92, + 18, + 66, + 88, + 246, + 227, + 102, + 104, + 90, + 221, + 12, + 224, + 85, + 102, + 89, + 54, + 205, + 150, + 221, + 145, + 203, + 230, + 100, + 243, + 229, + 60, + 166, + 104, + 217, + 59, + 94, + 113, + 51, + 21, + 170, + 213, + 141, + 15, + 199, + 99, + 59, + 142, + 198, + 24, + 130, + 99, + 46, + 78, + 103, + 237, + 242, + 201, + 6, + 40, + 89, + 95, + 247, + 193, + 93, + 215, + 212, + 5, + 84, + 136, + 169, + 148, + 247, + 185, + 100, + 145, + 58, + 10, + 133, + 151, + 248, + 222, + 125, + 193, + 11, + 115, + 43, + 96, + 152, + 40, + 23, + 82, + 2, + 198, + 94, + 40, + 6, + 97, + 29, + 140, + 101, + 72, + 60, + 111, + 133, + 194, + 0, + 49, + 122, + 158, + 39, + 194, + 198, + 93, + 21, + 66, + 143, + 83, + 155, + 224, + 101, + 116, + 200, + 62, + 28, + 105, + 63, + 86, + 233, + 15, + 194, + 49, + 134, + 117, + 86, + 171, + 104, + 172, + 37, + 31, + 156, + 235, + 45, + 178, + 227, + 99, + 28, + 125, + 119, + 19, + 243, + 91, + 78, + 14, + 196, + 62, + 20, + 45, + 97, + 112, + 204, + 57, + 48, + 160, + 42, + 48, + 199, + 142, + 231, + 0, + 55, + 205, + 116, + 120, + 184, + 188, + 218, + 200, + 107, + 219, + 113, + 15, + 193, + 94, + 5, + 86, + 88, + 49, + 45, + 120, + 234, + 62, + 139, + 149, + 175, + 206, + 190, + 177, + 246, + 61, + 160, + 125, + 30, + 173, + 68, + 101, + 157, + 59, + 199, + 220, + 124, + 155, + 211, + 35, + 187, + 41, + 139, + 255, + 223, + 249, + 212, + 127, + 137, + 115, + 24, + 154, + 210, + 152, + 54, + 20, + 23, + 236, + 86, + 169, + 223, + 225, + 87, + 168, + 76, + 35, + 134, + 160, + 120, + 207, + 11, + 114, + 50, + 164, + 239, + 200, + 105, + 101, + 41, + 209, + 110, + 51, + 197, + 171, + 247, + 145, + 239, + 255, + 238, + 103, + 71, + 235, + 80, + 245, + 78, + 159, + 129, + 29, + 246, + 138, + 83, + 87, + 141, + 30, + 127, + 57, + 125, + 238, + 84, + 9, + 71, + 69, + 25, + 40, + 3, + 98, + 255, + 67, + 136, + 43, + 71, + 38, + 162, + 116, + 160, + 238, + 236, + 149, + 114, + 247, + 46, + 210, + 146, + 102, + 182, + 5, + 44, + 73, + 201, + 201, + 213, + 229, + 25, + 48, + 123, + 48, + 82, + 229, + 42, + 223, + 246, + 253, + 112, + 103, + 228, + 91, + 221, + 84, + 80, + 156, + 37, + 90, + 212, + 59, + 99, + 28, + 31, + 89, + 162, + 61, + 171, + 136, + 124, + 67, + 154, + 228, + 211, + 52, + 85, + 64, + 61, + 91, + 53, + 132, + 37, + 98, + 90, + 164, + 222, + 145, + 212, + 170, + 250, + 168, + 130, + 247, + 72, + 180, + 74, + 45, + 32, + 42, + 122, + 126, + 23, + 153, + 14, + 243, + 235, + 204, + 217, + 99, + 188, + 48, + 57, + 237, + 151, + 98, + 77, + 21, + 16, + 113, + 198, + 70, + 97, + 213, + 17, + 107, + 118, + 46, + 204, + 29, + 23, + 108, + 89, + 191, + 57, + 102, + 206, + 13, + 162, + 19, + 231, + 43, + 175, + 18, + 37, + 12, + 231, + 216, + 97, + 59, + 136, + 236, + 131, + 194, + 21, + 236, + 127, + 16, + 180, + 103, + 165, + 46, + 242, + 162, + 251, + 69, + 212, + 120, + 255, + 192, + 175, + 240, + 250, + 79, + 237, + 225, + 71, + 151, + 48, + 77, + 35, + 156, + 7, + 168, + 73, + 183, + 131, + 201, + 51, + 201, + 31, + 102, + 195, + 7, + 68, + 54, + 224, + 117, + 33, + 64, + 105, + 175, + 71, + 241, + 250, + 80, + 115, + 132, + 168, + 185, + 169, + 76, + 68, + 21, + 197, + 82, + 234, + 130, + 199, + 30, + 78, + 44, + 153, + 175, + 192, + 72, + 61, + 146, + 201, + 3, + 205, + 234, + 45, + 51, + 217, + 115, + 117, + 65, + 193, + 40, + 192, + 88, + 44, + 55, + 178, + 236, + 203, + 175, + 2, + 44, + 202, + 6, + 231, + 184, + 233, + 93, + 130, + 66, + 132, + 127, + 10, + 83, + 131, + 238, + 175, + 146, + 243, + 196, + 200, + 219, + 211, + 88, + 252, + 136, + 183, + 229, + 230, + 226, + 120, + 13, + 143, + 130, + 173, + 160, + 198, + 63, + 117, + 199, + 254, + 26, + 99, + 124, + 76, + 233, + 190, + 204, + 35, + 215, + 200, + 120, + 23, + 157, + 1, + 88, + 161, + 14, + 83, + 233, + 46, + 89, + 143, + 9, + 6, + 127, + 72, + 111, + 253, + 105, + 69, + 125, + 187, + 83, + 241, + 90, + 151, + 237, + 113, + 148, + 208, + 239, + 179, + 19, + 170, + 192, + 120, + 52, + 9, + 224, + 199, + 76, + 45, + 193, + 59, + 19, + 204, + 157, + 165, + 124, + 113, + 220, + 130, + 83, + 244, + 74, + 126, + 229, + 9, + 156, + 231, + 209, + 175, + 186, + 226, + 53, + 146, + 105, + 6, + 117, + 132, + 64, + 96, + 7, + 163, + 188, + 119, + 90, + 155, + 231, + 68, + 113, + 51, + 157, + 129, + 194, + 191, + 60, + 87, + 96, + 220, + 217, + 64, + 180, + 125, + 89, + 22, + 239, + 173, + 79, + 54, + 230, + 168, + 248, + 59, + 244, + 229, + 1, + 167, + 227, + 40, + 242, + 114, + 29, + 147, + 154, + 204, + 94, + 89, + 104, + 28, + 71, + 221, + 17, + 94, + 15, + 173, + 180, + 230, + 201, + 124, + 213, + 245, + 201, + 4, + 254, + 252, + 238, + 198, + 41, + 159, + 167, + 45, + 229, + 150, + 54, + 136, + 123, + 35, + 201, + 227, + 34, + 158, + 174, + 94, + 101, + 15, + 64, + 75, + 12, + 141, + 44, + 97, + 35, + 98, + 84, + 40, + 199, + 51, + 138, + 87, + 123, + 158, + 0, + 196, + 149, + 81, + 173, + 171, + 229, + 173, + 67, + 97, + 102, + 25, + 175, + 86, + 103, + 155, + 106, + 73, + 97, + 79, + 58, + 202, + 248, + 111, + 57, + 69, + 214, + 228, + 67, + 243, + 62, + 238, + 114, + 202, + 61, + 110, + 32, + 33, + 212, + 84, + 213, + 227, + 105, + 11, + 24, + 91, + 11, + 25, + 17, + 57, + 127, + 47, + 43, + 77, + 198, + 128, + 137, + 43, + 181, + 136, + 3, + 180, + 96, + 47, + 61, + 134, + 42, + 64, + 72, + 70, + 111, + 27, + 216, + 225, + 45, + 130, + 207, + 127, + 153, + 140, + 42, + 8, + 116, + 228, + 59, + 88, + 117, + 222, + 162, + 218, + 56, + 249, + 165, + 235, + 162, + 216, + 202, + 132, + 157, + 116, + 117, + 15, + 182, + 21, + 80, + 197, + 70, + 194, + 186, + 36, + 235, + 150, + 40, + 252, + 102, + 223, + 176, + 25, + 218, + 45, + 207, + 234, + 41, + 169, + 68, + 217, + 225, + 232, + 48, + 211, + 60, + 129, + 12, + 37, + 98, + 65, + 149, + 149, + 111, + 173, + 115, + 109, + 33, + 227, + 44, + 35, + 196, + 173, + 4, + 207, + 113, + 34, + 143, + 157, + 245, + 54, + 221, + 11, + 71, + 174, + 150, + 148, + 200, + 141, + 208, + 47, + 13, + 50, + 118, + 92, + 100, + 216, + 77, + 129, + 102, + 165, + 19, + 145, + 86, + 120, + 35, + 65, + 42, + 50, + 57, + 187, + 27, + 31, + 200, + 235, + 143, + 150, + 58, + 26, + 112, + 85, + 9, + 95, + 189, + 11, + 49, + 8, + 113, + 177, + 124, + 235, + 138, + 16, + 39, + 117, + 32, + 178, + 111, + 195, + 66, + 198, + 177, + 138, + 111, + 68, + 75, + 147, + 246, + 72, + 175, + 71, + 71, + 121, + 109, + 97, + 118, + 232, + 42, + 11, + 6, + 198, + 73, + 127, + 213, + 135, + 59, + 167, + 73, + 150, + 203, + 137, + 80, + 110, + 56, + 194, + 244, + 152, + 94, + 87, + 224, + 22, + 115, + 33, + 118, + 145, + 124, + 99, + 218, + 58, + 173, + 77, + 73, + 21, + 222, + 248, + 59, + 53, + 159, + 20, + 38, + 138, + 89, + 184, + 11, + 122, + 65, + 40, + 2, + 71, + 113, + 34, + 12, + 127, + 217, + 15, + 186, + 90, + 72, + 132, + 27, + 70, + 132, + 25, + 72, + 81, + 109, + 158, + 169, + 35, + 205, + 36, + 165, + 117, + 1, + 17, + 217, + 41, + 251, + 246, + 143, + 174, + 246, + 193, + 70, + 34, + 200, + 99, + 76, + 207, + 143, + 243, + 46, + 98, + 127, + 43, + 81, + 43, + 15, + 123, + 206, + 130, + 189, + 236, + 178, + 76, + 152, + 200, + 53, + 4, + 41, + 27, + 149, + 34, + 186, + 162, + 184, + 104, + 73, + 235, + 234, + 213, + 237, + 140, + 251, + 38, + 143, + 231, + 71, + 247, + 52, + 248, + 217, + 153, + 247, + 52, + 105, + 220, + 160, + 227, + 126, + 156, + 33, + 32, + 187, + 169, + 43, + 17, + 141, + 151, + 242, + 234, + 182, + 112, + 219, + 79, + 65, + 188, + 114, + 43, + 104, + 199, + 141, + 185, + 127, + 244, + 104, + 68, + 222, + 79, + 91, + 149, + 210, + 47, + 147, + 23, + 239, + 153, + 87, + 79, + 180, + 131, + 23, + 25, + 190, + 42, + 158, + 28, + 208, + 167, + 250, + 212, + 31, + 30, + 54, + 207, + 142, + 100, + 101, + 46, + 155, + 134, + 170, + 34, + 235, + 51, + 122, + 154, + 11, + 196, + 129, + 71, + 55, + 148, + 176, + 191, + 26, + 162, + 243, + 134, + 215, + 171, + 93, + 161, + 55, + 199, + 217, + 149, + 33, + 237, + 88, + 154, + 220, + 11, + 67, + 177, + 204, + 211, + 141, + 208, + 164, + 242, + 208, + 9, + 19, + 218, + 234, + 72, + 89, + 117, + 52, + 28, + 68, + 106, + 207, + 122, + 78, + 61, + 92, + 211, + 112, + 175, + 210, + 202, + 0, + 56, + 125, + 228, + 202, + 234, + 218, + 241, + 128, + 100, + 44, + 242, + 132, + 229, + 166, + 57, + 168, + 205, + 191, + 143, + 16, + 193, + 33, + 59, + 110, + 95, + 142, + 40, + 163, + 233, + 247, + 192, + 249, + 110, + 9, + 122, + 83, + 113, + 138, + 100, + 7, + 68, + 33, + 117, + 87, + 218, + 8, + 243, + 45, + 48, + 21, + 146, + 172, + 214, + 80, + 63, + 84, + 78, + 233, + 117, + 13, + 45, + 13, + 46, + 143, + 165, + 128, + 120, + 255, + 18, + 41, + 214, + 187, + 15, + 126, + 169, + 64, + 100, + 23, + 250, + 8, + 14, + 244, + 134, + 29, + 216, + 54, + 118, + 104, + 253, + 186, + 64, + 11, + 21, + 9, + 63, + 48, + 16, + 81, + 187, + 181, + 201, + 76, + 99, + 65, + 76, + 164, + 174, + 245, + 211, + 174, + 194, + 54, + 137, + 236, + 54, + 191, + 194, + 18, + 242, + 104, + 143, + 65, + 140, + 121, + 242, + 250, + 138, + 12, + 204, + 161, + 9, + 104, + 71, + 21, + 162, + 169, + 197, + 213, + 105, + 55, + 226, + 250, + 64, + 36, + 225, + 144, + 243, + 134, + 179, + 177, + 235, + 16, + 57, + 203, + 148, + 172, + 167, + 162, + 141, + 48, + 2, + 105, + 65, + 64, + 74, + 59, + 162, + 3, + 248, + 82, + 117, + 13, + 17, + 92, + 69, + 146, + 164, + 37, + 217, + 20, + 161, + 144, + 23, + 38, + 36, + 148, + 96, + 238, + 43, + 155, + 200, + 217, + 159, + 6, + 226, + 243, + 161, + 229, + 225, + 27, + 219, + 222, + 248, + 120, + 18, + 222, + 87, + 69, + 12, + 56, + 210, + 60, + 229, + 124, + 58, + 51, + 218, + 202, + 169, + 85, + 187, + 199, + 208, + 106, + 108, + 206, + 204, + 237, + 21, + 6, + 172, + 104, + 144, + 9, + 206, + 81, + 241, + 50, + 201, + 44, + 162, + 183, + 109, + 42, + 114, + 217, + 154, + 31, + 151, + 143, + 1, + 170, + 183, + 56, + 174, + 20, + 238, + 254, + 40, + 192, + 8, + 57, + 238, + 96, + 33, + 38, + 133, + 23, + 181, + 143, + 15, + 169, + 140, + 45, + 131, + 61, + 250, + 29, + 166, + 102, + 1, + 157, + 96, + 115, + 67, + 40, + 7, + 198, + 199, + 40, + 95, + 225, + 140, + 13, + 106, + 142, + 210, + 181, + 152, + 243, + 189, + 13, + 226, + 229, + 206, + 177, + 8, + 61, + 140, + 209, + 151, + 57, + 18, + 117, + 216, + 121, + 68, + 174, + 2, + 201, + 241, + 62, + 55, + 53, + 253, + 146, + 79, + 18, + 120, + 140, + 112, + 232, + 113, + 74, + 117, + 191, + 36, + 99, + 105, + 58, + 112, + 136, + 163, + 97, + 3, + 93, + 145, + 107, + 251, + 51, + 141, + 70, + 184, + 233, + 211, + 12, + 116, + 171, + 143, + 150, + 180, + 108, + 149, + 104, + 132, + 218, + 215, + 224, + 40, + 14, + 192, + 211, + 84, + 2, + 130, + 85, + 23, + 56, + 187, + 210, + 49, + 101, + 64, + 60, + 133, + 93, + 83, + 175, + 215, + 84, + 82, + 120, + 5, + 7, + 120, + 21, + 167, + 165, + 70, + 196, + 190, + 189, + 250, + 103, + 226, + 249, + 252, + 33, + 245, + 249, + 94, + 88, + 211, + 147, + 211, + 123, + 100, + 196, + 216, + 228, + 150, + 247, + 170, + 15, + 231, + 239, + 254, + 60, + 207, + 141, + 114, + 244, + 65, + 242, + 150, + 243, + 245, + 94, + 34, + 90, + 232, + 202, + 76, + 169, + 66, + 53, + 89, + 66, + 108, + 102, + 46, + 136, + 106, + 200, + 43, + 67, + 74, + 155, + 114, + 230, + 146, + 3, + 228, + 64, + 45, + 159, + 128, + 70, + 96, + 141, + 86, + 102, + 217, + 20, + 233, + 180, + 136, + 122, + 122, + 92, + 20, + 233, + 249, + 220, + 52, + 97, + 126, + 35, + 11, + 207, + 183, + 170, + 127, + 22, + 25, + 115, + 227, + 48, + 25, + 92, + 219, + 168, + 51, + 8, + 32, + 58, + 20, + 53, + 153, + 94, + 194, + 134, + 164, + 252, + 72, + 255, + 241, + 166, + 101, + 38, + 13, + 177, + 158, + 96, + 12, + 150, + 229, + 140, + 14, + 74, + 138, + 70, + 86, + 134, + 193, + 45, + 183, + 35, + 175, + 148, + 74, + 38, + 78, + 87, + 212, + 154, + 159, + 139, + 216, + 223, + 218, + 182, + 210, + 167, + 221, + 77, + 10, + 229, + 223, + 252, + 243, + 30, + 223, + 123, + 225, + 233, + 238, + 61, + 132, + 165, + 160, + 139, + 116, + 117, + 6, + 165, + 206, + 119, + 202, + 168, + 67, + 62, + 110, + 147, + 139, + 161, + 5, + 74, + 236, + 137, + 253, + 170, + 245, + 230, + 240, + 83, + 176, + 130, + 159, + 41, + 178, + 87, + 58, + 38, + 168, + 115, + 77, + 175, + 159, + 172, + 239, + 238, + 25, + 111, + 226, + 234, + 172, + 100, + 176, + 219, + 165, + 69, + 209, + 63, + 42, + 207, + 35, + 20, + 123, + 119, + 49, + 103, + 75, + 166, + 15, + 209, + 32, + 154, + 154, + 42, + 143, + 65, + 188, + 62, + 56, + 113, + 249, + 29, + 126, + 197, + 106, + 53, + 208, + 54, + 58, + 185, + 54, + 45, + 44, + 149, + 232, + 240, + 79, + 18, + 46, + 237, + 25, + 118, + 118, + 175, + 96, + 226, + 203, + 241, + 242, + 96, + 80, + 197, + 242, + 60, + 50, + 128, + 143, + 58, + 170, + 82, + 152, + 200, + 109, + 196, + 141, + 66, + 85, + 28, + 236, + 90, + 223, + 138, + 78, + 182, + 132, + 188, + 117, + 216, + 65, + 232, + 95, + 41, + 98, + 35, + 115, + 27, + 221, + 212, + 188, + 161, + 207, + 96, + 89, + 19, + 137, + 15, + 7, + 29, + 31, + 32, + 114, + 62, + 210, + 186, + 177, + 188, + 250, + 54, + 122, + 92, + 224, + 7, + 104, + 65, + 139, + 105, + 201, + 220, + 162, + 151, + 161, + 169, + 117, + 51, + 29, + 113, + 117, + 195, + 47, + 123, + 67, + 99, + 219, + 81, + 165, + 17, + 152, + 174, + 103, + 29, + 218, + 27, + 40, + 145, + 249, + 6, + 191, + 210, + 16, + 10, + 100, + 242, + 203, + 192, + 125, + 212, + 231, + 244, + 204, + 33, + 7, + 15, + 201, + 134, + 190, + 7, + 219, + 118, + 220, + 232, + 152, + 147, + 145, + 101, + 174, + 191, + 153, + 63, + 209, + 107, + 125, + 169, + 210, + 28, + 6, + 15, + 244, + 83, + 64, + 146, + 28, + 217, + 148, + 47, + 213, + 233, + 119, + 22, + 224, + 228, + 36, + 155, + 81, + 130, + 118, + 158, + 104, + 156, + 177, + 169, + 137, + 76, + 132, + 167, + 163, + 57, + 164, + 204, + 180, + 65, + 18, + 71, + 109, + 103, + 250, + 234, + 118, + 223, + 93, + 101, + 110, + 180, + 55, + 98, + 52, + 237, + 74, + 63, + 82, + 49, + 113, + 212, + 23, + 218, + 77, + 208, + 43, + 111, + 157, + 139, + 62, + 126, + 71, + 33, + 179, + 126, + 145, + 154, + 150, + 54, + 117, + 108, + 78, + 196, + 92, + 135, + 101, + 83, + 101, + 29, + 97, + 136, + 168, + 224, + 95, + 188, + 187, + 205, + 104, + 56, + 98, + 200, + 52, + 43, + 48, + 245, + 233, + 85, + 102, + 117, + 213, + 86, + 188, + 114, + 250, + 160, + 76, + 128, + 66, + 121, + 240, + 234, + 162, + 147, + 42, + 202, + 229, + 216, + 170, + 163, + 11, + 215, + 190, + 138, + 113, + 99, + 195, + 110, + 139, + 182, + 236, + 77, + 215, + 225, + 97, + 110, + 207, + 99, + 17, + 163, + 116, + 182, + 96, + 79, + 143, + 40, + 52, + 149, + 96, + 14, + 130, + 133, + 52, + 105, + 168, + 249, + 138, + 62, + 129, + 137, + 68, + 48, + 110, + 88, + 70, + 73, + 201, + 9, + 203, + 79, + 204, + 127, + 84, + 78, + 253, + 70, + 140, + 106, + 124, + 191, + 103, + 178, + 19, + 7, + 250, + 186, + 40, + 126, + 184, + 1, + 70, + 245, + 151, + 184, + 146, + 133, + 78, + 249, + 62, + 85, + 255, + 114, + 235, + 99, + 45, + 86, + 88, + 255, + 92, + 92, + 39, + 187, + 227, + 7, + 95, + 75, + 235, + 16, + 136, + 187, + 158, + 41, + 70, + 133, + 148, + 180, + 204, + 200, + 95, + 156, + 131, + 72, + 71, + 169, + 75, + 31, + 210, + 91, + 117, + 179, + 228, + 128, + 62, + 254, + 26, + 61, + 135, + 172, + 40, + 240, + 216, + 83, + 122, + 250, + 199, + 146, + 189, + 209, + 42, + 138, + 98, + 242, + 155, + 97, + 222, + 246, + 100, + 221, + 70, + 143, + 222, + 127, + 187, + 209, + 146, + 240, + 133, + 183, + 249, + 130, + 220, + 166, + 70, + 43, + 11, + 122, + 170, + 119, + 232, + 27, + 8, + 74, + 164, + 49, + 56, + 23, + 36, + 166, + 223, + 0, + 105, + 159, + 176, + 138, + 190, + 51, + 163, + 223, + 59, + 222, + 217, + 109, + 49, + 45, + 215, + 160, + 11, + 103, + 249, + 48, + 25, + 212, + 164, + 231, + 16, + 117, + 130, + 83, + 77, + 27, + 121, + 192, + 149, + 144, + 83, + 236, + 57, + 224, + 139, + 97, + 170, + 85, + 84, + 55, + 228, + 224, + 66, + 123, + 108, + 198, + 188, + 213, + 221, + 66, + 186, + 216, + 238, + 224, + 53, + 40, + 104, + 214, + 220, + 42, + 44, + 255, + 93, + 36, + 71, + 162, + 70, + 123, + 121, + 171, + 109, + 116, + 60, + 113, + 27, + 213, + 54, + 182, + 58, + 153, + 226, + 187, + 11, + 161, + 106, + 81, + 38, + 7, + 35, + 238, + 75, + 250, + 54, + 70, + 215, + 83, + 115, + 145, + 208, + 125, + 110, + 36, + 86, + 94, + 143, + 182, + 39, + 77, + 36, + 212, + 254, + 97, + 121, + 240, + 247, + 139, + 200, + 107, + 232, + 90, + 12, + 253, + 215, + 159, + 104, + 233, + 208, + 91, + 7, + 239, + 203, + 188, + 118, + 254, + 150, + 141, + 155, + 132, + 229, + 95, + 135, + 155, + 218, + 198, + 203, + 87, + 113, + 8, + 58, + 147, + 30, + 61, + 87, + 126, + 229, + 179, + 44, + 186, + 241, + 72, + 78, + 172, + 92, + 127, + 58, + 134, + 139, + 191, + 0, + 16, + 109, + 96, + 71, + 27, + 159, + 168, + 182, + 83, + 78, + 41, + 77, + 18, + 67, + 93, + 236, + 184, + 2, + 93, + 50, + 4, + 104, + 254, + 225, + 63, + 27, + 45, + 53, + 106, + 253, + 208, + 71, + 196, + 71, + 243, + 145, + 142, + 152, + 143, + 69, + 160, + 143, + 69, + 19, + 225, + 64, + 101, + 213, + 33, + 104, + 254, + 64, + 105, + 235, + 79, + 50, + 134, + 127, + 110, + 174, + 136, + 92, + 22, + 197, + 194, + 36, + 100, + 12, + 125, + 215, + 42, + 185, + 157, + 186, + 36, + 212, + 45, + 23, + 1, + 17, + 247, + 46, + 72, + 44, + 199, + 255, + 15, + 95, + 19, + 49, + 135, + 105, + 15, + 119, + 31, + 126, + 243, + 207, + 109, + 96, + 74, + 98, + 124, + 74, + 232, + 176, + 173, + 185, + 157, + 152, + 67, + 89, + 32, + 55, + 128, + 212, + 223, + 246, + 70, + 149, + 41, + 147, + 233, + 19, + 126, + 173, + 8, + 250, + 155, + 90, + 204, + 132, + 6, + 118, + 31, + 57, + 202, + 14, + 200, + 210, + 93, + 176, + 24, + 242, + 243, + 124, + 97, + 95, + 166, + 255, + 129, + 150, + 153, + 84, + 181, + 210, + 126, + 249, + 189, + 255, + 105, + 246, + 255, + 199, + 182, + 58, + 242, + 239, + 10, + 119, + 61, + 246, + 106, + 106, + 93, + 0, + 130, + 128, + 108, + 85, + 84, + 168, + 246, + 182, + 43, + 195, + 212, + 130, + 92, + 77, + 241, + 87, + 55, + 228, + 39, + 106, + 136, + 164, + 84, + 102, + 120, + 59, + 163, + 217, + 1, + 131, + 65, + 38, + 208, + 72, + 66, + 218, + 98, + 178, + 90, + 109, + 115, + 45, + 187, + 253, + 36, + 22, + 162, + 93, + 133, + 38, + 92, + 66, + 212, + 60, + 226, + 161, + 53, + 89, + 218, + 248, + 122, + 212, + 94, + 61, + 5, + 97, + 36, + 5, + 29, + 66, + 78, + 73, + 244, + 17, + 18, + 87, + 193, + 104, + 106, + 111, + 173, + 61, + 213, + 223, + 20, + 223, + 104, + 160, + 201, + 97, + 12, + 135, + 232, + 133, + 112, + 115, + 108, + 109, + 253, + 60, + 151, + 240, + 68, + 255, + 0, + 176, + 157, + 169, + 10, + 254, + 230, + 85, + 69, + 150, + 202, + 36, + 46, + 134, + 141, + 247, + 179, + 188, + 128, + 226, + 176, + 181, + 14, + 79, + 132, + 81, + 1, + 101, + 172, + 48, + 76, + 145, + 118, + 129, + 255, + 25, + 193, + 225, + 49, + 244, + 23, + 142, + 90, + 58, + 251, + 50, + 202, + 249, + 164, + 210, + 121, + 106, + 229, + 51, + 94, + 142, + 83, + 50, + 162, + 30, + 6, + 111, + 216, + 75, + 14, + 44, + 76, + 193, + 222, + 253, + 76, + 52, + 118, + 44, + 236, + 94, + 140, + 46, + 167, + 140, + 23, + 208, + 135, + 8, + 12, + 218, + 80, + 17, + 13, + 129, + 251, + 152, + 40, + 76, + 212, + 38, + 59, + 87, + 248, + 129, + 174, + 37, + 198, + 246, + 86, + 165, + 194, + 74, + 233, + 44, + 120, + 62, + 115, + 16, + 249, + 40, + 21, + 104, + 101, + 224, + 1, + 169, + 136, + 155, + 19, + 187, + 135, + 116, + 214, + 57, + 166, + 85, + 202, + 61, + 83, + 62, + 221, + 44, + 11, + 101, + 198, + 135, + 142, + 77, + 54, + 194, + 38, + 46, + 175, + 249, + 40, + 23, + 209, + 27, + 28, + 210, + 231, + 246, + 253, + 202, + 118, + 92, + 165, + 118, + 191, + 204, + 250, + 52, + 23, + 42, + 136, + 172, + 221, + 128, + 95, + 128, + 153, + 2, + 221, + 67, + 31, + 14, + 73, + 8, + 106, + 171, + 184, + 209, + 175, + 92, + 105, + 140, + 179, + 6, + 74, + 92, + 2, + 201, + 135, + 250, + 196, + 71, + 103, + 41, + 56, + 241, + 139, + 144, + 194, + 227, + 163, + 67, + 26, + 5, + 48, + 182, + 159, + 242, + 168, + 118, + 180, + 35, + 143, + 215, + 1, + 63, + 68, + 93, + 99, + 151, + 131, + 108, + 194, + 208, + 190, + 212, + 38, + 185, + 246, + 28, + 156, + 94, + 5, + 51, + 41, + 47, + 50, + 42, + 168, + 125, + 236, + 81, + 138, + 132, + 8, + 231, + 47, + 84, + 5, + 129, + 167, + 229, + 135, + 32, + 238, + 224, + 3, + 110, + 90, + 149, + 241, + 241, + 241, + 180, + 106, + 226, + 56, + 58, + 37, + 164, + 10, + 101, + 41, + 191, + 158, + 103, + 124, + 68, + 95, + 172, + 214, + 205, + 203, + 254, + 127, + 214, + 249, + 254, + 90, + 156, + 27, + 96, + 71, + 221, + 94, + 243, + 195, + 2, + 154, + 108, + 15, + 157, + 134, + 197, + 91, + 18, + 72, + 87, + 13, + 153, + 27, + 226, + 132, + 80, + 173, + 169, + 4, + 204, + 127, + 91, + 228, + 221, + 58, + 102, + 162, + 233, + 241, + 92, + 118, + 54, + 17, + 60, + 100, + 120, + 141, + 175, + 189, + 76, + 110, + 157, + 206, + 234, + 151, + 230, + 232, + 29, + 182, + 79, + 136, + 81, + 91, + 149, + 182, + 248, + 223, + 166, + 31, + 56, + 0, + 14, + 66, + 198, + 184, + 155, + 38, + 127, + 227, + 115, + 114, + 35, + 61, + 152, + 244, + 146, + 170, + 187, + 148, + 73, + 146, + 46, + 76, + 115, + 82, + 80, + 26, + 255, + 231, + 81, + 177, + 49, + 124, + 36, + 50, + 80, + 49, + 243, + 46, + 28, + 10, + 40, + 117, + 11, + 73, + 247, + 191, + 130, + 239, + 1, + 19, + 73, + 8, + 8, + 58, + 165, + 214, + 191, + 17, + 135, + 227, + 180, + 101, + 223, + 81, + 72, + 55, + 244, + 142, + 188, + 81, + 247, + 165, + 60, + 21, + 63, + 43, + 61, + 106, + 173, + 191, + 160, + 250, + 67, + 8, + 37, + 249, + 246, + 169, + 202, + 74, + 30, + 18, + 148, + 7, + 56, + 204, + 79, + 207, + 95, + 122, + 198, + 100, + 7, + 175, + 173, + 43, + 162, + 123, + 84, + 162, + 219, + 1, + 250, + 53, + 127, + 168, + 90, + 36, + 45, + 97, + 35, + 198, + 163, + 197, + 58, + 91, + 245, + 88, + 247, + 141, + 74, + 29, + 153, + 4, + 81, + 66, + 159, + 102, + 197, + 104, + 83, + 234, + 212, + 30, + 67, + 34, + 193, + 231, + 225, + 236, + 97, + 209, + 157, + 71, + 42, + 159, + 120, + 150, + 163, + 155, + 219, + 2, + 192, + 225, + 232, + 0, + 162, + 182, + 208, + 157, + 43, + 48, + 90, + 1, + 51, + 199, + 204, + 115, + 199, + 178, + 201, + 191, + 102, + 46, + 194, + 10, + 44, + 131, + 41, + 86, + 35, + 192, + 226, + 248, + 43, + 46, + 69, + 18, + 130, + 106, + 109, + 38, + 51, + 185, + 30, + 233, + 26, + 13, + 224, + 63, + 89, + 220, + 184, + 240, + 214, + 161, + 89, + 28, + 131, + 206, + 183, + 66, + 37, + 254, + 113, + 76, + 206, + 100, + 153, + 33, + 205, + 47, + 221, + 60, + 92, + 124, + 233, + 103, + 219, + 141, + 18, + 97, + 178, + 6, + 207, + 232, + 153, + 229, + 67, + 112, + 122, + 120, + 222, + 79, + 21, + 227, + 127, + 62, + 64, + 236, + 58, + 21, + 178, + 14, + 135, + 166, + 182, + 180, + 41, + 90, + 118, + 1, + 44, + 97, + 116, + 196, + 3, + 201, + 90, + 111, + 111, + 155, + 111, + 205, + 149, + 7, + 45, + 240, + 49, + 0, + 73, + 174, + 178, + 84, + 195, + 188, + 58, + 115, + 25, + 218, + 244, + 140, + 220, + 107, + 98, + 110, + 17, + 195, + 91, + 24, + 109, + 135, + 192, + 17, + 20, + 114, + 157, + 98, + 231, + 199, + 46, + 144, + 24, + 140, + 224, + 106, + 56, + 66, + 100, + 82, + 43, + 163, + 36, + 201, + 126, + 12, + 246, + 166, + 206, + 89, + 81, + 60, + 58, + 94, + 128, + 212, + 125, + 76, + 54, + 233, + 226, + 3, + 27, + 66, + 210, + 84, + 39, + 57, + 172, + 210, + 235, + 160, + 73, + 213, + 136, + 12, + 206, + 40, + 224, + 124, + 33, + 130, + 211, + 17, + 236, + 141, + 91, + 183, + 71, + 18, + 235, + 166, + 79, + 93, + 35, + 16, + 31, + 114, + 106, + 8, + 99, + 52, + 146, + 46, + 101, + 246, + 51, + 196, + 235, + 52, + 188, + 252, + 100, + 120, + 207, + 217, + 10, + 182, + 178, + 64, + 113, + 221, + 97, + 14, + 106, + 116, + 206, + 173, + 157, + 70, + 18, + 14, + 169, + 254, + 189, + 235, + 39, + 241, + 69, + 161, + 1, + 45, + 171, + 234, + 37, + 187, + 192, + 231, + 181, + 154, + 78, + 116, + 44, + 253, + 245, + 178, + 161, + 47, + 33, + 24, + 55, + 245, + 195, + 62, + 143, + 59, + 155, + 19, + 26, + 80, + 216, + 27, + 76, + 41, + 193, + 57, + 96, + 66, + 197, + 249, + 245, + 221, + 82, + 180, + 248, + 56, + 80, + 162, + 153, + 172, + 171, + 28, + 93, + 85, + 14, + 98, + 126, + 255, + 98, + 173, + 101, + 235, + 69, + 43, + 5, + 112, + 47, + 93, + 34, + 148, + 47, + 224, + 163, + 82, + 111, + 63, + 217, + 189, + 244, + 5, + 25, + 203, + 75, + 169, + 22, + 165, + 25, + 85, + 9, + 169, + 23, + 85, + 200, + 111, + 12, + 67, + 135, + 250, + 13, + 140, + 118, + 209, + 7, + 35, + 137, + 93, + 250, + 64, + 22, + 247, + 143, + 171, + 220, + 133, + 188, + 183, + 2, + 48, + 107, + 42, + 184, + 237, + 82, + 80, + 140, + 59, + 79, + 227, + 156, + 171, + 8, + 107, + 83, + 96, + 237, + 149, + 56, + 242, + 203, + 59, + 178, + 187, + 195, + 30, + 50, + 10, + 132, + 94, + 1, + 53, + 98, + 30, + 116, + 155, + 6, + 198, + 56, + 79, + 91, + 226, + 13, + 14, + 117, + 61, + 100, + 202, + 246, + 152, + 139, + 247, + 32, + 173, + 111, + 83, + 223, + 124, + 131, + 66, + 70, + 53, + 25, + 192, + 121, + 78, + 193, + 19, + 225, + 54, + 81, + 25, + 122, + 62, + 165, + 234, + 185, + 52, + 89, + 213, + 109, + 121, + 44, + 179, + 90, + 167, + 181, + 68, + 152, + 32, + 85, + 121, + 72, + 6, + 187, + 164, + 227, + 113, + 203, + 34, + 11, + 124, + 69, + 155, + 187, + 218, + 194, + 94, + 130, + 189, + 118, + 30, + 67, + 255, + 219, + 122, + 55, + 66, + 52, + 150, + 26, + 56, + 36, + 221, + 27, + 3, + 168, + 101, + 64, + 75, + 121, + 225, + 45, + 169, + 33, + 104, + 173, + 110, + 190, + 199, + 12, + 137, + 116, + 234, + 153, + 146, + 217, + 160, + 150, + 204, + 96, + 121, + 157, + 103, + 29, + 186, + 249, + 206, + 190, + 74, + 110, + 53, + 175, + 140, + 250, + 75, + 240, + 111, + 84, + 84, + 183, + 80, + 13, + 165, + 22, + 187, + 124, + 208, + 76, + 137, + 66, + 110, + 3, + 1, + 85, + 63, + 37, + 24, + 157, + 179, + 110, + 69, + 111, + 21, + 232, + 150, + 173, + 119, + 105, + 53, + 202, + 111, + 72, + 77, + 63, + 147, + 161, + 190, + 96, + 184, + 210, + 127, + 103, + 248, + 156, + 154, + 176, + 134, + 211, + 220, + 121, + 149, + 253, + 194, + 147, + 6, + 145, + 213, + 111, + 52, + 249, + 18, + 142, + 232, + 61, + 183, + 30, + 203, + 125, + 205, + 56, + 183, + 73, + 242, + 227, + 125, + 43, + 184, + 245, + 211, + 28, + 137, + 204, + 65, + 208, + 73, + 223, + 72, + 83, + 88, + 121, + 74, + 113, + 20, + 19, + 53, + 234, + 194, + 20, + 151, + 165, + 171, + 162, + 166, + 124, + 92, + 47, + 37, + 95, + 179, + 2, + 48, + 201, + 12, + 162, + 6, + 199, + 218, + 48, + 57, + 77, + 191, + 28, + 146, + 83, + 254, + 248, + 123, + 237, + 43, + 153, + 148, + 104, + 19, + 228, + 152, + 113, + 175, + 193, + 152, + 129, + 80, + 186, + 161, + 100, + 225, + 103, + 249, + 188, + 202, + 228, + 1, + 138, + 107, + 120, + 217, + 66, + 142, + 148, + 49, + 73, + 150, + 216, + 246, + 51, + 72, + 86, + 180, + 82, + 42, + 54, + 83, + 97, + 31, + 154, + 177, + 120, + 160, + 40, + 237, + 96, + 14, + 183, + 44, + 187, + 226, + 13, + 86, + 29, + 121, + 235, + 33, + 200, + 234, + 65, + 154, + 105, + 220, + 18, + 204, + 2, + 38, + 173, + 195, + 157, + 142, + 97, + 205, + 148, + 60, + 231, + 165, + 99, + 5, + 47, + 58, + 191, + 26, + 42, + 47, + 63, + 89, + 167, + 145, + 11, + 185, + 12, + 91, + 78, + 143, + 10, + 80, + 184, + 32, + 4, + 70, + 86, + 199, + 147, + 206, + 158, + 64, + 48, + 81, + 86, + 94, + 254, + 86, + 192, + 126, + 189, + 58, + 199, + 221, + 189, + 10, + 243, + 180, + 4, + 228, + 117, + 18, + 236, + 53, + 128, + 82, + 5, + 80, + 13, + 14, + 97, + 200, + 26, + 62, + 26, + 74, + 145, + 87, + 7, + 37, + 106, + 241, + 79, + 247, + 36, + 6, + 119, + 133, + 52, + 83, + 26, + 242, + 97, + 198, + 113, + 228, + 93, + 166, + 4, + 105, + 166, + 9, + 76, + 119, + 217, + 193, + 122, + 90, + 191, + 164, + 238, + 15, + 105, + 16, + 244, + 244, + 235, + 70, + 7, + 83, + 111, + 233, + 71, + 48, + 175, + 68, + 164, + 54, + 125, + 225, + 203, + 83, + 170, + 78, + 29, + 3, + 10, + 3, + 132, + 1, + 251, + 251, + 176, + 20, + 232, + 242, + 178, + 192, + 238, + 33, + 78, + 76, + 203, + 58, + 209, + 248, + 214, + 212, + 215, + 136, + 251, + 219, + 126, + 144, + 204, + 121, + 57, + 203, + 150, + 170, + 116, + 3, + 69, + 188, + 27, + 94, + 106, + 87, + 8, + 45, + 190, + 198, + 244, + 52, + 243, + 138, + 239, + 145, + 203, + 213, + 113, + 142, + 207, + 141, + 125, + 185, + 220, + 73, + 51, + 162, + 181, + 30, + 208, + 179, + 178, + 108, + 232, + 80, + 117, + 156, + 1, + 87, + 91, + 87, + 126, + 115, + 135, + 203, + 81, + 137, + 23, + 106, + 131, + 245, + 160, + 159, + 126, + 240, + 181, + 157, + 154, + 255, + 236, + 89, + 199, + 128, + 132, + 214, + 27, + 60, + 101, + 121, + 32, + 75, + 167, + 80, + 79, + 199, + 84, + 62, + 117, + 222, + 44, + 214, + 20, + 37, + 31, + 169, + 157, + 242, + 203, + 189, + 157, + 255, + 185, + 65, + 80, + 8, + 74, + 80, + 229, + 26, + 228, + 213, + 200, + 56, + 155, + 32, + 5, + 1, + 27, + 226, + 219, + 147, + 94, + 226, + 196, + 31, + 14, + 142, + 168, + 246, + 2, + 181, + 78, + 245, + 100, + 58, + 95, + 120, + 26, + 71, + 130, + 91, + 46, + 158, + 112, + 112, + 32, + 215, + 185, + 241, + 243, + 212, + 68, + 208, + 104, + 210, + 90, + 139, + 253, + 109, + 204, + 15, + 224, + 203, + 45, + 202, + 215, + 34, + 43, + 96, + 58, + 61, + 160, + 34, + 54, + 244, + 119, + 110, + 95, + 59, + 169, + 128, + 239, + 14, + 249, + 86, + 118, + 140, + 237, + 6, + 21, + 27, + 69, + 162, + 99, + 176, + 108, + 50, + 125, + 136, + 95, + 72, + 94, + 53, + 242, + 89, + 247, + 94, + 222, + 157, + 175, + 133, + 194, + 24, + 17, + 14, + 101, + 69, + 251, + 221, + 73, + 118, + 242, + 10, + 152, + 3, + 38, + 58, + 43, + 254, + 186, + 48, + 67, + 93, + 63, + 2, + 154, + 38, + 68, + 0, + 117, + 211, + 166, + 6, + 49, + 37, + 103, + 100, + 48, + 221, + 252, + 112, + 142, + 147, + 158, + 119, + 250, + 169, + 138, + 31, + 206, + 43, + 116, + 100, + 30, + 142, + 125, + 4, + 252, + 49, + 189, + 100, + 241, + 240, + 60, + 231, + 139, + 29, + 238, + 158, + 22, + 79, + 174, + 254, + 162, + 29, + 59, + 254, + 150, + 3, + 125, + 16, + 114, + 129, + 116, + 6, + 2, + 123, + 177, + 249, + 59, + 62, + 124, + 128, + 88, + 96, + 77, + 189, + 226, + 160, + 132, + 215, + 32, + 247, + 131, + 44, + 32, + 179, + 38, + 131, + 101, + 104, + 30, + 199, + 107, + 198, + 186, + 86, + 181, + 108, + 142, + 192, + 179, + 66, + 195, + 48, + 89, + 112, + 157, + 142, + 50, + 56, + 184, + 11, + 11, + 241, + 177, + 104, + 213, + 19, + 255, + 40, + 165, + 41, + 4, + 37, + 113, + 214, + 172, + 132, + 64, + 184, + 177, + 102, + 23, + 27, + 88, + 110, + 119, + 196, + 131, + 71, + 213, + 53, + 184, + 123, + 124, + 188, + 17, + 135, + 14, + 255, + 166, + 178, + 115, + 167, + 186, + 175, + 12, + 38, + 56, + 197, + 241, + 252, + 187, + 227, + 253, + 14, + 67, + 91, + 171, + 34, + 202, + 114, + 131, + 65, + 165, + 2, + 127, + 207, + 72, + 107, + 174, + 53, + 130, + 208, + 194, + 248, + 253, + 73, + 114, + 172, + 118, + 173, + 30, + 119, + 132, + 55, + 228, + 13, + 48, + 85, + 38, + 44, + 210, + 52, + 105, + 14, + 235, + 165, + 200, + 60, + 101, + 186, + 231, + 239, + 253, + 111, + 148, + 189, + 44, + 1, + 116, + 130, + 194, + 4, + 139, + 7, + 232, + 196, + 145, + 45, + 2, + 57, + 177, + 204, + 1, + 2, + 71, + 62, + 144, + 147, + 89, + 118, + 11, + 178, + 98, + 180, + 173, + 59, + 21, + 93, + 54, + 186, + 152, + 43, + 155, + 218, + 33, + 47, + 9, + 222, + 100, + 55, + 114, + 237, + 14, + 216, + 248, + 57, + 214, + 177, + 229, + 105, + 157, + 142, + 89, + 98, + 155, + 66, + 57, + 104, + 114, + 62, + 199, + 27, + 30, + 176, + 219, + 135, + 107, + 246, + 199, + 70, + 225, + 47, + 84, + 236, + 238, + 156, + 159, + 216, + 249, + 13, + 97, + 168, + 109, + 213, + 52, + 198, + 128, + 38, + 184, + 209, + 119, + 96, + 218, + 70, + 206, + 48, + 63, + 36, + 176, + 63, + 220, + 191, + 20, + 81, + 134, + 204, + 168, + 255, + 195, + 137, + 242, + 50, + 132, + 169, + 106, + 43, + 30, + 178, + 68, + 186, + 81, + 23, + 190, + 189, + 235, + 86, + 75, + 114, + 152, + 224, + 207, + 219, + 66, + 6, + 59, + 64, + 16, + 254, + 174, + 226, + 171, + 92, + 150, + 4, + 51, + 126, + 66, + 150, + 68, + 183, + 12, + 51, + 134, + 158, + 190, + 143, + 199, + 22, + 172, + 185, + 78, + 183, + 248, + 161, + 153, + 140, + 83, + 105, + 108, + 116, + 7, + 168, + 114, + 177, + 217, + 153, + 138, + 133, + 26, + 180, + 118, + 130, + 165, + 92, + 77, + 195, + 156, + 222, + 167, + 203, + 156, + 125, + 59, + 19, + 74, + 184, + 87, + 169, + 203, + 104, + 66, + 161, + 229, + 166, + 21, + 164, + 72, + 170, + 23, + 40, + 9, + 110, + 255, + 55, + 77, + 137, + 214, + 143, + 139, + 158, + 193, + 229, + 221, + 224, + 40, + 195, + 252, + 12, + 70, + 100, + 81, + 53, + 9, + 0, + 0, + 226, + 92, + 111, + 124, + 191, + 220, + 46, + 49, + 194, + 197, + 240, + 248, + 50, + 3, + 225, + 49, + 195, + 71, + 158, + 64, + 237, + 232, + 136, + 0, + 63, + 230, + 24, + 212, + 22, + 51, + 230, + 7, + 203, + 127, + 130, + 81, + 2, + 51, + 193, + 50, + 122, + 71, + 215, + 221, + 49, + 77, + 66, + 146, + 253, + 72, + 131, + 2, + 1, + 178, + 113, + 155, + 68, + 129, + 208, + 215, + 35, + 239, + 155, + 33, + 144, + 31, + 166, + 56, + 146, + 69, + 251, + 37, + 252, + 210, + 49, + 23, + 249, + 219, + 120, + 98, + 189, + 249, + 127, + 234, + 142, + 83, + 32, + 45, + 204, + 180, + 184, + 113, + 21, + 172, + 44, + 14, + 85, + 230, + 216, + 43, + 228, + 60, + 201, + 62, + 117, + 75, + 132, + 145, + 236, + 104, + 241, + 255, + 186, + 45, + 193, + 124, + 102, + 218, + 2, + 224, + 154, + 192, + 46, + 167, + 25, + 217, + 101, + 209, + 184, + 4, + 216, + 148, + 218, + 59, + 254, + 103, + 138, + 132, + 68, + 245, + 20, + 40, + 204, + 136, + 148, + 119, + 189, + 50, + 27, + 194, + 255, + 231, + 96, + 122, + 85, + 78, + 64, + 207, + 87, + 189, + 65, + 63, + 192, + 55, + 16, + 183, + 191, + 72, + 226, + 72, + 247, + 28, + 214, + 60, + 68, + 125, + 105, + 226, + 134, + 205, + 233, + 37, + 105, + 237, + 65, + 49, + 107, + 164, + 104, + 177, + 189, + 194, + 35, + 133, + 5, + 131, + 161, + 166, + 177, + 247, + 95, + 235, + 212, + 202, + 95, + 221, + 134, + 241, + 236, + 36, + 119, + 40, + 59, + 64, + 32, + 244, + 199, + 238, + 144, + 150, + 10, + 185, + 109, + 208, + 237, + 187, + 69, + 8, + 34, + 131, + 227, + 115, + 135, + 37, + 158, + 38, + 246, + 150, + 151, + 172, + 237, + 195, + 151, + 218, + 233, + 253, + 106, + 149, + 69, + 204, + 252, + 228, + 66, + 42, + 203, + 48, + 138, + 216, + 107, + 160, + 220, + 103, + 208, + 145, + 23, + 230, + 225, + 227, + 234, + 84, + 240, + 40, + 60, + 175, + 111, + 102, + 103, + 199, + 236, + 44, + 44, + 119, + 136, + 149, + 17, + 192, + 222, + 1, + 244, + 113, + 99, + 58, + 181, + 179, + 207, + 7, + 30, + 22, + 69, + 252, + 141, + 58, + 160, + 82, + 232, + 250, + 42, + 230, + 204, + 142, + 103, + 51, + 209, + 130, + 115, + 7, + 83, + 173, + 253, + 60, + 193, + 185, + 199, + 217, + 60, + 120, + 97, + 239, + 116, + 134, + 206, + 201, + 57, + 247, + 225, + 29, + 117, + 67, + 34, + 29, + 170, + 244, + 238, + 236, + 129, + 197, + 63, + 68, + 21, + 127, + 78, + 232, + 80, + 176, + 11, + 104, + 18, + 255, + 28, + 26, + 1, + 221, + 250, + 167, + 37, + 12, + 150, + 244, + 109, + 112, + 175, + 48, + 232, + 190, + 42, + 110, + 178, + 165, + 130, + 242, + 18, + 186, + 171, + 13, + 51, + 179, + 202, + 247, + 217, + 216, + 222, + 140, + 95, + 239, + 66, + 169, + 35, + 198, + 10, + 241, + 242, + 218, + 229, + 167, + 184, + 135, + 183, + 20, + 156, + 91, + 236, + 196, + 41, + 44, + 123, + 238, + 167, + 56, + 89, + 159, + 114, + 187, + 12, + 97, + 12, + 201, + 216, + 146, + 27, + 137, + 219, + 167, + 216, + 7, + 146, + 166, + 251, + 101, + 17, + 32, + 0, + 19, + 118, + 243, + 71, + 82, + 118, + 128, + 10, + 202, + 149, + 134, + 39, + 110, + 255, + 139, + 7, + 36, + 128, + 26, + 61, + 109, + 68, + 80, + 160, + 162, + 62, + 213, + 130, + 111, + 175, + 133, + 65, + 116, + 9, + 13, + 21, + 128, + 117, + 160, + 96, + 132, + 81, + 124, + 101, + 242, + 4, + 254, + 124, + 185, + 122, + 245, + 21, + 62, + 135, + 201, + 34, + 16, + 96, + 186, + 104, + 155, + 78, + 36, + 40, + 233, + 138, + 42, + 60, + 90, + 57, + 12, + 196, + 84, + 220, + 137, + 252, + 133, + 145, + 112, + 175, + 51, + 148, + 28, + 80, + 53, + 200, + 21, + 23, + 1, + 186, + 177, + 117, + 19, + 181, + 190, + 193, + 149, + 193, + 1, + 39, + 129, + 115, + 255, + 36, + 52, + 91, + 192, + 255, + 204, + 33, + 57, + 177, + 155, + 131, + 173, + 135, + 247, + 9, + 140, + 151, + 38, + 106, + 51, + 218, + 14, + 134, + 132, + 184, + 12, + 151, + 162, + 49, + 195, + 167, + 45, + 103, + 208, + 245, + 144, + 102, + 79, + 157, + 124, + 119, + 68, + 178, + 181, + 46, + 206, + 19, + 197, + 3, + 113, + 141, + 203, + 143, + 200, + 15, + 104, + 82, + 157, + 114, + 32, + 86, + 134, + 126, + 38, + 145, + 29, + 239, + 231, + 79, + 162, + 163, + 182, + 32, + 15, + 107, + 130, + 77, + 102, + 147, + 155, + 86, + 136, + 56, + 224, + 104, + 169, + 196, + 99, + 72, + 9, + 144, + 243, + 36, + 105, + 18, + 250, + 238, + 145, + 75, + 213, + 98, + 233, + 134, + 49, + 90, + 227, + 213, + 5, + 225, + 94, + 77, + 241, + 220, + 232, + 73, + 94, + 222, + 229, + 39, + 63, + 60, + 187, + 87, + 215, + 115, + 94, + 144, + 32, + 108, + 164, + 233, + 222, + 189, + 170, + 107, + 0, + 35, + 225, + 198, + 239, + 181, + 195, + 39, + 91, + 174, + 19, + 227, + 62, + 135, + 243, + 76, + 14, + 106, + 12, + 210, + 221, + 33, + 16, + 142, + 141, + 222, + 190, + 209, + 120, + 255, + 189, + 85, + 146, + 71, + 38, + 232, + 187, + 169, + 45, + 59, + 146, + 41, + 141, + 154, + 231, + 137, + 243, + 28, + 50, + 49, + 185, + 216, + 75, + 31, + 93, + 220, + 136, + 130, + 50, + 96, + 162, + 133, + 30, + 253, + 16, + 35, + 17, + 92, + 210, + 160, + 193, + 242, + 155, + 193, + 73, + 5, + 148, + 24, + 237, + 100, + 118, + 195, + 213, + 159, + 121, + 9, + 217, + 235, + 30, + 233, + 190, + 61, + 119, + 113, + 144, + 121, + 231, + 59, + 28, + 38, + 228, + 75, + 118, + 56, + 70, + 0, + 117, + 63, + 29, + 82, + 237, + 169, + 231, + 34, + 246, + 219, + 8, + 48, + 158, + 26, + 208, + 155, + 177, + 127, + 34, + 10, + 69, + 27, + 116, + 242, + 234, + 243, + 4, + 75, + 155, + 105, + 2, + 212, + 53, + 24, + 74, + 212, + 118, + 19, + 18, + 165, + 247, + 255, + 198, + 42, + 150, + 28, + 169, + 149, + 213, + 109, + 176, + 38, + 177, + 254, + 75, + 49, + 254, + 32, + 100, + 85, + 77, + 242, + 38, + 82, + 147, + 87, + 197, + 22, + 13, + 245, + 13, + 71, + 59, + 120, + 72, + 36, + 147, + 12, + 184, + 251, + 93, + 74, + 121, + 97, + 204, + 43, + 126, + 240, + 254, + 200, + 90, + 247, + 245, + 35, + 215, + 68, + 146, + 36, + 105, + 249, + 36, + 212, + 157, + 197, + 106, + 53, + 110, + 25, + 171, + 194, + 93, + 62, + 185, + 190, + 121, + 10, + 118, + 29, + 5, + 156, + 55, + 4, + 184, + 160, + 97, + 77, + 56, + 137, + 224, + 199, + 141, + 112, + 118, + 211, + 40, + 231, + 15, + 211, + 240, + 76, + 185, + 66, + 102, + 0, + 98, + 87, + 122, + 29, + 129, + 191, + 116, + 48, + 15, + 225, + 202, + 187, + 14, + 104, + 48, + 11, + 49, + 89, + 27, + 76, + 183, + 230, + 86, + 72, + 121, + 222, + 240, + 25, + 183, + 200, + 27, + 220, + 122, + 37, + 32, + 18, + 38, + 104, + 90, + 230, + 185, + 73, + 10, + 160, + 119, + 36, + 41, + 105, + 51, + 143, + 151, + 7, + 65, + 102, + 67, + 23, + 221, + 47, + 183, + 73, + 173, + 200, + 20, + 212, + 100, + 196, + 46, + 235, + 112, + 96, + 50, + 213, + 123, + 4, + 237, + 116, + 157, + 81, + 122, + 206, + 200, + 129, + 251, + 126, + 178, + 116, + 197, + 21, + 89, + 241, + 188, + 101, + 27, + 235, + 41, + 132, + 148, + 132, + 157, + 14, + 198, + 131, + 29, + 109, + 239, + 192, + 12, + 177, + 243, + 61, + 103, + 85, + 172, + 8, + 222, + 130, + 53, + 54, + 197, + 193, + 87, + 73, + 150, + 98, + 251, + 186, + 74, + 16, + 26, + 94, + 139, + 5, + 182, + 19, + 7, + 144, + 227, + 186, + 10, + 23, + 210, + 191, + 65, + 178, + 196, + 47, + 70, + 121, + 90, + 36, + 9, + 208, + 189, + 248, + 99, + 44, + 38, + 6, + 237, + 39, + 163, + 128, + 141, + 79, + 201, + 40, + 91, + 134, + 202, + 40, + 234, + 174, + 164, + 71, + 75, + 212, + 64, + 68, + 149, + 75, + 58, + 27, + 86, + 107, + 105, + 246, + 119, + 63, + 50, + 76, + 49, + 115, + 220, + 156, + 20, + 185, + 160, + 107, + 210, + 205, + 163, + 99, + 185, + 194, + 99, + 185, + 245, + 174, + 101, + 167, + 63, + 243, + 124, + 253, + 14, + 145, + 2, + 145, + 173, + 81, + 164, + 126, + 8, + 231, + 198, + 143, + 78, + 221, + 206, + 232, + 170, + 90, + 190, + 128, + 22, + 97, + 43, + 189, + 206, + 49, + 246, + 45, + 101, + 63, + 58, + 192, + 230, + 143, + 99, + 102, + 43, + 109, + 255, + 146, + 213, + 19, + 21, + 97, + 222, + 136, + 76, + 37, + 194, + 182, + 231, + 173, + 245, + 175, + 58, + 136, + 54, + 41, + 38, + 130, + 137, + 242, + 101, + 143, + 137, + 164, + 36, + 143, + 47, + 112, + 97, + 196, + 148, + 183, + 11, + 151, + 230, + 211, + 94, + 48, + 124, + 24, + 37, + 191, + 78, + 59, + 37, + 25, + 183, + 47, + 143, + 180, + 248, + 246, + 240, + 161, + 221, + 138, + 145, + 254, + 138, + 22, + 191, + 248, + 1, + 125, + 45, + 196, + 252, + 145, + 34, + 2, + 228, + 228, + 8, + 120, + 180, + 89, + 174, + 176, + 51, + 56, + 124, + 209, + 185, + 15, + 89, + 133, + 31, + 51, + 161, + 56, + 11, + 4, + 182, + 233, + 5, + 122, + 54, + 217, + 183, + 150, + 252, + 235, + 169, + 185, + 109, + 33, + 29, + 31, + 33, + 53, + 87, + 1, + 91, + 46, + 48, + 94, + 98, + 109, + 214, + 207, + 35, + 62, + 213, + 98, + 22, + 41, + 118, + 32, + 245, + 10, + 62, + 28, + 248, + 136, + 49, + 113, + 168, + 31, + 98, + 243, + 187, + 229, + 154, + 175, + 156, + 201, + 46, + 131, + 151, + 163, + 193, + 42, + 119, + 52, + 48, + 103, + 12, + 36, + 52, + 82, + 189, + 217, + 29, + 137, + 10, + 183, + 243, + 99, + 101, + 64, + 86, + 99, + 249, + 75, + 4, + 89, + 53, + 253, + 195, + 249, + 128, + 82, + 91, + 37, + 81, + 189, + 186, + 98, + 229, + 229, + 219, + 22, + 9, + 198, + 54, + 169, + 224, + 65, + 24, + 111, + 174, + 105, + 161, + 175, + 158, + 63, + 23, + 28, + 212, + 193, + 119, + 58, + 72, + 210, + 163, + 159, + 63, + 126, + 166, + 23, + 90, + 182, + 214, + 76, + 232, + 29, + 114, + 109, + 35, + 44, + 138, + 210, + 175, + 184, + 23, + 75, + 68, + 3, + 51, + 81, + 79, + 153, + 173, + 121, + 108, + 110, + 7, + 75, + 186, + 206, + 217, + 91, + 110, + 218, + 209, + 42, + 86, + 26, + 141, + 181, + 72, + 43, + 13, + 204, + 212, + 244, + 187, + 16, + 201, + 31, + 226, + 32, + 105, + 11, + 93, + 235, + 90, + 173, + 57, + 254, + 151, + 199, + 31, + 54, + 21, + 249, + 84, + 30, + 7, + 37, + 3, + 101, + 194, + 230, + 84, + 16, + 144, + 68, + 19, + 152, + 70, + 35, + 17, + 81, + 34, + 243, + 115, + 45, + 171, + 17, + 211, + 205, + 206, + 122, + 236, + 33, + 87, + 71, + 231, + 127, + 115, + 177, + 16, + 108, + 19, + 137, + 78, + 47, + 15, + 79, + 171, + 63, + 176, + 113, + 55, + 62, + 141, + 26, + 212, + 40, + 18, + 120, + 55, + 227, + 36, + 208, + 153, + 0, + 243, + 115, + 23, + 212, + 182, + 185, + 243, + 211, + 81, + 247, + 111, + 117, + 63, + 104, + 247, + 72, + 206, + 219, + 193, + 170, + 97, + 124, + 41, + 116, + 34, + 251, + 83, + 3, + 50, + 89, + 72, + 37, + 148, + 24, + 251, + 101, + 111, + 32, + 119, + 194, + 6, + 221, + 81, + 40, + 101, + 149, + 188, + 171, + 33, + 246, + 130, + 160, + 38, + 200, + 143, + 231, + 1, + 225, + 29, + 111, + 65, + 8, + 129, + 60, + 75, + 37, + 104, + 95, + 232, + 239, + 81, + 11, + 128, + 50, + 70, + 242, + 202, + 75, + 224, + 139, + 147, + 33, + 78, + 47, + 128, + 169, + 195, + 117, + 197, + 202, + 175, + 131, + 82, + 209, + 15, + 70, + 26, + 246, + 182, + 206, + 200, + 34, + 141, + 79, + 70, + 50, + 87, + 250, + 111, + 124, + 2, + 3, + 162, + 126, + 25, + 0, + 52, + 143, + 96, + 67, + 213, + 142, + 119, + 143, + 130, + 192, + 88, + 50, + 54, + 127, + 54, + 75, + 199, + 43, + 165, + 172, + 95, + 187, + 166, + 127, + 47, + 239, + 32, + 223, + 92, + 149, + 158, + 254, + 181, + 231, + 239, + 140, + 17, + 210, + 218, + 203, + 153, + 66, + 114, + 34, + 36, + 245, + 78, + 248, + 237, + 126, + 100, + 17, + 90, + 235, + 47, + 72, + 171, + 178, + 204, + 139, + 15, + 97, + 96, + 9, + 42, + 250, + 202, + 240, + 10, + 241, + 168, + 67, + 177, + 99, + 17, + 54, + 151, + 42, + 162, + 187, + 127, + 212, + 129, + 3, + 216, + 29, + 31, + 110, + 63, + 219, + 57, + 18, + 171, + 142, + 75, + 89, + 145, + 68, + 187, + 158, + 251, + 112, + 171, + 26, + 98, + 156, + 107, + 65, + 135, + 117, + 69, + 1, + 91, + 90, + 176, + 92, + 70, + 176, + 207, + 77, + 8, + 124, + 170, + 77, + 159, + 207, + 213, + 158, + 31, + 39, + 28, + 119, + 243, + 181, + 104, + 3, + 211, + 56, + 242, + 71, + 191, + 54, + 191, + 144, + 53, + 46, + 200, + 114, + 42, + 62, + 108, + 90, + 162, + 218, + 20, + 173, + 133, + 202, + 86, + 216, + 127, + 67, + 181, + 236, + 240, + 12, + 41, + 177, + 1, + 146, + 5, + 22, + 220, + 215, + 28, + 65, + 135, + 58, + 174, + 22, + 205, + 117, + 12, + 194, + 237, + 117, + 17, + 107, + 245, + 121, + 26, + 28, + 196, + 241, + 198, + 140, + 176, + 135, + 248, + 73, + 224, + 157, + 171, + 83, + 174, + 67, + 91, + 81, + 228, + 157, + 19, + 244, + 155, + 18, + 119, + 62, + 60, + 99, + 212, + 212, + 131, + 6, + 127, + 143, + 97, + 220, + 59, + 83, + 201, + 49, + 163, + 209, + 168, + 29, + 156, + 86, + 105, + 145, + 81, + 200, + 41, + 31, + 62, + 83, + 78, + 103, + 103, + 18, + 111, + 121, + 47, + 110, + 93, + 224, + 198, + 174, + 193, + 130, + 116, + 238, + 194, + 188, + 4, + 56, + 80, + 1, + 189, + 58, + 84, + 87, + 230, + 160, + 65, + 195, + 88, + 72, + 226, + 172, + 192, + 254, + 244, + 252, + 163, + 162, + 97, + 74, + 81, + 56, + 69, + 54, + 108, + 107, + 30, + 203, + 169, + 187, + 188, + 23, + 238, + 64, + 148, + 223, + 58, + 230, + 31, + 150, + 150, + 162, + 86, + 161, + 206, + 0, + 29, + 202, + 22, + 155, + 162, + 25, + 14, + 225, + 81, + 214, + 47, + 254, + 27, + 33, + 33, + 23, + 141, + 237, + 181, + 109, + 69, + 121, + 114, + 214, + 201, + 229, + 212, + 241, + 62, + 216, + 29, + 177, + 253, + 233, + 49, + 15, + 115, + 76, + 31, + 53, + 106, + 133, + 13, + 178, + 177, + 184, + 151, + 171, + 242, + 37, + 53, + 9, + 175, + 9, + 79, + 46, + 251, + 56, + 95, + 116, + 48, + 77, + 54, + 102, + 57, + 133, + 196, + 142, + 251, + 127, + 18, + 112, + 140, + 145, + 168, + 6, + 5, + 218, + 206, + 176, + 68, + 52, + 94, + 61, + 248, + 80, + 200, + 88, + 219, + 162, + 118, + 210, + 81, + 88, + 35, + 240, + 127, + 166, + 225, + 5, + 106, + 165, + 65, + 25, + 152, + 231, + 125, + 77, + 33, + 181, + 104, + 232, + 5, + 121, + 93, + 109, + 44, + 167, + 49, + 48, + 17, + 167, + 57, + 174, + 157, + 46, + 106, + 162, + 186, + 25, + 181, + 48, + 220, + 241, + 167, + 50, + 162, + 115, + 159, + 152, + 215, + 110, + 189, + 70, + 15, + 216, + 170, + 98, + 83, + 209, + 152, + 184, + 96, + 228, + 209, + 142, + 16, + 0, + 47, + 167, + 147, + 212, + 127, + 235, + 213, + 185, + 212, + 122, + 13, + 75, + 64, + 113, + 21, + 134, + 160, + 165, + 215, + 119, + 212, + 15, + 133, + 171, + 225, + 45, + 178, + 171, + 15, + 106, + 246, + 137, + 12, + 242, + 250, + 46, + 16, + 207, + 36, + 103, + 198, + 175, + 43, + 51, + 131, + 148, + 221, + 240, + 78, + 135, + 93, + 0, + 248, + 54, + 113, + 12, + 62, + 245, + 125, + 87, + 202, + 5, + 231, + 134, + 143, + 170, + 120, + 62, + 230, + 23, + 113, + 190, + 194, + 31, + 22, + 157, + 144, + 215, + 171, + 193, + 222, + 251, + 126, + 207, + 15, + 84, + 222, + 117, + 241, + 252, + 82, + 221, + 116, + 207, + 181, + 233, + 234, + 41, + 25, + 156, + 220, + 109, + 107, + 89, + 142, + 101, + 91, + 149, + 22, + 78, + 20, + 114, + 62, + 71, + 21, + 195, + 24, + 58, + 7, + 220, + 249, + 134, + 81, + 79, + 16, + 3, + 62, + 32, + 96, + 29, + 26, + 126, + 23, + 174, + 199, + 208, + 47, + 219, + 62, + 95, + 134, + 25, + 55, + 38, + 50, + 44, + 222, + 245, + 41, + 13, + 160, + 27, + 3, + 78, + 50, + 128, + 43, + 43, + 135, + 191, + 164, + 214, + 108, + 254, + 50, + 24, + 246, + 101, + 136, + 220, + 138, + 30, + 207, + 106, + 77, + 66, + 101, + 253, + 91, + 79, + 104, + 1, + 180, + 216, + 200, + 12, + 222, + 248, + 40, + 17, + 27, + 142, + 244, + 90, + 34, + 146, + 38, + 167, + 16, + 98, + 90, + 108, + 105, + 86, + 229, + 163, + 89, + 130, + 16, + 83, + 22, + 33, + 65, + 23, + 100, + 243, + 131, + 35, + 65, + 148, + 92, + 197, + 49, + 222, + 115, + 41, + 211, + 149, + 239, + 242, + 224, + 123, + 120, + 206, + 6, + 74, + 88, + 206, + 173, + 58, + 97, + 200, + 31, + 227, + 237, + 85, + 148, + 16, + 165, + 199, + 19, + 233, + 41, + 102, + 20, + 219, + 41, + 231, + 64, + 200, + 138, + 87, + 10, + 72, + 202, + 21, + 231, + 35, + 122, + 30, + 143, + 148, + 27, + 12, + 29, + 229, + 22, + 14, + 59, + 146, + 149, + 244, + 8, + 211, + 205, + 190, + 225, + 6, + 129, + 162, + 81, + 181, + 123, + 151, + 215, + 168, + 26, + 44, + 18, + 73, + 37, + 100, + 109, + 173, + 249, + 120, + 73, + 238, + 68, + 7, + 145, + 121, + 44, + 184, + 8, + 118, + 69, + 185, + 254, + 56, + 57, + 153, + 71, + 23, + 247, + 241, + 100, + 243, + 196, + 25, + 161, + 243, + 230, + 117, + 38, + 55, + 27, + 239, + 43, + 35, + 82, + 77, + 46, + 162, + 164, + 246, + 151, + 55, + 83, + 124, + 0, + 164, + 110, + 111, + 74, + 253, + 221, + 87, + 29, + 176, + 236, + 164, + 146, + 180, + 154, + 105, + 205, + 240, + 166, + 185, + 236, + 33, + 243, + 109, + 235, + 166, + 25, + 182, + 237, + 188, + 142, + 74, + 172, + 198, + 151, + 3, + 149, + 102, + 220, + 238, + 5, + 70, + 29, + 118, + 67, + 15, + 23, + 4, + 34, + 85, + 1, + 148, + 35, + 173, + 79, + 84, + 2, + 68, + 147, + 142, + 108, + 61, + 59, + 207, + 109, + 51, + 128, + 74, + 4, + 215, + 92, + 117, + 17, + 0, + 94, + 117, + 254, + 41, + 93, + 146, + 29, + 85, + 44, + 47, + 173, + 92, + 52, + 33, + 143, + 30, + 56, + 9, + 62, + 81, + 80, + 103, + 123, + 82, + 53, + 221, + 10, + 63, + 167, + 157, + 180, + 54, + 185, + 138, + 98, + 63, + 24, + 46, + 246, + 14, + 35, + 195, + 132, + 171, + 190, + 9, + 109, + 60, + 104, + 192, + 224, + 113, + 96, + 113, + 251, + 10, + 95, + 156, + 54, + 58, + 95, + 30, + 131, + 53, + 216, + 160, + 98, + 30, + 113, + 147, + 27, + 196, + 242, + 146, + 37, + 147, + 126, + 8, + 41, + 102, + 252, + 72, + 14, + 222, + 212, + 202, + 9, + 75, + 175, + 19, + 78, + 245, + 115, + 222, + 90, + 66, + 222, + 104, + 105, + 16, + 63, + 17, + 194, + 228, + 253, + 132, + 62, + 200, + 143, + 74, + 123, + 58, + 207, + 116, + 205, + 186, + 107, + 30, + 203, + 131, + 219, + 183, + 253, + 54, + 60, + 251, + 215, + 116, + 62, + 219, + 171, + 210, + 93, + 235, + 94, + 209, + 67, + 172, + 196, + 70, + 15, + 67, + 160, + 235, + 230, + 125, + 93, + 123, + 211, + 131, + 231, + 87, + 203, + 206, + 34, + 154, + 227, + 94, + 245, + 57, + 121, + 163, + 223, + 118, + 165, + 7, + 252, + 55, + 252, + 25, + 13, + 63, + 150, + 73, + 125, + 44, + 232, + 226, + 168, + 4, + 180, + 168, + 20, + 65, + 178, + 235, + 70, + 189, + 13, + 0, + 209, + 185, + 141, + 203, + 241, + 153, + 54, + 186, + 114, + 92, + 203, + 113, + 24, + 145, + 62, + 80, + 118, + 94, + 41, + 226, + 223, + 91, + 253, + 37, + 129, + 64, + 24, + 175, + 197, + 18, + 99, + 78, + 228, + 251, + 134, + 247, + 213, + 213, + 18, + 161, + 195, + 81, + 32, + 243, + 55, + 22, + 180, + 50, + 120, + 36, + 154, + 113, + 126, + 191, + 199, + 83, + 172, + 66, + 65, + 103, + 160, + 115, + 189, + 109, + 199, + 213, + 111, + 131, + 240, + 189, + 83, + 93, + 251, + 92, + 242, + 17, + 10, + 235, + 157, + 10, + 136, + 22, + 11, + 119, + 122, + 239, + 230, + 84, + 138, + 250, + 184, + 170, + 160, + 122, + 110, + 73, + 44, + 106, + 95, + 215, + 165, + 132, + 177, + 149, + 137, + 21, + 104, + 158, + 6, + 23, + 132, + 14, + 176, + 173, + 18, + 142, + 128, + 253, + 40, + 183, + 130, + 113, + 238, + 45, + 51, + 42, + 157, + 195, + 199, + 189, + 61, + 126, + 98, + 77, + 20, + 26, + 185, + 5, + 111, + 186, + 167, + 250, + 171, + 103, + 241, + 135, + 183, + 60, + 41, + 146, + 71, + 59, + 47, + 240, + 3, + 151, + 181, + 160, + 52, + 51, + 166, + 83, + 196, + 84, + 20, + 50, + 239, + 67, + 225, + 195, + 254, + 95, + 251, + 95, + 168, + 73, + 47, + 42, + 244, + 156, + 252, + 146, + 173, + 76, + 248, + 44, + 15, + 157, + 165, + 56, + 111, + 38, + 204, + 163, + 128, + 240, + 134, + 110, + 99, + 205, + 9, + 205, + 79, + 122, + 55, + 186, + 203, + 115, + 212, + 151, + 156, + 3, + 20, + 26, + 107, + 162, + 81, + 114, + 250, + 141, + 47, + 244, + 51, + 134, + 73, + 111, + 19, + 4, + 93, + 235, + 180, + 0, + 49, + 46, + 62, + 249, + 89, + 9, + 205, + 88, + 16, + 205, + 195, + 149, + 11, + 251, + 164, + 145, + 188, + 230, + 109, + 124, + 155, + 159, + 123, + 114, + 159, + 62, + 247, + 147, + 67, + 159, + 31, + 100, + 100, + 248, + 62, + 49, + 16, + 198, + 90, + 100, + 192, + 30, + 59, + 253, + 182, + 160, + 69, + 46, + 41, + 41, + 101, + 154, + 5, + 130, + 132, + 174, + 158, + 88, + 83, + 235, + 16, + 242, + 74, + 126, + 21, + 201, + 12, + 53, + 16, + 65, + 110, + 32, + 169, + 137, + 82, + 5, + 194, + 224, + 105, + 56, + 124, + 208, + 180, + 96, + 40, + 200, + 94, + 217, + 143, + 63, + 36, + 128, + 97, + 177, + 212, + 13, + 19, + 26, + 111, + 48, + 245, + 0, + 102, + 63, + 118, + 61, + 95, + 149, + 179, + 42, + 70, + 206, + 236, + 66, + 10, + 51, + 181, + 175, + 90, + 174, + 136, + 195, + 102, + 125, + 21, + 70, + 38, + 233, + 163, + 71, + 52, + 38, + 13, + 133, + 176, + 71, + 40, + 225, + 213, + 236, + 207, + 138, + 35, + 210, + 135, + 118, + 244, + 115, + 69, + 110, + 148, + 231, + 49, + 159, + 191, + 57, + 15, + 69, + 88, + 128, + 121, + 239, + 3, + 251, + 203, + 248, + 244, + 28, + 234, + 9, + 229, + 158, + 127, + 43, + 203, + 91, + 189, + 159, + 19, + 170, + 166, + 15, + 125, + 226, + 119, + 23, + 98, + 241, + 60, + 102, + 84, + 127, + 239, + 11, + 225, + 0, + 81, + 222, + 189, + 108, + 19, + 151, + 69, + 145, + 224, + 163, + 44, + 139, + 89, + 121, + 212, + 76, + 245, + 133, + 153, + 96, + 142, + 118, + 207, + 216, + 120, + 161, + 136, + 6, + 237, + 112, + 200, + 152, + 174, + 248, + 253, + 19, + 61, + 66, + 38, + 218, + 225, + 240, + 219, + 231, + 170, + 133, + 87, + 207, + 181, + 31, + 247, + 108, + 115, + 183, + 62, + 209, + 234, + 151, + 112, + 93, + 7, + 148, + 238, + 172, + 10, + 13, + 97, + 40, + 121, + 44, + 243, + 218, + 156, + 71, + 186, + 197, + 97, + 232, + 178, + 85, + 51, + 133, + 176, + 228, + 97, + 239, + 245, + 29, + 187, + 204, + 97, + 115, + 213, + 12, + 182, + 164, + 22, + 113, + 252, + 45, + 148, + 126, + 30, + 201, + 34, + 6, + 75, + 135, + 196, + 81, + 249, + 79, + 235, + 22, + 27, + 117, + 226, + 8, + 236, + 44, + 122, + 236, + 56, + 219, + 204, + 125, + 82, + 237, + 189, + 35, + 1, + 43, + 15, + 18, + 133, + 184, + 99, + 126, + 93, + 132, + 162, + 80, + 176, + 161, + 103, + 90, + 192, + 242, + 181, + 90, + 67, + 126, + 218, + 112, + 136, + 186, + 222, + 193, + 140, + 48, + 177, + 207, + 96, + 15, + 243, + 60, + 250, + 39, + 7, + 101, + 4, + 245, + 185, + 87, + 56, + 246, + 170, + 10, + 178, + 37, + 212, + 224, + 250, + 230, + 124, + 181, + 90, + 143, + 71, + 49, + 35, + 152, + 131, + 67, + 199, + 110, + 211, + 38, + 179, + 232, + 104, + 9, + 55, + 32, + 206, + 212, + 40, + 154, + 238, + 167, + 107, + 210, + 30, + 24, + 180, + 125, + 222, + 211, + 203, + 137, + 116, + 152, + 243, + 129, + 223, + 156, + 114, + 67, + 196, + 212, + 116, + 62, + 245, + 92, + 10, + 122, + 187, + 220, + 226, + 105, + 83, + 118, + 108, + 54, + 49, + 73, + 237, + 40, + 110, + 123, + 113, + 251, + 97, + 212, + 73, + 225, + 88, + 236, + 250, + 58, + 56, + 48, + 131, + 215, + 128, + 173, + 230, + 28, + 57, + 183, + 3, + 42, + 220, + 172, + 7, + 143, + 40, + 102, + 99, + 198, + 139, + 226, + 34, + 231, + 109, + 48, + 63, + 2, + 26, + 237, + 149, + 105, + 221, + 49, + 255, + 224, + 24, + 127, + 126, + 0, + 57, + 127, + 40, + 108, + 64, + 19, + 222, + 48, + 72, + 25, + 69, + 175, + 182, + 188, + 188, + 254, + 184, + 220, + 105, + 226, + 94, + 146, + 202, + 71, + 239, + 28, + 92, + 81, + 122, + 199, + 35, + 150, + 88, + 30, + 248, + 251, + 80, + 0, + 118, + 224, + 153, + 238, + 191, + 137, + 186, + 252, + 175, + 242, + 24, + 79, + 122, + 44, + 122, + 5, + 106, + 53, + 128, + 95, + 149, + 171, + 36, + 222, + 142, + 78, + 19, + 211, + 176, + 61, + 66, + 132, + 236, + 72, + 120, + 67, + 123, + 216, + 23, + 231, + 127, + 197, + 53, + 249, + 58, + 129, + 186, + 160, + 27, + 25, + 70, + 10, + 150, + 94, + 4, + 31, + 119, + 143, + 8, + 135, + 245, + 98, + 82, + 191, + 43, + 168, + 82, + 61, + 132, + 159, + 134, + 155, + 150, + 120, + 190, + 91, + 226, + 142, + 231, + 68, + 151, + 29, + 14, + 128, + 76, + 186, + 254, + 58, + 82, + 105, + 143, + 112, + 239, + 55, + 241, + 166, + 166, + 80, + 175, + 108, + 168, + 48, + 185, + 67, + 86, + 7, + 27, + 184, + 100, + 191, + 240, + 183, + 18, + 96, + 125, + 137, + 121, + 251, + 119, + 141, + 54, + 3, + 233, + 168, + 80, + 160, + 21, + 221, + 131, + 41, + 65, + 225, + 13, + 89, + 2, + 220, + 112, + 72, + 110, + 57, + 179, + 103, + 248, + 187, + 73, + 94, + 96, + 116, + 80, + 3, + 246, + 60, + 119, + 92, + 101, + 254, + 59, + 217, + 45, + 21, + 252, + 198, + 117, + 60, + 98, + 6, + 163, + 182, + 217, + 252, + 221, + 170, + 18, + 236, + 76, + 51, + 167, + 87, + 177, + 17, + 242, + 26, + 250, + 55, + 181, + 223, + 66, + 198, + 166, + 171, + 99, + 146, + 237, + 64, + 52, + 209, + 206, + 170, + 51, + 60, + 19, + 74, + 92, + 33, + 179, + 96, + 196, + 89, + 190, + 73, + 164, + 35, + 196, + 214, + 120, + 211, + 16, + 86, + 192, + 35, + 184, + 195, + 3, + 244, + 228, + 188, + 166, + 111, + 177, + 13, + 177, + 138, + 31, + 124, + 69, + 65, + 181, + 143, + 210, + 253, + 27, + 80, + 115, + 91, + 177, + 118, + 83, + 101, + 170, + 181, + 12, + 85, + 118, + 6, + 219, + 108, + 196, + 31, + 89, + 209, + 8, + 131, + 201, + 80, + 136, + 32, + 182, + 106, + 65, + 236, + 234, + 60, + 86, + 113, + 75, + 11, + 181, + 209, + 192, + 185, + 66, + 88, + 184, + 11, + 149, + 116, + 123, + 145, + 163, + 37, + 229, + 32, + 219, + 3, + 241, + 235, + 156, + 59, + 252, + 141, + 82, + 164, + 171, + 190, + 129, + 110, + 247, + 164, + 223, + 95, + 194, + 240, + 227, + 163, + 91, + 167, + 234, + 143, + 190, + 121, + 27, + 73, + 156, + 66, + 217, + 9, + 57, + 165, + 217, + 246, + 244, + 65, + 219, + 0, + 80, + 99, + 39, + 24, + 55, + 209, + 159, + 250, + 180, + 153, + 116, + 43, + 17, + 52, + 234, + 211, + 70, + 36, + 106, + 187, + 180, + 166, + 239, + 180, + 235, + 54, + 40, + 112, + 167, + 41, + 165, + 96, + 225, + 197, + 82, + 91, + 249, + 60, + 122, + 70, + 7, + 205, + 226, + 220, + 175, + 221, + 15, + 92, + 1, + 85, + 31, + 98, + 28, + 24, + 34, + 182, + 228, + 111, + 159, + 174, + 242, + 61, + 103, + 82, + 29, + 15, + 182, + 89, + 49, + 96, + 35, + 226, + 34, + 107, + 182, + 165, + 253, + 41, + 69, + 74, + 11, + 149, + 58, + 243, + 232, + 241, + 236, + 216, + 183, + 77, + 114, + 123, + 208, + 221, + 227, + 176, + 143, + 137, + 229, + 96, + 66, + 83, + 187, + 51, + 7, + 219, + 212, + 49, + 11, + 80, + 229, + 223, + 18, + 207, + 83, + 100, + 68, + 212, + 194, + 192, + 27, + 202, + 29, + 27, + 120, + 239, + 165, + 53, + 72, + 80, + 77, + 81, + 52, + 104, + 165, + 212, + 251, + 137, + 90, + 232, + 131, + 89, + 190, + 253, + 178, + 23, + 144, + 129, + 56, + 196, + 238, + 139, + 18, + 210, + 185, + 80, + 159, + 227, + 8, + 77, + 39, + 74, + 222, + 92, + 239, + 24, + 228, + 115, + 18, + 219, + 99, + 218, + 67, + 241, + 135, + 88, + 253, + 220, + 114, + 60, + 207, + 218, + 100, + 161, + 143, + 100, + 61, + 68, + 201, + 129, + 63, + 28, + 250, + 171, + 70, + 101, + 174, + 243, + 149, + 204, + 150, + 25, + 199, + 90, + 74, + 136, + 72, + 84, + 130, + 237, + 155, + 220, + 182, + 147, + 240, + 146, + 59, + 205, + 130, + 221, + 142, + 52, + 96, + 237, + 109, + 225, + 58, + 11, + 184, + 207, + 126, + 210, + 116, + 150, + 146, + 164, + 223, + 60, + 7, + 146, + 28, + 223, + 234, + 120, + 218, + 204, + 236, + 57, + 142, + 97, + 69, + 137, + 13, + 206, + 109, + 90, + 213, + 218, + 71, + 78, + 142, + 223, + 242, + 67, + 13, + 237, + 215, + 18, + 36, + 132, + 228, + 151, + 22, + 96, + 173, + 221, + 140, + 186, + 146, + 19, + 39, + 75, + 155, + 55, + 192, + 192, + 148, + 137, + 117, + 17, + 91, + 86, + 234, + 228, + 186, + 201, + 247, + 132, + 104, + 247, + 44, + 77, + 212, + 147, + 240, + 43, + 170, + 118, + 57, + 96, + 152, + 171, + 48, + 43, + 57, + 165, + 53, + 182, + 70, + 160, + 37, + 94, + 79, + 102, + 153, + 226, + 196, + 65, + 62, + 159, + 87, + 60, + 32, + 20, + 84, + 24, + 183, + 189, + 113, + 224, + 58, + 24, + 132, + 13, + 50, + 199, + 39, + 129, + 156, + 48, + 183, + 4, + 5, + 101, + 47, + 71, + 107, + 86, + 9, + 158, + 93, + 11, + 87, + 87, + 100, + 35, + 10, + 23, + 194, + 12, + 188, + 211, + 167, + 253, + 237, + 78, + 20, + 74, + 97, + 169, + 130, + 83, + 178, + 46, + 4, + 201, + 174, + 27, + 131, + 101, + 221, + 144, + 14, + 205, + 25, + 26, + 211, + 161, + 246, + 224, + 67, + 210, + 138, + 11, + 36, + 232, + 180, + 7, + 126, + 71, + 16, + 101, + 39, + 212, + 157, + 177, + 101, + 216, + 132, + 93, + 101, + 243, + 75, + 28, + 104, + 0, + 255, + 31, + 155, + 34, + 128, + 68, + 16, + 254, + 65, + 211, + 116, + 206, + 48, + 41, + 120, + 34, + 147, + 22, + 158, + 51, + 1, + 252, + 60, + 4, + 143, + 22, + 229, + 1, + 50, + 187, + 236, + 58, + 0, + 173, + 68, + 26, + 216, + 38, + 134, + 205, + 73, + 56, + 224, + 17, + 45, + 203, + 1, + 221, + 20, + 70, + 147, + 27, + 191, + 120, + 71, + 194, + 138, + 92, + 236, + 249, + 176, + 103, + 215, + 222, + 174, + 177, + 140, + 42, + 75, + 34, + 116, + 19, + 193, + 64, + 186, + 109, + 252, + 201, + 5, + 226, + 73, + 46, + 26, + 58, + 43, + 35, + 13, + 238, + 217, + 72, + 13, + 108, + 200, + 145, + 183, + 169, + 107, + 111, + 61, + 229, + 241, + 48, + 195, + 124, + 146, + 181, + 31, + 230, + 40, + 181, + 200, + 174, + 150, + 213, + 222, + 184, + 35, + 169, + 159, + 88, + 5, + 112, + 34, + 129, + 15, + 7, + 6, + 146, + 145, + 1, + 123, + 54, + 87, + 192, + 124, + 145, + 234, + 245, + 198, + 206, + 76, + 93, + 3, + 57, + 156, + 208, + 122, + 147, + 9, + 184, + 181, + 138, + 112, + 106, + 52, + 116, + 140, + 197, + 175, + 158, + 90, + 208, + 4, + 183, + 176, + 25, + 148, + 46, + 64, + 136, + 20, + 176, + 6, + 89, + 9, + 198, + 76, + 106, + 238, + 3, + 204, + 27, + 176, + 27, + 231, + 32, + 74, + 104, + 42, + 92, + 119, + 129, + 190, + 31, + 124, + 72, + 149, + 152, + 114, + 198, + 137, + 33, + 21, + 241, + 226, + 40, + 30, + 197, + 216, + 219, + 234, + 112, + 186, + 201, + 2, + 84, + 100, + 11, + 218, + 145, + 182, + 103, + 199, + 224, + 121, + 83, + 3, + 96, + 228, + 121, + 73, + 137, + 32, + 143, + 83, + 18, + 211, + 98, + 110, + 166, + 91, + 141, + 147, + 60, + 78, + 234, + 212, + 23, + 202, + 98, + 137, + 209, + 170, + 164, + 164, + 182, + 236, + 75, + 237, + 16, + 168, + 192, + 190, + 3, + 106, + 191, + 4, + 85, + 132, + 92, + 49, + 236, + 175, + 185, + 199, + 204, + 52, + 201, + 244, + 243, + 22, + 88, + 50, + 86, + 28, + 155, + 179, + 125, + 255, + 42, + 99, + 223, + 109, + 55, + 65, + 225, + 53, + 62, + 190, + 180, + 85, + 20, + 128, + 68, + 140, + 170, + 93, + 216, + 192, + 84, + 147, + 145, + 45, + 55, + 246, + 143, + 184, + 54, + 132, + 185, + 200, + 135, + 178, + 249, + 128, + 185, + 152, + 135, + 251, + 88, + 183, + 247, + 17, + 146, + 10, + 72, + 172, + 228, + 90, + 210, + 91, + 85, + 206, + 174, + 35, + 57, + 134, + 53, + 132, + 199, + 96, + 175, + 136, + 224, + 112, + 52, + 26, + 12, + 111, + 214, + 172, + 236, + 226, + 179, + 38, + 131, + 241, + 15, + 210, + 187, + 193, + 17, + 172, + 143, + 247, + 249, + 9, + 90, + 91, + 251, + 66, + 71, + 157, + 33, + 8, + 150, + 91, + 164, + 244, + 108, + 236, + 169, + 203, + 227, + 253, + 44, + 62, + 4, + 225, + 162, + 184, + 57, + 5, + 104, + 98, + 12, + 223, + 67, + 182, + 27, + 3, + 86, + 183, + 27, + 224, + 169, + 203, + 131, + 116, + 154, + 213, + 74, + 223, + 156, + 153, + 188, + 226, + 118, + 26, + 150, + 76, + 53, + 119, + 29, + 96, + 250, + 143, + 128, + 83, + 118, + 215, + 79, + 233, + 151, + 55, + 202, + 132, + 215, + 137, + 150, + 21, + 15, + 159, + 152, + 81, + 179, + 221, + 170, + 204, + 225, + 57, + 227, + 164, + 57, + 35, + 182, + 236, + 77, + 106, + 249, + 25, + 92, + 87, + 76, + 105, + 103, + 96, + 243, + 251, + 109, + 58, + 85, + 120, + 30, + 217, + 203, + 189, + 249, + 216, + 220, + 3, + 64, + 94, + 125, + 45, + 208, + 47, + 3, + 172, + 148, + 90, + 138, + 31, + 109, + 75, + 114, + 91, + 61, + 103, + 145, + 213, + 227, + 88, + 175, + 115, + 2, + 70, + 243, + 42, + 176, + 174, + 135, + 137, + 240, + 57, + 95, + 203, + 51, + 249, + 24, + 206, + 234, + 75, + 134, + 245, + 25, + 45, + 110, + 183, + 240, + 15, + 62, + 96, + 168, + 140, + 204, + 13, + 255, + 104, + 134, + 170, + 165, + 219, + 19, + 145, + 27, + 113, + 38, + 18, + 76, + 240, + 140, + 162, + 24, + 102, + 104, + 52, + 106, + 105, + 18, + 161, + 153, + 237, + 131, + 81, + 133, + 59, + 238, + 67, + 158, + 241, + 219, + 79, + 86, + 204, + 127, + 47, + 228, + 225, + 248, + 153, + 193, + 101, + 237, + 142, + 250, + 56, + 36, + 62, + 109, + 217, + 34, + 251, + 200, + 127, + 168, + 147, + 160, + 155, + 13, + 203, + 165, + 104, + 197, + 164, + 92, + 186, + 167, + 115, + 202, + 177, + 193, + 45, + 206, + 124, + 130, + 208, + 141, + 179, + 122, + 18, + 33, + 234, + 45, + 13, + 4, + 170, + 216, + 57, + 216, + 48, + 23, + 81, + 57, + 49, + 20, + 3, + 138, + 34, + 10, + 7, + 85, + 235, + 221, + 108, + 106, + 25, + 229, + 247, + 128, + 137, + 129, + 93, + 192, + 128, + 48, + 252, + 139, + 204, + 45, + 163, + 36, + 242, + 201, + 99, + 152, + 95, + 151, + 121, + 180, + 16, + 71, + 138, + 178, + 220, + 175, + 134, + 102, + 35, + 42, + 36, + 49, + 247, + 78, + 219, + 171, + 201, + 104, + 120, + 110, + 135, + 103, + 218, + 157, + 25, + 184, + 9, + 118, + 249, + 104, + 167, + 24, + 181, + 100, + 41, + 156, + 105, + 192, + 2, + 252, + 37, + 73, + 116, + 250, + 145, + 12, + 248, + 23, + 227, + 72, + 33, + 244, + 28, + 241, + 29, + 220, + 89, + 202, + 255, + 104, + 20, + 31, + 58, + 94, + 106, + 97, + 49, + 44, + 149, + 28, + 163, + 248, + 196, + 42, + 130, + 95, + 227, + 146, + 20, + 125, + 130, + 83, + 158, + 54, + 239, + 110, + 116, + 88, + 242, + 218, + 113, + 67, + 77, + 255, + 219, + 58, + 168, + 114, + 235, + 98, + 11, + 39, + 37, + 121, + 33, + 193, + 103, + 187, + 239, + 228, + 194, + 81, + 51, + 10, + 80, + 8, + 16, + 233, + 242, + 158, + 140, + 222, + 9, + 86, + 94, + 28, + 223, + 24, + 79, + 123, + 145, + 100, + 37, + 45, + 113, + 102, + 245, + 10, + 244, + 8, + 141, + 153, + 156, + 80, + 130, + 79, + 36, + 149, + 58, + 237, + 166, + 59, + 74, + 193, + 47, + 186, + 91, + 248, + 48, + 166, + 117, + 144, + 205, + 144, + 148, + 47, + 89, + 77, + 56, + 236, + 162, + 99, + 134, + 4, + 149, + 152, + 20, + 111, + 133, + 90, + 86, + 148, + 136, + 255, + 239, + 151, + 72, + 15, + 159, + 78, + 53, + 139, + 251, + 211, + 251, + 118, + 103, + 105, + 99, + 249, + 111, + 104, + 22, + 249, + 167, + 181, + 25, + 50, + 145, + 107, + 34, + 118, + 174, + 104, + 248, + 24, + 245, + 168, + 76, + 25, + 224, + 49, + 177, + 121, + 68, + 17, + 137, + 100, + 61, + 196, + 255, + 111, + 124, + 190, + 152, + 22, + 131, + 242, + 227, + 224, + 245, + 29, + 129, + 95, + 77, + 84, + 175, + 74, + 204, + 110, + 0, + 104, + 40, + 177, + 219, + 55, + 14, + 54, + 241, + 90, + 132, + 130, + 31, + 12, + 222, + 130, + 40, + 217, + 135, + 128, + 206, + 15, + 84, + 82, + 70, + 26, + 186, + 170, + 183, + 137, + 97, + 44, + 126, + 135, + 101, + 172, + 254, + 222, + 159, + 92, + 119, + 94, + 45, + 174, + 119, + 245, + 184, + 63, + 17, + 152, + 34, + 11, + 101, + 153, + 27, + 92, + 23, + 65, + 115, + 215, + 40, + 33, + 252, + 69, + 92, + 160, + 0, + 85, + 194, + 14, + 16, + 207, + 119, + 201, + 138, + 77, + 218, + 195, + 212, + 175, + 20, + 180, + 41, + 55, + 25, + 82, + 111, + 66, + 213, + 84, + 1, + 186, + 12, + 129, + 46, + 87, + 0, + 16, + 216, + 87, + 160, + 100, + 63, + 229, + 90, + 187, + 51, + 82, + 60, + 185, + 23, + 100, + 240, + 173, + 110, + 142, + 186, + 202, + 180, + 5, + 10, + 6, + 15, + 38, + 111, + 38, + 135, + 40, + 91, + 41, + 192, + 52, + 107, + 28, + 119, + 63, + 129, + 51, + 142, + 127, + 246, + 25, + 72, + 42, + 124, + 153, + 232, + 5, + 7, + 91, + 108, + 3, + 108, + 182, + 240, + 129, + 103, + 135, + 185, + 138, + 6, + 32, + 37, + 63, + 36, + 5, + 27, + 168, + 75, + 101, + 22, + 102, + 209, + 224, + 13, + 194, + 120, + 111, + 10, + 28, + 226, + 194, + 18, + 99, + 53, + 221, + 24, + 162, + 22, + 92, + 90, + 148, + 22, + 211, + 30, + 140, + 53, + 244, + 135, + 62, + 130, + 87, + 4, + 240, + 118, + 221, + 196, + 69, + 209, + 235, + 108, + 66, + 168, + 185, + 157, + 38, + 1, + 92, + 155, + 168, + 68, + 120, + 163, + 51, + 88, + 47, + 252, + 26, + 93, + 134, + 163, + 246, + 75, + 239, + 203, + 34, + 144, + 94, + 143, + 197, + 30, + 207, + 182, + 86, + 195, + 144, + 55, + 102, + 145, + 97, + 147, + 209, + 142, + 203, + 24, + 242, + 91, + 16, + 184, + 160, + 36, + 81, + 247, + 177, + 89, + 89, + 174, + 16, + 79, + 78, + 99, + 206, + 178, + 31, + 4, + 36, + 149, + 183, + 78, + 88, + 173, + 200, + 80, + 152, + 33, + 45, + 195, + 162, + 161, + 236, + 197, + 10, + 126, + 212, + 237, + 226, + 203, + 226, + 118, + 10, + 179, + 111, + 178, + 4, + 127, + 186, + 203, + 49, + 40, + 54, + 238, + 38, + 103, + 34, + 204, + 243, + 164, + 245, + 75, + 20, + 48, + 25, + 80, + 209, + 66, + 148, + 205, + 80, + 82, + 88, + 204, + 0, + 118, + 230, + 174, + 97, + 7, + 35, + 142, + 88, + 159, + 184, + 150, + 106, + 134, + 197, + 184, + 0, + 223, + 187, + 89, + 84, + 58, + 86, + 67, + 43, + 35, + 214, + 132, + 23, + 43, + 122, + 192, + 19, + 8, + 192, + 45, + 108, + 207, + 213, + 193, + 181, + 114, + 240, + 165, + 39, + 149, + 77, + 118, + 136, + 10, + 156, + 15, + 156, + 65, + 113, + 231, + 75, + 198, + 160, + 255, + 122, + 108, + 75, + 167, + 252, + 57, + 243, + 166, + 173, + 229, + 159, + 66, + 229, + 141, + 131, + 178, + 46, + 97, + 244, + 213, + 254, + 67, + 14, + 16, + 177, + 78, + 120, + 3, + 100, + 174, + 79, + 131, + 186, + 204, + 83, + 218, + 203, + 226, + 237, + 123, + 179, + 4, + 201, + 132, + 38, + 39, + 194, + 62, + 11, + 224, + 172, + 121, + 219, + 220, + 250, + 82, + 228, + 46, + 176, + 80, + 107, + 77, + 56, + 174, + 0, + 229, + 152, + 80, + 149, + 185, + 21, + 160, + 60, + 124, + 95, + 173, + 241, + 172, + 197, + 85, + 41, + 2, + 105, + 40, + 3, + 32, + 36, + 118, + 218, + 16, + 109, + 99, + 55, + 18, + 110, + 231, + 113, + 52, + 121, + 171, + 203, + 193, + 2, + 255, + 7, + 254, + 0, + 162, + 118, + 230, + 68, + 15, + 59, + 99, + 111, + 82, + 135, + 215, + 203, + 8, + 4, + 110, + 236, + 103, + 89, + 170, + 28, + 200, + 117, + 32, + 16, + 94, + 243, + 48, + 116, + 91, + 52, + 150, + 34, + 78, + 223, + 46, + 146, + 129, + 78, + 101, + 91, + 52, + 134, + 69, + 19, + 82, + 10, + 107, + 170, + 109, + 102, + 77, + 223, + 43, + 223, + 100, + 174, + 80, + 17, + 245, + 198, + 105, + 217, + 226, + 66, + 48, + 179, + 177, + 45, + 119, + 50, + 238, + 135, + 184, + 215, + 16, + 190, + 124, + 24, + 40, + 244, + 131, + 20, + 160, + 202, + 54, + 54, + 40, + 80, + 8, + 58, + 206, + 221, + 91, + 50, + 28, + 197, + 180, + 207, + 205, + 255, + 162, + 37, + 80, + 219, + 204, + 228, + 57, + 65, + 188, + 8, + 225, + 122, + 246, + 92, + 111, + 208, + 106, + 231, + 92, + 250, + 117, + 160, + 235, + 98, + 166, + 46, + 97, + 229, + 159, + 163, + 231, + 13, + 200, + 108, + 212, + 252, + 96, + 102, + 192, + 13, + 230, + 201, + 219, + 34, + 142, + 234, + 90, + 113, + 104, + 128, + 121, + 234, + 7, + 62, + 67, + 146, + 10, + 176, + 109, + 84, + 103, + 143, + 244, + 65, + 185, + 76, + 200, + 185, + 64, + 252, + 247, + 235, + 252, + 189, + 128, + 113, + 31, + 9, + 189, + 150, + 166, + 64, + 89, + 249, + 185, + 52, + 223, + 59, + 19, + 50, + 23, + 112, + 127, + 22, + 235, + 170, + 42, + 81, + 235, + 215, + 133, + 157, + 153, + 193, + 22, + 158, + 132, + 244, + 18, + 158, + 212, + 100, + 128, + 82, + 193, + 227, + 86, + 59, + 31, + 67, + 61, + 114, + 252, + 245, + 124, + 85, + 94, + 45, + 228, + 87, + 241, + 53, + 37, + 79, + 191, + 123, + 101, + 5, + 95, + 157, + 75, + 93, + 99, + 189, + 176, + 154, + 121, + 199, + 188, + 164, + 76, + 234, + 66, + 115, + 32, + 205, + 71, + 171, + 167, + 139, + 251, + 67, + 248, + 178, + 199, + 35, + 213, + 1, + 154, + 98, + 111, + 4, + 12, + 207, + 157, + 133, + 156, + 22, + 253, + 12, + 13, + 57, + 192, + 104, + 227, + 59, + 92, + 58, + 76, + 46, + 223, + 75, + 205, + 42, + 13, + 223, + 152, + 183, + 26, + 155, + 171, + 69, + 47, + 158, + 34, + 228, + 114, + 131, + 8, + 251, + 113, + 11, + 20, + 199, + 11, + 97, + 229, + 255, + 149, + 74, + 196, + 95, + 130, + 48, + 57, + 72, + 54, + 50, + 174, + 77, + 128, + 251, + 129, + 74, + 254, + 242, + 1, + 186, + 33, + 197, + 91, + 135, + 76, + 43, + 76, + 216, + 193, + 177, + 208, + 116, + 117, + 28, + 150, + 53, + 74, + 65, + 147, + 91, + 133, + 147, + 101, + 21, + 183, + 198, + 199, + 78, + 218, + 15, + 137, + 172, + 79, + 179, + 26, + 224, + 156, + 53, + 4, + 210, + 163, + 58, + 160, + 233, + 36, + 232, + 93, + 250, + 4, + 190, + 65, + 85, + 178, + 195, + 174, + 46, + 215, + 233, + 36, + 136, + 225, + 113, + 68, + 28, + 204, + 165, + 243, + 98, + 17, + 154, + 7, + 12, + 56, + 151, + 218, + 193, + 107, + 167, + 59, + 123, + 24, + 95, + 169, + 35, + 100, + 71, + 112, + 231, + 180, + 8, + 94, + 41, + 169, + 193, + 6, + 191, + 188, + 73, + 59, + 53, + 37, + 109, + 100, + 48, + 16, + 166, + 185, + 115, + 59, + 6, + 40, + 232, + 137, + 22, + 229, + 60, + 82, + 149, + 77, + 177, + 229, + 18, + 249, + 5, + 164, + 108, + 116, + 112, + 153, + 3, + 149, + 38, + 248, + 83, + 35, + 25, + 247, + 212, + 152, + 90, + 167, + 16, + 78, + 80, + 99, + 240, + 55, + 52, + 22, + 48, + 85, + 3, + 228, + 101, + 108, + 112, + 62, + 6, + 12, + 70, + 125, + 120, + 129, + 161, + 35, + 142, + 90, + 70, + 30, + 87, + 121, + 200, + 114, + 143, + 176, + 242, + 205, + 14, + 13, + 49, + 27, + 92, + 250, + 6, + 160, + 92, + 13, + 54, + 108, + 13, + 221, + 88, + 120, + 227, + 123, + 174, + 191, + 2, + 101, + 114, + 202, + 20, + 27, + 114, + 255, + 213, + 59, + 236, + 24, + 55, + 116, + 67, + 104, + 74, + 248, + 247, + 37, + 60, + 55, + 223, + 26, + 103, + 49, + 3, + 33, + 80, + 32, + 8, + 16, + 80, + 115, + 116, + 96, + 193, + 146, + 225, + 139, + 179, + 11, + 99, + 215, + 139, + 104, + 40, + 19, + 33, + 222, + 96, + 234, + 198, + 78, + 121, + 165, + 226, + 105, + 247, + 184, + 81, + 171, + 54, + 151, + 200, + 75, + 1, + 56, + 64, + 121, + 246, + 144, + 171, + 153, + 148, + 52, + 77, + 30, + 52, + 40, + 99, + 234, + 99, + 109, + 164, + 152, + 116, + 115, + 231, + 199, + 254, + 3, + 143, + 17, + 151, + 70, + 191, + 59, + 173, + 213, + 11, + 246, + 191, + 148, + 194, + 42, + 130, + 248, + 131, + 101, + 101, + 156, + 175, + 101, + 112, + 51, + 168, + 28, + 230, + 20, + 117, + 199, + 195, + 173, + 1, + 96, + 168, + 239, + 211, + 243, + 28, + 44, + 118, + 155, + 136, + 192, + 129, + 243, + 138, + 124, + 94, + 167, + 9, + 42, + 212, + 56, + 13, + 75, + 87, + 28, + 19, + 30, + 192, + 39, + 93, + 98, + 23, + 15, + 187, + 88, + 195, + 85, + 129, + 184, + 30, + 142, + 24, + 148, + 7, + 56, + 159, + 140, + 127, + 231, + 59, + 90, + 42, + 135, + 16, + 170, + 187, + 129, + 15, + 27, + 86, + 241, + 109, + 82, + 73, + 230, + 134, + 29, + 38, + 205, + 106, + 146, + 237, + 75, + 115, + 45, + 56, + 16, + 81, + 25, + 126, + 252, + 6, + 63, + 181, + 15, + 34, + 231, + 59, + 174, + 91, + 145, + 235, + 59, + 22, + 248, + 77, + 28, + 185, + 230, + 138, + 251, + 61, + 218, + 247, + 84, + 112, + 201, + 203, + 199, + 111, + 72, + 242, + 181, + 54, + 130, + 146, + 68, + 213, + 97, + 66, + 165, + 152, + 3, + 236, + 151, + 42, + 118, + 199, + 34, + 249, + 88, + 39, + 41, + 188, + 61, + 193, + 250, + 227, + 173, + 177, + 104, + 102, + 37, + 124, + 225, + 74, + 147, + 195, + 236, + 12, + 16, + 91, + 52, + 194, + 109, + 211, + 143, + 68, + 34, + 121, + 159, + 159, + 61, + 12, + 13, + 75, + 138, + 219, + 50, + 248, + 2, + 231, + 8, + 1, + 89, + 199, + 162, + 39, + 176, + 65, + 37, + 230, + 106, + 121, + 98, + 177, + 85, + 115, + 115, + 249, + 118, + 250, + 119, + 36, + 160, + 40, + 249, + 231, + 115, + 89, + 235, + 252, + 186, + 68, + 163, + 160, + 35, + 225, + 211, + 12, + 230, + 116, + 205, + 141, + 157, + 201, + 58, + 39, + 200, + 32, + 206, + 75, + 23, + 223, + 233, + 184, + 4, + 72, + 11, + 114, + 233, + 118, + 62, + 53, + 31, + 134, + 204, + 189, + 115, + 67, + 120, + 17, + 157, + 117, + 161, + 170, + 3, + 209, + 235, + 114, + 240, + 25, + 223, + 226, + 182, + 204, + 150, + 208, + 243, + 45, + 67, + 64, + 90, + 245, + 204, + 121, + 184, + 240, + 30, + 144, + 182, + 11, + 159, + 7, + 143, + 10, + 43, + 219, + 230, + 66, + 204, + 181, + 12, + 25, + 173, + 247, + 23, + 20, + 141, + 190, + 133, + 100, + 10, + 124, + 25, + 34, + 48, + 233, + 32, + 128, + 55, + 215, + 34, + 55, + 198, + 33, + 24, + 55, + 208, + 68, + 82, + 171, + 24, + 1, + 74, + 173, + 246, + 187, + 237, + 225, + 1, + 25, + 174, + 239, + 43, + 173, + 107, + 64, + 21, + 45, + 0, + 55, + 219, + 9, + 128, + 120, + 62, + 91, + 189, + 148, + 220, + 24, + 47, + 15, + 124, + 184, + 54, + 97, + 187, + 176, + 216, + 21, + 153, + 101, + 100, + 227, + 216, + 36, + 202, + 6, + 121, + 53, + 103, + 45, + 33, + 4, + 18, + 232, + 227, + 80, + 132, + 130, + 241, + 101, + 75, + 23, + 16, + 137, + 1, + 213, + 191, + 185, + 122, + 101, + 96, + 70, + 82, + 93, + 37, + 56, + 148, + 63, + 165, + 183, + 239, + 118, + 69, + 194, + 99, + 28, + 201, + 97, + 15, + 30, + 153, + 9, + 189, + 103, + 133, + 111, + 122, + 131, + 211, + 210, + 147, + 244, + 139, + 8, + 125, + 41, + 142, + 191, + 170, + 125, + 46, + 54, + 224, + 180, + 57, + 109, + 234, + 220, + 76, + 82, + 211, + 136, + 164, + 122, + 93, + 155, + 166, + 124, + 50, + 144, + 104, + 3, + 237, + 132, + 186, + 190, + 20, + 14, + 197, + 32, + 224, + 207, + 12, + 114, + 203, + 138, + 157, + 163, + 223, + 108, + 248, + 36, + 145, + 1, + 18, + 135, + 10, + 224, + 62, + 28, + 126, + 150, + 163, + 212, + 91, + 241, + 106, + 113, + 177, + 141, + 65, + 238, + 126, + 18, + 203, + 197, + 140, + 247, + 133, + 224, + 25, + 35, + 142, + 77, + 189, + 17, + 188, + 127, + 237, + 31, + 166, + 69, + 64, + 227, + 215, + 6, + 63, + 221, + 126, + 234, + 226, + 249, + 107, + 246, + 10, + 214, + 73, + 37, + 245, + 127, + 241, + 103, + 104, + 3, + 80, + 65, + 65, + 1, + 119, + 9, + 241, + 198, + 134, + 43, + 193, + 217, + 31, + 198, + 20, + 213, + 137, + 20, + 252, + 193, + 20, + 164, + 141, + 236, + 184, + 181, + 209, + 8, + 99, + 84, + 34, + 220, + 218, + 50, + 82, + 248, + 238, + 165, + 214, + 206, + 104, + 142, + 38, + 233, + 16, + 75, + 130, + 187, + 205, + 171, + 208, + 104, + 198, + 105, + 180, + 192, + 77, + 115, + 13, + 32, + 118, + 21, + 249, + 108, + 254, + 58, + 45, + 249, + 150, + 227, + 2, + 135, + 237, + 204, + 113, + 221, + 102, + 173, + 238, + 59, + 34, + 58, + 217, + 92, + 248, + 220, + 116, + 120, + 115, + 215, + 76, + 140, + 75, + 187, + 19, + 24, + 170, + 48, + 35, + 186, + 106, + 165, + 80, + 196, + 246, + 57, + 193, + 49, + 98, + 152, + 180, + 178, + 14, + 170, + 194, + 164, + 177, + 38, + 70, + 92, + 52, + 128, + 178, + 61, + 171, + 104, + 154, + 221, + 85, + 90, + 232, + 59, + 178, + 148, + 210, + 152, + 42, + 169, + 210, + 4, + 48, + 168, + 254, + 148, + 15, + 188, + 208, + 62, + 254, + 122, + 110, + 177, + 134, + 167, + 67, + 14, + 239, + 173, + 228, + 73, + 48, + 66, + 114, + 231, + 162, + 20, + 232, + 145, + 14, + 94, + 156, + 100, + 117, + 15, + 12, + 120, + 174, + 146, + 239, + 17, + 29, + 170, + 219, + 86, + 154, + 232, + 177, + 170, + 183, + 89, + 35, + 88, + 169, + 51, + 185, + 46, + 152, + 78, + 195, + 251, + 119, + 45, + 214, + 145, + 1, + 172, + 234, + 27, + 26, + 122, + 239, + 216, + 229, + 13, + 184, + 42, + 111, + 148, + 162, + 181, + 203, + 61, + 28, + 254, + 26, + 30, + 93, + 93, + 172, + 191, + 124, + 233, + 159, + 227, + 225, + 99, + 33, + 124, + 161, + 196, + 234, + 128, + 176, + 55, + 39, + 69, + 251, + 202, + 161, + 245, + 241, + 70, + 217, + 136, + 12, + 212, + 40, + 112, + 12, + 143, + 115, + 40, + 212, + 165, + 181, + 254, + 39, + 226, + 202, + 217, + 31, + 84, + 246, + 154, + 150, + 85, + 176, + 139, + 41, + 20, + 214, + 172, + 172, + 101, + 43, + 37, + 37, + 62, + 186, + 114, + 86, + 75, + 205, + 207, + 213, + 88, + 87, + 63, + 144, + 132, + 232, + 97, + 65, + 137, + 165, + 116, + 43, + 249, + 134, + 31, + 209, + 35, + 21, + 85, + 216, + 190, + 211, + 219, + 146, + 205, + 179, + 110, + 38, + 151, + 134, + 161, + 116, + 55, + 50, + 239, + 142, + 42, + 237, + 17, + 193, + 64, + 81, + 213, + 15, + 66, + 110, + 98, + 117, + 154, + 34, + 56, + 158, + 205, + 195, + 217, + 48, + 104, + 154, + 9, + 149, + 208, + 167, + 211, + 59, + 15, + 115, + 120, + 14, + 244, + 74, + 254, + 109, + 81, + 232, + 179, + 7, + 17, + 118, + 237, + 215, + 79, + 154, + 22, + 114, + 3, + 141, + 186, + 154, + 43, + 212, + 93, + 181, + 2, + 65, + 128, + 116, + 224, + 104, + 61, + 91, + 108, + 138, + 10, + 16, + 198, + 235, + 174, + 58, + 85, + 215, + 166, + 181, + 115, + 194, + 47, + 32, + 204, + 36, + 151, + 244, + 50, + 230, + 56, + 225, + 23, + 155, + 188, + 54, + 103, + 6, + 195, + 130, + 85, + 76, + 212, + 212, + 193, + 185, + 20, + 20, + 152, + 107, + 140, + 104, + 69, + 195, + 217, + 156, + 13, + 178, + 103, + 200, + 15, + 174, + 76, + 101, + 181, + 245, + 144, + 180, + 127, + 35, + 111, + 81, + 4, + 52, + 119, + 76, + 13, + 77, + 26, + 29, + 167, + 34, + 213, + 62, + 28, + 209, + 157, + 202, + 242, + 135, + 213, + 108, + 32, + 255, + 91, + 23, + 61, + 123, + 132, + 179, + 71, + 33, + 217, + 128, + 213, + 170, + 129, + 208, + 31, + 153, + 104, + 186, + 101, + 33, + 122, + 170, + 109, + 218, + 251, + 67, + 229, + 240, + 26, + 113, + 179, + 51, + 100, + 217, + 202, + 186, + 55, + 213, + 16, + 217, + 141, + 60, + 8, + 153, + 6, + 79, + 222, + 89, + 123, + 242, + 104, + 24, + 201, + 37, + 10, + 254, + 239, + 112, + 30, + 177, + 45, + 195, + 241, + 181, + 18, + 250, + 33, + 232, + 225, + 55, + 222, + 211, + 26, + 241, + 20, + 77, + 88, + 199, + 53, + 72, + 151, + 184, + 59, + 129, + 203, + 245, + 162, + 161, + 218, + 21, + 39, + 121, + 226, + 134, + 131, + 130, + 21, + 80, + 42, + 252, + 251, + 21, + 79, + 51, + 210, + 69, + 115, + 36, + 246, + 208, + 8, + 163, + 94, + 203, + 189, + 236, + 112, + 86, + 219, + 116, + 150, + 91, + 245, + 37, + 246, + 219, + 100, + 207, + 78, + 94, + 253, + 90, + 217, + 169, + 18, + 6, + 144, + 229, + 164, + 69, + 61, + 126, + 160, + 157, + 129, + 208, + 252, + 252, + 185, + 249, + 165, + 156, + 100, + 26, + 248, + 172, + 18, + 194, + 0, + 116, + 11, + 36, + 189, + 58, + 220, + 153, + 48, + 137, + 186, + 171, + 182, + 69, + 61, + 214, + 9, + 167, + 80, + 222, + 212, + 158, + 138, + 150, + 190, + 176, + 233, + 220, + 16, + 228, + 230, + 169, + 54, + 197, + 91, + 11, + 30, + 225, + 10, + 63, + 234, + 116, + 147, + 87, + 137, + 28, + 221, + 175, + 45, + 176, + 55, + 100, + 39, + 141, + 221, + 28, + 18, + 29, + 65, + 209, + 102, + 43, + 143, + 14, + 172, + 223, + 9, + 149, + 52, + 19, + 177, + 149, + 131, + 4, + 63, + 21, + 3, + 42, + 161, + 104, + 34, + 131, + 232, + 24, + 157, + 184, + 52, + 204, + 18, + 130, + 157, + 180, + 152, + 136, + 157, + 99, + 49, + 202, + 83, + 177, + 1, + 6, + 71, + 84, + 148, + 234, + 39, + 66, + 62, + 200, + 238, + 246, + 238, + 89, + 190, + 3, + 164, + 151, + 37, + 146, + 157, + 119, + 222, + 97, + 203, + 159, + 170, + 7, + 227, + 148, + 90, + 149, + 127, + 62, + 220, + 247, + 219, + 185, + 199, + 120, + 119, + 237, + 99, + 95, + 163, + 121, + 119, + 60, + 164, + 76, + 34, + 38, + 187, + 244, + 152, + 24, + 141, + 130, + 169, + 215, + 7, + 198, + 14, + 76, + 217, + 65, + 222, + 80, + 7, + 41, + 13, + 250, + 101, + 68, + 250, + 188, + 54, + 45, + 251, + 74, + 175, + 201, + 54, + 73, + 102, + 244, + 182, + 183, + 114, + 188, + 198, + 60, + 160, + 21, + 44, + 215, + 119, + 126, + 67, + 49, + 213, + 205, + 136, + 86, + 32, + 178, + 175, + 249, + 171, + 134, + 66, + 215, + 223, + 237, + 118, + 55, + 83, + 173, + 3, + 227, + 249, + 81, + 96, + 169, + 183, + 114, + 37, + 242, + 96, + 175, + 219, + 93, + 65, + 190, + 104, + 113, + 36, + 36, + 156, + 90, + 148, + 77, + 106, + 175, + 169, + 3, + 226, + 1, + 53, + 116, + 137, + 124, + 123, + 215, + 229, + 225, + 53, + 133, + 93, + 179, + 131, + 123, + 211, + 50, + 6, + 164, + 24, + 20, + 177, + 96, + 77, + 224, + 199, + 200, + 63, + 155, + 165, + 237, + 154, + 158, + 92, + 92, + 175, + 22, + 146, + 80, + 148, + 198, + 232, + 20, + 103, + 110, + 236, + 32, + 231, + 128, + 226, + 17, + 87, + 60, + 184, + 222, + 207, + 93, + 187, + 223, + 243, + 243, + 225, + 152, + 115, + 217, + 57, + 129, + 91, + 72, + 134, + 225, + 176, + 210, + 243, + 190, + 110, + 251, + 170, + 208, + 193, + 38, + 242, + 57, + 226, + 114, + 29, + 200, + 147, + 250, + 177, + 70, + 252, + 138, + 7, + 252, + 177, + 36, + 255, + 199, + 59, + 186, + 129, + 76, + 179, + 187, + 124, + 81, + 27, + 101, + 40, + 128, + 23, + 17, + 158, + 52, + 126, + 10, + 204, + 64, + 130, + 75, + 67, + 255, + 60, + 25, + 170, + 57, + 242, + 153, + 247, + 63, + 204, + 69, + 93, + 138, + 222, + 215, + 97, + 146, + 4, + 159, + 176, + 203, + 241, + 211, + 141, + 62, + 224, + 198, + 152, + 124, + 76, + 75, + 87, + 189, + 92, + 236, + 151, + 7, + 100, + 223, + 58, + 85, + 65, + 221, + 212, + 21, + 16, + 188, + 128, + 161, + 114, + 220, + 234, + 254, + 132, + 33, + 20, + 150, + 166, + 72, + 186, + 96, + 14, + 22, + 96, + 106, + 11, + 14, + 140, + 82, + 77, + 122, + 138, + 99, + 57, + 226, + 129, + 100, + 75, + 73, + 160, + 216, + 26, + 90, + 238, + 36, + 165, + 239, + 153, + 60, + 72, + 90, + 248, + 229, + 63, + 144, + 177, + 252, + 201, + 179, + 31, + 18, + 215, + 248, + 146, + 1, + 26, + 204, + 249, + 60, + 210, + 10, + 127, + 222, + 28, + 108, + 6, + 166, + 225, + 85, + 59, + 42, + 225, + 251, + 188, + 45, + 114, + 97, + 168, + 204, + 129, + 98, + 68, + 44, + 6, + 207, + 106, + 207, + 232, + 25, + 11, + 170, + 192, + 19, + 229, + 145, + 0, + 105, + 114, + 190, + 239, + 195, + 161, + 70, + 153, + 162, + 128, + 129, + 166, + 119, + 114, + 110, + 5, + 180, + 154, + 179, + 252, + 204, + 101, + 34, + 76, + 196, + 86, + 155, + 145, + 125, + 245, + 211, + 18, + 131, + 144, + 231, + 65, + 161, + 216, + 52, + 172, + 22, + 103, + 210, + 239, + 69, + 185, + 14, + 153, + 178, + 148, + 181, + 119, + 80, + 221, + 127, + 52, + 211, + 119, + 32, + 10, + 109, + 124, + 115, + 14, + 70, + 111, + 117, + 37, + 2, + 30, + 175, + 213, + 155, + 153, + 59, + 59, + 159, + 246, + 50, + 30, + 188, + 107, + 182, + 6, + 64, + 6, + 237, + 176, + 150, + 220, + 158, + 214, + 157, + 190, + 156, + 88, + 225, + 46, + 148, + 196, + 124, + 221, + 13, + 63, + 252, + 118, + 20, + 179, + 63, + 208, + 24, + 44, + 142, + 99, + 194, + 183, + 74, + 162, + 111, + 242, + 44, + 192, + 118, + 231, + 222, + 225, + 216, + 104, + 147, + 100, + 84, + 100, + 125, + 49, + 92, + 116, + 217, + 118, + 137, + 240, + 59, + 139, + 170, + 12, + 166, + 179, + 218, + 188, + 48, + 14, + 113, + 169, + 137, + 63, + 159, + 201, + 42, + 23, + 218, + 80, + 174, + 199, + 41, + 13, + 189, + 178, + 162, + 110, + 181, + 59, + 172, + 85, + 176, + 63, + 51, + 182, + 111, + 241, + 192, + 103, + 70, + 27, + 170, + 12, + 0, + 114, + 239, + 234, + 73, + 23, + 193, + 111, + 17, + 5, + 193, + 241, + 126, + 102, + 174, + 68, + 180, + 34, + 25, + 177, + 57, + 160, + 140, + 74, + 132, + 93, + 99, + 187, + 40, + 47, + 80, + 141, + 40, + 9, + 144, + 172, + 59, + 107, + 105, + 89, + 56, + 34, + 7, + 32, + 177, + 140, + 219, + 26, + 113, + 160, + 53, + 0, + 173, + 217, + 15, + 84, + 219, + 6, + 154, + 154, + 208, + 213, + 30, + 128, + 153, + 45, + 110, + 44, + 26, + 179, + 191, + 106, + 214, + 96, + 126, + 193, + 18, + 34, + 210, + 99, + 60, + 19, + 73, + 116, + 77, + 228, + 116, + 240, + 151, + 248, + 72, + 114, + 93, + 214, + 96, + 115, + 122, + 153, + 246, + 86, + 170, + 105, + 176, + 99, + 229, + 76, + 41, + 45, + 113, + 105, + 40, + 245, + 238, + 128, + 113, + 163, + 149, + 178, + 229, + 18, + 7, + 249, + 54, + 41, + 224, + 46, + 190, + 176, + 152, + 59, + 169, + 156, + 157, + 106, + 40, + 4, + 198, + 146, + 60, + 80, + 76, + 141, + 186, + 242, + 255, + 62, + 206, + 117, + 117, + 151, + 9, + 74, + 72, + 235, + 97, + 24, + 212, + 227, + 231, + 70, + 164, + 66, + 159, + 77, + 163, + 190, + 70, + 93, + 111, + 195, + 78, + 151, + 136, + 179, + 58, + 53, + 110, + 225, + 89, + 120, + 9, + 42, + 19, + 74, + 209, + 43, + 207, + 222, + 53, + 117, + 127, + 66, + 57, + 247, + 243, + 114, + 182, + 82, + 154, + 57, + 123, + 224, + 42, + 66, + 231, + 29, + 74, + 61, + 117, + 215, + 127, + 153, + 250, + 240, + 60, + 92, + 137, + 242, + 93, + 114, + 7, + 253, + 46, + 205, + 206, + 161, + 8, + 35, + 192, + 78, + 215, + 30, + 248, + 210, + 231, + 28, + 0, + 227, + 16, + 102, + 171, + 33, + 176, + 130, + 141, + 118, + 200, + 28, + 17, + 79, + 2, + 102, + 90, + 17, + 199, + 167, + 36, + 183, + 20, + 51, + 99, + 229, + 224, + 82, + 167, + 191, + 242, + 221, + 218, + 60, + 46, + 124, + 196, + 120, + 87, + 23, + 98, + 216, + 188, + 151, + 128, + 245, + 145, + 151, + 28, + 91, + 115, + 92, + 197, + 224, + 56, + 47, + 65, + 114, + 145, + 113, + 230, + 249, + 213, + 229, + 159, + 130, + 119, + 242, + 92, + 11, + 219, + 12, + 36, + 133, + 143, + 182, + 227, + 131, + 226, + 111, + 169, + 197, + 183, + 192, + 164, + 152, + 83, + 243, + 164, + 52, + 26, + 87, + 215, + 162, + 129, + 83, + 141, + 34, + 102, + 105, + 180, + 174, + 175, + 0, + 231, + 84, + 21, + 238, + 245, + 204, + 169, + 230, + 253, + 0, + 206, + 75, + 63, + 227, + 220, + 51, + 63, + 157, + 68, + 2, + 206, + 127, + 72, + 11, + 79, + 34, + 52, + 200, + 28, + 86, + 212, + 158, + 241, + 107, + 139, + 171, + 2, + 169, + 203, + 148, + 140, + 230, + 84, + 210, + 42, + 185, + 41, + 171, + 201, + 213, + 202, + 15, + 229, + 44, + 182, + 48, + 10, + 210, + 17, + 172, + 217, + 27, + 74, + 56, + 113, + 56, + 81, + 73, + 114, + 168, + 101, + 82, + 15, + 189, + 125, + 125, + 58, + 157, + 216, + 72, + 62, + 61, + 35, + 113, + 100, + 131, + 91, + 22, + 23, + 234, + 101, + 49, + 232, + 29, + 114, + 89, + 137, + 27, + 72, + 106, + 219, + 15, + 205, + 34, + 224, + 118, + 96, + 245, + 26, + 120, + 221, + 29, + 244, + 181, + 104, + 87, + 181, + 24, + 61, + 103, + 8, + 183, + 110, + 87, + 104, + 23, + 226, + 78, + 22, + 87, + 46, + 111, + 249, + 212, + 228, + 82, + 104, + 0, + 145, + 33, + 125, + 63, + 173, + 236, + 141, + 248, + 80, + 100, + 17, + 235, + 47, + 181, + 233, + 10, + 93, + 148, + 108, + 12, + 120, + 68, + 236, + 57, + 251, + 23, + 229, + 126, + 187, + 79, + 30, + 251, + 152, + 105, + 123, + 234, + 18, + 221, + 149, + 184, + 139, + 12, + 75, + 99, + 229, + 157, + 242, + 194, + 193, + 99, + 242, + 2, + 132, + 186, + 70, + 24, + 190, + 55, + 232, + 164, + 150, + 31, + 204, + 186, + 201, + 214, + 182, + 31, + 245, + 99, + 60, + 224, + 7, + 31, + 128, + 21, + 198, + 236, + 9, + 228, + 43, + 178, + 144, + 49, + 244, + 189, + 129, + 87, + 152, + 150, + 176, + 142, + 100, + 35, + 81, + 113, + 112, + 104, + 96, + 47, + 181, + 138, + 139, + 8, + 26, + 99, + 207, + 224, + 240, + 197, + 68, + 179, + 172, + 57, + 23, + 124, + 26, + 246, + 182, + 136, + 129, + 53, + 42, + 164, + 84, + 138, + 227, + 63, + 160, + 151, + 115, + 29, + 166, + 35, + 220, + 53, + 235, + 100, + 10, + 142, + 192, + 133, + 208, + 145, + 214, + 82, + 4, + 166, + 10, + 74, + 14, + 171, + 119, + 112, + 124, + 238, + 108, + 240, + 121, + 16, + 151, + 36, + 33, + 35, + 182, + 54, + 216, + 157, + 59, + 38, + 41, + 184, + 91, + 147, + 94, + 160, + 16, + 156, + 247, + 26, + 122, + 226, + 156, + 92, + 112, + 151, + 111, + 82, + 170, + 190, + 215, + 174, + 184, + 4, + 48, + 8, + 78, + 76, + 37, + 74, + 124, + 3, + 122, + 190, + 10, + 101, + 65, + 198, + 113, + 192, + 42, + 170, + 167, + 185, + 144, + 95, + 2, + 229, + 191, + 152, + 162, + 236, + 21, + 36, + 42, + 60, + 110, + 33, + 170, + 166, + 158, + 202, + 74, + 63, + 13, + 29, + 58, + 217, + 250, + 211, + 55, + 216, + 171, + 99, + 115, + 232, + 38, + 48, + 97, + 203, + 46, + 144, + 197, + 111, + 131, + 153, + 232, + 240, + 51, + 235, + 68, + 155, + 191, + 71, + 243, + 51, + 189, + 252, + 27, + 234, + 140, + 19, + 93, + 116, + 163, + 127, + 199, + 181, + 193, + 43, + 1, + 127, + 141, + 215, + 156, + 1, + 232, + 147, + 159, + 94, + 87, + 230, + 47, + 10, + 45, + 29, + 69, + 104, + 165, + 224, + 190, + 8, + 238, + 27, + 70, + 31, + 159, + 158, + 146, + 95, + 233, + 192, + 2, + 42, + 47, + 247, + 223, + 180, + 141, + 202, + 166, + 219, + 134, + 91, + 145, + 95, + 216, + 218, + 102, + 106, + 17, + 46, + 122, + 14, + 42, + 214, + 14, + 182, + 223, + 164, + 186, + 37, + 107, + 139, + 65, + 108, + 85, + 180, + 116, + 58, + 162, + 188, + 18, + 112, + 112, + 90, + 108, + 79, + 89, + 67, + 175, + 101, + 89, + 59, + 232, + 202, + 123, + 227, + 111, + 134, + 182, + 217, + 28, + 15, + 224, + 50, + 78, + 180, + 90, + 178, + 117, + 31, + 136, + 175, + 251, + 88, + 224, + 41, + 145, + 14, + 135, + 162, + 138, + 46, + 214, + 217, + 170, + 234, + 244, + 240, + 212, + 180, + 79, + 243, + 51, + 27, + 76, + 79, + 28, + 53, + 155, + 144, + 60, + 149, + 1, + 43, + 228, + 134, + 247, + 100, + 29, + 96, + 188, + 182, + 149, + 58, + 188, + 255, + 64, + 157, + 194, + 219, + 157, + 201, + 155, + 202, + 142, + 19, + 208, + 151, + 90, + 159, + 179, + 71, + 197, + 191, + 38, + 204, + 214, + 75, + 28, + 59, + 250, + 156, + 95, + 234, + 134, + 102, + 83, + 211, + 1, + 42, + 98, + 138, + 136, + 128, + 217, + 218, + 78, + 195, + 8, + 174, + 13, + 87, + 194, + 79, + 191, + 148, + 105, + 81, + 148, + 79, + 177, + 194, + 12, + 85, + 15, + 253, + 19, + 48, + 202, + 157, + 82, + 155, + 110, + 13, + 225, + 110, + 147, + 156, + 33, + 80, + 43, + 76, + 203, + 183, + 15, + 52, + 135, + 69, + 38, + 191, + 207, + 196, + 58, + 240, + 202, + 127, + 75, + 21, + 102, + 102, + 154, + 105, + 184, + 228, + 228, + 130, + 185, + 98, + 61, + 212, + 200, + 49, + 135, + 236, + 136, + 148, + 179, + 150, + 18, + 74, + 44, + 58, + 106, + 178, + 13, + 199, + 92, + 178, + 212, + 229, + 191, + 106, + 109, + 203, + 229, + 85, + 233, + 107, + 221, + 241, + 253, + 203, + 178, + 15, + 235, + 161, + 162, + 210, + 224, + 240, + 113, + 180, + 29, + 82, + 227, + 164, + 114, + 64, + 242, + 58, + 197, + 125, + 150, + 86, + 217, + 0, + 59, + 150, + 51, + 212, + 174, + 93, + 212, + 23, + 72, + 102, + 65, + 187, + 105, + 242, + 189, + 82, + 157, + 73, + 225, + 102, + 226, + 91, + 179, + 219, + 104, + 211, + 125, + 213, + 244, + 40, + 19, + 133, + 55, + 228, + 107, + 203, + 237, + 189, + 30, + 37, + 179, + 190, + 160, + 26, + 158, + 219, + 200, + 2, + 194, + 23, + 130, + 225, + 4, + 30, + 106, + 99, + 33, + 115, + 52, + 247, + 194, + 75, + 43, + 16, + 96, + 81, + 191, + 169, + 97, + 66, + 121, + 222, + 189, + 79, + 21, + 234, + 121, + 36, + 95, + 42, + 74, + 201, + 222, + 96, + 96, + 201, + 77, + 169, + 24, + 74, + 8, + 218, + 135, + 113, + 40, + 120, + 30, + 42, + 123, + 162, + 221, + 44, + 26, + 113, + 100, + 158, + 83, + 172, + 42, + 147, + 186, + 245, + 238, + 67, + 197, + 97, + 199, + 193, + 44, + 7, + 250, + 30, + 93, + 102, + 173, + 34, + 69, + 59, + 174, + 100, + 123, + 91, + 185, + 75, + 99, + 63, + 137, + 131, + 79, + 157, + 17, + 91, + 40, + 238, + 106, + 107, + 238, + 29, + 227, + 251, + 79, + 157, + 229, + 7, + 255, + 13, + 161, + 113, + 13, + 251, + 234, + 1, + 117, + 227, + 255, + 216, + 233, + 55, + 135, + 55, + 109, + 251, + 239, + 200, + 200, + 123, + 114, + 175, + 26, + 29, + 55, + 241, + 176, + 120, + 178, + 140, + 240, + 177, + 174, + 79, + 236, + 229, + 79, + 68, + 161, + 155, + 104, + 218, + 248, + 230, + 160, + 97, + 97, + 137, + 169, + 67, + 31, + 249, + 203, + 201, + 71, + 72, + 153, + 174, + 98, + 226, + 29, + 1, + 217, + 22, + 146, + 72, + 41, + 90, + 188, + 149, + 140, + 89, + 41, + 231, + 231, + 78, + 131, + 64, + 224, + 190, + 27, + 142, + 72, + 98, + 225, + 173, + 148, + 70, + 155, + 53, + 23, + 6, + 192, + 146, + 246, + 229, + 145, + 0, + 54, + 220, + 87, + 104, + 86, + 203, + 42, + 219, + 74, + 222, + 223, + 91, + 35, + 0, + 52, + 40, + 123, + 120, + 252, + 47, + 204, + 180, + 241, + 255, + 159, + 74, + 113, + 87, + 143, + 94, + 250, + 29, + 115, + 104, + 26, + 51, + 10, + 55, + 119, + 154, + 26, + 17, + 195, + 187, + 1, + 237, + 242, + 238, + 251, + 48, + 23, + 45, + 77, + 128, + 133, + 69, + 130, + 206, + 147, + 250, + 184, + 91, + 37, + 107, + 113, + 96, + 33, + 113, + 161, + 45, + 77, + 60, + 207, + 90, + 71, + 89, + 173, + 228, + 255, + 56, + 52, + 7, + 231, + 127, + 140, + 107, + 96, + 35, + 207, + 247, + 130, + 58, + 249, + 127, + 205, + 97, + 100, + 127, + 74, + 125, + 97, + 95, + 13, + 76, + 174, + 207, + 179, + 2, + 162, + 243, + 50, + 81, + 115, + 154, + 7, + 90, + 121, + 59, + 218, + 57, + 115, + 32, + 31, + 23, + 75, + 187, + 104, + 78, + 228, + 237, + 68, + 179, + 74, + 42, + 209, + 147, + 233, + 204, + 61, + 56, + 96, + 229, + 82, + 249, + 196, + 35, + 35, + 111, + 110, + 178, + 31, + 94, + 24, + 246, + 131, + 198, + 248, + 107, + 60, + 58, + 110, + 250, + 199, + 138, + 215, + 247, + 211, + 25, + 131, + 176, + 52, + 156, + 32, + 189, + 220, + 192, + 100, + 211, + 126, + 179, + 232, + 4, + 214, + 27, + 195, + 139, + 108, + 92, + 29, + 16, + 208, + 36, + 67, + 32, + 175, + 81, + 225, + 73, + 57, + 200, + 75, + 3, + 1, + 126, + 20, + 100, + 231, + 90, + 234, + 43, + 32, + 122, + 191, + 43, + 188, + 43, + 187, + 112, + 141, + 169, + 155, + 57, + 174, + 97, + 104, + 128, + 45, + 188, + 248, + 84, + 27, + 197, + 218, + 152, + 166, + 233, + 132, + 88, + 67, + 38, + 243, + 111, + 227, + 206, + 37, + 30, + 171, + 32, + 136, + 162, + 141, + 151, + 140, + 179, + 160, + 57, + 12, + 248, + 138, + 214, + 215, + 35, + 54, + 111, + 156, + 130, + 78, + 186, + 9, + 223, + 97, + 251, + 44, + 157, + 195, + 31, + 181, + 165, + 34, + 155, + 3, + 91, + 147, + 174, + 3, + 105, + 189, + 28, + 111, + 55, + 96, + 120, + 13, + 47, + 80, + 205, + 166, + 171, + 119, + 239, + 53, + 147, + 142, + 33, + 97, + 192, + 21, + 227, + 122, + 228, + 73, + 1, + 34, + 201, + 192, + 50, + 0, + 144, + 183, + 72, + 163, + 142, + 37, + 240, + 70, + 26, + 115, + 182, + 120, + 150, + 183, + 73, + 179, + 167, + 2, + 148, + 234, + 20, + 157, + 111, + 210, + 110, + 198, + 171, + 235, + 77, + 178, + 183, + 86, + 40, + 99, + 3, + 106, + 152, + 242, + 170, + 168, + 217, + 134, + 250, + 219, + 104, + 55, + 128, + 89, + 162, + 235, + 16, + 138, + 223, + 238, + 208, + 144, + 152, + 62, + 109, + 42, + 242, + 119, + 221, + 249, + 214, + 88, + 64, + 19, + 23, + 130, + 41, + 255, + 232, + 46, + 143, + 96, + 27, + 106, + 50, + 53, + 221, + 4, + 246, + 38, + 48, + 251, + 217, + 117, + 205, + 72, + 167, + 47, + 59, + 99, + 199, + 224, + 16, + 244, + 71, + 224, + 85, + 81, + 79, + 120, + 122, + 86, + 64, + 179, + 56, + 158, + 85, + 164, + 236, + 89, + 250, + 103, + 167, + 6, + 239, + 187, + 78, + 218, + 196, + 59, + 155, + 76, + 44, + 145, + 192, + 131, + 21, + 142, + 24, + 26, + 149, + 220, + 67, + 16, + 60, + 215, + 162, + 59, + 160, + 210, + 73, + 25, + 200, + 96, + 112, + 104, + 0, + 32, + 228, + 83, + 57, + 4, + 30, + 241, + 80, + 130, + 110, + 117, + 110, + 219, + 79, + 135, + 101, + 59, + 235, + 88, + 154, + 105, + 111, + 30, + 228, + 159, + 231, + 52, + 194, + 51, + 25, + 135, + 116, + 209, + 51, + 50, + 234, + 172, + 177, + 179, + 192, + 132, + 200, + 8, + 19, + 32, + 234, + 209, + 176, + 196, + 65, + 241, + 211, + 4, + 0, + 28, + 61, + 226, + 163, + 128, + 20, + 93, + 128, + 170, + 211, + 70, + 87, + 117, + 246, + 15, + 116, + 183, + 150, + 65, + 19, + 35, + 16, + 223, + 238, + 117, + 248, + 45, + 129, + 75, + 62, + 146, + 82, + 179, + 218, + 0, + 30, + 171, + 16, + 190, + 164, + 128, + 48, + 168, + 62, + 27, + 80, + 104, + 106, + 40, + 251, + 150, + 19, + 98, + 25, + 46, + 192, + 135, + 234, + 247, + 229, + 100, + 137, + 157, + 192, + 64, + 251, + 72, + 38, + 100, + 62, + 182, + 206, + 84, + 37, + 174, + 114, + 138, + 45, + 70, + 59, + 123, + 190, + 221, + 207, + 235, + 57, + 127, + 75, + 179, + 245, + 166, + 200, + 44, + 236, + 69, + 198, + 41, + 17, + 120, + 216, + 113, + 150, + 5, + 187, + 58, + 36, + 40, + 34, + 36, + 149, + 254, + 100, + 62, + 163, + 30, + 113, + 131, + 90, + 229, + 126, + 36, + 115, + 72, + 74, + 241, + 200, + 80, + 166, + 144, + 178, + 90, + 105, + 6, + 221, + 63, + 38, + 88, + 22, + 67, + 179, + 12, + 9, + 214, + 143, + 215, + 117, + 3, + 89, + 144, + 13, + 51, + 52, + 41, + 23, + 179, + 202, + 242, + 213, + 56, + 174, + 255, + 47, + 31, + 173, + 168, + 4, + 38, + 86, + 158, + 189, + 58, + 202, + 203, + 203, + 162, + 209, + 184, + 127, + 21, + 54, + 67, + 35, + 222, + 42, + 196, + 22, + 105, + 138, + 105, + 47, + 146, + 131, + 245, + 240, + 17, + 24, + 167, + 12, + 1, + 147, + 203, + 33, + 156, + 173, + 219, + 1, + 236, + 159, + 242, + 220, + 51, + 161, + 93, + 109, + 236, + 105, + 96, + 3, + 115, + 31, + 26, + 185, + 75, + 80, + 85, + 109, + 171, + 2, + 166, + 0, + 221, + 148, + 90, + 154, + 146, + 6, + 105, + 206, + 39, + 71, + 197, + 154, + 108, + 152, + 34, + 19, + 143, + 200, + 165, + 163, + 7, + 127, + 239, + 130, + 200, + 16, + 182, + 74, + 199, + 185, + 42, + 27, + 87, + 220, + 44, + 150, + 16, + 5, + 234, + 41, + 1, + 168, + 45, + 220, + 91, + 101, + 237, + 34, + 4, + 116, + 49, + 245, + 43, + 53, + 140, + 29, + 56, + 193, + 202, + 57, + 191, + 211, + 65, + 237, + 98, + 168, + 7, + 229, + 96, + 129, + 144, + 15, + 190, + 218, + 218, + 162, + 27, + 135, + 34, + 55, + 6, + 86, + 106, + 22, + 119, + 239, + 184, + 236, + 251, + 167, + 106, + 84, + 113, + 238, + 156, + 222, + 105, + 180, + 246, + 128, + 255, + 200, + 34, + 204, + 252, + 213, + 42, + 182, + 127, + 46, + 226, + 85, + 68, + 86, + 50, + 131, + 9, + 211, + 247, + 125, + 241, + 201, + 1, + 218, + 115, + 143, + 61, + 156, + 159, + 138, + 205, + 2, + 2, + 200, + 158, + 212, + 52, + 182, + 67, + 174, + 77, + 50, + 152, + 94, + 222, + 106, + 7, + 86, + 183, + 233, + 39, + 118, + 188, + 166, + 226, + 165, + 2, + 215, + 164, + 3, + 132, + 40, + 53, + 152, + 122, + 189, + 247, + 170, + 134, + 103, + 57, + 118, + 82, + 231, + 36, + 114, + 93, + 93, + 17, + 131, + 93, + 75, + 193, + 87, + 164, + 233, + 82, + 222, + 242, + 99, + 101, + 65, + 125, + 245, + 154, + 84, + 99, + 19, + 17, + 214, + 103, + 173, + 64, + 3, + 242, + 53, + 127, + 63, + 225, + 180, + 193, + 82, + 185, + 156, + 21, + 213, + 41, + 37, + 106, + 116, + 105, + 141, + 136, + 161, + 75, + 187, + 25, + 122, + 154, + 23, + 172, + 85, + 221, + 22, + 156, + 215, + 99, + 90, + 89, + 16, + 85, + 146, + 16, + 200, + 49, + 46, + 140, + 202, + 86, + 215, + 83, + 71, + 183, + 41, + 76, + 51, + 28, + 102, + 173, + 106, + 63, + 9, + 232, + 213, + 239, + 181, + 241, + 167, + 93, + 23, + 56, + 50, + 217, + 181, + 205, + 82, + 37, + 145, + 187, + 167, + 85, + 2, + 153, + 13, + 178, + 5, + 104, + 41, + 219, + 60, + 177, + 163, + 9, + 241, + 78, + 88, + 61, + 29, + 129, + 187, + 36, + 18, + 9, + 12, + 253, + 56, + 114, + 210, + 71, + 9, + 24, + 13, + 200, + 165, + 72, + 44, + 222, + 173, + 148, + 159, + 70, + 76, + 109, + 99, + 233, + 139, + 91, + 119, + 110, + 60, + 47, + 130, + 164, + 162, + 36, + 0, + 155, + 175, + 107, + 251, + 242, + 105, + 170, + 111, + 225, + 24, + 126, + 80, + 88, + 162, + 166, + 46, + 17, + 130, + 192, + 191, + 130, + 248, + 184, + 11, + 242, + 13, + 66, + 197, + 112, + 114, + 251, + 62, + 111, + 112, + 154, + 185, + 214, + 173, + 134, + 197, + 205, + 236, + 192, + 243, + 122, + 185, + 218, + 3, + 149, + 18, + 113, + 43, + 10, + 58, + 239, + 84, + 75, + 52, + 110, + 124, + 149, + 50, + 172, + 21, + 13, + 146, + 146, + 18, + 81, + 185, + 41, + 48, + 63, + 208, + 233, + 194, + 141, + 158, + 90, + 162, + 201, + 55, + 10, + 146, + 235, + 236, + 162, + 76, + 91, + 99, + 236, + 169, + 11, + 78, + 112, + 94, + 23, + 10, + 14, + 102, + 35, + 138, + 39, + 62, + 54, + 139, + 202, + 225, + 168, + 30, + 106, + 119, + 191, + 144, + 134, + 181, + 137, + 139, + 139, + 157, + 16, + 124, + 67, + 180, + 167, + 108, + 108, + 68, + 68, + 104, + 15, + 53, + 68, + 92, + 96, + 48, + 106, + 75, + 209, + 23, + 222, + 120, + 231, + 129, + 151, + 86, + 20, + 119, + 14, + 98, + 13, + 234, + 127, + 159, + 160, + 255, + 74, + 116, + 246, + 18, + 137, + 84, + 36, + 5, + 167, + 163, + 100, + 113, + 83, + 33, + 24, + 73, + 77, + 248, + 51, + 195, + 243, + 152, + 177, + 202, + 91, + 94, + 249, + 111, + 171, + 21, + 143, + 56, + 114, + 255, + 197, + 1, + 128, + 7, + 78, + 6, + 102, + 167, + 98, + 81, + 205, + 59, + 37, + 243, + 126, + 201, + 219, + 47, + 78, + 10, + 220, + 83, + 147, + 244, + 89, + 186, + 160, + 236, + 101, + 90, + 188, + 3, + 11, + 5, + 86, + 160, + 197, + 250, + 141, + 163, + 142, + 201, + 145, + 248, + 96, + 25, + 164, + 9, + 129, + 129, + 234, + 123, + 112, + 253, + 163, + 233, + 156, + 97, + 122, + 218, + 166, + 248, + 93, + 26, + 237, + 87, + 18, + 253, + 245, + 222, + 129, + 221, + 140, + 239, + 139, + 209, + 89, + 82, + 215, + 0, + 100, + 73, + 234, + 214, + 199, + 212, + 119, + 117, + 119, + 56, + 68, + 156, + 176, + 129, + 212, + 174, + 140, + 77, + 79, + 83, + 206, + 108, + 64, + 47, + 33, + 137, + 255, + 230, + 42, + 108, + 97, + 190, + 174, + 83, + 195, + 7, + 116, + 139, + 74, + 254, + 56, + 22, + 252, + 133, + 17, + 252, + 101, + 255, + 123, + 15, + 243, + 193, + 4, + 171, + 22, + 36, + 143, + 109, + 27, + 119, + 55, + 94, + 51, + 244, + 34, + 119, + 239, + 39, + 90, + 171, + 127, + 10, + 129, + 137, + 226, + 165, + 50, + 98, + 11, + 194, + 64, + 30, + 239, + 102, + 100, + 83, + 149, + 116, + 29, + 165, + 147, + 83, + 3, + 55, + 115, + 204, + 70, + 111, + 207, + 156, + 88, + 102, + 81, + 7, + 1, + 6, + 5, + 252, + 146, + 219, + 70, + 182, + 54, + 111, + 123, + 210, + 204, + 153, + 180, + 184, + 137, + 179, + 57, + 118, + 188, + 145, + 190, + 86, + 95, + 217, + 85, + 154, + 133, + 115, + 39, + 162, + 52, + 108, + 171, + 29, + 77, + 84, + 238, + 80, + 241, + 41, + 255, + 23, + 231, + 104, + 25, + 243, + 240, + 47, + 36, + 211, + 25, + 187, + 18, + 208, + 59, + 218, + 183, + 110, + 226, + 126, + 184, + 80, + 88, + 233, + 56, + 69, + 76, + 109, + 128, + 192, + 14, + 101, + 76, + 114, + 36, + 129, + 239, + 242, + 52, + 216, + 233, + 23, + 157, + 217, + 162, + 132, + 126, + 31, + 2, + 48, + 187, + 122, + 133, + 14, + 30, + 195, + 150, + 17, + 227, + 222, + 59, + 19, + 166, + 95, + 253, + 249, + 92, + 82, + 123, + 22, + 247, + 241, + 212, + 121, + 14, + 111, + 157, + 72, + 49, + 244, + 55, + 57, + 206, + 98, + 93, + 121, + 233, + 212, + 2, + 117, + 143, + 230, + 239, + 255, + 193, + 74, + 106, + 205, + 179, + 133, + 82, + 215, + 145, + 92, + 249, + 140, + 77, + 7, + 50, + 24, + 197, + 40, + 156, + 34, + 102, + 214, + 250, + 43, + 13, + 41, + 141, + 212, + 213, + 8, + 26, + 211, + 9, + 69, + 160, + 42, + 78, + 73, + 100, + 158, + 15, + 114, + 0, + 60, + 250, + 118, + 115, + 229, + 35, + 158, + 93, + 173, + 14, + 127, + 1, + 210, + 56, + 223, + 55, + 108, + 214, + 206, + 166, + 157, + 183, + 3, + 128, + 221, + 128, + 98, + 178, + 187, + 186, + 142, + 84, + 102, + 237, + 10, + 123, + 98, + 74, + 133, + 111, + 196, + 242, + 102, + 153, + 189, + 110, + 13, + 151, + 158, + 121, + 170, + 40, + 243, + 227, + 86, + 11, + 194, + 53, + 87, + 98, + 2, + 14, + 153, + 201, + 229, + 113, + 160, + 91, + 120, + 40, + 84, + 116, + 141, + 174, + 61, + 25, + 250, + 177, + 120, + 161, + 120, + 240, + 105, + 225, + 21, + 236, + 62, + 207, + 243, + 59, + 89, + 34, + 167, + 85, + 238, + 236, + 114, + 216, + 61, + 160, + 123, + 95, + 11, + 142, + 21, + 130, + 170, + 57, + 217, + 255, + 148, + 59, + 156, + 212, + 67, + 251, + 233, + 18, + 86, + 108, + 15, + 54, + 186, + 104, + 62, + 144, + 235, + 141, + 207, + 27, + 63, + 68, + 163, + 144, + 59, + 45, + 65, + 196, + 169, + 84, + 195, + 113, + 16, + 79, + 196, + 81, + 49, + 209, + 92, + 156, + 68, + 239, + 212, + 10, + 152, + 226, + 216, + 253, + 159, + 138, + 130, + 134, + 101, + 86, + 97, + 179, + 220, + 4, + 205, + 21, + 153, + 162, + 244, + 162, + 176, + 68, + 41, + 231, + 130, + 28, + 249, + 200, + 97, + 4, + 113, + 70, + 229, + 219, + 101, + 108, + 111, + 8, + 7, + 159, + 15, + 73, + 42, + 165, + 107, + 45, + 134, + 163, + 28, + 84, + 199, + 44, + 9, + 76, + 27, + 87, + 108, + 10, + 0, + 68, + 63, + 13, + 235, + 88, + 121, + 248, + 168, + 194, + 200, + 204, + 242, + 51, + 230, + 160, + 9, + 122, + 111, + 11, + 242, + 216, + 149, + 229, + 24, + 4, + 100, + 135, + 169, + 70, + 108, + 192, + 105, + 19, + 76, + 118, + 40, + 57, + 182, + 58, + 45, + 155, + 126, + 109, + 221, + 189, + 115, + 105, + 122, + 197, + 20, + 135, + 134, + 44, + 27, + 93, + 133, + 87, + 186, + 199, + 80, + 222, + 67, + 171, + 180, + 111, + 106, + 142, + 17, + 154, + 155, + 211, + 139, + 21, + 213, + 23, + 153, + 120, + 152, + 134, + 166, + 121, + 121, + 22, + 13, + 83, + 131, + 48, + 232, + 44, + 230, + 159, + 103, + 140, + 165, + 108, + 187, + 87, + 28, + 52, + 25, + 196, + 6, + 142, + 92, + 179, + 30, + 29, + 228, + 111, + 245, + 240, + 174, + 100, + 106, + 180, + 12, + 203, + 208, + 24, + 51, + 188, + 138, + 196, + 117, + 250, + 79, + 191, + 96, + 198, + 92, + 163, + 188, + 254, + 185, + 69, + 36, + 104, + 110, + 176, + 171, + 41, + 192, + 119, + 15, + 163, + 156, + 174, + 111, + 252, + 214, + 227, + 32, + 155, + 229, + 19, + 228, + 147, + 247, + 52, + 57, + 12, + 111, + 93, + 186, + 161, + 7, + 66, + 82, + 103, + 4, + 197, + 197, + 138, + 212, + 138, + 200, + 185, + 114, + 108, + 230, + 136, + 116, + 27, + 87, + 128, + 162, + 172, + 225, + 52, + 82, + 233, + 173, + 142, + 91, + 243, + 155, + 88, + 72, + 219, + 168, + 212, + 161, + 83, + 98, + 1, + 244, + 128, + 59, + 64, + 128, + 80, + 12, + 3, + 147, + 196, + 138, + 50, + 240, + 23, + 93, + 158, + 156, + 173, + 33, + 25, + 17, + 234, + 20, + 57, + 56, + 73, + 74, + 68, + 6, + 2, + 156, + 155, + 103, + 80, + 64, + 43, + 67, + 39, + 196, + 123, + 45, + 226, + 234, + 92, + 34, + 44, + 67, + 217, + 159, + 239, + 203, + 177, + 46, + 148, + 88, + 98, + 123, + 32, + 128, + 113, + 100, + 137, + 36, + 215, + 91, + 250, + 75, + 155, + 102, + 29, + 124, + 173, + 157, + 230, + 127, + 34, + 165, + 120, + 211, + 121, + 211, + 198, + 27, + 26, + 32, + 157, + 93, + 146, + 54, + 29, + 164, + 83, + 214, + 201, + 231, + 222, + 133, + 194, + 14, + 116, + 10, + 149, + 54, + 158, + 77, + 241, + 192, + 169, + 121, + 57, + 168, + 161, + 43, + 43, + 5, + 63, + 87, + 118, + 224, + 217, + 151, + 165, + 1, + 171, + 27, + 95, + 83, + 162, + 146, + 95, + 246, + 131, + 210, + 39, + 55, + 4, + 58, + 120, + 29, + 159, + 58, + 59, + 99, + 35, + 129, + 105, + 40, + 242, + 19, + 254, + 106, + 221, + 147, + 86, + 214, + 44, + 221, + 191, + 28, + 199, + 6, + 174, + 219, + 29, + 226, + 205, + 219, + 167, + 149, + 119, + 18, + 234, + 70, + 220, + 216, + 207, + 173, + 123, + 195, + 247, + 29, + 18, + 10, + 105, + 135, + 19, + 94, + 132, + 10, + 140, + 240, + 95, + 160, + 73, + 212, + 221, + 243, + 159, + 100, + 174, + 65, + 200, + 57, + 117, + 40, + 47, + 217, + 193, + 242, + 222, + 133, + 25, + 25, + 196, + 201, + 138, + 12, + 119, + 14, + 216, + 36, + 74, + 241, + 2, + 250, + 94, + 165, + 26, + 207, + 194, + 214, + 128, + 157, + 28, + 61, + 203, + 198, + 146, + 148, + 109, + 50, + 78, + 234, + 60, + 61, + 219, + 237, + 146, + 239, + 85, + 137, + 195, + 65, + 102, + 185, + 96, + 120, + 244, + 143, + 4, + 215, + 56, + 244, + 108, + 254, + 60, + 79, + 125, + 58, + 246, + 11, + 171, + 155, + 230, + 156, + 220, + 97, + 84, + 104, + 254, + 113, + 239, + 24, + 105, + 109, + 219, + 88, + 53, + 226, + 164, + 25, + 84, + 143, + 58, + 231, + 99, + 42, + 215, + 251, + 218, + 191, + 33, + 237, + 180, + 140, + 170, + 137, + 115, + 38, + 38, + 84, + 28, + 33, + 129, + 89, + 232, + 41, + 107, + 32, + 134, + 201, + 223, + 120, + 140, + 18, + 137, + 82, + 218, + 40, + 75, + 24, + 56, + 133, + 63, + 152, + 96, + 248, + 81, + 12, + 244, + 41, + 63, + 130, + 1, + 70, + 116, + 76, + 107, + 254, + 58, + 66, + 17, + 66, + 168, + 236, + 147, + 229, + 80, + 83, + 118, + 176, + 102, + 229, + 245, + 253, + 18, + 98, + 106, + 145, + 240, + 59, + 86, + 31, + 141, + 98, + 244, + 236, + 221, + 70, + 157, + 132, + 74, + 202, + 11, + 211, + 245, + 109, + 212, + 204, + 102, + 213, + 194, + 172, + 68, + 61, + 196, + 110, + 24, + 74, + 52, + 209, + 105, + 148, + 177, + 49, + 134, + 101, + 31, + 100, + 83, + 92, + 165, + 239, + 148, + 66, + 146, + 94, + 145, + 3, + 64, + 44, + 27, + 181, + 194, + 132, + 89, + 58, + 39, + 109, + 60, + 48, + 100, + 107, + 127, + 130, + 46, + 6, + 35, + 236, + 249, + 178, + 191, + 209, + 251, + 242, + 60, + 236, + 202, + 235, + 99, + 144, + 118, + 243, + 104, + 144, + 163, + 149, + 28, + 134, + 64, + 75, + 58, + 46, + 249, + 80, + 218, + 124, + 230, + 63, + 204, + 119, + 34, + 137, + 37, + 184, + 172, + 18, + 25, + 19, + 210, + 80, + 33, + 47, + 3, + 60, + 253, + 42, + 68, + 212, + 12, + 168, + 57, + 54, + 39, + 120, + 73, + 142, + 21, + 73, + 5, + 78, + 52, + 55, + 71, + 101, + 215, + 243, + 163, + 38, + 62, + 239, + 11, + 55, + 53, + 178, + 92, + 64, + 148, + 20, + 234, + 144, + 19, + 241, + 237, + 134, + 62, + 16, + 176, + 110, + 219, + 59, + 64, + 67, + 249, + 116, + 207, + 30, + 187, + 143, + 135, + 193, + 84, + 230, + 19, + 47, + 26, + 254, + 30, + 146, + 64, + 171, + 162, + 151, + 246, + 117, + 199, + 255, + 138, + 247, + 194, + 92, + 26, + 37, + 135, + 76, + 148, + 57, + 113, + 129, + 47, + 192, + 132, + 248, + 26, + 63, + 98, + 54, + 137, + 157, + 122, + 139, + 52, + 106, + 165, + 32, + 105, + 202, + 70, + 160, + 53, + 135, + 18, + 31, + 186, + 1, + 35, + 67, + 29, + 240, + 176, + 61, + 138, + 8, + 89, + 65, + 9, + 223, + 68, + 73, + 245, + 127, + 149, + 173, + 141, + 124, + 105, + 95, + 209, + 13, + 109, + 106, + 179, + 83, + 255, + 192, + 65, + 55, + 133, + 110, + 91, + 108, + 56, + 138, + 137, + 12, + 111, + 140, + 84, + 227, + 84, + 183, + 190, + 94, + 134, + 3, + 228, + 187, + 88, + 165, + 22, + 41, + 48, + 82, + 84, + 206, + 55, + 221, + 144, + 141, + 166, + 104, + 188, + 157, + 248, + 142, + 153, + 179, + 3, + 66, + 34, + 146, + 8, + 229, + 42, + 8, + 39, + 158, + 156, + 101, + 218, + 163, + 161, + 79, + 120, + 127, + 201, + 156, + 157, + 82, + 31, + 101, + 74, + 20, + 72, + 57, + 36, + 113, + 140, + 22, + 162, + 161, + 0, + 247, + 41, + 6, + 113, + 207, + 134, + 203, + 40, + 54, + 196, + 55, + 227, + 145, + 94, + 118, + 120, + 59, + 85, + 188, + 40, + 142, + 0, + 1, + 21, + 22, + 234, + 167, + 213, + 152, + 62, + 46, + 198, + 64, + 185, + 208, + 137, + 42, + 143, + 223, + 62, + 144, + 160, + 81, + 56, + 247, + 130, + 105, + 207, + 67, + 186, + 45, + 88, + 223, + 148, + 20, + 13, + 10, + 45, + 236, + 32, + 33, + 235, + 243, + 177, + 71, + 144, + 45, + 39, + 78, + 133, + 88, + 1, + 112, + 87, + 126, + 25, + 96, + 53, + 35, + 247, + 223, + 163, + 231, + 175, + 94, + 65, + 36, + 123, + 25, + 204, + 3, + 159, + 129, + 23, + 19, + 149, + 87, + 154, + 197, + 5, + 38, + 6, + 75, + 11, + 80, + 204, + 23, + 152, + 23, + 38, + 174, + 39, + 74, + 214, + 204, + 253, + 17, + 218, + 84, + 184, + 6, + 52, + 45, + 172, + 143, + 206, + 82, + 116, + 83, + 139, + 186, + 219, + 121, + 52, + 50, + 63, + 35, + 89, + 30, + 159, + 199, + 64, + 133, + 244, + 72, + 98, + 170, + 233, + 4, + 210, + 85, + 236, + 122, + 194, + 18, + 190, + 51, + 47, + 127, + 239, + 237, + 198, + 119, + 223, + 100, + 141, + 161, + 153, + 107, + 209, + 18, + 92, + 209, + 74, + 199, + 172, + 213, + 47, + 180, + 217, + 123, + 117, + 3, + 175, + 117, + 119, + 9, + 108, + 109, + 138, + 15, + 101, + 172, + 104, + 243, + 21, + 230, + 146, + 27, + 248, + 254, + 115, + 92, + 97, + 235, + 189, + 119, + 94, + 201, + 199, + 246, + 224, + 111, + 65, + 97, + 212, + 57, + 237, + 4, + 158, + 41, + 159, + 221, + 169, + 172, + 224, + 9, + 159, + 41, + 197, + 162, + 251, + 183, + 183, + 65, + 14, + 139, + 160, + 146, + 212, + 216, + 95, + 212, + 52, + 94, + 125, + 85, + 1, + 190, + 108, + 88, + 250, + 190, + 100, + 56, + 156, + 166, + 56, + 9, + 240, + 211, + 138, + 166, + 219, + 102, + 220, + 173, + 133, + 182, + 98, + 31, + 136, + 35, + 240, + 108, + 3, + 143, + 98, + 12, + 163, + 43, + 117, + 44, + 187, + 21, + 160, + 190, + 222, + 3, + 120, + 204, + 233, + 96, + 162, + 44, + 0, + 101, + 19, + 209, + 115, + 122, + 101, + 143, + 85, + 142, + 8, + 214, + 12, + 32, + 83, + 55, + 76, + 246, + 188, + 166, + 55, + 121, + 6, + 164, + 208, + 164, + 233, + 209, + 14, + 35, + 119, + 25, + 170, + 98, + 102, + 205, + 127, + 13, + 22, + 185, + 132, + 104, + 215, + 187, + 56, + 18, + 52, + 106, + 199, + 37, + 123, + 120, + 206, + 215, + 146, + 49, + 246, + 113, + 86, + 237, + 240, + 107, + 197, + 71, + 43, + 58, + 128, + 134, + 205, + 213, + 200, + 104, + 45, + 156, + 22, + 182, + 94, + 181, + 217, + 101, + 23, + 116, + 18, + 31, + 62, + 130, + 57, + 129, + 31, + 98, + 115, + 207, + 189, + 2, + 57, + 248, + 230, + 48, + 59, + 15, + 66, + 163, + 11, + 163, + 94, + 56, + 219, + 94, + 119, + 130, + 143, + 48, + 146, + 202, + 149, + 194, + 153, + 250, + 132, + 115, + 184, + 208, + 134, + 40, + 182, + 88, + 104, + 19, + 136, + 241, + 152, + 190, + 232, + 245, + 74, + 47, + 154, + 156, + 109, + 214, + 189, + 98, + 193, + 27, + 30, + 16, + 122, + 66, + 153, + 155, + 48, + 100, + 209, + 197, + 210, + 29, + 202, + 35, + 19, + 91, + 30, + 9, + 25, + 160, + 4, + 19, + 154, + 179, + 219, + 35, + 114, + 43, + 202, + 52, + 164, + 104, + 210, + 230, + 77, + 189, + 85, + 115, + 170, + 230, + 138, + 193, + 8, + 184, + 234, + 81, + 20, + 233, + 71, + 12, + 95, + 113, + 196, + 201, + 38, + 90, + 36, + 34, + 78, + 208, + 156, + 5, + 45, + 67, + 116, + 13, + 55, + 44, + 62, + 41, + 171, + 91, + 120, + 23, + 213, + 30, + 233, + 98, + 13, + 110, + 209, + 26, + 110, + 32, + 77, + 105, + 178, + 240, + 251, + 117, + 149, + 12, + 224, + 189, + 18, + 101, + 241, + 245, + 139, + 153, + 65, + 144, + 77, + 169, + 98, + 46, + 166, + 48, + 233, + 22, + 1, + 140, + 126, + 167, + 16, + 205, + 102, + 49, + 149, + 86, + 168, + 170, + 44, + 196, + 176, + 7, + 246, + 54, + 56, + 228, + 33, + 24, + 252, + 172, + 72, + 62, + 250, + 188, + 128, + 23, + 148, + 186, + 159, + 211, + 170, + 88, + 51, + 184, + 162, + 137, + 193, + 6, + 100, + 177, + 25, + 32, + 82, + 160, + 102, + 81, + 218, + 227, + 248, + 77, + 113, + 211, + 151, + 108, + 82, + 84, + 89, + 245, + 47, + 29, + 96, + 238, + 40, + 223, + 29, + 201, + 132, + 246, + 43, + 164, + 251, + 136, + 39, + 114, + 243, + 151, + 56, + 24, + 236, + 121, + 134, + 171, + 99, + 206, + 21, + 92, + 173, + 36, + 142, + 172, + 4, + 89, + 74, + 197, + 125, + 253, + 16, + 5, + 248, + 10, + 172, + 67, + 145, + 144, + 234, + 108, + 188, + 219, + 218, + 28, + 14, + 122, + 246, + 238, + 74, + 58, + 191, + 120, + 114, + 53, + 23, + 160, + 253, + 86, + 222, + 23, + 89, + 91, + 119, + 0, + 29, + 245, + 135, + 37, + 135, + 186, + 78, + 124, + 165, + 216, + 198, + 99, + 98, + 225, + 164, + 93, + 15, + 95, + 101, + 220, + 139, + 62, + 132, + 80, + 17, + 193, + 165, + 74, + 244, + 204, + 6, + 32, + 233, + 231, + 106, + 113, + 206, + 39, + 185, + 108, + 179, + 162, + 125, + 70, + 155, + 13, + 218, + 124, + 7, + 213, + 128, + 114, + 87, + 75, + 1, + 86, + 61, + 138, + 230, + 210, + 16, + 172, + 178, + 205, + 6, + 27, + 161, + 55, + 77, + 211, + 223, + 223, + 187, + 6, + 160, + 22, + 92, + 194, + 144, + 39, + 228, + 104, + 31, + 211, + 236, + 205, + 82, + 35, + 230, + 117, + 24, + 76, + 14, + 208, + 112, + 5, + 213, + 35, + 123, + 115, + 18, + 250, + 174, + 99, + 62, + 230, + 2, + 59, + 193, + 195, + 32, + 49, + 120, + 144, + 204, + 183, + 116, + 22, + 255, + 80, + 142, + 73, + 198, + 244, + 18, + 27, + 217, + 95, + 27, + 61, + 115, + 67, + 167, + 9, + 252, + 166, + 197, + 164, + 116, + 48, + 52, + 202, + 53, + 45, + 28, + 247, + 181, + 161, + 8, + 43, + 108, + 16, + 19, + 222, + 47, + 225, + 36, + 57, + 222, + 112, + 213, + 237, + 91, + 163, + 236, + 187, + 46, + 250, + 228, + 74, + 27, + 98, + 173, + 106, + 21, + 251, + 107, + 214, + 149, + 118, + 127, + 211, + 36, + 252, + 5, + 27, + 90, + 6, + 67, + 28, + 215, + 100, + 25, + 16, + 102, + 21, + 239, + 190, + 225, + 96, + 64, + 37, + 219, + 51, + 215, + 175, + 37, + 234, + 147, + 211, + 148, + 69, + 146, + 252, + 47, + 51, + 152, + 240, + 251, + 169, + 78, + 29, + 159, + 145, + 36, + 176, + 221, + 231, + 209, + 2, + 99, + 33, + 205, + 101, + 222, + 110, + 51, + 102, + 81, + 92, + 54, + 219, + 108, + 232, + 72, + 141, + 221, + 151, + 205, + 138, + 192, + 57, + 103, + 15, + 228, + 58, + 28, + 25, + 54, + 66, + 208, + 71, + 81, + 181, + 37, + 51, + 19, + 104, + 157, + 175, + 31, + 53, + 120, + 195, + 101, + 89, + 173, + 183, + 26, + 6, + 7, + 67, + 49, + 199, + 72, + 243, + 187, + 41, + 161, + 160, + 212, + 95, + 141, + 61, + 56, + 181, + 9, + 61, + 109, + 83, + 92, + 245, + 241, + 28, + 21, + 52, + 185, + 134, + 131, + 196, + 122, + 17, + 150, + 18, + 131, + 243, + 171, + 123, + 25, + 134, + 181, + 159, + 234, + 214, + 194, + 164, + 154, + 225, + 173, + 37, + 121, + 83, + 189, + 197, + 45, + 229, + 39, + 243, + 218, + 146, + 68, + 124, + 43, + 253, + 32, + 109, + 202, + 221, + 33, + 251, + 154, + 13, + 22, + 250, + 223, + 85, + 48, + 55, + 134, + 39, + 36, + 57, + 21, + 94, + 174, + 210, + 128, + 252, + 70, + 185, + 211, + 200, + 47, + 122, + 125, + 190, + 123, + 251, + 126, + 208, + 152, + 159, + 94, + 52, + 143, + 208, + 25, + 49, + 72, + 60, + 73, + 5, + 24, + 205, + 209, + 22, + 70, + 68, + 10, + 166, + 149, + 136, + 248, + 179, + 207, + 115, + 212, + 127, + 167, + 27, + 253, + 77, + 103, + 139, + 78, + 7, + 57, + 40, + 92, + 154, + 147, + 35, + 90, + 136, + 164, + 196, + 67, + 113, + 16, + 219, + 40, + 37, + 198, + 187, + 170, + 96, + 50, + 48, + 194, + 142, + 212, + 62, + 3, + 210, + 142, + 73, + 102, + 231, + 55, + 193, + 177, + 126, + 12, + 78, + 0, + 222, + 108, + 15, + 223, + 104, + 64, + 182, + 65, + 224, + 43, + 34, + 46, + 89, + 132, + 172, + 25, + 246, + 102, + 180, + 144, + 248, + 245, + 83, + 150, + 113, + 100, + 156, + 53, + 146, + 111, + 112, + 26, + 103, + 127, + 58, + 208, + 96, + 139, + 254, + 137, + 162, + 249, + 28, + 190, + 220, + 40, + 94, + 135, + 190, + 93, + 225, + 59, + 222, + 238, + 17, + 162, + 92, + 88, + 247, + 183, + 194, + 22, + 213, + 4, + 208, + 117, + 119, + 19, + 86, + 88, + 208, + 213, + 162, + 196, + 78, + 106, + 64, + 176, + 2, + 1, + 212, + 30, + 167, + 173, + 200, + 140, + 4, + 86, + 135, + 171, + 124, + 179, + 74, + 232, + 194, + 182, + 20, + 212, + 86, + 230, + 89, + 212, + 159, + 203, + 16, + 200, + 206, + 77, + 146, + 74, + 172, + 78, + 68, + 87, + 154, + 104, + 217, + 57, + 177, + 135, + 218, + 163, + 49, + 65, + 210, + 42, + 27, + 62, + 101, + 59, + 180, + 207, + 67, + 98, + 184, + 42, + 194, + 63, + 2, + 16, + 127, + 111, + 240, + 203, + 148, + 23, + 136, + 17, + 147, + 91, + 110, + 28, + 142, + 12, + 77, + 48, + 189, + 19, + 12, + 141, + 180, + 196, + 151, + 105, + 27, + 238, + 186, + 135, + 219, + 192, + 126, + 51, + 251, + 160, + 6, + 251, + 135, + 244, + 114, + 88, + 250, + 76, + 75, + 116, + 141, + 20, + 156, + 87, + 98, + 201, + 21, + 154, + 232, + 207, + 133, + 248, + 111, + 67, + 249, + 242, + 152, + 178, + 35, + 213, + 112, + 221, + 21, + 155, + 254, + 92, + 18, + 56, + 106, + 1, + 213, + 162, + 213, + 167, + 172, + 247, + 52, + 85, + 69, + 68, + 27, + 210, + 92, + 239, + 84, + 191, + 85, + 112, + 67, + 202, + 135, + 12, + 129, + 6, + 221, + 14, + 190, + 26, + 99, + 159, + 93, + 104, + 57, + 157, + 95, + 157, + 28, + 105, + 211, + 69, + 36, + 32, + 154, + 35, + 149, + 80, + 56, + 208, + 105, + 224, + 29, + 130, + 166, + 48, + 146, + 101, + 160, + 205, + 244, + 208, + 89, + 68, + 245, + 63, + 48, + 29, + 132, + 236, + 136, + 23, + 28, + 146, + 116, + 45, + 120, + 143, + 112, + 165, + 108, + 198, + 226, + 236, + 104, + 111, + 189, + 62, + 43, + 142, + 77, + 108, + 226, + 183, + 3, + 74, + 189, + 29, + 152, + 66, + 223, + 22, + 129, + 231, + 24, + 62, + 166, + 241, + 69, + 207, + 159, + 75, + 5, + 7, + 126, + 250, + 221, + 161, + 127, + 108, + 162, + 118, + 158, + 29, + 215, + 112, + 185, + 203, + 98, + 217, + 63, + 198, + 133, + 245, + 184, + 188, + 6, + 64, + 44, + 41, + 215, + 128, + 41, + 177, + 22, + 195, + 179, + 203, + 40, + 125, + 205, + 151, + 14, + 136, + 238, + 199, + 77, + 140, + 122, + 194, + 16, + 130, + 167, + 71, + 135, + 62, + 163, + 90, + 18, + 247, + 234, + 252, + 117, + 66, + 14, + 223, + 106, + 175, + 211, + 188, + 97, + 137, + 158, + 233, + 135, + 82, + 24, + 149, + 106, + 243, + 0, + 72, + 184, + 118, + 89, + 200, + 195, + 147, + 123, + 207, + 166, + 193, + 65, + 96, + 6, + 137, + 46, + 186, + 67, + 219, + 46, + 130, + 126, + 181, + 202, + 37, + 10, + 72, + 221, + 220, + 39, + 175, + 236, + 70, + 191, + 249, + 193, + 200, + 215, + 108, + 167, + 188, + 248, + 129, + 149, + 109, + 32, + 143, + 74, + 194, + 33, + 6, + 164, + 142, + 251, + 206, + 170, + 13, + 46, + 248, + 41, + 130, + 191, + 63, + 106, + 36, + 222, + 102, + 11, + 92, + 86, + 176, + 64, + 204, + 247, + 183, + 57, + 123, + 232, + 175, + 19, + 113, + 47, + 14, + 28, + 201, + 162, + 134, + 2, + 79, + 95, + 66, + 251, + 21, + 201, + 82, + 46, + 47, + 227, + 203, + 72, + 107, + 159, + 178, + 216, + 3, + 132, + 157, + 201, + 222, + 174, + 181, + 28, + 118, + 69, + 195, + 58, + 207, + 226, + 9, + 127, + 42, + 96, + 61, + 28, + 239, + 105, + 229, + 97, + 179, + 53, + 203, + 190, + 67, + 36, + 85, + 239, + 59, + 243, + 75, + 131, + 8, + 149, + 96, + 44, + 160, + 1, + 135, + 12, + 240, + 203, + 184, + 107, + 49, + 169, + 56, + 246, + 32, + 116, + 7, + 37, + 135, + 33, + 185, + 99, + 59, + 79, + 122, + 134, + 175, + 132, + 12, + 165, + 31, + 229, + 113, + 48, + 219, + 26, + 156, + 219, + 101, + 112, + 3, + 76, + 38, + 74, + 64, + 158, + 18, + 46, + 51, + 176, + 49, + 16, + 60, + 90, + 207, + 129, + 12, + 41, + 184, + 103, + 243, + 132, + 232, + 172, + 20, + 94, + 8, + 32, + 150, + 80, + 218, + 109, + 51, + 107, + 179, + 0, + 204, + 124, + 245, + 188, + 51, + 246, + 5, + 14, + 147, + 170, + 135, + 100, + 247, + 78, + 73, + 3, + 62, + 146, + 56, + 119, + 175, + 236, + 40, + 88, + 31, + 23, + 251, + 119, + 139, + 94, + 65, + 232, + 132, + 204, + 31, + 194, + 31, + 17, + 223, + 111, + 49, + 243, + 132, + 198, + 212, + 124, + 78, + 95, + 104, + 106, + 158, + 45, + 126, + 208, + 143, + 45, + 55, + 76, + 39, + 74, + 182, + 99, + 56, + 101, + 241, + 104, + 196, + 36, + 143, + 243, + 246, + 150, + 97, + 21, + 58, + 83, + 5, + 131, + 19, + 142, + 6, + 248, + 76, + 68, + 1, + 229, + 255, + 7, + 38, + 113, + 209, + 119, + 179, + 114, + 150, + 252, + 79, + 135, + 29, + 167, + 145, + 232, + 135, + 104, + 68, + 18, + 99, + 149, + 55, + 128, + 165, + 111, + 245, + 35, + 197, + 200, + 223, + 245, + 94, + 65, + 99, + 10, + 73, + 106, + 141, + 42, + 174, + 92, + 195, + 220, + 80, + 0, + 41, + 80, + 85, + 77, + 249, + 17, + 169, + 216, + 166, + 145, + 168, + 136, + 110, + 131, + 73, + 37, + 46, + 61, + 62, + 47, + 152, + 90, + 176, + 135, + 61, + 89, + 170, + 130, + 103, + 221, + 190, + 12, + 242, + 66, + 176, + 222, + 118, + 13, + 226, + 126, + 58, + 60, + 143, + 255, + 202, + 187, + 62, + 87, + 38, + 103, + 232, + 89, + 169, + 177, + 217, + 54, + 197, + 104, + 161, + 155, + 212, + 93, + 221, + 198, + 23, + 46, + 72, + 131, + 194, + 230, + 8, + 210, + 6, + 237, + 14, + 243, + 36, + 156, + 51, + 243, + 93, + 163, + 227, + 48, + 153, + 94, + 207, + 88, + 84, + 43, + 146, + 113, + 162, + 103, + 132, + 233, + 97, + 40, + 33, + 210, + 25, + 126, + 14, + 31, + 152, + 38, + 35, + 41, + 124, + 6, + 33, + 24, + 93, + 95, + 155, + 0, + 161, + 252, + 116, + 145, + 79, + 3, + 4, + 209, + 3, + 88, + 32, + 239, + 171, + 94, + 237, + 110, + 149, + 191, + 9, + 253, + 189, + 59, + 177, + 208, + 197, + 129, + 33, + 0, + 56, + 30, + 157, + 115, + 230, + 202, + 94, + 108, + 150, + 127, + 73, + 45, + 90, + 19, + 26, + 40, + 223, + 213, + 254, + 34, + 50, + 52, + 242, + 55, + 235, + 25, + 236, + 168, + 211, + 33, + 47, + 84, + 244, + 223, + 255, + 43, + 23, + 19, + 251, + 61, + 113, + 101, + 116, + 25, + 178, + 232, + 216, + 105, + 192, + 18, + 14, + 150, + 42, + 74, + 5, + 68, + 9, + 12, + 65, + 98, + 212, + 35, + 21, + 220, + 155, + 3, + 246, + 47, + 164, + 172, + 148, + 110, + 129, + 200, + 141, + 248, + 3, + 223, + 43, + 188, + 9, + 197, + 181, + 237, + 15, + 172, + 50, + 118, + 96, + 79, + 206, + 246, + 215, + 224, + 251, + 19, + 129, + 43, + 159, + 45, + 228, + 14, + 178, + 244, + 153, + 8, + 22, + 183, + 174, + 228, + 1, + 85, + 71, + 41, + 97, + 150, + 61, + 161, + 140, + 202, + 87, + 219, + 123, + 22, + 242, + 235, + 74, + 84, + 108, + 116, + 28, + 100, + 169, + 146, + 22, + 242, + 184, + 89, + 32, + 116, + 88, + 174, + 133, + 147, + 239, + 29, + 107, + 203, + 28, + 221, + 229, + 74, + 181, + 232, + 111, + 35, + 99, + 142, + 1, + 77, + 159, + 81, + 100, + 75, + 138, + 49, + 158, + 51, + 210, + 167, + 113, + 113, + 26, + 103, + 32, + 202, + 37, + 215, + 157, + 91, + 41, + 37, + 128, + 24, + 226, + 168, + 197, + 183, + 15, + 30, + 22, + 183, + 68, + 66, + 169, + 65, + 44, + 141, + 224, + 135, + 95, + 119, + 15, + 98, + 29, + 161, + 35, + 121, + 191, + 28, + 152, + 21, + 13, + 158, + 109, + 240, + 14, + 225, + 175, + 210, + 203, + 235, + 80, + 182, + 205, + 57, + 77, + 5, + 114, + 130, + 6, + 20, + 162, + 177, + 167, + 2, + 59, + 222, + 187, + 32, + 110, + 214, + 110, + 36, + 180, + 247, + 183, + 136, + 36, + 24, + 237, + 214, + 97, + 137, + 51, + 144, + 194, + 67, + 155, + 113, + 244, + 235, + 213, + 146, + 48, + 248, + 102, + 77, + 200, + 159, + 167, + 22, + 136, + 29, + 151, + 166, + 244, + 226, + 203, + 135, + 14, + 146, + 179, + 170, + 100, + 84, + 199, + 65, + 123, + 180, + 182, + 13, + 148, + 234, + 201, + 46, + 162, + 33, + 162, + 245, + 28, + 131, + 201, + 46, + 19, + 66, + 164, + 113, + 118, + 85, + 67, + 78, + 164, + 228, + 254, + 143, + 125, + 226, + 153, + 248, + 174, + 46, + 192, + 85, + 169, + 140, + 1, + 65, + 191, + 88, + 99, + 218, + 46, + 207, + 20, + 221, + 48, + 122, + 191, + 20, + 170, + 55, + 225, + 158, + 229, + 184, + 82, + 208, + 31, + 73, + 81, + 87, + 107, + 48, + 18, + 31, + 72, + 158, + 215, + 170, + 140, + 104, + 235, + 151, + 117, + 39, + 157, + 3, + 163, + 87, + 237, + 108, + 88, + 173, + 7, + 185, + 177, + 70, + 200, + 180, + 57, + 154, + 48, + 161, + 122, + 66, + 232, + 60, + 0, + 151, + 204, + 204, + 96, + 218, + 22, + 64, + 229, + 165, + 43, + 98, + 11, + 101, + 229, + 108, + 243, + 138, + 225, + 16, + 52, + 181, + 244, + 217, + 237, + 185, + 107, + 140, + 140, + 131, + 201, + 37, + 123, + 204, + 240, + 87, + 119, + 91, + 116, + 169, + 239, + 228, + 105, + 161, + 129, + 131, + 9, + 201, + 105, + 196, + 196, + 165, + 56, + 218, + 226, + 182, + 232, + 158, + 43, + 49, + 157, + 192, + 4, + 83, + 54, + 42, + 55, + 27, + 86, + 188, + 174, + 67, + 255, + 165, + 102, + 137, + 208, + 5, + 171, + 215, + 164, + 177, + 245, + 175, + 109, + 203, + 91, + 84, + 228, + 10, + 200, + 105, + 192, + 52, + 219, + 43, + 133, + 96, + 109, + 47, + 40, + 70, + 230, + 104, + 86, + 141, + 37, + 190, + 80, + 217, + 134, + 228, + 50, + 25, + 150, + 4, + 27, + 44, + 194, + 37, + 190, + 170, + 156, + 138, + 107, + 132, + 123, + 115, + 234, + 125, + 173, + 62, + 121, + 194, + 105, + 25, + 10, + 115, + 220, + 58, + 119, + 53, + 223, + 240, + 88, + 228, + 45, + 48, + 70, + 22, + 35, + 133, + 247, + 118, + 222, + 148, + 27, + 13, + 208, + 94, + 0, + 214, + 138, + 7, + 59, + 85, + 232, + 163, + 4, + 234, + 196, + 97, + 143, + 107, + 147, + 103, + 149, + 74, + 45, + 75, + 51, + 229, + 201, + 152, + 239, + 232, + 122, + 103, + 158, + 68, + 216, + 53, + 54, + 54, + 253, + 230, + 13, + 199, + 124, + 174, + 196, + 132, + 230, + 99, + 56, + 59, + 148, + 123, + 169, + 147, + 94, + 38, + 144, + 12, + 121, + 129, + 3, + 18, + 177, + 159, + 50, + 253, + 144, + 83, + 225, + 44, + 232, + 195, + 254, + 195, + 18, + 203, + 93, + 72, + 210, + 32, + 114, + 182, + 242, + 61, + 198, + 115, + 213, + 55, + 74, + 197, + 243, + 60, + 123, + 53, + 122, + 209, + 162, + 202, + 245, + 67, + 26, + 230, + 66, + 135, + 166, + 248, + 101, + 135, + 254, + 88, + 74, + 122, + 209, + 43, + 239, + 36, + 221, + 193, + 162, + 200, + 254, + 25, + 150, + 214, + 162, + 177, + 70, + 40, + 149, + 29, + 98, + 113, + 163, + 99, + 132, + 217, + 54, + 62, + 168, + 178, + 25, + 154, + 142, + 158, + 184, + 163, + 26, + 104, + 0, + 51, + 232, + 42, + 156, + 120, + 254, + 191, + 253, + 208, + 158, + 224, + 129, + 219, + 8, + 56, + 95, + 38, + 170, + 101, + 204, + 156, + 139, + 185, + 148, + 94, + 192, + 68, + 4, + 250, + 232, + 110, + 119, + 56, + 33, + 248, + 249, + 199, + 198, + 250, + 25, + 166, + 232, + 171, + 139, + 56, + 197, + 109, + 61, + 79, + 106, + 225, + 54, + 101, + 51, + 185, + 198, + 129, + 147, + 246, + 255, + 254, + 200, + 66, + 27, + 230, + 84, + 108, + 95, + 18, + 165, + 251, + 146, + 96, + 164, + 88, + 207, + 37, + 93, + 56, + 33, + 103, + 11, + 224, + 56, + 186, + 136, + 41, + 140, + 212, + 71, + 4, + 196, + 100, + 242, + 127, + 180, + 163, + 112, + 64, + 219, + 81, + 177, + 127, + 143, + 218, + 236, + 143, + 252, + 159, + 110, + 4, + 58, + 167, + 70, + 192, + 124, + 171, + 202, + 17, + 36, + 45, + 124, + 168, + 145, + 56, + 104, + 205, + 186, + 70, + 217, + 235, + 80, + 187, + 65, + 24, + 100, + 149, + 179, + 190, + 209, + 53, + 157, + 7, + 213, + 158, + 174, + 197, + 192, + 222, + 117, + 233, + 41, + 103, + 158, + 251, + 89, + 87, + 140, + 190, + 45, + 146, + 127, + 176, + 69, + 187, + 158, + 157, + 161, + 2, + 253, + 26, + 246, + 166, + 250, + 114, + 165, + 109, + 67, + 219, + 57, + 120, + 37, + 139, + 158, + 183, + 200, + 173, + 85, + 215, + 89, + 216, + 148, + 68, + 234, + 101, + 66, + 36, + 244, + 154, + 194, + 28, + 253, + 122, + 249, + 221, + 184, + 81, + 213, + 40, + 7, + 181, + 37, + 16, + 3, + 226, + 129, + 27, + 16, + 135, + 9, + 90, + 172, + 174, + 137, + 249, + 105, + 15, + 79, + 33, + 83, + 9, + 17, + 208, + 158, + 157, + 112, + 58, + 55, + 85, + 128, + 208, + 9, + 245, + 58, + 71, + 74, + 187, + 131, + 94, + 144, + 18, + 70, + 74, + 175, + 11, + 26, + 33, + 50, + 243, + 200, + 199, + 115, + 99, + 123, + 214, + 163, + 101, + 127, + 119, + 133, + 60, + 174, + 221, + 211, + 16, + 168, + 240, + 111, + 125, + 250, + 19, + 68, + 182, + 220, + 154, + 241, + 101, + 75, + 124, + 32, + 28, + 50, + 248, + 166, + 253, + 77, + 231, + 168, + 59, + 222, + 186, + 120, + 40, + 150, + 232, + 61, + 64, + 186, + 7, + 45, + 236, + 14, + 181, + 224, + 225, + 169, + 96, + 98, + 56, + 243, + 50, + 160, + 68, + 76, + 229, + 71, + 95, + 112, + 208, + 156, + 13, + 244, + 153, + 239, + 59, + 99, + 54, + 85, + 209, + 171, + 143, + 239, + 126, + 155, + 204, + 133, + 87, + 159, + 66, + 98, + 241, + 0, + 50, + 0, + 3, + 122, + 207, + 152, + 182, + 129, + 12, + 70, + 125, + 52, + 9, + 241, + 64, + 248, + 65, + 142, + 68, + 169, + 94, + 224, + 62, + 133, + 55, + 51, + 14, + 102, + 179, + 44, + 60, + 167, + 55, + 241, + 254, + 177, + 70, + 127, + 230, + 65, + 31, + 27, + 148, + 77, + 86, + 120, + 47, + 141, + 60, + 124, + 188, + 183, + 67, + 193, + 34, + 238, + 222, + 204, + 44, + 192, + 136, + 99, + 74, + 120, + 56, + 135, + 164, + 68, + 95, + 170, + 248, + 179, + 202, + 38, + 106, + 170, + 207, + 70, + 36, + 188, + 44, + 30, + 113, + 225, + 183, + 149, + 58, + 50, + 135, + 16, + 97, + 131, + 156, + 9, + 192, + 46, + 156, + 64, + 215, + 71, + 19, + 135, + 166, + 46, + 198, + 58, + 2, + 156, + 230, + 121, + 81, + 127, + 25, + 64, + 203, + 249, + 158, + 14, + 95, + 151, + 37, + 7, + 92, + 163, + 96, + 100, + 33, + 66, + 117, + 64, + 207, + 226, + 64, + 98, + 197, + 63, + 229, + 250, + 2, + 39, + 174, + 136, + 115, + 220, + 227, + 47, + 141, + 145, + 21, + 80, + 53, + 58, + 222, + 79, + 87, + 211, + 233, + 0, + 224, + 153, + 178, + 38, + 12, + 185, + 34, + 225, + 55, + 86, + 105, + 90, + 114, + 3, + 154, + 222, + 83, + 228, + 243, + 235, + 118, + 32, + 249, + 41, + 238, + 70, + 138, + 45, + 188, + 197, + 44, + 152, + 139, + 153, + 145, + 80, + 150, + 6, + 210, + 218, + 102, + 123, + 57, + 222, + 228, + 180, + 97, + 162, + 54, + 181, + 45, + 133, + 65, + 55, + 146, + 14, + 249, + 156, + 159, + 49, + 168, + 113, + 44, + 86, + 185, + 97, + 17, + 23, + 162, + 78, + 118, + 180, + 245, + 165, + 149, + 125, + 41, + 159, + 150, + 13, + 113, + 202, + 140, + 223, + 198, + 207, + 191, + 113, + 186, + 66, + 241, + 103, + 28, + 65, + 89, + 230, + 82, + 212, + 178, + 223, + 217, + 195, + 113, + 242, + 80, + 25, + 109, + 109, + 89, + 215, + 81, + 42, + 41, + 135, + 99, + 66, + 120, + 75, + 205, + 71, + 45, + 180, + 195, + 103, + 14, + 179, + 136, + 64, + 145, + 8, + 16, + 242, + 45, + 162, + 58, + 89, + 233, + 215, + 199, + 149, + 103, + 6, + 45, + 100, + 94, + 27, + 138, + 239, + 231, + 245, + 39, + 52, + 218, + 146, + 239, + 37, + 86, + 1, + 7, + 75, + 9, + 18, + 47, + 160, + 37, + 254, + 145, + 185, + 39, + 135, + 194, + 81, + 69, + 102, + 21, + 92, + 12, + 246, + 151, + 120, + 242, + 94, + 26, + 182, + 177, + 110, + 229, + 245, + 109, + 237, + 123, + 246, + 68, + 12, + 19, + 170, + 248, + 108, + 153, + 19, + 169, + 172, + 191, + 172, + 243, + 208, + 139, + 34, + 95, + 0, + 96, + 94, + 21, + 103, + 67, + 116, + 18, + 135, + 125, + 160, + 27, + 67, + 179, + 116, + 226, + 140, + 32, + 128, + 119, + 85, + 1, + 101, + 76, + 96, + 130, + 25, + 106, + 219, + 153, + 80, + 42, + 178, + 215, + 222, + 255, + 199, + 197, + 56, + 14, + 122, + 164, + 145, + 57, + 78, + 92, + 126, + 45, + 123, + 171, + 106, + 60, + 120, + 236, + 10, + 8, + 85, + 78, + 163, + 228, + 140, + 197, + 42, + 25, + 238, + 153, + 175, + 117, + 152, + 9, + 119, + 238, + 144, + 28, + 242, + 134, + 10, + 202, + 103, + 129, + 3, + 126, + 185, + 132, + 38, + 151, + 1, + 152, + 50, + 197, + 112, + 35, + 206, + 252, + 196, + 35, + 130, + 191, + 110, + 92, + 125, + 203, + 101, + 129, + 113, + 105, + 138, + 239, + 176, + 242, + 251, + 52, + 120, + 166, + 18, + 177, + 205, + 5, + 199, + 252, + 154, + 17, + 100, + 14, + 42, + 186, + 245, + 62, + 21, + 178, + 245, + 83, + 234, + 43, + 84, + 101, + 145, + 73, + 169, + 221, + 97, + 120, + 112, + 231, + 121, + 7, + 164, + 113, + 45, + 180, + 191, + 35, + 152, + 237, + 57, + 22, + 20, + 124, + 186, + 109, + 199, + 184, + 65, + 194, + 75, + 196, + 239, + 32, + 248, + 193, + 107, + 202, + 248, + 83, + 121, + 172, + 128, + 92, + 235, + 61, + 99, + 64, + 243, + 31, + 97, + 124, + 45, + 181, + 245, + 37, + 186, + 115, + 8, + 153, + 20, + 62, + 1, + 131, + 200, + 91, + 180, + 156, + 36, + 169, + 32, + 64, + 214, + 188, + 15, + 232, + 60, + 81, + 191, + 42, + 116, + 13, + 218, + 59, + 118, + 21, + 113, + 6, + 224, + 83, + 18, + 226, + 231, + 29, + 47, + 53, + 158, + 192, + 63, + 137, + 181, + 83, + 115, + 12, + 195, + 6, + 238, + 203, + 247, + 199, + 59, + 171, + 59, + 45, + 214, + 113, + 3, + 35, + 9, + 79, + 196, + 41, + 50, + 175, + 10, + 119, + 14, + 37, + 168, + 49, + 39, + 235, + 234, + 171, + 69, + 254, + 128, + 179, + 172, + 119, + 178, + 104, + 160, + 224, + 214, + 42, + 40, + 223, + 247, + 131, + 190, + 212, + 1, + 113, + 7, + 38, + 168, + 231, + 253, + 246, + 239, + 178, + 205, + 182, + 244, + 195, + 229, + 22, + 117, + 201, + 79, + 210, + 58, + 184, + 220, + 227, + 25, + 246, + 126, + 3, + 82, + 231, + 38, + 51, + 49, + 72, + 222, + 41, + 109, + 211, + 244, + 137, + 195, + 97, + 150, + 172, + 126, + 195, + 34, + 102, + 235, + 161, + 28, + 39, + 225, + 207, + 48, + 135, + 72, + 141, + 240, + 187, + 192, + 41, + 211, + 82, + 247, + 12, + 91, + 93, + 134, + 67, + 237, + 63, + 83, + 122, + 233, + 98, + 0, + 236, + 218, + 157, + 157, + 39, + 117, + 116, + 197, + 240, + 213, + 52, + 230, + 37, + 160, + 25, + 83, + 35, + 170, + 77, + 26, + 83, + 136, + 209, + 68, + 210, + 192, + 179, + 206, + 87, + 168, + 67, + 165, + 213, + 99, + 19, + 249, + 182, + 136, + 204, + 86, + 145, + 176, + 215, + 110, + 234, + 245, + 164, + 201, + 145, + 154, + 231, + 158, + 102, + 117, + 84, + 168, + 89, + 129, + 250, + 190, + 96, + 196, + 0, + 174, + 235, + 140, + 228, + 122, + 201, + 234, + 0, + 235, + 98, + 223, + 1, + 143, + 158, + 82, + 221, + 2, + 223, + 214, + 85, + 144, + 83, + 89, + 40, + 65, + 240, + 25, + 57, + 31, + 255, + 230, + 56, + 182, + 10, + 88, + 220, + 99, + 240, + 75, + 178, + 82, + 63, + 120, + 41, + 242, + 210, + 188, + 81, + 203, + 118, + 177, + 86, + 201, + 40, + 7, + 21, + 171, + 89, + 238, + 193, + 175, + 2, + 226, + 125, + 96, + 73, + 141, + 246, + 49, + 205, + 102, + 181, + 207, + 159, + 137, + 13, + 46, + 90, + 203, + 209, + 217, + 122, + 204, + 220, + 5, + 72, + 29, + 247, + 204, + 249, + 40, + 72, + 211, + 225, + 250, + 211, + 166, + 33, + 103, + 45, + 146, + 196, + 107, + 240, + 86, + 127, + 225, + 227, + 7, + 54, + 83, + 121, + 238, + 201, + 143, + 178, + 109, + 11, + 138, + 22, + 215, + 10, + 83, + 45, + 217, + 30, + 251, + 28, + 206, + 46, + 59, + 63, + 133, + 234, + 199, + 66, + 182, + 133, + 95, + 232, + 186, + 140, + 231, + 117, + 131, + 0, + 129, + 222, + 23, + 91, + 206, + 98, + 186, + 252, + 184, + 97, + 237, + 41, + 57, + 246, + 98, + 21, + 2, + 70, + 92, + 137, + 203, + 210, + 18, + 194, + 63, + 255, + 133, + 184, + 107, + 33, + 144, + 248, + 49, + 164, + 134, + 37, + 33, + 168, + 204, + 200, + 173, + 139, + 53, + 72, + 22, + 94, + 94, + 36, + 86, + 186, + 52, + 20, + 57, + 27, + 188, + 13, + 214, + 78, + 51, + 239, + 132, + 200, + 98, + 237, + 8, + 111, + 100, + 52, + 181, + 50, + 39, + 176, + 251, + 81, + 55, + 155, + 144, + 155, + 76, + 84, + 30, + 180, + 36, + 194, + 237, + 67, + 254, + 120, + 22, + 246, + 1, + 7, + 124, + 157, + 1, + 102, + 186, + 142, + 10, + 23, + 173, + 220, + 253, + 104, + 89, + 8, + 73, + 54, + 244, + 137, + 137, + 223, + 237, + 101, + 56, + 212, + 203, + 17, + 147, + 179, + 248, + 254, + 251, + 221, + 37, + 44, + 31, + 136, + 244, + 183, + 169, + 92, + 62, + 192, + 64, + 168, + 6, + 146, + 254, + 95, + 145, + 249, + 228, + 46, + 185, + 165, + 92, + 238, + 91, + 14, + 148, + 51, + 27, + 58, + 143, + 48, + 170, + 225, + 5, + 201, + 37, + 48, + 196, + 34, + 135, + 44, + 155, + 221, + 30, + 233, + 132, + 183, + 42, + 233, + 173, + 120, + 49, + 152, + 65, + 53, + 122, + 66, + 216, + 182, + 172, + 195, + 192, + 189, + 104, + 27, + 255, + 87, + 77, + 35, + 167, + 53, + 106, + 84, + 142, + 127, + 218, + 100, + 192, + 175, + 23, + 38, + 188, + 225, + 165, + 186, + 113, + 49, + 253, + 86, + 105, + 154, + 36, + 178, + 49, + 23, + 254, + 53, + 60, + 179, + 146, + 59, + 116, + 99, + 251, + 223, + 86, + 17, + 146, + 222, + 230, + 245, + 56, + 152, + 150, + 179, + 172, + 177, + 64, + 145, + 45, + 131, + 244, + 89, + 239, + 180, + 215, + 245, + 125, + 29, + 93, + 140, + 67, + 250, + 26, + 31, + 147, + 217, + 197, + 79, + 113, + 83, + 37, + 21, + 109, + 90, + 102, + 152, + 166, + 219, + 15, + 121, + 10, + 244, + 17, + 112, + 121, + 201, + 229, + 205, + 196, + 120, + 15, + 127, + 66, + 91, + 155, + 114, + 137, + 61, + 10, + 73, + 42, + 232, + 162, + 148, + 0, + 132, + 37, + 154, + 32, + 128, + 245, + 41, + 156, + 137, + 142, + 16, + 92, + 36, + 55, + 28, + 111, + 184, + 120, + 83, + 247, + 78, + 21, + 11, + 188, + 211, + 81, + 37, + 106, + 76, + 85, + 100, + 17, + 108, + 30, + 56, + 170, + 0, + 138, + 48, + 112, + 44, + 60, + 103, + 193, + 22, + 114, + 175, + 135, + 51, + 97, + 35, + 215, + 79, + 133, + 13, + 56, + 238, + 184, + 117, + 152, + 181, + 82, + 220, + 119, + 58, + 176, + 248, + 241, + 74, + 70, + 65, + 66, + 111, + 65, + 165, + 81, + 111, + 103, + 48, + 210, + 113, + 9, + 133, + 48, + 153, + 229, + 46, + 237, + 211, + 65, + 164, + 25, + 127, + 148, + 114, + 124, + 2, + 163, + 135, + 8, + 230, + 58, + 189, + 214, + 237, + 50, + 93, + 220, + 179, + 93, + 51, + 216, + 19, + 159, + 66, + 123, + 165, + 121, + 35, + 40, + 122, + 126, + 215, + 249, + 227, + 73, + 120, + 40, + 82, + 70, + 48, + 41, + 187, + 38, + 63, + 80, + 163, + 90, + 219, + 73, + 3, + 180, + 65, + 169, + 195, + 90, + 40, + 124, + 199, + 198, + 100, + 80, + 145, + 167, + 15, + 4, + 224, + 58, + 78, + 42, + 138, + 170, + 10, + 47, + 115, + 189, + 73, + 176, + 82, + 9, + 137, + 226, + 63, + 64, + 0, + 141, + 21, + 153, + 48, + 246, + 174, + 193, + 101, + 184, + 230, + 36, + 194, + 157, + 200, + 225, + 182, + 17, + 217, + 113, + 245, + 153, + 29, + 65, + 79, + 167, + 146, + 44, + 102, + 5, + 170, + 144, + 72, + 188, + 227, + 4, + 150, + 186, + 92, + 231, + 50, + 77, + 194, + 90, + 43, + 73, + 186, + 168, + 120, + 180, + 241, + 57, + 180, + 15, + 22, + 250, + 63, + 183, + 126, + 106, + 24, + 86, + 164, + 24, + 34, + 125, + 186, + 50, + 118, + 74, + 237, + 189, + 88, + 141, + 60, + 202, + 172, + 90, + 74, + 53, + 123, + 185, + 99, + 127, + 246, + 65, + 41, + 242, + 53, + 29, + 182, + 59, + 210, + 17, + 251, + 213, + 199, + 162, + 199, + 181, + 225, + 81, + 64, + 38, + 101, + 111, + 152, + 92, + 83, + 145, + 27, + 100, + 179, + 15, + 176, + 121, + 40, + 9, + 25, + 51, + 23, + 177, + 96, + 136, + 81, + 101, + 83, + 163, + 245, + 88, + 122, + 255, + 150, + 180, + 210, + 151, + 113, + 175, + 123, + 144, + 225, + 185, + 102, + 175, + 224, + 103, + 165, + 172, + 207, + 34, + 184, + 189, + 161, + 250, + 74, + 239, + 31, + 32, + 161, + 37, + 205, + 112, + 17, + 141, + 187, + 138, + 144, + 83, + 35, + 65, + 238, + 9, + 177, + 29, + 22, + 48, + 93, + 66, + 68, + 217, + 36, + 136, + 224, + 222, + 215, + 178, + 146, + 230, + 254, + 200, + 174, + 252, + 152, + 16, + 97, + 195, + 99, + 0, + 78, + 89, + 28, + 235, + 199, + 127, + 229, + 80, + 251, + 240, + 39, + 90, + 138, + 172, + 142, + 9, + 147, + 151, + 249, + 64, + 73, + 131, + 205, + 63, + 1, + 162, + 138, + 46, + 66, + 248, + 65, + 252, + 194, + 224, + 39, + 100, + 47, + 125, + 10, + 56, + 254, + 63, + 12, + 144, + 114, + 253, + 201, + 165, + 65, + 130, + 201, + 121, + 98, + 63, + 172, + 3, + 212, + 235, + 228, + 203, + 58, + 97, + 83, + 181, + 126, + 110, + 104, + 112, + 227, + 15, + 199, + 144, + 48, + 207, + 175, + 169, + 24, + 172, + 181, + 203, + 182, + 163, + 247, + 130, + 31, + 35, + 124, + 197, + 230, + 133, + 171, + 144, + 56, + 168, + 2, + 60, + 163, + 31, + 75, + 56, + 37, + 201, + 119, + 2, + 18, + 38, + 85, + 177, + 125, + 249, + 150, + 86, + 45, + 255, + 223, + 195, + 129, + 41, + 234, + 179, + 114, + 171, + 167, + 120, + 31, + 192, + 236, + 189, + 77, + 69, + 80, + 139, + 239, + 73, + 167, + 35, + 180, + 64, + 197, + 250, + 216, + 226, + 240, + 184, + 158, + 92, + 195, + 20, + 144, + 133, + 253, + 183, + 2, + 160, + 58, + 217, + 143, + 60, + 115, + 206, + 89, + 224, + 40, + 161, + 162, + 53, + 140, + 249, + 75, + 19, + 234, + 178, + 195, + 228, + 88, + 31, + 152, + 33, + 114, + 240, + 210, + 8, + 226, + 47, + 193, + 55, + 170, + 112, + 163, + 250, + 122, + 150, + 153, + 189, + 13, + 85, + 75, + 4, + 253, + 173, + 23, + 238, + 164, + 125, + 50, + 100, + 67, + 27, + 222, + 243, + 150, + 166, + 143, + 164, + 171, + 27, + 15, + 186, + 236, + 175, + 2, + 158, + 17, + 243, + 106, + 77, + 17, + 1, + 69, + 180, + 185, + 222, + 165, + 147, + 76, + 190, + 189, + 165, + 3, + 212, + 181, + 137, + 210, + 170, + 37, + 54, + 100, + 144, + 68, + 254, + 21, + 37, + 100, + 161, + 246, + 225, + 84, + 129, + 10, + 238, + 254, + 250, + 214, + 162, + 224, + 174, + 192, + 81, + 135, + 67, + 9, + 67, + 51, + 110, + 164, + 205, + 59, + 176, + 161, + 153, + 81, + 110, + 69, + 46, + 89, + 29, + 82, + 82, + 31, + 218, + 115, + 24, + 61, + 168, + 28, + 187, + 95, + 137, + 248, + 195, + 247, + 73, + 177, + 200, + 88, + 174, + 13, + 229, + 131, + 215, + 213, + 180, + 215, + 126, + 187, + 66, + 251, + 153, + 115, + 63, + 189, + 82, + 45, + 240, + 43, + 81, + 241, + 185, + 247, + 87, + 159, + 134, + 183, + 254, + 104, + 57, + 156, + 115, + 195, + 12, + 149, + 170, + 95, + 216, + 12, + 51, + 113, + 254, + 39, + 89, + 8, + 182, + 204, + 161, + 34, + 129, + 42, + 41, + 129, + 35, + 50, + 54, + 88, + 0, + 198, + 171, + 221, + 108, + 245, + 253, + 95, + 43, + 89, + 144, + 130, + 148, + 173, + 182, + 215, + 16, + 47, + 177, + 133, + 169, + 66, + 127, + 2, + 77, + 105, + 255, + 158, + 124, + 230, + 0, + 120, + 123, + 61, + 236, + 38, + 57, + 159, + 59, + 159, + 162, + 223, + 53, + 56, + 169, + 199, + 108, + 233, + 157, + 40, + 153, + 8, + 122, + 80, + 111, + 93, + 208, + 55, + 149, + 7, + 96, + 123, + 126, + 97, + 208, + 70, + 62, + 185, + 92, + 169, + 80, + 62, + 141, + 101, + 146, + 200, + 127, + 119, + 51, + 202, + 242, + 241, + 255, + 4, + 111, + 143, + 216, + 83, + 106, + 129, + 33, + 222, + 98, + 234, + 121, + 210, + 89, + 71, + 218, + 138, + 162, + 56, + 35, + 64, + 245, + 246, + 123, + 16, + 146, + 91, + 68, + 163, + 71, + 159, + 5, + 199, + 178, + 30, + 149, + 57, + 149, + 96, + 1, + 179, + 8, + 216, + 34, + 240, + 97, + 147, + 11, + 231, + 250, + 189, + 102, + 167, + 61, + 249, + 141, + 3, + 187, + 175, + 249, + 181, + 75, + 89, + 106, + 9, + 186, + 0, + 185, + 97, + 193, + 220, + 113, + 117, + 81, + 122, + 251, + 162, + 2, + 111, + 143, + 242, + 99, + 171, + 39, + 68, + 90, + 2, + 231, + 163, + 56, + 113, + 148, + 173, + 185, + 134, + 68, + 148, + 175, + 4, + 4 +] diff --git a/crates/starknet_os/src/hints/hint_implementation/kzg/implementation.rs b/crates/starknet_os/src/hints/hint_implementation/kzg/implementation.rs new file mode 100644 index 00000000000..911ff4ee438 --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/kzg/implementation.rs @@ -0,0 +1,94 @@ +use ark_bls12_381::Fr; +use blockifier::state::state_api::StateReader; +use cairo_vm::hint_processor::builtin_hint_processor::hint_utils::{ + get_integer_from_var_name, + get_ptr_from_var_name, + get_relocatable_from_var_name, + insert_value_from_var_name, +}; +use cairo_vm::types::relocatable::MaybeRelocatable; +use starknet_types_core::felt::Felt; + +use crate::hints::error::{OsHintError, OsHintResult}; +use crate::hints::hint_implementation::kzg::utils::{ + polynomial_coefficients_to_kzg_commitment, + split_bigint3, +}; +use crate::hints::types::HintArgs; +use crate::hints::vars::{Const, Ids}; + +pub(crate) fn store_da_segment( + HintArgs { hint_processor, vm, ids_data, ap_tracking, constants, .. }: HintArgs<'_, S>, +) -> OsHintResult { + log::debug!("Executing store_da_segment hint."); + let state_updates_start = + get_ptr_from_var_name(Ids::StateUpdatesStart.into(), vm, ids_data, ap_tracking)?; + let da_size_felt = get_integer_from_var_name(Ids::DaSize.into(), vm, ids_data, ap_tracking)?; + let da_size = + usize::try_from(da_size_felt.to_biguint()).map_err(|error| OsHintError::IdsConversion { + variant: Ids::DaSize, + felt: da_size_felt, + ty: "usize".to_string(), + reason: error.to_string(), + })?; + + let da_segment: Vec = + vm.get_integer_range(state_updates_start, da_size)?.into_iter().map(|s| *s).collect(); + + let blob_length_felt = Const::BlobLength.fetch(constants)?; + let blob_length = usize::try_from(blob_length_felt.to_biguint()).map_err(|error| { + OsHintError::ConstConversion { + variant: Const::BlobLength, + felt: *blob_length_felt, + ty: "usize".to_string(), + reason: error.to_string(), + } + })?; + + let kzg_commitments: Vec<(Felt, Felt)> = da_segment + .chunks(blob_length) + .enumerate() + .map(|(chunk_id, chunk)| { + let coefficients: Vec = chunk.iter().map(|f| Fr::from(f.to_biguint())).collect(); + log::debug!("Computing KZG commitment on chunk {chunk_id}..."); + polynomial_coefficients_to_kzg_commitment(coefficients) + }) + .collect::>()?; + log::debug!("Done computing KZG commitments."); + + hint_processor.set_da_segment(da_segment)?; + + let n_blobs = kzg_commitments.len(); + let kzg_commitments_segment = vm.add_temporary_segment(); + let evals_segment = vm.add_temporary_segment(); + + insert_value_from_var_name(Ids::NBlobs.into(), n_blobs, vm, ids_data, ap_tracking)?; + insert_value_from_var_name( + Ids::KzgCommitments.into(), + kzg_commitments_segment, + vm, + ids_data, + ap_tracking, + )?; + insert_value_from_var_name(Ids::Evals.into(), evals_segment, vm, ids_data, ap_tracking)?; + + let kzg_commitments_flattened: Vec = + kzg_commitments.into_iter().flat_map(|c| [c.0.into(), c.1.into()]).collect(); + vm.write_arg(kzg_commitments_segment, &kzg_commitments_flattened)?; + + Ok(()) +} + +pub(crate) fn write_split_result( + HintArgs { vm, ids_data, ap_tracking, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let value = + get_integer_from_var_name(Ids::Value.into(), vm, ids_data, ap_tracking)?.to_bigint(); + let res_ptr = get_relocatable_from_var_name(Ids::Res.into(), vm, ids_data, ap_tracking)?; + + let splits: Vec = + split_bigint3(value)?.into_iter().map(MaybeRelocatable::Int).collect(); + vm.write_arg(res_ptr, &splits)?; + + Ok(()) +} diff --git a/crates/starknet_os/src/hints/hint_implementation/kzg/test.rs b/crates/starknet_os/src/hints/hint_implementation/kzg/test.rs new file mode 100644 index 00000000000..05973941d7d --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/kzg/test.rs @@ -0,0 +1,116 @@ +use std::sync::LazyLock; + +use ark_bls12_381::Fr; +use c_kzg::KzgCommitment; +use num_bigint::BigUint; +use num_traits::{Num, One, Zero}; +use rstest::rstest; +use starknet_types_core::felt::Felt; + +use crate::hints::hint_implementation::kzg::utils::{ + bit_reversal, + polynomial_coefficients_to_blob, + serialize_blob, + split_commitment, + FIELD_ELEMENTS_PER_BLOB, +}; + +static BLOB_SUBGROUP_GENERATOR: LazyLock = LazyLock::new(|| { + BigUint::from_str_radix( + "39033254847818212395286706435128746857159659164139250548781411570340225835782", + 10, + ) + .unwrap() +}); +static BLS_PRIME: LazyLock = LazyLock::new(|| { + BigUint::from_str_radix( + "52435875175126190479447740508185965837690552500527637822603658699938581184513", + 10, + ) + .unwrap() +}); +const BYTES_PER_BLOB: usize = FIELD_ELEMENTS_PER_BLOB * 32; + +static FFT_REGRESSION_INPUT: LazyLock> = LazyLock::new(|| { + serde_json::from_str::>(include_str!("fft_regression_input.json")) + .unwrap() + .into_iter() + .map(|s| Fr::from(BigUint::from_str_radix(&s, 10).unwrap())) + .collect() +}); +static FFT_REGRESSION_OUTPUT: LazyLock> = + LazyLock::new(|| serde_json::from_str(include_str!("fft_regression_output.json")).unwrap()); +static BLOB_REGRESSION_INPUT: LazyLock> = LazyLock::new(|| { + serde_json::from_str::>(include_str!("blob_regression_input.json")) + .unwrap() + .into_iter() + .map(|s| Fr::from(BigUint::from_str_radix(&s, 10).unwrap())) + .collect() +}); +static BLOB_REGRESSION_OUTPUT: LazyLock> = + LazyLock::new(|| serde_json::from_str(include_str!("blob_regression_output.json")).unwrap()); + +fn generate(generator: &BigUint) -> Vec { + let mut array = vec![BigUint::one()]; + for _ in 1..FIELD_ELEMENTS_PER_BLOB { + let last = array.last().unwrap().clone(); + let next = (generator * &last) % &*BLS_PRIME; + array.push(next); + } + bit_reversal(&mut array).unwrap(); + + array +} + +/// All the expected values are checked using the contract logic given in the Starknet core +/// contract: +/// https://github.com/starkware-libs/cairo-lang/blob/a86e92bfde9c171c0856d7b46580c66e004922f3/src/starkware/starknet/solidity/Starknet.sol#L209. +#[rstest] +#[case( + BigUint::from_str_radix( + "b7a71dc9d8e15ea474a69c0531e720cf5474b189ac9afc81590b91a225b1bf7fa5877ec546d090e0059f019c74675362", + 16, + ).unwrap(), + ( + Felt::from_hex_unchecked("590b91a225b1bf7fa5877ec546d090e0059f019c74675362"), + Felt::from_hex_unchecked("b7a71dc9d8e15ea474a69c0531e720cf5474b189ac9afc81"), + ) +)] +#[case( + BigUint::from_str_radix( + "a797c1973c99961e357246ee81bde0acbdd27e801d186ccb051732ecbaa75842afd3d8860d40b3e8eeea433bce18b5c8", + 16, + ).unwrap(), + ( + Felt::from_hex_unchecked("51732ecbaa75842afd3d8860d40b3e8eeea433bce18b5c8"), + Felt::from_hex_unchecked("a797c1973c99961e357246ee81bde0acbdd27e801d186ccb"), + ) +)] +fn test_split_commitment_function( + #[case] commitment: BigUint, + #[case] expected_output: (Felt, Felt), +) { + let commitment = KzgCommitment::from_bytes(&commitment.to_bytes_be()).unwrap(); + assert_eq!(split_commitment(&commitment).unwrap(), expected_output); +} + +#[rstest] +#[case::zero(vec![Fr::zero()], &vec![0u8; BYTES_PER_BLOB])] +#[case::one( + vec![Fr::one()], &(0..BYTES_PER_BLOB).map(|i| if (i + 1) % 32 == 0 { 1 } else { 0 }).collect() +)] +#[case::degree_one( + vec![Fr::zero(), Fr::from(10_u8)], + &serialize_blob( + &generate(&BLOB_SUBGROUP_GENERATOR) + .into_iter() + .map(|subgroup_elm| Fr::from((BigUint::from(10_u8) * subgroup_elm) % &*BLS_PRIME)) + .collect::>(), + ).unwrap() +)] +#[case::original(BLOB_REGRESSION_INPUT.to_vec(), &BLOB_REGRESSION_OUTPUT)] +#[case::generated(FFT_REGRESSION_INPUT.to_vec(), &FFT_REGRESSION_OUTPUT)] +fn test_fft_blob_regression(#[case] input: Vec, #[case] expected_output: &Vec) { + let bytes = polynomial_coefficients_to_blob(input).unwrap(); + assert_eq!(&bytes, expected_output); +} diff --git a/crates/starknet_os/src/hints/hint_implementation/kzg/utils.rs b/crates/starknet_os/src/hints/hint_implementation/kzg/utils.rs new file mode 100644 index 00000000000..29daea8ee86 --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/kzg/utils.rs @@ -0,0 +1,154 @@ +use std::num::ParseIntError; +use std::path::Path; +use std::sync::LazyLock; + +use ark_bls12_381::Fr; +use ark_ff::{BigInteger, PrimeField}; +use ark_poly::{EvaluationDomain, Radix2EvaluationDomain}; +use c_kzg::{Blob, KzgCommitment, KzgSettings, BYTES_PER_FIELD_ELEMENT}; +use num_bigint::{BigInt, ParseBigIntError}; +use num_traits::{Signed, Zero}; +use starknet_infra_utils::compile_time_cargo_manifest_dir; +use starknet_types_core::felt::Felt; + +use crate::hints::error::OsHintError; + +static BASE: LazyLock = LazyLock::new(|| BigInt::from(1u128 << 86)); +const COMMITMENT_BYTES_LENGTH: usize = 48; +const COMMITMENT_BYTES_MIDPOINT: usize = COMMITMENT_BYTES_LENGTH / 2; +const LOG2_FIELD_ELEMENTS_PER_BLOB: usize = 12; +pub(crate) const FIELD_ELEMENTS_PER_BLOB: usize = 1 << LOG2_FIELD_ELEMENTS_PER_BLOB; + +#[derive(Debug, thiserror::Error)] +pub enum FftError { + #[error(transparent)] + CKzg(#[from] c_kzg::Error), + #[error("Failed to create the evaluation domain.")] + EvalDomainCreation, + #[error(transparent)] + InvalidBinaryToUsize(ParseIntError), + #[error("Blob size must be {FIELD_ELEMENTS_PER_BLOB}, got {0}.")] + InvalidBlobSize(usize), + #[error(transparent)] + ParseBigUint(#[from] ParseBigIntError), + #[error("Too many coefficients; expected at most {FIELD_ELEMENTS_PER_BLOB}, got {0}.")] + TooManyCoefficients(usize), +} + +static KZG_SETTINGS: LazyLock = LazyLock::new(|| { + let path = + Path::new(compile_time_cargo_manifest_dir!()).join("resources").join("trusted_setup.txt"); + KzgSettings::load_trusted_setup_file(&path) + .unwrap_or_else(|error| panic!("Failed to load trusted setup file from {path:?}: {error}.")) +}); + +fn blob_to_kzg_commitment(blob: &Blob) -> Result { + Ok(KzgCommitment::blob_to_kzg_commitment(blob, &KZG_SETTINGS)?) +} + +fn pad_bytes(input_bytes: Vec, length: usize) -> Vec { + let mut bytes = input_bytes; + let padding = length.saturating_sub(bytes.len()); + if padding > 0 { + let mut padded_bytes = vec![0; padding]; + padded_bytes.extend(bytes); + bytes = padded_bytes; + } + bytes +} + +pub(crate) fn serialize_blob(blob: &[Fr]) -> Result, FftError> { + if blob.len() != FIELD_ELEMENTS_PER_BLOB { + return Err(FftError::InvalidBlobSize(blob.len())); + } + Ok(blob + .iter() + .flat_map(|x| pad_bytes(x.into_bigint().to_bytes_be(), BYTES_PER_FIELD_ELEMENT)) + .collect()) +} + +pub(crate) fn split_commitment(commitment: &KzgCommitment) -> Result<(Felt, Felt), FftError> { + let commitment_bytes: [u8; COMMITMENT_BYTES_LENGTH] = *commitment.to_bytes().as_ref(); + + // Split the number. + let low = &commitment_bytes[COMMITMENT_BYTES_MIDPOINT..]; + let high = &commitment_bytes[..COMMITMENT_BYTES_MIDPOINT]; + + Ok((Felt::from_bytes_be_slice(low), Felt::from_bytes_be_slice(high))) +} + +/// Performs bit-reversal permutation on the given vector, in-place. +/// Inlined from ark_poly. +// TODO(Dori): once the ark crates have a stable release with +// [this change](https://github.com/arkworks-rs/algebra/pull/960) included, remove this function +// and use `bitreverse_permutation_in_place`. +pub(crate) fn bit_reversal(unreversed_blob: &mut [T]) -> Result<(), FftError> { + if unreversed_blob.len() != FIELD_ELEMENTS_PER_BLOB { + return Err(FftError::InvalidBlobSize(unreversed_blob.len())); + } + + /// Reverses the bits of `n`, where `n` is represented by `LOG2_FIELD_ELEMENTS_PER_BLOB` bits. + fn bitreverse(mut n: usize) -> usize { + let mut r = 0; + for _ in 0..LOG2_FIELD_ELEMENTS_PER_BLOB { + // Mirror the bits: shift `n` right, shift `r` left. + r = (r << 1) | (n & 1); + n >>= 1; + } + r + } + + // Applies the bit-reversal permutation on all elements. Swaps only when `i < reversed_i` to + // avoid swapping the same element twice. + for i in 0..FIELD_ELEMENTS_PER_BLOB { + let reversed_i = bitreverse(i); + if i < reversed_i { + unreversed_blob.swap(i, reversed_i); + } + } + + Ok(()) +} + +pub(crate) fn polynomial_coefficients_to_blob(coefficients: Vec) -> Result, FftError> { + if coefficients.len() > FIELD_ELEMENTS_PER_BLOB { + return Err(FftError::TooManyCoefficients(coefficients.len())); + } + + // Pad with zeros to complete FIELD_ELEMENTS_PER_BLOB coefficients. + let mut evals = coefficients; + evals.resize(FIELD_ELEMENTS_PER_BLOB, Fr::zero()); + + // Perform FFT (in place) on the coefficients, and bit-reverse. + let domain = Radix2EvaluationDomain::::new(FIELD_ELEMENTS_PER_BLOB) + .ok_or(FftError::EvalDomainCreation)?; + domain.fft_in_place(&mut evals); + bit_reversal(&mut evals)?; + + // Serialize the FFT result into a blob. + serialize_blob(&evals) +} + +pub(crate) fn polynomial_coefficients_to_kzg_commitment( + coefficients: Vec, +) -> Result<(Felt, Felt), FftError> { + let blob = polynomial_coefficients_to_blob(coefficients)?; + let commitment_bytes = blob_to_kzg_commitment(&Blob::from_bytes(&blob)?)?; + split_commitment(&commitment_bytes) +} + +/// Takes an integer and returns its canonical representation as: +/// d0 + d1 * BASE + d2 * BASE**2. +/// d2 can be in the range (-2**127, 2**127). +// TODO(Dori): Consider using bls_split from the VM crate if and when public. +pub(crate) fn split_bigint3(num: BigInt) -> Result<[Felt; 3], OsHintError> { + let (q1, d0) = (&num / &*BASE, Felt::from(num % &*BASE)); + let (d2, d1) = (&q1 / &*BASE, Felt::from(q1 % &*BASE)); + if d2.abs() >= BigInt::from(1_u128 << 127) { + return Err(OsHintError::AssertionFailed { + message: format!("Remainder should be in (-2**127, 2**127), got {d2}."), + }); + } + + Ok([d0, d1, Felt::from(d2)]) +} diff --git a/crates/starknet_os/src/hints/hint_implementation/math.rs b/crates/starknet_os/src/hints/hint_implementation/math.rs new file mode 100644 index 00000000000..690066b0702 --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/math.rs @@ -0,0 +1,8 @@ +use blockifier::state::state_api::StateReader; + +use crate::hints::error::OsHintResult; +use crate::hints::types::HintArgs; + +pub(crate) fn log2_ceil(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} diff --git a/crates/starknet_os/src/hints/hint_implementation/os.rs b/crates/starknet_os/src/hints/hint_implementation/os.rs new file mode 100644 index 00000000000..c577d9cee09 --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/os.rs @@ -0,0 +1,110 @@ +use std::collections::HashMap; + +use blockifier::state::state_api::StateReader; +use cairo_vm::hint_processor::builtin_hint_processor::hint_utils::insert_value_into_ap; +use cairo_vm::types::relocatable::MaybeRelocatable; +use starknet_types_core::felt::Felt; + +use crate::hints::enum_definition::{AllHints, OsHint}; +use crate::hints::error::OsHintResult; +use crate::hints::nondet_offsets::insert_nondet_hint_value; +use crate::hints::types::HintArgs; +use crate::hints::vars::{CairoStruct, Scope}; +use crate::vm_utils::insert_values_to_fields; + +pub(crate) fn initialize_class_hashes( + HintArgs { hint_processor, exec_scopes, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let class_hash_to_compiled_class_hash: HashMap = + hint_processor + .execution_helper + .cached_state + .writes_compiled_class_hashes() + .into_iter() + .map(|(class_hash, compiled_class_hash)| { + (class_hash.0.into(), compiled_class_hash.0.into()) + }) + .collect(); + exec_scopes.insert_value(Scope::InitialDict.into(), class_hash_to_compiled_class_hash); + Ok(()) +} + +pub(crate) fn initialize_state_changes( + HintArgs { hint_processor, exec_scopes, vm, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let cached_state = &hint_processor.execution_helper.cached_state; + let writes_accessed_addresses = cached_state.writes_contract_addresses(); + let mut initial_dict: HashMap = HashMap::new(); + + for contract_address in writes_accessed_addresses { + let nonce = cached_state.get_nonce_at(contract_address)?; + let class_hash = cached_state.get_class_hash_at(contract_address)?; + let state_entry_base = vm.add_memory_segment(); + let storage_ptr = vm.add_memory_segment(); + insert_values_to_fields( + state_entry_base, + CairoStruct::StateEntry, + vm, + &[ + ("class_hash", class_hash.0.into()), + ("storage_ptr", storage_ptr.into()), + ("nonce", nonce.0.into()), + ], + &hint_processor.execution_helper.os_program, + )?; + initial_dict.insert((*contract_address.0.key()).into(), state_entry_base.into()); + } + exec_scopes.insert_value(Scope::InitialDict.into(), initial_dict); + Ok(()) +} + +pub(crate) fn write_full_output_to_memory( + HintArgs { vm, hint_processor, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let os_input = &hint_processor.execution_helper.os_input; + let full_output = Felt::from(os_input.full_output); + insert_nondet_hint_value(vm, AllHints::OsHint(OsHint::WriteFullOutputToMemory), full_output) +} + +pub(crate) fn configure_kzg_manager( + HintArgs { exec_scopes, .. }: HintArgs<'_, S>, +) -> OsHintResult { + // TODO(Aner): verify that inserting into the "root" scope is not neccessary. + exec_scopes.insert_value(Scope::SerializeDataAvailabilityCreatePages.into(), true); + Ok(()) +} + +pub(crate) fn set_ap_to_prev_block_hash( + HintArgs { hint_processor, vm, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let os_input = &hint_processor.execution_helper.os_input; + Ok(insert_value_into_ap(vm, os_input.prev_block_hash.0)?) +} + +pub(crate) fn set_ap_to_new_block_hash( + HintArgs { hint_processor, vm, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let os_input = &hint_processor.execution_helper.os_input; + Ok(insert_value_into_ap(vm, os_input.new_block_hash.0)?) +} + +pub(crate) fn starknet_os_input(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + // Nothing to do here; OS input already available on the hint processor. + Ok(()) +} + +pub(crate) fn init_state_update_pointer( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn get_n_blocks(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn create_block_additional_hints( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} diff --git a/crates/starknet_os/src/hints/hint_implementation/os_logger.rs b/crates/starknet_os/src/hints/hint_implementation/os_logger.rs new file mode 100644 index 00000000000..af56ee26420 --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/os_logger.rs @@ -0,0 +1,16 @@ +use blockifier::state::state_api::StateReader; + +use crate::hints::error::OsHintResult; +use crate::hints::types::HintArgs; + +pub(crate) fn os_logger_enter_syscall_prepare_exit_syscall( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn os_logger_exit_syscall( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} diff --git a/crates/starknet_os/src/hints/hint_implementation/output.rs b/crates/starknet_os/src/hints/hint_implementation/output.rs new file mode 100644 index 00000000000..a42bbb97bb1 --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/output.rs @@ -0,0 +1,103 @@ +use blockifier::state::state_api::StateReader; +use cairo_vm::hint_processor::builtin_hint_processor::hint_utils::{ + get_integer_from_var_name, + insert_value_from_var_name, +}; +use starknet_types_core::felt::Felt; + +use crate::hints::error::{OsHintError, OsHintResult}; +use crate::hints::types::HintArgs; +use crate::hints::vars::{Ids, Scope}; + +pub(crate) fn set_tree_structure(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn set_state_updates_start( + HintArgs { vm, exec_scopes, ids_data, ap_tracking, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let use_kzg_da_felt = + get_integer_from_var_name(Ids::UseKzgDa.into(), vm, ids_data, ap_tracking)?; + + // Set `use_kzg_da` in globals since it will be used in `process_data_availability` + exec_scopes.insert_value(Scope::UseKzgDa.into(), use_kzg_da_felt); + + // Recompute `compress_state_updates` until this issue is fixed in our VM version: + // https://github.com/lambdaclass/cairo-vm/issues/1897 + // TODO(Rotem): fix code when we update to VM 2.0.0 (fix should be available in one of the RCs). + + let full_output = get_integer_from_var_name(Ids::FullOutput.into(), vm, ids_data, ap_tracking)?; + let compress_state_updates = Felt::ONE - full_output; + + let use_kzg_da = match use_kzg_da_felt { + x if x == Felt::ONE => Ok(true), + x if x == Felt::ZERO => Ok(false), + _ => Err(OsHintError::BooleanIdExpected { id: Ids::UseKzgDa, felt: use_kzg_da_felt }), + }?; + + let use_compress_state_updates = match compress_state_updates { + x if x == Felt::ONE => Ok(true), + x if x == Felt::ZERO => Ok(false), + _ => Err(OsHintError::BooleanIdExpected { id: Ids::FullOutput, felt: full_output }), + }?; + + if use_kzg_da || use_compress_state_updates { + insert_value_from_var_name( + Ids::StateUpdatesStart.into(), + vm.add_memory_segment(), + vm, + ids_data, + ap_tracking, + )?; + } else { + // Assign a temporary segment, to be relocated into the output segment. + insert_value_from_var_name( + Ids::StateUpdatesStart.into(), + vm.add_temporary_segment(), + vm, + ids_data, + ap_tracking, + )?; + } + + Ok(()) +} + +pub(crate) fn set_compressed_start( + HintArgs { vm, exec_scopes, ids_data, ap_tracking, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let use_kzg_da_felt = exec_scopes.get::(Scope::UseKzgDa.into())?; + + let use_kzg_da = match use_kzg_da_felt { + x if x == Felt::ONE => Ok(true), + x if x == Felt::ZERO => Ok(false), + _ => Err(OsHintError::BooleanIdExpected { id: Ids::UseKzgDa, felt: use_kzg_da_felt }), + }?; + + if use_kzg_da { + insert_value_from_var_name( + Ids::CompressedStart.into(), + vm.add_memory_segment(), + vm, + ids_data, + ap_tracking, + )?; + } else { + // Assign a temporary segment, to be relocated into the output segment. + insert_value_from_var_name( + Ids::CompressedStart.into(), + vm.add_temporary_segment(), + vm, + ids_data, + ap_tracking, + )?; + } + + Ok(()) +} + +pub(crate) fn set_n_updates_small( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} diff --git a/crates/starknet_os/src/hints/hint_implementation/patricia.rs b/crates/starknet_os/src/hints/hint_implementation/patricia.rs new file mode 100644 index 00000000000..848a30b90f9 --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/patricia.rs @@ -0,0 +1,3 @@ +pub mod implementation; +#[allow(dead_code)] +pub mod utils; diff --git a/crates/starknet_os/src/hints/hint_implementation/patricia/implementation.rs b/crates/starknet_os/src/hints/hint_implementation/patricia/implementation.rs new file mode 100644 index 00000000000..187b39b6345 --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/patricia/implementation.rs @@ -0,0 +1,118 @@ +use blockifier::state::state_api::StateReader; +use cairo_vm::hint_processor::builtin_hint_processor::hint_utils::{ + get_integer_from_var_name, + insert_value_from_var_name, + insert_value_into_ap, +}; +use num_bigint::BigUint; +use starknet_types_core::felt::Felt; + +use crate::hints::error::{OsHintError, OsHintResult}; +use crate::hints::hint_implementation::patricia::utils::{DecodeNodeCase, PreimageMap}; +use crate::hints::types::HintArgs; +use crate::hints::vars::{CairoStruct, Ids, Scope}; +use crate::vm_utils::get_address_of_nested_fields; + +pub(crate) fn set_siblings(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn is_case_right( + HintArgs { vm, exec_scopes, ids_data, ap_tracking, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let case: DecodeNodeCase = exec_scopes.get(Scope::Case.into())?; + let bit = get_integer_from_var_name(Ids::Bit.into(), vm, ids_data, ap_tracking)?; + + let case_right = Felt::from(case == DecodeNodeCase::Right); + + if bit != Felt::ZERO && bit != Felt::ONE { + return Err(OsHintError::ExpectedBit { id: Ids::Bit, felt: bit }); + } + + // Felts do not support XOR, compute it manually. + let value_felt = Felt::from(bit != case_right); + insert_value_into_ap(vm, value_felt)?; + + Ok(()) +} + +pub(crate) fn set_bit( + HintArgs { hint_processor, vm, ids_data, ap_tracking, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let edge_path_addr = get_address_of_nested_fields( + ids_data, + Ids::Edge, + CairoStruct::NodeEdge, + vm, + ap_tracking, + &["path"], + &hint_processor.execution_helper.os_program, + )?; + let edge_path = vm.get_integer(edge_path_addr)?.into_owned(); + let new_length = u8::try_from( + get_integer_from_var_name(Ids::NewLength.into(), vm, ids_data, ap_tracking)?.to_biguint(), + )?; + + let bit = (edge_path.to_biguint() >> new_length) & BigUint::from(1u64); + let bit_felt = Felt::from(&bit); + insert_value_from_var_name(Ids::Bit.into(), bit_felt, vm, ids_data, ap_tracking)?; + + Ok(()) +} + +pub(crate) fn set_ap_to_descend(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn assert_case_is_right( + HintArgs { exec_scopes, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let case: DecodeNodeCase = exec_scopes.get(Scope::Case.into())?; + if case != DecodeNodeCase::Right { + return Err(OsHintError::AssertionFailed { message: "case != 'right".to_string() }); + } + Ok(()) +} + +pub(crate) fn write_case_not_left_to_ap( + HintArgs { vm, exec_scopes, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let case: DecodeNodeCase = exec_scopes.get(Scope::Case.into())?; + let value = Felt::from(case != DecodeNodeCase::Left); + insert_value_into_ap(vm, value)?; + Ok(()) +} + +pub(crate) fn split_descend(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn height_is_zero_or_len_node_preimage_is_two( + HintArgs { vm, exec_scopes, ids_data, ap_tracking, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let height = get_integer_from_var_name(Ids::Height.into(), vm, ids_data, ap_tracking)?; + + let answer = if height == Felt::ZERO { + Felt::ONE + } else { + let node = get_integer_from_var_name(Ids::Node.into(), vm, ids_data, ap_tracking)?; + let preimage_map: &PreimageMap = exec_scopes.get_ref(Scope::Preimage.into())?; + let preimage_value = + preimage_map.get(node.as_ref()).ok_or(OsHintError::MissingPreimage(node))?; + Felt::from(preimage_value.length() == 2) + }; + + insert_value_into_ap(vm, answer)?; + + Ok(()) +} + +pub(crate) fn prepare_preimage_validation_non_deterministic_hashes( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn build_descent_map(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} diff --git a/crates/starknet_os/src/hints/hint_implementation/patricia/utils.rs b/crates/starknet_os/src/hints/hint_implementation/patricia/utils.rs new file mode 100644 index 00000000000..ee0ded966f1 --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/patricia/utils.rs @@ -0,0 +1,28 @@ +use std::collections::HashMap; + +use starknet_patricia::patricia_merkle_tree::node_data::inner_node::{BinaryData, EdgeData}; +use starknet_types_core::felt::Felt; + +#[derive(Clone)] +pub enum Preimage { + Binary(BinaryData), + Edge(EdgeData), +} + +pub type PreimageMap = HashMap; + +impl Preimage { + pub fn length(&self) -> u8 { + match self { + Preimage::Binary(_) => 2, + Preimage::Edge(_) => 3, + } + } +} + +#[derive(Clone, PartialEq)] +pub enum DecodeNodeCase { + Left, + Right, + Both, +} diff --git a/crates/starknet_os/src/hints/hint_implementation/resources.rs b/crates/starknet_os/src/hints/hint_implementation/resources.rs new file mode 100644 index 00000000000..6b82f20df07 --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/resources.rs @@ -0,0 +1,30 @@ +use blockifier::state::state_api::StateReader; +use cairo_vm::hint_processor::builtin_hint_processor::hint_utils::{ + get_integer_from_var_name, + insert_value_into_ap, +}; +use starknet_types_core::felt::Felt; + +use crate::hints::error::OsHintResult; +use crate::hints::types::HintArgs; +use crate::hints::vars::Ids; + +pub(crate) fn remaining_gas_gt_max( + HintArgs { vm, ids_data, ap_tracking, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let remaining_gas = + get_integer_from_var_name(Ids::RemainingGas.into(), vm, ids_data, ap_tracking)?; + let max_gas = get_integer_from_var_name(Ids::MaxGas.into(), vm, ids_data, ap_tracking)?; + let remaining_gas_gt_max: Felt = (remaining_gas > max_gas).into(); + Ok(insert_value_into_ap(vm, remaining_gas_gt_max)?) +} + +pub(crate) fn debug_expected_initial_gas( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn is_sierra_gas_mode(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} diff --git a/crates/starknet_os/src/hints/hint_implementation/secp.rs b/crates/starknet_os/src/hints/hint_implementation/secp.rs new file mode 100644 index 00000000000..d1509d27bc9 --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/secp.rs @@ -0,0 +1,14 @@ +use blockifier::state::state_api::StateReader; + +use crate::hints::error::OsHintResult; +use crate::hints::types::HintArgs; + +pub(crate) fn is_on_curve(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn read_ec_point_from_address( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} diff --git a/crates/starknet_os/src/hints/hint_implementation/state.rs b/crates/starknet_os/src/hints/hint_implementation/state.rs new file mode 100644 index 00000000000..93bb2f090f4 --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/state.rs @@ -0,0 +1,96 @@ +use blockifier::state::state_api::StateReader; +use cairo_vm::hint_processor::builtin_hint_processor::hint_utils::insert_value_from_var_name; +use cairo_vm::types::relocatable::Relocatable; +use starknet_types_core::felt::Felt; + +use crate::hints::error::{OsHintError, OsHintResult}; +use crate::hints::types::HintArgs; +use crate::hints::vars::{Const, Ids, Scope}; +use crate::io::os_input::CommitmentInfo; + +#[derive(Clone)] +pub(crate) struct StateUpdatePointers { + pub(crate) _contract_address_to_storage_ptr: Relocatable, + pub(crate) _state_tree_pointer: Relocatable, + pub(crate) _class_tree_pointer: Relocatable, +} + +#[derive(Copy, Clone)] +enum CommitmentType { + Class, + State, +} + +fn verify_tree_height_eq_merkle_height(tree_height: Felt, merkle_height: Felt) -> OsHintResult { + if tree_height != merkle_height { + return Err(OsHintError::AssertionFailed { + message: format!( + "Tree height ({tree_height}) does not match Merkle height ({merkle_height})." + ), + }); + } + + Ok(()) +} + +fn set_preimage_for_commitments( + commitment_type: CommitmentType, + HintArgs { hint_processor, vm, exec_scopes, ids_data, ap_tracking, constants }: HintArgs<'_, S>, +) -> OsHintResult { + let os_input = &hint_processor.execution_helper.os_input; + let CommitmentInfo { previous_root, updated_root, commitment_facts, tree_height } = + match commitment_type { + CommitmentType::Class => &os_input.contract_class_commitment_info, + CommitmentType::State => &os_input.contract_state_commitment_info, + }; + insert_value_from_var_name( + Ids::InitialRoot.into(), + previous_root.0, + vm, + ids_data, + ap_tracking, + )?; + insert_value_from_var_name(Ids::FinalRoot.into(), updated_root.0, vm, ids_data, ap_tracking)?; + + // TODO(Dori): See if we can avoid the clone() here. Possible method: using `take()` to take + // ownership; we should, however, somehow invalidate the + // `os_input.contract_state_commitment_info.commitment_facts` field in this case (panic if + // accessed again after this line). + exec_scopes.insert_value(Scope::Preimage.into(), commitment_facts.clone()); + + let merkle_height = Const::MerkleHeight.fetch(constants)?; + let tree_height: Felt = (*tree_height).into(); + verify_tree_height_eq_merkle_height(tree_height, *merkle_height)?; + + Ok(()) +} + +pub(crate) fn set_preimage_for_state_commitments( + hint_args: HintArgs<'_, S>, +) -> OsHintResult { + set_preimage_for_commitments(CommitmentType::State, hint_args) +} + +pub(crate) fn set_preimage_for_class_commitments( + hint_args: HintArgs<'_, S>, +) -> OsHintResult { + set_preimage_for_commitments(CommitmentType::Class, hint_args) +} + +pub(crate) fn set_preimage_for_current_commitment_info( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn load_edge(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn load_bottom(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn decode_node(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} diff --git a/crates/starknet_os/src/hints/hint_implementation/stateful_compression.rs b/crates/starknet_os/src/hints/hint_implementation/stateful_compression.rs new file mode 100644 index 00000000000..c7ca0e9c91b --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/stateful_compression.rs @@ -0,0 +1,151 @@ +use std::collections::HashMap; + +use blockifier::state::state_api::{State, StateReader}; +use cairo_vm::any_box; +use cairo_vm::hint_processor::builtin_hint_processor::hint_utils::{ + get_integer_from_var_name, + insert_value_into_ap, +}; + +use crate::hints::error::OsHintResult; +use crate::hints::hint_implementation::state::StateUpdatePointers; +use crate::hints::types::HintArgs; +use crate::hints::vars::{Const, Ids, Scope}; + +pub(crate) fn enter_scope_with_aliases( + HintArgs { exec_scopes, .. }: HintArgs<'_, S>, +) -> OsHintResult { + // Note that aliases, execution_helper and os_input do not enter the new scope as they are not + // needed. + let dict_manager = exec_scopes.get_dict_manager()?; + let state_update_pointers_str: &str = Scope::StateUpdatePointers.into(); + let state_update_pointers: &StateUpdatePointers = exec_scopes.get(state_update_pointers_str)?; + let new_scope = HashMap::from([ + (Scope::DictManager.into(), any_box!(dict_manager)), + (state_update_pointers_str.to_string(), any_box!(state_update_pointers)), + ]); + exec_scopes.enter_scope(new_scope); + Ok(()) +} + +pub(crate) fn key_lt_min_alias_alloc_value( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn assert_key_big_enough_for_alias( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn read_alias_from_key( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn write_next_alias_from_key( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn read_alias_counter( + HintArgs { hint_processor, vm, constants, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let aliases_contract_address = Const::get_alias_contract_address(constants)?; + let alias_counter_storage_key = Const::get_alias_counter_storage_key(constants)?; + let alias_counter = hint_processor + .execution_helper + .cached_state + .get_storage_at(aliases_contract_address, alias_counter_storage_key)?; + Ok(insert_value_into_ap(vm, alias_counter)?) +} + +pub(crate) fn initialize_alias_counter( + HintArgs { hint_processor, constants, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let aliases_contract_address = Const::get_alias_contract_address(constants)?; + let alias_counter_storage_key = Const::get_alias_counter_storage_key(constants)?; + let initial_available_alias = *Const::InitialAvailableAlias.fetch(constants)?; + Ok(hint_processor.execution_helper.cached_state.set_storage_at( + aliases_contract_address, + alias_counter_storage_key, + initial_available_alias, + )?) +} + +pub(crate) fn update_alias_counter( + HintArgs { hint_processor, constants, ids_data, ap_tracking, vm, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let aliases_contract_address = Const::get_alias_contract_address(constants)?; + let alias_counter_storage_key = Const::get_alias_counter_storage_key(constants)?; + let next_available_alias = + get_integer_from_var_name(Ids::NextAvailableAlias.into(), vm, ids_data, ap_tracking)?; + Ok(hint_processor.execution_helper.cached_state.set_storage_at( + aliases_contract_address, + alias_counter_storage_key, + next_available_alias, + )?) +} + +pub(crate) fn contract_address_le_max_for_compression( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn compute_commitments_on_finalized_state_with_aliases( + HintArgs { hint_processor, exec_scopes, .. }: HintArgs<'_, S>, +) -> OsHintResult { + // TODO(Nimrod): Consider moving this hint to `state.rs`. + // TODO(Nimrod): Try to avoid this clone. + exec_scopes.insert_value( + Scope::CommitmentInfoByAddress.into(), + hint_processor.execution_helper.os_input.address_to_storage_commitment_info.clone(), + ); + + Ok(()) +} + +pub(crate) fn guess_contract_addr_storage_ptr( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn update_contract_addr_to_storage_ptr( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn guess_aliases_contract_storage_ptr( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn update_aliases_contract_to_storage_ptr( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn guess_state_ptr(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn update_state_ptr(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn guess_classes_ptr(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn update_classes_ptr(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} diff --git a/crates/starknet_os/src/hints/hint_implementation/stateless_compression.rs b/crates/starknet_os/src/hints/hint_implementation/stateless_compression.rs new file mode 100644 index 00000000000..79898bd8f1e --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/stateless_compression.rs @@ -0,0 +1,4 @@ +pub mod implementation; +#[cfg(test)] +pub mod tests; +pub mod utils; diff --git a/crates/starknet_os/src/hints/hint_implementation/stateless_compression/implementation.rs b/crates/starknet_os/src/hints/hint_implementation/stateless_compression/implementation.rs new file mode 100644 index 00000000000..78ebf75dff8 --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/stateless_compression/implementation.rs @@ -0,0 +1,80 @@ +use std::collections::HashMap; + +use blockifier::state::state_api::StateReader; +use cairo_vm::hint_processor::builtin_hint_processor::hint_utils::{ + get_integer_from_var_name, + get_maybe_relocatable_from_var_name, + get_ptr_from_var_name, + insert_value_from_var_name, +}; +use cairo_vm::types::relocatable::MaybeRelocatable; +use starknet_types_core::felt::Felt; + +use super::utils::compress; +use crate::hints::error::OsHintResult; +use crate::hints::hint_implementation::stateless_compression::utils::TOTAL_N_BUCKETS; +use crate::hints::types::HintArgs; +use crate::hints::vars::{Ids, Scope}; + +pub(crate) fn dictionary_from_bucket( + HintArgs { exec_scopes, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let initial_dict: HashMap = (0..TOTAL_N_BUCKETS) + .map(|bucket_index| (Felt::from(bucket_index).into(), Felt::ZERO.into())) + .collect(); + exec_scopes.insert_box(Scope::InitialDict.into(), Box::new(initial_dict)); + Ok(()) +} + +pub(crate) fn get_prev_offset( + HintArgs { vm, exec_scopes, ids_data, ap_tracking, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let dict_manager = exec_scopes.get_dict_manager()?; + + let dict_ptr = get_ptr_from_var_name(Ids::DictPtr.into(), vm, ids_data, ap_tracking)?; + let dict_tracker = dict_manager.borrow().get_tracker(dict_ptr)?.get_dictionary_copy(); + exec_scopes.insert_box(Scope::DictTracker.into(), Box::new(dict_tracker)); + + let bucket_index = + get_maybe_relocatable_from_var_name(Ids::BucketIndex.into(), vm, ids_data, ap_tracking)?; + let prev_offset = + dict_manager.borrow_mut().get_tracker_mut(dict_ptr)?.get_value(&bucket_index)?.clone(); + insert_value_from_var_name(Ids::PrevOffset.into(), prev_offset, vm, ids_data, ap_tracking)?; + Ok(()) +} + +pub(crate) fn compression_hint( + HintArgs { vm, ids_data, ap_tracking, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let data_start = get_ptr_from_var_name(Ids::DataStart.into(), vm, ids_data, ap_tracking)?; + let data_end = get_ptr_from_var_name(Ids::DataEnd.into(), vm, ids_data, ap_tracking)?; + let data_size = (data_end - data_start)?; + + let compressed_dst = + get_ptr_from_var_name(Ids::CompressedDst.into(), vm, ids_data, ap_tracking)?; + let data = + vm.get_integer_range(data_start, data_size)?.into_iter().map(|f| *f).collect::>(); + let compress_result = + compress(&data).into_iter().map(MaybeRelocatable::Int).collect::>(); + + vm.write_arg(compressed_dst, &compress_result)?; + + Ok(()) +} + +pub(crate) fn set_decompressed_dst( + HintArgs { vm, ids_data, ap_tracking, .. }: HintArgs<'_, S>, +) -> OsHintResult { + let decompressed_dst = + get_ptr_from_var_name(Ids::DecompressedDst.into(), vm, ids_data, ap_tracking)?; + + let packed_felt = get_integer_from_var_name(Ids::PackedFelt.into(), vm, ids_data, ap_tracking)?; + let elm_bound = get_integer_from_var_name(Ids::ElmBound.into(), vm, ids_data, ap_tracking)?; + + vm.insert_value( + decompressed_dst, + packed_felt.div_rem(&elm_bound.try_into().expect("elm_bound is zero")).1, + )?; + + Ok(()) +} diff --git a/crates/starknet_os/src/hints/hint_implementation/stateless_compression/tests.rs b/crates/starknet_os/src/hints/hint_implementation/stateless_compression/tests.rs new file mode 100644 index 00000000000..fa369f018f1 --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/stateless_compression/tests.rs @@ -0,0 +1,342 @@ +use std::cmp::min; +use std::collections::HashSet; + +use assert_matches::assert_matches; +use num_bigint::BigUint; +use num_integer::Integer; +use num_traits::ToPrimitive; +use rstest::rstest; +use starknet_types_core::felt::Felt; + +use super::utils::{ + compress, + felt_from_bits_le, + get_bucket_offsets, + get_n_elms_per_felt, + pack_usize_in_felts, + BitLength, + BitsArray, + BucketElement, + BucketElement125, + BucketElement31, + BucketElement62, + BucketElementTrait, + Buckets, + CompressionSet, + COMPRESSION_VERSION, + HEADER_ELM_BOUND, + N_UNIQUE_BUCKETS, + TOTAL_N_BUCKETS, +}; +use crate::hints::error::OsHintError; + +const HEADER_LEN: usize = 1 + 1 + TOTAL_N_BUCKETS; +// Utils + +pub fn unpack_felts( + compressed: &[Felt], + n_elms: usize, +) -> Vec> { + let n_elms_per_felt = BitLength::min_bit_length(LENGTH).unwrap().n_elems_in_felt(); + let mut result = Vec::with_capacity(n_elms); + + for felt in compressed { + let n_packed_elms = min(n_elms_per_felt, n_elms - result.len()); + for chunk in felt.to_bits_le()[0..n_packed_elms * LENGTH].chunks_exact(LENGTH) { + result.push(BitsArray(chunk.try_into().unwrap())); + } + } + + result +} + +pub fn unpack_felts_to_usize(compressed: &[Felt], n_elms: usize, elm_bound: u32) -> Vec { + let n_elms_per_felt = get_n_elms_per_felt(elm_bound); + let elm_bound_as_big = BigUint::from(elm_bound); + let mut result = Vec::with_capacity(n_elms); + + for felt in compressed { + let mut remaining = felt.to_biguint(); + let n_packed_elms = min(n_elms_per_felt, n_elms - result.len()); + for _ in 0..n_packed_elms { + let (new_remaining, value) = remaining.div_rem(&elm_bound_as_big); + result.push(value.to_usize().unwrap()); + remaining = new_remaining; + } + } + + result +} + +/// Decompresses the given compressed data. +pub fn decompress(compressed: &mut impl Iterator) -> Vec { + fn unpack_chunk( + compressed: &mut impl Iterator, + n_elms: usize, + ) -> Vec { + let n_elms_per_felt = BitLength::min_bit_length(LENGTH).unwrap().n_elems_in_felt(); + let n_packed_felts = n_elms.div_ceil(n_elms_per_felt); + let compressed_chunk: Vec<_> = compressed.take(n_packed_felts).collect(); + unpack_felts(&compressed_chunk, n_elms) + .into_iter() + .map(|bits: BitsArray| felt_from_bits_le(&bits.0).unwrap()) + .collect() + } + + fn unpack_chunk_to_usize( + compressed: &mut impl Iterator, + n_elms: usize, + elm_bound: u32, + ) -> Vec { + let n_elms_per_felt = get_n_elms_per_felt(elm_bound); + let n_packed_felts = n_elms.div_ceil(n_elms_per_felt); + + let compressed_chunk: Vec<_> = compressed.take(n_packed_felts).collect(); + unpack_felts_to_usize(&compressed_chunk, n_elms, elm_bound) + } + + let header = unpack_chunk_to_usize(compressed, HEADER_LEN, HEADER_ELM_BOUND); + let version = &header[0]; + assert!(version == &usize::from(COMPRESSION_VERSION), "Unsupported compression version."); + + let data_len = &header[1]; + let unique_value_bucket_lengths: Vec = header[2..2 + N_UNIQUE_BUCKETS].to_vec(); + let n_repeating_values = &header[2 + N_UNIQUE_BUCKETS]; + + let mut unique_values = Vec::new(); + unique_values.extend(compressed.take(unique_value_bucket_lengths[0])); // 252 bucket. + unique_values.extend(unpack_chunk::<125>(compressed, unique_value_bucket_lengths[1])); + unique_values.extend(unpack_chunk::<83>(compressed, unique_value_bucket_lengths[2])); + unique_values.extend(unpack_chunk::<62>(compressed, unique_value_bucket_lengths[3])); + unique_values.extend(unpack_chunk::<31>(compressed, unique_value_bucket_lengths[4])); + unique_values.extend(unpack_chunk::<15>(compressed, unique_value_bucket_lengths[5])); + + let repeating_value_pointers = unpack_chunk_to_usize( + compressed, + *n_repeating_values, + unique_values.len().try_into().unwrap(), + ); + + let repeating_values: Vec<_> = + repeating_value_pointers.iter().map(|ptr| unique_values[*ptr]).collect(); + + let mut all_values = unique_values; + all_values.extend(repeating_values); + + let bucket_index_per_elm: Vec = + unpack_chunk_to_usize(compressed, *data_len, TOTAL_N_BUCKETS.try_into().unwrap()); + + let all_bucket_lengths: Vec = + unique_value_bucket_lengths.into_iter().chain([*n_repeating_values]).collect(); + + let bucket_offsets = get_bucket_offsets(&all_bucket_lengths); + + let mut bucket_offset_trackers: Vec<_> = bucket_offsets; + + let mut result = Vec::new(); + for bucket_index in bucket_index_per_elm { + let offset = &mut bucket_offset_trackers[bucket_index]; + let value = all_values[*offset]; + *offset += 1; + result.push(value); + } + result +} + +// Tests + +#[rstest] +#[case::zero([false; 10], Felt::ZERO)] +#[case::thousand( + [false, false, false, true, false, true, true, true, true, true], + Felt::from(0b_0000_0011_1110_1000_u16), +)] +fn test_bits_array(#[case] expected: [bool; 10], #[case] felt: Felt) { + assert_eq!(BitsArray::<10>::try_from(felt).unwrap().0, expected); +} + +#[rstest] +#[case::max_fits(16, Felt::from(0xFFFF_u16))] +#[case::overflow(252, Felt::MAX)] +fn test_overflow_bits_array(#[case] n_bits_felt: usize, #[case] felt: Felt) { + let error = BitsArray::<10>::try_from(felt).unwrap_err(); + assert_matches!( + error, OsHintError::StatelessCompressionOverflow { n_bits, .. } if n_bits == n_bits_felt + ); +} + +#[test] +fn test_pack_and_unpack() { + let felts = [ + Felt::from(34_u32), + Felt::from(0_u32), + Felt::from(11111_u32), + Felt::from(1034_u32), + Felt::from(3404_u32), + ]; + let bucket: Vec<_> = + felts.into_iter().map(|f| BucketElement125::try_from(f).unwrap()).collect(); + let packed = BucketElement125::pack_in_felts(&bucket); + let unpacked = unpack_felts(packed.as_ref(), bucket.len()); + assert_eq!(bucket, unpacked); +} + +#[test] +fn test_buckets() { + let mut buckets = Buckets::new(); + buckets.add(BucketElement::BucketElement31(BucketElement31::try_from(Felt::ONE).unwrap())); + buckets.add(BucketElement::BucketElement62(BucketElement62::try_from(Felt::TWO).unwrap())); + let bucket62_3 = + BucketElement::BucketElement62(BucketElement62::try_from(Felt::THREE).unwrap()); + buckets.add(bucket62_3.clone()); + + assert_eq!(buckets.get_element_index(&bucket62_3), Some(&1_usize)); + assert_eq!(buckets.lengths(), [0, 0, 0, 2, 1, 0]); +} + +#[test] +fn test_usize_pack_and_unpack() { + let nums = vec![34, 0, 11111, 1034, 3404, 16, 32, 127, 129, 128]; + let elm_bound = 12345; + let packed = pack_usize_in_felts(&nums, elm_bound); + let unpacked = unpack_felts_to_usize(packed.as_ref(), nums.len(), elm_bound); + assert_eq!(nums, unpacked); +} + +#[test] +fn test_get_bucket_offsets() { + let lengths = vec![2, 3, 5]; + let offsets = get_bucket_offsets(&lengths); + assert_eq!(offsets, [0, 2, 5]); +} + +#[rstest] +#[case::unique_values( + vec![ + Felt::from(42), // < 15 bits + Felt::from(12833943439439439_u64), // 54 bits + Felt::from(1283394343), // 31 bits + ], + [0, 0, 0, 1, 1, 1], + 0, + vec![], +)] +#[case::repeated_values( + vec![ + Felt::from(43), + Felt::from(42), + Felt::from(42), + Felt::from(42), + ], + [0, 0, 0, 0, 0, 2], + 2, + vec![1, 1], +)] +#[case::edge_bucket_values( + vec![ + Felt::from((BigUint::from(1_u8) << 15) - 1_u8), + Felt::from(BigUint::from(1_u8) << 15), + Felt::from((BigUint::from(1_u8) << 31) - 1_u8), + Felt::from(BigUint::from(1_u8) << 31), + Felt::from((BigUint::from(1_u8) << 62) - 1_u8), + Felt::from(BigUint::from(1_u8) << 62), + Felt::from((BigUint::from(1_u8) << 83) - 1_u8), + Felt::from(BigUint::from(1_u8) << 83), + Felt::from((BigUint::from(1_u8) << 125) - 1_u8), + Felt::from(BigUint::from(1_u8) << 125), + Felt::MAX, + ], + [2, 2, 2, 2, 2, 1], + 0, + vec![], +)] +fn test_update_with_unique_values( + #[case] values: Vec, + #[case] expected_unique_lengths: [usize; N_UNIQUE_BUCKETS], + #[case] expected_n_repeating_values: usize, + #[case] expected_repeating_value_pointers: Vec, +) { + let compression_set = CompressionSet::new(&values); + assert_eq!(expected_unique_lengths, compression_set.get_unique_value_bucket_lengths()); + assert_eq!(expected_n_repeating_values, compression_set.n_repeating_values()); + assert_eq!(expected_repeating_value_pointers, compression_set.get_repeating_value_pointers()); +} + +// These values are calculated by importing the module and running the compression method +// ```py +// # import compress from compression +// def main() -> int: +// print(compress([2,3,1])) +// return 0 +// ``` +#[rstest] +#[case::single_value_1(vec![1u32], vec!["0x100000000000000000000000000000100000", "0x1", "0x5"])] +#[case::single_value_2(vec![2u32], vec!["0x100000000000000000000000000000100000", "0x2", "0x5"])] +#[case::single_value_3(vec![10u32], vec!["0x100000000000000000000000000000100000", "0xA", "0x5"])] +#[case::two_values(vec![1u32, 2], vec!["0x200000000000000000000000000000200000", "0x10001", "0x28"])] +#[case::three_values(vec![2u32, 3, 1], vec!["0x300000000000000000000000000000300000", "0x40018002", "0x11d"])] +#[case::four_values(vec![1u32, 2, 3, 4], vec!["0x400000000000000000000000000000400000", "0x8000c0010001", "0x7d0"])] +#[case::extracted_kzg_example(vec![1u32, 1, 6, 1991, 66, 0], vec!["0x10000500000000000000000000000000000600000", "0x841f1c0030001", "0x0", "0x17eff"])] + +fn test_compress_decompress(#[case] input: Vec, #[case] expected: Vec<&str>) { + let data: Vec<_> = input.into_iter().map(Felt::from).collect(); + let compressed = compress(&data); + let expected: Vec<_> = expected.iter().map(|s| Felt::from_hex_unchecked(s)).collect(); + assert_eq!(compressed, expected); + + let decompressed = decompress(&mut compressed.into_iter()); + assert_eq!(decompressed, data); +} + +#[rstest] +#[case::no_values( + vec![], + 0, // No buckets. + None, +)] +#[case::single_value_1( + vec![Felt::from(7777777)], + 1, // A single bucket with one value. + Some(300), // 1 header, 1 value, 1 pointer +)] +#[case::large_duplicates( + vec![Felt::from(BigUint::from(2_u8).pow(250)); 100], + 1, // Should remove duplicated values. + Some(5), +)] +#[case::small_values( + (0..0x8000).map(Felt::from).collect(), + 2048, // = 2**15/(251/15), as all elements are packed in the 15-bits bucket. + Some(7), +)] +#[case::mixed_buckets( + (0..252).map(|i| Felt::from(BigUint::from(2_u8).pow(i))).collect(), + 1 + 2 + 8 + 7 + 21 + 127, // All buckets are involved here. + Some(67), // More than half of the values are in the biggest (252-bit) bucket. +)] +fn test_compression_length( + #[case] data: Vec, + #[case] expected_unique_values_packed_length: usize, + #[case] expected_compression_percents: Option, +) { + let compressed = compress(&data); + + let n_unique_values = data.iter().collect::>().len(); + let n_repeated_values = data.len() - n_unique_values; + let expected_repeated_value_pointers_packed_length = + n_repeated_values.div_ceil(get_n_elms_per_felt(u32::try_from(n_unique_values).unwrap())); + let expected_bucket_indices_packed_length = + data.len().div_ceil(get_n_elms_per_felt(u32::try_from(TOTAL_N_BUCKETS).unwrap())); + + assert_eq!( + compressed.len(), + 1 + expected_unique_values_packed_length + + expected_repeated_value_pointers_packed_length + + expected_bucket_indices_packed_length + ); + + if let Some(expected_compression_percents_val) = expected_compression_percents { + assert_eq!(100 * compressed.len() / data.len(), expected_compression_percents_val); + } + assert_eq!(data, decompress(&mut compressed.into_iter())); +} diff --git a/crates/starknet_os/src/hints/hint_implementation/stateless_compression/utils.rs b/crates/starknet_os/src/hints/hint_implementation/stateless_compression/utils.rs new file mode 100644 index 00000000000..fe268e6789d --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/stateless_compression/utils.rs @@ -0,0 +1,483 @@ +use std::any::type_name; +use std::cmp::max; +use std::hash::Hash; + +use indexmap::IndexMap; +use num_bigint::BigUint; +use num_traits::{ToPrimitive, Zero}; +use starknet_types_core::felt::Felt; +use strum::EnumCount; +use strum_macros::Display; + +use crate::hints::error::OsHintError; + +pub(crate) const COMPRESSION_VERSION: u8 = 0; +pub(crate) const HEADER_ELM_N_BITS: usize = 20; +pub(crate) const HEADER_ELM_BOUND: u32 = 1 << HEADER_ELM_N_BITS; + +pub(crate) const N_UNIQUE_BUCKETS: usize = BitLength::COUNT; +/// Number of buckets, including the repeating values bucket. +pub(crate) const TOTAL_N_BUCKETS: usize = N_UNIQUE_BUCKETS + 1; + +pub(crate) const MAX_N_BITS: usize = 251; + +#[derive(Debug, Display, strum_macros::EnumCount)] +pub(crate) enum BitLength { + Bits15, + Bits31, + Bits62, + Bits83, + Bits125, + Bits252, +} + +impl BitLength { + const fn n_bits(&self) -> usize { + match self { + Self::Bits15 => 15, + Self::Bits31 => 31, + Self::Bits62 => 62, + Self::Bits83 => 83, + Self::Bits125 => 125, + Self::Bits252 => 252, + } + } + + pub(crate) fn n_elems_in_felt(&self) -> usize { + max(MAX_N_BITS / self.n_bits(), 1) + } + + pub(crate) fn min_bit_length(n_bits: usize) -> Result { + match n_bits { + _ if n_bits <= 15 => Ok(Self::Bits15), + _ if n_bits <= 31 => Ok(Self::Bits31), + _ if n_bits <= 62 => Ok(Self::Bits62), + _ if n_bits <= 83 => Ok(Self::Bits83), + _ if n_bits <= 125 => Ok(Self::Bits125), + _ if n_bits <= 252 => Ok(Self::Bits252), + _ => Err(OsHintError::StatelessCompressionOverflow { + n_bits, + type_name: type_name::().to_string(), + }), + } + } +} + +/// A struct representing a vector of bits with a specified size. +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub(crate) struct BitsArray(pub(crate) [bool; LENGTH]); + +impl TryFrom for BitsArray { + type Error = OsHintError; + + // Cloned the first `LENGTH` bits of the felt. + fn try_from(felt: Felt) -> Result { + let n_bits_felt = felt.bits(); + if n_bits_felt > LENGTH { + return Err(Self::Error::StatelessCompressionOverflow { + n_bits: n_bits_felt, + type_name: type_name::().to_string(), + }); + } + Ok(Self(felt.to_bits_le()[0..LENGTH].try_into().expect("Too many bits in Felt"))) + } +} + +impl TryFrom> for Felt { + type Error = OsHintError; + + fn try_from(bits_array: BitsArray) -> Result { + felt_from_bits_le(&bits_array.0) + } +} + +pub(crate) type BucketElement15 = BitsArray<15>; +pub(crate) type BucketElement31 = BitsArray<31>; +pub(crate) type BucketElement62 = BitsArray<62>; +pub(crate) type BucketElement83 = BitsArray<83>; +pub(crate) type BucketElement125 = BitsArray<125>; +pub(crate) type BucketElement252 = Felt; + +/// Returns an error in case the length is not guaranteed to fit in Felt (more than 251 bits). +pub(crate) fn felt_from_bits_le(bits: &[bool]) -> Result { + if bits.len() > MAX_N_BITS { + return Err(OsHintError::StatelessCompressionOverflow { + n_bits: bits.len(), + type_name: type_name::().to_string(), + }); + } + + let mut bytes = [0_u8; 32]; + for (byte_idx, chunk) in bits.chunks(8).enumerate() { + let mut byte = 0_u8; + for (bit_idx, bit) in chunk.iter().enumerate() { + if *bit { + byte |= 1 << bit_idx; + } + } + bytes[byte_idx] = byte; + } + Ok(Felt::from_bytes_le(&bytes)) +} + +pub(crate) trait BucketElementTrait: Sized { + fn pack_in_felts(elms: &[Self]) -> Vec; +} + +macro_rules! impl_bucket_element_trait { + ($bucket_element:ident, $bit_length:ident) => { + impl BucketElementTrait for $bucket_element { + fn pack_in_felts(elms: &[Self]) -> Vec { + let bit_length = BitLength::$bit_length; + elms.chunks(bit_length.n_elems_in_felt()) + .map(|chunk| { + felt_from_bits_le( + &(chunk + .iter() + .flat_map(|elem| elem.0.as_ref()) + .copied() + .collect::>()), + ) + .unwrap_or_else(|_| { + panic!( + "Chunks of size {}, each of bit length {}, fit in felts.", + bit_length.n_elems_in_felt(), + bit_length + ) + }) + }) + .collect() + } + } + }; +} + +impl_bucket_element_trait!(BucketElement15, Bits15); +impl_bucket_element_trait!(BucketElement31, Bits31); +impl_bucket_element_trait!(BucketElement62, Bits62); +impl_bucket_element_trait!(BucketElement83, Bits83); +impl_bucket_element_trait!(BucketElement125, Bits125); + +impl BucketElementTrait for BucketElement252 { + fn pack_in_felts(elms: &[Self]) -> Vec { + elms.to_vec() + } +} + +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub(crate) enum BucketElement { + BucketElement15(BucketElement15), + BucketElement31(BucketElement31), + BucketElement62(BucketElement62), + BucketElement83(BucketElement83), + BucketElement125(BucketElement125), + BucketElement252(BucketElement252), +} + +impl From for BucketElement { + fn from(felt: Felt) -> Self { + match BitLength::min_bit_length(felt.bits()).expect("felt is up to 252 bits") { + BitLength::Bits15 => { + BucketElement::BucketElement15(felt.try_into().expect("Up to 15 bits")) + } + BitLength::Bits31 => { + BucketElement::BucketElement31(felt.try_into().expect("Up to 31 bits")) + } + BitLength::Bits62 => { + BucketElement::BucketElement62(felt.try_into().expect("Up to 62 bits")) + } + BitLength::Bits83 => { + BucketElement::BucketElement83(felt.try_into().expect("Up to 83 bits")) + } + BitLength::Bits125 => { + BucketElement::BucketElement125(felt.try_into().expect("Up to 125 bits")) + } + BitLength::Bits252 => BucketElement::BucketElement252(felt), + } + } +} + +/// Holds IndexMap of unique values of the same size in bits. +#[derive(Default, Clone, Debug)] +struct UniqueValueBucket { + value_to_index: IndexMap, +} + +impl UniqueValueBucket { + fn new() -> Self { + Self { value_to_index: Default::default() } + } + + fn len(&self) -> usize { + self.value_to_index.len() + } + + fn contains(&self, value: &SizedElement) -> bool { + self.value_to_index.contains_key(value) + } + + fn add(&mut self, value: SizedElement) { + if !self.contains(&value) { + let next_index = self.value_to_index.len(); + self.value_to_index.insert(value, next_index); + } + } + + fn get_index(&self, value: &SizedElement) -> Option<&usize> { + self.value_to_index.get(value) + } + + fn pack_in_felts(self) -> Vec { + let values = self.value_to_index.into_keys().collect::>(); + SizedElement::pack_in_felts(&values) + } +} + +#[derive(Clone, Debug)] +pub(crate) struct Buckets { + bucket15: UniqueValueBucket, + bucket31: UniqueValueBucket, + bucket62: UniqueValueBucket, + bucket83: UniqueValueBucket, + bucket125: UniqueValueBucket, + bucket252: UniqueValueBucket, +} + +impl Buckets { + pub(crate) fn new() -> Self { + Self { + bucket15: UniqueValueBucket::new(), + bucket31: UniqueValueBucket::new(), + bucket62: UniqueValueBucket::new(), + bucket83: UniqueValueBucket::new(), + bucket125: UniqueValueBucket::new(), + bucket252: UniqueValueBucket::new(), + } + } + + /// Returns the bucket index and the inverse bucket index. + fn bucket_index(&self, bucket_element: &BucketElement) -> (usize, usize) { + let bucket_index = match bucket_element { + BucketElement::BucketElement15(_) => 0, + BucketElement::BucketElement31(_) => 1, + BucketElement::BucketElement62(_) => 2, + BucketElement::BucketElement83(_) => 3, + BucketElement::BucketElement125(_) => 4, + BucketElement::BucketElement252(_) => 5, + }; + (bucket_index, N_UNIQUE_BUCKETS - 1 - bucket_index) + } + + /// Returns the index of the element in the respective bucket. + pub(crate) fn get_element_index(&self, bucket_element: &BucketElement) -> Option<&usize> { + match bucket_element { + BucketElement::BucketElement15(bucket_element15) => { + self.bucket15.get_index(bucket_element15) + } + BucketElement::BucketElement31(bucket_element31) => { + self.bucket31.get_index(bucket_element31) + } + BucketElement::BucketElement62(bucket_element62) => { + self.bucket62.get_index(bucket_element62) + } + BucketElement::BucketElement83(bucket_element83) => { + self.bucket83.get_index(bucket_element83) + } + BucketElement::BucketElement125(bucket_element125) => { + self.bucket125.get_index(bucket_element125) + } + BucketElement::BucketElement252(bucket_element252) => { + self.bucket252.get_index(bucket_element252) + } + } + } + + pub(crate) fn add(&mut self, bucket_element: BucketElement) { + match bucket_element { + BucketElement::BucketElement15(bucket_element15) => self.bucket15.add(bucket_element15), + BucketElement::BucketElement31(bucket_element31) => self.bucket31.add(bucket_element31), + BucketElement::BucketElement62(bucket_element62) => self.bucket62.add(bucket_element62), + BucketElement::BucketElement83(bucket_element83) => self.bucket83.add(bucket_element83), + BucketElement::BucketElement125(bucket_element125) => { + self.bucket125.add(bucket_element125) + } + BucketElement::BucketElement252(bucket_element252) => { + self.bucket252.add(bucket_element252) + } + } + } + + /// Returns the lengths of the buckets from the bucket with the largest numbers to the bucket + /// with the smallest. + pub(crate) fn lengths(&self) -> [usize; N_UNIQUE_BUCKETS] { + [ + self.bucket252.len(), + self.bucket125.len(), + self.bucket83.len(), + self.bucket62.len(), + self.bucket31.len(), + self.bucket15.len(), + ] + } + + /// Chains the buckets from the bucket with the largest numbers to the bucket with the smallest, + /// and packed them into felts. + fn pack_in_felts(self) -> Vec { + [ + self.bucket15.pack_in_felts(), + self.bucket31.pack_in_felts(), + self.bucket62.pack_in_felts(), + self.bucket83.pack_in_felts(), + self.bucket125.pack_in_felts(), + self.bucket252.pack_in_felts(), + ] + .into_iter() + .rev() + .flatten() + .collect() + } +} + +/// A utility class for compression. +/// Used to manage and store the unique values in separate buckets according to their bit length. +#[derive(Clone, Debug)] +pub(crate) struct CompressionSet { + unique_value_buckets: Buckets, + /// For each repeating value, holds the unique bucket index and the index of the element in the + /// bucket. + repeating_value_bucket: Vec<(usize, usize)>, + /// For each element(including the repeating values), holds the containing bucket index. + bucket_index_per_elm: Vec, +} + +impl CompressionSet { + /// Creates a new Compression set. + /// Iterates over the provided values and assigns each value to the appropriate bucket based on + /// the number of bits required to represent it. If a value is already in a bucket, it is + /// recorded as a repeating value. Otherwise, it is added to the appropriate bucket. + pub fn new(values: &[Felt]) -> Self { + let mut obj = Self { + unique_value_buckets: Buckets::new(), + repeating_value_bucket: Vec::new(), + bucket_index_per_elm: Vec::new(), + }; + let repeating_values_bucket_index = N_UNIQUE_BUCKETS; + + for value in values { + let bucket_element = BucketElement::from(*value); + let (bucket_index, inverse_bucket_index) = + obj.unique_value_buckets.bucket_index(&bucket_element); + if let Some(element_index) = obj.unique_value_buckets.get_element_index(&bucket_element) + { + obj.repeating_value_bucket.push((bucket_index, *element_index)); + obj.bucket_index_per_elm.push(repeating_values_bucket_index); + } else { + obj.unique_value_buckets.add(bucket_element.clone()); + obj.bucket_index_per_elm.push(inverse_bucket_index); + } + } + obj + } + + pub fn get_unique_value_bucket_lengths(&self) -> [usize; N_UNIQUE_BUCKETS] { + self.unique_value_buckets.lengths() + } + + pub fn n_repeating_values(&self) -> usize { + self.repeating_value_bucket.len() + } + + /// Converts the repeating value locations from (bucket, index) to a global index in the chained + /// buckets. + pub fn get_repeating_value_pointers(&self) -> Vec { + let unique_value_bucket_lengths = self.get_unique_value_bucket_lengths(); + let bucket_offsets = get_bucket_offsets(&unique_value_bucket_lengths); + + self.repeating_value_bucket + .iter() + .map(|&(bucket_index, index_in_bucket)| bucket_offsets[bucket_index] + index_in_bucket) + .collect() + } + + pub fn pack_unique_values(self) -> Vec { + self.unique_value_buckets.pack_in_felts() + } +} + +/// Compresses the data provided to output a Vec of compressed Felts. +pub(crate) fn compress(data: &[Felt]) -> Vec { + assert!( + data.len() < HEADER_ELM_BOUND.to_usize().expect("usize overflow"), + "Data is too long: {} >= {HEADER_ELM_BOUND}.", + data.len() + ); + + let compression_set = CompressionSet::new(data); + + let unique_value_bucket_lengths = compression_set.get_unique_value_bucket_lengths(); + let n_unique_values: usize = unique_value_bucket_lengths.iter().sum(); + + let header: Vec = [COMPRESSION_VERSION.into(), data.len()] + .into_iter() + .chain(unique_value_bucket_lengths) + .chain([compression_set.n_repeating_values()]) + .collect(); + + let packed_header = pack_usize_in_felts(&header, HEADER_ELM_BOUND); + let packed_repeating_value_pointers = pack_usize_in_felts( + &compression_set.get_repeating_value_pointers(), + u32::try_from(n_unique_values).expect("Too many unique values"), + ); + let packed_bucket_index_per_elm = pack_usize_in_felts( + &compression_set.bucket_index_per_elm, + u32::try_from(TOTAL_N_BUCKETS).expect("Too many buckets"), + ); + + let unique_values = compression_set.pack_unique_values(); + [packed_header, unique_values, packed_repeating_value_pointers, packed_bucket_index_per_elm] + .into_iter() + .flatten() + .collect() +} + +/// Calculates the number of elements with the same bit length as the element bound, that can fit +/// into a single felt value. +pub fn get_n_elms_per_felt(elm_bound: u32) -> usize { + if elm_bound <= 1 { + return MAX_N_BITS; + } + let n_bits_required = elm_bound.ilog2() + 1; + MAX_N_BITS / usize::try_from(n_bits_required).expect("usize overflow") +} + +/// Packs a list of elements into multiple felts, ensuring that each felt contains as many elements +/// as can fit. +pub fn pack_usize_in_felts(elms: &[usize], elm_bound: u32) -> Vec { + elms.chunks(get_n_elms_per_felt(elm_bound)) + .map(|chunk| pack_usize_in_felt(chunk, elm_bound)) + .collect() +} + +/// Packs a chunk of elements into a single felt. Assumes that the elms fit in a felt. +fn pack_usize_in_felt(elms: &[usize], elm_bound: u32) -> Felt { + let elm_bound_as_big = BigUint::from(elm_bound); + elms.iter() + .enumerate() + .fold(BigUint::zero(), |acc, (i, elm)| { + acc + BigUint::from(*elm) * elm_bound_as_big.pow(u32::try_from(i).expect("fit u32")) + }) + .into() +} + +/// Computes the starting offsets for each bucket in a list of buckets, based on their lengths. +pub(crate) fn get_bucket_offsets(bucket_lengths: &[usize]) -> Vec { + let mut offsets = Vec::with_capacity(bucket_lengths.len()); + let mut current = 0; + + for &length in bucket_lengths { + offsets.push(current); + current += length; + } + + offsets +} diff --git a/crates/starknet_os/src/hints/hint_implementation/syscalls.rs b/crates/starknet_os/src/hints/hint_implementation/syscalls.rs new file mode 100644 index 00000000000..46ddeb40b21 --- /dev/null +++ b/crates/starknet_os/src/hints/hint_implementation/syscalls.rs @@ -0,0 +1,100 @@ +use blockifier::state::state_api::StateReader; +use cairo_vm::hint_processor::builtin_hint_processor::hint_utils::get_ptr_from_var_name; + +use crate::hints::error::OsHintResult; +use crate::hints::types::HintArgs; +use crate::hints::vars::Ids; + +pub(crate) fn call_contract(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn delegate_call(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn delegate_l1_handler( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn deploy(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn emit_event(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn get_block_number(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn get_block_timestamp( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn get_caller_address(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn get_contract_address( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn get_sequencer_address( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn get_tx_info(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn get_tx_signature(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn library_call(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn library_call_l1_handler( + HintArgs { .. }: HintArgs<'_, S>, +) -> OsHintResult { + todo!() +} + +pub(crate) fn replace_class(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn send_message_to_l1(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn storage_read(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn storage_write(HintArgs { .. }: HintArgs<'_, S>) -> OsHintResult { + todo!() +} + +pub(crate) fn set_syscall_ptr( + HintArgs { hint_processor, vm, ids_data, ap_tracking, .. }: HintArgs<'_, S>, +) -> OsHintResult { + hint_processor.syscall_hint_processor.set_syscall_ptr(get_ptr_from_var_name( + Ids::SyscallPtr.into(), + vm, + ids_data, + ap_tracking, + )?); + Ok(()) +} diff --git a/crates/starknet_os/src/hints/nondet_offsets.rs b/crates/starknet_os/src/hints/nondet_offsets.rs new file mode 100644 index 00000000000..ac86add54a8 --- /dev/null +++ b/crates/starknet_os/src/hints/nondet_offsets.rs @@ -0,0 +1,44 @@ +use std::collections::HashMap; +use std::sync::LazyLock; + +use cairo_vm::types::relocatable::MaybeRelocatable; +use cairo_vm::vm::vm_core::VirtualMachine; + +use crate::hints::enum_definition::{AllHints, OsHint}; +use crate::hints::error::{OsHintError, OsHintResult}; + +#[cfg(test)] +#[path = "nondet_offsets_test.rs"] +pub mod test; + +/// Hashmap in which the keys are all hints compiled from cairo code of the form +/// `local x = nondet %{ y %}`. The resulting hint string will be of the form +/// `memory[fp + O] = to_felt_or_relocatable(y)` for some offset `O` depending on the cairo code in +/// the respective function (locals before this line can effect the offset). We keep track of the +/// values here, and test for consistency with the hint string; the offset in the hint +/// implementation should be fetched from this map. +pub(crate) static NONDET_FP_OFFSETS: LazyLock> = LazyLock::new(|| { + HashMap::from([ + (AllHints::OsHint(OsHint::OsInputTransactions), 12), + (AllHints::OsHint(OsHint::ReadAliasFromKey), 0), + (AllHints::OsHint(OsHint::SegmentsAddTemp), 7), + (AllHints::OsHint(OsHint::SetFpPlus4ToTxNonce), 4), + (AllHints::OsHint(OsHint::GetBlocksNumber), 0), + (AllHints::OsHint(OsHint::TxAccountDeploymentDataLen), 4), + (AllHints::OsHint(OsHint::WriteFullOutputToMemory), 20), + (AllHints::OsHint(OsHint::WriteUseKzgDaToMemory), 19), + ]) +}); + +fn fetch_offset(hint: AllHints) -> Result { + Ok(*NONDET_FP_OFFSETS.get(&hint).ok_or(OsHintError::MissingOffsetForHint { hint })?) +} + +pub(crate) fn insert_nondet_hint_value>( + vm: &mut VirtualMachine, + hint: AllHints, + value: T, +) -> OsHintResult { + let offset = fetch_offset(hint)?; + Ok(vm.insert_value((vm.get_fp() + offset)?, value)?) +} diff --git a/crates/starknet_os/src/hints/nondet_offsets_test.rs b/crates/starknet_os/src/hints/nondet_offsets_test.rs new file mode 100644 index 00000000000..0682b512ed8 --- /dev/null +++ b/crates/starknet_os/src/hints/nondet_offsets_test.rs @@ -0,0 +1,29 @@ +use std::collections::HashSet; + +use crate::hints::enum_definition::AllHints; +use crate::hints::nondet_offsets::NONDET_FP_OFFSETS; +use crate::hints::types::HintEnum; + +#[test] +fn test_nondet_offset_strings() { + for (hint, offset) in NONDET_FP_OFFSETS.iter() { + let hint_str = hint.to_str(); + let expected_prefix = format!("memory[fp + {offset}]"); + assert!( + hint_str.starts_with(&expected_prefix), + "Mismatch between hint string and offset: expected '{expected_prefix}' as a prefix of \ + hint '{hint_str}'." + ); + } +} + +#[test] +fn test_nondet_hints_have_offsets() { + let nondet_hints: HashSet = + AllHints::all_iter().filter(|hint| hint.to_str().starts_with("memory[fp +")).collect(); + let hints_with_offsets: HashSet = NONDET_FP_OFFSETS.keys().copied().collect(); + assert_eq!( + nondet_hints, hints_with_offsets, + "Mismatch between hints with offsets and hints with 'memory[fp + ...]' prefix." + ); +} diff --git a/crates/starknet_os/src/hints/types.rs b/crates/starknet_os/src/hints/types.rs new file mode 100644 index 00000000000..849af12e63b --- /dev/null +++ b/crates/starknet_os/src/hints/types.rs @@ -0,0 +1,45 @@ +use std::collections::HashMap; + +use blockifier::state::state_api::StateReader; +use cairo_vm::hint_processor::hint_processor_definition::HintReference; +use cairo_vm::serde::deserialize_program::ApTracking; +use cairo_vm::types::exec_scope::ExecutionScopes; +use cairo_vm::vm::vm_core::VirtualMachine; +use starknet_types_core::felt::Felt; + +use crate::hint_processor::snos_hint_processor::SnosHintProcessor; +use crate::hints::error::{OsHintError, OsHintExtensionResult, OsHintResult}; + +/// Hint enum maps between a (python) hint string in the cairo OS program under cairo-lang to a +/// matching enum variant defined in the crate. +pub trait HintEnum { + fn from_str(hint_str: &str) -> Result + where + Self: Sized; + + fn to_str(&self) -> &'static str; +} + +pub struct HintArgs<'a, S: StateReader> { + pub hint_processor: &'a mut SnosHintProcessor, + pub vm: &'a mut VirtualMachine, + pub exec_scopes: &'a mut ExecutionScopes, + pub ids_data: &'a HashMap, + pub ap_tracking: &'a ApTracking, + pub constants: &'a HashMap, +} + +/// Executes the hint logic. +pub trait HintImplementation { + fn execute_hint(&self, hint_args: HintArgs<'_, S>) -> OsHintResult; +} + +/// Hint extensions extend the current map of hints used by the VM. +/// This behaviour achieves what the `vm_load_data` primitive does for cairo-lang and is needed to +/// implement OS hints like `vm_load_program`. +pub trait HintExtensionImplementation { + fn execute_hint_extensive( + &self, + hint_extension_args: HintArgs<'_, S>, + ) -> OsHintExtensionResult; +} diff --git a/crates/starknet_os/src/hints/vars.rs b/crates/starknet_os/src/hints/vars.rs new file mode 100644 index 00000000000..a4869b73dc0 --- /dev/null +++ b/crates/starknet_os/src/hints/vars.rs @@ -0,0 +1,365 @@ +use std::collections::HashMap; + +use cairo_vm::vm::errors::hint_errors::HintError; +use starknet_api::core::ContractAddress; +use starknet_api::state::StorageKey; +use starknet_types_core::felt::Felt; + +use crate::hints::error::OsHintError; + +#[derive(Copy, Clone)] +pub(crate) enum Scope { + BytecodeSegments, + BytecodeSegmentStructure, + BytecodeSegmentStructures, + Case, + CommitmentInfoByAddress, + CompiledClass, + CompiledClassFacts, + CompiledClassHash, + ComponentHashes, + DeprecatedClassHashes, + DictManager, + DictTracker, + InitialDict, + IsDeprecated, + Preimage, + SerializeDataAvailabilityCreatePages, + StateUpdatePointers, + SyscallHandlerType, + Transactions, + Tx, + UseKzgDa, +} + +impl From for &'static str { + fn from(scope: Scope) -> &'static str { + match scope { + Scope::BytecodeSegments => "bytecode_segments", + Scope::BytecodeSegmentStructure => "bytecode_segment_structure", + Scope::BytecodeSegmentStructures => "bytecode_segment_structures", + Scope::Case => "case", + Scope::CommitmentInfoByAddress => "commitment_info_by_address", + Scope::CompiledClass => "compiled_class", + Scope::CompiledClassFacts => "compiled_class_facts", + Scope::CompiledClassHash => "compiled_class_hash", + Scope::ComponentHashes => "component_hashes", + Scope::DeprecatedClassHashes => "__deprecated_class_hashes", + Scope::DictManager => "dict_manager", + Scope::DictTracker => "dict_tracker", + Scope::InitialDict => "initial_dict", + Scope::IsDeprecated => "is_deprecated", + Scope::Preimage => "preimage", + Scope::SerializeDataAvailabilityCreatePages => { + "__serialize_data_availability_create_pages__" + } + Scope::StateUpdatePointers => "state_update_pointers", + Scope::SyscallHandlerType => "syscall_handler_type", + Scope::Transactions => "transactions", + Scope::Tx => "tx", + Scope::UseKzgDa => "use_kzg_da", + } + } +} + +impl std::fmt::Display for Scope { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let scope_string: &'static str = (*self).into(); + write!(f, "{}", scope_string) + } +} + +impl From for String { + fn from(scope: Scope) -> String { + let scope_as_str: &str = scope.into(); + scope_as_str.to_string() + } +} + +#[derive(Debug, Clone)] +pub enum Ids { + AliasesEntry, + Bit, + BucketIndex, + BuiltinCosts, + BuiltinPtrs, + CompiledClass, + CompiledClassFact, + CompressedDst, + CompressedStart, + ContractAddress, + ContractStateChanges, + DaSize, + DataEnd, + DataStart, + DecompressedDst, + DictPtr, + Edge, + ElmBound, + Evals, + ExecutionContext, + FinalRoot, + FullOutput, + Hash, + Height, + InitialCarriedOutputs, + InitialRoot, + IsLeaf, + KzgCommitments, + Low, + MaxGas, + NBlobs, + NCompiledClassFacts, + NTxs, + NewLength, + NextAvailableAlias, + NewStateEntry, + Node, + OldBlockHash, + OldBlockNumber, + OsStateUpdate, + PackedFelt, + PrevOffset, + PrevValue, + RangeCheck96Ptr, + RemainingGas, + ResourceBounds, + Request, + Res, + Sha256Ptr, + StateEntry, + StateUpdatesStart, + SyscallPtr, + TransactionHash, + TxType, + UseKzgDa, + Value, +} + +impl From for &'static str { + fn from(ids: Ids) -> &'static str { + match ids { + Ids::AliasesEntry => "aliases_entry", + Ids::Bit => "bit", + Ids::BucketIndex => "bucket_index", + Ids::BuiltinCosts => "builtin_costs", + Ids::BuiltinPtrs => "builtin_ptrs", + Ids::CompiledClass => "compiled_class", + Ids::CompiledClassFact => "compiled_class_fact", + Ids::CompressedDst => "compressed_dst", + Ids::CompressedStart => "compressed_start", + Ids::ContractAddress => "contract_address", + Ids::ContractStateChanges => "contract_state_changes", + Ids::DaSize => "da_size", + Ids::DataEnd => "data_end", + Ids::DataStart => "data_start", + Ids::DecompressedDst => "decompressed_dst", + Ids::DictPtr => "dict_ptr", + Ids::Edge => "edge", + Ids::ElmBound => "elm_bound", + Ids::Evals => "evals", + Ids::ExecutionContext => "execution_context", + Ids::FinalRoot => "final_root", + Ids::FullOutput => "full_output", + Ids::Hash => "hash", + Ids::Height => "height", + Ids::InitialCarriedOutputs => "initial_carried_outputs", + Ids::InitialRoot => "initial_root", + Ids::IsLeaf => "is_leaf", + Ids::KzgCommitments => "kzg_commitments", + Ids::Low => "low", + Ids::MaxGas => "max_gas", + Ids::NBlobs => "n_blobs", + Ids::NCompiledClassFacts => "n_compiled_class_facts", + Ids::NTxs => "n_txs", + Ids::NewLength => "new_length", + Ids::NextAvailableAlias => "next_available_alias", + Ids::NewStateEntry => "new_state_entry", + Ids::Node => "node", + Ids::OldBlockHash => "old_block_hash", + Ids::OldBlockNumber => "old_block_number", + Ids::OsStateUpdate => "os_state_update", + Ids::PackedFelt => "packed_felt", + Ids::PrevOffset => "prev_offset", + Ids::PrevValue => "prev_value", + Ids::RangeCheck96Ptr => "range_check96_ptr", + Ids::RemainingGas => "remaining_gas", + Ids::ResourceBounds => "resource_bounds,", + Ids::Request => "request", + Ids::Res => "res", + Ids::Sha256Ptr => "sha256_ptr", + Ids::StateEntry => "state_entry", + Ids::StateUpdatesStart => "state_updates_start", + Ids::SyscallPtr => "syscall_ptr", + Ids::TransactionHash => "transaction_hash", + Ids::TxType => "tx_type", + Ids::UseKzgDa => "use_kzg_da", + Ids::Value => "value", + } + } +} + +#[derive(Clone, Copy, Debug)] +pub enum Const { + AliasContractAddress, + AliasCounterStorageKey, + Base, + BlobLength, + BlockHashContractAddress, + CompiledClassVersion, + DeprecatedCompiledClassVersion, + EntryPointInitialBudget, + InitialAvailableAlias, + MerkleHeight, + StoredBlockHashBuffer, +} + +impl From for &'static str { + fn from(constant: Const) -> &'static str { + match constant { + Const::AliasContractAddress => { + "starkware.starknet.core.os.constants.ALIAS_CONTRACT_ADDRESS" + } + Const::AliasCounterStorageKey => { + "starkware.starknet.core.os.state.aliases.ALIAS_COUNTER_STORAGE_KEY" + } + Const::Base => "starkware.starknet.core.os.data_availability.bls_field.BASE", + Const::BlobLength => { + "starkware.starknet.core.os.data_availability.commitment.BLOB_LENGTH" + } + Const::BlockHashContractAddress => { + "starkware.starknet.core.os.constants.BLOCK_HASH_CONTRACT_ADDRESS" + } + Const::CompiledClassVersion => { + "starkware.starknet.core.os.contract_class.compiled_class.COMPILED_CLASS_VERSION" + } + Const::DeprecatedCompiledClassVersion => { + "starkware.starknet.core.os.contract_class.deprecated_compiled_class.\ + DEPRECATED_COMPILED_CLASS_VERSION" + } + Const::InitialAvailableAlias => { + "starkware.starknet.core.os.state.aliases.INITIAL_AVAILABLE_ALIAS" + } + Const::MerkleHeight => "starkware.starknet.core.os.state.commitment.MERKLE_HEIGHT", + Const::StoredBlockHashBuffer => { + "starkware.starknet.core.os.constants.STORED_BLOCK_HASH_BUFFER" + } + Const::EntryPointInitialBudget => { + "starkware.starknet.core.os.constants.ENTRY_POINT_INITIAL_BUDGET" + } + } + } +} + +impl Const { + pub fn fetch<'a>(&self, constants: &'a HashMap) -> Result<&'a Felt, HintError> { + let identifier = (*self).into(); + constants.get(identifier).ok_or(HintError::MissingConstant(Box::new(identifier))) + } + + pub fn fetch_as>( + &self, + constants: &HashMap, + ) -> Result + where + >::Error: std::fmt::Debug, + { + let self_felt = self.fetch(constants)?; + T::try_from(*self_felt).map_err(|error| OsHintError::ConstConversion { + variant: *self, + felt: *self_felt, + ty: std::any::type_name::().into(), + reason: format!("{error:?}"), + }) + } + + pub fn get_alias_counter_storage_key( + constants: &HashMap, + ) -> Result { + Self::AliasCounterStorageKey.fetch_as(constants) + } + + pub fn get_alias_contract_address( + constants: &HashMap, + ) -> Result { + Self::AliasContractAddress.fetch_as(constants) + } +} + +#[derive(Copy, Clone)] +pub enum CairoStruct { + BigInt3, + BuiltinPointersPtr, + CompiledClass, + CompiledClassEntryPoint, + CompiledClassFact, + DeprecatedCompiledClass, + DeprecatedCompiledClassFact, + DeprecatedContractEntryPoint, + DictAccess, + ExecutionContext, + NodeEdge, + NonSelectableBuiltins, + OsStateUpdate, + ResourceBounds, + SelectableBuiltins, + StateEntry, + StorageReadPtr, + StorageReadRequestPtr, + StorageWritePtr, +} + +impl From for &'static str { + fn from(struct_name: CairoStruct) -> Self { + match struct_name { + CairoStruct::BigInt3 => { + "starkware.starknet.core.os.data_availability.bls_field.BigInt3" + } + CairoStruct::BuiltinPointersPtr => { + "starkware.starknet.core.os.builtins.BuiltinPointers*" + } + CairoStruct::CompiledClass => { + "starkware.starknet.core.os.contract_class.compiled_class.CompiledClass" + } + CairoStruct::CompiledClassEntryPoint => { + "starkware.starknet.core.os.contract_class.compiled_class.CompiledClassEntryPoint" + } + CairoStruct::CompiledClassFact => { + "starkware.starknet.core.os.contract_class.compiled_class.CompiledClassFact" + } + CairoStruct::DeprecatedCompiledClass => { + "starkware.starknet.core.os.contract_class.deprecated_compiled_class.\ + DeprecatedCompiledClass" + } + CairoStruct::DeprecatedCompiledClassFact => { + "starkware.starknet.core.os.contract_class.deprecated_compiled_class.\ + DeprecatedCompiledClassFact" + } + CairoStruct::DeprecatedContractEntryPoint => { + "starkware.starknet.core.os.contract_class.deprecated_compiled_class.\ + DeprecatedContractEntryPoint" + } + CairoStruct::DictAccess => "starkware.cairo.common.dict_access.DictAccess", + CairoStruct::ExecutionContext => { + "starkware.starknet.core.os.execution.execute_entry_point.ExecutionContext" + } + CairoStruct::NodeEdge => "starkware.cairo.common.patricia_utils.NodeEdge", + CairoStruct::NonSelectableBuiltins => { + "starkware.starknet.core.os.builtins.NonSelectableBuiltins" + } + CairoStruct::OsStateUpdate => "starkware.starknet.core.os.state.state.OsStateUpdate", + CairoStruct::ResourceBounds => "starkware.starknet.common.new_syscalls.ResourceBounds", + CairoStruct::SelectableBuiltins => { + "starkware.starknet.core.os.builtins.SelectableBuiltins" + } + CairoStruct::StateEntry => "starkware.starknet.core.os.state.state.StateEntry", + CairoStruct::StorageReadPtr => "starkware.starknet.common.syscalls.StorageRead*", + CairoStruct::StorageReadRequestPtr => { + "starkware.starknet.core.os.storage.StorageReadRequest*" + } + CairoStruct::StorageWritePtr => { + "starkware.starknet.common.syscalls.StorageWriteRequest*" + } + } + } +} diff --git a/crates/starknet_os/src/io.rs b/crates/starknet_os/src/io.rs new file mode 100644 index 00000000000..6f99cf1893d --- /dev/null +++ b/crates/starknet_os/src/io.rs @@ -0,0 +1,2 @@ +pub mod os_input; +pub mod os_output; diff --git a/crates/starknet_os/src/io/os_input.rs b/crates/starknet_os/src/io/os_input.rs new file mode 100644 index 00000000000..4eb0677799c --- /dev/null +++ b/crates/starknet_os/src/io/os_input.rs @@ -0,0 +1,93 @@ +use std::collections::HashMap; + +use blockifier::context::ChainInfo; +use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass; +use shared_execution_objects::central_objects::CentralTransactionExecutionInfo; +use starknet_api::block::{BlockHash, BlockInfo, BlockNumber}; +use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; +use starknet_api::deprecated_contract_class::ContractClass; +use starknet_api::executable_transaction::Transaction; +use starknet_api::state::StorageKey; +use starknet_patricia::hash::hash_trait::HashOutput; +use starknet_patricia::patricia_merkle_tree::types::SubTreeHeight; +use starknet_types_core::felt::Felt; + +#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))] +// TODO(Nimrod): Remove the `Clone` derive when possible. +#[derive(Debug, Clone)] +pub struct CommitmentInfo { + pub(crate) previous_root: HashOutput, + pub(crate) updated_root: HashOutput, + pub(crate) tree_height: SubTreeHeight, + // TODO(Dori, 1/8/2025): The value type here should probably be more specific (NodeData for + // L: Leaf). This poses a problem in deserialization, as a serialized edge node and a + // serialized contract state leaf are both currently vectors of 3 field elements; as the + // semantics of the values are unimportant for the OS commitments, we make do with a vector + // of field elements as values for now. + pub(crate) commitment_facts: HashMap>, +} + +#[cfg(any(feature = "testing", test))] +impl Default for CommitmentInfo { + fn default() -> CommitmentInfo { + CommitmentInfo { + previous_root: HashOutput::default(), + updated_root: HashOutput::default(), + tree_height: SubTreeHeight::ACTUAL_HEIGHT, + commitment_facts: HashMap::default(), + } + } +} + +#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))] +#[derive(Clone, Debug)] +pub struct ContractClassComponentHashes { + _contract_class_version: Felt, + _external_functions_hash: HashOutput, + _l1_handlers_hash: HashOutput, + _constructors_hash: HashOutput, + _abi_hash: HashOutput, + _sierra_program_hash: HashOutput, +} + +/// All input needed to initialize the execution helper. +// TODO(Dori): Add all fields needed to compute commitments, initialize a CachedState and other data +// required by the execution helper. +#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))] +#[cfg_attr(any(test, feature = "testing"), derive(Default))] +#[derive(Debug)] +pub struct StarknetOsInput { + pub(crate) contract_state_commitment_info: CommitmentInfo, + pub(crate) address_to_storage_commitment_info: HashMap, + pub(crate) contract_class_commitment_info: CommitmentInfo, + pub(crate) chain_info: ChainInfo, + pub(crate) deprecated_compiled_classes: HashMap, + #[allow(dead_code)] + pub(crate) compiled_classes: HashMap, + // Note: The Declare tx in the starknet_api crate has a class_info field with a contract_class + // field. This field is needed by the blockifier, but not used in the OS, so it is expected + // (and verified) to be initialized with an illegal value, to avoid using it accidentally. + pub transactions: Vec, + pub _tx_execution_infos: Vec, + // A mapping from Cairo 1 declared class hashes to the hashes of the contract class components. + pub(crate) declared_class_hash_to_component_hashes: + HashMap, + pub block_info: BlockInfo, + pub(crate) prev_block_hash: BlockHash, + pub(crate) new_block_hash: BlockHash, + // The block number and block hash of the (current_block_number - buffer) block, where + // buffer=STORED_BLOCK_HASH_BUFFER. + // It is the hash that is going to be written by this OS run. + pub(crate) old_block_number_and_hash: Option<(BlockNumber, BlockHash)>, + _debug_mode: bool, + pub(crate) full_output: bool, +} + +#[derive(Default, Debug)] +#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))] +pub struct CachedStateInput { + pub(crate) storage: HashMap>, + pub(crate) address_to_class_hash: HashMap, + pub(crate) address_to_nonce: HashMap, + pub(crate) class_hash_to_compiled_class_hash: HashMap, +} diff --git a/crates/starknet_os/src/io/os_output.rs b/crates/starknet_os/src/io/os_output.rs new file mode 100644 index 00000000000..01073115a9a --- /dev/null +++ b/crates/starknet_os/src/io/os_output.rs @@ -0,0 +1,97 @@ +use cairo_vm::types::builtin_name::BuiltinName; +use cairo_vm::types::relocatable::{MaybeRelocatable, Relocatable}; +use cairo_vm::vm::errors::memory_errors::MemoryError; +use cairo_vm::vm::errors::vm_errors::VirtualMachineError; +use cairo_vm::vm::runners::builtin_runner::BuiltinRunner; +use cairo_vm::vm::runners::cairo_pie::CairoPie; +use cairo_vm::vm::vm_core::VirtualMachine; +use num_traits::ToPrimitive; +use serde::Serialize; +use starknet_types_core::felt::Felt; + +use crate::errors::StarknetOsError; + +#[derive(Serialize)] +pub struct StarknetOsRunnerOutput { + // TODO(Tzahi): Define a struct for the output. + pub os_output: Vec, + pub cairo_pie: CairoPie, +} + +// Retrieve the output ptr data of a finalized run as a vec of felts. +pub fn get_run_output(vm: &VirtualMachine) -> Result, StarknetOsError> { + let (output_base, output_size) = get_output_info(vm)?; + get_raw_output(vm, output_base, output_size) +} + +/// Gets the output base segment and the output size from the VM return values and the VM +/// output builtin. +fn get_output_info(vm: &VirtualMachine) -> Result<(usize, usize), StarknetOsError> { + let output_base = vm + .get_builtin_runners() + .iter() + .find(|&runner| matches!(runner, BuiltinRunner::Output(_))) + .ok_or_else(|| StarknetOsError::VirtualMachineError(VirtualMachineError::NoOutputBuiltin))? + .base(); + let n_builtins = vm.get_builtin_runners().len(); + let builtin_end_ptrs = vm + .get_return_values(n_builtins) + .map_err(|err| StarknetOsError::VirtualMachineError(err.into()))?; + + // Find the output_builtin returned offset. + let output_size = builtin_end_ptrs + .iter() + .find_map(|ptr| { + if let MaybeRelocatable::RelocatableValue(Relocatable { segment_index, offset }) = ptr { + // Negative index is reserved for temporary memory segments. + // See https://github.com/lambdaclass/cairo-vm/blob/ed3117098dd33c96056880af6fa67f9 + // b2caebfb4/vm/src/vm/vm_memory/memory_segments.rs#L57. + if segment_index.to_usize().expect("segment_index is unexpectedly negative") + == output_base + { + Some(offset) + } else { + None + } + } else { + None + } + }) + .ok_or_else(|| { + StarknetOsError::VirtualMachineError( + MemoryError::MissingMemoryCells(BuiltinName::output.into()).into(), + ) + })?; + + Ok((output_base, *output_size)) +} + +/// Gets the OS output as an array of felts based on the output base and size. +fn get_raw_output( + vm: &VirtualMachine, + output_base: usize, + output_size: usize, +) -> Result, StarknetOsError> { + // Get output and check that everything is an integer. + let output_address = Relocatable::from(( + output_base.to_isize().expect("Output segment index unexpectedly exceeds isize::MAX"), + 0, + )); + let range_of_output = vm.get_range(output_address, output_size); + range_of_output + .iter() + .map(|x| match x { + Some(cow) => match **cow { + MaybeRelocatable::Int(val) => Ok(val), + MaybeRelocatable::RelocatableValue(val) => { + Err(StarknetOsError::VirtualMachineError( + VirtualMachineError::ExpectedIntAtRange(Box::new(Some(val.into()))), + )) + } + }, + None => Err(StarknetOsError::VirtualMachineError( + MemoryError::MissingMemoryCells(BuiltinName::output.into()).into(), + )), + }) + .collect() +} diff --git a/crates/starknet_os/src/lib.rs b/crates/starknet_os/src/lib.rs new file mode 100644 index 00000000000..aaa73750468 --- /dev/null +++ b/crates/starknet_os/src/lib.rs @@ -0,0 +1,9 @@ +pub mod errors; +pub mod hint_processor; +pub mod hints; +pub mod io; +pub mod runner; +pub mod syscall_handler_utils; +#[cfg(any(test, feature = "testing"))] +pub mod test_utils; +pub mod vm_utils; diff --git a/crates/starknet_os/src/runner.rs b/crates/starknet_os/src/runner.rs new file mode 100644 index 00000000000..eced195689a --- /dev/null +++ b/crates/starknet_os/src/runner.rs @@ -0,0 +1,100 @@ +use blockifier::state::state_api::StateReader; +use cairo_vm::cairo_run::CairoRunConfig; +use cairo_vm::types::layout_name::LayoutName; +use cairo_vm::types::program::Program; +use cairo_vm::vm::errors::vm_exception::VmException; +use cairo_vm::vm::runners::cairo_runner::CairoRunner; + +use crate::errors::StarknetOsError; +use crate::hint_processor::execution_helper::OsExecutionHelper; +use crate::hint_processor::panicking_state_reader::PanickingStateReader; +use crate::hint_processor::snos_hint_processor::{ + DeprecatedSyscallHintProcessor, + SnosHintProcessor, + SyscallHintProcessor, +}; +use crate::io::os_input::{CachedStateInput, StarknetOsInput}; +use crate::io::os_output::{get_run_output, StarknetOsRunnerOutput}; + +pub fn run_os( + compiled_os: &[u8], + layout: LayoutName, + os_input: StarknetOsInput, + state_reader: S, + cached_state_input: CachedStateInput, +) -> Result { + // Init CairoRunConfig. + let cairo_run_config = + CairoRunConfig { layout, relocate_mem: true, trace_enabled: true, ..Default::default() }; + let allow_missing_builtins = cairo_run_config.allow_missing_builtins.unwrap_or(false); + + // Load the Starknet OS Program. + let os_program = Program::from_bytes(compiled_os, Some(cairo_run_config.entrypoint))?; + + // Init cairo runner. + let mut cairo_runner = CairoRunner::new( + &os_program, + cairo_run_config.layout, + cairo_run_config.proof_mode, + cairo_run_config.trace_enabled, + )?; + + // Init the Cairo VM. + let end = cairo_runner.initialize(allow_missing_builtins)?; + + // Create execution helper. + let execution_helper = + OsExecutionHelper::new(os_input, os_program, state_reader, cached_state_input)?; + + // Create syscall handlers. + let syscall_handler = SyscallHintProcessor::new(); + let deprecated_syscall_handler = DeprecatedSyscallHintProcessor {}; + + // Create the hint processor. + let mut snos_hint_processor = + SnosHintProcessor::new(execution_helper, syscall_handler, deprecated_syscall_handler); + + // Run the Cairo VM. + cairo_runner + .run_until_pc(end, &mut snos_hint_processor) + .map_err(|err| VmException::from_vm_error(&cairo_runner, err))?; + + // End the Cairo VM run. + let disable_finalize_all = false; + cairo_runner.end_run( + cairo_run_config.disable_trace_padding, + disable_finalize_all, + &mut snos_hint_processor, + )?; + + if cairo_run_config.proof_mode { + cairo_runner.finalize_segments()?; + } + + // Prepare and check expected output. + let os_output = get_run_output(&cairo_runner.vm)?; + // TODO(Tzahi): log the output once it will have a proper struct. + cairo_runner.vm.verify_auto_deductions().map_err(StarknetOsError::VirtualMachineError)?; + cairo_runner + .read_return_values(allow_missing_builtins) + .map_err(StarknetOsError::RunnerError)?; + cairo_runner + .relocate(cairo_run_config.relocate_mem) + .map_err(|e| StarknetOsError::VirtualMachineError(e.into()))?; + + // Parse the Cairo VM output. + let cairo_pie = cairo_runner.get_cairo_pie().map_err(StarknetOsError::RunnerError)?; + + Ok(StarknetOsRunnerOutput { os_output, cairo_pie }) +} + +/// Run the OS with a "stateless" state reader - panics if the state is accessed for data that was +/// not pre-loaded as part of the input. +pub fn run_os_stateless( + compiled_os: &[u8], + layout: LayoutName, + os_input: StarknetOsInput, + cached_state_input: CachedStateInput, +) -> Result { + run_os(compiled_os, layout, os_input, PanickingStateReader, cached_state_input) +} diff --git a/crates/starknet_os/src/syscall_handler_utils.rs b/crates/starknet_os/src/syscall_handler_utils.rs new file mode 100644 index 00000000000..a66db1afa84 --- /dev/null +++ b/crates/starknet_os/src/syscall_handler_utils.rs @@ -0,0 +1,4 @@ +pub(crate) enum SyscallHandlerType { + SyscallHandler, + DeprecatedSyscallHandler, +} diff --git a/crates/starknet_os/src/test_utils.rs b/crates/starknet_os/src/test_utils.rs new file mode 100644 index 00000000000..248ea4a4336 --- /dev/null +++ b/crates/starknet_os/src/test_utils.rs @@ -0,0 +1,3 @@ +pub mod cairo_runner; +pub mod errors; +pub mod utils; diff --git a/crates/starknet_os/src/test_utils/cairo_runner.rs b/crates/starknet_os/src/test_utils/cairo_runner.rs new file mode 100644 index 00000000000..e5038f3544d --- /dev/null +++ b/crates/starknet_os/src/test_utils/cairo_runner.rs @@ -0,0 +1,510 @@ +use std::collections::{HashMap, HashSet}; + +use blockifier::blockifier_versioned_constants::VersionedConstants; +use cairo_vm::serde::deserialize_program::Member; +use cairo_vm::types::builtin_name::BuiltinName; +use cairo_vm::types::layout_name::LayoutName; +use cairo_vm::types::program::Program; +use cairo_vm::types::relocatable::{MaybeRelocatable, Relocatable}; +use cairo_vm::utils::is_subsequence; +use cairo_vm::vm::runners::cairo_runner::{CairoArg, CairoRunner}; +use cairo_vm::vm::vm_core::VirtualMachine; +use log::{debug, info}; +use serde_json::Value; +use starknet_types_core::felt::Felt; + +use crate::hint_processor::snos_hint_processor::SnosHintProcessor; +use crate::test_utils::errors::{ + Cairo0EntryPointRunnerError, + ExplicitArgError, + ImplicitArgError, + LoadReturnValueError, +}; + +pub type Cairo0EntryPointRunnerResult = Result; + +#[cfg(test)] +#[path = "cairo_runner_test.rs"] +mod test; + +/// An arg passed by value (i.e., a felt, tuple, named tuple or struct). +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum ValueArg { + Single(Felt), + Array(Vec), + Composed(Vec), +} + +/// An arg passed as a pointer. i.e., a pointer to a felt, tuple, named tuple or struct, or a +/// pointer to a pointer. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum PointerArg { + Array(Vec), + Composed(Vec), +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum EndpointArg { + Value(ValueArg), + Pointer(PointerArg), +} + +impl From for EndpointArg { + fn from(value: i32) -> Self { + Self::Value(ValueArg::Single(value.into())) + } +} + +impl EndpointArg { + /// Converts an endpoint arg into a vector of cairo args. + /// The cairo VM loads struct / tuple / named tuple parameters by adding each of their fields + /// to the stack. This is why a single endpoint arg can be converted into multiple cairo args - + /// an arg of type Struct {a: felt, b: felt} will be converted into a vector of two cairo args + /// of type felt. + fn to_cairo_arg_vec(endpoint_arg: &EndpointArg) -> Vec { + match endpoint_arg { + EndpointArg::Value(value_arg) => match value_arg { + ValueArg::Single(felt) => { + vec![CairoArg::Single(MaybeRelocatable::Int(*felt))] + } + ValueArg::Array(felts) => felts + .iter() + .map(|felt| CairoArg::Single(MaybeRelocatable::Int(*felt))) + .collect(), + ValueArg::Composed(endpoint_args) => { + endpoint_args.iter().flat_map(Self::to_cairo_arg_vec).collect() + } + }, + EndpointArg::Pointer(pointer_arg) => match pointer_arg { + PointerArg::Array(felts) => vec![CairoArg::Array( + felts.iter().map(|felt| MaybeRelocatable::Int(*felt)).collect(), + )], + PointerArg::Composed(endpoint_args) => vec![CairoArg::Composed( + endpoint_args.iter().flat_map(Self::to_cairo_arg_vec).collect(), + )], + }, + } + } + + /// Returns the size of the space the arg occupies on the stack (not including referenced + /// addresses). + fn memory_length(&self) -> usize { + match self { + Self::Value(value_arg) => match value_arg { + ValueArg::Single(_) => 1, + ValueArg::Array(array) => array.len(), + ValueArg::Composed(endpoint_args) => { + endpoint_args.iter().map(Self::memory_length).sum() + } + }, + Self::Pointer(_) => 1, + } + } +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum ImplicitArg { + Builtin(BuiltinName), + NonBuiltin(EndpointArg), +} + +impl ImplicitArg { + /// Returns the size of the space the arg occupies on the stack (not including referenced + /// addresses). + fn memory_length(&self) -> usize { + match self { + Self::Builtin(_) => 1, + Self::NonBuiltin(endpoint_arg) => endpoint_arg.memory_length(), + } + } +} + +/// Performs basic validations on the cairo arg. Assumes the arg is not a builtin. +/// A successful result from this function does NOT guarantee that the arguments are valid. +fn perform_basic_validations_on_endpoint_arg( + index: usize, + expected_arg: &Member, + actual_arg: &EndpointArg, +) -> Cairo0EntryPointRunnerResult<()> { + let actual_arg_is_felt = matches!(actual_arg, EndpointArg::Value(ValueArg::Single(_))); + let actual_arg_is_pointer = matches!(actual_arg, EndpointArg::Pointer(_)); + let actual_arg_is_struct_or_tuple = !actual_arg_is_felt && !actual_arg_is_pointer; + + let expected_arg_is_pointer = expected_arg.cairo_type.ends_with("*"); + let expected_arg_is_felt = expected_arg.cairo_type == "felt"; + let expected_arg_is_struct_or_tuple = !expected_arg_is_felt && !expected_arg_is_pointer; + + if expected_arg_is_felt != actual_arg_is_felt + || expected_arg_is_pointer != actual_arg_is_pointer + || expected_arg_is_struct_or_tuple != actual_arg_is_struct_or_tuple + { + Err(ExplicitArgError::Mismatch { + index, + expected: expected_arg.clone(), + actual: actual_arg.clone(), + })?; + }; + Ok(()) +} + +/// Performs basic validations on the explicit arguments. A successful result from this function +/// does NOT guarantee that the arguments are valid. +fn perform_basic_validations_on_explicit_args( + explicit_args: &[EndpointArg], + program: &Program, + entrypoint: &str, +) -> Cairo0EntryPointRunnerResult<()> { + let mut expected_explicit_args: Vec = program + .get_identifier(&format!("__main__.{}.Args", entrypoint)) + .unwrap_or_else(|| { + panic!("Found no explicit args identifier for entrypoint {}.", entrypoint) + }) + .members + .as_ref() + .unwrap() + .values() + .cloned() + .collect(); + + if expected_explicit_args.len() != explicit_args.len() { + Err(ExplicitArgError::WrongNumberOfArgs { + expected: expected_explicit_args.to_vec(), + actual: explicit_args.to_vec(), + })?; + } + + expected_explicit_args.sort_by(|a, b| a.offset.cmp(&b.offset)); + for (index, actual_arg) in explicit_args.iter().enumerate() { + let expected_arg = expected_explicit_args.get(index).unwrap(); + perform_basic_validations_on_endpoint_arg(index, expected_arg, actual_arg)?; + } + Ok(()) +} + +fn get_builtin_or_non(arg_name: &str) -> Option { + BuiltinName::from_str(arg_name.strip_suffix("_ptr")?) +} + +/// Performs basic validations on the implicit arguments. A successful result from this function +/// does NOT guarantee that the arguments are valid. +fn perform_basic_validations_on_implicit_args( + implicit_args: &[ImplicitArg], + program: &Program, + entrypoint: &str, + ordered_builtins: &[BuiltinName], +) -> Cairo0EntryPointRunnerResult<()> { + let mut expected_implicit_args: Vec<(String, Member)> = program + .get_identifier(&format!("__main__.{}.ImplicitArgs", entrypoint)) + .unwrap_or_else(|| { + panic!("Found no implicit args identifier for entrypoint {}.", entrypoint) + }) + .members + .as_ref() + .unwrap() + .iter() + .map(|(k, v)| (k.to_string(), v.clone())) + .collect(); + + expected_implicit_args.sort_by(|a, b| a.1.offset.cmp(&b.1.offset)); + if expected_implicit_args.len() != implicit_args.len() { + Err(ImplicitArgError::WrongNumberOfArgs { + expected: expected_implicit_args.clone(), + actual: implicit_args.to_vec(), + })?; + } + let mut actual_builtins: Vec = vec![]; + for (index, actual_arg) in implicit_args.iter().enumerate() { + let (expected_arg_name, expected_arg) = &expected_implicit_args[index]; + let expected_builtin_or_none = get_builtin_or_non(expected_arg_name); + let actual_builtin_or_none = match actual_arg { + ImplicitArg::Builtin(builtin) => Some(*builtin), + ImplicitArg::NonBuiltin(_) => None, + }; + if expected_builtin_or_none != actual_builtin_or_none { + Err(ImplicitArgError::Mismatch { + index, + expected: expected_arg.clone(), + actual: actual_arg.clone(), + })?; + } + match actual_arg { + ImplicitArg::Builtin(builtin) => { + actual_builtins.push(*builtin); + continue; + } + ImplicitArg::NonBuiltin(endpoint_arg) => { + perform_basic_validations_on_endpoint_arg(index, expected_arg, endpoint_arg)?; + } + } + } + if !is_subsequence(&actual_builtins, ordered_builtins) { + Err(ImplicitArgError::WrongBuiltinOrder { + correct_order: ordered_builtins.to_vec(), + actual_order: actual_builtins, + })?; + } + Ok(()) +} + +// This is a hack to add the entrypoint's builtins: +// Create a program with all the builtins, and only use the relevant builtins for the +// entrypoint. +// TODO(Amos): Add builtins properly once the VM allows loading an entrypoint's builtins. +// In addition, pass program as struct and add hint processor as param. +fn inject_builtins( + program_str: &str, + ordered_builtins: &[BuiltinName], + entrypoint: &str, +) -> Cairo0EntryPointRunnerResult { + let mut program_dict: HashMap = + serde_json::from_str(program_str).map_err(Cairo0EntryPointRunnerError::ProgramSerde)?; + program_dict.insert( + "builtins".to_string(), + Value::from_iter(ordered_builtins.iter().map(|b| b.to_str())), + ); + let program_str_with_builtins = + serde_json::to_string(&program_dict).map_err(Cairo0EntryPointRunnerError::ProgramSerde)?; + Ok(Program::from_bytes(program_str_with_builtins.as_bytes(), Some(entrypoint))?) +} + +fn convert_implicit_args_to_cairo_args( + implicit_args: &[ImplicitArg], + vm: &VirtualMachine, + ordered_builtins: &[BuiltinName], +) -> Vec { + let all_builtins_initial_stacks: Vec> = vm + .get_builtin_runners() + .iter() + .map(|builtin_runner| builtin_runner.initial_stack()) + .collect(); + let all_builtin_map: HashMap<_, _> = + ordered_builtins.iter().zip(all_builtins_initial_stacks).collect(); + implicit_args + .iter() + .flat_map(|arg| match arg { + ImplicitArg::Builtin(builtin) => { + all_builtin_map[builtin].iter().map(|b| b.clone().into()).collect() + } + ImplicitArg::NonBuiltin(endpoint_arg) => EndpointArg::to_cairo_arg_vec(endpoint_arg), + }) + .collect() +} + +fn get_ordered_builtins() -> Cairo0EntryPointRunnerResult> { + let ordered_builtins = vec![ + BuiltinName::output, + BuiltinName::pedersen, + BuiltinName::range_check, + BuiltinName::ecdsa, + BuiltinName::bitwise, + BuiltinName::ec_op, + BuiltinName::keccak, + BuiltinName::poseidon, + BuiltinName::range_check96, + BuiltinName::add_mod, + BuiltinName::mul_mod, + ]; + let actual_builtins = VersionedConstants::latest_constants() + .vm_resource_fee_cost() + .builtins + .keys() + .cloned() + .collect::>(); + if ordered_builtins.iter().cloned().collect::>() != actual_builtins { + Err(Cairo0EntryPointRunnerError::BuiltinMismatch { + cairo_runner_builtins: ordered_builtins.clone(), + actual_builtins, + })?; + } + Ok(ordered_builtins) +} + +/// A helper function for `load_endpoint_arg_from_address`. +/// Loads a sequence of felts from memory and returns it. +fn load_sequence_of_felts( + length: usize, + address: Relocatable, + vm: &VirtualMachine, +) -> Result, LoadReturnValueError> { + let mut felt_array = vec![]; + for i in 0..length { + felt_array.push(vm.get_integer((address + i)?)?.into_owned()); + } + Ok(felt_array) +} + +/// A helper function for `load_endpoint_arg_from_address`. +/// Loads a sequence of endpoint args from memory and returns it, together with the first address +/// after the sequence. +fn load_sequence_of_endpoint_args( + sequence: &[EndpointArg], + address: Relocatable, + vm: &VirtualMachine, +) -> Result<(Vec, Relocatable), LoadReturnValueError> { + let mut current_address = address; + let mut endpoint_args = vec![]; + for endpoint_arg in sequence.iter() { + let (value, next_address) = + load_endpoint_arg_from_address(endpoint_arg, current_address, vm)?; + endpoint_args.push(value); + current_address = next_address; + } + Ok((endpoint_args, current_address)) +} + +/// Loads a value from the VM and returns it, together with the address after said value. +/// Note - the values inside `value_structure` are ignored. +fn load_endpoint_arg_from_address( + value_structure: &EndpointArg, + address: Relocatable, + vm: &VirtualMachine, +) -> Result<(EndpointArg, Relocatable), LoadReturnValueError> { + let value_size = value_structure.memory_length(); + match value_structure { + EndpointArg::Value(value_arg) => match value_arg { + ValueArg::Single(_) => Ok(( + EndpointArg::Value(ValueArg::Single(vm.get_integer(address)?.into_owned())), + (address + value_size)?, + )), + ValueArg::Array(array) => { + let felt_array = load_sequence_of_felts(array.len(), address, vm)?; + Ok((EndpointArg::Value(ValueArg::Array(felt_array)), (address + value_size)?)) + } + ValueArg::Composed(endpoint_args) => { + let (endpoint_arg_array, next_address) = + load_sequence_of_endpoint_args(endpoint_args, address, vm)?; + Ok((EndpointArg::Value(ValueArg::Composed(endpoint_arg_array)), next_address)) + } + }, + EndpointArg::Pointer(pointer_arg) => match pointer_arg { + PointerArg::Array(array) => { + let array_pointer = vm.get_relocatable(address)?; + let felt_array = load_sequence_of_felts(array.len(), array_pointer, vm)?; + Ok((EndpointArg::Pointer(PointerArg::Array(felt_array)), (address + value_size)?)) + } + PointerArg::Composed(endpoint_args) => { + let (endpoint_arg_array, _) = load_sequence_of_endpoint_args( + endpoint_args, + vm.get_relocatable(address)?, + vm, + )?; + Ok(( + EndpointArg::Pointer(PointerArg::Composed(endpoint_arg_array)), + (address + value_size)?, + )) + } + }, + } +} + +/// Loads the explicit and implicit return values from the VM. +/// The implicit & explicit return values params are used to determine the return +/// values' structures (their values are ignored). +fn get_return_values( + implicit_return_values_structures: &[ImplicitArg], + explicit_return_values_structures: &[EndpointArg], + vm: &VirtualMachine, +) -> Result<(Vec, Vec), LoadReturnValueError> { + let return_args_len = implicit_return_values_structures + .iter() + .map(ImplicitArg::memory_length) + .sum::() + + explicit_return_values_structures.iter().map(EndpointArg::memory_length).sum::(); + let return_values_address = (vm.get_ap() - return_args_len)?; + let mut current_address = return_values_address; + + let mut implicit_return_values: Vec = vec![]; + for (i, implicit_arg) in implicit_return_values_structures.iter().enumerate() { + debug!("Loading implicit return value {}. Value: {:?}", i, implicit_arg); + match implicit_arg { + ImplicitArg::Builtin(builtin) => { + implicit_return_values.push(ImplicitArg::Builtin(*builtin)); + current_address = (current_address + implicit_arg.memory_length())?; + } + ImplicitArg::NonBuiltin(non_builtin_return_value) => { + let (value, next_arg_address) = + load_endpoint_arg_from_address(non_builtin_return_value, current_address, vm)?; + implicit_return_values.push(ImplicitArg::NonBuiltin(value)); + current_address = next_arg_address; + } + } + } + info!("Successfully loaded implicit return values."); + + let mut explicit_return_values: Vec = vec![]; + for (i, expected_return_value) in explicit_return_values_structures.iter().enumerate() { + debug!("Loading explicit return value {}. Value: {:?}", i, expected_return_value); + let (value, next_arg_address) = + load_endpoint_arg_from_address(expected_return_value, current_address, vm)?; + explicit_return_values.push(value); + current_address = next_arg_address; + } + info!("Successfully loaded explicit return values."); + + Ok((implicit_return_values, explicit_return_values)) +} + +// TODO(Amos): Add logs to the runner. +// TODO(Amos): Return different errors in different stages of the runner, for easier debugging. +// e.g., `ReturnValueError`. +pub fn run_cairo_0_entry_point( + program_str: &str, + entrypoint: &str, + explicit_args: &[EndpointArg], + implicit_args: &[ImplicitArg], + expected_explicit_return_values: &[EndpointArg], +) -> Cairo0EntryPointRunnerResult<(Vec, Vec)> { + let ordered_builtins = get_ordered_builtins()?; + let program = inject_builtins(program_str, &ordered_builtins, entrypoint)?; + let (state_reader, os_input) = (None, None); + let mut hint_processor = + SnosHintProcessor::new_for_testing(state_reader, os_input, Some(program.clone())); + info!("Program and Hint processor created successfully."); + + // TODO(Amos): Perform complete validations. + perform_basic_validations_on_explicit_args(explicit_args, &program, entrypoint)?; + perform_basic_validations_on_implicit_args( + implicit_args, + &program, + entrypoint, + &ordered_builtins, + )?; + info!("Performed basic validations on explicit & implicit args."); + + let proof_mode = false; + let trace_enabled = true; + let mut cairo_runner = + CairoRunner::new(&program, LayoutName::all_cairo, proof_mode, trace_enabled).unwrap(); + let allow_missing_builtins = false; + cairo_runner.initialize_builtins(allow_missing_builtins).unwrap(); + let program_base: Option = None; + cairo_runner.initialize_segments(program_base); + info!("Created and initialized Cairo runner."); + + let explicit_cairo_args: Vec = + explicit_args.iter().flat_map(EndpointArg::to_cairo_arg_vec).collect(); + let implicit_cairo_args = + convert_implicit_args_to_cairo_args(implicit_args, &cairo_runner.vm, &ordered_builtins); + let entrypoint_args: Vec<&CairoArg> = + implicit_cairo_args.iter().chain(explicit_cairo_args.iter()).collect(); + info!("Converted explicit & implicit args to Cairo args."); + + let verify_secure = true; + let program_segment_size: Option = None; + cairo_runner + .run_from_entrypoint( + program + .get_identifier(&format!("__main__.{}", entrypoint)) + .unwrap_or_else(|| panic!("entrypoint {} not found.", entrypoint)) + .pc + .unwrap(), + &entrypoint_args, + verify_secure, + program_segment_size, + &mut hint_processor, + ) + .map_err(Cairo0EntryPointRunnerError::RunCairoEndpoint)?; + info!("Successfully finished running entrypoint {}", entrypoint); + + Ok(get_return_values(implicit_args, expected_explicit_return_values, &cairo_runner.vm)?) +} diff --git a/crates/starknet_os/src/test_utils/cairo_runner_test.rs b/crates/starknet_os/src/test_utils/cairo_runner_test.rs new file mode 100644 index 00000000000..d141cf37b96 --- /dev/null +++ b/crates/starknet_os/src/test_utils/cairo_runner_test.rs @@ -0,0 +1,205 @@ +use cairo_vm::types::builtin_name::BuiltinName; + +use crate::test_utils::cairo_runner::{ + Cairo0EntryPointRunnerResult, + EndpointArg, + ImplicitArg, + PointerArg, + ValueArg, +}; +use crate::test_utils::utils::run_cairo_function_and_check_result; + +/// from starkware.cairo.common.alloc import alloc +/// from starkware.cairo.common.math import assert_lt +/// +/// struct CompoundStruct { +/// a: felt, +/// simple_struct: SimpleStruct*, +/// } +/// +/// struct SimpleStruct { +/// a: felt, +/// b: felt, +/// } +/// +/// func pass_felt_and_pointers(number: felt, array: felt*, tuple: felt*, simple_struct: +/// SimpleStruct*, compound_struct: CompoundStruct*) -> +/// (res1: felt, res2: felt*, res3: felt*, res4: CompoundStruct*) { +/// let (res_array: felt*) = alloc(); +/// let (res_tuple: felt*) = alloc(); +/// let (res_compound_struct: CompoundStruct*) = alloc(); +/// assert res_array[0] = array[0] + 1; +/// assert res_array[1] = array[1] + 2; +/// assert res_tuple[0] = tuple[0] + 1; +/// assert res_tuple[1] = tuple[1] + 2; +/// assert res_compound_struct.a = compound_struct.a + 1; +/// assert res_compound_struct.simple_struct = compound_struct.simple_struct; +/// let res_number = number + 1; +/// return (res1=res_number, res2=res_array, res3=res_tuple, res4=res_compound_struct); +/// } +/// +/// func pass_structs_and_tuples(tuple: (felt, felt), named_tuple: (a: felt, b:felt), +/// simple_struct: SimpleStruct, compound_struct: CompoundStruct) -> +/// (res1: (a: felt, b:felt), res2: SimpleStruct, res3: CompoundStruct) { +/// alloc_locals; +/// local res_simple_struct: SimpleStruct; +/// local res_compound_struct: CompoundStruct; +/// local res_named_tuple: (a: felt, b: felt); +/// assert res_simple_struct = SimpleStruct(a=simple_struct.a + 1, b=simple_struct.b + 2); +/// assert res_compound_struct = CompoundStruct(a=compound_struct.a + 1, +/// simple_struct=compound_struct.simple_struct); +/// assert res_named_tuple = (a=named_tuple.a + tuple[0], b=named_tuple.b + tuple[1]); +/// return (res1=res_named_tuple, res2=res_simple_struct, res3=res_compound_struct); +/// } +/// +/// func pass_implicit_args{range_check_ptr, compound_struct: CompoundStruct*, simple_struct: +/// SimpleStruct}(number_1: felt, number_2: felt) -> (res: felt) { +/// assert_lt(number_1, number_2); +/// let sum = number_1 + number_2; +/// return (res=sum); +/// } +const COMPILED_DUMMY_FUNCTION: &str = include_str!("compiled_dummy_function.json"); + +#[test] +fn test_felt_and_pointers() -> Cairo0EntryPointRunnerResult<()> { + // Parameters. + let number = 2; + let (first_array_val, second_array_val) = (3, 4); + let (first_tuple_val, second_tuple_val) = (5, 6); + let (first_simple_struct_val, second_simple_struct_val) = (7, 8); + let compound_struct_val = 9; + let array = EndpointArg::Pointer(PointerArg::Array(vec![ + first_array_val.into(), + second_array_val.into(), + ])); + let tuple = EndpointArg::Pointer(PointerArg::Array(vec![ + first_tuple_val.into(), + second_tuple_val.into(), + ])); + let simple_struct = EndpointArg::Pointer(PointerArg::Array(vec![ + first_simple_struct_val.into(), + second_simple_struct_val.into(), + ])); + let compound_struct = EndpointArg::Pointer(PointerArg::Composed(vec![ + compound_struct_val.into(), + simple_struct.clone(), + ])); + + // Expected return values. + let res1 = EndpointArg::Value(ValueArg::Single((number + 1).into())); + let res2 = EndpointArg::Pointer(PointerArg::Array(vec![ + (first_array_val + 1).into(), + (second_array_val + 2).into(), + ])); + let res3 = EndpointArg::Pointer(PointerArg::Array(vec![ + (first_tuple_val + 1).into(), + (second_tuple_val + 2).into(), + ])); + let res_simple_struct = EndpointArg::Pointer(PointerArg::Array(vec![ + first_simple_struct_val.into(), + second_simple_struct_val.into(), + ])); + let res4 = EndpointArg::Pointer(PointerArg::Composed(vec![ + (compound_struct_val + 1).into(), + res_simple_struct.clone(), + ])); + + run_cairo_function_and_check_result( + COMPILED_DUMMY_FUNCTION, + "pass_felt_and_pointers", + &[number.into(), array, tuple, simple_struct, compound_struct], + &[], + &[res1, res2, res3, res4], + &[], + ) +} + +#[test] +fn test_tuples_and_structs() -> Cairo0EntryPointRunnerResult<()> { + // Parameters. + let (first_tuple_val, second_tuple_val) = (3, 4); + let (first_named_tuple_val, second_named_tuple_val) = (5, 6); + let (first_simple_struct_val, second_simple_struct_val) = (7, 8); + let compound_struct_val = 9; + let tuple = + EndpointArg::Value(ValueArg::Array(vec![first_tuple_val.into(), second_tuple_val.into()])); + let named_tuple = EndpointArg::Value(ValueArg::Array(vec![ + first_named_tuple_val.into(), + second_named_tuple_val.into(), + ])); + let simple_struct = EndpointArg::Value(ValueArg::Array(vec![ + first_simple_struct_val.into(), + second_simple_struct_val.into(), + ])); + let simple_struct_pointer = EndpointArg::Pointer(PointerArg::Array(vec![ + first_simple_struct_val.into(), + second_simple_struct_val.into(), + ])); + let compound_struct = EndpointArg::Value(ValueArg::Composed(vec![ + compound_struct_val.into(), + simple_struct_pointer, + ])); + + // Expected return values. + let res1 = EndpointArg::Value(ValueArg::Array(vec![ + (first_named_tuple_val + first_tuple_val).into(), + (second_named_tuple_val + second_tuple_val).into(), + ])); + let res2 = EndpointArg::Value(ValueArg::Array(vec![ + (first_simple_struct_val + 1).into(), + (second_simple_struct_val + 2).into(), + ])); + let res_simple_struct_pointer = EndpointArg::Pointer(PointerArg::Array(vec![ + first_simple_struct_val.into(), + second_simple_struct_val.into(), + ])); + let res3 = EndpointArg::Value(ValueArg::Composed(vec![ + (compound_struct_val + 1).into(), + res_simple_struct_pointer, + ])); + + run_cairo_function_and_check_result( + COMPILED_DUMMY_FUNCTION, + "pass_structs_and_tuples", + &[tuple, named_tuple, simple_struct, compound_struct], + &[], + &[res1, res2, res3], + &[], + ) +} + +#[test] +fn test_implicit_args() -> Cairo0EntryPointRunnerResult<()> { + let number_1 = 1; + let number_2 = 2; + let (first_simple_struct_val, second_simple_struct_val) = (7, 8); + let compound_struct_val = 9; + let simple_struct = EndpointArg::Value(ValueArg::Array(vec![ + first_simple_struct_val.into(), + second_simple_struct_val.into(), + ])); + let inner_simple_struct = EndpointArg::Pointer(PointerArg::Array(vec![ + first_simple_struct_val.into(), + (second_simple_struct_val + 1).into(), + ])); + let compound_struct = EndpointArg::Pointer(PointerArg::Composed(vec![ + compound_struct_val.into(), + inner_simple_struct, + ])); + run_cairo_function_and_check_result( + COMPILED_DUMMY_FUNCTION, + "pass_implicit_args", + &[number_1.into(), number_2.into()], + &[ + ImplicitArg::Builtin(BuiltinName::range_check), + ImplicitArg::NonBuiltin(compound_struct.clone()), + ImplicitArg::NonBuiltin(simple_struct.clone()), + ], + &[(number_1 + number_2).into()], + &[ + ImplicitArg::Builtin(BuiltinName::range_check), + ImplicitArg::NonBuiltin(compound_struct), + ImplicitArg::NonBuiltin(simple_struct), + ], + ) +} diff --git a/crates/starknet_os/src/test_utils/compiled_dummy_function.json b/crates/starknet_os/src/test_utils/compiled_dummy_function.json new file mode 100644 index 00000000000..77ac4c9cd3b --- /dev/null +++ b/crates/starknet_os/src/test_utils/compiled_dummy_function.json @@ -0,0 +1,1468 @@ +{ + "prime": "0x800000000000011000000000000000000000000000000000000000000000001", + "data": [ + "0x40780017fff7fff", + "0x1", + "0x208b7fff7fff7ffe", + "0x400380007ffc7ffd", + "0x482680017ffc8000", + "0x1", + "0x208b7fff7fff7ffe", + "0x480a7ffb7fff8000", + "0x48297ffc80007ffd", + "0x1104800180018000", + "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffffb", + "0x208b7fff7fff7ffe", + "0x480a7ffb7fff8000", + "0x480a7ffc7fff8000", + "0x482680017ffd8000", + "0x800000000000011000000000000000000000000000000000000000000000000", + "0x1104800180018000", + "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffff8", + "0x208b7fff7fff7ffe", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffee", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffec", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffea", + "0x480280007ffa8000", + "0x482480017fff8000", + "0x1", + "0x400080007ff77fff", + "0x480280017ffa8000", + "0x482480017fff8000", + "0x2", + "0x400080017ff57fff", + "0x480280007ffb8000", + "0x482480017fff8000", + "0x1", + "0x400080007ff67fff", + "0x480280017ffb8000", + "0x482480017fff8000", + "0x2", + "0x400080017ff47fff", + "0x480280007ffd8000", + "0x482480017fff8000", + "0x1", + "0x400080007ff57fff", + "0x480280017ffd8000", + "0x400080017ff47fff", + "0x482680017ff98000", + "0x1", + "0x48127fed7fff8000", + "0x48127fef7fff8000", + "0x48127ff17fff8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x6", + "0x402780017ffa8000", + "0x1", + "0x402780017ffb8001", + "0x2", + "0x402780017ffc8002", + "0x1", + "0x400b7ffd7fff8003", + "0x402b7ff67ff88004", + "0x402b7ff77ff98005", + "0x480a80047fff8000", + "0x480a80057fff8000", + "0x480a80007fff8000", + "0x480a80017fff8000", + "0x480a80027fff8000", + "0x480a80037fff8000", + "0x208b7fff7fff7ffe", + "0x480a7ff87fff8000", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffc3", + "0x480a7ff97fff8000", + "0x480a7ffa7fff8000", + "0x480a7ffb7fff8000", + "0x482a7ffd7ffc8000", + "0x208b7fff7fff7ffe" + ], + "builtins": [], + "hints": { + "0": [ + { + "code": "memory[ap] = segments.add()", + "accessible_scopes": [ + "starkware.cairo.common.alloc", + "starkware.cairo.common.alloc.alloc" + ], + "flow_tracking_data": { + "ap_tracking": { + "group": 0, + "offset": 0 + }, + "reference_ids": {} + } + } + ], + "3": [ + { + "code": "from starkware.cairo.common.math_utils import assert_integer\nassert_integer(ids.a)\nassert 0 <= ids.a % PRIME < range_check_builtin.bound, f'a = {ids.a} is out of range.'", + "accessible_scopes": [ + "starkware.cairo.common.math", + "starkware.cairo.common.math.assert_nn" + ], + "flow_tracking_data": { + "ap_tracking": { + "group": 1, + "offset": 0 + }, + "reference_ids": { + "starkware.cairo.common.math.assert_nn.a": 0, + "starkware.cairo.common.math.assert_nn.range_check_ptr": 1 + } + } + } + ] + }, + "compiler_version": "0.14.0", + "main_scope": "__main__", + "identifiers": { + "starkware.cairo.common.alloc.alloc": { + "pc": 0, + "decorators": [], + "type": "function" + }, + "starkware.cairo.common.alloc.alloc.Args": { + "full_name": "starkware.cairo.common.alloc.alloc.Args", + "members": {}, + "size": 0, + "type": "struct" + }, + "starkware.cairo.common.alloc.alloc.ImplicitArgs": { + "full_name": "starkware.cairo.common.alloc.alloc.ImplicitArgs", + "members": {}, + "size": 0, + "type": "struct" + }, + "starkware.cairo.common.alloc.alloc.Return": { + "cairo_type": "(ptr: felt*)", + "type": "type_definition" + }, + "starkware.cairo.common.alloc.alloc.SIZEOF_LOCALS": { + "value": 0, + "type": "const" + }, + "starkware.cairo.common.bool.FALSE": { + "value": 0, + "type": "const" + }, + "starkware.cairo.common.bool.TRUE": { + "value": 1, + "type": "const" + }, + "starkware.cairo.common.math.FALSE": { + "destination": "starkware.cairo.common.bool.FALSE", + "type": "alias" + }, + "starkware.cairo.common.math.TRUE": { + "destination": "starkware.cairo.common.bool.TRUE", + "type": "alias" + }, + "starkware.cairo.common.math.assert_nn": { + "pc": 3, + "decorators": [], + "type": "function" + }, + "starkware.cairo.common.math.assert_nn.Args": { + "full_name": "starkware.cairo.common.math.assert_nn.Args", + "members": { + "a": { + "offset": 0, + "cairo_type": "felt" + } + }, + "size": 1, + "type": "struct" + }, + "starkware.cairo.common.math.assert_nn.a": { + "full_name": "starkware.cairo.common.math.assert_nn.a", + "cairo_type": "felt", + "references": [ + { + "pc": 3, + "value": "[cast(fp + (-3), felt*)]", + "ap_tracking_data": { + "group": 1, + "offset": 0 + } + } + ], + "type": "reference" + }, + "starkware.cairo.common.math.assert_nn.ImplicitArgs": { + "full_name": "starkware.cairo.common.math.assert_nn.ImplicitArgs", + "members": { + "range_check_ptr": { + "offset": 0, + "cairo_type": "felt" + } + }, + "size": 1, + "type": "struct" + }, + "starkware.cairo.common.math.assert_nn.range_check_ptr": { + "full_name": "starkware.cairo.common.math.assert_nn.range_check_ptr", + "cairo_type": "felt", + "references": [ + { + "pc": 3, + "value": "[cast(fp + (-4), felt*)]", + "ap_tracking_data": { + "group": 1, + "offset": 0 + } + }, + { + "pc": 4, + "value": "cast([fp + (-4)] + 1, felt)", + "ap_tracking_data": { + "group": 1, + "offset": 0 + } + } + ], + "type": "reference" + }, + "starkware.cairo.common.math.assert_nn.Return": { + "cairo_type": "()", + "type": "type_definition" + }, + "starkware.cairo.common.math.assert_nn.SIZEOF_LOCALS": { + "value": 0, + "type": "const" + }, + "starkware.cairo.common.math.assert_le": { + "pc": 7, + "decorators": [], + "type": "function" + }, + "starkware.cairo.common.math.assert_le.Args": { + "full_name": "starkware.cairo.common.math.assert_le.Args", + "members": { + "a": { + "offset": 0, + "cairo_type": "felt" + }, + "b": { + "offset": 1, + "cairo_type": "felt" + } + }, + "size": 2, + "type": "struct" + }, + "starkware.cairo.common.math.assert_le.a": { + "full_name": "starkware.cairo.common.math.assert_le.a", + "cairo_type": "felt", + "references": [ + { + "pc": 7, + "value": "[cast(fp + (-4), felt*)]", + "ap_tracking_data": { + "group": 2, + "offset": 0 + } + } + ], + "type": "reference" + }, + "starkware.cairo.common.math.assert_le.b": { + "full_name": "starkware.cairo.common.math.assert_le.b", + "cairo_type": "felt", + "references": [ + { + "pc": 7, + "value": "[cast(fp + (-3), felt*)]", + "ap_tracking_data": { + "group": 2, + "offset": 0 + } + } + ], + "type": "reference" + }, + "starkware.cairo.common.math.assert_le.ImplicitArgs": { + "full_name": "starkware.cairo.common.math.assert_le.ImplicitArgs", + "members": { + "range_check_ptr": { + "offset": 0, + "cairo_type": "felt" + } + }, + "size": 1, + "type": "struct" + }, + "starkware.cairo.common.math.assert_le.range_check_ptr": { + "full_name": "starkware.cairo.common.math.assert_le.range_check_ptr", + "cairo_type": "felt", + "references": [ + { + "pc": 7, + "value": "[cast(fp + (-5), felt*)]", + "ap_tracking_data": { + "group": 2, + "offset": 0 + } + }, + { + "pc": 11, + "value": "[cast(ap + (-1), felt*)]", + "ap_tracking_data": { + "group": 2, + "offset": 5 + } + } + ], + "type": "reference" + }, + "starkware.cairo.common.math.assert_le.Return": { + "cairo_type": "()", + "type": "type_definition" + }, + "starkware.cairo.common.math.assert_le.SIZEOF_LOCALS": { + "value": 0, + "type": "const" + }, + "starkware.cairo.common.math.assert_lt": { + "pc": 12, + "decorators": [], + "type": "function" + }, + "starkware.cairo.common.math.assert_lt.Args": { + "full_name": "starkware.cairo.common.math.assert_lt.Args", + "members": { + "a": { + "offset": 0, + "cairo_type": "felt" + }, + "b": { + "offset": 1, + "cairo_type": "felt" + } + }, + "size": 2, + "type": "struct" + }, + "starkware.cairo.common.math.assert_lt.a": { + "full_name": "starkware.cairo.common.math.assert_lt.a", + "cairo_type": "felt", + "references": [ + { + "pc": 12, + "value": "[cast(fp + (-4), felt*)]", + "ap_tracking_data": { + "group": 3, + "offset": 0 + } + } + ], + "type": "reference" + }, + "starkware.cairo.common.math.assert_lt.b": { + "full_name": "starkware.cairo.common.math.assert_lt.b", + "cairo_type": "felt", + "references": [ + { + "pc": 12, + "value": "[cast(fp + (-3), felt*)]", + "ap_tracking_data": { + "group": 3, + "offset": 0 + } + } + ], + "type": "reference" + }, + "starkware.cairo.common.math.assert_lt.ImplicitArgs": { + "full_name": "starkware.cairo.common.math.assert_lt.ImplicitArgs", + "members": { + "range_check_ptr": { + "offset": 0, + "cairo_type": "felt" + } + }, + "size": 1, + "type": "struct" + }, + "starkware.cairo.common.math.assert_lt.range_check_ptr": { + "full_name": "starkware.cairo.common.math.assert_lt.range_check_ptr", + "cairo_type": "felt", + "references": [ + { + "pc": 12, + "value": "[cast(fp + (-5), felt*)]", + "ap_tracking_data": { + "group": 3, + "offset": 0 + } + }, + { + "pc": 18, + "value": "[cast(ap + (-1), felt*)]", + "ap_tracking_data": { + "group": 3, + "offset": 10 + } + } + ], + "type": "reference" + }, + "starkware.cairo.common.math.assert_lt.Return": { + "cairo_type": "()", + "type": "type_definition" + }, + "starkware.cairo.common.math.assert_lt.SIZEOF_LOCALS": { + "value": 0, + "type": "const" + }, + "__main__.alloc": { + "destination": "starkware.cairo.common.alloc.alloc", + "type": "alias" + }, + "__main__.assert_lt": { + "destination": "starkware.cairo.common.math.assert_lt", + "type": "alias" + }, + "__main__.CompoundStruct": { + "full_name": "__main__.CompoundStruct", + "members": { + "a": { + "offset": 0, + "cairo_type": "felt" + }, + "simple_struct": { + "offset": 1, + "cairo_type": "__main__.SimpleStruct*" + } + }, + "size": 2, + "type": "struct" + }, + "__main__.SimpleStruct": { + "full_name": "__main__.SimpleStruct", + "members": { + "a": { + "offset": 0, + "cairo_type": "felt" + }, + "b": { + "offset": 1, + "cairo_type": "felt" + } + }, + "size": 2, + "type": "struct" + }, + "__main__.pass_felt_and_pointers": { + "pc": 19, + "decorators": [], + "type": "function" + }, + "__main__.pass_felt_and_pointers.Args": { + "full_name": "__main__.pass_felt_and_pointers.Args", + "members": { + "number": { + "offset": 0, + "cairo_type": "felt" + }, + "array": { + "offset": 1, + "cairo_type": "felt*" + }, + "tuple": { + "offset": 2, + "cairo_type": "felt*" + }, + "simple_struct": { + "offset": 3, + "cairo_type": "__main__.SimpleStruct*" + }, + "compound_struct": { + "offset": 4, + "cairo_type": "__main__.CompoundStruct*" + } + }, + "size": 5, + "type": "struct" + }, + "__main__.pass_felt_and_pointers.number": { + "full_name": "__main__.pass_felt_and_pointers.number", + "cairo_type": "felt", + "references": [ + { + "pc": 19, + "value": "[cast(fp + (-7), felt*)]", + "ap_tracking_data": { + "group": 4, + "offset": 0 + } + } + ], + "type": "reference" + }, + "__main__.pass_felt_and_pointers.array": { + "full_name": "__main__.pass_felt_and_pointers.array", + "cairo_type": "felt*", + "references": [ + { + "pc": 19, + "value": "[cast(fp + (-6), felt**)]", + "ap_tracking_data": { + "group": 4, + "offset": 0 + } + } + ], + "type": "reference" + }, + "__main__.pass_felt_and_pointers.tuple": { + "full_name": "__main__.pass_felt_and_pointers.tuple", + "cairo_type": "felt*", + "references": [ + { + "pc": 19, + "value": "[cast(fp + (-5), felt**)]", + "ap_tracking_data": { + "group": 4, + "offset": 0 + } + } + ], + "type": "reference" + }, + "__main__.pass_felt_and_pointers.simple_struct": { + "full_name": "__main__.pass_felt_and_pointers.simple_struct", + "cairo_type": "__main__.SimpleStruct*", + "references": [ + { + "pc": 19, + "value": "[cast(fp + (-4), __main__.SimpleStruct**)]", + "ap_tracking_data": { + "group": 4, + "offset": 0 + } + } + ], + "type": "reference" + }, + "__main__.pass_felt_and_pointers.compound_struct": { + "full_name": "__main__.pass_felt_and_pointers.compound_struct", + "cairo_type": "__main__.CompoundStruct*", + "references": [ + { + "pc": 19, + "value": "[cast(fp + (-3), __main__.CompoundStruct**)]", + "ap_tracking_data": { + "group": 4, + "offset": 0 + } + } + ], + "type": "reference" + }, + "__main__.pass_felt_and_pointers.ImplicitArgs": { + "full_name": "__main__.pass_felt_and_pointers.ImplicitArgs", + "members": {}, + "size": 0, + "type": "struct" + }, + "__main__.pass_felt_and_pointers.Return": { + "cairo_type": "(res1: felt, res2: felt*, res3: felt*, res4: __main__.CompoundStruct*)", + "type": "type_definition" + }, + "__main__.pass_felt_and_pointers.SIZEOF_LOCALS": { + "value": 0, + "type": "const" + }, + "__main__.pass_felt_and_pointers.res_array": { + "full_name": "__main__.pass_felt_and_pointers.res_array", + "cairo_type": "felt*", + "references": [ + { + "pc": 21, + "value": "[cast(ap + (-1), felt**)]", + "ap_tracking_data": { + "group": 4, + "offset": 3 + } + } + ], + "type": "reference" + }, + "__main__.pass_felt_and_pointers.res_tuple": { + "full_name": "__main__.pass_felt_and_pointers.res_tuple", + "cairo_type": "felt*", + "references": [ + { + "pc": 23, + "value": "[cast(ap + (-1), felt**)]", + "ap_tracking_data": { + "group": 4, + "offset": 6 + } + } + ], + "type": "reference" + }, + "__main__.pass_felt_and_pointers.res_compound_struct": { + "full_name": "__main__.pass_felt_and_pointers.res_compound_struct", + "cairo_type": "__main__.CompoundStruct*", + "references": [ + { + "pc": 25, + "value": "[cast(ap + (-1), __main__.CompoundStruct**)]", + "ap_tracking_data": { + "group": 4, + "offset": 9 + } + } + ], + "type": "reference" + }, + "__main__.pass_felt_and_pointers.res_number": { + "full_name": "__main__.pass_felt_and_pointers.res_number", + "cairo_type": "felt", + "references": [ + { + "pc": 47, + "value": "cast([fp + (-7)] + 1, felt)", + "ap_tracking_data": { + "group": 4, + "offset": 20 + } + } + ], + "type": "reference" + }, + "__main__.pass_structs_and_tuples": { + "pc": 53, + "decorators": [], + "type": "function" + }, + "__main__.pass_structs_and_tuples.Args": { + "full_name": "__main__.pass_structs_and_tuples.Args", + "members": { + "tuple": { + "offset": 0, + "cairo_type": "(felt, felt)" + }, + "named_tuple": { + "offset": 2, + "cairo_type": "(a: felt, b: felt)" + }, + "simple_struct": { + "offset": 4, + "cairo_type": "__main__.SimpleStruct" + }, + "compound_struct": { + "offset": 6, + "cairo_type": "__main__.CompoundStruct" + } + }, + "size": 8, + "type": "struct" + }, + "__main__.pass_structs_and_tuples.tuple": { + "full_name": "__main__.pass_structs_and_tuples.tuple", + "cairo_type": "(felt, felt)", + "references": [ + { + "pc": 53, + "value": "[cast(fp + (-10), (felt, felt)*)]", + "ap_tracking_data": { + "group": 5, + "offset": 0 + } + } + ], + "type": "reference" + }, + "__main__.pass_structs_and_tuples.named_tuple": { + "full_name": "__main__.pass_structs_and_tuples.named_tuple", + "cairo_type": "(a: felt, b: felt)", + "references": [ + { + "pc": 53, + "value": "[cast(fp + (-8), (a: felt, b: felt)*)]", + "ap_tracking_data": { + "group": 5, + "offset": 0 + } + } + ], + "type": "reference" + }, + "__main__.pass_structs_and_tuples.simple_struct": { + "full_name": "__main__.pass_structs_and_tuples.simple_struct", + "cairo_type": "__main__.SimpleStruct", + "references": [ + { + "pc": 53, + "value": "[cast(fp + (-6), __main__.SimpleStruct*)]", + "ap_tracking_data": { + "group": 5, + "offset": 0 + } + } + ], + "type": "reference" + }, + "__main__.pass_structs_and_tuples.compound_struct": { + "full_name": "__main__.pass_structs_and_tuples.compound_struct", + "cairo_type": "__main__.CompoundStruct", + "references": [ + { + "pc": 53, + "value": "[cast(fp + (-4), __main__.CompoundStruct*)]", + "ap_tracking_data": { + "group": 5, + "offset": 0 + } + } + ], + "type": "reference" + }, + "__main__.pass_structs_and_tuples.ImplicitArgs": { + "full_name": "__main__.pass_structs_and_tuples.ImplicitArgs", + "members": {}, + "size": 0, + "type": "struct" + }, + "__main__.pass_structs_and_tuples.Return": { + "cairo_type": "(res1: (a: felt, b: felt), res2: __main__.SimpleStruct, res3: __main__.CompoundStruct)", + "type": "type_definition" + }, + "__main__.pass_structs_and_tuples.SIZEOF_LOCALS": { + "value": 6, + "type": "const" + }, + "__main__.pass_structs_and_tuples.res_simple_struct": { + "full_name": "__main__.pass_structs_and_tuples.res_simple_struct", + "cairo_type": "__main__.SimpleStruct", + "references": [ + { + "pc": 55, + "value": "[cast(fp, __main__.SimpleStruct*)]", + "ap_tracking_data": { + "group": 5, + "offset": 6 + } + } + ], + "type": "reference" + }, + "__main__.pass_structs_and_tuples.res_compound_struct": { + "full_name": "__main__.pass_structs_and_tuples.res_compound_struct", + "cairo_type": "__main__.CompoundStruct", + "references": [ + { + "pc": 55, + "value": "[cast(fp + 2, __main__.CompoundStruct*)]", + "ap_tracking_data": { + "group": 5, + "offset": 6 + } + } + ], + "type": "reference" + }, + "__main__.pass_structs_and_tuples.res_named_tuple": { + "full_name": "__main__.pass_structs_and_tuples.res_named_tuple", + "cairo_type": "(a: felt, b: felt)", + "references": [ + { + "pc": 55, + "value": "[cast(fp + 4, (a: felt, b: felt)*)]", + "ap_tracking_data": { + "group": 5, + "offset": 6 + } + } + ], + "type": "reference" + }, + "__main__.pass_implicit_args": { + "pc": 71, + "decorators": [], + "type": "function" + }, + "__main__.pass_implicit_args.Args": { + "full_name": "__main__.pass_implicit_args.Args", + "members": { + "number_1": { + "offset": 0, + "cairo_type": "felt" + }, + "number_2": { + "offset": 1, + "cairo_type": "felt" + } + }, + "size": 2, + "type": "struct" + }, + "__main__.pass_implicit_args.number_1": { + "full_name": "__main__.pass_implicit_args.number_1", + "cairo_type": "felt", + "references": [ + { + "pc": 71, + "value": "[cast(fp + (-4), felt*)]", + "ap_tracking_data": { + "group": 6, + "offset": 0 + } + } + ], + "type": "reference" + }, + "__main__.pass_implicit_args.number_2": { + "full_name": "__main__.pass_implicit_args.number_2", + "cairo_type": "felt", + "references": [ + { + "pc": 71, + "value": "[cast(fp + (-3), felt*)]", + "ap_tracking_data": { + "group": 6, + "offset": 0 + } + } + ], + "type": "reference" + }, + "__main__.pass_implicit_args.ImplicitArgs": { + "full_name": "__main__.pass_implicit_args.ImplicitArgs", + "members": { + "range_check_ptr": { + "offset": 0, + "cairo_type": "felt" + }, + "compound_struct": { + "offset": 1, + "cairo_type": "__main__.CompoundStruct*" + }, + "simple_struct": { + "offset": 2, + "cairo_type": "__main__.SimpleStruct" + } + }, + "size": 4, + "type": "struct" + }, + "__main__.pass_implicit_args.range_check_ptr": { + "full_name": "__main__.pass_implicit_args.range_check_ptr", + "cairo_type": "felt", + "references": [ + { + "pc": 71, + "value": "[cast(fp + (-8), felt*)]", + "ap_tracking_data": { + "group": 6, + "offset": 0 + } + }, + { + "pc": 76, + "value": "[cast(ap + (-1), felt*)]", + "ap_tracking_data": { + "group": 6, + "offset": 15 + } + } + ], + "type": "reference" + }, + "__main__.pass_implicit_args.compound_struct": { + "full_name": "__main__.pass_implicit_args.compound_struct", + "cairo_type": "__main__.CompoundStruct*", + "references": [ + { + "pc": 71, + "value": "[cast(fp + (-7), __main__.CompoundStruct**)]", + "ap_tracking_data": { + "group": 6, + "offset": 0 + } + } + ], + "type": "reference" + }, + "__main__.pass_implicit_args.simple_struct": { + "full_name": "__main__.pass_implicit_args.simple_struct", + "cairo_type": "__main__.SimpleStruct", + "references": [ + { + "pc": 71, + "value": "[cast(fp + (-6), __main__.SimpleStruct*)]", + "ap_tracking_data": { + "group": 6, + "offset": 0 + } + } + ], + "type": "reference" + }, + "__main__.pass_implicit_args.Return": { + "cairo_type": "(res: felt)", + "type": "type_definition" + }, + "__main__.pass_implicit_args.SIZEOF_LOCALS": { + "value": 0, + "type": "const" + }, + "__main__.pass_implicit_args.sum": { + "full_name": "__main__.pass_implicit_args.sum", + "cairo_type": "felt", + "references": [ + { + "pc": 76, + "value": "cast([fp + (-4)] + [fp + (-3)], felt)", + "ap_tracking_data": { + "group": 6, + "offset": 15 + } + } + ], + "type": "reference" + }, + "__main__.pass_felt_and_pointers.__temp0": { + "full_name": "__main__.pass_felt_and_pointers.__temp0", + "cairo_type": "felt", + "references": [ + { + "pc": 26, + "value": "[cast(ap + (-1), felt*)]", + "ap_tracking_data": { + "group": 4, + "offset": 10 + } + } + ], + "type": "reference" + }, + "__main__.pass_felt_and_pointers.__temp1": { + "full_name": "__main__.pass_felt_and_pointers.__temp1", + "cairo_type": "felt", + "references": [ + { + "pc": 28, + "value": "[cast(ap + (-1), felt*)]", + "ap_tracking_data": { + "group": 4, + "offset": 11 + } + } + ], + "type": "reference" + }, + "__main__.pass_felt_and_pointers.__temp2": { + "full_name": "__main__.pass_felt_and_pointers.__temp2", + "cairo_type": "felt", + "references": [ + { + "pc": 30, + "value": "[cast(ap + (-1), felt*)]", + "ap_tracking_data": { + "group": 4, + "offset": 12 + } + } + ], + "type": "reference" + }, + "__main__.pass_felt_and_pointers.__temp3": { + "full_name": "__main__.pass_felt_and_pointers.__temp3", + "cairo_type": "felt", + "references": [ + { + "pc": 32, + "value": "[cast(ap + (-1), felt*)]", + "ap_tracking_data": { + "group": 4, + "offset": 13 + } + } + ], + "type": "reference" + }, + "__main__.pass_felt_and_pointers.__temp4": { + "full_name": "__main__.pass_felt_and_pointers.__temp4", + "cairo_type": "felt", + "references": [ + { + "pc": 34, + "value": "[cast(ap + (-1), felt*)]", + "ap_tracking_data": { + "group": 4, + "offset": 14 + } + } + ], + "type": "reference" + }, + "__main__.pass_felt_and_pointers.__temp5": { + "full_name": "__main__.pass_felt_and_pointers.__temp5", + "cairo_type": "felt", + "references": [ + { + "pc": 36, + "value": "[cast(ap + (-1), felt*)]", + "ap_tracking_data": { + "group": 4, + "offset": 15 + } + } + ], + "type": "reference" + }, + "__main__.pass_felt_and_pointers.__temp6": { + "full_name": "__main__.pass_felt_and_pointers.__temp6", + "cairo_type": "felt", + "references": [ + { + "pc": 38, + "value": "[cast(ap + (-1), felt*)]", + "ap_tracking_data": { + "group": 4, + "offset": 16 + } + } + ], + "type": "reference" + }, + "__main__.pass_felt_and_pointers.__temp7": { + "full_name": "__main__.pass_felt_and_pointers.__temp7", + "cairo_type": "felt", + "references": [ + { + "pc": 40, + "value": "[cast(ap + (-1), felt*)]", + "ap_tracking_data": { + "group": 4, + "offset": 17 + } + } + ], + "type": "reference" + }, + "__main__.pass_felt_and_pointers.__temp8": { + "full_name": "__main__.pass_felt_and_pointers.__temp8", + "cairo_type": "felt", + "references": [ + { + "pc": 42, + "value": "[cast(ap + (-1), felt*)]", + "ap_tracking_data": { + "group": 4, + "offset": 18 + } + } + ], + "type": "reference" + }, + "__main__.pass_felt_and_pointers.__temp9": { + "full_name": "__main__.pass_felt_and_pointers.__temp9", + "cairo_type": "felt", + "references": [ + { + "pc": 44, + "value": "[cast(ap + (-1), felt*)]", + "ap_tracking_data": { + "group": 4, + "offset": 19 + } + } + ], + "type": "reference" + }, + "__main__.pass_felt_and_pointers.__temp10": { + "full_name": "__main__.pass_felt_and_pointers.__temp10", + "cairo_type": "felt", + "references": [ + { + "pc": 46, + "value": "[cast(ap + (-1), felt*)]", + "ap_tracking_data": { + "group": 4, + "offset": 20 + } + } + ], + "type": "reference" + } + }, + "reference_manager": { + "references": [ + { + "pc": 3, + "value": "[cast(fp + (-3), felt*)]", + "ap_tracking_data": { + "group": 1, + "offset": 0 + } + }, + { + "pc": 3, + "value": "[cast(fp + (-4), felt*)]", + "ap_tracking_data": { + "group": 1, + "offset": 0 + } + }, + { + "pc": 4, + "value": "cast([fp + (-4)] + 1, felt)", + "ap_tracking_data": { + "group": 1, + "offset": 0 + } + }, + { + "pc": 7, + "value": "[cast(fp + (-4), felt*)]", + "ap_tracking_data": { + "group": 2, + "offset": 0 + } + }, + { + "pc": 7, + "value": "[cast(fp + (-3), felt*)]", + "ap_tracking_data": { + "group": 2, + "offset": 0 + } + }, + { + "pc": 7, + "value": "[cast(fp + (-5), felt*)]", + "ap_tracking_data": { + "group": 2, + "offset": 0 + } + }, + { + "pc": 11, + "value": "[cast(ap + (-1), felt*)]", + "ap_tracking_data": { + "group": 2, + "offset": 5 + } + }, + { + "pc": 12, + "value": "[cast(fp + (-4), felt*)]", + "ap_tracking_data": { + "group": 3, + "offset": 0 + } + }, + { + "pc": 12, + "value": "[cast(fp + (-3), felt*)]", + "ap_tracking_data": { + "group": 3, + "offset": 0 + } + }, + { + "pc": 12, + "value": "[cast(fp + (-5), felt*)]", + "ap_tracking_data": { + "group": 3, + "offset": 0 + } + }, + { + "pc": 18, + "value": "[cast(ap + (-1), felt*)]", + "ap_tracking_data": { + "group": 3, + "offset": 10 + } + }, + { + "pc": 19, + "value": "[cast(fp + (-7), felt*)]", + "ap_tracking_data": { + "group": 4, + "offset": 0 + } + }, + { + "pc": 19, + "value": "[cast(fp + (-6), felt**)]", + "ap_tracking_data": { + "group": 4, + "offset": 0 + } + }, + { + "pc": 19, + "value": "[cast(fp + (-5), felt**)]", + "ap_tracking_data": { + "group": 4, + "offset": 0 + } + }, + { + "pc": 19, + "value": "[cast(fp + (-4), __main__.SimpleStruct**)]", + "ap_tracking_data": { + "group": 4, + "offset": 0 + } + }, + { + "pc": 19, + "value": "[cast(fp + (-3), __main__.CompoundStruct**)]", + "ap_tracking_data": { + "group": 4, + "offset": 0 + } + }, + { + "pc": 21, + "value": "[cast(ap + (-1), felt**)]", + "ap_tracking_data": { + "group": 4, + "offset": 3 + } + }, + { + "pc": 23, + "value": "[cast(ap + (-1), felt**)]", + "ap_tracking_data": { + "group": 4, + "offset": 6 + } + }, + { + "pc": 25, + "value": "[cast(ap + (-1), __main__.CompoundStruct**)]", + "ap_tracking_data": { + "group": 4, + "offset": 9 + } + }, + { + "pc": 26, + "value": "[cast(ap + (-1), felt*)]", + "ap_tracking_data": { + "group": 4, + "offset": 10 + } + }, + { + "pc": 28, + "value": "[cast(ap + (-1), felt*)]", + "ap_tracking_data": { + "group": 4, + "offset": 11 + } + }, + { + "pc": 30, + "value": "[cast(ap + (-1), felt*)]", + "ap_tracking_data": { + "group": 4, + "offset": 12 + } + }, + { + "pc": 32, + "value": "[cast(ap + (-1), felt*)]", + "ap_tracking_data": { + "group": 4, + "offset": 13 + } + }, + { + "pc": 34, + "value": "[cast(ap + (-1), felt*)]", + "ap_tracking_data": { + "group": 4, + "offset": 14 + } + }, + { + "pc": 36, + "value": "[cast(ap + (-1), felt*)]", + "ap_tracking_data": { + "group": 4, + "offset": 15 + } + }, + { + "pc": 38, + "value": "[cast(ap + (-1), felt*)]", + "ap_tracking_data": { + "group": 4, + "offset": 16 + } + }, + { + "pc": 40, + "value": "[cast(ap + (-1), felt*)]", + "ap_tracking_data": { + "group": 4, + "offset": 17 + } + }, + { + "pc": 42, + "value": "[cast(ap + (-1), felt*)]", + "ap_tracking_data": { + "group": 4, + "offset": 18 + } + }, + { + "pc": 44, + "value": "[cast(ap + (-1), felt*)]", + "ap_tracking_data": { + "group": 4, + "offset": 19 + } + }, + { + "pc": 46, + "value": "[cast(ap + (-1), felt*)]", + "ap_tracking_data": { + "group": 4, + "offset": 20 + } + }, + { + "pc": 47, + "value": "cast([fp + (-7)] + 1, felt)", + "ap_tracking_data": { + "group": 4, + "offset": 20 + } + }, + { + "pc": 53, + "value": "[cast(fp + (-10), (felt, felt)*)]", + "ap_tracking_data": { + "group": 5, + "offset": 0 + } + }, + { + "pc": 53, + "value": "[cast(fp + (-8), (a: felt, b: felt)*)]", + "ap_tracking_data": { + "group": 5, + "offset": 0 + } + }, + { + "pc": 53, + "value": "[cast(fp + (-6), __main__.SimpleStruct*)]", + "ap_tracking_data": { + "group": 5, + "offset": 0 + } + }, + { + "pc": 53, + "value": "[cast(fp + (-4), __main__.CompoundStruct*)]", + "ap_tracking_data": { + "group": 5, + "offset": 0 + } + }, + { + "pc": 55, + "value": "[cast(fp, __main__.SimpleStruct*)]", + "ap_tracking_data": { + "group": 5, + "offset": 6 + } + }, + { + "pc": 55, + "value": "[cast(fp + 2, __main__.CompoundStruct*)]", + "ap_tracking_data": { + "group": 5, + "offset": 6 + } + }, + { + "pc": 55, + "value": "[cast(fp + 4, (a: felt, b: felt)*)]", + "ap_tracking_data": { + "group": 5, + "offset": 6 + } + }, + { + "pc": 71, + "value": "[cast(fp + (-4), felt*)]", + "ap_tracking_data": { + "group": 6, + "offset": 0 + } + }, + { + "pc": 71, + "value": "[cast(fp + (-3), felt*)]", + "ap_tracking_data": { + "group": 6, + "offset": 0 + } + }, + { + "pc": 71, + "value": "[cast(fp + (-8), felt*)]", + "ap_tracking_data": { + "group": 6, + "offset": 0 + } + }, + { + "pc": 71, + "value": "[cast(fp + (-7), __main__.CompoundStruct**)]", + "ap_tracking_data": { + "group": 6, + "offset": 0 + } + }, + { + "pc": 71, + "value": "[cast(fp + (-6), __main__.SimpleStruct*)]", + "ap_tracking_data": { + "group": 6, + "offset": 0 + } + }, + { + "pc": 76, + "value": "[cast(ap + (-1), felt*)]", + "ap_tracking_data": { + "group": 6, + "offset": 15 + } + }, + { + "pc": 76, + "value": "cast([fp + (-4)] + [fp + (-3)], felt)", + "ap_tracking_data": { + "group": 6, + "offset": 15 + } + } + ] + }, + "attributes": [], + "debug_info": null +} \ No newline at end of file diff --git a/crates/starknet_os/src/test_utils/errors.rs b/crates/starknet_os/src/test_utils/errors.rs new file mode 100644 index 00000000000..fcb76516175 --- /dev/null +++ b/crates/starknet_os/src/test_utils/errors.rs @@ -0,0 +1,76 @@ +use std::collections::HashSet; + +use cairo_vm::serde::deserialize_program::Member; +use cairo_vm::types::builtin_name::BuiltinName; +use cairo_vm::types::errors::math_errors::MathError; +use cairo_vm::types::errors::program_errors::ProgramError; +use cairo_vm::vm::errors::cairo_run_errors::CairoRunError; +use cairo_vm::vm::errors::memory_errors::MemoryError; +use cairo_vm::vm::errors::vm_errors::VirtualMachineError; + +use crate::test_utils::cairo_runner::{EndpointArg, ImplicitArg}; + +#[derive(Debug, thiserror::Error)] +pub enum Cairo0EntryPointRunnerError { + #[error(transparent)] + ExplicitArg(#[from] ExplicitArgError), + #[error(transparent)] + VirtualMachine(#[from] VirtualMachineError), + #[error(transparent)] + ImplicitArg(#[from] ImplicitArgError), + #[error(transparent)] + Program(#[from] ProgramError), + #[error(transparent)] + ProgramSerde(serde_json::Error), + #[error( + "The cairo runner's builtin list does not match the actual builtins, it should be \ + updated. Cairo Runner's builtins: {cairo_runner_builtins:?}, actual builtins: \ + {actual_builtins:?}" + )] + BuiltinMismatch { + cairo_runner_builtins: Vec, + actual_builtins: HashSet, + }, + #[error(transparent)] + RunCairoEndpoint(CairoRunError), + #[error(transparent)] + LoadReturnValue(#[from] LoadReturnValueError), +} + +#[derive(Debug, thiserror::Error)] +pub enum ExplicitArgError { + #[error( + "Mismatch for explicit arg {index}. expected arg: {expected:?}, actual arg: {actual:?}" + )] + Mismatch { index: usize, expected: Member, actual: EndpointArg }, + #[error( + "Expected {} explicit arguments, got {}. Expected args: {expected:?}, actual args: \ + {actual:?}", + .expected.len(), .actual.len() + )] + WrongNumberOfArgs { expected: Vec, actual: Vec }, +} + +#[derive(Debug, thiserror::Error)] +pub enum ImplicitArgError { + #[error( + "Mismatch for implicit arg {index}. expected arg: {expected:?}, actual arg: {actual:?}" + )] + Mismatch { index: usize, expected: Member, actual: ImplicitArg }, + #[error( + "Expected {} implicit arguments, got {}. Expected args: {expected:?}, actual args: \ + {actual:?}", + .expected.len(), .actual.len() + )] + WrongNumberOfArgs { expected: Vec<(String, Member)>, actual: Vec }, + #[error("Incorrect order of builtins. Expected: {correct_order:?}, actual: {actual_order:?}")] + WrongBuiltinOrder { correct_order: Vec, actual_order: Vec }, +} + +#[derive(Debug, thiserror::Error)] +pub enum LoadReturnValueError { + #[error(transparent)] + Math(#[from] MathError), + #[error(transparent)] + Memory(#[from] MemoryError), +} diff --git a/crates/starknet_os/src/test_utils/utils.rs b/crates/starknet_os/src/test_utils/utils.rs new file mode 100644 index 00000000000..d6d6dcd4ee3 --- /dev/null +++ b/crates/starknet_os/src/test_utils/utils.rs @@ -0,0 +1,26 @@ +use crate::test_utils::cairo_runner::{ + run_cairo_0_entry_point, + Cairo0EntryPointRunnerResult, + EndpointArg, + ImplicitArg, +}; + +pub fn run_cairo_function_and_check_result( + program_str: &str, + function_name: &str, + explicit_args: &[EndpointArg], + implicit_args: &[ImplicitArg], + expected_explicit_retdata: &[EndpointArg], + expected_implicit_retdata: &[ImplicitArg], +) -> Cairo0EntryPointRunnerResult<()> { + let (actual_implicit_retdata, actual_explicit_retdata) = run_cairo_0_entry_point( + program_str, + function_name, + explicit_args, + implicit_args, + expected_explicit_retdata, + )?; + assert_eq!(expected_explicit_retdata, &actual_explicit_retdata); + assert_eq!(expected_implicit_retdata, &actual_implicit_retdata); + Ok(()) +} diff --git a/crates/starknet_os/src/vm_utils.rs b/crates/starknet_os/src/vm_utils.rs new file mode 100644 index 00000000000..217227de454 --- /dev/null +++ b/crates/starknet_os/src/vm_utils.rs @@ -0,0 +1,215 @@ +use std::collections::HashMap; + +use cairo_vm::hint_processor::builtin_hint_processor::hint_utils::get_ptr_from_var_name; +use cairo_vm::hint_processor::hint_processor_definition::HintReference; +use cairo_vm::serde::deserialize_program::{ApTracking, Identifier}; +use cairo_vm::types::program::Program; +use cairo_vm::types::relocatable::{MaybeRelocatable, Relocatable}; +use cairo_vm::vm::errors::hint_errors::HintError; +use cairo_vm::vm::vm_core::VirtualMachine; +use starknet_types_core::felt::Felt; + +use crate::hints::error::{OsHintError, OsHintResult}; +use crate::hints::vars::{CairoStruct, Ids}; + +#[cfg(test)] +#[path = "vm_utils_test.rs"] +pub mod vm_utils_test; + +#[allow(dead_code)] +pub(crate) trait LoadCairoObject { + /// Inserts the cairo 0 representation of `self` into the VM at the given address. + fn load_into( + &self, + vm: &mut VirtualMachine, + identifier_getter: &IG, + address: Relocatable, + constants: &HashMap, + ) -> OsHintResult; +} + +#[allow(dead_code)] +pub(crate) trait CairoSized: LoadCairoObject { + /// Returns the size of the cairo object. + // TODO(Nimrod): Figure out how to compare the size to the actual size on cairo. + fn size(identifier_getter: &IG) -> usize; +} + +pub(crate) trait IdentifierGetter { + fn get_identifier(&self, identifier_name: &str) -> Result<&Identifier, OsHintError>; +} + +impl IdentifierGetter for Program { + fn get_identifier(&self, identifier_name: &str) -> Result<&Identifier, OsHintError> { + Ok(self.get_identifier(identifier_name).ok_or_else(|| { + HintError::UnknownIdentifier(identifier_name.to_string().into_boxed_str()) + })?) + } +} + +#[allow(dead_code)] +/// Fetches the address of nested fields of a cairo variable. +/// Example: Consider this hint: `ids.x.y.z`. This function fetches the address of `x`, +/// recursively fetches the offsets of `y` and `z`, and sums them up to get the address of `z`. +pub(crate) fn get_address_of_nested_fields( + ids_data: &HashMap, + id: Ids, + var_type: CairoStruct, + vm: &VirtualMachine, + ap_tracking: &ApTracking, + nested_fields: &[&str], + identifier_getter: &IG, +) -> Result { + let base_address = get_ptr_from_var_name(id.into(), vm, ids_data, ap_tracking)?; + + get_address_of_nested_fields_from_base_address( + base_address, + var_type, + vm, + nested_fields, + identifier_getter, + ) +} + +/// Fetches the address of nested fields of a cairo variable, given a base address. +pub(crate) fn get_address_of_nested_fields_from_base_address( + base_address: Relocatable, + var_type: CairoStruct, + vm: &VirtualMachine, + nested_fields: &[&str], + identifier_getter: &IG, +) -> Result { + let (actual_type, actual_base_address) = + deref_type_and_address_if_ptr(var_type.into(), base_address, vm)?; + let base_struct = identifier_getter.get_identifier(actual_type)?; + + fetch_nested_fields_address( + actual_base_address, + base_struct, + nested_fields, + identifier_getter, + vm, + ) +} + +/// Returns the actual type and the actual address of variable or a field, depending on whether or +/// not the type is a pointer. +fn deref_type_and_address_if_ptr<'a>( + cairo_type: &'a str, + base_address: Relocatable, + vm: &VirtualMachine, +) -> Result<(&'a str, Relocatable), OsHintError> { + Ok(match cairo_type.strip_suffix("*") { + Some(actual_cairo_type) => (actual_cairo_type, vm.get_relocatable(base_address)?), + None => (cairo_type, base_address), + }) +} + +/// Helper function to fetch the address of nested fields. +fn fetch_nested_fields_address( + base_address: Relocatable, + base_struct: &Identifier, + nested_fields: &[&str], + identifier_getter: &IG, + vm: &VirtualMachine, +) -> Result { + let field = match nested_fields.first() { + Some(first_field) => first_field, + None => return Ok(base_address), + }; + + let base_struct_name = base_struct + .full_name + .as_ref() + .ok_or_else(|| OsHintError::IdentifierHasNoFullName(Box::new(base_struct.clone())))?; + + let field_member = base_struct + .members + .as_ref() + .ok_or_else(|| OsHintError::IdentifierHasNoMembers(Box::new(base_struct.clone())))? + .get(&field.to_string()) + .ok_or_else(|| { + HintError::IdentifierHasNoMember(Box::from(( + base_struct_name.to_string(), + field.to_string(), + ))) + })?; + + let new_base_address = (base_address + field_member.offset)?; + + // If the field is a pointer, we remove the asterisk to know the exact type and + // recursively fetch the address of the field. + let (cairo_type, new_base_address) = + deref_type_and_address_if_ptr(&field_member.cairo_type, new_base_address, vm)?; + + if nested_fields.len() == 1 { + return Ok(new_base_address); + } + + let new_base_struct = identifier_getter.get_identifier(cairo_type)?; + + fetch_nested_fields_address( + new_base_address, + new_base_struct, + &nested_fields[1..], + identifier_getter, + vm, + ) +} + +/// Inserts a value to a nested field of a cairo variable given a base address. +pub(crate) fn insert_value_to_nested_field>( + base_address: Relocatable, + var_type: CairoStruct, + vm: &mut VirtualMachine, + nested_fields: &[&str], + identifier_getter: &IG, + val: T, +) -> OsHintResult { + let nested_field_addr = get_address_of_nested_fields_from_base_address( + base_address, + var_type, + vm, + nested_fields, + identifier_getter, + )?; + Ok(vm.insert_value(nested_field_addr, val)?) +} + +/// Inserts each value to a field of a cairo variable given a base address. +pub(crate) fn insert_values_to_fields( + base_address: Relocatable, + var_type: CairoStruct, + vm: &mut VirtualMachine, + nested_fields_and_value: &[(&str, MaybeRelocatable)], + identifier_getter: &IG, +) -> OsHintResult { + for (nested_fields, value) in nested_fields_and_value { + insert_value_to_nested_field( + base_address, + var_type, + vm, + &[nested_fields], + identifier_getter, + value, + )?; + } + Ok(()) +} + +impl + CairoSized> LoadCairoObject for Vec { + fn load_into( + &self, + vm: &mut VirtualMachine, + identifier_getter: &IG, + address: Relocatable, + constants: &HashMap, + ) -> OsHintResult { + let mut next_address = address; + for t in self.iter() { + t.load_into(vm, identifier_getter, next_address, constants)?; + next_address += T::size(identifier_getter); + } + Ok(()) + } +} diff --git a/crates/starknet_os/src/vm_utils_test.rs b/crates/starknet_os/src/vm_utils_test.rs new file mode 100644 index 00000000000..52e7c088e23 --- /dev/null +++ b/crates/starknet_os/src/vm_utils_test.rs @@ -0,0 +1,105 @@ +use std::collections::HashMap; + +use cairo_vm::serde::deserialize_program::Identifier; +use cairo_vm::types::relocatable::Relocatable; +use cairo_vm::vm::vm_core::VirtualMachine; +use rstest::rstest; +use serde_json; + +use super::{fetch_nested_fields_address, IdentifierGetter}; + +impl IdentifierGetter for HashMap { + fn get_identifier( + &self, + identifier_name: &str, + ) -> Result<&Identifier, crate::hints::error::OsHintError> { + Ok(self.get(identifier_name).unwrap()) + } +} + +#[rstest] +#[case::depth_1(0, vec!["double_double_point"])] +#[case::depth_2(4, vec!["double_double_point", "double_point2"])] +#[case::depth_2(6, vec!["double_double_point", "double_point2", "point2"])] +#[case::depth_4(3, vec!["double_double_point", "double_point1", "point2", "y"])] +fn get_address_of_nested_fields_without_ptrs( + #[case] expected_offset: usize, + #[case] nested_fields: Vec<&str>, +) { + let identifiers_json = r#" + { + "starkware.cairo.common.ec_point.EcPoint": { + "full_name": "starkware.cairo.common.ec_point.EcPoint", + "members": { + "x": { + "cairo_type": "felt", + "offset": 0 + }, + "y": { + "cairo_type": "felt", + "offset": 1 + } + }, + "size": 2, + "type": "struct" + }, + "DoublePoint": { + "full_name": "DoublePoint", + "members": { + "point1": { + "cairo_type": "starkware.cairo.common.ec_point.EcPoint", + "offset": 0 + }, + "point2": { + "cairo_type": "starkware.cairo.common.ec_point.EcPoint", + "offset": 2 + } + }, + "size": 4, + "type": "struct" + }, + "DoubleDoublePoint": { + "full_name": "DoubleDoublePoint", + "members": { + "double_point1": { + "cairo_type": "DoublePoint", + "offset": 0 + }, + "double_point2": { + "cairo_type": "DoublePoint", + "offset": 4 + } + }, + "size": 8, + "type": "struct" + }, + "DoubleDoublePointWrapper": { + "full_name": "DoubleDoublePointWrapper", + "members": { + "double_double_point": { + "cairo_type": "DoubleDoublePoint", + "offset": 0 + } + }, + "size": 8, + "type": "struct" + } + + }"#; + + let identifiers: HashMap = serde_json::from_str(identifiers_json).unwrap(); + let vm = VirtualMachine::new(false); // Dummy VM. + let dummy_base_address = Relocatable::from((11, 48)); // This is fetchable from 'wrapper'. + let base_struct = identifiers.get("DoubleDoublePointWrapper").unwrap(); + let actual_base_address = fetch_nested_fields_address( + dummy_base_address, + base_struct, + &nested_fields, + &identifiers, + &vm, + ) + .unwrap(); + assert_eq!(actual_base_address, (dummy_base_address + expected_offset).unwrap()) +} + +// TODO(Nimrod): Add test cases with pointers. diff --git a/crates/starknet_patricia/Cargo.toml b/crates/starknet_patricia/Cargo.toml index f636ebd8629..4a8badf559b 100644 --- a/crates/starknet_patricia/Cargo.toml +++ b/crates/starknet_patricia/Cargo.toml @@ -10,6 +10,7 @@ description = "Library for computing and updating Patricia trees." workspace = true [features] +deserialize = [] testing = [] [dev-dependencies] @@ -21,11 +22,11 @@ rstest.workspace = true async-recursion.workspace = true derive_more.workspace = true ethnum.workspace = true -hex.workspace = true rand.workspace = true serde = { workspace = true, features = ["derive"] } serde_json.workspace = true starknet-types-core.workspace = true +starknet_patricia_storage.workspace = true strum.workspace = true strum_macros.workspace = true thiserror.workspace = true diff --git a/crates/starknet_patricia/src/felt.rs b/crates/starknet_patricia/src/felt.rs index dd57127a2ea..5b0fc717a65 100644 --- a/crates/starknet_patricia/src/felt.rs +++ b/crates/starknet_patricia/src/felt.rs @@ -1,22 +1,5 @@ use ethnum::U256; -use serde::{Deserialize, Serialize}; -use starknet_types_core::felt::{Felt as StarknetTypesFelt, FromStrError}; - -#[derive( - Eq, - PartialEq, - Clone, - Copy, - Default, - Hash, - derive_more::Add, - derive_more::Sub, - PartialOrd, - Ord, - Serialize, - Deserialize, -)] -pub struct Felt(pub StarknetTypesFelt); +use starknet_types_core::felt::Felt; #[macro_export] macro_rules! impl_from_hex_for_felt_wrapper { @@ -43,83 +26,7 @@ macro_rules! impl_from { } }; } -impl_from!(Felt, StarknetTypesFelt, u128, u8); - -impl From for StarknetTypesFelt { - fn from(felt: Felt) -> Self { - felt.0 - } -} - -impl From<&Felt> for U256 { - fn from(felt: &Felt) -> Self { - U256::from_be_bytes(felt.to_bytes_be()) - } -} - -impl std::ops::Mul for Felt { - type Output = Self; - - fn mul(self, rhs: Self) -> Self { - Self(self.0 * rhs.0) - } -} - -impl core::fmt::Debug for Felt { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{:?}", U256::from(self)) - } -} - -impl Felt { - pub const ZERO: Felt = Felt(StarknetTypesFelt::ZERO); - #[allow(dead_code)] - pub const ONE: Felt = Felt(StarknetTypesFelt::ONE); - #[allow(dead_code)] - pub const TWO: Felt = Felt(StarknetTypesFelt::TWO); - #[allow(dead_code)] - pub const THREE: Felt = Felt(StarknetTypesFelt::THREE); - pub const MAX: Felt = Felt(StarknetTypesFelt::MAX); - - pub fn from_bytes_be_slice(bytes: &[u8]) -> Self { - Self(StarknetTypesFelt::from_bytes_be_slice(bytes)) - } - - /// Raises `self` to the power of `exponent`. - #[allow(dead_code)] - pub(crate) fn pow(&self, exponent: impl Into) -> Self { - Self(self.0.pow(exponent.into())) - } - - #[allow(dead_code)] - pub(crate) fn bits(&self) -> u8 { - self.0 - .bits() - .try_into() - // Should not fail as it takes less than 252 bits to represent a felt. - .expect("Unexpected error occurred when extracting bits of a Felt.") - } - - pub fn from_bytes_be(bytes: &[u8; 32]) -> Self { - StarknetTypesFelt::from_bytes_be(bytes).into() - } - - pub fn to_bytes_be(self) -> [u8; 32] { - self.0.to_bytes_be() - } - - /// Parse a hex-encoded number into `Felt`. - pub fn from_hex(hex_string: &str) -> Result { - Ok(StarknetTypesFelt::from_hex(hex_string)?.into()) - } - - pub fn to_hex(&self) -> String { - self.0.to_hex_string() - } - // Convert to a 64-character hexadecimal string without the "0x" prefix. - pub fn to_fixed_hex_string(&self) -> String { - // Zero-pad the remaining string - self.0.to_fixed_hex_string().strip_prefix("0x").unwrap_or("0").to_string() - } +pub fn u256_from_felt(felt: &Felt) -> U256 { + U256::from_be_bytes(felt.to_bytes_be()) } diff --git a/crates/starknet_patricia/src/hash/hash_trait.rs b/crates/starknet_patricia/src/hash/hash_trait.rs index c7ace47813e..2fdd6537a8c 100644 --- a/crates/starknet_patricia/src/hash/hash_trait.rs +++ b/crates/starknet_patricia/src/hash/hash_trait.rs @@ -1,8 +1,8 @@ -use starknet_types_core::felt::FromStrError; +use starknet_types_core::felt::{Felt, FromStrError}; -use crate::felt::Felt; use crate::impl_from_hex_for_felt_wrapper; +#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))] #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)] pub struct HashOutput(pub Felt); diff --git a/crates/starknet_patricia/src/lib.rs b/crates/starknet_patricia/src/lib.rs index a22e4808ab6..75ee6071d59 100644 --- a/crates/starknet_patricia/src/lib.rs +++ b/crates/starknet_patricia/src/lib.rs @@ -1,4 +1,3 @@ pub mod felt; pub mod hash; pub mod patricia_merkle_tree; -pub mod storage; diff --git a/crates/starknet_patricia/src/patricia_merkle_tree/external_test_utils.rs b/crates/starknet_patricia/src/patricia_merkle_tree/external_test_utils.rs index 5958d330ef8..77d52b5f04d 100644 --- a/crates/starknet_patricia/src/patricia_merkle_tree/external_test_utils.rs +++ b/crates/starknet_patricia/src/patricia_merkle_tree/external_test_utils.rs @@ -3,7 +3,11 @@ use std::collections::HashMap; use ethnum::U256; use rand::Rng; use serde_json::json; +use starknet_patricia_storage::map_storage::MapStorage; +use starknet_patricia_storage::storage_trait::{create_db_key, DbKey, DbValue}; +use starknet_types_core::felt::Felt; +use super::filled_tree::node_serde::PatriciaPrefix; use super::filled_tree::tree::{FilledTree, FilledTreeImpl}; use super::node_data::inner_node::{EdgePathLength, PathToBottom}; use super::node_data::leaf::{Leaf, LeafModifications, SkeletonLeaf}; @@ -13,24 +17,19 @@ use super::original_skeleton_tree::tree::{OriginalSkeletonTree, OriginalSkeleton use super::types::{NodeIndex, SortedLeafIndices, SubTreeHeight}; use super::updated_skeleton_tree::hash_function::TreeHashFunction; use super::updated_skeleton_tree::tree::{UpdatedSkeletonTree, UpdatedSkeletonTreeImpl}; -use crate::felt::Felt; +use crate::felt::u256_from_felt; use crate::hash::hash_trait::HashOutput; use crate::patricia_merkle_tree::errors::TypesError; -use crate::storage::map_storage::MapStorage; -use crate::storage::storage_trait::{create_db_key, StarknetPrefix, StorageKey, StorageValue}; - -impl TryFrom<&U256> for Felt { - type Error = TypesError; - fn try_from(value: &U256) -> Result { - if *value > U256::from(&Felt::MAX) { - return Err(TypesError::ConversionError { - from: *value, - to: "Felt", - reason: "value is bigger than felt::max", - }); - } - Ok(Self::from_bytes_be(&value.to_be_bytes())) + +pub fn u256_try_into_felt(value: &U256) -> Result> { + if *value > u256_from_felt(&Felt::MAX) { + return Err(TypesError::ConversionError { + from: *value, + to: "Felt", + reason: "value is bigger than felt::max", + }); } + Ok(Felt::from_bytes_be(&value.to_be_bytes())) } /// Generates a random U256 number between low and high (exclusive). @@ -126,7 +125,7 @@ pub async fn single_tree_flow_test + let mut result_map = HashMap::new(); // Serialize the hash result. - let json_hash = &json!(hash_result.0.to_hex()); + let json_hash = &json!(hash_result.0.to_hex_string()); result_map.insert("root_hash", json_hash); // Serlialize the storage modifications. let json_storage = &json!(filled_tree.serialize()); @@ -138,18 +137,16 @@ pub fn create_32_bytes_entry(simple_val: u128) -> [u8; 32] { U256::from(simple_val).to_be_bytes() } -fn create_patricia_key(val: u128) -> StorageKey { - create_db_key(StarknetPrefix::InnerNode.to_storage_prefix(), &U256::from(val).to_be_bytes()) +fn create_patricia_key(val: u128) -> DbKey { + create_db_key(PatriciaPrefix::InnerNode.into(), &U256::from(val).to_be_bytes()) } -fn create_binary_val(left: u128, right: u128) -> StorageValue { - StorageValue( - (create_32_bytes_entry(left).into_iter().chain(create_32_bytes_entry(right))).collect(), - ) +fn create_binary_val(left: u128, right: u128) -> DbValue { + DbValue((create_32_bytes_entry(left).into_iter().chain(create_32_bytes_entry(right))).collect()) } -fn create_edge_val(hash: u128, path: u128, length: u8) -> StorageValue { - StorageValue( +fn create_edge_val(hash: u128, path: u128, length: u8) -> DbValue { + DbValue( create_32_bytes_entry(hash) .into_iter() .chain(create_32_bytes_entry(path)) @@ -158,11 +155,11 @@ fn create_edge_val(hash: u128, path: u128, length: u8) -> StorageValue { ) } -pub fn create_binary_entry(left: u128, right: u128) -> (StorageKey, StorageValue) { +pub fn create_binary_entry(left: u128, right: u128) -> (DbKey, DbValue) { (create_patricia_key(left + right), create_binary_val(left, right)) } -pub fn create_edge_entry(hash: u128, path: u128, length: u8) -> (StorageKey, StorageValue) { +pub fn create_edge_entry(hash: u128, path: u128, length: u8) -> (DbKey, DbValue) { (create_patricia_key(hash + path + u128::from(length)), create_edge_val(hash, path, length)) } @@ -193,18 +190,12 @@ pub fn create_unmodified_subtree_skeleton_node( ) } -pub fn create_root_edge_entry( - old_root: u128, - subtree_height: SubTreeHeight, -) -> (StorageKey, StorageValue) { +pub fn create_root_edge_entry(old_root: u128, subtree_height: SubTreeHeight) -> (DbKey, DbValue) { // Assumes path is 0. let length = SubTreeHeight::ACTUAL_HEIGHT.0 - subtree_height.0; let new_root = old_root + u128::from(length); - let key = create_db_key( - StarknetPrefix::InnerNode.to_storage_prefix(), - &Felt::from(new_root).to_bytes_be(), - ); - let value = StorageValue( + let key = create_db_key(PatriciaPrefix::InnerNode.into(), &Felt::from(new_root).to_bytes_be()); + let value = DbValue( Felt::from(old_root) .to_bytes_be() .into_iter() diff --git a/crates/starknet_patricia/src/patricia_merkle_tree/filled_tree/node_serde.rs b/crates/starknet_patricia/src/patricia_merkle_tree/filled_tree/node_serde.rs index fc7295fd7ca..cb7ebb08503 100644 --- a/crates/starknet_patricia/src/patricia_merkle_tree/filled_tree/node_serde.rs +++ b/crates/starknet_patricia/src/patricia_merkle_tree/filled_tree/node_serde.rs @@ -1,7 +1,10 @@ use ethnum::U256; use serde::{Deserialize, Serialize}; +use starknet_patricia_storage::db_object::{DBObject, HasDynamicPrefix}; +use starknet_patricia_storage::errors::DeserializationError; +use starknet_patricia_storage::storage_trait::{DbKey, DbKeyPrefix, DbValue}; +use starknet_types_core::felt::Felt; -use crate::felt::Felt; use crate::hash::hash_trait::HashOutput; use crate::patricia_merkle_tree::filled_tree::node::FilledNode; use crate::patricia_merkle_tree::node_data::inner_node::{ @@ -12,9 +15,6 @@ use crate::patricia_merkle_tree::node_data::inner_node::{ PathToBottom, }; use crate::patricia_merkle_tree::node_data::leaf::Leaf; -use crate::storage::db_object::DBObject; -use crate::storage::errors::DeserializationError; -use crate::storage::storage_trait::{StarknetPrefix, StorageKey, StorageValue}; // Const describe the size of the serialized node. pub(crate) const SERIALIZE_HASH_BYTES: usize = 32; @@ -25,6 +25,21 @@ pub(crate) const EDGE_BYTES: usize = SERIALIZE_HASH_BYTES + EDGE_PATH_BYTES + ED #[allow(dead_code)] pub(crate) const STORAGE_LEAF_SIZE: usize = SERIALIZE_HASH_BYTES; +#[derive(Debug)] +pub enum PatriciaPrefix { + InnerNode, + Leaf(DbKeyPrefix), +} + +impl From for DbKeyPrefix { + fn from(value: PatriciaPrefix) -> Self { + match value { + PatriciaPrefix::InnerNode => Self::new(b"patricia_node"), + PatriciaPrefix::Leaf(prefix) => prefix, + } + } +} + /// Temporary struct to serialize the leaf CompiledClass. /// Required to comply to existing storage layout. #[derive(Serialize, Deserialize)] @@ -37,17 +52,27 @@ impl FilledNode { self.hash.0.to_bytes_be() } - pub fn db_key(&self) -> StorageKey { + pub fn db_key(&self) -> DbKey { self.get_db_key(&self.suffix()) } } +impl HasDynamicPrefix for FilledNode { + fn get_prefix(&self) -> DbKeyPrefix { + match &self.data { + NodeData::Binary(_) | NodeData::Edge(_) => PatriciaPrefix::InnerNode, + NodeData::Leaf(_) => PatriciaPrefix::Leaf(L::get_static_prefix()), + } + .into() + } +} + impl DBObject for FilledNode { /// This method serializes the filled node into a byte vector, where: /// - For binary nodes: Concatenates left and right hashes. /// - For edge nodes: Concatenates bottom hash, path, and path length. /// - For leaf nodes: use leaf.serialize() method. - fn serialize(&self) -> StorageValue { + fn serialize(&self) -> DbValue { match &self.data { NodeData::Binary(BinaryData { left_hash, right_hash }) => { // Serialize left and right hashes to byte arrays. @@ -56,7 +81,7 @@ impl DBObject for FilledNode { // Concatenate left and right hashes. let serialized = [left, right].concat(); - StorageValue(serialized) + DbValue(serialized) } NodeData::Edge(EdgeData { bottom_hash, path_to_bottom }) => { @@ -68,28 +93,19 @@ impl DBObject for FilledNode { // Concatenate bottom hash, path, and path length. let serialized = [bottom.to_vec(), path.to_vec(), length.to_vec()].concat(); - StorageValue(serialized) + DbValue(serialized) } NodeData::Leaf(leaf_data) => leaf_data.serialize(), } } - - fn get_prefix(&self) -> Vec { - match &self.data { - NodeData::Binary(_) | NodeData::Edge(_) => { - StarknetPrefix::InnerNode.to_storage_prefix() - } - NodeData::Leaf(leaf_data) => leaf_data.get_prefix(), - } - } } impl FilledNode { /// Deserializes filled nodes. pub(crate) fn deserialize( node_hash: HashOutput, - value: &StorageValue, + value: &DbValue, is_leaf: bool, ) -> Result { if is_leaf { @@ -130,8 +146,10 @@ impl FilledNode { .expect("Slice with incorrect length."), ) .into(), - EdgePathLength::new(value.0[EDGE_BYTES - 1])?, - )?, + EdgePathLength::new(value.0[EDGE_BYTES - 1]) + .map_err(|error| DeserializationError::ValueError(Box::new(error)))?, + ) + .map_err(|error| DeserializationError::ValueError(Box::new(error)))?, }), }) } diff --git a/crates/starknet_patricia/src/patricia_merkle_tree/filled_tree/tree.rs b/crates/starknet_patricia/src/patricia_merkle_tree/filled_tree/tree.rs index db98b66a1bd..584d426c6bf 100644 --- a/crates/starknet_patricia/src/patricia_merkle_tree/filled_tree/tree.rs +++ b/crates/starknet_patricia/src/patricia_merkle_tree/filled_tree/tree.rs @@ -4,6 +4,8 @@ use std::future::Future; use std::sync::{Arc, Mutex}; use async_recursion::async_recursion; +use starknet_patricia_storage::db_object::DBObject; +use starknet_patricia_storage::storage_trait::{DbKey, DbValue}; use crate::hash::hash_trait::HashOutput; use crate::patricia_merkle_tree::filled_tree::errors::FilledTreeError; @@ -14,8 +16,6 @@ use crate::patricia_merkle_tree::types::NodeIndex; use crate::patricia_merkle_tree::updated_skeleton_tree::hash_function::TreeHashFunction; use crate::patricia_merkle_tree::updated_skeleton_tree::node::UpdatedSkeletonNode; use crate::patricia_merkle_tree::updated_skeleton_tree::tree::UpdatedSkeletonTree; -use crate::storage::db_object::DBObject; -use crate::storage::storage_trait::{StorageKey, StorageValue}; #[cfg(test)] #[path = "tree_test.rs"] @@ -42,7 +42,7 @@ pub trait FilledTree: Sized + Send { /// Serializes the current state of the tree into a hashmap, /// where each key-value pair corresponds /// to a storage key and its serialized storage value. - fn serialize(&self) -> HashMap; + fn serialize(&self) -> HashMap; fn get_root_hash(&self) -> HashOutput; } @@ -363,7 +363,7 @@ impl FilledTree for FilledTreeImpl { }) } - fn serialize(&self) -> HashMap { + fn serialize(&self) -> HashMap { // This function iterates over each node in the tree, using the node's `db_key` as the // hashmap key and the result of the node's `serialize` method as the value. self.get_all_nodes().iter().map(|(_, node)| (node.db_key(), node.serialize())).collect() diff --git a/crates/starknet_patricia/src/patricia_merkle_tree/filled_tree/tree_test.rs b/crates/starknet_patricia/src/patricia_merkle_tree/filled_tree/tree_test.rs index bf820c651e5..ba6c9119576 100644 --- a/crates/starknet_patricia/src/patricia_merkle_tree/filled_tree/tree_test.rs +++ b/crates/starknet_patricia/src/patricia_merkle_tree/filled_tree/tree_test.rs @@ -1,6 +1,8 @@ use std::collections::HashMap; -use crate::felt::Felt; +use starknet_patricia_storage::map_storage::MapStorage; +use starknet_types_core::felt::Felt; + use crate::hash::hash_trait::HashOutput; use crate::patricia_merkle_tree::filled_tree::errors::FilledTreeError; use crate::patricia_merkle_tree::filled_tree::node::FilledNode; @@ -27,7 +29,6 @@ use crate::patricia_merkle_tree::updated_skeleton_tree::tree::{ UpdatedSkeletonTree, UpdatedSkeletonTreeImpl, }; -use crate::storage::map_storage::MapStorage; #[tokio::test(flavor = "multi_thread")] /// This test is a sanity test for computing the root hash of the patricia merkle tree with a single @@ -94,7 +95,7 @@ async fn test_small_filled_tree_create() { let (updated_skeleton_tree, modifications) = get_small_tree_updated_skeleton_and_leaf_modifications(); let expected_leaf_index_to_leaf_output: HashMap = - modifications.iter().map(|(index, leaf)| (*index, leaf.0.to_hex())).collect(); + modifications.iter().map(|(index, leaf)| (*index, leaf.0.to_hex_string())).collect(); let leaf_index_to_leaf_input: HashMap = modifications.into_iter().map(|(index, leaf)| (index, leaf.0)).collect(); diff --git a/crates/starknet_patricia/src/patricia_merkle_tree/internal_test_utils.rs b/crates/starknet_patricia/src/patricia_merkle_tree/internal_test_utils.rs index 4ed6f391a6a..ae36ea45159 100644 --- a/crates/starknet_patricia/src/patricia_merkle_tree/internal_test_utils.rs +++ b/crates/starknet_patricia/src/patricia_merkle_tree/internal_test_utils.rs @@ -1,8 +1,11 @@ use ethnum::U256; use rand::rngs::ThreadRng; use rstest::{fixture, rstest}; +use starknet_patricia_storage::db_object::{DBObject, Deserializable, HasStaticPrefix}; +use starknet_patricia_storage::errors::DeserializationError; +use starknet_patricia_storage::storage_trait::{DbKeyPrefix, DbValue}; +use starknet_types_core::felt::Felt; -use crate::felt::Felt; use crate::generate_trie_config; use crate::hash::hash_trait::HashOutput; use crate::patricia_merkle_tree::external_test_utils::get_random_u256; @@ -19,32 +22,26 @@ use crate::patricia_merkle_tree::updated_skeleton_tree::hash_function::{ }; use crate::patricia_merkle_tree::updated_skeleton_tree::node::UpdatedSkeletonNode; use crate::patricia_merkle_tree::updated_skeleton_tree::tree::UpdatedSkeletonTreeImpl; -use crate::storage::db_object::{DBObject, Deserializable}; -use crate::storage::storage_trait::StorageValue; #[derive(Debug, PartialEq, Clone, Copy, Default, Eq)] pub struct MockLeaf(pub(crate) Felt); -impl DBObject for MockLeaf { - fn serialize(&self) -> StorageValue { - StorageValue(self.0.to_bytes_be().to_vec()) +impl HasStaticPrefix for MockLeaf { + fn get_static_prefix() -> DbKeyPrefix { + DbKeyPrefix::new(&[0]) } +} - fn get_prefix(&self) -> Vec { - vec![0] +impl DBObject for MockLeaf { + fn serialize(&self) -> DbValue { + DbValue(self.0.to_bytes_be().to_vec()) } } impl Deserializable for MockLeaf { - fn deserialize( - value: &StorageValue, - ) -> Result { + fn deserialize(value: &DbValue) -> Result { Ok(Self(Felt::from_bytes_be_slice(&value.0))) } - - fn prefix() -> Vec { - vec![0] - } } impl Leaf for MockLeaf { @@ -60,7 +57,7 @@ impl Leaf for MockLeaf { if input == Felt::MAX { return Err(LeafError::LeafComputationError("Leaf computation error".to_string())); } - Ok((Self(input), input.to_hex())) + Ok((Self(input), input.to_hex_string())) } } diff --git a/crates/starknet_patricia/src/patricia_merkle_tree/node_data/inner_node.rs b/crates/starknet_patricia/src/patricia_merkle_tree/node_data/inner_node.rs index 4f2950a4f44..6aeaa341cb6 100644 --- a/crates/starknet_patricia/src/patricia_merkle_tree/node_data/inner_node.rs +++ b/crates/starknet_patricia/src/patricia_merkle_tree/node_data/inner_node.rs @@ -1,6 +1,6 @@ use ethnum::U256; +use starknet_types_core::felt::Felt; -use crate::felt::Felt; use crate::hash::hash_trait::HashOutput; use crate::patricia_merkle_tree::node_data::errors::{EdgePathError, PathToBottomError}; use crate::patricia_merkle_tree::node_data::leaf::Leaf; diff --git a/crates/starknet_patricia/src/patricia_merkle_tree/node_data/leaf.rs b/crates/starknet_patricia/src/patricia_merkle_tree/node_data/leaf.rs index e779a10d823..05e55fd7481 100644 --- a/crates/starknet_patricia/src/patricia_merkle_tree/node_data/leaf.rs +++ b/crates/starknet_patricia/src/patricia_merkle_tree/node_data/leaf.rs @@ -2,14 +2,17 @@ use std::collections::HashMap; use std::fmt::Debug; use std::future::Future; -use crate::felt::Felt; +use starknet_patricia_storage::db_object::{DBObject, Deserializable, HasStaticPrefix}; +use starknet_types_core::felt::Felt; + use crate::patricia_merkle_tree::node_data::errors::{LeafError, LeafResult}; use crate::patricia_merkle_tree::original_skeleton_tree::errors::OriginalSkeletonTreeError; use crate::patricia_merkle_tree::original_skeleton_tree::tree::OriginalSkeletonTreeResult; use crate::patricia_merkle_tree::types::NodeIndex; -use crate::storage::db_object::{DBObject, Deserializable}; -pub trait Leaf: Clone + Sync + Send + DBObject + Deserializable + Default + Debug + Eq { +pub trait Leaf: + Clone + Sync + Send + HasStaticPrefix + DBObject + Deserializable + Default + Debug + Eq +{ // TODO(Amos, 1/1/2025): When default values for associated types are stable - use them, and // add a default implementation for `create`. // [Issue](https://github.com/rust-lang/rust/issues/29661). diff --git a/crates/starknet_patricia/src/patricia_merkle_tree/original_skeleton_tree/create_tree.rs b/crates/starknet_patricia/src/patricia_merkle_tree/original_skeleton_tree/create_tree.rs index 1cbec49f823..14fbe31e157 100644 --- a/crates/starknet_patricia/src/patricia_merkle_tree/original_skeleton_tree/create_tree.rs +++ b/crates/starknet_patricia/src/patricia_merkle_tree/original_skeleton_tree/create_tree.rs @@ -2,10 +2,13 @@ use std::borrow::Borrow; use std::collections::HashMap; use std::fmt::Debug; +use starknet_patricia_storage::errors::StorageError; +use starknet_patricia_storage::storage_trait::{create_db_key, DbKey, Storage}; use tracing::warn; use crate::hash::hash_trait::HashOutput; use crate::patricia_merkle_tree::filled_tree::node::FilledNode; +use crate::patricia_merkle_tree::filled_tree::node_serde::PatriciaPrefix; use crate::patricia_merkle_tree::node_data::inner_node::{ BinaryData, EdgeData, @@ -21,8 +24,6 @@ use crate::patricia_merkle_tree::original_skeleton_tree::tree::{ }; use crate::patricia_merkle_tree::original_skeleton_tree::utils::split_leaves; use crate::patricia_merkle_tree::types::{NodeIndex, SortedLeafIndices, SubTreeHeight}; -use crate::storage::errors::StorageError; -use crate::storage::storage_trait::{create_db_key, StarknetPrefix, Storage, StorageKey}; #[cfg(test)] #[path = "create_tree_test.rs"] @@ -55,6 +56,14 @@ impl<'a> SubTree<'a> { self.sorted_leaf_indices.is_empty() } + pub(crate) fn get_root_prefix(&self) -> PatriciaPrefix { + if self.is_leaf() { + PatriciaPrefix::Leaf(L::get_static_prefix()) + } else { + PatriciaPrefix::InnerNode + } + } + /// Returns the bottom subtree which is referred from `self` by the given path. When creating /// the bottom subtree some indices that were modified under `self` are not modified under the /// bottom subtree (leaves that were previously empty). These indices are returned as well. @@ -217,15 +226,11 @@ impl<'a> OriginalSkeletonTreeImpl<'a> { storage: &impl Storage, ) -> OriginalSkeletonTreeResult>> { let mut subtrees_roots = vec![]; - let db_keys: Vec = subtrees + let db_keys: Vec = subtrees .iter() .map(|subtree| { create_db_key( - if subtree.is_leaf() { - L::prefix() - } else { - StarknetPrefix::InnerNode.to_storage_prefix() - }, + subtree.get_root_prefix::().into(), &subtree.root_hash.0.to_bytes_be(), ) }) diff --git a/crates/starknet_patricia/src/patricia_merkle_tree/original_skeleton_tree/create_tree_test.rs b/crates/starknet_patricia/src/patricia_merkle_tree/original_skeleton_tree/create_tree_test.rs index 145f2fa5ee7..3c94189ab48 100644 --- a/crates/starknet_patricia/src/patricia_merkle_tree/original_skeleton_tree/create_tree_test.rs +++ b/crates/starknet_patricia/src/patricia_merkle_tree/original_skeleton_tree/create_tree_test.rs @@ -3,9 +3,12 @@ use std::collections::HashMap; use ethnum::U256; use pretty_assertions::assert_eq; use rstest::rstest; +use starknet_patricia_storage::db_object::DBObject; +use starknet_patricia_storage::map_storage::MapStorage; +use starknet_patricia_storage::storage_trait::{DbKey, DbValue}; +use starknet_types_core::felt::Felt; use super::OriginalSkeletonTreeImpl; -use crate::felt::Felt; use crate::hash::hash_trait::HashOutput; use crate::patricia_merkle_tree::external_test_utils::{ create_binary_entry, @@ -27,9 +30,6 @@ use crate::patricia_merkle_tree::original_skeleton_tree::create_tree::SubTree; use crate::patricia_merkle_tree::original_skeleton_tree::node::OriginalSkeletonNode; use crate::patricia_merkle_tree::original_skeleton_tree::tree::OriginalSkeletonTree; use crate::patricia_merkle_tree::types::{NodeIndex, SortedLeafIndices, SubTreeHeight}; -use crate::storage::db_object::DBObject; -use crate::storage::map_storage::MapStorage; -use crate::storage::storage_trait::{StorageKey, StorageValue}; #[rstest] // This test assumes for simplicity that hash is addition (i.e hash(a,b) = a + b). @@ -411,7 +411,7 @@ fn test_get_bottom_subtree( assert_eq!(subtree, expected_subtree); } -pub(crate) fn create_mock_leaf_entry(val: u128) -> (StorageKey, StorageValue) { +pub(crate) fn create_mock_leaf_entry(val: u128) -> (DbKey, DbValue) { let leaf = MockLeaf(Felt::from(val)); (leaf.get_db_key(&leaf.0.to_bytes_be()), leaf.serialize()) } diff --git a/crates/starknet_patricia/src/patricia_merkle_tree/original_skeleton_tree/errors.rs b/crates/starknet_patricia/src/patricia_merkle_tree/original_skeleton_tree/errors.rs index f760ae16cda..16640e145f8 100644 --- a/crates/starknet_patricia/src/patricia_merkle_tree/original_skeleton_tree/errors.rs +++ b/crates/starknet_patricia/src/patricia_merkle_tree/original_skeleton_tree/errors.rs @@ -1,9 +1,9 @@ use std::fmt::Debug; +use starknet_patricia_storage::errors::{DeserializationError, StorageError}; use thiserror::Error; use crate::patricia_merkle_tree::types::NodeIndex; -use crate::storage::errors::{DeserializationError, StorageError}; #[derive(Debug, Error)] pub enum OriginalSkeletonTreeError { diff --git a/crates/starknet_patricia/src/patricia_merkle_tree/original_skeleton_tree/tree.rs b/crates/starknet_patricia/src/patricia_merkle_tree/original_skeleton_tree/tree.rs index 0a4dc210a4f..d89410021e8 100644 --- a/crates/starknet_patricia/src/patricia_merkle_tree/original_skeleton_tree/tree.rs +++ b/crates/starknet_patricia/src/patricia_merkle_tree/original_skeleton_tree/tree.rs @@ -1,12 +1,13 @@ use std::collections::HashMap; +use starknet_patricia_storage::storage_trait::Storage; + use crate::hash::hash_trait::HashOutput; use crate::patricia_merkle_tree::node_data::leaf::{Leaf, LeafModifications}; use crate::patricia_merkle_tree::original_skeleton_tree::config::OriginalSkeletonTreeConfig; use crate::patricia_merkle_tree::original_skeleton_tree::errors::OriginalSkeletonTreeError; use crate::patricia_merkle_tree::original_skeleton_tree::node::OriginalSkeletonNode; use crate::patricia_merkle_tree::types::{NodeIndex, SortedLeafIndices}; -use crate::storage::storage_trait::Storage; pub type OriginalSkeletonNodeMap = HashMap; pub type OriginalSkeletonTreeResult = Result; diff --git a/crates/starknet_patricia/src/patricia_merkle_tree/types.rs b/crates/starknet_patricia/src/patricia_merkle_tree/types.rs index 370731e0bd1..883a5a2a246 100644 --- a/crates/starknet_patricia/src/patricia_merkle_tree/types.rs +++ b/crates/starknet_patricia/src/patricia_merkle_tree/types.rs @@ -1,6 +1,7 @@ use ethnum::U256; +use starknet_types_core::felt::Felt; -use crate::felt::Felt; +use crate::felt::u256_from_felt; use crate::patricia_merkle_tree::errors::TypesError; use crate::patricia_merkle_tree::node_data::inner_node::{EdgePathLength, PathToBottom}; @@ -8,6 +9,7 @@ use crate::patricia_merkle_tree::node_data::inner_node::{EdgePathLength, PathToB #[path = "types_test.rs"] pub mod types_test; +#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))] #[derive(Clone, Copy, Debug, Eq, PartialEq, derive_more::Sub, derive_more::Display)] pub struct SubTreeHeight(pub(crate) u8); @@ -28,6 +30,12 @@ impl From for u8 { } } +impl From for Felt { + fn from(value: SubTreeHeight) -> Self { + value.0.into() + } +} + #[derive( Clone, Copy, Debug, PartialEq, Eq, Hash, derive_more::BitAnd, derive_more::Sub, PartialOrd, Ord, )] @@ -131,7 +139,7 @@ impl NodeIndex { } pub(crate) fn from_felt_value(felt: &Felt) -> Self { - Self(U256::from(felt)) + Self(u256_from_felt(felt)) } } diff --git a/crates/starknet_patricia/src/patricia_merkle_tree/types_test.rs b/crates/starknet_patricia/src/patricia_merkle_tree/types_test.rs index 08447d3b6fd..ab1b92c4cc1 100644 --- a/crates/starknet_patricia/src/patricia_merkle_tree/types_test.rs +++ b/crates/starknet_patricia/src/patricia_merkle_tree/types_test.rs @@ -2,8 +2,8 @@ use ethnum::{uint, U256}; use rand::rngs::ThreadRng; use rand::Rng; use rstest::rstest; +use starknet_types_core::felt::Felt; -use crate::felt::Felt; use crate::patricia_merkle_tree::external_test_utils::get_random_u256; use crate::patricia_merkle_tree::internal_test_utils::random; use crate::patricia_merkle_tree::node_data::inner_node::{EdgePathLength, PathToBottom}; @@ -121,5 +121,5 @@ fn test_nodeindex_to_felt_conversion() { #[rstest] fn test_felt_printing() { let felt = Felt::from(17_u8); - assert_eq!(format!("{:?}", felt), "17"); + assert_eq!(format!("{:?}", felt), "0x11"); } diff --git a/crates/starknet_patricia/src/patricia_merkle_tree/updated_skeleton_tree/create_tree_helper_test.rs b/crates/starknet_patricia/src/patricia_merkle_tree/updated_skeleton_tree/create_tree_helper_test.rs index f4988e578bd..038bf41815a 100644 --- a/crates/starknet_patricia/src/patricia_merkle_tree/updated_skeleton_tree/create_tree_helper_test.rs +++ b/crates/starknet_patricia/src/patricia_merkle_tree/updated_skeleton_tree/create_tree_helper_test.rs @@ -3,8 +3,9 @@ use std::collections::HashMap; use ethnum::{uint, U256}; use pretty_assertions::assert_eq; use rstest::{fixture, rstest}; +use starknet_patricia_storage::map_storage::MapStorage; +use starknet_types_core::felt::Felt; -use crate::felt::Felt; use crate::hash::hash_trait::HashOutput; use crate::patricia_merkle_tree::filled_tree::tree::FilledTree; use crate::patricia_merkle_tree::internal_test_utils::{ @@ -33,7 +34,6 @@ use crate::patricia_merkle_tree::updated_skeleton_tree::tree::{ UpdatedSkeletonTree, UpdatedSkeletonTreeImpl, }; -use crate::storage::map_storage::MapStorage; #[fixture] fn initial_updated_skeleton( diff --git a/crates/starknet_patricia/src/patricia_merkle_tree/updated_skeleton_tree/hash_function.rs b/crates/starknet_patricia/src/patricia_merkle_tree/updated_skeleton_tree/hash_function.rs index c35224ca102..ededd3340ee 100644 --- a/crates/starknet_patricia/src/patricia_merkle_tree/updated_skeleton_tree/hash_function.rs +++ b/crates/starknet_patricia/src/patricia_merkle_tree/updated_skeleton_tree/hash_function.rs @@ -1,4 +1,5 @@ -use crate::felt::Felt; +use starknet_types_core::felt::Felt; + use crate::hash::hash_trait::HashOutput; use crate::patricia_merkle_tree::node_data::inner_node::{ BinaryData, diff --git a/crates/starknet_patricia/src/patricia_merkle_tree/updated_skeleton_tree/tree_test.rs b/crates/starknet_patricia/src/patricia_merkle_tree/updated_skeleton_tree/tree_test.rs index 57cca5e8f29..faf6c207278 100644 --- a/crates/starknet_patricia/src/patricia_merkle_tree/updated_skeleton_tree/tree_test.rs +++ b/crates/starknet_patricia/src/patricia_merkle_tree/updated_skeleton_tree/tree_test.rs @@ -1,8 +1,9 @@ use std::collections::HashMap; use rstest::{fixture, rstest}; +use starknet_patricia_storage::map_storage::MapStorage; +use starknet_types_core::felt::Felt; -use crate::felt::Felt; use crate::hash::hash_trait::HashOutput; use crate::patricia_merkle_tree::internal_test_utils::{ get_initial_updated_skeleton, @@ -22,7 +23,6 @@ use crate::patricia_merkle_tree::updated_skeleton_tree::tree::{ UpdatedSkeletonTree, UpdatedSkeletonTreeImpl, }; -use crate::storage::map_storage::MapStorage; #[allow(clippy::as_conversions)] const TREE_HEIGHT: usize = SubTreeHeight::ACTUAL_HEIGHT.0 as usize; diff --git a/crates/starknet_patricia/src/storage/db_object.rs b/crates/starknet_patricia/src/storage/db_object.rs deleted file mode 100644 index 5c4d17b9b69..00000000000 --- a/crates/starknet_patricia/src/storage/db_object.rs +++ /dev/null @@ -1,25 +0,0 @@ -use crate::storage::errors::DeserializationError; -use crate::storage::storage_trait::{StorageKey, StorageValue}; - -pub trait DBObject { - /// Serializes the given value. - fn serialize(&self) -> StorageValue; - - // TODO(Aviv, 17/07/2024): Define a trait `T` for storage prefix and return `impl T` here. - /// Returns the storage key prefix of the DB object. - fn get_prefix(&self) -> Vec; - - /// Returns a `StorageKey` from a prefix and a suffix. - fn get_db_key(&self, suffix: &[u8]) -> StorageKey { - StorageKey([self.get_prefix(), b":".to_vec(), suffix.to_vec()].concat()) - } -} - -pub trait Deserializable: Sized { - /// Deserializes the given value. - fn deserialize(value: &StorageValue) -> Result; - - // TODO(Aviv, 17/07/2024): Define a trait `T` for storage prefix and return `impl T` here. - /// The prefix used to store in DB. - fn prefix() -> Vec; -} diff --git a/crates/starknet_patricia/src/storage/map_storage.rs b/crates/starknet_patricia/src/storage/map_storage.rs deleted file mode 100644 index 1fac3b34865..00000000000 --- a/crates/starknet_patricia/src/storage/map_storage.rs +++ /dev/null @@ -1,39 +0,0 @@ -use std::collections::HashMap; - -use serde::Serialize; - -use crate::storage::storage_trait::{Storage, StorageKey, StorageValue}; - -#[derive(Serialize, Debug, Default)] -#[cfg_attr(any(test, feature = "testing"), derive(Clone))] -pub struct MapStorage { - pub storage: HashMap, -} - -impl Storage for MapStorage { - fn get(&self, key: &StorageKey) -> Option<&StorageValue> { - self.storage.get(key) - } - - fn set(&mut self, key: StorageKey, value: StorageValue) -> Option { - self.storage.insert(key, value) - } - - fn mget(&self, keys: &[StorageKey]) -> Vec> { - keys.iter().map(|key| self.get(key)).collect::>() - } - - fn mset(&mut self, key_to_value: HashMap) { - self.storage.extend(key_to_value); - } - - fn delete(&mut self, key: &StorageKey) -> Option { - self.storage.remove(key) - } -} - -impl From> for MapStorage { - fn from(storage: HashMap) -> Self { - Self { storage } - } -} diff --git a/crates/starknet_patricia/src/storage/storage_trait.rs b/crates/starknet_patricia/src/storage/storage_trait.rs deleted file mode 100644 index 07d681cc7b9..00000000000 --- a/crates/starknet_patricia/src/storage/storage_trait.rs +++ /dev/null @@ -1,83 +0,0 @@ -use std::collections::HashMap; - -use serde::{Serialize, Serializer}; - -use crate::felt::Felt; - -#[derive(Debug, Eq, Hash, PartialEq)] -#[cfg_attr(any(test, feature = "testing"), derive(Clone))] -pub struct StorageKey(pub Vec); - -#[derive(Debug, Eq, PartialEq, Serialize)] -#[cfg_attr(any(test, feature = "testing"), derive(Clone))] -pub struct StorageValue(pub Vec); - -pub trait Storage: From> { - /// Returns value from storage, if it exists. - fn get(&self, key: &StorageKey) -> Option<&StorageValue>; - - /// Sets value in storage. If key already exists, its value is overwritten and the old value is - /// returned. - fn set(&mut self, key: StorageKey, value: StorageValue) -> Option; - - /// Returns values from storage in same order of given keys. Value is None for keys that do not - /// exist. - fn mget(&self, keys: &[StorageKey]) -> Vec>; - - /// Sets values in storage. - fn mset(&mut self, key_to_value: HashMap); - - /// Deletes value from storage and returns its value if it exists. Returns None if not. - fn delete(&mut self, key: &StorageKey) -> Option; -} - -// TODO(Aviv, 17/07/2024); Split between Storage prefix representation (trait) and node -// specific implementation (enum). -#[derive(Clone, Debug)] -pub enum StarknetPrefix { - InnerNode, - StorageLeaf, - StateTreeLeaf, - CompiledClassLeaf, -} - -/// Describes a storage prefix as used in Aerospike DB. -impl StarknetPrefix { - pub fn to_bytes(&self) -> &'static [u8] { - match self { - Self::InnerNode => b"patricia_node", - Self::StorageLeaf => b"starknet_storage_leaf", - Self::StateTreeLeaf => b"contract_state", - Self::CompiledClassLeaf => b"contract_class_leaf", - } - } - - pub fn to_storage_prefix(&self) -> Vec { - self.to_bytes().to_vec() - } -} - -impl From for StorageKey { - fn from(value: Felt) -> Self { - StorageKey(value.to_bytes_be().to_vec()) - } -} - -/// To send storage to Python storage, it is necessary to serialize it. -impl Serialize for StorageKey { - /// Serializes `StorageKey` to hexadecimal string representation. - /// Needed since serde's Serialize derive attribute only works on - /// HashMaps with String keys. - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - // Convert Vec to hexadecimal string representation and serialize it. - serializer.serialize_str(&hex::encode(&self.0)) - } -} - -/// Returns a `StorageKey` from a prefix and a suffix. -pub(crate) fn create_db_key(prefix: Vec, suffix: &[u8]) -> StorageKey { - StorageKey([prefix, b":".to_vec(), suffix.to_vec()].concat()) -} diff --git a/crates/starknet_patricia_storage/Cargo.toml b/crates/starknet_patricia_storage/Cargo.toml new file mode 100644 index 00000000000..f61d1ed9ad4 --- /dev/null +++ b/crates/starknet_patricia_storage/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "starknet_patricia_storage" +version.workspace = true +edition.workspace = true +repository.workspace = true +license-file.workspace = true +description = "Library for storage traits and serde for Patricia-Merkle tree commitment types." + +[features] +testing = [] + +[lints] +workspace = true + +[dependencies] +hex.workspace = true +serde = { workspace = true, features = ["derive"] } +serde_json.workspace = true +starknet-types-core.workspace = true +starknet_api.workspace = true +thiserror.workspace = true diff --git a/crates/starknet_patricia_storage/src/db_object.rs b/crates/starknet_patricia_storage/src/db_object.rs new file mode 100644 index 00000000000..91af298424d --- /dev/null +++ b/crates/starknet_patricia_storage/src/db_object.rs @@ -0,0 +1,33 @@ +use crate::errors::DeserializationError; +use crate::storage_trait::{create_db_key, DbKey, DbKeyPrefix, DbValue}; + +pub trait HasDynamicPrefix { + /// Returns the storage key prefix of the DB object. + fn get_prefix(&self) -> DbKeyPrefix; +} + +pub trait HasStaticPrefix { + /// Returns the storage key prefix of the DB object. + fn get_static_prefix() -> DbKeyPrefix; +} + +impl HasDynamicPrefix for T { + fn get_prefix(&self) -> DbKeyPrefix { + T::get_static_prefix() + } +} + +pub trait DBObject: HasDynamicPrefix { + /// Serializes the given value. + fn serialize(&self) -> DbValue; + + /// Returns a `DbKey` from a prefix and a suffix. + fn get_db_key(&self, suffix: &[u8]) -> DbKey { + create_db_key(self.get_prefix(), suffix) + } +} + +pub trait Deserializable: Sized { + /// Deserializes the given value. + fn deserialize(value: &DbValue) -> Result; +} diff --git a/crates/starknet_patricia/src/storage/errors.rs b/crates/starknet_patricia_storage/src/errors.rs similarity index 79% rename from crates/starknet_patricia/src/storage/errors.rs rename to crates/starknet_patricia_storage/src/errors.rs index 2a85137d49d..b927cb8a562 100644 --- a/crates/starknet_patricia/src/storage/errors.rs +++ b/crates/starknet_patricia_storage/src/errors.rs @@ -1,14 +1,14 @@ use serde_json; +use starknet_api::StarknetApiError; use starknet_types_core::felt::FromStrError; use thiserror::Error; -use crate::patricia_merkle_tree::node_data::errors::{EdgePathError, PathToBottomError}; -use crate::storage::storage_trait::StorageKey; +use crate::storage_trait::DbKey; #[derive(Debug, Error)] pub enum StorageError { #[error("The key {0:?} does not exist in storage.")] - MissingKey(StorageKey), + MissingKey(DbKey), } #[derive(thiserror::Error, Debug)] @@ -25,10 +25,6 @@ pub enum DeserializationError { NonExistingKey(String), #[error(transparent)] ParsingError(#[from] serde_json::Error), - #[error(transparent)] - EdgePathError(#[from] EdgePathError), - #[error(transparent)] - PathToBottomError(#[from] PathToBottomError), #[error("Unexpected prefix ({0:?}) variant when deserializing a leaf.")] // TODO(Aviv, 17/07/2024): Define a trait `T` for storage prefix and return `impl T` here. LeafPrefixError(Vec), @@ -38,4 +34,8 @@ pub enum DeserializationError { FeltParsingError(#[from] FromStrError), #[error("Encountered an invalid type when deserializing a leaf.")] LeafTypeError, + #[error(transparent)] + StarknetApiError(#[from] StarknetApiError), + #[error("Invalid value for deserialization: {0}.")] + ValueError(Box), } diff --git a/crates/starknet_patricia/src/storage.rs b/crates/starknet_patricia_storage/src/lib.rs similarity index 100% rename from crates/starknet_patricia/src/storage.rs rename to crates/starknet_patricia_storage/src/lib.rs diff --git a/crates/starknet_patricia_storage/src/map_storage.rs b/crates/starknet_patricia_storage/src/map_storage.rs new file mode 100644 index 00000000000..8f63cfd165b --- /dev/null +++ b/crates/starknet_patricia_storage/src/map_storage.rs @@ -0,0 +1,39 @@ +use std::collections::HashMap; + +use serde::Serialize; + +use crate::storage_trait::{DbKey, DbValue, Storage}; + +#[derive(Serialize, Debug, Default)] +#[cfg_attr(any(test, feature = "testing"), derive(Clone))] +pub struct MapStorage { + pub storage: HashMap, +} + +impl Storage for MapStorage { + fn get(&self, key: &DbKey) -> Option<&DbValue> { + self.storage.get(key) + } + + fn set(&mut self, key: DbKey, value: DbValue) -> Option { + self.storage.insert(key, value) + } + + fn mget(&self, keys: &[DbKey]) -> Vec> { + keys.iter().map(|key| self.get(key)).collect::>() + } + + fn mset(&mut self, key_to_value: HashMap) { + self.storage.extend(key_to_value); + } + + fn delete(&mut self, key: &DbKey) -> Option { + self.storage.remove(key) + } +} + +impl From> for MapStorage { + fn from(storage: HashMap) -> Self { + Self { storage } + } +} diff --git a/crates/starknet_patricia_storage/src/storage_trait.rs b/crates/starknet_patricia_storage/src/storage_trait.rs new file mode 100644 index 00000000000..2c6e4980d91 --- /dev/null +++ b/crates/starknet_patricia_storage/src/storage_trait.rs @@ -0,0 +1,69 @@ +use std::collections::HashMap; + +use serde::{Serialize, Serializer}; +use starknet_types_core::felt::Felt; + +#[derive(Debug, Eq, Hash, PartialEq)] +#[cfg_attr(any(test, feature = "testing"), derive(Clone))] +pub struct DbKey(pub Vec); + +#[derive(Debug, Eq, PartialEq, Serialize)] +#[cfg_attr(any(test, feature = "testing"), derive(Clone))] +pub struct DbValue(pub Vec); + +pub trait Storage: From> { + /// Returns value from storage, if it exists. + fn get(&self, key: &DbKey) -> Option<&DbValue>; + + /// Sets value in storage. If key already exists, its value is overwritten and the old value is + /// returned. + fn set(&mut self, key: DbKey, value: DbValue) -> Option; + + /// Returns values from storage in same order of given keys. Value is None for keys that do not + /// exist. + fn mget(&self, keys: &[DbKey]) -> Vec>; + + /// Sets values in storage. + fn mset(&mut self, key_to_value: HashMap); + + /// Deletes value from storage and returns its value if it exists. Returns None if not. + fn delete(&mut self, key: &DbKey) -> Option; +} + +#[derive(Debug)] +pub struct DbKeyPrefix(&'static [u8]); + +impl DbKeyPrefix { + pub fn new(prefix: &'static [u8]) -> Self { + Self(prefix) + } + + pub fn to_bytes(&self) -> &'static [u8] { + self.0 + } +} + +impl From for DbKey { + fn from(value: Felt) -> Self { + DbKey(value.to_bytes_be().to_vec()) + } +} + +/// To send storage to Python storage, it is necessary to serialize it. +impl Serialize for DbKey { + /// Serializes `DbKey` to hexadecimal string representation. + /// Needed since serde's Serialize derive attribute only works on + /// HashMaps with String keys. + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + // Convert Vec to hexadecimal string representation and serialize it. + serializer.serialize_str(&hex::encode(&self.0)) + } +} + +/// Returns a `DbKey` from a prefix and a suffix. +pub fn create_db_key(prefix: DbKeyPrefix, suffix: &[u8]) -> DbKey { + DbKey([prefix.to_bytes().to_vec(), b":".to_vec(), suffix.to_vec()].concat()) +} diff --git a/crates/starknet_sequencer_dashboard/Cargo.toml b/crates/starknet_sequencer_dashboard/Cargo.toml new file mode 100644 index 00000000000..a776068d70e --- /dev/null +++ b/crates/starknet_sequencer_dashboard/Cargo.toml @@ -0,0 +1,44 @@ +[package] +name = "starknet_sequencer_dashboard" +version.workspace = true +edition.workspace = true +repository.workspace = true +license.workspace = true + + +[features] +testing = [] + +[lints] +workspace = true + +[dependencies] +const_format.workspace = true +indexmap = { workspace = true, features = ["serde"] } +papyrus_sync.workspace = true +serde = { workspace = true, features = ["derive"] } +serde_json = { workspace = true, features = ["arbitrary_precision"] } +starknet_batcher.workspace = true +starknet_consensus.workspace = true +starknet_consensus_manager.workspace = true +starknet_gateway.workspace = true +starknet_http_server.workspace = true +starknet_infra_utils.workspace = true +starknet_mempool.workspace = true +starknet_mempool_p2p.workspace = true +starknet_sequencer_infra.workspace = true +starknet_sequencer_metrics.workspace = true +starknet_state_sync.workspace = true + +[dev-dependencies] +papyrus_sync = { workspace = true, features = ["testing"] } +starknet_batcher = { workspace = true, features = ["testing"] } +starknet_consensus = { workspace = true, features = ["testing"] } +starknet_consensus_manager = { workspace = true, features = ["testing"] } +starknet_gateway = { workspace = true, features = ["testing"] } +starknet_http_server = { workspace = true, features = ["testing"] } +starknet_infra_utils = { workspace = true, features = ["testing"] } +starknet_mempool = { workspace = true, features = ["testing"] } +starknet_mempool_p2p = { workspace = true, features = ["testing"] } +starknet_sequencer_infra = { workspace = true, features = ["testing"] } +starknet_state_sync = { workspace = true, features = ["testing"] } diff --git a/crates/starknet_sequencer_dashboard/src/alert_definitions.rs b/crates/starknet_sequencer_dashboard/src/alert_definitions.rs new file mode 100644 index 00000000000..6389efffc85 --- /dev/null +++ b/crates/starknet_sequencer_dashboard/src/alert_definitions.rs @@ -0,0 +1,28 @@ +use const_format::formatcp; +use starknet_gateway::metrics::TRANSACTIONS_RECEIVED; + +use crate::dashboard::{ + Alert, + AlertComparisonOp, + AlertCondition, + AlertGroup, + AlertLogicalOp, + Alerts, +}; + +pub const DEV_ALERTS_JSON_PATH: &str = "Monitoring/sequencer/dev_grafana_alerts.json"; + +const GATEWAY_ADD_TX_RATE_DROP: Alert = Alert { + name: "gateway_add_tx_rate_drop", + title: "Gateway add_tx rate drop", + alert_group: AlertGroup::Gateway, + expr: formatcp!("sum(rate({}[20m]))", TRANSACTIONS_RECEIVED.get_name()), + conditions: &[AlertCondition { + comparison_op: AlertComparisonOp::LessThan, + comparison_value: 0.01, + logical_op: AlertLogicalOp::And, + }], + pending_duration: "5m", +}; + +pub const SEQUENCER_ALERTS: Alerts = Alerts::new(&[GATEWAY_ADD_TX_RATE_DROP]); diff --git a/crates/starknet_sequencer_dashboard/src/bin/sequencer_dashboard_generator.rs b/crates/starknet_sequencer_dashboard/src/bin/sequencer_dashboard_generator.rs new file mode 100644 index 00000000000..5b0abf1ecfa --- /dev/null +++ b/crates/starknet_sequencer_dashboard/src/bin/sequencer_dashboard_generator.rs @@ -0,0 +1,9 @@ +use starknet_infra_utils::dumping::serialize_to_file; +use starknet_sequencer_dashboard::alert_definitions::{DEV_ALERTS_JSON_PATH, SEQUENCER_ALERTS}; +use starknet_sequencer_dashboard::dashboard_definitions::{DEV_JSON_PATH, SEQUENCER_DASHBOARD}; + +/// Creates the dashboard json file. +fn main() { + serialize_to_file(SEQUENCER_DASHBOARD, DEV_JSON_PATH); + serialize_to_file(SEQUENCER_ALERTS, DEV_ALERTS_JSON_PATH); +} diff --git a/crates/starknet_sequencer_dashboard/src/dashboard.rs b/crates/starknet_sequencer_dashboard/src/dashboard.rs new file mode 100644 index 00000000000..6e66b7e4741 --- /dev/null +++ b/crates/starknet_sequencer_dashboard/src/dashboard.rs @@ -0,0 +1,234 @@ +use std::collections::HashMap; + +use indexmap::IndexMap; +use serde::ser::{SerializeMap, SerializeStruct}; +use serde::{Serialize, Serializer}; +use starknet_sequencer_metrics::metrics::{MetricCounter, MetricGauge, MetricHistogram}; + +#[cfg(test)] +#[path = "dashboard_test.rs"] +mod dashboard_test; + +/// Grafana panel types. +#[derive(Clone, Debug, Serialize, PartialEq)] +pub enum PanelType { + #[serde(rename = "stat")] + Stat, + #[serde(rename = "graph")] + Graph, +} + +#[derive(Clone, Debug, PartialEq)] +pub struct Panel { + name: &'static str, + description: &'static str, + expr: &'static str, + panel_type: PanelType, +} + +impl Panel { + pub const fn new( + name: &'static str, + description: &'static str, + expr: &'static str, + panel_type: PanelType, + ) -> Self { + Self { name, description, expr, panel_type } + } + + pub const fn from_counter(metric: MetricCounter, panel_type: PanelType) -> Self { + Self::new(metric.get_name(), metric.get_description(), metric.get_name(), panel_type) + } + + pub const fn from_gauge(metric: MetricGauge, panel_type: PanelType) -> Self { + Self::new(metric.get_name(), metric.get_description(), metric.get_name(), panel_type) + } + + pub const fn from_hist(metric: MetricHistogram, panel_type: PanelType) -> Self { + Self::new(metric.get_name(), metric.get_description(), metric.get_name(), panel_type) + } +} + +// Custom Serialize implementation for Panel. +impl Serialize for Panel { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut state = serializer.serialize_struct("Panel", 5)?; // 5 fields (including extra dict) + state.serialize_field("title", &self.name)?; + state.serialize_field("description", &self.description)?; + state.serialize_field("type", &self.panel_type)?; + state.serialize_field("expr", &self.expr)?; + + // Append an empty dictionary `{}` at the end + let empty_map: HashMap = HashMap::new(); + state.serialize_field("extra_params", &empty_map)?; + + state.end() + } +} + +#[derive(Clone, Debug, PartialEq)] +pub struct Row { + name: &'static str, + panels: &'static [Panel], +} + +impl Row { + pub const fn new( + name: &'static str, + description: &'static str, + panels: &'static [Panel], + ) -> Self { + // TODO(Tsabary): remove description. + let _ = description; + Self { name, panels } + } +} + +// Custom Serialize implementation for Row. +impl Serialize for Row { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut map = serializer.serialize_map(Some(1))?; + map.serialize_entry(self.name, &self.panels)?; + map.end() + } +} + +#[derive(Clone, Debug, PartialEq)] +pub struct Dashboard { + name: &'static str, + rows: &'static [Row], +} + +impl Dashboard { + pub const fn new(name: &'static str, description: &'static str, rows: &'static [Row]) -> Self { + // TODO(Tsabary): remove description. + let _ = description; + Self { name, rows } + } +} + +// Custom Serialize implementation for Dashboard. +impl Serialize for Dashboard { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut map = serializer.serialize_map(Some(1))?; + let mut row_map = IndexMap::new(); + for row in self.rows { + row_map.insert(row.name, row.panels); + } + + map.serialize_entry(self.name, &row_map)?; + map.end() + } +} + +#[derive(Clone, Debug, PartialEq, Serialize)] +pub enum AlertComparisonOp { + #[serde(rename = "gt")] + GreaterThan, + #[serde(rename = "lt")] + LessThan, +} + +#[derive(Clone, Debug, PartialEq, Serialize)] +#[serde(rename_all = "snake_case")] +pub enum AlertLogicalOp { + And, + Or, +} + +/// Defines the condition to trigger the alert. +#[derive(Clone, Debug, PartialEq)] +pub struct AlertCondition { + // The comparison operator to use when comparing the expression to the value. + pub comparison_op: AlertComparisonOp, + // The value to compare the expression to. + pub comparison_value: f64, + // The logical operator between this condition and other conditions. + // TODO(Yael): Consider moving this field to the be one per alert to avoid ambiguity when + // trying to use a combination of `and` and `or` operators. + pub logical_op: AlertLogicalOp, +} + +impl Serialize for AlertCondition { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut state = serializer.serialize_struct("AlertCondition", 4)?; + + state.serialize_field( + "evaluator", + &serde_json::json!({ + "params": [self.comparison_value], + "type": self.comparison_op + }), + )?; + + state.serialize_field( + "operator", + &serde_json::json!({ + "type": self.logical_op + }), + )?; + + state.serialize_field( + "reducer", + &serde_json::json!({ + "params": [], + "type": "avg" + }), + )?; + + state.serialize_field("type", "query")?; + + state.end() + } +} + +#[derive(Clone, Debug, PartialEq, Serialize)] +#[serde(rename_all = "snake_case")] +pub enum AlertGroup { + Batcher, + Gateway, + Mempool, +} + +/// Describes the properties of an alert defined in grafana. +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct Alert { + // The name of the alert. + pub name: &'static str, + // The title that will be displayed. + pub title: &'static str, + // The group that the alert will be displayed under. + #[serde(rename = "ruleGroup")] + pub alert_group: AlertGroup, + // The expression to evaluate for the alert. + pub expr: &'static str, + // The conditions that must be met for the alert to be triggered. + pub conditions: &'static [AlertCondition], + // The time duration for which the alert conditions must be true before an alert is triggered. + #[serde(rename = "for")] + pub pending_duration: &'static str, +} + +/// Description of the alerts to be configured in the dashboard. +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct Alerts { + alerts: &'static [Alert], +} + +impl Alerts { + pub const fn new(alerts: &'static [Alert]) -> Self { + Self { alerts } + } +} diff --git a/crates/starknet_sequencer_dashboard/src/dashboard_definitions.rs b/crates/starknet_sequencer_dashboard/src/dashboard_definitions.rs new file mode 100644 index 00000000000..4983a7dc925 --- /dev/null +++ b/crates/starknet_sequencer_dashboard/src/dashboard_definitions.rs @@ -0,0 +1,372 @@ +use const_format::formatcp; +use starknet_batcher::metrics::{ + BATCHED_TRANSACTIONS, + CLASS_CACHE_HITS, + CLASS_CACHE_MISSES, + PROPOSAL_FAILED, + PROPOSAL_STARTED, + PROPOSAL_SUCCEEDED, +}; +use starknet_consensus::metrics::{ + CONSENSUS_BLOCK_NUMBER, + CONSENSUS_BUILD_PROPOSAL_FAILED, + CONSENSUS_BUILD_PROPOSAL_TOTAL, + CONSENSUS_CACHED_VOTES, + CONSENSUS_DECISIONS_REACHED_BY_CONSENSUS, + CONSENSUS_DECISIONS_REACHED_BY_SYNC, + CONSENSUS_MAX_CACHED_BLOCK_NUMBER, + CONSENSUS_PROPOSALS_INVALID, + CONSENSUS_PROPOSALS_RECEIVED, + CONSENSUS_PROPOSALS_VALIDATED, + CONSENSUS_PROPOSALS_VALID_INIT, + CONSENSUS_REPROPOSALS, + CONSENSUS_ROUND, +}; +use starknet_consensus_manager::metrics::{ + CONSENSUS_NUM_CONNECTED_PEERS, + CONSENSUS_PROPOSALS_NUM_RECEIVED_MESSAGES, + CONSENSUS_PROPOSALS_NUM_SENT_MESSAGES, + CONSENSUS_VOTES_NUM_RECEIVED_MESSAGES, + CONSENSUS_VOTES_NUM_SENT_MESSAGES, +}; +use starknet_gateway::metrics::{ + GATEWAY_ADD_TX_LATENCY, + GATEWAY_VALIDATE_TX_LATENCY, + LABEL_NAME_SOURCE, + LABEL_NAME_TX_TYPE as GATEWAY_LABEL_NAME_TX_TYPE, + TRANSACTIONS_FAILED, + TRANSACTIONS_RECEIVED, + TRANSACTIONS_SENT_TO_MEMPOOL, +}; +use starknet_http_server::metrics::ADDED_TRANSACTIONS_TOTAL; +use starknet_mempool::metrics::{ + LABEL_NAME_DROP_REASON, + LABEL_NAME_TX_TYPE as MEMPOOL_LABEL_NAME_TX_TYPE, + MEMPOOL_GET_TXS_SIZE, + MEMPOOL_PENDING_QUEUE_SIZE, + MEMPOOL_POOL_SIZE, + MEMPOOL_PRIORITY_QUEUE_SIZE, + MEMPOOL_TRANSACTIONS_COMMITTED, + MEMPOOL_TRANSACTIONS_DROPPED, + MEMPOOL_TRANSACTIONS_RECEIVED, + TRANSACTION_TIME_SPENT_IN_MEMPOOL, +}; +use starknet_mempool_p2p::metrics::{ + MEMPOOL_P2P_BROADCASTED_BATCH_SIZE, + MEMPOOL_P2P_NUM_CONNECTED_PEERS, + MEMPOOL_P2P_NUM_RECEIVED_MESSAGES, + MEMPOOL_P2P_NUM_SENT_MESSAGES, +}; +use starknet_state_sync::metrics::{ + STATE_SYNC_P2P_NUM_ACTIVE_INBOUND_SESSIONS, + STATE_SYNC_P2P_NUM_ACTIVE_OUTBOUND_SESSIONS, + STATE_SYNC_P2P_NUM_CONNECTED_PEERS, +}; + +use crate::dashboard::{Dashboard, Panel, PanelType, Row}; + +#[cfg(test)] +#[path = "dashboard_definitions_test.rs"] +mod dashboard_definitions_test; + +pub const DEV_JSON_PATH: &str = "Monitoring/sequencer/dev_grafana.json"; + +const PANEL_ADDED_TRANSACTIONS_TOTAL: Panel = + Panel::from_counter(ADDED_TRANSACTIONS_TOTAL, PanelType::Stat); +const PANEL_PROPOSAL_STARTED: Panel = Panel::from_counter(PROPOSAL_STARTED, PanelType::Stat); +const PANEL_PROPOSAL_SUCCEEDED: Panel = Panel::from_counter(PROPOSAL_SUCCEEDED, PanelType::Stat); +const PANEL_PROPOSAL_FAILED: Panel = Panel::from_counter(PROPOSAL_FAILED, PanelType::Stat); +const PANEL_BATCHED_TRANSACTIONS: Panel = + Panel::from_counter(BATCHED_TRANSACTIONS, PanelType::Stat); +const PANEL_CAIRO_NATIVE_CACHE_MISS_RATIO: Panel = Panel::new( + "cairo_native_cache_miss_ratio", + "The ratio of cache misses in the Cairo native cache", + formatcp!( + "100 * ({} / clamp_min(({} + {}), 1))", + CLASS_CACHE_MISSES.get_name(), + CLASS_CACHE_MISSES.get_name(), + CLASS_CACHE_HITS.get_name() + ), + PanelType::Graph, +); + +const PANEL_CONSENSUS_BLOCK_NUMBER: Panel = + Panel::from_gauge(CONSENSUS_BLOCK_NUMBER, PanelType::Stat); +const PANEL_CONSENSUS_ROUND: Panel = Panel::from_gauge(CONSENSUS_ROUND, PanelType::Stat); +const PANEL_CONSENSUS_MAX_CACHED_BLOCK_NUMBER: Panel = + Panel::from_gauge(CONSENSUS_MAX_CACHED_BLOCK_NUMBER, PanelType::Stat); +const PANEL_CONSENSUS_CACHED_VOTES: Panel = + Panel::from_gauge(CONSENSUS_CACHED_VOTES, PanelType::Stat); +const PANEL_CONSENSUS_DECISIONS_REACHED_BY_CONSENSUS: Panel = + Panel::from_counter(CONSENSUS_DECISIONS_REACHED_BY_CONSENSUS, PanelType::Stat); +const PANEL_CONSENSUS_DECISIONS_REACHED_BY_SYNC: Panel = + Panel::from_counter(CONSENSUS_DECISIONS_REACHED_BY_SYNC, PanelType::Stat); +const PANEL_CONSENSUS_PROPOSALS_RECEIVED: Panel = + Panel::from_counter(CONSENSUS_PROPOSALS_RECEIVED, PanelType::Stat); +const PANEL_CONSENSUS_PROPOSALS_VALID_INIT: Panel = + Panel::from_counter(CONSENSUS_PROPOSALS_VALID_INIT, PanelType::Stat); +const PANEL_CONSENSUS_PROPOSALS_VALIDATED: Panel = + Panel::from_counter(CONSENSUS_PROPOSALS_VALIDATED, PanelType::Stat); +const PANEL_CONSENSUS_PROPOSALS_INVALID: Panel = + Panel::from_counter(CONSENSUS_PROPOSALS_INVALID, PanelType::Stat); +const PANEL_CONSENSUS_BUILD_PROPOSAL_TOTAL: Panel = + Panel::from_counter(CONSENSUS_BUILD_PROPOSAL_TOTAL, PanelType::Stat); +const PANEL_CONSENSUS_BUILD_PROPOSAL_FAILED: Panel = + Panel::from_counter(CONSENSUS_BUILD_PROPOSAL_FAILED, PanelType::Stat); +const PANEL_CONSENSUS_REPROPOSALS: Panel = + Panel::from_counter(CONSENSUS_REPROPOSALS, PanelType::Stat); +const PANEL_MEMPOOL_P2P_NUM_CONNECTED_PEERS: Panel = + Panel::from_gauge(MEMPOOL_P2P_NUM_CONNECTED_PEERS, PanelType::Stat); +const PANEL_MEMPOOL_P2P_NUM_SENT_MESSAGES: Panel = + Panel::from_counter(MEMPOOL_P2P_NUM_SENT_MESSAGES, PanelType::Stat); +const PANEL_MEMPOOL_P2P_NUM_RECEIVED_MESSAGES: Panel = + Panel::from_counter(MEMPOOL_P2P_NUM_RECEIVED_MESSAGES, PanelType::Stat); +const PANEL_MEMPOOL_P2P_BROADCASTED_BATCH_SIZE: Panel = + Panel::from_hist(MEMPOOL_P2P_BROADCASTED_BATCH_SIZE, PanelType::Stat); +const PANEL_CONSENSUS_NUM_CONNECTED_PEERS: Panel = + Panel::from_gauge(CONSENSUS_NUM_CONNECTED_PEERS, PanelType::Stat); +const PANEL_CONSENSUS_VOTES_NUM_SENT_MESSAGES: Panel = + Panel::from_counter(CONSENSUS_VOTES_NUM_SENT_MESSAGES, PanelType::Stat); +const PANEL_CONSENSUS_VOTES_NUM_RECEIVED_MESSAGES: Panel = + Panel::from_counter(CONSENSUS_VOTES_NUM_RECEIVED_MESSAGES, PanelType::Stat); +const PANEL_CONSENSUS_PROPOSALS_NUM_SENT_MESSAGES: Panel = + Panel::from_counter(CONSENSUS_PROPOSALS_NUM_SENT_MESSAGES, PanelType::Stat); +const PANEL_CONSENSUS_PROPOSALS_NUM_RECEIVED_MESSAGES: Panel = + Panel::from_counter(CONSENSUS_PROPOSALS_NUM_RECEIVED_MESSAGES, PanelType::Stat); +const PANEL_STATE_SYNC_P2P_NUM_CONNECTED_PEERS: Panel = + Panel::from_gauge(STATE_SYNC_P2P_NUM_CONNECTED_PEERS, PanelType::Stat); +const PANEL_STATE_SYNC_P2P_NUM_ACTIVE_INBOUND_SESSIONS: Panel = + Panel::from_gauge(STATE_SYNC_P2P_NUM_ACTIVE_INBOUND_SESSIONS, PanelType::Stat); +const PANEL_STATE_SYNC_P2P_NUM_ACTIVE_OUTBOUND_SESSIONS: Panel = + Panel::from_gauge(STATE_SYNC_P2P_NUM_ACTIVE_OUTBOUND_SESSIONS, PanelType::Stat); +const PANEL_GATEWAY_TRANSACTIONS_RECEIVED_BY_TYPE: Panel = Panel::new( + TRANSACTIONS_RECEIVED.get_name(), + TRANSACTIONS_RECEIVED.get_description(), + formatcp!("sum by ({}) ({}) ", GATEWAY_LABEL_NAME_TX_TYPE, TRANSACTIONS_RECEIVED.get_name()), + PanelType::Stat, +); + +const PANEL_GATEWAY_TRANSACTIONS_RECEIVED_BY_SOURCE: Panel = Panel::new( + TRANSACTIONS_RECEIVED.get_name(), + TRANSACTIONS_RECEIVED.get_description(), + formatcp!("sum by ({}) ({}) ", LABEL_NAME_SOURCE, TRANSACTIONS_RECEIVED.get_name()), + PanelType::Stat, +); + +const PANEL_GATEWAY_TRANSACTIONS_RECEIVED_RATE: Panel = Panel::new( + "gateway_transactions_received_rate (TPS)", + "The rate of transactions received by the gateway during the last 20 minutes", + formatcp!("sum(rate({}[20m]))", TRANSACTIONS_RECEIVED.get_name()), + PanelType::Graph, +); + +const PANEL_GATEWAY_ADD_TX_LATENCY: Panel = Panel::new( + GATEWAY_ADD_TX_LATENCY.get_name(), + GATEWAY_ADD_TX_LATENCY.get_description(), + formatcp!("avg_over_time({}[2m])", GATEWAY_ADD_TX_LATENCY.get_name()), + PanelType::Graph, +); + +const PANEL_GATEWAY_VALIDATE_TX_LATENCY: Panel = Panel::new( + GATEWAY_VALIDATE_TX_LATENCY.get_name(), + GATEWAY_VALIDATE_TX_LATENCY.get_description(), + formatcp!("avg_over_time({}[2m])", GATEWAY_VALIDATE_TX_LATENCY.get_name()), + PanelType::Graph, +); + +const PANEL_GATEWAY_TRANSACTIONS_FAILED: Panel = Panel::new( + TRANSACTIONS_FAILED.get_name(), + TRANSACTIONS_FAILED.get_description(), + formatcp!("sum by ({}) ({})", GATEWAY_LABEL_NAME_TX_TYPE, TRANSACTIONS_FAILED.get_name()), + PanelType::Stat, +); + +const PANEL_GATEWAY_TRANSACTIONS_SENT_TO_MEMPOOL: Panel = Panel::new( + TRANSACTIONS_SENT_TO_MEMPOOL.get_name(), + TRANSACTIONS_SENT_TO_MEMPOOL.get_description(), + formatcp!( + "sum by ({}) ({})", + GATEWAY_LABEL_NAME_TX_TYPE, + TRANSACTIONS_SENT_TO_MEMPOOL.get_name() + ), + PanelType::Stat, +); + +const PANEL_MEMPOOL_TRANSACTIONS_RECEIVED: Panel = Panel::new( + MEMPOOL_TRANSACTIONS_RECEIVED.get_name(), + MEMPOOL_TRANSACTIONS_RECEIVED.get_description(), + formatcp!( + "sum by ({}) ({})", + MEMPOOL_LABEL_NAME_TX_TYPE, + MEMPOOL_TRANSACTIONS_RECEIVED.get_name() + ), + PanelType::Stat, +); + +const PANEL_MEMPOOL_TRANSACTIONS_RECEIVED_RATE: Panel = Panel::new( + "mempool_transactions_received_rate (TPS)", + "The rate of transactions received by the mempool during the last 20 minutes", + formatcp!("sum(rate({}[20m]))", MEMPOOL_TRANSACTIONS_RECEIVED.get_name()), + PanelType::Graph, +); + +const PANEL_MEMPOOL_TRANSACTIONS_COMMITTED: Panel = + Panel::from_counter(MEMPOOL_TRANSACTIONS_COMMITTED, PanelType::Stat); + +const PANEL_MEMPOOL_TRANSACTIONS_DROPPED: Panel = Panel::new( + MEMPOOL_TRANSACTIONS_DROPPED.get_name(), + MEMPOOL_TRANSACTIONS_DROPPED.get_description(), + formatcp!("sum by ({}) ({})", LABEL_NAME_DROP_REASON, MEMPOOL_TRANSACTIONS_DROPPED.get_name()), + PanelType::Stat, +); + +const PANEL_MEMPOOL_POOL_SIZE: Panel = Panel::new( + MEMPOOL_POOL_SIZE.get_name(), + "The average size of the pool", + formatcp!("avg_over_time({}[2m])", MEMPOOL_POOL_SIZE.get_name()), + PanelType::Graph, +); + +const PANEL_MEMPOOL_PRIORITY_QUEUE_SIZE: Panel = Panel::new( + MEMPOOL_PRIORITY_QUEUE_SIZE.get_name(), + "The average size of the priority queue", + formatcp!("avg_over_time({}[2m])", MEMPOOL_PRIORITY_QUEUE_SIZE.get_name()), + PanelType::Graph, +); + +const PANEL_MEMPOOL_PENDING_QUEUE_SIZE: Panel = Panel::new( + MEMPOOL_PENDING_QUEUE_SIZE.get_name(), + "The average size of the pending queue", + formatcp!("avg_over_time({}[2m])", MEMPOOL_PENDING_QUEUE_SIZE.get_name()), + PanelType::Graph, +); + +const PANEL_MEMPOOL_GET_TXS_SIZE: Panel = Panel::new( + MEMPOOL_GET_TXS_SIZE.get_name(), + "The average size of the get_txs", + formatcp!("avg_over_time({}[2m])", MEMPOOL_GET_TXS_SIZE.get_name()), + PanelType::Graph, +); + +const PANEL_MEMPOOL_TRANSACTION_TIME_SPENT: Panel = Panel::new( + TRANSACTION_TIME_SPENT_IN_MEMPOOL.get_name(), + TRANSACTION_TIME_SPENT_IN_MEMPOOL.get_description(), + formatcp!("avg_over_time({}[2m])", TRANSACTION_TIME_SPENT_IN_MEMPOOL.get_name()), + PanelType::Graph, +); + +const MEMPOOL_P2P_ROW: Row = Row::new( + "MempoolP2p", + "Mempool peer to peer metrics", + &[ + PANEL_MEMPOOL_P2P_NUM_CONNECTED_PEERS, + PANEL_MEMPOOL_P2P_NUM_SENT_MESSAGES, + PANEL_MEMPOOL_P2P_NUM_RECEIVED_MESSAGES, + PANEL_MEMPOOL_P2P_BROADCASTED_BATCH_SIZE, + ], +); + +const CONSENSUS_P2P_ROW: Row = Row::new( + "ConsensusP2p", + "Consensus peer to peer metrics", + &[ + PANEL_CONSENSUS_NUM_CONNECTED_PEERS, + PANEL_CONSENSUS_VOTES_NUM_SENT_MESSAGES, + PANEL_CONSENSUS_VOTES_NUM_RECEIVED_MESSAGES, + PANEL_CONSENSUS_PROPOSALS_NUM_SENT_MESSAGES, + PANEL_CONSENSUS_PROPOSALS_NUM_RECEIVED_MESSAGES, + ], +); + +const STATE_SYNC_P2P_ROW: Row = Row::new( + "StateSyncP2p", + "State sync peer to peer metrics", + &[ + PANEL_STATE_SYNC_P2P_NUM_CONNECTED_PEERS, + PANEL_STATE_SYNC_P2P_NUM_ACTIVE_INBOUND_SESSIONS, + PANEL_STATE_SYNC_P2P_NUM_ACTIVE_OUTBOUND_SESSIONS, + ], +); + +const BATCHER_ROW: Row = Row::new( + "Batcher", + "Batcher metrics including proposals and transactions", + &[ + PANEL_PROPOSAL_STARTED, + PANEL_PROPOSAL_SUCCEEDED, + PANEL_PROPOSAL_FAILED, + PANEL_BATCHED_TRANSACTIONS, + PANEL_CAIRO_NATIVE_CACHE_MISS_RATIO, + ], +); + +const CONSENSUS_ROW: Row = Row::new( + "Consensus", + "Consensus metrics including block number, round, and so on.", + &[ + PANEL_CONSENSUS_BLOCK_NUMBER, + PANEL_CONSENSUS_ROUND, + PANEL_CONSENSUS_MAX_CACHED_BLOCK_NUMBER, + PANEL_CONSENSUS_CACHED_VOTES, + PANEL_CONSENSUS_DECISIONS_REACHED_BY_CONSENSUS, + PANEL_CONSENSUS_DECISIONS_REACHED_BY_SYNC, + PANEL_CONSENSUS_PROPOSALS_RECEIVED, + PANEL_CONSENSUS_PROPOSALS_VALID_INIT, + PANEL_CONSENSUS_PROPOSALS_VALIDATED, + PANEL_CONSENSUS_PROPOSALS_INVALID, + PANEL_CONSENSUS_BUILD_PROPOSAL_TOTAL, + PANEL_CONSENSUS_BUILD_PROPOSAL_FAILED, + PANEL_CONSENSUS_REPROPOSALS, + ], +); + +const HTTP_SERVER_ROW: Row = Row::new( + "Http Server", + "Http Server metrics including added transactions", + &[PANEL_ADDED_TRANSACTIONS_TOTAL], +); + +pub const GATEWAY_ROW: Row = Row::new( + "Gateway", + "Gateway metrics", + &[ + PANEL_GATEWAY_TRANSACTIONS_RECEIVED_BY_TYPE, + PANEL_GATEWAY_TRANSACTIONS_RECEIVED_BY_SOURCE, + PANEL_GATEWAY_TRANSACTIONS_RECEIVED_RATE, + PANEL_GATEWAY_ADD_TX_LATENCY, + PANEL_GATEWAY_VALIDATE_TX_LATENCY, + PANEL_GATEWAY_TRANSACTIONS_FAILED, + PANEL_GATEWAY_TRANSACTIONS_SENT_TO_MEMPOOL, + ], +); + +pub const MEMPOOL_ROW: Row = Row::new( + "Mempool", + "Mempool metrics", + &[ + PANEL_MEMPOOL_TRANSACTIONS_RECEIVED, + PANEL_MEMPOOL_TRANSACTIONS_RECEIVED_RATE, + PANEL_MEMPOOL_TRANSACTIONS_DROPPED, + PANEL_MEMPOOL_TRANSACTIONS_COMMITTED, + PANEL_MEMPOOL_POOL_SIZE, + PANEL_MEMPOOL_PRIORITY_QUEUE_SIZE, + PANEL_MEMPOOL_PENDING_QUEUE_SIZE, + PANEL_MEMPOOL_GET_TXS_SIZE, + PANEL_MEMPOOL_TRANSACTION_TIME_SPENT, + ], +); + +pub const SEQUENCER_DASHBOARD: Dashboard = Dashboard::new( + "Sequencer Node Dashboard", + "Monitoring of the decentralized sequencer node", + &[ + BATCHER_ROW, + CONSENSUS_ROW, + HTTP_SERVER_ROW, + MEMPOOL_P2P_ROW, + CONSENSUS_P2P_ROW, + STATE_SYNC_P2P_ROW, + GATEWAY_ROW, + MEMPOOL_ROW, + ], +); diff --git a/crates/starknet_sequencer_dashboard/src/dashboard_definitions_test.rs b/crates/starknet_sequencer_dashboard/src/dashboard_definitions_test.rs new file mode 100644 index 00000000000..bf05f1ffcba --- /dev/null +++ b/crates/starknet_sequencer_dashboard/src/dashboard_definitions_test.rs @@ -0,0 +1,12 @@ +use starknet_infra_utils::dumping::serialize_to_file_test; + +use crate::alert_definitions::{DEV_ALERTS_JSON_PATH, SEQUENCER_ALERTS}; +use crate::dashboard_definitions::{DEV_JSON_PATH, SEQUENCER_DASHBOARD}; + +/// Test that the grafana dev dashboard and alert files are up to date. To update the default config +/// file, run: cargo run --bin sequencer_dashboard_generator -q +#[test] +fn default_dev_grafana_dashboard() { + serialize_to_file_test(SEQUENCER_DASHBOARD, DEV_JSON_PATH); + serialize_to_file_test(SEQUENCER_ALERTS, DEV_ALERTS_JSON_PATH); +} diff --git a/crates/starknet_sequencer_dashboard/src/dashboard_test.rs b/crates/starknet_sequencer_dashboard/src/dashboard_test.rs new file mode 100644 index 00000000000..0b2e88c9004 --- /dev/null +++ b/crates/starknet_sequencer_dashboard/src/dashboard_test.rs @@ -0,0 +1,37 @@ +use starknet_infra_utils::test_utils::assert_json_eq; + +use crate::dashboard::{Alert, AlertComparisonOp, AlertCondition, AlertGroup, AlertLogicalOp}; + +#[test] +fn serialize_alert() { + let alert = Alert { + name: "Name", + title: "Message", + alert_group: AlertGroup::Batcher, + expr: "max", + conditions: &[AlertCondition { + comparison_op: AlertComparisonOp::GreaterThan, + comparison_value: 10.0, + logical_op: AlertLogicalOp::And, + }], + pending_duration: "5m", + }; + + let serialized = serde_json::to_value(&alert).unwrap(); + let expected = serde_json::json!({ + "name": "Name", + "title": "Message", + "ruleGroup": "batcher", + "expr": "max", + "conditions": [ + { + "evaluator": { "params": [10.0], "type": "gt" }, + "operator": { "type": "and" }, + "reducer": {"params": [], "type": "avg"}, + "type": "query" + } + ], + "for": "5m" + }); + assert_json_eq(&serialized, &expected, "Json Comparison failed".to_string()); +} diff --git a/crates/starknet_sequencer_dashboard/src/lib.rs b/crates/starknet_sequencer_dashboard/src/lib.rs new file mode 100644 index 00000000000..e6029f800aa --- /dev/null +++ b/crates/starknet_sequencer_dashboard/src/lib.rs @@ -0,0 +1,5 @@ +pub mod alert_definitions; +pub mod dashboard; +pub mod dashboard_definitions; +#[cfg(test)] +mod metric_definitions_test; diff --git a/crates/starknet_sequencer_dashboard/src/metric_definitions_test.rs b/crates/starknet_sequencer_dashboard/src/metric_definitions_test.rs new file mode 100644 index 00000000000..80d880eb47b --- /dev/null +++ b/crates/starknet_sequencer_dashboard/src/metric_definitions_test.rs @@ -0,0 +1,31 @@ +use std::collections::HashSet; + +use papyrus_sync::metrics::PAPYRUS_SYNC_ALL_METRICS; +use starknet_batcher::metrics::BATCHER_ALL_METRICS; +use starknet_consensus_manager::metrics::CONSENSUS_ALL_METRICS; +use starknet_gateway::metrics::GATEWAY_ALL_METRICS; +use starknet_http_server::metrics::HTTP_SERVER_ALL_METRICS; +use starknet_mempool::metrics::MEMPOOL_ALL_METRICS; +use starknet_mempool_p2p::metrics::MEMPOOL_P2P_ALL_METRICS; +use starknet_sequencer_infra::metrics::INFRA_ALL_METRICS; +use starknet_state_sync::metrics::STATE_SYNC_ALL_METRICS; + +#[test] +fn metric_names_no_duplications() { + let all_metric_names = BATCHER_ALL_METRICS + .iter() + .chain(CONSENSUS_ALL_METRICS.iter()) + .chain(GATEWAY_ALL_METRICS.iter()) + .chain(HTTP_SERVER_ALL_METRICS.iter()) + .chain(INFRA_ALL_METRICS.iter()) + .chain(MEMPOOL_ALL_METRICS.iter()) + .chain(MEMPOOL_P2P_ALL_METRICS.iter()) + .chain(PAPYRUS_SYNC_ALL_METRICS.iter()) + .chain(STATE_SYNC_ALL_METRICS.iter()) + .collect::>(); + + let mut unique_metric_names: HashSet<&&'static str> = HashSet::new(); + for metric_name in all_metric_names { + assert!(unique_metric_names.insert(metric_name), "Duplicated metric name: {}", metric_name); + } +} diff --git a/crates/starknet_sequencer_deployments/Cargo.toml b/crates/starknet_sequencer_deployments/Cargo.toml new file mode 100644 index 00000000000..f80220da892 --- /dev/null +++ b/crates/starknet_sequencer_deployments/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "starknet_sequencer_deployments" +version.workspace = true +edition.workspace = true +repository.workspace = true +license.workspace = true + + +[lints] +workspace = true + + +[dependencies] +indexmap.workspace = true +serde.workspace = true +starknet_api.workspace = true +starknet_infra_utils.workspace = true +starknet_monitoring_endpoint.workspace = true +starknet_sequencer_node.workspace = true +strum.workspace = true +strum_macros.workspace = true + +[dev-dependencies] +serde_json.workspace = true +starknet_infra_utils = { workspace = true, features = ["testing"] } +starknet_sequencer_node = { workspace = true, features = ["testing"] } diff --git a/crates/starknet_sequencer_deployments/src/bin/deployment_generator.rs b/crates/starknet_sequencer_deployments/src/bin/deployment_generator.rs new file mode 100644 index 00000000000..81be6714d22 --- /dev/null +++ b/crates/starknet_sequencer_deployments/src/bin/deployment_generator.rs @@ -0,0 +1,17 @@ +use starknet_infra_utils::dumping::serialize_to_file; +use starknet_sequencer_deployments::deployment_definitions::DEPLOYMENTS; + +/// Creates the deployment json file. +fn main() { + for deployment_fn in DEPLOYMENTS { + let deployment_preset = deployment_fn(); + serialize_to_file( + deployment_preset.get_deployment(), + deployment_preset.get_dump_file_path(), + ); + + deployment_preset + .get_deployment() + .dump_application_config_files(deployment_preset.get_base_app_config_file_path()); + } +} diff --git a/crates/starknet_sequencer_deployments/src/deployment.rs b/crates/starknet_sequencer_deployments/src/deployment.rs new file mode 100644 index 00000000000..4ede0e54be2 --- /dev/null +++ b/crates/starknet_sequencer_deployments/src/deployment.rs @@ -0,0 +1,108 @@ +use std::net::{IpAddr, Ipv4Addr}; +#[cfg(test)] +use std::path::Path; +use std::path::PathBuf; + +use serde::Serialize; +use starknet_api::core::ChainId; +use starknet_monitoring_endpoint::config::MonitoringEndpointConfig; +use starknet_sequencer_node::config::config_utils::{ + get_deployment_from_config_path, + PresetConfig, +}; + +use crate::service::{DeploymentName, Service}; + +const DEPLOYMENT_IMAGE: &str = "ghcr.io/starkware-libs/sequencer/sequencer:dev"; + +pub struct DeploymentAndPreset { + deployment: Deployment, + // TODO(Tsabary): consider using PathBuf instead. + dump_file_path: &'static str, + base_app_config_file_path: &'static str, +} + +impl DeploymentAndPreset { + pub fn new( + deployment: Deployment, + dump_file_path: &'static str, + base_app_config_file_path: &'static str, + ) -> Self { + Self { deployment, dump_file_path, base_app_config_file_path } + } + + pub fn get_deployment(&self) -> &Deployment { + &self.deployment + } + + pub fn get_dump_file_path(&self) -> &'static str { + self.dump_file_path + } + + pub fn get_base_app_config_file_path(&self) -> &'static str { + self.base_app_config_file_path + } +} + +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct Deployment { + chain_id: ChainId, + image: &'static str, + application_config_subdir: String, + #[serde(skip_serializing)] + deployment_name: DeploymentName, + services: Vec, +} + +impl Deployment { + pub fn new(chain_id: ChainId, deployment_name: DeploymentName) -> Self { + let service_names = deployment_name.all_service_names(); + let services = + service_names.iter().map(|service_name| service_name.create_service()).collect(); + Self { + chain_id, + image: DEPLOYMENT_IMAGE, + application_config_subdir: deployment_name.get_path(), + deployment_name, + services, + } + } + + pub fn dump_application_config_files(&self, base_app_config_file_path: &str) { + let deployment_base_app_config = get_deployment_from_config_path(base_app_config_file_path); + + let component_configs = self.deployment_name.get_component_configs(None); + + // Iterate over the service component configs + for (service, component_config) in component_configs.iter() { + let service_deployment_base_app_config = deployment_base_app_config.clone(); + + let preset_config = PresetConfig { + config_path: PathBuf::from(&self.application_config_subdir) + .join(service.get_config_file_path()), + component_config: component_config.clone(), + monitoring_endpoint_config: MonitoringEndpointConfig { + ip: IpAddr::from(Ipv4Addr::UNSPECIFIED), + // TODO(Tsabary): services use 8082 for their monitoring. Fix that as a const + // and ensure throughout the deployment code. + port: 8082, + collect_metrics: true, + collect_profiling_metrics: true, + }, + }; + + service_deployment_base_app_config.dump_config_file(preset_config); + } + } + + #[cfg(test)] + pub(crate) fn assert_application_configs_exist(&self) { + for service in &self.services { + // Concatenate paths. + let subdir_path = Path::new(&self.application_config_subdir); + let full_path = subdir_path.join(service.get_config_path()); + // Assert existence. + assert!(full_path.exists(), "File does not exist: {:?}", full_path); + } + } +} diff --git a/crates/starknet_sequencer_deployments/src/deployment_definitions.rs b/crates/starknet_sequencer_deployments/src/deployment_definitions.rs new file mode 100644 index 00000000000..b5e1fb86821 --- /dev/null +++ b/crates/starknet_sequencer_deployments/src/deployment_definitions.rs @@ -0,0 +1,34 @@ +use starknet_api::core::ChainId; + +use crate::deployment::{Deployment, DeploymentAndPreset}; +use crate::service::DeploymentName; + +#[cfg(test)] +#[path = "deployment_definitions_test.rs"] +mod deployment_definitions_test; + +// TODO(Tsabary): decide on the dir structure and naming convention for the deployment presets. + +// TODO(Tsabary): temporarily moved this definition here, to include it in the deployment. +pub const SINGLE_NODE_CONFIG_PATH: &str = + "config/sequencer/presets/system_test_presets/single_node/node_0/executable_0/node_config.json"; + +type DeploymentFn = fn() -> DeploymentAndPreset; + +pub const DEPLOYMENTS: &[DeploymentFn] = &[create_main_deployment, create_testing_deployment]; + +fn create_main_deployment() -> DeploymentAndPreset { + DeploymentAndPreset::new( + Deployment::new(ChainId::IntegrationSepolia, DeploymentName::DistributedNode), + "config/sequencer/deployment_configs/testing/nightly_test_distributed_node.json", + SINGLE_NODE_CONFIG_PATH, + ) +} + +fn create_testing_deployment() -> DeploymentAndPreset { + DeploymentAndPreset::new( + Deployment::new(ChainId::IntegrationSepolia, DeploymentName::ConsolidatedNode), + "config/sequencer/deployment_configs/testing/nightly_test_all_in_one.json", + SINGLE_NODE_CONFIG_PATH, + ) +} diff --git a/crates/starknet_sequencer_deployments/src/deployment_definitions_test.rs b/crates/starknet_sequencer_deployments/src/deployment_definitions_test.rs new file mode 100644 index 00000000000..372bf45a858 --- /dev/null +++ b/crates/starknet_sequencer_deployments/src/deployment_definitions_test.rs @@ -0,0 +1,40 @@ +use std::env; + +use starknet_infra_utils::dumping::serialize_to_file_test; +use starknet_infra_utils::path::resolve_project_relative_path; + +use crate::deployment_definitions::DEPLOYMENTS; + +/// Test that the deployment file is up to date. To update it run: +/// cargo run --bin deployment_generator -q +#[test] +fn deployment_files_are_up_to_date() { + for deployment_fn in DEPLOYMENTS { + let deployment_preset = deployment_fn(); + serialize_to_file_test( + deployment_preset.get_deployment(), + deployment_preset.get_dump_file_path(), + ); + + // TODO(Tsabary): test that the dumped app-config files are up to date, i.e., their current + // content matches the dumped on. This test will replace the application_config_files_exist + // test below. + } +} + +#[test] +fn application_config_files_exist() { + env::set_current_dir(resolve_project_relative_path("").unwrap()) + .expect("Couldn't set working dir."); + for deployment_fn in DEPLOYMENTS { + let deployment_preset = deployment_fn(); + deployment_preset.get_deployment().assert_application_configs_exist(); + + // TODO(Tsabary): the following dumps the application config instead of verifying the + // already dumped values are updated. This is a temporary solution until the dump functions + // will be rearranged. + deployment_preset + .get_deployment() + .dump_application_config_files(deployment_preset.get_base_app_config_file_path()); + } +} diff --git a/crates/starknet_sequencer_deployments/src/deployments.rs b/crates/starknet_sequencer_deployments/src/deployments.rs new file mode 100644 index 00000000000..f08024196f4 --- /dev/null +++ b/crates/starknet_sequencer_deployments/src/deployments.rs @@ -0,0 +1,2 @@ +pub mod consolidated; +pub mod distributed; diff --git a/crates/starknet_sequencer_deployments/src/deployments/consolidated.rs b/crates/starknet_sequencer_deployments/src/deployments/consolidated.rs new file mode 100644 index 00000000000..9b840d3752a --- /dev/null +++ b/crates/starknet_sequencer_deployments/src/deployments/consolidated.rs @@ -0,0 +1,44 @@ +use indexmap::IndexMap; +use serde::Serialize; +use starknet_sequencer_node::config::component_config::ComponentConfig; +use strum::Display; +use strum_macros::{AsRefStr, EnumIter}; + +use crate::service::{GetComponentConfigs, Service, ServiceName, ServiceNameInner}; + +#[derive(Clone, Copy, Debug, Display, PartialEq, Eq, Hash, Serialize, AsRefStr, EnumIter)] +#[strum(serialize_all = "snake_case")] +pub enum ConsolidatedNodeServiceName { + Node, +} + +impl From for ServiceName { + fn from(service: ConsolidatedNodeServiceName) -> Self { + ServiceName::ConsolidatedNode(service) + } +} + +impl GetComponentConfigs for ConsolidatedNodeServiceName { + fn get_component_configs(_base_port: Option) -> IndexMap { + let mut component_config_map = IndexMap::new(); + component_config_map.insert( + ServiceName::ConsolidatedNode(ConsolidatedNodeServiceName::Node), + get_consolidated_config(), + ); + component_config_map + } +} + +impl ServiceNameInner for ConsolidatedNodeServiceName { + fn create_service(&self) -> Service { + match self { + ConsolidatedNodeServiceName::Node => { + Service::new(Into::::into(*self), false, false, 1, Some(32)) + } + } + } +} + +fn get_consolidated_config() -> ComponentConfig { + ComponentConfig::default() +} diff --git a/crates/starknet_sequencer_deployments/src/deployments/distributed.rs b/crates/starknet_sequencer_deployments/src/deployments/distributed.rs new file mode 100644 index 00000000000..319cbda75cd --- /dev/null +++ b/crates/starknet_sequencer_deployments/src/deployments/distributed.rs @@ -0,0 +1,315 @@ +use std::net::{IpAddr, Ipv4Addr}; + +use indexmap::IndexMap; +use serde::Serialize; +use starknet_sequencer_node::config::component_config::ComponentConfig; +use starknet_sequencer_node::config::component_execution_config::{ + ActiveComponentExecutionConfig, + ReactiveComponentExecutionConfig, +}; +use strum::{Display, IntoEnumIterator}; +use strum_macros::{AsRefStr, EnumIter}; + +use crate::service::{GetComponentConfigs, Service, ServiceName, ServiceNameInner}; + +const BASE_PORT: u16 = 55000; // TODO(Tsabary): arbitrary port, need to resolve. + +#[repr(u16)] +#[derive(Clone, Copy, Debug, Display, PartialEq, Eq, Hash, Serialize, AsRefStr, EnumIter)] +#[strum(serialize_all = "snake_case")] +pub enum DistributedNodeServiceName { + Batcher, + ClassManager, + ConsensusManager, + HttpServer, + Gateway, + L1Provider, + Mempool, + SierraCompiler, + StateSync, +} + +// Implement conversion from `DistributedNodeServiceName` to `ServiceName` +impl From for ServiceName { + fn from(service: DistributedNodeServiceName) -> Self { + ServiceName::DistributedNode(service) + } +} + +impl GetComponentConfigs for DistributedNodeServiceName { + fn get_component_configs(base_port: Option) -> IndexMap { + let mut component_config_map = IndexMap::::new(); + + let batcher = DistributedNodeServiceName::Batcher.component_config_pair(base_port); + let class_manager = + DistributedNodeServiceName::ClassManager.component_config_pair(base_port); + let gateway = DistributedNodeServiceName::Gateway.component_config_pair(base_port); + let l1_provider = DistributedNodeServiceName::L1Provider.component_config_pair(base_port); + let mempool = DistributedNodeServiceName::Mempool.component_config_pair(base_port); + let sierra_compiler = + DistributedNodeServiceName::SierraCompiler.component_config_pair(base_port); + let state_sync = DistributedNodeServiceName::StateSync.component_config_pair(base_port); + + for inner_service_name in DistributedNodeServiceName::iter() { + let component_config = match inner_service_name { + DistributedNodeServiceName::Batcher => get_batcher_config( + batcher.local(), + class_manager.remote(), + l1_provider.remote(), + mempool.remote(), + ), + DistributedNodeServiceName::ClassManager => { + get_class_manager_config(class_manager.local(), sierra_compiler.remote()) + } + DistributedNodeServiceName::ConsensusManager => get_consensus_manager_config( + batcher.remote(), + class_manager.remote(), + state_sync.remote(), + ), + DistributedNodeServiceName::HttpServer => get_http_server_config(gateway.remote()), + DistributedNodeServiceName::Gateway => get_gateway_config( + gateway.local(), + class_manager.remote(), + mempool.remote(), + state_sync.remote(), + ), + DistributedNodeServiceName::L1Provider => { + get_l1_provider_config(l1_provider.local(), state_sync.remote()) + } + DistributedNodeServiceName::Mempool => { + get_mempool_config(mempool.local(), class_manager.remote(), gateway.remote()) + } + DistributedNodeServiceName::SierraCompiler => { + get_sierra_compiler_config(sierra_compiler.local()) + } + DistributedNodeServiceName::StateSync => { + get_state_sync_config(state_sync.local(), class_manager.remote()) + } + }; + let service_name = inner_service_name.into(); + component_config_map.insert(service_name, component_config); + } + component_config_map + } +} + +// TODO(Tsabary): per each service, update all values. +impl ServiceNameInner for DistributedNodeServiceName { + fn create_service(&self) -> Service { + match self { + DistributedNodeServiceName::Batcher => { + Service::new(Into::::into(*self), false, false, 1, Some(32)) + } + DistributedNodeServiceName::ClassManager => { + Service::new(Into::::into(*self), false, false, 1, Some(32)) + } + DistributedNodeServiceName::ConsensusManager => { + Service::new(Into::::into(*self), false, false, 1, None) + } + DistributedNodeServiceName::HttpServer => { + Service::new(Into::::into(*self), false, false, 1, None) + } + DistributedNodeServiceName::Gateway => { + Service::new(Into::::into(*self), false, false, 1, None) + } + DistributedNodeServiceName::L1Provider => { + Service::new(Into::::into(*self), false, false, 1, None) + } + DistributedNodeServiceName::Mempool => { + Service::new(Into::::into(*self), false, false, 1, None) + } + DistributedNodeServiceName::SierraCompiler => { + Service::new(Into::::into(*self), false, false, 1, None) + } + DistributedNodeServiceName::StateSync => { + Service::new(Into::::into(*self), false, false, 1, Some(32)) + } + } + } +} + +impl DistributedNodeServiceName { + /// Returns a component execution config for a component that runs locally, and accepts inbound + /// connections from remote components. + pub fn component_config_for_local_service( + &self, + base_port: Option, + ) -> ReactiveComponentExecutionConfig { + ReactiveComponentExecutionConfig::local_with_remote_enabled( + self.url(), + self.ip(), + self.port(base_port), + ) + } + + /// Returns a component execution config for a component that is accessed remotely. + pub fn component_config_for_remote_service( + &self, + base_port: Option, + ) -> ReactiveComponentExecutionConfig { + ReactiveComponentExecutionConfig::remote(self.url(), self.ip(), self.port(base_port)) + } + + fn component_config_pair(&self, base_port: Option) -> DistributedNodeServiceConfigPair { + DistributedNodeServiceConfigPair { + local: self.component_config_for_local_service(base_port), + remote: self.component_config_for_remote_service(base_port), + } + } + + /// Url for the service. + fn url(&self) -> String { + let formatted_service_name = self.as_ref().replace('_', "-"); + format!("sequencer-{}-service", formatted_service_name) + } + + /// Unique port number per service. + fn port(&self, base_port: Option) -> u16 { + let port_offset = self.get_port_offset(); + let base_port = base_port.unwrap_or(BASE_PORT); + base_port + port_offset + } + + /// Listening address per service. + fn ip(&self) -> IpAddr { + IpAddr::from(Ipv4Addr::UNSPECIFIED) + } + + // Use the enum discriminant to generate a unique port per service. + // TODO(Tsabary): consider alternatives that enable removing the linter suppression. + #[allow(clippy::as_conversions)] + fn get_port_offset(&self) -> u16 { + *self as u16 + } +} + +/// Component config bundling for services of a distributed node: a config to run a component +/// locally while being accessible to other services, and a suitable config enabling such services +/// the access. +struct DistributedNodeServiceConfigPair { + local: ReactiveComponentExecutionConfig, + remote: ReactiveComponentExecutionConfig, +} + +impl DistributedNodeServiceConfigPair { + fn local(&self) -> ReactiveComponentExecutionConfig { + self.local.clone() + } + + fn remote(&self) -> ReactiveComponentExecutionConfig { + self.remote.clone() + } +} + +fn get_batcher_config( + batcher_local_config: ReactiveComponentExecutionConfig, + class_manager_remote_config: ReactiveComponentExecutionConfig, + l1_provider_remote_config: ReactiveComponentExecutionConfig, + mempool_remote_config: ReactiveComponentExecutionConfig, +) -> ComponentConfig { + let mut config = ComponentConfig::disabled(); + config.batcher = batcher_local_config; + config.class_manager = class_manager_remote_config; + config.l1_provider = l1_provider_remote_config; + config.mempool = mempool_remote_config; + config.monitoring_endpoint = ActiveComponentExecutionConfig::enabled(); + config +} + +fn get_class_manager_config( + class_manager_local_config: ReactiveComponentExecutionConfig, + sierra_compiler_remote_config: ReactiveComponentExecutionConfig, +) -> ComponentConfig { + let mut config = ComponentConfig::disabled(); + config.class_manager = class_manager_local_config; + config.sierra_compiler = sierra_compiler_remote_config; + config.monitoring_endpoint = ActiveComponentExecutionConfig::enabled(); + config +} + +fn get_gateway_config( + gateway_local_config: ReactiveComponentExecutionConfig, + class_manager_remote_config: ReactiveComponentExecutionConfig, + mempool_remote_config: ReactiveComponentExecutionConfig, + state_sync_remote_config: ReactiveComponentExecutionConfig, +) -> ComponentConfig { + let mut config = ComponentConfig::disabled(); + config.gateway = gateway_local_config; + config.class_manager = class_manager_remote_config; + config.mempool = mempool_remote_config; + config.state_sync = state_sync_remote_config; + config.monitoring_endpoint = ActiveComponentExecutionConfig::enabled(); + config +} + +fn get_mempool_config( + mempool_local_config: ReactiveComponentExecutionConfig, + class_manager_remote_config: ReactiveComponentExecutionConfig, + gateway_remote_config: ReactiveComponentExecutionConfig, +) -> ComponentConfig { + let mut config = ComponentConfig::disabled(); + config.mempool = mempool_local_config; + config.mempool_p2p = ReactiveComponentExecutionConfig::local_with_remote_disabled(); + config.class_manager = class_manager_remote_config; + config.gateway = gateway_remote_config; + config.monitoring_endpoint = ActiveComponentExecutionConfig::enabled(); + config +} + +fn get_sierra_compiler_config( + sierra_compiler_local_config: ReactiveComponentExecutionConfig, +) -> ComponentConfig { + let mut config = ComponentConfig::disabled(); + config.sierra_compiler = sierra_compiler_local_config; + config.monitoring_endpoint = ActiveComponentExecutionConfig::enabled(); + config +} + +fn get_state_sync_config( + state_sync_local_config: ReactiveComponentExecutionConfig, + class_manager_remote_config: ReactiveComponentExecutionConfig, +) -> ComponentConfig { + let mut config = ComponentConfig::disabled(); + config.state_sync = state_sync_local_config; + config.class_manager = class_manager_remote_config; + config.monitoring_endpoint = ActiveComponentExecutionConfig::enabled(); + config +} + +fn get_consensus_manager_config( + batcher_remote_config: ReactiveComponentExecutionConfig, + class_manager_remote_config: ReactiveComponentExecutionConfig, + state_sync_remote_config: ReactiveComponentExecutionConfig, +) -> ComponentConfig { + let mut config = ComponentConfig::disabled(); + config.consensus_manager = ActiveComponentExecutionConfig::enabled(); + config.batcher = batcher_remote_config; + config.class_manager = class_manager_remote_config; + config.state_sync = state_sync_remote_config; + config.monitoring_endpoint = ActiveComponentExecutionConfig::enabled(); + config +} + +fn get_http_server_config( + gateway_remote_config: ReactiveComponentExecutionConfig, +) -> ComponentConfig { + let mut config = ComponentConfig::disabled(); + config.http_server = ActiveComponentExecutionConfig::enabled(); + config.gateway = gateway_remote_config; + config.monitoring_endpoint = ActiveComponentExecutionConfig::enabled(); + config +} + +fn get_l1_provider_config( + l1_provider_local_config: ReactiveComponentExecutionConfig, + state_sync_remote_config: ReactiveComponentExecutionConfig, +) -> ComponentConfig { + let mut config = ComponentConfig::disabled(); + config.l1_provider = l1_provider_local_config; + config.l1_scraper = ActiveComponentExecutionConfig::enabled(); + config.state_sync = state_sync_remote_config; + config.monitoring_endpoint = ActiveComponentExecutionConfig::enabled(); + config +} + +// TODO(Tsabary): rename get_X_config fns to get_X_component_config. diff --git a/crates/starknet_sequencer_deployments/src/lib.rs b/crates/starknet_sequencer_deployments/src/lib.rs new file mode 100644 index 00000000000..6e143886825 --- /dev/null +++ b/crates/starknet_sequencer_deployments/src/lib.rs @@ -0,0 +1,4 @@ +pub mod deployment; +pub mod deployment_definitions; +pub mod deployments; +pub mod service; diff --git a/crates/starknet_sequencer_deployments/src/service.rs b/crates/starknet_sequencer_deployments/src/service.rs new file mode 100644 index 00000000000..9d0c8e450f2 --- /dev/null +++ b/crates/starknet_sequencer_deployments/src/service.rs @@ -0,0 +1,124 @@ +use std::fmt::Display; + +use indexmap::IndexMap; +use serde::{Serialize, Serializer}; +use starknet_sequencer_node::config::component_config::ComponentConfig; +use strum::{Display, EnumVariantNames, IntoEnumIterator}; +use strum_macros::{EnumDiscriminants, EnumIter, IntoStaticStr}; + +use crate::deployments::consolidated::ConsolidatedNodeServiceName; +use crate::deployments::distributed::DistributedNodeServiceName; + +const DEPLOYMENT_CONFIG_BASE_DIR_PATH: &str = "config/sequencer/presets"; +// TODO(Tsabary): need to distinguish between test and production configs in dir structure. +const APPLICATION_CONFIG_DIR_NAME: &str = "application_configs"; + +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct Service { + name: ServiceName, + // TODO(Tsabary): change config path to PathBuf type. + config_path: String, + ingress: bool, + autoscale: bool, + replicas: usize, + storage: Option, +} + +impl Service { + pub fn new( + name: ServiceName, + ingress: bool, + autoscale: bool, + replicas: usize, + storage: Option, + ) -> Self { + let config_path = name.get_config_file_path(); + Self { name, config_path, ingress, autoscale, replicas, storage } + } + + pub fn get_config_path(&self) -> String { + self.config_path.clone() + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, EnumDiscriminants)] +#[strum_discriminants( + name(DeploymentName), + derive(IntoStaticStr, EnumIter, EnumVariantNames, Serialize, Display), + strum(serialize_all = "snake_case") +)] +pub enum ServiceName { + ConsolidatedNode(ConsolidatedNodeServiceName), + DistributedNode(DistributedNodeServiceName), +} + +impl ServiceName { + pub fn get_config_file_path(&self) -> String { + let mut name = self.as_inner().to_string(); + name.push_str(".json"); + name + } + + pub fn create_service(&self) -> Service { + self.as_inner().create_service() + } + + fn as_inner(&self) -> &dyn ServiceNameInner { + match self { + ServiceName::ConsolidatedNode(inner) => inner, + ServiceName::DistributedNode(inner) => inner, + } + } +} + +pub(crate) trait ServiceNameInner: Display { + fn create_service(&self) -> Service; +} + +impl DeploymentName { + pub fn all_service_names(&self) -> Vec { + match self { + // TODO(Tsabary): find a way to avoid this code duplication. + Self::ConsolidatedNode => { + ConsolidatedNodeServiceName::iter().map(ServiceName::ConsolidatedNode).collect() + } + Self::DistributedNode => { + DistributedNodeServiceName::iter().map(ServiceName::DistributedNode).collect() + } + } + } + + pub fn get_path(&self) -> String { + format!("{}/{}/{}/", DEPLOYMENT_CONFIG_BASE_DIR_PATH, self, APPLICATION_CONFIG_DIR_NAME) + } + + pub fn get_component_configs( + &self, + base_port: Option, + ) -> IndexMap { + match self { + // TODO(Tsabary): avoid this code duplication. + Self::ConsolidatedNode => ConsolidatedNodeServiceName::get_component_configs(base_port), + Self::DistributedNode => DistributedNodeServiceName::get_component_configs(base_port), + } + } +} + +pub trait GetComponentConfigs { + // TODO(Tsabary): replace IndexMap with regular HashMap. Currently using IndexMap as the + // integration test relies on indices rather than service names. + fn get_component_configs(base_port: Option) -> IndexMap; +} + +impl Serialize for ServiceName { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + // Serialize only the inner value. + match self { + ServiceName::ConsolidatedNode(inner) => inner.serialize(serializer), + ServiceName::DistributedNode(inner) => inner.serialize(serializer), + } + } +} diff --git a/crates/starknet_sequencer_infra/Cargo.toml b/crates/starknet_sequencer_infra/Cargo.toml index fed187ac67c..c6509b760b0 100644 --- a/crates/starknet_sequencer_infra/Cargo.toml +++ b/crates/starknet_sequencer_infra/Cargo.toml @@ -7,25 +7,34 @@ license.workspace = true [features] -testing = [] +testing = ["starknet_sequencer_metrics/testing"] [lints] workspace = true [dependencies] async-trait.workspace = true -bincode.workspace = true hyper = { workspace = true, features = ["client", "http2", "server", "tcp"] } papyrus_config.workspace = true rstest.workspace = true serde = { workspace = true, features = ["derive"] } +serde_json.workspace = true +starknet_api.workspace = true +starknet_infra_utils.workspace = true +starknet_sequencer_metrics.workspace = true thiserror.workspace = true tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } +tower = { workspace = true, features = ["limit"] } tracing.workspace = true tracing-subscriber = { workspace = true, features = ["env-filter"] } validator.workspace = true [dev-dependencies] assert_matches.workspace = true +metrics.workspace = true +metrics-exporter-prometheus.workspace = true +once_cell.workspace = true pretty_assertions.workspace = true starknet-types-core.workspace = true +starknet_infra_utils = { workspace = true, features = ["testing"] } +starknet_sequencer_metrics = { workspace = true, features = ["testing"] } diff --git a/crates/starknet_sequencer_infra/src/component_client/definitions.rs b/crates/starknet_sequencer_infra/src/component_client/definitions.rs index f04cf8d6d25..e4b0947850d 100644 --- a/crates/starknet_sequencer_infra/src/component_client/definitions.rs +++ b/crates/starknet_sequencer_infra/src/component_client/definitions.rs @@ -1,5 +1,3 @@ -use std::sync::Arc; - use hyper::StatusCode; use serde::de::DeserializeOwned; use serde::Serialize; @@ -11,11 +9,11 @@ use crate::component_definitions::ServerError; #[derive(Clone, Debug, Error)] pub enum ClientError { #[error("Communication error: {0}")] - CommunicationFailure(Arc), + CommunicationFailure(String), #[error("Could not deserialize server response: {0}")] - ResponseDeserializationFailure(Arc), + ResponseDeserializationFailure(String), #[error("Could not parse the response: {0}")] - ResponseParsingFailure(Arc), + ResponseParsingFailure(String), #[error("Got status code: {0}, with server error: {1}")] ResponseError(StatusCode, ServerError), #[error("Got an unexpected response type: {0}")] @@ -26,8 +24,8 @@ pub type ClientResult = Result; pub struct Client where - Request: Send + Sync + Serialize, - Response: Send + Sync + DeserializeOwned, + Request: Send + Serialize, + Response: Send + DeserializeOwned, { local_client: Option>, remote_client: Option>, @@ -35,8 +33,8 @@ where impl Client where - Request: Send + Sync + Serialize, - Response: Send + Sync + DeserializeOwned, + Request: Send + Serialize, + Response: Send + DeserializeOwned, { pub fn new( local_client: Option>, diff --git a/crates/starknet_sequencer_infra/src/component_client/local_component_client.rs b/crates/starknet_sequencer_infra/src/component_client/local_component_client.rs index 4724f85b05c..0e5580fa09d 100644 --- a/crates/starknet_sequencer_infra/src/component_client/local_component_client.rs +++ b/crates/starknet_sequencer_infra/src/component_client/local_component_client.rs @@ -1,10 +1,9 @@ -use std::any::type_name; - use async_trait::async_trait; use serde::de::DeserializeOwned; use serde::Serialize; +use starknet_infra_utils::type_name::short_type_name; use tokio::sync::mpsc::{channel, Sender}; -use tracing::info; +use tracing::warn; use crate::component_client::ClientResult; use crate::component_definitions::{ComponentClient, ComponentRequestAndResponseSender}; @@ -66,16 +65,16 @@ use crate::component_definitions::{ComponentClient, ComponentRequestAndResponseS /// utilizing Tokio's async runtime and channels. pub struct LocalComponentClient where - Request: Send + Sync, - Response: Send + Sync, + Request: Send, + Response: Send, { tx: Sender>, } impl LocalComponentClient where - Request: Send + Sync, - Response: Send + Sync, + Request: Send, + Response: Send, { pub fn new(tx: Sender>) -> Self { Self { tx } @@ -86,8 +85,8 @@ where impl ComponentClient for LocalComponentClient where - Request: Send + Sync + Serialize + DeserializeOwned, - Response: Send + Sync + Serialize + DeserializeOwned, + Request: Send + Serialize + DeserializeOwned, + Response: Send + Serialize + DeserializeOwned, { async fn send(&self, request: Request) -> ClientResult { let (res_tx, mut res_rx) = channel::(1); @@ -99,11 +98,11 @@ where impl Drop for LocalComponentClient where - Request: Send + Sync, - Response: Send + Sync, + Request: Send, + Response: Send, { fn drop(&mut self) { - info!("Dropping LocalComponentClient {}.", type_name::()); + warn!("Dropping {}.", short_type_name::()); } } @@ -111,8 +110,8 @@ where // since it'll require transactions to be cloneable. impl Clone for LocalComponentClient where - Request: Send + Sync, - Response: Send + Sync, + Request: Send, + Response: Send, { fn clone(&self) -> Self { Self { tx: self.tx.clone() } diff --git a/crates/starknet_sequencer_infra/src/component_client/remote_component_client.rs b/crates/starknet_sequencer_infra/src/component_client/remote_component_client.rs index bb1cbc4c22f..d789308ffbb 100644 --- a/crates/starknet_sequencer_infra/src/component_client/remote_component_client.rs +++ b/crates/starknet_sequencer_infra/src/component_client/remote_component_client.rs @@ -1,7 +1,5 @@ use std::fmt::Debug; use std::marker::PhantomData; -use std::net::IpAddr; -use std::sync::Arc; use std::time::Duration; use async_trait::async_trait; @@ -10,10 +8,17 @@ use hyper::header::CONTENT_TYPE; use hyper::{Body, Client, Request as HyperRequest, Response as HyperResponse, StatusCode, Uri}; use serde::de::DeserializeOwned; use serde::Serialize; +use tokio::sync::Mutex; +use tracing::{debug, error}; use super::definitions::{ClientError, ClientResult}; -use crate::component_definitions::{ComponentClient, RemoteClientConfig, APPLICATION_OCTET_STREAM}; -use crate::serde_utils::BincodeSerdeWrapper; +use crate::component_definitions::{ + ComponentClient, + RemoteClientConfig, + ServerError, + APPLICATION_OCTET_STREAM, +}; +use crate::serde_utils::SerdeWrapper; /// The `RemoteComponentClient` struct is a generic client for sending component requests and /// receiving responses asynchronously through HTTP connection. @@ -55,16 +60,15 @@ use crate::serde_utils::BincodeSerdeWrapper; /// async fn main() { /// // Create a channel for sending requests and receiving responses /// // Instantiate the client. -/// let ip_address = std::net::IpAddr::V6(std::net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); +/// let url = "127.0.0.1".to_string(); /// let port: u16 = 8080; -/// let socket = std::net::SocketAddr::new(ip_address, port); /// let config = RemoteClientConfig { -/// socket, /// retries: 3, /// idle_connections: usize::MAX, /// idle_timeout: 90, +/// retry_interval: 3, /// }; -/// let client = RemoteComponentClient::::new(config); +/// let client = RemoteComponentClient::::new(config, &url, port); /// /// // Instantiate a request. /// let request = MyRequest { content: "Hello, world!".to_string() }; @@ -86,8 +90,14 @@ where uri: Uri, client: Client, config: RemoteClientConfig, - _req: PhantomData, - _res: PhantomData, + // [`RemoteComponentClient`] should be [`Send + Sync`] while [`Request`] and + // [`Response`] are only [`Send`]. [`Phantom`] is [`Send + Sync`] only if [`T`] is, despite + // this bound making no sense as the phantom data field is unused. As such, we wrap it as + // [`PhantomData>`], not enforcing the redundant [`Sync`] bound. Alternatively, + // we could also use [`unsafe impl Sync for RemoteComponentClient {}`], but + // we prefer the former for the sake of avoiding unsafe code. + _req: PhantomData>, + _res: PhantomData>, } impl RemoteComponentClient @@ -95,22 +105,19 @@ where Request: Serialize + DeserializeOwned + Debug, Response: Serialize + DeserializeOwned + Debug, { - pub fn new(config: RemoteClientConfig) -> Self { - let ip_address = config.socket.ip(); - let port = config.socket.port(); - let uri = match ip_address { - IpAddr::V4(ip_address) => format!("http://{}:{}/", ip_address, port).parse().unwrap(), - IpAddr::V6(ip_address) => format!("http://[{}]:{}/", ip_address, port).parse().unwrap(), - }; + pub fn new(config: RemoteClientConfig, url: &str, port: u16) -> Self { + let uri = format!("http://{}:{}/", url, port).parse().unwrap(); let client = Client::builder() .http2_only(true) .pool_max_idle_per_host(config.idle_connections) .pool_idle_timeout(Duration::from_secs(config.idle_timeout)) .build_http(); + debug!("RemoteComponentClient created with URI: {:?}", uri); Self { uri, client, config, _req: PhantomData, _res: PhantomData } } fn construct_http_request(&self, serialized_request: Vec) -> HyperRequest { + debug!("Sending request: {:?}", serialized_request); HyperRequest::post(self.uri.clone()) .header(CONTENT_TYPE, APPLICATION_OCTET_STREAM) .body(Body::from(serialized_request)) @@ -118,18 +125,30 @@ where } async fn try_send(&self, http_request: HyperRequest) -> ClientResult { - let http_response = self - .client - .request(http_request) - .await - .map_err(|e| ClientError::CommunicationFailure(Arc::new(e)))?; + debug!("Sending HTTP request: {:?}", http_request); + let http_response = self.client.request(http_request).await.map_err(|err| { + error!("HTTP request failed with error: {:?}", err); + ClientError::CommunicationFailure(err.to_string()) + })?; match http_response.status() { - StatusCode::OK => get_response_body(http_response).await, - status_code => Err(ClientError::ResponseError( - status_code, - get_response_body(http_response).await?, - )), + StatusCode::OK => { + let response_body = get_response_body(http_response).await; + debug!("Successfully deserialized response: {:?}", response_body); + response_body + } + status_code => { + error!( + "Unexpected response status: {:?}. Unable to deserialize response.", + status_code + ); + Err(ClientError::ResponseError( + status_code, + ServerError::RequestDeserializationFailure( + "Could not deserialize server response".to_string(), + ), + )) + } } } } @@ -138,27 +157,33 @@ where impl ComponentClient for RemoteComponentClient where - Request: Send + Sync + Serialize + DeserializeOwned + Debug, - Response: Send + Sync + Serialize + DeserializeOwned + Debug, + Request: Send + Serialize + DeserializeOwned + Debug, + Response: Send + Serialize + DeserializeOwned + Debug, { async fn send(&self, component_request: Request) -> ClientResult { // Serialize the request. - let serialized_request = BincodeSerdeWrapper::new(component_request) - .to_bincode() + let serialized_request = SerdeWrapper::new(component_request) + .wrapper_serialize() .expect("Request serialization should succeed"); // Construct the request, and send it up to 'max_retries + 1' times. Return if received a // successful response, or the last response if all attempts failed. let max_attempts = self.config.retries + 1; + debug!("Starting retry loop: max_attempts = {:?}", max_attempts); for attempt in 0..max_attempts { + debug!("Attempt {} of {:?}", attempt + 1, max_attempts); let http_request = self.construct_http_request(serialized_request.clone()); let res = self.try_send(http_request).await; if res.is_ok() { + debug!("Request successful on attempt {}: {:?}", attempt + 1, res); return res; } + error!("Request failed on attempt {}: {:?}", attempt + 1, res); if attempt == max_attempts - 1 { return res; } + error!("sleeping for {:?}", self.config.retry_interval); + tokio::time::sleep(Duration::from_secs(self.config.retry_interval)).await; } unreachable!("Guaranteed to return a response before reaching this point."); } @@ -170,10 +195,10 @@ where { let body_bytes = to_bytes(response.into_body()) .await - .map_err(|e| ClientError::ResponseParsingFailure(Arc::new(e)))?; + .map_err(|err| ClientError::ResponseParsingFailure(err.to_string()))?; - BincodeSerdeWrapper::::from_bincode(&body_bytes) - .map_err(|e| ClientError::ResponseDeserializationFailure(Arc::new(e))) + SerdeWrapper::::wrapper_deserialize(&body_bytes) + .map_err(|err| ClientError::ResponseDeserializationFailure(err.to_string())) } // Can't derive because derive forces the generics to also be `Clone`, which we prefer not to do diff --git a/crates/starknet_sequencer_infra/src/component_definitions.rs b/crates/starknet_sequencer_infra/src/component_definitions.rs index 6fd199b08cf..1f56219f579 100644 --- a/crates/starknet_sequencer_infra/src/component_definitions.rs +++ b/crates/starknet_sequencer_infra/src/component_definitions.rs @@ -1,26 +1,25 @@ -use std::any::type_name; use std::collections::BTreeMap; -use std::fmt::Debug; -use std::net::{IpAddr, Ipv4Addr, SocketAddr}; +use std::fmt::{Debug, Formatter, Result}; use async_trait::async_trait; use papyrus_config::dumping::{ser_param, SerializeConfig}; use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; +use starknet_infra_utils::type_name::short_type_name; use thiserror::Error; use tokio::sync::mpsc::{Receiver, Sender}; use tracing::{error, info}; use validator::Validate; use crate::component_client::ClientResult; -use crate::errors::ComponentError; pub const APPLICATION_OCTET_STREAM: &str = "application/octet-stream"; const DEFAULT_CHANNEL_BUFFER_SIZE: usize = 32; const DEFAULT_RETRIES: usize = 3; const DEFAULT_IDLE_CONNECTIONS: usize = usize::MAX; const DEFAULT_IDLE_TIMEOUT: u64 = 90; +const DEFAULT_RETRY_INTERVAL: u64 = 3; #[async_trait] pub trait ComponentRequestHandler { @@ -30,26 +29,52 @@ pub trait ComponentRequestHandler { #[async_trait] pub trait ComponentClient where - Request: Send + Sync + Serialize + DeserializeOwned, - Response: Send + Sync + Serialize + DeserializeOwned, + Request: Send + Serialize + DeserializeOwned, + Response: Send + Serialize + DeserializeOwned, { async fn send(&self, request: Request) -> ClientResult; } +pub async fn default_component_start_fn() { + info!("Starting component {} with the default starter.", short_type_name::()); +} + +// Generic std::fmt::debug implementation for request and response enums. Requires the +// request/response to support returning a string representation of the enum, e.g., by deriving +// `strum_macros::AsRefStr`. +pub fn default_request_response_debug_impl>( + f: &mut Formatter<'_>, + value: &T, +) -> Result { + write!(f, "{}::{}", short_type_name::(), value.as_ref()) +} + +#[macro_export] +macro_rules! impl_debug_for_infra_requests_and_responses { + ($t:ty) => { + impl std::fmt::Debug for $t { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + $crate::component_definitions::default_request_response_debug_impl(f, self) + } + } + }; +} + +// TODO(Lev/Tsabary): Enforce metrics registration at the start of the component to avoid missing +// metrics in the monitoring server. #[async_trait] pub trait ComponentStarter { - async fn start(&mut self) -> Result<(), ComponentError> { - info!("Starting component {} with the default starter.", type_name::()); - Ok(()) + async fn start(&mut self) { + default_component_start_fn::().await } } -pub struct ComponentCommunication { +pub struct ComponentCommunication { tx: Option>, rx: Option>, } -impl ComponentCommunication { +impl ComponentCommunication { pub fn new(tx: Option>, rx: Option>) -> Self { Self { tx, rx } } @@ -65,8 +90,8 @@ impl ComponentCommunication { pub struct ComponentRequestAndResponseSender where - Request: Send + Sync, - Response: Send + Sync, + Request: Send, + Response: Send, { pub request: Request, pub tx: Sender, @@ -104,20 +129,19 @@ impl Default for LocalServerConfig { // TODO(Nadin): Move the RemoteClientConfig and RemoteServerConfig to relevant modules. #[derive(Clone, Debug, Serialize, Deserialize, Validate, PartialEq)] pub struct RemoteClientConfig { - pub socket: SocketAddr, pub retries: usize, pub idle_connections: usize, pub idle_timeout: u64, + pub retry_interval: u64, } impl Default for RemoteClientConfig { fn default() -> Self { - let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 8080); Self { - socket, retries: DEFAULT_RETRIES, idle_connections: DEFAULT_IDLE_CONNECTIONS, idle_timeout: DEFAULT_IDLE_TIMEOUT, + retry_interval: DEFAULT_RETRY_INTERVAL, } } } @@ -125,12 +149,6 @@ impl Default for RemoteClientConfig { impl SerializeConfig for RemoteClientConfig { fn dump(&self) -> BTreeMap { BTreeMap::from_iter([ - ser_param( - "socket", - &self.socket.to_string(), - "The remote component server socket.", - ParamPrivacyInput::Public, - ), ser_param( "retries", &self.retries, @@ -149,29 +167,12 @@ impl SerializeConfig for RemoteClientConfig { "The duration in seconds to keep an idle connection open before closing.", ParamPrivacyInput::Public, ), + ser_param( + "retry_interval", + &self.retry_interval, + "The duration in seconds to wait between remote connection retries.", + ParamPrivacyInput::Public, + ), ]) } } - -#[derive(Clone, Debug, Serialize, Deserialize, Validate, PartialEq)] -pub struct RemoteServerConfig { - pub socket: SocketAddr, -} - -impl Default for RemoteServerConfig { - fn default() -> Self { - let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 8080); - Self { socket } - } -} - -impl SerializeConfig for RemoteServerConfig { - fn dump(&self) -> BTreeMap { - BTreeMap::from_iter([ser_param( - "socket", - &self.socket.to_string(), - "The remote component server socket.", - ParamPrivacyInput::Public, - )]) - } -} diff --git a/crates/starknet_sequencer_infra/src/component_server/definitions.rs b/crates/starknet_sequencer_infra/src/component_server/definitions.rs index 551f52b376c..3ef2d960009 100644 --- a/crates/starknet_sequencer_infra/src/component_server/definitions.rs +++ b/crates/starknet_sequencer_infra/src/component_server/definitions.rs @@ -1,12 +1,6 @@ use async_trait::async_trait; -use crate::errors::{ComponentServerError, ReplaceComponentError}; - #[async_trait] pub trait ComponentServerStarter { - async fn start(&mut self) -> Result<(), ComponentServerError>; -} - -pub trait ComponentReplacer { - fn replace(&mut self, component: Component) -> Result<(), ReplaceComponentError>; + async fn start(&mut self); } diff --git a/crates/starknet_sequencer_infra/src/component_server/empty_component_server.rs b/crates/starknet_sequencer_infra/src/component_server/empty_component_server.rs index aa4e9cd2d3a..e715c32fe70 100644 --- a/crates/starknet_sequencer_infra/src/component_server/empty_component_server.rs +++ b/crates/starknet_sequencer_infra/src/component_server/empty_component_server.rs @@ -1,11 +1,9 @@ -use std::any::type_name; - use async_trait::async_trait; +use starknet_infra_utils::type_name::short_type_name; use tracing::info; use crate::component_definitions::ComponentStarter; -use crate::component_server::{ComponentReplacer, ComponentServerStarter}; -use crate::errors::{ComponentServerError, ReplaceComponentError}; +use crate::component_server::ComponentServerStarter; pub struct WrapperServer { component: Component, @@ -19,17 +17,9 @@ impl WrapperServer { #[async_trait] impl ComponentServerStarter for WrapperServer { - async fn start(&mut self) -> Result<(), ComponentServerError> { - info!("Starting WrapperServer for {}.", type_name::()); - let res = self.component.start().await.map_err(ComponentServerError::ComponentError); - info!("Finished running WrapperServer for {}.", type_name::()); - res - } -} - -impl ComponentReplacer for WrapperServer { - fn replace(&mut self, component: Component) -> Result<(), ReplaceComponentError> { - self.component = component; - Ok(()) + async fn start(&mut self) { + info!("Starting WrapperServer for {}.", short_type_name::()); + self.component.start().await; + panic!("WrapperServer stopped for {}", short_type_name::()) } } diff --git a/crates/starknet_sequencer_infra/src/component_server/local_component_server.rs b/crates/starknet_sequencer_infra/src/component_server/local_component_server.rs index eeb4f02597e..36121edb36d 100644 --- a/crates/starknet_sequencer_infra/src/component_server/local_component_server.rs +++ b/crates/starknet_sequencer_infra/src/component_server/local_component_server.rs @@ -1,18 +1,19 @@ -use std::any::type_name; use std::fmt::Debug; -use std::marker::PhantomData; +use std::sync::Arc; use async_trait::async_trait; -use tokio::sync::mpsc::Receiver; -use tracing::{debug, error, info}; +use starknet_infra_utils::type_name::short_type_name; +use tokio::sync::mpsc::{Receiver, Sender}; +use tokio::sync::Semaphore; +use tracing::{debug, error, info, warn}; use crate::component_definitions::{ ComponentRequestAndResponseSender, ComponentRequestHandler, ComponentStarter, }; -use crate::component_server::{ComponentReplacer, ComponentServerStarter}; -use crate::errors::{ComponentServerError, ReplaceComponentError}; +use crate::component_server::ComponentServerStarter; +use crate::metrics::LocalServerMetrics; /// The `LocalComponentServer` struct is a generic server that handles requests and responses for a /// specified component. It receives requests, processes them using the provided component, and @@ -25,9 +26,9 @@ use crate::errors::{ComponentServerError, ReplaceComponentError}; /// the `ComponentRequestHandler` trait, which defines how the component processes requests and /// generates responses. /// - `Request`: The type of requests that the component will handle. This type must implement the -/// `Send` and `Sync` traits to ensure safe concurrency. +/// `Send` trait to ensure safe concurrency. /// - `Response`: The type of responses that the component will generate. This type must implement -/// the `Send` and `Sync` traits to ensure safe concurrency. +/// the `Send` trait to ensure safe concurrency. /// /// # Fields /// @@ -35,196 +36,231 @@ use crate::errors::{ComponentServerError, ReplaceComponentError}; /// - `rx`: A receiver that receives incoming requests along with a sender to send back the /// responses. This receiver is of type ` Receiver>`. -/// -/// # Example -/// ```rust -/// // Example usage of the LocalComponentServer -/// use std::sync::mpsc::{channel, Receiver}; -/// -/// use async_trait::async_trait; -/// use tokio::task; -/// -/// use crate::starknet_sequencer_infra::component_definitions::{ -/// ComponentRequestAndResponseSender, -/// ComponentRequestHandler, -/// ComponentStarter, -/// }; -/// use crate::starknet_sequencer_infra::component_server::{ -/// ComponentServerStarter, -/// LocalComponentServer, -/// }; -/// use crate::starknet_sequencer_infra::errors::ComponentServerError; -/// -/// // Define your component -/// struct MyComponent {} -/// -/// impl ComponentStarter for MyComponent {} -/// -/// // Define your request and response types -/// #[derive(Debug)] -/// struct MyRequest { -/// pub content: String, -/// } -/// -/// #[derive(Debug)] -/// struct MyResponse { -/// pub content: String, -/// } -/// -/// // Define your request processing logic -/// #[async_trait] -/// impl ComponentRequestHandler for MyComponent { -/// async fn handle_request(&mut self, request: MyRequest) -> MyResponse { -/// MyResponse { content: request.content + " processed" } -/// } -/// } -/// -/// #[tokio::main] -/// async fn main() { -/// // Create a channel for sending requests and receiving responses -/// let (tx, rx) = tokio::sync::mpsc::channel::< -/// ComponentRequestAndResponseSender, -/// >(100); -/// -/// // Instantiate the component. -/// let component = MyComponent {}; -/// -/// // Instantiate the server. -/// let mut server = LocalComponentServer::new(component, rx); -/// -/// // Start the server in a new task. -/// task::spawn(async move { -/// server.start().await; -/// }); -/// -/// // Ensure the server starts running. -/// task::yield_now().await; -/// -/// // Create the request and the response channel. -/// let (res_tx, mut res_rx) = tokio::sync::mpsc::channel::(1); -/// let request = MyRequest { content: "request example".to_string() }; -/// let request_and_res_tx = ComponentRequestAndResponseSender { request, tx: res_tx }; -/// -/// // Send the request. -/// tx.send(request_and_res_tx).await.unwrap(); -/// -/// // Receive the response. -/// let response = res_rx.recv().await.unwrap(); -/// assert!(response.content == "request example processed".to_string(), "Unexpected response"); -/// } -/// ``` -pub type LocalComponentServer = - BaseLocalComponentServer; -pub struct BlockingLocalServerType {} +/// - `metrics`: The metrics for the server. +pub struct LocalComponentServer +where + Component: ComponentRequestHandler, + Request: Send, + Response: Send, +{ + component: Component, + rx: Receiver>, + metrics: LocalServerMetrics, +} -#[async_trait] -impl ComponentServerStarter - for LocalComponentServer +impl LocalComponentServer where - Component: ComponentRequestHandler + Send + Sync + ComponentStarter, - Request: Send + Sync + Debug, - Response: Send + Sync + Debug, + Component: ComponentRequestHandler, + Request: Send, + Response: Send, { - async fn start(&mut self) -> Result<(), ComponentServerError> { - info!("Starting LocalComponentServer for {}.", type_name::()); - self.component.start().await?; - request_response_loop(&mut self.rx, &mut self.component).await; - info!("Finished LocalComponentServer for {}.", type_name::()); - Ok(()) + pub fn new( + component: Component, + rx: Receiver>, + metrics: LocalServerMetrics, + ) -> Self { + metrics.register(); + Self { component, rx, metrics } } } -pub type LocalActiveComponentServer = - BaseLocalComponentServer; -pub struct NonBlockingLocalServerType {} +impl Drop for LocalComponentServer +where + Component: ComponentRequestHandler, + Request: Send, + Response: Send, +{ + fn drop(&mut self) { + warn!("Dropping {}.", short_type_name::()); + } +} #[async_trait] impl ComponentServerStarter - for LocalActiveComponentServer + for LocalComponentServer where - Component: ComponentRequestHandler + ComponentStarter + Clone + Send + Sync, - Request: Send + Sync + Debug, - Response: Send + Sync + Debug, + Component: ComponentRequestHandler + Send + ComponentStarter, + Request: Send + Debug, + Response: Send + Debug, +{ + async fn start(&mut self) { + info!("Starting LocalComponentServer for {}.", short_type_name::()); + self.component.start().await; + request_response_loop(&mut self.rx, &mut self.component, &self.metrics).await; + panic!("Finished LocalComponentServer for {}.", short_type_name::()); + } +} + +async fn request_response_loop( + rx: &mut Receiver>, + component: &mut Component, + metrics: &LocalServerMetrics, +) where + Component: ComponentRequestHandler + Send, + Request: Send + Debug, + Response: Send + Debug, { - async fn start(&mut self) -> Result<(), ComponentServerError> { - let mut component = self.component.clone(); - let component_future = async move { component.start().await }; - let request_response_future = request_response_loop(&mut self.rx, &mut self.component); - - tokio::select! { - _res = component_future => { - error!("Component stopped."); - } - _res = request_response_future => { - error!("Server stopped."); - } - }; - error!("Server ended with unexpected Ok."); - Err(ComponentServerError::ServerUnexpectedlyStopped) + info!("Starting server for component {}", short_type_name::()); + + while let Some(request_and_res_tx) = rx.recv().await { + let request = request_and_res_tx.request; + let tx = request_and_res_tx.tx; + debug!("Component {} received request {:?}", short_type_name::(), request); + + metrics.increment_received(); + metrics.set_queue_depth(rx.len()); + + process_request(component, request, tx).await; + + metrics.increment_processed(); } + + error!("Stopping server for component {}", short_type_name::()); } -pub struct BaseLocalComponentServer +/// The `ConcurrentLocalComponentServer` struct is a generic server that handles concurrent requests +/// and responses for a specified component. It receives requests, processes them concurrently by +/// running the provided component in a task, with returning response back form the task. The server +/// needs to be started using the `start` function, which runs indefinitely. +/// +/// # Type Parameters +/// +/// - `Component`: The type of the component that will handle the requests. This type must implement +/// the `ComponentRequestHandler` trait, which defines how the component processes requests and +/// generates responses. In order to handle concurrent requests, the component must also implement +/// the `Clone` trait and the `Send`. +/// - `Request`: The type of requests that the component will handle. This type must implement the +/// `Send` trait to ensure safe concurrency. +/// - `Response`: The type of responses that the component will generate. This type must implement +/// the `Send` trait to ensure safe concurrency. +/// +/// # Fields +/// +/// - `component`: The component responsible for handling the requests and generating responses. +/// - `rx`: A receiver that receives incoming requests along with a sender to send back the +/// responses. This receiver is of type ` Receiver>`. +/// - `max_concurrency`: The maximum number of concurrent requests that the server can handle. +/// - `metrics`: The metrics for the server wrapped in Arc so it could be used concurrently. +pub struct ConcurrentLocalComponentServer where Component: ComponentRequestHandler, - Request: Send + Sync, - Response: Send + Sync, + Request: Send, + Response: Send, { component: Component, rx: Receiver>, - _local_server_type: PhantomData, + max_concurrency: usize, + metrics: Arc, } -impl - BaseLocalComponentServer +impl ConcurrentLocalComponentServer where Component: ComponentRequestHandler, - Request: Send + Sync, - Response: Send + Sync, + Request: Send, + Response: Send, { pub fn new( component: Component, rx: Receiver>, + max_concurrency: usize, + metrics: LocalServerMetrics, ) -> Self { - Self { component, rx, _local_server_type: PhantomData } + metrics.register(); + Self { component, rx, max_concurrency, metrics: Arc::new(metrics) } } } -impl ComponentReplacer - for BaseLocalComponentServer +// TODO(Lev,Itay): Find a way to avoid duplicity, maybe by a blanket implementation. +impl Drop + for ConcurrentLocalComponentServer where Component: ComponentRequestHandler, - Request: Send + Sync, - Response: Send + Sync, + Request: Send, + Response: Send, { - fn replace(&mut self, component: Component) -> Result<(), ReplaceComponentError> { - self.component = component; - Ok(()) + fn drop(&mut self) { + warn!("Dropping {}.", short_type_name::()); } } -async fn request_response_loop( +#[async_trait] +impl ComponentServerStarter + for ConcurrentLocalComponentServer +where + Component: + ComponentRequestHandler + ComponentStarter + Clone + Send + 'static, + Request: Send + Debug + 'static, + Response: Send + Debug + 'static, +{ + async fn start(&mut self) { + info!("Starting ConcurrentLocalComponentServer for {}.", short_type_name::()); + self.component.start().await; + concurrent_request_response_loop( + &mut self.rx, + &mut self.component, + self.max_concurrency, + self.metrics.clone(), + ) + .await; + panic!("Finished ConcurrentLocalComponentServer for {}.", short_type_name::()); + } +} + +// TODO(Itay): clean some code duplications here. +async fn concurrent_request_response_loop( rx: &mut Receiver>, component: &mut Component, + max_concurrency: usize, + metrics: Arc, ) where - Component: ComponentRequestHandler + Send + Sync, - Request: Send + Sync + Debug, - Response: Send + Sync + Debug, + Component: ComponentRequestHandler + Clone + Send + 'static, + Request: Send + Debug + 'static, + Response: Send + Debug + 'static, { - info!("Starting server for component {}", type_name::()); + info!("Starting concurrent server for component {}", short_type_name::()); + + let task_limiter = Arc::new(Semaphore::new(max_concurrency)); while let Some(request_and_res_tx) = rx.recv().await { let request = request_and_res_tx.request; let tx = request_and_res_tx.tx; - debug!("Component {} received request {:?}", type_name::(), request); + debug!("Component {} received request {:?}", short_type_name::(), request); + + metrics.increment_received(); + metrics.set_queue_depth(rx.len()); + + // Acquire a permit to run the task. + let permit = task_limiter.clone().acquire_owned().await.unwrap(); - let response = component.handle_request(request).await; - debug!("Component {} is sending response {:?}", type_name::(), response); + let mut cloned_component = component.clone(); + let cloned_metrics = metrics.clone(); + tokio::spawn(async move { + process_request(&mut cloned_component, request, tx).await; - // Send the response to the client. This might result in a panic if the client has closed - // the response channel, which is considered a bug. - tx.send(response).await.expect("Response connection should be open."); + cloned_metrics.increment_processed(); + + // Drop the permit to allow more tasks to be created. + drop(permit); + }); } - info!("Stopping server for component {}", type_name::()); + error!("Stopping concurrent server for component {}", short_type_name::()); +} + +async fn process_request( + component: &mut Component, + request: Request, + tx: Sender, +) where + Component: ComponentRequestHandler + Send, + Request: Send + Debug, + Response: Send + Debug, +{ + let response = component.handle_request(request).await; + debug!("Component {} is sending response {:?}", short_type_name::(), response); + + // Send the response to the client. This might result in a panic if the client has closed + // the response channel, which is considered a bug. + tx.send(response).await.expect("Response connection should be open."); } diff --git a/crates/starknet_sequencer_infra/src/component_server/remote_component_server.rs b/crates/starknet_sequencer_infra/src/component_server/remote_component_server.rs index 9b4b97584e3..f9527a5575a 100644 --- a/crates/starknet_sequencer_infra/src/component_server/remote_component_server.rs +++ b/crates/starknet_sequencer_infra/src/component_server/remote_component_server.rs @@ -1,5 +1,5 @@ use std::fmt::Debug; -use std::net::SocketAddr; +use std::net::{IpAddr, SocketAddr}; use std::sync::Arc; use async_trait::async_trait; @@ -9,17 +9,16 @@ use hyper::service::{make_service_fn, service_fn}; use hyper::{Body, Request as HyperRequest, Response as HyperResponse, Server, StatusCode}; use serde::de::DeserializeOwned; use serde::Serialize; +use starknet_infra_utils::type_name::short_type_name; +use tower::limit::ConcurrencyLimitLayer; +use tower::ServiceBuilder; +use tracing::{debug, error, warn}; use crate::component_client::{ClientError, LocalComponentClient}; -use crate::component_definitions::{ - ComponentClient, - RemoteServerConfig, - ServerError, - APPLICATION_OCTET_STREAM, -}; +use crate::component_definitions::{ComponentClient, ServerError, APPLICATION_OCTET_STREAM}; use crate::component_server::ComponentServerStarter; -use crate::errors::ComponentServerError; -use crate::serde_utils::BincodeSerdeWrapper; +use crate::metrics::RemoteServerMetrics; +use crate::serde_utils::SerdeWrapper; /// The `RemoteComponentServer` struct is a generic server that handles requests and responses for a /// specified component. It receives requests, processes them using the provided component, and @@ -46,19 +45,38 @@ use crate::serde_utils::BincodeSerdeWrapper; /// // Example usage of the RemoteComponentServer /// use async_trait::async_trait; /// use serde::{Deserialize, Serialize}; +/// use starknet_sequencer_metrics::metrics::{MetricCounter, MetricScope}; /// use tokio::task; /// /// use crate::starknet_sequencer_infra::component_client::LocalComponentClient; /// use crate::starknet_sequencer_infra::component_definitions::{ /// ComponentRequestHandler, /// ComponentStarter, -/// RemoteServerConfig, /// }; /// use crate::starknet_sequencer_infra::component_server::{ /// ComponentServerStarter, /// RemoteComponentServer, /// }; -/// use crate::starknet_sequencer_infra::errors::ComponentError; +/// use crate::starknet_sequencer_infra::metrics::RemoteServerMetrics; +/// +/// const REMOTE_MESSAGES_RECEIVED: MetricCounter = MetricCounter::new( +/// MetricScope::Infra, +/// "remote_received_messages_counter", +/// "Received remote messages counter", +/// 0, +/// ); +/// const REMOTE_VALID_MESSAGES_RECEIVED: MetricCounter = MetricCounter::new( +/// MetricScope::Infra, +/// "remote_valid_received_messages_counter", +/// "Received remote valid messages counter", +/// 0, +/// ); +/// const REMOTE_MESSAGES_PROCESSED: MetricCounter = MetricCounter::new( +/// MetricScope::Infra, +/// "remote_processed_messages_counter", +/// "Processed messages counter", +/// 0, +/// ); /// /// // Define your component /// struct MyComponent {} @@ -93,10 +111,20 @@ use crate::serde_utils::BincodeSerdeWrapper; /// // Set the ip address and port of the server's socket. /// let ip_address = std::net::IpAddr::V6(std::net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); /// let port: u16 = 8080; -/// let config = RemoteServerConfig { socket: std::net::SocketAddr::new(ip_address, port) }; +/// let max_concurrency = 10; /// /// // Instantiate the server. -/// let mut server = RemoteComponentServer::::new(local_client, config); +/// let mut server = RemoteComponentServer::::new( +/// local_client, +/// ip_address, +/// port, +/// max_concurrency, +/// RemoteServerMetrics::new( +/// &REMOTE_MESSAGES_RECEIVED, +/// &REMOTE_VALID_MESSAGES_RECEIVED, +/// &REMOTE_MESSAGES_PROCESSED, +/// ), +/// ); /// /// // Start the server in a new task. /// task::spawn(async move { @@ -106,45 +134,70 @@ use crate::serde_utils::BincodeSerdeWrapper; /// ``` pub struct RemoteComponentServer where - Request: Serialize + DeserializeOwned + Send + Sync + 'static, - Response: Serialize + DeserializeOwned + Send + Sync + 'static, + Request: Serialize + DeserializeOwned + Send + 'static, + Response: Serialize + DeserializeOwned + Send + 'static, { socket: SocketAddr, local_client: LocalComponentClient, + max_concurrency: usize, + metrics: Arc, } impl RemoteComponentServer where - Request: Serialize + DeserializeOwned + Debug + Send + Sync + 'static, - Response: Serialize + DeserializeOwned + Debug + Send + Sync + 'static, + Request: Serialize + DeserializeOwned + Debug + Send + 'static, + Response: Serialize + DeserializeOwned + Debug + Send + 'static, { pub fn new( local_client: LocalComponentClient, - config: RemoteServerConfig, + ip: IpAddr, + port: u16, + max_concurrency: usize, + metrics: RemoteServerMetrics, ) -> Self { - Self { local_client, socket: config.socket } + metrics.register(); + Self { + local_client, + socket: SocketAddr::new(ip, port), + max_concurrency, + metrics: Arc::new(metrics), + } } async fn remote_component_server_handler( http_request: HyperRequest, local_client: LocalComponentClient, + metrics: Arc, ) -> Result, hyper::Error> { + debug!("Received HTTP request: {:?}", http_request); let body_bytes = to_bytes(http_request.into_body()).await?; + debug!("Extracted {} bytes from HTTP request body", body_bytes.len()); - let http_response = match BincodeSerdeWrapper::::from_bincode(&body_bytes) - .map_err(|e| ClientError::ResponseDeserializationFailure(Arc::new(e))) + metrics.increment_total_received(); + + let http_response = match SerdeWrapper::::wrapper_deserialize(&body_bytes) + .map_err(|err| ClientError::ResponseDeserializationFailure(err.to_string())) { Ok(request) => { + debug!("Successfully deserialized request: {:?}", request); + metrics.increment_valid_received(); + let response = local_client.send(request).await; + + metrics.increment_processed(); + match response { - Ok(response) => HyperResponse::builder() - .status(StatusCode::OK) - .header(CONTENT_TYPE, APPLICATION_OCTET_STREAM) - .body(Body::from( - BincodeSerdeWrapper::new(response) - .to_bincode() - .expect("Response serialization should succeed"), - )), + Ok(response) => { + debug!("Local client processed request successfully: {:?}", response); + HyperResponse::builder() + .status(StatusCode::OK) + .header(CONTENT_TYPE, APPLICATION_OCTET_STREAM) + .body(Body::from( + SerdeWrapper::new(response) + .wrapper_serialize() + .expect("Response serialization should succeed"), + )) + } Err(error) => { panic!( "Remote server failed sending with its local client. Error: {:?}", @@ -154,15 +207,17 @@ where } } Err(error) => { + error!("Failed to deserialize request: {:?}", error); let server_error = ServerError::RequestDeserializationFailure(error.to_string()); HyperResponse::builder().status(StatusCode::BAD_REQUEST).body(Body::from( - BincodeSerdeWrapper::new(server_error) - .to_bincode() + SerdeWrapper::new(server_error) + .wrapper_serialize() .expect("Server error serialization should succeed"), )) } } .expect("Response building should succeed"); + debug!("Built HTTP response: {:?}", http_response); Ok(http_response) } @@ -171,23 +226,51 @@ where #[async_trait] impl ComponentServerStarter for RemoteComponentServer where - Request: Serialize + DeserializeOwned + Send + Sync + Debug + 'static, - Response: Serialize + DeserializeOwned + Send + Sync + Debug + 'static, + Request: Serialize + DeserializeOwned + Send + Debug + 'static, + Response: Serialize + DeserializeOwned + Send + Debug + 'static, { - async fn start(&mut self) -> Result<(), ComponentServerError> { + async fn start(&mut self) { + debug!("Starting server on socket: {:?}", self.socket); let make_svc = make_service_fn(|_conn| { let local_client = self.local_client.clone(); - async { - Ok::<_, hyper::Error>(service_fn(move |req| { - Self::remote_component_server_handler(req, local_client.clone()) - })) + let max_concurrency = self.max_concurrency; + debug!( + "Initializing service for new connection with max_concurrency: {:?}", + max_concurrency + ); + let metrics = self.metrics.clone(); + async move { + let app_service = service_fn(move |req| { + debug!("Received request: {:?}", req); + Self::remote_component_server_handler( + req, + local_client.clone(), + metrics.clone(), + ) + }); + + // Apply the ConcurrencyLimitLayer middleware + let service = ServiceBuilder::new() + .layer(ConcurrencyLimitLayer::new(max_concurrency)) + .service(app_service); + + Ok::<_, hyper::Error>(service) } }); - - Server::bind(&self.socket.clone()) + debug!("Binding server to socket: {:?}", self.socket); + Server::bind(&self.socket) .serve(make_svc) .await - .map_err(|err| ComponentServerError::HttpServerStartError(err.to_string()))?; - Ok(()) + .unwrap_or_else(|e| panic!("HttpServerStartError: {}", e)); + } +} + +impl Drop for RemoteComponentServer +where + Request: Serialize + DeserializeOwned + Send + 'static, + Response: Serialize + DeserializeOwned + Send + 'static, +{ + fn drop(&mut self) { + warn!("Dropping {}.", short_type_name::()); } } diff --git a/crates/starknet_sequencer_infra/src/errors.rs b/crates/starknet_sequencer_infra/src/errors.rs deleted file mode 100644 index 9f1b04211ef..00000000000 --- a/crates/starknet_sequencer_infra/src/errors.rs +++ /dev/null @@ -1,25 +0,0 @@ -use thiserror::Error; - -#[derive(Error, Debug, PartialEq, Clone)] -pub enum ComponentError { - #[error("Error in the component configuration.")] - ComponentConfigError, - #[error("An internal component error.")] - InternalComponentError, -} - -#[derive(Error, Debug, PartialEq, Clone)] -pub enum ComponentServerError { - #[error(transparent)] - ComponentError(#[from] ComponentError), - #[error("Http server has failed: {0}.")] - HttpServerStartError(String), - #[error("Server unexpectedly stopped.")] - ServerUnexpectedlyStopped, -} - -#[derive(Clone, Debug, Error)] -pub enum ReplaceComponentError { - #[error("Internal error.")] - InternalError, -} diff --git a/crates/starknet_sequencer_infra/src/lib.rs b/crates/starknet_sequencer_infra/src/lib.rs index 306085d44a8..2ed2aebd00d 100644 --- a/crates/starknet_sequencer_infra/src/lib.rs +++ b/crates/starknet_sequencer_infra/src/lib.rs @@ -1,10 +1,8 @@ pub mod component_client; pub mod component_definitions; pub mod component_server; -pub mod errors; +pub mod metrics; pub mod serde_utils; -#[cfg(any(feature = "testing", test))] -pub mod test_utils; #[cfg(test)] pub mod tests; pub mod trace_util; diff --git a/crates/starknet_sequencer_infra/src/metrics.rs b/crates/starknet_sequencer_infra/src/metrics.rs new file mode 100644 index 00000000000..a0361767afe --- /dev/null +++ b/crates/starknet_sequencer_infra/src/metrics.rs @@ -0,0 +1,173 @@ +use starknet_sequencer_metrics::define_metrics; +use starknet_sequencer_metrics::metrics::{MetricCounter, MetricGauge}; + +define_metrics!( + Infra => { + // Local server counters + MetricCounter { BATCHER_LOCAL_MSGS_RECEIVED, "batcher_local_msgs_received", "Counter of messages received by batcher local server", init = 0 }, + MetricCounter { BATCHER_LOCAL_MSGS_PROCESSED, "batcher_local_msgs_processed", "Counter of messages processed by batcher local server", init = 0 }, + MetricCounter { CLASS_MANAGER_LOCAL_MSGS_RECEIVED, "class_manager_local_msgs_received", "Counter of messages received by class manager local server", init = 0 }, + MetricCounter { CLASS_MANAGER_LOCAL_MSGS_PROCESSED, "class_manager_local_msgs_processed", "Counter of messages processed by class manager local server", init = 0 }, + MetricCounter { GATEWAY_LOCAL_MSGS_RECEIVED, "gateway_local_msgs_received", "Counter of messages received by gateway local server", init = 0 }, + MetricCounter { GATEWAY_LOCAL_MSGS_PROCESSED, "gateway_local_msgs_processed", "Counter of messages processed by gateway local server", init = 0 }, + MetricCounter { L1_PROVIDER_LOCAL_MSGS_RECEIVED, "l1_provider_local_msgs_received", "Counter of messages received by L1 provider local server", init = 0 }, + MetricCounter { L1_PROVIDER_LOCAL_MSGS_PROCESSED, "l1_provider_local_msgs_processed", "Counter of messages processed by L1 provider local server", init = 0 }, + MetricCounter { L1_GAS_PRICE_PROVIDER_LOCAL_MSGS_RECEIVED, "l1_gas_price_provider_local_msgs_received", "Counter of messages received by L1 gas price provider local server", init = 0 }, + MetricCounter { L1_GAS_PRICE_PROVIDER_LOCAL_MSGS_PROCESSED, "l1_gas_price_provider_local_msgs_processed", "Counter of messages processed by L1 gas price provider local server", init = 0 }, + MetricCounter { MEMPOOL_LOCAL_MSGS_RECEIVED, "mempool_local_msgs_received", "Counter of messages received by mempool local server", init = 0 }, + MetricCounter { MEMPOOL_LOCAL_MSGS_PROCESSED, "mempool_local_msgs_processed", "Counter of messages processed by mempool local server", init = 0 }, + MetricCounter { MEMPOOL_P2P_LOCAL_MSGS_RECEIVED, "mempool_p2p_propagator_local_msgs_received", "Counter of messages received by mempool p2p local server", init = 0 }, + MetricCounter { MEMPOOL_P2P_LOCAL_MSGS_PROCESSED, "mempool_p2p_propagator_local_msgs_processed", "Counter of messages processed by mempool p2p local server", init = 0 }, + MetricCounter { SIERRA_COMPILER_LOCAL_MSGS_RECEIVED, "sierra_compiler_local_msgs_received", "Counter of messages received by sierra compiler local server", init = 0 }, + MetricCounter { SIERRA_COMPILER_LOCAL_MSGS_PROCESSED, "sierra_compiler_local_msgs_processed", "Counter of messages processed by sierra compiler local server", init = 0 }, + MetricCounter { STATE_SYNC_LOCAL_MSGS_RECEIVED, "state_sync_local_msgs_received", "Counter of messages received by state sync local server", init = 0 }, + MetricCounter { STATE_SYNC_LOCAL_MSGS_PROCESSED, "state_sync_local_msgs_processed", "Counter of messages processed by state sync local server", init = 0 }, + // Remote server counters + MetricCounter { BATCHER_REMOTE_MSGS_RECEIVED, "batcher_remote_msgs_received", "Counter of messages received by batcher remote server", init = 0 }, + MetricCounter { BATCHER_REMOTE_VALID_MSGS_RECEIVED, "batcher_remote_valid_msgs_received", "Counter of valid messages received by batcher remote server", init = 0 }, + MetricCounter { BATCHER_REMOTE_MSGS_PROCESSED, "batcher_remote_msgs_processed", "Counter of messages processed by batcher remote server", init = 0 }, + MetricCounter { CLASS_MANAGER_REMOTE_MSGS_RECEIVED, "class_manager_remote_msgs_received", "Counter of messages received by class manager remote server", init = 0 }, + MetricCounter { CLASS_MANAGER_REMOTE_VALID_MSGS_RECEIVED, "class_manager_remote_valid_msgs_received", "Counter of valid messages received by class manager remote server", init = 0 }, + MetricCounter { CLASS_MANAGER_REMOTE_MSGS_PROCESSED, "class_manager_remote_msgs_processed", "Counter of messages processed by class manager remote server", init = 0 }, + MetricCounter { GATEWAY_REMOTE_MSGS_RECEIVED, "gateway_remote_msgs_received", "Counter of messages received by gateway remote server", init = 0 }, + MetricCounter { GATEWAY_REMOTE_VALID_MSGS_RECEIVED, "gateway_remote_valid_msgs_received", "Counter of valid messages received by gateway remote server", init = 0 }, + MetricCounter { GATEWAY_REMOTE_MSGS_PROCESSED, "gateway_remote_msgs_processed", "Counter of messages processed by gateway remote server", init = 0 }, + MetricCounter { L1_PROVIDER_REMOTE_MSGS_RECEIVED, "l1_provider_remote_msgs_received", "Counter of messages received by L1 provider remote server", init = 0 }, + MetricCounter { L1_PROVIDER_REMOTE_VALID_MSGS_RECEIVED, "l1_provider_remote_valid_msgs_received", "Counter of valid messages received by L1 provider remote server", init = 0 }, + MetricCounter { L1_PROVIDER_REMOTE_MSGS_PROCESSED, "l1_provider_remote_msgs_processed", "Counter of messages processed by L1 provider remote server", init = 0 }, + MetricCounter { L1_GAS_PRICE_PROVIDER_REMOTE_MSGS_RECEIVED, "l1_gas_price_provider_remote_msgs_received", "Counter of messages received by L1 gas price provider remote server", init = 0 }, + MetricCounter { L1_GAS_PRICE_PROVIDER_REMOTE_VALID_MSGS_RECEIVED, "l1_gas_price_provider_remote_valid_msgs_received", "Counter of valid messages received by L1 gas price provider remote server", init = 0 }, + MetricCounter { L1_GAS_PRICE_PROVIDER_REMOTE_MSGS_PROCESSED, "l1_gas_price_provider_remote_msgs_processed", "Counter of messages processed by L1 gas price provider remote server", init = 0 }, + MetricCounter { MEMPOOL_REMOTE_MSGS_RECEIVED, "mempool_remote_msgs_received", "Counter of messages received by mempool remote server", init = 0 }, + MetricCounter { MEMPOOL_REMOTE_VALID_MSGS_RECEIVED, "mempool_remote_valid_msgs_received", "Counter of valid messages received by mempool remote server", init = 0 }, + MetricCounter { MEMPOOL_REMOTE_MSGS_PROCESSED, "mempool_remote_msgs_processed", "Counter of messages processed by mempool remote server", init = 0 }, + MetricCounter { MEMPOOL_P2P_REMOTE_MSGS_RECEIVED, "mempool_p2p_propagator_remote_msgs_received", "Counter of messages received by mempool p2p remote server", init = 0 }, + MetricCounter { MEMPOOL_P2P_REMOTE_VALID_MSGS_RECEIVED, "mempool_p2p_propagator_remote_valid_msgs_received", "Counter of valid messages received by mempool p2p remote server", init = 0 }, + MetricCounter { MEMPOOL_P2P_REMOTE_MSGS_PROCESSED, "mempool_p2p_propagator_remote_msgs_processed", "Counter of messages processed by mempool p2p remote server", init = 0 }, + MetricCounter { STATE_SYNC_REMOTE_MSGS_RECEIVED, "state_sync_remote_msgs_received", "Counter of messages received by state sync remote server", init = 0 }, + MetricCounter { STATE_SYNC_REMOTE_VALID_MSGS_RECEIVED, "state_sync_remote_valid_msgs_received", "Counter of valid messages received by state sync remote server", init = 0 }, + MetricCounter { STATE_SYNC_REMOTE_MSGS_PROCESSED, "state_sync_remote_msgs_processed", "Counter of messages processed by state sync remote server", init = 0 }, + // Local server queue depths + MetricGauge { BATCHER_LOCAL_QUEUE_DEPTH, "batcher_local_queue_depth", "The depth of the batcher's local message queue" }, + MetricGauge { CLASS_MANAGER_LOCAL_QUEUE_DEPTH, "class_manager_local_queue_depth", "The depth of the class manager's local message queue" }, + MetricGauge { GATEWAY_LOCAL_QUEUE_DEPTH, "gateway_local_queue_depth", "The depth of the gateway's local message queue" }, + MetricGauge { L1_PROVIDER_LOCAL_QUEUE_DEPTH, "l1_provider_local_queue_depth", "The depth of the L1 provider's local message queue" }, + MetricGauge { L1_GAS_PRICE_PROVIDER_LOCAL_QUEUE_DEPTH, "l1_gas_price_provider_local_queue_depth", "The depth of the L1 gas price provider's local message queue" }, + MetricGauge { MEMPOOL_LOCAL_QUEUE_DEPTH, "mempool_local_queue_depth", "The depth of the mempool's local message queue" }, + MetricGauge { MEMPOOL_P2P_LOCAL_QUEUE_DEPTH, "mempool_p2p_propagator_local_queue_depth", "The depth of the mempool p2p's local message queue" }, + MetricGauge { SIERRA_COMPILER_LOCAL_QUEUE_DEPTH, "sierra_compiler_local_queue_depth", "The depth of the sierra compiler's local message queue" }, + MetricGauge { STATE_SYNC_LOCAL_QUEUE_DEPTH, "state_sync_local_queue_depth", "The depth of the state sync's local message queue" }, + }, +); + +/// A struct to contain all metrics for a local server. +pub struct LocalServerMetrics { + received_msgs: &'static MetricCounter, + processed_msgs: &'static MetricCounter, + queue_depth: &'static MetricGauge, +} + +impl LocalServerMetrics { + pub const fn new( + received_msgs: &'static MetricCounter, + processed_msgs: &'static MetricCounter, + queue_depth: &'static MetricGauge, + ) -> Self { + Self { received_msgs, processed_msgs, queue_depth } + } + + pub fn register(&self) { + self.received_msgs.register(); + self.processed_msgs.register(); + self.queue_depth.register(); + } + + pub fn increment_received(&self) { + self.received_msgs.increment(1); + } + + #[cfg(any(feature = "testing", test))] + pub fn get_received_value(&self, metrics_as_string: &str) -> u64 { + self.received_msgs + .parse_numeric_metric::(metrics_as_string) + .expect("received_msgs metrics should be available") + } + + pub fn increment_processed(&self) { + self.processed_msgs.increment(1); + } + + #[cfg(any(feature = "testing", test))] + pub fn get_processed_value(&self, metrics_as_string: &str) -> u64 { + self.processed_msgs + .parse_numeric_metric::(metrics_as_string) + .expect("processed_msgs metrics should be available") + } + + pub fn set_queue_depth(&self, value: usize) { + self.queue_depth.set_lossy(value); + } + + #[cfg(any(feature = "testing", test))] + pub fn get_queue_depth_value(&self, metrics_as_string: &str) -> usize { + self.queue_depth + .parse_numeric_metric::(metrics_as_string) + .expect("queue_depth metrics should be available") + } +} + +/// A struct to contain all metrics for a remote server. +pub struct RemoteServerMetrics { + total_received_msgs: &'static MetricCounter, + valid_received_msgs: &'static MetricCounter, + processed_msgs: &'static MetricCounter, +} + +impl RemoteServerMetrics { + pub const fn new( + total_received_msgs: &'static MetricCounter, + valid_received_msgs: &'static MetricCounter, + processed_msgs: &'static MetricCounter, + ) -> Self { + Self { total_received_msgs, valid_received_msgs, processed_msgs } + } + + pub fn register(&self) { + self.total_received_msgs.register(); + self.valid_received_msgs.register(); + self.processed_msgs.register(); + } + + pub fn increment_total_received(&self) { + self.total_received_msgs.increment(1); + } + + #[cfg(any(feature = "testing", test))] + pub fn get_total_received_value(&self, metrics_as_string: &str) -> u64 { + self.total_received_msgs + .parse_numeric_metric::(metrics_as_string) + .expect("total_received_msgs metrics should be available") + } + + pub fn increment_valid_received(&self) { + self.valid_received_msgs.increment(1); + } + + #[cfg(any(feature = "testing", test))] + pub fn get_valid_received_value(&self, metrics_as_string: &str) -> u64 { + self.valid_received_msgs + .parse_numeric_metric::(metrics_as_string) + .expect("valid_received_msgs metrics should be available") + } + + pub fn increment_processed(&self) { + self.processed_msgs.increment(1); + } + + #[cfg(any(feature = "testing", test))] + pub fn get_processed_value(&self, metrics_as_string: &str) -> u64 { + self.processed_msgs + .parse_numeric_metric::(metrics_as_string) + .expect("processed_msgs metrics should be available") + } +} diff --git a/crates/starknet_sequencer_infra/src/serde_utils.rs b/crates/starknet_sequencer_infra/src/serde_utils.rs index a93d0094816..bf921d800e7 100644 --- a/crates/starknet_sequencer_infra/src/serde_utils.rs +++ b/crates/starknet_sequencer_infra/src/serde_utils.rs @@ -1,7 +1,7 @@ use std::fmt::Debug; -use bincode::{deserialize, serialize}; use serde::{Deserialize, Serialize}; +use serde_json::{from_slice, to_vec}; #[cfg(test)] #[path = "serde_utils_test.rs"] @@ -10,11 +10,11 @@ pub mod serde_utils_test; // A generic wrapper struct for binary serialization and deserialization, used for remote component // communication. #[derive(Serialize, Deserialize, Debug)] -pub struct BincodeSerdeWrapper { +pub struct SerdeWrapper { data: T, } -impl BincodeSerdeWrapper +impl SerdeWrapper where T: Serialize + for<'de> Deserialize<'de> + Debug, { @@ -22,11 +22,11 @@ where Self { data } } - pub fn to_bincode(&self) -> Result, bincode::Error> { - serialize(self) + pub fn wrapper_serialize(&self) -> Result, serde_json::Error> { + to_vec(self) } - pub fn from_bincode(bytes: &[u8]) -> Result { - deserialize(bytes).map(|serde_wrapper: Self| serde_wrapper.data) + pub fn wrapper_deserialize(bytes: &[u8]) -> Result { + from_slice(bytes).map(|serde_wrapper: Self| serde_wrapper.data) } } diff --git a/crates/starknet_sequencer_infra/src/serde_utils_test.rs b/crates/starknet_sequencer_infra/src/serde_utils_test.rs index 51251c65309..6436a466e44 100644 --- a/crates/starknet_sequencer_infra/src/serde_utils_test.rs +++ b/crates/starknet_sequencer_infra/src/serde_utils_test.rs @@ -1,30 +1,40 @@ use std::fmt::Debug; use serde::{Deserialize, Serialize}; +use starknet_api::data_availability::DataAvailabilityMode; +use starknet_api::rpc_transaction::{ + RpcDeclareTransaction, + RpcDeclareTransactionV3, + RpcDeployAccountTransaction, + RpcDeployAccountTransactionV3, + RpcInvokeTransaction, + RpcInvokeTransactionV3, + RpcTransaction, +}; use starknet_types_core::felt::Felt; -use crate::serde_utils::BincodeSerdeWrapper; +use crate::serde_utils::SerdeWrapper; fn test_generic_data_serde(data: T) where - T: Serialize + for<'de> Deserialize<'de> + Debug + Clone + Copy + PartialEq, + T: Serialize + for<'de> Deserialize<'de> + Debug + Clone + PartialEq, { // Serialize and deserialize the data. - let encoded = BincodeSerdeWrapper::new(data).to_bincode().unwrap(); - let decoded = BincodeSerdeWrapper::::from_bincode(&encoded).unwrap(); + let encoded = SerdeWrapper::new(data.clone()).wrapper_serialize().unwrap(); + let decoded = SerdeWrapper::::wrapper_deserialize(&encoded).unwrap(); // Assert that the data is the same after serialization and deserialization. assert_eq!(data, decoded); } #[test] -fn test_serde_native_type() { +fn serde_native_type() { let data: u32 = 8; test_generic_data_serde(data); } #[test] -fn test_serde_struct_type() { +fn serde_struct_type() { #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq)] struct TestStruct { a: u32, @@ -36,7 +46,65 @@ fn test_serde_struct_type() { } #[test] -fn test_serde_felt() { +fn serde_felt() { let data: Felt = Felt::ONE; test_generic_data_serde(data); } + +#[test] +fn serde_rpc_invoke_tx() { + let invoke_tx = RpcInvokeTransactionV3 { + sender_address: Default::default(), + calldata: Default::default(), + signature: Default::default(), + nonce: Default::default(), + resource_bounds: Default::default(), + tip: Default::default(), + paymaster_data: Default::default(), + account_deployment_data: Default::default(), + nonce_data_availability_mode: DataAvailabilityMode::L1, + fee_data_availability_mode: DataAvailabilityMode::L1, + }; + let rpc_invoke_tx = RpcInvokeTransaction::V3(invoke_tx); + + test_generic_data_serde(RpcTransaction::Invoke(rpc_invoke_tx)); +} + +#[test] +fn serde_rpc_deploy_account_tx() { + let deploy_account_tx = RpcDeployAccountTransactionV3 { + signature: Default::default(), + nonce: Default::default(), + class_hash: Default::default(), + resource_bounds: Default::default(), + contract_address_salt: Default::default(), + constructor_calldata: Default::default(), + tip: Default::default(), + paymaster_data: Default::default(), + nonce_data_availability_mode: DataAvailabilityMode::L1, + fee_data_availability_mode: DataAvailabilityMode::L1, + }; + let rpc_deploy_account_tx = RpcDeployAccountTransaction::V3(deploy_account_tx); + + test_generic_data_serde(RpcTransaction::DeployAccount(rpc_deploy_account_tx)); +} + +#[test] +fn serde_rpc_declare_tx() { + let declare_tx = RpcDeclareTransactionV3 { + sender_address: Default::default(), + compiled_class_hash: Default::default(), + signature: Default::default(), + nonce: Default::default(), + contract_class: Default::default(), + resource_bounds: Default::default(), + tip: Default::default(), + paymaster_data: Default::default(), + account_deployment_data: Default::default(), + nonce_data_availability_mode: DataAvailabilityMode::L1, + fee_data_availability_mode: DataAvailabilityMode::L1, + }; + let rpc_declare_tx = RpcDeclareTransaction::V3(declare_tx); + + test_generic_data_serde(RpcTransaction::Declare(rpc_declare_tx)); +} diff --git a/crates/starknet_sequencer_infra/src/test_utils.rs b/crates/starknet_sequencer_infra/src/test_utils.rs deleted file mode 100644 index 464af8c7083..00000000000 --- a/crates/starknet_sequencer_infra/src/test_utils.rs +++ /dev/null @@ -1,17 +0,0 @@ -use std::net::SocketAddr; - -use tokio::net::TcpListener; - -/// Returns a unique IP address and port for testing purposes. -/// Tests run in parallel, so servers (like RPC or web) running on separate tests must have -/// different ports, otherwise the server will fail with "address already in use". -pub async fn get_available_socket() -> SocketAddr { - // Dynamically select port. - // First, set the port to 0 (dynamic port). - TcpListener::bind("127.0.0.1:0") - .await - .expect("Failed to bind to address") - // Then, resolve to the actual selected port. - .local_addr() - .expect("Failed to get local address") -} diff --git a/crates/starknet_sequencer_infra/src/tests/active_local_component_client_server_test.rs b/crates/starknet_sequencer_infra/src/tests/active_local_component_client_server_test.rs deleted file mode 100644 index 5f5d8f6951e..00000000000 --- a/crates/starknet_sequencer_infra/src/tests/active_local_component_client_server_test.rs +++ /dev/null @@ -1,190 +0,0 @@ -use std::future::pending; -use std::sync::Arc; - -use async_trait::async_trait; -use serde::{Deserialize, Serialize}; -use starknet_sequencer_infra::component_client::{ClientError, ClientResult, LocalComponentClient}; -use starknet_sequencer_infra::component_definitions::{ - ComponentRequestAndResponseSender, - ComponentRequestHandler, - ComponentStarter, -}; -use starknet_sequencer_infra::component_server::{ - ComponentServerStarter, - LocalActiveComponentServer, - WrapperServer, -}; -use starknet_sequencer_infra::errors::ComponentError; -use tokio::sync::mpsc::{channel, Sender}; -use tokio::sync::{Barrier, Mutex}; -use tokio::task; - -#[derive(Debug, Clone)] -struct ComponentC { - counter: Arc>, - max_iterations: usize, - barrier: Arc, -} - -impl ComponentC { - pub fn new(init_counter_value: usize, max_iterations: usize, barrier: Arc) -> Self { - Self { counter: Arc::new(Mutex::new(init_counter_value)), max_iterations, barrier } - } - - pub async fn c_get_counter(&self) -> usize { - *self.counter.lock().await - } - - pub async fn c_increment_counter(&self) { - *self.counter.lock().await += 1; - } -} - -#[async_trait] -impl ComponentStarter for ComponentC { - async fn start(&mut self) -> Result<(), ComponentError> { - for _ in 0..self.max_iterations { - self.c_increment_counter().await; - } - let val = self.c_get_counter().await; - assert!(val >= self.max_iterations); - self.barrier.wait().await; - - // Mimicking real start function that should not return. - let () = pending().await; - Ok(()) - } -} - -#[derive(Serialize, Deserialize, Debug)] -pub enum ComponentCRequest { - CIncCounter, - CGetCounter, -} - -#[derive(Serialize, Deserialize, Debug)] -pub enum ComponentCResponse { - CIncCounter, - CGetCounter(usize), -} - -#[async_trait] -trait ComponentCClientTrait: Send + Sync { - async fn c_inc_counter(&self) -> ClientResult<()>; - async fn c_get_counter(&self) -> ClientResult; -} - -struct ComponentD { - c: Box, - max_iterations: usize, - barrier: Arc, -} - -impl ComponentD { - pub fn new( - c: Box, - max_iterations: usize, - barrier: Arc, - ) -> Self { - Self { c, max_iterations, barrier } - } - - pub async fn d_increment_counter(&self) { - self.c.c_inc_counter().await.unwrap() - } - - pub async fn d_get_counter(&self) -> usize { - self.c.c_get_counter().await.unwrap() - } -} - -#[async_trait] -impl ComponentStarter for ComponentD { - async fn start(&mut self) -> Result<(), ComponentError> { - for _ in 0..self.max_iterations { - self.d_increment_counter().await; - } - let val = self.d_get_counter().await; - assert!(val >= self.max_iterations); - self.barrier.wait().await; - - // Mimicking real start function that should not return. - let () = pending().await; - Ok(()) - } -} - -#[async_trait] -impl ComponentCClientTrait for LocalComponentClient { - async fn c_inc_counter(&self) -> ClientResult<()> { - let res = self.send(ComponentCRequest::CIncCounter).await; - match res { - ComponentCResponse::CIncCounter => Ok(()), - _ => Err(ClientError::UnexpectedResponse("Unexpected Responce".to_string())), - } - } - - async fn c_get_counter(&self) -> ClientResult { - let res = self.send(ComponentCRequest::CGetCounter).await; - match res { - ComponentCResponse::CGetCounter(counter) => Ok(counter), - _ => Err(ClientError::UnexpectedResponse("Unexpected Responce".to_string())), - } - } -} - -#[async_trait] -impl ComponentRequestHandler for ComponentC { - async fn handle_request(&mut self, request: ComponentCRequest) -> ComponentCResponse { - match request { - ComponentCRequest::CGetCounter => { - ComponentCResponse::CGetCounter(self.c_get_counter().await) - } - ComponentCRequest::CIncCounter => { - self.c_increment_counter().await; - ComponentCResponse::CIncCounter - } - } - } -} - -async fn wait_and_verify_response( - tx_c: Sender>, - expected_counter_value: usize, - barrier: Arc, -) { - let c_client = LocalComponentClient::new(tx_c); - - barrier.wait().await; - assert_eq!(c_client.c_get_counter().await.unwrap(), expected_counter_value); -} - -#[tokio::test] -async fn test_setup_c_d() { - let init_counter_value: usize = 0; - let max_iterations: usize = 1024; - let expected_counter_value = max_iterations * 2; - - let (tx_c, rx_c) = - channel::>(32); - - let c_client = LocalComponentClient::new(tx_c.clone()); - - let barrier = Arc::new(Barrier::new(3)); - let component_c = ComponentC::new(init_counter_value, max_iterations, barrier.clone()); - let component_d = ComponentD::new(Box::new(c_client), max_iterations, barrier.clone()); - - let mut component_c_server = LocalActiveComponentServer::new(component_c, rx_c); - let mut component_d_server = WrapperServer::new(component_d); - - task::spawn(async move { - let _ = component_c_server.start().await; - }); - - task::spawn(async move { - let _ = component_d_server.start().await; - }); - - // Wait for the components to finish incrementing of the ComponentC::counter and verify it. - wait_and_verify_response(tx_c.clone(), expected_counter_value, barrier).await; -} diff --git a/crates/starknet_sequencer_infra/src/tests/concurrent_servers_test.rs b/crates/starknet_sequencer_infra/src/tests/concurrent_servers_test.rs new file mode 100644 index 00000000000..98fe946c180 --- /dev/null +++ b/crates/starknet_sequencer_infra/src/tests/concurrent_servers_test.rs @@ -0,0 +1,201 @@ +use std::fmt::Debug; +use std::sync::Arc; +use std::time::Duration; + +use async_trait::async_trait; +use serde::{Deserialize, Serialize}; +use tokio::sync::mpsc::channel; +use tokio::sync::Semaphore; +use tokio::task; +use tokio::time::timeout; + +use crate::component_client::{ClientResult, LocalComponentClient, RemoteComponentClient}; +use crate::component_definitions::{ + ComponentClient, + ComponentRequestAndResponseSender, + ComponentRequestHandler, + ComponentStarter, + RemoteClientConfig, +}; +use crate::component_server::{ + ComponentServerStarter, + ConcurrentLocalComponentServer, + RemoteComponentServer, +}; +use crate::tests::{AVAILABLE_PORTS, TEST_LOCAL_SERVER_METRICS, TEST_REMOTE_SERVER_METRICS}; + +type TestResult = ClientResult<()>; + +#[derive(Serialize, Deserialize, Debug)] +enum ConcurrentComponentRequest { + PerformAction(TestSemaphore), +} + +#[derive(Serialize, Deserialize, Debug)] +enum ConcurrentComponentResponse { + PerformAction, +} + +type LocalConcurrentComponentClient = + LocalComponentClient; +type RemoteConcurrentComponentClient = + RemoteComponentClient; + +#[async_trait] +trait ConcurrentComponentClientTrait: Send + Sync { + async fn perform_action(&self, field: TestSemaphore) -> TestResult; +} + +#[derive(Clone)] +struct ConcurrentComponent { + sem_a: Arc, + sem_b: Arc, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +enum TestSemaphore { + A, + B, +} + +async fn perform_semaphore_operations(sem_a: &Semaphore, sem_b: &Semaphore) { + sem_a.add_permits(1); + let _ = sem_b.acquire().await.unwrap(); +} + +impl ConcurrentComponent { + pub fn new() -> Self { + Self { sem_a: Arc::new(Semaphore::new(0)), sem_b: Arc::new(Semaphore::new(0)) } + } + + pub async fn perform_test(&self, field: TestSemaphore) { + match field { + TestSemaphore::A => perform_semaphore_operations(&self.sem_a, &self.sem_b).await, + TestSemaphore::B => perform_semaphore_operations(&self.sem_b, &self.sem_a).await, + }; + } +} + +impl ComponentStarter for ConcurrentComponent {} + +#[async_trait] +impl ComponentRequestHandler + for ConcurrentComponent +{ + async fn handle_request( + &mut self, + request: ConcurrentComponentRequest, + ) -> ConcurrentComponentResponse { + match request { + ConcurrentComponentRequest::PerformAction(field) => { + self.perform_test(field).await; + ConcurrentComponentResponse::PerformAction + } + } + } +} + +#[async_trait] +impl ConcurrentComponentClientTrait for ComponentClientType +where + ComponentClientType: + Send + Sync + ComponentClient, +{ + async fn perform_action(&self, field: TestSemaphore) -> TestResult { + match self.send(ConcurrentComponentRequest::PerformAction(field)).await? { + ConcurrentComponentResponse::PerformAction => Ok(()), + } + } +} + +async fn setup_concurrent_local_test() -> LocalConcurrentComponentClient { + let component = ConcurrentComponent::new(); + + let (tx_a, rx_a) = channel::< + ComponentRequestAndResponseSender, + >(32); + + let local_client = LocalConcurrentComponentClient::new(tx_a); + + let max_concurrency = 10; + let mut concurrent_local_server = ConcurrentLocalComponentServer::new( + component, + rx_a, + max_concurrency, + TEST_LOCAL_SERVER_METRICS, + ); + task::spawn(async move { + let _ = concurrent_local_server.start().await; + }); + + local_client +} + +async fn setup_concurrent_remote_test() -> RemoteConcurrentComponentClient { + let local_client = setup_concurrent_local_test().await; + let socket = AVAILABLE_PORTS.lock().await.get_next_local_host_socket(); + let config = RemoteClientConfig::default(); + + let max_concurrency = 10; + let mut concurrent_remote_server = RemoteComponentServer::new( + local_client.clone(), + socket.ip(), + socket.port(), + max_concurrency, + TEST_REMOTE_SERVER_METRICS, + ); + task::spawn(async move { + let _ = concurrent_remote_server.start().await; + }); + RemoteConcurrentComponentClient::new(config, &socket.ip().to_string(), socket.port()) +} + +async fn test_server( + client: Box, + field: TestSemaphore, + number_of_iterations: usize, +) { + for _ in 0..number_of_iterations { + client.perform_action(field.clone()).await.unwrap(); + } +} + +async fn perform_concurrency_test( + client_1: Box, + client_2: Box, +) { + let number_of_iterations = 10; + let test_task_1_handle = + task::spawn( + async move { test_server(client_1, TestSemaphore::A, number_of_iterations).await }, + ); + + let test_task_2_handle = + task::spawn( + async move { test_server(client_2, TestSemaphore::B, number_of_iterations).await }, + ); + + let timeout_duration = Duration::from_millis(100); + assert!( + timeout(timeout_duration, async { + tokio::try_join!(test_task_1_handle, test_task_2_handle).unwrap(); + }) + .await + .is_ok(), + "Test timed out" + ); +} + +#[tokio::test] +async fn local_concurrent_server() { + let client = setup_concurrent_local_test().await; + + perform_concurrency_test(Box::new(client.clone()), Box::new(client)).await; +} + +#[tokio::test] +async fn remote_server_concurrency() { + let client = setup_concurrent_remote_test().await; + + perform_concurrency_test(Box::new(client.clone()), Box::new(client)).await; +} diff --git a/crates/starknet_sequencer_infra/src/tests/local_component_client_server_test.rs b/crates/starknet_sequencer_infra/src/tests/local_component_client_server_test.rs index f3698677962..5981a3f8d7a 100644 --- a/crates/starknet_sequencer_infra/src/tests/local_component_client_server_test.rs +++ b/crates/starknet_sequencer_infra/src/tests/local_component_client_server_test.rs @@ -20,6 +20,7 @@ use crate::tests::{ ResultB, ValueA, ValueB, + TEST_LOCAL_SERVER_METRICS, }; type ComponentAClient = LocalComponentClient; @@ -59,7 +60,7 @@ impl ComponentBClientTrait for LocalComponentClient; pub(crate) type ResultB = ClientResult; +// Define mock local server metrics. +const TEST_MSGS_RECEIVED: MetricCounter = MetricCounter::new( + MetricScope::Infra, + "test_msgs_received", + "Test messages received counter", + 0, +); + +const TEST_MSGS_PROCESSED: MetricCounter = MetricCounter::new( + MetricScope::Infra, + "test_msgs_processed", + "Test messages processed counter", + 0, +); + +const TEST_QUEUE_DEPTH: MetricGauge = + MetricGauge::new(MetricScope::Infra, "queue_queue_depth", "Test channel queue depth gauge"); + +pub(crate) const TEST_LOCAL_SERVER_METRICS: LocalServerMetrics = + LocalServerMetrics::new(&TEST_MSGS_RECEIVED, &TEST_MSGS_PROCESSED, &TEST_QUEUE_DEPTH); + +const REMOTE_TEST_MSGS_RECEIVED: MetricCounter = MetricCounter::new( + MetricScope::Infra, + "remote_test_msgs_received", + "Remote test messages received counter", + 0, +); + +const REMOTE_VALID_TEST_MSGS_RECEIVED: MetricCounter = MetricCounter::new( + MetricScope::Infra, + "remote_valid_test_msgs_received", + "Valid remote test messages received counter", + 0, +); + +const REMOTE_TEST_MSGS_PROCESSED: MetricCounter = MetricCounter::new( + MetricScope::Infra, + "remote_test_msgs_processed", + "Remote test messages processed counter", + 0, +); + +pub(crate) const TEST_REMOTE_SERVER_METRICS: RemoteServerMetrics = RemoteServerMetrics::new( + &REMOTE_TEST_MSGS_RECEIVED, + &REMOTE_VALID_TEST_MSGS_RECEIVED, + &REMOTE_TEST_MSGS_PROCESSED, +); + +// Define the shared fixture +pub static AVAILABLE_PORTS: Lazy>> = Lazy::new(|| { + let available_ports = AvailablePorts::new(TestIdentifier::InfraUnitTests.into(), 0); + Arc::new(Mutex::new(available_ports)) +}); + #[derive(Serialize, Deserialize, Debug)] pub enum ComponentARequest { AGetValue, diff --git a/crates/starknet_sequencer_infra/src/tests/remote_component_client_server_test.rs b/crates/starknet_sequencer_infra/src/tests/remote_component_client_server_test.rs index ba6c1c884f7..48d6387bdd7 100644 --- a/crates/starknet_sequencer_infra/src/tests/remote_component_client_server_test.rs +++ b/crates/starknet_sequencer_infra/src/tests/remote_component_client_server_test.rs @@ -25,7 +25,6 @@ use crate::component_definitions::{ ComponentClient, ComponentRequestAndResponseSender, RemoteClientConfig, - RemoteServerConfig, ServerError, APPLICATION_OCTET_STREAM, }; @@ -34,8 +33,7 @@ use crate::component_server::{ LocalComponentServer, RemoteComponentServer, }; -use crate::serde_utils::BincodeSerdeWrapper; -use crate::test_utils::get_available_socket; +use crate::serde_utils::SerdeWrapper; use crate::tests::{ test_a_b_functionality, ComponentA, @@ -50,6 +48,9 @@ use crate::tests::{ ResultB, ValueA, ValueB, + AVAILABLE_PORTS, + TEST_LOCAL_SERVER_METRICS, + TEST_REMOTE_SERVER_METRICS, }; type ComponentAClient = RemoteComponentClient; @@ -117,18 +118,18 @@ async fn create_client_and_faulty_server(body: T) -> ComponentAClient where T: Serialize + DeserializeOwned + Debug + Send + Sync + 'static + Clone, { - let socket = get_available_socket().await; + let socket = AVAILABLE_PORTS.lock().await.get_next_local_host_socket(); task::spawn(async move { async fn handler( _http_request: Request, body: T, ) -> Result, hyper::Error> where - T: Serialize + DeserializeOwned + Debug + Send + Sync + Clone, + T: Serialize + DeserializeOwned + Debug, { Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(BincodeSerdeWrapper::new(body).to_bincode().unwrap())) + .body(Body::from(SerdeWrapper::new(body).wrapper_serialize().unwrap())) .unwrap()) } @@ -143,16 +144,18 @@ where // Ensure the server starts running. task::yield_now().await; - let config = RemoteClientConfig { socket, ..Default::default() }; - ComponentAClient::new(config) + let config = RemoteClientConfig::default(); + ComponentAClient::new(config, &socket.ip().to_string(), socket.port()) } async fn setup_for_tests(setup_value: ValueB, a_socket: SocketAddr, b_socket: SocketAddr) { - let a_config = RemoteClientConfig { socket: a_socket, ..Default::default() }; - let b_config = RemoteClientConfig { socket: b_socket, ..Default::default() }; + let a_config = RemoteClientConfig::default(); + let b_config = RemoteClientConfig::default(); - let a_remote_client = ComponentAClient::new(a_config); - let b_remote_client = ComponentBClient::new(b_config); + let a_remote_client = + ComponentAClient::new(a_config, &a_socket.ip().to_string(), a_socket.port()); + let b_remote_client = + ComponentBClient::new(b_config, &b_socket.ip().to_string(), b_socket.port()); let component_a = ComponentA::new(Box::new(b_remote_client)); let component_b = ComponentB::new(setup_value, Box::new(a_remote_client.clone())); @@ -165,13 +168,26 @@ async fn setup_for_tests(setup_value: ValueB, a_socket: SocketAddr, b_socket: So let a_local_client = LocalComponentClient::::new(tx_a); let b_local_client = LocalComponentClient::::new(tx_b); - let mut component_a_local_server = LocalComponentServer::new(component_a, rx_a); - let mut component_b_local_server = LocalComponentServer::new(component_b, rx_b); - - let mut component_a_remote_server = - RemoteComponentServer::new(a_local_client, RemoteServerConfig { socket: a_socket }); - let mut component_b_remote_server = - RemoteComponentServer::new(b_local_client, RemoteServerConfig { socket: b_socket }); + let mut component_a_local_server = + LocalComponentServer::new(component_a, rx_a, TEST_LOCAL_SERVER_METRICS); + let mut component_b_local_server = + LocalComponentServer::new(component_b, rx_b, TEST_LOCAL_SERVER_METRICS); + + let max_concurrency = 10; + let mut component_a_remote_server = RemoteComponentServer::new( + a_local_client, + a_socket.ip(), + a_socket.port(), + max_concurrency, + TEST_REMOTE_SERVER_METRICS, + ); + let mut component_b_remote_server = RemoteComponentServer::new( + b_local_client, + b_socket.ip(), + b_socket.port(), + max_concurrency, + TEST_REMOTE_SERVER_METRICS, + ); task::spawn(async move { let _ = component_a_local_server.start().await; @@ -193,24 +209,27 @@ async fn setup_for_tests(setup_value: ValueB, a_socket: SocketAddr, b_socket: So } #[tokio::test] -async fn test_proper_setup() { +async fn proper_setup() { let setup_value: ValueB = Felt::from(90); - let a_socket = get_available_socket().await; - let b_socket = get_available_socket().await; + let a_socket = AVAILABLE_PORTS.lock().await.get_next_local_host_socket(); + let b_socket = AVAILABLE_PORTS.lock().await.get_next_local_host_socket(); setup_for_tests(setup_value, a_socket, b_socket).await; - let a_client_config = RemoteClientConfig { socket: a_socket, ..Default::default() }; - let b_client_config = RemoteClientConfig { socket: b_socket, ..Default::default() }; + let a_client_config = RemoteClientConfig::default(); + let b_client_config = RemoteClientConfig::default(); + + let a_remote_client = + ComponentAClient::new(a_client_config, &a_socket.ip().to_string(), a_socket.port()); + let b_remote_client = + ComponentBClient::new(b_client_config, &b_socket.ip().to_string(), b_socket.port()); - let a_remote_client = ComponentAClient::new(a_client_config); - let b_remote_client = ComponentBClient::new(b_client_config); test_a_b_functionality(a_remote_client, b_remote_client, setup_value).await; } #[tokio::test] -async fn test_faulty_client_setup() { - let a_socket = get_available_socket().await; - let b_socket = get_available_socket().await; +async fn faulty_client_setup() { + let a_socket = AVAILABLE_PORTS.lock().await.get_next_local_host_socket(); + let b_socket = AVAILABLE_PORTS.lock().await.get_next_local_host_socket(); // Todo(uriel): Find a better way to pass expected value to the setup // 123 is some arbitrary value, we don't check it anyway. setup_for_tests(Felt::from(123), a_socket, b_socket).await; @@ -227,12 +246,12 @@ async fn test_faulty_client_setup() { format!("http://[{}]:{}/", self.socket.ip(), self.socket.port()).parse().unwrap(); let http_request = Request::post(uri) .header(CONTENT_TYPE, APPLICATION_OCTET_STREAM) - .body(Body::from(BincodeSerdeWrapper::new(component_request).to_bincode().unwrap())) + .body(Body::from(SerdeWrapper::new(component_request).wrapper_serialize().unwrap())) .unwrap(); let http_response = Client::new().request(http_request).await.unwrap(); let status_code = http_response.status(); let body_bytes = to_bytes(http_response.into_body()).await.unwrap(); - let response = BincodeSerdeWrapper::::from_bincode(&body_bytes).unwrap(); + let response = SerdeWrapper::::wrapper_deserialize(&body_bytes).unwrap(); Err(ClientError::ResponseError(status_code, response)) } } @@ -243,27 +262,28 @@ async fn test_faulty_client_setup() { } #[tokio::test] -async fn test_unconnected_server() { - let socket = get_available_socket().await; - let client_config = RemoteClientConfig { socket, ..Default::default() }; - let client = ComponentAClient::new(client_config); +async fn unconnected_server() { + let socket = AVAILABLE_PORTS.lock().await.get_next_local_host_socket(); + let client_config = RemoteClientConfig::default(); + let client = ComponentAClient::new(client_config, &socket.ip().to_string(), socket.port()); let expected_error_contained_keywords = ["Connection refused"]; verify_error(client, &expected_error_contained_keywords).await; } +// TODO(Nadin): add DESERIALIZE_REQ_ERROR_MESSAGE to the expected error keywords in the first case. #[rstest] #[case::request_deserialization_failure( create_client_and_faulty_server( ServerError::RequestDeserializationFailure(MOCK_SERVER_ERROR.to_string()) ).await, - &[StatusCode::BAD_REQUEST.as_str(),DESERIALIZE_REQ_ERROR_MESSAGE, MOCK_SERVER_ERROR], + &[StatusCode::BAD_REQUEST.as_str()], )] #[case::response_deserialization_failure( create_client_and_faulty_server(ARBITRARY_DATA.to_string()).await, &[DESERIALIZE_RES_ERROR_MESSAGE], )] #[tokio::test] -async fn test_faulty_server( +async fn faulty_server( #[case] client: ComponentAClient, #[case] expected_error_contained_keywords: &[&str], ) { @@ -271,8 +291,8 @@ async fn test_faulty_server( } #[tokio::test] -async fn test_retry_request() { - let socket = get_available_socket().await; +async fn retry_request() { + let socket = AVAILABLE_PORTS.lock().await.get_next_local_host_socket(); // Spawn a server that responses with OK every other request. task::spawn(async move { let should_send_ok = Arc::new(Mutex::new(false)); @@ -285,12 +305,12 @@ async fn test_retry_request() { let ret = if *should_send_ok { Response::builder() .status(StatusCode::OK) - .body(Body::from(BincodeSerdeWrapper::new(body).to_bincode().unwrap())) + .body(Body::from(SerdeWrapper::new(body).wrapper_serialize().unwrap())) .unwrap() } else { Response::builder() .status(StatusCode::IM_A_TEAPOT) - .body(Body::from(BincodeSerdeWrapper::new(body).to_bincode().unwrap())) + .body(Body::from(SerdeWrapper::new(body).wrapper_serialize().unwrap())) .unwrap() }; *should_send_ok = !*should_send_ok; @@ -315,22 +335,24 @@ async fn test_retry_request() { // sets the server state to 'true'. The second attempt (first retry) therefore returns a // 'success', while setting the server state to 'false' yet again. let retry_config = RemoteClientConfig { - socket, retries: 1, idle_connections: MAX_IDLE_CONNECTION, idle_timeout: IDLE_TIMEOUT, + ..Default::default() }; - let a_client_retry = ComponentAClient::new(retry_config); + let a_client_retry = + ComponentAClient::new(retry_config, &socket.ip().to_string(), socket.port()); assert_eq!(a_client_retry.a_get_value().await.unwrap(), VALID_VALUE_A); // The current server state is 'false', hence the first and only attempt returns an error. let no_retry_config = RemoteClientConfig { - socket, retries: 0, idle_connections: MAX_IDLE_CONNECTION, idle_timeout: IDLE_TIMEOUT, + ..Default::default() }; - let a_client_no_retry = ComponentAClient::new(no_retry_config); + let a_client_no_retry = + ComponentAClient::new(no_retry_config, &socket.ip().to_string(), socket.port()); let expected_error_contained_keywords = [StatusCode::IM_A_TEAPOT.as_str()]; verify_error(a_client_no_retry.clone(), &expected_error_contained_keywords).await; } diff --git a/crates/starknet_sequencer_infra/src/tests/server_metrics_test.rs b/crates/starknet_sequencer_infra/src/tests/server_metrics_test.rs new file mode 100644 index 00000000000..adee27e7a17 --- /dev/null +++ b/crates/starknet_sequencer_infra/src/tests/server_metrics_test.rs @@ -0,0 +1,402 @@ +use std::cmp::min; +use std::convert::TryInto; +use std::fmt::Debug; +use std::sync::Arc; + +use async_trait::async_trait; +use metrics::set_default_local_recorder; +use metrics_exporter_prometheus::PrometheusBuilder; +use serde::{Deserialize, Serialize}; +use tokio::sync::mpsc::{channel, Receiver}; +use tokio::sync::Semaphore; +use tokio::task::{self, JoinSet}; + +use crate::component_client::{ClientResult, LocalComponentClient, RemoteComponentClient}; +use crate::component_definitions::{ + ComponentClient, + ComponentRequestAndResponseSender, + ComponentRequestHandler, + ComponentStarter, + RemoteClientConfig, +}; +use crate::component_server::{ + ComponentServerStarter, + ConcurrentLocalComponentServer, + LocalComponentServer, + RemoteComponentServer, +}; +use crate::tests::{AVAILABLE_PORTS, TEST_LOCAL_SERVER_METRICS, TEST_REMOTE_SERVER_METRICS}; + +type TestResult = ClientResult<()>; + +const NUMBER_OF_ITERATIONS: usize = 10; + +#[derive(Serialize, Deserialize, Debug)] +enum TestComponentRequest { + PerformTest, +} + +#[derive(Serialize, Deserialize, Debug)] +enum TestComponentResponse { + PerformTest, +} + +type LocalTestComponentClient = LocalComponentClient; +type RemoteTestComponentClient = RemoteComponentClient; + +type TestReceiver = + Receiver>; + +#[async_trait] +trait TestComponentClientTrait: Send + Sync { + async fn perform_test(&self) -> TestResult; +} + +#[derive(Clone)] +struct TestComponent { + test_sem: Arc, +} + +impl TestComponent { + pub fn new(test_sem: Arc) -> Self { + Self { test_sem } + } + + pub async fn reduce_permit(&self) { + self.test_sem.acquire().await.unwrap().forget(); + } +} + +impl ComponentStarter for TestComponent {} + +#[async_trait] +impl ComponentRequestHandler for TestComponent { + async fn handle_request(&mut self, request: TestComponentRequest) -> TestComponentResponse { + match request { + TestComponentRequest::PerformTest => { + self.reduce_permit().await; + TestComponentResponse::PerformTest + } + } + } +} + +#[async_trait] +impl TestComponentClientTrait for ComponentClientType +where + ComponentClientType: Send + Sync + ComponentClient, +{ + async fn perform_test(&self) -> TestResult { + match self.send(TestComponentRequest::PerformTest).await? { + TestComponentResponse::PerformTest => Ok(()), + } + } +} + +struct BasicSetup { + component: TestComponent, + local_client: LocalTestComponentClient, + rx: TestReceiver, + test_sem: Arc, +} + +fn basic_test_setup() -> BasicSetup { + let test_sem = Arc::new(Semaphore::new(0)); + let component = TestComponent::new(test_sem.clone()); + + let (tx, rx) = channel::< + ComponentRequestAndResponseSender, + >(32); + + let local_client = LocalTestComponentClient::new(tx); + + BasicSetup { component, local_client, rx, test_sem } +} + +async fn setup_local_server_test() -> (Arc, LocalTestComponentClient) { + let BasicSetup { component, local_client, rx, test_sem } = basic_test_setup(); + + let mut local_server = LocalComponentServer::new(component, rx, TEST_LOCAL_SERVER_METRICS); + task::spawn(async move { + let _ = local_server.start().await; + }); + + (test_sem, local_client) +} + +async fn setup_concurrent_local_server_test( + max_concurrency: usize, +) -> (Arc, LocalTestComponentClient) { + let BasicSetup { component, local_client, rx, test_sem } = basic_test_setup(); + + let mut concurrent_local_server = ConcurrentLocalComponentServer::new( + component, + rx, + max_concurrency, + TEST_LOCAL_SERVER_METRICS, + ); + task::spawn(async move { + let _ = concurrent_local_server.start().await; + }); + + (test_sem, local_client) +} + +async fn setup_remote_server_test( + max_concurrency: usize, +) -> (Arc, RemoteTestComponentClient) { + let (test_sem, local_client) = setup_local_server_test().await; + let socket = AVAILABLE_PORTS.lock().await.get_next_local_host_socket(); + let config = RemoteClientConfig::default(); + + let mut remote_server = RemoteComponentServer::new( + local_client.clone(), + socket.ip(), + socket.port(), + max_concurrency, + TEST_REMOTE_SERVER_METRICS, + ); + task::spawn(async move { + let _ = remote_server.start().await; + }); + let remote_client = + RemoteTestComponentClient::new(config, &socket.ip().to_string(), socket.port()); + + (test_sem, remote_client) +} + +fn usize_to_u64(value: usize) -> u64 { + value.try_into().expect("Conversion failed") +} + +fn assert_server_metrics( + metrics_as_string: &str, + expected_received_msgs: usize, + expected_processed_msgs: usize, + expected_queue_depth: usize, +) { + let received_msgs = TEST_LOCAL_SERVER_METRICS.get_received_value(metrics_as_string); + let processed_msgs = TEST_LOCAL_SERVER_METRICS.get_processed_value(metrics_as_string); + let queue_depth = TEST_LOCAL_SERVER_METRICS.get_queue_depth_value(metrics_as_string); + + assert_eq!( + received_msgs, + usize_to_u64(expected_received_msgs), + "unexpected value for receives_msgs_started counter, expected {} got {:?}", + expected_received_msgs, + received_msgs, + ); + assert_eq!( + processed_msgs, + usize_to_u64(expected_processed_msgs), + "unexpected value for processed_msgs counter, expected {} got {:?}", + expected_processed_msgs, + processed_msgs, + ); + assert_eq!( + queue_depth, expected_queue_depth, + "unexpected value for queue_depth, expected {} got {:?}", + expected_queue_depth, queue_depth, + ); +} + +fn assert_remote_server_metrics( + metrics_as_string: &str, + expected_total_received_msgs: usize, + expected_valid_received_msgs: usize, + expected_processed_msgs: usize, +) { + let total_received_msgs = + TEST_REMOTE_SERVER_METRICS.get_total_received_value(metrics_as_string); + let valid_received_msgs = + TEST_REMOTE_SERVER_METRICS.get_valid_received_value(metrics_as_string); + let processed_msgs = TEST_REMOTE_SERVER_METRICS.get_processed_value(metrics_as_string); + + assert_eq!( + total_received_msgs, + usize_to_u64(expected_total_received_msgs), + "unexpected value for total_receives_msgs_started counter, expected {} got {:?}", + expected_total_received_msgs, + total_received_msgs, + ); + assert_eq!( + valid_received_msgs, + usize_to_u64(expected_valid_received_msgs), + "unexpected value for valid_receives_msgs_started counter, expected {} got {:?}", + expected_total_received_msgs, + valid_received_msgs, + ); + assert_eq!( + processed_msgs, + usize_to_u64(expected_processed_msgs), + "unexpected value for processed_msgs counter, expected {} got {:?}", + expected_processed_msgs, + processed_msgs, + ); +} + +#[tokio::test] +async fn only_metrics_counters_for_local_server() { + let recorder = PrometheusBuilder::new().build_recorder(); + let _recorder_guard = set_default_local_recorder(&recorder); + + let (test_sem, client) = setup_local_server_test().await; + + // At the beginning all metrics counters are zero. + let metrics_as_string = recorder.handle().render(); + assert_server_metrics(metrics_as_string.as_str(), 0, 0, 0); + + // In order to process a message the test component tries to acquire a permit from the + // test semaphore. Current test is checking that all metrics counters actually count so we + // need to provide enough permits for all messages to be processed. + test_sem.add_permits(NUMBER_OF_ITERATIONS); + for i in 0..NUMBER_OF_ITERATIONS { + client.perform_test().await.unwrap(); + + // Every time the request is sent and the response is received the metrics counters should + // be increased by one. + let metrics_as_string = recorder.handle().render(); + assert_server_metrics(metrics_as_string.as_str(), i + 1, i + 1, 0); + } +} + +#[tokio::test] +async fn all_metrics_for_local_server() { + let recorder = PrometheusBuilder::new().build_recorder(); + let _recorder_guard = set_default_local_recorder(&recorder); + + let (test_sem, client) = setup_local_server_test().await; + + // In order to test not only message counters but the queue depth too, first we will send all + // the messages by spawning multiple clients and by that filling the channel queue. + for _ in 0..NUMBER_OF_ITERATIONS { + let multi_client = client.clone(); + task::spawn(async move { + multi_client.perform_test().await.unwrap(); + }); + } + task::yield_now().await; + + // And then we will provide a single permit each time and check that all metrics are adjusted + // accordingly. + for i in 0..NUMBER_OF_ITERATIONS { + let metrics_as_string = recorder.handle().render(); + // After sending i permits we should have i + 1 received messages, because the first message + // doesn't need a permit to be received but need a permit to be processed. + // So we will have only i processed messages. + // And the queue depth should be: NUMBER_OF_ITERATIONS - number of received messages. + assert_server_metrics(metrics_as_string.as_str(), i + 1, i, NUMBER_OF_ITERATIONS - i - 1); + test_sem.add_permits(1); + task::yield_now().await; + } + + // Finally all messages processed and queue is empty. + let metrics_as_string = recorder.handle().render(); + assert_server_metrics( + metrics_as_string.as_str(), + NUMBER_OF_ITERATIONS, + NUMBER_OF_ITERATIONS, + 0, + ); +} + +#[tokio::test] +async fn only_metrics_counters_for_concurrent_server() { + let recorder = PrometheusBuilder::new().build_recorder(); + let _recorder_guard = set_default_local_recorder(&recorder); + + let max_concurrency = NUMBER_OF_ITERATIONS; + let (test_sem, client) = setup_concurrent_local_server_test(max_concurrency).await; + + // Current test is checking that all metrics counters can actually count in parallel. + // So first we send all the messages. + let mut tasks = JoinSet::new(); + for _ in 0..NUMBER_OF_ITERATIONS { + let multi_client = client.clone(); + tasks.spawn(async move { + multi_client.perform_test().await.unwrap(); + }); + } + task::yield_now().await; + + // By now all messages should be received but not processed. + let metrics_as_string = recorder.handle().render(); + assert_server_metrics(metrics_as_string.as_str(), NUMBER_OF_ITERATIONS, 0, 0); + + // Now we provide all permits and wait for all messages to be processed. + test_sem.add_permits(NUMBER_OF_ITERATIONS); + tasks.join_all().await; + + // Finally all messages processed and queue is empty. + let metrics_as_string = recorder.handle().render(); + assert_server_metrics( + metrics_as_string.as_str(), + NUMBER_OF_ITERATIONS, + NUMBER_OF_ITERATIONS, + 0, + ); +} + +#[tokio::test] +async fn all_metrics_for_concurrent_server() { + let recorder = PrometheusBuilder::new().build_recorder(); + let _recorder_guard = set_default_local_recorder(&recorder); + + let max_concurrency = NUMBER_OF_ITERATIONS / 2; + let (test_sem, client) = setup_concurrent_local_server_test(max_concurrency).await; + + // Current test is checking not only message counters but the queue depth too. + // So first we send all the messages. + for _ in 0..NUMBER_OF_ITERATIONS { + let multi_client = client.clone(); + task::spawn(async move { + multi_client.perform_test().await.unwrap(); + }); + } + task::yield_now().await; + + for i in 0..NUMBER_OF_ITERATIONS { + // After sending i permits, we should have 'max_concurrency + i + 1' received messages, + // up to a maximum of NUMBER_OF_ITERATIONS. + let expected_received_msgs = min(max_concurrency + 1 + i, NUMBER_OF_ITERATIONS); + + // The queue depth should be: 'NUMBER_OF_ITERATIONS - number of received messages'. + let expected_queue_depth = NUMBER_OF_ITERATIONS - expected_received_msgs; + + let metrics_as_string = recorder.handle().render(); + assert_server_metrics( + metrics_as_string.as_str(), + expected_received_msgs, + i, + expected_queue_depth, + ); + test_sem.add_permits(1); + task::yield_now().await; + } +} + +#[tokio::test] +async fn metrics_counters_for_remote_server() { + let recorder = PrometheusBuilder::new().build_recorder(); + let _recorder_guard = set_default_local_recorder(&recorder); + + let max_concurrency = NUMBER_OF_ITERATIONS; + let (test_sem, remote_client) = setup_remote_server_test(max_concurrency).await; + + // At the beginning all metrics counters are zero. + let metrics_as_string = recorder.handle().render(); + assert_server_metrics(metrics_as_string.as_str(), 0, 0, 0); + + // In order to process a message the test component tries to acquire a permit from the + // test semaphore. Current test is checking that all metrics counters actually count so we + // need to provide enough permits for all messages to be processed. + test_sem.add_permits(NUMBER_OF_ITERATIONS); + for i in 0..NUMBER_OF_ITERATIONS { + remote_client.perform_test().await.unwrap(); + + // Every time the request is sent and the response is received the metrics counters should + // be increased by one. + let metrics_as_string = recorder.handle().render(); + assert_remote_server_metrics(metrics_as_string.as_str(), i + 1, i + 1, i + 1); + } +} diff --git a/crates/starknet_sequencer_infra/src/trace_util.rs b/crates/starknet_sequencer_infra/src/trace_util.rs index 6506402b98c..7eb094bb53f 100644 --- a/crates/starknet_sequencer_infra/src/trace_util.rs +++ b/crates/starknet_sequencer_infra/src/trace_util.rs @@ -1,15 +1,68 @@ +use tokio::sync::OnceCell; use tracing::metadata::LevelFilter; use tracing_subscriber::prelude::*; use tracing_subscriber::{fmt, EnvFilter}; const DEFAULT_LEVEL: LevelFilter = LevelFilter::INFO; +// Define a OnceCell to ensure the configuration is initialized only once +static TRACING_INITIALIZED: OnceCell<()> = OnceCell::const_new(); -pub fn configure_tracing() { - let fmt_layer = fmt::layer().compact().with_target(true); - let level_filter_layer = - EnvFilter::builder().with_default_directive(DEFAULT_LEVEL.into()).from_env_lossy(); +pub static PID: std::sync::LazyLock = std::sync::LazyLock::new(std::process::id); - // This sets a single subscriber to all of the threads. We may want to implement different - // subscriber for some threads and use set_global_default instead of init. - tracing_subscriber::registry().with(fmt_layer).with(level_filter_layer).init(); +pub async fn configure_tracing() { + TRACING_INITIALIZED + .get_or_init(|| async { + let fmt_layer = fmt::layer().compact().with_target(true); + let level_filter_layer = + EnvFilter::builder().with_default_directive(DEFAULT_LEVEL.into()).from_env_lossy(); + + // This sets a single subscriber to all of the threads. We may want to implement + // different subscriber for some threads and use set_global_default instead + // of init. + tracing_subscriber::registry().with(fmt_layer).with(level_filter_layer).init(); + tracing::info!("Tracing has been successfully initialized."); + }) + .await; +} + +#[macro_export] +macro_rules! infra_event { + ($($arg:tt)*) => {{ + tracing::event!(PID = *$crate::trace_util::PID, $($arg)*); + }}; +} + +#[macro_export] +macro_rules! infra_trace { + ($($arg:tt)*) => {{ + tracing::trace!(PID = *$crate::trace_util::PID, $($arg)*); + }}; +} + +#[macro_export] +macro_rules! infra_debug { + ($($arg:tt)*) => {{ + tracing::debug!(PID = *$crate::trace_util::PID, $($arg)*); + }}; +} + +#[macro_export] +macro_rules! infra_info { + ($($arg:tt)*) => {{ + tracing::info!(PID = *$crate::trace_util::PID, $($arg)*); + }}; +} + +#[macro_export] +macro_rules! infra_warn { + ($($arg:tt)*) => {{ + tracing::warn!(PID = *$crate::trace_util::PID, $($arg)*); + }}; +} + +#[macro_export] +macro_rules! infra_error { + ($($arg:tt)*) => {{ + tracing::error!(PID = *$crate::trace_util::PID, $($arg)*); + }}; } diff --git a/crates/starknet_sequencer_metrics/Cargo.toml b/crates/starknet_sequencer_metrics/Cargo.toml new file mode 100644 index 00000000000..db7f526af10 --- /dev/null +++ b/crates/starknet_sequencer_metrics/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "starknet_sequencer_metrics" +version.workspace = true +edition.workspace = true +repository.workspace = true +license.workspace = true + + +[features] +testing = [] + +[lints] +workspace = true + +[dependencies] +indexmap.workspace = true +metrics.workspace = true +num-traits.workspace = true +paste.workspace = true +regex.workspace = true + +[dev-dependencies] +metrics-exporter-prometheus.workspace = true +rstest.workspace = true +strum.workspace = true +strum_macros.workspace = true diff --git a/crates/starknet_sequencer_metrics/src/label_utils.rs b/crates/starknet_sequencer_metrics/src/label_utils.rs new file mode 100644 index 00000000000..14caced0b89 --- /dev/null +++ b/crates/starknet_sequencer_metrics/src/label_utils.rs @@ -0,0 +1,228 @@ +/// Macro to generate a compile-time constant array containing all permutations +/// of multiple enums. +/// +/// This macro: +/// - Accepts a list of tuples (`($name, $enum)`) where: +/// - `$name` is a string representing the key for the enum. +/// - `$enum` is an enum type that implements `strum::EnumVariantNames`. +/// - Computes **all possible permutations** of the provided enums at **compile-time**. +/// - Generates a uniquely named constant in the format ``. +/// +/// # Example +/// ```rust, ignore +/// #[derive(strum::EnumVariantNames)] +/// enum Color { +/// Red, +/// Green, +/// Blue, +/// } +/// +/// #[derive(strum::EnumVariantNames)] +/// enum Size { +/// Small, +/// Medium, +/// Large, +/// } +/// +/// generate_permutations!( +/// ("color", Color), +/// ("size", Size), +/// ); +/// ``` +/// +/// # Output +/// ```text +/// [("color", "Red"), ("size", "Small")] +/// [("color", "Red"), ("size", "Medium")] +/// [("color", "Red"), ("size", "Large")] +/// [("color", "Green"), ("size", "Small")] +/// [("color", "Green"), ("size", "Medium")] +/// [("color", "Green"), ("size", "Large")] +/// [("color", "Blue"), ("size", "Small")] +/// [("color", "Blue"), ("size", "Medium")] +/// [("color", "Blue"), ("size", "Large")] +/// ``` +#[macro_export] +macro_rules! generate_permutations { + ($const_name:ident, $(($name:expr, $enum:ty)),* $(,)?) => { + $crate::paste::paste! { + // The generated constant containing all permutations. + pub const $const_name: [[(&'static str, &'static str); { + // Compute the number of enums being used in the permutations. + [$($enum::VARIANTS.len()),*].len() + }]; { + // Compute the total number of permutations. + let mut total_size = 1; + $( total_size *= $enum::VARIANTS.len(); )* + total_size + }] = { + /// An array holding references to the variant names of each enum. + const ENUM_VARIANTS: [&'static [&'static str]; { + [$($enum::VARIANTS.len()),*].len() + }] = [ + $($enum::VARIANTS),* + ]; + + /// A constant representing the total number of permutations. + const TOTAL_SIZE: usize = { + let mut product = 1; + $( product *= $enum::VARIANTS.len(); )* + product + }; + + /// A compile-time function to generate all permutations. + /// + /// # Arguments + /// * `variants` - A reference to an array of slices, where each slice contains the variants of an enum. + /// * `names` - A reference to an array of enum names. + /// + /// # Returns + /// A 2D array where each row represents a unique combination of variant names across the provided enums. + const fn expand( + variants: [&'static [&'static str]; N], + names: [&'static str; N] + ) -> [[(&'static str, &'static str); N]; TOTAL_SIZE] { + // The output array containing all possible variant name combinations. + let mut results: [[(&'static str, &'static str); N]; TOTAL_SIZE] = + [[("", ""); N]; TOTAL_SIZE]; + + let mut index = 0; + let mut counters = [0; N]; + + // Iterate over all possible permutations. + while index < TOTAL_SIZE { + let mut row: [(&'static str, &'static str); N] = [("", ""); N]; + let mut i = 0; + + // Assign the correct variant name to each position in the row. + while i < N { + row[i] = (names[i], variants[i][counters[i]]); + i += 1; + } + + results[index] = row; + index += 1; + + // Carry propagation for multi-dimensional iteration. + let mut carry = true; + let mut j = 0; + + while j < N && carry { + counters[j] += 1; + if counters[j] < variants[j].len() { + carry = false; + } else { + counters[j] = 0; + } + j += 1; + } + } + + results + } + + // Calls `expand` to generate the final constant containing all permutations. + expand(ENUM_VARIANTS, [$($name),*]) + }; + } + }; +} + +/// A macro that converts a **fixed-size 2D array** into a **slice of references**. +/// +/// This allows the array to be used in contexts where a dynamically sized slice (`&[&[(&str, +/// &str)]]`) is required instead of a statically sized array. +/// +/// # Example Usage +/// ```rust, ignore +/// const INPUT: [[(&str, &str); 2]; 3] = [ +/// [("Color", "Red"), ("Size", "Small")], +/// [("Color", "Blue"), ("Size", "Medium")], +/// [("Color", "Green"), ("Size", "Large")], +/// ]; +/// +/// convert_array!(PERMUTATION_SLICE, INPUT); +/// ``` +/// +/// # Expected Output: +/// ```rust, ignore +/// const PERMUTATION_SLICE : &[&[(&str, &str)]] = &[ +/// [("Color", "Red"), ("Size", "Small")], +/// [("Color", "Blue"), ("Size", "Medium")], +/// [("Color", "Green"), ("Size", "Large")] +/// ] +/// ``` +#[macro_export] +macro_rules! convert_array { + ($name:ident, $input:expr) => { + // A **slice reference** to the converted input array. + // This allows the macro to return a dynamically sized slice + // instead of a fixed-size array. + pub const $name: &[&[(&str, &str)]] = { + // A compile-time function to convert a fixed-size array into a slice of references. + // + // # Arguments + // * `input` - A reference to a 2D array of string tuples. + // + // # Returns + // A reference to an array of slices, where each slice represents a row in the input. + const fn build_refs<'a, const M: usize, const N: usize>( + input: &'a [[(&'a str, &'a str); N]; M], + ) -> [&'a [(&'a str, &'a str)]; M] { + // An array to hold the references to each row in the input. + let mut refs: [&[(&str, &str)]; M] = [&input[0]; M]; + + let mut i = 0; + while i < M { + refs[i] = &input[i]; + i += 1; + } + refs + } + + // Returns a reference to the slice representation of the input array. + &build_refs(&$input) + }; + }; +} + +/// Macro to generate a permutation of enum variants and store them in a user-defined constant. +/// +/// This macro: +/// - Generates an intermediate constant `_PERMUTATIONS` of all permutations as an array. +/// - Generates a constant `` as a reference slice to the aforementioned. +/// +/// # Arguments +/// - `$const_name`: The base name used for both the intermediate and final constants. +/// - A list of `(LABEL_NAME, ENUM_TYPE)` pairs. +/// +/// # Example Usage +/// ```rust, ignore +/// generate_permutation_labels!( +/// CUSTOM_LABELS_CONST, +/// (LABEL_NAME_TX_TYPE, RpcTransactionLabelValue), +/// (LABEL_NAME_SOURCE, SourceLabelValue), +/// ); +/// ``` +/// +/// # Generated Constants +/// ```rust, ignore +/// pub const CUSTOM_LABELS_CONST_PERMUTATIONS: [[(&'static str, &'static str); N]; TOTAL_SIZE] = { ... }; +/// pub const CUSTOM_LABELS_CONST: &[&[(&'static str, &'static str)]] = { ... }; +/// ``` +#[macro_export] +macro_rules! generate_permutation_labels { + ($const_name:ident, $(($name:expr, $enum:ty)),* $(,)?) => { + $crate::paste::paste! { + // Define the intermediate permutations constant by calling `generate_permutations!`. + $crate::generate_permutations!([<$const_name _PERMUTATIONS>], $(($name, $enum)),*); + + // Convert the intermediate permutations into a reference slice using the provided name. + $crate::convert_array!($const_name, [<$const_name _PERMUTATIONS>]); + } + }; +} + +#[cfg(test)] +#[path = "label_utils_test.rs"] +mod label_utils_test; diff --git a/crates/starknet_sequencer_metrics/src/label_utils_test.rs b/crates/starknet_sequencer_metrics/src/label_utils_test.rs new file mode 100644 index 00000000000..dd24ef97492 --- /dev/null +++ b/crates/starknet_sequencer_metrics/src/label_utils_test.rs @@ -0,0 +1,53 @@ +use std::cmp::Eq; +use std::collections::HashSet; +use std::hash::Hash; + +use strum::VariantNames; +use strum_macros::EnumVariantNames; + +#[allow(dead_code)] +#[derive(Debug, EnumVariantNames, Clone, Copy)] +enum Color { + Red, + Green, + Blue, +} + +#[allow(dead_code)] +#[derive(Debug, EnumVariantNames, Clone, Copy)] +enum Size { + Small, + Medium, + Large, +} + +generate_permutation_labels!(COLOR_SIZE_LABELS, ("color", Color), ("size", Size),); + +fn are_slices_equal(a: &[T], b: &[T]) -> bool { + a.len() == b.len() + && a.iter().cloned().collect::>() == b.iter().cloned().collect::>() +} + +#[test] +fn generate_permutations() { + let expected_values: [[(&str, &str); 2]; 9] = [ + [("color", "Red"), ("size", "Small")], + [("color", "Red"), ("size", "Medium")], + [("color", "Red"), ("size", "Large")], + [("color", "Green"), ("size", "Small")], + [("color", "Green"), ("size", "Medium")], + [("color", "Green"), ("size", "Large")], + [("color", "Blue"), ("size", "Small")], + [("color", "Blue"), ("size", "Medium")], + [("color", "Blue"), ("size", "Large")], + ]; + + assert!(are_slices_equal(&COLOR_SIZE_LABELS_PERMUTATIONS, &expected_values), "Mismatch"); +} + +// Tests the generated constants are of the correct type by binding them to typed variables. +#[test] +fn generate_permutation_labels_types() { + let _temp: [[(&str, &str); 2]; 9] = COLOR_SIZE_LABELS_PERMUTATIONS; + let _temp: &[&[(&str, &str)]] = COLOR_SIZE_LABELS; +} diff --git a/crates/starknet_sequencer_metrics/src/lib.rs b/crates/starknet_sequencer_metrics/src/lib.rs new file mode 100644 index 00000000000..84feec03d39 --- /dev/null +++ b/crates/starknet_sequencer_metrics/src/lib.rs @@ -0,0 +1,6 @@ +pub mod label_utils; +pub mod metric_definitions; +pub mod metrics; + +// Its being exported here to be used in define_metrics macro. +pub use paste; diff --git a/crates/starknet_sequencer_metrics/src/metric_definitions.rs b/crates/starknet_sequencer_metrics/src/metric_definitions.rs new file mode 100644 index 00000000000..c751c78dc6b --- /dev/null +++ b/crates/starknet_sequencer_metrics/src/metric_definitions.rs @@ -0,0 +1,44 @@ +/// Macro to define all metric constants for specified scopes and store them in a collection. +/// This generates: +/// - Individual metric constant according to type: `MetricCounter`or `MetricGauge` or +/// `LabeledMetricCounter`. +/// - A const array `ALL_METRICS` containing all $keys of all the metrics constants. +#[macro_export] +macro_rules! define_metrics { + ( + $( + $scope:ident => { + $( + $type:ty { $name:ident, $key:expr, $desc:expr $(, init = $init:expr)? $(, labels = $labels:expr)? } + ),* + $(,)? + } + ),* + $(,)? + ) => { + $( + $( + $crate::paste::paste! { + pub const $name: $type = <$type>::new( + $crate::metrics::MetricScope::$scope, + $key, + $desc + $(, $init)? // Only expands if `init = ...` is provided + $(, $labels)? // Only expands if `labels = ...` is provided + ); + } + )* + )* + + $( + #[cfg(any(feature = "testing", test))] + $crate::paste::paste! { + pub const [<$scope:snake:upper _ALL_METRICS>]: &[&'static str] = &[ + $( + $key, + )* + ]; + } + )* + }; +} diff --git a/crates/starknet_sequencer_metrics/src/metrics.rs b/crates/starknet_sequencer_metrics/src/metrics.rs new file mode 100644 index 00000000000..1a3b05303e2 --- /dev/null +++ b/crates/starknet_sequencer_metrics/src/metrics.rs @@ -0,0 +1,601 @@ +use std::fmt::Debug; +use std::str::FromStr; +use std::sync::OnceLock; + +use indexmap::IndexMap; +use metrics::{ + counter, + describe_counter, + describe_gauge, + describe_histogram, + gauge, + histogram, + IntoF64, +}; +use num_traits::Num; +use regex::{escape, Regex}; + +#[cfg(test)] +#[path = "metrics_test.rs"] +mod metrics_tests; + +/// Global variable set by the main config to enable collecting profiling metrics. +pub static COLLECT_SEQUENCER_PROFILING_METRICS: OnceLock = OnceLock::new(); + +/// Relevant components for which metrics can be defined. +#[derive(Clone, Copy, Debug)] +pub enum MetricScope { + Batcher, + ClassManager, + Consensus, + Gateway, + HttpServer, + Infra, + Mempool, + MempoolP2p, + StateSync, + PapyrusSync, +} + +pub struct MetricCounter { + scope: MetricScope, + name: &'static str, + description: &'static str, + initial_value: u64, +} + +impl MetricCounter { + pub const fn new( + scope: MetricScope, + name: &'static str, + description: &'static str, + initial_value: u64, + ) -> Self { + Self { scope, name, description, initial_value } + } + + pub const fn get_name(&self) -> &'static str { + self.name + } + + pub const fn get_scope(&self) -> MetricScope { + self.scope + } + + pub const fn get_description(&self) -> &'static str { + self.description + } + + pub fn register(&self) { + counter!(self.name).absolute(self.initial_value); + describe_counter!(self.name, self.description); + } + + pub fn increment(&self, value: u64) { + counter!(self.name).increment(value); + } + + pub fn parse_numeric_metric(&self, metrics_as_string: &str) -> Option { + parse_numeric_metric::(metrics_as_string, self.get_name(), None) + } + + #[cfg(any(feature = "testing", test))] + pub fn assert_eq(&self, metrics_as_string: &str, expected_value: T) { + let metric_value = self.parse_numeric_metric::(metrics_as_string).unwrap(); + assert_eq!( + metric_value, + expected_value, + "Metric counter {} did not match the expected value. expected value: {:?}, metric \ + value: {:?}", + self.get_name(), + expected_value, + metric_value + ); + } +} + +pub struct LabeledMetricCounter { + scope: MetricScope, + name: &'static str, + description: &'static str, + initial_value: u64, + label_permutations: &'static [&'static [(&'static str, &'static str)]], +} + +impl LabeledMetricCounter { + pub const fn new( + scope: MetricScope, + name: &'static str, + description: &'static str, + initial_value: u64, + label_permutations: &'static [&'static [(&'static str, &'static str)]], + ) -> Self { + Self { scope, name, description, initial_value, label_permutations } + } + + pub const fn get_name(&self) -> &'static str { + self.name + } + + pub const fn get_scope(&self) -> MetricScope { + self.scope + } + + pub const fn get_description(&self) -> &'static str { + self.description + } + + pub fn register(&self) { + self.label_permutations.iter().map(|&slice| slice.to_vec()).for_each(|labels| { + counter!(self.name, &labels).absolute(self.initial_value); + }); + describe_counter!(self.name, self.description); + } + + pub fn increment(&self, value: u64, labels: &[(&'static str, &'static str)]) { + counter!(self.name, labels).increment(value); + } + + pub fn parse_numeric_metric( + &self, + metrics_as_string: &str, + labels: &[(&'static str, &'static str)], + ) -> Option { + parse_numeric_metric::(metrics_as_string, self.get_name(), Some(labels)) + } + + #[cfg(any(feature = "testing", test))] + pub fn assert_eq( + &self, + metrics_as_string: &str, + expected_value: T, + label: &[(&'static str, &'static str)], + ) { + let metric_value = self.parse_numeric_metric::(metrics_as_string, label).unwrap(); + assert_eq!( + metric_value, + expected_value, + "Metric counter {} {:?} did not match the expected value. expected value: {:?}, metric + value: {:?}", + self.get_name(), + label, + expected_value, + metric_value + ); + } +} + +pub struct MetricGauge { + scope: MetricScope, + name: &'static str, + description: &'static str, +} + +impl MetricGauge { + pub const fn new(scope: MetricScope, name: &'static str, description: &'static str) -> Self { + Self { scope, name, description } + } + + pub const fn get_name(&self) -> &'static str { + self.name + } + + pub const fn get_scope(&self) -> MetricScope { + self.scope + } + + pub const fn get_description(&self) -> &'static str { + self.description + } + + pub fn register(&self) { + let _ = gauge!(self.name); + describe_gauge!(self.name, self.description); + } + + pub fn increment(&self, value: T) { + gauge!(self.name).increment(value.into_f64()); + } + + pub fn decrement(&self, value: T) { + gauge!(self.name).decrement(value.into_f64()); + } + + pub fn parse_numeric_metric(&self, metrics_as_string: &str) -> Option { + parse_numeric_metric::(metrics_as_string, self.get_name(), None) + } + + pub fn set(&self, value: T) { + gauge!(self.name).set(value.into_f64()); + } + + pub fn set_lossy(&self, value: T) { + gauge!(self.name).set(value.into_f64()); + } + + #[cfg(any(feature = "testing", test))] + pub fn assert_eq(&self, metrics_as_string: &str, expected_value: T) { + let metric_value = self.parse_numeric_metric::(metrics_as_string).unwrap(); + assert_eq!( + metric_value, + expected_value, + "Metric gauge {} did not match the expected value. expected value: {:?}, metric + value: {:?}", + self.get_name(), + expected_value, + metric_value + ); + } +} + +/// An object which can be lossy converted into a `f64` representation. +pub trait LossyIntoF64 { + fn into_f64(self) -> f64; +} + +impl LossyIntoF64 for f64 { + fn into_f64(self) -> f64 { + self + } +} + +macro_rules! into_f64 { + ($($ty:ty),*) => { + $( + impl LossyIntoF64 for $ty { + #[allow(clippy::as_conversions)] + fn into_f64(self) -> f64 { + self as f64 + } + } + )* + }; +} +into_f64!(u64, usize, i64); + +pub struct LabeledMetricGauge { + scope: MetricScope, + name: &'static str, + description: &'static str, + label_permutations: &'static [&'static [(&'static str, &'static str)]], +} + +impl LabeledMetricGauge { + pub const fn new( + scope: MetricScope, + name: &'static str, + description: &'static str, + label_permutations: &'static [&'static [(&'static str, &'static str)]], + ) -> Self { + Self { scope, name, description, label_permutations } + } + + pub const fn get_name(&self) -> &'static str { + self.name + } + + pub const fn get_scope(&self) -> MetricScope { + self.scope + } + + pub const fn get_description(&self) -> &'static str { + self.description + } + + pub fn register(&self) { + self.label_permutations.iter().map(|&slice| slice.to_vec()).for_each(|label| { + let _ = gauge!(self.name, &label); + }); + describe_gauge!(self.name, self.description); + } + + pub fn increment(&self, value: T, label: &[(&'static str, &'static str)]) { + gauge!(self.name, label).increment(value); + } + + pub fn decrement(&self, value: T, label: &[(&'static str, &'static str)]) { + gauge!(self.name, label).decrement(value.into_f64()); + } + + pub fn parse_numeric_metric( + &self, + metrics_as_string: &str, + label: &[(&'static str, &'static str)], + ) -> Option { + parse_numeric_metric::(metrics_as_string, self.get_name(), Some(label)) + } + + pub fn set(&self, value: T, label: &[(&'static str, &'static str)]) { + gauge!(self.name, label).set(value.into_f64()); + } + + #[cfg(any(feature = "testing", test))] + pub fn assert_eq( + &self, + metrics_as_string: &str, + expected_value: T, + label: &[(&'static str, &'static str)], + ) { + let metric_value = self.parse_numeric_metric::(metrics_as_string, label).unwrap(); + assert_eq!( + metric_value, + expected_value, + "Metric gauge {} {:?} did not match the expected value. expected value: {:?}, metric + value: {:?}", + self.get_name(), + label, + expected_value, + metric_value + ); + } +} + +pub struct MetricHistogram { + scope: MetricScope, + name: &'static str, + description: &'static str, +} + +#[derive(Default, Debug)] +pub struct HistogramValue { + pub sum: f64, + pub count: u64, + pub histogram: IndexMap, +} + +impl PartialEq for HistogramValue { + fn eq(&self, other: &Self) -> bool { + self.sum == other.sum && self.count == other.count + } +} + +impl MetricHistogram { + pub const fn new(scope: MetricScope, name: &'static str, description: &'static str) -> Self { + Self { scope, name, description } + } + + pub const fn get_name(&self) -> &'static str { + self.name + } + + pub const fn get_scope(&self) -> MetricScope { + self.scope + } + + pub const fn get_description(&self) -> &'static str { + self.description + } + + pub fn register(&self) { + let _ = histogram!(self.name); + describe_histogram!(self.name, self.description); + } + + pub fn record(&self, value: T) { + histogram!(self.name).record(value.into_f64()); + } + + pub fn record_many(&self, value: T, count: usize) { + histogram!(self.name).record_many(value.into_f64(), count); + } + + pub fn parse_histogram_metric(&self, metrics_as_string: &str) -> Option { + parse_histogram_metric(metrics_as_string, self.get_name(), None) + } + + #[cfg(any(feature = "testing", test))] + pub fn assert_eq(&self, metrics_as_string: &str, expected_value: &HistogramValue) { + let metric_value = self.parse_histogram_metric(metrics_as_string).unwrap(); + assert!( + metric_value == *expected_value, + "Metric histogram {} did not match the expected value. expected value: {:?}, metric \ + value: {:?}", + self.get_name(), + expected_value, + metric_value + ); + } +} + +pub struct LabeledMetricHistogram { + scope: MetricScope, + name: &'static str, + description: &'static str, + label_permutations: &'static [&'static [(&'static str, &'static str)]], +} + +impl LabeledMetricHistogram { + pub const fn new( + scope: MetricScope, + name: &'static str, + description: &'static str, + label_permutations: &'static [&'static [(&'static str, &'static str)]], + ) -> Self { + Self { scope, name, description, label_permutations } + } + + pub const fn get_name(&self) -> &'static str { + self.name + } + + pub const fn get_scope(&self) -> MetricScope { + self.scope + } + + pub const fn get_description(&self) -> &'static str { + self.description + } + + pub fn register(&self) { + self.label_permutations.iter().map(|&slice| slice.to_vec()).for_each(|labels| { + let _ = histogram!(self.name, &labels); + }); + describe_histogram!(self.name, self.description); + } + + pub fn record(&self, value: T, labels: &[(&'static str, &'static str)]) { + histogram!(self.name, labels).record(value.into_f64()); + } + + pub fn record_many( + &self, + value: T, + count: usize, + labels: &[(&'static str, &'static str)], + ) { + histogram!(self.name, labels).record_many(value.into_f64(), count); + } + + pub fn parse_histogram_metric( + &self, + metrics_as_string: &str, + labels: &[(&'static str, &'static str)], + ) -> Option { + parse_histogram_metric(metrics_as_string, self.get_name(), Some(labels)) + } + + #[cfg(any(feature = "testing", test))] + // TODO(tsabary): unite the labeled and unlabeld assert_eq functions. + pub fn assert_eq( + &self, + metrics_as_string: &str, + expected_value: &HistogramValue, + label: &[(&'static str, &'static str)], + ) { + let metric_value = self.parse_histogram_metric(metrics_as_string, label).unwrap(); + assert!( + metric_value == *expected_value, + "Metric histogram {} {:?} did not match the expected value. expected value: {:?}, \ + metric value: {:?}", + self.get_name(), + label, + expected_value, + metric_value + ); + } +} + +/// Parses a specific numeric metric value from a metrics string. +/// +/// # Arguments +/// +/// - `metrics_as_string`: A string containing the renders metrics data. +/// - `metric_name`: The name of the metric to search for. +/// +/// # Type Parameters +/// +/// - `T`: The numeric type to which the metric value will be parsed. The type must implement the +/// `Num` and `FromStr` traits, allowing it to represent numeric values and be parsed from a +/// string. Common types include `i32`, `u64`, and `f64`. +/// +/// # Returns +/// +/// - `Option`: Returns `Some(T)` if the metric is found and successfully parsed into the +/// specified numeric type `T`. Returns `None` if the metric is not found or if parsing fails. +pub fn parse_numeric_metric( + metrics_as_string: &str, + metric_name: &str, + labels: Option<&[(&'static str, &'static str)]>, +) -> Option { + // Construct a regex pattern to match Prometheus-style metrics. + // - If there are no labels, it matches: "metric_name " (e.g., `http_requests_total + // 123`). + // - If labels are present, it matches: "metric_name{label1="value1",label2="value2",...} + // " (e.g., `http_requests_total{method="POST",status="200"} 123`). + let mut labels_pattern = "".to_string(); + if let Some(labels) = labels { + // Create a regex to match "{label1="value1",label2="value2",...}". + let inner_pattern = labels + .iter() + .map(|(k, v)| format!(r#"{}="{}""#, escape(k), escape(v))) + .collect::>() + .join(r","); + labels_pattern = format!(r#"\{{{}\}}"#, inner_pattern) + }; + let pattern = format!(r#"{}{}\s+(\d+)"#, escape(metric_name), labels_pattern); + let re = Regex::new(&pattern).expect("Invalid regex"); + + // Search for the pattern in the output. + if let Some(captures) = re.captures(metrics_as_string) { + // Extract the numeric value. + if let Some(value) = captures.get(1) { + // Parse the string into a number. + return value.as_str().parse().ok(); + } + } + // If no match is found, return None. + None +} + +/// Parses a histogram metric from a metrics string. +/// +/// # Arguments +/// +/// - `metrics_as_string`: A string containing the rendered metrics data. +/// - `metric_name`: The name of the metric to search for. +/// - `labels`: Optional labels to match the metric. +/// +/// # Returns +/// +/// - `Option`: Returns `Some(HistogramValue)` if the metric is found and +/// successfully parsed. Returns `None` if the metric is not found or if parsing fails. +pub fn parse_histogram_metric( + metrics_as_string: &str, + metric_name: &str, + labels: Option<&[(&'static str, &'static str)]>, +) -> Option { + // Construct a regex pattern to match the labels if provided. + let mut quantile_labels_pattern = r#"\{"#.to_string(); + let mut labels_pattern = "".to_string(); + if let Some(labels) = labels { + let inner_pattern = labels + .iter() + .map(|(k, v)| format!(r#"{}="{}""#, escape(k), escape(v))) + .collect::>() + .join(r","); + quantile_labels_pattern = format!(r#"\{{{},"#, inner_pattern); + labels_pattern = format!(r#"\{{{}\}}"#, inner_pattern); + } + // Define regex patterns for quantiles, sum, and count. + let quantile_pattern = format!( + r#"{}{}quantile="([^"]+)"\}}\s+([\d\.]+)"#, + escape(metric_name), + quantile_labels_pattern + ); + let sum_pattern = format!(r#"{}_sum{}\s+([\d\.]+)"#, escape(metric_name), labels_pattern); + let count_pattern = format!(r#"{}_count{}\s+(\d+)"#, escape(metric_name), labels_pattern); + + // Compile the regex patterns. + let quantile_re = Regex::new(&quantile_pattern).expect("Invalid regex for quantiles"); + let sum_re = Regex::new(&sum_pattern).expect("Invalid regex for sum"); + let count_re = Regex::new(&count_pattern).expect("Invalid regex for count"); + + // Parse quantiles and insert them into the histogram. + let mut histogram = IndexMap::new(); + for captures in quantile_re.captures_iter(metrics_as_string) { + let quantile = captures.get(1)?.as_str().to_string(); + let value = captures.get(2)?.as_str().parse::().ok()?; + histogram.insert(quantile, value); + } + + // If no quantiles were found, return None. + if histogram.is_empty() { + return None; + } + + // Parse the sum value. + let sum = sum_re + .captures(metrics_as_string) + .and_then(|cap| cap.get(1)) + .and_then(|m| m.as_str().parse::().ok()) + .unwrap_or(0.0); + + // Parse the count value. + let count = count_re + .captures(metrics_as_string) + .and_then(|cap| cap.get(1)) + .and_then(|m| m.as_str().parse::().ok()) + .unwrap_or(0); + + Some(HistogramValue { sum, count, histogram }) +} diff --git a/crates/starknet_sequencer_metrics/src/metrics_test.rs b/crates/starknet_sequencer_metrics/src/metrics_test.rs new file mode 100644 index 00000000000..4aa767089da --- /dev/null +++ b/crates/starknet_sequencer_metrics/src/metrics_test.rs @@ -0,0 +1,189 @@ +use std::sync::LazyLock; + +use indexmap::indexmap; +use metrics::set_default_local_recorder; +use metrics_exporter_prometheus::PrometheusBuilder; +use rstest::rstest; +use strum::VariantNames; +use strum_macros::EnumVariantNames; + +use crate::generate_permutation_labels; +use crate::metrics::{HistogramValue, LabeledMetricHistogram, MetricHistogram, MetricScope}; + +const HISTOGRAM_TEST_METRIC: MetricHistogram = + MetricHistogram::new(MetricScope::Infra, "histogram_test_metric", "Histogram test metrics"); + +const LABEL_TYPE_NAME: &str = "label"; +const VALUE_TYPE_NAME: &str = "value"; + +#[allow(dead_code)] +#[derive(Debug, EnumVariantNames, Clone, Copy)] +enum TestLabelType { + Label1, +} + +#[allow(dead_code)] +#[derive(Debug, EnumVariantNames, Clone, Copy)] +enum TestLabelValue { + Value1, + Value2, +} + +// Create a labeled histogram metric with a single key-value pair. +generate_permutation_labels! { + SINGLE_KEY_VALUE_PAIR_LABELS, + (VALUE_TYPE_NAME, TestLabelValue), +} + +const SINGLE_KEY_VALUE_PAIR_LABELED_HISTOGRAM_METRIC: LabeledMetricHistogram = + LabeledMetricHistogram::new( + MetricScope::Infra, + "labeled_histogram_test_metric", + "Labeled histogram test metrics", + SINGLE_KEY_VALUE_PAIR_LABELS, + ); + +generate_permutation_labels! { + TWO_KEY_VALUE_PAIR_LABELS, + (LABEL_TYPE_NAME, TestLabelType), + (VALUE_TYPE_NAME, TestLabelValue), +} + +const TWO_KEY_VALUE_PAIR_LABELED_HISTOGRAM_METRIC: LabeledMetricHistogram = + LabeledMetricHistogram::new( + MetricScope::Infra, + "multi_labeled_histogram_test_metric", + "Multi labeled histogram test metrics", + TWO_KEY_VALUE_PAIR_LABELS, + ); + +const TEST_SET_1: &[(i32, usize)] = &[(1, 0), (100, 1), (80, 0), (50, 0), (93, 1)]; +static TEST_SET_1_RESULT: LazyLock = LazyLock::new(|| HistogramValue { + sum: 324.0, + count: 5, + histogram: indexmap! { + "0".to_string() => 1.0, + "0.5".to_string() => 80.00587021001003, + "0.9".to_string() => 92.99074853701167, + "0.95".to_string() => 92.99074853701167, + "0.99".to_string() => 92.99074853701167, + "0.999".to_string() => 92.99074853701167, + "1".to_string() => 100.0, + }, +}); + +const TEST_SET_2: &[(i32, usize)] = &[(1, 0), (10, 0), (20, 0), (30, 0), (80, 2)]; +static TEST_SET_2_RESULT: LazyLock = LazyLock::new(|| HistogramValue { + sum: 221.0, + count: 6, + histogram: indexmap! { + "0".to_string() => 1.0, + "0.5".to_string() => 19.999354639046004, + "0.9".to_string() => 80.00587021001003, + "0.95".to_string() => 80.00587021001003, + "0.99".to_string() => 80.00587021001003, + "0.999".to_string() => 80.00587021001003, + "1".to_string() => 80.0, + }, +}); + +static EMPTY_HISTOGRAM_VALUE: LazyLock = LazyLock::new(|| HistogramValue { + sum: 0.0, + count: 0, + histogram: indexmap! { + "0".to_string() => 0.0, + "0.5".to_string() => 0.0, + "0.9".to_string() => 0.0, + "0.95".to_string() => 0.0, + "0.99".to_string() => 0.0, + "0.999".to_string() => 0.0, + "1".to_string() => 0.0, + }, +}); + +fn record_non_labeled_histogram_set(metric: &MetricHistogram, test_set: &[(i32, usize)]) { + for (value, count) in test_set { + match *count { + 0 => metric.record(*value), + _ => metric.record_many(*value, *count), + } + } +} + +fn record_labeled_histogram_set( + metric: &LabeledMetricHistogram, + test_set: &[(i32, usize)], + label: &'static [(&str, &str)], +) { + for (value, count) in test_set { + match *count { + 0 => metric.record(*value, label), + _ => metric.record_many(*value, *count, label), + } + } +} + +#[test] +fn histogram_run_and_parse() { + let recorder = PrometheusBuilder::new().build_recorder(); + let _recorder_guard = set_default_local_recorder(&recorder); + + record_non_labeled_histogram_set(&HISTOGRAM_TEST_METRIC, TEST_SET_1); + + let metrics_as_string = recorder.handle().render(); + + assert_eq!( + HISTOGRAM_TEST_METRIC.parse_histogram_metric(&metrics_as_string).unwrap(), + *TEST_SET_1_RESULT + ); +} + +#[rstest] +#[case::single_key_value_pair( + SINGLE_KEY_VALUE_PAIR_LABELED_HISTOGRAM_METRIC, + SINGLE_KEY_VALUE_PAIR_LABELS +)] +#[case::two_key_value_pair(TWO_KEY_VALUE_PAIR_LABELED_HISTOGRAM_METRIC, TWO_KEY_VALUE_PAIR_LABELS)] +#[test] +fn labeled_histogram_run_and_parse( + #[case] labeled_histogram_metric: LabeledMetricHistogram, + #[case] labels: &'static [&[(&str, &str)]], +) { + let recorder = PrometheusBuilder::new().build_recorder(); + let _recorder_guard = set_default_local_recorder(&recorder); + + // Let perform some actions for the histogram metric with labels[0]. + labeled_histogram_metric.register(); + + record_labeled_histogram_set(&labeled_histogram_metric, TEST_SET_1, labels[0]); + + let metrics_as_string = recorder.handle().render(); + + assert_eq!( + labeled_histogram_metric.parse_histogram_metric(&metrics_as_string, labels[0]).unwrap(), + *TEST_SET_1_RESULT + ); + + // The histogram metric with labels[1] should be empty. + assert_eq!( + labeled_histogram_metric.parse_histogram_metric(&metrics_as_string, labels[1]).unwrap(), + *EMPTY_HISTOGRAM_VALUE + ); + + // Let perform some actions for the histogram metric with labels[1]. + record_labeled_histogram_set(&labeled_histogram_metric, TEST_SET_2, labels[1]); + + let metrics_as_string = recorder.handle().render(); + + // The histogram metric with labels[0] should be the same. + assert_eq!( + labeled_histogram_metric.parse_histogram_metric(&metrics_as_string, labels[0]).unwrap(), + *TEST_SET_1_RESULT + ); + + // Check the histogram metric with labels[1]. + assert_eq!( + labeled_histogram_metric.parse_histogram_metric(&metrics_as_string, labels[1]).unwrap(), + *TEST_SET_2_RESULT + ); +} diff --git a/crates/starknet_sequencer_node/Cargo.toml b/crates/starknet_sequencer_node/Cargo.toml index 29aa72a10ae..0ebfaafc5cb 100644 --- a/crates/starknet_sequencer_node/Cargo.toml +++ b/crates/starknet_sequencer_node/Cargo.toml @@ -6,48 +6,56 @@ repository.workspace = true license.workspace = true [features] -testing = ["papyrus_proc_macros", "thiserror"] +testing = [] [lints] workspace = true [dependencies] +apollo_reverts.workspace = true anyhow.workspace = true clap.workspace = true const_format.workspace = true futures.workspace = true -infra_utils.workspace = true +papyrus_base_layer.workspace = true papyrus_config.workspace = true -papyrus_proc_macros = { workspace = true, optional = true } rstest.workspace = true serde.workspace = true -starknet_api.workspace = true +serde_json.workspace = true starknet_batcher.workspace = true starknet_batcher_types.workspace = true +starknet_class_manager.workspace = true +starknet_class_manager_types.workspace = true starknet_consensus_manager.workspace = true starknet_gateway.workspace = true starknet_gateway_types.workspace = true starknet_http_server.workspace = true +starknet_infra_utils.workspace = true +starknet_l1_provider.workspace = true +starknet_l1_provider_types.workspace = true +starknet_l1_gas_price.workspace = true +starknet_l1_gas_price_types.workspace = true starknet_mempool.workspace = true starknet_mempool_p2p.workspace = true starknet_mempool_p2p_types.workspace = true starknet_mempool_types.workspace = true starknet_monitoring_endpoint.workspace = true starknet_sequencer_infra.workspace = true -starknet_sierra_compile.workspace = true +starknet_sierra_multicompile.workspace = true +starknet_sierra_multicompile_types.workspace = true +starknet_state_sync.workspace = true starknet_state_sync_types.workspace = true -thiserror = { workspace = true, optional = true } +tikv-jemallocator.workspace = true tokio.workspace = true tracing.workspace = true validator.workspace = true [dev-dependencies] -assert-json-diff.workspace = true assert_matches.workspace = true colored.workspace = true -infra_utils.workspace = true mempool_test_utils.workspace = true pretty_assertions.workspace = true -serde_json.workspace = true -# Enable self with "testing" feature in tests. -starknet_sequencer_node = { workspace = true, features = ["testing"] } +starknet_infra_utils = { workspace = true, features = ["testing"] } + +[package.metadata.cargo-machete] +ignored = ["tikv-jemallocator"] diff --git a/crates/starknet_sequencer_node/build.rs b/crates/starknet_sequencer_node/build.rs deleted file mode 100644 index 74fc7c9940e..00000000000 --- a/crates/starknet_sequencer_node/build.rs +++ /dev/null @@ -1,3 +0,0 @@ -// Sets up the environment variable OUT_DIR, which holds the cairo compiler binary. -// The binary is downloaded to OUT_DIR by the starknet_sierra_compile crate. -fn main() {} diff --git a/crates/starknet_sequencer_node/src/clients.rs b/crates/starknet_sequencer_node/src/clients.rs index 4ef7440f010..fde9821ddb2 100644 --- a/crates/starknet_sequencer_node/src/clients.rs +++ b/crates/starknet_sequencer_node/src/clients.rs @@ -7,6 +7,13 @@ use starknet_batcher_types::communication::{ RemoteBatcherClient, SharedBatcherClient, }; +use starknet_class_manager_types::{ + ClassManagerRequest, + ClassManagerResponse, + LocalClassManagerClient, + RemoteClassManagerClient, + SharedClassManagerClient, +}; use starknet_gateway_types::communication::{ GatewayRequest, GatewayResponse, @@ -14,6 +21,10 @@ use starknet_gateway_types::communication::{ RemoteGatewayClient, SharedGatewayClient, }; +use starknet_l1_gas_price::communication::{LocalL1GasPriceClient, RemoteL1GasPriceClient}; +use starknet_l1_gas_price_types::{L1GasPriceRequest, L1GasPriceResponse, SharedL1GasPriceClient}; +use starknet_l1_provider::communication::{LocalL1ProviderClient, RemoteL1ProviderClient}; +use starknet_l1_provider_types::{L1ProviderRequest, L1ProviderResponse, SharedL1ProviderClient}; use starknet_mempool_p2p_types::communication::{ LocalMempoolP2pPropagatorClient, MempoolP2pPropagatorRequest, @@ -29,24 +40,40 @@ use starknet_mempool_types::communication::{ SharedMempoolClient, }; use starknet_sequencer_infra::component_client::{Client, LocalComponentClient}; +use starknet_sierra_multicompile_types::{ + LocalSierraCompilerClient, + RemoteSierraCompilerClient, + SharedSierraCompilerClient, + SierraCompilerRequest, + SierraCompilerResponse, +}; +use starknet_state_sync_types::communication::{ + LocalStateSyncClient, + RemoteStateSyncClient, + SharedStateSyncClient, + StateSyncRequest, + StateSyncResponse, +}; use crate::communication::SequencerNodeCommunication; -use crate::config::component_execution_config::ComponentExecutionMode; +use crate::config::component_execution_config::ReactiveComponentExecutionMode; use crate::config::node_config::SequencerNodeConfig; pub struct SequencerNodeClients { - batcher_client: Option>, - mempool_client: Option>, - gateway_client: Option>, - // TODO (Lev): Change to Option>. + batcher_client: Client, + class_manager_client: Client, + gateway_client: Client, + l1_provider_client: Client, + l1_gas_price_client: Client, + mempool_client: Client, mempool_p2p_propagator_client: - Option>, + Client, + sierra_compiler_client: Client, + state_sync_client: Client, } -/// A macro to retrieve a shared client (either local or remote) from a specified field in a struct, -/// returning it wrapped in an `Arc`. This macro simplifies access to a client by checking if a -/// This macro simplifies client access by checking the specified client field and returning the -/// existing client, either local_client or remote_client. Only one will exist at a time. +/// A macro to retrieve a shared client wrapped in an `Arc`. The returned client is either the local +/// or the remote, as at most one of them exists. If neither, it returns `None`. /// /// # Arguments /// @@ -56,8 +83,8 @@ pub struct SequencerNodeClients { /// /// # Returns /// -/// An Option> containing the available client (local_client or remote_client), -/// wrapped in Arc. If neither client exists, it returns None. +/// An `Option>` containing the available client (local_client or +/// remote_client), wrapped in Arc. If neither exists, returns None. /// /// # Example /// @@ -73,20 +100,14 @@ pub struct SequencerNodeClients { /// } /// } /// ``` -/// -/// In this example, `get_shared_client!` checks if `batcher_client` has a local or remote client -/// available. If a local client exists, it returns `Some(Arc::new(local_client))`; otherwise, -/// it checks for a remote client and returns `Some(Arc::new(remote_client))` if available. -/// If neither client is available, it returns `None`. #[macro_export] macro_rules! get_shared_client { ($self:ident, $client_field:ident) => {{ - if let Some(client) = &$self.$client_field { - if let Some(local_client) = client.get_local_client() { - return Some(Arc::new(local_client)); - } else if let Some(remote_client) = client.get_remote_client() { - return Some(Arc::new(remote_client)); - } + let client = &$self.$client_field; + if let Some(local_client) = client.get_local_client() { + return Some(Arc::new(local_client)); + } else if let Some(remote_client) = client.get_remote_client() { + return Some(Arc::new(remote_client)); } None }}; @@ -94,88 +115,121 @@ macro_rules! get_shared_client { // TODO(Nadin): Refactor getters to remove code duplication. impl SequencerNodeClients { + pub fn get_batcher_local_client( + &self, + ) -> Option> { + self.batcher_client.get_local_client() + } + pub fn get_batcher_shared_client(&self) -> Option { get_shared_client!(self, batcher_client) } - pub fn get_batcher_local_client( + pub fn get_class_manager_local_client( &self, - ) -> Option> { - match &self.batcher_client { - Some(client) => client.get_local_client(), - None => None, - } + ) -> Option> { + self.class_manager_client.get_local_client() } - pub fn get_mempool_shared_client(&self) -> Option { - get_shared_client!(self, mempool_client) + pub fn get_class_manager_shared_client(&self) -> Option { + get_shared_client!(self, class_manager_client) } - pub fn get_mempool_local_client( + pub fn get_gateway_local_client( &self, - ) -> Option> { - match &self.mempool_client { - Some(client) => client.get_local_client(), - None => None, - } + ) -> Option> { + self.gateway_client.get_local_client() } pub fn get_gateway_shared_client(&self) -> Option { get_shared_client!(self, gateway_client) } - pub fn get_gateway_local_client( + pub fn get_l1_provider_local_client( &self, - ) -> Option> { - match &self.gateway_client { - Some(client) => client.get_local_client(), - None => None, - } + ) -> Option> { + self.l1_provider_client.get_local_client() } - pub fn get_mempool_p2p_propagator_shared_client( + pub fn get_l1_gas_price_provider_local_client( &self, - ) -> Option { - get_shared_client!(self, mempool_p2p_propagator_client) + ) -> Option> { + self.l1_gas_price_client.get_local_client() + } + + pub fn get_l1_provider_shared_client(&self) -> Option { + get_shared_client!(self, l1_provider_client) + } + + pub fn get_l1_gas_price_shared_client(&self) -> Option { + get_shared_client!(self, l1_gas_price_client) + } + + pub fn get_mempool_local_client( + &self, + ) -> Option> { + self.mempool_client.get_local_client() + } + + pub fn get_mempool_shared_client(&self) -> Option { + get_shared_client!(self, mempool_client) } pub fn get_mempool_p2p_propagator_local_client( &self, ) -> Option> { - match &self.mempool_p2p_propagator_client { - Some(client) => client.get_local_client(), - None => None, - } + self.mempool_p2p_propagator_client.get_local_client() + } + + pub fn get_mempool_p2p_propagator_shared_client( + &self, + ) -> Option { + get_shared_client!(self, mempool_p2p_propagator_client) + } + + pub fn get_sierra_compiler_local_client( + &self, + ) -> Option> { + self.sierra_compiler_client.get_local_client() + } + + pub fn get_sierra_compiler_shared_client(&self) -> Option { + get_shared_client!(self, sierra_compiler_client) + } + + pub fn get_state_sync_local_client( + &self, + ) -> Option> { + self.state_sync_client.get_local_client() + } + + pub fn get_state_sync_shared_client(&self) -> Option { + get_shared_client!(self, state_sync_client) } } -/// A macro for creating a component client, determined by the component's execution mode. Returns a -/// `Client` containing either a local client if the component is run locally, or a remote client if -/// the execution mode is Remote. Returns None if the execution mode is Disabled. +/// A macro for creating a component client fitting the component's execution mode. Returns a +/// `Client` containing: a local client if the component is run locally, a remote client if +/// the component is run remotely, and neither if the component is disabled. /// /// # Arguments /// /// * $execution_mode - A reference to the component's execution mode, i.e., type -/// &ComponentExecutionMode. +/// &ReactiveComponentExecutionMode. /// * $local_client_type - The type for the local client to create, e.g., LocalBatcherClient. The /// client type should have a function $local_client_type::new(tx: $channel_expr). /// * $remote_client_type - The type for the remote client to create, e.g., RemoteBatcherClient. The /// client type should have a function $remote_client_type::new(config). /// * $channel_expr - Sender side for the local client. -/// * $remote_client_config - Configuration for the remote client, passed as Some(config) when -/// available. -/// -/// # Returns -/// -/// An `Option>` containing either a local or remote client based on the execution mode -/// (LocalExecutionWithRemoteDisabled / LocalExecutionWithRemoteEnabled for local clients, Remote -/// for remote clients), or None if the execution mode is Disabled. +/// * $remote_client_config - Configuration for the remote client, passed as Option(config). +/// * $url - URL of the remote component server. +/// * $port - Listening port of the remote component server. /// /// # Example /// /// ```rust,ignore -/// // Assuming ComponentExecutionMode, channels, and remote client configuration are defined, and +/// // Assuming ReactiveComponentExecutionMode, channels, and remote client configuration are defined, and /// // LocalBatcherClient and RemoteBatcherClient have new methods that accept a channel and config, /// // respectively. /// let batcher_client: Option> = create_client!( @@ -183,13 +237,10 @@ impl SequencerNodeClients { /// LocalBatcherClient, /// RemoteBatcherClient, /// channels.take_batcher_tx(), -/// config.components.batcher.remote_client_config +/// config.components.batcher.remote_client_config, +/// config.components.batcher.url, +/// config.components.batcher.port /// ); -/// -/// match batcher_client { -/// Some(client) => println!("Client created: {:?}", client), -/// None => println!("Client not created because the execution mode is disabled."), -/// } /// ``` macro_rules! create_client { ( @@ -197,22 +248,22 @@ macro_rules! create_client { $local_client_type:ty, $remote_client_type:ty, $channel_expr:expr, - $remote_client_config:expr + $remote_client_config:expr, + $url:expr, + $port:expr ) => { match *$execution_mode { - ComponentExecutionMode::LocalExecutionWithRemoteDisabled - | ComponentExecutionMode::LocalExecutionWithRemoteEnabled => { + ReactiveComponentExecutionMode::LocalExecutionWithRemoteDisabled + | ReactiveComponentExecutionMode::LocalExecutionWithRemoteEnabled => { let local_client = Some(<$local_client_type>::new($channel_expr)); - Some(Client::new(local_client, None)) + Client::new(local_client, None) } - ComponentExecutionMode::Remote => match $remote_client_config { - Some(ref config) => { - let remote_client = Some(<$remote_client_type>::new(config.clone())); - Some(Client::new(None, remote_client)) - } - None => None, - }, - ComponentExecutionMode::Disabled => None, + ReactiveComponentExecutionMode::Remote => { + let remote_client = + Some(<$remote_client_type>::new($remote_client_config.clone(), $url, $port)); + Client::new(None, remote_client) + } + ReactiveComponentExecutionMode::Disabled => Client::new(None, None), } }; } @@ -226,21 +277,59 @@ pub fn create_node_clients( LocalBatcherClient, RemoteBatcherClient, channels.take_batcher_tx(), - config.components.batcher.remote_client_config + &config.components.batcher.remote_client_config, + &config.components.batcher.url, + config.components.batcher.port ); - let mempool_client = create_client!( - &config.components.mempool.execution_mode, - LocalMempoolClient, - RemoteMempoolClient, - channels.take_mempool_tx(), - config.components.mempool.remote_client_config + + let class_manager_client = create_client!( + &config.components.class_manager.execution_mode, + LocalClassManagerClient, + RemoteClassManagerClient, + channels.take_class_manager_tx(), + &config.components.class_manager.remote_client_config, + &config.components.class_manager.url, + config.components.class_manager.port ); + let gateway_client = create_client!( &config.components.gateway.execution_mode, LocalGatewayClient, RemoteGatewayClient, channels.take_gateway_tx(), - config.components.gateway.remote_client_config + &config.components.gateway.remote_client_config, + &config.components.gateway.url, + config.components.gateway.port + ); + + let l1_provider_client = create_client!( + &config.components.l1_provider.execution_mode, + LocalL1ProviderClient, + RemoteL1ProviderClient, + channels.take_l1_provider_tx(), + &config.components.l1_provider.remote_client_config, + &config.components.l1_provider.url, + config.components.l1_provider.port + ); + + let l1_gas_price_client = create_client!( + &config.components.l1_gas_price_provider.execution_mode, + LocalL1GasPriceClient, + RemoteL1GasPriceClient, + channels.take_l1_gas_price_tx(), + &config.components.l1_gas_price_provider.remote_client_config, + &config.components.l1_gas_price_provider.url, + config.components.l1_gas_price_provider.port + ); + + let mempool_client = create_client!( + &config.components.mempool.execution_mode, + LocalMempoolClient, + RemoteMempoolClient, + channels.take_mempool_tx(), + &config.components.mempool.remote_client_config, + &config.components.mempool.url, + config.components.mempool.port ); let mempool_p2p_propagator_client = create_client!( @@ -248,12 +337,40 @@ pub fn create_node_clients( LocalMempoolP2pPropagatorClient, RemoteMempoolP2pPropagatorClient, channels.take_mempool_p2p_propagator_tx(), - config.components.mempool_p2p.remote_client_config + &config.components.mempool_p2p.remote_client_config, + &config.components.mempool_p2p.url, + config.components.mempool_p2p.port + ); + + let sierra_compiler_client = create_client!( + &config.components.sierra_compiler.execution_mode, + LocalSierraCompilerClient, + RemoteSierraCompilerClient, + channels.take_sierra_compiler_tx(), + &config.components.sierra_compiler.remote_client_config, + &config.components.sierra_compiler.url, + config.components.sierra_compiler.port ); + + let state_sync_client = create_client!( + &config.components.state_sync.execution_mode, + LocalStateSyncClient, + RemoteStateSyncClient, + channels.take_state_sync_tx(), + &config.components.state_sync.remote_client_config, + &config.components.state_sync.url, + config.components.state_sync.port + ); + SequencerNodeClients { batcher_client, - mempool_client, + class_manager_client, gateway_client, + l1_provider_client, + l1_gas_price_client, + mempool_client, mempool_p2p_propagator_client, + sierra_compiler_client, + state_sync_client, } } diff --git a/crates/starknet_sequencer_node/src/communication.rs b/crates/starknet_sequencer_node/src/communication.rs index 812b72ab990..e13730cb965 100644 --- a/crates/starknet_sequencer_node/src/communication.rs +++ b/crates/starknet_sequencer_node/src/communication.rs @@ -1,17 +1,25 @@ use starknet_batcher_types::communication::BatcherRequestAndResponseSender; +use starknet_class_manager_types::ClassManagerRequestAndResponseSender; use starknet_gateway_types::communication::GatewayRequestAndResponseSender; +use starknet_l1_gas_price::communication::L1GasPriceRequestAndResponseSender; +use starknet_l1_provider::communication::L1ProviderRequestAndResponseSender; use starknet_mempool_p2p_types::communication::MempoolP2pPropagatorRequestAndResponseSender; use starknet_mempool_types::communication::MempoolRequestAndResponseSender; use starknet_sequencer_infra::component_definitions::ComponentCommunication; +use starknet_sierra_multicompile_types::SierraCompilerRequestAndResponseSender; use starknet_state_sync_types::communication::StateSyncRequestAndResponseSender; use tokio::sync::mpsc::{channel, Receiver, Sender}; pub struct SequencerNodeCommunication { batcher_channel: ComponentCommunication, + class_manager_channel: ComponentCommunication, gateway_channel: ComponentCommunication, + l1_provider_channel: ComponentCommunication, + l1_gas_price_channel: ComponentCommunication, mempool_channel: ComponentCommunication, mempool_p2p_propagator_channel: ComponentCommunication, + sierra_compiler_channel: ComponentCommunication, state_sync_channel: ComponentCommunication, } @@ -24,6 +32,14 @@ impl SequencerNodeCommunication { self.batcher_channel.take_rx() } + pub fn take_class_manager_tx(&mut self) -> Sender { + self.class_manager_channel.take_tx() + } + + pub fn take_class_manager_rx(&mut self) -> Receiver { + self.class_manager_channel.take_rx() + } + pub fn take_gateway_tx(&mut self) -> Sender { self.gateway_channel.take_tx() } @@ -32,6 +48,21 @@ impl SequencerNodeCommunication { self.gateway_channel.take_rx() } + pub fn take_l1_provider_tx(&mut self) -> Sender { + self.l1_provider_channel.take_tx() + } + + pub fn take_l1_provider_rx(&mut self) -> Receiver { + self.l1_provider_channel.take_rx() + } + + pub fn take_l1_gas_price_tx(&mut self) -> Sender { + self.l1_gas_price_channel.take_tx() + } + pub fn take_l1_gas_price_rx(&mut self) -> Receiver { + self.l1_gas_price_channel.take_rx() + } + pub fn take_mempool_p2p_propagator_tx( &mut self, ) -> Sender { @@ -51,6 +82,14 @@ impl SequencerNodeCommunication { self.mempool_channel.take_rx() } + pub fn take_sierra_compiler_tx(&mut self) -> Sender { + self.sierra_compiler_channel.take_tx() + } + + pub fn take_sierra_compiler_rx(&mut self) -> Receiver { + self.sierra_compiler_channel.take_rx() + } + pub fn take_state_sync_tx(&mut self) -> Sender { self.state_sync_channel.take_tx() } @@ -65,26 +104,54 @@ pub fn create_node_channels() -> SequencerNodeCommunication { let (tx_batcher, rx_batcher) = channel::(DEFAULT_INVOCATIONS_QUEUE_SIZE); + let (tx_class_manager, rx_class_manager) = + channel::(DEFAULT_INVOCATIONS_QUEUE_SIZE); + let (tx_gateway, rx_gateway) = channel::(DEFAULT_INVOCATIONS_QUEUE_SIZE); + let (tx_l1_provider, rx_l1_provider) = + channel::(DEFAULT_INVOCATIONS_QUEUE_SIZE); + + let (tx_l1_gas_price, rx_l1_gas_price) = + channel::(DEFAULT_INVOCATIONS_QUEUE_SIZE); + let (tx_mempool, rx_mempool) = channel::(DEFAULT_INVOCATIONS_QUEUE_SIZE); let (tx_mempool_p2p_propagator, rx_mempool_p2p_propagator) = channel::(DEFAULT_INVOCATIONS_QUEUE_SIZE); + let (tx_sierra_compiler, rx_sierra_compiler) = + channel::(DEFAULT_INVOCATIONS_QUEUE_SIZE); + let (tx_state_sync, rx_state_sync) = channel::(DEFAULT_INVOCATIONS_QUEUE_SIZE); SequencerNodeCommunication { batcher_channel: ComponentCommunication::new(Some(tx_batcher), Some(rx_batcher)), + class_manager_channel: ComponentCommunication::new( + Some(tx_class_manager), + Some(rx_class_manager), + ), gateway_channel: ComponentCommunication::new(Some(tx_gateway), Some(rx_gateway)), + l1_provider_channel: ComponentCommunication::new( + Some(tx_l1_provider), + Some(rx_l1_provider), + ), + l1_gas_price_channel: ComponentCommunication::new( + Some(tx_l1_gas_price), + Some(rx_l1_gas_price), + ), mempool_channel: ComponentCommunication::new(Some(tx_mempool), Some(rx_mempool)), mempool_p2p_propagator_channel: ComponentCommunication::new( Some(tx_mempool_p2p_propagator), Some(rx_mempool_p2p_propagator), ), + sierra_compiler_channel: ComponentCommunication::new( + Some(tx_sierra_compiler), + Some(rx_sierra_compiler), + ), state_sync_channel: ComponentCommunication::new(Some(tx_state_sync), Some(rx_state_sync)), } } diff --git a/crates/starknet_sequencer_node/src/components.rs b/crates/starknet_sequencer_node/src/components.rs index 266f37f15ed..d077ed7d62d 100644 --- a/crates/starknet_sequencer_node/src/components.rs +++ b/crates/starknet_sequencer_node/src/components.rs @@ -1,7 +1,16 @@ +use papyrus_base_layer::ethereum_base_layer_contract::EthereumBaseLayerContract; +use papyrus_base_layer::BaseLayerContract; use starknet_batcher::batcher::{create_batcher, Batcher}; +use starknet_class_manager::class_manager::create_class_manager; +use starknet_class_manager::ClassManager; use starknet_consensus_manager::consensus_manager::ConsensusManager; use starknet_gateway::gateway::{create_gateway, Gateway}; use starknet_http_server::http_server::{create_http_server, HttpServer}; +use starknet_l1_gas_price::l1_gas_price_provider::L1GasPriceProvider; +use starknet_l1_gas_price::l1_gas_price_scraper::L1GasPriceScraper; +use starknet_l1_provider::event_identifiers_to_track; +use starknet_l1_provider::l1_provider::{create_l1_provider, L1Provider}; +use starknet_l1_provider::l1_scraper::L1Scraper; use starknet_mempool::communication::{create_mempool, MempoolCommunicationWrapper}; use starknet_mempool_p2p::create_p2p_propagator_and_runner; use starknet_mempool_p2p::propagator::MempoolP2pPropagator; @@ -10,115 +19,302 @@ use starknet_monitoring_endpoint::monitoring_endpoint::{ create_monitoring_endpoint, MonitoringEndpoint, }; +use starknet_sierra_multicompile::{create_sierra_compiler, SierraCompiler}; +use starknet_state_sync::runner::StateSyncRunner; +use starknet_state_sync::{create_state_sync_and_runner, StateSync}; +use tracing::warn; use crate::clients::SequencerNodeClients; -use crate::config::component_execution_config::ComponentExecutionMode; +use crate::config::component_execution_config::{ + ActiveComponentExecutionMode, + ReactiveComponentExecutionMode, +}; use crate::config::node_config::SequencerNodeConfig; use crate::version::VERSION_FULL; pub struct SequencerNodeComponents { pub batcher: Option, + pub class_manager: Option, pub consensus_manager: Option, pub gateway: Option, pub http_server: Option, + pub l1_scraper: Option>, + pub l1_provider: Option, + pub l1_gas_price_scraper: Option>, + pub l1_gas_price_provider: Option, pub mempool: Option, pub monitoring_endpoint: Option, pub mempool_p2p_propagator: Option, pub mempool_p2p_runner: Option, + pub sierra_compiler: Option, + pub state_sync: Option, + pub state_sync_runner: Option, } -pub fn create_node_components( +pub async fn create_node_components( config: &SequencerNodeConfig, clients: &SequencerNodeClients, ) -> SequencerNodeComponents { let batcher = match config.components.batcher.execution_mode { - ComponentExecutionMode::LocalExecutionWithRemoteDisabled - | ComponentExecutionMode::LocalExecutionWithRemoteEnabled => { + ReactiveComponentExecutionMode::LocalExecutionWithRemoteDisabled + | ReactiveComponentExecutionMode::LocalExecutionWithRemoteEnabled => { let mempool_client = clients.get_mempool_shared_client().expect("Mempool Client should be available"); - Some(create_batcher(config.batcher_config.clone(), mempool_client)) + let l1_provider_client = clients + .get_l1_provider_shared_client() + .expect("L1 Provider Client should be available"); + // TODO(guyn): Should also create a gas price shared client and give it to batcher? + let class_manager_client = clients + .get_class_manager_shared_client() + .expect("Class Manager Client should be available"); + Some(create_batcher( + config.batcher_config.clone(), + mempool_client, + l1_provider_client, + class_manager_client, + )) } - ComponentExecutionMode::Disabled | ComponentExecutionMode::Remote => None, + ReactiveComponentExecutionMode::Disabled | ReactiveComponentExecutionMode::Remote => None, }; + + let class_manager = match config.components.class_manager.execution_mode { + ReactiveComponentExecutionMode::LocalExecutionWithRemoteDisabled + | ReactiveComponentExecutionMode::LocalExecutionWithRemoteEnabled => { + let compiler_shared_client = clients + .get_sierra_compiler_shared_client() + .expect("Sierra Compiler Client should be available"); + Some(create_class_manager(config.class_manager_config.clone(), compiler_shared_client)) + } + ReactiveComponentExecutionMode::Disabled | ReactiveComponentExecutionMode::Remote => None, + }; + let consensus_manager = match config.components.consensus_manager.execution_mode { - ComponentExecutionMode::LocalExecutionWithRemoteDisabled - | ComponentExecutionMode::LocalExecutionWithRemoteEnabled => { + ActiveComponentExecutionMode::Enabled => { let batcher_client = clients.get_batcher_shared_client().expect("Batcher Client should be available"); - Some(ConsensusManager::new(config.consensus_manager_config.clone(), batcher_client)) + let state_sync_client = clients + .get_state_sync_shared_client() + .expect("State Sync Client should be available"); + let class_manager_client = clients + .get_class_manager_shared_client() + .expect("Class Manager Client should be available"); + Some(ConsensusManager::new( + config.consensus_manager_config.clone(), + batcher_client, + state_sync_client, + class_manager_client, + )) } - ComponentExecutionMode::Disabled | ComponentExecutionMode::Remote => None, + ActiveComponentExecutionMode::Disabled => None, }; let gateway = match config.components.gateway.execution_mode { - ComponentExecutionMode::LocalExecutionWithRemoteDisabled - | ComponentExecutionMode::LocalExecutionWithRemoteEnabled => { + ReactiveComponentExecutionMode::LocalExecutionWithRemoteDisabled + | ReactiveComponentExecutionMode::LocalExecutionWithRemoteEnabled => { let mempool_client = clients.get_mempool_shared_client().expect("Mempool Client should be available"); - + let state_sync_client = clients + .get_state_sync_shared_client() + .expect("State Sync Client should be available"); + let class_manager_client = clients + .get_class_manager_shared_client() + .expect("Class Manager Client should be available"); Some(create_gateway( config.gateway_config.clone(), - config.rpc_state_reader_config.clone(), - config.compiler_config.clone(), + state_sync_client, mempool_client, + class_manager_client, )) } - ComponentExecutionMode::Disabled | ComponentExecutionMode::Remote => None, + ReactiveComponentExecutionMode::Disabled | ReactiveComponentExecutionMode::Remote => None, }; let http_server = match config.components.http_server.execution_mode { - ComponentExecutionMode::LocalExecutionWithRemoteDisabled - | ComponentExecutionMode::LocalExecutionWithRemoteEnabled => { + ActiveComponentExecutionMode::Enabled => { let gateway_client = clients.get_gateway_shared_client().expect("Gateway Client should be available"); Some(create_http_server(config.http_server_config.clone(), gateway_client)) } - ComponentExecutionMode::Disabled | ComponentExecutionMode::Remote => None, + ActiveComponentExecutionMode::Disabled => None, }; - let (mempool_p2p_propagator, mempool_p2p_runner) = match config - .components - .mempool_p2p - .execution_mode - { - ComponentExecutionMode::LocalExecutionWithRemoteDisabled - | ComponentExecutionMode::LocalExecutionWithRemoteEnabled => { - let gateway_client = - clients.get_gateway_shared_client().expect("Gateway Client should be available"); - let (mempool_p2p_propagator, mempool_p2p_runner) = - create_p2p_propagator_and_runner(config.mempool_p2p_config.clone(), gateway_client); - (Some(mempool_p2p_propagator), Some(mempool_p2p_runner)) - } - ComponentExecutionMode::Disabled | ComponentExecutionMode::Remote => (None, None), - }; + let (mempool_p2p_propagator, mempool_p2p_runner) = + match config.components.mempool_p2p.execution_mode { + ReactiveComponentExecutionMode::LocalExecutionWithRemoteDisabled + | ReactiveComponentExecutionMode::LocalExecutionWithRemoteEnabled => { + let gateway_client = clients + .get_gateway_shared_client() + .expect("Gateway Client should be available"); + let class_manager_client = clients + .get_class_manager_shared_client() + .expect("Class Manager Client should be available"); + let mempool_p2p_propagator_client = clients + .get_mempool_p2p_propagator_shared_client() + .expect("Mempool P2p Propagator Client should be available"); + let (mempool_p2p_propagator, mempool_p2p_runner) = create_p2p_propagator_and_runner( + config.mempool_p2p_config.clone(), + gateway_client, + class_manager_client, + mempool_p2p_propagator_client, + ); + (Some(mempool_p2p_propagator), Some(mempool_p2p_runner)) + } + ReactiveComponentExecutionMode::Disabled | ReactiveComponentExecutionMode::Remote => { + (None, None) + } + }; let mempool = match config.components.mempool.execution_mode { - ComponentExecutionMode::LocalExecutionWithRemoteDisabled - | ComponentExecutionMode::LocalExecutionWithRemoteEnabled => { + ReactiveComponentExecutionMode::LocalExecutionWithRemoteDisabled + | ReactiveComponentExecutionMode::LocalExecutionWithRemoteEnabled => { let mempool_p2p_propagator_client = clients .get_mempool_p2p_propagator_shared_client() .expect("Propagator Client should be available"); - let mempool = create_mempool(mempool_p2p_propagator_client); + let mempool = + create_mempool(config.mempool_config.clone(), mempool_p2p_propagator_client); Some(mempool) } - ComponentExecutionMode::Disabled | ComponentExecutionMode::Remote => None, + ReactiveComponentExecutionMode::Disabled | ReactiveComponentExecutionMode::Remote => None, }; let monitoring_endpoint = match config.components.monitoring_endpoint.execution_mode { - ComponentExecutionMode::LocalExecutionWithRemoteEnabled => Some( - create_monitoring_endpoint(config.monitoring_endpoint_config.clone(), VERSION_FULL), - ), - ComponentExecutionMode::LocalExecutionWithRemoteDisabled => None, - ComponentExecutionMode::Disabled | ComponentExecutionMode::Remote => None, + ActiveComponentExecutionMode::Enabled => Some(create_monitoring_endpoint( + config.monitoring_endpoint_config.clone(), + VERSION_FULL, + )), + ActiveComponentExecutionMode::Disabled => None, + }; + + let (state_sync, state_sync_runner) = match config.components.state_sync.execution_mode { + ReactiveComponentExecutionMode::LocalExecutionWithRemoteDisabled + | ReactiveComponentExecutionMode::LocalExecutionWithRemoteEnabled => { + let class_manager_client = clients + .get_class_manager_shared_client() + .expect("Class Manager Client should be available"); + let (state_sync, state_sync_runner) = create_state_sync_and_runner( + config.state_sync_config.clone(), + class_manager_client, + ); + (Some(state_sync), Some(state_sync_runner)) + } + ReactiveComponentExecutionMode::Disabled | ReactiveComponentExecutionMode::Remote => { + (None, None) + } + }; + + let l1_scraper = match config.components.l1_scraper.execution_mode { + ActiveComponentExecutionMode::Enabled => { + let l1_provider_client = clients.get_l1_provider_shared_client().unwrap(); + let l1_scraper_config = config.l1_scraper_config.clone(); + let base_layer = EthereumBaseLayerContract::new(config.base_layer_config.clone()); + Some( + L1Scraper::new( + l1_scraper_config, + l1_provider_client, + base_layer, + event_identifiers_to_track(), + ) + .await + .unwrap(), + ) + } + ActiveComponentExecutionMode::Disabled => None, + }; + + // Must be initialized after the l1 scraper, since the provider's (L2) startup height is derived + // from the scraper's (L1) startup height (unless the former is overridden via the config). + let l1_provider = match config.components.l1_provider.execution_mode { + ReactiveComponentExecutionMode::LocalExecutionWithRemoteDisabled + | ReactiveComponentExecutionMode::LocalExecutionWithRemoteEnabled => { + let provider_startup_height = match &l1_scraper { + Some(l1_scraper) => { + let (base_layer, l1_scraper_start_l1_height) = + (l1_scraper.base_layer.clone(), l1_scraper.last_l1_block_processed.number); + base_layer + .get_proved_block_at(l1_scraper_start_l1_height) + .await + .map(|block| block.number) + // This will likely only fail on tests, or on nodes that want to reexecute from + // genesis. The former should override the height, or setup Anvil accordingly, and + // the latter should use the correct L1 height. + .inspect_err(|err|{ + warn!("Error while attempting to get the L2 block at the L1 height the + scraper was initialized on. This is either due to running a test with + faulty Anvil state, or if the scraper was initialized too far back. + Attempting to use provider startup height override (read its docstring + before using!).\n {err}")}) + .ok().or(config.l1_provider_config.provider_startup_height_override) + } + None => { + warn!( + "L1 Scraper is disabled, attempting to use provider startup height \ + override in order to find L1 Provider startup height (read its docstring \ + before using!)" + ); + config.l1_provider_config.provider_startup_height_override + } + }; + let provider_startup_height = provider_startup_height.expect( + "Cannot determine L1 Provider startup height. Either enable the L1 Scraper on \ + height that is at least as old as L2 genesis, or override provider startup \ + height (read its docstring before using)", + ); + + Some(create_l1_provider( + config.l1_provider_config, + clients.get_l1_provider_shared_client().unwrap(), + clients.get_state_sync_shared_client().unwrap(), + provider_startup_height, + )) + } + ReactiveComponentExecutionMode::Disabled | ReactiveComponentExecutionMode::Remote => None, + }; + + let l1_gas_price_provider = match config.components.l1_gas_price_provider.execution_mode { + ReactiveComponentExecutionMode::LocalExecutionWithRemoteDisabled + | ReactiveComponentExecutionMode::LocalExecutionWithRemoteEnabled => { + Some(L1GasPriceProvider::new(config.l1_gas_price_provider_config.clone())) + } + ReactiveComponentExecutionMode::Disabled | ReactiveComponentExecutionMode::Remote => None, + }; + let l1_gas_price_scraper = match config.components.l1_gas_price_scraper.execution_mode { + ActiveComponentExecutionMode::Enabled => { + let l1_gas_price_client = clients.get_l1_gas_price_shared_client().unwrap(); + let l1_gas_price_scraper_config = config.l1_gas_price_scraper_config.clone(); + let base_layer = EthereumBaseLayerContract::new(config.base_layer_config.clone()); + + Some(L1GasPriceScraper::new( + l1_gas_price_scraper_config, + l1_gas_price_client, + base_layer, + )) + } + ActiveComponentExecutionMode::Disabled => None, + }; + + let sierra_compiler = match config.components.sierra_compiler.execution_mode { + ReactiveComponentExecutionMode::LocalExecutionWithRemoteDisabled + | ReactiveComponentExecutionMode::LocalExecutionWithRemoteEnabled => { + Some(create_sierra_compiler(config.compiler_config.clone())) + } + ReactiveComponentExecutionMode::Disabled | ReactiveComponentExecutionMode::Remote => None, }; SequencerNodeComponents { batcher, + class_manager, consensus_manager, gateway, http_server, + l1_scraper, + l1_provider, + l1_gas_price_scraper, + l1_gas_price_provider, mempool, monitoring_endpoint, mempool_p2p_propagator, mempool_p2p_runner, + sierra_compiler, + state_sync, + state_sync_runner, } } diff --git a/crates/starknet_sequencer_node/src/config/component_config.rs b/crates/starknet_sequencer_node/src/config/component_config.rs index fa5d3fcfc6a..fcfa6ba4194 100644 --- a/crates/starknet_sequencer_node/src/config/component_config.rs +++ b/crates/starknet_sequencer_node/src/config/component_config.rs @@ -5,53 +5,107 @@ use papyrus_config::{ParamPath, SerializedParam}; use serde::{Deserialize, Serialize}; use validator::Validate; -use crate::config::component_execution_config::ComponentExecutionConfig; +use crate::config::component_execution_config::{ + ActiveComponentExecutionConfig, + ReactiveComponentExecutionConfig, +}; /// The components configuration. -#[derive(Clone, Debug, Serialize, Deserialize, Validate, PartialEq)] +#[derive(Clone, Debug, Default, Serialize, Deserialize, Validate, PartialEq)] pub struct ComponentConfig { + // Reactive component configs. #[validate] - pub batcher: ComponentExecutionConfig, + pub batcher: ReactiveComponentExecutionConfig, #[validate] - pub consensus_manager: ComponentExecutionConfig, + pub class_manager: ReactiveComponentExecutionConfig, #[validate] - pub gateway: ComponentExecutionConfig, + pub gateway: ReactiveComponentExecutionConfig, #[validate] - pub http_server: ComponentExecutionConfig, + pub mempool: ReactiveComponentExecutionConfig, #[validate] - pub mempool: ComponentExecutionConfig, + pub mempool_p2p: ReactiveComponentExecutionConfig, #[validate] - pub mempool_p2p: ComponentExecutionConfig, + pub sierra_compiler: ReactiveComponentExecutionConfig, #[validate] - pub monitoring_endpoint: ComponentExecutionConfig, -} + pub state_sync: ReactiveComponentExecutionConfig, + #[validate] + pub l1_provider: ReactiveComponentExecutionConfig, + #[validate] + pub l1_gas_price_provider: ReactiveComponentExecutionConfig, -impl Default for ComponentConfig { - fn default() -> Self { - Self { - batcher: ComponentExecutionConfig::batcher_default_config(), - consensus_manager: ComponentExecutionConfig::consensus_manager_default_config(), - gateway: ComponentExecutionConfig::gateway_default_config(), - http_server: ComponentExecutionConfig::http_server_default_config(), - mempool: ComponentExecutionConfig::mempool_default_config(), - mempool_p2p: ComponentExecutionConfig::mempool_p2p_default_config(), - monitoring_endpoint: ComponentExecutionConfig::monitoring_endpoint_default_config(), - } - } + // Active component configs. + #[validate] + pub consensus_manager: ActiveComponentExecutionConfig, + #[validate] + pub http_server: ActiveComponentExecutionConfig, + #[validate] + pub l1_scraper: ActiveComponentExecutionConfig, + #[validate] + pub l1_gas_price_scraper: ActiveComponentExecutionConfig, + #[validate] + pub monitoring_endpoint: ActiveComponentExecutionConfig, } impl SerializeConfig for ComponentConfig { fn dump(&self) -> BTreeMap { let sub_configs = vec![ append_sub_config_name(self.batcher.dump(), "batcher"), + append_sub_config_name(self.class_manager.dump(), "class_manager"), append_sub_config_name(self.consensus_manager.dump(), "consensus_manager"), append_sub_config_name(self.gateway.dump(), "gateway"), append_sub_config_name(self.http_server.dump(), "http_server"), append_sub_config_name(self.mempool.dump(), "mempool"), + append_sub_config_name(self.l1_provider.dump(), "l1_provider"), + append_sub_config_name(self.l1_gas_price_provider.dump(), "l1_gas_price_provider"), + append_sub_config_name(self.l1_scraper.dump(), "l1_scraper"), + append_sub_config_name(self.l1_gas_price_scraper.dump(), "l1_gas_price_scraper"), append_sub_config_name(self.mempool_p2p.dump(), "mempool_p2p"), append_sub_config_name(self.monitoring_endpoint.dump(), "monitoring_endpoint"), + append_sub_config_name(self.sierra_compiler.dump(), "sierra_compiler"), + append_sub_config_name(self.state_sync.dump(), "state_sync"), ]; sub_configs.into_iter().flatten().collect() } } + +impl ComponentConfig { + pub fn disabled() -> ComponentConfig { + ComponentConfig { + batcher: ReactiveComponentExecutionConfig::disabled(), + class_manager: ReactiveComponentExecutionConfig::disabled(), + gateway: ReactiveComponentExecutionConfig::disabled(), + mempool: ReactiveComponentExecutionConfig::disabled(), + mempool_p2p: ReactiveComponentExecutionConfig::disabled(), + sierra_compiler: ReactiveComponentExecutionConfig::disabled(), + state_sync: ReactiveComponentExecutionConfig::disabled(), + l1_provider: ReactiveComponentExecutionConfig::disabled(), + l1_gas_price_provider: ReactiveComponentExecutionConfig::disabled(), + l1_scraper: ActiveComponentExecutionConfig::disabled(), + l1_gas_price_scraper: ActiveComponentExecutionConfig::disabled(), + consensus_manager: ActiveComponentExecutionConfig::disabled(), + http_server: ActiveComponentExecutionConfig::disabled(), + monitoring_endpoint: ActiveComponentExecutionConfig::disabled(), + } + } + + #[cfg(any(feature = "testing", test))] + pub fn set_urls_to_localhost(&mut self) { + self.batcher.set_url_to_localhost(); + self.class_manager.set_url_to_localhost(); + self.gateway.set_url_to_localhost(); + self.mempool.set_url_to_localhost(); + self.mempool_p2p.set_url_to_localhost(); + self.sierra_compiler.set_url_to_localhost(); + self.state_sync.set_url_to_localhost(); + self.l1_provider.set_url_to_localhost(); + self.l1_gas_price_provider.set_url_to_localhost(); + } +} + +#[cfg(any(feature = "testing", test))] +pub fn set_urls_to_localhost(component_configs: &mut [ComponentConfig]) { + for component_config in component_configs.iter_mut() { + component_config.set_urls_to_localhost(); + } +} diff --git a/crates/starknet_sequencer_node/src/config/component_execution_config.rs b/crates/starknet_sequencer_node/src/config/component_execution_config.rs index 61a8a1d0ee0..1ce38c1b5bd 100644 --- a/crates/starknet_sequencer_node/src/config/component_execution_config.rs +++ b/crates/starknet_sequencer_node/src/config/component_execution_config.rs @@ -1,50 +1,90 @@ use std::collections::BTreeMap; +use std::net::{IpAddr, Ipv4Addr, ToSocketAddrs}; -use papyrus_config::dumping::{ser_optional_sub_config, ser_param, SerializeConfig}; +use papyrus_config::dumping::{append_sub_config_name, ser_param, SerializeConfig}; use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; use serde::{Deserialize, Serialize}; -use starknet_sequencer_infra::component_definitions::{ - LocalServerConfig, - RemoteClientConfig, - RemoteServerConfig, -}; +use starknet_sequencer_infra::component_definitions::{LocalServerConfig, RemoteClientConfig}; use tracing::error; use validator::{Validate, ValidationError}; +use crate::config::config_utils::create_validation_error; + +const DEFAULT_URL: &str = "localhost"; +const DEFAULT_IP: IpAddr = IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)); +const DEFAULT_INVALID_PORT: u16 = 0; + +pub const MAX_CONCURRENCY: usize = 10; + #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -pub enum ComponentExecutionMode { +pub enum ReactiveComponentExecutionMode { Disabled, Remote, LocalExecutionWithRemoteEnabled, LocalExecutionWithRemoteDisabled, } +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +pub enum ActiveComponentExecutionMode { + Disabled, + Enabled, +} + // TODO(Lev/Tsabary): When papyrus_config will support it, change to include communication config in // the enum. -/// The single component configuration. +/// Reactive component configuration. #[derive(Clone, Debug, Serialize, Deserialize, Validate, PartialEq)] -#[validate(schema(function = "validate_single_component_config"))] -pub struct ComponentExecutionConfig { - pub execution_mode: ComponentExecutionMode, - pub local_server_config: Option, - pub remote_client_config: Option, - pub remote_server_config: Option, +#[validate(schema(function = "validate_reactive_component_execution_config"))] +pub struct ReactiveComponentExecutionConfig { + pub execution_mode: ReactiveComponentExecutionMode, + pub local_server_config: LocalServerConfig, + pub remote_client_config: RemoteClientConfig, + #[validate(custom = "validate_max_concurrency")] + pub max_concurrency: usize, + pub url: String, + pub ip: IpAddr, + pub port: u16, } -impl SerializeConfig for ComponentExecutionConfig { +impl SerializeConfig for ReactiveComponentExecutionConfig { fn dump(&self) -> BTreeMap { - let members = BTreeMap::from_iter([ser_param( - "execution_mode", - &self.execution_mode, - "The component execution mode.", - ParamPrivacyInput::Public, - )]); + let members = BTreeMap::from_iter([ + ser_param( + "execution_mode", + &self.execution_mode, + "The component execution mode.", + ParamPrivacyInput::Public, + ), + ser_param( + "max_concurrency", + &self.max_concurrency, + "The maximum number of concurrent requests handling.", + ParamPrivacyInput::Public, + ), + ser_param( + "url", + &self.url, + "URL of the remote component server.", + ParamPrivacyInput::Public, + ), + ser_param( + "ip", + &self.ip.to_string(), + "Binding address of the remote component server.", + ParamPrivacyInput::Public, + ), + ser_param( + "port", + &self.port, + "Listening port of the remote component server.", + ParamPrivacyInput::Public, + ), + ]); vec![ members, - ser_optional_sub_config(&self.local_server_config, "local_server_config"), - ser_optional_sub_config(&self.remote_client_config, "remote_client_config"), - ser_optional_sub_config(&self.remote_server_config, "remote_server_config"), + append_sub_config_name(self.local_server_config.dump(), "local_server_config"), + append_sub_config_name(self.remote_client_config.dump(), "remote_client_config"), ] .into_iter() .flatten() @@ -52,111 +92,180 @@ impl SerializeConfig for ComponentExecutionConfig { } } -impl Default for ComponentExecutionConfig { +impl Default for ReactiveComponentExecutionConfig { fn default() -> Self { - Self { - execution_mode: ComponentExecutionMode::LocalExecutionWithRemoteDisabled, - local_server_config: Some(LocalServerConfig::default()), - remote_client_config: None, - remote_server_config: None, - } + Self::local_with_remote_disabled() } } -/// Specific components default configurations. -impl ComponentExecutionConfig { - pub fn gateway_default_config() -> Self { +impl ReactiveComponentExecutionConfig { + pub fn disabled() -> Self { Self { - execution_mode: ComponentExecutionMode::LocalExecutionWithRemoteDisabled, - local_server_config: Some(LocalServerConfig::default()), - remote_client_config: None, - remote_server_config: None, + execution_mode: ReactiveComponentExecutionMode::Disabled, + local_server_config: LocalServerConfig::default(), + remote_client_config: RemoteClientConfig::default(), + max_concurrency: MAX_CONCURRENCY, + url: DEFAULT_URL.to_string(), + ip: DEFAULT_IP, + port: DEFAULT_INVALID_PORT, } } - // TODO(Tsabary/Lev): There's a bug here: the http server component does not need a local nor a - // remote config. However, the validation function requires that at least one of them is set. As - // a workaround I've set the local one, but this should be addressed. - pub fn http_server_default_config() -> Self { + pub fn remote(url: String, ip: IpAddr, port: u16) -> Self { Self { - execution_mode: ComponentExecutionMode::LocalExecutionWithRemoteEnabled, - local_server_config: Some(LocalServerConfig::default()), - remote_client_config: None, - remote_server_config: Some(RemoteServerConfig::default()), + execution_mode: ReactiveComponentExecutionMode::Remote, + local_server_config: LocalServerConfig::default(), + max_concurrency: MAX_CONCURRENCY, + remote_client_config: RemoteClientConfig::default(), + url, + ip, + port, } } - // TODO(Tsabary/Lev): There's a bug here: the monitoring endpoint component does not - // need a local nor a remote config. However, the validation function requires that at least - // one of them is set. As a workaround I've set the local one, but this should be addressed. - pub fn monitoring_endpoint_default_config() -> Self { + pub fn local_with_remote_enabled(url: String, ip: IpAddr, port: u16) -> Self { Self { - execution_mode: ComponentExecutionMode::LocalExecutionWithRemoteEnabled, - local_server_config: Some(LocalServerConfig::default()), - remote_client_config: None, - remote_server_config: Some(RemoteServerConfig::default()), + execution_mode: ReactiveComponentExecutionMode::LocalExecutionWithRemoteEnabled, + local_server_config: LocalServerConfig::default(), + remote_client_config: RemoteClientConfig::default(), + max_concurrency: MAX_CONCURRENCY, + url, + ip, + port, } } - pub fn mempool_default_config() -> Self { + pub fn local_with_remote_disabled() -> Self { Self { - execution_mode: ComponentExecutionMode::LocalExecutionWithRemoteDisabled, - local_server_config: Some(LocalServerConfig::default()), - remote_client_config: None, - remote_server_config: None, + execution_mode: ReactiveComponentExecutionMode::LocalExecutionWithRemoteDisabled, + local_server_config: LocalServerConfig::default(), + remote_client_config: RemoteClientConfig::default(), + max_concurrency: MAX_CONCURRENCY, + url: DEFAULT_URL.to_string(), + ip: DEFAULT_IP, + port: DEFAULT_INVALID_PORT, } } + fn is_valid_socket(&self) -> bool { + self.port != 0 + } - pub fn batcher_default_config() -> Self { - Self { - execution_mode: ComponentExecutionMode::LocalExecutionWithRemoteDisabled, - local_server_config: Some(LocalServerConfig::default()), - remote_client_config: None, - remote_server_config: None, - } + #[cfg(any(feature = "testing", test))] + pub fn set_url_to_localhost(&mut self) { + self.url = Ipv4Addr::LOCALHOST.to_string(); } +} - pub fn consensus_manager_default_config() -> Self { - Self { - execution_mode: ComponentExecutionMode::LocalExecutionWithRemoteDisabled, - local_server_config: Some(LocalServerConfig::default()), - remote_client_config: None, - remote_server_config: None, - } +/// Active component configuration. +#[derive(Clone, Debug, Serialize, Deserialize, Validate, PartialEq)] +#[validate(schema(function = "validate_active_component_execution_config"))] +pub struct ActiveComponentExecutionConfig { + pub execution_mode: ActiveComponentExecutionMode, +} + +impl SerializeConfig for ActiveComponentExecutionConfig { + fn dump(&self) -> BTreeMap { + BTreeMap::from_iter([ser_param( + "execution_mode", + &self.execution_mode, + "The component execution mode.", + ParamPrivacyInput::Public, + )]) } +} - pub fn mempool_p2p_default_config() -> Self { - Self { - execution_mode: ComponentExecutionMode::LocalExecutionWithRemoteDisabled, - local_server_config: Some(LocalServerConfig::default()), - remote_client_config: None, - remote_server_config: None, - } +impl Default for ActiveComponentExecutionConfig { + fn default() -> Self { + ActiveComponentExecutionConfig::enabled() + } +} + +impl ActiveComponentExecutionConfig { + pub fn disabled() -> Self { + Self { execution_mode: ActiveComponentExecutionMode::Disabled } + } + + pub fn enabled() -> Self { + Self { execution_mode: ActiveComponentExecutionMode::Enabled } } } -pub fn validate_single_component_config( - component_config: &ComponentExecutionConfig, +// Validates the configured URL. If the URL is invalid, it returns an error. +fn validate_url(url: &str) -> Result<(), ValidationError> { + let arbitrary_port: u16 = 0; + let socket_addrs = (url, arbitrary_port) + .to_socket_addrs() + .map_err(|e| create_url_validation_error(format!("Failed to resolve url IP: {}", e)))?; + + if socket_addrs.count() > 0 { + Ok(()) + } else { + Err(create_url_validation_error("No IP address found for the domain".to_string())) + } +} + +fn create_url_validation_error(error_msg: String) -> ValidationError { + create_validation_error(error_msg, "Failed to resolve url IP", "Ensure the url is valid.") +} + +// Validate the configured max concurrency. If the max concurrency is invalid, it returns an error. +fn validate_max_concurrency(max_concurrency: usize) -> Result<(), ValidationError> { + if max_concurrency > 0 { + Ok(()) + } else { + Err(create_validation_error( + format!("Invalid max_concurrency: {}", max_concurrency), + "Invalid max concurrency", + "Ensure the max concurrency is greater than 0.", + )) + } +} + +fn validate_reactive_component_execution_config( + component_config: &ReactiveComponentExecutionConfig, ) -> Result<(), ValidationError> { - match ( - component_config.execution_mode.clone(), - component_config.local_server_config.is_some(), - component_config.remote_client_config.is_some(), - component_config.remote_server_config.is_some(), - ) { - (ComponentExecutionMode::Disabled, false, false, false) => Ok(()), - (ComponentExecutionMode::Remote, false, true, false) => Ok(()), - (ComponentExecutionMode::LocalExecutionWithRemoteEnabled, true, false, true) => Ok(()), - (ComponentExecutionMode::LocalExecutionWithRemoteDisabled, true, false, false) => Ok(()), - (mode, local_server_config, remote_client_config, remote_server_config) => { + match (component_config.execution_mode.clone(), component_config.is_valid_socket()) { + (ReactiveComponentExecutionMode::Disabled, _) => Ok(()), + (ReactiveComponentExecutionMode::Remote, true) => { + validate_url(component_config.url.as_str()) + } + (ReactiveComponentExecutionMode::LocalExecutionWithRemoteEnabled, true) => { + validate_url(component_config.url.as_str()) + } + (ReactiveComponentExecutionMode::LocalExecutionWithRemoteDisabled, _) => Ok(()), + (mode, socket) => { error!( - "Invalid component execution configuration: mode: {:?}, local_server_config: \ - {:?}, remote_client_config: {:?}, remote_server_config: {:?}", - mode, local_server_config, remote_client_config, remote_server_config + "Invalid reactive component execution configuration: mode: {:?}, socket: {:?}", + mode, socket ); - let mut error = ValidationError::new("Invalid component execution configuration."); + let mut error = + ValidationError::new("Invalid reactive component execution configuration."); error.message = Some("Ensure settings align with the chosen execution mode.".into()); Err(error) } } } + +fn validate_active_component_execution_config( + _component_config: &ActiveComponentExecutionConfig, +) -> Result<(), ValidationError> { + Ok(()) +} + +// There are components that are described with a reactive mode setting, however, result in the +// creation of two components: one reactive and one active. The defined behavior is such that +// the active component is active if and only if the local component is running locally. The +// following function applies this logic. +impl From for ActiveComponentExecutionMode { + fn from(mode: ReactiveComponentExecutionMode) -> Self { + match mode { + ReactiveComponentExecutionMode::Disabled | ReactiveComponentExecutionMode::Remote => { + ActiveComponentExecutionMode::Disabled + } + ReactiveComponentExecutionMode::LocalExecutionWithRemoteEnabled + | ReactiveComponentExecutionMode::LocalExecutionWithRemoteDisabled => { + ActiveComponentExecutionMode::Enabled + } + } + } +} diff --git a/crates/starknet_sequencer_node/src/config/config_test.rs b/crates/starknet_sequencer_node/src/config/config_test.rs index 1975e0447ad..743e36b9de4 100644 --- a/crates/starknet_sequencer_node/src/config/config_test.rs +++ b/crates/starknet_sequencer_node/src/config/config_test.rs @@ -1,59 +1,87 @@ -use std::collections::HashSet; use std::env; use std::fs::File; +use std::net::{IpAddr, Ipv4Addr}; -use assert_json_diff::assert_json_eq; -use assert_matches::assert_matches; use colored::Colorize; -use infra_utils::path::resolve_project_relative_path; use papyrus_config::dumping::SerializeConfig; -use papyrus_config::validators::config_validate; -use papyrus_config::SerializedParam; use rstest::rstest; -use starknet_sequencer_infra::component_definitions::{ - LocalServerConfig, - RemoteClientConfig, - RemoteServerConfig, -}; +use starknet_infra_utils::path::resolve_project_relative_path; +use starknet_infra_utils::test_utils::assert_json_eq; +use starknet_sequencer_infra::component_definitions::{LocalServerConfig, RemoteClientConfig}; use validator::Validate; -use crate::config::component_execution_config::{ComponentExecutionConfig, ComponentExecutionMode}; +use crate::config::component_execution_config::{ + ReactiveComponentExecutionConfig, + ReactiveComponentExecutionMode, +}; +use crate::config::monitoring::MonitoringConfig; use crate::config::node_config::{ SequencerNodeConfig, CONFIG_NON_POINTERS_WHITELIST, CONFIG_POINTERS, DEFAULT_CONFIG_PATH, }; -use crate::config::test_utils::{create_test_config_load_args, RequiredParams}; -const LOCAL_EXECUTION_MODE: ComponentExecutionMode = - ComponentExecutionMode::LocalExecutionWithRemoteDisabled; -const ENABLE_REMOTE_CONNECTION_MODE: ComponentExecutionMode = - ComponentExecutionMode::LocalExecutionWithRemoteEnabled; +const LOCAL_EXECUTION_MODE: ReactiveComponentExecutionMode = + ReactiveComponentExecutionMode::LocalExecutionWithRemoteDisabled; +const ENABLE_REMOTE_CONNECTION_MODE: ReactiveComponentExecutionMode = + ReactiveComponentExecutionMode::LocalExecutionWithRemoteEnabled; -/// Test the validation of the struct ComponentExecutionConfig. +const VALID_URL: &str = "www.google.com"; +const VALID_IP: IpAddr = IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)); +const VALID_PORT: u16 = 8080; + +/// Test the validation of the struct ReactiveComponentExecutionConfig. /// Validates that execution mode of the component and the local/remote config are at sync. #[rstest] -#[case::local(ComponentExecutionMode::Disabled, None, None, None)] -#[case::local(ComponentExecutionMode::Remote, None, Some(RemoteClientConfig::default()), None)] -#[case::local(LOCAL_EXECUTION_MODE, Some(LocalServerConfig::default()), None, None)] +#[case::local( + ReactiveComponentExecutionMode::Disabled, + LocalServerConfig::default(), + RemoteClientConfig::default(), + VALID_URL, + VALID_IP, + VALID_PORT +)] +#[case::local( + ReactiveComponentExecutionMode::Remote, + LocalServerConfig::default(), + RemoteClientConfig::default(), + VALID_URL, + VALID_IP, + VALID_PORT +)] +#[case::local( + LOCAL_EXECUTION_MODE, + LocalServerConfig::default(), + RemoteClientConfig::default(), + VALID_URL, + VALID_IP, + VALID_PORT +)] #[case::remote( ENABLE_REMOTE_CONNECTION_MODE, - Some(LocalServerConfig::default()), - None, - Some(RemoteServerConfig::default()) + LocalServerConfig::default(), + RemoteClientConfig::default(), + VALID_URL, + VALID_IP, + VALID_PORT )] -fn test_valid_component_execution_config( - #[case] execution_mode: ComponentExecutionMode, - #[case] local_server_config: Option, - #[case] remote_client_config: Option, - #[case] remote_server_config: Option, +fn valid_component_execution_config( + #[case] execution_mode: ReactiveComponentExecutionMode, + #[case] local_server_config: LocalServerConfig, + #[case] remote_client_config: RemoteClientConfig, + #[case] url: &str, + #[case] ip: IpAddr, + #[case] port: u16, ) { - let component_exe_config = ComponentExecutionConfig { + let component_exe_config = ReactiveComponentExecutionConfig { execution_mode, local_server_config, remote_client_config, - remote_server_config, + max_concurrency: 1, + url: url.to_string(), + ip, + port, }; assert_eq!(component_exe_config.validate(), Ok(())); } @@ -62,19 +90,16 @@ fn test_valid_component_execution_config( /// date. To update the default config file, run: /// cargo run --bin sequencer_dump_config -q #[test] -fn test_default_config_file_is_up_to_date() { +fn default_config_file_is_up_to_date() { env::set_current_dir(resolve_project_relative_path("").unwrap()) .expect("Couldn't set working dir."); let from_default_config_file: serde_json::Value = serde_json::from_reader(File::open(DEFAULT_CONFIG_PATH).unwrap()).unwrap(); - let default_config = SequencerNodeConfig::default(); - assert_matches!(default_config.validate(), Ok(())); - // Create a temporary file and dump the default config to it. let mut tmp_file_path = env::temp_dir(); tmp_file_path.push("cfg.json"); - default_config + SequencerNodeConfig::default() .dump_to_file( &CONFIG_POINTERS, &CONFIG_NON_POINTERS_WHITELIST, @@ -86,47 +111,33 @@ fn test_default_config_file_is_up_to_date() { let from_code: serde_json::Value = serde_json::from_reader(File::open(tmp_file_path).unwrap()).unwrap(); - println!( - "{}", - "Default config file doesn't match the default NodeConfig implementation. Please update \ - it using the sequencer_dump_config binary." + let error_message = format!( + "{}\n{}", + "Default config file doesn't match the default SequencerNodeConfig implementation. Please \ + update it using the sequencer_dump_config binary." .purple() - .bold() - ); - println!( + .bold(), "Diffs shown below (default config file <<>> dump of SequencerNodeConfig::default())." ); - assert_json_eq!(from_default_config_file, from_code) + assert_json_eq(&from_default_config_file, &from_code, error_message); } -/// Tests parsing a node config without additional args. #[test] -fn test_config_parsing() { - let required_params = RequiredParams::create_for_testing(); - let args = create_test_config_load_args(required_params); - let config = SequencerNodeConfig::load_and_process(args); - let config = config.expect("Parsing function failed."); - - let result = config_validate(&config); - assert_matches!(result, Ok(_), "Expected Ok but got {:?}", result); +fn validate_config_success() { + let config = SequencerNodeConfig::default(); + assert!(config.validate().is_ok()); } -/// Tests compatibility of the required parameter settings: required params (containing required -/// pointer targets) and test util struct. -#[test] -fn test_required_params_setting() { - // Load the default config file. - let file = - std::fs::File::open(resolve_project_relative_path(DEFAULT_CONFIG_PATH).unwrap()).unwrap(); - let mut deserialized = serde_json::from_reader::<_, serde_json::Value>(file).unwrap(); - let expected_required_params = deserialized.as_object_mut().unwrap(); - expected_required_params.retain(|_, value| { - let param = serde_json::from_value::(value.clone()).unwrap(); - param.is_required() - }); - let expected_required_keys = - expected_required_params.keys().cloned().collect::>(); - - let required_params: HashSet = RequiredParams::field_names().into_iter().collect(); - assert_eq!(required_params, expected_required_keys); +#[rstest] +#[case::monitoring_and_profiling(true, true, true)] +#[case::monitoring_without_profiling(true, false, true)] +#[case::no_monitoring_nor_profiling(false, false, true)] +#[case::no_monitoring_with_profiling(false, true, false)] +fn monitoring_config( + #[case] collect_metrics: bool, + #[case] collect_profiling_metrics: bool, + #[case] expected_successful_validation: bool, +) { + let component_exe_config = MonitoringConfig { collect_metrics, collect_profiling_metrics }; + assert_eq!(component_exe_config.validate().is_ok(), expected_successful_validation); } diff --git a/crates/starknet_sequencer_node/src/config/config_utils.rs b/crates/starknet_sequencer_node/src/config/config_utils.rs new file mode 100644 index 00000000000..e37398e713d --- /dev/null +++ b/crates/starknet_sequencer_node/src/config/config_utils.rs @@ -0,0 +1,231 @@ +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +use papyrus_config::dumping::{ + combine_config_map_and_pointers, + ConfigPointers, + Pointers, + SerializeConfig, +}; +use serde_json::{to_value, Map, Value}; +use starknet_monitoring_endpoint::config::MonitoringEndpointConfig; +use tracing::{error, info}; +use validator::ValidationError; + +use crate::config::component_config::ComponentConfig; +use crate::config::definitions::ConfigPointersMap; +use crate::config::node_config::{ + SequencerNodeConfig, + CONFIG_NON_POINTERS_WHITELIST, + CONFIG_POINTERS, + POINTER_TARGET_VALUE, +}; +use crate::utils::load_and_validate_config; + +pub(crate) fn create_validation_error( + error_msg: String, + validate_code: &'static str, + validate_error_msg: &'static str, +) -> ValidationError { + error!(error_msg); + let mut error = ValidationError::new(validate_code); + error.message = Some(validate_error_msg.into()); + error +} +/// Transforms a nested JSON dictionary object into a simplified JSON dictionary object by +/// extracting specific values from the inner dictionaries. +/// +/// # Parameters +/// - `config_map`: A reference to a `serde_json::Value` that must be a JSON dictionary object. Each +/// key in the object maps to another JSON dictionary object. +/// +/// # Returns +/// - A `serde_json::Value` dictionary object where: +/// - Each key is preserved from the top-level dictionary. +/// - Each value corresponds to the `"value"` field of the nested JSON dictionary under the +/// original key. +/// +/// # Panics +/// This function panics if the provided `config_map` is not a JSON dictionary object. +pub fn config_to_preset(config_map: &Value) -> Value { + // Ensure the config_map is a JSON object. + if let Value::Object(map) = config_map { + let mut result = Map::new(); + + for (key, value) in map { + if let Value::Object(inner_map) = value { + // Extract the value. + if let Some(inner_value) = inner_map.get("value") { + // Add it to the result map + result.insert(key.clone(), inner_value.clone()); + } + } + } + + // Return the transformed result as a JSON object. + Value::Object(result) + } else { + panic!("Config map is not a JSON object: {:?}", config_map); + } +} + +/// Dumps the input JSON data to a file at the specified path. +pub fn dump_json_data(json_data: Value, file_path: &PathBuf) { + // Serialize the JSON data to a pretty-printed string + let json_string = serde_json::to_string_pretty(&json_data).unwrap(); + + // Write the JSON string to a file + let mut file = File::create(file_path).unwrap(); + file.write_all(json_string.as_bytes()).unwrap(); + + // Add an extra newline after the JSON content. + file.write_all(b"\n").unwrap(); + + file.flush().unwrap(); + + info!("Writing required config changes to: {:?}", file_path); +} + +// TODO(Tsabary): unify with the function of DeploymentBaseAppConfig. +pub fn dump_config_file( + config: SequencerNodeConfig, + pointers: &ConfigPointers, + non_pointer_params: &Pointers, + config_path: &PathBuf, +) { + // Create the entire mapping of the config and the pointers, without the required params. + let config_as_map = + combine_config_map_and_pointers(config.dump(), pointers, non_pointer_params).unwrap(); + + // Extract only the required fields from the config map. + let preset = config_to_preset(&config_as_map); + + validate_all_pointer_targets_set(preset.clone()).expect("Pointer target not set"); + + // Dump the preset to a file, return its path. + dump_json_data(preset, config_path); + assert!(config_path.exists(), "File does not exist: {:?}", config_path); +} + +// TODO(Nadin): Consider adding methods to ConfigPointers to encapsulate related functionality. +fn validate_all_pointer_targets_set(preset: Value) -> Result<(), ValidationError> { + if let Some(preset_map) = preset.as_object() { + for (key, value) in preset_map { + if value == POINTER_TARGET_VALUE { + return Err(create_validation_error( + format!("Pointer target not set for key: '{}'", key), + "pointer_target_not_set", + "Pointer target not set", + )); + } + } + Ok(()) + } else { + Err(create_validation_error( + "Preset must be an object".to_string(), + "invalid_preset_format", + "Preset is not a valid object", + )) + } +} + +// TODO(Tsabary): consider adding a `new` fn, and remove field visibility. +// TODO(Tsabary): need a new name for preset config. +// TODO(Tsabary): consider if having the MonitoringEndpointConfig part of PresetConfig makes sense. +pub struct PresetConfig { + pub config_path: PathBuf, + pub component_config: ComponentConfig, + pub monitoring_endpoint_config: MonitoringEndpointConfig, +} + +#[derive(Debug, Clone, Default)] +pub struct DeploymentBaseAppConfig { + config: SequencerNodeConfig, + config_pointers_map: ConfigPointersMap, + non_pointer_params: Pointers, +} + +impl DeploymentBaseAppConfig { + pub fn new( + config: SequencerNodeConfig, + config_pointers_map: ConfigPointersMap, + non_pointer_params: Pointers, + ) -> Self { + Self { config, config_pointers_map, non_pointer_params } + } + + pub fn get_config(&self) -> SequencerNodeConfig { + self.config.clone() + } + + // TODO(Tsabary): dump functions should not return values, need to separate this function. + // Suggestion: a modifying function that takes a preset config, and a dump function that takes a + // path. + pub fn dump_config_file(&self, preset_config: PresetConfig) -> SequencerNodeConfig { + let mut updated_config = self.config.clone(); + updated_config.components = preset_config.component_config; + updated_config.monitoring_endpoint_config = preset_config.monitoring_endpoint_config; + dump_config_file( + updated_config.clone(), + &self.config_pointers_map.clone().into(), + &self.non_pointer_params, + &preset_config.config_path, + ); + updated_config + } +} + +pub fn get_deployment_from_config_path(config_path: &str) -> DeploymentBaseAppConfig { + // TODO(Nadin): simplify this by using only config_path and removing the extra strings. + let config = load_and_validate_config(vec![ + "deployment_from_config_path".to_string(), + "--config_file".to_string(), + config_path.to_string(), + ]) + .unwrap(); + + let mut config_pointers_map = ConfigPointersMap::new(CONFIG_POINTERS.clone()); + + config_pointers_map.change_target_value( + "chain_id", + to_value(config.batcher_config.block_builder_config.chain_info.chain_id.clone()) + .expect("Failed to serialize ChainId"), + ); + config_pointers_map.change_target_value( + "eth_fee_token_address", + to_value( + config + .batcher_config + .block_builder_config + .chain_info + .fee_token_addresses + .eth_fee_token_address, + ) + .expect("Failed to serialize ContractAddress"), + ); + config_pointers_map.change_target_value( + "strk_fee_token_address", + to_value( + config + .batcher_config + .block_builder_config + .chain_info + .fee_token_addresses + .strk_fee_token_address, + ) + .expect("Failed to serialize ContractAddress"), + ); + config_pointers_map.change_target_value( + "validator_id", + to_value(config.consensus_manager_config.consensus_config.validator_id) + .expect("Failed to serialize ContractAddress"), + ); + config_pointers_map.change_target_value( + "recorder_url", + to_value(config.consensus_manager_config.cende_config.recorder_url.clone()) + .expect("Failed to serialize Url"), + ); + + DeploymentBaseAppConfig::new(config, config_pointers_map, CONFIG_NON_POINTERS_WHITELIST.clone()) +} diff --git a/crates/starknet_sequencer_node/src/config/definitions.rs b/crates/starknet_sequencer_node/src/config/definitions.rs new file mode 100644 index 00000000000..a92ec7ed1f8 --- /dev/null +++ b/crates/starknet_sequencer_node/src/config/definitions.rs @@ -0,0 +1,27 @@ +use std::collections::HashMap; + +use papyrus_config::dumping::{ConfigPointers, Pointers}; +use papyrus_config::{ParamPath, SerializedContent, SerializedParam}; +use serde_json::Value; + +#[derive(Debug, Clone, Default)] +pub struct ConfigPointersMap(HashMap); + +impl ConfigPointersMap { + pub fn new(config_pointers: ConfigPointers) -> Self { + ConfigPointersMap(config_pointers.into_iter().map(|((k, v), p)| (k, (v, p))).collect()) + } + + pub fn change_target_value(&mut self, target: &str, value: Value) { + assert!(self.0.contains_key(target)); + self.0.entry(target.to_owned()).and_modify(|(param, _)| { + param.content = SerializedContent::DefaultValue(value); + }); + } +} + +impl From for ConfigPointers { + fn from(config_pointers_map: ConfigPointersMap) -> Self { + config_pointers_map.0.into_iter().map(|(k, (v, p))| ((k, v), p)).collect() + } +} diff --git a/crates/starknet_sequencer_node/src/config/mod.rs b/crates/starknet_sequencer_node/src/config/mod.rs index 8e919cca3b7..f657ca57544 100644 --- a/crates/starknet_sequencer_node/src/config/mod.rs +++ b/crates/starknet_sequencer_node/src/config/mod.rs @@ -1,8 +1,11 @@ #[cfg(test)] mod config_test; +// TODO(Tsabary): deprecate usage of mod.rs files. + pub mod component_config; pub mod component_execution_config; +pub mod config_utils; +pub mod definitions; +pub mod monitoring; pub mod node_config; -#[cfg(any(feature = "testing", test))] -pub mod test_utils; diff --git a/crates/starknet_sequencer_node/src/config/monitoring.rs b/crates/starknet_sequencer_node/src/config/monitoring.rs new file mode 100644 index 00000000000..9462f0d03c7 --- /dev/null +++ b/crates/starknet_sequencer_node/src/config/monitoring.rs @@ -0,0 +1,55 @@ +use std::collections::BTreeMap; + +use papyrus_config::dumping::{ser_param, SerializeConfig}; +use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; +use serde::{Deserialize, Serialize}; +use validator::{Validate, ValidationError}; + +use crate::config::config_utils::create_validation_error; + +#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, Validate)] +#[validate(schema(function = "validate_monitoring_config"))] +pub struct MonitoringConfig { + pub collect_metrics: bool, + pub collect_profiling_metrics: bool, +} + +impl SerializeConfig for MonitoringConfig { + fn dump(&self) -> BTreeMap { + BTreeMap::from_iter([ + ser_param( + "collect_metrics", + &self.collect_metrics, + "Indicating if metrics should be recorded.", + ParamPrivacyInput::Public, + ), + ser_param( + "collect_profiling_metrics", + &self.collect_profiling_metrics, + "Indicating if profiling metrics should be collected.", + ParamPrivacyInput::Public, + ), + ]) + } +} + +impl Default for MonitoringConfig { + fn default() -> Self { + Self { collect_metrics: true, collect_profiling_metrics: true } + } +} + +pub(crate) fn create_monitoring_config_validation_error() -> ValidationError { + create_validation_error( + "Cannot collect profiling metrics when monitoring is disabled.".to_string(), + "Invalid monitoring configuration.", + "Cannot collect profiling metrics when monitoring is disabled.", + ) +} + +fn validate_monitoring_config(monitoring_config: &MonitoringConfig) -> Result<(), ValidationError> { + if !monitoring_config.collect_metrics && monitoring_config.collect_profiling_metrics { + return Err(create_monitoring_config_validation_error()); + } + Ok(()) +} diff --git a/crates/starknet_sequencer_node/src/config/node_config.rs b/crates/starknet_sequencer_node/src/config/node_config.rs index 2679e234e7e..d55d74022ce 100644 --- a/crates/starknet_sequencer_node/src/config/node_config.rs +++ b/crates/starknet_sequencer_node/src/config/node_config.rs @@ -1,60 +1,75 @@ use std::collections::{BTreeMap, HashSet}; use std::fs::File; -use std::path::Path; use std::sync::LazyLock; use std::vec::Vec; +use apollo_reverts::RevertConfig; use clap::Command; -use infra_utils::path::resolve_project_relative_path; +use papyrus_base_layer::ethereum_base_layer_contract::EthereumBaseLayerConfig; use papyrus_config::dumping::{ append_sub_config_name, generate_struct_pointer, - ser_pointer_target_required_param, + ser_pointer_target_param, set_pointing_param_paths, ConfigPointers, Pointers, SerializeConfig, }; use papyrus_config::loading::load_and_process_config; -use papyrus_config::{ConfigError, ParamPath, SerializationType, SerializedParam}; +use papyrus_config::{ConfigError, ParamPath, SerializedParam}; use serde::{Deserialize, Serialize}; use starknet_batcher::config::BatcherConfig; use starknet_batcher::VersionedConstantsOverrides; +use starknet_class_manager::config::FsClassManagerConfig; use starknet_consensus_manager::config::ConsensusManagerConfig; -use starknet_gateway::config::{GatewayConfig, RpcStateReaderConfig}; +use starknet_gateway::config::GatewayConfig; use starknet_http_server::config::HttpServerConfig; +use starknet_infra_utils::path::resolve_project_relative_path; +use starknet_l1_gas_price::l1_gas_price_provider::L1GasPriceProviderConfig; +use starknet_l1_gas_price::l1_gas_price_scraper::L1GasPriceScraperConfig; +use starknet_l1_provider::l1_scraper::L1ScraperConfig; +use starknet_l1_provider::L1ProviderConfig; +use starknet_mempool::config::MempoolConfig; use starknet_mempool_p2p::config::MempoolP2pConfig; use starknet_monitoring_endpoint::config::MonitoringEndpointConfig; -use starknet_sierra_compile::config::SierraToCasmCompilationConfig; +use starknet_sierra_multicompile::config::SierraCompilationConfig; +use starknet_state_sync::config::StateSyncConfig; use validator::Validate; use crate::config::component_config::ComponentConfig; +use crate::config::monitoring::MonitoringConfig; use crate::version::VERSION_FULL; // The path of the default configuration file, provided as part of the crate. pub const DEFAULT_CONFIG_PATH: &str = "config/sequencer/default_config.json"; +pub const POINTER_TARGET_VALUE: &str = "PointerTarget"; // Configuration parameters that share the same value across multiple components. pub static CONFIG_POINTERS: LazyLock = LazyLock::new(|| { let mut pointers = vec![ ( - ser_pointer_target_required_param( + ser_pointer_target_param( "chain_id", - SerializationType::String, - "The chain to follow.", + &POINTER_TARGET_VALUE.to_string(), + "The chain to follow. For more details see https://docs.starknet.io/documentation/architecture_and_concepts/Blocks/transactions/#chain-id.", ), set_pointing_param_paths(&[ "batcher_config.block_builder_config.chain_info.chain_id", "batcher_config.storage.db_config.chain_id", - "consensus_manager_config.consensus_config.network_config.chain_id", + "consensus_manager_config.context_config.chain_id", + "consensus_manager_config.network_config.chain_id", "gateway_config.chain_info.chain_id", + "l1_scraper_config.chain_id", + "l1_gas_price_scraper_config.chain_id", "mempool_p2p_config.network_config.chain_id", + "state_sync_config.storage_config.db_config.chain_id", + "state_sync_config.network_config.chain_id", ]), ), ( - ser_pointer_target_required_param( + ser_pointer_target_param( "eth_fee_token_address", - SerializationType::String, + &POINTER_TARGET_VALUE.to_string(), "Address of the ETH fee token.", ), set_pointing_param_paths(&[ @@ -64,9 +79,9 @@ pub static CONFIG_POINTERS: LazyLock = LazyLock::new(|| { ]), ), ( - ser_pointer_target_required_param( + ser_pointer_target_param( "strk_fee_token_address", - SerializationType::String, + &POINTER_TARGET_VALUE.to_string(), "Address of the STRK fee token.", ), set_pointing_param_paths(&[ @@ -75,14 +90,22 @@ pub static CONFIG_POINTERS: LazyLock = LazyLock::new(|| { "gateway_config.chain_info.fee_token_addresses.strk_fee_token_address", ]), ), - // TODO(tsabary): set as a regular required parameter. ( - ser_pointer_target_required_param( - "sequencer_address", - SerializationType::String, - "The sequencer address.", + ser_pointer_target_param( + "validator_id", + &POINTER_TARGET_VALUE.to_string(), + "The ID of the validator. \ + Also the address of this validator as a starknet contract.", ), - set_pointing_param_paths(&["batcher_config.block_builder_config.sequencer_address"]), + set_pointing_param_paths(&["consensus_manager_config.consensus_config.validator_id"]), + ), + ( + ser_pointer_target_param( + "recorder_url", + &POINTER_TARGET_VALUE.to_string(), + "The URL of the Pythonic cende_recorder", + ), + set_pointing_param_paths(&["consensus_manager_config.cende_config.recorder_url"]), ), ]; let mut common_execution_config = generate_struct_pointer( @@ -94,6 +117,16 @@ pub static CONFIG_POINTERS: LazyLock = LazyLock::new(|| { ]), ); pointers.append(&mut common_execution_config); + + let mut common_execution_config = generate_struct_pointer( + "revert_config".to_owned(), + &RevertConfig::default(), + set_pointing_param_paths(&[ + "state_sync_config.revert_config", + "consensus_manager_config.revert_config", + ]), + ); + pointers.append(&mut common_execution_config); pointers }); @@ -104,44 +137,77 @@ pub static CONFIG_NON_POINTERS_WHITELIST: LazyLock = /// The configurations of the various components of the node. #[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Validate)] pub struct SequencerNodeConfig { + // Infra related configs. #[validate] pub components: ComponentConfig, #[validate] + pub monitoring_config: MonitoringConfig, + + // Business-logic component configs. + #[validate] + pub base_layer_config: EthereumBaseLayerConfig, + #[validate] pub batcher_config: BatcherConfig, #[validate] + pub class_manager_config: FsClassManagerConfig, + #[validate] pub consensus_manager_config: ConsensusManagerConfig, #[validate] pub gateway_config: GatewayConfig, #[validate] pub http_server_config: HttpServerConfig, #[validate] - pub rpc_state_reader_config: RpcStateReaderConfig, + pub compiler_config: SierraCompilationConfig, + #[validate] + pub l1_provider_config: L1ProviderConfig, #[validate] - pub compiler_config: SierraToCasmCompilationConfig, + pub l1_gas_price_provider_config: L1GasPriceProviderConfig, + #[validate] + pub l1_scraper_config: L1ScraperConfig, + #[validate] + pub mempool_config: MempoolConfig, + #[validate] + pub l1_gas_price_scraper_config: L1GasPriceScraperConfig, #[validate] pub mempool_p2p_config: MempoolP2pConfig, #[validate] pub monitoring_endpoint_config: MonitoringEndpointConfig, + #[validate] + pub state_sync_config: StateSyncConfig, } impl SerializeConfig for SequencerNodeConfig { fn dump(&self) -> BTreeMap { let sub_configs = vec![ append_sub_config_name(self.components.dump(), "components"), + append_sub_config_name(self.monitoring_config.dump(), "monitoring_config"), + append_sub_config_name(self.base_layer_config.dump(), "base_layer_config"), append_sub_config_name(self.batcher_config.dump(), "batcher_config"), + append_sub_config_name(self.class_manager_config.dump(), "class_manager_config"), append_sub_config_name( self.consensus_manager_config.dump(), "consensus_manager_config", ), append_sub_config_name(self.gateway_config.dump(), "gateway_config"), append_sub_config_name(self.http_server_config.dump(), "http_server_config"), - append_sub_config_name(self.rpc_state_reader_config.dump(), "rpc_state_reader_config"), append_sub_config_name(self.compiler_config.dump(), "compiler_config"), + append_sub_config_name(self.mempool_config.dump(), "mempool_config"), append_sub_config_name(self.mempool_p2p_config.dump(), "mempool_p2p_config"), append_sub_config_name( self.monitoring_endpoint_config.dump(), "monitoring_endpoint_config", ), + append_sub_config_name(self.state_sync_config.dump(), "state_sync_config"), + append_sub_config_name(self.l1_provider_config.dump(), "l1_provider_config"), + append_sub_config_name(self.l1_scraper_config.dump(), "l1_scraper_config"), + append_sub_config_name( + self.l1_gas_price_provider_config.dump(), + "l1_gas_price_provider_config", + ), + append_sub_config_name( + self.l1_gas_price_scraper_config.dump(), + "l1_gas_price_scraper_config", + ), ]; sub_configs.into_iter().flatten().collect() @@ -151,27 +217,10 @@ impl SerializeConfig for SequencerNodeConfig { impl SequencerNodeConfig { /// Creates a config object. Selects the values from the default file and from resources with /// higher priority. - fn load_and_process_config_file( - args: Vec, - config_file_name: Option<&str>, - ) -> Result { - let config_file_name = match config_file_name { - Some(file_name) => Path::new(file_name), - None => &resolve_project_relative_path(DEFAULT_CONFIG_PATH)?, - }; - - let default_config_file = File::open(config_file_name)?; - load_and_process_config(default_config_file, node_command(), args) - } - pub fn load_and_process(args: Vec) -> Result { - Self::load_and_process_config_file(args, None) - } - pub fn load_and_process_file( - args: Vec, - config_file_name: &str, - ) -> Result { - Self::load_and_process_config_file(args, Some(config_file_name)) + let config_file_name = &resolve_project_relative_path(DEFAULT_CONFIG_PATH)?; + let default_config_file = File::open(config_file_name)?; + load_and_process_config(default_config_file, node_command(), args, true) } } diff --git a/crates/starknet_sequencer_node/src/config/test_utils.rs b/crates/starknet_sequencer_node/src/config/test_utils.rs deleted file mode 100644 index 9434886f096..00000000000 --- a/crates/starknet_sequencer_node/src/config/test_utils.rs +++ /dev/null @@ -1,54 +0,0 @@ -use std::vec::Vec; // Used by #[gen_field_names_fn]. - -use papyrus_proc_macros::gen_field_names_fn; -use starknet_api::core::{ChainId, ContractAddress}; - -use crate::config::node_config::node_command; - -/// Required parameters utility struct. -#[gen_field_names_fn] -pub struct RequiredParams { - pub chain_id: ChainId, - pub eth_fee_token_address: ContractAddress, - pub strk_fee_token_address: ContractAddress, - pub sequencer_address: ContractAddress, -} - -impl RequiredParams { - pub fn create_for_testing() -> Self { - Self { - chain_id: ChainId::create_for_testing(), - eth_fee_token_address: ContractAddress::from(2_u128), - strk_fee_token_address: ContractAddress::from(3_u128), - sequencer_address: ContractAddress::from(17_u128), - } - } - - // TODO(Tsabary): replace with a macro. - pub fn cli_args(&self) -> Vec { - let args = vec![ - "--chain_id".to_string(), - self.chain_id.to_string(), - "--eth_fee_token_address".to_string(), - self.eth_fee_token_address.to_string(), - "--strk_fee_token_address".to_string(), - self.strk_fee_token_address.to_string(), - "--sequencer_address".to_string(), - self.sequencer_address.to_string(), - ]; - // Verify all arguments and their values are present. - assert!( - args.len() == Self::field_names().len() * 2, - "Required parameter cli generation failure." - ); - args - } -} - -// Creates a vector of strings with the command name and required parameters that can be used as -// arguments to load a config. -pub fn create_test_config_load_args(required_params: RequiredParams) -> Vec { - let mut cli_args = vec![node_command().to_string()]; - cli_args.extend(required_params.cli_args()); - cli_args -} diff --git a/crates/starknet_sequencer_node/src/main.rs b/crates/starknet_sequencer_node/src/main.rs index af2e660948a..b8aed9d74b7 100644 --- a/crates/starknet_sequencer_node/src/main.rs +++ b/crates/starknet_sequencer_node/src/main.rs @@ -1,37 +1,25 @@ use std::env::args; -use std::process::exit; -use papyrus_config::validators::config_validate; -use papyrus_config::ConfigError; +use starknet_infra_utils::set_global_allocator; use starknet_sequencer_infra::trace_util::configure_tracing; -use starknet_sequencer_node::config::node_config::SequencerNodeConfig; use starknet_sequencer_node::servers::run_component_servers; -use starknet_sequencer_node::utils::create_node_modules; -use tracing::{error, info}; +use starknet_sequencer_node::utils::{create_node_modules, load_and_validate_config}; +use tracing::info; + +set_global_allocator!(); #[tokio::main] async fn main() -> anyhow::Result<()> { - configure_tracing(); - - let config = SequencerNodeConfig::load_and_process(args().collect()); - if let Err(ConfigError::CommandInput(clap_err)) = config { - error!("Failed loading configuration: {}", clap_err); - clap_err.exit(); - } - info!("Finished loading configuration."); + configure_tracing().await; - let config = config?; - if let Err(error) = config_validate(&config) { - error!("{}", error); - exit(1); - } - info!("Finished validating configuration."); + let config = + load_and_validate_config(args().collect()).expect("Failed to load and validate config"); // Clients are currently unused, but should not be dropped. - let (_clients, servers) = create_node_modules(&config); + let (_clients, servers) = create_node_modules(&config).await; info!("Starting components!"); - run_component_servers(servers).await?; + run_component_servers(servers).await; // TODO(Tsabary): Add graceful shutdown. Ok(()) diff --git a/crates/starknet_sequencer_node/src/servers.rs b/crates/starknet_sequencer_node/src/servers.rs index 020849bbc2a..f8767c58c5d 100644 --- a/crates/starknet_sequencer_node/src/servers.rs +++ b/crates/starknet_sequencer_node/src/servers.rs @@ -1,11 +1,24 @@ use std::future::pending; use std::pin::Pin; -use futures::{Future, FutureExt}; +use futures::stream::FuturesUnordered; +use futures::{Future, FutureExt, StreamExt}; +use papyrus_base_layer::ethereum_base_layer_contract::EthereumBaseLayerContract; use starknet_batcher::communication::{LocalBatcherServer, RemoteBatcherServer}; +use starknet_class_manager::communication::{LocalClassManagerServer, RemoteClassManagerServer}; use starknet_consensus_manager::communication::ConsensusManagerServer; use starknet_gateway::communication::{LocalGatewayServer, RemoteGatewayServer}; use starknet_http_server::communication::HttpServer; +use starknet_l1_gas_price::communication::{ + L1GasPriceScraperServer, + LocalL1GasPriceServer, + RemoteL1GasPriceServer, +}; +use starknet_l1_provider::communication::{ + L1ScraperServer, + LocalL1ProviderServer, + RemoteL1ProviderServer, +}; use starknet_mempool::communication::{LocalMempoolServer, RemoteMempoolServer}; use starknet_mempool_p2p::propagator::{ LocalMempoolP2pPropagatorServer, @@ -15,42 +28,115 @@ use starknet_mempool_p2p::runner::MempoolP2pRunnerServer; use starknet_monitoring_endpoint::communication::MonitoringEndpointServer; use starknet_sequencer_infra::component_server::{ ComponentServerStarter, + ConcurrentLocalComponentServer, LocalComponentServer, RemoteComponentServer, WrapperServer, }; -use starknet_sequencer_infra::errors::ComponentServerError; -use tracing::error; +use starknet_sequencer_infra::metrics::{ + LocalServerMetrics, + RemoteServerMetrics, + BATCHER_LOCAL_MSGS_PROCESSED, + BATCHER_LOCAL_MSGS_RECEIVED, + BATCHER_LOCAL_QUEUE_DEPTH, + BATCHER_REMOTE_MSGS_PROCESSED, + BATCHER_REMOTE_MSGS_RECEIVED, + BATCHER_REMOTE_VALID_MSGS_RECEIVED, + CLASS_MANAGER_LOCAL_MSGS_PROCESSED, + CLASS_MANAGER_LOCAL_MSGS_RECEIVED, + CLASS_MANAGER_LOCAL_QUEUE_DEPTH, + CLASS_MANAGER_REMOTE_MSGS_PROCESSED, + CLASS_MANAGER_REMOTE_MSGS_RECEIVED, + CLASS_MANAGER_REMOTE_VALID_MSGS_RECEIVED, + GATEWAY_LOCAL_MSGS_PROCESSED, + GATEWAY_LOCAL_MSGS_RECEIVED, + GATEWAY_LOCAL_QUEUE_DEPTH, + GATEWAY_REMOTE_MSGS_PROCESSED, + GATEWAY_REMOTE_MSGS_RECEIVED, + GATEWAY_REMOTE_VALID_MSGS_RECEIVED, + L1_GAS_PRICE_PROVIDER_LOCAL_MSGS_PROCESSED, + L1_GAS_PRICE_PROVIDER_LOCAL_MSGS_RECEIVED, + L1_GAS_PRICE_PROVIDER_LOCAL_QUEUE_DEPTH, + L1_GAS_PRICE_PROVIDER_REMOTE_MSGS_PROCESSED, + L1_GAS_PRICE_PROVIDER_REMOTE_MSGS_RECEIVED, + L1_GAS_PRICE_PROVIDER_REMOTE_VALID_MSGS_RECEIVED, + L1_PROVIDER_LOCAL_MSGS_PROCESSED, + L1_PROVIDER_LOCAL_MSGS_RECEIVED, + L1_PROVIDER_LOCAL_QUEUE_DEPTH, + L1_PROVIDER_REMOTE_MSGS_PROCESSED, + L1_PROVIDER_REMOTE_MSGS_RECEIVED, + L1_PROVIDER_REMOTE_VALID_MSGS_RECEIVED, + MEMPOOL_LOCAL_MSGS_PROCESSED, + MEMPOOL_LOCAL_MSGS_RECEIVED, + MEMPOOL_LOCAL_QUEUE_DEPTH, + MEMPOOL_P2P_LOCAL_MSGS_PROCESSED, + MEMPOOL_P2P_LOCAL_MSGS_RECEIVED, + MEMPOOL_P2P_LOCAL_QUEUE_DEPTH, + MEMPOOL_P2P_REMOTE_MSGS_PROCESSED, + MEMPOOL_P2P_REMOTE_MSGS_RECEIVED, + MEMPOOL_P2P_REMOTE_VALID_MSGS_RECEIVED, + MEMPOOL_REMOTE_MSGS_PROCESSED, + MEMPOOL_REMOTE_MSGS_RECEIVED, + MEMPOOL_REMOTE_VALID_MSGS_RECEIVED, + SIERRA_COMPILER_LOCAL_MSGS_PROCESSED, + SIERRA_COMPILER_LOCAL_MSGS_RECEIVED, + SIERRA_COMPILER_LOCAL_QUEUE_DEPTH, + STATE_SYNC_LOCAL_MSGS_PROCESSED, + STATE_SYNC_LOCAL_MSGS_RECEIVED, + STATE_SYNC_LOCAL_QUEUE_DEPTH, + STATE_SYNC_REMOTE_MSGS_PROCESSED, + STATE_SYNC_REMOTE_MSGS_RECEIVED, + STATE_SYNC_REMOTE_VALID_MSGS_RECEIVED, +}; +use starknet_sierra_multicompile::communication::LocalSierraCompilerServer; +use starknet_state_sync::runner::StateSyncRunnerServer; +use starknet_state_sync::{LocalStateSyncServer, RemoteStateSyncServer}; use crate::clients::SequencerNodeClients; use crate::communication::SequencerNodeCommunication; use crate::components::SequencerNodeComponents; -use crate::config::component_execution_config::ComponentExecutionMode; +use crate::config::component_execution_config::{ + ActiveComponentExecutionMode, + ReactiveComponentExecutionMode, +}; use crate::config::node_config::SequencerNodeConfig; // Component servers that can run locally. struct LocalServers { pub(crate) batcher: Option>, + pub(crate) class_manager: Option>, pub(crate) gateway: Option>, + pub(crate) l1_provider: Option>, + pub(crate) l1_gas_price_provider: Option>, pub(crate) mempool: Option>, pub(crate) mempool_p2p_propagator: Option>, + pub(crate) sierra_compiler: Option>, + pub(crate) state_sync: Option>, } // Component servers that wrap a component without a server. struct WrapperServers { pub(crate) consensus_manager: Option>, pub(crate) http_server: Option>, + pub(crate) l1_scraper_server: Option>>, + pub(crate) l1_gas_price_scraper_server: + Option>>, pub(crate) monitoring_endpoint: Option>, pub(crate) mempool_p2p_runner: Option>, + pub(crate) state_sync_runner: Option>, } // Component servers that can run remotely. // TODO(Nadin): Remove pub from the struct and update the fields to be pub(crate). pub struct RemoteServers { pub batcher: Option>, + pub class_manager: Option>, pub gateway: Option>, + pub l1_provider: Option>, + pub l1_gas_price_provider: Option>, pub mempool: Option>, pub mempool_p2p_propagator: Option>, + pub state_sync: Option>, } pub struct SequencerNodeServers { @@ -65,25 +151,28 @@ pub struct SequencerNodeServers { /// /// # Arguments /// -/// * `$execution_mode` - A reference to the component's execution mode, of type -/// `&ComponentExecutionMode`. -/// * `$local_client` - The local client to be used for the remote server initialization if the -/// execution mode is `Remote`. -/// * `$config` - The configuration for the remote server. +/// * `$execution_mode` - Component execution mode reference. +/// * `$local_client_getter` - Local client getter function, used for the remote server +/// initialization if needed. +/// * `$ip` - Remote component server binding address, default "0.0.0.0". +/// * `$port` - Remote component server listening port. +/// * `$max_concurrency` - the maximum number of concurrent connections the server will handle. /// /// # Returns /// /// An `Option>>` containing /// the remote server if the execution mode is Remote, or None if the execution mode is Disabled, -/// LocalExecutionWithRemoteEnabled or LocalExecutionWithRemoteDisabled. +/// LocalExecutionWithRemoteEnabled, or LocalExecutionWithRemoteDisabled. /// /// # Example /// /// ```rust,ignore /// let batcher_remote_server = create_remote_server!( /// &config.components.batcher.execution_mode, -/// clients.get_gateway_local_client(), -/// config.remote_server_config +/// || {clients.get_gateway_local_client()}, +/// config.components.batcher.ip, +/// config.components.batcher.port, +/// config.components.batcher.max_concurrency /// ); /// match batcher_remote_server { /// Some(server) => println!("Remote server created: {:?}", server), @@ -92,51 +181,67 @@ pub struct SequencerNodeServers { /// ``` #[macro_export] macro_rules! create_remote_server { - ($execution_mode:expr, $local_client:expr, $remote_server_config:expr) => { + ( + $execution_mode:expr, + $local_client_getter:expr, + $url:expr, + $port:expr, + $max_concurrency:expr, + $metrics:expr + ) => { match *$execution_mode { - ComponentExecutionMode::LocalExecutionWithRemoteEnabled => { - let local_client = $local_client + ReactiveComponentExecutionMode::LocalExecutionWithRemoteEnabled => { + let local_client = $local_client_getter() .expect("Local client should be set for inbound remote connections."); - let remote_server_config = $remote_server_config - .as_ref() - .expect("Remote server config should be set for inbound remote connections."); Some(Box::new(RemoteComponentServer::new( local_client, - remote_server_config.clone(), + $url, + $port, + $max_concurrency, + $metrics, ))) } - ComponentExecutionMode::LocalExecutionWithRemoteDisabled - | ComponentExecutionMode::Remote - | ComponentExecutionMode::Disabled => None, + ReactiveComponentExecutionMode::LocalExecutionWithRemoteDisabled + | ReactiveComponentExecutionMode::Remote + | ReactiveComponentExecutionMode::Disabled => None, } }; } -/// A macro for creating a component server, determined by the component's execution mode. Returns a -/// local server if the component is run locally, otherwise None. +/// A macro for creating a local component server or a concurrent local component server, determined +/// by the component's execution mode. Returns a [concurrent/regular] local server if the component +/// is run locally, otherwise None. /// /// # Arguments /// +/// * $server_type - the type of the server, one of string literals REGULAR_LOCAL_SERVER or +/// CONCURRENT_LOCAL_SERVER. /// * $execution_mode - A reference to the component's execution mode, i.e., type -/// &ComponentExecutionMode. +/// &ReactiveComponentExecutionMode. /// * $component - The component that will be taken to initialize the server if the execution mode /// is enabled(LocalExecutionWithRemoteDisabled / LocalExecutionWithRemoteEnabled). -/// * $Receiver - receiver side for the server. +/// * $receiver - receiver side for the server. +/// * $server_metrics - The metrics for the server. +/// * $max_concurrency - The maximum number of concurrent requests the server will handle. Only +/// required for the CONCURRENT_LOCAL_SERVER. /// /// # Returns /// -/// An Option>> containing the -/// server if the execution mode is enabled(LocalExecutionWithRemoteDisabled / +/// An Option>> or +/// an Option>> +/// containing the server if the execution mode is enabled(LocalExecutionWithRemoteDisabled / /// LocalExecutionWithRemoteEnabled), or None if the execution mode is Disabled. /// /// # Example /// /// ```rust,ignore /// let batcher_server = create_local_server!( +/// REGULAR_LOCAL_SERVER, /// &config.components.batcher.execution_mode, /// components.batcher, -/// communication.take_batcher_rx() +/// communication.take_batcher_rx(), +/// batcher_metrics /// ); /// match batcher_server { /// Some(server) => println!("Server created: {:?}", server), @@ -144,20 +249,30 @@ macro_rules! create_remote_server { /// } /// ``` macro_rules! create_local_server { - ($execution_mode:expr, $component:expr, $receiver:expr) => { + ($server_type:tt, $execution_mode:expr, $component:expr, $receiver:expr, $server_metrics:expr $(, $max_concurrency:expr)? ) => { match *$execution_mode { - ComponentExecutionMode::LocalExecutionWithRemoteDisabled - | ComponentExecutionMode::LocalExecutionWithRemoteEnabled => { - Some(Box::new(LocalComponentServer::new( + ReactiveComponentExecutionMode::LocalExecutionWithRemoteDisabled + | ReactiveComponentExecutionMode::LocalExecutionWithRemoteEnabled => { + Some(Box::new(create_local_server!(@create $server_type)( $component .take() .expect(concat!(stringify!($component), " is not initialized.")), $receiver, + $( $max_concurrency,)? + $server_metrics, ))) } - ComponentExecutionMode::Disabled | ComponentExecutionMode::Remote => None, + ReactiveComponentExecutionMode::Disabled | ReactiveComponentExecutionMode::Remote => { + None + } } }; + (@create REGULAR_LOCAL_SERVER) => { + LocalComponentServer::new + }; + (@create CONCURRENT_LOCAL_SERVER) => { + ConcurrentLocalComponentServer::new + }; } /// A macro for creating a WrapperServer, determined by the component's execution mode. Returns a @@ -166,7 +281,7 @@ macro_rules! create_local_server { /// # Arguments /// /// * $execution_mode - A reference to the component's execution mode, i.e., type -/// &ComponentExecutionMode. +/// &ReactiveComponentExecutionMode. /// * $component - The component that will be taken to initialize the server if the execution mode /// is enabled(LocalExecutionWithRemoteDisabled / LocalExecutionWithRemoteEnabled). /// @@ -179,7 +294,7 @@ macro_rules! create_local_server { /// # Example /// /// ```rust, ignore -/// // Assuming ComponentExecutionMode and components are defined, and WrapperServer +/// // Assuming ReactiveComponentExecutionMode and components are defined, and WrapperServer /// // has a new method that accepts a component. /// let consensus_manager_server = create_wrapper_server!( /// &config.components.consensus_manager.execution_mode, @@ -194,15 +309,10 @@ macro_rules! create_local_server { macro_rules! create_wrapper_server { ($execution_mode:expr, $component:expr) => { match *$execution_mode { - ComponentExecutionMode::LocalExecutionWithRemoteDisabled - | ComponentExecutionMode::LocalExecutionWithRemoteEnabled => { - Some(Box::new(WrapperServer::new( - $component - .take() - .expect(concat!(stringify!($component), " is not initialized.")), - ))) - } - ComponentExecutionMode::Disabled | ComponentExecutionMode::Remote => None, + ActiveComponentExecutionMode::Enabled => Some(Box::new(WrapperServer::new( + $component.take().expect(concat!(stringify!($component), " is not initialized.")), + ))), + ActiveComponentExecutionMode::Disabled => None, } }; } @@ -212,31 +322,159 @@ fn create_local_servers( communication: &mut SequencerNodeCommunication, components: &mut SequencerNodeComponents, ) -> LocalServers { + let batcher_metrics = LocalServerMetrics::new( + &BATCHER_LOCAL_MSGS_RECEIVED, + &BATCHER_LOCAL_MSGS_PROCESSED, + &BATCHER_LOCAL_QUEUE_DEPTH, + ); let batcher_server = create_local_server!( + REGULAR_LOCAL_SERVER, &config.components.batcher.execution_mode, - components.batcher, - communication.take_batcher_rx() + &mut components.batcher, + communication.take_batcher_rx(), + batcher_metrics + ); + + let class_manager_metrics = LocalServerMetrics::new( + &CLASS_MANAGER_LOCAL_MSGS_RECEIVED, + &CLASS_MANAGER_LOCAL_MSGS_PROCESSED, + &CLASS_MANAGER_LOCAL_QUEUE_DEPTH, + ); + let class_manager_server = create_local_server!( + REGULAR_LOCAL_SERVER, + &config.components.class_manager.execution_mode, + &mut components.class_manager, + communication.take_class_manager_rx(), + class_manager_metrics + ); + + let gateway_metrics = LocalServerMetrics::new( + &GATEWAY_LOCAL_MSGS_RECEIVED, + &GATEWAY_LOCAL_MSGS_PROCESSED, + &GATEWAY_LOCAL_QUEUE_DEPTH, ); let gateway_server = create_local_server!( + REGULAR_LOCAL_SERVER, &config.components.gateway.execution_mode, - components.gateway, - communication.take_gateway_rx() + &mut components.gateway, + communication.take_gateway_rx(), + gateway_metrics + ); + + let l1_provider_metrics = LocalServerMetrics::new( + &L1_PROVIDER_LOCAL_MSGS_RECEIVED, + &L1_PROVIDER_LOCAL_MSGS_PROCESSED, + &L1_PROVIDER_LOCAL_QUEUE_DEPTH, + ); + let l1_provider_server = create_local_server!( + REGULAR_LOCAL_SERVER, + &config.components.l1_provider.execution_mode, + &mut components.l1_provider, + communication.take_l1_provider_rx(), + l1_provider_metrics + ); + let l1_gas_price_provider_metrics = LocalServerMetrics::new( + &L1_GAS_PRICE_PROVIDER_LOCAL_MSGS_RECEIVED, + &L1_GAS_PRICE_PROVIDER_LOCAL_MSGS_PROCESSED, + &L1_GAS_PRICE_PROVIDER_LOCAL_QUEUE_DEPTH, + ); + let l1_gas_price_provider_server = create_local_server!( + REGULAR_LOCAL_SERVER, + &config.components.l1_gas_price_provider.execution_mode, + &mut components.l1_gas_price_provider, + communication.take_l1_gas_price_rx(), + l1_gas_price_provider_metrics + ); + let mempool_metrics = LocalServerMetrics::new( + &MEMPOOL_LOCAL_MSGS_RECEIVED, + &MEMPOOL_LOCAL_MSGS_PROCESSED, + &MEMPOOL_LOCAL_QUEUE_DEPTH, ); let mempool_server = create_local_server!( + REGULAR_LOCAL_SERVER, &config.components.mempool.execution_mode, - components.mempool, - communication.take_mempool_rx() + &mut components.mempool, + communication.take_mempool_rx(), + mempool_metrics + ); + + let mempool_p2p_metrics = LocalServerMetrics::new( + &MEMPOOL_P2P_LOCAL_MSGS_RECEIVED, + &MEMPOOL_P2P_LOCAL_MSGS_PROCESSED, + &MEMPOOL_P2P_LOCAL_QUEUE_DEPTH, ); let mempool_p2p_propagator_server = create_local_server!( + REGULAR_LOCAL_SERVER, &config.components.mempool_p2p.execution_mode, - components.mempool_p2p_propagator, - communication.take_mempool_p2p_propagator_rx() + &mut components.mempool_p2p_propagator, + communication.take_mempool_p2p_propagator_rx(), + mempool_p2p_metrics + ); + + let sierra_compiler_metrics = LocalServerMetrics::new( + &SIERRA_COMPILER_LOCAL_MSGS_RECEIVED, + &SIERRA_COMPILER_LOCAL_MSGS_PROCESSED, + &SIERRA_COMPILER_LOCAL_QUEUE_DEPTH, ); + let sierra_compiler_server = create_local_server!( + CONCURRENT_LOCAL_SERVER, + &config.components.sierra_compiler.execution_mode, + &mut components.sierra_compiler, + communication.take_sierra_compiler_rx(), + sierra_compiler_metrics, + config.components.sierra_compiler.max_concurrency + ); + + let state_sync_metrics = LocalServerMetrics::new( + &STATE_SYNC_LOCAL_MSGS_RECEIVED, + &STATE_SYNC_LOCAL_MSGS_PROCESSED, + &STATE_SYNC_LOCAL_QUEUE_DEPTH, + ); + let state_sync_server = create_local_server!( + REGULAR_LOCAL_SERVER, + &config.components.state_sync.execution_mode, + &mut components.state_sync, + communication.take_state_sync_rx(), + state_sync_metrics + ); + LocalServers { batcher: batcher_server, + class_manager: class_manager_server, gateway: gateway_server, + l1_provider: l1_provider_server, + l1_gas_price_provider: l1_gas_price_provider_server, mempool: mempool_server, mempool_p2p_propagator: mempool_p2p_propagator_server, + sierra_compiler: sierra_compiler_server, + state_sync: state_sync_server, + } +} + +async fn create_servers( + labeled_futures: Vec<(impl Future + Send + 'static, String)>, +) -> FuturesUnordered + Send>>> { + let tasks = FuturesUnordered::new(); + for (future, label) in labeled_futures.into_iter() { + tasks.push(future.map(move |_| label).boxed()); + } + tasks +} + +impl LocalServers { + async fn run(self) -> FuturesUnordered + Send>>> { + create_servers(vec![ + server_future_and_label(self.batcher, "Local Batcher"), + server_future_and_label(self.class_manager, "Local Class Manager"), + server_future_and_label(self.gateway, "Local Gateway"), + server_future_and_label(self.l1_provider, "Local L1 Provider"), + server_future_and_label(self.l1_gas_price_provider, "Local L1 Gas Price Provider"), + server_future_and_label(self.mempool, "Local Mempool"), + server_future_and_label(self.mempool_p2p_propagator, "Local Mempool P2p Propagator"), + server_future_and_label(self.sierra_compiler, "Concurrent Local Sierra Compiler"), + server_future_and_label(self.state_sync, "Local State Sync"), + ]) + .await } } @@ -244,38 +482,143 @@ pub fn create_remote_servers( config: &SequencerNodeConfig, clients: &SequencerNodeClients, ) -> RemoteServers { - let batcher_client = clients.get_batcher_local_client(); + let batcher_metrics = RemoteServerMetrics::new( + &BATCHER_REMOTE_MSGS_RECEIVED, + &BATCHER_REMOTE_VALID_MSGS_RECEIVED, + &BATCHER_REMOTE_MSGS_PROCESSED, + ); let batcher_server = create_remote_server!( &config.components.batcher.execution_mode, - batcher_client, - config.components.batcher.remote_server_config + || { clients.get_batcher_local_client() }, + config.components.batcher.ip, + config.components.batcher.port, + config.components.batcher.max_concurrency, + batcher_metrics ); - let gateway_client = clients.get_gateway_local_client(); + let class_manager_metrics = RemoteServerMetrics::new( + &CLASS_MANAGER_REMOTE_MSGS_RECEIVED, + &CLASS_MANAGER_REMOTE_VALID_MSGS_RECEIVED, + &CLASS_MANAGER_REMOTE_MSGS_PROCESSED, + ); + let class_manager_server = create_remote_server!( + &config.components.class_manager.execution_mode, + || { clients.get_class_manager_local_client() }, + config.components.class_manager.ip, + config.components.class_manager.port, + config.components.class_manager.max_concurrency, + class_manager_metrics + ); + + let gateway_metrics = RemoteServerMetrics::new( + &GATEWAY_REMOTE_MSGS_RECEIVED, + &GATEWAY_REMOTE_VALID_MSGS_RECEIVED, + &GATEWAY_REMOTE_MSGS_PROCESSED, + ); let gateway_server = create_remote_server!( &config.components.gateway.execution_mode, - gateway_client, - config.components.gateway.remote_server_config + || { clients.get_gateway_local_client() }, + config.components.gateway.ip, + config.components.gateway.port, + config.components.gateway.max_concurrency, + gateway_metrics + ); + + let l1_provider_metrics = RemoteServerMetrics::new( + &L1_PROVIDER_REMOTE_MSGS_RECEIVED, + &L1_PROVIDER_REMOTE_VALID_MSGS_RECEIVED, + &L1_PROVIDER_REMOTE_MSGS_PROCESSED, + ); + let l1_provider_server = create_remote_server!( + &config.components.l1_provider.execution_mode, + || { clients.get_l1_provider_local_client() }, + config.components.l1_provider.ip, + config.components.l1_provider.port, + config.components.l1_provider.max_concurrency, + l1_provider_metrics + ); + let l1_gas_price_provider_metrics = RemoteServerMetrics::new( + &L1_GAS_PRICE_PROVIDER_REMOTE_MSGS_RECEIVED, + &L1_GAS_PRICE_PROVIDER_REMOTE_VALID_MSGS_RECEIVED, + &L1_GAS_PRICE_PROVIDER_REMOTE_MSGS_PROCESSED, + ); + let l1_gas_price_provider_server = create_remote_server!( + &config.components.l1_gas_price_provider.execution_mode, + || { clients.get_l1_gas_price_provider_local_client() }, + config.components.l1_gas_price_provider.ip, + config.components.l1_gas_price_provider.port, + config.components.l1_gas_price_provider.max_concurrency, + l1_gas_price_provider_metrics + ); + + let mempool_metrics = RemoteServerMetrics::new( + &MEMPOOL_REMOTE_MSGS_RECEIVED, + &MEMPOOL_REMOTE_VALID_MSGS_RECEIVED, + &MEMPOOL_REMOTE_MSGS_PROCESSED, ); - let mempool_client = clients.get_mempool_local_client(); let mempool_server = create_remote_server!( &config.components.mempool.execution_mode, - mempool_client, - config.components.mempool.remote_server_config + || { clients.get_mempool_local_client() }, + config.components.mempool.ip, + config.components.mempool.port, + config.components.mempool.max_concurrency, + mempool_metrics ); - let mempool_p2p_propagator_client = clients.get_mempool_p2p_propagator_local_client(); + let mempool_p2p_metrics = RemoteServerMetrics::new( + &MEMPOOL_P2P_REMOTE_MSGS_RECEIVED, + &MEMPOOL_P2P_REMOTE_VALID_MSGS_RECEIVED, + &MEMPOOL_P2P_REMOTE_MSGS_PROCESSED, + ); let mempool_p2p_propagator_server = create_remote_server!( &config.components.mempool_p2p.execution_mode, - mempool_p2p_propagator_client, - config.components.mempool_p2p.remote_server_config + || { clients.get_mempool_p2p_propagator_local_client() }, + config.components.mempool_p2p.ip, + config.components.mempool_p2p.port, + config.components.mempool_p2p.max_concurrency, + mempool_p2p_metrics + ); + + let state_sync_metrics = RemoteServerMetrics::new( + &STATE_SYNC_REMOTE_MSGS_RECEIVED, + &STATE_SYNC_REMOTE_VALID_MSGS_RECEIVED, + &STATE_SYNC_REMOTE_MSGS_PROCESSED, + ); + let state_sync_server = create_remote_server!( + &config.components.state_sync.execution_mode, + || { clients.get_state_sync_local_client() }, + config.components.state_sync.ip, + config.components.state_sync.port, + config.components.state_sync.max_concurrency, + state_sync_metrics ); + RemoteServers { batcher: batcher_server, + class_manager: class_manager_server, gateway: gateway_server, + l1_provider: l1_provider_server, + l1_gas_price_provider: l1_gas_price_provider_server, mempool: mempool_server, mempool_p2p_propagator: mempool_p2p_propagator_server, + state_sync: state_sync_server, + } +} + +impl RemoteServers { + async fn run(self) -> FuturesUnordered + Send>>> { + create_servers(vec![ + server_future_and_label(self.batcher, "Remote Batcher"), + server_future_and_label(self.class_manager, "Remote Class Manager"), + server_future_and_label(self.gateway, "Remote Gateway"), + server_future_and_label(self.l1_provider, "Remote L1 Provider"), + server_future_and_label(self.l1_gas_price_provider, "Remote L1 Gas Price Provider"), + server_future_and_label(self.mempool, "Remote Mempool"), + server_future_and_label(self.mempool_p2p_propagator, "Remote Mempool P2p Propagator"), + server_future_and_label(self.state_sync, "Remote State Sync"), + ]) + .await } } @@ -287,25 +630,57 @@ fn create_wrapper_servers( &config.components.consensus_manager.execution_mode, components.consensus_manager ); + let http_server = create_wrapper_server!( &config.components.http_server.execution_mode, components.http_server ); + let l1_scraper_server = + create_wrapper_server!(&config.components.l1_scraper.execution_mode, components.l1_scraper); + + let l1_gas_price_scraper_server = create_wrapper_server!( + &config.components.l1_gas_price_scraper.execution_mode, + components.l1_gas_price_scraper + ); + let monitoring_endpoint_server = create_wrapper_server!( &config.components.monitoring_endpoint.execution_mode, components.monitoring_endpoint ); let mempool_p2p_runner_server = create_wrapper_server!( - &config.components.mempool_p2p.execution_mode, + &config.components.mempool_p2p.execution_mode.clone().into(), components.mempool_p2p_runner ); + let state_sync_runner_server = create_wrapper_server!( + &config.components.state_sync.execution_mode.clone().into(), + components.state_sync_runner + ); + WrapperServers { consensus_manager: consensus_manager_server, http_server, + l1_scraper_server, + l1_gas_price_scraper_server, monitoring_endpoint: monitoring_endpoint_server, mempool_p2p_runner: mempool_p2p_runner_server, + state_sync_runner: state_sync_runner_server, + } +} + +impl WrapperServers { + async fn run(self) -> FuturesUnordered + Send>>> { + create_servers(vec![ + server_future_and_label(self.consensus_manager, "Consensus Manager"), + server_future_and_label(self.http_server, "Http"), + server_future_and_label(self.l1_scraper_server, "L1 Scraper"), + server_future_and_label(self.l1_gas_price_scraper_server, "L1 Gas Price Scraper"), + server_future_and_label(self.monitoring_endpoint, "Monitoring Endpoint"), + server_future_and_label(self.mempool_p2p_runner, "Mempool P2p Runner"), + server_future_and_label(self.state_sync_runner, "State Sync Runner"), + ]) + .await } } @@ -323,112 +698,37 @@ pub fn create_node_servers( SequencerNodeServers { local_servers, remote_servers, wrapper_servers } } -// TODO(Nadin): refactor this function to reduce code duplication. -pub async fn run_component_servers(servers: SequencerNodeServers) -> anyhow::Result<()> { - // Batcher servers. - let local_batcher_future = get_server_future(servers.local_servers.batcher); - let remote_batcher_future = get_server_future(servers.remote_servers.batcher); - - // Consensus Manager server. - let consensus_manager_future = get_server_future(servers.wrapper_servers.consensus_manager); - - // Gateway servers. - let local_gateway_future = get_server_future(servers.local_servers.gateway); - let remote_gateway_future = get_server_future(servers.remote_servers.gateway); - - // HttpServer server. - let http_server_future = get_server_future(servers.wrapper_servers.http_server); - - // Mempool servers. - let local_mempool_future = get_server_future(servers.local_servers.mempool); - let remote_mempool_future = get_server_future(servers.remote_servers.mempool); - - // Sequencer Monitoring server. - let monitoring_endpoint_future = get_server_future(servers.wrapper_servers.monitoring_endpoint); - - // MempoolP2pPropagator servers. - let local_mempool_p2p_propagator_future = - get_server_future(servers.local_servers.mempool_p2p_propagator); - let remote_mempool_p2p_propagator_future = - get_server_future(servers.remote_servers.mempool_p2p_propagator); - - // MempoolP2pRunner server. - let mempool_p2p_runner_future = get_server_future(servers.wrapper_servers.mempool_p2p_runner); - - // Start servers. - let local_batcher_handle = tokio::spawn(local_batcher_future); - let remote_batcher_handle = tokio::spawn(remote_batcher_future); - let consensus_manager_handle = tokio::spawn(consensus_manager_future); - let local_gateway_handle = tokio::spawn(local_gateway_future); - let remote_gateway_handle = tokio::spawn(remote_gateway_future); - let http_server_handle = tokio::spawn(http_server_future); - let local_mempool_handle = tokio::spawn(local_mempool_future); - let remote_mempool_handle = tokio::spawn(remote_mempool_future); - let monitoring_endpoint_handle = tokio::spawn(monitoring_endpoint_future); - let local_mempool_p2p_propagator_handle = tokio::spawn(local_mempool_p2p_propagator_future); - let remote_mempool_p2p_propagator_handle = tokio::spawn(remote_mempool_p2p_propagator_future); - let mempool_p2p_runner_handle = tokio::spawn(mempool_p2p_runner_future); - - let result = tokio::select! { - res = local_batcher_handle => { - error!("Local Batcher Server stopped."); - res? - } - res = remote_batcher_handle => { - error!("Remote Batcher Server stopped."); - res? - } - res = consensus_manager_handle => { - error!("Consensus Manager Server stopped."); - res? - } - res = local_gateway_handle => { - error!("Local Gateway Server stopped."); - res? - } - res = remote_gateway_handle => { - error!("Remote Gateway Server stopped."); - res? - } - res = http_server_handle => { - error!("Http Server stopped."); - res? - } - res = local_mempool_handle => { - error!("Local Mempool Server stopped."); - res? - } - res = remote_mempool_handle => { - error!("Remote Mempool Server stopped."); - res? - } - res = monitoring_endpoint_handle => { - error!("Monitoring Endpoint Server stopped."); - res? - } - res = local_mempool_p2p_propagator_handle => { - error!("Local Mempool P2P Propagator Server stopped."); - res? - } - res = remote_mempool_p2p_propagator_handle => { - error!("Remote Mempool P2P Propagator Server stopped."); - res? - } - res = mempool_p2p_runner_handle => { - error!("Mempool P2P Runner Server stopped."); - res? - } - }; - error!("Servers ended with unexpected Ok."); - - Ok(result?) +pub async fn run_component_servers(servers: SequencerNodeServers) { + // TODO(alonl): check if we can use create_servers instead of extending a new + // FuturesUnordered. + let mut all_servers = FuturesUnordered::new(); + all_servers.extend(servers.local_servers.run().await); + all_servers.extend(servers.remote_servers.run().await); + all_servers.extend(servers.wrapper_servers.run().await); + + if let Some(servers_type) = all_servers.next().await { + // TODO(alonl): check all tasks are exited properly in case of a server failure before + // panicing. + panic!("{} Servers ended unexpectedly.", servers_type); + } else { + unreachable!("all_servers is never empty"); + } } -pub fn get_server_future( +type ComponentServerFuture = Pin + Send>>; + +fn get_server_future( server: Option>, -) -> Pin> + Send>> { +) -> ComponentServerFuture { match server { Some(mut server) => async move { server.start().await }.boxed(), None => pending().boxed(), } } + +pub fn server_future_and_label( + server: Option>, + label: &str, +) -> (ComponentServerFuture, String) { + (get_server_future(server), label.to_string()) +} diff --git a/crates/starknet_sequencer_node/src/test_utils/compilation.rs b/crates/starknet_sequencer_node/src/test_utils/compilation.rs deleted file mode 100644 index 5975f44073e..00000000000 --- a/crates/starknet_sequencer_node/src/test_utils/compilation.rs +++ /dev/null @@ -1,49 +0,0 @@ -use std::io; -use std::process::{ExitStatus, Stdio}; - -use infra_utils::command::create_shell_command; -use tracing::info; - -pub const NODE_EXECUTABLE_PATH: &str = "target/debug/starknet_sequencer_node"; - -#[cfg(test)] -#[path = "compilation_test.rs"] -mod compilation_test; - -#[derive(thiserror::Error, Debug)] -pub enum NodeCompilationError { - #[error(transparent)] - IO(#[from] io::Error), - #[error("Exit status: {0}.")] - Status(ExitStatus), -} - -/// Compiles the node using `cargo build` for testing purposes. -async fn compile_node() -> io::Result { - info!( - "Compiling the starknet_sequencer_node binary, expected destination: \ - {NODE_EXECUTABLE_PATH}" - ); - - // Run `cargo build` to compile the project - let compilation_result = create_shell_command("cargo") - .arg("build") - .arg("--bin") - .arg("starknet_sequencer_node") - .arg("--quiet") - .stderr(Stdio::inherit()) - .stdout(Stdio::inherit()) - .status() - .await?; - - info!("Compilation result: {:?}", compilation_result); - Ok(compilation_result) -} - -pub async fn compile_node_result() -> Result<(), NodeCompilationError> { - match compile_node().await { - Ok(status) if status.success() => Ok(()), - Ok(status) => Err(NodeCompilationError::Status(status)), - Err(e) => Err(NodeCompilationError::IO(e)), - } -} diff --git a/crates/starknet_sequencer_node/src/test_utils/compilation_test.rs b/crates/starknet_sequencer_node/src/test_utils/compilation_test.rs deleted file mode 100644 index 3e2f6b6200d..00000000000 --- a/crates/starknet_sequencer_node/src/test_utils/compilation_test.rs +++ /dev/null @@ -1,9 +0,0 @@ -use rstest::rstest; - -use crate::test_utils::compilation::compile_node_result; - -#[rstest] -#[tokio::test] -async fn test_compile_node() { - assert!(compile_node_result().await.is_ok(), "Compilation failed"); -} diff --git a/crates/starknet_sequencer_node/src/test_utils/mod.rs b/crates/starknet_sequencer_node/src/test_utils/mod.rs index 8753047299b..32969347369 100644 --- a/crates/starknet_sequencer_node/src/test_utils/mod.rs +++ b/crates/starknet_sequencer_node/src/test_utils/mod.rs @@ -1 +1 @@ -pub mod compilation; +pub mod node_runner; diff --git a/crates/starknet_sequencer_node/src/test_utils/node_runner.rs b/crates/starknet_sequencer_node/src/test_utils/node_runner.rs new file mode 100644 index 00000000000..eea83c56f8c --- /dev/null +++ b/crates/starknet_sequencer_node/src/test_utils/node_runner.rs @@ -0,0 +1,137 @@ +use std::fs::create_dir_all; +use std::path::PathBuf; +use std::process::Stdio; + +use starknet_infra_utils::command::create_shell_command; +use starknet_infra_utils::path::resolve_project_relative_path; +use tokio::fs::File; +use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader}; +use tokio::process::Child; +use tokio::task::{self, JoinHandle}; +use tracing::{error, info, instrument}; + +pub const NODE_EXECUTABLE_PATH: &str = "target/debug/starknet_sequencer_node"; +const TEMP_LOGS_DIR: &str = "integration_test_temporary_logs"; + +#[derive(Debug, Clone)] +pub struct NodeRunner { + node_index: usize, + executable_index: usize, +} + +impl NodeRunner { + pub fn new(node_index: usize, executable_index: usize) -> Self { + create_dir_all(TEMP_LOGS_DIR).unwrap(); + Self { node_index, executable_index } + } + + pub fn get_description(&self) -> String { + format!("Node id {} part {}:", self.node_index, self.executable_index) + } + + pub fn logs_file_path(&self) -> PathBuf { + PathBuf::from(TEMP_LOGS_DIR) + .join(format!("node_{}_part_{}.log", self.node_index, self.executable_index)) + } +} + +pub fn spawn_run_node(node_config_path: PathBuf, node_runner: NodeRunner) -> JoinHandle<()> { + task::spawn(async move { + info!("Running the node from its spawned task."); + // Obtain both handles, as the processes are terminated when their handles are dropped. + let (mut node_handle, _annotator_handle) = + spawn_node_child_process(node_config_path, node_runner.clone()).await; + let _node_run_result = node_handle. + wait(). // Runs the node until completion, should be running indefinitely. + await; // Awaits the completion of the node. + panic!("Node {:?} stopped unexpectedly.", node_runner); + }) +} + +#[instrument(skip(node_runner))] +async fn spawn_node_child_process( + node_config_path: PathBuf, + node_runner: NodeRunner, +) -> (Child, Child) { + info!("Getting the node executable."); + let node_executable = get_node_executable_path(); + + info!("Running the node from: {}", node_executable); + let mut node_cmd: Child = create_shell_command(node_executable.as_str()) + .arg("--config_file") + .arg(node_config_path.to_str().unwrap()) + .stderr(Stdio::inherit()) + .stdout(Stdio::piped()) + .kill_on_drop(true) // Required for stopping when the handle is dropped. + .spawn() + .expect("Spawning sequencer node should succeed."); + + let mut annotator_cmd: Child = create_shell_command("awk") + .arg("-v") + // Print the prefix in different colors. + .arg(format!("prefix=\u{1b}[3{}m{}\u{1b}[0m", node_runner.node_index+1, node_runner.get_description())) + .arg("{print prefix, $0}") + .stdin(std::process::Stdio::piped()) + .stderr(Stdio::inherit()) + .stdout(Stdio::inherit()) + .kill_on_drop(true) // Required for stopping when the handle is dropped. + .spawn() + .expect("Spawning node output annotation should succeed."); + + // Get the node stdout and the annotator stdin. + let node_stdout = node_cmd.stdout.take().expect("Node stdout should be available."); + let mut annotator_stdin = + annotator_cmd.stdin.take().expect("Annotator stdin should be available."); + + // Spawn a task to connect the node stdout with the annotator stdin. + tokio::spawn(async move { + let mut reader = BufReader::new(node_stdout).lines(); + info!("Writing node logs to file: {:?}", node_runner.logs_file_path()); + let mut file = + File::create(node_runner.logs_file_path()).await.expect("Failed to create log file."); + while let Some(line) = reader.next_line().await.transpose() { + match line { + Ok(line) => { + // Write to annotator stdin + if let Err(e) = annotator_stdin.write_all(line.as_bytes()).await { + error!("Failed to write to annotator stdin: {}", e); + } + if let Err(e) = annotator_stdin.write_all(b"\n").await { + error!("Failed to write newline to annotator stdin: {}", e); + } + + // Write to file + if let Err(e) = file.write_all(line.as_bytes()).await { + error!("Failed to write to file: {}", e); + } + if let Err(e) = file.write_all(b"\n").await { + error!("Failed to write newline to file: {}", e); + } + } + Err(e) => { + error!("Error while reading node stdout: {}", e); + } + } + } + + // Close the annotator stdin when done. + if let Err(e) = annotator_stdin.shutdown().await { + error!("Failed to shut down annotator stdin: {}", e); + } + }); + + (node_cmd, annotator_cmd) +} + +pub fn get_node_executable_path() -> String { + resolve_project_relative_path(NODE_EXECUTABLE_PATH).map_or_else( + |_| { + error!( + "Sequencer node binary is not present. Please compile it using 'cargo build --bin \ + starknet_sequencer_node' command." + ); + panic!("Node executable should be available"); + }, + |path| path.to_string_lossy().to_string(), + ) +} diff --git a/crates/starknet_sequencer_node/src/utils.rs b/crates/starknet_sequencer_node/src/utils.rs index 990ca27d90f..204813afc83 100644 --- a/crates/starknet_sequencer_node/src/utils.rs +++ b/crates/starknet_sequencer_node/src/utils.rs @@ -1,16 +1,48 @@ +use std::process::exit; + +use papyrus_config::presentation::get_config_presentation; +use papyrus_config::validators::config_validate; +use papyrus_config::ConfigError; +use tracing::{error, info}; + use crate::clients::{create_node_clients, SequencerNodeClients}; use crate::communication::create_node_channels; use crate::components::create_node_components; use crate::config::node_config::SequencerNodeConfig; use crate::servers::{create_node_servers, SequencerNodeServers}; -pub fn create_node_modules( +pub async fn create_node_modules( config: &SequencerNodeConfig, ) -> (SequencerNodeClients, SequencerNodeServers) { let mut channels = create_node_channels(); let clients = create_node_clients(config, &mut channels); - let components = create_node_components(config, &clients); + let components = create_node_components(config, &clients).await; let servers = create_node_servers(config, &mut channels, components, &clients); (clients, servers) } + +pub fn load_and_validate_config(args: Vec) -> Result { + let config = SequencerNodeConfig::load_and_process(args); + if let Err(ConfigError::CommandInput(clap_err)) = &config { + error!("Failed loading configuration: {}", clap_err); + clap_err.exit(); + } + info!("Finished loading configuration."); + + let config = config?; + if let Err(error) = config_validate(&config) { + error!("{}", error); + exit(1); + } + info!("Finished validating configuration."); + + info!("Config map:"); + info!( + "{:#?}", + get_config_presentation::(&config, false) + .expect("Should be able to get representation.") + ); + + Ok(config) +} diff --git a/crates/starknet_sequencer_node/src/version_test.rs b/crates/starknet_sequencer_node/src/version_test.rs index 65e50bfd9d3..13afebce468 100644 --- a/crates/starknet_sequencer_node/src/version_test.rs +++ b/crates/starknet_sequencer_node/src/version_test.rs @@ -1,7 +1,7 @@ use pretty_assertions::assert_eq; #[test] -fn test_version() { +fn version() { let expected_version = format!("{}.{}.{}", super::VERSION_MAJOR, super::VERSION_MINOR, super::VERSION_PATCH); assert_eq!(super::VERSION, expected_version); diff --git a/crates/starknet_sierra_compile/src/build_utils.rs b/crates/starknet_sierra_compile/src/build_utils.rs deleted file mode 100644 index 279668e2e42..00000000000 --- a/crates/starknet_sierra_compile/src/build_utils.rs +++ /dev/null @@ -1,40 +0,0 @@ -use std::path::{Path, PathBuf}; - -pub(crate) const CAIRO_LANG_BINARY_NAME: &str = "starknet-sierra-compile"; -#[cfg(feature = "cairo_native")] -pub(crate) const CAIRO_NATIVE_BINARY_NAME: &str = "starknet-native-compile"; - -fn out_dir() -> PathBuf { - Path::new(&std::env::var("OUT_DIR").expect("Failed to get the OUT_DIR environment variable")) - .to_path_buf() -} - -/// Get the crate's `OUT_DIR` and navigate up to reach the `target/BUILD_FLAVOR` directory. -/// This directory is shared across all crates in this project. -fn target_dir() -> PathBuf { - let out_dir = out_dir(); - - out_dir - .ancestors() - .nth(3) - .expect("Failed to navigate up three levels from OUT_DIR") - .to_path_buf() -} - -fn shared_folder_dir() -> PathBuf { - target_dir().join("shared_executables") -} - -pub fn binary_path(binary_name: &str) -> PathBuf { - shared_folder_dir().join(binary_name) -} - -#[cfg(feature = "cairo_native")] -pub fn output_file_path() -> String { - out_dir().join("output.so").to_str().unwrap().into() -} - -#[cfg(feature = "cairo_native")] -pub fn repo_root_dir() -> PathBuf { - Path::new(&std::env::var("CARGO_MANIFEST_DIR").unwrap()).join("../..").to_path_buf() -} diff --git a/crates/starknet_sierra_compile/src/command_line_compiler.rs b/crates/starknet_sierra_compile/src/command_line_compiler.rs deleted file mode 100644 index d485c2a960c..00000000000 --- a/crates/starknet_sierra_compile/src/command_line_compiler.rs +++ /dev/null @@ -1,100 +0,0 @@ -use std::io::Write; -use std::path::{Path, PathBuf}; -use std::process::Command; - -use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass; -use cairo_lang_starknet_classes::contract_class::ContractClass; -#[cfg(feature = "cairo_native")] -use cairo_native::executor::AotContractExecutor; -use tempfile::NamedTempFile; - -use crate::build_utils::{binary_path, CAIRO_LANG_BINARY_NAME}; -#[cfg(feature = "cairo_native")] -use crate::build_utils::{output_file_path, CAIRO_NATIVE_BINARY_NAME}; -use crate::config::SierraToCasmCompilationConfig; -use crate::errors::CompilationUtilError; -use crate::SierraToCasmCompiler; -#[cfg(feature = "cairo_native")] -use crate::SierraToNativeCompiler; - -#[derive(Clone)] -pub struct CommandLineCompiler { - pub config: SierraToCasmCompilationConfig, - path_to_starknet_sierra_compile_binary: PathBuf, - #[cfg(feature = "cairo_native")] - path_to_starknet_native_compile_binary: PathBuf, -} - -impl CommandLineCompiler { - pub fn new(config: SierraToCasmCompilationConfig) -> Self { - Self { - config, - path_to_starknet_sierra_compile_binary: binary_path(CAIRO_LANG_BINARY_NAME), - #[cfg(feature = "cairo_native")] - path_to_starknet_native_compile_binary: binary_path(CAIRO_NATIVE_BINARY_NAME), - } - } -} - -impl SierraToCasmCompiler for CommandLineCompiler { - fn compile( - &self, - contract_class: ContractClass, - ) -> Result { - let compiler_binary_path = &self.path_to_starknet_sierra_compile_binary; - let additional_args = [ - "--add-pythonic-hints", - "--max-bytecode-size", - &self.config.max_bytecode_size.to_string(), - ]; - - let stdout = compile_with_args(compiler_binary_path, contract_class, &additional_args)?; - Ok(serde_json::from_slice::(&stdout)?) - } -} - -#[cfg(feature = "cairo_native")] -impl SierraToNativeCompiler for CommandLineCompiler { - fn compile_to_native( - &self, - contract_class: ContractClass, - ) -> Result { - let compiler_binary_path = &self.path_to_starknet_native_compile_binary; - let output_file_path = output_file_path(); - let additional_args = [output_file_path.as_str()]; - - let _stdout = compile_with_args(compiler_binary_path, contract_class, &additional_args)?; - - Ok(AotContractExecutor::load(Path::new(&output_file_path))?) - } -} - -fn compile_with_args( - compiler_binary_path: &Path, - contract_class: ContractClass, - additional_args: &[&str], -) -> Result, CompilationUtilError> { - // Create a temporary file to store the Sierra contract class. - let serialized_contract_class = serde_json::to_string(&contract_class)?; - - let mut temp_file = NamedTempFile::new()?; - temp_file.write_all(serialized_contract_class.as_bytes())?; - let temp_file_path = temp_file.path().to_str().ok_or(CompilationUtilError::UnexpectedError( - "Failed to get temporary file path".to_owned(), - ))?; - - // Set the parameters for the compile process. - // TODO(Arni, Avi): Setup the ulimit for the process. - let mut command = Command::new(compiler_binary_path.as_os_str()); - command.arg(temp_file_path).args(additional_args); - - // Run the compile process. - let compile_output = command.output()?; - - if !compile_output.status.success() { - let stderr_output = String::from_utf8(compile_output.stderr) - .unwrap_or("Failed to get stderr output".into()); - return Err(CompilationUtilError::CompilationError(stderr_output)); - }; - Ok(compile_output.stdout) -} diff --git a/crates/starknet_sierra_compile/src/compile_test.rs b/crates/starknet_sierra_compile/src/compile_test.rs deleted file mode 100644 index 642cd4e4b9d..00000000000 --- a/crates/starknet_sierra_compile/src/compile_test.rs +++ /dev/null @@ -1,78 +0,0 @@ -use std::env; -use std::path::Path; - -use assert_matches::assert_matches; -use cairo_lang_starknet_classes::contract_class::ContractClass; -use infra_utils::path::resolve_project_relative_path; -use mempool_test_utils::{FAULTY_ACCOUNT_CLASS_FILE, TEST_FILES_FOLDER}; -use rstest::rstest; - -use crate::command_line_compiler::CommandLineCompiler; -use crate::config::SierraToCasmCompilationConfig; -use crate::errors::CompilationUtilError; -use crate::test_utils::contract_class_from_file; -use crate::SierraToCasmCompiler; -#[cfg(feature = "cairo_native")] -use crate::SierraToNativeCompiler; - -const SIERRA_TO_CASM_COMPILATION_CONFIG: SierraToCasmCompilationConfig = - SierraToCasmCompilationConfig { max_bytecode_size: 81920 }; - -fn command_line_compiler() -> CommandLineCompiler { - CommandLineCompiler::new(SIERRA_TO_CASM_COMPILATION_CONFIG) -} -fn get_test_contract() -> ContractClass { - env::set_current_dir(resolve_project_relative_path(TEST_FILES_FOLDER).unwrap()) - .expect("Failed to set current dir."); - let sierra_path = Path::new(FAULTY_ACCOUNT_CLASS_FILE); - contract_class_from_file(sierra_path) -} - -fn get_faulty_test_contract() -> ContractClass { - let mut contract_class = get_test_contract(); - // Truncate the sierra program to trigger an error. - contract_class.sierra_program = contract_class.sierra_program[..100].to_vec(); - contract_class -} - -#[rstest] -#[case::command_line_compiler(command_line_compiler())] -fn test_compile_sierra_to_casm(#[case] compiler: impl SierraToCasmCompiler) { - let expected_casm_contract_length = 72304; - - let contract_class = get_test_contract(); - let casm_contract = compiler.compile(contract_class).unwrap(); - let serialized_casm = serde_json::to_string_pretty(&casm_contract).unwrap().into_bytes(); - - assert_eq!(serialized_casm.len(), expected_casm_contract_length); -} - -// TODO(Arni, 1/5/2024): Add a test for panic result test. -#[rstest] -#[case::command_line_compiler(command_line_compiler())] -fn test_negative_flow_compile_sierra_to_casm(#[case] compiler: impl SierraToCasmCompiler) { - let contract_class = get_faulty_test_contract(); - - let result = compiler.compile(contract_class); - assert_matches!(result, Err(CompilationUtilError::CompilationError(..))); -} - -#[cfg(feature = "cairo_native")] -#[test] -fn test_compile_sierra_to_native() { - let compiler = command_line_compiler(); - let contract_class = get_test_contract(); - - // TODO(Avi, 1/1/2025): Check size/memory/time limits. - let _native_contract_executor = compiler.compile_to_native(contract_class).unwrap(); -} - -#[cfg(feature = "cairo_native")] -#[test] -fn test_negative_flow_compile_sierra_to_native() { - let compiler = command_line_compiler(); - let contract_class = get_faulty_test_contract(); - - let result = compiler.compile_to_native(contract_class); - assert_matches!(result, Err(CompilationUtilError::CompilationError(..))); -} diff --git a/crates/starknet_sierra_compile/src/config.rs b/crates/starknet_sierra_compile/src/config.rs deleted file mode 100644 index e3601b6f8ec..00000000000 --- a/crates/starknet_sierra_compile/src/config.rs +++ /dev/null @@ -1,29 +0,0 @@ -use std::collections::BTreeMap; - -use papyrus_config::dumping::{ser_param, SerializeConfig}; -use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; -use serde::{Deserialize, Serialize}; -use validator::Validate; - -#[derive(Clone, Debug, Serialize, Deserialize, Validate, PartialEq)] -pub struct SierraToCasmCompilationConfig { - /// CASM bytecode size limit. - pub max_bytecode_size: usize, -} - -impl Default for SierraToCasmCompilationConfig { - fn default() -> Self { - Self { max_bytecode_size: 81920 } - } -} - -impl SerializeConfig for SierraToCasmCompilationConfig { - fn dump(&self) -> BTreeMap { - BTreeMap::from_iter([ser_param( - "max_bytecode_size", - &self.max_bytecode_size, - "Limitation of contract bytecode size.", - ParamPrivacyInput::Public, - )]) - } -} diff --git a/crates/starknet_sierra_compile/src/lib.rs b/crates/starknet_sierra_compile/src/lib.rs deleted file mode 100644 index 1e79589aa3a..00000000000 --- a/crates/starknet_sierra_compile/src/lib.rs +++ /dev/null @@ -1,35 +0,0 @@ -//! A lib for compiling Sierra into Casm. -use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass; -use cairo_lang_starknet_classes::contract_class::ContractClass; -#[cfg(feature = "cairo_native")] -use cairo_native::executor::AotContractExecutor; - -use crate::errors::CompilationUtilError; - -pub mod build_utils; -pub mod command_line_compiler; -pub mod config; -pub mod errors; -pub mod utils; - -#[cfg(test)] -pub mod test_utils; - -#[cfg(test)] -#[path = "compile_test.rs"] -pub mod compile_test; - -pub trait SierraToCasmCompiler: Send + Sync { - fn compile( - &self, - contract_class: ContractClass, - ) -> Result; -} - -#[cfg(feature = "cairo_native")] -pub trait SierraToNativeCompiler: Send + Sync { - fn compile_to_native( - &self, - contract_class: ContractClass, - ) -> Result; -} diff --git a/crates/starknet_sierra_compile/Cargo.toml b/crates/starknet_sierra_multicompile/Cargo.toml similarity index 59% rename from crates/starknet_sierra_compile/Cargo.toml rename to crates/starknet_sierra_multicompile/Cargo.toml index 8e40f025b3a..db4c818ee03 100644 --- a/crates/starknet_sierra_compile/Cargo.toml +++ b/crates/starknet_sierra_multicompile/Cargo.toml @@ -1,9 +1,10 @@ [package] edition.workspace = true license.workspace = true -name = "starknet_sierra_compile" +name = "starknet_sierra_multicompile" repository.workspace = true version.workspace = true +description = "A utility crate for compiling Sierra code into CASM and / or native." [features] cairo_native = ["dep:cairo-native"] @@ -12,21 +13,32 @@ cairo_native = ["dep:cairo-native"] workspace = true [dependencies] +async-trait.workspace = true cairo-lang-sierra.workspace = true cairo-lang-starknet-classes.workspace = true cairo-lang-utils.workspace = true cairo-native = { workspace = true, optional = true } papyrus_config.workspace = true +rlimit.workspace = true serde.workspace = true serde_json.workspace = true starknet-types-core.workspace = true starknet_api.workspace = true +starknet_sequencer_infra.workspace = true +starknet_sierra_multicompile_types.workspace = true tempfile.workspace = true thiserror.workspace = true +tracing.workspace = true validator.workspace = true [dev-dependencies] assert_matches.workspace = true -infra_utils.workspace = true mempool_test_utils.workspace = true rstest.workspace = true +starknet_api.workspace = true +starknet_infra_utils.workspace = true +toml_test_utils.workspace = true + +[build-dependencies] +starknet_infra_utils.workspace = true +tempfile.workspace = true diff --git a/crates/starknet_sierra_compile/build.rs b/crates/starknet_sierra_multicompile/build.rs similarity index 60% rename from crates/starknet_sierra_compile/build.rs rename to crates/starknet_sierra_multicompile/build.rs index 86807edfd25..e6d21744b25 100644 --- a/crates/starknet_sierra_compile/build.rs +++ b/crates/starknet_sierra_multicompile/build.rs @@ -1,20 +1,20 @@ use std::process::Command; -include!("src/build_utils.rs"); +use tempfile::TempDir; + +include!("src/constants.rs"); +include!("src/paths.rs"); fn main() { println!("cargo:rerun-if-changed=../../Cargo.lock"); println!("cargo:rerun-if-changed=build.rs"); + set_run_time_out_dir_env_var(); install_starknet_sierra_compile(); #[cfg(feature = "cairo_native")] install_starknet_native_compile(); } -const REQUIRED_CAIRO_LANG_VERSION: &str = "2.7.1"; -#[cfg(feature = "cairo_native")] -const REQUIRED_CAIRO_NATIVE_VERSION: &str = "0.2.1-alpha.0"; - /// Downloads the Cairo crate from StarkWare's release page and extracts its contents into the /// `target` directory. This crate includes the `starknet-sierra-compile` binary, which is used to /// compile Sierra to Casm. The binary is executed as a subprocess whenever Sierra compilation is @@ -23,43 +23,26 @@ fn install_starknet_sierra_compile() { let binary_name = CAIRO_LANG_BINARY_NAME; let required_version = REQUIRED_CAIRO_LANG_VERSION; - let cairo_lang_binary_path = binary_path(binary_name); - println!("cargo:rerun-if-changed={:?}", cairo_lang_binary_path); - let cargo_install_args = &[binary_name, "--version", required_version]; install_compiler_binary(binary_name, required_version, cargo_install_args); } -/// Installs the `starknet-native-compile` crate from the current repository and moves the binary -/// to the shared executables folder. This crate includes the `starknet-native-compile` binary, +/// Install the `starknet-native-compile` crate and moves the binary to the `target` directory +/// (under shared executables folder). This crate includes the `starknet-native-compile` binary, /// which is used to compile Sierra to 0x86. The binary is executed as a subprocess whenever Sierra -/// compilation is required. +/// to native compilation is required. #[cfg(feature = "cairo_native")] fn install_starknet_native_compile() { let binary_name = CAIRO_NATIVE_BINARY_NAME; let required_version = REQUIRED_CAIRO_NATIVE_VERSION; - let cairo_native_binary_path = binary_path(binary_name); - println!("cargo:rerun-if-changed={:?}", cairo_native_binary_path); - - // Set the runtime library path. This is required for Cairo native compilation. - let runtime_library_path = repo_root_dir() - .join("crates/blockifier/cairo_native/target/release/libcairo_native_runtime.a"); - println!("cargo:rustc-env=CAIRO_NATIVE_RUNTIME_LIBRARY={}", runtime_library_path.display()); - println!("cargo:rerun-if-env-changed=CAIRO_NATIVE_RUNTIME_LIBRARY"); - - let starknet_native_compile_crate_path = repo_root_dir().join("crates/bin").join(binary_name); - let starknet_native_compile_crate_path_str = starknet_native_compile_crate_path - .to_str() - .expect("Failed to convert the crate path to str"); - println!("cargo:rerun-if-changed={}", starknet_native_compile_crate_path_str); - - let cargo_install_args = &["--path", starknet_native_compile_crate_path_str]; + let cargo_install_args = &["cairo-native", "--version", required_version, "--bin", binary_name]; install_compiler_binary(binary_name, required_version, cargo_install_args); } fn install_compiler_binary(binary_name: &str, required_version: &str, cargo_install_args: &[&str]) { - let binary_path = binary_path(binary_name); + let binary_path = binary_path(out_dir(), binary_name); + println!("cargo:rerun-if-changed={}", binary_path.to_str().unwrap()); match Command::new(&binary_path).args(["--version"]).output() { Ok(binary_version) => { @@ -80,17 +63,15 @@ fn install_compiler_binary(binary_name: &str, required_version: &str, cargo_inst } } - let out_dir = out_dir(); - let temp_cargo_path = out_dir.join("cargo"); - let post_install_file_path = temp_cargo_path.join("bin").join(binary_name); + let temp_cargo_path = TempDir::new().expect("Failed to create a temporary directory."); + let post_install_file_path = temp_cargo_path.path().join("bin").join(binary_name); - // Create the temporary cargo directory if it doesn't exist - std::fs::create_dir_all(&temp_cargo_path).expect("Failed to create cargo directory"); let install_command_status = Command::new("cargo") .args([ "install", "--root", - temp_cargo_path.to_str().expect("Failed to convert cargo_path to str"), + temp_cargo_path.path().to_str().expect("Failed to convert cargo_path to str"), + "--locked", ]) .args(cargo_install_args) .status() @@ -100,8 +81,8 @@ fn install_compiler_binary(binary_name: &str, required_version: &str, cargo_inst panic!("Failed to install {}", binary_name); } - // Move the 'starknet-sierra-compile' executable to a shared location - std::fs::create_dir_all(shared_folder_dir()) + // Move the '{binary_name}' executable to a shared location. + std::fs::create_dir_all(shared_folder_dir(out_dir())) .expect("Failed to create shared executables folder"); let move_command_status = Command::new("mv") .args([post_install_file_path.as_os_str(), binary_path.as_os_str()]) @@ -116,3 +97,17 @@ fn install_compiler_binary(binary_name: &str, required_version: &str, cargo_inst println!("Successfully set executable file: {:?}", binary_path.display()); } + +// Sets the `RUNTIME_ACCESSIBLE_OUT_DIR` environment variable to the `OUT_DIR` value, which will be +// available only after the build is completed. Most importantly, it is available during runtime. +fn set_run_time_out_dir_env_var() { + let out_dir = std::env::var("OUT_DIR").expect("OUT_DIR is not set"); + println!("cargo:rustc-env=RUNTIME_ACCESSIBLE_OUT_DIR={}", out_dir); +} + +// Returns the OUT_DIR. This function is only operable at build time. +fn out_dir() -> std::path::PathBuf { + std::env::var("OUT_DIR") + .expect("Failed to get the build time OUT_DIR environment variable") + .into() +} diff --git a/crates/starknet_sierra_multicompile/src/command_line_compiler.rs b/crates/starknet_sierra_multicompile/src/command_line_compiler.rs new file mode 100644 index 00000000000..c427be43ee6 --- /dev/null +++ b/crates/starknet_sierra_multicompile/src/command_line_compiler.rs @@ -0,0 +1,148 @@ +use std::io::Write; +use std::path::{Path, PathBuf}; +use std::process::Command; + +use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass; +use cairo_lang_starknet_classes::contract_class::ContractClass; +#[cfg(feature = "cairo_native")] +use cairo_native::executor::AotContractExecutor; +use tempfile::NamedTempFile; +use tracing::info; + +use crate::config::SierraCompilationConfig; +use crate::constants::CAIRO_LANG_BINARY_NAME; +#[cfg(feature = "cairo_native")] +use crate::constants::CAIRO_NATIVE_BINARY_NAME; +use crate::errors::CompilationUtilError; +use crate::paths::binary_path; +use crate::resource_limits::ResourceLimits; +use crate::SierraToCasmCompiler; +#[cfg(feature = "cairo_native")] +use crate::SierraToNativeCompiler; + +#[derive(Clone)] +pub struct CommandLineCompiler { + pub config: SierraCompilationConfig, + path_to_starknet_sierra_compile_binary: PathBuf, + #[cfg(feature = "cairo_native")] + path_to_starknet_native_compile_binary: PathBuf, +} + +impl CommandLineCompiler { + pub fn new(config: SierraCompilationConfig) -> Self { + let path_to_starknet_sierra_compile_binary = binary_path(out_dir(), CAIRO_LANG_BINARY_NAME); + info!("Using Sierra compiler binary at: {:?}", path_to_starknet_sierra_compile_binary); + + #[cfg(feature = "cairo_native")] + let path_to_starknet_native_compile_binary = match &config.sierra_to_native_compiler_path { + Some(path) => path.clone(), + None => binary_path(out_dir(), CAIRO_NATIVE_BINARY_NAME), + }; + Self { + config, + path_to_starknet_sierra_compile_binary, + #[cfg(feature = "cairo_native")] + path_to_starknet_native_compile_binary, + } + } +} + +impl SierraToCasmCompiler for CommandLineCompiler { + fn compile( + &self, + contract_class: ContractClass, + ) -> Result { + let compiler_binary_path = &self.path_to_starknet_sierra_compile_binary; + let additional_args = &[ + "--add-pythonic-hints", + "--max-bytecode-size", + &self.config.max_casm_bytecode_size.to_string(), + ]; + let resource_limits = ResourceLimits::new(None, None, None); + + let stdout = compile_with_args( + compiler_binary_path, + contract_class, + additional_args, + resource_limits, + )?; + Ok(serde_json::from_slice::(&stdout)?) + } +} + +#[cfg(feature = "cairo_native")] +impl SierraToNativeCompiler for CommandLineCompiler { + fn compile_to_native( + &self, + contract_class: ContractClass, + ) -> Result { + let compiler_binary_path = &self.path_to_starknet_native_compile_binary; + + let output_file = NamedTempFile::new()?; + let output_file_path = output_file.path().to_str().ok_or( + CompilationUtilError::UnexpectedError("Failed to get output file path".to_owned()), + )?; + let optimization_level = self.config.optimization_level.to_string(); + let additional_args = [output_file_path, "--opt-level", &optimization_level]; + let resource_limits = ResourceLimits::new( + Some(self.config.max_cpu_time), + Some(self.config.max_native_bytecode_size), + Some(self.config.max_memory_usage), + ); + let _stdout = compile_with_args( + compiler_binary_path, + contract_class, + &additional_args, + resource_limits, + )?; + + Ok(AotContractExecutor::from_path(Path::new(&output_file_path))?.unwrap()) + } + + fn panic_on_compilation_failure(&self) -> bool { + self.config.panic_on_compilation_failure + } +} + +fn compile_with_args( + compiler_binary_path: &Path, + contract_class: ContractClass, + additional_args: &[&str], + resource_limits: ResourceLimits, +) -> Result, CompilationUtilError> { + // Create a temporary file to store the Sierra contract class. + let serialized_contract_class = serde_json::to_string(&contract_class)?; + + let mut temp_file = NamedTempFile::new()?; + temp_file.write_all(serialized_contract_class.as_bytes())?; + let temp_file_path = temp_file.path().to_str().ok_or(CompilationUtilError::UnexpectedError( + "Failed to get temporary file path".to_owned(), + ))?; + + // Set the parameters for the compile process. + // TODO(Arni, Avi): Setup the ulimit for the process. + let mut command = Command::new(compiler_binary_path.as_os_str()); + command.arg(temp_file_path).args(additional_args); + + // Apply the resource limits to the command. + resource_limits.apply(&mut command); + + // Run the compile process. + let compile_output = command.output()?; + + if !compile_output.status.success() { + let stderr_output = String::from_utf8(compile_output.stderr) + .unwrap_or("Failed to get stderr output".into()); + // TODO(Avi, 28/2/2025): Make the error messages more readable. + return Err(CompilationUtilError::CompilationError(format!( + "Exit status: {}\n Stderr: {}", + compile_output.status, stderr_output + ))); + }; + Ok(compile_output.stdout) +} + +// Returns the OUT_DIR. This function is only operable at run time. +fn out_dir() -> PathBuf { + env!("RUNTIME_ACCESSIBLE_OUT_DIR").into() +} diff --git a/crates/starknet_sierra_multicompile/src/communication.rs b/crates/starknet_sierra_multicompile/src/communication.rs new file mode 100644 index 00000000000..72a78a689d6 --- /dev/null +++ b/crates/starknet_sierra_multicompile/src/communication.rs @@ -0,0 +1,31 @@ +use async_trait::async_trait; +use starknet_sequencer_infra::component_definitions::ComponentRequestHandler; +use starknet_sequencer_infra::component_server::{ + ConcurrentLocalComponentServer, + RemoteComponentServer, +}; +use starknet_sierra_multicompile_types::{ + SierraCompilerError, + SierraCompilerRequest, + SierraCompilerResponse, +}; + +use crate::SierraCompiler; + +pub type LocalSierraCompilerServer = + ConcurrentLocalComponentServer; +pub type RemoteSierraCompilerServer = + RemoteComponentServer; + +#[async_trait] +impl ComponentRequestHandler for SierraCompiler { + async fn handle_request(&mut self, request: SierraCompilerRequest) -> SierraCompilerResponse { + match request { + SierraCompilerRequest::Compile(contract_class) => { + let compilation_result = + self.compile(contract_class).map_err(SierraCompilerError::from); + SierraCompilerResponse::Compile(compilation_result) + } + } + } +} diff --git a/crates/starknet_sierra_multicompile/src/compile_test.rs b/crates/starknet_sierra_multicompile/src/compile_test.rs new file mode 100644 index 00000000000..1580e440894 --- /dev/null +++ b/crates/starknet_sierra_multicompile/src/compile_test.rs @@ -0,0 +1,143 @@ +use std::env; +use std::path::Path; + +use assert_matches::assert_matches; +use cairo_lang_starknet_classes::contract_class::ContractClass as CairoLangContractClass; +use mempool_test_utils::{FAULTY_ACCOUNT_CLASS_FILE, TEST_FILES_FOLDER}; +use rstest::rstest; +use starknet_api::contract_class::{ContractClass, SierraVersion}; +use starknet_api::state::SierraContractClass; +use starknet_infra_utils::path::resolve_project_relative_path; + +use crate::command_line_compiler::CommandLineCompiler; +use crate::config::{ + SierraCompilationConfig, + DEFAULT_MAX_CASM_BYTECODE_SIZE, + DEFAULT_MAX_CPU_TIME, + DEFAULT_MAX_MEMORY_USAGE, + DEFAULT_MAX_NATIVE_BYTECODE_SIZE, + DEFAULT_OPTIMIZATION_LEVEL, +}; +use crate::errors::CompilationUtilError; +use crate::test_utils::contract_class_from_file; +#[cfg(feature = "cairo_native")] +use crate::SierraToNativeCompiler; +use crate::{RawClass, SierraCompiler, SierraToCasmCompiler}; + +const SIERRA_COMPILATION_CONFIG: SierraCompilationConfig = SierraCompilationConfig { + max_casm_bytecode_size: DEFAULT_MAX_CASM_BYTECODE_SIZE, + sierra_to_native_compiler_path: None, + max_native_bytecode_size: DEFAULT_MAX_NATIVE_BYTECODE_SIZE, + max_cpu_time: DEFAULT_MAX_CPU_TIME, + max_memory_usage: DEFAULT_MAX_MEMORY_USAGE, + panic_on_compilation_failure: true, + optimization_level: DEFAULT_OPTIMIZATION_LEVEL, +}; + +fn command_line_compiler() -> CommandLineCompiler { + CommandLineCompiler::new(SIERRA_COMPILATION_CONFIG) +} + +fn get_test_contract() -> CairoLangContractClass { + env::set_current_dir(resolve_project_relative_path(TEST_FILES_FOLDER).unwrap()) + .expect("Failed to set current dir."); + let sierra_path = Path::new(FAULTY_ACCOUNT_CLASS_FILE); + contract_class_from_file(sierra_path) +} + +fn get_faulty_test_contract() -> CairoLangContractClass { + let mut contract_class = get_test_contract(); + // Truncate the sierra program to trigger an error. + contract_class.sierra_program = contract_class.sierra_program[..100].to_vec(); + contract_class +} + +#[rstest] +#[case::command_line_compiler(command_line_compiler())] +fn test_compile_sierra_to_casm(#[case] compiler: impl SierraToCasmCompiler) { + let expected_casm_contract_length = 72305; + + let contract_class = get_test_contract(); + let casm_contract = compiler.compile(contract_class).unwrap(); + let serialized_casm = serde_json::to_string_pretty(&casm_contract).unwrap().into_bytes(); + + assert_eq!(serialized_casm.len(), expected_casm_contract_length); +} + +// TODO(Arni, 1/5/2024): Add a test for panic result test. +#[rstest] +#[case::command_line_compiler(command_line_compiler())] +fn test_negative_flow_compile_sierra_to_casm(#[case] compiler: impl SierraToCasmCompiler) { + let contract_class = get_faulty_test_contract(); + + let result = compiler.compile(contract_class); + assert_matches!(result, Err(CompilationUtilError::CompilationError(..))); +} + +#[cfg(feature = "cairo_native")] +#[test] +fn test_compile_sierra_to_native() { + let compiler = command_line_compiler(); + let contract_class = get_test_contract(); + + let _native_contract_executor = compiler.compile_to_native(contract_class).unwrap(); +} + +#[cfg(feature = "cairo_native")] +#[test] +fn test_negative_flow_compile_sierra_to_native() { + let compiler = command_line_compiler(); + let contract_class = get_faulty_test_contract(); + + let result = compiler.compile_to_native(contract_class); + assert_matches!(result, Err(CompilationUtilError::CompilationError(..))); +} + +#[rstest] +fn test_max_casm_bytecode_size() { + let contract_class = get_test_contract(); + let expected_casm_bytecode_length = 1965; + + // Positive flow. + let compiler = CommandLineCompiler::new(SierraCompilationConfig { + max_casm_bytecode_size: expected_casm_bytecode_length, + ..SierraCompilationConfig::default() + }); + let casm_contract_class = compiler.compile(contract_class.clone()).expect( + "Failed to compile contract class. Probably an issue with the max_casm_bytecode_size.", + ); + assert_eq!(casm_contract_class.bytecode.len(), expected_casm_bytecode_length); + + // Negative flow. + let compiler = CommandLineCompiler::new(SierraCompilationConfig { + max_casm_bytecode_size: expected_casm_bytecode_length - 1, + ..SierraCompilationConfig::default() + }); + let result = compiler.compile(contract_class); + assert_matches!(result, Err(CompilationUtilError::CompilationError(string)) + if string.contains("Code size limit exceeded.") + ); +} + +// TODO(Elin): mock compiler. +#[test] +fn test_sierra_compiler() { + // Setup. + let compiler = command_line_compiler(); + let class = get_test_contract(); + let expected_executable_class = compiler.compile(class.clone()).unwrap(); + + let compiler = SierraCompiler::new(compiler); + let class = SierraContractClass::from(class); + let sierra_version = SierraVersion::extract_from_program(&class.sierra_program).unwrap(); + let expected_executable_class = ContractClass::V1((expected_executable_class, sierra_version)); + + // Test. + let raw_class = RawClass::try_from(class).unwrap(); + let (raw_executable_class, executable_class_hash) = compiler.compile(raw_class).unwrap(); + let executable_class = ContractClass::try_from(raw_executable_class).unwrap(); + + // Assert. + assert_eq!(executable_class, expected_executable_class); + assert_eq!(executable_class_hash, expected_executable_class.compiled_class_hash()); +} diff --git a/crates/starknet_sierra_multicompile/src/config.rs b/crates/starknet_sierra_multicompile/src/config.rs new file mode 100644 index 00000000000..80deb413f41 --- /dev/null +++ b/crates/starknet_sierra_multicompile/src/config.rs @@ -0,0 +1,96 @@ +use std::collections::BTreeMap; +use std::path::PathBuf; + +use papyrus_config::dumping::{ser_optional_param, ser_param, SerializeConfig}; +use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; +use serde::{Deserialize, Serialize}; +use validator::Validate; + +pub const DEFAULT_MAX_CASM_BYTECODE_SIZE: usize = 80 * 1024; +// TODO(Noa): Reconsider the default values. +pub const DEFAULT_MAX_NATIVE_BYTECODE_SIZE: u64 = 15 * 1024 * 1024; +pub const DEFAULT_MAX_CPU_TIME: u64 = 20; +pub const DEFAULT_MAX_MEMORY_USAGE: u64 = 5 * 1024 * 1024 * 1024; +pub const DEFAULT_OPTIMIZATION_LEVEL: u8 = 2; + +#[derive(Clone, Debug, Serialize, Deserialize, Validate, PartialEq)] +pub struct SierraCompilationConfig { + /// CASM bytecode size limit (in felts). + pub max_casm_bytecode_size: usize, + /// Native bytecode size limit (in bytes). + pub max_native_bytecode_size: u64, + /// Compilation CPU time limit (in seconds). + pub max_cpu_time: u64, + /// Compilation process’s virtual memory (address space) byte limit. + pub max_memory_usage: u64, + /// The level of optimization to apply during compilation. + pub optimization_level: u8, + pub panic_on_compilation_failure: bool, + /// Sierra-to-Native compiler binary path. + pub sierra_to_native_compiler_path: Option, +} + +impl Default for SierraCompilationConfig { + fn default() -> Self { + Self { + max_casm_bytecode_size: DEFAULT_MAX_CASM_BYTECODE_SIZE, + sierra_to_native_compiler_path: None, + max_native_bytecode_size: DEFAULT_MAX_NATIVE_BYTECODE_SIZE, + max_cpu_time: DEFAULT_MAX_CPU_TIME, + max_memory_usage: DEFAULT_MAX_MEMORY_USAGE, + panic_on_compilation_failure: false, + optimization_level: DEFAULT_OPTIMIZATION_LEVEL, + } + } +} + +impl SerializeConfig for SierraCompilationConfig { + fn dump(&self) -> BTreeMap { + let mut dump = BTreeMap::from_iter([ + ser_param( + "max_casm_bytecode_size", + &self.max_casm_bytecode_size, + "Limitation of compiled casm bytecode size.", + ParamPrivacyInput::Public, + ), + ser_param( + "max_native_bytecode_size", + &self.max_native_bytecode_size, + "Limitation of compiled native bytecode size.", + ParamPrivacyInput::Public, + ), + ser_param( + "max_cpu_time", + &self.max_cpu_time, + "Limitation of compilation cpu time (seconds).", + ParamPrivacyInput::Public, + ), + ser_param( + "max_memory_usage", + &self.max_memory_usage, + "Limitation of compilation process's virtual memory (bytes).", + ParamPrivacyInput::Public, + ), + ser_param( + "optimization_level", + &self.optimization_level, + "The level of optimization to apply during compilation.", + ParamPrivacyInput::Public, + ), + ser_param( + "panic_on_compilation_failure", + &self.panic_on_compilation_failure, + "Whether to panic on compilation failure.", + ParamPrivacyInput::Public, + ), + ]); + dump.extend(ser_optional_param( + &self.sierra_to_native_compiler_path, + "".into(), + "sierra_to_native_compiler_path", + "The path to the Sierra-to-Native compiler binary.", + ParamPrivacyInput::Public, + )); + dump + } +} diff --git a/crates/starknet_sierra_multicompile/src/constants.rs b/crates/starknet_sierra_multicompile/src/constants.rs new file mode 100644 index 00000000000..ec17fd08c7d --- /dev/null +++ b/crates/starknet_sierra_multicompile/src/constants.rs @@ -0,0 +1,12 @@ +// Note: This module includes constants that are needed during build and run times. It must +// not contain functionality that is available in only in one of these modes. Specifically, it +// must avoid relying on env variables such as 'CARGO_*' or 'OUT_DIR'. + +pub(crate) const CAIRO_LANG_BINARY_NAME: &str = "starknet-sierra-compile"; +#[cfg(feature = "cairo_native")] +pub(crate) const CAIRO_NATIVE_BINARY_NAME: &str = "starknet-native-compile"; + +pub const REQUIRED_CAIRO_LANG_VERSION: &str = "2.11.2"; +// TODO(Elin): test version alignment with Cargo. +#[cfg(feature = "cairo_native")] +pub const REQUIRED_CAIRO_NATIVE_VERSION: &str = "0.3.1"; diff --git a/crates/starknet_sierra_multicompile/src/constants_test.rs b/crates/starknet_sierra_multicompile/src/constants_test.rs new file mode 100644 index 00000000000..2a35d253746 --- /dev/null +++ b/crates/starknet_sierra_multicompile/src/constants_test.rs @@ -0,0 +1,42 @@ +use starknet_infra_utils::cairo_compiler_version::cairo1_compiler_version; +#[cfg(feature = "cairo_native")] +use toml_test_utils::{DependencyValue, ROOT_TOML}; + +use crate::constants::REQUIRED_CAIRO_LANG_VERSION; +#[cfg(feature = "cairo_native")] +use crate::constants::REQUIRED_CAIRO_NATIVE_VERSION; + +#[cfg(feature = "cairo_native")] +#[test] +fn required_cairo_native_version_test() { + let cairo_native_version = ROOT_TOML + .dependencies() + .filter_map(|(name, value)| match (name.as_str(), value) { + ("cairo-native", DependencyValue::Object { version, .. }) => version.as_ref(), + ("cairo-native", DependencyValue::String(version)) => Some(version), + _ => None, + }) + .next() + .expect("cairo-native dependency not found in root toml file."); + assert_eq!(REQUIRED_CAIRO_NATIVE_VERSION, cairo_native_version); +} + +#[test] +fn cairo_compiler_version() { + let binary_version = REQUIRED_CAIRO_LANG_VERSION; + let cargo_version = cairo1_compiler_version(); + + // Only run the assertion if version >= 2.11. + // For older versions, just return, effectively skipping the test. + if cargo_version.starts_with("2.11") { + assert_eq!( + binary_version, cargo_version, + "Compiler version mismatch; binary version: '{}', Cargo version: '{}'.", + binary_version, cargo_version + ); + panic!( + "Please remove the conditional (but leave the assertion!), + so version alignment is always tested." + ); + } +} diff --git a/crates/starknet_sierra_compile/src/errors.rs b/crates/starknet_sierra_multicompile/src/errors.rs similarity index 92% rename from crates/starknet_sierra_compile/src/errors.rs rename to crates/starknet_sierra_multicompile/src/errors.rs index d38760a5f76..0de236d66e7 100644 --- a/crates/starknet_sierra_compile/src/errors.rs +++ b/crates/starknet_sierra_multicompile/src/errors.rs @@ -2,9 +2,10 @@ use cairo_lang_starknet_classes::allowed_libfuncs::AllowedLibfuncsError; use cairo_lang_starknet_classes::casm_contract_class::StarknetSierraCompilationError; #[cfg(feature = "cairo_native")] use cairo_native; +use serde::{Deserialize, Serialize}; use thiserror::Error; -#[derive(Debug, Error)] +#[derive(Clone, Debug, Error, PartialEq, Eq, Serialize, Deserialize)] pub enum CompilationUtilError { #[error("Starknet Sierra compilation error: {0}")] CompilationError(String), diff --git a/crates/starknet_sierra_multicompile/src/lib.rs b/crates/starknet_sierra_multicompile/src/lib.rs new file mode 100644 index 00000000000..99d162ca5a0 --- /dev/null +++ b/crates/starknet_sierra_multicompile/src/lib.rs @@ -0,0 +1,112 @@ +//! A lib for compiling Sierra into Casm. +use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass; +use cairo_lang_starknet_classes::contract_class::ContractClass as CairoLangContractClass; +#[cfg(feature = "cairo_native")] +use cairo_native::executor::AotContractExecutor; +use config::SierraCompilationConfig; +use starknet_api::contract_class::{ContractClass, SierraVersion}; +use starknet_api::core::CompiledClassHash; +use starknet_api::state::SierraContractClass; +use starknet_api::StarknetApiError; +use starknet_sequencer_infra::component_definitions::ComponentStarter; +use starknet_sierra_multicompile_types::{RawClass, RawExecutableClass, RawExecutableHashedClass}; +use thiserror::Error; +use tracing::instrument; + +use crate::command_line_compiler::CommandLineCompiler; +use crate::errors::CompilationUtilError; +use crate::utils::into_contract_class_for_compilation; + +pub mod command_line_compiler; +pub mod communication; +pub mod config; +pub mod constants; +pub mod errors; +pub mod paths; +pub mod resource_limits; +pub mod utils; + +#[cfg(test)] +pub mod test_utils; + +#[cfg(test)] +#[path = "compile_test.rs"] +pub mod compile_test; + +pub type SierraCompilerResult = Result; + +#[cfg(test)] +#[path = "constants_test.rs"] +pub mod constants_test; + +pub trait SierraToCasmCompiler: Send + Sync { + fn compile( + &self, + contract_class: CairoLangContractClass, + ) -> Result; +} + +#[cfg(feature = "cairo_native")] +pub trait SierraToNativeCompiler: Send + Sync { + fn compile_to_native( + &self, + contract_class: CairoLangContractClass, + ) -> Result; + + fn panic_on_compilation_failure(&self) -> bool; +} + +#[derive(Debug, Error)] +pub enum SierraCompilerError { + #[error(transparent)] + ClassSerde(#[from] serde_json::Error), + #[error(transparent)] + CompilationFailed(#[from] CompilationUtilError), + #[error("Failed to parse Sierra version: {0}")] + SierraVersionFormat(StarknetApiError), +} + +impl From for starknet_sierra_multicompile_types::SierraCompilerError { + fn from(error: SierraCompilerError) -> Self { + starknet_sierra_multicompile_types::SierraCompilerError::CompilationFailed( + error.to_string(), + ) + } +} + +// TODO(Elin): consider generalizing the compiler if invocation implementations are added. +#[derive(Clone)] +pub struct SierraCompiler { + compiler: CommandLineCompiler, +} + +impl SierraCompiler { + pub fn new(compiler: CommandLineCompiler) -> Self { + Self { compiler } + } + + // TODO(Elin): move (de)serialization to infra. layer. + #[instrument(skip(self, class), err)] + pub fn compile(&self, class: RawClass) -> SierraCompilerResult { + let class = SierraContractClass::try_from(class)?; + let sierra_version = SierraVersion::extract_from_program(&class.sierra_program) + .map_err(SierraCompilerError::SierraVersionFormat)?; + let class = into_contract_class_for_compilation(&class); + + // TODO(Elin): handle resources (whether here or an infra. layer load-balancing). + let executable_class = self.compiler.compile(class)?; + // TODO(Elin): consider spawning a worker for hash calculation. + let executable_class_hash = CompiledClassHash(executable_class.compiled_class_hash()); + let executable_class = ContractClass::V1((executable_class, sierra_version)); + let executable_class = RawExecutableClass::try_from(executable_class)?; + + Ok((executable_class, executable_class_hash)) + } +} + +pub fn create_sierra_compiler(config: SierraCompilationConfig) -> SierraCompiler { + let compiler = CommandLineCompiler::new(config); + SierraCompiler::new(compiler) +} + +impl ComponentStarter for SierraCompiler {} diff --git a/crates/starknet_sierra_multicompile/src/paths.rs b/crates/starknet_sierra_multicompile/src/paths.rs new file mode 100644 index 00000000000..1fdb585cd6c --- /dev/null +++ b/crates/starknet_sierra_multicompile/src/paths.rs @@ -0,0 +1,19 @@ +// Note: This module includes path resolution functions that are needed during build and run times. +// It must not contain functionality that is available in only in one of these modes. Specifically, +// it must avoid relying on env variables such as 'CARGO_*' or 'OUT_DIR'. + +fn target_dir(out_dir: std::path::PathBuf) -> std::path::PathBuf { + out_dir + .ancestors() + .nth(3) + .expect("Failed to navigate up three levels from OUT_DIR") + .to_path_buf() +} + +fn shared_folder_dir(out_dir: std::path::PathBuf) -> std::path::PathBuf { + target_dir(out_dir).join("shared_executables") +} + +pub fn binary_path(out_dir: std::path::PathBuf, binary_name: &str) -> std::path::PathBuf { + shared_folder_dir(out_dir).join(binary_name) +} diff --git a/crates/starknet_sierra_multicompile/src/resource_limits.rs b/crates/starknet_sierra_multicompile/src/resource_limits.rs new file mode 100644 index 00000000000..89c6b61782e --- /dev/null +++ b/crates/starknet_sierra_multicompile/src/resource_limits.rs @@ -0,0 +1,9 @@ +#[cfg(unix)] +mod resource_limits_unix; +#[cfg(unix)] +pub use resource_limits_unix::ResourceLimits; + +#[cfg(windows)] +mod resource_limits_windows; +#[cfg(windows)] +pub use resource_limits_windows::ResourceLimits; diff --git a/crates/starknet_sierra_multicompile/src/resource_limits/resource_limits_test.rs b/crates/starknet_sierra_multicompile/src/resource_limits/resource_limits_test.rs new file mode 100644 index 00000000000..67530b16b3a --- /dev/null +++ b/crates/starknet_sierra_multicompile/src/resource_limits/resource_limits_test.rs @@ -0,0 +1,81 @@ +use std::process::Command; +use std::time::Instant; + +use rstest::rstest; +use tempfile::NamedTempFile; + +use crate::resource_limits::ResourceLimits; + +#[rstest] +fn test_cpu_time_limit() { + let cpu_limit = 1; // 1 second + let cpu_time_rlimit = ResourceLimits::new(Some(cpu_limit), None, None); + + let start = Instant::now(); + let mut command = Command::new("bash"); + command.args(["-c", "while true; do :; done;"]); + cpu_time_rlimit.apply(&mut command); + command.spawn().expect("Failed to start CPU consuming process").wait().unwrap(); + assert!(start.elapsed().as_secs() <= cpu_limit); +} + +#[rstest] +fn test_memory_size_limit() { + let memory_limit = 9 * 512 * 1024; // 4.5 MB + let memory_size_rlimit = ResourceLimits::new(None, None, Some(memory_limit)); + + let mut command = Command::new("bash"); + command.args(["-c", "a=(); while true; do a+=0; done;"]); + command.stderr(std::process::Stdio::piped()); + memory_size_rlimit.apply(&mut command); + let output = command.output().expect("Failed to start memory consuming process"); + let stderr = String::from_utf8_lossy(&output.stderr); + for line in stderr.lines() { + if line.starts_with("bash: xmalloc: cannot allocate") { + println!( + "Child process exited with status code: {}, and the following memory allocation \ + error:\n {}.", + output.status.code().unwrap(), + line + ); + return; + } + } + + panic!("Child process did not exit with a memory allocation error."); +} + +#[rstest] +fn test_file_size_limit() { + let file_limit = 10; // 10 bytes + let file_size_rlimit = ResourceLimits::new(None, Some(file_limit), None); + let temp_file = NamedTempFile::new().expect("Failed to create temporary file"); + let temp_file_path = temp_file.path().to_str().unwrap(); + + let mut command = Command::new("bash"); + command.args(["-c", format!("while true; do echo 0 >> {temp_file_path}; done;").as_str()]); + file_size_rlimit.apply(&mut command); + command.spawn().expect("Failed to start disk consuming process").wait().unwrap(); + assert_eq!(std::fs::metadata(temp_file_path).unwrap().len(), file_limit); +} + +#[rstest] +fn test_successful_resource_limited_command() { + let print_message = "Hello World!"; + + let cpu_limit = Some(1); // 1 second + let file_limit = Some(u64::try_from(print_message.len()).unwrap() + 1); + let memory_limit = Some(5 * 1024 * 1024); // 5 MB + let resource_limits = ResourceLimits::new(cpu_limit, file_limit, memory_limit); + + let temp_file = NamedTempFile::new().expect("Failed to create temporary file"); + let temp_file_path = temp_file.path().to_str().unwrap(); + + let mut command = Command::new("bash"); + command.args(["-c", format!("echo '{print_message}' > {temp_file_path}").as_str()]); + resource_limits.apply(&mut command); + let exit_status = command.spawn().expect("Failed to start process").wait().unwrap(); + + assert!(exit_status.success()); + assert_eq!(std::fs::read_to_string(temp_file_path).unwrap(), format!("{print_message}\n")); +} diff --git a/crates/starknet_sierra_multicompile/src/resource_limits/resource_limits_unix.rs b/crates/starknet_sierra_multicompile/src/resource_limits/resource_limits_unix.rs new file mode 100644 index 00000000000..5499dc0e17a --- /dev/null +++ b/crates/starknet_sierra_multicompile/src/resource_limits/resource_limits_unix.rs @@ -0,0 +1,114 @@ +use std::io; +use std::os::unix::process::CommandExt; +use std::process::Command; + +use rlimit::{setrlimit, Resource}; + +#[cfg(test)] +#[path = "resource_limits_test.rs"] +pub mod test; + +/// A struct to hold the information needed to set a limit on an individual OS resource. +struct RLimit { + /// A kind of resource. All resource constants are available on all unix platforms. + /// See for more information. + resource: Resource, + /// The soft limit for the resource. The limit may be increased by the process being limited. + soft_limit: u64, + /// The hard limit for the resource. May not be increased or exceeded by the affected process. + hard_limit: u64, + /// The units by which the resource is measured. + units: String, +} + +impl RLimit { + /// Set the resource limit for the current process. + fn set(&self) -> io::Result<()> { + // Use `println!` and not a logger because this method is called in an unsafe block, and we + // don't want to risk unexpected behavior. + println!( + "Setting {:?} limits: {} {} soft limit; {} {} hard limit.", + self.resource, self.soft_limit, self.units, self.hard_limit, self.units + ); + setrlimit(self.resource, self.soft_limit, self.hard_limit) + } +} + +/// A struct to hold resource limits for a process. +/// Each limit is optional and can be set to `None` if not needed. +/// NOTE: This struct is fully implemented only for Unix-like systems. +pub struct ResourceLimits { + /// A limit (in seconds) on the amount of CPU time that the process can consume. + cpu_time: Option, + /// The maximum size (in bytes) of files that the process may create. + file_size: Option, + /// The maximum size (in bytes) of the process’s virtual memory (address space). + memory_size: Option, +} + +impl ResourceLimits { + pub fn new( + cpu_time: Option, + file_size: Option, + memory_size: Option, + ) -> ResourceLimits { + ResourceLimits { + cpu_time: cpu_time.map(|t| RLimit { + resource: Resource::CPU, + soft_limit: t, + hard_limit: t, + units: "seconds".to_string(), + }), + file_size: file_size.map(|x| RLimit { + resource: Resource::FSIZE, + soft_limit: x, + hard_limit: x, + units: "bytes".to_string(), + }), + memory_size: memory_size.map(|y| RLimit { + resource: Resource::AS, + soft_limit: y, + hard_limit: y, + units: "bytes".to_string(), + }), + } + } + + /// Set all defined resource limits for the current process. Limits set to `None` are ignored. + pub fn set(&self) -> io::Result<()> { + [self.cpu_time.as_ref(), self.file_size.as_ref(), self.memory_size.as_ref()] + .iter() + .flatten() + .try_for_each(|resource_limit| resource_limit.set()) + } + + /// Apply the resource limits to a given command object. This moves the [`ResourceLimits`] + /// struct into a closure that is held by the given command. The closure is executed in the + /// child process spawned by the command, right before it invokes the `exec` system call. + pub fn apply(self, command: &mut Command) -> &mut Command { + if self.cpu_time.is_none() && self.file_size.is_none() && self.memory_size.is_none() { + return command; + } + unsafe { + // The `pre_exec` method runs a given closure after the parent process has been forked + // but before the child process calls `exec`. + // + // This closure runs in the child process after a `fork`, which primarily means that any + // modifications made to memory on behalf of this closure will **not** be visible to the + // parent process. This environment is often very constrained. Normal operations--such + // as using `malloc`, accessing environment variables through [`std::env`] or acquiring + // a mutex--are not guaranteed to work, because after `fork`, only one thread exists in + // the child process, while there may be multiple threads in the parent process. + // + // This closure is considered safe for the following reasons: + // 1. The [`ResourceLimits`] struct is fully constructed and moved into the closure. + // 2. No heap allocations occur in the `set` method. + // 3. `setrlimit` is an async-signal-safe system call, which means it is safe to invoke + // after `fork`. This is established in the POSIX `fork` specification: + // > ... the child process may only execute async-signal-safe operations until such + // time as one of the `exec` functions is called. + // (See ) + command.pre_exec(move || self.set()) + } + } +} diff --git a/crates/starknet_sierra_multicompile/src/resource_limits/resource_limits_windows.rs b/crates/starknet_sierra_multicompile/src/resource_limits/resource_limits_windows.rs new file mode 100644 index 00000000000..c0b09de8b77 --- /dev/null +++ b/crates/starknet_sierra_multicompile/src/resource_limits/resource_limits_windows.rs @@ -0,0 +1,28 @@ +use std::io; +use std::process::Command; + +/// A struct to hold resource limits for a process. +/// Each limit is optional and can be set to `None` if not needed. +/// NOTE: This is a trivial implementation for compiling on windows. +pub struct ResourceLimits; + +impl ResourceLimits { + pub fn new( + _cpu_time: Option, + _file_size: Option, + _memory_size: Option, + ) -> ResourceLimits { + ResourceLimits {} + } + + pub fn set(&self) -> io::Result<()> { + Ok(()) + } + + /// Apply the resource limits to a given command object. This moves the [`ResourceLimits`] + /// struct into a closure that is held by the given command. The closure is executed in the + /// child process spawned by the command, right before it invokes the `exec` system call. + pub fn apply(self, command: &mut Command) -> &mut Command { + command + } +} diff --git a/crates/starknet_sierra_compile/src/test_utils.rs b/crates/starknet_sierra_multicompile/src/test_utils.rs similarity index 100% rename from crates/starknet_sierra_compile/src/test_utils.rs rename to crates/starknet_sierra_multicompile/src/test_utils.rs diff --git a/crates/starknet_sierra_compile/src/utils.rs b/crates/starknet_sierra_multicompile/src/utils.rs similarity index 89% rename from crates/starknet_sierra_compile/src/utils.rs rename to crates/starknet_sierra_multicompile/src/utils.rs index e96d0ada5ff..bc73f000bd5 100644 --- a/crates/starknet_sierra_compile/src/utils.rs +++ b/crates/starknet_sierra_multicompile/src/utils.rs @@ -6,17 +6,17 @@ use cairo_lang_starknet_classes::contract_class::{ ContractEntryPoints as CairoLangContractEntryPoints, }; use cairo_lang_utils::bigint::BigUintAsHex; -use starknet_api::rpc_transaction::{ - ContractClass as RpcContractClass, - EntryPointByType as StarknetApiEntryPointByType, +use starknet_api::rpc_transaction::EntryPointByType as StarknetApiEntryPointByType; +use starknet_api::state::{ + EntryPoint as StarknetApiEntryPoint, + SierraContractClass as StarknetApiContractClass, }; -use starknet_api::state::EntryPoint as StarknetApiEntryPoint; use starknet_types_core::felt::Felt; /// Retruns a [`CairoLangContractClass`] struct ready for Sierra to Casm compilation. Note the `abi` /// field is None as it is not relevant for the compilation. pub fn into_contract_class_for_compilation( - rpc_contract_class: &RpcContractClass, + rpc_contract_class: &StarknetApiContractClass, ) -> CairoLangContractClass { let sierra_program = sierra_program_as_felts_to_big_uint_as_hex(&rpc_contract_class.sierra_program); diff --git a/crates/starknet_sierra_multicompile_types/Cargo.toml b/crates/starknet_sierra_multicompile_types/Cargo.toml new file mode 100644 index 00000000000..da1c0003302 --- /dev/null +++ b/crates/starknet_sierra_multicompile_types/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "starknet_sierra_multicompile_types" +edition.workspace = true +license.workspace = true +repository.workspace = true +version.workspace = true + +[lints] +workspace = true + +[features] +testing = ["mockall"] + +[dependencies] +async-trait.workspace = true +mockall = { workspace = true, optional = true } +papyrus_proc_macros.workspace = true +serde = { workspace = true, features = ["derive"] } +serde_json.workspace = true +starknet_api.workspace = true +starknet_sequencer_infra.workspace = true +thiserror.workspace = true + +[dev-dependencies] +mockall.workspace = true diff --git a/crates/starknet_sierra_multicompile_types/src/lib.rs b/crates/starknet_sierra_multicompile_types/src/lib.rs new file mode 100644 index 00000000000..4b34ca0736c --- /dev/null +++ b/crates/starknet_sierra_multicompile_types/src/lib.rs @@ -0,0 +1,196 @@ +use std::fs::{File, OpenOptions}; +use std::io::{BufReader, BufWriter}; +use std::path::PathBuf; +use std::sync::Arc; + +use async_trait::async_trait; +#[cfg(any(feature = "testing", test))] +use mockall::automock; +use papyrus_proc_macros::handle_all_response_variants; +use serde::{Deserialize, Serialize}; +use starknet_api::contract_class::ContractClass; +use starknet_api::core::CompiledClassHash; +use starknet_api::state::SierraContractClass; +use starknet_sequencer_infra::component_client::{ + ClientError, + LocalComponentClient, + RemoteComponentClient, +}; +use starknet_sequencer_infra::component_definitions::{ + ComponentClient, + ComponentRequestAndResponseSender, +}; +use thiserror::Error; + +pub type SierraCompilerResult = Result; +pub type SierraCompilerClientResult = Result; + +pub type RawExecutableHashedClass = (RawExecutableClass, CompiledClassHash); + +pub type LocalSierraCompilerClient = + LocalComponentClient; +pub type RemoteSierraCompilerClient = + RemoteComponentClient; +pub type SharedSierraCompilerClient = Arc; +pub type SierraCompilerRequestAndResponseSender = + ComponentRequestAndResponseSender; + +// TODO(Elin): change to a more efficient serde (bytes, or something similar). +// A prerequisite for this is to solve serde-untagged lack of support. + +type RawClassResult = Result; +pub type RawClass = SerializedClass; +pub type RawExecutableClass = SerializedClass; + +#[derive(Debug, Error)] +pub enum RawClassError { + #[error(transparent)] + IoError(#[from] std::io::Error), + #[error(transparent)] + WriteError(#[from] serde_json::Error), +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct SerializedClass(serde_json::Value, std::marker::PhantomData); + +impl SerializedClass { + pub fn into_value(self) -> serde_json::Value { + self.0 + } + + pub fn size(&self) -> RawClassResult { + Ok(serde_json::to_string_pretty(&self.0)?.len()) + } + + fn new(value: serde_json::Value) -> Self { + Self(value, std::marker::PhantomData) + } + + pub fn from_file(path: PathBuf) -> RawClassResult> { + let file = match File::open(path) { + Ok(file) => file, + Err(e) if e.kind() == std::io::ErrorKind::NotFound => return Ok(None), + Err(e) => return Err(e.into()), + }; + + match serde_json::from_reader(BufReader::new(file)) { + Ok(value) => Ok(Some(Self::new(value))), + // In case the file was deleted/tempered with until actual read is done. + Err(e) if e.is_io() && e.to_string().contains("No such file or directory") => Ok(None), + Err(e) => Err(e.into()), + } + } + + pub fn write_to_file(self, path: PathBuf) -> RawClassResult<()> { + if let Some(parent) = path.parent() { + std::fs::create_dir_all(parent)?; + } + + // Open a file for writing, deleting any existing content. + let file = OpenOptions::new() + .create(true) + .write(true) + .truncate(true) + .open(path) + .expect("Failing to open file with given options is impossible"); + + let writer = BufWriter::new(file); + serde_json::to_writer_pretty(writer, &self.into_value())?; + + Ok(()) + } + + #[cfg(any(feature = "testing", test))] + pub fn new_unchecked(value: serde_json::Value) -> Self { + Self::new(value) + } +} + +impl TryFrom for RawClass { + type Error = serde_json::Error; + + fn try_from(class: SierraContractClass) -> Result { + Ok(Self::new(serde_json::to_value(class)?)) + } +} + +impl TryFrom for SierraContractClass { + type Error = serde_json::Error; + + fn try_from(class: RawClass) -> Result { + serde_json::from_value(class.0) + } +} + +impl TryFrom for RawExecutableClass { + type Error = serde_json::Error; + + fn try_from(class: ContractClass) -> Result { + Ok(Self::new(serde_json::to_value(class)?)) + } +} + +impl TryFrom for ContractClass { + type Error = serde_json::Error; + + fn try_from(class: RawExecutableClass) -> Result { + serde_json::from_value(class.0) + } +} + +/// Serves as the Sierra compilation unit's shared interface. +/// Requires `Send + Sync` to allow transferring and sharing resources (inputs, futures) across +/// threads. +#[cfg_attr(any(feature = "testing", test), automock)] +#[async_trait] +pub trait SierraCompilerClient: Send + Sync { + async fn compile( + &self, + class: RawClass, + ) -> SierraCompilerClientResult; +} + +#[derive(Clone, Debug, Error, Eq, PartialEq, Serialize, Deserialize)] +pub enum SierraCompilerError { + #[error("Compilation failed: {0}")] + CompilationFailed(String), +} + +#[derive(Clone, Debug, Error)] +pub enum SierraCompilerClientError { + #[error(transparent)] + ClientError(#[from] ClientError), + #[error(transparent)] + SierraCompilerError(#[from] SierraCompilerError), +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum SierraCompilerRequest { + Compile(RawClass), +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum SierraCompilerResponse { + Compile(SierraCompilerResult), +} + +#[async_trait] +impl SierraCompilerClient for ComponentClientType +where + ComponentClientType: + Send + Sync + ComponentClient, +{ + async fn compile( + &self, + class: RawClass, + ) -> SierraCompilerClientResult { + let request = SierraCompilerRequest::Compile(class); + handle_all_response_variants!( + SierraCompilerResponse, + Compile, + SierraCompilerClientError, + SierraCompilerError, + Direct + ) + } +} diff --git a/crates/starknet_state_sync/Cargo.toml b/crates/starknet_state_sync/Cargo.toml index d746a8446a7..084dbe9a439 100644 --- a/crates/starknet_state_sync/Cargo.toml +++ b/crates/starknet_state_sync/Cargo.toml @@ -5,24 +5,36 @@ edition.workspace = true license.workspace = true repository.workspace = true +[features] +testing = [] + [lints] workspace = true [dependencies] +apollo_reverts.workspace = true async-trait.workspace = true futures.workspace = true -papyrus_base_layer.workspace = true papyrus_common.workspace = true papyrus_config.workspace = true +papyrus_network.workspace = true +papyrus_p2p_sync.workspace = true papyrus_storage.workspace = true papyrus_sync.workspace = true serde.workspace = true -starknet_api = { workspace = true, features = ["testing"] } +starknet-types-core.workspace = true +starknet_api.workspace = true +starknet_class_manager_types.workspace = true starknet_client.workspace = true starknet_sequencer_infra.workspace = true +starknet_sequencer_metrics.workspace = true starknet_state_sync_types.workspace = true tokio.workspace = true validator.workspace = true [dev-dependencies] +indexmap = { workspace = true, features = ["serde"] } +libp2p.workspace = true papyrus_storage = { workspace = true, features = ["testing"] } +papyrus_test_utils.workspace = true +rand_chacha.workspace = true diff --git a/crates/starknet_state_sync/src/config.rs b/crates/starknet_state_sync/src/config.rs index 87753c7f860..8c454a31e91 100644 --- a/crates/starknet_state_sync/src/config.rs +++ b/crates/starknet_state_sync/src/config.rs @@ -1,32 +1,96 @@ use std::collections::BTreeMap; +use std::path::PathBuf; +use std::result; -use papyrus_base_layer::ethereum_base_layer_contract::EthereumBaseLayerConfig; -use papyrus_config::dumping::{append_sub_config_name, SerializeConfig}; +use apollo_reverts::RevertConfig; +use papyrus_config::dumping::{append_sub_config_name, ser_optional_sub_config, SerializeConfig}; use papyrus_config::{ParamPath, SerializedParam}; +use papyrus_network::NetworkConfig; +use papyrus_p2p_sync::client::P2pSyncClientConfig; +use papyrus_storage::db::DbConfig; use papyrus_storage::StorageConfig; use papyrus_sync::sources::central::CentralSourceConfig; use papyrus_sync::SyncConfig; use serde::{Deserialize, Serialize}; -use validator::Validate; +use validator::{Validate, ValidationError}; -#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Validate)] +const STATE_SYNC_TCP_PORT: u16 = 12345; + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Validate)] +#[validate(schema(function = "validate_config"))] pub struct StateSyncConfig { #[validate] pub storage_config: StorageConfig, - // TODO(shahak): add validate to SyncConfig, CentralSourceConfig and EthereumBaseLayerConfig - // and use them here. - pub sync_config: SyncConfig, - pub central_config: CentralSourceConfig, - pub base_layer_config: EthereumBaseLayerConfig, + // TODO(Eitan): Add support for enum configs and use here + #[validate] + pub p2p_sync_client_config: Option, + #[validate] + pub central_sync_client_config: Option, + #[validate] + pub network_config: NetworkConfig, + #[validate] + pub revert_config: RevertConfig, } impl SerializeConfig for StateSyncConfig { + fn dump(&self) -> BTreeMap { + let mut config = BTreeMap::new(); + + config.extend(append_sub_config_name(self.storage_config.dump(), "storage_config")); + config.extend(append_sub_config_name(self.network_config.dump(), "network_config")); + config.extend(append_sub_config_name(self.revert_config.dump(), "revert_config")); + config.extend(ser_optional_sub_config( + &self.p2p_sync_client_config, + "p2p_sync_client_config", + )); + config.extend(ser_optional_sub_config( + &self.central_sync_client_config, + "central_sync_client_config", + )); + config + } +} + +fn validate_config(config: &StateSyncConfig) -> result::Result<(), ValidationError> { + if config.central_sync_client_config.is_some() && config.p2p_sync_client_config.is_some() + || config.central_sync_client_config.is_none() && config.p2p_sync_client_config.is_none() + { + return Err(ValidationError::new( + "Exactly one of --sync.#is_none or --p2p_sync.#is_none must be turned on", + )); + } + Ok(()) +} + +impl Default for StateSyncConfig { + fn default() -> Self { + Self { + storage_config: StorageConfig { + db_config: DbConfig { + path_prefix: PathBuf::from("/data/state_sync"), + ..Default::default() + }, + ..Default::default() + }, + p2p_sync_client_config: Some(P2pSyncClientConfig::default()), + central_sync_client_config: None, + network_config: NetworkConfig { port: STATE_SYNC_TCP_PORT, ..Default::default() }, + revert_config: RevertConfig::default(), + } + } +} + +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Validate)] +pub struct CentralSyncClientConfig { + pub sync_config: SyncConfig, + pub central_source_config: CentralSourceConfig, +} + +impl SerializeConfig for CentralSyncClientConfig { fn dump(&self) -> BTreeMap { vec![ - append_sub_config_name(self.storage_config.dump(), "storage_config"), append_sub_config_name(self.sync_config.dump(), "sync_config"), - append_sub_config_name(self.central_config.dump(), "central_config"), - append_sub_config_name(self.base_layer_config.dump(), "base_layer_config"), + append_sub_config_name(self.central_source_config.dump(), "central_source_config"), ] .into_iter() .flatten() diff --git a/crates/starknet_state_sync/src/lib.rs b/crates/starknet_state_sync/src/lib.rs index 598404ad971..602a02f74f0 100644 --- a/crates/starknet_state_sync/src/lib.rs +++ b/crates/starknet_state_sync/src/lib.rs @@ -1,26 +1,48 @@ pub mod config; +pub mod metrics; pub mod runner; +#[cfg(test)] +mod test; + +use std::cmp::min; use async_trait::async_trait; -use futures::channel::{mpsc, oneshot}; +use futures::channel::mpsc::{channel, Sender}; use futures::SinkExt; -use starknet_sequencer_infra::component_definitions::ComponentRequestHandler; +use papyrus_storage::body::BodyStorageReader; +use papyrus_storage::db::TransactionKind; +use papyrus_storage::header::HeaderStorageReader; +use papyrus_storage::state::{StateReader, StateStorageReader}; +use papyrus_storage::{StorageReader, StorageTxn}; +use starknet_api::block::BlockNumber; +use starknet_api::core::{ClassHash, ContractAddress, Nonce, BLOCK_HASH_TABLE_ADDRESS}; +use starknet_api::state::{StateNumber, StorageKey}; +use starknet_class_manager_types::SharedClassManagerClient; +use starknet_sequencer_infra::component_definitions::{ComponentRequestHandler, ComponentStarter}; +use starknet_sequencer_infra::component_server::{LocalComponentServer, RemoteComponentServer}; use starknet_state_sync_types::communication::{StateSyncRequest, StateSyncResponse}; use starknet_state_sync_types::errors::StateSyncError; +use starknet_state_sync_types::state_sync_types::{StateSyncResult, SyncBlock}; +use starknet_types_core::felt::Felt; use crate::config::StateSyncConfig; use crate::runner::StateSyncRunner; -// TODO(shahak): consider adding to config const BUFFER_SIZE: usize = 100000; -pub fn create_state_sync_and_runner(config: StateSyncConfig) -> (StateSync, StateSyncRunner) { - let (request_sender, request_receiver) = mpsc::channel(BUFFER_SIZE); - (StateSync { request_sender }, StateSyncRunner::new(config, request_receiver)) +pub fn create_state_sync_and_runner( + config: StateSyncConfig, + class_manager_client: SharedClassManagerClient, +) -> (StateSync, StateSyncRunner) { + let (new_block_sender, new_block_receiver) = channel(BUFFER_SIZE); + let (state_sync_runner, storage_reader) = + StateSyncRunner::new(config, new_block_receiver, class_manager_client); + (StateSync { storage_reader, new_block_sender }, state_sync_runner) } pub struct StateSync { - pub request_sender: mpsc::Sender<(StateSyncRequest, oneshot::Sender)>, + storage_reader: StorageReader, + new_block_sender: Sender, } // TODO(shahak): Have StateSyncRunner call StateSync instead of the opposite once we stop supporting @@ -28,12 +50,186 @@ pub struct StateSync { #[async_trait] impl ComponentRequestHandler for StateSync { async fn handle_request(&mut self, request: StateSyncRequest) -> StateSyncResponse { - let (response_sender, response_receiver) = oneshot::channel(); - if self.request_sender.send((request, response_sender)).await.is_err() { - return StateSyncResponse::GetBlock(Err(StateSyncError::RunnerCommunicationError)); + match request { + StateSyncRequest::GetBlock(block_number) => { + StateSyncResponse::GetBlock(self.get_block(block_number).map(Box::new)) + } + StateSyncRequest::AddNewBlock(sync_block) => StateSyncResponse::AddNewBlock( + self.new_block_sender.send(*sync_block).await.map_err(StateSyncError::from), + ), + StateSyncRequest::GetStorageAt(block_number, contract_address, storage_key) => { + StateSyncResponse::GetStorageAt(self.get_storage_at( + block_number, + contract_address, + storage_key, + )) + } + StateSyncRequest::GetNonceAt(block_number, contract_address) => { + StateSyncResponse::GetNonceAt(self.get_nonce_at(block_number, contract_address)) + } + StateSyncRequest::GetClassHashAt(block_number, contract_address) => { + StateSyncResponse::GetClassHashAt( + self.get_class_hash_at(block_number, contract_address), + ) + } + StateSyncRequest::GetLatestBlockNumber() => { + StateSyncResponse::GetLatestBlockNumber(self.get_latest_block_number()) + } + // TODO(shahak): Add tests for is_class_declared_at. + StateSyncRequest::IsClassDeclaredAt(block_number, class_hash) => { + StateSyncResponse::IsClassDeclaredAt( + self.is_class_declared_at(block_number, class_hash), + ) + } } - response_receiver.await.unwrap_or_else(|_| { - StateSyncResponse::GetBlock(Err(StateSyncError::RunnerCommunicationError)) - }) } } + +impl StateSync { + fn get_block(&self, block_number: BlockNumber) -> StateSyncResult> { + let txn = self.storage_reader.begin_ro_txn()?; + let block_header = txn.get_block_header(block_number)?; + let Some(block_transaction_hashes) = txn.get_block_transaction_hashes(block_number)? else { + return Ok(None); + }; + let Some(thin_state_diff) = txn.get_state_diff(block_number)? else { + return Ok(None); + }; + let Some(block_header) = block_header else { + return Ok(None); + }; + Ok(Some(SyncBlock { + state_diff: thin_state_diff, + block_header_without_hash: block_header.block_header_without_hash, + transaction_hashes: block_transaction_hashes, + })) + } + + fn get_storage_at( + &self, + block_number: BlockNumber, + contract_address: ContractAddress, + storage_key: StorageKey, + ) -> StateSyncResult { + let txn = self.storage_reader.begin_ro_txn()?; + verify_synced_up_to(&txn, block_number)?; + + let state_number = StateNumber::unchecked_right_after_block(block_number); + let state_reader = txn.get_state_reader()?; + + verify_contract_deployed(&state_reader, state_number, contract_address)?; + + let res = state_reader.get_storage_at(state_number, &contract_address, &storage_key)?; + + Ok(res) + } + + fn get_nonce_at( + &self, + block_number: BlockNumber, + contract_address: ContractAddress, + ) -> StateSyncResult { + let txn = self.storage_reader.begin_ro_txn()?; + verify_synced_up_to(&txn, block_number)?; + + let state_number = StateNumber::unchecked_right_after_block(block_number); + let state_reader = txn.get_state_reader()?; + + verify_contract_deployed(&state_reader, state_number, contract_address)?; + + let res = state_reader + .get_nonce_at(state_number, &contract_address)? + .ok_or(StateSyncError::ContractNotFound(contract_address))?; + + Ok(res) + } + + fn get_class_hash_at( + &self, + block_number: BlockNumber, + contract_address: ContractAddress, + ) -> StateSyncResult { + let txn = self.storage_reader.begin_ro_txn()?; + verify_synced_up_to(&txn, block_number)?; + + let state_number = StateNumber::unchecked_right_after_block(block_number); + let state_reader = txn.get_state_reader()?; + let class_hash = state_reader + .get_class_hash_at(state_number, &contract_address)? + .ok_or(StateSyncError::ContractNotFound(contract_address))?; + Ok(class_hash) + } + + fn get_latest_block_number(&self) -> StateSyncResult> { + let txn = self.storage_reader.begin_ro_txn()?; + let latest_block_number = latest_synced_block(&txn)?; + Ok(latest_block_number) + } + + fn is_class_declared_at( + &self, + block_number: BlockNumber, + class_hash: ClassHash, + ) -> StateSyncResult { + let class_definition_block_number_opt = self + .storage_reader + .begin_ro_txn()? + .get_state_reader()? + .get_class_definition_block_number(&class_hash)?; + Ok(class_definition_block_number_opt.is_some_and(|class_definition_block_number| { + class_definition_block_number <= block_number + })) + } +} + +fn verify_synced_up_to( + txn: &StorageTxn<'_, Mode>, + block_number: BlockNumber, +) -> Result<(), StateSyncError> { + if let Some(latest_block_number) = latest_synced_block(txn)? { + if latest_block_number >= block_number { + return Ok(()); + } + } + + Err(StateSyncError::BlockNotFound(block_number)) +} + +fn latest_synced_block( + txn: &StorageTxn<'_, Mode>, +) -> StateSyncResult> { + let latest_state_block_number = txn.get_state_marker()?.prev(); + if latest_state_block_number.is_none() { + return Ok(None); + } + + let latest_transaction_block_number = txn.get_body_marker()?.prev(); + if latest_transaction_block_number.is_none() { + return Ok(None); + } + + Ok(min(latest_state_block_number, latest_transaction_block_number)) +} + +fn verify_contract_deployed( + state_reader: &StateReader<'_, Mode>, + state_number: StateNumber, + contract_address: ContractAddress, +) -> Result<(), StateSyncError> { + // Contract address 0x1 is a special address, it stores the block + // hashes. Contracts are not deployed to this address. + if contract_address != BLOCK_HASH_TABLE_ADDRESS { + // check if the contract is deployed + state_reader + .get_class_hash_at(state_number, &contract_address)? + .ok_or(StateSyncError::ContractNotFound(contract_address))?; + }; + + Ok(()) +} + +pub type LocalStateSyncServer = + LocalComponentServer; +pub type RemoteStateSyncServer = RemoteComponentServer; + +impl ComponentStarter for StateSync {} diff --git a/crates/starknet_state_sync/src/metrics.rs b/crates/starknet_state_sync/src/metrics.rs new file mode 100644 index 00000000000..ce2c7afdae4 --- /dev/null +++ b/crates/starknet_state_sync/src/metrics.rs @@ -0,0 +1,12 @@ +use starknet_sequencer_metrics::define_metrics; +use starknet_sequencer_metrics::metrics::MetricGauge; + +define_metrics!( + StateSync => { + // Gauges + MetricGauge { STATE_SYNC_P2P_NUM_CONNECTED_PEERS, "apollo_sync_num_connected_peers", "The number of connected peers to the state sync p2p component" }, + MetricGauge { STATE_SYNC_P2P_NUM_ACTIVE_INBOUND_SESSIONS, "apollo_sync_num_active_inbound_sessions", "The number of inbound sessions to the state sync p2p component" }, + MetricGauge { STATE_SYNC_P2P_NUM_ACTIVE_OUTBOUND_SESSIONS, "apollo_sync_num_active_outbound_sessions", "The number of outbound sessions to the state sync p2p component" }, + MetricGauge { STATE_SYNC_P2P_NUM_BLACKLISTED_PEERS, "apollo_sync_num_blacklisted_peers", "The number of currently blacklisted peers by the state sync p2p component" }, + }, +); diff --git a/crates/starknet_state_sync/src/runner/mod.rs b/crates/starknet_state_sync/src/runner/mod.rs index 20546fbfe86..7f04f2b437e 100644 --- a/crates/starknet_state_sync/src/runner/mod.rs +++ b/crates/starknet_state_sync/src/runner/mod.rs @@ -3,62 +3,93 @@ mod test; use std::sync::Arc; +use apollo_reverts::{revert_block, revert_blocks_and_eternal_pending}; use async_trait::async_trait; -use futures::channel::{mpsc, oneshot}; -use futures::future::BoxFuture; +use futures::channel::mpsc::Receiver; +use futures::future::{self, pending, BoxFuture}; +use futures::never::Never; use futures::{FutureExt, StreamExt}; use papyrus_common::pending_classes::PendingClasses; +use papyrus_network::network_manager::metrics::{NetworkMetrics, SqmrNetworkMetrics}; +use papyrus_network::network_manager::{self, NetworkError, NetworkManager}; +use papyrus_p2p_sync::client::{ + P2pSyncClient, + P2pSyncClientChannels, + P2pSyncClientConfig, + P2pSyncClientError, +}; +use papyrus_p2p_sync::server::{P2pSyncServer, P2pSyncServerChannels}; +use papyrus_p2p_sync::{Protocol, BUFFER_SIZE}; use papyrus_storage::body::BodyStorageReader; +use papyrus_storage::class_manager::ClassManagerStorageReader; +use papyrus_storage::compiled_class::CasmStorageReader; +use papyrus_storage::db::TransactionKind; +use papyrus_storage::header::HeaderStorageReader; use papyrus_storage::state::StateStorageReader; -use papyrus_storage::{open_storage, StorageReader}; -use papyrus_sync::sources::base_layer::EthereumBaseLayerSource; -use papyrus_sync::sources::central::CentralSource; +use papyrus_storage::{open_storage, StorageReader, StorageTxn, StorageWriter}; +use papyrus_sync::metrics::{ + SYNC_BODY_MARKER, + SYNC_CLASS_MANAGER_MARKER, + SYNC_COMPILED_CLASS_MARKER, + SYNC_HEADER_MARKER, + SYNC_PROCESSED_TRANSACTIONS, + SYNC_REVERTED_TRANSACTIONS, + SYNC_STATE_MARKER, +}; +use papyrus_sync::sources::central::{CentralError, CentralSource}; use papyrus_sync::sources::pending::PendingSource; use papyrus_sync::{ - StateSync as PapyrusStateSync, - StateSyncError as PapyrusStateSyncError, + StateSync as CentralStateSync, + StateSyncError as CentralStateSyncError, GENESIS_HASH, }; use starknet_api::block::{BlockHash, BlockNumber}; use starknet_api::felt; +use starknet_class_manager_types::SharedClassManagerClient; use starknet_client::reader::objects::pending_data::{PendingBlock, PendingBlockOrDeprecated}; use starknet_client::reader::PendingData; use starknet_sequencer_infra::component_definitions::ComponentStarter; -use starknet_sequencer_infra::errors::ComponentError; -use starknet_state_sync_types::communication::{ - StateSyncRequest, - StateSyncResponse, - StateSyncResult, -}; +use starknet_sequencer_infra::component_server::WrapperServer; use starknet_state_sync_types::state_sync_types::SyncBlock; use tokio::sync::RwLock; -use crate::config::StateSyncConfig; +use crate::config::{CentralSyncClientConfig, StateSyncConfig}; +use crate::metrics::{ + STATE_SYNC_P2P_NUM_ACTIVE_INBOUND_SESSIONS, + STATE_SYNC_P2P_NUM_ACTIVE_OUTBOUND_SESSIONS, + STATE_SYNC_P2P_NUM_BLACKLISTED_PEERS, + STATE_SYNC_P2P_NUM_CONNECTED_PEERS, +}; pub struct StateSyncRunner { - #[allow(dead_code)] - request_receiver: mpsc::Receiver<(StateSyncRequest, oneshot::Sender)>, - #[allow(dead_code)] - storage_reader: StorageReader, - sync_future: BoxFuture<'static, Result<(), PapyrusStateSyncError>>, + network_future: BoxFuture<'static, Result<(), NetworkError>>, + // TODO(Matan): change client and server to requester and responder respectively + p2p_sync_client_future: BoxFuture<'static, Result>, + p2p_sync_server_future: BoxFuture<'static, Never>, + central_sync_client_future: BoxFuture<'static, Result<(), CentralStateSyncError>>, + new_block_dev_null_future: BoxFuture<'static, Never>, } #[async_trait] impl ComponentStarter for StateSyncRunner { - async fn start(&mut self) -> Result<(), ComponentError> { - loop { - tokio::select! { - result = &mut self.sync_future => return result.map_err(|_| ComponentError::InternalComponentError), - Some((request, sender)) = self.request_receiver.next() => { - let response = match request { - StateSyncRequest::GetBlock(block_number) => { - StateSyncResponse::GetBlock(self.get_block(block_number)) - } - }; - - sender.send(response).map_err(|_| ComponentError::InternalComponentError)? - } + async fn start(&mut self) { + tokio::select! { + _ = &mut self.network_future => { + panic!("StateSyncRunner failed - network stopped unexpectedly"); + } + _ = &mut self.p2p_sync_client_future => { + panic!("StateSyncRunner failed - p2p sync client stopped unexpectedly"); } + _never = &mut self.p2p_sync_server_future => { + unreachable!("Return type Never should never be constructed") + } + _ = &mut self.central_sync_client_future => { + panic!("StateSyncRunner failed - central sync client stopped unexpectedly"); + } + _never = &mut self.new_block_dev_null_future => { + unreachable!("Return type Never should never be constructed") + } + } } } @@ -66,11 +97,204 @@ impl ComponentStarter for StateSyncRunner { impl StateSyncRunner { pub fn new( config: StateSyncConfig, - request_receiver: mpsc::Receiver<(StateSyncRequest, oneshot::Sender)>, - ) -> Self { - let (storage_reader, storage_writer) = - open_storage(config.storage_config).expect("StateSyncRunner failed opening storage"); + new_block_receiver: Receiver, + class_manager_client: SharedClassManagerClient, + ) -> (Self, StorageReader) { + let StateSyncConfig { + storage_config, + p2p_sync_client_config, + central_sync_client_config, + network_config, + revert_config, + } = config; + + let (storage_reader, mut storage_writer) = + open_storage(storage_config).expect("StateSyncRunner failed opening storage"); + + register_metrics(&storage_reader.begin_ro_txn().unwrap()); + + if revert_config.should_revert { + let revert_up_to_and_including = revert_config.revert_up_to_and_including; + // We assume that sync always writes the headers before any other block data. + let current_header_marker = storage_reader + .begin_ro_txn() + .expect("Should be able to begin read only transaction") + .get_header_marker() + .expect("Should have a header marker"); + + let revert_block_fn = move |current_block_number| { + let n_reverted_txs = storage_writer + .begin_rw_txn() + .unwrap() + .get_block_transactions_count(current_block_number) + .unwrap() + .unwrap_or(0) + .try_into() + .expect("Failed to convert usize to u64"); + revert_block(&mut storage_writer, current_block_number); + update_marker_metrics(&storage_writer.begin_rw_txn().unwrap()); + SYNC_REVERTED_TRANSACTIONS.increment(n_reverted_txs); + async {} + }; + + return ( + Self { + network_future: pending().boxed(), + p2p_sync_client_future: revert_blocks_and_eternal_pending( + current_header_marker, + revert_up_to_and_including, + revert_block_fn, + "State Sync", + ) + .map(|_never| unreachable!("Never should never be constructed")) + .boxed(), + p2p_sync_server_future: pending().boxed(), + central_sync_client_future: pending().boxed(), + new_block_dev_null_future: pending().boxed(), + }, + storage_reader, + ); + } + + let network_manager_metrics = Some(NetworkMetrics { + num_connected_peers: STATE_SYNC_P2P_NUM_CONNECTED_PEERS, + num_blacklisted_peers: STATE_SYNC_P2P_NUM_BLACKLISTED_PEERS, + broadcast_metrics_by_topic: None, + sqmr_metrics: Some(SqmrNetworkMetrics { + num_active_inbound_sessions: STATE_SYNC_P2P_NUM_ACTIVE_INBOUND_SESSIONS, + num_active_outbound_sessions: STATE_SYNC_P2P_NUM_ACTIVE_OUTBOUND_SESSIONS, + }), + }); + let mut network_manager = network_manager::NetworkManager::new( + network_config, + Some(VERSION_FULL.to_string()), + network_manager_metrics, + ); + + // Creating the sync server future + let p2p_sync_server = Self::new_p2p_state_sync_server( + storage_reader.clone(), + &mut network_manager, + class_manager_client.clone(), + ); + let p2p_sync_server_future = p2p_sync_server.run().boxed(); + + // Creating the sync clients futures + // Exactly one of the sync clients must be turned on. + let (p2p_sync_client_future, central_sync_client_future, new_block_dev_null_future) = + match (p2p_sync_client_config, central_sync_client_config) { + (Some(p2p_sync_client_config), None) => { + let p2p_sync_client = Self::new_p2p_state_sync_client( + storage_reader.clone(), + storage_writer, + p2p_sync_client_config, + &mut network_manager, + new_block_receiver, + class_manager_client, + ); + let p2p_sync_client_future = p2p_sync_client.run().boxed(); + let central_sync_client_future = future::pending().boxed(); + let new_block_dev_null_future = future::pending().boxed(); + (p2p_sync_client_future, central_sync_client_future, new_block_dev_null_future) + } + (None, Some(central_sync_client_config)) => { + let central_sync_client = Self::new_central_state_sync_client( + storage_reader.clone(), + storage_writer, + central_sync_client_config, + class_manager_client, + ); + let p2p_sync_client_future = future::pending().boxed(); + let central_sync_client_future = central_sync_client.run().boxed(); + let new_block_dev_null_future = + create_new_block_receiver_future_dev_null(new_block_receiver); + (p2p_sync_client_future, central_sync_client_future, new_block_dev_null_future) + } + _ => { + panic!( + "It is validated that exactly one of --sync.#is_none or \ + --p2p_sync.#is_none must be turned on" + ) + } + }; + ( + Self { + network_future: network_manager.run().boxed(), + p2p_sync_client_future, + p2p_sync_server_future, + central_sync_client_future, + new_block_dev_null_future, + }, + storage_reader, + ) + } + + fn new_p2p_state_sync_client( + storage_reader: StorageReader, + storage_writer: StorageWriter, + p2p_sync_client_config: P2pSyncClientConfig, + network_manager: &mut NetworkManager, + new_block_receiver: Receiver, + class_manager_client: SharedClassManagerClient, + ) -> P2pSyncClient { + let header_client_sender = network_manager + .register_sqmr_protocol_client(Protocol::SignedBlockHeader.into(), BUFFER_SIZE); + let state_diff_client_sender = + network_manager.register_sqmr_protocol_client(Protocol::StateDiff.into(), BUFFER_SIZE); + let transaction_client_sender = network_manager + .register_sqmr_protocol_client(Protocol::Transaction.into(), BUFFER_SIZE); + let class_client_sender = + network_manager.register_sqmr_protocol_client(Protocol::Class.into(), BUFFER_SIZE); + let p2p_sync_client_channels = P2pSyncClientChannels::new( + header_client_sender, + state_diff_client_sender, + transaction_client_sender, + class_client_sender, + ); + P2pSyncClient::new( + p2p_sync_client_config, + storage_reader, + storage_writer, + p2p_sync_client_channels, + new_block_receiver.boxed(), + class_manager_client.clone(), + ) + } + + fn new_p2p_state_sync_server( + storage_reader: StorageReader, + network_manager: &mut NetworkManager, + class_manager_client: SharedClassManagerClient, + ) -> P2pSyncServer { + let header_server_receiver = network_manager + .register_sqmr_protocol_server(Protocol::SignedBlockHeader.into(), BUFFER_SIZE); + let state_diff_server_receiver = + network_manager.register_sqmr_protocol_server(Protocol::StateDiff.into(), BUFFER_SIZE); + let transaction_server_receiver = network_manager + .register_sqmr_protocol_server(Protocol::Transaction.into(), BUFFER_SIZE); + let class_server_receiver = + network_manager.register_sqmr_protocol_server(Protocol::Class.into(), BUFFER_SIZE); + let event_server_receiver = + network_manager.register_sqmr_protocol_server(Protocol::Event.into(), BUFFER_SIZE); + let p2p_sync_server_channels = P2pSyncServerChannels::new( + header_server_receiver, + state_diff_server_receiver, + transaction_server_receiver, + class_server_receiver, + event_server_receiver, + ); + P2pSyncServer::new(storage_reader, p2p_sync_server_channels, class_manager_client) + } + + fn new_central_state_sync_client( + storage_reader: StorageReader, + storage_writer: StorageWriter, + central_sync_client_config: CentralSyncClientConfig, + class_manager_client: SharedClassManagerClient, + ) -> CentralStateSync { + let CentralSyncClientConfig { sync_config, central_source_config } = + central_sync_client_config; let shared_highest_block = Arc::new(RwLock::new(None)); let pending_data = Arc::new(RwLock::new(PendingData { // The pending data might change later to DeprecatedPendingBlock, depending on the @@ -82,46 +306,78 @@ impl StateSyncRunner { ..Default::default() })); let pending_classes = Arc::new(RwLock::new(PendingClasses::default())); - let central_source = - CentralSource::new(config.central_config.clone(), VERSION_FULL, storage_reader.clone()) - .expect("Failed creating CentralSource"); - // TODO(shahak): add the ability to disable pending sync and disable it here. - let pending_source = PendingSource::new(config.central_config, VERSION_FULL) - .expect("Failed creating PendingSource"); - let base_layer_source = EthereumBaseLayerSource::new(config.base_layer_config) - .expect("Failed creating base layer"); - let sync = PapyrusStateSync::new( - config.sync_config, + CentralSource::new(central_source_config.clone(), VERSION_FULL, storage_reader.clone()) + .map_err(CentralError::ClientCreation) + .expect("CentralSource creation failed in central sync"); + let pending_source = PendingSource::new(central_source_config, VERSION_FULL) + .map_err(CentralError::ClientCreation) + .expect("PendingSource creation failed in central sync"); + let base_layer_source = None; + CentralStateSync::new( + sync_config, shared_highest_block, pending_data, pending_classes, central_source, pending_source, base_layer_source, - storage_reader.clone(), + storage_reader, storage_writer, - ); - let sync_future = sync.run().boxed(); - - // TODO(shahak): add rpc. - Self { request_receiver, storage_reader, sync_future } + Some(class_manager_client), + ) } +} - fn get_block(&self, block_number: BlockNumber) -> StateSyncResult> { - let txn = self.storage_reader.begin_ro_txn()?; - if let Some(block_transaction_hashes) = txn.get_block_transaction_hashes(block_number)? { - if let Some(thin_state_diff) = txn.get_state_diff(block_number)? { - return Ok(Some(SyncBlock { - state_diff: thin_state_diff, - transaction_hashes: block_transaction_hashes, - })); - } +/// A future that consumes the new block receiver and does nothing with the received blocks, to +/// prevent the buffer from filling up. +fn create_new_block_receiver_future_dev_null( + mut new_block_receiver: Receiver, +) -> BoxFuture<'static, Never> { + async move { + loop { + let _sync_block = new_block_receiver.next().await; } + } + .boxed() +} + +fn register_metrics(txn: &StorageTxn<'_, Mode>) { + SYNC_HEADER_MARKER.register(); + SYNC_BODY_MARKER.register(); + SYNC_STATE_MARKER.register(); + SYNC_CLASS_MANAGER_MARKER.register(); + SYNC_COMPILED_CLASS_MARKER.register(); + SYNC_PROCESSED_TRANSACTIONS.register(); + SYNC_REVERTED_TRANSACTIONS.register(); + update_marker_metrics(txn); + reconstruct_processed_transactions_metric(txn); +} + +fn update_marker_metrics(txn: &StorageTxn<'_, Mode>) { + SYNC_HEADER_MARKER.set_lossy(txn.get_header_marker().expect("Should have a header marker").0); + SYNC_BODY_MARKER.set_lossy(txn.get_body_marker().expect("Should have a body marker").0); + SYNC_STATE_MARKER.set_lossy(txn.get_state_marker().expect("Should have a state marker").0); + SYNC_CLASS_MANAGER_MARKER.set_lossy( + txn.get_class_manager_block_marker().expect("Should have a class manager block marker").0, + ); + SYNC_COMPILED_CLASS_MARKER + .set_lossy(txn.get_compiled_class_marker().expect("Should have a compiled class marker").0); +} + +fn reconstruct_processed_transactions_metric(txn: &StorageTxn<'_, impl TransactionKind>) { + let block_marker = txn.get_body_marker().expect("Should have a body marker"); - Ok(None) + for current_block_number in 0..block_marker.0 { + let current_block_tx_count = txn + .get_block_transactions_count(BlockNumber(current_block_number)) + .expect("Should have block transactions count") + .expect("Missing block body with block number smaller than body marker"); + SYNC_PROCESSED_TRANSACTIONS + .increment(current_block_tx_count.try_into().expect("Failed to convert usize to u64")); } } +pub type StateSyncRunnerServer = WrapperServer; // TODO(shahak): fill with a proper version, or allow not specifying the node version. const VERSION_FULL: &str = ""; diff --git a/crates/starknet_state_sync/src/runner/test.rs b/crates/starknet_state_sync/src/runner/test.rs index aeba980d668..429793b4c61 100644 --- a/crates/starknet_state_sync/src/runner/test.rs +++ b/crates/starknet_state_sync/src/runner/test.rs @@ -1,28 +1,62 @@ -use futures::channel::mpsc; -use futures::future::ready; +use futures::future::{pending, ready}; use futures::FutureExt; -use papyrus_storage::test_utils::get_test_storage; -use papyrus_sync::StateSyncError as PapyrusStateSyncError; +use papyrus_network::network_manager::NetworkError; +use papyrus_p2p_sync::client::P2pSyncClientError; use starknet_sequencer_infra::component_definitions::ComponentStarter; use super::StateSyncRunner; -const BUFFER_SIZE: usize = 1000; +#[test] +#[should_panic] +fn run_panics_when_network_future_returns() { + let network_future = ready(Ok(())).boxed(); + let p2p_sync_client_future = pending().boxed(); + let p2p_sync_server_future = pending().boxed(); + let central_sync_client_future = pending().boxed(); + let new_block_dev_null_future = pending().boxed(); + let mut state_sync_runner = StateSyncRunner { + network_future, + p2p_sync_client_future, + p2p_sync_server_future, + central_sync_client_future, + new_block_dev_null_future, + }; + state_sync_runner.start().now_or_never().unwrap(); +} #[test] -fn run_returns_when_sync_future_returns() { - let (_request_sender, request_receiver) = mpsc::channel(BUFFER_SIZE); - let (storage_reader, _storage_writer) = get_test_storage().0; - let sync_future = ready(Ok(())).boxed(); - let mut state_sync_runner = StateSyncRunner { request_receiver, storage_reader, sync_future }; - state_sync_runner.start().now_or_never().unwrap().unwrap(); +#[should_panic] +fn run_panics_when_network_future_returns_error() { + let network_future = + ready(Err(NetworkError::DialError(libp2p::swarm::DialError::Aborted))).boxed(); + let p2p_sync_client_future = pending().boxed(); + let p2p_sync_server_future = pending().boxed(); + let central_sync_client_future = pending().boxed(); + let new_block_dev_null_future = pending().boxed(); + let mut state_sync_runner = StateSyncRunner { + network_future, + p2p_sync_client_future, + p2p_sync_server_future, + central_sync_client_future, + new_block_dev_null_future, + }; + state_sync_runner.start().now_or_never().unwrap(); } #[test] -fn run_returns_error_when_sync_future_returns_error() { - let (_request_sender, request_receiver) = mpsc::channel(BUFFER_SIZE); - let (storage_reader, _storage_writer) = get_test_storage().0; - let sync_future = ready(Err(PapyrusStateSyncError::NoProgress)).boxed(); - let mut state_sync_runner = StateSyncRunner { request_receiver, storage_reader, sync_future }; - state_sync_runner.start().now_or_never().unwrap().unwrap_err(); +#[should_panic] +fn run_panics_when_sync_client_future_returns_error() { + let network_future = pending().boxed(); + let p2p_sync_client_future = ready(Err(P2pSyncClientError::TooManyResponses)).boxed(); + let p2p_sync_server_future = pending().boxed(); + let central_sync_client_future = pending().boxed(); + let new_block_dev_null_future = pending().boxed(); + let mut state_sync_runner = StateSyncRunner { + network_future, + p2p_sync_client_future, + p2p_sync_server_future, + central_sync_client_future, + new_block_dev_null_future, + }; + state_sync_runner.start().now_or_never().unwrap(); } diff --git a/crates/starknet_state_sync/src/test.rs b/crates/starknet_state_sync/src/test.rs new file mode 100644 index 00000000000..365196dac79 --- /dev/null +++ b/crates/starknet_state_sync/src/test.rs @@ -0,0 +1,304 @@ +// TODO(shahak): Test is_class_declared_at. +use futures::channel::mpsc::channel; +use indexmap::IndexMap; +use papyrus_storage::body::BodyStorageWriter; +use papyrus_storage::header::HeaderStorageWriter; +use papyrus_storage::state::StateStorageWriter; +use papyrus_storage::test_utils::get_test_storage; +use papyrus_storage::StorageWriter; +use papyrus_test_utils::{get_rng, get_test_block, get_test_state_diff, GetTestInstance}; +use rand_chacha::rand_core::RngCore; +use starknet_api::block::{Block, BlockHeader, BlockNumber}; +use starknet_api::core::{ClassHash, ContractAddress, Nonce}; +use starknet_api::state::{StorageKey, ThinStateDiff}; +use starknet_sequencer_infra::component_definitions::ComponentRequestHandler; +use starknet_state_sync_types::communication::{StateSyncRequest, StateSyncResponse}; +use starknet_state_sync_types::errors::StateSyncError; +use starknet_types_core::felt::Felt; + +use crate::StateSync; + +fn setup() -> (StateSync, StorageWriter) { + let ((storage_reader, storage_writer), _) = get_test_storage(); + let state_sync = StateSync { storage_reader, new_block_sender: channel(0).0 }; + (state_sync, storage_writer) +} + +#[tokio::test] +async fn test_get_block() { + let (mut state_sync, mut storage_writer) = setup(); + + let Block { header: expected_header, body: expected_body } = + get_test_block(1, None, None, None); + let expected_state_diff = ThinStateDiff::from(get_test_state_diff()); + + storage_writer + .begin_rw_txn() + .unwrap() + .append_header(expected_header.block_header_without_hash.block_number, &expected_header) + .unwrap() + .append_state_diff( + expected_header.block_header_without_hash.block_number, + expected_state_diff.clone(), + ) + .unwrap() + .append_body(expected_header.block_header_without_hash.block_number, expected_body.clone()) + .unwrap() + .commit() + .unwrap(); + + // Verify that the block was written and is returned correctly. + let response = state_sync + .handle_request(StateSyncRequest::GetBlock( + expected_header.block_header_without_hash.block_number, + )) + .await; + let StateSyncResponse::GetBlock(Ok(boxed_sync_block)) = response else { + panic!("Expected StateSyncResponse::GetBlock::Ok(Box(Some(_))), but got {:?}", response); + }; + let Some(block) = *boxed_sync_block else { + panic!("Expected Box(Some(_)), but got {:?}", boxed_sync_block); + }; + + assert_eq!(block.block_header_without_hash, expected_header.block_header_without_hash); + assert_eq!(block.state_diff, expected_state_diff); + assert_eq!(block.transaction_hashes.len(), 1); + assert_eq!(block.transaction_hashes[0], expected_body.transaction_hashes[0]); +} + +#[tokio::test] +async fn test_get_storage_at() { + let (mut state_sync, mut storage_writer) = setup(); + + let mut rng = get_rng(); + let address = ContractAddress::from(rng.next_u64()); + let key = StorageKey::from(rng.next_u64()); + let expected_value = Felt::from(rng.next_u64()); + let mut diff = ThinStateDiff::from(get_test_state_diff()); + diff.storage_diffs.insert(address, IndexMap::from([(key, expected_value)])); + diff.deployed_contracts.insert(address, Default::default()); + let header = BlockHeader::default(); + + storage_writer + .begin_rw_txn() + .unwrap() + .append_header(header.block_header_without_hash.block_number, &header) + .unwrap() + .append_state_diff(header.block_header_without_hash.block_number, diff.clone()) + .unwrap() + .append_body(header.block_header_without_hash.block_number, Default::default()) + .unwrap() + .commit() + .unwrap(); + + // Verify that the storage was written and is returned correctly. + let response = state_sync + .handle_request(StateSyncRequest::GetStorageAt( + header.block_header_without_hash.block_number, + address, + key, + )) + .await; + + let StateSyncResponse::GetStorageAt(Ok(value)) = response else { + panic!("Expected StateSyncResponse::GetStorageAt::Ok(_), but got {:?}", response); + }; + + assert_eq!(value, expected_value); +} + +#[tokio::test] +async fn test_get_nonce_at() { + let (mut state_sync, mut storage_writer) = setup(); + + let mut rng = get_rng(); + let address = ContractAddress::from(rng.next_u64()); + let expected_nonce = Nonce::get_test_instance(&mut rng); + let mut diff = ThinStateDiff::from(get_test_state_diff()); + diff.nonces.insert(address, expected_nonce); + diff.deployed_contracts.insert(address, Default::default()); + let header = BlockHeader::default(); + + storage_writer + .begin_rw_txn() + .unwrap() + .append_header(header.block_header_without_hash.block_number, &header) + .unwrap() + .append_state_diff(header.block_header_without_hash.block_number, diff.clone()) + .unwrap() + .append_body(header.block_header_without_hash.block_number, Default::default()) + .unwrap() + .commit() + .unwrap(); + + // Verify that the nonce was written and is returned correctly. + let response = state_sync + .handle_request(StateSyncRequest::GetNonceAt( + header.block_header_without_hash.block_number, + address, + )) + .await; + + let StateSyncResponse::GetNonceAt(Ok(nonce)) = response else { + panic!("Expected StateSyncResponse::GetNonceAt::Ok(_), but got {:?}", response); + }; + + assert_eq!(nonce, expected_nonce); +} + +#[tokio::test] +async fn get_class_hash_at() { + let (mut state_sync, mut storage_writer) = setup(); + + let mut rng = get_rng(); + let address = ContractAddress::from(rng.next_u64()); + let expected_class_hash = ClassHash::get_test_instance(&mut rng); + let mut diff = ThinStateDiff::from(get_test_state_diff()); + diff.deployed_contracts.insert(address, expected_class_hash); + let header = BlockHeader::default(); + + storage_writer + .begin_rw_txn() + .unwrap() + .append_header(header.block_header_without_hash.block_number, &header) + .unwrap() + .append_state_diff(header.block_header_without_hash.block_number, diff.clone()) + .unwrap() + .append_body(header.block_header_without_hash.block_number, Default::default()) + .unwrap() + .commit() + .unwrap(); + + // Verify that the class hash that was written is returned correctly. + let response = state_sync + .handle_request(StateSyncRequest::GetClassHashAt( + header.block_header_without_hash.block_number, + address, + )) + .await; + + let StateSyncResponse::GetClassHashAt(Ok(class_hash)) = response else { + panic!("Expected StateSyncResponse::GetClassHashAt::Ok(_), but got {:?}", response); + }; + + assert_eq!(class_hash, expected_class_hash); +} + +// Verify we get None/BlockNotFound when trying to call read methods with a block number that does +// not exist. +#[tokio::test] +async fn test_block_not_found() { + let (mut state_sync, _) = setup(); + let non_existing_block_number = BlockNumber(0); + + let response = + state_sync.handle_request(StateSyncRequest::GetBlock(non_existing_block_number)).await; + let StateSyncResponse::GetBlock(Ok(maybe_block)) = response else { + panic!("Expected StateSyncResponse::GetBlock::Ok(_), but got {:?}", response); + }; + + assert!(maybe_block.is_none()); + + let response = state_sync + .handle_request(StateSyncRequest::GetStorageAt( + non_existing_block_number, + Default::default(), + Default::default(), + )) + .await; + let StateSyncResponse::GetStorageAt(get_storage_at_result) = response else { + panic!("Expected StateSyncResponse::GetStorageAt(_), but got {:?}", response); + }; + + assert_eq!( + get_storage_at_result, + Err(StateSyncError::BlockNotFound(non_existing_block_number)) + ); + + let response = state_sync + .handle_request(StateSyncRequest::GetNonceAt(non_existing_block_number, Default::default())) + .await; + let StateSyncResponse::GetNonceAt(get_nonce_at_result) = response else { + panic!("Expected StateSyncResponse::GetNonceAt(_), but got {:?}", response); + }; + + assert_eq!(get_nonce_at_result, Err(StateSyncError::BlockNotFound(non_existing_block_number))); + + let response = state_sync + .handle_request(StateSyncRequest::GetClassHashAt( + non_existing_block_number, + Default::default(), + )) + .await; + let StateSyncResponse::GetClassHashAt(get_class_hash_at_result) = response else { + panic!("Expected StateSyncResponse::GetClassHashAt(_), but got {:?}", response); + }; + + assert_eq!( + get_class_hash_at_result, + Err(StateSyncError::BlockNotFound(non_existing_block_number)) + ); +} + +#[tokio::test] +async fn test_contract_not_found() { + let (mut state_sync, mut storage_writer) = setup(); + let address_u64 = 2_u64; + let address = ContractAddress::from(address_u64); + let mut diff = ThinStateDiff::default(); + // Create corrupted state diff with a contract that was not deployed. + diff.storage_diffs.insert(address, IndexMap::from([(Default::default(), Default::default())])); + diff.nonces.insert(address, Default::default()); + let header = BlockHeader::default(); + + storage_writer + .begin_rw_txn() + .unwrap() + .append_header(header.block_header_without_hash.block_number, &header) + .unwrap() + .append_state_diff(header.block_header_without_hash.block_number, diff) + .unwrap() + .append_body(header.block_header_without_hash.block_number, Default::default()) + .unwrap() + .commit() + .unwrap(); + + // Check that get_storage_at and get_nonce_at verify the contract was not deployed and therefore + // return contract not found, even though the state diff is corrupt and contains this storage + let response = state_sync + .handle_request(StateSyncRequest::GetStorageAt( + header.block_header_without_hash.block_number, + address, + Default::default(), + )) + .await; + let StateSyncResponse::GetStorageAt(get_storage_at_result) = response else { + panic!("Expected StateSyncResponse::GetStorageAt(_), but got {:?}", response); + }; + + assert_eq!(get_storage_at_result, Err(StateSyncError::ContractNotFound(address))); + + let response = state_sync + .handle_request(StateSyncRequest::GetNonceAt( + header.block_header_without_hash.block_number, + address, + )) + .await; + let StateSyncResponse::GetNonceAt(get_nonce_at_result) = response else { + panic!("Expected StateSyncResponse::GetNonceAt(_), but got {:?}", response); + }; + + assert_eq!(get_nonce_at_result, Err(StateSyncError::ContractNotFound(address))); + + let response = state_sync + .handle_request(StateSyncRequest::GetClassHashAt( + header.block_header_without_hash.block_number, + address, + )) + .await; + let StateSyncResponse::GetClassHashAt(get_class_hash_at_result) = response else { + panic!("Expected StateSyncResponse::GetClassHashAt(_), but got {:?}", response); + }; + + assert_eq!(get_class_hash_at_result, Err(StateSyncError::ContractNotFound(address))); +} diff --git a/crates/starknet_state_sync_types/Cargo.toml b/crates/starknet_state_sync_types/Cargo.toml index f9204e63388..7b9d8462513 100644 --- a/crates/starknet_state_sync_types/Cargo.toml +++ b/crates/starknet_state_sync_types/Cargo.toml @@ -5,14 +5,24 @@ edition.workspace = true license.workspace = true repository.workspace = true +[features] +testing = ["mockall"] + [lints] workspace = true [dependencies] async-trait.workspace = true +futures.workspace = true +mockall = { workspace = true, optional = true } papyrus_proc_macros.workspace = true papyrus_storage.workspace = true serde = { workspace = true, features = ["derive"] } +starknet-types-core.workspace = true starknet_api.workspace = true starknet_sequencer_infra.workspace = true +strum_macros.workspace = true thiserror.workspace = true + +[dev-dependencies] +mockall.workspace = true diff --git a/crates/starknet_state_sync_types/src/communication.rs b/crates/starknet_state_sync_types/src/communication.rs index 7b4e406c142..01e662714f0 100644 --- a/crates/starknet_state_sync_types/src/communication.rs +++ b/crates/starknet_state_sync_types/src/communication.rs @@ -1,9 +1,13 @@ use std::sync::Arc; use async_trait::async_trait; -use papyrus_proc_macros::handle_response_variants; +#[cfg(any(feature = "testing", test))] +use mockall::automock; +use papyrus_proc_macros::handle_all_response_variants; use serde::{Deserialize, Serialize}; use starknet_api::block::BlockNumber; +use starknet_api::core::{ClassHash, ContractAddress, Nonce}; +use starknet_api::state::StorageKey; use starknet_sequencer_infra::component_client::{ ClientError, LocalComponentClient, @@ -13,24 +17,75 @@ use starknet_sequencer_infra::component_definitions::{ ComponentClient, ComponentRequestAndResponseSender, }; +use starknet_sequencer_infra::impl_debug_for_infra_requests_and_responses; +use starknet_types_core::felt::Felt; +use strum_macros::AsRefStr; use thiserror::Error; use crate::errors::StateSyncError; -use crate::state_sync_types::SyncBlock; +use crate::state_sync_types::{StateSyncResult, SyncBlock}; +#[cfg_attr(any(test, feature = "testing"), automock)] #[async_trait] pub trait StateSyncClient: Send + Sync { /// Request for a block at a specific height. - /// If the block doesn't exist, or if the sync didn't download it yet, returns None. + /// Returns None if the block doesn't exist or the sync hasn't downloaded it yet. async fn get_block( &self, block_number: BlockNumber, ) -> StateSyncClientResult>; - // TODO: Add state reader methods for gateway. -} + /// Notify the sync that a new block has been created within the node so that other peers can + /// learn about it through sync. + async fn add_new_block(&self, sync_block: SyncBlock) -> StateSyncClientResult<()>; + + /// Request storage value under the given key in the given contract instance. + /// Returns a [BlockNotFound](StateSyncError::BlockNotFound) error if the block doesn't exist or + /// the sync hasn't been downloaded yet. + /// Returns a [ContractNotFound](StateSyncError::ContractNotFound) error If the contract has not + /// been deployed. + async fn get_storage_at( + &self, + block_number: BlockNumber, + contract_address: ContractAddress, + storage_key: StorageKey, + ) -> StateSyncClientResult; + + /// Request nonce in the given contract instance. + /// Returns a [BlockNotFound](StateSyncError::BlockNotFound) error if the block doesn't exist or + /// the sync hasn't been downloaded yet. + /// Returns a [ContractNotFound](StateSyncError::ContractNotFound) error If the contract has not + /// been deployed. + async fn get_nonce_at( + &self, + block_number: BlockNumber, + contract_address: ContractAddress, + ) -> StateSyncClientResult; + + /// Request class hash of contract class in the given contract instance. + /// Returns a [BlockNotFound](StateSyncError::BlockNotFound) error if the block doesn't exist or + /// the sync hasn't been downloaded yet. + /// Returns a [ContractNotFound](StateSyncError::ContractNotFound) error If the contract has not + /// been deployed. + async fn get_class_hash_at( + &self, + block_number: BlockNumber, + contract_address: ContractAddress, + ) -> StateSyncClientResult; -pub type StateSyncResult = Result; + /// Request latest block number the sync has downloaded. + /// Returns None if no latest block was yet downloaded. + async fn get_latest_block_number(&self) -> StateSyncClientResult>; + + /// Returns whether the given class was declared at the given block or before it. + async fn is_class_declared_at( + &self, + block_number: BlockNumber, + class_hash: ClassHash, + ) -> StateSyncClientResult; + + // TODO(Shahak): Add get_compiled_class_hash for StateSyncReader +} #[derive(Clone, Debug, Error)] pub enum StateSyncClientError { @@ -47,36 +102,129 @@ pub type SharedStateSyncClient = Arc; pub type StateSyncRequestAndResponseSender = ComponentRequestAndResponseSender; -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Serialize, Deserialize, AsRefStr)] pub enum StateSyncRequest { GetBlock(BlockNumber), + AddNewBlock(Box), + GetStorageAt(BlockNumber, ContractAddress, StorageKey), + GetNonceAt(BlockNumber, ContractAddress), + GetClassHashAt(BlockNumber, ContractAddress), + GetLatestBlockNumber(), + IsClassDeclaredAt(BlockNumber, ClassHash), } +impl_debug_for_infra_requests_and_responses!(StateSyncRequest); -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Serialize, Deserialize, AsRefStr)] pub enum StateSyncResponse { - GetBlock(StateSyncResult>), + GetBlock(StateSyncResult>>), + AddNewBlock(StateSyncResult<()>), + GetStorageAt(StateSyncResult), + GetNonceAt(StateSyncResult), + GetClassHashAt(StateSyncResult), + GetLatestBlockNumber(StateSyncResult>), + IsClassDeclaredAt(StateSyncResult), } +impl_debug_for_infra_requests_and_responses!(StateSyncResponse); #[async_trait] -impl StateSyncClient for LocalStateSyncClient { +impl StateSyncClient for ComponentClientType +where + ComponentClientType: Send + Sync + ComponentClient, +{ async fn get_block( &self, block_number: BlockNumber, ) -> StateSyncClientResult> { let request = StateSyncRequest::GetBlock(block_number); - let response = self.send(request).await; - handle_response_variants!(StateSyncResponse, GetBlock, StateSyncClientError, StateSyncError) + handle_all_response_variants!( + StateSyncResponse, + GetBlock, + StateSyncClientError, + StateSyncError, + Boxed + ) } -} -#[async_trait] -impl StateSyncClient for RemoteStateSyncClient { - async fn get_block( + async fn add_new_block(&self, sync_block: SyncBlock) -> StateSyncClientResult<()> { + let request = StateSyncRequest::AddNewBlock(Box::new(sync_block)); + handle_all_response_variants!( + StateSyncResponse, + AddNewBlock, + StateSyncClientError, + StateSyncError, + Direct + ) + } + + async fn get_storage_at( &self, block_number: BlockNumber, - ) -> StateSyncClientResult> { - let request = StateSyncRequest::GetBlock(block_number); - let response = self.send(request).await; - handle_response_variants!(StateSyncResponse, GetBlock, StateSyncClientError, StateSyncError) + contract_address: ContractAddress, + storage_key: StorageKey, + ) -> StateSyncClientResult { + let request = StateSyncRequest::GetStorageAt(block_number, contract_address, storage_key); + handle_all_response_variants!( + StateSyncResponse, + GetStorageAt, + StateSyncClientError, + StateSyncError, + Direct + ) + } + + async fn get_nonce_at( + &self, + block_number: BlockNumber, + contract_address: ContractAddress, + ) -> StateSyncClientResult { + let request = StateSyncRequest::GetNonceAt(block_number, contract_address); + handle_all_response_variants!( + StateSyncResponse, + GetNonceAt, + StateSyncClientError, + StateSyncError, + Direct + ) + } + + async fn get_class_hash_at( + &self, + block_number: BlockNumber, + contract_address: ContractAddress, + ) -> StateSyncClientResult { + let request = StateSyncRequest::GetClassHashAt(block_number, contract_address); + handle_all_response_variants!( + StateSyncResponse, + GetClassHashAt, + StateSyncClientError, + StateSyncError, + Direct + ) + } + + async fn get_latest_block_number(&self) -> StateSyncClientResult> { + let request = StateSyncRequest::GetLatestBlockNumber(); + handle_all_response_variants!( + StateSyncResponse, + GetLatestBlockNumber, + StateSyncClientError, + StateSyncError, + Direct + ) + } + + async fn is_class_declared_at( + &self, + block_number: BlockNumber, + class_hash: ClassHash, + ) -> StateSyncClientResult { + let request = StateSyncRequest::IsClassDeclaredAt(block_number, class_hash); + handle_all_response_variants!( + StateSyncResponse, + IsClassDeclaredAt, + StateSyncClientError, + StateSyncError, + Direct + ) } } diff --git a/crates/starknet_state_sync_types/src/errors.rs b/crates/starknet_state_sync_types/src/errors.rs index f5842256ac0..be42ab956ca 100644 --- a/crates/starknet_state_sync_types/src/errors.rs +++ b/crates/starknet_state_sync_types/src/errors.rs @@ -1,15 +1,33 @@ +use futures::channel::mpsc::SendError; use papyrus_storage::StorageError; use serde::{Deserialize, Serialize}; +use starknet_api::block::BlockNumber; +use starknet_api::core::{ClassHash, ContractAddress}; +use starknet_api::StarknetApiError; use thiserror::Error; -#[derive(Debug, Error, Serialize, Deserialize, Clone)] +#[derive(Debug, Error, Serialize, Deserialize, Clone, PartialEq, Eq)] pub enum StateSyncError { #[error("Communication error between StateSync and StateSyncRunner")] RunnerCommunicationError, - // StorageError does not derive Serialize, Deserialize and Clone Traits. - // We put the string of the error instead. + #[error("Block number {0} was not found")] + BlockNotFound(BlockNumber), + #[error("Contract address {0} was not found")] + ContractNotFound(ContractAddress), + #[error("Class hash {0} was not found")] + ClassNotFound(ClassHash), + // StorageError and StarknetApiError do not derive Serialize, Deserialize and Clone Traits. + // We put the string of the errors instead. #[error("Unexpected storage error: {0}")] StorageError(String), + // SendError does not derive Serialize and Deserialize Traits. + // We put the string of the error instead. + #[error("Error while sending SyncBlock from StateSync to P2pSyncClient")] + SendError(String), + #[error("Unexpected starknet api error: {0}")] + StarknetApiError(String), + #[error("State is empty, latest block returned None")] + EmptyState, } impl From for StateSyncError { @@ -17,3 +35,15 @@ impl From for StateSyncError { StateSyncError::StorageError(error.to_string()) } } + +impl From for StateSyncError { + fn from(error: StarknetApiError) -> Self { + StateSyncError::StarknetApiError(error.to_string()) + } +} + +impl From for StateSyncError { + fn from(error: SendError) -> Self { + StateSyncError::SendError(error.to_string()) + } +} diff --git a/crates/starknet_state_sync_types/src/state_sync_types.rs b/crates/starknet_state_sync_types/src/state_sync_types.rs index 4a2b7b2d45f..d8968545bbf 100644 --- a/crates/starknet_state_sync_types/src/state_sync_types.rs +++ b/crates/starknet_state_sync_types/src/state_sync_types.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize}; +use starknet_api::block::BlockHeaderWithoutHash; use starknet_api::state::ThinStateDiff; use starknet_api::transaction::TransactionHash; @@ -11,9 +12,10 @@ pub type StateSyncResult = Result; /// /// Blocks that came from the state sync are trusted. Therefore, SyncBlock doesn't contain data /// needed for verifying the block -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct SyncBlock { pub state_diff: ThinStateDiff, - // TODO: decide if we want block hash, parent block hash and full classes here. + // TODO(Matan): decide if we want block hash, parent block hash and full classes here. pub transaction_hashes: Vec, + pub block_header_without_hash: BlockHeaderWithoutHash, } diff --git a/crates/starknet_task_executor/src/tokio_executor.rs b/crates/starknet_task_executor/src/tokio_executor.rs index b77c954b301..880888b6a70 100644 --- a/crates/starknet_task_executor/src/tokio_executor.rs +++ b/crates/starknet_task_executor/src/tokio_executor.rs @@ -70,7 +70,7 @@ impl TaskExecutor for TokioExecutor { /// Spawns a task that may block, on a dedicated thread, preventing disruption of the async /// runtime. - + /// /// # Example /// /// ``` diff --git a/deployments/anvil/.gitignore b/deployments/anvil/.gitignore new file mode 100644 index 00000000000..dc0d6d7d379 --- /dev/null +++ b/deployments/anvil/.gitignore @@ -0,0 +1,4 @@ +__pycache__/ +.idea/ +dist/ +imports/ diff --git a/deployments/anvil/Pipfile b/deployments/anvil/Pipfile new file mode 100644 index 00000000000..8273824dc43 --- /dev/null +++ b/deployments/anvil/Pipfile @@ -0,0 +1,15 @@ +[[source]] +name = "pypi" +url = "https://pypi.org/simple" +verify_ssl = true + +[requires] +python_version = "3" + +[packages] +constructs = "~=10.4.2" +cdk8s = "~=2.69.17" +cdk8s-plus-28 = "~=2.5.6" + +[pipenv] +allow_prereleases = true diff --git a/deployments/anvil/Pipfile.lock b/deployments/anvil/Pipfile.lock new file mode 100644 index 00000000000..613de2896e4 --- /dev/null +++ b/deployments/anvil/Pipfile.lock @@ -0,0 +1,135 @@ +{ + "_meta": { + "hash": { + "sha256": "8d37692434b37388beb09bffe5913dee81d3f5d4102f7dbd67222f8bdead99c6" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "attrs": { + "hashes": [ + "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff", + "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308" + ], + "markers": "python_version >= '3.8'", + "version": "==24.3.0" + }, + "cattrs": { + "hashes": [ + "sha256:67c7495b760168d931a10233f979b28dc04daf853b30752246f4f8471c6d68d0", + "sha256:8028cfe1ff5382df59dd36474a86e02d817b06eaf8af84555441bac915d2ef85" + ], + "markers": "python_version >= '3.8'", + "version": "==24.1.2" + }, + "cdk8s": { + "hashes": [ + "sha256:96a86b2432391ad2372016ea0758e4ac6a0ffea58e4a4c1d3e36f51550994d43", + "sha256:b2538b86132894b44bb08ca238d35aa759428b9b00f813b73c448493c491d144" + ], + "index": "pypi", + "markers": "python_version ~= '3.8'", + "version": "==2.69.35" + }, + "cdk8s-plus-28": { + "hashes": [ + "sha256:458a430dc715d8f87c963685f3a609ad07896b2988a92f4e3bcbbef261273ea1", + "sha256:4b6673742b9a360b5703acf260ee929a9fdebc6df45474e53cb22f1dd9cc0a79" + ], + "index": "pypi", + "markers": "python_version ~= '3.8'", + "version": "==2.5.6" + }, + "constructs": { + "hashes": [ + "sha256:1f0f59b004edebfde0f826340698b8c34611f57848139b7954904c61645f13c1", + "sha256:ce54724360fffe10bab27d8a081844eb81f5ace7d7c62c84b719c49f164d5307" + ], + "index": "pypi", + "markers": "python_version ~= '3.8'", + "version": "==10.4.2" + }, + "exceptiongroup": { + "hashes": [ + "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", + "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc" + ], + "markers": "python_version < '3.11'", + "version": "==1.2.2" + }, + "importlib-resources": { + "hashes": [ + "sha256:185f87adef5bcc288449d98fb4fba07cea78bc036455dd44c5fc4a2fe78fed2c", + "sha256:789cfdc3ed28c78b67a06acb8126751ced69a3d5f79c095a98298cd8a760ccec" + ], + "markers": "python_version >= '3.9'", + "version": "==6.5.2" + }, + "jsii": { + "hashes": [ + "sha256:5a44d7c3a5a326fa3d9befdb3770b380057e0a61e3804e7c4907f70d76afaaa2", + "sha256:c79c47899f53a7c3c4b20f80d3cd306628fe9ed1852eee970324c71eba1d974e" + ], + "markers": "python_version ~= '3.8'", + "version": "==1.106.0" + }, + "publication": { + "hashes": [ + "sha256:0248885351febc11d8a1098d5c8e3ab2dabcf3e8c0c96db1e17ecd12b53afbe6", + "sha256:68416a0de76dddcdd2930d1c8ef853a743cc96c82416c4e4d3b5d901c6276dc4" + ], + "version": "==0.0.3" + }, + "python-dateutil": { + "hashes": [ + "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", + "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.9.0.post0" + }, + "six": { + "hashes": [ + "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", + "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.17.0" + }, + "typeguard": { + "hashes": [ + "sha256:00edaa8da3a133674796cf5ea87d9f4b4c367d77476e185e80251cc13dfbb8c4", + "sha256:5e3e3be01e887e7eafae5af63d1f36c849aaa94e3a0112097312aabfa16284f1" + ], + "markers": "python_full_version >= '3.5.3'", + "version": "==2.13.3" + }, + "typing-extensions": { + "hashes": [ + "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", + "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" + ], + "markers": "python_version >= '3.8'", + "version": "==4.12.2" + }, + "zipp": { + "hashes": [ + "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4", + "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931" + ], + "markers": "python_version < '3.10'", + "version": "==3.21.0" + } + }, + "develop": {} +} diff --git a/deployments/anvil/cdk8s.yaml b/deployments/anvil/cdk8s.yaml new file mode 100644 index 00000000000..7bd30b32efc --- /dev/null +++ b/deployments/anvil/cdk8s.yaml @@ -0,0 +1,4 @@ +language: python +app: pipenv run python main.py +imports: + - k8s diff --git a/deployments/anvil/main.py b/deployments/anvil/main.py new file mode 100755 index 00000000000..b56fa9c6ee3 --- /dev/null +++ b/deployments/anvil/main.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python +from constructs import Construct +from cdk8s import App, Chart, Names, YamlOutputType +from imports import k8s + +SERVICE_NAME = "anvil" +SERVICE_PORT = 8545 +CLUSTER = "sequencer-dev" +NAMESPACE = "anvil" +IMAGE = "ghcr.io/foundry-rs/foundry:v0.3.0" + + +class Anvil(Chart): + def __init__(self, scope: Construct, id: str, namespace: str): + super().__init__(scope, id, disable_resource_name_hashes=True, namespace=namespace) + + self.label = {"app": Names.to_label_value(self, include_hash=False)} + self.host = f"{self.node.id}.{CLUSTER}.sw-dev.io" + + k8s.KubeService( + self, + "service", + spec=k8s.ServiceSpec( + type="ClusterIP", + ports=[ + k8s.ServicePort( + name="http", + port=SERVICE_PORT, + target_port=k8s.IntOrString.from_number(SERVICE_PORT), + ), + ], + selector=self.label, + ), + ) + + k8s.KubeDeployment( + self, + "deployment", + spec=k8s.DeploymentSpec( + replicas=1, + selector=k8s.LabelSelector(match_labels=self.label), + template=k8s.PodTemplateSpec( + metadata=k8s.ObjectMeta(labels=self.label), + spec=k8s.PodSpec( + containers=[ + k8s.Container( + name=self.node.id, + image=IMAGE, + ports=[k8s.ContainerPort(container_port=SERVICE_PORT)], + command=[ + "anvil", + "--host", + "0.0.0.0", + "--block-time", + "1", + "--chain-id", + "31337", + ], + ) + ], + ), + ), + ), + ) + + k8s.KubeIngress( + self, + "ingress", + metadata=k8s.ObjectMeta( + name=f"{self.node.id}-ingress", + labels=self.label, + annotations={"nginx.ingress.kubernetes.io/rewrite-target": "/"}, + ), + spec=k8s.IngressSpec( + ingress_class_name="nginx", + rules=[ + k8s.IngressRule( + host=self.host, + http=k8s.HttpIngressRuleValue( + paths=[ + k8s.HttpIngressPath( + path="/", + path_type="ImplementationSpecific", + backend=k8s.IngressBackend( + service=k8s.IngressServiceBackend( + name=f"{self.node.id}-service", + port=k8s.ServiceBackendPort(number=SERVICE_PORT), + ) + ), + ) + ] + ), + ) + ], + ), + ) + + +app = App(yaml_output_type=YamlOutputType.FOLDER_PER_CHART_FILE_PER_RESOURCE) +Anvil(scope=app, id=SERVICE_NAME, namespace=NAMESPACE) + +app.synth() diff --git a/deployments/dummy_eth2strk_oracle/.gitignore b/deployments/dummy_eth2strk_oracle/.gitignore new file mode 100644 index 00000000000..dc0d6d7d379 --- /dev/null +++ b/deployments/dummy_eth2strk_oracle/.gitignore @@ -0,0 +1,4 @@ +__pycache__/ +.idea/ +dist/ +imports/ diff --git a/deployments/dummy_eth2strk_oracle/Pipfile b/deployments/dummy_eth2strk_oracle/Pipfile new file mode 100644 index 00000000000..8273824dc43 --- /dev/null +++ b/deployments/dummy_eth2strk_oracle/Pipfile @@ -0,0 +1,15 @@ +[[source]] +name = "pypi" +url = "https://pypi.org/simple" +verify_ssl = true + +[requires] +python_version = "3" + +[packages] +constructs = "~=10.4.2" +cdk8s = "~=2.69.17" +cdk8s-plus-28 = "~=2.5.6" + +[pipenv] +allow_prereleases = true diff --git a/deployments/dummy_eth2strk_oracle/Pipfile.lock b/deployments/dummy_eth2strk_oracle/Pipfile.lock new file mode 100644 index 00000000000..613de2896e4 --- /dev/null +++ b/deployments/dummy_eth2strk_oracle/Pipfile.lock @@ -0,0 +1,135 @@ +{ + "_meta": { + "hash": { + "sha256": "8d37692434b37388beb09bffe5913dee81d3f5d4102f7dbd67222f8bdead99c6" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "attrs": { + "hashes": [ + "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff", + "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308" + ], + "markers": "python_version >= '3.8'", + "version": "==24.3.0" + }, + "cattrs": { + "hashes": [ + "sha256:67c7495b760168d931a10233f979b28dc04daf853b30752246f4f8471c6d68d0", + "sha256:8028cfe1ff5382df59dd36474a86e02d817b06eaf8af84555441bac915d2ef85" + ], + "markers": "python_version >= '3.8'", + "version": "==24.1.2" + }, + "cdk8s": { + "hashes": [ + "sha256:96a86b2432391ad2372016ea0758e4ac6a0ffea58e4a4c1d3e36f51550994d43", + "sha256:b2538b86132894b44bb08ca238d35aa759428b9b00f813b73c448493c491d144" + ], + "index": "pypi", + "markers": "python_version ~= '3.8'", + "version": "==2.69.35" + }, + "cdk8s-plus-28": { + "hashes": [ + "sha256:458a430dc715d8f87c963685f3a609ad07896b2988a92f4e3bcbbef261273ea1", + "sha256:4b6673742b9a360b5703acf260ee929a9fdebc6df45474e53cb22f1dd9cc0a79" + ], + "index": "pypi", + "markers": "python_version ~= '3.8'", + "version": "==2.5.6" + }, + "constructs": { + "hashes": [ + "sha256:1f0f59b004edebfde0f826340698b8c34611f57848139b7954904c61645f13c1", + "sha256:ce54724360fffe10bab27d8a081844eb81f5ace7d7c62c84b719c49f164d5307" + ], + "index": "pypi", + "markers": "python_version ~= '3.8'", + "version": "==10.4.2" + }, + "exceptiongroup": { + "hashes": [ + "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", + "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc" + ], + "markers": "python_version < '3.11'", + "version": "==1.2.2" + }, + "importlib-resources": { + "hashes": [ + "sha256:185f87adef5bcc288449d98fb4fba07cea78bc036455dd44c5fc4a2fe78fed2c", + "sha256:789cfdc3ed28c78b67a06acb8126751ced69a3d5f79c095a98298cd8a760ccec" + ], + "markers": "python_version >= '3.9'", + "version": "==6.5.2" + }, + "jsii": { + "hashes": [ + "sha256:5a44d7c3a5a326fa3d9befdb3770b380057e0a61e3804e7c4907f70d76afaaa2", + "sha256:c79c47899f53a7c3c4b20f80d3cd306628fe9ed1852eee970324c71eba1d974e" + ], + "markers": "python_version ~= '3.8'", + "version": "==1.106.0" + }, + "publication": { + "hashes": [ + "sha256:0248885351febc11d8a1098d5c8e3ab2dabcf3e8c0c96db1e17ecd12b53afbe6", + "sha256:68416a0de76dddcdd2930d1c8ef853a743cc96c82416c4e4d3b5d901c6276dc4" + ], + "version": "==0.0.3" + }, + "python-dateutil": { + "hashes": [ + "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", + "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.9.0.post0" + }, + "six": { + "hashes": [ + "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", + "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.17.0" + }, + "typeguard": { + "hashes": [ + "sha256:00edaa8da3a133674796cf5ea87d9f4b4c367d77476e185e80251cc13dfbb8c4", + "sha256:5e3e3be01e887e7eafae5af63d1f36c849aaa94e3a0112097312aabfa16284f1" + ], + "markers": "python_full_version >= '3.5.3'", + "version": "==2.13.3" + }, + "typing-extensions": { + "hashes": [ + "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", + "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" + ], + "markers": "python_version >= '3.8'", + "version": "==4.12.2" + }, + "zipp": { + "hashes": [ + "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4", + "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931" + ], + "markers": "python_version < '3.10'", + "version": "==3.21.0" + } + }, + "develop": {} +} diff --git a/deployments/dummy_eth2strk_oracle/cdk8s.yaml b/deployments/dummy_eth2strk_oracle/cdk8s.yaml new file mode 100644 index 00000000000..7bd30b32efc --- /dev/null +++ b/deployments/dummy_eth2strk_oracle/cdk8s.yaml @@ -0,0 +1,4 @@ +language: python +app: pipenv run python main.py +imports: + - k8s diff --git a/deployments/dummy_eth2strk_oracle/main.py b/deployments/dummy_eth2strk_oracle/main.py new file mode 100755 index 00000000000..c9bd50a1f5c --- /dev/null +++ b/deployments/dummy_eth2strk_oracle/main.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python +from constructs import Construct +from cdk8s import App, Chart, Names, YamlOutputType +from imports import k8s + + +SERVICE_NAME = "dummy-eth2strk-oracle" +SERVICE_PORT = 9000 +CLUSTER = "sequencer-dev" +NAMESPACE = "dummy-eth2strk-oracle" +IMAGE = "us-central1-docker.pkg.dev/starkware-dev/sequencer/dummy_eth2strk_oracle:latest" + + +class DummyEth2StrkOracle(Chart): + def __init__(self, scope: Construct, id: str, namespace: str): + super().__init__(scope, id, disable_resource_name_hashes=True, namespace=namespace) + + self.label = {"app": Names.to_label_value(self, include_hash=False)} + self.host = f"{self.node.id}.{CLUSTER}.sw-dev.io" + + k8s.KubeService( + self, + "service", + spec=k8s.ServiceSpec( + type="ClusterIP", + ports=[ + k8s.ServicePort( + name="http", + port=SERVICE_PORT, + target_port=k8s.IntOrString.from_number(SERVICE_PORT), + ), + ], + selector=self.label, + ), + ) + + k8s.KubeDeployment( + self, + "deployment", + spec=k8s.DeploymentSpec( + replicas=1, + selector=k8s.LabelSelector(match_labels=self.label), + template=k8s.PodTemplateSpec( + metadata=k8s.ObjectMeta(labels=self.label), + spec=k8s.PodSpec( + containers=[ + k8s.Container( + name=self.node.id, + image=IMAGE, + env=[k8s.EnvVar(name="RUST_LOG", value="DEBUG")], + ports=[k8s.ContainerPort(container_port=SERVICE_PORT)], + ) + ], + ), + ), + ), + ) + + k8s.KubeIngress( + self, + "ingress", + metadata=k8s.ObjectMeta( + name=f"{self.node.id}-ingress", + labels=self.label, + annotations={"nginx.ingress.kubernetes.io/rewrite-target": "/"}, + ), + spec=k8s.IngressSpec( + ingress_class_name="nginx", + rules=[ + k8s.IngressRule( + host=self.host, + http=k8s.HttpIngressRuleValue( + paths=[ + k8s.HttpIngressPath( + path="/", + path_type="ImplementationSpecific", + backend=k8s.IngressBackend( + service=k8s.IngressServiceBackend( + name=f"{self.node.id}-service", + port=k8s.ServiceBackendPort(number=SERVICE_PORT), + ) + ), + ) + ] + ), + ) + ], + ), + ) + + +app = App(yaml_output_type=YamlOutputType.FOLDER_PER_CHART_FILE_PER_RESOURCE) +DummyEth2StrkOracle(scope=app, id=SERVICE_NAME, namespace=NAMESPACE) + +app.synth() diff --git a/deployments/dummy_recorder/.gitignore b/deployments/dummy_recorder/.gitignore new file mode 100644 index 00000000000..dc0d6d7d379 --- /dev/null +++ b/deployments/dummy_recorder/.gitignore @@ -0,0 +1,4 @@ +__pycache__/ +.idea/ +dist/ +imports/ diff --git a/deployments/dummy_recorder/Pipfile b/deployments/dummy_recorder/Pipfile new file mode 100644 index 00000000000..8273824dc43 --- /dev/null +++ b/deployments/dummy_recorder/Pipfile @@ -0,0 +1,15 @@ +[[source]] +name = "pypi" +url = "https://pypi.org/simple" +verify_ssl = true + +[requires] +python_version = "3" + +[packages] +constructs = "~=10.4.2" +cdk8s = "~=2.69.17" +cdk8s-plus-28 = "~=2.5.6" + +[pipenv] +allow_prereleases = true diff --git a/deployments/dummy_recorder/Pipfile.lock b/deployments/dummy_recorder/Pipfile.lock new file mode 100644 index 00000000000..613de2896e4 --- /dev/null +++ b/deployments/dummy_recorder/Pipfile.lock @@ -0,0 +1,135 @@ +{ + "_meta": { + "hash": { + "sha256": "8d37692434b37388beb09bffe5913dee81d3f5d4102f7dbd67222f8bdead99c6" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "attrs": { + "hashes": [ + "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff", + "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308" + ], + "markers": "python_version >= '3.8'", + "version": "==24.3.0" + }, + "cattrs": { + "hashes": [ + "sha256:67c7495b760168d931a10233f979b28dc04daf853b30752246f4f8471c6d68d0", + "sha256:8028cfe1ff5382df59dd36474a86e02d817b06eaf8af84555441bac915d2ef85" + ], + "markers": "python_version >= '3.8'", + "version": "==24.1.2" + }, + "cdk8s": { + "hashes": [ + "sha256:96a86b2432391ad2372016ea0758e4ac6a0ffea58e4a4c1d3e36f51550994d43", + "sha256:b2538b86132894b44bb08ca238d35aa759428b9b00f813b73c448493c491d144" + ], + "index": "pypi", + "markers": "python_version ~= '3.8'", + "version": "==2.69.35" + }, + "cdk8s-plus-28": { + "hashes": [ + "sha256:458a430dc715d8f87c963685f3a609ad07896b2988a92f4e3bcbbef261273ea1", + "sha256:4b6673742b9a360b5703acf260ee929a9fdebc6df45474e53cb22f1dd9cc0a79" + ], + "index": "pypi", + "markers": "python_version ~= '3.8'", + "version": "==2.5.6" + }, + "constructs": { + "hashes": [ + "sha256:1f0f59b004edebfde0f826340698b8c34611f57848139b7954904c61645f13c1", + "sha256:ce54724360fffe10bab27d8a081844eb81f5ace7d7c62c84b719c49f164d5307" + ], + "index": "pypi", + "markers": "python_version ~= '3.8'", + "version": "==10.4.2" + }, + "exceptiongroup": { + "hashes": [ + "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", + "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc" + ], + "markers": "python_version < '3.11'", + "version": "==1.2.2" + }, + "importlib-resources": { + "hashes": [ + "sha256:185f87adef5bcc288449d98fb4fba07cea78bc036455dd44c5fc4a2fe78fed2c", + "sha256:789cfdc3ed28c78b67a06acb8126751ced69a3d5f79c095a98298cd8a760ccec" + ], + "markers": "python_version >= '3.9'", + "version": "==6.5.2" + }, + "jsii": { + "hashes": [ + "sha256:5a44d7c3a5a326fa3d9befdb3770b380057e0a61e3804e7c4907f70d76afaaa2", + "sha256:c79c47899f53a7c3c4b20f80d3cd306628fe9ed1852eee970324c71eba1d974e" + ], + "markers": "python_version ~= '3.8'", + "version": "==1.106.0" + }, + "publication": { + "hashes": [ + "sha256:0248885351febc11d8a1098d5c8e3ab2dabcf3e8c0c96db1e17ecd12b53afbe6", + "sha256:68416a0de76dddcdd2930d1c8ef853a743cc96c82416c4e4d3b5d901c6276dc4" + ], + "version": "==0.0.3" + }, + "python-dateutil": { + "hashes": [ + "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", + "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.9.0.post0" + }, + "six": { + "hashes": [ + "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", + "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.17.0" + }, + "typeguard": { + "hashes": [ + "sha256:00edaa8da3a133674796cf5ea87d9f4b4c367d77476e185e80251cc13dfbb8c4", + "sha256:5e3e3be01e887e7eafae5af63d1f36c849aaa94e3a0112097312aabfa16284f1" + ], + "markers": "python_full_version >= '3.5.3'", + "version": "==2.13.3" + }, + "typing-extensions": { + "hashes": [ + "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", + "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" + ], + "markers": "python_version >= '3.8'", + "version": "==4.12.2" + }, + "zipp": { + "hashes": [ + "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4", + "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931" + ], + "markers": "python_version < '3.10'", + "version": "==3.21.0" + } + }, + "develop": {} +} diff --git a/deployments/dummy_recorder/cdk8s.yaml b/deployments/dummy_recorder/cdk8s.yaml new file mode 100644 index 00000000000..7bd30b32efc --- /dev/null +++ b/deployments/dummy_recorder/cdk8s.yaml @@ -0,0 +1,4 @@ +language: python +app: pipenv run python main.py +imports: + - k8s diff --git a/deployments/dummy_recorder/main.py b/deployments/dummy_recorder/main.py new file mode 100755 index 00000000000..7ee3d91abaa --- /dev/null +++ b/deployments/dummy_recorder/main.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python +from constructs import Construct +from cdk8s import App, Chart, Names, YamlOutputType +from imports import k8s + + +class DummyRecorder(Chart): + def __init__(self, scope: Construct, id: str, namespace: str): + super().__init__(scope, id, disable_resource_name_hashes=True, namespace=namespace) + + self.label = {"app": Names.to_label_value(self, include_hash=False)} + self.host = f"{self.node.id}.{self.namespace}.sw-dev.io" + + k8s.KubeService( + self, + "service", + spec=k8s.ServiceSpec( + type="ClusterIP", + ports=[ + k8s.ServicePort( + name="http", + port=8080, + target_port=k8s.IntOrString.from_number(8080) + ), + ], + selector=self.label, + ), + ) + + k8s.KubeDeployment( + self, + "deployment", + spec=k8s.DeploymentSpec( + replicas=1, + selector=k8s.LabelSelector(match_labels=self.label), + template=k8s.PodTemplateSpec( + metadata=k8s.ObjectMeta(labels=self.label), + spec=k8s.PodSpec( + containers=[ + k8s.Container( + name=self.node.id, + image="us-central1-docker.pkg.dev/starkware-dev/sequencer/dummy_recorder:latest", + env=[ + k8s.EnvVar( + name="RUST_LOG", + value="DEBUG" + ) + ], + ports=[ + k8s.ContainerPort( + container_port=8080 + ) + ], + ) + ], + ), + ), + ), + ) + + k8s.KubeIngress( + self, + "ingress", + metadata=k8s.ObjectMeta( + name=f"{self.node.id}-ingress", + labels=self.label, + annotations={ + "nginx.ingress.kubernetes.io/rewrite-target": "/" + } + ), + spec=k8s.IngressSpec( + ingress_class_name="nginx", + rules=[ + k8s.IngressRule( + host=self.host, + http=k8s.HttpIngressRuleValue( + paths=[ + k8s.HttpIngressPath( + path="/", + path_type="ImplementationSpecific", + backend=k8s.IngressBackend( + service=k8s.IngressServiceBackend( + name=f"{self.node.id}-service", + port=k8s.ServiceBackendPort( + number=8080 + ), + ) + ), + ) + ] + ), + ) + ] + ), + ) + + +app = App(yaml_output_type=YamlOutputType.FOLDER_PER_CHART_FILE_PER_RESOURCE) +DummyRecorder( + scope=app, + id="dummy-recorder", + namespace="dummy-recorder" +) + +app.synth() diff --git a/deployments/images/base/Dockerfile b/deployments/images/base/Dockerfile index 931544cd0ce..7a87fe70ec5 100644 --- a/deployments/images/base/Dockerfile +++ b/deployments/images/base/Dockerfile @@ -1,16 +1,15 @@ +# deployments/images/base/Dockerfile + # Dockerfile with multi-stage builds for efficient dependency caching and lightweight final image. # For more on Docker stages, visit: https://docs.docker.com/build/building/multi-stage/ +# We use dockerfile-x, for more information visit: https://github.com/devthefuture-org/dockerfile-x/blob/master/README.md -# We use Cargo Chef to compile dependencies before compiling the rest of the crates. -# This approach ensures proper Docker caching, where dependency layers are cached until a dependency changes. -# Code changes in our crates won't affect these cached layers, making the build process more efficient. -# More info on Cargo Chef: https://github.com/LukeMathWalker/cargo-chef - -FROM ubuntu:22.04 AS base -# WORKDIR /app +FROM ubuntu:24.04 AS base COPY scripts/install_build_tools.sh . COPY scripts/dependencies.sh . +COPY rust-toolchain.toml . + RUN apt update && apt -y install \ bzip2 \ curl \ @@ -22,6 +21,8 @@ ENV CARGO_HOME=${RUSTUP_HOME} ENV PATH=$PATH:${RUSTUP_HOME}/bin RUN ./install_build_tools.sh +RUN rustup toolchain install +RUN cargo install cargo-chef # Cleanup. RUN rm -f install_build_tools.sh dependencies.sh diff --git a/deployments/images/papyrus/Dockerfile b/deployments/images/papyrus/Dockerfile index 18a4049d844..6fc0e21636a 100644 --- a/deployments/images/papyrus/Dockerfile +++ b/deployments/images/papyrus/Dockerfile @@ -6,21 +6,22 @@ INCLUDE deployments/images/base/Dockerfile # Compile the papyrus_node crate in release mode, ensuring dependencies are locked. FROM base AS builder COPY . . +RUN rustup toolchain install RUN cargo build --release --package papyrus_node -FROM base AS papyrus_node +FROM ubuntu:24.04 as final_stage -ENV ID=1000 +ENV ID=1001 WORKDIR /app COPY --from=builder /target/release/papyrus_node /app/target/release/papyrus_node +COPY --from=builder /usr/bin/tini /usr/bin/tini COPY config/papyrus config/papyrus - # Create a new user "papyrus". RUN set -ex; \ - addgroup --gid ${ID} papyrus; \ - adduser --ingroup $(getent group ${ID} | cut -d: -f1) --uid ${ID} --gecos "" --disabled-password --home /app papyrus; \ + groupadd --gid ${ID} papyrus; \ + useradd --gid ${ID} --uid ${ID} --comment "" --create-home --home-dir /app papyrus; \ chown -R papyrus:papyrus /app # Expose RPC and monitoring ports. diff --git a/deployments/images/sequencer/Dockerfile b/deployments/images/sequencer/Dockerfile index d62dc01880d..26eb33db0cc 100644 --- a/deployments/images/sequencer/Dockerfile +++ b/deployments/images/sequencer/Dockerfile @@ -1,27 +1,42 @@ # syntax = devthefuture/dockerfile-x +# deployments/images/sequencer/Dockerfile + +# Dockerfile with multi-stage builds for efficient dependency caching and lightweight final image. +# For more on Docker stages, visit: https://docs.docker.com/build/building/multi-stage/ +# We use dockerfile-x, for more information visit: https://github.com/devthefuture-org/dockerfile-x/blob/master/README.md INCLUDE deployments/images/base/Dockerfile +FROM base AS planner +WORKDIR /app +COPY . . +# Installing rust version in rust-toolchain.toml +RUN cargo chef prepare --recipe-path recipe.json -# Compile the sequencer_node crate in release mode, ensuring dependencies are locked. FROM base AS builder +WORKDIR /app +COPY --from=planner /app/recipe.json recipe.json +RUN cargo chef cook --recipe-path recipe.json COPY . . -RUN cargo build --release --package starknet_sequencer_node +RUN cargo build -FROM base AS sequencer +FROM ubuntu:24.04 AS final_stage -ENV ID=1000 +ENV ID=1001 WORKDIR /app -COPY --from=builder /target/release/starknet_sequencer_node /app/target/release/starknet_sequencer_node +COPY --from=builder /app/target/debug/starknet_sequencer_node ./target/debug/starknet_sequencer_node +COPY --from=builder /app/target/debug/shared_executables/starknet-sierra-compile ./target/debug/shared_executables/starknet-sierra-compile +COPY --from=builder /usr/bin/tini /usr/bin/tini # Copy sequencer config COPY config/sequencer config/sequencer # Create a new user "sequencer". RUN set -ex; \ - addgroup --gid ${ID} sequencer; \ - adduser --ingroup $(getent group ${ID} | cut -d: -f1) --uid ${ID} --gecos "" --disabled-password --home /app sequencer; \ - chown -R sequencer:sequencer /app + groupadd --gid ${ID} sequencer; \ + useradd --gid ${ID} --uid ${ID} --comment "" --create-home --home-dir /app sequencer; \ + mkdir /data; \ + chown -R sequencer:sequencer /app /data # Expose RPC and monitoring ports. EXPOSE 8080 8081 8082 @@ -30,4 +45,4 @@ EXPOSE 8080 8081 8082 USER ${ID} # Set the entrypoint to use tini to manage the process. -ENTRYPOINT ["tini", "--", "/app/target/release/starknet_sequencer_node"] +ENTRYPOINT ["tini", "--", "/app/target/debug/starknet_sequencer_node"] diff --git a/deployments/images/sequencer/dummy_eth_to_strk_oracle.Dockerfile b/deployments/images/sequencer/dummy_eth_to_strk_oracle.Dockerfile new file mode 100644 index 00000000000..f263ab07e45 --- /dev/null +++ b/deployments/images/sequencer/dummy_eth_to_strk_oracle.Dockerfile @@ -0,0 +1,37 @@ +# syntax = devthefuture/dockerfile-x +# deployments/images/sequencer/dummy_eth_to_strk_oracle.Dockerfile + +# Dockerfile with multi-stage builds for efficient dependency caching and lightweight final image. +# For more on Docker stages, visit: https://docs.docker.com/build/building/multi-stage/ +# We use dockerfile-x, for more information visit: https://github.com/devthefuture-org/dockerfile-x/blob/master/README.md + +INCLUDE deployments/images/base/Dockerfile + +FROM base AS planner +WORKDIR /app +COPY . . +RUN cargo chef prepare --recipe-path recipe.json + +FROM base AS builder +WORKDIR /app +COPY --from=planner /app/recipe.json recipe.json +RUN cargo chef cook --recipe-path recipe.json +COPY . . +RUN cargo build + +FROM ubuntu:24.04 AS final_stage + +ENV ID=1001 +WORKDIR /app +COPY --from=builder /app/target/debug/dummy_eth_to_strk_oracle ./target/debug/dummy_eth_to_strk_oracle +COPY --from=builder /usr/bin/tini /usr/bin/tini + +RUN set -ex; \ + groupadd --gid ${ID} sequencer; \ + useradd --gid ${ID} --uid ${ID} --comment "" --create-home --home-dir /app sequencer; + +EXPOSE 9000 + +USER ${ID} + +ENTRYPOINT ["tini", "--", "/app/target/debug/dummy_eth_to_strk_oracle"] diff --git a/deployments/images/sequencer/dummy_recorder.Dockerfile b/deployments/images/sequencer/dummy_recorder.Dockerfile new file mode 100644 index 00000000000..97daffb721f --- /dev/null +++ b/deployments/images/sequencer/dummy_recorder.Dockerfile @@ -0,0 +1,37 @@ +# syntax = devthefuture/dockerfile-x +# deployments/images/sequencer/dummy_recorder.Dockerfile + +# Dockerfile with multi-stage builds for efficient dependency caching and lightweight final image. +# For more on Docker stages, visit: https://docs.docker.com/build/building/multi-stage/ +# We use dockerfile-x, for more information visit: https://github.com/devthefuture-org/dockerfile-x/blob/master/README.md + +INCLUDE deployments/images/base/Dockerfile + +FROM base AS planner +WORKDIR /app +COPY . . +RUN cargo chef prepare --recipe-path recipe.json + +FROM base AS builder +WORKDIR /app +COPY --from=planner /app/recipe.json recipe.json +RUN cargo chef cook --recipe-path recipe.json +COPY . . +RUN cargo build + +FROM ubuntu:24.04 AS final_stage + +ENV ID=1001 +WORKDIR /app +COPY --from=builder /app/target/debug/dummy_recorder ./target/debug/dummy_recorder +COPY --from=builder /usr/bin/tini /usr/bin/tini + +RUN set -ex; \ + groupadd --gid ${ID} sequencer; \ + useradd --gid ${ID} --uid ${ID} --comment "" --create-home --home-dir /app sequencer; + +EXPOSE 8080 + +USER ${ID} + +ENTRYPOINT ["tini", "--", "/app/target/debug/dummy_recorder"] diff --git a/deployments/images/sequencer/node_setup.Dockerfile b/deployments/images/sequencer/node_setup.Dockerfile new file mode 100644 index 00000000000..003940a25f4 --- /dev/null +++ b/deployments/images/sequencer/node_setup.Dockerfile @@ -0,0 +1,44 @@ +# syntax = devthefuture/dockerfile-x +# deployments/images/sequencer/node_setup.Dockerfile + +# Dockerfile with multi-stage builds for efficient dependency caching and lightweight final image. +# For more on Docker stages, visit: https://docs.docker.com/build/building/multi-stage/ +# We use dockerfile-x, for more information visit: https://github.com/devthefuture-org/dockerfile-x/blob/master/README.md + +INCLUDE deployments/images/base/Dockerfile + +FROM base AS planner +WORKDIR /app +COPY . . +RUN cargo chef prepare --recipe-path recipe.json + +FROM base AS builder +WORKDIR /app +RUN curl -L https://github.com/foundry-rs/foundry/releases/download/v0.3.0/foundry_v0.3.0_linux_amd64.tar.gz | tar -xz --wildcards 'anvil' +COPY --from=planner /app/recipe.json recipe.json +RUN cargo chef cook --recipe-path recipe.json +COPY . . +RUN cargo build + +FROM ubuntu:24.04 AS final_stage + +ENV ID=1001 +WORKDIR /app +# Required crate for sequencer_node_setup to work +COPY --from=builder /app/crates/blockifier_test_utils/resources ./crates/blockifier_test_utils/resources +COPY --from=builder /app/target/debug/sequencer_node_setup ./target/debug/sequencer_node_setup +COPY --from=builder /usr/bin/tini /usr/bin/tini +COPY --from=builder /app/anvil /usr/bin/anvil + +# Create a new user "sequencer". +RUN set -ex; \ + groupadd --gid ${ID} sequencer; \ + useradd --gid ${ID} --uid ${ID} --comment "" --create-home --home-dir /app sequencer; \ + mkdir -p /data /config; \ + chown -R sequencer:sequencer /app /data /config + +# Switch to the new user. +USER ${ID} + +# Set the entrypoint to use tini to manage the process. +ENTRYPOINT ["tini", "--", "/app/target/debug/sequencer_node_setup"] diff --git a/deployments/images/sequencer/simulator.Dockerfile b/deployments/images/sequencer/simulator.Dockerfile new file mode 100644 index 00000000000..49e90efc0f8 --- /dev/null +++ b/deployments/images/sequencer/simulator.Dockerfile @@ -0,0 +1,40 @@ +# syntax = devthefuture/dockerfile-x +# deployments/images/sequencer/simulator.Dockerfile + +# Dockerfile with multi-stage builds for efficient dependency caching and lightweight final image. +# For more on Docker stages, visit: https://docs.docker.com/build/building/multi-stage/ +# We use dockerfile-x, for more information visit: https://github.com/devthefuture-org/dockerfile-x/blob/master/README.md + +INCLUDE deployments/images/base/Dockerfile + +FROM base AS planner +WORKDIR /app +COPY . . +RUN cargo chef prepare --recipe-path recipe.json + +FROM base AS builder +WORKDIR /app +COPY --from=planner /app/recipe.json recipe.json +RUN cargo chef cook --recipe-path recipe.json +COPY . . +RUN cargo build + +FROM ubuntu:24.04 AS final_stage + +ENV ID=1001 +WORKDIR /app +COPY --from=builder /app/target/debug/sequencer_simulator ./target/debug/sequencer_simulator +COPY --from=builder /usr/bin/tini /usr/bin/tini + +# Create a new user "sequencer". +RUN set -ex; \ + groupadd --gid ${ID} sequencer; \ + useradd --gid ${ID} --uid ${ID} --comment "" --create-home --home-dir /app sequencer; \ + mkdir /data; \ + chown -R sequencer:sequencer /app /data + +# Switch to the new user. +USER ${ID} + +# Set the entrypoint to use tini to manage the process. +ENTRYPOINT ["tini", "--", "/app/target/debug/sequencer_simulator"] diff --git a/deployments/monitoring/Pipfile b/deployments/monitoring/Pipfile new file mode 100644 index 00000000000..8e9ee394092 --- /dev/null +++ b/deployments/monitoring/Pipfile @@ -0,0 +1,13 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[dev-packages] + +[packages] +grafanalib = "~=0.7.1" +requests = "*" + +[requires] +python_version = "3.10" diff --git a/deployments/monitoring/Pipfile.lock b/deployments/monitoring/Pipfile.lock new file mode 100644 index 00000000000..78293f1d27a --- /dev/null +++ b/deployments/monitoring/Pipfile.lock @@ -0,0 +1,168 @@ +{ + "_meta": { + "hash": { + "sha256": "407568b0be8e7944944aa478f87d59a4342e474771b01b3889d906871971500b" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.10" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "attrs": { + "hashes": [ + "sha256:1c97078a80c814273a76b2a298a932eb681c87415c11dee0a6921de7f1b02c3e", + "sha256:c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a" + ], + "markers": "python_version >= '3.8'", + "version": "==25.1.0" + }, + "certifi": { + "hashes": [ + "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651", + "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe" + ], + "markers": "python_version >= '3.6'", + "version": "==2025.1.31" + }, + "charset-normalizer": { + "hashes": [ + "sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537", + "sha256:01732659ba9b5b873fc117534143e4feefecf3b2078b0a6a2e925271bb6f4cfa", + "sha256:01ad647cdd609225c5350561d084b42ddf732f4eeefe6e678765636791e78b9a", + "sha256:04432ad9479fa40ec0f387795ddad4437a2b50417c69fa275e212933519ff294", + "sha256:0907f11d019260cdc3f94fbdb23ff9125f6b5d1039b76003b5b0ac9d6a6c9d5b", + "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd", + "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601", + "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd", + "sha256:0af291f4fe114be0280cdd29d533696a77b5b49cfde5467176ecab32353395c4", + "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d", + "sha256:1a2bc9f351a75ef49d664206d51f8e5ede9da246602dc2d2726837620ea034b2", + "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313", + "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd", + "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa", + "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8", + "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1", + "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2", + "sha256:2a75d49014d118e4198bcee5ee0a6f25856b29b12dbf7cd012791f8a6cc5c496", + "sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d", + "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b", + "sha256:2fb9bd477fdea8684f78791a6de97a953c51831ee2981f8e4f583ff3b9d9687e", + "sha256:311f30128d7d333eebd7896965bfcfbd0065f1716ec92bd5638d7748eb6f936a", + "sha256:329ce159e82018d646c7ac45b01a430369d526569ec08516081727a20e9e4af4", + "sha256:345b0426edd4e18138d6528aed636de7a9ed169b4aaf9d61a8c19e39d26838ca", + "sha256:363e2f92b0f0174b2f8238240a1a30142e3db7b957a5dd5689b0e75fb717cc78", + "sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408", + "sha256:3bed14e9c89dcb10e8f3a29f9ccac4955aebe93c71ae803af79265c9ca5644c5", + "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3", + "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f", + "sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a", + "sha256:49402233c892a461407c512a19435d1ce275543138294f7ef013f0b63d5d3765", + "sha256:4c0907b1928a36d5a998d72d64d8eaa7244989f7aaaf947500d3a800c83a3fd6", + "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146", + "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6", + "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9", + "sha256:619a609aa74ae43d90ed2e89bdd784765de0a25ca761b93e196d938b8fd1dbbd", + "sha256:6e27f48bcd0957c6d4cb9d6fa6b61d192d0b13d5ef563e5f2ae35feafc0d179c", + "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f", + "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545", + "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176", + "sha256:75832c08354f595c760a804588b9357d34ec00ba1c940c15e31e96d902093770", + "sha256:7709f51f5f7c853f0fb938bcd3bc59cdfdc5203635ffd18bf354f6967ea0f824", + "sha256:78baa6d91634dfb69ec52a463534bc0df05dbd546209b79a3880a34487f4b84f", + "sha256:7974a0b5ecd505609e3b19742b60cee7aa2aa2fb3151bc917e6e2646d7667dcf", + "sha256:7a4f97a081603d2050bfaffdefa5b02a9ec823f8348a572e39032caa8404a487", + "sha256:7b1bef6280950ee6c177b326508f86cad7ad4dff12454483b51d8b7d673a2c5d", + "sha256:7d053096f67cd1241601111b698f5cad775f97ab25d81567d3f59219b5f1adbd", + "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b", + "sha256:807f52c1f798eef6cf26beb819eeb8819b1622ddfeef9d0977a8502d4db6d534", + "sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f", + "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b", + "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9", + "sha256:89149166622f4db9b4b6a449256291dc87a99ee53151c74cbd82a53c8c2f6ccd", + "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125", + "sha256:8c60ca7339acd497a55b0ea5d506b2a2612afb2826560416f6894e8b5770d4a9", + "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de", + "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11", + "sha256:97f68b8d6831127e4787ad15e6757232e14e12060bec17091b85eb1486b91d8d", + "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35", + "sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f", + "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda", + "sha256:ab36c8eb7e454e34e60eb55ca5d241a5d18b2c6244f6827a30e451c42410b5f7", + "sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a", + "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971", + "sha256:b7b2d86dd06bfc2ade3312a83a5c364c7ec2e3498f8734282c6c3d4b07b346b8", + "sha256:b97e690a2118911e39b4042088092771b4ae3fc3aa86518f84b8cf6888dbdb41", + "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d", + "sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f", + "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757", + "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a", + "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886", + "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77", + "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76", + "sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247", + "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85", + "sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb", + "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7", + "sha256:dccbe65bd2f7f7ec22c4ff99ed56faa1e9f785482b9bbd7c717e26fd723a1d1e", + "sha256:dd78cfcda14a1ef52584dbb008f7ac81c1328c0f58184bf9a84c49c605002da6", + "sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037", + "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1", + "sha256:ea0d8d539afa5eb2728aa1932a988a9a7af94f18582ffae4bc10b3fbdad0626e", + "sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807", + "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407", + "sha256:ecddf25bee22fe4fe3737a399d0d177d72bc22be6913acfab364b40bce1ba83c", + "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12", + "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3", + "sha256:f30bf9fd9be89ecb2360c7d94a711f00c09b976258846efe40db3d05828e8089", + "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd", + "sha256:fc54db6c8593ef7d4b2a331b58653356cf04f67c960f584edb7c3d8c97e8f39e", + "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00", + "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616" + ], + "markers": "python_version >= '3.7'", + "version": "==3.4.1" + }, + "grafanalib": { + "hashes": [ + "sha256:3d92bb4e92ae78fe4e21c5b252ab51f4fdcacd8523ba5a44545b897b2a375b83", + "sha256:6fab5d7b837a1f2d1322ef762cd52e565ec0422707a7512765c59f668bdceb58" + ], + "index": "pypi", + "version": "==0.7.1" + }, + "idna": { + "hashes": [ + "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", + "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3" + ], + "markers": "python_version >= '3.6'", + "version": "==3.10" + }, + "requests": { + "hashes": [ + "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", + "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==2.32.3" + }, + "urllib3": { + "hashes": [ + "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", + "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d" + ], + "markers": "python_version >= '3.9'", + "version": "==2.3.0" + } + }, + "develop": {} +} diff --git a/deployments/monitoring/README.md b/deployments/monitoring/README.md new file mode 100644 index 00000000000..b227298716d --- /dev/null +++ b/deployments/monitoring/README.md @@ -0,0 +1,49 @@ +# Local Monitoring Stack + +### Requirements: +- Python3 +- docker >= 27.3.1 - (installation guide https://docs.docker.com/engine/install/ubuntu/) + +### Setup: +```bash +python3 -m venv monitoring_venv +source monitoring_venv/bin/activate +``` + +### Start up: +To run with docker cache: +```bash +./deployments/monitoring/deploy_local_stack.sh up -d +``` + +To force build (useful to enforce applying changes in docker file settings): +```bash +./deployments/monitoring/deploy_local_stack.sh up -d --build +``` + +## This will deploy a local stack of: +- Sequencer Node Setup +- Sequencer Node (using a config generated by **Sequencer Node Setup**.) +- Sequencer Node Simulator +- Dummy Cende Recorder +- Prometheus +- Grafana (Using: [dev_grafana.json](../../Monitoring/sequencer/dev_grafana.json) dashboard.) + +Once the node starts emitting logs, one can ctrl+c to move the run to the background. + +## Open Grafana: +After Grafana starts running, it can be viewed by accessing http://localhost:3000 in a web browser. + +## Troubleshooting +If encountering `Failed to deploy the monitoring stack locally`, verify the docker version is adequate: +``` +docker --version +docker compose --version +``` + +## Shutdown & Cleanup: +```bash +./deployments/monitoring/deploy_local_stack.sh down -v +deactivate +rm -rf monitoring_venv +``` diff --git a/deployments/monitoring/deploy_local_stack.sh b/deployments/monitoring/deploy_local_stack.sh new file mode 100755 index 00000000000..55b1ff7470c --- /dev/null +++ b/deployments/monitoring/deploy_local_stack.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +DOCKER_BUILDKIT=1 +COMPOSE_DOCKER_CLI_BUILD=1 + +export DOCKER_BUILDKIT +export COMPOSE_DOCKER_CLI_BUILD +export MONITORING_ENABLED=${MONITORING_ENABLED:-true} +export FOLLOW_LOGS=${FOLLOW_LOGS:-true} + +monitoring_dir=$(dirname -- "$(readlink -f -- "${BASH_SOURCE[0]}")") +export monitoring_dir + +if command -v docker compose &> /dev/null; then + docker_compose="docker compose" +elif command -v docker-compose &> /dev/null; then + docker_compose="docker-compose" +else + echo "Error: docker compose is missing, please install and try again. Official docs: https://docs.docker.com/compose/install/linux/" + exit 1 +fi + +if [ "$MONITORING_ENABLED" != true ]; then + services="sequencer_node_setup dummy_recorder dummy_eth_to_strk_oracle config_injector sequencer_node sequencer_simulator" +fi + +echo "Running: ${docker_compose} -f ${monitoring_dir}/local/docker-compose.yml $*" +${docker_compose} -f "${monitoring_dir}"/local/docker-compose.yml "$@" ${services} +ret=$? + +if [ "$ret" -ne 0 ]; then + echo "Failed to deploy the monitoring stack locally" + exit 1 +fi + +if [ "$1" == "down" ]; then + exit "$ret" +fi + +if [ "$MONITORING_ENABLED" == true ]; then + pip install -r "${monitoring_dir}"/src/requirements.txt + python "${monitoring_dir}"/src/dashboard_builder.py builder -j "${monitoring_dir}"/../../Monitoring/sequencer/dev_grafana.json -o /tmp/dashboard_builder -d -u +fi + +if [ "$FOLLOW_LOGS" == true ]; then + ${docker_compose} -f "${monitoring_dir}"/local/docker-compose.yml logs -f +fi diff --git a/deployments/monitoring/local/.env b/deployments/monitoring/local/.env new file mode 100644 index 00000000000..1bcc0842da6 --- /dev/null +++ b/deployments/monitoring/local/.env @@ -0,0 +1,7 @@ +DATA_VOLUME_MOUNT_PATH=/data +SEQUENCER_ROOT_DIR=${monitoring_dir}/../../ +SEQUENCER_CONFIG_SOURCE_PATH=${SEQUENCER_ROOT_DIR}/config/sequencer/presets/system_test_presets/single_node/node_0/executable_0/node_config.json +SEQUENCER_CONFIG_PATH=/config/node_config.json +SEQUENCER_HTTP_PORT=8081 +SEQUENCER_MONITORING_PORT=8082 +SIMULATOR_RUN_FOREVER=true diff --git a/deployments/monitoring/local/config/grafana/datasources/datasources.yml b/deployments/monitoring/local/config/grafana/datasources/datasources.yml new file mode 100644 index 00000000000..e42a563d966 --- /dev/null +++ b/deployments/monitoring/local/config/grafana/datasources/datasources.yml @@ -0,0 +1,17 @@ +apiVersion: 1 + +datasources: + - name: Prometheus + type: prometheus + access: proxy + isDefault: true + # Access mode - proxy (server in the UI) or direct (browser in the UI). + url: http://prometheus:9090 + jsonData: + httpMethod: POST + manageAlerts: true + prometheusType: Prometheus + prometheusVersion: 2.44.0 + cacheLevel: 'High' + disableRecordingRules: false + incrementalQueryOverlapWindow: 10m diff --git a/deployments/monitoring/local/config/prometheus/prometheus.yml b/deployments/monitoring/local/config/prometheus/prometheus.yml new file mode 100644 index 00000000000..87afb99c8aa --- /dev/null +++ b/deployments/monitoring/local/config/prometheus/prometheus.yml @@ -0,0 +1,12 @@ +global: + scrape_interval: 5s +scrape_configs: + - job_name: prometheus + static_configs: + - targets: + - prometheus:9090 + - job_name: node + metrics_path: /monitoring/metrics + static_configs: + - targets: + - sequencer_node:8082 diff --git a/deployments/monitoring/local/docker-compose.yml b/deployments/monitoring/local/docker-compose.yml new file mode 100644 index 00000000000..1eca8713c67 --- /dev/null +++ b/deployments/monitoring/local/docker-compose.yml @@ -0,0 +1,131 @@ +services: + prometheus: + image: prom/prometheus + ports: + - "9090:9090" + volumes: + - ${monitoring_dir}/local/config/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml + networks: + - sequencer-network + + grafana: + image: grafana/grafana:10.4.14-ubuntu + environment: + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + ports: + - "3000:3000" + volumes: + - ${monitoring_dir}/local/config/grafana/datasources:/etc/grafana/provisioning/datasources + networks: + - sequencer-network + + sequencer_node_setup: + build: + context: ${SEQUENCER_ROOT_DIR} + dockerfile: ${SEQUENCER_ROOT_DIR}/deployments/images/sequencer/node_setup.Dockerfile + entrypoint: "/bin/bash -c" + command: > + "./target/debug/sequencer_node_setup --output-base-dir ./output --data-prefix-path /data --n-distributed 0 --n-consolidated 1; + cp -r ./output/data/* /data" + volumes: + - data:/data + networks: + - sequencer-network + + dummy_recorder: + depends_on: + - sequencer_node_setup + build: + context: ${SEQUENCER_ROOT_DIR} + dockerfile: ${SEQUENCER_ROOT_DIR}/deployments/images/sequencer/dummy_recorder.Dockerfile + ports: + - "8080:8080" + networks: + - sequencer-network + + dummy_eth_to_strk_oracle: + depends_on: + - sequencer_node_setup + build: + context: ${SEQUENCER_ROOT_DIR} + dockerfile: ${SEQUENCER_ROOT_DIR}/deployments/images/sequencer/dummy_eth_to_strk_oracle.Dockerfile + ports: + - "9000:9000" + networks: + - sequencer-network + + config_injector: + depends_on: + sequencer_node_setup: + condition: service_completed_successfully + image: ubuntu:24.04 + entrypoint: "/bin/bash -c" + command: | + "DEBIAN_FRONTEND=noninteractive \ + apt update && \ + apt install -y jq moreutils && \ + cp /tmp/node_config.json ${SEQUENCER_CONFIG_PATH} \ + echo 'Injecting config changes...' && \ + jq '.\"recorder_url\" = \"http://dummy_recorder:8080\"' ${SEQUENCER_CONFIG_PATH} | sponge ${SEQUENCER_CONFIG_PATH} && \ + jq '.\"consensus_manager_config.eth_to_strk_oracle_config.base_url\" = \"http://dummy_eth_to_strk_oracle:9000/eth_to_strk_oracle?timestamp=\"' ${SEQUENCER_CONFIG_PATH} | sponge ${SEQUENCER_CONFIG_PATH} && \ + jq '.\"http_server_config.ip\" = \"0.0.0.0\"' ${SEQUENCER_CONFIG_PATH} | sponge ${SEQUENCER_CONFIG_PATH} && \ + jq '.\"http_server_config.port\" = ${SEQUENCER_HTTP_PORT}' ${SEQUENCER_CONFIG_PATH} | sponge ${SEQUENCER_CONFIG_PATH} && \ + jq '.\"monitoring_endpoint_config.port\" = ${SEQUENCER_MONITORING_PORT}' ${SEQUENCER_CONFIG_PATH} | sponge ${SEQUENCER_CONFIG_PATH} && \ + jq '.\"components.l1_scraper.execution_mode\" = \"Disabled\"' ${SEQUENCER_CONFIG_PATH} | sponge ${SEQUENCER_CONFIG_PATH} && \ + jq '.\"components.l1_gas_price_scraper.execution_mode\" = \"Disabled\"' ${SEQUENCER_CONFIG_PATH} | sponge ${SEQUENCER_CONFIG_PATH} && \ + echo 'Done'" + volumes: + - ${SEQUENCER_CONFIG_SOURCE_PATH}:/tmp/node_config.json + - config:/config + networks: + - sequencer-network + + sequencer_node: + depends_on: + config_injector: + condition: service_completed_successfully + dummy_recorder: + condition: service_started + sequencer_node_setup: + condition: service_completed_successfully + build: + context: ${SEQUENCER_ROOT_DIR} + dockerfile: ${SEQUENCER_ROOT_DIR}/deployments/images/sequencer/Dockerfile + ports: + - ${SEQUENCER_HTTP_PORT}:${SEQUENCER_HTTP_PORT} + - ${SEQUENCER_MONITORING_PORT}:${SEQUENCER_MONITORING_PORT} + command: + - "--config_file" + - "${SEQUENCER_CONFIG_PATH}" + volumes: + - data:/data + - config:/config + networks: + - sequencer-network + + sequencer_simulator: + depends_on: + - sequencer_node + build: + context: ${SEQUENCER_ROOT_DIR} + dockerfile: ${SEQUENCER_ROOT_DIR}/deployments/images/sequencer/simulator.Dockerfile + entrypoint: "/bin/bash -c" + command: > + "./target/debug/sequencer_simulator \ + --http-url http://sequencer_node \ + --http-port ${SEQUENCER_HTTP_PORT} \ + --monitoring-url http://sequencer_node \ + --monitoring-port ${SEQUENCER_MONITORING_PORT} \ + $(if [ \"$SIMULATOR_RUN_FOREVER\" = \"true\" ]; then echo '--run-forever'; fi)" + networks: + - sequencer-network + +volumes: + data: + config: + +networks: + sequencer-network: + driver: bridge diff --git a/deployments/monitoring/src/dashboard_builder.py b/deployments/monitoring/src/dashboard_builder.py new file mode 100755 index 00000000000..89dc2f45cd0 --- /dev/null +++ b/deployments/monitoring/src/dashboard_builder.py @@ -0,0 +1,166 @@ +import click +import logging +import datetime +import json +import os +import requests +import time + +from grafana10_objects import empty_dashboard, row_object + + +def create_grafana_panel( + panel: dict, panel_id: int, y_position: int, x_position: int +) -> dict: + grafana_panel = { + "id": panel_id, + "type": panel["type"], + "title": panel["title"], + "description": panel.get("description", ""), + "gridPos": {"h": 6, "w": 12, "x": x_position, "y": y_position}, + "targets": [ + { + "expr": panel["expr"] if isinstance(panel["expr"], str) else None, + "refId": chr(65 + panel_id % 26), + } + ], + "fieldConfig": { + "defaults": { + "unit": "none", + "thresholds": { + "mode": "absolute", + "steps": [ + {"color": "green", "value": None}, + {"color": "orange", "value": 70}, + {"color": "red", "value": 90}, + ], + }, + } + }, + } + return grafana_panel + + +def get_next_position(x_position, y_position): + """Helper function to calculate next position for the panel.""" + panel_grid_pos_width = 12 + + if x_position == panel_grid_pos_width: + x_position = 0 + y_position += 6 + else: + x_position += panel_grid_pos_width + + return x_position, y_position + + +def create_dashboard(dashboard_name: str, dev_dashboard: json) -> dict: + dashboard = empty_dashboard.copy() + panel_id = 1 + x_position = 0 + y_position = 0 + dashboard["title"] = dashboard_name + + for row_title, panels in dev_dashboard.items(): + row_panel = row_object.copy() + row_panel["title"] = row_title + row_panel["id"] = panel_id + row_panel["gridPos"]["y"] = y_position + row_panel["panels"] = [] + panel_id += 1 + x_position = 0 + y_position += 1 + dashboard["panels"].append(row_panel) + + for panel in panels: + grafana_panel = create_grafana_panel( + panel, panel_id, y_position, x_position + ) + row_panel["panels"].append(grafana_panel) + panel_id += 1 + x_position, y_position = get_next_position(x_position, y_position) + + return {"dashboard": dashboard} + + +def upload_dashboards_local(dashboard: dict) -> None: + retry = 0 + + while retry <= 10: + try: + res = requests.post( + "http://localhost:3000/api/dashboards/db", + json={**dashboard, **{"overwrite": True}}, + ) + if res.status_code != 200: + print(f"Failed to upload dashboard. {res.json()}") + break + print("Dashboard uploaded successfully.") + print( + f"you can view the dashboard at: http://localhost:3000{res.json()['url']}" + ) + break + except requests.exceptions.ConnectionError: + print("Grafana is not ready yet. Retrying...") + retry += 1 + time.sleep(5) + continue + + +@click.group() +def cli(): + pass + + +@cli.command() +@click.option("-j", "--dev_json_file", default="./dev_dashboard.json") +@click.option("-d", "--debug", is_flag=True, default=False) +@click.option("-u", "--upload", is_flag=True, default=False) +@click.option("-o", "--out_dir", default="./out") +def builder(dev_json_file, out_dir, upload, debug) -> None: + dashboards = [] + + # Logging + if debug: + logging.basicConfig( + level=logging.DEBUG, format="%(asctime)s - %(levelname)s - %(message)s" + ) + else: + logging.basicConfig( + level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s" + ) + start_time = datetime.datetime.now() + logging.info( + f'Starting to build grafana dashboard, time is {start_time.strftime("%Y-%m-%d %H:%M:%S")}' + ) + + # Load json file + with open(dev_json_file, "r") as f: + dev_json = json.load(f) + + for dashboard_name in dev_json.keys(): + dashboards.append( + [ + dashboard_name, + create_dashboard( + dashboard_name=dashboard_name, + dev_dashboard=dev_json[dashboard_name], + ), + ] + ) + print(dashboards) + + # Write the grafana dashboard + os.makedirs(out_dir, exist_ok=True) + for dashboard_name, dashboard in dashboards: + with open(f"{out_dir}/{dashboard_name}.json", "w") as f: + json.dump(dashboard, f, indent=4) + if upload: + upload_dashboards_local(dashboard=dashboard) + logging.info( + f'Done building grafana dashabord, time is {datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")}' + ) + + +if __name__ == "__main__": + cli() diff --git a/deployments/monitoring/src/grafana10_objects.py b/deployments/monitoring/src/grafana10_objects.py new file mode 100644 index 00000000000..6efa678b167 --- /dev/null +++ b/deployments/monitoring/src/grafana10_objects.py @@ -0,0 +1,54 @@ +empty_dashboard = { + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": True, + "hide": True, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": True, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "links": [], + "liveNow": False, + "panels": [], + "refresh": "5s", + "schemaVersion": 38, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "New dashboard", + "version": 0, + "weekStart": "" +} + +row_object = { + "collapsed": True, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 1, + "panels": [], + "title": "Row title 1", + "type": "row" +} diff --git a/deployments/monitoring/src/requirements.txt b/deployments/monitoring/src/requirements.txt new file mode 100644 index 00000000000..0d8c96eb77d --- /dev/null +++ b/deployments/monitoring/src/requirements.txt @@ -0,0 +1,2 @@ +click +requests diff --git a/deployments/papyrus/helm/config/example.json b/deployments/papyrus/helm/config/example.json index d9cef9180b7..c7db3e7f304 100644 --- a/deployments/papyrus/helm/config/example.json +++ b/deployments/papyrus/helm/config/example.json @@ -1,6 +1,6 @@ { "base_layer.node_url": "", - "network.tcp_port": 10000, + "network.port": 10000, "storage.db_config.path_prefix": "./data", "network.#is_none": false, "storage.scope": "FullArchive", diff --git a/deployments/papyrus/install_papyrus.py b/deployments/papyrus/install_papyrus.py index 69ea8cf3134..cfabd813d3c 100644 --- a/deployments/papyrus/install_papyrus.py +++ b/deployments/papyrus/install_papyrus.py @@ -8,7 +8,7 @@ GRAFANA_DASHBOARD_DESTINATION_FILE_PATH = "helm/Monitoring/grafana_dashboard.json" GRAFANA_ALERTS_DESTINATION_FILE_PATH = "helm/Monitoring/grafana_alerts.json" -# TODO: Add function to deploy monitoring dashboard. +# TODO(AlonDo): Add function to deploy monitoring dashboard. def parse_command_line_args(): parser = argparse.ArgumentParser(description="Install Papyrus node.") parser.add_argument("--release_name", type=str, required=True, help="Name for the helm release.") diff --git a/deployments/sequencer/.gitignore b/deployments/sequencer/.gitignore new file mode 100644 index 00000000000..dc0d6d7d379 --- /dev/null +++ b/deployments/sequencer/.gitignore @@ -0,0 +1,4 @@ +__pycache__/ +.idea/ +dist/ +imports/ diff --git a/deployments/sequencer/Pipfile b/deployments/sequencer/Pipfile index 981f62bbacf..abbb23c0b29 100644 --- a/deployments/sequencer/Pipfile +++ b/deployments/sequencer/Pipfile @@ -12,6 +12,7 @@ jsonschema = "~=4.23.0" exceptiongroup = "~=1.2.2" types-jsonschema = "*" mypy = "*" +black = "*" [requires] python_version = "3.10" diff --git a/deployments/sequencer/Pipfile.lock b/deployments/sequencer/Pipfile.lock index 2ec0a9b17a5..cbb2fb1c92a 100644 --- a/deployments/sequencer/Pipfile.lock +++ b/deployments/sequencer/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "285f4cd049b0929cb9456557aa88d520b18a14269a94291e3841af3ac4225304" + "sha256": "01419af2858671b702f87120feb7b3f3cbe6dc275f21415dc12463ed2218e92f" }, "pipfile-spec": 6, "requires": { @@ -18,11 +18,40 @@ "default": { "attrs": { "hashes": [ - "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346", - "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2" + "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", + "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b" ], - "markers": "python_version >= '3.7'", - "version": "==24.2.0" + "markers": "python_version >= '3.8'", + "version": "==25.3.0" + }, + "black": { + "hashes": [ + "sha256:030b9759066a4ee5e5aca28c3c77f9c64789cdd4de8ac1df642c40b708be6171", + "sha256:055e59b198df7ac0b7efca5ad7ff2516bca343276c466be72eb04a3bcc1f82d7", + "sha256:0e519ecf93120f34243e6b0054db49c00a35f84f195d5bce7e9f5cfc578fc2da", + "sha256:172b1dbff09f86ce6f4eb8edf9dede08b1fce58ba194c87d7a4f1a5aa2f5b3c2", + "sha256:1e2978f6df243b155ef5fa7e558a43037c3079093ed5d10fd84c43900f2d8ecc", + "sha256:33496d5cd1222ad73391352b4ae8da15253c5de89b93a80b3e2c8d9a19ec2666", + "sha256:3b48735872ec535027d979e8dcb20bf4f70b5ac75a8ea99f127c106a7d7aba9f", + "sha256:4b60580e829091e6f9238c848ea6750efed72140b91b048770b64e74fe04908b", + "sha256:759e7ec1e050a15f89b770cefbf91ebee8917aac5c20483bc2d80a6c3a04df32", + "sha256:8f0b18a02996a836cc9c9c78e5babec10930862827b1b724ddfe98ccf2f2fe4f", + "sha256:95e8176dae143ba9097f351d174fdaf0ccd29efb414b362ae3fd72bf0f710717", + "sha256:96c1c7cd856bba8e20094e36e0f948718dc688dba4a9d78c3adde52b9e6c2299", + "sha256:a1ee0a0c330f7b5130ce0caed9936a904793576ef4d2b98c40835d6a65afa6a0", + "sha256:a22f402b410566e2d1c950708c77ebf5ebd5d0d88a6a2e87c86d9fb48afa0d18", + "sha256:a39337598244de4bae26475f77dda852ea00a93bd4c728e09eacd827ec929df0", + "sha256:afebb7098bfbc70037a053b91ae8437c3857482d3a690fefc03e9ff7aa9a5fd3", + "sha256:bacabb307dca5ebaf9c118d2d2f6903da0d62c9faa82bd21a33eecc319559355", + "sha256:bce2e264d59c91e52d8000d507eb20a9aca4a778731a08cfff7e5ac4a4bb7096", + "sha256:d9e6827d563a2c820772b32ce8a42828dc6790f095f441beef18f96aa6f8294e", + "sha256:db8ea9917d6f8fc62abd90d944920d95e73c83a5ee3383493e35d271aca872e9", + "sha256:ea0213189960bda9cf99be5b8c8ce66bb054af5e9e861249cd23471bd7b0b3ba", + "sha256:f3df5f1bf91d36002b0a75389ca8663510cf0531cca8aa5c1ef695b46d98655f" + ], + "index": "pypi", + "markers": "python_version >= '3.9'", + "version": "==25.1.0" }, "cattrs": { "hashes": [ @@ -41,6 +70,14 @@ "markers": "python_version ~= '3.7'", "version": "==2.66.13" }, + "click": { + "hashes": [ + "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", + "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a" + ], + "markers": "python_version >= '3.7'", + "version": "==8.1.8" + }, "constructs": { "hashes": [ "sha256:ade1b5224830e78724ed50ce91ec2e6ce437c9983713c2b8ca541272283c5d37", @@ -61,19 +98,19 @@ }, "importlib-resources": { "hashes": [ - "sha256:980862a1d16c9e147a59603677fa2aa5fd82b87f223b6cb870695bcfce830065", - "sha256:ac29d5f956f01d5e4bb63102a5a19957f1b9175e45649977264a1416783bb717" + "sha256:185f87adef5bcc288449d98fb4fba07cea78bc036455dd44c5fc4a2fe78fed2c", + "sha256:789cfdc3ed28c78b67a06acb8126751ced69a3d5f79c095a98298cd8a760ccec" ], - "markers": "python_version >= '3.8'", - "version": "==6.4.5" + "markers": "python_version >= '3.9'", + "version": "==6.5.2" }, "jsii": { "hashes": [ - "sha256:435682d509e628e6f8a765b017102e6fcd553f4d0f6b3417b3f7eb295c2e0d1f", - "sha256:8888088479b449db6d8e3a7df25434ec4580bf4fc13f4f952e9db5f2a3fc0c0f" + "sha256:100bb48c7f74b8e22b3182c5466db1c32565ddb681ed5e2bf556076a734d3f07", + "sha256:85e0deca8089e2918776541e986d5abab90a66d4330eedfc14e8a060dd507bad" ], - "markers": "python_version ~= '3.8'", - "version": "==1.105.0" + "markers": "python_version ~= '3.9'", + "version": "==1.109.0" }, "jsonschema": { "hashes": [ @@ -94,42 +131,42 @@ }, "mypy": { "hashes": [ - "sha256:0246bcb1b5de7f08f2826451abd947bf656945209b140d16ed317f65a17dc7dc", - "sha256:0291a61b6fbf3e6673e3405cfcc0e7650bebc7939659fdca2702958038bd835e", - "sha256:0730d1c6a2739d4511dc4253f8274cdd140c55c32dfb0a4cf8b7a43f40abfa6f", - "sha256:07de989f89786f62b937851295ed62e51774722e5444a27cecca993fc3f9cd74", - "sha256:100fac22ce82925f676a734af0db922ecfea991e1d7ec0ceb1e115ebe501301a", - "sha256:164f28cb9d6367439031f4c81e84d3ccaa1e19232d9d05d37cb0bd880d3f93c2", - "sha256:20c7ee0bc0d5a9595c46f38beb04201f2620065a93755704e141fcac9f59db2b", - "sha256:3790ded76f0b34bc9c8ba4def8f919dd6a46db0f5a6610fb994fe8efdd447f73", - "sha256:39bb21c69a5d6342f4ce526e4584bc5c197fd20a60d14a8624d8743fffb9472e", - "sha256:3ddb5b9bf82e05cc9a627e84707b528e5c7caaa1c55c69e175abb15a761cec2d", - "sha256:3e38b980e5681f28f033f3be86b099a247b13c491f14bb8b1e1e134d23bb599d", - "sha256:4bde84334fbe19bad704b3f5b78c4abd35ff1026f8ba72b29de70dda0916beb6", - "sha256:51f869f4b6b538229c1d1bcc1dd7d119817206e2bc54e8e374b3dfa202defcca", - "sha256:581665e6f3a8a9078f28d5502f4c334c0c8d802ef55ea0e7276a6e409bc0d82d", - "sha256:5c7051a3461ae84dfb5dd15eff5094640c61c5f22257c8b766794e6dd85e72d5", - "sha256:5d5092efb8516d08440e36626f0153b5006d4088c1d663d88bf79625af3d1d62", - "sha256:6607e0f1dd1fb7f0aca14d936d13fd19eba5e17e1cd2a14f808fa5f8f6d8f60a", - "sha256:7029881ec6ffb8bc233a4fa364736789582c738217b133f1b55967115288a2bc", - "sha256:7b2353a44d2179846a096e25691d54d59904559f4232519d420d64da6828a3a7", - "sha256:7bcb0bb7f42a978bb323a7c88f1081d1b5dee77ca86f4100735a6f541299d8fb", - "sha256:7bfd8836970d33c2105562650656b6846149374dc8ed77d98424b40b09340ba7", - "sha256:7f5b7deae912cf8b77e990b9280f170381fdfbddf61b4ef80927edd813163732", - "sha256:8a21be69bd26fa81b1f80a61ee7ab05b076c674d9b18fb56239d72e21d9f4c80", - "sha256:9c250883f9fd81d212e0952c92dbfcc96fc237f4b7c92f56ac81fd48460b3e5a", - "sha256:9f73dba9ec77acb86457a8fc04b5239822df0c14a082564737833d2963677dbc", - "sha256:a0affb3a79a256b4183ba09811e3577c5163ed06685e4d4b46429a271ba174d2", - "sha256:a4c1bfcdbce96ff5d96fc9b08e3831acb30dc44ab02671eca5953eadad07d6d0", - "sha256:a6789be98a2017c912ae6ccb77ea553bbaf13d27605d2ca20a76dfbced631b24", - "sha256:a7b44178c9760ce1a43f544e595d35ed61ac2c3de306599fa59b38a6048e1aa7", - "sha256:bde31fc887c213e223bbfc34328070996061b0833b0a4cfec53745ed61f3519b", - "sha256:c5fc54dbb712ff5e5a0fca797e6e0aa25726c7e72c6a5850cfd2adbc1eb0a372", - "sha256:de2904956dac40ced10931ac967ae63c5089bd498542194b436eb097a9f77bc8" + "sha256:1124a18bc11a6a62887e3e137f37f53fbae476dc36c185d549d4f837a2a6a14e", + "sha256:171a9ca9a40cd1843abeca0e405bc1940cd9b305eaeea2dda769ba096932bb22", + "sha256:1905f494bfd7d85a23a88c5d97840888a7bd516545fc5aaedff0267e0bb54e2f", + "sha256:1fbb8da62dc352133d7d7ca90ed2fb0e9d42bb1a32724c287d3c76c58cbaa9c2", + "sha256:2922d42e16d6de288022e5ca321cd0618b238cfc5570e0263e5ba0a77dbef56f", + "sha256:2e2c2e6d3593f6451b18588848e66260ff62ccca522dd231cd4dd59b0160668b", + "sha256:2ee2d57e01a7c35de00f4634ba1bbf015185b219e4dc5909e281016df43f5ee5", + "sha256:2f2147ab812b75e5b5499b01ade1f4a81489a147c01585cda36019102538615f", + "sha256:404534629d51d3efea5c800ee7c42b72a6554d6c400e6a79eafe15d11341fd43", + "sha256:5469affef548bd1895d86d3bf10ce2b44e33d86923c29e4d675b3e323437ea3e", + "sha256:5a95fb17c13e29d2d5195869262f8125dfdb5c134dc8d9a9d0aecf7525b10c2c", + "sha256:6983aae8b2f653e098edb77f893f7b6aca69f6cffb19b2cc7443f23cce5f4828", + "sha256:712e962a6357634fef20412699a3655c610110e01cdaa6180acec7fc9f8513ba", + "sha256:8023ff13985661b50a5928fc7a5ca15f3d1affb41e5f0a9952cb68ef090b31ee", + "sha256:811aeccadfb730024c5d3e326b2fbe9249bb7413553f15499a4050f7c30e801d", + "sha256:8f8722560a14cde92fdb1e31597760dc35f9f5524cce17836c0d22841830fd5b", + "sha256:93faf3fdb04768d44bf28693293f3904bbb555d076b781ad2530214ee53e3445", + "sha256:973500e0774b85d9689715feeffcc980193086551110fd678ebe1f4342fb7c5e", + "sha256:979e4e1a006511dacf628e36fadfecbcc0160a8af6ca7dad2f5025529e082c13", + "sha256:98b7b9b9aedb65fe628c62a6dc57f6d5088ef2dfca37903a7d9ee374d03acca5", + "sha256:aea39e0583d05124836ea645f412e88a5c7d0fd77a6d694b60d9b6b2d9f184fd", + "sha256:b9378e2c00146c44793c98b8d5a61039a048e31f429fb0eb546d93f4b000bedf", + "sha256:baefc32840a9f00babd83251560e0ae1573e2f9d1b067719479bfb0e987c6357", + "sha256:be68172e9fd9ad8fb876c6389f16d1c1b5f100ffa779f77b1fb2176fcc9ab95b", + "sha256:c43a7682e24b4f576d93072216bf56eeff70d9140241f9edec0c104d0c515036", + "sha256:c4bb0e1bd29f7d34efcccd71cf733580191e9a264a2202b0239da95984c5b559", + "sha256:c7be1e46525adfa0d97681432ee9fcd61a3964c2446795714699a998d193f1a3", + "sha256:c9817fa23833ff189db061e6d2eff49b2f3b6ed9856b4a0a73046e41932d744f", + "sha256:ce436f4c6d218a070048ed6a44c0bbb10cd2cc5e272b29e7845f6a2f57ee4464", + "sha256:d10d994b41fb3497719bbf866f227b3489048ea4bbbb5015357db306249f7980", + "sha256:e601a7fa172c2131bff456bb3ee08a88360760d0d2f8cbd7a75a65497e2df078", + "sha256:f95579473af29ab73a10bada2f9722856792a36ec5af5399b653aa28360290a5" ], "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==1.13.0" + "markers": "python_version >= '3.9'", + "version": "==1.15.0" }, "mypy-extensions": { "hashes": [ @@ -139,6 +176,30 @@ "markers": "python_version >= '3.5'", "version": "==1.0.0" }, + "packaging": { + "hashes": [ + "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", + "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f" + ], + "markers": "python_version >= '3.8'", + "version": "==24.2" + }, + "pathspec": { + "hashes": [ + "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", + "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712" + ], + "markers": "python_version >= '3.8'", + "version": "==0.12.1" + }, + "platformdirs": { + "hashes": [ + "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907", + "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb" + ], + "markers": "python_version >= '3.8'", + "version": "==4.3.6" + }, "publication": { "hashes": [ "sha256:0248885351febc11d8a1098d5c8e3ab2dabcf3e8c0c96db1e17ecd12b53afbe6", @@ -151,120 +212,171 @@ "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==2.9.0.post0" }, "referencing": { "hashes": [ - "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c", - "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de" + "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa", + "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0" ], - "markers": "python_version >= '3.8'", - "version": "==0.35.1" + "markers": "python_version >= '3.9'", + "version": "==0.36.2" }, "rpds-py": { "hashes": [ - "sha256:031819f906bb146561af051c7cef4ba2003d28cff07efacef59da973ff7969ba", - "sha256:0626238a43152918f9e72ede9a3b6ccc9e299adc8ade0d67c5e142d564c9a83d", - "sha256:085ed25baac88953d4283e5b5bd094b155075bb40d07c29c4f073e10623f9f2e", - "sha256:0a9e0759e7be10109645a9fddaaad0619d58c9bf30a3f248a2ea57a7c417173a", - "sha256:0c025820b78817db6a76413fff6866790786c38f95ea3f3d3c93dbb73b632202", - "sha256:1ff2eba7f6c0cb523d7e9cff0903f2fe1feff8f0b2ceb6bd71c0e20a4dcee271", - "sha256:20cc1ed0bcc86d8e1a7e968cce15be45178fd16e2ff656a243145e0b439bd250", - "sha256:241e6c125568493f553c3d0fdbb38c74babf54b45cef86439d4cd97ff8feb34d", - "sha256:2c51d99c30091f72a3c5d126fad26236c3f75716b8b5e5cf8effb18889ced928", - "sha256:2d6129137f43f7fa02d41542ffff4871d4aefa724a5fe38e2c31a4e0fd343fb0", - "sha256:30b912c965b2aa76ba5168fd610087bad7fcde47f0a8367ee8f1876086ee6d1d", - "sha256:30bdc973f10d28e0337f71d202ff29345320f8bc49a31c90e6c257e1ccef4333", - "sha256:320c808df533695326610a1b6a0a6e98f033e49de55d7dc36a13c8a30cfa756e", - "sha256:32eb88c30b6a4f0605508023b7141d043a79b14acb3b969aa0b4f99b25bc7d4a", - "sha256:3b766a9f57663396e4f34f5140b3595b233a7b146e94777b97a8413a1da1be18", - "sha256:3b929c2bb6e29ab31f12a1117c39f7e6d6450419ab7464a4ea9b0b417174f044", - "sha256:3e30a69a706e8ea20444b98a49f386c17b26f860aa9245329bab0851ed100677", - "sha256:3e53861b29a13d5b70116ea4230b5f0f3547b2c222c5daa090eb7c9c82d7f664", - "sha256:40c91c6e34cf016fa8e6b59d75e3dbe354830777fcfd74c58b279dceb7975b75", - "sha256:4991ca61656e3160cdaca4851151fd3f4a92e9eba5c7a530ab030d6aee96ec89", - "sha256:4ab2c2a26d2f69cdf833174f4d9d86118edc781ad9a8fa13970b527bf8236027", - "sha256:4e8921a259f54bfbc755c5bbd60c82bb2339ae0324163f32868f63f0ebb873d9", - "sha256:4eb2de8a147ffe0626bfdc275fc6563aa7bf4b6db59cf0d44f0ccd6ca625a24e", - "sha256:5145282a7cd2ac16ea0dc46b82167754d5e103a05614b724457cffe614f25bd8", - "sha256:520ed8b99b0bf86a176271f6fe23024323862ac674b1ce5b02a72bfeff3fff44", - "sha256:52c041802a6efa625ea18027a0723676a778869481d16803481ef6cc02ea8cb3", - "sha256:5555db3e618a77034954b9dc547eae94166391a98eb867905ec8fcbce1308d95", - "sha256:58a0e345be4b18e6b8501d3b0aa540dad90caeed814c515e5206bb2ec26736fd", - "sha256:590ef88db231c9c1eece44dcfefd7515d8bf0d986d64d0caf06a81998a9e8cab", - "sha256:5afb5efde74c54724e1a01118c6e5c15e54e642c42a1ba588ab1f03544ac8c7a", - "sha256:688c93b77e468d72579351a84b95f976bd7b3e84aa6686be6497045ba84be560", - "sha256:6b4ef7725386dc0762857097f6b7266a6cdd62bfd209664da6712cb26acef035", - "sha256:6bc0e697d4d79ab1aacbf20ee5f0df80359ecf55db33ff41481cf3e24f206919", - "sha256:6dcc4949be728ede49e6244eabd04064336012b37f5c2200e8ec8eb2988b209c", - "sha256:6f54e7106f0001244a5f4cf810ba8d3f9c542e2730821b16e969d6887b664266", - "sha256:808f1ac7cf3b44f81c9475475ceb221f982ef548e44e024ad5f9e7060649540e", - "sha256:8404b3717da03cbf773a1d275d01fec84ea007754ed380f63dfc24fb76ce4592", - "sha256:878f6fea96621fda5303a2867887686d7a198d9e0f8a40be100a63f5d60c88c9", - "sha256:8a7ff941004d74d55a47f916afc38494bd1cfd4b53c482b77c03147c91ac0ac3", - "sha256:95a5bad1ac8a5c77b4e658671642e4af3707f095d2b78a1fdd08af0dfb647624", - "sha256:97ef67d9bbc3e15584c2f3c74bcf064af36336c10d2e21a2131e123ce0f924c9", - "sha256:98486337f7b4f3c324ab402e83453e25bb844f44418c066623db88e4c56b7c7b", - "sha256:98e4fe5db40db87ce1c65031463a760ec7906ab230ad2249b4572c2fc3ef1f9f", - "sha256:998a8080c4495e4f72132f3d66ff91f5997d799e86cec6ee05342f8f3cda7dca", - "sha256:9afe42102b40007f588666bc7de82451e10c6788f6f70984629db193849dced1", - "sha256:9e20da3957bdf7824afdd4b6eeb29510e83e026473e04952dca565170cd1ecc8", - "sha256:a017f813f24b9df929674d0332a374d40d7f0162b326562daae8066b502d0590", - "sha256:a429b99337062877d7875e4ff1a51fe788424d522bd64a8c0a20ef3021fdb6ed", - "sha256:a58ce66847711c4aa2ecfcfaff04cb0327f907fead8945ffc47d9407f41ff952", - "sha256:a78d8b634c9df7f8d175451cfeac3810a702ccb85f98ec95797fa98b942cea11", - "sha256:a89a8ce9e4e75aeb7fa5d8ad0f3fecdee813802592f4f46a15754dcb2fd6b061", - "sha256:a8eeec67590e94189f434c6d11c426892e396ae59e4801d17a93ac96b8c02a6c", - "sha256:aaeb25ccfb9b9014a10eaf70904ebf3f79faaa8e60e99e19eef9f478651b9b74", - "sha256:ad116dda078d0bc4886cb7840e19811562acdc7a8e296ea6ec37e70326c1b41c", - "sha256:af04ac89c738e0f0f1b913918024c3eab6e3ace989518ea838807177d38a2e94", - "sha256:af4a644bf890f56e41e74be7d34e9511e4954894d544ec6b8efe1e21a1a8da6c", - "sha256:b21747f79f360e790525e6f6438c7569ddbfb1b3197b9e65043f25c3c9b489d8", - "sha256:b229ce052ddf1a01c67d68166c19cb004fb3612424921b81c46e7ea7ccf7c3bf", - "sha256:b4de1da871b5c0fd5537b26a6fc6814c3cc05cabe0c941db6e9044ffbb12f04a", - "sha256:b80b4690bbff51a034bfde9c9f6bf9357f0a8c61f548942b80f7b66356508bf5", - "sha256:b876f2bc27ab5954e2fd88890c071bd0ed18b9c50f6ec3de3c50a5ece612f7a6", - "sha256:b8f107395f2f1d151181880b69a2869c69e87ec079c49c0016ab96860b6acbe5", - "sha256:b9b76e2afd585803c53c5b29e992ecd183f68285b62fe2668383a18e74abe7a3", - "sha256:c2b2f71c6ad6c2e4fc9ed9401080badd1469fa9889657ec3abea42a3d6b2e1ed", - "sha256:c3761f62fcfccf0864cc4665b6e7c3f0c626f0380b41b8bd1ce322103fa3ef87", - "sha256:c38dbf31c57032667dd5a2f0568ccde66e868e8f78d5a0d27dcc56d70f3fcd3b", - "sha256:ca9989d5d9b1b300bc18e1801c67b9f6d2c66b8fd9621b36072ed1df2c977f72", - "sha256:cbd7504a10b0955ea287114f003b7ad62330c9e65ba012c6223dba646f6ffd05", - "sha256:d167e4dbbdac48bd58893c7e446684ad5d425b407f9336e04ab52e8b9194e2ed", - "sha256:d2132377f9deef0c4db89e65e8bb28644ff75a18df5293e132a8d67748397b9f", - "sha256:da52d62a96e61c1c444f3998c434e8b263c384f6d68aca8274d2e08d1906325c", - "sha256:daa8efac2a1273eed2354397a51216ae1e198ecbce9036fba4e7610b308b6153", - "sha256:dc5695c321e518d9f03b7ea6abb5ea3af4567766f9852ad1560f501b17588c7b", - "sha256:de552f4a1916e520f2703ec474d2b4d3f86d41f353e7680b597512ffe7eac5d0", - "sha256:de609a6f1b682f70bb7163da745ee815d8f230d97276db049ab447767466a09d", - "sha256:e12bb09678f38b7597b8346983d2323a6482dcd59e423d9448108c1be37cac9d", - "sha256:e168afe6bf6ab7ab46c8c375606298784ecbe3ba31c0980b7dcbb9631dcba97e", - "sha256:e78868e98f34f34a88e23ee9ccaeeec460e4eaf6db16d51d7a9b883e5e785a5e", - "sha256:e860f065cc4ea6f256d6f411aba4b1251255366e48e972f8a347cf88077b24fd", - "sha256:ea3a6ac4d74820c98fcc9da4a57847ad2cc36475a8bd9683f32ab6d47a2bd682", - "sha256:ebf64e281a06c904a7636781d2e973d1f0926a5b8b480ac658dc0f556e7779f4", - "sha256:ed6378c9d66d0de903763e7706383d60c33829581f0adff47b6535f1802fa6db", - "sha256:ee1e4fc267b437bb89990b2f2abf6c25765b89b72dd4a11e21934df449e0c976", - "sha256:ee4eafd77cc98d355a0d02f263efc0d3ae3ce4a7c24740010a8b4012bbb24937", - "sha256:efec946f331349dfc4ae9d0e034c263ddde19414fe5128580f512619abed05f1", - "sha256:f414da5c51bf350e4b7960644617c130140423882305f7574b6cf65a3081cecb", - "sha256:f71009b0d5e94c0e86533c0b27ed7cacc1239cb51c178fd239c3cfefefb0400a", - "sha256:f983e4c2f603c95dde63df633eec42955508eefd8d0f0e6d236d31a044c882d7", - "sha256:faa5e8496c530f9c71f2b4e1c49758b06e5f4055e17144906245c99fa6d45356", - "sha256:fed5dfefdf384d6fe975cc026886aece4f292feaf69d0eeb716cfd3c5a4dd8be" + "sha256:09cd7dbcb673eb60518231e02874df66ec1296c01a4fcd733875755c02014b19", + "sha256:0f3288930b947cbebe767f84cf618d2cbe0b13be476e749da0e6a009f986248c", + "sha256:0fced9fd4a07a1ded1bac7e961ddd9753dd5d8b755ba8e05acba54a21f5f1522", + "sha256:112b8774b0b4ee22368fec42749b94366bd9b536f8f74c3d4175d4395f5cbd31", + "sha256:11dd60b2ffddba85715d8a66bb39b95ddbe389ad2cfcf42c833f1bcde0878eaf", + "sha256:178f8a60fc24511c0eb756af741c476b87b610dba83270fce1e5a430204566a4", + "sha256:1b08027489ba8fedde72ddd233a5ea411b85a6ed78175f40285bd401bde7466d", + "sha256:1bf5be5ba34e19be579ae873da515a2836a2166d8d7ee43be6ff909eda42b72b", + "sha256:1ed7de3c86721b4e83ac440751329ec6a1102229aa18163f84c75b06b525ad7e", + "sha256:1eedaaccc9bb66581d4ae7c50e15856e335e57ef2734dbc5fd8ba3e2a4ab3cb6", + "sha256:243241c95174b5fb7204c04595852fe3943cc41f47aa14c3828bc18cd9d3b2d6", + "sha256:26bb3e8de93443d55e2e748e9fd87deb5f8075ca7bc0502cfc8be8687d69a2ec", + "sha256:271fa2184cf28bdded86bb6217c8e08d3a169fe0bbe9be5e8d96e8476b707122", + "sha256:28358c54fffadf0ae893f6c1050e8f8853e45df22483b7fff2f6ab6152f5d8bf", + "sha256:285019078537949cecd0190f3690a0b0125ff743d6a53dfeb7a4e6787af154f5", + "sha256:2893d778d4671ee627bac4037a075168b2673c57186fb1a57e993465dbd79a93", + "sha256:2a54027554ce9b129fc3d633c92fa33b30de9f08bc61b32c053dc9b537266fed", + "sha256:2c6ae11e6e93728d86aafc51ced98b1658a0080a7dd9417d24bfb955bb09c3c2", + "sha256:2cfa07c346a7ad07019c33fb9a63cf3acb1f5363c33bc73014e20d9fe8b01cdd", + "sha256:35d5631ce0af26318dba0ae0ac941c534453e42f569011585cb323b7774502a5", + "sha256:3614d280bf7aab0d3721b5ce0e73434acb90a2c993121b6e81a1c15c665298ac", + "sha256:3902df19540e9af4cc0c3ae75974c65d2c156b9257e91f5101a51f99136d834c", + "sha256:3aaf141d39f45322e44fc2c742e4b8b4098ead5317e5f884770c8df0c332da70", + "sha256:3d8abf7896a91fb97e7977d1aadfcc2c80415d6dc2f1d0fca5b8d0df247248f3", + "sha256:3e77febf227a1dc3220159355dba68faa13f8dca9335d97504abf428469fb18b", + "sha256:3e9212f52074fc9d72cf242a84063787ab8e21e0950d4d6709886fb62bcb91d5", + "sha256:3ee9d6f0b38efb22ad94c3b68ffebe4c47865cdf4b17f6806d6c674e1feb4246", + "sha256:4233df01a250b3984465faed12ad472f035b7cd5240ea3f7c76b7a7016084495", + "sha256:4263320ed887ed843f85beba67f8b2d1483b5947f2dc73a8b068924558bfeace", + "sha256:4ab923167cfd945abb9b51a407407cf19f5bee35001221f2911dc85ffd35ff4f", + "sha256:4caafd1a22e5eaa3732acb7672a497123354bef79a9d7ceed43387d25025e935", + "sha256:50fb62f8d8364978478b12d5f03bf028c6bc2af04082479299139dc26edf4c64", + "sha256:55ff4151cfd4bc635e51cfb1c59ac9f7196b256b12e3a57deb9e5742e65941ad", + "sha256:5b98b6c953e5c2bda51ab4d5b4f172617d462eebc7f4bfdc7c7e6b423f6da957", + "sha256:5c9ff044eb07c8468594d12602291c635da292308c8c619244e30698e7fc455a", + "sha256:5e9c206a1abc27e0588cf8b7c8246e51f1a16a103734f7750830a1ccb63f557a", + "sha256:5fb89edee2fa237584e532fbf78f0ddd1e49a47c7c8cfa153ab4849dc72a35e6", + "sha256:633462ef7e61d839171bf206551d5ab42b30b71cac8f10a64a662536e057fdef", + "sha256:66f8d2a17e5838dd6fb9be6baaba8e75ae2f5fa6b6b755d597184bfcd3cb0eba", + "sha256:6959bb9928c5c999aba4a3f5a6799d571ddc2c59ff49917ecf55be2bbb4e3722", + "sha256:698a79d295626ee292d1730bc2ef6e70a3ab135b1d79ada8fde3ed0047b65a10", + "sha256:721f9c4011b443b6e84505fc00cc7aadc9d1743f1c988e4c89353e19c4a968ee", + "sha256:72e680c1518733b73c994361e4b06441b92e973ef7d9449feec72e8ee4f713da", + "sha256:75307599f0d25bf6937248e5ac4e3bde5ea72ae6618623b86146ccc7845ed00b", + "sha256:754fba3084b70162a6b91efceee8a3f06b19e43dac3f71841662053c0584209a", + "sha256:759462b2d0aa5a04be5b3e37fb8183615f47014ae6b116e17036b131985cb731", + "sha256:7938c7b0599a05246d704b3f5e01be91a93b411d0d6cc62275f025293b8a11ce", + "sha256:7b77e07233925bd33fc0022b8537774423e4c6680b6436316c5075e79b6384f4", + "sha256:7e5413d2e2d86025e73f05510ad23dad5950ab8417b7fc6beaad99be8077138b", + "sha256:7f3240dcfa14d198dba24b8b9cb3b108c06b68d45b7babd9eefc1038fdf7e707", + "sha256:7f9682a8f71acdf59fd554b82b1c12f517118ee72c0f3944eda461606dfe7eb9", + "sha256:8d67beb6002441faef8251c45e24994de32c4c8686f7356a1f601ad7c466f7c3", + "sha256:9441af1d25aed96901f97ad83d5c3e35e6cd21a25ca5e4916c82d7dd0490a4fa", + "sha256:98b257ae1e83f81fb947a363a274c4eb66640212516becaff7bef09a5dceacaa", + "sha256:9e9f3a3ac919406bc0414bbbd76c6af99253c507150191ea79fab42fdb35982a", + "sha256:a1c66e71ecfd2a4acf0e4bd75e7a3605afa8f9b28a3b497e4ba962719df2be57", + "sha256:a1e17d8dc8e57d8e0fd21f8f0f0a5211b3fa258b2e444c2053471ef93fe25a00", + "sha256:a20cb698c4a59c534c6701b1c24a968ff2768b18ea2991f886bd8985ce17a89f", + "sha256:a970bfaf130c29a679b1d0a6e0f867483cea455ab1535fb427566a475078f27f", + "sha256:a98f510d86f689fcb486dc59e6e363af04151e5260ad1bdddb5625c10f1e95f8", + "sha256:a9d3b728f5a5873d84cba997b9d617c6090ca5721caaa691f3b1a78c60adc057", + "sha256:ad76f44f70aac3a54ceb1813ca630c53415da3a24fd93c570b2dfb4856591017", + "sha256:ae28144c1daa61366205d32abd8c90372790ff79fc60c1a8ad7fd3c8553a600e", + "sha256:b03a8d50b137ee758e4c73638b10747b7c39988eb8e6cd11abb7084266455165", + "sha256:b5a96fcac2f18e5a0a23a75cd27ce2656c66c11c127b0318e508aab436b77428", + "sha256:b5ef909a37e9738d146519657a1aab4584018746a18f71c692f2f22168ece40c", + "sha256:b79f5ced71efd70414a9a80bbbfaa7160da307723166f09b69773153bf17c590", + "sha256:b91cceb5add79ee563bd1f70b30896bd63bc5f78a11c1f00a1e931729ca4f1f4", + "sha256:b92f5654157de1379c509b15acec9d12ecf6e3bc1996571b6cb82a4302060447", + "sha256:c04ca91dda8a61584165825907f5c967ca09e9c65fe8966ee753a3f2b019fe1e", + "sha256:c1f8afa346ccd59e4e5630d5abb67aba6a9812fddf764fd7eb11f382a345f8cc", + "sha256:c5334a71f7dc1160382d45997e29f2637c02f8a26af41073189d79b95d3321f1", + "sha256:c617d7453a80e29d9973b926983b1e700a9377dbe021faa36041c78537d7b08c", + "sha256:c632419c3870507ca20a37c8f8f5352317aca097639e524ad129f58c125c61c6", + "sha256:c6760211eee3a76316cf328f5a8bd695b47b1626d21c8a27fb3b2473a884d597", + "sha256:c698d123ce5d8f2d0cd17f73336615f6a2e3bdcedac07a1291bb4d8e7d82a05a", + "sha256:c76b32eb2ab650a29e423525e84eb197c45504b1c1e6e17b6cc91fcfeb1a4b1d", + "sha256:c8f7e90b948dc9dcfff8003f1ea3af08b29c062f681c05fd798e36daa3f7e3e8", + "sha256:c9e799dac1ffbe7b10c1fd42fe4cd51371a549c6e108249bde9cd1200e8f59b4", + "sha256:cafa48f2133d4daa028473ede7d81cd1b9f9e6925e9e4003ebdf77010ee02f35", + "sha256:ce473a2351c018b06dd8d30d5da8ab5a0831056cc53b2006e2a8028172c37ce5", + "sha256:d31ed4987d72aabdf521eddfb6a72988703c091cfc0064330b9e5f8d6a042ff5", + "sha256:d550d7e9e7d8676b183b37d65b5cd8de13676a738973d330b59dc8312df9c5dc", + "sha256:d6adb81564af0cd428910f83fa7da46ce9ad47c56c0b22b50872bc4515d91966", + "sha256:d6f6512a90bd5cd9030a6237f5346f046c6f0e40af98657568fa45695d4de59d", + "sha256:d7031d493c4465dbc8d40bd6cafefef4bd472b17db0ab94c53e7909ee781b9ef", + "sha256:d9f75a06ecc68f159d5d7603b734e1ff6daa9497a929150f794013aa9f6e3f12", + "sha256:db7707dde9143a67b8812c7e66aeb2d843fe33cc8e374170f4d2c50bd8f2472d", + "sha256:e0397dd0b3955c61ef9b22838144aa4bef6f0796ba5cc8edfc64d468b93798b4", + "sha256:e0df046f2266e8586cf09d00588302a32923eb6386ced0ca5c9deade6af9a149", + "sha256:e14f86b871ea74c3fddc9a40e947d6a5d09def5adc2076ee61fb910a9014fb35", + "sha256:e5963ea87f88bddf7edd59644a35a0feecf75f8985430124c253612d4f7d27ae", + "sha256:e768267cbe051dd8d1c5305ba690bb153204a09bf2e3de3ae530de955f5b5580", + "sha256:e9cb79ecedfc156c0692257ac7ed415243b6c35dd969baa461a6888fc79f2f07", + "sha256:ed6f011bedca8585787e5082cce081bac3d30f54520097b2411351b3574e1219", + "sha256:f3429fb8e15b20961efca8c8b21432623d85db2228cc73fe22756c6637aa39e7", + "sha256:f35eff113ad430b5272bbfc18ba111c66ff525828f24898b4e146eb479a2cdda", + "sha256:f3a6cb95074777f1ecda2ca4fa7717caa9ee6e534f42b7575a8f0d4cb0c24013", + "sha256:f7356a6da0562190558c4fcc14f0281db191cdf4cb96e7604c06acfcee96df15", + "sha256:f88626e3f5e57432e6191cd0c5d6d6b319b635e70b40be2ffba713053e5147dd", + "sha256:fad784a31869747df4ac968a351e070c06ca377549e4ace94775aaa3ab33ee06", + "sha256:fc869af5cba24d45fb0399b0cfdbcefcf6910bf4dee5d74036a57cf5264b3ff4", + "sha256:fee513135b5a58f3bb6d89e48326cd5aa308e4bcdf2f7d59f67c861ada482bf8" ], "markers": "python_version >= '3.9'", - "version": "==0.21.0" + "version": "==0.23.1" }, "six": { "hashes": [ - "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", - "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" + "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", + "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", - "version": "==1.16.0" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.17.0" + }, + "tomli": { + "hashes": [ + "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6", + "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd", + "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c", + "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b", + "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8", + "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6", + "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77", + "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff", + "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea", + "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192", + "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", + "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee", + "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4", + "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98", + "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8", + "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4", + "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281", + "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744", + "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69", + "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13", + "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140", + "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e", + "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e", + "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", + "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", + "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec", + "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2", + "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222", + "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106", + "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272", + "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a", + "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7" + ], + "markers": "python_version < '3.11'", + "version": "==2.2.1" }, "typeguard": { "hashes": [ @@ -276,19 +388,19 @@ }, "types-jsonschema": { "hashes": [ - "sha256:be283e23f0b87547316c2ee6b0fd36d95ea30e921db06478029e10b5b6aa6ac3", - "sha256:c93f48206f209a5bc4608d295ac39f172fb98b9e24159ce577dbd25ddb79a1c0" + "sha256:87934bd9231c99d8eff94cacfc06ba668f7973577a9bd9e1f9de957c5737313e", + "sha256:e8b15ad01f290ecf6aea53f93fbdf7d4730e4600313e89e8a7f95622f7e87b7c" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==4.23.0.20240813" + "version": "==4.23.0.20241208" }, "typing-extensions": { "hashes": [ "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" ], - "markers": "python_version >= '3.8'", + "markers": "python_version < '3.11'", "version": "==4.12.2" } }, diff --git a/deployments/sequencer/README.md b/deployments/sequencer/README.md index ea17fd77340..48ada26d7b0 100644 --- a/deployments/sequencer/README.md +++ b/deployments/sequencer/README.md @@ -1,7 +1,70 @@ -# CRD +# CDK8S Deployment +cdk8s is an open-source software development framework for defining Kubernetes applications, +and reusable abstractions using familiar programming languages and rich object-oriented APIs. +cdk8s apps synthesize into standard Kubernetes manifests that can be applied to any Kubernetes cluster. -Example usage of [`Custom Resources Definitions`](https://cdk8s.io/docs/latest/cli/import/#crds) construct and to define them within a cdk8s application: +- Official documentation https://cdk8s.io/docs/latest/ -- `App` (Core) -- `Chart` (Core) -- `Certificate` (CRD) +## Requirements +Please note: all the requirements instructions are optional. +You can use any method you like to install the required tools. + +### List of required tools +1. python3.10 +2. python3.10-pipenv +3. nodejs + npm +4. cdk8s-cli + +### Setup python3.10 +**For ubuntu 22.04 users** +```bash + sudo apt update + sudo apt install python3.10-full +``` +**For ubuntu 24.04 users** +```bash + sudo add-apt-repository ppa:deadsnakes/ppa + sudo apt update + sudo apt install python3.10-full +``` + +### Setup nodejs +```bash + curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash + # For bash users + source ~/.bashrc + + # For zsh users + source ~/.zshrc + nvm install 22.14.0 + nvm use 22.14.0 +``` + +### Install cdk8s +```bash + npm install -g cdk8s-cli@2.198.267 +``` + +### Install pipenv +```bash + pip install pipenv +``` + +## How to use cdk8s +### initialize cdk8s ( required to execute once ) +```bash + cd deployments/sequencer + pipenv install + cdk8s import +``` + +### Use cdk8s +#### Examples: +```bash + cd deployments/sequencer + cdk8s synth --app "pipenv run python main.py --namespace --deployment-config-file " +``` + +### Deploy sequencer +cdk8s generated the k8s manifests to `./dist` folder. +You can now use `kubectl apply` or any other preferred method to deploy. diff --git a/deployments/sequencer/app/monitoring.py b/deployments/sequencer/app/monitoring.py new file mode 100644 index 00000000000..62ec7bfede0 --- /dev/null +++ b/deployments/sequencer/app/monitoring.py @@ -0,0 +1,34 @@ +import json + +from constructs import Construct +from cdk8s import Names, ApiObjectMetadata +from imports.co.starkware.grafana import SharedGrafanaDashboard, SharedGrafanaDashboardSpec + +from services.monitoring import GrafanaDashboard + + +class MonitoringApp(Construct): + def __init__( + self, scope: Construct, id: str, namespace: str, grafana_dashboard: GrafanaDashboard + ) -> None: + super().__init__(scope, id) + + self.namespace = namespace + self.labels = { + "app": "sequencer-node", + "service": Names.to_label_value(self, include_hash=False), + } + + SharedGrafanaDashboard( + self, + "shared-grafana-dashboard", + metadata=ApiObjectMetadata( + labels=self.labels, + ), + spec=SharedGrafanaDashboardSpec( + collection_name="shared-grafana-dashboard", + dashboard_name=self.node.id, + folder_name=self.namespace, + dashboard_json=json.dumps(grafana_dashboard.get(), indent=2), + ), + ) diff --git a/deployments/sequencer/app/service.py b/deployments/sequencer/app/service.py index 17388ef14c2..25fee4dc8fe 100644 --- a/deployments/sequencer/app/service.py +++ b/deployments/sequencer/app/service.py @@ -1,261 +1,369 @@ import json +import typing -from itertools import chain from constructs import Construct from cdk8s import Names, ApiObjectMetadata from imports import k8s -from imports.com.google import cloud as google +from imports.io.external_secrets import ( + ExternalSecretV1Beta1 as ExternalSecret, + ExternalSecretV1Beta1Spec as ExternalSecretSpec, + ExternalSecretV1Beta1SpecData as ExternalSecretSpecData, + ExternalSecretV1Beta1SpecTarget as ExternalSecretSpecTarget, + ExternalSecretV1Beta1SpecDataRemoteRef as ExternalSecretSpecDataRemoteRef, + ExternalSecretV1Beta1SpecSecretStoreRef as ExternalSecretSpecSecretStoreRef, + ExternalSecretV1Beta1SpecSecretStoreRefKind as ExternalSecretSpecSecretStoreRefKind, + ExternalSecretV1Beta1SpecDataRemoteRefConversionStrategy as ExternalSecretSpecDataRemoteRefConversionStrategy, +) +from services import topology, const -from services import topology - -class ServiceApp(Construct): +class ServiceApp(Construct): def __init__( self, scope: Construct, id: str, *, namespace: str, - topology: topology.ServiceTopology + service_topology: topology.ServiceTopology, + external_secret=None, # Disabled for now ): super().__init__(scope, id) self.namespace = namespace - self.label = {"app": Names.to_label_value(self, include_hash=False)} - self.topology = topology - - self.set_k8s_namespace() - - if topology.service is not None: - self.set_k8s_service() - - if topology.config is not None: - self.set_k8s_configmap() - - if topology.deployment is not None: - self.set_k8s_deployment() - - if topology.ingress is not None: - self.set_k8s_ingress() - - if topology.pvc is not None: - self.set_k8s_pvc() - - def set_k8s_namespace(self): - return k8s.KubeNamespace( + self.labels = { + "app": "sequencer", + "service": Names.to_label_value(self, include_hash=False), + } + self.service_topology = service_topology + self.external_secret = external_secret + self.node_config = service_topology.config.get_config() + + self.config_map = k8s.KubeConfigMap( self, - "namespace", - metadata=k8s.ObjectMeta( - name=self.namespace - ) + "configmap", + metadata=k8s.ObjectMeta(name=f"{self.node.id}-config"), + data=dict(config=json.dumps(self.service_topology.config.get_config(), indent=2)), ) - def set_k8s_configmap(self): - return k8s.KubeConfigMap( + self.service = k8s.KubeService( self, - "configmap", - metadata=k8s.ObjectMeta( - name=f"{self.node.id}-config" + "service", + spec=k8s.ServiceSpec( + type=const.ServiceType.CLUSTER_IP, + ports=self._get_service_ports(), + selector=self.labels, ), - data=dict(config=json.dumps(self.topology.config.get())), ) - - def set_k8s_service(self): - return k8s.KubeService( - self, - "service", - spec=k8s.ServiceSpec( - type=self.topology.service.type.value, - ports=[ - k8s.ServicePort( - name=port.name, - port=port.port, - target_port=k8s.IntOrString.from_number(port.container_port), - ) for port in self.topology.service.ports - ], - selector=self.label - ) - ) - def set_k8s_deployment(self): - return k8s.KubeDeployment( + self.deployment = k8s.KubeDeployment( self, "deployment", + metadata=k8s.ObjectMeta(labels=self.labels), spec=k8s.DeploymentSpec( - replicas=self.topology.deployment.replicas, - selector=k8s.LabelSelector(match_labels=self.label), + replicas=self.service_topology.replicas, + selector=k8s.LabelSelector(match_labels=self.labels), template=k8s.PodTemplateSpec( - metadata=k8s.ObjectMeta(labels=self.label), + metadata=k8s.ObjectMeta(labels=self.labels), spec=k8s.PodSpec( - security_context=k8s.PodSecurityContext( - fs_group=1000 - ), + security_context=k8s.PodSecurityContext(fs_group=1000), + volumes=self._get_volumes(), containers=[ k8s.Container( - name=f"{self.node.id}-{container.name}", - image=container.image, - # command=["sleep", "infinity"], - args=container.args, - ports=[ - k8s.ContainerPort( - container_port=port.container_port - ) for port in container.ports - ], - startup_probe=k8s.Probe( - http_get=k8s.HttpGetAction( - path=container.startup_probe.path, - port=k8s.IntOrString.from_string(container.startup_probe.port) - if isinstance(container.startup_probe.port, str) - else k8s.IntOrString.from_number(container.startup_probe.port) - ), - period_seconds=container.startup_probe.period_seconds, - failure_threshold=container.startup_probe.failure_threshold, - timeout_seconds=container.startup_probe.timeout_seconds - ) if container.startup_probe is not None else None, - - readiness_probe=k8s.Probe( - http_get=k8s.HttpGetAction( - path=container.readiness_probe.path, - port=k8s.IntOrString.from_string(container.readiness_probe.port) - if isinstance(container.readiness_probe.port, str) - else k8s.IntOrString.from_number(container.readiness_probe.port) - ), - period_seconds=container.readiness_probe.period_seconds, - failure_threshold=container.readiness_probe.failure_threshold, - timeout_seconds=container.readiness_probe.timeout_seconds - ) if container.readiness_probe is not None else None, - - liveness_probe=k8s.Probe( - http_get=k8s.HttpGetAction( - path=container.liveness_probe.path, - port=k8s.IntOrString.from_string(container.liveness_probe.port) - if isinstance(container.liveness_probe.port, str) - else k8s.IntOrString.from_number(container.liveness_probe.port) - ), - period_seconds=container.liveness_probe.period_seconds, - failure_threshold=container.liveness_probe.failure_threshold, - timeout_seconds=container.liveness_probe.timeout_seconds - ) if container.liveness_probe is not None else None, - - volume_mounts=[ - k8s.VolumeMount( - name=mount.name, - mount_path=mount.mount_path, - read_only=mount.read_only - ) for mount in container.volume_mounts - ] - ) for container in self.topology.deployment.containers + name=self.node.id, + image=self.service_topology.image, + image_pull_policy="Always", + env=self._get_container_env(), + args=const.CONTAINER_ARGS, + ports=self._get_container_ports(), + startup_probe=self._get_http_probe(), + readiness_probe=self._get_http_probe( + path=const.PROBE_MONITORING_READY_PATH + ), + liveness_probe=self._get_http_probe(), + volume_mounts=self._get_volume_mounts(), + ) ], - volumes=list( - chain( - ( - k8s.Volume( - name=f"{self.node.id}-{volume.name}", - config_map=k8s.ConfigMapVolumeSource( - name=f"{self.node.id}-{volume.name}" - ) - ) for volume in self.topology.deployment.configmap_volumes - ) if self.topology.deployment.configmap_volumes is not None else None, - ( - k8s.Volume( - name=f"{self.node.id}-{volume.name}", - persistent_volume_claim=k8s.PersistentVolumeClaimVolumeSource( - claim_name=f"{self.node.id}-{volume.name}", - read_only=volume.read_only - ) - ) for volume in self.topology.deployment.pvc_volumes - ) if self.topology.deployment is not None else None + ), + ), + ), + ) + + if self.service_topology.ingress: + self.ingress = self._get_ingress() + + if self.service_topology.storage is not None: + self.pvc = self._get_persistent_volume_claim() + + if self.service_topology.autoscale: + self.hpa = self._get_hpa() + + def _get_external_secret(self) -> ExternalSecret: + return ExternalSecret( + self, + "external-secret", + metadata=ApiObjectMetadata(labels=self.labels), + spec=ExternalSecretSpec( + secret_store_ref=ExternalSecretSpecSecretStoreRef( + kind=ExternalSecretSpecSecretStoreRefKind.CLUSTER_SECRET_STORE, + name="external-secrets", + ), + refresh_interval="1m", + target=ExternalSecretSpecTarget( + name=f"{self.node.id}-secret", + ), + data=[ + ExternalSecretSpecData( + secret_key="secrets.json", + remote_ref=ExternalSecretSpecDataRemoteRef( + key=f"{self.node.id}-{self.namespace}", + conversion_strategy=ExternalSecretSpecDataRemoteRefConversionStrategy.DEFAULT, + ), + ), + ], + ), + ) + + def _get_hpa(self) -> k8s.KubeHorizontalPodAutoscalerV2: + return k8s.KubeHorizontalPodAutoscalerV2( + self, + "hpa", + metadata=k8s.ObjectMeta(labels=self.labels), + spec=k8s.HorizontalPodAutoscalerSpecV2( + min_replicas=self.service_topology.replicas, + max_replicas=const.HPA_MAX_REPLICAS, + scale_target_ref=k8s.CrossVersionObjectReferenceV2( + api_version="v1", kind="Deployment", name=self.deployment.name + ), + metrics=[ + k8s.MetricSpecV2( + type="Resource", + resource=k8s.ResourceMetricSourceV2( + name="cpu", + target=k8s.MetricTargetV2(type="Utilization", average_utilization=50), + ), + ) + ], + behavior=k8s.HorizontalPodAutoscalerBehaviorV2( + scale_up=k8s.HpaScalingRulesV2( + select_policy="Max", # Choose the highest scaling policy + stabilization_window_seconds=300, + policies=[ + k8s.HpaScalingPolicyV2( + type="Pods", + value=2, # Add 2 pods per scaling action + period_seconds=60, # Scaling happens at most once per minute ) - ) + ], ), ), ), ) - def set_k8s_ingress(self): + def _get_ingress(self) -> k8s.KubeIngress: + self.host = f"{self.node.id}.{self.namespace}.sw-dev.io" return k8s.KubeIngress( self, "ingress", metadata=k8s.ObjectMeta( name=f"{self.node.id}-ingress", - labels=self.label, - annotations=self.topology.ingress.annotations + labels=self.labels, + annotations={ + "kubernetes.io/tls-acme": "true", + "cert-manager.io/common-name": self.host, + "cert-manager.io/issue-temporary-certificate": "true", + "cert-manager.io/issuer": "letsencrypt-prod", + "acme.cert-manager.io/http01-edit-in-place": "true", + }, ), - spec=k8s.IngressSpec( - ingress_class_name=self.topology.ingress.class_name, - tls=[ - k8s.IngressTls( - hosts=tls.hosts, - secret_name=tls.secret_name - ) - for tls in self.topology.ingress.tls or [] - ], - rules=[ - k8s.IngressRule( - host=rule.host, - http=k8s.HttpIngressRuleValue( - paths=[ - k8s.HttpIngressPath( - path=path.path, - path_type=path.path_type, - backend=k8s.IngressBackend( - service=k8s.IngressServiceBackend( - name=path.backend_service_name, - port=k8s.ServiceBackendPort( - number=path.backend_service_port_number - ) - ) - ) - ) - for path in rule.paths or [] - ] - ) - ) - for rule in self.topology.ingress.rules or [] - ] - ) + spec=k8s.IngressSpec(tls=self._get_ingress_tls(), rules=self._get_ingress_rules()), ) - def set_k8s_pvc(self): - k8s.KubePersistentVolumeClaim( + def _get_persistent_volume_claim(self) -> k8s.KubePersistentVolumeClaim: + return k8s.KubePersistentVolumeClaim( self, "pvc", - metadata=k8s.ObjectMeta( - name=f"{self.node.id}-data", - labels=self.label - ), + metadata=k8s.ObjectMeta(name=f"{self.node.id}-data", labels=self.labels), spec=k8s.PersistentVolumeClaimSpec( - storage_class_name=self.topology.pvc.storage_class_name, - access_modes=self.topology.pvc.access_modes, - volume_mode=self.topology.pvc.volume_mode, + storage_class_name=const.PVC_STORAGE_CLASS_NAME, + access_modes=const.PVC_ACCESS_MODE, + volume_mode=const.PVC_VOLUME_MODE, resources=k8s.ResourceRequirements( - requests={"storage": k8s.Quantity.from_string(self.topology.pvc.storage)} - ) + requests={ + "storage": k8s.Quantity.from_string(f"{self.service_topology.storage}Gi") + } + ), + ), + ) + + def _get_config_attr(self, attr: str) -> str | int: + config_attr = self.node_config.get(attr) + assert config_attr is not None, f'Config attribute "{attr}" is missing.' + + return config_attr + + def _get_ports_subset_keys_from_config(self) -> typing.List[typing.Tuple[str, str]]: + ports = [] + for k, v in self.node_config.items(): + if k.endswith(".port") and v != 0: + if k.startswith("components."): + port_name = k.split(".")[1].replace("_", "-") + else: + port_name = k.split(".")[0].replace("_", "-") + else: + continue + + ports.append((port_name, k)) + + return ports + + def _get_container_ports(self) -> typing.List[k8s.ContainerPort]: + return [ + k8s.ContainerPort(container_port=self._get_config_attr(attr[1])) + for attr in self._get_ports_subset_keys_from_config() + ] + + def _get_service_ports(self) -> typing.List[k8s.ServicePort]: + return [ + k8s.ServicePort( + name=attr[0], + port=self._get_config_attr(attr[1]), + target_port=k8s.IntOrString.from_number(self._get_config_attr(attr[1])), ) + for attr in self._get_ports_subset_keys_from_config() + ] + + def _get_http_probe( + self, + period_seconds: int = const.PROBE_PERIOD_SECONDS, + failure_threshold: int = const.PROBE_FAILURE_THRESHOLD, + timeout_seconds: int = const.PROBE_TIMEOUT_SECONDS, + path: str = const.PROBE_MONITORING_ALIVE_PATH, + ) -> k8s.Probe: + port = self._get_config_attr("monitoring_endpoint_config.port") + + return k8s.Probe( + http_get=k8s.HttpGetAction( + path=path, + port=k8s.IntOrString.from_number(port), + ), + period_seconds=period_seconds, + failure_threshold=failure_threshold, + timeout_seconds=timeout_seconds, ) - def set_k8s_backend_config(self): - return google.BackendConfig( - self, - "backendconfig", - metadata=ApiObjectMetadata( - name=f"{self.node.id}-backendconfig", - labels=self.label + def _get_volume_mounts(self) -> typing.List[k8s.VolumeMount]: + volume_mounts = [ + ( + k8s.VolumeMount( + name=f"{self.node.id}-config", + mount_path="/config/sequencer/presets/", + read_only=True, + ) ), - spec=google.BackendConfigSpec( - health_check=google.BackendConfigSpecHealthCheck( - check_interval_sec=5, - healthy_threshold=10, - unhealthy_threshold=5, - timeout_sec=5, - request_path="/", - type="http" - ), - iap=google.BackendConfigSpecIap( - enabled=True, - oauthclient_credentials=google.BackendConfigSpecIapOauthclientCredentials( - secret_name="" - ) + ( + k8s.VolumeMount( + name=f"{self.node.id}-secret", + mount_path="/etc/secrets", + read_only=True, + ) + if self.external_secret is not None + else None + ), + ( + k8s.VolumeMount( + name=f"{self.node.id}-data", + mount_path="/data", + read_only=False, ) + if self.service_topology.storage + else None + ), + ] + + return [vm for vm in volume_mounts if vm is not None] + + def _get_volumes(self) -> typing.List[k8s.Volume]: + volumes = [ + ( + k8s.Volume( + name=f"{self.node.id}-config", + config_map=k8s.ConfigMapVolumeSource(name=f"{self.node.id}-config"), + ) + ), + ( + k8s.Volume( + name=f"{self.node.id}-secret", + secret=k8s.SecretVolumeSource( + secret_name=f"{self.node.id}-secret", + default_mode=400, + items=[ + k8s.KeyToPath( + key="secrets.json", + path="secrets.json", + ) + ], + ), + ) + if self.external_secret is not None + else None + ), + ( + k8s.Volume( + name=f"{self.node.id}-data", + persistent_volume_claim=k8s.PersistentVolumeClaimVolumeSource( + claim_name=f"{self.node.id}-data", read_only=False + ), + ) + if self.service_topology.storage + else None + ), + ] + + return [v for v in volumes if v is not None] + + def _get_ingress_rules(self) -> typing.List[k8s.IngressRule]: + return [ + k8s.IngressRule( + host=self.host, + http=k8s.HttpIngressRuleValue( + paths=[ + k8s.HttpIngressPath( + path="/monitoring", + path_type="Prefix", + backend=k8s.IngressBackend( + service=k8s.IngressServiceBackend( + name=f"{self.node.id}-service", + port=k8s.ServiceBackendPort( + number=self._get_config_attr( + "monitoring_endpoint_config.port" + ) + ), + ) + ), + ) + ] + ), ) - ) + ] + + def _get_ingress_tls(self) -> typing.List[k8s.IngressTls]: + return [k8s.IngressTls(hosts=[self.host], secret_name=f"{self.node.id}-tls")] + + @staticmethod + def _get_container_env() -> typing.List[k8s.EnvVar]: + return [ + k8s.EnvVar(name="RUST_LOG", value="debug"), + k8s.EnvVar(name="RUST_BACKTRACE", value="full"), + # TODO(Elin): consider a better way to uncolor app logs, maybe up the stack towards GCP. + k8s.EnvVar(name="NO_COLOR", value="1"), + ] + + @staticmethod + def _get_node_selector() -> typing.Dict[str, str]: + return {"role": "sequencer"} + + @staticmethod + def _get_tolerations() -> typing.Sequence[k8s.Toleration]: + return [ + k8s.Toleration(key="role", operator="Equal", value="sequencer", effect="NoSchedule"), + ] diff --git a/deployments/sequencer/black.sh b/deployments/sequencer/black.sh new file mode 100755 index 00000000000..2fdbd0b647e --- /dev/null +++ b/deployments/sequencer/black.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +# Run black on the sequencer deployment project. + +DEFAULT_ARGS="-l 100 -t py310 --exclude imports" +function fix() { + black ${DEFAULT_ARGS} . +} + +function check() { + black --diff --color ${DEFAULT_ARGS} . +} + +[[ $1 == "--fix" ]] && fix +[[ $1 == "--check" ]] && check diff --git a/deployments/sequencer/cdk8s.yaml b/deployments/sequencer/cdk8s.yaml index 17247a174a7..286fb0c60a9 100644 --- a/deployments/sequencer/cdk8s.yaml +++ b/deployments/sequencer/cdk8s.yaml @@ -3,3 +3,5 @@ app: pipenv install && pipenv run python ./main.py imports: - k8s@1.26.0 - resources/crds/backendconfigs_cloud_google_com.yaml + - resources/crds/external_secrets_crd_bundle.yaml + - resources/crds/shared_grafana10_dashboards_crd.yaml diff --git a/deployments/sequencer/config/sequencer.py b/deployments/sequencer/config/sequencer.py deleted file mode 100644 index be56e9272f8..00000000000 --- a/deployments/sequencer/config/sequencer.py +++ /dev/null @@ -1,22 +0,0 @@ -import os -import json -import jsonschema - -from services.objects import Config - - -ROOT_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), '../../../') -CONFIG_DIR = os.path.join(ROOT_DIR, 'config/sequencer/') - - -class SequencerDevConfig(Config): - def __init__(self, mount_path: str, config_file_path: str = ""): - super().__init__( - schema=json.loads(open(os.path.join(CONFIG_DIR, 'default_config.json'), 'r').read()), - config=json.loads(open(os.path.join(CONFIG_DIR, 'presets', 'config.json'), 'r').read()) if not config_file_path else json.loads(open(os.path.abspath(config_file_path)).read()), - mount_path=mount_path - ) - - - def validate(self): - jsonschema.validate(self.config, schema=self.schema) diff --git a/deployments/sequencer/deployment_config_schema.json b/deployments/sequencer/deployment_config_schema.json new file mode 100644 index 00000000000..2d087194478 --- /dev/null +++ b/deployments/sequencer/deployment_config_schema.json @@ -0,0 +1,29 @@ +{ + "type": "object", + "properties": { + "chain_id": {"type": "string"}, + "image": {"type": "string"}, + "application_config_subdir": {"type": "string"}, + "services": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": {"type": "string"}, + "config_path": {"type": "string"}, + "ingress": {"type": "boolean"}, + "replicas": {"type": "integer", "minimum": 1}, + "autoscale": {"type": "boolean"}, + "storage": { + "anyOf": [ + {"type": "integer", "minimum": 1}, + {"type": "null"} + ] + } + }, + "required": ["name", "config_path", "ingress", "replicas", "autoscale", "storage"] + } + } + }, + "required": ["chain_id", "services", "image", "application_config_subdir"] +} diff --git a/deployments/sequencer/imports/com/google/cloud/__init__.py b/deployments/sequencer/imports/com/google/cloud/__init__.py deleted file mode 100644 index 71d44945fa9..00000000000 --- a/deployments/sequencer/imports/com/google/cloud/__init__.py +++ /dev/null @@ -1,2761 +0,0 @@ -from pkgutil import extend_path -__path__ = extend_path(__path__, __name__) - -import abc -import builtins -import datetime -import enum -import typing - -import jsii -import publication -import typing_extensions - -import typeguard -from importlib.metadata import version as _metadata_package_version -TYPEGUARD_MAJOR_VERSION = int(_metadata_package_version('typeguard').split('.')[0]) - -def check_type(argname: str, value: object, expected_type: typing.Any) -> typing.Any: - if TYPEGUARD_MAJOR_VERSION <= 2: - return typeguard.check_type(argname=argname, value=value, expected_type=expected_type) # type:ignore - else: - if isinstance(value, jsii._reference_map.InterfaceDynamicProxy): # pyright: ignore [reportAttributeAccessIssue] - pass - else: - if TYPEGUARD_MAJOR_VERSION == 3: - typeguard.config.collection_check_strategy = typeguard.CollectionCheckStrategy.ALL_ITEMS # type:ignore - typeguard.check_type(value=value, expected_type=expected_type) # type:ignore - else: - typeguard.check_type(value=value, expected_type=expected_type, collection_check_strategy=typeguard.CollectionCheckStrategy.ALL_ITEMS) # type:ignore - -from ._jsii import * - -import cdk8s as _cdk8s_d3d9af27 -import constructs as _constructs_77d1e7e8 - - -class BackendConfig( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="comgooglecloud.BackendConfig", -): - ''' - :schema: BackendConfig - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[_cdk8s_d3d9af27.ApiObjectMetadata, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["BackendConfigSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "BackendConfig" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param metadata: - :param spec: BackendConfigSpec is the spec for a BackendConfig resource. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__478e053b34646f2f22c316b46d46fa578352a17dc0965e0733c3edbb3af21e40) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = BackendConfigProps(metadata=metadata, spec=spec) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - metadata: typing.Optional[typing.Union[_cdk8s_d3d9af27.ApiObjectMetadata, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["BackendConfigSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "BackendConfig". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param metadata: - :param spec: BackendConfigSpec is the spec for a BackendConfig resource. - ''' - props = BackendConfigProps(metadata=metadata, spec=spec) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "BackendConfig".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="comgooglecloud.BackendConfigProps", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata", "spec": "spec"}, -) -class BackendConfigProps: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union[_cdk8s_d3d9af27.ApiObjectMetadata, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["BackendConfigSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - ''' - :param metadata: - :param spec: BackendConfigSpec is the spec for a BackendConfig resource. - - :schema: BackendConfig - ''' - if isinstance(metadata, dict): - metadata = _cdk8s_d3d9af27.ApiObjectMetadata(**metadata) - if isinstance(spec, dict): - spec = BackendConfigSpec(**spec) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__e8e7a740219c8083806cfb80142ff0861537e30e169b215266207dac2fc18296) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - if spec is not None: - self._values["spec"] = spec - - @builtins.property - def metadata(self) -> typing.Optional[_cdk8s_d3d9af27.ApiObjectMetadata]: - ''' - :schema: BackendConfig#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional[_cdk8s_d3d9af27.ApiObjectMetadata], result) - - @builtins.property - def spec(self) -> typing.Optional["BackendConfigSpec"]: - '''BackendConfigSpec is the spec for a BackendConfig resource. - - :schema: BackendConfig#spec - ''' - result = self._values.get("spec") - return typing.cast(typing.Optional["BackendConfigSpec"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "BackendConfigProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="comgooglecloud.BackendConfigSpec", - jsii_struct_bases=[], - name_mapping={ - "cdn": "cdn", - "connection_draining": "connectionDraining", - "custom_request_headers": "customRequestHeaders", - "custom_response_headers": "customResponseHeaders", - "health_check": "healthCheck", - "iap": "iap", - "logging": "logging", - "security_policy": "securityPolicy", - "session_affinity": "sessionAffinity", - "timeout_sec": "timeoutSec", - }, -) -class BackendConfigSpec: - def __init__( - self, - *, - cdn: typing.Optional[typing.Union["BackendConfigSpecCdn", typing.Dict[builtins.str, typing.Any]]] = None, - connection_draining: typing.Optional[typing.Union["BackendConfigSpecConnectionDraining", typing.Dict[builtins.str, typing.Any]]] = None, - custom_request_headers: typing.Optional[typing.Union["BackendConfigSpecCustomRequestHeaders", typing.Dict[builtins.str, typing.Any]]] = None, - custom_response_headers: typing.Optional[typing.Union["BackendConfigSpecCustomResponseHeaders", typing.Dict[builtins.str, typing.Any]]] = None, - health_check: typing.Optional[typing.Union["BackendConfigSpecHealthCheck", typing.Dict[builtins.str, typing.Any]]] = None, - iap: typing.Optional[typing.Union["BackendConfigSpecIap", typing.Dict[builtins.str, typing.Any]]] = None, - logging: typing.Optional[typing.Union["BackendConfigSpecLogging", typing.Dict[builtins.str, typing.Any]]] = None, - security_policy: typing.Optional[typing.Union["BackendConfigSpecSecurityPolicy", typing.Dict[builtins.str, typing.Any]]] = None, - session_affinity: typing.Optional[typing.Union["BackendConfigSpecSessionAffinity", typing.Dict[builtins.str, typing.Any]]] = None, - timeout_sec: typing.Optional[jsii.Number] = None, - ) -> None: - '''BackendConfigSpec is the spec for a BackendConfig resource. - - :param cdn: CDNConfig contains configuration for CDN-enabled backends. - :param connection_draining: ConnectionDrainingConfig contains configuration for connection draining. For now the draining timeout. May manage more settings in the future. - :param custom_request_headers: CustomRequestHeadersConfig contains configuration for custom request headers. - :param custom_response_headers: CustomResponseHeadersConfig contains configuration for custom response headers. - :param health_check: HealthCheckConfig contains configuration for the health check. - :param iap: IAPConfig contains configuration for IAP-enabled backends. - :param logging: LogConfig contains configuration for logging. - :param security_policy: SecurityPolicyConfig contains configuration for CloudArmor-enabled backends. If not specified, the controller will not reconcile the security policy configuration. In other words, users can make changes in GCE without the controller overwriting them. - :param session_affinity: SessionAffinityConfig contains configuration for stickiness parameters. - :param timeout_sec: - - :schema: BackendConfigSpec - ''' - if isinstance(cdn, dict): - cdn = BackendConfigSpecCdn(**cdn) - if isinstance(connection_draining, dict): - connection_draining = BackendConfigSpecConnectionDraining(**connection_draining) - if isinstance(custom_request_headers, dict): - custom_request_headers = BackendConfigSpecCustomRequestHeaders(**custom_request_headers) - if isinstance(custom_response_headers, dict): - custom_response_headers = BackendConfigSpecCustomResponseHeaders(**custom_response_headers) - if isinstance(health_check, dict): - health_check = BackendConfigSpecHealthCheck(**health_check) - if isinstance(iap, dict): - iap = BackendConfigSpecIap(**iap) - if isinstance(logging, dict): - logging = BackendConfigSpecLogging(**logging) - if isinstance(security_policy, dict): - security_policy = BackendConfigSpecSecurityPolicy(**security_policy) - if isinstance(session_affinity, dict): - session_affinity = BackendConfigSpecSessionAffinity(**session_affinity) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__ed3aaa52e5e9ad8c8ce8edc12e3f41b1303bc88c9e4d6d58ade780d4014f2019) - check_type(argname="argument cdn", value=cdn, expected_type=type_hints["cdn"]) - check_type(argname="argument connection_draining", value=connection_draining, expected_type=type_hints["connection_draining"]) - check_type(argname="argument custom_request_headers", value=custom_request_headers, expected_type=type_hints["custom_request_headers"]) - check_type(argname="argument custom_response_headers", value=custom_response_headers, expected_type=type_hints["custom_response_headers"]) - check_type(argname="argument health_check", value=health_check, expected_type=type_hints["health_check"]) - check_type(argname="argument iap", value=iap, expected_type=type_hints["iap"]) - check_type(argname="argument logging", value=logging, expected_type=type_hints["logging"]) - check_type(argname="argument security_policy", value=security_policy, expected_type=type_hints["security_policy"]) - check_type(argname="argument session_affinity", value=session_affinity, expected_type=type_hints["session_affinity"]) - check_type(argname="argument timeout_sec", value=timeout_sec, expected_type=type_hints["timeout_sec"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if cdn is not None: - self._values["cdn"] = cdn - if connection_draining is not None: - self._values["connection_draining"] = connection_draining - if custom_request_headers is not None: - self._values["custom_request_headers"] = custom_request_headers - if custom_response_headers is not None: - self._values["custom_response_headers"] = custom_response_headers - if health_check is not None: - self._values["health_check"] = health_check - if iap is not None: - self._values["iap"] = iap - if logging is not None: - self._values["logging"] = logging - if security_policy is not None: - self._values["security_policy"] = security_policy - if session_affinity is not None: - self._values["session_affinity"] = session_affinity - if timeout_sec is not None: - self._values["timeout_sec"] = timeout_sec - - @builtins.property - def cdn(self) -> typing.Optional["BackendConfigSpecCdn"]: - '''CDNConfig contains configuration for CDN-enabled backends. - - :schema: BackendConfigSpec#cdn - ''' - result = self._values.get("cdn") - return typing.cast(typing.Optional["BackendConfigSpecCdn"], result) - - @builtins.property - def connection_draining( - self, - ) -> typing.Optional["BackendConfigSpecConnectionDraining"]: - '''ConnectionDrainingConfig contains configuration for connection draining. - - For now the draining timeout. May manage more settings in the future. - - :schema: BackendConfigSpec#connectionDraining - ''' - result = self._values.get("connection_draining") - return typing.cast(typing.Optional["BackendConfigSpecConnectionDraining"], result) - - @builtins.property - def custom_request_headers( - self, - ) -> typing.Optional["BackendConfigSpecCustomRequestHeaders"]: - '''CustomRequestHeadersConfig contains configuration for custom request headers. - - :schema: BackendConfigSpec#customRequestHeaders - ''' - result = self._values.get("custom_request_headers") - return typing.cast(typing.Optional["BackendConfigSpecCustomRequestHeaders"], result) - - @builtins.property - def custom_response_headers( - self, - ) -> typing.Optional["BackendConfigSpecCustomResponseHeaders"]: - '''CustomResponseHeadersConfig contains configuration for custom response headers. - - :schema: BackendConfigSpec#customResponseHeaders - ''' - result = self._values.get("custom_response_headers") - return typing.cast(typing.Optional["BackendConfigSpecCustomResponseHeaders"], result) - - @builtins.property - def health_check(self) -> typing.Optional["BackendConfigSpecHealthCheck"]: - '''HealthCheckConfig contains configuration for the health check. - - :schema: BackendConfigSpec#healthCheck - ''' - result = self._values.get("health_check") - return typing.cast(typing.Optional["BackendConfigSpecHealthCheck"], result) - - @builtins.property - def iap(self) -> typing.Optional["BackendConfigSpecIap"]: - '''IAPConfig contains configuration for IAP-enabled backends. - - :schema: BackendConfigSpec#iap - ''' - result = self._values.get("iap") - return typing.cast(typing.Optional["BackendConfigSpecIap"], result) - - @builtins.property - def logging(self) -> typing.Optional["BackendConfigSpecLogging"]: - '''LogConfig contains configuration for logging. - - :schema: BackendConfigSpec#logging - ''' - result = self._values.get("logging") - return typing.cast(typing.Optional["BackendConfigSpecLogging"], result) - - @builtins.property - def security_policy(self) -> typing.Optional["BackendConfigSpecSecurityPolicy"]: - '''SecurityPolicyConfig contains configuration for CloudArmor-enabled backends. - - If not specified, the controller will not reconcile the security policy configuration. In other words, users can make changes in GCE without the controller overwriting them. - - :schema: BackendConfigSpec#securityPolicy - ''' - result = self._values.get("security_policy") - return typing.cast(typing.Optional["BackendConfigSpecSecurityPolicy"], result) - - @builtins.property - def session_affinity(self) -> typing.Optional["BackendConfigSpecSessionAffinity"]: - '''SessionAffinityConfig contains configuration for stickiness parameters. - - :schema: BackendConfigSpec#sessionAffinity - ''' - result = self._values.get("session_affinity") - return typing.cast(typing.Optional["BackendConfigSpecSessionAffinity"], result) - - @builtins.property - def timeout_sec(self) -> typing.Optional[jsii.Number]: - ''' - :schema: BackendConfigSpec#timeoutSec - ''' - result = self._values.get("timeout_sec") - return typing.cast(typing.Optional[jsii.Number], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "BackendConfigSpec(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="comgooglecloud.BackendConfigSpecCdn", - jsii_struct_bases=[], - name_mapping={ - "enabled": "enabled", - "bypass_cache_on_request_headers": "bypassCacheOnRequestHeaders", - "cache_mode": "cacheMode", - "cache_policy": "cachePolicy", - "client_ttl": "clientTtl", - "default_ttl": "defaultTtl", - "max_ttl": "maxTtl", - "negative_caching": "negativeCaching", - "negative_caching_policy": "negativeCachingPolicy", - "request_coalescing": "requestCoalescing", - "serve_while_stale": "serveWhileStale", - "signed_url_cache_max_age_sec": "signedUrlCacheMaxAgeSec", - "signed_url_keys": "signedUrlKeys", - }, -) -class BackendConfigSpecCdn: - def __init__( - self, - *, - enabled: builtins.bool, - bypass_cache_on_request_headers: typing.Optional[typing.Sequence[typing.Union["BackendConfigSpecCdnBypassCacheOnRequestHeaders", typing.Dict[builtins.str, typing.Any]]]] = None, - cache_mode: typing.Optional[builtins.str] = None, - cache_policy: typing.Optional[typing.Union["BackendConfigSpecCdnCachePolicy", typing.Dict[builtins.str, typing.Any]]] = None, - client_ttl: typing.Optional[jsii.Number] = None, - default_ttl: typing.Optional[jsii.Number] = None, - max_ttl: typing.Optional[jsii.Number] = None, - negative_caching: typing.Optional[builtins.bool] = None, - negative_caching_policy: typing.Optional[typing.Sequence[typing.Union["BackendConfigSpecCdnNegativeCachingPolicy", typing.Dict[builtins.str, typing.Any]]]] = None, - request_coalescing: typing.Optional[builtins.bool] = None, - serve_while_stale: typing.Optional[jsii.Number] = None, - signed_url_cache_max_age_sec: typing.Optional[jsii.Number] = None, - signed_url_keys: typing.Optional[typing.Sequence[typing.Union["BackendConfigSpecCdnSignedUrlKeys", typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''CDNConfig contains configuration for CDN-enabled backends. - - :param enabled: - :param bypass_cache_on_request_headers: - :param cache_mode: - :param cache_policy: CacheKeyPolicy contains configuration for how requests to a CDN-enabled backend are cached. - :param client_ttl: - :param default_ttl: - :param max_ttl: - :param negative_caching: - :param negative_caching_policy: - :param request_coalescing: - :param serve_while_stale: - :param signed_url_cache_max_age_sec: - :param signed_url_keys: - - :schema: BackendConfigSpecCdn - ''' - if isinstance(cache_policy, dict): - cache_policy = BackendConfigSpecCdnCachePolicy(**cache_policy) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__622a4ce6676e87a1185b566cba87d43a91644ca1bc40dd893f4fac498eb82531) - check_type(argname="argument enabled", value=enabled, expected_type=type_hints["enabled"]) - check_type(argname="argument bypass_cache_on_request_headers", value=bypass_cache_on_request_headers, expected_type=type_hints["bypass_cache_on_request_headers"]) - check_type(argname="argument cache_mode", value=cache_mode, expected_type=type_hints["cache_mode"]) - check_type(argname="argument cache_policy", value=cache_policy, expected_type=type_hints["cache_policy"]) - check_type(argname="argument client_ttl", value=client_ttl, expected_type=type_hints["client_ttl"]) - check_type(argname="argument default_ttl", value=default_ttl, expected_type=type_hints["default_ttl"]) - check_type(argname="argument max_ttl", value=max_ttl, expected_type=type_hints["max_ttl"]) - check_type(argname="argument negative_caching", value=negative_caching, expected_type=type_hints["negative_caching"]) - check_type(argname="argument negative_caching_policy", value=negative_caching_policy, expected_type=type_hints["negative_caching_policy"]) - check_type(argname="argument request_coalescing", value=request_coalescing, expected_type=type_hints["request_coalescing"]) - check_type(argname="argument serve_while_stale", value=serve_while_stale, expected_type=type_hints["serve_while_stale"]) - check_type(argname="argument signed_url_cache_max_age_sec", value=signed_url_cache_max_age_sec, expected_type=type_hints["signed_url_cache_max_age_sec"]) - check_type(argname="argument signed_url_keys", value=signed_url_keys, expected_type=type_hints["signed_url_keys"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "enabled": enabled, - } - if bypass_cache_on_request_headers is not None: - self._values["bypass_cache_on_request_headers"] = bypass_cache_on_request_headers - if cache_mode is not None: - self._values["cache_mode"] = cache_mode - if cache_policy is not None: - self._values["cache_policy"] = cache_policy - if client_ttl is not None: - self._values["client_ttl"] = client_ttl - if default_ttl is not None: - self._values["default_ttl"] = default_ttl - if max_ttl is not None: - self._values["max_ttl"] = max_ttl - if negative_caching is not None: - self._values["negative_caching"] = negative_caching - if negative_caching_policy is not None: - self._values["negative_caching_policy"] = negative_caching_policy - if request_coalescing is not None: - self._values["request_coalescing"] = request_coalescing - if serve_while_stale is not None: - self._values["serve_while_stale"] = serve_while_stale - if signed_url_cache_max_age_sec is not None: - self._values["signed_url_cache_max_age_sec"] = signed_url_cache_max_age_sec - if signed_url_keys is not None: - self._values["signed_url_keys"] = signed_url_keys - - @builtins.property - def enabled(self) -> builtins.bool: - ''' - :schema: BackendConfigSpecCdn#enabled - ''' - result = self._values.get("enabled") - assert result is not None, "Required property 'enabled' is missing" - return typing.cast(builtins.bool, result) - - @builtins.property - def bypass_cache_on_request_headers( - self, - ) -> typing.Optional[typing.List["BackendConfigSpecCdnBypassCacheOnRequestHeaders"]]: - ''' - :schema: BackendConfigSpecCdn#bypassCacheOnRequestHeaders - ''' - result = self._values.get("bypass_cache_on_request_headers") - return typing.cast(typing.Optional[typing.List["BackendConfigSpecCdnBypassCacheOnRequestHeaders"]], result) - - @builtins.property - def cache_mode(self) -> typing.Optional[builtins.str]: - ''' - :schema: BackendConfigSpecCdn#cacheMode - ''' - result = self._values.get("cache_mode") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def cache_policy(self) -> typing.Optional["BackendConfigSpecCdnCachePolicy"]: - '''CacheKeyPolicy contains configuration for how requests to a CDN-enabled backend are cached. - - :schema: BackendConfigSpecCdn#cachePolicy - ''' - result = self._values.get("cache_policy") - return typing.cast(typing.Optional["BackendConfigSpecCdnCachePolicy"], result) - - @builtins.property - def client_ttl(self) -> typing.Optional[jsii.Number]: - ''' - :schema: BackendConfigSpecCdn#clientTtl - ''' - result = self._values.get("client_ttl") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def default_ttl(self) -> typing.Optional[jsii.Number]: - ''' - :schema: BackendConfigSpecCdn#defaultTtl - ''' - result = self._values.get("default_ttl") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def max_ttl(self) -> typing.Optional[jsii.Number]: - ''' - :schema: BackendConfigSpecCdn#maxTtl - ''' - result = self._values.get("max_ttl") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def negative_caching(self) -> typing.Optional[builtins.bool]: - ''' - :schema: BackendConfigSpecCdn#negativeCaching - ''' - result = self._values.get("negative_caching") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def negative_caching_policy( - self, - ) -> typing.Optional[typing.List["BackendConfigSpecCdnNegativeCachingPolicy"]]: - ''' - :schema: BackendConfigSpecCdn#negativeCachingPolicy - ''' - result = self._values.get("negative_caching_policy") - return typing.cast(typing.Optional[typing.List["BackendConfigSpecCdnNegativeCachingPolicy"]], result) - - @builtins.property - def request_coalescing(self) -> typing.Optional[builtins.bool]: - ''' - :schema: BackendConfigSpecCdn#requestCoalescing - ''' - result = self._values.get("request_coalescing") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def serve_while_stale(self) -> typing.Optional[jsii.Number]: - ''' - :schema: BackendConfigSpecCdn#serveWhileStale - ''' - result = self._values.get("serve_while_stale") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def signed_url_cache_max_age_sec(self) -> typing.Optional[jsii.Number]: - ''' - :schema: BackendConfigSpecCdn#signedUrlCacheMaxAgeSec - ''' - result = self._values.get("signed_url_cache_max_age_sec") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def signed_url_keys( - self, - ) -> typing.Optional[typing.List["BackendConfigSpecCdnSignedUrlKeys"]]: - ''' - :schema: BackendConfigSpecCdn#signedUrlKeys - ''' - result = self._values.get("signed_url_keys") - return typing.cast(typing.Optional[typing.List["BackendConfigSpecCdnSignedUrlKeys"]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "BackendConfigSpecCdn(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="comgooglecloud.BackendConfigSpecCdnBypassCacheOnRequestHeaders", - jsii_struct_bases=[], - name_mapping={"header_name": "headerName"}, -) -class BackendConfigSpecCdnBypassCacheOnRequestHeaders: - def __init__(self, *, header_name: typing.Optional[builtins.str] = None) -> None: - '''BypassCacheOnRequestHeader contains configuration for how requests containing specific request headers bypass the cache, even if the content was previously cached. - - :param header_name: The header field name to match on when bypassing cache. Values are case-insensitive. - - :schema: BackendConfigSpecCdnBypassCacheOnRequestHeaders - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__29143d667e3ffdd72b7660770c144cc283425c836b9727b5dce6d9ad54507331) - check_type(argname="argument header_name", value=header_name, expected_type=type_hints["header_name"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if header_name is not None: - self._values["header_name"] = header_name - - @builtins.property - def header_name(self) -> typing.Optional[builtins.str]: - '''The header field name to match on when bypassing cache. - - Values are case-insensitive. - - :schema: BackendConfigSpecCdnBypassCacheOnRequestHeaders#headerName - ''' - result = self._values.get("header_name") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "BackendConfigSpecCdnBypassCacheOnRequestHeaders(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="comgooglecloud.BackendConfigSpecCdnCachePolicy", - jsii_struct_bases=[], - name_mapping={ - "include_host": "includeHost", - "include_protocol": "includeProtocol", - "include_query_string": "includeQueryString", - "query_string_blacklist": "queryStringBlacklist", - "query_string_whitelist": "queryStringWhitelist", - }, -) -class BackendConfigSpecCdnCachePolicy: - def __init__( - self, - *, - include_host: typing.Optional[builtins.bool] = None, - include_protocol: typing.Optional[builtins.bool] = None, - include_query_string: typing.Optional[builtins.bool] = None, - query_string_blacklist: typing.Optional[typing.Sequence[builtins.str]] = None, - query_string_whitelist: typing.Optional[typing.Sequence[builtins.str]] = None, - ) -> None: - '''CacheKeyPolicy contains configuration for how requests to a CDN-enabled backend are cached. - - :param include_host: If true, requests to different hosts will be cached separately. - :param include_protocol: If true, http and https requests will be cached separately. - :param include_query_string: If true, query string parameters are included in the cache key according to QueryStringBlacklist and QueryStringWhitelist. If neither is set, the entire query string is included and if false the entire query string is excluded. - :param query_string_blacklist: Names of query strint parameters to exclude from cache keys. All other parameters are included. Either specify QueryStringBlacklist or QueryStringWhitelist, but not both. - :param query_string_whitelist: Names of query string parameters to include in cache keys. All other parameters are excluded. Either specify QueryStringBlacklist or QueryStringWhitelist, but not both. - - :schema: BackendConfigSpecCdnCachePolicy - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__58baffb66190c78e8d4c5f00de26d9625e7d2a0a6d8e74e5662211067b562a23) - check_type(argname="argument include_host", value=include_host, expected_type=type_hints["include_host"]) - check_type(argname="argument include_protocol", value=include_protocol, expected_type=type_hints["include_protocol"]) - check_type(argname="argument include_query_string", value=include_query_string, expected_type=type_hints["include_query_string"]) - check_type(argname="argument query_string_blacklist", value=query_string_blacklist, expected_type=type_hints["query_string_blacklist"]) - check_type(argname="argument query_string_whitelist", value=query_string_whitelist, expected_type=type_hints["query_string_whitelist"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if include_host is not None: - self._values["include_host"] = include_host - if include_protocol is not None: - self._values["include_protocol"] = include_protocol - if include_query_string is not None: - self._values["include_query_string"] = include_query_string - if query_string_blacklist is not None: - self._values["query_string_blacklist"] = query_string_blacklist - if query_string_whitelist is not None: - self._values["query_string_whitelist"] = query_string_whitelist - - @builtins.property - def include_host(self) -> typing.Optional[builtins.bool]: - '''If true, requests to different hosts will be cached separately. - - :schema: BackendConfigSpecCdnCachePolicy#includeHost - ''' - result = self._values.get("include_host") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def include_protocol(self) -> typing.Optional[builtins.bool]: - '''If true, http and https requests will be cached separately. - - :schema: BackendConfigSpecCdnCachePolicy#includeProtocol - ''' - result = self._values.get("include_protocol") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def include_query_string(self) -> typing.Optional[builtins.bool]: - '''If true, query string parameters are included in the cache key according to QueryStringBlacklist and QueryStringWhitelist. - - If neither is set, the entire query string is included and if false the entire query string is excluded. - - :schema: BackendConfigSpecCdnCachePolicy#includeQueryString - ''' - result = self._values.get("include_query_string") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def query_string_blacklist(self) -> typing.Optional[typing.List[builtins.str]]: - '''Names of query strint parameters to exclude from cache keys. - - All other parameters are included. Either specify QueryStringBlacklist or QueryStringWhitelist, but not both. - - :schema: BackendConfigSpecCdnCachePolicy#queryStringBlacklist - ''' - result = self._values.get("query_string_blacklist") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def query_string_whitelist(self) -> typing.Optional[typing.List[builtins.str]]: - '''Names of query string parameters to include in cache keys. - - All other parameters are excluded. Either specify QueryStringBlacklist or QueryStringWhitelist, but not both. - - :schema: BackendConfigSpecCdnCachePolicy#queryStringWhitelist - ''' - result = self._values.get("query_string_whitelist") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "BackendConfigSpecCdnCachePolicy(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="comgooglecloud.BackendConfigSpecCdnNegativeCachingPolicy", - jsii_struct_bases=[], - name_mapping={"code": "code", "ttl": "ttl"}, -) -class BackendConfigSpecCdnNegativeCachingPolicy: - def __init__( - self, - *, - code: typing.Optional[jsii.Number] = None, - ttl: typing.Optional[jsii.Number] = None, - ) -> None: - '''NegativeCachingPolicy contains configuration for how negative caching is applied. - - :param code: The HTTP status code to define a TTL against. Only HTTP status codes 300, 301, 308, 404, 405, 410, 421, 451 and 501 are can be specified as values, and you cannot specify a status code more than once. - :param ttl: The TTL (in seconds) for which to cache responses with the corresponding status code. The maximum allowed value is 1800s (30 minutes), noting that infrequently accessed objects may be evicted from the cache before the defined TTL. - - :schema: BackendConfigSpecCdnNegativeCachingPolicy - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__7df89c988b317eecced15460557d2535638cb9d58470bd2e37718341ca8102b6) - check_type(argname="argument code", value=code, expected_type=type_hints["code"]) - check_type(argname="argument ttl", value=ttl, expected_type=type_hints["ttl"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if code is not None: - self._values["code"] = code - if ttl is not None: - self._values["ttl"] = ttl - - @builtins.property - def code(self) -> typing.Optional[jsii.Number]: - '''The HTTP status code to define a TTL against. - - Only HTTP status codes 300, 301, 308, 404, 405, 410, 421, 451 and 501 are can be specified as values, and you cannot specify a status code more than once. - - :schema: BackendConfigSpecCdnNegativeCachingPolicy#code - ''' - result = self._values.get("code") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def ttl(self) -> typing.Optional[jsii.Number]: - '''The TTL (in seconds) for which to cache responses with the corresponding status code. - - The maximum allowed value is 1800s (30 minutes), noting that infrequently accessed objects may be evicted from the cache before the defined TTL. - - :schema: BackendConfigSpecCdnNegativeCachingPolicy#ttl - ''' - result = self._values.get("ttl") - return typing.cast(typing.Optional[jsii.Number], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "BackendConfigSpecCdnNegativeCachingPolicy(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="comgooglecloud.BackendConfigSpecCdnSignedUrlKeys", - jsii_struct_bases=[], - name_mapping={ - "key_name": "keyName", - "key_value": "keyValue", - "secret_name": "secretName", - }, -) -class BackendConfigSpecCdnSignedUrlKeys: - def __init__( - self, - *, - key_name: typing.Optional[builtins.str] = None, - key_value: typing.Optional[builtins.str] = None, - secret_name: typing.Optional[builtins.str] = None, - ) -> None: - '''SignedUrlKey represents a customer-supplied Signing Key used by Cloud CDN Signed URLs. - - :param key_name: KeyName: Name of the key. The name must be 1-63 characters long, and comply with RFC1035. Specifically, the name must be 1-63 characters long and match the regular expression ``[a-z]([-a-z0-9]*[a-z0-9])?`` which means the first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash. - :param key_value: KeyValue: 128-bit key value used for signing the URL. The key value must be a valid RFC 4648 Section 5 base64url encoded string. - :param secret_name: The name of a k8s secret which stores the 128-bit key value used for signing the URL. The key value must be a valid RFC 4648 Section 5 base64url encoded string - - :schema: BackendConfigSpecCdnSignedUrlKeys - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__c2bfc9b5d277ae2443b64ec9704ba599608ab4b41c297adb864d61ad89882fad) - check_type(argname="argument key_name", value=key_name, expected_type=type_hints["key_name"]) - check_type(argname="argument key_value", value=key_value, expected_type=type_hints["key_value"]) - check_type(argname="argument secret_name", value=secret_name, expected_type=type_hints["secret_name"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if key_name is not None: - self._values["key_name"] = key_name - if key_value is not None: - self._values["key_value"] = key_value - if secret_name is not None: - self._values["secret_name"] = secret_name - - @builtins.property - def key_name(self) -> typing.Optional[builtins.str]: - '''KeyName: Name of the key. - - The name must be 1-63 characters long, and comply with RFC1035. Specifically, the name must be 1-63 characters long and match the regular expression ``[a-z]([-a-z0-9]*[a-z0-9])?`` which means the first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash. - - :schema: BackendConfigSpecCdnSignedUrlKeys#keyName - ''' - result = self._values.get("key_name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def key_value(self) -> typing.Optional[builtins.str]: - '''KeyValue: 128-bit key value used for signing the URL. - - The key value must be a valid RFC 4648 Section 5 base64url encoded string. - - :schema: BackendConfigSpecCdnSignedUrlKeys#keyValue - ''' - result = self._values.get("key_value") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def secret_name(self) -> typing.Optional[builtins.str]: - '''The name of a k8s secret which stores the 128-bit key value used for signing the URL. - - The key value must be a valid RFC 4648 Section 5 base64url encoded string - - :schema: BackendConfigSpecCdnSignedUrlKeys#secretName - ''' - result = self._values.get("secret_name") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "BackendConfigSpecCdnSignedUrlKeys(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="comgooglecloud.BackendConfigSpecConnectionDraining", - jsii_struct_bases=[], - name_mapping={"draining_timeout_sec": "drainingTimeoutSec"}, -) -class BackendConfigSpecConnectionDraining: - def __init__( - self, - *, - draining_timeout_sec: typing.Optional[jsii.Number] = None, - ) -> None: - '''ConnectionDrainingConfig contains configuration for connection draining. - - For now the draining timeout. May manage more settings in the future. - - :param draining_timeout_sec: Draining timeout in seconds. - - :schema: BackendConfigSpecConnectionDraining - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__a8a4d781a8209b710ae791e501ffc537c4e1abe71291f6bfe94b802fde855fc0) - check_type(argname="argument draining_timeout_sec", value=draining_timeout_sec, expected_type=type_hints["draining_timeout_sec"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if draining_timeout_sec is not None: - self._values["draining_timeout_sec"] = draining_timeout_sec - - @builtins.property - def draining_timeout_sec(self) -> typing.Optional[jsii.Number]: - '''Draining timeout in seconds. - - :schema: BackendConfigSpecConnectionDraining#drainingTimeoutSec - ''' - result = self._values.get("draining_timeout_sec") - return typing.cast(typing.Optional[jsii.Number], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "BackendConfigSpecConnectionDraining(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="comgooglecloud.BackendConfigSpecCustomRequestHeaders", - jsii_struct_bases=[], - name_mapping={"headers": "headers"}, -) -class BackendConfigSpecCustomRequestHeaders: - def __init__( - self, - *, - headers: typing.Optional[typing.Sequence[builtins.str]] = None, - ) -> None: - '''CustomRequestHeadersConfig contains configuration for custom request headers. - - :param headers: - - :schema: BackendConfigSpecCustomRequestHeaders - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__8dc5d6b2f96616a24acd3ccf5a6df73b067f9250a84a34ae8d3eb2d6996a106d) - check_type(argname="argument headers", value=headers, expected_type=type_hints["headers"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if headers is not None: - self._values["headers"] = headers - - @builtins.property - def headers(self) -> typing.Optional[typing.List[builtins.str]]: - ''' - :schema: BackendConfigSpecCustomRequestHeaders#headers - ''' - result = self._values.get("headers") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "BackendConfigSpecCustomRequestHeaders(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="comgooglecloud.BackendConfigSpecCustomResponseHeaders", - jsii_struct_bases=[], - name_mapping={"headers": "headers"}, -) -class BackendConfigSpecCustomResponseHeaders: - def __init__( - self, - *, - headers: typing.Optional[typing.Sequence[builtins.str]] = None, - ) -> None: - '''CustomResponseHeadersConfig contains configuration for custom response headers. - - :param headers: - - :schema: BackendConfigSpecCustomResponseHeaders - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__3d55a2d2ade28e64a421578946506b571eb485866dc843b5f94b163bf1b36867) - check_type(argname="argument headers", value=headers, expected_type=type_hints["headers"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if headers is not None: - self._values["headers"] = headers - - @builtins.property - def headers(self) -> typing.Optional[typing.List[builtins.str]]: - ''' - :schema: BackendConfigSpecCustomResponseHeaders#headers - ''' - result = self._values.get("headers") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "BackendConfigSpecCustomResponseHeaders(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="comgooglecloud.BackendConfigSpecHealthCheck", - jsii_struct_bases=[], - name_mapping={ - "check_interval_sec": "checkIntervalSec", - "healthy_threshold": "healthyThreshold", - "port": "port", - "request_path": "requestPath", - "timeout_sec": "timeoutSec", - "type": "type", - "unhealthy_threshold": "unhealthyThreshold", - }, -) -class BackendConfigSpecHealthCheck: - def __init__( - self, - *, - check_interval_sec: typing.Optional[jsii.Number] = None, - healthy_threshold: typing.Optional[jsii.Number] = None, - port: typing.Optional[jsii.Number] = None, - request_path: typing.Optional[builtins.str] = None, - timeout_sec: typing.Optional[jsii.Number] = None, - type: typing.Optional[builtins.str] = None, - unhealthy_threshold: typing.Optional[jsii.Number] = None, - ) -> None: - '''HealthCheckConfig contains configuration for the health check. - - :param check_interval_sec: CheckIntervalSec is a health check parameter. See https://cloud.google.com/compute/docs/reference/rest/v1/healthChecks. - :param healthy_threshold: HealthyThreshold is a health check parameter. See https://cloud.google.com/compute/docs/reference/rest/v1/healthChecks. - :param port: Port is a health check parameter. See https://cloud.google.com/compute/docs/reference/rest/v1/healthChecks. If Port is used, the controller updates portSpecification as well - :param request_path: RequestPath is a health check parameter. See https://cloud.google.com/compute/docs/reference/rest/v1/healthChecks. - :param timeout_sec: TimeoutSec is a health check parameter. See https://cloud.google.com/compute/docs/reference/rest/v1/healthChecks. - :param type: Type is a health check parameter. See https://cloud.google.com/compute/docs/reference/rest/v1/healthChecks. - :param unhealthy_threshold: UnhealthyThreshold is a health check parameter. See https://cloud.google.com/compute/docs/reference/rest/v1/healthChecks. - - :schema: BackendConfigSpecHealthCheck - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__79c151f1f31cafead3943aeaed93e335f4e87ceb8da1e792180414251cfe761a) - check_type(argname="argument check_interval_sec", value=check_interval_sec, expected_type=type_hints["check_interval_sec"]) - check_type(argname="argument healthy_threshold", value=healthy_threshold, expected_type=type_hints["healthy_threshold"]) - check_type(argname="argument port", value=port, expected_type=type_hints["port"]) - check_type(argname="argument request_path", value=request_path, expected_type=type_hints["request_path"]) - check_type(argname="argument timeout_sec", value=timeout_sec, expected_type=type_hints["timeout_sec"]) - check_type(argname="argument type", value=type, expected_type=type_hints["type"]) - check_type(argname="argument unhealthy_threshold", value=unhealthy_threshold, expected_type=type_hints["unhealthy_threshold"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if check_interval_sec is not None: - self._values["check_interval_sec"] = check_interval_sec - if healthy_threshold is not None: - self._values["healthy_threshold"] = healthy_threshold - if port is not None: - self._values["port"] = port - if request_path is not None: - self._values["request_path"] = request_path - if timeout_sec is not None: - self._values["timeout_sec"] = timeout_sec - if type is not None: - self._values["type"] = type - if unhealthy_threshold is not None: - self._values["unhealthy_threshold"] = unhealthy_threshold - - @builtins.property - def check_interval_sec(self) -> typing.Optional[jsii.Number]: - '''CheckIntervalSec is a health check parameter. - - See https://cloud.google.com/compute/docs/reference/rest/v1/healthChecks. - - :schema: BackendConfigSpecHealthCheck#checkIntervalSec - ''' - result = self._values.get("check_interval_sec") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def healthy_threshold(self) -> typing.Optional[jsii.Number]: - '''HealthyThreshold is a health check parameter. - - See https://cloud.google.com/compute/docs/reference/rest/v1/healthChecks. - - :schema: BackendConfigSpecHealthCheck#healthyThreshold - ''' - result = self._values.get("healthy_threshold") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def port(self) -> typing.Optional[jsii.Number]: - '''Port is a health check parameter. - - See https://cloud.google.com/compute/docs/reference/rest/v1/healthChecks. If Port is used, the controller updates portSpecification as well - - :schema: BackendConfigSpecHealthCheck#port - ''' - result = self._values.get("port") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def request_path(self) -> typing.Optional[builtins.str]: - '''RequestPath is a health check parameter. - - See https://cloud.google.com/compute/docs/reference/rest/v1/healthChecks. - - :schema: BackendConfigSpecHealthCheck#requestPath - ''' - result = self._values.get("request_path") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def timeout_sec(self) -> typing.Optional[jsii.Number]: - '''TimeoutSec is a health check parameter. - - See https://cloud.google.com/compute/docs/reference/rest/v1/healthChecks. - - :schema: BackendConfigSpecHealthCheck#timeoutSec - ''' - result = self._values.get("timeout_sec") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def type(self) -> typing.Optional[builtins.str]: - '''Type is a health check parameter. - - See https://cloud.google.com/compute/docs/reference/rest/v1/healthChecks. - - :schema: BackendConfigSpecHealthCheck#type - ''' - result = self._values.get("type") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def unhealthy_threshold(self) -> typing.Optional[jsii.Number]: - '''UnhealthyThreshold is a health check parameter. - - See https://cloud.google.com/compute/docs/reference/rest/v1/healthChecks. - - :schema: BackendConfigSpecHealthCheck#unhealthyThreshold - ''' - result = self._values.get("unhealthy_threshold") - return typing.cast(typing.Optional[jsii.Number], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "BackendConfigSpecHealthCheck(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="comgooglecloud.BackendConfigSpecIap", - jsii_struct_bases=[], - name_mapping={ - "enabled": "enabled", - "oauthclient_credentials": "oauthclientCredentials", - }, -) -class BackendConfigSpecIap: - def __init__( - self, - *, - enabled: builtins.bool, - oauthclient_credentials: typing.Optional[typing.Union["BackendConfigSpecIapOauthclientCredentials", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''IAPConfig contains configuration for IAP-enabled backends. - - :param enabled: - :param oauthclient_credentials: OAuthClientCredentials contains credentials for a single IAP-enabled backend. - - :schema: BackendConfigSpecIap - ''' - if isinstance(oauthclient_credentials, dict): - oauthclient_credentials = BackendConfigSpecIapOauthclientCredentials(**oauthclient_credentials) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__13c7a07f21084397e395ce02eb15e5467ad5a76b4b555f0d12b8d64cd9eb3a84) - check_type(argname="argument enabled", value=enabled, expected_type=type_hints["enabled"]) - check_type(argname="argument oauthclient_credentials", value=oauthclient_credentials, expected_type=type_hints["oauthclient_credentials"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "enabled": enabled, - } - if oauthclient_credentials is not None: - self._values["oauthclient_credentials"] = oauthclient_credentials - - @builtins.property - def enabled(self) -> builtins.bool: - ''' - :schema: BackendConfigSpecIap#enabled - ''' - result = self._values.get("enabled") - assert result is not None, "Required property 'enabled' is missing" - return typing.cast(builtins.bool, result) - - @builtins.property - def oauthclient_credentials( - self, - ) -> typing.Optional["BackendConfigSpecIapOauthclientCredentials"]: - '''OAuthClientCredentials contains credentials for a single IAP-enabled backend. - - :schema: BackendConfigSpecIap#oauthclientCredentials - ''' - result = self._values.get("oauthclient_credentials") - return typing.cast(typing.Optional["BackendConfigSpecIapOauthclientCredentials"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "BackendConfigSpecIap(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="comgooglecloud.BackendConfigSpecIapOauthclientCredentials", - jsii_struct_bases=[], - name_mapping={ - "secret_name": "secretName", - "client_id": "clientId", - "client_secret": "clientSecret", - }, -) -class BackendConfigSpecIapOauthclientCredentials: - def __init__( - self, - *, - secret_name: builtins.str, - client_id: typing.Optional[builtins.str] = None, - client_secret: typing.Optional[builtins.str] = None, - ) -> None: - '''OAuthClientCredentials contains credentials for a single IAP-enabled backend. - - :param secret_name: The name of a k8s secret which stores the OAuth client id & secret. - :param client_id: Direct reference to OAuth client id. - :param client_secret: Direct reference to OAuth client secret. - - :schema: BackendConfigSpecIapOauthclientCredentials - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__9ce01ce36f37e0da11c74ffa5ee924df4b65d1e3adbf2ea4b16241b79f60c21e) - check_type(argname="argument secret_name", value=secret_name, expected_type=type_hints["secret_name"]) - check_type(argname="argument client_id", value=client_id, expected_type=type_hints["client_id"]) - check_type(argname="argument client_secret", value=client_secret, expected_type=type_hints["client_secret"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "secret_name": secret_name, - } - if client_id is not None: - self._values["client_id"] = client_id - if client_secret is not None: - self._values["client_secret"] = client_secret - - @builtins.property - def secret_name(self) -> builtins.str: - '''The name of a k8s secret which stores the OAuth client id & secret. - - :schema: BackendConfigSpecIapOauthclientCredentials#secretName - ''' - result = self._values.get("secret_name") - assert result is not None, "Required property 'secret_name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def client_id(self) -> typing.Optional[builtins.str]: - '''Direct reference to OAuth client id. - - :schema: BackendConfigSpecIapOauthclientCredentials#clientID - ''' - result = self._values.get("client_id") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def client_secret(self) -> typing.Optional[builtins.str]: - '''Direct reference to OAuth client secret. - - :schema: BackendConfigSpecIapOauthclientCredentials#clientSecret - ''' - result = self._values.get("client_secret") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "BackendConfigSpecIapOauthclientCredentials(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="comgooglecloud.BackendConfigSpecLogging", - jsii_struct_bases=[], - name_mapping={"enable": "enable", "sample_rate": "sampleRate"}, -) -class BackendConfigSpecLogging: - def __init__( - self, - *, - enable: typing.Optional[builtins.bool] = None, - sample_rate: typing.Optional[jsii.Number] = None, - ) -> None: - '''LogConfig contains configuration for logging. - - :param enable: This field denotes whether to enable logging for the load balancer traffic served by this backend service. - :param sample_rate: This field can only be specified if logging is enabled for this backend service. The value of the field must be in [0, 1]. This configures the sampling rate of requests to the load balancer where 1.0 means all logged requests are reported and 0.0 means no logged requests are reported. The default value is 1.0. - - :schema: BackendConfigSpecLogging - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__70de348aa7cf778b7313e13ebebbfdd0982a935c020de62a80311862fc6623a9) - check_type(argname="argument enable", value=enable, expected_type=type_hints["enable"]) - check_type(argname="argument sample_rate", value=sample_rate, expected_type=type_hints["sample_rate"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if enable is not None: - self._values["enable"] = enable - if sample_rate is not None: - self._values["sample_rate"] = sample_rate - - @builtins.property - def enable(self) -> typing.Optional[builtins.bool]: - '''This field denotes whether to enable logging for the load balancer traffic served by this backend service. - - :schema: BackendConfigSpecLogging#enable - ''' - result = self._values.get("enable") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def sample_rate(self) -> typing.Optional[jsii.Number]: - '''This field can only be specified if logging is enabled for this backend service. - - The value of the field must be in [0, 1]. This configures the sampling rate of requests to the load balancer where 1.0 means all logged requests are reported and 0.0 means no logged requests are reported. The default value is 1.0. - - :schema: BackendConfigSpecLogging#sampleRate - ''' - result = self._values.get("sample_rate") - return typing.cast(typing.Optional[jsii.Number], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "BackendConfigSpecLogging(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="comgooglecloud.BackendConfigSpecSecurityPolicy", - jsii_struct_bases=[], - name_mapping={"name": "name"}, -) -class BackendConfigSpecSecurityPolicy: - def __init__(self, *, name: builtins.str) -> None: - '''SecurityPolicyConfig contains configuration for CloudArmor-enabled backends. - - If not specified, the controller will not reconcile the security policy configuration. In other words, users can make changes in GCE without the controller overwriting them. - - :param name: Name of the security policy that should be associated. If set to empty, the existing security policy on the backend will be removed. - - :schema: BackendConfigSpecSecurityPolicy - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__98ab3b68c0a293fb2cbc562276ebfc79835049626e8b0cd436f56437f7ef2aad) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "name": name, - } - - @builtins.property - def name(self) -> builtins.str: - '''Name of the security policy that should be associated. - - If set to empty, the existing security policy on the backend will be removed. - - :schema: BackendConfigSpecSecurityPolicy#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "BackendConfigSpecSecurityPolicy(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="comgooglecloud.BackendConfigSpecSessionAffinity", - jsii_struct_bases=[], - name_mapping={ - "affinity_cookie_ttl_sec": "affinityCookieTtlSec", - "affinity_type": "affinityType", - }, -) -class BackendConfigSpecSessionAffinity: - def __init__( - self, - *, - affinity_cookie_ttl_sec: typing.Optional[jsii.Number] = None, - affinity_type: typing.Optional[builtins.str] = None, - ) -> None: - '''SessionAffinityConfig contains configuration for stickiness parameters. - - :param affinity_cookie_ttl_sec: - :param affinity_type: - - :schema: BackendConfigSpecSessionAffinity - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__12b36eeaa8e78922a88283ed58641b01eb9642275277cb5d79c87068d3e196b8) - check_type(argname="argument affinity_cookie_ttl_sec", value=affinity_cookie_ttl_sec, expected_type=type_hints["affinity_cookie_ttl_sec"]) - check_type(argname="argument affinity_type", value=affinity_type, expected_type=type_hints["affinity_type"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if affinity_cookie_ttl_sec is not None: - self._values["affinity_cookie_ttl_sec"] = affinity_cookie_ttl_sec - if affinity_type is not None: - self._values["affinity_type"] = affinity_type - - @builtins.property - def affinity_cookie_ttl_sec(self) -> typing.Optional[jsii.Number]: - ''' - :schema: BackendConfigSpecSessionAffinity#affinityCookieTtlSec - ''' - result = self._values.get("affinity_cookie_ttl_sec") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def affinity_type(self) -> typing.Optional[builtins.str]: - ''' - :schema: BackendConfigSpecSessionAffinity#affinityType - ''' - result = self._values.get("affinity_type") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "BackendConfigSpecSessionAffinity(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class BackendConfigV1Beta1( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="comgooglecloud.BackendConfigV1Beta1", -): - ''' - :schema: BackendConfigV1Beta1 - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[_cdk8s_d3d9af27.ApiObjectMetadata, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["BackendConfigV1Beta1Spec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "BackendConfigV1Beta1" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param metadata: - :param spec: BackendConfigSpec is the spec for a BackendConfig resource. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__344b0717d420cfea1a675b9b85d42abd06963df4f4e2b6703b26b6c888941945) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = BackendConfigV1Beta1Props(metadata=metadata, spec=spec) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - metadata: typing.Optional[typing.Union[_cdk8s_d3d9af27.ApiObjectMetadata, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["BackendConfigV1Beta1Spec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "BackendConfigV1Beta1". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param metadata: - :param spec: BackendConfigSpec is the spec for a BackendConfig resource. - ''' - props = BackendConfigV1Beta1Props(metadata=metadata, spec=spec) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "BackendConfigV1Beta1".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="comgooglecloud.BackendConfigV1Beta1Props", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata", "spec": "spec"}, -) -class BackendConfigV1Beta1Props: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union[_cdk8s_d3d9af27.ApiObjectMetadata, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["BackendConfigV1Beta1Spec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - ''' - :param metadata: - :param spec: BackendConfigSpec is the spec for a BackendConfig resource. - - :schema: BackendConfigV1Beta1 - ''' - if isinstance(metadata, dict): - metadata = _cdk8s_d3d9af27.ApiObjectMetadata(**metadata) - if isinstance(spec, dict): - spec = BackendConfigV1Beta1Spec(**spec) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__f97dd20787fe9d41b4c4414f7cf16853f3f154133fed2b3101de407e38a242f6) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - if spec is not None: - self._values["spec"] = spec - - @builtins.property - def metadata(self) -> typing.Optional[_cdk8s_d3d9af27.ApiObjectMetadata]: - ''' - :schema: BackendConfigV1Beta1#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional[_cdk8s_d3d9af27.ApiObjectMetadata], result) - - @builtins.property - def spec(self) -> typing.Optional["BackendConfigV1Beta1Spec"]: - '''BackendConfigSpec is the spec for a BackendConfig resource. - - :schema: BackendConfigV1Beta1#spec - ''' - result = self._values.get("spec") - return typing.cast(typing.Optional["BackendConfigV1Beta1Spec"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "BackendConfigV1Beta1Props(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="comgooglecloud.BackendConfigV1Beta1Spec", - jsii_struct_bases=[], - name_mapping={ - "cdn": "cdn", - "connection_draining": "connectionDraining", - "custom_request_headers": "customRequestHeaders", - "health_check": "healthCheck", - "iap": "iap", - "security_policy": "securityPolicy", - "session_affinity": "sessionAffinity", - "timeout_sec": "timeoutSec", - }, -) -class BackendConfigV1Beta1Spec: - def __init__( - self, - *, - cdn: typing.Optional[typing.Union["BackendConfigV1Beta1SpecCdn", typing.Dict[builtins.str, typing.Any]]] = None, - connection_draining: typing.Optional[typing.Union["BackendConfigV1Beta1SpecConnectionDraining", typing.Dict[builtins.str, typing.Any]]] = None, - custom_request_headers: typing.Optional[typing.Union["BackendConfigV1Beta1SpecCustomRequestHeaders", typing.Dict[builtins.str, typing.Any]]] = None, - health_check: typing.Optional[typing.Union["BackendConfigV1Beta1SpecHealthCheck", typing.Dict[builtins.str, typing.Any]]] = None, - iap: typing.Optional[typing.Union["BackendConfigV1Beta1SpecIap", typing.Dict[builtins.str, typing.Any]]] = None, - security_policy: typing.Optional[typing.Union["BackendConfigV1Beta1SpecSecurityPolicy", typing.Dict[builtins.str, typing.Any]]] = None, - session_affinity: typing.Optional[typing.Union["BackendConfigV1Beta1SpecSessionAffinity", typing.Dict[builtins.str, typing.Any]]] = None, - timeout_sec: typing.Optional[jsii.Number] = None, - ) -> None: - '''BackendConfigSpec is the spec for a BackendConfig resource. - - :param cdn: CDNConfig contains configuration for CDN-enabled backends. - :param connection_draining: ConnectionDrainingConfig contains configuration for connection draining. For now the draining timeout. May manage more settings in the future. - :param custom_request_headers: CustomRequestHeadersConfig contains configuration for custom request headers. - :param health_check: HealthCheckConfig contains configuration for the health check. - :param iap: IAPConfig contains configuration for IAP-enabled backends. - :param security_policy: SecurityPolicyConfig contains configuration for CloudArmor-enabled backends. If not specified, the controller will not reconcile the security policy configuration. In other words, users can make changes in GCE without the controller overwriting them. - :param session_affinity: SessionAffinityConfig contains configuration for stickiness parameters. - :param timeout_sec: - - :schema: BackendConfigV1Beta1Spec - ''' - if isinstance(cdn, dict): - cdn = BackendConfigV1Beta1SpecCdn(**cdn) - if isinstance(connection_draining, dict): - connection_draining = BackendConfigV1Beta1SpecConnectionDraining(**connection_draining) - if isinstance(custom_request_headers, dict): - custom_request_headers = BackendConfigV1Beta1SpecCustomRequestHeaders(**custom_request_headers) - if isinstance(health_check, dict): - health_check = BackendConfigV1Beta1SpecHealthCheck(**health_check) - if isinstance(iap, dict): - iap = BackendConfigV1Beta1SpecIap(**iap) - if isinstance(security_policy, dict): - security_policy = BackendConfigV1Beta1SpecSecurityPolicy(**security_policy) - if isinstance(session_affinity, dict): - session_affinity = BackendConfigV1Beta1SpecSessionAffinity(**session_affinity) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__ce76bcc047783b5343fff4e7a4014ad78591646cde2f19b57180e83c0addac84) - check_type(argname="argument cdn", value=cdn, expected_type=type_hints["cdn"]) - check_type(argname="argument connection_draining", value=connection_draining, expected_type=type_hints["connection_draining"]) - check_type(argname="argument custom_request_headers", value=custom_request_headers, expected_type=type_hints["custom_request_headers"]) - check_type(argname="argument health_check", value=health_check, expected_type=type_hints["health_check"]) - check_type(argname="argument iap", value=iap, expected_type=type_hints["iap"]) - check_type(argname="argument security_policy", value=security_policy, expected_type=type_hints["security_policy"]) - check_type(argname="argument session_affinity", value=session_affinity, expected_type=type_hints["session_affinity"]) - check_type(argname="argument timeout_sec", value=timeout_sec, expected_type=type_hints["timeout_sec"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if cdn is not None: - self._values["cdn"] = cdn - if connection_draining is not None: - self._values["connection_draining"] = connection_draining - if custom_request_headers is not None: - self._values["custom_request_headers"] = custom_request_headers - if health_check is not None: - self._values["health_check"] = health_check - if iap is not None: - self._values["iap"] = iap - if security_policy is not None: - self._values["security_policy"] = security_policy - if session_affinity is not None: - self._values["session_affinity"] = session_affinity - if timeout_sec is not None: - self._values["timeout_sec"] = timeout_sec - - @builtins.property - def cdn(self) -> typing.Optional["BackendConfigV1Beta1SpecCdn"]: - '''CDNConfig contains configuration for CDN-enabled backends. - - :schema: BackendConfigV1Beta1Spec#cdn - ''' - result = self._values.get("cdn") - return typing.cast(typing.Optional["BackendConfigV1Beta1SpecCdn"], result) - - @builtins.property - def connection_draining( - self, - ) -> typing.Optional["BackendConfigV1Beta1SpecConnectionDraining"]: - '''ConnectionDrainingConfig contains configuration for connection draining. - - For now the draining timeout. May manage more settings in the future. - - :schema: BackendConfigV1Beta1Spec#connectionDraining - ''' - result = self._values.get("connection_draining") - return typing.cast(typing.Optional["BackendConfigV1Beta1SpecConnectionDraining"], result) - - @builtins.property - def custom_request_headers( - self, - ) -> typing.Optional["BackendConfigV1Beta1SpecCustomRequestHeaders"]: - '''CustomRequestHeadersConfig contains configuration for custom request headers. - - :schema: BackendConfigV1Beta1Spec#customRequestHeaders - ''' - result = self._values.get("custom_request_headers") - return typing.cast(typing.Optional["BackendConfigV1Beta1SpecCustomRequestHeaders"], result) - - @builtins.property - def health_check(self) -> typing.Optional["BackendConfigV1Beta1SpecHealthCheck"]: - '''HealthCheckConfig contains configuration for the health check. - - :schema: BackendConfigV1Beta1Spec#healthCheck - ''' - result = self._values.get("health_check") - return typing.cast(typing.Optional["BackendConfigV1Beta1SpecHealthCheck"], result) - - @builtins.property - def iap(self) -> typing.Optional["BackendConfigV1Beta1SpecIap"]: - '''IAPConfig contains configuration for IAP-enabled backends. - - :schema: BackendConfigV1Beta1Spec#iap - ''' - result = self._values.get("iap") - return typing.cast(typing.Optional["BackendConfigV1Beta1SpecIap"], result) - - @builtins.property - def security_policy( - self, - ) -> typing.Optional["BackendConfigV1Beta1SpecSecurityPolicy"]: - '''SecurityPolicyConfig contains configuration for CloudArmor-enabled backends. - - If not specified, the controller will not reconcile the security policy configuration. In other words, users can make changes in GCE without the controller overwriting them. - - :schema: BackendConfigV1Beta1Spec#securityPolicy - ''' - result = self._values.get("security_policy") - return typing.cast(typing.Optional["BackendConfigV1Beta1SpecSecurityPolicy"], result) - - @builtins.property - def session_affinity( - self, - ) -> typing.Optional["BackendConfigV1Beta1SpecSessionAffinity"]: - '''SessionAffinityConfig contains configuration for stickiness parameters. - - :schema: BackendConfigV1Beta1Spec#sessionAffinity - ''' - result = self._values.get("session_affinity") - return typing.cast(typing.Optional["BackendConfigV1Beta1SpecSessionAffinity"], result) - - @builtins.property - def timeout_sec(self) -> typing.Optional[jsii.Number]: - ''' - :schema: BackendConfigV1Beta1Spec#timeoutSec - ''' - result = self._values.get("timeout_sec") - return typing.cast(typing.Optional[jsii.Number], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "BackendConfigV1Beta1Spec(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="comgooglecloud.BackendConfigV1Beta1SpecCdn", - jsii_struct_bases=[], - name_mapping={"enabled": "enabled", "cache_policy": "cachePolicy"}, -) -class BackendConfigV1Beta1SpecCdn: - def __init__( - self, - *, - enabled: builtins.bool, - cache_policy: typing.Optional[typing.Union["BackendConfigV1Beta1SpecCdnCachePolicy", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''CDNConfig contains configuration for CDN-enabled backends. - - :param enabled: - :param cache_policy: CacheKeyPolicy contains configuration for how requests to a CDN-enabled backend are cached. - - :schema: BackendConfigV1Beta1SpecCdn - ''' - if isinstance(cache_policy, dict): - cache_policy = BackendConfigV1Beta1SpecCdnCachePolicy(**cache_policy) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__7356f4b96f97aa57f7f1d1e7d1ee04d987bafe3588ef34aee1d27a535380fb82) - check_type(argname="argument enabled", value=enabled, expected_type=type_hints["enabled"]) - check_type(argname="argument cache_policy", value=cache_policy, expected_type=type_hints["cache_policy"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "enabled": enabled, - } - if cache_policy is not None: - self._values["cache_policy"] = cache_policy - - @builtins.property - def enabled(self) -> builtins.bool: - ''' - :schema: BackendConfigV1Beta1SpecCdn#enabled - ''' - result = self._values.get("enabled") - assert result is not None, "Required property 'enabled' is missing" - return typing.cast(builtins.bool, result) - - @builtins.property - def cache_policy(self) -> typing.Optional["BackendConfigV1Beta1SpecCdnCachePolicy"]: - '''CacheKeyPolicy contains configuration for how requests to a CDN-enabled backend are cached. - - :schema: BackendConfigV1Beta1SpecCdn#cachePolicy - ''' - result = self._values.get("cache_policy") - return typing.cast(typing.Optional["BackendConfigV1Beta1SpecCdnCachePolicy"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "BackendConfigV1Beta1SpecCdn(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="comgooglecloud.BackendConfigV1Beta1SpecCdnCachePolicy", - jsii_struct_bases=[], - name_mapping={ - "include_host": "includeHost", - "include_protocol": "includeProtocol", - "include_query_string": "includeQueryString", - "query_string_blacklist": "queryStringBlacklist", - "query_string_whitelist": "queryStringWhitelist", - }, -) -class BackendConfigV1Beta1SpecCdnCachePolicy: - def __init__( - self, - *, - include_host: typing.Optional[builtins.bool] = None, - include_protocol: typing.Optional[builtins.bool] = None, - include_query_string: typing.Optional[builtins.bool] = None, - query_string_blacklist: typing.Optional[typing.Sequence[builtins.str]] = None, - query_string_whitelist: typing.Optional[typing.Sequence[builtins.str]] = None, - ) -> None: - '''CacheKeyPolicy contains configuration for how requests to a CDN-enabled backend are cached. - - :param include_host: If true, requests to different hosts will be cached separately. - :param include_protocol: If true, http and https requests will be cached separately. - :param include_query_string: If true, query string parameters are included in the cache key according to QueryStringBlacklist and QueryStringWhitelist. If neither is set, the entire query string is included and if false the entire query string is excluded. - :param query_string_blacklist: Names of query strint parameters to exclude from cache keys. All other parameters are included. Either specify QueryStringBlacklist or QueryStringWhitelist, but not both. - :param query_string_whitelist: Names of query string parameters to include in cache keys. All other parameters are excluded. Either specify QueryStringBlacklist or QueryStringWhitelist, but not both. - - :schema: BackendConfigV1Beta1SpecCdnCachePolicy - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__f3de908e6a83c0f93d3ad698e79d4a79b4f86b58a6f774bedbd980fbdf53e06d) - check_type(argname="argument include_host", value=include_host, expected_type=type_hints["include_host"]) - check_type(argname="argument include_protocol", value=include_protocol, expected_type=type_hints["include_protocol"]) - check_type(argname="argument include_query_string", value=include_query_string, expected_type=type_hints["include_query_string"]) - check_type(argname="argument query_string_blacklist", value=query_string_blacklist, expected_type=type_hints["query_string_blacklist"]) - check_type(argname="argument query_string_whitelist", value=query_string_whitelist, expected_type=type_hints["query_string_whitelist"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if include_host is not None: - self._values["include_host"] = include_host - if include_protocol is not None: - self._values["include_protocol"] = include_protocol - if include_query_string is not None: - self._values["include_query_string"] = include_query_string - if query_string_blacklist is not None: - self._values["query_string_blacklist"] = query_string_blacklist - if query_string_whitelist is not None: - self._values["query_string_whitelist"] = query_string_whitelist - - @builtins.property - def include_host(self) -> typing.Optional[builtins.bool]: - '''If true, requests to different hosts will be cached separately. - - :schema: BackendConfigV1Beta1SpecCdnCachePolicy#includeHost - ''' - result = self._values.get("include_host") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def include_protocol(self) -> typing.Optional[builtins.bool]: - '''If true, http and https requests will be cached separately. - - :schema: BackendConfigV1Beta1SpecCdnCachePolicy#includeProtocol - ''' - result = self._values.get("include_protocol") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def include_query_string(self) -> typing.Optional[builtins.bool]: - '''If true, query string parameters are included in the cache key according to QueryStringBlacklist and QueryStringWhitelist. - - If neither is set, the entire query string is included and if false the entire query string is excluded. - - :schema: BackendConfigV1Beta1SpecCdnCachePolicy#includeQueryString - ''' - result = self._values.get("include_query_string") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def query_string_blacklist(self) -> typing.Optional[typing.List[builtins.str]]: - '''Names of query strint parameters to exclude from cache keys. - - All other parameters are included. Either specify QueryStringBlacklist or QueryStringWhitelist, but not both. - - :schema: BackendConfigV1Beta1SpecCdnCachePolicy#queryStringBlacklist - ''' - result = self._values.get("query_string_blacklist") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def query_string_whitelist(self) -> typing.Optional[typing.List[builtins.str]]: - '''Names of query string parameters to include in cache keys. - - All other parameters are excluded. Either specify QueryStringBlacklist or QueryStringWhitelist, but not both. - - :schema: BackendConfigV1Beta1SpecCdnCachePolicy#queryStringWhitelist - ''' - result = self._values.get("query_string_whitelist") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "BackendConfigV1Beta1SpecCdnCachePolicy(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="comgooglecloud.BackendConfigV1Beta1SpecConnectionDraining", - jsii_struct_bases=[], - name_mapping={"draining_timeout_sec": "drainingTimeoutSec"}, -) -class BackendConfigV1Beta1SpecConnectionDraining: - def __init__( - self, - *, - draining_timeout_sec: typing.Optional[jsii.Number] = None, - ) -> None: - '''ConnectionDrainingConfig contains configuration for connection draining. - - For now the draining timeout. May manage more settings in the future. - - :param draining_timeout_sec: Draining timeout in seconds. - - :schema: BackendConfigV1Beta1SpecConnectionDraining - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__c6f2fcacdc49b8b8096a586cf8c3e9c44397b88e90594778bad466213d4d3f38) - check_type(argname="argument draining_timeout_sec", value=draining_timeout_sec, expected_type=type_hints["draining_timeout_sec"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if draining_timeout_sec is not None: - self._values["draining_timeout_sec"] = draining_timeout_sec - - @builtins.property - def draining_timeout_sec(self) -> typing.Optional[jsii.Number]: - '''Draining timeout in seconds. - - :schema: BackendConfigV1Beta1SpecConnectionDraining#drainingTimeoutSec - ''' - result = self._values.get("draining_timeout_sec") - return typing.cast(typing.Optional[jsii.Number], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "BackendConfigV1Beta1SpecConnectionDraining(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="comgooglecloud.BackendConfigV1Beta1SpecCustomRequestHeaders", - jsii_struct_bases=[], - name_mapping={"headers": "headers"}, -) -class BackendConfigV1Beta1SpecCustomRequestHeaders: - def __init__( - self, - *, - headers: typing.Optional[typing.Sequence[builtins.str]] = None, - ) -> None: - '''CustomRequestHeadersConfig contains configuration for custom request headers. - - :param headers: - - :schema: BackendConfigV1Beta1SpecCustomRequestHeaders - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__778f47b4768dec1ed1170f49b440363a1f9082599e4b897535aa179f840e7c2e) - check_type(argname="argument headers", value=headers, expected_type=type_hints["headers"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if headers is not None: - self._values["headers"] = headers - - @builtins.property - def headers(self) -> typing.Optional[typing.List[builtins.str]]: - ''' - :schema: BackendConfigV1Beta1SpecCustomRequestHeaders#headers - ''' - result = self._values.get("headers") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "BackendConfigV1Beta1SpecCustomRequestHeaders(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="comgooglecloud.BackendConfigV1Beta1SpecHealthCheck", - jsii_struct_bases=[], - name_mapping={ - "check_interval_sec": "checkIntervalSec", - "healthy_threshold": "healthyThreshold", - "port": "port", - "request_path": "requestPath", - "timeout_sec": "timeoutSec", - "type": "type", - "unhealthy_threshold": "unhealthyThreshold", - }, -) -class BackendConfigV1Beta1SpecHealthCheck: - def __init__( - self, - *, - check_interval_sec: typing.Optional[jsii.Number] = None, - healthy_threshold: typing.Optional[jsii.Number] = None, - port: typing.Optional[jsii.Number] = None, - request_path: typing.Optional[builtins.str] = None, - timeout_sec: typing.Optional[jsii.Number] = None, - type: typing.Optional[builtins.str] = None, - unhealthy_threshold: typing.Optional[jsii.Number] = None, - ) -> None: - '''HealthCheckConfig contains configuration for the health check. - - :param check_interval_sec: CheckIntervalSec is a health check parameter. See https://cloud.google.com/compute/docs/reference/rest/v1/healthChecks. - :param healthy_threshold: HealthyThreshold is a health check parameter. See https://cloud.google.com/compute/docs/reference/rest/v1/healthChecks. - :param port: - :param request_path: RequestPath is a health check parameter. See https://cloud.google.com/compute/docs/reference/rest/v1/healthChecks. - :param timeout_sec: TimeoutSec is a health check parameter. See https://cloud.google.com/compute/docs/reference/rest/v1/healthChecks. - :param type: Type is a health check parameter. See https://cloud.google.com/compute/docs/reference/rest/v1/healthChecks. - :param unhealthy_threshold: UnhealthyThreshold is a health check parameter. See https://cloud.google.com/compute/docs/reference/rest/v1/healthChecks. - - :schema: BackendConfigV1Beta1SpecHealthCheck - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__458b54e537fe6beecc1d6be934ee37e0a01c133bc2eaf47c216a85fda2e77928) - check_type(argname="argument check_interval_sec", value=check_interval_sec, expected_type=type_hints["check_interval_sec"]) - check_type(argname="argument healthy_threshold", value=healthy_threshold, expected_type=type_hints["healthy_threshold"]) - check_type(argname="argument port", value=port, expected_type=type_hints["port"]) - check_type(argname="argument request_path", value=request_path, expected_type=type_hints["request_path"]) - check_type(argname="argument timeout_sec", value=timeout_sec, expected_type=type_hints["timeout_sec"]) - check_type(argname="argument type", value=type, expected_type=type_hints["type"]) - check_type(argname="argument unhealthy_threshold", value=unhealthy_threshold, expected_type=type_hints["unhealthy_threshold"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if check_interval_sec is not None: - self._values["check_interval_sec"] = check_interval_sec - if healthy_threshold is not None: - self._values["healthy_threshold"] = healthy_threshold - if port is not None: - self._values["port"] = port - if request_path is not None: - self._values["request_path"] = request_path - if timeout_sec is not None: - self._values["timeout_sec"] = timeout_sec - if type is not None: - self._values["type"] = type - if unhealthy_threshold is not None: - self._values["unhealthy_threshold"] = unhealthy_threshold - - @builtins.property - def check_interval_sec(self) -> typing.Optional[jsii.Number]: - '''CheckIntervalSec is a health check parameter. - - See https://cloud.google.com/compute/docs/reference/rest/v1/healthChecks. - - :schema: BackendConfigV1Beta1SpecHealthCheck#checkIntervalSec - ''' - result = self._values.get("check_interval_sec") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def healthy_threshold(self) -> typing.Optional[jsii.Number]: - '''HealthyThreshold is a health check parameter. - - See https://cloud.google.com/compute/docs/reference/rest/v1/healthChecks. - - :schema: BackendConfigV1Beta1SpecHealthCheck#healthyThreshold - ''' - result = self._values.get("healthy_threshold") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def port(self) -> typing.Optional[jsii.Number]: - ''' - :schema: BackendConfigV1Beta1SpecHealthCheck#port - ''' - result = self._values.get("port") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def request_path(self) -> typing.Optional[builtins.str]: - '''RequestPath is a health check parameter. - - See https://cloud.google.com/compute/docs/reference/rest/v1/healthChecks. - - :schema: BackendConfigV1Beta1SpecHealthCheck#requestPath - ''' - result = self._values.get("request_path") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def timeout_sec(self) -> typing.Optional[jsii.Number]: - '''TimeoutSec is a health check parameter. - - See https://cloud.google.com/compute/docs/reference/rest/v1/healthChecks. - - :schema: BackendConfigV1Beta1SpecHealthCheck#timeoutSec - ''' - result = self._values.get("timeout_sec") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def type(self) -> typing.Optional[builtins.str]: - '''Type is a health check parameter. - - See https://cloud.google.com/compute/docs/reference/rest/v1/healthChecks. - - :schema: BackendConfigV1Beta1SpecHealthCheck#type - ''' - result = self._values.get("type") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def unhealthy_threshold(self) -> typing.Optional[jsii.Number]: - '''UnhealthyThreshold is a health check parameter. - - See https://cloud.google.com/compute/docs/reference/rest/v1/healthChecks. - - :schema: BackendConfigV1Beta1SpecHealthCheck#unhealthyThreshold - ''' - result = self._values.get("unhealthy_threshold") - return typing.cast(typing.Optional[jsii.Number], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "BackendConfigV1Beta1SpecHealthCheck(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="comgooglecloud.BackendConfigV1Beta1SpecIap", - jsii_struct_bases=[], - name_mapping={ - "enabled": "enabled", - "oauthclient_credentials": "oauthclientCredentials", - }, -) -class BackendConfigV1Beta1SpecIap: - def __init__( - self, - *, - enabled: builtins.bool, - oauthclient_credentials: typing.Optional[typing.Union["BackendConfigV1Beta1SpecIapOauthclientCredentials", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''IAPConfig contains configuration for IAP-enabled backends. - - :param enabled: - :param oauthclient_credentials: OAuthClientCredentials contains credentials for a single IAP-enabled backend. - - :schema: BackendConfigV1Beta1SpecIap - ''' - if isinstance(oauthclient_credentials, dict): - oauthclient_credentials = BackendConfigV1Beta1SpecIapOauthclientCredentials(**oauthclient_credentials) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__648ecbb43d6288293062736e62bd90212e194b4583cd093010af134205fc20ae) - check_type(argname="argument enabled", value=enabled, expected_type=type_hints["enabled"]) - check_type(argname="argument oauthclient_credentials", value=oauthclient_credentials, expected_type=type_hints["oauthclient_credentials"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "enabled": enabled, - } - if oauthclient_credentials is not None: - self._values["oauthclient_credentials"] = oauthclient_credentials - - @builtins.property - def enabled(self) -> builtins.bool: - ''' - :schema: BackendConfigV1Beta1SpecIap#enabled - ''' - result = self._values.get("enabled") - assert result is not None, "Required property 'enabled' is missing" - return typing.cast(builtins.bool, result) - - @builtins.property - def oauthclient_credentials( - self, - ) -> typing.Optional["BackendConfigV1Beta1SpecIapOauthclientCredentials"]: - '''OAuthClientCredentials contains credentials for a single IAP-enabled backend. - - :schema: BackendConfigV1Beta1SpecIap#oauthclientCredentials - ''' - result = self._values.get("oauthclient_credentials") - return typing.cast(typing.Optional["BackendConfigV1Beta1SpecIapOauthclientCredentials"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "BackendConfigV1Beta1SpecIap(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="comgooglecloud.BackendConfigV1Beta1SpecIapOauthclientCredentials", - jsii_struct_bases=[], - name_mapping={ - "secret_name": "secretName", - "client_id": "clientId", - "client_secret": "clientSecret", - }, -) -class BackendConfigV1Beta1SpecIapOauthclientCredentials: - def __init__( - self, - *, - secret_name: builtins.str, - client_id: typing.Optional[builtins.str] = None, - client_secret: typing.Optional[builtins.str] = None, - ) -> None: - '''OAuthClientCredentials contains credentials for a single IAP-enabled backend. - - :param secret_name: The name of a k8s secret which stores the OAuth client id & secret. - :param client_id: Direct reference to OAuth client id. - :param client_secret: Direct reference to OAuth client secret. - - :schema: BackendConfigV1Beta1SpecIapOauthclientCredentials - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__0dc29a4b06fd6606e4aea860922706594c9ec38e4b0615449a84ea6f91315453) - check_type(argname="argument secret_name", value=secret_name, expected_type=type_hints["secret_name"]) - check_type(argname="argument client_id", value=client_id, expected_type=type_hints["client_id"]) - check_type(argname="argument client_secret", value=client_secret, expected_type=type_hints["client_secret"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "secret_name": secret_name, - } - if client_id is not None: - self._values["client_id"] = client_id - if client_secret is not None: - self._values["client_secret"] = client_secret - - @builtins.property - def secret_name(self) -> builtins.str: - '''The name of a k8s secret which stores the OAuth client id & secret. - - :schema: BackendConfigV1Beta1SpecIapOauthclientCredentials#secretName - ''' - result = self._values.get("secret_name") - assert result is not None, "Required property 'secret_name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def client_id(self) -> typing.Optional[builtins.str]: - '''Direct reference to OAuth client id. - - :schema: BackendConfigV1Beta1SpecIapOauthclientCredentials#clientID - ''' - result = self._values.get("client_id") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def client_secret(self) -> typing.Optional[builtins.str]: - '''Direct reference to OAuth client secret. - - :schema: BackendConfigV1Beta1SpecIapOauthclientCredentials#clientSecret - ''' - result = self._values.get("client_secret") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "BackendConfigV1Beta1SpecIapOauthclientCredentials(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="comgooglecloud.BackendConfigV1Beta1SpecSecurityPolicy", - jsii_struct_bases=[], - name_mapping={"name": "name"}, -) -class BackendConfigV1Beta1SpecSecurityPolicy: - def __init__(self, *, name: builtins.str) -> None: - '''SecurityPolicyConfig contains configuration for CloudArmor-enabled backends. - - If not specified, the controller will not reconcile the security policy configuration. In other words, users can make changes in GCE without the controller overwriting them. - - :param name: Name of the security policy that should be associated. If set to empty, the existing security policy on the backend will be removed. - - :schema: BackendConfigV1Beta1SpecSecurityPolicy - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__cdce0ae495867c2f18a2d5ba1ae20e252cbd90ac9ef9d6349e5bff94e9927b27) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "name": name, - } - - @builtins.property - def name(self) -> builtins.str: - '''Name of the security policy that should be associated. - - If set to empty, the existing security policy on the backend will be removed. - - :schema: BackendConfigV1Beta1SpecSecurityPolicy#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "BackendConfigV1Beta1SpecSecurityPolicy(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="comgooglecloud.BackendConfigV1Beta1SpecSessionAffinity", - jsii_struct_bases=[], - name_mapping={ - "affinity_cookie_ttl_sec": "affinityCookieTtlSec", - "affinity_type": "affinityType", - }, -) -class BackendConfigV1Beta1SpecSessionAffinity: - def __init__( - self, - *, - affinity_cookie_ttl_sec: typing.Optional[jsii.Number] = None, - affinity_type: typing.Optional[builtins.str] = None, - ) -> None: - '''SessionAffinityConfig contains configuration for stickiness parameters. - - :param affinity_cookie_ttl_sec: - :param affinity_type: - - :schema: BackendConfigV1Beta1SpecSessionAffinity - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__4538d5a95a2d339f0245126e5974162172c3eac10c8949e1b5d01fc77dc1a8ea) - check_type(argname="argument affinity_cookie_ttl_sec", value=affinity_cookie_ttl_sec, expected_type=type_hints["affinity_cookie_ttl_sec"]) - check_type(argname="argument affinity_type", value=affinity_type, expected_type=type_hints["affinity_type"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if affinity_cookie_ttl_sec is not None: - self._values["affinity_cookie_ttl_sec"] = affinity_cookie_ttl_sec - if affinity_type is not None: - self._values["affinity_type"] = affinity_type - - @builtins.property - def affinity_cookie_ttl_sec(self) -> typing.Optional[jsii.Number]: - ''' - :schema: BackendConfigV1Beta1SpecSessionAffinity#affinityCookieTtlSec - ''' - result = self._values.get("affinity_cookie_ttl_sec") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def affinity_type(self) -> typing.Optional[builtins.str]: - ''' - :schema: BackendConfigV1Beta1SpecSessionAffinity#affinityType - ''' - result = self._values.get("affinity_type") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "BackendConfigV1Beta1SpecSessionAffinity(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -__all__ = [ - "BackendConfig", - "BackendConfigProps", - "BackendConfigSpec", - "BackendConfigSpecCdn", - "BackendConfigSpecCdnBypassCacheOnRequestHeaders", - "BackendConfigSpecCdnCachePolicy", - "BackendConfigSpecCdnNegativeCachingPolicy", - "BackendConfigSpecCdnSignedUrlKeys", - "BackendConfigSpecConnectionDraining", - "BackendConfigSpecCustomRequestHeaders", - "BackendConfigSpecCustomResponseHeaders", - "BackendConfigSpecHealthCheck", - "BackendConfigSpecIap", - "BackendConfigSpecIapOauthclientCredentials", - "BackendConfigSpecLogging", - "BackendConfigSpecSecurityPolicy", - "BackendConfigSpecSessionAffinity", - "BackendConfigV1Beta1", - "BackendConfigV1Beta1Props", - "BackendConfigV1Beta1Spec", - "BackendConfigV1Beta1SpecCdn", - "BackendConfigV1Beta1SpecCdnCachePolicy", - "BackendConfigV1Beta1SpecConnectionDraining", - "BackendConfigV1Beta1SpecCustomRequestHeaders", - "BackendConfigV1Beta1SpecHealthCheck", - "BackendConfigV1Beta1SpecIap", - "BackendConfigV1Beta1SpecIapOauthclientCredentials", - "BackendConfigV1Beta1SpecSecurityPolicy", - "BackendConfigV1Beta1SpecSessionAffinity", -] - -publication.publish() - -def _typecheckingstub__478e053b34646f2f22c316b46d46fa578352a17dc0965e0733c3edbb3af21e40( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[_cdk8s_d3d9af27.ApiObjectMetadata, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[BackendConfigSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__e8e7a740219c8083806cfb80142ff0861537e30e169b215266207dac2fc18296( - *, - metadata: typing.Optional[typing.Union[_cdk8s_d3d9af27.ApiObjectMetadata, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[BackendConfigSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__ed3aaa52e5e9ad8c8ce8edc12e3f41b1303bc88c9e4d6d58ade780d4014f2019( - *, - cdn: typing.Optional[typing.Union[BackendConfigSpecCdn, typing.Dict[builtins.str, typing.Any]]] = None, - connection_draining: typing.Optional[typing.Union[BackendConfigSpecConnectionDraining, typing.Dict[builtins.str, typing.Any]]] = None, - custom_request_headers: typing.Optional[typing.Union[BackendConfigSpecCustomRequestHeaders, typing.Dict[builtins.str, typing.Any]]] = None, - custom_response_headers: typing.Optional[typing.Union[BackendConfigSpecCustomResponseHeaders, typing.Dict[builtins.str, typing.Any]]] = None, - health_check: typing.Optional[typing.Union[BackendConfigSpecHealthCheck, typing.Dict[builtins.str, typing.Any]]] = None, - iap: typing.Optional[typing.Union[BackendConfigSpecIap, typing.Dict[builtins.str, typing.Any]]] = None, - logging: typing.Optional[typing.Union[BackendConfigSpecLogging, typing.Dict[builtins.str, typing.Any]]] = None, - security_policy: typing.Optional[typing.Union[BackendConfigSpecSecurityPolicy, typing.Dict[builtins.str, typing.Any]]] = None, - session_affinity: typing.Optional[typing.Union[BackendConfigSpecSessionAffinity, typing.Dict[builtins.str, typing.Any]]] = None, - timeout_sec: typing.Optional[jsii.Number] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__622a4ce6676e87a1185b566cba87d43a91644ca1bc40dd893f4fac498eb82531( - *, - enabled: builtins.bool, - bypass_cache_on_request_headers: typing.Optional[typing.Sequence[typing.Union[BackendConfigSpecCdnBypassCacheOnRequestHeaders, typing.Dict[builtins.str, typing.Any]]]] = None, - cache_mode: typing.Optional[builtins.str] = None, - cache_policy: typing.Optional[typing.Union[BackendConfigSpecCdnCachePolicy, typing.Dict[builtins.str, typing.Any]]] = None, - client_ttl: typing.Optional[jsii.Number] = None, - default_ttl: typing.Optional[jsii.Number] = None, - max_ttl: typing.Optional[jsii.Number] = None, - negative_caching: typing.Optional[builtins.bool] = None, - negative_caching_policy: typing.Optional[typing.Sequence[typing.Union[BackendConfigSpecCdnNegativeCachingPolicy, typing.Dict[builtins.str, typing.Any]]]] = None, - request_coalescing: typing.Optional[builtins.bool] = None, - serve_while_stale: typing.Optional[jsii.Number] = None, - signed_url_cache_max_age_sec: typing.Optional[jsii.Number] = None, - signed_url_keys: typing.Optional[typing.Sequence[typing.Union[BackendConfigSpecCdnSignedUrlKeys, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__29143d667e3ffdd72b7660770c144cc283425c836b9727b5dce6d9ad54507331( - *, - header_name: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__58baffb66190c78e8d4c5f00de26d9625e7d2a0a6d8e74e5662211067b562a23( - *, - include_host: typing.Optional[builtins.bool] = None, - include_protocol: typing.Optional[builtins.bool] = None, - include_query_string: typing.Optional[builtins.bool] = None, - query_string_blacklist: typing.Optional[typing.Sequence[builtins.str]] = None, - query_string_whitelist: typing.Optional[typing.Sequence[builtins.str]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__7df89c988b317eecced15460557d2535638cb9d58470bd2e37718341ca8102b6( - *, - code: typing.Optional[jsii.Number] = None, - ttl: typing.Optional[jsii.Number] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__c2bfc9b5d277ae2443b64ec9704ba599608ab4b41c297adb864d61ad89882fad( - *, - key_name: typing.Optional[builtins.str] = None, - key_value: typing.Optional[builtins.str] = None, - secret_name: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__a8a4d781a8209b710ae791e501ffc537c4e1abe71291f6bfe94b802fde855fc0( - *, - draining_timeout_sec: typing.Optional[jsii.Number] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__8dc5d6b2f96616a24acd3ccf5a6df73b067f9250a84a34ae8d3eb2d6996a106d( - *, - headers: typing.Optional[typing.Sequence[builtins.str]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__3d55a2d2ade28e64a421578946506b571eb485866dc843b5f94b163bf1b36867( - *, - headers: typing.Optional[typing.Sequence[builtins.str]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__79c151f1f31cafead3943aeaed93e335f4e87ceb8da1e792180414251cfe761a( - *, - check_interval_sec: typing.Optional[jsii.Number] = None, - healthy_threshold: typing.Optional[jsii.Number] = None, - port: typing.Optional[jsii.Number] = None, - request_path: typing.Optional[builtins.str] = None, - timeout_sec: typing.Optional[jsii.Number] = None, - type: typing.Optional[builtins.str] = None, - unhealthy_threshold: typing.Optional[jsii.Number] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__13c7a07f21084397e395ce02eb15e5467ad5a76b4b555f0d12b8d64cd9eb3a84( - *, - enabled: builtins.bool, - oauthclient_credentials: typing.Optional[typing.Union[BackendConfigSpecIapOauthclientCredentials, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__9ce01ce36f37e0da11c74ffa5ee924df4b65d1e3adbf2ea4b16241b79f60c21e( - *, - secret_name: builtins.str, - client_id: typing.Optional[builtins.str] = None, - client_secret: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__70de348aa7cf778b7313e13ebebbfdd0982a935c020de62a80311862fc6623a9( - *, - enable: typing.Optional[builtins.bool] = None, - sample_rate: typing.Optional[jsii.Number] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__98ab3b68c0a293fb2cbc562276ebfc79835049626e8b0cd436f56437f7ef2aad( - *, - name: builtins.str, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__12b36eeaa8e78922a88283ed58641b01eb9642275277cb5d79c87068d3e196b8( - *, - affinity_cookie_ttl_sec: typing.Optional[jsii.Number] = None, - affinity_type: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__344b0717d420cfea1a675b9b85d42abd06963df4f4e2b6703b26b6c888941945( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[_cdk8s_d3d9af27.ApiObjectMetadata, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[BackendConfigV1Beta1Spec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__f97dd20787fe9d41b4c4414f7cf16853f3f154133fed2b3101de407e38a242f6( - *, - metadata: typing.Optional[typing.Union[_cdk8s_d3d9af27.ApiObjectMetadata, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[BackendConfigV1Beta1Spec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__ce76bcc047783b5343fff4e7a4014ad78591646cde2f19b57180e83c0addac84( - *, - cdn: typing.Optional[typing.Union[BackendConfigV1Beta1SpecCdn, typing.Dict[builtins.str, typing.Any]]] = None, - connection_draining: typing.Optional[typing.Union[BackendConfigV1Beta1SpecConnectionDraining, typing.Dict[builtins.str, typing.Any]]] = None, - custom_request_headers: typing.Optional[typing.Union[BackendConfigV1Beta1SpecCustomRequestHeaders, typing.Dict[builtins.str, typing.Any]]] = None, - health_check: typing.Optional[typing.Union[BackendConfigV1Beta1SpecHealthCheck, typing.Dict[builtins.str, typing.Any]]] = None, - iap: typing.Optional[typing.Union[BackendConfigV1Beta1SpecIap, typing.Dict[builtins.str, typing.Any]]] = None, - security_policy: typing.Optional[typing.Union[BackendConfigV1Beta1SpecSecurityPolicy, typing.Dict[builtins.str, typing.Any]]] = None, - session_affinity: typing.Optional[typing.Union[BackendConfigV1Beta1SpecSessionAffinity, typing.Dict[builtins.str, typing.Any]]] = None, - timeout_sec: typing.Optional[jsii.Number] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__7356f4b96f97aa57f7f1d1e7d1ee04d987bafe3588ef34aee1d27a535380fb82( - *, - enabled: builtins.bool, - cache_policy: typing.Optional[typing.Union[BackendConfigV1Beta1SpecCdnCachePolicy, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__f3de908e6a83c0f93d3ad698e79d4a79b4f86b58a6f774bedbd980fbdf53e06d( - *, - include_host: typing.Optional[builtins.bool] = None, - include_protocol: typing.Optional[builtins.bool] = None, - include_query_string: typing.Optional[builtins.bool] = None, - query_string_blacklist: typing.Optional[typing.Sequence[builtins.str]] = None, - query_string_whitelist: typing.Optional[typing.Sequence[builtins.str]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__c6f2fcacdc49b8b8096a586cf8c3e9c44397b88e90594778bad466213d4d3f38( - *, - draining_timeout_sec: typing.Optional[jsii.Number] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__778f47b4768dec1ed1170f49b440363a1f9082599e4b897535aa179f840e7c2e( - *, - headers: typing.Optional[typing.Sequence[builtins.str]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__458b54e537fe6beecc1d6be934ee37e0a01c133bc2eaf47c216a85fda2e77928( - *, - check_interval_sec: typing.Optional[jsii.Number] = None, - healthy_threshold: typing.Optional[jsii.Number] = None, - port: typing.Optional[jsii.Number] = None, - request_path: typing.Optional[builtins.str] = None, - timeout_sec: typing.Optional[jsii.Number] = None, - type: typing.Optional[builtins.str] = None, - unhealthy_threshold: typing.Optional[jsii.Number] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__648ecbb43d6288293062736e62bd90212e194b4583cd093010af134205fc20ae( - *, - enabled: builtins.bool, - oauthclient_credentials: typing.Optional[typing.Union[BackendConfigV1Beta1SpecIapOauthclientCredentials, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__0dc29a4b06fd6606e4aea860922706594c9ec38e4b0615449a84ea6f91315453( - *, - secret_name: builtins.str, - client_id: typing.Optional[builtins.str] = None, - client_secret: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__cdce0ae495867c2f18a2d5ba1ae20e252cbd90ac9ef9d6349e5bff94e9927b27( - *, - name: builtins.str, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__4538d5a95a2d339f0245126e5974162172c3eac10c8949e1b5d01fc77dc1a8ea( - *, - affinity_cookie_ttl_sec: typing.Optional[jsii.Number] = None, - affinity_type: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass diff --git a/deployments/sequencer/imports/com/google/cloud/_jsii/__init__.py b/deployments/sequencer/imports/com/google/cloud/_jsii/__init__.py deleted file mode 100644 index 3d11a66117c..00000000000 --- a/deployments/sequencer/imports/com/google/cloud/_jsii/__init__.py +++ /dev/null @@ -1,42 +0,0 @@ -from pkgutil import extend_path -__path__ = extend_path(__path__, __name__) - -import abc -import builtins -import datetime -import enum -import typing - -import jsii -import publication -import typing_extensions - -import typeguard -from importlib.metadata import version as _metadata_package_version -TYPEGUARD_MAJOR_VERSION = int(_metadata_package_version('typeguard').split('.')[0]) - -def check_type(argname: str, value: object, expected_type: typing.Any) -> typing.Any: - if TYPEGUARD_MAJOR_VERSION <= 2: - return typeguard.check_type(argname=argname, value=value, expected_type=expected_type) # type:ignore - else: - if isinstance(value, jsii._reference_map.InterfaceDynamicProxy): # pyright: ignore [reportAttributeAccessIssue] - pass - else: - if TYPEGUARD_MAJOR_VERSION == 3: - typeguard.config.collection_check_strategy = typeguard.CollectionCheckStrategy.ALL_ITEMS # type:ignore - typeguard.check_type(value=value, expected_type=expected_type) # type:ignore - else: - typeguard.check_type(value=value, expected_type=expected_type, collection_check_strategy=typeguard.CollectionCheckStrategy.ALL_ITEMS) # type:ignore - -import cdk8s._jsii -import constructs._jsii - -__jsii_assembly__ = jsii.JSIIAssembly.load( - "comgooglecloud", "0.0.0", __name__[0:-6], "comgooglecloud@0.0.0.jsii.tgz" -) - -__all__ = [ - "__jsii_assembly__", -] - -publication.publish() diff --git a/deployments/sequencer/imports/com/google/cloud/_jsii/comgooglecloud@0.0.0.jsii.tgz b/deployments/sequencer/imports/com/google/cloud/_jsii/comgooglecloud@0.0.0.jsii.tgz deleted file mode 100644 index 01017631ca2..00000000000 Binary files a/deployments/sequencer/imports/com/google/cloud/_jsii/comgooglecloud@0.0.0.jsii.tgz and /dev/null differ diff --git a/deployments/sequencer/imports/com/google/cloud/py.typed b/deployments/sequencer/imports/com/google/cloud/py.typed deleted file mode 100644 index 8b137891791..00000000000 --- a/deployments/sequencer/imports/com/google/cloud/py.typed +++ /dev/null @@ -1 +0,0 @@ - diff --git a/deployments/sequencer/imports/k8s/__init__.py b/deployments/sequencer/imports/k8s/__init__.py deleted file mode 100644 index 216c143a4f9..00000000000 --- a/deployments/sequencer/imports/k8s/__init__.py +++ /dev/null @@ -1,53620 +0,0 @@ -from pkgutil import extend_path -__path__ = extend_path(__path__, __name__) - -import abc -import builtins -import datetime -import enum -import typing - -import jsii -import publication -import typing_extensions - -import typeguard -from importlib.metadata import version as _metadata_package_version -TYPEGUARD_MAJOR_VERSION = int(_metadata_package_version('typeguard').split('.')[0]) - -def check_type(argname: str, value: object, expected_type: typing.Any) -> typing.Any: - if TYPEGUARD_MAJOR_VERSION <= 2: - return typeguard.check_type(argname=argname, value=value, expected_type=expected_type) # type:ignore - else: - if isinstance(value, jsii._reference_map.InterfaceDynamicProxy): # pyright: ignore [reportAttributeAccessIssue] - pass - else: - if TYPEGUARD_MAJOR_VERSION == 3: - typeguard.config.collection_check_strategy = typeguard.CollectionCheckStrategy.ALL_ITEMS # type:ignore - typeguard.check_type(value=value, expected_type=expected_type) # type:ignore - else: - typeguard.check_type(value=value, expected_type=expected_type, collection_check_strategy=typeguard.CollectionCheckStrategy.ALL_ITEMS) # type:ignore - -from ._jsii import * - -import cdk8s as _cdk8s_d3d9af27 -import constructs as _constructs_77d1e7e8 - - -@jsii.data_type( - jsii_type="k8s.Affinity", - jsii_struct_bases=[], - name_mapping={ - "node_affinity": "nodeAffinity", - "pod_affinity": "podAffinity", - "pod_anti_affinity": "podAntiAffinity", - }, -) -class Affinity: - def __init__( - self, - *, - node_affinity: typing.Optional[typing.Union["NodeAffinity", typing.Dict[builtins.str, typing.Any]]] = None, - pod_affinity: typing.Optional[typing.Union["PodAffinity", typing.Dict[builtins.str, typing.Any]]] = None, - pod_anti_affinity: typing.Optional[typing.Union["PodAntiAffinity", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Affinity is a group of affinity scheduling rules. - - :param node_affinity: Describes node affinity scheduling rules for the pod. - :param pod_affinity: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). - :param pod_anti_affinity: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). - - :schema: io.k8s.api.core.v1.Affinity - ''' - if isinstance(node_affinity, dict): - node_affinity = NodeAffinity(**node_affinity) - if isinstance(pod_affinity, dict): - pod_affinity = PodAffinity(**pod_affinity) - if isinstance(pod_anti_affinity, dict): - pod_anti_affinity = PodAntiAffinity(**pod_anti_affinity) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__b0b5f1aeea5be7ebc9dd226948240c3fe007bf069ec377c716b2c8df75f266a9) - check_type(argname="argument node_affinity", value=node_affinity, expected_type=type_hints["node_affinity"]) - check_type(argname="argument pod_affinity", value=pod_affinity, expected_type=type_hints["pod_affinity"]) - check_type(argname="argument pod_anti_affinity", value=pod_anti_affinity, expected_type=type_hints["pod_anti_affinity"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if node_affinity is not None: - self._values["node_affinity"] = node_affinity - if pod_affinity is not None: - self._values["pod_affinity"] = pod_affinity - if pod_anti_affinity is not None: - self._values["pod_anti_affinity"] = pod_anti_affinity - - @builtins.property - def node_affinity(self) -> typing.Optional["NodeAffinity"]: - '''Describes node affinity scheduling rules for the pod. - - :schema: io.k8s.api.core.v1.Affinity#nodeAffinity - ''' - result = self._values.get("node_affinity") - return typing.cast(typing.Optional["NodeAffinity"], result) - - @builtins.property - def pod_affinity(self) -> typing.Optional["PodAffinity"]: - '''Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). - - :schema: io.k8s.api.core.v1.Affinity#podAffinity - ''' - result = self._values.get("pod_affinity") - return typing.cast(typing.Optional["PodAffinity"], result) - - @builtins.property - def pod_anti_affinity(self) -> typing.Optional["PodAntiAffinity"]: - '''Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). - - :schema: io.k8s.api.core.v1.Affinity#podAntiAffinity - ''' - result = self._values.get("pod_anti_affinity") - return typing.cast(typing.Optional["PodAntiAffinity"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "Affinity(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.AggregationRule", - jsii_struct_bases=[], - name_mapping={"cluster_role_selectors": "clusterRoleSelectors"}, -) -class AggregationRule: - def __init__( - self, - *, - cluster_role_selectors: typing.Optional[typing.Sequence[typing.Union["LabelSelector", typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''AggregationRule describes how to locate ClusterRoles to aggregate into the ClusterRole. - - :param cluster_role_selectors: ClusterRoleSelectors holds a list of selectors which will be used to find ClusterRoles and create the rules. If any of the selectors match, then the ClusterRole's permissions will be added - - :schema: io.k8s.api.rbac.v1.AggregationRule - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__c6abea0d97901d2b42508f6bafd4b7f3b8e99dae1eb38751770090a223a1158b) - check_type(argname="argument cluster_role_selectors", value=cluster_role_selectors, expected_type=type_hints["cluster_role_selectors"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if cluster_role_selectors is not None: - self._values["cluster_role_selectors"] = cluster_role_selectors - - @builtins.property - def cluster_role_selectors(self) -> typing.Optional[typing.List["LabelSelector"]]: - '''ClusterRoleSelectors holds a list of selectors which will be used to find ClusterRoles and create the rules. - - If any of the selectors match, then the ClusterRole's permissions will be added - - :schema: io.k8s.api.rbac.v1.AggregationRule#clusterRoleSelectors - ''' - result = self._values.get("cluster_role_selectors") - return typing.cast(typing.Optional[typing.List["LabelSelector"]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "AggregationRule(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ApiServiceSpec", - jsii_struct_bases=[], - name_mapping={ - "group_priority_minimum": "groupPriorityMinimum", - "version_priority": "versionPriority", - "ca_bundle": "caBundle", - "group": "group", - "insecure_skip_tls_verify": "insecureSkipTlsVerify", - "service": "service", - "version": "version", - }, -) -class ApiServiceSpec: - def __init__( - self, - *, - group_priority_minimum: jsii.Number, - version_priority: jsii.Number, - ca_bundle: typing.Optional[builtins.str] = None, - group: typing.Optional[builtins.str] = None, - insecure_skip_tls_verify: typing.Optional[builtins.bool] = None, - service: typing.Optional[typing.Union["ServiceReference", typing.Dict[builtins.str, typing.Any]]] = None, - version: typing.Optional[builtins.str] = None, - ) -> None: - '''APIServiceSpec contains information for locating and communicating with a server. - - Only https is supported, though you are able to disable certificate verification. - - :param group_priority_minimum: GroupPriorityMininum is the priority this group should have at least. Higher priority means that the group is preferred by clients over lower priority ones. Note that other versions of this group might specify even higher GroupPriorityMininum values such that the whole group gets a higher priority. The primary sort is based on GroupPriorityMinimum, ordered highest number to lowest (20 before 10). The secondary sort is based on the alphabetical comparison of the name of the object. (v1.bar before v1.foo) We'd recommend something like: *.k8s.io (except extensions) at 18000 and PaaSes (OpenShift, Deis) are recommended to be in the 2000s - :param version_priority: VersionPriority controls the ordering of this API version inside of its group. Must be greater than zero. The primary sort is based on VersionPriority, ordered highest to lowest (20 before 10). Since it's inside of a group, the number can be small, probably in the 10s. In case of equal version priorities, the version string will be used to compute the order inside a group. If the version string is "kube-like", it will sort above non "kube-like" version strings, which are ordered lexicographically. "Kube-like" versions start with a "v", then are followed by a number (the major version), then optionally the string "alpha" or "beta" and another number (the minor version). These are sorted first by GA > beta > alpha (where GA is a version with no suffix such as beta or alpha), and then by comparing major version, then minor version. An example sorted list of versions: v10, v2, v1, v11beta2, v10beta3, v3beta1, v12alpha1, v11alpha2, foo1, foo10. - :param ca_bundle: CABundle is a PEM encoded CA bundle which will be used to validate an API server's serving certificate. If unspecified, system trust roots on the apiserver are used. - :param group: Group is the API group name this server hosts. - :param insecure_skip_tls_verify: InsecureSkipTLSVerify disables TLS certificate verification when communicating with this server. This is strongly discouraged. You should use the CABundle instead. - :param service: Service is a reference to the service for this API server. It must communicate on port 443. If the Service is nil, that means the handling for the API groupversion is handled locally on this server. The call will simply delegate to the normal handler chain to be fulfilled. - :param version: Version is the API version this server hosts. For example, "v1" - - :schema: io.k8s.kube-aggregator.pkg.apis.apiregistration.v1.APIServiceSpec - ''' - if isinstance(service, dict): - service = ServiceReference(**service) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__f218ab0fc666c93118e68a7a785bfe54888e33ebd68f9d3998ddac4e96d4a04d) - check_type(argname="argument group_priority_minimum", value=group_priority_minimum, expected_type=type_hints["group_priority_minimum"]) - check_type(argname="argument version_priority", value=version_priority, expected_type=type_hints["version_priority"]) - check_type(argname="argument ca_bundle", value=ca_bundle, expected_type=type_hints["ca_bundle"]) - check_type(argname="argument group", value=group, expected_type=type_hints["group"]) - check_type(argname="argument insecure_skip_tls_verify", value=insecure_skip_tls_verify, expected_type=type_hints["insecure_skip_tls_verify"]) - check_type(argname="argument service", value=service, expected_type=type_hints["service"]) - check_type(argname="argument version", value=version, expected_type=type_hints["version"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "group_priority_minimum": group_priority_minimum, - "version_priority": version_priority, - } - if ca_bundle is not None: - self._values["ca_bundle"] = ca_bundle - if group is not None: - self._values["group"] = group - if insecure_skip_tls_verify is not None: - self._values["insecure_skip_tls_verify"] = insecure_skip_tls_verify - if service is not None: - self._values["service"] = service - if version is not None: - self._values["version"] = version - - @builtins.property - def group_priority_minimum(self) -> jsii.Number: - '''GroupPriorityMininum is the priority this group should have at least. - - Higher priority means that the group is preferred by clients over lower priority ones. Note that other versions of this group might specify even higher GroupPriorityMininum values such that the whole group gets a higher priority. The primary sort is based on GroupPriorityMinimum, ordered highest number to lowest (20 before 10). The secondary sort is based on the alphabetical comparison of the name of the object. (v1.bar before v1.foo) We'd recommend something like: *.k8s.io (except extensions) at 18000 and PaaSes (OpenShift, Deis) are recommended to be in the 2000s - - :schema: io.k8s.kube-aggregator.pkg.apis.apiregistration.v1.APIServiceSpec#groupPriorityMinimum - ''' - result = self._values.get("group_priority_minimum") - assert result is not None, "Required property 'group_priority_minimum' is missing" - return typing.cast(jsii.Number, result) - - @builtins.property - def version_priority(self) -> jsii.Number: - '''VersionPriority controls the ordering of this API version inside of its group. - - Must be greater than zero. The primary sort is based on VersionPriority, ordered highest to lowest (20 before 10). Since it's inside of a group, the number can be small, probably in the 10s. In case of equal version priorities, the version string will be used to compute the order inside a group. If the version string is "kube-like", it will sort above non "kube-like" version strings, which are ordered lexicographically. "Kube-like" versions start with a "v", then are followed by a number (the major version), then optionally the string "alpha" or "beta" and another number (the minor version). These are sorted first by GA > beta > alpha (where GA is a version with no suffix such as beta or alpha), and then by comparing major version, then minor version. An example sorted list of versions: v10, v2, v1, v11beta2, v10beta3, v3beta1, v12alpha1, v11alpha2, foo1, foo10. - - :schema: io.k8s.kube-aggregator.pkg.apis.apiregistration.v1.APIServiceSpec#versionPriority - ''' - result = self._values.get("version_priority") - assert result is not None, "Required property 'version_priority' is missing" - return typing.cast(jsii.Number, result) - - @builtins.property - def ca_bundle(self) -> typing.Optional[builtins.str]: - '''CABundle is a PEM encoded CA bundle which will be used to validate an API server's serving certificate. - - If unspecified, system trust roots on the apiserver are used. - - :schema: io.k8s.kube-aggregator.pkg.apis.apiregistration.v1.APIServiceSpec#caBundle - ''' - result = self._values.get("ca_bundle") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def group(self) -> typing.Optional[builtins.str]: - '''Group is the API group name this server hosts. - - :schema: io.k8s.kube-aggregator.pkg.apis.apiregistration.v1.APIServiceSpec#group - ''' - result = self._values.get("group") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def insecure_skip_tls_verify(self) -> typing.Optional[builtins.bool]: - '''InsecureSkipTLSVerify disables TLS certificate verification when communicating with this server. - - This is strongly discouraged. You should use the CABundle instead. - - :schema: io.k8s.kube-aggregator.pkg.apis.apiregistration.v1.APIServiceSpec#insecureSkipTLSVerify - ''' - result = self._values.get("insecure_skip_tls_verify") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def service(self) -> typing.Optional["ServiceReference"]: - '''Service is a reference to the service for this API server. - - It must communicate on port 443. If the Service is nil, that means the handling for the API groupversion is handled locally on this server. The call will simply delegate to the normal handler chain to be fulfilled. - - :schema: io.k8s.kube-aggregator.pkg.apis.apiregistration.v1.APIServiceSpec#service - ''' - result = self._values.get("service") - return typing.cast(typing.Optional["ServiceReference"], result) - - @builtins.property - def version(self) -> typing.Optional[builtins.str]: - '''Version is the API version this server hosts. - - For example, "v1" - - :schema: io.k8s.kube-aggregator.pkg.apis.apiregistration.v1.APIServiceSpec#version - ''' - result = self._values.get("version") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ApiServiceSpec(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.AwsElasticBlockStoreVolumeSource", - jsii_struct_bases=[], - name_mapping={ - "volume_id": "volumeId", - "fs_type": "fsType", - "partition": "partition", - "read_only": "readOnly", - }, -) -class AwsElasticBlockStoreVolumeSource: - def __init__( - self, - *, - volume_id: builtins.str, - fs_type: typing.Optional[builtins.str] = None, - partition: typing.Optional[jsii.Number] = None, - read_only: typing.Optional[builtins.bool] = None, - ) -> None: - '''Represents a Persistent Disk resource in AWS. - - An AWS EBS disk must exist before mounting to a container. The disk must also be in the same AWS zone as the kubelet. An AWS EBS disk can only be mounted as read/write once. AWS EBS volumes support ownership management and SELinux relabeling. - - :param volume_id: volumeID is unique ID of the persistent disk resource in AWS (Amazon EBS volume). More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - :param fs_type: fsType is the filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - :param partition: partition is the partition in the volume that you want to mount. If omitted, the default is to mount by volume name. Examples: For volume /dev/sda1, you specify the partition as "1". Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). - :param read_only: readOnly value true will force the readOnly setting in VolumeMounts. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - - :schema: io.k8s.api.core.v1.AWSElasticBlockStoreVolumeSource - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__cfdcc8025d63ab999a257c0732b1137f522923a572bda91f7ca61de5c1afd6ec) - check_type(argname="argument volume_id", value=volume_id, expected_type=type_hints["volume_id"]) - check_type(argname="argument fs_type", value=fs_type, expected_type=type_hints["fs_type"]) - check_type(argname="argument partition", value=partition, expected_type=type_hints["partition"]) - check_type(argname="argument read_only", value=read_only, expected_type=type_hints["read_only"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "volume_id": volume_id, - } - if fs_type is not None: - self._values["fs_type"] = fs_type - if partition is not None: - self._values["partition"] = partition - if read_only is not None: - self._values["read_only"] = read_only - - @builtins.property - def volume_id(self) -> builtins.str: - '''volumeID is unique ID of the persistent disk resource in AWS (Amazon EBS volume). - - More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - - :schema: io.k8s.api.core.v1.AWSElasticBlockStoreVolumeSource#volumeID - ''' - result = self._values.get("volume_id") - assert result is not None, "Required property 'volume_id' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def fs_type(self) -> typing.Optional[builtins.str]: - '''fsType is the filesystem type of the volume that you want to mount. - - Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - - :schema: io.k8s.api.core.v1.AWSElasticBlockStoreVolumeSource#fsType - ''' - result = self._values.get("fs_type") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def partition(self) -> typing.Optional[jsii.Number]: - '''partition is the partition in the volume that you want to mount. - - If omitted, the default is to mount by volume name. Examples: For volume /dev/sda1, you specify the partition as "1". Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). - - :schema: io.k8s.api.core.v1.AWSElasticBlockStoreVolumeSource#partition - ''' - result = self._values.get("partition") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def read_only(self) -> typing.Optional[builtins.bool]: - '''readOnly value true will force the readOnly setting in VolumeMounts. - - More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - - :schema: io.k8s.api.core.v1.AWSElasticBlockStoreVolumeSource#readOnly - ''' - result = self._values.get("read_only") - return typing.cast(typing.Optional[builtins.bool], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "AwsElasticBlockStoreVolumeSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.AzureDiskVolumeSource", - jsii_struct_bases=[], - name_mapping={ - "disk_name": "diskName", - "disk_uri": "diskUri", - "caching_mode": "cachingMode", - "fs_type": "fsType", - "kind": "kind", - "read_only": "readOnly", - }, -) -class AzureDiskVolumeSource: - def __init__( - self, - *, - disk_name: builtins.str, - disk_uri: builtins.str, - caching_mode: typing.Optional[builtins.str] = None, - fs_type: typing.Optional[builtins.str] = None, - kind: typing.Optional[builtins.str] = None, - read_only: typing.Optional[builtins.bool] = None, - ) -> None: - '''AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod. - - :param disk_name: diskName is the Name of the data disk in the blob storage. - :param disk_uri: diskURI is the URI of data disk in the blob storage. - :param caching_mode: cachingMode is the Host Caching mode: None, Read Only, Read Write. - :param fs_type: fsType is Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - :param kind: kind expected values are Shared: multiple blob disks per storage account Dedicated: single blob disk per storage account Managed: azure managed data disk (only in managed availability set). defaults to shared - :param read_only: readOnly Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. Default: false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. - - :schema: io.k8s.api.core.v1.AzureDiskVolumeSource - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__42545c3f07626c9bf98c297356705624406f44b3ada49253cfa8b75145c9636d) - check_type(argname="argument disk_name", value=disk_name, expected_type=type_hints["disk_name"]) - check_type(argname="argument disk_uri", value=disk_uri, expected_type=type_hints["disk_uri"]) - check_type(argname="argument caching_mode", value=caching_mode, expected_type=type_hints["caching_mode"]) - check_type(argname="argument fs_type", value=fs_type, expected_type=type_hints["fs_type"]) - check_type(argname="argument kind", value=kind, expected_type=type_hints["kind"]) - check_type(argname="argument read_only", value=read_only, expected_type=type_hints["read_only"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "disk_name": disk_name, - "disk_uri": disk_uri, - } - if caching_mode is not None: - self._values["caching_mode"] = caching_mode - if fs_type is not None: - self._values["fs_type"] = fs_type - if kind is not None: - self._values["kind"] = kind - if read_only is not None: - self._values["read_only"] = read_only - - @builtins.property - def disk_name(self) -> builtins.str: - '''diskName is the Name of the data disk in the blob storage. - - :schema: io.k8s.api.core.v1.AzureDiskVolumeSource#diskName - ''' - result = self._values.get("disk_name") - assert result is not None, "Required property 'disk_name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def disk_uri(self) -> builtins.str: - '''diskURI is the URI of data disk in the blob storage. - - :schema: io.k8s.api.core.v1.AzureDiskVolumeSource#diskURI - ''' - result = self._values.get("disk_uri") - assert result is not None, "Required property 'disk_uri' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def caching_mode(self) -> typing.Optional[builtins.str]: - '''cachingMode is the Host Caching mode: None, Read Only, Read Write. - - :schema: io.k8s.api.core.v1.AzureDiskVolumeSource#cachingMode - ''' - result = self._values.get("caching_mode") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def fs_type(self) -> typing.Optional[builtins.str]: - '''fsType is Filesystem type to mount. - - Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - - :schema: io.k8s.api.core.v1.AzureDiskVolumeSource#fsType - ''' - result = self._values.get("fs_type") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def kind(self) -> typing.Optional[builtins.str]: - '''kind expected values are Shared: multiple blob disks per storage account Dedicated: single blob disk per storage account Managed: azure managed data disk (only in managed availability set). - - defaults to shared - - :schema: io.k8s.api.core.v1.AzureDiskVolumeSource#kind - ''' - result = self._values.get("kind") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def read_only(self) -> typing.Optional[builtins.bool]: - '''readOnly Defaults to false (read/write). - - ReadOnly here will force the ReadOnly setting in VolumeMounts. - - :default: false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. - - :schema: io.k8s.api.core.v1.AzureDiskVolumeSource#readOnly - ''' - result = self._values.get("read_only") - return typing.cast(typing.Optional[builtins.bool], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "AzureDiskVolumeSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.AzureFilePersistentVolumeSource", - jsii_struct_bases=[], - name_mapping={ - "secret_name": "secretName", - "share_name": "shareName", - "read_only": "readOnly", - "secret_namespace": "secretNamespace", - }, -) -class AzureFilePersistentVolumeSource: - def __init__( - self, - *, - secret_name: builtins.str, - share_name: builtins.str, - read_only: typing.Optional[builtins.bool] = None, - secret_namespace: typing.Optional[builtins.str] = None, - ) -> None: - '''AzureFile represents an Azure File Service mount on the host and bind mount to the pod. - - :param secret_name: secretName is the name of secret that contains Azure Storage Account Name and Key. - :param share_name: shareName is the azure Share Name. - :param read_only: readOnly defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. - :param secret_namespace: secretNamespace is the namespace of the secret that contains Azure Storage Account Name and Key default is the same as the Pod. - - :schema: io.k8s.api.core.v1.AzureFilePersistentVolumeSource - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__84f066edf5f8bb2aff501a75543bcd7bb28c293243500d6e69343a9a24263569) - check_type(argname="argument secret_name", value=secret_name, expected_type=type_hints["secret_name"]) - check_type(argname="argument share_name", value=share_name, expected_type=type_hints["share_name"]) - check_type(argname="argument read_only", value=read_only, expected_type=type_hints["read_only"]) - check_type(argname="argument secret_namespace", value=secret_namespace, expected_type=type_hints["secret_namespace"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "secret_name": secret_name, - "share_name": share_name, - } - if read_only is not None: - self._values["read_only"] = read_only - if secret_namespace is not None: - self._values["secret_namespace"] = secret_namespace - - @builtins.property - def secret_name(self) -> builtins.str: - '''secretName is the name of secret that contains Azure Storage Account Name and Key. - - :schema: io.k8s.api.core.v1.AzureFilePersistentVolumeSource#secretName - ''' - result = self._values.get("secret_name") - assert result is not None, "Required property 'secret_name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def share_name(self) -> builtins.str: - '''shareName is the azure Share Name. - - :schema: io.k8s.api.core.v1.AzureFilePersistentVolumeSource#shareName - ''' - result = self._values.get("share_name") - assert result is not None, "Required property 'share_name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def read_only(self) -> typing.Optional[builtins.bool]: - '''readOnly defaults to false (read/write). - - ReadOnly here will force the ReadOnly setting in VolumeMounts. - - :schema: io.k8s.api.core.v1.AzureFilePersistentVolumeSource#readOnly - ''' - result = self._values.get("read_only") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def secret_namespace(self) -> typing.Optional[builtins.str]: - '''secretNamespace is the namespace of the secret that contains Azure Storage Account Name and Key default is the same as the Pod. - - :schema: io.k8s.api.core.v1.AzureFilePersistentVolumeSource#secretNamespace - ''' - result = self._values.get("secret_namespace") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "AzureFilePersistentVolumeSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.AzureFileVolumeSource", - jsii_struct_bases=[], - name_mapping={ - "secret_name": "secretName", - "share_name": "shareName", - "read_only": "readOnly", - }, -) -class AzureFileVolumeSource: - def __init__( - self, - *, - secret_name: builtins.str, - share_name: builtins.str, - read_only: typing.Optional[builtins.bool] = None, - ) -> None: - '''AzureFile represents an Azure File Service mount on the host and bind mount to the pod. - - :param secret_name: secretName is the name of secret that contains Azure Storage Account Name and Key. - :param share_name: shareName is the azure share Name. - :param read_only: readOnly defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. - - :schema: io.k8s.api.core.v1.AzureFileVolumeSource - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__94648be721e46971848c0b51f3b1d4399d4a5e674368c83a893121cb3e801106) - check_type(argname="argument secret_name", value=secret_name, expected_type=type_hints["secret_name"]) - check_type(argname="argument share_name", value=share_name, expected_type=type_hints["share_name"]) - check_type(argname="argument read_only", value=read_only, expected_type=type_hints["read_only"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "secret_name": secret_name, - "share_name": share_name, - } - if read_only is not None: - self._values["read_only"] = read_only - - @builtins.property - def secret_name(self) -> builtins.str: - '''secretName is the name of secret that contains Azure Storage Account Name and Key. - - :schema: io.k8s.api.core.v1.AzureFileVolumeSource#secretName - ''' - result = self._values.get("secret_name") - assert result is not None, "Required property 'secret_name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def share_name(self) -> builtins.str: - '''shareName is the azure share Name. - - :schema: io.k8s.api.core.v1.AzureFileVolumeSource#shareName - ''' - result = self._values.get("share_name") - assert result is not None, "Required property 'share_name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def read_only(self) -> typing.Optional[builtins.bool]: - '''readOnly defaults to false (read/write). - - ReadOnly here will force the ReadOnly setting in VolumeMounts. - - :schema: io.k8s.api.core.v1.AzureFileVolumeSource#readOnly - ''' - result = self._values.get("read_only") - return typing.cast(typing.Optional[builtins.bool], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "AzureFileVolumeSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.BoundObjectReference", - jsii_struct_bases=[], - name_mapping={ - "api_version": "apiVersion", - "kind": "kind", - "name": "name", - "uid": "uid", - }, -) -class BoundObjectReference: - def __init__( - self, - *, - api_version: typing.Optional[builtins.str] = None, - kind: typing.Optional[builtins.str] = None, - name: typing.Optional[builtins.str] = None, - uid: typing.Optional[builtins.str] = None, - ) -> None: - '''BoundObjectReference is a reference to an object that a token is bound to. - - :param api_version: API version of the referent. - :param kind: Kind of the referent. Valid kinds are 'Pod' and 'Secret'. - :param name: Name of the referent. - :param uid: UID of the referent. - - :schema: io.k8s.api.authentication.v1.BoundObjectReference - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__3842071c1f7fa48baa6f58272703081a16a5000ba6ca2a54f8ed32aceb2e5309) - check_type(argname="argument api_version", value=api_version, expected_type=type_hints["api_version"]) - check_type(argname="argument kind", value=kind, expected_type=type_hints["kind"]) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument uid", value=uid, expected_type=type_hints["uid"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if api_version is not None: - self._values["api_version"] = api_version - if kind is not None: - self._values["kind"] = kind - if name is not None: - self._values["name"] = name - if uid is not None: - self._values["uid"] = uid - - @builtins.property - def api_version(self) -> typing.Optional[builtins.str]: - '''API version of the referent. - - :schema: io.k8s.api.authentication.v1.BoundObjectReference#apiVersion - ''' - result = self._values.get("api_version") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def kind(self) -> typing.Optional[builtins.str]: - '''Kind of the referent. - - Valid kinds are 'Pod' and 'Secret'. - - :schema: io.k8s.api.authentication.v1.BoundObjectReference#kind - ''' - result = self._values.get("kind") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def name(self) -> typing.Optional[builtins.str]: - '''Name of the referent. - - :schema: io.k8s.api.authentication.v1.BoundObjectReference#name - ''' - result = self._values.get("name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def uid(self) -> typing.Optional[builtins.str]: - '''UID of the referent. - - :schema: io.k8s.api.authentication.v1.BoundObjectReference#uid - ''' - result = self._values.get("uid") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "BoundObjectReference(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.Capabilities", - jsii_struct_bases=[], - name_mapping={"add": "add", "drop": "drop"}, -) -class Capabilities: - def __init__( - self, - *, - add: typing.Optional[typing.Sequence[builtins.str]] = None, - drop: typing.Optional[typing.Sequence[builtins.str]] = None, - ) -> None: - '''Adds and removes POSIX capabilities from running containers. - - :param add: Added capabilities. - :param drop: Removed capabilities. - - :schema: io.k8s.api.core.v1.Capabilities - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__be353859945b18989b92f139f2d1450880c136c416dfb6159bcc2bedd35f5528) - check_type(argname="argument add", value=add, expected_type=type_hints["add"]) - check_type(argname="argument drop", value=drop, expected_type=type_hints["drop"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if add is not None: - self._values["add"] = add - if drop is not None: - self._values["drop"] = drop - - @builtins.property - def add(self) -> typing.Optional[typing.List[builtins.str]]: - '''Added capabilities. - - :schema: io.k8s.api.core.v1.Capabilities#add - ''' - result = self._values.get("add") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def drop(self) -> typing.Optional[typing.List[builtins.str]]: - '''Removed capabilities. - - :schema: io.k8s.api.core.v1.Capabilities#drop - ''' - result = self._values.get("drop") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "Capabilities(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.CephFsPersistentVolumeSource", - jsii_struct_bases=[], - name_mapping={ - "monitors": "monitors", - "path": "path", - "read_only": "readOnly", - "secret_file": "secretFile", - "secret_ref": "secretRef", - "user": "user", - }, -) -class CephFsPersistentVolumeSource: - def __init__( - self, - *, - monitors: typing.Sequence[builtins.str], - path: typing.Optional[builtins.str] = None, - read_only: typing.Optional[builtins.bool] = None, - secret_file: typing.Optional[builtins.str] = None, - secret_ref: typing.Optional[typing.Union["SecretReference", typing.Dict[builtins.str, typing.Any]]] = None, - user: typing.Optional[builtins.str] = None, - ) -> None: - '''Represents a Ceph Filesystem mount that lasts the lifetime of a pod Cephfs volumes do not support ownership management or SELinux relabeling. - - :param monitors: monitors is Required: Monitors is a collection of Ceph monitors More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it. - :param path: path is Optional: Used as the mounted root, rather than the full Ceph tree, default is /. - :param read_only: readOnly is Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it Default: false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - :param secret_file: secretFile is Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it. - :param secret_ref: secretRef is Optional: SecretRef is reference to the authentication secret for User, default is empty. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - :param user: user is Optional: User is the rados user name, default is admin More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it. - - :schema: io.k8s.api.core.v1.CephFSPersistentVolumeSource - ''' - if isinstance(secret_ref, dict): - secret_ref = SecretReference(**secret_ref) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__3b5ad69df26a24d2f512ef505faa2117b55637afeef4390b17721af52ec2e212) - check_type(argname="argument monitors", value=monitors, expected_type=type_hints["monitors"]) - check_type(argname="argument path", value=path, expected_type=type_hints["path"]) - check_type(argname="argument read_only", value=read_only, expected_type=type_hints["read_only"]) - check_type(argname="argument secret_file", value=secret_file, expected_type=type_hints["secret_file"]) - check_type(argname="argument secret_ref", value=secret_ref, expected_type=type_hints["secret_ref"]) - check_type(argname="argument user", value=user, expected_type=type_hints["user"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "monitors": monitors, - } - if path is not None: - self._values["path"] = path - if read_only is not None: - self._values["read_only"] = read_only - if secret_file is not None: - self._values["secret_file"] = secret_file - if secret_ref is not None: - self._values["secret_ref"] = secret_ref - if user is not None: - self._values["user"] = user - - @builtins.property - def monitors(self) -> typing.List[builtins.str]: - '''monitors is Required: Monitors is a collection of Ceph monitors More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it. - - :schema: io.k8s.api.core.v1.CephFSPersistentVolumeSource#monitors - ''' - result = self._values.get("monitors") - assert result is not None, "Required property 'monitors' is missing" - return typing.cast(typing.List[builtins.str], result) - - @builtins.property - def path(self) -> typing.Optional[builtins.str]: - '''path is Optional: Used as the mounted root, rather than the full Ceph tree, default is /. - - :schema: io.k8s.api.core.v1.CephFSPersistentVolumeSource#path - ''' - result = self._values.get("path") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def read_only(self) -> typing.Optional[builtins.bool]: - '''readOnly is Optional: Defaults to false (read/write). - - ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - - :default: false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - - :schema: io.k8s.api.core.v1.CephFSPersistentVolumeSource#readOnly - ''' - result = self._values.get("read_only") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def secret_file(self) -> typing.Optional[builtins.str]: - '''secretFile is Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it. - - :schema: io.k8s.api.core.v1.CephFSPersistentVolumeSource#secretFile - ''' - result = self._values.get("secret_file") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def secret_ref(self) -> typing.Optional["SecretReference"]: - '''secretRef is Optional: SecretRef is reference to the authentication secret for User, default is empty. - - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - - :schema: io.k8s.api.core.v1.CephFSPersistentVolumeSource#secretRef - ''' - result = self._values.get("secret_ref") - return typing.cast(typing.Optional["SecretReference"], result) - - @builtins.property - def user(self) -> typing.Optional[builtins.str]: - '''user is Optional: User is the rados user name, default is admin More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it. - - :schema: io.k8s.api.core.v1.CephFSPersistentVolumeSource#user - ''' - result = self._values.get("user") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "CephFsPersistentVolumeSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.CephFsVolumeSource", - jsii_struct_bases=[], - name_mapping={ - "monitors": "monitors", - "path": "path", - "read_only": "readOnly", - "secret_file": "secretFile", - "secret_ref": "secretRef", - "user": "user", - }, -) -class CephFsVolumeSource: - def __init__( - self, - *, - monitors: typing.Sequence[builtins.str], - path: typing.Optional[builtins.str] = None, - read_only: typing.Optional[builtins.bool] = None, - secret_file: typing.Optional[builtins.str] = None, - secret_ref: typing.Optional[typing.Union["LocalObjectReference", typing.Dict[builtins.str, typing.Any]]] = None, - user: typing.Optional[builtins.str] = None, - ) -> None: - '''Represents a Ceph Filesystem mount that lasts the lifetime of a pod Cephfs volumes do not support ownership management or SELinux relabeling. - - :param monitors: monitors is Required: Monitors is a collection of Ceph monitors More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it. - :param path: path is Optional: Used as the mounted root, rather than the full Ceph tree, default is /. - :param read_only: readOnly is Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it Default: false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - :param secret_file: secretFile is Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it. - :param secret_ref: secretRef is Optional: SecretRef is reference to the authentication secret for User, default is empty. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - :param user: user is optional: User is the rados user name, default is admin More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it. - - :schema: io.k8s.api.core.v1.CephFSVolumeSource - ''' - if isinstance(secret_ref, dict): - secret_ref = LocalObjectReference(**secret_ref) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__58ba734b607dafa3947531043b85de9735a63082b9ba851ec726adf616b87935) - check_type(argname="argument monitors", value=monitors, expected_type=type_hints["monitors"]) - check_type(argname="argument path", value=path, expected_type=type_hints["path"]) - check_type(argname="argument read_only", value=read_only, expected_type=type_hints["read_only"]) - check_type(argname="argument secret_file", value=secret_file, expected_type=type_hints["secret_file"]) - check_type(argname="argument secret_ref", value=secret_ref, expected_type=type_hints["secret_ref"]) - check_type(argname="argument user", value=user, expected_type=type_hints["user"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "monitors": monitors, - } - if path is not None: - self._values["path"] = path - if read_only is not None: - self._values["read_only"] = read_only - if secret_file is not None: - self._values["secret_file"] = secret_file - if secret_ref is not None: - self._values["secret_ref"] = secret_ref - if user is not None: - self._values["user"] = user - - @builtins.property - def monitors(self) -> typing.List[builtins.str]: - '''monitors is Required: Monitors is a collection of Ceph monitors More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it. - - :schema: io.k8s.api.core.v1.CephFSVolumeSource#monitors - ''' - result = self._values.get("monitors") - assert result is not None, "Required property 'monitors' is missing" - return typing.cast(typing.List[builtins.str], result) - - @builtins.property - def path(self) -> typing.Optional[builtins.str]: - '''path is Optional: Used as the mounted root, rather than the full Ceph tree, default is /. - - :schema: io.k8s.api.core.v1.CephFSVolumeSource#path - ''' - result = self._values.get("path") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def read_only(self) -> typing.Optional[builtins.bool]: - '''readOnly is Optional: Defaults to false (read/write). - - ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - - :default: false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - - :schema: io.k8s.api.core.v1.CephFSVolumeSource#readOnly - ''' - result = self._values.get("read_only") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def secret_file(self) -> typing.Optional[builtins.str]: - '''secretFile is Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it. - - :schema: io.k8s.api.core.v1.CephFSVolumeSource#secretFile - ''' - result = self._values.get("secret_file") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def secret_ref(self) -> typing.Optional["LocalObjectReference"]: - '''secretRef is Optional: SecretRef is reference to the authentication secret for User, default is empty. - - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - - :schema: io.k8s.api.core.v1.CephFSVolumeSource#secretRef - ''' - result = self._values.get("secret_ref") - return typing.cast(typing.Optional["LocalObjectReference"], result) - - @builtins.property - def user(self) -> typing.Optional[builtins.str]: - '''user is optional: User is the rados user name, default is admin More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it. - - :schema: io.k8s.api.core.v1.CephFSVolumeSource#user - ''' - result = self._values.get("user") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "CephFsVolumeSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.CertificateSigningRequestSpec", - jsii_struct_bases=[], - name_mapping={ - "request": "request", - "signer_name": "signerName", - "expiration_seconds": "expirationSeconds", - "extra": "extra", - "groups": "groups", - "uid": "uid", - "usages": "usages", - "username": "username", - }, -) -class CertificateSigningRequestSpec: - def __init__( - self, - *, - request: builtins.str, - signer_name: builtins.str, - expiration_seconds: typing.Optional[jsii.Number] = None, - extra: typing.Optional[typing.Mapping[builtins.str, typing.Sequence[builtins.str]]] = None, - groups: typing.Optional[typing.Sequence[builtins.str]] = None, - uid: typing.Optional[builtins.str] = None, - usages: typing.Optional[typing.Sequence[builtins.str]] = None, - username: typing.Optional[builtins.str] = None, - ) -> None: - '''CertificateSigningRequestSpec contains the certificate request. - - :param request: request contains an x509 certificate signing request encoded in a "CERTIFICATE REQUEST" PEM block. When serialized as JSON or YAML, the data is additionally base64-encoded. - :param signer_name: signerName indicates the requested signer, and is a qualified name. List/watch requests for CertificateSigningRequests can filter on this field using a "spec.signerName=NAME" fieldSelector. Well-known Kubernetes signers are: 1. "kubernetes.io/kube-apiserver-client": issues client certificates that can be used to authenticate to kube-apiserver. Requests for this signer are never auto-approved by kube-controller-manager, can be issued by the "csrsigning" controller in kube-controller-manager. 2. "kubernetes.io/kube-apiserver-client-kubelet": issues client certificates that kubelets use to authenticate to kube-apiserver. Requests for this signer can be auto-approved by the "csrapproving" controller in kube-controller-manager, and can be issued by the "csrsigning" controller in kube-controller-manager. 3. "kubernetes.io/kubelet-serving" issues serving certificates that kubelets use to serve TLS endpoints, which kube-apiserver can connect to securely. Requests for this signer are never auto-approved by kube-controller-manager, and can be issued by the "csrsigning" controller in kube-controller-manager. More details are available at https://k8s.io/docs/reference/access-authn-authz/certificate-signing-requests/#kubernetes-signers Custom signerNames can also be specified. The signer defines: 1. Trust distribution: how trust (CA bundles) are distributed. 2. Permitted subjects: and behavior when a disallowed subject is requested. 3. Required, permitted, or forbidden x509 extensions in the request (including whether subjectAltNames are allowed, which types, restrictions on allowed values) and behavior when a disallowed extension is requested. 4. Required, permitted, or forbidden key usages / extended key usages. 5. Expiration/certificate lifetime: whether it is fixed by the signer, configurable by the admin. 6. Whether or not requests for CA certificates are allowed. - :param expiration_seconds: expirationSeconds is the requested duration of validity of the issued certificate. The certificate signer may issue a certificate with a different validity duration so a client must check the delta between the notBefore and and notAfter fields in the issued certificate to determine the actual duration. The v1.22+ in-tree implementations of the well-known Kubernetes signers will honor this field as long as the requested duration is not greater than the maximum duration they will honor per the --cluster-signing-duration CLI flag to the Kubernetes controller manager. Certificate signers may not honor this field for various reasons: 1. Old signer that is unaware of the field (such as the in-tree implementations prior to v1.22) 2. Signer whose configured maximum is shorter than the requested duration 3. Signer whose configured minimum is longer than the requested duration The minimum valid value for expirationSeconds is 600, i.e. 10 minutes. - :param extra: extra contains extra attributes of the user that created the CertificateSigningRequest. Populated by the API server on creation and immutable. - :param groups: groups contains group membership of the user that created the CertificateSigningRequest. Populated by the API server on creation and immutable. - :param uid: uid contains the uid of the user that created the CertificateSigningRequest. Populated by the API server on creation and immutable. - :param usages: usages specifies a set of key usages requested in the issued certificate. Requests for TLS client certificates typically request: "digital signature", "key encipherment", "client auth". Requests for TLS serving certificates typically request: "key encipherment", "digital signature", "server auth". Valid values are: "signing", "digital signature", "content commitment", "key encipherment", "key agreement", "data encipherment", "cert sign", "crl sign", "encipher only", "decipher only", "any", "server auth", "client auth", "code signing", "email protection", "s/mime", "ipsec end system", "ipsec tunnel", "ipsec user", "timestamping", "ocsp signing", "microsoft sgc", "netscape sgc" - :param username: username contains the name of the user that created the CertificateSigningRequest. Populated by the API server on creation and immutable. - - :schema: io.k8s.api.certificates.v1.CertificateSigningRequestSpec - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__a33e7e945dc9d389d58598a00c0615e6a0c101c66e3b1019bfbc65ff586ad288) - check_type(argname="argument request", value=request, expected_type=type_hints["request"]) - check_type(argname="argument signer_name", value=signer_name, expected_type=type_hints["signer_name"]) - check_type(argname="argument expiration_seconds", value=expiration_seconds, expected_type=type_hints["expiration_seconds"]) - check_type(argname="argument extra", value=extra, expected_type=type_hints["extra"]) - check_type(argname="argument groups", value=groups, expected_type=type_hints["groups"]) - check_type(argname="argument uid", value=uid, expected_type=type_hints["uid"]) - check_type(argname="argument usages", value=usages, expected_type=type_hints["usages"]) - check_type(argname="argument username", value=username, expected_type=type_hints["username"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "request": request, - "signer_name": signer_name, - } - if expiration_seconds is not None: - self._values["expiration_seconds"] = expiration_seconds - if extra is not None: - self._values["extra"] = extra - if groups is not None: - self._values["groups"] = groups - if uid is not None: - self._values["uid"] = uid - if usages is not None: - self._values["usages"] = usages - if username is not None: - self._values["username"] = username - - @builtins.property - def request(self) -> builtins.str: - '''request contains an x509 certificate signing request encoded in a "CERTIFICATE REQUEST" PEM block. - - When serialized as JSON or YAML, the data is additionally base64-encoded. - - :schema: io.k8s.api.certificates.v1.CertificateSigningRequestSpec#request - ''' - result = self._values.get("request") - assert result is not None, "Required property 'request' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def signer_name(self) -> builtins.str: - '''signerName indicates the requested signer, and is a qualified name. - - List/watch requests for CertificateSigningRequests can filter on this field using a "spec.signerName=NAME" fieldSelector. - - Well-known Kubernetes signers are: - - 1. "kubernetes.io/kube-apiserver-client": issues client certificates that can be used to authenticate to kube-apiserver. - Requests for this signer are never auto-approved by kube-controller-manager, can be issued by the "csrsigning" controller in kube-controller-manager. - 2. "kubernetes.io/kube-apiserver-client-kubelet": issues client certificates that kubelets use to authenticate to kube-apiserver. - Requests for this signer can be auto-approved by the "csrapproving" controller in kube-controller-manager, and can be issued by the "csrsigning" controller in kube-controller-manager. - 3. "kubernetes.io/kubelet-serving" issues serving certificates that kubelets use to serve TLS endpoints, which kube-apiserver can connect to securely. - Requests for this signer are never auto-approved by kube-controller-manager, and can be issued by the "csrsigning" controller in kube-controller-manager. - - More details are available at https://k8s.io/docs/reference/access-authn-authz/certificate-signing-requests/#kubernetes-signers - - Custom signerNames can also be specified. The signer defines: - - 1. Trust distribution: how trust (CA bundles) are distributed. - 2. Permitted subjects: and behavior when a disallowed subject is requested. - 3. Required, permitted, or forbidden x509 extensions in the request (including whether subjectAltNames are allowed, which types, restrictions on allowed values) and behavior when a disallowed extension is requested. - 4. Required, permitted, or forbidden key usages / extended key usages. - 5. Expiration/certificate lifetime: whether it is fixed by the signer, configurable by the admin. - 6. Whether or not requests for CA certificates are allowed. - - :schema: io.k8s.api.certificates.v1.CertificateSigningRequestSpec#signerName - ''' - result = self._values.get("signer_name") - assert result is not None, "Required property 'signer_name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def expiration_seconds(self) -> typing.Optional[jsii.Number]: - '''expirationSeconds is the requested duration of validity of the issued certificate. - - The certificate signer may issue a certificate with a different validity duration so a client must check the delta between the notBefore and and notAfter fields in the issued certificate to determine the actual duration. - - The v1.22+ in-tree implementations of the well-known Kubernetes signers will honor this field as long as the requested duration is not greater than the maximum duration they will honor per the --cluster-signing-duration CLI flag to the Kubernetes controller manager. - - Certificate signers may not honor this field for various reasons: - - 1. Old signer that is unaware of the field (such as the in-tree - implementations prior to v1.22) - 2. Signer whose configured maximum is shorter than the requested duration - 3. Signer whose configured minimum is longer than the requested duration - - The minimum valid value for expirationSeconds is 600, i.e. 10 minutes. - - :schema: io.k8s.api.certificates.v1.CertificateSigningRequestSpec#expirationSeconds - ''' - result = self._values.get("expiration_seconds") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def extra( - self, - ) -> typing.Optional[typing.Mapping[builtins.str, typing.List[builtins.str]]]: - '''extra contains extra attributes of the user that created the CertificateSigningRequest. - - Populated by the API server on creation and immutable. - - :schema: io.k8s.api.certificates.v1.CertificateSigningRequestSpec#extra - ''' - result = self._values.get("extra") - return typing.cast(typing.Optional[typing.Mapping[builtins.str, typing.List[builtins.str]]], result) - - @builtins.property - def groups(self) -> typing.Optional[typing.List[builtins.str]]: - '''groups contains group membership of the user that created the CertificateSigningRequest. - - Populated by the API server on creation and immutable. - - :schema: io.k8s.api.certificates.v1.CertificateSigningRequestSpec#groups - ''' - result = self._values.get("groups") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def uid(self) -> typing.Optional[builtins.str]: - '''uid contains the uid of the user that created the CertificateSigningRequest. - - Populated by the API server on creation and immutable. - - :schema: io.k8s.api.certificates.v1.CertificateSigningRequestSpec#uid - ''' - result = self._values.get("uid") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def usages(self) -> typing.Optional[typing.List[builtins.str]]: - '''usages specifies a set of key usages requested in the issued certificate. - - Requests for TLS client certificates typically request: "digital signature", "key encipherment", "client auth". - - Requests for TLS serving certificates typically request: "key encipherment", "digital signature", "server auth". - - Valid values are: - "signing", "digital signature", "content commitment", - "key encipherment", "key agreement", "data encipherment", - "cert sign", "crl sign", "encipher only", "decipher only", "any", - "server auth", "client auth", - "code signing", "email protection", "s/mime", - "ipsec end system", "ipsec tunnel", "ipsec user", - "timestamping", "ocsp signing", "microsoft sgc", "netscape sgc" - - :schema: io.k8s.api.certificates.v1.CertificateSigningRequestSpec#usages - ''' - result = self._values.get("usages") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def username(self) -> typing.Optional[builtins.str]: - '''username contains the name of the user that created the CertificateSigningRequest. - - Populated by the API server on creation and immutable. - - :schema: io.k8s.api.certificates.v1.CertificateSigningRequestSpec#username - ''' - result = self._values.get("username") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "CertificateSigningRequestSpec(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.CinderPersistentVolumeSource", - jsii_struct_bases=[], - name_mapping={ - "volume_id": "volumeId", - "fs_type": "fsType", - "read_only": "readOnly", - "secret_ref": "secretRef", - }, -) -class CinderPersistentVolumeSource: - def __init__( - self, - *, - volume_id: builtins.str, - fs_type: typing.Optional[builtins.str] = None, - read_only: typing.Optional[builtins.bool] = None, - secret_ref: typing.Optional[typing.Union["SecretReference", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Represents a cinder volume resource in Openstack. - - A Cinder volume must exist before mounting to a container. The volume must also be in the same region as the kubelet. Cinder volumes support ownership management and SELinux relabeling. - - :param volume_id: volumeID used to identify the volume in cinder. More info: https://examples.k8s.io/mysql-cinder-pd/README.md - :param fs_type: fsType Filesystem type to mount. Must be a filesystem type supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://examples.k8s.io/mysql-cinder-pd/README.md - :param read_only: readOnly is Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: https://examples.k8s.io/mysql-cinder-pd/README.md Default: false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: https://examples.k8s.io/mysql-cinder-pd/README.md - :param secret_ref: secretRef is Optional: points to a secret object containing parameters used to connect to OpenStack. - - :schema: io.k8s.api.core.v1.CinderPersistentVolumeSource - ''' - if isinstance(secret_ref, dict): - secret_ref = SecretReference(**secret_ref) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__881438521a2ffa8cb492e1a592803eba0118f41d19c6c9b21f89488919c9fe95) - check_type(argname="argument volume_id", value=volume_id, expected_type=type_hints["volume_id"]) - check_type(argname="argument fs_type", value=fs_type, expected_type=type_hints["fs_type"]) - check_type(argname="argument read_only", value=read_only, expected_type=type_hints["read_only"]) - check_type(argname="argument secret_ref", value=secret_ref, expected_type=type_hints["secret_ref"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "volume_id": volume_id, - } - if fs_type is not None: - self._values["fs_type"] = fs_type - if read_only is not None: - self._values["read_only"] = read_only - if secret_ref is not None: - self._values["secret_ref"] = secret_ref - - @builtins.property - def volume_id(self) -> builtins.str: - '''volumeID used to identify the volume in cinder. - - More info: https://examples.k8s.io/mysql-cinder-pd/README.md - - :schema: io.k8s.api.core.v1.CinderPersistentVolumeSource#volumeID - ''' - result = self._values.get("volume_id") - assert result is not None, "Required property 'volume_id' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def fs_type(self) -> typing.Optional[builtins.str]: - '''fsType Filesystem type to mount. - - Must be a filesystem type supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://examples.k8s.io/mysql-cinder-pd/README.md - - :schema: io.k8s.api.core.v1.CinderPersistentVolumeSource#fsType - ''' - result = self._values.get("fs_type") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def read_only(self) -> typing.Optional[builtins.bool]: - '''readOnly is Optional: Defaults to false (read/write). - - ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: https://examples.k8s.io/mysql-cinder-pd/README.md - - :default: false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: https://examples.k8s.io/mysql-cinder-pd/README.md - - :schema: io.k8s.api.core.v1.CinderPersistentVolumeSource#readOnly - ''' - result = self._values.get("read_only") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def secret_ref(self) -> typing.Optional["SecretReference"]: - '''secretRef is Optional: points to a secret object containing parameters used to connect to OpenStack. - - :schema: io.k8s.api.core.v1.CinderPersistentVolumeSource#secretRef - ''' - result = self._values.get("secret_ref") - return typing.cast(typing.Optional["SecretReference"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "CinderPersistentVolumeSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.CinderVolumeSource", - jsii_struct_bases=[], - name_mapping={ - "volume_id": "volumeId", - "fs_type": "fsType", - "read_only": "readOnly", - "secret_ref": "secretRef", - }, -) -class CinderVolumeSource: - def __init__( - self, - *, - volume_id: builtins.str, - fs_type: typing.Optional[builtins.str] = None, - read_only: typing.Optional[builtins.bool] = None, - secret_ref: typing.Optional[typing.Union["LocalObjectReference", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Represents a cinder volume resource in Openstack. - - A Cinder volume must exist before mounting to a container. The volume must also be in the same region as the kubelet. Cinder volumes support ownership management and SELinux relabeling. - - :param volume_id: volumeID used to identify the volume in cinder. More info: https://examples.k8s.io/mysql-cinder-pd/README.md - :param fs_type: fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://examples.k8s.io/mysql-cinder-pd/README.md - :param read_only: readOnly defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: https://examples.k8s.io/mysql-cinder-pd/README.md - :param secret_ref: secretRef is optional: points to a secret object containing parameters used to connect to OpenStack. - - :schema: io.k8s.api.core.v1.CinderVolumeSource - ''' - if isinstance(secret_ref, dict): - secret_ref = LocalObjectReference(**secret_ref) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__06ae43f93ff756a310e6d5117e9cf8625447a987c3d9a7fda373017a190d72bc) - check_type(argname="argument volume_id", value=volume_id, expected_type=type_hints["volume_id"]) - check_type(argname="argument fs_type", value=fs_type, expected_type=type_hints["fs_type"]) - check_type(argname="argument read_only", value=read_only, expected_type=type_hints["read_only"]) - check_type(argname="argument secret_ref", value=secret_ref, expected_type=type_hints["secret_ref"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "volume_id": volume_id, - } - if fs_type is not None: - self._values["fs_type"] = fs_type - if read_only is not None: - self._values["read_only"] = read_only - if secret_ref is not None: - self._values["secret_ref"] = secret_ref - - @builtins.property - def volume_id(self) -> builtins.str: - '''volumeID used to identify the volume in cinder. - - More info: https://examples.k8s.io/mysql-cinder-pd/README.md - - :schema: io.k8s.api.core.v1.CinderVolumeSource#volumeID - ''' - result = self._values.get("volume_id") - assert result is not None, "Required property 'volume_id' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def fs_type(self) -> typing.Optional[builtins.str]: - '''fsType is the filesystem type to mount. - - Must be a filesystem type supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://examples.k8s.io/mysql-cinder-pd/README.md - - :schema: io.k8s.api.core.v1.CinderVolumeSource#fsType - ''' - result = self._values.get("fs_type") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def read_only(self) -> typing.Optional[builtins.bool]: - '''readOnly defaults to false (read/write). - - ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: https://examples.k8s.io/mysql-cinder-pd/README.md - - :schema: io.k8s.api.core.v1.CinderVolumeSource#readOnly - ''' - result = self._values.get("read_only") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def secret_ref(self) -> typing.Optional["LocalObjectReference"]: - '''secretRef is optional: points to a secret object containing parameters used to connect to OpenStack. - - :schema: io.k8s.api.core.v1.CinderVolumeSource#secretRef - ''' - result = self._values.get("secret_ref") - return typing.cast(typing.Optional["LocalObjectReference"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "CinderVolumeSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ClaimSource", - jsii_struct_bases=[], - name_mapping={ - "resource_claim_name": "resourceClaimName", - "resource_claim_template_name": "resourceClaimTemplateName", - }, -) -class ClaimSource: - def __init__( - self, - *, - resource_claim_name: typing.Optional[builtins.str] = None, - resource_claim_template_name: typing.Optional[builtins.str] = None, - ) -> None: - '''ClaimSource describes a reference to a ResourceClaim. - - Exactly one of these fields should be set. Consumers of this type must treat an empty object as if it has an unknown value. - - :param resource_claim_name: ResourceClaimName is the name of a ResourceClaim object in the same namespace as this pod. - :param resource_claim_template_name: ResourceClaimTemplateName is the name of a ResourceClaimTemplate object in the same namespace as this pod. The template will be used to create a new ResourceClaim, which will be bound to this pod. When this pod is deleted, the ResourceClaim will also be deleted. The name of the ResourceClaim will be -, where is the PodResourceClaim.Name. Pod validation will reject the pod if the concatenated name is not valid for a ResourceClaim (e.g. too long). An existing ResourceClaim with that name that is not owned by the pod will not be used for the pod to avoid using an unrelated resource by mistake. Scheduling and pod startup are then blocked until the unrelated ResourceClaim is removed. This field is immutable and no changes will be made to the corresponding ResourceClaim by the control plane after creating the ResourceClaim. - - :schema: io.k8s.api.core.v1.ClaimSource - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__40bafd005da56b205ce1497f55b1fac61f4c26ca711edfc77173ea503ca29f1c) - check_type(argname="argument resource_claim_name", value=resource_claim_name, expected_type=type_hints["resource_claim_name"]) - check_type(argname="argument resource_claim_template_name", value=resource_claim_template_name, expected_type=type_hints["resource_claim_template_name"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if resource_claim_name is not None: - self._values["resource_claim_name"] = resource_claim_name - if resource_claim_template_name is not None: - self._values["resource_claim_template_name"] = resource_claim_template_name - - @builtins.property - def resource_claim_name(self) -> typing.Optional[builtins.str]: - '''ResourceClaimName is the name of a ResourceClaim object in the same namespace as this pod. - - :schema: io.k8s.api.core.v1.ClaimSource#resourceClaimName - ''' - result = self._values.get("resource_claim_name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def resource_claim_template_name(self) -> typing.Optional[builtins.str]: - '''ResourceClaimTemplateName is the name of a ResourceClaimTemplate object in the same namespace as this pod. - - The template will be used to create a new ResourceClaim, which will be bound to this pod. When this pod is deleted, the ResourceClaim will also be deleted. The name of the ResourceClaim will be -, where is the PodResourceClaim.Name. Pod validation will reject the pod if the concatenated name is not valid for a ResourceClaim (e.g. too long). - - An existing ResourceClaim with that name that is not owned by the pod will not be used for the pod to avoid using an unrelated resource by mistake. Scheduling and pod startup are then blocked until the unrelated ResourceClaim is removed. - - This field is immutable and no changes will be made to the corresponding ResourceClaim by the control plane after creating the ResourceClaim. - - :schema: io.k8s.api.core.v1.ClaimSource#resourceClaimTemplateName - ''' - result = self._values.get("resource_claim_template_name") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ClaimSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ClientIpConfig", - jsii_struct_bases=[], - name_mapping={"timeout_seconds": "timeoutSeconds"}, -) -class ClientIpConfig: - def __init__(self, *, timeout_seconds: typing.Optional[jsii.Number] = None) -> None: - '''ClientIPConfig represents the configurations of Client IP based session affinity. - - :param timeout_seconds: timeoutSeconds specifies the seconds of ClientIP type session sticky time. The value must be >0 && <=86400(for 1 day) if ServiceAffinity == "ClientIP". Default value is 10800(for 3 hours). - - :schema: io.k8s.api.core.v1.ClientIPConfig - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__29a449f3b3357364e9fe2eedbf3639c327226f11ef6b646b27d4a54e71dc5c9e) - check_type(argname="argument timeout_seconds", value=timeout_seconds, expected_type=type_hints["timeout_seconds"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if timeout_seconds is not None: - self._values["timeout_seconds"] = timeout_seconds - - @builtins.property - def timeout_seconds(self) -> typing.Optional[jsii.Number]: - '''timeoutSeconds specifies the seconds of ClientIP type session sticky time. - - The value must be >0 && <=86400(for 1 day) if ServiceAffinity == "ClientIP". Default value is 10800(for 3 hours). - - :schema: io.k8s.api.core.v1.ClientIPConfig#timeoutSeconds - ''' - result = self._values.get("timeout_seconds") - return typing.cast(typing.Optional[jsii.Number], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ClientIpConfig(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ClusterCidrSpecV1Alpha1", - jsii_struct_bases=[], - name_mapping={ - "per_node_host_bits": "perNodeHostBits", - "ipv4": "ipv4", - "ipv6": "ipv6", - "node_selector": "nodeSelector", - }, -) -class ClusterCidrSpecV1Alpha1: - def __init__( - self, - *, - per_node_host_bits: jsii.Number, - ipv4: typing.Optional[builtins.str] = None, - ipv6: typing.Optional[builtins.str] = None, - node_selector: typing.Optional[typing.Union["NodeSelector", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''ClusterCIDRSpec defines the desired state of ClusterCIDR. - - :param per_node_host_bits: PerNodeHostBits defines the number of host bits to be configured per node. A subnet mask determines how much of the address is used for network bits and host bits. For example an IPv4 address of 192.168.0.0/24, splits the address into 24 bits for the network portion and 8 bits for the host portion. To allocate 256 IPs, set this field to 8 (a /24 mask for IPv4 or a /120 for IPv6). Minimum value is 4 (16 IPs). This field is immutable. - :param ipv4: IPv4 defines an IPv4 IP block in CIDR notation(e.g. "10.0.0.0/8"). At least one of IPv4 and IPv6 must be specified. This field is immutable. - :param ipv6: IPv6 defines an IPv6 IP block in CIDR notation(e.g. "2001:db8::/64"). At least one of IPv4 and IPv6 must be specified. This field is immutable. - :param node_selector: NodeSelector defines which nodes the config is applicable to. An empty or nil NodeSelector selects all nodes. This field is immutable. - - :schema: io.k8s.api.networking.v1alpha1.ClusterCIDRSpec - ''' - if isinstance(node_selector, dict): - node_selector = NodeSelector(**node_selector) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__fe618ea608b9075a33b355598f43687c5206288062267eb0d99d0a9ca0ab859e) - check_type(argname="argument per_node_host_bits", value=per_node_host_bits, expected_type=type_hints["per_node_host_bits"]) - check_type(argname="argument ipv4", value=ipv4, expected_type=type_hints["ipv4"]) - check_type(argname="argument ipv6", value=ipv6, expected_type=type_hints["ipv6"]) - check_type(argname="argument node_selector", value=node_selector, expected_type=type_hints["node_selector"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "per_node_host_bits": per_node_host_bits, - } - if ipv4 is not None: - self._values["ipv4"] = ipv4 - if ipv6 is not None: - self._values["ipv6"] = ipv6 - if node_selector is not None: - self._values["node_selector"] = node_selector - - @builtins.property - def per_node_host_bits(self) -> jsii.Number: - '''PerNodeHostBits defines the number of host bits to be configured per node. - - A subnet mask determines how much of the address is used for network bits and host bits. For example an IPv4 address of 192.168.0.0/24, splits the address into 24 bits for the network portion and 8 bits for the host portion. To allocate 256 IPs, set this field to 8 (a /24 mask for IPv4 or a /120 for IPv6). Minimum value is 4 (16 IPs). This field is immutable. - - :schema: io.k8s.api.networking.v1alpha1.ClusterCIDRSpec#perNodeHostBits - ''' - result = self._values.get("per_node_host_bits") - assert result is not None, "Required property 'per_node_host_bits' is missing" - return typing.cast(jsii.Number, result) - - @builtins.property - def ipv4(self) -> typing.Optional[builtins.str]: - '''IPv4 defines an IPv4 IP block in CIDR notation(e.g. "10.0.0.0/8"). At least one of IPv4 and IPv6 must be specified. This field is immutable. - - :schema: io.k8s.api.networking.v1alpha1.ClusterCIDRSpec#ipv4 - ''' - result = self._values.get("ipv4") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def ipv6(self) -> typing.Optional[builtins.str]: - '''IPv6 defines an IPv6 IP block in CIDR notation(e.g. "2001:db8::/64"). At least one of IPv4 and IPv6 must be specified. This field is immutable. - - :schema: io.k8s.api.networking.v1alpha1.ClusterCIDRSpec#ipv6 - ''' - result = self._values.get("ipv6") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def node_selector(self) -> typing.Optional["NodeSelector"]: - '''NodeSelector defines which nodes the config is applicable to. - - An empty or nil NodeSelector selects all nodes. This field is immutable. - - :schema: io.k8s.api.networking.v1alpha1.ClusterCIDRSpec#nodeSelector - ''' - result = self._values.get("node_selector") - return typing.cast(typing.Optional["NodeSelector"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ClusterCidrSpecV1Alpha1(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ComponentCondition", - jsii_struct_bases=[], - name_mapping={ - "status": "status", - "type": "type", - "error": "error", - "message": "message", - }, -) -class ComponentCondition: - def __init__( - self, - *, - status: builtins.str, - type: builtins.str, - error: typing.Optional[builtins.str] = None, - message: typing.Optional[builtins.str] = None, - ) -> None: - '''Information about the condition of a component. - - :param status: Status of the condition for a component. Valid values for "Healthy": "True", "False", or "Unknown". - :param type: Type of condition for a component. Valid value: "Healthy" - :param error: Condition error code for a component. For example, a health check error code. - :param message: Message about the condition for a component. For example, information about a health check. - - :schema: io.k8s.api.core.v1.ComponentCondition - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__e5c6f493a36d20a0f5c15799a425473df0ef3509854c45bf00c9f2d1df43078b) - check_type(argname="argument status", value=status, expected_type=type_hints["status"]) - check_type(argname="argument type", value=type, expected_type=type_hints["type"]) - check_type(argname="argument error", value=error, expected_type=type_hints["error"]) - check_type(argname="argument message", value=message, expected_type=type_hints["message"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "status": status, - "type": type, - } - if error is not None: - self._values["error"] = error - if message is not None: - self._values["message"] = message - - @builtins.property - def status(self) -> builtins.str: - '''Status of the condition for a component. - - Valid values for "Healthy": "True", "False", or "Unknown". - - :schema: io.k8s.api.core.v1.ComponentCondition#status - ''' - result = self._values.get("status") - assert result is not None, "Required property 'status' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def type(self) -> builtins.str: - '''Type of condition for a component. - - Valid value: "Healthy" - - :schema: io.k8s.api.core.v1.ComponentCondition#type - ''' - result = self._values.get("type") - assert result is not None, "Required property 'type' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def error(self) -> typing.Optional[builtins.str]: - '''Condition error code for a component. - - For example, a health check error code. - - :schema: io.k8s.api.core.v1.ComponentCondition#error - ''' - result = self._values.get("error") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def message(self) -> typing.Optional[builtins.str]: - '''Message about the condition for a component. - - For example, information about a health check. - - :schema: io.k8s.api.core.v1.ComponentCondition#message - ''' - result = self._values.get("message") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ComponentCondition(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ConfigMapEnvSource", - jsii_struct_bases=[], - name_mapping={"name": "name", "optional": "optional"}, -) -class ConfigMapEnvSource: - def __init__( - self, - *, - name: typing.Optional[builtins.str] = None, - optional: typing.Optional[builtins.bool] = None, - ) -> None: - '''ConfigMapEnvSource selects a ConfigMap to populate the environment variables with. - - The contents of the target ConfigMap's Data field will represent the key-value pairs as environment variables. - - :param name: Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - :param optional: Specify whether the ConfigMap must be defined. - - :schema: io.k8s.api.core.v1.ConfigMapEnvSource - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__370b1c0b36f05ff3192a8cbbd224accabfbc47a41badefad8eae8d70919df5a8) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument optional", value=optional, expected_type=type_hints["optional"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if name is not None: - self._values["name"] = name - if optional is not None: - self._values["optional"] = optional - - @builtins.property - def name(self) -> typing.Optional[builtins.str]: - '''Name of the referent. - - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - - :schema: io.k8s.api.core.v1.ConfigMapEnvSource#name - ''' - result = self._values.get("name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def optional(self) -> typing.Optional[builtins.bool]: - '''Specify whether the ConfigMap must be defined. - - :schema: io.k8s.api.core.v1.ConfigMapEnvSource#optional - ''' - result = self._values.get("optional") - return typing.cast(typing.Optional[builtins.bool], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ConfigMapEnvSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ConfigMapKeySelector", - jsii_struct_bases=[], - name_mapping={"key": "key", "name": "name", "optional": "optional"}, -) -class ConfigMapKeySelector: - def __init__( - self, - *, - key: builtins.str, - name: typing.Optional[builtins.str] = None, - optional: typing.Optional[builtins.bool] = None, - ) -> None: - '''Selects a key from a ConfigMap. - - :param key: The key to select. - :param name: Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - :param optional: Specify whether the ConfigMap or its key must be defined. - - :schema: io.k8s.api.core.v1.ConfigMapKeySelector - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__e7b538afefcd3178906246a4633aa3edf9a64dc6b4f99e4f91adaab9981d5e5e) - check_type(argname="argument key", value=key, expected_type=type_hints["key"]) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument optional", value=optional, expected_type=type_hints["optional"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "key": key, - } - if name is not None: - self._values["name"] = name - if optional is not None: - self._values["optional"] = optional - - @builtins.property - def key(self) -> builtins.str: - '''The key to select. - - :schema: io.k8s.api.core.v1.ConfigMapKeySelector#key - ''' - result = self._values.get("key") - assert result is not None, "Required property 'key' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def name(self) -> typing.Optional[builtins.str]: - '''Name of the referent. - - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - - :schema: io.k8s.api.core.v1.ConfigMapKeySelector#name - ''' - result = self._values.get("name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def optional(self) -> typing.Optional[builtins.bool]: - '''Specify whether the ConfigMap or its key must be defined. - - :schema: io.k8s.api.core.v1.ConfigMapKeySelector#optional - ''' - result = self._values.get("optional") - return typing.cast(typing.Optional[builtins.bool], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ConfigMapKeySelector(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ConfigMapNodeConfigSource", - jsii_struct_bases=[], - name_mapping={ - "kubelet_config_key": "kubeletConfigKey", - "name": "name", - "namespace": "namespace", - "resource_version": "resourceVersion", - "uid": "uid", - }, -) -class ConfigMapNodeConfigSource: - def __init__( - self, - *, - kubelet_config_key: builtins.str, - name: builtins.str, - namespace: builtins.str, - resource_version: typing.Optional[builtins.str] = None, - uid: typing.Optional[builtins.str] = None, - ) -> None: - '''ConfigMapNodeConfigSource contains the information to reference a ConfigMap as a config source for the Node. - - This API is deprecated since 1.22: https://git.k8s.io/enhancements/keps/sig-node/281-dynamic-kubelet-configuration - - :param kubelet_config_key: KubeletConfigKey declares which key of the referenced ConfigMap corresponds to the KubeletConfiguration structure This field is required in all cases. - :param name: Name is the metadata.name of the referenced ConfigMap. This field is required in all cases. - :param namespace: Namespace is the metadata.namespace of the referenced ConfigMap. This field is required in all cases. - :param resource_version: ResourceVersion is the metadata.ResourceVersion of the referenced ConfigMap. This field is forbidden in Node.Spec, and required in Node.Status. - :param uid: UID is the metadata.UID of the referenced ConfigMap. This field is forbidden in Node.Spec, and required in Node.Status. - - :schema: io.k8s.api.core.v1.ConfigMapNodeConfigSource - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__1e65fe961a56a03c3374ec1160978c65396b145146e3c13dc4180daa47d645b1) - check_type(argname="argument kubelet_config_key", value=kubelet_config_key, expected_type=type_hints["kubelet_config_key"]) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument namespace", value=namespace, expected_type=type_hints["namespace"]) - check_type(argname="argument resource_version", value=resource_version, expected_type=type_hints["resource_version"]) - check_type(argname="argument uid", value=uid, expected_type=type_hints["uid"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "kubelet_config_key": kubelet_config_key, - "name": name, - "namespace": namespace, - } - if resource_version is not None: - self._values["resource_version"] = resource_version - if uid is not None: - self._values["uid"] = uid - - @builtins.property - def kubelet_config_key(self) -> builtins.str: - '''KubeletConfigKey declares which key of the referenced ConfigMap corresponds to the KubeletConfiguration structure This field is required in all cases. - - :schema: io.k8s.api.core.v1.ConfigMapNodeConfigSource#kubeletConfigKey - ''' - result = self._values.get("kubelet_config_key") - assert result is not None, "Required property 'kubelet_config_key' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def name(self) -> builtins.str: - '''Name is the metadata.name of the referenced ConfigMap. This field is required in all cases. - - :schema: io.k8s.api.core.v1.ConfigMapNodeConfigSource#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def namespace(self) -> builtins.str: - '''Namespace is the metadata.namespace of the referenced ConfigMap. This field is required in all cases. - - :schema: io.k8s.api.core.v1.ConfigMapNodeConfigSource#namespace - ''' - result = self._values.get("namespace") - assert result is not None, "Required property 'namespace' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def resource_version(self) -> typing.Optional[builtins.str]: - '''ResourceVersion is the metadata.ResourceVersion of the referenced ConfigMap. This field is forbidden in Node.Spec, and required in Node.Status. - - :schema: io.k8s.api.core.v1.ConfigMapNodeConfigSource#resourceVersion - ''' - result = self._values.get("resource_version") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def uid(self) -> typing.Optional[builtins.str]: - '''UID is the metadata.UID of the referenced ConfigMap. This field is forbidden in Node.Spec, and required in Node.Status. - - :schema: io.k8s.api.core.v1.ConfigMapNodeConfigSource#uid - ''' - result = self._values.get("uid") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ConfigMapNodeConfigSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ConfigMapProjection", - jsii_struct_bases=[], - name_mapping={"items": "items", "name": "name", "optional": "optional"}, -) -class ConfigMapProjection: - def __init__( - self, - *, - items: typing.Optional[typing.Sequence[typing.Union["KeyToPath", typing.Dict[builtins.str, typing.Any]]]] = None, - name: typing.Optional[builtins.str] = None, - optional: typing.Optional[builtins.bool] = None, - ) -> None: - '''Adapts a ConfigMap into a projected volume. - - The contents of the target ConfigMap's Data field will be presented in a projected volume as files using the keys in the Data field as the file names, unless the items element is populated with specific mappings of keys to paths. Note that this is identical to a configmap volume source without the default mode. - - :param items: items if unspecified, each key-value pair in the Data field of the referenced ConfigMap will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the ConfigMap, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'. - :param name: Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - :param optional: optional specify whether the ConfigMap or its keys must be defined. - - :schema: io.k8s.api.core.v1.ConfigMapProjection - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__8f0e7adaaf9481758c5623030368e21ede02645c5c82f6c273c7c50fce12b22c) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument optional", value=optional, expected_type=type_hints["optional"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if items is not None: - self._values["items"] = items - if name is not None: - self._values["name"] = name - if optional is not None: - self._values["optional"] = optional - - @builtins.property - def items(self) -> typing.Optional[typing.List["KeyToPath"]]: - '''items if unspecified, each key-value pair in the Data field of the referenced ConfigMap will be projected into the volume as a file whose name is the key and content is the value. - - If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the ConfigMap, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'. - - :schema: io.k8s.api.core.v1.ConfigMapProjection#items - ''' - result = self._values.get("items") - return typing.cast(typing.Optional[typing.List["KeyToPath"]], result) - - @builtins.property - def name(self) -> typing.Optional[builtins.str]: - '''Name of the referent. - - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - - :schema: io.k8s.api.core.v1.ConfigMapProjection#name - ''' - result = self._values.get("name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def optional(self) -> typing.Optional[builtins.bool]: - '''optional specify whether the ConfigMap or its keys must be defined. - - :schema: io.k8s.api.core.v1.ConfigMapProjection#optional - ''' - result = self._values.get("optional") - return typing.cast(typing.Optional[builtins.bool], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ConfigMapProjection(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ConfigMapVolumeSource", - jsii_struct_bases=[], - name_mapping={ - "default_mode": "defaultMode", - "items": "items", - "name": "name", - "optional": "optional", - }, -) -class ConfigMapVolumeSource: - def __init__( - self, - *, - default_mode: typing.Optional[jsii.Number] = None, - items: typing.Optional[typing.Sequence[typing.Union["KeyToPath", typing.Dict[builtins.str, typing.Any]]]] = None, - name: typing.Optional[builtins.str] = None, - optional: typing.Optional[builtins.bool] = None, - ) -> None: - '''Adapts a ConfigMap into a volume. - - The contents of the target ConfigMap's Data field will be presented in a volume as files using the keys in the Data field as the file names, unless the items element is populated with specific mappings of keys to paths. ConfigMap volumes support ownership management and SELinux relabeling. - - :param default_mode: defaultMode is optional: mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set. Default: 644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set. - :param items: items if unspecified, each key-value pair in the Data field of the referenced ConfigMap will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the ConfigMap, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'. - :param name: Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - :param optional: optional specify whether the ConfigMap or its keys must be defined. - - :schema: io.k8s.api.core.v1.ConfigMapVolumeSource - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__f732f389aef3745668fe1484c8ff5f95aba0fd695dd9a611adf068af963d4ed6) - check_type(argname="argument default_mode", value=default_mode, expected_type=type_hints["default_mode"]) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument optional", value=optional, expected_type=type_hints["optional"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if default_mode is not None: - self._values["default_mode"] = default_mode - if items is not None: - self._values["items"] = items - if name is not None: - self._values["name"] = name - if optional is not None: - self._values["optional"] = optional - - @builtins.property - def default_mode(self) -> typing.Optional[jsii.Number]: - '''defaultMode is optional: mode bits used to set permissions on created files by default. - - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set. - - :default: 644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set. - - :schema: io.k8s.api.core.v1.ConfigMapVolumeSource#defaultMode - ''' - result = self._values.get("default_mode") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def items(self) -> typing.Optional[typing.List["KeyToPath"]]: - '''items if unspecified, each key-value pair in the Data field of the referenced ConfigMap will be projected into the volume as a file whose name is the key and content is the value. - - If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the ConfigMap, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'. - - :schema: io.k8s.api.core.v1.ConfigMapVolumeSource#items - ''' - result = self._values.get("items") - return typing.cast(typing.Optional[typing.List["KeyToPath"]], result) - - @builtins.property - def name(self) -> typing.Optional[builtins.str]: - '''Name of the referent. - - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - - :schema: io.k8s.api.core.v1.ConfigMapVolumeSource#name - ''' - result = self._values.get("name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def optional(self) -> typing.Optional[builtins.bool]: - '''optional specify whether the ConfigMap or its keys must be defined. - - :schema: io.k8s.api.core.v1.ConfigMapVolumeSource#optional - ''' - result = self._values.get("optional") - return typing.cast(typing.Optional[builtins.bool], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ConfigMapVolumeSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.Container", - jsii_struct_bases=[], - name_mapping={ - "name": "name", - "args": "args", - "command": "command", - "env": "env", - "env_from": "envFrom", - "image": "image", - "image_pull_policy": "imagePullPolicy", - "lifecycle": "lifecycle", - "liveness_probe": "livenessProbe", - "ports": "ports", - "readiness_probe": "readinessProbe", - "resources": "resources", - "security_context": "securityContext", - "startup_probe": "startupProbe", - "stdin": "stdin", - "stdin_once": "stdinOnce", - "termination_message_path": "terminationMessagePath", - "termination_message_policy": "terminationMessagePolicy", - "tty": "tty", - "volume_devices": "volumeDevices", - "volume_mounts": "volumeMounts", - "working_dir": "workingDir", - }, -) -class Container: - def __init__( - self, - *, - name: builtins.str, - args: typing.Optional[typing.Sequence[builtins.str]] = None, - command: typing.Optional[typing.Sequence[builtins.str]] = None, - env: typing.Optional[typing.Sequence[typing.Union["EnvVar", typing.Dict[builtins.str, typing.Any]]]] = None, - env_from: typing.Optional[typing.Sequence[typing.Union["EnvFromSource", typing.Dict[builtins.str, typing.Any]]]] = None, - image: typing.Optional[builtins.str] = None, - image_pull_policy: typing.Optional[builtins.str] = None, - lifecycle: typing.Optional[typing.Union["Lifecycle", typing.Dict[builtins.str, typing.Any]]] = None, - liveness_probe: typing.Optional[typing.Union["Probe", typing.Dict[builtins.str, typing.Any]]] = None, - ports: typing.Optional[typing.Sequence[typing.Union["ContainerPort", typing.Dict[builtins.str, typing.Any]]]] = None, - readiness_probe: typing.Optional[typing.Union["Probe", typing.Dict[builtins.str, typing.Any]]] = None, - resources: typing.Optional[typing.Union["ResourceRequirements", typing.Dict[builtins.str, typing.Any]]] = None, - security_context: typing.Optional[typing.Union["SecurityContext", typing.Dict[builtins.str, typing.Any]]] = None, - startup_probe: typing.Optional[typing.Union["Probe", typing.Dict[builtins.str, typing.Any]]] = None, - stdin: typing.Optional[builtins.bool] = None, - stdin_once: typing.Optional[builtins.bool] = None, - termination_message_path: typing.Optional[builtins.str] = None, - termination_message_policy: typing.Optional[builtins.str] = None, - tty: typing.Optional[builtins.bool] = None, - volume_devices: typing.Optional[typing.Sequence[typing.Union["VolumeDevice", typing.Dict[builtins.str, typing.Any]]]] = None, - volume_mounts: typing.Optional[typing.Sequence[typing.Union["VolumeMount", typing.Dict[builtins.str, typing.Any]]]] = None, - working_dir: typing.Optional[builtins.str] = None, - ) -> None: - '''A single application container that you want to run within a pod. - - :param name: Name of the container specified as a DNS_LABEL. Each container in a pod must have a unique name (DNS_LABEL). Cannot be updated. - :param args: Arguments to the entrypoint. The container image's CMD is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell - :param command: Entrypoint array. Not executed within a shell. The container image's ENTRYPOINT is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell - :param env: List of environment variables to set in the container. Cannot be updated. - :param env_from: List of sources to populate environment variables in the container. The keys defined within a source must be a C_IDENTIFIER. All invalid keys will be reported as an event when the container is starting. When a key exists in multiple sources, the value associated with the last source will take precedence. Values defined by an Env with a duplicate key will take precedence. Cannot be updated. - :param image: Container image name. More info: https://kubernetes.io/docs/concepts/containers/images This field is optional to allow higher level config management to default or override container images in workload controllers like Deployments and StatefulSets. - :param image_pull_policy: Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images Default: Always if :latest tag is specified, or IfNotPresent otherwise. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images - :param lifecycle: Actions that the management system should take in response to container lifecycle events. Cannot be updated. - :param liveness_probe: Periodic probe of container liveness. Container will be restarted if the probe fails. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - :param ports: List of ports to expose from the container. Not specifying a port here DOES NOT prevent that port from being exposed. Any port which is listening on the default "0.0.0.0" address inside a container will be accessible from the network. Modifying this array with strategic merge patch may corrupt the data. For more information See https://github.com/kubernetes/kubernetes/issues/108255. Cannot be updated. - :param readiness_probe: Periodic probe of container service readiness. Container will be removed from service endpoints if the probe fails. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - :param resources: Compute Resources required by this container. Cannot be updated. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - :param security_context: SecurityContext defines the security options the container should be run with. If set, the fields of SecurityContext override the equivalent fields of PodSecurityContext. More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ - :param startup_probe: StartupProbe indicates that the Pod has successfully initialized. If specified, no other probes are executed until this completes successfully. If this probe fails, the Pod will be restarted, just as if the livenessProbe failed. This can be used to provide different probe parameters at the beginning of a Pod's lifecycle, when it might take a long time to load data or warm a cache, than during steady-state operation. This cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - :param stdin: Whether this container should allocate a buffer for stdin in the container runtime. If this is not set, reads from stdin in the container will always result in EOF. Default is false. Default: false. - :param stdin_once: Whether the container runtime should close the stdin channel after it has been opened by a single attach. When stdin is true the stdin stream will remain open across multiple attach sessions. If stdinOnce is set to true, stdin is opened on container start, is empty until the first client attaches to stdin, and then remains open and accepts data until the client disconnects, at which time stdin is closed and remains closed until the container is restarted. If this flag is false, a container processes that reads from stdin will never receive an EOF. Default is false Default: false - :param termination_message_path: Optional: Path at which the file to which the container's termination message will be written is mounted into the container's filesystem. Message written is intended to be brief final status, such as an assertion failure message. Will be truncated by the node if greater than 4096 bytes. The total message length across all containers will be limited to 12kb. Defaults to /dev/termination-log. Cannot be updated. Default: dev/termination-log. Cannot be updated. - :param termination_message_policy: Indicate how the termination message should be populated. File will use the contents of terminationMessagePath to populate the container status message on both success and failure. FallbackToLogsOnError will use the last chunk of container log output if the termination message file is empty and the container exited with an error. The log output is limited to 2048 bytes or 80 lines, whichever is smaller. Defaults to File. Cannot be updated. Default: File. Cannot be updated. - :param tty: Whether this container should allocate a TTY for itself, also requires 'stdin' to be true. Default is false. Default: false. - :param volume_devices: volumeDevices is the list of block devices to be used by the container. - :param volume_mounts: Pod volumes to mount into the container's filesystem. Cannot be updated. - :param working_dir: Container's working directory. If not specified, the container runtime's default will be used, which might be configured in the container image. Cannot be updated. - - :schema: io.k8s.api.core.v1.Container - ''' - if isinstance(lifecycle, dict): - lifecycle = Lifecycle(**lifecycle) - if isinstance(liveness_probe, dict): - liveness_probe = Probe(**liveness_probe) - if isinstance(readiness_probe, dict): - readiness_probe = Probe(**readiness_probe) - if isinstance(resources, dict): - resources = ResourceRequirements(**resources) - if isinstance(security_context, dict): - security_context = SecurityContext(**security_context) - if isinstance(startup_probe, dict): - startup_probe = Probe(**startup_probe) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__1b3b3fe219125d2e54fdddd91ecda52e6a495f38680a3a53b33f1b02c1b671da) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument args", value=args, expected_type=type_hints["args"]) - check_type(argname="argument command", value=command, expected_type=type_hints["command"]) - check_type(argname="argument env", value=env, expected_type=type_hints["env"]) - check_type(argname="argument env_from", value=env_from, expected_type=type_hints["env_from"]) - check_type(argname="argument image", value=image, expected_type=type_hints["image"]) - check_type(argname="argument image_pull_policy", value=image_pull_policy, expected_type=type_hints["image_pull_policy"]) - check_type(argname="argument lifecycle", value=lifecycle, expected_type=type_hints["lifecycle"]) - check_type(argname="argument liveness_probe", value=liveness_probe, expected_type=type_hints["liveness_probe"]) - check_type(argname="argument ports", value=ports, expected_type=type_hints["ports"]) - check_type(argname="argument readiness_probe", value=readiness_probe, expected_type=type_hints["readiness_probe"]) - check_type(argname="argument resources", value=resources, expected_type=type_hints["resources"]) - check_type(argname="argument security_context", value=security_context, expected_type=type_hints["security_context"]) - check_type(argname="argument startup_probe", value=startup_probe, expected_type=type_hints["startup_probe"]) - check_type(argname="argument stdin", value=stdin, expected_type=type_hints["stdin"]) - check_type(argname="argument stdin_once", value=stdin_once, expected_type=type_hints["stdin_once"]) - check_type(argname="argument termination_message_path", value=termination_message_path, expected_type=type_hints["termination_message_path"]) - check_type(argname="argument termination_message_policy", value=termination_message_policy, expected_type=type_hints["termination_message_policy"]) - check_type(argname="argument tty", value=tty, expected_type=type_hints["tty"]) - check_type(argname="argument volume_devices", value=volume_devices, expected_type=type_hints["volume_devices"]) - check_type(argname="argument volume_mounts", value=volume_mounts, expected_type=type_hints["volume_mounts"]) - check_type(argname="argument working_dir", value=working_dir, expected_type=type_hints["working_dir"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "name": name, - } - if args is not None: - self._values["args"] = args - if command is not None: - self._values["command"] = command - if env is not None: - self._values["env"] = env - if env_from is not None: - self._values["env_from"] = env_from - if image is not None: - self._values["image"] = image - if image_pull_policy is not None: - self._values["image_pull_policy"] = image_pull_policy - if lifecycle is not None: - self._values["lifecycle"] = lifecycle - if liveness_probe is not None: - self._values["liveness_probe"] = liveness_probe - if ports is not None: - self._values["ports"] = ports - if readiness_probe is not None: - self._values["readiness_probe"] = readiness_probe - if resources is not None: - self._values["resources"] = resources - if security_context is not None: - self._values["security_context"] = security_context - if startup_probe is not None: - self._values["startup_probe"] = startup_probe - if stdin is not None: - self._values["stdin"] = stdin - if stdin_once is not None: - self._values["stdin_once"] = stdin_once - if termination_message_path is not None: - self._values["termination_message_path"] = termination_message_path - if termination_message_policy is not None: - self._values["termination_message_policy"] = termination_message_policy - if tty is not None: - self._values["tty"] = tty - if volume_devices is not None: - self._values["volume_devices"] = volume_devices - if volume_mounts is not None: - self._values["volume_mounts"] = volume_mounts - if working_dir is not None: - self._values["working_dir"] = working_dir - - @builtins.property - def name(self) -> builtins.str: - '''Name of the container specified as a DNS_LABEL. - - Each container in a pod must have a unique name (DNS_LABEL). Cannot be updated. - - :schema: io.k8s.api.core.v1.Container#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def args(self) -> typing.Optional[typing.List[builtins.str]]: - '''Arguments to the entrypoint. - - The container image's CMD is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell - - :schema: io.k8s.api.core.v1.Container#args - ''' - result = self._values.get("args") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def command(self) -> typing.Optional[typing.List[builtins.str]]: - '''Entrypoint array. - - Not executed within a shell. The container image's ENTRYPOINT is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell - - :schema: io.k8s.api.core.v1.Container#command - ''' - result = self._values.get("command") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def env(self) -> typing.Optional[typing.List["EnvVar"]]: - '''List of environment variables to set in the container. - - Cannot be updated. - - :schema: io.k8s.api.core.v1.Container#env - ''' - result = self._values.get("env") - return typing.cast(typing.Optional[typing.List["EnvVar"]], result) - - @builtins.property - def env_from(self) -> typing.Optional[typing.List["EnvFromSource"]]: - '''List of sources to populate environment variables in the container. - - The keys defined within a source must be a C_IDENTIFIER. All invalid keys will be reported as an event when the container is starting. When a key exists in multiple sources, the value associated with the last source will take precedence. Values defined by an Env with a duplicate key will take precedence. Cannot be updated. - - :schema: io.k8s.api.core.v1.Container#envFrom - ''' - result = self._values.get("env_from") - return typing.cast(typing.Optional[typing.List["EnvFromSource"]], result) - - @builtins.property - def image(self) -> typing.Optional[builtins.str]: - '''Container image name. - - More info: https://kubernetes.io/docs/concepts/containers/images This field is optional to allow higher level config management to default or override container images in workload controllers like Deployments and StatefulSets. - - :schema: io.k8s.api.core.v1.Container#image - ''' - result = self._values.get("image") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def image_pull_policy(self) -> typing.Optional[builtins.str]: - '''Image pull policy. - - One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images - - :default: Always if :latest tag is specified, or IfNotPresent otherwise. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images - - :schema: io.k8s.api.core.v1.Container#imagePullPolicy - ''' - result = self._values.get("image_pull_policy") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def lifecycle(self) -> typing.Optional["Lifecycle"]: - '''Actions that the management system should take in response to container lifecycle events. - - Cannot be updated. - - :schema: io.k8s.api.core.v1.Container#lifecycle - ''' - result = self._values.get("lifecycle") - return typing.cast(typing.Optional["Lifecycle"], result) - - @builtins.property - def liveness_probe(self) -> typing.Optional["Probe"]: - '''Periodic probe of container liveness. - - Container will be restarted if the probe fails. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - - :schema: io.k8s.api.core.v1.Container#livenessProbe - ''' - result = self._values.get("liveness_probe") - return typing.cast(typing.Optional["Probe"], result) - - @builtins.property - def ports(self) -> typing.Optional[typing.List["ContainerPort"]]: - '''List of ports to expose from the container. - - Not specifying a port here DOES NOT prevent that port from being exposed. Any port which is listening on the default "0.0.0.0" address inside a container will be accessible from the network. Modifying this array with strategic merge patch may corrupt the data. For more information See https://github.com/kubernetes/kubernetes/issues/108255. Cannot be updated. - - :schema: io.k8s.api.core.v1.Container#ports - ''' - result = self._values.get("ports") - return typing.cast(typing.Optional[typing.List["ContainerPort"]], result) - - @builtins.property - def readiness_probe(self) -> typing.Optional["Probe"]: - '''Periodic probe of container service readiness. - - Container will be removed from service endpoints if the probe fails. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - - :schema: io.k8s.api.core.v1.Container#readinessProbe - ''' - result = self._values.get("readiness_probe") - return typing.cast(typing.Optional["Probe"], result) - - @builtins.property - def resources(self) -> typing.Optional["ResourceRequirements"]: - '''Compute Resources required by this container. - - Cannot be updated. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - - :schema: io.k8s.api.core.v1.Container#resources - ''' - result = self._values.get("resources") - return typing.cast(typing.Optional["ResourceRequirements"], result) - - @builtins.property - def security_context(self) -> typing.Optional["SecurityContext"]: - '''SecurityContext defines the security options the container should be run with. - - If set, the fields of SecurityContext override the equivalent fields of PodSecurityContext. More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ - - :schema: io.k8s.api.core.v1.Container#securityContext - ''' - result = self._values.get("security_context") - return typing.cast(typing.Optional["SecurityContext"], result) - - @builtins.property - def startup_probe(self) -> typing.Optional["Probe"]: - '''StartupProbe indicates that the Pod has successfully initialized. - - If specified, no other probes are executed until this completes successfully. If this probe fails, the Pod will be restarted, just as if the livenessProbe failed. This can be used to provide different probe parameters at the beginning of a Pod's lifecycle, when it might take a long time to load data or warm a cache, than during steady-state operation. This cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - - :schema: io.k8s.api.core.v1.Container#startupProbe - ''' - result = self._values.get("startup_probe") - return typing.cast(typing.Optional["Probe"], result) - - @builtins.property - def stdin(self) -> typing.Optional[builtins.bool]: - '''Whether this container should allocate a buffer for stdin in the container runtime. - - If this is not set, reads from stdin in the container will always result in EOF. Default is false. - - :default: false. - - :schema: io.k8s.api.core.v1.Container#stdin - ''' - result = self._values.get("stdin") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def stdin_once(self) -> typing.Optional[builtins.bool]: - '''Whether the container runtime should close the stdin channel after it has been opened by a single attach. - - When stdin is true the stdin stream will remain open across multiple attach sessions. If stdinOnce is set to true, stdin is opened on container start, is empty until the first client attaches to stdin, and then remains open and accepts data until the client disconnects, at which time stdin is closed and remains closed until the container is restarted. If this flag is false, a container processes that reads from stdin will never receive an EOF. Default is false - - :default: false - - :schema: io.k8s.api.core.v1.Container#stdinOnce - ''' - result = self._values.get("stdin_once") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def termination_message_path(self) -> typing.Optional[builtins.str]: - '''Optional: Path at which the file to which the container's termination message will be written is mounted into the container's filesystem. - - Message written is intended to be brief final status, such as an assertion failure message. Will be truncated by the node if greater than 4096 bytes. The total message length across all containers will be limited to 12kb. Defaults to /dev/termination-log. Cannot be updated. - - :default: dev/termination-log. Cannot be updated. - - :schema: io.k8s.api.core.v1.Container#terminationMessagePath - ''' - result = self._values.get("termination_message_path") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def termination_message_policy(self) -> typing.Optional[builtins.str]: - '''Indicate how the termination message should be populated. - - File will use the contents of terminationMessagePath to populate the container status message on both success and failure. FallbackToLogsOnError will use the last chunk of container log output if the termination message file is empty and the container exited with an error. The log output is limited to 2048 bytes or 80 lines, whichever is smaller. Defaults to File. Cannot be updated. - - :default: File. Cannot be updated. - - :schema: io.k8s.api.core.v1.Container#terminationMessagePolicy - ''' - result = self._values.get("termination_message_policy") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def tty(self) -> typing.Optional[builtins.bool]: - '''Whether this container should allocate a TTY for itself, also requires 'stdin' to be true. - - Default is false. - - :default: false. - - :schema: io.k8s.api.core.v1.Container#tty - ''' - result = self._values.get("tty") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def volume_devices(self) -> typing.Optional[typing.List["VolumeDevice"]]: - '''volumeDevices is the list of block devices to be used by the container. - - :schema: io.k8s.api.core.v1.Container#volumeDevices - ''' - result = self._values.get("volume_devices") - return typing.cast(typing.Optional[typing.List["VolumeDevice"]], result) - - @builtins.property - def volume_mounts(self) -> typing.Optional[typing.List["VolumeMount"]]: - '''Pod volumes to mount into the container's filesystem. - - Cannot be updated. - - :schema: io.k8s.api.core.v1.Container#volumeMounts - ''' - result = self._values.get("volume_mounts") - return typing.cast(typing.Optional[typing.List["VolumeMount"]], result) - - @builtins.property - def working_dir(self) -> typing.Optional[builtins.str]: - '''Container's working directory. - - If not specified, the container runtime's default will be used, which might be configured in the container image. Cannot be updated. - - :schema: io.k8s.api.core.v1.Container#workingDir - ''' - result = self._values.get("working_dir") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "Container(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ContainerPort", - jsii_struct_bases=[], - name_mapping={ - "container_port": "containerPort", - "host_ip": "hostIp", - "host_port": "hostPort", - "name": "name", - "protocol": "protocol", - }, -) -class ContainerPort: - def __init__( - self, - *, - container_port: jsii.Number, - host_ip: typing.Optional[builtins.str] = None, - host_port: typing.Optional[jsii.Number] = None, - name: typing.Optional[builtins.str] = None, - protocol: typing.Optional[builtins.str] = None, - ) -> None: - '''ContainerPort represents a network port in a single container. - - :param container_port: Number of port to expose on the pod's IP address. This must be a valid port number, 0 < x < 65536. - :param host_ip: What host IP to bind the external port to. - :param host_port: Number of port to expose on the host. If specified, this must be a valid port number, 0 < x < 65536. If HostNetwork is specified, this must match ContainerPort. Most containers do not need this. - :param name: If specified, this must be an IANA_SVC_NAME and unique within the pod. Each named port in a pod must have a unique name. Name for the port that can be referred to by services. - :param protocol: Protocol for port. Must be UDP, TCP, or SCTP. Defaults to "TCP". Default: TCP". - - :schema: io.k8s.api.core.v1.ContainerPort - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__ea50a33f53045ef963173d2b69fe4fa77a8142b8ae58ea83960e69f4839c879a) - check_type(argname="argument container_port", value=container_port, expected_type=type_hints["container_port"]) - check_type(argname="argument host_ip", value=host_ip, expected_type=type_hints["host_ip"]) - check_type(argname="argument host_port", value=host_port, expected_type=type_hints["host_port"]) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument protocol", value=protocol, expected_type=type_hints["protocol"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "container_port": container_port, - } - if host_ip is not None: - self._values["host_ip"] = host_ip - if host_port is not None: - self._values["host_port"] = host_port - if name is not None: - self._values["name"] = name - if protocol is not None: - self._values["protocol"] = protocol - - @builtins.property - def container_port(self) -> jsii.Number: - '''Number of port to expose on the pod's IP address. - - This must be a valid port number, 0 < x < 65536. - - :schema: io.k8s.api.core.v1.ContainerPort#containerPort - ''' - result = self._values.get("container_port") - assert result is not None, "Required property 'container_port' is missing" - return typing.cast(jsii.Number, result) - - @builtins.property - def host_ip(self) -> typing.Optional[builtins.str]: - '''What host IP to bind the external port to. - - :schema: io.k8s.api.core.v1.ContainerPort#hostIP - ''' - result = self._values.get("host_ip") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def host_port(self) -> typing.Optional[jsii.Number]: - '''Number of port to expose on the host. - - If specified, this must be a valid port number, 0 < x < 65536. If HostNetwork is specified, this must match ContainerPort. Most containers do not need this. - - :schema: io.k8s.api.core.v1.ContainerPort#hostPort - ''' - result = self._values.get("host_port") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def name(self) -> typing.Optional[builtins.str]: - '''If specified, this must be an IANA_SVC_NAME and unique within the pod. - - Each named port in a pod must have a unique name. Name for the port that can be referred to by services. - - :schema: io.k8s.api.core.v1.ContainerPort#name - ''' - result = self._values.get("name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def protocol(self) -> typing.Optional[builtins.str]: - '''Protocol for port. - - Must be UDP, TCP, or SCTP. Defaults to "TCP". - - :default: TCP". - - :schema: io.k8s.api.core.v1.ContainerPort#protocol - ''' - result = self._values.get("protocol") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ContainerPort(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ContainerResourceMetricSourceV2", - jsii_struct_bases=[], - name_mapping={"container": "container", "name": "name", "target": "target"}, -) -class ContainerResourceMetricSourceV2: - def __init__( - self, - *, - container: builtins.str, - name: builtins.str, - target: typing.Union["MetricTargetV2", typing.Dict[builtins.str, typing.Any]], - ) -> None: - '''ContainerResourceMetricSource indicates how to scale on a resource metric known to Kubernetes, as specified in requests and limits, describing each pod in the current scale target (e.g. CPU or memory). The values will be averaged together before being compared to the target. Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the "pods" source. Only one "target" type should be set. - - :param container: container is the name of the container in the pods of the scaling target. - :param name: name is the name of the resource in question. - :param target: target specifies the target value for the given metric. - - :schema: io.k8s.api.autoscaling.v2.ContainerResourceMetricSource - ''' - if isinstance(target, dict): - target = MetricTargetV2(**target) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__b4e84c9f4f18c845b4719ea9f3557e5fb076a9b483c5cb7bcb93a992c8066a28) - check_type(argname="argument container", value=container, expected_type=type_hints["container"]) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument target", value=target, expected_type=type_hints["target"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "container": container, - "name": name, - "target": target, - } - - @builtins.property - def container(self) -> builtins.str: - '''container is the name of the container in the pods of the scaling target. - - :schema: io.k8s.api.autoscaling.v2.ContainerResourceMetricSource#container - ''' - result = self._values.get("container") - assert result is not None, "Required property 'container' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def name(self) -> builtins.str: - '''name is the name of the resource in question. - - :schema: io.k8s.api.autoscaling.v2.ContainerResourceMetricSource#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def target(self) -> "MetricTargetV2": - '''target specifies the target value for the given metric. - - :schema: io.k8s.api.autoscaling.v2.ContainerResourceMetricSource#target - ''' - result = self._values.get("target") - assert result is not None, "Required property 'target' is missing" - return typing.cast("MetricTargetV2", result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ContainerResourceMetricSourceV2(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.CronJobSpec", - jsii_struct_bases=[], - name_mapping={ - "job_template": "jobTemplate", - "schedule": "schedule", - "concurrency_policy": "concurrencyPolicy", - "failed_jobs_history_limit": "failedJobsHistoryLimit", - "starting_deadline_seconds": "startingDeadlineSeconds", - "successful_jobs_history_limit": "successfulJobsHistoryLimit", - "suspend": "suspend", - "time_zone": "timeZone", - }, -) -class CronJobSpec: - def __init__( - self, - *, - job_template: typing.Union["JobTemplateSpec", typing.Dict[builtins.str, typing.Any]], - schedule: builtins.str, - concurrency_policy: typing.Optional[builtins.str] = None, - failed_jobs_history_limit: typing.Optional[jsii.Number] = None, - starting_deadline_seconds: typing.Optional[jsii.Number] = None, - successful_jobs_history_limit: typing.Optional[jsii.Number] = None, - suspend: typing.Optional[builtins.bool] = None, - time_zone: typing.Optional[builtins.str] = None, - ) -> None: - '''CronJobSpec describes how the job execution will look like and when it will actually run. - - :param job_template: Specifies the job that will be created when executing a CronJob. - :param schedule: The schedule in Cron format, see https://en.wikipedia.org/wiki/Cron. - :param concurrency_policy: Specifies how to treat concurrent executions of a Job. Valid values are: - "Allow" (default): allows CronJobs to run concurrently; - "Forbid": forbids concurrent runs, skipping next run if previous run hasn't finished yet; - "Replace": cancels currently running job and replaces it with a new one - :param failed_jobs_history_limit: The number of failed finished jobs to retain. Value must be non-negative integer. Defaults to 1. Default: 1. - :param starting_deadline_seconds: Optional deadline in seconds for starting the job if it misses scheduled time for any reason. Missed jobs executions will be counted as failed ones. - :param successful_jobs_history_limit: The number of successful finished jobs to retain. Value must be non-negative integer. Defaults to 3. Default: 3. - :param suspend: This flag tells the controller to suspend subsequent executions, it does not apply to already started executions. Defaults to false. Default: false. - :param time_zone: The time zone name for the given schedule, see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones. If not specified, this will default to the time zone of the kube-controller-manager process. The set of valid time zone names and the time zone offset is loaded from the system-wide time zone database by the API server during CronJob validation and the controller manager during execution. If no system-wide time zone database can be found a bundled version of the database is used instead. If the time zone name becomes invalid during the lifetime of a CronJob or due to a change in host configuration, the controller will stop creating new new Jobs and will create a system event with the reason UnknownTimeZone. More information can be found in https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/#time-zones This is beta field and must be enabled via the ``CronJobTimeZone`` feature gate. - - :schema: io.k8s.api.batch.v1.CronJobSpec - ''' - if isinstance(job_template, dict): - job_template = JobTemplateSpec(**job_template) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__ede2ac625e6994d9a90814ee390559d5afe3fc8cbac21bd43b66df929f6dc946) - check_type(argname="argument job_template", value=job_template, expected_type=type_hints["job_template"]) - check_type(argname="argument schedule", value=schedule, expected_type=type_hints["schedule"]) - check_type(argname="argument concurrency_policy", value=concurrency_policy, expected_type=type_hints["concurrency_policy"]) - check_type(argname="argument failed_jobs_history_limit", value=failed_jobs_history_limit, expected_type=type_hints["failed_jobs_history_limit"]) - check_type(argname="argument starting_deadline_seconds", value=starting_deadline_seconds, expected_type=type_hints["starting_deadline_seconds"]) - check_type(argname="argument successful_jobs_history_limit", value=successful_jobs_history_limit, expected_type=type_hints["successful_jobs_history_limit"]) - check_type(argname="argument suspend", value=suspend, expected_type=type_hints["suspend"]) - check_type(argname="argument time_zone", value=time_zone, expected_type=type_hints["time_zone"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "job_template": job_template, - "schedule": schedule, - } - if concurrency_policy is not None: - self._values["concurrency_policy"] = concurrency_policy - if failed_jobs_history_limit is not None: - self._values["failed_jobs_history_limit"] = failed_jobs_history_limit - if starting_deadline_seconds is not None: - self._values["starting_deadline_seconds"] = starting_deadline_seconds - if successful_jobs_history_limit is not None: - self._values["successful_jobs_history_limit"] = successful_jobs_history_limit - if suspend is not None: - self._values["suspend"] = suspend - if time_zone is not None: - self._values["time_zone"] = time_zone - - @builtins.property - def job_template(self) -> "JobTemplateSpec": - '''Specifies the job that will be created when executing a CronJob. - - :schema: io.k8s.api.batch.v1.CronJobSpec#jobTemplate - ''' - result = self._values.get("job_template") - assert result is not None, "Required property 'job_template' is missing" - return typing.cast("JobTemplateSpec", result) - - @builtins.property - def schedule(self) -> builtins.str: - '''The schedule in Cron format, see https://en.wikipedia.org/wiki/Cron. - - :schema: io.k8s.api.batch.v1.CronJobSpec#schedule - ''' - result = self._values.get("schedule") - assert result is not None, "Required property 'schedule' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def concurrency_policy(self) -> typing.Optional[builtins.str]: - '''Specifies how to treat concurrent executions of a Job. - - Valid values are: - "Allow" (default): allows CronJobs to run concurrently; - "Forbid": forbids concurrent runs, skipping next run if previous run hasn't finished yet; - "Replace": cancels currently running job and replaces it with a new one - - :schema: io.k8s.api.batch.v1.CronJobSpec#concurrencyPolicy - ''' - result = self._values.get("concurrency_policy") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def failed_jobs_history_limit(self) -> typing.Optional[jsii.Number]: - '''The number of failed finished jobs to retain. - - Value must be non-negative integer. Defaults to 1. - - :default: 1. - - :schema: io.k8s.api.batch.v1.CronJobSpec#failedJobsHistoryLimit - ''' - result = self._values.get("failed_jobs_history_limit") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def starting_deadline_seconds(self) -> typing.Optional[jsii.Number]: - '''Optional deadline in seconds for starting the job if it misses scheduled time for any reason. - - Missed jobs executions will be counted as failed ones. - - :schema: io.k8s.api.batch.v1.CronJobSpec#startingDeadlineSeconds - ''' - result = self._values.get("starting_deadline_seconds") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def successful_jobs_history_limit(self) -> typing.Optional[jsii.Number]: - '''The number of successful finished jobs to retain. - - Value must be non-negative integer. Defaults to 3. - - :default: 3. - - :schema: io.k8s.api.batch.v1.CronJobSpec#successfulJobsHistoryLimit - ''' - result = self._values.get("successful_jobs_history_limit") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def suspend(self) -> typing.Optional[builtins.bool]: - '''This flag tells the controller to suspend subsequent executions, it does not apply to already started executions. - - Defaults to false. - - :default: false. - - :schema: io.k8s.api.batch.v1.CronJobSpec#suspend - ''' - result = self._values.get("suspend") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def time_zone(self) -> typing.Optional[builtins.str]: - '''The time zone name for the given schedule, see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones. If not specified, this will default to the time zone of the kube-controller-manager process. The set of valid time zone names and the time zone offset is loaded from the system-wide time zone database by the API server during CronJob validation and the controller manager during execution. If no system-wide time zone database can be found a bundled version of the database is used instead. If the time zone name becomes invalid during the lifetime of a CronJob or due to a change in host configuration, the controller will stop creating new new Jobs and will create a system event with the reason UnknownTimeZone. More information can be found in https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/#time-zones This is beta field and must be enabled via the ``CronJobTimeZone`` feature gate. - - :schema: io.k8s.api.batch.v1.CronJobSpec#timeZone - ''' - result = self._values.get("time_zone") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "CronJobSpec(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.CrossVersionObjectReference", - jsii_struct_bases=[], - name_mapping={"kind": "kind", "name": "name", "api_version": "apiVersion"}, -) -class CrossVersionObjectReference: - def __init__( - self, - *, - kind: builtins.str, - name: builtins.str, - api_version: typing.Optional[builtins.str] = None, - ) -> None: - '''CrossVersionObjectReference contains enough information to let you identify the referred resource. - - :param kind: Kind of the referent; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - :param name: Name of the referent; More info: http://kubernetes.io/docs/user-guide/identifiers#names - :param api_version: API version of the referent. - - :schema: io.k8s.api.autoscaling.v1.CrossVersionObjectReference - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__16088e27454cd0459d4b0c1ddae21a0af78275822fe3ad5b12a9c2a78b7075bb) - check_type(argname="argument kind", value=kind, expected_type=type_hints["kind"]) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument api_version", value=api_version, expected_type=type_hints["api_version"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "kind": kind, - "name": name, - } - if api_version is not None: - self._values["api_version"] = api_version - - @builtins.property - def kind(self) -> builtins.str: - '''Kind of the referent; - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.autoscaling.v1.CrossVersionObjectReference#kind - ''' - result = self._values.get("kind") - assert result is not None, "Required property 'kind' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def name(self) -> builtins.str: - '''Name of the referent; - - More info: http://kubernetes.io/docs/user-guide/identifiers#names - - :schema: io.k8s.api.autoscaling.v1.CrossVersionObjectReference#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def api_version(self) -> typing.Optional[builtins.str]: - '''API version of the referent. - - :schema: io.k8s.api.autoscaling.v1.CrossVersionObjectReference#apiVersion - ''' - result = self._values.get("api_version") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "CrossVersionObjectReference(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.CrossVersionObjectReferenceV2", - jsii_struct_bases=[], - name_mapping={"kind": "kind", "name": "name", "api_version": "apiVersion"}, -) -class CrossVersionObjectReferenceV2: - def __init__( - self, - *, - kind: builtins.str, - name: builtins.str, - api_version: typing.Optional[builtins.str] = None, - ) -> None: - '''CrossVersionObjectReference contains enough information to let you identify the referred resource. - - :param kind: Kind of the referent; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - :param name: Name of the referent; More info: http://kubernetes.io/docs/user-guide/identifiers#names - :param api_version: API version of the referent. - - :schema: io.k8s.api.autoscaling.v2.CrossVersionObjectReference - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__3af8150f9f5d358140c2abd5fb9f92e0e98dd7941df54ff76043b6eff438e4e5) - check_type(argname="argument kind", value=kind, expected_type=type_hints["kind"]) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument api_version", value=api_version, expected_type=type_hints["api_version"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "kind": kind, - "name": name, - } - if api_version is not None: - self._values["api_version"] = api_version - - @builtins.property - def kind(self) -> builtins.str: - '''Kind of the referent; - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.autoscaling.v2.CrossVersionObjectReference#kind - ''' - result = self._values.get("kind") - assert result is not None, "Required property 'kind' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def name(self) -> builtins.str: - '''Name of the referent; - - More info: http://kubernetes.io/docs/user-guide/identifiers#names - - :schema: io.k8s.api.autoscaling.v2.CrossVersionObjectReference#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def api_version(self) -> typing.Optional[builtins.str]: - '''API version of the referent. - - :schema: io.k8s.api.autoscaling.v2.CrossVersionObjectReference#apiVersion - ''' - result = self._values.get("api_version") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "CrossVersionObjectReferenceV2(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.CsiDriverSpec", - jsii_struct_bases=[], - name_mapping={ - "attach_required": "attachRequired", - "fs_group_policy": "fsGroupPolicy", - "pod_info_on_mount": "podInfoOnMount", - "requires_republish": "requiresRepublish", - "se_linux_mount": "seLinuxMount", - "storage_capacity": "storageCapacity", - "token_requests": "tokenRequests", - "volume_lifecycle_modes": "volumeLifecycleModes", - }, -) -class CsiDriverSpec: - def __init__( - self, - *, - attach_required: typing.Optional[builtins.bool] = None, - fs_group_policy: typing.Optional[builtins.str] = None, - pod_info_on_mount: typing.Optional[builtins.bool] = None, - requires_republish: typing.Optional[builtins.bool] = None, - se_linux_mount: typing.Optional[builtins.bool] = None, - storage_capacity: typing.Optional[builtins.bool] = None, - token_requests: typing.Optional[typing.Sequence[typing.Union["TokenRequest", typing.Dict[builtins.str, typing.Any]]]] = None, - volume_lifecycle_modes: typing.Optional[typing.Sequence[builtins.str]] = None, - ) -> None: - '''CSIDriverSpec is the specification of a CSIDriver. - - :param attach_required: attachRequired indicates this CSI volume driver requires an attach operation (because it implements the CSI ControllerPublishVolume() method), and that the Kubernetes attach detach controller should call the attach volume interface which checks the volumeattachment status and waits until the volume is attached before proceeding to mounting. The CSI external-attacher coordinates with CSI volume driver and updates the volumeattachment status when the attach operation is complete. If the CSIDriverRegistry feature gate is enabled and the value is specified to false, the attach operation will be skipped. Otherwise the attach operation will be called. This field is immutable. - :param fs_group_policy: Defines if the underlying volume supports changing ownership and permission of the volume before being mounted. Refer to the specific FSGroupPolicy values for additional details. This field is immutable. Defaults to ReadWriteOnceWithFSType, which will examine each volume to determine if Kubernetes should modify ownership and permissions of the volume. With the default policy the defined fsGroup will only be applied if a fstype is defined and the volume's access mode contains ReadWriteOnce. Default: ReadWriteOnceWithFSType, which will examine each volume to determine if Kubernetes should modify ownership and permissions of the volume. With the default policy the defined fsGroup will only be applied if a fstype is defined and the volume's access mode contains ReadWriteOnce. - :param pod_info_on_mount: If set to true, podInfoOnMount indicates this CSI volume driver requires additional pod information (like podName, podUID, etc.) during mount operations. If set to false, pod information will not be passed on mount. Default is false. The CSI driver specifies podInfoOnMount as part of driver deployment. If true, Kubelet will pass pod information as VolumeContext in the CSI NodePublishVolume() calls. The CSI driver is responsible for parsing and validating the information passed in as VolumeContext. The following VolumeConext will be passed if podInfoOnMount is set to true. This list might grow, but the prefix will be used. "csi.storage.k8s.io/pod.name": pod.Name "csi.storage.k8s.io/pod.namespace": pod.Namespace "csi.storage.k8s.io/pod.uid": string(pod.UID) "csi.storage.k8s.io/ephemeral": "true" if the volume is an ephemeral inline volume defined by a CSIVolumeSource, otherwise "false". "csi.storage.k8s.io/ephemeral" is a new feature in Kubernetes 1.16. It is only required for drivers which support both the "Persistent" and "Ephemeral" VolumeLifecycleMode. Other drivers can leave pod info disabled and/or ignore this field. As Kubernetes 1.15 doesn't support this field, drivers can only support one mode when deployed on such a cluster and the deployment determines which mode that is, for example via a command line parameter of the driver. This field is immutable. Default: false. The CSI driver specifies podInfoOnMount as part of driver deployment. If true, Kubelet will pass pod information as VolumeContext in the CSI NodePublishVolume() calls. The CSI driver is responsible for parsing and validating the information passed in as VolumeContext. The following VolumeConext will be passed if podInfoOnMount is set to true. This list might grow, but the prefix will be used. "csi.storage.k8s.io/pod.name": pod.Name "csi.storage.k8s.io/pod.namespace": pod.Namespace "csi.storage.k8s.io/pod.uid": string(pod.UID) "csi.storage.k8s.io/ephemeral": "true" if the volume is an ephemeral inline volume - :param requires_republish: RequiresRepublish indicates the CSI driver wants ``NodePublishVolume`` being periodically called to reflect any possible change in the mounted volume. This field defaults to false. Note: After a successful initial NodePublishVolume call, subsequent calls to NodePublishVolume should only update the contents of the volume. New mount points will not be seen by a running container. - :param se_linux_mount: SELinuxMount specifies if the CSI driver supports "-o context" mount option. When "true", the CSI driver must ensure that all volumes provided by this CSI driver can be mounted separately with different ``-o context`` options. This is typical for storage backends that provide volumes as filesystems on block devices or as independent shared volumes. Kubernetes will call NodeStage / NodePublish with "-o context=xyz" mount option when mounting a ReadWriteOncePod volume used in Pod that has explicitly set SELinux context. In the future, it may be expanded to other volume AccessModes. In any case, Kubernetes will ensure that the volume is mounted only with a single SELinux context. When "false", Kubernetes won't pass any special SELinux mount options to the driver. This is typical for volumes that represent subdirectories of a bigger shared filesystem. Default is "false". Default: false". - :param storage_capacity: If set to true, storageCapacity indicates that the CSI volume driver wants pod scheduling to consider the storage capacity that the driver deployment will report by creating CSIStorageCapacity objects with capacity information. The check can be enabled immediately when deploying a driver. In that case, provisioning new volumes with late binding will pause until the driver deployment has published some suitable CSIStorageCapacity object. Alternatively, the driver can be deployed with the field unset or false and it can be flipped later when storage capacity information has been published. This field was immutable in Kubernetes <= 1.22 and now is mutable. - :param token_requests: TokenRequests indicates the CSI driver needs pods' service account tokens it is mounting volume for to do necessary authentication. Kubelet will pass the tokens in VolumeContext in the CSI NodePublishVolume calls. The CSI driver should parse and validate the following VolumeContext: "csi.storage.k8s.io/serviceAccount.tokens": { "": { "token": , "expirationTimestamp": , }, ... } Note: Audience in each TokenRequest should be different and at most one token is empty string. To receive a new token after expiry, RequiresRepublish can be used to trigger NodePublishVolume periodically. - :param volume_lifecycle_modes: volumeLifecycleModes defines what kind of volumes this CSI volume driver supports. The default if the list is empty is "Persistent", which is the usage defined by the CSI specification and implemented in Kubernetes via the usual PV/PVC mechanism. The other mode is "Ephemeral". In this mode, volumes are defined inline inside the pod spec with CSIVolumeSource and their lifecycle is tied to the lifecycle of that pod. A driver has to be aware of this because it is only going to get a NodePublishVolume call for such a volume. For more information about implementing this mode, see https://kubernetes-csi.github.io/docs/ephemeral-local-volumes.html A driver can support one or more of these modes and more modes may be added in the future. This field is beta. This field is immutable. - - :schema: io.k8s.api.storage.v1.CSIDriverSpec - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__17e3bd16387b10ac52d67d9c371444bdd008a79a45fd1fa94cf98f80b9c7070f) - check_type(argname="argument attach_required", value=attach_required, expected_type=type_hints["attach_required"]) - check_type(argname="argument fs_group_policy", value=fs_group_policy, expected_type=type_hints["fs_group_policy"]) - check_type(argname="argument pod_info_on_mount", value=pod_info_on_mount, expected_type=type_hints["pod_info_on_mount"]) - check_type(argname="argument requires_republish", value=requires_republish, expected_type=type_hints["requires_republish"]) - check_type(argname="argument se_linux_mount", value=se_linux_mount, expected_type=type_hints["se_linux_mount"]) - check_type(argname="argument storage_capacity", value=storage_capacity, expected_type=type_hints["storage_capacity"]) - check_type(argname="argument token_requests", value=token_requests, expected_type=type_hints["token_requests"]) - check_type(argname="argument volume_lifecycle_modes", value=volume_lifecycle_modes, expected_type=type_hints["volume_lifecycle_modes"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if attach_required is not None: - self._values["attach_required"] = attach_required - if fs_group_policy is not None: - self._values["fs_group_policy"] = fs_group_policy - if pod_info_on_mount is not None: - self._values["pod_info_on_mount"] = pod_info_on_mount - if requires_republish is not None: - self._values["requires_republish"] = requires_republish - if se_linux_mount is not None: - self._values["se_linux_mount"] = se_linux_mount - if storage_capacity is not None: - self._values["storage_capacity"] = storage_capacity - if token_requests is not None: - self._values["token_requests"] = token_requests - if volume_lifecycle_modes is not None: - self._values["volume_lifecycle_modes"] = volume_lifecycle_modes - - @builtins.property - def attach_required(self) -> typing.Optional[builtins.bool]: - '''attachRequired indicates this CSI volume driver requires an attach operation (because it implements the CSI ControllerPublishVolume() method), and that the Kubernetes attach detach controller should call the attach volume interface which checks the volumeattachment status and waits until the volume is attached before proceeding to mounting. - - The CSI external-attacher coordinates with CSI volume driver and updates the volumeattachment status when the attach operation is complete. If the CSIDriverRegistry feature gate is enabled and the value is specified to false, the attach operation will be skipped. Otherwise the attach operation will be called. - - This field is immutable. - - :schema: io.k8s.api.storage.v1.CSIDriverSpec#attachRequired - ''' - result = self._values.get("attach_required") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def fs_group_policy(self) -> typing.Optional[builtins.str]: - '''Defines if the underlying volume supports changing ownership and permission of the volume before being mounted. - - Refer to the specific FSGroupPolicy values for additional details. - - This field is immutable. - - Defaults to ReadWriteOnceWithFSType, which will examine each volume to determine if Kubernetes should modify ownership and permissions of the volume. With the default policy the defined fsGroup will only be applied if a fstype is defined and the volume's access mode contains ReadWriteOnce. - - :default: ReadWriteOnceWithFSType, which will examine each volume to determine if Kubernetes should modify ownership and permissions of the volume. With the default policy the defined fsGroup will only be applied if a fstype is defined and the volume's access mode contains ReadWriteOnce. - - :schema: io.k8s.api.storage.v1.CSIDriverSpec#fsGroupPolicy - ''' - result = self._values.get("fs_group_policy") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def pod_info_on_mount(self) -> typing.Optional[builtins.bool]: - '''If set to true, podInfoOnMount indicates this CSI volume driver requires additional pod information (like podName, podUID, etc.) during mount operations. If set to false, pod information will not be passed on mount. Default is false. The CSI driver specifies podInfoOnMount as part of driver deployment. If true, Kubelet will pass pod information as VolumeContext in the CSI NodePublishVolume() calls. The CSI driver is responsible for parsing and validating the information passed in as VolumeContext. The following VolumeConext will be passed if podInfoOnMount is set to true. This list might grow, but the prefix will be used. "csi.storage.k8s.io/pod.name": pod.Name "csi.storage.k8s.io/pod.namespace": pod.Namespace "csi.storage.k8s.io/pod.uid": string(pod.UID) "csi.storage.k8s.io/ephemeral": "true" if the volume is an ephemeral inline volume defined by a CSIVolumeSource, otherwise "false". - - "csi.storage.k8s.io/ephemeral" is a new feature in Kubernetes 1.16. It is only required for drivers which support both the "Persistent" and "Ephemeral" VolumeLifecycleMode. Other drivers can leave pod info disabled and/or ignore this field. As Kubernetes 1.15 doesn't support this field, drivers can only support one mode when deployed on such a cluster and the deployment determines which mode that is, for example via a command line parameter of the driver. - - This field is immutable. - - :default: false. The CSI driver specifies podInfoOnMount as part of driver deployment. If true, Kubelet will pass pod information as VolumeContext in the CSI NodePublishVolume() calls. The CSI driver is responsible for parsing and validating the information passed in as VolumeContext. The following VolumeConext will be passed if podInfoOnMount is set to true. This list might grow, but the prefix will be used. "csi.storage.k8s.io/pod.name": pod.Name "csi.storage.k8s.io/pod.namespace": pod.Namespace "csi.storage.k8s.io/pod.uid": string(pod.UID) "csi.storage.k8s.io/ephemeral": "true" if the volume is an ephemeral inline volume - - :schema: io.k8s.api.storage.v1.CSIDriverSpec#podInfoOnMount - ''' - result = self._values.get("pod_info_on_mount") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def requires_republish(self) -> typing.Optional[builtins.bool]: - '''RequiresRepublish indicates the CSI driver wants ``NodePublishVolume`` being periodically called to reflect any possible change in the mounted volume. - - This field defaults to false. - - Note: After a successful initial NodePublishVolume call, subsequent calls to NodePublishVolume should only update the contents of the volume. New mount points will not be seen by a running container. - - :schema: io.k8s.api.storage.v1.CSIDriverSpec#requiresRepublish - ''' - result = self._values.get("requires_republish") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def se_linux_mount(self) -> typing.Optional[builtins.bool]: - '''SELinuxMount specifies if the CSI driver supports "-o context" mount option. - - When "true", the CSI driver must ensure that all volumes provided by this CSI driver can be mounted separately with different ``-o context`` options. This is typical for storage backends that provide volumes as filesystems on block devices or as independent shared volumes. Kubernetes will call NodeStage / NodePublish with "-o context=xyz" mount option when mounting a ReadWriteOncePod volume used in Pod that has explicitly set SELinux context. In the future, it may be expanded to other volume AccessModes. In any case, Kubernetes will ensure that the volume is mounted only with a single SELinux context. - - When "false", Kubernetes won't pass any special SELinux mount options to the driver. This is typical for volumes that represent subdirectories of a bigger shared filesystem. - - Default is "false". - - :default: false". - - :schema: io.k8s.api.storage.v1.CSIDriverSpec#seLinuxMount - ''' - result = self._values.get("se_linux_mount") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def storage_capacity(self) -> typing.Optional[builtins.bool]: - '''If set to true, storageCapacity indicates that the CSI volume driver wants pod scheduling to consider the storage capacity that the driver deployment will report by creating CSIStorageCapacity objects with capacity information. - - The check can be enabled immediately when deploying a driver. In that case, provisioning new volumes with late binding will pause until the driver deployment has published some suitable CSIStorageCapacity object. - - Alternatively, the driver can be deployed with the field unset or false and it can be flipped later when storage capacity information has been published. - - This field was immutable in Kubernetes <= 1.22 and now is mutable. - - :schema: io.k8s.api.storage.v1.CSIDriverSpec#storageCapacity - ''' - result = self._values.get("storage_capacity") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def token_requests(self) -> typing.Optional[typing.List["TokenRequest"]]: - '''TokenRequests indicates the CSI driver needs pods' service account tokens it is mounting volume for to do necessary authentication. - - Kubelet will pass the tokens in VolumeContext in the CSI NodePublishVolume calls. The CSI driver should parse and validate the following VolumeContext: "csi.storage.k8s.io/serviceAccount.tokens": { - "": { - "token": , - "expirationTimestamp": , - }, - ... - } - - Note: Audience in each TokenRequest should be different and at most one token is empty string. To receive a new token after expiry, RequiresRepublish can be used to trigger NodePublishVolume periodically. - - :schema: io.k8s.api.storage.v1.CSIDriverSpec#tokenRequests - ''' - result = self._values.get("token_requests") - return typing.cast(typing.Optional[typing.List["TokenRequest"]], result) - - @builtins.property - def volume_lifecycle_modes(self) -> typing.Optional[typing.List[builtins.str]]: - '''volumeLifecycleModes defines what kind of volumes this CSI volume driver supports. - - The default if the list is empty is "Persistent", which is the usage defined by the CSI specification and implemented in Kubernetes via the usual PV/PVC mechanism. The other mode is "Ephemeral". In this mode, volumes are defined inline inside the pod spec with CSIVolumeSource and their lifecycle is tied to the lifecycle of that pod. A driver has to be aware of this because it is only going to get a NodePublishVolume call for such a volume. For more information about implementing this mode, see https://kubernetes-csi.github.io/docs/ephemeral-local-volumes.html A driver can support one or more of these modes and more modes may be added in the future. This field is beta. - - This field is immutable. - - :schema: io.k8s.api.storage.v1.CSIDriverSpec#volumeLifecycleModes - ''' - result = self._values.get("volume_lifecycle_modes") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "CsiDriverSpec(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.CsiNodeDriver", - jsii_struct_bases=[], - name_mapping={ - "name": "name", - "node_id": "nodeId", - "allocatable": "allocatable", - "topology_keys": "topologyKeys", - }, -) -class CsiNodeDriver: - def __init__( - self, - *, - name: builtins.str, - node_id: builtins.str, - allocatable: typing.Optional[typing.Union["VolumeNodeResources", typing.Dict[builtins.str, typing.Any]]] = None, - topology_keys: typing.Optional[typing.Sequence[builtins.str]] = None, - ) -> None: - '''CSINodeDriver holds information about the specification of one CSI driver installed on a node. - - :param name: This is the name of the CSI driver that this object refers to. This MUST be the same name returned by the CSI GetPluginName() call for that driver. - :param node_id: nodeID of the node from the driver point of view. This field enables Kubernetes to communicate with storage systems that do not share the same nomenclature for nodes. For example, Kubernetes may refer to a given node as "node1", but the storage system may refer to the same node as "nodeA". When Kubernetes issues a command to the storage system to attach a volume to a specific node, it can use this field to refer to the node name using the ID that the storage system will understand, e.g. "nodeA" instead of "node1". This field is required. - :param allocatable: allocatable represents the volume resources of a node that are available for scheduling. This field is beta. - :param topology_keys: topologyKeys is the list of keys supported by the driver. When a driver is initialized on a cluster, it provides a set of topology keys that it understands (e.g. "company.com/zone", "company.com/region"). When a driver is initialized on a node, it provides the same topology keys along with values. Kubelet will expose these topology keys as labels on its own node object. When Kubernetes does topology aware provisioning, it can use this list to determine which labels it should retrieve from the node object and pass back to the driver. It is possible for different nodes to use different topology keys. This can be empty if driver does not support topology. - - :schema: io.k8s.api.storage.v1.CSINodeDriver - ''' - if isinstance(allocatable, dict): - allocatable = VolumeNodeResources(**allocatable) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__adf2babe98e03e365ff1231a34008326706969b8f221e55270d116f02fb1c250) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument node_id", value=node_id, expected_type=type_hints["node_id"]) - check_type(argname="argument allocatable", value=allocatable, expected_type=type_hints["allocatable"]) - check_type(argname="argument topology_keys", value=topology_keys, expected_type=type_hints["topology_keys"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "name": name, - "node_id": node_id, - } - if allocatable is not None: - self._values["allocatable"] = allocatable - if topology_keys is not None: - self._values["topology_keys"] = topology_keys - - @builtins.property - def name(self) -> builtins.str: - '''This is the name of the CSI driver that this object refers to. - - This MUST be the same name returned by the CSI GetPluginName() call for that driver. - - :schema: io.k8s.api.storage.v1.CSINodeDriver#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def node_id(self) -> builtins.str: - '''nodeID of the node from the driver point of view. - - This field enables Kubernetes to communicate with storage systems that do not share the same nomenclature for nodes. For example, Kubernetes may refer to a given node as "node1", but the storage system may refer to the same node as "nodeA". When Kubernetes issues a command to the storage system to attach a volume to a specific node, it can use this field to refer to the node name using the ID that the storage system will understand, e.g. "nodeA" instead of "node1". This field is required. - - :schema: io.k8s.api.storage.v1.CSINodeDriver#nodeID - ''' - result = self._values.get("node_id") - assert result is not None, "Required property 'node_id' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def allocatable(self) -> typing.Optional["VolumeNodeResources"]: - '''allocatable represents the volume resources of a node that are available for scheduling. - - This field is beta. - - :schema: io.k8s.api.storage.v1.CSINodeDriver#allocatable - ''' - result = self._values.get("allocatable") - return typing.cast(typing.Optional["VolumeNodeResources"], result) - - @builtins.property - def topology_keys(self) -> typing.Optional[typing.List[builtins.str]]: - '''topologyKeys is the list of keys supported by the driver. - - When a driver is initialized on a cluster, it provides a set of topology keys that it understands (e.g. "company.com/zone", "company.com/region"). When a driver is initialized on a node, it provides the same topology keys along with values. Kubelet will expose these topology keys as labels on its own node object. When Kubernetes does topology aware provisioning, it can use this list to determine which labels it should retrieve from the node object and pass back to the driver. It is possible for different nodes to use different topology keys. This can be empty if driver does not support topology. - - :schema: io.k8s.api.storage.v1.CSINodeDriver#topologyKeys - ''' - result = self._values.get("topology_keys") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "CsiNodeDriver(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.CsiNodeSpec", - jsii_struct_bases=[], - name_mapping={"drivers": "drivers"}, -) -class CsiNodeSpec: - def __init__( - self, - *, - drivers: typing.Sequence[typing.Union[CsiNodeDriver, typing.Dict[builtins.str, typing.Any]]], - ) -> None: - '''CSINodeSpec holds information about the specification of all CSI drivers installed on a node. - - :param drivers: drivers is a list of information of all CSI Drivers existing on a node. If all drivers in the list are uninstalled, this can become empty. - - :schema: io.k8s.api.storage.v1.CSINodeSpec - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__39088f7ceefdd1a9586f416018ad793cc2af5c04145208fe263fc1262780bed0) - check_type(argname="argument drivers", value=drivers, expected_type=type_hints["drivers"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "drivers": drivers, - } - - @builtins.property - def drivers(self) -> typing.List[CsiNodeDriver]: - '''drivers is a list of information of all CSI Drivers existing on a node. - - If all drivers in the list are uninstalled, this can become empty. - - :schema: io.k8s.api.storage.v1.CSINodeSpec#drivers - ''' - result = self._values.get("drivers") - assert result is not None, "Required property 'drivers' is missing" - return typing.cast(typing.List[CsiNodeDriver], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "CsiNodeSpec(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.CsiPersistentVolumeSource", - jsii_struct_bases=[], - name_mapping={ - "driver": "driver", - "volume_handle": "volumeHandle", - "controller_expand_secret_ref": "controllerExpandSecretRef", - "controller_publish_secret_ref": "controllerPublishSecretRef", - "fs_type": "fsType", - "node_expand_secret_ref": "nodeExpandSecretRef", - "node_publish_secret_ref": "nodePublishSecretRef", - "node_stage_secret_ref": "nodeStageSecretRef", - "read_only": "readOnly", - "volume_attributes": "volumeAttributes", - }, -) -class CsiPersistentVolumeSource: - def __init__( - self, - *, - driver: builtins.str, - volume_handle: builtins.str, - controller_expand_secret_ref: typing.Optional[typing.Union["SecretReference", typing.Dict[builtins.str, typing.Any]]] = None, - controller_publish_secret_ref: typing.Optional[typing.Union["SecretReference", typing.Dict[builtins.str, typing.Any]]] = None, - fs_type: typing.Optional[builtins.str] = None, - node_expand_secret_ref: typing.Optional[typing.Union["SecretReference", typing.Dict[builtins.str, typing.Any]]] = None, - node_publish_secret_ref: typing.Optional[typing.Union["SecretReference", typing.Dict[builtins.str, typing.Any]]] = None, - node_stage_secret_ref: typing.Optional[typing.Union["SecretReference", typing.Dict[builtins.str, typing.Any]]] = None, - read_only: typing.Optional[builtins.bool] = None, - volume_attributes: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - ) -> None: - '''Represents storage that is managed by an external CSI volume driver (Beta feature). - - :param driver: driver is the name of the driver to use for this volume. Required. - :param volume_handle: volumeHandle is the unique volume name returned by the CSI volume plugin’s CreateVolume to refer to the volume on all subsequent calls. Required. - :param controller_expand_secret_ref: controllerExpandSecretRef is a reference to the secret object containing sensitive information to pass to the CSI driver to complete the CSI ControllerExpandVolume call. This is an beta field and requires enabling ExpandCSIVolumes feature gate. This field is optional, and may be empty if no secret is required. If the secret object contains more than one secret, all secrets are passed. - :param controller_publish_secret_ref: controllerPublishSecretRef is a reference to the secret object containing sensitive information to pass to the CSI driver to complete the CSI ControllerPublishVolume and ControllerUnpublishVolume calls. This field is optional, and may be empty if no secret is required. If the secret object contains more than one secret, all secrets are passed. - :param fs_type: fsType to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". - :param node_expand_secret_ref: nodeExpandSecretRef is a reference to the secret object containing sensitive information to pass to the CSI driver to complete the CSI NodeExpandVolume call. This is an alpha field and requires enabling CSINodeExpandSecret feature gate. This field is optional, may be omitted if no secret is required. If the secret object contains more than one secret, all secrets are passed. - :param node_publish_secret_ref: nodePublishSecretRef is a reference to the secret object containing sensitive information to pass to the CSI driver to complete the CSI NodePublishVolume and NodeUnpublishVolume calls. This field is optional, and may be empty if no secret is required. If the secret object contains more than one secret, all secrets are passed. - :param node_stage_secret_ref: nodeStageSecretRef is a reference to the secret object containing sensitive information to pass to the CSI driver to complete the CSI NodeStageVolume and NodeStageVolume and NodeUnstageVolume calls. This field is optional, and may be empty if no secret is required. If the secret object contains more than one secret, all secrets are passed. - :param read_only: readOnly value to pass to ControllerPublishVolumeRequest. Defaults to false (read/write). Default: false (read/write). - :param volume_attributes: volumeAttributes of the volume to publish. - - :schema: io.k8s.api.core.v1.CSIPersistentVolumeSource - ''' - if isinstance(controller_expand_secret_ref, dict): - controller_expand_secret_ref = SecretReference(**controller_expand_secret_ref) - if isinstance(controller_publish_secret_ref, dict): - controller_publish_secret_ref = SecretReference(**controller_publish_secret_ref) - if isinstance(node_expand_secret_ref, dict): - node_expand_secret_ref = SecretReference(**node_expand_secret_ref) - if isinstance(node_publish_secret_ref, dict): - node_publish_secret_ref = SecretReference(**node_publish_secret_ref) - if isinstance(node_stage_secret_ref, dict): - node_stage_secret_ref = SecretReference(**node_stage_secret_ref) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__a4ab30eceffd6722994926b775cdc47f663e43744c6b71a78d0f1642819580a5) - check_type(argname="argument driver", value=driver, expected_type=type_hints["driver"]) - check_type(argname="argument volume_handle", value=volume_handle, expected_type=type_hints["volume_handle"]) - check_type(argname="argument controller_expand_secret_ref", value=controller_expand_secret_ref, expected_type=type_hints["controller_expand_secret_ref"]) - check_type(argname="argument controller_publish_secret_ref", value=controller_publish_secret_ref, expected_type=type_hints["controller_publish_secret_ref"]) - check_type(argname="argument fs_type", value=fs_type, expected_type=type_hints["fs_type"]) - check_type(argname="argument node_expand_secret_ref", value=node_expand_secret_ref, expected_type=type_hints["node_expand_secret_ref"]) - check_type(argname="argument node_publish_secret_ref", value=node_publish_secret_ref, expected_type=type_hints["node_publish_secret_ref"]) - check_type(argname="argument node_stage_secret_ref", value=node_stage_secret_ref, expected_type=type_hints["node_stage_secret_ref"]) - check_type(argname="argument read_only", value=read_only, expected_type=type_hints["read_only"]) - check_type(argname="argument volume_attributes", value=volume_attributes, expected_type=type_hints["volume_attributes"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "driver": driver, - "volume_handle": volume_handle, - } - if controller_expand_secret_ref is not None: - self._values["controller_expand_secret_ref"] = controller_expand_secret_ref - if controller_publish_secret_ref is not None: - self._values["controller_publish_secret_ref"] = controller_publish_secret_ref - if fs_type is not None: - self._values["fs_type"] = fs_type - if node_expand_secret_ref is not None: - self._values["node_expand_secret_ref"] = node_expand_secret_ref - if node_publish_secret_ref is not None: - self._values["node_publish_secret_ref"] = node_publish_secret_ref - if node_stage_secret_ref is not None: - self._values["node_stage_secret_ref"] = node_stage_secret_ref - if read_only is not None: - self._values["read_only"] = read_only - if volume_attributes is not None: - self._values["volume_attributes"] = volume_attributes - - @builtins.property - def driver(self) -> builtins.str: - '''driver is the name of the driver to use for this volume. - - Required. - - :schema: io.k8s.api.core.v1.CSIPersistentVolumeSource#driver - ''' - result = self._values.get("driver") - assert result is not None, "Required property 'driver' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def volume_handle(self) -> builtins.str: - '''volumeHandle is the unique volume name returned by the CSI volume plugin’s CreateVolume to refer to the volume on all subsequent calls. - - Required. - - :schema: io.k8s.api.core.v1.CSIPersistentVolumeSource#volumeHandle - ''' - result = self._values.get("volume_handle") - assert result is not None, "Required property 'volume_handle' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def controller_expand_secret_ref(self) -> typing.Optional["SecretReference"]: - '''controllerExpandSecretRef is a reference to the secret object containing sensitive information to pass to the CSI driver to complete the CSI ControllerExpandVolume call. - - This is an beta field and requires enabling ExpandCSIVolumes feature gate. This field is optional, and may be empty if no secret is required. If the secret object contains more than one secret, all secrets are passed. - - :schema: io.k8s.api.core.v1.CSIPersistentVolumeSource#controllerExpandSecretRef - ''' - result = self._values.get("controller_expand_secret_ref") - return typing.cast(typing.Optional["SecretReference"], result) - - @builtins.property - def controller_publish_secret_ref(self) -> typing.Optional["SecretReference"]: - '''controllerPublishSecretRef is a reference to the secret object containing sensitive information to pass to the CSI driver to complete the CSI ControllerPublishVolume and ControllerUnpublishVolume calls. - - This field is optional, and may be empty if no secret is required. If the secret object contains more than one secret, all secrets are passed. - - :schema: io.k8s.api.core.v1.CSIPersistentVolumeSource#controllerPublishSecretRef - ''' - result = self._values.get("controller_publish_secret_ref") - return typing.cast(typing.Optional["SecretReference"], result) - - @builtins.property - def fs_type(self) -> typing.Optional[builtins.str]: - '''fsType to mount. - - Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". - - :schema: io.k8s.api.core.v1.CSIPersistentVolumeSource#fsType - ''' - result = self._values.get("fs_type") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def node_expand_secret_ref(self) -> typing.Optional["SecretReference"]: - '''nodeExpandSecretRef is a reference to the secret object containing sensitive information to pass to the CSI driver to complete the CSI NodeExpandVolume call. - - This is an alpha field and requires enabling CSINodeExpandSecret feature gate. This field is optional, may be omitted if no secret is required. If the secret object contains more than one secret, all secrets are passed. - - :schema: io.k8s.api.core.v1.CSIPersistentVolumeSource#nodeExpandSecretRef - ''' - result = self._values.get("node_expand_secret_ref") - return typing.cast(typing.Optional["SecretReference"], result) - - @builtins.property - def node_publish_secret_ref(self) -> typing.Optional["SecretReference"]: - '''nodePublishSecretRef is a reference to the secret object containing sensitive information to pass to the CSI driver to complete the CSI NodePublishVolume and NodeUnpublishVolume calls. - - This field is optional, and may be empty if no secret is required. If the secret object contains more than one secret, all secrets are passed. - - :schema: io.k8s.api.core.v1.CSIPersistentVolumeSource#nodePublishSecretRef - ''' - result = self._values.get("node_publish_secret_ref") - return typing.cast(typing.Optional["SecretReference"], result) - - @builtins.property - def node_stage_secret_ref(self) -> typing.Optional["SecretReference"]: - '''nodeStageSecretRef is a reference to the secret object containing sensitive information to pass to the CSI driver to complete the CSI NodeStageVolume and NodeStageVolume and NodeUnstageVolume calls. - - This field is optional, and may be empty if no secret is required. If the secret object contains more than one secret, all secrets are passed. - - :schema: io.k8s.api.core.v1.CSIPersistentVolumeSource#nodeStageSecretRef - ''' - result = self._values.get("node_stage_secret_ref") - return typing.cast(typing.Optional["SecretReference"], result) - - @builtins.property - def read_only(self) -> typing.Optional[builtins.bool]: - '''readOnly value to pass to ControllerPublishVolumeRequest. - - Defaults to false (read/write). - - :default: false (read/write). - - :schema: io.k8s.api.core.v1.CSIPersistentVolumeSource#readOnly - ''' - result = self._values.get("read_only") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def volume_attributes( - self, - ) -> typing.Optional[typing.Mapping[builtins.str, builtins.str]]: - '''volumeAttributes of the volume to publish. - - :schema: io.k8s.api.core.v1.CSIPersistentVolumeSource#volumeAttributes - ''' - result = self._values.get("volume_attributes") - return typing.cast(typing.Optional[typing.Mapping[builtins.str, builtins.str]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "CsiPersistentVolumeSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.CsiVolumeSource", - jsii_struct_bases=[], - name_mapping={ - "driver": "driver", - "fs_type": "fsType", - "node_publish_secret_ref": "nodePublishSecretRef", - "read_only": "readOnly", - "volume_attributes": "volumeAttributes", - }, -) -class CsiVolumeSource: - def __init__( - self, - *, - driver: builtins.str, - fs_type: typing.Optional[builtins.str] = None, - node_publish_secret_ref: typing.Optional[typing.Union["LocalObjectReference", typing.Dict[builtins.str, typing.Any]]] = None, - read_only: typing.Optional[builtins.bool] = None, - volume_attributes: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - ) -> None: - '''Represents a source location of a volume to mount, managed by an external CSI driver. - - :param driver: driver is the name of the CSI driver that handles this volume. Consult with your admin for the correct name as registered in the cluster. - :param fs_type: fsType to mount. Ex. "ext4", "xfs", "ntfs". If not provided, the empty value is passed to the associated CSI driver which will determine the default filesystem to apply. - :param node_publish_secret_ref: nodePublishSecretRef is a reference to the secret object containing sensitive information to pass to the CSI driver to complete the CSI NodePublishVolume and NodeUnpublishVolume calls. This field is optional, and may be empty if no secret is required. If the secret object contains more than one secret, all secret references are passed. - :param read_only: readOnly specifies a read-only configuration for the volume. Defaults to false (read/write). Default: false (read/write). - :param volume_attributes: volumeAttributes stores driver-specific properties that are passed to the CSI driver. Consult your driver's documentation for supported values. - - :schema: io.k8s.api.core.v1.CSIVolumeSource - ''' - if isinstance(node_publish_secret_ref, dict): - node_publish_secret_ref = LocalObjectReference(**node_publish_secret_ref) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__65e9dfb99794038b02bcf5d69b1da24f041cc9f271cf98f603749465f2a3c2fe) - check_type(argname="argument driver", value=driver, expected_type=type_hints["driver"]) - check_type(argname="argument fs_type", value=fs_type, expected_type=type_hints["fs_type"]) - check_type(argname="argument node_publish_secret_ref", value=node_publish_secret_ref, expected_type=type_hints["node_publish_secret_ref"]) - check_type(argname="argument read_only", value=read_only, expected_type=type_hints["read_only"]) - check_type(argname="argument volume_attributes", value=volume_attributes, expected_type=type_hints["volume_attributes"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "driver": driver, - } - if fs_type is not None: - self._values["fs_type"] = fs_type - if node_publish_secret_ref is not None: - self._values["node_publish_secret_ref"] = node_publish_secret_ref - if read_only is not None: - self._values["read_only"] = read_only - if volume_attributes is not None: - self._values["volume_attributes"] = volume_attributes - - @builtins.property - def driver(self) -> builtins.str: - '''driver is the name of the CSI driver that handles this volume. - - Consult with your admin for the correct name as registered in the cluster. - - :schema: io.k8s.api.core.v1.CSIVolumeSource#driver - ''' - result = self._values.get("driver") - assert result is not None, "Required property 'driver' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def fs_type(self) -> typing.Optional[builtins.str]: - '''fsType to mount. - - Ex. "ext4", "xfs", "ntfs". If not provided, the empty value is passed to the associated CSI driver which will determine the default filesystem to apply. - - :schema: io.k8s.api.core.v1.CSIVolumeSource#fsType - ''' - result = self._values.get("fs_type") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def node_publish_secret_ref(self) -> typing.Optional["LocalObjectReference"]: - '''nodePublishSecretRef is a reference to the secret object containing sensitive information to pass to the CSI driver to complete the CSI NodePublishVolume and NodeUnpublishVolume calls. - - This field is optional, and may be empty if no secret is required. If the secret object contains more than one secret, all secret references are passed. - - :schema: io.k8s.api.core.v1.CSIVolumeSource#nodePublishSecretRef - ''' - result = self._values.get("node_publish_secret_ref") - return typing.cast(typing.Optional["LocalObjectReference"], result) - - @builtins.property - def read_only(self) -> typing.Optional[builtins.bool]: - '''readOnly specifies a read-only configuration for the volume. - - Defaults to false (read/write). - - :default: false (read/write). - - :schema: io.k8s.api.core.v1.CSIVolumeSource#readOnly - ''' - result = self._values.get("read_only") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def volume_attributes( - self, - ) -> typing.Optional[typing.Mapping[builtins.str, builtins.str]]: - '''volumeAttributes stores driver-specific properties that are passed to the CSI driver. - - Consult your driver's documentation for supported values. - - :schema: io.k8s.api.core.v1.CSIVolumeSource#volumeAttributes - ''' - result = self._values.get("volume_attributes") - return typing.cast(typing.Optional[typing.Mapping[builtins.str, builtins.str]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "CsiVolumeSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.CustomResourceColumnDefinition", - jsii_struct_bases=[], - name_mapping={ - "json_path": "jsonPath", - "name": "name", - "type": "type", - "description": "description", - "format": "format", - "priority": "priority", - }, -) -class CustomResourceColumnDefinition: - def __init__( - self, - *, - json_path: builtins.str, - name: builtins.str, - type: builtins.str, - description: typing.Optional[builtins.str] = None, - format: typing.Optional[builtins.str] = None, - priority: typing.Optional[jsii.Number] = None, - ) -> None: - '''CustomResourceColumnDefinition specifies a column for server side printing. - - :param json_path: jsonPath is a simple JSON path (i.e. with array notation) which is evaluated against each custom resource to produce the value for this column. - :param name: name is a human readable name for the column. - :param type: type is an OpenAPI type definition for this column. See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types for details. - :param description: description is a human readable description of this column. - :param format: format is an optional OpenAPI type definition for this column. The 'name' format is applied to the primary identifier column to assist in clients identifying column is the resource name. See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types for details. - :param priority: priority is an integer defining the relative importance of this column compared to others. Lower numbers are considered higher priority. Columns that may be omitted in limited space scenarios should be given a priority greater than 0. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceColumnDefinition - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__67357d094ad4e40c9fcc3d8cbf7b086f1bfc3261b70c6905ae016e7272d48696) - check_type(argname="argument json_path", value=json_path, expected_type=type_hints["json_path"]) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument type", value=type, expected_type=type_hints["type"]) - check_type(argname="argument description", value=description, expected_type=type_hints["description"]) - check_type(argname="argument format", value=format, expected_type=type_hints["format"]) - check_type(argname="argument priority", value=priority, expected_type=type_hints["priority"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "json_path": json_path, - "name": name, - "type": type, - } - if description is not None: - self._values["description"] = description - if format is not None: - self._values["format"] = format - if priority is not None: - self._values["priority"] = priority - - @builtins.property - def json_path(self) -> builtins.str: - '''jsonPath is a simple JSON path (i.e. with array notation) which is evaluated against each custom resource to produce the value for this column. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceColumnDefinition#jsonPath - ''' - result = self._values.get("json_path") - assert result is not None, "Required property 'json_path' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def name(self) -> builtins.str: - '''name is a human readable name for the column. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceColumnDefinition#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def type(self) -> builtins.str: - '''type is an OpenAPI type definition for this column. - - See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types for details. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceColumnDefinition#type - ''' - result = self._values.get("type") - assert result is not None, "Required property 'type' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def description(self) -> typing.Optional[builtins.str]: - '''description is a human readable description of this column. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceColumnDefinition#description - ''' - result = self._values.get("description") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def format(self) -> typing.Optional[builtins.str]: - '''format is an optional OpenAPI type definition for this column. - - The 'name' format is applied to the primary identifier column to assist in clients identifying column is the resource name. See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types for details. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceColumnDefinition#format - ''' - result = self._values.get("format") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def priority(self) -> typing.Optional[jsii.Number]: - '''priority is an integer defining the relative importance of this column compared to others. - - Lower numbers are considered higher priority. Columns that may be omitted in limited space scenarios should be given a priority greater than 0. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceColumnDefinition#priority - ''' - result = self._values.get("priority") - return typing.cast(typing.Optional[jsii.Number], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "CustomResourceColumnDefinition(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.CustomResourceConversion", - jsii_struct_bases=[], - name_mapping={"strategy": "strategy", "webhook": "webhook"}, -) -class CustomResourceConversion: - def __init__( - self, - *, - strategy: builtins.str, - webhook: typing.Optional[typing.Union["WebhookConversion", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''CustomResourceConversion describes how to convert different versions of a CR. - - :param strategy: strategy specifies how custom resources are converted between versions. Allowed values are: - ``None``: The converter only change the apiVersion and would not touch any other field in the custom resource. - ``Webhook``: API Server will call to an external webhook to do the conversion. Additional information is needed for this option. This requires spec.preserveUnknownFields to be false, and spec.conversion.webhook to be set. - :param webhook: webhook describes how to call the conversion webhook. Required when ``strategy`` is set to ``Webhook``. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceConversion - ''' - if isinstance(webhook, dict): - webhook = WebhookConversion(**webhook) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__d70408b4791a667462cf9c5081a65101e992ff219dda7178fc0fe4a250937f89) - check_type(argname="argument strategy", value=strategy, expected_type=type_hints["strategy"]) - check_type(argname="argument webhook", value=webhook, expected_type=type_hints["webhook"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "strategy": strategy, - } - if webhook is not None: - self._values["webhook"] = webhook - - @builtins.property - def strategy(self) -> builtins.str: - '''strategy specifies how custom resources are converted between versions. - - Allowed values are: - ``None``: The converter only change the apiVersion and would not touch any other field in the custom resource. - ``Webhook``: API Server will call to an external webhook to do the conversion. Additional information - is needed for this option. This requires spec.preserveUnknownFields to be false, and spec.conversion.webhook to be set. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceConversion#strategy - ''' - result = self._values.get("strategy") - assert result is not None, "Required property 'strategy' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def webhook(self) -> typing.Optional["WebhookConversion"]: - '''webhook describes how to call the conversion webhook. - - Required when ``strategy`` is set to ``Webhook``. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceConversion#webhook - ''' - result = self._values.get("webhook") - return typing.cast(typing.Optional["WebhookConversion"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "CustomResourceConversion(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.CustomResourceDefinitionNames", - jsii_struct_bases=[], - name_mapping={ - "kind": "kind", - "plural": "plural", - "categories": "categories", - "list_kind": "listKind", - "short_names": "shortNames", - "singular": "singular", - }, -) -class CustomResourceDefinitionNames: - def __init__( - self, - *, - kind: builtins.str, - plural: builtins.str, - categories: typing.Optional[typing.Sequence[builtins.str]] = None, - list_kind: typing.Optional[builtins.str] = None, - short_names: typing.Optional[typing.Sequence[builtins.str]] = None, - singular: typing.Optional[builtins.str] = None, - ) -> None: - '''CustomResourceDefinitionNames indicates the names to serve this CustomResourceDefinition. - - :param kind: kind is the serialized kind of the resource. It is normally CamelCase and singular. Custom resource instances will use this value as the ``kind`` attribute in API calls. - :param plural: plural is the plural name of the resource to serve. The custom resources are served under ``/apis///.../``. Must match the name of the CustomResourceDefinition (in the form ``.``). Must be all lowercase. - :param categories: categories is a list of grouped resources this custom resource belongs to (e.g. 'all'). This is published in API discovery documents, and used by clients to support invocations like ``kubectl get all``. - :param list_kind: listKind is the serialized kind of the list for this resource. Defaults to "``kind``List". Default: kind`List". - :param short_names: shortNames are short names for the resource, exposed in API discovery documents, and used by clients to support invocations like ``kubectl get ``. It must be all lowercase. - :param singular: singular is the singular name of the resource. It must be all lowercase. Defaults to lowercased ``kind``. Default: lowercased ``kind``. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceDefinitionNames - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__9f1b391925af7e4945bb8d4ea39747ad4716515ac0a5519bb5b63e5039390614) - check_type(argname="argument kind", value=kind, expected_type=type_hints["kind"]) - check_type(argname="argument plural", value=plural, expected_type=type_hints["plural"]) - check_type(argname="argument categories", value=categories, expected_type=type_hints["categories"]) - check_type(argname="argument list_kind", value=list_kind, expected_type=type_hints["list_kind"]) - check_type(argname="argument short_names", value=short_names, expected_type=type_hints["short_names"]) - check_type(argname="argument singular", value=singular, expected_type=type_hints["singular"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "kind": kind, - "plural": plural, - } - if categories is not None: - self._values["categories"] = categories - if list_kind is not None: - self._values["list_kind"] = list_kind - if short_names is not None: - self._values["short_names"] = short_names - if singular is not None: - self._values["singular"] = singular - - @builtins.property - def kind(self) -> builtins.str: - '''kind is the serialized kind of the resource. - - It is normally CamelCase and singular. Custom resource instances will use this value as the ``kind`` attribute in API calls. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceDefinitionNames#kind - ''' - result = self._values.get("kind") - assert result is not None, "Required property 'kind' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def plural(self) -> builtins.str: - '''plural is the plural name of the resource to serve. - - The custom resources are served under ``/apis///.../``. Must match the name of the CustomResourceDefinition (in the form ``.``). Must be all lowercase. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceDefinitionNames#plural - ''' - result = self._values.get("plural") - assert result is not None, "Required property 'plural' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def categories(self) -> typing.Optional[typing.List[builtins.str]]: - '''categories is a list of grouped resources this custom resource belongs to (e.g. 'all'). This is published in API discovery documents, and used by clients to support invocations like ``kubectl get all``. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceDefinitionNames#categories - ''' - result = self._values.get("categories") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def list_kind(self) -> typing.Optional[builtins.str]: - '''listKind is the serialized kind of the list for this resource. - - Defaults to "``kind``List". - - :default: kind`List". - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceDefinitionNames#listKind - ''' - result = self._values.get("list_kind") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def short_names(self) -> typing.Optional[typing.List[builtins.str]]: - '''shortNames are short names for the resource, exposed in API discovery documents, and used by clients to support invocations like ``kubectl get ``. - - It must be all lowercase. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceDefinitionNames#shortNames - ''' - result = self._values.get("short_names") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def singular(self) -> typing.Optional[builtins.str]: - '''singular is the singular name of the resource. - - It must be all lowercase. Defaults to lowercased ``kind``. - - :default: lowercased ``kind``. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceDefinitionNames#singular - ''' - result = self._values.get("singular") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "CustomResourceDefinitionNames(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.CustomResourceDefinitionSpec", - jsii_struct_bases=[], - name_mapping={ - "group": "group", - "names": "names", - "scope": "scope", - "versions": "versions", - "conversion": "conversion", - "preserve_unknown_fields": "preserveUnknownFields", - }, -) -class CustomResourceDefinitionSpec: - def __init__( - self, - *, - group: builtins.str, - names: typing.Union[CustomResourceDefinitionNames, typing.Dict[builtins.str, typing.Any]], - scope: builtins.str, - versions: typing.Sequence[typing.Union["CustomResourceDefinitionVersion", typing.Dict[builtins.str, typing.Any]]], - conversion: typing.Optional[typing.Union[CustomResourceConversion, typing.Dict[builtins.str, typing.Any]]] = None, - preserve_unknown_fields: typing.Optional[builtins.bool] = None, - ) -> None: - '''CustomResourceDefinitionSpec describes how a user wants their resource to appear. - - :param group: group is the API group of the defined custom resource. The custom resources are served under ``/apis//...``. Must match the name of the CustomResourceDefinition (in the form ``.``). - :param names: names specify the resource and kind names for the custom resource. - :param scope: scope indicates whether the defined custom resource is cluster- or namespace-scoped. Allowed values are ``Cluster`` and ``Namespaced``. - :param versions: versions is the list of all API versions of the defined custom resource. Version names are used to compute the order in which served versions are listed in API discovery. If the version string is "kube-like", it will sort above non "kube-like" version strings, which are ordered lexicographically. "Kube-like" versions start with a "v", then are followed by a number (the major version), then optionally the string "alpha" or "beta" and another number (the minor version). These are sorted first by GA > beta > alpha (where GA is a version with no suffix such as beta or alpha), and then by comparing major version, then minor version. An example sorted list of versions: v10, v2, v1, v11beta2, v10beta3, v3beta1, v12alpha1, v11alpha2, foo1, foo10. - :param conversion: conversion defines conversion settings for the CRD. - :param preserve_unknown_fields: preserveUnknownFields indicates that object fields which are not specified in the OpenAPI schema should be preserved when persisting to storage. apiVersion, kind, metadata and known fields inside metadata are always preserved. This field is deprecated in favor of setting ``x-preserve-unknown-fields`` to true in ``spec.versions[*].schema.openAPIV3Schema``. See https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#field-pruning for details. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceDefinitionSpec - ''' - if isinstance(names, dict): - names = CustomResourceDefinitionNames(**names) - if isinstance(conversion, dict): - conversion = CustomResourceConversion(**conversion) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__3998b630c25e34db9c60fa9ce393302f885dc2d0aa7e7eddb9228b8dc8335d91) - check_type(argname="argument group", value=group, expected_type=type_hints["group"]) - check_type(argname="argument names", value=names, expected_type=type_hints["names"]) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument versions", value=versions, expected_type=type_hints["versions"]) - check_type(argname="argument conversion", value=conversion, expected_type=type_hints["conversion"]) - check_type(argname="argument preserve_unknown_fields", value=preserve_unknown_fields, expected_type=type_hints["preserve_unknown_fields"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "group": group, - "names": names, - "scope": scope, - "versions": versions, - } - if conversion is not None: - self._values["conversion"] = conversion - if preserve_unknown_fields is not None: - self._values["preserve_unknown_fields"] = preserve_unknown_fields - - @builtins.property - def group(self) -> builtins.str: - '''group is the API group of the defined custom resource. - - The custom resources are served under ``/apis//...``. Must match the name of the CustomResourceDefinition (in the form ``.``). - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceDefinitionSpec#group - ''' - result = self._values.get("group") - assert result is not None, "Required property 'group' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def names(self) -> CustomResourceDefinitionNames: - '''names specify the resource and kind names for the custom resource. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceDefinitionSpec#names - ''' - result = self._values.get("names") - assert result is not None, "Required property 'names' is missing" - return typing.cast(CustomResourceDefinitionNames, result) - - @builtins.property - def scope(self) -> builtins.str: - '''scope indicates whether the defined custom resource is cluster- or namespace-scoped. - - Allowed values are ``Cluster`` and ``Namespaced``. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceDefinitionSpec#scope - ''' - result = self._values.get("scope") - assert result is not None, "Required property 'scope' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def versions(self) -> typing.List["CustomResourceDefinitionVersion"]: - '''versions is the list of all API versions of the defined custom resource. - - Version names are used to compute the order in which served versions are listed in API discovery. If the version string is "kube-like", it will sort above non "kube-like" version strings, which are ordered lexicographically. "Kube-like" versions start with a "v", then are followed by a number (the major version), then optionally the string "alpha" or "beta" and another number (the minor version). These are sorted first by GA > beta > alpha (where GA is a version with no suffix such as beta or alpha), and then by comparing major version, then minor version. An example sorted list of versions: v10, v2, v1, v11beta2, v10beta3, v3beta1, v12alpha1, v11alpha2, foo1, foo10. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceDefinitionSpec#versions - ''' - result = self._values.get("versions") - assert result is not None, "Required property 'versions' is missing" - return typing.cast(typing.List["CustomResourceDefinitionVersion"], result) - - @builtins.property - def conversion(self) -> typing.Optional[CustomResourceConversion]: - '''conversion defines conversion settings for the CRD. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceDefinitionSpec#conversion - ''' - result = self._values.get("conversion") - return typing.cast(typing.Optional[CustomResourceConversion], result) - - @builtins.property - def preserve_unknown_fields(self) -> typing.Optional[builtins.bool]: - '''preserveUnknownFields indicates that object fields which are not specified in the OpenAPI schema should be preserved when persisting to storage. - - apiVersion, kind, metadata and known fields inside metadata are always preserved. This field is deprecated in favor of setting ``x-preserve-unknown-fields`` to true in ``spec.versions[*].schema.openAPIV3Schema``. See https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#field-pruning for details. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceDefinitionSpec#preserveUnknownFields - ''' - result = self._values.get("preserve_unknown_fields") - return typing.cast(typing.Optional[builtins.bool], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "CustomResourceDefinitionSpec(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.CustomResourceDefinitionVersion", - jsii_struct_bases=[], - name_mapping={ - "name": "name", - "served": "served", - "storage": "storage", - "additional_printer_columns": "additionalPrinterColumns", - "deprecated": "deprecated", - "deprecation_warning": "deprecationWarning", - "schema": "schema", - "subresources": "subresources", - }, -) -class CustomResourceDefinitionVersion: - def __init__( - self, - *, - name: builtins.str, - served: builtins.bool, - storage: builtins.bool, - additional_printer_columns: typing.Optional[typing.Sequence[typing.Union[CustomResourceColumnDefinition, typing.Dict[builtins.str, typing.Any]]]] = None, - deprecated: typing.Optional[builtins.bool] = None, - deprecation_warning: typing.Optional[builtins.str] = None, - schema: typing.Optional[typing.Union["CustomResourceValidation", typing.Dict[builtins.str, typing.Any]]] = None, - subresources: typing.Optional[typing.Union["CustomResourceSubresources", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''CustomResourceDefinitionVersion describes a version for CRD. - - :param name: name is the version name, e.g. “v1”, “v2beta1”, etc. The custom resources are served under this version at ``/apis///...`` if ``served`` is true. - :param served: served is a flag enabling/disabling this version from being served via REST APIs. - :param storage: storage indicates this version should be used when persisting custom resources to storage. There must be exactly one version with storage=true. - :param additional_printer_columns: additionalPrinterColumns specifies additional columns returned in Table output. See https://kubernetes.io/docs/reference/using-api/api-concepts/#receiving-resources-as-tables for details. If no columns are specified, a single column displaying the age of the custom resource is used. - :param deprecated: deprecated indicates this version of the custom resource API is deprecated. When set to true, API requests to this version receive a warning header in the server response. Defaults to false. Default: false. - :param deprecation_warning: deprecationWarning overrides the default warning returned to API clients. May only be set when ``deprecated`` is true. The default warning indicates this version is deprecated and recommends use of the newest served version of equal or greater stability, if one exists. - :param schema: schema describes the schema used for validation, pruning, and defaulting of this version of the custom resource. - :param subresources: subresources specify what subresources this version of the defined custom resource have. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceDefinitionVersion - ''' - if isinstance(schema, dict): - schema = CustomResourceValidation(**schema) - if isinstance(subresources, dict): - subresources = CustomResourceSubresources(**subresources) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__d6df99d714ea39698bb4328abb2c39a68421fd691d72d93bd6ddbb23b90046bf) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument served", value=served, expected_type=type_hints["served"]) - check_type(argname="argument storage", value=storage, expected_type=type_hints["storage"]) - check_type(argname="argument additional_printer_columns", value=additional_printer_columns, expected_type=type_hints["additional_printer_columns"]) - check_type(argname="argument deprecated", value=deprecated, expected_type=type_hints["deprecated"]) - check_type(argname="argument deprecation_warning", value=deprecation_warning, expected_type=type_hints["deprecation_warning"]) - check_type(argname="argument schema", value=schema, expected_type=type_hints["schema"]) - check_type(argname="argument subresources", value=subresources, expected_type=type_hints["subresources"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "name": name, - "served": served, - "storage": storage, - } - if additional_printer_columns is not None: - self._values["additional_printer_columns"] = additional_printer_columns - if deprecated is not None: - self._values["deprecated"] = deprecated - if deprecation_warning is not None: - self._values["deprecation_warning"] = deprecation_warning - if schema is not None: - self._values["schema"] = schema - if subresources is not None: - self._values["subresources"] = subresources - - @builtins.property - def name(self) -> builtins.str: - '''name is the version name, e.g. “v1”, “v2beta1”, etc. The custom resources are served under this version at ``/apis///...`` if ``served`` is true. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceDefinitionVersion#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def served(self) -> builtins.bool: - '''served is a flag enabling/disabling this version from being served via REST APIs. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceDefinitionVersion#served - ''' - result = self._values.get("served") - assert result is not None, "Required property 'served' is missing" - return typing.cast(builtins.bool, result) - - @builtins.property - def storage(self) -> builtins.bool: - '''storage indicates this version should be used when persisting custom resources to storage. - - There must be exactly one version with storage=true. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceDefinitionVersion#storage - ''' - result = self._values.get("storage") - assert result is not None, "Required property 'storage' is missing" - return typing.cast(builtins.bool, result) - - @builtins.property - def additional_printer_columns( - self, - ) -> typing.Optional[typing.List[CustomResourceColumnDefinition]]: - '''additionalPrinterColumns specifies additional columns returned in Table output. - - See https://kubernetes.io/docs/reference/using-api/api-concepts/#receiving-resources-as-tables for details. If no columns are specified, a single column displaying the age of the custom resource is used. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceDefinitionVersion#additionalPrinterColumns - ''' - result = self._values.get("additional_printer_columns") - return typing.cast(typing.Optional[typing.List[CustomResourceColumnDefinition]], result) - - @builtins.property - def deprecated(self) -> typing.Optional[builtins.bool]: - '''deprecated indicates this version of the custom resource API is deprecated. - - When set to true, API requests to this version receive a warning header in the server response. Defaults to false. - - :default: false. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceDefinitionVersion#deprecated - ''' - result = self._values.get("deprecated") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def deprecation_warning(self) -> typing.Optional[builtins.str]: - '''deprecationWarning overrides the default warning returned to API clients. - - May only be set when ``deprecated`` is true. The default warning indicates this version is deprecated and recommends use of the newest served version of equal or greater stability, if one exists. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceDefinitionVersion#deprecationWarning - ''' - result = self._values.get("deprecation_warning") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def schema(self) -> typing.Optional["CustomResourceValidation"]: - '''schema describes the schema used for validation, pruning, and defaulting of this version of the custom resource. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceDefinitionVersion#schema - ''' - result = self._values.get("schema") - return typing.cast(typing.Optional["CustomResourceValidation"], result) - - @builtins.property - def subresources(self) -> typing.Optional["CustomResourceSubresources"]: - '''subresources specify what subresources this version of the defined custom resource have. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceDefinitionVersion#subresources - ''' - result = self._values.get("subresources") - return typing.cast(typing.Optional["CustomResourceSubresources"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "CustomResourceDefinitionVersion(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.CustomResourceSubresourceScale", - jsii_struct_bases=[], - name_mapping={ - "spec_replicas_path": "specReplicasPath", - "status_replicas_path": "statusReplicasPath", - "label_selector_path": "labelSelectorPath", - }, -) -class CustomResourceSubresourceScale: - def __init__( - self, - *, - spec_replicas_path: builtins.str, - status_replicas_path: builtins.str, - label_selector_path: typing.Optional[builtins.str] = None, - ) -> None: - '''CustomResourceSubresourceScale defines how to serve the scale subresource for CustomResources. - - :param spec_replicas_path: specReplicasPath defines the JSON path inside of a custom resource that corresponds to Scale ``spec.replicas``. Only JSON paths without the array notation are allowed. Must be a JSON Path under ``.spec``. If there is no value under the given path in the custom resource, the ``/scale`` subresource will return an error on GET. - :param status_replicas_path: statusReplicasPath defines the JSON path inside of a custom resource that corresponds to Scale ``status.replicas``. Only JSON paths without the array notation are allowed. Must be a JSON Path under ``.status``. If there is no value under the given path in the custom resource, the ``status.replicas`` value in the ``/scale`` subresource will default to 0. - :param label_selector_path: labelSelectorPath defines the JSON path inside of a custom resource that corresponds to Scale ``status.selector``. Only JSON paths without the array notation are allowed. Must be a JSON Path under ``.status`` or ``.spec``. Must be set to work with HorizontalPodAutoscaler. The field pointed by this JSON path must be a string field (not a complex selector struct) which contains a serialized label selector in string form. More info: https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions#scale-subresource If there is no value under the given path in the custom resource, the ``status.selector`` value in the ``/scale`` subresource will default to the empty string. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceSubresourceScale - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__e504fd18aae767ddb56fbac096bf70df45780d510027e105b410fa62efa0ce33) - check_type(argname="argument spec_replicas_path", value=spec_replicas_path, expected_type=type_hints["spec_replicas_path"]) - check_type(argname="argument status_replicas_path", value=status_replicas_path, expected_type=type_hints["status_replicas_path"]) - check_type(argname="argument label_selector_path", value=label_selector_path, expected_type=type_hints["label_selector_path"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "spec_replicas_path": spec_replicas_path, - "status_replicas_path": status_replicas_path, - } - if label_selector_path is not None: - self._values["label_selector_path"] = label_selector_path - - @builtins.property - def spec_replicas_path(self) -> builtins.str: - '''specReplicasPath defines the JSON path inside of a custom resource that corresponds to Scale ``spec.replicas``. Only JSON paths without the array notation are allowed. Must be a JSON Path under ``.spec``. If there is no value under the given path in the custom resource, the ``/scale`` subresource will return an error on GET. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceSubresourceScale#specReplicasPath - ''' - result = self._values.get("spec_replicas_path") - assert result is not None, "Required property 'spec_replicas_path' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def status_replicas_path(self) -> builtins.str: - '''statusReplicasPath defines the JSON path inside of a custom resource that corresponds to Scale ``status.replicas``. Only JSON paths without the array notation are allowed. Must be a JSON Path under ``.status``. If there is no value under the given path in the custom resource, the ``status.replicas`` value in the ``/scale`` subresource will default to 0. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceSubresourceScale#statusReplicasPath - ''' - result = self._values.get("status_replicas_path") - assert result is not None, "Required property 'status_replicas_path' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def label_selector_path(self) -> typing.Optional[builtins.str]: - '''labelSelectorPath defines the JSON path inside of a custom resource that corresponds to Scale ``status.selector``. Only JSON paths without the array notation are allowed. Must be a JSON Path under ``.status`` or ``.spec``. Must be set to work with HorizontalPodAutoscaler. The field pointed by this JSON path must be a string field (not a complex selector struct) which contains a serialized label selector in string form. More info: https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions#scale-subresource If there is no value under the given path in the custom resource, the ``status.selector`` value in the ``/scale`` subresource will default to the empty string. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceSubresourceScale#labelSelectorPath - ''' - result = self._values.get("label_selector_path") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "CustomResourceSubresourceScale(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.CustomResourceSubresources", - jsii_struct_bases=[], - name_mapping={"scale": "scale", "status": "status"}, -) -class CustomResourceSubresources: - def __init__( - self, - *, - scale: typing.Optional[typing.Union[CustomResourceSubresourceScale, typing.Dict[builtins.str, typing.Any]]] = None, - status: typing.Any = None, - ) -> None: - '''CustomResourceSubresources defines the status and scale subresources for CustomResources. - - :param scale: scale indicates the custom resource should serve a ``/scale`` subresource that returns an ``autoscaling/v1`` Scale object. - :param status: status indicates the custom resource should serve a ``/status`` subresource. When enabled: 1. requests to the custom resource primary endpoint ignore changes to the ``status`` stanza of the object. 2. requests to the custom resource ``/status`` subresource ignore changes to anything other than the ``status`` stanza of the object. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceSubresources - ''' - if isinstance(scale, dict): - scale = CustomResourceSubresourceScale(**scale) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__c50da5aa5369520674d278d624a5847abf90b5ff122b8050299b5990def114cd) - check_type(argname="argument scale", value=scale, expected_type=type_hints["scale"]) - check_type(argname="argument status", value=status, expected_type=type_hints["status"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if scale is not None: - self._values["scale"] = scale - if status is not None: - self._values["status"] = status - - @builtins.property - def scale(self) -> typing.Optional[CustomResourceSubresourceScale]: - '''scale indicates the custom resource should serve a ``/scale`` subresource that returns an ``autoscaling/v1`` Scale object. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceSubresources#scale - ''' - result = self._values.get("scale") - return typing.cast(typing.Optional[CustomResourceSubresourceScale], result) - - @builtins.property - def status(self) -> typing.Any: - '''status indicates the custom resource should serve a ``/status`` subresource. - - When enabled: 1. requests to the custom resource primary endpoint ignore changes to the ``status`` stanza of the object. 2. requests to the custom resource ``/status`` subresource ignore changes to anything other than the ``status`` stanza of the object. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceSubresources#status - ''' - result = self._values.get("status") - return typing.cast(typing.Any, result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "CustomResourceSubresources(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.CustomResourceValidation", - jsii_struct_bases=[], - name_mapping={"open_apiv3_schema": "openApiv3Schema"}, -) -class CustomResourceValidation: - def __init__( - self, - *, - open_apiv3_schema: typing.Optional[typing.Union["JsonSchemaProps", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''CustomResourceValidation is a list of validation methods for CustomResources. - - :param open_apiv3_schema: openAPIV3Schema is the OpenAPI v3 schema to use for validation and pruning. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceValidation - ''' - if isinstance(open_apiv3_schema, dict): - open_apiv3_schema = JsonSchemaProps(**open_apiv3_schema) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__043bf7c99906ebf978f378e80401b671bd7d527825d3a4d5d96e0c729fdbf9a8) - check_type(argname="argument open_apiv3_schema", value=open_apiv3_schema, expected_type=type_hints["open_apiv3_schema"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if open_apiv3_schema is not None: - self._values["open_apiv3_schema"] = open_apiv3_schema - - @builtins.property - def open_apiv3_schema(self) -> typing.Optional["JsonSchemaProps"]: - '''openAPIV3Schema is the OpenAPI v3 schema to use for validation and pruning. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceValidation#openAPIV3Schema - ''' - result = self._values.get("open_apiv3_schema") - return typing.cast(typing.Optional["JsonSchemaProps"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "CustomResourceValidation(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.DaemonSetSpec", - jsii_struct_bases=[], - name_mapping={ - "selector": "selector", - "template": "template", - "min_ready_seconds": "minReadySeconds", - "revision_history_limit": "revisionHistoryLimit", - "update_strategy": "updateStrategy", - }, -) -class DaemonSetSpec: - def __init__( - self, - *, - selector: typing.Union["LabelSelector", typing.Dict[builtins.str, typing.Any]], - template: typing.Union["PodTemplateSpec", typing.Dict[builtins.str, typing.Any]], - min_ready_seconds: typing.Optional[jsii.Number] = None, - revision_history_limit: typing.Optional[jsii.Number] = None, - update_strategy: typing.Optional[typing.Union["DaemonSetUpdateStrategy", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''DaemonSetSpec is the specification of a daemon set. - - :param selector: A label query over pods that are managed by the daemon set. Must match in order to be controlled. It must match the pod template's labels. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors - :param template: An object that describes the pod that will be created. The DaemonSet will create exactly one copy of this pod on every node that matches the template's node selector (or on every node if no node selector is specified). More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller#pod-template - :param min_ready_seconds: The minimum number of seconds for which a newly created DaemonSet pod should be ready without any of its container crashing, for it to be considered available. Defaults to 0 (pod will be considered available as soon as it is ready). Default: 0 (pod will be considered available as soon as it is ready). - :param revision_history_limit: The number of old history to retain to allow rollback. This is a pointer to distinguish between explicit zero and not specified. Defaults to 10. Default: 10. - :param update_strategy: An update strategy to replace existing DaemonSet pods with new pods. - - :schema: io.k8s.api.apps.v1.DaemonSetSpec - ''' - if isinstance(selector, dict): - selector = LabelSelector(**selector) - if isinstance(template, dict): - template = PodTemplateSpec(**template) - if isinstance(update_strategy, dict): - update_strategy = DaemonSetUpdateStrategy(**update_strategy) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__14204ab2e113520a3c936870c510953423acc16ac3f52118402d23dec634f9a1) - check_type(argname="argument selector", value=selector, expected_type=type_hints["selector"]) - check_type(argname="argument template", value=template, expected_type=type_hints["template"]) - check_type(argname="argument min_ready_seconds", value=min_ready_seconds, expected_type=type_hints["min_ready_seconds"]) - check_type(argname="argument revision_history_limit", value=revision_history_limit, expected_type=type_hints["revision_history_limit"]) - check_type(argname="argument update_strategy", value=update_strategy, expected_type=type_hints["update_strategy"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "selector": selector, - "template": template, - } - if min_ready_seconds is not None: - self._values["min_ready_seconds"] = min_ready_seconds - if revision_history_limit is not None: - self._values["revision_history_limit"] = revision_history_limit - if update_strategy is not None: - self._values["update_strategy"] = update_strategy - - @builtins.property - def selector(self) -> "LabelSelector": - '''A label query over pods that are managed by the daemon set. - - Must match in order to be controlled. It must match the pod template's labels. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors - - :schema: io.k8s.api.apps.v1.DaemonSetSpec#selector - ''' - result = self._values.get("selector") - assert result is not None, "Required property 'selector' is missing" - return typing.cast("LabelSelector", result) - - @builtins.property - def template(self) -> "PodTemplateSpec": - '''An object that describes the pod that will be created. - - The DaemonSet will create exactly one copy of this pod on every node that matches the template's node selector (or on every node if no node selector is specified). More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller#pod-template - - :schema: io.k8s.api.apps.v1.DaemonSetSpec#template - ''' - result = self._values.get("template") - assert result is not None, "Required property 'template' is missing" - return typing.cast("PodTemplateSpec", result) - - @builtins.property - def min_ready_seconds(self) -> typing.Optional[jsii.Number]: - '''The minimum number of seconds for which a newly created DaemonSet pod should be ready without any of its container crashing, for it to be considered available. - - Defaults to 0 (pod will be considered available as soon as it is ready). - - :default: 0 (pod will be considered available as soon as it is ready). - - :schema: io.k8s.api.apps.v1.DaemonSetSpec#minReadySeconds - ''' - result = self._values.get("min_ready_seconds") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def revision_history_limit(self) -> typing.Optional[jsii.Number]: - '''The number of old history to retain to allow rollback. - - This is a pointer to distinguish between explicit zero and not specified. Defaults to 10. - - :default: 10. - - :schema: io.k8s.api.apps.v1.DaemonSetSpec#revisionHistoryLimit - ''' - result = self._values.get("revision_history_limit") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def update_strategy(self) -> typing.Optional["DaemonSetUpdateStrategy"]: - '''An update strategy to replace existing DaemonSet pods with new pods. - - :schema: io.k8s.api.apps.v1.DaemonSetSpec#updateStrategy - ''' - result = self._values.get("update_strategy") - return typing.cast(typing.Optional["DaemonSetUpdateStrategy"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "DaemonSetSpec(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.DaemonSetUpdateStrategy", - jsii_struct_bases=[], - name_mapping={"rolling_update": "rollingUpdate", "type": "type"}, -) -class DaemonSetUpdateStrategy: - def __init__( - self, - *, - rolling_update: typing.Optional[typing.Union["RollingUpdateDaemonSet", typing.Dict[builtins.str, typing.Any]]] = None, - type: typing.Optional[builtins.str] = None, - ) -> None: - '''DaemonSetUpdateStrategy is a struct used to control the update strategy for a DaemonSet. - - :param rolling_update: Rolling update config params. Present only if type = "RollingUpdate". - :param type: Type of daemon set update. Can be "RollingUpdate" or "OnDelete". Default is RollingUpdate. Default: RollingUpdate. - - :schema: io.k8s.api.apps.v1.DaemonSetUpdateStrategy - ''' - if isinstance(rolling_update, dict): - rolling_update = RollingUpdateDaemonSet(**rolling_update) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__8b11783b3c58aecec2330e072809ea832cb9b06930ebac2636be1238b0ff753f) - check_type(argname="argument rolling_update", value=rolling_update, expected_type=type_hints["rolling_update"]) - check_type(argname="argument type", value=type, expected_type=type_hints["type"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if rolling_update is not None: - self._values["rolling_update"] = rolling_update - if type is not None: - self._values["type"] = type - - @builtins.property - def rolling_update(self) -> typing.Optional["RollingUpdateDaemonSet"]: - '''Rolling update config params. - - Present only if type = "RollingUpdate". - - :schema: io.k8s.api.apps.v1.DaemonSetUpdateStrategy#rollingUpdate - ''' - result = self._values.get("rolling_update") - return typing.cast(typing.Optional["RollingUpdateDaemonSet"], result) - - @builtins.property - def type(self) -> typing.Optional[builtins.str]: - '''Type of daemon set update. - - Can be "RollingUpdate" or "OnDelete". Default is RollingUpdate. - - :default: RollingUpdate. - - :schema: io.k8s.api.apps.v1.DaemonSetUpdateStrategy#type - ''' - result = self._values.get("type") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "DaemonSetUpdateStrategy(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.DeleteOptions", - jsii_struct_bases=[], - name_mapping={ - "api_version": "apiVersion", - "dry_run": "dryRun", - "grace_period_seconds": "gracePeriodSeconds", - "kind": "kind", - "orphan_dependents": "orphanDependents", - "preconditions": "preconditions", - "propagation_policy": "propagationPolicy", - }, -) -class DeleteOptions: - def __init__( - self, - *, - api_version: typing.Optional[builtins.str] = None, - dry_run: typing.Optional[typing.Sequence[builtins.str]] = None, - grace_period_seconds: typing.Optional[jsii.Number] = None, - kind: typing.Optional["IoK8SApimachineryPkgApisMetaV1DeleteOptionsKind"] = None, - orphan_dependents: typing.Optional[builtins.bool] = None, - preconditions: typing.Optional[typing.Union["Preconditions", typing.Dict[builtins.str, typing.Any]]] = None, - propagation_policy: typing.Optional[builtins.str] = None, - ) -> None: - '''DeleteOptions may be provided when deleting an API object. - - :param api_version: APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - :param dry_run: When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed - :param grace_period_seconds: The duration in seconds before the object should be deleted. Value must be non-negative integer. The value zero indicates delete immediately. If this value is nil, the default grace period for the specified type will be used. Defaults to a per object value if not specified. zero means delete immediately. Default: a per object value if not specified. zero means delete immediately. - :param kind: Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - :param orphan_dependents: Deprecated: please use the PropagationPolicy, this field will be deprecated in 1.7. Should the dependent objects be orphaned. If true/false, the "orphan" finalizer will be added to/removed from the object's finalizers list. Either this field or PropagationPolicy may be set, but not both. - :param preconditions: Must be fulfilled before a deletion is carried out. If not possible, a 409 Conflict status will be returned. - :param propagation_policy: Whether and how garbage collection will be performed. Either this field or OrphanDependents may be set, but not both. The default policy is decided by the existing finalizer set in the metadata.finalizers and the resource-specific default policy. Acceptable values are: 'Orphan' - orphan the dependents; 'Background' - allow the garbage collector to delete the dependents in the background; 'Foreground' - a cascading policy that deletes all dependents in the foreground. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.DeleteOptions - ''' - if isinstance(preconditions, dict): - preconditions = Preconditions(**preconditions) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__51651210b2f45ea52509def59df38f1a165f6231405843108f8fb43c79e7fd13) - check_type(argname="argument api_version", value=api_version, expected_type=type_hints["api_version"]) - check_type(argname="argument dry_run", value=dry_run, expected_type=type_hints["dry_run"]) - check_type(argname="argument grace_period_seconds", value=grace_period_seconds, expected_type=type_hints["grace_period_seconds"]) - check_type(argname="argument kind", value=kind, expected_type=type_hints["kind"]) - check_type(argname="argument orphan_dependents", value=orphan_dependents, expected_type=type_hints["orphan_dependents"]) - check_type(argname="argument preconditions", value=preconditions, expected_type=type_hints["preconditions"]) - check_type(argname="argument propagation_policy", value=propagation_policy, expected_type=type_hints["propagation_policy"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if api_version is not None: - self._values["api_version"] = api_version - if dry_run is not None: - self._values["dry_run"] = dry_run - if grace_period_seconds is not None: - self._values["grace_period_seconds"] = grace_period_seconds - if kind is not None: - self._values["kind"] = kind - if orphan_dependents is not None: - self._values["orphan_dependents"] = orphan_dependents - if preconditions is not None: - self._values["preconditions"] = preconditions - if propagation_policy is not None: - self._values["propagation_policy"] = propagation_policy - - @builtins.property - def api_version(self) -> typing.Optional[builtins.str]: - '''APIVersion defines the versioned schema of this representation of an object. - - Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.DeleteOptions#apiVersion - ''' - result = self._values.get("api_version") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def dry_run(self) -> typing.Optional[typing.List[builtins.str]]: - '''When present, indicates that modifications should not be persisted. - - An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.DeleteOptions#dryRun - ''' - result = self._values.get("dry_run") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def grace_period_seconds(self) -> typing.Optional[jsii.Number]: - '''The duration in seconds before the object should be deleted. - - Value must be non-negative integer. The value zero indicates delete immediately. If this value is nil, the default grace period for the specified type will be used. Defaults to a per object value if not specified. zero means delete immediately. - - :default: a per object value if not specified. zero means delete immediately. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.DeleteOptions#gracePeriodSeconds - ''' - result = self._values.get("grace_period_seconds") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def kind( - self, - ) -> typing.Optional["IoK8SApimachineryPkgApisMetaV1DeleteOptionsKind"]: - '''Kind is a string value representing the REST resource this object represents. - - Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.DeleteOptions#kind - ''' - result = self._values.get("kind") - return typing.cast(typing.Optional["IoK8SApimachineryPkgApisMetaV1DeleteOptionsKind"], result) - - @builtins.property - def orphan_dependents(self) -> typing.Optional[builtins.bool]: - '''Deprecated: please use the PropagationPolicy, this field will be deprecated in 1.7. Should the dependent objects be orphaned. If true/false, the "orphan" finalizer will be added to/removed from the object's finalizers list. Either this field or PropagationPolicy may be set, but not both. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.DeleteOptions#orphanDependents - ''' - result = self._values.get("orphan_dependents") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def preconditions(self) -> typing.Optional["Preconditions"]: - '''Must be fulfilled before a deletion is carried out. - - If not possible, a 409 Conflict status will be returned. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.DeleteOptions#preconditions - ''' - result = self._values.get("preconditions") - return typing.cast(typing.Optional["Preconditions"], result) - - @builtins.property - def propagation_policy(self) -> typing.Optional[builtins.str]: - '''Whether and how garbage collection will be performed. - - Either this field or OrphanDependents may be set, but not both. The default policy is decided by the existing finalizer set in the metadata.finalizers and the resource-specific default policy. Acceptable values are: 'Orphan' - orphan the dependents; 'Background' - allow the garbage collector to delete the dependents in the background; 'Foreground' - a cascading policy that deletes all dependents in the foreground. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.DeleteOptions#propagationPolicy - ''' - result = self._values.get("propagation_policy") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "DeleteOptions(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.DeploymentSpec", - jsii_struct_bases=[], - name_mapping={ - "selector": "selector", - "template": "template", - "min_ready_seconds": "minReadySeconds", - "paused": "paused", - "progress_deadline_seconds": "progressDeadlineSeconds", - "replicas": "replicas", - "revision_history_limit": "revisionHistoryLimit", - "strategy": "strategy", - }, -) -class DeploymentSpec: - def __init__( - self, - *, - selector: typing.Union["LabelSelector", typing.Dict[builtins.str, typing.Any]], - template: typing.Union["PodTemplateSpec", typing.Dict[builtins.str, typing.Any]], - min_ready_seconds: typing.Optional[jsii.Number] = None, - paused: typing.Optional[builtins.bool] = None, - progress_deadline_seconds: typing.Optional[jsii.Number] = None, - replicas: typing.Optional[jsii.Number] = None, - revision_history_limit: typing.Optional[jsii.Number] = None, - strategy: typing.Optional[typing.Union["DeploymentStrategy", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''DeploymentSpec is the specification of the desired behavior of the Deployment. - - :param selector: Label selector for pods. Existing ReplicaSets whose pods are selected by this will be the ones affected by this deployment. It must match the pod template's labels. - :param template: Template describes the pods that will be created. - :param min_ready_seconds: Minimum number of seconds for which a newly created pod should be ready without any of its container crashing, for it to be considered available. Defaults to 0 (pod will be considered available as soon as it is ready) Default: 0 (pod will be considered available as soon as it is ready) - :param paused: Indicates that the deployment is paused. - :param progress_deadline_seconds: The maximum time in seconds for a deployment to make progress before it is considered to be failed. The deployment controller will continue to process failed deployments and a condition with a ProgressDeadlineExceeded reason will be surfaced in the deployment status. Note that progress will not be estimated during the time a deployment is paused. Defaults to 600s. Default: 600s. - :param replicas: Number of desired pods. This is a pointer to distinguish between explicit zero and not specified. Defaults to 1. Default: 1. - :param revision_history_limit: The number of old ReplicaSets to retain to allow rollback. This is a pointer to distinguish between explicit zero and not specified. Defaults to 10. Default: 10. - :param strategy: The deployment strategy to use to replace existing pods with new ones. - - :schema: io.k8s.api.apps.v1.DeploymentSpec - ''' - if isinstance(selector, dict): - selector = LabelSelector(**selector) - if isinstance(template, dict): - template = PodTemplateSpec(**template) - if isinstance(strategy, dict): - strategy = DeploymentStrategy(**strategy) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__88d492f2893c840ec003d2ddba4caf15921d31465e62b8a4667d961a583e3504) - check_type(argname="argument selector", value=selector, expected_type=type_hints["selector"]) - check_type(argname="argument template", value=template, expected_type=type_hints["template"]) - check_type(argname="argument min_ready_seconds", value=min_ready_seconds, expected_type=type_hints["min_ready_seconds"]) - check_type(argname="argument paused", value=paused, expected_type=type_hints["paused"]) - check_type(argname="argument progress_deadline_seconds", value=progress_deadline_seconds, expected_type=type_hints["progress_deadline_seconds"]) - check_type(argname="argument replicas", value=replicas, expected_type=type_hints["replicas"]) - check_type(argname="argument revision_history_limit", value=revision_history_limit, expected_type=type_hints["revision_history_limit"]) - check_type(argname="argument strategy", value=strategy, expected_type=type_hints["strategy"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "selector": selector, - "template": template, - } - if min_ready_seconds is not None: - self._values["min_ready_seconds"] = min_ready_seconds - if paused is not None: - self._values["paused"] = paused - if progress_deadline_seconds is not None: - self._values["progress_deadline_seconds"] = progress_deadline_seconds - if replicas is not None: - self._values["replicas"] = replicas - if revision_history_limit is not None: - self._values["revision_history_limit"] = revision_history_limit - if strategy is not None: - self._values["strategy"] = strategy - - @builtins.property - def selector(self) -> "LabelSelector": - '''Label selector for pods. - - Existing ReplicaSets whose pods are selected by this will be the ones affected by this deployment. It must match the pod template's labels. - - :schema: io.k8s.api.apps.v1.DeploymentSpec#selector - ''' - result = self._values.get("selector") - assert result is not None, "Required property 'selector' is missing" - return typing.cast("LabelSelector", result) - - @builtins.property - def template(self) -> "PodTemplateSpec": - '''Template describes the pods that will be created. - - :schema: io.k8s.api.apps.v1.DeploymentSpec#template - ''' - result = self._values.get("template") - assert result is not None, "Required property 'template' is missing" - return typing.cast("PodTemplateSpec", result) - - @builtins.property - def min_ready_seconds(self) -> typing.Optional[jsii.Number]: - '''Minimum number of seconds for which a newly created pod should be ready without any of its container crashing, for it to be considered available. - - Defaults to 0 (pod will be considered available as soon as it is ready) - - :default: 0 (pod will be considered available as soon as it is ready) - - :schema: io.k8s.api.apps.v1.DeploymentSpec#minReadySeconds - ''' - result = self._values.get("min_ready_seconds") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def paused(self) -> typing.Optional[builtins.bool]: - '''Indicates that the deployment is paused. - - :schema: io.k8s.api.apps.v1.DeploymentSpec#paused - ''' - result = self._values.get("paused") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def progress_deadline_seconds(self) -> typing.Optional[jsii.Number]: - '''The maximum time in seconds for a deployment to make progress before it is considered to be failed. - - The deployment controller will continue to process failed deployments and a condition with a ProgressDeadlineExceeded reason will be surfaced in the deployment status. Note that progress will not be estimated during the time a deployment is paused. Defaults to 600s. - - :default: 600s. - - :schema: io.k8s.api.apps.v1.DeploymentSpec#progressDeadlineSeconds - ''' - result = self._values.get("progress_deadline_seconds") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def replicas(self) -> typing.Optional[jsii.Number]: - '''Number of desired pods. - - This is a pointer to distinguish between explicit zero and not specified. Defaults to 1. - - :default: 1. - - :schema: io.k8s.api.apps.v1.DeploymentSpec#replicas - ''' - result = self._values.get("replicas") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def revision_history_limit(self) -> typing.Optional[jsii.Number]: - '''The number of old ReplicaSets to retain to allow rollback. - - This is a pointer to distinguish between explicit zero and not specified. Defaults to 10. - - :default: 10. - - :schema: io.k8s.api.apps.v1.DeploymentSpec#revisionHistoryLimit - ''' - result = self._values.get("revision_history_limit") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def strategy(self) -> typing.Optional["DeploymentStrategy"]: - '''The deployment strategy to use to replace existing pods with new ones. - - :schema: io.k8s.api.apps.v1.DeploymentSpec#strategy - ''' - result = self._values.get("strategy") - return typing.cast(typing.Optional["DeploymentStrategy"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "DeploymentSpec(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.DeploymentStrategy", - jsii_struct_bases=[], - name_mapping={"rolling_update": "rollingUpdate", "type": "type"}, -) -class DeploymentStrategy: - def __init__( - self, - *, - rolling_update: typing.Optional[typing.Union["RollingUpdateDeployment", typing.Dict[builtins.str, typing.Any]]] = None, - type: typing.Optional[builtins.str] = None, - ) -> None: - '''DeploymentStrategy describes how to replace existing pods with new ones. - - :param rolling_update: Rolling update config params. Present only if DeploymentStrategyType = RollingUpdate. - :param type: Type of deployment. Can be "Recreate" or "RollingUpdate". Default is RollingUpdate. Default: RollingUpdate. - - :schema: io.k8s.api.apps.v1.DeploymentStrategy - ''' - if isinstance(rolling_update, dict): - rolling_update = RollingUpdateDeployment(**rolling_update) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__47c8ed86524662fa654ab55acc09523cd7f42475f5339eab3418ffa208e11b45) - check_type(argname="argument rolling_update", value=rolling_update, expected_type=type_hints["rolling_update"]) - check_type(argname="argument type", value=type, expected_type=type_hints["type"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if rolling_update is not None: - self._values["rolling_update"] = rolling_update - if type is not None: - self._values["type"] = type - - @builtins.property - def rolling_update(self) -> typing.Optional["RollingUpdateDeployment"]: - '''Rolling update config params. - - Present only if DeploymentStrategyType = RollingUpdate. - - :schema: io.k8s.api.apps.v1.DeploymentStrategy#rollingUpdate - ''' - result = self._values.get("rolling_update") - return typing.cast(typing.Optional["RollingUpdateDeployment"], result) - - @builtins.property - def type(self) -> typing.Optional[builtins.str]: - '''Type of deployment. - - Can be "Recreate" or "RollingUpdate". Default is RollingUpdate. - - :default: RollingUpdate. - - :schema: io.k8s.api.apps.v1.DeploymentStrategy#type - ''' - result = self._values.get("type") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "DeploymentStrategy(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.DownwardApiProjection", - jsii_struct_bases=[], - name_mapping={"items": "items"}, -) -class DownwardApiProjection: - def __init__( - self, - *, - items: typing.Optional[typing.Sequence[typing.Union["DownwardApiVolumeFile", typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''Represents downward API info for projecting into a projected volume. - - Note that this is identical to a downwardAPI volume source without the default mode. - - :param items: Items is a list of DownwardAPIVolume file. - - :schema: io.k8s.api.core.v1.DownwardAPIProjection - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__869e1c36b23a22ea11fcce61bba7f500c0b12d2d573aa9739a152c0099840760) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if items is not None: - self._values["items"] = items - - @builtins.property - def items(self) -> typing.Optional[typing.List["DownwardApiVolumeFile"]]: - '''Items is a list of DownwardAPIVolume file. - - :schema: io.k8s.api.core.v1.DownwardAPIProjection#items - ''' - result = self._values.get("items") - return typing.cast(typing.Optional[typing.List["DownwardApiVolumeFile"]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "DownwardApiProjection(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.DownwardApiVolumeFile", - jsii_struct_bases=[], - name_mapping={ - "path": "path", - "field_ref": "fieldRef", - "mode": "mode", - "resource_field_ref": "resourceFieldRef", - }, -) -class DownwardApiVolumeFile: - def __init__( - self, - *, - path: builtins.str, - field_ref: typing.Optional[typing.Union["ObjectFieldSelector", typing.Dict[builtins.str, typing.Any]]] = None, - mode: typing.Optional[jsii.Number] = None, - resource_field_ref: typing.Optional[typing.Union["ResourceFieldSelector", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''DownwardAPIVolumeFile represents information to create the file containing the pod field. - - :param path: Required: Path is the relative path name of the file to be created. Must not be absolute or contain the '..' path. Must be utf-8 encoded. The first item of the relative path must not start with '..' - :param field_ref: Required: Selects a field of the pod: only annotations, labels, name and namespace are supported. - :param mode: Optional: mode bits used to set permissions on this file, must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set. - :param resource_field_ref: Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported. - - :schema: io.k8s.api.core.v1.DownwardAPIVolumeFile - ''' - if isinstance(field_ref, dict): - field_ref = ObjectFieldSelector(**field_ref) - if isinstance(resource_field_ref, dict): - resource_field_ref = ResourceFieldSelector(**resource_field_ref) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__101db0695abfdddd40bd62385a630a47df841ee1a6f24407608f8fe8b6ff069d) - check_type(argname="argument path", value=path, expected_type=type_hints["path"]) - check_type(argname="argument field_ref", value=field_ref, expected_type=type_hints["field_ref"]) - check_type(argname="argument mode", value=mode, expected_type=type_hints["mode"]) - check_type(argname="argument resource_field_ref", value=resource_field_ref, expected_type=type_hints["resource_field_ref"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "path": path, - } - if field_ref is not None: - self._values["field_ref"] = field_ref - if mode is not None: - self._values["mode"] = mode - if resource_field_ref is not None: - self._values["resource_field_ref"] = resource_field_ref - - @builtins.property - def path(self) -> builtins.str: - '''Required: Path is the relative path name of the file to be created. - - Must not be absolute or contain the '..' path. Must be utf-8 encoded. The first item of the relative path must not start with '..' - - :schema: io.k8s.api.core.v1.DownwardAPIVolumeFile#path - ''' - result = self._values.get("path") - assert result is not None, "Required property 'path' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def field_ref(self) -> typing.Optional["ObjectFieldSelector"]: - '''Required: Selects a field of the pod: only annotations, labels, name and namespace are supported. - - :schema: io.k8s.api.core.v1.DownwardAPIVolumeFile#fieldRef - ''' - result = self._values.get("field_ref") - return typing.cast(typing.Optional["ObjectFieldSelector"], result) - - @builtins.property - def mode(self) -> typing.Optional[jsii.Number]: - '''Optional: mode bits used to set permissions on this file, must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set. - - :schema: io.k8s.api.core.v1.DownwardAPIVolumeFile#mode - ''' - result = self._values.get("mode") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def resource_field_ref(self) -> typing.Optional["ResourceFieldSelector"]: - '''Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported. - - :schema: io.k8s.api.core.v1.DownwardAPIVolumeFile#resourceFieldRef - ''' - result = self._values.get("resource_field_ref") - return typing.cast(typing.Optional["ResourceFieldSelector"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "DownwardApiVolumeFile(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.DownwardApiVolumeSource", - jsii_struct_bases=[], - name_mapping={"default_mode": "defaultMode", "items": "items"}, -) -class DownwardApiVolumeSource: - def __init__( - self, - *, - default_mode: typing.Optional[jsii.Number] = None, - items: typing.Optional[typing.Sequence[typing.Union[DownwardApiVolumeFile, typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''DownwardAPIVolumeSource represents a volume containing downward API info. - - Downward API volumes support ownership management and SELinux relabeling. - - :param default_mode: Optional: mode bits to use on created files by default. Must be a Optional: mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set. Default: 644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set. - :param items: Items is a list of downward API volume file. - - :schema: io.k8s.api.core.v1.DownwardAPIVolumeSource - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__d43c40d536e8ef2ac9d664987c3d40ea8d2b2a7183453e3267caf21a4f0e109a) - check_type(argname="argument default_mode", value=default_mode, expected_type=type_hints["default_mode"]) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if default_mode is not None: - self._values["default_mode"] = default_mode - if items is not None: - self._values["items"] = items - - @builtins.property - def default_mode(self) -> typing.Optional[jsii.Number]: - '''Optional: mode bits to use on created files by default. - - Must be a Optional: mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set. - - :default: 644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set. - - :schema: io.k8s.api.core.v1.DownwardAPIVolumeSource#defaultMode - ''' - result = self._values.get("default_mode") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def items(self) -> typing.Optional[typing.List[DownwardApiVolumeFile]]: - '''Items is a list of downward API volume file. - - :schema: io.k8s.api.core.v1.DownwardAPIVolumeSource#items - ''' - result = self._values.get("items") - return typing.cast(typing.Optional[typing.List[DownwardApiVolumeFile]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "DownwardApiVolumeSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.EmptyDirVolumeSource", - jsii_struct_bases=[], - name_mapping={"medium": "medium", "size_limit": "sizeLimit"}, -) -class EmptyDirVolumeSource: - def __init__( - self, - *, - medium: typing.Optional[builtins.str] = None, - size_limit: typing.Optional["Quantity"] = None, - ) -> None: - '''Represents an empty directory for a pod. - - Empty directory volumes support ownership management and SELinux relabeling. - - :param medium: medium represents what type of storage medium should back this directory. The default is "" which means to use the node's default medium. Must be an empty string (default) or Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir - :param size_limit: sizeLimit is the total amount of local storage required for this EmptyDir volume. The size limit is also applicable for memory medium. The maximum usage on memory medium EmptyDir would be the minimum value between the SizeLimit specified here and the sum of memory limits of all containers in a pod. The default is nil which means that the limit is undefined. More info: http://kubernetes.io/docs/user-guide/volumes#emptydir - - :schema: io.k8s.api.core.v1.EmptyDirVolumeSource - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__51336821e156a17acb25064d05a943dee51ed6d9fede28f0496b90a126cbde50) - check_type(argname="argument medium", value=medium, expected_type=type_hints["medium"]) - check_type(argname="argument size_limit", value=size_limit, expected_type=type_hints["size_limit"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if medium is not None: - self._values["medium"] = medium - if size_limit is not None: - self._values["size_limit"] = size_limit - - @builtins.property - def medium(self) -> typing.Optional[builtins.str]: - '''medium represents what type of storage medium should back this directory. - - The default is "" which means to use the node's default medium. Must be an empty string (default) or Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir - - :schema: io.k8s.api.core.v1.EmptyDirVolumeSource#medium - ''' - result = self._values.get("medium") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def size_limit(self) -> typing.Optional["Quantity"]: - '''sizeLimit is the total amount of local storage required for this EmptyDir volume. - - The size limit is also applicable for memory medium. The maximum usage on memory medium EmptyDir would be the minimum value between the SizeLimit specified here and the sum of memory limits of all containers in a pod. The default is nil which means that the limit is undefined. More info: http://kubernetes.io/docs/user-guide/volumes#emptydir - - :schema: io.k8s.api.core.v1.EmptyDirVolumeSource#sizeLimit - ''' - result = self._values.get("size_limit") - return typing.cast(typing.Optional["Quantity"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "EmptyDirVolumeSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.Endpoint", - jsii_struct_bases=[], - name_mapping={ - "addresses": "addresses", - "conditions": "conditions", - "deprecated_topology": "deprecatedTopology", - "hints": "hints", - "hostname": "hostname", - "node_name": "nodeName", - "target_ref": "targetRef", - "zone": "zone", - }, -) -class Endpoint: - def __init__( - self, - *, - addresses: typing.Sequence[builtins.str], - conditions: typing.Optional[typing.Union["EndpointConditions", typing.Dict[builtins.str, typing.Any]]] = None, - deprecated_topology: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - hints: typing.Optional[typing.Union["EndpointHints", typing.Dict[builtins.str, typing.Any]]] = None, - hostname: typing.Optional[builtins.str] = None, - node_name: typing.Optional[builtins.str] = None, - target_ref: typing.Optional[typing.Union["ObjectReference", typing.Dict[builtins.str, typing.Any]]] = None, - zone: typing.Optional[builtins.str] = None, - ) -> None: - '''Endpoint represents a single logical "backend" implementing a service. - - :param addresses: addresses of this endpoint. The contents of this field are interpreted according to the corresponding EndpointSlice addressType field. Consumers must handle different types of addresses in the context of their own capabilities. This must contain at least one address but no more than 100. These are all assumed to be fungible and clients may choose to only use the first element. Refer to: https://issue.k8s.io/106267 - :param conditions: conditions contains information about the current status of the endpoint. - :param deprecated_topology: deprecatedTopology contains topology information part of the v1beta1 API. This field is deprecated, and will be removed when the v1beta1 API is removed (no sooner than kubernetes v1.24). While this field can hold values, it is not writable through the v1 API, and any attempts to write to it will be silently ignored. Topology information can be found in the zone and nodeName fields instead. - :param hints: hints contains information associated with how an endpoint should be consumed. - :param hostname: hostname of this endpoint. This field may be used by consumers of endpoints to distinguish endpoints from each other (e.g. in DNS names). Multiple endpoints which use the same hostname should be considered fungible (e.g. multiple A values in DNS). Must be lowercase and pass DNS Label (RFC 1123) validation. - :param node_name: nodeName represents the name of the Node hosting this endpoint. This can be used to determine endpoints local to a Node. - :param target_ref: targetRef is a reference to a Kubernetes object that represents this endpoint. - :param zone: zone is the name of the Zone this endpoint exists in. - - :schema: io.k8s.api.discovery.v1.Endpoint - ''' - if isinstance(conditions, dict): - conditions = EndpointConditions(**conditions) - if isinstance(hints, dict): - hints = EndpointHints(**hints) - if isinstance(target_ref, dict): - target_ref = ObjectReference(**target_ref) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__aecf0f91e9c72760558c73c60babfa2b9ec1400a6ace4c1cad4cdb2ce4cf4276) - check_type(argname="argument addresses", value=addresses, expected_type=type_hints["addresses"]) - check_type(argname="argument conditions", value=conditions, expected_type=type_hints["conditions"]) - check_type(argname="argument deprecated_topology", value=deprecated_topology, expected_type=type_hints["deprecated_topology"]) - check_type(argname="argument hints", value=hints, expected_type=type_hints["hints"]) - check_type(argname="argument hostname", value=hostname, expected_type=type_hints["hostname"]) - check_type(argname="argument node_name", value=node_name, expected_type=type_hints["node_name"]) - check_type(argname="argument target_ref", value=target_ref, expected_type=type_hints["target_ref"]) - check_type(argname="argument zone", value=zone, expected_type=type_hints["zone"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "addresses": addresses, - } - if conditions is not None: - self._values["conditions"] = conditions - if deprecated_topology is not None: - self._values["deprecated_topology"] = deprecated_topology - if hints is not None: - self._values["hints"] = hints - if hostname is not None: - self._values["hostname"] = hostname - if node_name is not None: - self._values["node_name"] = node_name - if target_ref is not None: - self._values["target_ref"] = target_ref - if zone is not None: - self._values["zone"] = zone - - @builtins.property - def addresses(self) -> typing.List[builtins.str]: - '''addresses of this endpoint. - - The contents of this field are interpreted according to the corresponding EndpointSlice addressType field. Consumers must handle different types of addresses in the context of their own capabilities. This must contain at least one address but no more than 100. These are all assumed to be fungible and clients may choose to only use the first element. Refer to: https://issue.k8s.io/106267 - - :schema: io.k8s.api.discovery.v1.Endpoint#addresses - ''' - result = self._values.get("addresses") - assert result is not None, "Required property 'addresses' is missing" - return typing.cast(typing.List[builtins.str], result) - - @builtins.property - def conditions(self) -> typing.Optional["EndpointConditions"]: - '''conditions contains information about the current status of the endpoint. - - :schema: io.k8s.api.discovery.v1.Endpoint#conditions - ''' - result = self._values.get("conditions") - return typing.cast(typing.Optional["EndpointConditions"], result) - - @builtins.property - def deprecated_topology( - self, - ) -> typing.Optional[typing.Mapping[builtins.str, builtins.str]]: - '''deprecatedTopology contains topology information part of the v1beta1 API. - - This field is deprecated, and will be removed when the v1beta1 API is removed (no sooner than kubernetes v1.24). While this field can hold values, it is not writable through the v1 API, and any attempts to write to it will be silently ignored. Topology information can be found in the zone and nodeName fields instead. - - :schema: io.k8s.api.discovery.v1.Endpoint#deprecatedTopology - ''' - result = self._values.get("deprecated_topology") - return typing.cast(typing.Optional[typing.Mapping[builtins.str, builtins.str]], result) - - @builtins.property - def hints(self) -> typing.Optional["EndpointHints"]: - '''hints contains information associated with how an endpoint should be consumed. - - :schema: io.k8s.api.discovery.v1.Endpoint#hints - ''' - result = self._values.get("hints") - return typing.cast(typing.Optional["EndpointHints"], result) - - @builtins.property - def hostname(self) -> typing.Optional[builtins.str]: - '''hostname of this endpoint. - - This field may be used by consumers of endpoints to distinguish endpoints from each other (e.g. in DNS names). Multiple endpoints which use the same hostname should be considered fungible (e.g. multiple A values in DNS). Must be lowercase and pass DNS Label (RFC 1123) validation. - - :schema: io.k8s.api.discovery.v1.Endpoint#hostname - ''' - result = self._values.get("hostname") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def node_name(self) -> typing.Optional[builtins.str]: - '''nodeName represents the name of the Node hosting this endpoint. - - This can be used to determine endpoints local to a Node. - - :schema: io.k8s.api.discovery.v1.Endpoint#nodeName - ''' - result = self._values.get("node_name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def target_ref(self) -> typing.Optional["ObjectReference"]: - '''targetRef is a reference to a Kubernetes object that represents this endpoint. - - :schema: io.k8s.api.discovery.v1.Endpoint#targetRef - ''' - result = self._values.get("target_ref") - return typing.cast(typing.Optional["ObjectReference"], result) - - @builtins.property - def zone(self) -> typing.Optional[builtins.str]: - '''zone is the name of the Zone this endpoint exists in. - - :schema: io.k8s.api.discovery.v1.Endpoint#zone - ''' - result = self._values.get("zone") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "Endpoint(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.EndpointAddress", - jsii_struct_bases=[], - name_mapping={ - "ip": "ip", - "hostname": "hostname", - "node_name": "nodeName", - "target_ref": "targetRef", - }, -) -class EndpointAddress: - def __init__( - self, - *, - ip: builtins.str, - hostname: typing.Optional[builtins.str] = None, - node_name: typing.Optional[builtins.str] = None, - target_ref: typing.Optional[typing.Union["ObjectReference", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''EndpointAddress is a tuple that describes single IP address. - - :param ip: The IP of this endpoint. May not be loopback (127.0.0.0/8), link-local (169.254.0.0/16), or link-local multicast ((224.0.0.0/24). IPv6 is also accepted but not fully supported on all platforms. Also, certain kubernetes components, like kube-proxy, are not IPv6 ready. - :param hostname: The Hostname of this endpoint. - :param node_name: Optional: Node hosting this endpoint. This can be used to determine endpoints local to a node. - :param target_ref: Reference to object providing the endpoint. - - :schema: io.k8s.api.core.v1.EndpointAddress - ''' - if isinstance(target_ref, dict): - target_ref = ObjectReference(**target_ref) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__970f09567748e206afbb46c0fa29177fb5967712f3943c875ccea8dfd5d1b3ce) - check_type(argname="argument ip", value=ip, expected_type=type_hints["ip"]) - check_type(argname="argument hostname", value=hostname, expected_type=type_hints["hostname"]) - check_type(argname="argument node_name", value=node_name, expected_type=type_hints["node_name"]) - check_type(argname="argument target_ref", value=target_ref, expected_type=type_hints["target_ref"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "ip": ip, - } - if hostname is not None: - self._values["hostname"] = hostname - if node_name is not None: - self._values["node_name"] = node_name - if target_ref is not None: - self._values["target_ref"] = target_ref - - @builtins.property - def ip(self) -> builtins.str: - '''The IP of this endpoint. - - May not be loopback (127.0.0.0/8), link-local (169.254.0.0/16), or link-local multicast ((224.0.0.0/24). IPv6 is also accepted but not fully supported on all platforms. Also, certain kubernetes components, like kube-proxy, are not IPv6 ready. - - :schema: io.k8s.api.core.v1.EndpointAddress#ip - ''' - result = self._values.get("ip") - assert result is not None, "Required property 'ip' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def hostname(self) -> typing.Optional[builtins.str]: - '''The Hostname of this endpoint. - - :schema: io.k8s.api.core.v1.EndpointAddress#hostname - ''' - result = self._values.get("hostname") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def node_name(self) -> typing.Optional[builtins.str]: - '''Optional: Node hosting this endpoint. - - This can be used to determine endpoints local to a node. - - :schema: io.k8s.api.core.v1.EndpointAddress#nodeName - ''' - result = self._values.get("node_name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def target_ref(self) -> typing.Optional["ObjectReference"]: - '''Reference to object providing the endpoint. - - :schema: io.k8s.api.core.v1.EndpointAddress#targetRef - ''' - result = self._values.get("target_ref") - return typing.cast(typing.Optional["ObjectReference"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "EndpointAddress(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.EndpointConditions", - jsii_struct_bases=[], - name_mapping={ - "ready": "ready", - "serving": "serving", - "terminating": "terminating", - }, -) -class EndpointConditions: - def __init__( - self, - *, - ready: typing.Optional[builtins.bool] = None, - serving: typing.Optional[builtins.bool] = None, - terminating: typing.Optional[builtins.bool] = None, - ) -> None: - '''EndpointConditions represents the current condition of an endpoint. - - :param ready: ready indicates that this endpoint is prepared to receive traffic, according to whatever system is managing the endpoint. A nil value indicates an unknown state. In most cases consumers should interpret this unknown state as ready. For compatibility reasons, ready should never be "true" for terminating endpoints. - :param serving: serving is identical to ready except that it is set regardless of the terminating state of endpoints. This condition should be set to true for a ready endpoint that is terminating. If nil, consumers should defer to the ready condition. - :param terminating: terminating indicates that this endpoint is terminating. A nil value indicates an unknown state. Consumers should interpret this unknown state to mean that the endpoint is not terminating. - - :schema: io.k8s.api.discovery.v1.EndpointConditions - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__b2b5238272f9d14831397973a28343d30df4184341889339940e2808d1357461) - check_type(argname="argument ready", value=ready, expected_type=type_hints["ready"]) - check_type(argname="argument serving", value=serving, expected_type=type_hints["serving"]) - check_type(argname="argument terminating", value=terminating, expected_type=type_hints["terminating"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if ready is not None: - self._values["ready"] = ready - if serving is not None: - self._values["serving"] = serving - if terminating is not None: - self._values["terminating"] = terminating - - @builtins.property - def ready(self) -> typing.Optional[builtins.bool]: - '''ready indicates that this endpoint is prepared to receive traffic, according to whatever system is managing the endpoint. - - A nil value indicates an unknown state. In most cases consumers should interpret this unknown state as ready. For compatibility reasons, ready should never be "true" for terminating endpoints. - - :schema: io.k8s.api.discovery.v1.EndpointConditions#ready - ''' - result = self._values.get("ready") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def serving(self) -> typing.Optional[builtins.bool]: - '''serving is identical to ready except that it is set regardless of the terminating state of endpoints. - - This condition should be set to true for a ready endpoint that is terminating. If nil, consumers should defer to the ready condition. - - :schema: io.k8s.api.discovery.v1.EndpointConditions#serving - ''' - result = self._values.get("serving") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def terminating(self) -> typing.Optional[builtins.bool]: - '''terminating indicates that this endpoint is terminating. - - A nil value indicates an unknown state. Consumers should interpret this unknown state to mean that the endpoint is not terminating. - - :schema: io.k8s.api.discovery.v1.EndpointConditions#terminating - ''' - result = self._values.get("terminating") - return typing.cast(typing.Optional[builtins.bool], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "EndpointConditions(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.EndpointHints", - jsii_struct_bases=[], - name_mapping={"for_zones": "forZones"}, -) -class EndpointHints: - def __init__( - self, - *, - for_zones: typing.Optional[typing.Sequence[typing.Union["ForZone", typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''EndpointHints provides hints describing how an endpoint should be consumed. - - :param for_zones: forZones indicates the zone(s) this endpoint should be consumed by to enable topology aware routing. - - :schema: io.k8s.api.discovery.v1.EndpointHints - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__72b3d0ad7203c24d6795afe4a3e837823411fa92c071099c508160c704770992) - check_type(argname="argument for_zones", value=for_zones, expected_type=type_hints["for_zones"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if for_zones is not None: - self._values["for_zones"] = for_zones - - @builtins.property - def for_zones(self) -> typing.Optional[typing.List["ForZone"]]: - '''forZones indicates the zone(s) this endpoint should be consumed by to enable topology aware routing. - - :schema: io.k8s.api.discovery.v1.EndpointHints#forZones - ''' - result = self._values.get("for_zones") - return typing.cast(typing.Optional[typing.List["ForZone"]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "EndpointHints(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.EndpointPort", - jsii_struct_bases=[], - name_mapping={ - "port": "port", - "app_protocol": "appProtocol", - "name": "name", - "protocol": "protocol", - }, -) -class EndpointPort: - def __init__( - self, - *, - port: jsii.Number, - app_protocol: typing.Optional[builtins.str] = None, - name: typing.Optional[builtins.str] = None, - protocol: typing.Optional[builtins.str] = None, - ) -> None: - '''EndpointPort is a tuple that describes a single port. - - :param port: The port number of the endpoint. - :param app_protocol: The application protocol for this port. This field follows standard Kubernetes label syntax. Un-prefixed names are reserved for IANA standard service names (as per RFC-6335 and https://www.iana.org/assignments/service-names). Non-standard protocols should use prefixed names such as mycompany.com/my-custom-protocol. - :param name: The name of this port. This must match the 'name' field in the corresponding ServicePort. Must be a DNS_LABEL. Optional only if one port is defined. - :param protocol: The IP protocol for this port. Must be UDP, TCP, or SCTP. Default is TCP. Default: TCP. - - :schema: io.k8s.api.core.v1.EndpointPort - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__198ff7c8fddac2085d2564d42a0d2f8327272caf700986100e27c5038c106c79) - check_type(argname="argument port", value=port, expected_type=type_hints["port"]) - check_type(argname="argument app_protocol", value=app_protocol, expected_type=type_hints["app_protocol"]) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument protocol", value=protocol, expected_type=type_hints["protocol"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "port": port, - } - if app_protocol is not None: - self._values["app_protocol"] = app_protocol - if name is not None: - self._values["name"] = name - if protocol is not None: - self._values["protocol"] = protocol - - @builtins.property - def port(self) -> jsii.Number: - '''The port number of the endpoint. - - :schema: io.k8s.api.core.v1.EndpointPort#port - ''' - result = self._values.get("port") - assert result is not None, "Required property 'port' is missing" - return typing.cast(jsii.Number, result) - - @builtins.property - def app_protocol(self) -> typing.Optional[builtins.str]: - '''The application protocol for this port. - - This field follows standard Kubernetes label syntax. Un-prefixed names are reserved for IANA standard service names (as per RFC-6335 and https://www.iana.org/assignments/service-names). Non-standard protocols should use prefixed names such as mycompany.com/my-custom-protocol. - - :schema: io.k8s.api.core.v1.EndpointPort#appProtocol - ''' - result = self._values.get("app_protocol") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def name(self) -> typing.Optional[builtins.str]: - '''The name of this port. - - This must match the 'name' field in the corresponding ServicePort. Must be a DNS_LABEL. Optional only if one port is defined. - - :schema: io.k8s.api.core.v1.EndpointPort#name - ''' - result = self._values.get("name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def protocol(self) -> typing.Optional[builtins.str]: - '''The IP protocol for this port. - - Must be UDP, TCP, or SCTP. Default is TCP. - - :default: TCP. - - :schema: io.k8s.api.core.v1.EndpointPort#protocol - ''' - result = self._values.get("protocol") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "EndpointPort(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.EndpointSubset", - jsii_struct_bases=[], - name_mapping={ - "addresses": "addresses", - "not_ready_addresses": "notReadyAddresses", - "ports": "ports", - }, -) -class EndpointSubset: - def __init__( - self, - *, - addresses: typing.Optional[typing.Sequence[typing.Union[EndpointAddress, typing.Dict[builtins.str, typing.Any]]]] = None, - not_ready_addresses: typing.Optional[typing.Sequence[typing.Union[EndpointAddress, typing.Dict[builtins.str, typing.Any]]]] = None, - ports: typing.Optional[typing.Sequence[typing.Union[EndpointPort, typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''EndpointSubset is a group of addresses with a common set of ports. - - The expanded set of endpoints is the Cartesian product of Addresses x Ports. For example, given: - - { - Addresses: [{"ip": "10.10.1.1"}, {"ip": "10.10.2.2"}], - Ports: [{"name": "a", "port": 8675}, {"name": "b", "port": 309}] - } - - The resulting set of endpoints can be viewed as: - - a: [ 10.10.1.1:8675, 10.10.2.2:8675 ], - b: [ 10.10.1.1:309, 10.10.2.2:309 ] - - :param addresses: IP addresses which offer the related ports that are marked as ready. These endpoints should be considered safe for load balancers and clients to utilize. - :param not_ready_addresses: IP addresses which offer the related ports but are not currently marked as ready because they have not yet finished starting, have recently failed a readiness check, or have recently failed a liveness check. - :param ports: Port numbers available on the related IP addresses. - - :schema: io.k8s.api.core.v1.EndpointSubset - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__f3121032b6cb224e5e34b7639c8027fadb2a705523967f72dda8e1bb2dc1c8ab) - check_type(argname="argument addresses", value=addresses, expected_type=type_hints["addresses"]) - check_type(argname="argument not_ready_addresses", value=not_ready_addresses, expected_type=type_hints["not_ready_addresses"]) - check_type(argname="argument ports", value=ports, expected_type=type_hints["ports"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if addresses is not None: - self._values["addresses"] = addresses - if not_ready_addresses is not None: - self._values["not_ready_addresses"] = not_ready_addresses - if ports is not None: - self._values["ports"] = ports - - @builtins.property - def addresses(self) -> typing.Optional[typing.List[EndpointAddress]]: - '''IP addresses which offer the related ports that are marked as ready. - - These endpoints should be considered safe for load balancers and clients to utilize. - - :schema: io.k8s.api.core.v1.EndpointSubset#addresses - ''' - result = self._values.get("addresses") - return typing.cast(typing.Optional[typing.List[EndpointAddress]], result) - - @builtins.property - def not_ready_addresses(self) -> typing.Optional[typing.List[EndpointAddress]]: - '''IP addresses which offer the related ports but are not currently marked as ready because they have not yet finished starting, have recently failed a readiness check, or have recently failed a liveness check. - - :schema: io.k8s.api.core.v1.EndpointSubset#notReadyAddresses - ''' - result = self._values.get("not_ready_addresses") - return typing.cast(typing.Optional[typing.List[EndpointAddress]], result) - - @builtins.property - def ports(self) -> typing.Optional[typing.List[EndpointPort]]: - '''Port numbers available on the related IP addresses. - - :schema: io.k8s.api.core.v1.EndpointSubset#ports - ''' - result = self._values.get("ports") - return typing.cast(typing.Optional[typing.List[EndpointPort]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "EndpointSubset(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.EnvFromSource", - jsii_struct_bases=[], - name_mapping={ - "config_map_ref": "configMapRef", - "prefix": "prefix", - "secret_ref": "secretRef", - }, -) -class EnvFromSource: - def __init__( - self, - *, - config_map_ref: typing.Optional[typing.Union[ConfigMapEnvSource, typing.Dict[builtins.str, typing.Any]]] = None, - prefix: typing.Optional[builtins.str] = None, - secret_ref: typing.Optional[typing.Union["SecretEnvSource", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''EnvFromSource represents the source of a set of ConfigMaps. - - :param config_map_ref: The ConfigMap to select from. - :param prefix: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER. - :param secret_ref: The Secret to select from. - - :schema: io.k8s.api.core.v1.EnvFromSource - ''' - if isinstance(config_map_ref, dict): - config_map_ref = ConfigMapEnvSource(**config_map_ref) - if isinstance(secret_ref, dict): - secret_ref = SecretEnvSource(**secret_ref) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__1e745a3a12e83796a4c7e9f2246565d74fe3f6a1041987cbb7dd3435aaba3180) - check_type(argname="argument config_map_ref", value=config_map_ref, expected_type=type_hints["config_map_ref"]) - check_type(argname="argument prefix", value=prefix, expected_type=type_hints["prefix"]) - check_type(argname="argument secret_ref", value=secret_ref, expected_type=type_hints["secret_ref"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if config_map_ref is not None: - self._values["config_map_ref"] = config_map_ref - if prefix is not None: - self._values["prefix"] = prefix - if secret_ref is not None: - self._values["secret_ref"] = secret_ref - - @builtins.property - def config_map_ref(self) -> typing.Optional[ConfigMapEnvSource]: - '''The ConfigMap to select from. - - :schema: io.k8s.api.core.v1.EnvFromSource#configMapRef - ''' - result = self._values.get("config_map_ref") - return typing.cast(typing.Optional[ConfigMapEnvSource], result) - - @builtins.property - def prefix(self) -> typing.Optional[builtins.str]: - '''An optional identifier to prepend to each key in the ConfigMap. - - Must be a C_IDENTIFIER. - - :schema: io.k8s.api.core.v1.EnvFromSource#prefix - ''' - result = self._values.get("prefix") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def secret_ref(self) -> typing.Optional["SecretEnvSource"]: - '''The Secret to select from. - - :schema: io.k8s.api.core.v1.EnvFromSource#secretRef - ''' - result = self._values.get("secret_ref") - return typing.cast(typing.Optional["SecretEnvSource"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "EnvFromSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.EnvVar", - jsii_struct_bases=[], - name_mapping={"name": "name", "value": "value", "value_from": "valueFrom"}, -) -class EnvVar: - def __init__( - self, - *, - name: builtins.str, - value: typing.Optional[builtins.str] = None, - value_from: typing.Optional[typing.Union["EnvVarSource", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''EnvVar represents an environment variable present in a Container. - - :param name: Name of the environment variable. Must be a C_IDENTIFIER. - :param value: Variable references $(VAR_NAME) are expanded using the previously defined environment variables in the container and any service environment variables. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless of whether the variable exists or not. Defaults to "". Default: . - :param value_from: Source for the environment variable's value. Cannot be used if value is not empty. - - :schema: io.k8s.api.core.v1.EnvVar - ''' - if isinstance(value_from, dict): - value_from = EnvVarSource(**value_from) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__7ff167fe39eff04347196f0b38e85c859cfdf9180d26b47b3ccc003411311c3a) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument value", value=value, expected_type=type_hints["value"]) - check_type(argname="argument value_from", value=value_from, expected_type=type_hints["value_from"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "name": name, - } - if value is not None: - self._values["value"] = value - if value_from is not None: - self._values["value_from"] = value_from - - @builtins.property - def name(self) -> builtins.str: - '''Name of the environment variable. - - Must be a C_IDENTIFIER. - - :schema: io.k8s.api.core.v1.EnvVar#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def value(self) -> typing.Optional[builtins.str]: - '''Variable references $(VAR_NAME) are expanded using the previously defined environment variables in the container and any service environment variables. - - If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless of whether the variable exists or not. Defaults to "". - - :default: . - - :schema: io.k8s.api.core.v1.EnvVar#value - ''' - result = self._values.get("value") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def value_from(self) -> typing.Optional["EnvVarSource"]: - '''Source for the environment variable's value. - - Cannot be used if value is not empty. - - :schema: io.k8s.api.core.v1.EnvVar#valueFrom - ''' - result = self._values.get("value_from") - return typing.cast(typing.Optional["EnvVarSource"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "EnvVar(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.EnvVarSource", - jsii_struct_bases=[], - name_mapping={ - "config_map_key_ref": "configMapKeyRef", - "field_ref": "fieldRef", - "resource_field_ref": "resourceFieldRef", - "secret_key_ref": "secretKeyRef", - }, -) -class EnvVarSource: - def __init__( - self, - *, - config_map_key_ref: typing.Optional[typing.Union[ConfigMapKeySelector, typing.Dict[builtins.str, typing.Any]]] = None, - field_ref: typing.Optional[typing.Union["ObjectFieldSelector", typing.Dict[builtins.str, typing.Any]]] = None, - resource_field_ref: typing.Optional[typing.Union["ResourceFieldSelector", typing.Dict[builtins.str, typing.Any]]] = None, - secret_key_ref: typing.Optional[typing.Union["SecretKeySelector", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''EnvVarSource represents a source for the value of an EnvVar. - - :param config_map_key_ref: Selects a key of a ConfigMap. - :param field_ref: Selects a field of the pod: supports metadata.name, metadata.namespace, ``metadata.labels['']``, ``metadata.annotations['']``, spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. - :param resource_field_ref: Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. - :param secret_key_ref: Selects a key of a secret in the pod's namespace. - - :schema: io.k8s.api.core.v1.EnvVarSource - ''' - if isinstance(config_map_key_ref, dict): - config_map_key_ref = ConfigMapKeySelector(**config_map_key_ref) - if isinstance(field_ref, dict): - field_ref = ObjectFieldSelector(**field_ref) - if isinstance(resource_field_ref, dict): - resource_field_ref = ResourceFieldSelector(**resource_field_ref) - if isinstance(secret_key_ref, dict): - secret_key_ref = SecretKeySelector(**secret_key_ref) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__8200f0b06b85522180fa691bfce5b26210b45cbf9374d77ea5dd65cbbf09b32a) - check_type(argname="argument config_map_key_ref", value=config_map_key_ref, expected_type=type_hints["config_map_key_ref"]) - check_type(argname="argument field_ref", value=field_ref, expected_type=type_hints["field_ref"]) - check_type(argname="argument resource_field_ref", value=resource_field_ref, expected_type=type_hints["resource_field_ref"]) - check_type(argname="argument secret_key_ref", value=secret_key_ref, expected_type=type_hints["secret_key_ref"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if config_map_key_ref is not None: - self._values["config_map_key_ref"] = config_map_key_ref - if field_ref is not None: - self._values["field_ref"] = field_ref - if resource_field_ref is not None: - self._values["resource_field_ref"] = resource_field_ref - if secret_key_ref is not None: - self._values["secret_key_ref"] = secret_key_ref - - @builtins.property - def config_map_key_ref(self) -> typing.Optional[ConfigMapKeySelector]: - '''Selects a key of a ConfigMap. - - :schema: io.k8s.api.core.v1.EnvVarSource#configMapKeyRef - ''' - result = self._values.get("config_map_key_ref") - return typing.cast(typing.Optional[ConfigMapKeySelector], result) - - @builtins.property - def field_ref(self) -> typing.Optional["ObjectFieldSelector"]: - '''Selects a field of the pod: supports metadata.name, metadata.namespace, ``metadata.labels['']``, ``metadata.annotations['']``, spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. - - :schema: io.k8s.api.core.v1.EnvVarSource#fieldRef - ''' - result = self._values.get("field_ref") - return typing.cast(typing.Optional["ObjectFieldSelector"], result) - - @builtins.property - def resource_field_ref(self) -> typing.Optional["ResourceFieldSelector"]: - '''Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. - - :schema: io.k8s.api.core.v1.EnvVarSource#resourceFieldRef - ''' - result = self._values.get("resource_field_ref") - return typing.cast(typing.Optional["ResourceFieldSelector"], result) - - @builtins.property - def secret_key_ref(self) -> typing.Optional["SecretKeySelector"]: - '''Selects a key of a secret in the pod's namespace. - - :schema: io.k8s.api.core.v1.EnvVarSource#secretKeyRef - ''' - result = self._values.get("secret_key_ref") - return typing.cast(typing.Optional["SecretKeySelector"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "EnvVarSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.EphemeralContainer", - jsii_struct_bases=[], - name_mapping={ - "name": "name", - "args": "args", - "command": "command", - "env": "env", - "env_from": "envFrom", - "image": "image", - "image_pull_policy": "imagePullPolicy", - "lifecycle": "lifecycle", - "liveness_probe": "livenessProbe", - "ports": "ports", - "readiness_probe": "readinessProbe", - "resources": "resources", - "security_context": "securityContext", - "startup_probe": "startupProbe", - "stdin": "stdin", - "stdin_once": "stdinOnce", - "target_container_name": "targetContainerName", - "termination_message_path": "terminationMessagePath", - "termination_message_policy": "terminationMessagePolicy", - "tty": "tty", - "volume_devices": "volumeDevices", - "volume_mounts": "volumeMounts", - "working_dir": "workingDir", - }, -) -class EphemeralContainer: - def __init__( - self, - *, - name: builtins.str, - args: typing.Optional[typing.Sequence[builtins.str]] = None, - command: typing.Optional[typing.Sequence[builtins.str]] = None, - env: typing.Optional[typing.Sequence[typing.Union[EnvVar, typing.Dict[builtins.str, typing.Any]]]] = None, - env_from: typing.Optional[typing.Sequence[typing.Union[EnvFromSource, typing.Dict[builtins.str, typing.Any]]]] = None, - image: typing.Optional[builtins.str] = None, - image_pull_policy: typing.Optional[builtins.str] = None, - lifecycle: typing.Optional[typing.Union["Lifecycle", typing.Dict[builtins.str, typing.Any]]] = None, - liveness_probe: typing.Optional[typing.Union["Probe", typing.Dict[builtins.str, typing.Any]]] = None, - ports: typing.Optional[typing.Sequence[typing.Union[ContainerPort, typing.Dict[builtins.str, typing.Any]]]] = None, - readiness_probe: typing.Optional[typing.Union["Probe", typing.Dict[builtins.str, typing.Any]]] = None, - resources: typing.Optional[typing.Union["ResourceRequirements", typing.Dict[builtins.str, typing.Any]]] = None, - security_context: typing.Optional[typing.Union["SecurityContext", typing.Dict[builtins.str, typing.Any]]] = None, - startup_probe: typing.Optional[typing.Union["Probe", typing.Dict[builtins.str, typing.Any]]] = None, - stdin: typing.Optional[builtins.bool] = None, - stdin_once: typing.Optional[builtins.bool] = None, - target_container_name: typing.Optional[builtins.str] = None, - termination_message_path: typing.Optional[builtins.str] = None, - termination_message_policy: typing.Optional[builtins.str] = None, - tty: typing.Optional[builtins.bool] = None, - volume_devices: typing.Optional[typing.Sequence[typing.Union["VolumeDevice", typing.Dict[builtins.str, typing.Any]]]] = None, - volume_mounts: typing.Optional[typing.Sequence[typing.Union["VolumeMount", typing.Dict[builtins.str, typing.Any]]]] = None, - working_dir: typing.Optional[builtins.str] = None, - ) -> None: - '''An EphemeralContainer is a temporary container that you may add to an existing Pod for user-initiated activities such as debugging. - - Ephemeral containers have no resource or scheduling guarantees, and they will not be restarted when they exit or when a Pod is removed or restarted. The kubelet may evict a Pod if an ephemeral container causes the Pod to exceed its resource allocation. - - To add an ephemeral container, use the ephemeralcontainers subresource of an existing Pod. Ephemeral containers may not be removed or restarted. - - :param name: Name of the ephemeral container specified as a DNS_LABEL. This name must be unique among all containers, init containers and ephemeral containers. - :param args: Arguments to the entrypoint. The image's CMD is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell - :param command: Entrypoint array. Not executed within a shell. The image's ENTRYPOINT is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell - :param env: List of environment variables to set in the container. Cannot be updated. - :param env_from: List of sources to populate environment variables in the container. The keys defined within a source must be a C_IDENTIFIER. All invalid keys will be reported as an event when the container is starting. When a key exists in multiple sources, the value associated with the last source will take precedence. Values defined by an Env with a duplicate key will take precedence. Cannot be updated. - :param image: Container image name. More info: https://kubernetes.io/docs/concepts/containers/images - :param image_pull_policy: Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images Default: Always if :latest tag is specified, or IfNotPresent otherwise. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images - :param lifecycle: Lifecycle is not allowed for ephemeral containers. - :param liveness_probe: Probes are not allowed for ephemeral containers. - :param ports: Ports are not allowed for ephemeral containers. - :param readiness_probe: Probes are not allowed for ephemeral containers. - :param resources: Resources are not allowed for ephemeral containers. Ephemeral containers use spare resources already allocated to the pod. - :param security_context: Optional: SecurityContext defines the security options the ephemeral container should be run with. If set, the fields of SecurityContext override the equivalent fields of PodSecurityContext. - :param startup_probe: Probes are not allowed for ephemeral containers. - :param stdin: Whether this container should allocate a buffer for stdin in the container runtime. If this is not set, reads from stdin in the container will always result in EOF. Default is false. Default: false. - :param stdin_once: Whether the container runtime should close the stdin channel after it has been opened by a single attach. When stdin is true the stdin stream will remain open across multiple attach sessions. If stdinOnce is set to true, stdin is opened on container start, is empty until the first client attaches to stdin, and then remains open and accepts data until the client disconnects, at which time stdin is closed and remains closed until the container is restarted. If this flag is false, a container processes that reads from stdin will never receive an EOF. Default is false Default: false - :param target_container_name: If set, the name of the container from PodSpec that this ephemeral container targets. The ephemeral container will be run in the namespaces (IPC, PID, etc) of this container. If not set then the ephemeral container uses the namespaces configured in the Pod spec. The container runtime must implement support for this feature. If the runtime does not support namespace targeting then the result of setting this field is undefined. - :param termination_message_path: Optional: Path at which the file to which the container's termination message will be written is mounted into the container's filesystem. Message written is intended to be brief final status, such as an assertion failure message. Will be truncated by the node if greater than 4096 bytes. The total message length across all containers will be limited to 12kb. Defaults to /dev/termination-log. Cannot be updated. Default: dev/termination-log. Cannot be updated. - :param termination_message_policy: Indicate how the termination message should be populated. File will use the contents of terminationMessagePath to populate the container status message on both success and failure. FallbackToLogsOnError will use the last chunk of container log output if the termination message file is empty and the container exited with an error. The log output is limited to 2048 bytes or 80 lines, whichever is smaller. Defaults to File. Cannot be updated. Default: File. Cannot be updated. - :param tty: Whether this container should allocate a TTY for itself, also requires 'stdin' to be true. Default is false. Default: false. - :param volume_devices: volumeDevices is the list of block devices to be used by the container. - :param volume_mounts: Pod volumes to mount into the container's filesystem. Subpath mounts are not allowed for ephemeral containers. Cannot be updated. - :param working_dir: Container's working directory. If not specified, the container runtime's default will be used, which might be configured in the container image. Cannot be updated. - - :schema: io.k8s.api.core.v1.EphemeralContainer - ''' - if isinstance(lifecycle, dict): - lifecycle = Lifecycle(**lifecycle) - if isinstance(liveness_probe, dict): - liveness_probe = Probe(**liveness_probe) - if isinstance(readiness_probe, dict): - readiness_probe = Probe(**readiness_probe) - if isinstance(resources, dict): - resources = ResourceRequirements(**resources) - if isinstance(security_context, dict): - security_context = SecurityContext(**security_context) - if isinstance(startup_probe, dict): - startup_probe = Probe(**startup_probe) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__3e01c0b51ea0b6a8c67c37763e480129a2534ef49ece7c443d6c8063f7415d29) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument args", value=args, expected_type=type_hints["args"]) - check_type(argname="argument command", value=command, expected_type=type_hints["command"]) - check_type(argname="argument env", value=env, expected_type=type_hints["env"]) - check_type(argname="argument env_from", value=env_from, expected_type=type_hints["env_from"]) - check_type(argname="argument image", value=image, expected_type=type_hints["image"]) - check_type(argname="argument image_pull_policy", value=image_pull_policy, expected_type=type_hints["image_pull_policy"]) - check_type(argname="argument lifecycle", value=lifecycle, expected_type=type_hints["lifecycle"]) - check_type(argname="argument liveness_probe", value=liveness_probe, expected_type=type_hints["liveness_probe"]) - check_type(argname="argument ports", value=ports, expected_type=type_hints["ports"]) - check_type(argname="argument readiness_probe", value=readiness_probe, expected_type=type_hints["readiness_probe"]) - check_type(argname="argument resources", value=resources, expected_type=type_hints["resources"]) - check_type(argname="argument security_context", value=security_context, expected_type=type_hints["security_context"]) - check_type(argname="argument startup_probe", value=startup_probe, expected_type=type_hints["startup_probe"]) - check_type(argname="argument stdin", value=stdin, expected_type=type_hints["stdin"]) - check_type(argname="argument stdin_once", value=stdin_once, expected_type=type_hints["stdin_once"]) - check_type(argname="argument target_container_name", value=target_container_name, expected_type=type_hints["target_container_name"]) - check_type(argname="argument termination_message_path", value=termination_message_path, expected_type=type_hints["termination_message_path"]) - check_type(argname="argument termination_message_policy", value=termination_message_policy, expected_type=type_hints["termination_message_policy"]) - check_type(argname="argument tty", value=tty, expected_type=type_hints["tty"]) - check_type(argname="argument volume_devices", value=volume_devices, expected_type=type_hints["volume_devices"]) - check_type(argname="argument volume_mounts", value=volume_mounts, expected_type=type_hints["volume_mounts"]) - check_type(argname="argument working_dir", value=working_dir, expected_type=type_hints["working_dir"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "name": name, - } - if args is not None: - self._values["args"] = args - if command is not None: - self._values["command"] = command - if env is not None: - self._values["env"] = env - if env_from is not None: - self._values["env_from"] = env_from - if image is not None: - self._values["image"] = image - if image_pull_policy is not None: - self._values["image_pull_policy"] = image_pull_policy - if lifecycle is not None: - self._values["lifecycle"] = lifecycle - if liveness_probe is not None: - self._values["liveness_probe"] = liveness_probe - if ports is not None: - self._values["ports"] = ports - if readiness_probe is not None: - self._values["readiness_probe"] = readiness_probe - if resources is not None: - self._values["resources"] = resources - if security_context is not None: - self._values["security_context"] = security_context - if startup_probe is not None: - self._values["startup_probe"] = startup_probe - if stdin is not None: - self._values["stdin"] = stdin - if stdin_once is not None: - self._values["stdin_once"] = stdin_once - if target_container_name is not None: - self._values["target_container_name"] = target_container_name - if termination_message_path is not None: - self._values["termination_message_path"] = termination_message_path - if termination_message_policy is not None: - self._values["termination_message_policy"] = termination_message_policy - if tty is not None: - self._values["tty"] = tty - if volume_devices is not None: - self._values["volume_devices"] = volume_devices - if volume_mounts is not None: - self._values["volume_mounts"] = volume_mounts - if working_dir is not None: - self._values["working_dir"] = working_dir - - @builtins.property - def name(self) -> builtins.str: - '''Name of the ephemeral container specified as a DNS_LABEL. - - This name must be unique among all containers, init containers and ephemeral containers. - - :schema: io.k8s.api.core.v1.EphemeralContainer#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def args(self) -> typing.Optional[typing.List[builtins.str]]: - '''Arguments to the entrypoint. - - The image's CMD is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell - - :schema: io.k8s.api.core.v1.EphemeralContainer#args - ''' - result = self._values.get("args") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def command(self) -> typing.Optional[typing.List[builtins.str]]: - '''Entrypoint array. - - Not executed within a shell. The image's ENTRYPOINT is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell - - :schema: io.k8s.api.core.v1.EphemeralContainer#command - ''' - result = self._values.get("command") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def env(self) -> typing.Optional[typing.List[EnvVar]]: - '''List of environment variables to set in the container. - - Cannot be updated. - - :schema: io.k8s.api.core.v1.EphemeralContainer#env - ''' - result = self._values.get("env") - return typing.cast(typing.Optional[typing.List[EnvVar]], result) - - @builtins.property - def env_from(self) -> typing.Optional[typing.List[EnvFromSource]]: - '''List of sources to populate environment variables in the container. - - The keys defined within a source must be a C_IDENTIFIER. All invalid keys will be reported as an event when the container is starting. When a key exists in multiple sources, the value associated with the last source will take precedence. Values defined by an Env with a duplicate key will take precedence. Cannot be updated. - - :schema: io.k8s.api.core.v1.EphemeralContainer#envFrom - ''' - result = self._values.get("env_from") - return typing.cast(typing.Optional[typing.List[EnvFromSource]], result) - - @builtins.property - def image(self) -> typing.Optional[builtins.str]: - '''Container image name. - - More info: https://kubernetes.io/docs/concepts/containers/images - - :schema: io.k8s.api.core.v1.EphemeralContainer#image - ''' - result = self._values.get("image") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def image_pull_policy(self) -> typing.Optional[builtins.str]: - '''Image pull policy. - - One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images - - :default: Always if :latest tag is specified, or IfNotPresent otherwise. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images - - :schema: io.k8s.api.core.v1.EphemeralContainer#imagePullPolicy - ''' - result = self._values.get("image_pull_policy") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def lifecycle(self) -> typing.Optional["Lifecycle"]: - '''Lifecycle is not allowed for ephemeral containers. - - :schema: io.k8s.api.core.v1.EphemeralContainer#lifecycle - ''' - result = self._values.get("lifecycle") - return typing.cast(typing.Optional["Lifecycle"], result) - - @builtins.property - def liveness_probe(self) -> typing.Optional["Probe"]: - '''Probes are not allowed for ephemeral containers. - - :schema: io.k8s.api.core.v1.EphemeralContainer#livenessProbe - ''' - result = self._values.get("liveness_probe") - return typing.cast(typing.Optional["Probe"], result) - - @builtins.property - def ports(self) -> typing.Optional[typing.List[ContainerPort]]: - '''Ports are not allowed for ephemeral containers. - - :schema: io.k8s.api.core.v1.EphemeralContainer#ports - ''' - result = self._values.get("ports") - return typing.cast(typing.Optional[typing.List[ContainerPort]], result) - - @builtins.property - def readiness_probe(self) -> typing.Optional["Probe"]: - '''Probes are not allowed for ephemeral containers. - - :schema: io.k8s.api.core.v1.EphemeralContainer#readinessProbe - ''' - result = self._values.get("readiness_probe") - return typing.cast(typing.Optional["Probe"], result) - - @builtins.property - def resources(self) -> typing.Optional["ResourceRequirements"]: - '''Resources are not allowed for ephemeral containers. - - Ephemeral containers use spare resources already allocated to the pod. - - :schema: io.k8s.api.core.v1.EphemeralContainer#resources - ''' - result = self._values.get("resources") - return typing.cast(typing.Optional["ResourceRequirements"], result) - - @builtins.property - def security_context(self) -> typing.Optional["SecurityContext"]: - '''Optional: SecurityContext defines the security options the ephemeral container should be run with. - - If set, the fields of SecurityContext override the equivalent fields of PodSecurityContext. - - :schema: io.k8s.api.core.v1.EphemeralContainer#securityContext - ''' - result = self._values.get("security_context") - return typing.cast(typing.Optional["SecurityContext"], result) - - @builtins.property - def startup_probe(self) -> typing.Optional["Probe"]: - '''Probes are not allowed for ephemeral containers. - - :schema: io.k8s.api.core.v1.EphemeralContainer#startupProbe - ''' - result = self._values.get("startup_probe") - return typing.cast(typing.Optional["Probe"], result) - - @builtins.property - def stdin(self) -> typing.Optional[builtins.bool]: - '''Whether this container should allocate a buffer for stdin in the container runtime. - - If this is not set, reads from stdin in the container will always result in EOF. Default is false. - - :default: false. - - :schema: io.k8s.api.core.v1.EphemeralContainer#stdin - ''' - result = self._values.get("stdin") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def stdin_once(self) -> typing.Optional[builtins.bool]: - '''Whether the container runtime should close the stdin channel after it has been opened by a single attach. - - When stdin is true the stdin stream will remain open across multiple attach sessions. If stdinOnce is set to true, stdin is opened on container start, is empty until the first client attaches to stdin, and then remains open and accepts data until the client disconnects, at which time stdin is closed and remains closed until the container is restarted. If this flag is false, a container processes that reads from stdin will never receive an EOF. Default is false - - :default: false - - :schema: io.k8s.api.core.v1.EphemeralContainer#stdinOnce - ''' - result = self._values.get("stdin_once") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def target_container_name(self) -> typing.Optional[builtins.str]: - '''If set, the name of the container from PodSpec that this ephemeral container targets. - - The ephemeral container will be run in the namespaces (IPC, PID, etc) of this container. If not set then the ephemeral container uses the namespaces configured in the Pod spec. - - The container runtime must implement support for this feature. If the runtime does not support namespace targeting then the result of setting this field is undefined. - - :schema: io.k8s.api.core.v1.EphemeralContainer#targetContainerName - ''' - result = self._values.get("target_container_name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def termination_message_path(self) -> typing.Optional[builtins.str]: - '''Optional: Path at which the file to which the container's termination message will be written is mounted into the container's filesystem. - - Message written is intended to be brief final status, such as an assertion failure message. Will be truncated by the node if greater than 4096 bytes. The total message length across all containers will be limited to 12kb. Defaults to /dev/termination-log. Cannot be updated. - - :default: dev/termination-log. Cannot be updated. - - :schema: io.k8s.api.core.v1.EphemeralContainer#terminationMessagePath - ''' - result = self._values.get("termination_message_path") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def termination_message_policy(self) -> typing.Optional[builtins.str]: - '''Indicate how the termination message should be populated. - - File will use the contents of terminationMessagePath to populate the container status message on both success and failure. FallbackToLogsOnError will use the last chunk of container log output if the termination message file is empty and the container exited with an error. The log output is limited to 2048 bytes or 80 lines, whichever is smaller. Defaults to File. Cannot be updated. - - :default: File. Cannot be updated. - - :schema: io.k8s.api.core.v1.EphemeralContainer#terminationMessagePolicy - ''' - result = self._values.get("termination_message_policy") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def tty(self) -> typing.Optional[builtins.bool]: - '''Whether this container should allocate a TTY for itself, also requires 'stdin' to be true. - - Default is false. - - :default: false. - - :schema: io.k8s.api.core.v1.EphemeralContainer#tty - ''' - result = self._values.get("tty") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def volume_devices(self) -> typing.Optional[typing.List["VolumeDevice"]]: - '''volumeDevices is the list of block devices to be used by the container. - - :schema: io.k8s.api.core.v1.EphemeralContainer#volumeDevices - ''' - result = self._values.get("volume_devices") - return typing.cast(typing.Optional[typing.List["VolumeDevice"]], result) - - @builtins.property - def volume_mounts(self) -> typing.Optional[typing.List["VolumeMount"]]: - '''Pod volumes to mount into the container's filesystem. - - Subpath mounts are not allowed for ephemeral containers. Cannot be updated. - - :schema: io.k8s.api.core.v1.EphemeralContainer#volumeMounts - ''' - result = self._values.get("volume_mounts") - return typing.cast(typing.Optional[typing.List["VolumeMount"]], result) - - @builtins.property - def working_dir(self) -> typing.Optional[builtins.str]: - '''Container's working directory. - - If not specified, the container runtime's default will be used, which might be configured in the container image. Cannot be updated. - - :schema: io.k8s.api.core.v1.EphemeralContainer#workingDir - ''' - result = self._values.get("working_dir") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "EphemeralContainer(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.EphemeralVolumeSource", - jsii_struct_bases=[], - name_mapping={"volume_claim_template": "volumeClaimTemplate"}, -) -class EphemeralVolumeSource: - def __init__( - self, - *, - volume_claim_template: typing.Optional[typing.Union["PersistentVolumeClaimTemplate", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Represents an ephemeral volume that is handled by a normal storage driver. - - :param volume_claim_template: Will be used to create a stand-alone PVC to provision the volume. The pod in which this EphemeralVolumeSource is embedded will be the owner of the PVC, i.e. the PVC will be deleted together with the pod. The name of the PVC will be ``-`` where ```` is the name from the ``PodSpec.Volumes`` array entry. Pod validation will reject the pod if the concatenated name is not valid for a PVC (for example, too long). An existing PVC with that name that is not owned by the pod will *not* be used for the pod to avoid using an unrelated volume by mistake. Starting the pod is then blocked until the unrelated PVC is removed. If such a pre-created PVC is meant to be used by the pod, the PVC has to updated with an owner reference to the pod once the pod exists. Normally this should not be necessary, but it may be useful when manually reconstructing a broken cluster. This field is read-only and no changes will be made by Kubernetes to the PVC after it has been created. Required, must not be nil. - - :schema: io.k8s.api.core.v1.EphemeralVolumeSource - ''' - if isinstance(volume_claim_template, dict): - volume_claim_template = PersistentVolumeClaimTemplate(**volume_claim_template) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__b18bb939a5ee93260e717b4a8b31bc6e5ff1329bc0dfc81f9c7fa24800f6854b) - check_type(argname="argument volume_claim_template", value=volume_claim_template, expected_type=type_hints["volume_claim_template"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if volume_claim_template is not None: - self._values["volume_claim_template"] = volume_claim_template - - @builtins.property - def volume_claim_template(self) -> typing.Optional["PersistentVolumeClaimTemplate"]: - '''Will be used to create a stand-alone PVC to provision the volume. - - The pod in which this EphemeralVolumeSource is embedded will be the owner of the PVC, i.e. the PVC will be deleted together with the pod. The name of the PVC will be ``-`` where ```` is the name from the ``PodSpec.Volumes`` array entry. Pod validation will reject the pod if the concatenated name is not valid for a PVC (for example, too long). - - An existing PVC with that name that is not owned by the pod will *not* be used for the pod to avoid using an unrelated volume by mistake. Starting the pod is then blocked until the unrelated PVC is removed. If such a pre-created PVC is meant to be used by the pod, the PVC has to updated with an owner reference to the pod once the pod exists. Normally this should not be necessary, but it may be useful when manually reconstructing a broken cluster. - - This field is read-only and no changes will be made by Kubernetes to the PVC after it has been created. - - Required, must not be nil. - - :schema: io.k8s.api.core.v1.EphemeralVolumeSource#volumeClaimTemplate - ''' - result = self._values.get("volume_claim_template") - return typing.cast(typing.Optional["PersistentVolumeClaimTemplate"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "EphemeralVolumeSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.EventSeries", - jsii_struct_bases=[], - name_mapping={"count": "count", "last_observed_time": "lastObservedTime"}, -) -class EventSeries: - def __init__( - self, - *, - count: jsii.Number, - last_observed_time: datetime.datetime, - ) -> None: - '''EventSeries contain information on series of events, i.e. thing that was/is happening continuously for some time. How often to update the EventSeries is up to the event reporters. The default event reporter in "k8s.io/client-go/tools/events/event_broadcaster.go" shows how this struct is updated on heartbeats and can guide customized reporter implementations. - - :param count: count is the number of occurrences in this series up to the last heartbeat time. - :param last_observed_time: lastObservedTime is the time when last Event from the series was seen before last heartbeat. - - :schema: io.k8s.api.events.v1.EventSeries - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__004487d3474ef54e77d3c4fc15800f434258914047b941481974745bac50347a) - check_type(argname="argument count", value=count, expected_type=type_hints["count"]) - check_type(argname="argument last_observed_time", value=last_observed_time, expected_type=type_hints["last_observed_time"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "count": count, - "last_observed_time": last_observed_time, - } - - @builtins.property - def count(self) -> jsii.Number: - '''count is the number of occurrences in this series up to the last heartbeat time. - - :schema: io.k8s.api.events.v1.EventSeries#count - ''' - result = self._values.get("count") - assert result is not None, "Required property 'count' is missing" - return typing.cast(jsii.Number, result) - - @builtins.property - def last_observed_time(self) -> datetime.datetime: - '''lastObservedTime is the time when last Event from the series was seen before last heartbeat. - - :schema: io.k8s.api.events.v1.EventSeries#lastObservedTime - ''' - result = self._values.get("last_observed_time") - assert result is not None, "Required property 'last_observed_time' is missing" - return typing.cast(datetime.datetime, result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "EventSeries(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.EventSource", - jsii_struct_bases=[], - name_mapping={"component": "component", "host": "host"}, -) -class EventSource: - def __init__( - self, - *, - component: typing.Optional[builtins.str] = None, - host: typing.Optional[builtins.str] = None, - ) -> None: - '''EventSource contains information for an event. - - :param component: Component from which the event is generated. - :param host: Node name on which the event is generated. - - :schema: io.k8s.api.core.v1.EventSource - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__4a9e80d349ff66b0083f1d53dad15acd2eb7b7353b7849460bd62f8e25e7974e) - check_type(argname="argument component", value=component, expected_type=type_hints["component"]) - check_type(argname="argument host", value=host, expected_type=type_hints["host"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if component is not None: - self._values["component"] = component - if host is not None: - self._values["host"] = host - - @builtins.property - def component(self) -> typing.Optional[builtins.str]: - '''Component from which the event is generated. - - :schema: io.k8s.api.core.v1.EventSource#component - ''' - result = self._values.get("component") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def host(self) -> typing.Optional[builtins.str]: - '''Node name on which the event is generated. - - :schema: io.k8s.api.core.v1.EventSource#host - ''' - result = self._values.get("host") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "EventSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ExecAction", - jsii_struct_bases=[], - name_mapping={"command": "command"}, -) -class ExecAction: - def __init__( - self, - *, - command: typing.Optional[typing.Sequence[builtins.str]] = None, - ) -> None: - '''ExecAction describes a "run in container" action. - - :param command: Command is the command line to execute inside the container, the working directory for the command is root ('/') in the container's filesystem. The command is simply exec'd, it is not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use a shell, you need to explicitly call out to that shell. Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - - :schema: io.k8s.api.core.v1.ExecAction - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__39b0da0ddb8fa067bbecf85dd3d7748f68c3c1d726d1f55f6612b8bd92883a73) - check_type(argname="argument command", value=command, expected_type=type_hints["command"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if command is not None: - self._values["command"] = command - - @builtins.property - def command(self) -> typing.Optional[typing.List[builtins.str]]: - '''Command is the command line to execute inside the container, the working directory for the command is root ('/') in the container's filesystem. - - The command is simply exec'd, it is not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use a shell, you need to explicitly call out to that shell. Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - - :schema: io.k8s.api.core.v1.ExecAction#command - ''' - result = self._values.get("command") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ExecAction(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ExternalDocumentation", - jsii_struct_bases=[], - name_mapping={"description": "description", "url": "url"}, -) -class ExternalDocumentation: - def __init__( - self, - *, - description: typing.Optional[builtins.str] = None, - url: typing.Optional[builtins.str] = None, - ) -> None: - '''ExternalDocumentation allows referencing an external resource for extended documentation. - - :param description: - :param url: - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.ExternalDocumentation - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__ed55df628bde684d5aa951f6b4c6672c57289721dbb3a11facc37969e46246f1) - check_type(argname="argument description", value=description, expected_type=type_hints["description"]) - check_type(argname="argument url", value=url, expected_type=type_hints["url"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if description is not None: - self._values["description"] = description - if url is not None: - self._values["url"] = url - - @builtins.property - def description(self) -> typing.Optional[builtins.str]: - ''' - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.ExternalDocumentation#description - ''' - result = self._values.get("description") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def url(self) -> typing.Optional[builtins.str]: - ''' - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.ExternalDocumentation#url - ''' - result = self._values.get("url") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ExternalDocumentation(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ExternalMetricSourceV2", - jsii_struct_bases=[], - name_mapping={"metric": "metric", "target": "target"}, -) -class ExternalMetricSourceV2: - def __init__( - self, - *, - metric: typing.Union["MetricIdentifierV2", typing.Dict[builtins.str, typing.Any]], - target: typing.Union["MetricTargetV2", typing.Dict[builtins.str, typing.Any]], - ) -> None: - '''ExternalMetricSource indicates how to scale on a metric not associated with any Kubernetes object (for example length of queue in cloud messaging service, or QPS from loadbalancer running outside of cluster). - - :param metric: metric identifies the target metric by name and selector. - :param target: target specifies the target value for the given metric. - - :schema: io.k8s.api.autoscaling.v2.ExternalMetricSource - ''' - if isinstance(metric, dict): - metric = MetricIdentifierV2(**metric) - if isinstance(target, dict): - target = MetricTargetV2(**target) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__991911955f55da3c4dbd38270ac60d304756b0eac9946bf6bab366840a5e5a7a) - check_type(argname="argument metric", value=metric, expected_type=type_hints["metric"]) - check_type(argname="argument target", value=target, expected_type=type_hints["target"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "metric": metric, - "target": target, - } - - @builtins.property - def metric(self) -> "MetricIdentifierV2": - '''metric identifies the target metric by name and selector. - - :schema: io.k8s.api.autoscaling.v2.ExternalMetricSource#metric - ''' - result = self._values.get("metric") - assert result is not None, "Required property 'metric' is missing" - return typing.cast("MetricIdentifierV2", result) - - @builtins.property - def target(self) -> "MetricTargetV2": - '''target specifies the target value for the given metric. - - :schema: io.k8s.api.autoscaling.v2.ExternalMetricSource#target - ''' - result = self._values.get("target") - assert result is not None, "Required property 'target' is missing" - return typing.cast("MetricTargetV2", result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ExternalMetricSourceV2(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.FcVolumeSource", - jsii_struct_bases=[], - name_mapping={ - "fs_type": "fsType", - "lun": "lun", - "read_only": "readOnly", - "target_ww_ns": "targetWwNs", - "wwids": "wwids", - }, -) -class FcVolumeSource: - def __init__( - self, - *, - fs_type: typing.Optional[builtins.str] = None, - lun: typing.Optional[jsii.Number] = None, - read_only: typing.Optional[builtins.bool] = None, - target_ww_ns: typing.Optional[typing.Sequence[builtins.str]] = None, - wwids: typing.Optional[typing.Sequence[builtins.str]] = None, - ) -> None: - '''Represents a Fibre Channel volume. - - Fibre Channel volumes can only be mounted as read/write once. Fibre Channel volumes support ownership management and SELinux relabeling. - - :param fs_type: fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - :param lun: lun is Optional: FC target lun number. - :param read_only: readOnly is Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. Default: false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. - :param target_ww_ns: targetWWNs is Optional: FC target worldwide names (WWNs). - :param wwids: wwids Optional: FC volume world wide identifiers (wwids) Either wwids or combination of targetWWNs and lun must be set, but not both simultaneously. - - :schema: io.k8s.api.core.v1.FCVolumeSource - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__2745107e20cb778ffd413fedde9112e0e0e1ad8530ac6be3aa44daf745945cd1) - check_type(argname="argument fs_type", value=fs_type, expected_type=type_hints["fs_type"]) - check_type(argname="argument lun", value=lun, expected_type=type_hints["lun"]) - check_type(argname="argument read_only", value=read_only, expected_type=type_hints["read_only"]) - check_type(argname="argument target_ww_ns", value=target_ww_ns, expected_type=type_hints["target_ww_ns"]) - check_type(argname="argument wwids", value=wwids, expected_type=type_hints["wwids"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if fs_type is not None: - self._values["fs_type"] = fs_type - if lun is not None: - self._values["lun"] = lun - if read_only is not None: - self._values["read_only"] = read_only - if target_ww_ns is not None: - self._values["target_ww_ns"] = target_ww_ns - if wwids is not None: - self._values["wwids"] = wwids - - @builtins.property - def fs_type(self) -> typing.Optional[builtins.str]: - '''fsType is the filesystem type to mount. - - Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - - :schema: io.k8s.api.core.v1.FCVolumeSource#fsType - ''' - result = self._values.get("fs_type") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def lun(self) -> typing.Optional[jsii.Number]: - '''lun is Optional: FC target lun number. - - :schema: io.k8s.api.core.v1.FCVolumeSource#lun - ''' - result = self._values.get("lun") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def read_only(self) -> typing.Optional[builtins.bool]: - '''readOnly is Optional: Defaults to false (read/write). - - ReadOnly here will force the ReadOnly setting in VolumeMounts. - - :default: false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. - - :schema: io.k8s.api.core.v1.FCVolumeSource#readOnly - ''' - result = self._values.get("read_only") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def target_ww_ns(self) -> typing.Optional[typing.List[builtins.str]]: - '''targetWWNs is Optional: FC target worldwide names (WWNs). - - :schema: io.k8s.api.core.v1.FCVolumeSource#targetWWNs - ''' - result = self._values.get("target_ww_ns") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def wwids(self) -> typing.Optional[typing.List[builtins.str]]: - '''wwids Optional: FC volume world wide identifiers (wwids) Either wwids or combination of targetWWNs and lun must be set, but not both simultaneously. - - :schema: io.k8s.api.core.v1.FCVolumeSource#wwids - ''' - result = self._values.get("wwids") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "FcVolumeSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.FlexPersistentVolumeSource", - jsii_struct_bases=[], - name_mapping={ - "driver": "driver", - "fs_type": "fsType", - "options": "options", - "read_only": "readOnly", - "secret_ref": "secretRef", - }, -) -class FlexPersistentVolumeSource: - def __init__( - self, - *, - driver: builtins.str, - fs_type: typing.Optional[builtins.str] = None, - options: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - read_only: typing.Optional[builtins.bool] = None, - secret_ref: typing.Optional[typing.Union["SecretReference", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''FlexPersistentVolumeSource represents a generic persistent volume resource that is provisioned/attached using an exec based plugin. - - :param driver: driver is the name of the driver to use for this volume. - :param fs_type: fsType is the Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". The default filesystem depends on FlexVolume script. - :param options: options is Optional: this field holds extra command options if any. - :param read_only: readOnly is Optional: defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. - :param secret_ref: secretRef is Optional: SecretRef is reference to the secret object containing sensitive information to pass to the plugin scripts. This may be empty if no secret object is specified. If the secret object contains more than one secret, all secrets are passed to the plugin scripts. - - :schema: io.k8s.api.core.v1.FlexPersistentVolumeSource - ''' - if isinstance(secret_ref, dict): - secret_ref = SecretReference(**secret_ref) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__361bb86c0f3e6ad95260e69e5449b56f8ed56cc62d38e36d89c325ca5045168e) - check_type(argname="argument driver", value=driver, expected_type=type_hints["driver"]) - check_type(argname="argument fs_type", value=fs_type, expected_type=type_hints["fs_type"]) - check_type(argname="argument options", value=options, expected_type=type_hints["options"]) - check_type(argname="argument read_only", value=read_only, expected_type=type_hints["read_only"]) - check_type(argname="argument secret_ref", value=secret_ref, expected_type=type_hints["secret_ref"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "driver": driver, - } - if fs_type is not None: - self._values["fs_type"] = fs_type - if options is not None: - self._values["options"] = options - if read_only is not None: - self._values["read_only"] = read_only - if secret_ref is not None: - self._values["secret_ref"] = secret_ref - - @builtins.property - def driver(self) -> builtins.str: - '''driver is the name of the driver to use for this volume. - - :schema: io.k8s.api.core.v1.FlexPersistentVolumeSource#driver - ''' - result = self._values.get("driver") - assert result is not None, "Required property 'driver' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def fs_type(self) -> typing.Optional[builtins.str]: - '''fsType is the Filesystem type to mount. - - Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". The default filesystem depends on FlexVolume script. - - :schema: io.k8s.api.core.v1.FlexPersistentVolumeSource#fsType - ''' - result = self._values.get("fs_type") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def options(self) -> typing.Optional[typing.Mapping[builtins.str, builtins.str]]: - '''options is Optional: this field holds extra command options if any. - - :schema: io.k8s.api.core.v1.FlexPersistentVolumeSource#options - ''' - result = self._values.get("options") - return typing.cast(typing.Optional[typing.Mapping[builtins.str, builtins.str]], result) - - @builtins.property - def read_only(self) -> typing.Optional[builtins.bool]: - '''readOnly is Optional: defaults to false (read/write). - - ReadOnly here will force the ReadOnly setting in VolumeMounts. - - :schema: io.k8s.api.core.v1.FlexPersistentVolumeSource#readOnly - ''' - result = self._values.get("read_only") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def secret_ref(self) -> typing.Optional["SecretReference"]: - '''secretRef is Optional: SecretRef is reference to the secret object containing sensitive information to pass to the plugin scripts. - - This may be empty if no secret object is specified. If the secret object contains more than one secret, all secrets are passed to the plugin scripts. - - :schema: io.k8s.api.core.v1.FlexPersistentVolumeSource#secretRef - ''' - result = self._values.get("secret_ref") - return typing.cast(typing.Optional["SecretReference"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "FlexPersistentVolumeSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.FlexVolumeSource", - jsii_struct_bases=[], - name_mapping={ - "driver": "driver", - "fs_type": "fsType", - "options": "options", - "read_only": "readOnly", - "secret_ref": "secretRef", - }, -) -class FlexVolumeSource: - def __init__( - self, - *, - driver: builtins.str, - fs_type: typing.Optional[builtins.str] = None, - options: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - read_only: typing.Optional[builtins.bool] = None, - secret_ref: typing.Optional[typing.Union["LocalObjectReference", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''FlexVolume represents a generic volume resource that is provisioned/attached using an exec based plugin. - - :param driver: driver is the name of the driver to use for this volume. - :param fs_type: fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". The default filesystem depends on FlexVolume script. - :param options: options is Optional: this field holds extra command options if any. - :param read_only: readOnly is Optional: defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. - :param secret_ref: secretRef is Optional: secretRef is reference to the secret object containing sensitive information to pass to the plugin scripts. This may be empty if no secret object is specified. If the secret object contains more than one secret, all secrets are passed to the plugin scripts. - - :schema: io.k8s.api.core.v1.FlexVolumeSource - ''' - if isinstance(secret_ref, dict): - secret_ref = LocalObjectReference(**secret_ref) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__01d639d31d18ccaee6a1c059e3369e39b1ae2532a11a7a6f32fd5bcfb50615c4) - check_type(argname="argument driver", value=driver, expected_type=type_hints["driver"]) - check_type(argname="argument fs_type", value=fs_type, expected_type=type_hints["fs_type"]) - check_type(argname="argument options", value=options, expected_type=type_hints["options"]) - check_type(argname="argument read_only", value=read_only, expected_type=type_hints["read_only"]) - check_type(argname="argument secret_ref", value=secret_ref, expected_type=type_hints["secret_ref"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "driver": driver, - } - if fs_type is not None: - self._values["fs_type"] = fs_type - if options is not None: - self._values["options"] = options - if read_only is not None: - self._values["read_only"] = read_only - if secret_ref is not None: - self._values["secret_ref"] = secret_ref - - @builtins.property - def driver(self) -> builtins.str: - '''driver is the name of the driver to use for this volume. - - :schema: io.k8s.api.core.v1.FlexVolumeSource#driver - ''' - result = self._values.get("driver") - assert result is not None, "Required property 'driver' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def fs_type(self) -> typing.Optional[builtins.str]: - '''fsType is the filesystem type to mount. - - Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". The default filesystem depends on FlexVolume script. - - :schema: io.k8s.api.core.v1.FlexVolumeSource#fsType - ''' - result = self._values.get("fs_type") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def options(self) -> typing.Optional[typing.Mapping[builtins.str, builtins.str]]: - '''options is Optional: this field holds extra command options if any. - - :schema: io.k8s.api.core.v1.FlexVolumeSource#options - ''' - result = self._values.get("options") - return typing.cast(typing.Optional[typing.Mapping[builtins.str, builtins.str]], result) - - @builtins.property - def read_only(self) -> typing.Optional[builtins.bool]: - '''readOnly is Optional: defaults to false (read/write). - - ReadOnly here will force the ReadOnly setting in VolumeMounts. - - :schema: io.k8s.api.core.v1.FlexVolumeSource#readOnly - ''' - result = self._values.get("read_only") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def secret_ref(self) -> typing.Optional["LocalObjectReference"]: - '''secretRef is Optional: secretRef is reference to the secret object containing sensitive information to pass to the plugin scripts. - - This may be empty if no secret object is specified. If the secret object contains more than one secret, all secrets are passed to the plugin scripts. - - :schema: io.k8s.api.core.v1.FlexVolumeSource#secretRef - ''' - result = self._values.get("secret_ref") - return typing.cast(typing.Optional["LocalObjectReference"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "FlexVolumeSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.FlockerVolumeSource", - jsii_struct_bases=[], - name_mapping={"dataset_name": "datasetName", "dataset_uuid": "datasetUuid"}, -) -class FlockerVolumeSource: - def __init__( - self, - *, - dataset_name: typing.Optional[builtins.str] = None, - dataset_uuid: typing.Optional[builtins.str] = None, - ) -> None: - '''Represents a Flocker volume mounted by the Flocker agent. - - One and only one of datasetName and datasetUUID should be set. Flocker volumes do not support ownership management or SELinux relabeling. - - :param dataset_name: datasetName is Name of the dataset stored as metadata -> name on the dataset for Flocker should be considered as deprecated. - :param dataset_uuid: datasetUUID is the UUID of the dataset. This is unique identifier of a Flocker dataset - - :schema: io.k8s.api.core.v1.FlockerVolumeSource - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__c8da19b7f0ffd9cf70dddb6e7c6984f3d78d5aa2c70fad98b528bc4aded8a549) - check_type(argname="argument dataset_name", value=dataset_name, expected_type=type_hints["dataset_name"]) - check_type(argname="argument dataset_uuid", value=dataset_uuid, expected_type=type_hints["dataset_uuid"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if dataset_name is not None: - self._values["dataset_name"] = dataset_name - if dataset_uuid is not None: - self._values["dataset_uuid"] = dataset_uuid - - @builtins.property - def dataset_name(self) -> typing.Optional[builtins.str]: - '''datasetName is Name of the dataset stored as metadata -> name on the dataset for Flocker should be considered as deprecated. - - :schema: io.k8s.api.core.v1.FlockerVolumeSource#datasetName - ''' - result = self._values.get("dataset_name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def dataset_uuid(self) -> typing.Optional[builtins.str]: - '''datasetUUID is the UUID of the dataset. - - This is unique identifier of a Flocker dataset - - :schema: io.k8s.api.core.v1.FlockerVolumeSource#datasetUUID - ''' - result = self._values.get("dataset_uuid") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "FlockerVolumeSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.FlowDistinguisherMethodV1Beta2", - jsii_struct_bases=[], - name_mapping={"type": "type"}, -) -class FlowDistinguisherMethodV1Beta2: - def __init__(self, *, type: builtins.str) -> None: - '''FlowDistinguisherMethod specifies the method of a flow distinguisher. - - :param type: ``type`` is the type of flow distinguisher method The supported types are "ByUser" and "ByNamespace". Required. - - :schema: io.k8s.api.flowcontrol.v1beta2.FlowDistinguisherMethod - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__f097bb4fbe672878a09ccbc6c996fba34cd3cbbd412e738d7df0e2c5790f6b10) - check_type(argname="argument type", value=type, expected_type=type_hints["type"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "type": type, - } - - @builtins.property - def type(self) -> builtins.str: - '''``type`` is the type of flow distinguisher method The supported types are "ByUser" and "ByNamespace". - - Required. - - :schema: io.k8s.api.flowcontrol.v1beta2.FlowDistinguisherMethod#type - ''' - result = self._values.get("type") - assert result is not None, "Required property 'type' is missing" - return typing.cast(builtins.str, result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "FlowDistinguisherMethodV1Beta2(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.FlowDistinguisherMethodV1Beta3", - jsii_struct_bases=[], - name_mapping={"type": "type"}, -) -class FlowDistinguisherMethodV1Beta3: - def __init__(self, *, type: builtins.str) -> None: - '''FlowDistinguisherMethod specifies the method of a flow distinguisher. - - :param type: ``type`` is the type of flow distinguisher method The supported types are "ByUser" and "ByNamespace". Required. - - :schema: io.k8s.api.flowcontrol.v1beta3.FlowDistinguisherMethod - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__bffd4b6077b1400f76c8885e39b16536445fb17247f408a55f48c1989bb500f7) - check_type(argname="argument type", value=type, expected_type=type_hints["type"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "type": type, - } - - @builtins.property - def type(self) -> builtins.str: - '''``type`` is the type of flow distinguisher method The supported types are "ByUser" and "ByNamespace". - - Required. - - :schema: io.k8s.api.flowcontrol.v1beta3.FlowDistinguisherMethod#type - ''' - result = self._values.get("type") - assert result is not None, "Required property 'type' is missing" - return typing.cast(builtins.str, result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "FlowDistinguisherMethodV1Beta3(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.FlowSchemaSpecV1Beta2", - jsii_struct_bases=[], - name_mapping={ - "priority_level_configuration": "priorityLevelConfiguration", - "distinguisher_method": "distinguisherMethod", - "matching_precedence": "matchingPrecedence", - "rules": "rules", - }, -) -class FlowSchemaSpecV1Beta2: - def __init__( - self, - *, - priority_level_configuration: typing.Union["PriorityLevelConfigurationReferenceV1Beta2", typing.Dict[builtins.str, typing.Any]], - distinguisher_method: typing.Optional[typing.Union[FlowDistinguisherMethodV1Beta2, typing.Dict[builtins.str, typing.Any]]] = None, - matching_precedence: typing.Optional[jsii.Number] = None, - rules: typing.Optional[typing.Sequence[typing.Union["PolicyRulesWithSubjectsV1Beta2", typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''FlowSchemaSpec describes how the FlowSchema's specification looks like. - - :param priority_level_configuration: ``priorityLevelConfiguration`` should reference a PriorityLevelConfiguration in the cluster. If the reference cannot be resolved, the FlowSchema will be ignored and marked as invalid in its status. Required. - :param distinguisher_method: ``distinguisherMethod`` defines how to compute the flow distinguisher for requests that match this schema. ``nil`` specifies that the distinguisher is disabled and thus will always be the empty string. - :param matching_precedence: ``matchingPrecedence`` is used to choose among the FlowSchemas that match a given request. The chosen FlowSchema is among those with the numerically lowest (which we take to be logically highest) MatchingPrecedence. Each MatchingPrecedence value must be ranged in [1,10000]. Note that if the precedence is not specified, it will be set to 1000 as default. - :param rules: ``rules`` describes which requests will match this flow schema. This FlowSchema matches a request if and only if at least one member of rules matches the request. if it is an empty slice, there will be no requests matching the FlowSchema. - - :schema: io.k8s.api.flowcontrol.v1beta2.FlowSchemaSpec - ''' - if isinstance(priority_level_configuration, dict): - priority_level_configuration = PriorityLevelConfigurationReferenceV1Beta2(**priority_level_configuration) - if isinstance(distinguisher_method, dict): - distinguisher_method = FlowDistinguisherMethodV1Beta2(**distinguisher_method) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__95a7a4e1d128cef7bb866d233e06c9bb0da818b45bcd627a65d99a570d28c5b7) - check_type(argname="argument priority_level_configuration", value=priority_level_configuration, expected_type=type_hints["priority_level_configuration"]) - check_type(argname="argument distinguisher_method", value=distinguisher_method, expected_type=type_hints["distinguisher_method"]) - check_type(argname="argument matching_precedence", value=matching_precedence, expected_type=type_hints["matching_precedence"]) - check_type(argname="argument rules", value=rules, expected_type=type_hints["rules"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "priority_level_configuration": priority_level_configuration, - } - if distinguisher_method is not None: - self._values["distinguisher_method"] = distinguisher_method - if matching_precedence is not None: - self._values["matching_precedence"] = matching_precedence - if rules is not None: - self._values["rules"] = rules - - @builtins.property - def priority_level_configuration( - self, - ) -> "PriorityLevelConfigurationReferenceV1Beta2": - '''``priorityLevelConfiguration`` should reference a PriorityLevelConfiguration in the cluster. - - If the reference cannot be resolved, the FlowSchema will be ignored and marked as invalid in its status. Required. - - :schema: io.k8s.api.flowcontrol.v1beta2.FlowSchemaSpec#priorityLevelConfiguration - ''' - result = self._values.get("priority_level_configuration") - assert result is not None, "Required property 'priority_level_configuration' is missing" - return typing.cast("PriorityLevelConfigurationReferenceV1Beta2", result) - - @builtins.property - def distinguisher_method(self) -> typing.Optional[FlowDistinguisherMethodV1Beta2]: - '''``distinguisherMethod`` defines how to compute the flow distinguisher for requests that match this schema. - - ``nil`` specifies that the distinguisher is disabled and thus will always be the empty string. - - :schema: io.k8s.api.flowcontrol.v1beta2.FlowSchemaSpec#distinguisherMethod - ''' - result = self._values.get("distinguisher_method") - return typing.cast(typing.Optional[FlowDistinguisherMethodV1Beta2], result) - - @builtins.property - def matching_precedence(self) -> typing.Optional[jsii.Number]: - '''``matchingPrecedence`` is used to choose among the FlowSchemas that match a given request. - - The chosen FlowSchema is among those with the numerically lowest (which we take to be logically highest) MatchingPrecedence. Each MatchingPrecedence value must be ranged in [1,10000]. Note that if the precedence is not specified, it will be set to 1000 as default. - - :schema: io.k8s.api.flowcontrol.v1beta2.FlowSchemaSpec#matchingPrecedence - ''' - result = self._values.get("matching_precedence") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def rules(self) -> typing.Optional[typing.List["PolicyRulesWithSubjectsV1Beta2"]]: - '''``rules`` describes which requests will match this flow schema. - - This FlowSchema matches a request if and only if at least one member of rules matches the request. if it is an empty slice, there will be no requests matching the FlowSchema. - - :schema: io.k8s.api.flowcontrol.v1beta2.FlowSchemaSpec#rules - ''' - result = self._values.get("rules") - return typing.cast(typing.Optional[typing.List["PolicyRulesWithSubjectsV1Beta2"]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "FlowSchemaSpecV1Beta2(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.FlowSchemaSpecV1Beta3", - jsii_struct_bases=[], - name_mapping={ - "priority_level_configuration": "priorityLevelConfiguration", - "distinguisher_method": "distinguisherMethod", - "matching_precedence": "matchingPrecedence", - "rules": "rules", - }, -) -class FlowSchemaSpecV1Beta3: - def __init__( - self, - *, - priority_level_configuration: typing.Union["PriorityLevelConfigurationReferenceV1Beta3", typing.Dict[builtins.str, typing.Any]], - distinguisher_method: typing.Optional[typing.Union[FlowDistinguisherMethodV1Beta3, typing.Dict[builtins.str, typing.Any]]] = None, - matching_precedence: typing.Optional[jsii.Number] = None, - rules: typing.Optional[typing.Sequence[typing.Union["PolicyRulesWithSubjectsV1Beta3", typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''FlowSchemaSpec describes how the FlowSchema's specification looks like. - - :param priority_level_configuration: ``priorityLevelConfiguration`` should reference a PriorityLevelConfiguration in the cluster. If the reference cannot be resolved, the FlowSchema will be ignored and marked as invalid in its status. Required. - :param distinguisher_method: ``distinguisherMethod`` defines how to compute the flow distinguisher for requests that match this schema. ``nil`` specifies that the distinguisher is disabled and thus will always be the empty string. - :param matching_precedence: ``matchingPrecedence`` is used to choose among the FlowSchemas that match a given request. The chosen FlowSchema is among those with the numerically lowest (which we take to be logically highest) MatchingPrecedence. Each MatchingPrecedence value must be ranged in [1,10000]. Note that if the precedence is not specified, it will be set to 1000 as default. - :param rules: ``rules`` describes which requests will match this flow schema. This FlowSchema matches a request if and only if at least one member of rules matches the request. if it is an empty slice, there will be no requests matching the FlowSchema. - - :schema: io.k8s.api.flowcontrol.v1beta3.FlowSchemaSpec - ''' - if isinstance(priority_level_configuration, dict): - priority_level_configuration = PriorityLevelConfigurationReferenceV1Beta3(**priority_level_configuration) - if isinstance(distinguisher_method, dict): - distinguisher_method = FlowDistinguisherMethodV1Beta3(**distinguisher_method) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__52d981628f2120d6117e98080ee21cdc5a95544b4e345b4f2083d09e3e6ac908) - check_type(argname="argument priority_level_configuration", value=priority_level_configuration, expected_type=type_hints["priority_level_configuration"]) - check_type(argname="argument distinguisher_method", value=distinguisher_method, expected_type=type_hints["distinguisher_method"]) - check_type(argname="argument matching_precedence", value=matching_precedence, expected_type=type_hints["matching_precedence"]) - check_type(argname="argument rules", value=rules, expected_type=type_hints["rules"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "priority_level_configuration": priority_level_configuration, - } - if distinguisher_method is not None: - self._values["distinguisher_method"] = distinguisher_method - if matching_precedence is not None: - self._values["matching_precedence"] = matching_precedence - if rules is not None: - self._values["rules"] = rules - - @builtins.property - def priority_level_configuration( - self, - ) -> "PriorityLevelConfigurationReferenceV1Beta3": - '''``priorityLevelConfiguration`` should reference a PriorityLevelConfiguration in the cluster. - - If the reference cannot be resolved, the FlowSchema will be ignored and marked as invalid in its status. Required. - - :schema: io.k8s.api.flowcontrol.v1beta3.FlowSchemaSpec#priorityLevelConfiguration - ''' - result = self._values.get("priority_level_configuration") - assert result is not None, "Required property 'priority_level_configuration' is missing" - return typing.cast("PriorityLevelConfigurationReferenceV1Beta3", result) - - @builtins.property - def distinguisher_method(self) -> typing.Optional[FlowDistinguisherMethodV1Beta3]: - '''``distinguisherMethod`` defines how to compute the flow distinguisher for requests that match this schema. - - ``nil`` specifies that the distinguisher is disabled and thus will always be the empty string. - - :schema: io.k8s.api.flowcontrol.v1beta3.FlowSchemaSpec#distinguisherMethod - ''' - result = self._values.get("distinguisher_method") - return typing.cast(typing.Optional[FlowDistinguisherMethodV1Beta3], result) - - @builtins.property - def matching_precedence(self) -> typing.Optional[jsii.Number]: - '''``matchingPrecedence`` is used to choose among the FlowSchemas that match a given request. - - The chosen FlowSchema is among those with the numerically lowest (which we take to be logically highest) MatchingPrecedence. Each MatchingPrecedence value must be ranged in [1,10000]. Note that if the precedence is not specified, it will be set to 1000 as default. - - :schema: io.k8s.api.flowcontrol.v1beta3.FlowSchemaSpec#matchingPrecedence - ''' - result = self._values.get("matching_precedence") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def rules(self) -> typing.Optional[typing.List["PolicyRulesWithSubjectsV1Beta3"]]: - '''``rules`` describes which requests will match this flow schema. - - This FlowSchema matches a request if and only if at least one member of rules matches the request. if it is an empty slice, there will be no requests matching the FlowSchema. - - :schema: io.k8s.api.flowcontrol.v1beta3.FlowSchemaSpec#rules - ''' - result = self._values.get("rules") - return typing.cast(typing.Optional[typing.List["PolicyRulesWithSubjectsV1Beta3"]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "FlowSchemaSpecV1Beta3(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ForZone", - jsii_struct_bases=[], - name_mapping={"name": "name"}, -) -class ForZone: - def __init__(self, *, name: builtins.str) -> None: - '''ForZone provides information about which zones should consume this endpoint. - - :param name: name represents the name of the zone. - - :schema: io.k8s.api.discovery.v1.ForZone - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__fc406b0dce866e82fadbc8c73de5da39909470ea692a663d044c98e9e75e472e) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "name": name, - } - - @builtins.property - def name(self) -> builtins.str: - '''name represents the name of the zone. - - :schema: io.k8s.api.discovery.v1.ForZone#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ForZone(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.GcePersistentDiskVolumeSource", - jsii_struct_bases=[], - name_mapping={ - "pd_name": "pdName", - "fs_type": "fsType", - "partition": "partition", - "read_only": "readOnly", - }, -) -class GcePersistentDiskVolumeSource: - def __init__( - self, - *, - pd_name: builtins.str, - fs_type: typing.Optional[builtins.str] = None, - partition: typing.Optional[jsii.Number] = None, - read_only: typing.Optional[builtins.bool] = None, - ) -> None: - '''Represents a Persistent Disk resource in Google Compute Engine. - - A GCE PD must exist before mounting to a container. The disk must also be in the same GCE project and zone as the kubelet. A GCE PD can only be mounted as read/write once or read-only many times. GCE PDs support ownership management and SELinux relabeling. - - :param pd_name: pdName is unique name of the PD resource in GCE. Used to identify the disk in GCE. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - :param fs_type: fsType is filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - :param partition: partition is the partition in the volume that you want to mount. If omitted, the default is to mount by volume name. Examples: For volume /dev/sda1, you specify the partition as "1". Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - :param read_only: readOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk Default: false. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - - :schema: io.k8s.api.core.v1.GCEPersistentDiskVolumeSource - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__67fa0238ae227faa5913c9a406cb8c1df336aa99b59c22be5e9022157eef8101) - check_type(argname="argument pd_name", value=pd_name, expected_type=type_hints["pd_name"]) - check_type(argname="argument fs_type", value=fs_type, expected_type=type_hints["fs_type"]) - check_type(argname="argument partition", value=partition, expected_type=type_hints["partition"]) - check_type(argname="argument read_only", value=read_only, expected_type=type_hints["read_only"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "pd_name": pd_name, - } - if fs_type is not None: - self._values["fs_type"] = fs_type - if partition is not None: - self._values["partition"] = partition - if read_only is not None: - self._values["read_only"] = read_only - - @builtins.property - def pd_name(self) -> builtins.str: - '''pdName is unique name of the PD resource in GCE. - - Used to identify the disk in GCE. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - - :schema: io.k8s.api.core.v1.GCEPersistentDiskVolumeSource#pdName - ''' - result = self._values.get("pd_name") - assert result is not None, "Required property 'pd_name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def fs_type(self) -> typing.Optional[builtins.str]: - '''fsType is filesystem type of the volume that you want to mount. - - Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - - :schema: io.k8s.api.core.v1.GCEPersistentDiskVolumeSource#fsType - ''' - result = self._values.get("fs_type") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def partition(self) -> typing.Optional[jsii.Number]: - '''partition is the partition in the volume that you want to mount. - - If omitted, the default is to mount by volume name. Examples: For volume /dev/sda1, you specify the partition as "1". Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - - :schema: io.k8s.api.core.v1.GCEPersistentDiskVolumeSource#partition - ''' - result = self._values.get("partition") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def read_only(self) -> typing.Optional[builtins.bool]: - '''readOnly here will force the ReadOnly setting in VolumeMounts. - - Defaults to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - - :default: false. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - - :schema: io.k8s.api.core.v1.GCEPersistentDiskVolumeSource#readOnly - ''' - result = self._values.get("read_only") - return typing.cast(typing.Optional[builtins.bool], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "GcePersistentDiskVolumeSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.GitRepoVolumeSource", - jsii_struct_bases=[], - name_mapping={ - "repository": "repository", - "directory": "directory", - "revision": "revision", - }, -) -class GitRepoVolumeSource: - def __init__( - self, - *, - repository: builtins.str, - directory: typing.Optional[builtins.str] = None, - revision: typing.Optional[builtins.str] = None, - ) -> None: - '''Represents a volume that is populated with the contents of a git repository. - - Git repo volumes do not support ownership management. Git repo volumes support SELinux relabeling. - - DEPRECATED: GitRepo is deprecated. To provision a container with a git repo, mount an EmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir into the Pod's container. - - :param repository: repository is the URL. - :param directory: directory is the target directory name. Must not contain or start with '..'. If '.' is supplied, the volume directory will be the git repository. Otherwise, if specified, the volume will contain the git repository in the subdirectory with the given name. - :param revision: revision is the commit hash for the specified revision. - - :schema: io.k8s.api.core.v1.GitRepoVolumeSource - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__d3929ab9177d349a3cbc08144a071eb034b82c6d036e2f32c383d99193bfa2fc) - check_type(argname="argument repository", value=repository, expected_type=type_hints["repository"]) - check_type(argname="argument directory", value=directory, expected_type=type_hints["directory"]) - check_type(argname="argument revision", value=revision, expected_type=type_hints["revision"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "repository": repository, - } - if directory is not None: - self._values["directory"] = directory - if revision is not None: - self._values["revision"] = revision - - @builtins.property - def repository(self) -> builtins.str: - '''repository is the URL. - - :schema: io.k8s.api.core.v1.GitRepoVolumeSource#repository - ''' - result = self._values.get("repository") - assert result is not None, "Required property 'repository' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def directory(self) -> typing.Optional[builtins.str]: - '''directory is the target directory name. - - Must not contain or start with '..'. If '.' is supplied, the volume directory will be the git repository. Otherwise, if specified, the volume will contain the git repository in the subdirectory with the given name. - - :schema: io.k8s.api.core.v1.GitRepoVolumeSource#directory - ''' - result = self._values.get("directory") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def revision(self) -> typing.Optional[builtins.str]: - '''revision is the commit hash for the specified revision. - - :schema: io.k8s.api.core.v1.GitRepoVolumeSource#revision - ''' - result = self._values.get("revision") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "GitRepoVolumeSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.GlusterfsPersistentVolumeSource", - jsii_struct_bases=[], - name_mapping={ - "endpoints": "endpoints", - "path": "path", - "endpoints_namespace": "endpointsNamespace", - "read_only": "readOnly", - }, -) -class GlusterfsPersistentVolumeSource: - def __init__( - self, - *, - endpoints: builtins.str, - path: builtins.str, - endpoints_namespace: typing.Optional[builtins.str] = None, - read_only: typing.Optional[builtins.bool] = None, - ) -> None: - '''Represents a Glusterfs mount that lasts the lifetime of a pod. - - Glusterfs volumes do not support ownership management or SELinux relabeling. - - :param endpoints: endpoints is the endpoint name that details Glusterfs topology. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod - :param path: path is the Glusterfs volume path. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod - :param endpoints_namespace: endpointsNamespace is the namespace that contains Glusterfs endpoint. If this field is empty, the EndpointNamespace defaults to the same namespace as the bound PVC. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod - :param read_only: readOnly here will force the Glusterfs volume to be mounted with read-only permissions. Defaults to false. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod Default: false. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod - - :schema: io.k8s.api.core.v1.GlusterfsPersistentVolumeSource - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__77c2e679ddedc14c8c772b4af1c9ebb540b76f5b4ae46f0ddd7f13c3f9068d2e) - check_type(argname="argument endpoints", value=endpoints, expected_type=type_hints["endpoints"]) - check_type(argname="argument path", value=path, expected_type=type_hints["path"]) - check_type(argname="argument endpoints_namespace", value=endpoints_namespace, expected_type=type_hints["endpoints_namespace"]) - check_type(argname="argument read_only", value=read_only, expected_type=type_hints["read_only"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "endpoints": endpoints, - "path": path, - } - if endpoints_namespace is not None: - self._values["endpoints_namespace"] = endpoints_namespace - if read_only is not None: - self._values["read_only"] = read_only - - @builtins.property - def endpoints(self) -> builtins.str: - '''endpoints is the endpoint name that details Glusterfs topology. - - More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod - - :schema: io.k8s.api.core.v1.GlusterfsPersistentVolumeSource#endpoints - ''' - result = self._values.get("endpoints") - assert result is not None, "Required property 'endpoints' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def path(self) -> builtins.str: - '''path is the Glusterfs volume path. - - More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod - - :schema: io.k8s.api.core.v1.GlusterfsPersistentVolumeSource#path - ''' - result = self._values.get("path") - assert result is not None, "Required property 'path' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def endpoints_namespace(self) -> typing.Optional[builtins.str]: - '''endpointsNamespace is the namespace that contains Glusterfs endpoint. - - If this field is empty, the EndpointNamespace defaults to the same namespace as the bound PVC. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod - - :schema: io.k8s.api.core.v1.GlusterfsPersistentVolumeSource#endpointsNamespace - ''' - result = self._values.get("endpoints_namespace") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def read_only(self) -> typing.Optional[builtins.bool]: - '''readOnly here will force the Glusterfs volume to be mounted with read-only permissions. - - Defaults to false. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod - - :default: false. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod - - :schema: io.k8s.api.core.v1.GlusterfsPersistentVolumeSource#readOnly - ''' - result = self._values.get("read_only") - return typing.cast(typing.Optional[builtins.bool], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "GlusterfsPersistentVolumeSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.GlusterfsVolumeSource", - jsii_struct_bases=[], - name_mapping={"endpoints": "endpoints", "path": "path", "read_only": "readOnly"}, -) -class GlusterfsVolumeSource: - def __init__( - self, - *, - endpoints: builtins.str, - path: builtins.str, - read_only: typing.Optional[builtins.bool] = None, - ) -> None: - '''Represents a Glusterfs mount that lasts the lifetime of a pod. - - Glusterfs volumes do not support ownership management or SELinux relabeling. - - :param endpoints: endpoints is the endpoint name that details Glusterfs topology. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod - :param path: path is the Glusterfs volume path. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod - :param read_only: readOnly here will force the Glusterfs volume to be mounted with read-only permissions. Defaults to false. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod Default: false. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod - - :schema: io.k8s.api.core.v1.GlusterfsVolumeSource - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__ee9a1041172608f39bf295d6750ada62e4ab7bf9812fabbb918c35d5ff339178) - check_type(argname="argument endpoints", value=endpoints, expected_type=type_hints["endpoints"]) - check_type(argname="argument path", value=path, expected_type=type_hints["path"]) - check_type(argname="argument read_only", value=read_only, expected_type=type_hints["read_only"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "endpoints": endpoints, - "path": path, - } - if read_only is not None: - self._values["read_only"] = read_only - - @builtins.property - def endpoints(self) -> builtins.str: - '''endpoints is the endpoint name that details Glusterfs topology. - - More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod - - :schema: io.k8s.api.core.v1.GlusterfsVolumeSource#endpoints - ''' - result = self._values.get("endpoints") - assert result is not None, "Required property 'endpoints' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def path(self) -> builtins.str: - '''path is the Glusterfs volume path. - - More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod - - :schema: io.k8s.api.core.v1.GlusterfsVolumeSource#path - ''' - result = self._values.get("path") - assert result is not None, "Required property 'path' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def read_only(self) -> typing.Optional[builtins.bool]: - '''readOnly here will force the Glusterfs volume to be mounted with read-only permissions. - - Defaults to false. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod - - :default: false. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod - - :schema: io.k8s.api.core.v1.GlusterfsVolumeSource#readOnly - ''' - result = self._values.get("read_only") - return typing.cast(typing.Optional[builtins.bool], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "GlusterfsVolumeSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.GroupSubjectV1Beta2", - jsii_struct_bases=[], - name_mapping={"name": "name"}, -) -class GroupSubjectV1Beta2: - def __init__(self, *, name: builtins.str) -> None: - '''GroupSubject holds detailed information for group-kind subject. - - :param name: name is the user group that matches, or "*" to match all user groups. See https://github.com/kubernetes/apiserver/blob/master/pkg/authentication/user/user.go for some well-known group names. Required. - - :schema: io.k8s.api.flowcontrol.v1beta2.GroupSubject - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__ea5fa7eede3defacccd3e49dd371a89a25a4831d1e7a6ecb1660bf6a617768ed) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "name": name, - } - - @builtins.property - def name(self) -> builtins.str: - '''name is the user group that matches, or "*" to match all user groups. - - See https://github.com/kubernetes/apiserver/blob/master/pkg/authentication/user/user.go for some well-known group names. Required. - - :schema: io.k8s.api.flowcontrol.v1beta2.GroupSubject#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "GroupSubjectV1Beta2(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.GroupSubjectV1Beta3", - jsii_struct_bases=[], - name_mapping={"name": "name"}, -) -class GroupSubjectV1Beta3: - def __init__(self, *, name: builtins.str) -> None: - '''GroupSubject holds detailed information for group-kind subject. - - :param name: name is the user group that matches, or "*" to match all user groups. See https://github.com/kubernetes/apiserver/blob/master/pkg/authentication/user/user.go for some well-known group names. Required. - - :schema: io.k8s.api.flowcontrol.v1beta3.GroupSubject - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__812aaf4ed41fa0dc75191b6335a0c23c3c9c9b13e69060ba616483b441140f2e) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "name": name, - } - - @builtins.property - def name(self) -> builtins.str: - '''name is the user group that matches, or "*" to match all user groups. - - See https://github.com/kubernetes/apiserver/blob/master/pkg/authentication/user/user.go for some well-known group names. Required. - - :schema: io.k8s.api.flowcontrol.v1beta3.GroupSubject#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "GroupSubjectV1Beta3(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.GrpcAction", - jsii_struct_bases=[], - name_mapping={"port": "port", "service": "service"}, -) -class GrpcAction: - def __init__( - self, - *, - port: jsii.Number, - service: typing.Optional[builtins.str] = None, - ) -> None: - ''' - :param port: Port number of the gRPC service. Number must be in the range 1 to 65535. - :param service: Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). If this is not specified, the default behavior is defined by gRPC. - - :schema: io.k8s.api.core.v1.GRPCAction - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__a4c720717a12c121388433640f65c648a1215ba44d394b015fa52bde58de178d) - check_type(argname="argument port", value=port, expected_type=type_hints["port"]) - check_type(argname="argument service", value=service, expected_type=type_hints["service"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "port": port, - } - if service is not None: - self._values["service"] = service - - @builtins.property - def port(self) -> jsii.Number: - '''Port number of the gRPC service. - - Number must be in the range 1 to 65535. - - :schema: io.k8s.api.core.v1.GRPCAction#port - ''' - result = self._values.get("port") - assert result is not None, "Required property 'port' is missing" - return typing.cast(jsii.Number, result) - - @builtins.property - def service(self) -> typing.Optional[builtins.str]: - '''Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - - If this is not specified, the default behavior is defined by gRPC. - - :schema: io.k8s.api.core.v1.GRPCAction#service - ''' - result = self._values.get("service") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "GrpcAction(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.HorizontalPodAutoscalerBehaviorV2", - jsii_struct_bases=[], - name_mapping={"scale_down": "scaleDown", "scale_up": "scaleUp"}, -) -class HorizontalPodAutoscalerBehaviorV2: - def __init__( - self, - *, - scale_down: typing.Optional[typing.Union["HpaScalingRulesV2", typing.Dict[builtins.str, typing.Any]]] = None, - scale_up: typing.Optional[typing.Union["HpaScalingRulesV2", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''HorizontalPodAutoscalerBehavior configures the scaling behavior of the target in both Up and Down directions (scaleUp and scaleDown fields respectively). - - :param scale_down: scaleDown is scaling policy for scaling Down. If not set, the default value is to allow to scale down to minReplicas pods, with a 300 second stabilization window (i.e., the highest recommendation for the last 300sec is used). - :param scale_up: scaleUp is scaling policy for scaling Up. If not set, the default value is the higher of: - increase no more than 4 pods per 60 seconds - double the number of pods per 60 seconds No stabilization is used. - - :schema: io.k8s.api.autoscaling.v2.HorizontalPodAutoscalerBehavior - ''' - if isinstance(scale_down, dict): - scale_down = HpaScalingRulesV2(**scale_down) - if isinstance(scale_up, dict): - scale_up = HpaScalingRulesV2(**scale_up) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__fda77f8a90785391fbbcd3ca1c11f062fa6bf7ae954e80fb24e4e288fdd17832) - check_type(argname="argument scale_down", value=scale_down, expected_type=type_hints["scale_down"]) - check_type(argname="argument scale_up", value=scale_up, expected_type=type_hints["scale_up"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if scale_down is not None: - self._values["scale_down"] = scale_down - if scale_up is not None: - self._values["scale_up"] = scale_up - - @builtins.property - def scale_down(self) -> typing.Optional["HpaScalingRulesV2"]: - '''scaleDown is scaling policy for scaling Down. - - If not set, the default value is to allow to scale down to minReplicas pods, with a 300 second stabilization window (i.e., the highest recommendation for the last 300sec is used). - - :schema: io.k8s.api.autoscaling.v2.HorizontalPodAutoscalerBehavior#scaleDown - ''' - result = self._values.get("scale_down") - return typing.cast(typing.Optional["HpaScalingRulesV2"], result) - - @builtins.property - def scale_up(self) -> typing.Optional["HpaScalingRulesV2"]: - '''scaleUp is scaling policy for scaling Up. - - If not set, the default value is the higher of: - - - increase no more than 4 pods per 60 seconds - - double the number of pods per 60 seconds - No stabilization is used. - - :schema: io.k8s.api.autoscaling.v2.HorizontalPodAutoscalerBehavior#scaleUp - ''' - result = self._values.get("scale_up") - return typing.cast(typing.Optional["HpaScalingRulesV2"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "HorizontalPodAutoscalerBehaviorV2(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.HorizontalPodAutoscalerSpec", - jsii_struct_bases=[], - name_mapping={ - "max_replicas": "maxReplicas", - "scale_target_ref": "scaleTargetRef", - "min_replicas": "minReplicas", - "target_cpu_utilization_percentage": "targetCpuUtilizationPercentage", - }, -) -class HorizontalPodAutoscalerSpec: - def __init__( - self, - *, - max_replicas: jsii.Number, - scale_target_ref: typing.Union[CrossVersionObjectReference, typing.Dict[builtins.str, typing.Any]], - min_replicas: typing.Optional[jsii.Number] = None, - target_cpu_utilization_percentage: typing.Optional[jsii.Number] = None, - ) -> None: - '''specification of a horizontal pod autoscaler. - - :param max_replicas: upper limit for the number of pods that can be set by the autoscaler; cannot be smaller than MinReplicas. - :param scale_target_ref: reference to scaled resource; horizontal pod autoscaler will learn the current resource consumption and will set the desired number of pods by using its Scale subresource. - :param min_replicas: minReplicas is the lower limit for the number of replicas to which the autoscaler can scale down. It defaults to 1 pod. minReplicas is allowed to be 0 if the alpha feature gate HPAScaleToZero is enabled and at least one Object or External metric is configured. Scaling is active as long as at least one metric value is available. - :param target_cpu_utilization_percentage: target average CPU utilization (represented as a percentage of requested CPU) over all the pods; if not specified the default autoscaling policy will be used. - - :schema: io.k8s.api.autoscaling.v1.HorizontalPodAutoscalerSpec - ''' - if isinstance(scale_target_ref, dict): - scale_target_ref = CrossVersionObjectReference(**scale_target_ref) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__67e90701cb6e8283c6dcdce1a9bcefa03010668cc5c0dc412f36e77d3b94c2c6) - check_type(argname="argument max_replicas", value=max_replicas, expected_type=type_hints["max_replicas"]) - check_type(argname="argument scale_target_ref", value=scale_target_ref, expected_type=type_hints["scale_target_ref"]) - check_type(argname="argument min_replicas", value=min_replicas, expected_type=type_hints["min_replicas"]) - check_type(argname="argument target_cpu_utilization_percentage", value=target_cpu_utilization_percentage, expected_type=type_hints["target_cpu_utilization_percentage"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "max_replicas": max_replicas, - "scale_target_ref": scale_target_ref, - } - if min_replicas is not None: - self._values["min_replicas"] = min_replicas - if target_cpu_utilization_percentage is not None: - self._values["target_cpu_utilization_percentage"] = target_cpu_utilization_percentage - - @builtins.property - def max_replicas(self) -> jsii.Number: - '''upper limit for the number of pods that can be set by the autoscaler; - - cannot be smaller than MinReplicas. - - :schema: io.k8s.api.autoscaling.v1.HorizontalPodAutoscalerSpec#maxReplicas - ''' - result = self._values.get("max_replicas") - assert result is not None, "Required property 'max_replicas' is missing" - return typing.cast(jsii.Number, result) - - @builtins.property - def scale_target_ref(self) -> CrossVersionObjectReference: - '''reference to scaled resource; - - horizontal pod autoscaler will learn the current resource consumption and will set the desired number of pods by using its Scale subresource. - - :schema: io.k8s.api.autoscaling.v1.HorizontalPodAutoscalerSpec#scaleTargetRef - ''' - result = self._values.get("scale_target_ref") - assert result is not None, "Required property 'scale_target_ref' is missing" - return typing.cast(CrossVersionObjectReference, result) - - @builtins.property - def min_replicas(self) -> typing.Optional[jsii.Number]: - '''minReplicas is the lower limit for the number of replicas to which the autoscaler can scale down. - - It defaults to 1 pod. minReplicas is allowed to be 0 if the alpha feature gate HPAScaleToZero is enabled and at least one Object or External metric is configured. Scaling is active as long as at least one metric value is available. - - :schema: io.k8s.api.autoscaling.v1.HorizontalPodAutoscalerSpec#minReplicas - ''' - result = self._values.get("min_replicas") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def target_cpu_utilization_percentage(self) -> typing.Optional[jsii.Number]: - '''target average CPU utilization (represented as a percentage of requested CPU) over all the pods; - - if not specified the default autoscaling policy will be used. - - :schema: io.k8s.api.autoscaling.v1.HorizontalPodAutoscalerSpec#targetCPUUtilizationPercentage - ''' - result = self._values.get("target_cpu_utilization_percentage") - return typing.cast(typing.Optional[jsii.Number], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "HorizontalPodAutoscalerSpec(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.HorizontalPodAutoscalerSpecV2", - jsii_struct_bases=[], - name_mapping={ - "max_replicas": "maxReplicas", - "scale_target_ref": "scaleTargetRef", - "behavior": "behavior", - "metrics": "metrics", - "min_replicas": "minReplicas", - }, -) -class HorizontalPodAutoscalerSpecV2: - def __init__( - self, - *, - max_replicas: jsii.Number, - scale_target_ref: typing.Union[CrossVersionObjectReferenceV2, typing.Dict[builtins.str, typing.Any]], - behavior: typing.Optional[typing.Union[HorizontalPodAutoscalerBehaviorV2, typing.Dict[builtins.str, typing.Any]]] = None, - metrics: typing.Optional[typing.Sequence[typing.Union["MetricSpecV2", typing.Dict[builtins.str, typing.Any]]]] = None, - min_replicas: typing.Optional[jsii.Number] = None, - ) -> None: - '''HorizontalPodAutoscalerSpec describes the desired functionality of the HorizontalPodAutoscaler. - - :param max_replicas: maxReplicas is the upper limit for the number of replicas to which the autoscaler can scale up. It cannot be less that minReplicas. - :param scale_target_ref: scaleTargetRef points to the target resource to scale, and is used to the pods for which metrics should be collected, as well as to actually change the replica count. - :param behavior: behavior configures the scaling behavior of the target in both Up and Down directions (scaleUp and scaleDown fields respectively). If not set, the default HPAScalingRules for scale up and scale down are used. - :param metrics: metrics contains the specifications for which to use to calculate the desired replica count (the maximum replica count across all metrics will be used). The desired replica count is calculated multiplying the ratio between the target value and the current value by the current number of pods. Ergo, metrics used must decrease as the pod count is increased, and vice-versa. See the individual metric source types for more information about how each type of metric must respond. If not set, the default metric will be set to 80% average CPU utilization. - :param min_replicas: minReplicas is the lower limit for the number of replicas to which the autoscaler can scale down. It defaults to 1 pod. minReplicas is allowed to be 0 if the alpha feature gate HPAScaleToZero is enabled and at least one Object or External metric is configured. Scaling is active as long as at least one metric value is available. - - :schema: io.k8s.api.autoscaling.v2.HorizontalPodAutoscalerSpec - ''' - if isinstance(scale_target_ref, dict): - scale_target_ref = CrossVersionObjectReferenceV2(**scale_target_ref) - if isinstance(behavior, dict): - behavior = HorizontalPodAutoscalerBehaviorV2(**behavior) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__a1323a69e978b64e93ef7f04e8455a1c9a9c3bb874ab3f67e7522bf7d2a07c64) - check_type(argname="argument max_replicas", value=max_replicas, expected_type=type_hints["max_replicas"]) - check_type(argname="argument scale_target_ref", value=scale_target_ref, expected_type=type_hints["scale_target_ref"]) - check_type(argname="argument behavior", value=behavior, expected_type=type_hints["behavior"]) - check_type(argname="argument metrics", value=metrics, expected_type=type_hints["metrics"]) - check_type(argname="argument min_replicas", value=min_replicas, expected_type=type_hints["min_replicas"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "max_replicas": max_replicas, - "scale_target_ref": scale_target_ref, - } - if behavior is not None: - self._values["behavior"] = behavior - if metrics is not None: - self._values["metrics"] = metrics - if min_replicas is not None: - self._values["min_replicas"] = min_replicas - - @builtins.property - def max_replicas(self) -> jsii.Number: - '''maxReplicas is the upper limit for the number of replicas to which the autoscaler can scale up. - - It cannot be less that minReplicas. - - :schema: io.k8s.api.autoscaling.v2.HorizontalPodAutoscalerSpec#maxReplicas - ''' - result = self._values.get("max_replicas") - assert result is not None, "Required property 'max_replicas' is missing" - return typing.cast(jsii.Number, result) - - @builtins.property - def scale_target_ref(self) -> CrossVersionObjectReferenceV2: - '''scaleTargetRef points to the target resource to scale, and is used to the pods for which metrics should be collected, as well as to actually change the replica count. - - :schema: io.k8s.api.autoscaling.v2.HorizontalPodAutoscalerSpec#scaleTargetRef - ''' - result = self._values.get("scale_target_ref") - assert result is not None, "Required property 'scale_target_ref' is missing" - return typing.cast(CrossVersionObjectReferenceV2, result) - - @builtins.property - def behavior(self) -> typing.Optional[HorizontalPodAutoscalerBehaviorV2]: - '''behavior configures the scaling behavior of the target in both Up and Down directions (scaleUp and scaleDown fields respectively). - - If not set, the default HPAScalingRules for scale up and scale down are used. - - :schema: io.k8s.api.autoscaling.v2.HorizontalPodAutoscalerSpec#behavior - ''' - result = self._values.get("behavior") - return typing.cast(typing.Optional[HorizontalPodAutoscalerBehaviorV2], result) - - @builtins.property - def metrics(self) -> typing.Optional[typing.List["MetricSpecV2"]]: - '''metrics contains the specifications for which to use to calculate the desired replica count (the maximum replica count across all metrics will be used). - - The desired replica count is calculated multiplying the ratio between the target value and the current value by the current number of pods. Ergo, metrics used must decrease as the pod count is increased, and vice-versa. See the individual metric source types for more information about how each type of metric must respond. If not set, the default metric will be set to 80% average CPU utilization. - - :schema: io.k8s.api.autoscaling.v2.HorizontalPodAutoscalerSpec#metrics - ''' - result = self._values.get("metrics") - return typing.cast(typing.Optional[typing.List["MetricSpecV2"]], result) - - @builtins.property - def min_replicas(self) -> typing.Optional[jsii.Number]: - '''minReplicas is the lower limit for the number of replicas to which the autoscaler can scale down. - - It defaults to 1 pod. minReplicas is allowed to be 0 if the alpha feature gate HPAScaleToZero is enabled and at least one Object or External metric is configured. Scaling is active as long as at least one metric value is available. - - :schema: io.k8s.api.autoscaling.v2.HorizontalPodAutoscalerSpec#minReplicas - ''' - result = self._values.get("min_replicas") - return typing.cast(typing.Optional[jsii.Number], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "HorizontalPodAutoscalerSpecV2(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.HostAlias", - jsii_struct_bases=[], - name_mapping={"hostnames": "hostnames", "ip": "ip"}, -) -class HostAlias: - def __init__( - self, - *, - hostnames: typing.Optional[typing.Sequence[builtins.str]] = None, - ip: typing.Optional[builtins.str] = None, - ) -> None: - '''HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the pod's hosts file. - - :param hostnames: Hostnames for the above IP address. - :param ip: IP address of the host file entry. - - :schema: io.k8s.api.core.v1.HostAlias - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__baf1f258035adb05fce6a499ac90c7c683c23515cb2387103291d65c150db057) - check_type(argname="argument hostnames", value=hostnames, expected_type=type_hints["hostnames"]) - check_type(argname="argument ip", value=ip, expected_type=type_hints["ip"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if hostnames is not None: - self._values["hostnames"] = hostnames - if ip is not None: - self._values["ip"] = ip - - @builtins.property - def hostnames(self) -> typing.Optional[typing.List[builtins.str]]: - '''Hostnames for the above IP address. - - :schema: io.k8s.api.core.v1.HostAlias#hostnames - ''' - result = self._values.get("hostnames") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def ip(self) -> typing.Optional[builtins.str]: - '''IP address of the host file entry. - - :schema: io.k8s.api.core.v1.HostAlias#ip - ''' - result = self._values.get("ip") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "HostAlias(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.HostPathVolumeSource", - jsii_struct_bases=[], - name_mapping={"path": "path", "type": "type"}, -) -class HostPathVolumeSource: - def __init__( - self, - *, - path: builtins.str, - type: typing.Optional[builtins.str] = None, - ) -> None: - '''Represents a host path mapped into a pod. - - Host path volumes do not support ownership management or SELinux relabeling. - - :param path: path of the directory on the host. If the path is a symlink, it will follow the link to the real path. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - :param type: type for HostPath Volume Defaults to "" More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath. Default: More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - - :schema: io.k8s.api.core.v1.HostPathVolumeSource - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__6e89b87d54e04bd3a5ed5104bd9aeeebc90ed613bc0805a39560bc2bbf615e55) - check_type(argname="argument path", value=path, expected_type=type_hints["path"]) - check_type(argname="argument type", value=type, expected_type=type_hints["type"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "path": path, - } - if type is not None: - self._values["type"] = type - - @builtins.property - def path(self) -> builtins.str: - '''path of the directory on the host. - - If the path is a symlink, it will follow the link to the real path. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - - :schema: io.k8s.api.core.v1.HostPathVolumeSource#path - ''' - result = self._values.get("path") - assert result is not None, "Required property 'path' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def type(self) -> typing.Optional[builtins.str]: - '''type for HostPath Volume Defaults to "" More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath. - - :default: More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - - :schema: io.k8s.api.core.v1.HostPathVolumeSource#type - ''' - result = self._values.get("type") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "HostPathVolumeSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.HpaScalingPolicyV2", - jsii_struct_bases=[], - name_mapping={"period_seconds": "periodSeconds", "type": "type", "value": "value"}, -) -class HpaScalingPolicyV2: - def __init__( - self, - *, - period_seconds: jsii.Number, - type: builtins.str, - value: jsii.Number, - ) -> None: - '''HPAScalingPolicy is a single policy which must hold true for a specified past interval. - - :param period_seconds: PeriodSeconds specifies the window of time for which the policy should hold true. PeriodSeconds must be greater than zero and less than or equal to 1800 (30 min). - :param type: Type is used to specify the scaling policy. - :param value: Value contains the amount of change which is permitted by the policy. It must be greater than zero - - :schema: io.k8s.api.autoscaling.v2.HPAScalingPolicy - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__aeb589a0fa4d0cc40251749153c9f79afe4dfc58697049ab09f63ee4925eb96d) - check_type(argname="argument period_seconds", value=period_seconds, expected_type=type_hints["period_seconds"]) - check_type(argname="argument type", value=type, expected_type=type_hints["type"]) - check_type(argname="argument value", value=value, expected_type=type_hints["value"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "period_seconds": period_seconds, - "type": type, - "value": value, - } - - @builtins.property - def period_seconds(self) -> jsii.Number: - '''PeriodSeconds specifies the window of time for which the policy should hold true. - - PeriodSeconds must be greater than zero and less than or equal to 1800 (30 min). - - :schema: io.k8s.api.autoscaling.v2.HPAScalingPolicy#periodSeconds - ''' - result = self._values.get("period_seconds") - assert result is not None, "Required property 'period_seconds' is missing" - return typing.cast(jsii.Number, result) - - @builtins.property - def type(self) -> builtins.str: - '''Type is used to specify the scaling policy. - - :schema: io.k8s.api.autoscaling.v2.HPAScalingPolicy#type - ''' - result = self._values.get("type") - assert result is not None, "Required property 'type' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def value(self) -> jsii.Number: - '''Value contains the amount of change which is permitted by the policy. - - It must be greater than zero - - :schema: io.k8s.api.autoscaling.v2.HPAScalingPolicy#value - ''' - result = self._values.get("value") - assert result is not None, "Required property 'value' is missing" - return typing.cast(jsii.Number, result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "HpaScalingPolicyV2(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.HpaScalingRulesV2", - jsii_struct_bases=[], - name_mapping={ - "policies": "policies", - "select_policy": "selectPolicy", - "stabilization_window_seconds": "stabilizationWindowSeconds", - }, -) -class HpaScalingRulesV2: - def __init__( - self, - *, - policies: typing.Optional[typing.Sequence[typing.Union[HpaScalingPolicyV2, typing.Dict[builtins.str, typing.Any]]]] = None, - select_policy: typing.Optional[builtins.str] = None, - stabilization_window_seconds: typing.Optional[jsii.Number] = None, - ) -> None: - '''HPAScalingRules configures the scaling behavior for one direction. - - These Rules are applied after calculating DesiredReplicas from metrics for the HPA. They can limit the scaling velocity by specifying scaling policies. They can prevent flapping by specifying the stabilization window, so that the number of replicas is not set instantly, instead, the safest value from the stabilization window is chosen. - - :param policies: policies is a list of potential scaling polices which can be used during scaling. At least one policy must be specified, otherwise the HPAScalingRules will be discarded as invalid - :param select_policy: selectPolicy is used to specify which policy should be used. If not set, the default value Max is used. - :param stabilization_window_seconds: StabilizationWindowSeconds is the number of seconds for which past recommendations should be considered while scaling up or scaling down. StabilizationWindowSeconds must be greater than or equal to zero and less than or equal to 3600 (one hour). If not set, use the default values: - For scale up: 0 (i.e. no stabilization is done). - For scale down: 300 (i.e. the stabilization window is 300 seconds long). - - :schema: io.k8s.api.autoscaling.v2.HPAScalingRules - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__01955266417ee884ef4e85d0ff6d261477e416614ba711701a5aa2f989ee95ae) - check_type(argname="argument policies", value=policies, expected_type=type_hints["policies"]) - check_type(argname="argument select_policy", value=select_policy, expected_type=type_hints["select_policy"]) - check_type(argname="argument stabilization_window_seconds", value=stabilization_window_seconds, expected_type=type_hints["stabilization_window_seconds"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if policies is not None: - self._values["policies"] = policies - if select_policy is not None: - self._values["select_policy"] = select_policy - if stabilization_window_seconds is not None: - self._values["stabilization_window_seconds"] = stabilization_window_seconds - - @builtins.property - def policies(self) -> typing.Optional[typing.List[HpaScalingPolicyV2]]: - '''policies is a list of potential scaling polices which can be used during scaling. - - At least one policy must be specified, otherwise the HPAScalingRules will be discarded as invalid - - :schema: io.k8s.api.autoscaling.v2.HPAScalingRules#policies - ''' - result = self._values.get("policies") - return typing.cast(typing.Optional[typing.List[HpaScalingPolicyV2]], result) - - @builtins.property - def select_policy(self) -> typing.Optional[builtins.str]: - '''selectPolicy is used to specify which policy should be used. - - If not set, the default value Max is used. - - :schema: io.k8s.api.autoscaling.v2.HPAScalingRules#selectPolicy - ''' - result = self._values.get("select_policy") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def stabilization_window_seconds(self) -> typing.Optional[jsii.Number]: - '''StabilizationWindowSeconds is the number of seconds for which past recommendations should be considered while scaling up or scaling down. - - StabilizationWindowSeconds must be greater than or equal to zero and less than or equal to 3600 (one hour). If not set, use the default values: - For scale up: 0 (i.e. no stabilization is done). - For scale down: 300 (i.e. the stabilization window is 300 seconds long). - - :schema: io.k8s.api.autoscaling.v2.HPAScalingRules#stabilizationWindowSeconds - ''' - result = self._values.get("stabilization_window_seconds") - return typing.cast(typing.Optional[jsii.Number], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "HpaScalingRulesV2(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.HttpGetAction", - jsii_struct_bases=[], - name_mapping={ - "port": "port", - "host": "host", - "http_headers": "httpHeaders", - "path": "path", - "scheme": "scheme", - }, -) -class HttpGetAction: - def __init__( - self, - *, - port: "IntOrString", - host: typing.Optional[builtins.str] = None, - http_headers: typing.Optional[typing.Sequence[typing.Union["HttpHeader", typing.Dict[builtins.str, typing.Any]]]] = None, - path: typing.Optional[builtins.str] = None, - scheme: typing.Optional[builtins.str] = None, - ) -> None: - '''HTTPGetAction describes an action based on HTTP Get requests. - - :param port: Name or number of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. - :param host: Host name to connect to, defaults to the pod IP. You probably want to set "Host" in httpHeaders instead. - :param http_headers: Custom headers to set in the request. HTTP allows repeated headers. - :param path: Path to access on the HTTP server. - :param scheme: Scheme to use for connecting to the host. Defaults to HTTP. Default: HTTP. - - :schema: io.k8s.api.core.v1.HTTPGetAction - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__62efc5742934988596159a1c4328467a5bf15711d92d0298db109be22da42dbc) - check_type(argname="argument port", value=port, expected_type=type_hints["port"]) - check_type(argname="argument host", value=host, expected_type=type_hints["host"]) - check_type(argname="argument http_headers", value=http_headers, expected_type=type_hints["http_headers"]) - check_type(argname="argument path", value=path, expected_type=type_hints["path"]) - check_type(argname="argument scheme", value=scheme, expected_type=type_hints["scheme"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "port": port, - } - if host is not None: - self._values["host"] = host - if http_headers is not None: - self._values["http_headers"] = http_headers - if path is not None: - self._values["path"] = path - if scheme is not None: - self._values["scheme"] = scheme - - @builtins.property - def port(self) -> "IntOrString": - '''Name or number of the port to access on the container. - - Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. - - :schema: io.k8s.api.core.v1.HTTPGetAction#port - ''' - result = self._values.get("port") - assert result is not None, "Required property 'port' is missing" - return typing.cast("IntOrString", result) - - @builtins.property - def host(self) -> typing.Optional[builtins.str]: - '''Host name to connect to, defaults to the pod IP. - - You probably want to set "Host" in httpHeaders instead. - - :schema: io.k8s.api.core.v1.HTTPGetAction#host - ''' - result = self._values.get("host") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def http_headers(self) -> typing.Optional[typing.List["HttpHeader"]]: - '''Custom headers to set in the request. - - HTTP allows repeated headers. - - :schema: io.k8s.api.core.v1.HTTPGetAction#httpHeaders - ''' - result = self._values.get("http_headers") - return typing.cast(typing.Optional[typing.List["HttpHeader"]], result) - - @builtins.property - def path(self) -> typing.Optional[builtins.str]: - '''Path to access on the HTTP server. - - :schema: io.k8s.api.core.v1.HTTPGetAction#path - ''' - result = self._values.get("path") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def scheme(self) -> typing.Optional[builtins.str]: - '''Scheme to use for connecting to the host. - - Defaults to HTTP. - - :default: HTTP. - - :schema: io.k8s.api.core.v1.HTTPGetAction#scheme - ''' - result = self._values.get("scheme") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "HttpGetAction(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.HttpHeader", - jsii_struct_bases=[], - name_mapping={"name": "name", "value": "value"}, -) -class HttpHeader: - def __init__(self, *, name: builtins.str, value: builtins.str) -> None: - '''HTTPHeader describes a custom header to be used in HTTP probes. - - :param name: The header field name. - :param value: The header field value. - - :schema: io.k8s.api.core.v1.HTTPHeader - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__65a4ad915e61cf4f8034eb768af84855c5eb30565af7046319e9debb114d6dbf) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument value", value=value, expected_type=type_hints["value"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "name": name, - "value": value, - } - - @builtins.property - def name(self) -> builtins.str: - '''The header field name. - - :schema: io.k8s.api.core.v1.HTTPHeader#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def value(self) -> builtins.str: - '''The header field value. - - :schema: io.k8s.api.core.v1.HTTPHeader#value - ''' - result = self._values.get("value") - assert result is not None, "Required property 'value' is missing" - return typing.cast(builtins.str, result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "HttpHeader(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.HttpIngressPath", - jsii_struct_bases=[], - name_mapping={"backend": "backend", "path_type": "pathType", "path": "path"}, -) -class HttpIngressPath: - def __init__( - self, - *, - backend: typing.Union["IngressBackend", typing.Dict[builtins.str, typing.Any]], - path_type: builtins.str, - path: typing.Optional[builtins.str] = None, - ) -> None: - '''HTTPIngressPath associates a path with a backend. - - Incoming urls matching the path are forwarded to the backend. - - :param backend: Backend defines the referenced service endpoint to which the traffic will be forwarded to. - :param path_type: PathType determines the interpretation of the Path matching. PathType can be one of the following values: * Exact: Matches the URL path exactly. * Prefix: Matches based on a URL path prefix split by '/'. Matching is done on a path element by element basis. A path element refers is the list of labels in the path split by the '/' separator. A request is a match for path p if every p is an element-wise prefix of p of the request path. Note that if the last element of the path is a substring of the last element in request path, it is not a match (e.g. /foo/bar matches /foo/bar/baz, but does not match /foo/barbaz). - ImplementationSpecific: Interpretation of the Path matching is up to the IngressClass. Implementations can treat this as a separate PathType or treat it identically to Prefix or Exact path types. Implementations are required to support all path types. - :param path: Path is matched against the path of an incoming request. Currently it can contain characters disallowed from the conventional "path" part of a URL as defined by RFC 3986. Paths must begin with a '/' and must be present when using PathType with value "Exact" or "Prefix". - - :schema: io.k8s.api.networking.v1.HTTPIngressPath - ''' - if isinstance(backend, dict): - backend = IngressBackend(**backend) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__1cca829c509cb330ab5cf95c6fc26b20f21813dc375800b70fcbfdfeec2654c5) - check_type(argname="argument backend", value=backend, expected_type=type_hints["backend"]) - check_type(argname="argument path_type", value=path_type, expected_type=type_hints["path_type"]) - check_type(argname="argument path", value=path, expected_type=type_hints["path"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "backend": backend, - "path_type": path_type, - } - if path is not None: - self._values["path"] = path - - @builtins.property - def backend(self) -> "IngressBackend": - '''Backend defines the referenced service endpoint to which the traffic will be forwarded to. - - :schema: io.k8s.api.networking.v1.HTTPIngressPath#backend - ''' - result = self._values.get("backend") - assert result is not None, "Required property 'backend' is missing" - return typing.cast("IngressBackend", result) - - @builtins.property - def path_type(self) -> builtins.str: - '''PathType determines the interpretation of the Path matching. - - PathType can be one of the following values: * Exact: Matches the URL path exactly. * Prefix: Matches based on a URL path prefix split by '/'. Matching is - done on a path element by element basis. A path element refers is the - list of labels in the path split by the '/' separator. A request is a - match for path p if every p is an element-wise prefix of p of the - request path. Note that if the last element of the path is a substring - of the last element in request path, it is not a match (e.g. /foo/bar - matches /foo/bar/baz, but does not match /foo/barbaz). - - - ImplementationSpecific: Interpretation of the Path matching is up to - the IngressClass. Implementations can treat this as a separate PathType - or treat it identically to Prefix or Exact path types. - Implementations are required to support all path types. - - :schema: io.k8s.api.networking.v1.HTTPIngressPath#pathType - ''' - result = self._values.get("path_type") - assert result is not None, "Required property 'path_type' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def path(self) -> typing.Optional[builtins.str]: - '''Path is matched against the path of an incoming request. - - Currently it can contain characters disallowed from the conventional "path" part of a URL as defined by RFC 3986. Paths must begin with a '/' and must be present when using PathType with value "Exact" or "Prefix". - - :schema: io.k8s.api.networking.v1.HTTPIngressPath#path - ''' - result = self._values.get("path") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "HttpIngressPath(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.HttpIngressRuleValue", - jsii_struct_bases=[], - name_mapping={"paths": "paths"}, -) -class HttpIngressRuleValue: - def __init__( - self, - *, - paths: typing.Sequence[typing.Union[HttpIngressPath, typing.Dict[builtins.str, typing.Any]]], - ) -> None: - '''HTTPIngressRuleValue is a list of http selectors pointing to backends. - - In the example: http:///? -> backend where where parts of the url correspond to RFC 3986, this resource will be used to match against everything after the last '/' and before the first '?' or '#'. - - :param paths: A collection of paths that map requests to backends. - - :schema: io.k8s.api.networking.v1.HTTPIngressRuleValue - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__05cd1df4bce67e8fa976f9efada12c170538e64a48328c5f255efdebc8f61d9a) - check_type(argname="argument paths", value=paths, expected_type=type_hints["paths"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "paths": paths, - } - - @builtins.property - def paths(self) -> typing.List[HttpIngressPath]: - '''A collection of paths that map requests to backends. - - :schema: io.k8s.api.networking.v1.HTTPIngressRuleValue#paths - ''' - result = self._values.get("paths") - assert result is not None, "Required property 'paths' is missing" - return typing.cast(typing.List[HttpIngressPath], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "HttpIngressRuleValue(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.IngressBackend", - jsii_struct_bases=[], - name_mapping={"resource": "resource", "service": "service"}, -) -class IngressBackend: - def __init__( - self, - *, - resource: typing.Optional[typing.Union["TypedLocalObjectReference", typing.Dict[builtins.str, typing.Any]]] = None, - service: typing.Optional[typing.Union["IngressServiceBackend", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''IngressBackend describes all endpoints for a given service and port. - - :param resource: Resource is an ObjectRef to another Kubernetes resource in the namespace of the Ingress object. If resource is specified, a service.Name and service.Port must not be specified. This is a mutually exclusive setting with "Service". - :param service: Service references a Service as a Backend. This is a mutually exclusive setting with "Resource". - - :schema: io.k8s.api.networking.v1.IngressBackend - ''' - if isinstance(resource, dict): - resource = TypedLocalObjectReference(**resource) - if isinstance(service, dict): - service = IngressServiceBackend(**service) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__df26b528fe90e75693923674dff2a906cecf821611adf7cf1d7a6745fd0cd715) - check_type(argname="argument resource", value=resource, expected_type=type_hints["resource"]) - check_type(argname="argument service", value=service, expected_type=type_hints["service"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if resource is not None: - self._values["resource"] = resource - if service is not None: - self._values["service"] = service - - @builtins.property - def resource(self) -> typing.Optional["TypedLocalObjectReference"]: - '''Resource is an ObjectRef to another Kubernetes resource in the namespace of the Ingress object. - - If resource is specified, a service.Name and service.Port must not be specified. This is a mutually exclusive setting with "Service". - - :schema: io.k8s.api.networking.v1.IngressBackend#resource - ''' - result = self._values.get("resource") - return typing.cast(typing.Optional["TypedLocalObjectReference"], result) - - @builtins.property - def service(self) -> typing.Optional["IngressServiceBackend"]: - '''Service references a Service as a Backend. - - This is a mutually exclusive setting with "Resource". - - :schema: io.k8s.api.networking.v1.IngressBackend#service - ''' - result = self._values.get("service") - return typing.cast(typing.Optional["IngressServiceBackend"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "IngressBackend(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.IngressClassParametersReference", - jsii_struct_bases=[], - name_mapping={ - "kind": "kind", - "name": "name", - "api_group": "apiGroup", - "namespace": "namespace", - "scope": "scope", - }, -) -class IngressClassParametersReference: - def __init__( - self, - *, - kind: builtins.str, - name: builtins.str, - api_group: typing.Optional[builtins.str] = None, - namespace: typing.Optional[builtins.str] = None, - scope: typing.Optional[builtins.str] = None, - ) -> None: - '''IngressClassParametersReference identifies an API object. - - This can be used to specify a cluster or namespace-scoped resource. - - :param kind: Kind is the type of resource being referenced. - :param name: Name is the name of resource being referenced. - :param api_group: APIGroup is the group for the resource being referenced. If APIGroup is not specified, the specified Kind must be in the core API group. For any other third-party types, APIGroup is required. - :param namespace: Namespace is the namespace of the resource being referenced. This field is required when scope is set to "Namespace" and must be unset when scope is set to "Cluster". - :param scope: Scope represents if this refers to a cluster or namespace scoped resource. This may be set to "Cluster" (default) or "Namespace". - - :schema: io.k8s.api.networking.v1.IngressClassParametersReference - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__b55c86b8fa568f61df7bfe266dca0075b336f1056df734d8a5f9f6b5116eadc6) - check_type(argname="argument kind", value=kind, expected_type=type_hints["kind"]) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument api_group", value=api_group, expected_type=type_hints["api_group"]) - check_type(argname="argument namespace", value=namespace, expected_type=type_hints["namespace"]) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "kind": kind, - "name": name, - } - if api_group is not None: - self._values["api_group"] = api_group - if namespace is not None: - self._values["namespace"] = namespace - if scope is not None: - self._values["scope"] = scope - - @builtins.property - def kind(self) -> builtins.str: - '''Kind is the type of resource being referenced. - - :schema: io.k8s.api.networking.v1.IngressClassParametersReference#kind - ''' - result = self._values.get("kind") - assert result is not None, "Required property 'kind' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def name(self) -> builtins.str: - '''Name is the name of resource being referenced. - - :schema: io.k8s.api.networking.v1.IngressClassParametersReference#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def api_group(self) -> typing.Optional[builtins.str]: - '''APIGroup is the group for the resource being referenced. - - If APIGroup is not specified, the specified Kind must be in the core API group. For any other third-party types, APIGroup is required. - - :schema: io.k8s.api.networking.v1.IngressClassParametersReference#apiGroup - ''' - result = self._values.get("api_group") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def namespace(self) -> typing.Optional[builtins.str]: - '''Namespace is the namespace of the resource being referenced. - - This field is required when scope is set to "Namespace" and must be unset when scope is set to "Cluster". - - :schema: io.k8s.api.networking.v1.IngressClassParametersReference#namespace - ''' - result = self._values.get("namespace") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def scope(self) -> typing.Optional[builtins.str]: - '''Scope represents if this refers to a cluster or namespace scoped resource. - - This may be set to "Cluster" (default) or "Namespace". - - :schema: io.k8s.api.networking.v1.IngressClassParametersReference#scope - ''' - result = self._values.get("scope") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "IngressClassParametersReference(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.IngressClassSpec", - jsii_struct_bases=[], - name_mapping={"controller": "controller", "parameters": "parameters"}, -) -class IngressClassSpec: - def __init__( - self, - *, - controller: typing.Optional[builtins.str] = None, - parameters: typing.Optional[typing.Union[IngressClassParametersReference, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''IngressClassSpec provides information about the class of an Ingress. - - :param controller: Controller refers to the name of the controller that should handle this class. This allows for different "flavors" that are controlled by the same controller. For example, you may have different Parameters for the same implementing controller. This should be specified as a domain-prefixed path no more than 250 characters in length, e.g. "acme.io/ingress-controller". This field is immutable. - :param parameters: Parameters is a link to a custom resource containing additional configuration for the controller. This is optional if the controller does not require extra parameters. - - :schema: io.k8s.api.networking.v1.IngressClassSpec - ''' - if isinstance(parameters, dict): - parameters = IngressClassParametersReference(**parameters) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__9135d7f530914c8efd0036d3c9b7f8302e7bf5f1a915332fbf5ddccf196262d1) - check_type(argname="argument controller", value=controller, expected_type=type_hints["controller"]) - check_type(argname="argument parameters", value=parameters, expected_type=type_hints["parameters"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if controller is not None: - self._values["controller"] = controller - if parameters is not None: - self._values["parameters"] = parameters - - @builtins.property - def controller(self) -> typing.Optional[builtins.str]: - '''Controller refers to the name of the controller that should handle this class. - - This allows for different "flavors" that are controlled by the same controller. For example, you may have different Parameters for the same implementing controller. This should be specified as a domain-prefixed path no more than 250 characters in length, e.g. "acme.io/ingress-controller". This field is immutable. - - :schema: io.k8s.api.networking.v1.IngressClassSpec#controller - ''' - result = self._values.get("controller") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def parameters(self) -> typing.Optional[IngressClassParametersReference]: - '''Parameters is a link to a custom resource containing additional configuration for the controller. - - This is optional if the controller does not require extra parameters. - - :schema: io.k8s.api.networking.v1.IngressClassSpec#parameters - ''' - result = self._values.get("parameters") - return typing.cast(typing.Optional[IngressClassParametersReference], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "IngressClassSpec(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.IngressRule", - jsii_struct_bases=[], - name_mapping={"host": "host", "http": "http"}, -) -class IngressRule: - def __init__( - self, - *, - host: typing.Optional[builtins.str] = None, - http: typing.Optional[typing.Union[HttpIngressRuleValue, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''IngressRule represents the rules mapping the paths under a specified host to the related backend services. - - Incoming requests are first evaluated for a host match, then routed to the backend associated with the matching IngressRuleValue. - - :param host: Host is the fully qualified domain name of a network host, as defined by RFC 3986. Note the following deviations from the "host" part of the URI as defined in RFC 3986: 1. IPs are not allowed. Currently an IngressRuleValue can only apply to the IP in the Spec of the parent Ingress. 2. The ``:`` delimiter is not respected because ports are not allowed. Currently the port of an Ingress is implicitly :80 for http and :443 for https. Both these may change in the future. Incoming requests are matched against the host before the IngressRuleValue. If the host is unspecified, the Ingress routes all traffic based on the specified IngressRuleValue. Host can be "precise" which is a domain name without the terminating dot of a network host (e.g. "foo.bar.com") or "wildcard", which is a domain name prefixed with a single wildcard label (e.g. "*.foo.com"). The wildcard character '*' must appear by itself as the first DNS label and matches only a single label. You cannot have a wildcard label by itself (e.g. Host == "*"). Requests will be matched against the Host field in the following way: 1. If Host is precise, the request matches this rule if the http host header is equal to Host. 2. If Host is a wildcard, then the request matches this rule if the http host header is to equal to the suffix (removing the first label) of the wildcard rule. - :param http: - - :schema: io.k8s.api.networking.v1.IngressRule - ''' - if isinstance(http, dict): - http = HttpIngressRuleValue(**http) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__f579f76985685fddfa2343f3fdb2f56b0ad569a16de003c2209b63ace70d1fee) - check_type(argname="argument host", value=host, expected_type=type_hints["host"]) - check_type(argname="argument http", value=http, expected_type=type_hints["http"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if host is not None: - self._values["host"] = host - if http is not None: - self._values["http"] = http - - @builtins.property - def host(self) -> typing.Optional[builtins.str]: - '''Host is the fully qualified domain name of a network host, as defined by RFC 3986. - - Note the following deviations from the "host" part of the URI as defined in RFC 3986: 1. IPs are not allowed. Currently an IngressRuleValue can only apply to - the IP in the Spec of the parent Ingress. - 2. The ``:`` delimiter is not respected because ports are not allowed. - Currently the port of an Ingress is implicitly :80 for http and - :443 for https. - Both these may change in the future. Incoming requests are matched against the host before the IngressRuleValue. If the host is unspecified, the Ingress routes all traffic based on the specified IngressRuleValue. - - Host can be "precise" which is a domain name without the terminating dot of a network host (e.g. "foo.bar.com") or "wildcard", which is a domain name prefixed with a single wildcard label (e.g. "*.foo.com"). The wildcard character '*' must appear by itself as the first DNS label and matches only a single label. You cannot have a wildcard label by itself (e.g. Host == "*"). Requests will be matched against the Host field in the following way: 1. If Host is precise, the request matches this rule if the http host header is equal to Host. 2. If Host is a wildcard, then the request matches this rule if the http host header is to equal to the suffix (removing the first label) of the wildcard rule. - - :schema: io.k8s.api.networking.v1.IngressRule#host - ''' - result = self._values.get("host") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def http(self) -> typing.Optional[HttpIngressRuleValue]: - ''' - :schema: io.k8s.api.networking.v1.IngressRule#http - ''' - result = self._values.get("http") - return typing.cast(typing.Optional[HttpIngressRuleValue], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "IngressRule(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.IngressServiceBackend", - jsii_struct_bases=[], - name_mapping={"name": "name", "port": "port"}, -) -class IngressServiceBackend: - def __init__( - self, - *, - name: builtins.str, - port: typing.Optional[typing.Union["ServiceBackendPort", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''IngressServiceBackend references a Kubernetes Service as a Backend. - - :param name: Name is the referenced service. The service must exist in the same namespace as the Ingress object. - :param port: Port of the referenced service. A port name or port number is required for a IngressServiceBackend. - - :schema: io.k8s.api.networking.v1.IngressServiceBackend - ''' - if isinstance(port, dict): - port = ServiceBackendPort(**port) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__e3e97fffe88d91fb9b536c53695ba745cdabbeb12e55b6dea45d253fdc89f5cd) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument port", value=port, expected_type=type_hints["port"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "name": name, - } - if port is not None: - self._values["port"] = port - - @builtins.property - def name(self) -> builtins.str: - '''Name is the referenced service. - - The service must exist in the same namespace as the Ingress object. - - :schema: io.k8s.api.networking.v1.IngressServiceBackend#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def port(self) -> typing.Optional["ServiceBackendPort"]: - '''Port of the referenced service. - - A port name or port number is required for a IngressServiceBackend. - - :schema: io.k8s.api.networking.v1.IngressServiceBackend#port - ''' - result = self._values.get("port") - return typing.cast(typing.Optional["ServiceBackendPort"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "IngressServiceBackend(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.IngressSpec", - jsii_struct_bases=[], - name_mapping={ - "default_backend": "defaultBackend", - "ingress_class_name": "ingressClassName", - "rules": "rules", - "tls": "tls", - }, -) -class IngressSpec: - def __init__( - self, - *, - default_backend: typing.Optional[typing.Union[IngressBackend, typing.Dict[builtins.str, typing.Any]]] = None, - ingress_class_name: typing.Optional[builtins.str] = None, - rules: typing.Optional[typing.Sequence[typing.Union[IngressRule, typing.Dict[builtins.str, typing.Any]]]] = None, - tls: typing.Optional[typing.Sequence[typing.Union["IngressTls", typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''IngressSpec describes the Ingress the user wishes to exist. - - :param default_backend: DefaultBackend is the backend that should handle requests that don't match any rule. If Rules are not specified, DefaultBackend must be specified. If DefaultBackend is not set, the handling of requests that do not match any of the rules will be up to the Ingress controller. - :param ingress_class_name: IngressClassName is the name of an IngressClass cluster resource. Ingress controller implementations use this field to know whether they should be serving this Ingress resource, by a transitive connection (controller -> IngressClass -> Ingress resource). Although the ``kubernetes.io/ingress.class`` annotation (simple constant name) was never formally defined, it was widely supported by Ingress controllers to create a direct binding between Ingress controller and Ingress resources. Newly created Ingress resources should prefer using the field. However, even though the annotation is officially deprecated, for backwards compatibility reasons, ingress controllers should still honor that annotation if present. - :param rules: A list of host rules used to configure the Ingress. If unspecified, or no rule matches, all traffic is sent to the default backend. - :param tls: TLS configuration. Currently the Ingress only supports a single TLS port, 443. If multiple members of this list specify different hosts, they will be multiplexed on the same port according to the hostname specified through the SNI TLS extension, if the ingress controller fulfilling the ingress supports SNI. - - :schema: io.k8s.api.networking.v1.IngressSpec - ''' - if isinstance(default_backend, dict): - default_backend = IngressBackend(**default_backend) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__97b273849944944f09361df5533bf081b4f556d667e5a81bba5956e651d6411b) - check_type(argname="argument default_backend", value=default_backend, expected_type=type_hints["default_backend"]) - check_type(argname="argument ingress_class_name", value=ingress_class_name, expected_type=type_hints["ingress_class_name"]) - check_type(argname="argument rules", value=rules, expected_type=type_hints["rules"]) - check_type(argname="argument tls", value=tls, expected_type=type_hints["tls"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if default_backend is not None: - self._values["default_backend"] = default_backend - if ingress_class_name is not None: - self._values["ingress_class_name"] = ingress_class_name - if rules is not None: - self._values["rules"] = rules - if tls is not None: - self._values["tls"] = tls - - @builtins.property - def default_backend(self) -> typing.Optional[IngressBackend]: - '''DefaultBackend is the backend that should handle requests that don't match any rule. - - If Rules are not specified, DefaultBackend must be specified. If DefaultBackend is not set, the handling of requests that do not match any of the rules will be up to the Ingress controller. - - :schema: io.k8s.api.networking.v1.IngressSpec#defaultBackend - ''' - result = self._values.get("default_backend") - return typing.cast(typing.Optional[IngressBackend], result) - - @builtins.property - def ingress_class_name(self) -> typing.Optional[builtins.str]: - '''IngressClassName is the name of an IngressClass cluster resource. - - Ingress controller implementations use this field to know whether they should be serving this Ingress resource, by a transitive connection (controller -> IngressClass -> Ingress resource). Although the ``kubernetes.io/ingress.class`` annotation (simple constant name) was never formally defined, it was widely supported by Ingress controllers to create a direct binding between Ingress controller and Ingress resources. Newly created Ingress resources should prefer using the field. However, even though the annotation is officially deprecated, for backwards compatibility reasons, ingress controllers should still honor that annotation if present. - - :schema: io.k8s.api.networking.v1.IngressSpec#ingressClassName - ''' - result = self._values.get("ingress_class_name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def rules(self) -> typing.Optional[typing.List[IngressRule]]: - '''A list of host rules used to configure the Ingress. - - If unspecified, or no rule matches, all traffic is sent to the default backend. - - :schema: io.k8s.api.networking.v1.IngressSpec#rules - ''' - result = self._values.get("rules") - return typing.cast(typing.Optional[typing.List[IngressRule]], result) - - @builtins.property - def tls(self) -> typing.Optional[typing.List["IngressTls"]]: - '''TLS configuration. - - Currently the Ingress only supports a single TLS port, 443. If multiple members of this list specify different hosts, they will be multiplexed on the same port according to the hostname specified through the SNI TLS extension, if the ingress controller fulfilling the ingress supports SNI. - - :schema: io.k8s.api.networking.v1.IngressSpec#tls - ''' - result = self._values.get("tls") - return typing.cast(typing.Optional[typing.List["IngressTls"]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "IngressSpec(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.IngressTls", - jsii_struct_bases=[], - name_mapping={"hosts": "hosts", "secret_name": "secretName"}, -) -class IngressTls: - def __init__( - self, - *, - hosts: typing.Optional[typing.Sequence[builtins.str]] = None, - secret_name: typing.Optional[builtins.str] = None, - ) -> None: - '''IngressTLS describes the transport layer security associated with an Ingress. - - :param hosts: Hosts are a list of hosts included in the TLS certificate. The values in this list must match the name/s used in the tlsSecret. Defaults to the wildcard host setting for the loadbalancer controller fulfilling this Ingress, if left unspecified. Default: the wildcard host setting for the loadbalancer controller fulfilling this Ingress, if left unspecified. - :param secret_name: SecretName is the name of the secret used to terminate TLS traffic on port 443. Field is left optional to allow TLS routing based on SNI hostname alone. If the SNI host in a listener conflicts with the "Host" header field used by an IngressRule, the SNI host is used for termination and value of the Host header is used for routing. - - :schema: io.k8s.api.networking.v1.IngressTLS - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__8025d7972fe3e671efe9fc76590f08e6af4537e71b575480407655a7b7b7b9ef) - check_type(argname="argument hosts", value=hosts, expected_type=type_hints["hosts"]) - check_type(argname="argument secret_name", value=secret_name, expected_type=type_hints["secret_name"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if hosts is not None: - self._values["hosts"] = hosts - if secret_name is not None: - self._values["secret_name"] = secret_name - - @builtins.property - def hosts(self) -> typing.Optional[typing.List[builtins.str]]: - '''Hosts are a list of hosts included in the TLS certificate. - - The values in this list must match the name/s used in the tlsSecret. Defaults to the wildcard host setting for the loadbalancer controller fulfilling this Ingress, if left unspecified. - - :default: the wildcard host setting for the loadbalancer controller fulfilling this Ingress, if left unspecified. - - :schema: io.k8s.api.networking.v1.IngressTLS#hosts - ''' - result = self._values.get("hosts") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def secret_name(self) -> typing.Optional[builtins.str]: - '''SecretName is the name of the secret used to terminate TLS traffic on port 443. - - Field is left optional to allow TLS routing based on SNI hostname alone. If the SNI host in a listener conflicts with the "Host" header field used by an IngressRule, the SNI host is used for termination and value of the Host header is used for routing. - - :schema: io.k8s.api.networking.v1.IngressTLS#secretName - ''' - result = self._values.get("secret_name") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "IngressTls(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class IntOrString(metaclass=jsii.JSIIMeta, jsii_type="k8s.IntOrString"): - ''' - :schema: io.k8s.apimachinery.pkg.util.intstr.IntOrString - ''' - - @jsii.member(jsii_name="fromNumber") - @builtins.classmethod - def from_number(cls, value: jsii.Number) -> "IntOrString": - ''' - :param value: - - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__35530c996723c32c7f16f8470b1263773efdf426fdc5791968292d1634936acc) - check_type(argname="argument value", value=value, expected_type=type_hints["value"]) - return typing.cast("IntOrString", jsii.sinvoke(cls, "fromNumber", [value])) - - @jsii.member(jsii_name="fromString") - @builtins.classmethod - def from_string(cls, value: builtins.str) -> "IntOrString": - ''' - :param value: - - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__c0d8454a87ccd93d2d171f9e20405b3c5d7964bd41fa7e35f0ca4da486da3504) - check_type(argname="argument value", value=value, expected_type=type_hints["value"]) - return typing.cast("IntOrString", jsii.sinvoke(cls, "fromString", [value])) - - @builtins.property - @jsii.member(jsii_name="value") - def value(self) -> typing.Union[builtins.str, jsii.Number]: - return typing.cast(typing.Union[builtins.str, jsii.Number], jsii.get(self, "value")) - - -@jsii.enum(jsii_type="k8s.IoK8SApimachineryPkgApisMetaV1DeleteOptionsKind") -class IoK8SApimachineryPkgApisMetaV1DeleteOptionsKind(enum.Enum): - '''Kind is a string value representing the REST resource this object represents. - - Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: IoK8SApimachineryPkgApisMetaV1DeleteOptionsKind - ''' - - DELETE_OPTIONS = "DELETE_OPTIONS" - '''DeleteOptions.''' - - -@jsii.data_type( - jsii_type="k8s.IpBlock", - jsii_struct_bases=[], - name_mapping={"cidr": "cidr", "except_": "except"}, -) -class IpBlock: - def __init__( - self, - *, - cidr: builtins.str, - except_: typing.Optional[typing.Sequence[builtins.str]] = None, - ) -> None: - '''IPBlock describes a particular CIDR (Ex. - - "192.168.1.0/24","2001:db8::/64") that is allowed to the pods matched by a NetworkPolicySpec's podSelector. The except entry describes CIDRs that should not be included within this rule. - - :param cidr: CIDR is a string representing the IP Block Valid examples are "192.168.1.0/24" or "2001:db8::/64". - :param except_: Except is a slice of CIDRs that should not be included within an IP Block Valid examples are "192.168.1.0/24" or "2001:db8::/64" Except values will be rejected if they are outside the CIDR range. - - :schema: io.k8s.api.networking.v1.IPBlock - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__06c394466495c1b06784a9836bf93d9ce9aec1a818eac2478c2db2ccb377d374) - check_type(argname="argument cidr", value=cidr, expected_type=type_hints["cidr"]) - check_type(argname="argument except_", value=except_, expected_type=type_hints["except_"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "cidr": cidr, - } - if except_ is not None: - self._values["except_"] = except_ - - @builtins.property - def cidr(self) -> builtins.str: - '''CIDR is a string representing the IP Block Valid examples are "192.168.1.0/24" or "2001:db8::/64". - - :schema: io.k8s.api.networking.v1.IPBlock#cidr - ''' - result = self._values.get("cidr") - assert result is not None, "Required property 'cidr' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def except_(self) -> typing.Optional[typing.List[builtins.str]]: - '''Except is a slice of CIDRs that should not be included within an IP Block Valid examples are "192.168.1.0/24" or "2001:db8::/64" Except values will be rejected if they are outside the CIDR range. - - :schema: io.k8s.api.networking.v1.IPBlock#except - ''' - result = self._values.get("except_") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "IpBlock(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.IscsiPersistentVolumeSource", - jsii_struct_bases=[], - name_mapping={ - "iqn": "iqn", - "lun": "lun", - "target_portal": "targetPortal", - "chap_auth_discovery": "chapAuthDiscovery", - "chap_auth_session": "chapAuthSession", - "fs_type": "fsType", - "initiator_name": "initiatorName", - "iscsi_interface": "iscsiInterface", - "portals": "portals", - "read_only": "readOnly", - "secret_ref": "secretRef", - }, -) -class IscsiPersistentVolumeSource: - def __init__( - self, - *, - iqn: builtins.str, - lun: jsii.Number, - target_portal: builtins.str, - chap_auth_discovery: typing.Optional[builtins.bool] = None, - chap_auth_session: typing.Optional[builtins.bool] = None, - fs_type: typing.Optional[builtins.str] = None, - initiator_name: typing.Optional[builtins.str] = None, - iscsi_interface: typing.Optional[builtins.str] = None, - portals: typing.Optional[typing.Sequence[builtins.str]] = None, - read_only: typing.Optional[builtins.bool] = None, - secret_ref: typing.Optional[typing.Union["SecretReference", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''ISCSIPersistentVolumeSource represents an ISCSI disk. - - ISCSI volumes can only be mounted as read/write once. ISCSI volumes support ownership management and SELinux relabeling. - - :param iqn: iqn is Target iSCSI Qualified Name. - :param lun: lun is iSCSI Target Lun number. - :param target_portal: targetPortal is iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port is other than default (typically TCP ports 860 and 3260). - :param chap_auth_discovery: chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication. - :param chap_auth_session: chapAuthSession defines whether support iSCSI Session CHAP authentication. - :param fs_type: fsType is the filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi - :param initiator_name: initiatorName is the custom iSCSI Initiator Name. If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface : will be created for the connection. - :param iscsi_interface: iscsiInterface is the interface Name that uses an iSCSI transport. Defaults to 'default' (tcp). Default: default' (tcp). - :param portals: portals is the iSCSI Target Portal List. The Portal is either an IP or ip_addr:port if the port is other than default (typically TCP ports 860 and 3260). - :param read_only: readOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false. Default: false. - :param secret_ref: secretRef is the CHAP Secret for iSCSI target and initiator authentication. - - :schema: io.k8s.api.core.v1.ISCSIPersistentVolumeSource - ''' - if isinstance(secret_ref, dict): - secret_ref = SecretReference(**secret_ref) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__61f74686d735cd7119fc3fdb8061ce0c3372549a76fba9b78a682fb2b8737efe) - check_type(argname="argument iqn", value=iqn, expected_type=type_hints["iqn"]) - check_type(argname="argument lun", value=lun, expected_type=type_hints["lun"]) - check_type(argname="argument target_portal", value=target_portal, expected_type=type_hints["target_portal"]) - check_type(argname="argument chap_auth_discovery", value=chap_auth_discovery, expected_type=type_hints["chap_auth_discovery"]) - check_type(argname="argument chap_auth_session", value=chap_auth_session, expected_type=type_hints["chap_auth_session"]) - check_type(argname="argument fs_type", value=fs_type, expected_type=type_hints["fs_type"]) - check_type(argname="argument initiator_name", value=initiator_name, expected_type=type_hints["initiator_name"]) - check_type(argname="argument iscsi_interface", value=iscsi_interface, expected_type=type_hints["iscsi_interface"]) - check_type(argname="argument portals", value=portals, expected_type=type_hints["portals"]) - check_type(argname="argument read_only", value=read_only, expected_type=type_hints["read_only"]) - check_type(argname="argument secret_ref", value=secret_ref, expected_type=type_hints["secret_ref"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "iqn": iqn, - "lun": lun, - "target_portal": target_portal, - } - if chap_auth_discovery is not None: - self._values["chap_auth_discovery"] = chap_auth_discovery - if chap_auth_session is not None: - self._values["chap_auth_session"] = chap_auth_session - if fs_type is not None: - self._values["fs_type"] = fs_type - if initiator_name is not None: - self._values["initiator_name"] = initiator_name - if iscsi_interface is not None: - self._values["iscsi_interface"] = iscsi_interface - if portals is not None: - self._values["portals"] = portals - if read_only is not None: - self._values["read_only"] = read_only - if secret_ref is not None: - self._values["secret_ref"] = secret_ref - - @builtins.property - def iqn(self) -> builtins.str: - '''iqn is Target iSCSI Qualified Name. - - :schema: io.k8s.api.core.v1.ISCSIPersistentVolumeSource#iqn - ''' - result = self._values.get("iqn") - assert result is not None, "Required property 'iqn' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def lun(self) -> jsii.Number: - '''lun is iSCSI Target Lun number. - - :schema: io.k8s.api.core.v1.ISCSIPersistentVolumeSource#lun - ''' - result = self._values.get("lun") - assert result is not None, "Required property 'lun' is missing" - return typing.cast(jsii.Number, result) - - @builtins.property - def target_portal(self) -> builtins.str: - '''targetPortal is iSCSI Target Portal. - - The Portal is either an IP or ip_addr:port if the port is other than default (typically TCP ports 860 and 3260). - - :schema: io.k8s.api.core.v1.ISCSIPersistentVolumeSource#targetPortal - ''' - result = self._values.get("target_portal") - assert result is not None, "Required property 'target_portal' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def chap_auth_discovery(self) -> typing.Optional[builtins.bool]: - '''chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication. - - :schema: io.k8s.api.core.v1.ISCSIPersistentVolumeSource#chapAuthDiscovery - ''' - result = self._values.get("chap_auth_discovery") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def chap_auth_session(self) -> typing.Optional[builtins.bool]: - '''chapAuthSession defines whether support iSCSI Session CHAP authentication. - - :schema: io.k8s.api.core.v1.ISCSIPersistentVolumeSource#chapAuthSession - ''' - result = self._values.get("chap_auth_session") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def fs_type(self) -> typing.Optional[builtins.str]: - '''fsType is the filesystem type of the volume that you want to mount. - - Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi - - :schema: io.k8s.api.core.v1.ISCSIPersistentVolumeSource#fsType - ''' - result = self._values.get("fs_type") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def initiator_name(self) -> typing.Optional[builtins.str]: - '''initiatorName is the custom iSCSI Initiator Name. - - If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface : will be created for the connection. - - :schema: io.k8s.api.core.v1.ISCSIPersistentVolumeSource#initiatorName - ''' - result = self._values.get("initiator_name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def iscsi_interface(self) -> typing.Optional[builtins.str]: - '''iscsiInterface is the interface Name that uses an iSCSI transport. - - Defaults to 'default' (tcp). - - :default: default' (tcp). - - :schema: io.k8s.api.core.v1.ISCSIPersistentVolumeSource#iscsiInterface - ''' - result = self._values.get("iscsi_interface") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def portals(self) -> typing.Optional[typing.List[builtins.str]]: - '''portals is the iSCSI Target Portal List. - - The Portal is either an IP or ip_addr:port if the port is other than default (typically TCP ports 860 and 3260). - - :schema: io.k8s.api.core.v1.ISCSIPersistentVolumeSource#portals - ''' - result = self._values.get("portals") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def read_only(self) -> typing.Optional[builtins.bool]: - '''readOnly here will force the ReadOnly setting in VolumeMounts. - - Defaults to false. - - :default: false. - - :schema: io.k8s.api.core.v1.ISCSIPersistentVolumeSource#readOnly - ''' - result = self._values.get("read_only") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def secret_ref(self) -> typing.Optional["SecretReference"]: - '''secretRef is the CHAP Secret for iSCSI target and initiator authentication. - - :schema: io.k8s.api.core.v1.ISCSIPersistentVolumeSource#secretRef - ''' - result = self._values.get("secret_ref") - return typing.cast(typing.Optional["SecretReference"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "IscsiPersistentVolumeSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.IscsiVolumeSource", - jsii_struct_bases=[], - name_mapping={ - "iqn": "iqn", - "lun": "lun", - "target_portal": "targetPortal", - "chap_auth_discovery": "chapAuthDiscovery", - "chap_auth_session": "chapAuthSession", - "fs_type": "fsType", - "initiator_name": "initiatorName", - "iscsi_interface": "iscsiInterface", - "portals": "portals", - "read_only": "readOnly", - "secret_ref": "secretRef", - }, -) -class IscsiVolumeSource: - def __init__( - self, - *, - iqn: builtins.str, - lun: jsii.Number, - target_portal: builtins.str, - chap_auth_discovery: typing.Optional[builtins.bool] = None, - chap_auth_session: typing.Optional[builtins.bool] = None, - fs_type: typing.Optional[builtins.str] = None, - initiator_name: typing.Optional[builtins.str] = None, - iscsi_interface: typing.Optional[builtins.str] = None, - portals: typing.Optional[typing.Sequence[builtins.str]] = None, - read_only: typing.Optional[builtins.bool] = None, - secret_ref: typing.Optional[typing.Union["LocalObjectReference", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Represents an ISCSI disk. - - ISCSI volumes can only be mounted as read/write once. ISCSI volumes support ownership management and SELinux relabeling. - - :param iqn: iqn is the target iSCSI Qualified Name. - :param lun: lun represents iSCSI Target Lun number. - :param target_portal: targetPortal is iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port is other than default (typically TCP ports 860 and 3260). - :param chap_auth_discovery: chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication. - :param chap_auth_session: chapAuthSession defines whether support iSCSI Session CHAP authentication. - :param fs_type: fsType is the filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi - :param initiator_name: initiatorName is the custom iSCSI Initiator Name. If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface : will be created for the connection. - :param iscsi_interface: iscsiInterface is the interface Name that uses an iSCSI transport. Defaults to 'default' (tcp). Default: default' (tcp). - :param portals: portals is the iSCSI Target Portal List. The portal is either an IP or ip_addr:port if the port is other than default (typically TCP ports 860 and 3260). - :param read_only: readOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false. Default: false. - :param secret_ref: secretRef is the CHAP Secret for iSCSI target and initiator authentication. - - :schema: io.k8s.api.core.v1.ISCSIVolumeSource - ''' - if isinstance(secret_ref, dict): - secret_ref = LocalObjectReference(**secret_ref) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__3f8a3f5224af62afa8f0a6e18b9dbecb3365354c791cdf02387e47f4f53ef0b6) - check_type(argname="argument iqn", value=iqn, expected_type=type_hints["iqn"]) - check_type(argname="argument lun", value=lun, expected_type=type_hints["lun"]) - check_type(argname="argument target_portal", value=target_portal, expected_type=type_hints["target_portal"]) - check_type(argname="argument chap_auth_discovery", value=chap_auth_discovery, expected_type=type_hints["chap_auth_discovery"]) - check_type(argname="argument chap_auth_session", value=chap_auth_session, expected_type=type_hints["chap_auth_session"]) - check_type(argname="argument fs_type", value=fs_type, expected_type=type_hints["fs_type"]) - check_type(argname="argument initiator_name", value=initiator_name, expected_type=type_hints["initiator_name"]) - check_type(argname="argument iscsi_interface", value=iscsi_interface, expected_type=type_hints["iscsi_interface"]) - check_type(argname="argument portals", value=portals, expected_type=type_hints["portals"]) - check_type(argname="argument read_only", value=read_only, expected_type=type_hints["read_only"]) - check_type(argname="argument secret_ref", value=secret_ref, expected_type=type_hints["secret_ref"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "iqn": iqn, - "lun": lun, - "target_portal": target_portal, - } - if chap_auth_discovery is not None: - self._values["chap_auth_discovery"] = chap_auth_discovery - if chap_auth_session is not None: - self._values["chap_auth_session"] = chap_auth_session - if fs_type is not None: - self._values["fs_type"] = fs_type - if initiator_name is not None: - self._values["initiator_name"] = initiator_name - if iscsi_interface is not None: - self._values["iscsi_interface"] = iscsi_interface - if portals is not None: - self._values["portals"] = portals - if read_only is not None: - self._values["read_only"] = read_only - if secret_ref is not None: - self._values["secret_ref"] = secret_ref - - @builtins.property - def iqn(self) -> builtins.str: - '''iqn is the target iSCSI Qualified Name. - - :schema: io.k8s.api.core.v1.ISCSIVolumeSource#iqn - ''' - result = self._values.get("iqn") - assert result is not None, "Required property 'iqn' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def lun(self) -> jsii.Number: - '''lun represents iSCSI Target Lun number. - - :schema: io.k8s.api.core.v1.ISCSIVolumeSource#lun - ''' - result = self._values.get("lun") - assert result is not None, "Required property 'lun' is missing" - return typing.cast(jsii.Number, result) - - @builtins.property - def target_portal(self) -> builtins.str: - '''targetPortal is iSCSI Target Portal. - - The Portal is either an IP or ip_addr:port if the port is other than default (typically TCP ports 860 and 3260). - - :schema: io.k8s.api.core.v1.ISCSIVolumeSource#targetPortal - ''' - result = self._values.get("target_portal") - assert result is not None, "Required property 'target_portal' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def chap_auth_discovery(self) -> typing.Optional[builtins.bool]: - '''chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication. - - :schema: io.k8s.api.core.v1.ISCSIVolumeSource#chapAuthDiscovery - ''' - result = self._values.get("chap_auth_discovery") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def chap_auth_session(self) -> typing.Optional[builtins.bool]: - '''chapAuthSession defines whether support iSCSI Session CHAP authentication. - - :schema: io.k8s.api.core.v1.ISCSIVolumeSource#chapAuthSession - ''' - result = self._values.get("chap_auth_session") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def fs_type(self) -> typing.Optional[builtins.str]: - '''fsType is the filesystem type of the volume that you want to mount. - - Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi - - :schema: io.k8s.api.core.v1.ISCSIVolumeSource#fsType - ''' - result = self._values.get("fs_type") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def initiator_name(self) -> typing.Optional[builtins.str]: - '''initiatorName is the custom iSCSI Initiator Name. - - If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface : will be created for the connection. - - :schema: io.k8s.api.core.v1.ISCSIVolumeSource#initiatorName - ''' - result = self._values.get("initiator_name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def iscsi_interface(self) -> typing.Optional[builtins.str]: - '''iscsiInterface is the interface Name that uses an iSCSI transport. - - Defaults to 'default' (tcp). - - :default: default' (tcp). - - :schema: io.k8s.api.core.v1.ISCSIVolumeSource#iscsiInterface - ''' - result = self._values.get("iscsi_interface") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def portals(self) -> typing.Optional[typing.List[builtins.str]]: - '''portals is the iSCSI Target Portal List. - - The portal is either an IP or ip_addr:port if the port is other than default (typically TCP ports 860 and 3260). - - :schema: io.k8s.api.core.v1.ISCSIVolumeSource#portals - ''' - result = self._values.get("portals") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def read_only(self) -> typing.Optional[builtins.bool]: - '''readOnly here will force the ReadOnly setting in VolumeMounts. - - Defaults to false. - - :default: false. - - :schema: io.k8s.api.core.v1.ISCSIVolumeSource#readOnly - ''' - result = self._values.get("read_only") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def secret_ref(self) -> typing.Optional["LocalObjectReference"]: - '''secretRef is the CHAP Secret for iSCSI target and initiator authentication. - - :schema: io.k8s.api.core.v1.ISCSIVolumeSource#secretRef - ''' - result = self._values.get("secret_ref") - return typing.cast(typing.Optional["LocalObjectReference"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "IscsiVolumeSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.JobSpec", - jsii_struct_bases=[], - name_mapping={ - "template": "template", - "active_deadline_seconds": "activeDeadlineSeconds", - "backoff_limit": "backoffLimit", - "completion_mode": "completionMode", - "completions": "completions", - "manual_selector": "manualSelector", - "parallelism": "parallelism", - "pod_failure_policy": "podFailurePolicy", - "selector": "selector", - "suspend": "suspend", - "ttl_seconds_after_finished": "ttlSecondsAfterFinished", - }, -) -class JobSpec: - def __init__( - self, - *, - template: typing.Union["PodTemplateSpec", typing.Dict[builtins.str, typing.Any]], - active_deadline_seconds: typing.Optional[jsii.Number] = None, - backoff_limit: typing.Optional[jsii.Number] = None, - completion_mode: typing.Optional[builtins.str] = None, - completions: typing.Optional[jsii.Number] = None, - manual_selector: typing.Optional[builtins.bool] = None, - parallelism: typing.Optional[jsii.Number] = None, - pod_failure_policy: typing.Optional[typing.Union["PodFailurePolicy", typing.Dict[builtins.str, typing.Any]]] = None, - selector: typing.Optional[typing.Union["LabelSelector", typing.Dict[builtins.str, typing.Any]]] = None, - suspend: typing.Optional[builtins.bool] = None, - ttl_seconds_after_finished: typing.Optional[jsii.Number] = None, - ) -> None: - '''JobSpec describes how the job execution will look like. - - :param template: Describes the pod that will be created when executing a job. More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/ - :param active_deadline_seconds: Specifies the duration in seconds relative to the startTime that the job may be continuously active before the system tries to terminate it; value must be positive integer. If a Job is suspended (at creation or through an update), this timer will effectively be stopped and reset when the Job is resumed again. - :param backoff_limit: Specifies the number of retries before marking this job failed. Defaults to 6 Default: 6 - :param completion_mode: CompletionMode specifies how Pod completions are tracked. It can be ``NonIndexed`` (default) or ``Indexed``. ``NonIndexed`` means that the Job is considered complete when there have been .spec.completions successfully completed Pods. Each Pod completion is homologous to each other. ``Indexed`` means that the Pods of a Job get an associated completion index from 0 to (.spec.completions - 1), available in the annotation batch.kubernetes.io/job-completion-index. The Job is considered complete when there is one successfully completed Pod for each index. When value is ``Indexed``, .spec.completions must be specified and ``.spec.parallelism`` must be less than or equal to 10^5. In addition, The Pod name takes the form ``$(job-name)-$(index)-$(random-string)``, the Pod hostname takes the form ``$(job-name)-$(index)``. More completion modes can be added in the future. If the Job controller observes a mode that it doesn't recognize, which is possible during upgrades due to version skew, the controller skips updates for the Job. - :param completions: Specifies the desired number of successfully finished pods the job should be run with. Setting to nil means that the success of any pod signals the success of all pods, and allows parallelism to have any positive value. Setting to 1 means that parallelism is limited to 1 and the success of that pod signals the success of the job. More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/ - :param manual_selector: manualSelector controls generation of pod labels and pod selectors. Leave ``manualSelector`` unset unless you are certain what you are doing. When false or unset, the system pick labels unique to this job and appends those labels to the pod template. When true, the user is responsible for picking unique labels and specifying the selector. Failure to pick a unique label may cause this and other jobs to not function correctly. However, You may see ``manualSelector=true`` in jobs that were created with the old ``extensions/v1beta1`` API. More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/#specifying-your-own-pod-selector - :param parallelism: Specifies the maximum desired number of pods the job should run at any given time. The actual number of pods running in steady state will be less than this number when ((.spec.completions - .status.successful) < .spec.parallelism), i.e. when the work left to do is less than max parallelism. More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/ - :param pod_failure_policy: Specifies the policy of handling failed pods. In particular, it allows to specify the set of actions and conditions which need to be satisfied to take the associated action. If empty, the default behaviour applies - the counter of failed pods, represented by the jobs's .status.failed field, is incremented and it is checked against the backoffLimit. This field cannot be used in combination with restartPolicy=OnFailure. This field is alpha-level. To use this field, you must enable the ``JobPodFailurePolicy`` feature gate (disabled by default). - :param selector: A label query over pods that should match the pod count. Normally, the system sets this field for you. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors - :param suspend: Suspend specifies whether the Job controller should create Pods or not. If a Job is created with suspend set to true, no Pods are created by the Job controller. If a Job is suspended after creation (i.e. the flag goes from false to true), the Job controller will delete all active Pods associated with this Job. Users must design their workload to gracefully handle this. Suspending a Job will reset the StartTime field of the Job, effectively resetting the ActiveDeadlineSeconds timer too. Defaults to false. Default: false. - :param ttl_seconds_after_finished: ttlSecondsAfterFinished limits the lifetime of a Job that has finished execution (either Complete or Failed). If this field is set, ttlSecondsAfterFinished after the Job finishes, it is eligible to be automatically deleted. When the Job is being deleted, its lifecycle guarantees (e.g. finalizers) will be honored. If this field is unset, the Job won't be automatically deleted. If this field is set to zero, the Job becomes eligible to be deleted immediately after it finishes. - - :schema: io.k8s.api.batch.v1.JobSpec - ''' - if isinstance(template, dict): - template = PodTemplateSpec(**template) - if isinstance(pod_failure_policy, dict): - pod_failure_policy = PodFailurePolicy(**pod_failure_policy) - if isinstance(selector, dict): - selector = LabelSelector(**selector) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__292598de0c2d5d5c366c954213d0653c155500e82fa84af63083a2187622ca4d) - check_type(argname="argument template", value=template, expected_type=type_hints["template"]) - check_type(argname="argument active_deadline_seconds", value=active_deadline_seconds, expected_type=type_hints["active_deadline_seconds"]) - check_type(argname="argument backoff_limit", value=backoff_limit, expected_type=type_hints["backoff_limit"]) - check_type(argname="argument completion_mode", value=completion_mode, expected_type=type_hints["completion_mode"]) - check_type(argname="argument completions", value=completions, expected_type=type_hints["completions"]) - check_type(argname="argument manual_selector", value=manual_selector, expected_type=type_hints["manual_selector"]) - check_type(argname="argument parallelism", value=parallelism, expected_type=type_hints["parallelism"]) - check_type(argname="argument pod_failure_policy", value=pod_failure_policy, expected_type=type_hints["pod_failure_policy"]) - check_type(argname="argument selector", value=selector, expected_type=type_hints["selector"]) - check_type(argname="argument suspend", value=suspend, expected_type=type_hints["suspend"]) - check_type(argname="argument ttl_seconds_after_finished", value=ttl_seconds_after_finished, expected_type=type_hints["ttl_seconds_after_finished"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "template": template, - } - if active_deadline_seconds is not None: - self._values["active_deadline_seconds"] = active_deadline_seconds - if backoff_limit is not None: - self._values["backoff_limit"] = backoff_limit - if completion_mode is not None: - self._values["completion_mode"] = completion_mode - if completions is not None: - self._values["completions"] = completions - if manual_selector is not None: - self._values["manual_selector"] = manual_selector - if parallelism is not None: - self._values["parallelism"] = parallelism - if pod_failure_policy is not None: - self._values["pod_failure_policy"] = pod_failure_policy - if selector is not None: - self._values["selector"] = selector - if suspend is not None: - self._values["suspend"] = suspend - if ttl_seconds_after_finished is not None: - self._values["ttl_seconds_after_finished"] = ttl_seconds_after_finished - - @builtins.property - def template(self) -> "PodTemplateSpec": - '''Describes the pod that will be created when executing a job. - - More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/ - - :schema: io.k8s.api.batch.v1.JobSpec#template - ''' - result = self._values.get("template") - assert result is not None, "Required property 'template' is missing" - return typing.cast("PodTemplateSpec", result) - - @builtins.property - def active_deadline_seconds(self) -> typing.Optional[jsii.Number]: - '''Specifies the duration in seconds relative to the startTime that the job may be continuously active before the system tries to terminate it; - - value must be positive integer. If a Job is suspended (at creation or through an update), this timer will effectively be stopped and reset when the Job is resumed again. - - :schema: io.k8s.api.batch.v1.JobSpec#activeDeadlineSeconds - ''' - result = self._values.get("active_deadline_seconds") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def backoff_limit(self) -> typing.Optional[jsii.Number]: - '''Specifies the number of retries before marking this job failed. - - Defaults to 6 - - :default: 6 - - :schema: io.k8s.api.batch.v1.JobSpec#backoffLimit - ''' - result = self._values.get("backoff_limit") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def completion_mode(self) -> typing.Optional[builtins.str]: - '''CompletionMode specifies how Pod completions are tracked. It can be ``NonIndexed`` (default) or ``Indexed``. - - ``NonIndexed`` means that the Job is considered complete when there have been .spec.completions successfully completed Pods. Each Pod completion is homologous to each other. - - ``Indexed`` means that the Pods of a Job get an associated completion index from 0 to (.spec.completions - 1), available in the annotation batch.kubernetes.io/job-completion-index. The Job is considered complete when there is one successfully completed Pod for each index. When value is ``Indexed``, .spec.completions must be specified and ``.spec.parallelism`` must be less than or equal to 10^5. In addition, The Pod name takes the form ``$(job-name)-$(index)-$(random-string)``, the Pod hostname takes the form ``$(job-name)-$(index)``. - - More completion modes can be added in the future. If the Job controller observes a mode that it doesn't recognize, which is possible during upgrades due to version skew, the controller skips updates for the Job. - - :schema: io.k8s.api.batch.v1.JobSpec#completionMode - ''' - result = self._values.get("completion_mode") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def completions(self) -> typing.Optional[jsii.Number]: - '''Specifies the desired number of successfully finished pods the job should be run with. - - Setting to nil means that the success of any pod signals the success of all pods, and allows parallelism to have any positive value. Setting to 1 means that parallelism is limited to 1 and the success of that pod signals the success of the job. More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/ - - :schema: io.k8s.api.batch.v1.JobSpec#completions - ''' - result = self._values.get("completions") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def manual_selector(self) -> typing.Optional[builtins.bool]: - '''manualSelector controls generation of pod labels and pod selectors. - - Leave ``manualSelector`` unset unless you are certain what you are doing. When false or unset, the system pick labels unique to this job and appends those labels to the pod template. When true, the user is responsible for picking unique labels and specifying the selector. Failure to pick a unique label may cause this and other jobs to not function correctly. However, You may see ``manualSelector=true`` in jobs that were created with the old ``extensions/v1beta1`` API. More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/#specifying-your-own-pod-selector - - :schema: io.k8s.api.batch.v1.JobSpec#manualSelector - ''' - result = self._values.get("manual_selector") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def parallelism(self) -> typing.Optional[jsii.Number]: - '''Specifies the maximum desired number of pods the job should run at any given time. - - The actual number of pods running in steady state will be less than this number when ((.spec.completions - .status.successful) < .spec.parallelism), i.e. when the work left to do is less than max parallelism. More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/ - - :schema: io.k8s.api.batch.v1.JobSpec#parallelism - ''' - result = self._values.get("parallelism") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def pod_failure_policy(self) -> typing.Optional["PodFailurePolicy"]: - '''Specifies the policy of handling failed pods. - - In particular, it allows to specify the set of actions and conditions which need to be satisfied to take the associated action. If empty, the default behaviour applies - the counter of failed pods, represented by the jobs's .status.failed field, is incremented and it is checked against the backoffLimit. This field cannot be used in combination with restartPolicy=OnFailure. - - This field is alpha-level. To use this field, you must enable the ``JobPodFailurePolicy`` feature gate (disabled by default). - - :schema: io.k8s.api.batch.v1.JobSpec#podFailurePolicy - ''' - result = self._values.get("pod_failure_policy") - return typing.cast(typing.Optional["PodFailurePolicy"], result) - - @builtins.property - def selector(self) -> typing.Optional["LabelSelector"]: - '''A label query over pods that should match the pod count. - - Normally, the system sets this field for you. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors - - :schema: io.k8s.api.batch.v1.JobSpec#selector - ''' - result = self._values.get("selector") - return typing.cast(typing.Optional["LabelSelector"], result) - - @builtins.property - def suspend(self) -> typing.Optional[builtins.bool]: - '''Suspend specifies whether the Job controller should create Pods or not. - - If a Job is created with suspend set to true, no Pods are created by the Job controller. If a Job is suspended after creation (i.e. the flag goes from false to true), the Job controller will delete all active Pods associated with this Job. Users must design their workload to gracefully handle this. Suspending a Job will reset the StartTime field of the Job, effectively resetting the ActiveDeadlineSeconds timer too. Defaults to false. - - :default: false. - - :schema: io.k8s.api.batch.v1.JobSpec#suspend - ''' - result = self._values.get("suspend") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def ttl_seconds_after_finished(self) -> typing.Optional[jsii.Number]: - '''ttlSecondsAfterFinished limits the lifetime of a Job that has finished execution (either Complete or Failed). - - If this field is set, ttlSecondsAfterFinished after the Job finishes, it is eligible to be automatically deleted. When the Job is being deleted, its lifecycle guarantees (e.g. finalizers) will be honored. If this field is unset, the Job won't be automatically deleted. If this field is set to zero, the Job becomes eligible to be deleted immediately after it finishes. - - :schema: io.k8s.api.batch.v1.JobSpec#ttlSecondsAfterFinished - ''' - result = self._values.get("ttl_seconds_after_finished") - return typing.cast(typing.Optional[jsii.Number], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "JobSpec(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.JobTemplateSpec", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata", "spec": "spec"}, -) -class JobTemplateSpec: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[JobSpec, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''JobTemplateSpec describes the data a Job should have when created from a template. - - :param metadata: Standard object's metadata of the jobs created from this template. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Specification of the desired behavior of the job. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.batch.v1.JobTemplateSpec - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if isinstance(spec, dict): - spec = JobSpec(**spec) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__1105e17aa0c313f4565b5065f5605339ba31de88c8c745050dc45e87d82509cd) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - if spec is not None: - self._values["spec"] = spec - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata of the jobs created from this template. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.batch.v1.JobTemplateSpec#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def spec(self) -> typing.Optional[JobSpec]: - '''Specification of the desired behavior of the job. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.batch.v1.JobTemplateSpec#spec - ''' - result = self._values.get("spec") - return typing.cast(typing.Optional[JobSpec], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "JobTemplateSpec(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.JsonSchemaProps", - jsii_struct_bases=[], - name_mapping={ - "additional_items": "additionalItems", - "additional_properties": "additionalProperties", - "all_of": "allOf", - "any_of": "anyOf", - "default": "default", - "definitions": "definitions", - "dependencies": "dependencies", - "description": "description", - "enum": "enum", - "example": "example", - "exclusive_maximum": "exclusiveMaximum", - "exclusive_minimum": "exclusiveMinimum", - "external_docs": "externalDocs", - "format": "format", - "id": "id", - "items": "items", - "maximum": "maximum", - "max_items": "maxItems", - "max_length": "maxLength", - "max_properties": "maxProperties", - "minimum": "minimum", - "min_items": "minItems", - "min_length": "minLength", - "min_properties": "minProperties", - "multiple_of": "multipleOf", - "not_": "not", - "nullable": "nullable", - "one_of": "oneOf", - "pattern": "pattern", - "pattern_properties": "patternProperties", - "properties": "properties", - "ref": "ref", - "required": "required", - "schema": "schema", - "title": "title", - "type": "type", - "unique_items": "uniqueItems", - "x_kubernetes_embedded_resource": "xKubernetesEmbeddedResource", - "x_kubernetes_int_or_string": "xKubernetesIntOrString", - "x_kubernetes_list_map_keys": "xKubernetesListMapKeys", - "x_kubernetes_list_type": "xKubernetesListType", - "x_kubernetes_map_type": "xKubernetesMapType", - "x_kubernetes_preserve_unknown_fields": "xKubernetesPreserveUnknownFields", - "x_kubernetes_validations": "xKubernetesValidations", - }, -) -class JsonSchemaProps: - def __init__( - self, - *, - additional_items: typing.Any = None, - additional_properties: typing.Any = None, - all_of: typing.Optional[typing.Sequence[typing.Union["JsonSchemaProps", typing.Dict[builtins.str, typing.Any]]]] = None, - any_of: typing.Optional[typing.Sequence[typing.Union["JsonSchemaProps", typing.Dict[builtins.str, typing.Any]]]] = None, - default: typing.Any = None, - definitions: typing.Optional[typing.Mapping[builtins.str, typing.Union["JsonSchemaProps", typing.Dict[builtins.str, typing.Any]]]] = None, - dependencies: typing.Optional[typing.Mapping[builtins.str, typing.Any]] = None, - description: typing.Optional[builtins.str] = None, - enum: typing.Optional[typing.Sequence[typing.Any]] = None, - example: typing.Any = None, - exclusive_maximum: typing.Optional[builtins.bool] = None, - exclusive_minimum: typing.Optional[builtins.bool] = None, - external_docs: typing.Optional[typing.Union[ExternalDocumentation, typing.Dict[builtins.str, typing.Any]]] = None, - format: typing.Optional[builtins.str] = None, - id: typing.Optional[builtins.str] = None, - items: typing.Any = None, - maximum: typing.Optional[jsii.Number] = None, - max_items: typing.Optional[jsii.Number] = None, - max_length: typing.Optional[jsii.Number] = None, - max_properties: typing.Optional[jsii.Number] = None, - minimum: typing.Optional[jsii.Number] = None, - min_items: typing.Optional[jsii.Number] = None, - min_length: typing.Optional[jsii.Number] = None, - min_properties: typing.Optional[jsii.Number] = None, - multiple_of: typing.Optional[jsii.Number] = None, - not_: typing.Optional[typing.Union["JsonSchemaProps", typing.Dict[builtins.str, typing.Any]]] = None, - nullable: typing.Optional[builtins.bool] = None, - one_of: typing.Optional[typing.Sequence[typing.Union["JsonSchemaProps", typing.Dict[builtins.str, typing.Any]]]] = None, - pattern: typing.Optional[builtins.str] = None, - pattern_properties: typing.Optional[typing.Mapping[builtins.str, typing.Union["JsonSchemaProps", typing.Dict[builtins.str, typing.Any]]]] = None, - properties: typing.Optional[typing.Mapping[builtins.str, typing.Union["JsonSchemaProps", typing.Dict[builtins.str, typing.Any]]]] = None, - ref: typing.Optional[builtins.str] = None, - required: typing.Optional[typing.Sequence[builtins.str]] = None, - schema: typing.Optional[builtins.str] = None, - title: typing.Optional[builtins.str] = None, - type: typing.Optional[builtins.str] = None, - unique_items: typing.Optional[builtins.bool] = None, - x_kubernetes_embedded_resource: typing.Optional[builtins.bool] = None, - x_kubernetes_int_or_string: typing.Optional[builtins.bool] = None, - x_kubernetes_list_map_keys: typing.Optional[typing.Sequence[builtins.str]] = None, - x_kubernetes_list_type: typing.Optional[builtins.str] = None, - x_kubernetes_map_type: typing.Optional[builtins.str] = None, - x_kubernetes_preserve_unknown_fields: typing.Optional[builtins.bool] = None, - x_kubernetes_validations: typing.Optional[typing.Sequence[typing.Union["ValidationRule", typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''JSONSchemaProps is a JSON-Schema following Specification Draft 4 (http://json-schema.org/). - - :param additional_items: - :param additional_properties: - :param all_of: - :param any_of: - :param default: default is a default value for undefined object fields. Defaulting is a beta feature under the CustomResourceDefaulting feature gate. Defaulting requires spec.preserveUnknownFields to be false. - :param definitions: - :param dependencies: - :param description: - :param enum: - :param example: - :param exclusive_maximum: - :param exclusive_minimum: - :param external_docs: - :param format: format is an OpenAPI v3 format string. Unknown formats are ignored. The following formats are validated:. - bsonobjectid: a bson object ID, i.e. a 24 characters hex string - uri: an URI as parsed by Golang net/url.ParseRequestURI - email: an email address as parsed by Golang net/mail.ParseAddress - hostname: a valid representation for an Internet host name, as defined by RFC 1034, section 3.1 [RFC1034]. - ipv4: an IPv4 IP as parsed by Golang net.ParseIP - ipv6: an IPv6 IP as parsed by Golang net.ParseIP - cidr: a CIDR as parsed by Golang net.ParseCIDR - mac: a MAC address as parsed by Golang net.ParseMAC - uuid: an UUID that allows uppercase defined by the regex (?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$ - uuid3: an UUID3 that allows uppercase defined by the regex (?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?3[0-9a-f]{3}-?[0-9a-f]{4}-?[0-9a-f]{12}$ - uuid4: an UUID4 that allows uppercase defined by the regex (?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?4[0-9a-f]{3}-?[89ab][0-9a-f]{3}-?[0-9a-f]{12}$ - uuid5: an UUID5 that allows uppercase defined by the regex (?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?5[0-9a-f]{3}-?[89ab][0-9a-f]{3}-?[0-9a-f]{12}$ - isbn: an ISBN10 or ISBN13 number string like "0321751043" or "978-0321751041" - isbn10: an ISBN10 number string like "0321751043" - isbn13: an ISBN13 number string like "978-0321751041" - creditcard: a credit card number defined by the regex ^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\\d{3})\\d{11})$ with any non digit characters mixed in - ssn: a U.S. social security number following the regex ^\\d{3}[- ]?\\d{2}[- ]?\\d{4}$ - hexcolor: an hexadecimal color code like "#FFFFFF: following the regex ^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$ - rgbcolor: an RGB color code like rgb like "rgb(255,255,2559" - byte: base64 encoded binary data - password: any kind of string - date: a date string like "2006-01-02" as defined by full-date in RFC3339 - duration: a duration string like "22 ns" as parsed by Golang time.ParseDuration or compatible with Scala duration format - datetime: a date time string like "2014-12-15T19:30:20.000Z" as defined by date-time in RFC3339. - :param id: - :param items: - :param maximum: - :param max_items: - :param max_length: - :param max_properties: - :param minimum: - :param min_items: - :param min_length: - :param min_properties: - :param multiple_of: - :param not_: - :param nullable: - :param one_of: - :param pattern: - :param pattern_properties: - :param properties: - :param ref: - :param required: - :param schema: - :param title: - :param type: - :param unique_items: - :param x_kubernetes_embedded_resource: x-kubernetes-embedded-resource defines that the value is an embedded Kubernetes runtime.Object, with TypeMeta and ObjectMeta. The type must be object. It is allowed to further restrict the embedded object. kind, apiVersion and metadata are validated automatically. x-kubernetes-preserve-unknown-fields is allowed to be true, but does not have to be if the object is fully specified (up to kind, apiVersion, metadata). - :param x_kubernetes_int_or_string: x-kubernetes-int-or-string specifies that this value is either an integer or a string. If this is true, an empty type is allowed and type as child of anyOf is permitted if following one of the following patterns: 1. anyOf: - type: integer - type: string 2. allOf: - anyOf: - type: integer - type: string - ... zero or more - :param x_kubernetes_list_map_keys: x-kubernetes-list-map-keys annotates an array with the x-kubernetes-list-type ``map`` by specifying the keys used as the index of the map. This tag MUST only be used on lists that have the "x-kubernetes-list-type" extension set to "map". Also, the values specified for this attribute must be a scalar typed field of the child structure (no nesting is supported). The properties specified must either be required or have a default value, to ensure those properties are present for all list items. - :param x_kubernetes_list_type: x-kubernetes-list-type annotates an array to further describe its topology. This extension must only be used on lists and may have 3 possible values: 1. ``atomic``: the list is treated as a single entity, like a scalar. Atomic lists will be entirely replaced when updated. This extension may be used on any type of list (struct, scalar, ...). 2. ``set``: Sets are lists that must not have multiple items with the same value. Each value must be a scalar, an object with x-kubernetes-map-type ``atomic`` or an array with x-kubernetes-list-type ``atomic``. 3. ``map``: These lists are like maps in that their elements have a non-index key used to identify them. Order is preserved upon merge. The map tag must only be used on a list with elements of type object. Defaults to atomic for arrays. Default: atomic for arrays. - :param x_kubernetes_map_type: x-kubernetes-map-type annotates an object to further describe its topology. This extension must only be used when type is object and may have 2 possible values: 1. ``granular``: These maps are actual maps (key-value pairs) and each fields are independent from each other (they can each be manipulated by separate actors). This is the default behaviour for all maps. 2. ``atomic``: the list is treated as a single entity, like a scalar. Atomic maps will be entirely replaced when updated. - :param x_kubernetes_preserve_unknown_fields: x-kubernetes-preserve-unknown-fields stops the API server decoding step from pruning fields which are not specified in the validation schema. This affects fields recursively, but switches back to normal pruning behaviour if nested properties or additionalProperties are specified in the schema. This can either be true or undefined. False is forbidden. - :param x_kubernetes_validations: x-kubernetes-validations describes a list of validation rules written in the CEL expression language. This field is an alpha-level. Using this field requires the feature gate ``CustomResourceValidationExpressions`` to be enabled. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps - ''' - if isinstance(external_docs, dict): - external_docs = ExternalDocumentation(**external_docs) - if isinstance(not_, dict): - not_ = JsonSchemaProps(**not_) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__daf776f0153100d207addeedc621b9aaef5a61bb490f24eaa0139862d3db2a89) - check_type(argname="argument additional_items", value=additional_items, expected_type=type_hints["additional_items"]) - check_type(argname="argument additional_properties", value=additional_properties, expected_type=type_hints["additional_properties"]) - check_type(argname="argument all_of", value=all_of, expected_type=type_hints["all_of"]) - check_type(argname="argument any_of", value=any_of, expected_type=type_hints["any_of"]) - check_type(argname="argument default", value=default, expected_type=type_hints["default"]) - check_type(argname="argument definitions", value=definitions, expected_type=type_hints["definitions"]) - check_type(argname="argument dependencies", value=dependencies, expected_type=type_hints["dependencies"]) - check_type(argname="argument description", value=description, expected_type=type_hints["description"]) - check_type(argname="argument enum", value=enum, expected_type=type_hints["enum"]) - check_type(argname="argument example", value=example, expected_type=type_hints["example"]) - check_type(argname="argument exclusive_maximum", value=exclusive_maximum, expected_type=type_hints["exclusive_maximum"]) - check_type(argname="argument exclusive_minimum", value=exclusive_minimum, expected_type=type_hints["exclusive_minimum"]) - check_type(argname="argument external_docs", value=external_docs, expected_type=type_hints["external_docs"]) - check_type(argname="argument format", value=format, expected_type=type_hints["format"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument maximum", value=maximum, expected_type=type_hints["maximum"]) - check_type(argname="argument max_items", value=max_items, expected_type=type_hints["max_items"]) - check_type(argname="argument max_length", value=max_length, expected_type=type_hints["max_length"]) - check_type(argname="argument max_properties", value=max_properties, expected_type=type_hints["max_properties"]) - check_type(argname="argument minimum", value=minimum, expected_type=type_hints["minimum"]) - check_type(argname="argument min_items", value=min_items, expected_type=type_hints["min_items"]) - check_type(argname="argument min_length", value=min_length, expected_type=type_hints["min_length"]) - check_type(argname="argument min_properties", value=min_properties, expected_type=type_hints["min_properties"]) - check_type(argname="argument multiple_of", value=multiple_of, expected_type=type_hints["multiple_of"]) - check_type(argname="argument not_", value=not_, expected_type=type_hints["not_"]) - check_type(argname="argument nullable", value=nullable, expected_type=type_hints["nullable"]) - check_type(argname="argument one_of", value=one_of, expected_type=type_hints["one_of"]) - check_type(argname="argument pattern", value=pattern, expected_type=type_hints["pattern"]) - check_type(argname="argument pattern_properties", value=pattern_properties, expected_type=type_hints["pattern_properties"]) - check_type(argname="argument properties", value=properties, expected_type=type_hints["properties"]) - check_type(argname="argument ref", value=ref, expected_type=type_hints["ref"]) - check_type(argname="argument required", value=required, expected_type=type_hints["required"]) - check_type(argname="argument schema", value=schema, expected_type=type_hints["schema"]) - check_type(argname="argument title", value=title, expected_type=type_hints["title"]) - check_type(argname="argument type", value=type, expected_type=type_hints["type"]) - check_type(argname="argument unique_items", value=unique_items, expected_type=type_hints["unique_items"]) - check_type(argname="argument x_kubernetes_embedded_resource", value=x_kubernetes_embedded_resource, expected_type=type_hints["x_kubernetes_embedded_resource"]) - check_type(argname="argument x_kubernetes_int_or_string", value=x_kubernetes_int_or_string, expected_type=type_hints["x_kubernetes_int_or_string"]) - check_type(argname="argument x_kubernetes_list_map_keys", value=x_kubernetes_list_map_keys, expected_type=type_hints["x_kubernetes_list_map_keys"]) - check_type(argname="argument x_kubernetes_list_type", value=x_kubernetes_list_type, expected_type=type_hints["x_kubernetes_list_type"]) - check_type(argname="argument x_kubernetes_map_type", value=x_kubernetes_map_type, expected_type=type_hints["x_kubernetes_map_type"]) - check_type(argname="argument x_kubernetes_preserve_unknown_fields", value=x_kubernetes_preserve_unknown_fields, expected_type=type_hints["x_kubernetes_preserve_unknown_fields"]) - check_type(argname="argument x_kubernetes_validations", value=x_kubernetes_validations, expected_type=type_hints["x_kubernetes_validations"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if additional_items is not None: - self._values["additional_items"] = additional_items - if additional_properties is not None: - self._values["additional_properties"] = additional_properties - if all_of is not None: - self._values["all_of"] = all_of - if any_of is not None: - self._values["any_of"] = any_of - if default is not None: - self._values["default"] = default - if definitions is not None: - self._values["definitions"] = definitions - if dependencies is not None: - self._values["dependencies"] = dependencies - if description is not None: - self._values["description"] = description - if enum is not None: - self._values["enum"] = enum - if example is not None: - self._values["example"] = example - if exclusive_maximum is not None: - self._values["exclusive_maximum"] = exclusive_maximum - if exclusive_minimum is not None: - self._values["exclusive_minimum"] = exclusive_minimum - if external_docs is not None: - self._values["external_docs"] = external_docs - if format is not None: - self._values["format"] = format - if id is not None: - self._values["id"] = id - if items is not None: - self._values["items"] = items - if maximum is not None: - self._values["maximum"] = maximum - if max_items is not None: - self._values["max_items"] = max_items - if max_length is not None: - self._values["max_length"] = max_length - if max_properties is not None: - self._values["max_properties"] = max_properties - if minimum is not None: - self._values["minimum"] = minimum - if min_items is not None: - self._values["min_items"] = min_items - if min_length is not None: - self._values["min_length"] = min_length - if min_properties is not None: - self._values["min_properties"] = min_properties - if multiple_of is not None: - self._values["multiple_of"] = multiple_of - if not_ is not None: - self._values["not_"] = not_ - if nullable is not None: - self._values["nullable"] = nullable - if one_of is not None: - self._values["one_of"] = one_of - if pattern is not None: - self._values["pattern"] = pattern - if pattern_properties is not None: - self._values["pattern_properties"] = pattern_properties - if properties is not None: - self._values["properties"] = properties - if ref is not None: - self._values["ref"] = ref - if required is not None: - self._values["required"] = required - if schema is not None: - self._values["schema"] = schema - if title is not None: - self._values["title"] = title - if type is not None: - self._values["type"] = type - if unique_items is not None: - self._values["unique_items"] = unique_items - if x_kubernetes_embedded_resource is not None: - self._values["x_kubernetes_embedded_resource"] = x_kubernetes_embedded_resource - if x_kubernetes_int_or_string is not None: - self._values["x_kubernetes_int_or_string"] = x_kubernetes_int_or_string - if x_kubernetes_list_map_keys is not None: - self._values["x_kubernetes_list_map_keys"] = x_kubernetes_list_map_keys - if x_kubernetes_list_type is not None: - self._values["x_kubernetes_list_type"] = x_kubernetes_list_type - if x_kubernetes_map_type is not None: - self._values["x_kubernetes_map_type"] = x_kubernetes_map_type - if x_kubernetes_preserve_unknown_fields is not None: - self._values["x_kubernetes_preserve_unknown_fields"] = x_kubernetes_preserve_unknown_fields - if x_kubernetes_validations is not None: - self._values["x_kubernetes_validations"] = x_kubernetes_validations - - @builtins.property - def additional_items(self) -> typing.Any: - ''' - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#additionalItems - ''' - result = self._values.get("additional_items") - return typing.cast(typing.Any, result) - - @builtins.property - def additional_properties(self) -> typing.Any: - ''' - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#additionalProperties - ''' - result = self._values.get("additional_properties") - return typing.cast(typing.Any, result) - - @builtins.property - def all_of(self) -> typing.Optional[typing.List["JsonSchemaProps"]]: - ''' - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#allOf - ''' - result = self._values.get("all_of") - return typing.cast(typing.Optional[typing.List["JsonSchemaProps"]], result) - - @builtins.property - def any_of(self) -> typing.Optional[typing.List["JsonSchemaProps"]]: - ''' - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#anyOf - ''' - result = self._values.get("any_of") - return typing.cast(typing.Optional[typing.List["JsonSchemaProps"]], result) - - @builtins.property - def default(self) -> typing.Any: - '''default is a default value for undefined object fields. - - Defaulting is a beta feature under the CustomResourceDefaulting feature gate. Defaulting requires spec.preserveUnknownFields to be false. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#default - ''' - result = self._values.get("default") - return typing.cast(typing.Any, result) - - @builtins.property - def definitions( - self, - ) -> typing.Optional[typing.Mapping[builtins.str, "JsonSchemaProps"]]: - ''' - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#definitions - ''' - result = self._values.get("definitions") - return typing.cast(typing.Optional[typing.Mapping[builtins.str, "JsonSchemaProps"]], result) - - @builtins.property - def dependencies(self) -> typing.Optional[typing.Mapping[builtins.str, typing.Any]]: - ''' - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#dependencies - ''' - result = self._values.get("dependencies") - return typing.cast(typing.Optional[typing.Mapping[builtins.str, typing.Any]], result) - - @builtins.property - def description(self) -> typing.Optional[builtins.str]: - ''' - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#description - ''' - result = self._values.get("description") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def enum(self) -> typing.Optional[typing.List[typing.Any]]: - ''' - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#enum - ''' - result = self._values.get("enum") - return typing.cast(typing.Optional[typing.List[typing.Any]], result) - - @builtins.property - def example(self) -> typing.Any: - ''' - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#example - ''' - result = self._values.get("example") - return typing.cast(typing.Any, result) - - @builtins.property - def exclusive_maximum(self) -> typing.Optional[builtins.bool]: - ''' - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#exclusiveMaximum - ''' - result = self._values.get("exclusive_maximum") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def exclusive_minimum(self) -> typing.Optional[builtins.bool]: - ''' - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#exclusiveMinimum - ''' - result = self._values.get("exclusive_minimum") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def external_docs(self) -> typing.Optional[ExternalDocumentation]: - ''' - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#externalDocs - ''' - result = self._values.get("external_docs") - return typing.cast(typing.Optional[ExternalDocumentation], result) - - @builtins.property - def format(self) -> typing.Optional[builtins.str]: - '''format is an OpenAPI v3 format string. Unknown formats are ignored. The following formats are validated:. - - - bsonobjectid: a bson object ID, i.e. a 24 characters hex string - uri: an URI as parsed by Golang net/url.ParseRequestURI - email: an email address as parsed by Golang net/mail.ParseAddress - hostname: a valid representation for an Internet host name, as defined by RFC 1034, section 3.1 [RFC1034]. - ipv4: an IPv4 IP as parsed by Golang net.ParseIP - ipv6: an IPv6 IP as parsed by Golang net.ParseIP - cidr: a CIDR as parsed by Golang net.ParseCIDR - mac: a MAC address as parsed by Golang net.ParseMAC - uuid: an UUID that allows uppercase defined by the regex (?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$ - uuid3: an UUID3 that allows uppercase defined by the regex (?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?3[0-9a-f]{3}-?[0-9a-f]{4}-?[0-9a-f]{12}$ - uuid4: an UUID4 that allows uppercase defined by the regex (?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?4[0-9a-f]{3}-?[89ab][0-9a-f]{3}-?[0-9a-f]{12}$ - uuid5: an UUID5 that allows uppercase defined by the regex (?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?5[0-9a-f]{3}-?[89ab][0-9a-f]{3}-?[0-9a-f]{12}$ - isbn: an ISBN10 or ISBN13 number string like "0321751043" or "978-0321751041" - isbn10: an ISBN10 number string like "0321751043" - isbn13: an ISBN13 number string like "978-0321751041" - creditcard: a credit card number defined by the regex ^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\\d{3})\\d{11})$ with any non digit characters mixed in - ssn: a U.S. social security number following the regex ^\\d{3}[- ]?\\d{2}[- ]?\\d{4}$ - hexcolor: an hexadecimal color code like "#FFFFFF: following the regex ^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$ - rgbcolor: an RGB color code like rgb like "rgb(255,255,2559" - byte: base64 encoded binary data - password: any kind of string - date: a date string like "2006-01-02" as defined by full-date in RFC3339 - duration: a duration string like "22 ns" as parsed by Golang time.ParseDuration or compatible with Scala duration format - datetime: a date time string like "2014-12-15T19:30:20.000Z" as defined by date-time in RFC3339. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#format - ''' - result = self._values.get("format") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def id(self) -> typing.Optional[builtins.str]: - ''' - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#id - ''' - result = self._values.get("id") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def items(self) -> typing.Any: - ''' - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#items - ''' - result = self._values.get("items") - return typing.cast(typing.Any, result) - - @builtins.property - def maximum(self) -> typing.Optional[jsii.Number]: - ''' - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#maximum - ''' - result = self._values.get("maximum") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def max_items(self) -> typing.Optional[jsii.Number]: - ''' - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#maxItems - ''' - result = self._values.get("max_items") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def max_length(self) -> typing.Optional[jsii.Number]: - ''' - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#maxLength - ''' - result = self._values.get("max_length") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def max_properties(self) -> typing.Optional[jsii.Number]: - ''' - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#maxProperties - ''' - result = self._values.get("max_properties") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def minimum(self) -> typing.Optional[jsii.Number]: - ''' - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#minimum - ''' - result = self._values.get("minimum") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def min_items(self) -> typing.Optional[jsii.Number]: - ''' - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#minItems - ''' - result = self._values.get("min_items") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def min_length(self) -> typing.Optional[jsii.Number]: - ''' - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#minLength - ''' - result = self._values.get("min_length") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def min_properties(self) -> typing.Optional[jsii.Number]: - ''' - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#minProperties - ''' - result = self._values.get("min_properties") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def multiple_of(self) -> typing.Optional[jsii.Number]: - ''' - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#multipleOf - ''' - result = self._values.get("multiple_of") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def not_(self) -> typing.Optional["JsonSchemaProps"]: - ''' - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#not - ''' - result = self._values.get("not_") - return typing.cast(typing.Optional["JsonSchemaProps"], result) - - @builtins.property - def nullable(self) -> typing.Optional[builtins.bool]: - ''' - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#nullable - ''' - result = self._values.get("nullable") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def one_of(self) -> typing.Optional[typing.List["JsonSchemaProps"]]: - ''' - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#oneOf - ''' - result = self._values.get("one_of") - return typing.cast(typing.Optional[typing.List["JsonSchemaProps"]], result) - - @builtins.property - def pattern(self) -> typing.Optional[builtins.str]: - ''' - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#pattern - ''' - result = self._values.get("pattern") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def pattern_properties( - self, - ) -> typing.Optional[typing.Mapping[builtins.str, "JsonSchemaProps"]]: - ''' - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#patternProperties - ''' - result = self._values.get("pattern_properties") - return typing.cast(typing.Optional[typing.Mapping[builtins.str, "JsonSchemaProps"]], result) - - @builtins.property - def properties( - self, - ) -> typing.Optional[typing.Mapping[builtins.str, "JsonSchemaProps"]]: - ''' - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#properties - ''' - result = self._values.get("properties") - return typing.cast(typing.Optional[typing.Mapping[builtins.str, "JsonSchemaProps"]], result) - - @builtins.property - def ref(self) -> typing.Optional[builtins.str]: - ''' - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#$ref - ''' - result = self._values.get("ref") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def required(self) -> typing.Optional[typing.List[builtins.str]]: - ''' - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#required - ''' - result = self._values.get("required") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def schema(self) -> typing.Optional[builtins.str]: - ''' - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#$schema - ''' - result = self._values.get("schema") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def title(self) -> typing.Optional[builtins.str]: - ''' - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#title - ''' - result = self._values.get("title") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def type(self) -> typing.Optional[builtins.str]: - ''' - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#type - ''' - result = self._values.get("type") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def unique_items(self) -> typing.Optional[builtins.bool]: - ''' - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#uniqueItems - ''' - result = self._values.get("unique_items") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def x_kubernetes_embedded_resource(self) -> typing.Optional[builtins.bool]: - '''x-kubernetes-embedded-resource defines that the value is an embedded Kubernetes runtime.Object, with TypeMeta and ObjectMeta. The type must be object. It is allowed to further restrict the embedded object. kind, apiVersion and metadata are validated automatically. x-kubernetes-preserve-unknown-fields is allowed to be true, but does not have to be if the object is fully specified (up to kind, apiVersion, metadata). - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#x-kubernetes-embedded-resource - ''' - result = self._values.get("x_kubernetes_embedded_resource") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def x_kubernetes_int_or_string(self) -> typing.Optional[builtins.bool]: - '''x-kubernetes-int-or-string specifies that this value is either an integer or a string. - - If this is true, an empty type is allowed and type as child of anyOf is permitted if following one of the following patterns: - - 1. anyOf: - - - type: integer - - type: string - - 1. allOf: - - - anyOf: - - type: integer - - type: string - - ... zero or more - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#x-kubernetes-int-or-string - ''' - result = self._values.get("x_kubernetes_int_or_string") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def x_kubernetes_list_map_keys(self) -> typing.Optional[typing.List[builtins.str]]: - '''x-kubernetes-list-map-keys annotates an array with the x-kubernetes-list-type ``map`` by specifying the keys used as the index of the map. - - This tag MUST only be used on lists that have the "x-kubernetes-list-type" extension set to "map". Also, the values specified for this attribute must be a scalar typed field of the child structure (no nesting is supported). - - The properties specified must either be required or have a default value, to ensure those properties are present for all list items. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#x-kubernetes-list-map-keys - ''' - result = self._values.get("x_kubernetes_list_map_keys") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def x_kubernetes_list_type(self) -> typing.Optional[builtins.str]: - '''x-kubernetes-list-type annotates an array to further describe its topology. - - This extension must only be used on lists and may have 3 possible values: - - 1. ``atomic``: the list is treated as a single entity, like a scalar. - Atomic lists will be entirely replaced when updated. This extension - may be used on any type of list (struct, scalar, ...). - 2. ``set``: - Sets are lists that must not have multiple items with the same value. Each - value must be a scalar, an object with x-kubernetes-map-type ``atomic`` or an - array with x-kubernetes-list-type ``atomic``. - 3. ``map``: - These lists are like maps in that their elements have a non-index key - used to identify them. Order is preserved upon merge. The map tag - must only be used on a list with elements of type object. - Defaults to atomic for arrays. - - :default: atomic for arrays. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#x-kubernetes-list-type - ''' - result = self._values.get("x_kubernetes_list_type") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def x_kubernetes_map_type(self) -> typing.Optional[builtins.str]: - '''x-kubernetes-map-type annotates an object to further describe its topology. - - This extension must only be used when type is object and may have 2 possible values: - - 1. ``granular``: - These maps are actual maps (key-value pairs) and each fields are independent - from each other (they can each be manipulated by separate actors). This is - the default behaviour for all maps. - 2. ``atomic``: the list is treated as a single entity, like a scalar. - Atomic maps will be entirely replaced when updated. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#x-kubernetes-map-type - ''' - result = self._values.get("x_kubernetes_map_type") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def x_kubernetes_preserve_unknown_fields(self) -> typing.Optional[builtins.bool]: - '''x-kubernetes-preserve-unknown-fields stops the API server decoding step from pruning fields which are not specified in the validation schema. - - This affects fields recursively, but switches back to normal pruning behaviour if nested properties or additionalProperties are specified in the schema. This can either be true or undefined. False is forbidden. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#x-kubernetes-preserve-unknown-fields - ''' - result = self._values.get("x_kubernetes_preserve_unknown_fields") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def x_kubernetes_validations( - self, - ) -> typing.Optional[typing.List["ValidationRule"]]: - '''x-kubernetes-validations describes a list of validation rules written in the CEL expression language. - - This field is an alpha-level. Using this field requires the feature gate ``CustomResourceValidationExpressions`` to be enabled. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps#x-kubernetes-validations - ''' - result = self._values.get("x_kubernetes_validations") - return typing.cast(typing.Optional[typing.List["ValidationRule"]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "JsonSchemaProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KeyToPath", - jsii_struct_bases=[], - name_mapping={"key": "key", "path": "path", "mode": "mode"}, -) -class KeyToPath: - def __init__( - self, - *, - key: builtins.str, - path: builtins.str, - mode: typing.Optional[jsii.Number] = None, - ) -> None: - '''Maps a string key to a path within a volume. - - :param key: key is the key to project. - :param path: path is the relative path of the file to map the key to. May not be an absolute path. May not contain the path element '..'. May not start with the string '..'. - :param mode: mode is Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set. - - :schema: io.k8s.api.core.v1.KeyToPath - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__1f579c4b13a88f3186bcbc183fc5b54bf1b162f87adf1d2ad83a9a8b5e0bb447) - check_type(argname="argument key", value=key, expected_type=type_hints["key"]) - check_type(argname="argument path", value=path, expected_type=type_hints["path"]) - check_type(argname="argument mode", value=mode, expected_type=type_hints["mode"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "key": key, - "path": path, - } - if mode is not None: - self._values["mode"] = mode - - @builtins.property - def key(self) -> builtins.str: - '''key is the key to project. - - :schema: io.k8s.api.core.v1.KeyToPath#key - ''' - result = self._values.get("key") - assert result is not None, "Required property 'key' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def path(self) -> builtins.str: - '''path is the relative path of the file to map the key to. - - May not be an absolute path. May not contain the path element '..'. May not start with the string '..'. - - :schema: io.k8s.api.core.v1.KeyToPath#path - ''' - result = self._values.get("path") - assert result is not None, "Required property 'path' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def mode(self) -> typing.Optional[jsii.Number]: - '''mode is Optional: mode bits used to set permissions on this file. - - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set. - - :schema: io.k8s.api.core.v1.KeyToPath#mode - ''' - result = self._values.get("mode") - return typing.cast(typing.Optional[jsii.Number], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KeyToPath(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeApiService( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeApiService", -): - '''APIService represents a server for a particular GroupVersion. - - Name must be "version.group". - - :schema: io.k8s.kube-aggregator.pkg.apis.apiregistration.v1.APIService - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[ApiServiceSpec, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.kube-aggregator.pkg.apis.apiregistration.v1.APIService" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Spec contains information for locating and communicating with a server. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__ad1fad6e721ef9e49639f06836c185c6738b1170ece4dac50e287ae3f90985ef) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeApiServiceProps(metadata=metadata, spec=spec) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[ApiServiceSpec, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.kube-aggregator.pkg.apis.apiregistration.v1.APIService". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Spec contains information for locating and communicating with a server. - ''' - props = KubeApiServiceProps(metadata=metadata, spec=spec) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.kube-aggregator.pkg.apis.apiregistration.v1.APIService".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubeApiServiceList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeApiServiceList", -): - '''APIServiceList is a list of APIService objects. - - :schema: io.k8s.kube-aggregator.pkg.apis.apiregistration.v1.APIServiceList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeApiServiceProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.kube-aggregator.pkg.apis.apiregistration.v1.APIServiceList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: Items is the list of APIService. - :param metadata: Standard list metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__77fd17dee8360181013ec5a3e589f22059cfcb4847e3a0abf0dfd56b33024d5e) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeApiServiceListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeApiServiceProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.kube-aggregator.pkg.apis.apiregistration.v1.APIServiceList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: Items is the list of APIService. - :param metadata: Standard list metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - ''' - props = KubeApiServiceListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.kube-aggregator.pkg.apis.apiregistration.v1.APIServiceList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeApiServiceListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeApiServiceListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeApiServiceProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''APIServiceList is a list of APIService objects. - - :param items: Items is the list of APIService. - :param metadata: Standard list metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - - :schema: io.k8s.kube-aggregator.pkg.apis.apiregistration.v1.APIServiceList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__e14504c02b3947489445078365563d536c1ed7457661296ae07aa79c8452d4e1) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeApiServiceProps"]: - '''Items is the list of APIService. - - :schema: io.k8s.kube-aggregator.pkg.apis.apiregistration.v1.APIServiceList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeApiServiceProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - - :schema: io.k8s.kube-aggregator.pkg.apis.apiregistration.v1.APIServiceList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeApiServiceListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubeApiServiceProps", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata", "spec": "spec"}, -) -class KubeApiServiceProps: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[ApiServiceSpec, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''APIService represents a server for a particular GroupVersion. - - Name must be "version.group". - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Spec contains information for locating and communicating with a server. - - :schema: io.k8s.kube-aggregator.pkg.apis.apiregistration.v1.APIService - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if isinstance(spec, dict): - spec = ApiServiceSpec(**spec) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__fa388b54653e1794b03d081efbf5ba6ac4082c87f562e32c6beeaedcb2062b0f) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - if spec is not None: - self._values["spec"] = spec - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.kube-aggregator.pkg.apis.apiregistration.v1.APIService#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def spec(self) -> typing.Optional[ApiServiceSpec]: - '''Spec contains information for locating and communicating with a server. - - :schema: io.k8s.kube-aggregator.pkg.apis.apiregistration.v1.APIService#spec - ''' - result = self._values.get("spec") - return typing.cast(typing.Optional[ApiServiceSpec], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeApiServiceProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeBinding( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeBinding", -): - '''Binding ties one object to another; - - for example, a pod is bound to a node by a scheduler. Deprecated in 1.7, please use the bindings subresource of pods instead. - - :schema: io.k8s.api.core.v1.Binding - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - target: typing.Union["ObjectReference", typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.core.v1.Binding" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param target: The target object that you want to bind to the standard object. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__3278205b7b7726ad41ab6a4d62cd97f9a37714beb4600b6ee0290e7ff44f6280) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeBindingProps(target=target, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - target: typing.Union["ObjectReference", typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.core.v1.Binding". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param target: The target object that you want to bind to the standard object. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - props = KubeBindingProps(target=target, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.core.v1.Binding".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeBindingProps", - jsii_struct_bases=[], - name_mapping={"target": "target", "metadata": "metadata"}, -) -class KubeBindingProps: - def __init__( - self, - *, - target: typing.Union["ObjectReference", typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Binding ties one object to another; - - for example, a pod is bound to a node by a scheduler. Deprecated in 1.7, please use the bindings subresource of pods instead. - - :param target: The target object that you want to bind to the standard object. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.core.v1.Binding - ''' - if isinstance(target, dict): - target = ObjectReference(**target) - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__17f73704962797e0f37ad68c644b7528547425a2b7852b93aad34d9faee41a89) - check_type(argname="argument target", value=target, expected_type=type_hints["target"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "target": target, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def target(self) -> "ObjectReference": - '''The target object that you want to bind to the standard object. - - :schema: io.k8s.api.core.v1.Binding#target - ''' - result = self._values.get("target") - assert result is not None, "Required property 'target' is missing" - return typing.cast("ObjectReference", result) - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.core.v1.Binding#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeBindingProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeCertificateSigningRequest( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeCertificateSigningRequest", -): - '''CertificateSigningRequest objects provide a mechanism to obtain x509 certificates by submitting a certificate signing request, and having it asynchronously approved and issued. - - Kubelets use this API to obtain: - - 1. client certificates to authenticate to kube-apiserver (with the "kubernetes.io/kube-apiserver-client-kubelet" signerName). - 2. serving certificates for TLS endpoints kube-apiserver can connect to securely (with the "kubernetes.io/kubelet-serving" signerName). - - This API can be used to request client certificates to authenticate to kube-apiserver (with the "kubernetes.io/kube-apiserver-client" signerName), or to obtain certificates from custom non-Kubernetes signers. - - :schema: io.k8s.api.certificates.v1.CertificateSigningRequest - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - spec: typing.Union[CertificateSigningRequestSpec, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.certificates.v1.CertificateSigningRequest" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param spec: spec contains the certificate request, and is immutable after creation. Only the request, signerName, expirationSeconds, and usages fields can be set on creation. Other fields are derived by Kubernetes and cannot be modified by users. - :param metadata: - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__d8ca0f64663445c4ac257415151a8230f1cc231c9caccfdbdc0b6fa02d9459d2) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeCertificateSigningRequestProps(spec=spec, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - spec: typing.Union[CertificateSigningRequestSpec, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.certificates.v1.CertificateSigningRequest". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param spec: spec contains the certificate request, and is immutable after creation. Only the request, signerName, expirationSeconds, and usages fields can be set on creation. Other fields are derived by Kubernetes and cannot be modified by users. - :param metadata: - ''' - props = KubeCertificateSigningRequestProps(spec=spec, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.certificates.v1.CertificateSigningRequest".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubeCertificateSigningRequestList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeCertificateSigningRequestList", -): - '''CertificateSigningRequestList is a collection of CertificateSigningRequest objects. - - :schema: io.k8s.api.certificates.v1.CertificateSigningRequestList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeCertificateSigningRequestProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.certificates.v1.CertificateSigningRequestList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: items is a collection of CertificateSigningRequest objects. - :param metadata: - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__0e52ee2201ff43e5e93e3d5f4283d795109cda99111d410facf2ba779fca8f23) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeCertificateSigningRequestListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeCertificateSigningRequestProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.certificates.v1.CertificateSigningRequestList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: items is a collection of CertificateSigningRequest objects. - :param metadata: - ''' - props = KubeCertificateSigningRequestListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.certificates.v1.CertificateSigningRequestList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeCertificateSigningRequestListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeCertificateSigningRequestListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeCertificateSigningRequestProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''CertificateSigningRequestList is a collection of CertificateSigningRequest objects. - - :param items: items is a collection of CertificateSigningRequest objects. - :param metadata: - - :schema: io.k8s.api.certificates.v1.CertificateSigningRequestList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__2dcc4a87e5addcc1390a4a9233596ca3523db6bde4ddce413276e7da14156140) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeCertificateSigningRequestProps"]: - '''items is a collection of CertificateSigningRequest objects. - - :schema: io.k8s.api.certificates.v1.CertificateSigningRequestList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeCertificateSigningRequestProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - ''' - :schema: io.k8s.api.certificates.v1.CertificateSigningRequestList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeCertificateSigningRequestListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubeCertificateSigningRequestProps", - jsii_struct_bases=[], - name_mapping={"spec": "spec", "metadata": "metadata"}, -) -class KubeCertificateSigningRequestProps: - def __init__( - self, - *, - spec: typing.Union[CertificateSigningRequestSpec, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''CertificateSigningRequest objects provide a mechanism to obtain x509 certificates by submitting a certificate signing request, and having it asynchronously approved and issued. - - Kubelets use this API to obtain: - - 1. client certificates to authenticate to kube-apiserver (with the "kubernetes.io/kube-apiserver-client-kubelet" signerName). - 2. serving certificates for TLS endpoints kube-apiserver can connect to securely (with the "kubernetes.io/kubelet-serving" signerName). - - This API can be used to request client certificates to authenticate to kube-apiserver (with the "kubernetes.io/kube-apiserver-client" signerName), or to obtain certificates from custom non-Kubernetes signers. - - :param spec: spec contains the certificate request, and is immutable after creation. Only the request, signerName, expirationSeconds, and usages fields can be set on creation. Other fields are derived by Kubernetes and cannot be modified by users. - :param metadata: - - :schema: io.k8s.api.certificates.v1.CertificateSigningRequest - ''' - if isinstance(spec, dict): - spec = CertificateSigningRequestSpec(**spec) - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__ea26900e83d9c03052f5118bf686d1cf204888ec1fe99f0622dd1de5b45ebc2a) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "spec": spec, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def spec(self) -> CertificateSigningRequestSpec: - '''spec contains the certificate request, and is immutable after creation. - - Only the request, signerName, expirationSeconds, and usages fields can be set on creation. Other fields are derived by Kubernetes and cannot be modified by users. - - :schema: io.k8s.api.certificates.v1.CertificateSigningRequest#spec - ''' - result = self._values.get("spec") - assert result is not None, "Required property 'spec' is missing" - return typing.cast(CertificateSigningRequestSpec, result) - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - ''' - :schema: io.k8s.api.certificates.v1.CertificateSigningRequest#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeCertificateSigningRequestProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeClusterCidrListV1Alpha1( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeClusterCidrListV1Alpha1", -): - '''ClusterCIDRList contains a list of ClusterCIDR. - - :schema: io.k8s.api.networking.v1alpha1.ClusterCIDRList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeClusterCidrv1Alpha1Props", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.networking.v1alpha1.ClusterCIDRList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: Items is the list of ClusterCIDRs. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__bebe2c6d28eb4d63601ff21a7495134127d04e845886c60aef428b3c9d659d48) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeClusterCidrListV1Alpha1Props(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeClusterCidrv1Alpha1Props", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.networking.v1alpha1.ClusterCIDRList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: Items is the list of ClusterCIDRs. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - props = KubeClusterCidrListV1Alpha1Props(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.networking.v1alpha1.ClusterCIDRList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeClusterCidrListV1Alpha1Props", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeClusterCidrListV1Alpha1Props: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeClusterCidrv1Alpha1Props", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''ClusterCIDRList contains a list of ClusterCIDR. - - :param items: Items is the list of ClusterCIDRs. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.networking.v1alpha1.ClusterCIDRList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__2568516c61e397e6ffe9ac679a0c57c224fdd0d1ee2c188bf4282ba2ec5d1871) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeClusterCidrv1Alpha1Props"]: - '''Items is the list of ClusterCIDRs. - - :schema: io.k8s.api.networking.v1alpha1.ClusterCIDRList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeClusterCidrv1Alpha1Props"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.networking.v1alpha1.ClusterCIDRList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeClusterCidrListV1Alpha1Props(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeClusterCidrv1Alpha1( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeClusterCidrv1Alpha1", -): - '''ClusterCIDR represents a single configuration for per-Node Pod CIDR allocations when the MultiCIDRRangeAllocator is enabled (see the config for kube-controller-manager). - - A cluster may have any number of ClusterCIDR resources, all of which will be considered when allocating a CIDR for a Node. A ClusterCIDR is eligible to be used for a given Node when the node selector matches the node in question and has free CIDRs to allocate. In case of multiple matching ClusterCIDR resources, the allocator will attempt to break ties using internal heuristics, but any ClusterCIDR whose node selector matches the Node may be used. - - :schema: io.k8s.api.networking.v1alpha1.ClusterCIDR - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[ClusterCidrSpecV1Alpha1, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.networking.v1alpha1.ClusterCIDR" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Spec is the desired state of the ClusterCIDR. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__38c199ac22bb3d8686743ec4676956ef1167fe20e7487535199d00a97bec4353) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeClusterCidrv1Alpha1Props(metadata=metadata, spec=spec) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[ClusterCidrSpecV1Alpha1, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.networking.v1alpha1.ClusterCIDR". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Spec is the desired state of the ClusterCIDR. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - ''' - props = KubeClusterCidrv1Alpha1Props(metadata=metadata, spec=spec) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.networking.v1alpha1.ClusterCIDR".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeClusterCidrv1Alpha1Props", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata", "spec": "spec"}, -) -class KubeClusterCidrv1Alpha1Props: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[ClusterCidrSpecV1Alpha1, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''ClusterCIDR represents a single configuration for per-Node Pod CIDR allocations when the MultiCIDRRangeAllocator is enabled (see the config for kube-controller-manager). - - A cluster may have any number of ClusterCIDR resources, all of which will be considered when allocating a CIDR for a Node. A ClusterCIDR is eligible to be used for a given Node when the node selector matches the node in question and has free CIDRs to allocate. In case of multiple matching ClusterCIDR resources, the allocator will attempt to break ties using internal heuristics, but any ClusterCIDR whose node selector matches the Node may be used. - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Spec is the desired state of the ClusterCIDR. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.networking.v1alpha1.ClusterCIDR - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if isinstance(spec, dict): - spec = ClusterCidrSpecV1Alpha1(**spec) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__0b3f026fe04c5a65af81aa7b0f498e86a380bd11b60aaa10b02765b32bd15386) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - if spec is not None: - self._values["spec"] = spec - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.networking.v1alpha1.ClusterCIDR#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def spec(self) -> typing.Optional[ClusterCidrSpecV1Alpha1]: - '''Spec is the desired state of the ClusterCIDR. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.networking.v1alpha1.ClusterCIDR#spec - ''' - result = self._values.get("spec") - return typing.cast(typing.Optional[ClusterCidrSpecV1Alpha1], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeClusterCidrv1Alpha1Props(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeClusterRole( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeClusterRole", -): - '''ClusterRole is a cluster level, logical grouping of PolicyRules that can be referenced as a unit by a RoleBinding or ClusterRoleBinding. - - :schema: io.k8s.api.rbac.v1.ClusterRole - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - aggregation_rule: typing.Optional[typing.Union[AggregationRule, typing.Dict[builtins.str, typing.Any]]] = None, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - rules: typing.Optional[typing.Sequence[typing.Union["PolicyRule", typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''Defines a "io.k8s.api.rbac.v1.ClusterRole" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param aggregation_rule: AggregationRule is an optional field that describes how to build the Rules for this ClusterRole. If AggregationRule is set, then the Rules are controller managed and direct changes to Rules will be stomped by the controller. - :param metadata: Standard object's metadata. - :param rules: Rules holds all the PolicyRules for this ClusterRole. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__3dee6cbdf96ca0b97f9963be7a7a6f153933e9b244671b09569b2449b5df5bfb) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeClusterRoleProps( - aggregation_rule=aggregation_rule, metadata=metadata, rules=rules - ) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - aggregation_rule: typing.Optional[typing.Union[AggregationRule, typing.Dict[builtins.str, typing.Any]]] = None, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - rules: typing.Optional[typing.Sequence[typing.Union["PolicyRule", typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.rbac.v1.ClusterRole". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param aggregation_rule: AggregationRule is an optional field that describes how to build the Rules for this ClusterRole. If AggregationRule is set, then the Rules are controller managed and direct changes to Rules will be stomped by the controller. - :param metadata: Standard object's metadata. - :param rules: Rules holds all the PolicyRules for this ClusterRole. - ''' - props = KubeClusterRoleProps( - aggregation_rule=aggregation_rule, metadata=metadata, rules=rules - ) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.rbac.v1.ClusterRole".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubeClusterRoleBinding( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeClusterRoleBinding", -): - '''ClusterRoleBinding references a ClusterRole, but not contain it. - - It can reference a ClusterRole in the global namespace, and adds who information via Subject. - - :schema: io.k8s.api.rbac.v1.ClusterRoleBinding - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - role_ref: typing.Union["RoleRef", typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - subjects: typing.Optional[typing.Sequence[typing.Union["Subject", typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''Defines a "io.k8s.api.rbac.v1.ClusterRoleBinding" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param role_ref: RoleRef can only reference a ClusterRole in the global namespace. If the RoleRef cannot be resolved, the Authorizer must return an error. - :param metadata: Standard object's metadata. - :param subjects: Subjects holds references to the objects the role applies to. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__3e6775a7ad52980f5d176d04772d94063734f3c3829aeb08e03f9554da3c084e) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeClusterRoleBindingProps( - role_ref=role_ref, metadata=metadata, subjects=subjects - ) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - role_ref: typing.Union["RoleRef", typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - subjects: typing.Optional[typing.Sequence[typing.Union["Subject", typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.rbac.v1.ClusterRoleBinding". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param role_ref: RoleRef can only reference a ClusterRole in the global namespace. If the RoleRef cannot be resolved, the Authorizer must return an error. - :param metadata: Standard object's metadata. - :param subjects: Subjects holds references to the objects the role applies to. - ''' - props = KubeClusterRoleBindingProps( - role_ref=role_ref, metadata=metadata, subjects=subjects - ) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.rbac.v1.ClusterRoleBinding".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubeClusterRoleBindingList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeClusterRoleBindingList", -): - '''ClusterRoleBindingList is a collection of ClusterRoleBindings. - - :schema: io.k8s.api.rbac.v1.ClusterRoleBindingList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeClusterRoleBindingProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.rbac.v1.ClusterRoleBindingList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: Items is a list of ClusterRoleBindings. - :param metadata: Standard object's metadata. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__0c3606f96360dc6b85d5722a2bd315d4372920a7b08580cdd2b23ef4b3de402c) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeClusterRoleBindingListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeClusterRoleBindingProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.rbac.v1.ClusterRoleBindingList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: Items is a list of ClusterRoleBindings. - :param metadata: Standard object's metadata. - ''' - props = KubeClusterRoleBindingListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.rbac.v1.ClusterRoleBindingList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeClusterRoleBindingListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeClusterRoleBindingListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeClusterRoleBindingProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''ClusterRoleBindingList is a collection of ClusterRoleBindings. - - :param items: Items is a list of ClusterRoleBindings. - :param metadata: Standard object's metadata. - - :schema: io.k8s.api.rbac.v1.ClusterRoleBindingList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__2c82a518d0376ee32a141ec070cbf273462cdd5ce947e4b47885cda5cfe73403) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeClusterRoleBindingProps"]: - '''Items is a list of ClusterRoleBindings. - - :schema: io.k8s.api.rbac.v1.ClusterRoleBindingList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeClusterRoleBindingProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard object's metadata. - - :schema: io.k8s.api.rbac.v1.ClusterRoleBindingList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeClusterRoleBindingListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubeClusterRoleBindingProps", - jsii_struct_bases=[], - name_mapping={ - "role_ref": "roleRef", - "metadata": "metadata", - "subjects": "subjects", - }, -) -class KubeClusterRoleBindingProps: - def __init__( - self, - *, - role_ref: typing.Union["RoleRef", typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - subjects: typing.Optional[typing.Sequence[typing.Union["Subject", typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''ClusterRoleBinding references a ClusterRole, but not contain it. - - It can reference a ClusterRole in the global namespace, and adds who information via Subject. - - :param role_ref: RoleRef can only reference a ClusterRole in the global namespace. If the RoleRef cannot be resolved, the Authorizer must return an error. - :param metadata: Standard object's metadata. - :param subjects: Subjects holds references to the objects the role applies to. - - :schema: io.k8s.api.rbac.v1.ClusterRoleBinding - ''' - if isinstance(role_ref, dict): - role_ref = RoleRef(**role_ref) - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__257a9d454c53443a5bcf76ea68af6361260af7fedca4596fd5f3e37805c7a05f) - check_type(argname="argument role_ref", value=role_ref, expected_type=type_hints["role_ref"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument subjects", value=subjects, expected_type=type_hints["subjects"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "role_ref": role_ref, - } - if metadata is not None: - self._values["metadata"] = metadata - if subjects is not None: - self._values["subjects"] = subjects - - @builtins.property - def role_ref(self) -> "RoleRef": - '''RoleRef can only reference a ClusterRole in the global namespace. - - If the RoleRef cannot be resolved, the Authorizer must return an error. - - :schema: io.k8s.api.rbac.v1.ClusterRoleBinding#roleRef - ''' - result = self._values.get("role_ref") - assert result is not None, "Required property 'role_ref' is missing" - return typing.cast("RoleRef", result) - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata. - - :schema: io.k8s.api.rbac.v1.ClusterRoleBinding#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def subjects(self) -> typing.Optional[typing.List["Subject"]]: - '''Subjects holds references to the objects the role applies to. - - :schema: io.k8s.api.rbac.v1.ClusterRoleBinding#subjects - ''' - result = self._values.get("subjects") - return typing.cast(typing.Optional[typing.List["Subject"]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeClusterRoleBindingProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeClusterRoleList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeClusterRoleList", -): - '''ClusterRoleList is a collection of ClusterRoles. - - :schema: io.k8s.api.rbac.v1.ClusterRoleList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeClusterRoleProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.rbac.v1.ClusterRoleList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: Items is a list of ClusterRoles. - :param metadata: Standard object's metadata. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__2a7f78944eda3f35935b1126aeb9bacc3bb96930fb629d27ae700ff852b519da) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeClusterRoleListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeClusterRoleProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.rbac.v1.ClusterRoleList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: Items is a list of ClusterRoles. - :param metadata: Standard object's metadata. - ''' - props = KubeClusterRoleListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.rbac.v1.ClusterRoleList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeClusterRoleListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeClusterRoleListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeClusterRoleProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''ClusterRoleList is a collection of ClusterRoles. - - :param items: Items is a list of ClusterRoles. - :param metadata: Standard object's metadata. - - :schema: io.k8s.api.rbac.v1.ClusterRoleList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__3567db5c4e5df260e3bfb132c868492937f16ab86f1fd556633c1bdf5c23ac38) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeClusterRoleProps"]: - '''Items is a list of ClusterRoles. - - :schema: io.k8s.api.rbac.v1.ClusterRoleList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeClusterRoleProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard object's metadata. - - :schema: io.k8s.api.rbac.v1.ClusterRoleList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeClusterRoleListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubeClusterRoleProps", - jsii_struct_bases=[], - name_mapping={ - "aggregation_rule": "aggregationRule", - "metadata": "metadata", - "rules": "rules", - }, -) -class KubeClusterRoleProps: - def __init__( - self, - *, - aggregation_rule: typing.Optional[typing.Union[AggregationRule, typing.Dict[builtins.str, typing.Any]]] = None, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - rules: typing.Optional[typing.Sequence[typing.Union["PolicyRule", typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''ClusterRole is a cluster level, logical grouping of PolicyRules that can be referenced as a unit by a RoleBinding or ClusterRoleBinding. - - :param aggregation_rule: AggregationRule is an optional field that describes how to build the Rules for this ClusterRole. If AggregationRule is set, then the Rules are controller managed and direct changes to Rules will be stomped by the controller. - :param metadata: Standard object's metadata. - :param rules: Rules holds all the PolicyRules for this ClusterRole. - - :schema: io.k8s.api.rbac.v1.ClusterRole - ''' - if isinstance(aggregation_rule, dict): - aggregation_rule = AggregationRule(**aggregation_rule) - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__6faf558e694a82d5282c1ee1c2544179d7e40c708128f00e73fbc361becd9539) - check_type(argname="argument aggregation_rule", value=aggregation_rule, expected_type=type_hints["aggregation_rule"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument rules", value=rules, expected_type=type_hints["rules"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if aggregation_rule is not None: - self._values["aggregation_rule"] = aggregation_rule - if metadata is not None: - self._values["metadata"] = metadata - if rules is not None: - self._values["rules"] = rules - - @builtins.property - def aggregation_rule(self) -> typing.Optional[AggregationRule]: - '''AggregationRule is an optional field that describes how to build the Rules for this ClusterRole. - - If AggregationRule is set, then the Rules are controller managed and direct changes to Rules will be stomped by the controller. - - :schema: io.k8s.api.rbac.v1.ClusterRole#aggregationRule - ''' - result = self._values.get("aggregation_rule") - return typing.cast(typing.Optional[AggregationRule], result) - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata. - - :schema: io.k8s.api.rbac.v1.ClusterRole#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def rules(self) -> typing.Optional[typing.List["PolicyRule"]]: - '''Rules holds all the PolicyRules for this ClusterRole. - - :schema: io.k8s.api.rbac.v1.ClusterRole#rules - ''' - result = self._values.get("rules") - return typing.cast(typing.Optional[typing.List["PolicyRule"]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeClusterRoleProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeComponentStatus( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeComponentStatus", -): - '''ComponentStatus (and ComponentStatusList) holds the cluster validation info. - - Deprecated: This API is deprecated in v1.19+ - - :schema: io.k8s.api.core.v1.ComponentStatus - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - conditions: typing.Optional[typing.Sequence[typing.Union[ComponentCondition, typing.Dict[builtins.str, typing.Any]]]] = None, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.core.v1.ComponentStatus" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param conditions: List of component conditions observed. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__d8eff1e5ed3dcdcfd0064a2af74f4bb031286a15e4ced98c55de4d26be394984) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeComponentStatusProps(conditions=conditions, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - conditions: typing.Optional[typing.Sequence[typing.Union[ComponentCondition, typing.Dict[builtins.str, typing.Any]]]] = None, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.core.v1.ComponentStatus". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param conditions: List of component conditions observed. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - props = KubeComponentStatusProps(conditions=conditions, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.core.v1.ComponentStatus".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubeComponentStatusList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeComponentStatusList", -): - '''Status of all the conditions for the component as a list of ComponentStatus objects. - - Deprecated: This API is deprecated in v1.19+ - - :schema: io.k8s.api.core.v1.ComponentStatusList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeComponentStatusProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.core.v1.ComponentStatusList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: List of ComponentStatus objects. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__0d9905c184dc69ca415f46304054e8fc5f1fccdfa501490bb06a6ae27a2d0ba1) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeComponentStatusListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeComponentStatusProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.core.v1.ComponentStatusList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: List of ComponentStatus objects. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - ''' - props = KubeComponentStatusListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.core.v1.ComponentStatusList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeComponentStatusListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeComponentStatusListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeComponentStatusProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Status of all the conditions for the component as a list of ComponentStatus objects. - - Deprecated: This API is deprecated in v1.19+ - - :param items: List of ComponentStatus objects. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.core.v1.ComponentStatusList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__5c9df658fe078e86baff4d98993a70937fe9986e7be888a790e26f3c6c308a3c) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeComponentStatusProps"]: - '''List of ComponentStatus objects. - - :schema: io.k8s.api.core.v1.ComponentStatusList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeComponentStatusProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.core.v1.ComponentStatusList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeComponentStatusListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubeComponentStatusProps", - jsii_struct_bases=[], - name_mapping={"conditions": "conditions", "metadata": "metadata"}, -) -class KubeComponentStatusProps: - def __init__( - self, - *, - conditions: typing.Optional[typing.Sequence[typing.Union[ComponentCondition, typing.Dict[builtins.str, typing.Any]]]] = None, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''ComponentStatus (and ComponentStatusList) holds the cluster validation info. - - Deprecated: This API is deprecated in v1.19+ - - :param conditions: List of component conditions observed. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.core.v1.ComponentStatus - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__67f24fea501ac86ffd29cd8da4d47fae1b8eb42d42c249efb3614ebb5feb3863) - check_type(argname="argument conditions", value=conditions, expected_type=type_hints["conditions"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if conditions is not None: - self._values["conditions"] = conditions - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def conditions(self) -> typing.Optional[typing.List[ComponentCondition]]: - '''List of component conditions observed. - - :schema: io.k8s.api.core.v1.ComponentStatus#conditions - ''' - result = self._values.get("conditions") - return typing.cast(typing.Optional[typing.List[ComponentCondition]], result) - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.core.v1.ComponentStatus#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeComponentStatusProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeConfigMap( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeConfigMap", -): - '''ConfigMap holds configuration data for pods to consume. - - :schema: io.k8s.api.core.v1.ConfigMap - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - binary_data: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - data: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - immutable: typing.Optional[builtins.bool] = None, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.core.v1.ConfigMap" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param binary_data: BinaryData contains the binary data. Each key must consist of alphanumeric characters, '-', '_' or '.'. BinaryData can contain byte sequences that are not in the UTF-8 range. The keys stored in BinaryData must not overlap with the ones in the Data field, this is enforced during validation process. Using this field will require 1.10+ apiserver and kubelet. - :param data: Data contains the configuration data. Each key must consist of alphanumeric characters, '-', '_' or '.'. Values with non-UTF-8 byte sequences must use the BinaryData field. The keys stored in Data must not overlap with the keys in the BinaryData field, this is enforced during validation process. - :param immutable: Immutable, if set to true, ensures that data stored in the ConfigMap cannot be updated (only object metadata can be modified). If not set to true, the field can be modified at any time. Defaulted to nil. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__44ace9753e03a95f69ddde69315c9f4f0d5af51063739be870b98c92d1309343) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeConfigMapProps( - binary_data=binary_data, data=data, immutable=immutable, metadata=metadata - ) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - binary_data: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - data: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - immutable: typing.Optional[builtins.bool] = None, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.core.v1.ConfigMap". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param binary_data: BinaryData contains the binary data. Each key must consist of alphanumeric characters, '-', '_' or '.'. BinaryData can contain byte sequences that are not in the UTF-8 range. The keys stored in BinaryData must not overlap with the ones in the Data field, this is enforced during validation process. Using this field will require 1.10+ apiserver and kubelet. - :param data: Data contains the configuration data. Each key must consist of alphanumeric characters, '-', '_' or '.'. Values with non-UTF-8 byte sequences must use the BinaryData field. The keys stored in Data must not overlap with the keys in the BinaryData field, this is enforced during validation process. - :param immutable: Immutable, if set to true, ensures that data stored in the ConfigMap cannot be updated (only object metadata can be modified). If not set to true, the field can be modified at any time. Defaulted to nil. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - props = KubeConfigMapProps( - binary_data=binary_data, data=data, immutable=immutable, metadata=metadata - ) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.core.v1.ConfigMap".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubeConfigMapList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeConfigMapList", -): - '''ConfigMapList is a resource containing a list of ConfigMap objects. - - :schema: io.k8s.api.core.v1.ConfigMapList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeConfigMapProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.core.v1.ConfigMapList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: Items is the list of ConfigMaps. - :param metadata: More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__bc144a49936aebdfc387ec91a45153a5fd302f7ee0809a80a9ce001cf966a1ab) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeConfigMapListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeConfigMapProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.core.v1.ConfigMapList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: Items is the list of ConfigMaps. - :param metadata: More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - ''' - props = KubeConfigMapListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.core.v1.ConfigMapList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeConfigMapListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeConfigMapListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeConfigMapProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''ConfigMapList is a resource containing a list of ConfigMap objects. - - :param items: Items is the list of ConfigMaps. - :param metadata: More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - - :schema: io.k8s.api.core.v1.ConfigMapList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__48767662592e262431179254e449350dab987b1cb93287f37b377cb0152ccfe0) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeConfigMapProps"]: - '''Items is the list of ConfigMaps. - - :schema: io.k8s.api.core.v1.ConfigMapList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeConfigMapProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - - :schema: io.k8s.api.core.v1.ConfigMapList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeConfigMapListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubeConfigMapProps", - jsii_struct_bases=[], - name_mapping={ - "binary_data": "binaryData", - "data": "data", - "immutable": "immutable", - "metadata": "metadata", - }, -) -class KubeConfigMapProps: - def __init__( - self, - *, - binary_data: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - data: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - immutable: typing.Optional[builtins.bool] = None, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''ConfigMap holds configuration data for pods to consume. - - :param binary_data: BinaryData contains the binary data. Each key must consist of alphanumeric characters, '-', '_' or '.'. BinaryData can contain byte sequences that are not in the UTF-8 range. The keys stored in BinaryData must not overlap with the ones in the Data field, this is enforced during validation process. Using this field will require 1.10+ apiserver and kubelet. - :param data: Data contains the configuration data. Each key must consist of alphanumeric characters, '-', '_' or '.'. Values with non-UTF-8 byte sequences must use the BinaryData field. The keys stored in Data must not overlap with the keys in the BinaryData field, this is enforced during validation process. - :param immutable: Immutable, if set to true, ensures that data stored in the ConfigMap cannot be updated (only object metadata can be modified). If not set to true, the field can be modified at any time. Defaulted to nil. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.core.v1.ConfigMap - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__1a39b77b09572a5978b914a6a73c5b5de4761e48a8d3b3d72892406c734d515a) - check_type(argname="argument binary_data", value=binary_data, expected_type=type_hints["binary_data"]) - check_type(argname="argument data", value=data, expected_type=type_hints["data"]) - check_type(argname="argument immutable", value=immutable, expected_type=type_hints["immutable"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if binary_data is not None: - self._values["binary_data"] = binary_data - if data is not None: - self._values["data"] = data - if immutable is not None: - self._values["immutable"] = immutable - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def binary_data( - self, - ) -> typing.Optional[typing.Mapping[builtins.str, builtins.str]]: - '''BinaryData contains the binary data. - - Each key must consist of alphanumeric characters, '-', '_' or '.'. BinaryData can contain byte sequences that are not in the UTF-8 range. The keys stored in BinaryData must not overlap with the ones in the Data field, this is enforced during validation process. Using this field will require 1.10+ apiserver and kubelet. - - :schema: io.k8s.api.core.v1.ConfigMap#binaryData - ''' - result = self._values.get("binary_data") - return typing.cast(typing.Optional[typing.Mapping[builtins.str, builtins.str]], result) - - @builtins.property - def data(self) -> typing.Optional[typing.Mapping[builtins.str, builtins.str]]: - '''Data contains the configuration data. - - Each key must consist of alphanumeric characters, '-', '_' or '.'. Values with non-UTF-8 byte sequences must use the BinaryData field. The keys stored in Data must not overlap with the keys in the BinaryData field, this is enforced during validation process. - - :schema: io.k8s.api.core.v1.ConfigMap#data - ''' - result = self._values.get("data") - return typing.cast(typing.Optional[typing.Mapping[builtins.str, builtins.str]], result) - - @builtins.property - def immutable(self) -> typing.Optional[builtins.bool]: - '''Immutable, if set to true, ensures that data stored in the ConfigMap cannot be updated (only object metadata can be modified). - - If not set to true, the field can be modified at any time. Defaulted to nil. - - :schema: io.k8s.api.core.v1.ConfigMap#immutable - ''' - result = self._values.get("immutable") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.core.v1.ConfigMap#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeConfigMapProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeControllerRevision( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeControllerRevision", -): - '''ControllerRevision implements an immutable snapshot of state data. - - Clients are responsible for serializing and deserializing the objects that contain their internal state. Once a ControllerRevision has been successfully created, it can not be updated. The API Server will fail validation of all requests that attempt to mutate the Data field. ControllerRevisions may, however, be deleted. Note that, due to its use by both the DaemonSet and StatefulSet controllers for update and rollback, this object is beta. However, it may be subject to name and representation changes in future releases, and clients should not depend on its stability. It is primarily for internal use by controllers. - - :schema: io.k8s.api.apps.v1.ControllerRevision - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - revision: jsii.Number, - data: typing.Any = None, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.apps.v1.ControllerRevision" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param revision: Revision indicates the revision of the state represented by Data. - :param data: Data is the serialized representation of the state. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__3f6bf27fc901e0e15fea30db5d1c34b86ec9c3614e410979df0e341049bf3822) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeControllerRevisionProps( - revision=revision, data=data, metadata=metadata - ) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - revision: jsii.Number, - data: typing.Any = None, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.apps.v1.ControllerRevision". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param revision: Revision indicates the revision of the state represented by Data. - :param data: Data is the serialized representation of the state. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - props = KubeControllerRevisionProps( - revision=revision, data=data, metadata=metadata - ) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.apps.v1.ControllerRevision".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubeControllerRevisionList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeControllerRevisionList", -): - '''ControllerRevisionList is a resource containing a list of ControllerRevision objects. - - :schema: io.k8s.api.apps.v1.ControllerRevisionList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeControllerRevisionProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.apps.v1.ControllerRevisionList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: Items is the list of ControllerRevisions. - :param metadata: More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__53efa27ce81b16cf7569d10e432e48ab5aea03632a8afb6454ccfa8e6454c620) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeControllerRevisionListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeControllerRevisionProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.apps.v1.ControllerRevisionList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: Items is the list of ControllerRevisions. - :param metadata: More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - ''' - props = KubeControllerRevisionListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.apps.v1.ControllerRevisionList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeControllerRevisionListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeControllerRevisionListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeControllerRevisionProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''ControllerRevisionList is a resource containing a list of ControllerRevision objects. - - :param items: Items is the list of ControllerRevisions. - :param metadata: More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - - :schema: io.k8s.api.apps.v1.ControllerRevisionList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__b4279c16d501dc382f5edb2bf61182477b32760c149cdd162209ec9571c29ccf) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeControllerRevisionProps"]: - '''Items is the list of ControllerRevisions. - - :schema: io.k8s.api.apps.v1.ControllerRevisionList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeControllerRevisionProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - - :schema: io.k8s.api.apps.v1.ControllerRevisionList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeControllerRevisionListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubeControllerRevisionProps", - jsii_struct_bases=[], - name_mapping={"revision": "revision", "data": "data", "metadata": "metadata"}, -) -class KubeControllerRevisionProps: - def __init__( - self, - *, - revision: jsii.Number, - data: typing.Any = None, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''ControllerRevision implements an immutable snapshot of state data. - - Clients are responsible for serializing and deserializing the objects that contain their internal state. Once a ControllerRevision has been successfully created, it can not be updated. The API Server will fail validation of all requests that attempt to mutate the Data field. ControllerRevisions may, however, be deleted. Note that, due to its use by both the DaemonSet and StatefulSet controllers for update and rollback, this object is beta. However, it may be subject to name and representation changes in future releases, and clients should not depend on its stability. It is primarily for internal use by controllers. - - :param revision: Revision indicates the revision of the state represented by Data. - :param data: Data is the serialized representation of the state. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.apps.v1.ControllerRevision - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__2de468b613a3e33f95f5158a17d168ea0ab46ec3ccc31df40206c6abcc1e847c) - check_type(argname="argument revision", value=revision, expected_type=type_hints["revision"]) - check_type(argname="argument data", value=data, expected_type=type_hints["data"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "revision": revision, - } - if data is not None: - self._values["data"] = data - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def revision(self) -> jsii.Number: - '''Revision indicates the revision of the state represented by Data. - - :schema: io.k8s.api.apps.v1.ControllerRevision#revision - ''' - result = self._values.get("revision") - assert result is not None, "Required property 'revision' is missing" - return typing.cast(jsii.Number, result) - - @builtins.property - def data(self) -> typing.Any: - '''Data is the serialized representation of the state. - - :schema: io.k8s.api.apps.v1.ControllerRevision#data - ''' - result = self._values.get("data") - return typing.cast(typing.Any, result) - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.apps.v1.ControllerRevision#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeControllerRevisionProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeCronJob( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeCronJob", -): - '''CronJob represents the configuration of a single cron job. - - :schema: io.k8s.api.batch.v1.CronJob - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[CronJobSpec, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.batch.v1.CronJob" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Specification of the desired behavior of a cron job, including the schedule. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__6f1a45e449c623808f20a18094f28e7c251c7307291135b721a1487e56524e00) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeCronJobProps(metadata=metadata, spec=spec) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[CronJobSpec, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.batch.v1.CronJob". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Specification of the desired behavior of a cron job, including the schedule. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - ''' - props = KubeCronJobProps(metadata=metadata, spec=spec) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.batch.v1.CronJob".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubeCronJobList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeCronJobList", -): - '''CronJobList is a collection of cron jobs. - - :schema: io.k8s.api.batch.v1.CronJobList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeCronJobProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.batch.v1.CronJobList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: items is the list of CronJobs. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__bcac49fe1ddc47b748d3a574b6b07b351b0ff80b7dc9c34aa888370f7d9b0db7) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeCronJobListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeCronJobProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.batch.v1.CronJobList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: items is the list of CronJobs. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - props = KubeCronJobListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.batch.v1.CronJobList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeCronJobListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeCronJobListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeCronJobProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''CronJobList is a collection of cron jobs. - - :param items: items is the list of CronJobs. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.batch.v1.CronJobList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__06c3ad596042c9920e15bed2efd12904b2272ff2c9e68409c0600e6a9c884986) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeCronJobProps"]: - '''items is the list of CronJobs. - - :schema: io.k8s.api.batch.v1.CronJobList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeCronJobProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.batch.v1.CronJobList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeCronJobListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubeCronJobProps", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata", "spec": "spec"}, -) -class KubeCronJobProps: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[CronJobSpec, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''CronJob represents the configuration of a single cron job. - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Specification of the desired behavior of a cron job, including the schedule. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.batch.v1.CronJob - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if isinstance(spec, dict): - spec = CronJobSpec(**spec) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__8c260e3c5e7fe913831f1f3fd5594cf9e987523fa1fe919b7bd14b3830dc4259) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - if spec is not None: - self._values["spec"] = spec - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.batch.v1.CronJob#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def spec(self) -> typing.Optional[CronJobSpec]: - '''Specification of the desired behavior of a cron job, including the schedule. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.batch.v1.CronJob#spec - ''' - result = self._values.get("spec") - return typing.cast(typing.Optional[CronJobSpec], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeCronJobProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeCsiDriver( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeCsiDriver", -): - '''CSIDriver captures information about a Container Storage Interface (CSI) volume driver deployed on the cluster. - - Kubernetes attach detach controller uses this object to determine whether attach is required. Kubelet uses this object to determine whether pod information needs to be passed on mount. CSIDriver objects are non-namespaced. - - :schema: io.k8s.api.storage.v1.CSIDriver - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - spec: typing.Union[CsiDriverSpec, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.storage.v1.CSIDriver" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param spec: Specification of the CSI Driver. - :param metadata: Standard object metadata. metadata.Name indicates the name of the CSI driver that this object refers to; it MUST be the same name returned by the CSI GetPluginName() call for that driver. The driver name must be 63 characters or less, beginning and ending with an alphanumeric character ([a-z0-9A-Z]) with dashes (-), dots (.), and alphanumerics between. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__6e7e584127b81c956ad07d8cf4276ab9626e642741a92936946c0e875c29d3a1) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeCsiDriverProps(spec=spec, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - spec: typing.Union[CsiDriverSpec, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.storage.v1.CSIDriver". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param spec: Specification of the CSI Driver. - :param metadata: Standard object metadata. metadata.Name indicates the name of the CSI driver that this object refers to; it MUST be the same name returned by the CSI GetPluginName() call for that driver. The driver name must be 63 characters or less, beginning and ending with an alphanumeric character ([a-z0-9A-Z]) with dashes (-), dots (.), and alphanumerics between. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - props = KubeCsiDriverProps(spec=spec, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.storage.v1.CSIDriver".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubeCsiDriverList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeCsiDriverList", -): - '''CSIDriverList is a collection of CSIDriver objects. - - :schema: io.k8s.api.storage.v1.CSIDriverList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeCsiDriverProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.storage.v1.CSIDriverList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: items is the list of CSIDriver. - :param metadata: Standard list metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__b44071bd892488f6cfd5df886a9920126e60fa5a0934f4b7139d3fb2d7d22baa) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeCsiDriverListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeCsiDriverProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.storage.v1.CSIDriverList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: items is the list of CSIDriver. - :param metadata: Standard list metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - ''' - props = KubeCsiDriverListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.storage.v1.CSIDriverList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeCsiDriverListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeCsiDriverListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeCsiDriverProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''CSIDriverList is a collection of CSIDriver objects. - - :param items: items is the list of CSIDriver. - :param metadata: Standard list metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - - :schema: io.k8s.api.storage.v1.CSIDriverList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__8a6ccbefd0e7c044fdda4f1e093169516e8d19ebafaa273f96679b9ab863cdf9) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeCsiDriverProps"]: - '''items is the list of CSIDriver. - - :schema: io.k8s.api.storage.v1.CSIDriverList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeCsiDriverProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - - :schema: io.k8s.api.storage.v1.CSIDriverList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeCsiDriverListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubeCsiDriverProps", - jsii_struct_bases=[], - name_mapping={"spec": "spec", "metadata": "metadata"}, -) -class KubeCsiDriverProps: - def __init__( - self, - *, - spec: typing.Union[CsiDriverSpec, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''CSIDriver captures information about a Container Storage Interface (CSI) volume driver deployed on the cluster. - - Kubernetes attach detach controller uses this object to determine whether attach is required. Kubelet uses this object to determine whether pod information needs to be passed on mount. CSIDriver objects are non-namespaced. - - :param spec: Specification of the CSI Driver. - :param metadata: Standard object metadata. metadata.Name indicates the name of the CSI driver that this object refers to; it MUST be the same name returned by the CSI GetPluginName() call for that driver. The driver name must be 63 characters or less, beginning and ending with an alphanumeric character ([a-z0-9A-Z]) with dashes (-), dots (.), and alphanumerics between. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.storage.v1.CSIDriver - ''' - if isinstance(spec, dict): - spec = CsiDriverSpec(**spec) - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__192ebe10745c7f8861d48c71de7ec8b38130461925dd6355d7c98af27ca4a75e) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "spec": spec, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def spec(self) -> CsiDriverSpec: - '''Specification of the CSI Driver. - - :schema: io.k8s.api.storage.v1.CSIDriver#spec - ''' - result = self._values.get("spec") - assert result is not None, "Required property 'spec' is missing" - return typing.cast(CsiDriverSpec, result) - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object metadata. - - metadata.Name indicates the name of the CSI driver that this object refers to; it MUST be the same name returned by the CSI GetPluginName() call for that driver. The driver name must be 63 characters or less, beginning and ending with an alphanumeric character ([a-z0-9A-Z]) with dashes (-), dots (.), and alphanumerics between. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.storage.v1.CSIDriver#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeCsiDriverProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeCsiNode( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeCsiNode", -): - '''CSINode holds information about all CSI drivers installed on a node. - - CSI drivers do not need to create the CSINode object directly. As long as they use the node-driver-registrar sidecar container, the kubelet will automatically populate the CSINode object for the CSI driver as part of kubelet plugin registration. CSINode has the same name as a node. If the object is missing, it means either there are no CSI Drivers available on the node, or the Kubelet version is low enough that it doesn't create this object. CSINode has an OwnerReference that points to the corresponding node object. - - :schema: io.k8s.api.storage.v1.CSINode - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - spec: typing.Union[CsiNodeSpec, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.storage.v1.CSINode" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param spec: spec is the specification of CSINode. - :param metadata: metadata.name must be the Kubernetes node name. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__7dd065420aed16ce38e08784b9f9c9401b5ee146421a5de47261e92390d97f7f) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeCsiNodeProps(spec=spec, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - spec: typing.Union[CsiNodeSpec, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.storage.v1.CSINode". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param spec: spec is the specification of CSINode. - :param metadata: metadata.name must be the Kubernetes node name. - ''' - props = KubeCsiNodeProps(spec=spec, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.storage.v1.CSINode".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubeCsiNodeList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeCsiNodeList", -): - '''CSINodeList is a collection of CSINode objects. - - :schema: io.k8s.api.storage.v1.CSINodeList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeCsiNodeProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.storage.v1.CSINodeList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: items is the list of CSINode. - :param metadata: Standard list metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__0deee8737363a6bd1dbec0ca3dacc8cee5d8804a1ad839104355341fbb23d96e) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeCsiNodeListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeCsiNodeProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.storage.v1.CSINodeList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: items is the list of CSINode. - :param metadata: Standard list metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - ''' - props = KubeCsiNodeListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.storage.v1.CSINodeList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeCsiNodeListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeCsiNodeListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeCsiNodeProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''CSINodeList is a collection of CSINode objects. - - :param items: items is the list of CSINode. - :param metadata: Standard list metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - - :schema: io.k8s.api.storage.v1.CSINodeList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__66913be37f64f6682b27e7f3a521516525d302b97ec992adec50d5de0ba5090d) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeCsiNodeProps"]: - '''items is the list of CSINode. - - :schema: io.k8s.api.storage.v1.CSINodeList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeCsiNodeProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - - :schema: io.k8s.api.storage.v1.CSINodeList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeCsiNodeListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubeCsiNodeProps", - jsii_struct_bases=[], - name_mapping={"spec": "spec", "metadata": "metadata"}, -) -class KubeCsiNodeProps: - def __init__( - self, - *, - spec: typing.Union[CsiNodeSpec, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''CSINode holds information about all CSI drivers installed on a node. - - CSI drivers do not need to create the CSINode object directly. As long as they use the node-driver-registrar sidecar container, the kubelet will automatically populate the CSINode object for the CSI driver as part of kubelet plugin registration. CSINode has the same name as a node. If the object is missing, it means either there are no CSI Drivers available on the node, or the Kubelet version is low enough that it doesn't create this object. CSINode has an OwnerReference that points to the corresponding node object. - - :param spec: spec is the specification of CSINode. - :param metadata: metadata.name must be the Kubernetes node name. - - :schema: io.k8s.api.storage.v1.CSINode - ''' - if isinstance(spec, dict): - spec = CsiNodeSpec(**spec) - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__42b00c3000fc9438453d9f4f95e20b93766d5f40f65fce8ca9b29b21e1ab5b96) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "spec": spec, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def spec(self) -> CsiNodeSpec: - '''spec is the specification of CSINode. - - :schema: io.k8s.api.storage.v1.CSINode#spec - ''' - result = self._values.get("spec") - assert result is not None, "Required property 'spec' is missing" - return typing.cast(CsiNodeSpec, result) - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''metadata.name must be the Kubernetes node name. - - :schema: io.k8s.api.storage.v1.CSINode#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeCsiNodeProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeCsiStorageCapacity( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeCsiStorageCapacity", -): - '''CSIStorageCapacity stores the result of one CSI GetCapacity call. - - For a given StorageClass, this describes the available capacity in a particular topology segment. This can be used when considering where to instantiate new PersistentVolumes. - - For example this can express things like: - StorageClass "standard" has "1234 GiB" available in "topology.kubernetes.io/zone=us-east1" - StorageClass "localssd" has "10 GiB" available in "kubernetes.io/hostname=knode-abc123" - - The following three cases all imply that no capacity is available for a certain combination: - no object exists with suitable topology and storage class name - such an object exists, but the capacity is unset - such an object exists, but the capacity is zero - - The producer of these objects can decide which approach is more suitable. - - They are consumed by the kube-scheduler when a CSI driver opts into capacity-aware scheduling with CSIDriverSpec.StorageCapacity. The scheduler compares the MaximumVolumeSize against the requested size of pending volumes to filter out unsuitable nodes. If MaximumVolumeSize is unset, it falls back to a comparison against the less precise Capacity. If that is also unset, the scheduler assumes that capacity is insufficient and tries some other node. - - :schema: io.k8s.api.storage.v1.CSIStorageCapacity - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - storage_class_name: builtins.str, - capacity: typing.Optional["Quantity"] = None, - maximum_volume_size: typing.Optional["Quantity"] = None, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - node_topology: typing.Optional[typing.Union["LabelSelector", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.storage.v1.CSIStorageCapacity" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param storage_class_name: The name of the StorageClass that the reported capacity applies to. It must meet the same requirements as the name of a StorageClass object (non-empty, DNS subdomain). If that object no longer exists, the CSIStorageCapacity object is obsolete and should be removed by its creator. This field is immutable. - :param capacity: Capacity is the value reported by the CSI driver in its GetCapacityResponse for a GetCapacityRequest with topology and parameters that match the previous fields. The semantic is currently (CSI spec 1.2) defined as: The available capacity, in bytes, of the storage that can be used to provision volumes. If not set, that information is currently unavailable. - :param maximum_volume_size: MaximumVolumeSize is the value reported by the CSI driver in its GetCapacityResponse for a GetCapacityRequest with topology and parameters that match the previous fields. This is defined since CSI spec 1.4.0 as the largest size that may be used in a CreateVolumeRequest.capacity_range.required_bytes field to create a volume with the same parameters as those in GetCapacityRequest. The corresponding value in the Kubernetes API is ResourceRequirements.Requests in a volume claim. - :param metadata: Standard object's metadata. The name has no particular meaning. It must be be a DNS subdomain (dots allowed, 253 characters). To ensure that there are no conflicts with other CSI drivers on the cluster, the recommendation is to use csisc-, a generated name, or a reverse-domain name which ends with the unique CSI driver name. Objects are namespaced. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param node_topology: NodeTopology defines which nodes have access to the storage for which capacity was reported. If not set, the storage is not accessible from any node in the cluster. If empty, the storage is accessible from all nodes. This field is immutable. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__672a59a6175ac3d81f59910bb1d738e8e11c47b69c2c3db2480f4a98e073f0df) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeCsiStorageCapacityProps( - storage_class_name=storage_class_name, - capacity=capacity, - maximum_volume_size=maximum_volume_size, - metadata=metadata, - node_topology=node_topology, - ) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - storage_class_name: builtins.str, - capacity: typing.Optional["Quantity"] = None, - maximum_volume_size: typing.Optional["Quantity"] = None, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - node_topology: typing.Optional[typing.Union["LabelSelector", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.storage.v1.CSIStorageCapacity". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param storage_class_name: The name of the StorageClass that the reported capacity applies to. It must meet the same requirements as the name of a StorageClass object (non-empty, DNS subdomain). If that object no longer exists, the CSIStorageCapacity object is obsolete and should be removed by its creator. This field is immutable. - :param capacity: Capacity is the value reported by the CSI driver in its GetCapacityResponse for a GetCapacityRequest with topology and parameters that match the previous fields. The semantic is currently (CSI spec 1.2) defined as: The available capacity, in bytes, of the storage that can be used to provision volumes. If not set, that information is currently unavailable. - :param maximum_volume_size: MaximumVolumeSize is the value reported by the CSI driver in its GetCapacityResponse for a GetCapacityRequest with topology and parameters that match the previous fields. This is defined since CSI spec 1.4.0 as the largest size that may be used in a CreateVolumeRequest.capacity_range.required_bytes field to create a volume with the same parameters as those in GetCapacityRequest. The corresponding value in the Kubernetes API is ResourceRequirements.Requests in a volume claim. - :param metadata: Standard object's metadata. The name has no particular meaning. It must be be a DNS subdomain (dots allowed, 253 characters). To ensure that there are no conflicts with other CSI drivers on the cluster, the recommendation is to use csisc-, a generated name, or a reverse-domain name which ends with the unique CSI driver name. Objects are namespaced. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param node_topology: NodeTopology defines which nodes have access to the storage for which capacity was reported. If not set, the storage is not accessible from any node in the cluster. If empty, the storage is accessible from all nodes. This field is immutable. - ''' - props = KubeCsiStorageCapacityProps( - storage_class_name=storage_class_name, - capacity=capacity, - maximum_volume_size=maximum_volume_size, - metadata=metadata, - node_topology=node_topology, - ) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.storage.v1.CSIStorageCapacity".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubeCsiStorageCapacityList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeCsiStorageCapacityList", -): - '''CSIStorageCapacityList is a collection of CSIStorageCapacity objects. - - :schema: io.k8s.api.storage.v1.CSIStorageCapacityList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeCsiStorageCapacityProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.storage.v1.CSIStorageCapacityList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: Items is the list of CSIStorageCapacity objects. - :param metadata: Standard list metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__26349328195cfeb3eebe739f212c79b7cd4474d7dcb20a0a0589a9932a0d1b21) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeCsiStorageCapacityListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeCsiStorageCapacityProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.storage.v1.CSIStorageCapacityList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: Items is the list of CSIStorageCapacity objects. - :param metadata: Standard list metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - ''' - props = KubeCsiStorageCapacityListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.storage.v1.CSIStorageCapacityList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeCsiStorageCapacityListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeCsiStorageCapacityListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeCsiStorageCapacityProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''CSIStorageCapacityList is a collection of CSIStorageCapacity objects. - - :param items: Items is the list of CSIStorageCapacity objects. - :param metadata: Standard list metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - - :schema: io.k8s.api.storage.v1.CSIStorageCapacityList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__65f4b3047ee5f0d908b2716319143dd4ccd26083f8d0735e0801a078fe3d839a) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeCsiStorageCapacityProps"]: - '''Items is the list of CSIStorageCapacity objects. - - :schema: io.k8s.api.storage.v1.CSIStorageCapacityList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeCsiStorageCapacityProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - - :schema: io.k8s.api.storage.v1.CSIStorageCapacityList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeCsiStorageCapacityListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeCsiStorageCapacityListV1Beta1( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeCsiStorageCapacityListV1Beta1", -): - '''CSIStorageCapacityList is a collection of CSIStorageCapacity objects. - - :schema: io.k8s.api.storage.v1beta1.CSIStorageCapacityList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeCsiStorageCapacityV1Beta1Props", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.storage.v1beta1.CSIStorageCapacityList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: Items is the list of CSIStorageCapacity objects. - :param metadata: Standard list metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__661ec608be88da1c7692b081e6f7c74ef61ce4e8d4a37bd7ec5da8d2611cf0a8) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeCsiStorageCapacityListV1Beta1Props(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeCsiStorageCapacityV1Beta1Props", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.storage.v1beta1.CSIStorageCapacityList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: Items is the list of CSIStorageCapacity objects. - :param metadata: Standard list metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - ''' - props = KubeCsiStorageCapacityListV1Beta1Props(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.storage.v1beta1.CSIStorageCapacityList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeCsiStorageCapacityListV1Beta1Props", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeCsiStorageCapacityListV1Beta1Props: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeCsiStorageCapacityV1Beta1Props", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''CSIStorageCapacityList is a collection of CSIStorageCapacity objects. - - :param items: Items is the list of CSIStorageCapacity objects. - :param metadata: Standard list metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - - :schema: io.k8s.api.storage.v1beta1.CSIStorageCapacityList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__400eae37cc38d2ad1a0f22a496ee8496cb5d543295c2d8fb25d899afe6986998) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeCsiStorageCapacityV1Beta1Props"]: - '''Items is the list of CSIStorageCapacity objects. - - :schema: io.k8s.api.storage.v1beta1.CSIStorageCapacityList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeCsiStorageCapacityV1Beta1Props"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - - :schema: io.k8s.api.storage.v1beta1.CSIStorageCapacityList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeCsiStorageCapacityListV1Beta1Props(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubeCsiStorageCapacityProps", - jsii_struct_bases=[], - name_mapping={ - "storage_class_name": "storageClassName", - "capacity": "capacity", - "maximum_volume_size": "maximumVolumeSize", - "metadata": "metadata", - "node_topology": "nodeTopology", - }, -) -class KubeCsiStorageCapacityProps: - def __init__( - self, - *, - storage_class_name: builtins.str, - capacity: typing.Optional["Quantity"] = None, - maximum_volume_size: typing.Optional["Quantity"] = None, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - node_topology: typing.Optional[typing.Union["LabelSelector", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''CSIStorageCapacity stores the result of one CSI GetCapacity call. - - For a given StorageClass, this describes the available capacity in a particular topology segment. This can be used when considering where to instantiate new PersistentVolumes. - - For example this can express things like: - StorageClass "standard" has "1234 GiB" available in "topology.kubernetes.io/zone=us-east1" - StorageClass "localssd" has "10 GiB" available in "kubernetes.io/hostname=knode-abc123" - - The following three cases all imply that no capacity is available for a certain combination: - no object exists with suitable topology and storage class name - such an object exists, but the capacity is unset - such an object exists, but the capacity is zero - - The producer of these objects can decide which approach is more suitable. - - They are consumed by the kube-scheduler when a CSI driver opts into capacity-aware scheduling with CSIDriverSpec.StorageCapacity. The scheduler compares the MaximumVolumeSize against the requested size of pending volumes to filter out unsuitable nodes. If MaximumVolumeSize is unset, it falls back to a comparison against the less precise Capacity. If that is also unset, the scheduler assumes that capacity is insufficient and tries some other node. - - :param storage_class_name: The name of the StorageClass that the reported capacity applies to. It must meet the same requirements as the name of a StorageClass object (non-empty, DNS subdomain). If that object no longer exists, the CSIStorageCapacity object is obsolete and should be removed by its creator. This field is immutable. - :param capacity: Capacity is the value reported by the CSI driver in its GetCapacityResponse for a GetCapacityRequest with topology and parameters that match the previous fields. The semantic is currently (CSI spec 1.2) defined as: The available capacity, in bytes, of the storage that can be used to provision volumes. If not set, that information is currently unavailable. - :param maximum_volume_size: MaximumVolumeSize is the value reported by the CSI driver in its GetCapacityResponse for a GetCapacityRequest with topology and parameters that match the previous fields. This is defined since CSI spec 1.4.0 as the largest size that may be used in a CreateVolumeRequest.capacity_range.required_bytes field to create a volume with the same parameters as those in GetCapacityRequest. The corresponding value in the Kubernetes API is ResourceRequirements.Requests in a volume claim. - :param metadata: Standard object's metadata. The name has no particular meaning. It must be be a DNS subdomain (dots allowed, 253 characters). To ensure that there are no conflicts with other CSI drivers on the cluster, the recommendation is to use csisc-, a generated name, or a reverse-domain name which ends with the unique CSI driver name. Objects are namespaced. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param node_topology: NodeTopology defines which nodes have access to the storage for which capacity was reported. If not set, the storage is not accessible from any node in the cluster. If empty, the storage is accessible from all nodes. This field is immutable. - - :schema: io.k8s.api.storage.v1.CSIStorageCapacity - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if isinstance(node_topology, dict): - node_topology = LabelSelector(**node_topology) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__fdfcf2ccfe14adfd27a6bbb6dc09e54facd4c0be62f6bb48afb0ce7b0e5f31bd) - check_type(argname="argument storage_class_name", value=storage_class_name, expected_type=type_hints["storage_class_name"]) - check_type(argname="argument capacity", value=capacity, expected_type=type_hints["capacity"]) - check_type(argname="argument maximum_volume_size", value=maximum_volume_size, expected_type=type_hints["maximum_volume_size"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument node_topology", value=node_topology, expected_type=type_hints["node_topology"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "storage_class_name": storage_class_name, - } - if capacity is not None: - self._values["capacity"] = capacity - if maximum_volume_size is not None: - self._values["maximum_volume_size"] = maximum_volume_size - if metadata is not None: - self._values["metadata"] = metadata - if node_topology is not None: - self._values["node_topology"] = node_topology - - @builtins.property - def storage_class_name(self) -> builtins.str: - '''The name of the StorageClass that the reported capacity applies to. - - It must meet the same requirements as the name of a StorageClass object (non-empty, DNS subdomain). If that object no longer exists, the CSIStorageCapacity object is obsolete and should be removed by its creator. This field is immutable. - - :schema: io.k8s.api.storage.v1.CSIStorageCapacity#storageClassName - ''' - result = self._values.get("storage_class_name") - assert result is not None, "Required property 'storage_class_name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def capacity(self) -> typing.Optional["Quantity"]: - '''Capacity is the value reported by the CSI driver in its GetCapacityResponse for a GetCapacityRequest with topology and parameters that match the previous fields. - - The semantic is currently (CSI spec 1.2) defined as: The available capacity, in bytes, of the storage that can be used to provision volumes. If not set, that information is currently unavailable. - - :schema: io.k8s.api.storage.v1.CSIStorageCapacity#capacity - ''' - result = self._values.get("capacity") - return typing.cast(typing.Optional["Quantity"], result) - - @builtins.property - def maximum_volume_size(self) -> typing.Optional["Quantity"]: - '''MaximumVolumeSize is the value reported by the CSI driver in its GetCapacityResponse for a GetCapacityRequest with topology and parameters that match the previous fields. - - This is defined since CSI spec 1.4.0 as the largest size that may be used in a CreateVolumeRequest.capacity_range.required_bytes field to create a volume with the same parameters as those in GetCapacityRequest. The corresponding value in the Kubernetes API is ResourceRequirements.Requests in a volume claim. - - :schema: io.k8s.api.storage.v1.CSIStorageCapacity#maximumVolumeSize - ''' - result = self._values.get("maximum_volume_size") - return typing.cast(typing.Optional["Quantity"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata. - - The name has no particular meaning. It must be be a DNS subdomain (dots allowed, 253 characters). To ensure that there are no conflicts with other CSI drivers on the cluster, the recommendation is to use csisc-, a generated name, or a reverse-domain name which ends with the unique CSI driver name. - - Objects are namespaced. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.storage.v1.CSIStorageCapacity#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def node_topology(self) -> typing.Optional["LabelSelector"]: - '''NodeTopology defines which nodes have access to the storage for which capacity was reported. - - If not set, the storage is not accessible from any node in the cluster. If empty, the storage is accessible from all nodes. This field is immutable. - - :schema: io.k8s.api.storage.v1.CSIStorageCapacity#nodeTopology - ''' - result = self._values.get("node_topology") - return typing.cast(typing.Optional["LabelSelector"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeCsiStorageCapacityProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeCsiStorageCapacityV1Beta1( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeCsiStorageCapacityV1Beta1", -): - '''CSIStorageCapacity stores the result of one CSI GetCapacity call. - - For a given StorageClass, this describes the available capacity in a particular topology segment. This can be used when considering where to instantiate new PersistentVolumes. - - For example this can express things like: - StorageClass "standard" has "1234 GiB" available in "topology.kubernetes.io/zone=us-east1" - StorageClass "localssd" has "10 GiB" available in "kubernetes.io/hostname=knode-abc123" - - The following three cases all imply that no capacity is available for a certain combination: - no object exists with suitable topology and storage class name - such an object exists, but the capacity is unset - such an object exists, but the capacity is zero - - The producer of these objects can decide which approach is more suitable. - - They are consumed by the kube-scheduler when a CSI driver opts into capacity-aware scheduling with CSIDriverSpec.StorageCapacity. The scheduler compares the MaximumVolumeSize against the requested size of pending volumes to filter out unsuitable nodes. If MaximumVolumeSize is unset, it falls back to a comparison against the less precise Capacity. If that is also unset, the scheduler assumes that capacity is insufficient and tries some other node. - - :schema: io.k8s.api.storage.v1beta1.CSIStorageCapacity - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - storage_class_name: builtins.str, - capacity: typing.Optional["Quantity"] = None, - maximum_volume_size: typing.Optional["Quantity"] = None, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - node_topology: typing.Optional[typing.Union["LabelSelector", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.storage.v1beta1.CSIStorageCapacity" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param storage_class_name: The name of the StorageClass that the reported capacity applies to. It must meet the same requirements as the name of a StorageClass object (non-empty, DNS subdomain). If that object no longer exists, the CSIStorageCapacity object is obsolete and should be removed by its creator. This field is immutable. - :param capacity: Capacity is the value reported by the CSI driver in its GetCapacityResponse for a GetCapacityRequest with topology and parameters that match the previous fields. The semantic is currently (CSI spec 1.2) defined as: The available capacity, in bytes, of the storage that can be used to provision volumes. If not set, that information is currently unavailable. - :param maximum_volume_size: MaximumVolumeSize is the value reported by the CSI driver in its GetCapacityResponse for a GetCapacityRequest with topology and parameters that match the previous fields. This is defined since CSI spec 1.4.0 as the largest size that may be used in a CreateVolumeRequest.capacity_range.required_bytes field to create a volume with the same parameters as those in GetCapacityRequest. The corresponding value in the Kubernetes API is ResourceRequirements.Requests in a volume claim. - :param metadata: Standard object's metadata. The name has no particular meaning. It must be be a DNS subdomain (dots allowed, 253 characters). To ensure that there are no conflicts with other CSI drivers on the cluster, the recommendation is to use csisc-, a generated name, or a reverse-domain name which ends with the unique CSI driver name. Objects are namespaced. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param node_topology: NodeTopology defines which nodes have access to the storage for which capacity was reported. If not set, the storage is not accessible from any node in the cluster. If empty, the storage is accessible from all nodes. This field is immutable. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__cce715b0cafab1814f8745ad981ca208df4018c7a12f6d649842f804831cf83e) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeCsiStorageCapacityV1Beta1Props( - storage_class_name=storage_class_name, - capacity=capacity, - maximum_volume_size=maximum_volume_size, - metadata=metadata, - node_topology=node_topology, - ) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - storage_class_name: builtins.str, - capacity: typing.Optional["Quantity"] = None, - maximum_volume_size: typing.Optional["Quantity"] = None, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - node_topology: typing.Optional[typing.Union["LabelSelector", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.storage.v1beta1.CSIStorageCapacity". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param storage_class_name: The name of the StorageClass that the reported capacity applies to. It must meet the same requirements as the name of a StorageClass object (non-empty, DNS subdomain). If that object no longer exists, the CSIStorageCapacity object is obsolete and should be removed by its creator. This field is immutable. - :param capacity: Capacity is the value reported by the CSI driver in its GetCapacityResponse for a GetCapacityRequest with topology and parameters that match the previous fields. The semantic is currently (CSI spec 1.2) defined as: The available capacity, in bytes, of the storage that can be used to provision volumes. If not set, that information is currently unavailable. - :param maximum_volume_size: MaximumVolumeSize is the value reported by the CSI driver in its GetCapacityResponse for a GetCapacityRequest with topology and parameters that match the previous fields. This is defined since CSI spec 1.4.0 as the largest size that may be used in a CreateVolumeRequest.capacity_range.required_bytes field to create a volume with the same parameters as those in GetCapacityRequest. The corresponding value in the Kubernetes API is ResourceRequirements.Requests in a volume claim. - :param metadata: Standard object's metadata. The name has no particular meaning. It must be be a DNS subdomain (dots allowed, 253 characters). To ensure that there are no conflicts with other CSI drivers on the cluster, the recommendation is to use csisc-, a generated name, or a reverse-domain name which ends with the unique CSI driver name. Objects are namespaced. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param node_topology: NodeTopology defines which nodes have access to the storage for which capacity was reported. If not set, the storage is not accessible from any node in the cluster. If empty, the storage is accessible from all nodes. This field is immutable. - ''' - props = KubeCsiStorageCapacityV1Beta1Props( - storage_class_name=storage_class_name, - capacity=capacity, - maximum_volume_size=maximum_volume_size, - metadata=metadata, - node_topology=node_topology, - ) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.storage.v1beta1.CSIStorageCapacity".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeCsiStorageCapacityV1Beta1Props", - jsii_struct_bases=[], - name_mapping={ - "storage_class_name": "storageClassName", - "capacity": "capacity", - "maximum_volume_size": "maximumVolumeSize", - "metadata": "metadata", - "node_topology": "nodeTopology", - }, -) -class KubeCsiStorageCapacityV1Beta1Props: - def __init__( - self, - *, - storage_class_name: builtins.str, - capacity: typing.Optional["Quantity"] = None, - maximum_volume_size: typing.Optional["Quantity"] = None, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - node_topology: typing.Optional[typing.Union["LabelSelector", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''CSIStorageCapacity stores the result of one CSI GetCapacity call. - - For a given StorageClass, this describes the available capacity in a particular topology segment. This can be used when considering where to instantiate new PersistentVolumes. - - For example this can express things like: - StorageClass "standard" has "1234 GiB" available in "topology.kubernetes.io/zone=us-east1" - StorageClass "localssd" has "10 GiB" available in "kubernetes.io/hostname=knode-abc123" - - The following three cases all imply that no capacity is available for a certain combination: - no object exists with suitable topology and storage class name - such an object exists, but the capacity is unset - such an object exists, but the capacity is zero - - The producer of these objects can decide which approach is more suitable. - - They are consumed by the kube-scheduler when a CSI driver opts into capacity-aware scheduling with CSIDriverSpec.StorageCapacity. The scheduler compares the MaximumVolumeSize against the requested size of pending volumes to filter out unsuitable nodes. If MaximumVolumeSize is unset, it falls back to a comparison against the less precise Capacity. If that is also unset, the scheduler assumes that capacity is insufficient and tries some other node. - - :param storage_class_name: The name of the StorageClass that the reported capacity applies to. It must meet the same requirements as the name of a StorageClass object (non-empty, DNS subdomain). If that object no longer exists, the CSIStorageCapacity object is obsolete and should be removed by its creator. This field is immutable. - :param capacity: Capacity is the value reported by the CSI driver in its GetCapacityResponse for a GetCapacityRequest with topology and parameters that match the previous fields. The semantic is currently (CSI spec 1.2) defined as: The available capacity, in bytes, of the storage that can be used to provision volumes. If not set, that information is currently unavailable. - :param maximum_volume_size: MaximumVolumeSize is the value reported by the CSI driver in its GetCapacityResponse for a GetCapacityRequest with topology and parameters that match the previous fields. This is defined since CSI spec 1.4.0 as the largest size that may be used in a CreateVolumeRequest.capacity_range.required_bytes field to create a volume with the same parameters as those in GetCapacityRequest. The corresponding value in the Kubernetes API is ResourceRequirements.Requests in a volume claim. - :param metadata: Standard object's metadata. The name has no particular meaning. It must be be a DNS subdomain (dots allowed, 253 characters). To ensure that there are no conflicts with other CSI drivers on the cluster, the recommendation is to use csisc-, a generated name, or a reverse-domain name which ends with the unique CSI driver name. Objects are namespaced. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param node_topology: NodeTopology defines which nodes have access to the storage for which capacity was reported. If not set, the storage is not accessible from any node in the cluster. If empty, the storage is accessible from all nodes. This field is immutable. - - :schema: io.k8s.api.storage.v1beta1.CSIStorageCapacity - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if isinstance(node_topology, dict): - node_topology = LabelSelector(**node_topology) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__8418b166e025fb1853c1ac02bf35c29f522036d884cff7a2ce4f670249d87d99) - check_type(argname="argument storage_class_name", value=storage_class_name, expected_type=type_hints["storage_class_name"]) - check_type(argname="argument capacity", value=capacity, expected_type=type_hints["capacity"]) - check_type(argname="argument maximum_volume_size", value=maximum_volume_size, expected_type=type_hints["maximum_volume_size"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument node_topology", value=node_topology, expected_type=type_hints["node_topology"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "storage_class_name": storage_class_name, - } - if capacity is not None: - self._values["capacity"] = capacity - if maximum_volume_size is not None: - self._values["maximum_volume_size"] = maximum_volume_size - if metadata is not None: - self._values["metadata"] = metadata - if node_topology is not None: - self._values["node_topology"] = node_topology - - @builtins.property - def storage_class_name(self) -> builtins.str: - '''The name of the StorageClass that the reported capacity applies to. - - It must meet the same requirements as the name of a StorageClass object (non-empty, DNS subdomain). If that object no longer exists, the CSIStorageCapacity object is obsolete and should be removed by its creator. This field is immutable. - - :schema: io.k8s.api.storage.v1beta1.CSIStorageCapacity#storageClassName - ''' - result = self._values.get("storage_class_name") - assert result is not None, "Required property 'storage_class_name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def capacity(self) -> typing.Optional["Quantity"]: - '''Capacity is the value reported by the CSI driver in its GetCapacityResponse for a GetCapacityRequest with topology and parameters that match the previous fields. - - The semantic is currently (CSI spec 1.2) defined as: The available capacity, in bytes, of the storage that can be used to provision volumes. If not set, that information is currently unavailable. - - :schema: io.k8s.api.storage.v1beta1.CSIStorageCapacity#capacity - ''' - result = self._values.get("capacity") - return typing.cast(typing.Optional["Quantity"], result) - - @builtins.property - def maximum_volume_size(self) -> typing.Optional["Quantity"]: - '''MaximumVolumeSize is the value reported by the CSI driver in its GetCapacityResponse for a GetCapacityRequest with topology and parameters that match the previous fields. - - This is defined since CSI spec 1.4.0 as the largest size that may be used in a CreateVolumeRequest.capacity_range.required_bytes field to create a volume with the same parameters as those in GetCapacityRequest. The corresponding value in the Kubernetes API is ResourceRequirements.Requests in a volume claim. - - :schema: io.k8s.api.storage.v1beta1.CSIStorageCapacity#maximumVolumeSize - ''' - result = self._values.get("maximum_volume_size") - return typing.cast(typing.Optional["Quantity"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata. - - The name has no particular meaning. It must be be a DNS subdomain (dots allowed, 253 characters). To ensure that there are no conflicts with other CSI drivers on the cluster, the recommendation is to use csisc-, a generated name, or a reverse-domain name which ends with the unique CSI driver name. - - Objects are namespaced. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.storage.v1beta1.CSIStorageCapacity#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def node_topology(self) -> typing.Optional["LabelSelector"]: - '''NodeTopology defines which nodes have access to the storage for which capacity was reported. - - If not set, the storage is not accessible from any node in the cluster. If empty, the storage is accessible from all nodes. This field is immutable. - - :schema: io.k8s.api.storage.v1beta1.CSIStorageCapacity#nodeTopology - ''' - result = self._values.get("node_topology") - return typing.cast(typing.Optional["LabelSelector"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeCsiStorageCapacityV1Beta1Props(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeCustomResourceDefinition( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeCustomResourceDefinition", -): - '''CustomResourceDefinition represents a resource that should be exposed on the API server. - - Its name MUST be in the format <.spec.name>.<.spec.group>. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceDefinition - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - spec: typing.Union[CustomResourceDefinitionSpec, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceDefinition" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param spec: spec describes how the user wants the resources to appear. - :param metadata: Standard object's metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__334b5f39cea8395ab2e2384ecfed468321d1dfffaf1287949e0062ceeb5f21e2) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeCustomResourceDefinitionProps(spec=spec, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - spec: typing.Union[CustomResourceDefinitionSpec, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceDefinition". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param spec: spec describes how the user wants the resources to appear. - :param metadata: Standard object's metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - ''' - props = KubeCustomResourceDefinitionProps(spec=spec, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceDefinition".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubeCustomResourceDefinitionList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeCustomResourceDefinitionList", -): - '''CustomResourceDefinitionList is a list of CustomResourceDefinition objects. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceDefinitionList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeCustomResourceDefinitionProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceDefinitionList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: items list individual CustomResourceDefinition objects. - :param metadata: Standard object's metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__62a298f00bfce341f3c14b23cd20df7fd098569753f147819ade11b8eec605b1) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeCustomResourceDefinitionListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeCustomResourceDefinitionProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceDefinitionList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: items list individual CustomResourceDefinition objects. - :param metadata: Standard object's metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - ''' - props = KubeCustomResourceDefinitionListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceDefinitionList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeCustomResourceDefinitionListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeCustomResourceDefinitionListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeCustomResourceDefinitionProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''CustomResourceDefinitionList is a list of CustomResourceDefinition objects. - - :param items: items list individual CustomResourceDefinition objects. - :param metadata: Standard object's metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceDefinitionList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__1f2426ee351c62ae7b958ae547946c551446a7db0fe0c9ccdaa7a2c0f038b9ee) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeCustomResourceDefinitionProps"]: - '''items list individual CustomResourceDefinition objects. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceDefinitionList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeCustomResourceDefinitionProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard object's metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceDefinitionList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeCustomResourceDefinitionListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubeCustomResourceDefinitionProps", - jsii_struct_bases=[], - name_mapping={"spec": "spec", "metadata": "metadata"}, -) -class KubeCustomResourceDefinitionProps: - def __init__( - self, - *, - spec: typing.Union[CustomResourceDefinitionSpec, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''CustomResourceDefinition represents a resource that should be exposed on the API server. - - Its name MUST be in the format <.spec.name>.<.spec.group>. - - :param spec: spec describes how the user wants the resources to appear. - :param metadata: Standard object's metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceDefinition - ''' - if isinstance(spec, dict): - spec = CustomResourceDefinitionSpec(**spec) - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__44acb3eb0ed88657237084766aeeb318a33cb87a320ff83db090657729bf6a38) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "spec": spec, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def spec(self) -> CustomResourceDefinitionSpec: - '''spec describes how the user wants the resources to appear. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceDefinition#spec - ''' - result = self._values.get("spec") - assert result is not None, "Required property 'spec' is missing" - return typing.cast(CustomResourceDefinitionSpec, result) - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceDefinition#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeCustomResourceDefinitionProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeDaemonSet( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeDaemonSet", -): - '''DaemonSet represents the configuration of a daemon set. - - :schema: io.k8s.api.apps.v1.DaemonSet - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[DaemonSetSpec, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.apps.v1.DaemonSet" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: The desired behavior of this daemon set. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__e6e8fa30f38ce100278001efebe064bf62d0a0cf7e9f6a251b4a468ea63e5b8a) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeDaemonSetProps(metadata=metadata, spec=spec) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[DaemonSetSpec, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.apps.v1.DaemonSet". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: The desired behavior of this daemon set. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - ''' - props = KubeDaemonSetProps(metadata=metadata, spec=spec) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.apps.v1.DaemonSet".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubeDaemonSetList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeDaemonSetList", -): - '''DaemonSetList is a collection of daemon sets. - - :schema: io.k8s.api.apps.v1.DaemonSetList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeDaemonSetProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.apps.v1.DaemonSetList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: A list of daemon sets. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__7f2704f8f4ce59ac94c9b58e78430742d4a18fba3f41ec245074edd74b149be0) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeDaemonSetListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeDaemonSetProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.apps.v1.DaemonSetList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: A list of daemon sets. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - props = KubeDaemonSetListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.apps.v1.DaemonSetList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeDaemonSetListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeDaemonSetListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeDaemonSetProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''DaemonSetList is a collection of daemon sets. - - :param items: A list of daemon sets. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.apps.v1.DaemonSetList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__abb376a268375c85da81816f728709a72ab35d8db244a766b4b858a0479a2d2f) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeDaemonSetProps"]: - '''A list of daemon sets. - - :schema: io.k8s.api.apps.v1.DaemonSetList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeDaemonSetProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.apps.v1.DaemonSetList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeDaemonSetListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubeDaemonSetProps", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata", "spec": "spec"}, -) -class KubeDaemonSetProps: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[DaemonSetSpec, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''DaemonSet represents the configuration of a daemon set. - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: The desired behavior of this daemon set. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.apps.v1.DaemonSet - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if isinstance(spec, dict): - spec = DaemonSetSpec(**spec) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__8fbbc65d9c988de23c71a61edaf7bba46d33be225fd1159056e6bef26714816b) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - if spec is not None: - self._values["spec"] = spec - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.apps.v1.DaemonSet#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def spec(self) -> typing.Optional[DaemonSetSpec]: - '''The desired behavior of this daemon set. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.apps.v1.DaemonSet#spec - ''' - result = self._values.get("spec") - return typing.cast(typing.Optional[DaemonSetSpec], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeDaemonSetProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeDeployment( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeDeployment", -): - '''Deployment enables declarative updates for Pods and ReplicaSets. - - :schema: io.k8s.api.apps.v1.Deployment - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[DeploymentSpec, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.apps.v1.Deployment" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Specification of the desired behavior of the Deployment. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__5e1e2a79d85486449fa0833d4177ee006fe290e62f76e13917ded50a2b61ba2d) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeDeploymentProps(metadata=metadata, spec=spec) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[DeploymentSpec, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.apps.v1.Deployment". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Specification of the desired behavior of the Deployment. - ''' - props = KubeDeploymentProps(metadata=metadata, spec=spec) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.apps.v1.Deployment".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubeDeploymentList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeDeploymentList", -): - '''DeploymentList is a list of Deployments. - - :schema: io.k8s.api.apps.v1.DeploymentList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeDeploymentProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.apps.v1.DeploymentList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: Items is the list of Deployments. - :param metadata: Standard list metadata. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__8338f8fe3af7e0a8022f1814586a09e0d841fc7164e1523e8640ea827a30f1a9) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeDeploymentListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeDeploymentProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.apps.v1.DeploymentList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: Items is the list of Deployments. - :param metadata: Standard list metadata. - ''' - props = KubeDeploymentListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.apps.v1.DeploymentList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeDeploymentListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeDeploymentListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeDeploymentProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''DeploymentList is a list of Deployments. - - :param items: Items is the list of Deployments. - :param metadata: Standard list metadata. - - :schema: io.k8s.api.apps.v1.DeploymentList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__6c281c2946d751d060ba2a36cc155cd227429237972a82bf34b0aa5ec907a092) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeDeploymentProps"]: - '''Items is the list of Deployments. - - :schema: io.k8s.api.apps.v1.DeploymentList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeDeploymentProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata. - - :schema: io.k8s.api.apps.v1.DeploymentList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeDeploymentListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubeDeploymentProps", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata", "spec": "spec"}, -) -class KubeDeploymentProps: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[DeploymentSpec, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Deployment enables declarative updates for Pods and ReplicaSets. - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Specification of the desired behavior of the Deployment. - - :schema: io.k8s.api.apps.v1.Deployment - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if isinstance(spec, dict): - spec = DeploymentSpec(**spec) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__3f938ae7726ab98563b8c569f39380bdfb08ba493b5b18b7911fc99dd59fca9d) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - if spec is not None: - self._values["spec"] = spec - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.apps.v1.Deployment#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def spec(self) -> typing.Optional[DeploymentSpec]: - '''Specification of the desired behavior of the Deployment. - - :schema: io.k8s.api.apps.v1.Deployment#spec - ''' - result = self._values.get("spec") - return typing.cast(typing.Optional[DeploymentSpec], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeDeploymentProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeEndpointSlice( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeEndpointSlice", -): - '''EndpointSlice represents a subset of the endpoints that implement a service. - - For a given service there may be multiple EndpointSlice objects, selected by labels, which must be joined to produce the full set of endpoints. - - :schema: io.k8s.api.discovery.v1.EndpointSlice - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - address_type: builtins.str, - endpoints: typing.Sequence[typing.Union[Endpoint, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ports: typing.Optional[typing.Sequence[typing.Union[EndpointPort, typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''Defines a "io.k8s.api.discovery.v1.EndpointSlice" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param address_type: addressType specifies the type of address carried by this EndpointSlice. All addresses in this slice must be the same type. This field is immutable after creation. The following address types are currently supported: * IPv4: Represents an IPv4 Address. * IPv6: Represents an IPv6 Address. * FQDN: Represents a Fully Qualified Domain Name. - :param endpoints: endpoints is a list of unique endpoints in this slice. Each slice may include a maximum of 1000 endpoints. - :param metadata: Standard object's metadata. - :param ports: ports specifies the list of network ports exposed by each endpoint in this slice. Each port must have a unique name. When ports is empty, it indicates that there are no defined ports. When a port is defined with a nil port value, it indicates "all ports". Each slice may include a maximum of 100 ports. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__4a3aca436c82217519bb07237133dd6f4d2c21c528a0a7e98d7963d8062245d1) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeEndpointSliceProps( - address_type=address_type, - endpoints=endpoints, - metadata=metadata, - ports=ports, - ) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - address_type: builtins.str, - endpoints: typing.Sequence[typing.Union[Endpoint, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ports: typing.Optional[typing.Sequence[typing.Union[EndpointPort, typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.discovery.v1.EndpointSlice". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param address_type: addressType specifies the type of address carried by this EndpointSlice. All addresses in this slice must be the same type. This field is immutable after creation. The following address types are currently supported: * IPv4: Represents an IPv4 Address. * IPv6: Represents an IPv6 Address. * FQDN: Represents a Fully Qualified Domain Name. - :param endpoints: endpoints is a list of unique endpoints in this slice. Each slice may include a maximum of 1000 endpoints. - :param metadata: Standard object's metadata. - :param ports: ports specifies the list of network ports exposed by each endpoint in this slice. Each port must have a unique name. When ports is empty, it indicates that there are no defined ports. When a port is defined with a nil port value, it indicates "all ports". Each slice may include a maximum of 100 ports. - ''' - props = KubeEndpointSliceProps( - address_type=address_type, - endpoints=endpoints, - metadata=metadata, - ports=ports, - ) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.discovery.v1.EndpointSlice".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubeEndpointSliceList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeEndpointSliceList", -): - '''EndpointSliceList represents a list of endpoint slices. - - :schema: io.k8s.api.discovery.v1.EndpointSliceList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeEndpointSliceProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.discovery.v1.EndpointSliceList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: List of endpoint slices. - :param metadata: Standard list metadata. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__a4184b57cf196b9cf44ae6f0a3e88a09792447aa938bae1ad32ddf0430cc8472) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeEndpointSliceListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeEndpointSliceProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.discovery.v1.EndpointSliceList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: List of endpoint slices. - :param metadata: Standard list metadata. - ''' - props = KubeEndpointSliceListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.discovery.v1.EndpointSliceList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeEndpointSliceListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeEndpointSliceListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeEndpointSliceProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''EndpointSliceList represents a list of endpoint slices. - - :param items: List of endpoint slices. - :param metadata: Standard list metadata. - - :schema: io.k8s.api.discovery.v1.EndpointSliceList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__893756756978bc6e8b8cd4f9974acd87d10a41169ee8149b2474685511e1202f) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeEndpointSliceProps"]: - '''List of endpoint slices. - - :schema: io.k8s.api.discovery.v1.EndpointSliceList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeEndpointSliceProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata. - - :schema: io.k8s.api.discovery.v1.EndpointSliceList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeEndpointSliceListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubeEndpointSliceProps", - jsii_struct_bases=[], - name_mapping={ - "address_type": "addressType", - "endpoints": "endpoints", - "metadata": "metadata", - "ports": "ports", - }, -) -class KubeEndpointSliceProps: - def __init__( - self, - *, - address_type: builtins.str, - endpoints: typing.Sequence[typing.Union[Endpoint, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ports: typing.Optional[typing.Sequence[typing.Union[EndpointPort, typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''EndpointSlice represents a subset of the endpoints that implement a service. - - For a given service there may be multiple EndpointSlice objects, selected by labels, which must be joined to produce the full set of endpoints. - - :param address_type: addressType specifies the type of address carried by this EndpointSlice. All addresses in this slice must be the same type. This field is immutable after creation. The following address types are currently supported: * IPv4: Represents an IPv4 Address. * IPv6: Represents an IPv6 Address. * FQDN: Represents a Fully Qualified Domain Name. - :param endpoints: endpoints is a list of unique endpoints in this slice. Each slice may include a maximum of 1000 endpoints. - :param metadata: Standard object's metadata. - :param ports: ports specifies the list of network ports exposed by each endpoint in this slice. Each port must have a unique name. When ports is empty, it indicates that there are no defined ports. When a port is defined with a nil port value, it indicates "all ports". Each slice may include a maximum of 100 ports. - - :schema: io.k8s.api.discovery.v1.EndpointSlice - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__d5a0710afc3e844c1100b501405d8ce44983ec5b3c3f16765cabf7c83048029e) - check_type(argname="argument address_type", value=address_type, expected_type=type_hints["address_type"]) - check_type(argname="argument endpoints", value=endpoints, expected_type=type_hints["endpoints"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument ports", value=ports, expected_type=type_hints["ports"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "address_type": address_type, - "endpoints": endpoints, - } - if metadata is not None: - self._values["metadata"] = metadata - if ports is not None: - self._values["ports"] = ports - - @builtins.property - def address_type(self) -> builtins.str: - '''addressType specifies the type of address carried by this EndpointSlice. - - All addresses in this slice must be the same type. This field is immutable after creation. The following address types are currently supported: * IPv4: Represents an IPv4 Address. * IPv6: Represents an IPv6 Address. * FQDN: Represents a Fully Qualified Domain Name. - - :schema: io.k8s.api.discovery.v1.EndpointSlice#addressType - ''' - result = self._values.get("address_type") - assert result is not None, "Required property 'address_type' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def endpoints(self) -> typing.List[Endpoint]: - '''endpoints is a list of unique endpoints in this slice. - - Each slice may include a maximum of 1000 endpoints. - - :schema: io.k8s.api.discovery.v1.EndpointSlice#endpoints - ''' - result = self._values.get("endpoints") - assert result is not None, "Required property 'endpoints' is missing" - return typing.cast(typing.List[Endpoint], result) - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata. - - :schema: io.k8s.api.discovery.v1.EndpointSlice#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def ports(self) -> typing.Optional[typing.List[EndpointPort]]: - '''ports specifies the list of network ports exposed by each endpoint in this slice. - - Each port must have a unique name. When ports is empty, it indicates that there are no defined ports. When a port is defined with a nil port value, it indicates "all ports". Each slice may include a maximum of 100 ports. - - :schema: io.k8s.api.discovery.v1.EndpointSlice#ports - ''' - result = self._values.get("ports") - return typing.cast(typing.Optional[typing.List[EndpointPort]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeEndpointSliceProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeEndpoints( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeEndpoints", -): - '''Endpoints is a collection of endpoints that implement the actual service. Example:. - - Name: "mysvc", - Subsets: [ - { - Addresses: [{"ip": "10.10.1.1"}, {"ip": "10.10.2.2"}], - Ports: [{"name": "a", "port": 8675}, {"name": "b", "port": 309}] - }, - { - Addresses: [{"ip": "10.10.3.3"}], - Ports: [{"name": "a", "port": 93}, {"name": "b", "port": 76}] - }, - ] - - :schema: io.k8s.api.core.v1.Endpoints - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - subsets: typing.Optional[typing.Sequence[typing.Union[EndpointSubset, typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''Defines a "io.k8s.api.core.v1.Endpoints" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param subsets: The set of all endpoints is the union of all subsets. Addresses are placed into subsets according to the IPs they share. A single address with multiple ports, some of which are ready and some of which are not (because they come from different containers) will result in the address being displayed in different subsets for the different ports. No address will appear in both Addresses and NotReadyAddresses in the same subset. Sets of addresses and ports that comprise a service. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__07c03de2e3c29871d33c0d6587ce2a4fb58f9ad5c55ff53ae8ca18161ca8f75d) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeEndpointsProps(metadata=metadata, subsets=subsets) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - subsets: typing.Optional[typing.Sequence[typing.Union[EndpointSubset, typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.core.v1.Endpoints". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param subsets: The set of all endpoints is the union of all subsets. Addresses are placed into subsets according to the IPs they share. A single address with multiple ports, some of which are ready and some of which are not (because they come from different containers) will result in the address being displayed in different subsets for the different ports. No address will appear in both Addresses and NotReadyAddresses in the same subset. Sets of addresses and ports that comprise a service. - ''' - props = KubeEndpointsProps(metadata=metadata, subsets=subsets) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.core.v1.Endpoints".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubeEndpointsList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeEndpointsList", -): - '''EndpointsList is a list of endpoints. - - :schema: io.k8s.api.core.v1.EndpointsList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeEndpointsProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.core.v1.EndpointsList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: List of endpoints. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__f7ec0ee98c97171c7128134d941789c4354bb07ecb52a28f275a4b6010dc9009) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeEndpointsListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeEndpointsProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.core.v1.EndpointsList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: List of endpoints. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - ''' - props = KubeEndpointsListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.core.v1.EndpointsList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeEndpointsListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeEndpointsListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeEndpointsProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''EndpointsList is a list of endpoints. - - :param items: List of endpoints. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.core.v1.EndpointsList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__dabdb04acd54ff7c5f4be3268ab8a4d155c02f3b13492e7bc3edd37ae5e31e6e) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeEndpointsProps"]: - '''List of endpoints. - - :schema: io.k8s.api.core.v1.EndpointsList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeEndpointsProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.core.v1.EndpointsList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeEndpointsListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubeEndpointsProps", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata", "subsets": "subsets"}, -) -class KubeEndpointsProps: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - subsets: typing.Optional[typing.Sequence[typing.Union[EndpointSubset, typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''Endpoints is a collection of endpoints that implement the actual service. Example:. - - Name: "mysvc", - Subsets: [ - { - Addresses: [{"ip": "10.10.1.1"}, {"ip": "10.10.2.2"}], - Ports: [{"name": "a", "port": 8675}, {"name": "b", "port": 309}] - }, - { - Addresses: [{"ip": "10.10.3.3"}], - Ports: [{"name": "a", "port": 93}, {"name": "b", "port": 76}] - }, - ] - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param subsets: The set of all endpoints is the union of all subsets. Addresses are placed into subsets according to the IPs they share. A single address with multiple ports, some of which are ready and some of which are not (because they come from different containers) will result in the address being displayed in different subsets for the different ports. No address will appear in both Addresses and NotReadyAddresses in the same subset. Sets of addresses and ports that comprise a service. - - :schema: io.k8s.api.core.v1.Endpoints - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__0dbeba4d3e9f8a17aefc98d861feaeeb225997236ef3922454cbd361215afdf7) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument subsets", value=subsets, expected_type=type_hints["subsets"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - if subsets is not None: - self._values["subsets"] = subsets - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.core.v1.Endpoints#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def subsets(self) -> typing.Optional[typing.List[EndpointSubset]]: - '''The set of all endpoints is the union of all subsets. - - Addresses are placed into subsets according to the IPs they share. A single address with multiple ports, some of which are ready and some of which are not (because they come from different containers) will result in the address being displayed in different subsets for the different ports. No address will appear in both Addresses and NotReadyAddresses in the same subset. Sets of addresses and ports that comprise a service. - - :schema: io.k8s.api.core.v1.Endpoints#subsets - ''' - result = self._values.get("subsets") - return typing.cast(typing.Optional[typing.List[EndpointSubset]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeEndpointsProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeEvent( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeEvent", -): - '''Event is a report of an event somewhere in the cluster. - - It generally denotes some state change in the system. Events have a limited retention time and triggers and messages may evolve with time. Event consumers should not rely on the timing of an event with a given Reason reflecting a consistent underlying trigger, or the continued existence of events with that Reason. Events should be treated as informative, best-effort, supplemental data. - - :schema: io.k8s.api.events.v1.Event - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - event_time: datetime.datetime, - action: typing.Optional[builtins.str] = None, - deprecated_count: typing.Optional[jsii.Number] = None, - deprecated_first_timestamp: typing.Optional[datetime.datetime] = None, - deprecated_last_timestamp: typing.Optional[datetime.datetime] = None, - deprecated_source: typing.Optional[typing.Union[EventSource, typing.Dict[builtins.str, typing.Any]]] = None, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - note: typing.Optional[builtins.str] = None, - reason: typing.Optional[builtins.str] = None, - regarding: typing.Optional[typing.Union["ObjectReference", typing.Dict[builtins.str, typing.Any]]] = None, - related: typing.Optional[typing.Union["ObjectReference", typing.Dict[builtins.str, typing.Any]]] = None, - reporting_controller: typing.Optional[builtins.str] = None, - reporting_instance: typing.Optional[builtins.str] = None, - series: typing.Optional[typing.Union[EventSeries, typing.Dict[builtins.str, typing.Any]]] = None, - type: typing.Optional[builtins.str] = None, - ) -> None: - '''Defines a "io.k8s.api.events.v1.Event" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param event_time: eventTime is the time when this Event was first observed. It is required. - :param action: action is what action was taken/failed regarding to the regarding object. It is machine-readable. This field cannot be empty for new Events and it can have at most 128 characters. - :param deprecated_count: deprecatedCount is the deprecated field assuring backward compatibility with core.v1 Event type. - :param deprecated_first_timestamp: deprecatedFirstTimestamp is the deprecated field assuring backward compatibility with core.v1 Event type. - :param deprecated_last_timestamp: deprecatedLastTimestamp is the deprecated field assuring backward compatibility with core.v1 Event type. - :param deprecated_source: deprecatedSource is the deprecated field assuring backward compatibility with core.v1 Event type. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param note: note is a human-readable description of the status of this operation. Maximal length of the note is 1kB, but libraries should be prepared to handle values up to 64kB. - :param reason: reason is why the action was taken. It is human-readable. This field cannot be empty for new Events and it can have at most 128 characters. - :param regarding: regarding contains the object this Event is about. In most cases it's an Object reporting controller implements, e.g. ReplicaSetController implements ReplicaSets and this event is emitted because it acts on some changes in a ReplicaSet object. - :param related: related is the optional secondary object for more complex actions. E.g. when regarding object triggers a creation or deletion of related object. - :param reporting_controller: reportingController is the name of the controller that emitted this Event, e.g. ``kubernetes.io/kubelet``. This field cannot be empty for new Events. - :param reporting_instance: reportingInstance is the ID of the controller instance, e.g. ``kubelet-xyzf``. This field cannot be empty for new Events and it can have at most 128 characters. - :param series: series is data about the Event series this event represents or nil if it's a singleton Event. - :param type: type is the type of this event (Normal, Warning), new types could be added in the future. It is machine-readable. This field cannot be empty for new Events. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__bff248256702fdbc7f8830bde32e723508feda5df87528f11bc2ce4646805a0f) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeEventProps( - event_time=event_time, - action=action, - deprecated_count=deprecated_count, - deprecated_first_timestamp=deprecated_first_timestamp, - deprecated_last_timestamp=deprecated_last_timestamp, - deprecated_source=deprecated_source, - metadata=metadata, - note=note, - reason=reason, - regarding=regarding, - related=related, - reporting_controller=reporting_controller, - reporting_instance=reporting_instance, - series=series, - type=type, - ) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - event_time: datetime.datetime, - action: typing.Optional[builtins.str] = None, - deprecated_count: typing.Optional[jsii.Number] = None, - deprecated_first_timestamp: typing.Optional[datetime.datetime] = None, - deprecated_last_timestamp: typing.Optional[datetime.datetime] = None, - deprecated_source: typing.Optional[typing.Union[EventSource, typing.Dict[builtins.str, typing.Any]]] = None, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - note: typing.Optional[builtins.str] = None, - reason: typing.Optional[builtins.str] = None, - regarding: typing.Optional[typing.Union["ObjectReference", typing.Dict[builtins.str, typing.Any]]] = None, - related: typing.Optional[typing.Union["ObjectReference", typing.Dict[builtins.str, typing.Any]]] = None, - reporting_controller: typing.Optional[builtins.str] = None, - reporting_instance: typing.Optional[builtins.str] = None, - series: typing.Optional[typing.Union[EventSeries, typing.Dict[builtins.str, typing.Any]]] = None, - type: typing.Optional[builtins.str] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.events.v1.Event". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param event_time: eventTime is the time when this Event was first observed. It is required. - :param action: action is what action was taken/failed regarding to the regarding object. It is machine-readable. This field cannot be empty for new Events and it can have at most 128 characters. - :param deprecated_count: deprecatedCount is the deprecated field assuring backward compatibility with core.v1 Event type. - :param deprecated_first_timestamp: deprecatedFirstTimestamp is the deprecated field assuring backward compatibility with core.v1 Event type. - :param deprecated_last_timestamp: deprecatedLastTimestamp is the deprecated field assuring backward compatibility with core.v1 Event type. - :param deprecated_source: deprecatedSource is the deprecated field assuring backward compatibility with core.v1 Event type. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param note: note is a human-readable description of the status of this operation. Maximal length of the note is 1kB, but libraries should be prepared to handle values up to 64kB. - :param reason: reason is why the action was taken. It is human-readable. This field cannot be empty for new Events and it can have at most 128 characters. - :param regarding: regarding contains the object this Event is about. In most cases it's an Object reporting controller implements, e.g. ReplicaSetController implements ReplicaSets and this event is emitted because it acts on some changes in a ReplicaSet object. - :param related: related is the optional secondary object for more complex actions. E.g. when regarding object triggers a creation or deletion of related object. - :param reporting_controller: reportingController is the name of the controller that emitted this Event, e.g. ``kubernetes.io/kubelet``. This field cannot be empty for new Events. - :param reporting_instance: reportingInstance is the ID of the controller instance, e.g. ``kubelet-xyzf``. This field cannot be empty for new Events and it can have at most 128 characters. - :param series: series is data about the Event series this event represents or nil if it's a singleton Event. - :param type: type is the type of this event (Normal, Warning), new types could be added in the future. It is machine-readable. This field cannot be empty for new Events. - ''' - props = KubeEventProps( - event_time=event_time, - action=action, - deprecated_count=deprecated_count, - deprecated_first_timestamp=deprecated_first_timestamp, - deprecated_last_timestamp=deprecated_last_timestamp, - deprecated_source=deprecated_source, - metadata=metadata, - note=note, - reason=reason, - regarding=regarding, - related=related, - reporting_controller=reporting_controller, - reporting_instance=reporting_instance, - series=series, - type=type, - ) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.events.v1.Event".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubeEventList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeEventList", -): - '''EventList is a list of Event objects. - - :schema: io.k8s.api.events.v1.EventList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeEventProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.events.v1.EventList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: items is a list of schema objects. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__e546e7e1029a776b150b1d203fdfd30b45f89d03516fbe6b00d28c4dde254656) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeEventListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeEventProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.events.v1.EventList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: items is a list of schema objects. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - props = KubeEventListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.events.v1.EventList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeEventListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeEventListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeEventProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''EventList is a list of Event objects. - - :param items: items is a list of schema objects. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.events.v1.EventList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__f1413ee6881591e1991bd16a7298ddbd2f5adf1365ff312c068728af9df75f5d) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeEventProps"]: - '''items is a list of schema objects. - - :schema: io.k8s.api.events.v1.EventList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeEventProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.events.v1.EventList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeEventListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubeEventProps", - jsii_struct_bases=[], - name_mapping={ - "event_time": "eventTime", - "action": "action", - "deprecated_count": "deprecatedCount", - "deprecated_first_timestamp": "deprecatedFirstTimestamp", - "deprecated_last_timestamp": "deprecatedLastTimestamp", - "deprecated_source": "deprecatedSource", - "metadata": "metadata", - "note": "note", - "reason": "reason", - "regarding": "regarding", - "related": "related", - "reporting_controller": "reportingController", - "reporting_instance": "reportingInstance", - "series": "series", - "type": "type", - }, -) -class KubeEventProps: - def __init__( - self, - *, - event_time: datetime.datetime, - action: typing.Optional[builtins.str] = None, - deprecated_count: typing.Optional[jsii.Number] = None, - deprecated_first_timestamp: typing.Optional[datetime.datetime] = None, - deprecated_last_timestamp: typing.Optional[datetime.datetime] = None, - deprecated_source: typing.Optional[typing.Union[EventSource, typing.Dict[builtins.str, typing.Any]]] = None, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - note: typing.Optional[builtins.str] = None, - reason: typing.Optional[builtins.str] = None, - regarding: typing.Optional[typing.Union["ObjectReference", typing.Dict[builtins.str, typing.Any]]] = None, - related: typing.Optional[typing.Union["ObjectReference", typing.Dict[builtins.str, typing.Any]]] = None, - reporting_controller: typing.Optional[builtins.str] = None, - reporting_instance: typing.Optional[builtins.str] = None, - series: typing.Optional[typing.Union[EventSeries, typing.Dict[builtins.str, typing.Any]]] = None, - type: typing.Optional[builtins.str] = None, - ) -> None: - '''Event is a report of an event somewhere in the cluster. - - It generally denotes some state change in the system. Events have a limited retention time and triggers and messages may evolve with time. Event consumers should not rely on the timing of an event with a given Reason reflecting a consistent underlying trigger, or the continued existence of events with that Reason. Events should be treated as informative, best-effort, supplemental data. - - :param event_time: eventTime is the time when this Event was first observed. It is required. - :param action: action is what action was taken/failed regarding to the regarding object. It is machine-readable. This field cannot be empty for new Events and it can have at most 128 characters. - :param deprecated_count: deprecatedCount is the deprecated field assuring backward compatibility with core.v1 Event type. - :param deprecated_first_timestamp: deprecatedFirstTimestamp is the deprecated field assuring backward compatibility with core.v1 Event type. - :param deprecated_last_timestamp: deprecatedLastTimestamp is the deprecated field assuring backward compatibility with core.v1 Event type. - :param deprecated_source: deprecatedSource is the deprecated field assuring backward compatibility with core.v1 Event type. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param note: note is a human-readable description of the status of this operation. Maximal length of the note is 1kB, but libraries should be prepared to handle values up to 64kB. - :param reason: reason is why the action was taken. It is human-readable. This field cannot be empty for new Events and it can have at most 128 characters. - :param regarding: regarding contains the object this Event is about. In most cases it's an Object reporting controller implements, e.g. ReplicaSetController implements ReplicaSets and this event is emitted because it acts on some changes in a ReplicaSet object. - :param related: related is the optional secondary object for more complex actions. E.g. when regarding object triggers a creation or deletion of related object. - :param reporting_controller: reportingController is the name of the controller that emitted this Event, e.g. ``kubernetes.io/kubelet``. This field cannot be empty for new Events. - :param reporting_instance: reportingInstance is the ID of the controller instance, e.g. ``kubelet-xyzf``. This field cannot be empty for new Events and it can have at most 128 characters. - :param series: series is data about the Event series this event represents or nil if it's a singleton Event. - :param type: type is the type of this event (Normal, Warning), new types could be added in the future. It is machine-readable. This field cannot be empty for new Events. - - :schema: io.k8s.api.events.v1.Event - ''' - if isinstance(deprecated_source, dict): - deprecated_source = EventSource(**deprecated_source) - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if isinstance(regarding, dict): - regarding = ObjectReference(**regarding) - if isinstance(related, dict): - related = ObjectReference(**related) - if isinstance(series, dict): - series = EventSeries(**series) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__48c2a6f443e17733c15e46b85814aa0990b46cd3a60cd4b9a9dbb71d3d3e844b) - check_type(argname="argument event_time", value=event_time, expected_type=type_hints["event_time"]) - check_type(argname="argument action", value=action, expected_type=type_hints["action"]) - check_type(argname="argument deprecated_count", value=deprecated_count, expected_type=type_hints["deprecated_count"]) - check_type(argname="argument deprecated_first_timestamp", value=deprecated_first_timestamp, expected_type=type_hints["deprecated_first_timestamp"]) - check_type(argname="argument deprecated_last_timestamp", value=deprecated_last_timestamp, expected_type=type_hints["deprecated_last_timestamp"]) - check_type(argname="argument deprecated_source", value=deprecated_source, expected_type=type_hints["deprecated_source"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument note", value=note, expected_type=type_hints["note"]) - check_type(argname="argument reason", value=reason, expected_type=type_hints["reason"]) - check_type(argname="argument regarding", value=regarding, expected_type=type_hints["regarding"]) - check_type(argname="argument related", value=related, expected_type=type_hints["related"]) - check_type(argname="argument reporting_controller", value=reporting_controller, expected_type=type_hints["reporting_controller"]) - check_type(argname="argument reporting_instance", value=reporting_instance, expected_type=type_hints["reporting_instance"]) - check_type(argname="argument series", value=series, expected_type=type_hints["series"]) - check_type(argname="argument type", value=type, expected_type=type_hints["type"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "event_time": event_time, - } - if action is not None: - self._values["action"] = action - if deprecated_count is not None: - self._values["deprecated_count"] = deprecated_count - if deprecated_first_timestamp is not None: - self._values["deprecated_first_timestamp"] = deprecated_first_timestamp - if deprecated_last_timestamp is not None: - self._values["deprecated_last_timestamp"] = deprecated_last_timestamp - if deprecated_source is not None: - self._values["deprecated_source"] = deprecated_source - if metadata is not None: - self._values["metadata"] = metadata - if note is not None: - self._values["note"] = note - if reason is not None: - self._values["reason"] = reason - if regarding is not None: - self._values["regarding"] = regarding - if related is not None: - self._values["related"] = related - if reporting_controller is not None: - self._values["reporting_controller"] = reporting_controller - if reporting_instance is not None: - self._values["reporting_instance"] = reporting_instance - if series is not None: - self._values["series"] = series - if type is not None: - self._values["type"] = type - - @builtins.property - def event_time(self) -> datetime.datetime: - '''eventTime is the time when this Event was first observed. - - It is required. - - :schema: io.k8s.api.events.v1.Event#eventTime - ''' - result = self._values.get("event_time") - assert result is not None, "Required property 'event_time' is missing" - return typing.cast(datetime.datetime, result) - - @builtins.property - def action(self) -> typing.Optional[builtins.str]: - '''action is what action was taken/failed regarding to the regarding object. - - It is machine-readable. This field cannot be empty for new Events and it can have at most 128 characters. - - :schema: io.k8s.api.events.v1.Event#action - ''' - result = self._values.get("action") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def deprecated_count(self) -> typing.Optional[jsii.Number]: - '''deprecatedCount is the deprecated field assuring backward compatibility with core.v1 Event type. - - :schema: io.k8s.api.events.v1.Event#deprecatedCount - ''' - result = self._values.get("deprecated_count") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def deprecated_first_timestamp(self) -> typing.Optional[datetime.datetime]: - '''deprecatedFirstTimestamp is the deprecated field assuring backward compatibility with core.v1 Event type. - - :schema: io.k8s.api.events.v1.Event#deprecatedFirstTimestamp - ''' - result = self._values.get("deprecated_first_timestamp") - return typing.cast(typing.Optional[datetime.datetime], result) - - @builtins.property - def deprecated_last_timestamp(self) -> typing.Optional[datetime.datetime]: - '''deprecatedLastTimestamp is the deprecated field assuring backward compatibility with core.v1 Event type. - - :schema: io.k8s.api.events.v1.Event#deprecatedLastTimestamp - ''' - result = self._values.get("deprecated_last_timestamp") - return typing.cast(typing.Optional[datetime.datetime], result) - - @builtins.property - def deprecated_source(self) -> typing.Optional[EventSource]: - '''deprecatedSource is the deprecated field assuring backward compatibility with core.v1 Event type. - - :schema: io.k8s.api.events.v1.Event#deprecatedSource - ''' - result = self._values.get("deprecated_source") - return typing.cast(typing.Optional[EventSource], result) - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.events.v1.Event#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def note(self) -> typing.Optional[builtins.str]: - '''note is a human-readable description of the status of this operation. - - Maximal length of the note is 1kB, but libraries should be prepared to handle values up to 64kB. - - :schema: io.k8s.api.events.v1.Event#note - ''' - result = self._values.get("note") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def reason(self) -> typing.Optional[builtins.str]: - '''reason is why the action was taken. - - It is human-readable. This field cannot be empty for new Events and it can have at most 128 characters. - - :schema: io.k8s.api.events.v1.Event#reason - ''' - result = self._values.get("reason") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def regarding(self) -> typing.Optional["ObjectReference"]: - '''regarding contains the object this Event is about. - - In most cases it's an Object reporting controller implements, e.g. ReplicaSetController implements ReplicaSets and this event is emitted because it acts on some changes in a ReplicaSet object. - - :schema: io.k8s.api.events.v1.Event#regarding - ''' - result = self._values.get("regarding") - return typing.cast(typing.Optional["ObjectReference"], result) - - @builtins.property - def related(self) -> typing.Optional["ObjectReference"]: - '''related is the optional secondary object for more complex actions. - - E.g. when regarding object triggers a creation or deletion of related object. - - :schema: io.k8s.api.events.v1.Event#related - ''' - result = self._values.get("related") - return typing.cast(typing.Optional["ObjectReference"], result) - - @builtins.property - def reporting_controller(self) -> typing.Optional[builtins.str]: - '''reportingController is the name of the controller that emitted this Event, e.g. ``kubernetes.io/kubelet``. This field cannot be empty for new Events. - - :schema: io.k8s.api.events.v1.Event#reportingController - ''' - result = self._values.get("reporting_controller") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def reporting_instance(self) -> typing.Optional[builtins.str]: - '''reportingInstance is the ID of the controller instance, e.g. ``kubelet-xyzf``. This field cannot be empty for new Events and it can have at most 128 characters. - - :schema: io.k8s.api.events.v1.Event#reportingInstance - ''' - result = self._values.get("reporting_instance") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def series(self) -> typing.Optional[EventSeries]: - '''series is data about the Event series this event represents or nil if it's a singleton Event. - - :schema: io.k8s.api.events.v1.Event#series - ''' - result = self._values.get("series") - return typing.cast(typing.Optional[EventSeries], result) - - @builtins.property - def type(self) -> typing.Optional[builtins.str]: - '''type is the type of this event (Normal, Warning), new types could be added in the future. - - It is machine-readable. This field cannot be empty for new Events. - - :schema: io.k8s.api.events.v1.Event#type - ''' - result = self._values.get("type") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeEventProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeEviction( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeEviction", -): - '''Eviction evicts a pod from its node subject to certain policies and safety constraints. - - This is a subresource of Pod. A request to cause such an eviction is created by POSTing to .../pods//evictions. - - :schema: io.k8s.api.policy.v1.Eviction - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - delete_options: typing.Optional[typing.Union[DeleteOptions, typing.Dict[builtins.str, typing.Any]]] = None, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.policy.v1.Eviction" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param delete_options: DeleteOptions may be provided. - :param metadata: ObjectMeta describes the pod that is being evicted. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__ce3fc7d57adcd46be2dfb9bf2c29323102143783bface1d1cbd34980309078ba) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeEvictionProps(delete_options=delete_options, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - delete_options: typing.Optional[typing.Union[DeleteOptions, typing.Dict[builtins.str, typing.Any]]] = None, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.policy.v1.Eviction". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param delete_options: DeleteOptions may be provided. - :param metadata: ObjectMeta describes the pod that is being evicted. - ''' - props = KubeEvictionProps(delete_options=delete_options, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.policy.v1.Eviction".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeEvictionProps", - jsii_struct_bases=[], - name_mapping={"delete_options": "deleteOptions", "metadata": "metadata"}, -) -class KubeEvictionProps: - def __init__( - self, - *, - delete_options: typing.Optional[typing.Union[DeleteOptions, typing.Dict[builtins.str, typing.Any]]] = None, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Eviction evicts a pod from its node subject to certain policies and safety constraints. - - This is a subresource of Pod. A request to cause such an eviction is created by POSTing to .../pods//evictions. - - :param delete_options: DeleteOptions may be provided. - :param metadata: ObjectMeta describes the pod that is being evicted. - - :schema: io.k8s.api.policy.v1.Eviction - ''' - if isinstance(delete_options, dict): - delete_options = DeleteOptions(**delete_options) - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__87cf0d2be9c3f9f8ef8e2278ad8544565ff3211d2445691804c2609bf06a14a3) - check_type(argname="argument delete_options", value=delete_options, expected_type=type_hints["delete_options"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if delete_options is not None: - self._values["delete_options"] = delete_options - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def delete_options(self) -> typing.Optional[DeleteOptions]: - '''DeleteOptions may be provided. - - :schema: io.k8s.api.policy.v1.Eviction#deleteOptions - ''' - result = self._values.get("delete_options") - return typing.cast(typing.Optional[DeleteOptions], result) - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''ObjectMeta describes the pod that is being evicted. - - :schema: io.k8s.api.policy.v1.Eviction#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeEvictionProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeFlowSchemaListV1Beta2( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeFlowSchemaListV1Beta2", -): - '''FlowSchemaList is a list of FlowSchema objects. - - :schema: io.k8s.api.flowcontrol.v1beta2.FlowSchemaList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeFlowSchemaV1Beta2Props", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.flowcontrol.v1beta2.FlowSchemaList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: ``items`` is a list of FlowSchemas. - :param metadata: ``metadata`` is the standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__78dcce4ae43399b690dc9289853b5102369f03ffcdfb89350c8411a78672d51b) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeFlowSchemaListV1Beta2Props(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeFlowSchemaV1Beta2Props", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.flowcontrol.v1beta2.FlowSchemaList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: ``items`` is a list of FlowSchemas. - :param metadata: ``metadata`` is the standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - props = KubeFlowSchemaListV1Beta2Props(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.flowcontrol.v1beta2.FlowSchemaList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeFlowSchemaListV1Beta2Props", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeFlowSchemaListV1Beta2Props: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeFlowSchemaV1Beta2Props", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''FlowSchemaList is a list of FlowSchema objects. - - :param items: ``items`` is a list of FlowSchemas. - :param metadata: ``metadata`` is the standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.flowcontrol.v1beta2.FlowSchemaList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__7840b0ea66b23c128361bc5a2f5b97608be83a0c9fb75ed5aa96409d669ab7dd) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeFlowSchemaV1Beta2Props"]: - '''``items`` is a list of FlowSchemas. - - :schema: io.k8s.api.flowcontrol.v1beta2.FlowSchemaList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeFlowSchemaV1Beta2Props"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''``metadata`` is the standard list metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.flowcontrol.v1beta2.FlowSchemaList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeFlowSchemaListV1Beta2Props(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeFlowSchemaListV1Beta3( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeFlowSchemaListV1Beta3", -): - '''FlowSchemaList is a list of FlowSchema objects. - - :schema: io.k8s.api.flowcontrol.v1beta3.FlowSchemaList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeFlowSchemaV1Beta3Props", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.flowcontrol.v1beta3.FlowSchemaList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: ``items`` is a list of FlowSchemas. - :param metadata: ``metadata`` is the standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__3d77a2bc947160fa8c8b7379c2b017e6bb43ad9bb7d61e92ce9feee34f94bfe9) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeFlowSchemaListV1Beta3Props(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeFlowSchemaV1Beta3Props", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.flowcontrol.v1beta3.FlowSchemaList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: ``items`` is a list of FlowSchemas. - :param metadata: ``metadata`` is the standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - props = KubeFlowSchemaListV1Beta3Props(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.flowcontrol.v1beta3.FlowSchemaList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeFlowSchemaListV1Beta3Props", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeFlowSchemaListV1Beta3Props: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeFlowSchemaV1Beta3Props", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''FlowSchemaList is a list of FlowSchema objects. - - :param items: ``items`` is a list of FlowSchemas. - :param metadata: ``metadata`` is the standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.flowcontrol.v1beta3.FlowSchemaList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__9324188a061c5eae530453984a55d9350e8a735317db123e7ead7e0c73209b67) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeFlowSchemaV1Beta3Props"]: - '''``items`` is a list of FlowSchemas. - - :schema: io.k8s.api.flowcontrol.v1beta3.FlowSchemaList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeFlowSchemaV1Beta3Props"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''``metadata`` is the standard list metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.flowcontrol.v1beta3.FlowSchemaList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeFlowSchemaListV1Beta3Props(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeFlowSchemaV1Beta2( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeFlowSchemaV1Beta2", -): - '''FlowSchema defines the schema of a group of flows. - - Note that a flow is made up of a set of inbound API requests with similar attributes and is identified by a pair of strings: the name of the FlowSchema and a "flow distinguisher". - - :schema: io.k8s.api.flowcontrol.v1beta2.FlowSchema - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[FlowSchemaSpecV1Beta2, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.flowcontrol.v1beta2.FlowSchema" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param metadata: ``metadata`` is the standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: ``spec`` is the specification of the desired behavior of a FlowSchema. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__7a45c05db0efb498337d9fdf72478dae3390139a5e4eb9ef9809436601b2a0da) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeFlowSchemaV1Beta2Props(metadata=metadata, spec=spec) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[FlowSchemaSpecV1Beta2, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.flowcontrol.v1beta2.FlowSchema". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param metadata: ``metadata`` is the standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: ``spec`` is the specification of the desired behavior of a FlowSchema. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - ''' - props = KubeFlowSchemaV1Beta2Props(metadata=metadata, spec=spec) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.flowcontrol.v1beta2.FlowSchema".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeFlowSchemaV1Beta2Props", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata", "spec": "spec"}, -) -class KubeFlowSchemaV1Beta2Props: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[FlowSchemaSpecV1Beta2, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''FlowSchema defines the schema of a group of flows. - - Note that a flow is made up of a set of inbound API requests with similar attributes and is identified by a pair of strings: the name of the FlowSchema and a "flow distinguisher". - - :param metadata: ``metadata`` is the standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: ``spec`` is the specification of the desired behavior of a FlowSchema. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.flowcontrol.v1beta2.FlowSchema - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if isinstance(spec, dict): - spec = FlowSchemaSpecV1Beta2(**spec) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__e106d80425e44c2dfdc8be52665b26e79dc781475001784de3ddaa904271cc59) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - if spec is not None: - self._values["spec"] = spec - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''``metadata`` is the standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.flowcontrol.v1beta2.FlowSchema#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def spec(self) -> typing.Optional[FlowSchemaSpecV1Beta2]: - '''``spec`` is the specification of the desired behavior of a FlowSchema. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.flowcontrol.v1beta2.FlowSchema#spec - ''' - result = self._values.get("spec") - return typing.cast(typing.Optional[FlowSchemaSpecV1Beta2], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeFlowSchemaV1Beta2Props(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeFlowSchemaV1Beta3( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeFlowSchemaV1Beta3", -): - '''FlowSchema defines the schema of a group of flows. - - Note that a flow is made up of a set of inbound API requests with similar attributes and is identified by a pair of strings: the name of the FlowSchema and a "flow distinguisher". - - :schema: io.k8s.api.flowcontrol.v1beta3.FlowSchema - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[FlowSchemaSpecV1Beta3, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.flowcontrol.v1beta3.FlowSchema" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param metadata: ``metadata`` is the standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: ``spec`` is the specification of the desired behavior of a FlowSchema. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__a9b9348b12fce50fb80513761ddfb24eea7f7945e13e61ce1aa0681387d5b265) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeFlowSchemaV1Beta3Props(metadata=metadata, spec=spec) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[FlowSchemaSpecV1Beta3, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.flowcontrol.v1beta3.FlowSchema". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param metadata: ``metadata`` is the standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: ``spec`` is the specification of the desired behavior of a FlowSchema. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - ''' - props = KubeFlowSchemaV1Beta3Props(metadata=metadata, spec=spec) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.flowcontrol.v1beta3.FlowSchema".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeFlowSchemaV1Beta3Props", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata", "spec": "spec"}, -) -class KubeFlowSchemaV1Beta3Props: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[FlowSchemaSpecV1Beta3, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''FlowSchema defines the schema of a group of flows. - - Note that a flow is made up of a set of inbound API requests with similar attributes and is identified by a pair of strings: the name of the FlowSchema and a "flow distinguisher". - - :param metadata: ``metadata`` is the standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: ``spec`` is the specification of the desired behavior of a FlowSchema. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.flowcontrol.v1beta3.FlowSchema - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if isinstance(spec, dict): - spec = FlowSchemaSpecV1Beta3(**spec) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__6410a409fbe720f8a5200bbc56c83314c2abbde52a3f3e6d86dcffa538d45f0e) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - if spec is not None: - self._values["spec"] = spec - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''``metadata`` is the standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.flowcontrol.v1beta3.FlowSchema#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def spec(self) -> typing.Optional[FlowSchemaSpecV1Beta3]: - '''``spec`` is the specification of the desired behavior of a FlowSchema. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.flowcontrol.v1beta3.FlowSchema#spec - ''' - result = self._values.get("spec") - return typing.cast(typing.Optional[FlowSchemaSpecV1Beta3], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeFlowSchemaV1Beta3Props(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeHorizontalPodAutoscaler( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeHorizontalPodAutoscaler", -): - '''configuration of a horizontal pod autoscaler. - - :schema: io.k8s.api.autoscaling.v1.HorizontalPodAutoscaler - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[HorizontalPodAutoscalerSpec, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.autoscaling.v1.HorizontalPodAutoscaler" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param metadata: Standard object metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: behaviour of autoscaler. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__3659a33a1f8b87b529d9e9023dd6bb01e0bfb73facc829ec1a43b27043decca0) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeHorizontalPodAutoscalerProps(metadata=metadata, spec=spec) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[HorizontalPodAutoscalerSpec, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.autoscaling.v1.HorizontalPodAutoscaler". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param metadata: Standard object metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: behaviour of autoscaler. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status. - ''' - props = KubeHorizontalPodAutoscalerProps(metadata=metadata, spec=spec) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.autoscaling.v1.HorizontalPodAutoscaler".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubeHorizontalPodAutoscalerList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeHorizontalPodAutoscalerList", -): - '''list of horizontal pod autoscaler objects. - - :schema: io.k8s.api.autoscaling.v1.HorizontalPodAutoscalerList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeHorizontalPodAutoscalerProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.autoscaling.v1.HorizontalPodAutoscalerList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: list of horizontal pod autoscaler objects. - :param metadata: Standard list metadata. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__d083f278632697415785096091248f1e45891163fa170df1eb5824abc4d7153c) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeHorizontalPodAutoscalerListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeHorizontalPodAutoscalerProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.autoscaling.v1.HorizontalPodAutoscalerList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: list of horizontal pod autoscaler objects. - :param metadata: Standard list metadata. - ''' - props = KubeHorizontalPodAutoscalerListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.autoscaling.v1.HorizontalPodAutoscalerList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeHorizontalPodAutoscalerListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeHorizontalPodAutoscalerListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeHorizontalPodAutoscalerProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''list of horizontal pod autoscaler objects. - - :param items: list of horizontal pod autoscaler objects. - :param metadata: Standard list metadata. - - :schema: io.k8s.api.autoscaling.v1.HorizontalPodAutoscalerList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__e26ffe8caa8bac98a411574cbd7526286da29c633ab894498e0b6be6bad7b5ec) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeHorizontalPodAutoscalerProps"]: - '''list of horizontal pod autoscaler objects. - - :schema: io.k8s.api.autoscaling.v1.HorizontalPodAutoscalerList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeHorizontalPodAutoscalerProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata. - - :schema: io.k8s.api.autoscaling.v1.HorizontalPodAutoscalerList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeHorizontalPodAutoscalerListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeHorizontalPodAutoscalerListV2( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeHorizontalPodAutoscalerListV2", -): - '''HorizontalPodAutoscalerList is a list of horizontal pod autoscaler objects. - - :schema: io.k8s.api.autoscaling.v2.HorizontalPodAutoscalerList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeHorizontalPodAutoscalerV2Props", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.autoscaling.v2.HorizontalPodAutoscalerList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: items is the list of horizontal pod autoscaler objects. - :param metadata: metadata is the standard list metadata. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__612b9b7f601cf85679f8310aba2b1726e9093cf95529f5cdb32980ecb876fc78) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeHorizontalPodAutoscalerListV2Props(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeHorizontalPodAutoscalerV2Props", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.autoscaling.v2.HorizontalPodAutoscalerList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: items is the list of horizontal pod autoscaler objects. - :param metadata: metadata is the standard list metadata. - ''' - props = KubeHorizontalPodAutoscalerListV2Props(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.autoscaling.v2.HorizontalPodAutoscalerList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeHorizontalPodAutoscalerListV2Props", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeHorizontalPodAutoscalerListV2Props: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeHorizontalPodAutoscalerV2Props", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''HorizontalPodAutoscalerList is a list of horizontal pod autoscaler objects. - - :param items: items is the list of horizontal pod autoscaler objects. - :param metadata: metadata is the standard list metadata. - - :schema: io.k8s.api.autoscaling.v2.HorizontalPodAutoscalerList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__82d754c8d97bd9130289b15ea62a398adf7971a9304499522bbc19f063139128) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeHorizontalPodAutoscalerV2Props"]: - '''items is the list of horizontal pod autoscaler objects. - - :schema: io.k8s.api.autoscaling.v2.HorizontalPodAutoscalerList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeHorizontalPodAutoscalerV2Props"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''metadata is the standard list metadata. - - :schema: io.k8s.api.autoscaling.v2.HorizontalPodAutoscalerList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeHorizontalPodAutoscalerListV2Props(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubeHorizontalPodAutoscalerProps", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata", "spec": "spec"}, -) -class KubeHorizontalPodAutoscalerProps: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[HorizontalPodAutoscalerSpec, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''configuration of a horizontal pod autoscaler. - - :param metadata: Standard object metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: behaviour of autoscaler. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status. - - :schema: io.k8s.api.autoscaling.v1.HorizontalPodAutoscaler - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if isinstance(spec, dict): - spec = HorizontalPodAutoscalerSpec(**spec) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__542b4bd5deadf3f3ea668c268b55d72b558ce8b50e724f90f1bae3abad482de7) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - if spec is not None: - self._values["spec"] = spec - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.autoscaling.v1.HorizontalPodAutoscaler#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def spec(self) -> typing.Optional[HorizontalPodAutoscalerSpec]: - '''behaviour of autoscaler. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status. - - :schema: io.k8s.api.autoscaling.v1.HorizontalPodAutoscaler#spec - ''' - result = self._values.get("spec") - return typing.cast(typing.Optional[HorizontalPodAutoscalerSpec], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeHorizontalPodAutoscalerProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeHorizontalPodAutoscalerV2( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeHorizontalPodAutoscalerV2", -): - '''HorizontalPodAutoscaler is the configuration for a horizontal pod autoscaler, which automatically manages the replica count of any resource implementing the scale subresource based on the metrics specified. - - :schema: io.k8s.api.autoscaling.v2.HorizontalPodAutoscaler - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[HorizontalPodAutoscalerSpecV2, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.autoscaling.v2.HorizontalPodAutoscaler" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param metadata: metadata is the standard object metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: spec is the specification for the behaviour of the autoscaler. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__9ca507f6cd5ee9c7cea60234c215b0a4ffad2c91ec0a23f8d44798e355cbb065) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeHorizontalPodAutoscalerV2Props(metadata=metadata, spec=spec) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[HorizontalPodAutoscalerSpecV2, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.autoscaling.v2.HorizontalPodAutoscaler". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param metadata: metadata is the standard object metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: spec is the specification for the behaviour of the autoscaler. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status. - ''' - props = KubeHorizontalPodAutoscalerV2Props(metadata=metadata, spec=spec) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.autoscaling.v2.HorizontalPodAutoscaler".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeHorizontalPodAutoscalerV2Props", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata", "spec": "spec"}, -) -class KubeHorizontalPodAutoscalerV2Props: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[HorizontalPodAutoscalerSpecV2, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''HorizontalPodAutoscaler is the configuration for a horizontal pod autoscaler, which automatically manages the replica count of any resource implementing the scale subresource based on the metrics specified. - - :param metadata: metadata is the standard object metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: spec is the specification for the behaviour of the autoscaler. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status. - - :schema: io.k8s.api.autoscaling.v2.HorizontalPodAutoscaler - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if isinstance(spec, dict): - spec = HorizontalPodAutoscalerSpecV2(**spec) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__53e62de6a231cf1b2dd6d0d4c7bf7bca086b1fee4162cdbfec39861730181a09) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - if spec is not None: - self._values["spec"] = spec - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''metadata is the standard object metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.autoscaling.v2.HorizontalPodAutoscaler#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def spec(self) -> typing.Optional[HorizontalPodAutoscalerSpecV2]: - '''spec is the specification for the behaviour of the autoscaler. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status. - - :schema: io.k8s.api.autoscaling.v2.HorizontalPodAutoscaler#spec - ''' - result = self._values.get("spec") - return typing.cast(typing.Optional[HorizontalPodAutoscalerSpecV2], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeHorizontalPodAutoscalerV2Props(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeIngress( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeIngress", -): - '''Ingress is a collection of rules that allow inbound connections to reach the endpoints defined by a backend. - - An Ingress can be configured to give services externally-reachable urls, load balance traffic, terminate SSL, offer name based virtual hosting etc. - - :schema: io.k8s.api.networking.v1.Ingress - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[IngressSpec, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.networking.v1.Ingress" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Spec is the desired state of the Ingress. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__fecb69d0c5ae696fc26dfb5e8ab4fdf624ec8c1b40d730da8ee18908df85a89a) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeIngressProps(metadata=metadata, spec=spec) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[IngressSpec, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.networking.v1.Ingress". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Spec is the desired state of the Ingress. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - ''' - props = KubeIngressProps(metadata=metadata, spec=spec) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.networking.v1.Ingress".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubeIngressClass( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeIngressClass", -): - '''IngressClass represents the class of the Ingress, referenced by the Ingress Spec. - - The ``ingressclass.kubernetes.io/is-default-class`` annotation can be used to indicate that an IngressClass should be considered default. When a single IngressClass resource has this annotation set to true, new Ingress resources without a class specified will be assigned this default class. - - :schema: io.k8s.api.networking.v1.IngressClass - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[IngressClassSpec, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.networking.v1.IngressClass" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Spec is the desired state of the IngressClass. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__d418ae2f0a6f2d90c9b2dd88ca1f6a84e3153a97a96e7ff6807e07b0dd61c0b7) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeIngressClassProps(metadata=metadata, spec=spec) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[IngressClassSpec, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.networking.v1.IngressClass". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Spec is the desired state of the IngressClass. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - ''' - props = KubeIngressClassProps(metadata=metadata, spec=spec) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.networking.v1.IngressClass".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubeIngressClassList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeIngressClassList", -): - '''IngressClassList is a collection of IngressClasses. - - :schema: io.k8s.api.networking.v1.IngressClassList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeIngressClassProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.networking.v1.IngressClassList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: Items is the list of IngressClasses. - :param metadata: Standard list metadata. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__bc0fa42e29a73942af0afef36f066bacef13f7e6faa1064781e6f6b6797cc61a) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeIngressClassListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeIngressClassProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.networking.v1.IngressClassList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: Items is the list of IngressClasses. - :param metadata: Standard list metadata. - ''' - props = KubeIngressClassListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.networking.v1.IngressClassList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeIngressClassListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeIngressClassListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeIngressClassProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''IngressClassList is a collection of IngressClasses. - - :param items: Items is the list of IngressClasses. - :param metadata: Standard list metadata. - - :schema: io.k8s.api.networking.v1.IngressClassList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__82c7c14ff0df4771b1efd0ca1f8329565f6bcd7e8eaa44ac5477a9fd2a3c41d2) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeIngressClassProps"]: - '''Items is the list of IngressClasses. - - :schema: io.k8s.api.networking.v1.IngressClassList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeIngressClassProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata. - - :schema: io.k8s.api.networking.v1.IngressClassList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeIngressClassListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubeIngressClassProps", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata", "spec": "spec"}, -) -class KubeIngressClassProps: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[IngressClassSpec, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''IngressClass represents the class of the Ingress, referenced by the Ingress Spec. - - The ``ingressclass.kubernetes.io/is-default-class`` annotation can be used to indicate that an IngressClass should be considered default. When a single IngressClass resource has this annotation set to true, new Ingress resources without a class specified will be assigned this default class. - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Spec is the desired state of the IngressClass. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.networking.v1.IngressClass - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if isinstance(spec, dict): - spec = IngressClassSpec(**spec) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__5ff63d6e124700008192e962f05892ebc82196bb74b11b70eaba4b39b70836b7) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - if spec is not None: - self._values["spec"] = spec - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.networking.v1.IngressClass#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def spec(self) -> typing.Optional[IngressClassSpec]: - '''Spec is the desired state of the IngressClass. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.networking.v1.IngressClass#spec - ''' - result = self._values.get("spec") - return typing.cast(typing.Optional[IngressClassSpec], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeIngressClassProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeIngressList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeIngressList", -): - '''IngressList is a collection of Ingress. - - :schema: io.k8s.api.networking.v1.IngressList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeIngressProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.networking.v1.IngressList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: Items is the list of Ingress. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__f226e78ce6490682fe3c9a63b8ce32fe7c21b49aa9ce2e44e5b9fd3f61a3d60a) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeIngressListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeIngressProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.networking.v1.IngressList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: Items is the list of Ingress. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - props = KubeIngressListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.networking.v1.IngressList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeIngressListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeIngressListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeIngressProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''IngressList is a collection of Ingress. - - :param items: Items is the list of Ingress. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.networking.v1.IngressList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__f7312bcea7e490386f6d60582abdc979996825d2af8c213e81cab63ed38979d1) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeIngressProps"]: - '''Items is the list of Ingress. - - :schema: io.k8s.api.networking.v1.IngressList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeIngressProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.networking.v1.IngressList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeIngressListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubeIngressProps", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata", "spec": "spec"}, -) -class KubeIngressProps: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[IngressSpec, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Ingress is a collection of rules that allow inbound connections to reach the endpoints defined by a backend. - - An Ingress can be configured to give services externally-reachable urls, load balance traffic, terminate SSL, offer name based virtual hosting etc. - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Spec is the desired state of the Ingress. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.networking.v1.Ingress - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if isinstance(spec, dict): - spec = IngressSpec(**spec) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__c6fb53470ef0dd80ea7bd4fef27d3ddf64cb7f36e5eea57e17b603eea466bdbd) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - if spec is not None: - self._values["spec"] = spec - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.networking.v1.Ingress#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def spec(self) -> typing.Optional[IngressSpec]: - '''Spec is the desired state of the Ingress. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.networking.v1.Ingress#spec - ''' - result = self._values.get("spec") - return typing.cast(typing.Optional[IngressSpec], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeIngressProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeJob( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeJob", -): - '''Job represents the configuration of a single job. - - :schema: io.k8s.api.batch.v1.Job - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[JobSpec, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.batch.v1.Job" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Specification of the desired behavior of a job. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__fff358859e9af9ea8332041ebc8c62133b4e15d6bae01f757722777868bbf975) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeJobProps(metadata=metadata, spec=spec) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[JobSpec, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.batch.v1.Job". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Specification of the desired behavior of a job. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - ''' - props = KubeJobProps(metadata=metadata, spec=spec) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.batch.v1.Job".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubeJobList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeJobList", -): - '''JobList is a collection of jobs. - - :schema: io.k8s.api.batch.v1.JobList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeJobProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.batch.v1.JobList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: items is the list of Jobs. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__ebfb0aedffe4b9969191f6572e8cede1b485af52b80986d4fcdbaf0f5983cd6d) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeJobListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeJobProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.batch.v1.JobList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: items is the list of Jobs. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - props = KubeJobListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.batch.v1.JobList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeJobListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeJobListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeJobProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''JobList is a collection of jobs. - - :param items: items is the list of Jobs. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.batch.v1.JobList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__8c68110c5b5d423614744f1c0238268018af1c5d3aac79966f04ee1b380605fa) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeJobProps"]: - '''items is the list of Jobs. - - :schema: io.k8s.api.batch.v1.JobList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeJobProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.batch.v1.JobList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeJobListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubeJobProps", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata", "spec": "spec"}, -) -class KubeJobProps: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[JobSpec, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Job represents the configuration of a single job. - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Specification of the desired behavior of a job. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.batch.v1.Job - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if isinstance(spec, dict): - spec = JobSpec(**spec) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__d8623d11ce8ff4879cf0c14e0993080e88ac2cb1e525affa070848156c47f58d) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - if spec is not None: - self._values["spec"] = spec - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.batch.v1.Job#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def spec(self) -> typing.Optional[JobSpec]: - '''Specification of the desired behavior of a job. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.batch.v1.Job#spec - ''' - result = self._values.get("spec") - return typing.cast(typing.Optional[JobSpec], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeJobProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeLease( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeLease", -): - '''Lease defines a lease concept. - - :schema: io.k8s.api.coordination.v1.Lease - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["LeaseSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.coordination.v1.Lease" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param metadata: More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - :param spec: Specification of the Lease. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__9d7ac416a382b84ffda17705003bcb5bf298edcb4ce565074e252fb3615f92b2) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeLeaseProps(metadata=metadata, spec=spec) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["LeaseSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.coordination.v1.Lease". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param metadata: More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - :param spec: Specification of the Lease. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - ''' - props = KubeLeaseProps(metadata=metadata, spec=spec) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.coordination.v1.Lease".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubeLeaseList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeLeaseList", -): - '''LeaseList is a list of Lease objects. - - :schema: io.k8s.api.coordination.v1.LeaseList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeLeaseProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.coordination.v1.LeaseList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: Items is a list of schema objects. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__75166c72791817156d385921cd400e23041c5ec11ee91d66d38a9f3f2858d1b7) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeLeaseListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeLeaseProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.coordination.v1.LeaseList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: Items is a list of schema objects. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - props = KubeLeaseListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.coordination.v1.LeaseList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeLeaseListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeLeaseListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeLeaseProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''LeaseList is a list of Lease objects. - - :param items: Items is a list of schema objects. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.coordination.v1.LeaseList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__298c44b61ec9eb849c15cf2a5e383a73704159b87103b7b3ad5e506767bc102f) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeLeaseProps"]: - '''Items is a list of schema objects. - - :schema: io.k8s.api.coordination.v1.LeaseList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeLeaseProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.coordination.v1.LeaseList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeLeaseListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubeLeaseProps", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata", "spec": "spec"}, -) -class KubeLeaseProps: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["LeaseSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Lease defines a lease concept. - - :param metadata: More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - :param spec: Specification of the Lease. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.coordination.v1.Lease - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if isinstance(spec, dict): - spec = LeaseSpec(**spec) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__087e36c33055af38c535d84159dc6ca27d3ac01c18260bfd1accaa57ca9e9f87) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - if spec is not None: - self._values["spec"] = spec - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - - :schema: io.k8s.api.coordination.v1.Lease#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def spec(self) -> typing.Optional["LeaseSpec"]: - '''Specification of the Lease. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.coordination.v1.Lease#spec - ''' - result = self._values.get("spec") - return typing.cast(typing.Optional["LeaseSpec"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeLeaseProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeLimitRange( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeLimitRange", -): - '''LimitRange sets resource usage limits for each kind of resource in a Namespace. - - :schema: io.k8s.api.core.v1.LimitRange - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["LimitRangeSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.core.v1.LimitRange" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Spec defines the limits enforced. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__a07d6eaf25ce775558c3ff31cf7338c76165ccf4142236e04da563765d8cf0b1) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeLimitRangeProps(metadata=metadata, spec=spec) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["LimitRangeSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.core.v1.LimitRange". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Spec defines the limits enforced. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - ''' - props = KubeLimitRangeProps(metadata=metadata, spec=spec) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.core.v1.LimitRange".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubeLimitRangeList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeLimitRangeList", -): - '''LimitRangeList is a list of LimitRange items. - - :schema: io.k8s.api.core.v1.LimitRangeList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeLimitRangeProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.core.v1.LimitRangeList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: Items is a list of LimitRange objects. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__c7a8f8a9863b43e2fd00c4b8c7d258d2c05e91ae89be7106f6de4aed120b72db) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeLimitRangeListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeLimitRangeProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.core.v1.LimitRangeList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: Items is a list of LimitRange objects. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - ''' - props = KubeLimitRangeListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.core.v1.LimitRangeList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeLimitRangeListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeLimitRangeListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeLimitRangeProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''LimitRangeList is a list of LimitRange items. - - :param items: Items is a list of LimitRange objects. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.core.v1.LimitRangeList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__1ddfc6edaee1a35d88f539af8024140cdbeb093b064f536ca3b5b93e5ccaba6c) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeLimitRangeProps"]: - '''Items is a list of LimitRange objects. - - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - - :schema: io.k8s.api.core.v1.LimitRangeList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeLimitRangeProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.core.v1.LimitRangeList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeLimitRangeListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubeLimitRangeProps", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata", "spec": "spec"}, -) -class KubeLimitRangeProps: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["LimitRangeSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''LimitRange sets resource usage limits for each kind of resource in a Namespace. - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Spec defines the limits enforced. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.core.v1.LimitRange - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if isinstance(spec, dict): - spec = LimitRangeSpec(**spec) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__2f09492d34c2b6f246cc5363c69827532389bf688a8153b21d1be33b85f10e08) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - if spec is not None: - self._values["spec"] = spec - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.core.v1.LimitRange#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def spec(self) -> typing.Optional["LimitRangeSpec"]: - '''Spec defines the limits enforced. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.core.v1.LimitRange#spec - ''' - result = self._values.get("spec") - return typing.cast(typing.Optional["LimitRangeSpec"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeLimitRangeProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeLocalSubjectAccessReview( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeLocalSubjectAccessReview", -): - '''LocalSubjectAccessReview checks whether or not a user or group can perform an action in a given namespace. - - Having a namespace scoped resource makes it much easier to grant namespace scoped policy that includes permissions checking. - - :schema: io.k8s.api.authorization.v1.LocalSubjectAccessReview - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - spec: typing.Union["SubjectAccessReviewSpec", typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.authorization.v1.LocalSubjectAccessReview" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param spec: Spec holds information about the request being evaluated. spec.namespace must be equal to the namespace you made the request against. If empty, it is defaulted. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__cdf9554ef0e379495534a1087b68841710eca3f0d932611510b7ba25ae57d8c0) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeLocalSubjectAccessReviewProps(spec=spec, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - spec: typing.Union["SubjectAccessReviewSpec", typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.authorization.v1.LocalSubjectAccessReview". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param spec: Spec holds information about the request being evaluated. spec.namespace must be equal to the namespace you made the request against. If empty, it is defaulted. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - props = KubeLocalSubjectAccessReviewProps(spec=spec, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.authorization.v1.LocalSubjectAccessReview".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeLocalSubjectAccessReviewProps", - jsii_struct_bases=[], - name_mapping={"spec": "spec", "metadata": "metadata"}, -) -class KubeLocalSubjectAccessReviewProps: - def __init__( - self, - *, - spec: typing.Union["SubjectAccessReviewSpec", typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''LocalSubjectAccessReview checks whether or not a user or group can perform an action in a given namespace. - - Having a namespace scoped resource makes it much easier to grant namespace scoped policy that includes permissions checking. - - :param spec: Spec holds information about the request being evaluated. spec.namespace must be equal to the namespace you made the request against. If empty, it is defaulted. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.authorization.v1.LocalSubjectAccessReview - ''' - if isinstance(spec, dict): - spec = SubjectAccessReviewSpec(**spec) - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__70906afc8c383c855cbd20f07b10abc432f25794647078ae07044f7af0aecd01) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "spec": spec, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def spec(self) -> "SubjectAccessReviewSpec": - '''Spec holds information about the request being evaluated. - - spec.namespace must be equal to the namespace you made the request against. If empty, it is defaulted. - - :schema: io.k8s.api.authorization.v1.LocalSubjectAccessReview#spec - ''' - result = self._values.get("spec") - assert result is not None, "Required property 'spec' is missing" - return typing.cast("SubjectAccessReviewSpec", result) - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard list metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.authorization.v1.LocalSubjectAccessReview#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeLocalSubjectAccessReviewProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeMutatingWebhookConfiguration( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeMutatingWebhookConfiguration", -): - '''MutatingWebhookConfiguration describes the configuration of and admission webhook that accept or reject and may change the object. - - :schema: io.k8s.api.admissionregistration.v1.MutatingWebhookConfiguration - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - webhooks: typing.Optional[typing.Sequence[typing.Union["MutatingWebhook", typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''Defines a "io.k8s.api.admissionregistration.v1.MutatingWebhookConfiguration" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param metadata: Standard object metadata; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - :param webhooks: Webhooks is a list of webhooks and the affected resources and operations. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__78fbbe028a200f70510169b8127ab5f20fbf81ad5ddeeea991e488779448b60f) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeMutatingWebhookConfigurationProps( - metadata=metadata, webhooks=webhooks - ) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - webhooks: typing.Optional[typing.Sequence[typing.Union["MutatingWebhook", typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.admissionregistration.v1.MutatingWebhookConfiguration". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param metadata: Standard object metadata; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - :param webhooks: Webhooks is a list of webhooks and the affected resources and operations. - ''' - props = KubeMutatingWebhookConfigurationProps( - metadata=metadata, webhooks=webhooks - ) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.admissionregistration.v1.MutatingWebhookConfiguration".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubeMutatingWebhookConfigurationList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeMutatingWebhookConfigurationList", -): - '''MutatingWebhookConfigurationList is a list of MutatingWebhookConfiguration. - - :schema: io.k8s.api.admissionregistration.v1.MutatingWebhookConfigurationList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeMutatingWebhookConfigurationProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.admissionregistration.v1.MutatingWebhookConfigurationList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: List of MutatingWebhookConfiguration. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__85169c24c76c15a829cd177c34e67d5781ce9a0ad8b7556ff48f987f00297ec0) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeMutatingWebhookConfigurationListProps( - items=items, metadata=metadata - ) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeMutatingWebhookConfigurationProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.admissionregistration.v1.MutatingWebhookConfigurationList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: List of MutatingWebhookConfiguration. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - ''' - props = KubeMutatingWebhookConfigurationListProps( - items=items, metadata=metadata - ) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.admissionregistration.v1.MutatingWebhookConfigurationList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeMutatingWebhookConfigurationListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeMutatingWebhookConfigurationListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeMutatingWebhookConfigurationProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''MutatingWebhookConfigurationList is a list of MutatingWebhookConfiguration. - - :param items: List of MutatingWebhookConfiguration. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.admissionregistration.v1.MutatingWebhookConfigurationList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__1c5bb2cd72caaf431cbf1350e28d2e0bcdd4dbf8a7a42278e8f2bea99bf5e665) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeMutatingWebhookConfigurationProps"]: - '''List of MutatingWebhookConfiguration. - - :schema: io.k8s.api.admissionregistration.v1.MutatingWebhookConfigurationList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeMutatingWebhookConfigurationProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.admissionregistration.v1.MutatingWebhookConfigurationList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeMutatingWebhookConfigurationListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubeMutatingWebhookConfigurationProps", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata", "webhooks": "webhooks"}, -) -class KubeMutatingWebhookConfigurationProps: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - webhooks: typing.Optional[typing.Sequence[typing.Union["MutatingWebhook", typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''MutatingWebhookConfiguration describes the configuration of and admission webhook that accept or reject and may change the object. - - :param metadata: Standard object metadata; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - :param webhooks: Webhooks is a list of webhooks and the affected resources and operations. - - :schema: io.k8s.api.admissionregistration.v1.MutatingWebhookConfiguration - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__dcc8f1c51a09b8fe278a8bee5d20fb75c30d888189811d6a2f4a60c0182384cf) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument webhooks", value=webhooks, expected_type=type_hints["webhooks"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - if webhooks is not None: - self._values["webhooks"] = webhooks - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object metadata; - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - - :schema: io.k8s.api.admissionregistration.v1.MutatingWebhookConfiguration#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def webhooks(self) -> typing.Optional[typing.List["MutatingWebhook"]]: - '''Webhooks is a list of webhooks and the affected resources and operations. - - :schema: io.k8s.api.admissionregistration.v1.MutatingWebhookConfiguration#webhooks - ''' - result = self._values.get("webhooks") - return typing.cast(typing.Optional[typing.List["MutatingWebhook"]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeMutatingWebhookConfigurationProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeNamespace( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeNamespace", -): - '''Namespace provides a scope for Names. - - Use of multiple namespaces is optional. - - :schema: io.k8s.api.core.v1.Namespace - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["NamespaceSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.core.v1.Namespace" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Spec defines the behavior of the Namespace. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__6f6e25823687f32bbbae9c3f609a0a538b76fedf96c8ad3f980c332a61ece4d7) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeNamespaceProps(metadata=metadata, spec=spec) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["NamespaceSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.core.v1.Namespace". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Spec defines the behavior of the Namespace. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - ''' - props = KubeNamespaceProps(metadata=metadata, spec=spec) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.core.v1.Namespace".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubeNamespaceList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeNamespaceList", -): - '''NamespaceList is a list of Namespaces. - - :schema: io.k8s.api.core.v1.NamespaceList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeNamespaceProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.core.v1.NamespaceList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: Items is the list of Namespace objects in the list. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__01d5f81c2dc4b588166fb78ad26a95dd96f084900df60db1eef3c086859371cc) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeNamespaceListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeNamespaceProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.core.v1.NamespaceList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: Items is the list of Namespace objects in the list. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - ''' - props = KubeNamespaceListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.core.v1.NamespaceList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeNamespaceListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeNamespaceListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeNamespaceProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''NamespaceList is a list of Namespaces. - - :param items: Items is the list of Namespace objects in the list. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.core.v1.NamespaceList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__ce390ce5e8435afb3fcc00c620b42a1bcc0f105b5ece6671255dfd268155ef06) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeNamespaceProps"]: - '''Items is the list of Namespace objects in the list. - - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ - - :schema: io.k8s.api.core.v1.NamespaceList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeNamespaceProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.core.v1.NamespaceList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeNamespaceListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubeNamespaceProps", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata", "spec": "spec"}, -) -class KubeNamespaceProps: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["NamespaceSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Namespace provides a scope for Names. - - Use of multiple namespaces is optional. - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Spec defines the behavior of the Namespace. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.core.v1.Namespace - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if isinstance(spec, dict): - spec = NamespaceSpec(**spec) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__e949e610104e12f08b92fa062a63801c86734b9c1a875a1871c872376e5f48f5) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - if spec is not None: - self._values["spec"] = spec - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.core.v1.Namespace#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def spec(self) -> typing.Optional["NamespaceSpec"]: - '''Spec defines the behavior of the Namespace. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.core.v1.Namespace#spec - ''' - result = self._values.get("spec") - return typing.cast(typing.Optional["NamespaceSpec"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeNamespaceProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeNetworkPolicy( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeNetworkPolicy", -): - '''NetworkPolicy describes what network traffic is allowed for a set of Pods. - - :schema: io.k8s.api.networking.v1.NetworkPolicy - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["NetworkPolicySpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.networking.v1.NetworkPolicy" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Specification of the desired behavior for this NetworkPolicy. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__3711bfdbb9ff2b20fcc1d837ff64f7be94291bbcbda2f8e20d3fe735d0fca788) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeNetworkPolicyProps(metadata=metadata, spec=spec) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["NetworkPolicySpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.networking.v1.NetworkPolicy". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Specification of the desired behavior for this NetworkPolicy. - ''' - props = KubeNetworkPolicyProps(metadata=metadata, spec=spec) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.networking.v1.NetworkPolicy".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubeNetworkPolicyList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeNetworkPolicyList", -): - '''NetworkPolicyList is a list of NetworkPolicy objects. - - :schema: io.k8s.api.networking.v1.NetworkPolicyList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeNetworkPolicyProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.networking.v1.NetworkPolicyList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: Items is a list of schema objects. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__00430867067236e8cdbeb77ac9ba9e262f12d9a45a20172656a49f0096a6a0fa) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeNetworkPolicyListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeNetworkPolicyProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.networking.v1.NetworkPolicyList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: Items is a list of schema objects. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - props = KubeNetworkPolicyListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.networking.v1.NetworkPolicyList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeNetworkPolicyListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeNetworkPolicyListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeNetworkPolicyProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''NetworkPolicyList is a list of NetworkPolicy objects. - - :param items: Items is a list of schema objects. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.networking.v1.NetworkPolicyList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__b302db7bf53a96dc070815693c9fbbe25197993b09e83ed216e2ab04dea04a7c) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeNetworkPolicyProps"]: - '''Items is a list of schema objects. - - :schema: io.k8s.api.networking.v1.NetworkPolicyList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeNetworkPolicyProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.networking.v1.NetworkPolicyList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeNetworkPolicyListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubeNetworkPolicyProps", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata", "spec": "spec"}, -) -class KubeNetworkPolicyProps: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["NetworkPolicySpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''NetworkPolicy describes what network traffic is allowed for a set of Pods. - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Specification of the desired behavior for this NetworkPolicy. - - :schema: io.k8s.api.networking.v1.NetworkPolicy - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if isinstance(spec, dict): - spec = NetworkPolicySpec(**spec) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__56f98657e1b111a4046c2a9c0419040c502cc5aa1a89c7cf31c45f390c9d36f6) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - if spec is not None: - self._values["spec"] = spec - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.networking.v1.NetworkPolicy#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def spec(self) -> typing.Optional["NetworkPolicySpec"]: - '''Specification of the desired behavior for this NetworkPolicy. - - :schema: io.k8s.api.networking.v1.NetworkPolicy#spec - ''' - result = self._values.get("spec") - return typing.cast(typing.Optional["NetworkPolicySpec"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeNetworkPolicyProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeNode( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeNode", -): - '''Node is a worker node in Kubernetes. - - Each node will have a unique identifier in the cache (i.e. in etcd). - - :schema: io.k8s.api.core.v1.Node - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["NodeSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.core.v1.Node" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Spec defines the behavior of a node. https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__9d26fbe2f6299bf5a92f7395765819856b261fc03eda02a9a56f93d5b7387ad9) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeNodeProps(metadata=metadata, spec=spec) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["NodeSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.core.v1.Node". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Spec defines the behavior of a node. https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - ''' - props = KubeNodeProps(metadata=metadata, spec=spec) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.core.v1.Node".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubeNodeList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeNodeList", -): - '''NodeList is the whole list of all Nodes which have been registered with master. - - :schema: io.k8s.api.core.v1.NodeList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeNodeProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.core.v1.NodeList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: List of nodes. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__8f7dc24543b0e86588c1d33f101b19fbd515d5284e141acd3821411e47509e33) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeNodeListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeNodeProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.core.v1.NodeList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: List of nodes. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - ''' - props = KubeNodeListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.core.v1.NodeList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeNodeListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeNodeListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeNodeProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''NodeList is the whole list of all Nodes which have been registered with master. - - :param items: List of nodes. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.core.v1.NodeList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__5390372ece82529262be3baed0dd084e87300d8b0e3a8999ebe4dde860bbc9d5) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeNodeProps"]: - '''List of nodes. - - :schema: io.k8s.api.core.v1.NodeList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeNodeProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.core.v1.NodeList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeNodeListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubeNodeProps", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata", "spec": "spec"}, -) -class KubeNodeProps: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["NodeSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Node is a worker node in Kubernetes. - - Each node will have a unique identifier in the cache (i.e. in etcd). - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Spec defines the behavior of a node. https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.core.v1.Node - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if isinstance(spec, dict): - spec = NodeSpec(**spec) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__8da3066966e9bc82c9130ec84a7522be8c5dadb42ba10b9448c9336ca5c791b4) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - if spec is not None: - self._values["spec"] = spec - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.core.v1.Node#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def spec(self) -> typing.Optional["NodeSpec"]: - '''Spec defines the behavior of a node. - - https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.core.v1.Node#spec - ''' - result = self._values.get("spec") - return typing.cast(typing.Optional["NodeSpec"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeNodeProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubePersistentVolume( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubePersistentVolume", -): - '''PersistentVolume (PV) is a storage resource provisioned by an administrator. - - It is analogous to a node. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes - - :schema: io.k8s.api.core.v1.PersistentVolume - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["PersistentVolumeSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.core.v1.PersistentVolume" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: spec defines a specification of a persistent volume owned by the cluster. Provisioned by an administrator. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistent-volumes - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__12bf57b692f7f69fdce50d1cd90aee7dac0c22bd6db1ac7fcdfc312a4655c48f) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubePersistentVolumeProps(metadata=metadata, spec=spec) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["PersistentVolumeSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.core.v1.PersistentVolume". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: spec defines a specification of a persistent volume owned by the cluster. Provisioned by an administrator. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistent-volumes - ''' - props = KubePersistentVolumeProps(metadata=metadata, spec=spec) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.core.v1.PersistentVolume".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubePersistentVolumeClaim( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubePersistentVolumeClaim", -): - '''PersistentVolumeClaim is a user's request for and claim to a persistent volume. - - :schema: io.k8s.api.core.v1.PersistentVolumeClaim - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["PersistentVolumeClaimSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.core.v1.PersistentVolumeClaim" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: spec defines the desired characteristics of a volume requested by a pod author. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__52de231eda8f9efad578bfd47588cd714011f8b2ef9871fb4aa8ea7d11990c24) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubePersistentVolumeClaimProps(metadata=metadata, spec=spec) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["PersistentVolumeClaimSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.core.v1.PersistentVolumeClaim". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: spec defines the desired characteristics of a volume requested by a pod author. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - ''' - props = KubePersistentVolumeClaimProps(metadata=metadata, spec=spec) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.core.v1.PersistentVolumeClaim".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubePersistentVolumeClaimList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubePersistentVolumeClaimList", -): - '''PersistentVolumeClaimList is a list of PersistentVolumeClaim items. - - :schema: io.k8s.api.core.v1.PersistentVolumeClaimList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubePersistentVolumeClaimProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.core.v1.PersistentVolumeClaimList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: items is a list of persistent volume claims. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__715fd5e65023048e75b48ea598d1ac99e0a7d2546108f2b88ab23ec45963900b) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubePersistentVolumeClaimListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubePersistentVolumeClaimProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.core.v1.PersistentVolumeClaimList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: items is a list of persistent volume claims. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - ''' - props = KubePersistentVolumeClaimListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.core.v1.PersistentVolumeClaimList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubePersistentVolumeClaimListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubePersistentVolumeClaimListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubePersistentVolumeClaimProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''PersistentVolumeClaimList is a list of PersistentVolumeClaim items. - - :param items: items is a list of persistent volume claims. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.core.v1.PersistentVolumeClaimList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__fcb84271af780f85ce85f44dfbd05476e40e28da01cc541644af7cc50e317760) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubePersistentVolumeClaimProps"]: - '''items is a list of persistent volume claims. - - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - - :schema: io.k8s.api.core.v1.PersistentVolumeClaimList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubePersistentVolumeClaimProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.core.v1.PersistentVolumeClaimList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubePersistentVolumeClaimListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubePersistentVolumeClaimProps", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata", "spec": "spec"}, -) -class KubePersistentVolumeClaimProps: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["PersistentVolumeClaimSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''PersistentVolumeClaim is a user's request for and claim to a persistent volume. - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: spec defines the desired characteristics of a volume requested by a pod author. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - - :schema: io.k8s.api.core.v1.PersistentVolumeClaim - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if isinstance(spec, dict): - spec = PersistentVolumeClaimSpec(**spec) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__b414219b4cd98868a08f6b7fd13ba03bb20c34f93bab1c6766671850b87da5ba) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - if spec is not None: - self._values["spec"] = spec - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.core.v1.PersistentVolumeClaim#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def spec(self) -> typing.Optional["PersistentVolumeClaimSpec"]: - '''spec defines the desired characteristics of a volume requested by a pod author. - - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - - :schema: io.k8s.api.core.v1.PersistentVolumeClaim#spec - ''' - result = self._values.get("spec") - return typing.cast(typing.Optional["PersistentVolumeClaimSpec"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubePersistentVolumeClaimProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubePersistentVolumeList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubePersistentVolumeList", -): - '''PersistentVolumeList is a list of PersistentVolume items. - - :schema: io.k8s.api.core.v1.PersistentVolumeList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubePersistentVolumeProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.core.v1.PersistentVolumeList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: items is a list of persistent volumes. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__20543683b7b15c750805ae3b00ee8120f78f9aefc5d6360da9191b713c8a3df9) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubePersistentVolumeListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubePersistentVolumeProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.core.v1.PersistentVolumeList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: items is a list of persistent volumes. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - ''' - props = KubePersistentVolumeListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.core.v1.PersistentVolumeList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubePersistentVolumeListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubePersistentVolumeListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubePersistentVolumeProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''PersistentVolumeList is a list of PersistentVolume items. - - :param items: items is a list of persistent volumes. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.core.v1.PersistentVolumeList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__edf32a684938145a8c425ea13a1f6c2a5251323dae13a0c7266e5144002b58ea) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubePersistentVolumeProps"]: - '''items is a list of persistent volumes. - - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes - - :schema: io.k8s.api.core.v1.PersistentVolumeList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubePersistentVolumeProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.core.v1.PersistentVolumeList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubePersistentVolumeListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubePersistentVolumeProps", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata", "spec": "spec"}, -) -class KubePersistentVolumeProps: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["PersistentVolumeSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''PersistentVolume (PV) is a storage resource provisioned by an administrator. - - It is analogous to a node. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: spec defines a specification of a persistent volume owned by the cluster. Provisioned by an administrator. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistent-volumes - - :schema: io.k8s.api.core.v1.PersistentVolume - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if isinstance(spec, dict): - spec = PersistentVolumeSpec(**spec) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__b6dbdf4915f5c3999c02319ddabd6bc2300a3ec520d35a7124154a1d0c74b284) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - if spec is not None: - self._values["spec"] = spec - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.core.v1.PersistentVolume#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def spec(self) -> typing.Optional["PersistentVolumeSpec"]: - '''spec defines a specification of a persistent volume owned by the cluster. - - Provisioned by an administrator. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistent-volumes - - :schema: io.k8s.api.core.v1.PersistentVolume#spec - ''' - result = self._values.get("spec") - return typing.cast(typing.Optional["PersistentVolumeSpec"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubePersistentVolumeProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubePod( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubePod", -): - '''Pod is a collection of containers that can run on a host. - - This resource is created by clients and scheduled onto hosts. - - :schema: io.k8s.api.core.v1.Pod - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["PodSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.core.v1.Pod" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Specification of the desired behavior of the pod. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__84a44a2c055874076c014e7b070891672ce45fae07fc36b0223efb3b157db547) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubePodProps(metadata=metadata, spec=spec) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["PodSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.core.v1.Pod". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Specification of the desired behavior of the pod. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - ''' - props = KubePodProps(metadata=metadata, spec=spec) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.core.v1.Pod".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubePodDisruptionBudget( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubePodDisruptionBudget", -): - '''PodDisruptionBudget is an object to define the max disruption that can be caused to a collection of pods. - - :schema: io.k8s.api.policy.v1.PodDisruptionBudget - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["PodDisruptionBudgetSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.policy.v1.PodDisruptionBudget" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Specification of the desired behavior of the PodDisruptionBudget. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__a57adcbd50267ff3f43029f0497ba1eecdf3774ae3544c7d0d200eb6af32af47) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubePodDisruptionBudgetProps(metadata=metadata, spec=spec) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["PodDisruptionBudgetSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.policy.v1.PodDisruptionBudget". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Specification of the desired behavior of the PodDisruptionBudget. - ''' - props = KubePodDisruptionBudgetProps(metadata=metadata, spec=spec) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.policy.v1.PodDisruptionBudget".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubePodDisruptionBudgetList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubePodDisruptionBudgetList", -): - '''PodDisruptionBudgetList is a collection of PodDisruptionBudgets. - - :schema: io.k8s.api.policy.v1.PodDisruptionBudgetList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubePodDisruptionBudgetProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.policy.v1.PodDisruptionBudgetList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: Items is a list of PodDisruptionBudgets. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__5b28042f5f757861077d829159ace796645ed62a098c4b7445cc49d65bae4e39) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubePodDisruptionBudgetListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubePodDisruptionBudgetProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.policy.v1.PodDisruptionBudgetList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: Items is a list of PodDisruptionBudgets. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - props = KubePodDisruptionBudgetListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.policy.v1.PodDisruptionBudgetList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubePodDisruptionBudgetListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubePodDisruptionBudgetListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubePodDisruptionBudgetProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''PodDisruptionBudgetList is a collection of PodDisruptionBudgets. - - :param items: Items is a list of PodDisruptionBudgets. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.policy.v1.PodDisruptionBudgetList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__46fe8577d9d9bc235b20f9635bed1bb38c4182635cbbbd4f777b9ecddafd24d4) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubePodDisruptionBudgetProps"]: - '''Items is a list of PodDisruptionBudgets. - - :schema: io.k8s.api.policy.v1.PodDisruptionBudgetList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubePodDisruptionBudgetProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.policy.v1.PodDisruptionBudgetList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubePodDisruptionBudgetListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubePodDisruptionBudgetProps", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata", "spec": "spec"}, -) -class KubePodDisruptionBudgetProps: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["PodDisruptionBudgetSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''PodDisruptionBudget is an object to define the max disruption that can be caused to a collection of pods. - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Specification of the desired behavior of the PodDisruptionBudget. - - :schema: io.k8s.api.policy.v1.PodDisruptionBudget - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if isinstance(spec, dict): - spec = PodDisruptionBudgetSpec(**spec) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__bb3fa1126b3b2249e66d034d2cb0c2af262892c5e513cb56fa7071cbf1f323b4) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - if spec is not None: - self._values["spec"] = spec - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.policy.v1.PodDisruptionBudget#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def spec(self) -> typing.Optional["PodDisruptionBudgetSpec"]: - '''Specification of the desired behavior of the PodDisruptionBudget. - - :schema: io.k8s.api.policy.v1.PodDisruptionBudget#spec - ''' - result = self._values.get("spec") - return typing.cast(typing.Optional["PodDisruptionBudgetSpec"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubePodDisruptionBudgetProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubePodList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubePodList", -): - '''PodList is a list of Pods. - - :schema: io.k8s.api.core.v1.PodList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubePodProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.core.v1.PodList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: List of pods. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__26810161725b72ec95fed518f5f1bd2878189eec88948e1665c6504f0e1c80e4) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubePodListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubePodProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.core.v1.PodList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: List of pods. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - ''' - props = KubePodListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.core.v1.PodList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubePodListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubePodListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubePodProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''PodList is a list of Pods. - - :param items: List of pods. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.core.v1.PodList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__6c6da0c93bfd87422fec0434260e7ca746775802e283035b82a97804b6a5cbad) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubePodProps"]: - '''List of pods. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md - - :schema: io.k8s.api.core.v1.PodList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubePodProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.core.v1.PodList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubePodListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubePodProps", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata", "spec": "spec"}, -) -class KubePodProps: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["PodSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Pod is a collection of containers that can run on a host. - - This resource is created by clients and scheduled onto hosts. - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Specification of the desired behavior of the pod. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.core.v1.Pod - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if isinstance(spec, dict): - spec = PodSpec(**spec) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__a49e5de6a1c7d64f87b3fd99f6f3a7f9173827eb846d6b3423f251cc8e6dee73) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - if spec is not None: - self._values["spec"] = spec - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.core.v1.Pod#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def spec(self) -> typing.Optional["PodSpec"]: - '''Specification of the desired behavior of the pod. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.core.v1.Pod#spec - ''' - result = self._values.get("spec") - return typing.cast(typing.Optional["PodSpec"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubePodProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubePodSchedulingListV1Alpha1( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubePodSchedulingListV1Alpha1", -): - '''PodSchedulingList is a collection of Pod scheduling objects. - - :schema: io.k8s.api.resource.v1alpha1.PodSchedulingList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubePodSchedulingV1Alpha1Props", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.resource.v1alpha1.PodSchedulingList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: Items is the list of PodScheduling objects. - :param metadata: Standard list metadata. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__ca5c307c4cf8c1a6abfe2594c184c4510f1f094dbb431db9ed4c05139b0636a3) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubePodSchedulingListV1Alpha1Props(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubePodSchedulingV1Alpha1Props", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.resource.v1alpha1.PodSchedulingList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: Items is the list of PodScheduling objects. - :param metadata: Standard list metadata. - ''' - props = KubePodSchedulingListV1Alpha1Props(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.resource.v1alpha1.PodSchedulingList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubePodSchedulingListV1Alpha1Props", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubePodSchedulingListV1Alpha1Props: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubePodSchedulingV1Alpha1Props", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''PodSchedulingList is a collection of Pod scheduling objects. - - :param items: Items is the list of PodScheduling objects. - :param metadata: Standard list metadata. - - :schema: io.k8s.api.resource.v1alpha1.PodSchedulingList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__7a3f9f9a13fab7ad4309606460387114d09f26fe708e57d0ade367760eba22d4) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubePodSchedulingV1Alpha1Props"]: - '''Items is the list of PodScheduling objects. - - :schema: io.k8s.api.resource.v1alpha1.PodSchedulingList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubePodSchedulingV1Alpha1Props"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata. - - :schema: io.k8s.api.resource.v1alpha1.PodSchedulingList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubePodSchedulingListV1Alpha1Props(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubePodSchedulingV1Alpha1( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubePodSchedulingV1Alpha1", -): - '''PodScheduling objects hold information that is needed to schedule a Pod with ResourceClaims that use "WaitForFirstConsumer" allocation mode. - - This is an alpha type and requires enabling the DynamicResourceAllocation feature gate. - - :schema: io.k8s.api.resource.v1alpha1.PodScheduling - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - spec: typing.Union["PodSchedulingSpecV1Alpha1", typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.resource.v1alpha1.PodScheduling" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param spec: Spec describes where resources for the Pod are needed. - :param metadata: Standard object metadata. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__3f4856868eca18e4ac926608e85a1bc5de5344771a17d102cda0ca44b4a61ee2) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubePodSchedulingV1Alpha1Props(spec=spec, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - spec: typing.Union["PodSchedulingSpecV1Alpha1", typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.resource.v1alpha1.PodScheduling". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param spec: Spec describes where resources for the Pod are needed. - :param metadata: Standard object metadata. - ''' - props = KubePodSchedulingV1Alpha1Props(spec=spec, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.resource.v1alpha1.PodScheduling".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubePodSchedulingV1Alpha1Props", - jsii_struct_bases=[], - name_mapping={"spec": "spec", "metadata": "metadata"}, -) -class KubePodSchedulingV1Alpha1Props: - def __init__( - self, - *, - spec: typing.Union["PodSchedulingSpecV1Alpha1", typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''PodScheduling objects hold information that is needed to schedule a Pod with ResourceClaims that use "WaitForFirstConsumer" allocation mode. - - This is an alpha type and requires enabling the DynamicResourceAllocation feature gate. - - :param spec: Spec describes where resources for the Pod are needed. - :param metadata: Standard object metadata. - - :schema: io.k8s.api.resource.v1alpha1.PodScheduling - ''' - if isinstance(spec, dict): - spec = PodSchedulingSpecV1Alpha1(**spec) - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__b8378dcaf5913bb1f58986bd024042b8cd1b3448b4c03b331937a17870ffaac0) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "spec": spec, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def spec(self) -> "PodSchedulingSpecV1Alpha1": - '''Spec describes where resources for the Pod are needed. - - :schema: io.k8s.api.resource.v1alpha1.PodScheduling#spec - ''' - result = self._values.get("spec") - assert result is not None, "Required property 'spec' is missing" - return typing.cast("PodSchedulingSpecV1Alpha1", result) - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object metadata. - - :schema: io.k8s.api.resource.v1alpha1.PodScheduling#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubePodSchedulingV1Alpha1Props(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubePodTemplate( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubePodTemplate", -): - '''PodTemplate describes a template for creating copies of a predefined pod. - - :schema: io.k8s.api.core.v1.PodTemplate - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - template: typing.Optional[typing.Union["PodTemplateSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.core.v1.PodTemplate" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param template: Template defines the pods that will be created from this pod template. https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__0ef25d47e407a94a1f7c5da1b4a8137999b9f10f2eb06612819328e43413ecaa) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubePodTemplateProps(metadata=metadata, template=template) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - template: typing.Optional[typing.Union["PodTemplateSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.core.v1.PodTemplate". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param template: Template defines the pods that will be created from this pod template. https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - ''' - props = KubePodTemplateProps(metadata=metadata, template=template) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.core.v1.PodTemplate".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubePodTemplateList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubePodTemplateList", -): - '''PodTemplateList is a list of PodTemplates. - - :schema: io.k8s.api.core.v1.PodTemplateList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubePodTemplateProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.core.v1.PodTemplateList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: List of pod templates. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__e1a00fe17edb33a47aa58d4b3bdf326f8cd52b6c5fa5b4b447fef63416e0153a) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubePodTemplateListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubePodTemplateProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.core.v1.PodTemplateList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: List of pod templates. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - ''' - props = KubePodTemplateListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.core.v1.PodTemplateList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubePodTemplateListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubePodTemplateListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubePodTemplateProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''PodTemplateList is a list of PodTemplates. - - :param items: List of pod templates. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.core.v1.PodTemplateList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__db699f3f7785aaafe421c68826e9aee0751d2471a5f84fcd072d2dc7bf1e42f6) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubePodTemplateProps"]: - '''List of pod templates. - - :schema: io.k8s.api.core.v1.PodTemplateList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubePodTemplateProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.core.v1.PodTemplateList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubePodTemplateListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubePodTemplateProps", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata", "template": "template"}, -) -class KubePodTemplateProps: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - template: typing.Optional[typing.Union["PodTemplateSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''PodTemplate describes a template for creating copies of a predefined pod. - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param template: Template defines the pods that will be created from this pod template. https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.core.v1.PodTemplate - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if isinstance(template, dict): - template = PodTemplateSpec(**template) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__b1246c731572d1c19b516cbd1928d932af12c395562d89193038a193dc8c19d6) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument template", value=template, expected_type=type_hints["template"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - if template is not None: - self._values["template"] = template - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.core.v1.PodTemplate#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def template(self) -> typing.Optional["PodTemplateSpec"]: - '''Template defines the pods that will be created from this pod template. - - https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.core.v1.PodTemplate#template - ''' - result = self._values.get("template") - return typing.cast(typing.Optional["PodTemplateSpec"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubePodTemplateProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubePriorityClass( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubePriorityClass", -): - '''PriorityClass defines mapping from a priority class name to the priority integer value. - - The value can be any valid integer. - - :schema: io.k8s.api.scheduling.v1.PriorityClass - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - value: jsii.Number, - description: typing.Optional[builtins.str] = None, - global_default: typing.Optional[builtins.bool] = None, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - preemption_policy: typing.Optional[builtins.str] = None, - ) -> None: - '''Defines a "io.k8s.api.scheduling.v1.PriorityClass" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param value: The value of this priority class. This is the actual priority that pods receive when they have the name of this class in their pod spec. - :param description: description is an arbitrary string that usually provides guidelines on when this priority class should be used. - :param global_default: globalDefault specifies whether this PriorityClass should be considered as the default priority for pods that do not have any priority class. Only one PriorityClass can be marked as ``globalDefault``. However, if more than one PriorityClasses exists with their ``globalDefault`` field set to true, the smallest value of such global default PriorityClasses will be used as the default priority. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param preemption_policy: PreemptionPolicy is the Policy for preempting pods with lower priority. One of Never, PreemptLowerPriority. Defaults to PreemptLowerPriority if unset. Default: PreemptLowerPriority if unset. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__7849121f7cc4169719bf7c0334ed5b358df3185c443cdcca26f3ba64a177342f) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubePriorityClassProps( - value=value, - description=description, - global_default=global_default, - metadata=metadata, - preemption_policy=preemption_policy, - ) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - value: jsii.Number, - description: typing.Optional[builtins.str] = None, - global_default: typing.Optional[builtins.bool] = None, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - preemption_policy: typing.Optional[builtins.str] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.scheduling.v1.PriorityClass". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param value: The value of this priority class. This is the actual priority that pods receive when they have the name of this class in their pod spec. - :param description: description is an arbitrary string that usually provides guidelines on when this priority class should be used. - :param global_default: globalDefault specifies whether this PriorityClass should be considered as the default priority for pods that do not have any priority class. Only one PriorityClass can be marked as ``globalDefault``. However, if more than one PriorityClasses exists with their ``globalDefault`` field set to true, the smallest value of such global default PriorityClasses will be used as the default priority. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param preemption_policy: PreemptionPolicy is the Policy for preempting pods with lower priority. One of Never, PreemptLowerPriority. Defaults to PreemptLowerPriority if unset. Default: PreemptLowerPriority if unset. - ''' - props = KubePriorityClassProps( - value=value, - description=description, - global_default=global_default, - metadata=metadata, - preemption_policy=preemption_policy, - ) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.scheduling.v1.PriorityClass".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubePriorityClassList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubePriorityClassList", -): - '''PriorityClassList is a collection of priority classes. - - :schema: io.k8s.api.scheduling.v1.PriorityClassList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubePriorityClassProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.scheduling.v1.PriorityClassList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: items is the list of PriorityClasses. - :param metadata: Standard list metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__925536e8f6c1bb4cef79d5881b407f57c20a6380415cbaf45a82301ab03c453c) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubePriorityClassListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubePriorityClassProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.scheduling.v1.PriorityClassList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: items is the list of PriorityClasses. - :param metadata: Standard list metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - ''' - props = KubePriorityClassListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.scheduling.v1.PriorityClassList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubePriorityClassListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubePriorityClassListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubePriorityClassProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''PriorityClassList is a collection of priority classes. - - :param items: items is the list of PriorityClasses. - :param metadata: Standard list metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - - :schema: io.k8s.api.scheduling.v1.PriorityClassList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__00e2a2b2d5dd902a6c32a404e9c7208d7bfc775f9ade4170dc45106963c0b49b) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubePriorityClassProps"]: - '''items is the list of PriorityClasses. - - :schema: io.k8s.api.scheduling.v1.PriorityClassList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubePriorityClassProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - - :schema: io.k8s.api.scheduling.v1.PriorityClassList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubePriorityClassListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubePriorityClassProps", - jsii_struct_bases=[], - name_mapping={ - "value": "value", - "description": "description", - "global_default": "globalDefault", - "metadata": "metadata", - "preemption_policy": "preemptionPolicy", - }, -) -class KubePriorityClassProps: - def __init__( - self, - *, - value: jsii.Number, - description: typing.Optional[builtins.str] = None, - global_default: typing.Optional[builtins.bool] = None, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - preemption_policy: typing.Optional[builtins.str] = None, - ) -> None: - '''PriorityClass defines mapping from a priority class name to the priority integer value. - - The value can be any valid integer. - - :param value: The value of this priority class. This is the actual priority that pods receive when they have the name of this class in their pod spec. - :param description: description is an arbitrary string that usually provides guidelines on when this priority class should be used. - :param global_default: globalDefault specifies whether this PriorityClass should be considered as the default priority for pods that do not have any priority class. Only one PriorityClass can be marked as ``globalDefault``. However, if more than one PriorityClasses exists with their ``globalDefault`` field set to true, the smallest value of such global default PriorityClasses will be used as the default priority. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param preemption_policy: PreemptionPolicy is the Policy for preempting pods with lower priority. One of Never, PreemptLowerPriority. Defaults to PreemptLowerPriority if unset. Default: PreemptLowerPriority if unset. - - :schema: io.k8s.api.scheduling.v1.PriorityClass - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__d2a7a0f6e62dd93fbc211f3259e5bdec03162b72d41924ec9b0431446407d338) - check_type(argname="argument value", value=value, expected_type=type_hints["value"]) - check_type(argname="argument description", value=description, expected_type=type_hints["description"]) - check_type(argname="argument global_default", value=global_default, expected_type=type_hints["global_default"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument preemption_policy", value=preemption_policy, expected_type=type_hints["preemption_policy"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "value": value, - } - if description is not None: - self._values["description"] = description - if global_default is not None: - self._values["global_default"] = global_default - if metadata is not None: - self._values["metadata"] = metadata - if preemption_policy is not None: - self._values["preemption_policy"] = preemption_policy - - @builtins.property - def value(self) -> jsii.Number: - '''The value of this priority class. - - This is the actual priority that pods receive when they have the name of this class in their pod spec. - - :schema: io.k8s.api.scheduling.v1.PriorityClass#value - ''' - result = self._values.get("value") - assert result is not None, "Required property 'value' is missing" - return typing.cast(jsii.Number, result) - - @builtins.property - def description(self) -> typing.Optional[builtins.str]: - '''description is an arbitrary string that usually provides guidelines on when this priority class should be used. - - :schema: io.k8s.api.scheduling.v1.PriorityClass#description - ''' - result = self._values.get("description") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def global_default(self) -> typing.Optional[builtins.bool]: - '''globalDefault specifies whether this PriorityClass should be considered as the default priority for pods that do not have any priority class. - - Only one PriorityClass can be marked as ``globalDefault``. However, if more than one PriorityClasses exists with their ``globalDefault`` field set to true, the smallest value of such global default PriorityClasses will be used as the default priority. - - :schema: io.k8s.api.scheduling.v1.PriorityClass#globalDefault - ''' - result = self._values.get("global_default") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.scheduling.v1.PriorityClass#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def preemption_policy(self) -> typing.Optional[builtins.str]: - '''PreemptionPolicy is the Policy for preempting pods with lower priority. - - One of Never, PreemptLowerPriority. Defaults to PreemptLowerPriority if unset. - - :default: PreemptLowerPriority if unset. - - :schema: io.k8s.api.scheduling.v1.PriorityClass#preemptionPolicy - ''' - result = self._values.get("preemption_policy") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubePriorityClassProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubePriorityLevelConfigurationListV1Beta2( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubePriorityLevelConfigurationListV1Beta2", -): - '''PriorityLevelConfigurationList is a list of PriorityLevelConfiguration objects. - - :schema: io.k8s.api.flowcontrol.v1beta2.PriorityLevelConfigurationList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubePriorityLevelConfigurationV1Beta2Props", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.flowcontrol.v1beta2.PriorityLevelConfigurationList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: ``items`` is a list of request-priorities. - :param metadata: ``metadata`` is the standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__b037d843ce4cd847a493957e491386d8281a274d20cb7ecfd13937547ca54046) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubePriorityLevelConfigurationListV1Beta2Props( - items=items, metadata=metadata - ) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubePriorityLevelConfigurationV1Beta2Props", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.flowcontrol.v1beta2.PriorityLevelConfigurationList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: ``items`` is a list of request-priorities. - :param metadata: ``metadata`` is the standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - props = KubePriorityLevelConfigurationListV1Beta2Props( - items=items, metadata=metadata - ) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.flowcontrol.v1beta2.PriorityLevelConfigurationList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubePriorityLevelConfigurationListV1Beta2Props", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubePriorityLevelConfigurationListV1Beta2Props: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubePriorityLevelConfigurationV1Beta2Props", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''PriorityLevelConfigurationList is a list of PriorityLevelConfiguration objects. - - :param items: ``items`` is a list of request-priorities. - :param metadata: ``metadata`` is the standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.flowcontrol.v1beta2.PriorityLevelConfigurationList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__a6a9dc2a0db58fcbfb69d80748f76fed9e1834c5756fcc6381cf1cbb86af3654) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubePriorityLevelConfigurationV1Beta2Props"]: - '''``items`` is a list of request-priorities. - - :schema: io.k8s.api.flowcontrol.v1beta2.PriorityLevelConfigurationList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubePriorityLevelConfigurationV1Beta2Props"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''``metadata`` is the standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.flowcontrol.v1beta2.PriorityLevelConfigurationList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubePriorityLevelConfigurationListV1Beta2Props(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubePriorityLevelConfigurationListV1Beta3( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubePriorityLevelConfigurationListV1Beta3", -): - '''PriorityLevelConfigurationList is a list of PriorityLevelConfiguration objects. - - :schema: io.k8s.api.flowcontrol.v1beta3.PriorityLevelConfigurationList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubePriorityLevelConfigurationV1Beta3Props", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.flowcontrol.v1beta3.PriorityLevelConfigurationList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: ``items`` is a list of request-priorities. - :param metadata: ``metadata`` is the standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__64fe405e3b84d29190baf774ed90a32c12ed6a17a342bae6b6bb18c8e57ca058) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubePriorityLevelConfigurationListV1Beta3Props( - items=items, metadata=metadata - ) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubePriorityLevelConfigurationV1Beta3Props", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.flowcontrol.v1beta3.PriorityLevelConfigurationList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: ``items`` is a list of request-priorities. - :param metadata: ``metadata`` is the standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - props = KubePriorityLevelConfigurationListV1Beta3Props( - items=items, metadata=metadata - ) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.flowcontrol.v1beta3.PriorityLevelConfigurationList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubePriorityLevelConfigurationListV1Beta3Props", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubePriorityLevelConfigurationListV1Beta3Props: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubePriorityLevelConfigurationV1Beta3Props", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''PriorityLevelConfigurationList is a list of PriorityLevelConfiguration objects. - - :param items: ``items`` is a list of request-priorities. - :param metadata: ``metadata`` is the standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.flowcontrol.v1beta3.PriorityLevelConfigurationList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__8a9a2b4f57da24e68294448c136ed1b7f46757a2e39eb80d97db30d3fae1887e) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubePriorityLevelConfigurationV1Beta3Props"]: - '''``items`` is a list of request-priorities. - - :schema: io.k8s.api.flowcontrol.v1beta3.PriorityLevelConfigurationList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubePriorityLevelConfigurationV1Beta3Props"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''``metadata`` is the standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.flowcontrol.v1beta3.PriorityLevelConfigurationList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubePriorityLevelConfigurationListV1Beta3Props(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubePriorityLevelConfigurationV1Beta2( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubePriorityLevelConfigurationV1Beta2", -): - '''PriorityLevelConfiguration represents the configuration of a priority level. - - :schema: io.k8s.api.flowcontrol.v1beta2.PriorityLevelConfiguration - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["PriorityLevelConfigurationSpecV1Beta2", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.flowcontrol.v1beta2.PriorityLevelConfiguration" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param metadata: ``metadata`` is the standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: ``spec`` is the specification of the desired behavior of a "request-priority". More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__a6c55383ef965654b933b8b84cb96236498acefe9c7f0b588064162d95585f05) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubePriorityLevelConfigurationV1Beta2Props( - metadata=metadata, spec=spec - ) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["PriorityLevelConfigurationSpecV1Beta2", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.flowcontrol.v1beta2.PriorityLevelConfiguration". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param metadata: ``metadata`` is the standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: ``spec`` is the specification of the desired behavior of a "request-priority". More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - ''' - props = KubePriorityLevelConfigurationV1Beta2Props( - metadata=metadata, spec=spec - ) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.flowcontrol.v1beta2.PriorityLevelConfiguration".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubePriorityLevelConfigurationV1Beta2Props", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata", "spec": "spec"}, -) -class KubePriorityLevelConfigurationV1Beta2Props: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["PriorityLevelConfigurationSpecV1Beta2", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''PriorityLevelConfiguration represents the configuration of a priority level. - - :param metadata: ``metadata`` is the standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: ``spec`` is the specification of the desired behavior of a "request-priority". More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.flowcontrol.v1beta2.PriorityLevelConfiguration - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if isinstance(spec, dict): - spec = PriorityLevelConfigurationSpecV1Beta2(**spec) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__ebcd2e792a37c952b3b0359c48478c4abfbe9ef8402855ed70cefd8874e5696b) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - if spec is not None: - self._values["spec"] = spec - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''``metadata`` is the standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.flowcontrol.v1beta2.PriorityLevelConfiguration#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def spec(self) -> typing.Optional["PriorityLevelConfigurationSpecV1Beta2"]: - '''``spec`` is the specification of the desired behavior of a "request-priority". - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.flowcontrol.v1beta2.PriorityLevelConfiguration#spec - ''' - result = self._values.get("spec") - return typing.cast(typing.Optional["PriorityLevelConfigurationSpecV1Beta2"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubePriorityLevelConfigurationV1Beta2Props(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubePriorityLevelConfigurationV1Beta3( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubePriorityLevelConfigurationV1Beta3", -): - '''PriorityLevelConfiguration represents the configuration of a priority level. - - :schema: io.k8s.api.flowcontrol.v1beta3.PriorityLevelConfiguration - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["PriorityLevelConfigurationSpecV1Beta3", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.flowcontrol.v1beta3.PriorityLevelConfiguration" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param metadata: ``metadata`` is the standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: ``spec`` is the specification of the desired behavior of a "request-priority". More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__e5b00c189c9bee05bebcfdcd22a465297c6da0c35fbc81c5172ea3c48f65b7f2) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubePriorityLevelConfigurationV1Beta3Props( - metadata=metadata, spec=spec - ) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["PriorityLevelConfigurationSpecV1Beta3", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.flowcontrol.v1beta3.PriorityLevelConfiguration". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param metadata: ``metadata`` is the standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: ``spec`` is the specification of the desired behavior of a "request-priority". More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - ''' - props = KubePriorityLevelConfigurationV1Beta3Props( - metadata=metadata, spec=spec - ) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.flowcontrol.v1beta3.PriorityLevelConfiguration".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubePriorityLevelConfigurationV1Beta3Props", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata", "spec": "spec"}, -) -class KubePriorityLevelConfigurationV1Beta3Props: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["PriorityLevelConfigurationSpecV1Beta3", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''PriorityLevelConfiguration represents the configuration of a priority level. - - :param metadata: ``metadata`` is the standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: ``spec`` is the specification of the desired behavior of a "request-priority". More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.flowcontrol.v1beta3.PriorityLevelConfiguration - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if isinstance(spec, dict): - spec = PriorityLevelConfigurationSpecV1Beta3(**spec) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__77fb534a06fef313d54401762de300dc3563bf4d8411dada16072154c0234ba3) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - if spec is not None: - self._values["spec"] = spec - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''``metadata`` is the standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.flowcontrol.v1beta3.PriorityLevelConfiguration#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def spec(self) -> typing.Optional["PriorityLevelConfigurationSpecV1Beta3"]: - '''``spec`` is the specification of the desired behavior of a "request-priority". - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.flowcontrol.v1beta3.PriorityLevelConfiguration#spec - ''' - result = self._values.get("spec") - return typing.cast(typing.Optional["PriorityLevelConfigurationSpecV1Beta3"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubePriorityLevelConfigurationV1Beta3Props(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeReplicaSet( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeReplicaSet", -): - '''ReplicaSet ensures that a specified number of pod replicas are running at any given time. - - :schema: io.k8s.api.apps.v1.ReplicaSet - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["ReplicaSetSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.apps.v1.ReplicaSet" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param metadata: If the Labels of a ReplicaSet are empty, they are defaulted to be the same as the Pod(s) that the ReplicaSet manages. Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Spec defines the specification of the desired behavior of the ReplicaSet. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__10b1e6952ed8e4461a4c7cb6055b12f7d11053876688102605ac9643cba57005) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeReplicaSetProps(metadata=metadata, spec=spec) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["ReplicaSetSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.apps.v1.ReplicaSet". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param metadata: If the Labels of a ReplicaSet are empty, they are defaulted to be the same as the Pod(s) that the ReplicaSet manages. Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Spec defines the specification of the desired behavior of the ReplicaSet. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - ''' - props = KubeReplicaSetProps(metadata=metadata, spec=spec) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.apps.v1.ReplicaSet".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubeReplicaSetList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeReplicaSetList", -): - '''ReplicaSetList is a collection of ReplicaSets. - - :schema: io.k8s.api.apps.v1.ReplicaSetList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeReplicaSetProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.apps.v1.ReplicaSetList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: List of ReplicaSets. More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__24d3450455c5e97bf49cda54253c588d8a6ee19f76f1cf671ba9f98802a53d99) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeReplicaSetListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeReplicaSetProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.apps.v1.ReplicaSetList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: List of ReplicaSets. More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - ''' - props = KubeReplicaSetListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.apps.v1.ReplicaSetList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeReplicaSetListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeReplicaSetListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeReplicaSetProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''ReplicaSetList is a collection of ReplicaSets. - - :param items: List of ReplicaSets. More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.apps.v1.ReplicaSetList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__62c387938d1bc321eddeb2ff018f798c1e609329bfdcd7b74261bb70e472d00f) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeReplicaSetProps"]: - '''List of ReplicaSets. - - More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller - - :schema: io.k8s.api.apps.v1.ReplicaSetList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeReplicaSetProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.apps.v1.ReplicaSetList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeReplicaSetListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubeReplicaSetProps", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata", "spec": "spec"}, -) -class KubeReplicaSetProps: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["ReplicaSetSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''ReplicaSet ensures that a specified number of pod replicas are running at any given time. - - :param metadata: If the Labels of a ReplicaSet are empty, they are defaulted to be the same as the Pod(s) that the ReplicaSet manages. Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Spec defines the specification of the desired behavior of the ReplicaSet. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.apps.v1.ReplicaSet - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if isinstance(spec, dict): - spec = ReplicaSetSpec(**spec) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__3356ec84091f3836aed86951b46f5c67fde6b2669f3404b932d0ffb3aa92b8b1) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - if spec is not None: - self._values["spec"] = spec - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''If the Labels of a ReplicaSet are empty, they are defaulted to be the same as the Pod(s) that the ReplicaSet manages. - - Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.apps.v1.ReplicaSet#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def spec(self) -> typing.Optional["ReplicaSetSpec"]: - '''Spec defines the specification of the desired behavior of the ReplicaSet. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.apps.v1.ReplicaSet#spec - ''' - result = self._values.get("spec") - return typing.cast(typing.Optional["ReplicaSetSpec"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeReplicaSetProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeReplicationController( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeReplicationController", -): - '''ReplicationController represents the configuration of a replication controller. - - :schema: io.k8s.api.core.v1.ReplicationController - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["ReplicationControllerSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.core.v1.ReplicationController" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param metadata: If the Labels of a ReplicationController are empty, they are defaulted to be the same as the Pod(s) that the replication controller manages. Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Spec defines the specification of the desired behavior of the replication controller. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__b76c77ebee47f8e1db2fb813b337b8d1cb81ba43cc3b5afa6d87b4d42f8ccc27) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeReplicationControllerProps(metadata=metadata, spec=spec) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["ReplicationControllerSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.core.v1.ReplicationController". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param metadata: If the Labels of a ReplicationController are empty, they are defaulted to be the same as the Pod(s) that the replication controller manages. Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Spec defines the specification of the desired behavior of the replication controller. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - ''' - props = KubeReplicationControllerProps(metadata=metadata, spec=spec) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.core.v1.ReplicationController".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubeReplicationControllerList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeReplicationControllerList", -): - '''ReplicationControllerList is a collection of replication controllers. - - :schema: io.k8s.api.core.v1.ReplicationControllerList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeReplicationControllerProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.core.v1.ReplicationControllerList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: List of replication controllers. More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__b3b728b8344327bdb06c9b83008eeef39b961f93e5cf0c03f478bfe4429bc465) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeReplicationControllerListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeReplicationControllerProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.core.v1.ReplicationControllerList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: List of replication controllers. More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - ''' - props = KubeReplicationControllerListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.core.v1.ReplicationControllerList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeReplicationControllerListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeReplicationControllerListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeReplicationControllerProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''ReplicationControllerList is a collection of replication controllers. - - :param items: List of replication controllers. More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.core.v1.ReplicationControllerList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__9883740538c9153a5fd5f360dbdefcf08f177d9bcc570eb8535695b601d2cc31) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeReplicationControllerProps"]: - '''List of replication controllers. - - More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller - - :schema: io.k8s.api.core.v1.ReplicationControllerList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeReplicationControllerProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.core.v1.ReplicationControllerList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeReplicationControllerListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubeReplicationControllerProps", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata", "spec": "spec"}, -) -class KubeReplicationControllerProps: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["ReplicationControllerSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''ReplicationController represents the configuration of a replication controller. - - :param metadata: If the Labels of a ReplicationController are empty, they are defaulted to be the same as the Pod(s) that the replication controller manages. Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Spec defines the specification of the desired behavior of the replication controller. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.core.v1.ReplicationController - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if isinstance(spec, dict): - spec = ReplicationControllerSpec(**spec) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__d1907ebb731e0f56418eaea7fe01ae75a6a0f7a66fe54291e68654e7347b8e5c) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - if spec is not None: - self._values["spec"] = spec - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''If the Labels of a ReplicationController are empty, they are defaulted to be the same as the Pod(s) that the replication controller manages. - - Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.core.v1.ReplicationController#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def spec(self) -> typing.Optional["ReplicationControllerSpec"]: - '''Spec defines the specification of the desired behavior of the replication controller. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.core.v1.ReplicationController#spec - ''' - result = self._values.get("spec") - return typing.cast(typing.Optional["ReplicationControllerSpec"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeReplicationControllerProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeResourceClaimListV1Alpha1( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeResourceClaimListV1Alpha1", -): - '''ResourceClaimList is a collection of claims. - - :schema: io.k8s.api.resource.v1alpha1.ResourceClaimList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeResourceClaimV1Alpha1Props", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.resource.v1alpha1.ResourceClaimList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: Items is the list of resource claims. - :param metadata: Standard list metadata. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__e200cdf7bdfd425880660ef6ebcb90da88783cb7874f700af41261d226802408) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeResourceClaimListV1Alpha1Props(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeResourceClaimV1Alpha1Props", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.resource.v1alpha1.ResourceClaimList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: Items is the list of resource claims. - :param metadata: Standard list metadata. - ''' - props = KubeResourceClaimListV1Alpha1Props(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.resource.v1alpha1.ResourceClaimList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeResourceClaimListV1Alpha1Props", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeResourceClaimListV1Alpha1Props: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeResourceClaimV1Alpha1Props", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''ResourceClaimList is a collection of claims. - - :param items: Items is the list of resource claims. - :param metadata: Standard list metadata. - - :schema: io.k8s.api.resource.v1alpha1.ResourceClaimList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__de1fd43faf0ba317c36809119ca61ff37dc7311bff784a153466481f3c1f7aac) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeResourceClaimV1Alpha1Props"]: - '''Items is the list of resource claims. - - :schema: io.k8s.api.resource.v1alpha1.ResourceClaimList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeResourceClaimV1Alpha1Props"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata. - - :schema: io.k8s.api.resource.v1alpha1.ResourceClaimList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeResourceClaimListV1Alpha1Props(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeResourceClaimTemplateListV1Alpha1( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeResourceClaimTemplateListV1Alpha1", -): - '''ResourceClaimTemplateList is a collection of claim templates. - - :schema: io.k8s.api.resource.v1alpha1.ResourceClaimTemplateList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeResourceClaimTemplateV1Alpha1Props", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.resource.v1alpha1.ResourceClaimTemplateList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: Items is the list of resource claim templates. - :param metadata: Standard list metadata. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__6fbb34cbc640559672bb256ab485dc10d838f47767a362a9647924f5939ec9b7) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeResourceClaimTemplateListV1Alpha1Props( - items=items, metadata=metadata - ) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeResourceClaimTemplateV1Alpha1Props", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.resource.v1alpha1.ResourceClaimTemplateList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: Items is the list of resource claim templates. - :param metadata: Standard list metadata. - ''' - props = KubeResourceClaimTemplateListV1Alpha1Props( - items=items, metadata=metadata - ) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.resource.v1alpha1.ResourceClaimTemplateList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeResourceClaimTemplateListV1Alpha1Props", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeResourceClaimTemplateListV1Alpha1Props: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeResourceClaimTemplateV1Alpha1Props", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''ResourceClaimTemplateList is a collection of claim templates. - - :param items: Items is the list of resource claim templates. - :param metadata: Standard list metadata. - - :schema: io.k8s.api.resource.v1alpha1.ResourceClaimTemplateList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__28698822e45bda3d63db1ad3983a08b594ae8089817211a639d0d2b2212c5c0e) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeResourceClaimTemplateV1Alpha1Props"]: - '''Items is the list of resource claim templates. - - :schema: io.k8s.api.resource.v1alpha1.ResourceClaimTemplateList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeResourceClaimTemplateV1Alpha1Props"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata. - - :schema: io.k8s.api.resource.v1alpha1.ResourceClaimTemplateList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeResourceClaimTemplateListV1Alpha1Props(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeResourceClaimTemplateV1Alpha1( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeResourceClaimTemplateV1Alpha1", -): - '''ResourceClaimTemplate is used to produce ResourceClaim objects. - - :schema: io.k8s.api.resource.v1alpha1.ResourceClaimTemplate - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - spec: typing.Union["ResourceClaimTemplateSpecV1Alpha1", typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.resource.v1alpha1.ResourceClaimTemplate" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param spec: Describes the ResourceClaim that is to be generated. This field is immutable. A ResourceClaim will get created by the control plane for a Pod when needed and then not get updated anymore. - :param metadata: Standard object metadata. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__19b55a664e022e7cf75a2e7db6a0c16e6791ff0f493db7b0ac8902687bdfc771) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeResourceClaimTemplateV1Alpha1Props(spec=spec, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - spec: typing.Union["ResourceClaimTemplateSpecV1Alpha1", typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.resource.v1alpha1.ResourceClaimTemplate". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param spec: Describes the ResourceClaim that is to be generated. This field is immutable. A ResourceClaim will get created by the control plane for a Pod when needed and then not get updated anymore. - :param metadata: Standard object metadata. - ''' - props = KubeResourceClaimTemplateV1Alpha1Props(spec=spec, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.resource.v1alpha1.ResourceClaimTemplate".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeResourceClaimTemplateV1Alpha1Props", - jsii_struct_bases=[], - name_mapping={"spec": "spec", "metadata": "metadata"}, -) -class KubeResourceClaimTemplateV1Alpha1Props: - def __init__( - self, - *, - spec: typing.Union["ResourceClaimTemplateSpecV1Alpha1", typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''ResourceClaimTemplate is used to produce ResourceClaim objects. - - :param spec: Describes the ResourceClaim that is to be generated. This field is immutable. A ResourceClaim will get created by the control plane for a Pod when needed and then not get updated anymore. - :param metadata: Standard object metadata. - - :schema: io.k8s.api.resource.v1alpha1.ResourceClaimTemplate - ''' - if isinstance(spec, dict): - spec = ResourceClaimTemplateSpecV1Alpha1(**spec) - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__895c0745ae5288dd68b676af5ebba5862e4ff365a8b6cb7256b72cebb64ed32f) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "spec": spec, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def spec(self) -> "ResourceClaimTemplateSpecV1Alpha1": - '''Describes the ResourceClaim that is to be generated. - - This field is immutable. A ResourceClaim will get created by the control plane for a Pod when needed and then not get updated anymore. - - :schema: io.k8s.api.resource.v1alpha1.ResourceClaimTemplate#spec - ''' - result = self._values.get("spec") - assert result is not None, "Required property 'spec' is missing" - return typing.cast("ResourceClaimTemplateSpecV1Alpha1", result) - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object metadata. - - :schema: io.k8s.api.resource.v1alpha1.ResourceClaimTemplate#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeResourceClaimTemplateV1Alpha1Props(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeResourceClaimV1Alpha1( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeResourceClaimV1Alpha1", -): - '''ResourceClaim describes which resources are needed by a resource consumer. - - Its status tracks whether the resource has been allocated and what the resulting attributes are. - - This is an alpha type and requires enabling the DynamicResourceAllocation feature gate. - - :schema: io.k8s.api.resource.v1alpha1.ResourceClaim - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - spec: typing.Union["ResourceClaimSpecV1Alpha1", typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.resource.v1alpha1.ResourceClaim" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param spec: Spec describes the desired attributes of a resource that then needs to be allocated. It can only be set once when creating the ResourceClaim. - :param metadata: Standard object metadata. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__a1f97fddc933efea2a1616dae66764060c73225f24ca19f70ab4da1cff53e88f) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeResourceClaimV1Alpha1Props(spec=spec, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - spec: typing.Union["ResourceClaimSpecV1Alpha1", typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.resource.v1alpha1.ResourceClaim". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param spec: Spec describes the desired attributes of a resource that then needs to be allocated. It can only be set once when creating the ResourceClaim. - :param metadata: Standard object metadata. - ''' - props = KubeResourceClaimV1Alpha1Props(spec=spec, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.resource.v1alpha1.ResourceClaim".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeResourceClaimV1Alpha1Props", - jsii_struct_bases=[], - name_mapping={"spec": "spec", "metadata": "metadata"}, -) -class KubeResourceClaimV1Alpha1Props: - def __init__( - self, - *, - spec: typing.Union["ResourceClaimSpecV1Alpha1", typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''ResourceClaim describes which resources are needed by a resource consumer. - - Its status tracks whether the resource has been allocated and what the resulting attributes are. - - This is an alpha type and requires enabling the DynamicResourceAllocation feature gate. - - :param spec: Spec describes the desired attributes of a resource that then needs to be allocated. It can only be set once when creating the ResourceClaim. - :param metadata: Standard object metadata. - - :schema: io.k8s.api.resource.v1alpha1.ResourceClaim - ''' - if isinstance(spec, dict): - spec = ResourceClaimSpecV1Alpha1(**spec) - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__881875cd1d5513534efa2e6323236285dc2d6c692541f339978f5f88cbd7191d) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "spec": spec, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def spec(self) -> "ResourceClaimSpecV1Alpha1": - '''Spec describes the desired attributes of a resource that then needs to be allocated. - - It can only be set once when creating the ResourceClaim. - - :schema: io.k8s.api.resource.v1alpha1.ResourceClaim#spec - ''' - result = self._values.get("spec") - assert result is not None, "Required property 'spec' is missing" - return typing.cast("ResourceClaimSpecV1Alpha1", result) - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object metadata. - - :schema: io.k8s.api.resource.v1alpha1.ResourceClaim#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeResourceClaimV1Alpha1Props(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeResourceClassListV1Alpha1( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeResourceClassListV1Alpha1", -): - '''ResourceClassList is a collection of classes. - - :schema: io.k8s.api.resource.v1alpha1.ResourceClassList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeResourceClassV1Alpha1Props", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.resource.v1alpha1.ResourceClassList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: Items is the list of resource classes. - :param metadata: Standard list metadata. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__e1695fa3fd0da9c0899fd14ab89c516ae780955a7fabddea610d77da29a44ed4) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeResourceClassListV1Alpha1Props(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeResourceClassV1Alpha1Props", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.resource.v1alpha1.ResourceClassList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: Items is the list of resource classes. - :param metadata: Standard list metadata. - ''' - props = KubeResourceClassListV1Alpha1Props(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.resource.v1alpha1.ResourceClassList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeResourceClassListV1Alpha1Props", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeResourceClassListV1Alpha1Props: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeResourceClassV1Alpha1Props", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''ResourceClassList is a collection of classes. - - :param items: Items is the list of resource classes. - :param metadata: Standard list metadata. - - :schema: io.k8s.api.resource.v1alpha1.ResourceClassList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__ac68af0f54677d6e7e28921a84e980663e5bbd36841ef1ddab313b91449b124a) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeResourceClassV1Alpha1Props"]: - '''Items is the list of resource classes. - - :schema: io.k8s.api.resource.v1alpha1.ResourceClassList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeResourceClassV1Alpha1Props"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata. - - :schema: io.k8s.api.resource.v1alpha1.ResourceClassList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeResourceClassListV1Alpha1Props(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeResourceClassV1Alpha1( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeResourceClassV1Alpha1", -): - '''ResourceClass is used by administrators to influence how resources are allocated. - - This is an alpha type and requires enabling the DynamicResourceAllocation feature gate. - - :schema: io.k8s.api.resource.v1alpha1.ResourceClass - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - driver_name: builtins.str, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - parameters_ref: typing.Optional[typing.Union["ResourceClassParametersReferenceV1Alpha1", typing.Dict[builtins.str, typing.Any]]] = None, - suitable_nodes: typing.Optional[typing.Union["NodeSelector", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.resource.v1alpha1.ResourceClass" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param driver_name: DriverName defines the name of the dynamic resource driver that is used for allocation of a ResourceClaim that uses this class. Resource drivers have a unique name in forward domain order (acme.example.com). - :param metadata: Standard object metadata. - :param parameters_ref: ParametersRef references an arbitrary separate object that may hold parameters that will be used by the driver when allocating a resource that uses this class. A dynamic resource driver can distinguish between parameters stored here and and those stored in ResourceClaimSpec. - :param suitable_nodes: Only nodes matching the selector will be considered by the scheduler when trying to find a Node that fits a Pod when that Pod uses a ResourceClaim that has not been allocated yet. Setting this field is optional. If null, all nodes are candidates. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__73e955754ed6b0a944de335f682e555ee872f783b244a6172a6174b18e2953f2) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeResourceClassV1Alpha1Props( - driver_name=driver_name, - metadata=metadata, - parameters_ref=parameters_ref, - suitable_nodes=suitable_nodes, - ) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - driver_name: builtins.str, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - parameters_ref: typing.Optional[typing.Union["ResourceClassParametersReferenceV1Alpha1", typing.Dict[builtins.str, typing.Any]]] = None, - suitable_nodes: typing.Optional[typing.Union["NodeSelector", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.resource.v1alpha1.ResourceClass". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param driver_name: DriverName defines the name of the dynamic resource driver that is used for allocation of a ResourceClaim that uses this class. Resource drivers have a unique name in forward domain order (acme.example.com). - :param metadata: Standard object metadata. - :param parameters_ref: ParametersRef references an arbitrary separate object that may hold parameters that will be used by the driver when allocating a resource that uses this class. A dynamic resource driver can distinguish between parameters stored here and and those stored in ResourceClaimSpec. - :param suitable_nodes: Only nodes matching the selector will be considered by the scheduler when trying to find a Node that fits a Pod when that Pod uses a ResourceClaim that has not been allocated yet. Setting this field is optional. If null, all nodes are candidates. - ''' - props = KubeResourceClassV1Alpha1Props( - driver_name=driver_name, - metadata=metadata, - parameters_ref=parameters_ref, - suitable_nodes=suitable_nodes, - ) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.resource.v1alpha1.ResourceClass".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeResourceClassV1Alpha1Props", - jsii_struct_bases=[], - name_mapping={ - "driver_name": "driverName", - "metadata": "metadata", - "parameters_ref": "parametersRef", - "suitable_nodes": "suitableNodes", - }, -) -class KubeResourceClassV1Alpha1Props: - def __init__( - self, - *, - driver_name: builtins.str, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - parameters_ref: typing.Optional[typing.Union["ResourceClassParametersReferenceV1Alpha1", typing.Dict[builtins.str, typing.Any]]] = None, - suitable_nodes: typing.Optional[typing.Union["NodeSelector", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''ResourceClass is used by administrators to influence how resources are allocated. - - This is an alpha type and requires enabling the DynamicResourceAllocation feature gate. - - :param driver_name: DriverName defines the name of the dynamic resource driver that is used for allocation of a ResourceClaim that uses this class. Resource drivers have a unique name in forward domain order (acme.example.com). - :param metadata: Standard object metadata. - :param parameters_ref: ParametersRef references an arbitrary separate object that may hold parameters that will be used by the driver when allocating a resource that uses this class. A dynamic resource driver can distinguish between parameters stored here and and those stored in ResourceClaimSpec. - :param suitable_nodes: Only nodes matching the selector will be considered by the scheduler when trying to find a Node that fits a Pod when that Pod uses a ResourceClaim that has not been allocated yet. Setting this field is optional. If null, all nodes are candidates. - - :schema: io.k8s.api.resource.v1alpha1.ResourceClass - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if isinstance(parameters_ref, dict): - parameters_ref = ResourceClassParametersReferenceV1Alpha1(**parameters_ref) - if isinstance(suitable_nodes, dict): - suitable_nodes = NodeSelector(**suitable_nodes) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__4dcda1419c55ac01a43092063ef99623f9153c117048d8a4d4a0ebd85bae5430) - check_type(argname="argument driver_name", value=driver_name, expected_type=type_hints["driver_name"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument parameters_ref", value=parameters_ref, expected_type=type_hints["parameters_ref"]) - check_type(argname="argument suitable_nodes", value=suitable_nodes, expected_type=type_hints["suitable_nodes"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "driver_name": driver_name, - } - if metadata is not None: - self._values["metadata"] = metadata - if parameters_ref is not None: - self._values["parameters_ref"] = parameters_ref - if suitable_nodes is not None: - self._values["suitable_nodes"] = suitable_nodes - - @builtins.property - def driver_name(self) -> builtins.str: - '''DriverName defines the name of the dynamic resource driver that is used for allocation of a ResourceClaim that uses this class. - - Resource drivers have a unique name in forward domain order (acme.example.com). - - :schema: io.k8s.api.resource.v1alpha1.ResourceClass#driverName - ''' - result = self._values.get("driver_name") - assert result is not None, "Required property 'driver_name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object metadata. - - :schema: io.k8s.api.resource.v1alpha1.ResourceClass#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def parameters_ref( - self, - ) -> typing.Optional["ResourceClassParametersReferenceV1Alpha1"]: - '''ParametersRef references an arbitrary separate object that may hold parameters that will be used by the driver when allocating a resource that uses this class. - - A dynamic resource driver can distinguish between parameters stored here and and those stored in ResourceClaimSpec. - - :schema: io.k8s.api.resource.v1alpha1.ResourceClass#parametersRef - ''' - result = self._values.get("parameters_ref") - return typing.cast(typing.Optional["ResourceClassParametersReferenceV1Alpha1"], result) - - @builtins.property - def suitable_nodes(self) -> typing.Optional["NodeSelector"]: - '''Only nodes matching the selector will be considered by the scheduler when trying to find a Node that fits a Pod when that Pod uses a ResourceClaim that has not been allocated yet. - - Setting this field is optional. If null, all nodes are candidates. - - :schema: io.k8s.api.resource.v1alpha1.ResourceClass#suitableNodes - ''' - result = self._values.get("suitable_nodes") - return typing.cast(typing.Optional["NodeSelector"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeResourceClassV1Alpha1Props(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeResourceQuota( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeResourceQuota", -): - '''ResourceQuota sets aggregate quota restrictions enforced per namespace. - - :schema: io.k8s.api.core.v1.ResourceQuota - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["ResourceQuotaSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.core.v1.ResourceQuota" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Spec defines the desired quota. https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__3ac4857c79a81ca461b8b100787cc5d2e4fa270a239531d0b264e7c1c647ebbc) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeResourceQuotaProps(metadata=metadata, spec=spec) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["ResourceQuotaSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.core.v1.ResourceQuota". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Spec defines the desired quota. https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - ''' - props = KubeResourceQuotaProps(metadata=metadata, spec=spec) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.core.v1.ResourceQuota".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubeResourceQuotaList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeResourceQuotaList", -): - '''ResourceQuotaList is a list of ResourceQuota items. - - :schema: io.k8s.api.core.v1.ResourceQuotaList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeResourceQuotaProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.core.v1.ResourceQuotaList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: Items is a list of ResourceQuota objects. More info: https://kubernetes.io/docs/concepts/policy/resource-quotas/ - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__1c8449d16fa5f0f57efb0bf048a173204cb2eee0724e5beee1997b7fd6446ae2) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeResourceQuotaListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeResourceQuotaProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.core.v1.ResourceQuotaList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: Items is a list of ResourceQuota objects. More info: https://kubernetes.io/docs/concepts/policy/resource-quotas/ - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - ''' - props = KubeResourceQuotaListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.core.v1.ResourceQuotaList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeResourceQuotaListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeResourceQuotaListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeResourceQuotaProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''ResourceQuotaList is a list of ResourceQuota items. - - :param items: Items is a list of ResourceQuota objects. More info: https://kubernetes.io/docs/concepts/policy/resource-quotas/ - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.core.v1.ResourceQuotaList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__fa8b7d22abad60c9e4fcd3d3a379006b596879c4f9044fb09d9e785c02019aa7) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeResourceQuotaProps"]: - '''Items is a list of ResourceQuota objects. - - More info: https://kubernetes.io/docs/concepts/policy/resource-quotas/ - - :schema: io.k8s.api.core.v1.ResourceQuotaList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeResourceQuotaProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.core.v1.ResourceQuotaList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeResourceQuotaListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubeResourceQuotaProps", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata", "spec": "spec"}, -) -class KubeResourceQuotaProps: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["ResourceQuotaSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''ResourceQuota sets aggregate quota restrictions enforced per namespace. - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Spec defines the desired quota. https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.core.v1.ResourceQuota - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if isinstance(spec, dict): - spec = ResourceQuotaSpec(**spec) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__659f76ba4ff363b4daafbc9b629fcbc230c1a0e0e932683b9fd35f50e4d29548) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - if spec is not None: - self._values["spec"] = spec - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.core.v1.ResourceQuota#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def spec(self) -> typing.Optional["ResourceQuotaSpec"]: - '''Spec defines the desired quota. - - https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.core.v1.ResourceQuota#spec - ''' - result = self._values.get("spec") - return typing.cast(typing.Optional["ResourceQuotaSpec"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeResourceQuotaProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeRole( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeRole", -): - '''Role is a namespaced, logical grouping of PolicyRules that can be referenced as a unit by a RoleBinding. - - :schema: io.k8s.api.rbac.v1.Role - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - rules: typing.Optional[typing.Sequence[typing.Union["PolicyRule", typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''Defines a "io.k8s.api.rbac.v1.Role" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param metadata: Standard object's metadata. - :param rules: Rules holds all the PolicyRules for this Role. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__29ed150ac8d5e84462d3788ba6966b3d87204185e9002d23a85b76b17ea79449) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeRoleProps(metadata=metadata, rules=rules) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - rules: typing.Optional[typing.Sequence[typing.Union["PolicyRule", typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.rbac.v1.Role". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param metadata: Standard object's metadata. - :param rules: Rules holds all the PolicyRules for this Role. - ''' - props = KubeRoleProps(metadata=metadata, rules=rules) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.rbac.v1.Role".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubeRoleBinding( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeRoleBinding", -): - '''RoleBinding references a role, but does not contain it. - - It can reference a Role in the same namespace or a ClusterRole in the global namespace. It adds who information via Subjects and namespace information by which namespace it exists in. RoleBindings in a given namespace only have effect in that namespace. - - :schema: io.k8s.api.rbac.v1.RoleBinding - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - role_ref: typing.Union["RoleRef", typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - subjects: typing.Optional[typing.Sequence[typing.Union["Subject", typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''Defines a "io.k8s.api.rbac.v1.RoleBinding" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param role_ref: RoleRef can reference a Role in the current namespace or a ClusterRole in the global namespace. If the RoleRef cannot be resolved, the Authorizer must return an error. - :param metadata: Standard object's metadata. - :param subjects: Subjects holds references to the objects the role applies to. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__2165aae46dbd747e3dfe47c03209e8f301ca3f4ac24494fe9f9cda773496d188) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeRoleBindingProps( - role_ref=role_ref, metadata=metadata, subjects=subjects - ) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - role_ref: typing.Union["RoleRef", typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - subjects: typing.Optional[typing.Sequence[typing.Union["Subject", typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.rbac.v1.RoleBinding". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param role_ref: RoleRef can reference a Role in the current namespace or a ClusterRole in the global namespace. If the RoleRef cannot be resolved, the Authorizer must return an error. - :param metadata: Standard object's metadata. - :param subjects: Subjects holds references to the objects the role applies to. - ''' - props = KubeRoleBindingProps( - role_ref=role_ref, metadata=metadata, subjects=subjects - ) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.rbac.v1.RoleBinding".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubeRoleBindingList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeRoleBindingList", -): - '''RoleBindingList is a collection of RoleBindings. - - :schema: io.k8s.api.rbac.v1.RoleBindingList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeRoleBindingProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.rbac.v1.RoleBindingList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: Items is a list of RoleBindings. - :param metadata: Standard object's metadata. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__f87b0d405558e8e0b39449098e57a74cf3f58b136a74b32013664caea0d5c426) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeRoleBindingListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeRoleBindingProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.rbac.v1.RoleBindingList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: Items is a list of RoleBindings. - :param metadata: Standard object's metadata. - ''' - props = KubeRoleBindingListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.rbac.v1.RoleBindingList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeRoleBindingListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeRoleBindingListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeRoleBindingProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''RoleBindingList is a collection of RoleBindings. - - :param items: Items is a list of RoleBindings. - :param metadata: Standard object's metadata. - - :schema: io.k8s.api.rbac.v1.RoleBindingList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__0ea68389c941015338a6dd149e67bba16f03189d9fca5c31ff0b58b27c250791) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeRoleBindingProps"]: - '''Items is a list of RoleBindings. - - :schema: io.k8s.api.rbac.v1.RoleBindingList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeRoleBindingProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard object's metadata. - - :schema: io.k8s.api.rbac.v1.RoleBindingList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeRoleBindingListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubeRoleBindingProps", - jsii_struct_bases=[], - name_mapping={ - "role_ref": "roleRef", - "metadata": "metadata", - "subjects": "subjects", - }, -) -class KubeRoleBindingProps: - def __init__( - self, - *, - role_ref: typing.Union["RoleRef", typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - subjects: typing.Optional[typing.Sequence[typing.Union["Subject", typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''RoleBinding references a role, but does not contain it. - - It can reference a Role in the same namespace or a ClusterRole in the global namespace. It adds who information via Subjects and namespace information by which namespace it exists in. RoleBindings in a given namespace only have effect in that namespace. - - :param role_ref: RoleRef can reference a Role in the current namespace or a ClusterRole in the global namespace. If the RoleRef cannot be resolved, the Authorizer must return an error. - :param metadata: Standard object's metadata. - :param subjects: Subjects holds references to the objects the role applies to. - - :schema: io.k8s.api.rbac.v1.RoleBinding - ''' - if isinstance(role_ref, dict): - role_ref = RoleRef(**role_ref) - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__8a2b8de1d0bd2d542efd8d7543a30c1daee70a3e4a630cb0ef968ba5f26deb1d) - check_type(argname="argument role_ref", value=role_ref, expected_type=type_hints["role_ref"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument subjects", value=subjects, expected_type=type_hints["subjects"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "role_ref": role_ref, - } - if metadata is not None: - self._values["metadata"] = metadata - if subjects is not None: - self._values["subjects"] = subjects - - @builtins.property - def role_ref(self) -> "RoleRef": - '''RoleRef can reference a Role in the current namespace or a ClusterRole in the global namespace. - - If the RoleRef cannot be resolved, the Authorizer must return an error. - - :schema: io.k8s.api.rbac.v1.RoleBinding#roleRef - ''' - result = self._values.get("role_ref") - assert result is not None, "Required property 'role_ref' is missing" - return typing.cast("RoleRef", result) - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata. - - :schema: io.k8s.api.rbac.v1.RoleBinding#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def subjects(self) -> typing.Optional[typing.List["Subject"]]: - '''Subjects holds references to the objects the role applies to. - - :schema: io.k8s.api.rbac.v1.RoleBinding#subjects - ''' - result = self._values.get("subjects") - return typing.cast(typing.Optional[typing.List["Subject"]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeRoleBindingProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeRoleList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeRoleList", -): - '''RoleList is a collection of Roles. - - :schema: io.k8s.api.rbac.v1.RoleList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeRoleProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.rbac.v1.RoleList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: Items is a list of Roles. - :param metadata: Standard object's metadata. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__33688bb860def340a9dd80a000256bd8166770cd75a90c4230022160b6b60fa3) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeRoleListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeRoleProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.rbac.v1.RoleList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: Items is a list of Roles. - :param metadata: Standard object's metadata. - ''' - props = KubeRoleListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.rbac.v1.RoleList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeRoleListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeRoleListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeRoleProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''RoleList is a collection of Roles. - - :param items: Items is a list of Roles. - :param metadata: Standard object's metadata. - - :schema: io.k8s.api.rbac.v1.RoleList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__47ad3ce5aaac7e92b0ff56cef58990cd52e68663c4295dd4088db5f6306dfd41) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeRoleProps"]: - '''Items is a list of Roles. - - :schema: io.k8s.api.rbac.v1.RoleList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeRoleProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard object's metadata. - - :schema: io.k8s.api.rbac.v1.RoleList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeRoleListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubeRoleProps", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata", "rules": "rules"}, -) -class KubeRoleProps: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - rules: typing.Optional[typing.Sequence[typing.Union["PolicyRule", typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''Role is a namespaced, logical grouping of PolicyRules that can be referenced as a unit by a RoleBinding. - - :param metadata: Standard object's metadata. - :param rules: Rules holds all the PolicyRules for this Role. - - :schema: io.k8s.api.rbac.v1.Role - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__03f10491b2f4c7a09738e2bec5b9b83fb9ac2df6d87e8a3a04a69a591071960d) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument rules", value=rules, expected_type=type_hints["rules"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - if rules is not None: - self._values["rules"] = rules - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata. - - :schema: io.k8s.api.rbac.v1.Role#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def rules(self) -> typing.Optional[typing.List["PolicyRule"]]: - '''Rules holds all the PolicyRules for this Role. - - :schema: io.k8s.api.rbac.v1.Role#rules - ''' - result = self._values.get("rules") - return typing.cast(typing.Optional[typing.List["PolicyRule"]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeRoleProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeRuntimeClass( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeRuntimeClass", -): - '''RuntimeClass defines a class of container runtime supported in the cluster. - - The RuntimeClass is used to determine which container runtime is used to run all containers in a pod. RuntimeClasses are manually defined by a user or cluster provisioner, and referenced in the PodSpec. The Kubelet is responsible for resolving the RuntimeClassName reference before running the pod. For more details, see https://kubernetes.io/docs/concepts/containers/runtime-class/ - - :schema: io.k8s.api.node.v1.RuntimeClass - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - handler: builtins.str, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - overhead: typing.Optional[typing.Union["Overhead", typing.Dict[builtins.str, typing.Any]]] = None, - scheduling: typing.Optional[typing.Union["Scheduling", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.node.v1.RuntimeClass" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param handler: Handler specifies the underlying runtime and configuration that the CRI implementation will use to handle pods of this class. The possible values are specific to the node & CRI configuration. It is assumed that all handlers are available on every node, and handlers of the same name are equivalent on every node. For example, a handler called "runc" might specify that the runc OCI runtime (using native Linux containers) will be used to run the containers in a pod. The Handler must be lowercase, conform to the DNS Label (RFC 1123) requirements, and is immutable. - :param metadata: More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - :param overhead: Overhead represents the resource overhead associated with running a pod for a given RuntimeClass. For more details, see https://kubernetes.io/docs/concepts/scheduling-eviction/pod-overhead/ - :param scheduling: Scheduling holds the scheduling constraints to ensure that pods running with this RuntimeClass are scheduled to nodes that support it. If scheduling is nil, this RuntimeClass is assumed to be supported by all nodes. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__73e802aeb77adf68ded78bc844e953e29156ea338b23850869f1eb458d0535ba) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeRuntimeClassProps( - handler=handler, - metadata=metadata, - overhead=overhead, - scheduling=scheduling, - ) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - handler: builtins.str, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - overhead: typing.Optional[typing.Union["Overhead", typing.Dict[builtins.str, typing.Any]]] = None, - scheduling: typing.Optional[typing.Union["Scheduling", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.node.v1.RuntimeClass". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param handler: Handler specifies the underlying runtime and configuration that the CRI implementation will use to handle pods of this class. The possible values are specific to the node & CRI configuration. It is assumed that all handlers are available on every node, and handlers of the same name are equivalent on every node. For example, a handler called "runc" might specify that the runc OCI runtime (using native Linux containers) will be used to run the containers in a pod. The Handler must be lowercase, conform to the DNS Label (RFC 1123) requirements, and is immutable. - :param metadata: More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - :param overhead: Overhead represents the resource overhead associated with running a pod for a given RuntimeClass. For more details, see https://kubernetes.io/docs/concepts/scheduling-eviction/pod-overhead/ - :param scheduling: Scheduling holds the scheduling constraints to ensure that pods running with this RuntimeClass are scheduled to nodes that support it. If scheduling is nil, this RuntimeClass is assumed to be supported by all nodes. - ''' - props = KubeRuntimeClassProps( - handler=handler, - metadata=metadata, - overhead=overhead, - scheduling=scheduling, - ) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.node.v1.RuntimeClass".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubeRuntimeClassList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeRuntimeClassList", -): - '''RuntimeClassList is a list of RuntimeClass objects. - - :schema: io.k8s.api.node.v1.RuntimeClassList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeRuntimeClassProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.node.v1.RuntimeClassList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: Items is a list of schema objects. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__b5d566a802c97a52571a895dd9503f614c01f4aca1f561b22f26cc02ba498284) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeRuntimeClassListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeRuntimeClassProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.node.v1.RuntimeClassList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: Items is a list of schema objects. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - props = KubeRuntimeClassListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.node.v1.RuntimeClassList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeRuntimeClassListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeRuntimeClassListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeRuntimeClassProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''RuntimeClassList is a list of RuntimeClass objects. - - :param items: Items is a list of schema objects. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.node.v1.RuntimeClassList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__235ff08f57089721a1cc755e07eeac0f1cf566b511fa57277b1026eb51582c2a) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeRuntimeClassProps"]: - '''Items is a list of schema objects. - - :schema: io.k8s.api.node.v1.RuntimeClassList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeRuntimeClassProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.node.v1.RuntimeClassList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeRuntimeClassListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubeRuntimeClassProps", - jsii_struct_bases=[], - name_mapping={ - "handler": "handler", - "metadata": "metadata", - "overhead": "overhead", - "scheduling": "scheduling", - }, -) -class KubeRuntimeClassProps: - def __init__( - self, - *, - handler: builtins.str, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - overhead: typing.Optional[typing.Union["Overhead", typing.Dict[builtins.str, typing.Any]]] = None, - scheduling: typing.Optional[typing.Union["Scheduling", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''RuntimeClass defines a class of container runtime supported in the cluster. - - The RuntimeClass is used to determine which container runtime is used to run all containers in a pod. RuntimeClasses are manually defined by a user or cluster provisioner, and referenced in the PodSpec. The Kubelet is responsible for resolving the RuntimeClassName reference before running the pod. For more details, see https://kubernetes.io/docs/concepts/containers/runtime-class/ - - :param handler: Handler specifies the underlying runtime and configuration that the CRI implementation will use to handle pods of this class. The possible values are specific to the node & CRI configuration. It is assumed that all handlers are available on every node, and handlers of the same name are equivalent on every node. For example, a handler called "runc" might specify that the runc OCI runtime (using native Linux containers) will be used to run the containers in a pod. The Handler must be lowercase, conform to the DNS Label (RFC 1123) requirements, and is immutable. - :param metadata: More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - :param overhead: Overhead represents the resource overhead associated with running a pod for a given RuntimeClass. For more details, see https://kubernetes.io/docs/concepts/scheduling-eviction/pod-overhead/ - :param scheduling: Scheduling holds the scheduling constraints to ensure that pods running with this RuntimeClass are scheduled to nodes that support it. If scheduling is nil, this RuntimeClass is assumed to be supported by all nodes. - - :schema: io.k8s.api.node.v1.RuntimeClass - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if isinstance(overhead, dict): - overhead = Overhead(**overhead) - if isinstance(scheduling, dict): - scheduling = Scheduling(**scheduling) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__66d9897bab16ca27a49026227ad29d408015abcd5910370e14974dcb1b0a858e) - check_type(argname="argument handler", value=handler, expected_type=type_hints["handler"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument overhead", value=overhead, expected_type=type_hints["overhead"]) - check_type(argname="argument scheduling", value=scheduling, expected_type=type_hints["scheduling"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "handler": handler, - } - if metadata is not None: - self._values["metadata"] = metadata - if overhead is not None: - self._values["overhead"] = overhead - if scheduling is not None: - self._values["scheduling"] = scheduling - - @builtins.property - def handler(self) -> builtins.str: - '''Handler specifies the underlying runtime and configuration that the CRI implementation will use to handle pods of this class. - - The possible values are specific to the node & CRI configuration. It is assumed that all handlers are available on every node, and handlers of the same name are equivalent on every node. For example, a handler called "runc" might specify that the runc OCI runtime (using native Linux containers) will be used to run the containers in a pod. The Handler must be lowercase, conform to the DNS Label (RFC 1123) requirements, and is immutable. - - :schema: io.k8s.api.node.v1.RuntimeClass#handler - ''' - result = self._values.get("handler") - assert result is not None, "Required property 'handler' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - - :schema: io.k8s.api.node.v1.RuntimeClass#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def overhead(self) -> typing.Optional["Overhead"]: - '''Overhead represents the resource overhead associated with running a pod for a given RuntimeClass. - - For more details, see - https://kubernetes.io/docs/concepts/scheduling-eviction/pod-overhead/ - - :schema: io.k8s.api.node.v1.RuntimeClass#overhead - ''' - result = self._values.get("overhead") - return typing.cast(typing.Optional["Overhead"], result) - - @builtins.property - def scheduling(self) -> typing.Optional["Scheduling"]: - '''Scheduling holds the scheduling constraints to ensure that pods running with this RuntimeClass are scheduled to nodes that support it. - - If scheduling is nil, this RuntimeClass is assumed to be supported by all nodes. - - :schema: io.k8s.api.node.v1.RuntimeClass#scheduling - ''' - result = self._values.get("scheduling") - return typing.cast(typing.Optional["Scheduling"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeRuntimeClassProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeScale( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeScale", -): - '''Scale represents a scaling request for a resource. - - :schema: io.k8s.api.autoscaling.v1.Scale - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["ScaleSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.autoscaling.v1.Scale" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param metadata: Standard object metadata; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - :param spec: defines the behavior of the scale. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__9b1969418b2c3135a3004bf63bc8af2d184c22929c1fbbbb43547d0537ad13fc) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeScaleProps(metadata=metadata, spec=spec) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["ScaleSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.autoscaling.v1.Scale". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param metadata: Standard object metadata; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - :param spec: defines the behavior of the scale. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status. - ''' - props = KubeScaleProps(metadata=metadata, spec=spec) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.autoscaling.v1.Scale".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeScaleProps", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata", "spec": "spec"}, -) -class KubeScaleProps: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["ScaleSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Scale represents a scaling request for a resource. - - :param metadata: Standard object metadata; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - :param spec: defines the behavior of the scale. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status. - - :schema: io.k8s.api.autoscaling.v1.Scale - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if isinstance(spec, dict): - spec = ScaleSpec(**spec) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__13391d438725de4a637b7b0d0a5bd88c6ec8637161c91c5b416382d69c1a3ab7) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - if spec is not None: - self._values["spec"] = spec - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object metadata; - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - - :schema: io.k8s.api.autoscaling.v1.Scale#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def spec(self) -> typing.Optional["ScaleSpec"]: - '''defines the behavior of the scale. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status. - - :schema: io.k8s.api.autoscaling.v1.Scale#spec - ''' - result = self._values.get("spec") - return typing.cast(typing.Optional["ScaleSpec"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeScaleProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeSecret( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeSecret", -): - '''Secret holds secret data of a certain type. - - The total bytes of the values in the Data field must be less than MaxSecretSize bytes. - - :schema: io.k8s.api.core.v1.Secret - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - data: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - immutable: typing.Optional[builtins.bool] = None, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - string_data: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - type: typing.Optional[builtins.str] = None, - ) -> None: - '''Defines a "io.k8s.api.core.v1.Secret" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param data: Data contains the secret data. Each key must consist of alphanumeric characters, '-', '_' or '.'. The serialized form of the secret data is a base64 encoded string, representing the arbitrary (possibly non-string) data value here. Described in https://tools.ietf.org/html/rfc4648#section-4 - :param immutable: Immutable, if set to true, ensures that data stored in the Secret cannot be updated (only object metadata can be modified). If not set to true, the field can be modified at any time. Defaulted to nil. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param string_data: stringData allows specifying non-binary secret data in string form. It is provided as a write-only input field for convenience. All keys and values are merged into the data field on write, overwriting any existing values. The stringData field is never output when reading from the API. - :param type: Used to facilitate programmatic handling of secret data. More info: https://kubernetes.io/docs/concepts/configuration/secret/#secret-types - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__58e682738c653346c651cc36d3c734a00b97388b8a9fd3f9cdc4718f06a89355) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeSecretProps( - data=data, - immutable=immutable, - metadata=metadata, - string_data=string_data, - type=type, - ) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - data: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - immutable: typing.Optional[builtins.bool] = None, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - string_data: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - type: typing.Optional[builtins.str] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.core.v1.Secret". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param data: Data contains the secret data. Each key must consist of alphanumeric characters, '-', '_' or '.'. The serialized form of the secret data is a base64 encoded string, representing the arbitrary (possibly non-string) data value here. Described in https://tools.ietf.org/html/rfc4648#section-4 - :param immutable: Immutable, if set to true, ensures that data stored in the Secret cannot be updated (only object metadata can be modified). If not set to true, the field can be modified at any time. Defaulted to nil. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param string_data: stringData allows specifying non-binary secret data in string form. It is provided as a write-only input field for convenience. All keys and values are merged into the data field on write, overwriting any existing values. The stringData field is never output when reading from the API. - :param type: Used to facilitate programmatic handling of secret data. More info: https://kubernetes.io/docs/concepts/configuration/secret/#secret-types - ''' - props = KubeSecretProps( - data=data, - immutable=immutable, - metadata=metadata, - string_data=string_data, - type=type, - ) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.core.v1.Secret".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubeSecretList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeSecretList", -): - '''SecretList is a list of Secret. - - :schema: io.k8s.api.core.v1.SecretList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeSecretProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.core.v1.SecretList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: Items is a list of secret objects. More info: https://kubernetes.io/docs/concepts/configuration/secret - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__dc75a614004131c047322f90f10784835a1f3438fc40eba549cef8b51c8279a7) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeSecretListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeSecretProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.core.v1.SecretList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: Items is a list of secret objects. More info: https://kubernetes.io/docs/concepts/configuration/secret - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - ''' - props = KubeSecretListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.core.v1.SecretList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeSecretListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeSecretListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeSecretProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''SecretList is a list of Secret. - - :param items: Items is a list of secret objects. More info: https://kubernetes.io/docs/concepts/configuration/secret - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.core.v1.SecretList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__68a713428aa6f657fd246ae3b43b8fa8e61bb28094b94473804b537cbefbc6ec) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeSecretProps"]: - '''Items is a list of secret objects. - - More info: https://kubernetes.io/docs/concepts/configuration/secret - - :schema: io.k8s.api.core.v1.SecretList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeSecretProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.core.v1.SecretList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeSecretListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubeSecretProps", - jsii_struct_bases=[], - name_mapping={ - "data": "data", - "immutable": "immutable", - "metadata": "metadata", - "string_data": "stringData", - "type": "type", - }, -) -class KubeSecretProps: - def __init__( - self, - *, - data: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - immutable: typing.Optional[builtins.bool] = None, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - string_data: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - type: typing.Optional[builtins.str] = None, - ) -> None: - '''Secret holds secret data of a certain type. - - The total bytes of the values in the Data field must be less than MaxSecretSize bytes. - - :param data: Data contains the secret data. Each key must consist of alphanumeric characters, '-', '_' or '.'. The serialized form of the secret data is a base64 encoded string, representing the arbitrary (possibly non-string) data value here. Described in https://tools.ietf.org/html/rfc4648#section-4 - :param immutable: Immutable, if set to true, ensures that data stored in the Secret cannot be updated (only object metadata can be modified). If not set to true, the field can be modified at any time. Defaulted to nil. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param string_data: stringData allows specifying non-binary secret data in string form. It is provided as a write-only input field for convenience. All keys and values are merged into the data field on write, overwriting any existing values. The stringData field is never output when reading from the API. - :param type: Used to facilitate programmatic handling of secret data. More info: https://kubernetes.io/docs/concepts/configuration/secret/#secret-types - - :schema: io.k8s.api.core.v1.Secret - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__63ee35f74b966b919ab03aa2ea463b9251eb7bc667ff598909abc78e4bdeaea6) - check_type(argname="argument data", value=data, expected_type=type_hints["data"]) - check_type(argname="argument immutable", value=immutable, expected_type=type_hints["immutable"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument string_data", value=string_data, expected_type=type_hints["string_data"]) - check_type(argname="argument type", value=type, expected_type=type_hints["type"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if data is not None: - self._values["data"] = data - if immutable is not None: - self._values["immutable"] = immutable - if metadata is not None: - self._values["metadata"] = metadata - if string_data is not None: - self._values["string_data"] = string_data - if type is not None: - self._values["type"] = type - - @builtins.property - def data(self) -> typing.Optional[typing.Mapping[builtins.str, builtins.str]]: - '''Data contains the secret data. - - Each key must consist of alphanumeric characters, '-', '_' or '.'. The serialized form of the secret data is a base64 encoded string, representing the arbitrary (possibly non-string) data value here. Described in https://tools.ietf.org/html/rfc4648#section-4 - - :schema: io.k8s.api.core.v1.Secret#data - ''' - result = self._values.get("data") - return typing.cast(typing.Optional[typing.Mapping[builtins.str, builtins.str]], result) - - @builtins.property - def immutable(self) -> typing.Optional[builtins.bool]: - '''Immutable, if set to true, ensures that data stored in the Secret cannot be updated (only object metadata can be modified). - - If not set to true, the field can be modified at any time. Defaulted to nil. - - :schema: io.k8s.api.core.v1.Secret#immutable - ''' - result = self._values.get("immutable") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.core.v1.Secret#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def string_data( - self, - ) -> typing.Optional[typing.Mapping[builtins.str, builtins.str]]: - '''stringData allows specifying non-binary secret data in string form. - - It is provided as a write-only input field for convenience. All keys and values are merged into the data field on write, overwriting any existing values. The stringData field is never output when reading from the API. - - :schema: io.k8s.api.core.v1.Secret#stringData - ''' - result = self._values.get("string_data") - return typing.cast(typing.Optional[typing.Mapping[builtins.str, builtins.str]], result) - - @builtins.property - def type(self) -> typing.Optional[builtins.str]: - '''Used to facilitate programmatic handling of secret data. - - More info: https://kubernetes.io/docs/concepts/configuration/secret/#secret-types - - :schema: io.k8s.api.core.v1.Secret#type - ''' - result = self._values.get("type") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeSecretProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeSelfSubjectAccessReview( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeSelfSubjectAccessReview", -): - '''SelfSubjectAccessReview checks whether or the current user can perform an action. - - Not filling in a spec.namespace means "in all namespaces". Self is a special case, because users should always be able to check whether they can perform an action - - :schema: io.k8s.api.authorization.v1.SelfSubjectAccessReview - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - spec: typing.Union["SelfSubjectAccessReviewSpec", typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.authorization.v1.SelfSubjectAccessReview" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param spec: Spec holds information about the request being evaluated. user and groups must be empty - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__df9b9cd04099ed39eea458145ab91abff6e618a668a3f190dd8dd744c3510f27) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeSelfSubjectAccessReviewProps(spec=spec, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - spec: typing.Union["SelfSubjectAccessReviewSpec", typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.authorization.v1.SelfSubjectAccessReview". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param spec: Spec holds information about the request being evaluated. user and groups must be empty - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - props = KubeSelfSubjectAccessReviewProps(spec=spec, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.authorization.v1.SelfSubjectAccessReview".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeSelfSubjectAccessReviewProps", - jsii_struct_bases=[], - name_mapping={"spec": "spec", "metadata": "metadata"}, -) -class KubeSelfSubjectAccessReviewProps: - def __init__( - self, - *, - spec: typing.Union["SelfSubjectAccessReviewSpec", typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''SelfSubjectAccessReview checks whether or the current user can perform an action. - - Not filling in a spec.namespace means "in all namespaces". Self is a special case, because users should always be able to check whether they can perform an action - - :param spec: Spec holds information about the request being evaluated. user and groups must be empty - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.authorization.v1.SelfSubjectAccessReview - ''' - if isinstance(spec, dict): - spec = SelfSubjectAccessReviewSpec(**spec) - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__eb99da3761969040fbad9ae0f21de6f39fd7f9db7330ac8a2e14fd12dbe08b62) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "spec": spec, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def spec(self) -> "SelfSubjectAccessReviewSpec": - '''Spec holds information about the request being evaluated. - - user and groups must be empty - - :schema: io.k8s.api.authorization.v1.SelfSubjectAccessReview#spec - ''' - result = self._values.get("spec") - assert result is not None, "Required property 'spec' is missing" - return typing.cast("SelfSubjectAccessReviewSpec", result) - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard list metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.authorization.v1.SelfSubjectAccessReview#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeSelfSubjectAccessReviewProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeSelfSubjectReviewV1Alpha1( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeSelfSubjectReviewV1Alpha1", -): - '''SelfSubjectReview contains the user information that the kube-apiserver has about the user making this request. - - When using impersonation, users will receive the user info of the user being impersonated. - - :schema: io.k8s.api.authentication.v1alpha1.SelfSubjectReview - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.authentication.v1alpha1.SelfSubjectReview" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__dc60febb32a5f5f830b0cbfeae492a65d79ebf66796edf824b494c89482a7e3f) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeSelfSubjectReviewV1Alpha1Props(metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.authentication.v1alpha1.SelfSubjectReview". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - props = KubeSelfSubjectReviewV1Alpha1Props(metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.authentication.v1alpha1.SelfSubjectReview".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeSelfSubjectReviewV1Alpha1Props", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata"}, -) -class KubeSelfSubjectReviewV1Alpha1Props: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''SelfSubjectReview contains the user information that the kube-apiserver has about the user making this request. - - When using impersonation, users will receive the user info of the user being impersonated. - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.authentication.v1alpha1.SelfSubjectReview - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__740c60c3b930f3570c75be79b9daab533abd7ec5f3e5998f46de9d7e22d8dd90) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.authentication.v1alpha1.SelfSubjectReview#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeSelfSubjectReviewV1Alpha1Props(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeSelfSubjectRulesReview( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeSelfSubjectRulesReview", -): - '''SelfSubjectRulesReview enumerates the set of actions the current user can perform within a namespace. - - The returned list of actions may be incomplete depending on the server's authorization mode, and any errors experienced during the evaluation. SelfSubjectRulesReview should be used by UIs to show/hide actions, or to quickly let an end user reason about their permissions. It should NOT Be used by external systems to drive authorization decisions as this raises confused deputy, cache lifetime/revocation, and correctness concerns. SubjectAccessReview, and LocalAccessReview are the correct way to defer authorization decisions to the API server. - - :schema: io.k8s.api.authorization.v1.SelfSubjectRulesReview - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - spec: typing.Union["SelfSubjectRulesReviewSpec", typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.authorization.v1.SelfSubjectRulesReview" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param spec: Spec holds information about the request being evaluated. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__958ad9ca21d898b2c0171fc826e39e897cf8dea21c3e45749b9459904cb9d316) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeSelfSubjectRulesReviewProps(spec=spec, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - spec: typing.Union["SelfSubjectRulesReviewSpec", typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.authorization.v1.SelfSubjectRulesReview". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param spec: Spec holds information about the request being evaluated. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - props = KubeSelfSubjectRulesReviewProps(spec=spec, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.authorization.v1.SelfSubjectRulesReview".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeSelfSubjectRulesReviewProps", - jsii_struct_bases=[], - name_mapping={"spec": "spec", "metadata": "metadata"}, -) -class KubeSelfSubjectRulesReviewProps: - def __init__( - self, - *, - spec: typing.Union["SelfSubjectRulesReviewSpec", typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''SelfSubjectRulesReview enumerates the set of actions the current user can perform within a namespace. - - The returned list of actions may be incomplete depending on the server's authorization mode, and any errors experienced during the evaluation. SelfSubjectRulesReview should be used by UIs to show/hide actions, or to quickly let an end user reason about their permissions. It should NOT Be used by external systems to drive authorization decisions as this raises confused deputy, cache lifetime/revocation, and correctness concerns. SubjectAccessReview, and LocalAccessReview are the correct way to defer authorization decisions to the API server. - - :param spec: Spec holds information about the request being evaluated. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.authorization.v1.SelfSubjectRulesReview - ''' - if isinstance(spec, dict): - spec = SelfSubjectRulesReviewSpec(**spec) - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__28a64acd86978440d745bb1246cc04b86d29d6d85116e22b178d1054e6389b67) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "spec": spec, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def spec(self) -> "SelfSubjectRulesReviewSpec": - '''Spec holds information about the request being evaluated. - - :schema: io.k8s.api.authorization.v1.SelfSubjectRulesReview#spec - ''' - result = self._values.get("spec") - assert result is not None, "Required property 'spec' is missing" - return typing.cast("SelfSubjectRulesReviewSpec", result) - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard list metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.authorization.v1.SelfSubjectRulesReview#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeSelfSubjectRulesReviewProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeService( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeService", -): - '''Service is a named abstraction of software service (for example, mysql) consisting of local port (for example 3306) that the proxy listens on, and the selector that determines which pods will answer requests sent through the proxy. - - :schema: io.k8s.api.core.v1.Service - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["ServiceSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.core.v1.Service" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Spec defines the behavior of a service. https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__ae5267509ab57695c0bcbad4782a5c278f89e6749acf2e274e7fef884ff7c154) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeServiceProps(metadata=metadata, spec=spec) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["ServiceSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.core.v1.Service". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Spec defines the behavior of a service. https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - ''' - props = KubeServiceProps(metadata=metadata, spec=spec) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.core.v1.Service".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubeServiceAccount( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeServiceAccount", -): - '''ServiceAccount binds together: * a name, understood by users, and perhaps by peripheral systems, for an identity * a principal that can be authenticated and authorized * a set of secrets. - - :schema: io.k8s.api.core.v1.ServiceAccount - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - automount_service_account_token: typing.Optional[builtins.bool] = None, - image_pull_secrets: typing.Optional[typing.Sequence[typing.Union["LocalObjectReference", typing.Dict[builtins.str, typing.Any]]]] = None, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - secrets: typing.Optional[typing.Sequence[typing.Union["ObjectReference", typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''Defines a "io.k8s.api.core.v1.ServiceAccount" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param automount_service_account_token: AutomountServiceAccountToken indicates whether pods running as this service account should have an API token automatically mounted. Can be overridden at the pod level. - :param image_pull_secrets: ImagePullSecrets is a list of references to secrets in the same namespace to use for pulling any images in pods that reference this ServiceAccount. ImagePullSecrets are distinct from Secrets because Secrets can be mounted in the pod, but ImagePullSecrets are only accessed by the kubelet. More info: https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param secrets: Secrets is a list of the secrets in the same namespace that pods running using this ServiceAccount are allowed to use. Pods are only limited to this list if this service account has a "kubernetes.io/enforce-mountable-secrets" annotation set to "true". This field should not be used to find auto-generated service account token secrets for use outside of pods. Instead, tokens can be requested directly using the TokenRequest API, or service account token secrets can be manually created. More info: https://kubernetes.io/docs/concepts/configuration/secret - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__e5e237c758b7687f05aeba33ce7b5312826313f3a39706ad9f17b91865051abf) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeServiceAccountProps( - automount_service_account_token=automount_service_account_token, - image_pull_secrets=image_pull_secrets, - metadata=metadata, - secrets=secrets, - ) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - automount_service_account_token: typing.Optional[builtins.bool] = None, - image_pull_secrets: typing.Optional[typing.Sequence[typing.Union["LocalObjectReference", typing.Dict[builtins.str, typing.Any]]]] = None, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - secrets: typing.Optional[typing.Sequence[typing.Union["ObjectReference", typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.core.v1.ServiceAccount". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param automount_service_account_token: AutomountServiceAccountToken indicates whether pods running as this service account should have an API token automatically mounted. Can be overridden at the pod level. - :param image_pull_secrets: ImagePullSecrets is a list of references to secrets in the same namespace to use for pulling any images in pods that reference this ServiceAccount. ImagePullSecrets are distinct from Secrets because Secrets can be mounted in the pod, but ImagePullSecrets are only accessed by the kubelet. More info: https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param secrets: Secrets is a list of the secrets in the same namespace that pods running using this ServiceAccount are allowed to use. Pods are only limited to this list if this service account has a "kubernetes.io/enforce-mountable-secrets" annotation set to "true". This field should not be used to find auto-generated service account token secrets for use outside of pods. Instead, tokens can be requested directly using the TokenRequest API, or service account token secrets can be manually created. More info: https://kubernetes.io/docs/concepts/configuration/secret - ''' - props = KubeServiceAccountProps( - automount_service_account_token=automount_service_account_token, - image_pull_secrets=image_pull_secrets, - metadata=metadata, - secrets=secrets, - ) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.core.v1.ServiceAccount".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubeServiceAccountList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeServiceAccountList", -): - '''ServiceAccountList is a list of ServiceAccount objects. - - :schema: io.k8s.api.core.v1.ServiceAccountList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeServiceAccountProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.core.v1.ServiceAccountList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: List of ServiceAccounts. More info: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__f86f64fd2fbbd19af1e77f68fedbf039aee41aa5d18ecc31b5ef98921f5a8a25) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeServiceAccountListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeServiceAccountProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.core.v1.ServiceAccountList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: List of ServiceAccounts. More info: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - ''' - props = KubeServiceAccountListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.core.v1.ServiceAccountList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeServiceAccountListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeServiceAccountListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeServiceAccountProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''ServiceAccountList is a list of ServiceAccount objects. - - :param items: List of ServiceAccounts. More info: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.core.v1.ServiceAccountList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__643831477ea8dbd90061f7f5cc95e1a83af9e4fdad06f1b94b48253d8f32f842) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeServiceAccountProps"]: - '''List of ServiceAccounts. - - More info: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ - - :schema: io.k8s.api.core.v1.ServiceAccountList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeServiceAccountProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.core.v1.ServiceAccountList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeServiceAccountListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubeServiceAccountProps", - jsii_struct_bases=[], - name_mapping={ - "automount_service_account_token": "automountServiceAccountToken", - "image_pull_secrets": "imagePullSecrets", - "metadata": "metadata", - "secrets": "secrets", - }, -) -class KubeServiceAccountProps: - def __init__( - self, - *, - automount_service_account_token: typing.Optional[builtins.bool] = None, - image_pull_secrets: typing.Optional[typing.Sequence[typing.Union["LocalObjectReference", typing.Dict[builtins.str, typing.Any]]]] = None, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - secrets: typing.Optional[typing.Sequence[typing.Union["ObjectReference", typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''ServiceAccount binds together: * a name, understood by users, and perhaps by peripheral systems, for an identity * a principal that can be authenticated and authorized * a set of secrets. - - :param automount_service_account_token: AutomountServiceAccountToken indicates whether pods running as this service account should have an API token automatically mounted. Can be overridden at the pod level. - :param image_pull_secrets: ImagePullSecrets is a list of references to secrets in the same namespace to use for pulling any images in pods that reference this ServiceAccount. ImagePullSecrets are distinct from Secrets because Secrets can be mounted in the pod, but ImagePullSecrets are only accessed by the kubelet. More info: https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param secrets: Secrets is a list of the secrets in the same namespace that pods running using this ServiceAccount are allowed to use. Pods are only limited to this list if this service account has a "kubernetes.io/enforce-mountable-secrets" annotation set to "true". This field should not be used to find auto-generated service account token secrets for use outside of pods. Instead, tokens can be requested directly using the TokenRequest API, or service account token secrets can be manually created. More info: https://kubernetes.io/docs/concepts/configuration/secret - - :schema: io.k8s.api.core.v1.ServiceAccount - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__ec9a6be9029d2ceb1c08d223e9b02d893a24441944fdbe9ad2eaa60dc6e92fb8) - check_type(argname="argument automount_service_account_token", value=automount_service_account_token, expected_type=type_hints["automount_service_account_token"]) - check_type(argname="argument image_pull_secrets", value=image_pull_secrets, expected_type=type_hints["image_pull_secrets"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument secrets", value=secrets, expected_type=type_hints["secrets"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if automount_service_account_token is not None: - self._values["automount_service_account_token"] = automount_service_account_token - if image_pull_secrets is not None: - self._values["image_pull_secrets"] = image_pull_secrets - if metadata is not None: - self._values["metadata"] = metadata - if secrets is not None: - self._values["secrets"] = secrets - - @builtins.property - def automount_service_account_token(self) -> typing.Optional[builtins.bool]: - '''AutomountServiceAccountToken indicates whether pods running as this service account should have an API token automatically mounted. - - Can be overridden at the pod level. - - :schema: io.k8s.api.core.v1.ServiceAccount#automountServiceAccountToken - ''' - result = self._values.get("automount_service_account_token") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def image_pull_secrets( - self, - ) -> typing.Optional[typing.List["LocalObjectReference"]]: - '''ImagePullSecrets is a list of references to secrets in the same namespace to use for pulling any images in pods that reference this ServiceAccount. - - ImagePullSecrets are distinct from Secrets because Secrets can be mounted in the pod, but ImagePullSecrets are only accessed by the kubelet. More info: https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod - - :schema: io.k8s.api.core.v1.ServiceAccount#imagePullSecrets - ''' - result = self._values.get("image_pull_secrets") - return typing.cast(typing.Optional[typing.List["LocalObjectReference"]], result) - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.core.v1.ServiceAccount#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def secrets(self) -> typing.Optional[typing.List["ObjectReference"]]: - '''Secrets is a list of the secrets in the same namespace that pods running using this ServiceAccount are allowed to use. - - Pods are only limited to this list if this service account has a "kubernetes.io/enforce-mountable-secrets" annotation set to "true". This field should not be used to find auto-generated service account token secrets for use outside of pods. Instead, tokens can be requested directly using the TokenRequest API, or service account token secrets can be manually created. More info: https://kubernetes.io/docs/concepts/configuration/secret - - :schema: io.k8s.api.core.v1.ServiceAccount#secrets - ''' - result = self._values.get("secrets") - return typing.cast(typing.Optional[typing.List["ObjectReference"]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeServiceAccountProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeServiceList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeServiceList", -): - '''ServiceList holds a list of services. - - :schema: io.k8s.api.core.v1.ServiceList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeServiceProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.core.v1.ServiceList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: List of services. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__86886b0bfb469dbc12b9a68cef4da02889f1ee314d709a8e71414cc8031cfed6) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeServiceListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeServiceProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.core.v1.ServiceList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: List of services. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - ''' - props = KubeServiceListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.core.v1.ServiceList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeServiceListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeServiceListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeServiceProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''ServiceList holds a list of services. - - :param items: List of services. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.core.v1.ServiceList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__59198a82aa11d0d9508f7dc568777e1717191f7b72d24ffdc52ce442de8d3c85) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeServiceProps"]: - '''List of services. - - :schema: io.k8s.api.core.v1.ServiceList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeServiceProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.core.v1.ServiceList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeServiceListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubeServiceProps", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata", "spec": "spec"}, -) -class KubeServiceProps: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["ServiceSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Service is a named abstraction of software service (for example, mysql) consisting of local port (for example 3306) that the proxy listens on, and the selector that determines which pods will answer requests sent through the proxy. - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Spec defines the behavior of a service. https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.core.v1.Service - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if isinstance(spec, dict): - spec = ServiceSpec(**spec) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__645975c208c0e6b41f85f3d3300b485fbb81771422750ddca1d83f18801e711c) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - if spec is not None: - self._values["spec"] = spec - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.core.v1.Service#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def spec(self) -> typing.Optional["ServiceSpec"]: - '''Spec defines the behavior of a service. - - https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.core.v1.Service#spec - ''' - result = self._values.get("spec") - return typing.cast(typing.Optional["ServiceSpec"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeServiceProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeStatefulSet( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeStatefulSet", -): - '''StatefulSet represents a set of pods with consistent identities. - - Identities are defined as: - - - Network: A single stable DNS and hostname. - - Storage: As many VolumeClaims as requested. - - The StatefulSet guarantees that a given network identity will always map to the same storage identity. - - :schema: io.k8s.api.apps.v1.StatefulSet - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["StatefulSetSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.apps.v1.StatefulSet" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Spec defines the desired identities of pods in this set. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__312da024b0ac59942da22a6230187a87d3bbc5ff2eced525e6d591ec5c4ac0fd) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeStatefulSetProps(metadata=metadata, spec=spec) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["StatefulSetSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.apps.v1.StatefulSet". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Spec defines the desired identities of pods in this set. - ''' - props = KubeStatefulSetProps(metadata=metadata, spec=spec) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.apps.v1.StatefulSet".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubeStatefulSetList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeStatefulSetList", -): - '''StatefulSetList is a collection of StatefulSets. - - :schema: io.k8s.api.apps.v1.StatefulSetList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeStatefulSetProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.apps.v1.StatefulSetList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: Items is the list of stateful sets. - :param metadata: Standard list's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__8c61b86fcbbb88c288e62d1aeb4e69b71ab9619771039bf5b77239a716db57dd) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeStatefulSetListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeStatefulSetProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.apps.v1.StatefulSetList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: Items is the list of stateful sets. - :param metadata: Standard list's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - props = KubeStatefulSetListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.apps.v1.StatefulSetList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeStatefulSetListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeStatefulSetListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeStatefulSetProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''StatefulSetList is a collection of StatefulSets. - - :param items: Items is the list of stateful sets. - :param metadata: Standard list's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.apps.v1.StatefulSetList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__860181d5582a30497e3a5c2f4a313c6a4b92df72cfab5a28201a1e2c12cdd5d5) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeStatefulSetProps"]: - '''Items is the list of stateful sets. - - :schema: io.k8s.api.apps.v1.StatefulSetList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeStatefulSetProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.apps.v1.StatefulSetList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeStatefulSetListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubeStatefulSetProps", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata", "spec": "spec"}, -) -class KubeStatefulSetProps: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["StatefulSetSpec", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''StatefulSet represents a set of pods with consistent identities. - - Identities are defined as: - - - Network: A single stable DNS and hostname. - - Storage: As many VolumeClaims as requested. - - The StatefulSet guarantees that a given network identity will always map to the same storage identity. - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Spec defines the desired identities of pods in this set. - - :schema: io.k8s.api.apps.v1.StatefulSet - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if isinstance(spec, dict): - spec = StatefulSetSpec(**spec) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__9415c25af12fba9cb563f49680ded90088a786ca6ef171beb298495032382794) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - if spec is not None: - self._values["spec"] = spec - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.apps.v1.StatefulSet#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def spec(self) -> typing.Optional["StatefulSetSpec"]: - '''Spec defines the desired identities of pods in this set. - - :schema: io.k8s.api.apps.v1.StatefulSet#spec - ''' - result = self._values.get("spec") - return typing.cast(typing.Optional["StatefulSetSpec"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeStatefulSetProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeStatus( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeStatus", -): - '''Status is a return value for calls that don't return other objects. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.Status - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - code: typing.Optional[jsii.Number] = None, - details: typing.Optional[typing.Union["StatusDetails", typing.Dict[builtins.str, typing.Any]]] = None, - message: typing.Optional[builtins.str] = None, - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - reason: typing.Optional[builtins.str] = None, - ) -> None: - '''Defines a "io.k8s.apimachinery.pkg.apis.meta.v1.Status" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param code: Suggested HTTP return code for this status, 0 if not set. - :param details: Extended data associated with the reason. Each reason may define its own extended details. This field is optional and the data returned is not guaranteed to conform to any schema except that defined by the reason type. - :param message: A human-readable description of the status of this operation. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - :param reason: A machine-readable description of why this operation is in the "Failure" status. If this value is empty there is no information available. A Reason clarifies an HTTP status code but does not override it. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__5cd6f81cf090a4033a6f747068175ccdd01d276de8560fa979a1eea0da875d99) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeStatusProps( - code=code, - details=details, - message=message, - metadata=metadata, - reason=reason, - ) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - code: typing.Optional[jsii.Number] = None, - details: typing.Optional[typing.Union["StatusDetails", typing.Dict[builtins.str, typing.Any]]] = None, - message: typing.Optional[builtins.str] = None, - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - reason: typing.Optional[builtins.str] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.apimachinery.pkg.apis.meta.v1.Status". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param code: Suggested HTTP return code for this status, 0 if not set. - :param details: Extended data associated with the reason. Each reason may define its own extended details. This field is optional and the data returned is not guaranteed to conform to any schema except that defined by the reason type. - :param message: A human-readable description of the status of this operation. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - :param reason: A machine-readable description of why this operation is in the "Failure" status. If this value is empty there is no information available. A Reason clarifies an HTTP status code but does not override it. - ''' - props = KubeStatusProps( - code=code, - details=details, - message=message, - metadata=metadata, - reason=reason, - ) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.apimachinery.pkg.apis.meta.v1.Status".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeStatusProps", - jsii_struct_bases=[], - name_mapping={ - "code": "code", - "details": "details", - "message": "message", - "metadata": "metadata", - "reason": "reason", - }, -) -class KubeStatusProps: - def __init__( - self, - *, - code: typing.Optional[jsii.Number] = None, - details: typing.Optional[typing.Union["StatusDetails", typing.Dict[builtins.str, typing.Any]]] = None, - message: typing.Optional[builtins.str] = None, - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - reason: typing.Optional[builtins.str] = None, - ) -> None: - '''Status is a return value for calls that don't return other objects. - - :param code: Suggested HTTP return code for this status, 0 if not set. - :param details: Extended data associated with the reason. Each reason may define its own extended details. This field is optional and the data returned is not guaranteed to conform to any schema except that defined by the reason type. - :param message: A human-readable description of the status of this operation. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - :param reason: A machine-readable description of why this operation is in the "Failure" status. If this value is empty there is no information available. A Reason clarifies an HTTP status code but does not override it. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.Status - ''' - if isinstance(details, dict): - details = StatusDetails(**details) - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__4143b0ac58cd2ed3e56cba31c073cbc2ecd0f798e3c8eba8c4aa27bf03019254) - check_type(argname="argument code", value=code, expected_type=type_hints["code"]) - check_type(argname="argument details", value=details, expected_type=type_hints["details"]) - check_type(argname="argument message", value=message, expected_type=type_hints["message"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument reason", value=reason, expected_type=type_hints["reason"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if code is not None: - self._values["code"] = code - if details is not None: - self._values["details"] = details - if message is not None: - self._values["message"] = message - if metadata is not None: - self._values["metadata"] = metadata - if reason is not None: - self._values["reason"] = reason - - @builtins.property - def code(self) -> typing.Optional[jsii.Number]: - '''Suggested HTTP return code for this status, 0 if not set. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.Status#code - ''' - result = self._values.get("code") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def details(self) -> typing.Optional["StatusDetails"]: - '''Extended data associated with the reason. - - Each reason may define its own extended details. This field is optional and the data returned is not guaranteed to conform to any schema except that defined by the reason type. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.Status#details - ''' - result = self._values.get("details") - return typing.cast(typing.Optional["StatusDetails"], result) - - @builtins.property - def message(self) -> typing.Optional[builtins.str]: - '''A human-readable description of the status of this operation. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.Status#message - ''' - result = self._values.get("message") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.Status#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - @builtins.property - def reason(self) -> typing.Optional[builtins.str]: - '''A machine-readable description of why this operation is in the "Failure" status. - - If this value is empty there is no information available. A Reason clarifies an HTTP status code but does not override it. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.Status#reason - ''' - result = self._values.get("reason") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeStatusProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeStorageClass( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeStorageClass", -): - '''StorageClass describes the parameters for a class of storage for which PersistentVolumes can be dynamically provisioned. - - StorageClasses are non-namespaced; the name of the storage class according to etcd is in ObjectMeta.Name. - - :schema: io.k8s.api.storage.v1.StorageClass - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - provisioner: builtins.str, - allowed_topologies: typing.Optional[typing.Sequence[typing.Union["TopologySelectorTerm", typing.Dict[builtins.str, typing.Any]]]] = None, - allow_volume_expansion: typing.Optional[builtins.bool] = None, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - mount_options: typing.Optional[typing.Sequence[builtins.str]] = None, - parameters: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - reclaim_policy: typing.Optional[builtins.str] = None, - volume_binding_mode: typing.Optional[builtins.str] = None, - ) -> None: - '''Defines a "io.k8s.api.storage.v1.StorageClass" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param provisioner: Provisioner indicates the type of the provisioner. - :param allowed_topologies: Restrict the node topologies where volumes can be dynamically provisioned. Each volume plugin defines its own supported topology specifications. An empty TopologySelectorTerm list means there is no topology restriction. This field is only honored by servers that enable the VolumeScheduling feature. - :param allow_volume_expansion: AllowVolumeExpansion shows whether the storage class allow volume expand. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param mount_options: Dynamically provisioned PersistentVolumes of this storage class are created with these mountOptions, e.g. ["ro", "soft"]. Not validated - mount of the PVs will simply fail if one is invalid. - :param parameters: Parameters holds the parameters for the provisioner that should create volumes of this storage class. - :param reclaim_policy: Dynamically provisioned PersistentVolumes of this storage class are created with this reclaimPolicy. Defaults to Delete. Default: Delete. - :param volume_binding_mode: VolumeBindingMode indicates how PersistentVolumeClaims should be provisioned and bound. When unset, VolumeBindingImmediate is used. This field is only honored by servers that enable the VolumeScheduling feature. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__047df7981d1ae82b04f2e59adc1e0b713c54c65e95598c90ab39efd0bbcffb11) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeStorageClassProps( - provisioner=provisioner, - allowed_topologies=allowed_topologies, - allow_volume_expansion=allow_volume_expansion, - metadata=metadata, - mount_options=mount_options, - parameters=parameters, - reclaim_policy=reclaim_policy, - volume_binding_mode=volume_binding_mode, - ) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - provisioner: builtins.str, - allowed_topologies: typing.Optional[typing.Sequence[typing.Union["TopologySelectorTerm", typing.Dict[builtins.str, typing.Any]]]] = None, - allow_volume_expansion: typing.Optional[builtins.bool] = None, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - mount_options: typing.Optional[typing.Sequence[builtins.str]] = None, - parameters: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - reclaim_policy: typing.Optional[builtins.str] = None, - volume_binding_mode: typing.Optional[builtins.str] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.storage.v1.StorageClass". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param provisioner: Provisioner indicates the type of the provisioner. - :param allowed_topologies: Restrict the node topologies where volumes can be dynamically provisioned. Each volume plugin defines its own supported topology specifications. An empty TopologySelectorTerm list means there is no topology restriction. This field is only honored by servers that enable the VolumeScheduling feature. - :param allow_volume_expansion: AllowVolumeExpansion shows whether the storage class allow volume expand. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param mount_options: Dynamically provisioned PersistentVolumes of this storage class are created with these mountOptions, e.g. ["ro", "soft"]. Not validated - mount of the PVs will simply fail if one is invalid. - :param parameters: Parameters holds the parameters for the provisioner that should create volumes of this storage class. - :param reclaim_policy: Dynamically provisioned PersistentVolumes of this storage class are created with this reclaimPolicy. Defaults to Delete. Default: Delete. - :param volume_binding_mode: VolumeBindingMode indicates how PersistentVolumeClaims should be provisioned and bound. When unset, VolumeBindingImmediate is used. This field is only honored by servers that enable the VolumeScheduling feature. - ''' - props = KubeStorageClassProps( - provisioner=provisioner, - allowed_topologies=allowed_topologies, - allow_volume_expansion=allow_volume_expansion, - metadata=metadata, - mount_options=mount_options, - parameters=parameters, - reclaim_policy=reclaim_policy, - volume_binding_mode=volume_binding_mode, - ) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.storage.v1.StorageClass".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubeStorageClassList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeStorageClassList", -): - '''StorageClassList is a collection of storage classes. - - :schema: io.k8s.api.storage.v1.StorageClassList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeStorageClassProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.storage.v1.StorageClassList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: Items is the list of StorageClasses. - :param metadata: Standard list metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__bf39d1bbc80954512531c8ebbcfaeb459523317cb1f4375b5090a4c2a1c602f4) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeStorageClassListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeStorageClassProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.storage.v1.StorageClassList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: Items is the list of StorageClasses. - :param metadata: Standard list metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - ''' - props = KubeStorageClassListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.storage.v1.StorageClassList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeStorageClassListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeStorageClassListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeStorageClassProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''StorageClassList is a collection of storage classes. - - :param items: Items is the list of StorageClasses. - :param metadata: Standard list metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - - :schema: io.k8s.api.storage.v1.StorageClassList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__036f96145bee86ebfca9cb6d6479755dc2a261bf7c08a4d2e572d758d0005bf5) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeStorageClassProps"]: - '''Items is the list of StorageClasses. - - :schema: io.k8s.api.storage.v1.StorageClassList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeStorageClassProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - - :schema: io.k8s.api.storage.v1.StorageClassList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeStorageClassListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubeStorageClassProps", - jsii_struct_bases=[], - name_mapping={ - "provisioner": "provisioner", - "allowed_topologies": "allowedTopologies", - "allow_volume_expansion": "allowVolumeExpansion", - "metadata": "metadata", - "mount_options": "mountOptions", - "parameters": "parameters", - "reclaim_policy": "reclaimPolicy", - "volume_binding_mode": "volumeBindingMode", - }, -) -class KubeStorageClassProps: - def __init__( - self, - *, - provisioner: builtins.str, - allowed_topologies: typing.Optional[typing.Sequence[typing.Union["TopologySelectorTerm", typing.Dict[builtins.str, typing.Any]]]] = None, - allow_volume_expansion: typing.Optional[builtins.bool] = None, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - mount_options: typing.Optional[typing.Sequence[builtins.str]] = None, - parameters: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - reclaim_policy: typing.Optional[builtins.str] = None, - volume_binding_mode: typing.Optional[builtins.str] = None, - ) -> None: - '''StorageClass describes the parameters for a class of storage for which PersistentVolumes can be dynamically provisioned. - - StorageClasses are non-namespaced; the name of the storage class according to etcd is in ObjectMeta.Name. - - :param provisioner: Provisioner indicates the type of the provisioner. - :param allowed_topologies: Restrict the node topologies where volumes can be dynamically provisioned. Each volume plugin defines its own supported topology specifications. An empty TopologySelectorTerm list means there is no topology restriction. This field is only honored by servers that enable the VolumeScheduling feature. - :param allow_volume_expansion: AllowVolumeExpansion shows whether the storage class allow volume expand. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param mount_options: Dynamically provisioned PersistentVolumes of this storage class are created with these mountOptions, e.g. ["ro", "soft"]. Not validated - mount of the PVs will simply fail if one is invalid. - :param parameters: Parameters holds the parameters for the provisioner that should create volumes of this storage class. - :param reclaim_policy: Dynamically provisioned PersistentVolumes of this storage class are created with this reclaimPolicy. Defaults to Delete. Default: Delete. - :param volume_binding_mode: VolumeBindingMode indicates how PersistentVolumeClaims should be provisioned and bound. When unset, VolumeBindingImmediate is used. This field is only honored by servers that enable the VolumeScheduling feature. - - :schema: io.k8s.api.storage.v1.StorageClass - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__3697ffdc356ed18bd130e122d368bb18f095fa7f9f60844c7c50e565931d0f37) - check_type(argname="argument provisioner", value=provisioner, expected_type=type_hints["provisioner"]) - check_type(argname="argument allowed_topologies", value=allowed_topologies, expected_type=type_hints["allowed_topologies"]) - check_type(argname="argument allow_volume_expansion", value=allow_volume_expansion, expected_type=type_hints["allow_volume_expansion"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument mount_options", value=mount_options, expected_type=type_hints["mount_options"]) - check_type(argname="argument parameters", value=parameters, expected_type=type_hints["parameters"]) - check_type(argname="argument reclaim_policy", value=reclaim_policy, expected_type=type_hints["reclaim_policy"]) - check_type(argname="argument volume_binding_mode", value=volume_binding_mode, expected_type=type_hints["volume_binding_mode"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "provisioner": provisioner, - } - if allowed_topologies is not None: - self._values["allowed_topologies"] = allowed_topologies - if allow_volume_expansion is not None: - self._values["allow_volume_expansion"] = allow_volume_expansion - if metadata is not None: - self._values["metadata"] = metadata - if mount_options is not None: - self._values["mount_options"] = mount_options - if parameters is not None: - self._values["parameters"] = parameters - if reclaim_policy is not None: - self._values["reclaim_policy"] = reclaim_policy - if volume_binding_mode is not None: - self._values["volume_binding_mode"] = volume_binding_mode - - @builtins.property - def provisioner(self) -> builtins.str: - '''Provisioner indicates the type of the provisioner. - - :schema: io.k8s.api.storage.v1.StorageClass#provisioner - ''' - result = self._values.get("provisioner") - assert result is not None, "Required property 'provisioner' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def allowed_topologies( - self, - ) -> typing.Optional[typing.List["TopologySelectorTerm"]]: - '''Restrict the node topologies where volumes can be dynamically provisioned. - - Each volume plugin defines its own supported topology specifications. An empty TopologySelectorTerm list means there is no topology restriction. This field is only honored by servers that enable the VolumeScheduling feature. - - :schema: io.k8s.api.storage.v1.StorageClass#allowedTopologies - ''' - result = self._values.get("allowed_topologies") - return typing.cast(typing.Optional[typing.List["TopologySelectorTerm"]], result) - - @builtins.property - def allow_volume_expansion(self) -> typing.Optional[builtins.bool]: - '''AllowVolumeExpansion shows whether the storage class allow volume expand. - - :schema: io.k8s.api.storage.v1.StorageClass#allowVolumeExpansion - ''' - result = self._values.get("allow_volume_expansion") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.storage.v1.StorageClass#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def mount_options(self) -> typing.Optional[typing.List[builtins.str]]: - '''Dynamically provisioned PersistentVolumes of this storage class are created with these mountOptions, e.g. ["ro", "soft"]. Not validated - mount of the PVs will simply fail if one is invalid. - - :schema: io.k8s.api.storage.v1.StorageClass#mountOptions - ''' - result = self._values.get("mount_options") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def parameters(self) -> typing.Optional[typing.Mapping[builtins.str, builtins.str]]: - '''Parameters holds the parameters for the provisioner that should create volumes of this storage class. - - :schema: io.k8s.api.storage.v1.StorageClass#parameters - ''' - result = self._values.get("parameters") - return typing.cast(typing.Optional[typing.Mapping[builtins.str, builtins.str]], result) - - @builtins.property - def reclaim_policy(self) -> typing.Optional[builtins.str]: - '''Dynamically provisioned PersistentVolumes of this storage class are created with this reclaimPolicy. - - Defaults to Delete. - - :default: Delete. - - :schema: io.k8s.api.storage.v1.StorageClass#reclaimPolicy - ''' - result = self._values.get("reclaim_policy") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def volume_binding_mode(self) -> typing.Optional[builtins.str]: - '''VolumeBindingMode indicates how PersistentVolumeClaims should be provisioned and bound. - - When unset, VolumeBindingImmediate is used. This field is only honored by servers that enable the VolumeScheduling feature. - - :schema: io.k8s.api.storage.v1.StorageClass#volumeBindingMode - ''' - result = self._values.get("volume_binding_mode") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeStorageClassProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeStorageVersionListV1Alpha1( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeStorageVersionListV1Alpha1", -): - '''A list of StorageVersions. - - :schema: io.k8s.api.apiserverinternal.v1alpha1.StorageVersionList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeStorageVersionV1Alpha1Props", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.apiserverinternal.v1alpha1.StorageVersionList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: Items holds a list of StorageVersion. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__6bef958a387947bcbcdbaaf4348094be86a7afa3a9acd45c6af4fa3f17a69374) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeStorageVersionListV1Alpha1Props(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeStorageVersionV1Alpha1Props", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.apiserverinternal.v1alpha1.StorageVersionList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: Items holds a list of StorageVersion. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - props = KubeStorageVersionListV1Alpha1Props(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.apiserverinternal.v1alpha1.StorageVersionList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeStorageVersionListV1Alpha1Props", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeStorageVersionListV1Alpha1Props: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeStorageVersionV1Alpha1Props", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''A list of StorageVersions. - - :param items: Items holds a list of StorageVersion. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.apiserverinternal.v1alpha1.StorageVersionList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__19ee4dcbe1aeb266f148e1052692cd8958a0190c04daee972cd1b30ba28ce226) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeStorageVersionV1Alpha1Props"]: - '''Items holds a list of StorageVersion. - - :schema: io.k8s.api.apiserverinternal.v1alpha1.StorageVersionList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeStorageVersionV1Alpha1Props"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.apiserverinternal.v1alpha1.StorageVersionList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeStorageVersionListV1Alpha1Props(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeStorageVersionV1Alpha1( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeStorageVersionV1Alpha1", -): - '''Storage version of a specific resource. - - :schema: io.k8s.api.apiserverinternal.v1alpha1.StorageVersion - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - spec: typing.Any, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.apiserverinternal.v1alpha1.StorageVersion" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param spec: Spec is an empty spec. It is here to comply with Kubernetes API style. - :param metadata: The name is .. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__cc83b314c4364ad0b9556dfaf2c46909a2a42787e7446c3f1febc8414b884180) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeStorageVersionV1Alpha1Props(spec=spec, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - spec: typing.Any, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.apiserverinternal.v1alpha1.StorageVersion". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param spec: Spec is an empty spec. It is here to comply with Kubernetes API style. - :param metadata: The name is .. - ''' - props = KubeStorageVersionV1Alpha1Props(spec=spec, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.apiserverinternal.v1alpha1.StorageVersion".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeStorageVersionV1Alpha1Props", - jsii_struct_bases=[], - name_mapping={"spec": "spec", "metadata": "metadata"}, -) -class KubeStorageVersionV1Alpha1Props: - def __init__( - self, - *, - spec: typing.Any, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Storage version of a specific resource. - - :param spec: Spec is an empty spec. It is here to comply with Kubernetes API style. - :param metadata: The name is .. - - :schema: io.k8s.api.apiserverinternal.v1alpha1.StorageVersion - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__ce0ae7328893e918f22537ca4ff18691995679aa30d67b8739ecb52c8707ba18) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "spec": spec, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def spec(self) -> typing.Any: - '''Spec is an empty spec. - - It is here to comply with Kubernetes API style. - - :schema: io.k8s.api.apiserverinternal.v1alpha1.StorageVersion#spec - ''' - result = self._values.get("spec") - assert result is not None, "Required property 'spec' is missing" - return typing.cast(typing.Any, result) - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''The name is .. - - :schema: io.k8s.api.apiserverinternal.v1alpha1.StorageVersion#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeStorageVersionV1Alpha1Props(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeSubjectAccessReview( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeSubjectAccessReview", -): - '''SubjectAccessReview checks whether or not a user or group can perform an action. - - :schema: io.k8s.api.authorization.v1.SubjectAccessReview - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - spec: typing.Union["SubjectAccessReviewSpec", typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.authorization.v1.SubjectAccessReview" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param spec: Spec holds information about the request being evaluated. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__37315244b0b06d4a6c0153890d8b113b5be8f7e3f4a53706dc5bc0f2430750e9) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeSubjectAccessReviewProps(spec=spec, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - spec: typing.Union["SubjectAccessReviewSpec", typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.authorization.v1.SubjectAccessReview". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param spec: Spec holds information about the request being evaluated. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - props = KubeSubjectAccessReviewProps(spec=spec, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.authorization.v1.SubjectAccessReview".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeSubjectAccessReviewProps", - jsii_struct_bases=[], - name_mapping={"spec": "spec", "metadata": "metadata"}, -) -class KubeSubjectAccessReviewProps: - def __init__( - self, - *, - spec: typing.Union["SubjectAccessReviewSpec", typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''SubjectAccessReview checks whether or not a user or group can perform an action. - - :param spec: Spec holds information about the request being evaluated. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.authorization.v1.SubjectAccessReview - ''' - if isinstance(spec, dict): - spec = SubjectAccessReviewSpec(**spec) - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__11cdd3c28c7b3734c17f57f7700873f376c05d84eb4ac3686850aba44049b917) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "spec": spec, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def spec(self) -> "SubjectAccessReviewSpec": - '''Spec holds information about the request being evaluated. - - :schema: io.k8s.api.authorization.v1.SubjectAccessReview#spec - ''' - result = self._values.get("spec") - assert result is not None, "Required property 'spec' is missing" - return typing.cast("SubjectAccessReviewSpec", result) - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard list metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.authorization.v1.SubjectAccessReview#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeSubjectAccessReviewProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeTokenRequest( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeTokenRequest", -): - '''TokenRequest requests a token for a given service account. - - :schema: io.k8s.api.authentication.v1.TokenRequest - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - spec: typing.Union["TokenRequestSpec", typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.authentication.v1.TokenRequest" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param spec: Spec holds information about the request being evaluated. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__474147e21deffaa53de4be8235f1e51831b183ee5ffadd3666a10e29d2a2f678) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeTokenRequestProps(spec=spec, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - spec: typing.Union["TokenRequestSpec", typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.authentication.v1.TokenRequest". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param spec: Spec holds information about the request being evaluated. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - props = KubeTokenRequestProps(spec=spec, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.authentication.v1.TokenRequest".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeTokenRequestProps", - jsii_struct_bases=[], - name_mapping={"spec": "spec", "metadata": "metadata"}, -) -class KubeTokenRequestProps: - def __init__( - self, - *, - spec: typing.Union["TokenRequestSpec", typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''TokenRequest requests a token for a given service account. - - :param spec: Spec holds information about the request being evaluated. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.authentication.v1.TokenRequest - ''' - if isinstance(spec, dict): - spec = TokenRequestSpec(**spec) - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__56b2d758ed6094af31246d270d662cd4cd5baa62a9a3db945fe752d8a0c8b2ba) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "spec": spec, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def spec(self) -> "TokenRequestSpec": - '''Spec holds information about the request being evaluated. - - :schema: io.k8s.api.authentication.v1.TokenRequest#spec - ''' - result = self._values.get("spec") - assert result is not None, "Required property 'spec' is missing" - return typing.cast("TokenRequestSpec", result) - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.authentication.v1.TokenRequest#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeTokenRequestProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeTokenReview( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeTokenReview", -): - '''TokenReview attempts to authenticate a token to a known user. - - Note: TokenReview requests may be cached by the webhook token authenticator plugin in the kube-apiserver. - - :schema: io.k8s.api.authentication.v1.TokenReview - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - spec: typing.Union["TokenReviewSpec", typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.authentication.v1.TokenReview" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param spec: Spec holds information about the request being evaluated. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__26b5a5f85fa4a9cd06563e623d28b06fe5cb2ff87240ba40c3ffd54a769b1b7e) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeTokenReviewProps(spec=spec, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - spec: typing.Union["TokenReviewSpec", typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.authentication.v1.TokenReview". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param spec: Spec holds information about the request being evaluated. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - props = KubeTokenReviewProps(spec=spec, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.authentication.v1.TokenReview".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeTokenReviewProps", - jsii_struct_bases=[], - name_mapping={"spec": "spec", "metadata": "metadata"}, -) -class KubeTokenReviewProps: - def __init__( - self, - *, - spec: typing.Union["TokenReviewSpec", typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''TokenReview attempts to authenticate a token to a known user. - - Note: TokenReview requests may be cached by the webhook token authenticator plugin in the kube-apiserver. - - :param spec: Spec holds information about the request being evaluated. - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.authentication.v1.TokenReview - ''' - if isinstance(spec, dict): - spec = TokenReviewSpec(**spec) - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__fdad9a9e34ccb530008909556ec697b7e32e7e75a62c0a40b2de70d6f94defa9) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "spec": spec, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def spec(self) -> "TokenReviewSpec": - '''Spec holds information about the request being evaluated. - - :schema: io.k8s.api.authentication.v1.TokenReview#spec - ''' - result = self._values.get("spec") - assert result is not None, "Required property 'spec' is missing" - return typing.cast("TokenReviewSpec", result) - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.authentication.v1.TokenReview#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeTokenReviewProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeValidatingAdmissionPolicyBindingListV1Alpha1( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeValidatingAdmissionPolicyBindingListV1Alpha1", -): - '''ValidatingAdmissionPolicyBindingList is a list of ValidatingAdmissionPolicyBinding. - - :schema: io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyBindingList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Optional[typing.Sequence[typing.Union["KubeValidatingAdmissionPolicyBindingV1Alpha1Props", typing.Dict[builtins.str, typing.Any]]]] = None, - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyBindingList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: List of PolicyBinding. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__aba7512ee266951498a04cd9a269f09706de6ad19ad3648606375a371fb62628) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeValidatingAdmissionPolicyBindingListV1Alpha1Props( - items=items, metadata=metadata - ) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Optional[typing.Sequence[typing.Union["KubeValidatingAdmissionPolicyBindingV1Alpha1Props", typing.Dict[builtins.str, typing.Any]]]] = None, - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyBindingList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: List of PolicyBinding. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - ''' - props = KubeValidatingAdmissionPolicyBindingListV1Alpha1Props( - items=items, metadata=metadata - ) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyBindingList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeValidatingAdmissionPolicyBindingListV1Alpha1Props", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeValidatingAdmissionPolicyBindingListV1Alpha1Props: - def __init__( - self, - *, - items: typing.Optional[typing.Sequence[typing.Union["KubeValidatingAdmissionPolicyBindingV1Alpha1Props", typing.Dict[builtins.str, typing.Any]]]] = None, - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''ValidatingAdmissionPolicyBindingList is a list of ValidatingAdmissionPolicyBinding. - - :param items: List of PolicyBinding. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyBindingList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__58df6ed691a95aca20efd7ea05e0fc7ba9fc3d6f3743649a0799ed2ed11983ec) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if items is not None: - self._values["items"] = items - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items( - self, - ) -> typing.Optional[typing.List["KubeValidatingAdmissionPolicyBindingV1Alpha1Props"]]: - '''List of PolicyBinding. - - :schema: io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyBindingList#items - ''' - result = self._values.get("items") - return typing.cast(typing.Optional[typing.List["KubeValidatingAdmissionPolicyBindingV1Alpha1Props"]], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyBindingList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeValidatingAdmissionPolicyBindingListV1Alpha1Props(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeValidatingAdmissionPolicyBindingV1Alpha1( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeValidatingAdmissionPolicyBindingV1Alpha1", -): - '''ValidatingAdmissionPolicyBinding binds the ValidatingAdmissionPolicy with paramerized resources. - - ValidatingAdmissionPolicyBinding and parameter CRDs together define how cluster administrators configure policies for clusters. - - :schema: io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyBinding - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["ValidatingAdmissionPolicyBindingSpecV1Alpha1", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyBinding" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param metadata: Standard object metadata; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - :param spec: Specification of the desired behavior of the ValidatingAdmissionPolicyBinding. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__56be5cfcf392871de51369cb7627d15581b617ac5c85c34c2825c7dc7b3feaf2) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeValidatingAdmissionPolicyBindingV1Alpha1Props( - metadata=metadata, spec=spec - ) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["ValidatingAdmissionPolicyBindingSpecV1Alpha1", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyBinding". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param metadata: Standard object metadata; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - :param spec: Specification of the desired behavior of the ValidatingAdmissionPolicyBinding. - ''' - props = KubeValidatingAdmissionPolicyBindingV1Alpha1Props( - metadata=metadata, spec=spec - ) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyBinding".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeValidatingAdmissionPolicyBindingV1Alpha1Props", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata", "spec": "spec"}, -) -class KubeValidatingAdmissionPolicyBindingV1Alpha1Props: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["ValidatingAdmissionPolicyBindingSpecV1Alpha1", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''ValidatingAdmissionPolicyBinding binds the ValidatingAdmissionPolicy with paramerized resources. - - ValidatingAdmissionPolicyBinding and parameter CRDs together define how cluster administrators configure policies for clusters. - - :param metadata: Standard object metadata; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - :param spec: Specification of the desired behavior of the ValidatingAdmissionPolicyBinding. - - :schema: io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyBinding - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if isinstance(spec, dict): - spec = ValidatingAdmissionPolicyBindingSpecV1Alpha1(**spec) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__02dcc69943131299a07758a92f8e2cda2225cdddcbbf84f8acd3bb912a2792da) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - if spec is not None: - self._values["spec"] = spec - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object metadata; - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - - :schema: io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyBinding#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def spec(self) -> typing.Optional["ValidatingAdmissionPolicyBindingSpecV1Alpha1"]: - '''Specification of the desired behavior of the ValidatingAdmissionPolicyBinding. - - :schema: io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyBinding#spec - ''' - result = self._values.get("spec") - return typing.cast(typing.Optional["ValidatingAdmissionPolicyBindingSpecV1Alpha1"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeValidatingAdmissionPolicyBindingV1Alpha1Props(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeValidatingAdmissionPolicyListV1Alpha1( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeValidatingAdmissionPolicyListV1Alpha1", -): - '''ValidatingAdmissionPolicyList is a list of ValidatingAdmissionPolicy. - - :schema: io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Optional[typing.Sequence[typing.Union["KubeValidatingAdmissionPolicyV1Alpha1Props", typing.Dict[builtins.str, typing.Any]]]] = None, - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: List of ValidatingAdmissionPolicy. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__5a03cdbc2d5280c7b4ec9ffb4625db7a698d7ded6744c1e54ec807bff308084f) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeValidatingAdmissionPolicyListV1Alpha1Props( - items=items, metadata=metadata - ) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Optional[typing.Sequence[typing.Union["KubeValidatingAdmissionPolicyV1Alpha1Props", typing.Dict[builtins.str, typing.Any]]]] = None, - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: List of ValidatingAdmissionPolicy. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - ''' - props = KubeValidatingAdmissionPolicyListV1Alpha1Props( - items=items, metadata=metadata - ) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeValidatingAdmissionPolicyListV1Alpha1Props", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeValidatingAdmissionPolicyListV1Alpha1Props: - def __init__( - self, - *, - items: typing.Optional[typing.Sequence[typing.Union["KubeValidatingAdmissionPolicyV1Alpha1Props", typing.Dict[builtins.str, typing.Any]]]] = None, - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''ValidatingAdmissionPolicyList is a list of ValidatingAdmissionPolicy. - - :param items: List of ValidatingAdmissionPolicy. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__27f6c645b042b326a7c234f10c50683e94fe2b281a2747e856507e896bcdba42) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if items is not None: - self._values["items"] = items - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items( - self, - ) -> typing.Optional[typing.List["KubeValidatingAdmissionPolicyV1Alpha1Props"]]: - '''List of ValidatingAdmissionPolicy. - - :schema: io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyList#items - ''' - result = self._values.get("items") - return typing.cast(typing.Optional[typing.List["KubeValidatingAdmissionPolicyV1Alpha1Props"]], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeValidatingAdmissionPolicyListV1Alpha1Props(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeValidatingAdmissionPolicyV1Alpha1( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeValidatingAdmissionPolicyV1Alpha1", -): - '''ValidatingAdmissionPolicy describes the definition of an admission validation policy that accepts or rejects an object without changing it. - - :schema: io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicy - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["ValidatingAdmissionPolicySpecV1Alpha1", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicy" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param metadata: Standard object metadata; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - :param spec: Specification of the desired behavior of the ValidatingAdmissionPolicy. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__40d71fe31ba527f1708a40aa586fc9c2850b09853dfc30d5893fce5bd4e83459) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeValidatingAdmissionPolicyV1Alpha1Props( - metadata=metadata, spec=spec - ) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["ValidatingAdmissionPolicySpecV1Alpha1", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicy". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param metadata: Standard object metadata; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - :param spec: Specification of the desired behavior of the ValidatingAdmissionPolicy. - ''' - props = KubeValidatingAdmissionPolicyV1Alpha1Props( - metadata=metadata, spec=spec - ) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicy".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeValidatingAdmissionPolicyV1Alpha1Props", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata", "spec": "spec"}, -) -class KubeValidatingAdmissionPolicyV1Alpha1Props: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union["ValidatingAdmissionPolicySpecV1Alpha1", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''ValidatingAdmissionPolicy describes the definition of an admission validation policy that accepts or rejects an object without changing it. - - :param metadata: Standard object metadata; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - :param spec: Specification of the desired behavior of the ValidatingAdmissionPolicy. - - :schema: io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicy - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if isinstance(spec, dict): - spec = ValidatingAdmissionPolicySpecV1Alpha1(**spec) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__040f3513e9b89931f8fae1a4242c8701b631d9855f134d09d77119b9a1eee24f) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - if spec is not None: - self._values["spec"] = spec - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object metadata; - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - - :schema: io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicy#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def spec(self) -> typing.Optional["ValidatingAdmissionPolicySpecV1Alpha1"]: - '''Specification of the desired behavior of the ValidatingAdmissionPolicy. - - :schema: io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicy#spec - ''' - result = self._values.get("spec") - return typing.cast(typing.Optional["ValidatingAdmissionPolicySpecV1Alpha1"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeValidatingAdmissionPolicyV1Alpha1Props(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeValidatingWebhookConfiguration( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeValidatingWebhookConfiguration", -): - '''ValidatingWebhookConfiguration describes the configuration of and admission webhook that accept or reject and object without changing it. - - :schema: io.k8s.api.admissionregistration.v1.ValidatingWebhookConfiguration - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - webhooks: typing.Optional[typing.Sequence[typing.Union["ValidatingWebhook", typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''Defines a "io.k8s.api.admissionregistration.v1.ValidatingWebhookConfiguration" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param metadata: Standard object metadata; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - :param webhooks: Webhooks is a list of webhooks and the affected resources and operations. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__34e339703b236d0321dab9bd748a6980939b9f38a87e67f04aca4a50ee3aecf8) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeValidatingWebhookConfigurationProps( - metadata=metadata, webhooks=webhooks - ) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - webhooks: typing.Optional[typing.Sequence[typing.Union["ValidatingWebhook", typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.admissionregistration.v1.ValidatingWebhookConfiguration". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param metadata: Standard object metadata; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - :param webhooks: Webhooks is a list of webhooks and the affected resources and operations. - ''' - props = KubeValidatingWebhookConfigurationProps( - metadata=metadata, webhooks=webhooks - ) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.admissionregistration.v1.ValidatingWebhookConfiguration".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubeValidatingWebhookConfigurationList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeValidatingWebhookConfigurationList", -): - '''ValidatingWebhookConfigurationList is a list of ValidatingWebhookConfiguration. - - :schema: io.k8s.api.admissionregistration.v1.ValidatingWebhookConfigurationList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeValidatingWebhookConfigurationProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.admissionregistration.v1.ValidatingWebhookConfigurationList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: List of ValidatingWebhookConfiguration. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__1103257d673223fc00aa538b9609e9e419b426afd25ebb3a9b7dc9e0e202d6dc) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeValidatingWebhookConfigurationListProps( - items=items, metadata=metadata - ) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeValidatingWebhookConfigurationProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.admissionregistration.v1.ValidatingWebhookConfigurationList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: List of ValidatingWebhookConfiguration. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - ''' - props = KubeValidatingWebhookConfigurationListProps( - items=items, metadata=metadata - ) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.admissionregistration.v1.ValidatingWebhookConfigurationList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeValidatingWebhookConfigurationListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeValidatingWebhookConfigurationListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeValidatingWebhookConfigurationProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''ValidatingWebhookConfigurationList is a list of ValidatingWebhookConfiguration. - - :param items: List of ValidatingWebhookConfiguration. - :param metadata: Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.admissionregistration.v1.ValidatingWebhookConfigurationList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__702f63ae21781f4ac2e03fa52d1a43aa7dd941efb0a90957cb50bb979345695b) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeValidatingWebhookConfigurationProps"]: - '''List of ValidatingWebhookConfiguration. - - :schema: io.k8s.api.admissionregistration.v1.ValidatingWebhookConfigurationList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeValidatingWebhookConfigurationProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.admissionregistration.v1.ValidatingWebhookConfigurationList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeValidatingWebhookConfigurationListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubeValidatingWebhookConfigurationProps", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata", "webhooks": "webhooks"}, -) -class KubeValidatingWebhookConfigurationProps: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - webhooks: typing.Optional[typing.Sequence[typing.Union["ValidatingWebhook", typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''ValidatingWebhookConfiguration describes the configuration of and admission webhook that accept or reject and object without changing it. - - :param metadata: Standard object metadata; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - :param webhooks: Webhooks is a list of webhooks and the affected resources and operations. - - :schema: io.k8s.api.admissionregistration.v1.ValidatingWebhookConfiguration - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__bc3909ca83dd252c0b1916ec5180a66b37a3898a0491cb64159a92891339f221) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument webhooks", value=webhooks, expected_type=type_hints["webhooks"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - if webhooks is not None: - self._values["webhooks"] = webhooks - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object metadata; - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - - :schema: io.k8s.api.admissionregistration.v1.ValidatingWebhookConfiguration#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - @builtins.property - def webhooks(self) -> typing.Optional[typing.List["ValidatingWebhook"]]: - '''Webhooks is a list of webhooks and the affected resources and operations. - - :schema: io.k8s.api.admissionregistration.v1.ValidatingWebhookConfiguration#webhooks - ''' - result = self._values.get("webhooks") - return typing.cast(typing.Optional[typing.List["ValidatingWebhook"]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeValidatingWebhookConfigurationProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class KubeVolumeAttachment( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeVolumeAttachment", -): - '''VolumeAttachment captures the intent to attach or detach the specified volume to/from the specified node. - - VolumeAttachment objects are non-namespaced. - - :schema: io.k8s.api.storage.v1.VolumeAttachment - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - spec: typing.Union["VolumeAttachmentSpec", typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.storage.v1.VolumeAttachment" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param spec: Specification of the desired attach/detach volume behavior. Populated by the Kubernetes system. - :param metadata: Standard object metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__7d33788b211c51d74f2a918fa8acbb6022d3dcfdfc9205cd1ccd06c35a1ca5d1) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeVolumeAttachmentProps(spec=spec, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - spec: typing.Union["VolumeAttachmentSpec", typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.storage.v1.VolumeAttachment". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param spec: Specification of the desired attach/detach volume behavior. Populated by the Kubernetes system. - :param metadata: Standard object metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - ''' - props = KubeVolumeAttachmentProps(spec=spec, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.storage.v1.VolumeAttachment".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -class KubeVolumeAttachmentList( - _cdk8s_d3d9af27.ApiObject, - metaclass=jsii.JSIIMeta, - jsii_type="k8s.KubeVolumeAttachmentList", -): - '''VolumeAttachmentList is a collection of VolumeAttachment objects. - - :schema: io.k8s.api.storage.v1.VolumeAttachmentList - ''' - - def __init__( - self, - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union["KubeVolumeAttachmentProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a "io.k8s.api.storage.v1.VolumeAttachmentList" API object. - - :param scope: the scope in which to define this object. - :param id: a scope-local name for the object. - :param items: Items is the list of VolumeAttachments. - :param metadata: Standard list metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__ab4791be96cea53663cb0786137bf6128b7451e4c73f0e202e0155efaf9d465b) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - check_type(argname="argument id", value=id, expected_type=type_hints["id"]) - props = KubeVolumeAttachmentListProps(items=items, metadata=metadata) - - jsii.create(self.__class__, self, [scope, id, props]) - - @jsii.member(jsii_name="manifest") - @builtins.classmethod - def manifest( - cls, - *, - items: typing.Sequence[typing.Union["KubeVolumeAttachmentProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> typing.Any: - '''Renders a Kubernetes manifest for "io.k8s.api.storage.v1.VolumeAttachmentList". - - This can be used to inline resource manifests inside other objects (e.g. as templates). - - :param items: Items is the list of VolumeAttachments. - :param metadata: Standard list metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - ''' - props = KubeVolumeAttachmentListProps(items=items, metadata=metadata) - - return typing.cast(typing.Any, jsii.sinvoke(cls, "manifest", [props])) - - @jsii.member(jsii_name="toJson") - def to_json(self) -> typing.Any: - '''Renders the object to Kubernetes JSON.''' - return typing.cast(typing.Any, jsii.invoke(self, "toJson", [])) - - @jsii.python.classproperty - @jsii.member(jsii_name="GVK") - def GVK(cls) -> _cdk8s_d3d9af27.GroupVersionKind: - '''Returns the apiVersion and kind for "io.k8s.api.storage.v1.VolumeAttachmentList".''' - return typing.cast(_cdk8s_d3d9af27.GroupVersionKind, jsii.sget(cls, "GVK")) - - -@jsii.data_type( - jsii_type="k8s.KubeVolumeAttachmentListProps", - jsii_struct_bases=[], - name_mapping={"items": "items", "metadata": "metadata"}, -) -class KubeVolumeAttachmentListProps: - def __init__( - self, - *, - items: typing.Sequence[typing.Union["KubeVolumeAttachmentProps", typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union["ListMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''VolumeAttachmentList is a collection of VolumeAttachment objects. - - :param items: Items is the list of VolumeAttachments. - :param metadata: Standard list metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - - :schema: io.k8s.api.storage.v1.VolumeAttachmentList - ''' - if isinstance(metadata, dict): - metadata = ListMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__94942bd80cbcefacd1366946263ffe130479fa1a6a5daaf01c23920ee29e1db7) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "items": items, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def items(self) -> typing.List["KubeVolumeAttachmentProps"]: - '''Items is the list of VolumeAttachments. - - :schema: io.k8s.api.storage.v1.VolumeAttachmentList#items - ''' - result = self._values.get("items") - assert result is not None, "Required property 'items' is missing" - return typing.cast(typing.List["KubeVolumeAttachmentProps"], result) - - @builtins.property - def metadata(self) -> typing.Optional["ListMeta"]: - '''Standard list metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. - - :schema: io.k8s.api.storage.v1.VolumeAttachmentList#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ListMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeVolumeAttachmentListProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.KubeVolumeAttachmentProps", - jsii_struct_bases=[], - name_mapping={"spec": "spec", "metadata": "metadata"}, -) -class KubeVolumeAttachmentProps: - def __init__( - self, - *, - spec: typing.Union["VolumeAttachmentSpec", typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union["ObjectMeta", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''VolumeAttachment captures the intent to attach or detach the specified volume to/from the specified node. - - VolumeAttachment objects are non-namespaced. - - :param spec: Specification of the desired attach/detach volume behavior. Populated by the Kubernetes system. - :param metadata: Standard object metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.storage.v1.VolumeAttachment - ''' - if isinstance(spec, dict): - spec = VolumeAttachmentSpec(**spec) - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__9667f25c50a7755fb88e35e207298fc0e40ee7aed92a3420f75a02d74426c326) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "spec": spec, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def spec(self) -> "VolumeAttachmentSpec": - '''Specification of the desired attach/detach volume behavior. - - Populated by the Kubernetes system. - - :schema: io.k8s.api.storage.v1.VolumeAttachment#spec - ''' - result = self._values.get("spec") - assert result is not None, "Required property 'spec' is missing" - return typing.cast("VolumeAttachmentSpec", result) - - @builtins.property - def metadata(self) -> typing.Optional["ObjectMeta"]: - '''Standard object metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.storage.v1.VolumeAttachment#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional["ObjectMeta"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "KubeVolumeAttachmentProps(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.LabelSelector", - jsii_struct_bases=[], - name_mapping={ - "match_expressions": "matchExpressions", - "match_labels": "matchLabels", - }, -) -class LabelSelector: - def __init__( - self, - *, - match_expressions: typing.Optional[typing.Sequence[typing.Union["LabelSelectorRequirement", typing.Dict[builtins.str, typing.Any]]]] = None, - match_labels: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - ) -> None: - '''A label selector is a label query over a set of resources. - - The result of matchLabels and matchExpressions are ANDed. An empty label selector matches all objects. A null label selector matches no objects. - - :param match_expressions: matchExpressions is a list of label selector requirements. The requirements are ANDed. - :param match_labels: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.LabelSelector - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__4d456112fc12591335ee47253835365291967e786ee79f8d91249182e98fdd86) - check_type(argname="argument match_expressions", value=match_expressions, expected_type=type_hints["match_expressions"]) - check_type(argname="argument match_labels", value=match_labels, expected_type=type_hints["match_labels"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if match_expressions is not None: - self._values["match_expressions"] = match_expressions - if match_labels is not None: - self._values["match_labels"] = match_labels - - @builtins.property - def match_expressions( - self, - ) -> typing.Optional[typing.List["LabelSelectorRequirement"]]: - '''matchExpressions is a list of label selector requirements. - - The requirements are ANDed. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.LabelSelector#matchExpressions - ''' - result = self._values.get("match_expressions") - return typing.cast(typing.Optional[typing.List["LabelSelectorRequirement"]], result) - - @builtins.property - def match_labels( - self, - ) -> typing.Optional[typing.Mapping[builtins.str, builtins.str]]: - '''matchLabels is a map of {key,value} pairs. - - A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.LabelSelector#matchLabels - ''' - result = self._values.get("match_labels") - return typing.cast(typing.Optional[typing.Mapping[builtins.str, builtins.str]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "LabelSelector(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.LabelSelectorRequirement", - jsii_struct_bases=[], - name_mapping={"key": "key", "operator": "operator", "values": "values"}, -) -class LabelSelectorRequirement: - def __init__( - self, - *, - key: builtins.str, - operator: builtins.str, - values: typing.Optional[typing.Sequence[builtins.str]] = None, - ) -> None: - '''A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - - :param key: key is the label key that the selector applies to. - :param operator: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. - :param values: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.LabelSelectorRequirement - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__e384e360ddc460b3a27ab64f240971fb10f71f62661ae8ee39b61341807594f2) - check_type(argname="argument key", value=key, expected_type=type_hints["key"]) - check_type(argname="argument operator", value=operator, expected_type=type_hints["operator"]) - check_type(argname="argument values", value=values, expected_type=type_hints["values"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "key": key, - "operator": operator, - } - if values is not None: - self._values["values"] = values - - @builtins.property - def key(self) -> builtins.str: - '''key is the label key that the selector applies to. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.LabelSelectorRequirement#key - ''' - result = self._values.get("key") - assert result is not None, "Required property 'key' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def operator(self) -> builtins.str: - '''operator represents a key's relationship to a set of values. - - Valid operators are In, NotIn, Exists and DoesNotExist. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.LabelSelectorRequirement#operator - ''' - result = self._values.get("operator") - assert result is not None, "Required property 'operator' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def values(self) -> typing.Optional[typing.List[builtins.str]]: - '''values is an array of string values. - - If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.LabelSelectorRequirement#values - ''' - result = self._values.get("values") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "LabelSelectorRequirement(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.LeaseSpec", - jsii_struct_bases=[], - name_mapping={ - "acquire_time": "acquireTime", - "holder_identity": "holderIdentity", - "lease_duration_seconds": "leaseDurationSeconds", - "lease_transitions": "leaseTransitions", - "renew_time": "renewTime", - }, -) -class LeaseSpec: - def __init__( - self, - *, - acquire_time: typing.Optional[datetime.datetime] = None, - holder_identity: typing.Optional[builtins.str] = None, - lease_duration_seconds: typing.Optional[jsii.Number] = None, - lease_transitions: typing.Optional[jsii.Number] = None, - renew_time: typing.Optional[datetime.datetime] = None, - ) -> None: - '''LeaseSpec is a specification of a Lease. - - :param acquire_time: acquireTime is a time when the current lease was acquired. - :param holder_identity: holderIdentity contains the identity of the holder of a current lease. - :param lease_duration_seconds: leaseDurationSeconds is a duration that candidates for a lease need to wait to force acquire it. This is measure against time of last observed RenewTime. - :param lease_transitions: leaseTransitions is the number of transitions of a lease between holders. - :param renew_time: renewTime is a time when the current holder of a lease has last updated the lease. - - :schema: io.k8s.api.coordination.v1.LeaseSpec - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__401c15ef806c5b756921eeaf607340ba52477c9d6dab3b4ed3171aa7accf13c0) - check_type(argname="argument acquire_time", value=acquire_time, expected_type=type_hints["acquire_time"]) - check_type(argname="argument holder_identity", value=holder_identity, expected_type=type_hints["holder_identity"]) - check_type(argname="argument lease_duration_seconds", value=lease_duration_seconds, expected_type=type_hints["lease_duration_seconds"]) - check_type(argname="argument lease_transitions", value=lease_transitions, expected_type=type_hints["lease_transitions"]) - check_type(argname="argument renew_time", value=renew_time, expected_type=type_hints["renew_time"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if acquire_time is not None: - self._values["acquire_time"] = acquire_time - if holder_identity is not None: - self._values["holder_identity"] = holder_identity - if lease_duration_seconds is not None: - self._values["lease_duration_seconds"] = lease_duration_seconds - if lease_transitions is not None: - self._values["lease_transitions"] = lease_transitions - if renew_time is not None: - self._values["renew_time"] = renew_time - - @builtins.property - def acquire_time(self) -> typing.Optional[datetime.datetime]: - '''acquireTime is a time when the current lease was acquired. - - :schema: io.k8s.api.coordination.v1.LeaseSpec#acquireTime - ''' - result = self._values.get("acquire_time") - return typing.cast(typing.Optional[datetime.datetime], result) - - @builtins.property - def holder_identity(self) -> typing.Optional[builtins.str]: - '''holderIdentity contains the identity of the holder of a current lease. - - :schema: io.k8s.api.coordination.v1.LeaseSpec#holderIdentity - ''' - result = self._values.get("holder_identity") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def lease_duration_seconds(self) -> typing.Optional[jsii.Number]: - '''leaseDurationSeconds is a duration that candidates for a lease need to wait to force acquire it. - - This is measure against time of last observed RenewTime. - - :schema: io.k8s.api.coordination.v1.LeaseSpec#leaseDurationSeconds - ''' - result = self._values.get("lease_duration_seconds") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def lease_transitions(self) -> typing.Optional[jsii.Number]: - '''leaseTransitions is the number of transitions of a lease between holders. - - :schema: io.k8s.api.coordination.v1.LeaseSpec#leaseTransitions - ''' - result = self._values.get("lease_transitions") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def renew_time(self) -> typing.Optional[datetime.datetime]: - '''renewTime is a time when the current holder of a lease has last updated the lease. - - :schema: io.k8s.api.coordination.v1.LeaseSpec#renewTime - ''' - result = self._values.get("renew_time") - return typing.cast(typing.Optional[datetime.datetime], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "LeaseSpec(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.Lifecycle", - jsii_struct_bases=[], - name_mapping={"post_start": "postStart", "pre_stop": "preStop"}, -) -class Lifecycle: - def __init__( - self, - *, - post_start: typing.Optional[typing.Union["LifecycleHandler", typing.Dict[builtins.str, typing.Any]]] = None, - pre_stop: typing.Optional[typing.Union["LifecycleHandler", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Lifecycle describes actions that the management system should take in response to container lifecycle events. - - For the PostStart and PreStop lifecycle handlers, management of the container blocks until the action is complete, unless the container process fails, in which case the handler is aborted. - - :param post_start: PostStart is called immediately after a container is created. If the handler fails, the container is terminated and restarted according to its restart policy. Other management of the container blocks until the hook completes. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks - :param pre_stop: PreStop is called immediately before a container is terminated due to an API request or management event such as liveness/startup probe failure, preemption, resource contention, etc. The handler is not called if the container crashes or exits. The Pod's termination grace period countdown begins before the PreStop hook is executed. Regardless of the outcome of the handler, the container will eventually terminate within the Pod's termination grace period (unless delayed by finalizers). Other management of the container blocks until the hook completes or until the termination grace period is reached. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks - - :schema: io.k8s.api.core.v1.Lifecycle - ''' - if isinstance(post_start, dict): - post_start = LifecycleHandler(**post_start) - if isinstance(pre_stop, dict): - pre_stop = LifecycleHandler(**pre_stop) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__7bd1d9e48df3fb31eaad590d942020be7329bc9ca7a62db73e43e7362b1cc50d) - check_type(argname="argument post_start", value=post_start, expected_type=type_hints["post_start"]) - check_type(argname="argument pre_stop", value=pre_stop, expected_type=type_hints["pre_stop"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if post_start is not None: - self._values["post_start"] = post_start - if pre_stop is not None: - self._values["pre_stop"] = pre_stop - - @builtins.property - def post_start(self) -> typing.Optional["LifecycleHandler"]: - '''PostStart is called immediately after a container is created. - - If the handler fails, the container is terminated and restarted according to its restart policy. Other management of the container blocks until the hook completes. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks - - :schema: io.k8s.api.core.v1.Lifecycle#postStart - ''' - result = self._values.get("post_start") - return typing.cast(typing.Optional["LifecycleHandler"], result) - - @builtins.property - def pre_stop(self) -> typing.Optional["LifecycleHandler"]: - '''PreStop is called immediately before a container is terminated due to an API request or management event such as liveness/startup probe failure, preemption, resource contention, etc. - - The handler is not called if the container crashes or exits. The Pod's termination grace period countdown begins before the PreStop hook is executed. Regardless of the outcome of the handler, the container will eventually terminate within the Pod's termination grace period (unless delayed by finalizers). Other management of the container blocks until the hook completes or until the termination grace period is reached. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks - - :schema: io.k8s.api.core.v1.Lifecycle#preStop - ''' - result = self._values.get("pre_stop") - return typing.cast(typing.Optional["LifecycleHandler"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "Lifecycle(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.LifecycleHandler", - jsii_struct_bases=[], - name_mapping={"exec": "exec", "http_get": "httpGet", "tcp_socket": "tcpSocket"}, -) -class LifecycleHandler: - def __init__( - self, - *, - exec: typing.Optional[typing.Union[ExecAction, typing.Dict[builtins.str, typing.Any]]] = None, - http_get: typing.Optional[typing.Union[HttpGetAction, typing.Dict[builtins.str, typing.Any]]] = None, - tcp_socket: typing.Optional[typing.Union["TcpSocketAction", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''LifecycleHandler defines a specific action that should be taken in a lifecycle hook. - - One and only one of the fields, except TCPSocket must be specified. - - :param exec: Exec specifies the action to take. - :param http_get: HTTPGet specifies the http request to perform. - :param tcp_socket: Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept for the backward compatibility. There are no validation of this field and lifecycle hooks will fail in runtime when tcp handler is specified. - - :schema: io.k8s.api.core.v1.LifecycleHandler - ''' - if isinstance(exec, dict): - exec = ExecAction(**exec) - if isinstance(http_get, dict): - http_get = HttpGetAction(**http_get) - if isinstance(tcp_socket, dict): - tcp_socket = TcpSocketAction(**tcp_socket) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__26ab4379df425e6abfcd38434919756033f8e7da90416a68d159b10d8103d3a0) - check_type(argname="argument exec", value=exec, expected_type=type_hints["exec"]) - check_type(argname="argument http_get", value=http_get, expected_type=type_hints["http_get"]) - check_type(argname="argument tcp_socket", value=tcp_socket, expected_type=type_hints["tcp_socket"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if exec is not None: - self._values["exec"] = exec - if http_get is not None: - self._values["http_get"] = http_get - if tcp_socket is not None: - self._values["tcp_socket"] = tcp_socket - - @builtins.property - def exec(self) -> typing.Optional[ExecAction]: - '''Exec specifies the action to take. - - :schema: io.k8s.api.core.v1.LifecycleHandler#exec - ''' - result = self._values.get("exec") - return typing.cast(typing.Optional[ExecAction], result) - - @builtins.property - def http_get(self) -> typing.Optional[HttpGetAction]: - '''HTTPGet specifies the http request to perform. - - :schema: io.k8s.api.core.v1.LifecycleHandler#httpGet - ''' - result = self._values.get("http_get") - return typing.cast(typing.Optional[HttpGetAction], result) - - @builtins.property - def tcp_socket(self) -> typing.Optional["TcpSocketAction"]: - '''Deprecated. - - TCPSocket is NOT supported as a LifecycleHandler and kept for the backward compatibility. There are no validation of this field and lifecycle hooks will fail in runtime when tcp handler is specified. - - :schema: io.k8s.api.core.v1.LifecycleHandler#tcpSocket - ''' - result = self._values.get("tcp_socket") - return typing.cast(typing.Optional["TcpSocketAction"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "LifecycleHandler(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.LimitRangeItem", - jsii_struct_bases=[], - name_mapping={ - "type": "type", - "default": "default", - "default_request": "defaultRequest", - "max": "max", - "max_limit_request_ratio": "maxLimitRequestRatio", - "min": "min", - }, -) -class LimitRangeItem: - def __init__( - self, - *, - type: builtins.str, - default: typing.Optional[typing.Mapping[builtins.str, "Quantity"]] = None, - default_request: typing.Optional[typing.Mapping[builtins.str, "Quantity"]] = None, - max: typing.Optional[typing.Mapping[builtins.str, "Quantity"]] = None, - max_limit_request_ratio: typing.Optional[typing.Mapping[builtins.str, "Quantity"]] = None, - min: typing.Optional[typing.Mapping[builtins.str, "Quantity"]] = None, - ) -> None: - '''LimitRangeItem defines a min/max usage limit for any resource that matches on kind. - - :param type: Type of resource that this limit applies to. - :param default: Default resource requirement limit value by resource name if resource limit is omitted. - :param default_request: DefaultRequest is the default resource requirement request value by resource name if resource request is omitted. - :param max: Max usage constraints on this kind by resource name. - :param max_limit_request_ratio: MaxLimitRequestRatio if specified, the named resource must have a request and limit that are both non-zero where limit divided by request is less than or equal to the enumerated value; this represents the max burst for the named resource. - :param min: Min usage constraints on this kind by resource name. - - :schema: io.k8s.api.core.v1.LimitRangeItem - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__f178641e82038afdb476dfb5344285c2cd173e3d277341d2bdd9147b73026eee) - check_type(argname="argument type", value=type, expected_type=type_hints["type"]) - check_type(argname="argument default", value=default, expected_type=type_hints["default"]) - check_type(argname="argument default_request", value=default_request, expected_type=type_hints["default_request"]) - check_type(argname="argument max", value=max, expected_type=type_hints["max"]) - check_type(argname="argument max_limit_request_ratio", value=max_limit_request_ratio, expected_type=type_hints["max_limit_request_ratio"]) - check_type(argname="argument min", value=min, expected_type=type_hints["min"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "type": type, - } - if default is not None: - self._values["default"] = default - if default_request is not None: - self._values["default_request"] = default_request - if max is not None: - self._values["max"] = max - if max_limit_request_ratio is not None: - self._values["max_limit_request_ratio"] = max_limit_request_ratio - if min is not None: - self._values["min"] = min - - @builtins.property - def type(self) -> builtins.str: - '''Type of resource that this limit applies to. - - :schema: io.k8s.api.core.v1.LimitRangeItem#type - ''' - result = self._values.get("type") - assert result is not None, "Required property 'type' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def default(self) -> typing.Optional[typing.Mapping[builtins.str, "Quantity"]]: - '''Default resource requirement limit value by resource name if resource limit is omitted. - - :schema: io.k8s.api.core.v1.LimitRangeItem#default - ''' - result = self._values.get("default") - return typing.cast(typing.Optional[typing.Mapping[builtins.str, "Quantity"]], result) - - @builtins.property - def default_request( - self, - ) -> typing.Optional[typing.Mapping[builtins.str, "Quantity"]]: - '''DefaultRequest is the default resource requirement request value by resource name if resource request is omitted. - - :schema: io.k8s.api.core.v1.LimitRangeItem#defaultRequest - ''' - result = self._values.get("default_request") - return typing.cast(typing.Optional[typing.Mapping[builtins.str, "Quantity"]], result) - - @builtins.property - def max(self) -> typing.Optional[typing.Mapping[builtins.str, "Quantity"]]: - '''Max usage constraints on this kind by resource name. - - :schema: io.k8s.api.core.v1.LimitRangeItem#max - ''' - result = self._values.get("max") - return typing.cast(typing.Optional[typing.Mapping[builtins.str, "Quantity"]], result) - - @builtins.property - def max_limit_request_ratio( - self, - ) -> typing.Optional[typing.Mapping[builtins.str, "Quantity"]]: - '''MaxLimitRequestRatio if specified, the named resource must have a request and limit that are both non-zero where limit divided by request is less than or equal to the enumerated value; - - this represents the max burst for the named resource. - - :schema: io.k8s.api.core.v1.LimitRangeItem#maxLimitRequestRatio - ''' - result = self._values.get("max_limit_request_ratio") - return typing.cast(typing.Optional[typing.Mapping[builtins.str, "Quantity"]], result) - - @builtins.property - def min(self) -> typing.Optional[typing.Mapping[builtins.str, "Quantity"]]: - '''Min usage constraints on this kind by resource name. - - :schema: io.k8s.api.core.v1.LimitRangeItem#min - ''' - result = self._values.get("min") - return typing.cast(typing.Optional[typing.Mapping[builtins.str, "Quantity"]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "LimitRangeItem(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.LimitRangeSpec", - jsii_struct_bases=[], - name_mapping={"limits": "limits"}, -) -class LimitRangeSpec: - def __init__( - self, - *, - limits: typing.Sequence[typing.Union[LimitRangeItem, typing.Dict[builtins.str, typing.Any]]], - ) -> None: - '''LimitRangeSpec defines a min/max usage limit for resources that match on kind. - - :param limits: Limits is the list of LimitRangeItem objects that are enforced. - - :schema: io.k8s.api.core.v1.LimitRangeSpec - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__027b4c522c19844f185c6e4f67a4d23daf36b62d09bea8f49867796254123ae9) - check_type(argname="argument limits", value=limits, expected_type=type_hints["limits"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "limits": limits, - } - - @builtins.property - def limits(self) -> typing.List[LimitRangeItem]: - '''Limits is the list of LimitRangeItem objects that are enforced. - - :schema: io.k8s.api.core.v1.LimitRangeSpec#limits - ''' - result = self._values.get("limits") - assert result is not None, "Required property 'limits' is missing" - return typing.cast(typing.List[LimitRangeItem], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "LimitRangeSpec(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.LimitResponseV1Beta2", - jsii_struct_bases=[], - name_mapping={"type": "type", "queuing": "queuing"}, -) -class LimitResponseV1Beta2: - def __init__( - self, - *, - type: builtins.str, - queuing: typing.Optional[typing.Union["QueuingConfigurationV1Beta2", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''LimitResponse defines how to handle requests that can not be executed right now. - - :param type: ``type`` is "Queue" or "Reject". "Queue" means that requests that can not be executed upon arrival are held in a queue until they can be executed or a queuing limit is reached. "Reject" means that requests that can not be executed upon arrival are rejected. Required. - :param queuing: ``queuing`` holds the configuration parameters for queuing. This field may be non-empty only if ``type`` is ``"Queue"``. - - :schema: io.k8s.api.flowcontrol.v1beta2.LimitResponse - ''' - if isinstance(queuing, dict): - queuing = QueuingConfigurationV1Beta2(**queuing) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__a7d2e84b41662f85530d92f23057ed1bfa4d969fe97f435f241fb59d9e3bcf55) - check_type(argname="argument type", value=type, expected_type=type_hints["type"]) - check_type(argname="argument queuing", value=queuing, expected_type=type_hints["queuing"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "type": type, - } - if queuing is not None: - self._values["queuing"] = queuing - - @builtins.property - def type(self) -> builtins.str: - '''``type`` is "Queue" or "Reject". - - "Queue" means that requests that can not be executed upon arrival are held in a queue until they can be executed or a queuing limit is reached. "Reject" means that requests that can not be executed upon arrival are rejected. Required. - - :schema: io.k8s.api.flowcontrol.v1beta2.LimitResponse#type - ''' - result = self._values.get("type") - assert result is not None, "Required property 'type' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def queuing(self) -> typing.Optional["QueuingConfigurationV1Beta2"]: - '''``queuing`` holds the configuration parameters for queuing. - - This field may be non-empty only if ``type`` is ``"Queue"``. - - :schema: io.k8s.api.flowcontrol.v1beta2.LimitResponse#queuing - ''' - result = self._values.get("queuing") - return typing.cast(typing.Optional["QueuingConfigurationV1Beta2"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "LimitResponseV1Beta2(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.LimitResponseV1Beta3", - jsii_struct_bases=[], - name_mapping={"type": "type", "queuing": "queuing"}, -) -class LimitResponseV1Beta3: - def __init__( - self, - *, - type: builtins.str, - queuing: typing.Optional[typing.Union["QueuingConfigurationV1Beta3", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''LimitResponse defines how to handle requests that can not be executed right now. - - :param type: ``type`` is "Queue" or "Reject". "Queue" means that requests that can not be executed upon arrival are held in a queue until they can be executed or a queuing limit is reached. "Reject" means that requests that can not be executed upon arrival are rejected. Required. - :param queuing: ``queuing`` holds the configuration parameters for queuing. This field may be non-empty only if ``type`` is ``"Queue"``. - - :schema: io.k8s.api.flowcontrol.v1beta3.LimitResponse - ''' - if isinstance(queuing, dict): - queuing = QueuingConfigurationV1Beta3(**queuing) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__d647edc50a3472caac98caf06f5a31e4200bbd7ef2bb53fe956d146e70245f10) - check_type(argname="argument type", value=type, expected_type=type_hints["type"]) - check_type(argname="argument queuing", value=queuing, expected_type=type_hints["queuing"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "type": type, - } - if queuing is not None: - self._values["queuing"] = queuing - - @builtins.property - def type(self) -> builtins.str: - '''``type`` is "Queue" or "Reject". - - "Queue" means that requests that can not be executed upon arrival are held in a queue until they can be executed or a queuing limit is reached. "Reject" means that requests that can not be executed upon arrival are rejected. Required. - - :schema: io.k8s.api.flowcontrol.v1beta3.LimitResponse#type - ''' - result = self._values.get("type") - assert result is not None, "Required property 'type' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def queuing(self) -> typing.Optional["QueuingConfigurationV1Beta3"]: - '''``queuing`` holds the configuration parameters for queuing. - - This field may be non-empty only if ``type`` is ``"Queue"``. - - :schema: io.k8s.api.flowcontrol.v1beta3.LimitResponse#queuing - ''' - result = self._values.get("queuing") - return typing.cast(typing.Optional["QueuingConfigurationV1Beta3"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "LimitResponseV1Beta3(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.LimitedPriorityLevelConfigurationV1Beta2", - jsii_struct_bases=[], - name_mapping={ - "assured_concurrency_shares": "assuredConcurrencyShares", - "borrowing_limit_percent": "borrowingLimitPercent", - "lendable_percent": "lendablePercent", - "limit_response": "limitResponse", - }, -) -class LimitedPriorityLevelConfigurationV1Beta2: - def __init__( - self, - *, - assured_concurrency_shares: typing.Optional[jsii.Number] = None, - borrowing_limit_percent: typing.Optional[jsii.Number] = None, - lendable_percent: typing.Optional[jsii.Number] = None, - limit_response: typing.Optional[typing.Union[LimitResponseV1Beta2, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''LimitedPriorityLevelConfiguration specifies how to handle requests that are subject to limits. - - It addresses two issues: - - - How are requests for this priority level limited? - - What should be done with requests that exceed the limit? - - :param assured_concurrency_shares: ``assuredConcurrencyShares`` (ACS) configures the execution limit, which is a limit on the number of requests of this priority level that may be exeucting at a given time. ACS must be a positive number. The server's concurrency limit (SCL) is divided among the concurrency-controlled priority levels in proportion to their assured concurrency shares. This produces the assured concurrency value (ACV) --- the number of requests that may be executing at a time --- for each such priority level: ACV(l) = ceil( SCL * ACS(l) / ( sum[priority levels k] ACS(k) ) ) bigger numbers of ACS mean more reserved concurrent requests (at the expense of every other PL). This field has a default value of 30. - :param borrowing_limit_percent: ``borrowingLimitPercent``, if present, configures a limit on how many seats this priority level can borrow from other priority levels. The limit is known as this level's BorrowingConcurrencyLimit (BorrowingCL) and is a limit on the total number of seats that this level may borrow at any one time. This field holds the ratio of that limit to the level's nominal concurrency limit. When this field is non-nil, it must hold a non-negative integer and the limit is calculated as follows. BorrowingCL(i) = round( NominalCL(i) * borrowingLimitPercent(i)/100.0 ) The value of this field can be more than 100, implying that this priority level can borrow a number of seats that is greater than its own nominal concurrency limit (NominalCL). When this field is left ``nil``, the limit is effectively infinite. - :param lendable_percent: ``lendablePercent`` prescribes the fraction of the level's NominalCL that can be borrowed by other priority levels. The value of this field must be between 0 and 100, inclusive, and it defaults to 0. The number of seats that other levels can borrow from this level, known as this level's LendableConcurrencyLimit (LendableCL), is defined as follows. LendableCL(i) = round( NominalCL(i) * lendablePercent(i)/100.0 ) - :param limit_response: ``limitResponse`` indicates what to do with requests that can not be executed right now. - - :schema: io.k8s.api.flowcontrol.v1beta2.LimitedPriorityLevelConfiguration - ''' - if isinstance(limit_response, dict): - limit_response = LimitResponseV1Beta2(**limit_response) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__1de531b9c958a31d6159e3de559aad52ec6bc11571ae701ec5b953bf9aac78cf) - check_type(argname="argument assured_concurrency_shares", value=assured_concurrency_shares, expected_type=type_hints["assured_concurrency_shares"]) - check_type(argname="argument borrowing_limit_percent", value=borrowing_limit_percent, expected_type=type_hints["borrowing_limit_percent"]) - check_type(argname="argument lendable_percent", value=lendable_percent, expected_type=type_hints["lendable_percent"]) - check_type(argname="argument limit_response", value=limit_response, expected_type=type_hints["limit_response"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if assured_concurrency_shares is not None: - self._values["assured_concurrency_shares"] = assured_concurrency_shares - if borrowing_limit_percent is not None: - self._values["borrowing_limit_percent"] = borrowing_limit_percent - if lendable_percent is not None: - self._values["lendable_percent"] = lendable_percent - if limit_response is not None: - self._values["limit_response"] = limit_response - - @builtins.property - def assured_concurrency_shares(self) -> typing.Optional[jsii.Number]: - '''``assuredConcurrencyShares`` (ACS) configures the execution limit, which is a limit on the number of requests of this priority level that may be exeucting at a given time. - - ACS must be a positive number. The server's concurrency limit (SCL) is divided among the concurrency-controlled priority levels in proportion to their assured concurrency shares. This produces the assured concurrency value (ACV) --- the number of requests that may be executing at a time --- for each such priority level: - - ACV(l) = ceil( SCL * ACS(l) / ( sum[priority levels k] ACS(k) ) ) - - bigger numbers of ACS mean more reserved concurrent requests (at the expense of every other PL). This field has a default value of 30. - - :schema: io.k8s.api.flowcontrol.v1beta2.LimitedPriorityLevelConfiguration#assuredConcurrencyShares - ''' - result = self._values.get("assured_concurrency_shares") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def borrowing_limit_percent(self) -> typing.Optional[jsii.Number]: - '''``borrowingLimitPercent``, if present, configures a limit on how many seats this priority level can borrow from other priority levels. - - The limit is known as this level's BorrowingConcurrencyLimit (BorrowingCL) and is a limit on the total number of seats that this level may borrow at any one time. This field holds the ratio of that limit to the level's nominal concurrency limit. When this field is non-nil, it must hold a non-negative integer and the limit is calculated as follows. - - BorrowingCL(i) = round( NominalCL(i) * borrowingLimitPercent(i)/100.0 ) - - The value of this field can be more than 100, implying that this priority level can borrow a number of seats that is greater than its own nominal concurrency limit (NominalCL). When this field is left ``nil``, the limit is effectively infinite. - - :schema: io.k8s.api.flowcontrol.v1beta2.LimitedPriorityLevelConfiguration#borrowingLimitPercent - ''' - result = self._values.get("borrowing_limit_percent") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def lendable_percent(self) -> typing.Optional[jsii.Number]: - '''``lendablePercent`` prescribes the fraction of the level's NominalCL that can be borrowed by other priority levels. - - The value of this field must be between 0 and 100, inclusive, and it defaults to 0. The number of seats that other levels can borrow from this level, known as this level's LendableConcurrencyLimit (LendableCL), is defined as follows. - - LendableCL(i) = round( NominalCL(i) * lendablePercent(i)/100.0 ) - - :schema: io.k8s.api.flowcontrol.v1beta2.LimitedPriorityLevelConfiguration#lendablePercent - ''' - result = self._values.get("lendable_percent") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def limit_response(self) -> typing.Optional[LimitResponseV1Beta2]: - '''``limitResponse`` indicates what to do with requests that can not be executed right now. - - :schema: io.k8s.api.flowcontrol.v1beta2.LimitedPriorityLevelConfiguration#limitResponse - ''' - result = self._values.get("limit_response") - return typing.cast(typing.Optional[LimitResponseV1Beta2], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "LimitedPriorityLevelConfigurationV1Beta2(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.LimitedPriorityLevelConfigurationV1Beta3", - jsii_struct_bases=[], - name_mapping={ - "borrowing_limit_percent": "borrowingLimitPercent", - "lendable_percent": "lendablePercent", - "limit_response": "limitResponse", - "nominal_concurrency_shares": "nominalConcurrencyShares", - }, -) -class LimitedPriorityLevelConfigurationV1Beta3: - def __init__( - self, - *, - borrowing_limit_percent: typing.Optional[jsii.Number] = None, - lendable_percent: typing.Optional[jsii.Number] = None, - limit_response: typing.Optional[typing.Union[LimitResponseV1Beta3, typing.Dict[builtins.str, typing.Any]]] = None, - nominal_concurrency_shares: typing.Optional[jsii.Number] = None, - ) -> None: - '''LimitedPriorityLevelConfiguration specifies how to handle requests that are subject to limits. - - It addresses two issues: - - - How are requests for this priority level limited? - - What should be done with requests that exceed the limit? - - :param borrowing_limit_percent: ``borrowingLimitPercent``, if present, configures a limit on how many seats this priority level can borrow from other priority levels. The limit is known as this level's BorrowingConcurrencyLimit (BorrowingCL) and is a limit on the total number of seats that this level may borrow at any one time. This field holds the ratio of that limit to the level's nominal concurrency limit. When this field is non-nil, it must hold a non-negative integer and the limit is calculated as follows. BorrowingCL(i) = round( NominalCL(i) * borrowingLimitPercent(i)/100.0 ) The value of this field can be more than 100, implying that this priority level can borrow a number of seats that is greater than its own nominal concurrency limit (NominalCL). When this field is left ``nil``, the limit is effectively infinite. - :param lendable_percent: ``lendablePercent`` prescribes the fraction of the level's NominalCL that can be borrowed by other priority levels. The value of this field must be between 0 and 100, inclusive, and it defaults to 0. The number of seats that other levels can borrow from this level, known as this level's LendableConcurrencyLimit (LendableCL), is defined as follows. LendableCL(i) = round( NominalCL(i) * lendablePercent(i)/100.0 ) - :param limit_response: ``limitResponse`` indicates what to do with requests that can not be executed right now. - :param nominal_concurrency_shares: ``nominalConcurrencyShares`` (NCS) contributes to the computation of the NominalConcurrencyLimit (NominalCL) of this level. This is the number of execution seats available at this priority level. This is used both for requests dispatched from this priority level as well as requests dispatched from other priority levels borrowing seats from this level. The server's concurrency limit (ServerCL) is divided among the Limited priority levels in proportion to their NCS values: NominalCL(i) = ceil( ServerCL * NCS(i) / sum_ncs ) sum_ncs = sum[limited priority level k] NCS(k) Bigger numbers mean a larger nominal concurrency limit, at the expense of every other Limited priority level. This field has a default value of 30. - - :schema: io.k8s.api.flowcontrol.v1beta3.LimitedPriorityLevelConfiguration - ''' - if isinstance(limit_response, dict): - limit_response = LimitResponseV1Beta3(**limit_response) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__6f5ecffd25d8896c671c9cdd6db9659e0a8f6678e8899d85af3d7ddb13cef0ef) - check_type(argname="argument borrowing_limit_percent", value=borrowing_limit_percent, expected_type=type_hints["borrowing_limit_percent"]) - check_type(argname="argument lendable_percent", value=lendable_percent, expected_type=type_hints["lendable_percent"]) - check_type(argname="argument limit_response", value=limit_response, expected_type=type_hints["limit_response"]) - check_type(argname="argument nominal_concurrency_shares", value=nominal_concurrency_shares, expected_type=type_hints["nominal_concurrency_shares"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if borrowing_limit_percent is not None: - self._values["borrowing_limit_percent"] = borrowing_limit_percent - if lendable_percent is not None: - self._values["lendable_percent"] = lendable_percent - if limit_response is not None: - self._values["limit_response"] = limit_response - if nominal_concurrency_shares is not None: - self._values["nominal_concurrency_shares"] = nominal_concurrency_shares - - @builtins.property - def borrowing_limit_percent(self) -> typing.Optional[jsii.Number]: - '''``borrowingLimitPercent``, if present, configures a limit on how many seats this priority level can borrow from other priority levels. - - The limit is known as this level's BorrowingConcurrencyLimit (BorrowingCL) and is a limit on the total number of seats that this level may borrow at any one time. This field holds the ratio of that limit to the level's nominal concurrency limit. When this field is non-nil, it must hold a non-negative integer and the limit is calculated as follows. - - BorrowingCL(i) = round( NominalCL(i) * borrowingLimitPercent(i)/100.0 ) - - The value of this field can be more than 100, implying that this priority level can borrow a number of seats that is greater than its own nominal concurrency limit (NominalCL). When this field is left ``nil``, the limit is effectively infinite. - - :schema: io.k8s.api.flowcontrol.v1beta3.LimitedPriorityLevelConfiguration#borrowingLimitPercent - ''' - result = self._values.get("borrowing_limit_percent") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def lendable_percent(self) -> typing.Optional[jsii.Number]: - '''``lendablePercent`` prescribes the fraction of the level's NominalCL that can be borrowed by other priority levels. - - The value of this field must be between 0 and 100, inclusive, and it defaults to 0. The number of seats that other levels can borrow from this level, known as this level's LendableConcurrencyLimit (LendableCL), is defined as follows. - - LendableCL(i) = round( NominalCL(i) * lendablePercent(i)/100.0 ) - - :schema: io.k8s.api.flowcontrol.v1beta3.LimitedPriorityLevelConfiguration#lendablePercent - ''' - result = self._values.get("lendable_percent") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def limit_response(self) -> typing.Optional[LimitResponseV1Beta3]: - '''``limitResponse`` indicates what to do with requests that can not be executed right now. - - :schema: io.k8s.api.flowcontrol.v1beta3.LimitedPriorityLevelConfiguration#limitResponse - ''' - result = self._values.get("limit_response") - return typing.cast(typing.Optional[LimitResponseV1Beta3], result) - - @builtins.property - def nominal_concurrency_shares(self) -> typing.Optional[jsii.Number]: - '''``nominalConcurrencyShares`` (NCS) contributes to the computation of the NominalConcurrencyLimit (NominalCL) of this level. - - This is the number of execution seats available at this priority level. This is used both for requests dispatched from this priority level as well as requests dispatched from other priority levels borrowing seats from this level. The server's concurrency limit (ServerCL) is divided among the Limited priority levels in proportion to their NCS values: - - NominalCL(i) = ceil( ServerCL * NCS(i) / sum_ncs ) sum_ncs = sum[limited priority level k] NCS(k) - - Bigger numbers mean a larger nominal concurrency limit, at the expense of every other Limited priority level. This field has a default value of 30. - - :schema: io.k8s.api.flowcontrol.v1beta3.LimitedPriorityLevelConfiguration#nominalConcurrencyShares - ''' - result = self._values.get("nominal_concurrency_shares") - return typing.cast(typing.Optional[jsii.Number], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "LimitedPriorityLevelConfigurationV1Beta3(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ListMeta", - jsii_struct_bases=[], - name_mapping={ - "continue_": "continue", - "remaining_item_count": "remainingItemCount", - "resource_version": "resourceVersion", - "self_link": "selfLink", - }, -) -class ListMeta: - def __init__( - self, - *, - continue_: typing.Optional[builtins.str] = None, - remaining_item_count: typing.Optional[jsii.Number] = None, - resource_version: typing.Optional[builtins.str] = None, - self_link: typing.Optional[builtins.str] = None, - ) -> None: - '''ListMeta describes metadata that synthetic resources must have, including lists and various status objects. - - A resource may have only one of {ObjectMeta, ListMeta}. - - :param continue_: continue may be set if the user set a limit on the number of items returned, and indicates that the server has more data available. The value is opaque and may be used to issue another request to the endpoint that served this list to retrieve the next set of available objects. Continuing a consistent list may not be possible if the server configuration has changed or more than a few minutes have passed. The resourceVersion field returned when using this continue value will be identical to the value in the first response, unless you have received this token from an error message. - :param remaining_item_count: remainingItemCount is the number of subsequent items in the list which are not included in this list response. If the list request contained label or field selectors, then the number of remaining items is unknown and the field will be left unset and omitted during serialization. If the list is complete (either because it is not chunking or because this is the last chunk), then there are no more remaining items and this field will be left unset and omitted during serialization. Servers older than v1.15 do not set this field. The intended use of the remainingItemCount is *estimating* the size of a collection. Clients should not rely on the remainingItemCount to be set or to be exact. - :param resource_version: String that identifies the server's internal version of this object that can be used by clients to determine when objects have changed. Value must be treated as opaque by clients and passed unmodified back to the server. Populated by the system. Read-only. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - :param self_link: Deprecated: selfLink is a legacy read-only field that is no longer populated by the system. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.ListMeta - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__c89d5e06a349da5660f2e0e4d4f09e7a3e9ddf286741898802308a9398682fb7) - check_type(argname="argument continue_", value=continue_, expected_type=type_hints["continue_"]) - check_type(argname="argument remaining_item_count", value=remaining_item_count, expected_type=type_hints["remaining_item_count"]) - check_type(argname="argument resource_version", value=resource_version, expected_type=type_hints["resource_version"]) - check_type(argname="argument self_link", value=self_link, expected_type=type_hints["self_link"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if continue_ is not None: - self._values["continue_"] = continue_ - if remaining_item_count is not None: - self._values["remaining_item_count"] = remaining_item_count - if resource_version is not None: - self._values["resource_version"] = resource_version - if self_link is not None: - self._values["self_link"] = self_link - - @builtins.property - def continue_(self) -> typing.Optional[builtins.str]: - '''continue may be set if the user set a limit on the number of items returned, and indicates that the server has more data available. - - The value is opaque and may be used to issue another request to the endpoint that served this list to retrieve the next set of available objects. Continuing a consistent list may not be possible if the server configuration has changed or more than a few minutes have passed. The resourceVersion field returned when using this continue value will be identical to the value in the first response, unless you have received this token from an error message. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.ListMeta#continue - ''' - result = self._values.get("continue_") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def remaining_item_count(self) -> typing.Optional[jsii.Number]: - '''remainingItemCount is the number of subsequent items in the list which are not included in this list response. - - If the list request contained label or field selectors, then the number of remaining items is unknown and the field will be left unset and omitted during serialization. If the list is complete (either because it is not chunking or because this is the last chunk), then there are no more remaining items and this field will be left unset and omitted during serialization. Servers older than v1.15 do not set this field. The intended use of the remainingItemCount is *estimating* the size of a collection. Clients should not rely on the remainingItemCount to be set or to be exact. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.ListMeta#remainingItemCount - ''' - result = self._values.get("remaining_item_count") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def resource_version(self) -> typing.Optional[builtins.str]: - '''String that identifies the server's internal version of this object that can be used by clients to determine when objects have changed. - - Value must be treated as opaque by clients and passed unmodified back to the server. Populated by the system. Read-only. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.ListMeta#resourceVersion - ''' - result = self._values.get("resource_version") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def self_link(self) -> typing.Optional[builtins.str]: - '''Deprecated: selfLink is a legacy read-only field that is no longer populated by the system. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.ListMeta#selfLink - ''' - result = self._values.get("self_link") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ListMeta(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.LocalObjectReference", - jsii_struct_bases=[], - name_mapping={"name": "name"}, -) -class LocalObjectReference: - def __init__(self, *, name: typing.Optional[builtins.str] = None) -> None: - '''LocalObjectReference contains enough information to let you locate the referenced object inside the same namespace. - - :param name: Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - - :schema: io.k8s.api.core.v1.LocalObjectReference - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__d4bcf5caa3c82746d54e01aae949e13a5e8eb43da22feabb16930ea634934182) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if name is not None: - self._values["name"] = name - - @builtins.property - def name(self) -> typing.Optional[builtins.str]: - '''Name of the referent. - - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - - :schema: io.k8s.api.core.v1.LocalObjectReference#name - ''' - result = self._values.get("name") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "LocalObjectReference(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.LocalVolumeSource", - jsii_struct_bases=[], - name_mapping={"path": "path", "fs_type": "fsType"}, -) -class LocalVolumeSource: - def __init__( - self, - *, - path: builtins.str, - fs_type: typing.Optional[builtins.str] = None, - ) -> None: - '''Local represents directly-attached storage with node affinity (Beta feature). - - :param path: path of the full path to the volume on the node. It can be either a directory or block device (disk, partition, ...). - :param fs_type: fsType is the filesystem type to mount. It applies only when the Path is a block device. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". The default value is to auto-select a filesystem if unspecified. - - :schema: io.k8s.api.core.v1.LocalVolumeSource - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__b968cf718668502f36d95fef3ccb40aea55d0b34c90e37b5b542eeec51d43091) - check_type(argname="argument path", value=path, expected_type=type_hints["path"]) - check_type(argname="argument fs_type", value=fs_type, expected_type=type_hints["fs_type"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "path": path, - } - if fs_type is not None: - self._values["fs_type"] = fs_type - - @builtins.property - def path(self) -> builtins.str: - '''path of the full path to the volume on the node. - - It can be either a directory or block device (disk, partition, ...). - - :schema: io.k8s.api.core.v1.LocalVolumeSource#path - ''' - result = self._values.get("path") - assert result is not None, "Required property 'path' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def fs_type(self) -> typing.Optional[builtins.str]: - '''fsType is the filesystem type to mount. - - It applies only when the Path is a block device. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". The default value is to auto-select a filesystem if unspecified. - - :schema: io.k8s.api.core.v1.LocalVolumeSource#fsType - ''' - result = self._values.get("fs_type") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "LocalVolumeSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ManagedFieldsEntry", - jsii_struct_bases=[], - name_mapping={ - "api_version": "apiVersion", - "fields_type": "fieldsType", - "fields_v1": "fieldsV1", - "manager": "manager", - "operation": "operation", - "subresource": "subresource", - "time": "time", - }, -) -class ManagedFieldsEntry: - def __init__( - self, - *, - api_version: typing.Optional[builtins.str] = None, - fields_type: typing.Optional[builtins.str] = None, - fields_v1: typing.Any = None, - manager: typing.Optional[builtins.str] = None, - operation: typing.Optional[builtins.str] = None, - subresource: typing.Optional[builtins.str] = None, - time: typing.Optional[datetime.datetime] = None, - ) -> None: - '''ManagedFieldsEntry is a workflow-id, a FieldSet and the group version of the resource that the fieldset applies to. - - :param api_version: APIVersion defines the version of this resource that this field set applies to. The format is "group/version" just like the top-level APIVersion field. It is necessary to track the version of a field set because it cannot be automatically converted. - :param fields_type: FieldsType is the discriminator for the different fields format and version. There is currently only one possible value: "FieldsV1" - :param fields_v1: FieldsV1 holds the first JSON version format as described in the "FieldsV1" type. - :param manager: Manager is an identifier of the workflow managing these fields. - :param operation: Operation is the type of operation which lead to this ManagedFieldsEntry being created. The only valid values for this field are 'Apply' and 'Update'. - :param subresource: Subresource is the name of the subresource used to update that object, or empty string if the object was updated through the main resource. The value of this field is used to distinguish between managers, even if they share the same name. For example, a status update will be distinct from a regular update using the same manager name. Note that the APIVersion field is not related to the Subresource field and it always corresponds to the version of the main resource. - :param time: Time is the timestamp of when the ManagedFields entry was added. The timestamp will also be updated if a field is added, the manager changes any of the owned fields value or removes a field. The timestamp does not update when a field is removed from the entry because another manager took it over. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.ManagedFieldsEntry - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__7d4739bc7dc7000dc6e5fca030c204929e2fd79081deaecd9bb2d31a8ff798f8) - check_type(argname="argument api_version", value=api_version, expected_type=type_hints["api_version"]) - check_type(argname="argument fields_type", value=fields_type, expected_type=type_hints["fields_type"]) - check_type(argname="argument fields_v1", value=fields_v1, expected_type=type_hints["fields_v1"]) - check_type(argname="argument manager", value=manager, expected_type=type_hints["manager"]) - check_type(argname="argument operation", value=operation, expected_type=type_hints["operation"]) - check_type(argname="argument subresource", value=subresource, expected_type=type_hints["subresource"]) - check_type(argname="argument time", value=time, expected_type=type_hints["time"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if api_version is not None: - self._values["api_version"] = api_version - if fields_type is not None: - self._values["fields_type"] = fields_type - if fields_v1 is not None: - self._values["fields_v1"] = fields_v1 - if manager is not None: - self._values["manager"] = manager - if operation is not None: - self._values["operation"] = operation - if subresource is not None: - self._values["subresource"] = subresource - if time is not None: - self._values["time"] = time - - @builtins.property - def api_version(self) -> typing.Optional[builtins.str]: - '''APIVersion defines the version of this resource that this field set applies to. - - The format is "group/version" just like the top-level APIVersion field. It is necessary to track the version of a field set because it cannot be automatically converted. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.ManagedFieldsEntry#apiVersion - ''' - result = self._values.get("api_version") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def fields_type(self) -> typing.Optional[builtins.str]: - '''FieldsType is the discriminator for the different fields format and version. - - There is currently only one possible value: "FieldsV1" - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.ManagedFieldsEntry#fieldsType - ''' - result = self._values.get("fields_type") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def fields_v1(self) -> typing.Any: - '''FieldsV1 holds the first JSON version format as described in the "FieldsV1" type. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.ManagedFieldsEntry#fieldsV1 - ''' - result = self._values.get("fields_v1") - return typing.cast(typing.Any, result) - - @builtins.property - def manager(self) -> typing.Optional[builtins.str]: - '''Manager is an identifier of the workflow managing these fields. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.ManagedFieldsEntry#manager - ''' - result = self._values.get("manager") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def operation(self) -> typing.Optional[builtins.str]: - '''Operation is the type of operation which lead to this ManagedFieldsEntry being created. - - The only valid values for this field are 'Apply' and 'Update'. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.ManagedFieldsEntry#operation - ''' - result = self._values.get("operation") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def subresource(self) -> typing.Optional[builtins.str]: - '''Subresource is the name of the subresource used to update that object, or empty string if the object was updated through the main resource. - - The value of this field is used to distinguish between managers, even if they share the same name. For example, a status update will be distinct from a regular update using the same manager name. Note that the APIVersion field is not related to the Subresource field and it always corresponds to the version of the main resource. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.ManagedFieldsEntry#subresource - ''' - result = self._values.get("subresource") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def time(self) -> typing.Optional[datetime.datetime]: - '''Time is the timestamp of when the ManagedFields entry was added. - - The timestamp will also be updated if a field is added, the manager changes any of the owned fields value or removes a field. The timestamp does not update when a field is removed from the entry because another manager took it over. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.ManagedFieldsEntry#time - ''' - result = self._values.get("time") - return typing.cast(typing.Optional[datetime.datetime], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ManagedFieldsEntry(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.MatchResourcesV1Alpha1", - jsii_struct_bases=[], - name_mapping={ - "exclude_resource_rules": "excludeResourceRules", - "match_policy": "matchPolicy", - "namespace_selector": "namespaceSelector", - "object_selector": "objectSelector", - "resource_rules": "resourceRules", - }, -) -class MatchResourcesV1Alpha1: - def __init__( - self, - *, - exclude_resource_rules: typing.Optional[typing.Sequence[typing.Union["NamedRuleWithOperationsV1Alpha1", typing.Dict[builtins.str, typing.Any]]]] = None, - match_policy: typing.Optional[builtins.str] = None, - namespace_selector: typing.Optional[typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]]] = None, - object_selector: typing.Optional[typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]]] = None, - resource_rules: typing.Optional[typing.Sequence[typing.Union["NamedRuleWithOperationsV1Alpha1", typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''MatchResources decides whether to run the admission control policy on an object based on whether it meets the match criteria. - - The exclude rules take precedence over include rules (if a resource matches both, it is excluded) - - :param exclude_resource_rules: ExcludeResourceRules describes what operations on what resources/subresources the ValidatingAdmissionPolicy should not care about. The exclude rules take precedence over include rules (if a resource matches both, it is excluded) - :param match_policy: matchPolicy defines how the "MatchResources" list is used to match incoming requests. Allowed values are "Exact" or "Equivalent". - Exact: match a request only if it exactly matches a specified rule. For example, if deployments can be modified via apps/v1, apps/v1beta1, and extensions/v1beta1, but "rules" only included ``apiGroups:["apps"], apiVersions:["v1"], resources: ["deployments"]``, a request to apps/v1beta1 or extensions/v1beta1 would not be sent to the ValidatingAdmissionPolicy. - Equivalent: match a request if modifies a resource listed in rules, even via another API group or version. For example, if deployments can be modified via apps/v1, apps/v1beta1, and extensions/v1beta1, and "rules" only included ``apiGroups:["apps"], apiVersions:["v1"], resources: ["deployments"]``, a request to apps/v1beta1 or extensions/v1beta1 would be converted to apps/v1 and sent to the ValidatingAdmissionPolicy. Defaults to "Equivalent" Default: Equivalent" - :param namespace_selector: NamespaceSelector decides whether to run the admission control policy on an object based on whether the namespace for that object matches the selector. If the object itself is a namespace, the matching is performed on object.metadata.labels. If the object is another cluster scoped resource, it never skips the policy. For example, to run the webhook on any objects whose namespace is not associated with "runlevel" of "0" or "1"; you will set the selector as follows: "namespaceSelector": { "matchExpressions": [ { "key": "runlevel", "operator": "NotIn", "values": [ "0", "1" ] } ] } If instead you want to only run the policy on any objects whose namespace is associated with the "environment" of "prod" or "staging"; you will set the selector as follows: "namespaceSelector": { "matchExpressions": [ { "key": "environment", "operator": "In", "values": [ "prod", "staging" ] } ] } See https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ for more examples of label selectors. Default to the empty LabelSelector, which matches everything. Default: the empty LabelSelector, which matches everything. - :param object_selector: ObjectSelector decides whether to run the validation based on if the object has matching labels. objectSelector is evaluated against both the oldObject and newObject that would be sent to the cel validation, and is considered to match if either object matches the selector. A null object (oldObject in the case of create, or newObject in the case of delete) or an object that cannot have labels (like a DeploymentRollback or a PodProxyOptions object) is not considered to match. Use the object selector only if the webhook is opt-in, because end users may skip the admission webhook by setting the labels. Default to the empty LabelSelector, which matches everything. Default: the empty LabelSelector, which matches everything. - :param resource_rules: ResourceRules describes what operations on what resources/subresources the ValidatingAdmissionPolicy matches. The policy cares about an operation if it matches *any* Rule. - - :schema: io.k8s.api.admissionregistration.v1alpha1.MatchResources - ''' - if isinstance(namespace_selector, dict): - namespace_selector = LabelSelector(**namespace_selector) - if isinstance(object_selector, dict): - object_selector = LabelSelector(**object_selector) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__353cd8dc9e4702f1a8e203983ad89fe7e2f2cf3e018a030464f491008c59202f) - check_type(argname="argument exclude_resource_rules", value=exclude_resource_rules, expected_type=type_hints["exclude_resource_rules"]) - check_type(argname="argument match_policy", value=match_policy, expected_type=type_hints["match_policy"]) - check_type(argname="argument namespace_selector", value=namespace_selector, expected_type=type_hints["namespace_selector"]) - check_type(argname="argument object_selector", value=object_selector, expected_type=type_hints["object_selector"]) - check_type(argname="argument resource_rules", value=resource_rules, expected_type=type_hints["resource_rules"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if exclude_resource_rules is not None: - self._values["exclude_resource_rules"] = exclude_resource_rules - if match_policy is not None: - self._values["match_policy"] = match_policy - if namespace_selector is not None: - self._values["namespace_selector"] = namespace_selector - if object_selector is not None: - self._values["object_selector"] = object_selector - if resource_rules is not None: - self._values["resource_rules"] = resource_rules - - @builtins.property - def exclude_resource_rules( - self, - ) -> typing.Optional[typing.List["NamedRuleWithOperationsV1Alpha1"]]: - '''ExcludeResourceRules describes what operations on what resources/subresources the ValidatingAdmissionPolicy should not care about. - - The exclude rules take precedence over include rules (if a resource matches both, it is excluded) - - :schema: io.k8s.api.admissionregistration.v1alpha1.MatchResources#excludeResourceRules - ''' - result = self._values.get("exclude_resource_rules") - return typing.cast(typing.Optional[typing.List["NamedRuleWithOperationsV1Alpha1"]], result) - - @builtins.property - def match_policy(self) -> typing.Optional[builtins.str]: - '''matchPolicy defines how the "MatchResources" list is used to match incoming requests. Allowed values are "Exact" or "Equivalent". - - - Exact: match a request only if it exactly matches a specified rule. For example, if deployments can be modified via apps/v1, apps/v1beta1, and extensions/v1beta1, but "rules" only included ``apiGroups:["apps"], apiVersions:["v1"], resources: ["deployments"]``, a request to apps/v1beta1 or extensions/v1beta1 would not be sent to the ValidatingAdmissionPolicy. - - Equivalent: match a request if modifies a resource listed in rules, even via another API group or version. For example, if deployments can be modified via apps/v1, apps/v1beta1, and extensions/v1beta1, and "rules" only included ``apiGroups:["apps"], apiVersions:["v1"], resources: ["deployments"]``, a request to apps/v1beta1 or extensions/v1beta1 would be converted to apps/v1 and sent to the ValidatingAdmissionPolicy. - - Defaults to "Equivalent" - - :default: Equivalent" - - :schema: io.k8s.api.admissionregistration.v1alpha1.MatchResources#matchPolicy - ''' - result = self._values.get("match_policy") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def namespace_selector(self) -> typing.Optional[LabelSelector]: - '''NamespaceSelector decides whether to run the admission control policy on an object based on whether the namespace for that object matches the selector. - - If the object itself is a namespace, the matching is performed on object.metadata.labels. If the object is another cluster scoped resource, it never skips the policy. - - For example, to run the webhook on any objects whose namespace is not associated with "runlevel" of "0" or "1"; you will set the selector as follows: "namespaceSelector": { - "matchExpressions": [ - { - "key": "runlevel", - "operator": "NotIn", - "values": [ - "0", - "1" - ] - } - ] - } - - If instead you want to only run the policy on any objects whose namespace is associated with the "environment" of "prod" or "staging"; you will set the selector as follows: "namespaceSelector": { - "matchExpressions": [ - { - "key": "environment", - "operator": "In", - "values": [ - "prod", - "staging" - ] - } - ] - } - - See https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ for more examples of label selectors. - - Default to the empty LabelSelector, which matches everything. - - :default: the empty LabelSelector, which matches everything. - - :schema: io.k8s.api.admissionregistration.v1alpha1.MatchResources#namespaceSelector - ''' - result = self._values.get("namespace_selector") - return typing.cast(typing.Optional[LabelSelector], result) - - @builtins.property - def object_selector(self) -> typing.Optional[LabelSelector]: - '''ObjectSelector decides whether to run the validation based on if the object has matching labels. - - objectSelector is evaluated against both the oldObject and newObject that would be sent to the cel validation, and is considered to match if either object matches the selector. A null object (oldObject in the case of create, or newObject in the case of delete) or an object that cannot have labels (like a DeploymentRollback or a PodProxyOptions object) is not considered to match. Use the object selector only if the webhook is opt-in, because end users may skip the admission webhook by setting the labels. Default to the empty LabelSelector, which matches everything. - - :default: the empty LabelSelector, which matches everything. - - :schema: io.k8s.api.admissionregistration.v1alpha1.MatchResources#objectSelector - ''' - result = self._values.get("object_selector") - return typing.cast(typing.Optional[LabelSelector], result) - - @builtins.property - def resource_rules( - self, - ) -> typing.Optional[typing.List["NamedRuleWithOperationsV1Alpha1"]]: - '''ResourceRules describes what operations on what resources/subresources the ValidatingAdmissionPolicy matches. - - The policy cares about an operation if it matches *any* Rule. - - :schema: io.k8s.api.admissionregistration.v1alpha1.MatchResources#resourceRules - ''' - result = self._values.get("resource_rules") - return typing.cast(typing.Optional[typing.List["NamedRuleWithOperationsV1Alpha1"]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "MatchResourcesV1Alpha1(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.MetricIdentifierV2", - jsii_struct_bases=[], - name_mapping={"name": "name", "selector": "selector"}, -) -class MetricIdentifierV2: - def __init__( - self, - *, - name: builtins.str, - selector: typing.Optional[typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''MetricIdentifier defines the name and optionally selector for a metric. - - :param name: name is the name of the given metric. - :param selector: selector is the string-encoded form of a standard kubernetes label selector for the given metric When set, it is passed as an additional parameter to the metrics server for more specific metrics scoping. When unset, just the metricName will be used to gather metrics. - - :schema: io.k8s.api.autoscaling.v2.MetricIdentifier - ''' - if isinstance(selector, dict): - selector = LabelSelector(**selector) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__05f3c3477ee039ee62c1437881247ebc79634cd90deb0f404da58859b54f239b) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument selector", value=selector, expected_type=type_hints["selector"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "name": name, - } - if selector is not None: - self._values["selector"] = selector - - @builtins.property - def name(self) -> builtins.str: - '''name is the name of the given metric. - - :schema: io.k8s.api.autoscaling.v2.MetricIdentifier#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def selector(self) -> typing.Optional[LabelSelector]: - '''selector is the string-encoded form of a standard kubernetes label selector for the given metric When set, it is passed as an additional parameter to the metrics server for more specific metrics scoping. - - When unset, just the metricName will be used to gather metrics. - - :schema: io.k8s.api.autoscaling.v2.MetricIdentifier#selector - ''' - result = self._values.get("selector") - return typing.cast(typing.Optional[LabelSelector], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "MetricIdentifierV2(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.MetricSpecV2", - jsii_struct_bases=[], - name_mapping={ - "type": "type", - "container_resource": "containerResource", - "external": "external", - "object": "object", - "pods": "pods", - "resource": "resource", - }, -) -class MetricSpecV2: - def __init__( - self, - *, - type: builtins.str, - container_resource: typing.Optional[typing.Union[ContainerResourceMetricSourceV2, typing.Dict[builtins.str, typing.Any]]] = None, - external: typing.Optional[typing.Union[ExternalMetricSourceV2, typing.Dict[builtins.str, typing.Any]]] = None, - object: typing.Optional[typing.Union["ObjectMetricSourceV2", typing.Dict[builtins.str, typing.Any]]] = None, - pods: typing.Optional[typing.Union["PodsMetricSourceV2", typing.Dict[builtins.str, typing.Any]]] = None, - resource: typing.Optional[typing.Union["ResourceMetricSourceV2", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''MetricSpec specifies how to scale based on a single metric (only ``type`` and one other matching field should be set at once). - - :param type: type is the type of metric source. It should be one of "ContainerResource", "External", "Object", "Pods" or "Resource", each mapping to a matching field in the object. Note: "ContainerResource" type is available on when the feature-gate HPAContainerMetrics is enabled - :param container_resource: containerResource refers to a resource metric (such as those specified in requests and limits) known to Kubernetes describing a single container in each pod of the current scale target (e.g. CPU or memory). Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the "pods" source. This is an alpha feature and can be enabled by the HPAContainerMetrics feature flag. - :param external: external refers to a global metric that is not associated with any Kubernetes object. It allows autoscaling based on information coming from components running outside of cluster (for example length of queue in cloud messaging service, or QPS from loadbalancer running outside of cluster). - :param object: object refers to a metric describing a single kubernetes object (for example, hits-per-second on an Ingress object). - :param pods: pods refers to a metric describing each pod in the current scale target (for example, transactions-processed-per-second). The values will be averaged together before being compared to the target value. - :param resource: resource refers to a resource metric (such as those specified in requests and limits) known to Kubernetes describing each pod in the current scale target (e.g. CPU or memory). Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the "pods" source. - - :schema: io.k8s.api.autoscaling.v2.MetricSpec - ''' - if isinstance(container_resource, dict): - container_resource = ContainerResourceMetricSourceV2(**container_resource) - if isinstance(external, dict): - external = ExternalMetricSourceV2(**external) - if isinstance(object, dict): - object = ObjectMetricSourceV2(**object) - if isinstance(pods, dict): - pods = PodsMetricSourceV2(**pods) - if isinstance(resource, dict): - resource = ResourceMetricSourceV2(**resource) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__776c3a518a700d093a83bf2abc7751e45a06a623a34cd032f17c5caa38d5a529) - check_type(argname="argument type", value=type, expected_type=type_hints["type"]) - check_type(argname="argument container_resource", value=container_resource, expected_type=type_hints["container_resource"]) - check_type(argname="argument external", value=external, expected_type=type_hints["external"]) - check_type(argname="argument object", value=object, expected_type=type_hints["object"]) - check_type(argname="argument pods", value=pods, expected_type=type_hints["pods"]) - check_type(argname="argument resource", value=resource, expected_type=type_hints["resource"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "type": type, - } - if container_resource is not None: - self._values["container_resource"] = container_resource - if external is not None: - self._values["external"] = external - if object is not None: - self._values["object"] = object - if pods is not None: - self._values["pods"] = pods - if resource is not None: - self._values["resource"] = resource - - @builtins.property - def type(self) -> builtins.str: - '''type is the type of metric source. - - It should be one of "ContainerResource", "External", "Object", "Pods" or "Resource", each mapping to a matching field in the object. Note: "ContainerResource" type is available on when the feature-gate HPAContainerMetrics is enabled - - :schema: io.k8s.api.autoscaling.v2.MetricSpec#type - ''' - result = self._values.get("type") - assert result is not None, "Required property 'type' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def container_resource(self) -> typing.Optional[ContainerResourceMetricSourceV2]: - '''containerResource refers to a resource metric (such as those specified in requests and limits) known to Kubernetes describing a single container in each pod of the current scale target (e.g. CPU or memory). Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the "pods" source. This is an alpha feature and can be enabled by the HPAContainerMetrics feature flag. - - :schema: io.k8s.api.autoscaling.v2.MetricSpec#containerResource - ''' - result = self._values.get("container_resource") - return typing.cast(typing.Optional[ContainerResourceMetricSourceV2], result) - - @builtins.property - def external(self) -> typing.Optional[ExternalMetricSourceV2]: - '''external refers to a global metric that is not associated with any Kubernetes object. - - It allows autoscaling based on information coming from components running outside of cluster (for example length of queue in cloud messaging service, or QPS from loadbalancer running outside of cluster). - - :schema: io.k8s.api.autoscaling.v2.MetricSpec#external - ''' - result = self._values.get("external") - return typing.cast(typing.Optional[ExternalMetricSourceV2], result) - - @builtins.property - def object(self) -> typing.Optional["ObjectMetricSourceV2"]: - '''object refers to a metric describing a single kubernetes object (for example, hits-per-second on an Ingress object). - - :schema: io.k8s.api.autoscaling.v2.MetricSpec#object - ''' - result = self._values.get("object") - return typing.cast(typing.Optional["ObjectMetricSourceV2"], result) - - @builtins.property - def pods(self) -> typing.Optional["PodsMetricSourceV2"]: - '''pods refers to a metric describing each pod in the current scale target (for example, transactions-processed-per-second). - - The values will be averaged together before being compared to the target value. - - :schema: io.k8s.api.autoscaling.v2.MetricSpec#pods - ''' - result = self._values.get("pods") - return typing.cast(typing.Optional["PodsMetricSourceV2"], result) - - @builtins.property - def resource(self) -> typing.Optional["ResourceMetricSourceV2"]: - '''resource refers to a resource metric (such as those specified in requests and limits) known to Kubernetes describing each pod in the current scale target (e.g. CPU or memory). Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the "pods" source. - - :schema: io.k8s.api.autoscaling.v2.MetricSpec#resource - ''' - result = self._values.get("resource") - return typing.cast(typing.Optional["ResourceMetricSourceV2"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "MetricSpecV2(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.MetricTargetV2", - jsii_struct_bases=[], - name_mapping={ - "type": "type", - "average_utilization": "averageUtilization", - "average_value": "averageValue", - "value": "value", - }, -) -class MetricTargetV2: - def __init__( - self, - *, - type: builtins.str, - average_utilization: typing.Optional[jsii.Number] = None, - average_value: typing.Optional["Quantity"] = None, - value: typing.Optional["Quantity"] = None, - ) -> None: - '''MetricTarget defines the target value, average value, or average utilization of a specific metric. - - :param type: type represents whether the metric type is Utilization, Value, or AverageValue. - :param average_utilization: averageUtilization is the target value of the average of the resource metric across all relevant pods, represented as a percentage of the requested value of the resource for the pods. Currently only valid for Resource metric source type - :param average_value: averageValue is the target value of the average of the metric across all relevant pods (as a quantity). - :param value: value is the target value of the metric (as a quantity). - - :schema: io.k8s.api.autoscaling.v2.MetricTarget - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__91b2fc60d3480fdb5746f707be7158323bd2542cb5bf771776ee1d23f94b5209) - check_type(argname="argument type", value=type, expected_type=type_hints["type"]) - check_type(argname="argument average_utilization", value=average_utilization, expected_type=type_hints["average_utilization"]) - check_type(argname="argument average_value", value=average_value, expected_type=type_hints["average_value"]) - check_type(argname="argument value", value=value, expected_type=type_hints["value"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "type": type, - } - if average_utilization is not None: - self._values["average_utilization"] = average_utilization - if average_value is not None: - self._values["average_value"] = average_value - if value is not None: - self._values["value"] = value - - @builtins.property - def type(self) -> builtins.str: - '''type represents whether the metric type is Utilization, Value, or AverageValue. - - :schema: io.k8s.api.autoscaling.v2.MetricTarget#type - ''' - result = self._values.get("type") - assert result is not None, "Required property 'type' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def average_utilization(self) -> typing.Optional[jsii.Number]: - '''averageUtilization is the target value of the average of the resource metric across all relevant pods, represented as a percentage of the requested value of the resource for the pods. - - Currently only valid for Resource metric source type - - :schema: io.k8s.api.autoscaling.v2.MetricTarget#averageUtilization - ''' - result = self._values.get("average_utilization") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def average_value(self) -> typing.Optional["Quantity"]: - '''averageValue is the target value of the average of the metric across all relevant pods (as a quantity). - - :schema: io.k8s.api.autoscaling.v2.MetricTarget#averageValue - ''' - result = self._values.get("average_value") - return typing.cast(typing.Optional["Quantity"], result) - - @builtins.property - def value(self) -> typing.Optional["Quantity"]: - '''value is the target value of the metric (as a quantity). - - :schema: io.k8s.api.autoscaling.v2.MetricTarget#value - ''' - result = self._values.get("value") - return typing.cast(typing.Optional["Quantity"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "MetricTargetV2(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.MutatingWebhook", - jsii_struct_bases=[], - name_mapping={ - "admission_review_versions": "admissionReviewVersions", - "client_config": "clientConfig", - "name": "name", - "side_effects": "sideEffects", - "failure_policy": "failurePolicy", - "match_policy": "matchPolicy", - "namespace_selector": "namespaceSelector", - "object_selector": "objectSelector", - "reinvocation_policy": "reinvocationPolicy", - "rules": "rules", - "timeout_seconds": "timeoutSeconds", - }, -) -class MutatingWebhook: - def __init__( - self, - *, - admission_review_versions: typing.Sequence[builtins.str], - client_config: typing.Union["WebhookClientConfig", typing.Dict[builtins.str, typing.Any]], - name: builtins.str, - side_effects: builtins.str, - failure_policy: typing.Optional[builtins.str] = None, - match_policy: typing.Optional[builtins.str] = None, - namespace_selector: typing.Optional[typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]]] = None, - object_selector: typing.Optional[typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]]] = None, - reinvocation_policy: typing.Optional[builtins.str] = None, - rules: typing.Optional[typing.Sequence[typing.Union["RuleWithOperations", typing.Dict[builtins.str, typing.Any]]]] = None, - timeout_seconds: typing.Optional[jsii.Number] = None, - ) -> None: - '''MutatingWebhook describes an admission webhook and the resources and operations it applies to. - - :param admission_review_versions: AdmissionReviewVersions is an ordered list of preferred ``AdmissionReview`` versions the Webhook expects. API server will try to use first version in the list which it supports. If none of the versions specified in this list supported by API server, validation will fail for this object. If a persisted webhook configuration specifies allowed versions and does not include any versions known to the API Server, calls to the webhook will fail and be subject to the failure policy. - :param client_config: ClientConfig defines how to communicate with the hook. Required - :param name: The name of the admission webhook. Name should be fully qualified, e.g., imagepolicy.kubernetes.io, where "imagepolicy" is the name of the webhook, and kubernetes.io is the name of the organization. Required. - :param side_effects: SideEffects states whether this webhook has side effects. Acceptable values are: None, NoneOnDryRun (webhooks created via v1beta1 may also specify Some or Unknown). Webhooks with side effects MUST implement a reconciliation system, since a request may be rejected by a future step in the admission chain and the side effects therefore need to be undone. Requests with the dryRun attribute will be auto-rejected if they match a webhook with sideEffects == Unknown or Some. - :param failure_policy: FailurePolicy defines how unrecognized errors from the admission endpoint are handled - allowed values are Ignore or Fail. Defaults to Fail. Default: Fail. - :param match_policy: matchPolicy defines how the "rules" list is used to match incoming requests. Allowed values are "Exact" or "Equivalent". - Exact: match a request only if it exactly matches a specified rule. For example, if deployments can be modified via apps/v1, apps/v1beta1, and extensions/v1beta1, but "rules" only included ``apiGroups:["apps"], apiVersions:["v1"], resources: ["deployments"]``, a request to apps/v1beta1 or extensions/v1beta1 would not be sent to the webhook. - Equivalent: match a request if modifies a resource listed in rules, even via another API group or version. For example, if deployments can be modified via apps/v1, apps/v1beta1, and extensions/v1beta1, and "rules" only included ``apiGroups:["apps"], apiVersions:["v1"], resources: ["deployments"]``, a request to apps/v1beta1 or extensions/v1beta1 would be converted to apps/v1 and sent to the webhook. Defaults to "Equivalent" Default: Equivalent" - :param namespace_selector: NamespaceSelector decides whether to run the webhook on an object based on whether the namespace for that object matches the selector. If the object itself is a namespace, the matching is performed on object.metadata.labels. If the object is another cluster scoped resource, it never skips the webhook. For example, to run the webhook on any objects whose namespace is not associated with "runlevel" of "0" or "1"; you will set the selector as follows: "namespaceSelector": { "matchExpressions": [ { "key": "runlevel", "operator": "NotIn", "values": [ "0", "1" ] } ] } If instead you want to only run the webhook on any objects whose namespace is associated with the "environment" of "prod" or "staging"; you will set the selector as follows: "namespaceSelector": { "matchExpressions": [ { "key": "environment", "operator": "In", "values": [ "prod", "staging" ] } ] } See https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ for more examples of label selectors. Default to the empty LabelSelector, which matches everything. Default: the empty LabelSelector, which matches everything. - :param object_selector: ObjectSelector decides whether to run the webhook based on if the object has matching labels. objectSelector is evaluated against both the oldObject and newObject that would be sent to the webhook, and is considered to match if either object matches the selector. A null object (oldObject in the case of create, or newObject in the case of delete) or an object that cannot have labels (like a DeploymentRollback or a PodProxyOptions object) is not considered to match. Use the object selector only if the webhook is opt-in, because end users may skip the admission webhook by setting the labels. Default to the empty LabelSelector, which matches everything. Default: the empty LabelSelector, which matches everything. - :param reinvocation_policy: reinvocationPolicy indicates whether this webhook should be called multiple times as part of a single admission evaluation. Allowed values are "Never" and "IfNeeded". Never: the webhook will not be called more than once in a single admission evaluation. IfNeeded: the webhook will be called at least one additional time as part of the admission evaluation if the object being admitted is modified by other admission plugins after the initial webhook call. Webhooks that specify this option *must* be idempotent, able to process objects they previously admitted. Note: * the number of additional invocations is not guaranteed to be exactly one. * if additional invocations result in further modifications to the object, webhooks are not guaranteed to be invoked again. * webhooks that use this option may be reordered to minimize the number of additional invocations. * to validate an object after all mutations are guaranteed complete, use a validating admission webhook instead. Defaults to "Never". Default: Never". - :param rules: Rules describes what operations on what resources/subresources the webhook cares about. The webhook cares about an operation if it matches *any* Rule. However, in order to prevent ValidatingAdmissionWebhooks and MutatingAdmissionWebhooks from putting the cluster in a state which cannot be recovered from without completely disabling the plugin, ValidatingAdmissionWebhooks and MutatingAdmissionWebhooks are never called on admission requests for ValidatingWebhookConfiguration and MutatingWebhookConfiguration objects. - :param timeout_seconds: TimeoutSeconds specifies the timeout for this webhook. After the timeout passes, the webhook call will be ignored or the API call will fail based on the failure policy. The timeout value must be between 1 and 30 seconds. Default to 10 seconds. Default: 10 seconds. - - :schema: io.k8s.api.admissionregistration.v1.MutatingWebhook - ''' - if isinstance(client_config, dict): - client_config = WebhookClientConfig(**client_config) - if isinstance(namespace_selector, dict): - namespace_selector = LabelSelector(**namespace_selector) - if isinstance(object_selector, dict): - object_selector = LabelSelector(**object_selector) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__3b2b9fcd912bddbb67354eb50436e2e46cb9c69e54efee129d032491ec3fda21) - check_type(argname="argument admission_review_versions", value=admission_review_versions, expected_type=type_hints["admission_review_versions"]) - check_type(argname="argument client_config", value=client_config, expected_type=type_hints["client_config"]) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument side_effects", value=side_effects, expected_type=type_hints["side_effects"]) - check_type(argname="argument failure_policy", value=failure_policy, expected_type=type_hints["failure_policy"]) - check_type(argname="argument match_policy", value=match_policy, expected_type=type_hints["match_policy"]) - check_type(argname="argument namespace_selector", value=namespace_selector, expected_type=type_hints["namespace_selector"]) - check_type(argname="argument object_selector", value=object_selector, expected_type=type_hints["object_selector"]) - check_type(argname="argument reinvocation_policy", value=reinvocation_policy, expected_type=type_hints["reinvocation_policy"]) - check_type(argname="argument rules", value=rules, expected_type=type_hints["rules"]) - check_type(argname="argument timeout_seconds", value=timeout_seconds, expected_type=type_hints["timeout_seconds"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "admission_review_versions": admission_review_versions, - "client_config": client_config, - "name": name, - "side_effects": side_effects, - } - if failure_policy is not None: - self._values["failure_policy"] = failure_policy - if match_policy is not None: - self._values["match_policy"] = match_policy - if namespace_selector is not None: - self._values["namespace_selector"] = namespace_selector - if object_selector is not None: - self._values["object_selector"] = object_selector - if reinvocation_policy is not None: - self._values["reinvocation_policy"] = reinvocation_policy - if rules is not None: - self._values["rules"] = rules - if timeout_seconds is not None: - self._values["timeout_seconds"] = timeout_seconds - - @builtins.property - def admission_review_versions(self) -> typing.List[builtins.str]: - '''AdmissionReviewVersions is an ordered list of preferred ``AdmissionReview`` versions the Webhook expects. - - API server will try to use first version in the list which it supports. If none of the versions specified in this list supported by API server, validation will fail for this object. If a persisted webhook configuration specifies allowed versions and does not include any versions known to the API Server, calls to the webhook will fail and be subject to the failure policy. - - :schema: io.k8s.api.admissionregistration.v1.MutatingWebhook#admissionReviewVersions - ''' - result = self._values.get("admission_review_versions") - assert result is not None, "Required property 'admission_review_versions' is missing" - return typing.cast(typing.List[builtins.str], result) - - @builtins.property - def client_config(self) -> "WebhookClientConfig": - '''ClientConfig defines how to communicate with the hook. - - Required - - :schema: io.k8s.api.admissionregistration.v1.MutatingWebhook#clientConfig - ''' - result = self._values.get("client_config") - assert result is not None, "Required property 'client_config' is missing" - return typing.cast("WebhookClientConfig", result) - - @builtins.property - def name(self) -> builtins.str: - '''The name of the admission webhook. - - Name should be fully qualified, e.g., imagepolicy.kubernetes.io, where "imagepolicy" is the name of the webhook, and kubernetes.io is the name of the organization. Required. - - :schema: io.k8s.api.admissionregistration.v1.MutatingWebhook#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def side_effects(self) -> builtins.str: - '''SideEffects states whether this webhook has side effects. - - Acceptable values are: None, NoneOnDryRun (webhooks created via v1beta1 may also specify Some or Unknown). Webhooks with side effects MUST implement a reconciliation system, since a request may be rejected by a future step in the admission chain and the side effects therefore need to be undone. Requests with the dryRun attribute will be auto-rejected if they match a webhook with sideEffects == Unknown or Some. - - :schema: io.k8s.api.admissionregistration.v1.MutatingWebhook#sideEffects - ''' - result = self._values.get("side_effects") - assert result is not None, "Required property 'side_effects' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def failure_policy(self) -> typing.Optional[builtins.str]: - '''FailurePolicy defines how unrecognized errors from the admission endpoint are handled - allowed values are Ignore or Fail. - - Defaults to Fail. - - :default: Fail. - - :schema: io.k8s.api.admissionregistration.v1.MutatingWebhook#failurePolicy - ''' - result = self._values.get("failure_policy") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def match_policy(self) -> typing.Optional[builtins.str]: - '''matchPolicy defines how the "rules" list is used to match incoming requests. Allowed values are "Exact" or "Equivalent". - - - Exact: match a request only if it exactly matches a specified rule. For example, if deployments can be modified via apps/v1, apps/v1beta1, and extensions/v1beta1, but "rules" only included ``apiGroups:["apps"], apiVersions:["v1"], resources: ["deployments"]``, a request to apps/v1beta1 or extensions/v1beta1 would not be sent to the webhook. - - Equivalent: match a request if modifies a resource listed in rules, even via another API group or version. For example, if deployments can be modified via apps/v1, apps/v1beta1, and extensions/v1beta1, and "rules" only included ``apiGroups:["apps"], apiVersions:["v1"], resources: ["deployments"]``, a request to apps/v1beta1 or extensions/v1beta1 would be converted to apps/v1 and sent to the webhook. - - Defaults to "Equivalent" - - :default: Equivalent" - - :schema: io.k8s.api.admissionregistration.v1.MutatingWebhook#matchPolicy - ''' - result = self._values.get("match_policy") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def namespace_selector(self) -> typing.Optional[LabelSelector]: - '''NamespaceSelector decides whether to run the webhook on an object based on whether the namespace for that object matches the selector. - - If the object itself is a namespace, the matching is performed on object.metadata.labels. If the object is another cluster scoped resource, it never skips the webhook. - - For example, to run the webhook on any objects whose namespace is not associated with "runlevel" of "0" or "1"; you will set the selector as follows: "namespaceSelector": { - "matchExpressions": [ - { - "key": "runlevel", - "operator": "NotIn", - "values": [ - "0", - "1" - ] - } - ] - } - - If instead you want to only run the webhook on any objects whose namespace is associated with the "environment" of "prod" or "staging"; you will set the selector as follows: "namespaceSelector": { - "matchExpressions": [ - { - "key": "environment", - "operator": "In", - "values": [ - "prod", - "staging" - ] - } - ] - } - - See https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ for more examples of label selectors. - - Default to the empty LabelSelector, which matches everything. - - :default: the empty LabelSelector, which matches everything. - - :schema: io.k8s.api.admissionregistration.v1.MutatingWebhook#namespaceSelector - ''' - result = self._values.get("namespace_selector") - return typing.cast(typing.Optional[LabelSelector], result) - - @builtins.property - def object_selector(self) -> typing.Optional[LabelSelector]: - '''ObjectSelector decides whether to run the webhook based on if the object has matching labels. - - objectSelector is evaluated against both the oldObject and newObject that would be sent to the webhook, and is considered to match if either object matches the selector. A null object (oldObject in the case of create, or newObject in the case of delete) or an object that cannot have labels (like a DeploymentRollback or a PodProxyOptions object) is not considered to match. Use the object selector only if the webhook is opt-in, because end users may skip the admission webhook by setting the labels. Default to the empty LabelSelector, which matches everything. - - :default: the empty LabelSelector, which matches everything. - - :schema: io.k8s.api.admissionregistration.v1.MutatingWebhook#objectSelector - ''' - result = self._values.get("object_selector") - return typing.cast(typing.Optional[LabelSelector], result) - - @builtins.property - def reinvocation_policy(self) -> typing.Optional[builtins.str]: - '''reinvocationPolicy indicates whether this webhook should be called multiple times as part of a single admission evaluation. - - Allowed values are "Never" and "IfNeeded". - - Never: the webhook will not be called more than once in a single admission evaluation. - - IfNeeded: the webhook will be called at least one additional time as part of the admission evaluation if the object being admitted is modified by other admission plugins after the initial webhook call. Webhooks that specify this option *must* be idempotent, able to process objects they previously admitted. Note: * the number of additional invocations is not guaranteed to be exactly one. * if additional invocations result in further modifications to the object, webhooks are not guaranteed to be invoked again. * webhooks that use this option may be reordered to minimize the number of additional invocations. * to validate an object after all mutations are guaranteed complete, use a validating admission webhook instead. - - Defaults to "Never". - - :default: Never". - - :schema: io.k8s.api.admissionregistration.v1.MutatingWebhook#reinvocationPolicy - ''' - result = self._values.get("reinvocation_policy") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def rules(self) -> typing.Optional[typing.List["RuleWithOperations"]]: - '''Rules describes what operations on what resources/subresources the webhook cares about. - - The webhook cares about an operation if it matches *any* Rule. However, in order to prevent ValidatingAdmissionWebhooks and MutatingAdmissionWebhooks from putting the cluster in a state which cannot be recovered from without completely disabling the plugin, ValidatingAdmissionWebhooks and MutatingAdmissionWebhooks are never called on admission requests for ValidatingWebhookConfiguration and MutatingWebhookConfiguration objects. - - :schema: io.k8s.api.admissionregistration.v1.MutatingWebhook#rules - ''' - result = self._values.get("rules") - return typing.cast(typing.Optional[typing.List["RuleWithOperations"]], result) - - @builtins.property - def timeout_seconds(self) -> typing.Optional[jsii.Number]: - '''TimeoutSeconds specifies the timeout for this webhook. - - After the timeout passes, the webhook call will be ignored or the API call will fail based on the failure policy. The timeout value must be between 1 and 30 seconds. Default to 10 seconds. - - :default: 10 seconds. - - :schema: io.k8s.api.admissionregistration.v1.MutatingWebhook#timeoutSeconds - ''' - result = self._values.get("timeout_seconds") - return typing.cast(typing.Optional[jsii.Number], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "MutatingWebhook(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.NamedRuleWithOperationsV1Alpha1", - jsii_struct_bases=[], - name_mapping={ - "api_groups": "apiGroups", - "api_versions": "apiVersions", - "operations": "operations", - "resource_names": "resourceNames", - "resources": "resources", - "scope": "scope", - }, -) -class NamedRuleWithOperationsV1Alpha1: - def __init__( - self, - *, - api_groups: typing.Optional[typing.Sequence[builtins.str]] = None, - api_versions: typing.Optional[typing.Sequence[builtins.str]] = None, - operations: typing.Optional[typing.Sequence[builtins.str]] = None, - resource_names: typing.Optional[typing.Sequence[builtins.str]] = None, - resources: typing.Optional[typing.Sequence[builtins.str]] = None, - scope: typing.Optional[builtins.str] = None, - ) -> None: - '''NamedRuleWithOperations is a tuple of Operations and Resources with ResourceNames. - - :param api_groups: APIGroups is the API groups the resources belong to. '*' is all groups. If '*' is present, the length of the slice must be one. Required. - :param api_versions: APIVersions is the API versions the resources belong to. '*' is all versions. If '*' is present, the length of the slice must be one. Required. - :param operations: Operations is the operations the admission hook cares about - CREATE, UPDATE, DELETE, CONNECT or * for all of those operations and any future admission operations that are added. If '*' is present, the length of the slice must be one. Required. - :param resource_names: ResourceNames is an optional white list of names that the rule applies to. An empty set means that everything is allowed. - :param resources: Resources is a list of resources this rule applies to. For example: 'pods' means pods. 'pods/log' means the log subresource of pods. '*' means all resources, but not subresources. 'pods/*' means all subresources of pods. '*/scale' means all scale subresources. '*/*' means all resources and their subresources. If wildcard is present, the validation rule will ensure resources do not overlap with each other. Depending on the enclosing object, subresources might not be allowed. Required. - :param scope: scope specifies the scope of this rule. Valid values are "Cluster", "Namespaced", and "*" "Cluster" means that only cluster-scoped resources will match this rule. Namespace API objects are cluster-scoped. "Namespaced" means that only namespaced resources will match this rule. "*" means that there are no scope restrictions. Subresources match the scope of their parent resource. Default is "*". Default: . - - :schema: io.k8s.api.admissionregistration.v1alpha1.NamedRuleWithOperations - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__86254bd3c48c4175d2d8989d74b51ebf1d5e08f635d6ca938cbe71ad127a3055) - check_type(argname="argument api_groups", value=api_groups, expected_type=type_hints["api_groups"]) - check_type(argname="argument api_versions", value=api_versions, expected_type=type_hints["api_versions"]) - check_type(argname="argument operations", value=operations, expected_type=type_hints["operations"]) - check_type(argname="argument resource_names", value=resource_names, expected_type=type_hints["resource_names"]) - check_type(argname="argument resources", value=resources, expected_type=type_hints["resources"]) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if api_groups is not None: - self._values["api_groups"] = api_groups - if api_versions is not None: - self._values["api_versions"] = api_versions - if operations is not None: - self._values["operations"] = operations - if resource_names is not None: - self._values["resource_names"] = resource_names - if resources is not None: - self._values["resources"] = resources - if scope is not None: - self._values["scope"] = scope - - @builtins.property - def api_groups(self) -> typing.Optional[typing.List[builtins.str]]: - '''APIGroups is the API groups the resources belong to. - - '*' is all groups. If '*' is present, the length of the slice must be one. Required. - - :schema: io.k8s.api.admissionregistration.v1alpha1.NamedRuleWithOperations#apiGroups - ''' - result = self._values.get("api_groups") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def api_versions(self) -> typing.Optional[typing.List[builtins.str]]: - '''APIVersions is the API versions the resources belong to. - - '*' is all versions. If '*' is present, the length of the slice must be one. Required. - - :schema: io.k8s.api.admissionregistration.v1alpha1.NamedRuleWithOperations#apiVersions - ''' - result = self._values.get("api_versions") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def operations(self) -> typing.Optional[typing.List[builtins.str]]: - '''Operations is the operations the admission hook cares about - CREATE, UPDATE, DELETE, CONNECT or * for all of those operations and any future admission operations that are added. - - If '*' is present, the length of the slice must be one. Required. - - :schema: io.k8s.api.admissionregistration.v1alpha1.NamedRuleWithOperations#operations - ''' - result = self._values.get("operations") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def resource_names(self) -> typing.Optional[typing.List[builtins.str]]: - '''ResourceNames is an optional white list of names that the rule applies to. - - An empty set means that everything is allowed. - - :schema: io.k8s.api.admissionregistration.v1alpha1.NamedRuleWithOperations#resourceNames - ''' - result = self._values.get("resource_names") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def resources(self) -> typing.Optional[typing.List[builtins.str]]: - '''Resources is a list of resources this rule applies to. - - For example: 'pods' means pods. 'pods/log' means the log subresource of pods. '*' means all resources, but not subresources. 'pods/*' means all subresources of pods. '*/scale' means all scale subresources. '*/*' means all resources and their subresources. - - If wildcard is present, the validation rule will ensure resources do not overlap with each other. - - Depending on the enclosing object, subresources might not be allowed. Required. - - :schema: io.k8s.api.admissionregistration.v1alpha1.NamedRuleWithOperations#resources - ''' - result = self._values.get("resources") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def scope(self) -> typing.Optional[builtins.str]: - '''scope specifies the scope of this rule. - - Valid values are "Cluster", "Namespaced", and "*" "Cluster" means that only cluster-scoped resources will match this rule. Namespace API objects are cluster-scoped. "Namespaced" means that only namespaced resources will match this rule. "*" means that there are no scope restrictions. Subresources match the scope of their parent resource. Default is "*". - - :default: . - - :schema: io.k8s.api.admissionregistration.v1alpha1.NamedRuleWithOperations#scope - ''' - result = self._values.get("scope") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "NamedRuleWithOperationsV1Alpha1(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.NamespaceSpec", - jsii_struct_bases=[], - name_mapping={"finalizers": "finalizers"}, -) -class NamespaceSpec: - def __init__( - self, - *, - finalizers: typing.Optional[typing.Sequence[builtins.str]] = None, - ) -> None: - '''NamespaceSpec describes the attributes on a Namespace. - - :param finalizers: Finalizers is an opaque list of values that must be empty to permanently remove object from storage. More info: https://kubernetes.io/docs/tasks/administer-cluster/namespaces/ - - :schema: io.k8s.api.core.v1.NamespaceSpec - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__0ea645c91cd000f5a4da28ff25155be76d43d13a8e9e70b0d5c0f6eb2529d3c8) - check_type(argname="argument finalizers", value=finalizers, expected_type=type_hints["finalizers"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if finalizers is not None: - self._values["finalizers"] = finalizers - - @builtins.property - def finalizers(self) -> typing.Optional[typing.List[builtins.str]]: - '''Finalizers is an opaque list of values that must be empty to permanently remove object from storage. - - More info: https://kubernetes.io/docs/tasks/administer-cluster/namespaces/ - - :schema: io.k8s.api.core.v1.NamespaceSpec#finalizers - ''' - result = self._values.get("finalizers") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "NamespaceSpec(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.NetworkPolicyEgressRule", - jsii_struct_bases=[], - name_mapping={"ports": "ports", "to": "to"}, -) -class NetworkPolicyEgressRule: - def __init__( - self, - *, - ports: typing.Optional[typing.Sequence[typing.Union["NetworkPolicyPort", typing.Dict[builtins.str, typing.Any]]]] = None, - to: typing.Optional[typing.Sequence[typing.Union["NetworkPolicyPeer", typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''NetworkPolicyEgressRule describes a particular set of traffic that is allowed out of pods matched by a NetworkPolicySpec's podSelector. - - The traffic must match both ports and to. This type is beta-level in 1.8 - - :param ports: List of destination ports for outgoing traffic. Each item in this list is combined using a logical OR. If this field is empty or missing, this rule matches all ports (traffic not restricted by port). If this field is present and contains at least one item, then this rule allows traffic only if the traffic matches at least one port in the list. - :param to: List of destinations for outgoing traffic of pods selected for this rule. Items in this list are combined using a logical OR operation. If this field is empty or missing, this rule matches all destinations (traffic not restricted by destination). If this field is present and contains at least one item, this rule allows traffic only if the traffic matches at least one item in the to list. - - :schema: io.k8s.api.networking.v1.NetworkPolicyEgressRule - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__2310900f85c6226ede2a61dd42a7652ea8cc83e009f119df2fbd2f16997b26de) - check_type(argname="argument ports", value=ports, expected_type=type_hints["ports"]) - check_type(argname="argument to", value=to, expected_type=type_hints["to"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if ports is not None: - self._values["ports"] = ports - if to is not None: - self._values["to"] = to - - @builtins.property - def ports(self) -> typing.Optional[typing.List["NetworkPolicyPort"]]: - '''List of destination ports for outgoing traffic. - - Each item in this list is combined using a logical OR. If this field is empty or missing, this rule matches all ports (traffic not restricted by port). If this field is present and contains at least one item, then this rule allows traffic only if the traffic matches at least one port in the list. - - :schema: io.k8s.api.networking.v1.NetworkPolicyEgressRule#ports - ''' - result = self._values.get("ports") - return typing.cast(typing.Optional[typing.List["NetworkPolicyPort"]], result) - - @builtins.property - def to(self) -> typing.Optional[typing.List["NetworkPolicyPeer"]]: - '''List of destinations for outgoing traffic of pods selected for this rule. - - Items in this list are combined using a logical OR operation. If this field is empty or missing, this rule matches all destinations (traffic not restricted by destination). If this field is present and contains at least one item, this rule allows traffic only if the traffic matches at least one item in the to list. - - :schema: io.k8s.api.networking.v1.NetworkPolicyEgressRule#to - ''' - result = self._values.get("to") - return typing.cast(typing.Optional[typing.List["NetworkPolicyPeer"]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "NetworkPolicyEgressRule(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.NetworkPolicyIngressRule", - jsii_struct_bases=[], - name_mapping={"from_": "from", "ports": "ports"}, -) -class NetworkPolicyIngressRule: - def __init__( - self, - *, - from_: typing.Optional[typing.Sequence[typing.Union["NetworkPolicyPeer", typing.Dict[builtins.str, typing.Any]]]] = None, - ports: typing.Optional[typing.Sequence[typing.Union["NetworkPolicyPort", typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''NetworkPolicyIngressRule describes a particular set of traffic that is allowed to the pods matched by a NetworkPolicySpec's podSelector. - - The traffic must match both ports and from. - - :param from_: List of sources which should be able to access the pods selected for this rule. Items in this list are combined using a logical OR operation. If this field is empty or missing, this rule matches all sources (traffic not restricted by source). If this field is present and contains at least one item, this rule allows traffic only if the traffic matches at least one item in the from list. - :param ports: List of ports which should be made accessible on the pods selected for this rule. Each item in this list is combined using a logical OR. If this field is empty or missing, this rule matches all ports (traffic not restricted by port). If this field is present and contains at least one item, then this rule allows traffic only if the traffic matches at least one port in the list. - - :schema: io.k8s.api.networking.v1.NetworkPolicyIngressRule - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__539e72cf73f95f606fca75f4cbd682e72299b5c8617bc9a6aafa6f3c15b73e64) - check_type(argname="argument from_", value=from_, expected_type=type_hints["from_"]) - check_type(argname="argument ports", value=ports, expected_type=type_hints["ports"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if from_ is not None: - self._values["from_"] = from_ - if ports is not None: - self._values["ports"] = ports - - @builtins.property - def from_(self) -> typing.Optional[typing.List["NetworkPolicyPeer"]]: - '''List of sources which should be able to access the pods selected for this rule. - - Items in this list are combined using a logical OR operation. If this field is empty or missing, this rule matches all sources (traffic not restricted by source). If this field is present and contains at least one item, this rule allows traffic only if the traffic matches at least one item in the from list. - - :schema: io.k8s.api.networking.v1.NetworkPolicyIngressRule#from - ''' - result = self._values.get("from_") - return typing.cast(typing.Optional[typing.List["NetworkPolicyPeer"]], result) - - @builtins.property - def ports(self) -> typing.Optional[typing.List["NetworkPolicyPort"]]: - '''List of ports which should be made accessible on the pods selected for this rule. - - Each item in this list is combined using a logical OR. If this field is empty or missing, this rule matches all ports (traffic not restricted by port). If this field is present and contains at least one item, then this rule allows traffic only if the traffic matches at least one port in the list. - - :schema: io.k8s.api.networking.v1.NetworkPolicyIngressRule#ports - ''' - result = self._values.get("ports") - return typing.cast(typing.Optional[typing.List["NetworkPolicyPort"]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "NetworkPolicyIngressRule(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.NetworkPolicyPeer", - jsii_struct_bases=[], - name_mapping={ - "ip_block": "ipBlock", - "namespace_selector": "namespaceSelector", - "pod_selector": "podSelector", - }, -) -class NetworkPolicyPeer: - def __init__( - self, - *, - ip_block: typing.Optional[typing.Union[IpBlock, typing.Dict[builtins.str, typing.Any]]] = None, - namespace_selector: typing.Optional[typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]]] = None, - pod_selector: typing.Optional[typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''NetworkPolicyPeer describes a peer to allow traffic to/from. - - Only certain combinations of fields are allowed - - :param ip_block: IPBlock defines policy on a particular IPBlock. If this field is set then neither of the other fields can be. - :param namespace_selector: Selects Namespaces using cluster-scoped labels. This field follows standard label selector semantics; if present but empty, it selects all namespaces. If PodSelector is also set, then the NetworkPolicyPeer as a whole selects the Pods matching PodSelector in the Namespaces selected by NamespaceSelector. Otherwise it selects all Pods in the Namespaces selected by NamespaceSelector. - :param pod_selector: This is a label selector which selects Pods. This field follows standard label selector semantics; if present but empty, it selects all pods. If NamespaceSelector is also set, then the NetworkPolicyPeer as a whole selects the Pods matching PodSelector in the Namespaces selected by NamespaceSelector. Otherwise it selects the Pods matching PodSelector in the policy's own Namespace. - - :schema: io.k8s.api.networking.v1.NetworkPolicyPeer - ''' - if isinstance(ip_block, dict): - ip_block = IpBlock(**ip_block) - if isinstance(namespace_selector, dict): - namespace_selector = LabelSelector(**namespace_selector) - if isinstance(pod_selector, dict): - pod_selector = LabelSelector(**pod_selector) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__79d11d83de8d6e2520a2426cb19cd2d699bfd94c627f4b84d0a50530c388c1bf) - check_type(argname="argument ip_block", value=ip_block, expected_type=type_hints["ip_block"]) - check_type(argname="argument namespace_selector", value=namespace_selector, expected_type=type_hints["namespace_selector"]) - check_type(argname="argument pod_selector", value=pod_selector, expected_type=type_hints["pod_selector"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if ip_block is not None: - self._values["ip_block"] = ip_block - if namespace_selector is not None: - self._values["namespace_selector"] = namespace_selector - if pod_selector is not None: - self._values["pod_selector"] = pod_selector - - @builtins.property - def ip_block(self) -> typing.Optional[IpBlock]: - '''IPBlock defines policy on a particular IPBlock. - - If this field is set then neither of the other fields can be. - - :schema: io.k8s.api.networking.v1.NetworkPolicyPeer#ipBlock - ''' - result = self._values.get("ip_block") - return typing.cast(typing.Optional[IpBlock], result) - - @builtins.property - def namespace_selector(self) -> typing.Optional[LabelSelector]: - '''Selects Namespaces using cluster-scoped labels. - - This field follows standard label selector semantics; if present but empty, it selects all namespaces. - - If PodSelector is also set, then the NetworkPolicyPeer as a whole selects the Pods matching PodSelector in the Namespaces selected by NamespaceSelector. Otherwise it selects all Pods in the Namespaces selected by NamespaceSelector. - - :schema: io.k8s.api.networking.v1.NetworkPolicyPeer#namespaceSelector - ''' - result = self._values.get("namespace_selector") - return typing.cast(typing.Optional[LabelSelector], result) - - @builtins.property - def pod_selector(self) -> typing.Optional[LabelSelector]: - '''This is a label selector which selects Pods. - - This field follows standard label selector semantics; if present but empty, it selects all pods. - - If NamespaceSelector is also set, then the NetworkPolicyPeer as a whole selects the Pods matching PodSelector in the Namespaces selected by NamespaceSelector. Otherwise it selects the Pods matching PodSelector in the policy's own Namespace. - - :schema: io.k8s.api.networking.v1.NetworkPolicyPeer#podSelector - ''' - result = self._values.get("pod_selector") - return typing.cast(typing.Optional[LabelSelector], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "NetworkPolicyPeer(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.NetworkPolicyPort", - jsii_struct_bases=[], - name_mapping={"end_port": "endPort", "port": "port", "protocol": "protocol"}, -) -class NetworkPolicyPort: - def __init__( - self, - *, - end_port: typing.Optional[jsii.Number] = None, - port: typing.Optional[IntOrString] = None, - protocol: typing.Optional[builtins.str] = None, - ) -> None: - '''NetworkPolicyPort describes a port to allow traffic on. - - :param end_port: If set, indicates that the range of ports from port to endPort, inclusive, should be allowed by the policy. This field cannot be defined if the port field is not defined or if the port field is defined as a named (string) port. The endPort must be equal or greater than port. - :param port: The port on the given protocol. This can either be a numerical or named port on a pod. If this field is not provided, this matches all port names and numbers. If present, only traffic on the specified protocol AND port will be matched. - :param protocol: The protocol (TCP, UDP, or SCTP) which traffic must match. If not specified, this field defaults to TCP. - - :schema: io.k8s.api.networking.v1.NetworkPolicyPort - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__49079df49fbd7a79ac55d3eb11dc0d2260b7ec0d23bd59e732339eebb03b1866) - check_type(argname="argument end_port", value=end_port, expected_type=type_hints["end_port"]) - check_type(argname="argument port", value=port, expected_type=type_hints["port"]) - check_type(argname="argument protocol", value=protocol, expected_type=type_hints["protocol"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if end_port is not None: - self._values["end_port"] = end_port - if port is not None: - self._values["port"] = port - if protocol is not None: - self._values["protocol"] = protocol - - @builtins.property - def end_port(self) -> typing.Optional[jsii.Number]: - '''If set, indicates that the range of ports from port to endPort, inclusive, should be allowed by the policy. - - This field cannot be defined if the port field is not defined or if the port field is defined as a named (string) port. The endPort must be equal or greater than port. - - :schema: io.k8s.api.networking.v1.NetworkPolicyPort#endPort - ''' - result = self._values.get("end_port") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def port(self) -> typing.Optional[IntOrString]: - '''The port on the given protocol. - - This can either be a numerical or named port on a pod. If this field is not provided, this matches all port names and numbers. If present, only traffic on the specified protocol AND port will be matched. - - :schema: io.k8s.api.networking.v1.NetworkPolicyPort#port - ''' - result = self._values.get("port") - return typing.cast(typing.Optional[IntOrString], result) - - @builtins.property - def protocol(self) -> typing.Optional[builtins.str]: - '''The protocol (TCP, UDP, or SCTP) which traffic must match. - - If not specified, this field defaults to TCP. - - :schema: io.k8s.api.networking.v1.NetworkPolicyPort#protocol - ''' - result = self._values.get("protocol") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "NetworkPolicyPort(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.NetworkPolicySpec", - jsii_struct_bases=[], - name_mapping={ - "pod_selector": "podSelector", - "egress": "egress", - "ingress": "ingress", - "policy_types": "policyTypes", - }, -) -class NetworkPolicySpec: - def __init__( - self, - *, - pod_selector: typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]], - egress: typing.Optional[typing.Sequence[typing.Union[NetworkPolicyEgressRule, typing.Dict[builtins.str, typing.Any]]]] = None, - ingress: typing.Optional[typing.Sequence[typing.Union[NetworkPolicyIngressRule, typing.Dict[builtins.str, typing.Any]]]] = None, - policy_types: typing.Optional[typing.Sequence[builtins.str]] = None, - ) -> None: - '''NetworkPolicySpec provides the specification of a NetworkPolicy. - - :param pod_selector: Selects the pods to which this NetworkPolicy object applies. The array of ingress rules is applied to any pods selected by this field. Multiple network policies can select the same set of pods. In this case, the ingress rules for each are combined additively. This field is NOT optional and follows standard label selector semantics. An empty podSelector matches all pods in this namespace. - :param egress: List of egress rules to be applied to the selected pods. Outgoing traffic is allowed if there are no NetworkPolicies selecting the pod (and cluster policy otherwise allows the traffic), OR if the traffic matches at least one egress rule across all of the NetworkPolicy objects whose podSelector matches the pod. If this field is empty then this NetworkPolicy limits all outgoing traffic (and serves solely to ensure that the pods it selects are isolated by default). This field is beta-level in 1.8 - :param ingress: List of ingress rules to be applied to the selected pods. Traffic is allowed to a pod if there are no NetworkPolicies selecting the pod (and cluster policy otherwise allows the traffic), OR if the traffic source is the pod's local node, OR if the traffic matches at least one ingress rule across all of the NetworkPolicy objects whose podSelector matches the pod. If this field is empty then this NetworkPolicy does not allow any traffic (and serves solely to ensure that the pods it selects are isolated by default) - :param policy_types: List of rule types that the NetworkPolicy relates to. Valid options are ["Ingress"], ["Egress"], or ["Ingress", "Egress"]. If this field is not specified, it will default based on the existence of Ingress or Egress rules; policies that contain an Egress section are assumed to affect Egress, and all policies (whether or not they contain an Ingress section) are assumed to affect Ingress. If you want to write an egress-only policy, you must explicitly specify policyTypes [ "Egress" ]. Likewise, if you want to write a policy that specifies that no egress is allowed, you must specify a policyTypes value that include "Egress" (since such a policy would not include an Egress section and would otherwise default to just [ "Ingress" ]). This field is beta-level in 1.8 - - :schema: io.k8s.api.networking.v1.NetworkPolicySpec - ''' - if isinstance(pod_selector, dict): - pod_selector = LabelSelector(**pod_selector) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__d9c84fc90459d1cd97b3329e793a8d157a79bc350c911daca3c8b5b185a16977) - check_type(argname="argument pod_selector", value=pod_selector, expected_type=type_hints["pod_selector"]) - check_type(argname="argument egress", value=egress, expected_type=type_hints["egress"]) - check_type(argname="argument ingress", value=ingress, expected_type=type_hints["ingress"]) - check_type(argname="argument policy_types", value=policy_types, expected_type=type_hints["policy_types"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "pod_selector": pod_selector, - } - if egress is not None: - self._values["egress"] = egress - if ingress is not None: - self._values["ingress"] = ingress - if policy_types is not None: - self._values["policy_types"] = policy_types - - @builtins.property - def pod_selector(self) -> LabelSelector: - '''Selects the pods to which this NetworkPolicy object applies. - - The array of ingress rules is applied to any pods selected by this field. Multiple network policies can select the same set of pods. In this case, the ingress rules for each are combined additively. This field is NOT optional and follows standard label selector semantics. An empty podSelector matches all pods in this namespace. - - :schema: io.k8s.api.networking.v1.NetworkPolicySpec#podSelector - ''' - result = self._values.get("pod_selector") - assert result is not None, "Required property 'pod_selector' is missing" - return typing.cast(LabelSelector, result) - - @builtins.property - def egress(self) -> typing.Optional[typing.List[NetworkPolicyEgressRule]]: - '''List of egress rules to be applied to the selected pods. - - Outgoing traffic is allowed if there are no NetworkPolicies selecting the pod (and cluster policy otherwise allows the traffic), OR if the traffic matches at least one egress rule across all of the NetworkPolicy objects whose podSelector matches the pod. If this field is empty then this NetworkPolicy limits all outgoing traffic (and serves solely to ensure that the pods it selects are isolated by default). This field is beta-level in 1.8 - - :schema: io.k8s.api.networking.v1.NetworkPolicySpec#egress - ''' - result = self._values.get("egress") - return typing.cast(typing.Optional[typing.List[NetworkPolicyEgressRule]], result) - - @builtins.property - def ingress(self) -> typing.Optional[typing.List[NetworkPolicyIngressRule]]: - '''List of ingress rules to be applied to the selected pods. - - Traffic is allowed to a pod if there are no NetworkPolicies selecting the pod (and cluster policy otherwise allows the traffic), OR if the traffic source is the pod's local node, OR if the traffic matches at least one ingress rule across all of the NetworkPolicy objects whose podSelector matches the pod. If this field is empty then this NetworkPolicy does not allow any traffic (and serves solely to ensure that the pods it selects are isolated by default) - - :schema: io.k8s.api.networking.v1.NetworkPolicySpec#ingress - ''' - result = self._values.get("ingress") - return typing.cast(typing.Optional[typing.List[NetworkPolicyIngressRule]], result) - - @builtins.property - def policy_types(self) -> typing.Optional[typing.List[builtins.str]]: - '''List of rule types that the NetworkPolicy relates to. - - Valid options are ["Ingress"], ["Egress"], or ["Ingress", "Egress"]. If this field is not specified, it will default based on the existence of Ingress or Egress rules; policies that contain an Egress section are assumed to affect Egress, and all policies (whether or not they contain an Ingress section) are assumed to affect Ingress. If you want to write an egress-only policy, you must explicitly specify policyTypes [ "Egress" ]. Likewise, if you want to write a policy that specifies that no egress is allowed, you must specify a policyTypes value that include "Egress" (since such a policy would not include an Egress section and would otherwise default to just [ "Ingress" ]). This field is beta-level in 1.8 - - :schema: io.k8s.api.networking.v1.NetworkPolicySpec#policyTypes - ''' - result = self._values.get("policy_types") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "NetworkPolicySpec(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.NfsVolumeSource", - jsii_struct_bases=[], - name_mapping={"path": "path", "server": "server", "read_only": "readOnly"}, -) -class NfsVolumeSource: - def __init__( - self, - *, - path: builtins.str, - server: builtins.str, - read_only: typing.Optional[builtins.bool] = None, - ) -> None: - '''Represents an NFS mount that lasts the lifetime of a pod. - - NFS volumes do not support ownership management or SELinux relabeling. - - :param path: path that is exported by the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - :param server: server is the hostname or IP address of the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - :param read_only: readOnly here will force the NFS export to be mounted with read-only permissions. Defaults to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs Default: false. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - - :schema: io.k8s.api.core.v1.NFSVolumeSource - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__64ef53a74120cbc99eb5a721f1a72955a4b1a591eaaf717f4ad02b252033b821) - check_type(argname="argument path", value=path, expected_type=type_hints["path"]) - check_type(argname="argument server", value=server, expected_type=type_hints["server"]) - check_type(argname="argument read_only", value=read_only, expected_type=type_hints["read_only"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "path": path, - "server": server, - } - if read_only is not None: - self._values["read_only"] = read_only - - @builtins.property - def path(self) -> builtins.str: - '''path that is exported by the NFS server. - - More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - - :schema: io.k8s.api.core.v1.NFSVolumeSource#path - ''' - result = self._values.get("path") - assert result is not None, "Required property 'path' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def server(self) -> builtins.str: - '''server is the hostname or IP address of the NFS server. - - More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - - :schema: io.k8s.api.core.v1.NFSVolumeSource#server - ''' - result = self._values.get("server") - assert result is not None, "Required property 'server' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def read_only(self) -> typing.Optional[builtins.bool]: - '''readOnly here will force the NFS export to be mounted with read-only permissions. - - Defaults to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - - :default: false. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - - :schema: io.k8s.api.core.v1.NFSVolumeSource#readOnly - ''' - result = self._values.get("read_only") - return typing.cast(typing.Optional[builtins.bool], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "NfsVolumeSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.NodeAffinity", - jsii_struct_bases=[], - name_mapping={ - "preferred_during_scheduling_ignored_during_execution": "preferredDuringSchedulingIgnoredDuringExecution", - "required_during_scheduling_ignored_during_execution": "requiredDuringSchedulingIgnoredDuringExecution", - }, -) -class NodeAffinity: - def __init__( - self, - *, - preferred_during_scheduling_ignored_during_execution: typing.Optional[typing.Sequence[typing.Union["PreferredSchedulingTerm", typing.Dict[builtins.str, typing.Any]]]] = None, - required_during_scheduling_ignored_during_execution: typing.Optional[typing.Union["NodeSelector", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Node affinity is a group of node affinity scheduling rules. - - :param preferred_during_scheduling_ignored_during_execution: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node matches the corresponding matchExpressions; the node(s) with the highest sum are the most preferred. - :param required_during_scheduling_ignored_during_execution: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to an update), the system may or may not try to eventually evict the pod from its node. - - :schema: io.k8s.api.core.v1.NodeAffinity - ''' - if isinstance(required_during_scheduling_ignored_during_execution, dict): - required_during_scheduling_ignored_during_execution = NodeSelector(**required_during_scheduling_ignored_during_execution) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__b48e0015647b26feaba0b33c63daf8b67b9219ead4d1f2049e1565931a1ebf3f) - check_type(argname="argument preferred_during_scheduling_ignored_during_execution", value=preferred_during_scheduling_ignored_during_execution, expected_type=type_hints["preferred_during_scheduling_ignored_during_execution"]) - check_type(argname="argument required_during_scheduling_ignored_during_execution", value=required_during_scheduling_ignored_during_execution, expected_type=type_hints["required_during_scheduling_ignored_during_execution"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if preferred_during_scheduling_ignored_during_execution is not None: - self._values["preferred_during_scheduling_ignored_during_execution"] = preferred_during_scheduling_ignored_during_execution - if required_during_scheduling_ignored_during_execution is not None: - self._values["required_during_scheduling_ignored_during_execution"] = required_during_scheduling_ignored_during_execution - - @builtins.property - def preferred_during_scheduling_ignored_during_execution( - self, - ) -> typing.Optional[typing.List["PreferredSchedulingTerm"]]: - '''The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. - - The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node matches the corresponding matchExpressions; the node(s) with the highest sum are the most preferred. - - :schema: io.k8s.api.core.v1.NodeAffinity#preferredDuringSchedulingIgnoredDuringExecution - ''' - result = self._values.get("preferred_during_scheduling_ignored_during_execution") - return typing.cast(typing.Optional[typing.List["PreferredSchedulingTerm"]], result) - - @builtins.property - def required_during_scheduling_ignored_during_execution( - self, - ) -> typing.Optional["NodeSelector"]: - '''If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. - - If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to an update), the system may or may not try to eventually evict the pod from its node. - - :schema: io.k8s.api.core.v1.NodeAffinity#requiredDuringSchedulingIgnoredDuringExecution - ''' - result = self._values.get("required_during_scheduling_ignored_during_execution") - return typing.cast(typing.Optional["NodeSelector"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "NodeAffinity(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.NodeConfigSource", - jsii_struct_bases=[], - name_mapping={"config_map": "configMap"}, -) -class NodeConfigSource: - def __init__( - self, - *, - config_map: typing.Optional[typing.Union[ConfigMapNodeConfigSource, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''NodeConfigSource specifies a source of node configuration. - - Exactly one subfield (excluding metadata) must be non-nil. This API is deprecated since 1.22 - - :param config_map: ConfigMap is a reference to a Node's ConfigMap. - - :schema: io.k8s.api.core.v1.NodeConfigSource - ''' - if isinstance(config_map, dict): - config_map = ConfigMapNodeConfigSource(**config_map) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__cf7f83b52a971565e60c01b2feacf24dc56b2f356b8bd133298411fd8ca953fc) - check_type(argname="argument config_map", value=config_map, expected_type=type_hints["config_map"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if config_map is not None: - self._values["config_map"] = config_map - - @builtins.property - def config_map(self) -> typing.Optional[ConfigMapNodeConfigSource]: - '''ConfigMap is a reference to a Node's ConfigMap. - - :schema: io.k8s.api.core.v1.NodeConfigSource#configMap - ''' - result = self._values.get("config_map") - return typing.cast(typing.Optional[ConfigMapNodeConfigSource], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "NodeConfigSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.NodeSelector", - jsii_struct_bases=[], - name_mapping={"node_selector_terms": "nodeSelectorTerms"}, -) -class NodeSelector: - def __init__( - self, - *, - node_selector_terms: typing.Sequence[typing.Union["NodeSelectorTerm", typing.Dict[builtins.str, typing.Any]]], - ) -> None: - '''A node selector represents the union of the results of one or more label queries over a set of nodes; - - that is, it represents the OR of the selectors represented by the node selector terms. - - :param node_selector_terms: Required. A list of node selector terms. The terms are ORed. - - :schema: io.k8s.api.core.v1.NodeSelector - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__860ee52caab59ff2ee19e780fd4b3b278089ce131229f4b4c67d9158710bfd41) - check_type(argname="argument node_selector_terms", value=node_selector_terms, expected_type=type_hints["node_selector_terms"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "node_selector_terms": node_selector_terms, - } - - @builtins.property - def node_selector_terms(self) -> typing.List["NodeSelectorTerm"]: - '''Required. - - A list of node selector terms. The terms are ORed. - - :schema: io.k8s.api.core.v1.NodeSelector#nodeSelectorTerms - ''' - result = self._values.get("node_selector_terms") - assert result is not None, "Required property 'node_selector_terms' is missing" - return typing.cast(typing.List["NodeSelectorTerm"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "NodeSelector(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.NodeSelectorRequirement", - jsii_struct_bases=[], - name_mapping={"key": "key", "operator": "operator", "values": "values"}, -) -class NodeSelectorRequirement: - def __init__( - self, - *, - key: builtins.str, - operator: builtins.str, - values: typing.Optional[typing.Sequence[builtins.str]] = None, - ) -> None: - '''A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - - :param key: The label key that the selector applies to. - :param operator: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - :param values: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. - - :schema: io.k8s.api.core.v1.NodeSelectorRequirement - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__078a37e4a700d461ea8bef52cbb31305d573e12bce0411df8938b6a2bea57c6e) - check_type(argname="argument key", value=key, expected_type=type_hints["key"]) - check_type(argname="argument operator", value=operator, expected_type=type_hints["operator"]) - check_type(argname="argument values", value=values, expected_type=type_hints["values"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "key": key, - "operator": operator, - } - if values is not None: - self._values["values"] = values - - @builtins.property - def key(self) -> builtins.str: - '''The label key that the selector applies to. - - :schema: io.k8s.api.core.v1.NodeSelectorRequirement#key - ''' - result = self._values.get("key") - assert result is not None, "Required property 'key' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def operator(self) -> builtins.str: - '''Represents a key's relationship to a set of values. - - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - - :schema: io.k8s.api.core.v1.NodeSelectorRequirement#operator - ''' - result = self._values.get("operator") - assert result is not None, "Required property 'operator' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def values(self) -> typing.Optional[typing.List[builtins.str]]: - '''An array of string values. - - If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. - - :schema: io.k8s.api.core.v1.NodeSelectorRequirement#values - ''' - result = self._values.get("values") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "NodeSelectorRequirement(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.NodeSelectorTerm", - jsii_struct_bases=[], - name_mapping={ - "match_expressions": "matchExpressions", - "match_fields": "matchFields", - }, -) -class NodeSelectorTerm: - def __init__( - self, - *, - match_expressions: typing.Optional[typing.Sequence[typing.Union[NodeSelectorRequirement, typing.Dict[builtins.str, typing.Any]]]] = None, - match_fields: typing.Optional[typing.Sequence[typing.Union[NodeSelectorRequirement, typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''A null or empty node selector term matches no objects. - - The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. - - :param match_expressions: A list of node selector requirements by node's labels. - :param match_fields: A list of node selector requirements by node's fields. - - :schema: io.k8s.api.core.v1.NodeSelectorTerm - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__00ea4bc7ccd8ca5e61bdb8b0ba65854a04f15b4b8fbaf25f3edafd171975a953) - check_type(argname="argument match_expressions", value=match_expressions, expected_type=type_hints["match_expressions"]) - check_type(argname="argument match_fields", value=match_fields, expected_type=type_hints["match_fields"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if match_expressions is not None: - self._values["match_expressions"] = match_expressions - if match_fields is not None: - self._values["match_fields"] = match_fields - - @builtins.property - def match_expressions( - self, - ) -> typing.Optional[typing.List[NodeSelectorRequirement]]: - '''A list of node selector requirements by node's labels. - - :schema: io.k8s.api.core.v1.NodeSelectorTerm#matchExpressions - ''' - result = self._values.get("match_expressions") - return typing.cast(typing.Optional[typing.List[NodeSelectorRequirement]], result) - - @builtins.property - def match_fields(self) -> typing.Optional[typing.List[NodeSelectorRequirement]]: - '''A list of node selector requirements by node's fields. - - :schema: io.k8s.api.core.v1.NodeSelectorTerm#matchFields - ''' - result = self._values.get("match_fields") - return typing.cast(typing.Optional[typing.List[NodeSelectorRequirement]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "NodeSelectorTerm(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.NodeSpec", - jsii_struct_bases=[], - name_mapping={ - "config_source": "configSource", - "external_id": "externalId", - "pod_cidr": "podCidr", - "pod_cid_rs": "podCidRs", - "provider_id": "providerId", - "taints": "taints", - "unschedulable": "unschedulable", - }, -) -class NodeSpec: - def __init__( - self, - *, - config_source: typing.Optional[typing.Union[NodeConfigSource, typing.Dict[builtins.str, typing.Any]]] = None, - external_id: typing.Optional[builtins.str] = None, - pod_cidr: typing.Optional[builtins.str] = None, - pod_cid_rs: typing.Optional[typing.Sequence[builtins.str]] = None, - provider_id: typing.Optional[builtins.str] = None, - taints: typing.Optional[typing.Sequence[typing.Union["Taint", typing.Dict[builtins.str, typing.Any]]]] = None, - unschedulable: typing.Optional[builtins.bool] = None, - ) -> None: - '''NodeSpec describes the attributes that a node is created with. - - :param config_source: Deprecated: Previously used to specify the source of the node's configuration for the DynamicKubeletConfig feature. This feature is removed. - :param external_id: Deprecated. Not all kubelets will set this field. Remove field after 1.13. see: https://issues.k8s.io/61966 - :param pod_cidr: PodCIDR represents the pod IP range assigned to the node. - :param pod_cid_rs: podCIDRs represents the IP ranges assigned to the node for usage by Pods on that node. If this field is specified, the 0th entry must match the podCIDR field. It may contain at most 1 value for each of IPv4 and IPv6. - :param provider_id: ID of the node assigned by the cloud provider in the format: ://. - :param taints: If specified, the node's taints. - :param unschedulable: Unschedulable controls node schedulability of new pods. By default, node is schedulable. More info: https://kubernetes.io/docs/concepts/nodes/node/#manual-node-administration - - :schema: io.k8s.api.core.v1.NodeSpec - ''' - if isinstance(config_source, dict): - config_source = NodeConfigSource(**config_source) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__6e50f14ca142b7e1ae3aa4c3b0de77e924013889955b6653359e1c2bc719eb0d) - check_type(argname="argument config_source", value=config_source, expected_type=type_hints["config_source"]) - check_type(argname="argument external_id", value=external_id, expected_type=type_hints["external_id"]) - check_type(argname="argument pod_cidr", value=pod_cidr, expected_type=type_hints["pod_cidr"]) - check_type(argname="argument pod_cid_rs", value=pod_cid_rs, expected_type=type_hints["pod_cid_rs"]) - check_type(argname="argument provider_id", value=provider_id, expected_type=type_hints["provider_id"]) - check_type(argname="argument taints", value=taints, expected_type=type_hints["taints"]) - check_type(argname="argument unschedulable", value=unschedulable, expected_type=type_hints["unschedulable"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if config_source is not None: - self._values["config_source"] = config_source - if external_id is not None: - self._values["external_id"] = external_id - if pod_cidr is not None: - self._values["pod_cidr"] = pod_cidr - if pod_cid_rs is not None: - self._values["pod_cid_rs"] = pod_cid_rs - if provider_id is not None: - self._values["provider_id"] = provider_id - if taints is not None: - self._values["taints"] = taints - if unschedulable is not None: - self._values["unschedulable"] = unschedulable - - @builtins.property - def config_source(self) -> typing.Optional[NodeConfigSource]: - '''Deprecated: Previously used to specify the source of the node's configuration for the DynamicKubeletConfig feature. - - This feature is removed. - - :schema: io.k8s.api.core.v1.NodeSpec#configSource - ''' - result = self._values.get("config_source") - return typing.cast(typing.Optional[NodeConfigSource], result) - - @builtins.property - def external_id(self) -> typing.Optional[builtins.str]: - '''Deprecated. - - Not all kubelets will set this field. Remove field after 1.13. see: https://issues.k8s.io/61966 - - :schema: io.k8s.api.core.v1.NodeSpec#externalID - ''' - result = self._values.get("external_id") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def pod_cidr(self) -> typing.Optional[builtins.str]: - '''PodCIDR represents the pod IP range assigned to the node. - - :schema: io.k8s.api.core.v1.NodeSpec#podCIDR - ''' - result = self._values.get("pod_cidr") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def pod_cid_rs(self) -> typing.Optional[typing.List[builtins.str]]: - '''podCIDRs represents the IP ranges assigned to the node for usage by Pods on that node. - - If this field is specified, the 0th entry must match the podCIDR field. It may contain at most 1 value for each of IPv4 and IPv6. - - :schema: io.k8s.api.core.v1.NodeSpec#podCIDRs - ''' - result = self._values.get("pod_cid_rs") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def provider_id(self) -> typing.Optional[builtins.str]: - '''ID of the node assigned by the cloud provider in the format: ://. - - :schema: io.k8s.api.core.v1.NodeSpec#providerID - ''' - result = self._values.get("provider_id") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def taints(self) -> typing.Optional[typing.List["Taint"]]: - '''If specified, the node's taints. - - :schema: io.k8s.api.core.v1.NodeSpec#taints - ''' - result = self._values.get("taints") - return typing.cast(typing.Optional[typing.List["Taint"]], result) - - @builtins.property - def unschedulable(self) -> typing.Optional[builtins.bool]: - '''Unschedulable controls node schedulability of new pods. - - By default, node is schedulable. More info: https://kubernetes.io/docs/concepts/nodes/node/#manual-node-administration - - :schema: io.k8s.api.core.v1.NodeSpec#unschedulable - ''' - result = self._values.get("unschedulable") - return typing.cast(typing.Optional[builtins.bool], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "NodeSpec(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.NonResourceAttributes", - jsii_struct_bases=[], - name_mapping={"path": "path", "verb": "verb"}, -) -class NonResourceAttributes: - def __init__( - self, - *, - path: typing.Optional[builtins.str] = None, - verb: typing.Optional[builtins.str] = None, - ) -> None: - '''NonResourceAttributes includes the authorization attributes available for non-resource requests to the Authorizer interface. - - :param path: Path is the URL path of the request. - :param verb: Verb is the standard HTTP verb. - - :schema: io.k8s.api.authorization.v1.NonResourceAttributes - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__87614183732b5aa4dd1bacd6db0063d066b6c9f07ce5f58af69ea84b6410702b) - check_type(argname="argument path", value=path, expected_type=type_hints["path"]) - check_type(argname="argument verb", value=verb, expected_type=type_hints["verb"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if path is not None: - self._values["path"] = path - if verb is not None: - self._values["verb"] = verb - - @builtins.property - def path(self) -> typing.Optional[builtins.str]: - '''Path is the URL path of the request. - - :schema: io.k8s.api.authorization.v1.NonResourceAttributes#path - ''' - result = self._values.get("path") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def verb(self) -> typing.Optional[builtins.str]: - '''Verb is the standard HTTP verb. - - :schema: io.k8s.api.authorization.v1.NonResourceAttributes#verb - ''' - result = self._values.get("verb") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "NonResourceAttributes(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.NonResourcePolicyRuleV1Beta2", - jsii_struct_bases=[], - name_mapping={"non_resource_ur_ls": "nonResourceUrLs", "verbs": "verbs"}, -) -class NonResourcePolicyRuleV1Beta2: - def __init__( - self, - *, - non_resource_ur_ls: typing.Sequence[builtins.str], - verbs: typing.Sequence[builtins.str], - ) -> None: - '''NonResourcePolicyRule is a predicate that matches non-resource requests according to their verb and the target non-resource URL. - - A NonResourcePolicyRule matches a request if and only if both (a) at least one member of verbs matches the request and (b) at least one member of nonResourceURLs matches the request. - - :param non_resource_ur_ls: ``nonResourceURLs`` is a set of url prefixes that a user should have access to and may not be empty. For example: - "/healthz" is legal - "/hea*" is illegal - "/hea" is legal but matches nothing - "/hea/*" also matches nothing - "/healthz/*" matches all per-component health checks. "*" matches all non-resource urls. if it is present, it must be the only entry. Required. - :param verbs: ``verbs`` is a list of matching verbs and may not be empty. "*" matches all verbs. If it is present, it must be the only entry. Required. - - :schema: io.k8s.api.flowcontrol.v1beta2.NonResourcePolicyRule - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__78a3ae6e3e68c976f8ca44549a07d51b42b5a18ad0717f0a4f2148124dce3b35) - check_type(argname="argument non_resource_ur_ls", value=non_resource_ur_ls, expected_type=type_hints["non_resource_ur_ls"]) - check_type(argname="argument verbs", value=verbs, expected_type=type_hints["verbs"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "non_resource_ur_ls": non_resource_ur_ls, - "verbs": verbs, - } - - @builtins.property - def non_resource_ur_ls(self) -> typing.List[builtins.str]: - '''``nonResourceURLs`` is a set of url prefixes that a user should have access to and may not be empty. - - For example: - - - "/healthz" is legal - - "/hea*" is illegal - - "/hea" is legal but matches nothing - - "/hea/*" also matches nothing - - "/healthz/*" matches all per-component health checks. - "*" matches all non-resource urls. if it is present, it must be the only entry. Required. - - :schema: io.k8s.api.flowcontrol.v1beta2.NonResourcePolicyRule#nonResourceURLs - ''' - result = self._values.get("non_resource_ur_ls") - assert result is not None, "Required property 'non_resource_ur_ls' is missing" - return typing.cast(typing.List[builtins.str], result) - - @builtins.property - def verbs(self) -> typing.List[builtins.str]: - '''``verbs`` is a list of matching verbs and may not be empty. - - "*" matches all verbs. If it is present, it must be the only entry. Required. - - :schema: io.k8s.api.flowcontrol.v1beta2.NonResourcePolicyRule#verbs - ''' - result = self._values.get("verbs") - assert result is not None, "Required property 'verbs' is missing" - return typing.cast(typing.List[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "NonResourcePolicyRuleV1Beta2(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.NonResourcePolicyRuleV1Beta3", - jsii_struct_bases=[], - name_mapping={"non_resource_ur_ls": "nonResourceUrLs", "verbs": "verbs"}, -) -class NonResourcePolicyRuleV1Beta3: - def __init__( - self, - *, - non_resource_ur_ls: typing.Sequence[builtins.str], - verbs: typing.Sequence[builtins.str], - ) -> None: - '''NonResourcePolicyRule is a predicate that matches non-resource requests according to their verb and the target non-resource URL. - - A NonResourcePolicyRule matches a request if and only if both (a) at least one member of verbs matches the request and (b) at least one member of nonResourceURLs matches the request. - - :param non_resource_ur_ls: ``nonResourceURLs`` is a set of url prefixes that a user should have access to and may not be empty. For example: - "/healthz" is legal - "/hea*" is illegal - "/hea" is legal but matches nothing - "/hea/*" also matches nothing - "/healthz/*" matches all per-component health checks. "*" matches all non-resource urls. if it is present, it must be the only entry. Required. - :param verbs: ``verbs`` is a list of matching verbs and may not be empty. "*" matches all verbs. If it is present, it must be the only entry. Required. - - :schema: io.k8s.api.flowcontrol.v1beta3.NonResourcePolicyRule - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__549b23213444b2d234a332570b6d25763ed069c291b506dcbc8e9cfbd8b38579) - check_type(argname="argument non_resource_ur_ls", value=non_resource_ur_ls, expected_type=type_hints["non_resource_ur_ls"]) - check_type(argname="argument verbs", value=verbs, expected_type=type_hints["verbs"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "non_resource_ur_ls": non_resource_ur_ls, - "verbs": verbs, - } - - @builtins.property - def non_resource_ur_ls(self) -> typing.List[builtins.str]: - '''``nonResourceURLs`` is a set of url prefixes that a user should have access to and may not be empty. - - For example: - - - "/healthz" is legal - - "/hea*" is illegal - - "/hea" is legal but matches nothing - - "/hea/*" also matches nothing - - "/healthz/*" matches all per-component health checks. - "*" matches all non-resource urls. if it is present, it must be the only entry. Required. - - :schema: io.k8s.api.flowcontrol.v1beta3.NonResourcePolicyRule#nonResourceURLs - ''' - result = self._values.get("non_resource_ur_ls") - assert result is not None, "Required property 'non_resource_ur_ls' is missing" - return typing.cast(typing.List[builtins.str], result) - - @builtins.property - def verbs(self) -> typing.List[builtins.str]: - '''``verbs`` is a list of matching verbs and may not be empty. - - "*" matches all verbs. If it is present, it must be the only entry. Required. - - :schema: io.k8s.api.flowcontrol.v1beta3.NonResourcePolicyRule#verbs - ''' - result = self._values.get("verbs") - assert result is not None, "Required property 'verbs' is missing" - return typing.cast(typing.List[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "NonResourcePolicyRuleV1Beta3(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ObjectFieldSelector", - jsii_struct_bases=[], - name_mapping={"field_path": "fieldPath", "api_version": "apiVersion"}, -) -class ObjectFieldSelector: - def __init__( - self, - *, - field_path: builtins.str, - api_version: typing.Optional[builtins.str] = None, - ) -> None: - '''ObjectFieldSelector selects an APIVersioned field of an object. - - :param field_path: Path of the field to select in the specified API version. - :param api_version: Version of the schema the FieldPath is written in terms of, defaults to "v1". - - :schema: io.k8s.api.core.v1.ObjectFieldSelector - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__c814859696bb254244f25cd638a669639c7d94c59b5e4180978a9f2c8497378a) - check_type(argname="argument field_path", value=field_path, expected_type=type_hints["field_path"]) - check_type(argname="argument api_version", value=api_version, expected_type=type_hints["api_version"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "field_path": field_path, - } - if api_version is not None: - self._values["api_version"] = api_version - - @builtins.property - def field_path(self) -> builtins.str: - '''Path of the field to select in the specified API version. - - :schema: io.k8s.api.core.v1.ObjectFieldSelector#fieldPath - ''' - result = self._values.get("field_path") - assert result is not None, "Required property 'field_path' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def api_version(self) -> typing.Optional[builtins.str]: - '''Version of the schema the FieldPath is written in terms of, defaults to "v1". - - :schema: io.k8s.api.core.v1.ObjectFieldSelector#apiVersion - ''' - result = self._values.get("api_version") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ObjectFieldSelector(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ObjectMeta", - jsii_struct_bases=[], - name_mapping={ - "annotations": "annotations", - "creation_timestamp": "creationTimestamp", - "deletion_grace_period_seconds": "deletionGracePeriodSeconds", - "deletion_timestamp": "deletionTimestamp", - "finalizers": "finalizers", - "generate_name": "generateName", - "generation": "generation", - "labels": "labels", - "managed_fields": "managedFields", - "name": "name", - "namespace": "namespace", - "owner_references": "ownerReferences", - "resource_version": "resourceVersion", - "self_link": "selfLink", - "uid": "uid", - }, -) -class ObjectMeta: - def __init__( - self, - *, - annotations: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - creation_timestamp: typing.Optional[datetime.datetime] = None, - deletion_grace_period_seconds: typing.Optional[jsii.Number] = None, - deletion_timestamp: typing.Optional[datetime.datetime] = None, - finalizers: typing.Optional[typing.Sequence[builtins.str]] = None, - generate_name: typing.Optional[builtins.str] = None, - generation: typing.Optional[jsii.Number] = None, - labels: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - managed_fields: typing.Optional[typing.Sequence[typing.Union[ManagedFieldsEntry, typing.Dict[builtins.str, typing.Any]]]] = None, - name: typing.Optional[builtins.str] = None, - namespace: typing.Optional[builtins.str] = None, - owner_references: typing.Optional[typing.Sequence[typing.Union["OwnerReference", typing.Dict[builtins.str, typing.Any]]]] = None, - resource_version: typing.Optional[builtins.str] = None, - self_link: typing.Optional[builtins.str] = None, - uid: typing.Optional[builtins.str] = None, - ) -> None: - '''ObjectMeta is metadata that all persisted resources must have, which includes all objects users must create. - - :param annotations: Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. They are not queryable and should be preserved when modifying objects. More info: http://kubernetes.io/docs/user-guide/annotations - :param creation_timestamp: CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param deletion_grace_period_seconds: Number of seconds allowed for this object to gracefully terminate before it will be removed from the system. Only set when deletionTimestamp is also set. May only be shortened. Read-only. - :param deletion_timestamp: DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This field is set by the server when a graceful deletion is requested by the user, and is not directly settable by a client. The resource is expected to be deleted (no longer visible from resource lists, and not reachable by name) after the time in this field, once the finalizers list is empty. As long as the finalizers list contains items, deletion is blocked. Once the deletionTimestamp is set, this value may not be unset or be set further into the future, although it may be shortened or the resource may be deleted prior to this time. For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react by sending a graceful termination signal to the containers in the pod. After that 30 seconds, the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup, remove the pod from the API. In the presence of network partitions, this object may still exist after this timestamp, until an administrator or automated process can determine the resource is fully terminated. If not set, graceful deletion of the object has not been requested. Populated by the system when a graceful deletion is requested. Read-only. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param finalizers: Must be empty before the object is deleted from the registry. Each entry is an identifier for the responsible component that will remove the entry from the list. If the deletionTimestamp of the object is non-nil, entries in this list can only be removed. Finalizers may be processed and removed in any order. Order is NOT enforced because it introduces significant risk of stuck finalizers. finalizers is a shared field, any actor with permission can reorder it. If the finalizer list is processed in order, then this can lead to a situation in which the component responsible for the first finalizer in the list is waiting for a signal (field value, external system, or other) produced by a component responsible for a finalizer later in the list, resulting in a deadlock. Without enforced ordering finalizers are free to order amongst themselves and are not vulnerable to ordering changes in the list. - :param generate_name: GenerateName is an optional prefix, used by the server, to generate a unique name ONLY IF the Name field has not been provided. If this field is used, the name returned to the client will be different than the name passed. This value will also be combined with a unique suffix. The provided value has the same validation rules as the Name field, and may be truncated by the length of the suffix required to make the value unique on the server. If this field is specified and the generated name exists, the server will return a 409. Applied only if Name is not specified. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency - :param generation: A sequence number representing a specific generation of the desired state. Populated by the system. Read-only. - :param labels: Map of string keys and values that can be used to organize and categorize (scope and select) objects. May match selectors of replication controllers and services. More info: http://kubernetes.io/docs/user-guide/labels - :param managed_fields: ManagedFields maps workflow-id and version to the set of fields that are managed by that workflow. This is mostly for internal housekeeping, and users typically shouldn't need to set or understand this field. A workflow can be the user's name, a controller's name, or the name of a specific apply path like "ci-cd". The set of fields is always in the version that the workflow used when modifying the object. - :param name: Name must be unique within a namespace. Is required when creating resources, although some resources may allow a client to request the generation of an appropriate name automatically. Name is primarily intended for creation idempotence and configuration definition. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/identifiers#names - :param namespace: Namespace defines the space within which each name must be unique. An empty namespace is equivalent to the "default" namespace, but "default" is the canonical representation. Not all objects are required to be scoped to a namespace - the value of this field for those objects will be empty. Must be a DNS_LABEL. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/namespaces - :param owner_references: List of objects depended by this object. If ALL objects in the list have been deleted, this object will be garbage collected. If this object is managed by a controller, then an entry in this list will point to this controller, with the controller field set to true. There cannot be more than one managing controller. - :param resource_version: An opaque value that represents the internal version of this object that can be used by clients to determine when objects have changed. May be used for optimistic concurrency, change detection, and the watch operation on a resource or set of resources. Clients must treat these values as opaque and passed unmodified back to the server. They may only be valid for a particular resource or set of resources. Populated by the system. Read-only. Value must be treated as opaque by clients and . More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - :param self_link: Deprecated: selfLink is a legacy read-only field that is no longer populated by the system. - :param uid: UID is the unique in time and space value for this object. It is typically generated by the server on successful creation of a resource and is not allowed to change on PUT operations. Populated by the system. Read-only. More info: http://kubernetes.io/docs/user-guide/identifiers#uids - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__7ee1f9d34e34f50cf19155ec68863e4beccde0e8fb69f1e800f6e8b53b8a2af5) - check_type(argname="argument annotations", value=annotations, expected_type=type_hints["annotations"]) - check_type(argname="argument creation_timestamp", value=creation_timestamp, expected_type=type_hints["creation_timestamp"]) - check_type(argname="argument deletion_grace_period_seconds", value=deletion_grace_period_seconds, expected_type=type_hints["deletion_grace_period_seconds"]) - check_type(argname="argument deletion_timestamp", value=deletion_timestamp, expected_type=type_hints["deletion_timestamp"]) - check_type(argname="argument finalizers", value=finalizers, expected_type=type_hints["finalizers"]) - check_type(argname="argument generate_name", value=generate_name, expected_type=type_hints["generate_name"]) - check_type(argname="argument generation", value=generation, expected_type=type_hints["generation"]) - check_type(argname="argument labels", value=labels, expected_type=type_hints["labels"]) - check_type(argname="argument managed_fields", value=managed_fields, expected_type=type_hints["managed_fields"]) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument namespace", value=namespace, expected_type=type_hints["namespace"]) - check_type(argname="argument owner_references", value=owner_references, expected_type=type_hints["owner_references"]) - check_type(argname="argument resource_version", value=resource_version, expected_type=type_hints["resource_version"]) - check_type(argname="argument self_link", value=self_link, expected_type=type_hints["self_link"]) - check_type(argname="argument uid", value=uid, expected_type=type_hints["uid"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if annotations is not None: - self._values["annotations"] = annotations - if creation_timestamp is not None: - self._values["creation_timestamp"] = creation_timestamp - if deletion_grace_period_seconds is not None: - self._values["deletion_grace_period_seconds"] = deletion_grace_period_seconds - if deletion_timestamp is not None: - self._values["deletion_timestamp"] = deletion_timestamp - if finalizers is not None: - self._values["finalizers"] = finalizers - if generate_name is not None: - self._values["generate_name"] = generate_name - if generation is not None: - self._values["generation"] = generation - if labels is not None: - self._values["labels"] = labels - if managed_fields is not None: - self._values["managed_fields"] = managed_fields - if name is not None: - self._values["name"] = name - if namespace is not None: - self._values["namespace"] = namespace - if owner_references is not None: - self._values["owner_references"] = owner_references - if resource_version is not None: - self._values["resource_version"] = resource_version - if self_link is not None: - self._values["self_link"] = self_link - if uid is not None: - self._values["uid"] = uid - - @builtins.property - def annotations( - self, - ) -> typing.Optional[typing.Mapping[builtins.str, builtins.str]]: - '''Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. - - They are not queryable and should be preserved when modifying objects. More info: http://kubernetes.io/docs/user-guide/annotations - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta#annotations - ''' - result = self._values.get("annotations") - return typing.cast(typing.Optional[typing.Mapping[builtins.str, builtins.str]], result) - - @builtins.property - def creation_timestamp(self) -> typing.Optional[datetime.datetime]: - '''CreationTimestamp is a timestamp representing the server time when this object was created. - - It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. - - Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta#creationTimestamp - ''' - result = self._values.get("creation_timestamp") - return typing.cast(typing.Optional[datetime.datetime], result) - - @builtins.property - def deletion_grace_period_seconds(self) -> typing.Optional[jsii.Number]: - '''Number of seconds allowed for this object to gracefully terminate before it will be removed from the system. - - Only set when deletionTimestamp is also set. May only be shortened. Read-only. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta#deletionGracePeriodSeconds - ''' - result = self._values.get("deletion_grace_period_seconds") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def deletion_timestamp(self) -> typing.Optional[datetime.datetime]: - '''DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. - - This field is set by the server when a graceful deletion is requested by the user, and is not directly settable by a client. The resource is expected to be deleted (no longer visible from resource lists, and not reachable by name) after the time in this field, once the finalizers list is empty. As long as the finalizers list contains items, deletion is blocked. Once the deletionTimestamp is set, this value may not be unset or be set further into the future, although it may be shortened or the resource may be deleted prior to this time. For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react by sending a graceful termination signal to the containers in the pod. After that 30 seconds, the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup, remove the pod from the API. In the presence of network partitions, this object may still exist after this timestamp, until an administrator or automated process can determine the resource is fully terminated. If not set, graceful deletion of the object has not been requested. - - Populated by the system when a graceful deletion is requested. Read-only. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta#deletionTimestamp - ''' - result = self._values.get("deletion_timestamp") - return typing.cast(typing.Optional[datetime.datetime], result) - - @builtins.property - def finalizers(self) -> typing.Optional[typing.List[builtins.str]]: - '''Must be empty before the object is deleted from the registry. - - Each entry is an identifier for the responsible component that will remove the entry from the list. If the deletionTimestamp of the object is non-nil, entries in this list can only be removed. Finalizers may be processed and removed in any order. Order is NOT enforced because it introduces significant risk of stuck finalizers. finalizers is a shared field, any actor with permission can reorder it. If the finalizer list is processed in order, then this can lead to a situation in which the component responsible for the first finalizer in the list is waiting for a signal (field value, external system, or other) produced by a component responsible for a finalizer later in the list, resulting in a deadlock. Without enforced ordering finalizers are free to order amongst themselves and are not vulnerable to ordering changes in the list. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta#finalizers - ''' - result = self._values.get("finalizers") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def generate_name(self) -> typing.Optional[builtins.str]: - '''GenerateName is an optional prefix, used by the server, to generate a unique name ONLY IF the Name field has not been provided. - - If this field is used, the name returned to the client will be different than the name passed. This value will also be combined with a unique suffix. The provided value has the same validation rules as the Name field, and may be truncated by the length of the suffix required to make the value unique on the server. - - If this field is specified and the generated name exists, the server will return a 409. - - Applied only if Name is not specified. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta#generateName - ''' - result = self._values.get("generate_name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def generation(self) -> typing.Optional[jsii.Number]: - '''A sequence number representing a specific generation of the desired state. - - Populated by the system. Read-only. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta#generation - ''' - result = self._values.get("generation") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def labels(self) -> typing.Optional[typing.Mapping[builtins.str, builtins.str]]: - '''Map of string keys and values that can be used to organize and categorize (scope and select) objects. - - May match selectors of replication controllers and services. More info: http://kubernetes.io/docs/user-guide/labels - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta#labels - ''' - result = self._values.get("labels") - return typing.cast(typing.Optional[typing.Mapping[builtins.str, builtins.str]], result) - - @builtins.property - def managed_fields(self) -> typing.Optional[typing.List[ManagedFieldsEntry]]: - '''ManagedFields maps workflow-id and version to the set of fields that are managed by that workflow. - - This is mostly for internal housekeeping, and users typically shouldn't need to set or understand this field. A workflow can be the user's name, a controller's name, or the name of a specific apply path like "ci-cd". The set of fields is always in the version that the workflow used when modifying the object. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta#managedFields - ''' - result = self._values.get("managed_fields") - return typing.cast(typing.Optional[typing.List[ManagedFieldsEntry]], result) - - @builtins.property - def name(self) -> typing.Optional[builtins.str]: - '''Name must be unique within a namespace. - - Is required when creating resources, although some resources may allow a client to request the generation of an appropriate name automatically. Name is primarily intended for creation idempotence and configuration definition. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/identifiers#names - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta#name - ''' - result = self._values.get("name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def namespace(self) -> typing.Optional[builtins.str]: - '''Namespace defines the space within which each name must be unique. - - An empty namespace is equivalent to the "default" namespace, but "default" is the canonical representation. Not all objects are required to be scoped to a namespace - the value of this field for those objects will be empty. - - Must be a DNS_LABEL. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/namespaces - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta#namespace - ''' - result = self._values.get("namespace") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def owner_references(self) -> typing.Optional[typing.List["OwnerReference"]]: - '''List of objects depended by this object. - - If ALL objects in the list have been deleted, this object will be garbage collected. If this object is managed by a controller, then an entry in this list will point to this controller, with the controller field set to true. There cannot be more than one managing controller. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta#ownerReferences - ''' - result = self._values.get("owner_references") - return typing.cast(typing.Optional[typing.List["OwnerReference"]], result) - - @builtins.property - def resource_version(self) -> typing.Optional[builtins.str]: - '''An opaque value that represents the internal version of this object that can be used by clients to determine when objects have changed. - - May be used for optimistic concurrency, change detection, and the watch operation on a resource or set of resources. Clients must treat these values as opaque and passed unmodified back to the server. They may only be valid for a particular resource or set of resources. - - Populated by the system. Read-only. Value must be treated as opaque by clients and . More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta#resourceVersion - ''' - result = self._values.get("resource_version") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def self_link(self) -> typing.Optional[builtins.str]: - '''Deprecated: selfLink is a legacy read-only field that is no longer populated by the system. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta#selfLink - ''' - result = self._values.get("self_link") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def uid(self) -> typing.Optional[builtins.str]: - '''UID is the unique in time and space value for this object. - - It is typically generated by the server on successful creation of a resource and is not allowed to change on PUT operations. - - Populated by the system. Read-only. More info: http://kubernetes.io/docs/user-guide/identifiers#uids - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta#uid - ''' - result = self._values.get("uid") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ObjectMeta(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ObjectMetricSourceV2", - jsii_struct_bases=[], - name_mapping={ - "described_object": "describedObject", - "metric": "metric", - "target": "target", - }, -) -class ObjectMetricSourceV2: - def __init__( - self, - *, - described_object: typing.Union[CrossVersionObjectReferenceV2, typing.Dict[builtins.str, typing.Any]], - metric: typing.Union[MetricIdentifierV2, typing.Dict[builtins.str, typing.Any]], - target: typing.Union[MetricTargetV2, typing.Dict[builtins.str, typing.Any]], - ) -> None: - '''ObjectMetricSource indicates how to scale on a metric describing a kubernetes object (for example, hits-per-second on an Ingress object). - - :param described_object: describedObject specifies the descriptions of a object,such as kind,name apiVersion. - :param metric: metric identifies the target metric by name and selector. - :param target: target specifies the target value for the given metric. - - :schema: io.k8s.api.autoscaling.v2.ObjectMetricSource - ''' - if isinstance(described_object, dict): - described_object = CrossVersionObjectReferenceV2(**described_object) - if isinstance(metric, dict): - metric = MetricIdentifierV2(**metric) - if isinstance(target, dict): - target = MetricTargetV2(**target) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__059fe76b0567d05ad5259ae2145743ed0bb9b8ff4488936dba8234b467603882) - check_type(argname="argument described_object", value=described_object, expected_type=type_hints["described_object"]) - check_type(argname="argument metric", value=metric, expected_type=type_hints["metric"]) - check_type(argname="argument target", value=target, expected_type=type_hints["target"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "described_object": described_object, - "metric": metric, - "target": target, - } - - @builtins.property - def described_object(self) -> CrossVersionObjectReferenceV2: - '''describedObject specifies the descriptions of a object,such as kind,name apiVersion. - - :schema: io.k8s.api.autoscaling.v2.ObjectMetricSource#describedObject - ''' - result = self._values.get("described_object") - assert result is not None, "Required property 'described_object' is missing" - return typing.cast(CrossVersionObjectReferenceV2, result) - - @builtins.property - def metric(self) -> MetricIdentifierV2: - '''metric identifies the target metric by name and selector. - - :schema: io.k8s.api.autoscaling.v2.ObjectMetricSource#metric - ''' - result = self._values.get("metric") - assert result is not None, "Required property 'metric' is missing" - return typing.cast(MetricIdentifierV2, result) - - @builtins.property - def target(self) -> MetricTargetV2: - '''target specifies the target value for the given metric. - - :schema: io.k8s.api.autoscaling.v2.ObjectMetricSource#target - ''' - result = self._values.get("target") - assert result is not None, "Required property 'target' is missing" - return typing.cast(MetricTargetV2, result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ObjectMetricSourceV2(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ObjectReference", - jsii_struct_bases=[], - name_mapping={ - "api_version": "apiVersion", - "field_path": "fieldPath", - "kind": "kind", - "name": "name", - "namespace": "namespace", - "resource_version": "resourceVersion", - "uid": "uid", - }, -) -class ObjectReference: - def __init__( - self, - *, - api_version: typing.Optional[builtins.str] = None, - field_path: typing.Optional[builtins.str] = None, - kind: typing.Optional[builtins.str] = None, - name: typing.Optional[builtins.str] = None, - namespace: typing.Optional[builtins.str] = None, - resource_version: typing.Optional[builtins.str] = None, - uid: typing.Optional[builtins.str] = None, - ) -> None: - '''ObjectReference contains enough information to let you inspect or modify the referred object. - - :param api_version: API version of the referent. - :param field_path: If referring to a piece of an object instead of an entire object, this string should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. For example, if the object reference is to a container within a pod, this would take on a value like: "spec.containers{name}" (where "name" refers to the name of the container that triggered the event) or if no container name is specified "spec.containers[2]" (container with index 2 in this pod). This syntax is chosen only to have some well-defined way of referencing a part of an object. - :param kind: Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - :param name: Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - :param namespace: Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ - :param resource_version: Specific resourceVersion to which this reference is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - :param uid: UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids - - :schema: io.k8s.api.core.v1.ObjectReference - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__c20094532bd9f73694f77438189bb3de9c66cbdd0365b5006af71270a4661cc5) - check_type(argname="argument api_version", value=api_version, expected_type=type_hints["api_version"]) - check_type(argname="argument field_path", value=field_path, expected_type=type_hints["field_path"]) - check_type(argname="argument kind", value=kind, expected_type=type_hints["kind"]) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument namespace", value=namespace, expected_type=type_hints["namespace"]) - check_type(argname="argument resource_version", value=resource_version, expected_type=type_hints["resource_version"]) - check_type(argname="argument uid", value=uid, expected_type=type_hints["uid"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if api_version is not None: - self._values["api_version"] = api_version - if field_path is not None: - self._values["field_path"] = field_path - if kind is not None: - self._values["kind"] = kind - if name is not None: - self._values["name"] = name - if namespace is not None: - self._values["namespace"] = namespace - if resource_version is not None: - self._values["resource_version"] = resource_version - if uid is not None: - self._values["uid"] = uid - - @builtins.property - def api_version(self) -> typing.Optional[builtins.str]: - '''API version of the referent. - - :schema: io.k8s.api.core.v1.ObjectReference#apiVersion - ''' - result = self._values.get("api_version") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def field_path(self) -> typing.Optional[builtins.str]: - '''If referring to a piece of an object instead of an entire object, this string should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. For example, if the object reference is to a container within a pod, this would take on a value like: "spec.containers{name}" (where "name" refers to the name of the container that triggered the event) or if no container name is specified "spec.containers[2]" (container with index 2 in this pod). This syntax is chosen only to have some well-defined way of referencing a part of an object. - - :schema: io.k8s.api.core.v1.ObjectReference#fieldPath - ''' - result = self._values.get("field_path") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def kind(self) -> typing.Optional[builtins.str]: - '''Kind of the referent. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.api.core.v1.ObjectReference#kind - ''' - result = self._values.get("kind") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def name(self) -> typing.Optional[builtins.str]: - '''Name of the referent. - - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - - :schema: io.k8s.api.core.v1.ObjectReference#name - ''' - result = self._values.get("name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def namespace(self) -> typing.Optional[builtins.str]: - '''Namespace of the referent. - - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ - - :schema: io.k8s.api.core.v1.ObjectReference#namespace - ''' - result = self._values.get("namespace") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def resource_version(self) -> typing.Optional[builtins.str]: - '''Specific resourceVersion to which this reference is made, if any. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - - :schema: io.k8s.api.core.v1.ObjectReference#resourceVersion - ''' - result = self._values.get("resource_version") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def uid(self) -> typing.Optional[builtins.str]: - '''UID of the referent. - - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids - - :schema: io.k8s.api.core.v1.ObjectReference#uid - ''' - result = self._values.get("uid") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ObjectReference(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.Overhead", - jsii_struct_bases=[], - name_mapping={"pod_fixed": "podFixed"}, -) -class Overhead: - def __init__( - self, - *, - pod_fixed: typing.Optional[typing.Mapping[builtins.str, "Quantity"]] = None, - ) -> None: - '''Overhead structure represents the resource overhead associated with running a pod. - - :param pod_fixed: PodFixed represents the fixed resource overhead associated with running a pod. - - :schema: io.k8s.api.node.v1.Overhead - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__57ac617e483fea78edd490dac696636c32772cbc5e9c8196a16758039d227d56) - check_type(argname="argument pod_fixed", value=pod_fixed, expected_type=type_hints["pod_fixed"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if pod_fixed is not None: - self._values["pod_fixed"] = pod_fixed - - @builtins.property - def pod_fixed(self) -> typing.Optional[typing.Mapping[builtins.str, "Quantity"]]: - '''PodFixed represents the fixed resource overhead associated with running a pod. - - :schema: io.k8s.api.node.v1.Overhead#podFixed - ''' - result = self._values.get("pod_fixed") - return typing.cast(typing.Optional[typing.Mapping[builtins.str, "Quantity"]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "Overhead(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.OwnerReference", - jsii_struct_bases=[], - name_mapping={ - "api_version": "apiVersion", - "kind": "kind", - "name": "name", - "uid": "uid", - "block_owner_deletion": "blockOwnerDeletion", - "controller": "controller", - }, -) -class OwnerReference: - def __init__( - self, - *, - api_version: builtins.str, - kind: builtins.str, - name: builtins.str, - uid: builtins.str, - block_owner_deletion: typing.Optional[builtins.bool] = None, - controller: typing.Optional[builtins.bool] = None, - ) -> None: - '''OwnerReference contains enough information to let you identify an owning object. - - An owning object must be in the same namespace as the dependent, or be cluster-scoped, so there is no namespace field. - - :param api_version: API version of the referent. - :param kind: Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - :param name: Name of the referent. More info: http://kubernetes.io/docs/user-guide/identifiers#names - :param uid: UID of the referent. More info: http://kubernetes.io/docs/user-guide/identifiers#uids - :param block_owner_deletion: If true, AND if the owner has the "foregroundDeletion" finalizer, then the owner cannot be deleted from the key-value store until this reference is removed. See https://kubernetes.io/docs/concepts/architecture/garbage-collection/#foreground-deletion for how the garbage collector interacts with this field and enforces the foreground deletion. Defaults to false. To set this field, a user needs "delete" permission of the owner, otherwise 422 (Unprocessable Entity) will be returned. Default: false. To set this field, a user needs "delete" permission of the owner, otherwise 422 (Unprocessable Entity) will be returned. - :param controller: If true, this reference points to the managing controller. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.OwnerReference - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__f492c2fd31467da33dd2714b04585d0827fb1e1b0cf0b750d6db405bd88f0eeb) - check_type(argname="argument api_version", value=api_version, expected_type=type_hints["api_version"]) - check_type(argname="argument kind", value=kind, expected_type=type_hints["kind"]) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument uid", value=uid, expected_type=type_hints["uid"]) - check_type(argname="argument block_owner_deletion", value=block_owner_deletion, expected_type=type_hints["block_owner_deletion"]) - check_type(argname="argument controller", value=controller, expected_type=type_hints["controller"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "api_version": api_version, - "kind": kind, - "name": name, - "uid": uid, - } - if block_owner_deletion is not None: - self._values["block_owner_deletion"] = block_owner_deletion - if controller is not None: - self._values["controller"] = controller - - @builtins.property - def api_version(self) -> builtins.str: - '''API version of the referent. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.OwnerReference#apiVersion - ''' - result = self._values.get("api_version") - assert result is not None, "Required property 'api_version' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def kind(self) -> builtins.str: - '''Kind of the referent. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.OwnerReference#kind - ''' - result = self._values.get("kind") - assert result is not None, "Required property 'kind' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def name(self) -> builtins.str: - '''Name of the referent. - - More info: http://kubernetes.io/docs/user-guide/identifiers#names - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.OwnerReference#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def uid(self) -> builtins.str: - '''UID of the referent. - - More info: http://kubernetes.io/docs/user-guide/identifiers#uids - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.OwnerReference#uid - ''' - result = self._values.get("uid") - assert result is not None, "Required property 'uid' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def block_owner_deletion(self) -> typing.Optional[builtins.bool]: - '''If true, AND if the owner has the "foregroundDeletion" finalizer, then the owner cannot be deleted from the key-value store until this reference is removed. - - See https://kubernetes.io/docs/concepts/architecture/garbage-collection/#foreground-deletion for how the garbage collector interacts with this field and enforces the foreground deletion. Defaults to false. To set this field, a user needs "delete" permission of the owner, otherwise 422 (Unprocessable Entity) will be returned. - - :default: false. To set this field, a user needs "delete" permission of the owner, otherwise 422 (Unprocessable Entity) will be returned. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.OwnerReference#blockOwnerDeletion - ''' - result = self._values.get("block_owner_deletion") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def controller(self) -> typing.Optional[builtins.bool]: - '''If true, this reference points to the managing controller. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.OwnerReference#controller - ''' - result = self._values.get("controller") - return typing.cast(typing.Optional[builtins.bool], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "OwnerReference(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ParamKindV1Alpha1", - jsii_struct_bases=[], - name_mapping={"api_version": "apiVersion", "kind": "kind"}, -) -class ParamKindV1Alpha1: - def __init__( - self, - *, - api_version: typing.Optional[builtins.str] = None, - kind: typing.Optional[builtins.str] = None, - ) -> None: - '''ParamKind is a tuple of Group Kind and Version. - - :param api_version: APIVersion is the API group version the resources belong to. In format of "group/version". Required. - :param kind: Kind is the API kind the resources belong to. Required. - - :schema: io.k8s.api.admissionregistration.v1alpha1.ParamKind - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__ca366a1a5a55375a1aef0df1d3a5ee87b07269561ad4145843c552a10838efa1) - check_type(argname="argument api_version", value=api_version, expected_type=type_hints["api_version"]) - check_type(argname="argument kind", value=kind, expected_type=type_hints["kind"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if api_version is not None: - self._values["api_version"] = api_version - if kind is not None: - self._values["kind"] = kind - - @builtins.property - def api_version(self) -> typing.Optional[builtins.str]: - '''APIVersion is the API group version the resources belong to. - - In format of "group/version". Required. - - :schema: io.k8s.api.admissionregistration.v1alpha1.ParamKind#apiVersion - ''' - result = self._values.get("api_version") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def kind(self) -> typing.Optional[builtins.str]: - '''Kind is the API kind the resources belong to. - - Required. - - :schema: io.k8s.api.admissionregistration.v1alpha1.ParamKind#kind - ''' - result = self._values.get("kind") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ParamKindV1Alpha1(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ParamRefV1Alpha1", - jsii_struct_bases=[], - name_mapping={"name": "name", "namespace": "namespace"}, -) -class ParamRefV1Alpha1: - def __init__( - self, - *, - name: typing.Optional[builtins.str] = None, - namespace: typing.Optional[builtins.str] = None, - ) -> None: - '''ParamRef references a parameter resource. - - :param name: Name of the resource being referenced. - :param namespace: Namespace of the referenced resource. Should be empty for the cluster-scoped resources - - :schema: io.k8s.api.admissionregistration.v1alpha1.ParamRef - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__001cc96ea35cdecf4deeab0b5f67d5cac9ccd26cc9b639769b91f8b011165e5e) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument namespace", value=namespace, expected_type=type_hints["namespace"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if name is not None: - self._values["name"] = name - if namespace is not None: - self._values["namespace"] = namespace - - @builtins.property - def name(self) -> typing.Optional[builtins.str]: - '''Name of the resource being referenced. - - :schema: io.k8s.api.admissionregistration.v1alpha1.ParamRef#name - ''' - result = self._values.get("name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def namespace(self) -> typing.Optional[builtins.str]: - '''Namespace of the referenced resource. - - Should be empty for the cluster-scoped resources - - :schema: io.k8s.api.admissionregistration.v1alpha1.ParamRef#namespace - ''' - result = self._values.get("namespace") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ParamRefV1Alpha1(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.PersistentVolumeClaimSpec", - jsii_struct_bases=[], - name_mapping={ - "access_modes": "accessModes", - "data_source": "dataSource", - "data_source_ref": "dataSourceRef", - "resources": "resources", - "selector": "selector", - "storage_class_name": "storageClassName", - "volume_mode": "volumeMode", - "volume_name": "volumeName", - }, -) -class PersistentVolumeClaimSpec: - def __init__( - self, - *, - access_modes: typing.Optional[typing.Sequence[builtins.str]] = None, - data_source: typing.Optional[typing.Union["TypedLocalObjectReference", typing.Dict[builtins.str, typing.Any]]] = None, - data_source_ref: typing.Optional[typing.Union["TypedObjectReference", typing.Dict[builtins.str, typing.Any]]] = None, - resources: typing.Optional[typing.Union["ResourceRequirements", typing.Dict[builtins.str, typing.Any]]] = None, - selector: typing.Optional[typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]]] = None, - storage_class_name: typing.Optional[builtins.str] = None, - volume_mode: typing.Optional[builtins.str] = None, - volume_name: typing.Optional[builtins.str] = None, - ) -> None: - '''PersistentVolumeClaimSpec describes the common attributes of storage devices and allows a Source for provider-specific attributes. - - :param access_modes: accessModes contains the desired access modes the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 - :param data_source: dataSource field can be used to specify either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) * An existing PVC (PersistentVolumeClaim) If the provisioner or an external controller can support the specified data source, it will create a new volume based on the contents of the specified data source. When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. If the namespace is specified, then dataSourceRef will not be copied to dataSource. - :param data_source_ref: dataSourceRef specifies the object from which to populate the volume with data, if a non-empty volume is desired. This may be any object from a non-empty API group (non core object) or a PersistentVolumeClaim object. When this field is specified, volume binding will only succeed if the type of the specified object matches some installed volume populator or dynamic provisioner. This field will replace the functionality of the dataSource field and as such if both fields are non-empty, they must have the same value. For backwards compatibility, when namespace isn't specified in dataSourceRef, both fields (dataSource and dataSourceRef) will be set to the same value automatically if one of them is empty and the other is non-empty. When namespace is specified in dataSourceRef, dataSource isn't set to the same value and must be empty. There are three important differences between dataSource and dataSourceRef: * While dataSource only allows two specific types of objects, dataSourceRef allows any non-core object, as well as PersistentVolumeClaim objects. - While dataSource ignores disallowed values (dropping them), dataSourceRef preserves all values, and generates an error if a disallowed value is specified. - While dataSource only allows local objects, dataSourceRef allows objects in any namespaces. (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - :param resources: resources represents the minimum resources the volume should have. If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements that are lower than previous value but must still be higher than capacity recorded in the status field of the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources - :param selector: selector is a label query over volumes to consider for binding. - :param storage_class_name: storageClassName is the name of the StorageClass required by the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 - :param volume_mode: volumeMode defines what type of volume is required by the claim. Value of Filesystem is implied when not included in claim spec. - :param volume_name: volumeName is the binding reference to the PersistentVolume backing this claim. - - :schema: io.k8s.api.core.v1.PersistentVolumeClaimSpec - ''' - if isinstance(data_source, dict): - data_source = TypedLocalObjectReference(**data_source) - if isinstance(data_source_ref, dict): - data_source_ref = TypedObjectReference(**data_source_ref) - if isinstance(resources, dict): - resources = ResourceRequirements(**resources) - if isinstance(selector, dict): - selector = LabelSelector(**selector) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__be23e20b8fae04cc3c5f02f0df1e7da53e588f89c5d6bcc9ca2ad145ca3ea9ac) - check_type(argname="argument access_modes", value=access_modes, expected_type=type_hints["access_modes"]) - check_type(argname="argument data_source", value=data_source, expected_type=type_hints["data_source"]) - check_type(argname="argument data_source_ref", value=data_source_ref, expected_type=type_hints["data_source_ref"]) - check_type(argname="argument resources", value=resources, expected_type=type_hints["resources"]) - check_type(argname="argument selector", value=selector, expected_type=type_hints["selector"]) - check_type(argname="argument storage_class_name", value=storage_class_name, expected_type=type_hints["storage_class_name"]) - check_type(argname="argument volume_mode", value=volume_mode, expected_type=type_hints["volume_mode"]) - check_type(argname="argument volume_name", value=volume_name, expected_type=type_hints["volume_name"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if access_modes is not None: - self._values["access_modes"] = access_modes - if data_source is not None: - self._values["data_source"] = data_source - if data_source_ref is not None: - self._values["data_source_ref"] = data_source_ref - if resources is not None: - self._values["resources"] = resources - if selector is not None: - self._values["selector"] = selector - if storage_class_name is not None: - self._values["storage_class_name"] = storage_class_name - if volume_mode is not None: - self._values["volume_mode"] = volume_mode - if volume_name is not None: - self._values["volume_name"] = volume_name - - @builtins.property - def access_modes(self) -> typing.Optional[typing.List[builtins.str]]: - '''accessModes contains the desired access modes the volume should have. - - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 - - :schema: io.k8s.api.core.v1.PersistentVolumeClaimSpec#accessModes - ''' - result = self._values.get("access_modes") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def data_source(self) -> typing.Optional["TypedLocalObjectReference"]: - '''dataSource field can be used to specify either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) * An existing PVC (PersistentVolumeClaim) If the provisioner or an external controller can support the specified data source, it will create a new volume based on the contents of the specified data source. When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. If the namespace is specified, then dataSourceRef will not be copied to dataSource. - - :schema: io.k8s.api.core.v1.PersistentVolumeClaimSpec#dataSource - ''' - result = self._values.get("data_source") - return typing.cast(typing.Optional["TypedLocalObjectReference"], result) - - @builtins.property - def data_source_ref(self) -> typing.Optional["TypedObjectReference"]: - '''dataSourceRef specifies the object from which to populate the volume with data, if a non-empty volume is desired. - - This may be any object from a non-empty API group (non core object) or a PersistentVolumeClaim object. When this field is specified, volume binding will only succeed if the type of the specified object matches some installed volume populator or dynamic provisioner. This field will replace the functionality of the dataSource field and as such if both fields are non-empty, they must have the same value. For backwards compatibility, when namespace isn't specified in dataSourceRef, both fields (dataSource and dataSourceRef) will be set to the same value automatically if one of them is empty and the other is non-empty. When namespace is specified in dataSourceRef, dataSource isn't set to the same value and must be empty. There are three important differences between dataSource and dataSourceRef: * While dataSource only allows two specific types of objects, dataSourceRef - allows any non-core object, as well as PersistentVolumeClaim objects. - - - While dataSource ignores disallowed values (dropping them), dataSourceRef - preserves all values, and generates an error if a disallowed value is - specified. - - While dataSource only allows local objects, dataSourceRef allows objects - in any namespaces. - (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - - :schema: io.k8s.api.core.v1.PersistentVolumeClaimSpec#dataSourceRef - ''' - result = self._values.get("data_source_ref") - return typing.cast(typing.Optional["TypedObjectReference"], result) - - @builtins.property - def resources(self) -> typing.Optional["ResourceRequirements"]: - '''resources represents the minimum resources the volume should have. - - If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements that are lower than previous value but must still be higher than capacity recorded in the status field of the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources - - :schema: io.k8s.api.core.v1.PersistentVolumeClaimSpec#resources - ''' - result = self._values.get("resources") - return typing.cast(typing.Optional["ResourceRequirements"], result) - - @builtins.property - def selector(self) -> typing.Optional[LabelSelector]: - '''selector is a label query over volumes to consider for binding. - - :schema: io.k8s.api.core.v1.PersistentVolumeClaimSpec#selector - ''' - result = self._values.get("selector") - return typing.cast(typing.Optional[LabelSelector], result) - - @builtins.property - def storage_class_name(self) -> typing.Optional[builtins.str]: - '''storageClassName is the name of the StorageClass required by the claim. - - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 - - :schema: io.k8s.api.core.v1.PersistentVolumeClaimSpec#storageClassName - ''' - result = self._values.get("storage_class_name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def volume_mode(self) -> typing.Optional[builtins.str]: - '''volumeMode defines what type of volume is required by the claim. - - Value of Filesystem is implied when not included in claim spec. - - :schema: io.k8s.api.core.v1.PersistentVolumeClaimSpec#volumeMode - ''' - result = self._values.get("volume_mode") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def volume_name(self) -> typing.Optional[builtins.str]: - '''volumeName is the binding reference to the PersistentVolume backing this claim. - - :schema: io.k8s.api.core.v1.PersistentVolumeClaimSpec#volumeName - ''' - result = self._values.get("volume_name") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "PersistentVolumeClaimSpec(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.PersistentVolumeClaimTemplate", - jsii_struct_bases=[], - name_mapping={"spec": "spec", "metadata": "metadata"}, -) -class PersistentVolumeClaimTemplate: - def __init__( - self, - *, - spec: typing.Union[PersistentVolumeClaimSpec, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''PersistentVolumeClaimTemplate is used to produce PersistentVolumeClaim objects as part of an EphemeralVolumeSource. - - :param spec: The specification for the PersistentVolumeClaim. The entire content is copied unchanged into the PVC that gets created from this template. The same fields as in a PersistentVolumeClaim are also valid here. - :param metadata: May contain labels and annotations that will be copied into the PVC when creating it. No other fields are allowed and will be rejected during validation. - - :schema: io.k8s.api.core.v1.PersistentVolumeClaimTemplate - ''' - if isinstance(spec, dict): - spec = PersistentVolumeClaimSpec(**spec) - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__cee40a2a8084d3e6408f7a24fa29121063e73cd7d587715d3996c04e0be4bd5e) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "spec": spec, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def spec(self) -> PersistentVolumeClaimSpec: - '''The specification for the PersistentVolumeClaim. - - The entire content is copied unchanged into the PVC that gets created from this template. The same fields as in a PersistentVolumeClaim are also valid here. - - :schema: io.k8s.api.core.v1.PersistentVolumeClaimTemplate#spec - ''' - result = self._values.get("spec") - assert result is not None, "Required property 'spec' is missing" - return typing.cast(PersistentVolumeClaimSpec, result) - - @builtins.property - def metadata(self) -> typing.Optional[ObjectMeta]: - '''May contain labels and annotations that will be copied into the PVC when creating it. - - No other fields are allowed and will be rejected during validation. - - :schema: io.k8s.api.core.v1.PersistentVolumeClaimTemplate#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional[ObjectMeta], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "PersistentVolumeClaimTemplate(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.PersistentVolumeClaimVolumeSource", - jsii_struct_bases=[], - name_mapping={"claim_name": "claimName", "read_only": "readOnly"}, -) -class PersistentVolumeClaimVolumeSource: - def __init__( - self, - *, - claim_name: builtins.str, - read_only: typing.Optional[builtins.bool] = None, - ) -> None: - '''PersistentVolumeClaimVolumeSource references the user's PVC in the same namespace. - - This volume finds the bound PV and mounts that volume for the pod. A PersistentVolumeClaimVolumeSource is, essentially, a wrapper around another type of volume that is owned by someone else (the system). - - :param claim_name: claimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - :param read_only: readOnly Will force the ReadOnly setting in VolumeMounts. Default false. - - :schema: io.k8s.api.core.v1.PersistentVolumeClaimVolumeSource - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__077a0f4dddf176bb8ddbe6260969da6b9456d4aae46a38dd256c0a2204c8ee7b) - check_type(argname="argument claim_name", value=claim_name, expected_type=type_hints["claim_name"]) - check_type(argname="argument read_only", value=read_only, expected_type=type_hints["read_only"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "claim_name": claim_name, - } - if read_only is not None: - self._values["read_only"] = read_only - - @builtins.property - def claim_name(self) -> builtins.str: - '''claimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume. - - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - - :schema: io.k8s.api.core.v1.PersistentVolumeClaimVolumeSource#claimName - ''' - result = self._values.get("claim_name") - assert result is not None, "Required property 'claim_name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def read_only(self) -> typing.Optional[builtins.bool]: - '''readOnly Will force the ReadOnly setting in VolumeMounts. - - Default false. - - :schema: io.k8s.api.core.v1.PersistentVolumeClaimVolumeSource#readOnly - ''' - result = self._values.get("read_only") - return typing.cast(typing.Optional[builtins.bool], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "PersistentVolumeClaimVolumeSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.PersistentVolumeSpec", - jsii_struct_bases=[], - name_mapping={ - "access_modes": "accessModes", - "aws_elastic_block_store": "awsElasticBlockStore", - "azure_disk": "azureDisk", - "azure_file": "azureFile", - "capacity": "capacity", - "cephfs": "cephfs", - "cinder": "cinder", - "claim_ref": "claimRef", - "csi": "csi", - "fc": "fc", - "flex_volume": "flexVolume", - "flocker": "flocker", - "gce_persistent_disk": "gcePersistentDisk", - "glusterfs": "glusterfs", - "host_path": "hostPath", - "iscsi": "iscsi", - "local": "local", - "mount_options": "mountOptions", - "nfs": "nfs", - "node_affinity": "nodeAffinity", - "persistent_volume_reclaim_policy": "persistentVolumeReclaimPolicy", - "photon_persistent_disk": "photonPersistentDisk", - "portworx_volume": "portworxVolume", - "quobyte": "quobyte", - "rbd": "rbd", - "scale_io": "scaleIo", - "storage_class_name": "storageClassName", - "storageos": "storageos", - "volume_mode": "volumeMode", - "vsphere_volume": "vsphereVolume", - }, -) -class PersistentVolumeSpec: - def __init__( - self, - *, - access_modes: typing.Optional[typing.Sequence[builtins.str]] = None, - aws_elastic_block_store: typing.Optional[typing.Union[AwsElasticBlockStoreVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - azure_disk: typing.Optional[typing.Union[AzureDiskVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - azure_file: typing.Optional[typing.Union[AzureFilePersistentVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - capacity: typing.Optional[typing.Mapping[builtins.str, "Quantity"]] = None, - cephfs: typing.Optional[typing.Union[CephFsPersistentVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - cinder: typing.Optional[typing.Union[CinderPersistentVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - claim_ref: typing.Optional[typing.Union[ObjectReference, typing.Dict[builtins.str, typing.Any]]] = None, - csi: typing.Optional[typing.Union[CsiPersistentVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - fc: typing.Optional[typing.Union[FcVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - flex_volume: typing.Optional[typing.Union[FlexPersistentVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - flocker: typing.Optional[typing.Union[FlockerVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - gce_persistent_disk: typing.Optional[typing.Union[GcePersistentDiskVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - glusterfs: typing.Optional[typing.Union[GlusterfsPersistentVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - host_path: typing.Optional[typing.Union[HostPathVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - iscsi: typing.Optional[typing.Union[IscsiPersistentVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - local: typing.Optional[typing.Union[LocalVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - mount_options: typing.Optional[typing.Sequence[builtins.str]] = None, - nfs: typing.Optional[typing.Union[NfsVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - node_affinity: typing.Optional[typing.Union["VolumeNodeAffinity", typing.Dict[builtins.str, typing.Any]]] = None, - persistent_volume_reclaim_policy: typing.Optional[builtins.str] = None, - photon_persistent_disk: typing.Optional[typing.Union["PhotonPersistentDiskVolumeSource", typing.Dict[builtins.str, typing.Any]]] = None, - portworx_volume: typing.Optional[typing.Union["PortworxVolumeSource", typing.Dict[builtins.str, typing.Any]]] = None, - quobyte: typing.Optional[typing.Union["QuobyteVolumeSource", typing.Dict[builtins.str, typing.Any]]] = None, - rbd: typing.Optional[typing.Union["RbdPersistentVolumeSource", typing.Dict[builtins.str, typing.Any]]] = None, - scale_io: typing.Optional[typing.Union["ScaleIoPersistentVolumeSource", typing.Dict[builtins.str, typing.Any]]] = None, - storage_class_name: typing.Optional[builtins.str] = None, - storageos: typing.Optional[typing.Union["StorageOsPersistentVolumeSource", typing.Dict[builtins.str, typing.Any]]] = None, - volume_mode: typing.Optional[builtins.str] = None, - vsphere_volume: typing.Optional[typing.Union["VsphereVirtualDiskVolumeSource", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''PersistentVolumeSpec is the specification of a persistent volume. - - :param access_modes: accessModes contains all ways the volume can be mounted. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes - :param aws_elastic_block_store: awsElasticBlockStore represents an AWS Disk resource that is attached to a kubelet's host machine and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - :param azure_disk: azureDisk represents an Azure Data Disk mount on the host and bind mount to the pod. - :param azure_file: azureFile represents an Azure File Service mount on the host and bind mount to the pod. - :param capacity: capacity is the description of the persistent volume's resources and capacity. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#capacity - :param cephfs: cephFS represents a Ceph FS mount on the host that shares a pod's lifetime. - :param cinder: cinder represents a cinder volume attached and mounted on kubelets host machine. More info: https://examples.k8s.io/mysql-cinder-pd/README.md - :param claim_ref: claimRef is part of a bi-directional binding between PersistentVolume and PersistentVolumeClaim. Expected to be non-nil when bound. claim.VolumeName is the authoritative bind between PV and PVC. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#binding - :param csi: csi represents storage that is handled by an external CSI driver (Beta feature). - :param fc: fc represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod. - :param flex_volume: flexVolume represents a generic volume resource that is provisioned/attached using an exec based plugin. - :param flocker: flocker represents a Flocker volume attached to a kubelet's host machine and exposed to the pod for its usage. This depends on the Flocker control service being running - :param gce_persistent_disk: gcePersistentDisk represents a GCE Disk resource that is attached to a kubelet's host machine and then exposed to the pod. Provisioned by an admin. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - :param glusterfs: glusterfs represents a Glusterfs volume that is attached to a host and exposed to the pod. Provisioned by an admin. More info: https://examples.k8s.io/volumes/glusterfs/README.md - :param host_path: hostPath represents a directory on the host. Provisioned by a developer or tester. This is useful for single-node development and testing only! On-host storage is not supported in any way and WILL NOT WORK in a multi-node cluster. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - :param iscsi: iscsi represents an ISCSI Disk resource that is attached to a kubelet's host machine and then exposed to the pod. Provisioned by an admin. - :param local: local represents directly-attached storage with node affinity. - :param mount_options: mountOptions is the list of mount options, e.g. ["ro", "soft"]. Not validated - mount will simply fail if one is invalid. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes/#mount-options. - :param nfs: nfs represents an NFS mount on the host. Provisioned by an admin. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - :param node_affinity: nodeAffinity defines constraints that limit what nodes this volume can be accessed from. This field influences the scheduling of pods that use this volume. - :param persistent_volume_reclaim_policy: persistentVolumeReclaimPolicy defines what happens to a persistent volume when released from its claim. Valid options are Retain (default for manually created PersistentVolumes), Delete (default for dynamically provisioned PersistentVolumes), and Recycle (deprecated). Recycle must be supported by the volume plugin underlying this PersistentVolume. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#reclaiming - :param photon_persistent_disk: photonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine. - :param portworx_volume: portworxVolume represents a portworx volume attached and mounted on kubelets host machine. - :param quobyte: quobyte represents a Quobyte mount on the host that shares a pod's lifetime. - :param rbd: rbd represents a Rados Block Device mount on the host that shares a pod's lifetime. More info: https://examples.k8s.io/volumes/rbd/README.md - :param scale_io: scaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes. - :param storage_class_name: storageClassName is the name of StorageClass to which this persistent volume belongs. Empty value means that this volume does not belong to any StorageClass. - :param storageos: storageOS represents a StorageOS volume that is attached to the kubelet's host machine and mounted into the pod More info: https://examples.k8s.io/volumes/storageos/README.md. - :param volume_mode: volumeMode defines if a volume is intended to be used with a formatted filesystem or to remain in raw block state. Value of Filesystem is implied when not included in spec. - :param vsphere_volume: vsphereVolume represents a vSphere volume attached and mounted on kubelets host machine. - - :schema: io.k8s.api.core.v1.PersistentVolumeSpec - ''' - if isinstance(aws_elastic_block_store, dict): - aws_elastic_block_store = AwsElasticBlockStoreVolumeSource(**aws_elastic_block_store) - if isinstance(azure_disk, dict): - azure_disk = AzureDiskVolumeSource(**azure_disk) - if isinstance(azure_file, dict): - azure_file = AzureFilePersistentVolumeSource(**azure_file) - if isinstance(cephfs, dict): - cephfs = CephFsPersistentVolumeSource(**cephfs) - if isinstance(cinder, dict): - cinder = CinderPersistentVolumeSource(**cinder) - if isinstance(claim_ref, dict): - claim_ref = ObjectReference(**claim_ref) - if isinstance(csi, dict): - csi = CsiPersistentVolumeSource(**csi) - if isinstance(fc, dict): - fc = FcVolumeSource(**fc) - if isinstance(flex_volume, dict): - flex_volume = FlexPersistentVolumeSource(**flex_volume) - if isinstance(flocker, dict): - flocker = FlockerVolumeSource(**flocker) - if isinstance(gce_persistent_disk, dict): - gce_persistent_disk = GcePersistentDiskVolumeSource(**gce_persistent_disk) - if isinstance(glusterfs, dict): - glusterfs = GlusterfsPersistentVolumeSource(**glusterfs) - if isinstance(host_path, dict): - host_path = HostPathVolumeSource(**host_path) - if isinstance(iscsi, dict): - iscsi = IscsiPersistentVolumeSource(**iscsi) - if isinstance(local, dict): - local = LocalVolumeSource(**local) - if isinstance(nfs, dict): - nfs = NfsVolumeSource(**nfs) - if isinstance(node_affinity, dict): - node_affinity = VolumeNodeAffinity(**node_affinity) - if isinstance(photon_persistent_disk, dict): - photon_persistent_disk = PhotonPersistentDiskVolumeSource(**photon_persistent_disk) - if isinstance(portworx_volume, dict): - portworx_volume = PortworxVolumeSource(**portworx_volume) - if isinstance(quobyte, dict): - quobyte = QuobyteVolumeSource(**quobyte) - if isinstance(rbd, dict): - rbd = RbdPersistentVolumeSource(**rbd) - if isinstance(scale_io, dict): - scale_io = ScaleIoPersistentVolumeSource(**scale_io) - if isinstance(storageos, dict): - storageos = StorageOsPersistentVolumeSource(**storageos) - if isinstance(vsphere_volume, dict): - vsphere_volume = VsphereVirtualDiskVolumeSource(**vsphere_volume) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__35aff97a067cf96c268b843a969ca0b9162e0690f21670fdecba69ea27a470fb) - check_type(argname="argument access_modes", value=access_modes, expected_type=type_hints["access_modes"]) - check_type(argname="argument aws_elastic_block_store", value=aws_elastic_block_store, expected_type=type_hints["aws_elastic_block_store"]) - check_type(argname="argument azure_disk", value=azure_disk, expected_type=type_hints["azure_disk"]) - check_type(argname="argument azure_file", value=azure_file, expected_type=type_hints["azure_file"]) - check_type(argname="argument capacity", value=capacity, expected_type=type_hints["capacity"]) - check_type(argname="argument cephfs", value=cephfs, expected_type=type_hints["cephfs"]) - check_type(argname="argument cinder", value=cinder, expected_type=type_hints["cinder"]) - check_type(argname="argument claim_ref", value=claim_ref, expected_type=type_hints["claim_ref"]) - check_type(argname="argument csi", value=csi, expected_type=type_hints["csi"]) - check_type(argname="argument fc", value=fc, expected_type=type_hints["fc"]) - check_type(argname="argument flex_volume", value=flex_volume, expected_type=type_hints["flex_volume"]) - check_type(argname="argument flocker", value=flocker, expected_type=type_hints["flocker"]) - check_type(argname="argument gce_persistent_disk", value=gce_persistent_disk, expected_type=type_hints["gce_persistent_disk"]) - check_type(argname="argument glusterfs", value=glusterfs, expected_type=type_hints["glusterfs"]) - check_type(argname="argument host_path", value=host_path, expected_type=type_hints["host_path"]) - check_type(argname="argument iscsi", value=iscsi, expected_type=type_hints["iscsi"]) - check_type(argname="argument local", value=local, expected_type=type_hints["local"]) - check_type(argname="argument mount_options", value=mount_options, expected_type=type_hints["mount_options"]) - check_type(argname="argument nfs", value=nfs, expected_type=type_hints["nfs"]) - check_type(argname="argument node_affinity", value=node_affinity, expected_type=type_hints["node_affinity"]) - check_type(argname="argument persistent_volume_reclaim_policy", value=persistent_volume_reclaim_policy, expected_type=type_hints["persistent_volume_reclaim_policy"]) - check_type(argname="argument photon_persistent_disk", value=photon_persistent_disk, expected_type=type_hints["photon_persistent_disk"]) - check_type(argname="argument portworx_volume", value=portworx_volume, expected_type=type_hints["portworx_volume"]) - check_type(argname="argument quobyte", value=quobyte, expected_type=type_hints["quobyte"]) - check_type(argname="argument rbd", value=rbd, expected_type=type_hints["rbd"]) - check_type(argname="argument scale_io", value=scale_io, expected_type=type_hints["scale_io"]) - check_type(argname="argument storage_class_name", value=storage_class_name, expected_type=type_hints["storage_class_name"]) - check_type(argname="argument storageos", value=storageos, expected_type=type_hints["storageos"]) - check_type(argname="argument volume_mode", value=volume_mode, expected_type=type_hints["volume_mode"]) - check_type(argname="argument vsphere_volume", value=vsphere_volume, expected_type=type_hints["vsphere_volume"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if access_modes is not None: - self._values["access_modes"] = access_modes - if aws_elastic_block_store is not None: - self._values["aws_elastic_block_store"] = aws_elastic_block_store - if azure_disk is not None: - self._values["azure_disk"] = azure_disk - if azure_file is not None: - self._values["azure_file"] = azure_file - if capacity is not None: - self._values["capacity"] = capacity - if cephfs is not None: - self._values["cephfs"] = cephfs - if cinder is not None: - self._values["cinder"] = cinder - if claim_ref is not None: - self._values["claim_ref"] = claim_ref - if csi is not None: - self._values["csi"] = csi - if fc is not None: - self._values["fc"] = fc - if flex_volume is not None: - self._values["flex_volume"] = flex_volume - if flocker is not None: - self._values["flocker"] = flocker - if gce_persistent_disk is not None: - self._values["gce_persistent_disk"] = gce_persistent_disk - if glusterfs is not None: - self._values["glusterfs"] = glusterfs - if host_path is not None: - self._values["host_path"] = host_path - if iscsi is not None: - self._values["iscsi"] = iscsi - if local is not None: - self._values["local"] = local - if mount_options is not None: - self._values["mount_options"] = mount_options - if nfs is not None: - self._values["nfs"] = nfs - if node_affinity is not None: - self._values["node_affinity"] = node_affinity - if persistent_volume_reclaim_policy is not None: - self._values["persistent_volume_reclaim_policy"] = persistent_volume_reclaim_policy - if photon_persistent_disk is not None: - self._values["photon_persistent_disk"] = photon_persistent_disk - if portworx_volume is not None: - self._values["portworx_volume"] = portworx_volume - if quobyte is not None: - self._values["quobyte"] = quobyte - if rbd is not None: - self._values["rbd"] = rbd - if scale_io is not None: - self._values["scale_io"] = scale_io - if storage_class_name is not None: - self._values["storage_class_name"] = storage_class_name - if storageos is not None: - self._values["storageos"] = storageos - if volume_mode is not None: - self._values["volume_mode"] = volume_mode - if vsphere_volume is not None: - self._values["vsphere_volume"] = vsphere_volume - - @builtins.property - def access_modes(self) -> typing.Optional[typing.List[builtins.str]]: - '''accessModes contains all ways the volume can be mounted. - - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes - - :schema: io.k8s.api.core.v1.PersistentVolumeSpec#accessModes - ''' - result = self._values.get("access_modes") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def aws_elastic_block_store( - self, - ) -> typing.Optional[AwsElasticBlockStoreVolumeSource]: - '''awsElasticBlockStore represents an AWS Disk resource that is attached to a kubelet's host machine and then exposed to the pod. - - More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - - :schema: io.k8s.api.core.v1.PersistentVolumeSpec#awsElasticBlockStore - ''' - result = self._values.get("aws_elastic_block_store") - return typing.cast(typing.Optional[AwsElasticBlockStoreVolumeSource], result) - - @builtins.property - def azure_disk(self) -> typing.Optional[AzureDiskVolumeSource]: - '''azureDisk represents an Azure Data Disk mount on the host and bind mount to the pod. - - :schema: io.k8s.api.core.v1.PersistentVolumeSpec#azureDisk - ''' - result = self._values.get("azure_disk") - return typing.cast(typing.Optional[AzureDiskVolumeSource], result) - - @builtins.property - def azure_file(self) -> typing.Optional[AzureFilePersistentVolumeSource]: - '''azureFile represents an Azure File Service mount on the host and bind mount to the pod. - - :schema: io.k8s.api.core.v1.PersistentVolumeSpec#azureFile - ''' - result = self._values.get("azure_file") - return typing.cast(typing.Optional[AzureFilePersistentVolumeSource], result) - - @builtins.property - def capacity(self) -> typing.Optional[typing.Mapping[builtins.str, "Quantity"]]: - '''capacity is the description of the persistent volume's resources and capacity. - - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#capacity - - :schema: io.k8s.api.core.v1.PersistentVolumeSpec#capacity - ''' - result = self._values.get("capacity") - return typing.cast(typing.Optional[typing.Mapping[builtins.str, "Quantity"]], result) - - @builtins.property - def cephfs(self) -> typing.Optional[CephFsPersistentVolumeSource]: - '''cephFS represents a Ceph FS mount on the host that shares a pod's lifetime. - - :schema: io.k8s.api.core.v1.PersistentVolumeSpec#cephfs - ''' - result = self._values.get("cephfs") - return typing.cast(typing.Optional[CephFsPersistentVolumeSource], result) - - @builtins.property - def cinder(self) -> typing.Optional[CinderPersistentVolumeSource]: - '''cinder represents a cinder volume attached and mounted on kubelets host machine. - - More info: https://examples.k8s.io/mysql-cinder-pd/README.md - - :schema: io.k8s.api.core.v1.PersistentVolumeSpec#cinder - ''' - result = self._values.get("cinder") - return typing.cast(typing.Optional[CinderPersistentVolumeSource], result) - - @builtins.property - def claim_ref(self) -> typing.Optional[ObjectReference]: - '''claimRef is part of a bi-directional binding between PersistentVolume and PersistentVolumeClaim. - - Expected to be non-nil when bound. claim.VolumeName is the authoritative bind between PV and PVC. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#binding - - :schema: io.k8s.api.core.v1.PersistentVolumeSpec#claimRef - ''' - result = self._values.get("claim_ref") - return typing.cast(typing.Optional[ObjectReference], result) - - @builtins.property - def csi(self) -> typing.Optional[CsiPersistentVolumeSource]: - '''csi represents storage that is handled by an external CSI driver (Beta feature). - - :schema: io.k8s.api.core.v1.PersistentVolumeSpec#csi - ''' - result = self._values.get("csi") - return typing.cast(typing.Optional[CsiPersistentVolumeSource], result) - - @builtins.property - def fc(self) -> typing.Optional[FcVolumeSource]: - '''fc represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod. - - :schema: io.k8s.api.core.v1.PersistentVolumeSpec#fc - ''' - result = self._values.get("fc") - return typing.cast(typing.Optional[FcVolumeSource], result) - - @builtins.property - def flex_volume(self) -> typing.Optional[FlexPersistentVolumeSource]: - '''flexVolume represents a generic volume resource that is provisioned/attached using an exec based plugin. - - :schema: io.k8s.api.core.v1.PersistentVolumeSpec#flexVolume - ''' - result = self._values.get("flex_volume") - return typing.cast(typing.Optional[FlexPersistentVolumeSource], result) - - @builtins.property - def flocker(self) -> typing.Optional[FlockerVolumeSource]: - '''flocker represents a Flocker volume attached to a kubelet's host machine and exposed to the pod for its usage. - - This depends on the Flocker control service being running - - :schema: io.k8s.api.core.v1.PersistentVolumeSpec#flocker - ''' - result = self._values.get("flocker") - return typing.cast(typing.Optional[FlockerVolumeSource], result) - - @builtins.property - def gce_persistent_disk(self) -> typing.Optional[GcePersistentDiskVolumeSource]: - '''gcePersistentDisk represents a GCE Disk resource that is attached to a kubelet's host machine and then exposed to the pod. - - Provisioned by an admin. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - - :schema: io.k8s.api.core.v1.PersistentVolumeSpec#gcePersistentDisk - ''' - result = self._values.get("gce_persistent_disk") - return typing.cast(typing.Optional[GcePersistentDiskVolumeSource], result) - - @builtins.property - def glusterfs(self) -> typing.Optional[GlusterfsPersistentVolumeSource]: - '''glusterfs represents a Glusterfs volume that is attached to a host and exposed to the pod. - - Provisioned by an admin. More info: https://examples.k8s.io/volumes/glusterfs/README.md - - :schema: io.k8s.api.core.v1.PersistentVolumeSpec#glusterfs - ''' - result = self._values.get("glusterfs") - return typing.cast(typing.Optional[GlusterfsPersistentVolumeSource], result) - - @builtins.property - def host_path(self) -> typing.Optional[HostPathVolumeSource]: - '''hostPath represents a directory on the host. - - Provisioned by a developer or tester. This is useful for single-node development and testing only! On-host storage is not supported in any way and WILL NOT WORK in a multi-node cluster. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - - :schema: io.k8s.api.core.v1.PersistentVolumeSpec#hostPath - ''' - result = self._values.get("host_path") - return typing.cast(typing.Optional[HostPathVolumeSource], result) - - @builtins.property - def iscsi(self) -> typing.Optional[IscsiPersistentVolumeSource]: - '''iscsi represents an ISCSI Disk resource that is attached to a kubelet's host machine and then exposed to the pod. - - Provisioned by an admin. - - :schema: io.k8s.api.core.v1.PersistentVolumeSpec#iscsi - ''' - result = self._values.get("iscsi") - return typing.cast(typing.Optional[IscsiPersistentVolumeSource], result) - - @builtins.property - def local(self) -> typing.Optional[LocalVolumeSource]: - '''local represents directly-attached storage with node affinity. - - :schema: io.k8s.api.core.v1.PersistentVolumeSpec#local - ''' - result = self._values.get("local") - return typing.cast(typing.Optional[LocalVolumeSource], result) - - @builtins.property - def mount_options(self) -> typing.Optional[typing.List[builtins.str]]: - '''mountOptions is the list of mount options, e.g. ["ro", "soft"]. Not validated - mount will simply fail if one is invalid. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes/#mount-options. - - :schema: io.k8s.api.core.v1.PersistentVolumeSpec#mountOptions - ''' - result = self._values.get("mount_options") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def nfs(self) -> typing.Optional[NfsVolumeSource]: - '''nfs represents an NFS mount on the host. - - Provisioned by an admin. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - - :schema: io.k8s.api.core.v1.PersistentVolumeSpec#nfs - ''' - result = self._values.get("nfs") - return typing.cast(typing.Optional[NfsVolumeSource], result) - - @builtins.property - def node_affinity(self) -> typing.Optional["VolumeNodeAffinity"]: - '''nodeAffinity defines constraints that limit what nodes this volume can be accessed from. - - This field influences the scheduling of pods that use this volume. - - :schema: io.k8s.api.core.v1.PersistentVolumeSpec#nodeAffinity - ''' - result = self._values.get("node_affinity") - return typing.cast(typing.Optional["VolumeNodeAffinity"], result) - - @builtins.property - def persistent_volume_reclaim_policy(self) -> typing.Optional[builtins.str]: - '''persistentVolumeReclaimPolicy defines what happens to a persistent volume when released from its claim. - - Valid options are Retain (default for manually created PersistentVolumes), Delete (default for dynamically provisioned PersistentVolumes), and Recycle (deprecated). Recycle must be supported by the volume plugin underlying this PersistentVolume. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#reclaiming - - :schema: io.k8s.api.core.v1.PersistentVolumeSpec#persistentVolumeReclaimPolicy - ''' - result = self._values.get("persistent_volume_reclaim_policy") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def photon_persistent_disk( - self, - ) -> typing.Optional["PhotonPersistentDiskVolumeSource"]: - '''photonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine. - - :schema: io.k8s.api.core.v1.PersistentVolumeSpec#photonPersistentDisk - ''' - result = self._values.get("photon_persistent_disk") - return typing.cast(typing.Optional["PhotonPersistentDiskVolumeSource"], result) - - @builtins.property - def portworx_volume(self) -> typing.Optional["PortworxVolumeSource"]: - '''portworxVolume represents a portworx volume attached and mounted on kubelets host machine. - - :schema: io.k8s.api.core.v1.PersistentVolumeSpec#portworxVolume - ''' - result = self._values.get("portworx_volume") - return typing.cast(typing.Optional["PortworxVolumeSource"], result) - - @builtins.property - def quobyte(self) -> typing.Optional["QuobyteVolumeSource"]: - '''quobyte represents a Quobyte mount on the host that shares a pod's lifetime. - - :schema: io.k8s.api.core.v1.PersistentVolumeSpec#quobyte - ''' - result = self._values.get("quobyte") - return typing.cast(typing.Optional["QuobyteVolumeSource"], result) - - @builtins.property - def rbd(self) -> typing.Optional["RbdPersistentVolumeSource"]: - '''rbd represents a Rados Block Device mount on the host that shares a pod's lifetime. - - More info: https://examples.k8s.io/volumes/rbd/README.md - - :schema: io.k8s.api.core.v1.PersistentVolumeSpec#rbd - ''' - result = self._values.get("rbd") - return typing.cast(typing.Optional["RbdPersistentVolumeSource"], result) - - @builtins.property - def scale_io(self) -> typing.Optional["ScaleIoPersistentVolumeSource"]: - '''scaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes. - - :schema: io.k8s.api.core.v1.PersistentVolumeSpec#scaleIO - ''' - result = self._values.get("scale_io") - return typing.cast(typing.Optional["ScaleIoPersistentVolumeSource"], result) - - @builtins.property - def storage_class_name(self) -> typing.Optional[builtins.str]: - '''storageClassName is the name of StorageClass to which this persistent volume belongs. - - Empty value means that this volume does not belong to any StorageClass. - - :schema: io.k8s.api.core.v1.PersistentVolumeSpec#storageClassName - ''' - result = self._values.get("storage_class_name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def storageos(self) -> typing.Optional["StorageOsPersistentVolumeSource"]: - '''storageOS represents a StorageOS volume that is attached to the kubelet's host machine and mounted into the pod More info: https://examples.k8s.io/volumes/storageos/README.md. - - :schema: io.k8s.api.core.v1.PersistentVolumeSpec#storageos - ''' - result = self._values.get("storageos") - return typing.cast(typing.Optional["StorageOsPersistentVolumeSource"], result) - - @builtins.property - def volume_mode(self) -> typing.Optional[builtins.str]: - '''volumeMode defines if a volume is intended to be used with a formatted filesystem or to remain in raw block state. - - Value of Filesystem is implied when not included in spec. - - :schema: io.k8s.api.core.v1.PersistentVolumeSpec#volumeMode - ''' - result = self._values.get("volume_mode") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def vsphere_volume(self) -> typing.Optional["VsphereVirtualDiskVolumeSource"]: - '''vsphereVolume represents a vSphere volume attached and mounted on kubelets host machine. - - :schema: io.k8s.api.core.v1.PersistentVolumeSpec#vsphereVolume - ''' - result = self._values.get("vsphere_volume") - return typing.cast(typing.Optional["VsphereVirtualDiskVolumeSource"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "PersistentVolumeSpec(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.PhotonPersistentDiskVolumeSource", - jsii_struct_bases=[], - name_mapping={"pd_id": "pdId", "fs_type": "fsType"}, -) -class PhotonPersistentDiskVolumeSource: - def __init__( - self, - *, - pd_id: builtins.str, - fs_type: typing.Optional[builtins.str] = None, - ) -> None: - '''Represents a Photon Controller persistent disk resource. - - :param pd_id: pdID is the ID that identifies Photon Controller persistent disk. - :param fs_type: fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - - :schema: io.k8s.api.core.v1.PhotonPersistentDiskVolumeSource - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__7b0be95f372a9aa5db6fdac38282cc046204e7f43c46d9459c585522c86b2f39) - check_type(argname="argument pd_id", value=pd_id, expected_type=type_hints["pd_id"]) - check_type(argname="argument fs_type", value=fs_type, expected_type=type_hints["fs_type"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "pd_id": pd_id, - } - if fs_type is not None: - self._values["fs_type"] = fs_type - - @builtins.property - def pd_id(self) -> builtins.str: - '''pdID is the ID that identifies Photon Controller persistent disk. - - :schema: io.k8s.api.core.v1.PhotonPersistentDiskVolumeSource#pdID - ''' - result = self._values.get("pd_id") - assert result is not None, "Required property 'pd_id' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def fs_type(self) -> typing.Optional[builtins.str]: - '''fsType is the filesystem type to mount. - - Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - - :schema: io.k8s.api.core.v1.PhotonPersistentDiskVolumeSource#fsType - ''' - result = self._values.get("fs_type") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "PhotonPersistentDiskVolumeSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.PodAffinity", - jsii_struct_bases=[], - name_mapping={ - "preferred_during_scheduling_ignored_during_execution": "preferredDuringSchedulingIgnoredDuringExecution", - "required_during_scheduling_ignored_during_execution": "requiredDuringSchedulingIgnoredDuringExecution", - }, -) -class PodAffinity: - def __init__( - self, - *, - preferred_during_scheduling_ignored_during_execution: typing.Optional[typing.Sequence[typing.Union["WeightedPodAffinityTerm", typing.Dict[builtins.str, typing.Any]]]] = None, - required_during_scheduling_ignored_during_execution: typing.Optional[typing.Sequence[typing.Union["PodAffinityTerm", typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''Pod affinity is a group of inter pod affinity scheduling rules. - - :param preferred_during_scheduling_ignored_during_execution: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. - :param required_during_scheduling_ignored_during_execution: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. - - :schema: io.k8s.api.core.v1.PodAffinity - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__0830de33ed62413d27b090c2218c86cadcbd37738b116d98ce30ae82e8676733) - check_type(argname="argument preferred_during_scheduling_ignored_during_execution", value=preferred_during_scheduling_ignored_during_execution, expected_type=type_hints["preferred_during_scheduling_ignored_during_execution"]) - check_type(argname="argument required_during_scheduling_ignored_during_execution", value=required_during_scheduling_ignored_during_execution, expected_type=type_hints["required_during_scheduling_ignored_during_execution"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if preferred_during_scheduling_ignored_during_execution is not None: - self._values["preferred_during_scheduling_ignored_during_execution"] = preferred_during_scheduling_ignored_during_execution - if required_during_scheduling_ignored_during_execution is not None: - self._values["required_during_scheduling_ignored_during_execution"] = required_during_scheduling_ignored_during_execution - - @builtins.property - def preferred_during_scheduling_ignored_during_execution( - self, - ) -> typing.Optional[typing.List["WeightedPodAffinityTerm"]]: - '''The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. - - The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. - - :schema: io.k8s.api.core.v1.PodAffinity#preferredDuringSchedulingIgnoredDuringExecution - ''' - result = self._values.get("preferred_during_scheduling_ignored_during_execution") - return typing.cast(typing.Optional[typing.List["WeightedPodAffinityTerm"]], result) - - @builtins.property - def required_during_scheduling_ignored_during_execution( - self, - ) -> typing.Optional[typing.List["PodAffinityTerm"]]: - '''If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. - - If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. - - :schema: io.k8s.api.core.v1.PodAffinity#requiredDuringSchedulingIgnoredDuringExecution - ''' - result = self._values.get("required_during_scheduling_ignored_during_execution") - return typing.cast(typing.Optional[typing.List["PodAffinityTerm"]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "PodAffinity(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.PodAffinityTerm", - jsii_struct_bases=[], - name_mapping={ - "topology_key": "topologyKey", - "label_selector": "labelSelector", - "namespaces": "namespaces", - "namespace_selector": "namespaceSelector", - }, -) -class PodAffinityTerm: - def __init__( - self, - *, - topology_key: builtins.str, - label_selector: typing.Optional[typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]]] = None, - namespaces: typing.Optional[typing.Sequence[builtins.str]] = None, - namespace_selector: typing.Optional[typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running. - - :param topology_key: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. - :param label_selector: A label query over a set of resources, in this case pods. - :param namespaces: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace". - :param namespace_selector: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. - - :schema: io.k8s.api.core.v1.PodAffinityTerm - ''' - if isinstance(label_selector, dict): - label_selector = LabelSelector(**label_selector) - if isinstance(namespace_selector, dict): - namespace_selector = LabelSelector(**namespace_selector) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__063b73cb46562ef4af361b17cfc211f3c56960b9052f045d67104026b7d98e93) - check_type(argname="argument topology_key", value=topology_key, expected_type=type_hints["topology_key"]) - check_type(argname="argument label_selector", value=label_selector, expected_type=type_hints["label_selector"]) - check_type(argname="argument namespaces", value=namespaces, expected_type=type_hints["namespaces"]) - check_type(argname="argument namespace_selector", value=namespace_selector, expected_type=type_hints["namespace_selector"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "topology_key": topology_key, - } - if label_selector is not None: - self._values["label_selector"] = label_selector - if namespaces is not None: - self._values["namespaces"] = namespaces - if namespace_selector is not None: - self._values["namespace_selector"] = namespace_selector - - @builtins.property - def topology_key(self) -> builtins.str: - '''This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. - - Empty topologyKey is not allowed. - - :schema: io.k8s.api.core.v1.PodAffinityTerm#topologyKey - ''' - result = self._values.get("topology_key") - assert result is not None, "Required property 'topology_key' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def label_selector(self) -> typing.Optional[LabelSelector]: - '''A label query over a set of resources, in this case pods. - - :schema: io.k8s.api.core.v1.PodAffinityTerm#labelSelector - ''' - result = self._values.get("label_selector") - return typing.cast(typing.Optional[LabelSelector], result) - - @builtins.property - def namespaces(self) -> typing.Optional[typing.List[builtins.str]]: - '''namespaces specifies a static list of namespace names that the term applies to. - - The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace". - - :schema: io.k8s.api.core.v1.PodAffinityTerm#namespaces - ''' - result = self._values.get("namespaces") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def namespace_selector(self) -> typing.Optional[LabelSelector]: - '''A label query over the set of namespaces that the term applies to. - - The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. - - :schema: io.k8s.api.core.v1.PodAffinityTerm#namespaceSelector - ''' - result = self._values.get("namespace_selector") - return typing.cast(typing.Optional[LabelSelector], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "PodAffinityTerm(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.PodAntiAffinity", - jsii_struct_bases=[], - name_mapping={ - "preferred_during_scheduling_ignored_during_execution": "preferredDuringSchedulingIgnoredDuringExecution", - "required_during_scheduling_ignored_during_execution": "requiredDuringSchedulingIgnoredDuringExecution", - }, -) -class PodAntiAffinity: - def __init__( - self, - *, - preferred_during_scheduling_ignored_during_execution: typing.Optional[typing.Sequence[typing.Union["WeightedPodAffinityTerm", typing.Dict[builtins.str, typing.Any]]]] = None, - required_during_scheduling_ignored_during_execution: typing.Optional[typing.Sequence[typing.Union[PodAffinityTerm, typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''Pod anti affinity is a group of inter pod anti affinity scheduling rules. - - :param preferred_during_scheduling_ignored_during_execution: The scheduler will prefer to schedule pods to nodes that satisfy the anti-affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling anti-affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. - :param required_during_scheduling_ignored_during_execution: If the anti-affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the anti-affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. - - :schema: io.k8s.api.core.v1.PodAntiAffinity - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__cab9a027f8884b485c148ce998a3d4c392c0b58b23786402dd0caf2c5a319034) - check_type(argname="argument preferred_during_scheduling_ignored_during_execution", value=preferred_during_scheduling_ignored_during_execution, expected_type=type_hints["preferred_during_scheduling_ignored_during_execution"]) - check_type(argname="argument required_during_scheduling_ignored_during_execution", value=required_during_scheduling_ignored_during_execution, expected_type=type_hints["required_during_scheduling_ignored_during_execution"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if preferred_during_scheduling_ignored_during_execution is not None: - self._values["preferred_during_scheduling_ignored_during_execution"] = preferred_during_scheduling_ignored_during_execution - if required_during_scheduling_ignored_during_execution is not None: - self._values["required_during_scheduling_ignored_during_execution"] = required_during_scheduling_ignored_during_execution - - @builtins.property - def preferred_during_scheduling_ignored_during_execution( - self, - ) -> typing.Optional[typing.List["WeightedPodAffinityTerm"]]: - '''The scheduler will prefer to schedule pods to nodes that satisfy the anti-affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. - - The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling anti-affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. - - :schema: io.k8s.api.core.v1.PodAntiAffinity#preferredDuringSchedulingIgnoredDuringExecution - ''' - result = self._values.get("preferred_during_scheduling_ignored_during_execution") - return typing.cast(typing.Optional[typing.List["WeightedPodAffinityTerm"]], result) - - @builtins.property - def required_during_scheduling_ignored_during_execution( - self, - ) -> typing.Optional[typing.List[PodAffinityTerm]]: - '''If the anti-affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. - - If the anti-affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. - - :schema: io.k8s.api.core.v1.PodAntiAffinity#requiredDuringSchedulingIgnoredDuringExecution - ''' - result = self._values.get("required_during_scheduling_ignored_during_execution") - return typing.cast(typing.Optional[typing.List[PodAffinityTerm]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "PodAntiAffinity(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.PodDisruptionBudgetSpec", - jsii_struct_bases=[], - name_mapping={ - "max_unavailable": "maxUnavailable", - "min_available": "minAvailable", - "selector": "selector", - "unhealthy_pod_eviction_policy": "unhealthyPodEvictionPolicy", - }, -) -class PodDisruptionBudgetSpec: - def __init__( - self, - *, - max_unavailable: typing.Optional[IntOrString] = None, - min_available: typing.Optional[IntOrString] = None, - selector: typing.Optional[typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]]] = None, - unhealthy_pod_eviction_policy: typing.Optional[builtins.str] = None, - ) -> None: - '''PodDisruptionBudgetSpec is a description of a PodDisruptionBudget. - - :param max_unavailable: An eviction is allowed if at most "maxUnavailable" pods selected by "selector" are unavailable after the eviction, i.e. even in absence of the evicted pod. For example, one can prevent all voluntary evictions by specifying 0. This is a mutually exclusive setting with "minAvailable". - :param min_available: An eviction is allowed if at least "minAvailable" pods selected by "selector" will still be available after the eviction, i.e. even in the absence of the evicted pod. So for example you can prevent all voluntary evictions by specifying "100%". - :param selector: Label query over pods whose evictions are managed by the disruption budget. A null selector will match no pods, while an empty ({}) selector will select all pods within the namespace. - :param unhealthy_pod_eviction_policy: UnhealthyPodEvictionPolicy defines the criteria for when unhealthy pods should be considered for eviction. Current implementation considers healthy pods, as pods that have status.conditions item with type="Ready",status="True". Valid policies are IfHealthyBudget and AlwaysAllow. If no policy is specified, the default behavior will be used, which corresponds to the IfHealthyBudget policy. IfHealthyBudget policy means that running pods (status.phase="Running"), but not yet healthy can be evicted only if the guarded application is not disrupted (status.currentHealthy is at least equal to status.desiredHealthy). Healthy pods will be subject to the PDB for eviction. AlwaysAllow policy means that all running pods (status.phase="Running"), but not yet healthy are considered disrupted and can be evicted regardless of whether the criteria in a PDB is met. This means perspective running pods of a disrupted application might not get a chance to become healthy. Healthy pods will be subject to the PDB for eviction. Additional policies may be added in the future. Clients making eviction decisions should disallow eviction of unhealthy pods if they encounter an unrecognized policy in this field. This field is alpha-level. The eviction API uses this field when the feature gate PDBUnhealthyPodEvictionPolicy is enabled (disabled by default). - - :schema: io.k8s.api.policy.v1.PodDisruptionBudgetSpec - ''' - if isinstance(selector, dict): - selector = LabelSelector(**selector) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__fcf659f51d3ad1ddb70e76f4550c401ae77b9bed37d6671e9b1895983dbc2bc6) - check_type(argname="argument max_unavailable", value=max_unavailable, expected_type=type_hints["max_unavailable"]) - check_type(argname="argument min_available", value=min_available, expected_type=type_hints["min_available"]) - check_type(argname="argument selector", value=selector, expected_type=type_hints["selector"]) - check_type(argname="argument unhealthy_pod_eviction_policy", value=unhealthy_pod_eviction_policy, expected_type=type_hints["unhealthy_pod_eviction_policy"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if max_unavailable is not None: - self._values["max_unavailable"] = max_unavailable - if min_available is not None: - self._values["min_available"] = min_available - if selector is not None: - self._values["selector"] = selector - if unhealthy_pod_eviction_policy is not None: - self._values["unhealthy_pod_eviction_policy"] = unhealthy_pod_eviction_policy - - @builtins.property - def max_unavailable(self) -> typing.Optional[IntOrString]: - '''An eviction is allowed if at most "maxUnavailable" pods selected by "selector" are unavailable after the eviction, i.e. even in absence of the evicted pod. For example, one can prevent all voluntary evictions by specifying 0. This is a mutually exclusive setting with "minAvailable". - - :schema: io.k8s.api.policy.v1.PodDisruptionBudgetSpec#maxUnavailable - ''' - result = self._values.get("max_unavailable") - return typing.cast(typing.Optional[IntOrString], result) - - @builtins.property - def min_available(self) -> typing.Optional[IntOrString]: - '''An eviction is allowed if at least "minAvailable" pods selected by "selector" will still be available after the eviction, i.e. even in the absence of the evicted pod. So for example you can prevent all voluntary evictions by specifying "100%". - - :schema: io.k8s.api.policy.v1.PodDisruptionBudgetSpec#minAvailable - ''' - result = self._values.get("min_available") - return typing.cast(typing.Optional[IntOrString], result) - - @builtins.property - def selector(self) -> typing.Optional[LabelSelector]: - '''Label query over pods whose evictions are managed by the disruption budget. - - A null selector will match no pods, while an empty ({}) selector will select all pods within the namespace. - - :schema: io.k8s.api.policy.v1.PodDisruptionBudgetSpec#selector - ''' - result = self._values.get("selector") - return typing.cast(typing.Optional[LabelSelector], result) - - @builtins.property - def unhealthy_pod_eviction_policy(self) -> typing.Optional[builtins.str]: - '''UnhealthyPodEvictionPolicy defines the criteria for when unhealthy pods should be considered for eviction. - - Current implementation considers healthy pods, as pods that have status.conditions item with type="Ready",status="True". - - Valid policies are IfHealthyBudget and AlwaysAllow. If no policy is specified, the default behavior will be used, which corresponds to the IfHealthyBudget policy. - - IfHealthyBudget policy means that running pods (status.phase="Running"), but not yet healthy can be evicted only if the guarded application is not disrupted (status.currentHealthy is at least equal to status.desiredHealthy). Healthy pods will be subject to the PDB for eviction. - - AlwaysAllow policy means that all running pods (status.phase="Running"), but not yet healthy are considered disrupted and can be evicted regardless of whether the criteria in a PDB is met. This means perspective running pods of a disrupted application might not get a chance to become healthy. Healthy pods will be subject to the PDB for eviction. - - Additional policies may be added in the future. Clients making eviction decisions should disallow eviction of unhealthy pods if they encounter an unrecognized policy in this field. - - This field is alpha-level. The eviction API uses this field when the feature gate PDBUnhealthyPodEvictionPolicy is enabled (disabled by default). - - :schema: io.k8s.api.policy.v1.PodDisruptionBudgetSpec#unhealthyPodEvictionPolicy - ''' - result = self._values.get("unhealthy_pod_eviction_policy") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "PodDisruptionBudgetSpec(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.PodDnsConfig", - jsii_struct_bases=[], - name_mapping={ - "nameservers": "nameservers", - "options": "options", - "searches": "searches", - }, -) -class PodDnsConfig: - def __init__( - self, - *, - nameservers: typing.Optional[typing.Sequence[builtins.str]] = None, - options: typing.Optional[typing.Sequence[typing.Union["PodDnsConfigOption", typing.Dict[builtins.str, typing.Any]]]] = None, - searches: typing.Optional[typing.Sequence[builtins.str]] = None, - ) -> None: - '''PodDNSConfig defines the DNS parameters of a pod in addition to those generated from DNSPolicy. - - :param nameservers: A list of DNS name server IP addresses. This will be appended to the base nameservers generated from DNSPolicy. Duplicated nameservers will be removed. - :param options: A list of DNS resolver options. This will be merged with the base options generated from DNSPolicy. Duplicated entries will be removed. Resolution options given in Options will override those that appear in the base DNSPolicy. - :param searches: A list of DNS search domains for host-name lookup. This will be appended to the base search paths generated from DNSPolicy. Duplicated search paths will be removed. - - :schema: io.k8s.api.core.v1.PodDNSConfig - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__8c30b93db014abaf8ed6b5187f791e1155288ba850e120d30272e029498d46a2) - check_type(argname="argument nameservers", value=nameservers, expected_type=type_hints["nameservers"]) - check_type(argname="argument options", value=options, expected_type=type_hints["options"]) - check_type(argname="argument searches", value=searches, expected_type=type_hints["searches"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if nameservers is not None: - self._values["nameservers"] = nameservers - if options is not None: - self._values["options"] = options - if searches is not None: - self._values["searches"] = searches - - @builtins.property - def nameservers(self) -> typing.Optional[typing.List[builtins.str]]: - '''A list of DNS name server IP addresses. - - This will be appended to the base nameservers generated from DNSPolicy. Duplicated nameservers will be removed. - - :schema: io.k8s.api.core.v1.PodDNSConfig#nameservers - ''' - result = self._values.get("nameservers") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def options(self) -> typing.Optional[typing.List["PodDnsConfigOption"]]: - '''A list of DNS resolver options. - - This will be merged with the base options generated from DNSPolicy. Duplicated entries will be removed. Resolution options given in Options will override those that appear in the base DNSPolicy. - - :schema: io.k8s.api.core.v1.PodDNSConfig#options - ''' - result = self._values.get("options") - return typing.cast(typing.Optional[typing.List["PodDnsConfigOption"]], result) - - @builtins.property - def searches(self) -> typing.Optional[typing.List[builtins.str]]: - '''A list of DNS search domains for host-name lookup. - - This will be appended to the base search paths generated from DNSPolicy. Duplicated search paths will be removed. - - :schema: io.k8s.api.core.v1.PodDNSConfig#searches - ''' - result = self._values.get("searches") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "PodDnsConfig(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.PodDnsConfigOption", - jsii_struct_bases=[], - name_mapping={"name": "name", "value": "value"}, -) -class PodDnsConfigOption: - def __init__( - self, - *, - name: typing.Optional[builtins.str] = None, - value: typing.Optional[builtins.str] = None, - ) -> None: - '''PodDNSConfigOption defines DNS resolver options of a pod. - - :param name: Required. - :param value: - - :schema: io.k8s.api.core.v1.PodDNSConfigOption - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__815fe5aad5ae05289693b717c8d0482e9f0ca6d59c31bed07e76d275fb763759) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument value", value=value, expected_type=type_hints["value"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if name is not None: - self._values["name"] = name - if value is not None: - self._values["value"] = value - - @builtins.property - def name(self) -> typing.Optional[builtins.str]: - '''Required. - - :schema: io.k8s.api.core.v1.PodDNSConfigOption#name - ''' - result = self._values.get("name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def value(self) -> typing.Optional[builtins.str]: - ''' - :schema: io.k8s.api.core.v1.PodDNSConfigOption#value - ''' - result = self._values.get("value") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "PodDnsConfigOption(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.PodFailurePolicy", - jsii_struct_bases=[], - name_mapping={"rules": "rules"}, -) -class PodFailurePolicy: - def __init__( - self, - *, - rules: typing.Sequence[typing.Union["PodFailurePolicyRule", typing.Dict[builtins.str, typing.Any]]], - ) -> None: - '''PodFailurePolicy describes how failed pods influence the backoffLimit. - - :param rules: A list of pod failure policy rules. The rules are evaluated in order. Once a rule matches a Pod failure, the remaining of the rules are ignored. When no rule matches the Pod failure, the default handling applies - the counter of pod failures is incremented and it is checked against the backoffLimit. At most 20 elements are allowed. - - :schema: io.k8s.api.batch.v1.PodFailurePolicy - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__7d648d0923526488e7170f574c8a29f5a5121299dee93365c01d1ca343751c04) - check_type(argname="argument rules", value=rules, expected_type=type_hints["rules"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "rules": rules, - } - - @builtins.property - def rules(self) -> typing.List["PodFailurePolicyRule"]: - '''A list of pod failure policy rules. - - The rules are evaluated in order. Once a rule matches a Pod failure, the remaining of the rules are ignored. When no rule matches the Pod failure, the default handling applies - the counter of pod failures is incremented and it is checked against the backoffLimit. At most 20 elements are allowed. - - :schema: io.k8s.api.batch.v1.PodFailurePolicy#rules - ''' - result = self._values.get("rules") - assert result is not None, "Required property 'rules' is missing" - return typing.cast(typing.List["PodFailurePolicyRule"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "PodFailurePolicy(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.PodFailurePolicyOnExitCodesRequirement", - jsii_struct_bases=[], - name_mapping={ - "operator": "operator", - "values": "values", - "container_name": "containerName", - }, -) -class PodFailurePolicyOnExitCodesRequirement: - def __init__( - self, - *, - operator: builtins.str, - values: typing.Sequence[jsii.Number], - container_name: typing.Optional[builtins.str] = None, - ) -> None: - '''PodFailurePolicyOnExitCodesRequirement describes the requirement for handling a failed pod based on its container exit codes. - - In particular, it lookups the .state.terminated.exitCode for each app container and init container status, represented by the .status.containerStatuses and .status.initContainerStatuses fields in the Pod status, respectively. Containers completed with success (exit code 0) are excluded from the requirement check. - - :param operator: Represents the relationship between the container exit code(s) and the specified values. Containers completed with success (exit code 0) are excluded from the requirement check. Possible values are: - In: the requirement is satisfied if at least one container exit code (might be multiple if there are multiple containers not restricted by the 'containerName' field) is in the set of specified values. - NotIn: the requirement is satisfied if at least one container exit code (might be multiple if there are multiple containers not restricted by the 'containerName' field) is not in the set of specified values. Additional values are considered to be added in the future. Clients should react to an unknown operator by assuming the requirement is not satisfied. - :param values: Specifies the set of values. Each returned container exit code (might be multiple in case of multiple containers) is checked against this set of values with respect to the operator. The list of values must be ordered and must not contain duplicates. Value '0' cannot be used for the In operator. At least one element is required. At most 255 elements are allowed. - :param container_name: Restricts the check for exit codes to the container with the specified name. When null, the rule applies to all containers. When specified, it should match one the container or initContainer names in the pod template. - - :schema: io.k8s.api.batch.v1.PodFailurePolicyOnExitCodesRequirement - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__9156cdbac4d38b9bf3a2fd6d97fb9187f19aa4043a7010b5897b2c0ff19ddb5a) - check_type(argname="argument operator", value=operator, expected_type=type_hints["operator"]) - check_type(argname="argument values", value=values, expected_type=type_hints["values"]) - check_type(argname="argument container_name", value=container_name, expected_type=type_hints["container_name"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "operator": operator, - "values": values, - } - if container_name is not None: - self._values["container_name"] = container_name - - @builtins.property - def operator(self) -> builtins.str: - '''Represents the relationship between the container exit code(s) and the specified values. - - Containers completed with success (exit code 0) are excluded from the requirement check. Possible values are: - In: the requirement is satisfied if at least one container exit code - (might be multiple if there are multiple containers not restricted - by the 'containerName' field) is in the set of specified values. - - - NotIn: the requirement is satisfied if at least one container exit code - (might be multiple if there are multiple containers not restricted - by the 'containerName' field) is not in the set of specified values. - Additional values are considered to be added in the future. Clients should react to an unknown operator by assuming the requirement is not satisfied. - - :schema: io.k8s.api.batch.v1.PodFailurePolicyOnExitCodesRequirement#operator - ''' - result = self._values.get("operator") - assert result is not None, "Required property 'operator' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def values(self) -> typing.List[jsii.Number]: - '''Specifies the set of values. - - Each returned container exit code (might be multiple in case of multiple containers) is checked against this set of values with respect to the operator. The list of values must be ordered and must not contain duplicates. Value '0' cannot be used for the In operator. At least one element is required. At most 255 elements are allowed. - - :schema: io.k8s.api.batch.v1.PodFailurePolicyOnExitCodesRequirement#values - ''' - result = self._values.get("values") - assert result is not None, "Required property 'values' is missing" - return typing.cast(typing.List[jsii.Number], result) - - @builtins.property - def container_name(self) -> typing.Optional[builtins.str]: - '''Restricts the check for exit codes to the container with the specified name. - - When null, the rule applies to all containers. When specified, it should match one the container or initContainer names in the pod template. - - :schema: io.k8s.api.batch.v1.PodFailurePolicyOnExitCodesRequirement#containerName - ''' - result = self._values.get("container_name") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "PodFailurePolicyOnExitCodesRequirement(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.PodFailurePolicyOnPodConditionsPattern", - jsii_struct_bases=[], - name_mapping={"status": "status", "type": "type"}, -) -class PodFailurePolicyOnPodConditionsPattern: - def __init__(self, *, status: builtins.str, type: builtins.str) -> None: - '''PodFailurePolicyOnPodConditionsPattern describes a pattern for matching an actual pod condition type. - - :param status: Specifies the required Pod condition status. To match a pod condition it is required that the specified status equals the pod condition status. Defaults to True. Default: True. - :param type: Specifies the required Pod condition type. To match a pod condition it is required that specified type equals the pod condition type. - - :schema: io.k8s.api.batch.v1.PodFailurePolicyOnPodConditionsPattern - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__749d7e1a80b843779b9d09f3b38a68a3fd1c77026783179dbf25170231c5a720) - check_type(argname="argument status", value=status, expected_type=type_hints["status"]) - check_type(argname="argument type", value=type, expected_type=type_hints["type"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "status": status, - "type": type, - } - - @builtins.property - def status(self) -> builtins.str: - '''Specifies the required Pod condition status. - - To match a pod condition it is required that the specified status equals the pod condition status. Defaults to True. - - :default: True. - - :schema: io.k8s.api.batch.v1.PodFailurePolicyOnPodConditionsPattern#status - ''' - result = self._values.get("status") - assert result is not None, "Required property 'status' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def type(self) -> builtins.str: - '''Specifies the required Pod condition type. - - To match a pod condition it is required that specified type equals the pod condition type. - - :schema: io.k8s.api.batch.v1.PodFailurePolicyOnPodConditionsPattern#type - ''' - result = self._values.get("type") - assert result is not None, "Required property 'type' is missing" - return typing.cast(builtins.str, result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "PodFailurePolicyOnPodConditionsPattern(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.PodFailurePolicyRule", - jsii_struct_bases=[], - name_mapping={ - "action": "action", - "on_pod_conditions": "onPodConditions", - "on_exit_codes": "onExitCodes", - }, -) -class PodFailurePolicyRule: - def __init__( - self, - *, - action: builtins.str, - on_pod_conditions: typing.Sequence[typing.Union[PodFailurePolicyOnPodConditionsPattern, typing.Dict[builtins.str, typing.Any]]], - on_exit_codes: typing.Optional[typing.Union[PodFailurePolicyOnExitCodesRequirement, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''PodFailurePolicyRule describes how a pod failure is handled when the requirements are met. - - One of OnExitCodes and onPodConditions, but not both, can be used in each rule. - - :param action: Specifies the action taken on a pod failure when the requirements are satisfied. Possible values are: - FailJob: indicates that the pod's job is marked as Failed and all running pods are terminated. - Ignore: indicates that the counter towards the .backoffLimit is not incremented and a replacement pod is created. - Count: indicates that the pod is handled in the default way - the counter towards the .backoffLimit is incremented. Additional values are considered to be added in the future. Clients should react to an unknown action by skipping the rule. - :param on_pod_conditions: Represents the requirement on the pod conditions. The requirement is represented as a list of pod condition patterns. The requirement is satisfied if at least one pattern matches an actual pod condition. At most 20 elements are allowed. - :param on_exit_codes: Represents the requirement on the container exit codes. - - :schema: io.k8s.api.batch.v1.PodFailurePolicyRule - ''' - if isinstance(on_exit_codes, dict): - on_exit_codes = PodFailurePolicyOnExitCodesRequirement(**on_exit_codes) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__9752d799ae40ee7e1d07cceb2daac5e29af9b379c43f336814f8928b638ebe0a) - check_type(argname="argument action", value=action, expected_type=type_hints["action"]) - check_type(argname="argument on_pod_conditions", value=on_pod_conditions, expected_type=type_hints["on_pod_conditions"]) - check_type(argname="argument on_exit_codes", value=on_exit_codes, expected_type=type_hints["on_exit_codes"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "action": action, - "on_pod_conditions": on_pod_conditions, - } - if on_exit_codes is not None: - self._values["on_exit_codes"] = on_exit_codes - - @builtins.property - def action(self) -> builtins.str: - '''Specifies the action taken on a pod failure when the requirements are satisfied. - - Possible values are: - FailJob: indicates that the pod's job is marked as Failed and all - running pods are terminated. - - - Ignore: indicates that the counter towards the .backoffLimit is not - incremented and a replacement pod is created. - - Count: indicates that the pod is handled in the default way - the - counter towards the .backoffLimit is incremented. - Additional values are considered to be added in the future. Clients should react to an unknown action by skipping the rule. - - :schema: io.k8s.api.batch.v1.PodFailurePolicyRule#action - ''' - result = self._values.get("action") - assert result is not None, "Required property 'action' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def on_pod_conditions(self) -> typing.List[PodFailurePolicyOnPodConditionsPattern]: - '''Represents the requirement on the pod conditions. - - The requirement is represented as a list of pod condition patterns. The requirement is satisfied if at least one pattern matches an actual pod condition. At most 20 elements are allowed. - - :schema: io.k8s.api.batch.v1.PodFailurePolicyRule#onPodConditions - ''' - result = self._values.get("on_pod_conditions") - assert result is not None, "Required property 'on_pod_conditions' is missing" - return typing.cast(typing.List[PodFailurePolicyOnPodConditionsPattern], result) - - @builtins.property - def on_exit_codes(self) -> typing.Optional[PodFailurePolicyOnExitCodesRequirement]: - '''Represents the requirement on the container exit codes. - - :schema: io.k8s.api.batch.v1.PodFailurePolicyRule#onExitCodes - ''' - result = self._values.get("on_exit_codes") - return typing.cast(typing.Optional[PodFailurePolicyOnExitCodesRequirement], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "PodFailurePolicyRule(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.PodOs", - jsii_struct_bases=[], - name_mapping={"name": "name"}, -) -class PodOs: - def __init__(self, *, name: builtins.str) -> None: - '''PodOS defines the OS parameters of a pod. - - :param name: Name is the name of the operating system. The currently supported values are linux and windows. Additional value may be defined in future and can be one of: https://github.com/opencontainers/runtime-spec/blob/master/config.md#platform-specific-configuration Clients should expect to handle additional values and treat unrecognized values in this field as os: null - - :schema: io.k8s.api.core.v1.PodOS - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__447466b6ee10b58f2a9031698c5d443c3de519f08a74be7dba21e1509f800a9f) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "name": name, - } - - @builtins.property - def name(self) -> builtins.str: - '''Name is the name of the operating system. - - The currently supported values are linux and windows. Additional value may be defined in future and can be one of: https://github.com/opencontainers/runtime-spec/blob/master/config.md#platform-specific-configuration Clients should expect to handle additional values and treat unrecognized values in this field as os: null - - :schema: io.k8s.api.core.v1.PodOS#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "PodOs(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.PodReadinessGate", - jsii_struct_bases=[], - name_mapping={"condition_type": "conditionType"}, -) -class PodReadinessGate: - def __init__(self, *, condition_type: builtins.str) -> None: - '''PodReadinessGate contains the reference to a pod condition. - - :param condition_type: ConditionType refers to a condition in the pod's condition list with matching type. - - :schema: io.k8s.api.core.v1.PodReadinessGate - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__6efa6da68115e82d6b27bff9f91e3ed47585fedf0e8e6358afee97da2cccc1fc) - check_type(argname="argument condition_type", value=condition_type, expected_type=type_hints["condition_type"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "condition_type": condition_type, - } - - @builtins.property - def condition_type(self) -> builtins.str: - '''ConditionType refers to a condition in the pod's condition list with matching type. - - :schema: io.k8s.api.core.v1.PodReadinessGate#conditionType - ''' - result = self._values.get("condition_type") - assert result is not None, "Required property 'condition_type' is missing" - return typing.cast(builtins.str, result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "PodReadinessGate(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.PodResourceClaim", - jsii_struct_bases=[], - name_mapping={"name": "name", "source": "source"}, -) -class PodResourceClaim: - def __init__( - self, - *, - name: builtins.str, - source: typing.Optional[typing.Union[ClaimSource, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''PodResourceClaim references exactly one ResourceClaim through a ClaimSource. - - It adds a name to it that uniquely identifies the ResourceClaim inside the Pod. Containers that need access to the ResourceClaim reference it with this name. - - :param name: Name uniquely identifies this resource claim inside the pod. This must be a DNS_LABEL. - :param source: Source describes where to find the ResourceClaim. - - :schema: io.k8s.api.core.v1.PodResourceClaim - ''' - if isinstance(source, dict): - source = ClaimSource(**source) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__593eecd9b8e25f27db87859570a28b2ffda74b52af7ef080a6bc114f4b263f52) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument source", value=source, expected_type=type_hints["source"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "name": name, - } - if source is not None: - self._values["source"] = source - - @builtins.property - def name(self) -> builtins.str: - '''Name uniquely identifies this resource claim inside the pod. - - This must be a DNS_LABEL. - - :schema: io.k8s.api.core.v1.PodResourceClaim#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def source(self) -> typing.Optional[ClaimSource]: - '''Source describes where to find the ResourceClaim. - - :schema: io.k8s.api.core.v1.PodResourceClaim#source - ''' - result = self._values.get("source") - return typing.cast(typing.Optional[ClaimSource], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "PodResourceClaim(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.PodSchedulingGate", - jsii_struct_bases=[], - name_mapping={"name": "name"}, -) -class PodSchedulingGate: - def __init__(self, *, name: builtins.str) -> None: - '''PodSchedulingGate is associated to a Pod to guard its scheduling. - - :param name: Name of the scheduling gate. Each scheduling gate must have a unique name field. - - :schema: io.k8s.api.core.v1.PodSchedulingGate - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__ba3a868f60063830cfdaddc5e19d4d1ef9980dc7ffe3b27b3e802c3eaede83dc) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "name": name, - } - - @builtins.property - def name(self) -> builtins.str: - '''Name of the scheduling gate. - - Each scheduling gate must have a unique name field. - - :schema: io.k8s.api.core.v1.PodSchedulingGate#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "PodSchedulingGate(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.PodSchedulingSpecV1Alpha1", - jsii_struct_bases=[], - name_mapping={ - "potential_nodes": "potentialNodes", - "selected_node": "selectedNode", - }, -) -class PodSchedulingSpecV1Alpha1: - def __init__( - self, - *, - potential_nodes: typing.Optional[typing.Sequence[builtins.str]] = None, - selected_node: typing.Optional[builtins.str] = None, - ) -> None: - '''PodSchedulingSpec describes where resources for the Pod are needed. - - :param potential_nodes: PotentialNodes lists nodes where the Pod might be able to run. The size of this field is limited to 128. This is large enough for many clusters. Larger clusters may need more attempts to find a node that suits all pending resources. This may get increased in the future, but not reduced. - :param selected_node: SelectedNode is the node for which allocation of ResourceClaims that are referenced by the Pod and that use "WaitForFirstConsumer" allocation is to be attempted. - - :schema: io.k8s.api.resource.v1alpha1.PodSchedulingSpec - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__cbaa152d2aa3b0f9ec0ecda0ddb7625c4422ee7ea4ee6a8b3c47fc6deee35d21) - check_type(argname="argument potential_nodes", value=potential_nodes, expected_type=type_hints["potential_nodes"]) - check_type(argname="argument selected_node", value=selected_node, expected_type=type_hints["selected_node"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if potential_nodes is not None: - self._values["potential_nodes"] = potential_nodes - if selected_node is not None: - self._values["selected_node"] = selected_node - - @builtins.property - def potential_nodes(self) -> typing.Optional[typing.List[builtins.str]]: - '''PotentialNodes lists nodes where the Pod might be able to run. - - The size of this field is limited to 128. This is large enough for many clusters. Larger clusters may need more attempts to find a node that suits all pending resources. This may get increased in the future, but not reduced. - - :schema: io.k8s.api.resource.v1alpha1.PodSchedulingSpec#potentialNodes - ''' - result = self._values.get("potential_nodes") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def selected_node(self) -> typing.Optional[builtins.str]: - '''SelectedNode is the node for which allocation of ResourceClaims that are referenced by the Pod and that use "WaitForFirstConsumer" allocation is to be attempted. - - :schema: io.k8s.api.resource.v1alpha1.PodSchedulingSpec#selectedNode - ''' - result = self._values.get("selected_node") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "PodSchedulingSpecV1Alpha1(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.PodSecurityContext", - jsii_struct_bases=[], - name_mapping={ - "fs_group": "fsGroup", - "fs_group_change_policy": "fsGroupChangePolicy", - "run_as_group": "runAsGroup", - "run_as_non_root": "runAsNonRoot", - "run_as_user": "runAsUser", - "seccomp_profile": "seccompProfile", - "se_linux_options": "seLinuxOptions", - "supplemental_groups": "supplementalGroups", - "sysctls": "sysctls", - "windows_options": "windowsOptions", - }, -) -class PodSecurityContext: - def __init__( - self, - *, - fs_group: typing.Optional[jsii.Number] = None, - fs_group_change_policy: typing.Optional[builtins.str] = None, - run_as_group: typing.Optional[jsii.Number] = None, - run_as_non_root: typing.Optional[builtins.bool] = None, - run_as_user: typing.Optional[jsii.Number] = None, - seccomp_profile: typing.Optional[typing.Union["SeccompProfile", typing.Dict[builtins.str, typing.Any]]] = None, - se_linux_options: typing.Optional[typing.Union["SeLinuxOptions", typing.Dict[builtins.str, typing.Any]]] = None, - supplemental_groups: typing.Optional[typing.Sequence[jsii.Number]] = None, - sysctls: typing.Optional[typing.Sequence[typing.Union["Sysctl", typing.Dict[builtins.str, typing.Any]]]] = None, - windows_options: typing.Optional[typing.Union["WindowsSecurityContextOptions", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''PodSecurityContext holds pod-level security attributes and common container settings. - - Some fields are also present in container.securityContext. Field values of container.securityContext take precedence over field values of PodSecurityContext. - - :param fs_group: A special supplemental group that applies to all containers in a pod. Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod: 1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw---- If unset, the Kubelet will not modify the ownership and permissions of any volume. Note that this field cannot be set when spec.os.name is windows. - :param fs_group_change_policy: fsGroupChangePolicy defines behavior of changing ownership and permission of the volume before being exposed inside Pod. This field will only apply to volume types which support fsGroup based ownership(and permissions). It will have no effect on ephemeral volume types such as: secret, configmaps and emptydir. Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. Note that this field cannot be set when spec.os.name is windows. - :param run_as_group: The GID to run the entrypoint of the container process. Uses runtime default if unset. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container. Note that this field cannot be set when spec.os.name is windows. - :param run_as_non_root: Indicates that the container must run as a non-root user. If true, the Kubelet will validate the image at runtime to ensure that it does not run as UID 0 (root) and fail to start the container if it does. If unset or false, no such validation will be performed. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. - :param run_as_user: The UID to run the entrypoint of the container process. Defaults to user specified in image metadata if unspecified. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container. Note that this field cannot be set when spec.os.name is windows. Default: user specified in image metadata if unspecified. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container. Note that this field cannot be set when spec.os.name is windows. - :param seccomp_profile: The seccomp options to use by the containers in this pod. Note that this field cannot be set when spec.os.name is windows. - :param se_linux_options: The SELinux context to be applied to all containers. If unspecified, the container runtime will allocate a random SELinux context for each container. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container. Note that this field cannot be set when spec.os.name is windows. - :param supplemental_groups: A list of groups applied to the first process run in each container, in addition to the container's primary GID, the fsGroup (if specified), and group memberships defined in the container image for the uid of the container process. If unspecified, no additional groups are added to any container. Note that group memberships defined in the container image for the uid of the container process are still effective, even if they are not included in this list. Note that this field cannot be set when spec.os.name is windows. - :param sysctls: Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported sysctls (by the container runtime) might fail to launch. Note that this field cannot be set when spec.os.name is windows. - :param windows_options: The Windows specific settings applied to all containers. If unspecified, the options within a container's SecurityContext will be used. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. Note that this field cannot be set when spec.os.name is linux. - - :schema: io.k8s.api.core.v1.PodSecurityContext - ''' - if isinstance(seccomp_profile, dict): - seccomp_profile = SeccompProfile(**seccomp_profile) - if isinstance(se_linux_options, dict): - se_linux_options = SeLinuxOptions(**se_linux_options) - if isinstance(windows_options, dict): - windows_options = WindowsSecurityContextOptions(**windows_options) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__b23f586ca6b5b102b009640138cfcb7cb8db5fffa8d48ddb6c723e2d52bc60bc) - check_type(argname="argument fs_group", value=fs_group, expected_type=type_hints["fs_group"]) - check_type(argname="argument fs_group_change_policy", value=fs_group_change_policy, expected_type=type_hints["fs_group_change_policy"]) - check_type(argname="argument run_as_group", value=run_as_group, expected_type=type_hints["run_as_group"]) - check_type(argname="argument run_as_non_root", value=run_as_non_root, expected_type=type_hints["run_as_non_root"]) - check_type(argname="argument run_as_user", value=run_as_user, expected_type=type_hints["run_as_user"]) - check_type(argname="argument seccomp_profile", value=seccomp_profile, expected_type=type_hints["seccomp_profile"]) - check_type(argname="argument se_linux_options", value=se_linux_options, expected_type=type_hints["se_linux_options"]) - check_type(argname="argument supplemental_groups", value=supplemental_groups, expected_type=type_hints["supplemental_groups"]) - check_type(argname="argument sysctls", value=sysctls, expected_type=type_hints["sysctls"]) - check_type(argname="argument windows_options", value=windows_options, expected_type=type_hints["windows_options"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if fs_group is not None: - self._values["fs_group"] = fs_group - if fs_group_change_policy is not None: - self._values["fs_group_change_policy"] = fs_group_change_policy - if run_as_group is not None: - self._values["run_as_group"] = run_as_group - if run_as_non_root is not None: - self._values["run_as_non_root"] = run_as_non_root - if run_as_user is not None: - self._values["run_as_user"] = run_as_user - if seccomp_profile is not None: - self._values["seccomp_profile"] = seccomp_profile - if se_linux_options is not None: - self._values["se_linux_options"] = se_linux_options - if supplemental_groups is not None: - self._values["supplemental_groups"] = supplemental_groups - if sysctls is not None: - self._values["sysctls"] = sysctls - if windows_options is not None: - self._values["windows_options"] = windows_options - - @builtins.property - def fs_group(self) -> typing.Optional[jsii.Number]: - '''A special supplemental group that applies to all containers in a pod. - - Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod: - - 1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw---- - - If unset, the Kubelet will not modify the ownership and permissions of any volume. Note that this field cannot be set when spec.os.name is windows. - - :schema: io.k8s.api.core.v1.PodSecurityContext#fsGroup - ''' - result = self._values.get("fs_group") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def fs_group_change_policy(self) -> typing.Optional[builtins.str]: - '''fsGroupChangePolicy defines behavior of changing ownership and permission of the volume before being exposed inside Pod. - - This field will only apply to volume types which support fsGroup based ownership(and permissions). It will have no effect on ephemeral volume types such as: secret, configmaps and emptydir. Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. Note that this field cannot be set when spec.os.name is windows. - - :schema: io.k8s.api.core.v1.PodSecurityContext#fsGroupChangePolicy - ''' - result = self._values.get("fs_group_change_policy") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def run_as_group(self) -> typing.Optional[jsii.Number]: - '''The GID to run the entrypoint of the container process. - - Uses runtime default if unset. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container. Note that this field cannot be set when spec.os.name is windows. - - :schema: io.k8s.api.core.v1.PodSecurityContext#runAsGroup - ''' - result = self._values.get("run_as_group") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def run_as_non_root(self) -> typing.Optional[builtins.bool]: - '''Indicates that the container must run as a non-root user. - - If true, the Kubelet will validate the image at runtime to ensure that it does not run as UID 0 (root) and fail to start the container if it does. If unset or false, no such validation will be performed. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. - - :schema: io.k8s.api.core.v1.PodSecurityContext#runAsNonRoot - ''' - result = self._values.get("run_as_non_root") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def run_as_user(self) -> typing.Optional[jsii.Number]: - '''The UID to run the entrypoint of the container process. - - Defaults to user specified in image metadata if unspecified. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container. Note that this field cannot be set when spec.os.name is windows. - - :default: user specified in image metadata if unspecified. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container. Note that this field cannot be set when spec.os.name is windows. - - :schema: io.k8s.api.core.v1.PodSecurityContext#runAsUser - ''' - result = self._values.get("run_as_user") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def seccomp_profile(self) -> typing.Optional["SeccompProfile"]: - '''The seccomp options to use by the containers in this pod. - - Note that this field cannot be set when spec.os.name is windows. - - :schema: io.k8s.api.core.v1.PodSecurityContext#seccompProfile - ''' - result = self._values.get("seccomp_profile") - return typing.cast(typing.Optional["SeccompProfile"], result) - - @builtins.property - def se_linux_options(self) -> typing.Optional["SeLinuxOptions"]: - '''The SELinux context to be applied to all containers. - - If unspecified, the container runtime will allocate a random SELinux context for each container. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container. Note that this field cannot be set when spec.os.name is windows. - - :schema: io.k8s.api.core.v1.PodSecurityContext#seLinuxOptions - ''' - result = self._values.get("se_linux_options") - return typing.cast(typing.Optional["SeLinuxOptions"], result) - - @builtins.property - def supplemental_groups(self) -> typing.Optional[typing.List[jsii.Number]]: - '''A list of groups applied to the first process run in each container, in addition to the container's primary GID, the fsGroup (if specified), and group memberships defined in the container image for the uid of the container process. - - If unspecified, no additional groups are added to any container. Note that group memberships defined in the container image for the uid of the container process are still effective, even if they are not included in this list. Note that this field cannot be set when spec.os.name is windows. - - :schema: io.k8s.api.core.v1.PodSecurityContext#supplementalGroups - ''' - result = self._values.get("supplemental_groups") - return typing.cast(typing.Optional[typing.List[jsii.Number]], result) - - @builtins.property - def sysctls(self) -> typing.Optional[typing.List["Sysctl"]]: - '''Sysctls hold a list of namespaced sysctls used for the pod. - - Pods with unsupported sysctls (by the container runtime) might fail to launch. Note that this field cannot be set when spec.os.name is windows. - - :schema: io.k8s.api.core.v1.PodSecurityContext#sysctls - ''' - result = self._values.get("sysctls") - return typing.cast(typing.Optional[typing.List["Sysctl"]], result) - - @builtins.property - def windows_options(self) -> typing.Optional["WindowsSecurityContextOptions"]: - '''The Windows specific settings applied to all containers. - - If unspecified, the options within a container's SecurityContext will be used. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. Note that this field cannot be set when spec.os.name is linux. - - :schema: io.k8s.api.core.v1.PodSecurityContext#windowsOptions - ''' - result = self._values.get("windows_options") - return typing.cast(typing.Optional["WindowsSecurityContextOptions"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "PodSecurityContext(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.PodSpec", - jsii_struct_bases=[], - name_mapping={ - "containers": "containers", - "active_deadline_seconds": "activeDeadlineSeconds", - "affinity": "affinity", - "automount_service_account_token": "automountServiceAccountToken", - "dns_config": "dnsConfig", - "dns_policy": "dnsPolicy", - "enable_service_links": "enableServiceLinks", - "ephemeral_containers": "ephemeralContainers", - "host_aliases": "hostAliases", - "host_ipc": "hostIpc", - "hostname": "hostname", - "host_network": "hostNetwork", - "host_pid": "hostPid", - "host_users": "hostUsers", - "image_pull_secrets": "imagePullSecrets", - "init_containers": "initContainers", - "node_name": "nodeName", - "node_selector": "nodeSelector", - "os": "os", - "overhead": "overhead", - "preemption_policy": "preemptionPolicy", - "priority": "priority", - "priority_class_name": "priorityClassName", - "readiness_gates": "readinessGates", - "resource_claims": "resourceClaims", - "restart_policy": "restartPolicy", - "runtime_class_name": "runtimeClassName", - "scheduler_name": "schedulerName", - "scheduling_gates": "schedulingGates", - "security_context": "securityContext", - "service_account": "serviceAccount", - "service_account_name": "serviceAccountName", - "set_hostname_as_fqdn": "setHostnameAsFqdn", - "share_process_namespace": "shareProcessNamespace", - "subdomain": "subdomain", - "termination_grace_period_seconds": "terminationGracePeriodSeconds", - "tolerations": "tolerations", - "topology_spread_constraints": "topologySpreadConstraints", - "volumes": "volumes", - }, -) -class PodSpec: - def __init__( - self, - *, - containers: typing.Sequence[typing.Union[Container, typing.Dict[builtins.str, typing.Any]]], - active_deadline_seconds: typing.Optional[jsii.Number] = None, - affinity: typing.Optional[typing.Union[Affinity, typing.Dict[builtins.str, typing.Any]]] = None, - automount_service_account_token: typing.Optional[builtins.bool] = None, - dns_config: typing.Optional[typing.Union[PodDnsConfig, typing.Dict[builtins.str, typing.Any]]] = None, - dns_policy: typing.Optional[builtins.str] = None, - enable_service_links: typing.Optional[builtins.bool] = None, - ephemeral_containers: typing.Optional[typing.Sequence[typing.Union[EphemeralContainer, typing.Dict[builtins.str, typing.Any]]]] = None, - host_aliases: typing.Optional[typing.Sequence[typing.Union[HostAlias, typing.Dict[builtins.str, typing.Any]]]] = None, - host_ipc: typing.Optional[builtins.bool] = None, - hostname: typing.Optional[builtins.str] = None, - host_network: typing.Optional[builtins.bool] = None, - host_pid: typing.Optional[builtins.bool] = None, - host_users: typing.Optional[builtins.bool] = None, - image_pull_secrets: typing.Optional[typing.Sequence[typing.Union[LocalObjectReference, typing.Dict[builtins.str, typing.Any]]]] = None, - init_containers: typing.Optional[typing.Sequence[typing.Union[Container, typing.Dict[builtins.str, typing.Any]]]] = None, - node_name: typing.Optional[builtins.str] = None, - node_selector: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - os: typing.Optional[typing.Union[PodOs, typing.Dict[builtins.str, typing.Any]]] = None, - overhead: typing.Optional[typing.Mapping[builtins.str, "Quantity"]] = None, - preemption_policy: typing.Optional[builtins.str] = None, - priority: typing.Optional[jsii.Number] = None, - priority_class_name: typing.Optional[builtins.str] = None, - readiness_gates: typing.Optional[typing.Sequence[typing.Union[PodReadinessGate, typing.Dict[builtins.str, typing.Any]]]] = None, - resource_claims: typing.Optional[typing.Sequence[typing.Union[PodResourceClaim, typing.Dict[builtins.str, typing.Any]]]] = None, - restart_policy: typing.Optional[builtins.str] = None, - runtime_class_name: typing.Optional[builtins.str] = None, - scheduler_name: typing.Optional[builtins.str] = None, - scheduling_gates: typing.Optional[typing.Sequence[typing.Union[PodSchedulingGate, typing.Dict[builtins.str, typing.Any]]]] = None, - security_context: typing.Optional[typing.Union[PodSecurityContext, typing.Dict[builtins.str, typing.Any]]] = None, - service_account: typing.Optional[builtins.str] = None, - service_account_name: typing.Optional[builtins.str] = None, - set_hostname_as_fqdn: typing.Optional[builtins.bool] = None, - share_process_namespace: typing.Optional[builtins.bool] = None, - subdomain: typing.Optional[builtins.str] = None, - termination_grace_period_seconds: typing.Optional[jsii.Number] = None, - tolerations: typing.Optional[typing.Sequence[typing.Union["Toleration", typing.Dict[builtins.str, typing.Any]]]] = None, - topology_spread_constraints: typing.Optional[typing.Sequence[typing.Union["TopologySpreadConstraint", typing.Dict[builtins.str, typing.Any]]]] = None, - volumes: typing.Optional[typing.Sequence[typing.Union["Volume", typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''PodSpec is a description of a pod. - - :param containers: List of containers belonging to the pod. Containers cannot currently be added or removed. There must be at least one container in a Pod. Cannot be updated. - :param active_deadline_seconds: Optional duration in seconds the pod may be active on the node relative to StartTime before the system will actively try to mark it failed and kill associated containers. Value must be a positive integer. - :param affinity: If specified, the pod's scheduling constraints. - :param automount_service_account_token: AutomountServiceAccountToken indicates whether a service account token should be automatically mounted. - :param dns_config: Specifies the DNS parameters of a pod. Parameters specified here will be merged to the generated DNS configuration based on DNSPolicy. - :param dns_policy: Set DNS policy for the pod. Defaults to "ClusterFirst". Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'. Default: ClusterFirst". Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'. - :param enable_service_links: EnableServiceLinks indicates whether information about services should be injected into pod's environment variables, matching the syntax of Docker links. Optional: Defaults to true. Default: true. - :param ephemeral_containers: List of ephemeral containers run in this pod. Ephemeral containers may be run in an existing pod to perform user-initiated actions such as debugging. This list cannot be specified when creating a pod, and it cannot be modified by updating the pod spec. In order to add an ephemeral container to an existing pod, use the pod's ephemeralcontainers subresource. - :param host_aliases: HostAliases is an optional list of hosts and IPs that will be injected into the pod's hosts file if specified. This is only valid for non-hostNetwork pods. - :param host_ipc: Use the host's ipc namespace. Optional: Default to false. Default: false. - :param hostname: Specifies the hostname of the Pod If not specified, the pod's hostname will be set to a system-defined value. - :param host_network: Host networking requested for this pod. Use the host's network namespace. If this option is set, the ports that will be used must be specified. Default to false. Default: false. - :param host_pid: Use the host's pid namespace. Optional: Default to false. Default: false. - :param host_users: Use the host's user namespace. Optional: Default to true. If set to true or not present, the pod will be run in the host user namespace, useful for when the pod needs a feature only available to the host user namespace, such as loading a kernel module with CAP_SYS_MODULE. When set to false, a new userns is created for the pod. Setting false is useful for mitigating container breakout vulnerabilities even allowing users to run their containers as root without actually having root privileges on the host. This field is alpha-level and is only honored by servers that enable the UserNamespacesSupport feature. Default: true. If set to true or not present, the pod will be run in the host user namespace, useful for when the pod needs a feature only available to the host user namespace, such as loading a kernel module with CAP_SYS_MODULE. When set to false, a new userns is created for the pod. Setting false is useful for mitigating container breakout vulnerabilities even allowing users to run their containers as root without actually having root privileges on the host. This field is alpha-level and is only honored by servers that enable the UserNamespacesSupport feature. - :param image_pull_secrets: ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec. If specified, these secrets will be passed to individual puller implementations for them to use. More info: https://kubernetes.io/docs/concepts/containers/images#specifying-imagepullsecrets-on-a-pod - :param init_containers: List of initialization containers belonging to the pod. Init containers are executed in order prior to containers being started. If any init container fails, the pod is considered to have failed and is handled according to its restartPolicy. The name for an init container or normal container must be unique among all containers. Init containers may not have Lifecycle actions, Readiness probes, Liveness probes, or Startup probes. The resourceRequirements of an init container are taken into account during scheduling by finding the highest request/limit for each resource type, and then using the max of of that value or the sum of the normal containers. Limits are applied to init containers in a similar fashion. Init containers cannot currently be added or removed. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ - :param node_name: NodeName is a request to schedule this pod onto a specific node. If it is non-empty, the scheduler simply schedules this pod onto that node, assuming that it fits resource requirements. - :param node_selector: NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node's labels for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ - :param os: Specifies the OS of the containers in the pod. Some pod and container fields are restricted if this is set. If the OS field is set to linux, the following fields must be unset: -securityContext.windowsOptions If the OS field is set to windows, following fields must be unset: - spec.hostPID - spec.hostIPC - spec.hostUsers - spec.securityContext.seLinuxOptions - spec.securityContext.seccompProfile - spec.securityContext.fsGroup - spec.securityContext.fsGroupChangePolicy - spec.securityContext.sysctls - spec.shareProcessNamespace - spec.securityContext.runAsUser - spec.securityContext.runAsGroup - spec.securityContext.supplementalGroups - spec.containers[*].securityContext.seLinuxOptions - spec.containers[*].securityContext.seccompProfile - spec.containers[*].securityContext.capabilities - spec.containers[*].securityContext.readOnlyRootFilesystem - spec.containers[*].securityContext.privileged - spec.containers[*].securityContext.allowPrivilegeEscalation - spec.containers[*].securityContext.procMount - spec.containers[*].securityContext.runAsUser - spec.containers[*].securityContext.runAsGroup - :param overhead: Overhead represents the resource overhead associated with running a pod for a given RuntimeClass. This field will be autopopulated at admission time by the RuntimeClass admission controller. If the RuntimeClass admission controller is enabled, overhead must not be set in Pod create requests. The RuntimeClass admission controller will reject Pod create requests which have the overhead already set. If RuntimeClass is configured and selected in the PodSpec, Overhead will be set to the value defined in the corresponding RuntimeClass, otherwise it will remain unset and treated as zero. More info: https://git.k8s.io/enhancements/keps/sig-node/688-pod-overhead/README.md - :param preemption_policy: PreemptionPolicy is the Policy for preempting pods with lower priority. One of Never, PreemptLowerPriority. Defaults to PreemptLowerPriority if unset. Default: PreemptLowerPriority if unset. - :param priority: The priority value. Various system components use this field to find the priority of the pod. When Priority Admission Controller is enabled, it prevents users from setting this field. The admission controller populates this field from PriorityClassName. The higher the value, the higher the priority. - :param priority_class_name: If specified, indicates the pod's priority. "system-node-critical" and "system-cluster-critical" are two special keywords which indicate the highest priorities with the former being the highest priority. Any other name must be defined by creating a PriorityClass object with that name. If not specified, the pod priority will be default or zero if there is no default. - :param readiness_gates: If specified, all readiness gates will be evaluated for pod readiness. A pod is ready when all its containers are ready AND all conditions specified in the readiness gates have status equal to "True" More info: https://git.k8s.io/enhancements/keps/sig-network/580-pod-readiness-gates - :param resource_claims: ResourceClaims defines which ResourceClaims must be allocated and reserved before the Pod is allowed to start. The resources will be made available to those containers which consume them by name. This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. This field is immutable. - :param restart_policy: Restart policy for all containers within the pod. One of Always, OnFailure, Never. Default to Always. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy Default: Always. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy - :param runtime_class_name: RuntimeClassName refers to a RuntimeClass object in the node.k8s.io group, which should be used to run this pod. If no RuntimeClass resource matches the named class, the pod will not be run. If unset or empty, the "legacy" RuntimeClass will be used, which is an implicit class with an empty definition that uses the default runtime handler. More info: https://git.k8s.io/enhancements/keps/sig-node/585-runtime-class. - :param scheduler_name: If specified, the pod will be dispatched by specified scheduler. If not specified, the pod will be dispatched by default scheduler. - :param scheduling_gates: SchedulingGates is an opaque list of values that if specified will block scheduling the pod. More info: https://git.k8s.io/enhancements/keps/sig-scheduling/3521-pod-scheduling-readiness. This is an alpha-level feature enabled by PodSchedulingReadiness feature gate. - :param security_context: SecurityContext holds pod-level security attributes and common container settings. Optional: Defaults to empty. See type description for default values of each field. Default: empty. See type description for default values of each field. - :param service_account: DeprecatedServiceAccount is a depreciated alias for ServiceAccountName. Deprecated: Use serviceAccountName instead. - :param service_account_name: ServiceAccountName is the name of the ServiceAccount to use to run this pod. More info: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ - :param set_hostname_as_fqdn: If true the pod's hostname will be configured as the pod's FQDN, rather than the leaf name (the default). In Linux containers, this means setting the FQDN in the hostname field of the kernel (the nodename field of struct utsname). In Windows containers, this means setting the registry value of hostname for the registry key HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters to FQDN. If a pod does not have FQDN, this has no effect. Default to false. Default: false. - :param share_process_namespace: Share a single process namespace between all of the containers in a pod. When this is set containers will be able to view and signal processes from other containers in the same pod, and the first process in each container will not be assigned PID 1. HostPID and ShareProcessNamespace cannot both be set. Optional: Default to false. Default: false. - :param subdomain: If specified, the fully qualified Pod hostname will be "...svc.". If not specified, the pod will not have a domainname at all. - :param termination_grace_period_seconds: Optional duration in seconds the pod needs to terminate gracefully. May be decreased in delete request. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). If this value is nil, the default grace period will be used instead. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. Defaults to 30 seconds. Default: 30 seconds. - :param tolerations: If specified, the pod's tolerations. - :param topology_spread_constraints: TopologySpreadConstraints describes how a group of pods ought to spread across topology domains. Scheduler will schedule pods in a way which abides by the constraints. All topologySpreadConstraints are ANDed. - :param volumes: List of volumes that can be mounted by containers belonging to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes - - :schema: io.k8s.api.core.v1.PodSpec - ''' - if isinstance(affinity, dict): - affinity = Affinity(**affinity) - if isinstance(dns_config, dict): - dns_config = PodDnsConfig(**dns_config) - if isinstance(os, dict): - os = PodOs(**os) - if isinstance(security_context, dict): - security_context = PodSecurityContext(**security_context) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__9ddad62f26f59d5b393ec9c7814efae31dbad75f06f4456a0bef61a6ce7dd763) - check_type(argname="argument containers", value=containers, expected_type=type_hints["containers"]) - check_type(argname="argument active_deadline_seconds", value=active_deadline_seconds, expected_type=type_hints["active_deadline_seconds"]) - check_type(argname="argument affinity", value=affinity, expected_type=type_hints["affinity"]) - check_type(argname="argument automount_service_account_token", value=automount_service_account_token, expected_type=type_hints["automount_service_account_token"]) - check_type(argname="argument dns_config", value=dns_config, expected_type=type_hints["dns_config"]) - check_type(argname="argument dns_policy", value=dns_policy, expected_type=type_hints["dns_policy"]) - check_type(argname="argument enable_service_links", value=enable_service_links, expected_type=type_hints["enable_service_links"]) - check_type(argname="argument ephemeral_containers", value=ephemeral_containers, expected_type=type_hints["ephemeral_containers"]) - check_type(argname="argument host_aliases", value=host_aliases, expected_type=type_hints["host_aliases"]) - check_type(argname="argument host_ipc", value=host_ipc, expected_type=type_hints["host_ipc"]) - check_type(argname="argument hostname", value=hostname, expected_type=type_hints["hostname"]) - check_type(argname="argument host_network", value=host_network, expected_type=type_hints["host_network"]) - check_type(argname="argument host_pid", value=host_pid, expected_type=type_hints["host_pid"]) - check_type(argname="argument host_users", value=host_users, expected_type=type_hints["host_users"]) - check_type(argname="argument image_pull_secrets", value=image_pull_secrets, expected_type=type_hints["image_pull_secrets"]) - check_type(argname="argument init_containers", value=init_containers, expected_type=type_hints["init_containers"]) - check_type(argname="argument node_name", value=node_name, expected_type=type_hints["node_name"]) - check_type(argname="argument node_selector", value=node_selector, expected_type=type_hints["node_selector"]) - check_type(argname="argument os", value=os, expected_type=type_hints["os"]) - check_type(argname="argument overhead", value=overhead, expected_type=type_hints["overhead"]) - check_type(argname="argument preemption_policy", value=preemption_policy, expected_type=type_hints["preemption_policy"]) - check_type(argname="argument priority", value=priority, expected_type=type_hints["priority"]) - check_type(argname="argument priority_class_name", value=priority_class_name, expected_type=type_hints["priority_class_name"]) - check_type(argname="argument readiness_gates", value=readiness_gates, expected_type=type_hints["readiness_gates"]) - check_type(argname="argument resource_claims", value=resource_claims, expected_type=type_hints["resource_claims"]) - check_type(argname="argument restart_policy", value=restart_policy, expected_type=type_hints["restart_policy"]) - check_type(argname="argument runtime_class_name", value=runtime_class_name, expected_type=type_hints["runtime_class_name"]) - check_type(argname="argument scheduler_name", value=scheduler_name, expected_type=type_hints["scheduler_name"]) - check_type(argname="argument scheduling_gates", value=scheduling_gates, expected_type=type_hints["scheduling_gates"]) - check_type(argname="argument security_context", value=security_context, expected_type=type_hints["security_context"]) - check_type(argname="argument service_account", value=service_account, expected_type=type_hints["service_account"]) - check_type(argname="argument service_account_name", value=service_account_name, expected_type=type_hints["service_account_name"]) - check_type(argname="argument set_hostname_as_fqdn", value=set_hostname_as_fqdn, expected_type=type_hints["set_hostname_as_fqdn"]) - check_type(argname="argument share_process_namespace", value=share_process_namespace, expected_type=type_hints["share_process_namespace"]) - check_type(argname="argument subdomain", value=subdomain, expected_type=type_hints["subdomain"]) - check_type(argname="argument termination_grace_period_seconds", value=termination_grace_period_seconds, expected_type=type_hints["termination_grace_period_seconds"]) - check_type(argname="argument tolerations", value=tolerations, expected_type=type_hints["tolerations"]) - check_type(argname="argument topology_spread_constraints", value=topology_spread_constraints, expected_type=type_hints["topology_spread_constraints"]) - check_type(argname="argument volumes", value=volumes, expected_type=type_hints["volumes"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "containers": containers, - } - if active_deadline_seconds is not None: - self._values["active_deadline_seconds"] = active_deadline_seconds - if affinity is not None: - self._values["affinity"] = affinity - if automount_service_account_token is not None: - self._values["automount_service_account_token"] = automount_service_account_token - if dns_config is not None: - self._values["dns_config"] = dns_config - if dns_policy is not None: - self._values["dns_policy"] = dns_policy - if enable_service_links is not None: - self._values["enable_service_links"] = enable_service_links - if ephemeral_containers is not None: - self._values["ephemeral_containers"] = ephemeral_containers - if host_aliases is not None: - self._values["host_aliases"] = host_aliases - if host_ipc is not None: - self._values["host_ipc"] = host_ipc - if hostname is not None: - self._values["hostname"] = hostname - if host_network is not None: - self._values["host_network"] = host_network - if host_pid is not None: - self._values["host_pid"] = host_pid - if host_users is not None: - self._values["host_users"] = host_users - if image_pull_secrets is not None: - self._values["image_pull_secrets"] = image_pull_secrets - if init_containers is not None: - self._values["init_containers"] = init_containers - if node_name is not None: - self._values["node_name"] = node_name - if node_selector is not None: - self._values["node_selector"] = node_selector - if os is not None: - self._values["os"] = os - if overhead is not None: - self._values["overhead"] = overhead - if preemption_policy is not None: - self._values["preemption_policy"] = preemption_policy - if priority is not None: - self._values["priority"] = priority - if priority_class_name is not None: - self._values["priority_class_name"] = priority_class_name - if readiness_gates is not None: - self._values["readiness_gates"] = readiness_gates - if resource_claims is not None: - self._values["resource_claims"] = resource_claims - if restart_policy is not None: - self._values["restart_policy"] = restart_policy - if runtime_class_name is not None: - self._values["runtime_class_name"] = runtime_class_name - if scheduler_name is not None: - self._values["scheduler_name"] = scheduler_name - if scheduling_gates is not None: - self._values["scheduling_gates"] = scheduling_gates - if security_context is not None: - self._values["security_context"] = security_context - if service_account is not None: - self._values["service_account"] = service_account - if service_account_name is not None: - self._values["service_account_name"] = service_account_name - if set_hostname_as_fqdn is not None: - self._values["set_hostname_as_fqdn"] = set_hostname_as_fqdn - if share_process_namespace is not None: - self._values["share_process_namespace"] = share_process_namespace - if subdomain is not None: - self._values["subdomain"] = subdomain - if termination_grace_period_seconds is not None: - self._values["termination_grace_period_seconds"] = termination_grace_period_seconds - if tolerations is not None: - self._values["tolerations"] = tolerations - if topology_spread_constraints is not None: - self._values["topology_spread_constraints"] = topology_spread_constraints - if volumes is not None: - self._values["volumes"] = volumes - - @builtins.property - def containers(self) -> typing.List[Container]: - '''List of containers belonging to the pod. - - Containers cannot currently be added or removed. There must be at least one container in a Pod. Cannot be updated. - - :schema: io.k8s.api.core.v1.PodSpec#containers - ''' - result = self._values.get("containers") - assert result is not None, "Required property 'containers' is missing" - return typing.cast(typing.List[Container], result) - - @builtins.property - def active_deadline_seconds(self) -> typing.Optional[jsii.Number]: - '''Optional duration in seconds the pod may be active on the node relative to StartTime before the system will actively try to mark it failed and kill associated containers. - - Value must be a positive integer. - - :schema: io.k8s.api.core.v1.PodSpec#activeDeadlineSeconds - ''' - result = self._values.get("active_deadline_seconds") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def affinity(self) -> typing.Optional[Affinity]: - '''If specified, the pod's scheduling constraints. - - :schema: io.k8s.api.core.v1.PodSpec#affinity - ''' - result = self._values.get("affinity") - return typing.cast(typing.Optional[Affinity], result) - - @builtins.property - def automount_service_account_token(self) -> typing.Optional[builtins.bool]: - '''AutomountServiceAccountToken indicates whether a service account token should be automatically mounted. - - :schema: io.k8s.api.core.v1.PodSpec#automountServiceAccountToken - ''' - result = self._values.get("automount_service_account_token") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def dns_config(self) -> typing.Optional[PodDnsConfig]: - '''Specifies the DNS parameters of a pod. - - Parameters specified here will be merged to the generated DNS configuration based on DNSPolicy. - - :schema: io.k8s.api.core.v1.PodSpec#dnsConfig - ''' - result = self._values.get("dns_config") - return typing.cast(typing.Optional[PodDnsConfig], result) - - @builtins.property - def dns_policy(self) -> typing.Optional[builtins.str]: - '''Set DNS policy for the pod. - - Defaults to "ClusterFirst". Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'. - - :default: ClusterFirst". Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'. - - :schema: io.k8s.api.core.v1.PodSpec#dnsPolicy - ''' - result = self._values.get("dns_policy") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def enable_service_links(self) -> typing.Optional[builtins.bool]: - '''EnableServiceLinks indicates whether information about services should be injected into pod's environment variables, matching the syntax of Docker links. - - Optional: Defaults to true. - - :default: true. - - :schema: io.k8s.api.core.v1.PodSpec#enableServiceLinks - ''' - result = self._values.get("enable_service_links") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def ephemeral_containers(self) -> typing.Optional[typing.List[EphemeralContainer]]: - '''List of ephemeral containers run in this pod. - - Ephemeral containers may be run in an existing pod to perform user-initiated actions such as debugging. This list cannot be specified when creating a pod, and it cannot be modified by updating the pod spec. In order to add an ephemeral container to an existing pod, use the pod's ephemeralcontainers subresource. - - :schema: io.k8s.api.core.v1.PodSpec#ephemeralContainers - ''' - result = self._values.get("ephemeral_containers") - return typing.cast(typing.Optional[typing.List[EphemeralContainer]], result) - - @builtins.property - def host_aliases(self) -> typing.Optional[typing.List[HostAlias]]: - '''HostAliases is an optional list of hosts and IPs that will be injected into the pod's hosts file if specified. - - This is only valid for non-hostNetwork pods. - - :schema: io.k8s.api.core.v1.PodSpec#hostAliases - ''' - result = self._values.get("host_aliases") - return typing.cast(typing.Optional[typing.List[HostAlias]], result) - - @builtins.property - def host_ipc(self) -> typing.Optional[builtins.bool]: - '''Use the host's ipc namespace. - - Optional: Default to false. - - :default: false. - - :schema: io.k8s.api.core.v1.PodSpec#hostIPC - ''' - result = self._values.get("host_ipc") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def hostname(self) -> typing.Optional[builtins.str]: - '''Specifies the hostname of the Pod If not specified, the pod's hostname will be set to a system-defined value. - - :schema: io.k8s.api.core.v1.PodSpec#hostname - ''' - result = self._values.get("hostname") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def host_network(self) -> typing.Optional[builtins.bool]: - '''Host networking requested for this pod. - - Use the host's network namespace. If this option is set, the ports that will be used must be specified. Default to false. - - :default: false. - - :schema: io.k8s.api.core.v1.PodSpec#hostNetwork - ''' - result = self._values.get("host_network") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def host_pid(self) -> typing.Optional[builtins.bool]: - '''Use the host's pid namespace. - - Optional: Default to false. - - :default: false. - - :schema: io.k8s.api.core.v1.PodSpec#hostPID - ''' - result = self._values.get("host_pid") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def host_users(self) -> typing.Optional[builtins.bool]: - '''Use the host's user namespace. - - Optional: Default to true. If set to true or not present, the pod will be run in the host user namespace, useful for when the pod needs a feature only available to the host user namespace, such as loading a kernel module with CAP_SYS_MODULE. When set to false, a new userns is created for the pod. Setting false is useful for mitigating container breakout vulnerabilities even allowing users to run their containers as root without actually having root privileges on the host. This field is alpha-level and is only honored by servers that enable the UserNamespacesSupport feature. - - :default: true. If set to true or not present, the pod will be run in the host user namespace, useful for when the pod needs a feature only available to the host user namespace, such as loading a kernel module with CAP_SYS_MODULE. When set to false, a new userns is created for the pod. Setting false is useful for mitigating container breakout vulnerabilities even allowing users to run their containers as root without actually having root privileges on the host. This field is alpha-level and is only honored by servers that enable the UserNamespacesSupport feature. - - :schema: io.k8s.api.core.v1.PodSpec#hostUsers - ''' - result = self._values.get("host_users") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def image_pull_secrets(self) -> typing.Optional[typing.List[LocalObjectReference]]: - '''ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec. - - If specified, these secrets will be passed to individual puller implementations for them to use. More info: https://kubernetes.io/docs/concepts/containers/images#specifying-imagepullsecrets-on-a-pod - - :schema: io.k8s.api.core.v1.PodSpec#imagePullSecrets - ''' - result = self._values.get("image_pull_secrets") - return typing.cast(typing.Optional[typing.List[LocalObjectReference]], result) - - @builtins.property - def init_containers(self) -> typing.Optional[typing.List[Container]]: - '''List of initialization containers belonging to the pod. - - Init containers are executed in order prior to containers being started. If any init container fails, the pod is considered to have failed and is handled according to its restartPolicy. The name for an init container or normal container must be unique among all containers. Init containers may not have Lifecycle actions, Readiness probes, Liveness probes, or Startup probes. The resourceRequirements of an init container are taken into account during scheduling by finding the highest request/limit for each resource type, and then using the max of of that value or the sum of the normal containers. Limits are applied to init containers in a similar fashion. Init containers cannot currently be added or removed. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ - - :schema: io.k8s.api.core.v1.PodSpec#initContainers - ''' - result = self._values.get("init_containers") - return typing.cast(typing.Optional[typing.List[Container]], result) - - @builtins.property - def node_name(self) -> typing.Optional[builtins.str]: - '''NodeName is a request to schedule this pod onto a specific node. - - If it is non-empty, the scheduler simply schedules this pod onto that node, assuming that it fits resource requirements. - - :schema: io.k8s.api.core.v1.PodSpec#nodeName - ''' - result = self._values.get("node_name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def node_selector( - self, - ) -> typing.Optional[typing.Mapping[builtins.str, builtins.str]]: - '''NodeSelector is a selector which must be true for the pod to fit on a node. - - Selector which must match a node's labels for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ - - :schema: io.k8s.api.core.v1.PodSpec#nodeSelector - ''' - result = self._values.get("node_selector") - return typing.cast(typing.Optional[typing.Mapping[builtins.str, builtins.str]], result) - - @builtins.property - def os(self) -> typing.Optional[PodOs]: - '''Specifies the OS of the containers in the pod. - - Some pod and container fields are restricted if this is set. - - If the OS field is set to linux, the following fields must be unset: -securityContext.windowsOptions - - If the OS field is set to windows, following fields must be unset: - spec.hostPID - spec.hostIPC - spec.hostUsers - spec.securityContext.seLinuxOptions - spec.securityContext.seccompProfile - spec.securityContext.fsGroup - spec.securityContext.fsGroupChangePolicy - spec.securityContext.sysctls - spec.shareProcessNamespace - spec.securityContext.runAsUser - spec.securityContext.runAsGroup - spec.securityContext.supplementalGroups - spec.containers[*].securityContext.seLinuxOptions - spec.containers[*].securityContext.seccompProfile - spec.containers[*].securityContext.capabilities - spec.containers[*].securityContext.readOnlyRootFilesystem - spec.containers[*].securityContext.privileged - spec.containers[*].securityContext.allowPrivilegeEscalation - spec.containers[*].securityContext.procMount - spec.containers[*].securityContext.runAsUser - spec.containers[*].securityContext.runAsGroup - - :schema: io.k8s.api.core.v1.PodSpec#os - ''' - result = self._values.get("os") - return typing.cast(typing.Optional[PodOs], result) - - @builtins.property - def overhead(self) -> typing.Optional[typing.Mapping[builtins.str, "Quantity"]]: - '''Overhead represents the resource overhead associated with running a pod for a given RuntimeClass. - - This field will be autopopulated at admission time by the RuntimeClass admission controller. If the RuntimeClass admission controller is enabled, overhead must not be set in Pod create requests. The RuntimeClass admission controller will reject Pod create requests which have the overhead already set. If RuntimeClass is configured and selected in the PodSpec, Overhead will be set to the value defined in the corresponding RuntimeClass, otherwise it will remain unset and treated as zero. More info: https://git.k8s.io/enhancements/keps/sig-node/688-pod-overhead/README.md - - :schema: io.k8s.api.core.v1.PodSpec#overhead - ''' - result = self._values.get("overhead") - return typing.cast(typing.Optional[typing.Mapping[builtins.str, "Quantity"]], result) - - @builtins.property - def preemption_policy(self) -> typing.Optional[builtins.str]: - '''PreemptionPolicy is the Policy for preempting pods with lower priority. - - One of Never, PreemptLowerPriority. Defaults to PreemptLowerPriority if unset. - - :default: PreemptLowerPriority if unset. - - :schema: io.k8s.api.core.v1.PodSpec#preemptionPolicy - ''' - result = self._values.get("preemption_policy") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def priority(self) -> typing.Optional[jsii.Number]: - '''The priority value. - - Various system components use this field to find the priority of the pod. When Priority Admission Controller is enabled, it prevents users from setting this field. The admission controller populates this field from PriorityClassName. The higher the value, the higher the priority. - - :schema: io.k8s.api.core.v1.PodSpec#priority - ''' - result = self._values.get("priority") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def priority_class_name(self) -> typing.Optional[builtins.str]: - '''If specified, indicates the pod's priority. - - "system-node-critical" and "system-cluster-critical" are two special keywords which indicate the highest priorities with the former being the highest priority. Any other name must be defined by creating a PriorityClass object with that name. If not specified, the pod priority will be default or zero if there is no default. - - :schema: io.k8s.api.core.v1.PodSpec#priorityClassName - ''' - result = self._values.get("priority_class_name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def readiness_gates(self) -> typing.Optional[typing.List[PodReadinessGate]]: - '''If specified, all readiness gates will be evaluated for pod readiness. - - A pod is ready when all its containers are ready AND all conditions specified in the readiness gates have status equal to "True" More info: https://git.k8s.io/enhancements/keps/sig-network/580-pod-readiness-gates - - :schema: io.k8s.api.core.v1.PodSpec#readinessGates - ''' - result = self._values.get("readiness_gates") - return typing.cast(typing.Optional[typing.List[PodReadinessGate]], result) - - @builtins.property - def resource_claims(self) -> typing.Optional[typing.List[PodResourceClaim]]: - '''ResourceClaims defines which ResourceClaims must be allocated and reserved before the Pod is allowed to start. - - The resources will be made available to those containers which consume them by name. - - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - - This field is immutable. - - :schema: io.k8s.api.core.v1.PodSpec#resourceClaims - ''' - result = self._values.get("resource_claims") - return typing.cast(typing.Optional[typing.List[PodResourceClaim]], result) - - @builtins.property - def restart_policy(self) -> typing.Optional[builtins.str]: - '''Restart policy for all containers within the pod. - - One of Always, OnFailure, Never. Default to Always. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy - - :default: Always. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy - - :schema: io.k8s.api.core.v1.PodSpec#restartPolicy - ''' - result = self._values.get("restart_policy") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def runtime_class_name(self) -> typing.Optional[builtins.str]: - '''RuntimeClassName refers to a RuntimeClass object in the node.k8s.io group, which should be used to run this pod. If no RuntimeClass resource matches the named class, the pod will not be run. If unset or empty, the "legacy" RuntimeClass will be used, which is an implicit class with an empty definition that uses the default runtime handler. More info: https://git.k8s.io/enhancements/keps/sig-node/585-runtime-class. - - :schema: io.k8s.api.core.v1.PodSpec#runtimeClassName - ''' - result = self._values.get("runtime_class_name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def scheduler_name(self) -> typing.Optional[builtins.str]: - '''If specified, the pod will be dispatched by specified scheduler. - - If not specified, the pod will be dispatched by default scheduler. - - :schema: io.k8s.api.core.v1.PodSpec#schedulerName - ''' - result = self._values.get("scheduler_name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def scheduling_gates(self) -> typing.Optional[typing.List[PodSchedulingGate]]: - '''SchedulingGates is an opaque list of values that if specified will block scheduling the pod. More info: https://git.k8s.io/enhancements/keps/sig-scheduling/3521-pod-scheduling-readiness. - - This is an alpha-level feature enabled by PodSchedulingReadiness feature gate. - - :schema: io.k8s.api.core.v1.PodSpec#schedulingGates - ''' - result = self._values.get("scheduling_gates") - return typing.cast(typing.Optional[typing.List[PodSchedulingGate]], result) - - @builtins.property - def security_context(self) -> typing.Optional[PodSecurityContext]: - '''SecurityContext holds pod-level security attributes and common container settings. - - Optional: Defaults to empty. See type description for default values of each field. - - :default: empty. See type description for default values of each field. - - :schema: io.k8s.api.core.v1.PodSpec#securityContext - ''' - result = self._values.get("security_context") - return typing.cast(typing.Optional[PodSecurityContext], result) - - @builtins.property - def service_account(self) -> typing.Optional[builtins.str]: - '''DeprecatedServiceAccount is a depreciated alias for ServiceAccountName. - - Deprecated: Use serviceAccountName instead. - - :schema: io.k8s.api.core.v1.PodSpec#serviceAccount - ''' - result = self._values.get("service_account") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def service_account_name(self) -> typing.Optional[builtins.str]: - '''ServiceAccountName is the name of the ServiceAccount to use to run this pod. - - More info: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ - - :schema: io.k8s.api.core.v1.PodSpec#serviceAccountName - ''' - result = self._values.get("service_account_name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def set_hostname_as_fqdn(self) -> typing.Optional[builtins.bool]: - '''If true the pod's hostname will be configured as the pod's FQDN, rather than the leaf name (the default). - - In Linux containers, this means setting the FQDN in the hostname field of the kernel (the nodename field of struct utsname). In Windows containers, this means setting the registry value of hostname for the registry key HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters to FQDN. If a pod does not have FQDN, this has no effect. Default to false. - - :default: false. - - :schema: io.k8s.api.core.v1.PodSpec#setHostnameAsFQDN - ''' - result = self._values.get("set_hostname_as_fqdn") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def share_process_namespace(self) -> typing.Optional[builtins.bool]: - '''Share a single process namespace between all of the containers in a pod. - - When this is set containers will be able to view and signal processes from other containers in the same pod, and the first process in each container will not be assigned PID 1. HostPID and ShareProcessNamespace cannot both be set. Optional: Default to false. - - :default: false. - - :schema: io.k8s.api.core.v1.PodSpec#shareProcessNamespace - ''' - result = self._values.get("share_process_namespace") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def subdomain(self) -> typing.Optional[builtins.str]: - '''If specified, the fully qualified Pod hostname will be "...svc.". If not specified, the pod will not have a domainname at all. - - :schema: io.k8s.api.core.v1.PodSpec#subdomain - ''' - result = self._values.get("subdomain") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def termination_grace_period_seconds(self) -> typing.Optional[jsii.Number]: - '''Optional duration in seconds the pod needs to terminate gracefully. - - May be decreased in delete request. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). If this value is nil, the default grace period will be used instead. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. Defaults to 30 seconds. - - :default: 30 seconds. - - :schema: io.k8s.api.core.v1.PodSpec#terminationGracePeriodSeconds - ''' - result = self._values.get("termination_grace_period_seconds") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def tolerations(self) -> typing.Optional[typing.List["Toleration"]]: - '''If specified, the pod's tolerations. - - :schema: io.k8s.api.core.v1.PodSpec#tolerations - ''' - result = self._values.get("tolerations") - return typing.cast(typing.Optional[typing.List["Toleration"]], result) - - @builtins.property - def topology_spread_constraints( - self, - ) -> typing.Optional[typing.List["TopologySpreadConstraint"]]: - '''TopologySpreadConstraints describes how a group of pods ought to spread across topology domains. - - Scheduler will schedule pods in a way which abides by the constraints. All topologySpreadConstraints are ANDed. - - :schema: io.k8s.api.core.v1.PodSpec#topologySpreadConstraints - ''' - result = self._values.get("topology_spread_constraints") - return typing.cast(typing.Optional[typing.List["TopologySpreadConstraint"]], result) - - @builtins.property - def volumes(self) -> typing.Optional[typing.List["Volume"]]: - '''List of volumes that can be mounted by containers belonging to the pod. - - More info: https://kubernetes.io/docs/concepts/storage/volumes - - :schema: io.k8s.api.core.v1.PodSpec#volumes - ''' - result = self._values.get("volumes") - return typing.cast(typing.Optional[typing.List["Volume"]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "PodSpec(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.PodTemplateSpec", - jsii_struct_bases=[], - name_mapping={"metadata": "metadata", "spec": "spec"}, -) -class PodTemplateSpec: - def __init__( - self, - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[PodSpec, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''PodTemplateSpec describes the data a pod should have when created from a template. - - :param metadata: Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - :param spec: Specification of the desired behavior of the pod. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.core.v1.PodTemplateSpec - ''' - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if isinstance(spec, dict): - spec = PodSpec(**spec) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__a23cda3e55cf29ffda2e22bb377999f4b35fa2ff1fdb8ae27faf58b7f2b9c866) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if metadata is not None: - self._values["metadata"] = metadata - if spec is not None: - self._values["spec"] = spec - - @builtins.property - def metadata(self) -> typing.Optional[ObjectMeta]: - '''Standard object's metadata. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - - :schema: io.k8s.api.core.v1.PodTemplateSpec#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional[ObjectMeta], result) - - @builtins.property - def spec(self) -> typing.Optional[PodSpec]: - '''Specification of the desired behavior of the pod. - - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - - :schema: io.k8s.api.core.v1.PodTemplateSpec#spec - ''' - result = self._values.get("spec") - return typing.cast(typing.Optional[PodSpec], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "PodTemplateSpec(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.PodsMetricSourceV2", - jsii_struct_bases=[], - name_mapping={"metric": "metric", "target": "target"}, -) -class PodsMetricSourceV2: - def __init__( - self, - *, - metric: typing.Union[MetricIdentifierV2, typing.Dict[builtins.str, typing.Any]], - target: typing.Union[MetricTargetV2, typing.Dict[builtins.str, typing.Any]], - ) -> None: - '''PodsMetricSource indicates how to scale on a metric describing each pod in the current scale target (for example, transactions-processed-per-second). - - The values will be averaged together before being compared to the target value. - - :param metric: metric identifies the target metric by name and selector. - :param target: target specifies the target value for the given metric. - - :schema: io.k8s.api.autoscaling.v2.PodsMetricSource - ''' - if isinstance(metric, dict): - metric = MetricIdentifierV2(**metric) - if isinstance(target, dict): - target = MetricTargetV2(**target) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__4e1daa232feea2f9ba7daaf3807ee414905ce98c0d3805ab6cd957f8405729b3) - check_type(argname="argument metric", value=metric, expected_type=type_hints["metric"]) - check_type(argname="argument target", value=target, expected_type=type_hints["target"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "metric": metric, - "target": target, - } - - @builtins.property - def metric(self) -> MetricIdentifierV2: - '''metric identifies the target metric by name and selector. - - :schema: io.k8s.api.autoscaling.v2.PodsMetricSource#metric - ''' - result = self._values.get("metric") - assert result is not None, "Required property 'metric' is missing" - return typing.cast(MetricIdentifierV2, result) - - @builtins.property - def target(self) -> MetricTargetV2: - '''target specifies the target value for the given metric. - - :schema: io.k8s.api.autoscaling.v2.PodsMetricSource#target - ''' - result = self._values.get("target") - assert result is not None, "Required property 'target' is missing" - return typing.cast(MetricTargetV2, result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "PodsMetricSourceV2(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.PolicyRule", - jsii_struct_bases=[], - name_mapping={ - "verbs": "verbs", - "api_groups": "apiGroups", - "non_resource_ur_ls": "nonResourceUrLs", - "resource_names": "resourceNames", - "resources": "resources", - }, -) -class PolicyRule: - def __init__( - self, - *, - verbs: typing.Sequence[builtins.str], - api_groups: typing.Optional[typing.Sequence[builtins.str]] = None, - non_resource_ur_ls: typing.Optional[typing.Sequence[builtins.str]] = None, - resource_names: typing.Optional[typing.Sequence[builtins.str]] = None, - resources: typing.Optional[typing.Sequence[builtins.str]] = None, - ) -> None: - '''PolicyRule holds information that describes a policy rule, but does not contain information about who the rule applies to or which namespace the rule applies to. - - :param verbs: Verbs is a list of Verbs that apply to ALL the ResourceKinds contained in this rule. '*' represents all verbs. - :param api_groups: APIGroups is the name of the APIGroup that contains the resources. If multiple API groups are specified, any action requested against one of the enumerated resources in any API group will be allowed. "" represents the core API group and "*" represents all API groups. - :param non_resource_ur_ls: NonResourceURLs is a set of partial urls that a user should have access to. *s are allowed, but only as the full, final step in the path Since non-resource URLs are not namespaced, this field is only applicable for ClusterRoles referenced from a ClusterRoleBinding. Rules can either apply to API resources (such as "pods" or "secrets") or non-resource URL paths (such as "/api"), but not both. - :param resource_names: ResourceNames is an optional white list of names that the rule applies to. An empty set means that everything is allowed. - :param resources: Resources is a list of resources this rule applies to. '*' represents all resources. - - :schema: io.k8s.api.rbac.v1.PolicyRule - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__faa1080f7a02c3d2eac7f18aad0cdbef93f8f9cff0f9825224a9dd8a829faf0a) - check_type(argname="argument verbs", value=verbs, expected_type=type_hints["verbs"]) - check_type(argname="argument api_groups", value=api_groups, expected_type=type_hints["api_groups"]) - check_type(argname="argument non_resource_ur_ls", value=non_resource_ur_ls, expected_type=type_hints["non_resource_ur_ls"]) - check_type(argname="argument resource_names", value=resource_names, expected_type=type_hints["resource_names"]) - check_type(argname="argument resources", value=resources, expected_type=type_hints["resources"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "verbs": verbs, - } - if api_groups is not None: - self._values["api_groups"] = api_groups - if non_resource_ur_ls is not None: - self._values["non_resource_ur_ls"] = non_resource_ur_ls - if resource_names is not None: - self._values["resource_names"] = resource_names - if resources is not None: - self._values["resources"] = resources - - @builtins.property - def verbs(self) -> typing.List[builtins.str]: - '''Verbs is a list of Verbs that apply to ALL the ResourceKinds contained in this rule. - - '*' represents all verbs. - - :schema: io.k8s.api.rbac.v1.PolicyRule#verbs - ''' - result = self._values.get("verbs") - assert result is not None, "Required property 'verbs' is missing" - return typing.cast(typing.List[builtins.str], result) - - @builtins.property - def api_groups(self) -> typing.Optional[typing.List[builtins.str]]: - '''APIGroups is the name of the APIGroup that contains the resources. - - If multiple API groups are specified, any action requested against one of the enumerated resources in any API group will be allowed. "" represents the core API group and "*" represents all API groups. - - :schema: io.k8s.api.rbac.v1.PolicyRule#apiGroups - ''' - result = self._values.get("api_groups") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def non_resource_ur_ls(self) -> typing.Optional[typing.List[builtins.str]]: - '''NonResourceURLs is a set of partial urls that a user should have access to. - - *s are allowed, but only as the full, final step in the path Since non-resource URLs are not namespaced, this field is only applicable for ClusterRoles referenced from a ClusterRoleBinding. Rules can either apply to API resources (such as "pods" or "secrets") or non-resource URL paths (such as "/api"), but not both. - - :schema: io.k8s.api.rbac.v1.PolicyRule#nonResourceURLs - ''' - result = self._values.get("non_resource_ur_ls") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def resource_names(self) -> typing.Optional[typing.List[builtins.str]]: - '''ResourceNames is an optional white list of names that the rule applies to. - - An empty set means that everything is allowed. - - :schema: io.k8s.api.rbac.v1.PolicyRule#resourceNames - ''' - result = self._values.get("resource_names") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def resources(self) -> typing.Optional[typing.List[builtins.str]]: - '''Resources is a list of resources this rule applies to. - - '*' represents all resources. - - :schema: io.k8s.api.rbac.v1.PolicyRule#resources - ''' - result = self._values.get("resources") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "PolicyRule(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.PolicyRulesWithSubjectsV1Beta2", - jsii_struct_bases=[], - name_mapping={ - "subjects": "subjects", - "non_resource_rules": "nonResourceRules", - "resource_rules": "resourceRules", - }, -) -class PolicyRulesWithSubjectsV1Beta2: - def __init__( - self, - *, - subjects: typing.Sequence[typing.Union["SubjectV1Beta2", typing.Dict[builtins.str, typing.Any]]], - non_resource_rules: typing.Optional[typing.Sequence[typing.Union[NonResourcePolicyRuleV1Beta2, typing.Dict[builtins.str, typing.Any]]]] = None, - resource_rules: typing.Optional[typing.Sequence[typing.Union["ResourcePolicyRuleV1Beta2", typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''PolicyRulesWithSubjects prescribes a test that applies to a request to an apiserver. - - The test considers the subject making the request, the verb being requested, and the resource to be acted upon. This PolicyRulesWithSubjects matches a request if and only if both (a) at least one member of subjects matches the request and (b) at least one member of resourceRules or nonResourceRules matches the request. - - :param subjects: subjects is the list of normal user, serviceaccount, or group that this rule cares about. There must be at least one member in this slice. A slice that includes both the system:authenticated and system:unauthenticated user groups matches every request. Required. - :param non_resource_rules: ``nonResourceRules`` is a list of NonResourcePolicyRules that identify matching requests according to their verb and the target non-resource URL. - :param resource_rules: ``resourceRules`` is a slice of ResourcePolicyRules that identify matching requests according to their verb and the target resource. At least one of ``resourceRules`` and ``nonResourceRules`` has to be non-empty. - - :schema: io.k8s.api.flowcontrol.v1beta2.PolicyRulesWithSubjects - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__b8fb123532a9c4783d0f6374006effe94f2abbd28e993ae2827ad3601ddf98c5) - check_type(argname="argument subjects", value=subjects, expected_type=type_hints["subjects"]) - check_type(argname="argument non_resource_rules", value=non_resource_rules, expected_type=type_hints["non_resource_rules"]) - check_type(argname="argument resource_rules", value=resource_rules, expected_type=type_hints["resource_rules"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "subjects": subjects, - } - if non_resource_rules is not None: - self._values["non_resource_rules"] = non_resource_rules - if resource_rules is not None: - self._values["resource_rules"] = resource_rules - - @builtins.property - def subjects(self) -> typing.List["SubjectV1Beta2"]: - '''subjects is the list of normal user, serviceaccount, or group that this rule cares about. - - There must be at least one member in this slice. A slice that includes both the system:authenticated and system:unauthenticated user groups matches every request. Required. - - :schema: io.k8s.api.flowcontrol.v1beta2.PolicyRulesWithSubjects#subjects - ''' - result = self._values.get("subjects") - assert result is not None, "Required property 'subjects' is missing" - return typing.cast(typing.List["SubjectV1Beta2"], result) - - @builtins.property - def non_resource_rules( - self, - ) -> typing.Optional[typing.List[NonResourcePolicyRuleV1Beta2]]: - '''``nonResourceRules`` is a list of NonResourcePolicyRules that identify matching requests according to their verb and the target non-resource URL. - - :schema: io.k8s.api.flowcontrol.v1beta2.PolicyRulesWithSubjects#nonResourceRules - ''' - result = self._values.get("non_resource_rules") - return typing.cast(typing.Optional[typing.List[NonResourcePolicyRuleV1Beta2]], result) - - @builtins.property - def resource_rules( - self, - ) -> typing.Optional[typing.List["ResourcePolicyRuleV1Beta2"]]: - '''``resourceRules`` is a slice of ResourcePolicyRules that identify matching requests according to their verb and the target resource. - - At least one of ``resourceRules`` and ``nonResourceRules`` has to be non-empty. - - :schema: io.k8s.api.flowcontrol.v1beta2.PolicyRulesWithSubjects#resourceRules - ''' - result = self._values.get("resource_rules") - return typing.cast(typing.Optional[typing.List["ResourcePolicyRuleV1Beta2"]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "PolicyRulesWithSubjectsV1Beta2(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.PolicyRulesWithSubjectsV1Beta3", - jsii_struct_bases=[], - name_mapping={ - "subjects": "subjects", - "non_resource_rules": "nonResourceRules", - "resource_rules": "resourceRules", - }, -) -class PolicyRulesWithSubjectsV1Beta3: - def __init__( - self, - *, - subjects: typing.Sequence[typing.Union["SubjectV1Beta3", typing.Dict[builtins.str, typing.Any]]], - non_resource_rules: typing.Optional[typing.Sequence[typing.Union[NonResourcePolicyRuleV1Beta3, typing.Dict[builtins.str, typing.Any]]]] = None, - resource_rules: typing.Optional[typing.Sequence[typing.Union["ResourcePolicyRuleV1Beta3", typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''PolicyRulesWithSubjects prescribes a test that applies to a request to an apiserver. - - The test considers the subject making the request, the verb being requested, and the resource to be acted upon. This PolicyRulesWithSubjects matches a request if and only if both (a) at least one member of subjects matches the request and (b) at least one member of resourceRules or nonResourceRules matches the request. - - :param subjects: subjects is the list of normal user, serviceaccount, or group that this rule cares about. There must be at least one member in this slice. A slice that includes both the system:authenticated and system:unauthenticated user groups matches every request. Required. - :param non_resource_rules: ``nonResourceRules`` is a list of NonResourcePolicyRules that identify matching requests according to their verb and the target non-resource URL. - :param resource_rules: ``resourceRules`` is a slice of ResourcePolicyRules that identify matching requests according to their verb and the target resource. At least one of ``resourceRules`` and ``nonResourceRules`` has to be non-empty. - - :schema: io.k8s.api.flowcontrol.v1beta3.PolicyRulesWithSubjects - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__d696363024826d8d1400b937d2aa6b61b3eaaa59024841f169586f09d8fa40dd) - check_type(argname="argument subjects", value=subjects, expected_type=type_hints["subjects"]) - check_type(argname="argument non_resource_rules", value=non_resource_rules, expected_type=type_hints["non_resource_rules"]) - check_type(argname="argument resource_rules", value=resource_rules, expected_type=type_hints["resource_rules"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "subjects": subjects, - } - if non_resource_rules is not None: - self._values["non_resource_rules"] = non_resource_rules - if resource_rules is not None: - self._values["resource_rules"] = resource_rules - - @builtins.property - def subjects(self) -> typing.List["SubjectV1Beta3"]: - '''subjects is the list of normal user, serviceaccount, or group that this rule cares about. - - There must be at least one member in this slice. A slice that includes both the system:authenticated and system:unauthenticated user groups matches every request. Required. - - :schema: io.k8s.api.flowcontrol.v1beta3.PolicyRulesWithSubjects#subjects - ''' - result = self._values.get("subjects") - assert result is not None, "Required property 'subjects' is missing" - return typing.cast(typing.List["SubjectV1Beta3"], result) - - @builtins.property - def non_resource_rules( - self, - ) -> typing.Optional[typing.List[NonResourcePolicyRuleV1Beta3]]: - '''``nonResourceRules`` is a list of NonResourcePolicyRules that identify matching requests according to their verb and the target non-resource URL. - - :schema: io.k8s.api.flowcontrol.v1beta3.PolicyRulesWithSubjects#nonResourceRules - ''' - result = self._values.get("non_resource_rules") - return typing.cast(typing.Optional[typing.List[NonResourcePolicyRuleV1Beta3]], result) - - @builtins.property - def resource_rules( - self, - ) -> typing.Optional[typing.List["ResourcePolicyRuleV1Beta3"]]: - '''``resourceRules`` is a slice of ResourcePolicyRules that identify matching requests according to their verb and the target resource. - - At least one of ``resourceRules`` and ``nonResourceRules`` has to be non-empty. - - :schema: io.k8s.api.flowcontrol.v1beta3.PolicyRulesWithSubjects#resourceRules - ''' - result = self._values.get("resource_rules") - return typing.cast(typing.Optional[typing.List["ResourcePolicyRuleV1Beta3"]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "PolicyRulesWithSubjectsV1Beta3(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.PortworxVolumeSource", - jsii_struct_bases=[], - name_mapping={ - "volume_id": "volumeId", - "fs_type": "fsType", - "read_only": "readOnly", - }, -) -class PortworxVolumeSource: - def __init__( - self, - *, - volume_id: builtins.str, - fs_type: typing.Optional[builtins.str] = None, - read_only: typing.Optional[builtins.bool] = None, - ) -> None: - '''PortworxVolumeSource represents a Portworx volume resource. - - :param volume_id: volumeID uniquely identifies a Portworx volume. - :param fs_type: fSType represents the filesystem type to mount Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs". Implicitly inferred to be "ext4" if unspecified. - :param read_only: readOnly defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. - - :schema: io.k8s.api.core.v1.PortworxVolumeSource - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__e5881c74274a6e5dc2a25e69584d9a7a08eda9f51afd4f560f3731ae800319a9) - check_type(argname="argument volume_id", value=volume_id, expected_type=type_hints["volume_id"]) - check_type(argname="argument fs_type", value=fs_type, expected_type=type_hints["fs_type"]) - check_type(argname="argument read_only", value=read_only, expected_type=type_hints["read_only"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "volume_id": volume_id, - } - if fs_type is not None: - self._values["fs_type"] = fs_type - if read_only is not None: - self._values["read_only"] = read_only - - @builtins.property - def volume_id(self) -> builtins.str: - '''volumeID uniquely identifies a Portworx volume. - - :schema: io.k8s.api.core.v1.PortworxVolumeSource#volumeID - ''' - result = self._values.get("volume_id") - assert result is not None, "Required property 'volume_id' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def fs_type(self) -> typing.Optional[builtins.str]: - '''fSType represents the filesystem type to mount Must be a filesystem type supported by the host operating system. - - Ex. "ext4", "xfs". Implicitly inferred to be "ext4" if unspecified. - - :schema: io.k8s.api.core.v1.PortworxVolumeSource#fsType - ''' - result = self._values.get("fs_type") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def read_only(self) -> typing.Optional[builtins.bool]: - '''readOnly defaults to false (read/write). - - ReadOnly here will force the ReadOnly setting in VolumeMounts. - - :schema: io.k8s.api.core.v1.PortworxVolumeSource#readOnly - ''' - result = self._values.get("read_only") - return typing.cast(typing.Optional[builtins.bool], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "PortworxVolumeSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.Preconditions", - jsii_struct_bases=[], - name_mapping={"resource_version": "resourceVersion", "uid": "uid"}, -) -class Preconditions: - def __init__( - self, - *, - resource_version: typing.Optional[builtins.str] = None, - uid: typing.Optional[builtins.str] = None, - ) -> None: - '''Preconditions must be fulfilled before an operation (update, delete, etc.) is carried out. - - :param resource_version: Specifies the target ResourceVersion. - :param uid: Specifies the target UID. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.Preconditions - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__5d83cea33916e66ca6553e6bdfe2c022d25c2d9b0d13a46f323bef2db497363e) - check_type(argname="argument resource_version", value=resource_version, expected_type=type_hints["resource_version"]) - check_type(argname="argument uid", value=uid, expected_type=type_hints["uid"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if resource_version is not None: - self._values["resource_version"] = resource_version - if uid is not None: - self._values["uid"] = uid - - @builtins.property - def resource_version(self) -> typing.Optional[builtins.str]: - '''Specifies the target ResourceVersion. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.Preconditions#resourceVersion - ''' - result = self._values.get("resource_version") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def uid(self) -> typing.Optional[builtins.str]: - '''Specifies the target UID. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.Preconditions#uid - ''' - result = self._values.get("uid") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "Preconditions(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.PreferredSchedulingTerm", - jsii_struct_bases=[], - name_mapping={"preference": "preference", "weight": "weight"}, -) -class PreferredSchedulingTerm: - def __init__( - self, - *, - preference: typing.Union[NodeSelectorTerm, typing.Dict[builtins.str, typing.Any]], - weight: jsii.Number, - ) -> None: - '''An empty preferred scheduling term matches all objects with implicit weight 0 (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). - - :param preference: A node selector term, associated with the corresponding weight. - :param weight: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. - - :schema: io.k8s.api.core.v1.PreferredSchedulingTerm - ''' - if isinstance(preference, dict): - preference = NodeSelectorTerm(**preference) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__4778017af685ac589aca31cd5f8aed67ddd4b8d050f99423b40b402a8758f9df) - check_type(argname="argument preference", value=preference, expected_type=type_hints["preference"]) - check_type(argname="argument weight", value=weight, expected_type=type_hints["weight"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "preference": preference, - "weight": weight, - } - - @builtins.property - def preference(self) -> NodeSelectorTerm: - '''A node selector term, associated with the corresponding weight. - - :schema: io.k8s.api.core.v1.PreferredSchedulingTerm#preference - ''' - result = self._values.get("preference") - assert result is not None, "Required property 'preference' is missing" - return typing.cast(NodeSelectorTerm, result) - - @builtins.property - def weight(self) -> jsii.Number: - '''Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. - - :schema: io.k8s.api.core.v1.PreferredSchedulingTerm#weight - ''' - result = self._values.get("weight") - assert result is not None, "Required property 'weight' is missing" - return typing.cast(jsii.Number, result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "PreferredSchedulingTerm(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.PriorityLevelConfigurationReferenceV1Beta2", - jsii_struct_bases=[], - name_mapping={"name": "name"}, -) -class PriorityLevelConfigurationReferenceV1Beta2: - def __init__(self, *, name: builtins.str) -> None: - '''PriorityLevelConfigurationReference contains information that points to the "request-priority" being used. - - :param name: ``name`` is the name of the priority level configuration being referenced Required. - - :schema: io.k8s.api.flowcontrol.v1beta2.PriorityLevelConfigurationReference - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__76bd97c74c99efa5169495b9849f8685fb180d45e0f29dbce62f0fe15e286f13) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "name": name, - } - - @builtins.property - def name(self) -> builtins.str: - '''``name`` is the name of the priority level configuration being referenced Required. - - :schema: io.k8s.api.flowcontrol.v1beta2.PriorityLevelConfigurationReference#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "PriorityLevelConfigurationReferenceV1Beta2(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.PriorityLevelConfigurationReferenceV1Beta3", - jsii_struct_bases=[], - name_mapping={"name": "name"}, -) -class PriorityLevelConfigurationReferenceV1Beta3: - def __init__(self, *, name: builtins.str) -> None: - '''PriorityLevelConfigurationReference contains information that points to the "request-priority" being used. - - :param name: ``name`` is the name of the priority level configuration being referenced Required. - - :schema: io.k8s.api.flowcontrol.v1beta3.PriorityLevelConfigurationReference - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__9a0146b969cc8a7d1c0ff18cf7d2f32e995d6c975b94478b11b395aca5759667) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "name": name, - } - - @builtins.property - def name(self) -> builtins.str: - '''``name`` is the name of the priority level configuration being referenced Required. - - :schema: io.k8s.api.flowcontrol.v1beta3.PriorityLevelConfigurationReference#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "PriorityLevelConfigurationReferenceV1Beta3(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.PriorityLevelConfigurationSpecV1Beta2", - jsii_struct_bases=[], - name_mapping={"type": "type", "limited": "limited"}, -) -class PriorityLevelConfigurationSpecV1Beta2: - def __init__( - self, - *, - type: builtins.str, - limited: typing.Optional[typing.Union[LimitedPriorityLevelConfigurationV1Beta2, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''PriorityLevelConfigurationSpec specifies the configuration of a priority level. - - :param type: ``type`` indicates whether this priority level is subject to limitation on request execution. A value of ``"Exempt"`` means that requests of this priority level are not subject to a limit (and thus are never queued) and do not detract from the capacity made available to other priority levels. A value of ``"Limited"`` means that (a) requests of this priority level *are* subject to limits and (b) some of the server's limited capacity is made available exclusively to this priority level. Required. - :param limited: ``limited`` specifies how requests are handled for a Limited priority level. This field must be non-empty if and only if ``type`` is ``"Limited"``. - - :schema: io.k8s.api.flowcontrol.v1beta2.PriorityLevelConfigurationSpec - ''' - if isinstance(limited, dict): - limited = LimitedPriorityLevelConfigurationV1Beta2(**limited) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__94bca280ba8f7fad3c10c340b8cf6039d7a0f6cbd700ea283a8eeb4f1a9bdaad) - check_type(argname="argument type", value=type, expected_type=type_hints["type"]) - check_type(argname="argument limited", value=limited, expected_type=type_hints["limited"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "type": type, - } - if limited is not None: - self._values["limited"] = limited - - @builtins.property - def type(self) -> builtins.str: - '''``type`` indicates whether this priority level is subject to limitation on request execution. - - A value of ``"Exempt"`` means that requests of this priority level are not subject to a limit (and thus are never queued) and do not detract from the capacity made available to other priority levels. A value of ``"Limited"`` means that (a) requests of this priority level *are* subject to limits and (b) some of the server's limited capacity is made available exclusively to this priority level. Required. - - :schema: io.k8s.api.flowcontrol.v1beta2.PriorityLevelConfigurationSpec#type - ''' - result = self._values.get("type") - assert result is not None, "Required property 'type' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def limited(self) -> typing.Optional[LimitedPriorityLevelConfigurationV1Beta2]: - '''``limited`` specifies how requests are handled for a Limited priority level. - - This field must be non-empty if and only if ``type`` is ``"Limited"``. - - :schema: io.k8s.api.flowcontrol.v1beta2.PriorityLevelConfigurationSpec#limited - ''' - result = self._values.get("limited") - return typing.cast(typing.Optional[LimitedPriorityLevelConfigurationV1Beta2], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "PriorityLevelConfigurationSpecV1Beta2(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.PriorityLevelConfigurationSpecV1Beta3", - jsii_struct_bases=[], - name_mapping={"type": "type", "limited": "limited"}, -) -class PriorityLevelConfigurationSpecV1Beta3: - def __init__( - self, - *, - type: builtins.str, - limited: typing.Optional[typing.Union[LimitedPriorityLevelConfigurationV1Beta3, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''PriorityLevelConfigurationSpec specifies the configuration of a priority level. - - :param type: ``type`` indicates whether this priority level is subject to limitation on request execution. A value of ``"Exempt"`` means that requests of this priority level are not subject to a limit (and thus are never queued) and do not detract from the capacity made available to other priority levels. A value of ``"Limited"`` means that (a) requests of this priority level *are* subject to limits and (b) some of the server's limited capacity is made available exclusively to this priority level. Required. - :param limited: ``limited`` specifies how requests are handled for a Limited priority level. This field must be non-empty if and only if ``type`` is ``"Limited"``. - - :schema: io.k8s.api.flowcontrol.v1beta3.PriorityLevelConfigurationSpec - ''' - if isinstance(limited, dict): - limited = LimitedPriorityLevelConfigurationV1Beta3(**limited) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__c30b61d9bf19716fdc32867c5d90748be48b5c7c3c858ba8b5c867223594eb77) - check_type(argname="argument type", value=type, expected_type=type_hints["type"]) - check_type(argname="argument limited", value=limited, expected_type=type_hints["limited"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "type": type, - } - if limited is not None: - self._values["limited"] = limited - - @builtins.property - def type(self) -> builtins.str: - '''``type`` indicates whether this priority level is subject to limitation on request execution. - - A value of ``"Exempt"`` means that requests of this priority level are not subject to a limit (and thus are never queued) and do not detract from the capacity made available to other priority levels. A value of ``"Limited"`` means that (a) requests of this priority level *are* subject to limits and (b) some of the server's limited capacity is made available exclusively to this priority level. Required. - - :schema: io.k8s.api.flowcontrol.v1beta3.PriorityLevelConfigurationSpec#type - ''' - result = self._values.get("type") - assert result is not None, "Required property 'type' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def limited(self) -> typing.Optional[LimitedPriorityLevelConfigurationV1Beta3]: - '''``limited`` specifies how requests are handled for a Limited priority level. - - This field must be non-empty if and only if ``type`` is ``"Limited"``. - - :schema: io.k8s.api.flowcontrol.v1beta3.PriorityLevelConfigurationSpec#limited - ''' - result = self._values.get("limited") - return typing.cast(typing.Optional[LimitedPriorityLevelConfigurationV1Beta3], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "PriorityLevelConfigurationSpecV1Beta3(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.Probe", - jsii_struct_bases=[], - name_mapping={ - "exec": "exec", - "failure_threshold": "failureThreshold", - "grpc": "grpc", - "http_get": "httpGet", - "initial_delay_seconds": "initialDelaySeconds", - "period_seconds": "periodSeconds", - "success_threshold": "successThreshold", - "tcp_socket": "tcpSocket", - "termination_grace_period_seconds": "terminationGracePeriodSeconds", - "timeout_seconds": "timeoutSeconds", - }, -) -class Probe: - def __init__( - self, - *, - exec: typing.Optional[typing.Union[ExecAction, typing.Dict[builtins.str, typing.Any]]] = None, - failure_threshold: typing.Optional[jsii.Number] = None, - grpc: typing.Optional[typing.Union[GrpcAction, typing.Dict[builtins.str, typing.Any]]] = None, - http_get: typing.Optional[typing.Union[HttpGetAction, typing.Dict[builtins.str, typing.Any]]] = None, - initial_delay_seconds: typing.Optional[jsii.Number] = None, - period_seconds: typing.Optional[jsii.Number] = None, - success_threshold: typing.Optional[jsii.Number] = None, - tcp_socket: typing.Optional[typing.Union["TcpSocketAction", typing.Dict[builtins.str, typing.Any]]] = None, - termination_grace_period_seconds: typing.Optional[jsii.Number] = None, - timeout_seconds: typing.Optional[jsii.Number] = None, - ) -> None: - '''Probe describes a health check to be performed against a container to determine whether it is alive or ready to receive traffic. - - :param exec: Exec specifies the action to take. - :param failure_threshold: Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3. Minimum value is 1. Default: 3. Minimum value is 1. - :param grpc: GRPC specifies an action involving a GRPC port. This is a beta field and requires enabling GRPCContainerProbe feature gate. - :param http_get: HTTPGet specifies the http request to perform. - :param initial_delay_seconds: Number of seconds after the container has started before liveness probes are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - :param period_seconds: How often (in seconds) to perform the probe. Default to 10 seconds. Minimum value is 1. Default: 10 seconds. Minimum value is 1. - :param success_threshold: Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. Default: 1. Must be 1 for liveness and startup. Minimum value is 1. - :param tcp_socket: TCPSocket specifies an action involving a TCP port. - :param termination_grace_period_seconds: Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. - :param timeout_seconds: Number of seconds after which the probe times out. Defaults to 1 second. Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes Default: 1 second. Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - - :schema: io.k8s.api.core.v1.Probe - ''' - if isinstance(exec, dict): - exec = ExecAction(**exec) - if isinstance(grpc, dict): - grpc = GrpcAction(**grpc) - if isinstance(http_get, dict): - http_get = HttpGetAction(**http_get) - if isinstance(tcp_socket, dict): - tcp_socket = TcpSocketAction(**tcp_socket) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__db09437a4be3e51aba0181b1494c0c550aa4867813268b893ac716f115fa48c1) - check_type(argname="argument exec", value=exec, expected_type=type_hints["exec"]) - check_type(argname="argument failure_threshold", value=failure_threshold, expected_type=type_hints["failure_threshold"]) - check_type(argname="argument grpc", value=grpc, expected_type=type_hints["grpc"]) - check_type(argname="argument http_get", value=http_get, expected_type=type_hints["http_get"]) - check_type(argname="argument initial_delay_seconds", value=initial_delay_seconds, expected_type=type_hints["initial_delay_seconds"]) - check_type(argname="argument period_seconds", value=period_seconds, expected_type=type_hints["period_seconds"]) - check_type(argname="argument success_threshold", value=success_threshold, expected_type=type_hints["success_threshold"]) - check_type(argname="argument tcp_socket", value=tcp_socket, expected_type=type_hints["tcp_socket"]) - check_type(argname="argument termination_grace_period_seconds", value=termination_grace_period_seconds, expected_type=type_hints["termination_grace_period_seconds"]) - check_type(argname="argument timeout_seconds", value=timeout_seconds, expected_type=type_hints["timeout_seconds"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if exec is not None: - self._values["exec"] = exec - if failure_threshold is not None: - self._values["failure_threshold"] = failure_threshold - if grpc is not None: - self._values["grpc"] = grpc - if http_get is not None: - self._values["http_get"] = http_get - if initial_delay_seconds is not None: - self._values["initial_delay_seconds"] = initial_delay_seconds - if period_seconds is not None: - self._values["period_seconds"] = period_seconds - if success_threshold is not None: - self._values["success_threshold"] = success_threshold - if tcp_socket is not None: - self._values["tcp_socket"] = tcp_socket - if termination_grace_period_seconds is not None: - self._values["termination_grace_period_seconds"] = termination_grace_period_seconds - if timeout_seconds is not None: - self._values["timeout_seconds"] = timeout_seconds - - @builtins.property - def exec(self) -> typing.Optional[ExecAction]: - '''Exec specifies the action to take. - - :schema: io.k8s.api.core.v1.Probe#exec - ''' - result = self._values.get("exec") - return typing.cast(typing.Optional[ExecAction], result) - - @builtins.property - def failure_threshold(self) -> typing.Optional[jsii.Number]: - '''Minimum consecutive failures for the probe to be considered failed after having succeeded. - - Defaults to 3. Minimum value is 1. - - :default: 3. Minimum value is 1. - - :schema: io.k8s.api.core.v1.Probe#failureThreshold - ''' - result = self._values.get("failure_threshold") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def grpc(self) -> typing.Optional[GrpcAction]: - '''GRPC specifies an action involving a GRPC port. - - This is a beta field and requires enabling GRPCContainerProbe feature gate. - - :schema: io.k8s.api.core.v1.Probe#grpc - ''' - result = self._values.get("grpc") - return typing.cast(typing.Optional[GrpcAction], result) - - @builtins.property - def http_get(self) -> typing.Optional[HttpGetAction]: - '''HTTPGet specifies the http request to perform. - - :schema: io.k8s.api.core.v1.Probe#httpGet - ''' - result = self._values.get("http_get") - return typing.cast(typing.Optional[HttpGetAction], result) - - @builtins.property - def initial_delay_seconds(self) -> typing.Optional[jsii.Number]: - '''Number of seconds after the container has started before liveness probes are initiated. - - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - - :schema: io.k8s.api.core.v1.Probe#initialDelaySeconds - ''' - result = self._values.get("initial_delay_seconds") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def period_seconds(self) -> typing.Optional[jsii.Number]: - '''How often (in seconds) to perform the probe. - - Default to 10 seconds. Minimum value is 1. - - :default: 10 seconds. Minimum value is 1. - - :schema: io.k8s.api.core.v1.Probe#periodSeconds - ''' - result = self._values.get("period_seconds") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def success_threshold(self) -> typing.Optional[jsii.Number]: - '''Minimum consecutive successes for the probe to be considered successful after having failed. - - Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. - - :default: 1. Must be 1 for liveness and startup. Minimum value is 1. - - :schema: io.k8s.api.core.v1.Probe#successThreshold - ''' - result = self._values.get("success_threshold") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def tcp_socket(self) -> typing.Optional["TcpSocketAction"]: - '''TCPSocket specifies an action involving a TCP port. - - :schema: io.k8s.api.core.v1.Probe#tcpSocket - ''' - result = self._values.get("tcp_socket") - return typing.cast(typing.Optional["TcpSocketAction"], result) - - @builtins.property - def termination_grace_period_seconds(self) -> typing.Optional[jsii.Number]: - '''Optional duration in seconds the pod needs to terminate gracefully upon probe failure. - - The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. - - :schema: io.k8s.api.core.v1.Probe#terminationGracePeriodSeconds - ''' - result = self._values.get("termination_grace_period_seconds") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def timeout_seconds(self) -> typing.Optional[jsii.Number]: - '''Number of seconds after which the probe times out. - - Defaults to 1 second. Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - - :default: 1 second. Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - - :schema: io.k8s.api.core.v1.Probe#timeoutSeconds - ''' - result = self._values.get("timeout_seconds") - return typing.cast(typing.Optional[jsii.Number], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "Probe(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ProjectedVolumeSource", - jsii_struct_bases=[], - name_mapping={"default_mode": "defaultMode", "sources": "sources"}, -) -class ProjectedVolumeSource: - def __init__( - self, - *, - default_mode: typing.Optional[jsii.Number] = None, - sources: typing.Optional[typing.Sequence[typing.Union["VolumeProjection", typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''Represents a projected volume source. - - :param default_mode: defaultMode are the mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set. - :param sources: sources is the list of volume projections. - - :schema: io.k8s.api.core.v1.ProjectedVolumeSource - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__7074d18926a011b639c0d0e74c2a29fc486086a8992a0ccda6c888fe8065ce84) - check_type(argname="argument default_mode", value=default_mode, expected_type=type_hints["default_mode"]) - check_type(argname="argument sources", value=sources, expected_type=type_hints["sources"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if default_mode is not None: - self._values["default_mode"] = default_mode - if sources is not None: - self._values["sources"] = sources - - @builtins.property - def default_mode(self) -> typing.Optional[jsii.Number]: - '''defaultMode are the mode bits used to set permissions on created files by default. - - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set. - - :schema: io.k8s.api.core.v1.ProjectedVolumeSource#defaultMode - ''' - result = self._values.get("default_mode") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def sources(self) -> typing.Optional[typing.List["VolumeProjection"]]: - '''sources is the list of volume projections. - - :schema: io.k8s.api.core.v1.ProjectedVolumeSource#sources - ''' - result = self._values.get("sources") - return typing.cast(typing.Optional[typing.List["VolumeProjection"]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ProjectedVolumeSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -class Quantity(metaclass=jsii.JSIIMeta, jsii_type="k8s.Quantity"): - ''' - :schema: io.k8s.apimachinery.pkg.api.resource.Quantity - ''' - - @jsii.member(jsii_name="fromNumber") - @builtins.classmethod - def from_number(cls, value: jsii.Number) -> "Quantity": - ''' - :param value: - - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__5424c0bd9afaecc70d51e745b052a4e736b88cf285925889028bab8d3cfb8fee) - check_type(argname="argument value", value=value, expected_type=type_hints["value"]) - return typing.cast("Quantity", jsii.sinvoke(cls, "fromNumber", [value])) - - @jsii.member(jsii_name="fromString") - @builtins.classmethod - def from_string(cls, value: builtins.str) -> "Quantity": - ''' - :param value: - - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__abf2ed361dde0b07fa7185d50da371e8631fdccf28cb302e7e5d62f671a79d9a) - check_type(argname="argument value", value=value, expected_type=type_hints["value"]) - return typing.cast("Quantity", jsii.sinvoke(cls, "fromString", [value])) - - @builtins.property - @jsii.member(jsii_name="value") - def value(self) -> typing.Union[builtins.str, jsii.Number]: - return typing.cast(typing.Union[builtins.str, jsii.Number], jsii.get(self, "value")) - - -@jsii.data_type( - jsii_type="k8s.QueuingConfigurationV1Beta2", - jsii_struct_bases=[], - name_mapping={ - "hand_size": "handSize", - "queue_length_limit": "queueLengthLimit", - "queues": "queues", - }, -) -class QueuingConfigurationV1Beta2: - def __init__( - self, - *, - hand_size: typing.Optional[jsii.Number] = None, - queue_length_limit: typing.Optional[jsii.Number] = None, - queues: typing.Optional[jsii.Number] = None, - ) -> None: - '''QueuingConfiguration holds the configuration parameters for queuing. - - :param hand_size: ``handSize`` is a small positive number that configures the shuffle sharding of requests into queues. When enqueuing a request at this priority level the request's flow identifier (a string pair) is hashed and the hash value is used to shuffle the list of queues and deal a hand of the size specified here. The request is put into one of the shortest queues in that hand. ``handSize`` must be no larger than ``queues``, and should be significantly smaller (so that a few heavy flows do not saturate most of the queues). See the user-facing documentation for more extensive guidance on setting this field. This field has a default value of 8. - :param queue_length_limit: ``queueLengthLimit`` is the maximum number of requests allowed to be waiting in a given queue of this priority level at a time; excess requests are rejected. This value must be positive. If not specified, it will be defaulted to 50. - :param queues: ``queues`` is the number of queues for this priority level. The queues exist independently at each apiserver. The value must be positive. Setting it to 1 effectively precludes shufflesharding and thus makes the distinguisher method of associated flow schemas irrelevant. This field has a default value of 64. - - :schema: io.k8s.api.flowcontrol.v1beta2.QueuingConfiguration - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__8d5a34c8cf9c81ed2f5b31625c4cec39f9cc1c5c9d4fb1cd5b7c4ea13cbfecda) - check_type(argname="argument hand_size", value=hand_size, expected_type=type_hints["hand_size"]) - check_type(argname="argument queue_length_limit", value=queue_length_limit, expected_type=type_hints["queue_length_limit"]) - check_type(argname="argument queues", value=queues, expected_type=type_hints["queues"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if hand_size is not None: - self._values["hand_size"] = hand_size - if queue_length_limit is not None: - self._values["queue_length_limit"] = queue_length_limit - if queues is not None: - self._values["queues"] = queues - - @builtins.property - def hand_size(self) -> typing.Optional[jsii.Number]: - '''``handSize`` is a small positive number that configures the shuffle sharding of requests into queues. - - When enqueuing a request at this priority level the request's flow identifier (a string pair) is hashed and the hash value is used to shuffle the list of queues and deal a hand of the size specified here. The request is put into one of the shortest queues in that hand. ``handSize`` must be no larger than ``queues``, and should be significantly smaller (so that a few heavy flows do not saturate most of the queues). See the user-facing documentation for more extensive guidance on setting this field. This field has a default value of 8. - - :schema: io.k8s.api.flowcontrol.v1beta2.QueuingConfiguration#handSize - ''' - result = self._values.get("hand_size") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def queue_length_limit(self) -> typing.Optional[jsii.Number]: - '''``queueLengthLimit`` is the maximum number of requests allowed to be waiting in a given queue of this priority level at a time; - - excess requests are rejected. This value must be positive. If not specified, it will be defaulted to 50. - - :schema: io.k8s.api.flowcontrol.v1beta2.QueuingConfiguration#queueLengthLimit - ''' - result = self._values.get("queue_length_limit") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def queues(self) -> typing.Optional[jsii.Number]: - '''``queues`` is the number of queues for this priority level. - - The queues exist independently at each apiserver. The value must be positive. Setting it to 1 effectively precludes shufflesharding and thus makes the distinguisher method of associated flow schemas irrelevant. This field has a default value of 64. - - :schema: io.k8s.api.flowcontrol.v1beta2.QueuingConfiguration#queues - ''' - result = self._values.get("queues") - return typing.cast(typing.Optional[jsii.Number], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "QueuingConfigurationV1Beta2(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.QueuingConfigurationV1Beta3", - jsii_struct_bases=[], - name_mapping={ - "hand_size": "handSize", - "queue_length_limit": "queueLengthLimit", - "queues": "queues", - }, -) -class QueuingConfigurationV1Beta3: - def __init__( - self, - *, - hand_size: typing.Optional[jsii.Number] = None, - queue_length_limit: typing.Optional[jsii.Number] = None, - queues: typing.Optional[jsii.Number] = None, - ) -> None: - '''QueuingConfiguration holds the configuration parameters for queuing. - - :param hand_size: ``handSize`` is a small positive number that configures the shuffle sharding of requests into queues. When enqueuing a request at this priority level the request's flow identifier (a string pair) is hashed and the hash value is used to shuffle the list of queues and deal a hand of the size specified here. The request is put into one of the shortest queues in that hand. ``handSize`` must be no larger than ``queues``, and should be significantly smaller (so that a few heavy flows do not saturate most of the queues). See the user-facing documentation for more extensive guidance on setting this field. This field has a default value of 8. - :param queue_length_limit: ``queueLengthLimit`` is the maximum number of requests allowed to be waiting in a given queue of this priority level at a time; excess requests are rejected. This value must be positive. If not specified, it will be defaulted to 50. - :param queues: ``queues`` is the number of queues for this priority level. The queues exist independently at each apiserver. The value must be positive. Setting it to 1 effectively precludes shufflesharding and thus makes the distinguisher method of associated flow schemas irrelevant. This field has a default value of 64. - - :schema: io.k8s.api.flowcontrol.v1beta3.QueuingConfiguration - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__a1037b25a0b4c030cbae5567cfd92e97afe9e0798778e912b05229e9373472d1) - check_type(argname="argument hand_size", value=hand_size, expected_type=type_hints["hand_size"]) - check_type(argname="argument queue_length_limit", value=queue_length_limit, expected_type=type_hints["queue_length_limit"]) - check_type(argname="argument queues", value=queues, expected_type=type_hints["queues"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if hand_size is not None: - self._values["hand_size"] = hand_size - if queue_length_limit is not None: - self._values["queue_length_limit"] = queue_length_limit - if queues is not None: - self._values["queues"] = queues - - @builtins.property - def hand_size(self) -> typing.Optional[jsii.Number]: - '''``handSize`` is a small positive number that configures the shuffle sharding of requests into queues. - - When enqueuing a request at this priority level the request's flow identifier (a string pair) is hashed and the hash value is used to shuffle the list of queues and deal a hand of the size specified here. The request is put into one of the shortest queues in that hand. ``handSize`` must be no larger than ``queues``, and should be significantly smaller (so that a few heavy flows do not saturate most of the queues). See the user-facing documentation for more extensive guidance on setting this field. This field has a default value of 8. - - :schema: io.k8s.api.flowcontrol.v1beta3.QueuingConfiguration#handSize - ''' - result = self._values.get("hand_size") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def queue_length_limit(self) -> typing.Optional[jsii.Number]: - '''``queueLengthLimit`` is the maximum number of requests allowed to be waiting in a given queue of this priority level at a time; - - excess requests are rejected. This value must be positive. If not specified, it will be defaulted to 50. - - :schema: io.k8s.api.flowcontrol.v1beta3.QueuingConfiguration#queueLengthLimit - ''' - result = self._values.get("queue_length_limit") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def queues(self) -> typing.Optional[jsii.Number]: - '''``queues`` is the number of queues for this priority level. - - The queues exist independently at each apiserver. The value must be positive. Setting it to 1 effectively precludes shufflesharding and thus makes the distinguisher method of associated flow schemas irrelevant. This field has a default value of 64. - - :schema: io.k8s.api.flowcontrol.v1beta3.QueuingConfiguration#queues - ''' - result = self._values.get("queues") - return typing.cast(typing.Optional[jsii.Number], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "QueuingConfigurationV1Beta3(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.QuobyteVolumeSource", - jsii_struct_bases=[], - name_mapping={ - "registry": "registry", - "volume": "volume", - "group": "group", - "read_only": "readOnly", - "tenant": "tenant", - "user": "user", - }, -) -class QuobyteVolumeSource: - def __init__( - self, - *, - registry: builtins.str, - volume: builtins.str, - group: typing.Optional[builtins.str] = None, - read_only: typing.Optional[builtins.bool] = None, - tenant: typing.Optional[builtins.str] = None, - user: typing.Optional[builtins.str] = None, - ) -> None: - '''Represents a Quobyte mount that lasts the lifetime of a pod. - - Quobyte volumes do not support ownership management or SELinux relabeling. - - :param registry: registry represents a single or multiple Quobyte Registry services specified as a string as host:port pair (multiple entries are separated with commas) which acts as the central registry for volumes. - :param volume: volume is a string that references an already created Quobyte volume by name. - :param group: group to map volume access to Default is no group. Default: no group - :param read_only: readOnly here will force the Quobyte volume to be mounted with read-only permissions. Defaults to false. Default: false. - :param tenant: tenant owning the given Quobyte volume in the Backend Used with dynamically provisioned Quobyte volumes, value is set by the plugin. - :param user: user to map volume access to Defaults to serivceaccount user. Default: serivceaccount user - - :schema: io.k8s.api.core.v1.QuobyteVolumeSource - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__06c16a4eef69abcb24206e80e63cd1b95acadcfeb11e968c6e6938adf8d6afba) - check_type(argname="argument registry", value=registry, expected_type=type_hints["registry"]) - check_type(argname="argument volume", value=volume, expected_type=type_hints["volume"]) - check_type(argname="argument group", value=group, expected_type=type_hints["group"]) - check_type(argname="argument read_only", value=read_only, expected_type=type_hints["read_only"]) - check_type(argname="argument tenant", value=tenant, expected_type=type_hints["tenant"]) - check_type(argname="argument user", value=user, expected_type=type_hints["user"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "registry": registry, - "volume": volume, - } - if group is not None: - self._values["group"] = group - if read_only is not None: - self._values["read_only"] = read_only - if tenant is not None: - self._values["tenant"] = tenant - if user is not None: - self._values["user"] = user - - @builtins.property - def registry(self) -> builtins.str: - '''registry represents a single or multiple Quobyte Registry services specified as a string as host:port pair (multiple entries are separated with commas) which acts as the central registry for volumes. - - :schema: io.k8s.api.core.v1.QuobyteVolumeSource#registry - ''' - result = self._values.get("registry") - assert result is not None, "Required property 'registry' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def volume(self) -> builtins.str: - '''volume is a string that references an already created Quobyte volume by name. - - :schema: io.k8s.api.core.v1.QuobyteVolumeSource#volume - ''' - result = self._values.get("volume") - assert result is not None, "Required property 'volume' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def group(self) -> typing.Optional[builtins.str]: - '''group to map volume access to Default is no group. - - :default: no group - - :schema: io.k8s.api.core.v1.QuobyteVolumeSource#group - ''' - result = self._values.get("group") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def read_only(self) -> typing.Optional[builtins.bool]: - '''readOnly here will force the Quobyte volume to be mounted with read-only permissions. - - Defaults to false. - - :default: false. - - :schema: io.k8s.api.core.v1.QuobyteVolumeSource#readOnly - ''' - result = self._values.get("read_only") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def tenant(self) -> typing.Optional[builtins.str]: - '''tenant owning the given Quobyte volume in the Backend Used with dynamically provisioned Quobyte volumes, value is set by the plugin. - - :schema: io.k8s.api.core.v1.QuobyteVolumeSource#tenant - ''' - result = self._values.get("tenant") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def user(self) -> typing.Optional[builtins.str]: - '''user to map volume access to Defaults to serivceaccount user. - - :default: serivceaccount user - - :schema: io.k8s.api.core.v1.QuobyteVolumeSource#user - ''' - result = self._values.get("user") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "QuobyteVolumeSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.RbdPersistentVolumeSource", - jsii_struct_bases=[], - name_mapping={ - "image": "image", - "monitors": "monitors", - "fs_type": "fsType", - "keyring": "keyring", - "pool": "pool", - "read_only": "readOnly", - "secret_ref": "secretRef", - "user": "user", - }, -) -class RbdPersistentVolumeSource: - def __init__( - self, - *, - image: builtins.str, - monitors: typing.Sequence[builtins.str], - fs_type: typing.Optional[builtins.str] = None, - keyring: typing.Optional[builtins.str] = None, - pool: typing.Optional[builtins.str] = None, - read_only: typing.Optional[builtins.bool] = None, - secret_ref: typing.Optional[typing.Union["SecretReference", typing.Dict[builtins.str, typing.Any]]] = None, - user: typing.Optional[builtins.str] = None, - ) -> None: - '''Represents a Rados Block Device mount that lasts the lifetime of a pod. - - RBD volumes support ownership management and SELinux relabeling. - - :param image: image is the rados image name. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - :param monitors: monitors is a collection of Ceph monitors. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - :param fs_type: fsType is the filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd - :param keyring: keyring is the path to key ring for RBDUser. Default is /etc/ceph/keyring. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it Default: etc/ceph/keyring. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - :param pool: pool is the rados pool name. Default is rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it Default: rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - :param read_only: readOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it Default: false. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - :param secret_ref: secretRef is name of the authentication secret for RBDUser. If provided overrides keyring. Default is nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it Default: nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - :param user: user is the rados user name. Default is admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it Default: admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - - :schema: io.k8s.api.core.v1.RBDPersistentVolumeSource - ''' - if isinstance(secret_ref, dict): - secret_ref = SecretReference(**secret_ref) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__4f5316d57fc5b5c34025f51982f7e682403dd695b70e08c67fc74cffd5c675fb) - check_type(argname="argument image", value=image, expected_type=type_hints["image"]) - check_type(argname="argument monitors", value=monitors, expected_type=type_hints["monitors"]) - check_type(argname="argument fs_type", value=fs_type, expected_type=type_hints["fs_type"]) - check_type(argname="argument keyring", value=keyring, expected_type=type_hints["keyring"]) - check_type(argname="argument pool", value=pool, expected_type=type_hints["pool"]) - check_type(argname="argument read_only", value=read_only, expected_type=type_hints["read_only"]) - check_type(argname="argument secret_ref", value=secret_ref, expected_type=type_hints["secret_ref"]) - check_type(argname="argument user", value=user, expected_type=type_hints["user"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "image": image, - "monitors": monitors, - } - if fs_type is not None: - self._values["fs_type"] = fs_type - if keyring is not None: - self._values["keyring"] = keyring - if pool is not None: - self._values["pool"] = pool - if read_only is not None: - self._values["read_only"] = read_only - if secret_ref is not None: - self._values["secret_ref"] = secret_ref - if user is not None: - self._values["user"] = user - - @builtins.property - def image(self) -> builtins.str: - '''image is the rados image name. - - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - - :schema: io.k8s.api.core.v1.RBDPersistentVolumeSource#image - ''' - result = self._values.get("image") - assert result is not None, "Required property 'image' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def monitors(self) -> typing.List[builtins.str]: - '''monitors is a collection of Ceph monitors. - - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - - :schema: io.k8s.api.core.v1.RBDPersistentVolumeSource#monitors - ''' - result = self._values.get("monitors") - assert result is not None, "Required property 'monitors' is missing" - return typing.cast(typing.List[builtins.str], result) - - @builtins.property - def fs_type(self) -> typing.Optional[builtins.str]: - '''fsType is the filesystem type of the volume that you want to mount. - - Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd - - :schema: io.k8s.api.core.v1.RBDPersistentVolumeSource#fsType - ''' - result = self._values.get("fs_type") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def keyring(self) -> typing.Optional[builtins.str]: - '''keyring is the path to key ring for RBDUser. - - Default is /etc/ceph/keyring. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - - :default: etc/ceph/keyring. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - - :schema: io.k8s.api.core.v1.RBDPersistentVolumeSource#keyring - ''' - result = self._values.get("keyring") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def pool(self) -> typing.Optional[builtins.str]: - '''pool is the rados pool name. - - Default is rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - - :default: rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - - :schema: io.k8s.api.core.v1.RBDPersistentVolumeSource#pool - ''' - result = self._values.get("pool") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def read_only(self) -> typing.Optional[builtins.bool]: - '''readOnly here will force the ReadOnly setting in VolumeMounts. - - Defaults to false. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - - :default: false. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - - :schema: io.k8s.api.core.v1.RBDPersistentVolumeSource#readOnly - ''' - result = self._values.get("read_only") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def secret_ref(self) -> typing.Optional["SecretReference"]: - '''secretRef is name of the authentication secret for RBDUser. - - If provided overrides keyring. Default is nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - - :default: nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - - :schema: io.k8s.api.core.v1.RBDPersistentVolumeSource#secretRef - ''' - result = self._values.get("secret_ref") - return typing.cast(typing.Optional["SecretReference"], result) - - @builtins.property - def user(self) -> typing.Optional[builtins.str]: - '''user is the rados user name. - - Default is admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - - :default: admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - - :schema: io.k8s.api.core.v1.RBDPersistentVolumeSource#user - ''' - result = self._values.get("user") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "RbdPersistentVolumeSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.RbdVolumeSource", - jsii_struct_bases=[], - name_mapping={ - "image": "image", - "monitors": "monitors", - "fs_type": "fsType", - "keyring": "keyring", - "pool": "pool", - "read_only": "readOnly", - "secret_ref": "secretRef", - "user": "user", - }, -) -class RbdVolumeSource: - def __init__( - self, - *, - image: builtins.str, - monitors: typing.Sequence[builtins.str], - fs_type: typing.Optional[builtins.str] = None, - keyring: typing.Optional[builtins.str] = None, - pool: typing.Optional[builtins.str] = None, - read_only: typing.Optional[builtins.bool] = None, - secret_ref: typing.Optional[typing.Union[LocalObjectReference, typing.Dict[builtins.str, typing.Any]]] = None, - user: typing.Optional[builtins.str] = None, - ) -> None: - '''Represents a Rados Block Device mount that lasts the lifetime of a pod. - - RBD volumes support ownership management and SELinux relabeling. - - :param image: image is the rados image name. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - :param monitors: monitors is a collection of Ceph monitors. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - :param fs_type: fsType is the filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd - :param keyring: keyring is the path to key ring for RBDUser. Default is /etc/ceph/keyring. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it Default: etc/ceph/keyring. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - :param pool: pool is the rados pool name. Default is rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it Default: rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - :param read_only: readOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it Default: false. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - :param secret_ref: secretRef is name of the authentication secret for RBDUser. If provided overrides keyring. Default is nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it Default: nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - :param user: user is the rados user name. Default is admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it Default: admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - - :schema: io.k8s.api.core.v1.RBDVolumeSource - ''' - if isinstance(secret_ref, dict): - secret_ref = LocalObjectReference(**secret_ref) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__b775d6c9c36f825c00349ce924014aaf1d073ef444b854540aaaa1b195f1f2e1) - check_type(argname="argument image", value=image, expected_type=type_hints["image"]) - check_type(argname="argument monitors", value=monitors, expected_type=type_hints["monitors"]) - check_type(argname="argument fs_type", value=fs_type, expected_type=type_hints["fs_type"]) - check_type(argname="argument keyring", value=keyring, expected_type=type_hints["keyring"]) - check_type(argname="argument pool", value=pool, expected_type=type_hints["pool"]) - check_type(argname="argument read_only", value=read_only, expected_type=type_hints["read_only"]) - check_type(argname="argument secret_ref", value=secret_ref, expected_type=type_hints["secret_ref"]) - check_type(argname="argument user", value=user, expected_type=type_hints["user"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "image": image, - "monitors": monitors, - } - if fs_type is not None: - self._values["fs_type"] = fs_type - if keyring is not None: - self._values["keyring"] = keyring - if pool is not None: - self._values["pool"] = pool - if read_only is not None: - self._values["read_only"] = read_only - if secret_ref is not None: - self._values["secret_ref"] = secret_ref - if user is not None: - self._values["user"] = user - - @builtins.property - def image(self) -> builtins.str: - '''image is the rados image name. - - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - - :schema: io.k8s.api.core.v1.RBDVolumeSource#image - ''' - result = self._values.get("image") - assert result is not None, "Required property 'image' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def monitors(self) -> typing.List[builtins.str]: - '''monitors is a collection of Ceph monitors. - - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - - :schema: io.k8s.api.core.v1.RBDVolumeSource#monitors - ''' - result = self._values.get("monitors") - assert result is not None, "Required property 'monitors' is missing" - return typing.cast(typing.List[builtins.str], result) - - @builtins.property - def fs_type(self) -> typing.Optional[builtins.str]: - '''fsType is the filesystem type of the volume that you want to mount. - - Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd - - :schema: io.k8s.api.core.v1.RBDVolumeSource#fsType - ''' - result = self._values.get("fs_type") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def keyring(self) -> typing.Optional[builtins.str]: - '''keyring is the path to key ring for RBDUser. - - Default is /etc/ceph/keyring. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - - :default: etc/ceph/keyring. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - - :schema: io.k8s.api.core.v1.RBDVolumeSource#keyring - ''' - result = self._values.get("keyring") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def pool(self) -> typing.Optional[builtins.str]: - '''pool is the rados pool name. - - Default is rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - - :default: rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - - :schema: io.k8s.api.core.v1.RBDVolumeSource#pool - ''' - result = self._values.get("pool") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def read_only(self) -> typing.Optional[builtins.bool]: - '''readOnly here will force the ReadOnly setting in VolumeMounts. - - Defaults to false. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - - :default: false. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - - :schema: io.k8s.api.core.v1.RBDVolumeSource#readOnly - ''' - result = self._values.get("read_only") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def secret_ref(self) -> typing.Optional[LocalObjectReference]: - '''secretRef is name of the authentication secret for RBDUser. - - If provided overrides keyring. Default is nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - - :default: nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - - :schema: io.k8s.api.core.v1.RBDVolumeSource#secretRef - ''' - result = self._values.get("secret_ref") - return typing.cast(typing.Optional[LocalObjectReference], result) - - @builtins.property - def user(self) -> typing.Optional[builtins.str]: - '''user is the rados user name. - - Default is admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - - :default: admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - - :schema: io.k8s.api.core.v1.RBDVolumeSource#user - ''' - result = self._values.get("user") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "RbdVolumeSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ReplicaSetSpec", - jsii_struct_bases=[], - name_mapping={ - "selector": "selector", - "min_ready_seconds": "minReadySeconds", - "replicas": "replicas", - "template": "template", - }, -) -class ReplicaSetSpec: - def __init__( - self, - *, - selector: typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]], - min_ready_seconds: typing.Optional[jsii.Number] = None, - replicas: typing.Optional[jsii.Number] = None, - template: typing.Optional[typing.Union[PodTemplateSpec, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''ReplicaSetSpec is the specification of a ReplicaSet. - - :param selector: Selector is a label query over pods that should match the replica count. Label keys and values that must match in order to be controlled by this replica set. It must match the pod template's labels. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors - :param min_ready_seconds: Minimum number of seconds for which a newly created pod should be ready without any of its container crashing, for it to be considered available. Defaults to 0 (pod will be considered available as soon as it is ready) Default: 0 (pod will be considered available as soon as it is ready) - :param replicas: Replicas is the number of desired replicas. This is a pointer to distinguish between explicit zero and unspecified. Defaults to 1. More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller/#what-is-a-replicationcontroller Default: 1. More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller/#what-is-a-replicationcontroller - :param template: Template is the object that describes the pod that will be created if insufficient replicas are detected. More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller#pod-template - - :schema: io.k8s.api.apps.v1.ReplicaSetSpec - ''' - if isinstance(selector, dict): - selector = LabelSelector(**selector) - if isinstance(template, dict): - template = PodTemplateSpec(**template) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__4a649a1eff04d9feb07747ac0b41f1e738bb62df7f0a6d730148217e8a0b1f7b) - check_type(argname="argument selector", value=selector, expected_type=type_hints["selector"]) - check_type(argname="argument min_ready_seconds", value=min_ready_seconds, expected_type=type_hints["min_ready_seconds"]) - check_type(argname="argument replicas", value=replicas, expected_type=type_hints["replicas"]) - check_type(argname="argument template", value=template, expected_type=type_hints["template"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "selector": selector, - } - if min_ready_seconds is not None: - self._values["min_ready_seconds"] = min_ready_seconds - if replicas is not None: - self._values["replicas"] = replicas - if template is not None: - self._values["template"] = template - - @builtins.property - def selector(self) -> LabelSelector: - '''Selector is a label query over pods that should match the replica count. - - Label keys and values that must match in order to be controlled by this replica set. It must match the pod template's labels. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors - - :schema: io.k8s.api.apps.v1.ReplicaSetSpec#selector - ''' - result = self._values.get("selector") - assert result is not None, "Required property 'selector' is missing" - return typing.cast(LabelSelector, result) - - @builtins.property - def min_ready_seconds(self) -> typing.Optional[jsii.Number]: - '''Minimum number of seconds for which a newly created pod should be ready without any of its container crashing, for it to be considered available. - - Defaults to 0 (pod will be considered available as soon as it is ready) - - :default: 0 (pod will be considered available as soon as it is ready) - - :schema: io.k8s.api.apps.v1.ReplicaSetSpec#minReadySeconds - ''' - result = self._values.get("min_ready_seconds") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def replicas(self) -> typing.Optional[jsii.Number]: - '''Replicas is the number of desired replicas. - - This is a pointer to distinguish between explicit zero and unspecified. Defaults to 1. More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller/#what-is-a-replicationcontroller - - :default: 1. More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller/#what-is-a-replicationcontroller - - :schema: io.k8s.api.apps.v1.ReplicaSetSpec#replicas - ''' - result = self._values.get("replicas") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def template(self) -> typing.Optional[PodTemplateSpec]: - '''Template is the object that describes the pod that will be created if insufficient replicas are detected. - - More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller#pod-template - - :schema: io.k8s.api.apps.v1.ReplicaSetSpec#template - ''' - result = self._values.get("template") - return typing.cast(typing.Optional[PodTemplateSpec], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ReplicaSetSpec(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ReplicationControllerSpec", - jsii_struct_bases=[], - name_mapping={ - "min_ready_seconds": "minReadySeconds", - "replicas": "replicas", - "selector": "selector", - "template": "template", - }, -) -class ReplicationControllerSpec: - def __init__( - self, - *, - min_ready_seconds: typing.Optional[jsii.Number] = None, - replicas: typing.Optional[jsii.Number] = None, - selector: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - template: typing.Optional[typing.Union[PodTemplateSpec, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''ReplicationControllerSpec is the specification of a replication controller. - - :param min_ready_seconds: Minimum number of seconds for which a newly created pod should be ready without any of its container crashing, for it to be considered available. Defaults to 0 (pod will be considered available as soon as it is ready) Default: 0 (pod will be considered available as soon as it is ready) - :param replicas: Replicas is the number of desired replicas. This is a pointer to distinguish between explicit zero and unspecified. Defaults to 1. More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller#what-is-a-replicationcontroller Default: 1. More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller#what-is-a-replicationcontroller - :param selector: Selector is a label query over pods that should match the Replicas count. If Selector is empty, it is defaulted to the labels present on the Pod template. Label keys and values that must match in order to be controlled by this replication controller, if empty defaulted to labels on Pod template. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors - :param template: Template is the object that describes the pod that will be created if insufficient replicas are detected. This takes precedence over a TemplateRef. More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller#pod-template - - :schema: io.k8s.api.core.v1.ReplicationControllerSpec - ''' - if isinstance(template, dict): - template = PodTemplateSpec(**template) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__cb1a637f64dd89041b0c36855e6e4b2ebb97a853ce2ab8bf74baa53399293aa9) - check_type(argname="argument min_ready_seconds", value=min_ready_seconds, expected_type=type_hints["min_ready_seconds"]) - check_type(argname="argument replicas", value=replicas, expected_type=type_hints["replicas"]) - check_type(argname="argument selector", value=selector, expected_type=type_hints["selector"]) - check_type(argname="argument template", value=template, expected_type=type_hints["template"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if min_ready_seconds is not None: - self._values["min_ready_seconds"] = min_ready_seconds - if replicas is not None: - self._values["replicas"] = replicas - if selector is not None: - self._values["selector"] = selector - if template is not None: - self._values["template"] = template - - @builtins.property - def min_ready_seconds(self) -> typing.Optional[jsii.Number]: - '''Minimum number of seconds for which a newly created pod should be ready without any of its container crashing, for it to be considered available. - - Defaults to 0 (pod will be considered available as soon as it is ready) - - :default: 0 (pod will be considered available as soon as it is ready) - - :schema: io.k8s.api.core.v1.ReplicationControllerSpec#minReadySeconds - ''' - result = self._values.get("min_ready_seconds") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def replicas(self) -> typing.Optional[jsii.Number]: - '''Replicas is the number of desired replicas. - - This is a pointer to distinguish between explicit zero and unspecified. Defaults to 1. More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller#what-is-a-replicationcontroller - - :default: 1. More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller#what-is-a-replicationcontroller - - :schema: io.k8s.api.core.v1.ReplicationControllerSpec#replicas - ''' - result = self._values.get("replicas") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def selector(self) -> typing.Optional[typing.Mapping[builtins.str, builtins.str]]: - '''Selector is a label query over pods that should match the Replicas count. - - If Selector is empty, it is defaulted to the labels present on the Pod template. Label keys and values that must match in order to be controlled by this replication controller, if empty defaulted to labels on Pod template. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors - - :schema: io.k8s.api.core.v1.ReplicationControllerSpec#selector - ''' - result = self._values.get("selector") - return typing.cast(typing.Optional[typing.Mapping[builtins.str, builtins.str]], result) - - @builtins.property - def template(self) -> typing.Optional[PodTemplateSpec]: - '''Template is the object that describes the pod that will be created if insufficient replicas are detected. - - This takes precedence over a TemplateRef. More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller#pod-template - - :schema: io.k8s.api.core.v1.ReplicationControllerSpec#template - ''' - result = self._values.get("template") - return typing.cast(typing.Optional[PodTemplateSpec], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ReplicationControllerSpec(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ResourceAttributes", - jsii_struct_bases=[], - name_mapping={ - "group": "group", - "name": "name", - "namespace": "namespace", - "resource": "resource", - "subresource": "subresource", - "verb": "verb", - "version": "version", - }, -) -class ResourceAttributes: - def __init__( - self, - *, - group: typing.Optional[builtins.str] = None, - name: typing.Optional[builtins.str] = None, - namespace: typing.Optional[builtins.str] = None, - resource: typing.Optional[builtins.str] = None, - subresource: typing.Optional[builtins.str] = None, - verb: typing.Optional[builtins.str] = None, - version: typing.Optional[builtins.str] = None, - ) -> None: - '''ResourceAttributes includes the authorization attributes available for resource requests to the Authorizer interface. - - :param group: Group is the API Group of the Resource. "*" means all. - :param name: Name is the name of the resource being requested for a "get" or deleted for a "delete". "" (empty) means all. - :param namespace: Namespace is the namespace of the action being requested. Currently, there is no distinction between no namespace and all namespaces "" (empty) is defaulted for LocalSubjectAccessReviews "" (empty) is empty for cluster-scoped resources "" (empty) means "all" for namespace scoped resources from a SubjectAccessReview or SelfSubjectAccessReview - :param resource: Resource is one of the existing resource types. "*" means all. - :param subresource: Subresource is one of the existing resource types. "" means none. - :param verb: Verb is a kubernetes resource API verb, like: get, list, watch, create, update, delete, proxy. "*" means all. - :param version: Version is the API Version of the Resource. "*" means all. - - :schema: io.k8s.api.authorization.v1.ResourceAttributes - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__1389ee6ee42f772dc34e626fc6cda72a7449fbddee89e52988179f65c725d996) - check_type(argname="argument group", value=group, expected_type=type_hints["group"]) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument namespace", value=namespace, expected_type=type_hints["namespace"]) - check_type(argname="argument resource", value=resource, expected_type=type_hints["resource"]) - check_type(argname="argument subresource", value=subresource, expected_type=type_hints["subresource"]) - check_type(argname="argument verb", value=verb, expected_type=type_hints["verb"]) - check_type(argname="argument version", value=version, expected_type=type_hints["version"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if group is not None: - self._values["group"] = group - if name is not None: - self._values["name"] = name - if namespace is not None: - self._values["namespace"] = namespace - if resource is not None: - self._values["resource"] = resource - if subresource is not None: - self._values["subresource"] = subresource - if verb is not None: - self._values["verb"] = verb - if version is not None: - self._values["version"] = version - - @builtins.property - def group(self) -> typing.Optional[builtins.str]: - '''Group is the API Group of the Resource. - - "*" means all. - - :schema: io.k8s.api.authorization.v1.ResourceAttributes#group - ''' - result = self._values.get("group") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def name(self) -> typing.Optional[builtins.str]: - '''Name is the name of the resource being requested for a "get" or deleted for a "delete". - - "" (empty) means all. - - :schema: io.k8s.api.authorization.v1.ResourceAttributes#name - ''' - result = self._values.get("name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def namespace(self) -> typing.Optional[builtins.str]: - '''Namespace is the namespace of the action being requested. - - Currently, there is no distinction between no namespace and all namespaces "" (empty) is defaulted for LocalSubjectAccessReviews "" (empty) is empty for cluster-scoped resources "" (empty) means "all" for namespace scoped resources from a SubjectAccessReview or SelfSubjectAccessReview - - :schema: io.k8s.api.authorization.v1.ResourceAttributes#namespace - ''' - result = self._values.get("namespace") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def resource(self) -> typing.Optional[builtins.str]: - '''Resource is one of the existing resource types. - - "*" means all. - - :schema: io.k8s.api.authorization.v1.ResourceAttributes#resource - ''' - result = self._values.get("resource") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def subresource(self) -> typing.Optional[builtins.str]: - '''Subresource is one of the existing resource types. - - "" means none. - - :schema: io.k8s.api.authorization.v1.ResourceAttributes#subresource - ''' - result = self._values.get("subresource") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def verb(self) -> typing.Optional[builtins.str]: - '''Verb is a kubernetes resource API verb, like: get, list, watch, create, update, delete, proxy. - - "*" means all. - - :schema: io.k8s.api.authorization.v1.ResourceAttributes#verb - ''' - result = self._values.get("verb") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def version(self) -> typing.Optional[builtins.str]: - '''Version is the API Version of the Resource. - - "*" means all. - - :schema: io.k8s.api.authorization.v1.ResourceAttributes#version - ''' - result = self._values.get("version") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ResourceAttributes(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ResourceClaim", - jsii_struct_bases=[], - name_mapping={"name": "name"}, -) -class ResourceClaim: - def __init__(self, *, name: builtins.str) -> None: - '''ResourceClaim references one entry in PodSpec.ResourceClaims. - - :param name: Name must match the name of one entry in pod.spec.resourceClaims of the Pod where this field is used. It makes that resource available inside a container. - - :schema: io.k8s.api.core.v1.ResourceClaim - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__91cfdd0118d393ecd84db840ef420f5ffe5190ebbd91733137901a1accc49509) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "name": name, - } - - @builtins.property - def name(self) -> builtins.str: - '''Name must match the name of one entry in pod.spec.resourceClaims of the Pod where this field is used. It makes that resource available inside a container. - - :schema: io.k8s.api.core.v1.ResourceClaim#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ResourceClaim(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ResourceClaimParametersReferenceV1Alpha1", - jsii_struct_bases=[], - name_mapping={"kind": "kind", "name": "name", "api_group": "apiGroup"}, -) -class ResourceClaimParametersReferenceV1Alpha1: - def __init__( - self, - *, - kind: builtins.str, - name: builtins.str, - api_group: typing.Optional[builtins.str] = None, - ) -> None: - '''ResourceClaimParametersReference contains enough information to let you locate the parameters for a ResourceClaim. - - The object must be in the same namespace as the ResourceClaim. - - :param kind: Kind is the type of resource being referenced. This is the same value as in the parameter object's metadata, for example "ConfigMap". - :param name: Name is the name of resource being referenced. - :param api_group: APIGroup is the group for the resource being referenced. It is empty for the core API. This matches the group in the APIVersion that is used when creating the resources. - - :schema: io.k8s.api.resource.v1alpha1.ResourceClaimParametersReference - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__3577080f3432d03b6855e16ee80a2c353219d63b419c899aeaa67829a6e5c1fd) - check_type(argname="argument kind", value=kind, expected_type=type_hints["kind"]) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument api_group", value=api_group, expected_type=type_hints["api_group"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "kind": kind, - "name": name, - } - if api_group is not None: - self._values["api_group"] = api_group - - @builtins.property - def kind(self) -> builtins.str: - '''Kind is the type of resource being referenced. - - This is the same value as in the parameter object's metadata, for example "ConfigMap". - - :schema: io.k8s.api.resource.v1alpha1.ResourceClaimParametersReference#kind - ''' - result = self._values.get("kind") - assert result is not None, "Required property 'kind' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def name(self) -> builtins.str: - '''Name is the name of resource being referenced. - - :schema: io.k8s.api.resource.v1alpha1.ResourceClaimParametersReference#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def api_group(self) -> typing.Optional[builtins.str]: - '''APIGroup is the group for the resource being referenced. - - It is empty for the core API. This matches the group in the APIVersion that is used when creating the resources. - - :schema: io.k8s.api.resource.v1alpha1.ResourceClaimParametersReference#apiGroup - ''' - result = self._values.get("api_group") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ResourceClaimParametersReferenceV1Alpha1(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ResourceClaimSpecV1Alpha1", - jsii_struct_bases=[], - name_mapping={ - "resource_class_name": "resourceClassName", - "allocation_mode": "allocationMode", - "parameters_ref": "parametersRef", - }, -) -class ResourceClaimSpecV1Alpha1: - def __init__( - self, - *, - resource_class_name: builtins.str, - allocation_mode: typing.Optional[builtins.str] = None, - parameters_ref: typing.Optional[typing.Union[ResourceClaimParametersReferenceV1Alpha1, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''ResourceClaimSpec defines how a resource is to be allocated. - - :param resource_class_name: ResourceClassName references the driver and additional parameters via the name of a ResourceClass that was created as part of the driver deployment. - :param allocation_mode: Allocation can start immediately or when a Pod wants to use the resource. "WaitForFirstConsumer" is the default. - :param parameters_ref: ParametersRef references a separate object with arbitrary parameters that will be used by the driver when allocating a resource for the claim. The object must be in the same namespace as the ResourceClaim. - - :schema: io.k8s.api.resource.v1alpha1.ResourceClaimSpec - ''' - if isinstance(parameters_ref, dict): - parameters_ref = ResourceClaimParametersReferenceV1Alpha1(**parameters_ref) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__222e0cbad16de6e748d8f212a7f2442c819c2ab8c5a44ca7bae369ddd8d4b534) - check_type(argname="argument resource_class_name", value=resource_class_name, expected_type=type_hints["resource_class_name"]) - check_type(argname="argument allocation_mode", value=allocation_mode, expected_type=type_hints["allocation_mode"]) - check_type(argname="argument parameters_ref", value=parameters_ref, expected_type=type_hints["parameters_ref"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "resource_class_name": resource_class_name, - } - if allocation_mode is not None: - self._values["allocation_mode"] = allocation_mode - if parameters_ref is not None: - self._values["parameters_ref"] = parameters_ref - - @builtins.property - def resource_class_name(self) -> builtins.str: - '''ResourceClassName references the driver and additional parameters via the name of a ResourceClass that was created as part of the driver deployment. - - :schema: io.k8s.api.resource.v1alpha1.ResourceClaimSpec#resourceClassName - ''' - result = self._values.get("resource_class_name") - assert result is not None, "Required property 'resource_class_name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def allocation_mode(self) -> typing.Optional[builtins.str]: - '''Allocation can start immediately or when a Pod wants to use the resource. - - "WaitForFirstConsumer" is the default. - - :schema: io.k8s.api.resource.v1alpha1.ResourceClaimSpec#allocationMode - ''' - result = self._values.get("allocation_mode") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def parameters_ref( - self, - ) -> typing.Optional[ResourceClaimParametersReferenceV1Alpha1]: - '''ParametersRef references a separate object with arbitrary parameters that will be used by the driver when allocating a resource for the claim. - - The object must be in the same namespace as the ResourceClaim. - - :schema: io.k8s.api.resource.v1alpha1.ResourceClaimSpec#parametersRef - ''' - result = self._values.get("parameters_ref") - return typing.cast(typing.Optional[ResourceClaimParametersReferenceV1Alpha1], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ResourceClaimSpecV1Alpha1(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ResourceClaimTemplateSpecV1Alpha1", - jsii_struct_bases=[], - name_mapping={"spec": "spec", "metadata": "metadata"}, -) -class ResourceClaimTemplateSpecV1Alpha1: - def __init__( - self, - *, - spec: typing.Union[ResourceClaimSpecV1Alpha1, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''ResourceClaimTemplateSpec contains the metadata and fields for a ResourceClaim. - - :param spec: Spec for the ResourceClaim. The entire content is copied unchanged into the ResourceClaim that gets created from this template. The same fields as in a ResourceClaim are also valid here. - :param metadata: ObjectMeta may contain labels and annotations that will be copied into the PVC when creating it. No other fields are allowed and will be rejected during validation. - - :schema: io.k8s.api.resource.v1alpha1.ResourceClaimTemplateSpec - ''' - if isinstance(spec, dict): - spec = ResourceClaimSpecV1Alpha1(**spec) - if isinstance(metadata, dict): - metadata = ObjectMeta(**metadata) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__e997f36b60700a40ef5d273c773afd5de1bd6dd5b1729cba9b1011cf89235456) - check_type(argname="argument spec", value=spec, expected_type=type_hints["spec"]) - check_type(argname="argument metadata", value=metadata, expected_type=type_hints["metadata"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "spec": spec, - } - if metadata is not None: - self._values["metadata"] = metadata - - @builtins.property - def spec(self) -> ResourceClaimSpecV1Alpha1: - '''Spec for the ResourceClaim. - - The entire content is copied unchanged into the ResourceClaim that gets created from this template. The same fields as in a ResourceClaim are also valid here. - - :schema: io.k8s.api.resource.v1alpha1.ResourceClaimTemplateSpec#spec - ''' - result = self._values.get("spec") - assert result is not None, "Required property 'spec' is missing" - return typing.cast(ResourceClaimSpecV1Alpha1, result) - - @builtins.property - def metadata(self) -> typing.Optional[ObjectMeta]: - '''ObjectMeta may contain labels and annotations that will be copied into the PVC when creating it. - - No other fields are allowed and will be rejected during validation. - - :schema: io.k8s.api.resource.v1alpha1.ResourceClaimTemplateSpec#metadata - ''' - result = self._values.get("metadata") - return typing.cast(typing.Optional[ObjectMeta], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ResourceClaimTemplateSpecV1Alpha1(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ResourceClassParametersReferenceV1Alpha1", - jsii_struct_bases=[], - name_mapping={ - "kind": "kind", - "name": "name", - "api_group": "apiGroup", - "namespace": "namespace", - }, -) -class ResourceClassParametersReferenceV1Alpha1: - def __init__( - self, - *, - kind: builtins.str, - name: builtins.str, - api_group: typing.Optional[builtins.str] = None, - namespace: typing.Optional[builtins.str] = None, - ) -> None: - '''ResourceClassParametersReference contains enough information to let you locate the parameters for a ResourceClass. - - :param kind: Kind is the type of resource being referenced. This is the same value as in the parameter object's metadata. - :param name: Name is the name of resource being referenced. - :param api_group: APIGroup is the group for the resource being referenced. It is empty for the core API. This matches the group in the APIVersion that is used when creating the resources. - :param namespace: Namespace that contains the referenced resource. Must be empty for cluster-scoped resources and non-empty for namespaced resources. - - :schema: io.k8s.api.resource.v1alpha1.ResourceClassParametersReference - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__5afcc6783d7cbb47b83e346e5c573888b38fd04b8cfd4d6ca64f7b0a4392f11c) - check_type(argname="argument kind", value=kind, expected_type=type_hints["kind"]) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument api_group", value=api_group, expected_type=type_hints["api_group"]) - check_type(argname="argument namespace", value=namespace, expected_type=type_hints["namespace"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "kind": kind, - "name": name, - } - if api_group is not None: - self._values["api_group"] = api_group - if namespace is not None: - self._values["namespace"] = namespace - - @builtins.property - def kind(self) -> builtins.str: - '''Kind is the type of resource being referenced. - - This is the same value as in the parameter object's metadata. - - :schema: io.k8s.api.resource.v1alpha1.ResourceClassParametersReference#kind - ''' - result = self._values.get("kind") - assert result is not None, "Required property 'kind' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def name(self) -> builtins.str: - '''Name is the name of resource being referenced. - - :schema: io.k8s.api.resource.v1alpha1.ResourceClassParametersReference#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def api_group(self) -> typing.Optional[builtins.str]: - '''APIGroup is the group for the resource being referenced. - - It is empty for the core API. This matches the group in the APIVersion that is used when creating the resources. - - :schema: io.k8s.api.resource.v1alpha1.ResourceClassParametersReference#apiGroup - ''' - result = self._values.get("api_group") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def namespace(self) -> typing.Optional[builtins.str]: - '''Namespace that contains the referenced resource. - - Must be empty for cluster-scoped resources and non-empty for namespaced resources. - - :schema: io.k8s.api.resource.v1alpha1.ResourceClassParametersReference#namespace - ''' - result = self._values.get("namespace") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ResourceClassParametersReferenceV1Alpha1(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ResourceFieldSelector", - jsii_struct_bases=[], - name_mapping={ - "resource": "resource", - "container_name": "containerName", - "divisor": "divisor", - }, -) -class ResourceFieldSelector: - def __init__( - self, - *, - resource: builtins.str, - container_name: typing.Optional[builtins.str] = None, - divisor: typing.Optional[Quantity] = None, - ) -> None: - '''ResourceFieldSelector represents container resources (cpu, memory) and their output format. - - :param resource: Required: resource to select. - :param container_name: Container name: required for volumes, optional for env vars. - :param divisor: Specifies the output format of the exposed resources, defaults to "1". - - :schema: io.k8s.api.core.v1.ResourceFieldSelector - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__7117ce5ef6d2382048cc325329ebe4abba77c2be754492f7322ea7cc6b3c8c8c) - check_type(argname="argument resource", value=resource, expected_type=type_hints["resource"]) - check_type(argname="argument container_name", value=container_name, expected_type=type_hints["container_name"]) - check_type(argname="argument divisor", value=divisor, expected_type=type_hints["divisor"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "resource": resource, - } - if container_name is not None: - self._values["container_name"] = container_name - if divisor is not None: - self._values["divisor"] = divisor - - @builtins.property - def resource(self) -> builtins.str: - '''Required: resource to select. - - :schema: io.k8s.api.core.v1.ResourceFieldSelector#resource - ''' - result = self._values.get("resource") - assert result is not None, "Required property 'resource' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def container_name(self) -> typing.Optional[builtins.str]: - '''Container name: required for volumes, optional for env vars. - - :schema: io.k8s.api.core.v1.ResourceFieldSelector#containerName - ''' - result = self._values.get("container_name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def divisor(self) -> typing.Optional[Quantity]: - '''Specifies the output format of the exposed resources, defaults to "1". - - :schema: io.k8s.api.core.v1.ResourceFieldSelector#divisor - ''' - result = self._values.get("divisor") - return typing.cast(typing.Optional[Quantity], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ResourceFieldSelector(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ResourceMetricSourceV2", - jsii_struct_bases=[], - name_mapping={"name": "name", "target": "target"}, -) -class ResourceMetricSourceV2: - def __init__( - self, - *, - name: builtins.str, - target: typing.Union[MetricTargetV2, typing.Dict[builtins.str, typing.Any]], - ) -> None: - '''ResourceMetricSource indicates how to scale on a resource metric known to Kubernetes, as specified in requests and limits, describing each pod in the current scale target (e.g. CPU or memory). The values will be averaged together before being compared to the target. Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the "pods" source. Only one "target" type should be set. - - :param name: name is the name of the resource in question. - :param target: target specifies the target value for the given metric. - - :schema: io.k8s.api.autoscaling.v2.ResourceMetricSource - ''' - if isinstance(target, dict): - target = MetricTargetV2(**target) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__62e5706b1c72eb3d6f6b070e53fc6646c3236f3cf9b9bbbbfc3f1022dda08d0d) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument target", value=target, expected_type=type_hints["target"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "name": name, - "target": target, - } - - @builtins.property - def name(self) -> builtins.str: - '''name is the name of the resource in question. - - :schema: io.k8s.api.autoscaling.v2.ResourceMetricSource#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def target(self) -> MetricTargetV2: - '''target specifies the target value for the given metric. - - :schema: io.k8s.api.autoscaling.v2.ResourceMetricSource#target - ''' - result = self._values.get("target") - assert result is not None, "Required property 'target' is missing" - return typing.cast(MetricTargetV2, result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ResourceMetricSourceV2(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ResourcePolicyRuleV1Beta2", - jsii_struct_bases=[], - name_mapping={ - "api_groups": "apiGroups", - "resources": "resources", - "verbs": "verbs", - "cluster_scope": "clusterScope", - "namespaces": "namespaces", - }, -) -class ResourcePolicyRuleV1Beta2: - def __init__( - self, - *, - api_groups: typing.Sequence[builtins.str], - resources: typing.Sequence[builtins.str], - verbs: typing.Sequence[builtins.str], - cluster_scope: typing.Optional[builtins.bool] = None, - namespaces: typing.Optional[typing.Sequence[builtins.str]] = None, - ) -> None: - '''ResourcePolicyRule is a predicate that matches some resource requests, testing the request's verb and the target resource. - - A ResourcePolicyRule matches a resource request if and only if: (a) at least one member of verbs matches the request, (b) at least one member of apiGroups matches the request, (c) at least one member of resources matches the request, and (d) either (d1) the request does not specify a namespace (i.e., ``Namespace==""``) and clusterScope is true or (d2) the request specifies a namespace and least one member of namespaces matches the request's namespace. - - :param api_groups: ``apiGroups`` is a list of matching API groups and may not be empty. "*" matches all API groups and, if present, must be the only entry. Required. - :param resources: ``resources`` is a list of matching resources (i.e., lowercase and plural) with, if desired, subresource. For example, [ "services", "nodes/status" ]. This list may not be empty. "*" matches all resources and, if present, must be the only entry. Required. - :param verbs: ``verbs`` is a list of matching verbs and may not be empty. "*" matches all verbs and, if present, must be the only entry. Required. - :param cluster_scope: ``clusterScope`` indicates whether to match requests that do not specify a namespace (which happens either because the resource is not namespaced or the request targets all namespaces). If this field is omitted or false then the ``namespaces`` field must contain a non-empty list. - :param namespaces: ``namespaces`` is a list of target namespaces that restricts matches. A request that specifies a target namespace matches only if either (a) this list contains that target namespace or (b) this list contains "*". Note that "*" matches any specified namespace but does not match a request that *does not specify* a namespace (see the ``clusterScope`` field for that). This list may be empty, but only if ``clusterScope`` is true. - - :schema: io.k8s.api.flowcontrol.v1beta2.ResourcePolicyRule - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__36c3728ec619997c16f03e7e503f9b6faa92c7d0be82c87e3f0a2c89c144f2bb) - check_type(argname="argument api_groups", value=api_groups, expected_type=type_hints["api_groups"]) - check_type(argname="argument resources", value=resources, expected_type=type_hints["resources"]) - check_type(argname="argument verbs", value=verbs, expected_type=type_hints["verbs"]) - check_type(argname="argument cluster_scope", value=cluster_scope, expected_type=type_hints["cluster_scope"]) - check_type(argname="argument namespaces", value=namespaces, expected_type=type_hints["namespaces"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "api_groups": api_groups, - "resources": resources, - "verbs": verbs, - } - if cluster_scope is not None: - self._values["cluster_scope"] = cluster_scope - if namespaces is not None: - self._values["namespaces"] = namespaces - - @builtins.property - def api_groups(self) -> typing.List[builtins.str]: - '''``apiGroups`` is a list of matching API groups and may not be empty. - - "*" matches all API groups and, if present, must be the only entry. Required. - - :schema: io.k8s.api.flowcontrol.v1beta2.ResourcePolicyRule#apiGroups - ''' - result = self._values.get("api_groups") - assert result is not None, "Required property 'api_groups' is missing" - return typing.cast(typing.List[builtins.str], result) - - @builtins.property - def resources(self) -> typing.List[builtins.str]: - '''``resources`` is a list of matching resources (i.e., lowercase and plural) with, if desired, subresource. For example, [ "services", "nodes/status" ]. This list may not be empty. "*" matches all resources and, if present, must be the only entry. Required. - - :schema: io.k8s.api.flowcontrol.v1beta2.ResourcePolicyRule#resources - ''' - result = self._values.get("resources") - assert result is not None, "Required property 'resources' is missing" - return typing.cast(typing.List[builtins.str], result) - - @builtins.property - def verbs(self) -> typing.List[builtins.str]: - '''``verbs`` is a list of matching verbs and may not be empty. - - "*" matches all verbs and, if present, must be the only entry. Required. - - :schema: io.k8s.api.flowcontrol.v1beta2.ResourcePolicyRule#verbs - ''' - result = self._values.get("verbs") - assert result is not None, "Required property 'verbs' is missing" - return typing.cast(typing.List[builtins.str], result) - - @builtins.property - def cluster_scope(self) -> typing.Optional[builtins.bool]: - '''``clusterScope`` indicates whether to match requests that do not specify a namespace (which happens either because the resource is not namespaced or the request targets all namespaces). - - If this field is omitted or false then the ``namespaces`` field must contain a non-empty list. - - :schema: io.k8s.api.flowcontrol.v1beta2.ResourcePolicyRule#clusterScope - ''' - result = self._values.get("cluster_scope") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def namespaces(self) -> typing.Optional[typing.List[builtins.str]]: - '''``namespaces`` is a list of target namespaces that restricts matches. - - A request that specifies a target namespace matches only if either (a) this list contains that target namespace or (b) this list contains "*". Note that "*" matches any specified namespace but does not match a request that *does not specify* a namespace (see the ``clusterScope`` field for that). This list may be empty, but only if ``clusterScope`` is true. - - :schema: io.k8s.api.flowcontrol.v1beta2.ResourcePolicyRule#namespaces - ''' - result = self._values.get("namespaces") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ResourcePolicyRuleV1Beta2(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ResourcePolicyRuleV1Beta3", - jsii_struct_bases=[], - name_mapping={ - "api_groups": "apiGroups", - "resources": "resources", - "verbs": "verbs", - "cluster_scope": "clusterScope", - "namespaces": "namespaces", - }, -) -class ResourcePolicyRuleV1Beta3: - def __init__( - self, - *, - api_groups: typing.Sequence[builtins.str], - resources: typing.Sequence[builtins.str], - verbs: typing.Sequence[builtins.str], - cluster_scope: typing.Optional[builtins.bool] = None, - namespaces: typing.Optional[typing.Sequence[builtins.str]] = None, - ) -> None: - '''ResourcePolicyRule is a predicate that matches some resource requests, testing the request's verb and the target resource. - - A ResourcePolicyRule matches a resource request if and only if: (a) at least one member of verbs matches the request, (b) at least one member of apiGroups matches the request, (c) at least one member of resources matches the request, and (d) either (d1) the request does not specify a namespace (i.e., ``Namespace==""``) and clusterScope is true or (d2) the request specifies a namespace and least one member of namespaces matches the request's namespace. - - :param api_groups: ``apiGroups`` is a list of matching API groups and may not be empty. "*" matches all API groups and, if present, must be the only entry. Required. - :param resources: ``resources`` is a list of matching resources (i.e., lowercase and plural) with, if desired, subresource. For example, [ "services", "nodes/status" ]. This list may not be empty. "*" matches all resources and, if present, must be the only entry. Required. - :param verbs: ``verbs`` is a list of matching verbs and may not be empty. "*" matches all verbs and, if present, must be the only entry. Required. - :param cluster_scope: ``clusterScope`` indicates whether to match requests that do not specify a namespace (which happens either because the resource is not namespaced or the request targets all namespaces). If this field is omitted or false then the ``namespaces`` field must contain a non-empty list. - :param namespaces: ``namespaces`` is a list of target namespaces that restricts matches. A request that specifies a target namespace matches only if either (a) this list contains that target namespace or (b) this list contains "*". Note that "*" matches any specified namespace but does not match a request that *does not specify* a namespace (see the ``clusterScope`` field for that). This list may be empty, but only if ``clusterScope`` is true. - - :schema: io.k8s.api.flowcontrol.v1beta3.ResourcePolicyRule - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__c9ae6771cea2f9e8c2c610a5b19310cef1a10452a5eab35dc8eb9198c9ed8025) - check_type(argname="argument api_groups", value=api_groups, expected_type=type_hints["api_groups"]) - check_type(argname="argument resources", value=resources, expected_type=type_hints["resources"]) - check_type(argname="argument verbs", value=verbs, expected_type=type_hints["verbs"]) - check_type(argname="argument cluster_scope", value=cluster_scope, expected_type=type_hints["cluster_scope"]) - check_type(argname="argument namespaces", value=namespaces, expected_type=type_hints["namespaces"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "api_groups": api_groups, - "resources": resources, - "verbs": verbs, - } - if cluster_scope is not None: - self._values["cluster_scope"] = cluster_scope - if namespaces is not None: - self._values["namespaces"] = namespaces - - @builtins.property - def api_groups(self) -> typing.List[builtins.str]: - '''``apiGroups`` is a list of matching API groups and may not be empty. - - "*" matches all API groups and, if present, must be the only entry. Required. - - :schema: io.k8s.api.flowcontrol.v1beta3.ResourcePolicyRule#apiGroups - ''' - result = self._values.get("api_groups") - assert result is not None, "Required property 'api_groups' is missing" - return typing.cast(typing.List[builtins.str], result) - - @builtins.property - def resources(self) -> typing.List[builtins.str]: - '''``resources`` is a list of matching resources (i.e., lowercase and plural) with, if desired, subresource. For example, [ "services", "nodes/status" ]. This list may not be empty. "*" matches all resources and, if present, must be the only entry. Required. - - :schema: io.k8s.api.flowcontrol.v1beta3.ResourcePolicyRule#resources - ''' - result = self._values.get("resources") - assert result is not None, "Required property 'resources' is missing" - return typing.cast(typing.List[builtins.str], result) - - @builtins.property - def verbs(self) -> typing.List[builtins.str]: - '''``verbs`` is a list of matching verbs and may not be empty. - - "*" matches all verbs and, if present, must be the only entry. Required. - - :schema: io.k8s.api.flowcontrol.v1beta3.ResourcePolicyRule#verbs - ''' - result = self._values.get("verbs") - assert result is not None, "Required property 'verbs' is missing" - return typing.cast(typing.List[builtins.str], result) - - @builtins.property - def cluster_scope(self) -> typing.Optional[builtins.bool]: - '''``clusterScope`` indicates whether to match requests that do not specify a namespace (which happens either because the resource is not namespaced or the request targets all namespaces). - - If this field is omitted or false then the ``namespaces`` field must contain a non-empty list. - - :schema: io.k8s.api.flowcontrol.v1beta3.ResourcePolicyRule#clusterScope - ''' - result = self._values.get("cluster_scope") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def namespaces(self) -> typing.Optional[typing.List[builtins.str]]: - '''``namespaces`` is a list of target namespaces that restricts matches. - - A request that specifies a target namespace matches only if either (a) this list contains that target namespace or (b) this list contains "*". Note that "*" matches any specified namespace but does not match a request that *does not specify* a namespace (see the ``clusterScope`` field for that). This list may be empty, but only if ``clusterScope`` is true. - - :schema: io.k8s.api.flowcontrol.v1beta3.ResourcePolicyRule#namespaces - ''' - result = self._values.get("namespaces") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ResourcePolicyRuleV1Beta3(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ResourceQuotaSpec", - jsii_struct_bases=[], - name_mapping={ - "hard": "hard", - "scopes": "scopes", - "scope_selector": "scopeSelector", - }, -) -class ResourceQuotaSpec: - def __init__( - self, - *, - hard: typing.Optional[typing.Mapping[builtins.str, Quantity]] = None, - scopes: typing.Optional[typing.Sequence[builtins.str]] = None, - scope_selector: typing.Optional[typing.Union["ScopeSelector", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''ResourceQuotaSpec defines the desired hard limits to enforce for Quota. - - :param hard: hard is the set of desired hard limits for each named resource. More info: https://kubernetes.io/docs/concepts/policy/resource-quotas/ - :param scopes: A collection of filters that must match each object tracked by a quota. If not specified, the quota matches all objects. - :param scope_selector: scopeSelector is also a collection of filters like scopes that must match each object tracked by a quota but expressed using ScopeSelectorOperator in combination with possible values. For a resource to match, both scopes AND scopeSelector (if specified in spec), must be matched. - - :schema: io.k8s.api.core.v1.ResourceQuotaSpec - ''' - if isinstance(scope_selector, dict): - scope_selector = ScopeSelector(**scope_selector) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__1f38b292c93787ac346fc7bdbff50edd3c17b9ea8d3ae69b3ef92ad11538687e) - check_type(argname="argument hard", value=hard, expected_type=type_hints["hard"]) - check_type(argname="argument scopes", value=scopes, expected_type=type_hints["scopes"]) - check_type(argname="argument scope_selector", value=scope_selector, expected_type=type_hints["scope_selector"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if hard is not None: - self._values["hard"] = hard - if scopes is not None: - self._values["scopes"] = scopes - if scope_selector is not None: - self._values["scope_selector"] = scope_selector - - @builtins.property - def hard(self) -> typing.Optional[typing.Mapping[builtins.str, Quantity]]: - '''hard is the set of desired hard limits for each named resource. - - More info: https://kubernetes.io/docs/concepts/policy/resource-quotas/ - - :schema: io.k8s.api.core.v1.ResourceQuotaSpec#hard - ''' - result = self._values.get("hard") - return typing.cast(typing.Optional[typing.Mapping[builtins.str, Quantity]], result) - - @builtins.property - def scopes(self) -> typing.Optional[typing.List[builtins.str]]: - '''A collection of filters that must match each object tracked by a quota. - - If not specified, the quota matches all objects. - - :schema: io.k8s.api.core.v1.ResourceQuotaSpec#scopes - ''' - result = self._values.get("scopes") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def scope_selector(self) -> typing.Optional["ScopeSelector"]: - '''scopeSelector is also a collection of filters like scopes that must match each object tracked by a quota but expressed using ScopeSelectorOperator in combination with possible values. - - For a resource to match, both scopes AND scopeSelector (if specified in spec), must be matched. - - :schema: io.k8s.api.core.v1.ResourceQuotaSpec#scopeSelector - ''' - result = self._values.get("scope_selector") - return typing.cast(typing.Optional["ScopeSelector"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ResourceQuotaSpec(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ResourceRequirements", - jsii_struct_bases=[], - name_mapping={"claims": "claims", "limits": "limits", "requests": "requests"}, -) -class ResourceRequirements: - def __init__( - self, - *, - claims: typing.Optional[typing.Sequence[typing.Union[ResourceClaim, typing.Dict[builtins.str, typing.Any]]]] = None, - limits: typing.Optional[typing.Mapping[builtins.str, Quantity]] = None, - requests: typing.Optional[typing.Mapping[builtins.str, Quantity]] = None, - ) -> None: - '''ResourceRequirements describes the compute resource requirements. - - :param claims: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. This field is immutable. - :param limits: Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - :param requests: Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - - :schema: io.k8s.api.core.v1.ResourceRequirements - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__6f28381f115e86cc4a857dc64662f80338d1b27b3fbd53665d90231711e3a3cd) - check_type(argname="argument claims", value=claims, expected_type=type_hints["claims"]) - check_type(argname="argument limits", value=limits, expected_type=type_hints["limits"]) - check_type(argname="argument requests", value=requests, expected_type=type_hints["requests"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if claims is not None: - self._values["claims"] = claims - if limits is not None: - self._values["limits"] = limits - if requests is not None: - self._values["requests"] = requests - - @builtins.property - def claims(self) -> typing.Optional[typing.List[ResourceClaim]]: - '''Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - - This field is immutable. - - :schema: io.k8s.api.core.v1.ResourceRequirements#claims - ''' - result = self._values.get("claims") - return typing.cast(typing.Optional[typing.List[ResourceClaim]], result) - - @builtins.property - def limits(self) -> typing.Optional[typing.Mapping[builtins.str, Quantity]]: - '''Limits describes the maximum amount of compute resources allowed. - - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - - :schema: io.k8s.api.core.v1.ResourceRequirements#limits - ''' - result = self._values.get("limits") - return typing.cast(typing.Optional[typing.Mapping[builtins.str, Quantity]], result) - - @builtins.property - def requests(self) -> typing.Optional[typing.Mapping[builtins.str, Quantity]]: - '''Requests describes the minimum amount of compute resources required. - - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - - :schema: io.k8s.api.core.v1.ResourceRequirements#requests - ''' - result = self._values.get("requests") - return typing.cast(typing.Optional[typing.Mapping[builtins.str, Quantity]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ResourceRequirements(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.RoleRef", - jsii_struct_bases=[], - name_mapping={"api_group": "apiGroup", "kind": "kind", "name": "name"}, -) -class RoleRef: - def __init__( - self, - *, - api_group: builtins.str, - kind: builtins.str, - name: builtins.str, - ) -> None: - '''RoleRef contains information that points to the role being used. - - :param api_group: APIGroup is the group for the resource being referenced. - :param kind: Kind is the type of resource being referenced. - :param name: Name is the name of resource being referenced. - - :schema: io.k8s.api.rbac.v1.RoleRef - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__34728caa2c65a1bce45499a1f4530a2e2966d14ff7e6d57ddbf874c837a09229) - check_type(argname="argument api_group", value=api_group, expected_type=type_hints["api_group"]) - check_type(argname="argument kind", value=kind, expected_type=type_hints["kind"]) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "api_group": api_group, - "kind": kind, - "name": name, - } - - @builtins.property - def api_group(self) -> builtins.str: - '''APIGroup is the group for the resource being referenced. - - :schema: io.k8s.api.rbac.v1.RoleRef#apiGroup - ''' - result = self._values.get("api_group") - assert result is not None, "Required property 'api_group' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def kind(self) -> builtins.str: - '''Kind is the type of resource being referenced. - - :schema: io.k8s.api.rbac.v1.RoleRef#kind - ''' - result = self._values.get("kind") - assert result is not None, "Required property 'kind' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def name(self) -> builtins.str: - '''Name is the name of resource being referenced. - - :schema: io.k8s.api.rbac.v1.RoleRef#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "RoleRef(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.RollingUpdateDaemonSet", - jsii_struct_bases=[], - name_mapping={"max_surge": "maxSurge", "max_unavailable": "maxUnavailable"}, -) -class RollingUpdateDaemonSet: - def __init__( - self, - *, - max_surge: typing.Optional[IntOrString] = None, - max_unavailable: typing.Optional[IntOrString] = None, - ) -> None: - '''Spec to control the desired behavior of daemon set rolling update. - - :param max_surge: The maximum number of nodes with an existing available DaemonSet pod that can have an updated DaemonSet pod during during an update. Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). This can not be 0 if MaxUnavailable is 0. Absolute number is calculated from percentage by rounding up to a minimum of 1. Default value is 0. Example: when this is set to 30%, at most 30% of the total number of nodes that should be running the daemon pod (i.e. status.desiredNumberScheduled) can have their a new pod created before the old pod is marked as deleted. The update starts by launching new pods on 30% of nodes. Once an updated pod is available (Ready for at least minReadySeconds) the old DaemonSet pod on that node is marked deleted. If the old pod becomes unavailable for any reason (Ready transitions to false, is evicted, or is drained) an updated pod is immediatedly created on that node without considering surge limits. Allowing surge implies the possibility that the resources consumed by the daemonset on any given node can double if the readiness check fails, and so resource intensive daemonsets should take into account that they may cause evictions during disruption. - :param max_unavailable: The maximum number of DaemonSet pods that can be unavailable during the update. Value can be an absolute number (ex: 5) or a percentage of total number of DaemonSet pods at the start of the update (ex: 10%). Absolute number is calculated from percentage by rounding up. This cannot be 0 if MaxSurge is 0 Default value is 1. Example: when this is set to 30%, at most 30% of the total number of nodes that should be running the daemon pod (i.e. status.desiredNumberScheduled) can have their pods stopped for an update at any given time. The update starts by stopping at most 30% of those DaemonSet pods and then brings up new DaemonSet pods in their place. Once the new pods are available, it then proceeds onto other DaemonSet pods, thus ensuring that at least 70% of original number of DaemonSet pods are available at all times during the update. - - :schema: io.k8s.api.apps.v1.RollingUpdateDaemonSet - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__36e1da895206a5ed9179f6d5649f08d688e482419e0ac3c555bca88a46e32a8d) - check_type(argname="argument max_surge", value=max_surge, expected_type=type_hints["max_surge"]) - check_type(argname="argument max_unavailable", value=max_unavailable, expected_type=type_hints["max_unavailable"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if max_surge is not None: - self._values["max_surge"] = max_surge - if max_unavailable is not None: - self._values["max_unavailable"] = max_unavailable - - @builtins.property - def max_surge(self) -> typing.Optional[IntOrString]: - '''The maximum number of nodes with an existing available DaemonSet pod that can have an updated DaemonSet pod during during an update. - - Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). This can not be 0 if MaxUnavailable is 0. Absolute number is calculated from percentage by rounding up to a minimum of 1. Default value is 0. Example: when this is set to 30%, at most 30% of the total number of nodes that should be running the daemon pod (i.e. status.desiredNumberScheduled) can have their a new pod created before the old pod is marked as deleted. The update starts by launching new pods on 30% of nodes. Once an updated pod is available (Ready for at least minReadySeconds) the old DaemonSet pod on that node is marked deleted. If the old pod becomes unavailable for any reason (Ready transitions to false, is evicted, or is drained) an updated pod is immediatedly created on that node without considering surge limits. Allowing surge implies the possibility that the resources consumed by the daemonset on any given node can double if the readiness check fails, and so resource intensive daemonsets should take into account that they may cause evictions during disruption. - - :schema: io.k8s.api.apps.v1.RollingUpdateDaemonSet#maxSurge - ''' - result = self._values.get("max_surge") - return typing.cast(typing.Optional[IntOrString], result) - - @builtins.property - def max_unavailable(self) -> typing.Optional[IntOrString]: - '''The maximum number of DaemonSet pods that can be unavailable during the update. - - Value can be an absolute number (ex: 5) or a percentage of total number of DaemonSet pods at the start of the update (ex: 10%). Absolute number is calculated from percentage by rounding up. This cannot be 0 if MaxSurge is 0 Default value is 1. Example: when this is set to 30%, at most 30% of the total number of nodes that should be running the daemon pod (i.e. status.desiredNumberScheduled) can have their pods stopped for an update at any given time. The update starts by stopping at most 30% of those DaemonSet pods and then brings up new DaemonSet pods in their place. Once the new pods are available, it then proceeds onto other DaemonSet pods, thus ensuring that at least 70% of original number of DaemonSet pods are available at all times during the update. - - :schema: io.k8s.api.apps.v1.RollingUpdateDaemonSet#maxUnavailable - ''' - result = self._values.get("max_unavailable") - return typing.cast(typing.Optional[IntOrString], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "RollingUpdateDaemonSet(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.RollingUpdateDeployment", - jsii_struct_bases=[], - name_mapping={"max_surge": "maxSurge", "max_unavailable": "maxUnavailable"}, -) -class RollingUpdateDeployment: - def __init__( - self, - *, - max_surge: typing.Optional[IntOrString] = None, - max_unavailable: typing.Optional[IntOrString] = None, - ) -> None: - '''Spec to control the desired behavior of rolling update. - - :param max_surge: The maximum number of pods that can be scheduled above the desired number of pods. Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). This can not be 0 if MaxUnavailable is 0. Absolute number is calculated from percentage by rounding up. Defaults to 25%. Example: when this is set to 30%, the new ReplicaSet can be scaled up immediately when the rolling update starts, such that the total number of old and new pods do not exceed 130% of desired pods. Once old pods have been killed, new ReplicaSet can be scaled up further, ensuring that total number of pods running at any time during the update is at most 130% of desired pods. Default: 25%. Example: when this is set to 30%, the new ReplicaSet can be scaled up immediately when the rolling update starts, such that the total number of old and new pods do not exceed 130% of desired pods. Once old pods have been killed, new ReplicaSet can be scaled up further, ensuring that total number of pods running at any time during the update is at most 130% of desired pods. - :param max_unavailable: The maximum number of pods that can be unavailable during the update. Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). Absolute number is calculated from percentage by rounding down. This can not be 0 if MaxSurge is 0. Defaults to 25%. Example: when this is set to 30%, the old ReplicaSet can be scaled down to 70% of desired pods immediately when the rolling update starts. Once new pods are ready, old ReplicaSet can be scaled down further, followed by scaling up the new ReplicaSet, ensuring that the total number of pods available at all times during the update is at least 70% of desired pods. Default: 25%. Example: when this is set to 30%, the old ReplicaSet can be scaled down to 70% of desired pods immediately when the rolling update starts. Once new pods are ready, old ReplicaSet can be scaled down further, followed by scaling up the new ReplicaSet, ensuring that the total number of pods available at all times during the update is at least 70% of desired pods. - - :schema: io.k8s.api.apps.v1.RollingUpdateDeployment - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__8a2a897588ced8e993501e8a731a38dd93a578e6bdfbc01a36044482c0ac6796) - check_type(argname="argument max_surge", value=max_surge, expected_type=type_hints["max_surge"]) - check_type(argname="argument max_unavailable", value=max_unavailable, expected_type=type_hints["max_unavailable"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if max_surge is not None: - self._values["max_surge"] = max_surge - if max_unavailable is not None: - self._values["max_unavailable"] = max_unavailable - - @builtins.property - def max_surge(self) -> typing.Optional[IntOrString]: - '''The maximum number of pods that can be scheduled above the desired number of pods. - - Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). This can not be 0 if MaxUnavailable is 0. Absolute number is calculated from percentage by rounding up. Defaults to 25%. Example: when this is set to 30%, the new ReplicaSet can be scaled up immediately when the rolling update starts, such that the total number of old and new pods do not exceed 130% of desired pods. Once old pods have been killed, new ReplicaSet can be scaled up further, ensuring that total number of pods running at any time during the update is at most 130% of desired pods. - - :default: 25%. Example: when this is set to 30%, the new ReplicaSet can be scaled up immediately when the rolling update starts, such that the total number of old and new pods do not exceed 130% of desired pods. Once old pods have been killed, new ReplicaSet can be scaled up further, ensuring that total number of pods running at any time during the update is at most 130% of desired pods. - - :schema: io.k8s.api.apps.v1.RollingUpdateDeployment#maxSurge - ''' - result = self._values.get("max_surge") - return typing.cast(typing.Optional[IntOrString], result) - - @builtins.property - def max_unavailable(self) -> typing.Optional[IntOrString]: - '''The maximum number of pods that can be unavailable during the update. - - Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). Absolute number is calculated from percentage by rounding down. This can not be 0 if MaxSurge is 0. Defaults to 25%. Example: when this is set to 30%, the old ReplicaSet can be scaled down to 70% of desired pods immediately when the rolling update starts. Once new pods are ready, old ReplicaSet can be scaled down further, followed by scaling up the new ReplicaSet, ensuring that the total number of pods available at all times during the update is at least 70% of desired pods. - - :default: 25%. Example: when this is set to 30%, the old ReplicaSet can be scaled down to 70% of desired pods immediately when the rolling update starts. Once new pods are ready, old ReplicaSet can be scaled down further, followed by scaling up the new ReplicaSet, ensuring that the total number of pods available at all times during the update is at least 70% of desired pods. - - :schema: io.k8s.api.apps.v1.RollingUpdateDeployment#maxUnavailable - ''' - result = self._values.get("max_unavailable") - return typing.cast(typing.Optional[IntOrString], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "RollingUpdateDeployment(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.RollingUpdateStatefulSetStrategy", - jsii_struct_bases=[], - name_mapping={"max_unavailable": "maxUnavailable", "partition": "partition"}, -) -class RollingUpdateStatefulSetStrategy: - def __init__( - self, - *, - max_unavailable: typing.Optional[IntOrString] = None, - partition: typing.Optional[jsii.Number] = None, - ) -> None: - '''RollingUpdateStatefulSetStrategy is used to communicate parameter for RollingUpdateStatefulSetStrategyType. - - :param max_unavailable: The maximum number of pods that can be unavailable during the update. Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). Absolute number is calculated from percentage by rounding up. This can not be 0. Defaults to 1. This field is alpha-level and is only honored by servers that enable the MaxUnavailableStatefulSet feature. The field applies to all pods in the range 0 to Replicas-1. That means if there is any unavailable pod in the range 0 to Replicas-1, it will be counted towards MaxUnavailable. Default: 1. This field is alpha-level and is only honored by servers that enable the MaxUnavailableStatefulSet feature. The field applies to all pods in the range 0 to Replicas-1. That means if there is any unavailable pod in the range 0 to Replicas-1, it will be counted towards MaxUnavailable. - :param partition: Partition indicates the ordinal at which the StatefulSet should be partitioned for updates. During a rolling update, all pods from ordinal Replicas-1 to Partition are updated. All pods from ordinal Partition-1 to 0 remain untouched. This is helpful in being able to do a canary based deployment. The default value is 0. - - :schema: io.k8s.api.apps.v1.RollingUpdateStatefulSetStrategy - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__5244c3370eebd6a466d9aa0a3a0f3ab6e3fec32436cc8b602ba25a37b7f9e5ec) - check_type(argname="argument max_unavailable", value=max_unavailable, expected_type=type_hints["max_unavailable"]) - check_type(argname="argument partition", value=partition, expected_type=type_hints["partition"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if max_unavailable is not None: - self._values["max_unavailable"] = max_unavailable - if partition is not None: - self._values["partition"] = partition - - @builtins.property - def max_unavailable(self) -> typing.Optional[IntOrString]: - '''The maximum number of pods that can be unavailable during the update. - - Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). Absolute number is calculated from percentage by rounding up. This can not be 0. Defaults to 1. This field is alpha-level and is only honored by servers that enable the MaxUnavailableStatefulSet feature. The field applies to all pods in the range 0 to Replicas-1. That means if there is any unavailable pod in the range 0 to Replicas-1, it will be counted towards MaxUnavailable. - - :default: 1. This field is alpha-level and is only honored by servers that enable the MaxUnavailableStatefulSet feature. The field applies to all pods in the range 0 to Replicas-1. That means if there is any unavailable pod in the range 0 to Replicas-1, it will be counted towards MaxUnavailable. - - :schema: io.k8s.api.apps.v1.RollingUpdateStatefulSetStrategy#maxUnavailable - ''' - result = self._values.get("max_unavailable") - return typing.cast(typing.Optional[IntOrString], result) - - @builtins.property - def partition(self) -> typing.Optional[jsii.Number]: - '''Partition indicates the ordinal at which the StatefulSet should be partitioned for updates. - - During a rolling update, all pods from ordinal Replicas-1 to Partition are updated. All pods from ordinal Partition-1 to 0 remain untouched. This is helpful in being able to do a canary based deployment. The default value is 0. - - :schema: io.k8s.api.apps.v1.RollingUpdateStatefulSetStrategy#partition - ''' - result = self._values.get("partition") - return typing.cast(typing.Optional[jsii.Number], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "RollingUpdateStatefulSetStrategy(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.RuleWithOperations", - jsii_struct_bases=[], - name_mapping={ - "api_groups": "apiGroups", - "api_versions": "apiVersions", - "operations": "operations", - "resources": "resources", - "scope": "scope", - }, -) -class RuleWithOperations: - def __init__( - self, - *, - api_groups: typing.Optional[typing.Sequence[builtins.str]] = None, - api_versions: typing.Optional[typing.Sequence[builtins.str]] = None, - operations: typing.Optional[typing.Sequence[builtins.str]] = None, - resources: typing.Optional[typing.Sequence[builtins.str]] = None, - scope: typing.Optional[builtins.str] = None, - ) -> None: - '''RuleWithOperations is a tuple of Operations and Resources. - - It is recommended to make sure that all the tuple expansions are valid. - - :param api_groups: APIGroups is the API groups the resources belong to. '*' is all groups. If '*' is present, the length of the slice must be one. Required. - :param api_versions: APIVersions is the API versions the resources belong to. '*' is all versions. If '*' is present, the length of the slice must be one. Required. - :param operations: Operations is the operations the admission hook cares about - CREATE, UPDATE, DELETE, CONNECT or * for all of those operations and any future admission operations that are added. If '*' is present, the length of the slice must be one. Required. - :param resources: Resources is a list of resources this rule applies to. For example: 'pods' means pods. 'pods/log' means the log subresource of pods. '*' means all resources, but not subresources. 'pods/*' means all subresources of pods. '*/scale' means all scale subresources. '*/*' means all resources and their subresources. If wildcard is present, the validation rule will ensure resources do not overlap with each other. Depending on the enclosing object, subresources might not be allowed. Required. - :param scope: scope specifies the scope of this rule. Valid values are "Cluster", "Namespaced", and "*" "Cluster" means that only cluster-scoped resources will match this rule. Namespace API objects are cluster-scoped. "Namespaced" means that only namespaced resources will match this rule. "*" means that there are no scope restrictions. Subresources match the scope of their parent resource. Default is "*". Default: . - - :schema: io.k8s.api.admissionregistration.v1.RuleWithOperations - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__a86077ec1a02004936f4e7b29b4891e15e965506276980ac5cde5434c9cb21a0) - check_type(argname="argument api_groups", value=api_groups, expected_type=type_hints["api_groups"]) - check_type(argname="argument api_versions", value=api_versions, expected_type=type_hints["api_versions"]) - check_type(argname="argument operations", value=operations, expected_type=type_hints["operations"]) - check_type(argname="argument resources", value=resources, expected_type=type_hints["resources"]) - check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if api_groups is not None: - self._values["api_groups"] = api_groups - if api_versions is not None: - self._values["api_versions"] = api_versions - if operations is not None: - self._values["operations"] = operations - if resources is not None: - self._values["resources"] = resources - if scope is not None: - self._values["scope"] = scope - - @builtins.property - def api_groups(self) -> typing.Optional[typing.List[builtins.str]]: - '''APIGroups is the API groups the resources belong to. - - '*' is all groups. If '*' is present, the length of the slice must be one. Required. - - :schema: io.k8s.api.admissionregistration.v1.RuleWithOperations#apiGroups - ''' - result = self._values.get("api_groups") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def api_versions(self) -> typing.Optional[typing.List[builtins.str]]: - '''APIVersions is the API versions the resources belong to. - - '*' is all versions. If '*' is present, the length of the slice must be one. Required. - - :schema: io.k8s.api.admissionregistration.v1.RuleWithOperations#apiVersions - ''' - result = self._values.get("api_versions") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def operations(self) -> typing.Optional[typing.List[builtins.str]]: - '''Operations is the operations the admission hook cares about - CREATE, UPDATE, DELETE, CONNECT or * for all of those operations and any future admission operations that are added. - - If '*' is present, the length of the slice must be one. Required. - - :schema: io.k8s.api.admissionregistration.v1.RuleWithOperations#operations - ''' - result = self._values.get("operations") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def resources(self) -> typing.Optional[typing.List[builtins.str]]: - '''Resources is a list of resources this rule applies to. - - For example: 'pods' means pods. 'pods/log' means the log subresource of pods. '*' means all resources, but not subresources. 'pods/*' means all subresources of pods. '*/scale' means all scale subresources. '*/*' means all resources and their subresources. - - If wildcard is present, the validation rule will ensure resources do not overlap with each other. - - Depending on the enclosing object, subresources might not be allowed. Required. - - :schema: io.k8s.api.admissionregistration.v1.RuleWithOperations#resources - ''' - result = self._values.get("resources") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def scope(self) -> typing.Optional[builtins.str]: - '''scope specifies the scope of this rule. - - Valid values are "Cluster", "Namespaced", and "*" "Cluster" means that only cluster-scoped resources will match this rule. Namespace API objects are cluster-scoped. "Namespaced" means that only namespaced resources will match this rule. "*" means that there are no scope restrictions. Subresources match the scope of their parent resource. Default is "*". - - :default: . - - :schema: io.k8s.api.admissionregistration.v1.RuleWithOperations#scope - ''' - result = self._values.get("scope") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "RuleWithOperations(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ScaleIoPersistentVolumeSource", - jsii_struct_bases=[], - name_mapping={ - "gateway": "gateway", - "secret_ref": "secretRef", - "system": "system", - "fs_type": "fsType", - "protection_domain": "protectionDomain", - "read_only": "readOnly", - "ssl_enabled": "sslEnabled", - "storage_mode": "storageMode", - "storage_pool": "storagePool", - "volume_name": "volumeName", - }, -) -class ScaleIoPersistentVolumeSource: - def __init__( - self, - *, - gateway: builtins.str, - secret_ref: typing.Union["SecretReference", typing.Dict[builtins.str, typing.Any]], - system: builtins.str, - fs_type: typing.Optional[builtins.str] = None, - protection_domain: typing.Optional[builtins.str] = None, - read_only: typing.Optional[builtins.bool] = None, - ssl_enabled: typing.Optional[builtins.bool] = None, - storage_mode: typing.Optional[builtins.str] = None, - storage_pool: typing.Optional[builtins.str] = None, - volume_name: typing.Optional[builtins.str] = None, - ) -> None: - '''ScaleIOPersistentVolumeSource represents a persistent ScaleIO volume. - - :param gateway: gateway is the host address of the ScaleIO API Gateway. - :param secret_ref: secretRef references to the secret for ScaleIO user and other sensitive information. If this is not provided, Login operation will fail. - :param system: system is the name of the storage system as configured in ScaleIO. - :param fs_type: fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Default is "xfs" Default: xfs" - :param protection_domain: protectionDomain is the name of the ScaleIO Protection Domain for the configured storage. - :param read_only: readOnly defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. - :param ssl_enabled: sslEnabled is the flag to enable/disable SSL communication with Gateway, default false. - :param storage_mode: storageMode indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. Default is ThinProvisioned. Default: ThinProvisioned. - :param storage_pool: storagePool is the ScaleIO Storage Pool associated with the protection domain. - :param volume_name: volumeName is the name of a volume already created in the ScaleIO system that is associated with this volume source. - - :schema: io.k8s.api.core.v1.ScaleIOPersistentVolumeSource - ''' - if isinstance(secret_ref, dict): - secret_ref = SecretReference(**secret_ref) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__a3db8aeafd58b5a9ffd7810c912395c33f597e9a328ad9492e778f5f6c3b1201) - check_type(argname="argument gateway", value=gateway, expected_type=type_hints["gateway"]) - check_type(argname="argument secret_ref", value=secret_ref, expected_type=type_hints["secret_ref"]) - check_type(argname="argument system", value=system, expected_type=type_hints["system"]) - check_type(argname="argument fs_type", value=fs_type, expected_type=type_hints["fs_type"]) - check_type(argname="argument protection_domain", value=protection_domain, expected_type=type_hints["protection_domain"]) - check_type(argname="argument read_only", value=read_only, expected_type=type_hints["read_only"]) - check_type(argname="argument ssl_enabled", value=ssl_enabled, expected_type=type_hints["ssl_enabled"]) - check_type(argname="argument storage_mode", value=storage_mode, expected_type=type_hints["storage_mode"]) - check_type(argname="argument storage_pool", value=storage_pool, expected_type=type_hints["storage_pool"]) - check_type(argname="argument volume_name", value=volume_name, expected_type=type_hints["volume_name"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "gateway": gateway, - "secret_ref": secret_ref, - "system": system, - } - if fs_type is not None: - self._values["fs_type"] = fs_type - if protection_domain is not None: - self._values["protection_domain"] = protection_domain - if read_only is not None: - self._values["read_only"] = read_only - if ssl_enabled is not None: - self._values["ssl_enabled"] = ssl_enabled - if storage_mode is not None: - self._values["storage_mode"] = storage_mode - if storage_pool is not None: - self._values["storage_pool"] = storage_pool - if volume_name is not None: - self._values["volume_name"] = volume_name - - @builtins.property - def gateway(self) -> builtins.str: - '''gateway is the host address of the ScaleIO API Gateway. - - :schema: io.k8s.api.core.v1.ScaleIOPersistentVolumeSource#gateway - ''' - result = self._values.get("gateway") - assert result is not None, "Required property 'gateway' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def secret_ref(self) -> "SecretReference": - '''secretRef references to the secret for ScaleIO user and other sensitive information. - - If this is not provided, Login operation will fail. - - :schema: io.k8s.api.core.v1.ScaleIOPersistentVolumeSource#secretRef - ''' - result = self._values.get("secret_ref") - assert result is not None, "Required property 'secret_ref' is missing" - return typing.cast("SecretReference", result) - - @builtins.property - def system(self) -> builtins.str: - '''system is the name of the storage system as configured in ScaleIO. - - :schema: io.k8s.api.core.v1.ScaleIOPersistentVolumeSource#system - ''' - result = self._values.get("system") - assert result is not None, "Required property 'system' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def fs_type(self) -> typing.Optional[builtins.str]: - '''fsType is the filesystem type to mount. - - Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Default is "xfs" - - :default: xfs" - - :schema: io.k8s.api.core.v1.ScaleIOPersistentVolumeSource#fsType - ''' - result = self._values.get("fs_type") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def protection_domain(self) -> typing.Optional[builtins.str]: - '''protectionDomain is the name of the ScaleIO Protection Domain for the configured storage. - - :schema: io.k8s.api.core.v1.ScaleIOPersistentVolumeSource#protectionDomain - ''' - result = self._values.get("protection_domain") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def read_only(self) -> typing.Optional[builtins.bool]: - '''readOnly defaults to false (read/write). - - ReadOnly here will force the ReadOnly setting in VolumeMounts. - - :schema: io.k8s.api.core.v1.ScaleIOPersistentVolumeSource#readOnly - ''' - result = self._values.get("read_only") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def ssl_enabled(self) -> typing.Optional[builtins.bool]: - '''sslEnabled is the flag to enable/disable SSL communication with Gateway, default false. - - :schema: io.k8s.api.core.v1.ScaleIOPersistentVolumeSource#sslEnabled - ''' - result = self._values.get("ssl_enabled") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def storage_mode(self) -> typing.Optional[builtins.str]: - '''storageMode indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. - - Default is ThinProvisioned. - - :default: ThinProvisioned. - - :schema: io.k8s.api.core.v1.ScaleIOPersistentVolumeSource#storageMode - ''' - result = self._values.get("storage_mode") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def storage_pool(self) -> typing.Optional[builtins.str]: - '''storagePool is the ScaleIO Storage Pool associated with the protection domain. - - :schema: io.k8s.api.core.v1.ScaleIOPersistentVolumeSource#storagePool - ''' - result = self._values.get("storage_pool") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def volume_name(self) -> typing.Optional[builtins.str]: - '''volumeName is the name of a volume already created in the ScaleIO system that is associated with this volume source. - - :schema: io.k8s.api.core.v1.ScaleIOPersistentVolumeSource#volumeName - ''' - result = self._values.get("volume_name") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ScaleIoPersistentVolumeSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ScaleIoVolumeSource", - jsii_struct_bases=[], - name_mapping={ - "gateway": "gateway", - "secret_ref": "secretRef", - "system": "system", - "fs_type": "fsType", - "protection_domain": "protectionDomain", - "read_only": "readOnly", - "ssl_enabled": "sslEnabled", - "storage_mode": "storageMode", - "storage_pool": "storagePool", - "volume_name": "volumeName", - }, -) -class ScaleIoVolumeSource: - def __init__( - self, - *, - gateway: builtins.str, - secret_ref: typing.Union[LocalObjectReference, typing.Dict[builtins.str, typing.Any]], - system: builtins.str, - fs_type: typing.Optional[builtins.str] = None, - protection_domain: typing.Optional[builtins.str] = None, - read_only: typing.Optional[builtins.bool] = None, - ssl_enabled: typing.Optional[builtins.bool] = None, - storage_mode: typing.Optional[builtins.str] = None, - storage_pool: typing.Optional[builtins.str] = None, - volume_name: typing.Optional[builtins.str] = None, - ) -> None: - '''ScaleIOVolumeSource represents a persistent ScaleIO volume. - - :param gateway: gateway is the host address of the ScaleIO API Gateway. - :param secret_ref: secretRef references to the secret for ScaleIO user and other sensitive information. If this is not provided, Login operation will fail. - :param system: system is the name of the storage system as configured in ScaleIO. - :param fs_type: fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Default is "xfs". Default: xfs". - :param protection_domain: protectionDomain is the name of the ScaleIO Protection Domain for the configured storage. - :param read_only: readOnly Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. Default: false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. - :param ssl_enabled: sslEnabled Flag enable/disable SSL communication with Gateway, default false. - :param storage_mode: storageMode indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. Default is ThinProvisioned. Default: ThinProvisioned. - :param storage_pool: storagePool is the ScaleIO Storage Pool associated with the protection domain. - :param volume_name: volumeName is the name of a volume already created in the ScaleIO system that is associated with this volume source. - - :schema: io.k8s.api.core.v1.ScaleIOVolumeSource - ''' - if isinstance(secret_ref, dict): - secret_ref = LocalObjectReference(**secret_ref) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__a01207e2538a5a1358fca3cbc8251d3c0eac11c259c7d6e013872e8e0c4e0aff) - check_type(argname="argument gateway", value=gateway, expected_type=type_hints["gateway"]) - check_type(argname="argument secret_ref", value=secret_ref, expected_type=type_hints["secret_ref"]) - check_type(argname="argument system", value=system, expected_type=type_hints["system"]) - check_type(argname="argument fs_type", value=fs_type, expected_type=type_hints["fs_type"]) - check_type(argname="argument protection_domain", value=protection_domain, expected_type=type_hints["protection_domain"]) - check_type(argname="argument read_only", value=read_only, expected_type=type_hints["read_only"]) - check_type(argname="argument ssl_enabled", value=ssl_enabled, expected_type=type_hints["ssl_enabled"]) - check_type(argname="argument storage_mode", value=storage_mode, expected_type=type_hints["storage_mode"]) - check_type(argname="argument storage_pool", value=storage_pool, expected_type=type_hints["storage_pool"]) - check_type(argname="argument volume_name", value=volume_name, expected_type=type_hints["volume_name"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "gateway": gateway, - "secret_ref": secret_ref, - "system": system, - } - if fs_type is not None: - self._values["fs_type"] = fs_type - if protection_domain is not None: - self._values["protection_domain"] = protection_domain - if read_only is not None: - self._values["read_only"] = read_only - if ssl_enabled is not None: - self._values["ssl_enabled"] = ssl_enabled - if storage_mode is not None: - self._values["storage_mode"] = storage_mode - if storage_pool is not None: - self._values["storage_pool"] = storage_pool - if volume_name is not None: - self._values["volume_name"] = volume_name - - @builtins.property - def gateway(self) -> builtins.str: - '''gateway is the host address of the ScaleIO API Gateway. - - :schema: io.k8s.api.core.v1.ScaleIOVolumeSource#gateway - ''' - result = self._values.get("gateway") - assert result is not None, "Required property 'gateway' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def secret_ref(self) -> LocalObjectReference: - '''secretRef references to the secret for ScaleIO user and other sensitive information. - - If this is not provided, Login operation will fail. - - :schema: io.k8s.api.core.v1.ScaleIOVolumeSource#secretRef - ''' - result = self._values.get("secret_ref") - assert result is not None, "Required property 'secret_ref' is missing" - return typing.cast(LocalObjectReference, result) - - @builtins.property - def system(self) -> builtins.str: - '''system is the name of the storage system as configured in ScaleIO. - - :schema: io.k8s.api.core.v1.ScaleIOVolumeSource#system - ''' - result = self._values.get("system") - assert result is not None, "Required property 'system' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def fs_type(self) -> typing.Optional[builtins.str]: - '''fsType is the filesystem type to mount. - - Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Default is "xfs". - - :default: xfs". - - :schema: io.k8s.api.core.v1.ScaleIOVolumeSource#fsType - ''' - result = self._values.get("fs_type") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def protection_domain(self) -> typing.Optional[builtins.str]: - '''protectionDomain is the name of the ScaleIO Protection Domain for the configured storage. - - :schema: io.k8s.api.core.v1.ScaleIOVolumeSource#protectionDomain - ''' - result = self._values.get("protection_domain") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def read_only(self) -> typing.Optional[builtins.bool]: - '''readOnly Defaults to false (read/write). - - ReadOnly here will force the ReadOnly setting in VolumeMounts. - - :default: false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. - - :schema: io.k8s.api.core.v1.ScaleIOVolumeSource#readOnly - ''' - result = self._values.get("read_only") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def ssl_enabled(self) -> typing.Optional[builtins.bool]: - '''sslEnabled Flag enable/disable SSL communication with Gateway, default false. - - :schema: io.k8s.api.core.v1.ScaleIOVolumeSource#sslEnabled - ''' - result = self._values.get("ssl_enabled") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def storage_mode(self) -> typing.Optional[builtins.str]: - '''storageMode indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. - - Default is ThinProvisioned. - - :default: ThinProvisioned. - - :schema: io.k8s.api.core.v1.ScaleIOVolumeSource#storageMode - ''' - result = self._values.get("storage_mode") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def storage_pool(self) -> typing.Optional[builtins.str]: - '''storagePool is the ScaleIO Storage Pool associated with the protection domain. - - :schema: io.k8s.api.core.v1.ScaleIOVolumeSource#storagePool - ''' - result = self._values.get("storage_pool") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def volume_name(self) -> typing.Optional[builtins.str]: - '''volumeName is the name of a volume already created in the ScaleIO system that is associated with this volume source. - - :schema: io.k8s.api.core.v1.ScaleIOVolumeSource#volumeName - ''' - result = self._values.get("volume_name") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ScaleIoVolumeSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ScaleSpec", - jsii_struct_bases=[], - name_mapping={"replicas": "replicas"}, -) -class ScaleSpec: - def __init__(self, *, replicas: typing.Optional[jsii.Number] = None) -> None: - '''ScaleSpec describes the attributes of a scale subresource. - - :param replicas: desired number of instances for the scaled object. - - :schema: io.k8s.api.autoscaling.v1.ScaleSpec - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__933ce43198d2e61bf18cbdc69b1a85d78c4b5059b04255c8eaae6fd004cd796f) - check_type(argname="argument replicas", value=replicas, expected_type=type_hints["replicas"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if replicas is not None: - self._values["replicas"] = replicas - - @builtins.property - def replicas(self) -> typing.Optional[jsii.Number]: - '''desired number of instances for the scaled object. - - :schema: io.k8s.api.autoscaling.v1.ScaleSpec#replicas - ''' - result = self._values.get("replicas") - return typing.cast(typing.Optional[jsii.Number], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ScaleSpec(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.Scheduling", - jsii_struct_bases=[], - name_mapping={"node_selector": "nodeSelector", "tolerations": "tolerations"}, -) -class Scheduling: - def __init__( - self, - *, - node_selector: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - tolerations: typing.Optional[typing.Sequence[typing.Union["Toleration", typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''Scheduling specifies the scheduling constraints for nodes supporting a RuntimeClass. - - :param node_selector: nodeSelector lists labels that must be present on nodes that support this RuntimeClass. Pods using this RuntimeClass can only be scheduled to a node matched by this selector. The RuntimeClass nodeSelector is merged with a pod's existing nodeSelector. Any conflicts will cause the pod to be rejected in admission. - :param tolerations: tolerations are appended (excluding duplicates) to pods running with this RuntimeClass during admission, effectively unioning the set of nodes tolerated by the pod and the RuntimeClass. - - :schema: io.k8s.api.node.v1.Scheduling - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__ec3f34534a8ab02cd430086d5367d2f94c6c0e7343339e7bfc16ee13ddc99d7a) - check_type(argname="argument node_selector", value=node_selector, expected_type=type_hints["node_selector"]) - check_type(argname="argument tolerations", value=tolerations, expected_type=type_hints["tolerations"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if node_selector is not None: - self._values["node_selector"] = node_selector - if tolerations is not None: - self._values["tolerations"] = tolerations - - @builtins.property - def node_selector( - self, - ) -> typing.Optional[typing.Mapping[builtins.str, builtins.str]]: - '''nodeSelector lists labels that must be present on nodes that support this RuntimeClass. - - Pods using this RuntimeClass can only be scheduled to a node matched by this selector. The RuntimeClass nodeSelector is merged with a pod's existing nodeSelector. Any conflicts will cause the pod to be rejected in admission. - - :schema: io.k8s.api.node.v1.Scheduling#nodeSelector - ''' - result = self._values.get("node_selector") - return typing.cast(typing.Optional[typing.Mapping[builtins.str, builtins.str]], result) - - @builtins.property - def tolerations(self) -> typing.Optional[typing.List["Toleration"]]: - '''tolerations are appended (excluding duplicates) to pods running with this RuntimeClass during admission, effectively unioning the set of nodes tolerated by the pod and the RuntimeClass. - - :schema: io.k8s.api.node.v1.Scheduling#tolerations - ''' - result = self._values.get("tolerations") - return typing.cast(typing.Optional[typing.List["Toleration"]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "Scheduling(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ScopeSelector", - jsii_struct_bases=[], - name_mapping={"match_expressions": "matchExpressions"}, -) -class ScopeSelector: - def __init__( - self, - *, - match_expressions: typing.Optional[typing.Sequence[typing.Union["ScopedResourceSelectorRequirement", typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''A scope selector represents the AND of the selectors represented by the scoped-resource selector requirements. - - :param match_expressions: A list of scope selector requirements by scope of the resources. - - :schema: io.k8s.api.core.v1.ScopeSelector - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__9b4391c052c165b6256ea047b5596eab2fcecf19b0a9177b1c5aa1a8485a8d65) - check_type(argname="argument match_expressions", value=match_expressions, expected_type=type_hints["match_expressions"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if match_expressions is not None: - self._values["match_expressions"] = match_expressions - - @builtins.property - def match_expressions( - self, - ) -> typing.Optional[typing.List["ScopedResourceSelectorRequirement"]]: - '''A list of scope selector requirements by scope of the resources. - - :schema: io.k8s.api.core.v1.ScopeSelector#matchExpressions - ''' - result = self._values.get("match_expressions") - return typing.cast(typing.Optional[typing.List["ScopedResourceSelectorRequirement"]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ScopeSelector(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ScopedResourceSelectorRequirement", - jsii_struct_bases=[], - name_mapping={ - "operator": "operator", - "scope_name": "scopeName", - "values": "values", - }, -) -class ScopedResourceSelectorRequirement: - def __init__( - self, - *, - operator: builtins.str, - scope_name: builtins.str, - values: typing.Optional[typing.Sequence[builtins.str]] = None, - ) -> None: - '''A scoped-resource selector requirement is a selector that contains values, a scope name, and an operator that relates the scope name and values. - - :param operator: Represents a scope's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. - :param scope_name: The name of the scope that the selector applies to. - :param values: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. - - :schema: io.k8s.api.core.v1.ScopedResourceSelectorRequirement - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__25d2fa33badd5c55fedc6548e4a9811bdcfdd1569a40592b494f98dd2faa0d58) - check_type(argname="argument operator", value=operator, expected_type=type_hints["operator"]) - check_type(argname="argument scope_name", value=scope_name, expected_type=type_hints["scope_name"]) - check_type(argname="argument values", value=values, expected_type=type_hints["values"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "operator": operator, - "scope_name": scope_name, - } - if values is not None: - self._values["values"] = values - - @builtins.property - def operator(self) -> builtins.str: - '''Represents a scope's relationship to a set of values. - - Valid operators are In, NotIn, Exists, DoesNotExist. - - :schema: io.k8s.api.core.v1.ScopedResourceSelectorRequirement#operator - ''' - result = self._values.get("operator") - assert result is not None, "Required property 'operator' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def scope_name(self) -> builtins.str: - '''The name of the scope that the selector applies to. - - :schema: io.k8s.api.core.v1.ScopedResourceSelectorRequirement#scopeName - ''' - result = self._values.get("scope_name") - assert result is not None, "Required property 'scope_name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def values(self) -> typing.Optional[typing.List[builtins.str]]: - '''An array of string values. - - If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. - - :schema: io.k8s.api.core.v1.ScopedResourceSelectorRequirement#values - ''' - result = self._values.get("values") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ScopedResourceSelectorRequirement(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.SeLinuxOptions", - jsii_struct_bases=[], - name_mapping={"level": "level", "role": "role", "type": "type", "user": "user"}, -) -class SeLinuxOptions: - def __init__( - self, - *, - level: typing.Optional[builtins.str] = None, - role: typing.Optional[builtins.str] = None, - type: typing.Optional[builtins.str] = None, - user: typing.Optional[builtins.str] = None, - ) -> None: - '''SELinuxOptions are the labels to be applied to the container. - - :param level: Level is SELinux level label that applies to the container. - :param role: Role is a SELinux role label that applies to the container. - :param type: Type is a SELinux type label that applies to the container. - :param user: User is a SELinux user label that applies to the container. - - :schema: io.k8s.api.core.v1.SELinuxOptions - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__83c2afea88042856c9e697502b222fdab3ba5aa314b8db7832e18390438f4cae) - check_type(argname="argument level", value=level, expected_type=type_hints["level"]) - check_type(argname="argument role", value=role, expected_type=type_hints["role"]) - check_type(argname="argument type", value=type, expected_type=type_hints["type"]) - check_type(argname="argument user", value=user, expected_type=type_hints["user"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if level is not None: - self._values["level"] = level - if role is not None: - self._values["role"] = role - if type is not None: - self._values["type"] = type - if user is not None: - self._values["user"] = user - - @builtins.property - def level(self) -> typing.Optional[builtins.str]: - '''Level is SELinux level label that applies to the container. - - :schema: io.k8s.api.core.v1.SELinuxOptions#level - ''' - result = self._values.get("level") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def role(self) -> typing.Optional[builtins.str]: - '''Role is a SELinux role label that applies to the container. - - :schema: io.k8s.api.core.v1.SELinuxOptions#role - ''' - result = self._values.get("role") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def type(self) -> typing.Optional[builtins.str]: - '''Type is a SELinux type label that applies to the container. - - :schema: io.k8s.api.core.v1.SELinuxOptions#type - ''' - result = self._values.get("type") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def user(self) -> typing.Optional[builtins.str]: - '''User is a SELinux user label that applies to the container. - - :schema: io.k8s.api.core.v1.SELinuxOptions#user - ''' - result = self._values.get("user") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "SeLinuxOptions(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.SeccompProfile", - jsii_struct_bases=[], - name_mapping={"type": "type", "localhost_profile": "localhostProfile"}, -) -class SeccompProfile: - def __init__( - self, - *, - type: builtins.str, - localhost_profile: typing.Optional[builtins.str] = None, - ) -> None: - '''SeccompProfile defines a pod/container's seccomp profile settings. - - Only one profile source may be set. - - :param type: type indicates which kind of seccomp profile will be applied. Valid options are:. Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied. - :param localhost_profile: localhostProfile indicates a profile defined in a file on the node should be used. The profile must be preconfigured on the node to work. Must be a descending path, relative to the kubelet's configured seccomp profile location. Must only be set if type is "Localhost". - - :schema: io.k8s.api.core.v1.SeccompProfile - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__671e277701b07860347cc95c432e5605a89c2d148bebfccaead627a5b559eba4) - check_type(argname="argument type", value=type, expected_type=type_hints["type"]) - check_type(argname="argument localhost_profile", value=localhost_profile, expected_type=type_hints["localhost_profile"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "type": type, - } - if localhost_profile is not None: - self._values["localhost_profile"] = localhost_profile - - @builtins.property - def type(self) -> builtins.str: - '''type indicates which kind of seccomp profile will be applied. Valid options are:. - - Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied. - - :schema: io.k8s.api.core.v1.SeccompProfile#type - ''' - result = self._values.get("type") - assert result is not None, "Required property 'type' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def localhost_profile(self) -> typing.Optional[builtins.str]: - '''localhostProfile indicates a profile defined in a file on the node should be used. - - The profile must be preconfigured on the node to work. Must be a descending path, relative to the kubelet's configured seccomp profile location. Must only be set if type is "Localhost". - - :schema: io.k8s.api.core.v1.SeccompProfile#localhostProfile - ''' - result = self._values.get("localhost_profile") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "SeccompProfile(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.SecretEnvSource", - jsii_struct_bases=[], - name_mapping={"name": "name", "optional": "optional"}, -) -class SecretEnvSource: - def __init__( - self, - *, - name: typing.Optional[builtins.str] = None, - optional: typing.Optional[builtins.bool] = None, - ) -> None: - '''SecretEnvSource selects a Secret to populate the environment variables with. - - The contents of the target Secret's Data field will represent the key-value pairs as environment variables. - - :param name: Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - :param optional: Specify whether the Secret must be defined. - - :schema: io.k8s.api.core.v1.SecretEnvSource - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__8d52030565d59aad237de569c2f9746d89c90816ecd991ddc7b7ea6624d871ff) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument optional", value=optional, expected_type=type_hints["optional"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if name is not None: - self._values["name"] = name - if optional is not None: - self._values["optional"] = optional - - @builtins.property - def name(self) -> typing.Optional[builtins.str]: - '''Name of the referent. - - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - - :schema: io.k8s.api.core.v1.SecretEnvSource#name - ''' - result = self._values.get("name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def optional(self) -> typing.Optional[builtins.bool]: - '''Specify whether the Secret must be defined. - - :schema: io.k8s.api.core.v1.SecretEnvSource#optional - ''' - result = self._values.get("optional") - return typing.cast(typing.Optional[builtins.bool], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "SecretEnvSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.SecretKeySelector", - jsii_struct_bases=[], - name_mapping={"key": "key", "name": "name", "optional": "optional"}, -) -class SecretKeySelector: - def __init__( - self, - *, - key: builtins.str, - name: typing.Optional[builtins.str] = None, - optional: typing.Optional[builtins.bool] = None, - ) -> None: - '''SecretKeySelector selects a key of a Secret. - - :param key: The key of the secret to select from. Must be a valid secret key. - :param name: Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - :param optional: Specify whether the Secret or its key must be defined. - - :schema: io.k8s.api.core.v1.SecretKeySelector - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__10d7b89d6873826406c0f3f0882c9b1e23eec486efebbb601cb05ef478c62925) - check_type(argname="argument key", value=key, expected_type=type_hints["key"]) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument optional", value=optional, expected_type=type_hints["optional"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "key": key, - } - if name is not None: - self._values["name"] = name - if optional is not None: - self._values["optional"] = optional - - @builtins.property - def key(self) -> builtins.str: - '''The key of the secret to select from. - - Must be a valid secret key. - - :schema: io.k8s.api.core.v1.SecretKeySelector#key - ''' - result = self._values.get("key") - assert result is not None, "Required property 'key' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def name(self) -> typing.Optional[builtins.str]: - '''Name of the referent. - - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - - :schema: io.k8s.api.core.v1.SecretKeySelector#name - ''' - result = self._values.get("name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def optional(self) -> typing.Optional[builtins.bool]: - '''Specify whether the Secret or its key must be defined. - - :schema: io.k8s.api.core.v1.SecretKeySelector#optional - ''' - result = self._values.get("optional") - return typing.cast(typing.Optional[builtins.bool], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "SecretKeySelector(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.SecretProjection", - jsii_struct_bases=[], - name_mapping={"items": "items", "name": "name", "optional": "optional"}, -) -class SecretProjection: - def __init__( - self, - *, - items: typing.Optional[typing.Sequence[typing.Union[KeyToPath, typing.Dict[builtins.str, typing.Any]]]] = None, - name: typing.Optional[builtins.str] = None, - optional: typing.Optional[builtins.bool] = None, - ) -> None: - '''Adapts a secret into a projected volume. - - The contents of the target Secret's Data field will be presented in a projected volume as files using the keys in the Data field as the file names. Note that this is identical to a secret volume source without the default mode. - - :param items: items if unspecified, each key-value pair in the Data field of the referenced Secret will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the Secret, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'. - :param name: Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - :param optional: optional field specify whether the Secret or its key must be defined. - - :schema: io.k8s.api.core.v1.SecretProjection - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__cef90561db8db5a4c9a8b89a6f3b87e04f52ca6ca4775954c0d0434b48021869) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument optional", value=optional, expected_type=type_hints["optional"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if items is not None: - self._values["items"] = items - if name is not None: - self._values["name"] = name - if optional is not None: - self._values["optional"] = optional - - @builtins.property - def items(self) -> typing.Optional[typing.List[KeyToPath]]: - '''items if unspecified, each key-value pair in the Data field of the referenced Secret will be projected into the volume as a file whose name is the key and content is the value. - - If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the Secret, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'. - - :schema: io.k8s.api.core.v1.SecretProjection#items - ''' - result = self._values.get("items") - return typing.cast(typing.Optional[typing.List[KeyToPath]], result) - - @builtins.property - def name(self) -> typing.Optional[builtins.str]: - '''Name of the referent. - - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - - :schema: io.k8s.api.core.v1.SecretProjection#name - ''' - result = self._values.get("name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def optional(self) -> typing.Optional[builtins.bool]: - '''optional field specify whether the Secret or its key must be defined. - - :schema: io.k8s.api.core.v1.SecretProjection#optional - ''' - result = self._values.get("optional") - return typing.cast(typing.Optional[builtins.bool], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "SecretProjection(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.SecretReference", - jsii_struct_bases=[], - name_mapping={"name": "name", "namespace": "namespace"}, -) -class SecretReference: - def __init__( - self, - *, - name: typing.Optional[builtins.str] = None, - namespace: typing.Optional[builtins.str] = None, - ) -> None: - '''SecretReference represents a Secret Reference. - - It has enough information to retrieve secret in any namespace - - :param name: name is unique within a namespace to reference a secret resource. - :param namespace: namespace defines the space within which the secret name must be unique. - - :schema: io.k8s.api.core.v1.SecretReference - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__7a151e3e3fd089bf4b7fe70426a9c364c57d5a3d0a27a642e74873d5c32aba01) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument namespace", value=namespace, expected_type=type_hints["namespace"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if name is not None: - self._values["name"] = name - if namespace is not None: - self._values["namespace"] = namespace - - @builtins.property - def name(self) -> typing.Optional[builtins.str]: - '''name is unique within a namespace to reference a secret resource. - - :schema: io.k8s.api.core.v1.SecretReference#name - ''' - result = self._values.get("name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def namespace(self) -> typing.Optional[builtins.str]: - '''namespace defines the space within which the secret name must be unique. - - :schema: io.k8s.api.core.v1.SecretReference#namespace - ''' - result = self._values.get("namespace") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "SecretReference(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.SecretVolumeSource", - jsii_struct_bases=[], - name_mapping={ - "default_mode": "defaultMode", - "items": "items", - "optional": "optional", - "secret_name": "secretName", - }, -) -class SecretVolumeSource: - def __init__( - self, - *, - default_mode: typing.Optional[jsii.Number] = None, - items: typing.Optional[typing.Sequence[typing.Union[KeyToPath, typing.Dict[builtins.str, typing.Any]]]] = None, - optional: typing.Optional[builtins.bool] = None, - secret_name: typing.Optional[builtins.str] = None, - ) -> None: - '''Adapts a Secret into a volume. - - The contents of the target Secret's Data field will be presented in a volume as files using the keys in the Data field as the file names. Secret volumes support ownership management and SELinux relabeling. - - :param default_mode: defaultMode is Optional: mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set. Default: 644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set. - :param items: items If unspecified, each key-value pair in the Data field of the referenced Secret will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the Secret, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'. - :param optional: optional field specify whether the Secret or its keys must be defined. - :param secret_name: secretName is the name of the secret in the pod's namespace to use. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret - - :schema: io.k8s.api.core.v1.SecretVolumeSource - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__25d6ed85323c7db8b962d40135ed579f6269a43590382c950b1f670739dd5d9c) - check_type(argname="argument default_mode", value=default_mode, expected_type=type_hints["default_mode"]) - check_type(argname="argument items", value=items, expected_type=type_hints["items"]) - check_type(argname="argument optional", value=optional, expected_type=type_hints["optional"]) - check_type(argname="argument secret_name", value=secret_name, expected_type=type_hints["secret_name"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if default_mode is not None: - self._values["default_mode"] = default_mode - if items is not None: - self._values["items"] = items - if optional is not None: - self._values["optional"] = optional - if secret_name is not None: - self._values["secret_name"] = secret_name - - @builtins.property - def default_mode(self) -> typing.Optional[jsii.Number]: - '''defaultMode is Optional: mode bits used to set permissions on created files by default. - - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set. - - :default: 644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set. - - :schema: io.k8s.api.core.v1.SecretVolumeSource#defaultMode - ''' - result = self._values.get("default_mode") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def items(self) -> typing.Optional[typing.List[KeyToPath]]: - '''items If unspecified, each key-value pair in the Data field of the referenced Secret will be projected into the volume as a file whose name is the key and content is the value. - - If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the Secret, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'. - - :schema: io.k8s.api.core.v1.SecretVolumeSource#items - ''' - result = self._values.get("items") - return typing.cast(typing.Optional[typing.List[KeyToPath]], result) - - @builtins.property - def optional(self) -> typing.Optional[builtins.bool]: - '''optional field specify whether the Secret or its keys must be defined. - - :schema: io.k8s.api.core.v1.SecretVolumeSource#optional - ''' - result = self._values.get("optional") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def secret_name(self) -> typing.Optional[builtins.str]: - '''secretName is the name of the secret in the pod's namespace to use. - - More info: https://kubernetes.io/docs/concepts/storage/volumes#secret - - :schema: io.k8s.api.core.v1.SecretVolumeSource#secretName - ''' - result = self._values.get("secret_name") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "SecretVolumeSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.SecurityContext", - jsii_struct_bases=[], - name_mapping={ - "allow_privilege_escalation": "allowPrivilegeEscalation", - "capabilities": "capabilities", - "privileged": "privileged", - "proc_mount": "procMount", - "read_only_root_filesystem": "readOnlyRootFilesystem", - "run_as_group": "runAsGroup", - "run_as_non_root": "runAsNonRoot", - "run_as_user": "runAsUser", - "seccomp_profile": "seccompProfile", - "se_linux_options": "seLinuxOptions", - "windows_options": "windowsOptions", - }, -) -class SecurityContext: - def __init__( - self, - *, - allow_privilege_escalation: typing.Optional[builtins.bool] = None, - capabilities: typing.Optional[typing.Union[Capabilities, typing.Dict[builtins.str, typing.Any]]] = None, - privileged: typing.Optional[builtins.bool] = None, - proc_mount: typing.Optional[builtins.str] = None, - read_only_root_filesystem: typing.Optional[builtins.bool] = None, - run_as_group: typing.Optional[jsii.Number] = None, - run_as_non_root: typing.Optional[builtins.bool] = None, - run_as_user: typing.Optional[jsii.Number] = None, - seccomp_profile: typing.Optional[typing.Union[SeccompProfile, typing.Dict[builtins.str, typing.Any]]] = None, - se_linux_options: typing.Optional[typing.Union[SeLinuxOptions, typing.Dict[builtins.str, typing.Any]]] = None, - windows_options: typing.Optional[typing.Union["WindowsSecurityContextOptions", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''SecurityContext holds security configuration that will be applied to a container. - - Some fields are present in both SecurityContext and PodSecurityContext. When both are set, the values in SecurityContext take precedence. - - :param allow_privilege_escalation: AllowPrivilegeEscalation controls whether a process can gain more privileges than its parent process. This bool directly controls if the no_new_privs flag will be set on the container process. AllowPrivilegeEscalation is true always when the container is: 1) run as Privileged 2) has CAP_SYS_ADMIN Note that this field cannot be set when spec.os.name is windows. - :param capabilities: The capabilities to add/drop when running containers. Defaults to the default set of capabilities granted by the container runtime. Note that this field cannot be set when spec.os.name is windows. Default: the default set of capabilities granted by the container runtime. Note that this field cannot be set when spec.os.name is windows. - :param privileged: Run container in privileged mode. Processes in privileged containers are essentially equivalent to root on the host. Defaults to false. Note that this field cannot be set when spec.os.name is windows. Default: false. Note that this field cannot be set when spec.os.name is windows. - :param proc_mount: procMount denotes the type of proc mount to use for the containers. The default is DefaultProcMount which uses the container runtime defaults for readonly paths and masked paths. This requires the ProcMountType feature flag to be enabled. Note that this field cannot be set when spec.os.name is windows. - :param read_only_root_filesystem: Whether this container has a read-only root filesystem. Default is false. Note that this field cannot be set when spec.os.name is windows. Default: false. Note that this field cannot be set when spec.os.name is windows. - :param run_as_group: The GID to run the entrypoint of the container process. Uses runtime default if unset. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. Note that this field cannot be set when spec.os.name is windows. - :param run_as_non_root: Indicates that the container must run as a non-root user. If true, the Kubelet will validate the image at runtime to ensure that it does not run as UID 0 (root) and fail to start the container if it does. If unset or false, no such validation will be performed. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. - :param run_as_user: The UID to run the entrypoint of the container process. Defaults to user specified in image metadata if unspecified. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. Note that this field cannot be set when spec.os.name is windows. Default: user specified in image metadata if unspecified. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. Note that this field cannot be set when spec.os.name is windows. - :param seccomp_profile: The seccomp options to use by this container. If seccomp options are provided at both the pod & container level, the container options override the pod options. Note that this field cannot be set when spec.os.name is windows. - :param se_linux_options: The SELinux context to be applied to the container. If unspecified, the container runtime will allocate a random SELinux context for each container. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. Note that this field cannot be set when spec.os.name is windows. - :param windows_options: The Windows specific settings applied to all containers. If unspecified, the options from the PodSecurityContext will be used. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. Note that this field cannot be set when spec.os.name is linux. - - :schema: io.k8s.api.core.v1.SecurityContext - ''' - if isinstance(capabilities, dict): - capabilities = Capabilities(**capabilities) - if isinstance(seccomp_profile, dict): - seccomp_profile = SeccompProfile(**seccomp_profile) - if isinstance(se_linux_options, dict): - se_linux_options = SeLinuxOptions(**se_linux_options) - if isinstance(windows_options, dict): - windows_options = WindowsSecurityContextOptions(**windows_options) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__433d0b1cb870f05b48bfb6eeb4e8d9af769be17981b3d3465be0319c5fdcfe58) - check_type(argname="argument allow_privilege_escalation", value=allow_privilege_escalation, expected_type=type_hints["allow_privilege_escalation"]) - check_type(argname="argument capabilities", value=capabilities, expected_type=type_hints["capabilities"]) - check_type(argname="argument privileged", value=privileged, expected_type=type_hints["privileged"]) - check_type(argname="argument proc_mount", value=proc_mount, expected_type=type_hints["proc_mount"]) - check_type(argname="argument read_only_root_filesystem", value=read_only_root_filesystem, expected_type=type_hints["read_only_root_filesystem"]) - check_type(argname="argument run_as_group", value=run_as_group, expected_type=type_hints["run_as_group"]) - check_type(argname="argument run_as_non_root", value=run_as_non_root, expected_type=type_hints["run_as_non_root"]) - check_type(argname="argument run_as_user", value=run_as_user, expected_type=type_hints["run_as_user"]) - check_type(argname="argument seccomp_profile", value=seccomp_profile, expected_type=type_hints["seccomp_profile"]) - check_type(argname="argument se_linux_options", value=se_linux_options, expected_type=type_hints["se_linux_options"]) - check_type(argname="argument windows_options", value=windows_options, expected_type=type_hints["windows_options"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if allow_privilege_escalation is not None: - self._values["allow_privilege_escalation"] = allow_privilege_escalation - if capabilities is not None: - self._values["capabilities"] = capabilities - if privileged is not None: - self._values["privileged"] = privileged - if proc_mount is not None: - self._values["proc_mount"] = proc_mount - if read_only_root_filesystem is not None: - self._values["read_only_root_filesystem"] = read_only_root_filesystem - if run_as_group is not None: - self._values["run_as_group"] = run_as_group - if run_as_non_root is not None: - self._values["run_as_non_root"] = run_as_non_root - if run_as_user is not None: - self._values["run_as_user"] = run_as_user - if seccomp_profile is not None: - self._values["seccomp_profile"] = seccomp_profile - if se_linux_options is not None: - self._values["se_linux_options"] = se_linux_options - if windows_options is not None: - self._values["windows_options"] = windows_options - - @builtins.property - def allow_privilege_escalation(self) -> typing.Optional[builtins.bool]: - '''AllowPrivilegeEscalation controls whether a process can gain more privileges than its parent process. - - This bool directly controls if the no_new_privs flag will be set on the container process. AllowPrivilegeEscalation is true always when the container is: 1) run as Privileged 2) has CAP_SYS_ADMIN Note that this field cannot be set when spec.os.name is windows. - - :schema: io.k8s.api.core.v1.SecurityContext#allowPrivilegeEscalation - ''' - result = self._values.get("allow_privilege_escalation") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def capabilities(self) -> typing.Optional[Capabilities]: - '''The capabilities to add/drop when running containers. - - Defaults to the default set of capabilities granted by the container runtime. Note that this field cannot be set when spec.os.name is windows. - - :default: the default set of capabilities granted by the container runtime. Note that this field cannot be set when spec.os.name is windows. - - :schema: io.k8s.api.core.v1.SecurityContext#capabilities - ''' - result = self._values.get("capabilities") - return typing.cast(typing.Optional[Capabilities], result) - - @builtins.property - def privileged(self) -> typing.Optional[builtins.bool]: - '''Run container in privileged mode. - - Processes in privileged containers are essentially equivalent to root on the host. Defaults to false. Note that this field cannot be set when spec.os.name is windows. - - :default: false. Note that this field cannot be set when spec.os.name is windows. - - :schema: io.k8s.api.core.v1.SecurityContext#privileged - ''' - result = self._values.get("privileged") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def proc_mount(self) -> typing.Optional[builtins.str]: - '''procMount denotes the type of proc mount to use for the containers. - - The default is DefaultProcMount which uses the container runtime defaults for readonly paths and masked paths. This requires the ProcMountType feature flag to be enabled. Note that this field cannot be set when spec.os.name is windows. - - :schema: io.k8s.api.core.v1.SecurityContext#procMount - ''' - result = self._values.get("proc_mount") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def read_only_root_filesystem(self) -> typing.Optional[builtins.bool]: - '''Whether this container has a read-only root filesystem. - - Default is false. Note that this field cannot be set when spec.os.name is windows. - - :default: false. Note that this field cannot be set when spec.os.name is windows. - - :schema: io.k8s.api.core.v1.SecurityContext#readOnlyRootFilesystem - ''' - result = self._values.get("read_only_root_filesystem") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def run_as_group(self) -> typing.Optional[jsii.Number]: - '''The GID to run the entrypoint of the container process. - - Uses runtime default if unset. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. Note that this field cannot be set when spec.os.name is windows. - - :schema: io.k8s.api.core.v1.SecurityContext#runAsGroup - ''' - result = self._values.get("run_as_group") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def run_as_non_root(self) -> typing.Optional[builtins.bool]: - '''Indicates that the container must run as a non-root user. - - If true, the Kubelet will validate the image at runtime to ensure that it does not run as UID 0 (root) and fail to start the container if it does. If unset or false, no such validation will be performed. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. - - :schema: io.k8s.api.core.v1.SecurityContext#runAsNonRoot - ''' - result = self._values.get("run_as_non_root") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def run_as_user(self) -> typing.Optional[jsii.Number]: - '''The UID to run the entrypoint of the container process. - - Defaults to user specified in image metadata if unspecified. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. Note that this field cannot be set when spec.os.name is windows. - - :default: user specified in image metadata if unspecified. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. Note that this field cannot be set when spec.os.name is windows. - - :schema: io.k8s.api.core.v1.SecurityContext#runAsUser - ''' - result = self._values.get("run_as_user") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def seccomp_profile(self) -> typing.Optional[SeccompProfile]: - '''The seccomp options to use by this container. - - If seccomp options are provided at both the pod & container level, the container options override the pod options. Note that this field cannot be set when spec.os.name is windows. - - :schema: io.k8s.api.core.v1.SecurityContext#seccompProfile - ''' - result = self._values.get("seccomp_profile") - return typing.cast(typing.Optional[SeccompProfile], result) - - @builtins.property - def se_linux_options(self) -> typing.Optional[SeLinuxOptions]: - '''The SELinux context to be applied to the container. - - If unspecified, the container runtime will allocate a random SELinux context for each container. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. Note that this field cannot be set when spec.os.name is windows. - - :schema: io.k8s.api.core.v1.SecurityContext#seLinuxOptions - ''' - result = self._values.get("se_linux_options") - return typing.cast(typing.Optional[SeLinuxOptions], result) - - @builtins.property - def windows_options(self) -> typing.Optional["WindowsSecurityContextOptions"]: - '''The Windows specific settings applied to all containers. - - If unspecified, the options from the PodSecurityContext will be used. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. Note that this field cannot be set when spec.os.name is linux. - - :schema: io.k8s.api.core.v1.SecurityContext#windowsOptions - ''' - result = self._values.get("windows_options") - return typing.cast(typing.Optional["WindowsSecurityContextOptions"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "SecurityContext(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.SelfSubjectAccessReviewSpec", - jsii_struct_bases=[], - name_mapping={ - "non_resource_attributes": "nonResourceAttributes", - "resource_attributes": "resourceAttributes", - }, -) -class SelfSubjectAccessReviewSpec: - def __init__( - self, - *, - non_resource_attributes: typing.Optional[typing.Union[NonResourceAttributes, typing.Dict[builtins.str, typing.Any]]] = None, - resource_attributes: typing.Optional[typing.Union[ResourceAttributes, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''SelfSubjectAccessReviewSpec is a description of the access request. - - Exactly one of ResourceAuthorizationAttributes and NonResourceAuthorizationAttributes must be set - - :param non_resource_attributes: NonResourceAttributes describes information for a non-resource access request. - :param resource_attributes: ResourceAuthorizationAttributes describes information for a resource access request. - - :schema: io.k8s.api.authorization.v1.SelfSubjectAccessReviewSpec - ''' - if isinstance(non_resource_attributes, dict): - non_resource_attributes = NonResourceAttributes(**non_resource_attributes) - if isinstance(resource_attributes, dict): - resource_attributes = ResourceAttributes(**resource_attributes) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__e1c2bf0513f041ce3e18333d43a5849dff775b6c0bf8ea1391d425c73771a607) - check_type(argname="argument non_resource_attributes", value=non_resource_attributes, expected_type=type_hints["non_resource_attributes"]) - check_type(argname="argument resource_attributes", value=resource_attributes, expected_type=type_hints["resource_attributes"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if non_resource_attributes is not None: - self._values["non_resource_attributes"] = non_resource_attributes - if resource_attributes is not None: - self._values["resource_attributes"] = resource_attributes - - @builtins.property - def non_resource_attributes(self) -> typing.Optional[NonResourceAttributes]: - '''NonResourceAttributes describes information for a non-resource access request. - - :schema: io.k8s.api.authorization.v1.SelfSubjectAccessReviewSpec#nonResourceAttributes - ''' - result = self._values.get("non_resource_attributes") - return typing.cast(typing.Optional[NonResourceAttributes], result) - - @builtins.property - def resource_attributes(self) -> typing.Optional[ResourceAttributes]: - '''ResourceAuthorizationAttributes describes information for a resource access request. - - :schema: io.k8s.api.authorization.v1.SelfSubjectAccessReviewSpec#resourceAttributes - ''' - result = self._values.get("resource_attributes") - return typing.cast(typing.Optional[ResourceAttributes], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "SelfSubjectAccessReviewSpec(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.SelfSubjectRulesReviewSpec", - jsii_struct_bases=[], - name_mapping={"namespace": "namespace"}, -) -class SelfSubjectRulesReviewSpec: - def __init__(self, *, namespace: typing.Optional[builtins.str] = None) -> None: - '''SelfSubjectRulesReviewSpec defines the specification for SelfSubjectRulesReview. - - :param namespace: Namespace to evaluate rules for. Required. - - :schema: io.k8s.api.authorization.v1.SelfSubjectRulesReviewSpec - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__e8dd2a0d136f9e7e8480f73531aaae29fb249c5b4c11d47022b16354c78aace9) - check_type(argname="argument namespace", value=namespace, expected_type=type_hints["namespace"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if namespace is not None: - self._values["namespace"] = namespace - - @builtins.property - def namespace(self) -> typing.Optional[builtins.str]: - '''Namespace to evaluate rules for. - - Required. - - :schema: io.k8s.api.authorization.v1.SelfSubjectRulesReviewSpec#namespace - ''' - result = self._values.get("namespace") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "SelfSubjectRulesReviewSpec(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ServiceAccountSubjectV1Beta2", - jsii_struct_bases=[], - name_mapping={"name": "name", "namespace": "namespace"}, -) -class ServiceAccountSubjectV1Beta2: - def __init__(self, *, name: builtins.str, namespace: builtins.str) -> None: - '''ServiceAccountSubject holds detailed information for service-account-kind subject. - - :param name: ``name`` is the name of matching ServiceAccount objects, or "*" to match regardless of name. Required. - :param namespace: ``namespace`` is the namespace of matching ServiceAccount objects. Required. - - :schema: io.k8s.api.flowcontrol.v1beta2.ServiceAccountSubject - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__ed7e13eb7021a2b0809d1809b6e9d20476c12f8399abed5e9535445cd3a54214) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument namespace", value=namespace, expected_type=type_hints["namespace"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "name": name, - "namespace": namespace, - } - - @builtins.property - def name(self) -> builtins.str: - '''``name`` is the name of matching ServiceAccount objects, or "*" to match regardless of name. - - Required. - - :schema: io.k8s.api.flowcontrol.v1beta2.ServiceAccountSubject#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def namespace(self) -> builtins.str: - '''``namespace`` is the namespace of matching ServiceAccount objects. - - Required. - - :schema: io.k8s.api.flowcontrol.v1beta2.ServiceAccountSubject#namespace - ''' - result = self._values.get("namespace") - assert result is not None, "Required property 'namespace' is missing" - return typing.cast(builtins.str, result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ServiceAccountSubjectV1Beta2(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ServiceAccountSubjectV1Beta3", - jsii_struct_bases=[], - name_mapping={"name": "name", "namespace": "namespace"}, -) -class ServiceAccountSubjectV1Beta3: - def __init__(self, *, name: builtins.str, namespace: builtins.str) -> None: - '''ServiceAccountSubject holds detailed information for service-account-kind subject. - - :param name: ``name`` is the name of matching ServiceAccount objects, or "*" to match regardless of name. Required. - :param namespace: ``namespace`` is the namespace of matching ServiceAccount objects. Required. - - :schema: io.k8s.api.flowcontrol.v1beta3.ServiceAccountSubject - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__324da826cf3bc07c48d0532607d6bac7ab807122d6cde1c86aaf149e3ac5a926) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument namespace", value=namespace, expected_type=type_hints["namespace"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "name": name, - "namespace": namespace, - } - - @builtins.property - def name(self) -> builtins.str: - '''``name`` is the name of matching ServiceAccount objects, or "*" to match regardless of name. - - Required. - - :schema: io.k8s.api.flowcontrol.v1beta3.ServiceAccountSubject#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def namespace(self) -> builtins.str: - '''``namespace`` is the namespace of matching ServiceAccount objects. - - Required. - - :schema: io.k8s.api.flowcontrol.v1beta3.ServiceAccountSubject#namespace - ''' - result = self._values.get("namespace") - assert result is not None, "Required property 'namespace' is missing" - return typing.cast(builtins.str, result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ServiceAccountSubjectV1Beta3(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ServiceAccountTokenProjection", - jsii_struct_bases=[], - name_mapping={ - "path": "path", - "audience": "audience", - "expiration_seconds": "expirationSeconds", - }, -) -class ServiceAccountTokenProjection: - def __init__( - self, - *, - path: builtins.str, - audience: typing.Optional[builtins.str] = None, - expiration_seconds: typing.Optional[jsii.Number] = None, - ) -> None: - '''ServiceAccountTokenProjection represents a projected service account token volume. - - This projection can be used to insert a service account token into the pods runtime filesystem for use against APIs (Kubernetes API Server or otherwise). - - :param path: path is the path relative to the mount point of the file to project the token into. - :param audience: audience is the intended audience of the token. A recipient of a token must identify itself with an identifier specified in the audience of the token, and otherwise should reject the token. The audience defaults to the identifier of the apiserver. - :param expiration_seconds: expirationSeconds is the requested duration of validity of the service account token. As the token approaches expiration, the kubelet volume plugin will proactively rotate the service account token. The kubelet will start trying to rotate the token if the token is older than 80 percent of its time to live or if the token is older than 24 hours.Defaults to 1 hour and must be at least 10 minutes. Default: 1 hour and must be at least 10 minutes. - - :schema: io.k8s.api.core.v1.ServiceAccountTokenProjection - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__eca876ebc0d31f3618cfee4eac3e898196a37c6e4c1f8a9e32ddf0170545dcb7) - check_type(argname="argument path", value=path, expected_type=type_hints["path"]) - check_type(argname="argument audience", value=audience, expected_type=type_hints["audience"]) - check_type(argname="argument expiration_seconds", value=expiration_seconds, expected_type=type_hints["expiration_seconds"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "path": path, - } - if audience is not None: - self._values["audience"] = audience - if expiration_seconds is not None: - self._values["expiration_seconds"] = expiration_seconds - - @builtins.property - def path(self) -> builtins.str: - '''path is the path relative to the mount point of the file to project the token into. - - :schema: io.k8s.api.core.v1.ServiceAccountTokenProjection#path - ''' - result = self._values.get("path") - assert result is not None, "Required property 'path' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def audience(self) -> typing.Optional[builtins.str]: - '''audience is the intended audience of the token. - - A recipient of a token must identify itself with an identifier specified in the audience of the token, and otherwise should reject the token. The audience defaults to the identifier of the apiserver. - - :schema: io.k8s.api.core.v1.ServiceAccountTokenProjection#audience - ''' - result = self._values.get("audience") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def expiration_seconds(self) -> typing.Optional[jsii.Number]: - '''expirationSeconds is the requested duration of validity of the service account token. - - As the token approaches expiration, the kubelet volume plugin will proactively rotate the service account token. The kubelet will start trying to rotate the token if the token is older than 80 percent of its time to live or if the token is older than 24 hours.Defaults to 1 hour and must be at least 10 minutes. - - :default: 1 hour and must be at least 10 minutes. - - :schema: io.k8s.api.core.v1.ServiceAccountTokenProjection#expirationSeconds - ''' - result = self._values.get("expiration_seconds") - return typing.cast(typing.Optional[jsii.Number], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ServiceAccountTokenProjection(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ServiceBackendPort", - jsii_struct_bases=[], - name_mapping={"name": "name", "number": "number"}, -) -class ServiceBackendPort: - def __init__( - self, - *, - name: typing.Optional[builtins.str] = None, - number: typing.Optional[jsii.Number] = None, - ) -> None: - '''ServiceBackendPort is the service port being referenced. - - :param name: Name is the name of the port on the Service. This is a mutually exclusive setting with "Number". - :param number: Number is the numerical port number (e.g. 80) on the Service. This is a mutually exclusive setting with "Name". - - :schema: io.k8s.api.networking.v1.ServiceBackendPort - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__ccc9db063c0edd035d30aa78a916f1d768a960f314c38168ba4c4e95ca2ae99e) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument number", value=number, expected_type=type_hints["number"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if name is not None: - self._values["name"] = name - if number is not None: - self._values["number"] = number - - @builtins.property - def name(self) -> typing.Optional[builtins.str]: - '''Name is the name of the port on the Service. - - This is a mutually exclusive setting with "Number". - - :schema: io.k8s.api.networking.v1.ServiceBackendPort#name - ''' - result = self._values.get("name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def number(self) -> typing.Optional[jsii.Number]: - '''Number is the numerical port number (e.g. 80) on the Service. This is a mutually exclusive setting with "Name". - - :schema: io.k8s.api.networking.v1.ServiceBackendPort#number - ''' - result = self._values.get("number") - return typing.cast(typing.Optional[jsii.Number], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ServiceBackendPort(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ServicePort", - jsii_struct_bases=[], - name_mapping={ - "port": "port", - "app_protocol": "appProtocol", - "name": "name", - "node_port": "nodePort", - "protocol": "protocol", - "target_port": "targetPort", - }, -) -class ServicePort: - def __init__( - self, - *, - port: jsii.Number, - app_protocol: typing.Optional[builtins.str] = None, - name: typing.Optional[builtins.str] = None, - node_port: typing.Optional[jsii.Number] = None, - protocol: typing.Optional[builtins.str] = None, - target_port: typing.Optional[IntOrString] = None, - ) -> None: - '''ServicePort contains information on service's port. - - :param port: The port that will be exposed by this service. - :param app_protocol: The application protocol for this port. This field follows standard Kubernetes label syntax. Un-prefixed names are reserved for IANA standard service names (as per RFC-6335 and https://www.iana.org/assignments/service-names). Non-standard protocols should use prefixed names such as mycompany.com/my-custom-protocol. - :param name: The name of this port within the service. This must be a DNS_LABEL. All ports within a ServiceSpec must have unique names. When considering the endpoints for a Service, this must match the 'name' field in the EndpointPort. Optional if only one ServicePort is defined on this service. - :param node_port: The port on each node on which this service is exposed when type is NodePort or LoadBalancer. Usually assigned by the system. If a value is specified, in-range, and not in use it will be used, otherwise the operation will fail. If not specified, a port will be allocated if this Service requires one. If this field is specified when creating a Service which does not need it, creation will fail. This field will be wiped when updating a Service to no longer need it (e.g. changing type from NodePort to ClusterIP). More info: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport - :param protocol: The IP protocol for this port. Supports "TCP", "UDP", and "SCTP". Default is TCP. Default: TCP. - :param target_port: Number or name of the port to access on the pods targeted by the service. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. If this is a string, it will be looked up as a named port in the target Pod's container ports. If this is not specified, the value of the 'port' field is used (an identity map). This field is ignored for services with clusterIP=None, and should be omitted or set equal to the 'port' field. More info: https://kubernetes.io/docs/concepts/services-networking/service/#defining-a-service - - :schema: io.k8s.api.core.v1.ServicePort - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__34bd12b0b5b5ee6a8e28438e78966717248ee25b5c7c6a0cadd99c8e5843ebb3) - check_type(argname="argument port", value=port, expected_type=type_hints["port"]) - check_type(argname="argument app_protocol", value=app_protocol, expected_type=type_hints["app_protocol"]) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument node_port", value=node_port, expected_type=type_hints["node_port"]) - check_type(argname="argument protocol", value=protocol, expected_type=type_hints["protocol"]) - check_type(argname="argument target_port", value=target_port, expected_type=type_hints["target_port"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "port": port, - } - if app_protocol is not None: - self._values["app_protocol"] = app_protocol - if name is not None: - self._values["name"] = name - if node_port is not None: - self._values["node_port"] = node_port - if protocol is not None: - self._values["protocol"] = protocol - if target_port is not None: - self._values["target_port"] = target_port - - @builtins.property - def port(self) -> jsii.Number: - '''The port that will be exposed by this service. - - :schema: io.k8s.api.core.v1.ServicePort#port - ''' - result = self._values.get("port") - assert result is not None, "Required property 'port' is missing" - return typing.cast(jsii.Number, result) - - @builtins.property - def app_protocol(self) -> typing.Optional[builtins.str]: - '''The application protocol for this port. - - This field follows standard Kubernetes label syntax. Un-prefixed names are reserved for IANA standard service names (as per RFC-6335 and https://www.iana.org/assignments/service-names). Non-standard protocols should use prefixed names such as mycompany.com/my-custom-protocol. - - :schema: io.k8s.api.core.v1.ServicePort#appProtocol - ''' - result = self._values.get("app_protocol") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def name(self) -> typing.Optional[builtins.str]: - '''The name of this port within the service. - - This must be a DNS_LABEL. All ports within a ServiceSpec must have unique names. When considering the endpoints for a Service, this must match the 'name' field in the EndpointPort. Optional if only one ServicePort is defined on this service. - - :schema: io.k8s.api.core.v1.ServicePort#name - ''' - result = self._values.get("name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def node_port(self) -> typing.Optional[jsii.Number]: - '''The port on each node on which this service is exposed when type is NodePort or LoadBalancer. - - Usually assigned by the system. If a value is specified, in-range, and not in use it will be used, otherwise the operation will fail. If not specified, a port will be allocated if this Service requires one. If this field is specified when creating a Service which does not need it, creation will fail. This field will be wiped when updating a Service to no longer need it (e.g. changing type from NodePort to ClusterIP). More info: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport - - :schema: io.k8s.api.core.v1.ServicePort#nodePort - ''' - result = self._values.get("node_port") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def protocol(self) -> typing.Optional[builtins.str]: - '''The IP protocol for this port. - - Supports "TCP", "UDP", and "SCTP". Default is TCP. - - :default: TCP. - - :schema: io.k8s.api.core.v1.ServicePort#protocol - ''' - result = self._values.get("protocol") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def target_port(self) -> typing.Optional[IntOrString]: - '''Number or name of the port to access on the pods targeted by the service. - - Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. If this is a string, it will be looked up as a named port in the target Pod's container ports. If this is not specified, the value of the 'port' field is used (an identity map). This field is ignored for services with clusterIP=None, and should be omitted or set equal to the 'port' field. More info: https://kubernetes.io/docs/concepts/services-networking/service/#defining-a-service - - :schema: io.k8s.api.core.v1.ServicePort#targetPort - ''' - result = self._values.get("target_port") - return typing.cast(typing.Optional[IntOrString], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ServicePort(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ServiceReference", - jsii_struct_bases=[], - name_mapping={ - "name": "name", - "namespace": "namespace", - "path": "path", - "port": "port", - }, -) -class ServiceReference: - def __init__( - self, - *, - name: builtins.str, - namespace: builtins.str, - path: typing.Optional[builtins.str] = None, - port: typing.Optional[jsii.Number] = None, - ) -> None: - '''ServiceReference holds a reference to Service.legacy.k8s.io. - - :param name: ``name`` is the name of the service. Required - :param namespace: ``namespace`` is the namespace of the service. Required - :param path: ``path`` is an optional URL path which will be sent in any request to this service. - :param port: If specified, the port on the service that hosting webhook. Default to 443 for backward compatibility. ``port`` should be a valid port number (1-65535, inclusive). Default: 443 for backward compatibility. ``port`` should be a valid port number (1-65535, inclusive). - - :schema: io.k8s.api.admissionregistration.v1.ServiceReference - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__6d9ad2a01fb9e7ce732f776bc88e9c896a203ce950547fb864ef2833ae00ee24) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument namespace", value=namespace, expected_type=type_hints["namespace"]) - check_type(argname="argument path", value=path, expected_type=type_hints["path"]) - check_type(argname="argument port", value=port, expected_type=type_hints["port"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "name": name, - "namespace": namespace, - } - if path is not None: - self._values["path"] = path - if port is not None: - self._values["port"] = port - - @builtins.property - def name(self) -> builtins.str: - '''``name`` is the name of the service. - - Required - - :schema: io.k8s.api.admissionregistration.v1.ServiceReference#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def namespace(self) -> builtins.str: - '''``namespace`` is the namespace of the service. - - Required - - :schema: io.k8s.api.admissionregistration.v1.ServiceReference#namespace - ''' - result = self._values.get("namespace") - assert result is not None, "Required property 'namespace' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def path(self) -> typing.Optional[builtins.str]: - '''``path`` is an optional URL path which will be sent in any request to this service. - - :schema: io.k8s.api.admissionregistration.v1.ServiceReference#path - ''' - result = self._values.get("path") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def port(self) -> typing.Optional[jsii.Number]: - '''If specified, the port on the service that hosting webhook. - - Default to 443 for backward compatibility. ``port`` should be a valid port number (1-65535, inclusive). - - :default: 443 for backward compatibility. ``port`` should be a valid port number (1-65535, inclusive). - - :schema: io.k8s.api.admissionregistration.v1.ServiceReference#port - ''' - result = self._values.get("port") - return typing.cast(typing.Optional[jsii.Number], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ServiceReference(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ServiceSpec", - jsii_struct_bases=[], - name_mapping={ - "allocate_load_balancer_node_ports": "allocateLoadBalancerNodePorts", - "cluster_ip": "clusterIp", - "cluster_i_ps": "clusterIPs", - "external_i_ps": "externalIPs", - "external_name": "externalName", - "external_traffic_policy": "externalTrafficPolicy", - "health_check_node_port": "healthCheckNodePort", - "internal_traffic_policy": "internalTrafficPolicy", - "ip_families": "ipFamilies", - "ip_family_policy": "ipFamilyPolicy", - "load_balancer_class": "loadBalancerClass", - "load_balancer_ip": "loadBalancerIp", - "load_balancer_source_ranges": "loadBalancerSourceRanges", - "ports": "ports", - "publish_not_ready_addresses": "publishNotReadyAddresses", - "selector": "selector", - "session_affinity": "sessionAffinity", - "session_affinity_config": "sessionAffinityConfig", - "type": "type", - }, -) -class ServiceSpec: - def __init__( - self, - *, - allocate_load_balancer_node_ports: typing.Optional[builtins.bool] = None, - cluster_ip: typing.Optional[builtins.str] = None, - cluster_i_ps: typing.Optional[typing.Sequence[builtins.str]] = None, - external_i_ps: typing.Optional[typing.Sequence[builtins.str]] = None, - external_name: typing.Optional[builtins.str] = None, - external_traffic_policy: typing.Optional[builtins.str] = None, - health_check_node_port: typing.Optional[jsii.Number] = None, - internal_traffic_policy: typing.Optional[builtins.str] = None, - ip_families: typing.Optional[typing.Sequence[builtins.str]] = None, - ip_family_policy: typing.Optional[builtins.str] = None, - load_balancer_class: typing.Optional[builtins.str] = None, - load_balancer_ip: typing.Optional[builtins.str] = None, - load_balancer_source_ranges: typing.Optional[typing.Sequence[builtins.str]] = None, - ports: typing.Optional[typing.Sequence[typing.Union[ServicePort, typing.Dict[builtins.str, typing.Any]]]] = None, - publish_not_ready_addresses: typing.Optional[builtins.bool] = None, - selector: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - session_affinity: typing.Optional[builtins.str] = None, - session_affinity_config: typing.Optional[typing.Union["SessionAffinityConfig", typing.Dict[builtins.str, typing.Any]]] = None, - type: typing.Optional[builtins.str] = None, - ) -> None: - '''ServiceSpec describes the attributes that a user creates on a service. - - :param allocate_load_balancer_node_ports: allocateLoadBalancerNodePorts defines if NodePorts will be automatically allocated for services with type LoadBalancer. Default is "true". It may be set to "false" if the cluster load-balancer does not rely on NodePorts. If the caller requests specific NodePorts (by specifying a value), those requests will be respected, regardless of this field. This field may only be set for services with type LoadBalancer and will be cleared if the type is changed to any other type. Default: true". It may be set to "false" if the cluster load-balancer does not rely on NodePorts. If the caller requests specific NodePorts (by specifying a value), those requests will be respected, regardless of this field. This field may only be set for services with type LoadBalancer and will be cleared if the type is changed to any other type. - :param cluster_ip: clusterIP is the IP address of the service and is usually assigned randomly. If an address is specified manually, is in-range (as per system configuration), and is not in use, it will be allocated to the service; otherwise creation of the service will fail. This field may not be changed through updates unless the type field is also being changed to ExternalName (which requires this field to be blank) or the type field is being changed from ExternalName (in which case this field may optionally be specified, as describe above). Valid values are "None", empty string (""), or a valid IP address. Setting this to "None" makes a "headless service" (no virtual IP), which is useful when direct endpoint connections are preferred and proxying is not required. Only applies to types ClusterIP, NodePort, and LoadBalancer. If this field is specified when creating a Service of type ExternalName, creation will fail. This field will be wiped when updating a Service to type ExternalName. More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies - :param cluster_i_ps: ClusterIPs is a list of IP addresses assigned to this service, and are usually assigned randomly. If an address is specified manually, is in-range (as per system configuration), and is not in use, it will be allocated to the service; otherwise creation of the service will fail. This field may not be changed through updates unless the type field is also being changed to ExternalName (which requires this field to be empty) or the type field is being changed from ExternalName (in which case this field may optionally be specified, as describe above). Valid values are "None", empty string (""), or a valid IP address. Setting this to "None" makes a "headless service" (no virtual IP), which is useful when direct endpoint connections are preferred and proxying is not required. Only applies to types ClusterIP, NodePort, and LoadBalancer. If this field is specified when creating a Service of type ExternalName, creation will fail. This field will be wiped when updating a Service to type ExternalName. If this field is not specified, it will be initialized from the clusterIP field. If this field is specified, clients must ensure that clusterIPs[0] and clusterIP have the same value. This field may hold a maximum of two entries (dual-stack IPs, in either order). These IPs must correspond to the values of the ipFamilies field. Both clusterIPs and ipFamilies are governed by the ipFamilyPolicy field. More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies - :param external_i_ps: externalIPs is a list of IP addresses for which nodes in the cluster will also accept traffic for this service. These IPs are not managed by Kubernetes. The user is responsible for ensuring that traffic arrives at a node with this IP. A common example is external load-balancers that are not part of the Kubernetes system. - :param external_name: externalName is the external reference that discovery mechanisms will return as an alias for this service (e.g. a DNS CNAME record). No proxying will be involved. Must be a lowercase RFC-1123 hostname (https://tools.ietf.org/html/rfc1123) and requires ``type`` to be "ExternalName". - :param external_traffic_policy: externalTrafficPolicy describes how nodes distribute service traffic they receive on one of the Service's "externally-facing" addresses (NodePorts, ExternalIPs, and LoadBalancer IPs). If set to "Local", the proxy will configure the service in a way that assumes that external load balancers will take care of balancing the service traffic between nodes, and so each node will deliver traffic only to the node-local endpoints of the service, without masquerading the client source IP. (Traffic mistakenly sent to a node with no endpoints will be dropped.) The default value, "Cluster", uses the standard behavior of routing to all endpoints evenly (possibly modified by topology and other features). Note that traffic sent to an External IP or LoadBalancer IP from within the cluster will always get "Cluster" semantics, but clients sending to a NodePort from within the cluster may need to take traffic policy into account when picking a node. - :param health_check_node_port: healthCheckNodePort specifies the healthcheck nodePort for the service. This only applies when type is set to LoadBalancer and externalTrafficPolicy is set to Local. If a value is specified, is in-range, and is not in use, it will be used. If not specified, a value will be automatically allocated. External systems (e.g. load-balancers) can use this port to determine if a given node holds endpoints for this service or not. If this field is specified when creating a Service which does not need it, creation will fail. This field will be wiped when updating a Service to no longer need it (e.g. changing type). This field cannot be updated once set. - :param internal_traffic_policy: InternalTrafficPolicy describes how nodes distribute service traffic they receive on the ClusterIP. If set to "Local", the proxy will assume that pods only want to talk to endpoints of the service on the same node as the pod, dropping the traffic if there are no local endpoints. The default value, "Cluster", uses the standard behavior of routing to all endpoints evenly (possibly modified by topology and other features). - :param ip_families: IPFamilies is a list of IP families (e.g. IPv4, IPv6) assigned to this service. This field is usually assigned automatically based on cluster configuration and the ipFamilyPolicy field. If this field is specified manually, the requested family is available in the cluster, and ipFamilyPolicy allows it, it will be used; otherwise creation of the service will fail. This field is conditionally mutable: it allows for adding or removing a secondary IP family, but it does not allow changing the primary IP family of the Service. Valid values are "IPv4" and "IPv6". This field only applies to Services of types ClusterIP, NodePort, and LoadBalancer, and does apply to "headless" services. This field will be wiped when updating a Service to type ExternalName. This field may hold a maximum of two entries (dual-stack families, in either order). These families must correspond to the values of the clusterIPs field, if specified. Both clusterIPs and ipFamilies are governed by the ipFamilyPolicy field. - :param ip_family_policy: IPFamilyPolicy represents the dual-stack-ness requested or required by this Service. If there is no value provided, then this field will be set to SingleStack. Services can be "SingleStack" (a single IP family), "PreferDualStack" (two IP families on dual-stack configured clusters or a single IP family on single-stack clusters), or "RequireDualStack" (two IP families on dual-stack configured clusters, otherwise fail). The ipFamilies and clusterIPs fields depend on the value of this field. This field will be wiped when updating a service to type ExternalName. - :param load_balancer_class: loadBalancerClass is the class of the load balancer implementation this Service belongs to. If specified, the value of this field must be a label-style identifier, with an optional prefix, e.g. "internal-vip" or "example.com/internal-vip". Unprefixed names are reserved for end-users. This field can only be set when the Service type is 'LoadBalancer'. If not set, the default load balancer implementation is used, today this is typically done through the cloud provider integration, but should apply for any default implementation. If set, it is assumed that a load balancer implementation is watching for Services with a matching class. Any default load balancer implementation (e.g. cloud providers) should ignore Services that set this field. This field can only be set when creating or updating a Service to type 'LoadBalancer'. Once set, it can not be changed. This field will be wiped when a service is updated to a non 'LoadBalancer' type. - :param load_balancer_ip: Only applies to Service Type: LoadBalancer. This feature depends on whether the underlying cloud-provider supports specifying the loadBalancerIP when a load balancer is created. This field will be ignored if the cloud-provider does not support the feature. Deprecated: This field was under-specified and its meaning varies across implementations, and it cannot support dual-stack. As of Kubernetes v1.24, users are encouraged to use implementation-specific annotations when available. This field may be removed in a future API version. - :param load_balancer_source_ranges: If specified and supported by the platform, this will restrict traffic through the cloud-provider load-balancer will be restricted to the specified client IPs. This field will be ignored if the cloud-provider does not support the feature." More info: https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/ - :param ports: The list of ports that are exposed by this service. More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies - :param publish_not_ready_addresses: publishNotReadyAddresses indicates that any agent which deals with endpoints for this Service should disregard any indications of ready/not-ready. The primary use case for setting this field is for a StatefulSet's Headless Service to propagate SRV DNS records for its Pods for the purpose of peer discovery. The Kubernetes controllers that generate Endpoints and EndpointSlice resources for Services interpret this to mean that all endpoints are considered "ready" even if the Pods themselves are not. Agents which consume only Kubernetes generated endpoints through the Endpoints or EndpointSlice resources can safely assume this behavior. - :param selector: Route service traffic to pods with label keys and values matching this selector. If empty or not present, the service is assumed to have an external process managing its endpoints, which Kubernetes will not modify. Only applies to types ClusterIP, NodePort, and LoadBalancer. Ignored if type is ExternalName. More info: https://kubernetes.io/docs/concepts/services-networking/service/ - :param session_affinity: Supports "ClientIP" and "None". Used to maintain session affinity. Enable client IP based session affinity. Must be ClientIP or None. Defaults to None. More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies Default: None. More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies - :param session_affinity_config: sessionAffinityConfig contains the configurations of session affinity. - :param type: type determines how the Service is exposed. Defaults to ClusterIP. Valid options are ExternalName, ClusterIP, NodePort, and LoadBalancer. "ClusterIP" allocates a cluster-internal IP address for load-balancing to endpoints. Endpoints are determined by the selector or if that is not specified, by manual construction of an Endpoints object or EndpointSlice objects. If clusterIP is "None", no virtual IP is allocated and the endpoints are published as a set of endpoints rather than a virtual IP. "NodePort" builds on ClusterIP and allocates a port on every node which routes to the same endpoints as the clusterIP. "LoadBalancer" builds on NodePort and creates an external load-balancer (if supported in the current cloud) which routes to the same endpoints as the clusterIP. "ExternalName" aliases this service to the specified externalName. Several other fields do not apply to ExternalName services. More info: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types Default: ClusterIP. Valid options are ExternalName, ClusterIP, NodePort, and LoadBalancer. "ClusterIP" allocates a cluster-internal IP address for load-balancing to endpoints. Endpoints are determined by the selector or if that is not specified, by manual construction of an Endpoints object or EndpointSlice objects. If clusterIP is "None", no virtual IP is allocated and the endpoints are published as a set of endpoints rather than a virtual IP. "NodePort" builds on ClusterIP and allocates a port on every node which routes to the same endpoints as the clusterIP. "LoadBalancer" builds on NodePort and creates an external load-balancer (if supported in the current cloud) which routes to the same endpoints as the clusterIP. "ExternalName" aliases this service to the specified externalName. Several other fields do not apply to ExternalName services. More info: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types - - :schema: io.k8s.api.core.v1.ServiceSpec - ''' - if isinstance(session_affinity_config, dict): - session_affinity_config = SessionAffinityConfig(**session_affinity_config) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__28a62a3352f8d0567f520784bd515250a02d7d2d6686265c9478416f87acb91e) - check_type(argname="argument allocate_load_balancer_node_ports", value=allocate_load_balancer_node_ports, expected_type=type_hints["allocate_load_balancer_node_ports"]) - check_type(argname="argument cluster_ip", value=cluster_ip, expected_type=type_hints["cluster_ip"]) - check_type(argname="argument cluster_i_ps", value=cluster_i_ps, expected_type=type_hints["cluster_i_ps"]) - check_type(argname="argument external_i_ps", value=external_i_ps, expected_type=type_hints["external_i_ps"]) - check_type(argname="argument external_name", value=external_name, expected_type=type_hints["external_name"]) - check_type(argname="argument external_traffic_policy", value=external_traffic_policy, expected_type=type_hints["external_traffic_policy"]) - check_type(argname="argument health_check_node_port", value=health_check_node_port, expected_type=type_hints["health_check_node_port"]) - check_type(argname="argument internal_traffic_policy", value=internal_traffic_policy, expected_type=type_hints["internal_traffic_policy"]) - check_type(argname="argument ip_families", value=ip_families, expected_type=type_hints["ip_families"]) - check_type(argname="argument ip_family_policy", value=ip_family_policy, expected_type=type_hints["ip_family_policy"]) - check_type(argname="argument load_balancer_class", value=load_balancer_class, expected_type=type_hints["load_balancer_class"]) - check_type(argname="argument load_balancer_ip", value=load_balancer_ip, expected_type=type_hints["load_balancer_ip"]) - check_type(argname="argument load_balancer_source_ranges", value=load_balancer_source_ranges, expected_type=type_hints["load_balancer_source_ranges"]) - check_type(argname="argument ports", value=ports, expected_type=type_hints["ports"]) - check_type(argname="argument publish_not_ready_addresses", value=publish_not_ready_addresses, expected_type=type_hints["publish_not_ready_addresses"]) - check_type(argname="argument selector", value=selector, expected_type=type_hints["selector"]) - check_type(argname="argument session_affinity", value=session_affinity, expected_type=type_hints["session_affinity"]) - check_type(argname="argument session_affinity_config", value=session_affinity_config, expected_type=type_hints["session_affinity_config"]) - check_type(argname="argument type", value=type, expected_type=type_hints["type"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if allocate_load_balancer_node_ports is not None: - self._values["allocate_load_balancer_node_ports"] = allocate_load_balancer_node_ports - if cluster_ip is not None: - self._values["cluster_ip"] = cluster_ip - if cluster_i_ps is not None: - self._values["cluster_i_ps"] = cluster_i_ps - if external_i_ps is not None: - self._values["external_i_ps"] = external_i_ps - if external_name is not None: - self._values["external_name"] = external_name - if external_traffic_policy is not None: - self._values["external_traffic_policy"] = external_traffic_policy - if health_check_node_port is not None: - self._values["health_check_node_port"] = health_check_node_port - if internal_traffic_policy is not None: - self._values["internal_traffic_policy"] = internal_traffic_policy - if ip_families is not None: - self._values["ip_families"] = ip_families - if ip_family_policy is not None: - self._values["ip_family_policy"] = ip_family_policy - if load_balancer_class is not None: - self._values["load_balancer_class"] = load_balancer_class - if load_balancer_ip is not None: - self._values["load_balancer_ip"] = load_balancer_ip - if load_balancer_source_ranges is not None: - self._values["load_balancer_source_ranges"] = load_balancer_source_ranges - if ports is not None: - self._values["ports"] = ports - if publish_not_ready_addresses is not None: - self._values["publish_not_ready_addresses"] = publish_not_ready_addresses - if selector is not None: - self._values["selector"] = selector - if session_affinity is not None: - self._values["session_affinity"] = session_affinity - if session_affinity_config is not None: - self._values["session_affinity_config"] = session_affinity_config - if type is not None: - self._values["type"] = type - - @builtins.property - def allocate_load_balancer_node_ports(self) -> typing.Optional[builtins.bool]: - '''allocateLoadBalancerNodePorts defines if NodePorts will be automatically allocated for services with type LoadBalancer. - - Default is "true". It may be set to "false" if the cluster load-balancer does not rely on NodePorts. If the caller requests specific NodePorts (by specifying a value), those requests will be respected, regardless of this field. This field may only be set for services with type LoadBalancer and will be cleared if the type is changed to any other type. - - :default: true". It may be set to "false" if the cluster load-balancer does not rely on NodePorts. If the caller requests specific NodePorts (by specifying a value), those requests will be respected, regardless of this field. This field may only be set for services with type LoadBalancer and will be cleared if the type is changed to any other type. - - :schema: io.k8s.api.core.v1.ServiceSpec#allocateLoadBalancerNodePorts - ''' - result = self._values.get("allocate_load_balancer_node_ports") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def cluster_ip(self) -> typing.Optional[builtins.str]: - '''clusterIP is the IP address of the service and is usually assigned randomly. - - If an address is specified manually, is in-range (as per system configuration), and is not in use, it will be allocated to the service; otherwise creation of the service will fail. This field may not be changed through updates unless the type field is also being changed to ExternalName (which requires this field to be blank) or the type field is being changed from ExternalName (in which case this field may optionally be specified, as describe above). Valid values are "None", empty string (""), or a valid IP address. Setting this to "None" makes a "headless service" (no virtual IP), which is useful when direct endpoint connections are preferred and proxying is not required. Only applies to types ClusterIP, NodePort, and LoadBalancer. If this field is specified when creating a Service of type ExternalName, creation will fail. This field will be wiped when updating a Service to type ExternalName. More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies - - :schema: io.k8s.api.core.v1.ServiceSpec#clusterIP - ''' - result = self._values.get("cluster_ip") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def cluster_i_ps(self) -> typing.Optional[typing.List[builtins.str]]: - '''ClusterIPs is a list of IP addresses assigned to this service, and are usually assigned randomly. - - If an address is specified manually, is in-range (as per system configuration), and is not in use, it will be allocated to the service; otherwise creation of the service will fail. This field may not be changed through updates unless the type field is also being changed to ExternalName (which requires this field to be empty) or the type field is being changed from ExternalName (in which case this field may optionally be specified, as describe above). Valid values are "None", empty string (""), or a valid IP address. Setting this to "None" makes a "headless service" (no virtual IP), which is useful when direct endpoint connections are preferred and proxying is not required. Only applies to types ClusterIP, NodePort, and LoadBalancer. If this field is specified when creating a Service of type ExternalName, creation will fail. This field will be wiped when updating a Service to type ExternalName. If this field is not specified, it will be initialized from the clusterIP field. If this field is specified, clients must ensure that clusterIPs[0] and clusterIP have the same value. - - This field may hold a maximum of two entries (dual-stack IPs, in either order). These IPs must correspond to the values of the ipFamilies field. Both clusterIPs and ipFamilies are governed by the ipFamilyPolicy field. More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies - - :schema: io.k8s.api.core.v1.ServiceSpec#clusterIPs - ''' - result = self._values.get("cluster_i_ps") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def external_i_ps(self) -> typing.Optional[typing.List[builtins.str]]: - '''externalIPs is a list of IP addresses for which nodes in the cluster will also accept traffic for this service. - - These IPs are not managed by Kubernetes. The user is responsible for ensuring that traffic arrives at a node with this IP. A common example is external load-balancers that are not part of the Kubernetes system. - - :schema: io.k8s.api.core.v1.ServiceSpec#externalIPs - ''' - result = self._values.get("external_i_ps") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def external_name(self) -> typing.Optional[builtins.str]: - '''externalName is the external reference that discovery mechanisms will return as an alias for this service (e.g. a DNS CNAME record). No proxying will be involved. Must be a lowercase RFC-1123 hostname (https://tools.ietf.org/html/rfc1123) and requires ``type`` to be "ExternalName". - - :schema: io.k8s.api.core.v1.ServiceSpec#externalName - ''' - result = self._values.get("external_name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def external_traffic_policy(self) -> typing.Optional[builtins.str]: - '''externalTrafficPolicy describes how nodes distribute service traffic they receive on one of the Service's "externally-facing" addresses (NodePorts, ExternalIPs, and LoadBalancer IPs). - - If set to "Local", the proxy will configure the service in a way that assumes that external load balancers will take care of balancing the service traffic between nodes, and so each node will deliver traffic only to the node-local endpoints of the service, without masquerading the client source IP. (Traffic mistakenly sent to a node with no endpoints will be dropped.) The default value, "Cluster", uses the standard behavior of routing to all endpoints evenly (possibly modified by topology and other features). Note that traffic sent to an External IP or LoadBalancer IP from within the cluster will always get "Cluster" semantics, but clients sending to a NodePort from within the cluster may need to take traffic policy into account when picking a node. - - :schema: io.k8s.api.core.v1.ServiceSpec#externalTrafficPolicy - ''' - result = self._values.get("external_traffic_policy") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def health_check_node_port(self) -> typing.Optional[jsii.Number]: - '''healthCheckNodePort specifies the healthcheck nodePort for the service. - - This only applies when type is set to LoadBalancer and externalTrafficPolicy is set to Local. If a value is specified, is in-range, and is not in use, it will be used. If not specified, a value will be automatically allocated. External systems (e.g. load-balancers) can use this port to determine if a given node holds endpoints for this service or not. If this field is specified when creating a Service which does not need it, creation will fail. This field will be wiped when updating a Service to no longer need it (e.g. changing type). This field cannot be updated once set. - - :schema: io.k8s.api.core.v1.ServiceSpec#healthCheckNodePort - ''' - result = self._values.get("health_check_node_port") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def internal_traffic_policy(self) -> typing.Optional[builtins.str]: - '''InternalTrafficPolicy describes how nodes distribute service traffic they receive on the ClusterIP. - - If set to "Local", the proxy will assume that pods only want to talk to endpoints of the service on the same node as the pod, dropping the traffic if there are no local endpoints. The default value, "Cluster", uses the standard behavior of routing to all endpoints evenly (possibly modified by topology and other features). - - :schema: io.k8s.api.core.v1.ServiceSpec#internalTrafficPolicy - ''' - result = self._values.get("internal_traffic_policy") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def ip_families(self) -> typing.Optional[typing.List[builtins.str]]: - '''IPFamilies is a list of IP families (e.g. IPv4, IPv6) assigned to this service. This field is usually assigned automatically based on cluster configuration and the ipFamilyPolicy field. If this field is specified manually, the requested family is available in the cluster, and ipFamilyPolicy allows it, it will be used; otherwise creation of the service will fail. This field is conditionally mutable: it allows for adding or removing a secondary IP family, but it does not allow changing the primary IP family of the Service. Valid values are "IPv4" and "IPv6". This field only applies to Services of types ClusterIP, NodePort, and LoadBalancer, and does apply to "headless" services. This field will be wiped when updating a Service to type ExternalName. - - This field may hold a maximum of two entries (dual-stack families, in either order). These families must correspond to the values of the clusterIPs field, if specified. Both clusterIPs and ipFamilies are governed by the ipFamilyPolicy field. - - :schema: io.k8s.api.core.v1.ServiceSpec#ipFamilies - ''' - result = self._values.get("ip_families") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def ip_family_policy(self) -> typing.Optional[builtins.str]: - '''IPFamilyPolicy represents the dual-stack-ness requested or required by this Service. - - If there is no value provided, then this field will be set to SingleStack. Services can be "SingleStack" (a single IP family), "PreferDualStack" (two IP families on dual-stack configured clusters or a single IP family on single-stack clusters), or "RequireDualStack" (two IP families on dual-stack configured clusters, otherwise fail). The ipFamilies and clusterIPs fields depend on the value of this field. This field will be wiped when updating a service to type ExternalName. - - :schema: io.k8s.api.core.v1.ServiceSpec#ipFamilyPolicy - ''' - result = self._values.get("ip_family_policy") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def load_balancer_class(self) -> typing.Optional[builtins.str]: - '''loadBalancerClass is the class of the load balancer implementation this Service belongs to. - - If specified, the value of this field must be a label-style identifier, with an optional prefix, e.g. "internal-vip" or "example.com/internal-vip". Unprefixed names are reserved for end-users. This field can only be set when the Service type is 'LoadBalancer'. If not set, the default load balancer implementation is used, today this is typically done through the cloud provider integration, but should apply for any default implementation. If set, it is assumed that a load balancer implementation is watching for Services with a matching class. Any default load balancer implementation (e.g. cloud providers) should ignore Services that set this field. This field can only be set when creating or updating a Service to type 'LoadBalancer'. Once set, it can not be changed. This field will be wiped when a service is updated to a non 'LoadBalancer' type. - - :schema: io.k8s.api.core.v1.ServiceSpec#loadBalancerClass - ''' - result = self._values.get("load_balancer_class") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def load_balancer_ip(self) -> typing.Optional[builtins.str]: - '''Only applies to Service Type: LoadBalancer. - - This feature depends on whether the underlying cloud-provider supports specifying the loadBalancerIP when a load balancer is created. This field will be ignored if the cloud-provider does not support the feature. Deprecated: This field was under-specified and its meaning varies across implementations, and it cannot support dual-stack. As of Kubernetes v1.24, users are encouraged to use implementation-specific annotations when available. This field may be removed in a future API version. - - :schema: io.k8s.api.core.v1.ServiceSpec#loadBalancerIP - ''' - result = self._values.get("load_balancer_ip") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def load_balancer_source_ranges(self) -> typing.Optional[typing.List[builtins.str]]: - '''If specified and supported by the platform, this will restrict traffic through the cloud-provider load-balancer will be restricted to the specified client IPs. - - This field will be ignored if the cloud-provider does not support the feature." More info: https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/ - - :schema: io.k8s.api.core.v1.ServiceSpec#loadBalancerSourceRanges - ''' - result = self._values.get("load_balancer_source_ranges") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def ports(self) -> typing.Optional[typing.List[ServicePort]]: - '''The list of ports that are exposed by this service. - - More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies - - :schema: io.k8s.api.core.v1.ServiceSpec#ports - ''' - result = self._values.get("ports") - return typing.cast(typing.Optional[typing.List[ServicePort]], result) - - @builtins.property - def publish_not_ready_addresses(self) -> typing.Optional[builtins.bool]: - '''publishNotReadyAddresses indicates that any agent which deals with endpoints for this Service should disregard any indications of ready/not-ready. - - The primary use case for setting this field is for a StatefulSet's Headless Service to propagate SRV DNS records for its Pods for the purpose of peer discovery. The Kubernetes controllers that generate Endpoints and EndpointSlice resources for Services interpret this to mean that all endpoints are considered "ready" even if the Pods themselves are not. Agents which consume only Kubernetes generated endpoints through the Endpoints or EndpointSlice resources can safely assume this behavior. - - :schema: io.k8s.api.core.v1.ServiceSpec#publishNotReadyAddresses - ''' - result = self._values.get("publish_not_ready_addresses") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def selector(self) -> typing.Optional[typing.Mapping[builtins.str, builtins.str]]: - '''Route service traffic to pods with label keys and values matching this selector. - - If empty or not present, the service is assumed to have an external process managing its endpoints, which Kubernetes will not modify. Only applies to types ClusterIP, NodePort, and LoadBalancer. Ignored if type is ExternalName. More info: https://kubernetes.io/docs/concepts/services-networking/service/ - - :schema: io.k8s.api.core.v1.ServiceSpec#selector - ''' - result = self._values.get("selector") - return typing.cast(typing.Optional[typing.Mapping[builtins.str, builtins.str]], result) - - @builtins.property - def session_affinity(self) -> typing.Optional[builtins.str]: - '''Supports "ClientIP" and "None". - - Used to maintain session affinity. Enable client IP based session affinity. Must be ClientIP or None. Defaults to None. More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies - - :default: None. More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies - - :schema: io.k8s.api.core.v1.ServiceSpec#sessionAffinity - ''' - result = self._values.get("session_affinity") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def session_affinity_config(self) -> typing.Optional["SessionAffinityConfig"]: - '''sessionAffinityConfig contains the configurations of session affinity. - - :schema: io.k8s.api.core.v1.ServiceSpec#sessionAffinityConfig - ''' - result = self._values.get("session_affinity_config") - return typing.cast(typing.Optional["SessionAffinityConfig"], result) - - @builtins.property - def type(self) -> typing.Optional[builtins.str]: - '''type determines how the Service is exposed. - - Defaults to ClusterIP. Valid options are ExternalName, ClusterIP, NodePort, and LoadBalancer. "ClusterIP" allocates a cluster-internal IP address for load-balancing to endpoints. Endpoints are determined by the selector or if that is not specified, by manual construction of an Endpoints object or EndpointSlice objects. If clusterIP is "None", no virtual IP is allocated and the endpoints are published as a set of endpoints rather than a virtual IP. "NodePort" builds on ClusterIP and allocates a port on every node which routes to the same endpoints as the clusterIP. "LoadBalancer" builds on NodePort and creates an external load-balancer (if supported in the current cloud) which routes to the same endpoints as the clusterIP. "ExternalName" aliases this service to the specified externalName. Several other fields do not apply to ExternalName services. More info: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types - - :default: ClusterIP. Valid options are ExternalName, ClusterIP, NodePort, and LoadBalancer. "ClusterIP" allocates a cluster-internal IP address for load-balancing to endpoints. Endpoints are determined by the selector or if that is not specified, by manual construction of an Endpoints object or EndpointSlice objects. If clusterIP is "None", no virtual IP is allocated and the endpoints are published as a set of endpoints rather than a virtual IP. "NodePort" builds on ClusterIP and allocates a port on every node which routes to the same endpoints as the clusterIP. "LoadBalancer" builds on NodePort and creates an external load-balancer (if supported in the current cloud) which routes to the same endpoints as the clusterIP. "ExternalName" aliases this service to the specified externalName. Several other fields do not apply to ExternalName services. More info: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types - - :schema: io.k8s.api.core.v1.ServiceSpec#type - ''' - result = self._values.get("type") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ServiceSpec(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.SessionAffinityConfig", - jsii_struct_bases=[], - name_mapping={"client_ip": "clientIp"}, -) -class SessionAffinityConfig: - def __init__( - self, - *, - client_ip: typing.Optional[typing.Union[ClientIpConfig, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''SessionAffinityConfig represents the configurations of session affinity. - - :param client_ip: clientIP contains the configurations of Client IP based session affinity. - - :schema: io.k8s.api.core.v1.SessionAffinityConfig - ''' - if isinstance(client_ip, dict): - client_ip = ClientIpConfig(**client_ip) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__41fa363df0cef39b3a21ee7d4b32e767f771c391235a46bf9ce8b369b1bcb705) - check_type(argname="argument client_ip", value=client_ip, expected_type=type_hints["client_ip"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if client_ip is not None: - self._values["client_ip"] = client_ip - - @builtins.property - def client_ip(self) -> typing.Optional[ClientIpConfig]: - '''clientIP contains the configurations of Client IP based session affinity. - - :schema: io.k8s.api.core.v1.SessionAffinityConfig#clientIP - ''' - result = self._values.get("client_ip") - return typing.cast(typing.Optional[ClientIpConfig], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "SessionAffinityConfig(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.StatefulSetOrdinals", - jsii_struct_bases=[], - name_mapping={"start": "start"}, -) -class StatefulSetOrdinals: - def __init__(self, *, start: typing.Optional[jsii.Number] = None) -> None: - '''StatefulSetOrdinals describes the policy used for replica ordinal assignment in this StatefulSet. - - :param start: start is the number representing the first replica's index. It may be used to number replicas from an alternate index (eg: 1-indexed) over the default 0-indexed names, or to orchestrate progressive movement of replicas from one StatefulSet to another. If set, replica indices will be in the range: [.spec.ordinals.start, .spec.ordinals.start + .spec.replicas). If unset, defaults to 0. Replica indices will be in the range: [0, .spec.replicas). - - :schema: io.k8s.api.apps.v1.StatefulSetOrdinals - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__1e58617ce6e9215ed1ab28dc2eee5d66eab33dc7bfaa27792ade3a835dd2b944) - check_type(argname="argument start", value=start, expected_type=type_hints["start"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if start is not None: - self._values["start"] = start - - @builtins.property - def start(self) -> typing.Optional[jsii.Number]: - '''start is the number representing the first replica's index. - - It may be used to number replicas from an alternate index (eg: 1-indexed) over the default 0-indexed names, or to orchestrate progressive movement of replicas from one StatefulSet to another. If set, replica indices will be in the range: - [.spec.ordinals.start, .spec.ordinals.start + .spec.replicas). - If unset, defaults to 0. Replica indices will be in the range: - [0, .spec.replicas). - - :schema: io.k8s.api.apps.v1.StatefulSetOrdinals#start - ''' - result = self._values.get("start") - return typing.cast(typing.Optional[jsii.Number], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "StatefulSetOrdinals(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.StatefulSetPersistentVolumeClaimRetentionPolicy", - jsii_struct_bases=[], - name_mapping={"when_deleted": "whenDeleted", "when_scaled": "whenScaled"}, -) -class StatefulSetPersistentVolumeClaimRetentionPolicy: - def __init__( - self, - *, - when_deleted: typing.Optional[builtins.str] = None, - when_scaled: typing.Optional[builtins.str] = None, - ) -> None: - '''StatefulSetPersistentVolumeClaimRetentionPolicy describes the policy used for PVCs created from the StatefulSet VolumeClaimTemplates. - - :param when_deleted: WhenDeleted specifies what happens to PVCs created from StatefulSet VolumeClaimTemplates when the StatefulSet is deleted. The default policy of ``Retain`` causes PVCs to not be affected by StatefulSet deletion. The ``Delete`` policy causes those PVCs to be deleted. - :param when_scaled: WhenScaled specifies what happens to PVCs created from StatefulSet VolumeClaimTemplates when the StatefulSet is scaled down. The default policy of ``Retain`` causes PVCs to not be affected by a scaledown. The ``Delete`` policy causes the associated PVCs for any excess pods above the replica count to be deleted. - - :schema: io.k8s.api.apps.v1.StatefulSetPersistentVolumeClaimRetentionPolicy - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__94098796780c55cdb42c5b053d638803027114010a1003ea7430353fd3179c5a) - check_type(argname="argument when_deleted", value=when_deleted, expected_type=type_hints["when_deleted"]) - check_type(argname="argument when_scaled", value=when_scaled, expected_type=type_hints["when_scaled"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if when_deleted is not None: - self._values["when_deleted"] = when_deleted - if when_scaled is not None: - self._values["when_scaled"] = when_scaled - - @builtins.property - def when_deleted(self) -> typing.Optional[builtins.str]: - '''WhenDeleted specifies what happens to PVCs created from StatefulSet VolumeClaimTemplates when the StatefulSet is deleted. - - The default policy of ``Retain`` causes PVCs to not be affected by StatefulSet deletion. The ``Delete`` policy causes those PVCs to be deleted. - - :schema: io.k8s.api.apps.v1.StatefulSetPersistentVolumeClaimRetentionPolicy#whenDeleted - ''' - result = self._values.get("when_deleted") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def when_scaled(self) -> typing.Optional[builtins.str]: - '''WhenScaled specifies what happens to PVCs created from StatefulSet VolumeClaimTemplates when the StatefulSet is scaled down. - - The default policy of ``Retain`` causes PVCs to not be affected by a scaledown. The ``Delete`` policy causes the associated PVCs for any excess pods above the replica count to be deleted. - - :schema: io.k8s.api.apps.v1.StatefulSetPersistentVolumeClaimRetentionPolicy#whenScaled - ''' - result = self._values.get("when_scaled") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "StatefulSetPersistentVolumeClaimRetentionPolicy(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.StatefulSetSpec", - jsii_struct_bases=[], - name_mapping={ - "selector": "selector", - "service_name": "serviceName", - "template": "template", - "min_ready_seconds": "minReadySeconds", - "ordinals": "ordinals", - "persistent_volume_claim_retention_policy": "persistentVolumeClaimRetentionPolicy", - "pod_management_policy": "podManagementPolicy", - "replicas": "replicas", - "revision_history_limit": "revisionHistoryLimit", - "update_strategy": "updateStrategy", - "volume_claim_templates": "volumeClaimTemplates", - }, -) -class StatefulSetSpec: - def __init__( - self, - *, - selector: typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]], - service_name: builtins.str, - template: typing.Union[PodTemplateSpec, typing.Dict[builtins.str, typing.Any]], - min_ready_seconds: typing.Optional[jsii.Number] = None, - ordinals: typing.Optional[typing.Union[StatefulSetOrdinals, typing.Dict[builtins.str, typing.Any]]] = None, - persistent_volume_claim_retention_policy: typing.Optional[typing.Union[StatefulSetPersistentVolumeClaimRetentionPolicy, typing.Dict[builtins.str, typing.Any]]] = None, - pod_management_policy: typing.Optional[builtins.str] = None, - replicas: typing.Optional[jsii.Number] = None, - revision_history_limit: typing.Optional[jsii.Number] = None, - update_strategy: typing.Optional[typing.Union["StatefulSetUpdateStrategy", typing.Dict[builtins.str, typing.Any]]] = None, - volume_claim_templates: typing.Optional[typing.Sequence[typing.Union[KubePersistentVolumeClaimProps, typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''A StatefulSetSpec is the specification of a StatefulSet. - - :param selector: selector is a label query over pods that should match the replica count. It must match the pod template's labels. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors - :param service_name: serviceName is the name of the service that governs this StatefulSet. This service must exist before the StatefulSet, and is responsible for the network identity of the set. Pods get DNS/hostnames that follow the pattern: pod-specific-string.serviceName.default.svc.cluster.local where "pod-specific-string" is managed by the StatefulSet controller. - :param template: template is the object that describes the pod that will be created if insufficient replicas are detected. Each pod stamped out by the StatefulSet will fulfill this Template, but have a unique identity from the rest of the StatefulSet. Each pod will be named with the format -. For example, a pod in a StatefulSet named "web" with index number "3" would be named "web-3". - :param min_ready_seconds: Minimum number of seconds for which a newly created pod should be ready without any of its container crashing for it to be considered available. Defaults to 0 (pod will be considered available as soon as it is ready) Default: 0 (pod will be considered available as soon as it is ready) - :param ordinals: ordinals controls the numbering of replica indices in a StatefulSet. The default ordinals behavior assigns a "0" index to the first replica and increments the index by one for each additional replica requested. Using the ordinals field requires the StatefulSetStartOrdinal feature gate to be enabled, which is alpha. - :param persistent_volume_claim_retention_policy: persistentVolumeClaimRetentionPolicy describes the lifecycle of persistent volume claims created from volumeClaimTemplates. By default, all persistent volume claims are created as needed and retained until manually deleted. This policy allows the lifecycle to be altered, for example by deleting persistent volume claims when their stateful set is deleted, or when their pod is scaled down. This requires the StatefulSetAutoDeletePVC feature gate to be enabled, which is alpha. +optional - :param pod_management_policy: podManagementPolicy controls how pods are created during initial scale up, when replacing pods on nodes, or when scaling down. The default policy is ``OrderedReady``, where pods are created in increasing order (pod-0, then pod-1, etc) and the controller will wait until each pod is ready before continuing. When scaling down, the pods are removed in the opposite order. The alternative policy is ``Parallel`` which will create pods in parallel to match the desired scale without waiting, and on scale down will delete all pods at once. - :param replicas: replicas is the desired number of replicas of the given Template. These are replicas in the sense that they are instantiations of the same Template, but individual replicas also have a consistent identity. If unspecified, defaults to 1. - :param revision_history_limit: revisionHistoryLimit is the maximum number of revisions that will be maintained in the StatefulSet's revision history. The revision history consists of all revisions not represented by a currently applied StatefulSetSpec version. The default value is 10. - :param update_strategy: updateStrategy indicates the StatefulSetUpdateStrategy that will be employed to update Pods in the StatefulSet when a revision is made to Template. - :param volume_claim_templates: volumeClaimTemplates is a list of claims that pods are allowed to reference. The StatefulSet controller is responsible for mapping network identities to claims in a way that maintains the identity of a pod. Every claim in this list must have at least one matching (by name) volumeMount in one container in the template. A claim in this list takes precedence over any volumes in the template, with the same name. - - :schema: io.k8s.api.apps.v1.StatefulSetSpec - ''' - if isinstance(selector, dict): - selector = LabelSelector(**selector) - if isinstance(template, dict): - template = PodTemplateSpec(**template) - if isinstance(ordinals, dict): - ordinals = StatefulSetOrdinals(**ordinals) - if isinstance(persistent_volume_claim_retention_policy, dict): - persistent_volume_claim_retention_policy = StatefulSetPersistentVolumeClaimRetentionPolicy(**persistent_volume_claim_retention_policy) - if isinstance(update_strategy, dict): - update_strategy = StatefulSetUpdateStrategy(**update_strategy) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__6b3479a4db27d16f25eff18cf9e8bad5d98c3cce86039a11df4bfd5a6c9d128f) - check_type(argname="argument selector", value=selector, expected_type=type_hints["selector"]) - check_type(argname="argument service_name", value=service_name, expected_type=type_hints["service_name"]) - check_type(argname="argument template", value=template, expected_type=type_hints["template"]) - check_type(argname="argument min_ready_seconds", value=min_ready_seconds, expected_type=type_hints["min_ready_seconds"]) - check_type(argname="argument ordinals", value=ordinals, expected_type=type_hints["ordinals"]) - check_type(argname="argument persistent_volume_claim_retention_policy", value=persistent_volume_claim_retention_policy, expected_type=type_hints["persistent_volume_claim_retention_policy"]) - check_type(argname="argument pod_management_policy", value=pod_management_policy, expected_type=type_hints["pod_management_policy"]) - check_type(argname="argument replicas", value=replicas, expected_type=type_hints["replicas"]) - check_type(argname="argument revision_history_limit", value=revision_history_limit, expected_type=type_hints["revision_history_limit"]) - check_type(argname="argument update_strategy", value=update_strategy, expected_type=type_hints["update_strategy"]) - check_type(argname="argument volume_claim_templates", value=volume_claim_templates, expected_type=type_hints["volume_claim_templates"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "selector": selector, - "service_name": service_name, - "template": template, - } - if min_ready_seconds is not None: - self._values["min_ready_seconds"] = min_ready_seconds - if ordinals is not None: - self._values["ordinals"] = ordinals - if persistent_volume_claim_retention_policy is not None: - self._values["persistent_volume_claim_retention_policy"] = persistent_volume_claim_retention_policy - if pod_management_policy is not None: - self._values["pod_management_policy"] = pod_management_policy - if replicas is not None: - self._values["replicas"] = replicas - if revision_history_limit is not None: - self._values["revision_history_limit"] = revision_history_limit - if update_strategy is not None: - self._values["update_strategy"] = update_strategy - if volume_claim_templates is not None: - self._values["volume_claim_templates"] = volume_claim_templates - - @builtins.property - def selector(self) -> LabelSelector: - '''selector is a label query over pods that should match the replica count. - - It must match the pod template's labels. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors - - :schema: io.k8s.api.apps.v1.StatefulSetSpec#selector - ''' - result = self._values.get("selector") - assert result is not None, "Required property 'selector' is missing" - return typing.cast(LabelSelector, result) - - @builtins.property - def service_name(self) -> builtins.str: - '''serviceName is the name of the service that governs this StatefulSet. - - This service must exist before the StatefulSet, and is responsible for the network identity of the set. Pods get DNS/hostnames that follow the pattern: pod-specific-string.serviceName.default.svc.cluster.local where "pod-specific-string" is managed by the StatefulSet controller. - - :schema: io.k8s.api.apps.v1.StatefulSetSpec#serviceName - ''' - result = self._values.get("service_name") - assert result is not None, "Required property 'service_name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def template(self) -> PodTemplateSpec: - '''template is the object that describes the pod that will be created if insufficient replicas are detected. - - Each pod stamped out by the StatefulSet will fulfill this Template, but have a unique identity from the rest of the StatefulSet. Each pod will be named with the format -. For example, a pod in a StatefulSet named "web" with index number "3" would be named "web-3". - - :schema: io.k8s.api.apps.v1.StatefulSetSpec#template - ''' - result = self._values.get("template") - assert result is not None, "Required property 'template' is missing" - return typing.cast(PodTemplateSpec, result) - - @builtins.property - def min_ready_seconds(self) -> typing.Optional[jsii.Number]: - '''Minimum number of seconds for which a newly created pod should be ready without any of its container crashing for it to be considered available. - - Defaults to 0 (pod will be considered available as soon as it is ready) - - :default: 0 (pod will be considered available as soon as it is ready) - - :schema: io.k8s.api.apps.v1.StatefulSetSpec#minReadySeconds - ''' - result = self._values.get("min_ready_seconds") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def ordinals(self) -> typing.Optional[StatefulSetOrdinals]: - '''ordinals controls the numbering of replica indices in a StatefulSet. - - The default ordinals behavior assigns a "0" index to the first replica and increments the index by one for each additional replica requested. Using the ordinals field requires the StatefulSetStartOrdinal feature gate to be enabled, which is alpha. - - :schema: io.k8s.api.apps.v1.StatefulSetSpec#ordinals - ''' - result = self._values.get("ordinals") - return typing.cast(typing.Optional[StatefulSetOrdinals], result) - - @builtins.property - def persistent_volume_claim_retention_policy( - self, - ) -> typing.Optional[StatefulSetPersistentVolumeClaimRetentionPolicy]: - '''persistentVolumeClaimRetentionPolicy describes the lifecycle of persistent volume claims created from volumeClaimTemplates. - - By default, all persistent volume claims are created as needed and retained until manually deleted. This policy allows the lifecycle to be altered, for example by deleting persistent volume claims when their stateful set is deleted, or when their pod is scaled down. This requires the StatefulSetAutoDeletePVC feature gate to be enabled, which is alpha. +optional - - :schema: io.k8s.api.apps.v1.StatefulSetSpec#persistentVolumeClaimRetentionPolicy - ''' - result = self._values.get("persistent_volume_claim_retention_policy") - return typing.cast(typing.Optional[StatefulSetPersistentVolumeClaimRetentionPolicy], result) - - @builtins.property - def pod_management_policy(self) -> typing.Optional[builtins.str]: - '''podManagementPolicy controls how pods are created during initial scale up, when replacing pods on nodes, or when scaling down. - - The default policy is ``OrderedReady``, where pods are created in increasing order (pod-0, then pod-1, etc) and the controller will wait until each pod is ready before continuing. When scaling down, the pods are removed in the opposite order. The alternative policy is ``Parallel`` which will create pods in parallel to match the desired scale without waiting, and on scale down will delete all pods at once. - - :schema: io.k8s.api.apps.v1.StatefulSetSpec#podManagementPolicy - ''' - result = self._values.get("pod_management_policy") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def replicas(self) -> typing.Optional[jsii.Number]: - '''replicas is the desired number of replicas of the given Template. - - These are replicas in the sense that they are instantiations of the same Template, but individual replicas also have a consistent identity. If unspecified, defaults to 1. - - :schema: io.k8s.api.apps.v1.StatefulSetSpec#replicas - ''' - result = self._values.get("replicas") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def revision_history_limit(self) -> typing.Optional[jsii.Number]: - '''revisionHistoryLimit is the maximum number of revisions that will be maintained in the StatefulSet's revision history. - - The revision history consists of all revisions not represented by a currently applied StatefulSetSpec version. The default value is 10. - - :schema: io.k8s.api.apps.v1.StatefulSetSpec#revisionHistoryLimit - ''' - result = self._values.get("revision_history_limit") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def update_strategy(self) -> typing.Optional["StatefulSetUpdateStrategy"]: - '''updateStrategy indicates the StatefulSetUpdateStrategy that will be employed to update Pods in the StatefulSet when a revision is made to Template. - - :schema: io.k8s.api.apps.v1.StatefulSetSpec#updateStrategy - ''' - result = self._values.get("update_strategy") - return typing.cast(typing.Optional["StatefulSetUpdateStrategy"], result) - - @builtins.property - def volume_claim_templates( - self, - ) -> typing.Optional[typing.List[KubePersistentVolumeClaimProps]]: - '''volumeClaimTemplates is a list of claims that pods are allowed to reference. - - The StatefulSet controller is responsible for mapping network identities to claims in a way that maintains the identity of a pod. Every claim in this list must have at least one matching (by name) volumeMount in one container in the template. A claim in this list takes precedence over any volumes in the template, with the same name. - - :schema: io.k8s.api.apps.v1.StatefulSetSpec#volumeClaimTemplates - ''' - result = self._values.get("volume_claim_templates") - return typing.cast(typing.Optional[typing.List[KubePersistentVolumeClaimProps]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "StatefulSetSpec(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.StatefulSetUpdateStrategy", - jsii_struct_bases=[], - name_mapping={"rolling_update": "rollingUpdate", "type": "type"}, -) -class StatefulSetUpdateStrategy: - def __init__( - self, - *, - rolling_update: typing.Optional[typing.Union[RollingUpdateStatefulSetStrategy, typing.Dict[builtins.str, typing.Any]]] = None, - type: typing.Optional[builtins.str] = None, - ) -> None: - '''StatefulSetUpdateStrategy indicates the strategy that the StatefulSet controller will use to perform updates. - - It includes any additional parameters necessary to perform the update for the indicated strategy. - - :param rolling_update: RollingUpdate is used to communicate parameters when Type is RollingUpdateStatefulSetStrategyType. - :param type: Type indicates the type of the StatefulSetUpdateStrategy. Default is RollingUpdate. Default: RollingUpdate. - - :schema: io.k8s.api.apps.v1.StatefulSetUpdateStrategy - ''' - if isinstance(rolling_update, dict): - rolling_update = RollingUpdateStatefulSetStrategy(**rolling_update) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__376e0b967be23662818c61d56be6d18bdec2d63c793172960fbff07b791bc301) - check_type(argname="argument rolling_update", value=rolling_update, expected_type=type_hints["rolling_update"]) - check_type(argname="argument type", value=type, expected_type=type_hints["type"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if rolling_update is not None: - self._values["rolling_update"] = rolling_update - if type is not None: - self._values["type"] = type - - @builtins.property - def rolling_update(self) -> typing.Optional[RollingUpdateStatefulSetStrategy]: - '''RollingUpdate is used to communicate parameters when Type is RollingUpdateStatefulSetStrategyType. - - :schema: io.k8s.api.apps.v1.StatefulSetUpdateStrategy#rollingUpdate - ''' - result = self._values.get("rolling_update") - return typing.cast(typing.Optional[RollingUpdateStatefulSetStrategy], result) - - @builtins.property - def type(self) -> typing.Optional[builtins.str]: - '''Type indicates the type of the StatefulSetUpdateStrategy. - - Default is RollingUpdate. - - :default: RollingUpdate. - - :schema: io.k8s.api.apps.v1.StatefulSetUpdateStrategy#type - ''' - result = self._values.get("type") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "StatefulSetUpdateStrategy(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.StatusCause", - jsii_struct_bases=[], - name_mapping={"field": "field", "message": "message", "reason": "reason"}, -) -class StatusCause: - def __init__( - self, - *, - field: typing.Optional[builtins.str] = None, - message: typing.Optional[builtins.str] = None, - reason: typing.Optional[builtins.str] = None, - ) -> None: - '''StatusCause provides more information about an api.Status failure, including cases when multiple errors are encountered. - - :param field: The field of the resource that has caused this error, as named by its JSON serialization. May include dot and postfix notation for nested attributes. Arrays are zero-indexed. Fields may appear more than once in an array of causes due to fields having multiple errors. Optional. Examples: "name" - the field "name" on the current resource "items[0].name" - the field "name" on the first array entry in "items" - :param message: A human-readable description of the cause of the error. This field may be presented as-is to a reader. - :param reason: A machine-readable description of the cause of the error. If this value is empty there is no information available. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.StatusCause - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__9a84cad04e682eba7f45d6717bea7bd461527f9be5b61611af8ae5829ed76917) - check_type(argname="argument field", value=field, expected_type=type_hints["field"]) - check_type(argname="argument message", value=message, expected_type=type_hints["message"]) - check_type(argname="argument reason", value=reason, expected_type=type_hints["reason"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if field is not None: - self._values["field"] = field - if message is not None: - self._values["message"] = message - if reason is not None: - self._values["reason"] = reason - - @builtins.property - def field(self) -> typing.Optional[builtins.str]: - '''The field of the resource that has caused this error, as named by its JSON serialization. - - May include dot and postfix notation for nested attributes. Arrays are zero-indexed. Fields may appear more than once in an array of causes due to fields having multiple errors. Optional. - - Examples: - "name" - the field "name" on the current resource - "items[0].name" - the field "name" on the first array entry in "items" - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.StatusCause#field - ''' - result = self._values.get("field") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def message(self) -> typing.Optional[builtins.str]: - '''A human-readable description of the cause of the error. - - This field may be presented as-is to a reader. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.StatusCause#message - ''' - result = self._values.get("message") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def reason(self) -> typing.Optional[builtins.str]: - '''A machine-readable description of the cause of the error. - - If this value is empty there is no information available. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.StatusCause#reason - ''' - result = self._values.get("reason") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "StatusCause(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.StatusDetails", - jsii_struct_bases=[], - name_mapping={ - "causes": "causes", - "group": "group", - "kind": "kind", - "name": "name", - "retry_after_seconds": "retryAfterSeconds", - "uid": "uid", - }, -) -class StatusDetails: - def __init__( - self, - *, - causes: typing.Optional[typing.Sequence[typing.Union[StatusCause, typing.Dict[builtins.str, typing.Any]]]] = None, - group: typing.Optional[builtins.str] = None, - kind: typing.Optional[builtins.str] = None, - name: typing.Optional[builtins.str] = None, - retry_after_seconds: typing.Optional[jsii.Number] = None, - uid: typing.Optional[builtins.str] = None, - ) -> None: - '''StatusDetails is a set of additional properties that MAY be set by the server to provide additional information about a response. - - The Reason field of a Status object defines what attributes will be set. Clients must ignore fields that do not match the defined type of each attribute, and should assume that any attribute may be empty, invalid, or under defined. - - :param causes: The Causes array includes more details associated with the StatusReason failure. Not all StatusReasons may provide detailed causes. - :param group: The group attribute of the resource associated with the status StatusReason. - :param kind: The kind attribute of the resource associated with the status StatusReason. On some operations may differ from the requested resource Kind. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - :param name: The name attribute of the resource associated with the status StatusReason (when there is a single name which can be described). - :param retry_after_seconds: If specified, the time in seconds before the operation should be retried. Some errors may indicate the client must take an alternate action - for those errors this field may indicate how long to wait before taking the alternate action. - :param uid: UID of the resource. (when there is a single resource which can be described). More info: http://kubernetes.io/docs/user-guide/identifiers#uids - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.StatusDetails - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__86c96dd405073e5b3285a98f15293117917ec67b04be70820dcaf694a2ea1f98) - check_type(argname="argument causes", value=causes, expected_type=type_hints["causes"]) - check_type(argname="argument group", value=group, expected_type=type_hints["group"]) - check_type(argname="argument kind", value=kind, expected_type=type_hints["kind"]) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument retry_after_seconds", value=retry_after_seconds, expected_type=type_hints["retry_after_seconds"]) - check_type(argname="argument uid", value=uid, expected_type=type_hints["uid"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if causes is not None: - self._values["causes"] = causes - if group is not None: - self._values["group"] = group - if kind is not None: - self._values["kind"] = kind - if name is not None: - self._values["name"] = name - if retry_after_seconds is not None: - self._values["retry_after_seconds"] = retry_after_seconds - if uid is not None: - self._values["uid"] = uid - - @builtins.property - def causes(self) -> typing.Optional[typing.List[StatusCause]]: - '''The Causes array includes more details associated with the StatusReason failure. - - Not all StatusReasons may provide detailed causes. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.StatusDetails#causes - ''' - result = self._values.get("causes") - return typing.cast(typing.Optional[typing.List[StatusCause]], result) - - @builtins.property - def group(self) -> typing.Optional[builtins.str]: - '''The group attribute of the resource associated with the status StatusReason. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.StatusDetails#group - ''' - result = self._values.get("group") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def kind(self) -> typing.Optional[builtins.str]: - '''The kind attribute of the resource associated with the status StatusReason. - - On some operations may differ from the requested resource Kind. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.StatusDetails#kind - ''' - result = self._values.get("kind") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def name(self) -> typing.Optional[builtins.str]: - '''The name attribute of the resource associated with the status StatusReason (when there is a single name which can be described). - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.StatusDetails#name - ''' - result = self._values.get("name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def retry_after_seconds(self) -> typing.Optional[jsii.Number]: - '''If specified, the time in seconds before the operation should be retried. - - Some errors may indicate the client must take an alternate action - for those errors this field may indicate how long to wait before taking the alternate action. - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.StatusDetails#retryAfterSeconds - ''' - result = self._values.get("retry_after_seconds") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def uid(self) -> typing.Optional[builtins.str]: - '''UID of the resource. - - (when there is a single resource which can be described). More info: http://kubernetes.io/docs/user-guide/identifiers#uids - - :schema: io.k8s.apimachinery.pkg.apis.meta.v1.StatusDetails#uid - ''' - result = self._values.get("uid") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "StatusDetails(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.StorageOsPersistentVolumeSource", - jsii_struct_bases=[], - name_mapping={ - "fs_type": "fsType", - "read_only": "readOnly", - "secret_ref": "secretRef", - "volume_name": "volumeName", - "volume_namespace": "volumeNamespace", - }, -) -class StorageOsPersistentVolumeSource: - def __init__( - self, - *, - fs_type: typing.Optional[builtins.str] = None, - read_only: typing.Optional[builtins.bool] = None, - secret_ref: typing.Optional[typing.Union[ObjectReference, typing.Dict[builtins.str, typing.Any]]] = None, - volume_name: typing.Optional[builtins.str] = None, - volume_namespace: typing.Optional[builtins.str] = None, - ) -> None: - '''Represents a StorageOS persistent volume resource. - - :param fs_type: fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - :param read_only: readOnly defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. - :param secret_ref: secretRef specifies the secret to use for obtaining the StorageOS API credentials. If not specified, default values will be attempted. - :param volume_name: volumeName is the human-readable name of the StorageOS volume. Volume names are only unique within a namespace. - :param volume_namespace: volumeNamespace specifies the scope of the volume within StorageOS. If no namespace is specified then the Pod's namespace will be used. This allows the Kubernetes name scoping to be mirrored within StorageOS for tighter integration. Set VolumeName to any name to override the default behaviour. Set to "default" if you are not using namespaces within StorageOS. Namespaces that do not pre-exist within StorageOS will be created. - - :schema: io.k8s.api.core.v1.StorageOSPersistentVolumeSource - ''' - if isinstance(secret_ref, dict): - secret_ref = ObjectReference(**secret_ref) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__dcb3feea41d91b4ceb6ebfb62e681f60b70439c9ca50095a408680f3be68ff39) - check_type(argname="argument fs_type", value=fs_type, expected_type=type_hints["fs_type"]) - check_type(argname="argument read_only", value=read_only, expected_type=type_hints["read_only"]) - check_type(argname="argument secret_ref", value=secret_ref, expected_type=type_hints["secret_ref"]) - check_type(argname="argument volume_name", value=volume_name, expected_type=type_hints["volume_name"]) - check_type(argname="argument volume_namespace", value=volume_namespace, expected_type=type_hints["volume_namespace"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if fs_type is not None: - self._values["fs_type"] = fs_type - if read_only is not None: - self._values["read_only"] = read_only - if secret_ref is not None: - self._values["secret_ref"] = secret_ref - if volume_name is not None: - self._values["volume_name"] = volume_name - if volume_namespace is not None: - self._values["volume_namespace"] = volume_namespace - - @builtins.property - def fs_type(self) -> typing.Optional[builtins.str]: - '''fsType is the filesystem type to mount. - - Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - - :schema: io.k8s.api.core.v1.StorageOSPersistentVolumeSource#fsType - ''' - result = self._values.get("fs_type") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def read_only(self) -> typing.Optional[builtins.bool]: - '''readOnly defaults to false (read/write). - - ReadOnly here will force the ReadOnly setting in VolumeMounts. - - :schema: io.k8s.api.core.v1.StorageOSPersistentVolumeSource#readOnly - ''' - result = self._values.get("read_only") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def secret_ref(self) -> typing.Optional[ObjectReference]: - '''secretRef specifies the secret to use for obtaining the StorageOS API credentials. - - If not specified, default values will be attempted. - - :schema: io.k8s.api.core.v1.StorageOSPersistentVolumeSource#secretRef - ''' - result = self._values.get("secret_ref") - return typing.cast(typing.Optional[ObjectReference], result) - - @builtins.property - def volume_name(self) -> typing.Optional[builtins.str]: - '''volumeName is the human-readable name of the StorageOS volume. - - Volume names are only unique within a namespace. - - :schema: io.k8s.api.core.v1.StorageOSPersistentVolumeSource#volumeName - ''' - result = self._values.get("volume_name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def volume_namespace(self) -> typing.Optional[builtins.str]: - '''volumeNamespace specifies the scope of the volume within StorageOS. - - If no namespace is specified then the Pod's namespace will be used. This allows the Kubernetes name scoping to be mirrored within StorageOS for tighter integration. Set VolumeName to any name to override the default behaviour. Set to "default" if you are not using namespaces within StorageOS. Namespaces that do not pre-exist within StorageOS will be created. - - :schema: io.k8s.api.core.v1.StorageOSPersistentVolumeSource#volumeNamespace - ''' - result = self._values.get("volume_namespace") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "StorageOsPersistentVolumeSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.StorageOsVolumeSource", - jsii_struct_bases=[], - name_mapping={ - "fs_type": "fsType", - "read_only": "readOnly", - "secret_ref": "secretRef", - "volume_name": "volumeName", - "volume_namespace": "volumeNamespace", - }, -) -class StorageOsVolumeSource: - def __init__( - self, - *, - fs_type: typing.Optional[builtins.str] = None, - read_only: typing.Optional[builtins.bool] = None, - secret_ref: typing.Optional[typing.Union[LocalObjectReference, typing.Dict[builtins.str, typing.Any]]] = None, - volume_name: typing.Optional[builtins.str] = None, - volume_namespace: typing.Optional[builtins.str] = None, - ) -> None: - '''Represents a StorageOS persistent volume resource. - - :param fs_type: fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - :param read_only: readOnly defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. - :param secret_ref: secretRef specifies the secret to use for obtaining the StorageOS API credentials. If not specified, default values will be attempted. - :param volume_name: volumeName is the human-readable name of the StorageOS volume. Volume names are only unique within a namespace. - :param volume_namespace: volumeNamespace specifies the scope of the volume within StorageOS. If no namespace is specified then the Pod's namespace will be used. This allows the Kubernetes name scoping to be mirrored within StorageOS for tighter integration. Set VolumeName to any name to override the default behaviour. Set to "default" if you are not using namespaces within StorageOS. Namespaces that do not pre-exist within StorageOS will be created. - - :schema: io.k8s.api.core.v1.StorageOSVolumeSource - ''' - if isinstance(secret_ref, dict): - secret_ref = LocalObjectReference(**secret_ref) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__5d2e2a4a4a5336dd9d67d0c9d9952b1bd60bcf2097cd69ae70efbfd4bafa92b4) - check_type(argname="argument fs_type", value=fs_type, expected_type=type_hints["fs_type"]) - check_type(argname="argument read_only", value=read_only, expected_type=type_hints["read_only"]) - check_type(argname="argument secret_ref", value=secret_ref, expected_type=type_hints["secret_ref"]) - check_type(argname="argument volume_name", value=volume_name, expected_type=type_hints["volume_name"]) - check_type(argname="argument volume_namespace", value=volume_namespace, expected_type=type_hints["volume_namespace"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if fs_type is not None: - self._values["fs_type"] = fs_type - if read_only is not None: - self._values["read_only"] = read_only - if secret_ref is not None: - self._values["secret_ref"] = secret_ref - if volume_name is not None: - self._values["volume_name"] = volume_name - if volume_namespace is not None: - self._values["volume_namespace"] = volume_namespace - - @builtins.property - def fs_type(self) -> typing.Optional[builtins.str]: - '''fsType is the filesystem type to mount. - - Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - - :schema: io.k8s.api.core.v1.StorageOSVolumeSource#fsType - ''' - result = self._values.get("fs_type") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def read_only(self) -> typing.Optional[builtins.bool]: - '''readOnly defaults to false (read/write). - - ReadOnly here will force the ReadOnly setting in VolumeMounts. - - :schema: io.k8s.api.core.v1.StorageOSVolumeSource#readOnly - ''' - result = self._values.get("read_only") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def secret_ref(self) -> typing.Optional[LocalObjectReference]: - '''secretRef specifies the secret to use for obtaining the StorageOS API credentials. - - If not specified, default values will be attempted. - - :schema: io.k8s.api.core.v1.StorageOSVolumeSource#secretRef - ''' - result = self._values.get("secret_ref") - return typing.cast(typing.Optional[LocalObjectReference], result) - - @builtins.property - def volume_name(self) -> typing.Optional[builtins.str]: - '''volumeName is the human-readable name of the StorageOS volume. - - Volume names are only unique within a namespace. - - :schema: io.k8s.api.core.v1.StorageOSVolumeSource#volumeName - ''' - result = self._values.get("volume_name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def volume_namespace(self) -> typing.Optional[builtins.str]: - '''volumeNamespace specifies the scope of the volume within StorageOS. - - If no namespace is specified then the Pod's namespace will be used. This allows the Kubernetes name scoping to be mirrored within StorageOS for tighter integration. Set VolumeName to any name to override the default behaviour. Set to "default" if you are not using namespaces within StorageOS. Namespaces that do not pre-exist within StorageOS will be created. - - :schema: io.k8s.api.core.v1.StorageOSVolumeSource#volumeNamespace - ''' - result = self._values.get("volume_namespace") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "StorageOsVolumeSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.Subject", - jsii_struct_bases=[], - name_mapping={ - "kind": "kind", - "name": "name", - "api_group": "apiGroup", - "namespace": "namespace", - }, -) -class Subject: - def __init__( - self, - *, - kind: builtins.str, - name: builtins.str, - api_group: typing.Optional[builtins.str] = None, - namespace: typing.Optional[builtins.str] = None, - ) -> None: - '''Subject contains a reference to the object or user identities a role binding applies to. - - This can either hold a direct API object reference, or a value for non-objects such as user and group names. - - :param kind: Kind of object being referenced. Values defined by this API group are "User", "Group", and "ServiceAccount". If the Authorizer does not recognized the kind value, the Authorizer should report an error. - :param name: Name of the object being referenced. - :param api_group: APIGroup holds the API group of the referenced subject. Defaults to "" for ServiceAccount subjects. Defaults to "rbac.authorization.k8s.io" for User and Group subjects. Default: for ServiceAccount subjects. Defaults to "rbac.authorization.k8s.io" for User and Group subjects. - :param namespace: Namespace of the referenced object. If the object kind is non-namespace, such as "User" or "Group", and this value is not empty the Authorizer should report an error. - - :schema: io.k8s.api.rbac.v1.Subject - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__3984acd97248bbea84b86bad6e78e1c94aee46eaf7dce10320654c981464a3aa) - check_type(argname="argument kind", value=kind, expected_type=type_hints["kind"]) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument api_group", value=api_group, expected_type=type_hints["api_group"]) - check_type(argname="argument namespace", value=namespace, expected_type=type_hints["namespace"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "kind": kind, - "name": name, - } - if api_group is not None: - self._values["api_group"] = api_group - if namespace is not None: - self._values["namespace"] = namespace - - @builtins.property - def kind(self) -> builtins.str: - '''Kind of object being referenced. - - Values defined by this API group are "User", "Group", and "ServiceAccount". If the Authorizer does not recognized the kind value, the Authorizer should report an error. - - :schema: io.k8s.api.rbac.v1.Subject#kind - ''' - result = self._values.get("kind") - assert result is not None, "Required property 'kind' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def name(self) -> builtins.str: - '''Name of the object being referenced. - - :schema: io.k8s.api.rbac.v1.Subject#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def api_group(self) -> typing.Optional[builtins.str]: - '''APIGroup holds the API group of the referenced subject. - - Defaults to "" for ServiceAccount subjects. Defaults to "rbac.authorization.k8s.io" for User and Group subjects. - - :default: for ServiceAccount subjects. Defaults to "rbac.authorization.k8s.io" for User and Group subjects. - - :schema: io.k8s.api.rbac.v1.Subject#apiGroup - ''' - result = self._values.get("api_group") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def namespace(self) -> typing.Optional[builtins.str]: - '''Namespace of the referenced object. - - If the object kind is non-namespace, such as "User" or "Group", and this value is not empty the Authorizer should report an error. - - :schema: io.k8s.api.rbac.v1.Subject#namespace - ''' - result = self._values.get("namespace") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "Subject(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.SubjectAccessReviewSpec", - jsii_struct_bases=[], - name_mapping={ - "extra": "extra", - "groups": "groups", - "non_resource_attributes": "nonResourceAttributes", - "resource_attributes": "resourceAttributes", - "uid": "uid", - "user": "user", - }, -) -class SubjectAccessReviewSpec: - def __init__( - self, - *, - extra: typing.Optional[typing.Mapping[builtins.str, typing.Sequence[builtins.str]]] = None, - groups: typing.Optional[typing.Sequence[builtins.str]] = None, - non_resource_attributes: typing.Optional[typing.Union[NonResourceAttributes, typing.Dict[builtins.str, typing.Any]]] = None, - resource_attributes: typing.Optional[typing.Union[ResourceAttributes, typing.Dict[builtins.str, typing.Any]]] = None, - uid: typing.Optional[builtins.str] = None, - user: typing.Optional[builtins.str] = None, - ) -> None: - '''SubjectAccessReviewSpec is a description of the access request. - - Exactly one of ResourceAuthorizationAttributes and NonResourceAuthorizationAttributes must be set - - :param extra: Extra corresponds to the user.Info.GetExtra() method from the authenticator. Since that is input to the authorizer it needs a reflection here. - :param groups: Groups is the groups you're testing for. - :param non_resource_attributes: NonResourceAttributes describes information for a non-resource access request. - :param resource_attributes: ResourceAuthorizationAttributes describes information for a resource access request. - :param uid: UID information about the requesting user. - :param user: User is the user you're testing for. If you specify "User" but not "Groups", then is it interpreted as "What if User were not a member of any groups - - :schema: io.k8s.api.authorization.v1.SubjectAccessReviewSpec - ''' - if isinstance(non_resource_attributes, dict): - non_resource_attributes = NonResourceAttributes(**non_resource_attributes) - if isinstance(resource_attributes, dict): - resource_attributes = ResourceAttributes(**resource_attributes) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__aecec73f519b5097699d859a6173cfe87c594463900289ecfb24c4a3c623ca4a) - check_type(argname="argument extra", value=extra, expected_type=type_hints["extra"]) - check_type(argname="argument groups", value=groups, expected_type=type_hints["groups"]) - check_type(argname="argument non_resource_attributes", value=non_resource_attributes, expected_type=type_hints["non_resource_attributes"]) - check_type(argname="argument resource_attributes", value=resource_attributes, expected_type=type_hints["resource_attributes"]) - check_type(argname="argument uid", value=uid, expected_type=type_hints["uid"]) - check_type(argname="argument user", value=user, expected_type=type_hints["user"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if extra is not None: - self._values["extra"] = extra - if groups is not None: - self._values["groups"] = groups - if non_resource_attributes is not None: - self._values["non_resource_attributes"] = non_resource_attributes - if resource_attributes is not None: - self._values["resource_attributes"] = resource_attributes - if uid is not None: - self._values["uid"] = uid - if user is not None: - self._values["user"] = user - - @builtins.property - def extra( - self, - ) -> typing.Optional[typing.Mapping[builtins.str, typing.List[builtins.str]]]: - '''Extra corresponds to the user.Info.GetExtra() method from the authenticator. Since that is input to the authorizer it needs a reflection here. - - :schema: io.k8s.api.authorization.v1.SubjectAccessReviewSpec#extra - ''' - result = self._values.get("extra") - return typing.cast(typing.Optional[typing.Mapping[builtins.str, typing.List[builtins.str]]], result) - - @builtins.property - def groups(self) -> typing.Optional[typing.List[builtins.str]]: - '''Groups is the groups you're testing for. - - :schema: io.k8s.api.authorization.v1.SubjectAccessReviewSpec#groups - ''' - result = self._values.get("groups") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def non_resource_attributes(self) -> typing.Optional[NonResourceAttributes]: - '''NonResourceAttributes describes information for a non-resource access request. - - :schema: io.k8s.api.authorization.v1.SubjectAccessReviewSpec#nonResourceAttributes - ''' - result = self._values.get("non_resource_attributes") - return typing.cast(typing.Optional[NonResourceAttributes], result) - - @builtins.property - def resource_attributes(self) -> typing.Optional[ResourceAttributes]: - '''ResourceAuthorizationAttributes describes information for a resource access request. - - :schema: io.k8s.api.authorization.v1.SubjectAccessReviewSpec#resourceAttributes - ''' - result = self._values.get("resource_attributes") - return typing.cast(typing.Optional[ResourceAttributes], result) - - @builtins.property - def uid(self) -> typing.Optional[builtins.str]: - '''UID information about the requesting user. - - :schema: io.k8s.api.authorization.v1.SubjectAccessReviewSpec#uid - ''' - result = self._values.get("uid") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def user(self) -> typing.Optional[builtins.str]: - '''User is the user you're testing for. - - If you specify "User" but not "Groups", then is it interpreted as "What if User were not a member of any groups - - :schema: io.k8s.api.authorization.v1.SubjectAccessReviewSpec#user - ''' - result = self._values.get("user") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "SubjectAccessReviewSpec(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.SubjectV1Beta2", - jsii_struct_bases=[], - name_mapping={ - "kind": "kind", - "group": "group", - "service_account": "serviceAccount", - "user": "user", - }, -) -class SubjectV1Beta2: - def __init__( - self, - *, - kind: builtins.str, - group: typing.Optional[typing.Union[GroupSubjectV1Beta2, typing.Dict[builtins.str, typing.Any]]] = None, - service_account: typing.Optional[typing.Union[ServiceAccountSubjectV1Beta2, typing.Dict[builtins.str, typing.Any]]] = None, - user: typing.Optional[typing.Union["UserSubjectV1Beta2", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Subject matches the originator of a request, as identified by the request authentication system. - - There are three ways of matching an originator; by user, group, or service account. - - :param kind: ``kind`` indicates which one of the other fields is non-empty. Required - :param group: ``group`` matches based on user group name. - :param service_account: ``serviceAccount`` matches ServiceAccounts. - :param user: ``user`` matches based on username. - - :schema: io.k8s.api.flowcontrol.v1beta2.Subject - ''' - if isinstance(group, dict): - group = GroupSubjectV1Beta2(**group) - if isinstance(service_account, dict): - service_account = ServiceAccountSubjectV1Beta2(**service_account) - if isinstance(user, dict): - user = UserSubjectV1Beta2(**user) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__65ada18dc9b20030468e8eb483d832680b97ad6e44b4cc62b86e84cd497f848d) - check_type(argname="argument kind", value=kind, expected_type=type_hints["kind"]) - check_type(argname="argument group", value=group, expected_type=type_hints["group"]) - check_type(argname="argument service_account", value=service_account, expected_type=type_hints["service_account"]) - check_type(argname="argument user", value=user, expected_type=type_hints["user"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "kind": kind, - } - if group is not None: - self._values["group"] = group - if service_account is not None: - self._values["service_account"] = service_account - if user is not None: - self._values["user"] = user - - @builtins.property - def kind(self) -> builtins.str: - '''``kind`` indicates which one of the other fields is non-empty. - - Required - - :schema: io.k8s.api.flowcontrol.v1beta2.Subject#kind - ''' - result = self._values.get("kind") - assert result is not None, "Required property 'kind' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def group(self) -> typing.Optional[GroupSubjectV1Beta2]: - '''``group`` matches based on user group name. - - :schema: io.k8s.api.flowcontrol.v1beta2.Subject#group - ''' - result = self._values.get("group") - return typing.cast(typing.Optional[GroupSubjectV1Beta2], result) - - @builtins.property - def service_account(self) -> typing.Optional[ServiceAccountSubjectV1Beta2]: - '''``serviceAccount`` matches ServiceAccounts. - - :schema: io.k8s.api.flowcontrol.v1beta2.Subject#serviceAccount - ''' - result = self._values.get("service_account") - return typing.cast(typing.Optional[ServiceAccountSubjectV1Beta2], result) - - @builtins.property - def user(self) -> typing.Optional["UserSubjectV1Beta2"]: - '''``user`` matches based on username. - - :schema: io.k8s.api.flowcontrol.v1beta2.Subject#user - ''' - result = self._values.get("user") - return typing.cast(typing.Optional["UserSubjectV1Beta2"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "SubjectV1Beta2(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.SubjectV1Beta3", - jsii_struct_bases=[], - name_mapping={ - "kind": "kind", - "group": "group", - "service_account": "serviceAccount", - "user": "user", - }, -) -class SubjectV1Beta3: - def __init__( - self, - *, - kind: builtins.str, - group: typing.Optional[typing.Union[GroupSubjectV1Beta3, typing.Dict[builtins.str, typing.Any]]] = None, - service_account: typing.Optional[typing.Union[ServiceAccountSubjectV1Beta3, typing.Dict[builtins.str, typing.Any]]] = None, - user: typing.Optional[typing.Union["UserSubjectV1Beta3", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Subject matches the originator of a request, as identified by the request authentication system. - - There are three ways of matching an originator; by user, group, or service account. - - :param kind: ``kind`` indicates which one of the other fields is non-empty. Required - :param group: ``group`` matches based on user group name. - :param service_account: ``serviceAccount`` matches ServiceAccounts. - :param user: ``user`` matches based on username. - - :schema: io.k8s.api.flowcontrol.v1beta3.Subject - ''' - if isinstance(group, dict): - group = GroupSubjectV1Beta3(**group) - if isinstance(service_account, dict): - service_account = ServiceAccountSubjectV1Beta3(**service_account) - if isinstance(user, dict): - user = UserSubjectV1Beta3(**user) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__a46ab1f8a869330d80daeca76c731f5168b250899559c5f9260da9dae23b95e3) - check_type(argname="argument kind", value=kind, expected_type=type_hints["kind"]) - check_type(argname="argument group", value=group, expected_type=type_hints["group"]) - check_type(argname="argument service_account", value=service_account, expected_type=type_hints["service_account"]) - check_type(argname="argument user", value=user, expected_type=type_hints["user"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "kind": kind, - } - if group is not None: - self._values["group"] = group - if service_account is not None: - self._values["service_account"] = service_account - if user is not None: - self._values["user"] = user - - @builtins.property - def kind(self) -> builtins.str: - '''``kind`` indicates which one of the other fields is non-empty. - - Required - - :schema: io.k8s.api.flowcontrol.v1beta3.Subject#kind - ''' - result = self._values.get("kind") - assert result is not None, "Required property 'kind' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def group(self) -> typing.Optional[GroupSubjectV1Beta3]: - '''``group`` matches based on user group name. - - :schema: io.k8s.api.flowcontrol.v1beta3.Subject#group - ''' - result = self._values.get("group") - return typing.cast(typing.Optional[GroupSubjectV1Beta3], result) - - @builtins.property - def service_account(self) -> typing.Optional[ServiceAccountSubjectV1Beta3]: - '''``serviceAccount`` matches ServiceAccounts. - - :schema: io.k8s.api.flowcontrol.v1beta3.Subject#serviceAccount - ''' - result = self._values.get("service_account") - return typing.cast(typing.Optional[ServiceAccountSubjectV1Beta3], result) - - @builtins.property - def user(self) -> typing.Optional["UserSubjectV1Beta3"]: - '''``user`` matches based on username. - - :schema: io.k8s.api.flowcontrol.v1beta3.Subject#user - ''' - result = self._values.get("user") - return typing.cast(typing.Optional["UserSubjectV1Beta3"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "SubjectV1Beta3(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.Sysctl", - jsii_struct_bases=[], - name_mapping={"name": "name", "value": "value"}, -) -class Sysctl: - def __init__(self, *, name: builtins.str, value: builtins.str) -> None: - '''Sysctl defines a kernel parameter to be set. - - :param name: Name of a property to set. - :param value: Value of a property to set. - - :schema: io.k8s.api.core.v1.Sysctl - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__9ebcbff853e5595a246037a229aabe3a4bd6f6aa6b8deb141b7669a41d7f6ca4) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument value", value=value, expected_type=type_hints["value"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "name": name, - "value": value, - } - - @builtins.property - def name(self) -> builtins.str: - '''Name of a property to set. - - :schema: io.k8s.api.core.v1.Sysctl#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def value(self) -> builtins.str: - '''Value of a property to set. - - :schema: io.k8s.api.core.v1.Sysctl#value - ''' - result = self._values.get("value") - assert result is not None, "Required property 'value' is missing" - return typing.cast(builtins.str, result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "Sysctl(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.Taint", - jsii_struct_bases=[], - name_mapping={ - "effect": "effect", - "key": "key", - "time_added": "timeAdded", - "value": "value", - }, -) -class Taint: - def __init__( - self, - *, - effect: builtins.str, - key: builtins.str, - time_added: typing.Optional[datetime.datetime] = None, - value: typing.Optional[builtins.str] = None, - ) -> None: - '''The node this Taint is attached to has the "effect" on any pod that does not tolerate the Taint. - - :param effect: Required. The effect of the taint on pods that do not tolerate the taint. Valid effects are NoSchedule, PreferNoSchedule and NoExecute. - :param key: Required. The taint key to be applied to a node. - :param time_added: TimeAdded represents the time at which the taint was added. It is only written for NoExecute taints. - :param value: The taint value corresponding to the taint key. - - :schema: io.k8s.api.core.v1.Taint - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__c83d8efd7618c397938f355d9ce22e16abef5083f86d96444f7001334f075b74) - check_type(argname="argument effect", value=effect, expected_type=type_hints["effect"]) - check_type(argname="argument key", value=key, expected_type=type_hints["key"]) - check_type(argname="argument time_added", value=time_added, expected_type=type_hints["time_added"]) - check_type(argname="argument value", value=value, expected_type=type_hints["value"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "effect": effect, - "key": key, - } - if time_added is not None: - self._values["time_added"] = time_added - if value is not None: - self._values["value"] = value - - @builtins.property - def effect(self) -> builtins.str: - '''Required. - - The effect of the taint on pods that do not tolerate the taint. Valid effects are NoSchedule, PreferNoSchedule and NoExecute. - - :schema: io.k8s.api.core.v1.Taint#effect - ''' - result = self._values.get("effect") - assert result is not None, "Required property 'effect' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def key(self) -> builtins.str: - '''Required. - - The taint key to be applied to a node. - - :schema: io.k8s.api.core.v1.Taint#key - ''' - result = self._values.get("key") - assert result is not None, "Required property 'key' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def time_added(self) -> typing.Optional[datetime.datetime]: - '''TimeAdded represents the time at which the taint was added. - - It is only written for NoExecute taints. - - :schema: io.k8s.api.core.v1.Taint#timeAdded - ''' - result = self._values.get("time_added") - return typing.cast(typing.Optional[datetime.datetime], result) - - @builtins.property - def value(self) -> typing.Optional[builtins.str]: - '''The taint value corresponding to the taint key. - - :schema: io.k8s.api.core.v1.Taint#value - ''' - result = self._values.get("value") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "Taint(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.TcpSocketAction", - jsii_struct_bases=[], - name_mapping={"port": "port", "host": "host"}, -) -class TcpSocketAction: - def __init__( - self, - *, - port: IntOrString, - host: typing.Optional[builtins.str] = None, - ) -> None: - '''TCPSocketAction describes an action based on opening a socket. - - :param port: Number or name of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. - :param host: Optional: Host name to connect to, defaults to the pod IP. - - :schema: io.k8s.api.core.v1.TCPSocketAction - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__4153948139cfde3a540da2062fd40a5b8a03f099e85f3acd26bee80243897532) - check_type(argname="argument port", value=port, expected_type=type_hints["port"]) - check_type(argname="argument host", value=host, expected_type=type_hints["host"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "port": port, - } - if host is not None: - self._values["host"] = host - - @builtins.property - def port(self) -> IntOrString: - '''Number or name of the port to access on the container. - - Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. - - :schema: io.k8s.api.core.v1.TCPSocketAction#port - ''' - result = self._values.get("port") - assert result is not None, "Required property 'port' is missing" - return typing.cast(IntOrString, result) - - @builtins.property - def host(self) -> typing.Optional[builtins.str]: - '''Optional: Host name to connect to, defaults to the pod IP. - - :schema: io.k8s.api.core.v1.TCPSocketAction#host - ''' - result = self._values.get("host") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "TcpSocketAction(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.TokenRequest", - jsii_struct_bases=[], - name_mapping={"audience": "audience", "expiration_seconds": "expirationSeconds"}, -) -class TokenRequest: - def __init__( - self, - *, - audience: builtins.str, - expiration_seconds: typing.Optional[jsii.Number] = None, - ) -> None: - '''TokenRequest contains parameters of a service account token. - - :param audience: Audience is the intended audience of the token in "TokenRequestSpec". It will default to the audiences of kube apiserver. - :param expiration_seconds: ExpirationSeconds is the duration of validity of the token in "TokenRequestSpec". It has the same default value of "ExpirationSeconds" in "TokenRequestSpec". - - :schema: io.k8s.api.storage.v1.TokenRequest - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__a2eca0bb8eadb510ffaf95db1104ca4195c2708f05a8a378b0cd66f7b398bee9) - check_type(argname="argument audience", value=audience, expected_type=type_hints["audience"]) - check_type(argname="argument expiration_seconds", value=expiration_seconds, expected_type=type_hints["expiration_seconds"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "audience": audience, - } - if expiration_seconds is not None: - self._values["expiration_seconds"] = expiration_seconds - - @builtins.property - def audience(self) -> builtins.str: - '''Audience is the intended audience of the token in "TokenRequestSpec". - - It will default to the audiences of kube apiserver. - - :schema: io.k8s.api.storage.v1.TokenRequest#audience - ''' - result = self._values.get("audience") - assert result is not None, "Required property 'audience' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def expiration_seconds(self) -> typing.Optional[jsii.Number]: - '''ExpirationSeconds is the duration of validity of the token in "TokenRequestSpec". - - It has the same default value of "ExpirationSeconds" in "TokenRequestSpec". - - :schema: io.k8s.api.storage.v1.TokenRequest#expirationSeconds - ''' - result = self._values.get("expiration_seconds") - return typing.cast(typing.Optional[jsii.Number], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "TokenRequest(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.TokenRequestSpec", - jsii_struct_bases=[], - name_mapping={ - "audiences": "audiences", - "bound_object_ref": "boundObjectRef", - "expiration_seconds": "expirationSeconds", - }, -) -class TokenRequestSpec: - def __init__( - self, - *, - audiences: typing.Sequence[builtins.str], - bound_object_ref: typing.Optional[typing.Union[BoundObjectReference, typing.Dict[builtins.str, typing.Any]]] = None, - expiration_seconds: typing.Optional[jsii.Number] = None, - ) -> None: - '''TokenRequestSpec contains client provided parameters of a token request. - - :param audiences: Audiences are the intendend audiences of the token. A recipient of a token must identify themself with an identifier in the list of audiences of the token, and otherwise should reject the token. A token issued for multiple audiences may be used to authenticate against any of the audiences listed but implies a high degree of trust between the target audiences. - :param bound_object_ref: BoundObjectRef is a reference to an object that the token will be bound to. The token will only be valid for as long as the bound object exists. NOTE: The API server's TokenReview endpoint will validate the BoundObjectRef, but other audiences may not. Keep ExpirationSeconds small if you want prompt revocation. - :param expiration_seconds: ExpirationSeconds is the requested duration of validity of the request. The token issuer may return a token with a different validity duration so a client needs to check the 'expiration' field in a response. - - :schema: io.k8s.api.authentication.v1.TokenRequestSpec - ''' - if isinstance(bound_object_ref, dict): - bound_object_ref = BoundObjectReference(**bound_object_ref) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__1c6ecf81dacd22a528a277c2eacd8c58c1bb9bead7fa63a6eb43b6ba97554708) - check_type(argname="argument audiences", value=audiences, expected_type=type_hints["audiences"]) - check_type(argname="argument bound_object_ref", value=bound_object_ref, expected_type=type_hints["bound_object_ref"]) - check_type(argname="argument expiration_seconds", value=expiration_seconds, expected_type=type_hints["expiration_seconds"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "audiences": audiences, - } - if bound_object_ref is not None: - self._values["bound_object_ref"] = bound_object_ref - if expiration_seconds is not None: - self._values["expiration_seconds"] = expiration_seconds - - @builtins.property - def audiences(self) -> typing.List[builtins.str]: - '''Audiences are the intendend audiences of the token. - - A recipient of a token must identify themself with an identifier in the list of audiences of the token, and otherwise should reject the token. A token issued for multiple audiences may be used to authenticate against any of the audiences listed but implies a high degree of trust between the target audiences. - - :schema: io.k8s.api.authentication.v1.TokenRequestSpec#audiences - ''' - result = self._values.get("audiences") - assert result is not None, "Required property 'audiences' is missing" - return typing.cast(typing.List[builtins.str], result) - - @builtins.property - def bound_object_ref(self) -> typing.Optional[BoundObjectReference]: - '''BoundObjectRef is a reference to an object that the token will be bound to. - - The token will only be valid for as long as the bound object exists. NOTE: The API server's TokenReview endpoint will validate the BoundObjectRef, but other audiences may not. Keep ExpirationSeconds small if you want prompt revocation. - - :schema: io.k8s.api.authentication.v1.TokenRequestSpec#boundObjectRef - ''' - result = self._values.get("bound_object_ref") - return typing.cast(typing.Optional[BoundObjectReference], result) - - @builtins.property - def expiration_seconds(self) -> typing.Optional[jsii.Number]: - '''ExpirationSeconds is the requested duration of validity of the request. - - The token issuer may return a token with a different validity duration so a client needs to check the 'expiration' field in a response. - - :schema: io.k8s.api.authentication.v1.TokenRequestSpec#expirationSeconds - ''' - result = self._values.get("expiration_seconds") - return typing.cast(typing.Optional[jsii.Number], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "TokenRequestSpec(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.TokenReviewSpec", - jsii_struct_bases=[], - name_mapping={"audiences": "audiences", "token": "token"}, -) -class TokenReviewSpec: - def __init__( - self, - *, - audiences: typing.Optional[typing.Sequence[builtins.str]] = None, - token: typing.Optional[builtins.str] = None, - ) -> None: - '''TokenReviewSpec is a description of the token authentication request. - - :param audiences: Audiences is a list of the identifiers that the resource server presented with the token identifies as. Audience-aware token authenticators will verify that the token was intended for at least one of the audiences in this list. If no audiences are provided, the audience will default to the audience of the Kubernetes apiserver. - :param token: Token is the opaque bearer token. - - :schema: io.k8s.api.authentication.v1.TokenReviewSpec - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__9132ea931e42ff03246a2f8dce15a0589348550d3687a44aa8d9ba434d2757ce) - check_type(argname="argument audiences", value=audiences, expected_type=type_hints["audiences"]) - check_type(argname="argument token", value=token, expected_type=type_hints["token"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if audiences is not None: - self._values["audiences"] = audiences - if token is not None: - self._values["token"] = token - - @builtins.property - def audiences(self) -> typing.Optional[typing.List[builtins.str]]: - '''Audiences is a list of the identifiers that the resource server presented with the token identifies as. - - Audience-aware token authenticators will verify that the token was intended for at least one of the audiences in this list. If no audiences are provided, the audience will default to the audience of the Kubernetes apiserver. - - :schema: io.k8s.api.authentication.v1.TokenReviewSpec#audiences - ''' - result = self._values.get("audiences") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def token(self) -> typing.Optional[builtins.str]: - '''Token is the opaque bearer token. - - :schema: io.k8s.api.authentication.v1.TokenReviewSpec#token - ''' - result = self._values.get("token") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "TokenReviewSpec(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.Toleration", - jsii_struct_bases=[], - name_mapping={ - "effect": "effect", - "key": "key", - "operator": "operator", - "toleration_seconds": "tolerationSeconds", - "value": "value", - }, -) -class Toleration: - def __init__( - self, - *, - effect: typing.Optional[builtins.str] = None, - key: typing.Optional[builtins.str] = None, - operator: typing.Optional[builtins.str] = None, - toleration_seconds: typing.Optional[jsii.Number] = None, - value: typing.Optional[builtins.str] = None, - ) -> None: - '''The pod this Toleration is attached to tolerates any taint that matches the triple using the matching operator . - - :param effect: Effect indicates the taint effect to match. Empty means match all taint effects. When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - :param key: Key is the taint key that the toleration applies to. Empty means match all taint keys. If the key is empty, operator must be Exists; this combination means to match all values and all keys. - :param operator: Operator represents a key's relationship to the value. Valid operators are Exists and Equal. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. Default: Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. - :param toleration_seconds: TolerationSeconds represents the period of time the toleration (which must be of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, it is not set, which means tolerate the taint forever (do not evict). Zero and negative values will be treated as 0 (evict immediately) by the system. - :param value: Value is the taint value the toleration matches to. If the operator is Exists, the value should be empty, otherwise just a regular string. - - :schema: io.k8s.api.core.v1.Toleration - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__fc64b64ca6a4e327627ef4fc0e43d3b9ed50e8e8d69828c2afe44f74a3b45f9f) - check_type(argname="argument effect", value=effect, expected_type=type_hints["effect"]) - check_type(argname="argument key", value=key, expected_type=type_hints["key"]) - check_type(argname="argument operator", value=operator, expected_type=type_hints["operator"]) - check_type(argname="argument toleration_seconds", value=toleration_seconds, expected_type=type_hints["toleration_seconds"]) - check_type(argname="argument value", value=value, expected_type=type_hints["value"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if effect is not None: - self._values["effect"] = effect - if key is not None: - self._values["key"] = key - if operator is not None: - self._values["operator"] = operator - if toleration_seconds is not None: - self._values["toleration_seconds"] = toleration_seconds - if value is not None: - self._values["value"] = value - - @builtins.property - def effect(self) -> typing.Optional[builtins.str]: - '''Effect indicates the taint effect to match. - - Empty means match all taint effects. When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - - :schema: io.k8s.api.core.v1.Toleration#effect - ''' - result = self._values.get("effect") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def key(self) -> typing.Optional[builtins.str]: - '''Key is the taint key that the toleration applies to. - - Empty means match all taint keys. If the key is empty, operator must be Exists; this combination means to match all values and all keys. - - :schema: io.k8s.api.core.v1.Toleration#key - ''' - result = self._values.get("key") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def operator(self) -> typing.Optional[builtins.str]: - '''Operator represents a key's relationship to the value. - - Valid operators are Exists and Equal. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. - - :default: Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. - - :schema: io.k8s.api.core.v1.Toleration#operator - ''' - result = self._values.get("operator") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def toleration_seconds(self) -> typing.Optional[jsii.Number]: - '''TolerationSeconds represents the period of time the toleration (which must be of effect NoExecute, otherwise this field is ignored) tolerates the taint. - - By default, it is not set, which means tolerate the taint forever (do not evict). Zero and negative values will be treated as 0 (evict immediately) by the system. - - :schema: io.k8s.api.core.v1.Toleration#tolerationSeconds - ''' - result = self._values.get("toleration_seconds") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def value(self) -> typing.Optional[builtins.str]: - '''Value is the taint value the toleration matches to. - - If the operator is Exists, the value should be empty, otherwise just a regular string. - - :schema: io.k8s.api.core.v1.Toleration#value - ''' - result = self._values.get("value") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "Toleration(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.TopologySelectorLabelRequirement", - jsii_struct_bases=[], - name_mapping={"key": "key", "values": "values"}, -) -class TopologySelectorLabelRequirement: - def __init__( - self, - *, - key: builtins.str, - values: typing.Sequence[builtins.str], - ) -> None: - '''A topology selector requirement is a selector that matches given label. - - This is an alpha feature and may change in the future. - - :param key: The label key that the selector applies to. - :param values: An array of string values. One value must match the label to be selected. Each entry in Values is ORed. - - :schema: io.k8s.api.core.v1.TopologySelectorLabelRequirement - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__25a9d23f38a251fc5c0330f0132bfd279ea0abef87090dfd767fb5044ec62263) - check_type(argname="argument key", value=key, expected_type=type_hints["key"]) - check_type(argname="argument values", value=values, expected_type=type_hints["values"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "key": key, - "values": values, - } - - @builtins.property - def key(self) -> builtins.str: - '''The label key that the selector applies to. - - :schema: io.k8s.api.core.v1.TopologySelectorLabelRequirement#key - ''' - result = self._values.get("key") - assert result is not None, "Required property 'key' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def values(self) -> typing.List[builtins.str]: - '''An array of string values. - - One value must match the label to be selected. Each entry in Values is ORed. - - :schema: io.k8s.api.core.v1.TopologySelectorLabelRequirement#values - ''' - result = self._values.get("values") - assert result is not None, "Required property 'values' is missing" - return typing.cast(typing.List[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "TopologySelectorLabelRequirement(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.TopologySelectorTerm", - jsii_struct_bases=[], - name_mapping={"match_label_expressions": "matchLabelExpressions"}, -) -class TopologySelectorTerm: - def __init__( - self, - *, - match_label_expressions: typing.Optional[typing.Sequence[typing.Union[TopologySelectorLabelRequirement, typing.Dict[builtins.str, typing.Any]]]] = None, - ) -> None: - '''A topology selector term represents the result of label queries. - - A null or empty topology selector term matches no objects. The requirements of them are ANDed. It provides a subset of functionality as NodeSelectorTerm. This is an alpha feature and may change in the future. - - :param match_label_expressions: A list of topology selector requirements by labels. - - :schema: io.k8s.api.core.v1.TopologySelectorTerm - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__f598eb2ca65a39d9b8fc7d3e58cfab9e1b3f88e885b8823a74892071e3a7dfb5) - check_type(argname="argument match_label_expressions", value=match_label_expressions, expected_type=type_hints["match_label_expressions"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if match_label_expressions is not None: - self._values["match_label_expressions"] = match_label_expressions - - @builtins.property - def match_label_expressions( - self, - ) -> typing.Optional[typing.List[TopologySelectorLabelRequirement]]: - '''A list of topology selector requirements by labels. - - :schema: io.k8s.api.core.v1.TopologySelectorTerm#matchLabelExpressions - ''' - result = self._values.get("match_label_expressions") - return typing.cast(typing.Optional[typing.List[TopologySelectorLabelRequirement]], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "TopologySelectorTerm(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.TopologySpreadConstraint", - jsii_struct_bases=[], - name_mapping={ - "max_skew": "maxSkew", - "topology_key": "topologyKey", - "when_unsatisfiable": "whenUnsatisfiable", - "label_selector": "labelSelector", - "match_label_keys": "matchLabelKeys", - "min_domains": "minDomains", - "node_affinity_policy": "nodeAffinityPolicy", - "node_taints_policy": "nodeTaintsPolicy", - }, -) -class TopologySpreadConstraint: - def __init__( - self, - *, - max_skew: jsii.Number, - topology_key: builtins.str, - when_unsatisfiable: builtins.str, - label_selector: typing.Optional[typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]]] = None, - match_label_keys: typing.Optional[typing.Sequence[builtins.str]] = None, - min_domains: typing.Optional[jsii.Number] = None, - node_affinity_policy: typing.Optional[builtins.str] = None, - node_taints_policy: typing.Optional[builtins.str] = None, - ) -> None: - '''TopologySpreadConstraint specifies how to spread matching pods among the given topology. - - :param max_skew: MaxSkew describes the degree to which pods may be unevenly distributed. When ``whenUnsatisfiable=DoNotSchedule``, it is the maximum permitted difference between the number of matching pods in the target topology and the global minimum. The global minimum is the minimum number of matching pods in an eligible domain or zero if the number of eligible domains is less than MinDomains. For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same labelSelector spread as 2/2/1: In this case, the global minimum is 1. | zone1 | zone2 | zone3 | | P P | P P | P | - if MaxSkew is 1, incoming pod can only be scheduled to zone3 to become 2/2/2; scheduling it onto zone1(zone2) would make the ActualSkew(3-1) on zone1(zone2) violate MaxSkew(1). - if MaxSkew is 2, incoming pod can be scheduled onto any zone. When ``whenUnsatisfiable=ScheduleAnyway``, it is used to give higher precedence to topologies that satisfy it. It's a required field. Default value is 1 and 0 is not allowed. - :param topology_key: TopologyKey is the key of node labels. Nodes that have a label with this key and identical values are considered to be in the same topology. We consider each as a "bucket", and try to put balanced number of pods into each bucket. We define a domain as a particular instance of a topology. Also, we define an eligible domain as a domain whose nodes meet the requirements of nodeAffinityPolicy and nodeTaintsPolicy. e.g. If TopologyKey is "kubernetes.io/hostname", each Node is a domain of that topology. And, if TopologyKey is "topology.kubernetes.io/zone", each zone is a domain of that topology. It's a required field. - :param when_unsatisfiable: WhenUnsatisfiable indicates how to deal with a pod if it doesn't satisfy the spread constraint. - DoNotSchedule (default) tells the scheduler not to schedule it. - ScheduleAnyway tells the scheduler to schedule the pod in any location, but giving higher precedence to topologies that would help reduce the skew. A constraint is considered "Unsatisfiable" for an incoming pod if and only if every possible node assignment for that pod would violate "MaxSkew" on some topology. For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same labelSelector spread as 3/1/1: | zone1 | zone2 | zone3 | | P P P | P | P | If WhenUnsatisfiable is set to DoNotSchedule, incoming pod can only be scheduled to zone2(zone3) to become 3/2/1(3/1/2) as ActualSkew(2-1) on zone2(zone3) satisfies MaxSkew(1). In other words, the cluster can still be imbalanced, but scheduler won't make it *more* imbalanced. It's a required field. - :param label_selector: LabelSelector is used to find matching pods. Pods that match this label selector are counted to determine the number of pods in their corresponding topology domain. - :param match_label_keys: MatchLabelKeys is a set of pod label keys to select the pods over which spreading will be calculated. The keys are used to lookup values from the incoming pod labels, those key-value labels are ANDed with labelSelector to select the group of existing pods over which spreading will be calculated for the incoming pod. Keys that don't exist in the incoming pod labels will be ignored. A null or empty list means only match against labelSelector. - :param min_domains: MinDomains indicates a minimum number of eligible domains. When the number of eligible domains with matching topology keys is less than minDomains, Pod Topology Spread treats "global minimum" as 0, and then the calculation of Skew is performed. And when the number of eligible domains with matching topology keys equals or greater than minDomains, this value has no effect on scheduling. As a result, when the number of eligible domains is less than minDomains, scheduler won't schedule more than maxSkew Pods to those domains. If value is nil, the constraint behaves as if MinDomains is equal to 1. Valid values are integers greater than 0. When value is not nil, WhenUnsatisfiable must be DoNotSchedule. For example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same labelSelector spread as 2/2/2: | zone1 | zone2 | zone3 | | P P | P P | P P | The number of domains is less than 5(MinDomains), so "global minimum" is treated as 0. In this situation, new pod with the same labelSelector cannot be scheduled, because computed skew will be 3(3 - 0) if new Pod is scheduled to any of the three zones, it will violate MaxSkew. This is a beta field and requires the MinDomainsInPodTopologySpread feature gate to be enabled (enabled by default). - :param node_affinity_policy: NodeAffinityPolicy indicates how we will treat Pod's nodeAffinity/nodeSelector when calculating pod topology spread skew. Options are: - Honor: only nodes matching nodeAffinity/nodeSelector are included in the calculations. - Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations. If this value is nil, the behavior is equivalent to the Honor policy. This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag. - :param node_taints_policy: NodeTaintsPolicy indicates how we will treat node taints when calculating pod topology spread skew. Options are: - Honor: nodes without taints, along with tainted nodes for which the incoming pod has a toleration, are included. - Ignore: node taints are ignored. All nodes are included. If this value is nil, the behavior is equivalent to the Ignore policy. This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag. - - :schema: io.k8s.api.core.v1.TopologySpreadConstraint - ''' - if isinstance(label_selector, dict): - label_selector = LabelSelector(**label_selector) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__d563e5e62c67208bafb547e16adedf3e17b27b1cb3c8cd46509e6398021dcef5) - check_type(argname="argument max_skew", value=max_skew, expected_type=type_hints["max_skew"]) - check_type(argname="argument topology_key", value=topology_key, expected_type=type_hints["topology_key"]) - check_type(argname="argument when_unsatisfiable", value=when_unsatisfiable, expected_type=type_hints["when_unsatisfiable"]) - check_type(argname="argument label_selector", value=label_selector, expected_type=type_hints["label_selector"]) - check_type(argname="argument match_label_keys", value=match_label_keys, expected_type=type_hints["match_label_keys"]) - check_type(argname="argument min_domains", value=min_domains, expected_type=type_hints["min_domains"]) - check_type(argname="argument node_affinity_policy", value=node_affinity_policy, expected_type=type_hints["node_affinity_policy"]) - check_type(argname="argument node_taints_policy", value=node_taints_policy, expected_type=type_hints["node_taints_policy"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "max_skew": max_skew, - "topology_key": topology_key, - "when_unsatisfiable": when_unsatisfiable, - } - if label_selector is not None: - self._values["label_selector"] = label_selector - if match_label_keys is not None: - self._values["match_label_keys"] = match_label_keys - if min_domains is not None: - self._values["min_domains"] = min_domains - if node_affinity_policy is not None: - self._values["node_affinity_policy"] = node_affinity_policy - if node_taints_policy is not None: - self._values["node_taints_policy"] = node_taints_policy - - @builtins.property - def max_skew(self) -> jsii.Number: - '''MaxSkew describes the degree to which pods may be unevenly distributed. - - When ``whenUnsatisfiable=DoNotSchedule``, it is the maximum permitted difference between the number of matching pods in the target topology and the global minimum. The global minimum is the minimum number of matching pods in an eligible domain or zero if the number of eligible domains is less than MinDomains. For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same labelSelector spread as 2/2/1: In this case, the global minimum is 1. | zone1 | zone2 | zone3 | | P P | P P | P | - if MaxSkew is 1, incoming pod can only be scheduled to zone3 to become 2/2/2; scheduling it onto zone1(zone2) would make the ActualSkew(3-1) on zone1(zone2) violate MaxSkew(1). - if MaxSkew is 2, incoming pod can be scheduled onto any zone. When ``whenUnsatisfiable=ScheduleAnyway``, it is used to give higher precedence to topologies that satisfy it. It's a required field. Default value is 1 and 0 is not allowed. - - :schema: io.k8s.api.core.v1.TopologySpreadConstraint#maxSkew - ''' - result = self._values.get("max_skew") - assert result is not None, "Required property 'max_skew' is missing" - return typing.cast(jsii.Number, result) - - @builtins.property - def topology_key(self) -> builtins.str: - '''TopologyKey is the key of node labels. - - Nodes that have a label with this key and identical values are considered to be in the same topology. We consider each as a "bucket", and try to put balanced number of pods into each bucket. We define a domain as a particular instance of a topology. Also, we define an eligible domain as a domain whose nodes meet the requirements of nodeAffinityPolicy and nodeTaintsPolicy. e.g. If TopologyKey is "kubernetes.io/hostname", each Node is a domain of that topology. And, if TopologyKey is "topology.kubernetes.io/zone", each zone is a domain of that topology. It's a required field. - - :schema: io.k8s.api.core.v1.TopologySpreadConstraint#topologyKey - ''' - result = self._values.get("topology_key") - assert result is not None, "Required property 'topology_key' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def when_unsatisfiable(self) -> builtins.str: - '''WhenUnsatisfiable indicates how to deal with a pod if it doesn't satisfy the spread constraint. - - - DoNotSchedule (default) tells the scheduler not to schedule it. - ScheduleAnyway tells the scheduler to schedule the pod in any location, - but giving higher precedence to topologies that would help reduce the - skew. - A constraint is considered "Unsatisfiable" for an incoming pod if and only if every possible node assignment for that pod would violate "MaxSkew" on some topology. For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same labelSelector spread as 3/1/1: | zone1 | zone2 | zone3 | | P P P | P | P | If WhenUnsatisfiable is set to DoNotSchedule, incoming pod can only be scheduled to zone2(zone3) to become 3/2/1(3/1/2) as ActualSkew(2-1) on zone2(zone3) satisfies MaxSkew(1). In other words, the cluster can still be imbalanced, but scheduler won't make it *more* imbalanced. It's a required field. - - :schema: io.k8s.api.core.v1.TopologySpreadConstraint#whenUnsatisfiable - ''' - result = self._values.get("when_unsatisfiable") - assert result is not None, "Required property 'when_unsatisfiable' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def label_selector(self) -> typing.Optional[LabelSelector]: - '''LabelSelector is used to find matching pods. - - Pods that match this label selector are counted to determine the number of pods in their corresponding topology domain. - - :schema: io.k8s.api.core.v1.TopologySpreadConstraint#labelSelector - ''' - result = self._values.get("label_selector") - return typing.cast(typing.Optional[LabelSelector], result) - - @builtins.property - def match_label_keys(self) -> typing.Optional[typing.List[builtins.str]]: - '''MatchLabelKeys is a set of pod label keys to select the pods over which spreading will be calculated. - - The keys are used to lookup values from the incoming pod labels, those key-value labels are ANDed with labelSelector to select the group of existing pods over which spreading will be calculated for the incoming pod. Keys that don't exist in the incoming pod labels will be ignored. A null or empty list means only match against labelSelector. - - :schema: io.k8s.api.core.v1.TopologySpreadConstraint#matchLabelKeys - ''' - result = self._values.get("match_label_keys") - return typing.cast(typing.Optional[typing.List[builtins.str]], result) - - @builtins.property - def min_domains(self) -> typing.Optional[jsii.Number]: - '''MinDomains indicates a minimum number of eligible domains. - - When the number of eligible domains with matching topology keys is less than minDomains, Pod Topology Spread treats "global minimum" as 0, and then the calculation of Skew is performed. And when the number of eligible domains with matching topology keys equals or greater than minDomains, this value has no effect on scheduling. As a result, when the number of eligible domains is less than minDomains, scheduler won't schedule more than maxSkew Pods to those domains. If value is nil, the constraint behaves as if MinDomains is equal to 1. Valid values are integers greater than 0. When value is not nil, WhenUnsatisfiable must be DoNotSchedule. - - For example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same labelSelector spread as 2/2/2: | zone1 | zone2 | zone3 | | P P | P P | P P | The number of domains is less than 5(MinDomains), so "global minimum" is treated as 0. In this situation, new pod with the same labelSelector cannot be scheduled, because computed skew will be 3(3 - 0) if new Pod is scheduled to any of the three zones, it will violate MaxSkew. - - This is a beta field and requires the MinDomainsInPodTopologySpread feature gate to be enabled (enabled by default). - - :schema: io.k8s.api.core.v1.TopologySpreadConstraint#minDomains - ''' - result = self._values.get("min_domains") - return typing.cast(typing.Optional[jsii.Number], result) - - @builtins.property - def node_affinity_policy(self) -> typing.Optional[builtins.str]: - '''NodeAffinityPolicy indicates how we will treat Pod's nodeAffinity/nodeSelector when calculating pod topology spread skew. - - Options are: - Honor: only nodes matching nodeAffinity/nodeSelector are included in the calculations. - Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations. - - If this value is nil, the behavior is equivalent to the Honor policy. This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag. - - :schema: io.k8s.api.core.v1.TopologySpreadConstraint#nodeAffinityPolicy - ''' - result = self._values.get("node_affinity_policy") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def node_taints_policy(self) -> typing.Optional[builtins.str]: - '''NodeTaintsPolicy indicates how we will treat node taints when calculating pod topology spread skew. - - Options are: - Honor: nodes without taints, along with tainted nodes for which the incoming pod has a toleration, are included. - Ignore: node taints are ignored. All nodes are included. - - If this value is nil, the behavior is equivalent to the Ignore policy. This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag. - - :schema: io.k8s.api.core.v1.TopologySpreadConstraint#nodeTaintsPolicy - ''' - result = self._values.get("node_taints_policy") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "TopologySpreadConstraint(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.TypedLocalObjectReference", - jsii_struct_bases=[], - name_mapping={"kind": "kind", "name": "name", "api_group": "apiGroup"}, -) -class TypedLocalObjectReference: - def __init__( - self, - *, - kind: builtins.str, - name: builtins.str, - api_group: typing.Optional[builtins.str] = None, - ) -> None: - '''TypedLocalObjectReference contains enough information to let you locate the typed referenced object inside the same namespace. - - :param kind: Kind is the type of resource being referenced. - :param name: Name is the name of resource being referenced. - :param api_group: APIGroup is the group for the resource being referenced. If APIGroup is not specified, the specified Kind must be in the core API group. For any other third-party types, APIGroup is required. - - :schema: io.k8s.api.core.v1.TypedLocalObjectReference - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__e0c8161c6a54145904571f1150bbbdb550defbe6c662fd937bd97bb2f9815bde) - check_type(argname="argument kind", value=kind, expected_type=type_hints["kind"]) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument api_group", value=api_group, expected_type=type_hints["api_group"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "kind": kind, - "name": name, - } - if api_group is not None: - self._values["api_group"] = api_group - - @builtins.property - def kind(self) -> builtins.str: - '''Kind is the type of resource being referenced. - - :schema: io.k8s.api.core.v1.TypedLocalObjectReference#kind - ''' - result = self._values.get("kind") - assert result is not None, "Required property 'kind' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def name(self) -> builtins.str: - '''Name is the name of resource being referenced. - - :schema: io.k8s.api.core.v1.TypedLocalObjectReference#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def api_group(self) -> typing.Optional[builtins.str]: - '''APIGroup is the group for the resource being referenced. - - If APIGroup is not specified, the specified Kind must be in the core API group. For any other third-party types, APIGroup is required. - - :schema: io.k8s.api.core.v1.TypedLocalObjectReference#apiGroup - ''' - result = self._values.get("api_group") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "TypedLocalObjectReference(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.TypedObjectReference", - jsii_struct_bases=[], - name_mapping={ - "kind": "kind", - "name": "name", - "api_group": "apiGroup", - "namespace": "namespace", - }, -) -class TypedObjectReference: - def __init__( - self, - *, - kind: builtins.str, - name: builtins.str, - api_group: typing.Optional[builtins.str] = None, - namespace: typing.Optional[builtins.str] = None, - ) -> None: - ''' - :param kind: Kind is the type of resource being referenced. - :param name: Name is the name of resource being referenced. - :param api_group: APIGroup is the group for the resource being referenced. If APIGroup is not specified, the specified Kind must be in the core API group. For any other third-party types, APIGroup is required. - :param namespace: Namespace is the namespace of resource being referenced Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - - :schema: io.k8s.api.core.v1.TypedObjectReference - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__bece17868eb3d8e19bda1cfa4d9b7e4762df845f22f80e0d969ca1a026323551) - check_type(argname="argument kind", value=kind, expected_type=type_hints["kind"]) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument api_group", value=api_group, expected_type=type_hints["api_group"]) - check_type(argname="argument namespace", value=namespace, expected_type=type_hints["namespace"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "kind": kind, - "name": name, - } - if api_group is not None: - self._values["api_group"] = api_group - if namespace is not None: - self._values["namespace"] = namespace - - @builtins.property - def kind(self) -> builtins.str: - '''Kind is the type of resource being referenced. - - :schema: io.k8s.api.core.v1.TypedObjectReference#kind - ''' - result = self._values.get("kind") - assert result is not None, "Required property 'kind' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def name(self) -> builtins.str: - '''Name is the name of resource being referenced. - - :schema: io.k8s.api.core.v1.TypedObjectReference#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def api_group(self) -> typing.Optional[builtins.str]: - '''APIGroup is the group for the resource being referenced. - - If APIGroup is not specified, the specified Kind must be in the core API group. For any other third-party types, APIGroup is required. - - :schema: io.k8s.api.core.v1.TypedObjectReference#apiGroup - ''' - result = self._values.get("api_group") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def namespace(self) -> typing.Optional[builtins.str]: - '''Namespace is the namespace of resource being referenced Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - - :schema: io.k8s.api.core.v1.TypedObjectReference#namespace - ''' - result = self._values.get("namespace") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "TypedObjectReference(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.UserSubjectV1Beta2", - jsii_struct_bases=[], - name_mapping={"name": "name"}, -) -class UserSubjectV1Beta2: - def __init__(self, *, name: builtins.str) -> None: - '''UserSubject holds detailed information for user-kind subject. - - :param name: ``name`` is the username that matches, or "*" to match all usernames. Required. - - :schema: io.k8s.api.flowcontrol.v1beta2.UserSubject - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__17a6f5ab5147a857e5ba844ed1dbdafc559b209da7c06b37c6aab6dc5f5ceaab) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "name": name, - } - - @builtins.property - def name(self) -> builtins.str: - '''``name`` is the username that matches, or "*" to match all usernames. - - Required. - - :schema: io.k8s.api.flowcontrol.v1beta2.UserSubject#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "UserSubjectV1Beta2(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.UserSubjectV1Beta3", - jsii_struct_bases=[], - name_mapping={"name": "name"}, -) -class UserSubjectV1Beta3: - def __init__(self, *, name: builtins.str) -> None: - '''UserSubject holds detailed information for user-kind subject. - - :param name: ``name`` is the username that matches, or "*" to match all usernames. Required. - - :schema: io.k8s.api.flowcontrol.v1beta3.UserSubject - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__4922cdd9a47a2508da7b0db66f1f2de9875fc489bfc823c7fc81b715099a31b6) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "name": name, - } - - @builtins.property - def name(self) -> builtins.str: - '''``name`` is the username that matches, or "*" to match all usernames. - - Required. - - :schema: io.k8s.api.flowcontrol.v1beta3.UserSubject#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "UserSubjectV1Beta3(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ValidatingAdmissionPolicyBindingSpecV1Alpha1", - jsii_struct_bases=[], - name_mapping={ - "match_resources": "matchResources", - "param_ref": "paramRef", - "policy_name": "policyName", - }, -) -class ValidatingAdmissionPolicyBindingSpecV1Alpha1: - def __init__( - self, - *, - match_resources: typing.Optional[typing.Union[MatchResourcesV1Alpha1, typing.Dict[builtins.str, typing.Any]]] = None, - param_ref: typing.Optional[typing.Union[ParamRefV1Alpha1, typing.Dict[builtins.str, typing.Any]]] = None, - policy_name: typing.Optional[builtins.str] = None, - ) -> None: - '''ValidatingAdmissionPolicyBindingSpec is the specification of the ValidatingAdmissionPolicyBinding. - - :param match_resources: MatchResources declares what resources match this binding and will be validated by it. Note that this is intersected with the policy's matchConstraints, so only requests that are matched by the policy can be selected by this. If this is unset, all resources matched by the policy are validated by this binding When resourceRules is unset, it does not constrain resource matching. If a resource is matched by the other fields of this object, it will be validated. Note that this is differs from ValidatingAdmissionPolicy matchConstraints, where resourceRules are required. - :param param_ref: ParamRef specifies the parameter resource used to configure the admission control policy. It should point to a resource of the type specified in ParamKind of the bound ValidatingAdmissionPolicy. If the policy specifies a ParamKind and the resource referred to by ParamRef does not exist, this binding is considered mis-configured and the FailurePolicy of the ValidatingAdmissionPolicy applied. - :param policy_name: PolicyName references a ValidatingAdmissionPolicy name which the ValidatingAdmissionPolicyBinding binds to. If the referenced resource does not exist, this binding is considered invalid and will be ignored Required. - - :schema: io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyBindingSpec - ''' - if isinstance(match_resources, dict): - match_resources = MatchResourcesV1Alpha1(**match_resources) - if isinstance(param_ref, dict): - param_ref = ParamRefV1Alpha1(**param_ref) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__0d38c442b8405ac15b84cec7d96ee561544c67c7960c701be6a4e8938804eefa) - check_type(argname="argument match_resources", value=match_resources, expected_type=type_hints["match_resources"]) - check_type(argname="argument param_ref", value=param_ref, expected_type=type_hints["param_ref"]) - check_type(argname="argument policy_name", value=policy_name, expected_type=type_hints["policy_name"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if match_resources is not None: - self._values["match_resources"] = match_resources - if param_ref is not None: - self._values["param_ref"] = param_ref - if policy_name is not None: - self._values["policy_name"] = policy_name - - @builtins.property - def match_resources(self) -> typing.Optional[MatchResourcesV1Alpha1]: - '''MatchResources declares what resources match this binding and will be validated by it. - - Note that this is intersected with the policy's matchConstraints, so only requests that are matched by the policy can be selected by this. If this is unset, all resources matched by the policy are validated by this binding When resourceRules is unset, it does not constrain resource matching. If a resource is matched by the other fields of this object, it will be validated. Note that this is differs from ValidatingAdmissionPolicy matchConstraints, where resourceRules are required. - - :schema: io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyBindingSpec#matchResources - ''' - result = self._values.get("match_resources") - return typing.cast(typing.Optional[MatchResourcesV1Alpha1], result) - - @builtins.property - def param_ref(self) -> typing.Optional[ParamRefV1Alpha1]: - '''ParamRef specifies the parameter resource used to configure the admission control policy. - - It should point to a resource of the type specified in ParamKind of the bound ValidatingAdmissionPolicy. If the policy specifies a ParamKind and the resource referred to by ParamRef does not exist, this binding is considered mis-configured and the FailurePolicy of the ValidatingAdmissionPolicy applied. - - :schema: io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyBindingSpec#paramRef - ''' - result = self._values.get("param_ref") - return typing.cast(typing.Optional[ParamRefV1Alpha1], result) - - @builtins.property - def policy_name(self) -> typing.Optional[builtins.str]: - '''PolicyName references a ValidatingAdmissionPolicy name which the ValidatingAdmissionPolicyBinding binds to. - - If the referenced resource does not exist, this binding is considered invalid and will be ignored Required. - - :schema: io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyBindingSpec#policyName - ''' - result = self._values.get("policy_name") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ValidatingAdmissionPolicyBindingSpecV1Alpha1(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ValidatingAdmissionPolicySpecV1Alpha1", - jsii_struct_bases=[], - name_mapping={ - "validations": "validations", - "failure_policy": "failurePolicy", - "match_constraints": "matchConstraints", - "param_kind": "paramKind", - }, -) -class ValidatingAdmissionPolicySpecV1Alpha1: - def __init__( - self, - *, - validations: typing.Sequence[typing.Union["ValidationV1Alpha1", typing.Dict[builtins.str, typing.Any]]], - failure_policy: typing.Optional[builtins.str] = None, - match_constraints: typing.Optional[typing.Union[MatchResourcesV1Alpha1, typing.Dict[builtins.str, typing.Any]]] = None, - param_kind: typing.Optional[typing.Union[ParamKindV1Alpha1, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''ValidatingAdmissionPolicySpec is the specification of the desired behavior of the AdmissionPolicy. - - :param validations: Validations contain CEL expressions which is used to apply the validation. A minimum of one validation is required for a policy definition. Required. - :param failure_policy: FailurePolicy defines how to handle failures for the admission policy. Failures can occur from invalid or mis-configured policy definitions or bindings. A policy is invalid if spec.paramKind refers to a non-existent Kind. A binding is invalid if spec.paramRef.name refers to a non-existent resource. Allowed values are Ignore or Fail. Defaults to Fail. Default: Fail. - :param match_constraints: MatchConstraints specifies what resources this policy is designed to validate. The AdmissionPolicy cares about a request if it matches *all* Constraints. However, in order to prevent clusters from being put into an unstable state that cannot be recovered from via the API ValidatingAdmissionPolicy cannot match ValidatingAdmissionPolicy and ValidatingAdmissionPolicyBinding. Required. - :param param_kind: ParamKind specifies the kind of resources used to parameterize this policy. If absent, there are no parameters for this policy and the param CEL variable will not be provided to validation expressions. If ParamKind refers to a non-existent kind, this policy definition is mis-configured and the FailurePolicy is applied. If paramKind is specified but paramRef is unset in ValidatingAdmissionPolicyBinding, the params variable will be null. - - :schema: io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicySpec - ''' - if isinstance(match_constraints, dict): - match_constraints = MatchResourcesV1Alpha1(**match_constraints) - if isinstance(param_kind, dict): - param_kind = ParamKindV1Alpha1(**param_kind) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__0419a6826a131473eb218fd7b964c8f1501e74582c4575a39889f77a48866837) - check_type(argname="argument validations", value=validations, expected_type=type_hints["validations"]) - check_type(argname="argument failure_policy", value=failure_policy, expected_type=type_hints["failure_policy"]) - check_type(argname="argument match_constraints", value=match_constraints, expected_type=type_hints["match_constraints"]) - check_type(argname="argument param_kind", value=param_kind, expected_type=type_hints["param_kind"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "validations": validations, - } - if failure_policy is not None: - self._values["failure_policy"] = failure_policy - if match_constraints is not None: - self._values["match_constraints"] = match_constraints - if param_kind is not None: - self._values["param_kind"] = param_kind - - @builtins.property - def validations(self) -> typing.List["ValidationV1Alpha1"]: - '''Validations contain CEL expressions which is used to apply the validation. - - A minimum of one validation is required for a policy definition. Required. - - :schema: io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicySpec#validations - ''' - result = self._values.get("validations") - assert result is not None, "Required property 'validations' is missing" - return typing.cast(typing.List["ValidationV1Alpha1"], result) - - @builtins.property - def failure_policy(self) -> typing.Optional[builtins.str]: - '''FailurePolicy defines how to handle failures for the admission policy. - - Failures can occur from invalid or mis-configured policy definitions or bindings. A policy is invalid if spec.paramKind refers to a non-existent Kind. A binding is invalid if spec.paramRef.name refers to a non-existent resource. Allowed values are Ignore or Fail. Defaults to Fail. - - :default: Fail. - - :schema: io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicySpec#failurePolicy - ''' - result = self._values.get("failure_policy") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def match_constraints(self) -> typing.Optional[MatchResourcesV1Alpha1]: - '''MatchConstraints specifies what resources this policy is designed to validate. - - The AdmissionPolicy cares about a request if it matches *all* Constraints. However, in order to prevent clusters from being put into an unstable state that cannot be recovered from via the API ValidatingAdmissionPolicy cannot match ValidatingAdmissionPolicy and ValidatingAdmissionPolicyBinding. Required. - - :schema: io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicySpec#matchConstraints - ''' - result = self._values.get("match_constraints") - return typing.cast(typing.Optional[MatchResourcesV1Alpha1], result) - - @builtins.property - def param_kind(self) -> typing.Optional[ParamKindV1Alpha1]: - '''ParamKind specifies the kind of resources used to parameterize this policy. - - If absent, there are no parameters for this policy and the param CEL variable will not be provided to validation expressions. If ParamKind refers to a non-existent kind, this policy definition is mis-configured and the FailurePolicy is applied. If paramKind is specified but paramRef is unset in ValidatingAdmissionPolicyBinding, the params variable will be null. - - :schema: io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicySpec#paramKind - ''' - result = self._values.get("param_kind") - return typing.cast(typing.Optional[ParamKindV1Alpha1], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ValidatingAdmissionPolicySpecV1Alpha1(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ValidatingWebhook", - jsii_struct_bases=[], - name_mapping={ - "admission_review_versions": "admissionReviewVersions", - "client_config": "clientConfig", - "name": "name", - "side_effects": "sideEffects", - "failure_policy": "failurePolicy", - "match_policy": "matchPolicy", - "namespace_selector": "namespaceSelector", - "object_selector": "objectSelector", - "rules": "rules", - "timeout_seconds": "timeoutSeconds", - }, -) -class ValidatingWebhook: - def __init__( - self, - *, - admission_review_versions: typing.Sequence[builtins.str], - client_config: typing.Union["WebhookClientConfig", typing.Dict[builtins.str, typing.Any]], - name: builtins.str, - side_effects: builtins.str, - failure_policy: typing.Optional[builtins.str] = None, - match_policy: typing.Optional[builtins.str] = None, - namespace_selector: typing.Optional[typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]]] = None, - object_selector: typing.Optional[typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]]] = None, - rules: typing.Optional[typing.Sequence[typing.Union[RuleWithOperations, typing.Dict[builtins.str, typing.Any]]]] = None, - timeout_seconds: typing.Optional[jsii.Number] = None, - ) -> None: - '''ValidatingWebhook describes an admission webhook and the resources and operations it applies to. - - :param admission_review_versions: AdmissionReviewVersions is an ordered list of preferred ``AdmissionReview`` versions the Webhook expects. API server will try to use first version in the list which it supports. If none of the versions specified in this list supported by API server, validation will fail for this object. If a persisted webhook configuration specifies allowed versions and does not include any versions known to the API Server, calls to the webhook will fail and be subject to the failure policy. - :param client_config: ClientConfig defines how to communicate with the hook. Required - :param name: The name of the admission webhook. Name should be fully qualified, e.g., imagepolicy.kubernetes.io, where "imagepolicy" is the name of the webhook, and kubernetes.io is the name of the organization. Required. - :param side_effects: SideEffects states whether this webhook has side effects. Acceptable values are: None, NoneOnDryRun (webhooks created via v1beta1 may also specify Some or Unknown). Webhooks with side effects MUST implement a reconciliation system, since a request may be rejected by a future step in the admission chain and the side effects therefore need to be undone. Requests with the dryRun attribute will be auto-rejected if they match a webhook with sideEffects == Unknown or Some. - :param failure_policy: FailurePolicy defines how unrecognized errors from the admission endpoint are handled - allowed values are Ignore or Fail. Defaults to Fail. Default: Fail. - :param match_policy: matchPolicy defines how the "rules" list is used to match incoming requests. Allowed values are "Exact" or "Equivalent". - Exact: match a request only if it exactly matches a specified rule. For example, if deployments can be modified via apps/v1, apps/v1beta1, and extensions/v1beta1, but "rules" only included ``apiGroups:["apps"], apiVersions:["v1"], resources: ["deployments"]``, a request to apps/v1beta1 or extensions/v1beta1 would not be sent to the webhook. - Equivalent: match a request if modifies a resource listed in rules, even via another API group or version. For example, if deployments can be modified via apps/v1, apps/v1beta1, and extensions/v1beta1, and "rules" only included ``apiGroups:["apps"], apiVersions:["v1"], resources: ["deployments"]``, a request to apps/v1beta1 or extensions/v1beta1 would be converted to apps/v1 and sent to the webhook. Defaults to "Equivalent" Default: Equivalent" - :param namespace_selector: NamespaceSelector decides whether to run the webhook on an object based on whether the namespace for that object matches the selector. If the object itself is a namespace, the matching is performed on object.metadata.labels. If the object is another cluster scoped resource, it never skips the webhook. For example, to run the webhook on any objects whose namespace is not associated with "runlevel" of "0" or "1"; you will set the selector as follows: "namespaceSelector": { "matchExpressions": [ { "key": "runlevel", "operator": "NotIn", "values": [ "0", "1" ] } ] } If instead you want to only run the webhook on any objects whose namespace is associated with the "environment" of "prod" or "staging"; you will set the selector as follows: "namespaceSelector": { "matchExpressions": [ { "key": "environment", "operator": "In", "values": [ "prod", "staging" ] } ] } See https://kubernetes.io/docs/concepts/overview/working-with-objects/labels for more examples of label selectors. Default to the empty LabelSelector, which matches everything. Default: the empty LabelSelector, which matches everything. - :param object_selector: ObjectSelector decides whether to run the webhook based on if the object has matching labels. objectSelector is evaluated against both the oldObject and newObject that would be sent to the webhook, and is considered to match if either object matches the selector. A null object (oldObject in the case of create, or newObject in the case of delete) or an object that cannot have labels (like a DeploymentRollback or a PodProxyOptions object) is not considered to match. Use the object selector only if the webhook is opt-in, because end users may skip the admission webhook by setting the labels. Default to the empty LabelSelector, which matches everything. Default: the empty LabelSelector, which matches everything. - :param rules: Rules describes what operations on what resources/subresources the webhook cares about. The webhook cares about an operation if it matches *any* Rule. However, in order to prevent ValidatingAdmissionWebhooks and MutatingAdmissionWebhooks from putting the cluster in a state which cannot be recovered from without completely disabling the plugin, ValidatingAdmissionWebhooks and MutatingAdmissionWebhooks are never called on admission requests for ValidatingWebhookConfiguration and MutatingWebhookConfiguration objects. - :param timeout_seconds: TimeoutSeconds specifies the timeout for this webhook. After the timeout passes, the webhook call will be ignored or the API call will fail based on the failure policy. The timeout value must be between 1 and 30 seconds. Default to 10 seconds. Default: 10 seconds. - - :schema: io.k8s.api.admissionregistration.v1.ValidatingWebhook - ''' - if isinstance(client_config, dict): - client_config = WebhookClientConfig(**client_config) - if isinstance(namespace_selector, dict): - namespace_selector = LabelSelector(**namespace_selector) - if isinstance(object_selector, dict): - object_selector = LabelSelector(**object_selector) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__ac0bdffd3ae40593dcc946344a4b810ff63dcf95c9d059bc98c0876523b7dbc9) - check_type(argname="argument admission_review_versions", value=admission_review_versions, expected_type=type_hints["admission_review_versions"]) - check_type(argname="argument client_config", value=client_config, expected_type=type_hints["client_config"]) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument side_effects", value=side_effects, expected_type=type_hints["side_effects"]) - check_type(argname="argument failure_policy", value=failure_policy, expected_type=type_hints["failure_policy"]) - check_type(argname="argument match_policy", value=match_policy, expected_type=type_hints["match_policy"]) - check_type(argname="argument namespace_selector", value=namespace_selector, expected_type=type_hints["namespace_selector"]) - check_type(argname="argument object_selector", value=object_selector, expected_type=type_hints["object_selector"]) - check_type(argname="argument rules", value=rules, expected_type=type_hints["rules"]) - check_type(argname="argument timeout_seconds", value=timeout_seconds, expected_type=type_hints["timeout_seconds"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "admission_review_versions": admission_review_versions, - "client_config": client_config, - "name": name, - "side_effects": side_effects, - } - if failure_policy is not None: - self._values["failure_policy"] = failure_policy - if match_policy is not None: - self._values["match_policy"] = match_policy - if namespace_selector is not None: - self._values["namespace_selector"] = namespace_selector - if object_selector is not None: - self._values["object_selector"] = object_selector - if rules is not None: - self._values["rules"] = rules - if timeout_seconds is not None: - self._values["timeout_seconds"] = timeout_seconds - - @builtins.property - def admission_review_versions(self) -> typing.List[builtins.str]: - '''AdmissionReviewVersions is an ordered list of preferred ``AdmissionReview`` versions the Webhook expects. - - API server will try to use first version in the list which it supports. If none of the versions specified in this list supported by API server, validation will fail for this object. If a persisted webhook configuration specifies allowed versions and does not include any versions known to the API Server, calls to the webhook will fail and be subject to the failure policy. - - :schema: io.k8s.api.admissionregistration.v1.ValidatingWebhook#admissionReviewVersions - ''' - result = self._values.get("admission_review_versions") - assert result is not None, "Required property 'admission_review_versions' is missing" - return typing.cast(typing.List[builtins.str], result) - - @builtins.property - def client_config(self) -> "WebhookClientConfig": - '''ClientConfig defines how to communicate with the hook. - - Required - - :schema: io.k8s.api.admissionregistration.v1.ValidatingWebhook#clientConfig - ''' - result = self._values.get("client_config") - assert result is not None, "Required property 'client_config' is missing" - return typing.cast("WebhookClientConfig", result) - - @builtins.property - def name(self) -> builtins.str: - '''The name of the admission webhook. - - Name should be fully qualified, e.g., imagepolicy.kubernetes.io, where "imagepolicy" is the name of the webhook, and kubernetes.io is the name of the organization. Required. - - :schema: io.k8s.api.admissionregistration.v1.ValidatingWebhook#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def side_effects(self) -> builtins.str: - '''SideEffects states whether this webhook has side effects. - - Acceptable values are: None, NoneOnDryRun (webhooks created via v1beta1 may also specify Some or Unknown). Webhooks with side effects MUST implement a reconciliation system, since a request may be rejected by a future step in the admission chain and the side effects therefore need to be undone. Requests with the dryRun attribute will be auto-rejected if they match a webhook with sideEffects == Unknown or Some. - - :schema: io.k8s.api.admissionregistration.v1.ValidatingWebhook#sideEffects - ''' - result = self._values.get("side_effects") - assert result is not None, "Required property 'side_effects' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def failure_policy(self) -> typing.Optional[builtins.str]: - '''FailurePolicy defines how unrecognized errors from the admission endpoint are handled - allowed values are Ignore or Fail. - - Defaults to Fail. - - :default: Fail. - - :schema: io.k8s.api.admissionregistration.v1.ValidatingWebhook#failurePolicy - ''' - result = self._values.get("failure_policy") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def match_policy(self) -> typing.Optional[builtins.str]: - '''matchPolicy defines how the "rules" list is used to match incoming requests. Allowed values are "Exact" or "Equivalent". - - - Exact: match a request only if it exactly matches a specified rule. For example, if deployments can be modified via apps/v1, apps/v1beta1, and extensions/v1beta1, but "rules" only included ``apiGroups:["apps"], apiVersions:["v1"], resources: ["deployments"]``, a request to apps/v1beta1 or extensions/v1beta1 would not be sent to the webhook. - - Equivalent: match a request if modifies a resource listed in rules, even via another API group or version. For example, if deployments can be modified via apps/v1, apps/v1beta1, and extensions/v1beta1, and "rules" only included ``apiGroups:["apps"], apiVersions:["v1"], resources: ["deployments"]``, a request to apps/v1beta1 or extensions/v1beta1 would be converted to apps/v1 and sent to the webhook. - - Defaults to "Equivalent" - - :default: Equivalent" - - :schema: io.k8s.api.admissionregistration.v1.ValidatingWebhook#matchPolicy - ''' - result = self._values.get("match_policy") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def namespace_selector(self) -> typing.Optional[LabelSelector]: - '''NamespaceSelector decides whether to run the webhook on an object based on whether the namespace for that object matches the selector. - - If the object itself is a namespace, the matching is performed on object.metadata.labels. If the object is another cluster scoped resource, it never skips the webhook. - - For example, to run the webhook on any objects whose namespace is not associated with "runlevel" of "0" or "1"; you will set the selector as follows: "namespaceSelector": { - "matchExpressions": [ - { - "key": "runlevel", - "operator": "NotIn", - "values": [ - "0", - "1" - ] - } - ] - } - - If instead you want to only run the webhook on any objects whose namespace is associated with the "environment" of "prod" or "staging"; you will set the selector as follows: "namespaceSelector": { - "matchExpressions": [ - { - "key": "environment", - "operator": "In", - "values": [ - "prod", - "staging" - ] - } - ] - } - - See https://kubernetes.io/docs/concepts/overview/working-with-objects/labels for more examples of label selectors. - - Default to the empty LabelSelector, which matches everything. - - :default: the empty LabelSelector, which matches everything. - - :schema: io.k8s.api.admissionregistration.v1.ValidatingWebhook#namespaceSelector - ''' - result = self._values.get("namespace_selector") - return typing.cast(typing.Optional[LabelSelector], result) - - @builtins.property - def object_selector(self) -> typing.Optional[LabelSelector]: - '''ObjectSelector decides whether to run the webhook based on if the object has matching labels. - - objectSelector is evaluated against both the oldObject and newObject that would be sent to the webhook, and is considered to match if either object matches the selector. A null object (oldObject in the case of create, or newObject in the case of delete) or an object that cannot have labels (like a DeploymentRollback or a PodProxyOptions object) is not considered to match. Use the object selector only if the webhook is opt-in, because end users may skip the admission webhook by setting the labels. Default to the empty LabelSelector, which matches everything. - - :default: the empty LabelSelector, which matches everything. - - :schema: io.k8s.api.admissionregistration.v1.ValidatingWebhook#objectSelector - ''' - result = self._values.get("object_selector") - return typing.cast(typing.Optional[LabelSelector], result) - - @builtins.property - def rules(self) -> typing.Optional[typing.List[RuleWithOperations]]: - '''Rules describes what operations on what resources/subresources the webhook cares about. - - The webhook cares about an operation if it matches *any* Rule. However, in order to prevent ValidatingAdmissionWebhooks and MutatingAdmissionWebhooks from putting the cluster in a state which cannot be recovered from without completely disabling the plugin, ValidatingAdmissionWebhooks and MutatingAdmissionWebhooks are never called on admission requests for ValidatingWebhookConfiguration and MutatingWebhookConfiguration objects. - - :schema: io.k8s.api.admissionregistration.v1.ValidatingWebhook#rules - ''' - result = self._values.get("rules") - return typing.cast(typing.Optional[typing.List[RuleWithOperations]], result) - - @builtins.property - def timeout_seconds(self) -> typing.Optional[jsii.Number]: - '''TimeoutSeconds specifies the timeout for this webhook. - - After the timeout passes, the webhook call will be ignored or the API call will fail based on the failure policy. The timeout value must be between 1 and 30 seconds. Default to 10 seconds. - - :default: 10 seconds. - - :schema: io.k8s.api.admissionregistration.v1.ValidatingWebhook#timeoutSeconds - ''' - result = self._values.get("timeout_seconds") - return typing.cast(typing.Optional[jsii.Number], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ValidatingWebhook(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ValidationRule", - jsii_struct_bases=[], - name_mapping={"rule": "rule", "message": "message"}, -) -class ValidationRule: - def __init__( - self, - *, - rule: builtins.str, - message: typing.Optional[builtins.str] = None, - ) -> None: - '''ValidationRule describes a validation rule written in the CEL expression language. - - :param rule: Rule represents the expression which will be evaluated by CEL. ref: https://github.com/google/cel-spec The Rule is scoped to the location of the x-kubernetes-validations extension in the schema. The ``self`` variable in the CEL expression is bound to the scoped value. Example: - Rule scoped to the root of a resource with a status subresource: {"rule": "self.status.actual <= self.spec.maxDesired"} If the Rule is scoped to an object with properties, the accessible properties of the object are field selectable via ``self.field`` and field presence can be checked via ``has(self.field)``. Null valued fields are treated as absent fields in CEL expressions. If the Rule is scoped to an object with additionalProperties (i.e. a map) the value of the map are accessible via ``self[mapKey]``, map containment can be checked via ``mapKey in self`` and all entries of the map are accessible via CEL macros and functions such as ``self.all(...)``. If the Rule is scoped to an array, the elements of the array are accessible via ``self[i]`` and also by macros and functions. If the Rule is scoped to a scalar, ``self`` is bound to the scalar value. Examples: - Rule scoped to a map of objects: {"rule": "self.components['Widget'].priority < 10"} - Rule scoped to a list of integers: {"rule": "self.values.all(value, value >= 0 && value < 100)"} - Rule scoped to a string value: {"rule": "self.startsWith('kube')"} The ``apiVersion``, ``kind``, ``metadata.name`` and ``metadata.generateName`` are always accessible from the root of the object and from any x-kubernetes-embedded-resource annotated objects. No other metadata properties are accessible. Unknown data preserved in custom resources via x-kubernetes-preserve-unknown-fields is not accessible in CEL expressions. This includes: - Unknown field values that are preserved by object schemas with x-kubernetes-preserve-unknown-fields. - Object properties where the property schema is of an "unknown type". An "unknown type" is recursively defined as: - A schema with no type and x-kubernetes-preserve-unknown-fields set to true - An array where the items schema is of an "unknown type" - An object where the additionalProperties schema is of an "unknown type" Only property names of the form ``[a-zA-Z_.-/][a-zA-Z0-9_.-/]*`` are accessible. Accessible property names are escaped according to the following rules when accessed in the expression: - '**' escapes to '**underscores**' - '.' escapes to '**dot**' - '-' escapes to '**dash**' - '/' escapes to '**slash**' - Property names that exactly match a CEL RESERVED keyword escape to '**{keyword}__'. The keywords are: "true", "false", "null", "in", "as", "break", "const", "continue", "else", "for", "function", "if", "import", "let", "loop", "package", "namespace", "return". Examples: - Rule accessing a property named "namespace": {"rule": "self.**namespace** > 0"} - Rule accessing a property named "x-prop": {"rule": "self.x__dash__prop > 0"} - Rule accessing a property named "redact__d": {"rule": "self.redact__underscores__d > 0"} Equality on arrays with x-kubernetes-list-type of 'set' or 'map' ignores element order, i.e. [1, 2] == [2, 1]. Concatenation on arrays with x-kubernetes-list-type use the semantics of the list type: - 'set': ``X + Y`` performs a union where the array positions of all elements in ``X`` are preserved and non-intersecting elements in ``Y`` are appended, retaining their partial order. - 'map': ``X + Y`` performs a merge where the array positions of all keys in ``X`` are preserved but the values are overwritten by values in ``Y`` when the key sets of ``X`` and ``Y`` intersect. Elements in ``Y`` with non-intersecting keys are appended, retaining their partial order. - :param message: Message represents the message displayed when validation fails. The message is required if the Rule contains line breaks. The message must not contain line breaks. If unset, the message is "failed rule: {Rule}". e.g. "must be a URL with the host matching spec.host" - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.ValidationRule - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__8500698ff415569f959cc71557c593435adb8418cbc4abf4ced8324f4f0da96d) - check_type(argname="argument rule", value=rule, expected_type=type_hints["rule"]) - check_type(argname="argument message", value=message, expected_type=type_hints["message"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "rule": rule, - } - if message is not None: - self._values["message"] = message - - @builtins.property - def rule(self) -> builtins.str: - '''Rule represents the expression which will be evaluated by CEL. - - ref: https://github.com/google/cel-spec The Rule is scoped to the location of the x-kubernetes-validations extension in the schema. The ``self`` variable in the CEL expression is bound to the scoped value. Example: - Rule scoped to the root of a resource with a status subresource: {"rule": "self.status.actual <= self.spec.maxDesired"} - - If the Rule is scoped to an object with properties, the accessible properties of the object are field selectable via ``self.field`` and field presence can be checked via ``has(self.field)``. Null valued fields are treated as absent fields in CEL expressions. If the Rule is scoped to an object with additionalProperties (i.e. a map) the value of the map are accessible via ``self[mapKey]``, map containment can be checked via ``mapKey in self`` and all entries of the map are accessible via CEL macros and functions such as ``self.all(...)``. If the Rule is scoped to an array, the elements of the array are accessible via ``self[i]`` and also by macros and functions. If the Rule is scoped to a scalar, ``self`` is bound to the scalar value. Examples: - Rule scoped to a map of objects: {"rule": "self.components['Widget'].priority < 10"} - Rule scoped to a list of integers: {"rule": "self.values.all(value, value >= 0 && value < 100)"} - Rule scoped to a string value: {"rule": "self.startsWith('kube')"} - - The ``apiVersion``, ``kind``, ``metadata.name`` and ``metadata.generateName`` are always accessible from the root of the object and from any x-kubernetes-embedded-resource annotated objects. No other metadata properties are accessible. - - Unknown data preserved in custom resources via x-kubernetes-preserve-unknown-fields is not accessible in CEL expressions. This includes: - Unknown field values that are preserved by object schemas with x-kubernetes-preserve-unknown-fields. - Object properties where the property schema is of an "unknown type". An "unknown type" is recursively defined as: - - - A schema with no type and x-kubernetes-preserve-unknown-fields set to true - - An array where the items schema is of an "unknown type" - - An object where the additionalProperties schema is of an "unknown type" - - Only property names of the form ``[a-zA-Z_.-/][a-zA-Z0-9_.-/]*`` are accessible. Accessible property names are escaped according to the following rules when accessed in the expression: - '**' escapes to '**underscores**' - '.' escapes to '**dot**' - '-' escapes to '**dash**' - '/' escapes to '**slash**' - Property names that exactly match a CEL RESERVED keyword escape to '**{keyword}__'. The keywords are: - "true", "false", "null", "in", "as", "break", "const", "continue", "else", "for", "function", "if", - "import", "let", "loop", "package", "namespace", "return". - Examples: - - - Rule accessing a property named "namespace": {"rule": "self.**namespace** > 0"} - - Rule accessing a property named "x-prop": {"rule": "self.x__dash__prop > 0"} - - Rule accessing a property named "redact__d": {"rule": "self.redact__underscores__d > 0"} - - Equality on arrays with x-kubernetes-list-type of 'set' or 'map' ignores element order, i.e. [1, 2] == [2, 1]. Concatenation on arrays with x-kubernetes-list-type use the semantics of the list type: - - - 'set': ``X + Y`` performs a union where the array positions of all elements in ``X`` are preserved and - non-intersecting elements in ``Y`` are appended, retaining their partial order. - - 'map': ``X + Y`` performs a merge where the array positions of all keys in ``X`` are preserved but the values - are overwritten by values in ``Y`` when the key sets of ``X`` and ``Y`` intersect. Elements in ``Y`` with - non-intersecting keys are appended, retaining their partial order. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.ValidationRule#rule - ''' - result = self._values.get("rule") - assert result is not None, "Required property 'rule' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def message(self) -> typing.Optional[builtins.str]: - '''Message represents the message displayed when validation fails. - - The message is required if the Rule contains line breaks. The message must not contain line breaks. If unset, the message is "failed rule: {Rule}". e.g. "must be a URL with the host matching spec.host" - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.ValidationRule#message - ''' - result = self._values.get("message") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ValidationRule(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.ValidationV1Alpha1", - jsii_struct_bases=[], - name_mapping={ - "expression": "expression", - "message": "message", - "reason": "reason", - }, -) -class ValidationV1Alpha1: - def __init__( - self, - *, - expression: builtins.str, - message: typing.Optional[builtins.str] = None, - reason: typing.Optional[builtins.str] = None, - ) -> None: - '''Validation specifies the CEL expression which is used to apply the validation. - - :param expression: Expression represents the expression which will be evaluated by CEL. ref: https://github.com/google/cel-spec CEL expressions have access to the contents of the Admission request/response, organized into CEL variables as well as some other useful variables: 'object' - The object from the incoming request. The value is null for DELETE requests. 'oldObject' - The existing object. The value is null for CREATE requests. 'request' - Attributes of the admission request(`ref `_). 'params' - Parameter resource referred to by the policy binding being evaluated. Only populated if the policy has a ParamKind. The ``apiVersion``, ``kind``, ``metadata.name`` and ``metadata.generateName`` are always accessible from the root of the object. No other metadata properties are accessible. Only property names of the form ``[a-zA-Z_.-/][a-zA-Z0-9_.-/]*`` are accessible. Accessible property names are escaped according to the following rules when accessed in the expression: - '**' escapes to '**underscores**' - '.' escapes to '**dot**' - '-' escapes to '**dash**' - '/' escapes to '**slash**' - Property names that exactly match a CEL RESERVED keyword escape to '**{keyword}__'. The keywords are: "true", "false", "null", "in", "as", "break", "const", "continue", "else", "for", "function", "if", "import", "let", "loop", "package", "namespace", "return". Examples: - Expression accessing a property named "namespace": {"Expression": "object.**namespace** > 0"} - Expression accessing a property named "x-prop": {"Expression": "object.x__dash__prop > 0"} - Expression accessing a property named "redact__d": {"Expression": "object.redact__underscores__d > 0"} Equality on arrays with list type of 'set' or 'map' ignores element order, i.e. [1, 2] == [2, 1]. Concatenation on arrays with x-kubernetes-list-type use the semantics of the list type: - 'set': ``X + Y`` performs a union where the array positions of all elements in ``X`` are preserved and non-intersecting elements in ``Y`` are appended, retaining their partial order. - 'map': ``X + Y`` performs a merge where the array positions of all keys in ``X`` are preserved but the values are overwritten by values in ``Y`` when the key sets of ``X`` and ``Y`` intersect. Elements in ``Y`` with non-intersecting keys are appended, retaining their partial order. Required. - :param message: Message represents the message displayed when validation fails. The message is required if the Expression contains line breaks. The message must not contain line breaks. If unset, the message is "failed rule: {Rule}". e.g. "must be a URL with the host matching spec.host" If the Expression contains line breaks. Message is required. The message must not contain line breaks. If unset, the message is "failed Expression: {Expression}". - :param reason: Reason represents a machine-readable description of why this validation failed. If this is the first validation in the list to fail, this reason, as well as the corresponding HTTP response code, are used in the HTTP response to the client. The currently supported reasons are: "Unauthorized", "Forbidden", "Invalid", "RequestEntityTooLarge". If not set, StatusReasonInvalid is used in the response to the client. - - :schema: io.k8s.api.admissionregistration.v1alpha1.Validation - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__2e42e86e2cf6a0b9c2247c2d420d94cd03debba0ad4391ae8e0001bde4c15b3f) - check_type(argname="argument expression", value=expression, expected_type=type_hints["expression"]) - check_type(argname="argument message", value=message, expected_type=type_hints["message"]) - check_type(argname="argument reason", value=reason, expected_type=type_hints["reason"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "expression": expression, - } - if message is not None: - self._values["message"] = message - if reason is not None: - self._values["reason"] = reason - - @builtins.property - def expression(self) -> builtins.str: - '''Expression represents the expression which will be evaluated by CEL. - - ref: https://github.com/google/cel-spec CEL expressions have access to the contents of the Admission request/response, organized into CEL variables as well as some other useful variables: - - 'object' - The object from the incoming request. The value is null for DELETE requests. 'oldObject' - The existing object. The value is null for CREATE requests. 'request' - Attributes of the admission request(`ref `_). 'params' - Parameter resource referred to by the policy binding being evaluated. Only populated if the policy has a ParamKind. - - The ``apiVersion``, ``kind``, ``metadata.name`` and ``metadata.generateName`` are always accessible from the root of the object. No other metadata properties are accessible. - - Only property names of the form ``[a-zA-Z_.-/][a-zA-Z0-9_.-/]*`` are accessible. Accessible property names are escaped according to the following rules when accessed in the expression: - '**' escapes to '**underscores**' - '.' escapes to '**dot**' - '-' escapes to '**dash**' - '/' escapes to '**slash**' - Property names that exactly match a CEL RESERVED keyword escape to '**{keyword}__'. The keywords are: - "true", "false", "null", "in", "as", "break", "const", "continue", "else", "for", "function", "if", - "import", "let", "loop", "package", "namespace", "return". - Examples: - - - Expression accessing a property named "namespace": {"Expression": "object.**namespace** > 0"} - - Expression accessing a property named "x-prop": {"Expression": "object.x__dash__prop > 0"} - - Expression accessing a property named "redact__d": {"Expression": "object.redact__underscores__d > 0"} - - Equality on arrays with list type of 'set' or 'map' ignores element order, i.e. [1, 2] == [2, 1]. Concatenation on arrays with x-kubernetes-list-type use the semantics of the list type: - - - 'set': ``X + Y`` performs a union where the array positions of all elements in ``X`` are preserved and - non-intersecting elements in ``Y`` are appended, retaining their partial order. - - 'map': ``X + Y`` performs a merge where the array positions of all keys in ``X`` are preserved but the values - are overwritten by values in ``Y`` when the key sets of ``X`` and ``Y`` intersect. Elements in ``Y`` with - non-intersecting keys are appended, retaining their partial order. - Required. - - :schema: io.k8s.api.admissionregistration.v1alpha1.Validation#expression - ''' - result = self._values.get("expression") - assert result is not None, "Required property 'expression' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def message(self) -> typing.Optional[builtins.str]: - '''Message represents the message displayed when validation fails. - - The message is required if the Expression contains line breaks. The message must not contain line breaks. If unset, the message is "failed rule: {Rule}". e.g. "must be a URL with the host matching spec.host" If the Expression contains line breaks. Message is required. The message must not contain line breaks. If unset, the message is "failed Expression: {Expression}". - - :schema: io.k8s.api.admissionregistration.v1alpha1.Validation#message - ''' - result = self._values.get("message") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def reason(self) -> typing.Optional[builtins.str]: - '''Reason represents a machine-readable description of why this validation failed. - - If this is the first validation in the list to fail, this reason, as well as the corresponding HTTP response code, are used in the HTTP response to the client. The currently supported reasons are: "Unauthorized", "Forbidden", "Invalid", "RequestEntityTooLarge". If not set, StatusReasonInvalid is used in the response to the client. - - :schema: io.k8s.api.admissionregistration.v1alpha1.Validation#reason - ''' - result = self._values.get("reason") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "ValidationV1Alpha1(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.Volume", - jsii_struct_bases=[], - name_mapping={ - "name": "name", - "aws_elastic_block_store": "awsElasticBlockStore", - "azure_disk": "azureDisk", - "azure_file": "azureFile", - "cephfs": "cephfs", - "cinder": "cinder", - "config_map": "configMap", - "csi": "csi", - "downward_api": "downwardApi", - "empty_dir": "emptyDir", - "ephemeral": "ephemeral", - "fc": "fc", - "flex_volume": "flexVolume", - "flocker": "flocker", - "gce_persistent_disk": "gcePersistentDisk", - "git_repo": "gitRepo", - "glusterfs": "glusterfs", - "host_path": "hostPath", - "iscsi": "iscsi", - "nfs": "nfs", - "persistent_volume_claim": "persistentVolumeClaim", - "photon_persistent_disk": "photonPersistentDisk", - "portworx_volume": "portworxVolume", - "projected": "projected", - "quobyte": "quobyte", - "rbd": "rbd", - "scale_io": "scaleIo", - "secret": "secret", - "storageos": "storageos", - "vsphere_volume": "vsphereVolume", - }, -) -class Volume: - def __init__( - self, - *, - name: builtins.str, - aws_elastic_block_store: typing.Optional[typing.Union[AwsElasticBlockStoreVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - azure_disk: typing.Optional[typing.Union[AzureDiskVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - azure_file: typing.Optional[typing.Union[AzureFileVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - cephfs: typing.Optional[typing.Union[CephFsVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - cinder: typing.Optional[typing.Union[CinderVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - config_map: typing.Optional[typing.Union[ConfigMapVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - csi: typing.Optional[typing.Union[CsiVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - downward_api: typing.Optional[typing.Union[DownwardApiVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - empty_dir: typing.Optional[typing.Union[EmptyDirVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - ephemeral: typing.Optional[typing.Union[EphemeralVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - fc: typing.Optional[typing.Union[FcVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - flex_volume: typing.Optional[typing.Union[FlexVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - flocker: typing.Optional[typing.Union[FlockerVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - gce_persistent_disk: typing.Optional[typing.Union[GcePersistentDiskVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - git_repo: typing.Optional[typing.Union[GitRepoVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - glusterfs: typing.Optional[typing.Union[GlusterfsVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - host_path: typing.Optional[typing.Union[HostPathVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - iscsi: typing.Optional[typing.Union[IscsiVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - nfs: typing.Optional[typing.Union[NfsVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - persistent_volume_claim: typing.Optional[typing.Union[PersistentVolumeClaimVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - photon_persistent_disk: typing.Optional[typing.Union[PhotonPersistentDiskVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - portworx_volume: typing.Optional[typing.Union[PortworxVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - projected: typing.Optional[typing.Union[ProjectedVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - quobyte: typing.Optional[typing.Union[QuobyteVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - rbd: typing.Optional[typing.Union[RbdVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - scale_io: typing.Optional[typing.Union[ScaleIoVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - secret: typing.Optional[typing.Union[SecretVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - storageos: typing.Optional[typing.Union[StorageOsVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - vsphere_volume: typing.Optional[typing.Union["VsphereVirtualDiskVolumeSource", typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Volume represents a named volume in a pod that may be accessed by any container in the pod. - - :param name: name of the volume. Must be a DNS_LABEL and unique within the pod. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - :param aws_elastic_block_store: awsElasticBlockStore represents an AWS Disk resource that is attached to a kubelet's host machine and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - :param azure_disk: azureDisk represents an Azure Data Disk mount on the host and bind mount to the pod. - :param azure_file: azureFile represents an Azure File Service mount on the host and bind mount to the pod. - :param cephfs: cephFS represents a Ceph FS mount on the host that shares a pod's lifetime. - :param cinder: cinder represents a cinder volume attached and mounted on kubelets host machine. More info: https://examples.k8s.io/mysql-cinder-pd/README.md - :param config_map: configMap represents a configMap that should populate this volume. - :param csi: csi (Container Storage Interface) represents ephemeral storage that is handled by certain external CSI drivers (Beta feature). - :param downward_api: downwardAPI represents downward API about the pod that should populate this volume. - :param empty_dir: emptyDir represents a temporary directory that shares a pod's lifetime. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir - :param ephemeral: ephemeral represents a volume that is handled by a cluster storage driver. The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, and deleted when the pod is removed. Use this if: a) the volume is only needed while the pod runs, b) features of normal volumes like restoring from snapshot or capacity tracking are needed, c) the storage driver is specified through a storage class, and d) the storage driver supports dynamic volume provisioning through a PersistentVolumeClaim (see EphemeralVolumeSource for more information on the connection between this volume type and PersistentVolumeClaim). Use PersistentVolumeClaim or one of the vendor-specific APIs for volumes that persist for longer than the lifecycle of an individual pod. Use CSI for light-weight local ephemeral volumes if the CSI driver is meant to be used that way - see the documentation of the driver for more information. A pod can use both types of ephemeral volumes and persistent volumes at the same time. - :param fc: fc represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod. - :param flex_volume: flexVolume represents a generic volume resource that is provisioned/attached using an exec based plugin. - :param flocker: flocker represents a Flocker volume attached to a kubelet's host machine. This depends on the Flocker control service being running - :param gce_persistent_disk: gcePersistentDisk represents a GCE Disk resource that is attached to a kubelet's host machine and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - :param git_repo: gitRepo represents a git repository at a particular revision. DEPRECATED: GitRepo is deprecated. To provision a container with a git repo, mount an EmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir into the Pod's container. - :param glusterfs: glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. More info: https://examples.k8s.io/volumes/glusterfs/README.md - :param host_path: hostPath represents a pre-existing file or directory on the host machine that is directly exposed to the container. This is generally used for system agents or other privileged things that are allowed to see the host machine. Most containers will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - :param iscsi: iscsi represents an ISCSI Disk resource that is attached to a kubelet's host machine and then exposed to the pod. More info: https://examples.k8s.io/volumes/iscsi/README.md - :param nfs: nfs represents an NFS mount on the host that shares a pod's lifetime More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs. - :param persistent_volume_claim: persistentVolumeClaimVolumeSource represents a reference to a PersistentVolumeClaim in the same namespace. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - :param photon_persistent_disk: photonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine. - :param portworx_volume: portworxVolume represents a portworx volume attached and mounted on kubelets host machine. - :param projected: projected items for all in one resources secrets, configmaps, and downward API. - :param quobyte: quobyte represents a Quobyte mount on the host that shares a pod's lifetime. - :param rbd: rbd represents a Rados Block Device mount on the host that shares a pod's lifetime. More info: https://examples.k8s.io/volumes/rbd/README.md - :param scale_io: scaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes. - :param secret: secret represents a secret that should populate this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret - :param storageos: storageOS represents a StorageOS volume attached and mounted on Kubernetes nodes. - :param vsphere_volume: vsphereVolume represents a vSphere volume attached and mounted on kubelets host machine. - - :schema: io.k8s.api.core.v1.Volume - ''' - if isinstance(aws_elastic_block_store, dict): - aws_elastic_block_store = AwsElasticBlockStoreVolumeSource(**aws_elastic_block_store) - if isinstance(azure_disk, dict): - azure_disk = AzureDiskVolumeSource(**azure_disk) - if isinstance(azure_file, dict): - azure_file = AzureFileVolumeSource(**azure_file) - if isinstance(cephfs, dict): - cephfs = CephFsVolumeSource(**cephfs) - if isinstance(cinder, dict): - cinder = CinderVolumeSource(**cinder) - if isinstance(config_map, dict): - config_map = ConfigMapVolumeSource(**config_map) - if isinstance(csi, dict): - csi = CsiVolumeSource(**csi) - if isinstance(downward_api, dict): - downward_api = DownwardApiVolumeSource(**downward_api) - if isinstance(empty_dir, dict): - empty_dir = EmptyDirVolumeSource(**empty_dir) - if isinstance(ephemeral, dict): - ephemeral = EphemeralVolumeSource(**ephemeral) - if isinstance(fc, dict): - fc = FcVolumeSource(**fc) - if isinstance(flex_volume, dict): - flex_volume = FlexVolumeSource(**flex_volume) - if isinstance(flocker, dict): - flocker = FlockerVolumeSource(**flocker) - if isinstance(gce_persistent_disk, dict): - gce_persistent_disk = GcePersistentDiskVolumeSource(**gce_persistent_disk) - if isinstance(git_repo, dict): - git_repo = GitRepoVolumeSource(**git_repo) - if isinstance(glusterfs, dict): - glusterfs = GlusterfsVolumeSource(**glusterfs) - if isinstance(host_path, dict): - host_path = HostPathVolumeSource(**host_path) - if isinstance(iscsi, dict): - iscsi = IscsiVolumeSource(**iscsi) - if isinstance(nfs, dict): - nfs = NfsVolumeSource(**nfs) - if isinstance(persistent_volume_claim, dict): - persistent_volume_claim = PersistentVolumeClaimVolumeSource(**persistent_volume_claim) - if isinstance(photon_persistent_disk, dict): - photon_persistent_disk = PhotonPersistentDiskVolumeSource(**photon_persistent_disk) - if isinstance(portworx_volume, dict): - portworx_volume = PortworxVolumeSource(**portworx_volume) - if isinstance(projected, dict): - projected = ProjectedVolumeSource(**projected) - if isinstance(quobyte, dict): - quobyte = QuobyteVolumeSource(**quobyte) - if isinstance(rbd, dict): - rbd = RbdVolumeSource(**rbd) - if isinstance(scale_io, dict): - scale_io = ScaleIoVolumeSource(**scale_io) - if isinstance(secret, dict): - secret = SecretVolumeSource(**secret) - if isinstance(storageos, dict): - storageos = StorageOsVolumeSource(**storageos) - if isinstance(vsphere_volume, dict): - vsphere_volume = VsphereVirtualDiskVolumeSource(**vsphere_volume) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__b0baec088296b673c4c879b5ee48b961991a0c2bba4add80d27e32c59d57f145) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument aws_elastic_block_store", value=aws_elastic_block_store, expected_type=type_hints["aws_elastic_block_store"]) - check_type(argname="argument azure_disk", value=azure_disk, expected_type=type_hints["azure_disk"]) - check_type(argname="argument azure_file", value=azure_file, expected_type=type_hints["azure_file"]) - check_type(argname="argument cephfs", value=cephfs, expected_type=type_hints["cephfs"]) - check_type(argname="argument cinder", value=cinder, expected_type=type_hints["cinder"]) - check_type(argname="argument config_map", value=config_map, expected_type=type_hints["config_map"]) - check_type(argname="argument csi", value=csi, expected_type=type_hints["csi"]) - check_type(argname="argument downward_api", value=downward_api, expected_type=type_hints["downward_api"]) - check_type(argname="argument empty_dir", value=empty_dir, expected_type=type_hints["empty_dir"]) - check_type(argname="argument ephemeral", value=ephemeral, expected_type=type_hints["ephemeral"]) - check_type(argname="argument fc", value=fc, expected_type=type_hints["fc"]) - check_type(argname="argument flex_volume", value=flex_volume, expected_type=type_hints["flex_volume"]) - check_type(argname="argument flocker", value=flocker, expected_type=type_hints["flocker"]) - check_type(argname="argument gce_persistent_disk", value=gce_persistent_disk, expected_type=type_hints["gce_persistent_disk"]) - check_type(argname="argument git_repo", value=git_repo, expected_type=type_hints["git_repo"]) - check_type(argname="argument glusterfs", value=glusterfs, expected_type=type_hints["glusterfs"]) - check_type(argname="argument host_path", value=host_path, expected_type=type_hints["host_path"]) - check_type(argname="argument iscsi", value=iscsi, expected_type=type_hints["iscsi"]) - check_type(argname="argument nfs", value=nfs, expected_type=type_hints["nfs"]) - check_type(argname="argument persistent_volume_claim", value=persistent_volume_claim, expected_type=type_hints["persistent_volume_claim"]) - check_type(argname="argument photon_persistent_disk", value=photon_persistent_disk, expected_type=type_hints["photon_persistent_disk"]) - check_type(argname="argument portworx_volume", value=portworx_volume, expected_type=type_hints["portworx_volume"]) - check_type(argname="argument projected", value=projected, expected_type=type_hints["projected"]) - check_type(argname="argument quobyte", value=quobyte, expected_type=type_hints["quobyte"]) - check_type(argname="argument rbd", value=rbd, expected_type=type_hints["rbd"]) - check_type(argname="argument scale_io", value=scale_io, expected_type=type_hints["scale_io"]) - check_type(argname="argument secret", value=secret, expected_type=type_hints["secret"]) - check_type(argname="argument storageos", value=storageos, expected_type=type_hints["storageos"]) - check_type(argname="argument vsphere_volume", value=vsphere_volume, expected_type=type_hints["vsphere_volume"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "name": name, - } - if aws_elastic_block_store is not None: - self._values["aws_elastic_block_store"] = aws_elastic_block_store - if azure_disk is not None: - self._values["azure_disk"] = azure_disk - if azure_file is not None: - self._values["azure_file"] = azure_file - if cephfs is not None: - self._values["cephfs"] = cephfs - if cinder is not None: - self._values["cinder"] = cinder - if config_map is not None: - self._values["config_map"] = config_map - if csi is not None: - self._values["csi"] = csi - if downward_api is not None: - self._values["downward_api"] = downward_api - if empty_dir is not None: - self._values["empty_dir"] = empty_dir - if ephemeral is not None: - self._values["ephemeral"] = ephemeral - if fc is not None: - self._values["fc"] = fc - if flex_volume is not None: - self._values["flex_volume"] = flex_volume - if flocker is not None: - self._values["flocker"] = flocker - if gce_persistent_disk is not None: - self._values["gce_persistent_disk"] = gce_persistent_disk - if git_repo is not None: - self._values["git_repo"] = git_repo - if glusterfs is not None: - self._values["glusterfs"] = glusterfs - if host_path is not None: - self._values["host_path"] = host_path - if iscsi is not None: - self._values["iscsi"] = iscsi - if nfs is not None: - self._values["nfs"] = nfs - if persistent_volume_claim is not None: - self._values["persistent_volume_claim"] = persistent_volume_claim - if photon_persistent_disk is not None: - self._values["photon_persistent_disk"] = photon_persistent_disk - if portworx_volume is not None: - self._values["portworx_volume"] = portworx_volume - if projected is not None: - self._values["projected"] = projected - if quobyte is not None: - self._values["quobyte"] = quobyte - if rbd is not None: - self._values["rbd"] = rbd - if scale_io is not None: - self._values["scale_io"] = scale_io - if secret is not None: - self._values["secret"] = secret - if storageos is not None: - self._values["storageos"] = storageos - if vsphere_volume is not None: - self._values["vsphere_volume"] = vsphere_volume - - @builtins.property - def name(self) -> builtins.str: - '''name of the volume. - - Must be a DNS_LABEL and unique within the pod. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - - :schema: io.k8s.api.core.v1.Volume#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def aws_elastic_block_store( - self, - ) -> typing.Optional[AwsElasticBlockStoreVolumeSource]: - '''awsElasticBlockStore represents an AWS Disk resource that is attached to a kubelet's host machine and then exposed to the pod. - - More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - - :schema: io.k8s.api.core.v1.Volume#awsElasticBlockStore - ''' - result = self._values.get("aws_elastic_block_store") - return typing.cast(typing.Optional[AwsElasticBlockStoreVolumeSource], result) - - @builtins.property - def azure_disk(self) -> typing.Optional[AzureDiskVolumeSource]: - '''azureDisk represents an Azure Data Disk mount on the host and bind mount to the pod. - - :schema: io.k8s.api.core.v1.Volume#azureDisk - ''' - result = self._values.get("azure_disk") - return typing.cast(typing.Optional[AzureDiskVolumeSource], result) - - @builtins.property - def azure_file(self) -> typing.Optional[AzureFileVolumeSource]: - '''azureFile represents an Azure File Service mount on the host and bind mount to the pod. - - :schema: io.k8s.api.core.v1.Volume#azureFile - ''' - result = self._values.get("azure_file") - return typing.cast(typing.Optional[AzureFileVolumeSource], result) - - @builtins.property - def cephfs(self) -> typing.Optional[CephFsVolumeSource]: - '''cephFS represents a Ceph FS mount on the host that shares a pod's lifetime. - - :schema: io.k8s.api.core.v1.Volume#cephfs - ''' - result = self._values.get("cephfs") - return typing.cast(typing.Optional[CephFsVolumeSource], result) - - @builtins.property - def cinder(self) -> typing.Optional[CinderVolumeSource]: - '''cinder represents a cinder volume attached and mounted on kubelets host machine. - - More info: https://examples.k8s.io/mysql-cinder-pd/README.md - - :schema: io.k8s.api.core.v1.Volume#cinder - ''' - result = self._values.get("cinder") - return typing.cast(typing.Optional[CinderVolumeSource], result) - - @builtins.property - def config_map(self) -> typing.Optional[ConfigMapVolumeSource]: - '''configMap represents a configMap that should populate this volume. - - :schema: io.k8s.api.core.v1.Volume#configMap - ''' - result = self._values.get("config_map") - return typing.cast(typing.Optional[ConfigMapVolumeSource], result) - - @builtins.property - def csi(self) -> typing.Optional[CsiVolumeSource]: - '''csi (Container Storage Interface) represents ephemeral storage that is handled by certain external CSI drivers (Beta feature). - - :schema: io.k8s.api.core.v1.Volume#csi - ''' - result = self._values.get("csi") - return typing.cast(typing.Optional[CsiVolumeSource], result) - - @builtins.property - def downward_api(self) -> typing.Optional[DownwardApiVolumeSource]: - '''downwardAPI represents downward API about the pod that should populate this volume. - - :schema: io.k8s.api.core.v1.Volume#downwardAPI - ''' - result = self._values.get("downward_api") - return typing.cast(typing.Optional[DownwardApiVolumeSource], result) - - @builtins.property - def empty_dir(self) -> typing.Optional[EmptyDirVolumeSource]: - '''emptyDir represents a temporary directory that shares a pod's lifetime. - - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir - - :schema: io.k8s.api.core.v1.Volume#emptyDir - ''' - result = self._values.get("empty_dir") - return typing.cast(typing.Optional[EmptyDirVolumeSource], result) - - @builtins.property - def ephemeral(self) -> typing.Optional[EphemeralVolumeSource]: - '''ephemeral represents a volume that is handled by a cluster storage driver. - - The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, and deleted when the pod is removed. - - Use this if: a) the volume is only needed while the pod runs, b) features of normal volumes like restoring from snapshot or capacity - tracking are needed, - c) the storage driver is specified through a storage class, and d) the storage driver supports dynamic volume provisioning through - a PersistentVolumeClaim (see EphemeralVolumeSource for more - information on the connection between this volume type - and PersistentVolumeClaim). - - Use PersistentVolumeClaim or one of the vendor-specific APIs for volumes that persist for longer than the lifecycle of an individual pod. - - Use CSI for light-weight local ephemeral volumes if the CSI driver is meant to be used that way - see the documentation of the driver for more information. - - A pod can use both types of ephemeral volumes and persistent volumes at the same time. - - :schema: io.k8s.api.core.v1.Volume#ephemeral - ''' - result = self._values.get("ephemeral") - return typing.cast(typing.Optional[EphemeralVolumeSource], result) - - @builtins.property - def fc(self) -> typing.Optional[FcVolumeSource]: - '''fc represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod. - - :schema: io.k8s.api.core.v1.Volume#fc - ''' - result = self._values.get("fc") - return typing.cast(typing.Optional[FcVolumeSource], result) - - @builtins.property - def flex_volume(self) -> typing.Optional[FlexVolumeSource]: - '''flexVolume represents a generic volume resource that is provisioned/attached using an exec based plugin. - - :schema: io.k8s.api.core.v1.Volume#flexVolume - ''' - result = self._values.get("flex_volume") - return typing.cast(typing.Optional[FlexVolumeSource], result) - - @builtins.property - def flocker(self) -> typing.Optional[FlockerVolumeSource]: - '''flocker represents a Flocker volume attached to a kubelet's host machine. - - This depends on the Flocker control service being running - - :schema: io.k8s.api.core.v1.Volume#flocker - ''' - result = self._values.get("flocker") - return typing.cast(typing.Optional[FlockerVolumeSource], result) - - @builtins.property - def gce_persistent_disk(self) -> typing.Optional[GcePersistentDiskVolumeSource]: - '''gcePersistentDisk represents a GCE Disk resource that is attached to a kubelet's host machine and then exposed to the pod. - - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - - :schema: io.k8s.api.core.v1.Volume#gcePersistentDisk - ''' - result = self._values.get("gce_persistent_disk") - return typing.cast(typing.Optional[GcePersistentDiskVolumeSource], result) - - @builtins.property - def git_repo(self) -> typing.Optional[GitRepoVolumeSource]: - '''gitRepo represents a git repository at a particular revision. - - DEPRECATED: GitRepo is deprecated. To provision a container with a git repo, mount an EmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir into the Pod's container. - - :schema: io.k8s.api.core.v1.Volume#gitRepo - ''' - result = self._values.get("git_repo") - return typing.cast(typing.Optional[GitRepoVolumeSource], result) - - @builtins.property - def glusterfs(self) -> typing.Optional[GlusterfsVolumeSource]: - '''glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. - - More info: https://examples.k8s.io/volumes/glusterfs/README.md - - :schema: io.k8s.api.core.v1.Volume#glusterfs - ''' - result = self._values.get("glusterfs") - return typing.cast(typing.Optional[GlusterfsVolumeSource], result) - - @builtins.property - def host_path(self) -> typing.Optional[HostPathVolumeSource]: - '''hostPath represents a pre-existing file or directory on the host machine that is directly exposed to the container. - - This is generally used for system agents or other privileged things that are allowed to see the host machine. Most containers will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - - :schema: io.k8s.api.core.v1.Volume#hostPath - ''' - result = self._values.get("host_path") - return typing.cast(typing.Optional[HostPathVolumeSource], result) - - @builtins.property - def iscsi(self) -> typing.Optional[IscsiVolumeSource]: - '''iscsi represents an ISCSI Disk resource that is attached to a kubelet's host machine and then exposed to the pod. - - More info: https://examples.k8s.io/volumes/iscsi/README.md - - :schema: io.k8s.api.core.v1.Volume#iscsi - ''' - result = self._values.get("iscsi") - return typing.cast(typing.Optional[IscsiVolumeSource], result) - - @builtins.property - def nfs(self) -> typing.Optional[NfsVolumeSource]: - '''nfs represents an NFS mount on the host that shares a pod's lifetime More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs. - - :schema: io.k8s.api.core.v1.Volume#nfs - ''' - result = self._values.get("nfs") - return typing.cast(typing.Optional[NfsVolumeSource], result) - - @builtins.property - def persistent_volume_claim( - self, - ) -> typing.Optional[PersistentVolumeClaimVolumeSource]: - '''persistentVolumeClaimVolumeSource represents a reference to a PersistentVolumeClaim in the same namespace. - - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - - :schema: io.k8s.api.core.v1.Volume#persistentVolumeClaim - ''' - result = self._values.get("persistent_volume_claim") - return typing.cast(typing.Optional[PersistentVolumeClaimVolumeSource], result) - - @builtins.property - def photon_persistent_disk( - self, - ) -> typing.Optional[PhotonPersistentDiskVolumeSource]: - '''photonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine. - - :schema: io.k8s.api.core.v1.Volume#photonPersistentDisk - ''' - result = self._values.get("photon_persistent_disk") - return typing.cast(typing.Optional[PhotonPersistentDiskVolumeSource], result) - - @builtins.property - def portworx_volume(self) -> typing.Optional[PortworxVolumeSource]: - '''portworxVolume represents a portworx volume attached and mounted on kubelets host machine. - - :schema: io.k8s.api.core.v1.Volume#portworxVolume - ''' - result = self._values.get("portworx_volume") - return typing.cast(typing.Optional[PortworxVolumeSource], result) - - @builtins.property - def projected(self) -> typing.Optional[ProjectedVolumeSource]: - '''projected items for all in one resources secrets, configmaps, and downward API. - - :schema: io.k8s.api.core.v1.Volume#projected - ''' - result = self._values.get("projected") - return typing.cast(typing.Optional[ProjectedVolumeSource], result) - - @builtins.property - def quobyte(self) -> typing.Optional[QuobyteVolumeSource]: - '''quobyte represents a Quobyte mount on the host that shares a pod's lifetime. - - :schema: io.k8s.api.core.v1.Volume#quobyte - ''' - result = self._values.get("quobyte") - return typing.cast(typing.Optional[QuobyteVolumeSource], result) - - @builtins.property - def rbd(self) -> typing.Optional[RbdVolumeSource]: - '''rbd represents a Rados Block Device mount on the host that shares a pod's lifetime. - - More info: https://examples.k8s.io/volumes/rbd/README.md - - :schema: io.k8s.api.core.v1.Volume#rbd - ''' - result = self._values.get("rbd") - return typing.cast(typing.Optional[RbdVolumeSource], result) - - @builtins.property - def scale_io(self) -> typing.Optional[ScaleIoVolumeSource]: - '''scaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes. - - :schema: io.k8s.api.core.v1.Volume#scaleIO - ''' - result = self._values.get("scale_io") - return typing.cast(typing.Optional[ScaleIoVolumeSource], result) - - @builtins.property - def secret(self) -> typing.Optional[SecretVolumeSource]: - '''secret represents a secret that should populate this volume. - - More info: https://kubernetes.io/docs/concepts/storage/volumes#secret - - :schema: io.k8s.api.core.v1.Volume#secret - ''' - result = self._values.get("secret") - return typing.cast(typing.Optional[SecretVolumeSource], result) - - @builtins.property - def storageos(self) -> typing.Optional[StorageOsVolumeSource]: - '''storageOS represents a StorageOS volume attached and mounted on Kubernetes nodes. - - :schema: io.k8s.api.core.v1.Volume#storageos - ''' - result = self._values.get("storageos") - return typing.cast(typing.Optional[StorageOsVolumeSource], result) - - @builtins.property - def vsphere_volume(self) -> typing.Optional["VsphereVirtualDiskVolumeSource"]: - '''vsphereVolume represents a vSphere volume attached and mounted on kubelets host machine. - - :schema: io.k8s.api.core.v1.Volume#vsphereVolume - ''' - result = self._values.get("vsphere_volume") - return typing.cast(typing.Optional["VsphereVirtualDiskVolumeSource"], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "Volume(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.VolumeAttachmentSource", - jsii_struct_bases=[], - name_mapping={ - "inline_volume_spec": "inlineVolumeSpec", - "persistent_volume_name": "persistentVolumeName", - }, -) -class VolumeAttachmentSource: - def __init__( - self, - *, - inline_volume_spec: typing.Optional[typing.Union[PersistentVolumeSpec, typing.Dict[builtins.str, typing.Any]]] = None, - persistent_volume_name: typing.Optional[builtins.str] = None, - ) -> None: - '''VolumeAttachmentSource represents a volume that should be attached. - - Right now only PersistenVolumes can be attached via external attacher, in future we may allow also inline volumes in pods. Exactly one member can be set. - - :param inline_volume_spec: inlineVolumeSpec contains all the information necessary to attach a persistent volume defined by a pod's inline VolumeSource. This field is populated only for the CSIMigration feature. It contains translated fields from a pod's inline VolumeSource to a PersistentVolumeSpec. This field is beta-level and is only honored by servers that enabled the CSIMigration feature. - :param persistent_volume_name: Name of the persistent volume to attach. - - :schema: io.k8s.api.storage.v1.VolumeAttachmentSource - ''' - if isinstance(inline_volume_spec, dict): - inline_volume_spec = PersistentVolumeSpec(**inline_volume_spec) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__b3f9952d5e8dadf3ded289f1651a13c30397c804b078b1918f7e368a400af926) - check_type(argname="argument inline_volume_spec", value=inline_volume_spec, expected_type=type_hints["inline_volume_spec"]) - check_type(argname="argument persistent_volume_name", value=persistent_volume_name, expected_type=type_hints["persistent_volume_name"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if inline_volume_spec is not None: - self._values["inline_volume_spec"] = inline_volume_spec - if persistent_volume_name is not None: - self._values["persistent_volume_name"] = persistent_volume_name - - @builtins.property - def inline_volume_spec(self) -> typing.Optional[PersistentVolumeSpec]: - '''inlineVolumeSpec contains all the information necessary to attach a persistent volume defined by a pod's inline VolumeSource. - - This field is populated only for the CSIMigration feature. It contains translated fields from a pod's inline VolumeSource to a PersistentVolumeSpec. This field is beta-level and is only honored by servers that enabled the CSIMigration feature. - - :schema: io.k8s.api.storage.v1.VolumeAttachmentSource#inlineVolumeSpec - ''' - result = self._values.get("inline_volume_spec") - return typing.cast(typing.Optional[PersistentVolumeSpec], result) - - @builtins.property - def persistent_volume_name(self) -> typing.Optional[builtins.str]: - '''Name of the persistent volume to attach. - - :schema: io.k8s.api.storage.v1.VolumeAttachmentSource#persistentVolumeName - ''' - result = self._values.get("persistent_volume_name") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "VolumeAttachmentSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.VolumeAttachmentSpec", - jsii_struct_bases=[], - name_mapping={"attacher": "attacher", "node_name": "nodeName", "source": "source"}, -) -class VolumeAttachmentSpec: - def __init__( - self, - *, - attacher: builtins.str, - node_name: builtins.str, - source: typing.Union[VolumeAttachmentSource, typing.Dict[builtins.str, typing.Any]], - ) -> None: - '''VolumeAttachmentSpec is the specification of a VolumeAttachment request. - - :param attacher: Attacher indicates the name of the volume driver that MUST handle this request. This is the name returned by GetPluginName(). - :param node_name: The node that the volume should be attached to. - :param source: Source represents the volume that should be attached. - - :schema: io.k8s.api.storage.v1.VolumeAttachmentSpec - ''' - if isinstance(source, dict): - source = VolumeAttachmentSource(**source) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__c4b9cc875951c45fbf95df095c19992e6e0cb9bae73892b27970af014c9ef130) - check_type(argname="argument attacher", value=attacher, expected_type=type_hints["attacher"]) - check_type(argname="argument node_name", value=node_name, expected_type=type_hints["node_name"]) - check_type(argname="argument source", value=source, expected_type=type_hints["source"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "attacher": attacher, - "node_name": node_name, - "source": source, - } - - @builtins.property - def attacher(self) -> builtins.str: - '''Attacher indicates the name of the volume driver that MUST handle this request. - - This is the name returned by GetPluginName(). - - :schema: io.k8s.api.storage.v1.VolumeAttachmentSpec#attacher - ''' - result = self._values.get("attacher") - assert result is not None, "Required property 'attacher' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def node_name(self) -> builtins.str: - '''The node that the volume should be attached to. - - :schema: io.k8s.api.storage.v1.VolumeAttachmentSpec#nodeName - ''' - result = self._values.get("node_name") - assert result is not None, "Required property 'node_name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def source(self) -> VolumeAttachmentSource: - '''Source represents the volume that should be attached. - - :schema: io.k8s.api.storage.v1.VolumeAttachmentSpec#source - ''' - result = self._values.get("source") - assert result is not None, "Required property 'source' is missing" - return typing.cast(VolumeAttachmentSource, result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "VolumeAttachmentSpec(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.VolumeDevice", - jsii_struct_bases=[], - name_mapping={"device_path": "devicePath", "name": "name"}, -) -class VolumeDevice: - def __init__(self, *, device_path: builtins.str, name: builtins.str) -> None: - '''volumeDevice describes a mapping of a raw block device within a container. - - :param device_path: devicePath is the path inside of the container that the device will be mapped to. - :param name: name must match the name of a persistentVolumeClaim in the pod. - - :schema: io.k8s.api.core.v1.VolumeDevice - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__79302810697edefbd8389c6b329719eb591c59ac9f35d9046bda0be521703345) - check_type(argname="argument device_path", value=device_path, expected_type=type_hints["device_path"]) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "device_path": device_path, - "name": name, - } - - @builtins.property - def device_path(self) -> builtins.str: - '''devicePath is the path inside of the container that the device will be mapped to. - - :schema: io.k8s.api.core.v1.VolumeDevice#devicePath - ''' - result = self._values.get("device_path") - assert result is not None, "Required property 'device_path' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def name(self) -> builtins.str: - '''name must match the name of a persistentVolumeClaim in the pod. - - :schema: io.k8s.api.core.v1.VolumeDevice#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "VolumeDevice(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.VolumeMount", - jsii_struct_bases=[], - name_mapping={ - "mount_path": "mountPath", - "name": "name", - "mount_propagation": "mountPropagation", - "read_only": "readOnly", - "sub_path": "subPath", - "sub_path_expr": "subPathExpr", - }, -) -class VolumeMount: - def __init__( - self, - *, - mount_path: builtins.str, - name: builtins.str, - mount_propagation: typing.Optional[builtins.str] = None, - read_only: typing.Optional[builtins.bool] = None, - sub_path: typing.Optional[builtins.str] = None, - sub_path_expr: typing.Optional[builtins.str] = None, - ) -> None: - '''VolumeMount describes a mounting of a Volume within a container. - - :param mount_path: Path within the container at which the volume should be mounted. Must not contain ':'. - :param name: This must match the Name of a Volume. - :param mount_propagation: mountPropagation determines how mounts are propagated from the host to container and the other way around. When not set, MountPropagationNone is used. This field is beta in 1.10. - :param read_only: Mounted read-only if true, read-write otherwise (false or unspecified). Defaults to false. Default: false. - :param sub_path: Path within the volume from which the container's volume should be mounted. Defaults to "" (volume's root). Default: volume's root). - :param sub_path_expr: Expanded path within the volume from which the container's volume should be mounted. Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. Defaults to "" (volume's root). SubPathExpr and SubPath are mutually exclusive. Default: volume's root). SubPathExpr and SubPath are mutually exclusive. - - :schema: io.k8s.api.core.v1.VolumeMount - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__7bc86759e585609a7ca09f49d33b128e9d64f2504bc6d8b9cd2b329582357e17) - check_type(argname="argument mount_path", value=mount_path, expected_type=type_hints["mount_path"]) - check_type(argname="argument name", value=name, expected_type=type_hints["name"]) - check_type(argname="argument mount_propagation", value=mount_propagation, expected_type=type_hints["mount_propagation"]) - check_type(argname="argument read_only", value=read_only, expected_type=type_hints["read_only"]) - check_type(argname="argument sub_path", value=sub_path, expected_type=type_hints["sub_path"]) - check_type(argname="argument sub_path_expr", value=sub_path_expr, expected_type=type_hints["sub_path_expr"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "mount_path": mount_path, - "name": name, - } - if mount_propagation is not None: - self._values["mount_propagation"] = mount_propagation - if read_only is not None: - self._values["read_only"] = read_only - if sub_path is not None: - self._values["sub_path"] = sub_path - if sub_path_expr is not None: - self._values["sub_path_expr"] = sub_path_expr - - @builtins.property - def mount_path(self) -> builtins.str: - '''Path within the container at which the volume should be mounted. - - Must not contain ':'. - - :schema: io.k8s.api.core.v1.VolumeMount#mountPath - ''' - result = self._values.get("mount_path") - assert result is not None, "Required property 'mount_path' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def name(self) -> builtins.str: - '''This must match the Name of a Volume. - - :schema: io.k8s.api.core.v1.VolumeMount#name - ''' - result = self._values.get("name") - assert result is not None, "Required property 'name' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def mount_propagation(self) -> typing.Optional[builtins.str]: - '''mountPropagation determines how mounts are propagated from the host to container and the other way around. - - When not set, MountPropagationNone is used. This field is beta in 1.10. - - :schema: io.k8s.api.core.v1.VolumeMount#mountPropagation - ''' - result = self._values.get("mount_propagation") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def read_only(self) -> typing.Optional[builtins.bool]: - '''Mounted read-only if true, read-write otherwise (false or unspecified). - - Defaults to false. - - :default: false. - - :schema: io.k8s.api.core.v1.VolumeMount#readOnly - ''' - result = self._values.get("read_only") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def sub_path(self) -> typing.Optional[builtins.str]: - '''Path within the volume from which the container's volume should be mounted. - - Defaults to "" (volume's root). - - :default: volume's root). - - :schema: io.k8s.api.core.v1.VolumeMount#subPath - ''' - result = self._values.get("sub_path") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def sub_path_expr(self) -> typing.Optional[builtins.str]: - '''Expanded path within the volume from which the container's volume should be mounted. - - Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. Defaults to "" (volume's root). SubPathExpr and SubPath are mutually exclusive. - - :default: volume's root). SubPathExpr and SubPath are mutually exclusive. - - :schema: io.k8s.api.core.v1.VolumeMount#subPathExpr - ''' - result = self._values.get("sub_path_expr") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "VolumeMount(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.VolumeNodeAffinity", - jsii_struct_bases=[], - name_mapping={"required": "required"}, -) -class VolumeNodeAffinity: - def __init__( - self, - *, - required: typing.Optional[typing.Union[NodeSelector, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''VolumeNodeAffinity defines constraints that limit what nodes this volume can be accessed from. - - :param required: required specifies hard node constraints that must be met. - - :schema: io.k8s.api.core.v1.VolumeNodeAffinity - ''' - if isinstance(required, dict): - required = NodeSelector(**required) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__7c2f59acda00c7a6490c99644a0f6c1d5b9c7c0ca5e955d2d1c906c4defb4ade) - check_type(argname="argument required", value=required, expected_type=type_hints["required"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if required is not None: - self._values["required"] = required - - @builtins.property - def required(self) -> typing.Optional[NodeSelector]: - '''required specifies hard node constraints that must be met. - - :schema: io.k8s.api.core.v1.VolumeNodeAffinity#required - ''' - result = self._values.get("required") - return typing.cast(typing.Optional[NodeSelector], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "VolumeNodeAffinity(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.VolumeNodeResources", - jsii_struct_bases=[], - name_mapping={"count": "count"}, -) -class VolumeNodeResources: - def __init__(self, *, count: typing.Optional[jsii.Number] = None) -> None: - '''VolumeNodeResources is a set of resource limits for scheduling of volumes. - - :param count: Maximum number of unique volumes managed by the CSI driver that can be used on a node. A volume that is both attached and mounted on a node is considered to be used once, not twice. The same rule applies for a unique volume that is shared among multiple pods on the same node. If this field is not specified, then the supported number of volumes on this node is unbounded. - - :schema: io.k8s.api.storage.v1.VolumeNodeResources - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__2a5c11cd7f903e3f4b9668bb558dbf7b284d3be245138a41dc7978f947084911) - check_type(argname="argument count", value=count, expected_type=type_hints["count"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if count is not None: - self._values["count"] = count - - @builtins.property - def count(self) -> typing.Optional[jsii.Number]: - '''Maximum number of unique volumes managed by the CSI driver that can be used on a node. - - A volume that is both attached and mounted on a node is considered to be used once, not twice. The same rule applies for a unique volume that is shared among multiple pods on the same node. If this field is not specified, then the supported number of volumes on this node is unbounded. - - :schema: io.k8s.api.storage.v1.VolumeNodeResources#count - ''' - result = self._values.get("count") - return typing.cast(typing.Optional[jsii.Number], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "VolumeNodeResources(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.VolumeProjection", - jsii_struct_bases=[], - name_mapping={ - "config_map": "configMap", - "downward_api": "downwardApi", - "secret": "secret", - "service_account_token": "serviceAccountToken", - }, -) -class VolumeProjection: - def __init__( - self, - *, - config_map: typing.Optional[typing.Union[ConfigMapProjection, typing.Dict[builtins.str, typing.Any]]] = None, - downward_api: typing.Optional[typing.Union[DownwardApiProjection, typing.Dict[builtins.str, typing.Any]]] = None, - secret: typing.Optional[typing.Union[SecretProjection, typing.Dict[builtins.str, typing.Any]]] = None, - service_account_token: typing.Optional[typing.Union[ServiceAccountTokenProjection, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''Projection that may be projected along with other supported volume types. - - :param config_map: configMap information about the configMap data to project. - :param downward_api: downwardAPI information about the downwardAPI data to project. - :param secret: secret information about the secret data to project. - :param service_account_token: serviceAccountToken is information about the serviceAccountToken data to project. - - :schema: io.k8s.api.core.v1.VolumeProjection - ''' - if isinstance(config_map, dict): - config_map = ConfigMapProjection(**config_map) - if isinstance(downward_api, dict): - downward_api = DownwardApiProjection(**downward_api) - if isinstance(secret, dict): - secret = SecretProjection(**secret) - if isinstance(service_account_token, dict): - service_account_token = ServiceAccountTokenProjection(**service_account_token) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__21035918b928e2f804e2bbaaf7f50d5c4b3eb354a5e4a66e639edff79f735bfc) - check_type(argname="argument config_map", value=config_map, expected_type=type_hints["config_map"]) - check_type(argname="argument downward_api", value=downward_api, expected_type=type_hints["downward_api"]) - check_type(argname="argument secret", value=secret, expected_type=type_hints["secret"]) - check_type(argname="argument service_account_token", value=service_account_token, expected_type=type_hints["service_account_token"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if config_map is not None: - self._values["config_map"] = config_map - if downward_api is not None: - self._values["downward_api"] = downward_api - if secret is not None: - self._values["secret"] = secret - if service_account_token is not None: - self._values["service_account_token"] = service_account_token - - @builtins.property - def config_map(self) -> typing.Optional[ConfigMapProjection]: - '''configMap information about the configMap data to project. - - :schema: io.k8s.api.core.v1.VolumeProjection#configMap - ''' - result = self._values.get("config_map") - return typing.cast(typing.Optional[ConfigMapProjection], result) - - @builtins.property - def downward_api(self) -> typing.Optional[DownwardApiProjection]: - '''downwardAPI information about the downwardAPI data to project. - - :schema: io.k8s.api.core.v1.VolumeProjection#downwardAPI - ''' - result = self._values.get("downward_api") - return typing.cast(typing.Optional[DownwardApiProjection], result) - - @builtins.property - def secret(self) -> typing.Optional[SecretProjection]: - '''secret information about the secret data to project. - - :schema: io.k8s.api.core.v1.VolumeProjection#secret - ''' - result = self._values.get("secret") - return typing.cast(typing.Optional[SecretProjection], result) - - @builtins.property - def service_account_token(self) -> typing.Optional[ServiceAccountTokenProjection]: - '''serviceAccountToken is information about the serviceAccountToken data to project. - - :schema: io.k8s.api.core.v1.VolumeProjection#serviceAccountToken - ''' - result = self._values.get("service_account_token") - return typing.cast(typing.Optional[ServiceAccountTokenProjection], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "VolumeProjection(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.VsphereVirtualDiskVolumeSource", - jsii_struct_bases=[], - name_mapping={ - "volume_path": "volumePath", - "fs_type": "fsType", - "storage_policy_id": "storagePolicyId", - "storage_policy_name": "storagePolicyName", - }, -) -class VsphereVirtualDiskVolumeSource: - def __init__( - self, - *, - volume_path: builtins.str, - fs_type: typing.Optional[builtins.str] = None, - storage_policy_id: typing.Optional[builtins.str] = None, - storage_policy_name: typing.Optional[builtins.str] = None, - ) -> None: - '''Represents a vSphere volume resource. - - :param volume_path: volumePath is the path that identifies vSphere volume vmdk. - :param fs_type: fsType is filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - :param storage_policy_id: storagePolicyID is the storage Policy Based Management (SPBM) profile ID associated with the StoragePolicyName. - :param storage_policy_name: storagePolicyName is the storage Policy Based Management (SPBM) profile name. - - :schema: io.k8s.api.core.v1.VsphereVirtualDiskVolumeSource - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__2746f4a6c4d559e6cea852caa195b0acdbccb5fcc65b72211461db64e954a2e0) - check_type(argname="argument volume_path", value=volume_path, expected_type=type_hints["volume_path"]) - check_type(argname="argument fs_type", value=fs_type, expected_type=type_hints["fs_type"]) - check_type(argname="argument storage_policy_id", value=storage_policy_id, expected_type=type_hints["storage_policy_id"]) - check_type(argname="argument storage_policy_name", value=storage_policy_name, expected_type=type_hints["storage_policy_name"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "volume_path": volume_path, - } - if fs_type is not None: - self._values["fs_type"] = fs_type - if storage_policy_id is not None: - self._values["storage_policy_id"] = storage_policy_id - if storage_policy_name is not None: - self._values["storage_policy_name"] = storage_policy_name - - @builtins.property - def volume_path(self) -> builtins.str: - '''volumePath is the path that identifies vSphere volume vmdk. - - :schema: io.k8s.api.core.v1.VsphereVirtualDiskVolumeSource#volumePath - ''' - result = self._values.get("volume_path") - assert result is not None, "Required property 'volume_path' is missing" - return typing.cast(builtins.str, result) - - @builtins.property - def fs_type(self) -> typing.Optional[builtins.str]: - '''fsType is filesystem type to mount. - - Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - - :schema: io.k8s.api.core.v1.VsphereVirtualDiskVolumeSource#fsType - ''' - result = self._values.get("fs_type") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def storage_policy_id(self) -> typing.Optional[builtins.str]: - '''storagePolicyID is the storage Policy Based Management (SPBM) profile ID associated with the StoragePolicyName. - - :schema: io.k8s.api.core.v1.VsphereVirtualDiskVolumeSource#storagePolicyID - ''' - result = self._values.get("storage_policy_id") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def storage_policy_name(self) -> typing.Optional[builtins.str]: - '''storagePolicyName is the storage Policy Based Management (SPBM) profile name. - - :schema: io.k8s.api.core.v1.VsphereVirtualDiskVolumeSource#storagePolicyName - ''' - result = self._values.get("storage_policy_name") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "VsphereVirtualDiskVolumeSource(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.WebhookClientConfig", - jsii_struct_bases=[], - name_mapping={"ca_bundle": "caBundle", "service": "service", "url": "url"}, -) -class WebhookClientConfig: - def __init__( - self, - *, - ca_bundle: typing.Optional[builtins.str] = None, - service: typing.Optional[typing.Union[ServiceReference, typing.Dict[builtins.str, typing.Any]]] = None, - url: typing.Optional[builtins.str] = None, - ) -> None: - '''WebhookClientConfig contains the information to make a TLS connection with the webhook. - - :param ca_bundle: ``caBundle`` is a PEM encoded CA bundle which will be used to validate the webhook's server certificate. If unspecified, system trust roots on the apiserver are used. - :param service: ``service`` is a reference to the service for this webhook. Either ``service`` or ``url`` must be specified. If the webhook is running within the cluster, then you should use ``service``. - :param url: ``url`` gives the location of the webhook, in standard URL form (``scheme://host:port/path``). Exactly one of ``url`` or ``service`` must be specified. The ``host`` should not refer to a service running in the cluster; use the ``service`` field instead. The host might be resolved via external DNS in some apiservers (e.g., ``kube-apiserver`` cannot resolve in-cluster DNS as that would be a layering violation). ``host`` may also be an IP address. Please note that using ``localhost`` or ``127.0.0.1`` as a ``host`` is risky unless you take great care to run this webhook on all hosts which run an apiserver which might need to make calls to this webhook. Such installs are likely to be non-portable, i.e., not easy to turn up in a new cluster. The scheme must be "https"; the URL must begin with "https://". A path is optional, and if present may be any string permissible in a URL. You may use the path to pass an arbitrary string to the webhook, for example, a cluster identifier. Attempting to use a user or basic auth e.g. "user:password@" is not allowed. Fragments ("#...") and query parameters ("?...") are not allowed, either. - - :schema: io.k8s.api.admissionregistration.v1.WebhookClientConfig - ''' - if isinstance(service, dict): - service = ServiceReference(**service) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__01a4d6ecbc5d3180d6159e848cb27db4b9411ca07eae56bb4a7c0ea53622d2a9) - check_type(argname="argument ca_bundle", value=ca_bundle, expected_type=type_hints["ca_bundle"]) - check_type(argname="argument service", value=service, expected_type=type_hints["service"]) - check_type(argname="argument url", value=url, expected_type=type_hints["url"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if ca_bundle is not None: - self._values["ca_bundle"] = ca_bundle - if service is not None: - self._values["service"] = service - if url is not None: - self._values["url"] = url - - @builtins.property - def ca_bundle(self) -> typing.Optional[builtins.str]: - '''``caBundle`` is a PEM encoded CA bundle which will be used to validate the webhook's server certificate. - - If unspecified, system trust roots on the apiserver are used. - - :schema: io.k8s.api.admissionregistration.v1.WebhookClientConfig#caBundle - ''' - result = self._values.get("ca_bundle") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def service(self) -> typing.Optional[ServiceReference]: - '''``service`` is a reference to the service for this webhook. Either ``service`` or ``url`` must be specified. - - If the webhook is running within the cluster, then you should use ``service``. - - :schema: io.k8s.api.admissionregistration.v1.WebhookClientConfig#service - ''' - result = self._values.get("service") - return typing.cast(typing.Optional[ServiceReference], result) - - @builtins.property - def url(self) -> typing.Optional[builtins.str]: - '''``url`` gives the location of the webhook, in standard URL form (``scheme://host:port/path``). - - Exactly one of ``url`` or ``service`` must be specified. - - The ``host`` should not refer to a service running in the cluster; use the ``service`` field instead. The host might be resolved via external DNS in some apiservers (e.g., ``kube-apiserver`` cannot resolve in-cluster DNS as that would be a layering violation). ``host`` may also be an IP address. - - Please note that using ``localhost`` or ``127.0.0.1`` as a ``host`` is risky unless you take great care to run this webhook on all hosts which run an apiserver which might need to make calls to this webhook. Such installs are likely to be non-portable, i.e., not easy to turn up in a new cluster. - - The scheme must be "https"; the URL must begin with "https://". - - A path is optional, and if present may be any string permissible in a URL. You may use the path to pass an arbitrary string to the webhook, for example, a cluster identifier. - - Attempting to use a user or basic auth e.g. "user:password@" is not allowed. Fragments ("#...") and query parameters ("?...") are not allowed, either. - - :schema: io.k8s.api.admissionregistration.v1.WebhookClientConfig#url - ''' - result = self._values.get("url") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "WebhookClientConfig(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.WebhookConversion", - jsii_struct_bases=[], - name_mapping={ - "conversion_review_versions": "conversionReviewVersions", - "client_config": "clientConfig", - }, -) -class WebhookConversion: - def __init__( - self, - *, - conversion_review_versions: typing.Sequence[builtins.str], - client_config: typing.Optional[typing.Union[WebhookClientConfig, typing.Dict[builtins.str, typing.Any]]] = None, - ) -> None: - '''WebhookConversion describes how to call a conversion webhook. - - :param conversion_review_versions: conversionReviewVersions is an ordered list of preferred ``ConversionReview`` versions the Webhook expects. The API server will use the first version in the list which it supports. If none of the versions specified in this list are supported by API server, conversion will fail for the custom resource. If a persisted Webhook configuration specifies allowed versions and does not include any versions known to the API Server, calls to the webhook will fail. - :param client_config: clientConfig is the instructions for how to call the webhook if strategy is ``Webhook``. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.WebhookConversion - ''' - if isinstance(client_config, dict): - client_config = WebhookClientConfig(**client_config) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__39d792294d4b2186ea27ff788c8be1ec22d2503757195afb3bd815d2f0d57bdf) - check_type(argname="argument conversion_review_versions", value=conversion_review_versions, expected_type=type_hints["conversion_review_versions"]) - check_type(argname="argument client_config", value=client_config, expected_type=type_hints["client_config"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "conversion_review_versions": conversion_review_versions, - } - if client_config is not None: - self._values["client_config"] = client_config - - @builtins.property - def conversion_review_versions(self) -> typing.List[builtins.str]: - '''conversionReviewVersions is an ordered list of preferred ``ConversionReview`` versions the Webhook expects. - - The API server will use the first version in the list which it supports. If none of the versions specified in this list are supported by API server, conversion will fail for the custom resource. If a persisted Webhook configuration specifies allowed versions and does not include any versions known to the API Server, calls to the webhook will fail. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.WebhookConversion#conversionReviewVersions - ''' - result = self._values.get("conversion_review_versions") - assert result is not None, "Required property 'conversion_review_versions' is missing" - return typing.cast(typing.List[builtins.str], result) - - @builtins.property - def client_config(self) -> typing.Optional[WebhookClientConfig]: - '''clientConfig is the instructions for how to call the webhook if strategy is ``Webhook``. - - :schema: io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.WebhookConversion#clientConfig - ''' - result = self._values.get("client_config") - return typing.cast(typing.Optional[WebhookClientConfig], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "WebhookConversion(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.WeightedPodAffinityTerm", - jsii_struct_bases=[], - name_mapping={"pod_affinity_term": "podAffinityTerm", "weight": "weight"}, -) -class WeightedPodAffinityTerm: - def __init__( - self, - *, - pod_affinity_term: typing.Union[PodAffinityTerm, typing.Dict[builtins.str, typing.Any]], - weight: jsii.Number, - ) -> None: - '''The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s). - - :param pod_affinity_term: Required. A pod affinity term, associated with the corresponding weight. - :param weight: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. - - :schema: io.k8s.api.core.v1.WeightedPodAffinityTerm - ''' - if isinstance(pod_affinity_term, dict): - pod_affinity_term = PodAffinityTerm(**pod_affinity_term) - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__889aca33f8b0538629ceed10073db78bcf15ce67a8d28c641286fa3ca92dd955) - check_type(argname="argument pod_affinity_term", value=pod_affinity_term, expected_type=type_hints["pod_affinity_term"]) - check_type(argname="argument weight", value=weight, expected_type=type_hints["weight"]) - self._values: typing.Dict[builtins.str, typing.Any] = { - "pod_affinity_term": pod_affinity_term, - "weight": weight, - } - - @builtins.property - def pod_affinity_term(self) -> PodAffinityTerm: - '''Required. - - A pod affinity term, associated with the corresponding weight. - - :schema: io.k8s.api.core.v1.WeightedPodAffinityTerm#podAffinityTerm - ''' - result = self._values.get("pod_affinity_term") - assert result is not None, "Required property 'pod_affinity_term' is missing" - return typing.cast(PodAffinityTerm, result) - - @builtins.property - def weight(self) -> jsii.Number: - '''weight associated with matching the corresponding podAffinityTerm, in the range 1-100. - - :schema: io.k8s.api.core.v1.WeightedPodAffinityTerm#weight - ''' - result = self._values.get("weight") - assert result is not None, "Required property 'weight' is missing" - return typing.cast(jsii.Number, result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "WeightedPodAffinityTerm(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -@jsii.data_type( - jsii_type="k8s.WindowsSecurityContextOptions", - jsii_struct_bases=[], - name_mapping={ - "gmsa_credential_spec": "gmsaCredentialSpec", - "gmsa_credential_spec_name": "gmsaCredentialSpecName", - "host_process": "hostProcess", - "run_as_user_name": "runAsUserName", - }, -) -class WindowsSecurityContextOptions: - def __init__( - self, - *, - gmsa_credential_spec: typing.Optional[builtins.str] = None, - gmsa_credential_spec_name: typing.Optional[builtins.str] = None, - host_process: typing.Optional[builtins.bool] = None, - run_as_user_name: typing.Optional[builtins.str] = None, - ) -> None: - '''WindowsSecurityContextOptions contain Windows-specific options and credentials. - - :param gmsa_credential_spec: GMSACredentialSpec is where the GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the GMSA credential spec named by the GMSACredentialSpecName field. - :param gmsa_credential_spec_name: GMSACredentialSpecName is the name of the GMSA credential spec to use. - :param host_process: HostProcess determines if a container should be run as a 'Host Process' container. This field is alpha-level and will only be honored by components that enable the WindowsHostProcessContainers feature flag. Setting this field without the feature flag will result in errors when validating the Pod. All of a Pod's containers must have the same effective HostProcess value (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). In addition, if HostProcess is true then HostNetwork must also be set to true. - :param run_as_user_name: The UserName in Windows to run the entrypoint of the container process. Defaults to the user specified in image metadata if unspecified. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. Default: the user specified in image metadata if unspecified. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. - - :schema: io.k8s.api.core.v1.WindowsSecurityContextOptions - ''' - if __debug__: - type_hints = typing.get_type_hints(_typecheckingstub__8f8f55e98c07892c190b8b23ad570c48466b356f369032020c69a96f2ea2d0ea) - check_type(argname="argument gmsa_credential_spec", value=gmsa_credential_spec, expected_type=type_hints["gmsa_credential_spec"]) - check_type(argname="argument gmsa_credential_spec_name", value=gmsa_credential_spec_name, expected_type=type_hints["gmsa_credential_spec_name"]) - check_type(argname="argument host_process", value=host_process, expected_type=type_hints["host_process"]) - check_type(argname="argument run_as_user_name", value=run_as_user_name, expected_type=type_hints["run_as_user_name"]) - self._values: typing.Dict[builtins.str, typing.Any] = {} - if gmsa_credential_spec is not None: - self._values["gmsa_credential_spec"] = gmsa_credential_spec - if gmsa_credential_spec_name is not None: - self._values["gmsa_credential_spec_name"] = gmsa_credential_spec_name - if host_process is not None: - self._values["host_process"] = host_process - if run_as_user_name is not None: - self._values["run_as_user_name"] = run_as_user_name - - @builtins.property - def gmsa_credential_spec(self) -> typing.Optional[builtins.str]: - '''GMSACredentialSpec is where the GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the GMSA credential spec named by the GMSACredentialSpecName field. - - :schema: io.k8s.api.core.v1.WindowsSecurityContextOptions#gmsaCredentialSpec - ''' - result = self._values.get("gmsa_credential_spec") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def gmsa_credential_spec_name(self) -> typing.Optional[builtins.str]: - '''GMSACredentialSpecName is the name of the GMSA credential spec to use. - - :schema: io.k8s.api.core.v1.WindowsSecurityContextOptions#gmsaCredentialSpecName - ''' - result = self._values.get("gmsa_credential_spec_name") - return typing.cast(typing.Optional[builtins.str], result) - - @builtins.property - def host_process(self) -> typing.Optional[builtins.bool]: - '''HostProcess determines if a container should be run as a 'Host Process' container. - - This field is alpha-level and will only be honored by components that enable the WindowsHostProcessContainers feature flag. Setting this field without the feature flag will result in errors when validating the Pod. All of a Pod's containers must have the same effective HostProcess value (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). In addition, if HostProcess is true then HostNetwork must also be set to true. - - :schema: io.k8s.api.core.v1.WindowsSecurityContextOptions#hostProcess - ''' - result = self._values.get("host_process") - return typing.cast(typing.Optional[builtins.bool], result) - - @builtins.property - def run_as_user_name(self) -> typing.Optional[builtins.str]: - '''The UserName in Windows to run the entrypoint of the container process. - - Defaults to the user specified in image metadata if unspecified. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. - - :default: the user specified in image metadata if unspecified. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. - - :schema: io.k8s.api.core.v1.WindowsSecurityContextOptions#runAsUserName - ''' - result = self._values.get("run_as_user_name") - return typing.cast(typing.Optional[builtins.str], result) - - def __eq__(self, rhs: typing.Any) -> builtins.bool: - return isinstance(rhs, self.__class__) and rhs._values == self._values - - def __ne__(self, rhs: typing.Any) -> builtins.bool: - return not (rhs == self) - - def __repr__(self) -> str: - return "WindowsSecurityContextOptions(%s)" % ", ".join( - k + "=" + repr(v) for k, v in self._values.items() - ) - - -__all__ = [ - "Affinity", - "AggregationRule", - "ApiServiceSpec", - "AwsElasticBlockStoreVolumeSource", - "AzureDiskVolumeSource", - "AzureFilePersistentVolumeSource", - "AzureFileVolumeSource", - "BoundObjectReference", - "Capabilities", - "CephFsPersistentVolumeSource", - "CephFsVolumeSource", - "CertificateSigningRequestSpec", - "CinderPersistentVolumeSource", - "CinderVolumeSource", - "ClaimSource", - "ClientIpConfig", - "ClusterCidrSpecV1Alpha1", - "ComponentCondition", - "ConfigMapEnvSource", - "ConfigMapKeySelector", - "ConfigMapNodeConfigSource", - "ConfigMapProjection", - "ConfigMapVolumeSource", - "Container", - "ContainerPort", - "ContainerResourceMetricSourceV2", - "CronJobSpec", - "CrossVersionObjectReference", - "CrossVersionObjectReferenceV2", - "CsiDriverSpec", - "CsiNodeDriver", - "CsiNodeSpec", - "CsiPersistentVolumeSource", - "CsiVolumeSource", - "CustomResourceColumnDefinition", - "CustomResourceConversion", - "CustomResourceDefinitionNames", - "CustomResourceDefinitionSpec", - "CustomResourceDefinitionVersion", - "CustomResourceSubresourceScale", - "CustomResourceSubresources", - "CustomResourceValidation", - "DaemonSetSpec", - "DaemonSetUpdateStrategy", - "DeleteOptions", - "DeploymentSpec", - "DeploymentStrategy", - "DownwardApiProjection", - "DownwardApiVolumeFile", - "DownwardApiVolumeSource", - "EmptyDirVolumeSource", - "Endpoint", - "EndpointAddress", - "EndpointConditions", - "EndpointHints", - "EndpointPort", - "EndpointSubset", - "EnvFromSource", - "EnvVar", - "EnvVarSource", - "EphemeralContainer", - "EphemeralVolumeSource", - "EventSeries", - "EventSource", - "ExecAction", - "ExternalDocumentation", - "ExternalMetricSourceV2", - "FcVolumeSource", - "FlexPersistentVolumeSource", - "FlexVolumeSource", - "FlockerVolumeSource", - "FlowDistinguisherMethodV1Beta2", - "FlowDistinguisherMethodV1Beta3", - "FlowSchemaSpecV1Beta2", - "FlowSchemaSpecV1Beta3", - "ForZone", - "GcePersistentDiskVolumeSource", - "GitRepoVolumeSource", - "GlusterfsPersistentVolumeSource", - "GlusterfsVolumeSource", - "GroupSubjectV1Beta2", - "GroupSubjectV1Beta3", - "GrpcAction", - "HorizontalPodAutoscalerBehaviorV2", - "HorizontalPodAutoscalerSpec", - "HorizontalPodAutoscalerSpecV2", - "HostAlias", - "HostPathVolumeSource", - "HpaScalingPolicyV2", - "HpaScalingRulesV2", - "HttpGetAction", - "HttpHeader", - "HttpIngressPath", - "HttpIngressRuleValue", - "IngressBackend", - "IngressClassParametersReference", - "IngressClassSpec", - "IngressRule", - "IngressServiceBackend", - "IngressSpec", - "IngressTls", - "IntOrString", - "IoK8SApimachineryPkgApisMetaV1DeleteOptionsKind", - "IpBlock", - "IscsiPersistentVolumeSource", - "IscsiVolumeSource", - "JobSpec", - "JobTemplateSpec", - "JsonSchemaProps", - "KeyToPath", - "KubeApiService", - "KubeApiServiceList", - "KubeApiServiceListProps", - "KubeApiServiceProps", - "KubeBinding", - "KubeBindingProps", - "KubeCertificateSigningRequest", - "KubeCertificateSigningRequestList", - "KubeCertificateSigningRequestListProps", - "KubeCertificateSigningRequestProps", - "KubeClusterCidrListV1Alpha1", - "KubeClusterCidrListV1Alpha1Props", - "KubeClusterCidrv1Alpha1", - "KubeClusterCidrv1Alpha1Props", - "KubeClusterRole", - "KubeClusterRoleBinding", - "KubeClusterRoleBindingList", - "KubeClusterRoleBindingListProps", - "KubeClusterRoleBindingProps", - "KubeClusterRoleList", - "KubeClusterRoleListProps", - "KubeClusterRoleProps", - "KubeComponentStatus", - "KubeComponentStatusList", - "KubeComponentStatusListProps", - "KubeComponentStatusProps", - "KubeConfigMap", - "KubeConfigMapList", - "KubeConfigMapListProps", - "KubeConfigMapProps", - "KubeControllerRevision", - "KubeControllerRevisionList", - "KubeControllerRevisionListProps", - "KubeControllerRevisionProps", - "KubeCronJob", - "KubeCronJobList", - "KubeCronJobListProps", - "KubeCronJobProps", - "KubeCsiDriver", - "KubeCsiDriverList", - "KubeCsiDriverListProps", - "KubeCsiDriverProps", - "KubeCsiNode", - "KubeCsiNodeList", - "KubeCsiNodeListProps", - "KubeCsiNodeProps", - "KubeCsiStorageCapacity", - "KubeCsiStorageCapacityList", - "KubeCsiStorageCapacityListProps", - "KubeCsiStorageCapacityListV1Beta1", - "KubeCsiStorageCapacityListV1Beta1Props", - "KubeCsiStorageCapacityProps", - "KubeCsiStorageCapacityV1Beta1", - "KubeCsiStorageCapacityV1Beta1Props", - "KubeCustomResourceDefinition", - "KubeCustomResourceDefinitionList", - "KubeCustomResourceDefinitionListProps", - "KubeCustomResourceDefinitionProps", - "KubeDaemonSet", - "KubeDaemonSetList", - "KubeDaemonSetListProps", - "KubeDaemonSetProps", - "KubeDeployment", - "KubeDeploymentList", - "KubeDeploymentListProps", - "KubeDeploymentProps", - "KubeEndpointSlice", - "KubeEndpointSliceList", - "KubeEndpointSliceListProps", - "KubeEndpointSliceProps", - "KubeEndpoints", - "KubeEndpointsList", - "KubeEndpointsListProps", - "KubeEndpointsProps", - "KubeEvent", - "KubeEventList", - "KubeEventListProps", - "KubeEventProps", - "KubeEviction", - "KubeEvictionProps", - "KubeFlowSchemaListV1Beta2", - "KubeFlowSchemaListV1Beta2Props", - "KubeFlowSchemaListV1Beta3", - "KubeFlowSchemaListV1Beta3Props", - "KubeFlowSchemaV1Beta2", - "KubeFlowSchemaV1Beta2Props", - "KubeFlowSchemaV1Beta3", - "KubeFlowSchemaV1Beta3Props", - "KubeHorizontalPodAutoscaler", - "KubeHorizontalPodAutoscalerList", - "KubeHorizontalPodAutoscalerListProps", - "KubeHorizontalPodAutoscalerListV2", - "KubeHorizontalPodAutoscalerListV2Props", - "KubeHorizontalPodAutoscalerProps", - "KubeHorizontalPodAutoscalerV2", - "KubeHorizontalPodAutoscalerV2Props", - "KubeIngress", - "KubeIngressClass", - "KubeIngressClassList", - "KubeIngressClassListProps", - "KubeIngressClassProps", - "KubeIngressList", - "KubeIngressListProps", - "KubeIngressProps", - "KubeJob", - "KubeJobList", - "KubeJobListProps", - "KubeJobProps", - "KubeLease", - "KubeLeaseList", - "KubeLeaseListProps", - "KubeLeaseProps", - "KubeLimitRange", - "KubeLimitRangeList", - "KubeLimitRangeListProps", - "KubeLimitRangeProps", - "KubeLocalSubjectAccessReview", - "KubeLocalSubjectAccessReviewProps", - "KubeMutatingWebhookConfiguration", - "KubeMutatingWebhookConfigurationList", - "KubeMutatingWebhookConfigurationListProps", - "KubeMutatingWebhookConfigurationProps", - "KubeNamespace", - "KubeNamespaceList", - "KubeNamespaceListProps", - "KubeNamespaceProps", - "KubeNetworkPolicy", - "KubeNetworkPolicyList", - "KubeNetworkPolicyListProps", - "KubeNetworkPolicyProps", - "KubeNode", - "KubeNodeList", - "KubeNodeListProps", - "KubeNodeProps", - "KubePersistentVolume", - "KubePersistentVolumeClaim", - "KubePersistentVolumeClaimList", - "KubePersistentVolumeClaimListProps", - "KubePersistentVolumeClaimProps", - "KubePersistentVolumeList", - "KubePersistentVolumeListProps", - "KubePersistentVolumeProps", - "KubePod", - "KubePodDisruptionBudget", - "KubePodDisruptionBudgetList", - "KubePodDisruptionBudgetListProps", - "KubePodDisruptionBudgetProps", - "KubePodList", - "KubePodListProps", - "KubePodProps", - "KubePodSchedulingListV1Alpha1", - "KubePodSchedulingListV1Alpha1Props", - "KubePodSchedulingV1Alpha1", - "KubePodSchedulingV1Alpha1Props", - "KubePodTemplate", - "KubePodTemplateList", - "KubePodTemplateListProps", - "KubePodTemplateProps", - "KubePriorityClass", - "KubePriorityClassList", - "KubePriorityClassListProps", - "KubePriorityClassProps", - "KubePriorityLevelConfigurationListV1Beta2", - "KubePriorityLevelConfigurationListV1Beta2Props", - "KubePriorityLevelConfigurationListV1Beta3", - "KubePriorityLevelConfigurationListV1Beta3Props", - "KubePriorityLevelConfigurationV1Beta2", - "KubePriorityLevelConfigurationV1Beta2Props", - "KubePriorityLevelConfigurationV1Beta3", - "KubePriorityLevelConfigurationV1Beta3Props", - "KubeReplicaSet", - "KubeReplicaSetList", - "KubeReplicaSetListProps", - "KubeReplicaSetProps", - "KubeReplicationController", - "KubeReplicationControllerList", - "KubeReplicationControllerListProps", - "KubeReplicationControllerProps", - "KubeResourceClaimListV1Alpha1", - "KubeResourceClaimListV1Alpha1Props", - "KubeResourceClaimTemplateListV1Alpha1", - "KubeResourceClaimTemplateListV1Alpha1Props", - "KubeResourceClaimTemplateV1Alpha1", - "KubeResourceClaimTemplateV1Alpha1Props", - "KubeResourceClaimV1Alpha1", - "KubeResourceClaimV1Alpha1Props", - "KubeResourceClassListV1Alpha1", - "KubeResourceClassListV1Alpha1Props", - "KubeResourceClassV1Alpha1", - "KubeResourceClassV1Alpha1Props", - "KubeResourceQuota", - "KubeResourceQuotaList", - "KubeResourceQuotaListProps", - "KubeResourceQuotaProps", - "KubeRole", - "KubeRoleBinding", - "KubeRoleBindingList", - "KubeRoleBindingListProps", - "KubeRoleBindingProps", - "KubeRoleList", - "KubeRoleListProps", - "KubeRoleProps", - "KubeRuntimeClass", - "KubeRuntimeClassList", - "KubeRuntimeClassListProps", - "KubeRuntimeClassProps", - "KubeScale", - "KubeScaleProps", - "KubeSecret", - "KubeSecretList", - "KubeSecretListProps", - "KubeSecretProps", - "KubeSelfSubjectAccessReview", - "KubeSelfSubjectAccessReviewProps", - "KubeSelfSubjectReviewV1Alpha1", - "KubeSelfSubjectReviewV1Alpha1Props", - "KubeSelfSubjectRulesReview", - "KubeSelfSubjectRulesReviewProps", - "KubeService", - "KubeServiceAccount", - "KubeServiceAccountList", - "KubeServiceAccountListProps", - "KubeServiceAccountProps", - "KubeServiceList", - "KubeServiceListProps", - "KubeServiceProps", - "KubeStatefulSet", - "KubeStatefulSetList", - "KubeStatefulSetListProps", - "KubeStatefulSetProps", - "KubeStatus", - "KubeStatusProps", - "KubeStorageClass", - "KubeStorageClassList", - "KubeStorageClassListProps", - "KubeStorageClassProps", - "KubeStorageVersionListV1Alpha1", - "KubeStorageVersionListV1Alpha1Props", - "KubeStorageVersionV1Alpha1", - "KubeStorageVersionV1Alpha1Props", - "KubeSubjectAccessReview", - "KubeSubjectAccessReviewProps", - "KubeTokenRequest", - "KubeTokenRequestProps", - "KubeTokenReview", - "KubeTokenReviewProps", - "KubeValidatingAdmissionPolicyBindingListV1Alpha1", - "KubeValidatingAdmissionPolicyBindingListV1Alpha1Props", - "KubeValidatingAdmissionPolicyBindingV1Alpha1", - "KubeValidatingAdmissionPolicyBindingV1Alpha1Props", - "KubeValidatingAdmissionPolicyListV1Alpha1", - "KubeValidatingAdmissionPolicyListV1Alpha1Props", - "KubeValidatingAdmissionPolicyV1Alpha1", - "KubeValidatingAdmissionPolicyV1Alpha1Props", - "KubeValidatingWebhookConfiguration", - "KubeValidatingWebhookConfigurationList", - "KubeValidatingWebhookConfigurationListProps", - "KubeValidatingWebhookConfigurationProps", - "KubeVolumeAttachment", - "KubeVolumeAttachmentList", - "KubeVolumeAttachmentListProps", - "KubeVolumeAttachmentProps", - "LabelSelector", - "LabelSelectorRequirement", - "LeaseSpec", - "Lifecycle", - "LifecycleHandler", - "LimitRangeItem", - "LimitRangeSpec", - "LimitResponseV1Beta2", - "LimitResponseV1Beta3", - "LimitedPriorityLevelConfigurationV1Beta2", - "LimitedPriorityLevelConfigurationV1Beta3", - "ListMeta", - "LocalObjectReference", - "LocalVolumeSource", - "ManagedFieldsEntry", - "MatchResourcesV1Alpha1", - "MetricIdentifierV2", - "MetricSpecV2", - "MetricTargetV2", - "MutatingWebhook", - "NamedRuleWithOperationsV1Alpha1", - "NamespaceSpec", - "NetworkPolicyEgressRule", - "NetworkPolicyIngressRule", - "NetworkPolicyPeer", - "NetworkPolicyPort", - "NetworkPolicySpec", - "NfsVolumeSource", - "NodeAffinity", - "NodeConfigSource", - "NodeSelector", - "NodeSelectorRequirement", - "NodeSelectorTerm", - "NodeSpec", - "NonResourceAttributes", - "NonResourcePolicyRuleV1Beta2", - "NonResourcePolicyRuleV1Beta3", - "ObjectFieldSelector", - "ObjectMeta", - "ObjectMetricSourceV2", - "ObjectReference", - "Overhead", - "OwnerReference", - "ParamKindV1Alpha1", - "ParamRefV1Alpha1", - "PersistentVolumeClaimSpec", - "PersistentVolumeClaimTemplate", - "PersistentVolumeClaimVolumeSource", - "PersistentVolumeSpec", - "PhotonPersistentDiskVolumeSource", - "PodAffinity", - "PodAffinityTerm", - "PodAntiAffinity", - "PodDisruptionBudgetSpec", - "PodDnsConfig", - "PodDnsConfigOption", - "PodFailurePolicy", - "PodFailurePolicyOnExitCodesRequirement", - "PodFailurePolicyOnPodConditionsPattern", - "PodFailurePolicyRule", - "PodOs", - "PodReadinessGate", - "PodResourceClaim", - "PodSchedulingGate", - "PodSchedulingSpecV1Alpha1", - "PodSecurityContext", - "PodSpec", - "PodTemplateSpec", - "PodsMetricSourceV2", - "PolicyRule", - "PolicyRulesWithSubjectsV1Beta2", - "PolicyRulesWithSubjectsV1Beta3", - "PortworxVolumeSource", - "Preconditions", - "PreferredSchedulingTerm", - "PriorityLevelConfigurationReferenceV1Beta2", - "PriorityLevelConfigurationReferenceV1Beta3", - "PriorityLevelConfigurationSpecV1Beta2", - "PriorityLevelConfigurationSpecV1Beta3", - "Probe", - "ProjectedVolumeSource", - "Quantity", - "QueuingConfigurationV1Beta2", - "QueuingConfigurationV1Beta3", - "QuobyteVolumeSource", - "RbdPersistentVolumeSource", - "RbdVolumeSource", - "ReplicaSetSpec", - "ReplicationControllerSpec", - "ResourceAttributes", - "ResourceClaim", - "ResourceClaimParametersReferenceV1Alpha1", - "ResourceClaimSpecV1Alpha1", - "ResourceClaimTemplateSpecV1Alpha1", - "ResourceClassParametersReferenceV1Alpha1", - "ResourceFieldSelector", - "ResourceMetricSourceV2", - "ResourcePolicyRuleV1Beta2", - "ResourcePolicyRuleV1Beta3", - "ResourceQuotaSpec", - "ResourceRequirements", - "RoleRef", - "RollingUpdateDaemonSet", - "RollingUpdateDeployment", - "RollingUpdateStatefulSetStrategy", - "RuleWithOperations", - "ScaleIoPersistentVolumeSource", - "ScaleIoVolumeSource", - "ScaleSpec", - "Scheduling", - "ScopeSelector", - "ScopedResourceSelectorRequirement", - "SeLinuxOptions", - "SeccompProfile", - "SecretEnvSource", - "SecretKeySelector", - "SecretProjection", - "SecretReference", - "SecretVolumeSource", - "SecurityContext", - "SelfSubjectAccessReviewSpec", - "SelfSubjectRulesReviewSpec", - "ServiceAccountSubjectV1Beta2", - "ServiceAccountSubjectV1Beta3", - "ServiceAccountTokenProjection", - "ServiceBackendPort", - "ServicePort", - "ServiceReference", - "ServiceSpec", - "SessionAffinityConfig", - "StatefulSetOrdinals", - "StatefulSetPersistentVolumeClaimRetentionPolicy", - "StatefulSetSpec", - "StatefulSetUpdateStrategy", - "StatusCause", - "StatusDetails", - "StorageOsPersistentVolumeSource", - "StorageOsVolumeSource", - "Subject", - "SubjectAccessReviewSpec", - "SubjectV1Beta2", - "SubjectV1Beta3", - "Sysctl", - "Taint", - "TcpSocketAction", - "TokenRequest", - "TokenRequestSpec", - "TokenReviewSpec", - "Toleration", - "TopologySelectorLabelRequirement", - "TopologySelectorTerm", - "TopologySpreadConstraint", - "TypedLocalObjectReference", - "TypedObjectReference", - "UserSubjectV1Beta2", - "UserSubjectV1Beta3", - "ValidatingAdmissionPolicyBindingSpecV1Alpha1", - "ValidatingAdmissionPolicySpecV1Alpha1", - "ValidatingWebhook", - "ValidationRule", - "ValidationV1Alpha1", - "Volume", - "VolumeAttachmentSource", - "VolumeAttachmentSpec", - "VolumeDevice", - "VolumeMount", - "VolumeNodeAffinity", - "VolumeNodeResources", - "VolumeProjection", - "VsphereVirtualDiskVolumeSource", - "WebhookClientConfig", - "WebhookConversion", - "WeightedPodAffinityTerm", - "WindowsSecurityContextOptions", -] - -publication.publish() - -def _typecheckingstub__b0b5f1aeea5be7ebc9dd226948240c3fe007bf069ec377c716b2c8df75f266a9( - *, - node_affinity: typing.Optional[typing.Union[NodeAffinity, typing.Dict[builtins.str, typing.Any]]] = None, - pod_affinity: typing.Optional[typing.Union[PodAffinity, typing.Dict[builtins.str, typing.Any]]] = None, - pod_anti_affinity: typing.Optional[typing.Union[PodAntiAffinity, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__c6abea0d97901d2b42508f6bafd4b7f3b8e99dae1eb38751770090a223a1158b( - *, - cluster_role_selectors: typing.Optional[typing.Sequence[typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__f218ab0fc666c93118e68a7a785bfe54888e33ebd68f9d3998ddac4e96d4a04d( - *, - group_priority_minimum: jsii.Number, - version_priority: jsii.Number, - ca_bundle: typing.Optional[builtins.str] = None, - group: typing.Optional[builtins.str] = None, - insecure_skip_tls_verify: typing.Optional[builtins.bool] = None, - service: typing.Optional[typing.Union[ServiceReference, typing.Dict[builtins.str, typing.Any]]] = None, - version: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__cfdcc8025d63ab999a257c0732b1137f522923a572bda91f7ca61de5c1afd6ec( - *, - volume_id: builtins.str, - fs_type: typing.Optional[builtins.str] = None, - partition: typing.Optional[jsii.Number] = None, - read_only: typing.Optional[builtins.bool] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__42545c3f07626c9bf98c297356705624406f44b3ada49253cfa8b75145c9636d( - *, - disk_name: builtins.str, - disk_uri: builtins.str, - caching_mode: typing.Optional[builtins.str] = None, - fs_type: typing.Optional[builtins.str] = None, - kind: typing.Optional[builtins.str] = None, - read_only: typing.Optional[builtins.bool] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__84f066edf5f8bb2aff501a75543bcd7bb28c293243500d6e69343a9a24263569( - *, - secret_name: builtins.str, - share_name: builtins.str, - read_only: typing.Optional[builtins.bool] = None, - secret_namespace: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__94648be721e46971848c0b51f3b1d4399d4a5e674368c83a893121cb3e801106( - *, - secret_name: builtins.str, - share_name: builtins.str, - read_only: typing.Optional[builtins.bool] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__3842071c1f7fa48baa6f58272703081a16a5000ba6ca2a54f8ed32aceb2e5309( - *, - api_version: typing.Optional[builtins.str] = None, - kind: typing.Optional[builtins.str] = None, - name: typing.Optional[builtins.str] = None, - uid: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__be353859945b18989b92f139f2d1450880c136c416dfb6159bcc2bedd35f5528( - *, - add: typing.Optional[typing.Sequence[builtins.str]] = None, - drop: typing.Optional[typing.Sequence[builtins.str]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__3b5ad69df26a24d2f512ef505faa2117b55637afeef4390b17721af52ec2e212( - *, - monitors: typing.Sequence[builtins.str], - path: typing.Optional[builtins.str] = None, - read_only: typing.Optional[builtins.bool] = None, - secret_file: typing.Optional[builtins.str] = None, - secret_ref: typing.Optional[typing.Union[SecretReference, typing.Dict[builtins.str, typing.Any]]] = None, - user: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__58ba734b607dafa3947531043b85de9735a63082b9ba851ec726adf616b87935( - *, - monitors: typing.Sequence[builtins.str], - path: typing.Optional[builtins.str] = None, - read_only: typing.Optional[builtins.bool] = None, - secret_file: typing.Optional[builtins.str] = None, - secret_ref: typing.Optional[typing.Union[LocalObjectReference, typing.Dict[builtins.str, typing.Any]]] = None, - user: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__a33e7e945dc9d389d58598a00c0615e6a0c101c66e3b1019bfbc65ff586ad288( - *, - request: builtins.str, - signer_name: builtins.str, - expiration_seconds: typing.Optional[jsii.Number] = None, - extra: typing.Optional[typing.Mapping[builtins.str, typing.Sequence[builtins.str]]] = None, - groups: typing.Optional[typing.Sequence[builtins.str]] = None, - uid: typing.Optional[builtins.str] = None, - usages: typing.Optional[typing.Sequence[builtins.str]] = None, - username: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__881438521a2ffa8cb492e1a592803eba0118f41d19c6c9b21f89488919c9fe95( - *, - volume_id: builtins.str, - fs_type: typing.Optional[builtins.str] = None, - read_only: typing.Optional[builtins.bool] = None, - secret_ref: typing.Optional[typing.Union[SecretReference, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__06ae43f93ff756a310e6d5117e9cf8625447a987c3d9a7fda373017a190d72bc( - *, - volume_id: builtins.str, - fs_type: typing.Optional[builtins.str] = None, - read_only: typing.Optional[builtins.bool] = None, - secret_ref: typing.Optional[typing.Union[LocalObjectReference, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__40bafd005da56b205ce1497f55b1fac61f4c26ca711edfc77173ea503ca29f1c( - *, - resource_claim_name: typing.Optional[builtins.str] = None, - resource_claim_template_name: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__29a449f3b3357364e9fe2eedbf3639c327226f11ef6b646b27d4a54e71dc5c9e( - *, - timeout_seconds: typing.Optional[jsii.Number] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__fe618ea608b9075a33b355598f43687c5206288062267eb0d99d0a9ca0ab859e( - *, - per_node_host_bits: jsii.Number, - ipv4: typing.Optional[builtins.str] = None, - ipv6: typing.Optional[builtins.str] = None, - node_selector: typing.Optional[typing.Union[NodeSelector, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__e5c6f493a36d20a0f5c15799a425473df0ef3509854c45bf00c9f2d1df43078b( - *, - status: builtins.str, - type: builtins.str, - error: typing.Optional[builtins.str] = None, - message: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__370b1c0b36f05ff3192a8cbbd224accabfbc47a41badefad8eae8d70919df5a8( - *, - name: typing.Optional[builtins.str] = None, - optional: typing.Optional[builtins.bool] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__e7b538afefcd3178906246a4633aa3edf9a64dc6b4f99e4f91adaab9981d5e5e( - *, - key: builtins.str, - name: typing.Optional[builtins.str] = None, - optional: typing.Optional[builtins.bool] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__1e65fe961a56a03c3374ec1160978c65396b145146e3c13dc4180daa47d645b1( - *, - kubelet_config_key: builtins.str, - name: builtins.str, - namespace: builtins.str, - resource_version: typing.Optional[builtins.str] = None, - uid: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__8f0e7adaaf9481758c5623030368e21ede02645c5c82f6c273c7c50fce12b22c( - *, - items: typing.Optional[typing.Sequence[typing.Union[KeyToPath, typing.Dict[builtins.str, typing.Any]]]] = None, - name: typing.Optional[builtins.str] = None, - optional: typing.Optional[builtins.bool] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__f732f389aef3745668fe1484c8ff5f95aba0fd695dd9a611adf068af963d4ed6( - *, - default_mode: typing.Optional[jsii.Number] = None, - items: typing.Optional[typing.Sequence[typing.Union[KeyToPath, typing.Dict[builtins.str, typing.Any]]]] = None, - name: typing.Optional[builtins.str] = None, - optional: typing.Optional[builtins.bool] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__1b3b3fe219125d2e54fdddd91ecda52e6a495f38680a3a53b33f1b02c1b671da( - *, - name: builtins.str, - args: typing.Optional[typing.Sequence[builtins.str]] = None, - command: typing.Optional[typing.Sequence[builtins.str]] = None, - env: typing.Optional[typing.Sequence[typing.Union[EnvVar, typing.Dict[builtins.str, typing.Any]]]] = None, - env_from: typing.Optional[typing.Sequence[typing.Union[EnvFromSource, typing.Dict[builtins.str, typing.Any]]]] = None, - image: typing.Optional[builtins.str] = None, - image_pull_policy: typing.Optional[builtins.str] = None, - lifecycle: typing.Optional[typing.Union[Lifecycle, typing.Dict[builtins.str, typing.Any]]] = None, - liveness_probe: typing.Optional[typing.Union[Probe, typing.Dict[builtins.str, typing.Any]]] = None, - ports: typing.Optional[typing.Sequence[typing.Union[ContainerPort, typing.Dict[builtins.str, typing.Any]]]] = None, - readiness_probe: typing.Optional[typing.Union[Probe, typing.Dict[builtins.str, typing.Any]]] = None, - resources: typing.Optional[typing.Union[ResourceRequirements, typing.Dict[builtins.str, typing.Any]]] = None, - security_context: typing.Optional[typing.Union[SecurityContext, typing.Dict[builtins.str, typing.Any]]] = None, - startup_probe: typing.Optional[typing.Union[Probe, typing.Dict[builtins.str, typing.Any]]] = None, - stdin: typing.Optional[builtins.bool] = None, - stdin_once: typing.Optional[builtins.bool] = None, - termination_message_path: typing.Optional[builtins.str] = None, - termination_message_policy: typing.Optional[builtins.str] = None, - tty: typing.Optional[builtins.bool] = None, - volume_devices: typing.Optional[typing.Sequence[typing.Union[VolumeDevice, typing.Dict[builtins.str, typing.Any]]]] = None, - volume_mounts: typing.Optional[typing.Sequence[typing.Union[VolumeMount, typing.Dict[builtins.str, typing.Any]]]] = None, - working_dir: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__ea50a33f53045ef963173d2b69fe4fa77a8142b8ae58ea83960e69f4839c879a( - *, - container_port: jsii.Number, - host_ip: typing.Optional[builtins.str] = None, - host_port: typing.Optional[jsii.Number] = None, - name: typing.Optional[builtins.str] = None, - protocol: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__b4e84c9f4f18c845b4719ea9f3557e5fb076a9b483c5cb7bcb93a992c8066a28( - *, - container: builtins.str, - name: builtins.str, - target: typing.Union[MetricTargetV2, typing.Dict[builtins.str, typing.Any]], -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__ede2ac625e6994d9a90814ee390559d5afe3fc8cbac21bd43b66df929f6dc946( - *, - job_template: typing.Union[JobTemplateSpec, typing.Dict[builtins.str, typing.Any]], - schedule: builtins.str, - concurrency_policy: typing.Optional[builtins.str] = None, - failed_jobs_history_limit: typing.Optional[jsii.Number] = None, - starting_deadline_seconds: typing.Optional[jsii.Number] = None, - successful_jobs_history_limit: typing.Optional[jsii.Number] = None, - suspend: typing.Optional[builtins.bool] = None, - time_zone: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__16088e27454cd0459d4b0c1ddae21a0af78275822fe3ad5b12a9c2a78b7075bb( - *, - kind: builtins.str, - name: builtins.str, - api_version: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__3af8150f9f5d358140c2abd5fb9f92e0e98dd7941df54ff76043b6eff438e4e5( - *, - kind: builtins.str, - name: builtins.str, - api_version: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__17e3bd16387b10ac52d67d9c371444bdd008a79a45fd1fa94cf98f80b9c7070f( - *, - attach_required: typing.Optional[builtins.bool] = None, - fs_group_policy: typing.Optional[builtins.str] = None, - pod_info_on_mount: typing.Optional[builtins.bool] = None, - requires_republish: typing.Optional[builtins.bool] = None, - se_linux_mount: typing.Optional[builtins.bool] = None, - storage_capacity: typing.Optional[builtins.bool] = None, - token_requests: typing.Optional[typing.Sequence[typing.Union[TokenRequest, typing.Dict[builtins.str, typing.Any]]]] = None, - volume_lifecycle_modes: typing.Optional[typing.Sequence[builtins.str]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__adf2babe98e03e365ff1231a34008326706969b8f221e55270d116f02fb1c250( - *, - name: builtins.str, - node_id: builtins.str, - allocatable: typing.Optional[typing.Union[VolumeNodeResources, typing.Dict[builtins.str, typing.Any]]] = None, - topology_keys: typing.Optional[typing.Sequence[builtins.str]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__39088f7ceefdd1a9586f416018ad793cc2af5c04145208fe263fc1262780bed0( - *, - drivers: typing.Sequence[typing.Union[CsiNodeDriver, typing.Dict[builtins.str, typing.Any]]], -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__a4ab30eceffd6722994926b775cdc47f663e43744c6b71a78d0f1642819580a5( - *, - driver: builtins.str, - volume_handle: builtins.str, - controller_expand_secret_ref: typing.Optional[typing.Union[SecretReference, typing.Dict[builtins.str, typing.Any]]] = None, - controller_publish_secret_ref: typing.Optional[typing.Union[SecretReference, typing.Dict[builtins.str, typing.Any]]] = None, - fs_type: typing.Optional[builtins.str] = None, - node_expand_secret_ref: typing.Optional[typing.Union[SecretReference, typing.Dict[builtins.str, typing.Any]]] = None, - node_publish_secret_ref: typing.Optional[typing.Union[SecretReference, typing.Dict[builtins.str, typing.Any]]] = None, - node_stage_secret_ref: typing.Optional[typing.Union[SecretReference, typing.Dict[builtins.str, typing.Any]]] = None, - read_only: typing.Optional[builtins.bool] = None, - volume_attributes: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__65e9dfb99794038b02bcf5d69b1da24f041cc9f271cf98f603749465f2a3c2fe( - *, - driver: builtins.str, - fs_type: typing.Optional[builtins.str] = None, - node_publish_secret_ref: typing.Optional[typing.Union[LocalObjectReference, typing.Dict[builtins.str, typing.Any]]] = None, - read_only: typing.Optional[builtins.bool] = None, - volume_attributes: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__67357d094ad4e40c9fcc3d8cbf7b086f1bfc3261b70c6905ae016e7272d48696( - *, - json_path: builtins.str, - name: builtins.str, - type: builtins.str, - description: typing.Optional[builtins.str] = None, - format: typing.Optional[builtins.str] = None, - priority: typing.Optional[jsii.Number] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__d70408b4791a667462cf9c5081a65101e992ff219dda7178fc0fe4a250937f89( - *, - strategy: builtins.str, - webhook: typing.Optional[typing.Union[WebhookConversion, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__9f1b391925af7e4945bb8d4ea39747ad4716515ac0a5519bb5b63e5039390614( - *, - kind: builtins.str, - plural: builtins.str, - categories: typing.Optional[typing.Sequence[builtins.str]] = None, - list_kind: typing.Optional[builtins.str] = None, - short_names: typing.Optional[typing.Sequence[builtins.str]] = None, - singular: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__3998b630c25e34db9c60fa9ce393302f885dc2d0aa7e7eddb9228b8dc8335d91( - *, - group: builtins.str, - names: typing.Union[CustomResourceDefinitionNames, typing.Dict[builtins.str, typing.Any]], - scope: builtins.str, - versions: typing.Sequence[typing.Union[CustomResourceDefinitionVersion, typing.Dict[builtins.str, typing.Any]]], - conversion: typing.Optional[typing.Union[CustomResourceConversion, typing.Dict[builtins.str, typing.Any]]] = None, - preserve_unknown_fields: typing.Optional[builtins.bool] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__d6df99d714ea39698bb4328abb2c39a68421fd691d72d93bd6ddbb23b90046bf( - *, - name: builtins.str, - served: builtins.bool, - storage: builtins.bool, - additional_printer_columns: typing.Optional[typing.Sequence[typing.Union[CustomResourceColumnDefinition, typing.Dict[builtins.str, typing.Any]]]] = None, - deprecated: typing.Optional[builtins.bool] = None, - deprecation_warning: typing.Optional[builtins.str] = None, - schema: typing.Optional[typing.Union[CustomResourceValidation, typing.Dict[builtins.str, typing.Any]]] = None, - subresources: typing.Optional[typing.Union[CustomResourceSubresources, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__e504fd18aae767ddb56fbac096bf70df45780d510027e105b410fa62efa0ce33( - *, - spec_replicas_path: builtins.str, - status_replicas_path: builtins.str, - label_selector_path: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__c50da5aa5369520674d278d624a5847abf90b5ff122b8050299b5990def114cd( - *, - scale: typing.Optional[typing.Union[CustomResourceSubresourceScale, typing.Dict[builtins.str, typing.Any]]] = None, - status: typing.Any = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__043bf7c99906ebf978f378e80401b671bd7d527825d3a4d5d96e0c729fdbf9a8( - *, - open_apiv3_schema: typing.Optional[typing.Union[JsonSchemaProps, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__14204ab2e113520a3c936870c510953423acc16ac3f52118402d23dec634f9a1( - *, - selector: typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]], - template: typing.Union[PodTemplateSpec, typing.Dict[builtins.str, typing.Any]], - min_ready_seconds: typing.Optional[jsii.Number] = None, - revision_history_limit: typing.Optional[jsii.Number] = None, - update_strategy: typing.Optional[typing.Union[DaemonSetUpdateStrategy, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__8b11783b3c58aecec2330e072809ea832cb9b06930ebac2636be1238b0ff753f( - *, - rolling_update: typing.Optional[typing.Union[RollingUpdateDaemonSet, typing.Dict[builtins.str, typing.Any]]] = None, - type: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__51651210b2f45ea52509def59df38f1a165f6231405843108f8fb43c79e7fd13( - *, - api_version: typing.Optional[builtins.str] = None, - dry_run: typing.Optional[typing.Sequence[builtins.str]] = None, - grace_period_seconds: typing.Optional[jsii.Number] = None, - kind: typing.Optional[IoK8SApimachineryPkgApisMetaV1DeleteOptionsKind] = None, - orphan_dependents: typing.Optional[builtins.bool] = None, - preconditions: typing.Optional[typing.Union[Preconditions, typing.Dict[builtins.str, typing.Any]]] = None, - propagation_policy: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__88d492f2893c840ec003d2ddba4caf15921d31465e62b8a4667d961a583e3504( - *, - selector: typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]], - template: typing.Union[PodTemplateSpec, typing.Dict[builtins.str, typing.Any]], - min_ready_seconds: typing.Optional[jsii.Number] = None, - paused: typing.Optional[builtins.bool] = None, - progress_deadline_seconds: typing.Optional[jsii.Number] = None, - replicas: typing.Optional[jsii.Number] = None, - revision_history_limit: typing.Optional[jsii.Number] = None, - strategy: typing.Optional[typing.Union[DeploymentStrategy, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__47c8ed86524662fa654ab55acc09523cd7f42475f5339eab3418ffa208e11b45( - *, - rolling_update: typing.Optional[typing.Union[RollingUpdateDeployment, typing.Dict[builtins.str, typing.Any]]] = None, - type: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__869e1c36b23a22ea11fcce61bba7f500c0b12d2d573aa9739a152c0099840760( - *, - items: typing.Optional[typing.Sequence[typing.Union[DownwardApiVolumeFile, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__101db0695abfdddd40bd62385a630a47df841ee1a6f24407608f8fe8b6ff069d( - *, - path: builtins.str, - field_ref: typing.Optional[typing.Union[ObjectFieldSelector, typing.Dict[builtins.str, typing.Any]]] = None, - mode: typing.Optional[jsii.Number] = None, - resource_field_ref: typing.Optional[typing.Union[ResourceFieldSelector, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__d43c40d536e8ef2ac9d664987c3d40ea8d2b2a7183453e3267caf21a4f0e109a( - *, - default_mode: typing.Optional[jsii.Number] = None, - items: typing.Optional[typing.Sequence[typing.Union[DownwardApiVolumeFile, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__51336821e156a17acb25064d05a943dee51ed6d9fede28f0496b90a126cbde50( - *, - medium: typing.Optional[builtins.str] = None, - size_limit: typing.Optional[Quantity] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__aecf0f91e9c72760558c73c60babfa2b9ec1400a6ace4c1cad4cdb2ce4cf4276( - *, - addresses: typing.Sequence[builtins.str], - conditions: typing.Optional[typing.Union[EndpointConditions, typing.Dict[builtins.str, typing.Any]]] = None, - deprecated_topology: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - hints: typing.Optional[typing.Union[EndpointHints, typing.Dict[builtins.str, typing.Any]]] = None, - hostname: typing.Optional[builtins.str] = None, - node_name: typing.Optional[builtins.str] = None, - target_ref: typing.Optional[typing.Union[ObjectReference, typing.Dict[builtins.str, typing.Any]]] = None, - zone: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__970f09567748e206afbb46c0fa29177fb5967712f3943c875ccea8dfd5d1b3ce( - *, - ip: builtins.str, - hostname: typing.Optional[builtins.str] = None, - node_name: typing.Optional[builtins.str] = None, - target_ref: typing.Optional[typing.Union[ObjectReference, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__b2b5238272f9d14831397973a28343d30df4184341889339940e2808d1357461( - *, - ready: typing.Optional[builtins.bool] = None, - serving: typing.Optional[builtins.bool] = None, - terminating: typing.Optional[builtins.bool] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__72b3d0ad7203c24d6795afe4a3e837823411fa92c071099c508160c704770992( - *, - for_zones: typing.Optional[typing.Sequence[typing.Union[ForZone, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__198ff7c8fddac2085d2564d42a0d2f8327272caf700986100e27c5038c106c79( - *, - port: jsii.Number, - app_protocol: typing.Optional[builtins.str] = None, - name: typing.Optional[builtins.str] = None, - protocol: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__f3121032b6cb224e5e34b7639c8027fadb2a705523967f72dda8e1bb2dc1c8ab( - *, - addresses: typing.Optional[typing.Sequence[typing.Union[EndpointAddress, typing.Dict[builtins.str, typing.Any]]]] = None, - not_ready_addresses: typing.Optional[typing.Sequence[typing.Union[EndpointAddress, typing.Dict[builtins.str, typing.Any]]]] = None, - ports: typing.Optional[typing.Sequence[typing.Union[EndpointPort, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__1e745a3a12e83796a4c7e9f2246565d74fe3f6a1041987cbb7dd3435aaba3180( - *, - config_map_ref: typing.Optional[typing.Union[ConfigMapEnvSource, typing.Dict[builtins.str, typing.Any]]] = None, - prefix: typing.Optional[builtins.str] = None, - secret_ref: typing.Optional[typing.Union[SecretEnvSource, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__7ff167fe39eff04347196f0b38e85c859cfdf9180d26b47b3ccc003411311c3a( - *, - name: builtins.str, - value: typing.Optional[builtins.str] = None, - value_from: typing.Optional[typing.Union[EnvVarSource, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__8200f0b06b85522180fa691bfce5b26210b45cbf9374d77ea5dd65cbbf09b32a( - *, - config_map_key_ref: typing.Optional[typing.Union[ConfigMapKeySelector, typing.Dict[builtins.str, typing.Any]]] = None, - field_ref: typing.Optional[typing.Union[ObjectFieldSelector, typing.Dict[builtins.str, typing.Any]]] = None, - resource_field_ref: typing.Optional[typing.Union[ResourceFieldSelector, typing.Dict[builtins.str, typing.Any]]] = None, - secret_key_ref: typing.Optional[typing.Union[SecretKeySelector, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__3e01c0b51ea0b6a8c67c37763e480129a2534ef49ece7c443d6c8063f7415d29( - *, - name: builtins.str, - args: typing.Optional[typing.Sequence[builtins.str]] = None, - command: typing.Optional[typing.Sequence[builtins.str]] = None, - env: typing.Optional[typing.Sequence[typing.Union[EnvVar, typing.Dict[builtins.str, typing.Any]]]] = None, - env_from: typing.Optional[typing.Sequence[typing.Union[EnvFromSource, typing.Dict[builtins.str, typing.Any]]]] = None, - image: typing.Optional[builtins.str] = None, - image_pull_policy: typing.Optional[builtins.str] = None, - lifecycle: typing.Optional[typing.Union[Lifecycle, typing.Dict[builtins.str, typing.Any]]] = None, - liveness_probe: typing.Optional[typing.Union[Probe, typing.Dict[builtins.str, typing.Any]]] = None, - ports: typing.Optional[typing.Sequence[typing.Union[ContainerPort, typing.Dict[builtins.str, typing.Any]]]] = None, - readiness_probe: typing.Optional[typing.Union[Probe, typing.Dict[builtins.str, typing.Any]]] = None, - resources: typing.Optional[typing.Union[ResourceRequirements, typing.Dict[builtins.str, typing.Any]]] = None, - security_context: typing.Optional[typing.Union[SecurityContext, typing.Dict[builtins.str, typing.Any]]] = None, - startup_probe: typing.Optional[typing.Union[Probe, typing.Dict[builtins.str, typing.Any]]] = None, - stdin: typing.Optional[builtins.bool] = None, - stdin_once: typing.Optional[builtins.bool] = None, - target_container_name: typing.Optional[builtins.str] = None, - termination_message_path: typing.Optional[builtins.str] = None, - termination_message_policy: typing.Optional[builtins.str] = None, - tty: typing.Optional[builtins.bool] = None, - volume_devices: typing.Optional[typing.Sequence[typing.Union[VolumeDevice, typing.Dict[builtins.str, typing.Any]]]] = None, - volume_mounts: typing.Optional[typing.Sequence[typing.Union[VolumeMount, typing.Dict[builtins.str, typing.Any]]]] = None, - working_dir: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__b18bb939a5ee93260e717b4a8b31bc6e5ff1329bc0dfc81f9c7fa24800f6854b( - *, - volume_claim_template: typing.Optional[typing.Union[PersistentVolumeClaimTemplate, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__004487d3474ef54e77d3c4fc15800f434258914047b941481974745bac50347a( - *, - count: jsii.Number, - last_observed_time: datetime.datetime, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__4a9e80d349ff66b0083f1d53dad15acd2eb7b7353b7849460bd62f8e25e7974e( - *, - component: typing.Optional[builtins.str] = None, - host: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__39b0da0ddb8fa067bbecf85dd3d7748f68c3c1d726d1f55f6612b8bd92883a73( - *, - command: typing.Optional[typing.Sequence[builtins.str]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__ed55df628bde684d5aa951f6b4c6672c57289721dbb3a11facc37969e46246f1( - *, - description: typing.Optional[builtins.str] = None, - url: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__991911955f55da3c4dbd38270ac60d304756b0eac9946bf6bab366840a5e5a7a( - *, - metric: typing.Union[MetricIdentifierV2, typing.Dict[builtins.str, typing.Any]], - target: typing.Union[MetricTargetV2, typing.Dict[builtins.str, typing.Any]], -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__2745107e20cb778ffd413fedde9112e0e0e1ad8530ac6be3aa44daf745945cd1( - *, - fs_type: typing.Optional[builtins.str] = None, - lun: typing.Optional[jsii.Number] = None, - read_only: typing.Optional[builtins.bool] = None, - target_ww_ns: typing.Optional[typing.Sequence[builtins.str]] = None, - wwids: typing.Optional[typing.Sequence[builtins.str]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__361bb86c0f3e6ad95260e69e5449b56f8ed56cc62d38e36d89c325ca5045168e( - *, - driver: builtins.str, - fs_type: typing.Optional[builtins.str] = None, - options: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - read_only: typing.Optional[builtins.bool] = None, - secret_ref: typing.Optional[typing.Union[SecretReference, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__01d639d31d18ccaee6a1c059e3369e39b1ae2532a11a7a6f32fd5bcfb50615c4( - *, - driver: builtins.str, - fs_type: typing.Optional[builtins.str] = None, - options: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - read_only: typing.Optional[builtins.bool] = None, - secret_ref: typing.Optional[typing.Union[LocalObjectReference, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__c8da19b7f0ffd9cf70dddb6e7c6984f3d78d5aa2c70fad98b528bc4aded8a549( - *, - dataset_name: typing.Optional[builtins.str] = None, - dataset_uuid: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__f097bb4fbe672878a09ccbc6c996fba34cd3cbbd412e738d7df0e2c5790f6b10( - *, - type: builtins.str, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__bffd4b6077b1400f76c8885e39b16536445fb17247f408a55f48c1989bb500f7( - *, - type: builtins.str, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__95a7a4e1d128cef7bb866d233e06c9bb0da818b45bcd627a65d99a570d28c5b7( - *, - priority_level_configuration: typing.Union[PriorityLevelConfigurationReferenceV1Beta2, typing.Dict[builtins.str, typing.Any]], - distinguisher_method: typing.Optional[typing.Union[FlowDistinguisherMethodV1Beta2, typing.Dict[builtins.str, typing.Any]]] = None, - matching_precedence: typing.Optional[jsii.Number] = None, - rules: typing.Optional[typing.Sequence[typing.Union[PolicyRulesWithSubjectsV1Beta2, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__52d981628f2120d6117e98080ee21cdc5a95544b4e345b4f2083d09e3e6ac908( - *, - priority_level_configuration: typing.Union[PriorityLevelConfigurationReferenceV1Beta3, typing.Dict[builtins.str, typing.Any]], - distinguisher_method: typing.Optional[typing.Union[FlowDistinguisherMethodV1Beta3, typing.Dict[builtins.str, typing.Any]]] = None, - matching_precedence: typing.Optional[jsii.Number] = None, - rules: typing.Optional[typing.Sequence[typing.Union[PolicyRulesWithSubjectsV1Beta3, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__fc406b0dce866e82fadbc8c73de5da39909470ea692a663d044c98e9e75e472e( - *, - name: builtins.str, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__67fa0238ae227faa5913c9a406cb8c1df336aa99b59c22be5e9022157eef8101( - *, - pd_name: builtins.str, - fs_type: typing.Optional[builtins.str] = None, - partition: typing.Optional[jsii.Number] = None, - read_only: typing.Optional[builtins.bool] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__d3929ab9177d349a3cbc08144a071eb034b82c6d036e2f32c383d99193bfa2fc( - *, - repository: builtins.str, - directory: typing.Optional[builtins.str] = None, - revision: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__77c2e679ddedc14c8c772b4af1c9ebb540b76f5b4ae46f0ddd7f13c3f9068d2e( - *, - endpoints: builtins.str, - path: builtins.str, - endpoints_namespace: typing.Optional[builtins.str] = None, - read_only: typing.Optional[builtins.bool] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__ee9a1041172608f39bf295d6750ada62e4ab7bf9812fabbb918c35d5ff339178( - *, - endpoints: builtins.str, - path: builtins.str, - read_only: typing.Optional[builtins.bool] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__ea5fa7eede3defacccd3e49dd371a89a25a4831d1e7a6ecb1660bf6a617768ed( - *, - name: builtins.str, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__812aaf4ed41fa0dc75191b6335a0c23c3c9c9b13e69060ba616483b441140f2e( - *, - name: builtins.str, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__a4c720717a12c121388433640f65c648a1215ba44d394b015fa52bde58de178d( - *, - port: jsii.Number, - service: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__fda77f8a90785391fbbcd3ca1c11f062fa6bf7ae954e80fb24e4e288fdd17832( - *, - scale_down: typing.Optional[typing.Union[HpaScalingRulesV2, typing.Dict[builtins.str, typing.Any]]] = None, - scale_up: typing.Optional[typing.Union[HpaScalingRulesV2, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__67e90701cb6e8283c6dcdce1a9bcefa03010668cc5c0dc412f36e77d3b94c2c6( - *, - max_replicas: jsii.Number, - scale_target_ref: typing.Union[CrossVersionObjectReference, typing.Dict[builtins.str, typing.Any]], - min_replicas: typing.Optional[jsii.Number] = None, - target_cpu_utilization_percentage: typing.Optional[jsii.Number] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__a1323a69e978b64e93ef7f04e8455a1c9a9c3bb874ab3f67e7522bf7d2a07c64( - *, - max_replicas: jsii.Number, - scale_target_ref: typing.Union[CrossVersionObjectReferenceV2, typing.Dict[builtins.str, typing.Any]], - behavior: typing.Optional[typing.Union[HorizontalPodAutoscalerBehaviorV2, typing.Dict[builtins.str, typing.Any]]] = None, - metrics: typing.Optional[typing.Sequence[typing.Union[MetricSpecV2, typing.Dict[builtins.str, typing.Any]]]] = None, - min_replicas: typing.Optional[jsii.Number] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__baf1f258035adb05fce6a499ac90c7c683c23515cb2387103291d65c150db057( - *, - hostnames: typing.Optional[typing.Sequence[builtins.str]] = None, - ip: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__6e89b87d54e04bd3a5ed5104bd9aeeebc90ed613bc0805a39560bc2bbf615e55( - *, - path: builtins.str, - type: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__aeb589a0fa4d0cc40251749153c9f79afe4dfc58697049ab09f63ee4925eb96d( - *, - period_seconds: jsii.Number, - type: builtins.str, - value: jsii.Number, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__01955266417ee884ef4e85d0ff6d261477e416614ba711701a5aa2f989ee95ae( - *, - policies: typing.Optional[typing.Sequence[typing.Union[HpaScalingPolicyV2, typing.Dict[builtins.str, typing.Any]]]] = None, - select_policy: typing.Optional[builtins.str] = None, - stabilization_window_seconds: typing.Optional[jsii.Number] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__62efc5742934988596159a1c4328467a5bf15711d92d0298db109be22da42dbc( - *, - port: IntOrString, - host: typing.Optional[builtins.str] = None, - http_headers: typing.Optional[typing.Sequence[typing.Union[HttpHeader, typing.Dict[builtins.str, typing.Any]]]] = None, - path: typing.Optional[builtins.str] = None, - scheme: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__65a4ad915e61cf4f8034eb768af84855c5eb30565af7046319e9debb114d6dbf( - *, - name: builtins.str, - value: builtins.str, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__1cca829c509cb330ab5cf95c6fc26b20f21813dc375800b70fcbfdfeec2654c5( - *, - backend: typing.Union[IngressBackend, typing.Dict[builtins.str, typing.Any]], - path_type: builtins.str, - path: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__05cd1df4bce67e8fa976f9efada12c170538e64a48328c5f255efdebc8f61d9a( - *, - paths: typing.Sequence[typing.Union[HttpIngressPath, typing.Dict[builtins.str, typing.Any]]], -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__df26b528fe90e75693923674dff2a906cecf821611adf7cf1d7a6745fd0cd715( - *, - resource: typing.Optional[typing.Union[TypedLocalObjectReference, typing.Dict[builtins.str, typing.Any]]] = None, - service: typing.Optional[typing.Union[IngressServiceBackend, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__b55c86b8fa568f61df7bfe266dca0075b336f1056df734d8a5f9f6b5116eadc6( - *, - kind: builtins.str, - name: builtins.str, - api_group: typing.Optional[builtins.str] = None, - namespace: typing.Optional[builtins.str] = None, - scope: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__9135d7f530914c8efd0036d3c9b7f8302e7bf5f1a915332fbf5ddccf196262d1( - *, - controller: typing.Optional[builtins.str] = None, - parameters: typing.Optional[typing.Union[IngressClassParametersReference, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__f579f76985685fddfa2343f3fdb2f56b0ad569a16de003c2209b63ace70d1fee( - *, - host: typing.Optional[builtins.str] = None, - http: typing.Optional[typing.Union[HttpIngressRuleValue, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__e3e97fffe88d91fb9b536c53695ba745cdabbeb12e55b6dea45d253fdc89f5cd( - *, - name: builtins.str, - port: typing.Optional[typing.Union[ServiceBackendPort, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__97b273849944944f09361df5533bf081b4f556d667e5a81bba5956e651d6411b( - *, - default_backend: typing.Optional[typing.Union[IngressBackend, typing.Dict[builtins.str, typing.Any]]] = None, - ingress_class_name: typing.Optional[builtins.str] = None, - rules: typing.Optional[typing.Sequence[typing.Union[IngressRule, typing.Dict[builtins.str, typing.Any]]]] = None, - tls: typing.Optional[typing.Sequence[typing.Union[IngressTls, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__8025d7972fe3e671efe9fc76590f08e6af4537e71b575480407655a7b7b7b9ef( - *, - hosts: typing.Optional[typing.Sequence[builtins.str]] = None, - secret_name: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__35530c996723c32c7f16f8470b1263773efdf426fdc5791968292d1634936acc( - value: jsii.Number, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__c0d8454a87ccd93d2d171f9e20405b3c5d7964bd41fa7e35f0ca4da486da3504( - value: builtins.str, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__06c394466495c1b06784a9836bf93d9ce9aec1a818eac2478c2db2ccb377d374( - *, - cidr: builtins.str, - except_: typing.Optional[typing.Sequence[builtins.str]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__61f74686d735cd7119fc3fdb8061ce0c3372549a76fba9b78a682fb2b8737efe( - *, - iqn: builtins.str, - lun: jsii.Number, - target_portal: builtins.str, - chap_auth_discovery: typing.Optional[builtins.bool] = None, - chap_auth_session: typing.Optional[builtins.bool] = None, - fs_type: typing.Optional[builtins.str] = None, - initiator_name: typing.Optional[builtins.str] = None, - iscsi_interface: typing.Optional[builtins.str] = None, - portals: typing.Optional[typing.Sequence[builtins.str]] = None, - read_only: typing.Optional[builtins.bool] = None, - secret_ref: typing.Optional[typing.Union[SecretReference, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__3f8a3f5224af62afa8f0a6e18b9dbecb3365354c791cdf02387e47f4f53ef0b6( - *, - iqn: builtins.str, - lun: jsii.Number, - target_portal: builtins.str, - chap_auth_discovery: typing.Optional[builtins.bool] = None, - chap_auth_session: typing.Optional[builtins.bool] = None, - fs_type: typing.Optional[builtins.str] = None, - initiator_name: typing.Optional[builtins.str] = None, - iscsi_interface: typing.Optional[builtins.str] = None, - portals: typing.Optional[typing.Sequence[builtins.str]] = None, - read_only: typing.Optional[builtins.bool] = None, - secret_ref: typing.Optional[typing.Union[LocalObjectReference, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__292598de0c2d5d5c366c954213d0653c155500e82fa84af63083a2187622ca4d( - *, - template: typing.Union[PodTemplateSpec, typing.Dict[builtins.str, typing.Any]], - active_deadline_seconds: typing.Optional[jsii.Number] = None, - backoff_limit: typing.Optional[jsii.Number] = None, - completion_mode: typing.Optional[builtins.str] = None, - completions: typing.Optional[jsii.Number] = None, - manual_selector: typing.Optional[builtins.bool] = None, - parallelism: typing.Optional[jsii.Number] = None, - pod_failure_policy: typing.Optional[typing.Union[PodFailurePolicy, typing.Dict[builtins.str, typing.Any]]] = None, - selector: typing.Optional[typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]]] = None, - suspend: typing.Optional[builtins.bool] = None, - ttl_seconds_after_finished: typing.Optional[jsii.Number] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__1105e17aa0c313f4565b5065f5605339ba31de88c8c745050dc45e87d82509cd( - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[JobSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__daf776f0153100d207addeedc621b9aaef5a61bb490f24eaa0139862d3db2a89( - *, - additional_items: typing.Any = None, - additional_properties: typing.Any = None, - all_of: typing.Optional[typing.Sequence[typing.Union[JsonSchemaProps, typing.Dict[builtins.str, typing.Any]]]] = None, - any_of: typing.Optional[typing.Sequence[typing.Union[JsonSchemaProps, typing.Dict[builtins.str, typing.Any]]]] = None, - default: typing.Any = None, - definitions: typing.Optional[typing.Mapping[builtins.str, typing.Union[JsonSchemaProps, typing.Dict[builtins.str, typing.Any]]]] = None, - dependencies: typing.Optional[typing.Mapping[builtins.str, typing.Any]] = None, - description: typing.Optional[builtins.str] = None, - enum: typing.Optional[typing.Sequence[typing.Any]] = None, - example: typing.Any = None, - exclusive_maximum: typing.Optional[builtins.bool] = None, - exclusive_minimum: typing.Optional[builtins.bool] = None, - external_docs: typing.Optional[typing.Union[ExternalDocumentation, typing.Dict[builtins.str, typing.Any]]] = None, - format: typing.Optional[builtins.str] = None, - id: typing.Optional[builtins.str] = None, - items: typing.Any = None, - maximum: typing.Optional[jsii.Number] = None, - max_items: typing.Optional[jsii.Number] = None, - max_length: typing.Optional[jsii.Number] = None, - max_properties: typing.Optional[jsii.Number] = None, - minimum: typing.Optional[jsii.Number] = None, - min_items: typing.Optional[jsii.Number] = None, - min_length: typing.Optional[jsii.Number] = None, - min_properties: typing.Optional[jsii.Number] = None, - multiple_of: typing.Optional[jsii.Number] = None, - not_: typing.Optional[typing.Union[JsonSchemaProps, typing.Dict[builtins.str, typing.Any]]] = None, - nullable: typing.Optional[builtins.bool] = None, - one_of: typing.Optional[typing.Sequence[typing.Union[JsonSchemaProps, typing.Dict[builtins.str, typing.Any]]]] = None, - pattern: typing.Optional[builtins.str] = None, - pattern_properties: typing.Optional[typing.Mapping[builtins.str, typing.Union[JsonSchemaProps, typing.Dict[builtins.str, typing.Any]]]] = None, - properties: typing.Optional[typing.Mapping[builtins.str, typing.Union[JsonSchemaProps, typing.Dict[builtins.str, typing.Any]]]] = None, - ref: typing.Optional[builtins.str] = None, - required: typing.Optional[typing.Sequence[builtins.str]] = None, - schema: typing.Optional[builtins.str] = None, - title: typing.Optional[builtins.str] = None, - type: typing.Optional[builtins.str] = None, - unique_items: typing.Optional[builtins.bool] = None, - x_kubernetes_embedded_resource: typing.Optional[builtins.bool] = None, - x_kubernetes_int_or_string: typing.Optional[builtins.bool] = None, - x_kubernetes_list_map_keys: typing.Optional[typing.Sequence[builtins.str]] = None, - x_kubernetes_list_type: typing.Optional[builtins.str] = None, - x_kubernetes_map_type: typing.Optional[builtins.str] = None, - x_kubernetes_preserve_unknown_fields: typing.Optional[builtins.bool] = None, - x_kubernetes_validations: typing.Optional[typing.Sequence[typing.Union[ValidationRule, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__1f579c4b13a88f3186bcbc183fc5b54bf1b162f87adf1d2ad83a9a8b5e0bb447( - *, - key: builtins.str, - path: builtins.str, - mode: typing.Optional[jsii.Number] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__ad1fad6e721ef9e49639f06836c185c6738b1170ece4dac50e287ae3f90985ef( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[ApiServiceSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__77fd17dee8360181013ec5a3e589f22059cfcb4847e3a0abf0dfd56b33024d5e( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeApiServiceProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__e14504c02b3947489445078365563d536c1ed7457661296ae07aa79c8452d4e1( - *, - items: typing.Sequence[typing.Union[KubeApiServiceProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__fa388b54653e1794b03d081efbf5ba6ac4082c87f562e32c6beeaedcb2062b0f( - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[ApiServiceSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__3278205b7b7726ad41ab6a4d62cd97f9a37714beb4600b6ee0290e7ff44f6280( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - target: typing.Union[ObjectReference, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__17f73704962797e0f37ad68c644b7528547425a2b7852b93aad34d9faee41a89( - *, - target: typing.Union[ObjectReference, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__d8ca0f64663445c4ac257415151a8230f1cc231c9caccfdbdc0b6fa02d9459d2( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - spec: typing.Union[CertificateSigningRequestSpec, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__0e52ee2201ff43e5e93e3d5f4283d795109cda99111d410facf2ba779fca8f23( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeCertificateSigningRequestProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__2dcc4a87e5addcc1390a4a9233596ca3523db6bde4ddce413276e7da14156140( - *, - items: typing.Sequence[typing.Union[KubeCertificateSigningRequestProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__ea26900e83d9c03052f5118bf686d1cf204888ec1fe99f0622dd1de5b45ebc2a( - *, - spec: typing.Union[CertificateSigningRequestSpec, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__bebe2c6d28eb4d63601ff21a7495134127d04e845886c60aef428b3c9d659d48( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeClusterCidrv1Alpha1Props, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__2568516c61e397e6ffe9ac679a0c57c224fdd0d1ee2c188bf4282ba2ec5d1871( - *, - items: typing.Sequence[typing.Union[KubeClusterCidrv1Alpha1Props, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__38c199ac22bb3d8686743ec4676956ef1167fe20e7487535199d00a97bec4353( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[ClusterCidrSpecV1Alpha1, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__0b3f026fe04c5a65af81aa7b0f498e86a380bd11b60aaa10b02765b32bd15386( - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[ClusterCidrSpecV1Alpha1, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__3dee6cbdf96ca0b97f9963be7a7a6f153933e9b244671b09569b2449b5df5bfb( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - aggregation_rule: typing.Optional[typing.Union[AggregationRule, typing.Dict[builtins.str, typing.Any]]] = None, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - rules: typing.Optional[typing.Sequence[typing.Union[PolicyRule, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__3e6775a7ad52980f5d176d04772d94063734f3c3829aeb08e03f9554da3c084e( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - role_ref: typing.Union[RoleRef, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - subjects: typing.Optional[typing.Sequence[typing.Union[Subject, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__0c3606f96360dc6b85d5722a2bd315d4372920a7b08580cdd2b23ef4b3de402c( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeClusterRoleBindingProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__2c82a518d0376ee32a141ec070cbf273462cdd5ce947e4b47885cda5cfe73403( - *, - items: typing.Sequence[typing.Union[KubeClusterRoleBindingProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__257a9d454c53443a5bcf76ea68af6361260af7fedca4596fd5f3e37805c7a05f( - *, - role_ref: typing.Union[RoleRef, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - subjects: typing.Optional[typing.Sequence[typing.Union[Subject, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__2a7f78944eda3f35935b1126aeb9bacc3bb96930fb629d27ae700ff852b519da( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeClusterRoleProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__3567db5c4e5df260e3bfb132c868492937f16ab86f1fd556633c1bdf5c23ac38( - *, - items: typing.Sequence[typing.Union[KubeClusterRoleProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__6faf558e694a82d5282c1ee1c2544179d7e40c708128f00e73fbc361becd9539( - *, - aggregation_rule: typing.Optional[typing.Union[AggregationRule, typing.Dict[builtins.str, typing.Any]]] = None, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - rules: typing.Optional[typing.Sequence[typing.Union[PolicyRule, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__d8eff1e5ed3dcdcfd0064a2af74f4bb031286a15e4ced98c55de4d26be394984( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - conditions: typing.Optional[typing.Sequence[typing.Union[ComponentCondition, typing.Dict[builtins.str, typing.Any]]]] = None, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__0d9905c184dc69ca415f46304054e8fc5f1fccdfa501490bb06a6ae27a2d0ba1( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeComponentStatusProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__5c9df658fe078e86baff4d98993a70937fe9986e7be888a790e26f3c6c308a3c( - *, - items: typing.Sequence[typing.Union[KubeComponentStatusProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__67f24fea501ac86ffd29cd8da4d47fae1b8eb42d42c249efb3614ebb5feb3863( - *, - conditions: typing.Optional[typing.Sequence[typing.Union[ComponentCondition, typing.Dict[builtins.str, typing.Any]]]] = None, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__44ace9753e03a95f69ddde69315c9f4f0d5af51063739be870b98c92d1309343( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - binary_data: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - data: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - immutable: typing.Optional[builtins.bool] = None, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__bc144a49936aebdfc387ec91a45153a5fd302f7ee0809a80a9ce001cf966a1ab( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeConfigMapProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__48767662592e262431179254e449350dab987b1cb93287f37b377cb0152ccfe0( - *, - items: typing.Sequence[typing.Union[KubeConfigMapProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__1a39b77b09572a5978b914a6a73c5b5de4761e48a8d3b3d72892406c734d515a( - *, - binary_data: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - data: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - immutable: typing.Optional[builtins.bool] = None, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__3f6bf27fc901e0e15fea30db5d1c34b86ec9c3614e410979df0e341049bf3822( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - revision: jsii.Number, - data: typing.Any = None, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__53efa27ce81b16cf7569d10e432e48ab5aea03632a8afb6454ccfa8e6454c620( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeControllerRevisionProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__b4279c16d501dc382f5edb2bf61182477b32760c149cdd162209ec9571c29ccf( - *, - items: typing.Sequence[typing.Union[KubeControllerRevisionProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__2de468b613a3e33f95f5158a17d168ea0ab46ec3ccc31df40206c6abcc1e847c( - *, - revision: jsii.Number, - data: typing.Any = None, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__6f1a45e449c623808f20a18094f28e7c251c7307291135b721a1487e56524e00( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[CronJobSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__bcac49fe1ddc47b748d3a574b6b07b351b0ff80b7dc9c34aa888370f7d9b0db7( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeCronJobProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__06c3ad596042c9920e15bed2efd12904b2272ff2c9e68409c0600e6a9c884986( - *, - items: typing.Sequence[typing.Union[KubeCronJobProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__8c260e3c5e7fe913831f1f3fd5594cf9e987523fa1fe919b7bd14b3830dc4259( - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[CronJobSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__6e7e584127b81c956ad07d8cf4276ab9626e642741a92936946c0e875c29d3a1( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - spec: typing.Union[CsiDriverSpec, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__b44071bd892488f6cfd5df886a9920126e60fa5a0934f4b7139d3fb2d7d22baa( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeCsiDriverProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__8a6ccbefd0e7c044fdda4f1e093169516e8d19ebafaa273f96679b9ab863cdf9( - *, - items: typing.Sequence[typing.Union[KubeCsiDriverProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__192ebe10745c7f8861d48c71de7ec8b38130461925dd6355d7c98af27ca4a75e( - *, - spec: typing.Union[CsiDriverSpec, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__7dd065420aed16ce38e08784b9f9c9401b5ee146421a5de47261e92390d97f7f( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - spec: typing.Union[CsiNodeSpec, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__0deee8737363a6bd1dbec0ca3dacc8cee5d8804a1ad839104355341fbb23d96e( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeCsiNodeProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__66913be37f64f6682b27e7f3a521516525d302b97ec992adec50d5de0ba5090d( - *, - items: typing.Sequence[typing.Union[KubeCsiNodeProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__42b00c3000fc9438453d9f4f95e20b93766d5f40f65fce8ca9b29b21e1ab5b96( - *, - spec: typing.Union[CsiNodeSpec, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__672a59a6175ac3d81f59910bb1d738e8e11c47b69c2c3db2480f4a98e073f0df( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - storage_class_name: builtins.str, - capacity: typing.Optional[Quantity] = None, - maximum_volume_size: typing.Optional[Quantity] = None, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - node_topology: typing.Optional[typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__26349328195cfeb3eebe739f212c79b7cd4474d7dcb20a0a0589a9932a0d1b21( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeCsiStorageCapacityProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__65f4b3047ee5f0d908b2716319143dd4ccd26083f8d0735e0801a078fe3d839a( - *, - items: typing.Sequence[typing.Union[KubeCsiStorageCapacityProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__661ec608be88da1c7692b081e6f7c74ef61ce4e8d4a37bd7ec5da8d2611cf0a8( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeCsiStorageCapacityV1Beta1Props, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__400eae37cc38d2ad1a0f22a496ee8496cb5d543295c2d8fb25d899afe6986998( - *, - items: typing.Sequence[typing.Union[KubeCsiStorageCapacityV1Beta1Props, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__fdfcf2ccfe14adfd27a6bbb6dc09e54facd4c0be62f6bb48afb0ce7b0e5f31bd( - *, - storage_class_name: builtins.str, - capacity: typing.Optional[Quantity] = None, - maximum_volume_size: typing.Optional[Quantity] = None, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - node_topology: typing.Optional[typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__cce715b0cafab1814f8745ad981ca208df4018c7a12f6d649842f804831cf83e( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - storage_class_name: builtins.str, - capacity: typing.Optional[Quantity] = None, - maximum_volume_size: typing.Optional[Quantity] = None, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - node_topology: typing.Optional[typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__8418b166e025fb1853c1ac02bf35c29f522036d884cff7a2ce4f670249d87d99( - *, - storage_class_name: builtins.str, - capacity: typing.Optional[Quantity] = None, - maximum_volume_size: typing.Optional[Quantity] = None, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - node_topology: typing.Optional[typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__334b5f39cea8395ab2e2384ecfed468321d1dfffaf1287949e0062ceeb5f21e2( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - spec: typing.Union[CustomResourceDefinitionSpec, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__62a298f00bfce341f3c14b23cd20df7fd098569753f147819ade11b8eec605b1( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeCustomResourceDefinitionProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__1f2426ee351c62ae7b958ae547946c551446a7db0fe0c9ccdaa7a2c0f038b9ee( - *, - items: typing.Sequence[typing.Union[KubeCustomResourceDefinitionProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__44acb3eb0ed88657237084766aeeb318a33cb87a320ff83db090657729bf6a38( - *, - spec: typing.Union[CustomResourceDefinitionSpec, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__e6e8fa30f38ce100278001efebe064bf62d0a0cf7e9f6a251b4a468ea63e5b8a( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[DaemonSetSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__7f2704f8f4ce59ac94c9b58e78430742d4a18fba3f41ec245074edd74b149be0( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeDaemonSetProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__abb376a268375c85da81816f728709a72ab35d8db244a766b4b858a0479a2d2f( - *, - items: typing.Sequence[typing.Union[KubeDaemonSetProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__8fbbc65d9c988de23c71a61edaf7bba46d33be225fd1159056e6bef26714816b( - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[DaemonSetSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__5e1e2a79d85486449fa0833d4177ee006fe290e62f76e13917ded50a2b61ba2d( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[DeploymentSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__8338f8fe3af7e0a8022f1814586a09e0d841fc7164e1523e8640ea827a30f1a9( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeDeploymentProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__6c281c2946d751d060ba2a36cc155cd227429237972a82bf34b0aa5ec907a092( - *, - items: typing.Sequence[typing.Union[KubeDeploymentProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__3f938ae7726ab98563b8c569f39380bdfb08ba493b5b18b7911fc99dd59fca9d( - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[DeploymentSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__4a3aca436c82217519bb07237133dd6f4d2c21c528a0a7e98d7963d8062245d1( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - address_type: builtins.str, - endpoints: typing.Sequence[typing.Union[Endpoint, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - ports: typing.Optional[typing.Sequence[typing.Union[EndpointPort, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__a4184b57cf196b9cf44ae6f0a3e88a09792447aa938bae1ad32ddf0430cc8472( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeEndpointSliceProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__893756756978bc6e8b8cd4f9974acd87d10a41169ee8149b2474685511e1202f( - *, - items: typing.Sequence[typing.Union[KubeEndpointSliceProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__d5a0710afc3e844c1100b501405d8ce44983ec5b3c3f16765cabf7c83048029e( - *, - address_type: builtins.str, - endpoints: typing.Sequence[typing.Union[Endpoint, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - ports: typing.Optional[typing.Sequence[typing.Union[EndpointPort, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__07c03de2e3c29871d33c0d6587ce2a4fb58f9ad5c55ff53ae8ca18161ca8f75d( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - subsets: typing.Optional[typing.Sequence[typing.Union[EndpointSubset, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__f7ec0ee98c97171c7128134d941789c4354bb07ecb52a28f275a4b6010dc9009( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeEndpointsProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__dabdb04acd54ff7c5f4be3268ab8a4d155c02f3b13492e7bc3edd37ae5e31e6e( - *, - items: typing.Sequence[typing.Union[KubeEndpointsProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__0dbeba4d3e9f8a17aefc98d861feaeeb225997236ef3922454cbd361215afdf7( - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - subsets: typing.Optional[typing.Sequence[typing.Union[EndpointSubset, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__bff248256702fdbc7f8830bde32e723508feda5df87528f11bc2ce4646805a0f( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - event_time: datetime.datetime, - action: typing.Optional[builtins.str] = None, - deprecated_count: typing.Optional[jsii.Number] = None, - deprecated_first_timestamp: typing.Optional[datetime.datetime] = None, - deprecated_last_timestamp: typing.Optional[datetime.datetime] = None, - deprecated_source: typing.Optional[typing.Union[EventSource, typing.Dict[builtins.str, typing.Any]]] = None, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - note: typing.Optional[builtins.str] = None, - reason: typing.Optional[builtins.str] = None, - regarding: typing.Optional[typing.Union[ObjectReference, typing.Dict[builtins.str, typing.Any]]] = None, - related: typing.Optional[typing.Union[ObjectReference, typing.Dict[builtins.str, typing.Any]]] = None, - reporting_controller: typing.Optional[builtins.str] = None, - reporting_instance: typing.Optional[builtins.str] = None, - series: typing.Optional[typing.Union[EventSeries, typing.Dict[builtins.str, typing.Any]]] = None, - type: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__e546e7e1029a776b150b1d203fdfd30b45f89d03516fbe6b00d28c4dde254656( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeEventProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__f1413ee6881591e1991bd16a7298ddbd2f5adf1365ff312c068728af9df75f5d( - *, - items: typing.Sequence[typing.Union[KubeEventProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__48c2a6f443e17733c15e46b85814aa0990b46cd3a60cd4b9a9dbb71d3d3e844b( - *, - event_time: datetime.datetime, - action: typing.Optional[builtins.str] = None, - deprecated_count: typing.Optional[jsii.Number] = None, - deprecated_first_timestamp: typing.Optional[datetime.datetime] = None, - deprecated_last_timestamp: typing.Optional[datetime.datetime] = None, - deprecated_source: typing.Optional[typing.Union[EventSource, typing.Dict[builtins.str, typing.Any]]] = None, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - note: typing.Optional[builtins.str] = None, - reason: typing.Optional[builtins.str] = None, - regarding: typing.Optional[typing.Union[ObjectReference, typing.Dict[builtins.str, typing.Any]]] = None, - related: typing.Optional[typing.Union[ObjectReference, typing.Dict[builtins.str, typing.Any]]] = None, - reporting_controller: typing.Optional[builtins.str] = None, - reporting_instance: typing.Optional[builtins.str] = None, - series: typing.Optional[typing.Union[EventSeries, typing.Dict[builtins.str, typing.Any]]] = None, - type: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__ce3fc7d57adcd46be2dfb9bf2c29323102143783bface1d1cbd34980309078ba( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - delete_options: typing.Optional[typing.Union[DeleteOptions, typing.Dict[builtins.str, typing.Any]]] = None, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__87cf0d2be9c3f9f8ef8e2278ad8544565ff3211d2445691804c2609bf06a14a3( - *, - delete_options: typing.Optional[typing.Union[DeleteOptions, typing.Dict[builtins.str, typing.Any]]] = None, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__78dcce4ae43399b690dc9289853b5102369f03ffcdfb89350c8411a78672d51b( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeFlowSchemaV1Beta2Props, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__7840b0ea66b23c128361bc5a2f5b97608be83a0c9fb75ed5aa96409d669ab7dd( - *, - items: typing.Sequence[typing.Union[KubeFlowSchemaV1Beta2Props, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__3d77a2bc947160fa8c8b7379c2b017e6bb43ad9bb7d61e92ce9feee34f94bfe9( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeFlowSchemaV1Beta3Props, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__9324188a061c5eae530453984a55d9350e8a735317db123e7ead7e0c73209b67( - *, - items: typing.Sequence[typing.Union[KubeFlowSchemaV1Beta3Props, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__7a45c05db0efb498337d9fdf72478dae3390139a5e4eb9ef9809436601b2a0da( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[FlowSchemaSpecV1Beta2, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__e106d80425e44c2dfdc8be52665b26e79dc781475001784de3ddaa904271cc59( - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[FlowSchemaSpecV1Beta2, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__a9b9348b12fce50fb80513761ddfb24eea7f7945e13e61ce1aa0681387d5b265( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[FlowSchemaSpecV1Beta3, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__6410a409fbe720f8a5200bbc56c83314c2abbde52a3f3e6d86dcffa538d45f0e( - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[FlowSchemaSpecV1Beta3, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__3659a33a1f8b87b529d9e9023dd6bb01e0bfb73facc829ec1a43b27043decca0( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[HorizontalPodAutoscalerSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__d083f278632697415785096091248f1e45891163fa170df1eb5824abc4d7153c( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeHorizontalPodAutoscalerProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__e26ffe8caa8bac98a411574cbd7526286da29c633ab894498e0b6be6bad7b5ec( - *, - items: typing.Sequence[typing.Union[KubeHorizontalPodAutoscalerProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__612b9b7f601cf85679f8310aba2b1726e9093cf95529f5cdb32980ecb876fc78( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeHorizontalPodAutoscalerV2Props, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__82d754c8d97bd9130289b15ea62a398adf7971a9304499522bbc19f063139128( - *, - items: typing.Sequence[typing.Union[KubeHorizontalPodAutoscalerV2Props, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__542b4bd5deadf3f3ea668c268b55d72b558ce8b50e724f90f1bae3abad482de7( - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[HorizontalPodAutoscalerSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__9ca507f6cd5ee9c7cea60234c215b0a4ffad2c91ec0a23f8d44798e355cbb065( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[HorizontalPodAutoscalerSpecV2, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__53e62de6a231cf1b2dd6d0d4c7bf7bca086b1fee4162cdbfec39861730181a09( - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[HorizontalPodAutoscalerSpecV2, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__fecb69d0c5ae696fc26dfb5e8ab4fdf624ec8c1b40d730da8ee18908df85a89a( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[IngressSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__d418ae2f0a6f2d90c9b2dd88ca1f6a84e3153a97a96e7ff6807e07b0dd61c0b7( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[IngressClassSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__bc0fa42e29a73942af0afef36f066bacef13f7e6faa1064781e6f6b6797cc61a( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeIngressClassProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__82c7c14ff0df4771b1efd0ca1f8329565f6bcd7e8eaa44ac5477a9fd2a3c41d2( - *, - items: typing.Sequence[typing.Union[KubeIngressClassProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__5ff63d6e124700008192e962f05892ebc82196bb74b11b70eaba4b39b70836b7( - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[IngressClassSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__f226e78ce6490682fe3c9a63b8ce32fe7c21b49aa9ce2e44e5b9fd3f61a3d60a( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeIngressProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__f7312bcea7e490386f6d60582abdc979996825d2af8c213e81cab63ed38979d1( - *, - items: typing.Sequence[typing.Union[KubeIngressProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__c6fb53470ef0dd80ea7bd4fef27d3ddf64cb7f36e5eea57e17b603eea466bdbd( - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[IngressSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__fff358859e9af9ea8332041ebc8c62133b4e15d6bae01f757722777868bbf975( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[JobSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__ebfb0aedffe4b9969191f6572e8cede1b485af52b80986d4fcdbaf0f5983cd6d( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeJobProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__8c68110c5b5d423614744f1c0238268018af1c5d3aac79966f04ee1b380605fa( - *, - items: typing.Sequence[typing.Union[KubeJobProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__d8623d11ce8ff4879cf0c14e0993080e88ac2cb1e525affa070848156c47f58d( - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[JobSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__9d7ac416a382b84ffda17705003bcb5bf298edcb4ce565074e252fb3615f92b2( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[LeaseSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__75166c72791817156d385921cd400e23041c5ec11ee91d66d38a9f3f2858d1b7( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeLeaseProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__298c44b61ec9eb849c15cf2a5e383a73704159b87103b7b3ad5e506767bc102f( - *, - items: typing.Sequence[typing.Union[KubeLeaseProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__087e36c33055af38c535d84159dc6ca27d3ac01c18260bfd1accaa57ca9e9f87( - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[LeaseSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__a07d6eaf25ce775558c3ff31cf7338c76165ccf4142236e04da563765d8cf0b1( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[LimitRangeSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__c7a8f8a9863b43e2fd00c4b8c7d258d2c05e91ae89be7106f6de4aed120b72db( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeLimitRangeProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__1ddfc6edaee1a35d88f539af8024140cdbeb093b064f536ca3b5b93e5ccaba6c( - *, - items: typing.Sequence[typing.Union[KubeLimitRangeProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__2f09492d34c2b6f246cc5363c69827532389bf688a8153b21d1be33b85f10e08( - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[LimitRangeSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__cdf9554ef0e379495534a1087b68841710eca3f0d932611510b7ba25ae57d8c0( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - spec: typing.Union[SubjectAccessReviewSpec, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__70906afc8c383c855cbd20f07b10abc432f25794647078ae07044f7af0aecd01( - *, - spec: typing.Union[SubjectAccessReviewSpec, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__78fbbe028a200f70510169b8127ab5f20fbf81ad5ddeeea991e488779448b60f( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - webhooks: typing.Optional[typing.Sequence[typing.Union[MutatingWebhook, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__85169c24c76c15a829cd177c34e67d5781ce9a0ad8b7556ff48f987f00297ec0( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeMutatingWebhookConfigurationProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__1c5bb2cd72caaf431cbf1350e28d2e0bcdd4dbf8a7a42278e8f2bea99bf5e665( - *, - items: typing.Sequence[typing.Union[KubeMutatingWebhookConfigurationProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__dcc8f1c51a09b8fe278a8bee5d20fb75c30d888189811d6a2f4a60c0182384cf( - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - webhooks: typing.Optional[typing.Sequence[typing.Union[MutatingWebhook, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__6f6e25823687f32bbbae9c3f609a0a538b76fedf96c8ad3f980c332a61ece4d7( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[NamespaceSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__01d5f81c2dc4b588166fb78ad26a95dd96f084900df60db1eef3c086859371cc( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeNamespaceProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__ce390ce5e8435afb3fcc00c620b42a1bcc0f105b5ece6671255dfd268155ef06( - *, - items: typing.Sequence[typing.Union[KubeNamespaceProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__e949e610104e12f08b92fa062a63801c86734b9c1a875a1871c872376e5f48f5( - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[NamespaceSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__3711bfdbb9ff2b20fcc1d837ff64f7be94291bbcbda2f8e20d3fe735d0fca788( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[NetworkPolicySpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__00430867067236e8cdbeb77ac9ba9e262f12d9a45a20172656a49f0096a6a0fa( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeNetworkPolicyProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__b302db7bf53a96dc070815693c9fbbe25197993b09e83ed216e2ab04dea04a7c( - *, - items: typing.Sequence[typing.Union[KubeNetworkPolicyProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__56f98657e1b111a4046c2a9c0419040c502cc5aa1a89c7cf31c45f390c9d36f6( - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[NetworkPolicySpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__9d26fbe2f6299bf5a92f7395765819856b261fc03eda02a9a56f93d5b7387ad9( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[NodeSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__8f7dc24543b0e86588c1d33f101b19fbd515d5284e141acd3821411e47509e33( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeNodeProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__5390372ece82529262be3baed0dd084e87300d8b0e3a8999ebe4dde860bbc9d5( - *, - items: typing.Sequence[typing.Union[KubeNodeProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__8da3066966e9bc82c9130ec84a7522be8c5dadb42ba10b9448c9336ca5c791b4( - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[NodeSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__12bf57b692f7f69fdce50d1cd90aee7dac0c22bd6db1ac7fcdfc312a4655c48f( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[PersistentVolumeSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__52de231eda8f9efad578bfd47588cd714011f8b2ef9871fb4aa8ea7d11990c24( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[PersistentVolumeClaimSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__715fd5e65023048e75b48ea598d1ac99e0a7d2546108f2b88ab23ec45963900b( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubePersistentVolumeClaimProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__fcb84271af780f85ce85f44dfbd05476e40e28da01cc541644af7cc50e317760( - *, - items: typing.Sequence[typing.Union[KubePersistentVolumeClaimProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__b414219b4cd98868a08f6b7fd13ba03bb20c34f93bab1c6766671850b87da5ba( - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[PersistentVolumeClaimSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__20543683b7b15c750805ae3b00ee8120f78f9aefc5d6360da9191b713c8a3df9( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubePersistentVolumeProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__edf32a684938145a8c425ea13a1f6c2a5251323dae13a0c7266e5144002b58ea( - *, - items: typing.Sequence[typing.Union[KubePersistentVolumeProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__b6dbdf4915f5c3999c02319ddabd6bc2300a3ec520d35a7124154a1d0c74b284( - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[PersistentVolumeSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__84a44a2c055874076c014e7b070891672ce45fae07fc36b0223efb3b157db547( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[PodSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__a57adcbd50267ff3f43029f0497ba1eecdf3774ae3544c7d0d200eb6af32af47( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[PodDisruptionBudgetSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__5b28042f5f757861077d829159ace796645ed62a098c4b7445cc49d65bae4e39( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubePodDisruptionBudgetProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__46fe8577d9d9bc235b20f9635bed1bb38c4182635cbbbd4f777b9ecddafd24d4( - *, - items: typing.Sequence[typing.Union[KubePodDisruptionBudgetProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__bb3fa1126b3b2249e66d034d2cb0c2af262892c5e513cb56fa7071cbf1f323b4( - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[PodDisruptionBudgetSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__26810161725b72ec95fed518f5f1bd2878189eec88948e1665c6504f0e1c80e4( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubePodProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__6c6da0c93bfd87422fec0434260e7ca746775802e283035b82a97804b6a5cbad( - *, - items: typing.Sequence[typing.Union[KubePodProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__a49e5de6a1c7d64f87b3fd99f6f3a7f9173827eb846d6b3423f251cc8e6dee73( - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[PodSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__ca5c307c4cf8c1a6abfe2594c184c4510f1f094dbb431db9ed4c05139b0636a3( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubePodSchedulingV1Alpha1Props, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__7a3f9f9a13fab7ad4309606460387114d09f26fe708e57d0ade367760eba22d4( - *, - items: typing.Sequence[typing.Union[KubePodSchedulingV1Alpha1Props, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__3f4856868eca18e4ac926608e85a1bc5de5344771a17d102cda0ca44b4a61ee2( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - spec: typing.Union[PodSchedulingSpecV1Alpha1, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__b8378dcaf5913bb1f58986bd024042b8cd1b3448b4c03b331937a17870ffaac0( - *, - spec: typing.Union[PodSchedulingSpecV1Alpha1, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__0ef25d47e407a94a1f7c5da1b4a8137999b9f10f2eb06612819328e43413ecaa( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - template: typing.Optional[typing.Union[PodTemplateSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__e1a00fe17edb33a47aa58d4b3bdf326f8cd52b6c5fa5b4b447fef63416e0153a( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubePodTemplateProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__db699f3f7785aaafe421c68826e9aee0751d2471a5f84fcd072d2dc7bf1e42f6( - *, - items: typing.Sequence[typing.Union[KubePodTemplateProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__b1246c731572d1c19b516cbd1928d932af12c395562d89193038a193dc8c19d6( - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - template: typing.Optional[typing.Union[PodTemplateSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__7849121f7cc4169719bf7c0334ed5b358df3185c443cdcca26f3ba64a177342f( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - value: jsii.Number, - description: typing.Optional[builtins.str] = None, - global_default: typing.Optional[builtins.bool] = None, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - preemption_policy: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__925536e8f6c1bb4cef79d5881b407f57c20a6380415cbaf45a82301ab03c453c( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubePriorityClassProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__00e2a2b2d5dd902a6c32a404e9c7208d7bfc775f9ade4170dc45106963c0b49b( - *, - items: typing.Sequence[typing.Union[KubePriorityClassProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__d2a7a0f6e62dd93fbc211f3259e5bdec03162b72d41924ec9b0431446407d338( - *, - value: jsii.Number, - description: typing.Optional[builtins.str] = None, - global_default: typing.Optional[builtins.bool] = None, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - preemption_policy: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__b037d843ce4cd847a493957e491386d8281a274d20cb7ecfd13937547ca54046( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubePriorityLevelConfigurationV1Beta2Props, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__a6a9dc2a0db58fcbfb69d80748f76fed9e1834c5756fcc6381cf1cbb86af3654( - *, - items: typing.Sequence[typing.Union[KubePriorityLevelConfigurationV1Beta2Props, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__64fe405e3b84d29190baf774ed90a32c12ed6a17a342bae6b6bb18c8e57ca058( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubePriorityLevelConfigurationV1Beta3Props, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__8a9a2b4f57da24e68294448c136ed1b7f46757a2e39eb80d97db30d3fae1887e( - *, - items: typing.Sequence[typing.Union[KubePriorityLevelConfigurationV1Beta3Props, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__a6c55383ef965654b933b8b84cb96236498acefe9c7f0b588064162d95585f05( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[PriorityLevelConfigurationSpecV1Beta2, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__ebcd2e792a37c952b3b0359c48478c4abfbe9ef8402855ed70cefd8874e5696b( - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[PriorityLevelConfigurationSpecV1Beta2, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__e5b00c189c9bee05bebcfdcd22a465297c6da0c35fbc81c5172ea3c48f65b7f2( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[PriorityLevelConfigurationSpecV1Beta3, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__77fb534a06fef313d54401762de300dc3563bf4d8411dada16072154c0234ba3( - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[PriorityLevelConfigurationSpecV1Beta3, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__10b1e6952ed8e4461a4c7cb6055b12f7d11053876688102605ac9643cba57005( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[ReplicaSetSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__24d3450455c5e97bf49cda54253c588d8a6ee19f76f1cf671ba9f98802a53d99( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeReplicaSetProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__62c387938d1bc321eddeb2ff018f798c1e609329bfdcd7b74261bb70e472d00f( - *, - items: typing.Sequence[typing.Union[KubeReplicaSetProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__3356ec84091f3836aed86951b46f5c67fde6b2669f3404b932d0ffb3aa92b8b1( - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[ReplicaSetSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__b76c77ebee47f8e1db2fb813b337b8d1cb81ba43cc3b5afa6d87b4d42f8ccc27( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[ReplicationControllerSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__b3b728b8344327bdb06c9b83008eeef39b961f93e5cf0c03f478bfe4429bc465( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeReplicationControllerProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__9883740538c9153a5fd5f360dbdefcf08f177d9bcc570eb8535695b601d2cc31( - *, - items: typing.Sequence[typing.Union[KubeReplicationControllerProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__d1907ebb731e0f56418eaea7fe01ae75a6a0f7a66fe54291e68654e7347b8e5c( - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[ReplicationControllerSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__e200cdf7bdfd425880660ef6ebcb90da88783cb7874f700af41261d226802408( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeResourceClaimV1Alpha1Props, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__de1fd43faf0ba317c36809119ca61ff37dc7311bff784a153466481f3c1f7aac( - *, - items: typing.Sequence[typing.Union[KubeResourceClaimV1Alpha1Props, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__6fbb34cbc640559672bb256ab485dc10d838f47767a362a9647924f5939ec9b7( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeResourceClaimTemplateV1Alpha1Props, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__28698822e45bda3d63db1ad3983a08b594ae8089817211a639d0d2b2212c5c0e( - *, - items: typing.Sequence[typing.Union[KubeResourceClaimTemplateV1Alpha1Props, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__19b55a664e022e7cf75a2e7db6a0c16e6791ff0f493db7b0ac8902687bdfc771( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - spec: typing.Union[ResourceClaimTemplateSpecV1Alpha1, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__895c0745ae5288dd68b676af5ebba5862e4ff365a8b6cb7256b72cebb64ed32f( - *, - spec: typing.Union[ResourceClaimTemplateSpecV1Alpha1, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__a1f97fddc933efea2a1616dae66764060c73225f24ca19f70ab4da1cff53e88f( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - spec: typing.Union[ResourceClaimSpecV1Alpha1, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__881875cd1d5513534efa2e6323236285dc2d6c692541f339978f5f88cbd7191d( - *, - spec: typing.Union[ResourceClaimSpecV1Alpha1, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__e1695fa3fd0da9c0899fd14ab89c516ae780955a7fabddea610d77da29a44ed4( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeResourceClassV1Alpha1Props, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__ac68af0f54677d6e7e28921a84e980663e5bbd36841ef1ddab313b91449b124a( - *, - items: typing.Sequence[typing.Union[KubeResourceClassV1Alpha1Props, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__73e955754ed6b0a944de335f682e555ee872f783b244a6172a6174b18e2953f2( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - driver_name: builtins.str, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - parameters_ref: typing.Optional[typing.Union[ResourceClassParametersReferenceV1Alpha1, typing.Dict[builtins.str, typing.Any]]] = None, - suitable_nodes: typing.Optional[typing.Union[NodeSelector, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__4dcda1419c55ac01a43092063ef99623f9153c117048d8a4d4a0ebd85bae5430( - *, - driver_name: builtins.str, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - parameters_ref: typing.Optional[typing.Union[ResourceClassParametersReferenceV1Alpha1, typing.Dict[builtins.str, typing.Any]]] = None, - suitable_nodes: typing.Optional[typing.Union[NodeSelector, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__3ac4857c79a81ca461b8b100787cc5d2e4fa270a239531d0b264e7c1c647ebbc( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[ResourceQuotaSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__1c8449d16fa5f0f57efb0bf048a173204cb2eee0724e5beee1997b7fd6446ae2( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeResourceQuotaProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__fa8b7d22abad60c9e4fcd3d3a379006b596879c4f9044fb09d9e785c02019aa7( - *, - items: typing.Sequence[typing.Union[KubeResourceQuotaProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__659f76ba4ff363b4daafbc9b629fcbc230c1a0e0e932683b9fd35f50e4d29548( - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[ResourceQuotaSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__29ed150ac8d5e84462d3788ba6966b3d87204185e9002d23a85b76b17ea79449( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - rules: typing.Optional[typing.Sequence[typing.Union[PolicyRule, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__2165aae46dbd747e3dfe47c03209e8f301ca3f4ac24494fe9f9cda773496d188( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - role_ref: typing.Union[RoleRef, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - subjects: typing.Optional[typing.Sequence[typing.Union[Subject, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__f87b0d405558e8e0b39449098e57a74cf3f58b136a74b32013664caea0d5c426( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeRoleBindingProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__0ea68389c941015338a6dd149e67bba16f03189d9fca5c31ff0b58b27c250791( - *, - items: typing.Sequence[typing.Union[KubeRoleBindingProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__8a2b8de1d0bd2d542efd8d7543a30c1daee70a3e4a630cb0ef968ba5f26deb1d( - *, - role_ref: typing.Union[RoleRef, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - subjects: typing.Optional[typing.Sequence[typing.Union[Subject, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__33688bb860def340a9dd80a000256bd8166770cd75a90c4230022160b6b60fa3( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeRoleProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__47ad3ce5aaac7e92b0ff56cef58990cd52e68663c4295dd4088db5f6306dfd41( - *, - items: typing.Sequence[typing.Union[KubeRoleProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__03f10491b2f4c7a09738e2bec5b9b83fb9ac2df6d87e8a3a04a69a591071960d( - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - rules: typing.Optional[typing.Sequence[typing.Union[PolicyRule, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__73e802aeb77adf68ded78bc844e953e29156ea338b23850869f1eb458d0535ba( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - handler: builtins.str, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - overhead: typing.Optional[typing.Union[Overhead, typing.Dict[builtins.str, typing.Any]]] = None, - scheduling: typing.Optional[typing.Union[Scheduling, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__b5d566a802c97a52571a895dd9503f614c01f4aca1f561b22f26cc02ba498284( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeRuntimeClassProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__235ff08f57089721a1cc755e07eeac0f1cf566b511fa57277b1026eb51582c2a( - *, - items: typing.Sequence[typing.Union[KubeRuntimeClassProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__66d9897bab16ca27a49026227ad29d408015abcd5910370e14974dcb1b0a858e( - *, - handler: builtins.str, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - overhead: typing.Optional[typing.Union[Overhead, typing.Dict[builtins.str, typing.Any]]] = None, - scheduling: typing.Optional[typing.Union[Scheduling, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__9b1969418b2c3135a3004bf63bc8af2d184c22929c1fbbbb43547d0537ad13fc( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[ScaleSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__13391d438725de4a637b7b0d0a5bd88c6ec8637161c91c5b416382d69c1a3ab7( - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[ScaleSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__58e682738c653346c651cc36d3c734a00b97388b8a9fd3f9cdc4718f06a89355( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - data: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - immutable: typing.Optional[builtins.bool] = None, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - string_data: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - type: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__dc75a614004131c047322f90f10784835a1f3438fc40eba549cef8b51c8279a7( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeSecretProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__68a713428aa6f657fd246ae3b43b8fa8e61bb28094b94473804b537cbefbc6ec( - *, - items: typing.Sequence[typing.Union[KubeSecretProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__63ee35f74b966b919ab03aa2ea463b9251eb7bc667ff598909abc78e4bdeaea6( - *, - data: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - immutable: typing.Optional[builtins.bool] = None, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - string_data: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - type: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__df9b9cd04099ed39eea458145ab91abff6e618a668a3f190dd8dd744c3510f27( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - spec: typing.Union[SelfSubjectAccessReviewSpec, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__eb99da3761969040fbad9ae0f21de6f39fd7f9db7330ac8a2e14fd12dbe08b62( - *, - spec: typing.Union[SelfSubjectAccessReviewSpec, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__dc60febb32a5f5f830b0cbfeae492a65d79ebf66796edf824b494c89482a7e3f( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__740c60c3b930f3570c75be79b9daab533abd7ec5f3e5998f46de9d7e22d8dd90( - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__958ad9ca21d898b2c0171fc826e39e897cf8dea21c3e45749b9459904cb9d316( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - spec: typing.Union[SelfSubjectRulesReviewSpec, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__28a64acd86978440d745bb1246cc04b86d29d6d85116e22b178d1054e6389b67( - *, - spec: typing.Union[SelfSubjectRulesReviewSpec, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__ae5267509ab57695c0bcbad4782a5c278f89e6749acf2e274e7fef884ff7c154( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[ServiceSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__e5e237c758b7687f05aeba33ce7b5312826313f3a39706ad9f17b91865051abf( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - automount_service_account_token: typing.Optional[builtins.bool] = None, - image_pull_secrets: typing.Optional[typing.Sequence[typing.Union[LocalObjectReference, typing.Dict[builtins.str, typing.Any]]]] = None, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - secrets: typing.Optional[typing.Sequence[typing.Union[ObjectReference, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__f86f64fd2fbbd19af1e77f68fedbf039aee41aa5d18ecc31b5ef98921f5a8a25( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeServiceAccountProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__643831477ea8dbd90061f7f5cc95e1a83af9e4fdad06f1b94b48253d8f32f842( - *, - items: typing.Sequence[typing.Union[KubeServiceAccountProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__ec9a6be9029d2ceb1c08d223e9b02d893a24441944fdbe9ad2eaa60dc6e92fb8( - *, - automount_service_account_token: typing.Optional[builtins.bool] = None, - image_pull_secrets: typing.Optional[typing.Sequence[typing.Union[LocalObjectReference, typing.Dict[builtins.str, typing.Any]]]] = None, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - secrets: typing.Optional[typing.Sequence[typing.Union[ObjectReference, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__86886b0bfb469dbc12b9a68cef4da02889f1ee314d709a8e71414cc8031cfed6( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeServiceProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__59198a82aa11d0d9508f7dc568777e1717191f7b72d24ffdc52ce442de8d3c85( - *, - items: typing.Sequence[typing.Union[KubeServiceProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__645975c208c0e6b41f85f3d3300b485fbb81771422750ddca1d83f18801e711c( - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[ServiceSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__312da024b0ac59942da22a6230187a87d3bbc5ff2eced525e6d591ec5c4ac0fd( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[StatefulSetSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__8c61b86fcbbb88c288e62d1aeb4e69b71ab9619771039bf5b77239a716db57dd( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeStatefulSetProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__860181d5582a30497e3a5c2f4a313c6a4b92df72cfab5a28201a1e2c12cdd5d5( - *, - items: typing.Sequence[typing.Union[KubeStatefulSetProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__9415c25af12fba9cb563f49680ded90088a786ca6ef171beb298495032382794( - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[StatefulSetSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__5cd6f81cf090a4033a6f747068175ccdd01d276de8560fa979a1eea0da875d99( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - code: typing.Optional[jsii.Number] = None, - details: typing.Optional[typing.Union[StatusDetails, typing.Dict[builtins.str, typing.Any]]] = None, - message: typing.Optional[builtins.str] = None, - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, - reason: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__4143b0ac58cd2ed3e56cba31c073cbc2ecd0f798e3c8eba8c4aa27bf03019254( - *, - code: typing.Optional[jsii.Number] = None, - details: typing.Optional[typing.Union[StatusDetails, typing.Dict[builtins.str, typing.Any]]] = None, - message: typing.Optional[builtins.str] = None, - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, - reason: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__047df7981d1ae82b04f2e59adc1e0b713c54c65e95598c90ab39efd0bbcffb11( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - provisioner: builtins.str, - allowed_topologies: typing.Optional[typing.Sequence[typing.Union[TopologySelectorTerm, typing.Dict[builtins.str, typing.Any]]]] = None, - allow_volume_expansion: typing.Optional[builtins.bool] = None, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - mount_options: typing.Optional[typing.Sequence[builtins.str]] = None, - parameters: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - reclaim_policy: typing.Optional[builtins.str] = None, - volume_binding_mode: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__bf39d1bbc80954512531c8ebbcfaeb459523317cb1f4375b5090a4c2a1c602f4( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeStorageClassProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__036f96145bee86ebfca9cb6d6479755dc2a261bf7c08a4d2e572d758d0005bf5( - *, - items: typing.Sequence[typing.Union[KubeStorageClassProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__3697ffdc356ed18bd130e122d368bb18f095fa7f9f60844c7c50e565931d0f37( - *, - provisioner: builtins.str, - allowed_topologies: typing.Optional[typing.Sequence[typing.Union[TopologySelectorTerm, typing.Dict[builtins.str, typing.Any]]]] = None, - allow_volume_expansion: typing.Optional[builtins.bool] = None, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - mount_options: typing.Optional[typing.Sequence[builtins.str]] = None, - parameters: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - reclaim_policy: typing.Optional[builtins.str] = None, - volume_binding_mode: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__6bef958a387947bcbcdbaaf4348094be86a7afa3a9acd45c6af4fa3f17a69374( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeStorageVersionV1Alpha1Props, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__19ee4dcbe1aeb266f148e1052692cd8958a0190c04daee972cd1b30ba28ce226( - *, - items: typing.Sequence[typing.Union[KubeStorageVersionV1Alpha1Props, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__cc83b314c4364ad0b9556dfaf2c46909a2a42787e7446c3f1febc8414b884180( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - spec: typing.Any, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__ce0ae7328893e918f22537ca4ff18691995679aa30d67b8739ecb52c8707ba18( - *, - spec: typing.Any, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__37315244b0b06d4a6c0153890d8b113b5be8f7e3f4a53706dc5bc0f2430750e9( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - spec: typing.Union[SubjectAccessReviewSpec, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__11cdd3c28c7b3734c17f57f7700873f376c05d84eb4ac3686850aba44049b917( - *, - spec: typing.Union[SubjectAccessReviewSpec, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__474147e21deffaa53de4be8235f1e51831b183ee5ffadd3666a10e29d2a2f678( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - spec: typing.Union[TokenRequestSpec, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__56b2d758ed6094af31246d270d662cd4cd5baa62a9a3db945fe752d8a0c8b2ba( - *, - spec: typing.Union[TokenRequestSpec, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__26b5a5f85fa4a9cd06563e623d28b06fe5cb2ff87240ba40c3ffd54a769b1b7e( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - spec: typing.Union[TokenReviewSpec, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__fdad9a9e34ccb530008909556ec697b7e32e7e75a62c0a40b2de70d6f94defa9( - *, - spec: typing.Union[TokenReviewSpec, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__aba7512ee266951498a04cd9a269f09706de6ad19ad3648606375a371fb62628( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Optional[typing.Sequence[typing.Union[KubeValidatingAdmissionPolicyBindingV1Alpha1Props, typing.Dict[builtins.str, typing.Any]]]] = None, - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__58df6ed691a95aca20efd7ea05e0fc7ba9fc3d6f3743649a0799ed2ed11983ec( - *, - items: typing.Optional[typing.Sequence[typing.Union[KubeValidatingAdmissionPolicyBindingV1Alpha1Props, typing.Dict[builtins.str, typing.Any]]]] = None, - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__56be5cfcf392871de51369cb7627d15581b617ac5c85c34c2825c7dc7b3feaf2( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[ValidatingAdmissionPolicyBindingSpecV1Alpha1, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__02dcc69943131299a07758a92f8e2cda2225cdddcbbf84f8acd3bb912a2792da( - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[ValidatingAdmissionPolicyBindingSpecV1Alpha1, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__5a03cdbc2d5280c7b4ec9ffb4625db7a698d7ded6744c1e54ec807bff308084f( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Optional[typing.Sequence[typing.Union[KubeValidatingAdmissionPolicyV1Alpha1Props, typing.Dict[builtins.str, typing.Any]]]] = None, - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__27f6c645b042b326a7c234f10c50683e94fe2b281a2747e856507e896bcdba42( - *, - items: typing.Optional[typing.Sequence[typing.Union[KubeValidatingAdmissionPolicyV1Alpha1Props, typing.Dict[builtins.str, typing.Any]]]] = None, - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__40d71fe31ba527f1708a40aa586fc9c2850b09853dfc30d5893fce5bd4e83459( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[ValidatingAdmissionPolicySpecV1Alpha1, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__040f3513e9b89931f8fae1a4242c8701b631d9855f134d09d77119b9a1eee24f( - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[ValidatingAdmissionPolicySpecV1Alpha1, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__34e339703b236d0321dab9bd748a6980939b9f38a87e67f04aca4a50ee3aecf8( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - webhooks: typing.Optional[typing.Sequence[typing.Union[ValidatingWebhook, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__1103257d673223fc00aa538b9609e9e419b426afd25ebb3a9b7dc9e0e202d6dc( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeValidatingWebhookConfigurationProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__702f63ae21781f4ac2e03fa52d1a43aa7dd941efb0a90957cb50bb979345695b( - *, - items: typing.Sequence[typing.Union[KubeValidatingWebhookConfigurationProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__bc3909ca83dd252c0b1916ec5180a66b37a3898a0491cb64159a92891339f221( - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - webhooks: typing.Optional[typing.Sequence[typing.Union[ValidatingWebhook, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__7d33788b211c51d74f2a918fa8acbb6022d3dcfdfc9205cd1ccd06c35a1ca5d1( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - spec: typing.Union[VolumeAttachmentSpec, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__ab4791be96cea53663cb0786137bf6128b7451e4c73f0e202e0155efaf9d465b( - scope: _constructs_77d1e7e8.Construct, - id: builtins.str, - *, - items: typing.Sequence[typing.Union[KubeVolumeAttachmentProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__94942bd80cbcefacd1366946263ffe130479fa1a6a5daaf01c23920ee29e1db7( - *, - items: typing.Sequence[typing.Union[KubeVolumeAttachmentProps, typing.Dict[builtins.str, typing.Any]]], - metadata: typing.Optional[typing.Union[ListMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__9667f25c50a7755fb88e35e207298fc0e40ee7aed92a3420f75a02d74426c326( - *, - spec: typing.Union[VolumeAttachmentSpec, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__4d456112fc12591335ee47253835365291967e786ee79f8d91249182e98fdd86( - *, - match_expressions: typing.Optional[typing.Sequence[typing.Union[LabelSelectorRequirement, typing.Dict[builtins.str, typing.Any]]]] = None, - match_labels: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__e384e360ddc460b3a27ab64f240971fb10f71f62661ae8ee39b61341807594f2( - *, - key: builtins.str, - operator: builtins.str, - values: typing.Optional[typing.Sequence[builtins.str]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__401c15ef806c5b756921eeaf607340ba52477c9d6dab3b4ed3171aa7accf13c0( - *, - acquire_time: typing.Optional[datetime.datetime] = None, - holder_identity: typing.Optional[builtins.str] = None, - lease_duration_seconds: typing.Optional[jsii.Number] = None, - lease_transitions: typing.Optional[jsii.Number] = None, - renew_time: typing.Optional[datetime.datetime] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__7bd1d9e48df3fb31eaad590d942020be7329bc9ca7a62db73e43e7362b1cc50d( - *, - post_start: typing.Optional[typing.Union[LifecycleHandler, typing.Dict[builtins.str, typing.Any]]] = None, - pre_stop: typing.Optional[typing.Union[LifecycleHandler, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__26ab4379df425e6abfcd38434919756033f8e7da90416a68d159b10d8103d3a0( - *, - exec: typing.Optional[typing.Union[ExecAction, typing.Dict[builtins.str, typing.Any]]] = None, - http_get: typing.Optional[typing.Union[HttpGetAction, typing.Dict[builtins.str, typing.Any]]] = None, - tcp_socket: typing.Optional[typing.Union[TcpSocketAction, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__f178641e82038afdb476dfb5344285c2cd173e3d277341d2bdd9147b73026eee( - *, - type: builtins.str, - default: typing.Optional[typing.Mapping[builtins.str, Quantity]] = None, - default_request: typing.Optional[typing.Mapping[builtins.str, Quantity]] = None, - max: typing.Optional[typing.Mapping[builtins.str, Quantity]] = None, - max_limit_request_ratio: typing.Optional[typing.Mapping[builtins.str, Quantity]] = None, - min: typing.Optional[typing.Mapping[builtins.str, Quantity]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__027b4c522c19844f185c6e4f67a4d23daf36b62d09bea8f49867796254123ae9( - *, - limits: typing.Sequence[typing.Union[LimitRangeItem, typing.Dict[builtins.str, typing.Any]]], -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__a7d2e84b41662f85530d92f23057ed1bfa4d969fe97f435f241fb59d9e3bcf55( - *, - type: builtins.str, - queuing: typing.Optional[typing.Union[QueuingConfigurationV1Beta2, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__d647edc50a3472caac98caf06f5a31e4200bbd7ef2bb53fe956d146e70245f10( - *, - type: builtins.str, - queuing: typing.Optional[typing.Union[QueuingConfigurationV1Beta3, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__1de531b9c958a31d6159e3de559aad52ec6bc11571ae701ec5b953bf9aac78cf( - *, - assured_concurrency_shares: typing.Optional[jsii.Number] = None, - borrowing_limit_percent: typing.Optional[jsii.Number] = None, - lendable_percent: typing.Optional[jsii.Number] = None, - limit_response: typing.Optional[typing.Union[LimitResponseV1Beta2, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__6f5ecffd25d8896c671c9cdd6db9659e0a8f6678e8899d85af3d7ddb13cef0ef( - *, - borrowing_limit_percent: typing.Optional[jsii.Number] = None, - lendable_percent: typing.Optional[jsii.Number] = None, - limit_response: typing.Optional[typing.Union[LimitResponseV1Beta3, typing.Dict[builtins.str, typing.Any]]] = None, - nominal_concurrency_shares: typing.Optional[jsii.Number] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__c89d5e06a349da5660f2e0e4d4f09e7a3e9ddf286741898802308a9398682fb7( - *, - continue_: typing.Optional[builtins.str] = None, - remaining_item_count: typing.Optional[jsii.Number] = None, - resource_version: typing.Optional[builtins.str] = None, - self_link: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__d4bcf5caa3c82746d54e01aae949e13a5e8eb43da22feabb16930ea634934182( - *, - name: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__b968cf718668502f36d95fef3ccb40aea55d0b34c90e37b5b542eeec51d43091( - *, - path: builtins.str, - fs_type: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__7d4739bc7dc7000dc6e5fca030c204929e2fd79081deaecd9bb2d31a8ff798f8( - *, - api_version: typing.Optional[builtins.str] = None, - fields_type: typing.Optional[builtins.str] = None, - fields_v1: typing.Any = None, - manager: typing.Optional[builtins.str] = None, - operation: typing.Optional[builtins.str] = None, - subresource: typing.Optional[builtins.str] = None, - time: typing.Optional[datetime.datetime] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__353cd8dc9e4702f1a8e203983ad89fe7e2f2cf3e018a030464f491008c59202f( - *, - exclude_resource_rules: typing.Optional[typing.Sequence[typing.Union[NamedRuleWithOperationsV1Alpha1, typing.Dict[builtins.str, typing.Any]]]] = None, - match_policy: typing.Optional[builtins.str] = None, - namespace_selector: typing.Optional[typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]]] = None, - object_selector: typing.Optional[typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]]] = None, - resource_rules: typing.Optional[typing.Sequence[typing.Union[NamedRuleWithOperationsV1Alpha1, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__05f3c3477ee039ee62c1437881247ebc79634cd90deb0f404da58859b54f239b( - *, - name: builtins.str, - selector: typing.Optional[typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__776c3a518a700d093a83bf2abc7751e45a06a623a34cd032f17c5caa38d5a529( - *, - type: builtins.str, - container_resource: typing.Optional[typing.Union[ContainerResourceMetricSourceV2, typing.Dict[builtins.str, typing.Any]]] = None, - external: typing.Optional[typing.Union[ExternalMetricSourceV2, typing.Dict[builtins.str, typing.Any]]] = None, - object: typing.Optional[typing.Union[ObjectMetricSourceV2, typing.Dict[builtins.str, typing.Any]]] = None, - pods: typing.Optional[typing.Union[PodsMetricSourceV2, typing.Dict[builtins.str, typing.Any]]] = None, - resource: typing.Optional[typing.Union[ResourceMetricSourceV2, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__91b2fc60d3480fdb5746f707be7158323bd2542cb5bf771776ee1d23f94b5209( - *, - type: builtins.str, - average_utilization: typing.Optional[jsii.Number] = None, - average_value: typing.Optional[Quantity] = None, - value: typing.Optional[Quantity] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__3b2b9fcd912bddbb67354eb50436e2e46cb9c69e54efee129d032491ec3fda21( - *, - admission_review_versions: typing.Sequence[builtins.str], - client_config: typing.Union[WebhookClientConfig, typing.Dict[builtins.str, typing.Any]], - name: builtins.str, - side_effects: builtins.str, - failure_policy: typing.Optional[builtins.str] = None, - match_policy: typing.Optional[builtins.str] = None, - namespace_selector: typing.Optional[typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]]] = None, - object_selector: typing.Optional[typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]]] = None, - reinvocation_policy: typing.Optional[builtins.str] = None, - rules: typing.Optional[typing.Sequence[typing.Union[RuleWithOperations, typing.Dict[builtins.str, typing.Any]]]] = None, - timeout_seconds: typing.Optional[jsii.Number] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__86254bd3c48c4175d2d8989d74b51ebf1d5e08f635d6ca938cbe71ad127a3055( - *, - api_groups: typing.Optional[typing.Sequence[builtins.str]] = None, - api_versions: typing.Optional[typing.Sequence[builtins.str]] = None, - operations: typing.Optional[typing.Sequence[builtins.str]] = None, - resource_names: typing.Optional[typing.Sequence[builtins.str]] = None, - resources: typing.Optional[typing.Sequence[builtins.str]] = None, - scope: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__0ea645c91cd000f5a4da28ff25155be76d43d13a8e9e70b0d5c0f6eb2529d3c8( - *, - finalizers: typing.Optional[typing.Sequence[builtins.str]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__2310900f85c6226ede2a61dd42a7652ea8cc83e009f119df2fbd2f16997b26de( - *, - ports: typing.Optional[typing.Sequence[typing.Union[NetworkPolicyPort, typing.Dict[builtins.str, typing.Any]]]] = None, - to: typing.Optional[typing.Sequence[typing.Union[NetworkPolicyPeer, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__539e72cf73f95f606fca75f4cbd682e72299b5c8617bc9a6aafa6f3c15b73e64( - *, - from_: typing.Optional[typing.Sequence[typing.Union[NetworkPolicyPeer, typing.Dict[builtins.str, typing.Any]]]] = None, - ports: typing.Optional[typing.Sequence[typing.Union[NetworkPolicyPort, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__79d11d83de8d6e2520a2426cb19cd2d699bfd94c627f4b84d0a50530c388c1bf( - *, - ip_block: typing.Optional[typing.Union[IpBlock, typing.Dict[builtins.str, typing.Any]]] = None, - namespace_selector: typing.Optional[typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]]] = None, - pod_selector: typing.Optional[typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__49079df49fbd7a79ac55d3eb11dc0d2260b7ec0d23bd59e732339eebb03b1866( - *, - end_port: typing.Optional[jsii.Number] = None, - port: typing.Optional[IntOrString] = None, - protocol: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__d9c84fc90459d1cd97b3329e793a8d157a79bc350c911daca3c8b5b185a16977( - *, - pod_selector: typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]], - egress: typing.Optional[typing.Sequence[typing.Union[NetworkPolicyEgressRule, typing.Dict[builtins.str, typing.Any]]]] = None, - ingress: typing.Optional[typing.Sequence[typing.Union[NetworkPolicyIngressRule, typing.Dict[builtins.str, typing.Any]]]] = None, - policy_types: typing.Optional[typing.Sequence[builtins.str]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__64ef53a74120cbc99eb5a721f1a72955a4b1a591eaaf717f4ad02b252033b821( - *, - path: builtins.str, - server: builtins.str, - read_only: typing.Optional[builtins.bool] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__b48e0015647b26feaba0b33c63daf8b67b9219ead4d1f2049e1565931a1ebf3f( - *, - preferred_during_scheduling_ignored_during_execution: typing.Optional[typing.Sequence[typing.Union[PreferredSchedulingTerm, typing.Dict[builtins.str, typing.Any]]]] = None, - required_during_scheduling_ignored_during_execution: typing.Optional[typing.Union[NodeSelector, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__cf7f83b52a971565e60c01b2feacf24dc56b2f356b8bd133298411fd8ca953fc( - *, - config_map: typing.Optional[typing.Union[ConfigMapNodeConfigSource, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__860ee52caab59ff2ee19e780fd4b3b278089ce131229f4b4c67d9158710bfd41( - *, - node_selector_terms: typing.Sequence[typing.Union[NodeSelectorTerm, typing.Dict[builtins.str, typing.Any]]], -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__078a37e4a700d461ea8bef52cbb31305d573e12bce0411df8938b6a2bea57c6e( - *, - key: builtins.str, - operator: builtins.str, - values: typing.Optional[typing.Sequence[builtins.str]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__00ea4bc7ccd8ca5e61bdb8b0ba65854a04f15b4b8fbaf25f3edafd171975a953( - *, - match_expressions: typing.Optional[typing.Sequence[typing.Union[NodeSelectorRequirement, typing.Dict[builtins.str, typing.Any]]]] = None, - match_fields: typing.Optional[typing.Sequence[typing.Union[NodeSelectorRequirement, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__6e50f14ca142b7e1ae3aa4c3b0de77e924013889955b6653359e1c2bc719eb0d( - *, - config_source: typing.Optional[typing.Union[NodeConfigSource, typing.Dict[builtins.str, typing.Any]]] = None, - external_id: typing.Optional[builtins.str] = None, - pod_cidr: typing.Optional[builtins.str] = None, - pod_cid_rs: typing.Optional[typing.Sequence[builtins.str]] = None, - provider_id: typing.Optional[builtins.str] = None, - taints: typing.Optional[typing.Sequence[typing.Union[Taint, typing.Dict[builtins.str, typing.Any]]]] = None, - unschedulable: typing.Optional[builtins.bool] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__87614183732b5aa4dd1bacd6db0063d066b6c9f07ce5f58af69ea84b6410702b( - *, - path: typing.Optional[builtins.str] = None, - verb: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__78a3ae6e3e68c976f8ca44549a07d51b42b5a18ad0717f0a4f2148124dce3b35( - *, - non_resource_ur_ls: typing.Sequence[builtins.str], - verbs: typing.Sequence[builtins.str], -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__549b23213444b2d234a332570b6d25763ed069c291b506dcbc8e9cfbd8b38579( - *, - non_resource_ur_ls: typing.Sequence[builtins.str], - verbs: typing.Sequence[builtins.str], -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__c814859696bb254244f25cd638a669639c7d94c59b5e4180978a9f2c8497378a( - *, - field_path: builtins.str, - api_version: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__7ee1f9d34e34f50cf19155ec68863e4beccde0e8fb69f1e800f6e8b53b8a2af5( - *, - annotations: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - creation_timestamp: typing.Optional[datetime.datetime] = None, - deletion_grace_period_seconds: typing.Optional[jsii.Number] = None, - deletion_timestamp: typing.Optional[datetime.datetime] = None, - finalizers: typing.Optional[typing.Sequence[builtins.str]] = None, - generate_name: typing.Optional[builtins.str] = None, - generation: typing.Optional[jsii.Number] = None, - labels: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - managed_fields: typing.Optional[typing.Sequence[typing.Union[ManagedFieldsEntry, typing.Dict[builtins.str, typing.Any]]]] = None, - name: typing.Optional[builtins.str] = None, - namespace: typing.Optional[builtins.str] = None, - owner_references: typing.Optional[typing.Sequence[typing.Union[OwnerReference, typing.Dict[builtins.str, typing.Any]]]] = None, - resource_version: typing.Optional[builtins.str] = None, - self_link: typing.Optional[builtins.str] = None, - uid: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__059fe76b0567d05ad5259ae2145743ed0bb9b8ff4488936dba8234b467603882( - *, - described_object: typing.Union[CrossVersionObjectReferenceV2, typing.Dict[builtins.str, typing.Any]], - metric: typing.Union[MetricIdentifierV2, typing.Dict[builtins.str, typing.Any]], - target: typing.Union[MetricTargetV2, typing.Dict[builtins.str, typing.Any]], -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__c20094532bd9f73694f77438189bb3de9c66cbdd0365b5006af71270a4661cc5( - *, - api_version: typing.Optional[builtins.str] = None, - field_path: typing.Optional[builtins.str] = None, - kind: typing.Optional[builtins.str] = None, - name: typing.Optional[builtins.str] = None, - namespace: typing.Optional[builtins.str] = None, - resource_version: typing.Optional[builtins.str] = None, - uid: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__57ac617e483fea78edd490dac696636c32772cbc5e9c8196a16758039d227d56( - *, - pod_fixed: typing.Optional[typing.Mapping[builtins.str, Quantity]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__f492c2fd31467da33dd2714b04585d0827fb1e1b0cf0b750d6db405bd88f0eeb( - *, - api_version: builtins.str, - kind: builtins.str, - name: builtins.str, - uid: builtins.str, - block_owner_deletion: typing.Optional[builtins.bool] = None, - controller: typing.Optional[builtins.bool] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__ca366a1a5a55375a1aef0df1d3a5ee87b07269561ad4145843c552a10838efa1( - *, - api_version: typing.Optional[builtins.str] = None, - kind: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__001cc96ea35cdecf4deeab0b5f67d5cac9ccd26cc9b639769b91f8b011165e5e( - *, - name: typing.Optional[builtins.str] = None, - namespace: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__be23e20b8fae04cc3c5f02f0df1e7da53e588f89c5d6bcc9ca2ad145ca3ea9ac( - *, - access_modes: typing.Optional[typing.Sequence[builtins.str]] = None, - data_source: typing.Optional[typing.Union[TypedLocalObjectReference, typing.Dict[builtins.str, typing.Any]]] = None, - data_source_ref: typing.Optional[typing.Union[TypedObjectReference, typing.Dict[builtins.str, typing.Any]]] = None, - resources: typing.Optional[typing.Union[ResourceRequirements, typing.Dict[builtins.str, typing.Any]]] = None, - selector: typing.Optional[typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]]] = None, - storage_class_name: typing.Optional[builtins.str] = None, - volume_mode: typing.Optional[builtins.str] = None, - volume_name: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__cee40a2a8084d3e6408f7a24fa29121063e73cd7d587715d3996c04e0be4bd5e( - *, - spec: typing.Union[PersistentVolumeClaimSpec, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__077a0f4dddf176bb8ddbe6260969da6b9456d4aae46a38dd256c0a2204c8ee7b( - *, - claim_name: builtins.str, - read_only: typing.Optional[builtins.bool] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__35aff97a067cf96c268b843a969ca0b9162e0690f21670fdecba69ea27a470fb( - *, - access_modes: typing.Optional[typing.Sequence[builtins.str]] = None, - aws_elastic_block_store: typing.Optional[typing.Union[AwsElasticBlockStoreVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - azure_disk: typing.Optional[typing.Union[AzureDiskVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - azure_file: typing.Optional[typing.Union[AzureFilePersistentVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - capacity: typing.Optional[typing.Mapping[builtins.str, Quantity]] = None, - cephfs: typing.Optional[typing.Union[CephFsPersistentVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - cinder: typing.Optional[typing.Union[CinderPersistentVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - claim_ref: typing.Optional[typing.Union[ObjectReference, typing.Dict[builtins.str, typing.Any]]] = None, - csi: typing.Optional[typing.Union[CsiPersistentVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - fc: typing.Optional[typing.Union[FcVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - flex_volume: typing.Optional[typing.Union[FlexPersistentVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - flocker: typing.Optional[typing.Union[FlockerVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - gce_persistent_disk: typing.Optional[typing.Union[GcePersistentDiskVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - glusterfs: typing.Optional[typing.Union[GlusterfsPersistentVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - host_path: typing.Optional[typing.Union[HostPathVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - iscsi: typing.Optional[typing.Union[IscsiPersistentVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - local: typing.Optional[typing.Union[LocalVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - mount_options: typing.Optional[typing.Sequence[builtins.str]] = None, - nfs: typing.Optional[typing.Union[NfsVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - node_affinity: typing.Optional[typing.Union[VolumeNodeAffinity, typing.Dict[builtins.str, typing.Any]]] = None, - persistent_volume_reclaim_policy: typing.Optional[builtins.str] = None, - photon_persistent_disk: typing.Optional[typing.Union[PhotonPersistentDiskVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - portworx_volume: typing.Optional[typing.Union[PortworxVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - quobyte: typing.Optional[typing.Union[QuobyteVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - rbd: typing.Optional[typing.Union[RbdPersistentVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - scale_io: typing.Optional[typing.Union[ScaleIoPersistentVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - storage_class_name: typing.Optional[builtins.str] = None, - storageos: typing.Optional[typing.Union[StorageOsPersistentVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - volume_mode: typing.Optional[builtins.str] = None, - vsphere_volume: typing.Optional[typing.Union[VsphereVirtualDiskVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__7b0be95f372a9aa5db6fdac38282cc046204e7f43c46d9459c585522c86b2f39( - *, - pd_id: builtins.str, - fs_type: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__0830de33ed62413d27b090c2218c86cadcbd37738b116d98ce30ae82e8676733( - *, - preferred_during_scheduling_ignored_during_execution: typing.Optional[typing.Sequence[typing.Union[WeightedPodAffinityTerm, typing.Dict[builtins.str, typing.Any]]]] = None, - required_during_scheduling_ignored_during_execution: typing.Optional[typing.Sequence[typing.Union[PodAffinityTerm, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__063b73cb46562ef4af361b17cfc211f3c56960b9052f045d67104026b7d98e93( - *, - topology_key: builtins.str, - label_selector: typing.Optional[typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]]] = None, - namespaces: typing.Optional[typing.Sequence[builtins.str]] = None, - namespace_selector: typing.Optional[typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__cab9a027f8884b485c148ce998a3d4c392c0b58b23786402dd0caf2c5a319034( - *, - preferred_during_scheduling_ignored_during_execution: typing.Optional[typing.Sequence[typing.Union[WeightedPodAffinityTerm, typing.Dict[builtins.str, typing.Any]]]] = None, - required_during_scheduling_ignored_during_execution: typing.Optional[typing.Sequence[typing.Union[PodAffinityTerm, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__fcf659f51d3ad1ddb70e76f4550c401ae77b9bed37d6671e9b1895983dbc2bc6( - *, - max_unavailable: typing.Optional[IntOrString] = None, - min_available: typing.Optional[IntOrString] = None, - selector: typing.Optional[typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]]] = None, - unhealthy_pod_eviction_policy: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__8c30b93db014abaf8ed6b5187f791e1155288ba850e120d30272e029498d46a2( - *, - nameservers: typing.Optional[typing.Sequence[builtins.str]] = None, - options: typing.Optional[typing.Sequence[typing.Union[PodDnsConfigOption, typing.Dict[builtins.str, typing.Any]]]] = None, - searches: typing.Optional[typing.Sequence[builtins.str]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__815fe5aad5ae05289693b717c8d0482e9f0ca6d59c31bed07e76d275fb763759( - *, - name: typing.Optional[builtins.str] = None, - value: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__7d648d0923526488e7170f574c8a29f5a5121299dee93365c01d1ca343751c04( - *, - rules: typing.Sequence[typing.Union[PodFailurePolicyRule, typing.Dict[builtins.str, typing.Any]]], -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__9156cdbac4d38b9bf3a2fd6d97fb9187f19aa4043a7010b5897b2c0ff19ddb5a( - *, - operator: builtins.str, - values: typing.Sequence[jsii.Number], - container_name: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__749d7e1a80b843779b9d09f3b38a68a3fd1c77026783179dbf25170231c5a720( - *, - status: builtins.str, - type: builtins.str, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__9752d799ae40ee7e1d07cceb2daac5e29af9b379c43f336814f8928b638ebe0a( - *, - action: builtins.str, - on_pod_conditions: typing.Sequence[typing.Union[PodFailurePolicyOnPodConditionsPattern, typing.Dict[builtins.str, typing.Any]]], - on_exit_codes: typing.Optional[typing.Union[PodFailurePolicyOnExitCodesRequirement, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__447466b6ee10b58f2a9031698c5d443c3de519f08a74be7dba21e1509f800a9f( - *, - name: builtins.str, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__6efa6da68115e82d6b27bff9f91e3ed47585fedf0e8e6358afee97da2cccc1fc( - *, - condition_type: builtins.str, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__593eecd9b8e25f27db87859570a28b2ffda74b52af7ef080a6bc114f4b263f52( - *, - name: builtins.str, - source: typing.Optional[typing.Union[ClaimSource, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__ba3a868f60063830cfdaddc5e19d4d1ef9980dc7ffe3b27b3e802c3eaede83dc( - *, - name: builtins.str, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__cbaa152d2aa3b0f9ec0ecda0ddb7625c4422ee7ea4ee6a8b3c47fc6deee35d21( - *, - potential_nodes: typing.Optional[typing.Sequence[builtins.str]] = None, - selected_node: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__b23f586ca6b5b102b009640138cfcb7cb8db5fffa8d48ddb6c723e2d52bc60bc( - *, - fs_group: typing.Optional[jsii.Number] = None, - fs_group_change_policy: typing.Optional[builtins.str] = None, - run_as_group: typing.Optional[jsii.Number] = None, - run_as_non_root: typing.Optional[builtins.bool] = None, - run_as_user: typing.Optional[jsii.Number] = None, - seccomp_profile: typing.Optional[typing.Union[SeccompProfile, typing.Dict[builtins.str, typing.Any]]] = None, - se_linux_options: typing.Optional[typing.Union[SeLinuxOptions, typing.Dict[builtins.str, typing.Any]]] = None, - supplemental_groups: typing.Optional[typing.Sequence[jsii.Number]] = None, - sysctls: typing.Optional[typing.Sequence[typing.Union[Sysctl, typing.Dict[builtins.str, typing.Any]]]] = None, - windows_options: typing.Optional[typing.Union[WindowsSecurityContextOptions, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__9ddad62f26f59d5b393ec9c7814efae31dbad75f06f4456a0bef61a6ce7dd763( - *, - containers: typing.Sequence[typing.Union[Container, typing.Dict[builtins.str, typing.Any]]], - active_deadline_seconds: typing.Optional[jsii.Number] = None, - affinity: typing.Optional[typing.Union[Affinity, typing.Dict[builtins.str, typing.Any]]] = None, - automount_service_account_token: typing.Optional[builtins.bool] = None, - dns_config: typing.Optional[typing.Union[PodDnsConfig, typing.Dict[builtins.str, typing.Any]]] = None, - dns_policy: typing.Optional[builtins.str] = None, - enable_service_links: typing.Optional[builtins.bool] = None, - ephemeral_containers: typing.Optional[typing.Sequence[typing.Union[EphemeralContainer, typing.Dict[builtins.str, typing.Any]]]] = None, - host_aliases: typing.Optional[typing.Sequence[typing.Union[HostAlias, typing.Dict[builtins.str, typing.Any]]]] = None, - host_ipc: typing.Optional[builtins.bool] = None, - hostname: typing.Optional[builtins.str] = None, - host_network: typing.Optional[builtins.bool] = None, - host_pid: typing.Optional[builtins.bool] = None, - host_users: typing.Optional[builtins.bool] = None, - image_pull_secrets: typing.Optional[typing.Sequence[typing.Union[LocalObjectReference, typing.Dict[builtins.str, typing.Any]]]] = None, - init_containers: typing.Optional[typing.Sequence[typing.Union[Container, typing.Dict[builtins.str, typing.Any]]]] = None, - node_name: typing.Optional[builtins.str] = None, - node_selector: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - os: typing.Optional[typing.Union[PodOs, typing.Dict[builtins.str, typing.Any]]] = None, - overhead: typing.Optional[typing.Mapping[builtins.str, Quantity]] = None, - preemption_policy: typing.Optional[builtins.str] = None, - priority: typing.Optional[jsii.Number] = None, - priority_class_name: typing.Optional[builtins.str] = None, - readiness_gates: typing.Optional[typing.Sequence[typing.Union[PodReadinessGate, typing.Dict[builtins.str, typing.Any]]]] = None, - resource_claims: typing.Optional[typing.Sequence[typing.Union[PodResourceClaim, typing.Dict[builtins.str, typing.Any]]]] = None, - restart_policy: typing.Optional[builtins.str] = None, - runtime_class_name: typing.Optional[builtins.str] = None, - scheduler_name: typing.Optional[builtins.str] = None, - scheduling_gates: typing.Optional[typing.Sequence[typing.Union[PodSchedulingGate, typing.Dict[builtins.str, typing.Any]]]] = None, - security_context: typing.Optional[typing.Union[PodSecurityContext, typing.Dict[builtins.str, typing.Any]]] = None, - service_account: typing.Optional[builtins.str] = None, - service_account_name: typing.Optional[builtins.str] = None, - set_hostname_as_fqdn: typing.Optional[builtins.bool] = None, - share_process_namespace: typing.Optional[builtins.bool] = None, - subdomain: typing.Optional[builtins.str] = None, - termination_grace_period_seconds: typing.Optional[jsii.Number] = None, - tolerations: typing.Optional[typing.Sequence[typing.Union[Toleration, typing.Dict[builtins.str, typing.Any]]]] = None, - topology_spread_constraints: typing.Optional[typing.Sequence[typing.Union[TopologySpreadConstraint, typing.Dict[builtins.str, typing.Any]]]] = None, - volumes: typing.Optional[typing.Sequence[typing.Union[Volume, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__a23cda3e55cf29ffda2e22bb377999f4b35fa2ff1fdb8ae27faf58b7f2b9c866( - *, - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, - spec: typing.Optional[typing.Union[PodSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__4e1daa232feea2f9ba7daaf3807ee414905ce98c0d3805ab6cd957f8405729b3( - *, - metric: typing.Union[MetricIdentifierV2, typing.Dict[builtins.str, typing.Any]], - target: typing.Union[MetricTargetV2, typing.Dict[builtins.str, typing.Any]], -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__faa1080f7a02c3d2eac7f18aad0cdbef93f8f9cff0f9825224a9dd8a829faf0a( - *, - verbs: typing.Sequence[builtins.str], - api_groups: typing.Optional[typing.Sequence[builtins.str]] = None, - non_resource_ur_ls: typing.Optional[typing.Sequence[builtins.str]] = None, - resource_names: typing.Optional[typing.Sequence[builtins.str]] = None, - resources: typing.Optional[typing.Sequence[builtins.str]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__b8fb123532a9c4783d0f6374006effe94f2abbd28e993ae2827ad3601ddf98c5( - *, - subjects: typing.Sequence[typing.Union[SubjectV1Beta2, typing.Dict[builtins.str, typing.Any]]], - non_resource_rules: typing.Optional[typing.Sequence[typing.Union[NonResourcePolicyRuleV1Beta2, typing.Dict[builtins.str, typing.Any]]]] = None, - resource_rules: typing.Optional[typing.Sequence[typing.Union[ResourcePolicyRuleV1Beta2, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__d696363024826d8d1400b937d2aa6b61b3eaaa59024841f169586f09d8fa40dd( - *, - subjects: typing.Sequence[typing.Union[SubjectV1Beta3, typing.Dict[builtins.str, typing.Any]]], - non_resource_rules: typing.Optional[typing.Sequence[typing.Union[NonResourcePolicyRuleV1Beta3, typing.Dict[builtins.str, typing.Any]]]] = None, - resource_rules: typing.Optional[typing.Sequence[typing.Union[ResourcePolicyRuleV1Beta3, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__e5881c74274a6e5dc2a25e69584d9a7a08eda9f51afd4f560f3731ae800319a9( - *, - volume_id: builtins.str, - fs_type: typing.Optional[builtins.str] = None, - read_only: typing.Optional[builtins.bool] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__5d83cea33916e66ca6553e6bdfe2c022d25c2d9b0d13a46f323bef2db497363e( - *, - resource_version: typing.Optional[builtins.str] = None, - uid: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__4778017af685ac589aca31cd5f8aed67ddd4b8d050f99423b40b402a8758f9df( - *, - preference: typing.Union[NodeSelectorTerm, typing.Dict[builtins.str, typing.Any]], - weight: jsii.Number, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__76bd97c74c99efa5169495b9849f8685fb180d45e0f29dbce62f0fe15e286f13( - *, - name: builtins.str, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__9a0146b969cc8a7d1c0ff18cf7d2f32e995d6c975b94478b11b395aca5759667( - *, - name: builtins.str, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__94bca280ba8f7fad3c10c340b8cf6039d7a0f6cbd700ea283a8eeb4f1a9bdaad( - *, - type: builtins.str, - limited: typing.Optional[typing.Union[LimitedPriorityLevelConfigurationV1Beta2, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__c30b61d9bf19716fdc32867c5d90748be48b5c7c3c858ba8b5c867223594eb77( - *, - type: builtins.str, - limited: typing.Optional[typing.Union[LimitedPriorityLevelConfigurationV1Beta3, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__db09437a4be3e51aba0181b1494c0c550aa4867813268b893ac716f115fa48c1( - *, - exec: typing.Optional[typing.Union[ExecAction, typing.Dict[builtins.str, typing.Any]]] = None, - failure_threshold: typing.Optional[jsii.Number] = None, - grpc: typing.Optional[typing.Union[GrpcAction, typing.Dict[builtins.str, typing.Any]]] = None, - http_get: typing.Optional[typing.Union[HttpGetAction, typing.Dict[builtins.str, typing.Any]]] = None, - initial_delay_seconds: typing.Optional[jsii.Number] = None, - period_seconds: typing.Optional[jsii.Number] = None, - success_threshold: typing.Optional[jsii.Number] = None, - tcp_socket: typing.Optional[typing.Union[TcpSocketAction, typing.Dict[builtins.str, typing.Any]]] = None, - termination_grace_period_seconds: typing.Optional[jsii.Number] = None, - timeout_seconds: typing.Optional[jsii.Number] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__7074d18926a011b639c0d0e74c2a29fc486086a8992a0ccda6c888fe8065ce84( - *, - default_mode: typing.Optional[jsii.Number] = None, - sources: typing.Optional[typing.Sequence[typing.Union[VolumeProjection, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__5424c0bd9afaecc70d51e745b052a4e736b88cf285925889028bab8d3cfb8fee( - value: jsii.Number, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__abf2ed361dde0b07fa7185d50da371e8631fdccf28cb302e7e5d62f671a79d9a( - value: builtins.str, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__8d5a34c8cf9c81ed2f5b31625c4cec39f9cc1c5c9d4fb1cd5b7c4ea13cbfecda( - *, - hand_size: typing.Optional[jsii.Number] = None, - queue_length_limit: typing.Optional[jsii.Number] = None, - queues: typing.Optional[jsii.Number] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__a1037b25a0b4c030cbae5567cfd92e97afe9e0798778e912b05229e9373472d1( - *, - hand_size: typing.Optional[jsii.Number] = None, - queue_length_limit: typing.Optional[jsii.Number] = None, - queues: typing.Optional[jsii.Number] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__06c16a4eef69abcb24206e80e63cd1b95acadcfeb11e968c6e6938adf8d6afba( - *, - registry: builtins.str, - volume: builtins.str, - group: typing.Optional[builtins.str] = None, - read_only: typing.Optional[builtins.bool] = None, - tenant: typing.Optional[builtins.str] = None, - user: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__4f5316d57fc5b5c34025f51982f7e682403dd695b70e08c67fc74cffd5c675fb( - *, - image: builtins.str, - monitors: typing.Sequence[builtins.str], - fs_type: typing.Optional[builtins.str] = None, - keyring: typing.Optional[builtins.str] = None, - pool: typing.Optional[builtins.str] = None, - read_only: typing.Optional[builtins.bool] = None, - secret_ref: typing.Optional[typing.Union[SecretReference, typing.Dict[builtins.str, typing.Any]]] = None, - user: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__b775d6c9c36f825c00349ce924014aaf1d073ef444b854540aaaa1b195f1f2e1( - *, - image: builtins.str, - monitors: typing.Sequence[builtins.str], - fs_type: typing.Optional[builtins.str] = None, - keyring: typing.Optional[builtins.str] = None, - pool: typing.Optional[builtins.str] = None, - read_only: typing.Optional[builtins.bool] = None, - secret_ref: typing.Optional[typing.Union[LocalObjectReference, typing.Dict[builtins.str, typing.Any]]] = None, - user: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__4a649a1eff04d9feb07747ac0b41f1e738bb62df7f0a6d730148217e8a0b1f7b( - *, - selector: typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]], - min_ready_seconds: typing.Optional[jsii.Number] = None, - replicas: typing.Optional[jsii.Number] = None, - template: typing.Optional[typing.Union[PodTemplateSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__cb1a637f64dd89041b0c36855e6e4b2ebb97a853ce2ab8bf74baa53399293aa9( - *, - min_ready_seconds: typing.Optional[jsii.Number] = None, - replicas: typing.Optional[jsii.Number] = None, - selector: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - template: typing.Optional[typing.Union[PodTemplateSpec, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__1389ee6ee42f772dc34e626fc6cda72a7449fbddee89e52988179f65c725d996( - *, - group: typing.Optional[builtins.str] = None, - name: typing.Optional[builtins.str] = None, - namespace: typing.Optional[builtins.str] = None, - resource: typing.Optional[builtins.str] = None, - subresource: typing.Optional[builtins.str] = None, - verb: typing.Optional[builtins.str] = None, - version: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__91cfdd0118d393ecd84db840ef420f5ffe5190ebbd91733137901a1accc49509( - *, - name: builtins.str, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__3577080f3432d03b6855e16ee80a2c353219d63b419c899aeaa67829a6e5c1fd( - *, - kind: builtins.str, - name: builtins.str, - api_group: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__222e0cbad16de6e748d8f212a7f2442c819c2ab8c5a44ca7bae369ddd8d4b534( - *, - resource_class_name: builtins.str, - allocation_mode: typing.Optional[builtins.str] = None, - parameters_ref: typing.Optional[typing.Union[ResourceClaimParametersReferenceV1Alpha1, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__e997f36b60700a40ef5d273c773afd5de1bd6dd5b1729cba9b1011cf89235456( - *, - spec: typing.Union[ResourceClaimSpecV1Alpha1, typing.Dict[builtins.str, typing.Any]], - metadata: typing.Optional[typing.Union[ObjectMeta, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__5afcc6783d7cbb47b83e346e5c573888b38fd04b8cfd4d6ca64f7b0a4392f11c( - *, - kind: builtins.str, - name: builtins.str, - api_group: typing.Optional[builtins.str] = None, - namespace: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__7117ce5ef6d2382048cc325329ebe4abba77c2be754492f7322ea7cc6b3c8c8c( - *, - resource: builtins.str, - container_name: typing.Optional[builtins.str] = None, - divisor: typing.Optional[Quantity] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__62e5706b1c72eb3d6f6b070e53fc6646c3236f3cf9b9bbbbfc3f1022dda08d0d( - *, - name: builtins.str, - target: typing.Union[MetricTargetV2, typing.Dict[builtins.str, typing.Any]], -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__36c3728ec619997c16f03e7e503f9b6faa92c7d0be82c87e3f0a2c89c144f2bb( - *, - api_groups: typing.Sequence[builtins.str], - resources: typing.Sequence[builtins.str], - verbs: typing.Sequence[builtins.str], - cluster_scope: typing.Optional[builtins.bool] = None, - namespaces: typing.Optional[typing.Sequence[builtins.str]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__c9ae6771cea2f9e8c2c610a5b19310cef1a10452a5eab35dc8eb9198c9ed8025( - *, - api_groups: typing.Sequence[builtins.str], - resources: typing.Sequence[builtins.str], - verbs: typing.Sequence[builtins.str], - cluster_scope: typing.Optional[builtins.bool] = None, - namespaces: typing.Optional[typing.Sequence[builtins.str]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__1f38b292c93787ac346fc7bdbff50edd3c17b9ea8d3ae69b3ef92ad11538687e( - *, - hard: typing.Optional[typing.Mapping[builtins.str, Quantity]] = None, - scopes: typing.Optional[typing.Sequence[builtins.str]] = None, - scope_selector: typing.Optional[typing.Union[ScopeSelector, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__6f28381f115e86cc4a857dc64662f80338d1b27b3fbd53665d90231711e3a3cd( - *, - claims: typing.Optional[typing.Sequence[typing.Union[ResourceClaim, typing.Dict[builtins.str, typing.Any]]]] = None, - limits: typing.Optional[typing.Mapping[builtins.str, Quantity]] = None, - requests: typing.Optional[typing.Mapping[builtins.str, Quantity]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__34728caa2c65a1bce45499a1f4530a2e2966d14ff7e6d57ddbf874c837a09229( - *, - api_group: builtins.str, - kind: builtins.str, - name: builtins.str, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__36e1da895206a5ed9179f6d5649f08d688e482419e0ac3c555bca88a46e32a8d( - *, - max_surge: typing.Optional[IntOrString] = None, - max_unavailable: typing.Optional[IntOrString] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__8a2a897588ced8e993501e8a731a38dd93a578e6bdfbc01a36044482c0ac6796( - *, - max_surge: typing.Optional[IntOrString] = None, - max_unavailable: typing.Optional[IntOrString] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__5244c3370eebd6a466d9aa0a3a0f3ab6e3fec32436cc8b602ba25a37b7f9e5ec( - *, - max_unavailable: typing.Optional[IntOrString] = None, - partition: typing.Optional[jsii.Number] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__a86077ec1a02004936f4e7b29b4891e15e965506276980ac5cde5434c9cb21a0( - *, - api_groups: typing.Optional[typing.Sequence[builtins.str]] = None, - api_versions: typing.Optional[typing.Sequence[builtins.str]] = None, - operations: typing.Optional[typing.Sequence[builtins.str]] = None, - resources: typing.Optional[typing.Sequence[builtins.str]] = None, - scope: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__a3db8aeafd58b5a9ffd7810c912395c33f597e9a328ad9492e778f5f6c3b1201( - *, - gateway: builtins.str, - secret_ref: typing.Union[SecretReference, typing.Dict[builtins.str, typing.Any]], - system: builtins.str, - fs_type: typing.Optional[builtins.str] = None, - protection_domain: typing.Optional[builtins.str] = None, - read_only: typing.Optional[builtins.bool] = None, - ssl_enabled: typing.Optional[builtins.bool] = None, - storage_mode: typing.Optional[builtins.str] = None, - storage_pool: typing.Optional[builtins.str] = None, - volume_name: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__a01207e2538a5a1358fca3cbc8251d3c0eac11c259c7d6e013872e8e0c4e0aff( - *, - gateway: builtins.str, - secret_ref: typing.Union[LocalObjectReference, typing.Dict[builtins.str, typing.Any]], - system: builtins.str, - fs_type: typing.Optional[builtins.str] = None, - protection_domain: typing.Optional[builtins.str] = None, - read_only: typing.Optional[builtins.bool] = None, - ssl_enabled: typing.Optional[builtins.bool] = None, - storage_mode: typing.Optional[builtins.str] = None, - storage_pool: typing.Optional[builtins.str] = None, - volume_name: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__933ce43198d2e61bf18cbdc69b1a85d78c4b5059b04255c8eaae6fd004cd796f( - *, - replicas: typing.Optional[jsii.Number] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__ec3f34534a8ab02cd430086d5367d2f94c6c0e7343339e7bfc16ee13ddc99d7a( - *, - node_selector: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - tolerations: typing.Optional[typing.Sequence[typing.Union[Toleration, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__9b4391c052c165b6256ea047b5596eab2fcecf19b0a9177b1c5aa1a8485a8d65( - *, - match_expressions: typing.Optional[typing.Sequence[typing.Union[ScopedResourceSelectorRequirement, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__25d2fa33badd5c55fedc6548e4a9811bdcfdd1569a40592b494f98dd2faa0d58( - *, - operator: builtins.str, - scope_name: builtins.str, - values: typing.Optional[typing.Sequence[builtins.str]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__83c2afea88042856c9e697502b222fdab3ba5aa314b8db7832e18390438f4cae( - *, - level: typing.Optional[builtins.str] = None, - role: typing.Optional[builtins.str] = None, - type: typing.Optional[builtins.str] = None, - user: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__671e277701b07860347cc95c432e5605a89c2d148bebfccaead627a5b559eba4( - *, - type: builtins.str, - localhost_profile: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__8d52030565d59aad237de569c2f9746d89c90816ecd991ddc7b7ea6624d871ff( - *, - name: typing.Optional[builtins.str] = None, - optional: typing.Optional[builtins.bool] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__10d7b89d6873826406c0f3f0882c9b1e23eec486efebbb601cb05ef478c62925( - *, - key: builtins.str, - name: typing.Optional[builtins.str] = None, - optional: typing.Optional[builtins.bool] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__cef90561db8db5a4c9a8b89a6f3b87e04f52ca6ca4775954c0d0434b48021869( - *, - items: typing.Optional[typing.Sequence[typing.Union[KeyToPath, typing.Dict[builtins.str, typing.Any]]]] = None, - name: typing.Optional[builtins.str] = None, - optional: typing.Optional[builtins.bool] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__7a151e3e3fd089bf4b7fe70426a9c364c57d5a3d0a27a642e74873d5c32aba01( - *, - name: typing.Optional[builtins.str] = None, - namespace: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__25d6ed85323c7db8b962d40135ed579f6269a43590382c950b1f670739dd5d9c( - *, - default_mode: typing.Optional[jsii.Number] = None, - items: typing.Optional[typing.Sequence[typing.Union[KeyToPath, typing.Dict[builtins.str, typing.Any]]]] = None, - optional: typing.Optional[builtins.bool] = None, - secret_name: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__433d0b1cb870f05b48bfb6eeb4e8d9af769be17981b3d3465be0319c5fdcfe58( - *, - allow_privilege_escalation: typing.Optional[builtins.bool] = None, - capabilities: typing.Optional[typing.Union[Capabilities, typing.Dict[builtins.str, typing.Any]]] = None, - privileged: typing.Optional[builtins.bool] = None, - proc_mount: typing.Optional[builtins.str] = None, - read_only_root_filesystem: typing.Optional[builtins.bool] = None, - run_as_group: typing.Optional[jsii.Number] = None, - run_as_non_root: typing.Optional[builtins.bool] = None, - run_as_user: typing.Optional[jsii.Number] = None, - seccomp_profile: typing.Optional[typing.Union[SeccompProfile, typing.Dict[builtins.str, typing.Any]]] = None, - se_linux_options: typing.Optional[typing.Union[SeLinuxOptions, typing.Dict[builtins.str, typing.Any]]] = None, - windows_options: typing.Optional[typing.Union[WindowsSecurityContextOptions, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__e1c2bf0513f041ce3e18333d43a5849dff775b6c0bf8ea1391d425c73771a607( - *, - non_resource_attributes: typing.Optional[typing.Union[NonResourceAttributes, typing.Dict[builtins.str, typing.Any]]] = None, - resource_attributes: typing.Optional[typing.Union[ResourceAttributes, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__e8dd2a0d136f9e7e8480f73531aaae29fb249c5b4c11d47022b16354c78aace9( - *, - namespace: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__ed7e13eb7021a2b0809d1809b6e9d20476c12f8399abed5e9535445cd3a54214( - *, - name: builtins.str, - namespace: builtins.str, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__324da826cf3bc07c48d0532607d6bac7ab807122d6cde1c86aaf149e3ac5a926( - *, - name: builtins.str, - namespace: builtins.str, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__eca876ebc0d31f3618cfee4eac3e898196a37c6e4c1f8a9e32ddf0170545dcb7( - *, - path: builtins.str, - audience: typing.Optional[builtins.str] = None, - expiration_seconds: typing.Optional[jsii.Number] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__ccc9db063c0edd035d30aa78a916f1d768a960f314c38168ba4c4e95ca2ae99e( - *, - name: typing.Optional[builtins.str] = None, - number: typing.Optional[jsii.Number] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__34bd12b0b5b5ee6a8e28438e78966717248ee25b5c7c6a0cadd99c8e5843ebb3( - *, - port: jsii.Number, - app_protocol: typing.Optional[builtins.str] = None, - name: typing.Optional[builtins.str] = None, - node_port: typing.Optional[jsii.Number] = None, - protocol: typing.Optional[builtins.str] = None, - target_port: typing.Optional[IntOrString] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__6d9ad2a01fb9e7ce732f776bc88e9c896a203ce950547fb864ef2833ae00ee24( - *, - name: builtins.str, - namespace: builtins.str, - path: typing.Optional[builtins.str] = None, - port: typing.Optional[jsii.Number] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__28a62a3352f8d0567f520784bd515250a02d7d2d6686265c9478416f87acb91e( - *, - allocate_load_balancer_node_ports: typing.Optional[builtins.bool] = None, - cluster_ip: typing.Optional[builtins.str] = None, - cluster_i_ps: typing.Optional[typing.Sequence[builtins.str]] = None, - external_i_ps: typing.Optional[typing.Sequence[builtins.str]] = None, - external_name: typing.Optional[builtins.str] = None, - external_traffic_policy: typing.Optional[builtins.str] = None, - health_check_node_port: typing.Optional[jsii.Number] = None, - internal_traffic_policy: typing.Optional[builtins.str] = None, - ip_families: typing.Optional[typing.Sequence[builtins.str]] = None, - ip_family_policy: typing.Optional[builtins.str] = None, - load_balancer_class: typing.Optional[builtins.str] = None, - load_balancer_ip: typing.Optional[builtins.str] = None, - load_balancer_source_ranges: typing.Optional[typing.Sequence[builtins.str]] = None, - ports: typing.Optional[typing.Sequence[typing.Union[ServicePort, typing.Dict[builtins.str, typing.Any]]]] = None, - publish_not_ready_addresses: typing.Optional[builtins.bool] = None, - selector: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None, - session_affinity: typing.Optional[builtins.str] = None, - session_affinity_config: typing.Optional[typing.Union[SessionAffinityConfig, typing.Dict[builtins.str, typing.Any]]] = None, - type: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__41fa363df0cef39b3a21ee7d4b32e767f771c391235a46bf9ce8b369b1bcb705( - *, - client_ip: typing.Optional[typing.Union[ClientIpConfig, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__1e58617ce6e9215ed1ab28dc2eee5d66eab33dc7bfaa27792ade3a835dd2b944( - *, - start: typing.Optional[jsii.Number] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__94098796780c55cdb42c5b053d638803027114010a1003ea7430353fd3179c5a( - *, - when_deleted: typing.Optional[builtins.str] = None, - when_scaled: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__6b3479a4db27d16f25eff18cf9e8bad5d98c3cce86039a11df4bfd5a6c9d128f( - *, - selector: typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]], - service_name: builtins.str, - template: typing.Union[PodTemplateSpec, typing.Dict[builtins.str, typing.Any]], - min_ready_seconds: typing.Optional[jsii.Number] = None, - ordinals: typing.Optional[typing.Union[StatefulSetOrdinals, typing.Dict[builtins.str, typing.Any]]] = None, - persistent_volume_claim_retention_policy: typing.Optional[typing.Union[StatefulSetPersistentVolumeClaimRetentionPolicy, typing.Dict[builtins.str, typing.Any]]] = None, - pod_management_policy: typing.Optional[builtins.str] = None, - replicas: typing.Optional[jsii.Number] = None, - revision_history_limit: typing.Optional[jsii.Number] = None, - update_strategy: typing.Optional[typing.Union[StatefulSetUpdateStrategy, typing.Dict[builtins.str, typing.Any]]] = None, - volume_claim_templates: typing.Optional[typing.Sequence[typing.Union[KubePersistentVolumeClaimProps, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__376e0b967be23662818c61d56be6d18bdec2d63c793172960fbff07b791bc301( - *, - rolling_update: typing.Optional[typing.Union[RollingUpdateStatefulSetStrategy, typing.Dict[builtins.str, typing.Any]]] = None, - type: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__9a84cad04e682eba7f45d6717bea7bd461527f9be5b61611af8ae5829ed76917( - *, - field: typing.Optional[builtins.str] = None, - message: typing.Optional[builtins.str] = None, - reason: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__86c96dd405073e5b3285a98f15293117917ec67b04be70820dcaf694a2ea1f98( - *, - causes: typing.Optional[typing.Sequence[typing.Union[StatusCause, typing.Dict[builtins.str, typing.Any]]]] = None, - group: typing.Optional[builtins.str] = None, - kind: typing.Optional[builtins.str] = None, - name: typing.Optional[builtins.str] = None, - retry_after_seconds: typing.Optional[jsii.Number] = None, - uid: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__dcb3feea41d91b4ceb6ebfb62e681f60b70439c9ca50095a408680f3be68ff39( - *, - fs_type: typing.Optional[builtins.str] = None, - read_only: typing.Optional[builtins.bool] = None, - secret_ref: typing.Optional[typing.Union[ObjectReference, typing.Dict[builtins.str, typing.Any]]] = None, - volume_name: typing.Optional[builtins.str] = None, - volume_namespace: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__5d2e2a4a4a5336dd9d67d0c9d9952b1bd60bcf2097cd69ae70efbfd4bafa92b4( - *, - fs_type: typing.Optional[builtins.str] = None, - read_only: typing.Optional[builtins.bool] = None, - secret_ref: typing.Optional[typing.Union[LocalObjectReference, typing.Dict[builtins.str, typing.Any]]] = None, - volume_name: typing.Optional[builtins.str] = None, - volume_namespace: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__3984acd97248bbea84b86bad6e78e1c94aee46eaf7dce10320654c981464a3aa( - *, - kind: builtins.str, - name: builtins.str, - api_group: typing.Optional[builtins.str] = None, - namespace: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__aecec73f519b5097699d859a6173cfe87c594463900289ecfb24c4a3c623ca4a( - *, - extra: typing.Optional[typing.Mapping[builtins.str, typing.Sequence[builtins.str]]] = None, - groups: typing.Optional[typing.Sequence[builtins.str]] = None, - non_resource_attributes: typing.Optional[typing.Union[NonResourceAttributes, typing.Dict[builtins.str, typing.Any]]] = None, - resource_attributes: typing.Optional[typing.Union[ResourceAttributes, typing.Dict[builtins.str, typing.Any]]] = None, - uid: typing.Optional[builtins.str] = None, - user: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__65ada18dc9b20030468e8eb483d832680b97ad6e44b4cc62b86e84cd497f848d( - *, - kind: builtins.str, - group: typing.Optional[typing.Union[GroupSubjectV1Beta2, typing.Dict[builtins.str, typing.Any]]] = None, - service_account: typing.Optional[typing.Union[ServiceAccountSubjectV1Beta2, typing.Dict[builtins.str, typing.Any]]] = None, - user: typing.Optional[typing.Union[UserSubjectV1Beta2, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__a46ab1f8a869330d80daeca76c731f5168b250899559c5f9260da9dae23b95e3( - *, - kind: builtins.str, - group: typing.Optional[typing.Union[GroupSubjectV1Beta3, typing.Dict[builtins.str, typing.Any]]] = None, - service_account: typing.Optional[typing.Union[ServiceAccountSubjectV1Beta3, typing.Dict[builtins.str, typing.Any]]] = None, - user: typing.Optional[typing.Union[UserSubjectV1Beta3, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__9ebcbff853e5595a246037a229aabe3a4bd6f6aa6b8deb141b7669a41d7f6ca4( - *, - name: builtins.str, - value: builtins.str, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__c83d8efd7618c397938f355d9ce22e16abef5083f86d96444f7001334f075b74( - *, - effect: builtins.str, - key: builtins.str, - time_added: typing.Optional[datetime.datetime] = None, - value: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__4153948139cfde3a540da2062fd40a5b8a03f099e85f3acd26bee80243897532( - *, - port: IntOrString, - host: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__a2eca0bb8eadb510ffaf95db1104ca4195c2708f05a8a378b0cd66f7b398bee9( - *, - audience: builtins.str, - expiration_seconds: typing.Optional[jsii.Number] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__1c6ecf81dacd22a528a277c2eacd8c58c1bb9bead7fa63a6eb43b6ba97554708( - *, - audiences: typing.Sequence[builtins.str], - bound_object_ref: typing.Optional[typing.Union[BoundObjectReference, typing.Dict[builtins.str, typing.Any]]] = None, - expiration_seconds: typing.Optional[jsii.Number] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__9132ea931e42ff03246a2f8dce15a0589348550d3687a44aa8d9ba434d2757ce( - *, - audiences: typing.Optional[typing.Sequence[builtins.str]] = None, - token: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__fc64b64ca6a4e327627ef4fc0e43d3b9ed50e8e8d69828c2afe44f74a3b45f9f( - *, - effect: typing.Optional[builtins.str] = None, - key: typing.Optional[builtins.str] = None, - operator: typing.Optional[builtins.str] = None, - toleration_seconds: typing.Optional[jsii.Number] = None, - value: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__25a9d23f38a251fc5c0330f0132bfd279ea0abef87090dfd767fb5044ec62263( - *, - key: builtins.str, - values: typing.Sequence[builtins.str], -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__f598eb2ca65a39d9b8fc7d3e58cfab9e1b3f88e885b8823a74892071e3a7dfb5( - *, - match_label_expressions: typing.Optional[typing.Sequence[typing.Union[TopologySelectorLabelRequirement, typing.Dict[builtins.str, typing.Any]]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__d563e5e62c67208bafb547e16adedf3e17b27b1cb3c8cd46509e6398021dcef5( - *, - max_skew: jsii.Number, - topology_key: builtins.str, - when_unsatisfiable: builtins.str, - label_selector: typing.Optional[typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]]] = None, - match_label_keys: typing.Optional[typing.Sequence[builtins.str]] = None, - min_domains: typing.Optional[jsii.Number] = None, - node_affinity_policy: typing.Optional[builtins.str] = None, - node_taints_policy: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__e0c8161c6a54145904571f1150bbbdb550defbe6c662fd937bd97bb2f9815bde( - *, - kind: builtins.str, - name: builtins.str, - api_group: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__bece17868eb3d8e19bda1cfa4d9b7e4762df845f22f80e0d969ca1a026323551( - *, - kind: builtins.str, - name: builtins.str, - api_group: typing.Optional[builtins.str] = None, - namespace: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__17a6f5ab5147a857e5ba844ed1dbdafc559b209da7c06b37c6aab6dc5f5ceaab( - *, - name: builtins.str, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__4922cdd9a47a2508da7b0db66f1f2de9875fc489bfc823c7fc81b715099a31b6( - *, - name: builtins.str, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__0d38c442b8405ac15b84cec7d96ee561544c67c7960c701be6a4e8938804eefa( - *, - match_resources: typing.Optional[typing.Union[MatchResourcesV1Alpha1, typing.Dict[builtins.str, typing.Any]]] = None, - param_ref: typing.Optional[typing.Union[ParamRefV1Alpha1, typing.Dict[builtins.str, typing.Any]]] = None, - policy_name: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__0419a6826a131473eb218fd7b964c8f1501e74582c4575a39889f77a48866837( - *, - validations: typing.Sequence[typing.Union[ValidationV1Alpha1, typing.Dict[builtins.str, typing.Any]]], - failure_policy: typing.Optional[builtins.str] = None, - match_constraints: typing.Optional[typing.Union[MatchResourcesV1Alpha1, typing.Dict[builtins.str, typing.Any]]] = None, - param_kind: typing.Optional[typing.Union[ParamKindV1Alpha1, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__ac0bdffd3ae40593dcc946344a4b810ff63dcf95c9d059bc98c0876523b7dbc9( - *, - admission_review_versions: typing.Sequence[builtins.str], - client_config: typing.Union[WebhookClientConfig, typing.Dict[builtins.str, typing.Any]], - name: builtins.str, - side_effects: builtins.str, - failure_policy: typing.Optional[builtins.str] = None, - match_policy: typing.Optional[builtins.str] = None, - namespace_selector: typing.Optional[typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]]] = None, - object_selector: typing.Optional[typing.Union[LabelSelector, typing.Dict[builtins.str, typing.Any]]] = None, - rules: typing.Optional[typing.Sequence[typing.Union[RuleWithOperations, typing.Dict[builtins.str, typing.Any]]]] = None, - timeout_seconds: typing.Optional[jsii.Number] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__8500698ff415569f959cc71557c593435adb8418cbc4abf4ced8324f4f0da96d( - *, - rule: builtins.str, - message: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__2e42e86e2cf6a0b9c2247c2d420d94cd03debba0ad4391ae8e0001bde4c15b3f( - *, - expression: builtins.str, - message: typing.Optional[builtins.str] = None, - reason: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__b0baec088296b673c4c879b5ee48b961991a0c2bba4add80d27e32c59d57f145( - *, - name: builtins.str, - aws_elastic_block_store: typing.Optional[typing.Union[AwsElasticBlockStoreVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - azure_disk: typing.Optional[typing.Union[AzureDiskVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - azure_file: typing.Optional[typing.Union[AzureFileVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - cephfs: typing.Optional[typing.Union[CephFsVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - cinder: typing.Optional[typing.Union[CinderVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - config_map: typing.Optional[typing.Union[ConfigMapVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - csi: typing.Optional[typing.Union[CsiVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - downward_api: typing.Optional[typing.Union[DownwardApiVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - empty_dir: typing.Optional[typing.Union[EmptyDirVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - ephemeral: typing.Optional[typing.Union[EphemeralVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - fc: typing.Optional[typing.Union[FcVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - flex_volume: typing.Optional[typing.Union[FlexVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - flocker: typing.Optional[typing.Union[FlockerVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - gce_persistent_disk: typing.Optional[typing.Union[GcePersistentDiskVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - git_repo: typing.Optional[typing.Union[GitRepoVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - glusterfs: typing.Optional[typing.Union[GlusterfsVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - host_path: typing.Optional[typing.Union[HostPathVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - iscsi: typing.Optional[typing.Union[IscsiVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - nfs: typing.Optional[typing.Union[NfsVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - persistent_volume_claim: typing.Optional[typing.Union[PersistentVolumeClaimVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - photon_persistent_disk: typing.Optional[typing.Union[PhotonPersistentDiskVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - portworx_volume: typing.Optional[typing.Union[PortworxVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - projected: typing.Optional[typing.Union[ProjectedVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - quobyte: typing.Optional[typing.Union[QuobyteVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - rbd: typing.Optional[typing.Union[RbdVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - scale_io: typing.Optional[typing.Union[ScaleIoVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - secret: typing.Optional[typing.Union[SecretVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - storageos: typing.Optional[typing.Union[StorageOsVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, - vsphere_volume: typing.Optional[typing.Union[VsphereVirtualDiskVolumeSource, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__b3f9952d5e8dadf3ded289f1651a13c30397c804b078b1918f7e368a400af926( - *, - inline_volume_spec: typing.Optional[typing.Union[PersistentVolumeSpec, typing.Dict[builtins.str, typing.Any]]] = None, - persistent_volume_name: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__c4b9cc875951c45fbf95df095c19992e6e0cb9bae73892b27970af014c9ef130( - *, - attacher: builtins.str, - node_name: builtins.str, - source: typing.Union[VolumeAttachmentSource, typing.Dict[builtins.str, typing.Any]], -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__79302810697edefbd8389c6b329719eb591c59ac9f35d9046bda0be521703345( - *, - device_path: builtins.str, - name: builtins.str, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__7bc86759e585609a7ca09f49d33b128e9d64f2504bc6d8b9cd2b329582357e17( - *, - mount_path: builtins.str, - name: builtins.str, - mount_propagation: typing.Optional[builtins.str] = None, - read_only: typing.Optional[builtins.bool] = None, - sub_path: typing.Optional[builtins.str] = None, - sub_path_expr: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__7c2f59acda00c7a6490c99644a0f6c1d5b9c7c0ca5e955d2d1c906c4defb4ade( - *, - required: typing.Optional[typing.Union[NodeSelector, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__2a5c11cd7f903e3f4b9668bb558dbf7b284d3be245138a41dc7978f947084911( - *, - count: typing.Optional[jsii.Number] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__21035918b928e2f804e2bbaaf7f50d5c4b3eb354a5e4a66e639edff79f735bfc( - *, - config_map: typing.Optional[typing.Union[ConfigMapProjection, typing.Dict[builtins.str, typing.Any]]] = None, - downward_api: typing.Optional[typing.Union[DownwardApiProjection, typing.Dict[builtins.str, typing.Any]]] = None, - secret: typing.Optional[typing.Union[SecretProjection, typing.Dict[builtins.str, typing.Any]]] = None, - service_account_token: typing.Optional[typing.Union[ServiceAccountTokenProjection, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__2746f4a6c4d559e6cea852caa195b0acdbccb5fcc65b72211461db64e954a2e0( - *, - volume_path: builtins.str, - fs_type: typing.Optional[builtins.str] = None, - storage_policy_id: typing.Optional[builtins.str] = None, - storage_policy_name: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__01a4d6ecbc5d3180d6159e848cb27db4b9411ca07eae56bb4a7c0ea53622d2a9( - *, - ca_bundle: typing.Optional[builtins.str] = None, - service: typing.Optional[typing.Union[ServiceReference, typing.Dict[builtins.str, typing.Any]]] = None, - url: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__39d792294d4b2186ea27ff788c8be1ec22d2503757195afb3bd815d2f0d57bdf( - *, - conversion_review_versions: typing.Sequence[builtins.str], - client_config: typing.Optional[typing.Union[WebhookClientConfig, typing.Dict[builtins.str, typing.Any]]] = None, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__889aca33f8b0538629ceed10073db78bcf15ce67a8d28c641286fa3ca92dd955( - *, - pod_affinity_term: typing.Union[PodAffinityTerm, typing.Dict[builtins.str, typing.Any]], - weight: jsii.Number, -) -> None: - """Type checking stubs""" - pass - -def _typecheckingstub__8f8f55e98c07892c190b8b23ad570c48466b356f369032020c69a96f2ea2d0ea( - *, - gmsa_credential_spec: typing.Optional[builtins.str] = None, - gmsa_credential_spec_name: typing.Optional[builtins.str] = None, - host_process: typing.Optional[builtins.bool] = None, - run_as_user_name: typing.Optional[builtins.str] = None, -) -> None: - """Type checking stubs""" - pass diff --git a/deployments/sequencer/imports/k8s/_jsii/__init__.py b/deployments/sequencer/imports/k8s/_jsii/__init__.py deleted file mode 100644 index 2e314cfbcbb..00000000000 --- a/deployments/sequencer/imports/k8s/_jsii/__init__.py +++ /dev/null @@ -1,42 +0,0 @@ -from pkgutil import extend_path -__path__ = extend_path(__path__, __name__) - -import abc -import builtins -import datetime -import enum -import typing - -import jsii -import publication -import typing_extensions - -import typeguard -from importlib.metadata import version as _metadata_package_version -TYPEGUARD_MAJOR_VERSION = int(_metadata_package_version('typeguard').split('.')[0]) - -def check_type(argname: str, value: object, expected_type: typing.Any) -> typing.Any: - if TYPEGUARD_MAJOR_VERSION <= 2: - return typeguard.check_type(argname=argname, value=value, expected_type=expected_type) # type:ignore - else: - if isinstance(value, jsii._reference_map.InterfaceDynamicProxy): # pyright: ignore [reportAttributeAccessIssue] - pass - else: - if TYPEGUARD_MAJOR_VERSION == 3: - typeguard.config.collection_check_strategy = typeguard.CollectionCheckStrategy.ALL_ITEMS # type:ignore - typeguard.check_type(value=value, expected_type=expected_type) # type:ignore - else: - typeguard.check_type(value=value, expected_type=expected_type, collection_check_strategy=typeguard.CollectionCheckStrategy.ALL_ITEMS) # type:ignore - -import cdk8s._jsii -import constructs._jsii - -__jsii_assembly__ = jsii.JSIIAssembly.load( - "k8s", "0.0.0", __name__[0:-6], "k8s@0.0.0.jsii.tgz" -) - -__all__ = [ - "__jsii_assembly__", -] - -publication.publish() diff --git a/deployments/sequencer/imports/k8s/_jsii/k8s@0.0.0.jsii.tgz b/deployments/sequencer/imports/k8s/_jsii/k8s@0.0.0.jsii.tgz deleted file mode 100644 index 176fdafb319..00000000000 Binary files a/deployments/sequencer/imports/k8s/_jsii/k8s@0.0.0.jsii.tgz and /dev/null differ diff --git a/deployments/sequencer/imports/k8s/py.typed b/deployments/sequencer/imports/k8s/py.typed deleted file mode 100644 index 8b137891791..00000000000 --- a/deployments/sequencer/imports/k8s/py.typed +++ /dev/null @@ -1 +0,0 @@ - diff --git a/deployments/sequencer/main.py b/deployments/sequencer/main.py index 09da3b83edc..d56f8b547ce 100644 --- a/deployments/sequencer/main.py +++ b/deployments/sequencer/main.py @@ -1,25 +1,12 @@ #!/usr/bin/env python3 -import dataclasses from constructs import Construct from cdk8s import App, Chart, YamlOutputType -from typing import Optional -from config.sequencer import Config from app.service import ServiceApp -from services import topology, helpers - - -@dataclasses.dataclass -class SystemStructure: - topology: str = "mesh" - replicas: str = "2" - size: str = "small" - config: Optional[Config] = None - - def __post_init__(self): - self.config.validate() +from app.monitoring import MonitoringApp +from services import topology, helpers, config, monitoring class SequencerNode(Chart): @@ -28,33 +15,59 @@ def __init__( scope: Construct, name: str, namespace: str, - topology: topology.ServiceTopology + service_topology: topology.ServiceTopology, ): - super().__init__( - scope, name, disable_resource_name_hashes=True, namespace=namespace - ) + super().__init__(scope, name, disable_resource_name_hashes=True, namespace=namespace) self.service = ServiceApp( - self, - name, - namespace=namespace, - topology=topology + self, name, namespace=namespace, service_topology=service_topology ) + +class SequencerMonitoring(Chart): + def __init__( + self, + scope: Construct, + name: str, + namespace: str, + grafana_dashboard: monitoring.GrafanaDashboard, + ): + super().__init__(scope, name, disable_resource_name_hashes=True, namespace=namespace) + self.dashboard = MonitoringApp( + self, name, namespace=namespace, grafana_dashboard=grafana_dashboard + ) + + def main(): - if helpers.args.env == "dev": - system_preset = topology.SequencerDev() - elif helpers.args.env == "prod": - system_preset = topology.SequencerProd() + args = helpers.argument_parser() + app = App(yaml_output_type=YamlOutputType.FOLDER_PER_CHART_FILE_PER_RESOURCE) - app = App( - yaml_output_type=YamlOutputType.FOLDER_PER_CHART_FILE_PER_RESOURCE - ) + preset = config.DeploymentConfig(args.deployment_config_file) + services = preset.get_services() + image = preset.get_image() + application_config_subdir = preset.get_application_config_subdir() + + for svc in services: + SequencerNode( + scope=app, + name=f'sequencer-{svc["name"].lower()}', + namespace=args.namespace, + service_topology=topology.ServiceTopology( + config=config.SequencerConfig( + config_subdir=application_config_subdir, config_path=svc["config_path"] + ), + image=image, + replicas=svc["replicas"], + autoscale=svc["autoscale"], + ingress=svc["ingress"], + storage=svc["storage"], + ), + ) - SequencerNode( + SequencerMonitoring( scope=app, - name="sequencer-node", - namespace=helpers.args.namespace, - topology=system_preset + name="sequencer-monitoring", + namespace=args.namespace, + grafana_dashboard=monitoring.GrafanaDashboard("dev_grafana.json"), ) app.synth() diff --git a/deployments/sequencer/package.json b/deployments/sequencer/package.json deleted file mode 100644 index a60dd8b1230..00000000000 --- a/deployments/sequencer/package.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "@python/cdk8s-crd", - "version": "0.0.0", - "main": "index.js", - "types": "index.d.ts", - "license": "Apache-2.0", - "private": true, - "scripts": { - "import": "cdk8s import", - "build": "npm run import && npm run synth", - "synth": "cdk8s synth" - } -} \ No newline at end of file diff --git a/deployments/sequencer/references/sequencer-node/ConfigMap.sequencer-node-config.k8s.yaml b/deployments/sequencer/references/sequencer-node/ConfigMap.sequencer-node-config.k8s.yaml index d2defb92b31..aff048ed46b 100644 --- a/deployments/sequencer/references/sequencer-node/ConfigMap.sequencer-node-config.k8s.yaml +++ b/deployments/sequencer/references/sequencer-node/ConfigMap.sequencer-node-config.k8s.yaml @@ -4,4 +4,4 @@ metadata: name: sequencer-node-config namespace: test data: - config: '{"chain_id": "0x5", "eth_fee_token_address": "0x6", "strk_fee_token_address": "0x7", "components.batcher.execution_mode": "Disabled", "components.batcher.local_server_config.#is_none": true, "components.consensus_manager.execution_mode": "Disabled", "components.gateway.execution_mode": "Disabled", "components.http_server.execution_mode": "Disabled", "components.mempool.execution_mode": "Disabled", "components.mempool_p2p.execution_mode": "Disabled", "components.consensus_manager.local_server_config.#is_none": true, "components.gateway.local_server_config.#is_none": true, "components.http_server.local_server_config.#is_none": true, "components.mempool.local_server_config.#is_none": true, "components.mempool_p2p.local_server_config.#is_none": true, "components.http_server.remote_server_config.#is_none": true, "batcher_config.storage.db_config.enforce_file_exists": false, "batcher_config.storage.db_config.path_prefix": "/data"}' + config: '{"base_layer_config.node_url": "https://node_url/", "base_layer_config.starknet_contract_address": "0xc662c410C0ECf747543f5bA90660f6ABeBD9C8c4", "batcher_config.block_builder_config.bouncer_config.block_max_capacity.builtin_count.add_mod": 156250, "batcher_config.block_builder_config.bouncer_config.block_max_capacity.builtin_count.bitwise": 39062, "batcher_config.block_builder_config.bouncer_config.block_max_capacity.builtin_count.ec_op": 2441, "batcher_config.block_builder_config.bouncer_config.block_max_capacity.builtin_count.ecdsa": 1220, "batcher_config.block_builder_config.bouncer_config.block_max_capacity.builtin_count.keccak": 1220, "batcher_config.block_builder_config.bouncer_config.block_max_capacity.builtin_count.mul_mod": 156250, "batcher_config.block_builder_config.bouncer_config.block_max_capacity.builtin_count.pedersen": 78125, "batcher_config.block_builder_config.bouncer_config.block_max_capacity.builtin_count.poseidon": 78125, "batcher_config.block_builder_config.bouncer_config.block_max_capacity.builtin_count.range_check": 156250, "batcher_config.block_builder_config.bouncer_config.block_max_capacity.builtin_count.range_check96": 156250, "batcher_config.block_builder_config.bouncer_config.block_max_capacity.l1_gas": 2500000, "batcher_config.block_builder_config.bouncer_config.block_max_capacity.message_segment_length": 3700, "batcher_config.block_builder_config.bouncer_config.block_max_capacity.n_events": 5000, "batcher_config.block_builder_config.bouncer_config.block_max_capacity.n_steps": 75000, "batcher_config.block_builder_config.bouncer_config.block_max_capacity.sierra_gas": 250000000, "batcher_config.block_builder_config.bouncer_config.block_max_capacity.state_diff_size": 4000, "batcher_config.block_builder_config.execute_config.concurrency_config.chunk_size": 64, "batcher_config.block_builder_config.execute_config.concurrency_config.enabled": true, "batcher_config.block_builder_config.execute_config.concurrency_config.n_workers": 4, "batcher_config.block_builder_config.execute_config.stack_size": 62914560, "batcher_config.block_builder_config.tx_chunk_size": 100, "batcher_config.contract_class_manager_config.cairo_native_run_config.channel_size": 2000, "batcher_config.contract_class_manager_config.cairo_native_run_config.run_cairo_native": false, "batcher_config.contract_class_manager_config.cairo_native_run_config.wait_on_native_compilation": false, "batcher_config.contract_class_manager_config.contract_cache_size": 600, "batcher_config.contract_class_manager_config.native_compiler_config.max_casm_bytecode_size": 81920, "batcher_config.contract_class_manager_config.native_compiler_config.max_cpu_time": 20, "batcher_config.contract_class_manager_config.native_compiler_config.max_memory_usage": 5368709120, "batcher_config.contract_class_manager_config.native_compiler_config.max_native_bytecode_size": 15728640, "batcher_config.contract_class_manager_config.native_compiler_config.sierra_to_native_compiler_path": "", "batcher_config.contract_class_manager_config.native_compiler_config.sierra_to_native_compiler_path.#is_none": true, "batcher_config.input_stream_content_buffer_size": 400, "batcher_config.max_l1_handler_txs_per_block_proposal": 3, "batcher_config.outstream_content_buffer_size": 100, "batcher_config.storage.db_config.enforce_file_exists": false, "batcher_config.storage.db_config.growth_step": 67108864, "batcher_config.storage.db_config.max_size": 34359738368, "batcher_config.storage.db_config.min_size": 1048576, "batcher_config.storage.db_config.path_prefix": "/data/node_0/executable_0/batcher", "batcher_config.storage.mmap_file_config.growth_step": 1048576, "batcher_config.storage.mmap_file_config.max_object_size": 65536, "batcher_config.storage.mmap_file_config.max_size": 16777216, "batcher_config.storage.scope": "StateOnly", "chain_id": "CHAIN_ID_SUBDIR", "class_manager_config.class_manager_config.cached_class_storage_config.class_cache_size": 100, "class_manager_config.class_manager_config.cached_class_storage_config.deprecated_class_cache_size": 100, "class_manager_config.class_storage_config.class_hash_storage_config.enforce_file_exists": false, "class_manager_config.class_storage_config.class_hash_storage_config.max_size": 1048576, "class_manager_config.class_storage_config.class_hash_storage_config.path_prefix": "/data/node_0/executable_0/class_manager/class_hash_storage", "class_manager_config.class_storage_config.persistent_root": "/data/node_0/executable_0/class_manager/persistent_root", "compiler_config.max_casm_bytecode_size": 81920, "compiler_config.max_cpu_time": 20, "compiler_config.max_memory_usage": 5368709120, "compiler_config.max_native_bytecode_size": 15728640, "compiler_config.sierra_to_native_compiler_path": "", "compiler_config.sierra_to_native_compiler_path.#is_none": true, "components.batcher.execution_mode": "LocalExecutionWithRemoteDisabled", "components.batcher.ip": "0.0.0.0", "components.batcher.local_server_config.channel_buffer_size": 32, "components.batcher.max_concurrency": 10, "components.batcher.port": 0, "components.batcher.remote_client_config.idle_connections": 18446744073709551615, "components.batcher.remote_client_config.idle_timeout": 90, "components.batcher.remote_client_config.retries": 3, "components.batcher.url": "localhost", "components.class_manager.execution_mode": "LocalExecutionWithRemoteDisabled", "components.class_manager.ip": "0.0.0.0", "components.class_manager.local_server_config.channel_buffer_size": 32, "components.class_manager.max_concurrency": 10, "components.class_manager.port": 0, "components.class_manager.remote_client_config.idle_connections": 18446744073709551615, "components.class_manager.remote_client_config.idle_timeout": 90, "components.class_manager.remote_client_config.retries": 3, "components.class_manager.url": "localhost", "components.consensus_manager.execution_mode": "Enabled", "components.gateway.execution_mode": "LocalExecutionWithRemoteDisabled", "components.gateway.ip": "0.0.0.0", "components.gateway.local_server_config.channel_buffer_size": 32, "components.gateway.max_concurrency": 10, "components.gateway.port": 0, "components.gateway.remote_client_config.idle_connections": 18446744073709551615, "components.gateway.remote_client_config.idle_timeout": 90, "components.gateway.remote_client_config.retries": 3, "components.gateway.url": "localhost", "components.http_server.execution_mode": "Enabled", "components.l1_provider.execution_mode": "LocalExecutionWithRemoteDisabled", "components.l1_provider.ip": "0.0.0.0", "components.l1_provider.local_server_config.channel_buffer_size": 32, "components.l1_provider.max_concurrency": 10, "components.l1_provider.port": 0, "components.l1_provider.remote_client_config.idle_connections": 18446744073709551615, "components.l1_provider.remote_client_config.idle_timeout": 90, "components.l1_provider.remote_client_config.retries": 3, "components.l1_provider.url": "localhost", "components.l1_scraper.execution_mode": "Enabled", "components.mempool.execution_mode": "LocalExecutionWithRemoteDisabled", "components.mempool.ip": "0.0.0.0", "components.mempool.local_server_config.channel_buffer_size": 32, "components.mempool.max_concurrency": 10, "components.mempool.port": 0, "components.mempool.remote_client_config.idle_connections": 18446744073709551615, "components.mempool.remote_client_config.idle_timeout": 90, "components.mempool.remote_client_config.retries": 3, "components.mempool.url": "localhost", "components.mempool_p2p.execution_mode": "LocalExecutionWithRemoteDisabled", "components.mempool_p2p.ip": "0.0.0.0", "components.mempool_p2p.local_server_config.channel_buffer_size": 32, "components.mempool_p2p.max_concurrency": 10, "components.mempool_p2p.port": 0, "components.mempool_p2p.remote_client_config.idle_connections": 18446744073709551615, "components.mempool_p2p.remote_client_config.idle_timeout": 90, "components.mempool_p2p.remote_client_config.retries": 3, "components.mempool_p2p.url": "localhost", "components.monitoring_endpoint.execution_mode": "Enabled", "components.sierra_compiler.execution_mode": "LocalExecutionWithRemoteDisabled", "components.sierra_compiler.ip": "0.0.0.0", "components.sierra_compiler.local_server_config.channel_buffer_size": 32, "components.sierra_compiler.max_concurrency": 10, "components.sierra_compiler.port": 0, "components.sierra_compiler.remote_client_config.idle_connections": 18446744073709551615, "components.sierra_compiler.remote_client_config.idle_timeout": 90, "components.sierra_compiler.remote_client_config.retries": 3, "components.sierra_compiler.url": "localhost", "components.state_sync.execution_mode": "LocalExecutionWithRemoteDisabled", "components.state_sync.ip": "0.0.0.0", "components.state_sync.local_server_config.channel_buffer_size": 32, "components.state_sync.max_concurrency": 10, "components.state_sync.port": 0, "components.state_sync.remote_client_config.idle_connections": 18446744073709551615, "components.state_sync.remote_client_config.idle_timeout": 90, "components.state_sync.remote_client_config.retries": 3, "components.state_sync.url": "localhost", "consensus_manager_config.broadcast_buffer_size": 10000, "consensus_manager_config.cende_config.certificates_file_path": "", "consensus_manager_config.cende_config.certificates_file_path.#is_none": true, "consensus_manager_config.cende_config.skip_write_height": 1, "consensus_manager_config.cende_config.skip_write_height.#is_none": false, "consensus_manager_config.consensus_config.future_height_limit": 10, "consensus_manager_config.consensus_config.future_height_round_limit": 1, "consensus_manager_config.consensus_config.future_round_limit": 10, "consensus_manager_config.consensus_config.startup_delay": 15, "consensus_manager_config.consensus_config.sync_retry_interval": 1.0, "consensus_manager_config.consensus_config.timeouts.precommit_timeout": 3.0, "consensus_manager_config.consensus_config.timeouts.prevote_timeout": 3.0, "consensus_manager_config.consensus_config.timeouts.proposal_timeout": 9.0, "consensus_manager_config.context_config.batcher_build_buffer": 100, "consensus_manager_config.context_config.block_timestamp_window": 1, "consensus_manager_config.context_config.l1_da_mode": true, "consensus_manager_config.context_config.num_validators": 1, "consensus_manager_config.immediate_active_height": 1, "consensus_manager_config.network_config.advertised_multiaddr": "", "consensus_manager_config.network_config.advertised_multiaddr.#is_none": true, "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "", "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": true, "consensus_manager_config.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": 2, "consensus_manager_config.network_config.discovery_config.bootstrap_dial_retry_config.factor": 5, "consensus_manager_config.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": 5, "consensus_manager_config.network_config.discovery_config.heartbeat_interval": 100, "consensus_manager_config.network_config.idle_connection_timeout": 120, "consensus_manager_config.network_config.peer_manager_config.malicious_timeout_seconds": 1, "consensus_manager_config.network_config.peer_manager_config.unstable_timeout_millis": 1000, "consensus_manager_config.network_config.secret_key": "0x0101010101010101010101010101010101010101010101010101010101010101", "consensus_manager_config.network_config.session_timeout": 120, "consensus_manager_config.network_config.tcp_port": 55540, "consensus_manager_config.proposals_topic": "consensus_proposals", "consensus_manager_config.votes_topic": "consensus_votes", "eth_fee_token_address": "0x1001", "gateway_config.stateful_tx_validator_config.max_nonce_for_validation_skip": "0x1", "gateway_config.stateless_tx_validator_config.max_calldata_length": 10, "gateway_config.stateless_tx_validator_config.max_contract_class_object_size": 4089446, "gateway_config.stateless_tx_validator_config.max_sierra_version.major": 1, "gateway_config.stateless_tx_validator_config.max_sierra_version.minor": 5, "gateway_config.stateless_tx_validator_config.max_sierra_version.patch": 18446744073709551615, "gateway_config.stateless_tx_validator_config.max_signature_length": 2, "gateway_config.stateless_tx_validator_config.min_sierra_version.major": 1, "gateway_config.stateless_tx_validator_config.min_sierra_version.minor": 1, "gateway_config.stateless_tx_validator_config.min_sierra_version.patch": 0, "gateway_config.stateless_tx_validator_config.validate_non_zero_l1_data_gas_fee": false, "gateway_config.stateless_tx_validator_config.validate_non_zero_l1_gas_fee": true, "gateway_config.stateless_tx_validator_config.validate_non_zero_l2_gas_fee": false, "http_server_config.ip": "127.0.0.1", "http_server_config.port": 8080, "l1_provider_config.bootstrap_catch_up_height": 0, "l1_provider_config.provider_startup_height": 1, "l1_provider_config.startup_sync_sleep_retry_interval": 0.0, "l1_scraper_config.finality": 0, "l1_scraper_config.polling_interval": 1, "l1_scraper_config.startup_rewind_time": 0, "mempool_p2p_config.network_buffer_size": 10000, "mempool_p2p_config.network_config.advertised_multiaddr": "", "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": true, "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "", "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": true, "mempool_p2p_config.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": 2, "mempool_p2p_config.network_config.discovery_config.bootstrap_dial_retry_config.factor": 5, "mempool_p2p_config.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": 5, "mempool_p2p_config.network_config.discovery_config.heartbeat_interval": 100, "mempool_p2p_config.network_config.idle_connection_timeout": 120, "mempool_p2p_config.network_config.peer_manager_config.malicious_timeout_seconds": 1, "mempool_p2p_config.network_config.peer_manager_config.unstable_timeout_millis": 1000, "mempool_p2p_config.network_config.secret_key": "0x0101010101010101010101010101010101010101010101010101010101010101", "mempool_p2p_config.network_config.session_timeout": 120, "mempool_p2p_config.network_config.tcp_port": 55542, "monitoring_endpoint_config.collect_metrics": true, "monitoring_endpoint_config.ip": "0.0.0.0", "monitoring_endpoint_config.port": 8082, "recorder_url": "http://127.0.0.1:55000/", "revert_config.revert_up_to_and_including": 18446744073709551615, "revert_config.should_revert": false, "state_sync_config.central_sync_client_config.#is_none": true, "state_sync_config.central_sync_client_config.central_source_config.class_cache_size": 100, "state_sync_config.central_sync_client_config.central_source_config.concurrent_requests": 10, "state_sync_config.central_sync_client_config.central_source_config.http_headers": "", "state_sync_config.central_sync_client_config.central_source_config.max_classes_to_download": 20, "state_sync_config.central_sync_client_config.central_source_config.max_state_updates_to_download": 20, "state_sync_config.central_sync_client_config.central_source_config.max_state_updates_to_store_in_memory": 20, "state_sync_config.central_sync_client_config.central_source_config.retry_config.max_retries": 10, "state_sync_config.central_sync_client_config.central_source_config.retry_config.retry_base_millis": 30, "state_sync_config.central_sync_client_config.central_source_config.retry_config.retry_max_delay_millis": 30000, "state_sync_config.central_sync_client_config.central_source_config.starknet_url": "https://alpha-mainnet.starknet.io/", "state_sync_config.central_sync_client_config.sync_config.base_layer_propagation_sleep_duration": 10, "state_sync_config.central_sync_client_config.sync_config.block_propagation_sleep_duration": 2, "state_sync_config.central_sync_client_config.sync_config.blocks_max_stream_size": 1000, "state_sync_config.central_sync_client_config.sync_config.collect_pending_data": false, "state_sync_config.central_sync_client_config.sync_config.recoverable_error_sleep_duration": 3, "state_sync_config.central_sync_client_config.sync_config.state_updates_max_stream_size": 1000, "state_sync_config.central_sync_client_config.sync_config.verify_blocks": true, "state_sync_config.network_config.advertised_multiaddr": "", "state_sync_config.network_config.advertised_multiaddr.#is_none": true, "state_sync_config.network_config.bootstrap_peer_multiaddr": "", "state_sync_config.network_config.bootstrap_peer_multiaddr.#is_none": true, "state_sync_config.network_config.discovery_config.bootstrap_dial_retry_config.base_delay_millis": 2, "state_sync_config.network_config.discovery_config.bootstrap_dial_retry_config.factor": 5, "state_sync_config.network_config.discovery_config.bootstrap_dial_retry_config.max_delay_seconds": 5, "state_sync_config.network_config.discovery_config.heartbeat_interval": 100, "state_sync_config.network_config.idle_connection_timeout": 120, "state_sync_config.network_config.peer_manager_config.malicious_timeout_seconds": 1, "state_sync_config.network_config.peer_manager_config.unstable_timeout_millis": 1000, "state_sync_config.network_config.secret_key": "0x0101010101010101010101010101010101010101010101010101010101010101", "state_sync_config.network_config.session_timeout": 120, "state_sync_config.network_config.tcp_port": 55541, "state_sync_config.p2p_sync_client_config.#is_none": false, "state_sync_config.p2p_sync_client_config.buffer_size": 100000, "state_sync_config.p2p_sync_client_config.num_block_classes_per_query": 100, "state_sync_config.p2p_sync_client_config.num_block_state_diffs_per_query": 100, "state_sync_config.p2p_sync_client_config.num_block_transactions_per_query": 100, "state_sync_config.p2p_sync_client_config.num_headers_per_query": 10000, "state_sync_config.p2p_sync_client_config.wait_period_for_new_data": 50, "state_sync_config.p2p_sync_client_config.wait_period_for_other_protocol": 50, "state_sync_config.storage_config.db_config.enforce_file_exists": false, "state_sync_config.storage_config.db_config.growth_step": 67108864, "state_sync_config.storage_config.db_config.max_size": 34359738368, "state_sync_config.storage_config.db_config.min_size": 1048576, "state_sync_config.storage_config.db_config.path_prefix": "/data/node_0/executable_0/state_sync", "state_sync_config.storage_config.mmap_file_config.growth_step": 1048576, "state_sync_config.storage_config.mmap_file_config.max_object_size": 65536, "state_sync_config.storage_config.mmap_file_config.max_size": 16777216, "state_sync_config.storage_config.scope": "FullArchive", "strk_fee_token_address": "0x1002", "validator_id": "0x64", "versioned_constants_overrides.invoke_tx_max_n_steps": 10000000, "versioned_constants_overrides.max_recursion_depth": 50, "versioned_constants_overrides.validate_max_n_steps": 1000000}' diff --git a/deployments/sequencer/references/sequencer-node/Deployment.sequencer-node-deployment.k8s.yaml b/deployments/sequencer/references/sequencer-node/Deployment.sequencer-node-deployment.k8s.yaml index c2bec23431b..2a3f0602460 100644 --- a/deployments/sequencer/references/sequencer-node/Deployment.sequencer-node-deployment.k8s.yaml +++ b/deployments/sequencer/references/sequencer-node/Deployment.sequencer-node-deployment.k8s.yaml @@ -17,7 +17,8 @@ spec: - args: - --config_file - /config/sequencer/presets/config - image: us.gcr.io/starkware-dev/sequencer-node-test:0.0.1-dev.3 + image: ghcr.io/starkware-libs/sequencer/sequencer:dev + imagePullPolicy: Always livenessProbe: failureThreshold: 5 httpGet: @@ -25,31 +26,33 @@ spec: port: 8082 periodSeconds: 10 timeoutSeconds: 5 - name: sequencer-node-server + name: sequencer-node ports: + - containerPort: 55540 - containerPort: 8080 - - containerPort: 8081 + - containerPort: 55542 - containerPort: 8082 + - containerPort: 55541 readinessProbe: failureThreshold: 5 httpGet: - path: /monitoring/ready + path: /monitoring/alive port: 8082 periodSeconds: 10 timeoutSeconds: 5 startupProbe: - failureThreshold: 10 + failureThreshold: 5 httpGet: - path: /monitoring/nodeVersion + path: /monitoring/alive port: 8082 periodSeconds: 10 timeoutSeconds: 5 volumeMounts: - mountPath: /config/sequencer/presets/ - name: config + name: sequencer-node-config readOnly: true - mountPath: /data - name: data + name: sequencer-node-data readOnly: false securityContext: fsGroup: 1000 diff --git a/deployments/sequencer/references/sequencer-node/Ingress.sequencer-node-ingress.k8s.yaml b/deployments/sequencer/references/sequencer-node/Ingress.sequencer-node-ingress.k8s.yaml index 7539704f4be..744f0b3ca9b 100644 --- a/deployments/sequencer/references/sequencer-node/Ingress.sequencer-node-ingress.k8s.yaml +++ b/deployments/sequencer/references/sequencer-node/Ingress.sequencer-node-ingress.k8s.yaml @@ -3,7 +3,7 @@ kind: Ingress metadata: annotations: acme.cert-manager.io/http01-edit-in-place: "true" - cert-manager.io/common-name: test.gcp-integration.sw-dev.io + cert-manager.io/common-name: sequencer-node.test.sw-dev.io cert-manager.io/issue-temporary-certificate: "true" cert-manager.io/issuer: letsencrypt-prod kubernetes.io/tls-acme: "true" @@ -13,7 +13,7 @@ metadata: namespace: test spec: rules: - - host: test.gcp-integration.sw-dev.io + - host: sequencer-node.test.sw-dev.io http: paths: - backend: @@ -21,9 +21,9 @@ spec: name: sequencer-node-service port: number: 8082 - path: /monitoring/ + path: /monitoring pathType: Prefix tls: - hosts: - - test.gcp-integration.sw-dev.io - secretName: sequencer-tls + - sequencer-node.test.sw-dev.io + secretName: sequencer-node-tls diff --git a/deployments/sequencer/references/sequencer-node/Service.sequencer-node-service.k8s.yaml b/deployments/sequencer/references/sequencer-node/Service.sequencer-node-service.k8s.yaml index 600478fde75..d7d860a81dc 100644 --- a/deployments/sequencer/references/sequencer-node/Service.sequencer-node-service.k8s.yaml +++ b/deployments/sequencer/references/sequencer-node/Service.sequencer-node-service.k8s.yaml @@ -5,15 +5,21 @@ metadata: namespace: test spec: ports: + - name: consensus + port: 55540 + targetPort: 55540 - name: http - port: 80 + port: 8080 targetPort: 8080 - - name: rpc - port: 8081 - targetPort: 8081 + - name: mempool + port: 55542 + targetPort: 55542 - name: monitoring port: 8082 targetPort: 8082 + - name: state + port: 55541 + targetPort: 55541 selector: app: sequencer-node type: ClusterIP diff --git a/deployments/sequencer/resources/crds/external_secrets_crd_bundle.yaml b/deployments/sequencer/resources/crds/external_secrets_crd_bundle.yaml new file mode 100644 index 00000000000..3d563e62842 --- /dev/null +++ b/deployments/sequencer/resources/crds/external_secrets_crd_bundle.yaml @@ -0,0 +1,18032 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.17.2 + labels: + external-secrets.io/component: controller + name: clusterexternalsecrets.external-secrets.io +spec: + group: external-secrets.io + names: + categories: + - external-secrets + kind: ClusterExternalSecret + listKind: ClusterExternalSecretList + plural: clusterexternalsecrets + shortNames: + - ces + singular: clusterexternalsecret + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .spec.externalSecretSpec.secretStoreRef.name + name: Store + type: string + - jsonPath: .spec.refreshTime + name: Refresh Interval + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + name: v1beta1 + schema: + openAPIV3Schema: + description: ClusterExternalSecret is the Schema for the clusterexternalsecrets API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: ClusterExternalSecretSpec defines the desired state of ClusterExternalSecret. + properties: + externalSecretMetadata: + description: The metadata of the external secrets to be created + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + externalSecretName: + description: |- + The name of the external secrets to be created. + Defaults to the name of the ClusterExternalSecret + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + externalSecretSpec: + description: The spec for the ExternalSecrets to be created + properties: + data: + description: Data defines the connection between the Kubernetes Secret keys and the Provider data + items: + description: ExternalSecretData defines the connection between the Kubernetes Secret key (spec.data.) and the Provider data. + properties: + remoteRef: + description: |- + RemoteRef points to the remote secret and defines + which secret (version/property/..) to fetch. + properties: + conversionStrategy: + default: Default + description: Used to define a conversion Strategy + enum: + - Default + - Unicode + type: string + decodingStrategy: + default: None + description: Used to define a decoding Strategy + enum: + - Auto + - Base64 + - Base64URL + - None + type: string + key: + description: Key is the key used in the Provider, mandatory + type: string + metadataPolicy: + default: None + description: Policy for fetching tags/labels from provider secrets, possible options are Fetch, None. Defaults to None + enum: + - None + - Fetch + type: string + property: + description: Used to select a specific property of the Provider value (if a map), if supported + type: string + version: + description: Used to select a specific version of the Provider value, if supported + type: string + required: + - key + type: object + secretKey: + description: The key in the Kubernetes Secret to store the value. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + sourceRef: + description: |- + SourceRef allows you to override the source + from which the value will be pulled. + maxProperties: 1 + minProperties: 1 + properties: + generatorRef: + description: |- + GeneratorRef points to a generator custom resource. + + Deprecated: The generatorRef is not implemented in .data[]. + this will be removed with v1. + properties: + apiVersion: + default: generators.external-secrets.io/v1alpha1 + description: Specify the apiVersion of the generator resource + type: string + kind: + description: Specify the Kind of the generator resource + enum: + - ACRAccessToken + - ClusterGenerator + - ECRAuthorizationToken + - Fake + - GCRAccessToken + - GithubAccessToken + - QuayAccessToken + - Password + - STSSessionToken + - UUID + - VaultDynamicSecret + - Webhook + - Grafana + type: string + name: + description: Specify the name of the generator resource + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - kind + - name + type: object + storeRef: + description: SecretStoreRef defines which SecretStore to fetch the ExternalSecret data. + properties: + kind: + description: |- + Kind of the SecretStore resource (SecretStore or ClusterSecretStore) + Defaults to `SecretStore` + enum: + - SecretStore + - ClusterSecretStore + type: string + name: + description: Name of the SecretStore resource + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + type: object + type: object + required: + - remoteRef + - secretKey + type: object + type: array + dataFrom: + description: |- + DataFrom is used to fetch all properties from a specific Provider data + If multiple entries are specified, the Secret keys are merged in the specified order + items: + properties: + extract: + description: |- + Used to extract multiple key/value pairs from one secret + Note: Extract does not support sourceRef.Generator or sourceRef.GeneratorRef. + properties: + conversionStrategy: + default: Default + description: Used to define a conversion Strategy + enum: + - Default + - Unicode + type: string + decodingStrategy: + default: None + description: Used to define a decoding Strategy + enum: + - Auto + - Base64 + - Base64URL + - None + type: string + key: + description: Key is the key used in the Provider, mandatory + type: string + metadataPolicy: + default: None + description: Policy for fetching tags/labels from provider secrets, possible options are Fetch, None. Defaults to None + enum: + - None + - Fetch + type: string + property: + description: Used to select a specific property of the Provider value (if a map), if supported + type: string + version: + description: Used to select a specific version of the Provider value, if supported + type: string + required: + - key + type: object + find: + description: |- + Used to find secrets based on tags or regular expressions + Note: Find does not support sourceRef.Generator or sourceRef.GeneratorRef. + properties: + conversionStrategy: + default: Default + description: Used to define a conversion Strategy + enum: + - Default + - Unicode + type: string + decodingStrategy: + default: None + description: Used to define a decoding Strategy + enum: + - Auto + - Base64 + - Base64URL + - None + type: string + name: + description: Finds secrets based on the name. + properties: + regexp: + description: Finds secrets base + type: string + type: object + path: + description: A root path to start the find operations. + type: string + tags: + additionalProperties: + type: string + description: Find secrets based on tags. + type: object + type: object + rewrite: + description: |- + Used to rewrite secret Keys after getting them from the secret Provider + Multiple Rewrite operations can be provided. They are applied in a layered order (first to last) + items: + properties: + regexp: + description: |- + Used to rewrite with regular expressions. + The resulting key will be the output of a regexp.ReplaceAll operation. + properties: + source: + description: Used to define the regular expression of a re.Compiler. + type: string + target: + description: Used to define the target pattern of a ReplaceAll operation. + type: string + required: + - source + - target + type: object + transform: + description: |- + Used to apply string transformation on the secrets. + The resulting key will be the output of the template applied by the operation. + properties: + template: + description: |- + Used to define the template to apply on the secret name. + `.value ` will specify the secret name in the template. + type: string + required: + - template + type: object + type: object + type: array + sourceRef: + description: |- + SourceRef points to a store or generator + which contains secret values ready to use. + Use this in combination with Extract or Find pull values out of + a specific SecretStore. + When sourceRef points to a generator Extract or Find is not supported. + The generator returns a static map of values + maxProperties: 1 + minProperties: 1 + properties: + generatorRef: + description: GeneratorRef points to a generator custom resource. + properties: + apiVersion: + default: generators.external-secrets.io/v1alpha1 + description: Specify the apiVersion of the generator resource + type: string + kind: + description: Specify the Kind of the generator resource + enum: + - ACRAccessToken + - ClusterGenerator + - ECRAuthorizationToken + - Fake + - GCRAccessToken + - GithubAccessToken + - QuayAccessToken + - Password + - STSSessionToken + - UUID + - VaultDynamicSecret + - Webhook + - Grafana + type: string + name: + description: Specify the name of the generator resource + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - kind + - name + type: object + storeRef: + description: SecretStoreRef defines which SecretStore to fetch the ExternalSecret data. + properties: + kind: + description: |- + Kind of the SecretStore resource (SecretStore or ClusterSecretStore) + Defaults to `SecretStore` + enum: + - SecretStore + - ClusterSecretStore + type: string + name: + description: Name of the SecretStore resource + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + type: object + type: object + type: object + type: array + refreshInterval: + default: 1h + description: |- + RefreshInterval is the amount of time before the values are read again from the SecretStore provider, + specified as Golang Duration strings. + Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h" + Example values: "1h", "2h30m", "5d", "10s" + May be set to zero to fetch and create it once. Defaults to 1h. + type: string + secretStoreRef: + description: SecretStoreRef defines which SecretStore to fetch the ExternalSecret data. + properties: + kind: + description: |- + Kind of the SecretStore resource (SecretStore or ClusterSecretStore) + Defaults to `SecretStore` + enum: + - SecretStore + - ClusterSecretStore + type: string + name: + description: Name of the SecretStore resource + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + type: object + target: + default: + creationPolicy: Owner + deletionPolicy: Retain + description: |- + ExternalSecretTarget defines the Kubernetes Secret to be created + There can be only one target per ExternalSecret. + properties: + creationPolicy: + default: Owner + description: |- + CreationPolicy defines rules on how to create the resulting Secret. + Defaults to "Owner" + enum: + - Owner + - Orphan + - Merge + - None + type: string + deletionPolicy: + default: Retain + description: |- + DeletionPolicy defines rules on how to delete the resulting Secret. + Defaults to "Retain" + enum: + - Delete + - Merge + - Retain + type: string + immutable: + description: Immutable defines if the final secret will be immutable + type: boolean + name: + description: |- + The name of the Secret resource to be managed. + Defaults to the .metadata.name of the ExternalSecret resource + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + template: + description: Template defines a blueprint for the created Secret resource. + properties: + data: + additionalProperties: + type: string + type: object + engineVersion: + default: v2 + description: |- + EngineVersion specifies the template engine version + that should be used to compile/execute the + template specified in .data and .templateFrom[]. + enum: + - v1 + - v2 + type: string + mergePolicy: + default: Replace + enum: + - Replace + - Merge + type: string + metadata: + description: ExternalSecretTemplateMetadata defines metadata fields for the Secret blueprint. + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + templateFrom: + items: + properties: + configMap: + properties: + items: + description: A list of keys in the ConfigMap/Secret to use as templates for Secret data + items: + properties: + key: + description: A key in the ConfigMap/Secret + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + templateAs: + default: Values + enum: + - Values + - KeysAndValues + type: string + required: + - key + type: object + type: array + name: + description: The name of the ConfigMap/Secret resource + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - items + - name + type: object + literal: + type: string + secret: + properties: + items: + description: A list of keys in the ConfigMap/Secret to use as templates for Secret data + items: + properties: + key: + description: A key in the ConfigMap/Secret + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + templateAs: + default: Values + enum: + - Values + - KeysAndValues + type: string + required: + - key + type: object + type: array + name: + description: The name of the ConfigMap/Secret resource + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - items + - name + type: object + target: + default: Data + enum: + - Data + - Annotations + - Labels + type: string + type: object + type: array + type: + type: string + type: object + type: object + type: object + namespaceSelector: + description: |- + The labels to select by to find the Namespaces to create the ExternalSecrets in. + Deprecated: Use NamespaceSelectors instead. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaceSelectors: + description: A list of labels to select by to find the Namespaces to create the ExternalSecrets in. The selectors are ORed. + items: + description: |- + A label selector is a label query over a set of resources. The result of matchLabels and + matchExpressions are ANDed. An empty label selector matches all objects. A null + label selector matches no objects. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: array + namespaces: + description: Choose namespaces by name. This field is ORed with anything that NamespaceSelectors ends up choosing. + items: + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: array + refreshTime: + description: The time in which the controller should reconcile its objects and recheck namespaces for labels. + type: string + required: + - externalSecretSpec + type: object + status: + description: ClusterExternalSecretStatus defines the observed state of ClusterExternalSecret. + properties: + conditions: + items: + properties: + message: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + externalSecretName: + description: ExternalSecretName is the name of the ExternalSecrets created by the ClusterExternalSecret + type: string + failedNamespaces: + description: Failed namespaces are the namespaces that failed to apply an ExternalSecret + items: + description: ClusterExternalSecretNamespaceFailure represents a failed namespace deployment and it's reason. + properties: + namespace: + description: Namespace is the namespace that failed when trying to apply an ExternalSecret + type: string + reason: + description: Reason is why the ExternalSecret failed to apply to the namespace + type: string + required: + - namespace + type: object + type: array + provisionedNamespaces: + description: ProvisionedNamespaces are the namespaces where the ClusterExternalSecret has secrets + items: + type: string + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} + conversion: + strategy: Webhook + webhook: + conversionReviewVersions: + - v1 + clientConfig: + service: + name: kubernetes + namespace: default + path: /convert +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.17.2 + labels: + external-secrets.io/component: controller + name: clustersecretstores.external-secrets.io +spec: + group: external-secrets.io + names: + categories: + - external-secrets + kind: ClusterSecretStore + listKind: ClusterSecretStoreList + plural: clustersecretstores + shortNames: + - css + singular: clustersecretstore + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: AGE + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].reason + name: Status + type: string + deprecated: true + name: v1alpha1 + schema: + openAPIV3Schema: + description: ClusterSecretStore represents a secure external location for storing secrets, which can be referenced as part of `storeRef` fields. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: SecretStoreSpec defines the desired state of SecretStore. + properties: + controller: + description: |- + Used to select the correct ESO controller (think: ingress.ingressClassName) + The ESO controller is instantiated with a specific controller name and filters ES based on this property + type: string + provider: + description: Used to configure the provider. Only one provider may be set + maxProperties: 1 + minProperties: 1 + properties: + akeyless: + description: Akeyless configures this store to sync secrets using Akeyless Vault provider + properties: + akeylessGWApiURL: + description: Akeyless GW API Url from which the secrets to be fetched from. + type: string + authSecretRef: + description: Auth configures how the operator authenticates with Akeyless. + properties: + kubernetesAuth: + description: |- + Kubernetes authenticates with Akeyless by passing the ServiceAccount + token stored in the named Secret resource. + properties: + accessID: + description: the Akeyless Kubernetes auth-method access-id + type: string + k8sConfName: + description: Kubernetes-auth configuration name in Akeyless-Gateway + type: string + secretRef: + description: |- + Optional secret field containing a Kubernetes ServiceAccount JWT used + for authenticating with Akeyless. If a name is specified without a key, + `token` is the default. If one is not specified, the one bound to + the controller will be used. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + serviceAccountRef: + description: |- + Optional service account field containing the name of a kubernetes ServiceAccount. + If the service account is specified, the service account secret token JWT will be used + for authenticating with Akeyless. If the service account selector is not supplied, + the secretRef will be used instead. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + required: + - accessID + - k8sConfName + type: object + secretRef: + description: |- + Reference to a Secret that contains the details + to authenticate with Akeyless. + properties: + accessID: + description: The SecretAccessID is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + accessType: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + accessTypeParam: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + type: object + caBundle: + description: |- + PEM/base64 encoded CA bundle used to validate Akeyless Gateway certificate. Only used + if the AkeylessGWApiURL URL is using HTTPS protocol. If not set the system root certificates + are used to validate the TLS connection. + format: byte + type: string + caProvider: + description: The provider for the CA bundle to use to validate Akeyless Gateway certificate. + properties: + key: + description: The key where the CA certificate can be found in the Secret or ConfigMap. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the object located at the provider type. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: The namespace the Provider type is in. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + required: + - akeylessGWApiURL + - authSecretRef + type: object + alibaba: + description: Alibaba configures this store to sync secrets using Alibaba Cloud provider + properties: + auth: + description: AlibabaAuth contains a secretRef for credentials. + properties: + rrsa: + description: Authenticate against Alibaba using RRSA. + properties: + oidcProviderArn: + type: string + oidcTokenFilePath: + type: string + roleArn: + type: string + sessionName: + type: string + required: + - oidcProviderArn + - oidcTokenFilePath + - roleArn + - sessionName + type: object + secretRef: + description: AlibabaAuthSecretRef holds secret references for Alibaba credentials. + properties: + accessKeyIDSecretRef: + description: The AccessKeyID is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + accessKeySecretSecretRef: + description: The AccessKeySecret is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - accessKeyIDSecretRef + - accessKeySecretSecretRef + type: object + type: object + regionID: + description: Alibaba Region to be used for the provider + type: string + required: + - auth + - regionID + type: object + aws: + description: AWS configures this store to sync secrets using AWS Secret Manager provider + properties: + auth: + description: |- + Auth defines the information necessary to authenticate against AWS + if not set aws sdk will infer credentials from your environment + see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials + properties: + jwt: + description: Authenticate against AWS using service account tokens. + properties: + serviceAccountRef: + description: A reference to a ServiceAccount resource. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + type: object + secretRef: + description: |- + AWSAuthSecretRef holds secret references for AWS credentials + both AccessKeyID and SecretAccessKey must be defined in order to properly authenticate. + properties: + accessKeyIDSecretRef: + description: The AccessKeyID is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + secretAccessKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + type: object + region: + description: AWS Region to be used for the provider + type: string + role: + description: Role is a Role ARN which the SecretManager provider will assume + type: string + service: + description: Service defines which service should be used to fetch the secrets + enum: + - SecretsManager + - ParameterStore + type: string + required: + - region + - service + type: object + azurekv: + description: AzureKV configures this store to sync secrets using Azure Key Vault provider + properties: + authSecretRef: + description: Auth configures how the operator authenticates with Azure. Required for ServicePrincipal auth type. + properties: + clientId: + description: The Azure clientId of the service principle used for authentication. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + clientSecret: + description: The Azure ClientSecret of the service principle used for authentication. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + authType: + default: ServicePrincipal + description: |- + Auth type defines how to authenticate to the keyvault service. + Valid values are: + - "ServicePrincipal" (default): Using a service principal (tenantId, clientId, clientSecret) + - "ManagedIdentity": Using Managed Identity assigned to the pod (see aad-pod-identity) + enum: + - ServicePrincipal + - ManagedIdentity + - WorkloadIdentity + type: string + identityId: + description: If multiple Managed Identity is assigned to the pod, you can select the one to be used + type: string + serviceAccountRef: + description: |- + ServiceAccountRef specified the service account + that should be used when authenticating with WorkloadIdentity. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + tenantId: + description: TenantID configures the Azure Tenant to send requests to. Required for ServicePrincipal auth type. + type: string + vaultUrl: + description: Vault Url from which the secrets to be fetched from. + type: string + required: + - vaultUrl + type: object + fake: + description: Fake configures a store with static key/value pairs + properties: + data: + items: + properties: + key: + type: string + value: + type: string + valueMap: + additionalProperties: + type: string + type: object + version: + type: string + required: + - key + type: object + type: array + required: + - data + type: object + gcpsm: + description: GCPSM configures this store to sync secrets using Google Cloud Platform Secret Manager provider + properties: + auth: + description: Auth defines the information necessary to authenticate against GCP + properties: + secretRef: + properties: + secretAccessKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + workloadIdentity: + properties: + clusterLocation: + type: string + clusterName: + type: string + clusterProjectID: + type: string + serviceAccountRef: + description: A reference to a ServiceAccount resource. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + required: + - clusterLocation + - clusterName + - serviceAccountRef + type: object + type: object + projectID: + description: ProjectID project where secret is located + type: string + type: object + gitlab: + description: GitLab configures this store to sync secrets using GitLab Variables provider + properties: + auth: + description: Auth configures how secret-manager authenticates with a GitLab instance. + properties: + SecretRef: + properties: + accessToken: + description: AccessToken is used for authentication. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + required: + - SecretRef + type: object + projectID: + description: ProjectID specifies a project where secrets are located. + type: string + url: + description: URL configures the GitLab instance URL. Defaults to https://gitlab.com/. + type: string + required: + - auth + type: object + ibm: + description: IBM configures this store to sync secrets using IBM Cloud provider + properties: + auth: + description: Auth configures how secret-manager authenticates with the IBM secrets manager. + properties: + secretRef: + properties: + secretApiKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + required: + - secretRef + type: object + serviceUrl: + description: ServiceURL is the Endpoint URL that is specific to the Secrets Manager service instance + type: string + required: + - auth + type: object + kubernetes: + description: Kubernetes configures this store to sync secrets using a Kubernetes cluster provider + properties: + auth: + description: Auth configures how secret-manager authenticates with a Kubernetes instance. + maxProperties: 1 + minProperties: 1 + properties: + cert: + description: has both clientCert and clientKey as secretKeySelector + properties: + clientCert: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + clientKey: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + serviceAccount: + description: points to a service account that should be used for authentication + properties: + serviceAccount: + description: A reference to a ServiceAccount resource. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + type: object + token: + description: use static token to authenticate with + properties: + bearerToken: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + type: object + remoteNamespace: + default: default + description: Remote namespace to fetch the secrets from + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + server: + description: configures the Kubernetes server Address. + properties: + caBundle: + description: CABundle is a base64-encoded CA certificate + format: byte + type: string + caProvider: + description: 'see: https://external-secrets.io/v0.4.1/spec/#external-secrets.io/v1alpha1.CAProvider' + properties: + key: + description: The key where the CA certificate can be found in the Secret or ConfigMap. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the object located at the provider type. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: The namespace the Provider type is in. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + url: + default: kubernetes.default + description: configures the Kubernetes server Address. + type: string + type: object + required: + - auth + type: object + oracle: + description: Oracle configures this store to sync secrets using Oracle Vault provider + properties: + auth: + description: |- + Auth configures how secret-manager authenticates with the Oracle Vault. + If empty, instance principal is used. Optionally, the authenticating principal type + and/or user data may be supplied for the use of workload identity and user principal. + properties: + secretRef: + description: SecretRef to pass through sensitive information. + properties: + fingerprint: + description: Fingerprint is the fingerprint of the API private key. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + privatekey: + description: PrivateKey is the user's API Signing Key in PEM format, used for authentication. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - fingerprint + - privatekey + type: object + tenancy: + description: Tenancy is the tenancy OCID where user is located. + type: string + user: + description: User is an access OCID specific to the account. + type: string + required: + - secretRef + - tenancy + - user + type: object + compartment: + description: |- + Compartment is the vault compartment OCID. + Required for PushSecret + type: string + encryptionKey: + description: |- + EncryptionKey is the OCID of the encryption key within the vault. + Required for PushSecret + type: string + principalType: + description: |- + The type of principal to use for authentication. If left blank, the Auth struct will + determine the principal type. This optional field must be specified if using + workload identity. + enum: + - "" + - UserPrincipal + - InstancePrincipal + - Workload + type: string + region: + description: Region is the region where vault is located. + type: string + serviceAccountRef: + description: |- + ServiceAccountRef specified the service account + that should be used when authenticating with WorkloadIdentity. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + vault: + description: Vault is the vault's OCID of the specific vault where secret is located. + type: string + required: + - region + - vault + type: object + passworddepot: + description: Configures a store to sync secrets with a Password Depot instance. + properties: + auth: + description: Auth configures how secret-manager authenticates with a Password Depot instance. + properties: + secretRef: + properties: + credentials: + description: Username / Password is used for authentication. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + required: + - secretRef + type: object + database: + description: Database to use as source + type: string + host: + description: URL configures the Password Depot instance URL. + type: string + required: + - auth + - database + - host + type: object + vault: + description: Vault configures this store to sync secrets using Hashi provider + properties: + auth: + description: Auth configures how secret-manager authenticates with the Vault server. + properties: + appRole: + description: |- + AppRole authenticates with Vault using the App Role auth mechanism, + with the role and secret stored in a Kubernetes Secret resource. + properties: + path: + default: approle + description: |- + Path where the App Role authentication backend is mounted + in Vault, e.g: "approle" + type: string + roleId: + description: |- + RoleID configured in the App Role authentication backend when setting + up the authentication backend in Vault. + type: string + secretRef: + description: |- + Reference to a key in a Secret that contains the App Role secret used + to authenticate with Vault. + The `key` field must be specified and denotes which entry within the Secret + resource is used as the app role secret. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - path + - roleId + - secretRef + type: object + cert: + description: |- + Cert authenticates with TLS Certificates by passing client certificate, private key and ca certificate + Cert authentication method + properties: + clientCert: + description: |- + ClientCert is a certificate to authenticate using the Cert Vault + authentication method + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + secretRef: + description: |- + SecretRef to a key in a Secret resource containing client private key to + authenticate with Vault using the Cert authentication method + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + jwt: + description: |- + Jwt authenticates with Vault by passing role and JWT token using the + JWT/OIDC authentication method + properties: + kubernetesServiceAccountToken: + description: |- + Optional ServiceAccountToken specifies the Kubernetes service account for which to request + a token for with the `TokenRequest` API. + properties: + audiences: + description: |- + Optional audiences field that will be used to request a temporary Kubernetes service + account token for the service account referenced by `serviceAccountRef`. + Defaults to a single audience `vault` it not specified. + items: + type: string + type: array + expirationSeconds: + description: |- + Optional expiration time in seconds that will be used to request a temporary + Kubernetes service account token for the service account referenced by + `serviceAccountRef`. + Defaults to 10 minutes. + format: int64 + type: integer + serviceAccountRef: + description: Service account field containing the name of a kubernetes ServiceAccount. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + required: + - serviceAccountRef + type: object + path: + default: jwt + description: |- + Path where the JWT authentication backend is mounted + in Vault, e.g: "jwt" + type: string + role: + description: |- + Role is a JWT role to authenticate using the JWT/OIDC Vault + authentication method + type: string + secretRef: + description: |- + Optional SecretRef that refers to a key in a Secret resource containing JWT token to + authenticate with Vault using the JWT/OIDC authentication method. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - path + type: object + kubernetes: + description: |- + Kubernetes authenticates with Vault by passing the ServiceAccount + token stored in the named Secret resource to the Vault server. + properties: + mountPath: + default: kubernetes + description: |- + Path where the Kubernetes authentication backend is mounted in Vault, e.g: + "kubernetes" + type: string + role: + description: |- + A required field containing the Vault Role to assume. A Role binds a + Kubernetes ServiceAccount with a set of Vault policies. + type: string + secretRef: + description: |- + Optional secret field containing a Kubernetes ServiceAccount JWT used + for authenticating with Vault. If a name is specified without a key, + `token` is the default. If one is not specified, the one bound to + the controller will be used. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + serviceAccountRef: + description: |- + Optional service account field containing the name of a kubernetes ServiceAccount. + If the service account is specified, the service account secret token JWT will be used + for authenticating with Vault. If the service account selector is not supplied, + the secretRef will be used instead. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + required: + - mountPath + - role + type: object + ldap: + description: |- + Ldap authenticates with Vault by passing username/password pair using + the LDAP authentication method + properties: + path: + default: ldap + description: |- + Path where the LDAP authentication backend is mounted + in Vault, e.g: "ldap" + type: string + secretRef: + description: |- + SecretRef to a key in a Secret resource containing password for the LDAP + user used to authenticate with Vault using the LDAP authentication + method + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + username: + description: |- + Username is a LDAP user name used to authenticate using the LDAP Vault + authentication method + type: string + required: + - path + - username + type: object + tokenSecretRef: + description: TokenSecretRef authenticates with Vault by presenting a token. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + caBundle: + description: |- + PEM encoded CA bundle used to validate Vault server certificate. Only used + if the Server URL is using HTTPS protocol. This parameter is ignored for + plain HTTP protocol connection. If not set the system root certificates + are used to validate the TLS connection. + format: byte + type: string + caProvider: + description: The provider for the CA bundle to use to validate Vault server certificate. + properties: + key: + description: The key where the CA certificate can be found in the Secret or ConfigMap. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the object located at the provider type. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: The namespace the Provider type is in. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + forwardInconsistent: + description: |- + ForwardInconsistent tells Vault to forward read-after-write requests to the Vault + leader instead of simply retrying within a loop. This can increase performance if + the option is enabled serverside. + https://www.vaultproject.io/docs/configuration/replication#allow_forwarding_via_header + type: boolean + namespace: + description: |- + Name of the vault namespace. Namespaces is a set of features within Vault Enterprise that allows + Vault environments to support Secure Multi-tenancy. e.g: "ns1". + More about namespaces can be found here https://www.vaultproject.io/docs/enterprise/namespaces + type: string + path: + description: |- + Path is the mount path of the Vault KV backend endpoint, e.g: + "secret". The v2 KV secret engine version specific "/data" path suffix + for fetching secrets from Vault is optional and will be appended + if not present in specified path. + type: string + readYourWrites: + description: |- + ReadYourWrites ensures isolated read-after-write semantics by + providing discovered cluster replication states in each request. + More information about eventual consistency in Vault can be found here + https://www.vaultproject.io/docs/enterprise/consistency + type: boolean + server: + description: 'Server is the connection address for the Vault server, e.g: "https://vault.example.com:8200".' + type: string + version: + default: v2 + description: |- + Version is the Vault KV secret engine version. This can be either "v1" or + "v2". Version defaults to "v2". + enum: + - v1 + - v2 + type: string + required: + - auth + - server + type: object + webhook: + description: Webhook configures this store to sync secrets using a generic templated webhook + properties: + body: + description: Body + type: string + caBundle: + description: |- + PEM encoded CA bundle used to validate webhook server certificate. Only used + if the Server URL is using HTTPS protocol. This parameter is ignored for + plain HTTP protocol connection. If not set the system root certificates + are used to validate the TLS connection. + format: byte + type: string + caProvider: + description: The provider for the CA bundle to use to validate webhook server certificate. + properties: + key: + description: The key where the CA certificate can be found in the Secret or ConfigMap. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the object located at the provider type. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: The namespace the Provider type is in. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + headers: + additionalProperties: + type: string + description: Headers + type: object + method: + description: Webhook Method + type: string + result: + description: Result formatting + properties: + jsonPath: + description: Json path of return value + type: string + type: object + secrets: + description: |- + Secrets to fill in templates + These secrets will be passed to the templating function as key value pairs under the given name + items: + properties: + name: + description: Name of this secret in templates + type: string + secretRef: + description: Secret ref to fill in credentials + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - name + - secretRef + type: object + type: array + timeout: + description: Timeout + type: string + url: + description: Webhook url to call + type: string + required: + - result + - url + type: object + yandexlockbox: + description: YandexLockbox configures this store to sync secrets using Yandex Lockbox provider + properties: + apiEndpoint: + description: Yandex.Cloud API endpoint (e.g. 'api.cloud.yandex.net:443') + type: string + auth: + description: Auth defines the information necessary to authenticate against Yandex Lockbox + properties: + authorizedKeySecretRef: + description: The authorized key used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + caProvider: + description: The provider for the CA bundle to use to validate Yandex.Cloud server certificate. + properties: + certSecretRef: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + required: + - auth + type: object + type: object + retrySettings: + description: Used to configure http retries if failed + properties: + maxRetries: + format: int32 + type: integer + retryInterval: + type: string + type: object + required: + - provider + type: object + status: + description: SecretStoreStatus defines the observed state of the SecretStore. + properties: + conditions: + items: + properties: + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + type: object + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: AGE + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].reason + name: Status + type: string + - jsonPath: .status.capabilities + name: Capabilities + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + name: v1beta1 + schema: + openAPIV3Schema: + description: ClusterSecretStore represents a secure external location for storing secrets, which can be referenced as part of `storeRef` fields. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: SecretStoreSpec defines the desired state of SecretStore. + properties: + conditions: + description: Used to constraint a ClusterSecretStore to specific namespaces. Relevant only to ClusterSecretStore + items: + description: |- + ClusterSecretStoreCondition describes a condition by which to choose namespaces to process ExternalSecrets in + for a ClusterSecretStore instance. + properties: + namespaceRegexes: + description: Choose namespaces by using regex matching + items: + type: string + type: array + namespaceSelector: + description: Choose namespace using a labelSelector + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: Choose namespaces by name + items: + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: array + type: object + type: array + controller: + description: |- + Used to select the correct ESO controller (think: ingress.ingressClassName) + The ESO controller is instantiated with a specific controller name and filters ES based on this property + type: string + provider: + description: Used to configure the provider. Only one provider may be set + maxProperties: 1 + minProperties: 1 + properties: + akeyless: + description: Akeyless configures this store to sync secrets using Akeyless Vault provider + properties: + akeylessGWApiURL: + description: Akeyless GW API Url from which the secrets to be fetched from. + type: string + authSecretRef: + description: Auth configures how the operator authenticates with Akeyless. + properties: + kubernetesAuth: + description: |- + Kubernetes authenticates with Akeyless by passing the ServiceAccount + token stored in the named Secret resource. + properties: + accessID: + description: the Akeyless Kubernetes auth-method access-id + type: string + k8sConfName: + description: Kubernetes-auth configuration name in Akeyless-Gateway + type: string + secretRef: + description: |- + Optional secret field containing a Kubernetes ServiceAccount JWT used + for authenticating with Akeyless. If a name is specified without a key, + `token` is the default. If one is not specified, the one bound to + the controller will be used. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + serviceAccountRef: + description: |- + Optional service account field containing the name of a kubernetes ServiceAccount. + If the service account is specified, the service account secret token JWT will be used + for authenticating with Akeyless. If the service account selector is not supplied, + the secretRef will be used instead. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + required: + - accessID + - k8sConfName + type: object + secretRef: + description: |- + Reference to a Secret that contains the details + to authenticate with Akeyless. + properties: + accessID: + description: The SecretAccessID is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + accessType: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + accessTypeParam: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + type: object + caBundle: + description: |- + PEM/base64 encoded CA bundle used to validate Akeyless Gateway certificate. Only used + if the AkeylessGWApiURL URL is using HTTPS protocol. If not set the system root certificates + are used to validate the TLS connection. + format: byte + type: string + caProvider: + description: The provider for the CA bundle to use to validate Akeyless Gateway certificate. + properties: + key: + description: The key where the CA certificate can be found in the Secret or ConfigMap. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the object located at the provider type. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace the Provider type is in. + Can only be defined when used in a ClusterSecretStore. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + required: + - akeylessGWApiURL + - authSecretRef + type: object + alibaba: + description: Alibaba configures this store to sync secrets using Alibaba Cloud provider + properties: + auth: + description: AlibabaAuth contains a secretRef for credentials. + properties: + rrsa: + description: Authenticate against Alibaba using RRSA. + properties: + oidcProviderArn: + type: string + oidcTokenFilePath: + type: string + roleArn: + type: string + sessionName: + type: string + required: + - oidcProviderArn + - oidcTokenFilePath + - roleArn + - sessionName + type: object + secretRef: + description: AlibabaAuthSecretRef holds secret references for Alibaba credentials. + properties: + accessKeyIDSecretRef: + description: The AccessKeyID is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + accessKeySecretSecretRef: + description: The AccessKeySecret is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - accessKeyIDSecretRef + - accessKeySecretSecretRef + type: object + type: object + regionID: + description: Alibaba Region to be used for the provider + type: string + required: + - auth + - regionID + type: object + aws: + description: AWS configures this store to sync secrets using AWS Secret Manager provider + properties: + additionalRoles: + description: AdditionalRoles is a chained list of Role ARNs which the provider will sequentially assume before assuming the Role + items: + type: string + type: array + auth: + description: |- + Auth defines the information necessary to authenticate against AWS + if not set aws sdk will infer credentials from your environment + see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials + properties: + jwt: + description: Authenticate against AWS using service account tokens. + properties: + serviceAccountRef: + description: A reference to a ServiceAccount resource. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + type: object + secretRef: + description: |- + AWSAuthSecretRef holds secret references for AWS credentials + both AccessKeyID and SecretAccessKey must be defined in order to properly authenticate. + properties: + accessKeyIDSecretRef: + description: The AccessKeyID is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + secretAccessKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + sessionTokenSecretRef: + description: |- + The SessionToken used for authentication + This must be defined if AccessKeyID and SecretAccessKey are temporary credentials + see: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_use-resources.html + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + type: object + externalID: + description: AWS External ID set on assumed IAM roles + type: string + prefix: + description: Prefix adds a prefix to all retrieved values. + type: string + region: + description: AWS Region to be used for the provider + type: string + role: + description: Role is a Role ARN which the provider will assume + type: string + secretsManager: + description: SecretsManager defines how the provider behaves when interacting with AWS SecretsManager + properties: + forceDeleteWithoutRecovery: + description: |- + Specifies whether to delete the secret without any recovery window. You + can't use both this parameter and RecoveryWindowInDays in the same call. + If you don't use either, then by default Secrets Manager uses a 30 day + recovery window. + see: https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_DeleteSecret.html#SecretsManager-DeleteSecret-request-ForceDeleteWithoutRecovery + type: boolean + recoveryWindowInDays: + description: |- + The number of days from 7 to 30 that Secrets Manager waits before + permanently deleting the secret. You can't use both this parameter and + ForceDeleteWithoutRecovery in the same call. If you don't use either, + then by default Secrets Manager uses a 30 day recovery window. + see: https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_DeleteSecret.html#SecretsManager-DeleteSecret-request-RecoveryWindowInDays + format: int64 + type: integer + type: object + service: + description: Service defines which service should be used to fetch the secrets + enum: + - SecretsManager + - ParameterStore + type: string + sessionTags: + description: AWS STS assume role session tags + items: + properties: + key: + type: string + value: + type: string + required: + - key + - value + type: object + type: array + transitiveTagKeys: + description: AWS STS assume role transitive session tags. Required when multiple rules are used with the provider + items: + type: string + type: array + required: + - region + - service + type: object + azurekv: + description: AzureKV configures this store to sync secrets using Azure Key Vault provider + properties: + authSecretRef: + description: Auth configures how the operator authenticates with Azure. Required for ServicePrincipal auth type. Optional for WorkloadIdentity. + properties: + clientCertificate: + description: The Azure ClientCertificate of the service principle used for authentication. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + clientId: + description: The Azure clientId of the service principle or managed identity used for authentication. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + clientSecret: + description: The Azure ClientSecret of the service principle used for authentication. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + tenantId: + description: The Azure tenantId of the managed identity used for authentication. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + authType: + default: ServicePrincipal + description: |- + Auth type defines how to authenticate to the keyvault service. + Valid values are: + - "ServicePrincipal" (default): Using a service principal (tenantId, clientId, clientSecret) + - "ManagedIdentity": Using Managed Identity assigned to the pod (see aad-pod-identity) + enum: + - ServicePrincipal + - ManagedIdentity + - WorkloadIdentity + type: string + environmentType: + default: PublicCloud + description: |- + EnvironmentType specifies the Azure cloud environment endpoints to use for + connecting and authenticating with Azure. By default it points to the public cloud AAD endpoint. + The following endpoints are available, also see here: https://github.com/Azure/go-autorest/blob/main/autorest/azure/environments.go#L152 + PublicCloud, USGovernmentCloud, ChinaCloud, GermanCloud + enum: + - PublicCloud + - USGovernmentCloud + - ChinaCloud + - GermanCloud + type: string + identityId: + description: If multiple Managed Identity is assigned to the pod, you can select the one to be used + type: string + serviceAccountRef: + description: |- + ServiceAccountRef specified the service account + that should be used when authenticating with WorkloadIdentity. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + tenantId: + description: TenantID configures the Azure Tenant to send requests to. Required for ServicePrincipal auth type. Optional for WorkloadIdentity. + type: string + vaultUrl: + description: Vault Url from which the secrets to be fetched from. + type: string + required: + - vaultUrl + type: object + beyondtrust: + description: Beyondtrust configures this store to sync secrets using Password Safe provider. + properties: + auth: + description: Auth configures how the operator authenticates with Beyondtrust. + properties: + apiKey: + description: APIKey If not provided then ClientID/ClientSecret become required. + properties: + secretRef: + description: SecretRef references a key in a secret that will be used as value. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + value: + description: Value can be specified directly to set a value without using a secret. + type: string + type: object + certificate: + description: Certificate (cert.pem) for use when authenticating with an OAuth client Id using a Client Certificate. + properties: + secretRef: + description: SecretRef references a key in a secret that will be used as value. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + value: + description: Value can be specified directly to set a value without using a secret. + type: string + type: object + certificateKey: + description: Certificate private key (key.pem). For use when authenticating with an OAuth client Id + properties: + secretRef: + description: SecretRef references a key in a secret that will be used as value. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + value: + description: Value can be specified directly to set a value without using a secret. + type: string + type: object + clientId: + description: ClientID is the API OAuth Client ID. + properties: + secretRef: + description: SecretRef references a key in a secret that will be used as value. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + value: + description: Value can be specified directly to set a value without using a secret. + type: string + type: object + clientSecret: + description: ClientSecret is the API OAuth Client Secret. + properties: + secretRef: + description: SecretRef references a key in a secret that will be used as value. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + value: + description: Value can be specified directly to set a value without using a secret. + type: string + type: object + type: object + server: + description: Auth configures how API server works. + properties: + apiUrl: + type: string + apiVersion: + type: string + clientTimeOutSeconds: + description: Timeout specifies a time limit for requests made by this Client. The timeout includes connection time, any redirects, and reading the response body. Defaults to 45 seconds. + type: integer + retrievalType: + description: The secret retrieval type. SECRET = Secrets Safe (credential, text, file). MANAGED_ACCOUNT = Password Safe account associated with a system. + type: string + separator: + description: A character that separates the folder names. + type: string + verifyCA: + type: boolean + required: + - apiUrl + - verifyCA + type: object + required: + - auth + - server + type: object + bitwardensecretsmanager: + description: BitwardenSecretsManager configures this store to sync secrets using BitwardenSecretsManager provider + properties: + apiURL: + type: string + auth: + description: |- + Auth configures how secret-manager authenticates with a bitwarden machine account instance. + Make sure that the token being used has permissions on the given secret. + properties: + secretRef: + description: BitwardenSecretsManagerSecretRef contains the credential ref to the bitwarden instance. + properties: + credentials: + description: AccessToken used for the bitwarden instance. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - credentials + type: object + required: + - secretRef + type: object + bitwardenServerSDKURL: + type: string + caBundle: + description: |- + Base64 encoded certificate for the bitwarden server sdk. The sdk MUST run with HTTPS to make sure no MITM attack + can be performed. + type: string + caProvider: + description: 'see: https://external-secrets.io/latest/spec/#external-secrets.io/v1alpha1.CAProvider' + properties: + key: + description: The key where the CA certificate can be found in the Secret or ConfigMap. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the object located at the provider type. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace the Provider type is in. + Can only be defined when used in a ClusterSecretStore. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + identityURL: + type: string + organizationID: + description: OrganizationID determines which organization this secret store manages. + type: string + projectID: + description: ProjectID determines which project this secret store manages. + type: string + required: + - auth + - organizationID + - projectID + type: object + chef: + description: Chef configures this store to sync secrets with chef server + properties: + auth: + description: Auth defines the information necessary to authenticate against chef Server + properties: + secretRef: + description: ChefAuthSecretRef holds secret references for chef server login credentials. + properties: + privateKeySecretRef: + description: SecretKey is the Signing Key in PEM format, used for authentication. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - privateKeySecretRef + type: object + required: + - secretRef + type: object + serverUrl: + description: ServerURL is the chef server URL used to connect to. If using orgs you should include your org in the url and terminate the url with a "/" + type: string + username: + description: UserName should be the user ID on the chef server + type: string + required: + - auth + - serverUrl + - username + type: object + conjur: + description: Conjur configures this store to sync secrets using conjur provider + properties: + auth: + properties: + apikey: + properties: + account: + type: string + apiKeyRef: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + userRef: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - account + - apiKeyRef + - userRef + type: object + jwt: + properties: + account: + type: string + hostId: + description: |- + Optional HostID for JWT authentication. This may be used depending + on how the Conjur JWT authenticator policy is configured. + type: string + secretRef: + description: |- + Optional SecretRef that refers to a key in a Secret resource containing JWT token to + authenticate with Conjur using the JWT authentication method. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + serviceAccountRef: + description: |- + Optional ServiceAccountRef specifies the Kubernetes service account for which to request + a token for with the `TokenRequest` API. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + serviceID: + description: The conjur authn jwt webservice id + type: string + required: + - account + - serviceID + type: object + type: object + caBundle: + type: string + caProvider: + description: |- + Used to provide custom certificate authority (CA) certificates + for a secret store. The CAProvider points to a Secret or ConfigMap resource + that contains a PEM-encoded certificate. + properties: + key: + description: The key where the CA certificate can be found in the Secret or ConfigMap. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the object located at the provider type. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace the Provider type is in. + Can only be defined when used in a ClusterSecretStore. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + url: + type: string + required: + - auth + - url + type: object + delinea: + description: |- + Delinea DevOps Secrets Vault + https://docs.delinea.com/online-help/products/devops-secrets-vault/current + properties: + clientId: + description: ClientID is the non-secret part of the credential. + properties: + secretRef: + description: SecretRef references a key in a secret that will be used as value. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + value: + description: Value can be specified directly to set a value without using a secret. + type: string + type: object + clientSecret: + description: ClientSecret is the secret part of the credential. + properties: + secretRef: + description: SecretRef references a key in a secret that will be used as value. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + value: + description: Value can be specified directly to set a value without using a secret. + type: string + type: object + tenant: + description: Tenant is the chosen hostname / site name. + type: string + tld: + description: |- + TLD is based on the server location that was chosen during provisioning. + If unset, defaults to "com". + type: string + urlTemplate: + description: |- + URLTemplate + If unset, defaults to "https://%s.secretsvaultcloud.%s/v1/%s%s". + type: string + required: + - clientId + - clientSecret + - tenant + type: object + device42: + description: Device42 configures this store to sync secrets using the Device42 provider + properties: + auth: + description: Auth configures how secret-manager authenticates with a Device42 instance. + properties: + secretRef: + properties: + credentials: + description: Username / Password is used for authentication. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + required: + - secretRef + type: object + host: + description: URL configures the Device42 instance URL. + type: string + required: + - auth + - host + type: object + doppler: + description: Doppler configures this store to sync secrets using the Doppler provider + properties: + auth: + description: Auth configures how the Operator authenticates with the Doppler API + properties: + secretRef: + properties: + dopplerToken: + description: |- + The DopplerToken is used for authentication. + See https://docs.doppler.com/reference/api#authentication for auth token types. + The Key attribute defaults to dopplerToken if not specified. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - dopplerToken + type: object + required: + - secretRef + type: object + config: + description: Doppler config (required if not using a Service Token) + type: string + format: + description: Format enables the downloading of secrets as a file (string) + enum: + - json + - dotnet-json + - env + - yaml + - docker + type: string + nameTransformer: + description: Environment variable compatible name transforms that change secret names to a different format + enum: + - upper-camel + - camel + - lower-snake + - tf-var + - dotnet-env + - lower-kebab + type: string + project: + description: Doppler project (required if not using a Service Token) + type: string + required: + - auth + type: object + fake: + description: Fake configures a store with static key/value pairs + properties: + data: + items: + properties: + key: + type: string + value: + type: string + valueMap: + additionalProperties: + type: string + description: 'Deprecated: ValueMap is deprecated and is intended to be removed in the future, use the `value` field instead.' + type: object + version: + type: string + required: + - key + type: object + type: array + required: + - data + type: object + fortanix: + description: Fortanix configures this store to sync secrets using the Fortanix provider + properties: + apiKey: + description: APIKey is the API token to access SDKMS Applications. + properties: + secretRef: + description: SecretRef is a reference to a secret containing the SDKMS API Key. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + apiUrl: + description: APIURL is the URL of SDKMS API. Defaults to `sdkms.fortanix.com`. + type: string + type: object + gcpsm: + description: GCPSM configures this store to sync secrets using Google Cloud Platform Secret Manager provider + properties: + auth: + description: Auth defines the information necessary to authenticate against GCP + properties: + secretRef: + properties: + secretAccessKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + workloadIdentity: + properties: + clusterLocation: + type: string + clusterName: + type: string + clusterProjectID: + type: string + serviceAccountRef: + description: A reference to a ServiceAccount resource. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + required: + - clusterLocation + - clusterName + - serviceAccountRef + type: object + type: object + location: + description: Location optionally defines a location for a secret + type: string + projectID: + description: ProjectID project where secret is located + type: string + type: object + github: + description: Github configures this store to push Github Action secrets using Github API provider + properties: + appID: + description: appID specifies the Github APP that will be used to authenticate the client + format: int64 + type: integer + auth: + description: auth configures how secret-manager authenticates with a Github instance. + properties: + privateKey: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - privateKey + type: object + environment: + description: environment will be used to fetch secrets from a particular environment within a github repository + type: string + installationID: + description: installationID specifies the Github APP installation that will be used to authenticate the client + format: int64 + type: integer + organization: + description: organization will be used to fetch secrets from the Github organization + type: string + repository: + description: repository will be used to fetch secrets from the Github repository within an organization + type: string + uploadURL: + description: Upload URL for enterprise instances. Default to URL. + type: string + url: + default: https://github.com/ + description: URL configures the Github instance URL. Defaults to https://github.com/. + type: string + required: + - appID + - auth + - installationID + - organization + type: object + gitlab: + description: GitLab configures this store to sync secrets using GitLab Variables provider + properties: + auth: + description: Auth configures how secret-manager authenticates with a GitLab instance. + properties: + SecretRef: + properties: + accessToken: + description: AccessToken is used for authentication. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + required: + - SecretRef + type: object + environment: + description: Environment environment_scope of gitlab CI/CD variables (Please see https://docs.gitlab.com/ee/ci/environments/#create-a-static-environment on how to create environments) + type: string + groupIDs: + description: GroupIDs specify, which gitlab groups to pull secrets from. Group secrets are read from left to right followed by the project variables. + items: + type: string + type: array + inheritFromGroups: + description: InheritFromGroups specifies whether parent groups should be discovered and checked for secrets. + type: boolean + projectID: + description: ProjectID specifies a project where secrets are located. + type: string + url: + description: URL configures the GitLab instance URL. Defaults to https://gitlab.com/. + type: string + required: + - auth + type: object + ibm: + description: IBM configures this store to sync secrets using IBM Cloud provider + properties: + auth: + description: Auth configures how secret-manager authenticates with the IBM secrets manager. + maxProperties: 1 + minProperties: 1 + properties: + containerAuth: + description: IBM Container-based auth with IAM Trusted Profile. + properties: + iamEndpoint: + type: string + profile: + description: the IBM Trusted Profile + type: string + tokenLocation: + description: Location the token is mounted on the pod + type: string + required: + - profile + type: object + secretRef: + properties: + secretApiKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + type: object + serviceUrl: + description: ServiceURL is the Endpoint URL that is specific to the Secrets Manager service instance + type: string + required: + - auth + type: object + infisical: + description: Infisical configures this store to sync secrets using the Infisical provider + properties: + auth: + description: Auth configures how the Operator authenticates with the Infisical API + properties: + universalAuthCredentials: + properties: + clientId: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + clientSecret: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - clientId + - clientSecret + type: object + type: object + hostAPI: + default: https://app.infisical.com/api + description: HostAPI specifies the base URL of the Infisical API. If not provided, it defaults to "https://app.infisical.com/api". + type: string + secretsScope: + description: SecretsScope defines the scope of the secrets within the workspace + properties: + environmentSlug: + description: EnvironmentSlug is the required slug identifier for the environment. + type: string + expandSecretReferences: + default: true + description: ExpandSecretReferences indicates whether secret references should be expanded. Defaults to true if not provided. + type: boolean + projectSlug: + description: ProjectSlug is the required slug identifier for the project. + type: string + recursive: + default: false + description: Recursive indicates whether the secrets should be fetched recursively. Defaults to false if not provided. + type: boolean + secretsPath: + default: / + description: SecretsPath specifies the path to the secrets within the workspace. Defaults to "/" if not provided. + type: string + required: + - environmentSlug + - projectSlug + type: object + required: + - auth + - secretsScope + type: object + keepersecurity: + description: KeeperSecurity configures this store to sync secrets using the KeeperSecurity provider + properties: + authRef: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + folderID: + type: string + required: + - authRef + - folderID + type: object + kubernetes: + description: Kubernetes configures this store to sync secrets using a Kubernetes cluster provider + properties: + auth: + description: Auth configures how secret-manager authenticates with a Kubernetes instance. + maxProperties: 1 + minProperties: 1 + properties: + cert: + description: has both clientCert and clientKey as secretKeySelector + properties: + clientCert: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + clientKey: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + serviceAccount: + description: points to a service account that should be used for authentication + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + token: + description: use static token to authenticate with + properties: + bearerToken: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + type: object + authRef: + description: A reference to a secret that contains the auth information. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + remoteNamespace: + default: default + description: Remote namespace to fetch the secrets from + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + server: + description: configures the Kubernetes server Address. + properties: + caBundle: + description: CABundle is a base64-encoded CA certificate + format: byte + type: string + caProvider: + description: 'see: https://external-secrets.io/v0.4.1/spec/#external-secrets.io/v1alpha1.CAProvider' + properties: + key: + description: The key where the CA certificate can be found in the Secret or ConfigMap. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the object located at the provider type. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace the Provider type is in. + Can only be defined when used in a ClusterSecretStore. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + url: + default: kubernetes.default + description: configures the Kubernetes server Address. + type: string + type: object + type: object + onboardbase: + description: Onboardbase configures this store to sync secrets using the Onboardbase provider + properties: + apiHost: + default: https://public.onboardbase.com/api/v1/ + description: APIHost use this to configure the host url for the API for selfhosted installation, default is https://public.onboardbase.com/api/v1/ + type: string + auth: + description: Auth configures how the Operator authenticates with the Onboardbase API + properties: + apiKeyRef: + description: |- + OnboardbaseAPIKey is the APIKey generated by an admin account. + It is used to recognize and authorize access to a project and environment within onboardbase + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + passcodeRef: + description: OnboardbasePasscode is the passcode attached to the API Key + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - apiKeyRef + - passcodeRef + type: object + environment: + default: development + description: Environment is the name of an environmnent within a project to pull the secrets from + type: string + project: + default: development + description: Project is an onboardbase project that the secrets should be pulled from + type: string + required: + - apiHost + - auth + - environment + - project + type: object + onepassword: + description: OnePassword configures this store to sync secrets using the 1Password Cloud provider + properties: + auth: + description: Auth defines the information necessary to authenticate against OnePassword Connect Server + properties: + secretRef: + description: OnePasswordAuthSecretRef holds secret references for 1Password credentials. + properties: + connectTokenSecretRef: + description: The ConnectToken is used for authentication to a 1Password Connect Server. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - connectTokenSecretRef + type: object + required: + - secretRef + type: object + connectHost: + description: ConnectHost defines the OnePassword Connect Server to connect to + type: string + vaults: + additionalProperties: + type: integer + description: Vaults defines which OnePassword vaults to search in which order + type: object + required: + - auth + - connectHost + - vaults + type: object + oracle: + description: Oracle configures this store to sync secrets using Oracle Vault provider + properties: + auth: + description: |- + Auth configures how secret-manager authenticates with the Oracle Vault. + If empty, use the instance principal, otherwise the user credentials specified in Auth. + properties: + secretRef: + description: SecretRef to pass through sensitive information. + properties: + fingerprint: + description: Fingerprint is the fingerprint of the API private key. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + privatekey: + description: PrivateKey is the user's API Signing Key in PEM format, used for authentication. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - fingerprint + - privatekey + type: object + tenancy: + description: Tenancy is the tenancy OCID where user is located. + type: string + user: + description: User is an access OCID specific to the account. + type: string + required: + - secretRef + - tenancy + - user + type: object + compartment: + description: |- + Compartment is the vault compartment OCID. + Required for PushSecret + type: string + encryptionKey: + description: |- + EncryptionKey is the OCID of the encryption key within the vault. + Required for PushSecret + type: string + principalType: + description: |- + The type of principal to use for authentication. If left blank, the Auth struct will + determine the principal type. This optional field must be specified if using + workload identity. + enum: + - "" + - UserPrincipal + - InstancePrincipal + - Workload + type: string + region: + description: Region is the region where vault is located. + type: string + serviceAccountRef: + description: |- + ServiceAccountRef specified the service account + that should be used when authenticating with WorkloadIdentity. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + vault: + description: Vault is the vault's OCID of the specific vault where secret is located. + type: string + required: + - region + - vault + type: object + passbolt: + properties: + auth: + description: Auth defines the information necessary to authenticate against Passbolt Server + properties: + passwordSecretRef: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + privateKeySecretRef: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - passwordSecretRef + - privateKeySecretRef + type: object + host: + description: Host defines the Passbolt Server to connect to + type: string + required: + - auth + - host + type: object + passworddepot: + description: Configures a store to sync secrets with a Password Depot instance. + properties: + auth: + description: Auth configures how secret-manager authenticates with a Password Depot instance. + properties: + secretRef: + properties: + credentials: + description: Username / Password is used for authentication. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + required: + - secretRef + type: object + database: + description: Database to use as source + type: string + host: + description: URL configures the Password Depot instance URL. + type: string + required: + - auth + - database + - host + type: object + previder: + description: Previder configures this store to sync secrets using the Previder provider + properties: + auth: + description: PreviderAuth contains a secretRef for credentials. + properties: + secretRef: + description: PreviderAuthSecretRef holds secret references for Previder Vault credentials. + properties: + accessToken: + description: The AccessToken is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - accessToken + type: object + type: object + baseUri: + type: string + required: + - auth + type: object + pulumi: + description: Pulumi configures this store to sync secrets using the Pulumi provider + properties: + accessToken: + description: AccessToken is the access tokens to sign in to the Pulumi Cloud Console. + properties: + secretRef: + description: SecretRef is a reference to a secret containing the Pulumi API token. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + apiUrl: + default: https://api.pulumi.com/api/esc + description: APIURL is the URL of the Pulumi API. + type: string + environment: + description: |- + Environment are YAML documents composed of static key-value pairs, programmatic expressions, + dynamically retrieved values from supported providers including all major clouds, + and other Pulumi ESC environments. + To create a new environment, visit https://www.pulumi.com/docs/esc/environments/ for more information. + type: string + organization: + description: |- + Organization are a space to collaborate on shared projects and stacks. + To create a new organization, visit https://app.pulumi.com/ and click "New Organization". + type: string + project: + description: Project is the name of the Pulumi ESC project the environment belongs to. + type: string + required: + - accessToken + - environment + - organization + - project + type: object + scaleway: + description: Scaleway + properties: + accessKey: + description: AccessKey is the non-secret part of the api key. + properties: + secretRef: + description: SecretRef references a key in a secret that will be used as value. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + value: + description: Value can be specified directly to set a value without using a secret. + type: string + type: object + apiUrl: + description: APIURL is the url of the api to use. Defaults to https://api.scaleway.com + type: string + projectId: + description: 'ProjectID is the id of your project, which you can find in the console: https://console.scaleway.com/project/settings' + type: string + region: + description: 'Region where your secrets are located: https://developers.scaleway.com/en/quickstart/#region-and-zone' + type: string + secretKey: + description: SecretKey is the non-secret part of the api key. + properties: + secretRef: + description: SecretRef references a key in a secret that will be used as value. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + value: + description: Value can be specified directly to set a value without using a secret. + type: string + type: object + required: + - accessKey + - projectId + - region + - secretKey + type: object + secretserver: + description: |- + SecretServer configures this store to sync secrets using SecretServer provider + https://docs.delinea.com/online-help/secret-server/start.htm + properties: + password: + description: Password is the secret server account password. + properties: + secretRef: + description: SecretRef references a key in a secret that will be used as value. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + value: + description: Value can be specified directly to set a value without using a secret. + type: string + type: object + serverURL: + description: |- + ServerURL + URL to your secret server installation + type: string + username: + description: Username is the secret server account username. + properties: + secretRef: + description: SecretRef references a key in a secret that will be used as value. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + value: + description: Value can be specified directly to set a value without using a secret. + type: string + type: object + required: + - password + - serverURL + - username + type: object + senhasegura: + description: Senhasegura configures this store to sync secrets using senhasegura provider + properties: + auth: + description: Auth defines parameters to authenticate in senhasegura + properties: + clientId: + type: string + clientSecretSecretRef: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - clientId + - clientSecretSecretRef + type: object + ignoreSslCertificate: + default: false + description: IgnoreSslCertificate defines if SSL certificate must be ignored + type: boolean + module: + description: Module defines which senhasegura module should be used to get secrets + type: string + url: + description: URL of senhasegura + type: string + required: + - auth + - module + - url + type: object + vault: + description: Vault configures this store to sync secrets using Hashi provider + properties: + auth: + description: Auth configures how secret-manager authenticates with the Vault server. + properties: + appRole: + description: |- + AppRole authenticates with Vault using the App Role auth mechanism, + with the role and secret stored in a Kubernetes Secret resource. + properties: + path: + default: approle + description: |- + Path where the App Role authentication backend is mounted + in Vault, e.g: "approle" + type: string + roleId: + description: |- + RoleID configured in the App Role authentication backend when setting + up the authentication backend in Vault. + type: string + roleRef: + description: |- + Reference to a key in a Secret that contains the App Role ID used + to authenticate with Vault. + The `key` field must be specified and denotes which entry within the Secret + resource is used as the app role id. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + secretRef: + description: |- + Reference to a key in a Secret that contains the App Role secret used + to authenticate with Vault. + The `key` field must be specified and denotes which entry within the Secret + resource is used as the app role secret. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - path + - secretRef + type: object + cert: + description: |- + Cert authenticates with TLS Certificates by passing client certificate, private key and ca certificate + Cert authentication method + properties: + clientCert: + description: |- + ClientCert is a certificate to authenticate using the Cert Vault + authentication method + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + secretRef: + description: |- + SecretRef to a key in a Secret resource containing client private key to + authenticate with Vault using the Cert authentication method + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + iam: + description: |- + Iam authenticates with vault by passing a special AWS request signed with AWS IAM credentials + AWS IAM authentication method + properties: + externalID: + description: AWS External ID set on assumed IAM roles + type: string + jwt: + description: Specify a service account with IRSA enabled + properties: + serviceAccountRef: + description: A reference to a ServiceAccount resource. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + type: object + path: + description: 'Path where the AWS auth method is enabled in Vault, e.g: "aws"' + type: string + region: + description: AWS region + type: string + role: + description: This is the AWS role to be assumed before talking to vault + type: string + secretRef: + description: Specify credentials in a Secret object + properties: + accessKeyIDSecretRef: + description: The AccessKeyID is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + secretAccessKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + sessionTokenSecretRef: + description: |- + The SessionToken used for authentication + This must be defined if AccessKeyID and SecretAccessKey are temporary credentials + see: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_use-resources.html + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + vaultAwsIamServerID: + description: 'X-Vault-AWS-IAM-Server-ID is an additional header used by Vault IAM auth method to mitigate against different types of replay attacks. More details here: https://developer.hashicorp.com/vault/docs/auth/aws' + type: string + vaultRole: + description: Vault Role. In vault, a role describes an identity with a set of permissions, groups, or policies you want to attach a user of the secrets engine + type: string + required: + - vaultRole + type: object + jwt: + description: |- + Jwt authenticates with Vault by passing role and JWT token using the + JWT/OIDC authentication method + properties: + kubernetesServiceAccountToken: + description: |- + Optional ServiceAccountToken specifies the Kubernetes service account for which to request + a token for with the `TokenRequest` API. + properties: + audiences: + description: |- + Optional audiences field that will be used to request a temporary Kubernetes service + account token for the service account referenced by `serviceAccountRef`. + Defaults to a single audience `vault` it not specified. + Deprecated: use serviceAccountRef.Audiences instead + items: + type: string + type: array + expirationSeconds: + description: |- + Optional expiration time in seconds that will be used to request a temporary + Kubernetes service account token for the service account referenced by + `serviceAccountRef`. + Deprecated: this will be removed in the future. + Defaults to 10 minutes. + format: int64 + type: integer + serviceAccountRef: + description: Service account field containing the name of a kubernetes ServiceAccount. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + required: + - serviceAccountRef + type: object + path: + default: jwt + description: |- + Path where the JWT authentication backend is mounted + in Vault, e.g: "jwt" + type: string + role: + description: |- + Role is a JWT role to authenticate using the JWT/OIDC Vault + authentication method + type: string + secretRef: + description: |- + Optional SecretRef that refers to a key in a Secret resource containing JWT token to + authenticate with Vault using the JWT/OIDC authentication method. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - path + type: object + kubernetes: + description: |- + Kubernetes authenticates with Vault by passing the ServiceAccount + token stored in the named Secret resource to the Vault server. + properties: + mountPath: + default: kubernetes + description: |- + Path where the Kubernetes authentication backend is mounted in Vault, e.g: + "kubernetes" + type: string + role: + description: |- + A required field containing the Vault Role to assume. A Role binds a + Kubernetes ServiceAccount with a set of Vault policies. + type: string + secretRef: + description: |- + Optional secret field containing a Kubernetes ServiceAccount JWT used + for authenticating with Vault. If a name is specified without a key, + `token` is the default. If one is not specified, the one bound to + the controller will be used. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + serviceAccountRef: + description: |- + Optional service account field containing the name of a kubernetes ServiceAccount. + If the service account is specified, the service account secret token JWT will be used + for authenticating with Vault. If the service account selector is not supplied, + the secretRef will be used instead. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + required: + - mountPath + - role + type: object + ldap: + description: |- + Ldap authenticates with Vault by passing username/password pair using + the LDAP authentication method + properties: + path: + default: ldap + description: |- + Path where the LDAP authentication backend is mounted + in Vault, e.g: "ldap" + type: string + secretRef: + description: |- + SecretRef to a key in a Secret resource containing password for the LDAP + user used to authenticate with Vault using the LDAP authentication + method + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + username: + description: |- + Username is an LDAP username used to authenticate using the LDAP Vault + authentication method + type: string + required: + - path + - username + type: object + namespace: + description: |- + Name of the vault namespace to authenticate to. This can be different than the namespace your secret is in. + Namespaces is a set of features within Vault Enterprise that allows + Vault environments to support Secure Multi-tenancy. e.g: "ns1". + More about namespaces can be found here https://www.vaultproject.io/docs/enterprise/namespaces + This will default to Vault.Namespace field if set, or empty otherwise + type: string + tokenSecretRef: + description: TokenSecretRef authenticates with Vault by presenting a token. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + userPass: + description: UserPass authenticates with Vault by passing username/password pair + properties: + path: + default: userpass + description: |- + Path where the UserPassword authentication backend is mounted + in Vault, e.g: "userpass" + type: string + secretRef: + description: |- + SecretRef to a key in a Secret resource containing password for the + user used to authenticate with Vault using the UserPass authentication + method + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + username: + description: |- + Username is a username used to authenticate using the UserPass Vault + authentication method + type: string + required: + - path + - username + type: object + type: object + caBundle: + description: |- + PEM encoded CA bundle used to validate Vault server certificate. Only used + if the Server URL is using HTTPS protocol. This parameter is ignored for + plain HTTP protocol connection. If not set the system root certificates + are used to validate the TLS connection. + format: byte + type: string + caProvider: + description: The provider for the CA bundle to use to validate Vault server certificate. + properties: + key: + description: The key where the CA certificate can be found in the Secret or ConfigMap. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the object located at the provider type. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace the Provider type is in. + Can only be defined when used in a ClusterSecretStore. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + forwardInconsistent: + description: |- + ForwardInconsistent tells Vault to forward read-after-write requests to the Vault + leader instead of simply retrying within a loop. This can increase performance if + the option is enabled serverside. + https://www.vaultproject.io/docs/configuration/replication#allow_forwarding_via_header + type: boolean + headers: + additionalProperties: + type: string + description: Headers to be added in Vault request + type: object + namespace: + description: |- + Name of the vault namespace. Namespaces is a set of features within Vault Enterprise that allows + Vault environments to support Secure Multi-tenancy. e.g: "ns1". + More about namespaces can be found here https://www.vaultproject.io/docs/enterprise/namespaces + type: string + path: + description: |- + Path is the mount path of the Vault KV backend endpoint, e.g: + "secret". The v2 KV secret engine version specific "/data" path suffix + for fetching secrets from Vault is optional and will be appended + if not present in specified path. + type: string + readYourWrites: + description: |- + ReadYourWrites ensures isolated read-after-write semantics by + providing discovered cluster replication states in each request. + More information about eventual consistency in Vault can be found here + https://www.vaultproject.io/docs/enterprise/consistency + type: boolean + server: + description: 'Server is the connection address for the Vault server, e.g: "https://vault.example.com:8200".' + type: string + tls: + description: |- + The configuration used for client side related TLS communication, when the Vault server + requires mutual authentication. Only used if the Server URL is using HTTPS protocol. + This parameter is ignored for plain HTTP protocol connection. + It's worth noting this configuration is different from the "TLS certificates auth method", + which is available under the `auth.cert` section. + properties: + certSecretRef: + description: |- + CertSecretRef is a certificate added to the transport layer + when communicating with the Vault server. + If no key for the Secret is specified, external-secret will default to 'tls.crt'. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + keySecretRef: + description: |- + KeySecretRef to a key in a Secret resource containing client private key + added to the transport layer when communicating with the Vault server. + If no key for the Secret is specified, external-secret will default to 'tls.key'. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + version: + default: v2 + description: |- + Version is the Vault KV secret engine version. This can be either "v1" or + "v2". Version defaults to "v2". + enum: + - v1 + - v2 + type: string + required: + - server + type: object + webhook: + description: Webhook configures this store to sync secrets using a generic templated webhook + properties: + body: + description: Body + type: string + caBundle: + description: |- + PEM encoded CA bundle used to validate webhook server certificate. Only used + if the Server URL is using HTTPS protocol. This parameter is ignored for + plain HTTP protocol connection. If not set the system root certificates + are used to validate the TLS connection. + format: byte + type: string + caProvider: + description: The provider for the CA bundle to use to validate webhook server certificate. + properties: + key: + description: The key where the CA certificate can be found in the Secret or ConfigMap. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the object located at the provider type. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: The namespace the Provider type is in. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + headers: + additionalProperties: + type: string + description: Headers + type: object + method: + description: Webhook Method + type: string + result: + description: Result formatting + properties: + jsonPath: + description: Json path of return value + type: string + type: object + secrets: + description: |- + Secrets to fill in templates + These secrets will be passed to the templating function as key value pairs under the given name + items: + properties: + name: + description: Name of this secret in templates + type: string + secretRef: + description: Secret ref to fill in credentials + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - name + - secretRef + type: object + type: array + timeout: + description: Timeout + type: string + url: + description: Webhook url to call + type: string + required: + - result + - url + type: object + yandexcertificatemanager: + description: YandexCertificateManager configures this store to sync secrets using Yandex Certificate Manager provider + properties: + apiEndpoint: + description: Yandex.Cloud API endpoint (e.g. 'api.cloud.yandex.net:443') + type: string + auth: + description: Auth defines the information necessary to authenticate against Yandex Certificate Manager + properties: + authorizedKeySecretRef: + description: The authorized key used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + caProvider: + description: The provider for the CA bundle to use to validate Yandex.Cloud server certificate. + properties: + certSecretRef: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + required: + - auth + type: object + yandexlockbox: + description: YandexLockbox configures this store to sync secrets using Yandex Lockbox provider + properties: + apiEndpoint: + description: Yandex.Cloud API endpoint (e.g. 'api.cloud.yandex.net:443') + type: string + auth: + description: Auth defines the information necessary to authenticate against Yandex Lockbox + properties: + authorizedKeySecretRef: + description: The authorized key used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + caProvider: + description: The provider for the CA bundle to use to validate Yandex.Cloud server certificate. + properties: + certSecretRef: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + required: + - auth + type: object + type: object + refreshInterval: + description: Used to configure store refresh interval in seconds. Empty or 0 will default to the controller config. + type: integer + retrySettings: + description: Used to configure http retries if failed + properties: + maxRetries: + format: int32 + type: integer + retryInterval: + type: string + type: object + required: + - provider + type: object + status: + description: SecretStoreStatus defines the observed state of the SecretStore. + properties: + capabilities: + description: SecretStoreCapabilities defines the possible operations a SecretStore can do. + type: string + conditions: + items: + properties: + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} + conversion: + strategy: Webhook + webhook: + conversionReviewVersions: + - v1 + clientConfig: + service: + name: kubernetes + namespace: default + path: /convert +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.17.2 + labels: + external-secrets.io/component: controller + name: externalsecrets.external-secrets.io +spec: + group: external-secrets.io + names: + categories: + - external-secrets + kind: ExternalSecret + listKind: ExternalSecretList + plural: externalsecrets + shortNames: + - es + singular: externalsecret + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.secretStoreRef.kind + name: Store + type: string + - jsonPath: .spec.secretStoreRef.name + name: Store + type: string + - jsonPath: .spec.refreshInterval + name: Refresh Interval + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].reason + name: Status + type: string + deprecated: true + name: v1alpha1 + schema: + openAPIV3Schema: + description: ExternalSecret is the Schema for the external-secrets API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: ExternalSecretSpec defines the desired state of ExternalSecret. + properties: + data: + description: Data defines the connection between the Kubernetes Secret keys and the Provider data + items: + description: ExternalSecretData defines the connection between the Kubernetes Secret key (spec.data.) and the Provider data. + properties: + remoteRef: + description: ExternalSecretDataRemoteRef defines Provider data location. + properties: + conversionStrategy: + default: Default + description: Used to define a conversion Strategy + enum: + - Default + - Unicode + type: string + key: + description: Key is the key used in the Provider, mandatory + type: string + property: + description: Used to select a specific property of the Provider value (if a map), if supported + type: string + version: + description: Used to select a specific version of the Provider value, if supported + type: string + required: + - key + type: object + secretKey: + description: The key in the Kubernetes Secret to store the value. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + required: + - remoteRef + - secretKey + type: object + type: array + dataFrom: + description: |- + DataFrom is used to fetch all properties from a specific Provider data + If multiple entries are specified, the Secret keys are merged in the specified order + items: + description: ExternalSecretDataRemoteRef defines Provider data location. + properties: + conversionStrategy: + default: Default + description: Used to define a conversion Strategy + enum: + - Default + - Unicode + type: string + key: + description: Key is the key used in the Provider, mandatory + type: string + property: + description: Used to select a specific property of the Provider value (if a map), if supported + type: string + version: + description: Used to select a specific version of the Provider value, if supported + type: string + required: + - key + type: object + type: array + refreshInterval: + default: 1h + description: |- + RefreshInterval is the amount of time before the values are read again from the SecretStore provider + Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h" + May be set to zero to fetch and create it once. Defaults to 1h. + type: string + secretStoreRef: + description: SecretStoreRef defines which SecretStore to fetch the ExternalSecret data. + properties: + kind: + description: |- + Kind of the SecretStore resource (SecretStore or ClusterSecretStore) + Defaults to `SecretStore` + enum: + - SecretStore + - ClusterSecretStore + type: string + name: + description: Name of the SecretStore resource + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + type: object + target: + description: |- + ExternalSecretTarget defines the Kubernetes Secret to be created + There can be only one target per ExternalSecret. + properties: + creationPolicy: + default: Owner + description: |- + CreationPolicy defines rules on how to create the resulting Secret. + Defaults to "Owner" + enum: + - Owner + - Merge + - None + type: string + immutable: + description: Immutable defines if the final secret will be immutable + type: boolean + name: + description: |- + The name of the Secret resource to be managed. + Defaults to the .metadata.name of the ExternalSecret resource + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + template: + description: Template defines a blueprint for the created Secret resource. + properties: + data: + additionalProperties: + type: string + type: object + engineVersion: + default: v1 + description: |- + EngineVersion specifies the template engine version + that should be used to compile/execute the + template specified in .data and .templateFrom[]. + enum: + - v1 + - v2 + type: string + metadata: + description: ExternalSecretTemplateMetadata defines metadata fields for the Secret blueprint. + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + templateFrom: + items: + maxProperties: 1 + minProperties: 1 + properties: + configMap: + properties: + items: + description: A list of keys in the ConfigMap/Secret to use as templates for Secret data + items: + properties: + key: + description: A key in the ConfigMap/Secret + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + required: + - key + type: object + type: array + name: + description: The name of the ConfigMap/Secret resource + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - items + - name + type: object + secret: + properties: + items: + description: A list of keys in the ConfigMap/Secret to use as templates for Secret data + items: + properties: + key: + description: A key in the ConfigMap/Secret + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + required: + - key + type: object + type: array + name: + description: The name of the ConfigMap/Secret resource + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - items + - name + type: object + type: object + type: array + type: + type: string + type: object + type: object + required: + - secretStoreRef + - target + type: object + status: + properties: + binding: + description: Binding represents a servicebinding.io Provisioned Service reference to the secret + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + conditions: + items: + properties: + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + refreshTime: + description: |- + refreshTime is the time and date the external secret was fetched and + the target secret updated + format: date-time + nullable: true + type: string + syncedResourceVersion: + description: SyncedResourceVersion keeps track of the last synced version + type: string + type: object + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .spec.secretStoreRef.kind + name: StoreType + type: string + - jsonPath: .spec.secretStoreRef.name + name: Store + type: string + - jsonPath: .spec.refreshInterval + name: Refresh Interval + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].reason + name: Status + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + name: v1beta1 + schema: + openAPIV3Schema: + description: ExternalSecret is the Schema for the external-secrets API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: ExternalSecretSpec defines the desired state of ExternalSecret. + properties: + data: + description: Data defines the connection between the Kubernetes Secret keys and the Provider data + items: + description: ExternalSecretData defines the connection between the Kubernetes Secret key (spec.data.) and the Provider data. + properties: + remoteRef: + description: |- + RemoteRef points to the remote secret and defines + which secret (version/property/..) to fetch. + properties: + conversionStrategy: + default: Default + description: Used to define a conversion Strategy + enum: + - Default + - Unicode + type: string + decodingStrategy: + default: None + description: Used to define a decoding Strategy + enum: + - Auto + - Base64 + - Base64URL + - None + type: string + key: + description: Key is the key used in the Provider, mandatory + type: string + metadataPolicy: + default: None + description: Policy for fetching tags/labels from provider secrets, possible options are Fetch, None. Defaults to None + enum: + - None + - Fetch + type: string + property: + description: Used to select a specific property of the Provider value (if a map), if supported + type: string + version: + description: Used to select a specific version of the Provider value, if supported + type: string + required: + - key + type: object + secretKey: + description: The key in the Kubernetes Secret to store the value. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + sourceRef: + description: |- + SourceRef allows you to override the source + from which the value will be pulled. + maxProperties: 1 + minProperties: 1 + properties: + generatorRef: + description: |- + GeneratorRef points to a generator custom resource. + + Deprecated: The generatorRef is not implemented in .data[]. + this will be removed with v1. + properties: + apiVersion: + default: generators.external-secrets.io/v1alpha1 + description: Specify the apiVersion of the generator resource + type: string + kind: + description: Specify the Kind of the generator resource + enum: + - ACRAccessToken + - ClusterGenerator + - ECRAuthorizationToken + - Fake + - GCRAccessToken + - GithubAccessToken + - QuayAccessToken + - Password + - STSSessionToken + - UUID + - VaultDynamicSecret + - Webhook + - Grafana + type: string + name: + description: Specify the name of the generator resource + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - kind + - name + type: object + storeRef: + description: SecretStoreRef defines which SecretStore to fetch the ExternalSecret data. + properties: + kind: + description: |- + Kind of the SecretStore resource (SecretStore or ClusterSecretStore) + Defaults to `SecretStore` + enum: + - SecretStore + - ClusterSecretStore + type: string + name: + description: Name of the SecretStore resource + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + type: object + type: object + required: + - remoteRef + - secretKey + type: object + type: array + dataFrom: + description: |- + DataFrom is used to fetch all properties from a specific Provider data + If multiple entries are specified, the Secret keys are merged in the specified order + items: + properties: + extract: + description: |- + Used to extract multiple key/value pairs from one secret + Note: Extract does not support sourceRef.Generator or sourceRef.GeneratorRef. + properties: + conversionStrategy: + default: Default + description: Used to define a conversion Strategy + enum: + - Default + - Unicode + type: string + decodingStrategy: + default: None + description: Used to define a decoding Strategy + enum: + - Auto + - Base64 + - Base64URL + - None + type: string + key: + description: Key is the key used in the Provider, mandatory + type: string + metadataPolicy: + default: None + description: Policy for fetching tags/labels from provider secrets, possible options are Fetch, None. Defaults to None + enum: + - None + - Fetch + type: string + property: + description: Used to select a specific property of the Provider value (if a map), if supported + type: string + version: + description: Used to select a specific version of the Provider value, if supported + type: string + required: + - key + type: object + find: + description: |- + Used to find secrets based on tags or regular expressions + Note: Find does not support sourceRef.Generator or sourceRef.GeneratorRef. + properties: + conversionStrategy: + default: Default + description: Used to define a conversion Strategy + enum: + - Default + - Unicode + type: string + decodingStrategy: + default: None + description: Used to define a decoding Strategy + enum: + - Auto + - Base64 + - Base64URL + - None + type: string + name: + description: Finds secrets based on the name. + properties: + regexp: + description: Finds secrets base + type: string + type: object + path: + description: A root path to start the find operations. + type: string + tags: + additionalProperties: + type: string + description: Find secrets based on tags. + type: object + type: object + rewrite: + description: |- + Used to rewrite secret Keys after getting them from the secret Provider + Multiple Rewrite operations can be provided. They are applied in a layered order (first to last) + items: + properties: + regexp: + description: |- + Used to rewrite with regular expressions. + The resulting key will be the output of a regexp.ReplaceAll operation. + properties: + source: + description: Used to define the regular expression of a re.Compiler. + type: string + target: + description: Used to define the target pattern of a ReplaceAll operation. + type: string + required: + - source + - target + type: object + transform: + description: |- + Used to apply string transformation on the secrets. + The resulting key will be the output of the template applied by the operation. + properties: + template: + description: |- + Used to define the template to apply on the secret name. + `.value ` will specify the secret name in the template. + type: string + required: + - template + type: object + type: object + type: array + sourceRef: + description: |- + SourceRef points to a store or generator + which contains secret values ready to use. + Use this in combination with Extract or Find pull values out of + a specific SecretStore. + When sourceRef points to a generator Extract or Find is not supported. + The generator returns a static map of values + maxProperties: 1 + minProperties: 1 + properties: + generatorRef: + description: GeneratorRef points to a generator custom resource. + properties: + apiVersion: + default: generators.external-secrets.io/v1alpha1 + description: Specify the apiVersion of the generator resource + type: string + kind: + description: Specify the Kind of the generator resource + enum: + - ACRAccessToken + - ClusterGenerator + - ECRAuthorizationToken + - Fake + - GCRAccessToken + - GithubAccessToken + - QuayAccessToken + - Password + - STSSessionToken + - UUID + - VaultDynamicSecret + - Webhook + - Grafana + type: string + name: + description: Specify the name of the generator resource + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - kind + - name + type: object + storeRef: + description: SecretStoreRef defines which SecretStore to fetch the ExternalSecret data. + properties: + kind: + description: |- + Kind of the SecretStore resource (SecretStore or ClusterSecretStore) + Defaults to `SecretStore` + enum: + - SecretStore + - ClusterSecretStore + type: string + name: + description: Name of the SecretStore resource + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + type: object + type: object + type: object + type: array + refreshInterval: + default: 1h + description: |- + RefreshInterval is the amount of time before the values are read again from the SecretStore provider, + specified as Golang Duration strings. + Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h" + Example values: "1h", "2h30m", "5d", "10s" + May be set to zero to fetch and create it once. Defaults to 1h. + type: string + secretStoreRef: + description: SecretStoreRef defines which SecretStore to fetch the ExternalSecret data. + properties: + kind: + description: |- + Kind of the SecretStore resource (SecretStore or ClusterSecretStore) + Defaults to `SecretStore` + enum: + - SecretStore + - ClusterSecretStore + type: string + name: + description: Name of the SecretStore resource + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + type: object + target: + default: + creationPolicy: Owner + deletionPolicy: Retain + description: |- + ExternalSecretTarget defines the Kubernetes Secret to be created + There can be only one target per ExternalSecret. + properties: + creationPolicy: + default: Owner + description: |- + CreationPolicy defines rules on how to create the resulting Secret. + Defaults to "Owner" + enum: + - Owner + - Orphan + - Merge + - None + type: string + deletionPolicy: + default: Retain + description: |- + DeletionPolicy defines rules on how to delete the resulting Secret. + Defaults to "Retain" + enum: + - Delete + - Merge + - Retain + type: string + immutable: + description: Immutable defines if the final secret will be immutable + type: boolean + name: + description: |- + The name of the Secret resource to be managed. + Defaults to the .metadata.name of the ExternalSecret resource + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + template: + description: Template defines a blueprint for the created Secret resource. + properties: + data: + additionalProperties: + type: string + type: object + engineVersion: + default: v2 + description: |- + EngineVersion specifies the template engine version + that should be used to compile/execute the + template specified in .data and .templateFrom[]. + enum: + - v1 + - v2 + type: string + mergePolicy: + default: Replace + enum: + - Replace + - Merge + type: string + metadata: + description: ExternalSecretTemplateMetadata defines metadata fields for the Secret blueprint. + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + templateFrom: + items: + properties: + configMap: + properties: + items: + description: A list of keys in the ConfigMap/Secret to use as templates for Secret data + items: + properties: + key: + description: A key in the ConfigMap/Secret + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + templateAs: + default: Values + enum: + - Values + - KeysAndValues + type: string + required: + - key + type: object + type: array + name: + description: The name of the ConfigMap/Secret resource + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - items + - name + type: object + literal: + type: string + secret: + properties: + items: + description: A list of keys in the ConfigMap/Secret to use as templates for Secret data + items: + properties: + key: + description: A key in the ConfigMap/Secret + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + templateAs: + default: Values + enum: + - Values + - KeysAndValues + type: string + required: + - key + type: object + type: array + name: + description: The name of the ConfigMap/Secret resource + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - items + - name + type: object + target: + default: Data + enum: + - Data + - Annotations + - Labels + type: string + type: object + type: array + type: + type: string + type: object + type: object + type: object + status: + properties: + binding: + description: Binding represents a servicebinding.io Provisioned Service reference to the secret + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + conditions: + items: + properties: + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + refreshTime: + description: |- + refreshTime is the time and date the external secret was fetched and + the target secret updated + format: date-time + nullable: true + type: string + syncedResourceVersion: + description: SyncedResourceVersion keeps track of the last synced version + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} + conversion: + strategy: Webhook + webhook: + conversionReviewVersions: + - v1 + clientConfig: + service: + name: kubernetes + namespace: default + path: /convert +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.17.2 + labels: + external-secrets.io/component: controller + name: pushsecrets.external-secrets.io +spec: + group: external-secrets.io + names: + categories: + - external-secrets + kind: PushSecret + listKind: PushSecretList + plural: pushsecrets + shortNames: + - ps + singular: pushsecret + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: AGE + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].reason + name: Status + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: PushSecretSpec configures the behavior of the PushSecret. + properties: + data: + description: Secret Data that should be pushed to providers + items: + properties: + conversionStrategy: + default: None + description: Used to define a conversion Strategy for the secret keys + enum: + - None + - ReverseUnicode + type: string + match: + description: Match a given Secret Key to be pushed to the provider. + properties: + remoteRef: + description: Remote Refs to push to providers. + properties: + property: + description: Name of the property in the resulting secret + type: string + remoteKey: + description: Name of the resulting provider secret. + type: string + required: + - remoteKey + type: object + secretKey: + description: Secret Key to be pushed + type: string + required: + - remoteRef + type: object + metadata: + description: |- + Metadata is metadata attached to the secret. + The structure of metadata is provider specific, please look it up in the provider documentation. + x-kubernetes-preserve-unknown-fields: true + required: + - match + type: object + type: array + deletionPolicy: + default: None + description: Deletion Policy to handle Secrets in the provider. + enum: + - Delete + - None + type: string + refreshInterval: + default: 1h + description: The Interval to which External Secrets will try to push a secret definition + type: string + secretStoreRefs: + items: + properties: + kind: + default: SecretStore + description: Kind of the SecretStore resource (SecretStore or ClusterSecretStore) + enum: + - SecretStore + - ClusterSecretStore + type: string + labelSelector: + description: Optionally, sync to secret stores with label selector + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + name: + description: Optionally, sync to the SecretStore of the given name + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + type: object + type: array + selector: + description: The Secret Selector (k8s source) for the Push Secret + maxProperties: 1 + minProperties: 1 + properties: + generatorRef: + description: Point to a generator to create a Secret. + properties: + apiVersion: + default: generators.external-secrets.io/v1alpha1 + description: Specify the apiVersion of the generator resource + type: string + kind: + description: Specify the Kind of the generator resource + enum: + - ACRAccessToken + - ClusterGenerator + - ECRAuthorizationToken + - Fake + - GCRAccessToken + - GithubAccessToken + - QuayAccessToken + - Password + - STSSessionToken + - UUID + - VaultDynamicSecret + - Webhook + - Grafana + type: string + name: + description: Specify the name of the generator resource + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - kind + - name + type: object + secret: + description: Select a Secret to Push. + properties: + name: + description: |- + Name of the Secret. + The Secret must exist in the same namespace as the PushSecret manifest. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - name + type: object + type: object + template: + description: Template defines a blueprint for the created Secret resource. + properties: + data: + additionalProperties: + type: string + type: object + engineVersion: + default: v2 + description: |- + EngineVersion specifies the template engine version + that should be used to compile/execute the + template specified in .data and .templateFrom[]. + enum: + - v1 + - v2 + type: string + mergePolicy: + default: Replace + enum: + - Replace + - Merge + type: string + metadata: + description: ExternalSecretTemplateMetadata defines metadata fields for the Secret blueprint. + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + templateFrom: + items: + properties: + configMap: + properties: + items: + description: A list of keys in the ConfigMap/Secret to use as templates for Secret data + items: + properties: + key: + description: A key in the ConfigMap/Secret + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + templateAs: + default: Values + enum: + - Values + - KeysAndValues + type: string + required: + - key + type: object + type: array + name: + description: The name of the ConfigMap/Secret resource + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - items + - name + type: object + literal: + type: string + secret: + properties: + items: + description: A list of keys in the ConfigMap/Secret to use as templates for Secret data + items: + properties: + key: + description: A key in the ConfigMap/Secret + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + templateAs: + default: Values + enum: + - Values + - KeysAndValues + type: string + required: + - key + type: object + type: array + name: + description: The name of the ConfigMap/Secret resource + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - items + - name + type: object + target: + default: Data + enum: + - Data + - Annotations + - Labels + type: string + type: object + type: array + type: + type: string + type: object + updatePolicy: + default: Replace + description: UpdatePolicy to handle Secrets in the provider. + enum: + - Replace + - IfNotExists + type: string + required: + - secretStoreRefs + - selector + type: object + status: + description: PushSecretStatus indicates the history of the status of PushSecret. + properties: + conditions: + items: + description: PushSecretStatusCondition indicates the status of the PushSecret. + properties: + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + description: PushSecretConditionType indicates the condition of the PushSecret. + type: string + required: + - status + - type + type: object + type: array + refreshTime: + description: |- + refreshTime is the time and date the external secret was fetched and + the target secret updated + format: date-time + nullable: true + type: string + syncedPushSecrets: + additionalProperties: + additionalProperties: + properties: + conversionStrategy: + default: None + description: Used to define a conversion Strategy for the secret keys + enum: + - None + - ReverseUnicode + type: string + match: + description: Match a given Secret Key to be pushed to the provider. + properties: + remoteRef: + description: Remote Refs to push to providers. + properties: + property: + description: Name of the property in the resulting secret + type: string + remoteKey: + description: Name of the resulting provider secret. + type: string + required: + - remoteKey + type: object + secretKey: + description: Secret Key to be pushed + type: string + required: + - remoteRef + type: object + metadata: + description: |- + Metadata is metadata attached to the secret. + The structure of metadata is provider specific, please look it up in the provider documentation. + x-kubernetes-preserve-unknown-fields: true + required: + - match + type: object + type: object + description: |- + Synced PushSecrets, including secrets that already exist in provider. + Matches secret stores to PushSecretData that was stored to that secret store. + type: object + syncedResourceVersion: + description: SyncedResourceVersion keeps track of the last synced version. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} + conversion: + strategy: Webhook + webhook: + conversionReviewVersions: + - v1 + clientConfig: + service: + name: kubernetes + namespace: default + path: /convert +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.17.2 + labels: + external-secrets.io/component: controller + name: secretstores.external-secrets.io +spec: + group: external-secrets.io + names: + categories: + - external-secrets + kind: SecretStore + listKind: SecretStoreList + plural: secretstores + shortNames: + - ss + singular: secretstore + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: AGE + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].reason + name: Status + type: string + deprecated: true + name: v1alpha1 + schema: + openAPIV3Schema: + description: SecretStore represents a secure external location for storing secrets, which can be referenced as part of `storeRef` fields. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: SecretStoreSpec defines the desired state of SecretStore. + properties: + controller: + description: |- + Used to select the correct ESO controller (think: ingress.ingressClassName) + The ESO controller is instantiated with a specific controller name and filters ES based on this property + type: string + provider: + description: Used to configure the provider. Only one provider may be set + maxProperties: 1 + minProperties: 1 + properties: + akeyless: + description: Akeyless configures this store to sync secrets using Akeyless Vault provider + properties: + akeylessGWApiURL: + description: Akeyless GW API Url from which the secrets to be fetched from. + type: string + authSecretRef: + description: Auth configures how the operator authenticates with Akeyless. + properties: + kubernetesAuth: + description: |- + Kubernetes authenticates with Akeyless by passing the ServiceAccount + token stored in the named Secret resource. + properties: + accessID: + description: the Akeyless Kubernetes auth-method access-id + type: string + k8sConfName: + description: Kubernetes-auth configuration name in Akeyless-Gateway + type: string + secretRef: + description: |- + Optional secret field containing a Kubernetes ServiceAccount JWT used + for authenticating with Akeyless. If a name is specified without a key, + `token` is the default. If one is not specified, the one bound to + the controller will be used. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + serviceAccountRef: + description: |- + Optional service account field containing the name of a kubernetes ServiceAccount. + If the service account is specified, the service account secret token JWT will be used + for authenticating with Akeyless. If the service account selector is not supplied, + the secretRef will be used instead. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + required: + - accessID + - k8sConfName + type: object + secretRef: + description: |- + Reference to a Secret that contains the details + to authenticate with Akeyless. + properties: + accessID: + description: The SecretAccessID is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + accessType: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + accessTypeParam: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + type: object + caBundle: + description: |- + PEM/base64 encoded CA bundle used to validate Akeyless Gateway certificate. Only used + if the AkeylessGWApiURL URL is using HTTPS protocol. If not set the system root certificates + are used to validate the TLS connection. + format: byte + type: string + caProvider: + description: The provider for the CA bundle to use to validate Akeyless Gateway certificate. + properties: + key: + description: The key where the CA certificate can be found in the Secret or ConfigMap. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the object located at the provider type. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: The namespace the Provider type is in. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + required: + - akeylessGWApiURL + - authSecretRef + type: object + alibaba: + description: Alibaba configures this store to sync secrets using Alibaba Cloud provider + properties: + auth: + description: AlibabaAuth contains a secretRef for credentials. + properties: + rrsa: + description: Authenticate against Alibaba using RRSA. + properties: + oidcProviderArn: + type: string + oidcTokenFilePath: + type: string + roleArn: + type: string + sessionName: + type: string + required: + - oidcProviderArn + - oidcTokenFilePath + - roleArn + - sessionName + type: object + secretRef: + description: AlibabaAuthSecretRef holds secret references for Alibaba credentials. + properties: + accessKeyIDSecretRef: + description: The AccessKeyID is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + accessKeySecretSecretRef: + description: The AccessKeySecret is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - accessKeyIDSecretRef + - accessKeySecretSecretRef + type: object + type: object + regionID: + description: Alibaba Region to be used for the provider + type: string + required: + - auth + - regionID + type: object + aws: + description: AWS configures this store to sync secrets using AWS Secret Manager provider + properties: + auth: + description: |- + Auth defines the information necessary to authenticate against AWS + if not set aws sdk will infer credentials from your environment + see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials + properties: + jwt: + description: Authenticate against AWS using service account tokens. + properties: + serviceAccountRef: + description: A reference to a ServiceAccount resource. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + type: object + secretRef: + description: |- + AWSAuthSecretRef holds secret references for AWS credentials + both AccessKeyID and SecretAccessKey must be defined in order to properly authenticate. + properties: + accessKeyIDSecretRef: + description: The AccessKeyID is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + secretAccessKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + type: object + region: + description: AWS Region to be used for the provider + type: string + role: + description: Role is a Role ARN which the SecretManager provider will assume + type: string + service: + description: Service defines which service should be used to fetch the secrets + enum: + - SecretsManager + - ParameterStore + type: string + required: + - region + - service + type: object + azurekv: + description: AzureKV configures this store to sync secrets using Azure Key Vault provider + properties: + authSecretRef: + description: Auth configures how the operator authenticates with Azure. Required for ServicePrincipal auth type. + properties: + clientId: + description: The Azure clientId of the service principle used for authentication. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + clientSecret: + description: The Azure ClientSecret of the service principle used for authentication. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + authType: + default: ServicePrincipal + description: |- + Auth type defines how to authenticate to the keyvault service. + Valid values are: + - "ServicePrincipal" (default): Using a service principal (tenantId, clientId, clientSecret) + - "ManagedIdentity": Using Managed Identity assigned to the pod (see aad-pod-identity) + enum: + - ServicePrincipal + - ManagedIdentity + - WorkloadIdentity + type: string + identityId: + description: If multiple Managed Identity is assigned to the pod, you can select the one to be used + type: string + serviceAccountRef: + description: |- + ServiceAccountRef specified the service account + that should be used when authenticating with WorkloadIdentity. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + tenantId: + description: TenantID configures the Azure Tenant to send requests to. Required for ServicePrincipal auth type. + type: string + vaultUrl: + description: Vault Url from which the secrets to be fetched from. + type: string + required: + - vaultUrl + type: object + fake: + description: Fake configures a store with static key/value pairs + properties: + data: + items: + properties: + key: + type: string + value: + type: string + valueMap: + additionalProperties: + type: string + type: object + version: + type: string + required: + - key + type: object + type: array + required: + - data + type: object + gcpsm: + description: GCPSM configures this store to sync secrets using Google Cloud Platform Secret Manager provider + properties: + auth: + description: Auth defines the information necessary to authenticate against GCP + properties: + secretRef: + properties: + secretAccessKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + workloadIdentity: + properties: + clusterLocation: + type: string + clusterName: + type: string + clusterProjectID: + type: string + serviceAccountRef: + description: A reference to a ServiceAccount resource. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + required: + - clusterLocation + - clusterName + - serviceAccountRef + type: object + type: object + projectID: + description: ProjectID project where secret is located + type: string + type: object + gitlab: + description: GitLab configures this store to sync secrets using GitLab Variables provider + properties: + auth: + description: Auth configures how secret-manager authenticates with a GitLab instance. + properties: + SecretRef: + properties: + accessToken: + description: AccessToken is used for authentication. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + required: + - SecretRef + type: object + projectID: + description: ProjectID specifies a project where secrets are located. + type: string + url: + description: URL configures the GitLab instance URL. Defaults to https://gitlab.com/. + type: string + required: + - auth + type: object + ibm: + description: IBM configures this store to sync secrets using IBM Cloud provider + properties: + auth: + description: Auth configures how secret-manager authenticates with the IBM secrets manager. + properties: + secretRef: + properties: + secretApiKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + required: + - secretRef + type: object + serviceUrl: + description: ServiceURL is the Endpoint URL that is specific to the Secrets Manager service instance + type: string + required: + - auth + type: object + kubernetes: + description: Kubernetes configures this store to sync secrets using a Kubernetes cluster provider + properties: + auth: + description: Auth configures how secret-manager authenticates with a Kubernetes instance. + maxProperties: 1 + minProperties: 1 + properties: + cert: + description: has both clientCert and clientKey as secretKeySelector + properties: + clientCert: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + clientKey: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + serviceAccount: + description: points to a service account that should be used for authentication + properties: + serviceAccount: + description: A reference to a ServiceAccount resource. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + type: object + token: + description: use static token to authenticate with + properties: + bearerToken: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + type: object + remoteNamespace: + default: default + description: Remote namespace to fetch the secrets from + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + server: + description: configures the Kubernetes server Address. + properties: + caBundle: + description: CABundle is a base64-encoded CA certificate + format: byte + type: string + caProvider: + description: 'see: https://external-secrets.io/v0.4.1/spec/#external-secrets.io/v1alpha1.CAProvider' + properties: + key: + description: The key where the CA certificate can be found in the Secret or ConfigMap. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the object located at the provider type. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: The namespace the Provider type is in. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + url: + default: kubernetes.default + description: configures the Kubernetes server Address. + type: string + type: object + required: + - auth + type: object + oracle: + description: Oracle configures this store to sync secrets using Oracle Vault provider + properties: + auth: + description: |- + Auth configures how secret-manager authenticates with the Oracle Vault. + If empty, instance principal is used. Optionally, the authenticating principal type + and/or user data may be supplied for the use of workload identity and user principal. + properties: + secretRef: + description: SecretRef to pass through sensitive information. + properties: + fingerprint: + description: Fingerprint is the fingerprint of the API private key. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + privatekey: + description: PrivateKey is the user's API Signing Key in PEM format, used for authentication. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - fingerprint + - privatekey + type: object + tenancy: + description: Tenancy is the tenancy OCID where user is located. + type: string + user: + description: User is an access OCID specific to the account. + type: string + required: + - secretRef + - tenancy + - user + type: object + compartment: + description: |- + Compartment is the vault compartment OCID. + Required for PushSecret + type: string + encryptionKey: + description: |- + EncryptionKey is the OCID of the encryption key within the vault. + Required for PushSecret + type: string + principalType: + description: |- + The type of principal to use for authentication. If left blank, the Auth struct will + determine the principal type. This optional field must be specified if using + workload identity. + enum: + - "" + - UserPrincipal + - InstancePrincipal + - Workload + type: string + region: + description: Region is the region where vault is located. + type: string + serviceAccountRef: + description: |- + ServiceAccountRef specified the service account + that should be used when authenticating with WorkloadIdentity. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + vault: + description: Vault is the vault's OCID of the specific vault where secret is located. + type: string + required: + - region + - vault + type: object + passworddepot: + description: Configures a store to sync secrets with a Password Depot instance. + properties: + auth: + description: Auth configures how secret-manager authenticates with a Password Depot instance. + properties: + secretRef: + properties: + credentials: + description: Username / Password is used for authentication. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + required: + - secretRef + type: object + database: + description: Database to use as source + type: string + host: + description: URL configures the Password Depot instance URL. + type: string + required: + - auth + - database + - host + type: object + vault: + description: Vault configures this store to sync secrets using Hashi provider + properties: + auth: + description: Auth configures how secret-manager authenticates with the Vault server. + properties: + appRole: + description: |- + AppRole authenticates with Vault using the App Role auth mechanism, + with the role and secret stored in a Kubernetes Secret resource. + properties: + path: + default: approle + description: |- + Path where the App Role authentication backend is mounted + in Vault, e.g: "approle" + type: string + roleId: + description: |- + RoleID configured in the App Role authentication backend when setting + up the authentication backend in Vault. + type: string + secretRef: + description: |- + Reference to a key in a Secret that contains the App Role secret used + to authenticate with Vault. + The `key` field must be specified and denotes which entry within the Secret + resource is used as the app role secret. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - path + - roleId + - secretRef + type: object + cert: + description: |- + Cert authenticates with TLS Certificates by passing client certificate, private key and ca certificate + Cert authentication method + properties: + clientCert: + description: |- + ClientCert is a certificate to authenticate using the Cert Vault + authentication method + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + secretRef: + description: |- + SecretRef to a key in a Secret resource containing client private key to + authenticate with Vault using the Cert authentication method + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + jwt: + description: |- + Jwt authenticates with Vault by passing role and JWT token using the + JWT/OIDC authentication method + properties: + kubernetesServiceAccountToken: + description: |- + Optional ServiceAccountToken specifies the Kubernetes service account for which to request + a token for with the `TokenRequest` API. + properties: + audiences: + description: |- + Optional audiences field that will be used to request a temporary Kubernetes service + account token for the service account referenced by `serviceAccountRef`. + Defaults to a single audience `vault` it not specified. + items: + type: string + type: array + expirationSeconds: + description: |- + Optional expiration time in seconds that will be used to request a temporary + Kubernetes service account token for the service account referenced by + `serviceAccountRef`. + Defaults to 10 minutes. + format: int64 + type: integer + serviceAccountRef: + description: Service account field containing the name of a kubernetes ServiceAccount. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + required: + - serviceAccountRef + type: object + path: + default: jwt + description: |- + Path where the JWT authentication backend is mounted + in Vault, e.g: "jwt" + type: string + role: + description: |- + Role is a JWT role to authenticate using the JWT/OIDC Vault + authentication method + type: string + secretRef: + description: |- + Optional SecretRef that refers to a key in a Secret resource containing JWT token to + authenticate with Vault using the JWT/OIDC authentication method. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - path + type: object + kubernetes: + description: |- + Kubernetes authenticates with Vault by passing the ServiceAccount + token stored in the named Secret resource to the Vault server. + properties: + mountPath: + default: kubernetes + description: |- + Path where the Kubernetes authentication backend is mounted in Vault, e.g: + "kubernetes" + type: string + role: + description: |- + A required field containing the Vault Role to assume. A Role binds a + Kubernetes ServiceAccount with a set of Vault policies. + type: string + secretRef: + description: |- + Optional secret field containing a Kubernetes ServiceAccount JWT used + for authenticating with Vault. If a name is specified without a key, + `token` is the default. If one is not specified, the one bound to + the controller will be used. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + serviceAccountRef: + description: |- + Optional service account field containing the name of a kubernetes ServiceAccount. + If the service account is specified, the service account secret token JWT will be used + for authenticating with Vault. If the service account selector is not supplied, + the secretRef will be used instead. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + required: + - mountPath + - role + type: object + ldap: + description: |- + Ldap authenticates with Vault by passing username/password pair using + the LDAP authentication method + properties: + path: + default: ldap + description: |- + Path where the LDAP authentication backend is mounted + in Vault, e.g: "ldap" + type: string + secretRef: + description: |- + SecretRef to a key in a Secret resource containing password for the LDAP + user used to authenticate with Vault using the LDAP authentication + method + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + username: + description: |- + Username is a LDAP user name used to authenticate using the LDAP Vault + authentication method + type: string + required: + - path + - username + type: object + tokenSecretRef: + description: TokenSecretRef authenticates with Vault by presenting a token. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + caBundle: + description: |- + PEM encoded CA bundle used to validate Vault server certificate. Only used + if the Server URL is using HTTPS protocol. This parameter is ignored for + plain HTTP protocol connection. If not set the system root certificates + are used to validate the TLS connection. + format: byte + type: string + caProvider: + description: The provider for the CA bundle to use to validate Vault server certificate. + properties: + key: + description: The key where the CA certificate can be found in the Secret or ConfigMap. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the object located at the provider type. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: The namespace the Provider type is in. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + forwardInconsistent: + description: |- + ForwardInconsistent tells Vault to forward read-after-write requests to the Vault + leader instead of simply retrying within a loop. This can increase performance if + the option is enabled serverside. + https://www.vaultproject.io/docs/configuration/replication#allow_forwarding_via_header + type: boolean + namespace: + description: |- + Name of the vault namespace. Namespaces is a set of features within Vault Enterprise that allows + Vault environments to support Secure Multi-tenancy. e.g: "ns1". + More about namespaces can be found here https://www.vaultproject.io/docs/enterprise/namespaces + type: string + path: + description: |- + Path is the mount path of the Vault KV backend endpoint, e.g: + "secret". The v2 KV secret engine version specific "/data" path suffix + for fetching secrets from Vault is optional and will be appended + if not present in specified path. + type: string + readYourWrites: + description: |- + ReadYourWrites ensures isolated read-after-write semantics by + providing discovered cluster replication states in each request. + More information about eventual consistency in Vault can be found here + https://www.vaultproject.io/docs/enterprise/consistency + type: boolean + server: + description: 'Server is the connection address for the Vault server, e.g: "https://vault.example.com:8200".' + type: string + version: + default: v2 + description: |- + Version is the Vault KV secret engine version. This can be either "v1" or + "v2". Version defaults to "v2". + enum: + - v1 + - v2 + type: string + required: + - auth + - server + type: object + webhook: + description: Webhook configures this store to sync secrets using a generic templated webhook + properties: + body: + description: Body + type: string + caBundle: + description: |- + PEM encoded CA bundle used to validate webhook server certificate. Only used + if the Server URL is using HTTPS protocol. This parameter is ignored for + plain HTTP protocol connection. If not set the system root certificates + are used to validate the TLS connection. + format: byte + type: string + caProvider: + description: The provider for the CA bundle to use to validate webhook server certificate. + properties: + key: + description: The key where the CA certificate can be found in the Secret or ConfigMap. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the object located at the provider type. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: The namespace the Provider type is in. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + headers: + additionalProperties: + type: string + description: Headers + type: object + method: + description: Webhook Method + type: string + result: + description: Result formatting + properties: + jsonPath: + description: Json path of return value + type: string + type: object + secrets: + description: |- + Secrets to fill in templates + These secrets will be passed to the templating function as key value pairs under the given name + items: + properties: + name: + description: Name of this secret in templates + type: string + secretRef: + description: Secret ref to fill in credentials + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - name + - secretRef + type: object + type: array + timeout: + description: Timeout + type: string + url: + description: Webhook url to call + type: string + required: + - result + - url + type: object + yandexlockbox: + description: YandexLockbox configures this store to sync secrets using Yandex Lockbox provider + properties: + apiEndpoint: + description: Yandex.Cloud API endpoint (e.g. 'api.cloud.yandex.net:443') + type: string + auth: + description: Auth defines the information necessary to authenticate against Yandex Lockbox + properties: + authorizedKeySecretRef: + description: The authorized key used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + caProvider: + description: The provider for the CA bundle to use to validate Yandex.Cloud server certificate. + properties: + certSecretRef: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + required: + - auth + type: object + type: object + retrySettings: + description: Used to configure http retries if failed + properties: + maxRetries: + format: int32 + type: integer + retryInterval: + type: string + type: object + required: + - provider + type: object + status: + description: SecretStoreStatus defines the observed state of the SecretStore. + properties: + conditions: + items: + properties: + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + type: object + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: AGE + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].reason + name: Status + type: string + - jsonPath: .status.capabilities + name: Capabilities + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + name: v1beta1 + schema: + openAPIV3Schema: + description: SecretStore represents a secure external location for storing secrets, which can be referenced as part of `storeRef` fields. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: SecretStoreSpec defines the desired state of SecretStore. + properties: + conditions: + description: Used to constraint a ClusterSecretStore to specific namespaces. Relevant only to ClusterSecretStore + items: + description: |- + ClusterSecretStoreCondition describes a condition by which to choose namespaces to process ExternalSecrets in + for a ClusterSecretStore instance. + properties: + namespaceRegexes: + description: Choose namespaces by using regex matching + items: + type: string + type: array + namespaceSelector: + description: Choose namespace using a labelSelector + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: Choose namespaces by name + items: + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: array + type: object + type: array + controller: + description: |- + Used to select the correct ESO controller (think: ingress.ingressClassName) + The ESO controller is instantiated with a specific controller name and filters ES based on this property + type: string + provider: + description: Used to configure the provider. Only one provider may be set + maxProperties: 1 + minProperties: 1 + properties: + akeyless: + description: Akeyless configures this store to sync secrets using Akeyless Vault provider + properties: + akeylessGWApiURL: + description: Akeyless GW API Url from which the secrets to be fetched from. + type: string + authSecretRef: + description: Auth configures how the operator authenticates with Akeyless. + properties: + kubernetesAuth: + description: |- + Kubernetes authenticates with Akeyless by passing the ServiceAccount + token stored in the named Secret resource. + properties: + accessID: + description: the Akeyless Kubernetes auth-method access-id + type: string + k8sConfName: + description: Kubernetes-auth configuration name in Akeyless-Gateway + type: string + secretRef: + description: |- + Optional secret field containing a Kubernetes ServiceAccount JWT used + for authenticating with Akeyless. If a name is specified without a key, + `token` is the default. If one is not specified, the one bound to + the controller will be used. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + serviceAccountRef: + description: |- + Optional service account field containing the name of a kubernetes ServiceAccount. + If the service account is specified, the service account secret token JWT will be used + for authenticating with Akeyless. If the service account selector is not supplied, + the secretRef will be used instead. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + required: + - accessID + - k8sConfName + type: object + secretRef: + description: |- + Reference to a Secret that contains the details + to authenticate with Akeyless. + properties: + accessID: + description: The SecretAccessID is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + accessType: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + accessTypeParam: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + type: object + caBundle: + description: |- + PEM/base64 encoded CA bundle used to validate Akeyless Gateway certificate. Only used + if the AkeylessGWApiURL URL is using HTTPS protocol. If not set the system root certificates + are used to validate the TLS connection. + format: byte + type: string + caProvider: + description: The provider for the CA bundle to use to validate Akeyless Gateway certificate. + properties: + key: + description: The key where the CA certificate can be found in the Secret or ConfigMap. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the object located at the provider type. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace the Provider type is in. + Can only be defined when used in a ClusterSecretStore. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + required: + - akeylessGWApiURL + - authSecretRef + type: object + alibaba: + description: Alibaba configures this store to sync secrets using Alibaba Cloud provider + properties: + auth: + description: AlibabaAuth contains a secretRef for credentials. + properties: + rrsa: + description: Authenticate against Alibaba using RRSA. + properties: + oidcProviderArn: + type: string + oidcTokenFilePath: + type: string + roleArn: + type: string + sessionName: + type: string + required: + - oidcProviderArn + - oidcTokenFilePath + - roleArn + - sessionName + type: object + secretRef: + description: AlibabaAuthSecretRef holds secret references for Alibaba credentials. + properties: + accessKeyIDSecretRef: + description: The AccessKeyID is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + accessKeySecretSecretRef: + description: The AccessKeySecret is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - accessKeyIDSecretRef + - accessKeySecretSecretRef + type: object + type: object + regionID: + description: Alibaba Region to be used for the provider + type: string + required: + - auth + - regionID + type: object + aws: + description: AWS configures this store to sync secrets using AWS Secret Manager provider + properties: + additionalRoles: + description: AdditionalRoles is a chained list of Role ARNs which the provider will sequentially assume before assuming the Role + items: + type: string + type: array + auth: + description: |- + Auth defines the information necessary to authenticate against AWS + if not set aws sdk will infer credentials from your environment + see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials + properties: + jwt: + description: Authenticate against AWS using service account tokens. + properties: + serviceAccountRef: + description: A reference to a ServiceAccount resource. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + type: object + secretRef: + description: |- + AWSAuthSecretRef holds secret references for AWS credentials + both AccessKeyID and SecretAccessKey must be defined in order to properly authenticate. + properties: + accessKeyIDSecretRef: + description: The AccessKeyID is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + secretAccessKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + sessionTokenSecretRef: + description: |- + The SessionToken used for authentication + This must be defined if AccessKeyID and SecretAccessKey are temporary credentials + see: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_use-resources.html + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + type: object + externalID: + description: AWS External ID set on assumed IAM roles + type: string + prefix: + description: Prefix adds a prefix to all retrieved values. + type: string + region: + description: AWS Region to be used for the provider + type: string + role: + description: Role is a Role ARN which the provider will assume + type: string + secretsManager: + description: SecretsManager defines how the provider behaves when interacting with AWS SecretsManager + properties: + forceDeleteWithoutRecovery: + description: |- + Specifies whether to delete the secret without any recovery window. You + can't use both this parameter and RecoveryWindowInDays in the same call. + If you don't use either, then by default Secrets Manager uses a 30 day + recovery window. + see: https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_DeleteSecret.html#SecretsManager-DeleteSecret-request-ForceDeleteWithoutRecovery + type: boolean + recoveryWindowInDays: + description: |- + The number of days from 7 to 30 that Secrets Manager waits before + permanently deleting the secret. You can't use both this parameter and + ForceDeleteWithoutRecovery in the same call. If you don't use either, + then by default Secrets Manager uses a 30 day recovery window. + see: https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_DeleteSecret.html#SecretsManager-DeleteSecret-request-RecoveryWindowInDays + format: int64 + type: integer + type: object + service: + description: Service defines which service should be used to fetch the secrets + enum: + - SecretsManager + - ParameterStore + type: string + sessionTags: + description: AWS STS assume role session tags + items: + properties: + key: + type: string + value: + type: string + required: + - key + - value + type: object + type: array + transitiveTagKeys: + description: AWS STS assume role transitive session tags. Required when multiple rules are used with the provider + items: + type: string + type: array + required: + - region + - service + type: object + azurekv: + description: AzureKV configures this store to sync secrets using Azure Key Vault provider + properties: + authSecretRef: + description: Auth configures how the operator authenticates with Azure. Required for ServicePrincipal auth type. Optional for WorkloadIdentity. + properties: + clientCertificate: + description: The Azure ClientCertificate of the service principle used for authentication. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + clientId: + description: The Azure clientId of the service principle or managed identity used for authentication. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + clientSecret: + description: The Azure ClientSecret of the service principle used for authentication. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + tenantId: + description: The Azure tenantId of the managed identity used for authentication. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + authType: + default: ServicePrincipal + description: |- + Auth type defines how to authenticate to the keyvault service. + Valid values are: + - "ServicePrincipal" (default): Using a service principal (tenantId, clientId, clientSecret) + - "ManagedIdentity": Using Managed Identity assigned to the pod (see aad-pod-identity) + enum: + - ServicePrincipal + - ManagedIdentity + - WorkloadIdentity + type: string + environmentType: + default: PublicCloud + description: |- + EnvironmentType specifies the Azure cloud environment endpoints to use for + connecting and authenticating with Azure. By default it points to the public cloud AAD endpoint. + The following endpoints are available, also see here: https://github.com/Azure/go-autorest/blob/main/autorest/azure/environments.go#L152 + PublicCloud, USGovernmentCloud, ChinaCloud, GermanCloud + enum: + - PublicCloud + - USGovernmentCloud + - ChinaCloud + - GermanCloud + type: string + identityId: + description: If multiple Managed Identity is assigned to the pod, you can select the one to be used + type: string + serviceAccountRef: + description: |- + ServiceAccountRef specified the service account + that should be used when authenticating with WorkloadIdentity. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + tenantId: + description: TenantID configures the Azure Tenant to send requests to. Required for ServicePrincipal auth type. Optional for WorkloadIdentity. + type: string + vaultUrl: + description: Vault Url from which the secrets to be fetched from. + type: string + required: + - vaultUrl + type: object + beyondtrust: + description: Beyondtrust configures this store to sync secrets using Password Safe provider. + properties: + auth: + description: Auth configures how the operator authenticates with Beyondtrust. + properties: + apiKey: + description: APIKey If not provided then ClientID/ClientSecret become required. + properties: + secretRef: + description: SecretRef references a key in a secret that will be used as value. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + value: + description: Value can be specified directly to set a value without using a secret. + type: string + type: object + certificate: + description: Certificate (cert.pem) for use when authenticating with an OAuth client Id using a Client Certificate. + properties: + secretRef: + description: SecretRef references a key in a secret that will be used as value. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + value: + description: Value can be specified directly to set a value without using a secret. + type: string + type: object + certificateKey: + description: Certificate private key (key.pem). For use when authenticating with an OAuth client Id + properties: + secretRef: + description: SecretRef references a key in a secret that will be used as value. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + value: + description: Value can be specified directly to set a value without using a secret. + type: string + type: object + clientId: + description: ClientID is the API OAuth Client ID. + properties: + secretRef: + description: SecretRef references a key in a secret that will be used as value. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + value: + description: Value can be specified directly to set a value without using a secret. + type: string + type: object + clientSecret: + description: ClientSecret is the API OAuth Client Secret. + properties: + secretRef: + description: SecretRef references a key in a secret that will be used as value. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + value: + description: Value can be specified directly to set a value without using a secret. + type: string + type: object + type: object + server: + description: Auth configures how API server works. + properties: + apiUrl: + type: string + apiVersion: + type: string + clientTimeOutSeconds: + description: Timeout specifies a time limit for requests made by this Client. The timeout includes connection time, any redirects, and reading the response body. Defaults to 45 seconds. + type: integer + retrievalType: + description: The secret retrieval type. SECRET = Secrets Safe (credential, text, file). MANAGED_ACCOUNT = Password Safe account associated with a system. + type: string + separator: + description: A character that separates the folder names. + type: string + verifyCA: + type: boolean + required: + - apiUrl + - verifyCA + type: object + required: + - auth + - server + type: object + bitwardensecretsmanager: + description: BitwardenSecretsManager configures this store to sync secrets using BitwardenSecretsManager provider + properties: + apiURL: + type: string + auth: + description: |- + Auth configures how secret-manager authenticates with a bitwarden machine account instance. + Make sure that the token being used has permissions on the given secret. + properties: + secretRef: + description: BitwardenSecretsManagerSecretRef contains the credential ref to the bitwarden instance. + properties: + credentials: + description: AccessToken used for the bitwarden instance. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - credentials + type: object + required: + - secretRef + type: object + bitwardenServerSDKURL: + type: string + caBundle: + description: |- + Base64 encoded certificate for the bitwarden server sdk. The sdk MUST run with HTTPS to make sure no MITM attack + can be performed. + type: string + caProvider: + description: 'see: https://external-secrets.io/latest/spec/#external-secrets.io/v1alpha1.CAProvider' + properties: + key: + description: The key where the CA certificate can be found in the Secret or ConfigMap. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the object located at the provider type. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace the Provider type is in. + Can only be defined when used in a ClusterSecretStore. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + identityURL: + type: string + organizationID: + description: OrganizationID determines which organization this secret store manages. + type: string + projectID: + description: ProjectID determines which project this secret store manages. + type: string + required: + - auth + - organizationID + - projectID + type: object + chef: + description: Chef configures this store to sync secrets with chef server + properties: + auth: + description: Auth defines the information necessary to authenticate against chef Server + properties: + secretRef: + description: ChefAuthSecretRef holds secret references for chef server login credentials. + properties: + privateKeySecretRef: + description: SecretKey is the Signing Key in PEM format, used for authentication. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - privateKeySecretRef + type: object + required: + - secretRef + type: object + serverUrl: + description: ServerURL is the chef server URL used to connect to. If using orgs you should include your org in the url and terminate the url with a "/" + type: string + username: + description: UserName should be the user ID on the chef server + type: string + required: + - auth + - serverUrl + - username + type: object + conjur: + description: Conjur configures this store to sync secrets using conjur provider + properties: + auth: + properties: + apikey: + properties: + account: + type: string + apiKeyRef: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + userRef: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - account + - apiKeyRef + - userRef + type: object + jwt: + properties: + account: + type: string + hostId: + description: |- + Optional HostID for JWT authentication. This may be used depending + on how the Conjur JWT authenticator policy is configured. + type: string + secretRef: + description: |- + Optional SecretRef that refers to a key in a Secret resource containing JWT token to + authenticate with Conjur using the JWT authentication method. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + serviceAccountRef: + description: |- + Optional ServiceAccountRef specifies the Kubernetes service account for which to request + a token for with the `TokenRequest` API. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + serviceID: + description: The conjur authn jwt webservice id + type: string + required: + - account + - serviceID + type: object + type: object + caBundle: + type: string + caProvider: + description: |- + Used to provide custom certificate authority (CA) certificates + for a secret store. The CAProvider points to a Secret or ConfigMap resource + that contains a PEM-encoded certificate. + properties: + key: + description: The key where the CA certificate can be found in the Secret or ConfigMap. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the object located at the provider type. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace the Provider type is in. + Can only be defined when used in a ClusterSecretStore. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + url: + type: string + required: + - auth + - url + type: object + delinea: + description: |- + Delinea DevOps Secrets Vault + https://docs.delinea.com/online-help/products/devops-secrets-vault/current + properties: + clientId: + description: ClientID is the non-secret part of the credential. + properties: + secretRef: + description: SecretRef references a key in a secret that will be used as value. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + value: + description: Value can be specified directly to set a value without using a secret. + type: string + type: object + clientSecret: + description: ClientSecret is the secret part of the credential. + properties: + secretRef: + description: SecretRef references a key in a secret that will be used as value. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + value: + description: Value can be specified directly to set a value without using a secret. + type: string + type: object + tenant: + description: Tenant is the chosen hostname / site name. + type: string + tld: + description: |- + TLD is based on the server location that was chosen during provisioning. + If unset, defaults to "com". + type: string + urlTemplate: + description: |- + URLTemplate + If unset, defaults to "https://%s.secretsvaultcloud.%s/v1/%s%s". + type: string + required: + - clientId + - clientSecret + - tenant + type: object + device42: + description: Device42 configures this store to sync secrets using the Device42 provider + properties: + auth: + description: Auth configures how secret-manager authenticates with a Device42 instance. + properties: + secretRef: + properties: + credentials: + description: Username / Password is used for authentication. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + required: + - secretRef + type: object + host: + description: URL configures the Device42 instance URL. + type: string + required: + - auth + - host + type: object + doppler: + description: Doppler configures this store to sync secrets using the Doppler provider + properties: + auth: + description: Auth configures how the Operator authenticates with the Doppler API + properties: + secretRef: + properties: + dopplerToken: + description: |- + The DopplerToken is used for authentication. + See https://docs.doppler.com/reference/api#authentication for auth token types. + The Key attribute defaults to dopplerToken if not specified. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - dopplerToken + type: object + required: + - secretRef + type: object + config: + description: Doppler config (required if not using a Service Token) + type: string + format: + description: Format enables the downloading of secrets as a file (string) + enum: + - json + - dotnet-json + - env + - yaml + - docker + type: string + nameTransformer: + description: Environment variable compatible name transforms that change secret names to a different format + enum: + - upper-camel + - camel + - lower-snake + - tf-var + - dotnet-env + - lower-kebab + type: string + project: + description: Doppler project (required if not using a Service Token) + type: string + required: + - auth + type: object + fake: + description: Fake configures a store with static key/value pairs + properties: + data: + items: + properties: + key: + type: string + value: + type: string + valueMap: + additionalProperties: + type: string + description: 'Deprecated: ValueMap is deprecated and is intended to be removed in the future, use the `value` field instead.' + type: object + version: + type: string + required: + - key + type: object + type: array + required: + - data + type: object + fortanix: + description: Fortanix configures this store to sync secrets using the Fortanix provider + properties: + apiKey: + description: APIKey is the API token to access SDKMS Applications. + properties: + secretRef: + description: SecretRef is a reference to a secret containing the SDKMS API Key. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + apiUrl: + description: APIURL is the URL of SDKMS API. Defaults to `sdkms.fortanix.com`. + type: string + type: object + gcpsm: + description: GCPSM configures this store to sync secrets using Google Cloud Platform Secret Manager provider + properties: + auth: + description: Auth defines the information necessary to authenticate against GCP + properties: + secretRef: + properties: + secretAccessKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + workloadIdentity: + properties: + clusterLocation: + type: string + clusterName: + type: string + clusterProjectID: + type: string + serviceAccountRef: + description: A reference to a ServiceAccount resource. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + required: + - clusterLocation + - clusterName + - serviceAccountRef + type: object + type: object + location: + description: Location optionally defines a location for a secret + type: string + projectID: + description: ProjectID project where secret is located + type: string + type: object + github: + description: Github configures this store to push Github Action secrets using Github API provider + properties: + appID: + description: appID specifies the Github APP that will be used to authenticate the client + format: int64 + type: integer + auth: + description: auth configures how secret-manager authenticates with a Github instance. + properties: + privateKey: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - privateKey + type: object + environment: + description: environment will be used to fetch secrets from a particular environment within a github repository + type: string + installationID: + description: installationID specifies the Github APP installation that will be used to authenticate the client + format: int64 + type: integer + organization: + description: organization will be used to fetch secrets from the Github organization + type: string + repository: + description: repository will be used to fetch secrets from the Github repository within an organization + type: string + uploadURL: + description: Upload URL for enterprise instances. Default to URL. + type: string + url: + default: https://github.com/ + description: URL configures the Github instance URL. Defaults to https://github.com/. + type: string + required: + - appID + - auth + - installationID + - organization + type: object + gitlab: + description: GitLab configures this store to sync secrets using GitLab Variables provider + properties: + auth: + description: Auth configures how secret-manager authenticates with a GitLab instance. + properties: + SecretRef: + properties: + accessToken: + description: AccessToken is used for authentication. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + required: + - SecretRef + type: object + environment: + description: Environment environment_scope of gitlab CI/CD variables (Please see https://docs.gitlab.com/ee/ci/environments/#create-a-static-environment on how to create environments) + type: string + groupIDs: + description: GroupIDs specify, which gitlab groups to pull secrets from. Group secrets are read from left to right followed by the project variables. + items: + type: string + type: array + inheritFromGroups: + description: InheritFromGroups specifies whether parent groups should be discovered and checked for secrets. + type: boolean + projectID: + description: ProjectID specifies a project where secrets are located. + type: string + url: + description: URL configures the GitLab instance URL. Defaults to https://gitlab.com/. + type: string + required: + - auth + type: object + ibm: + description: IBM configures this store to sync secrets using IBM Cloud provider + properties: + auth: + description: Auth configures how secret-manager authenticates with the IBM secrets manager. + maxProperties: 1 + minProperties: 1 + properties: + containerAuth: + description: IBM Container-based auth with IAM Trusted Profile. + properties: + iamEndpoint: + type: string + profile: + description: the IBM Trusted Profile + type: string + tokenLocation: + description: Location the token is mounted on the pod + type: string + required: + - profile + type: object + secretRef: + properties: + secretApiKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + type: object + serviceUrl: + description: ServiceURL is the Endpoint URL that is specific to the Secrets Manager service instance + type: string + required: + - auth + type: object + infisical: + description: Infisical configures this store to sync secrets using the Infisical provider + properties: + auth: + description: Auth configures how the Operator authenticates with the Infisical API + properties: + universalAuthCredentials: + properties: + clientId: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + clientSecret: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - clientId + - clientSecret + type: object + type: object + hostAPI: + default: https://app.infisical.com/api + description: HostAPI specifies the base URL of the Infisical API. If not provided, it defaults to "https://app.infisical.com/api". + type: string + secretsScope: + description: SecretsScope defines the scope of the secrets within the workspace + properties: + environmentSlug: + description: EnvironmentSlug is the required slug identifier for the environment. + type: string + expandSecretReferences: + default: true + description: ExpandSecretReferences indicates whether secret references should be expanded. Defaults to true if not provided. + type: boolean + projectSlug: + description: ProjectSlug is the required slug identifier for the project. + type: string + recursive: + default: false + description: Recursive indicates whether the secrets should be fetched recursively. Defaults to false if not provided. + type: boolean + secretsPath: + default: / + description: SecretsPath specifies the path to the secrets within the workspace. Defaults to "/" if not provided. + type: string + required: + - environmentSlug + - projectSlug + type: object + required: + - auth + - secretsScope + type: object + keepersecurity: + description: KeeperSecurity configures this store to sync secrets using the KeeperSecurity provider + properties: + authRef: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + folderID: + type: string + required: + - authRef + - folderID + type: object + kubernetes: + description: Kubernetes configures this store to sync secrets using a Kubernetes cluster provider + properties: + auth: + description: Auth configures how secret-manager authenticates with a Kubernetes instance. + maxProperties: 1 + minProperties: 1 + properties: + cert: + description: has both clientCert and clientKey as secretKeySelector + properties: + clientCert: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + clientKey: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + serviceAccount: + description: points to a service account that should be used for authentication + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + token: + description: use static token to authenticate with + properties: + bearerToken: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + type: object + authRef: + description: A reference to a secret that contains the auth information. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + remoteNamespace: + default: default + description: Remote namespace to fetch the secrets from + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + server: + description: configures the Kubernetes server Address. + properties: + caBundle: + description: CABundle is a base64-encoded CA certificate + format: byte + type: string + caProvider: + description: 'see: https://external-secrets.io/v0.4.1/spec/#external-secrets.io/v1alpha1.CAProvider' + properties: + key: + description: The key where the CA certificate can be found in the Secret or ConfigMap. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the object located at the provider type. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace the Provider type is in. + Can only be defined when used in a ClusterSecretStore. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + url: + default: kubernetes.default + description: configures the Kubernetes server Address. + type: string + type: object + type: object + onboardbase: + description: Onboardbase configures this store to sync secrets using the Onboardbase provider + properties: + apiHost: + default: https://public.onboardbase.com/api/v1/ + description: APIHost use this to configure the host url for the API for selfhosted installation, default is https://public.onboardbase.com/api/v1/ + type: string + auth: + description: Auth configures how the Operator authenticates with the Onboardbase API + properties: + apiKeyRef: + description: |- + OnboardbaseAPIKey is the APIKey generated by an admin account. + It is used to recognize and authorize access to a project and environment within onboardbase + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + passcodeRef: + description: OnboardbasePasscode is the passcode attached to the API Key + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - apiKeyRef + - passcodeRef + type: object + environment: + default: development + description: Environment is the name of an environmnent within a project to pull the secrets from + type: string + project: + default: development + description: Project is an onboardbase project that the secrets should be pulled from + type: string + required: + - apiHost + - auth + - environment + - project + type: object + onepassword: + description: OnePassword configures this store to sync secrets using the 1Password Cloud provider + properties: + auth: + description: Auth defines the information necessary to authenticate against OnePassword Connect Server + properties: + secretRef: + description: OnePasswordAuthSecretRef holds secret references for 1Password credentials. + properties: + connectTokenSecretRef: + description: The ConnectToken is used for authentication to a 1Password Connect Server. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - connectTokenSecretRef + type: object + required: + - secretRef + type: object + connectHost: + description: ConnectHost defines the OnePassword Connect Server to connect to + type: string + vaults: + additionalProperties: + type: integer + description: Vaults defines which OnePassword vaults to search in which order + type: object + required: + - auth + - connectHost + - vaults + type: object + oracle: + description: Oracle configures this store to sync secrets using Oracle Vault provider + properties: + auth: + description: |- + Auth configures how secret-manager authenticates with the Oracle Vault. + If empty, use the instance principal, otherwise the user credentials specified in Auth. + properties: + secretRef: + description: SecretRef to pass through sensitive information. + properties: + fingerprint: + description: Fingerprint is the fingerprint of the API private key. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + privatekey: + description: PrivateKey is the user's API Signing Key in PEM format, used for authentication. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - fingerprint + - privatekey + type: object + tenancy: + description: Tenancy is the tenancy OCID where user is located. + type: string + user: + description: User is an access OCID specific to the account. + type: string + required: + - secretRef + - tenancy + - user + type: object + compartment: + description: |- + Compartment is the vault compartment OCID. + Required for PushSecret + type: string + encryptionKey: + description: |- + EncryptionKey is the OCID of the encryption key within the vault. + Required for PushSecret + type: string + principalType: + description: |- + The type of principal to use for authentication. If left blank, the Auth struct will + determine the principal type. This optional field must be specified if using + workload identity. + enum: + - "" + - UserPrincipal + - InstancePrincipal + - Workload + type: string + region: + description: Region is the region where vault is located. + type: string + serviceAccountRef: + description: |- + ServiceAccountRef specified the service account + that should be used when authenticating with WorkloadIdentity. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + vault: + description: Vault is the vault's OCID of the specific vault where secret is located. + type: string + required: + - region + - vault + type: object + passbolt: + properties: + auth: + description: Auth defines the information necessary to authenticate against Passbolt Server + properties: + passwordSecretRef: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + privateKeySecretRef: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - passwordSecretRef + - privateKeySecretRef + type: object + host: + description: Host defines the Passbolt Server to connect to + type: string + required: + - auth + - host + type: object + passworddepot: + description: Configures a store to sync secrets with a Password Depot instance. + properties: + auth: + description: Auth configures how secret-manager authenticates with a Password Depot instance. + properties: + secretRef: + properties: + credentials: + description: Username / Password is used for authentication. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + required: + - secretRef + type: object + database: + description: Database to use as source + type: string + host: + description: URL configures the Password Depot instance URL. + type: string + required: + - auth + - database + - host + type: object + previder: + description: Previder configures this store to sync secrets using the Previder provider + properties: + auth: + description: PreviderAuth contains a secretRef for credentials. + properties: + secretRef: + description: PreviderAuthSecretRef holds secret references for Previder Vault credentials. + properties: + accessToken: + description: The AccessToken is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - accessToken + type: object + type: object + baseUri: + type: string + required: + - auth + type: object + pulumi: + description: Pulumi configures this store to sync secrets using the Pulumi provider + properties: + accessToken: + description: AccessToken is the access tokens to sign in to the Pulumi Cloud Console. + properties: + secretRef: + description: SecretRef is a reference to a secret containing the Pulumi API token. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + apiUrl: + default: https://api.pulumi.com/api/esc + description: APIURL is the URL of the Pulumi API. + type: string + environment: + description: |- + Environment are YAML documents composed of static key-value pairs, programmatic expressions, + dynamically retrieved values from supported providers including all major clouds, + and other Pulumi ESC environments. + To create a new environment, visit https://www.pulumi.com/docs/esc/environments/ for more information. + type: string + organization: + description: |- + Organization are a space to collaborate on shared projects and stacks. + To create a new organization, visit https://app.pulumi.com/ and click "New Organization". + type: string + project: + description: Project is the name of the Pulumi ESC project the environment belongs to. + type: string + required: + - accessToken + - environment + - organization + - project + type: object + scaleway: + description: Scaleway + properties: + accessKey: + description: AccessKey is the non-secret part of the api key. + properties: + secretRef: + description: SecretRef references a key in a secret that will be used as value. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + value: + description: Value can be specified directly to set a value without using a secret. + type: string + type: object + apiUrl: + description: APIURL is the url of the api to use. Defaults to https://api.scaleway.com + type: string + projectId: + description: 'ProjectID is the id of your project, which you can find in the console: https://console.scaleway.com/project/settings' + type: string + region: + description: 'Region where your secrets are located: https://developers.scaleway.com/en/quickstart/#region-and-zone' + type: string + secretKey: + description: SecretKey is the non-secret part of the api key. + properties: + secretRef: + description: SecretRef references a key in a secret that will be used as value. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + value: + description: Value can be specified directly to set a value without using a secret. + type: string + type: object + required: + - accessKey + - projectId + - region + - secretKey + type: object + secretserver: + description: |- + SecretServer configures this store to sync secrets using SecretServer provider + https://docs.delinea.com/online-help/secret-server/start.htm + properties: + password: + description: Password is the secret server account password. + properties: + secretRef: + description: SecretRef references a key in a secret that will be used as value. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + value: + description: Value can be specified directly to set a value without using a secret. + type: string + type: object + serverURL: + description: |- + ServerURL + URL to your secret server installation + type: string + username: + description: Username is the secret server account username. + properties: + secretRef: + description: SecretRef references a key in a secret that will be used as value. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + value: + description: Value can be specified directly to set a value without using a secret. + type: string + type: object + required: + - password + - serverURL + - username + type: object + senhasegura: + description: Senhasegura configures this store to sync secrets using senhasegura provider + properties: + auth: + description: Auth defines parameters to authenticate in senhasegura + properties: + clientId: + type: string + clientSecretSecretRef: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - clientId + - clientSecretSecretRef + type: object + ignoreSslCertificate: + default: false + description: IgnoreSslCertificate defines if SSL certificate must be ignored + type: boolean + module: + description: Module defines which senhasegura module should be used to get secrets + type: string + url: + description: URL of senhasegura + type: string + required: + - auth + - module + - url + type: object + vault: + description: Vault configures this store to sync secrets using Hashi provider + properties: + auth: + description: Auth configures how secret-manager authenticates with the Vault server. + properties: + appRole: + description: |- + AppRole authenticates with Vault using the App Role auth mechanism, + with the role and secret stored in a Kubernetes Secret resource. + properties: + path: + default: approle + description: |- + Path where the App Role authentication backend is mounted + in Vault, e.g: "approle" + type: string + roleId: + description: |- + RoleID configured in the App Role authentication backend when setting + up the authentication backend in Vault. + type: string + roleRef: + description: |- + Reference to a key in a Secret that contains the App Role ID used + to authenticate with Vault. + The `key` field must be specified and denotes which entry within the Secret + resource is used as the app role id. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + secretRef: + description: |- + Reference to a key in a Secret that contains the App Role secret used + to authenticate with Vault. + The `key` field must be specified and denotes which entry within the Secret + resource is used as the app role secret. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - path + - secretRef + type: object + cert: + description: |- + Cert authenticates with TLS Certificates by passing client certificate, private key and ca certificate + Cert authentication method + properties: + clientCert: + description: |- + ClientCert is a certificate to authenticate using the Cert Vault + authentication method + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + secretRef: + description: |- + SecretRef to a key in a Secret resource containing client private key to + authenticate with Vault using the Cert authentication method + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + iam: + description: |- + Iam authenticates with vault by passing a special AWS request signed with AWS IAM credentials + AWS IAM authentication method + properties: + externalID: + description: AWS External ID set on assumed IAM roles + type: string + jwt: + description: Specify a service account with IRSA enabled + properties: + serviceAccountRef: + description: A reference to a ServiceAccount resource. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + type: object + path: + description: 'Path where the AWS auth method is enabled in Vault, e.g: "aws"' + type: string + region: + description: AWS region + type: string + role: + description: This is the AWS role to be assumed before talking to vault + type: string + secretRef: + description: Specify credentials in a Secret object + properties: + accessKeyIDSecretRef: + description: The AccessKeyID is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + secretAccessKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + sessionTokenSecretRef: + description: |- + The SessionToken used for authentication + This must be defined if AccessKeyID and SecretAccessKey are temporary credentials + see: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_use-resources.html + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + vaultAwsIamServerID: + description: 'X-Vault-AWS-IAM-Server-ID is an additional header used by Vault IAM auth method to mitigate against different types of replay attacks. More details here: https://developer.hashicorp.com/vault/docs/auth/aws' + type: string + vaultRole: + description: Vault Role. In vault, a role describes an identity with a set of permissions, groups, or policies you want to attach a user of the secrets engine + type: string + required: + - vaultRole + type: object + jwt: + description: |- + Jwt authenticates with Vault by passing role and JWT token using the + JWT/OIDC authentication method + properties: + kubernetesServiceAccountToken: + description: |- + Optional ServiceAccountToken specifies the Kubernetes service account for which to request + a token for with the `TokenRequest` API. + properties: + audiences: + description: |- + Optional audiences field that will be used to request a temporary Kubernetes service + account token for the service account referenced by `serviceAccountRef`. + Defaults to a single audience `vault` it not specified. + Deprecated: use serviceAccountRef.Audiences instead + items: + type: string + type: array + expirationSeconds: + description: |- + Optional expiration time in seconds that will be used to request a temporary + Kubernetes service account token for the service account referenced by + `serviceAccountRef`. + Deprecated: this will be removed in the future. + Defaults to 10 minutes. + format: int64 + type: integer + serviceAccountRef: + description: Service account field containing the name of a kubernetes ServiceAccount. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + required: + - serviceAccountRef + type: object + path: + default: jwt + description: |- + Path where the JWT authentication backend is mounted + in Vault, e.g: "jwt" + type: string + role: + description: |- + Role is a JWT role to authenticate using the JWT/OIDC Vault + authentication method + type: string + secretRef: + description: |- + Optional SecretRef that refers to a key in a Secret resource containing JWT token to + authenticate with Vault using the JWT/OIDC authentication method. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - path + type: object + kubernetes: + description: |- + Kubernetes authenticates with Vault by passing the ServiceAccount + token stored in the named Secret resource to the Vault server. + properties: + mountPath: + default: kubernetes + description: |- + Path where the Kubernetes authentication backend is mounted in Vault, e.g: + "kubernetes" + type: string + role: + description: |- + A required field containing the Vault Role to assume. A Role binds a + Kubernetes ServiceAccount with a set of Vault policies. + type: string + secretRef: + description: |- + Optional secret field containing a Kubernetes ServiceAccount JWT used + for authenticating with Vault. If a name is specified without a key, + `token` is the default. If one is not specified, the one bound to + the controller will be used. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + serviceAccountRef: + description: |- + Optional service account field containing the name of a kubernetes ServiceAccount. + If the service account is specified, the service account secret token JWT will be used + for authenticating with Vault. If the service account selector is not supplied, + the secretRef will be used instead. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + required: + - mountPath + - role + type: object + ldap: + description: |- + Ldap authenticates with Vault by passing username/password pair using + the LDAP authentication method + properties: + path: + default: ldap + description: |- + Path where the LDAP authentication backend is mounted + in Vault, e.g: "ldap" + type: string + secretRef: + description: |- + SecretRef to a key in a Secret resource containing password for the LDAP + user used to authenticate with Vault using the LDAP authentication + method + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + username: + description: |- + Username is an LDAP username used to authenticate using the LDAP Vault + authentication method + type: string + required: + - path + - username + type: object + namespace: + description: |- + Name of the vault namespace to authenticate to. This can be different than the namespace your secret is in. + Namespaces is a set of features within Vault Enterprise that allows + Vault environments to support Secure Multi-tenancy. e.g: "ns1". + More about namespaces can be found here https://www.vaultproject.io/docs/enterprise/namespaces + This will default to Vault.Namespace field if set, or empty otherwise + type: string + tokenSecretRef: + description: TokenSecretRef authenticates with Vault by presenting a token. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + userPass: + description: UserPass authenticates with Vault by passing username/password pair + properties: + path: + default: userpass + description: |- + Path where the UserPassword authentication backend is mounted + in Vault, e.g: "userpass" + type: string + secretRef: + description: |- + SecretRef to a key in a Secret resource containing password for the + user used to authenticate with Vault using the UserPass authentication + method + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + username: + description: |- + Username is a username used to authenticate using the UserPass Vault + authentication method + type: string + required: + - path + - username + type: object + type: object + caBundle: + description: |- + PEM encoded CA bundle used to validate Vault server certificate. Only used + if the Server URL is using HTTPS protocol. This parameter is ignored for + plain HTTP protocol connection. If not set the system root certificates + are used to validate the TLS connection. + format: byte + type: string + caProvider: + description: The provider for the CA bundle to use to validate Vault server certificate. + properties: + key: + description: The key where the CA certificate can be found in the Secret or ConfigMap. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the object located at the provider type. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace the Provider type is in. + Can only be defined when used in a ClusterSecretStore. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + forwardInconsistent: + description: |- + ForwardInconsistent tells Vault to forward read-after-write requests to the Vault + leader instead of simply retrying within a loop. This can increase performance if + the option is enabled serverside. + https://www.vaultproject.io/docs/configuration/replication#allow_forwarding_via_header + type: boolean + headers: + additionalProperties: + type: string + description: Headers to be added in Vault request + type: object + namespace: + description: |- + Name of the vault namespace. Namespaces is a set of features within Vault Enterprise that allows + Vault environments to support Secure Multi-tenancy. e.g: "ns1". + More about namespaces can be found here https://www.vaultproject.io/docs/enterprise/namespaces + type: string + path: + description: |- + Path is the mount path of the Vault KV backend endpoint, e.g: + "secret". The v2 KV secret engine version specific "/data" path suffix + for fetching secrets from Vault is optional and will be appended + if not present in specified path. + type: string + readYourWrites: + description: |- + ReadYourWrites ensures isolated read-after-write semantics by + providing discovered cluster replication states in each request. + More information about eventual consistency in Vault can be found here + https://www.vaultproject.io/docs/enterprise/consistency + type: boolean + server: + description: 'Server is the connection address for the Vault server, e.g: "https://vault.example.com:8200".' + type: string + tls: + description: |- + The configuration used for client side related TLS communication, when the Vault server + requires mutual authentication. Only used if the Server URL is using HTTPS protocol. + This parameter is ignored for plain HTTP protocol connection. + It's worth noting this configuration is different from the "TLS certificates auth method", + which is available under the `auth.cert` section. + properties: + certSecretRef: + description: |- + CertSecretRef is a certificate added to the transport layer + when communicating with the Vault server. + If no key for the Secret is specified, external-secret will default to 'tls.crt'. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + keySecretRef: + description: |- + KeySecretRef to a key in a Secret resource containing client private key + added to the transport layer when communicating with the Vault server. + If no key for the Secret is specified, external-secret will default to 'tls.key'. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + version: + default: v2 + description: |- + Version is the Vault KV secret engine version. This can be either "v1" or + "v2". Version defaults to "v2". + enum: + - v1 + - v2 + type: string + required: + - server + type: object + webhook: + description: Webhook configures this store to sync secrets using a generic templated webhook + properties: + body: + description: Body + type: string + caBundle: + description: |- + PEM encoded CA bundle used to validate webhook server certificate. Only used + if the Server URL is using HTTPS protocol. This parameter is ignored for + plain HTTP protocol connection. If not set the system root certificates + are used to validate the TLS connection. + format: byte + type: string + caProvider: + description: The provider for the CA bundle to use to validate webhook server certificate. + properties: + key: + description: The key where the CA certificate can be found in the Secret or ConfigMap. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the object located at the provider type. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: The namespace the Provider type is in. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + headers: + additionalProperties: + type: string + description: Headers + type: object + method: + description: Webhook Method + type: string + result: + description: Result formatting + properties: + jsonPath: + description: Json path of return value + type: string + type: object + secrets: + description: |- + Secrets to fill in templates + These secrets will be passed to the templating function as key value pairs under the given name + items: + properties: + name: + description: Name of this secret in templates + type: string + secretRef: + description: Secret ref to fill in credentials + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - name + - secretRef + type: object + type: array + timeout: + description: Timeout + type: string + url: + description: Webhook url to call + type: string + required: + - result + - url + type: object + yandexcertificatemanager: + description: YandexCertificateManager configures this store to sync secrets using Yandex Certificate Manager provider + properties: + apiEndpoint: + description: Yandex.Cloud API endpoint (e.g. 'api.cloud.yandex.net:443') + type: string + auth: + description: Auth defines the information necessary to authenticate against Yandex Certificate Manager + properties: + authorizedKeySecretRef: + description: The authorized key used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + caProvider: + description: The provider for the CA bundle to use to validate Yandex.Cloud server certificate. + properties: + certSecretRef: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + required: + - auth + type: object + yandexlockbox: + description: YandexLockbox configures this store to sync secrets using Yandex Lockbox provider + properties: + apiEndpoint: + description: Yandex.Cloud API endpoint (e.g. 'api.cloud.yandex.net:443') + type: string + auth: + description: Auth defines the information necessary to authenticate against Yandex Lockbox + properties: + authorizedKeySecretRef: + description: The authorized key used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + caProvider: + description: The provider for the CA bundle to use to validate Yandex.Cloud server certificate. + properties: + certSecretRef: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + required: + - auth + type: object + type: object + refreshInterval: + description: Used to configure store refresh interval in seconds. Empty or 0 will default to the controller config. + type: integer + retrySettings: + description: Used to configure http retries if failed + properties: + maxRetries: + format: int32 + type: integer + retryInterval: + type: string + type: object + required: + - provider + type: object + status: + description: SecretStoreStatus defines the observed state of the SecretStore. + properties: + capabilities: + description: SecretStoreCapabilities defines the possible operations a SecretStore can do. + type: string + conditions: + items: + properties: + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} + conversion: + strategy: Webhook + webhook: + conversionReviewVersions: + - v1 + clientConfig: + service: + name: kubernetes + namespace: default + path: /convert +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.17.2 + labels: + external-secrets.io/component: controller + name: acraccesstokens.generators.external-secrets.io +spec: + group: generators.external-secrets.io + names: + categories: + - external-secrets + - external-secrets-generators + kind: ACRAccessToken + listKind: ACRAccessTokenList + plural: acraccesstokens + singular: acraccesstoken + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + ACRAccessToken returns an Azure Container Registry token + that can be used for pushing/pulling images. + Note: by default it will return an ACR Refresh Token with full access + (depending on the identity). + This can be scoped down to the repository level using .spec.scope. + In case scope is defined it will return an ACR Access Token. + + See docs: https://github.com/Azure/acr/blob/main/docs/AAD-OAuth.md + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: |- + ACRAccessTokenSpec defines how to generate the access token + e.g. how to authenticate and which registry to use. + see: https://github.com/Azure/acr/blob/main/docs/AAD-OAuth.md#overview + properties: + auth: + properties: + managedIdentity: + description: ManagedIdentity uses Azure Managed Identity to authenticate with Azure. + properties: + identityId: + description: If multiple Managed Identity is assigned to the pod, you can select the one to be used + type: string + type: object + servicePrincipal: + description: ServicePrincipal uses Azure Service Principal credentials to authenticate with Azure. + properties: + secretRef: + description: |- + Configuration used to authenticate with Azure using static + credentials stored in a Kind=Secret. + properties: + clientId: + description: The Azure clientId of the service principle used for authentication. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + clientSecret: + description: The Azure ClientSecret of the service principle used for authentication. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + required: + - secretRef + type: object + workloadIdentity: + description: WorkloadIdentity uses Azure Workload Identity to authenticate with Azure. + properties: + serviceAccountRef: + description: |- + ServiceAccountRef specified the service account + that should be used when authenticating with WorkloadIdentity. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + type: object + type: object + environmentType: + default: PublicCloud + description: |- + EnvironmentType specifies the Azure cloud environment endpoints to use for + connecting and authenticating with Azure. By default it points to the public cloud AAD endpoint. + The following endpoints are available, also see here: https://github.com/Azure/go-autorest/blob/main/autorest/azure/environments.go#L152 + PublicCloud, USGovernmentCloud, ChinaCloud, GermanCloud + enum: + - PublicCloud + - USGovernmentCloud + - ChinaCloud + - GermanCloud + type: string + registry: + description: |- + the domain name of the ACR registry + e.g. foobarexample.azurecr.io + type: string + scope: + description: |- + Define the scope for the access token, e.g. pull/push access for a repository. + if not provided it will return a refresh token that has full scope. + Note: you need to pin it down to the repository level, there is no wildcard available. + + examples: + repository:my-repository:pull,push + repository:my-repository:pull + + see docs for details: https://docs.docker.com/registry/spec/auth/scope/ + type: string + tenantId: + description: TenantID configures the Azure Tenant to send requests to. Required for ServicePrincipal auth type. + type: string + required: + - auth + - registry + type: object + type: object + served: true + storage: true + subresources: + status: {} + conversion: + strategy: Webhook + webhook: + conversionReviewVersions: + - v1 + clientConfig: + service: + name: kubernetes + namespace: default + path: /convert +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.17.2 + labels: + external-secrets.io/component: controller + name: clustergenerators.generators.external-secrets.io +spec: + group: generators.external-secrets.io + names: + categories: + - external-secrets + - external-secrets-generators + kind: ClusterGenerator + listKind: ClusterGeneratorList + plural: clustergenerators + singular: clustergenerator + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: ClusterGenerator represents a cluster-wide generator which can be referenced as part of `generatorRef` fields. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + generator: + description: Generator the spec for this generator, must match the kind. + maxProperties: 1 + minProperties: 1 + properties: + acrAccessTokenSpec: + description: |- + ACRAccessTokenSpec defines how to generate the access token + e.g. how to authenticate and which registry to use. + see: https://github.com/Azure/acr/blob/main/docs/AAD-OAuth.md#overview + properties: + auth: + properties: + managedIdentity: + description: ManagedIdentity uses Azure Managed Identity to authenticate with Azure. + properties: + identityId: + description: If multiple Managed Identity is assigned to the pod, you can select the one to be used + type: string + type: object + servicePrincipal: + description: ServicePrincipal uses Azure Service Principal credentials to authenticate with Azure. + properties: + secretRef: + description: |- + Configuration used to authenticate with Azure using static + credentials stored in a Kind=Secret. + properties: + clientId: + description: The Azure clientId of the service principle used for authentication. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + clientSecret: + description: The Azure ClientSecret of the service principle used for authentication. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + required: + - secretRef + type: object + workloadIdentity: + description: WorkloadIdentity uses Azure Workload Identity to authenticate with Azure. + properties: + serviceAccountRef: + description: |- + ServiceAccountRef specified the service account + that should be used when authenticating with WorkloadIdentity. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + type: object + type: object + environmentType: + default: PublicCloud + description: |- + EnvironmentType specifies the Azure cloud environment endpoints to use for + connecting and authenticating with Azure. By default it points to the public cloud AAD endpoint. + The following endpoints are available, also see here: https://github.com/Azure/go-autorest/blob/main/autorest/azure/environments.go#L152 + PublicCloud, USGovernmentCloud, ChinaCloud, GermanCloud + enum: + - PublicCloud + - USGovernmentCloud + - ChinaCloud + - GermanCloud + type: string + registry: + description: |- + the domain name of the ACR registry + e.g. foobarexample.azurecr.io + type: string + scope: + description: |- + Define the scope for the access token, e.g. pull/push access for a repository. + if not provided it will return a refresh token that has full scope. + Note: you need to pin it down to the repository level, there is no wildcard available. + + examples: + repository:my-repository:pull,push + repository:my-repository:pull + + see docs for details: https://docs.docker.com/registry/spec/auth/scope/ + type: string + tenantId: + description: TenantID configures the Azure Tenant to send requests to. Required for ServicePrincipal auth type. + type: string + required: + - auth + - registry + type: object + ecrAuthorizationTokenSpec: + properties: + auth: + description: Auth defines how to authenticate with AWS + properties: + jwt: + description: Authenticate against AWS using service account tokens. + properties: + serviceAccountRef: + description: A reference to a ServiceAccount resource. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + type: object + secretRef: + description: |- + AWSAuthSecretRef holds secret references for AWS credentials + both AccessKeyID and SecretAccessKey must be defined in order to properly authenticate. + properties: + accessKeyIDSecretRef: + description: The AccessKeyID is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + secretAccessKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + sessionTokenSecretRef: + description: |- + The SessionToken used for authentication + This must be defined if AccessKeyID and SecretAccessKey are temporary credentials + see: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_use-resources.html + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + type: object + region: + description: Region specifies the region to operate in. + type: string + role: + description: |- + You can assume a role before making calls to the + desired AWS service. + type: string + scope: + description: |- + Scope specifies the ECR service scope. + Valid options are private and public. + type: string + required: + - region + type: object + fakeSpec: + description: FakeSpec contains the static data. + properties: + controller: + description: |- + Used to select the correct ESO controller (think: ingress.ingressClassName) + The ESO controller is instantiated with a specific controller name and filters VDS based on this property + type: string + data: + additionalProperties: + type: string + description: |- + Data defines the static data returned + by this generator. + type: object + type: object + gcrAccessTokenSpec: + properties: + auth: + description: Auth defines the means for authenticating with GCP + properties: + secretRef: + properties: + secretAccessKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + workloadIdentity: + properties: + clusterLocation: + type: string + clusterName: + type: string + clusterProjectID: + type: string + serviceAccountRef: + description: A reference to a ServiceAccount resource. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + required: + - clusterLocation + - clusterName + - serviceAccountRef + type: object + type: object + projectID: + description: ProjectID defines which project to use to authenticate with + type: string + required: + - auth + - projectID + type: object + githubAccessTokenSpec: + properties: + appID: + type: string + auth: + description: Auth configures how ESO authenticates with a Github instance. + properties: + privateKey: + properties: + secretRef: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - secretRef + type: object + required: + - privateKey + type: object + installID: + type: string + permissions: + additionalProperties: + type: string + description: Map of permissions the token will have. If omitted, defaults to all permissions the GitHub App has. + type: object + repositories: + description: |- + List of repositories the token will have access to. If omitted, defaults to all repositories the GitHub App + is installed to. + items: + type: string + type: array + url: + description: URL configures the Github instance URL. Defaults to https://github.com/. + type: string + required: + - appID + - auth + - installID + type: object + grafanaSpec: + description: GrafanaSpec controls the behavior of the grafana generator. + properties: + auth: + description: |- + Auth is the authentication configuration to authenticate + against the Grafana instance. + properties: + token: + description: |- + A service account token used to authenticate against the Grafana instance. + Note: you need a token which has elevated permissions to create service accounts. + See here for the documentation on basic roles offered by Grafana: + https://grafana.com/docs/grafana/latest/administration/roles-and-permissions/access-control/rbac-fixed-basic-role-definitions/ + properties: + key: + description: The key where the token is found. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + type: object + required: + - token + type: object + serviceAccount: + description: |- + ServiceAccount is the configuration for the service account that + is supposed to be generated by the generator. + properties: + name: + description: Name is the name of the service account that will be created by ESO. + type: string + role: + description: |- + Role is the role of the service account. + See here for the documentation on basic roles offered by Grafana: + https://grafana.com/docs/grafana/latest/administration/roles-and-permissions/access-control/rbac-fixed-basic-role-definitions/ + type: string + required: + - name + - role + type: object + url: + description: URL is the URL of the Grafana instance. + type: string + required: + - auth + - serviceAccount + - url + type: object + passwordSpec: + description: PasswordSpec controls the behavior of the password generator. + properties: + allowRepeat: + default: false + description: set AllowRepeat to true to allow repeating characters. + type: boolean + digits: + description: |- + Digits specifies the number of digits in the generated + password. If omitted it defaults to 25% of the length of the password + type: integer + length: + default: 24 + description: |- + Length of the password to be generated. + Defaults to 24 + type: integer + noUpper: + default: false + description: Set NoUpper to disable uppercase characters + type: boolean + symbolCharacters: + description: |- + SymbolCharacters specifies the special characters that should be used + in the generated password. + type: string + symbols: + description: |- + Symbols specifies the number of symbol characters in the generated + password. If omitted it defaults to 25% of the length of the password + type: integer + required: + - allowRepeat + - length + - noUpper + type: object + quayAccessTokenSpec: + properties: + robotAccount: + description: Name of the robot account you are federating with + type: string + serviceAccountRef: + description: Name of the service account you are federating with + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + url: + description: URL configures the Quay instance URL. Defaults to quay.io. + type: string + required: + - robotAccount + - serviceAccountRef + type: object + stsSessionTokenSpec: + properties: + auth: + description: Auth defines how to authenticate with AWS + properties: + jwt: + description: Authenticate against AWS using service account tokens. + properties: + serviceAccountRef: + description: A reference to a ServiceAccount resource. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + type: object + secretRef: + description: |- + AWSAuthSecretRef holds secret references for AWS credentials + both AccessKeyID and SecretAccessKey must be defined in order to properly authenticate. + properties: + accessKeyIDSecretRef: + description: The AccessKeyID is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + secretAccessKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + sessionTokenSecretRef: + description: |- + The SessionToken used for authentication + This must be defined if AccessKeyID and SecretAccessKey are temporary credentials + see: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_use-resources.html + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + type: object + region: + description: Region specifies the region to operate in. + type: string + requestParameters: + description: RequestParameters contains parameters that can be passed to the STS service. + properties: + serialNumber: + description: |- + SerialNumber is the identification number of the MFA device that is associated with the IAM user who is making + the GetSessionToken call. + Possible values: hardware device (such as GAHT12345678) or an Amazon Resource Name (ARN) for a virtual device + (such as arn:aws:iam::123456789012:mfa/user) + type: string + sessionDuration: + description: |- + SessionDuration The duration, in seconds, that the credentials should remain valid. Acceptable durations for + IAM user sessions range from 900 seconds (15 minutes) to 129,600 seconds (36 hours), with 43,200 seconds + (12 hours) as the default. + format: int64 + type: integer + tokenCode: + description: TokenCode is the value provided by the MFA device, if MFA is required. + type: string + type: object + role: + description: |- + You can assume a role before making calls to the + desired AWS service. + type: string + required: + - region + type: object + uuidSpec: + description: UUIDSpec controls the behavior of the uuid generator. + type: object + vaultDynamicSecretSpec: + properties: + allowEmptyResponse: + default: false + description: Do not fail if no secrets are found. Useful for requests where no data is expected. + type: boolean + controller: + description: |- + Used to select the correct ESO controller (think: ingress.ingressClassName) + The ESO controller is instantiated with a specific controller name and filters VDS based on this property + type: string + method: + description: Vault API method to use (GET/POST/other) + type: string + parameters: + description: Parameters to pass to Vault write (for non-GET methods) + x-kubernetes-preserve-unknown-fields: true + path: + description: Vault path to obtain the dynamic secret from + type: string + provider: + description: Vault provider common spec + properties: + auth: + description: Auth configures how secret-manager authenticates with the Vault server. + properties: + appRole: + description: |- + AppRole authenticates with Vault using the App Role auth mechanism, + with the role and secret stored in a Kubernetes Secret resource. + properties: + path: + default: approle + description: |- + Path where the App Role authentication backend is mounted + in Vault, e.g: "approle" + type: string + roleId: + description: |- + RoleID configured in the App Role authentication backend when setting + up the authentication backend in Vault. + type: string + roleRef: + description: |- + Reference to a key in a Secret that contains the App Role ID used + to authenticate with Vault. + The `key` field must be specified and denotes which entry within the Secret + resource is used as the app role id. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + secretRef: + description: |- + Reference to a key in a Secret that contains the App Role secret used + to authenticate with Vault. + The `key` field must be specified and denotes which entry within the Secret + resource is used as the app role secret. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - path + - secretRef + type: object + cert: + description: |- + Cert authenticates with TLS Certificates by passing client certificate, private key and ca certificate + Cert authentication method + properties: + clientCert: + description: |- + ClientCert is a certificate to authenticate using the Cert Vault + authentication method + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + secretRef: + description: |- + SecretRef to a key in a Secret resource containing client private key to + authenticate with Vault using the Cert authentication method + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + iam: + description: |- + Iam authenticates with vault by passing a special AWS request signed with AWS IAM credentials + AWS IAM authentication method + properties: + externalID: + description: AWS External ID set on assumed IAM roles + type: string + jwt: + description: Specify a service account with IRSA enabled + properties: + serviceAccountRef: + description: A reference to a ServiceAccount resource. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + type: object + path: + description: 'Path where the AWS auth method is enabled in Vault, e.g: "aws"' + type: string + region: + description: AWS region + type: string + role: + description: This is the AWS role to be assumed before talking to vault + type: string + secretRef: + description: Specify credentials in a Secret object + properties: + accessKeyIDSecretRef: + description: The AccessKeyID is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + secretAccessKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + sessionTokenSecretRef: + description: |- + The SessionToken used for authentication + This must be defined if AccessKeyID and SecretAccessKey are temporary credentials + see: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_use-resources.html + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + vaultAwsIamServerID: + description: 'X-Vault-AWS-IAM-Server-ID is an additional header used by Vault IAM auth method to mitigate against different types of replay attacks. More details here: https://developer.hashicorp.com/vault/docs/auth/aws' + type: string + vaultRole: + description: Vault Role. In vault, a role describes an identity with a set of permissions, groups, or policies you want to attach a user of the secrets engine + type: string + required: + - vaultRole + type: object + jwt: + description: |- + Jwt authenticates with Vault by passing role and JWT token using the + JWT/OIDC authentication method + properties: + kubernetesServiceAccountToken: + description: |- + Optional ServiceAccountToken specifies the Kubernetes service account for which to request + a token for with the `TokenRequest` API. + properties: + audiences: + description: |- + Optional audiences field that will be used to request a temporary Kubernetes service + account token for the service account referenced by `serviceAccountRef`. + Defaults to a single audience `vault` it not specified. + Deprecated: use serviceAccountRef.Audiences instead + items: + type: string + type: array + expirationSeconds: + description: |- + Optional expiration time in seconds that will be used to request a temporary + Kubernetes service account token for the service account referenced by + `serviceAccountRef`. + Deprecated: this will be removed in the future. + Defaults to 10 minutes. + format: int64 + type: integer + serviceAccountRef: + description: Service account field containing the name of a kubernetes ServiceAccount. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + required: + - serviceAccountRef + type: object + path: + default: jwt + description: |- + Path where the JWT authentication backend is mounted + in Vault, e.g: "jwt" + type: string + role: + description: |- + Role is a JWT role to authenticate using the JWT/OIDC Vault + authentication method + type: string + secretRef: + description: |- + Optional SecretRef that refers to a key in a Secret resource containing JWT token to + authenticate with Vault using the JWT/OIDC authentication method. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - path + type: object + kubernetes: + description: |- + Kubernetes authenticates with Vault by passing the ServiceAccount + token stored in the named Secret resource to the Vault server. + properties: + mountPath: + default: kubernetes + description: |- + Path where the Kubernetes authentication backend is mounted in Vault, e.g: + "kubernetes" + type: string + role: + description: |- + A required field containing the Vault Role to assume. A Role binds a + Kubernetes ServiceAccount with a set of Vault policies. + type: string + secretRef: + description: |- + Optional secret field containing a Kubernetes ServiceAccount JWT used + for authenticating with Vault. If a name is specified without a key, + `token` is the default. If one is not specified, the one bound to + the controller will be used. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + serviceAccountRef: + description: |- + Optional service account field containing the name of a kubernetes ServiceAccount. + If the service account is specified, the service account secret token JWT will be used + for authenticating with Vault. If the service account selector is not supplied, + the secretRef will be used instead. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + required: + - mountPath + - role + type: object + ldap: + description: |- + Ldap authenticates with Vault by passing username/password pair using + the LDAP authentication method + properties: + path: + default: ldap + description: |- + Path where the LDAP authentication backend is mounted + in Vault, e.g: "ldap" + type: string + secretRef: + description: |- + SecretRef to a key in a Secret resource containing password for the LDAP + user used to authenticate with Vault using the LDAP authentication + method + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + username: + description: |- + Username is an LDAP username used to authenticate using the LDAP Vault + authentication method + type: string + required: + - path + - username + type: object + namespace: + description: |- + Name of the vault namespace to authenticate to. This can be different than the namespace your secret is in. + Namespaces is a set of features within Vault Enterprise that allows + Vault environments to support Secure Multi-tenancy. e.g: "ns1". + More about namespaces can be found here https://www.vaultproject.io/docs/enterprise/namespaces + This will default to Vault.Namespace field if set, or empty otherwise + type: string + tokenSecretRef: + description: TokenSecretRef authenticates with Vault by presenting a token. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + userPass: + description: UserPass authenticates with Vault by passing username/password pair + properties: + path: + default: userpass + description: |- + Path where the UserPassword authentication backend is mounted + in Vault, e.g: "userpass" + type: string + secretRef: + description: |- + SecretRef to a key in a Secret resource containing password for the + user used to authenticate with Vault using the UserPass authentication + method + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + username: + description: |- + Username is a username used to authenticate using the UserPass Vault + authentication method + type: string + required: + - path + - username + type: object + type: object + caBundle: + description: |- + PEM encoded CA bundle used to validate Vault server certificate. Only used + if the Server URL is using HTTPS protocol. This parameter is ignored for + plain HTTP protocol connection. If not set the system root certificates + are used to validate the TLS connection. + format: byte + type: string + caProvider: + description: The provider for the CA bundle to use to validate Vault server certificate. + properties: + key: + description: The key where the CA certificate can be found in the Secret or ConfigMap. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the object located at the provider type. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace the Provider type is in. + Can only be defined when used in a ClusterSecretStore. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + forwardInconsistent: + description: |- + ForwardInconsistent tells Vault to forward read-after-write requests to the Vault + leader instead of simply retrying within a loop. This can increase performance if + the option is enabled serverside. + https://www.vaultproject.io/docs/configuration/replication#allow_forwarding_via_header + type: boolean + headers: + additionalProperties: + type: string + description: Headers to be added in Vault request + type: object + namespace: + description: |- + Name of the vault namespace. Namespaces is a set of features within Vault Enterprise that allows + Vault environments to support Secure Multi-tenancy. e.g: "ns1". + More about namespaces can be found here https://www.vaultproject.io/docs/enterprise/namespaces + type: string + path: + description: |- + Path is the mount path of the Vault KV backend endpoint, e.g: + "secret". The v2 KV secret engine version specific "/data" path suffix + for fetching secrets from Vault is optional and will be appended + if not present in specified path. + type: string + readYourWrites: + description: |- + ReadYourWrites ensures isolated read-after-write semantics by + providing discovered cluster replication states in each request. + More information about eventual consistency in Vault can be found here + https://www.vaultproject.io/docs/enterprise/consistency + type: boolean + server: + description: 'Server is the connection address for the Vault server, e.g: "https://vault.example.com:8200".' + type: string + tls: + description: |- + The configuration used for client side related TLS communication, when the Vault server + requires mutual authentication. Only used if the Server URL is using HTTPS protocol. + This parameter is ignored for plain HTTP protocol connection. + It's worth noting this configuration is different from the "TLS certificates auth method", + which is available under the `auth.cert` section. + properties: + certSecretRef: + description: |- + CertSecretRef is a certificate added to the transport layer + when communicating with the Vault server. + If no key for the Secret is specified, external-secret will default to 'tls.crt'. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + keySecretRef: + description: |- + KeySecretRef to a key in a Secret resource containing client private key + added to the transport layer when communicating with the Vault server. + If no key for the Secret is specified, external-secret will default to 'tls.key'. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + version: + default: v2 + description: |- + Version is the Vault KV secret engine version. This can be either "v1" or + "v2". Version defaults to "v2". + enum: + - v1 + - v2 + type: string + required: + - server + type: object + resultType: + default: Data + description: |- + Result type defines which data is returned from the generator. + By default it is the "data" section of the Vault API response. + When using e.g. /auth/token/create the "data" section is empty but + the "auth" section contains the generated token. + Please refer to the vault docs regarding the result data structure. + Additionally, accessing the raw response is possibly by using "Raw" result type. + enum: + - Data + - Auth + - Raw + type: string + retrySettings: + description: Used to configure http retries if failed + properties: + maxRetries: + format: int32 + type: integer + retryInterval: + type: string + type: object + required: + - path + - provider + type: object + webhookSpec: + description: WebhookSpec controls the behavior of the external generator. Any body parameters should be passed to the server through the parameters field. + properties: + body: + description: Body + type: string + caBundle: + description: |- + PEM encoded CA bundle used to validate webhook server certificate. Only used + if the Server URL is using HTTPS protocol. This parameter is ignored for + plain HTTP protocol connection. If not set the system root certificates + are used to validate the TLS connection. + format: byte + type: string + caProvider: + description: The provider for the CA bundle to use to validate webhook server certificate. + properties: + key: + description: The key where the CA certificate can be found in the Secret or ConfigMap. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the object located at the provider type. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: The namespace the Provider type is in. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + headers: + additionalProperties: + type: string + description: Headers + type: object + method: + description: Webhook Method + type: string + result: + description: Result formatting + properties: + jsonPath: + description: Json path of return value + type: string + type: object + secrets: + description: |- + Secrets to fill in templates + These secrets will be passed to the templating function as key value pairs under the given name + items: + properties: + name: + description: Name of this secret in templates + type: string + secretRef: + description: Secret ref to fill in credentials + properties: + key: + description: The key where the token is found. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + type: object + required: + - name + - secretRef + type: object + type: array + timeout: + description: Timeout + type: string + url: + description: Webhook url to call + type: string + required: + - result + - url + type: object + type: object + kind: + description: Kind the kind of this generator. + enum: + - ACRAccessToken + - ECRAuthorizationToken + - Fake + - GCRAccessToken + - GithubAccessToken + - QuayAccessToken + - Password + - STSSessionToken + - UUID + - VaultDynamicSecret + - Webhook + - Grafana + type: string + required: + - generator + - kind + type: object + type: object + served: true + storage: true + subresources: + status: {} + conversion: + strategy: Webhook + webhook: + conversionReviewVersions: + - v1 + clientConfig: + service: + name: kubernetes + namespace: default + path: /convert +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.17.2 + labels: + external-secrets.io/component: controller + name: ecrauthorizationtokens.generators.external-secrets.io +spec: + group: generators.external-secrets.io + names: + categories: + - external-secrets + - external-secrets-generators + kind: ECRAuthorizationToken + listKind: ECRAuthorizationTokenList + plural: ecrauthorizationtokens + singular: ecrauthorizationtoken + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + ECRAuthorizationTokenSpec uses the GetAuthorizationToken API to retrieve an + authorization token. + The authorization token is valid for 12 hours. + The authorizationToken returned is a base64 encoded string that can be decoded + and used in a docker login command to authenticate to a registry. + For more information, see Registry authentication (https://docs.aws.amazon.com/AmazonECR/latest/userguide/Registries.html#registry_auth) in the Amazon Elastic Container Registry User Guide. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + auth: + description: Auth defines how to authenticate with AWS + properties: + jwt: + description: Authenticate against AWS using service account tokens. + properties: + serviceAccountRef: + description: A reference to a ServiceAccount resource. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + type: object + secretRef: + description: |- + AWSAuthSecretRef holds secret references for AWS credentials + both AccessKeyID and SecretAccessKey must be defined in order to properly authenticate. + properties: + accessKeyIDSecretRef: + description: The AccessKeyID is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + secretAccessKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + sessionTokenSecretRef: + description: |- + The SessionToken used for authentication + This must be defined if AccessKeyID and SecretAccessKey are temporary credentials + see: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_use-resources.html + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + type: object + region: + description: Region specifies the region to operate in. + type: string + role: + description: |- + You can assume a role before making calls to the + desired AWS service. + type: string + scope: + description: |- + Scope specifies the ECR service scope. + Valid options are private and public. + type: string + required: + - region + type: object + type: object + served: true + storage: true + subresources: + status: {} + conversion: + strategy: Webhook + webhook: + conversionReviewVersions: + - v1 + clientConfig: + service: + name: kubernetes + namespace: default + path: /convert +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.17.2 + labels: + external-secrets.io/component: controller + name: fakes.generators.external-secrets.io +spec: + group: generators.external-secrets.io + names: + categories: + - external-secrets + - external-secrets-generators + kind: Fake + listKind: FakeList + plural: fakes + singular: fake + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + Fake generator is used for testing. It lets you define + a static set of credentials that is always returned. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: FakeSpec contains the static data. + properties: + controller: + description: |- + Used to select the correct ESO controller (think: ingress.ingressClassName) + The ESO controller is instantiated with a specific controller name and filters VDS based on this property + type: string + data: + additionalProperties: + type: string + description: |- + Data defines the static data returned + by this generator. + type: object + type: object + type: object + served: true + storage: true + subresources: + status: {} + conversion: + strategy: Webhook + webhook: + conversionReviewVersions: + - v1 + clientConfig: + service: + name: kubernetes + namespace: default + path: /convert +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.17.2 + labels: + external-secrets.io/component: controller + name: gcraccesstokens.generators.external-secrets.io +spec: + group: generators.external-secrets.io + names: + categories: + - external-secrets + - external-secrets-generators + kind: GCRAccessToken + listKind: GCRAccessTokenList + plural: gcraccesstokens + singular: gcraccesstoken + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + GCRAccessToken generates an GCP access token + that can be used to authenticate with GCR. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + auth: + description: Auth defines the means for authenticating with GCP + properties: + secretRef: + properties: + secretAccessKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + workloadIdentity: + properties: + clusterLocation: + type: string + clusterName: + type: string + clusterProjectID: + type: string + serviceAccountRef: + description: A reference to a ServiceAccount resource. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + required: + - clusterLocation + - clusterName + - serviceAccountRef + type: object + type: object + projectID: + description: ProjectID defines which project to use to authenticate with + type: string + required: + - auth + - projectID + type: object + type: object + served: true + storage: true + subresources: + status: {} + conversion: + strategy: Webhook + webhook: + conversionReviewVersions: + - v1 + clientConfig: + service: + name: kubernetes + namespace: default + path: /convert +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.17.2 + labels: + external-secrets.io/component: controller + name: generatorstates.generators.external-secrets.io +spec: + group: generators.external-secrets.io + names: + categories: + - external-secrets + - external-secrets-generators + kind: GeneratorState + listKind: GeneratorStateList + plural: generatorstates + shortNames: + - gs + singular: generatorstate + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.garbageCollectionDeadline + name: GC Deadline + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + garbageCollectionDeadline: + description: |- + GarbageCollectionDeadline is the time after which the generator state + will be deleted. + It is set by the controller which creates the generator state and + can be set configured by the user. + If the garbage collection deadline is not set the generator state will not be deleted. + format: date-time + type: string + resource: + description: |- + Resource is the generator manifest that produced the state. + It is a snapshot of the generator manifest at the time the state was produced. + This manifest will be used to delete the resource. Any configuration that is referenced + in the manifest should be available at the time of garbage collection. If that is not the case deletion will + be blocked by a finalizer. + x-kubernetes-preserve-unknown-fields: true + state: + description: State is the state that was produced by the generator implementation. + x-kubernetes-preserve-unknown-fields: true + required: + - resource + - state + type: object + status: + properties: + conditions: + items: + properties: + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: {} + conversion: + strategy: Webhook + webhook: + conversionReviewVersions: + - v1 + clientConfig: + service: + name: kubernetes + namespace: default + path: /convert +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.17.2 + labels: + external-secrets.io/component: controller + name: githubaccesstokens.generators.external-secrets.io +spec: + group: generators.external-secrets.io + names: + categories: + - external-secrets + - external-secrets-generators + kind: GithubAccessToken + listKind: GithubAccessTokenList + plural: githubaccesstokens + singular: githubaccesstoken + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: GithubAccessToken generates ghs_ accessToken + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + appID: + type: string + auth: + description: Auth configures how ESO authenticates with a Github instance. + properties: + privateKey: + properties: + secretRef: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - secretRef + type: object + required: + - privateKey + type: object + installID: + type: string + permissions: + additionalProperties: + type: string + description: Map of permissions the token will have. If omitted, defaults to all permissions the GitHub App has. + type: object + repositories: + description: |- + List of repositories the token will have access to. If omitted, defaults to all repositories the GitHub App + is installed to. + items: + type: string + type: array + url: + description: URL configures the Github instance URL. Defaults to https://github.com/. + type: string + required: + - appID + - auth + - installID + type: object + type: object + served: true + storage: true + subresources: + status: {} + conversion: + strategy: Webhook + webhook: + conversionReviewVersions: + - v1 + clientConfig: + service: + name: kubernetes + namespace: default + path: /convert +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.17.2 + labels: + external-secrets.io/component: controller + name: grafanas.generators.external-secrets.io +spec: + group: generators.external-secrets.io + names: + categories: + - external-secrets + - external-secrets-generators + kind: Grafana + listKind: GrafanaList + plural: grafanas + singular: grafana + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: GrafanaSpec controls the behavior of the grafana generator. + properties: + auth: + description: |- + Auth is the authentication configuration to authenticate + against the Grafana instance. + properties: + token: + description: |- + A service account token used to authenticate against the Grafana instance. + Note: you need a token which has elevated permissions to create service accounts. + See here for the documentation on basic roles offered by Grafana: + https://grafana.com/docs/grafana/latest/administration/roles-and-permissions/access-control/rbac-fixed-basic-role-definitions/ + properties: + key: + description: The key where the token is found. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + type: object + required: + - token + type: object + serviceAccount: + description: |- + ServiceAccount is the configuration for the service account that + is supposed to be generated by the generator. + properties: + name: + description: Name is the name of the service account that will be created by ESO. + type: string + role: + description: |- + Role is the role of the service account. + See here for the documentation on basic roles offered by Grafana: + https://grafana.com/docs/grafana/latest/administration/roles-and-permissions/access-control/rbac-fixed-basic-role-definitions/ + type: string + required: + - name + - role + type: object + url: + description: URL is the URL of the Grafana instance. + type: string + required: + - auth + - serviceAccount + - url + type: object + type: object + served: true + storage: true + subresources: + status: {} + conversion: + strategy: Webhook + webhook: + conversionReviewVersions: + - v1 + clientConfig: + service: + name: kubernetes + namespace: default + path: /convert +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.17.2 + labels: + external-secrets.io/component: controller + name: passwords.generators.external-secrets.io +spec: + group: generators.external-secrets.io + names: + categories: + - external-secrets + - external-secrets-generators + kind: Password + listKind: PasswordList + plural: passwords + singular: password + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + Password generates a random password based on the + configuration parameters in spec. + You can specify the length, characterset and other attributes. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: PasswordSpec controls the behavior of the password generator. + properties: + allowRepeat: + default: false + description: set AllowRepeat to true to allow repeating characters. + type: boolean + digits: + description: |- + Digits specifies the number of digits in the generated + password. If omitted it defaults to 25% of the length of the password + type: integer + length: + default: 24 + description: |- + Length of the password to be generated. + Defaults to 24 + type: integer + noUpper: + default: false + description: Set NoUpper to disable uppercase characters + type: boolean + symbolCharacters: + description: |- + SymbolCharacters specifies the special characters that should be used + in the generated password. + type: string + symbols: + description: |- + Symbols specifies the number of symbol characters in the generated + password. If omitted it defaults to 25% of the length of the password + type: integer + required: + - allowRepeat + - length + - noUpper + type: object + type: object + served: true + storage: true + subresources: + status: {} + conversion: + strategy: Webhook + webhook: + conversionReviewVersions: + - v1 + clientConfig: + service: + name: kubernetes + namespace: default + path: /convert +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.17.2 + labels: + external-secrets.io/component: controller + name: quayaccesstokens.generators.external-secrets.io +spec: + group: generators.external-secrets.io + names: + categories: + - external-secrets + - external-secrets-generators + kind: QuayAccessToken + listKind: QuayAccessTokenList + plural: quayaccesstokens + singular: quayaccesstoken + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: QuayAccessToken generates Quay oauth token for pulling/pushing images + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + robotAccount: + description: Name of the robot account you are federating with + type: string + serviceAccountRef: + description: Name of the service account you are federating with + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + url: + description: URL configures the Quay instance URL. Defaults to quay.io. + type: string + required: + - robotAccount + - serviceAccountRef + type: object + type: object + served: true + storage: true + subresources: + status: {} + conversion: + strategy: Webhook + webhook: + conversionReviewVersions: + - v1 + clientConfig: + service: + name: kubernetes + namespace: default + path: /convert +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.17.2 + labels: + external-secrets.io/component: controller + name: stssessiontokens.generators.external-secrets.io +spec: + group: generators.external-secrets.io + names: + categories: + - external-secrets + - external-secrets-generators + kind: STSSessionToken + listKind: STSSessionTokenList + plural: stssessiontokens + singular: stssessiontoken + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + STSSessionToken uses the GetSessionToken API to retrieve an authorization token. + The authorization token is valid for 12 hours. + The authorizationToken returned is a base64 encoded string that can be decoded. + For more information, see GetSessionToken (https://docs.aws.amazon.com/STS/latest/APIReference/API_GetSessionToken.html). + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + auth: + description: Auth defines how to authenticate with AWS + properties: + jwt: + description: Authenticate against AWS using service account tokens. + properties: + serviceAccountRef: + description: A reference to a ServiceAccount resource. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + type: object + secretRef: + description: |- + AWSAuthSecretRef holds secret references for AWS credentials + both AccessKeyID and SecretAccessKey must be defined in order to properly authenticate. + properties: + accessKeyIDSecretRef: + description: The AccessKeyID is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + secretAccessKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + sessionTokenSecretRef: + description: |- + The SessionToken used for authentication + This must be defined if AccessKeyID and SecretAccessKey are temporary credentials + see: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_use-resources.html + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + type: object + region: + description: Region specifies the region to operate in. + type: string + requestParameters: + description: RequestParameters contains parameters that can be passed to the STS service. + properties: + serialNumber: + description: |- + SerialNumber is the identification number of the MFA device that is associated with the IAM user who is making + the GetSessionToken call. + Possible values: hardware device (such as GAHT12345678) or an Amazon Resource Name (ARN) for a virtual device + (such as arn:aws:iam::123456789012:mfa/user) + type: string + sessionDuration: + description: |- + SessionDuration The duration, in seconds, that the credentials should remain valid. Acceptable durations for + IAM user sessions range from 900 seconds (15 minutes) to 129,600 seconds (36 hours), with 43,200 seconds + (12 hours) as the default. + format: int64 + type: integer + tokenCode: + description: TokenCode is the value provided by the MFA device, if MFA is required. + type: string + type: object + role: + description: |- + You can assume a role before making calls to the + desired AWS service. + type: string + required: + - region + type: object + type: object + served: true + storage: true + subresources: + status: {} + conversion: + strategy: Webhook + webhook: + conversionReviewVersions: + - v1 + clientConfig: + service: + name: kubernetes + namespace: default + path: /convert +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.17.2 + labels: + external-secrets.io/component: controller + name: uuids.generators.external-secrets.io +spec: + group: generators.external-secrets.io + names: + categories: + - external-secrets + - external-secrets-generators + kind: UUID + listKind: UUIDList + plural: uuids + singular: uuid + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: UUID generates a version 1 UUID (e56657e3-764f-11ef-a397-65231a88c216). + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: UUIDSpec controls the behavior of the uuid generator. + type: object + type: object + served: true + storage: true + subresources: + status: {} + conversion: + strategy: Webhook + webhook: + conversionReviewVersions: + - v1 + clientConfig: + service: + name: kubernetes + namespace: default + path: /convert +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.17.2 + labels: + external-secrets.io/component: controller + name: vaultdynamicsecrets.generators.external-secrets.io +spec: + group: generators.external-secrets.io + names: + categories: + - external-secrets + - external-secrets-generators + kind: VaultDynamicSecret + listKind: VaultDynamicSecretList + plural: vaultdynamicsecrets + singular: vaultdynamicsecret + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + allowEmptyResponse: + default: false + description: Do not fail if no secrets are found. Useful for requests where no data is expected. + type: boolean + controller: + description: |- + Used to select the correct ESO controller (think: ingress.ingressClassName) + The ESO controller is instantiated with a specific controller name and filters VDS based on this property + type: string + method: + description: Vault API method to use (GET/POST/other) + type: string + parameters: + description: Parameters to pass to Vault write (for non-GET methods) + x-kubernetes-preserve-unknown-fields: true + path: + description: Vault path to obtain the dynamic secret from + type: string + provider: + description: Vault provider common spec + properties: + auth: + description: Auth configures how secret-manager authenticates with the Vault server. + properties: + appRole: + description: |- + AppRole authenticates with Vault using the App Role auth mechanism, + with the role and secret stored in a Kubernetes Secret resource. + properties: + path: + default: approle + description: |- + Path where the App Role authentication backend is mounted + in Vault, e.g: "approle" + type: string + roleId: + description: |- + RoleID configured in the App Role authentication backend when setting + up the authentication backend in Vault. + type: string + roleRef: + description: |- + Reference to a key in a Secret that contains the App Role ID used + to authenticate with Vault. + The `key` field must be specified and denotes which entry within the Secret + resource is used as the app role id. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + secretRef: + description: |- + Reference to a key in a Secret that contains the App Role secret used + to authenticate with Vault. + The `key` field must be specified and denotes which entry within the Secret + resource is used as the app role secret. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - path + - secretRef + type: object + cert: + description: |- + Cert authenticates with TLS Certificates by passing client certificate, private key and ca certificate + Cert authentication method + properties: + clientCert: + description: |- + ClientCert is a certificate to authenticate using the Cert Vault + authentication method + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + secretRef: + description: |- + SecretRef to a key in a Secret resource containing client private key to + authenticate with Vault using the Cert authentication method + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + iam: + description: |- + Iam authenticates with vault by passing a special AWS request signed with AWS IAM credentials + AWS IAM authentication method + properties: + externalID: + description: AWS External ID set on assumed IAM roles + type: string + jwt: + description: Specify a service account with IRSA enabled + properties: + serviceAccountRef: + description: A reference to a ServiceAccount resource. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + type: object + path: + description: 'Path where the AWS auth method is enabled in Vault, e.g: "aws"' + type: string + region: + description: AWS region + type: string + role: + description: This is the AWS role to be assumed before talking to vault + type: string + secretRef: + description: Specify credentials in a Secret object + properties: + accessKeyIDSecretRef: + description: The AccessKeyID is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + secretAccessKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + sessionTokenSecretRef: + description: |- + The SessionToken used for authentication + This must be defined if AccessKeyID and SecretAccessKey are temporary credentials + see: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_use-resources.html + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + vaultAwsIamServerID: + description: 'X-Vault-AWS-IAM-Server-ID is an additional header used by Vault IAM auth method to mitigate against different types of replay attacks. More details here: https://developer.hashicorp.com/vault/docs/auth/aws' + type: string + vaultRole: + description: Vault Role. In vault, a role describes an identity with a set of permissions, groups, or policies you want to attach a user of the secrets engine + type: string + required: + - vaultRole + type: object + jwt: + description: |- + Jwt authenticates with Vault by passing role and JWT token using the + JWT/OIDC authentication method + properties: + kubernetesServiceAccountToken: + description: |- + Optional ServiceAccountToken specifies the Kubernetes service account for which to request + a token for with the `TokenRequest` API. + properties: + audiences: + description: |- + Optional audiences field that will be used to request a temporary Kubernetes service + account token for the service account referenced by `serviceAccountRef`. + Defaults to a single audience `vault` it not specified. + Deprecated: use serviceAccountRef.Audiences instead + items: + type: string + type: array + expirationSeconds: + description: |- + Optional expiration time in seconds that will be used to request a temporary + Kubernetes service account token for the service account referenced by + `serviceAccountRef`. + Deprecated: this will be removed in the future. + Defaults to 10 minutes. + format: int64 + type: integer + serviceAccountRef: + description: Service account field containing the name of a kubernetes ServiceAccount. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + required: + - serviceAccountRef + type: object + path: + default: jwt + description: |- + Path where the JWT authentication backend is mounted + in Vault, e.g: "jwt" + type: string + role: + description: |- + Role is a JWT role to authenticate using the JWT/OIDC Vault + authentication method + type: string + secretRef: + description: |- + Optional SecretRef that refers to a key in a Secret resource containing JWT token to + authenticate with Vault using the JWT/OIDC authentication method. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + required: + - path + type: object + kubernetes: + description: |- + Kubernetes authenticates with Vault by passing the ServiceAccount + token stored in the named Secret resource to the Vault server. + properties: + mountPath: + default: kubernetes + description: |- + Path where the Kubernetes authentication backend is mounted in Vault, e.g: + "kubernetes" + type: string + role: + description: |- + A required field containing the Vault Role to assume. A Role binds a + Kubernetes ServiceAccount with a set of Vault policies. + type: string + secretRef: + description: |- + Optional secret field containing a Kubernetes ServiceAccount JWT used + for authenticating with Vault. If a name is specified without a key, + `token` is the default. If one is not specified, the one bound to + the controller will be used. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + serviceAccountRef: + description: |- + Optional service account field containing the name of a kubernetes ServiceAccount. + If the service account is specified, the service account secret token JWT will be used + for authenticating with Vault. If the service account selector is not supplied, + the secretRef will be used instead. + properties: + audiences: + description: |- + Audience specifies the `aud` claim for the service account token + If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity + then this audiences will be appended to the list + items: + type: string + type: array + name: + description: The name of the ServiceAccount resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + Namespace of the resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + required: + - mountPath + - role + type: object + ldap: + description: |- + Ldap authenticates with Vault by passing username/password pair using + the LDAP authentication method + properties: + path: + default: ldap + description: |- + Path where the LDAP authentication backend is mounted + in Vault, e.g: "ldap" + type: string + secretRef: + description: |- + SecretRef to a key in a Secret resource containing password for the LDAP + user used to authenticate with Vault using the LDAP authentication + method + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + username: + description: |- + Username is an LDAP username used to authenticate using the LDAP Vault + authentication method + type: string + required: + - path + - username + type: object + namespace: + description: |- + Name of the vault namespace to authenticate to. This can be different than the namespace your secret is in. + Namespaces is a set of features within Vault Enterprise that allows + Vault environments to support Secure Multi-tenancy. e.g: "ns1". + More about namespaces can be found here https://www.vaultproject.io/docs/enterprise/namespaces + This will default to Vault.Namespace field if set, or empty otherwise + type: string + tokenSecretRef: + description: TokenSecretRef authenticates with Vault by presenting a token. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + userPass: + description: UserPass authenticates with Vault by passing username/password pair + properties: + path: + default: userpass + description: |- + Path where the UserPassword authentication backend is mounted + in Vault, e.g: "userpass" + type: string + secretRef: + description: |- + SecretRef to a key in a Secret resource containing password for the + user used to authenticate with Vault using the UserPass authentication + method + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + username: + description: |- + Username is a username used to authenticate using the UserPass Vault + authentication method + type: string + required: + - path + - username + type: object + type: object + caBundle: + description: |- + PEM encoded CA bundle used to validate Vault server certificate. Only used + if the Server URL is using HTTPS protocol. This parameter is ignored for + plain HTTP protocol connection. If not set the system root certificates + are used to validate the TLS connection. + format: byte + type: string + caProvider: + description: The provider for the CA bundle to use to validate Vault server certificate. + properties: + key: + description: The key where the CA certificate can be found in the Secret or ConfigMap. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the object located at the provider type. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace the Provider type is in. + Can only be defined when used in a ClusterSecretStore. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + forwardInconsistent: + description: |- + ForwardInconsistent tells Vault to forward read-after-write requests to the Vault + leader instead of simply retrying within a loop. This can increase performance if + the option is enabled serverside. + https://www.vaultproject.io/docs/configuration/replication#allow_forwarding_via_header + type: boolean + headers: + additionalProperties: + type: string + description: Headers to be added in Vault request + type: object + namespace: + description: |- + Name of the vault namespace. Namespaces is a set of features within Vault Enterprise that allows + Vault environments to support Secure Multi-tenancy. e.g: "ns1". + More about namespaces can be found here https://www.vaultproject.io/docs/enterprise/namespaces + type: string + path: + description: |- + Path is the mount path of the Vault KV backend endpoint, e.g: + "secret". The v2 KV secret engine version specific "/data" path suffix + for fetching secrets from Vault is optional and will be appended + if not present in specified path. + type: string + readYourWrites: + description: |- + ReadYourWrites ensures isolated read-after-write semantics by + providing discovered cluster replication states in each request. + More information about eventual consistency in Vault can be found here + https://www.vaultproject.io/docs/enterprise/consistency + type: boolean + server: + description: 'Server is the connection address for the Vault server, e.g: "https://vault.example.com:8200".' + type: string + tls: + description: |- + The configuration used for client side related TLS communication, when the Vault server + requires mutual authentication. Only used if the Server URL is using HTTPS protocol. + This parameter is ignored for plain HTTP protocol connection. + It's worth noting this configuration is different from the "TLS certificates auth method", + which is available under the `auth.cert` section. + properties: + certSecretRef: + description: |- + CertSecretRef is a certificate added to the transport layer + when communicating with the Vault server. + If no key for the Secret is specified, external-secret will default to 'tls.crt'. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + keySecretRef: + description: |- + KeySecretRef to a key in a Secret resource containing client private key + added to the transport layer when communicating with the Vault server. + If no key for the Secret is specified, external-secret will default to 'tls.key'. + properties: + key: + description: |- + A key in the referenced Secret. + Some instances of this field may be defaulted, in others it may be required. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: |- + The namespace of the Secret resource being referred to. + Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: object + type: object + version: + default: v2 + description: |- + Version is the Vault KV secret engine version. This can be either "v1" or + "v2". Version defaults to "v2". + enum: + - v1 + - v2 + type: string + required: + - server + type: object + resultType: + default: Data + description: |- + Result type defines which data is returned from the generator. + By default it is the "data" section of the Vault API response. + When using e.g. /auth/token/create the "data" section is empty but + the "auth" section contains the generated token. + Please refer to the vault docs regarding the result data structure. + Additionally, accessing the raw response is possibly by using "Raw" result type. + enum: + - Data + - Auth + - Raw + type: string + retrySettings: + description: Used to configure http retries if failed + properties: + maxRetries: + format: int32 + type: integer + retryInterval: + type: string + type: object + required: + - path + - provider + type: object + type: object + served: true + storage: true + subresources: + status: {} + conversion: + strategy: Webhook + webhook: + conversionReviewVersions: + - v1 + clientConfig: + service: + name: kubernetes + namespace: default + path: /convert +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.17.2 + labels: + external-secrets.io/component: controller + name: webhooks.generators.external-secrets.io +spec: + group: generators.external-secrets.io + names: + categories: + - external-secrets + - external-secrets-generators + kind: Webhook + listKind: WebhookList + plural: webhooks + singular: webhook + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + Webhook connects to a third party API server to handle the secrets generation + configuration parameters in spec. + You can specify the server, the token, and additional body parameters. + See documentation for the full API specification for requests and responses. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: WebhookSpec controls the behavior of the external generator. Any body parameters should be passed to the server through the parameters field. + properties: + body: + description: Body + type: string + caBundle: + description: |- + PEM encoded CA bundle used to validate webhook server certificate. Only used + if the Server URL is using HTTPS protocol. This parameter is ignored for + plain HTTP protocol connection. If not set the system root certificates + are used to validate the TLS connection. + format: byte + type: string + caProvider: + description: The provider for the CA bundle to use to validate webhook server certificate. + properties: + key: + description: The key where the CA certificate can be found in the Secret or ConfigMap. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the object located at the provider type. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + description: The namespace the Provider type is in. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + headers: + additionalProperties: + type: string + description: Headers + type: object + method: + description: Webhook Method + type: string + result: + description: Result formatting + properties: + jsonPath: + description: Json path of return value + type: string + type: object + secrets: + description: |- + Secrets to fill in templates + These secrets will be passed to the templating function as key value pairs under the given name + items: + properties: + name: + description: Name of this secret in templates + type: string + secretRef: + description: Secret ref to fill in credentials + properties: + key: + description: The key where the token is found. + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ + type: string + name: + description: The name of the Secret resource being referred to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + type: object + required: + - name + - secretRef + type: object + type: array + timeout: + description: Timeout + type: string + url: + description: Webhook url to call + type: string + required: + - result + - url + type: object + type: object + served: true + storage: true + subresources: + status: {} + conversion: + strategy: Webhook + webhook: + conversionReviewVersions: + - v1 + clientConfig: + service: + name: kubernetes + namespace: default + path: /convert diff --git a/deployments/sequencer/resources/crds/shared_grafana10_dashboards_crd.yaml b/deployments/sequencer/resources/crds/shared_grafana10_dashboards_crd.yaml new file mode 100644 index 00000000000..646c0552025 --- /dev/null +++ b/deployments/sequencer/resources/crds/shared_grafana10_dashboards_crd.yaml @@ -0,0 +1,50 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: sharedgrafanadashboards.grafana.starkware.co +spec: + group: grafana.starkware.co + versions: + - name: v1beta1 + served: true + storage: true + additionalPrinterColumns: + - jsonPath: .status.apply.status + name: status + type: string + - jsonPath: .status.apply.grafana + name: grafana + type: string + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + required: + - dashboardName + - folderName + - dashboardJson + - CollectionName + properties: + dashboardName: + type: string + folderName: + type: string + dashboardJson: + type: string + CollectionName: + type: string + default: shared-grafana10-dashboards + status: + description: Status of the shared grafana dashboard CRD instance. This is set and managed automatically. + type: object + x-kubernetes-preserve-unknown-fields: true + scope: Namespaced + names: + plural: sharedgrafanadashboards + singular: sharedgrafanadashboard + kind: SharedGrafanaDashboard + shortNames: + - sgd + - sgds diff --git a/deployments/sequencer/services/config.py b/deployments/sequencer/services/config.py new file mode 100644 index 00000000000..1634122e181 --- /dev/null +++ b/deployments/sequencer/services/config.py @@ -0,0 +1,55 @@ +import json +import os +from typing import Dict, Any +from jsonschema import validate, ValidationError + + +class DeploymentConfig: + SCHEMA_FILE = "deployment_config_schema.json" + + def __init__(self, deployment_config_file: str): + self.deployment_config_file_path = deployment_config_file + self._deployment_config_data = self._read_deployment_config_file() + self._schema = self._load_schema() + self._validate_deployment_config() + + def _validate_deployment_config(self): + try: + validate(instance=self._deployment_config_data, schema=self._schema) + except ValidationError as e: + raise ValueError(f"Invalid deployment config file: {e.message}") + + def _load_schema(self): + with open(self.SCHEMA_FILE) as f: + return json.load(f) + + def _read_deployment_config_file(self): + with open(self.deployment_config_file_path) as f: + return json.loads(f.read()) + + def get_chain_id(self): + return self._deployment_config_data.get("chain_id") + + def get_image(self): + return self._deployment_config_data.get("image") + + def get_application_config_subdir(self): + return self._deployment_config_data.get("application_config_subdir") + + def get_services(self): + return [service for service in self._deployment_config_data.get("services", [])] + + +class SequencerConfig: + ROOT_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../../") + + def __init__(self, config_subdir: str, config_path: str): + self.config_subdir = os.path.join(self.ROOT_DIR, config_subdir) + self.config_path = os.path.join(self.config_subdir, config_path) + + def get_config(self) -> Dict[Any, Any]: + with open(self.config_path) as config_file: + return json.loads(config_file.read()) + + def validate(self): + pass diff --git a/deployments/sequencer/services/const.py b/deployments/sequencer/services/const.py index 34fb300965d..8056019d275 100644 --- a/deployments/sequencer/services/const.py +++ b/deployments/sequencer/services/const.py @@ -1,18 +1,29 @@ from enum import Enum + # k8s service types -class ServiceType(Enum): - CLUSTER_IP = "ClusterIP" - LOAD_BALANCER = "LoadBalancer" - NODE_PORT = "NodePort" +class ServiceType(str, Enum): + CLUSTER_IP = "ClusterIP" + LOAD_BALANCER = "LoadBalancer" + NODE_PORT = "NodePort" + +CONTAINER_ARGS = ["--config_file", "/config/sequencer/presets/config"] # k8s container ports HTTP_CONTAINER_PORT = 8080 RPC_CONTAINER_PORT = 8081 MONITORING_CONTAINER_PORT = 8082 -# k8s service ports -HTTP_SERVICE_PORT = 80 -RPC_SERVICE_PORT = 8081 -MONITORING_SERVICE_PORT = 8082 +PROBE_MONITORING_READY_PATH = "/monitoring/ready" +PROBE_MONITORING_ALIVE_PATH = "/monitoring/alive" +PROBE_FAILURE_THRESHOLD = 5 +PROBE_PERIOD_SECONDS = 10 +PROBE_TIMEOUT_SECONDS = 5 + +PVC_STORAGE_CLASS_NAME = "premium-rwo" +PVC_VOLUME_MODE = "Filesystem" +PVC_ACCESS_MODE = ["ReadWriteOnce"] + +HPA_MIN_REPLICAS = 1 +HPA_MAX_REPLICAS = 100 diff --git a/deployments/sequencer/services/helpers.py b/deployments/sequencer/services/helpers.py index 554f02d12ce..64e076400f7 100644 --- a/deployments/sequencer/services/helpers.py +++ b/deployments/sequencer/services/helpers.py @@ -4,24 +4,9 @@ def argument_parser(): parser = argparse.ArgumentParser() + parser.add_argument("--namespace", required=True, type=str, help="Kubernetes namespace.") parser.add_argument( - "--namespace", - required=True, - type=str, - help="Required: Specify the Kubernetes namespace." - ) - parser.add_argument( - "--config-file", - type=str, - help="Optional: Path to sequencer configuration file." - ) - parser.add_argument( - "--env", - default="dev", - type=str, - help="Optional: Specify the enironment (e.g., dev, prod)" + "--deployment-config-file", required=True, type=str, help="Path to deployment config file." ) return parser.parse_args() - -args = argument_parser() diff --git a/deployments/sequencer/services/monitoring.py b/deployments/sequencer/services/monitoring.py new file mode 100644 index 00000000000..7ff2237f9af --- /dev/null +++ b/deployments/sequencer/services/monitoring.py @@ -0,0 +1,15 @@ +import json +import os + + +class GrafanaDashboard: + ROOT_DIR = os.path.join( + os.path.dirname(os.path.abspath(__file__)), "../../../Monitoring/sequencer/" + ) + + def __init__(self, dashboard_file: str): + self.dashboard_path = os.path.join(self.ROOT_DIR, dashboard_file) + + def get(self): + with open(self.dashboard_path, "r") as f: + return json.load(f) diff --git a/deployments/sequencer/services/objects.py b/deployments/sequencer/services/objects.py deleted file mode 100644 index 597011a62c1..00000000000 --- a/deployments/sequencer/services/objects.py +++ /dev/null @@ -1,126 +0,0 @@ -import dataclasses -from typing import Optional, List, Dict, Any, Mapping, Sequence -from services import const - - -@dataclasses.dataclass -class Probe: - port: int | str - path: str - period_seconds: int - failure_threshold: int - timeout_seconds: int - - def __post_init__(self): - assert not isinstance(self.port, (bool)), \ - "Port must be of type int or str, not bool." - - -@dataclasses.dataclass -class PortMapping: - name: str - port: int - container_port: int - - -@dataclasses.dataclass -class Service: - type: Optional[const.ServiceType] - selector: Mapping[str, str] - ports: Sequence[PortMapping] - - -@dataclasses.dataclass -class PersistentVolumeClaim: - storage_class_name: str | None - access_modes: list[str] | None - volume_mode: str | None - storage: str | None - read_only: bool | None - mount_path: str | None - - -@dataclasses.dataclass -class Config: - schema: Dict[Any, Any] - config: Dict[Any, Any] - mount_path: str - - def get(self): - return self.config - - def validate(self): - pass - - -@dataclasses.dataclass -class IngressRuleHttpPath: - path: Optional[str] - path_type: str - backend_service_name: str - backend_service_port_number: int - backend_service_port_name: Optional[str] = None - - -@dataclasses.dataclass -class IngressRule: - host: str - paths: Sequence[IngressRuleHttpPath] - - -@dataclasses.dataclass -class IngressTls: - hosts: Sequence[str] | None = None - secret_name: str | None = None - - -@dataclasses.dataclass -class Ingress: - annotations: Mapping[str, str] | None - class_name: str | None - rules: Sequence[IngressRule] | None - tls: Sequence[IngressTls] | None - - -@dataclasses.dataclass -class VolumeMount: - name: str - mount_path: str - read_only: bool - - -@dataclasses.dataclass -class ConfigMapVolume: - name: str - - -@dataclasses.dataclass -class PvcVolume: - name: str - read_only: bool - - -@ dataclasses.dataclass -class ContainerPort: - container_port: int - - -@dataclasses.dataclass -class Container: - name: str - image: str - args: List[str] - ports: Sequence[ContainerPort] - startup_probe: Optional[Probe] - readiness_probe: Optional[Probe] - liveness_probe: Optional[Probe] - volume_mounts: Sequence[VolumeMount] - - -@dataclasses.dataclass -class Deployment: - replicas: int - annotations: Mapping[str, str] | None - containers: Sequence[Container] | None - configmap_volumes: Sequence[ConfigMapVolume] | None - pvc_volumes: Sequence[PvcVolume] | None diff --git a/deployments/sequencer/services/topology.py b/deployments/sequencer/services/topology.py index be9ebaa7c85..fb54f78f7b1 100644 --- a/deployments/sequencer/services/topology.py +++ b/deployments/sequencer/services/topology.py @@ -2,23 +2,14 @@ import typing -from services import ( - objects, - topology_helpers -) +from services.config import SequencerConfig @dataclasses.dataclass class ServiceTopology: - deployment: typing.Optional[objects.Deployment] = dataclasses.field(default_factory=topology_helpers.get_deployment) - config: typing.Optional[objects.Config] = dataclasses.field(default_factory=topology_helpers.get_config) - service: typing.Optional[objects.Service] = dataclasses.field(default_factory=topology_helpers.get_service) - pvc: typing.Optional[objects.PersistentVolumeClaim] = dataclasses.field(default_factory=topology_helpers.get_pvc) - ingress: typing.Optional[objects.Ingress] = dataclasses.field(default_factory=topology_helpers.get_ingress) - - -class SequencerDev(ServiceTopology): - pass - -class SequencerProd(SequencerDev): - pass + config: typing.Optional[SequencerConfig] + image: str + ingress: bool + replicas: int + autoscale: bool + storage: int | None diff --git a/deployments/sequencer/services/topology_helpers.py b/deployments/sequencer/services/topology_helpers.py deleted file mode 100644 index 2a0a6091620..00000000000 --- a/deployments/sequencer/services/topology_helpers.py +++ /dev/null @@ -1,123 +0,0 @@ -from services import objects, const, helpers -from config.sequencer import SequencerDevConfig - - -def get_pvc() -> objects.PersistentVolumeClaim: - return objects.PersistentVolumeClaim( - access_modes=["ReadWriteOnce"], - storage_class_name="premium-rwo", - volume_mode="Filesystem", - storage="64Gi", - mount_path="/data", - read_only=False - ) - - -def get_config() -> objects.Config: - return SequencerDevConfig( - mount_path="/config/sequencer/presets/", - config_file_path=helpers.args.config_file - ) - - -def get_ingress() -> objects.Ingress: - return objects.Ingress( - annotations={ - "kubernetes.io/tls-acme": "true", - "cert-manager.io/common-name": f"{helpers.args.namespace}.gcp-integration.sw-dev.io", - "cert-manager.io/issue-temporary-certificate": "true", - "cert-manager.io/issuer": "letsencrypt-prod", - "acme.cert-manager.io/http01-edit-in-place": "true" - }, - class_name=None, - rules=[ - objects.IngressRule( - host=f"{helpers.args.namespace}.gcp-integration.sw-dev.io", - paths=[ - objects.IngressRuleHttpPath( - path="/monitoring/", - path_type="Prefix", - backend_service_name="sequencer-node-service", - backend_service_port_number=const.MONITORING_SERVICE_PORT - ) - ] - ) - ], - tls=[ - objects.IngressTls( - hosts=[ - f"{helpers.args.namespace}.gcp-integration.sw-dev.io" - ], - secret_name="sequencer-tls" - ) - ] - ) - - -def get_service() -> objects.Service: - return objects.Service( - type=const.ServiceType.CLUSTER_IP, - selector={}, - ports=[ - objects.PortMapping( - name="http", - port=const.HTTP_SERVICE_PORT, - container_port=const.HTTP_CONTAINER_PORT - ), - objects.PortMapping( - name="rpc", - port=const.RPC_SERVICE_PORT, - container_port=const.RPC_CONTAINER_PORT - ), - objects.PortMapping( - name="monitoring", - port=const.MONITORING_SERVICE_PORT, - container_port=const.MONITORING_CONTAINER_PORT - ) - ] - ) - - -def get_deployment() -> objects.Deployment: - return objects.Deployment( - replicas=1, - annotations={}, - containers=[ - objects.Container( - name="server", - image="us.gcr.io/starkware-dev/sequencer-node-test:0.0.1-dev.3", - args=["--config_file", "/config/sequencer/presets/config"], - ports=[ - objects.ContainerPort(container_port=const.HTTP_CONTAINER_PORT), - objects.ContainerPort(container_port=const.RPC_CONTAINER_PORT), - objects.ContainerPort(container_port=const.MONITORING_CONTAINER_PORT) - ], - startup_probe=objects.Probe(port=const.MONITORING_CONTAINER_PORT, path="/monitoring/nodeVersion", period_seconds=10, failure_threshold=10, timeout_seconds=5), - readiness_probe=objects.Probe(port=const.MONITORING_CONTAINER_PORT, path="/monitoring/ready", period_seconds=10, failure_threshold=5, timeout_seconds=5), - liveness_probe=objects.Probe(port=const.MONITORING_CONTAINER_PORT, path="/monitoring/alive", period_seconds=10, failure_threshold=5, timeout_seconds=5), - volume_mounts=[ - objects.VolumeMount( - name="config", - mount_path="/config/sequencer/presets/", - read_only=True - ), - objects.VolumeMount( - name="data", - mount_path="/data", - read_only=False - ) - ] - ) - ], - pvc_volumes=[ - objects.PvcVolume( - name="data", - read_only=False - ) - ], - configmap_volumes=[ - objects.ConfigMapVolume( - name="config" - ) - ] - ) diff --git a/deployments/sequencer_simulator/.gitignore b/deployments/sequencer_simulator/.gitignore new file mode 100644 index 00000000000..dc0d6d7d379 --- /dev/null +++ b/deployments/sequencer_simulator/.gitignore @@ -0,0 +1,4 @@ +__pycache__/ +.idea/ +dist/ +imports/ diff --git a/deployments/sequencer_simulator/Pipfile b/deployments/sequencer_simulator/Pipfile new file mode 100644 index 00000000000..695a12d17e3 --- /dev/null +++ b/deployments/sequencer_simulator/Pipfile @@ -0,0 +1,13 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +constructs = "*" +cdk8s = "*" + +[dev-packages] + +[requires] +python_version = "3.12" diff --git a/deployments/sequencer_simulator/Pipfile.lock b/deployments/sequencer_simulator/Pipfile.lock new file mode 100644 index 00000000000..3fb326707d7 --- /dev/null +++ b/deployments/sequencer_simulator/Pipfile.lock @@ -0,0 +1,110 @@ +{ + "_meta": { + "hash": { + "sha256": "c6c40ab1f100ee54f62b7f3fb568aacbebcd642c4e3575dfc9e4e5e2e8447fe1" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.12" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "attrs": { + "hashes": [ + "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff", + "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308" + ], + "markers": "python_version >= '3.8'", + "version": "==24.3.0" + }, + "cattrs": { + "hashes": [ + "sha256:67c7495b760168d931a10233f979b28dc04daf853b30752246f4f8471c6d68d0", + "sha256:8028cfe1ff5382df59dd36474a86e02d817b06eaf8af84555441bac915d2ef85" + ], + "markers": "python_version >= '3.8'", + "version": "==24.1.2" + }, + "cdk8s": { + "hashes": [ + "sha256:7786dca0430ed46b3ff838b624d976e6e084ed0382003441263e9646444d3e9f", + "sha256:a0fc18160c284fdb7884b53c75725c3e910a1816f224a297048e7af91ebe6db1" + ], + "index": "pypi", + "markers": "python_version ~= '3.8'", + "version": "==2.69.41" + }, + "constructs": { + "hashes": [ + "sha256:1f0f59b004edebfde0f826340698b8c34611f57848139b7954904c61645f13c1", + "sha256:ce54724360fffe10bab27d8a081844eb81f5ace7d7c62c84b719c49f164d5307" + ], + "index": "pypi", + "markers": "python_version ~= '3.8'", + "version": "==10.4.2" + }, + "importlib-resources": { + "hashes": [ + "sha256:185f87adef5bcc288449d98fb4fba07cea78bc036455dd44c5fc4a2fe78fed2c", + "sha256:789cfdc3ed28c78b67a06acb8126751ced69a3d5f79c095a98298cd8a760ccec" + ], + "markers": "python_version >= '3.9'", + "version": "==6.5.2" + }, + "jsii": { + "hashes": [ + "sha256:5a44d7c3a5a326fa3d9befdb3770b380057e0a61e3804e7c4907f70d76afaaa2", + "sha256:c79c47899f53a7c3c4b20f80d3cd306628fe9ed1852eee970324c71eba1d974e" + ], + "markers": "python_version ~= '3.8'", + "version": "==1.106.0" + }, + "publication": { + "hashes": [ + "sha256:0248885351febc11d8a1098d5c8e3ab2dabcf3e8c0c96db1e17ecd12b53afbe6", + "sha256:68416a0de76dddcdd2930d1c8ef853a743cc96c82416c4e4d3b5d901c6276dc4" + ], + "version": "==0.0.3" + }, + "python-dateutil": { + "hashes": [ + "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", + "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.9.0.post0" + }, + "six": { + "hashes": [ + "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", + "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.17.0" + }, + "typeguard": { + "hashes": [ + "sha256:00edaa8da3a133674796cf5ea87d9f4b4c367d77476e185e80251cc13dfbb8c4", + "sha256:5e3e3be01e887e7eafae5af63d1f36c849aaa94e3a0112097312aabfa16284f1" + ], + "markers": "python_full_version >= '3.5.3'", + "version": "==2.13.3" + }, + "typing-extensions": { + "hashes": [ + "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", + "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" + ], + "markers": "python_version >= '3.8'", + "version": "==4.12.2" + } + }, + "develop": {} +} diff --git a/deployments/sequencer_simulator/cdk8s.yaml b/deployments/sequencer_simulator/cdk8s.yaml new file mode 100644 index 00000000000..7bd30b32efc --- /dev/null +++ b/deployments/sequencer_simulator/cdk8s.yaml @@ -0,0 +1,4 @@ +language: python +app: pipenv run python main.py +imports: + - k8s diff --git a/deployments/sequencer_simulator/main.py b/deployments/sequencer_simulator/main.py new file mode 100755 index 00000000000..7014f1c407c --- /dev/null +++ b/deployments/sequencer_simulator/main.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python +from constructs import Construct +from cdk8s import App, Chart, Names, YamlOutputType +from imports import k8s + +from typing import Dict +import json +import os +import argparse + +def argument_parser(): + parser = argparse.ArgumentParser() + parser.add_argument( + "--namespace", + required=True, + type=str, + help="Required: Specify the Kubernetes namespace." + ) + parser.add_argument( + "--config", + type=str, + required=True, + help="Required: Specify the sequencer config path" + ) + + return parser.parse_args() + +def get_config(path: str): + with open(os.path.abspath(path), "r") as f: + return json.loads(f.read()) + +class Simulator(Chart): + def __init__(self, scope: Construct, id: str, namespace: str, config: Dict): + super().__init__(scope, id, disable_resource_name_hashes=True, namespace=namespace) + + self.label = {"app": Names.to_label_value(self, include_hash=False)} + self.config = config + + k8s.KubeConfigMap( + self, + "configmap", + metadata=k8s.ObjectMeta(name=f"{self.node.id}-config"), + data=dict(config=json.dumps(self.config)), + ) + + k8s.KubeDeployment( + self, + "deployment", + spec=k8s.DeploymentSpec( + replicas=1, + selector=k8s.LabelSelector(match_labels=self.label), + template=k8s.PodTemplateSpec( + metadata=k8s.ObjectMeta(labels=self.label), + spec=k8s.PodSpec( + volumes=[ + k8s.Volume( + name=f"{self.node.id}-config", + config_map=k8s.ConfigMapVolumeSource( + name=f"{self.node.id}-config" + ) + ) + ], + containers=[ + k8s.Container( + name=self.node.id, + image="us-central1-docker.pkg.dev/starkware-dev/sequencer/simulator:0.0.1", + args=["--config_file", "/config/sequencer/presets/config"], + env=[ + k8s.EnvVar( + name="RUST_LOG", + value="debug" + ), + k8s.EnvVar( + name="RUST_BACKTRACE", + value="full" + ) + ], + volume_mounts=[ + k8s.VolumeMount( + name=f"{self.node.id}-config", + mount_path="/config/sequencer/presets/", + read_only=True + ) + ] + ) + ], + ), + ), + ), + ) + + +def main(): + args = argument_parser() + app = App(yaml_output_type=YamlOutputType.FOLDER_PER_CHART_FILE_PER_RESOURCE) + Simulator( + scope=app, + id="sequencer-simulator", + namespace=args.namespace, + config=get_config(args.config) + ) + + app.synth() + + +if __name__ == "__main__": + main() diff --git a/docker-ci/images/sequencer-ci.Dockerfile b/docker-ci/images/sequencer-ci.Dockerfile new file mode 100644 index 00000000000..885be42e6c7 --- /dev/null +++ b/docker-ci/images/sequencer-ci.Dockerfile @@ -0,0 +1,24 @@ +# syntax = devthefuture/dockerfile-x +# docker-ci/images/sequencer-ci.Dockerfile + +# Dockerfile with multi-stage builds for efficient dependency caching and lightweight final image. +# For more on Docker stages, visit: https://docs.docker.com/build/building/multi-stage/ +# We use dockerfile-x, for more information visit: https://github.com/devthefuture-org/dockerfile-x/blob/master/README.md + +INCLUDE deployments/images/base/Dockerfile + +FROM base AS builder + +ARG USERNAME=sequencer +ARG USER_UID=1000 +ARG USER_GID=$USER_UID + +RUN apt update && apt install -y sudo + +RUN groupadd --gid $USER_GID $USERNAME || true +RUN useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -m $USERNAME || \ + usermod --login ${USERNAME} --move-home --home /home/${USERNAME} `grep ${USER_UID} /etc/passwd | awk -F: '{print $1}'` + +RUN echo "#${USER_UID} ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers.d/developer + +USER ${USERNAME} diff --git a/docs/papyrus/CONTRIBUTING.md b/docs/papyrus/CONTRIBUTING.md index 57cce3dba08..afcc62da74c 100644 --- a/docs/papyrus/CONTRIBUTING.md +++ b/docs/papyrus/CONTRIBUTING.md @@ -53,4 +53,4 @@ Your code will need to pass [CI](../.github/workflows/ci.yml) before it can be m - Pass all local tests and all integration tests. - Be formatted according to [rustfmt](https://github.com/rust-lang/rustfmt). - Be linted according to [clippy](https://github.com/rust-lang/rust-clippy) -- Not include unused dependencies (Checked by [udeps](https://github.com/est31/cargo-udeps)). +- Not include unused dependencies (Checked by [machete](https://github.com/bnjbvr/cargo-machete)). diff --git a/docs/papyrus/README.adoc b/docs/papyrus/README.adoc index be63392ae18..a6ef811d902 100644 --- a/docs/papyrus/README.adoc +++ b/docs/papyrus/README.adoc @@ -231,21 +231,21 @@ cargo run --release --package papyrus_node --bin papyrus_node -- \ cargo run --release --package papyrus_node --bin papyrus_node -- \ --base_layer.node_url \ --network.bootstrap_peer_multiaddr.#is_none false \ - --network.bootstrap_peer_multiaddr /ip4//tcp//p2p/ + --network.bootstrap_peer_multiaddr /ip4//tcp//p2p/ ---- You can also use DNS instead of ip4 by typing ---- - --network.bootstrap_peer_multiaddr /dns//tcp//p2p/ + --network.bootstrap_peer_multiaddr /dns//tcp//p2p/ ---- -==== P2P Sync (with bootstrap connection) +==== P2p Sync (with bootstrap connection) [source, bash] ---- cargo run --release --package papyrus_node --bin papyrus_node -- \ --base_layer.node_url \ --network.bootstrap_peer_multiaddr.#is_none false \ - --network.bootstrap_peer_multiaddr /ip4//tcp//p2p/ \ + --network.bootstrap_peer_multiaddr /ip4//tcp//p2p/ \ --sync.#is_none true \ --p2p_sync.#is_none false ---- @@ -253,7 +253,7 @@ cargo run --release --package papyrus_node --bin papyrus_node -- \ [NOTE] ==== .In case you are running more than one node on the same machine, notice you will have to specify the following fields (to avoid collisions): -* network.tcp_port +* network.port * monitoring_gateway.server_address * rpc.server_address * storage.db_config.path_prefix @@ -352,7 +352,7 @@ Gets statistics for each table in the libmdbx database. For more information, se `metrics`:: Gets metrics of the node’s activity. For more information, see xref:#collecting-metrics[]. `peer_id`:: -Gets the P2P peer ID of the node (if the network component is inactive returns an empty string). +Gets the p2p peer ID of the node (if the network component is inactive returns an empty string). == Collecting metrics diff --git a/papyrus_utilities.Dockerfile b/papyrus_utilities.Dockerfile index f6a36f79634..436b89d6ba9 100644 --- a/papyrus_utilities.Dockerfile +++ b/papyrus_utilities.Dockerfile @@ -6,45 +6,35 @@ # To build the papyrus utilities image, run from the root of the project: # DOCKER_BUILDKIT=1 COMPOSE_DOCKER_CLI_BUILD=1 docker build -f papyrus_utilities.Dockerfile . -INCLUDE Dockerfile +INCLUDE deployments/images/base/Dockerfile # Build papyrus utilities. -FROM builder AS utilities_builder +FROM base AS builder +COPY . . # Build papyrus_load_test and copy its resources. -RUN cargo build --target x86_64-unknown-linux-musl --release --package papyrus_load_test --bin papyrus_load_test - -# Build dump_declared_classes. -RUN cargo build --target x86_64-unknown-linux-musl --release --package papyrus_storage --features "clap" \ - --bin dump_declared_classes +RUN cargo build --release --package papyrus_load_test --bin papyrus_load_test # Build storage_benchmark. -RUN cargo build --target x86_64-unknown-linux-musl --release --package papyrus_storage \ +RUN cargo build --release --package papyrus_storage \ --features "clap statistical" --bin storage_benchmark # Starting a new stage so that the final image will contain only the executables. -FROM alpine:3.17.0 AS papyrus_utilities - -# Set the working directory to '/app', to match the main docker file. -WORKDIR /app +FROM ubuntu:22.04 # Copy the load test executable and its resources. -COPY --from=utilities_builder /app/target/x86_64-unknown-linux-musl/release/papyrus_load_test /app/target/release/papyrus_load_test -COPY crates/papyrus_load_test/resources/ /app/crates/papyrus_load_test/resources - -# Copy the dump_declared_classes executable. -COPY --from=utilities_builder /app/target/x86_64-unknown-linux-musl/release/dump_declared_classes /app/target/release/dump_declared_classes +COPY --from=builder /target/release/papyrus_load_test /target/release/papyrus_load_test +COPY crates/papyrus_load_test/resources/ /crates/papyrus_load_test/resources # Copy the storage_benchmark executable. -COPY --from=utilities_builder /app/target/x86_64-unknown-linux-musl/release/storage_benchmark /app/target/release/storage_benchmark +COPY --from=builder /target/release/storage_benchmark /target/release/storage_benchmark # Set the PATH environment variable to enable running an executable only with its name. -ENV PATH="/app/target/release:${PATH}" +ENV PATH="/target/release:${PATH}" ENTRYPOINT echo -e \ "There is no default executable for this image. Run an executable using its name or path to it.\n\ The available executables are:\n\ - papyrus_load_test, performs a stress test on a node RPC gateway.\n\ - - dump_declared_classes, dumps the declared_classes table from the storage to a file.\n\ - storage_benchmark, performs a benchmark on the storage.\n\ For example, in a docker runtime: docker run --entrypoint papyrus_load_test " diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 31cfd7b24a0..52e88dc40ec 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "stable" -components = ["clippy", "rustc-dev", "rustfmt"] +channel = "1.85" +components = ["rustc-dev"] profile = "default" targets = ["x86_64-unknown-linux-gnu"] diff --git a/rustfmt.toml b/rustfmt.toml index 3820d621dd4..ba76e595e32 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -20,6 +20,9 @@ unstable_features = true version = "Two" wrap_comments = true +# Automatically generated files by protoc +ignore = ["/crates/papyrus_protobuf/src/protobuf/protoc_output.rs"] + # To use these settings in vscode, add the following line to your settings: # "rust-analyzer.rustfmt.overrideCommand": [ # "rustup", diff --git a/scripts/build_native_blockifier.sh b/scripts/build_native_blockifier.sh index 7ba7aaa968d..e6dc77c78ef 100755 --- a/scripts/build_native_blockifier.sh +++ b/scripts/build_native_blockifier.sh @@ -9,11 +9,14 @@ function clean() { function build() { + ret=0 echo "Building..." pypy3.9 -m venv /tmp/venv source /tmp/venv/bin/activate - cargo build --release -p native_blockifier --features "testing" || clean + rustup toolchain install + cargo build --release -p native_blockifier --features "cairo_native" || ret=$? clean + return $ret } build diff --git a/scripts/committer/generate_committer_flamegraph.sh b/scripts/committer/generate_committer_flamegraph.sh index d1d680595cb..6eee9ead28f 100644 --- a/scripts/committer/generate_committer_flamegraph.sh +++ b/scripts/committer/generate_committer_flamegraph.sh @@ -20,8 +20,8 @@ if ! command -v perf; then fi ROOT_DIR=$(git rev-parse --show-toplevel) -BENCH_INPUT_FILES_PREFIX=$(cat ${ROOT_DIR}/crates/committer_cli/src/tests/flow_test_files_prefix) +BENCH_INPUT_FILES_PREFIX=$(cat ${ROOT_DIR}/crates/starknet_committer_and_os_cli/src/committer_cli/tests/flow_test_files_prefix) # Lower security level in perf_event_paranoid to 2 to allow cargo to use perf without running on root. sudo sysctl kernel.perf_event_paranoid=2 -gcloud storage cat gs://committer-testing-artifacts/${BENCH_INPUT_FILES_PREFIX}/committer_flow_inputs.json | jq -r .committer_input | CARGO_PROFILE_RELEASE_DEBUG=true cargo flamegraph -p committer_cli -- commit +gcloud storage cat gs://committer-testing-artifacts/${BENCH_INPUT_FILES_PREFIX}/committer_flow_inputs.json | jq -r .committer_input | CARGO_PROFILE_RELEASE_DEBUG=true cargo flamegraph -p starknet_committer_and_os_cli -- commit diff --git a/scripts/generate_changelog.py b/scripts/generate_changelog.py index 24e92947d8b..a074a26aefb 100755 --- a/scripts/generate_changelog.py +++ b/scripts/generate_changelog.py @@ -5,15 +5,19 @@ # Usage: # scripts/generate_changelog.py --start --end --project -GIT_CLIFF_VERSION = "2.4.0" +GIT_CLIFF_VERSION = "2.7.0" PROJECT_TO_PATHS = {"blockifier": ["crates/blockifier/"], "all": []} + def prepare_git_cliff(version: str): """ Install git-cliff if missing. """ run_command( - command=f'cargo install --list | grep -q "git-cliff v{version}" || cargo install git-cliff@{version}' + command=( + f'cargo install --list | grep -q "git-cliff v{version}" || ' + f"cargo install git-cliff@{version}" + ) ) @@ -21,7 +25,8 @@ def build_command(project_name: str, start_tag: str, end_tag: str) -> str: paths = PROJECT_TO_PATHS[project_name] include_paths = " ".join((f"--include-path {path}" for path in paths)) return ( - f'git-cliff {start_tag}..{end_tag} -o changelog_{start_tag}_{end_tag}.md --ignore-tags ".*-dev.[0-9]+" {include_paths}' + f"git-cliff {start_tag}..{end_tag} -o changelog_{start_tag}_{end_tag}.md " + f'--ignore-tags ".*-dev.[0-9]+" --tag {end_tag} {include_paths}' ) @@ -32,7 +37,9 @@ def build_command(project_name: str, start_tag: str, end_tag: str) -> str: ) parser.add_argument("--end", type=str, help="The commit/tag that changelog's history ends at.") parser.add_argument( - "--project", choices=PROJECT_TO_PATHS.keys(), help="The project that the changelog is generated for." + "--project", + choices=PROJECT_TO_PATHS.keys(), + help="The project that the changelog is generated for.", ) args = parser.parse_args() prepare_git_cliff(version=GIT_CLIFF_VERSION) diff --git a/scripts/merge_branches.py b/scripts/merge_branches.py index 7c43f477dc1..40d592fd1b3 100755 --- a/scripts/merge_branches.py +++ b/scripts/merge_branches.py @@ -17,7 +17,7 @@ FINAL_BRANCH = "main" MERGE_PATHS_FILE = "scripts/merge_paths.json" -FILES_TO_PRESERVE = {"rust-toolchain.toml"} +FILES_TO_PRESERVE = {"rust-toolchain.toml", "scripts/parent_branch.txt"} def load_merge_paths() -> Dict[str, str]: diff --git a/scripts/merge_paths.json b/scripts/merge_paths.json index d2f2c3cb3ed..e34991cf9e5 100644 --- a/scripts/merge_paths.json +++ b/scripts/merge_paths.json @@ -1,3 +1,5 @@ { - "main-v0.13.2": "main" + "main-v0.13.2": "main-v0.13.4", + "main-v0.13.4": "main-v0.13.5", + "main-v0.13.5": "main" } diff --git a/scripts/merge_paths_test.py b/scripts/merge_paths_test.py index 3b083904cb8..e98272b6f95 100755 --- a/scripts/merge_paths_test.py +++ b/scripts/merge_paths_test.py @@ -1,9 +1,20 @@ +import pytest +from typing import Dict + from merge_branches import FINAL_BRANCH, MERGE_PATHS_FILE, load_merge_paths -def test_linear_path(): - merge_paths = load_merge_paths() +@pytest.fixture +def parent_branch() -> str: + return open("scripts/parent_branch.txt").read().strip() + + +@pytest.fixture +def merge_paths() -> Dict[str, str]: + return load_merge_paths() + +def test_linear_path(merge_paths: Dict[str, str]): src_dst_iter = iter(merge_paths.items()) (oldest_branch, prev_dst_branch) = next(src_dst_iter) assert ( @@ -11,9 +22,7 @@ def test_linear_path(): ), f"Oldest branch '{oldest_branch}' cannot be a destination branch." for src_branch, dst_branch in src_dst_iter: - assert ( - prev_dst_branch == src_branch - ), ( + assert prev_dst_branch == src_branch, ( f"Since the merge graph is linear, the source branch '{src_branch}' must be the same " f"as the previous destination branch, which is '{prev_dst_branch}'. Check out " f"{MERGE_PATHS_FILE}." @@ -23,3 +32,11 @@ def test_linear_path(): assert ( prev_dst_branch == FINAL_BRANCH ), f"The last destination is '{prev_dst_branch}' but must be '{FINAL_BRANCH}'." + + +def test_parent_branch_is_on_path(parent_branch: str, merge_paths: Dict[str, str]): + known_branches = set(merge_paths.keys()) | set(merge_paths.values()) + assert parent_branch in known_branches, ( + f"Parent branch '{parent_branch}' is not on the merge path (branches in merge path: " + f"{known_branches})." + ) diff --git a/scripts/named_todos.py b/scripts/named_todos.py new file mode 100755 index 00000000000..33e9bb1b9ac --- /dev/null +++ b/scripts/named_todos.py @@ -0,0 +1,80 @@ +import os +import re + + +import argparse +from typing import Optional +from tests_utils import ( + get_local_changes, +) + + +def validate_todo_format(file_path: str) -> bool: + """ + Validates that all TODO comments in the file are formatted as TODO(X), where X is a non-empty + string of characters. + + Args: + file_path (str): Path to the file to be checked. + + Returns: + bool: True if all TODO comments are valid, False otherwise. + """ + # Skip this current file, as the following regex definition itself is detected as an unformatted + # TODO comment. + if os.path.relpath(__file__) == file_path: + return True + + # Matches a comment indicator (// or #), any set characters, and the TODO literal. + comment_todo_pattern = re.compile(r"(\/\/|#).*?TODO") + # Matches a comment indicator (// or #), an optional single space, the TODO literal, + # parenthesis bounding a non-empty string (owner name), and a colon. + required_comment_todo_pattern = re.compile(r"(\/\/|#) ?TODO\([^)]+\):") + invalid_todos = [] + try: + with open(file_path, "r") as file: + for line_number, line in enumerate(file, start=1): + if comment_todo_pattern.search(line): + if not required_comment_todo_pattern.search(line): + invalid_todos.append((file_path, line_number, line.strip())) + except Exception as e: + # Make sure to report which file caused the error before re-raising the exception. + print(f"Error while reading file {file_path}: {e}") + raise e + if len(invalid_todos) > 0: + print(f"{len(invalid_todos)} invalid TODOs found.") + for file_path, line_number, line in invalid_todos: + print(f"{file_path}:{line_number}: '{line}'") + return False + return True + + +def enforce_named_todos(commit_id: Optional[str]): + """ + Enforce TODO comments format. + If commit_id is provided, compares against that commit; otherwise, compares against HEAD. + """ + + local_changes = get_local_changes(".", commit_id=commit_id) + print(f"Enforcing TODO format on modified files: {local_changes}.") + successful_validation = all( + validate_todo_format(file_path) + for file_path in local_changes + if os.path.isfile(file_path) and not file_path.endswith(".bin") + ) + assert successful_validation, "Found invalid TODOs" + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(description="Enforcing all TODO comments are properly named.") + parser.add_argument("--commit_id", type=str, help="GIT commit ID to compare against.") + return parser.parse_args() + + +def main(): + args = parse_args() + enforce_named_todos(commit_id=args.commit_id) + + +if __name__ == "__main__": + main() diff --git a/scripts/papyrus/p2p_sync_e2e_test/client_node_config.json b/scripts/papyrus/p2p_sync_e2e_test/client_node_config.json index 393ee3bd87c..a7996901644 100644 --- a/scripts/papyrus/p2p_sync_e2e_test/client_node_config.json +++ b/scripts/papyrus/p2p_sync_e2e_test/client_node_config.json @@ -6,7 +6,7 @@ "monitoring_gateway.server_address": "127.0.0.1:8082", "collect_metrics": true, "rpc.server_address": "127.0.0.1:8083", - "network.tcp_port": 10003, + "network.port": 10003, "network.bootstrap_peer_multiaddr.#is_none": false, "network.bootstrap_peer_multiaddr": "/ip4/127.0.0.1/tcp/10000/p2p/12D3KooWDFYi71juk6dYWo3UDvqs5gAzGDc124LSvcR5d187Tdvi" } diff --git a/scripts/parent_branch.txt b/scripts/parent_branch.txt new file mode 100644 index 00000000000..ba2906d0666 --- /dev/null +++ b/scripts/parent_branch.txt @@ -0,0 +1 @@ +main diff --git a/scripts/run_feature_combos_test.py b/scripts/run_feature_combos_test.py new file mode 100644 index 00000000000..3e4e91c3c68 --- /dev/null +++ b/scripts/run_feature_combos_test.py @@ -0,0 +1,41 @@ +#!/bin/env python3 + +import subprocess +from typing import List +from tests_utils import get_workspace_packages + + +def run_command(cmd: List[str]): + print(f"Running '{' '.join(cmd)}'", flush=True) + subprocess.run(cmd, check=True) + + +def build_without_features(package: str): + run_command(cmd=["cargo", "build", "--package", package]) + + +def build_with_all_features(package: str): + run_command(cmd=["cargo", "build", "--all-features", "--package", package]) + + +def main(): + packages = get_workspace_packages() + print(f"Building {len(packages)} packages without features.", flush=True) + featureless_failures, feature_failures = {}, {} + for package in packages: + try: + build_without_features(package) + except Exception as e: + featureless_failures[package] = str(e) + print(f"Building {len(packages)} packages with all features.", flush=True) + for package in packages: + try: + build_with_all_features(package) + except Exception as e: + feature_failures[package] = str(e) + failures = {"featureless": featureless_failures, "featured": feature_failures} + assert failures == {"featureless": {}, "featured": {}}, f"{failures=}." + + +if __name__ == "__main__": + main() diff --git a/scripts/run_tests.py b/scripts/run_tests.py index 76cfba374ca..6f0890b41fe 100755 --- a/scripts/run_tests.py +++ b/scripts/run_tests.py @@ -12,42 +12,63 @@ ) # Set of files which - if changed - should trigger tests for all packages. -ALL_TEST_TRIGGERS: Set[str] = {"Cargo.toml", "Cargo.lock"} +ALL_TEST_TRIGGERS: Set[str] = {"Cargo.toml", "Cargo.lock", "rust-toolchain.toml"} + +# Set of crates which - if changed - should trigger the integration tests. +INTEGRATION_TEST_CRATE_TRIGGERS: Set[str] = {"starknet_integration_tests"} + +# Sequencer node binary name. +SEQUENCER_BINARY_NAME: str = "starknet_sequencer_node" + +# List of sequencer node integration test binary names. Stored as a list to maintain order. +SEQUENCER_INTEGRATION_TEST_NAMES: List[str] = [ + "integration_test_positive_flow", + "integration_test_restart_flow", + "integration_test_revert_flow", + "integration_test_central_and_p2p_sync_flow", +] # Enum of base commands. class BaseCommand(Enum): TEST = "test" - CODECOV = "codecov" - RUSTFMT = "rustfmt" CLIPPY = "clippy" DOC = "doc" + INTEGRATION = "integration" - def cmd(self, crates: Set[str]) -> List[str]: + def cmds(self, crates: Set[str]) -> List[List[str]]: package_args = [] for package in crates: package_args.extend(["--package", package]) if self == BaseCommand.TEST: - return ["cargo", "test"] + package_args - elif self == BaseCommand.CODECOV: - return [ - "cargo", - "llvm-cov", - "--codecov", - "-r", - "--output-path", - "codecov.json", - ] + package_args - elif self == BaseCommand.RUSTFMT: - fmt_args = package_args if len(package_args) > 0 else ["--all"] - return ["scripts/rust_fmt.sh"] + fmt_args + ["--", "--check"] + return [["cargo", "test"] + package_args] elif self == BaseCommand.CLIPPY: clippy_args = package_args if len(package_args) > 0 else ["--workspace"] - return ["cargo", "clippy"] + clippy_args + return [["cargo", "clippy"] + clippy_args + ["--all-targets", "--all-features"]] elif self == BaseCommand.DOC: doc_args = package_args if len(package_args) > 0 else ["--workspace"] - return ["cargo", "doc", "-r", "--document-private-items", "--no-deps"] + doc_args + return [["cargo", "doc", "--document-private-items", "--no-deps"] + doc_args] + elif self == BaseCommand.INTEGRATION: + # Do nothing if integration tests should not be triggered. + if INTEGRATION_TEST_CRATE_TRIGGERS.isdisjoint(crates): + print(f"Skipping sequencer integration tests.") + return [] + + print(f"Composing sequencer integration test commands.") + # Commands to build the node and all the test binaries. + build_cmds = [ + ["cargo", "build", "--bin", binary_name] + for binary_name in [SEQUENCER_BINARY_NAME] + SEQUENCER_INTEGRATION_TEST_NAMES + ] + # Port setup command, used to prevent port binding issues. + port_cmds = [["sysctl", "-w", "net.ipv4.ip_local_port_range='40000 40200'"]] + # Commands to run the test binaries. + run_cmds = [ + [f"./target/debug/{test_binary_name}"] + for test_binary_name in SEQUENCER_INTEGRATION_TEST_NAMES + ] + return build_cmds + port_cmds + run_cmds raise NotImplementedError(f"Command {self} not implemented.") @@ -63,16 +84,13 @@ def test_crates(crates: Set[str], base_command: BaseCommand): Runs tests for the given crates. If no crates provided, runs tests for all crates. """ - args = [] - for package in crates: - args.extend(["--package", package]) - # If crates is empty (i.e. changes_only is False), all packages will be tested (no args). - cmd = base_command.cmd(crates=crates) + cmds = base_command.cmds(crates=crates) - print("Running tests...") - print(cmd, flush=True) - subprocess.run(cmd, check=True) + print("Executing test commands...") + for cmd in cmds: + print(cmd, flush=True) + subprocess.run(cmd, check=True) print("Tests complete.") diff --git a/scripts/rust_fmt.sh b/scripts/rust_fmt.sh index 4478e594e95..b63f824b872 100755 --- a/scripts/rust_fmt.sh +++ b/scripts/rust_fmt.sh @@ -1,13 +1,20 @@ #!/bin/bash -# Install toolchain if missing (local run). -TOOLCHAIN="nightly-2024-04-29" +set -euo pipefail + +if [[ -n "${CI:-}" ]]; then + echo "This script should not be run in a CI environment, as it installs toolchains out of cache." + exit 1 +fi + +SCRIPT_DIR="$(dirname "${BASH_SOURCE[0]}")" +TOOLCHAIN=$(grep "EXTRA_RUST_TOOLCHAINS:" "${SCRIPT_DIR}"/../.github/workflows/main.yml | awk '{print $2}') function install_rustfmt() { - rustup toolchain install ${TOOLCHAIN} - rustup component add --toolchain ${TOOLCHAIN} rustfmt + rustup toolchain install "${TOOLCHAIN}" + rustup component add --toolchain "${TOOLCHAIN}" rustfmt } -rustup toolchain list | grep -q ${TOOLCHAIN} || install_rustfmt +rustup toolchain list | grep -q "${TOOLCHAIN}" || install_rustfmt -cargo +${TOOLCHAIN} fmt $@ +cargo +"${TOOLCHAIN}" fmt --all -- "$@" diff --git a/scripts/sequencer-ci.Dockerfile b/scripts/sequencer-ci.Dockerfile deleted file mode 100644 index 77a9902dff6..00000000000 --- a/scripts/sequencer-ci.Dockerfile +++ /dev/null @@ -1,22 +0,0 @@ -FROM ubuntu:20.04 - -ARG USERNAME=sequencer -ARG USER_UID=1000 -ARG USER_GID=$USER_UID - -RUN apt update && apt install -y sudo - -RUN groupadd --gid $USER_GID $USERNAME && \ - useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -m $USERNAME -RUN echo "%${USERNAME} ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers.d/developer - -USER ${USERNAME} - -ENV RUSTUP_HOME=/var/tmp/rust -ENV CARGO_HOME=${RUSTUP_HOME} -ENV PATH=$PATH:${RUSTUP_HOME}/bin - -COPY install_build_tools.sh . -COPY dependencies.sh . - -RUN ./install_build_tools.sh diff --git a/scripts/sequencer_integration_test.sh b/scripts/sequencer_integration_test.sh new file mode 100755 index 00000000000..a2954945b9b --- /dev/null +++ b/scripts/sequencer_integration_test.sh @@ -0,0 +1,84 @@ +#!/usr/bin/env bash +# scripts/sequencer_integration_test.sh +# +# Usage: +# ./scripts/sequencer_integration_test.sh [test] +# +# If no argument is provided, the default test "positive" is run. +# You can also pass: +# - "positive" to run the positive flow test, +# - "restart" to run the restart flow test, or +# - "revert" to run the revert flow test, +# - "sync" to run the central and p2p sync flow test, +# - "all" to run all tests. +# +# Note: Make sure the binaries exist in +# crates/starknet_integration_tests/src/bin/sequencer_node_integration_tests/ +# with names such as positive_flow.rs, revert_flow.rs, restart_flow.rs, sync_flow.rs + +# The test requires sudo privileges for running certain commands. +# Ensure sudo privileges are available before proceeding. +sudo -v || { echo "Sudo authentication failed. Exiting."; exit 1; } +# Setting the ephemeral port range to be a distinct range that should be available. This is to +# resolve issues arising due to the way libp2p chooses its used ports, resulting in sporadic +# conflicts with the node configuration, and port binding errors. Disabling this could result in the +# aforementioned sporadic error. +sudo sysctl -w "net.ipv4.ip_local_port_range=40000 40200" + + +# TODO(noamsp): find a way to get this mapping automatically instead of hardcoding +declare -A TEST_ALIASES=( + [positive]="integration_test_positive_flow" + [restart]="integration_test_restart_flow" + [revert]="integration_test_revert_flow" + [sync]="integration_test_central_and_p2p_sync_flow" +) + +# Set default test if none provided +TEST="${1:-positive}" + +echo "Running integration test alias: $TEST" + +SEQUENCER_BINARY="starknet_sequencer_node" +ANVIL_PROCESS_NAME="anvil" + +# Stop any running instances of SEQUENCER_BINARY (ignore error if not found) +killall "$SEQUENCER_BINARY" 2>/dev/null +# Stop any running instances of Anvil (ignore error if not found) +killall "$ANVIL_PROCESS_NAME" 2>/dev/null + +# Build the main node binary (if required) +cargo build --bin "$SEQUENCER_BINARY" + +# Helper function to build a test binary +build_test() { + local tname="$1" + echo "==> Building test: $tname" + cargo build --bin "$tname" || { echo "Build for $tname failed"; exit 1; } +} + +# Helper function to run a test binary +run_test() { + local tname="$1" + echo "==> Running test: $tname" + "./target/debug/$tname" || { echo "Test $tname failed"; exit 1; } +} + +if [ "$TEST" = "all" ]; then + for alias in "${!TEST_ALIASES[@]}"; do + build_test "${TEST_ALIASES[$alias]}" + done + for alias in "${!TEST_ALIASES[@]}"; do + run_test "${TEST_ALIASES[$alias]}" + done + exit 0 +fi + +if [ -z "${TEST_ALIASES[$TEST]}" ]; then + echo "Invalid alias: '$TEST'" + echo "Valid aliases are: all,$(IFS=,; echo "${!TEST_ALIASES[*]}")" + exit 1 +fi + +build_test "${TEST_ALIASES[$TEST]}" +run_test "${TEST_ALIASES[$TEST]}" diff --git a/scripts/tests_utils.py b/scripts/tests_utils.py index eedbdc3523e..f8df71bc9ee 100644 --- a/scripts/tests_utils.py +++ b/scripts/tests_utils.py @@ -28,6 +28,10 @@ def get_workspace_tree() -> Dict[str, str]: return tree +def get_workspace_packages() -> Set[str]: + return set(get_workspace_tree().keys()) + + def get_local_changes(repo_path, commit_id: Optional[str]) -> List[str]: os.environ["GIT_PYTHON_REFRESH"] = "quiet" # noqa repo = Repo(repo_path) diff --git a/toml_test_utils/Cargo.toml b/toml_test_utils/Cargo.toml new file mode 100644 index 00000000000..91ac30899e0 --- /dev/null +++ b/toml_test_utils/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "toml_test_utils" +version.workspace = true +edition.workspace = true +repository.workspace = true +license.workspace = true +description = "Utilities for working with TOML files in tests." + +[lints] +workspace = true + +[dependencies] +serde = { workspace = true, features = ["derive"] } +toml.workspace = true diff --git a/toml_test_utils/src/lib.rs b/toml_test_utils/src/lib.rs new file mode 100644 index 00000000000..fe55597edc4 --- /dev/null +++ b/toml_test_utils/src/lib.rs @@ -0,0 +1,193 @@ +use std::collections::{HashMap, HashSet}; +use std::fs; +use std::path::Path; +use std::sync::LazyLock; + +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[serde(untagged)] +pub enum LintValue { + Bool(bool), +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(untagged)] +pub enum DependencyValue { + String(String), + Object { version: Option, path: Option, features: Option> }, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Package { + version: String, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct WorkspaceFields { + package: Package, + members: Vec, + dependencies: HashMap, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct CargoToml { + workspace: WorkspaceFields, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(untagged)] +pub enum PackageEntryValue { + String(String), + Object { workspace: bool }, + Other(toml::Value), +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct CrateCargoToml { + pub package: HashMap, + pub dependencies: Option>, + #[serde(rename = "dev-dependencies")] + pub dev_dependencies: Option>, + pub lints: Option>, +} + +impl CrateCargoToml { + pub fn from_name(name: &String) -> Self { + MEMBER_TOMLS.get(name).unwrap_or_else(|| panic!("No member crate '{name}' found.")).clone() + } + + pub fn package_name(&self) -> &String { + match self.package.get("name") { + Some(PackageEntryValue::String(name)) => name, + _ => panic!("No name found in crate toml {self:?}."), + } + } + + pub fn path_dependencies(&self) -> impl Iterator + '_ { + self.dependencies.iter().flatten().filter_map(|(_name, value)| { + if let DependencyValue::Object { path: Some(path), .. } = value { + Some(path.to_string()) + } else { + None + } + }) + } + + /// Returns all direct member dependencies of self. + pub fn member_dependency_names(&self, include_dev_dependencies: bool) -> HashSet { + let member_crate_names: HashSet<&String> = + MEMBER_TOMLS.values().map(CrateCargoToml::package_name).collect(); + + self.dependencies + .iter() + .flatten() + .chain(if include_dev_dependencies { + self.dev_dependencies.iter().flatten() + } else { + None.iter().flatten() + }) + .filter_map( + |(name, _value)| { + if member_crate_names.contains(name) { Some(name.clone()) } else { None } + }, + ) + .collect() + } + + /// Helper function for member_dependency_names_recursive. + fn member_dependency_names_recursive_aux( + &self, + include_dev_dependencies: bool, + processed_member_names: &mut HashSet, + ) -> HashSet { + let direct_member_dependencies = self.member_dependency_names(include_dev_dependencies); + let mut members = HashSet::new(); + for toml in direct_member_dependencies.iter().map(CrateCargoToml::from_name) { + // To prevent infinite recursion, we only recurse on members that have not been + // processed yet. If a member depends on itself, this can lead to a loop. + let dep_name = toml.package_name(); + members.insert(dep_name.clone()); + if !processed_member_names.contains(dep_name) { + processed_member_names.insert(dep_name.clone()); + members.extend(toml.member_dependency_names_recursive_aux( + include_dev_dependencies, + processed_member_names, + )); + } + } + members + } + + /// Returns all member dependencies of self in the dependency tree. + pub fn member_dependency_names_recursive( + &self, + include_dev_dependencies: bool, + ) -> HashSet { + self.member_dependency_names_recursive_aux(include_dev_dependencies, &mut HashSet::new()) + } +} + +#[derive(Debug)] +pub struct LocalCrate { + pub name: String, + pub path: String, + pub version: Option, +} + +pub static ROOT_TOML: LazyLock = LazyLock::new(|| { + let root_toml: CargoToml = + toml::from_str(include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/../Cargo.toml"))) + .unwrap(); + root_toml +}); +pub static MEMBER_TOMLS: LazyLock> = + LazyLock::new(|| ROOT_TOML.member_cargo_tomls()); + +impl CargoToml { + pub fn members(&self) -> &Vec { + &self.workspace.members + } + + pub fn workspace_version(&self) -> &str { + &self.workspace.package.version + } + + pub fn contains_dependency(&self, name: &str) -> bool { + self.workspace.dependencies.contains_key(name) + } + + pub fn dependencies(&self) -> impl Iterator + '_ { + self.workspace.dependencies.iter() + } + + pub fn path_dependencies(&self) -> impl Iterator + '_ { + self.dependencies().filter_map(|(name, value)| { + if let DependencyValue::Object { path: Some(path), version, .. } = value { + Some(LocalCrate { + name: name.clone(), + path: path.to_string(), + version: version.clone(), + }) + } else { + None + } + }) + } + + pub fn member_cargo_tomls(&self) -> HashMap { + let crates_dir = Path::new(concat!(env!("CARGO_MANIFEST_DIR"), "/../")); + self.members() + .iter() + .map(|member| { + let cargo_toml_path = crates_dir.join(member).join("Cargo.toml"); + + let cargo_toml_content = fs::read_to_string(&cargo_toml_path) + .unwrap_or_else(|_| panic!("Failed to read {:?}", cargo_toml_path)); + + let cargo_toml: CrateCargoToml = toml::from_str(&cargo_toml_content).unwrap(); + (cargo_toml.package_name().clone(), cargo_toml) + }) + .collect() + } +} diff --git a/workspace_tests/Cargo.toml b/workspace_tests/Cargo.toml index 18a57a14546..8ca2a7d0f6a 100644 --- a/workspace_tests/Cargo.toml +++ b/workspace_tests/Cargo.toml @@ -7,8 +7,7 @@ license-file.workspace = true description = "Workspace-level tests." [dev-dependencies] -serde = { workspace = true, features = ["derive"] } -toml.workspace = true +toml_test_utils.path = "../toml_test_utils" [[test]] name = "workspace_tests" diff --git a/workspace_tests/lints_test.rs b/workspace_tests/lints_test.rs index c42243dce58..1e956293892 100644 --- a/workspace_tests/lints_test.rs +++ b/workspace_tests/lints_test.rs @@ -1,12 +1,11 @@ use std::collections::HashMap; -use crate::toml_utils::{CrateCargoToml, LintValue, ROOT_TOML}; +use toml_test_utils::{CrateCargoToml, LintValue, MEMBER_TOMLS}; #[test] fn test_lints_section_exists() { - let crates_without_lints: Vec<_> = ROOT_TOML - .member_cargo_tomls() - .into_iter() + let crates_without_lints: Vec<_> = MEMBER_TOMLS + .iter() .filter(|(_, CrateCargoToml { lints, .. })| lints.is_none()) .map(|(crate_name, _)| crate_name) .collect(); @@ -20,9 +19,8 @@ fn test_lints_section_exists() { fn test_lints_from_workspace() { let expected_lints_entry = HashMap::::from([("workspace".into(), LintValue::Bool(true))]); - let crates_without_workspace_lints: Vec<_> = ROOT_TOML - .member_cargo_tomls() - .into_iter() + let crates_without_workspace_lints: Vec<_> = MEMBER_TOMLS + .iter() .filter(|(_, CrateCargoToml { lints, .. })| match lints { None => false, Some(lints) => lints != &expected_lints_entry, diff --git a/workspace_tests/main.rs b/workspace_tests/main.rs index dce1c1efde0..499364c01df 100644 --- a/workspace_tests/main.rs +++ b/workspace_tests/main.rs @@ -2,5 +2,4 @@ pub mod lints_test; pub mod package_integrity_test; -pub mod toml_utils; pub mod version_integrity_test; diff --git a/workspace_tests/package_integrity_test.rs b/workspace_tests/package_integrity_test.rs index 3c76f6fe4f6..79a4dd86e30 100644 --- a/workspace_tests/package_integrity_test.rs +++ b/workspace_tests/package_integrity_test.rs @@ -1,12 +1,50 @@ use std::path::PathBuf; -use crate::toml_utils::{PackageEntryValue, ROOT_TOML}; +use toml_test_utils::{DependencyValue, PackageEntryValue, MEMBER_TOMLS}; + +/// Hard-coded list of crates that are allowed to use test code in their (non-dev) dependencies. +/// Should only contain test-related crates. +static CRATES_ALLOWED_TO_USE_TESTING_FEATURE: [&str; 6] = [ + "starknet_integration_tests", + "papyrus_test_utils", + "blockifier_test_utils", + "papyrus_load_test", + "mempool_test_utils", + // The CLI crate exposes tests that require test utils in dependencies. + // TODO(Dori): Consider splitting the build of the CLI crate to a test build and a production + // build. + "starknet_committer_and_os_cli", +]; + +/// Tests that no member crate has itself in it's dependency tree. +/// This may occur if, for example, a developer wants to activate a feature of a crate in tests, and +/// adds a dependency on itself in dev-dependencies with this feature active. +/// Note: a common (erroneous) use case would be to activate the "testing" feature of a crate in +/// tests by adding a dependency on itself in dev-dependencies. This is not allowed; any code gated +/// by the testing feature should also be gated by `test`. +#[test] +fn test_no_self_dependencies() { + let members_with_self_deps: Vec = MEMBER_TOMLS + .iter() + .filter_map(|(name, toml)| { + if toml.member_dependency_names_recursive(true).contains(toml.package_name()) { + Some(name.clone()) + } else { + None + } + }) + .collect(); + assert!( + members_with_self_deps.is_empty(), + "The following crates have themselves in their dependency tree: \ + {members_with_self_deps:?}. This is not allowed." + ); +} #[test] fn test_package_names_match_directory() { - let mismatched_packages: Vec<_> = ROOT_TOML - .member_cargo_tomls() - .into_iter() + let mismatched_packages: Vec<_> = MEMBER_TOMLS + .iter() .filter_map(|(path_str, toml)| { let path = PathBuf::from(&path_str); let directory_name = path.file_name()?.to_str()?; @@ -24,3 +62,51 @@ fn test_package_names_match_directory() { missing a name field: {mismatched_packages:?}." ); } + +/// Tests that no dependency activates the "testing" feature (dev-dependencies may). +#[test] +fn test_no_testing_feature_in_business_logic() { + let mut testing_feature_deps: Vec<_> = MEMBER_TOMLS + .iter() + // Ignore test-specific crates. + .filter_map(|(package_name, toml)| { + if CRATES_ALLOWED_TO_USE_TESTING_FEATURE.contains(&package_name.as_str()) { + None + } else { + Some((package_name, toml)) + } + }) + // Ignore crates without dependencies. + .filter_map(|(package_name, toml)| { + toml.dependencies.as_ref().map(|dependencies| (package_name, dependencies)) + }) + .filter_map(|(package_name, dependencies)| { + let testing_feature_deps = dependencies + .iter() + .filter_map(|(name, value)| { + if let DependencyValue::Object { features: Some(features), .. } = value { + if features.contains(&"testing".to_string()) { + Some(name.clone()) + } else { + None + } + } else { + None + } + }) + .collect::>(); + if testing_feature_deps.is_empty() { + None + } else { + Some((package_name.clone(), testing_feature_deps)) + } + }) + .collect(); + testing_feature_deps.sort(); + assert!( + testing_feature_deps.is_empty(), + "The following crates have (non-testing) dependencies with the 'testing' feature \ + activated. If the crate is a test crate, add it to {}.\n{testing_feature_deps:#?}", + stringify!(CRATES_ALLOWED_TO_USE_TESTING_FEATURE) + ); +} diff --git a/workspace_tests/toml_utils.rs b/workspace_tests/toml_utils.rs deleted file mode 100644 index ba102d747c5..00000000000 --- a/workspace_tests/toml_utils.rs +++ /dev/null @@ -1,121 +0,0 @@ -use std::collections::HashMap; -use std::fs; -use std::path::Path; -use std::sync::LazyLock; - -use serde::{Deserialize, Serialize}; - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -#[serde(untagged)] -pub(crate) enum LintValue { - Bool(bool), -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -#[serde(untagged)] -pub(crate) enum DependencyValue { - String(String), - Object { version: Option, path: Option, features: Option> }, -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub(crate) struct Package { - version: String, -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub(crate) struct WorkspaceFields { - package: Package, - members: Vec, - dependencies: HashMap, -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub(crate) struct CargoToml { - workspace: WorkspaceFields, -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -#[serde(untagged)] -pub(crate) enum PackageEntryValue { - String(String), - Object { workspace: bool }, - Other(toml::Value), -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub(crate) struct CrateCargoToml { - pub(crate) package: HashMap, - dependencies: Option>, - #[serde(rename = "dev-dependencies")] - dev_dependencies: Option>, - pub(crate) lints: Option>, -} - -#[derive(Debug)] -pub(crate) struct LocalCrate { - pub(crate) path: String, - pub(crate) version: String, -} - -pub(crate) static ROOT_TOML: LazyLock = LazyLock::new(|| { - let root_toml: CargoToml = - toml::from_str(include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/../Cargo.toml"))) - .unwrap(); - root_toml -}); - -impl CargoToml { - pub(crate) fn members(&self) -> &Vec { - &self.workspace.members - } - - pub(crate) fn workspace_version(&self) -> &str { - &self.workspace.package.version - } - - pub(crate) fn dependencies(&self) -> impl Iterator + '_ { - self.workspace.dependencies.iter() - } - - pub(crate) fn path_dependencies(&self) -> impl Iterator + '_ { - self.dependencies().filter_map(|(_name, value)| { - if let DependencyValue::Object { path: Some(path), version: Some(version), .. } = value - { - Some(LocalCrate { path: path.to_string(), version: version.to_string() }) - } else { - None - } - }) - } - - pub(crate) fn member_cargo_tomls(&self) -> HashMap { - let crates_dir = Path::new(concat!(env!("CARGO_MANIFEST_DIR"), "/../")); - self.members() - .iter() - .map(|member| { - let cargo_toml_path = crates_dir.join(member).join("Cargo.toml"); - - let cargo_toml_content = fs::read_to_string(&cargo_toml_path) - .unwrap_or_else(|_| panic!("Failed to read {:?}", cargo_toml_path)); - - let cargo_toml: CrateCargoToml = toml::from_str(&cargo_toml_content).unwrap(); - (member.clone(), cargo_toml) - }) - .collect() - } -} - -impl CrateCargoToml { - pub(crate) fn path_dependencies(&self) -> impl Iterator + '_ { - self.dependencies.iter().chain(self.dev_dependencies.iter()).flatten().filter_map( - |(_name, value)| { - if let DependencyValue::Object { path: Some(path), .. } = value { - Some(path.to_string()) - } else { - None - } - }, - ) - } -} diff --git a/workspace_tests/version_integrity_test.rs b/workspace_tests/version_integrity_test.rs index 2f30127a686..2e284782b83 100644 --- a/workspace_tests/version_integrity_test.rs +++ b/workspace_tests/version_integrity_test.rs @@ -1,4 +1,127 @@ -use crate::toml_utils::{DependencyValue, LocalCrate, PackageEntryValue, ROOT_TOML}; +use std::collections::{HashMap, HashSet}; +use std::sync::LazyLock; + +use toml_test_utils::{ + CrateCargoToml, + DependencyValue, + LocalCrate, + PackageEntryValue, + MEMBER_TOMLS, + ROOT_TOML, +}; + +const PARENT_BRANCH: &str = include_str!("../scripts/parent_branch.txt"); +const MAIN_PARENT_BRANCH: &str = "main"; +const EXPECTED_MAIN_VERSION: &str = "0.0.0"; + +static ROOT_CRATES_FOR_PUBLISH: LazyLock> = + LazyLock::new(|| HashSet::from(["blockifier"])); +static CRATES_FOR_PUBLISH: LazyLock> = LazyLock::new(|| { + let publish_deps: HashSet = ROOT_CRATES_FOR_PUBLISH + .iter() + .flat_map(|crate_name| { + // No requirement to publish dev dependencies. + CrateCargoToml::from_name(&crate_name.to_string()) + .member_dependency_names_recursive(false) + }) + .collect(); + publish_deps + .union(&ROOT_CRATES_FOR_PUBLISH.iter().map(|s| s.to_string()).collect()) + .cloned() + .collect() +}); + +/// All member crates listed in the root Cargo.toml should have a version field if and only if they +/// are intended for publishing. +/// To understand why the workspace benefits from this check, consider the following scenario: +/// Say crates X, Y and Z are members of the workspace, and crates/X/Cargo.toml is: +/// ```toml +/// [package] +/// name = "X" +/// +/// [dependencies] +/// Y.workspace = true +/// +/// [dev-dependencies] +/// Z.workspace = true +/// ``` +/// Consider the (problematic) contents of the root Cargo.toml: +/// ```toml +/// X = { path = "crates/X", version = "1.2.3" } +/// Y = { path = "crates/Y", version = "1.2.3" } +/// Z = { path = "crates/Z", version = "1.2.3" } +/// ``` +/// If X is intended for publishing, both X and Y must have a valid version field. Z is not required +/// for publishing, because it is only a dev dependency. However, since it has a version field, +/// `cargo publish -p X` will fail because Z is not published. +/// If the root Cargo.toml is: +/// ```toml +/// X = { path = "crates/X", version = "1.2.3" } +/// Y = { path = "crates/Y", version = "1.2.3" } +/// Z.path = "crates/Z" +/// ``` +/// then `cargo publish -p X` will succeed, because the command ignores path dependencies without +/// version fallbacks. +#[test] +fn test_members_have_version_iff_they_are_for_publish() { + let members_with_version: HashSet = ROOT_TOML + .path_dependencies() + .filter_map( + |LocalCrate { name, version, .. }| { + if version.is_some() { Some(name.clone()) } else { None } + }, + ) + .collect(); + let members_without_version: HashSet = ROOT_TOML + .path_dependencies() + .filter_map( + |LocalCrate { name, .. }| { + if !members_with_version.contains(&name) { Some(name) } else { None } + }, + ) + .collect(); + + let mut published_crates_without_version: Vec = + members_without_version.intersection(&*CRATES_FOR_PUBLISH).cloned().collect(); + let mut unpublished_crates_with_version: Vec = + members_with_version.difference(&*CRATES_FOR_PUBLISH).cloned().collect(); + published_crates_without_version.sort(); + unpublished_crates_with_version.sort(); + assert!( + published_crates_without_version.is_empty() && unpublished_crates_with_version.is_empty(), + "The following crates are missing a version field in the workspace Cargo.toml: \ + {published_crates_without_version:#?}.\nThe following crates have a version field but \ + are not intended for publishing: {unpublished_crates_with_version:#?}." + ); +} + +#[test] +fn test_members_are_deps() { + let member_tomls = ROOT_TOML.member_cargo_tomls(); + let non_dep_members: Vec<_> = + member_tomls.keys().filter(|member| !ROOT_TOML.contains_dependency(member)).collect(); + assert!( + non_dep_members.is_empty(), + "The following crates are members of the workspace but not dependencies: \ + {non_dep_members:?}." + ); +} + +#[test] +fn test_members_have_paths() { + let member_tomls = ROOT_TOML.member_cargo_tomls(); + let path_dependencies_names: HashSet = + ROOT_TOML.path_dependencies().map(|dep| dep.name).collect(); + let members_without_paths: Vec<_> = member_tomls + .keys() + .filter(|member| !path_dependencies_names.contains(&member.to_string())) + .collect(); + assert!( + members_without_paths.is_empty(), + "The following crates are members of the workspace but do not have a path: \ + {members_without_paths:?}." + ); +} #[test] fn test_path_dependencies_are_members() { @@ -18,7 +141,11 @@ fn test_version_alignment() { let workspace_version = ROOT_TOML.workspace_version(); let crates_with_incorrect_version: Vec<_> = ROOT_TOML .path_dependencies() - .filter(|LocalCrate { version, .. }| version != workspace_version) + .filter( + |LocalCrate { version, .. }| { + if let Some(version) = version { version != workspace_version } else { false } + }, + ) .collect(); assert!( crates_with_incorrect_version.is_empty(), @@ -29,25 +156,24 @@ fn test_version_alignment() { #[test] fn validate_crate_version_is_workspace() { - let crates_without_workspace_version: Vec = ROOT_TOML - .member_cargo_tomls() - .into_iter() + let crates_without_workspace_version: Vec = MEMBER_TOMLS + .iter() .flat_map(|(member, toml)| match toml.package.get("version") { // No `version` field. - None => Some(member), + None => Some(member.clone()), Some(version) => match version { // version = "x.y.z". - PackageEntryValue::String(_) => Some(member), + PackageEntryValue::String(_) => Some(member.clone()), // version.workspace = (true | false). PackageEntryValue::Object { workspace } => { if *workspace { None } else { - Some(member) + Some(member.clone()) } } // Unknown version object. - PackageEntryValue::Other(_) => Some(member), + PackageEntryValue::Other(_) => Some(member.clone()), }, }) .collect(); @@ -61,8 +187,17 @@ fn validate_crate_version_is_workspace() { #[test] fn validate_no_path_dependencies() { - let all_path_deps_in_crate_tomls: Vec = - ROOT_TOML.member_cargo_tomls().values().flat_map(|toml| toml.path_dependencies()).collect(); + let all_path_deps_in_crate_tomls: HashMap = MEMBER_TOMLS + .iter() + .filter_map(|(crate_name, toml)| { + let path_deps: Vec = toml.path_dependencies().collect(); + if path_deps.is_empty() { + None + } else { + Some((crate_name.clone(), path_deps.join(", "))) + } + }) + .collect(); assert!( all_path_deps_in_crate_tomls.is_empty(), @@ -86,3 +221,15 @@ fn test_no_features_in_workspace() { needs them." ); } + +#[test] +fn test_main_branch_is_versionless() { + if PARENT_BRANCH.trim() == MAIN_PARENT_BRANCH { + let workspace_version = ROOT_TOML.workspace_version(); + assert_eq!( + workspace_version, EXPECTED_MAIN_VERSION, + "The workspace version should be '{EXPECTED_MAIN_VERSION}' when the parent branch is \ + '{MAIN_PARENT_BRANCH}'; found {workspace_version}.", + ); + } +}